qmapshack-1.10.0/test/000755 001750 000144 00000000000 13216664442 015711 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/000755 001750 000144 00000000000 13216664442 017570 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/CKnownExtension.cpp000644 001750 000144 00000007362 13023451227 023367 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "TestHelper.h" #include "test_QMapShack.h" #include "gis/gpx/CGpxProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" static QStringList GarminTPX1Exts = {"atemp", "wtemp", "depth", "hr", "cad"}; void test_QMapShack::readExtGarminTPX1(const QString &file, const QString &ns) { CGpxProject *proj = dynamic_cast(readProjFile(file)); VERIFY_EQUAL(1, proj->childCount()); for(int i = 0; i < proj->childCount(); i++) { IGisItem *item = dynamic_cast(proj->child(i)); CGisItemTrk *itemTrk = dynamic_cast(item); if(nullptr != itemTrk) { const CTrackData &trk = itemTrk->getTrackData(); // filter all internal extensions (starting with ::ql:) QStringList extensions = itemTrk->getExistingDataSources().filter(QRegExp("^((?!::ql:).)*$")); VERIFY_EQUAL(GarminTPX1Exts.size(), extensions.size()); for(const QString &exp : GarminTPX1Exts) { const QString &fullExp = ns + ":TrackPointExtension|" + ns + ":" + exp; SUBVERIFY(extensions.contains(fullExp), "Missing extension " + fullExp) } const fTrkPtGetVal &getAtemp = CKnownExtension::get(ns + ":TrackPointExtension|" + ns + ":atemp").valueFunc; const fTrkPtGetVal &getWtemp = CKnownExtension::get(ns + ":TrackPointExtension|" + ns + ":wtemp").valueFunc; const fTrkPtGetVal &getDepth = CKnownExtension::get(ns + ":TrackPointExtension|" + ns + ":depth").valueFunc; const fTrkPtGetVal &getHR = CKnownExtension::get(ns + ":TrackPointExtension|" + ns + ":hr").valueFunc; const fTrkPtGetVal &getCad = CKnownExtension::get(ns + ":TrackPointExtension|" + ns + ":cad").valueFunc; int i = 0; for(const trkpt_t &trkpt : trk) { SUBVERIFY((0. != trkpt.lat) || (0. != trkpt.lon), "Trackpoint has position 0/0"); for(const QString &ext : trkpt.extensions.keys()) { VERIFY_EQUAL(true, CKnownExtension::isKnown(ext)); } // try to read values from the file, they start at a specific value and are incremented from trkpt to trkpt VERIFY_EQUAL( 20 + i, getAtemp(trkpt)); VERIFY_EQUAL( 10 + i, getWtemp(trkpt)); VERIFY_EQUAL(100 + i, getDepth(trkpt)); VERIFY_EQUAL( 90 + i, getHR(trkpt)); VERIFY_EQUAL( 60 + i, getCad(trkpt)); ++i; } } } delete proj; } void test_QMapShack::_readExtGarminTPX1_tp1() { readExtGarminTPX1(testInput + "gpx/gpx_ext_GarminTPX1_tp1.gpx", "tp1"); } void test_QMapShack::_readExtGarminTPX1_gpxtpx() { readExtGarminTPX1(testInput + "gpx/gpx_ext_GarminTPX1_gpxtpx.gpx", "gpxtpx"); } qmapshack-1.10.0/test/unittest/CGisItemTrk.cpp000644 001750 000144 00000003624 12727447634 022436 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "TestHelper.h" #include "test_QMapShack.h" #include "gis/gpx/CGpxProject.h" #include "gis/trk/CGisItemTrk.h" #include void test_QMapShack::_filterDeleteExtension() { for(const QString &file : inputFiles) { IGisProject *proj = readProjFile(file); expectedGisProject exp = TestHelper::readExpProj(fileToPath(file) + ".xml"); exp.changed = true; // filtering changes a project for(int i = 0; i < proj->childCount(); i++) { CGisItemTrk *trk = dynamic_cast(proj->child(i)); if(nullptr != trk) { expectedTrack &expTrk = exp.trks[trk->getName()]; while(!expTrk.extensions.empty()) { expectedExtension expExt = expTrk.extensions.take(expTrk.extensions.keys().first()); trk->filterDeleteExtension(expExt.name); verify(exp, *proj); } } } delete proj; } } qmapshack-1.10.0/test/unittest/CFitProject.cpp000644 001750 000144 00000002357 12727447634 022467 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 #include "TestHelper.h" #include "test_QMapShack.h" #include "gis/prj/IGisProject.h" #include "gis/fit/CFitProject.h" void test_QMapShack::_readValidFitFiles() { delete readProjFile("2015-05-07-22-03-17.fit"); delete readProjFile("Warisouderghem_course.fit"); delete readProjFile("2016-03-12_15-16-50_4_20.fit"); } qmapshack-1.10.0/test/unittest/TestHelper.h000644 001750 000144 00000004561 12727447634 022036 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef TESTHELPER_H #define TESTHELPER_H #include #define SUBVERIFY(EXPR, MSG) { \ if(!(EXPR)) { \ throw QString("Verification of `%1` failed: %2 (%3:%4)").arg(#EXPR).arg(MSG).arg(__FILE__).arg(__LINE__); \ } \ } #define VERIFY_EQUAL(EXP, ACT) \ SUBVERIFY( (EXP == ACT), QTest::toString(QString("Expected `%1`, got `%2`").arg(EXP).arg(ACT)) ); struct expectedWaypoint { QString name; }; struct expectedExtension { QString name; //< the name as used in the file bool known; //< if true, the value has to be known (e.g. CKnownExtension::isKnown() returns true) bool everyPoint; //< if true, the value has to be set for every single trkpt bool derived; //< if true, the value is derived by QMS }; struct expectedTrack { QString name; int colorIdx; int segCount; int ptCount; QHash extensions; }; struct expectedRoute { QString name; int ptCount; }; struct expectedArea { QString name; int colorIdx; int ptCount; }; struct expectedGisProject { QString name; QString desc; bool changed; QHash wpts; QHash trks; QHash rtes; QHash ovls; }; class TestHelper { public: static QString getTempFileName(const QString &ext); static expectedGisProject readExpProj(const QString &file); }; #endif // TESTHELPER_H qmapshack-1.10.0/test/unittest/CGpxProject.cpp000644 001750 000144 00000003226 13015033052 022447 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "TestHelper.h" #include "test_QMapShack.h" #include "gis/gpx/CGpxProject.h" void test_QMapShack::writeReadGpxFile(const QString &file) { IGisProject *proj = readProjFile(file); QString tmpFile = TestHelper::getTempFileName("gpx"); CGpxProject::saveAs(tmpFile, *proj, false); delete proj; proj = readProjFile(tmpFile, true, false); verify(file, *proj); delete proj; QFile(tmpFile).remove(); } void test_QMapShack::_writeReadGpxFile() { writeReadGpxFile("qtt_gpx_file0.gpx"); writeReadGpxFile("gpx_ext_GarminTPX1_gpxtpx.gpx"); writeReadGpxFile("gpx_ext_GarminTPX1_tp1.gpx"); writeReadGpxFile("gpx_ext_GarminTPX1_cns.gpx"); writeReadGpxFile("V1.6.0_file1.qms"); writeReadGpxFile("V1.6.0_file2.qms"); } qmapshack-1.10.0/test/unittest/input/000755 001750 000144 00000000000 13216664442 020727 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/input/qms/000755 001750 000144 00000000000 13216664442 021527 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/input/qms/V1.6.0_file1.qms.xml000644 001750 000144 00000001472 12727447634 024734 0ustar00oeichlerxusers000000 000000 1.6.0 Test1 qmapshack-1.10.0/test/unittest/input/qms/V1.6.0_file2.qms000644 001750 000144 00000014030 12727447634 024130 0ustar00oeichlerxusers000000 000000 QMProj b/home/chris/gps_tracks/migrateDB/V1.6.0_file2.qms1.6.0 Test2l%{ @a677605fc1a0284de30d9a8dad6dca50l% 0://icons/48x48/Start.png Initial version.QMapShackl% 6://icons/48x48/EditText.pngChanged nameQMapShackl%0 6://icons/48x48/EditText.pngChanged name| QMTrk m A xڽyTI$FEIC=("*)RQPWQՇ h`qAAA uAM o售-=2moj eW2R>,N eld dl\[W&}20ЛCqsPiwPx9";?ӴRŊ$O5ިxA:x^S\2Z7eH=INƥ6dxKUo9gokqjڵ7'!*!M]0P- <^( B> >,@[rdvpl^xHT\JJV*9~yO| /ߝTɾ7J/Ժx(Au(|P@/|F^n?eMuf!c)Dyǀʠq3]`L*eEʓV<̬Rv~8T&FPnFlH*Q*-C|۬z :ER&J/]~2p> m!@QJ{O1p&wԹ[j1DR}5鸔Sد)|d'E|+\j2ZJ-p\MNA\ܺ),jOW;j T(ޗ|B!JEZ7 ƣ%~Tp:VԑD@ã)@:xj1Pgf]~Tf8.q)ݛFR/uҽl.u7ugW=Fy1E@]rExL}<4!5W!l5!KP ԋVt*= nmSĶw\c.555PSZE6-Bܺw .c6dUR76Me5I| Qu*P-)b"zO3`%suf`f}4㆏@35b9e9cb3b0d0c4f9be5a23b71954012QMapShack@35b9e9cb3b0d0c4f9be5a23b71954012l% T0://icons/48x48/Start.png Initial version.QMRte xs```Hf0d0aHd0Җ@2!! -%'jMb  @(^ 0 H3Aj0HvrIq.A@Z 9؀-9@#H50c{[?PP5$8?<(\/3/89 U/(};).!%YޟJF+ږmYOһ h[l>;`V36h M6qon׆$ ZKxo-/'WbuSN>ϟZ0}ʰ;֯(XsHyMQK'2\(|K΄s~w+/{o&X\P^E?WJ WmtClMۺ=6.=~8QP{Ҕ}~Ye5ڽ9k״iZRUѫ 噚6c`}IV^WeXTՐ5,o bK!C:V>wkΓr-~0E=VWtCAãguFֱ-ųqцS3%e4f(Aߗœl;A^S}۶,[S8fVe~3n^sYd;KӁ^|yӻ=>Tͻ8<[.IH9Iˈ ŚWj`1oޜ\Syh[a*.M?Y:->?z+he*BcNcTP*[u3;B}br|cߺ ֪ ǦE{2U1_Iɵ_m-,Y%$G>￟VV;KluyڦK??d@]´ee\$PAaJ y m//55a_@ǭ^ 韽(6C C[~.׉7/^ݭ?c82;aߺ![lRr w2*#]Hpc6^Ԏ&`oG'mn޳ځNyvu1ĭoOzYl t.>߾?df=~r'"OiIS/;Qq%(YS(tOѳw|vm_nP玎T3O|&}X27#q'곎znMf6-/gmlh6pKdZyEG^Vs׊ҷ7m{*t 7N^>&1[5M6F4ij꤮[f?}XL8ۿwOL3I+Rr ɓ~lMgq(m{yݳ4s-2؅LN=S]fz0L{(C3e,9u&28i/]sZƜGy0:V]N0~6ߴõ_}8%o="Ob#~٩cz%.-<1E/c(Ӝ-xbTtsYĸEfb?5_jSrz(^t c Mu0hE0ZVhE@l<&:9VhE0ZV#"`k\ojyhE0ZVȪ|anf jV"@k.rRE@818f766bc3e15f21592b0bdb6c5d2feaQMapShack@818f766bc3e15f21592b0bdb6c5d2feal% T0://icons/48x48/Start.png Initial version.QMWpt xs```0f0e0c0@ڂ! ( $ R i@Y # 6&iL*P Mub 1.6.0 Test2 qmapshack-1.10.0/test/unittest/input/qms/V1.6.0_file1.qms000644 001750 000144 00000017514 12727447634 024141 0ustar00oeichlerxusers000000 000000 QMProj b/home/chris/gps_tracks/migrateDB/V1.6.0_file1.qms1.6.0 Test1l%@2cae86e050b48b04df0bf7e5e61a77cal% 0://icons/48x48/Start.png Initial version.QMapShackl%pL6://icons/48x48/EditText.pngChanged nameQMapShackl%(4://icons/48x48/ActFoot.pngXChanged activity to 'Foot' for range(0..29).QMapShackl%6://icons/48x48/ActCycle.pngbChanged activity to 'Bicycle' for range(30..127).CQMTrk 46xڽyXGnPq B<#r4A`rE#!* \rC+Vm||}NwW]U CQ.KSfa@c2!z~'Kw#X6\b3% P |h lnj577SgQ0GKޮԟC-4%ǶMfhZ 3FR!07bX#E`雯Z2a;95__׃ ݪ7P)>gU? UvP=UR=K@P\6\={=qO`RЉPRrBLGG5q*QAP!T]CH]i v&0c@e.,5Z < Tzx^M՟X8 T >ueaxT`lPxԀV#k'Z?|3T Pqxތ*L¥r[I}%ќВK-]-ܫTu*{YGRb^KmmU]Hj`h7IƢ(Zh) |(-f EXnrЫػzNK F Ce(Jᡊ j3kAL~soX0:Pxjdh[$^[R5đ\[T2K}Q*&a_vL]5j[ ZBv[`_5W@"p{YaT_M)ڢje\Jr8^ >-Ev vy5D)R&Rwd*J0/lZ$lYρ**mJ!Pʔ.%6N7CMktebE\**SW@]R^):ҐpQoTe%]J5ir{JDPE":\ìP&⭸ԓ39M@䰺Jq)W$|c5˲ou'R]KKhMp@=}@=.Y R+QoJUS :3U䈚W[@mwef D 5U=ICMeY/q3@j깢Ik)BtR"҃b}PQw/k/UD 5(g<\T}P[n_tC='#.UyiR5؃M '_54؃j+fɼ׈;ģ||&jy8<3rPT;@klx T8=O/WĥJe^fCˠw[G9So/@ڭD %@h䉚{W:YmKE=ӛʹ5,bTi]z 2stA ->B>@}ew.uZ\E^UScӱG^Zj9ھ>Pmw (57*uO0h1Xa D‘rD0FBfA 8ǃ6H0>Gyj= 3Bf@ %z6Q֩=X&^|{vҒ1< S>}Ϟ:AטHorD2\{-"1Խޙ6=gƙXۭA1KS T<J> o$`Dɠ1 Yzm`"*Ozb =LV9kbg Hď!,Qd,Yۈ_q(0it6Ʊber Ђ6V ]0*fYD ИjB`lXQO p[|0]Q-~rhL8ئlXFO3hUAWX ;U>eS h UN"PQ /J$ @,[:@t@-1--82/nӴ~ړ+я jX8VsGXk!TΰsiwG=qC2*k?v{e捵2fpI 5w녻VZ=OPaⴠ2ӳ["* hO80z4^7,?!#>E>oץi=\UTM;qyIu'^Zs'}y'!mLݕUMVrDj:ϊkg;j?skwrn7qr%bH=`*Wx}b[ڇu7 ]2O*S!m.壘t6%)iߩ9ν:rLe-gfTV<|ٽ>5-z*1q ӞiyEM+oɆ[yxuWTM'+s02O`V]ҹ-fYK]]/OpZ ][?wl`Ӌ-JRLU?e*'ޞҙ/h{o.gV;|/)`VbrR[ԚcxWy2V% ڿUF_=+th⨓&GtTZӔ5{wD\2KRWE*t]B&o>=d@(%5ĿTjA2#am,(?fq*Ehh U߾J=UWZӴ!隩:Lnqޥ戦nNhEo(=Pk̮up8P%80G"uT;zWesC{b>,yi(笜oJ-iho 61q;=!~C_#^m$Τ$\cܸ^A<%ugÅs4[H3JPֽܶU9LZ3'wa~bb%Cdw&|-E'Z۪îɏZw7u\$0CAMlIh9$ڠ~&˔vD?~܇/.QV̽r(rxlԖAq{'32H/+܎^@c׫MgWu,vDD% $\n:*3={, !{[rbh*fB4\O5ϊ_^9V;uضA-†k;рh+i}Wp?괙=HhyKrD۶5JL) žY$37 K}wN+Oe*jȗŴ%V#0"AAO(Xybk `DF|XDu- ߚ,'!`DF|XDp/B"y1"#0"`U@ 1URbmxaDF`DaS!,S[cy dZY/jZE@d6d615b68b96c9e94c211f05c5ebcf82QMapShack@d6d615b68b96c9e94c211f05c5ebcf82l%o T0://icons/48x48/Start.png Initial version.QMWpt xmN;@[ ?h@P$6j,[Q&2ޛJ#Lƒ1UH8 $RDƛp`L=vg}y:/, YV |pEŞS9tM.q@AV8;OMuQZh?T@a57e93a86581a15297592d61303865c3QMapShack@a57e93a86581a15297592d61303865c3l%(0://icons/48x48/Start.png Initial version.QMapShackl%<://icons/48x48/SelectColor.pngChanged colorQMapShackl%4://icons/48x48/Pattern.png*Changed fill pattern.QMapShackl% 4://icons/48x48/Opacity.png Changed opacity.QMapShackl% 4://icons/48x48/Opacity.png Changed opacity.QMapShackl%6://icons/48x48/TextBold.png*Changed border width.QMapShackl%x6://icons/48x48/TextBold.png*Changed border width.QMArea xs```HeHc0bcS#3d md%2T -rI `F`Yfl@Ő54-'p( M(^U覡 cÌ'zmHߔƘF8umЊhÍsҤ*h4AvK6YEZ=y&]>:e`/#@P$G"q@ded5fffd33f398830ef34c2f528b7dd2QMapShack@ded5fffd33f398830ef34c2f528b7dd2qmapshack-1.10.0/test/unittest/input/slf/000755 001750 000144 00000000000 13216664442 021513 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/input/slf/qtt_slf_file0.slf000644 001750 000144 00006072215 12727447634 025001 0ustar00oeichlerxusers000000 000000 133718414AB7-C76E-6520-7FD5-D380A550FE0C5040004730004121430000000197.3949828422673005.1816674690724940020.615264465743586bike10-1420000g0049508.760000000058429.9899999999948327.8800000000031407190male30010015020025030049.54503349.70060310.66342810.55627813604720000017-9170024593.33333333333213.98888888888888928.4kmh35500000-800-52348.33333333334015.356820001411912312613012000367121155602180505-1Mon Jul 27 09:29:52 GMT+0200 2015true00000001406990140699000955460fitZone15500000000 qmapshack-1.10.0/test/unittest/input/slf/qtt_slf_file0.slf.xml000644 001750 000144 00000002346 12727447634 025570 0ustar00oeichlerxusers000000 000000 qttest slf file 0 QTTest .slf input file 0 qmapshack-1.10.0/test/unittest/input/gpx/000755 001750 000144 00000000000 13216664442 021525 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_gpxtpx.gpx000644 001750 000144 00000007036 12727447634 027325 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS gpxtpx Track 525 20.0 10.0 100.0 90 60 526 21.0 11.0 101.0 91 61 527 22.0 12.0 102.0 92 62 528 23.0 13.0 103.0 93 63 529 24.0 14.0 104.0 94 64 530 25.0 15.0 105.0 95 65 531 26.0 16.0 106.0 96 66 531 27.0 17.0 107.0 97 67 qmapshack-1.10.0/test/unittest/input/gpx/qtt_gpx_file0.gpx.xml000644 001750 000144 00000002147 12727447634 025625 0ustar00oeichlerxusers000000 000000 QTTest gpx file 0 QTTest gpx input file 0 qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_cns.gpx000644 001750 000144 00000007023 12727447634 026552 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS cns Track 525 20.0 10.0 100.0 90 60 526 21.0 11.0 101.0 91 61 527 22.0 12.0 102.0 92 62 528 23.0 13.0 103.0 93 63 529 24.0 14.0 104.0 94 64 530 25.0 15.0 105.0 95 65 531 26.0 16.0 106.0 96 66 531 27.0 17.0 107.0 97 67 qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_tp1.gpx.xml000644 001750 000144 00000002627 12727447634 027277 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS tp1 qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_cns.gpx.xml000644 001750 000144 00000002627 12727447634 027356 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS cns qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_gpxtpx.gpx.xml000644 001750 000144 00000002720 12727447634 030117 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS gpxtpx qmapshack-1.10.0/test/unittest/input/gpx/qtt_gpx_file0.gpx000644 001750 000144 00000517467 12727447634 025046 0ustar00oeichlerxusers000000 000000 QTTest gpx file 0 QTTest gpx input file 0 Track 9a180f190e7dcf7dbda0f2fcbf3c7078 3 ://icons/48x48/Start.png 2015-11-19T18:50:31Z Initial version. ://icons/48x48/EditText.png 2015-11-19T18:50:55Z Changed name DarkBlue 525 0 18.000000 123 526 0 18.000000 129 527 0 18.000000 184 528 0 18.000000 115 529 0 18.000000 158 530 0 18.000000 119 531 0 18.000000 181 531 0 18.000000 117 532 0 18.000000 148 532 0 18.000000 115 533 0 18.000000 136 533 0 18.000000 149 534 0 18.000000 191 534 0 18.000000 126 534 0 18.000000 189 535 0 18.000000 122 535 0 18.000000 163 535 0 18.000000 157 536 0 18.000000 133 536 0 18.000000 110 536 0 18.000000 150 536 0 18.000000 156 536 0 18.000000 185 536 0 18.000000 104 536 0 18.000000 110 536 0 17.000000 163 536 0 18.000000 101 536 0 18.000000 172 536 0 18.000000 110 536 0 18.000000 148 536 0 17.000000 125 536 0 18.000000 167 537 0 17.000000 189 537 0 17.000000 175 537 0 17.000000 172 537 0 17.000000 190 537 0 17.000000 192 537 0 17.000000 137 537 0 17.000000 189 538 0 17.000000 177 538 0 17.000000 132 539 0 17.000000 119 539 0 17.000000 199 539 0 17.000000 116 539 0 17.000000 170 539 0 17.000000 150 539 0 17.000000 193 539 0 17.000000 171 539 0 17.000000 110 539 0 17.000000 120 539 0 17.000000 155 539 0 17.000000 170 539 0 17.000000 107 539 0 17.000000 151 539 0 17.000000 119 539 0 17.000000 127 539 0 17.000000 163 539 0 17.000000 144 539 0 17.000000 103 539 0 17.000000 146 539 0 17.000000 107 539 0 17.000000 103 539 0 17.000000 116 540 0 17.000000 139 540 0 17.000000 168 540 0 17.000000 153 540 0 17.000000 168 540 0 17.000000 127 540 0 17.000000 146 540 0 17.000000 127 540 0 17.000000 145 540 0 17.000000 193 540 0 17.000000 108 540 0 17.000000 145 540 0 17.000000 194 540 0 17.000000 185 540 0 17.000000 112 540 0 17.000000 101 538 0 17.000000 123 538 0 17.000000 186 538 0 17.000000 143 538 0 17.000000 176 538 0 17.000000 187 538 0 17.000000 137 538 0 17.000000 194 538 0 17.000000 179 538 0 17.000000 183 538 0 17.000000 194 538 0 17.000000 158 538 0 17.000000 159 538 0 17.000000 131 538 0 17.000000 142 539 0 17.000000 190 539 0 17.000000 115 539 0 17.000000 183 539 0 17.000000 173 539 0 17.000000 149 539 0 17.000000 121 539 0 17.000000 111 538 0 17.000000 104 538 0 17.000000 142 538 0 17.000000 132 538 0 17.000000 110 538 0 17.000000 142 538 0 17.000000 162 538 0 17.000000 161 538 0 17.000000 177 538 0 17.000000 148 538 0 17.000000 198 538 0 17.000000 192 538 0 17.000000 164 538 0 17.000000 174 538 0 17.000000 195 538 0 17.000000 151 538 0 17.000000 122 538 0 17.000000 129 538 0 17.000000 181 538 0 17.000000 100 538 0 17.000000 128 533 0 19.000000 191 533 0 20.000000 136 533 0 20.000000 140 533 0 20.000000 187 533 0 20.000000 195 533 0 20.000000 199 533 0 20.000000 115 533 0 20.000000 154 533 0 20.000000 123 533 0 20.000000 177 533 0 20.000000 145 533 0 20.000000 173 533 0 20.000000 119 533 0 20.000000 147 533 0 20.000000 192 533 0 20.000000 185 533 0 19.000000 194 533 0 20.000000 139 533 0 19.000000 134 533 0 20.000000 120 533 0 20.000000 132 533 0 19.000000 133 533 0 20.000000 157 533 0 19.000000 143 533 0 20.000000 187 533 0 20.000000 164 533 0 19.000000 151 533 0 20.000000 189 533 0 19.000000 183 533 0 20.000000 163 533 0 20.000000 147 533 0 19.000000 142 533 0 19.000000 100 533 0 19.000000 160 533 0 19.000000 192 533 0 19.000000 134 533 0 19.000000 125 533 0 19.000000 141 533 0 19.000000 124 533 0 19.000000 197 533 0 19.000000 147 533 0 19.000000 168 533 0 19.000000 180 533 0 19.000000 185 533 0 19.000000 127 533 0 19.000000 160 533 0 19.000000 170 533 0 19.000000 113 533 0 19.000000 175 533 0 19.000000 137 533 0 19.000000 115 533 0 19.000000 164 533 0 19.000000 163 533 0 19.000000 156 533 0 19.000000 120 533 0 19.000000 195 533 0 19.000000 190 533 0 19.000000 142 533 0 19.000000 164 533 0 19.000000 194 533 0 19.000000 175 533 0 19.000000 176 533 0 19.000000 104 533 0 19.000000 196 533 0 19.000000 132 533 0 19.000000 173 533 0 19.000000 160 533 0 19.000000 156 533 0 19.000000 155 533 0 19.000000 170 533 0 19.000000 125 533 0 19.000000 148 533 0 19.000000 125 533 0 19.000000 171 533 0 19.000000 144 533 0 19.000000 164 533 0 19.000000 112 533 0 19.000000 104 533 0 19.000000 190 533 0 19.000000 184 533 0 19.000000 124 533 0 19.000000 159 533 0 19.000000 179 533 0 19.000000 111 533 0 19.000000 145 533 0 19.000000 102 533 0 19.000000 146 533 0 19.000000 133 533 0 19.000000 197 533 0 19.000000 149 533 0 19.000000 139 533 0 19.000000 123 533 0 19.000000 186 533 0 19.000000 134 533 0 19.000000 176 533 0 19.000000 177 533 0 19.000000 138 533 0 19.000000 131 533 0 19.000000 166 533 0 19.000000 191 533 0 19.000000 132 533 0 19.000000 157 533 0 19.000000 155 533 0 19.000000 102 533 0 19.000000 170 533 0 19.000000 150 533 0 19.000000 135 533 0 19.000000 163 533 0 19.000000 123 533 0 19.000000 194 533 0 19.000000 107 533 0 19.000000 183 533 0 19.000000 121 533 0 19.000000 137 533 0 19.000000 101 533 0 19.000000 165 533 0 19.000000 121 533 0 19.000000 141 533 0 19.000000 136 533 0 19.000000 127 533 0 19.000000 169 533 0 19.000000 134 533 0 19.000000 128 533 0 19.000000 104 533 0 19.000000 180 533 0 19.000000 184 533 0 19.000000 180 533 0 19.000000 113 533 0 19.000000 186 533 0 19.000000 147 533 0 19.000000 103 533 0 19.000000 159 533 0 19.000000 129 533 0 19.000000 154 533 0 19.000000 103 533 0 19.000000 129 533 0 19.000000 101 533 0 19.000000 146 533 0 19.000000 110 533 0 19.000000 122 533 0 19.000000 127 534 0 19.000000 117 534 0 19.000000 102 534 0 19.000000 127 534 0 19.000000 186 535 0 19.000000 166 535 0 19.000000 178 535 0 19.000000 123 535 0 19.000000 125 535 0 19.000000 171 535 0 19.000000 105 535 0 18.000000 103 535 0 19.000000 153 535 0 19.000000 192 535 0 19.000000 115 535 0 19.000000 102 535 0 18.000000 137 535 0 19.000000 113 535 0 19.000000 191 535 0 18.000000 130 535 0 18.000000 161 536 0 18.000000 127 536 0 18.000000 119 536 0 18.000000 151 536 0 18.000000 108 536 0 18.000000 164 536 0 18.000000 166 536 0 18.000000 136 536 0 18.000000 187 536 0 18.000000 122 536 0 18.000000 185 536 0 18.000000 109 536 0 18.000000 103 536 0 18.000000 111 536 0 18.000000 194 536 0 18.000000 116 536 0 18.000000 153 536 0 18.000000 155 536 0 18.000000 120 536 0 18.000000 141 536 0 18.000000 183 536 0 18.000000 120 536 0 18.000000 148 536 0 18.000000 117 536 0 18.000000 152 536 0 18.000000 180 536 0 18.000000 185 536 0 18.000000 165 535 0 18.000000 149 535 0 18.000000 130 535 0 18.000000 143 535 0 18.000000 129 535 0 18.000000 177 535 0 18.000000 181 535 0 18.000000 140 535 0 18.000000 169 535 0 18.000000 124 535 0 18.000000 127 535 0 18.000000 156 535 0 18.000000 157 535 0 18.000000 104 535 0 18.000000 114 535 0 18.000000 137 535 0 18.000000 164 535 0 18.000000 182 535 0 18.000000 185 535 0 18.000000 112 535 0 18.000000 199 535 0 18.000000 165 535 0 18.000000 143 534 0 18.000000 167 532 0 18.000000 193 530 0 18.000000 165 528 0 18.000000 170 526 0 18.000000 174 525 0 18.000000 127 523 0 18.000000 119 521 0 18.000000 135 518 0 18.000000 137 513 0 17.000000 174 511 0 17.000000 188 508 0 17.000000 180 504 0 17.000000 110 502 0 17.000000 171 501 0 17.000000 199 501 0 17.000000 118 500 0 17.000000 170 500 0 17.000000 179 500 0 17.000000 143 499 0 17.000000 109 498 0 17.000000 146 496 0 17.000000 133 494 0 17.000000 155 494 0 17.000000 141 494 0 17.000000 151 494 0 17.000000 154 493 0 17.000000 165 493 0 17.000000 160 493 0 17.000000 177 493 0 17.000000 130 493 0 17.000000 186 493 0 17.000000 106 493 0 17.000000 148 493 0 17.000000 132 493 0 17.000000 152 493 0 17.000000 100 493 0 17.000000 118 493 0 17.000000 170 493 0 17.000000 151 493 0 17.000000 136 493 0 17.000000 101 493 0 17.000000 151 494 0 17.000000 181 495 0 17.000000 124 496 0 17.000000 154 497 0 17.000000 132 498 0 17.000000 113 499 0 17.000000 154 500 0 17.000000 124 501 0 17.000000 148 502 0 17.000000 176 502 0 17.000000 132 502 0 17.000000 190 503 0 17.000000 194 503 0 17.000000 109 505 0 17.000000 147 505 0 17.000000 112 505 0 16.000000 194 505 0 17.000000 180 505 0 17.000000 192 506 0 17.000000 192 506 0 16.000000 157 506 0 16.000000 101 506 0 16.000000 169 506 0 16.000000 162 506 0 16.000000 127 506 0 16.000000 198 506 0 16.000000 172 506 0 16.000000 199 506 0 16.000000 119 506 0 16.000000 155 506 0 16.000000 192 506 0 16.000000 167 506 0 16.000000 156 506 0 16.000000 136 506 0 16.000000 146 506 0 16.000000 118 506 0 16.000000 118 507 0 16.000000 136 507 0 16.000000 107 507 0 16.000000 186 507 0 16.000000 129 507 0 16.000000 139 507 0 16.000000 185 507 0 16.000000 118 507 0 16.000000 174 507 0 16.000000 116 507 0 16.000000 167 507 0 16.000000 122 507 0 16.000000 188 507 0 16.000000 149 507 0 16.000000 126 507 0 16.000000 157 507 0 16.000000 143 507 0 16.000000 149 507 0 16.000000 198 507 0 16.000000 130 507 0 16.000000 183 507 0 16.000000 184 507 0 16.000000 102 507 0 16.000000 173 507 0 16.000000 125 507 0 16.000000 161 507 0 16.000000 163 507 0 16.000000 115 507 0 16.000000 196 507 0 16.000000 121 507 0 16.000000 175 507 0 16.000000 108 507 0 16.000000 121 507 0 16.000000 176 506 0 16.000000 100 506 0 16.000000 148 506 0 16.000000 124 504 0 16.000000 157 504 0 16.000000 148 504 0 16.000000 143 505 0 16.000000 153 505 0 16.000000 100 506 0 16.000000 112 507 0 16.000000 107 508 0 16.000000 187 508 0 16.000000 180 508 0 16.000000 172 508 0 16.000000 130 508 0 16.000000 132 509 0 16.000000 101 509 0 16.000000 163 510 0 16.000000 191 511 0 16.000000 190 511 0 16.000000 162 511 0 16.000000 162 511 0 16.000000 182 511 0 16.000000 137 511 0 16.000000 130 511 0 16.000000 197 511 0 16.000000 153 511 0 16.000000 190 511 0 16.000000 136 511 0 16.000000 155 511 0 16.000000 173 511 0 16.000000 110 511 0 16.000000 117 511 0 16.000000 103 511 0 16.000000 133 511 0 16.000000 173 511 0 16.000000 159 511 0 16.000000 178 511 0 16.000000 153 511 0 16.000000 169 511 0 16.000000 137 511 0 16.000000 160 511 0 16.000000 148 511 0 16.000000 197 511 0 16.000000 124 511 0 16.000000 181 511 0 16.000000 124 511 0 16.000000 174 511 0 16.000000 173 511 0 16.000000 104 512 0 16.000000 187 513 0 16.000000 171 513 0 16.000000 174 514 0 16.000000 148 514 0 16.000000 173 514 0 16.000000 135 515 0 16.000000 199 515 0 16.000000 114 516 0 16.000000 110 516 0 16.000000 131 516 0 16.000000 107 517 0 16.000000 115 517 0 16.000000 137 517 0 15.000000 113 517 0 16.000000 113 517 0 16.000000 162 517 0 16.000000 187 517 0 16.000000 144 517 0 15.000000 193 517 0 16.000000 137 517 0 16.000000 190 517 0 15.000000 191 517 0 16.000000 104 517 0 15.000000 112 517 0 16.000000 199 517 0 16.000000 180 518 0 16.000000 152 518 0 16.000000 182 518 0 15.000000 115 518 0 16.000000 116 518 0 15.000000 180 518 0 16.000000 172 737731bbb1294a15d0b19b63a32faa9a 0 1 qmapshack-1.10.0/test/unittest/input/gpx/gpx_ext_GarminTPX1_tp1.gpx000644 001750 000144 00000006373 12727447634 026502 0ustar00oeichlerxusers000000 000000 Garmin TPX1 Test NS tp1 Track 525 20.0 10.0 100.0 90 60 526 21.0 11.0 101.0 91 61 527 22.0 12.0 102.0 92 62 528 23.0 13.0 103.0 93 63 529 24.0 14.0 104.0 94 64 530 25.0 15.0 105.0 95 65 531 26.0 16.0 106.0 96 66 531 27.0 17.0 107.0 97 67 qmapshack-1.10.0/test/unittest/input/fit/000755 001750 000144 00000000000 13216664442 021511 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/unittest/input/fit/2016-03-12_15-16-50_4_20.fit.xml000644 001750 000144 00000002371 12727447634 025556 0ustar00oeichlerxusers000000 000000 2016-12-03-15-13-03 qmapshack-1.10.0/test/unittest/input/fit/Warisouderghem_course.fit000644 001750 000144 00000112343 12727447634 026576 0ustar00oeichlerxusers000000 000000 tӔ.FIT@c.A1B2Warisouderghem ^$ YK(p.cXQs $ c(AC8  )bfghijk   !"`acH[\]^_delmc.c. #o,w "$%xѿnZ""$o,w #%r Dc.Ec. #o,w^ c.#w _ r c.0#w _ rc.7# v%a rc.#v2a r"c.##vi@` r&c.)#_vG_ r*c.0#?vN^ s1c.>#4v/\[ r9c.L#*viY r@c. [#!vvV rFc.e#wv$T sKc.p#ϫvMU sRc.|#IvU sSc.g#veV t[c.5#vU rbc.#vT ric.Х#v,U rqc.#zvV rxc.k#ov\Y rc.9#dvZ rc.#Yv[ rc.#Nv$Y rc.#CvS rc.#@vQ tc.`#m sc.n#up= sc.#Oub~< sc.6+#u; sc.8#u`= sc.E#Juߦ@ sc.bS#u^A sc.`#uB sc.*n#Eu\C sc.{#uB s c.#uZ@ sc.V#Au< sc.#vuX; sc.#mu: s'c.# rc.^#P4u3: rc.#)6uv+5 rc.#7u84 rc.#-uE3 rc.#-#uhR0 rc.#u?_- rc.#[ul) rc.#ux# rc.+*#tŅ rc.A6# t rc.WB#tt rc.lN#NtK rc.bZ#t" r c.Y#t sc.W#t sc.N#Lt" rc.F#t# r&c.=#ut$ r-c.04#2et% r4c.F+#Tt& r;c.x"#Ct( rBc.G.# rc._#&tK rc.*n#twY rc.|# s#g rc.[#st rc.#tf rc.i#t r c.#t rc.w#t, rc.#tø r!c.# t[ r(c.# t r0c.M#Cs r7c.#s5 r>c.#s rFc./#sx  rMc.z#Rs rUc.#s% r\c.#ls]3 rcc.]#Vs@ rkc.#`?sN rrc.#(sA\ rzc.? #si rc. #+rw rc.#or% rc.!#rǒ rc.O#rh rc.#Sr rc.&#r  rc.0#r] rc.9#Our rc.FC#dr rc.L#SrR rc.vV#JCr rc. `#2r  rc.i#!rF rc.=s#Er% rc.|#r2 rc.m#q;@ rc.#@qM rc.#qZ rc.4#q0h r c.̬#;qu rc.c#qӂ rc.#q% r c.#5{qv r(c.+#jqȪ r/c.#Yq r6c.Z#0Iqk r=c.#8q rDc.#'q rLc.!#*q` rSc. #}q rZc.Q#p rac.a#pT rhc.*#npy" rpc.4#p/ rwc.N?#Kp< r~c.I#pI rc.T#)p W rc.;_#p1d rc.i#pVq rc.t#tqp{~ rc.(#bp rc.̉#QTpĘ rc.A#Fp rc.F#Ppf rc.E#,[p rc.#Np rc.#ApH rc.<#85pz rc.#(p rc.y#p rc.X# pt sc.7#o  sc.#o sc.#o7+ sc.#o6 sc.#opC s c.C#5oP sc.#Ϛo\ sc.#joWi s c.L#zou s'c.#io s.c.#:Yo> s5c.U#Ho s sJc. #3m7L sRc.g# mpY sYc.# mf s`c.$#ls sgc.#jl snc.#QlU suc.@#8l s}c.#lǨ sc.#l sc.[#l: sc.#tls sc. #al sc.v#Nl sc.#;l sc.3##p(lX sc.*#Wl sc.1#>l sc.8#k- sc.2#fkn: sc.,#kG sc.kDU sc. #kb sc.#kp sc.#etk} sc.#_k sc.#2KkY sc.#6kĥ s c.#!k/ sc.#k sc.#Sk s#c.#jD s*c.#j s1c.*#Mj s8c.7#jC s@c.uD#j sGc.`Q#Gj sNc.K^#jC+ sUc.7k#j8 s]c."x#AjE sdc.#jBS skc.#j` src.#;jm syc.Ы#jB{ sc.#|j sc.#4sj sc.#ijA sc.}#_j sc.i#.Vj sc.T#LjA sc.?#Bj sc.+#'9j sc. #z/j@ sc.,#&j sc.7#j4 rc.B#hj rc.}M#ir) rc.jX#i7 rc.Vc#iD rc.Cn#9iOR rc./y#i_ rc.#im rc.#Ui,{ r c.# iˈ rc.#}ij rc.ͯ#rni  r"c.#&_i r)c.#OiH r0c.#@i r8c.#B1i r?c.l#!i% rGc.X#i rNc.E#^ic rUc.1#h r]c.#h rdc.#h@, rkc.f(#hy9 ssc.(4#hF szc.?#hS sc.K#i%a sc.$Y#iZn sc.f#?i{ sc.5t#iĈ sc.#~"i sc.F#)i/ sc.Μ#/id sc.V#^6i sc.߷#[#ib sc.h#]io sc.Uv#Äi| sc.#)iԉ sc.l#yi sc.؞#ti sc.#Zi sc.#i sc.#i" sc.#cik rc.#Ƹi rc.#i rc.#>i sc.x#}i7 sc.:#i  sc.#is sc.#:i% sc.~ #xi2 sc.@#iL@ sc.%#iM sc.2#5i[ s%c.@#s|i&i s-c.FN#tiv s4c.\#lib si shc.S#6i soc.#.iP swc.#%'i s~c.#ci  sc.Z#i* sc.$i' sc.o$qh4 sc. $h6B sc.$UhlO sc.!$ǽh\ sc.$9hi sc.C"$hw sc.'$hH sc.F-$lh sc.(3$1Wh rc. 9$cBho rc.>$-h rc.D$h_ rc.J$h rc.P$*gN rc.vV$\g rc.7\$g> rc.Y$gf  sc. W$;g sc.T$Xg$ sc. R$vng1 s$c.~O$Xg? s+c.L$Bg,L s2c.gJ$,gTY s:c.G$g{f sAc.PE$ gs sHc.B$'fˀ sOc.N@$f sVc.F$sf$ s\c.K$fV scc.zQ$Zf sic.$W$f spc.O${f rwc.V$mgf4 rc.\$Rf rc.Fc$G>fs rc.i$)f rc.pp$!f rc.w$fR rc.}$e) rc./$ie7 rc.Ċ$e0E rc.Y$CeR rc.$eo` rc.$en rc.$pe{ rc.$[eN rc.B$dGe rc.׸$2e rc.l$>e- rc.$ e̿ rc.$dl rc.+$d  r c.$d rc.U$_dJ rc.$d r!c.$d r(c.$wd r0c.$ad, r7c.$KdF: r?c.$5dG rFc. $dtU rMc.#$ d c rUc.:$}cp r\c.Q $mc9~ rcc.h$\cЋ rkc.$Lcg rrc.$;c ryc.$+c rc.$oc, rc.)$dc/ sc.2$Yc2 sc.-<$Nc5 sc.E$Cc8 sc.UQ$;c sc.]$3c sc.h$+c sc.`t$#c sc.$c) sc.G$ cQ4 rc.$b? rc.Ӄ$bI rc.$bT rc.p$b_ rc.̑$bj rc.'$bv rc.s$bB rc.c$5b sc.S$kb sc.C$b: sc.2$׼b s c."$ b sc.$Bb2 sc.$xb sc.$b s&c. $b+ s-c.$b s4c. $b  r;c.i"$bT rCc.($ؽb' rJc. /$˩b4 rQc.|5$bB rXc.;$bVO r_c.4B$mb\ rfc.nH$Ybi rmc.P$dIb_v stc.#Y$8b s{c.}a$.(bm sc.i$b sc.2r$b{ sc.z$]a sc.ǂ$a sc.F$sa rc.Ɖ$a) rc.F$[ax rc.$a rc.$pa[ sc.u$|a sc.Ҏ$Qia  sc.1$Va sc.$rAa& sc.׀$,ac4 sc.*z$Wa B sc.s$aO sc.{$`\ rc.$`i rc.Ћ$g`w rc.$4`9 rc.$`\ rc.$Ζ`~ rc.($` rc.>$gr`ø r#c.T$4`` r*c.i$N` r1c.$;`* r9c.$)`M r@c.$h`o rGc.$5` rNc.$_ rUc.$_! r\c.$_. rcc.$h_< rjc./ $4_>I rqc.E$_`V ryc.Z$΅_c rc.p%$s_p rc.-$ga_} rc.5$4O_ rc.:=$>_  rc.tB$+_B sc.G$_w sc.L$._ sc.$R$=^ sc.^W$M^ sc.\$\^M sc.a$l^ sc.g${^ sc.'l$^ sc.u$q^? rc.$r^  rc.?$Tb^- rc.$Q^5; rc.$7A^H rc.V$0^U rc. $ ^,c r c.$^~p rc.n$]} rc. $o]" r c.$]t r'c.$R]ƥ r/c.8$ü] r6c.$5]j r=c.$] rDc.O$] rKc.$z]` rSc.$i] rZc. $$Y] r`c./$b] sgc.Q;$Yk] smc.F$t]' stc.R$|]2 szc.9^$_]> sc.i$]J sc.nj$w]>X sc.k$1a]~e sc.k$J]r sc.Wl$c4] sc.l$]@ sc.m$] sc.t$\S rc.D|$L\$ rc.$\ rc.$\ rc.D$?\ rc.$\k rc.$\< rc.D$2u\! rc.$b\ ! rc.$~P\! rc.E$%>\'! rc.$+\T4! rc.$\%A! rc.L$R\N! sc.$\_\! sc.y$[i! s$c.$H[w! s+c. $[5! s3c.=$[Ғ! s:c.$$>[o! sAc.k1$[ ! sIc.>$[! sPc.J$5[E! sWc./W$[! s_c.c$[! sfc.g$Vx[! smc.k$b[2! suc.o$M[ " s|c.s$Y7[" sc.w$![?'" sc.2v$~ [x3" sc.t$Z?" sc.r$zZK" sc.q$Z!X" sc.io$vZYd" sc.m$Zp" sc.l$rZ|" sc.Sj$}Z" sc.h$jZ;" sc.@h$|SZ" sc.g$X<$ rc.'$*XI$ rc.$XW$ rc.S$Xb$ sc.$Wn$ sc.$Wz$ sc.$W$ sc.z$Wb$ sc.E$W=$ sc.$WH$ rc.$sWS$ rc.9$]W^$ rc.$HWi$ rc.M$U2W<$ rc.$W$ r c.ԧ$W$ rc.$TV% rc.W$V% rc.$VG% s&c.n$V,% s-c.$aV8% s4c.$,VE% s;c.$qVJR% sBc.$\V _% sIc.$HVk% sPc.s$3V)y% rWc.$sV% r^c.)$- V% rec.$UA% rmc.$U% rtc.;$ZU% r{c.$UY% rc.$ͥU% rc.&$U% rc.$}U{% sc.a$8hU% sc.$TSUK & sc. $q>U& sc.:$)U'& sc.$U4& sc.u$TA& sc.!$TTO& sc.&$T\& sc.M,$T$j& sc.1$6Tw& sc.X7$T&~ sc.C$TV&| sc.N$}T&w sc.Z$pT&s sc.8f$cT~&q sc.q$VT&n s c.}$pITB&m sc.`$X'_ sLc.)$SJ'Z sSc.$SV'V sYc.$Slb'Q s_c.+$YSJn'Q sfc. $S(z'Q slc.$S'S ssc.$>Sk'T szc. $|xSϞ'S sc.$fS4'R sc.m$TS'Q sc.Y$7CS'L sc.E$v1Sb'D sc.N$S': sc.'$S'2 sc.$ S}') sc.$SY'' sc.$R4(& sc.m$sR($ rc.$R#() rc.$YR,1(( rc.$R>() rc.1$?R|L(! rc. $R$Z( rc.$%Rg( rc.D#$Rtu( rc./$ R( rc.<$~RĐ( rc.WI$|Rl( r c.V$dqR( rc.b$eR( rc.^$ORO( s"c.[$9R( s)c.eW$W#Ru( s1c.S$ R ( s8c.O$Q( s?c.?L$Q0 ) sGc.H$vQ) sNc.D$>QW&) sUc.A$Q3) s]c.b=$͇Q}A) sdc.9$qQO) skc.5$][Q\) ssc.^2$FQ8j) syc.5$2Qu) sc.8$Q) sc..$Q׎) sc.U#$Q/) sc.$P) sc. $P޶) sc.E$P6) sc.$P) sc.$ӶP) sc.5$ͧP<) sc.$ƘP) sc.$P* sc.%$zPC* sc.$lP!* sc.˳$IZP-* sc.$HPl8* sc. $6PC* sc.,$$%P=O* sc.M$mPZ* sc.$Pf*# sc.$Or*% r c.$O,*( rc.O$QO*) rc.u$OI*, rc.l$Oؤ*. r%c.Qr$Oa*5 s,c. x$O*; s3c.}$vOs*? s;c.{$aO*B sBc.3$LO*G sIc.$7O*K sQc.$"O+M sXc.]$ O +Q s_c.$}N+T sgc.$N2,+V smc.ί$N8+] ssc.$NC+d szc.$NO+j sc.F$N[+l sc.\$N[g+l sc. $Nr+l sc.$N~+n sc.e$}N+p sc.$oN+r sc.$aNA+q sc.V $TN֬+p sc.$|HN+u sc.$M'p, rc.)d$xM}, r%c.L]$dMJ, r,c.oV$}PMۘ, r4c.O$= s)c.d $X-H2F s/c.e $2H'2M s6c.% $0'H32R r=c.|1 $`H#@2V rDc.= $HL2W rJc.H $H)Y2T rQc.T $Ge2K rXc._ $!G/r2G r_c.6k $QG~2D rfc.v $G62? rlc.M $G2; rsc. $G<27 rzc.M $wG24 sc. $G޾20 sc.z $gG/23 sc. $kG25 sc. $WUG25 sc.= $>G#27 sc.ӑ $G(Gt3: sc.i $G3= sc. $6F3? sc. $Fh)3= sc., $&F63; sc.Ô $F D38 sc.Q $F[Q39 sc.ܗ $]F]3: sc.g $xF/j3< sc. $dFv3< sc.| $wOF3= sc. $:Fl3: sc. $2&F֛3: sc. $F@38 sc. $+Fе36 rc.ݺ $VEa34 rc. $E3. rc. $E3( r%c.z $E3# r,c. $!Ei3$ s3c. $CE4& s;c. $dE4( sBc.9 $nEo!4' sIc.i $ZE.4$ sPc. $FE<4 sWc.ɨ $2EuI4 s_c. $ EV4$ sfc.( $/ E$d40 smc.X $PD{q4= stc. $D~4H s{c.ǀ $DƋ4L sc.s $D4K sc.f $D4H sc.Y $D4G sc.M $D4F sc. P $aD4J rc.S $D4L rc.U $#{D4L rc.X $eD4H rc.[ $OD5G rc.^ $G:D 5D rc.a $$D5F rc.d $ D(5G rc.g $C&55L rc.m $CB5G sc.9t $-CxP5? sc.|z $DC!^59 sc. $ZCk56 sc. $qCry51 sc.F $|C5, s c. $gCĔ5* sc.̙ $RCm5& sc. $=C5 s!c.S $(C5 s)c. $Cg5 s0c.ٲ $B5 s7c. $%B5 s?c." $Ba5 sEc. $B5 rKc. $Bh 6 rRc.H $B6 rXc. $*B #6 s_c. $TBT/6 sec.D $~vB;6 slc. $bBG6 ssc. $NBS6 syc.A $:B$`6 sc. $&'BXl6 sc. $PBx6 sc.U $B6 sc.v $A6 sc. $A6 sc. $GAA6} sc. $ Am6a sc. $̤A6C sc. $A6% sc.; $QA6 sc.\ $nA6 sc.} $[AD6 sc.o $JAo7 sc. $O4A7 rc.I $A"7 rc. $A#07 rc.# $=@_=7 rc. $@J7 rc. $@W7 rc.j $,@e7 rc. $|@Or7 rc.E $ˆ@7 rc. $q@ƌ7 r#c. $j[@7 r+c. $E@>7 r2c. $ 0@z7 r9c.f $Y@7 r@c. $@7 rGc.i $?.7 rMc. $?87 sRc. $?B7 sXc.8 $?L7 s_c.* $?u8 sfc. $?8 smc. $?!8 stc." $?.8 s{c./ $?<8 sc.= $?CI8 sc.K $?lV8 sc.Y $?c8 sc.yY $?o8 sc.8Y $@;|8 sc.X $&@8 sc.X $u;@8 sc.vX $O@28 sc.=e $)Z@8 sc.r $Sd@8 sc.~ $}n@68 sc. $x@8 sc.] $Ђ@8 sc.% $@:8 sc. $$@8 sc. $N@ 9 sc.| $x@>9 sc.D $@&9 sc. $˿@39 s c. $@AA9 sc.r $@N9 sc. $@[9 sc.6 $R@i9 s&c.& $@5v9 s-c.3 $@i9 s4c.\A $N@9 s;c.N $@ҝ9 sBc. \ $@9 sIc.i $J@;9 sQc.v $@o9 sWc.q $@9 r^c.`k $ ;Y r c. $o>;\ rc. $a>(;Y rc. $R>5;e r c.P $D>xC;m r'c. $5>P;r r.c.# $&r>p^;r r6c.) $]>k;w r=c.. $ H>gy; rDc.R4 $2>; rKc.9 $>^; rSc.? $>ڡ; rZc.!E $=U; rac.`J $=Ѽ; ric.X $= ; rpc.f $=o; rwc.t $=; r~c. $= ; rc.# $=]; rc.@ $= < rc.̬ $=< sc.W $=j&< sc. $>=I3< sc.n $=(@< sc. $=M< sc. $}=Y< sc. $<=f< sc. $=s< sc.($=< sc.&$z=c< sc.?4$:=B< sc.A$=!< sc.VO$=< sc.\$x=< sc.mj$8=< sc.w$=< sc.$=< s c.4$=< sc.$z=$< sc.$u=Q = sc.9$p=~= s$c.$k=#= s+c.$f=/= s1c./$b=<= s8c.$W=H= s?c.$@M=PU= sFc.$B=a= sMc. $8=n= sSc.$!.=@{= sZc.k$$#== sac.J0$a== shc.*<$=1= soc. H$=֭= svc.S$A<|= s}c._$<!= sc.j$I<H= rc.u$<o= rc.$<= rc.!$'<= rc.@$q<> rc._$< > rc.$<0#> rc.$N<W0> rc.$t<}=> rc.$f<J> rc.$+Y<W> rc.$uK<d> rc.$><r> rc.$wT<> rc.!$j<n> rc.$f<> rc.>$ݗ<è> rc.$<n> rc.C$<\> r c.$ <J> rc.K*$1<7> rc.7$A<%> r!c.SE$R<> r(c.R$b<? r/c.[`$s<? r6c.m$<? r=c.c{$<*? rDc.$|<7? rKc.k$w<D? rRc.$r<Q? rYc.r$m<^? r`c.$h<pk? rgc.]$c<^x? roc.2$V<? rvc.$I<? r~c.$;<+? rc.$.<Ů? rc.$ <_? rc._$<? rc.4$<? rc. +$ ;,? rc.6$;? rc.B$(;_@ rc.N$; @ rc.aZ$0;@ rc.6f$;-)@ rc. r$7;6@ rc.}$;`D@ rc.$;P@ sc.$;\@h sc.$>;"i@O sc.$;cu@9 sc.$;@- sc.$};@# sc.$=;&@ s c.v$;f@ sc.$}u;{@ sc.-$j;@ s c. $w`;@ s'c.$V;@ s.c.$f;K@ s5c.($v;@n sC$';A sPc.L$/;#&A sWc.U$7;2A s^c.]$;F?A sec.@k$;KA rlc.x$;XA rsc.F$;7eA ryc.ȓ$;qA rc.K$;~A rc.ή$;(A rc.P$;ΗA rc.$;sA rc.H$;A rc. $;uA rc.$;A rc.$;-A rc.S$;A rc.$;8A! rc.>$7y;A' rc.$e;B) rc.$Y;B2 rc.;$M;wBI rc.q$A;)B\ rc.($R;H6Bj sc.0$b;BBj sc.!9$r;OBk sc.A$;h[Bh sc.JD$l;2hBe sc.F$xW;tBi s c.I$5B;ŁBq sc.JL$,;Bw sc.N$;YB| s"c.Q$j;#B s)c.JT$&:B s/c.V$:B s6c.Y$:B s=c.4\$:JB sDc.e$L:(B rKc.m$:B rRc.v${:C rXc.$dt: C s^c.$l:C sdc.z$.e:2#C sjc.`$]:L.C spc.9$V:g9C swc.$C:9FC s~c.8$1: SC sc.$T:_C sc.7$ :lC sc.$9yC sc.5$9VC sc.$n9(C sc.4$59C sc.$9̬C sc.3$Ÿ9C sc.$9qC sc. $9C sc.$49\C sc.'$Θ9C sc.04$h9GC sc.SA$9D sc. M$R9XD rc.X$9D rc.}d$9*D rc.5p$Iu9-7D rc.{$j9CD rc.$_9ePD rc._$@U9]D rc.$J9iD rc.Ъ$?9:vD r#c.$859ւD r*c.B$*9rD r1c.$9D r8c.U$9tD r?c.$8ڶD rFc.[$8@D rNc.$8D rUc.a$8 D r\c.$͹8rD rcc.f$Ũ8D rkc.$8>E rrc.l#$8E ryc.,$u8 "E rc.r6$d8p/E rc.?$T8H r1c.1;$l4LH r8c.@$yV4ZH r?c.D$@4zgH rFc.I$k+4tH rNc.{N$4iH rUc.NS$]4H r\c. X$3WH rdc.\$O3ΪH rkc.a$ȿ3FH rrc.f$A3H rzc.jk$34H rc.=p$33H rc.u$i3#H rc.y$%T3H rc.~$>3 I rc.P$)3I rc.$3\#I sc.$300I sc.ޛ$2=I sc.$2II sc.=$2VI sc.l$ 2cI sc.$2UpI sc.$2*}I sc.$2I sc.*${2ҖI sc.&$j2I sc.$P]2eI sc.$P2#I sc.K$C2I sc.$A72I s c. $*2_I sc.Y$2I sc.$$ 2I sc.$|1iJ s$c.$:1 J s*c."$1J s0c.D%$1\$J s7c.X!$1@1J s>c.l$1%>J sEc.$1 KJ sLc.$j1WJ sSc.$%U1dJ sZc. $-@1qJ sac. $5+1~J shc.$<1J soc.$D1fJ svc. $K0JJ s}c.@$0/J sc.$0hJ rc.$0J rc.$V0J rc.$0J rc.$r0JJ rc.v$^0K rc.U$uJ0K rc.3$=60K rc.$"0,)K rc.$ 0e6K rc.϶$/CK rc.ݰ$/PK rc.$/]K rc.J$j/9jK rc.$ /vK rc.$հ/K rc.n$/MK rc.$$?/K rc.$/K r c.${/aK rc.H$_n/K rc.$a/K rc.&$T/uK r&c.3$H/K s-c.?$=/;K s5c.6L$2/L s$B.; M sc.l$4.wM sc.$"'.#M sc.$]./Mw sc.$ .,$+O s1c.I$+vO s7c.T$+O s>c.R`$+\O sEc.k$+O sLc.j$p+qO rTc.i$Y+O r[c.h$B+O rbc.g$++U P ric.q$x+GP spc.{$ +9#P swc.U$j*+0P s~c.$*=P sc. $*GP sc.*$;*WRP sc.;$*\P sc.$%*|hP rc.Ԍ$J*tP rc. $o*P rc.m$n*P rc.$[*P rc.$MK*P sc.D$:*ذP sc.$)*P sc.$*DP sc.$*P sc.H$)P sc.$)4P sc.w$)Q sc.$Ľ) Q sc.$)#Q sc.>$)s(Q sc.$)5Q s c.$q)SCQ rc.$[)PQ rc. $E)s^Q r#c.)$/)lQ r*c.H$)yQ r1c.h$)"Q r9c.$(Q r@c. $(BQ rGc.+$D({Q rNc.6$(Q rVc.7B$̮(Q r]c.oM$((Q rdc.X$T(aQ rkc.c$(Q rrc.n$x(Q ryc.z$j( R sc.*$](cR sc.‘$P(&R sc.Z$C(3R sc.$6(9AR sc.$o)(NR sc."$W([R sc.$?(iR sc.R$'(WvR sc.$'R sc.$'R sc.$'-R sc.~$'uR sc.'$W'R rc.$'R rc.z+$'lR rc.#8$]'R rc.D$'R rc.vQ$ 'dR rc.^$b|' S r c.j$p'S rc.rw$e'\&S rc.$gY'4S r!c.Ő$M'AS r)c.n$B'SOS& r0c.$m6'\S+ r7c.$*'jS/ r?c.j$'KxS2 rFc.$r'S/ rNc.~$'S2 rTc.w$'gS= sZc.p$i)'2SH sac.h$:'SS sgc.a$J'S^ snc.Z$['Sk stc.:$l'bSx s{c.*$:t'aS sc. $u|'`S sc. -$'_T sc.9$'^T sc.F$$'^T sc.S$_'](T sc.`$'\5T sc.m$ԭ'[BT sc.z$'ZOT sc.$'\T sc.$'jT sc.ˤ$'WwT sc.߲$'T sc.$'T sc.$'ST sc.$'T~ sc.$'T| sc.l$h'yT{ rc.$М'Tz rc. $9'tTw r c.\$$'Tk rc.2$ 'nT` rc.@$r' U\ r c.LO$ۭ'iU^ r(c.]$C'%U` r/c.k$'d3Ua r6c.c.$}'_NUb rEc.ܖ$'[U` rLc.,$N'YiU^ rTc.|$'vU\ r[c.$'TUY rbc.$'ёUV ric.k$'OUQ rqc.$X'̬UI rxc. $'JUA rc.[ $)'U= rc.$'DU8 rc.%$'U5 rc.K4$c'?U0 rc.B$'U+ rc.P$4': V$ rc.;_$'V rc.m$'5&V rc.{$n'3V rc.+$'/AV rc.{$?'NV rc.˦$'*\V rc.$(iV rc.j$y($wV rc.$ (V rc. $J ( V rc.Z$(V rc.$(V rc. $(V r c.J$(V rc.'$U(V rc.5$!(V r c.:D$'%(V r(c.R$(( V r/c.`$+( W r6c.*o$a/(W r>c.z}$2(&W rEc.ʋ$26(4W rLc.$9(}AW rTc.i$=(NW r[c.$l@(x\W rbc. $C(iW ric.Y$>G(swW rqc.$J(W rxc.$M(mW r~c.?$X()W sc. $*c(W sc. $m(W sc.@ $Ux(^W sc.$ $(W sc./ $(W sc.): $(W sc.D $Т('W sc.N $(W sc.KY $p(QX sc.c $A(X sc.m $(zX sc.y $(+X rc. $(9X rc. $S([FX rc. $(SX rc. $(`X rc. $(c.9!$,'uY rFc.E!$' Y rMc.|Q!$' Y rTc.m\!$''Y r[c.]g!$'4Y rbc.Mr!$'PAY} ric.=}!$'NYx roc..!$'ZYo rvc.!$'gYc r}c.!$'WtYY rc.!$}'YM rc.!$p'ڍYC rc.߾!$c'Y; rc.!$V']Y5 rc.!$I'Y, rc.!$<'Y rc.h!$0'Y rc.y!$2'Y rc.!$e 'Y rc.!$&Y rc.!$&Y rc."$& Z rc."$1&Z rc. "$d&!Z rc."$&-Z rc."$o&;Z rc.s"$n&NHZ rc.A"$OY&}UZ rc.""$C&bZ rc."$q/&oZ s c.="$&|Z sc."$T&Z sc. "$%Z sc.  qmapshack-1.10.0/test/unittest/input/fit/2015-05-07-22-03-17.fit000644 001750 000144 00000153303 12727447634 024155 0ustar00oeichlerxusers000000 000000 .FIT@㦍y/A1hBy/C   y/㦍hy/ y/ y/}-yTy^D  y/EO y/' <2F    452G    edge810 <(6H       Gm<I J  y/~#tv9 Kh y/; y/#9`v7 6 y/ #Fv#9 8 y/ #uDv_%= 2 y/ #KDv&= $[ y/9 #JEv&< ~[ y/ #KvU+8 5 y/O#Ov-6 y< "y/#rVv+33 H %y/#cvl<. NQ ,y/#ҁvS* S -y/#1v3V) CE 0y/#&v.^. B 1y/#v_2  2y/!#pv,a6 5  3y/#Zvb8  4y/#vc9  6y/#͙vg6 . 7y/#yvDj3 4? 8y/#Ovl1 F :y/I#vr, zO ;y/#vv+ U ?y/#v' "Z Ay/N#hv?% !X Dy/#xv& T Gy/#'v:) H Hy/#Ivʞ*  Iy/}#-v#, / Jy/Ⱥ#.vJ. n My/#7v. B Ny/Z#vY- C Uy/#v/ ? Xy/%#vz3 l  Yy/#v74  Zy/D#v7  [y/#v8 = \y/W#vL8 ? by/4#vY;  ey/<#pvY>  hy/<#pvYA  qy/<#pvY@  y/<#pvY@  y/#v?  y/#=v:  y/#v9  y/#v7   y/'#"v4 m  y/#LvT4 % y/x#v3 m- y/#v2 0 y/#v1 3 y/q#v/ 6 y/#Zvq0 w7 y/ø#Zvs0 7 y/#v1 < y/^#:vt1 %; y/n#fv" / A y/#v . 2A y/#0v/ @ y/#v3/ @ y/#v"/ = y/#v/4 q y/#6v64 6 y/Z#Mv84 8 y//#.tvJ2 a> y/#8Svb5 @> y/#&7vRw6 B; y/#ovΉ5 < y/$# v6 < y/'#2v}6 : y/~2#cu5 Y= y/7#9u$4 m= y/D;#Mu4 G? z/SC#ua3 ? z/%E#Zu4 > z/F#uj4 ; z/M#qu3 : z/&R#u3 8; z/[#u5 : z/l#u7 a8 z/t# u6 ? z/z#_ug5 NF &z/_#muH5 F +z/#7ui9 G ,z/#DuB!: IC /z/#up&? A 1z/#u)A : 2z/i#u+D : 2z/; 4z/W#uN.G ~; 7z/S#u3J > 9z/p#NuR7L @ =z/#u>O @ Cz/#uJQ N Fz/#,uRI L Iz/?#vuZ[D  Jz/M#Hu ^A  Lz/W#Fub@  Nz/'#uf> L Oz/#"uh< M Pz/Y#unk; -N Sz/w#uv8 3; Uz/#+uE}7 g< ]z/g#u5 = ^z/|#u05 > ez/#3v2 z @ mz/#4vJ3 K @ nz/h#8v4 Y ? vz/#Yv@2 ? ~z/S/#Suv5 G< z/4#yvo8 K z/):#Z|v < ?H z/?#}v> ~D z/D#~v@ C z/gG#~v8A B z/FO#~v C pB z/Y#7~v*D 6F z/b#{v3D A z/xe#Ryv5C @A z/j#nvN>>  z/m#%fvC=  z/t#UvzO9 E z/v#QvR8 TE z/ۀ#?va3 v z/Ћ#0 2 z/#v> 4 z/>#yvs= 6 z/#v[= 5 z/#Uv>= 5 z/L#<-v> 5 z/#Gv? 6 z/\#[v; g8 z/^#[v < 6 z/i #ZvJ= 6 z/#Xv= 3 z/g#Wvn > 5 z/%#wUv[)> 5 z/b(#Tv+= 5 z/2#7Rv^5< K6 {/KE#?NvF< 8 {/mY#GvZ@ ? {/{]#Ev^C $A {/e#EBvoeH e@ {/f#Av0gI @ {/q#)=vqM ? {/zs# P{/#P3vt 8 Q{/]#R3vSt #9 Z{/I#3v-t = ^{/: `{/<#4v2m O a{/I#4v k JL b{/f#3vh O d{/#0v*b R f{/0#@+v*` N h{/##v$a [ F j{/#>vf B k{/#0vXj C n{/#> vj ? o{/#vi 0 q{/#iusd 9 s{/#wu` 9 t{/#uu!^ ! v{/Q#u(W # w{/|#u+R  x{/3#u'/M ! y{/#5u72K A {{/#u8J z= |{/#Bu:J P= {/#"uEIK 9 {/2#>uKK $8 {/#uSQ 4 {/E# u+VR 2 {/#u5[V 0 {/##@u]W Q0 {/##ubX u1 {/B&# uaeW X1 {/O8#fu?yV 1 {/?#Bu4W 3 {/MF# u,W  {/X#uu8X 1 {/j#cuMZ 1 {/Qm#>buZ ;1 {/Av#V[u] . {/|#Vu_ , {/#Pu` . {/҆#Iuc 6 {/#Fuc 7 {/#tre D |/ߗ#x)t"g > |/#tm ; |/# tTo +; |/ʠ#to > |/K#s]l 5@ |/# D|/#\Hsi ; J|/!#2sj < R|/#/s//i n= [|/4#rtDi ? a|/#rRl : b|/#Nr,Tm : c|/#r_Vn : g|/|#r._p 9 i|/#$r4cr 8 m|/f#_rjt 6 n|/#+rlu 7 q|/H#rrv 7 w|//#r@v 4 }|/1# }rw w: |/w# |/?#Ecru E |/#brMu zH |/9 |/B#cr|x JJ |/i#drȥ} B |/B#ier = |/]#fhrG Z 9 |/#lr- 6 |/#mr~ M 6 |/# |/yr > |/.+#Jxr  > |/=1#%wr | A |/g;#ur; m? |/cI#vrG ? |/U#yr A |/;^#j|r A |/a#}r` B |/Rc#Z~r B |/np#r+ A |/|#r@8 A |/#rXF @ |/#r[H ? |/#Gr#S |@ }/#r[ A }/u#r^ B }/ #ܸr1i wC }/P#ru cA }/#r7w A }/# r A }/z#r @ &}/8#Pr{ A -}/6#sG @ /}/#s A 8}/#s @ 9}/# s ? A}/#1s = G}/#T?s O? H}/#As ^> P}/#QSs '= U}/#G^s = Y}/ #,gs > `}/v#wsy = h}/#هs < l}/Y!#esJ < n}/##sZ < u}/w-#)s_" = {}/6#sH- < }/C#s< = }/I#9sC = }/O#sK < }/W#/sU = }/OZ#sQY < }/d#s0f =< }/2i#s#k !; }/j#sl < }/r#sru @ }/y#:sp} = }/# tڈ ? }/̄#8 t_ > }/9 }/h#t ? }/;#X"tP ? }/#b-t ( > }/Ȧ#9t3 @ }/#PAt  = }/X#Jt  = }/}#Yt  p? }/#ct!  = }/#^ft_ &= }/#}pt] x< }/^#^xt =< }/;#t  L; }/~#"t^  ; }/I#:t  < ~/.#ٌt  < ~/O#t  e: ~/#t  : ~/#CtN,  < ~/#et93  U; ~/T##st8  9 !~/a.#t~B ! m 9 #~/1#htE # 9 )~/<#tP % : /~/FF#3tY ' - : 1~/I#ӡt\ ( - ; 7~/S#te *  : =~/]#էtn + < A~/d#\tu - 7< D~/i#qtiz - J< K~/u#3tv / == Q~/ƀ#t 1 +< T~/y#tN 3 E< V~/#t 3 < ^~/#t 7 /; b~/#ۿt 8 ; e~/#Kt? 9 > < k~/L#t 9 hH q~/#t = kF r~/w#tw = D v~/#tC > > |~/#(t @ > ~//#{t C = ~/?#0t D ; ~/#t^ F X: ~/#tW G 9 ~/#t I A ~/#t K ? ~/ #t) M @ ~/l#tR N X< ~/M#Nt Q < ~/:#t& S ; ~/ #tY( T P; ~/&#ot. U < ~/*-#t5 X : ~/,.#t7 Y j : ~/i4#tK= X 4= ~/=#tKG [ = ~/E#ugO \ = ~/L# uW ^ ?= ~/S#u_ `  > ~/[#+ui b > ~/yb#*ur d A ~/d#,ut d kA ~/n#+?u f C ~/u#Kum g A ~/9 ~/~x#Ou i z B ~/}#Zu i ZC ~/#ku m A ~/:#$pu n C ~/#|xu p @ ~/#uٸ s O> /# u u H= /#'u. y ; /J#׼u z *; /#Zu } X= /#ku ~ = #/#u g? %/#u ? */#&u @ +/#lu C -/"#|ug %@ 0/#uF B 8/ #u-, H 9/#|v. G @/u#v9 gF D/6# vl@ H H/ #vF K O/$#HvQ I Q/#bvU J U/H!#v.\ A [/+#9v(f A `/5#vgo 7B c/;#vu tB j/{I# v A p/U#!vv @ q/W#?"v @ y/Vh#"%v tA /%t#T'v5 @ / v#'v A /#*v ? /R#,v H? /#i-v j= /#/v @ /͟#0vP > /#1v < /#4v ? /w#6v 7@ /X#e7v @ /#;v> B /#3>vL pA /y#@v7 A /#Cv) A /x#rCvp+ 1A / #Ev8 @ /v#6Gv8> = /J#IvrH aB /'##JvN KA /)#(Lv9U B /6#Ov\a D />#Qvi > /A#KRvk > / M#pTvv @ /HS# UvB| > /Y#Vv 0? /d#WvԌ D? /r#}[vQ 4A /z#V\v > /|#c\vd A /8 /#=_v A /X#bvw AA /h#(dvQ A %/K#gv3 yF -/F#Fkv- A //#`lv A 4/!#nvG C  ΀/#qv ; р/#v K: ׀/s#v \8 ؀/%#v f< ۀ/љ#v  I ‮/#\vN A 怮/#kvs ? 耮/O#vD  퀮/T#vv 7 /#9v f7 /ҿ#v 6 /#v7 Y6 /K#ؚv ; /#v ; /#(v ; /W#Ov9 ): /#ڏv 18 /#vq < /#8v" (: /:#v;$ 9 /;#vf0 p9 !/U#\v8 > "/#vz: > &/=#v\@ E< */ #vE s : +/d#v2G  9 0/##֑vZM  9 4/)#v3R" 8 5/^*#:vpS# 7 8 :/8 ;/d2#Jv[)  7 =/4#vh], 7 @/8#v`. Y 6 E/>#vif4 5 G/@#[vh5  4 L/F#=vn: Q 6 O/J#v%q< 5 T/qO#rv3v? 5 X/S#v_zA 8 ]/:Y#yvB B > d/_# vD ~ 8 n/g#xvH 6 p/h#v@I 6 u/k#vK ; / r#v3N  = /s#UvO > /x#WvLP '< /}#vK  /#5wI pE /##wG J /#swF K /t#/wF H /}#wG lG /j#wG |F /ҡ#wG EC// /e#pvGJ (B /#v2K +B /#v:K A /#vL C /k#^vJ#M C ȁ/#vn,O nB Ё/#ʹv9T > ؁/ئ#vyHX =; ہ/#vMY z; ߁/נ#;vTZ &> 聮/#wv\eY \B 쁮/F#kvlY ; /#\evpY ; /q#/_vtY R< /p#Svb|Z }= /ٞ#$QvT~Z > /#LvCZ ? /a#Ev<\ D< /߮#"Av_ [< / #;vՕb < /#8vb (< /#2vud = /2#,vXe < /#v_j : /q#vj ; /#v{o ; "/7#@ut 9; #/#~ut ; )/B#Hubz 4 +/$#0u{ ^4 0/# u~ 4 1/S#Cu 4 5/1#\u% 3 >/+#u o3 G/"#u 5 Q/3#u" 6 R/p5#Hug$ 6 Y/A#}v0 9 `/>P#v= 5 f/7 i/?e#jv;Q F4 k/i#dvcU~ m6 r/y# vd| : u/ۀ# vNk{ ; x/#u vrz t> y/q#( vtty > |/h#2v{v ; }/#vn~u D  /#u҃s d4 /g#un 7 /#ujk 8 /#uDg : /#ua s /I#@u` ^ /f#{u[  /#u'X  /m#uX  /#?u:V I7 /#nuU =6 /#(uQ  /R#uR 1 /# uR " /a#˺uJ 4 / #4uC ; /#8u> ; /#u= +< /%#u[= @ /4#u)C < /#u0+E ? /#)v:-H ? /l#.v4O : ‚/>#Zv6O < ɂ/##U(vEU < Ђ/)#F#:v_ 9 /?#)v` 9 /CF#wvb 3 /+N#v̲a H3 /U#?vw] ^: /\#1w9Z  /^#WwoZ g /d#nwW  /j#wT  /r#wN  %/|#!wH p ./#'wD I //ɢ#m(wGD H 0/#!)wC I 9/i#.wQ7B WE B/#4w1LC k H/V#6wbVE  O/#9wdaE / U/#n=whlD  V/a#2>w+nD  Y/4#=;w5sD " [/I#B5wCwB k4 ]/#.w{@ {8 e/\ #SwA o3 h/ #wE , i/ #3wɑF { , l/#wkI 4" m/0#wI  s/#wJ { y/O#twZK  /;#wZI  /#wZJ  /#wK  /6 /#wK  /#wK  /#wK  ̓/#wK  ⃮/#wK  /#wK  /#wL  /#wK  /#wK  )/#wK  7/#wK  A/#wJ  Q/#wJ  R/#wJ  _/#wK  l/#wK  x/#wJ  /#wJ  /#wJ /L  /#wJ  /#wJ  /#wJ  /6 ΄/#wI  ڄ/#w˗J  脮/#w˗J  /#wΗJ  /#wΗI  /#wΗI 3/#wΗI I/~#rwΗI \/~#rwΗI j/~#rwΗI q/x#iwΗI /x#iwΗI /x#iwΗI /l#cwΗI /l#cwΗI υ/Y#WwΗJ ᅮ/Y#WwΗI 녮/5 /d#qwؗI /d#qwؗJ /m#|wߗJ +/m#|wߗJ ;/#lwI I/#wI [/#wJ o/#wJ /#wK /#w K /#w J †/#wK Ն/#wJ 醮/#w<K /#w<K /#w<K /#wFK /5 !/#wFL //#wFL =/#wkM M/#wkM ]/#wsM l/#wsM y/#wsM /# wxM /# wxN /# wxN /# wxM /%#wN ·/%#wN 懮/#9wN /#LwN /#LwN '//#dwM @//#dwN C/4 X/.#wM q/.#wM /,#wM /1#wN /1#wN ˈ/-#wN ߈/-#wN /8#wN /8#wN /8#wN /C#swN -/C#swN wW /#>wW /#"wX /#"wW ̚/#wX /#wX /#w'X /. /#w'X /#w'X '/#w'X >/#w'Y V/#w(Y m/#w,Y /#w,Z /#w7Z /#w7Z /#w=Z ӛ/#w=[ 䛮/#wE[ /#wE[ /#DwE\ /#DwE\ -/#DwE\ 1/- =/#FwE\ L/#FwE] Y/#GwE\ k/#GwE\ ~/#GwE\ /#RwE\ /#RwE\ /#DwE\ /#DwE\ Μ/#DwE\ ޜ/#PwE] /#PwE\ /#TwE\ /#TwE] !/#IwE\ 3/#IwE\ F/#IwE\ V/#awE\ ]/- j/#awE] s/#wE] /#wE] /#wE\ /#wE] /#wE] Ɲ/#iwK] ؝/#iwK] 蝮/#w^ /#w^ /#w^ /#w^ //#w^ C/#w_ W/#w_ l/#w_ ~/#w_ /, /|#Sw_ /|#Sw^ /m#w^ Ξ/m#w^ ឮ/i#w^ /i#w^ /Z#w] /Z#w] 5/Z#w] G/Z#w] V/]#w] f/]#w] |/#wÛ] /#wÛ] /#wɛ] /, /#wɛ] ˟/#wޛ] ޟ/#wޛ] 쟮/#wޛ] /#w] /#w] /#w^ //#w] E/#w1] Z/#w1^ h/ #w>^ |/ #w>] /#wG] /#wG^ /#wJ^ ˠ/#wJ] ޠ/#wJ^ ᠮ/+ /#wJ^ /#wJ^ /#wO^ )/#wO^ ?/.#w]^ S/.#w]_ h/-#w]_ /.#w^_ /.#w^_ /=#wl` á/=#wl` ֡/B#wq` /B#wq` /=#wqa /+ /=#wqa (/3#wqa 9/3#wqa G/-#wqa Y/-#wqa m/-#wqa /,#wqa /,#wqa /*#wqa /*#wqa /#wqa Ѣ/#wqa 墮/#wqa /#2wx` /#2wxa /#Awx` &/#Awxa 7/#*wx` 9/* F/#*wx` X/#*wx` g/#<wx` y/#<wxa /#Lwx` /#Lwxa /#Lwxa /#Vwxb ʣ/#Vwxb ף/#Kwxb ߣ/#Kwxb /#Kwxc /#Awxc /#Awxc #/#Awxc 5/#%wyd J/#%wyd ^/#we e/* p/#wd /#!we /#!we /#)we /#)we ͤ/#Qwe ܤ/#Qwe /#Qwf /#Iwf /#wf */#wf @/ #wÜe S/ #wÜf f/ #wÜe t/2#&we /2#&we /) /D#,we /D#,we /;#we ѥ/;#we 楮/,#wd /,#we /(# wd /(# wd 1/#wc C/#wd T/#wd h/#wc {/#wc /#!wd /#!wc /#%wc /( ʦ/#%wd ম/#wc /#wc /#wd /#wc #/#wd 1/#wd C/#wd X/ # w d h/ # w d x/#w%d /#w%d /#w%e /#w0e /#w0e ħ/#w0e Ч/#w0e 䧮/#w0f ꧮ/( /#w9f /#w9f /$#w@f #/$#w@f ./$#w@f >/'#wDg F/'#wDg J/'#wDg V/'#wDg i/#wDg z/#wDg /#wGg /#wGh /#wGg Ш/#wGg 樮/#wGh /#wGh /#wLh /( %/#wLh ;/,#w^i Q/I#wxi f/I#wxi y/Z#wi /Z#wi /Z#wi /i#wi Ʃ/i#wi ֩/#wi /#wi /#wɝi /#wɝi +/#wɝi 9/#wɝi B/' J/#wɝh Y/#wɝh j/#wɝh /#wɝh /#wםh /#wםh /#wםh Ī/#wםh Ӫ/#wםg 誮/#wםg /#wםg /#wםg /#wٝg (/#wٝg :/#wٝg L/#wٝg b/#wg n/' w/#wg /#wg /#wg /x#wg ū/x#wh ۫/x#wh /x#wh /`#wi '/T#wh ?/T#wh R/K#wi g/K#wh {/B#wi /B#wi /' /H# wi /H# wj ì/C# wk լ/C# wj 묮/;#wk /;#wk /;#wk /5# wk 8/5# wk L/5# wk W/5# wl [/5# wl i/8#wl y/8#wl /@#wl /@#wm /G#wm ĭ/G#wm ƭ/& խ/G#wm 筮/`#:wm /`#:wn /i#Kwn /i#Kwn 3/o#Ew!n F/o#Ew!n ^/n#!w"n o/n#!w"n /_#w"n /_#w"n /_#w"o /Y#w"n /Y#w"o ̮/E#w"o ߮/E#w"o 쮮/E#w"o /% /#w"o /#w"o !/#w"n -/#w"o >/#w"n L/#w"o Y/#w"o i/#w"o y/#w"o /#w"n /#w"n /#w"n /#w"n ů/#w"o ԯ/#w"o 篮/#w"n /#w"o /#w$p /% !/#w$o 3/#w3o F/#w3p Z/#wFq m/#wFq /#wFq /#wFr /#wFr /#wFr /#wFr ̰/#wFr ۰/#wHs 鰮/#wHs /#wIs /#wIt $/#wIt 9/#wIu K/$ N/#wIu g/#wIu /#wSv /#wSv /+#wv /+#wv /V#ww ұ/V#ww 汮/V#ww /\#wv /\#ww /Y#wv -/Y#ww >/l#wÞw K/l#wÞw ^/l#wÞw k/u#wɞw w/$ |/u#wɞv /l#wɞw /l#wɞw /l#wɞw /O#wɞw Ӳ/O#wɞx 岮/?#wɞw /?#wɞw /9#wɞw /9#wɞw -/E#wӞw @/E#wӞw O/E#wӞw _/F#wԞw l/F#wԞw }/7#wԞw /7#wԞv /D#wv /# /D#wv /D#wv ӳ/\#wu 糮/\#wv /`#wu /`#wu +/U#wv E/[#wv Y/[#wv p/a#wv /a#ww /_#ww /\#gww ϴ/\#gww ϴ/# 㴮/b#Xwx /b#Xwx /a#Rww /a#Rww 3/S#Mww G/S#Mww ^/H#<wv u/H#<wv /C#:wv /C#:wv /+#?wv Ե/#3wv 赮/#3wv /" /#Eww /#Eww 0/#hww C/#hww T/#cwx d/#cww v/'#Xw&x /'#Xw&x /'#Xw&x /#Sw&x /#Sw&x ̶/#Rw&x ߶/#Rw&y / #Ww&y / #Ww&y /#Sw&y '/! 6/#Sw&y K/#Yw)y \/#Yw)y t/#w)y /#w0y /#w0y /#w;y ɷ/#w;z ۷/#w=z /#w=z /#w={ /#w@{ /#w@{ 2/#wD| 3/#wD| G/#wD{ S/! Y/ #wD| l/ #wD| /#wD| /#wD| /#xwD| /#xwD| ϸ/#zwD| ⸮/#zwD| /#qwD| /#qwD| /#twI| 4/#twI| G/#ZwQ| ]/#ZwQ| o/ #Ew^| /! / #Ew^| /#Dwh| /#Dwh} /#Gwl| ѹ/#Gwl} Ṯ/#9ws} /#9ws} //#w} //#w} &//#w} :/#w~ H/#w~ Z/#w} k/#w~ |/#w~ /#w~ /#w} /  /#w~ /#w~ Һ/#w~ 亮/#w~ /#w /#w /#w /#w ,/#w =/#w J/#w ]/#w n/#w ~/#w /#w /#w /#w /#w Ȼ/#w ׻/ ڻ/#w /#w /#w /#w /'#w 5/'#w J/-#w \/-#w l/.#wß /.#wß /X#w /X#w /x#w ȼ/x#w ؼ/#w 鼮/#w /#w / /#w '/#w >/#w V/#w j/#w y/#w /#w /#w /#w /#w Ž/#w ؽ/#w 齮/#w /#w# /#w# /#w, 0/#w, 0/ E/#w, Y/#w, l/#w4 /#w4 /#wA /#wA Ͼ/#wN 侮/#wQ /#wQ /#wQ #/#wQ 6/#wS H/#wS U/#wS \/ e/#wS t/#wS /#wS /#wS /#wS /#wZ /#1wy /#1wy ̿/#1wy ܿ/#w 濮/#w /#w /#w /#w )/#w~ 2/#w >/#w~ O/#w~ `/#w~ q/#w /$#wϠ / /$#wϠ~ /$#wϠ~ /##wϠ /##wϠ~ /##wϠ /#"wϠ /#"wϠ /##wϠ /##wϠ /#!wϠ +/#!wϠ B/#DwϠ S/#DwϠ d/#DwϠ r/#>wϠ /#>wϠ /#=wϠ /#=wϠ /#=wϠ / /#AwϠ /#AwϠ /#FwϠ ®/#FwϠ ®/#NwϠ #®/#NwϠ 5®/#UwϠ I®/#UwϠ [®/#dwϠ n®/#dwϠ ®/#^wϠ ®/#^wϠ ®/#^wϠ ®/#cwР ®/#cwР ®/#owР ®/ ®/#owР ®/#owР î/#wР î/#wР )î/}#wР 5î/}#wР Bî/}#wР Qî/x#wР cî/x#wР mî/x#wР yî/#}wޠ î/#}wޠ î/#}wޠ î/#wޠ î/#wޠ î/#wޠ î/#wޠ î/#wޠ î/#w Į/#w Į/ Į/t#{w &Į/t#{w 4Į/t#{w AĮ/|#ow TĮ/|#ow bĮ/#pw rĮ/#pw Į/#pw Į/}#w Į/}#w Į/}#w Į/#w Į/#w Į/#w Į/#ew Į/#ew Į/#ew Į/#ew Ů/#lw  Ů/#lw  +Ů/#aw  8Ů/ 9Ů/#aw  EŮ/#aw  RŮ/#bw  aŮ/#bw  qŮ/#bw  Ů/p#Zw  Ů/p#Zw  Ů/p#Zw  Ů/v#aw Ů/v#aw Ů/v#aw Ů/s#ew Ů/s#ew Ů/x#nw Ʈ/x#nw Ʈ/x#nw *Ʈ/{#w 7Ʈ/{#w EƮ/#w0 \Ʈ/#w0 dƮ/ oƮ/#w9 |Ʈ/#w9 Ʈ/#w9 Ʈ/#w9 Ʈ/#w9 Ʈ/#wA Ʈ/#wA Ʈ/#wB Ʈ/#wB Ǯ/#wL Ǯ/#wL /Ǯ/#wL DǮ/#wQ ZǮ/#wQ pǮ/#wQ Ǯ/#wQ Ǯ/ Ǯ/#w\ Ǯ/#wh Ǯ/#wh Ǯ/#wh Ǯ/#w Ǯ/#w Ǯ/#w Ȯ/#w Ȯ/#w $Ȯ/#w 6Ȯ/#w HȮ/#w TȮ/#w bȮ/#w uȮ/#w Ȯ/#w Ȯ/#w Ȯ/#w Ȯ/#w Ȯ/ Ȯ/#+w Ȯ/#+w Ȯ/#+w Ȯ/#,w ɮ/#,w ɮ/#Ew /ɮ/#Ew Aɮ/#@w Sɮ/#@w aɮ/#@w bɮ/#Ew mɮ/#Ew }ɮ/#Ew ɮ/#w ɮ/#w ɮ/#w ɮ/#w ɮ/#w ɮ/#w ɮ/ ɮ/#w ɮ/#w ʮ/#w ʮ/#w "ʮ/#w 2ʮ/#w Dʮ/#w Oʮ/#w bʮ/#w vʮ/#w ʮ/#wš ʮ/#wš ʮ/#wš ʮ/#wѡ ʮ/#wѡ ʮ/#(w ˮ/#(w ˮ/ $ˮ/#@w <ˮ/#@w Kˮ/#Bw ^ˮ/#Bw qˮ/ #7w yˮ/ #7w ˮ/ #7w ˮ/ #7w ˮ/$#;w ˮ/$#;w ˮ/#>w ˮ/#>w ˮ/##<w ̮/##<w ̮/&#5w *̮/&#5w <̮/,#3w  A̮/ O̮/,#3w  c̮/(#)w  w̮/(#)w  ̮/#9w  ̮/#9w  ̮/#/w  ̮/#/w  ̮/ #6w  ̮/ #6w  ̮/ #6w  ͮ/#w  ͮ/#w  2ͮ/#w  Gͮ/#w  \ͮ/#w  jͮ/#w  mͮ/ |ͮ/#w  ͮ/#w  ͮ/#w  ͮ/#w  ͮ/#w  ͮ/#w  ͮ/#w  ͮ/#w  ή/#w  ή/#w  .ή/#w  Cή/#w  Xή/#w  lή/#w  {ή/#w  ή/#w  ή/ ή/#w  ή/#w  ή/#w  ή/#w  ή/#w  ή/#w  Ϯ/#w  Ϯ/#w  -Ϯ/#w  @Ϯ/#w  PϮ/#w  ]Ϯ/#w pϮ/#w Ϯ/# w Ϯ/# w Ϯ/# w Ϯ/#w Ϯ/#w Ϯ/~ Ϯ/#w" Ϯ/#w" Ϯ/#w0 Ю/#w0 Ю/#w0 )Ю/#Ew1 <Ю/#Ew1 PЮ/#Nw< _Ю/#Nw< rЮ/#2w< Ю/#2w< Ю/#$w< Ю/#$w< Ю/#w< Ю/#w< Ю/#w< Ю/#w< Ю/{ Ю/#w< Ѯ/#w< !Ѯ/#w< 5Ѯ/#w< DѮ/#w< TѮ/#w< dѮ/t#w< qѮ/t#w< Ѯ/u#$w= Ѯ/u#$w= Ѯ/u#$w= Ѯ/r#1w= Ѯ/r#1w= Ѯ/h#"w= Ѯ/h#"w= Ү/[#7w= Ү/[#7w= Ү/w !Ү/[#7w= 2Ү/B#3w= @Ү/B#3w= OҮ/##w= ]Ү/##w= kҮ/##w= yҮ/#Iw= Ү/#Iw= Ү/#>w= Ү/#>w= Ү/#>w= Ү/#+w= Ү/#+w= Ү/#+w= Ү/#w= Ү/#w= Ӯ/#w= Ӯ/#w= 2Ӯ/#w= CӮ/#w= JӮ/s VӮ/#w= iӮ/#wP yӮ/#wP Ӯ/#wP Ӯ/#wc Ӯ/#wc Ӯ/#wl Ӯ/#wl Ӯ/#wl Ӯ/ #wv Ӯ/ #wv Ԯ/#@wz $Ԯ/#@wz 1Ԯ/%#7w EԮ/%#7w WԮ//#(w mԮ//#(w vԮ/o Ԯ/.#w Ԯ/.#w Ԯ/<#w Ԯ/<#w Ԯ/<#w Ԯ/,#w Ԯ/,#w Ԯ//#w ծ//#w ծ/#w 1ծ/#w Cծ/# w Uծ/# w kծ/#w ծ/#w ծ/#w ծ/j ծ/#w ծ/#w ծ/ #w ծ/ #w ծ/#w ֮/#w ֮/#wƢ *֮/#wƢ ?֮/-#wߢ R֮/-#wߢ d֮/.#w t֮/.#w ֮/4#w ֮/4#w ֮/4#w ֮/D#w ֮/D#w ֮/e ֮/Y#w ֮/Y#w ֮/Y#w ֮/X#w ׮/X#w #׮/Y#w  9׮/Y#w  H׮/Y#w  _׮/V#w  s׮/:#w  ׮/:#w  ׮/:#w  ׮/+#w  ׮/+#w  ׮/!#w  ׮/!#w  ׮/_ ׮/#w  خ/#w  خ/ #w  /خ/ #w  Aخ/#w  Sخ/#w  dخ/#w yخ/#w خ/#w خ/#w خ/#w" خ/#w" خ//#w5 خ//#w5 خ//#w5 ٮ/<#wA $ٮ/<#wA &ٮ/Y 0ٮ/<#wB >ٮ/<#wB Kٮ/<#wB ]ٮ/4#wB jٮ/4#wB yٮ/4#wB ٮ/4#wB ٮ/4#wB ٮ/B#wN ٮ/B#wN ٮ/B#wN ٮ/N#wW ٮ/N#wW ٮ/N#wW ٮ/Y#wb ڮ/Y#wb ڮ/Z#wb +ڮ/Z#wb @ڮ/Z#wb Rڮ/V Vڮ/t#4wy kڮ/#\w ڮ/#\w ڮ/#]w ڮ/#]w ڮ/#]w ڮ/#]w ڮ/#_w ڮ/#_w ڮ/#Xw ڮ/#Xw ۮ/#Xw ۮ/#Hw &ۮ/#Hw 7ۮ/#Pw Lۮ/#Pw ^ۮ/#Jw nۮ/#Jw {ۮ/#Jw ~ۮ/Q ۮ/#Rw ۮ/#Rw ۮ/#^w ۮ/#^w ۮ/#Nw ۮ/#Nw ۮ/#Lw ܮ/#Lw #ܮ/#Pw <ܮ/#Pw Rܮ/#@w jܮ/#@w ܮ/#5w ܮ/#5w ܮ/R  ܮ/#7wʣ ܮ/#7wʣ ܮ/#;wӣ ܮ/#;wӣ ܮ/#;wӣ ܮ/#=wԣ ݮ/#=wԣ ݮ/#Ow *ݮ/#Ow 9ݮ/#Ow Jݮ/#Sw `ݮ/#Sw tݮ/#cw ݮ/#cw ݮ/#rw ݮ/#rw ݮ/#_w ݮ/#_w ݮ/Q  ݮ/#pw ݮ/#pw ݮ/#pw ޮ/#uw 'ޮ/#uw 8ޮ/#uw Lޮ/#uw Qޮ/#uw aޮ/#ww wޮ/#ww ޮ/#lw ޮ/#aw  ޮ/#aw  ޮ/#fw  ޮ/#fw  ޮ/#uw  ߮/P  ߮/#uw  &߮/#xw  :߮/#xw  P߮/#|w  g߮/#|w  }߮/#~w  ߮/#~w  ߮/#ww  ߮/#uw  ߮/#uw  ߮/#uw  /#uw  /#cw  !/#cw  //P  2/#rw F/#rw \/#Xw o/#Xw /#Iw /#Iw /#Iw /x#3w /x#3w /X#w /X#w /X#w /X#w />#w />#w &/,#w 3/,#w E/,#w Y/"#w [/O  k/"#w /#w /#w /#w /#w /#w /#w /#w /#w /#w 4/#w L/#w9 a/#w9 w/#w9 /N  /#w: /#w: /#w: /#wA /#wA /#wA / #wA / #wA $/ #wA :/#'wA M/#'wA ^/# wA q/# wA /#wA /#wA /#wn /N  /#wn /#wz /#wz /#wz / #wz / #wz /5#w ./5#w ?/5#w F/C#w Q/C#w a/C#w q/A#w /A#w /1#w /1#w /1#w /9#w /9#w /N  /8#w /8#w /9#w /9#w 6/6#w K/6#w b/+#w u/+#w /2#w /2#w /#w /#w /#w /# w /# w / #,w / #,w /M  / #,w ,/#Nw ;/#Nw K/#[w [/#[w e/#[w s/#mw /#mw /#mw /#tw /#tw /#tw /#w /#w /#w /#w /#w /#wä %/#wä 7/K  9/#wƤ J/#wƤ \/#wƤ n/#wƤ /#wƤ /#wǤ /#wǤ /#wˤ /#wˤ /#wˤ /#wˤ /# wФ !/# wФ 5/#w٤ G/#w٤ W/#w d/I  h/#w |/#w /#w /#w /#w /#w /#w /#w /#w /#w /#w +/#w ;/#w I/#w \/#w n/#w /#w /#w /G /#w /#w /#w /#w /#w /#w /#_w /#w /#w !/7#w ,/;#Ww :/;#Ww I/;#Ww X/4#Nw l/N#w |/N#w /M#w /M#w /M#w /D /{#w /{#w /#w /#w /#w /#w )/#w w#br#% =[/ N<   0ptuvwxy  "#$%-jklqQefghirsz{/y/~#tv{.{ ,#2>w#br#% =[O"/. / Лqmapshack-1.10.0/test/unittest/input/fit/Warisouderghem_course.fit.xml000644 001750 000144 00000001577 12727447634 027403 0ustar00oeichlerxusers000000 000000 Warisouderghem qmapshack-1.10.0/test/unittest/input/fit/2015-05-07-22-03-17.fit.xml000644 001750 000144 00000002411 12727447634 024745 0ustar00oeichlerxusers000000 000000 2015-07-05-22-03-17 qmapshack-1.10.0/test/unittest/input/fit/2016-03-12_15-16-50_4_20.fit000644 001750 000144 00000005436 12727447634 024764 0ustar00oeichlerxusers000000 000000  .FIT@@TF1AA1,BF1C   F1@TA,F18SN F1Qx^xdF1jy+yaD F1EO F1X3 $<FF1'!Q sGhF1iNF1x! vF1'! pwF1HF1!i * w0F12!'  vF1! pNyF1!= NzF1! t  zCF1 !Z O}SF1! -O~T F1h! pT F1!V eyTF1X! pPF1!? $OF1,! -ORF1! 5PF1C! <7E#F1!G& @ M$F1 !( bB2N'F1 !O1 GT+F1!!= nOP2F1!uP n\Q6F1I 7F1!?] eeP:F1:F1[!hd 3kO=F1B!j pzR>F1x!-l rRBF1]!s yRCF1!u {SDF1M!w }REF1 !y zRJF1! XUENF1!z 'OF1o!Oy ÐRF1 TF1!;t 0 XF1!Ts J>AYF1^F1v!Vr ΦK_F1]!r ObF1!r ~QdF1=!s #fF1!r !iF1p!Gq gmF1A!)m d nF1!j '1qF1h!|a sF1!Z uF1!T *vF1%!]Q 0zF12!C G}F1!9 ~F1!6  F1C!v, pF1Y!\$ XF1F1![ F1F1F1! F1+! F1! F1! }F1! zF1w!y xF1F1@TA,F18SN F1QxxdF1jyWy`F1F1F1!F wF1! zF1! |F1F1@TA,F18SN F1QxxdF1jy$ Xy`J!      F1F1'!Q ! gpV!ŀ !y % p HUF1 K"      F1F1'!Q gpV!ŀ !y % p HUL" F1pVF1iNqmapshack-1.10.0/test/unittest/input/randomize_hr.awk000644 001750 000144 00000000607 12727447634 024127 0ustar00oeichlerxusers000000 000000 #!/bin/gawk -f function randint(start, end) { return start + int((end - start) * rand()) } function randfloat(start, end) { return start + ((end - start) * rand()) } // { matched=0; } match($0, /^(\s*)([0-9]+(\.[0-9]+)?)<\/gpxtpx:hr>\s*$/, ary) { print ary[1] "" randint(100, 200) ""; matched=1; } // { if(0 == matched) { print $0; } } qmapshack-1.10.0/test/unittest/CMakeLists.txt000644 001750 000144 00000003616 13025704317 022330 0ustar00oeichlerxusers000000 000000 # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) find_package(Qt5Test) find_package(Qt5Widgets) find_package(Qt5Core) find_package(Qt5Xml) find_package(Qt5Script) find_package(Qt5Sql) find_package(Qt5WebKitWidgets) find_package(Qt5LinguistTools) find_package(Qt5PrintSupport) if(UNIX) if(Qt5DBus_FOUND) find_package(Qt5DBus) endif(Qt5DBus_FOUND) endif(UNIX) find_package(GDAL REQUIRED) find_package(PROJ REQUIRED) find_package(ROUTINO REQUIRED) if(UNIX) if(Qt5DBus_FOUND) set(DBUS_LIB Qt5::DBus) endif(Qt5DBus_FOUND) else(UNIX) set(DBUS_LIB) endif(UNIX) if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif(UNIX) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../src ) include_directories( SYSTEM # this prevents warnings from non-QMS headers ${GDAL_INCLUDE_DIRS} ${PROJ_INCLUDE_DIRS} ${ROUTINO_INCLUDE_DIRS} ${ALGLIB_INCLUDE_DIRS} ) qt5_add_resources(RC_SRCS ./../../src/resources.qrc) add_executable(qttest EXCLUDE_FROM_ALL main.cpp test_QMapShack.h CGpxProject.cpp CFitProject.cpp CQmsProject.cpp CSlfReader.cpp CKnownExtension.cpp TestHelper.cpp CGisItemTrk.cpp ${RC_SRCS}) # copy the input files required by the unittests to ./bin/input file(COPY input DESTINATION ${CMAKE_BINARY_DIR}/bin/) target_link_libraries(qttest Qt5::Widgets Qt5::Xml Qt5::Script Qt5::Sql Qt5::WebKitWidgets Qt5::PrintSupport Qt5::Test QMS ${DBUS_LIB} ${GDAL_LIBRARIES} ${PROJ_LIBRARIES} ${ROUTINO_LIBRARIES} ${ALGLIB_LIBRARIES} ) add_custom_command( OUTPUT tests_run.log COMMAND qttest DEPENDS qttest COMMENT "Executing the Unittests" VERBATIM ) add_custom_target( run_tests DEPENDS tests_run.log ) qmapshack-1.10.0/test/unittest/TestHelper.cpp000644 001750 000144 00000012130 12727447634 022360 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 #include #include #include #include "TestHelper.h" QString TestHelper::getTempFileName(const QString &ext) { QTemporaryFile tmp("qtt_XXXXXX." + ext); tmp.open(); QString tempFile = tmp.fileName(); tmp.remove(); return tempFile; } static QString getAttribute(const QDomNode &node, const QString &name) { const QDomNamedNodeMap &attrs = node.attributes(); if(!attrs.contains(name)) { QWARN( QString("Attribute `%1` does not exist in DomNode `%2`").arg(name).arg(node.nodeName()).toStdString().c_str() ); return QString(); } return attrs.namedItem(name).nodeValue(); } static QHash getExpectedAreas(const QDomNode &exp) { QHash expOvls; const QDomNodeList &ovlList = exp.namedItem("areas").childNodes(); for(int i = 0; i < ovlList.length(); i++) { const QDomNode &node = ovlList.item(i); expectedArea ovl; ovl.name = getAttribute(node, "name"); ovl.colorIdx = getAttribute(node, "colorIdx").toInt(); ovl.ptCount = getAttribute(node, "pointcount").toInt(); expOvls.insert(ovl.name, ovl); } return expOvls; } static QHash getExpectedRoutes(const QDomNode &exp) { QHash expRtes; const QDomNodeList &rteList = exp.namedItem("routes").childNodes(); for(int i = 0; i < rteList.length(); i++) { const QDomNode &node = rteList.item(i); expectedRoute rte; rte.name = getAttribute(node, "name"); rte.ptCount = getAttribute(node, "pointcount").toInt(); expRtes.insert(rte.name, rte); } return expRtes; } static QHash getExpectedTracks(const QDomNode &exp) { QHash expTrks; const QDomNodeList &trkList = exp.namedItem("tracks").childNodes(); for(int i = 0; i < trkList.length(); i++) { const QDomNode &node = trkList.item(i); expectedTrack trk; trk.name = getAttribute(node, "name"); trk.segCount = getAttribute(node, "segcount" ).toInt(); trk.ptCount = getAttribute(node, "pointcount").toInt(); trk.colorIdx = getAttribute(node, "colorIdx" ).toInt(); QHash extensions; const QDomNodeList &extList = node.namedItem("colorSources").childNodes(); for(int j = 0; j < extList.length(); j++) { expectedExtension ext; ext.name = getAttribute(extList.item(j), "name"); ext.known = getAttribute(extList.item(j), "known") == "true"; ext.everyPoint = getAttribute(extList.item(j), "everypoint") == "true"; ext.derived = getAttribute(extList.item(j), "derived") == "true"; extensions.insert(ext.name, ext); } trk.extensions = extensions; expTrks.insert(trk.name, trk); } return expTrks; } static QHash getExpectedWaypoints(const QDomNode &exp) { QHash expWpts; const QDomNodeList &wptList = exp.namedItem("waypoints").childNodes(); for(int i = 0; i < wptList.length(); i++) { const QDomNode &node = wptList.item(i); expectedWaypoint wpt; wpt.name = node.attributes().namedItem("name").nodeValue(); expWpts.insert(wpt.name, wpt); } return expWpts; } expectedGisProject TestHelper::readExpProj(const QString &fileName) { QFile file(fileName); QDomDocument xml; QString msg; int line; int column; SUBVERIFY(xml.setContent(&file, false, &msg, &line, &column), QString("[%1:%2] %3").arg(fileName).arg(line).arg(msg)); const QDomNode &exp = xml.namedItem("expected"); expectedGisProject proj; proj.changed = false; //< projects should never be changed after loading proj.name = exp.namedItem("name").firstChild().nodeValue(); proj.desc = exp.namedItem("desc").firstChild().nodeValue(); proj.wpts = getExpectedWaypoints(exp); proj.trks = getExpectedTracks(exp); proj.rtes = getExpectedRoutes(exp); proj.ovls = getExpectedAreas(exp); return proj; } qmapshack-1.10.0/test/unittest/test_QMapShack.h000644 001750 000144 00000005630 12727447634 022624 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 #include #include "TestHelper.h" class IGisProject; class CGpxProject; class CQmsProject; class CSlfProject; extern QString testInput; #define TCWRAPPER( CALL ) { try { CALL; } catch(QString &error) { QFAIL(error.toStdString().c_str()); } \ } class test_QMapShack : public QObject { Q_OBJECT QString testInput; QList inputFiles; void verify(const QString &expectFile, const IGisProject &proj); void verify(expectedGisProject exp, const IGisProject &proj); void verify(const QString &projFile); QString fileToPath(const QString &file); IGisProject* readProjFile(const QString &file, bool valid = true, bool forceVerify = true); // CSlfReader void _readValidSLFFile(); void _readNonExistingSLFFile(); // CGpxProject void writeReadGpxFile(const QString &file); void _writeReadGpxFile(); // CKnownExtension void _readExtGarminTPX1_tp1(); void _readExtGarminTPX1_gpxtpx(); void readExtGarminTPX1(const QString &file, const QString &ns); // CQmsProject void _readQmsFile_1_6_0(); void _writeReadQmsFile(); // CFitProject void _readValidFitFiles(); // CGisItemTrk void _filterDeleteExtension(); private slots: void initTestCase(); void testreadValidSLFFile() { TCWRAPPER( _readValidSLFFile() ) } void testreadNonExistingSLFFile() { TCWRAPPER( _readNonExistingSLFFile() ) } void testwriteReadGpxFile() { TCWRAPPER( _writeReadGpxFile() ) } void testreadQmsFile_1_6_0() { TCWRAPPER( _readQmsFile_1_6_0() ) } void testwriteReadQmsFile() { TCWRAPPER( _writeReadQmsFile() ) } void testreadExtGarminTPX1_gpxtpx() { TCWRAPPER( _readExtGarminTPX1_gpxtpx() ) } void testreadExtGarminTPX1_tp1() { TCWRAPPER( _readExtGarminTPX1_tp1() ) } void testreadValidFitFiles() { TCWRAPPER( _readValidFitFiles() ) } void testfilterDeleteExtension() { TCWRAPPER( _filterDeleteExtension() ) } }; qmapshack-1.10.0/test/unittest/main.cpp000644 001750 000144 00000022301 13023451227 021205 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 #include #include "TestHelper.h" #include "test_QMapShack.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/fit/CFitProject.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/slf/CSlfProject.h" #include "gis/slf/CSlfReader.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CSettings.h" #include "setup/IAppSetup.h" QString testInput; void test_QMapShack::initTestCase() { IAppSetup* env = IAppSetup::getPlatformInstance(); env->processArguments(); env->initLogHandler(); env->initQMapShack(); SETTINGS; IUnit::self().setUnitType((IUnit::type_e)cfg.value("MainWindow/units",IUnit::eTypeMetric).toInt(), nullptr); CKnownExtension::init(IUnit::self()); testInput = QCoreApplication::applicationDirPath() + "/input/"; inputFiles = { "qtt_gpx_file0.gpx" , "gpx_ext_GarminTPX1_gpxtpx.gpx" , "gpx_ext_GarminTPX1_tp1.gpx" , "V1.6.0_file1.qms" , "V1.6.0_file2.qms" }; } void test_QMapShack::verify(expectedGisProject exp, const IGisProject &proj) { VERIFY_EQUAL(true, proj.isValid()); VERIFY_EQUAL(exp.changed, proj.isChanged()); VERIFY_EQUAL(exp.name, proj.getName()); VERIFY_EQUAL(exp.desc, proj.getDescription()); VERIFY_EQUAL(exp.wpts.count(), proj.getItemCountByType(IGisItem::eTypeWpt)); VERIFY_EQUAL(exp.trks.count(), proj.getItemCountByType(IGisItem::eTypeTrk)); VERIFY_EQUAL(exp.rtes.count(), proj.getItemCountByType(IGisItem::eTypeRte)); VERIFY_EQUAL(exp.ovls.count(), proj.getItemCountByType(IGisItem::eTypeOvl)); for(int i = 0; i < proj.childCount(); i++) { IGisItem *item = dynamic_cast(proj.child(i)); CGisItemWpt *wpt = dynamic_cast(item); if(nullptr != wpt) { VERIFY_EQUAL(true, exp.wpts.contains(wpt->getName())); exp.wpts.remove(wpt->getName()); SUBVERIFY(wpt->getPosition() != QPointF(0., 0.), "Waypoint has position 0/0"); } CGisItemTrk *itemTrk = dynamic_cast(item); if(nullptr != itemTrk) { const CTrackData &trk = itemTrk->getTrackData(); SUBVERIFY(exp.trks.contains(itemTrk->getName()), QString("Found track `%1`, there shouldn't be any track with that name").arg(itemTrk->getName())); const expectedTrack &expTrk = exp.trks.take(itemTrk->getName()); int trkptCount = 0; for(const trkseg_t &seg : trk.segs) { trkptCount += seg.pts.count(); for(const trkpt_t &trkpt : seg.pts) { SUBVERIFY((0. != trkpt.lat) || (0. != trkpt.lon), "Trackpoint has position 0/0"); for(const QString &key : expTrk.extensions.keys()) { VERIFY_EQUAL(expTrk.extensions[key].known, CKnownExtension::isKnown(key)); if(expTrk.extensions[key].everyPoint) { SUBVERIFY(trkpt.extensions.contains(key), QString("Missing extension `%1`on trackpoint").arg(key)); } } } } VERIFY_EQUAL(expTrk.segCount, trk.segs.count()); VERIFY_EQUAL(expTrk.ptCount, trkptCount); VERIFY_EQUAL(expTrk.colorIdx, itemTrk->getColorIdx()); QStringList existingSources = itemTrk->getExistingDataSources(); for(const QString &ext : expTrk.extensions.keys()) { SUBVERIFY(existingSources.contains(ext), QString("Missing extension `%1`").arg(ext)); existingSources.removeOne(ext); } auto accuFunc = [](const QString &accu, const QString &b) { return accu.isEmpty() ? b : QString("%1, %2").arg(accu).arg(b); }; QString remainingExts = std::accumulate(existingSources.cbegin(), existingSources.cend(), QString(), accuFunc); SUBVERIFY(existingSources.isEmpty(), QString("existingSources still contains: ") + remainingExts); } CGisItemRte *itemRte = dynamic_cast(item); if(nullptr != itemRte) { SUBVERIFY(exp.rtes.contains(itemRte->getName()), QString("Found route `%1`, there shouldn't be any route with that name").arg(itemRte->getName())); const CGisItemRte::rte_t &rte = itemRte->getRoute(); const expectedRoute &expRte = exp.rtes.take(itemRte->getName()); VERIFY_EQUAL(expRte.ptCount, rte.pts.size()); } CGisItemOvlArea *itemOvl = dynamic_cast(item); if(nullptr != itemOvl) { SUBVERIFY(exp.ovls.contains(itemOvl->getName()), QString("Found area `%1`, there shouldn't be any area with that name").arg(itemOvl->getName())); const expectedArea &expOvl = exp.ovls.take(itemOvl->getName()); VERIFY_EQUAL(expOvl.colorIdx, itemOvl->getColorIdx()); const CGisItemOvlArea::area_t &area = itemOvl->getAreaData(); VERIFY_EQUAL(expOvl.ptCount, area.pts.size()); } } // ensure all expected waypoints/tracks actually exist SUBVERIFY(exp.wpts.isEmpty(), "Not all expected waypoints found"); SUBVERIFY(exp.trks.isEmpty(), "Not all expected tracks found"); SUBVERIFY(exp.rtes.isEmpty(), "Not all expected routes found"); SUBVERIFY(exp.ovls.isEmpty(), "Not all expected areas found"); } void test_QMapShack::verify(const QString &projFile, const IGisProject &proj) { expectedGisProject exp = TestHelper::readExpProj(fileToPath(projFile) + ".xml"); verify(exp, proj); } void test_QMapShack::verify(const QString &projFile) { IGisProject *proj = readProjFile(projFile); expectedGisProject exp = TestHelper::readExpProj(fileToPath(projFile) + ".xml"); verify(exp, *proj); delete proj; } QString test_QMapShack::fileToPath(const QString &file) { if(!QFileInfo(file).exists()) { return testInput + "/" + file.right(3) + "/" + file; } return file; } IGisProject* test_QMapShack::readProjFile(const QString &file, bool valid, bool forceVerify) { IGisProject *proj = nullptr; try { if(file.endsWith(".gpx")) { CGpxProject *gpxProj = new CGpxProject("a very random string to prevent loading via constructor", (CGisListWks*) nullptr); gpxProj->blockUpdateItems(true); CGpxProject::loadGpx(fileToPath(file), gpxProj); gpxProj->blockUpdateItems(false); proj = gpxProj; SUBVERIFY(IGisProject::eTypeGpx == proj->getType(), "Project has invalid type"); } else if(file.endsWith(".qms")) { proj = new CQmsProject(fileToPath(file), (CGisListWks*) nullptr); SUBVERIFY(IGisProject::eTypeQms == proj->getType(), "Project has invalid type"); } else if(file.endsWith(".slf")) { CSlfProject *slfProj = new CSlfProject("a very random string to prevent loading via constructor", false); proj = slfProj; CSlfReader::readFile(fileToPath(file), slfProj); SUBVERIFY(IGisProject::eTypeSlf == proj->getType(), "Project has invalid type"); } else if(file.endsWith(".fit")) { proj = new CFitProject(fileToPath(file), (CGisListWks*) nullptr); SUBVERIFY(IGisProject::eTypeFit == proj->getType(), "Project has invalid type"); } else { SUBVERIFY(false, "Internal error: Can't read project file `" + file + "`"); } } catch(QString &errormsg) { SUBVERIFY(!valid, "Expected `" + file + "` to be valid, error while reading: " + errormsg); delete proj; proj = nullptr; } SUBVERIFY(valid || nullptr == proj, "File is neither valid, nor an exception was thrown"); if(nullptr != proj) { const QString &projPath = fileToPath(file); SUBVERIFY(QFile(projPath + ".xml").exists() || !forceVerify, "Can't verify file `" + file + "`, .xml does not exist"); if(QFile(projPath + ".xml").exists()) { verify(file, *proj); } } return proj; } QTEST_MAIN(test_QMapShack) qmapshack-1.10.0/test/unittest/CQmsProject.cpp000644 001750 000144 00000003326 12727447634 022502 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 #include "TestHelper.h" #include "test_QMapShack.h" #include "gis/gpx/CGpxProject.h" #include "gis/qms/CQmsProject.h" void test_QMapShack::_readQmsFile_1_6_0() { IGisProject *proj1 = readProjFile("V1.6.0_file1.qms"); verify("V1.6.0_file1.qms", *proj1); delete proj1; IGisProject *proj2 = readProjFile("V1.6.0_file2.qms"); verify("V1.6.0_file2.qms", *proj2); delete proj2; } void test_QMapShack::_writeReadQmsFile() { for(const QString &file : inputFiles) { IGisProject *proj = readProjFile(file); QString tmpFile = TestHelper::getTempFileName("qms"); CQmsProject::saveAs(tmpFile, *proj); delete proj; proj = readProjFile(tmpFile, true, false); verify(file, *proj); delete proj; QFile(tmpFile).remove(); } } qmapshack-1.10.0/test/unittest/CSlfReader.cpp000644 001750 000144 00000002231 12727447634 022254 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "test_QMapShack.h" #include "gis/prj/IGisProject.h" void test_QMapShack::_readValidSLFFile() { verify("qtt_slf_file0.slf"); } void test_QMapShack::_readNonExistingSLFFile() { delete readProjFile("qtt_slf_DOES_NOT_EXIST.slf", false, false); } qmapshack-1.10.0/test/OSX_uitest/000755 001750 000144 00000000000 13216664442 017757 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/test/OSX_uitest/suite.py000755 001750 000144 00000003417 12727447634 021502 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from testtools import ToolsTestCase from testroute import RouteTestCase from testdatabase import DatabaseTestCase from testmaps import MapsTestCase from qmstestcase import * class TestTest(QmsTestCase): def __init__(self, methodName): QmsTestCase.__init__(self, methodName) def testT(self): t = MapsTestCase('testLoadDem') t.getAppHandle() t.testLoadDem() t.testLoadMaps() def suite(): t = unittest.TestSuite() t.addTest(TestTest('testT')) #return t suiteMaps = MapsTestCase.suite() suiteDatbase = DatabaseTestCase.suite() suiteRoute = RouteTestCase.suite() suiteToos = ToolsTestCase.suite() alltests = unittest.TestSuite([suiteMaps, suiteDatbase, suiteRoute, suiteToos]) #alltests = unittest.TestSuite([suiteMaps, suiteRoute]) #return suiteRoute return alltests unittest.TextTestRunner(verbosity=2).run(suite()) qmapshack-1.10.0/test/OSX_uitest/uitest.cfg000644 001750 000144 00000000506 12727447634 021766 0ustar00oeichlerxusers000000 000000 [directory] out.test.dir=/data/GPS/out vrt.out.file=test.vrt routing.out.file=test cache.dir= dem.dir.ch=/data/GPS/Relief/L32 dem.dir=/data/GPS/Relief dem.name=l32 ch map.dir=/data/GPS/Karten map.name=raumbezug ch pbf.dir.ch=/data/GPS/Routing pdf.file.ch=switzerland-latest.osm.pbf mem.dir.ch=/data/GPS/Routing [flow] wait=1.0qmapshack-1.10.0/test/OSX_uitest/testroute.py000644 001750 000144 00000016520 12727447634 022403 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from qmstestcase import * class RouteTestCase(QmsTestCase): def __init__(self, methodName): QmsTestCase.__init__(self, methodName) def testConfigRoutino(self): self.showRoute() # first dropdown Routino (offline) res = self.appWin().find('AXPopUpButton').selectPopupElement('Routino (offline)') self.assertTrue(res, 'set routino popup button failed') routeButton = self.app.findAllR('AXRadioButton', 'Route')[0] groups = self.appWin().findAll('AXGroup', '') group = self._findNeighbour(groups, routeButton) # setup database group.find('AXButton', '...').click() dlgRoutinoDb = self.app.find('AXWindow') pathes = dlgRoutinoDb.find('AXList').findAll('AXStaticText') routinoPath = config.get('directory', 'mem.dir.ch') routinoPathAdded = False for path in pathes: if path.getText() == routinoPath: routinoPathAdded = True logger.info('routino path ' + routinoPath + ' already added') break if routinoPathAdded == False: logger.info('adding routino path ' + routinoPath) dlgRoutinoDb.find('AXButton', '...').click() res = self.safeDirectoryDlg(routinoPath) self.assertTrue(res, 'set directory dialog failed') dlgRoutinoDb.find('AXGroup').find('AXButton', 'OK').click() # the group for the Routino Route settings dropdowns = group.findAll('AXPopUpButton') for dropdown in dropdowns: dropdown.selectPopupElement('Fahrrad') dropdown.selectPopupElement('Deutsch') dropdown.selectPopupElement('Schnellste') dropdown.selectPopupElement('Europa') dropdown.selectPopupElement('Switzerland') def testSearchGoogle(self): # --> search google self.showDaten() town = 'Grindelwald' grid = self.datenProjectGrid() if len(grid) < 2 or grid[1].getText() <> '': # click menu self.app.selectMenuItem('Projekt', 'Mit Google suchen') googleInput = self.datenProjectGrid()[1] else: googleInput = grid[1] googleInput.click() waitShort() self.app.sendKey("a", [COMMAND]) self.app.sendSingleKey(BACKSPACE) self.app.sendKey(town) self.app.sendSingleKey(RETURN) #self.app.sendKey('\n') waitShort() resultTown = self.datenProjectGrid()[3] self.assertRegexpMatches(resultTown.getText(), town) resultTown.doubleClick() waitShort() map = self.mapArea() map.click() waitShort() # --> position in status bar coordField = self.appWin().find('AXStaticText').find('AXStaticText') logger.debug(unicode(coordField.getText()).encode('utf8')) self.assertRegexpMatches(coordField.getText(), u'N46\xb0 37.\d{3} E008\xb0 02.\d{3}') # \xb0 ° map.click() def testRoute(self): # relies on testSearchGoogle #self.startApp() self.showMaps() # --> routing with routino # click to center of map, where the searched place is map = self.mapArea() map.click() waitShort() # auto routing self.app.sendKey('a', [CONTROL]) waitShort() map.selectPopupMenu(2) waitShort() map.moveAndClick(10, 112) waitShort() map.click() waitShort() map.clickRight() text = map.find('AXStaticText', 'Track*') self.assertTrue(text.valid()) logger.debug(unicode(text.getText()).encode('utf8')) self.assertRegexpMatches(text.getText(), "35\d m") def testSaveRoute(self): projName='uitest' # --> save route map = self.mapArea() map.find('AXButton', 'Als neu speichern').click() #map.find('AXButton', 'Abbrechen').click() projDlg = self.app.find('AXWindow', u'Ein Projekt auswählen...') self.assertTrue(projDlg.valid()) # FIXME here is a bug in the GUI #projDlg.find('AXList').findAll('AXStaticText')[0].click() #projDlg.find('AXTextField').click() self.app.sendSingleKey(TAB) self.app.sendKey('uitest') # *.qms, *.gpx, Datenbank projDlg.find('AXRadioButton', '*.gpx').click() projDlg.find('AXGroup').find('AXButton', 'OK').click() nameDlg = self.app.find('AXWindow', u'Name bearbeiten...') self.assertTrue(nameDlg.valid()) # FIXME here is a bug in the GUI #nameDlg.find('AXTextField').click() self.app.sendKey(projName) nameDlg.find('AXGroup').find('AXButton', 'OK').click() waitShort() self.showDaten() # somehow the app reference has been lost, get it again self.getAppHandle() grid = self.datenProjectGrid(projName) self.assertIs(len(grid), 1) grid[0].doubleClick() grid = self.datenProjectGrid(projName) self.assertIs(len(grid), 2) grid[1].clickRight() grid[1].selectPopupMenu(1) buttonView = self.appWin().findR('AXRadioButton', projName) groups = self.appWin().findAll('AXGroup', '') detailView = self._findNeighbour(groups, buttonView, Direction.below).find('AXSplitGroup') detailView.findAll('AXGroup')[1].find('AXRadioButton', 'Punkte').click() table = detailView.findAll('AXGroup')[0].find('AXGroup').findAll('AXGroup') # 10 columns per row self.assertEqual(table[2].getText(), '1045 m') # the next lines are for a route if False: trkDlg = self.app.find('AXWindow', projName) self.assertTrue(trkDlg.valid()) self.assertEqual(trkDlg.find('AXGroup').find('AXTextField').getText(), projName) # close dialog trkDlg.find('AXButton').click() # close track grid[0].selectPopupMenu(8) waitShort() questionDlg = self.app.find('AXWindow', '') questionDlg.find('AXGroup').find('AXButton', 'Nein').click() def testEditRoute(self): # TODO pass @staticmethod def suite(): suite = unittest.TestSuite() suite.addTest(RouteTestCase('testConfigRoutino')) suite.addTest(RouteTestCase('testSearchGoogle')) suite.addTest(RouteTestCase('testRoute')) suite.addTest(RouteTestCase('testSaveRoute')) suite.addTest(RouteTestCase('testEditRoute')) return suiteqmapshack-1.10.0/test/OSX_uitest/qmstestcase.py000644 001750 000144 00000020066 12727447634 022701 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from uiautomator import * import unittest import os dirCache = os.path.expanduser("~") + "/.QMapShack/" class Direction: above, below, left, right = range(1, 5) class EntryList: def __init__(self, app): self.app = app def grid(self, name=None): pass def showList(self): pass def focusList(self): pass def _isEntryActivated(self, entry, name): entry.click() self.app.sendSingleKey(DOWN) self.app.sendSingleKey(UP) self.app.sendSingleKey(RIGHT) waitShort() # check if map has not bean activated before g = self.grid() activated = False i = 0 posEntry = -2 while i < len(g): e = g[i] if e.getText() == name: posEntry = i if e.getText() == '' and posEntry == i - 1: activated = True break i += 1 return activated def _findEntry(self, name): entry = None firstChar=name[0] # break for infinite loop b = 0 while (entry is None) or (b < 15): b = b + 1 self.app.sendKey(firstChar) grid = self.grid(name) if len(grid) > 0: entry = grid[0] break return entry def activateEntry(self, name, activate=True): self.showList() self.focusList() entry = self._findEntry(name) if entry is None: return False # check if map has not bean activated before activated = self._isEntryActivated(entry, name) logger.info('entry ' + name + ' is activated ' + str(activated)) entry.click() if (not activate and activated) or (activate and not activated): logger.debug('popup 1') entry.selectPopupMenu(1) if activate and activated: logger.debug('popup 2') entry.selectPopupMenu(1) # map will be reorder after deactivate, thus search it again entry = self._findEntry(name) # if map has already been activated, make sure tiles will be loaded again logger.debug('popup 3') entry.selectPopupMenu(1) return True class MapList(EntryList): def __init__(self, gui): EntryList.__init__(self, gui.app) self.gui = gui def grid(self, name=None): return self.gui.mapGrid(name) def showList(self): self.gui.showMaps() def focusList(self): self.gui.focusMapGrid() class DemList(EntryList): def __init__(self, gui): EntryList.__init__(self, gui.app) self.gui = gui def grid(self, name=None): return self.gui.demGrid(name) def showList(self): self.gui.showDem() def focusList(self): self.gui.focusDemGrid() class QmsGui(UIAutomator): def __init__(self): UIAutomator.__init__(self) def showRoute(self): self.app.findR('AXRadioButton', 'Route', False).click() waitShort() def showDaten(self): self.app.findR('AXRadioButton', 'Daten', False).click() waitShort() def showMaps(self): self.app.findR('AXRadioButton', 'Karten', False).click() waitShort() def showDem(self): self.app.findR('AXRadioButton', u'Dig. Höhenmodell (DEM)', False).click() waitShort() def datenProjectGrid(self, match = None): return self.appWin().findAll('AXSplitGroup')[0].findAll('AXGroup')[1].findAll('AXGroup', match) def datenDbGrid(self, match = None): return self.appWin().findAll('AXSplitGroup')[0].findAll('AXGroup')[0].findAll('AXGroup', match) def _findNeighbour(self, elements, beside, direction=Direction.above): x, y = beside.ax.AXPosition w, h = beside.ax.AXSize threshold = 10 for e in elements: if e.valid() and e.visible(): gx, gy = e.ax.AXPosition gw, gh = e.ax.AXSize # TODO add left / right aspect if direction == Direction.above: if (gh + gy + threshold > y) and (gh + gy - threshold < y): return e if direction == Direction.below: if (gy + threshold > y + h) and (gy - threshold < y + h): return e def _anyElementOf(self, elements, types): if not isinstance(elements, list): elements = [elements] if not isinstance(types, list): types = [types] for element in elements: if element.ax.AXRole in types: return True return False def mapGrid(self, match = None): mapButton = self.app.findR('AXRadioButton', 'Karten', False) groups = self.appWin().findAll('AXGroup', '', False) group = self._findNeighbour(groups, mapButton) return group.findAll('AXGroup')[0].findAll('AXGroup', match) #return self.appWin().findAll('AXGroup', '')[1].findAll('AXGroup')[0].findAll('AXGroup', match) def focusMapGrid(self): self.mapGrid()[0].parent().click() #self.appWin().findAll('AXGroup', '')[1].findAll('AXGroup')[0].click() def demGrid(self, match = None): demButton = self.app.findR('AXRadioButton', u'Dig. Höhenmodell (DEM)', False) groups = self.appWin().findAll('AXGroup', '', False) group = self._findNeighbour(groups, demButton) return group.find('AXGroup').findAll('AXGroup', match) def focusDemGrid(self): self.demGrid()[0].parent().click() def mapArea(self): groups = self.appWin(True).findAll('AXGroup', '', True) mapGroup = None for group in groups: if group.valid() and group.visible(): children = group.children() if len(children) == 0 or not self._anyElementOf(children, ['AXGroup', 'AXSplitGroup', 'AXPopUpButton']): mapGroup = group break #UIAutomator.debug(mapGroup, 1) return mapGroup def selectMap(self, name, activate=True): return MapList(self).activateEntry(name, activate) def selectDem(self, name, activate=True): return DemList(self).activateEntry(name, activate) class QmsTestCase(QmsGui, unittest.TestCase): def __init__(self, methodName): QmsGui.__init__(self) unittest.TestCase.__init__(self, methodName) def _cleanDir(self, dirPath): try: if os.path.isdir(dirPath): fileList = os.listdir(dirPath) [ os.remove(os.path.abspath(os.path.join(dirPath,fileName))) for fileName in fileList ] except OSError: pass def _cleanFiles(self): try: os.remove(config.get('directory', 'out.test.dir') + "/" + config.get('directory', 'vrt.out.file')) except OSError: pass self._cleanDir(dirCache+'WorldSat') self._cleanDir(dirCache+'OSM') self._cleanDir(dirCache+'OSM_Topo') self._cleanDir(config.get('directory', 'out.test.dir')) def setUp(self): self._cleanFiles() res = self.getAppHandle() self.assertTrue(res) self._cleanFiles() def tearDown(self): pass qmapshack-1.10.0/test/OSX_uitest/testtools.py000644 001750 000144 00000007346 12727447634 022413 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from qmstestcase import * class ToolsTestCase(QmsTestCase): def __init__(self, methodName): QmsTestCase.__init__(self, methodName) def testVrtBuilder(self): self.app.selectMenuItem('Werkzeug', 'VRT Builder') group = self.app.findR('AXStaticText', 'Quelldateien*').parent() group.findAll('AXButton', '...')[0].click() res = self.openFileDlg(config.get('directory', 'dem.dir.ch')) self.assertTrue(res) group.findAll('AXButton', '...')[1].click() res = self.safeFileDlg(config.get('directory', 'out.test.dir') , config.get('directory', 'vrt.out.file')) self.assertTrue(res) group.find('AXButton', 'Start').click() wait(1.0) group = self.app.findR('AXStaticText', 'Quelldateien*').parent() # test result resultField = group.find('AXStaticText', '') resultField.click() self.app.sendKey('a', [COMMAND]) self.assertRegexpMatches(resultField.ax.AXSelectedText, '0...10...20...30...40...50...60...70...80...90...100 - done') self.assertTrue(os.path.isfile(config.get('directory', 'out.test.dir') + '/' + config.get('directory', 'vrt.out.file'))) def testRoutinoDatabaseBuilder(self): self.app.selectMenuItem('Werkzeug', 'Routino Datenbank erstellen') group = self.app.findR('AXStaticText', 'Quelldateien*').parent() group.findAll('AXButton', '...')[0].click() res = self.openFileDlg(config.get('directory', 'pbf.dir.ch'), config.get('directory', 'pdf.file.ch')) self.assertTrue(res) group.findAll('AXButton', '...')[1].click() res = self.safeDirectoryDlg(config.get('directory', 'out.test.dir')) self.assertTrue(res) # FIXME here is a bug in the GUI group.find('AXStaticText', '').click() self.app.sendSingleKey(TAB) self.app.sendKey(config.get('directory', 'routing.out.file')) waitShort() group.find('AXButton', 'Starten').click() i = 1 text = None while i < 15: i = i + 1 wait(10) group = self.app.findR('AXStaticText', 'Quelldateien*').parent() # test result resultField = group.find('AXStaticText', '') resultField.click() self.app.sendKey('a', [COMMAND]) text = resultField.ax.AXSelectedText if text.endswith('!!! erledigt !!!'): break self.assertRegexpMatches(text, '!!! erledigt !!!') file = config.get('directory', 'out.test.dir') + '/' + config.get('directory', 'routing.out.file')+ "-nodes.mem" self.assertTrue(os.path.isfile(file), file + " not fould") @staticmethod def suite(): suite = unittest.TestSuite() suite.addTest(ToolsTestCase('testVrtBuilder')) suite.addTest(ToolsTestCase('testRoutinoDatabaseBuilder')) return suiteqmapshack-1.10.0/test/OSX_uitest/testdatabase.py000644 001750 000144 00000003440 12727447634 023006 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from qmstestcase import * class DatabaseTestCase(QmsTestCase): def __init__(self, methodName): QmsTestCase.__init__(self, methodName) def testConfigDatabase(self): self.showDaten() dbGroup = self.appWin().findAll('AXSplitGroup')[0].findAll('AXGroup')[0] # for the case an already existing db has been selected dbGroup.click() dbGroup.clickRight() waitShort() self.app.findAllR('AXMenu', '')[0].click() waitShort() dlg = self.app.find('AXWindow', 'Datenbank*') self.assertEqual(dlg.getText(), u'Datenbank hinzufügen...') # TODO configure #dlg.find('AXGroup').find('AXButton', 'OK').click() dlg.find('AXGroup').find('AXButton', 'Abbrechen').click() @staticmethod def suite(): suite = unittest.TestSuite() suite.addTest(DatabaseTestCase('testConfigDatabase')) return suiteqmapshack-1.10.0/test/OSX_uitest/testmaps.py000644 001750 000144 00000007365 12727447634 022214 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ from qmstestcase import * import datetime class MapsTestCase(QmsTestCase): def __init__(self, methodName): QmsTestCase.__init__(self, methodName) def testLoadDem(self): dirDem = config.get('directory', 'dem.dir') self.app.selectMenuItem('Datei', 'DEM Verzeichnisse angeben') demPathDlg = self.app.find('AXWindow', u'Pfad für DEM Dateien setzen') pathes = demPathDlg.find('AXList').findAll('AXStaticText') mapThere = False for path in pathes: if path.getText() == dirDem: mapThere = True if mapThere == False: demPathDlg.findAll('AXButton', '...')[0].click() waitShort() self.safeDirectoryDlg(dirDem) waitShort() self.assertTrue(demPathDlg.find('AXList').find('AXStaticText', dirDem).valid()) demPathDlg.find('AXGroup').find('AXButton', 'OK').click() waitShort() self.getAppHandle() # activate map demName = config.get('directory', 'dem.name') res = self.selectDem(demName, True) self.assertTrue(res) def testLoadMaps(self): mapDir = config.get('directory', 'map.dir') self.app.selectMenuItem('Datei', 'Kartenverzeichnisse angeben') mapPathDlg = self.app.find('AXWindow', 'Kartenpfad einrichten') pathes = mapPathDlg.find('AXList').findAll('AXStaticText') mapThere = False for path in pathes: if path.getText() == mapDir: mapThere = True if mapThere == False: mapPathDlg.findAll('AXButton', '...')[1].click() self.safeDirectoryDlg(mapDir) waitShort() self.assertTrue(mapPathDlg.find('AXList').find('AXStaticText', mapDir).valid()) mapPathDlg.find('AXGroup').find('AXButton', 'OK').click() waitShort() self.getAppHandle() # activate map mapName = config.get('directory', 'map.name') res = self.selectMap(mapName, True) self.assertTrue(res) def testOnlineMap(self): type = 'OSM' self.selectMap('OSM', True) # check downloaded tiles dateCreated = datetime.datetime.now() - datetime.timedelta(minutes=1) dirPath = dirCache+type tiles = 0 wait(3.0) fileList = os.listdir(dirPath) for fileName in fileList: t = os.path.getmtime(os.path.abspath(os.path.join(dirPath,fileName))) dateFile = datetime.datetime.fromtimestamp(t) if dateCreated < dateFile: tiles = tiles + 1 self.assertTrue(tiles > 8, 'only %s tiles found' % tiles) @staticmethod def suite(): suite = unittest.TestSuite() suite.addTest(MapsTestCase('testLoadDem')) suite.addTest(MapsTestCase('testLoadMaps')) suite.addTest(MapsTestCase('testOnlineMap')) return suite qmapshack-1.10.0/test/OSX_uitest/uiautomator.py000644 001750 000144 00000033107 12727447634 022716 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- """ /********************************************************************************************** Copyright (C) 2016 Ivo Kronenberg 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 . **********************************************************************************************/ """ import atomac import atomac.AXKeyboard as AXKeyboard from collections import deque import time import logging import ConfigParser def initConfig(): config = ConfigParser.ConfigParser() config.read('uitest.cfg') return config def initLogger(): FORMAT = '%(asctime)-15s %(message)s' logging.basicConfig(format=FORMAT) log = logging.getLogger('uitest') log.setLevel(logging.INFO) return log logger = initLogger() config = initConfig() def waitShort(): time.sleep(config.getfloat('flow', 'wait')) def wait(sec): time.sleep(sec) class UIBase: def __init__(self, ax, app): self.ax = ax self.cache = {} if app is None: self.app = self else: self.app = app if ax is None: raise ReferenceError() def _lookup(self, find, type, match, clear): key = find + '#' + type if match is not None: key = key + '#' + match logger.debug(unicode(key).encode('utf8')) if key in self.cache: if clear: del self.cache[key] return None logger.debug('match') return self.cache[key] logger.debug('no match') return None def _put(self, element, find, type, match): key = find + '#' + type if match is not None: key = key + '#' + match self.cache[key] = element return element def centreCoordinates(self): x, y = self.ax.AXPosition width, height = self.ax.AXSize return (x + width / 2, y + height / 2) def valid(self): return self.ax is not None def enabled(self): return self.valid() and self.ax.AXEnabled def _measureEnter(self, method): self.start = time.time() self.methodname = method def _measureLeave(self): end = time.time() logger.debug("exec time " + self.methodname + " " + str(end - self.start)) def find(self, type, textmatch=None, refresh=True): self._measureEnter("find") try: v = self._lookup('find', type, textmatch, refresh) if v is not None: return v if textmatch is not None: e = UIElement(self.ax.findFirst(AXRole=type, AXTitle=textmatch), self.app) return self._put(e, 'find', type, textmatch) else: e = UIElement(self.ax.findFirst(AXRole=type), self.app) return self._put(e, 'find', type, textmatch) finally: self._measureLeave() def findNr(self, type, textmatch, nr, refresh=True): return self.findAll(type, textmatch, refresh)[nr] def findAll(self, type, textmatch=None, refresh=True): self._measureEnter("findAll") try: v = self._lookup('findAll', type, textmatch, refresh) if v is not None: return v if textmatch is not None: axs = self.ax.findAll(AXRole=type, AXTitle=textmatch) else: axs = self.ax.findAll(AXRole=type) e = [] if axs is not None and len(axs) > 0: for ax in axs: e.append(UIElement(ax, self.app)) return self._put(e, 'findAll', type, textmatch) finally: self._measureLeave() def findAllR(self, type, textmatch=None, refresh=True): self._measureEnter("findAllR") try: v = self._lookup('findAllR', type, textmatch, refresh) if v is not None: return v if textmatch is not None: axs = self.ax.findAllR(AXRole=type, AXTitle=textmatch) else: axs = self.ax.findAllR(AXRole=type) e = [] if axs is not None and len(axs) > 0: for ax in axs: e.append(UIElement(ax, self.app)) return self._put(e, 'findAllR', type, textmatch) finally: self._measureLeave() def findR(self, type, textmatch=None, refresh=True): self._measureEnter("findR") try: v = self._lookup('findR', type, textmatch, refresh) if v is not None: return v if textmatch is not None: e = UIElement(self.ax.findFirstR(AXRole=type, AXTitle=textmatch), self.app) return self._put(e, 'findR', type, textmatch) else: e = UIElement(self.ax.findFirstR(AXRole=type), self.app) return self._put(e, 'findR', type, textmatch) finally: self._measureLeave() def parent(self): return UIElement(self.ax.AXParent, self.app) def children(self): e = [] axs = self.ax.AXChildren if axs is not None and len(axs) > 0: for ax in axs: e.append(UIElement(ax, self.app)) return e def visible(self): x, y = self.ax.AXPosition return x >= 0 and y >= 0 # Special keys TAB = '' RETURN = '' ESCAPE = '' CAPS_LOCK = '' DELETE = '' NUM_LOCK = '' SCROLL_LOCK = '' PAUSE = '' BACKSPACE = '' INSERT = '' # Cursor movement UP = '' DOWN = '' LEFT = '' RIGHT = '' PAGE_UP = '' PAGE_DOWN = '' HOME = '' END = '' # Modifier keys COMMAND_L = '' SHIFT_L = '' OPTION_L = '' CONTROL_L = '' COMMAND_R = '' SHIFT_R = '' OPTION_R = '' CONTROL_R = '' # Default modifier keys -> left: COMMAND = COMMAND_L SHIFT = SHIFT_L OPTION = OPTION_L CONTROL = CONTROL_L class KeyboardHandler (UIBase): def __init__(self, ax, app): UIBase.__init__(self, ax, app) def _replace(self, str): return str.replace(u'ö', '\xd6') def sendKey(self, key, modifiers = []): if len(modifiers) == 0: self.app.ax.sendKeys(key) else: self.app.ax.sendKeyWithModifiers(key, modifiers) def sendSingleKey(self, key): self.app.ax.sendKey(key) class MouseHandler(UIBase): def __init__(self, ax, app): UIBase.__init__(self, ax, app) self.dx = 0 self.dy = 0 def _coordinates(self): (x, y) = self.centreCoordinates() return (x+self.dx, y+self.dy) def click(self): #self.ax.Press() self.app.ax.clickMouseButtonLeft(self._coordinates()) def doubleClick(self): self.app.ax.doubleClickMouse(self._coordinates()) def clickRight(self): self.app.ax.clickMouseButtonRight(self._coordinates()) def moveAndClick(self, dx, dy): self.dx = dx self.dy = dy self.app.ax.clickMouseButtonLeft(self._coordinates()) class UIElement(UIBase, MouseHandler): def __init__(self, ax, app): UIBase.__init__(self, ax, app) MouseHandler.__init__(self, ax, app) def setValue(self, value): self.ax.AXValue = value def getText(self): if self.ax.AXValue is not None: return self.ax.AXValue return self.ax.AXTitle def selectPopupElement(self, title): langElements = self.find('AXList').findAll('AXStaticText', title) if len(langElements) == 1: self.click() waitShort() langElements[0].click() return True return False def selectPopupMenu(self, nr): self.clickRight() waitShort() i = 0 while i < nr: self.app.sendSingleKey(DOWN) i = i + 1 self.app.sendSingleKey(RETURN) class UIApp(UIElement, KeyboardHandler): def __init__(self, app): UIElement.__init__(self, app, None) KeyboardHandler.__init__(self, app, None) # bugfixes for event queue self.app.keyboard = AXKeyboard.loadKeyboard() self.app.eventList = deque() @staticmethod def getApp(bundleName): ax = None try: ax = atomac.getAppRefByBundleId(bundleName) except ValueError: ax = atomac.launchAppByBundleId(bundleName) if ax is None: ax = atomac.getAppRefByBundleId(bundleName) while ax.AXTitle is None: ax = atomac.getAppRefByBundleId(bundleName) ax.activate() return UIApp(ax) def selectMenuItem(self, menuText, menuItemText): # AXMenuBar -> AXMenuBarItem -> AXMenu -> AXMenuItem menu = self.app.ax.AXMenuBar.findFirst(AXRole='AXMenuBarItem', AXTitle=menuText) menuitem = menu.findFirstR(AXRole='AXMenuItem', AXTitle=menuItemText) menu.Press() menuitem.Press() class UIAutomator: def __init__(self): self.app = None self.appName = 'QMapShack*' self.bundleId = 'org.qlandkarte.QMapShack' def appWin(self, reload=False): return self.app.find('AXWindow', None, reload) def openFileDlg(self, dirname, filename=None): fileDlg = self.app.find('AXWindow', 'Dateien*') if fileDlg.valid() == False: return False # input for directory self.app.sendKey('7', [SHIFT]) # / waitShort() dirInput = fileDlg.find('AXSheet') dirInput.find('AXTextField').setValue(dirname) waitShort() dirInput.findNr('AXButton', None, 1).click() # select file subelement = fileDlg.find('AXGroup').find('AXSplitGroup').find('AXSplitGroup').find('AXScrollArea').find('AXOutline') files = subelement.findAllR('AXTextField') found = False if filename is not None: for f in files: if f.ax.AXFilename == filename: f.click() break if found == False: files[0].click() # open fileDlg.find('AXButton', '\xd6ffnen').click() waitShort() return True def safeFileDlg(self, dirname, filename = None): fileDlg = self.app.find('AXWindow', 'Zieldatei*') if fileDlg.valid() == False: return False # input for directory self.app.sendKey('7', [SHIFT]) waitShort() dirInput = fileDlg.find('AXSheet') dirInput.find('AXTextField').setValue(dirname) self.app.sendKey('\n') waitShort() # set filename fileDlg.find('AXTextField').setValue(filename) waitShort() fileDlg.find('AXButton', 'Sichern').click() waitShort() return True def safeDirectoryDlg(self, dirname): # 'Zielpfad*' fileDlg = self.app.find('AXWindow') if fileDlg.valid() == False: return False # input for directory self.app.sendKey('7', [SHIFT]) waitShort() dirInput = fileDlg.find('AXSheet') dirInput.find('AXTextField').setValue(dirname) self.app.sendKey('\n') waitShort() fileDlg.find('AXButton', u'Öffnen').click() waitShort() return True def getAppHandle(self): self.app = UIApp.getApp(self.bundleId) return self.app.valid() def closeApp(self): self.app.sendKey('q', [COMMAND]) # TODO assert return True @staticmethod def debug(element, depth=1, nr=0, inv=0, typeMap=None): if depth <= inv and depth > 0: return if element is None: print "None element" elif isinstance(element, list): i = 0 ctypeMap = {} for e in element: UIAutomator.debug(e, depth, i, inv, ctypeMap) i = i+1 else: if typeMap is None: typeMap = {} type = element.ax.AXRole tcount = 0 if type in typeMap: tcount = tcount + typeMap[type] typeMap[type] = tcount pre = "".ljust(inv*4) print pre + str(nr) + " (" + str(typeMap[type]) +") " + str(element.ax) print pre +" attributes " + str(element.ax.getAttributes()) print pre +" actions: " + str(element.ax.getActions()) print pre +" Pos / Size: " + str(element.ax.AXPosition) + " " + str(element.ax.AXSize) print pre +" parent: "+ str(element.parent().ax) print pre +" children: " if element.ax.AXChildren is not None: c = 0 cinv = inv+1 ctypeMap = {} for child in element.ax.AXChildren: UIAutomator.debug(UIElement(child, element.app), depth, c, cinv, ctypeMap) c = c + 1 qmapshack-1.10.0/mkfile000755 001750 000144 00000001464 12540525371 016130 0ustar00oeichlerxusers000000 000000 #!/usr/bin/python import sys import os if len(sys.argv) != 2: print "bad number of arguments" sys.exit(-1) path = sys.argv[0][:-6] fn = sys.argv[1] if os.path.exists(fn): print "file already exists." sys.exit(-1) pathTemplates = os.path.join(path, "templates") name, ext = os.path.splitext(fn) if ext == ".h": template = os.path.join(pathTemplates, "header.h") elif ext == ".cpp": template = os.path.join(pathTemplates, "source.cpp") elif ext == ".c": template = os.path.join(pathTemplates, "source.c") else: print "unknown file type" sys.exit(-1) fid = file(template,"r") text = fid.read() fid.close() text = text.replace("CLASSNAME_H", name.upper() + "_H") text = text.replace("CLASSNAME", name) fid = file(fn,"w") fid.write(text) fid.close() qmapshack-1.10.0/cmake/000755 001750 000144 00000000000 13216664442 016012 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/cmake/Modules/000755 001750 000144 00000000000 13216664442 017422 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/cmake/Modules/MacroCopyFile.cmake000644 001750 000144 00000002157 12374350216 023120 0ustar00oeichlerxusers000000 000000 # - macro_copy_file(_src _dst) # Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst} # # Example: # macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.) # Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory # # Copyright (c) 2006-2007 Wengo # Copyright (c) 2006-2008 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING file. macro (macro_copy_file _src _dst) # Removes all path containing .svn or CVS or CMakeLists.txt during the copy if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*") if (CMAKE_VERBOSE_MAKEFILE) message(STATUS "Copy file from ${_src} to ${_dst}") endif (CMAKE_VERBOSE_MAKEFILE) # Creates directory if necessary get_filename_component(_path ${_dst} PATH) file(MAKE_DIRECTORY ${_path}) execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst} OUTPUT_QUIET ) endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*") endmacro (macro_copy_file) qmapshack-1.10.0/cmake/Modules/FindALGLIB.cmake000644 001750 000144 00000003474 13024173403 022154 0ustar00oeichlerxusers000000 000000 # - Try to find ALGLIB # Once done this will define # # ALGLIB_FOUND - system has ALGLIB # ALGLIB_INCLUDE_DIRS - the ALGLIB include directory # ALGLIB_LIBRARIES - Link these to use ALGLIB # ALGLIB_DEFINITIONS - Compiler switches required for using ALGLIB # # Copyright (c) 2009 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (ALGLIB_LIBRARIES AND ALGLIB_INCLUDE_DIRS) # in cache already set(ALGLIB_FOUND TRUE) else (ALGLIB_LIBRARIES AND ALGLIB_INCLUDE_DIRS) find_path(ALGLIB_INCLUDE_DIR NAMES interpolation.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_INSTALL_PREFIX}/include PATH_SUFFIXES alglib libalglib ) mark_as_advanced(ALGLIB_INCLUDE_DIR) find_library(ALGLIB_LIBRARY NAMES alglib PATHS /usr/lib64 /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_INSTALL_PREFIX}/lib ) mark_as_advanced(ALGLIB_LIBRARY) set(ALGLIB_INCLUDE_DIRS ${ALGLIB_INCLUDE_DIR} ) set(ALGLIB_LIBRARIES ${ALGLIB_LIBRARY} ) if (ALGLIB_INCLUDE_DIRS AND ALGLIB_LIBRARIES) set(ALGLIB_FOUND TRUE) endif (ALGLIB_INCLUDE_DIRS AND ALGLIB_LIBRARIES) if (ALGLIB_FOUND) if (NOT ALGLIB_FIND_QUIETLY) message(STATUS "Found ALGLIB: ${ALGLIB_LIBRARIES}") endif (NOT ALGLIB_FIND_QUIETLY) else (ALGLIB_FOUND) message(STATUS "Could not find ALGLIB using internal code.") endif (ALGLIB_FOUND) # show the PROJ_INCLUDE_DIRS and PROJ_LIBRARIES variables only in the advanced view mark_as_advanced(ALGLIB_INCLUDE_DIRS ALGLIB_LIBRARIES) endif (ALGLIB_LIBRARIES AND ALGLIB_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindQuaZip.cmake000644 001750 000144 00000005207 13066132137 022434 0ustar00oeichlerxusers000000 000000 # - Try to find QUAZIP # Once done this will define # # QUAZIP_FOUND - system has QUAZIP # QUAZIP_INCLUDE_DIRS - the QUAZIP include directory # QUAZIP_LIBRARIES - Link these to use QUAZIP # QUAZIP_DEFINITIONS - Compiler switches required for using QUAZIP # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (QUAZIP_LIBRARIES AND QUAZIP_INCLUDE_DIRS) # in cache already set(QUAZIP_FOUND TRUE) else (QUAZIP_LIBRARIES AND QUAZIP_INCLUDE_DIRS) find_path(QUAZIP_INCLUDE_DIR NAMES quazip.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/quazip5 /usr/local/include/quazip5 /opt/local/include/quazip5 /usr/include/quazip /usr/local/include/quazip /opt/local/include/quazip /sw/include/quazip5 ${CMAKE_INSTALL_PREFIX}/include ${QUAZIP_DEV_PATH}/include/ ) mark_as_advanced(QUAZIP_INCLUDE_DIR) IF (WIN32) FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h HINTS ${QT_DEV_PATH}/include/QtZlib/) ENDIF (WIN32) find_library(LIBQUAZIP_LIBRARY NAMES quazip5 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_INSTALL_PREFIX}/include ${QUAZIP_DEV_PATH}/lib ) mark_as_advanced(LIBQUAZIP_LIBRARY) if (LIBQUAZIP_LIBRARY) set(LIBQUAZIP_FOUND TRUE) endif (LIBQUAZIP_LIBRARY) set(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} IF (WIN32) ${QUAZIP_ZLIB_INCLUDE_DIR} ENDIF (WIN32) ) if (LIBQUAZIP_FOUND) set(QUAZIP_LIBRARIES ${QUAZIP_LIBRARIES} ${LIBQUAZIP_LIBRARY}) endif (LIBQUAZIP_FOUND) if (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) set(QUAZIP_FOUND TRUE) endif (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) if (QUAZIP_FOUND) if (NOT QUAZIP_FIND_QUIETLY) message(STATUS "Found QUAZIP: ${QUAZIP_LIBRARIES}") message(STATUS "Found QUAZIP: ${QUAZIP_INCLUDE_DIR}") endif (NOT QUAZIP_FIND_QUIETLY) else (QUAZIP_FOUND) if (QUAZIP_FIND_REQUIRED) message(FATAL_ERROR "Could not find QUAZIP") endif (QUAZIP_FIND_REQUIRED) endif (QUAZIP_FOUND) # show the QUAZIP_INCLUDE_DIRS and QUAZIP_LIBRARIES variables only in the advanced view mark_as_advanced(QUAZIP_INCLUDE_DIRS QUAZIP_LIBRARIES) endif (QUAZIP_LIBRARIES AND QUAZIP_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindEXIF.cmake000644 001750 000144 00000003360 12374350216 021755 0ustar00oeichlerxusers000000 000000 # - Try to find EXIF # Once done this will define # # EXIF_FOUND - system has EXIF # EXIF_INCLUDE_DIRS - the EXIF include directory # EXIF_LIBRARIES - Link these to use EXIF # EXIF_DEFINITIONS - Compiler switches required for using EXIF # # Copyright (c) 2006 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (EXIF_LIBRARIES AND EXIF_INCLUDE_DIRS) # in cache already set(EXIF_FOUND TRUE) else (EXIF_LIBRARIES AND EXIF_INCLUDE_DIRS) find_path(EXIF_INCLUDE_DIRS NAMES exif-data.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/libexif /usr/local/include/libexif /opt/local/include/libexif /sw/include/libexif ) # debian uses version suffixes # add suffix evey new release find_library(EXIF_LIBRARIES NAMES exif PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) if (EXIF_INCLUDE_DIRS AND EXIF_LIBRARIES) set(EXIF_FOUND TRUE) endif (EXIF_INCLUDE_DIRS AND EXIF_LIBRARIES) if (EXIF_FOUND) if (NOT EXIF_FIND_QUIETLY) message(STATUS "Found EXIF: ${EXIF_LIBRARIES}") endif (NOT EXIF_FIND_QUIETLY) else (EXIF_FOUND) if (EXIF_FIND_REQUIRED) message(FATAL_ERROR "Could not find EXIF") endif (EXIF_FIND_REQUIRED) endif (EXIF_FOUND) # show the EXIF_INCLUDE_DIRS and EXIF_LIBRARIES variables only in the advanced view mark_as_advanced(EXIF_INCLUDE_DIRS EXIF_LIBRARIES) endif (EXIF_LIBRARIES AND EXIF_INCLUDE_DIRS) if (WIN32) set(EXIF_FOUND TRUE) set(EXIF_LIBRARIES "") set(EXIF_INCLUDE_DIRS "") endif (WIN32) qmapshack-1.10.0/cmake/Modules/FindQtSoap.cmake000644 001750 000144 00000003561 12374350216 022434 0ustar00oeichlerxusers000000 000000 # - Try to find QtSoap # Once done this will define # # QTSOAP_FOUND - system has QTSOAP # QTSOAP_INCLUDE_DIRS - the QTSOAP include directory # QTSOAP_LIBRARIES - Link these to use QTSOAP # QTSOAP_DEFINITIONS - Compiler switches required for using QTSOAP # # Copyright (c) 2006 Andreas Schneider # updated for QtSoap by Dan Horák # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (QTSOAP_LIBRARIES AND QTSOAP_INCLUDE_DIRS) # in cache already set(QTSOAP_FOUND TRUE) else (QTSOAP_LIBRARIES AND QTSOAP_INCLUDE_DIRS) find_path(QTSOAP_INCLUDE_DIRS NAMES qtsoap.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/QtSoap /usr/local/include/QtSoap /opt/local/include/QtSoap /sw/include/QtSoap ) # debian uses version suffixes # add suffix evey new release find_library(QTSOAP_LIBRARIES NAMES qtsoap PATHS /usr/lib64 /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) if (QTSOAP_INCLUDE_DIRS AND QTSOAP_LIBRARIES) set(QTSOAP_FOUND TRUE) endif (QTSOAP_INCLUDE_DIRS AND QTSOAP_LIBRARIES) if (QTSOAP_FOUND) if (NOT QTSOAP_FIND_QUIETLY) message(STATUS "Found QtSoap: ${QTSOAP_LIBRARIES}") endif (NOT QTSOAP_FIND_QUIETLY) else (QTSOAP_FOUND) if (QTSOAP_FIND_REQUIRED) message(FATAL_ERROR "Could not find QtSoap") endif (QTSOAP_FIND_REQUIRED) endif (QTSOAP_FOUND) # show the QTSOAP_INCLUDE_DIRS and QTSOAP_LIBRARIES variables only in the advanced view mark_as_advanced(QTSOAP_INCLUDE_DIRS QTSOAP_LIBRARIES) endif (QTSOAP_LIBRARIES AND QTSOAP_INCLUDE_DIRS) if (WIN32) set(QTSOAP_FOUND FALSE) set(QTSOAP_LIBRARIES "") set(QTSOAP_INCLUDE_DIRS "") endif (WIN32) qmapshack-1.10.0/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000644 001750 000144 00000001227 12374350216 025762 0ustar00oeichlerxusers000000 000000 # - MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource) if (_insource) message(SEND_ERROR "${_errorMessage}") message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.") endif (_insource) endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) qmapshack-1.10.0/cmake/Modules/DefineInstallationPaths.cmake000644 001750 000144 00000007132 12374350216 025176 0ustar00oeichlerxusers000000 000000 if (UNIX) IF (NOT APPLICATION_NAME) MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME") SET(APPLICATION_NAME ${PROJECT_NAME}) ENDIF (NOT APPLICATION_NAME) STRING(TOLOWER ${APPLICATION_NAME} _APPLICATION_NAME) # Suffix for Linux SET(LIB_SUFFIX CACHE STRING "Define suffix of directory name (32/64)" ) SET(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" FORCE ) SET(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Base directory for files which go to share/" FORCE ) SET(DATA_INSTALL_PREFIX "${SHARE_INSTALL_PREFIX}/" CACHE PATH "The parent directory where applications can install their data" FORCE) # The following are directories where stuff will be installed to SET(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The ${_APPLICATION_NAME} binary install dir (default prefix/bin)" FORCE ) SET(SBIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/sbin" CACHE PATH "The ${_APPLICATION_NAME} sbin install dir (default prefix/sbin)" FORCE ) SET(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)" FORCE ) SET(LIBEXEC_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/libexec" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)" FORCE ) SET(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/${_APPLICATION_NAME}" CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${_APPLICATION_NAME})" FORCE ) SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix (default prefix/include)" FORCE ) SET(DATA_INSTALL_DIR "${DATA_INSTALL_PREFIX}" CACHE PATH "The parent directory where applications can install their data (default prefix/share/${_APPLICATION_NAME})" FORCE ) SET(HTML_INSTALL_DIR "${DATA_INSTALL_PREFIX}/doc/HTML" CACHE PATH "The HTML install dir for documentation (default data/doc/html)" FORCE ) SET(ICON_INSTALL_DIR "${DATA_INSTALL_PREFIX}/icons" CACHE PATH "The icon install dir (default data/icons/)" FORCE ) SET(SOUND_INSTALL_DIR "${DATA_INSTALL_PREFIX}/sounds" CACHE PATH "The install dir for sound files (default data/sounds)" FORCE ) SET(LOCALE_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/locale" CACHE PATH "The install dir for translations (default prefix/share/locale)" FORCE ) SET(XDG_APPS_DIR "${SHARE_INSTALL_PREFIX}/applications/" CACHE PATH "The XDG apps dir" FORCE ) SET(XDG_DIRECTORY_DIR "${SHARE_INSTALL_PREFIX}/desktop-directories" CACHE PATH "The XDG directory" FORCE ) SET(SYSCONF_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/etc" CACHE PATH "The ${_APPLICATION_NAME} sysconfig install dir (default prefix/etc)" FORCE ) SET(MAN_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/man" CACHE PATH "The ${_APPLICATION_NAME} man install dir (default prefix/man)" FORCE ) SET(INFO_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/info" CACHE PATH "The ${_APPLICATION_NAME} info install dir (default prefix/info)" FORCE ) endif (UNIX) if (WIN32) # Same same SET(BIN_INSTALL_DIR .) SET(SBIN_INSTALL_DIR .) SET(LIB_INSTALL_DIR .) SET(PLUGIN_INSTALL_DIR plugins) SET(HTML_INSTALL_DIR doc/HTML) SET(ICON_INSTALL_DIR .) SET(SOUND_INSTALL_DIR .) SET(LOCALE_INSTALL_DIR lang) endif (WIN32) qmapshack-1.10.0/cmake/Modules/Qt5PatchedLinguistToolsMacros.cmake000644 001750 000144 00000011172 12705713523 026272 0ustar00oeichlerxusers000000 000000 #============================================================================= # Copyright 2005-2011 Kitware, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of Kitware, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= include(CMakeParseArguments) function(QT5_PATCHED_CREATE_TRANSLATION _qm_files) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) cmake_parse_arguments(_LUPDATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(_lupdate_files ${_LUPDATE_UNPARSED_ARGUMENTS}) set(_lupdate_options ${_LUPDATE_OPTIONS}) set(_my_sources) set(_my_tsfiles) foreach(_file ${_lupdate_files}) get_filename_component(_ext ${_file} EXT) get_filename_component(_abs_FILE ${_file} ABSOLUTE) if(_ext MATCHES "ts") list(APPEND _my_tsfiles ${_abs_FILE}) else() list(APPEND _my_sources ${_abs_FILE}) endif() endforeach() foreach(_ts_file ${_my_tsfiles}) if(_my_sources) # make a list file to call lupdate on, so we don't make our commands too # long for some systems # get_filename_component(_ts_name ${_ts_file} NAME_WE) get_filename_component(_name ${_ts_file} NAME) string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _ts_name ${_name}) set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file") set(_lst_file_srcs) foreach(_lst_file_src ${_my_sources}) set(_lst_file_srcs "${_lst_file_src}\n${_lst_file_srcs}") endforeach() get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES) foreach(_pro_include ${_inc_DIRS}) get_filename_component(_abs_include "${_pro_include}" ABSOLUTE) set(_lst_file_srcs "-I${_pro_include}\n${_lst_file_srcs}") endforeach() file(WRITE ${_ts_lst_file} "${_lst_file_srcs}") endif() add_custom_command(OUTPUT ${_ts_file} COMMAND ${Qt5_LUPDATE_EXECUTABLE} ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file} DEPENDS ${_my_sources} ${_ts_lst_file} VERBATIM) endforeach() qt5_patched_add_translation(${_qm_files} ${_my_tsfiles}) set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() function(QT5_PATCHED_ADD_TRANSLATION _qm_files) foreach(_current_FILE ${ARGN}) get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE) # get_filename_component(qm ${_abs_FILE} NAME_WE) get_filename_component(_name ${_abs_FILE} NAME) string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" qm ${_name}) get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION) if(output_location) file(MAKE_DIRECTORY "${output_location}") set(qm "${output_location}/${qm}.qm") else() set(qm "${CMAKE_CURRENT_BINARY_DIR}/${qm}.qm") endif() add_custom_command(OUTPUT ${qm} COMMAND ${Qt5_LRELEASE_EXECUTABLE} ARGS ${_abs_FILE} -qm ${qm} DEPENDS ${_abs_FILE} VERBATIM ) list(APPEND ${_qm_files} ${qm}) endforeach() set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() qmapshack-1.10.0/cmake/Modules/TranslateTs.cmake000644 001750 000144 00000012767 12705713523 022702 0ustar00oeichlerxusers000000 000000 #============================================================================= # Copyright 2014 Luís Pereira # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= # # funtion translate_ts(qmFiles # [USE_QT5 [Yes | No]] # [UPDATE_TRANSLATIONS [Yes | No]] # [UPDATE_OPTIONS] update_options # SOURCES # [TEMPLATE] translation_template # [TRANSLATION_DIR] translation_directory # [INSTALL_DIR] install_directory # [COMPONENT] component # ) # Output: # qmFiles The generated compiled translations (.qm) files # # Input: # USE_QT5 Optional flag to choose between Qt4 and Qt5. Defaults to Qt5 # # UPDATE_TRANSLATIONS Optional flag. Setting it to Yes, extracts and # compiles the translations. Setting it No, only # compiles them. # # UPDATE_OPTIONS Optional options to lupdate when UPDATE_TRANSLATIONS # is True. # # TEMPLATE Optional translations files base name. Defaults to # ${PROJECT_NAME}. An .ts extensions is added. # # TRANSLATION_DIR Optional path to the directory with the .ts files, # relative to the CMakeList.txt. Defaults to # "translations". # # INSTALL_DIR Optional destination of the file compiled files (qmFiles). # If not present no installation is performed # # COMPONENT Optional install component. Only effective if INSTALL_DIR # present. Defaults to "Runtime". # CMake v2.8.3 needed to use the CMakeParseArguments module cmake_minimum_required(VERSION 2.8.3 FATAL_ERROR) # We use our patched version to round a annoying bug. include(Qt5PatchedLinguistToolsMacros) function(translate_ts qmFiles) set(oneValueArgs USE_QT5 UPDATE_TRANSLATIONS TEMPLATE TRANSLATION_DIR INSTALL_DIR COMPONENT) set(multiValueArgs SOURCES UPDATE_OPTIONS) cmake_parse_arguments(TR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if (NOT DEFINED TR_UPDATE_TRANSLATIONS) set(TR_UPDATE_TRANSLATIONS "No") endif() if (NOT DEFINED TR_UPDATE_OPTIONS) set(TR_UPDATE_OPTIONS "") endif() message(STATUS "") if (NOT DEFINED TR_USE_QT5) set(TR_USE_QT5 "Yes") endif() if(NOT DEFINED TR_TEMPLATE) set(TR_TEMPLATE "${PROJECT_NAME}") endif() if (NOT DEFINED TR_TRANSLATION_DIR) set(TR_TRANSLATION_DIR "translations") endif() file(GLOB tsFiles "${TR_TRANSLATION_DIR}/${TR_TEMPLATE}_*.ts") set(templateFile "${TR_TRANSLATION_DIR}/${TR_TEMPLATE}.ts") if(TR_USE_QT5) # Qt5 if (TR_UPDATE_TRANSLATIONS) qt5_patched_create_translation(QMS ${TR_SOURCES} ${templateFile} OPTIONS ${TR_UPDATE_OPTIONS} ) qt5_patched_create_translation(QM ${TR_SOURCES} ${tsFiles} OPTIONS ${TR_UPDATE_OPTIONS} ) else() qt5_patched_add_translation(QM ${tsFiles}) endif() else() # Qt4 if(TR_UPDATE_TRANSLATIONS) qt4_create_translation(QMS ${TR_SOURCES} ${templateFile} OPTIONS ${TR_UPDATE_OPTIONS} ) qt4_create_translation(QM ${TR_SOURCES} ${tsFiles} OPTIONS ${TR_UPDATE_OPTIONS} ) else() qt4_add_translation(QM ${tsFiles}) endif() endif() if(TR_UPDATE_TRANSLATIONS) add_custom_target("update_${TR_TEMPLATE}_ts" ALL DEPENDS ${QMS}) endif() if(DEFINED TR_INSTALL_DIR) if(NOT DEFINED TR_COMPONENT) set(TR_COMPONENT "Runtime") endif() install(FILES ${QM} DESTINATION "${TR_INSTALL_DIR}" COMPONENT "${TR_COMPONENT}" ) endif() set(${qmFiles} ${QM} PARENT_SCOPE) endfunction() qmapshack-1.10.0/cmake/Modules/FindJPEG.cmake000644 001750 000144 00000004110 12374350216 021741 0ustar00oeichlerxusers000000 000000 # - Try to find LIBJPEG # Once done this will define # # JPEG_FOUND - system has LIBJPEG # JPEG_INCLUDE_DIRS - the LIBJPEG include directory # JPEG_LIBRARIES - Link these to use LIBJPEG # JPEG_DEFINITIONS - Compiler switches required for using LIBJPEG # # Copyright (c) 2009 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # NOTE: For Windows, please adapt the path (currently E:/qlgt/tools/libjpeg/win32) # to your local installation directory if (JPEG_LIBRARIES AND JPEG_INCLUDE_DIRS) # in cache already set(JPEG_FOUND TRUE) else (JPEG_LIBRARIES AND JPEG_INCLUDE_DIRS) find_path(JPEG_INCLUDE_DIR NAMES jpeglib.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_SOURCE_DIR}/Win32/GDAL/include ) mark_as_advanced(JPEG_INCLUDE_DIR) find_library(LIBJPEG_LIBRARY NAMES if (WIN32) libjpeg else (WIN32) jpeg endif (WIN32) PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_SOURCE_DIR}/Win32/GDAL/lib ) mark_as_advanced(LIBJPEG_LIBRARY) if (LIBJPEG_LIBRARY) set(LIBJPEG_FOUND TRUE) endif (LIBJPEG_LIBRARY) set(JPEG_INCLUDE_DIRS ${JPEG_INCLUDE_DIR} ) if (LIBJPEG_FOUND) set(JPEG_LIBRARIES ${JPEG_LIBRARIES} ${LIBJPEG_LIBRARY} ) endif (LIBJPEG_FOUND) if (JPEG_INCLUDE_DIRS AND JPEG_LIBRARIES) set(JPEG_FOUND TRUE) endif (JPEG_INCLUDE_DIRS AND JPEG_LIBRARIES) if (JPEG_FOUND) if (NOT JPEG_FIND_QUIETLY) message(STATUS "Found LIBJPEG: ${JPEG_LIBRARIES}") endif (NOT JPEG_FIND_QUIETLY) else (JPEG_FOUND) if (JPEG_FIND_REQUIRED) message(FATAL_ERROR "Could not find LIBJPEG") endif (JPEG_FIND_REQUIRED) endif (JPEG_FOUND) # show the JPEG_INCLUDE_DIRS and JPEG_LIBRARIES variables only in the advanced view mark_as_advanced(JPEG_INCLUDE_DIRS JPEG_LIBRARIES) endif (JPEG_LIBRARIES AND JPEG_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindDMTX.cmake000644 001750 000144 00000003425 12374350216 022000 0ustar00oeichlerxusers000000 000000 # - Try to find DMTX # Once done this will define # # DMTX_FOUND - system has DMTX # DMTX_INCLUDE_DIRS - the DMTX include directory # DMTX_LIBRARIES - Link these to use DMTX # DMTX_DEFINITIONS - Compiler switches required for using DMTX # # Copyright (c) 2006 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (DMTX_LIBRARIES AND DMTX_INCLUDE_DIRS) # in cache already set(DMTX_FOUND TRUE) else (DMTX_LIBRARIES AND DMTX_INCLUDE_DIRS) find_path(DMTX_INCLUDE_DIRS NAMES dmtx.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/libdmtx /usr/local/include/libdmtx /opt/local/include/libdmtx /sw/include/libdmtx ../../tools/libdmtx ) # debian uses version suffixes # add suffix evey new release find_library(DMTX_LIBRARIES NAMES if (WIN32) libdmtx else (WIN32) dmtx endif (WIN32) PATHS /usr/lib64 /usr/lib /usr/local/lib /opt/local/lib /sw/lib ../../tools/libdmtx ) if (DMTX_INCLUDE_DIRS AND DMTX_LIBRARIES) set(DMTX_FOUND TRUE) endif (DMTX_INCLUDE_DIRS AND DMTX_LIBRARIES) if (DMTX_FOUND) if (NOT DMTX_FIND_QUIETLY) message(STATUS "Found DMTX: ${DMTX_LIBRARIES}") endif (NOT DMTX_FIND_QUIETLY) else (DMTX_FOUND) if (DMTX_FIND_REQUIRED) message(FATAL_ERROR "Could not find DMTX") endif (DMTX_FIND_REQUIRED) endif (DMTX_FOUND) # show the DMTX_INCLUDE_DIRS and DMTX_LIBRARIES variables only in the advanced view mark_as_advanced(DMTX_INCLUDE_DIRS DMTX_LIBRARIES) endif (DMTX_LIBRARIES AND DMTX_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindPROJ.cmake000644 001750 000144 00000004140 12765457042 022002 0ustar00oeichlerxusers000000 000000 # - Try to find PROJ # Once done this will define # # PROJ_FOUND - system has PROJ # PROJ_INCLUDE_DIRS - the PROJ include directory # PROJ_LIBRARIES - Link these to use PROJ # PROJ_DEFINITIONS - Compiler switches required for using PROJ # # Copyright (c) 2009 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS) # in cache already set(PROJ_FOUND TRUE) else (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS) find_path(PROJ_INCLUDE_DIR NAMES proj_api.h PATHS if(WIN32) ${PROJ_DEV_PATH}/include endif(WIN32) /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_INSTALL_PREFIX}/include ${CMAKE_SOURCE_DIR}/Win32/GDAL/include PATH_SUFFIXES proj4 ) mark_as_advanced(PROJ_INCLUDE_DIR) find_library(LIBPROJ_LIBRARY NAMES proj proj_i PATHS if(WIN32) ${PROJ_DEV_PATH}/lib endif(WIN32) /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_SOURCE_DIR}/Win32/GDAL/lib ) mark_as_advanced(LIBPROJ_LIBRARY) if (LIBPROJ_LIBRARY) set(LIBPROJ_FOUND TRUE) endif (LIBPROJ_LIBRARY) set(PROJ_INCLUDE_DIRS ${PROJ_INCLUDE_DIR} ) if (LIBPROJ_FOUND) set(PROJ_LIBRARIES ${PROJ_LIBRARIES} ${LIBPROJ_LIBRARY} ) endif (LIBPROJ_FOUND) if (PROJ_INCLUDE_DIRS AND PROJ_LIBRARIES) set(PROJ_FOUND TRUE) endif (PROJ_INCLUDE_DIRS AND PROJ_LIBRARIES) if (PROJ_FOUND) if (NOT PROJ_FIND_QUIETLY) message(STATUS "Found PROJ: ${PROJ_LIBRARIES}") endif (NOT PROJ_FIND_QUIETLY) else (PROJ_FOUND) if (PROJ_FIND_REQUIRED) message(FATAL_ERROR "Could not find PROJ") endif (PROJ_FIND_REQUIRED) endif (PROJ_FOUND) # show the PROJ_INCLUDE_DIRS and PROJ_LIBRARIES variables only in the advanced view mark_as_advanced(PROJ_INCLUDE_DIRS PROJ_LIBRARIES) endif (PROJ_LIBRARIES AND PROJ_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindGPSD.cmake000644 001750 000144 00000003353 12374350216 021761 0ustar00oeichlerxusers000000 000000 # - Try to find GPSD # Once done this will define # # GPSD_FOUND - system has GPSD # GPSD_INCLUDE_DIRS - the GPSD include directory # GPSD_LIBRARIES - Link these to use GPSD # GPSD_DEFINITIONS - Compiler switches required for using GPSD # # Copyright (c) 2006 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS) # in cache already set(GPSD_FOUND TRUE) else (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS) find_path(GPSD_INCLUDE_DIRS NAMES gps.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/gps /usr/local/include/gps /opt/local/include/gps /sw/include/gps ) # debian uses version suffixes # add suffix evey new release find_library(GPSD_LIBRARIES NAMES gps PATHS /usr/lib64 /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) if (GPSD_INCLUDE_DIRS AND GPSD_LIBRARIES) set(GPSD_FOUND TRUE) endif (GPSD_INCLUDE_DIRS AND GPSD_LIBRARIES) if (GPSD_FOUND) if (NOT GPSD_FIND_QUIETLY) message(STATUS "Found GPSD: ${GPSD_LIBRARIES}") endif (NOT GPSD_FIND_QUIETLY) else (GPSD_FOUND) if (GPSD_FIND_REQUIRED) message(FATAL_ERROR "Could not find GPSD") endif (GPSD_FIND_REQUIRED) endif (GPSD_FOUND) # show the GPSD_INCLUDE_DIRS and GPSD_LIBRARIES variables only in the advanced view mark_as_advanced(GPSD_INCLUDE_DIRS GPSD_LIBRARIES) endif (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS) if (WIN32) set(GPSD_FOUND FALSE) set(GPSD_LIBRARIES "") set(GPSD_INCLUDE_DIRS "") endif (WIN32) qmapshack-1.10.0/cmake/Modules/DefineCMakeDefaults.cmake000644 001750 000144 00000001611 12374350216 024201 0ustar00oeichlerxusers000000 000000 # Always include srcdir and builddir in include path # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in # about every subdir # since cmake 2.4.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # Put the include dirs which are in the source or build tree # before all other include dirs, so the headers in the sources # are prefered over the already installed ones # since cmake 2.4.1 set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output # since cmake 2.4.0 set(CMAKE_COLOR_MAKEFILE ON) # Define the generic version of the libraries here set(GENERIC_LIB_VERSION "0.1.0") set(GENERIC_LIB_SOVERSION "0") # Set the default build type to release with debug info if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE ) endif (NOT CMAKE_BUILD_TYPE) qmapshack-1.10.0/cmake/Modules/FindGDAL.cmake000644 001750 000144 00000004265 12765457042 021747 0ustar00oeichlerxusers000000 000000 # - Try to find GDAL # Once done this will define # # GDAL_FOUND - system has GDAL # GDAL_INCLUDE_DIRS - the GDAL include directory # GDAL_LIBRARIES - Link these to use GDAL # GDAL_DEFINITIONS - Compiler switches required for using GDAL # # Copyright (c) 2006 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS) # in cache already set(GDAL_FOUND TRUE) else (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS) find_path(GDAL_INCLUDE_DIR NAMES gdal.h PATHS if(WIN32) ${GDAL_DEV_PATH}/include endif(WIN32) /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_INSTALL_PREFIX}/include /usr/include/gdal /usr/local/include/gdal /opt/local/include/gdal /sw/include/gdal ${CMAKE_INSTALL_PREFIX}/include/gdal ${CMAKE_SOURCE_DIR}/Win32/GDAL/include PATH_SUFFIXES gdal ) # debian uses version suffixes # add suffix evey new release find_library(GDAL_LIBRARY NAMES gdal gdal1.3.2 gdal1.4.0 gdal1.5.0 gdal1.6.0 gdal1.7.0 gdal1.8.0 gdal gdal_i PATHS if(WIN32) ${GDAL_DEV_PATH}/lib endif(WIN32) /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_SOURCE_DIR}/Win32/GDAL/lib ) set(GDAL_INCLUDE_DIRS ${GDAL_INCLUDE_DIR} ) set(GDAL_LIBRARIES ${GDAL_LIBRARY} ) if (GDAL_INCLUDE_DIRS AND GDAL_LIBRARIES) set(GDAL_FOUND TRUE) endif (GDAL_INCLUDE_DIRS AND GDAL_LIBRARIES) if (GDAL_FOUND) if (NOT GDAL_FIND_QUIETLY) message(STATUS "Found GDAL: ${GDAL_LIBRARIES}") endif (NOT GDAL_FIND_QUIETLY) else (GDAL_FOUND) if (GDAL_FIND_REQUIRED) message(FATAL_ERROR "Could not find GDAL") endif (GDAL_FIND_REQUIRED) endif (GDAL_FOUND) # show the GDAL_INCLUDE_DIRS and GDAL_LIBRARIES variables only in the advanced view mark_as_advanced(GDAL_INCLUDE_DIRS GDAL_LIBRARIES) endif (GDAL_LIBRARIES AND GDAL_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindXercesC.cmake000644 001750 000144 00000004775 12374350216 022571 0ustar00oeichlerxusers000000 000000 # - Try to find XercesC # Once done this will define # # XERCESC_FOUND - system has XercesC # XERCESC_INCLUDE_DIRS - the XercesC include directory # XERCESC_LIBRARIES - Link these to use XercesC # XERCESC_DEFINITIONS - Compiler switches required for using XercesC # # Copyright (c) 2009 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS) # in cache already set(XERCESC_FOUND TRUE) else (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS) find_path(XERCESC_INCLUDE_DIR NAMES xercesc/util/XercesVersion.hpp PATHS /usr/include /usr/local/include /opt/local/include /sw/include C:/progra~1/xerces-c_2_8_0/include ) mark_as_advanced(XERCESC_INCLUDE_DIR) find_library(XERCES-C_LIBRARY NAMES xerces-c xerces-c_2 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib C:/progra~1/xerces-c_2_8_0/lib ) mark_as_advanced(XERCES-C_LIBRARY) find_library(XERCES-DEPDOM_LIBRARY NAMES xerces-depdom xerces-depdom_2 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib C:/progra~1/xerces-c_2_8_0/lib ) mark_as_advanced(XERCES-DEPDOM_LIBRARY) if (XERCES-C_LIBRARY) set(XERCES-C_FOUND TRUE) endif (XERCES-C_LIBRARY) if (XERCES-DEPDOM_LIBRARY) set(XERCES-DEPDOM_FOUND TRUE) endif (XERCES-DEPDOM_LIBRARY) set(XERCESC_INCLUDE_DIRS ${XERCESC_INCLUDE_DIR} ) if (XERCES-C_FOUND) set(XERCESC_LIBRARIES ${XERCESC_LIBRARIES} ${XERCES-C_LIBRARY} ) endif (XERCES-C_FOUND) if (XERCES-DEPDOM_FOUND) set(XERCESC_LIBRARIES ${XERCESC_LIBRARIES} ${XERCES-DEPDOM_LIBRARY} ) endif (XERCES-DEPDOM_FOUND) if (XERCESC_INCLUDE_DIRS AND XERCESC_LIBRARIES) set(XERCESC_FOUND TRUE) endif (XERCESC_INCLUDE_DIRS AND XERCESC_LIBRARIES) if (XERCESC_FOUND) if (NOT XercesC_FIND_QUIETLY) message(STATUS "Found XercesC: ${XERCESC_LIBRARIES}") endif (NOT XercesC_FIND_QUIETLY) else (XERCESC_FOUND) if (XercesC_FIND_REQUIRED) message(FATAL_ERROR "Could not find XercesC") endif (XercesC_FIND_REQUIRED) endif (XERCESC_FOUND) # show the XERCESC_INCLUDE_DIRS and XERCESC_LIBRARIES variables only in the advanced view mark_as_advanced(XERCESC_INCLUDE_DIRS XERCESC_LIBRARIES) endif (XERCESC_LIBRARIES AND XERCESC_INCLUDE_DIRS) qmapshack-1.10.0/cmake/Modules/FindQextSerialPort.cmake000644 001750 000144 00000004363 12374350216 024154 0ustar00oeichlerxusers000000 000000 # - Try to find QextSerialPort # Once done this will define # # QEXTSERIALPORT_FOUND - system has QEXTSERIALPORT # QEXTSERIALPORT_INCLUDE_DIRS - the QEXTSERIALPORT include directory # QEXTSERIALPORT_LIBRARIES - Link these to use QEXTSERIALPORT # QEXTSERIALPORT_DEFINITIONS - Compiler switches required for using QEXTSERIALPORT # # Copyright (c) 2006 Andreas Schneider # updated for QextSerialPort by Dan Horák # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (QEXTSERIALPORT_LIBRARIES AND QEXTSERIALPORT_INCLUDE_DIRS) # in cache already set(QEXTSERIALPORT_FOUND TRUE) else (QEXTSERIALPORT_LIBRARIES AND QEXTSERIALPORT_INCLUDE_DIRS) find_path(QEXTSERIALPORT_INCLUDE_DIRS NAMES qextserialport.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include /usr/include/QtExtSerialPort /usr/local/include/QtExtSerialPort /opt/local/include/QtExtSerialPort /sw/include/QtExtSerialPort ) # debian uses version suffixes # add suffix evey new release find_library(QEXTSERIALPORT_LIBRARIES NAMES qextserialport-1.2 PATHS /usr/lib64 /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) if (QEXTSERIALPORT_INCLUDE_DIRS AND QEXTSERIALPORT_LIBRARIES) set(QEXTSERIALPORT_FOUND TRUE) endif (QEXTSERIALPORT_INCLUDE_DIRS AND QEXTSERIALPORT_LIBRARIES) if (QEXTSERIALPORT_FOUND) if (NOT QEXTSERIALPORT_FIND_QUIETLY) message(STATUS "Found QtExtSerialPort: ${QEXTSERIALPORT_LIBRARIES}") endif (NOT QEXTSERIALPORT_FIND_QUIETLY) else (QEXTSERIALPORT_FOUND) if (QEXTSERIALPORT_FIND_REQUIRED) message(FATAL_ERROR "Could not find QtExtSerialPort") endif (QEXTSERIALPORT_FIND_REQUIRED) endif (QEXTSERIALPORT_FOUND) # show the QEXTSERIALPORT_INCLUDE_DIRS and QEXTSERIALPORT_LIBRARIES variables only in the advanced view mark_as_advanced(QEXTSERIALPORT_INCLUDE_DIRS QEXTSERIALPORT_LIBRARIES) endif (QEXTSERIALPORT_LIBRARIES AND QEXTSERIALPORT_INCLUDE_DIRS) if (WIN32) set(QEXTSERIALPORT_FOUND FALSE) set(QEXTSERIALPORT_LIBRARIES "") set(QEXTSERIALPORT_INCLUDE_DIRS "") endif (WIN32) qmapshack-1.10.0/cmake/Modules/CMakeLists.txt000644 001750 000144 00000001556 13024173403 022156 0ustar00oeichlerxusers000000 000000 # install the cmake files file(GLOB cmakeFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.cmake") set(module_install_dir ${DATA_INSTALL_DIR}/cmake/modules ) install( FILES ${cmakeFiles} DESTINATION ${module_install_dir} ) # the files listed here will be removed by remove_obsoleted_cmake_files.cmake, Alex set(FILES_TO_REMOVE ) install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake ) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "#generated by cmake, don't edit\n\n") foreach ( _current_FILE ${FILES_TO_REMOVE}) file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "message(STATUS \"Removing ${module_install_dir}/${_current_FILE}\" )\n" ) file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/remove_files.cmake "exec_program( ${CMAKE_COMMAND} ARGS -E remove ${module_install_dir}/${_current_FILE} OUTPUT_VARIABLE _dummy)\n" ) endforeach ( _current_FILE) qmapshack-1.10.0/cmake/Modules/DefineCompilerFlags.cmake000644 001750 000144 00000000531 12374350216 024260 0ustar00oeichlerxusers000000 000000 # define system dependent compiler flags include(CheckCXXCompilerFlag) # with -fPIC if(UNIX AND NOT WIN32) if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") check_cxx_compiler_flag("-fPIC" WITH_FPIC) if(WITH_FPIC) ADD_DEFINITIONS(-fPIC) endif(WITH_FPIC) endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") endif(UNIX AND NOT WIN32) qmapshack-1.10.0/cmake/Modules/TranslateDesktop.cmake000644 001750 000144 00000006132 12705713523 023712 0ustar00oeichlerxusers000000 000000 #============================================================================= # The translate_desktop() function was copied from the # LXQt LXQtTranslate.cmake # # Original Author: Alexander Sokolov # # funtion translate_desktop(_RESULT # SOURCES # [TRANSLATION_DIR] translation_directory # ) # Output: # _RESULT The generated .desktop (.desktop) files # # Input: # # SOURCES List of input desktop files (.destktop.in) to be translated # (merged), relative to the CMakeList.txt. # # TRANSLATION_DIR Optional path to the directory with the .ts files, # relative to the CMakeList.txt. Defaults to # "translations". # #============================================================================= function(translate_desktop _RESULT) # Parse arguments *************************************** set(oneValueArgs TRANSLATION_DIR) set(multiValueArgs SOURCES) cmake_parse_arguments(_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # check for unknown arguments set(_UNPARSED_ARGS ${_ARGS_UNPARSED_ARGUMENTS}) if (NOT ${_UNPARSED_ARGS} STREQUAL "") MESSAGE(FATAL_ERROR "Unknown arguments '${_UNPARSED_ARGS}'.\n" "See translate_desktop() documentation for more information.\n" ) endif() if (NOT DEFINED _ARGS_SOURCES) set(${_RESULT} "" PARENT_SCOPE) return() else() set(_sources ${_ARGS_SOURCES}) endif() if (NOT DEFINED _ARGS_TRANSLATION_DIR) set(_translationDir "translations") else() set(_translationDir ${_ARGS_TRANSLATION_DIR}) endif() get_filename_component (_translationDir ${_translationDir} ABSOLUTE) foreach (_inFile ${_sources}) get_filename_component(_inFile ${_inFile} ABSOLUTE) get_filename_component(_fileName ${_inFile} NAME_WE) #Extract the real extension ............ get_filename_component(_fileExt ${_inFile} EXT) string(REPLACE ".in" "" _fileExt ${_fileExt}) #....................................... set(_outFile "${CMAKE_CURRENT_BINARY_DIR}/${_fileName}${_fileExt}") file(GLOB _translations ${_translationDir}/${_fileName}_*${_fileExt} ) set(_pattern "'\\[.*]\\s*='") if (_translations) list(SORT _translations) add_custom_command(OUTPUT ${_outFile} COMMAND grep -v -a "'#TRANSLATIONS_DIR='" ${_inFile} > ${_outFile} COMMAND grep -h -a ${_pattern} ${_translations} >> ${_outFile} COMMENT "Generating ${_fileName}${_fileExt}" ) else() add_custom_command(OUTPUT ${_outFile} COMMAND grep -v -a "'#TRANSLATIONS_DIR='" ${_inFile} > ${_outFile} COMMENT "Generating ${_fileName}${_fileExt}" ) endif() set(__result ${__result} ${_outFile}) endforeach() set(${_RESULT} ${__result} PARENT_SCOPE) endfunction(translate_desktop) qmapshack-1.10.0/cmake/Modules/COPYING-CMAKE-SCRIPTS000644 001750 000144 00000002457 12374350216 022423 0ustar00oeichlerxusers000000 000000 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. qmapshack-1.10.0/cmake/Modules/FindROUTINO.cmake000644 001750 000144 00000005645 12765457042 022402 0ustar00oeichlerxusers000000 000000 # - Try to find ROUTINO # Once done this will define # # ROUTINO_FOUND - system has ROUTINO # ROUTINO_INCLUDE_DIRS - the ROUTINO include directory # ROUTINO_LIBRARIES - Link these to use ROUTINO # ROUTINO_DEFINITIONS - Compiler switches required for using ROUTINO # ROUTINO_XML_PATH - Path to profile.xml and translation.xml # # Copyright (c) 2009 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (ROUTINO_LIBRARIES AND ROUTINO_INCLUDE_DIRS AND ROUTINO_XML_PATH) # in cache already set(ROUTINO_FOUND TRUE) else (ROUTINO_LIBRARIES AND ROUTINO_INCLUDE_DIRS AND ROUTINO_XML_PATH) find_path(ROUTINO_INCLUDE_DIR NAMES routino.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_INSTALL_PREFIX}/include ${ROUTINO_DEV_PATH}/include/ ) mark_as_advanced(ROUTINO_INCLUDE_DIR) find_library(LIBROUTINO_LIBRARY NAMES routino PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_INSTALL_PREFIX}/include ${ROUTINO_DEV_PATH}/lib ) mark_as_advanced(LIBROUTINO_LIBRARY) find_path(ROUTINO_XML_PATH NAMES profiles.xml translations.xml tagging.xml PATHS /usr/share/routino /usr/local/share/routino /opt/local/share/routino ${CMAKE_INSTALL_PREFIX}/share/routino ${ROUTINO_DEV_PATH}/xml/ ) mark_as_advanced(ROUTINO_XML_PATH) if (LIBROUTINO_LIBRARY) set(LIBROUTINO_FOUND TRUE) endif (LIBROUTINO_LIBRARY) set(ROUTINO_INCLUDE_DIRS ${ROUTINO_INCLUDE_DIR} ) if (LIBROUTINO_FOUND) set(ROUTINO_LIBRARIES ${ROUTINO_LIBRARIES} ${LIBROUTINO_LIBRARY}) endif (LIBROUTINO_FOUND) if (ROUTINO_INCLUDE_DIRS AND ROUTINO_LIBRARIES AND ROUTINO_XML_PATH) set(ROUTINO_FOUND TRUE) endif (ROUTINO_INCLUDE_DIRS AND ROUTINO_LIBRARIES AND ROUTINO_XML_PATH) if (ROUTINO_FOUND) if (NOT ROUTINO_FIND_QUIETLY) message(STATUS "Found ROUTINO: ${ROUTINO_LIBRARIES}") message(STATUS "Found ROUTINO: ${ROUTINO_INCLUDE_DIR}") message(STATUS "Found ROUTINO: ${ROUTINO_XML_PATH}") endif (NOT ROUTINO_FIND_QUIETLY) else (ROUTINO_FOUND) if (ROUTINO_FIND_REQUIRED) message(FATAL_ERROR "Could not find ROUTINO") endif (ROUTINO_FIND_REQUIRED) endif (ROUTINO_FOUND) # show the ROUTINO_INCLUDE_DIRS and ROUTINO_LIBRARIES variables only in the advanced view mark_as_advanced(ROUTINO_INCLUDE_DIRS ROUTINO_LIBRARIES ROUTINO_XML_PATH) endif (ROUTINO_LIBRARIES AND ROUTINO_INCLUDE_DIRS AND ROUTINO_XML_PATH) qmapshack-1.10.0/cmake/CMakeLists.txt000644 001750 000144 00000000032 12374350216 020540 0ustar00oeichlerxusers000000 000000 add_subdirectory(Modules) qmapshack-1.10.0/3rdparty/000755 001750 000144 00000000000 13216664442 016502 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/3rdparty/alglib/000755 001750 000144 00000000000 13216664442 017734 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/3rdparty/alglib/src/000755 001750 000144 00000000000 13216664442 020523 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/3rdparty/alglib/src/alglibinternal.h000755 001750 000144 00000106405 13015033052 023654 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _alglibinternal_pkg_h #define _alglibinternal_pkg_h #include "ap.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_vector ba0; ae_vector ia0; ae_vector ia1; ae_vector ia2; ae_vector ia3; ae_vector ra0; ae_vector ra1; ae_vector ra2; ae_vector ra3; ae_matrix rm0; ae_matrix rm1; } apbuffers; typedef struct { ae_bool val; } sboolean; typedef struct { ae_vector val; } sbooleanarray; typedef struct { ae_int_t val; } sinteger; typedef struct { ae_vector val; } sintegerarray; typedef struct { double val; } sreal; typedef struct { ae_vector val; } srealarray; typedef struct { ae_complex val; } scomplex; typedef struct { ae_vector val; } scomplexarray; typedef struct { ae_int_t chunksize; ae_int_t ntotal; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_vector batch4buf; ae_vector hpcbuf; ae_matrix xy; ae_matrix xy2; ae_vector xyrow; ae_vector x; ae_vector y; ae_vector desiredy; double e; ae_vector g; ae_vector tmp0; } mlpbuffers; typedef struct { ae_bool brackt; ae_bool stage1; ae_int_t infoc; double dg; double dgm; double dginit; double dgtest; double dgx; double dgxm; double dgy; double dgym; double finit; double ftest1; double fm; double fx; double fxm; double fy; double fym; double stx; double sty; double stmin; double stmax; double width; double width1; double xtrapf; } linminstate; typedef struct { ae_bool needf; ae_vector x; double f; ae_int_t n; ae_vector xbase; ae_vector s; double stplen; double fcur; double stpmax; ae_int_t fmax; ae_int_t nfev; ae_int_t info; rcommstate rstate; } armijostate; typedef struct { ae_matrix entries; ae_vector buffer; ae_vector precr; ae_vector preci; ae_shared_pool bluesteinpool; } fasttransformplan; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { ae_bool seterrorflag(ae_bool* flag, ae_bool cond, ae_state *_state); ae_bool seterrorflagdiff(ae_bool* flag, double val, double refval, double tol, double s, ae_state *_state); void touchint(ae_int_t* a, ae_state *_state); void touchreal(double* a, ae_state *_state); double coalesce(double a, double b, ae_state *_state); double inttoreal(ae_int_t a, ae_state *_state); double logbase2(double x, ae_state *_state); ae_bool approxequalrel(double a, double b, double tol, ae_state *_state); void taskgenint1d(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void taskgenint1dequidist(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void taskgenint1dcheb1(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void taskgenint1dcheb2(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); ae_bool aredistinct(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state); void bvectorsetlengthatleast(/* Boolean */ ae_vector* x, ae_int_t n, ae_state *_state); void ivectorsetlengthatleast(/* Integer */ ae_vector* x, ae_int_t n, ae_state *_state); void rvectorsetlengthatleast(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); void rmatrixsetlengthatleast(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); void rmatrixresize(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); void imatrixresize(/* Integer */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); ae_bool isfinitevector(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); ae_bool isfinitecvector(/* Complex */ ae_vector* z, ae_int_t n, ae_state *_state); ae_bool apservisfinitematrix(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); ae_bool isfinitertrmatrix(/* Real */ ae_matrix* x, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool apservisfiniteornanmatrix(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state); double safepythag2(double x, double y, ae_state *_state); double safepythag3(double x, double y, double z, ae_state *_state); ae_int_t saferdiv(double x, double y, double* r, ae_state *_state); double safeminposrv(double x, double y, double v, ae_state *_state); void apperiodicmap(double* x, double a, double b, double* k, ae_state *_state); double randomnormal(ae_state *_state); void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); void swapi(ae_int_t* v0, ae_int_t* v1, ae_state *_state); void swapr(double* v0, double* v1, ae_state *_state); double maxreal3(double v0, double v1, double v2, ae_state *_state); void inc(ae_int_t* v, ae_state *_state); void dec(ae_int_t* v, ae_state *_state); void countdown(ae_int_t* v, ae_state *_state); double boundval(double x, double b1, double b2, ae_state *_state); void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state); void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state); ae_complex unserializecomplex(ae_serializer* s, ae_state *_state); void allocrealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_int_t n, ae_state *_state); void serializerealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_int_t n, ae_state *_state); void unserializerealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_state *_state); void allocintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_int_t n, ae_state *_state); void serializeintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_int_t n, ae_state *_state); void unserializeintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_state *_state); void allocrealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_int_t n0, ae_int_t n1, ae_state *_state); void serializerealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_int_t n0, ae_int_t n1, ae_state *_state); void unserializerealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_state *_state); void copyintegerarray(/* Integer */ ae_vector* src, /* Integer */ ae_vector* dst, ae_state *_state); void copyrealarray(/* Real */ ae_vector* src, /* Real */ ae_vector* dst, ae_state *_state); void copyrealmatrix(/* Real */ ae_matrix* src, /* Real */ ae_matrix* dst, ae_state *_state); ae_int_t recsearch(/* Integer */ ae_vector* a, ae_int_t nrec, ae_int_t nheader, ae_int_t i0, ae_int_t i1, /* Integer */ ae_vector* b, ae_state *_state); void splitlengtheven(ae_int_t tasksize, ae_int_t* task0, ae_int_t* task1, ae_state *_state); void splitlength(ae_int_t tasksize, ae_int_t chunksize, ae_int_t* task0, ae_int_t* task1, ae_state *_state); ae_int_t chunkscount(ae_int_t tasksize, ae_int_t chunksize, ae_state *_state); void _apbuffers_init(void* _p, ae_state *_state); void _apbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _apbuffers_clear(void* _p); void _apbuffers_destroy(void* _p); void _sboolean_init(void* _p, ae_state *_state); void _sboolean_init_copy(void* _dst, void* _src, ae_state *_state); void _sboolean_clear(void* _p); void _sboolean_destroy(void* _p); void _sbooleanarray_init(void* _p, ae_state *_state); void _sbooleanarray_init_copy(void* _dst, void* _src, ae_state *_state); void _sbooleanarray_clear(void* _p); void _sbooleanarray_destroy(void* _p); void _sinteger_init(void* _p, ae_state *_state); void _sinteger_init_copy(void* _dst, void* _src, ae_state *_state); void _sinteger_clear(void* _p); void _sinteger_destroy(void* _p); void _sintegerarray_init(void* _p, ae_state *_state); void _sintegerarray_init_copy(void* _dst, void* _src, ae_state *_state); void _sintegerarray_clear(void* _p); void _sintegerarray_destroy(void* _p); void _sreal_init(void* _p, ae_state *_state); void _sreal_init_copy(void* _dst, void* _src, ae_state *_state); void _sreal_clear(void* _p); void _sreal_destroy(void* _p); void _srealarray_init(void* _p, ae_state *_state); void _srealarray_init_copy(void* _dst, void* _src, ae_state *_state); void _srealarray_clear(void* _p); void _srealarray_destroy(void* _p); void _scomplex_init(void* _p, ae_state *_state); void _scomplex_init_copy(void* _dst, void* _src, ae_state *_state); void _scomplex_clear(void* _p); void _scomplex_destroy(void* _p); void _scomplexarray_init(void* _p, ae_state *_state); void _scomplexarray_init_copy(void* _dst, void* _src, ae_state *_state); void _scomplexarray_clear(void* _p); void _scomplexarray_destroy(void* _p); ae_int_t getrdfserializationcode(ae_state *_state); ae_int_t getkdtreeserializationcode(ae_state *_state); ae_int_t getmlpserializationcode(ae_state *_state); ae_int_t getmlpeserializationcode(ae_state *_state); ae_int_t getrbfserializationcode(ae_state *_state); void tagsort(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, ae_state *_state); void tagsortbuf(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, apbuffers* buf, ae_state *_state); void tagsortfasti(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, /* Real */ ae_vector* bufa, /* Integer */ ae_vector* bufb, ae_int_t n, ae_state *_state); void tagsortfastr(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* bufa, /* Real */ ae_vector* bufb, ae_int_t n, ae_state *_state); void tagsortfast(/* Real */ ae_vector* a, /* Real */ ae_vector* bufa, ae_int_t n, ae_state *_state); void tagsortmiddleir(/* Integer */ ae_vector* a, /* Real */ ae_vector* b, ae_int_t offset, ae_int_t n, ae_state *_state); void tagheappushi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t* n, double va, ae_int_t vb, ae_state *_state); void tagheapreplacetopi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t n, double va, ae_int_t vb, ae_state *_state); void tagheappopi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t* n, ae_state *_state); ae_int_t lowerbound(/* Real */ ae_vector* a, ae_int_t n, double t, ae_state *_state); ae_int_t upperbound(/* Real */ ae_vector* a, ae_int_t n, double t, ae_state *_state); void rankx(/* Real */ ae_vector* x, ae_int_t n, ae_bool iscentered, apbuffers* buf, ae_state *_state); ae_bool cmatrixrank1f(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_vector* u, ae_int_t iu, /* Complex */ ae_vector* v, ae_int_t iv, ae_state *_state); ae_bool rmatrixrank1f(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_vector* u, ae_int_t iu, /* Real */ ae_vector* v, ae_int_t iv, ae_state *_state); ae_bool cmatrixmvf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Complex */ ae_vector* x, ae_int_t ix, /* Complex */ ae_vector* y, ae_int_t iy, ae_state *_state); ae_bool rmatrixmvf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Real */ ae_vector* x, ae_int_t ix, /* Real */ ae_vector* y, ae_int_t iy, ae_state *_state); ae_bool cmatrixrighttrsmf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool cmatrixlefttrsmf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool rmatrixrighttrsmf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool rmatrixlefttrsmf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool cmatrixherkf(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); ae_bool rmatrixsyrkf(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); ae_bool rmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); ae_bool cmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void cmatrixgemmk(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemmk(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemmk44v00(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemmk44v01(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemmk44v10(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemmk44v11(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); ae_bool rmatrixsyrkmkl(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); ae_bool cmatrixherkmkl(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); ae_bool rmatrixgemmmkl(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); ae_bool cmatrixgemmmkl(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); ae_bool cmatrixlefttrsmmkl(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool cmatrixrighttrsmmkl(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool rmatrixlefttrsmmkl(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool rmatrixrighttrsmmkl(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); ae_bool spdmatrixcholeskymkl(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool* cholresult, ae_state *_state); ae_bool rmatrixplumkl(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); ae_bool rmatrixbdmkl(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* e, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, ae_state *_state); ae_bool rmatrixbdmultiplybymkl(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool byq, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state); ae_bool rmatrixhessenbergmkl(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); ae_bool rmatrixhessenbergunpackqmkl(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state); ae_bool smatrixtdmkl(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state); ae_bool smatrixtdunpackqmkl(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state); ae_bool hmatrixtdmkl(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state); ae_bool hmatrixtdunpackqmkl(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Complex */ ae_matrix* q, ae_state *_state); ae_bool rmatrixbdsvdmkl(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_bool* svdresult, ae_state *_state); ae_bool rmatrixinternalschurdecompositionmkl(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state); ae_bool rmatrixinternaltrevcmkl(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state); ae_bool smatrixtdevdmkl(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_bool* evdresult, ae_state *_state); double vectornorm2(/* Real */ ae_vector* x, ae_int_t i1, ae_int_t i2, ae_state *_state); ae_int_t vectoridxabsmax(/* Real */ ae_vector* x, ae_int_t i1, ae_int_t i2, ae_state *_state); ae_int_t columnidxabsmax(/* Real */ ae_matrix* x, ae_int_t i1, ae_int_t i2, ae_int_t j, ae_state *_state); ae_int_t rowidxabsmax(/* Real */ ae_matrix* x, ae_int_t j1, ae_int_t j2, ae_int_t i, ae_state *_state); double upperhessenberg1norm(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, /* Real */ ae_vector* work, ae_state *_state); void copymatrix(/* Real */ ae_matrix* a, ae_int_t is1, ae_int_t is2, ae_int_t js1, ae_int_t js2, /* Real */ ae_matrix* b, ae_int_t id1, ae_int_t id2, ae_int_t jd1, ae_int_t jd2, ae_state *_state); void inplacetranspose(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, /* Real */ ae_vector* work, ae_state *_state); void copyandtranspose(/* Real */ ae_matrix* a, ae_int_t is1, ae_int_t is2, ae_int_t js1, ae_int_t js2, /* Real */ ae_matrix* b, ae_int_t id1, ae_int_t id2, ae_int_t jd1, ae_int_t jd2, ae_state *_state); void matrixvectormultiply(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, ae_bool trans, /* Real */ ae_vector* x, ae_int_t ix1, ae_int_t ix2, double alpha, /* Real */ ae_vector* y, ae_int_t iy1, ae_int_t iy2, double beta, ae_state *_state); double pythag2(double x, double y, ae_state *_state); void matrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, double alpha, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, double beta, /* Real */ ae_vector* work, ae_state *_state); void hermitianmatrixvectormultiply(/* Complex */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Complex */ ae_vector* x, ae_complex alpha, /* Complex */ ae_vector* y, ae_state *_state); void hermitianrank2update(/* Complex */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Complex */ ae_vector* x, /* Complex */ ae_vector* y, /* Complex */ ae_vector* t, ae_complex alpha, ae_state *_state); void generatereflection(/* Real */ ae_vector* x, ae_int_t n, double* tau, ae_state *_state); void applyreflectionfromtheleft(/* Real */ ae_matrix* c, double tau, /* Real */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* work, ae_state *_state); void applyreflectionfromtheright(/* Real */ ae_matrix* c, double tau, /* Real */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* work, ae_state *_state); void complexgeneratereflection(/* Complex */ ae_vector* x, ae_int_t n, ae_complex* tau, ae_state *_state); void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, ae_complex tau, /* Complex */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Complex */ ae_vector* work, ae_state *_state); void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, ae_complex tau, /* Complex */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Complex */ ae_vector* work, ae_state *_state); void symmetricmatrixvectormultiply(/* Real */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* x, double alpha, /* Real */ ae_vector* y, ae_state *_state); void symmetricrank2update(/* Real */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* t, double alpha, ae_state *_state); void applyrotationsfromtheleft(ae_bool isforward, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* c, /* Real */ ae_vector* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* work, ae_state *_state); void applyrotationsfromtheright(ae_bool isforward, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* c, /* Real */ ae_vector* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* work, ae_state *_state); void generaterotation(double f, double g, double* cs, double* sn, double* r, ae_state *_state); void rmatrixinternalschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state); ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, /* Real */ ae_matrix* s, ae_state *_state); void internalschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state); void rmatrixtrsafesolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, double* s, ae_bool isupper, ae_bool istrans, ae_bool isunit, ae_state *_state); void safesolvetriangular(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, double* s, ae_bool isupper, ae_bool istrans, ae_bool isunit, ae_bool normin, /* Real */ ae_vector* cnorm, ae_state *_state); ae_bool rmatrixscaledtrsafesolve(/* Real */ ae_matrix* a, double sa, ae_int_t n, /* Real */ ae_vector* x, ae_bool isupper, ae_int_t trans, ae_bool isunit, double maxgrowth, ae_state *_state); ae_bool cmatrixscaledtrsafesolve(/* Complex */ ae_matrix* a, double sa, ae_int_t n, /* Complex */ ae_vector* x, ae_bool isupper, ae_int_t trans, ae_bool isunit, double maxgrowth, ae_state *_state); void hpcpreparechunkedgradient(/* Real */ ae_vector* weights, ae_int_t wcount, ae_int_t ntotal, ae_int_t nin, ae_int_t nout, mlpbuffers* buf, ae_state *_state); void hpcfinalizechunkedgradient(mlpbuffers* buf, /* Real */ ae_vector* grad, ae_state *_state); ae_bool hpcchunkedgradient(/* Real */ ae_vector* weights, /* Integer */ ae_vector* structinfo, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, double* e, ae_bool naturalerrorfunc, ae_state *_state); ae_bool hpcchunkedprocess(/* Real */ ae_vector* weights, /* Integer */ ae_vector* structinfo, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, ae_state *_state); void _mlpbuffers_init(void* _p, ae_state *_state); void _mlpbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpbuffers_clear(void* _p); void _mlpbuffers_destroy(void* _p); void xdot(/* Real */ ae_vector* a, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* temp, double* r, double* rerr, ae_state *_state); void xcdot(/* Complex */ ae_vector* a, /* Complex */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* temp, ae_complex* r, double* rerr, ae_state *_state); void linminnormalized(/* Real */ ae_vector* d, double* stp, ae_int_t n, ae_state *_state); void mcsrch(ae_int_t n, /* Real */ ae_vector* x, double* f, /* Real */ ae_vector* g, /* Real */ ae_vector* s, double* stp, double stpmax, double gtol, ae_int_t* info, ae_int_t* nfev, /* Real */ ae_vector* wa, linminstate* state, ae_int_t* stage, ae_state *_state); void armijocreate(ae_int_t n, /* Real */ ae_vector* x, double f, /* Real */ ae_vector* s, double stp, double stpmax, ae_int_t fmax, armijostate* state, ae_state *_state); ae_bool armijoiteration(armijostate* state, ae_state *_state); void armijoresults(armijostate* state, ae_int_t* info, double* stp, double* f, ae_state *_state); void _linminstate_init(void* _p, ae_state *_state); void _linminstate_init_copy(void* _dst, void* _src, ae_state *_state); void _linminstate_clear(void* _p); void _linminstate_destroy(void* _p); void _armijostate_init(void* _p, ae_state *_state); void _armijostate_init_copy(void* _dst, void* _src, ae_state *_state); void _armijostate_clear(void* _p); void _armijostate_destroy(void* _p); void findprimitiverootandinverse(ae_int_t n, ae_int_t* proot, ae_int_t* invproot, ae_state *_state); void ftcomplexfftplan(ae_int_t n, ae_int_t k, fasttransformplan* plan, ae_state *_state); void ftapplyplan(fasttransformplan* plan, /* Real */ ae_vector* a, ae_int_t offsa, ae_int_t repcnt, ae_state *_state); void ftbasefactorize(ae_int_t n, ae_int_t tasktype, ae_int_t* n1, ae_int_t* n2, ae_state *_state); ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state); ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state); ae_int_t ftbasefindsmootheven(ae_int_t n, ae_state *_state); double ftbasegetflopestimate(ae_int_t n, ae_state *_state); void _fasttransformplan_init(void* _p, ae_state *_state); void _fasttransformplan_init_copy(void* _dst, void* _src, ae_state *_state); void _fasttransformplan_clear(void* _p); void _fasttransformplan_destroy(void* _p); double nulog1p(double x, ae_state *_state); double nuexpm1(double x, ae_state *_state); double nucosm1(double x, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/specialfunctions.h000755 001750 000144 00000174747 13015033052 024254 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _specialfunctions_pkg_h #define _specialfunctions_pkg_h #include "ap.h" #include "alglibinternal.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Gamma function Input parameters: X - argument Domain: 0 < X < 171.6 -170 < X < 0, X is not an integer. Relative error: arithmetic domain # trials peak rms IEEE -170,-33 20000 2.3e-15 3.3e-16 IEEE -33, 33 20000 9.4e-16 2.2e-16 IEEE 33, 171.6 20000 2.3e-15 3.2e-16 Cephes Math Library Release 2.8: June, 2000 Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double gammafunction(const double x); /************************************************************************* Natural logarithm of gamma function Input parameters: X - argument Result: logarithm of the absolute value of the Gamma(X). Output parameters: SgnGam - sign(Gamma(X)) Domain: 0 < X < 2.55e305 -2.55e305 < X < 0, X is not an integer. ACCURACY: arithmetic domain # trials peak rms IEEE 0, 3 28000 5.4e-16 1.1e-16 IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 The error criterion was relative when the function magnitude was greater than one but absolute when it was less than one. The following test used the relative error criterion, though at certain points the relative error could be much higher than indicated. IEEE -200, -4 10000 4.8e-16 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double lngamma(const double x, double &sgngam); /************************************************************************* Error function The integral is x - 2 | | 2 erf(x) = -------- | exp( - t ) dt. sqrt(pi) | | - 0 For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise erf(x) = 1 - erfc(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 3.7e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunction(const double x); /************************************************************************* Complementary error function 1 - erf(x) = inf. - 2 | | 2 erfc(x) = -------- | exp( - t ) dt sqrt(pi) | | - x For small x, erfc(x) = 1 - erf(x); otherwise rational approximations are computed. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,26.6417 30000 5.7e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunctionc(const double x); /************************************************************************* Normal distribution function Returns the area under the Gaussian probability density function, integrated from minus infinity to x: x - 1 | | 2 ndtr(x) = --------- | exp( - t /2 ) dt sqrt(2pi) | | - -inf. = ( 1 + erf(z) ) / 2 = erfc(z) / 2 where z = x/sqrt(2). Computation is via the functions erf and erfc. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE -13,0 30000 3.4e-14 6.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double normaldistribution(const double x); /************************************************************************* Inverse of the error function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double inverf(const double e); /************************************************************************* Inverse of Normal distribution function Returns the argument, x, for which the area under the Gaussian probability density function (integrated from minus infinity to x) is equal to y. For small arguments 0 < y < exp(-2), the program computes z = sqrt( -2.0 * log(y) ); then the approximation is x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). There are two rational functions P/Q, one for 0 < y < exp(-32) and the other for y up to exp(-2). For larger arguments, w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0.125, 1 20000 7.2e-16 1.3e-16 IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double invnormaldistribution(const double y0); /************************************************************************* Incomplete gamma integral The function is defined by x - 1 | | -t a-1 igam(a,x) = ----- | e t dt. - | | | (a) - 0 In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 200000 3.6e-14 2.9e-15 IEEE 0,100 300000 9.9e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegamma(const double a, const double x); /************************************************************************* Complemented incomplete gamma integral The function is defined by igamc(a,x) = 1 - igam(a,x) inf. - 1 | | -t a-1 = ----- | e t dt. - | | | (a) - x In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Tested at random a, x. a x Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegammac(const double a, const double x); /************************************************************************* Inverse of complemented imcomplete gamma integral Given p, the function finds x such that igamc( a, x ) = p. Starting with the approximate value 3 x = a t where t = 1 - d - ndtri(p) sqrt(d) and d = 1/9a, the routine performs up to 10 Newton iterations to find the root of igamc(a,x) - p = 0. ACCURACY: Tested at random a, p in the intervals indicated. a p Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletegammac(const double a, const double y0); /************************************************************************* Airy function Solution of the differential equation y"(x) = xy. The function returns the two independent solutions Ai, Bi and their first derivatives Ai'(x), Bi'(x). Evaluation is by power series summation for small x, by rational minimax approximations for large x. ACCURACY: Error criterion is absolute when function <= 1, relative when function > 1, except * denotes relative error criterion. For large negative x, the absolute error increases as x^1.5. For large positive x, the relative error increases as x^1.5. Arithmetic domain function # trials peak rms IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void airy(const double x, double &ai, double &aip, double &bi, double &bip); /************************************************************************* Bessel function of order zero Returns Bessel function of order zero of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval the following rational approximation is used: 2 2 (w - r ) (w - r ) P (w) / Q (w) 1 2 3 8 2 where w = x and the two r's are zeros of the function. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 60000 4.2e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj0(const double x); /************************************************************************* Bessel function of order one Returns Bessel function of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 24 term Chebyshev expansion is used. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 2.6e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj1(const double x); /************************************************************************* Bessel function of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The ratio of jn(x) to j0(x) is computed by backward recurrence. First the ratio jn/jn-1 is found by a continued fraction expansion. Then the recurrence relating successive orders is applied until j0 or j1 is reached. If n = 0 or 1 the routine for j0 or j1 is called directly. ACCURACY: Absolute error: arithmetic range # trials peak rms IEEE 0, 30 5000 4.4e-16 7.9e-17 Not suitable for large n or x. Use jv() (fractional order) instead. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseljn(const ae_int_t n, const double x); /************************************************************************* Bessel function of the second kind, order zero Returns Bessel function of the second kind, of order zero, of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval a rational approximation R(x) is employed to compute y0(x) = R(x) + 2 * log(x) * j0(x) / PI. Thus a call to j0() is required. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error, when y0(x) < 1; else relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.3e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely0(const double x); /************************************************************************* Bessel function of second kind of order one Returns Bessel function of the second kind of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 25 term Chebyshev expansion is used, and a call to j1() is required. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.0e-15 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely1(const double x); /************************************************************************* Bessel function of second kind of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The function is evaluated by forward recurrence on n, starting with values computed by the routines y0() and y1(). If n = 0 or 1 the routine for y0 or y1 is called directly. ACCURACY: Absolute error, except relative when y > 1: arithmetic domain # trials peak rms IEEE 0, 30 30000 3.4e-15 4.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselyn(const ae_int_t n, const double x); /************************************************************************* Modified Bessel function of order zero Returns modified Bessel function of order zero of the argument. The function is defined as i0(x) = j0( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 5.8e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli0(const double x); /************************************************************************* Modified Bessel function of order one Returns modified Bessel function of order one of the argument. The function is defined as i1(x) = -i j1( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.9e-15 2.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli1(const double x); /************************************************************************* Modified Bessel function, second kind, order zero Returns modified Bessel function of the second kind of order zero of the argument. The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Tested at 2000 random points between 0 and 8. Peak absolute error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk0(const double x); /************************************************************************* Modified Bessel function, second kind, order one Computes the modified Bessel function of the second kind of order one of the argument. The range is partitioned into the two intervals [0,2] and (2, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk1(const double x); /************************************************************************* Modified Bessel function, second kind, integer order Returns modified Bessel function of the second kind of order n of the argument. The range is partitioned into the two intervals [0,9.55] and (9.55, infinity). An ascending power series is used in the low range, and an asymptotic expansion in the high range. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 90000 1.8e-8 3.0e-10 Error is high only near the crossover point x = 9.55 between the two expansions used. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier *************************************************************************/ double besselkn(const ae_int_t nn, const double x); /************************************************************************* Beta function - - | (a) | (b) beta( a, b ) = -----------. - | (a+b) For large arguments the logarithm of the function is evaluated using lgam(), then exponentiated. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 8.1e-14 1.1e-14 Cephes Math Library Release 2.0: April, 1987 Copyright 1984, 1987 by Stephen L. Moshier *************************************************************************/ double beta(const double a, const double b); /************************************************************************* Incomplete beta integral Returns incomplete beta integral of the arguments, evaluated from zero to x. The function is defined as x - - | (a+b) | | a-1 b-1 ----------- | t (1-t) dt. - - | | | (a) | (b) - 0 The domain of definition is 0 <= x <= 1. In this implementation a and b are restricted to positive values. The integral from x to 1 may be obtained by the symmetry relation 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). The integral is evaluated by a continued fraction expansion or, when b*x is small, by a power series. ACCURACY: Tested at uniformly distributed random points (a,b,x) with a and b in "domain" and x between 0 and 1. Relative error arithmetic domain # trials peak rms IEEE 0,5 10000 6.9e-15 4.5e-16 IEEE 0,85 250000 2.2e-13 1.7e-14 IEEE 0,1000 30000 5.3e-12 6.3e-13 IEEE 0,10000 250000 9.3e-11 7.1e-12 IEEE 0,100000 10000 8.7e-10 4.8e-11 Outputs smaller than the IEEE gradual underflow threshold were excluded from these statistics. Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double incompletebeta(const double a, const double b, const double x); /************************************************************************* Inverse of imcomplete beta integral Given y, the function finds x such that incbet( a, b, x ) = y . The routine performs interval halving or Newton iterations to find the root of incbet(a,b,x) - y = 0. ACCURACY: Relative error: x a,b arithmetic domain domain # trials peak rms IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 With a and b constrained to half-integer or integer values: IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 With a = .5, b constrained to half-integer or integer values: IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1996, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletebeta(const double a, const double b, const double y); /************************************************************************* Binomial distribution Returns the sum of the terms 0 through k of the Binomial probability density: k -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=0 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p), with p between 0 and 1. a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 4.3e-15 2.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p); /************************************************************************* Complemented binomial distribution Returns the sum of the terms k+1 through n of the Binomial probability density: n -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=k+1 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 6.7e-15 8.2e-16 For p between 0 and .001: IEEE 0,100 100000 1.5e-13 2.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p); /************************************************************************* Inverse binomial distribution Finds the event probability p such that the sum of the terms 0 through k of the Binomial probability density is equal to the given cumulative probability y. This is accomplished using the inverse beta integral function and the relation 1 - p = incbi( n-k, k+1, y ). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 2.3e-14 6.4e-16 IEEE 0,10000 100000 6.6e-12 1.2e-13 For p between 10^-6 and 0.001: IEEE 0,100 100000 2.0e-12 1.3e-14 IEEE 0,10000 100000 1.5e-12 3.2e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y); /************************************************************************* Calculation of the value of the Chebyshev polynomials of the first and second kinds. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument, -1 <= x <= 1 Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x); /************************************************************************* Summation of Chebyshev polynomials using Clenshaws recurrence formula. This routine calculates c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) or c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) depending on the R. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x); /************************************************************************* Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void chebyshevcoefficients(const ae_int_t n, real_1d_array &c); /************************************************************************* Conversion of a series of Chebyshev polynomials to a power series. Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as B[0] + B[1]*X + ... + B[N]*X^N. Input parameters: A - Chebyshev series coefficients N - degree, N>=0 Output parameters B - power series coefficients *************************************************************************/ void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b); /************************************************************************* Chi-square distribution Returns the area under the left hand tail (from 0 to x) of the Chi square probability density function with v degrees of freedom. x - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - 0 where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquaredistribution(const double v, const double x); /************************************************************************* Complemented Chi-square distribution Returns the area under the right hand tail (from x to infinity) of the Chi square probability density function with v degrees of freedom: inf. - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - x where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquarecdistribution(const double v, const double x); /************************************************************************* Inverse of complemented Chi-square distribution Finds the Chi-square argument x such that the integral from x to infinity of the Chi-square density is equal to the given cumulative probability y. This is accomplished using the inverse gamma integral function and the relation x/2 = igami( df/2, y ); ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double invchisquaredistribution(const double v, const double y); /************************************************************************* Dawson's Integral Approximates the integral x - 2 | | 2 dawsn(x) = exp( -x ) | exp( t ) dt | | - 0 Three different rational approximations are employed, for the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,10 10000 6.9e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double dawsonintegral(const double x); /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 using the approximation P(x) - log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralk(const double m); /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 where m = 1 - m1, using the approximation P(x) - log x Q(x). The argument m1 is used rather than m so that the logarithmic singularity at m = 1 will be shifted to the origin; this preserves maximum accuracy. K(0) = pi/2. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralkhighprecision(const double m1); /************************************************************************* Incomplete elliptic integral of the first kind F(phi|m) Approximates the integral phi - | | | dt F(phi_\m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random points with m in [0, 1] and phi as indicated. Relative error: arithmetic domain # trials peak rms IEEE -10,10 200000 7.4e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegralk(const double phi, const double m); /************************************************************************* Complete elliptic integral of the second kind Approximates the integral pi/2 - | | 2 E(m) = | sqrt( 1 - m sin t ) dt | | - 0 using the approximation P(x) - x log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 1 10000 2.1e-16 7.3e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegrale(const double m); /************************************************************************* Incomplete elliptic integral of the second kind Approximates the integral phi - | | | 2 E(phi_\m) = | sqrt( 1 - m sin t ) dt | | | - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random arguments with phi in [-10, 10] and m in [0, 1]. Relative error: arithmetic domain # trials peak rms IEEE -10,10 150000 3.3e-15 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegrale(const double phi, const double m); /************************************************************************* Exponential integral Ei(x) x - t | | e Ei(x) = -|- --- dt . | | t - -inf Not defined for x <= 0. See also expn.c. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,100 50000 8.6e-16 1.3e-16 Cephes Math Library Release 2.8: May, 1999 Copyright 1999 by Stephen L. Moshier *************************************************************************/ double exponentialintegralei(const double x); /************************************************************************* Exponential integral En(x) Evaluates the exponential integral inf. - | | -xt | e E (x) = | ---- dt. n | n | | t - 1 Both n and x must be nonnegative. The routine employs either a power series, a continued fraction, or an asymptotic formula depending on the relative values of n and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 10000 1.7e-15 3.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 2000 by Stephen L. Moshier *************************************************************************/ double exponentialintegralen(const double x, const ae_int_t n); /************************************************************************* F distribution Returns the area from zero to x under the F density function (also known as Snedcor's density or the variance ratio density). This is the density of x = (u1/df1)/(u2/df2), where u1 and u2 are random variables having Chi square distributions with df1 and df2 degrees of freedom, respectively. The incomplete beta integral is used, according to the formula P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). The arguments a and b are greater than zero, and x is nonnegative. ACCURACY: Tested at random points (a,b,x). x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fdistribution(const ae_int_t a, const ae_int_t b, const double x); /************************************************************************* Complemented F distribution Returns the area from x to infinity under the F density function (also known as Snedcor's density or the variance ratio density). inf. - 1 | | a-1 b-1 1-P(x) = ------ | t (1-t) dt B(a,b) | | - x The incomplete beta integral is used, according to the formula P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). ACCURACY: Tested at random points (a,b,x) in the indicated intervals. x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fcdistribution(const ae_int_t a, const ae_int_t b, const double x); /************************************************************************* Inverse of complemented F distribution Finds the F density argument x such that the integral from x to infinity of the F density is equal to the given probability p. This is accomplished using the inverse beta integral function and the relations z = incbi( df2/2, df1/2, p ) x = df2 (1-z) / (df1 z). Note: the following relations hold for the inverse of the uncomplemented F distribution: z = incbi( df1/2, df2/2, p ) x = df2 z / (df1 (1-z)). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between .001 and 1: IEEE 1,100 100000 8.3e-15 4.7e-16 IEEE 1,10000 100000 2.1e-11 1.4e-13 For p between 10^-6 and 10^-3: IEEE 1,100 50000 1.3e-12 8.4e-15 IEEE 1,10000 50000 3.0e-12 4.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invfdistribution(const ae_int_t a, const ae_int_t b, const double y); /************************************************************************* Fresnel integral Evaluates the Fresnel integrals x - | | C(x) = | cos(pi/2 t**2) dt, | | - 0 x - | | S(x) = | sin(pi/2 t**2) dt. | | - 0 The integrals are evaluated by a power series for x < 1. For x >= 1 auxiliary functions f(x) and g(x) are employed such that C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) ACCURACY: Relative error. Arithmetic function domain # trials peak rms IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void fresnelintegral(const double x, double &c, double &s); /************************************************************************* Calculation of the value of the Hermite polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial Hn at x *************************************************************************/ double hermitecalculate(const ae_int_t n, const double x); /************************************************************************* Summation of Hermite polynomials using Clenshaws recurrence formula. This routine calculates c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial at x *************************************************************************/ double hermitesum(const real_1d_array &c, const ae_int_t n, const double x); /************************************************************************* Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void hermitecoefficients(const ae_int_t n, real_1d_array &c); /************************************************************************* Jacobian Elliptic Functions Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), and dn(u|m) of parameter m between 0 and 1, and real argument u. These functions are periodic, with quarter-period on the real axis equal to the complete elliptic integral ellpk(1.0-m). Relation to incomplete elliptic integral: If u = ellik(phi,m), then sn(u|m) = sin(phi), and cn(u|m) = cos(phi). Phi is called the amplitude of u. Computation is by means of the arithmetic-geometric mean algorithm, except when m is within 1e-9 of 0 or 1. In the latter case with m close to 1, the approximation applies only for phi < pi/2. ACCURACY: Tested at random points with u between 0 and 10, m between 0 and 1. Absolute error (* = relative error): arithmetic function # trials peak rms IEEE phi 10000 9.2e-16* 1.4e-16* IEEE sn 50000 4.1e-15 4.6e-16 IEEE cn 40000 3.6e-15 4.4e-16 IEEE dn 10000 1.3e-12 1.8e-14 Peak error observed in consistency check using addition theorem for sn(u+v) was 4e-16 (absolute). Also tested by the above relation to the incomplete elliptic integral. Accuracy deteriorates when u is large. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph); /************************************************************************* Calculation of the value of the Laguerre polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial Ln at x *************************************************************************/ double laguerrecalculate(const ae_int_t n, const double x); /************************************************************************* Summation of Laguerre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial at x *************************************************************************/ double laguerresum(const real_1d_array &c, const ae_int_t n, const double x); /************************************************************************* Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void laguerrecoefficients(const ae_int_t n, real_1d_array &c); /************************************************************************* Calculation of the value of the Legendre polynomial Pn. Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial Pn at x *************************************************************************/ double legendrecalculate(const ae_int_t n, const double x); /************************************************************************* Summation of Legendre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial at x *************************************************************************/ double legendresum(const real_1d_array &c, const ae_int_t n, const double x); /************************************************************************* Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void legendrecoefficients(const ae_int_t n, real_1d_array &c); /************************************************************************* Poisson distribution Returns the sum of the first k+1 terms of the Poisson distribution: k j -- -m m > e -- -- j! j=0 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the relation y = pdtr( k, m ) = igamc( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissondistribution(const ae_int_t k, const double m); /************************************************************************* Complemented Poisson distribution Returns the sum of the terms k+1 to infinity of the Poisson distribution: inf. j -- -m m > e -- -- j! j=k+1 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the formula y = pdtrc( k, m ) = igam( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissoncdistribution(const ae_int_t k, const double m); /************************************************************************* Inverse Poisson distribution Finds the Poisson variable x such that the integral from 0 to x of the Poisson density is equal to the given probability y. This is accomplished using the inverse gamma integral function and the relation m = igami( k+1, y ). ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invpoissondistribution(const ae_int_t k, const double y); /************************************************************************* Psi (digamma) function d - psi(x) = -- ln | (x) dx is the logarithmic derivative of the gamma function. For integer x, n-1 - psi(n) = -EUL + > 1/k. - k=1 This formula is used for 0 < n <= 10. If x is negative, it is transformed to a positive argument by the reflection formula psi(1-x) = psi(x) + pi cot(pi x). For general positive x, the argument is made greater than 10 using the recurrence psi(x+1) = psi(x) + 1/x. Then the following asymptotic expansion is applied: inf. B - 2k psi(x) = log(x) - 1/2x - > ------- - 2k k=1 2k x where the B2k are Bernoulli numbers. ACCURACY: Relative error (except absolute when |psi| < 1): arithmetic domain # trials peak rms IEEE 0,30 30000 1.3e-15 1.4e-16 IEEE -30,0 40000 1.5e-15 2.2e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double psi(const double x); /************************************************************************* Student's t distribution Computes the integral from minus infinity to t of the Student t distribution with integer k > 0 degrees of freedom: t - | | - | 2 -(k+1)/2 | ( (k+1)/2 ) | ( x ) ---------------------- | ( 1 + --- ) dx - | ( k ) sqrt( k pi ) | ( k/2 ) | | | - -inf. Relation to incomplete beta integral: 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) where z = k/(k + t**2). For t < -2, this is the method of computation. For higher t, a direct method is derived from integration by parts. Since the function is symmetric about t=0, the area under the right tail of the density is found by calling the function with -t instead of t. ACCURACY: Tested at random 1 <= k <= 25. The "domain" refers to t. Relative error: arithmetic domain # trials peak rms IEEE -100,-2 50000 5.9e-15 1.4e-15 IEEE -2,100 500000 2.7e-15 4.9e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double studenttdistribution(const ae_int_t k, const double t); /************************************************************************* Functional inverse of Student's t distribution Given probability p, finds the argument t such that stdtr(k,t) is equal to p. ACCURACY: Tested at random 1 <= k <= 100. The "domain" refers to p: Relative error: arithmetic domain # trials peak rms IEEE .001,.999 25000 5.7e-15 8.0e-16 IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invstudenttdistribution(const ae_int_t k, const double p); /************************************************************************* Sine and cosine integrals Evaluates the integrals x - | cos t - 1 Ci(x) = eul + ln x + | --------- dt, | t - 0 x - | sin t Si(x) = | ----- dt | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are approximated by rational functions. For x > 8 auxiliary functions f(x) and g(x) are employed such that Ci(x) = f(x) sin(x) - g(x) cos(x) Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) ACCURACY: Test interval = [0,50]. Absolute error, except relative when > 1: arithmetic function # trials peak rms IEEE Si 30000 4.4e-16 7.3e-17 IEEE Ci 30000 6.9e-16 5.1e-17 Cephes Math Library Release 2.1: January, 1989 Copyright 1984, 1987, 1989 by Stephen L. Moshier *************************************************************************/ void sinecosineintegrals(const double x, double &si, double &ci); /************************************************************************* Hyperbolic sine and cosine integrals Approximates the integrals x - | | cosh t - 1 Chi(x) = eul + ln x + | ----------- dt, | | t - 0 x - | | sinh t Shi(x) = | ------ dt | | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are evaluated by power series for x < 8 and by Chebyshev expansions for x between 8 and 88. For large x, both functions approach exp(x)/2x. Arguments greater than 88 in magnitude return MAXNUM. ACCURACY: Test interval 0 to 88. Relative error: arithmetic function # trials peak rms IEEE Shi 30000 6.9e-16 1.6e-16 Absolute error, except relative when |Chi| > 1: IEEE Chi 30000 8.4e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { double gammafunction(double x, ae_state *_state); double lngamma(double x, double* sgngam, ae_state *_state); double errorfunction(double x, ae_state *_state); double errorfunctionc(double x, ae_state *_state); double normaldistribution(double x, ae_state *_state); double inverf(double e, ae_state *_state); double invnormaldistribution(double y0, ae_state *_state); double incompletegamma(double a, double x, ae_state *_state); double incompletegammac(double a, double x, ae_state *_state); double invincompletegammac(double a, double y0, ae_state *_state); void airy(double x, double* ai, double* aip, double* bi, double* bip, ae_state *_state); double besselj0(double x, ae_state *_state); double besselj1(double x, ae_state *_state); double besseljn(ae_int_t n, double x, ae_state *_state); double bessely0(double x, ae_state *_state); double bessely1(double x, ae_state *_state); double besselyn(ae_int_t n, double x, ae_state *_state); double besseli0(double x, ae_state *_state); double besseli1(double x, ae_state *_state); double besselk0(double x, ae_state *_state); double besselk1(double x, ae_state *_state); double besselkn(ae_int_t nn, double x, ae_state *_state); double beta(double a, double b, ae_state *_state); double incompletebeta(double a, double b, double x, ae_state *_state); double invincompletebeta(double a, double b, double y, ae_state *_state); double binomialdistribution(ae_int_t k, ae_int_t n, double p, ae_state *_state); double binomialcdistribution(ae_int_t k, ae_int_t n, double p, ae_state *_state); double invbinomialdistribution(ae_int_t k, ae_int_t n, double y, ae_state *_state); double chebyshevcalculate(ae_int_t r, ae_int_t n, double x, ae_state *_state); double chebyshevsum(/* Real */ ae_vector* c, ae_int_t r, ae_int_t n, double x, ae_state *_state); void chebyshevcoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); void fromchebyshev(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* b, ae_state *_state); double chisquaredistribution(double v, double x, ae_state *_state); double chisquarecdistribution(double v, double x, ae_state *_state); double invchisquaredistribution(double v, double y, ae_state *_state); double dawsonintegral(double x, ae_state *_state); double ellipticintegralk(double m, ae_state *_state); double ellipticintegralkhighprecision(double m1, ae_state *_state); double incompleteellipticintegralk(double phi, double m, ae_state *_state); double ellipticintegrale(double m, ae_state *_state); double incompleteellipticintegrale(double phi, double m, ae_state *_state); double exponentialintegralei(double x, ae_state *_state); double exponentialintegralen(double x, ae_int_t n, ae_state *_state); double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); double invfdistribution(ae_int_t a, ae_int_t b, double y, ae_state *_state); void fresnelintegral(double x, double* c, double* s, ae_state *_state); double hermitecalculate(ae_int_t n, double x, ae_state *_state); double hermitesum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state); void hermitecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); void jacobianellipticfunctions(double u, double m, double* sn, double* cn, double* dn, double* ph, ae_state *_state); double laguerrecalculate(ae_int_t n, double x, ae_state *_state); double laguerresum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state); void laguerrecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); double legendrecalculate(ae_int_t n, double x, ae_state *_state); double legendresum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state); void legendrecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); double poissondistribution(ae_int_t k, double m, ae_state *_state); double poissoncdistribution(ae_int_t k, double m, ae_state *_state); double invpoissondistribution(ae_int_t k, double y, ae_state *_state); double psi(double x, ae_state *_state); double studenttdistribution(ae_int_t k, double t, ae_state *_state); double invstudenttdistribution(ae_int_t k, double p, ae_state *_state); void sinecosineintegrals(double x, double* si, double* ci, ae_state *_state); void hyperbolicsinecosineintegrals(double x, double* shi, double* chi, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/linalg.cpp000755 001750 000144 00005742714 13015033052 022504 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "linalg.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Cache-oblivous complex "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixtranspose(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cache-oblivous real "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixtranspose(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This code enforces symmetricy of the matrix by copying Upper part to lower one (or vice versa). INPUT PARAMETERS: A - matrix N - number of rows/columns IsUpper - whether we want to copy upper triangle to lower one (True) or vice versa (False). *************************************************************************/ void rmatrixenforcesymmetricity(const real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixenforcesymmetricity(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixcopy(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixcopy(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_1d_array &u, const ae_int_t iu, complex_1d_array &v, const ae_int_t iv) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrank1(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(u.c_ptr()), iu, const_cast(v.c_ptr()), iv, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_1d_array &u, const ae_int_t iu, real_1d_array &v, const ae_int_t iv) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrank1(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(u.c_ptr()), iu, const_cast(v.c_ptr()), iv, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) M>=0 N - number of columns of op(A) N>=0 A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T * OpA=2 => op(A) = A^H X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixmv(m, n, const_cast(a.c_ptr()), ia, ja, opa, const_cast(x.c_ptr()), ix, const_cast(y.c_ptr()), iy, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) N - number of columns of op(A) A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixmv(m, n, const_cast(a.c_ptr()), ia, ja, opa, const_cast(x.c_ptr()), ix, const_cast(y.c_ptr()), iy, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C where: * C is NxN Hermitian matrix given by its upper/lower triangle * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^H is calculated * 2 - A^H*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether upper or lower triangle of C is updated; this function updates only one half of C, leaving other half unchanged (not referenced at all). -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixherk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixherk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C where: * C is NxN symmetric matrix given by its upper/lower triangle * A is NxK matrix when A*A^T is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^T is calculated * 2 - A^T*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether C is upper triangular or lower triangular -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition, conjugate transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition Beta - coefficient C - matrix (PREALLOCATED, large enough to store result) IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixgemm(m, n, k, *alpha.c_ptr(), const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, *beta.c_ptr(), const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixgemm(m, n, k, *alpha.c_ptr(), const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, *beta.c_ptr(), const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition Beta - coefficient C - PREALLOCATED output matrix, large enough to store result IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 2009-2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixgemm(m, n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, beta, const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixgemm(m, n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, beta, const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine is an older version of CMatrixHERK(), one with wrong name (it is HErmitian update, not SYmmetric). It is left here for backward compatibility. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* QR decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. The elements of matrix R are located on and above the main diagonal of matrix A. The elements which are located in Tau array and below the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(k-1), where k = min(m,n), and each H(i) is in the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LQ decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices L and Q in compact form (see below) Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..Min(M,N)-1]. Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. The elements of matrix L are located on and below the main diagonal of matrix A. The elements which are located in Tau array and above the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(k-1)*H(k-2)*...*H(1)*H(0), where k = min(m,n), and each H(i) is of the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* QR decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LQ decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and L in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Partial unpacking of matrix Q from the QR decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixQR subroutine. QColumns - required number of columns of matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose indexes range within [0..M-1, 0..QColumns-1]. If QColumns=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixqrunpackr(const_cast(a.c_ptr()), m, n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Partial unpacking of matrix Q from the LQ decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices L and Q in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixLQ subroutine. QRows - required number of rows in matrix Q. N>=QRows>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose indexes range within [0..QRows-1, 0..N-1]. If QRows=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlqunpackl(const_cast(a.c_ptr()), m, n, const_cast(l.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Partial unpacking of matrix Q from QR decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixQR subroutine . QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose index ranges within [0..M-1, 0..QColumns-1]. If QColumns=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixqrunpackr(const_cast(a.c_ptr()), m, n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixLQ subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixLQ subroutine . QRows - required number of rows in matrix Q. N>=QColumns>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose index ranges within [0..QRows-1, 0..N-1]. If QRows=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of CMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlqunpackl(const_cast(a.c_ptr()), m, n, const_cast(l.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Reduction of a rectangular matrix to bidiagonal form The algorithm reduces the rectangular matrix A to bidiagonal form by orthogonal transformations P and Q: A = Q*B*(P^T). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function because ! bidiagonal decompostion is inherently sequential in nature. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - source matrix. array[0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q, B, P in compact form (see below). TauQ - scalar factors which are used to form matrix Q. TauP - scalar factors which are used to form matrix P. The main diagonal and one of the secondary diagonals of matrix A are replaced with bidiagonal matrix B. Other elements contain elementary reflections which form MxM matrix Q and NxN matrix P, respectively. If M>=N, B is the upper bidiagonal MxN matrix and is stored in the corresponding elements of matrix A. Matrix Q is represented as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i). Matrix P is as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). If M n): m=5, n=6 (m < n): ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) ( v1 v2 v3 v4 v5 ) Here vi and ui are vectors which form H(i) and G(i), and d and e - are the diagonal and off-diagonal elements of matrix B. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbd(const_cast(a.c_ptr()), m, n, const_cast(tauq.c_ptr()), const_cast(taup.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix Q which reduces a matrix to bidiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array[0..M-1, 0..QColumns-1] If QColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbdunpackq(const_cast(qp.c_ptr()), m, n, const_cast(tauq.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication by matrix Q which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by Q or Q'. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. Z - multiplied matrix. array[0..ZRows-1,0..ZColumns-1] ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=M, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=M, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by Q or Q'. Output parameters: Z - product of Z and Q. Array[0..ZRows-1,0..ZColumns-1] If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbdmultiplybyq(const_cast(qp.c_ptr()), m, n, const_cast(tauq.c_ptr()), const_cast(z.c_ptr()), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix P which reduces matrix A to bidiagonal form. The subroutine returns transposed matrix P. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of ToBidiagonal subroutine. PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. Output parameters: PT - first PTRows columns of matrix P^T Array[0..PTRows-1, 0..N-1] If PTRows=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbdunpackpt(const_cast(qp.c_ptr()), m, n, const_cast(taup.c_ptr()), ptrows, const_cast(pt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication by matrix P which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by P or P'. Input parameters: QP - matrices Q and P in compact form. Output of RMatrixBD subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of RMatrixBD subroutine. Z - multiplied matrix. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=N, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=N, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by P or P'. Output parameters: Z - product of Z and P. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbdmultiplybyp(const_cast(qp.c_ptr()), m, n, const_cast(taup.c_ptr()), const_cast(z.c_ptr()), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking of the main and secondary diagonals of bidiagonal decomposition of matrix A. Input parameters: B - output of RMatrixBD subroutine. M - number of rows in matrix B. N - number of columns in matrix B. Output parameters: IsUpper - True, if the matrix is upper bidiagonal. otherwise IsUpper is False. D - the main diagonal. Array whose index ranges within [0..Min(M,N)-1]. E - the secondary diagonal (upper or lower, depending on the value of IsUpper). Array index ranges within [0..Min(M,N)-1], the last element is not used. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixbdunpackdiagonals(const_cast(b.c_ptr()), m, n, &isupper, const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, where Q is an orthogonal matrix, H - Hessenberg matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A with elements [0..N-1, 0..N-1] N - size of matrix A. Output parameters: A - matrices Q and P in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..N-2] Matrix H is located on the main diagonal, on the lower secondary diagonal and above the main diagonal of matrix A. The elements which are used to form matrix Q are situated in array Tau and below the lower secondary diagonal of matrix A as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(n-2), where each H(i) is given by H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - is a real vector, so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixhessenberg(const_cast(a.c_ptr()), n, const_cast(tau.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix Q which reduces matrix A to upper Hessenberg form COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Tau - scalar factors which are used to form Q. Output of RMatrixHessenberg subroutine. Output parameters: Q - matrix Q. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixhessenbergunpackq(const_cast(a.c_ptr()), n, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Output parameters: H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixhessenbergunpackh(const_cast(a.c_ptr()), n, const_cast(h.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Reduction of a symmetric matrix which is given by its higher or lower triangular part to a tridiagonal matrix using orthogonal similarity transformation: Q'*A*Q=T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::smatrixtd(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix Q which reduces symmetric matrix to a tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a SMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of SMatrixTD subroutine) Tau - the result of a SMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::smatrixtdunpackq(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Reduction of a Hermitian matrix which is given by its higher or lower triangular part to a real tridiagonal matrix using unitary similarity transformation: Q'*A*Q = T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of real symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of real symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hmatrixtd(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a HMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of HMatrixTD subroutine) Tau - the result of a HMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hmatrixtdunpackq(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Singular value decomposition of a bidiagonal matrix (extended algorithm) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm performs the singular value decomposition of a bidiagonal matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - orthogonal matrices, S - diagonal matrix with non-negative elements on the main diagonal, in descending order. The algorithm finds singular values. In addition, the algorithm can calculate matrices Q and P (more precisely, not the matrices, but their product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, matrices U and VT can be of any type, including identity. Furthermore, the algorithm can calculate Q'*C (this product is calculated more effectively than U*Q, because this calculation operates with rows instead of matrix columns). The feature of the algorithm is its ability to find all singular values including those which are arbitrarily close to 0 with relative accuracy close to machine precision. If the parameter IsFractionalAccuracyRequired is set to True, all singular values will have high relative accuracy close to machine precision. If the parameter is set to False, only the biggest singular value will have relative accuracy close to machine precision. The absolute error of other singular values is equal to the absolute error of the biggest singular value. Input parameters: D - main diagonal of matrix B. Array whose index ranges within [0..N-1]. E - superdiagonal (or subdiagonal) of matrix B. Array whose index ranges within [0..N-2]. N - size of matrix B. IsUpper - True, if the matrix is upper bidiagonal. IsFractionalAccuracyRequired - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. U - matrix to be multiplied by Q. Array whose indexes range within [0..NRU-1, 0..N-1]. The matrix can be bigger, in that case only the submatrix [0..NRU-1, 0..N-1] will be multiplied by Q. NRU - number of rows in matrix U. C - matrix to be multiplied by Q'. Array whose indexes range within [0..N-1, 0..NCC-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCC-1] will be multiplied by Q'. NCC - number of columns in matrix C. VT - matrix to be multiplied by P^T. Array whose indexes range within [0..N-1, 0..NCVT-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCVT-1] will be multiplied by P^T. NCVT - number of columns in matrix VT. Output parameters: D - singular values of matrix B in descending order. U - if NRU>0, contains matrix U*Q. VT - if NCVT>0, contains matrix (P^T)*VT. C - if NCC>0, contains matrix Q'*C. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). NOTE: multiplication U*Q is performed by means of transposition to internal buffer, multiplication and backward transposition. It helps to avoid costly columnwise operations and speed-up algorithm. Additional information: The type of convergence is controlled by the internal parameter TOL. If the parameter is greater than 0, the singular values will have relative accuracy TOL. If TOL<0, the singular values will have absolute accuracy ABS(TOL)*norm(B). By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, where Epsilon is the machine precision. It is not recommended to use TOL less than 10*Epsilon since this will considerably slow down the algorithm and may not lead to error decreasing. History: * 31 March, 2007. changed MAXITR from 6 to 12. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1999. *************************************************************************/ bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::rmatrixbdsvd(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, isupper, isfractionalaccuracyrequired, const_cast(u.c_ptr()), nru, const_cast(c.c_ptr()), ncc, const_cast(vt.c_ptr()), ncvt, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Singular value decomposition of a rectangular matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm calculates the singular value decomposition of a matrix of size MxN: A = U * S * V^T The algorithm finds the singular values and, optionally, matrices U and V^T. The algorithm can find both first min(M,N) columns of matrix U and rows of matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM and NxN respectively). Take into account that the subroutine does not return matrix V but V^T. Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. UNeeded - 0, 1 or 2. See the description of the parameter U. VTNeeded - 0, 1 or 2. See the description of the parameter VT. AdditionalMemory - If the parameter: * equals 0, the algorithm doesnt use additional memory (lower requirements, lower performance). * equals 1, the algorithm uses additional memory of size min(M,N)*min(M,N) of real numbers. It often speeds up the algorithm. * equals 2, the algorithm uses additional memory of size M*min(M,N) of real numbers. It allows to get a maximum performance. The recommended value of the parameter is 2. Output parameters: W - contains singular values in descending order. U - if UNeeded=0, U isn't changed, the left singular vectors are not calculated. if Uneeded=1, U contains left singular vectors (first min(M,N) columns of matrix U). Array whose indexes range within [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U contains matrix U wholly. Array whose indexes range within [0..M-1, 0..M-1]. VT - if VTNeeded=0, VT isnt changed, the right singular vectors are not calculated. if VTNeeded=1, VT contains right singular vectors (first min(M,N) rows of matrix V^T). Array whose indexes range within [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT contains matrix V^T wholly. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::rmatrixsvd(const_cast(a.c_ptr()), m, n, uneeded, vtneeded, additionalmemory, const_cast(w.c_ptr()), const_cast(u.c_ptr()), const_cast(vt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } bool smp_rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::_pexec_rmatrixsvd(const_cast(a.c_ptr()), m, n, uneeded, vtneeded, additionalmemory, const_cast(w.c_ptr()), const_cast(u.c_ptr()), const_cast(vt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Finding the eigenvalues and eigenvectors of a symmetric matrix The algorithm finds eigen pairs of a symmetric matrix by reducing it to tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpper - storage format. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixevd(const_cast(a.c_ptr()), n, zneeded, isupper, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric matrix in a given half open interval (A, B] by using a bisection and inverse iteration Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half open interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval (M>=0). W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixevdr(const_cast(a.c_ptr()), n, zneeded, isupper, b1, b2, &m, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a symmetric matrix with given indexes by using bisection and inverse iteration methods. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixevdi(const_cast(a.c_ptr()), n, zneeded, isupper, i1, i2, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/ bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::hmatrixevd(const_cast(a.c_ptr()), n, zneeded, isupper, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian matrix in a given half-interval (A, B] by using a bisection and inverse iteration Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half-interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval, M>=0 W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::hmatrixevdr(const_cast(a.c_ptr()), n, zneeded, isupper, b1, b2, &m, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a Hermitian matrix with given indexes by using bisection and inverse iteration methods Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::hmatrixevdi(const_cast(a.c_ptr()), n, zneeded, isupper, i1, i2, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by using an QL/QR algorithm with implicit shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix; * 2, the eigenvectors of a tridiagonal matrix replace the square matrix Z; * 3, matrix Z contains the first row of the eigenvectors matrix. Z - if ZNeeded=1, Z contains the square matrix by which the eigenvectors are multiplied. Array whose indexes range within [0..N-1, 0..N-1]. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the product of a given matrix (from the left) and the eigenvectors matrix (from the right); * 2, Z contains the eigenvectors. * 3, Z contains the first row of the eigenvectors matrix. If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. In that case, the eigenvectors are stored in the matrix columns. If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixtdevd(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a given half-interval (A, B] by using bisection and inverse iteration. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix, N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. A, B - half-interval (A, B] to search eigenvalues in. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..M-1]. M - number of eigenvalues found in the given half-interval (M>=0). Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and NxM matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..M-1]. * 2, contains the matrix of the eigenvectors found. Array whose indexes range within [0..N-1, 0..M-1]. Result: True, if successful. In that case, M contains the number of eigenvalues in the given half-interval (could be equal to 0), D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 31.03.2008 by Bochkanov Sergey *************************************************************************/ bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixtdevdr(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, a, b, &m, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine for finding tridiagonal matrix eigenvalues/vectors with given indexes (in ascending order) by using the bisection and inverse iteraion. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix. N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and Nx(I2-I1) matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..I2-I1]. * 2, contains the matrix of the eigenvalues found. Array whose indexes range within [0..N-1, 0..I2-I1]. Result: True, if successful. In that case, D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 25.12.2005 by Bochkanov Sergey *************************************************************************/ bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixtdevdi(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, i1, i2, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Speed-up provided by MKL for this particular problem (EVD) ! is really high, because MKL uses combination of (a) better low-level ! optimizations, and (b) better EVD algorithms. ! ! On one particular SSE-capable machine for N=1024, commercial MKL- ! -capable ALGLIB was: ! * 7-10 times faster than open source "generic C" version ! * 15-18 times faster than "pure C#" version ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm finds eigenvalues and eigenvectors of a general matrix by using the QR algorithm with multiple shifts. The algorithm can find eigenvalues and both left and right eigenvectors. The right eigenvector is a vector x such that A*x = w*x, and the left eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex conjugate transposition of vector y). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. VNeeded - flag controlling whether eigenvectors are needed or not. If VNeeded is equal to: * 0, eigenvectors are not returned; * 1, right eigenvectors are returned; * 2, left eigenvectors are returned; * 3, both left and right eigenvectors are returned. Output parameters: WR - real parts of eigenvalues. Array whose index ranges within [0..N-1]. WR - imaginary parts of eigenvalues. Array whose index ranges within [0..N-1]. VL, VR - arrays of left and right eigenvectors (if they are needed). If WI[i]=0, the respective eigenvalue is a real number, and it corresponds to the column number I of matrices VL/VR. If WI[i]>0, we have a pair of complex conjugate numbers with positive and negative imaginary parts: the first eigenvalue WR[i] + sqrt(-1)*WI[i]; the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; WI[i]>0 WI[i+1] = -WI[i] < 0 In that case, the eigenvector corresponding to the first eigenvalue is located in i and i+1 columns of matrices VL/VR (the column number i contains the real part, and the column number i+1 contains the imaginary part), and the vector corresponding to the second eigenvalue is a complex conjugate to the first vector. Arrays whose indexes range within [0..N-1, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm has not converged. Note 1: Some users may ask the following question: what if WI[N-1]>0? WI[N] must contain an eigenvalue which is complex conjugate to the N-th eigenvalue, but the array has only size N? The answer is as follows: such a situation cannot occur because the algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is strictly less than N-1. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms of linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. See also the InternalTREVC subroutine. The algorithm is based on the LAPACK 3.0 library. *************************************************************************/ bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::rmatrixevd(const_cast(a.c_ptr()), n, vneeded, const_cast(wr.c_ptr()), const_cast(wi.c_ptr()), const_cast(vl.c_ptr()), const_cast(vr.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of a random uniformly distributed (Haar) orthogonal matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrndorthogonal(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of a random Haar distributed orthogonal complex matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrndorthogonal(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN complex matrix with given condition number C and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN symmetric matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::smatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN symmetric positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random SPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN Hermitian matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Generation of random NxN Hermitian positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random HPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrndorthogonalfromtheright(const_cast(a.c_ptr()), m, n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixrndorthogonalfromtheleft(const_cast(a.c_ptr()), m, n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication of MxN complex matrix by NxN random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrndorthogonalfromtheright(const_cast(a.c_ptr()), m, n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiplication of MxN complex matrix by MxM random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixrndorthogonalfromtheleft(const_cast(a.c_ptr()), m, n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Symmetric multiplication of NxN matrix by random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q'*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndmultiply(real_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::smatrixrndmultiply(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Hermitian multiplication of NxN matrix by random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q^H*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hmatrixrndmultiply(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Sparse matrix structure. You should use ALGLIB functions to work with sparse matrix. Never try to access its fields directly! NOTES ON THE SPARSE STORAGE FORMATS Sparse matrices can be stored using several formats: * Hash-Table representation * Compressed Row Storage (CRS) * Skyline matrix storage (SKS) Each of the formats has benefits and drawbacks: * Hash-table is good for dynamic operations (insertion of new elements), but does not support linear algebra operations * CRS is good for operations like matrix-vector or matrix-matrix products, but its initialization is less convenient - you have to tell row sizes at the initialization, and you have to fill matrix only row by row, from left to right. * SKS is a special format which is used to store triangular factors from Cholesky factorization. It does not support dynamic modification, and support for linear algebra operations is very limited. Tables below outline information about these two formats: OPERATIONS WITH MATRIX HASH CRS SKS creation + + + SparseGet + + + SparseRewriteExisting + + + SparseSet + SparseAdd + SparseGetRow + + SparseGetCompressedRow + + sparse-dense linear algebra + + *************************************************************************/ _sparsematrix_owner::_sparsematrix_owner() { p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_sparsematrix_init(p_struct, NULL); } _sparsematrix_owner::_sparsematrix_owner(const _sparsematrix_owner &rhs) { p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _sparsematrix_owner& _sparsematrix_owner::operator=(const _sparsematrix_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_sparsematrix_clear(p_struct); alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _sparsematrix_owner::~_sparsematrix_owner() { alglib_impl::_sparsematrix_clear(p_struct); ae_free(p_struct); } alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() { return p_struct; } alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() const { return const_cast(p_struct); } sparsematrix::sparsematrix() : _sparsematrix_owner() { } sparsematrix::sparsematrix(const sparsematrix &rhs):_sparsematrix_owner(rhs) { } sparsematrix& sparsematrix::operator=(const sparsematrix &rhs) { if( this==&rhs ) return *this; _sparsematrix_owner::operator=(rhs); return *this; } sparsematrix::~sparsematrix() { } /************************************************************************* Temporary buffers for sparse matrix operations. You should pass an instance of this structure to factorization functions. It allows to reuse memory during repeated sparse factorizations. You do not have to call some initialization function - simply passing an instance to factorization function is enough. *************************************************************************/ _sparsebuffers_owner::_sparsebuffers_owner() { p_struct = (alglib_impl::sparsebuffers*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsebuffers), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_sparsebuffers_init(p_struct, NULL); } _sparsebuffers_owner::_sparsebuffers_owner(const _sparsebuffers_owner &rhs) { p_struct = (alglib_impl::sparsebuffers*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsebuffers), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_sparsebuffers_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _sparsebuffers_owner& _sparsebuffers_owner::operator=(const _sparsebuffers_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_sparsebuffers_clear(p_struct); alglib_impl::_sparsebuffers_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _sparsebuffers_owner::~_sparsebuffers_owner() { alglib_impl::_sparsebuffers_clear(p_struct); ae_free(p_struct); } alglib_impl::sparsebuffers* _sparsebuffers_owner::c_ptr() { return p_struct; } alglib_impl::sparsebuffers* _sparsebuffers_owner::c_ptr() const { return const_cast(p_struct); } sparsebuffers::sparsebuffers() : _sparsebuffers_owner() { } sparsebuffers::sparsebuffers(const sparsebuffers &rhs):_sparsebuffers_owner(rhs) { } sparsebuffers& sparsebuffers::operator=(const sparsebuffers &rhs) { if( this==&rhs ) return *this; _sparsebuffers_owner::operator=(rhs); return *this; } sparsebuffers::~sparsebuffers() { } /************************************************************************* This function creates sparse matrix in a Hash-Table format. This function creates Hast-Table matrix, which can be converted to CRS format after its initialization is over. Typical usage scenario for a sparse matrix is: 1. creation in a Hash-Table format 2. insertion of the matrix elements 3. conversion to the CRS representation 4. matrix is passed to some linear algebra algorithm Some information about different matrix formats can be found below, in the "NOTES" section. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. NOTE 1 Hash-tables use memory inefficiently, and they have to keep some amount of the "spare memory" in order to have good performance. Hash table for matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, where C is a small constant, about 1.5-2 in magnitude. CRS storage, from the other side, is more memory-efficient, and needs just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows in a matrix. When you convert from the Hash-Table to CRS representation, all unneeded memory will be freed. NOTE 2 Comments of SparseMatrix structure outline information about different sparse storage formats. We recommend you to read them before starting to use ALGLIB sparse matrices. NOTE 3 This function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreate(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function creates sparse matrix in a Hash-Table format. This function creates Hast-Table matrix, which can be converted to CRS format after its initialization is over. Typical usage scenario for a sparse matrix is: 1. creation in a Hash-Table format 2. insertion of the matrix elements 3. conversion to the CRS representation 4. matrix is passed to some linear algebra algorithm Some information about different matrix formats can be found below, in the "NOTES" section. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. NOTE 1 Hash-tables use memory inefficiently, and they have to keep some amount of the "spare memory" in order to have good performance. Hash table for matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, where C is a small constant, about 1.5-2 in magnitude. CRS storage, from the other side, is more memory-efficient, and needs just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows in a matrix. When you convert from the Hash-Table to CRS representation, all unneeded memory will be freed. NOTE 2 Comments of SparseMatrix structure outline information about different sparse storage formats. We recommend you to read them before starting to use ALGLIB sparse matrices. NOTE 3 This function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; k = 0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreate(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This version of SparseCreate function creates sparse matrix in Hash-Table format, reusing previously allocated storage as much as possible. Read comments for SparseCreate() for more information. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. S - SparseMatrix structure which MAY contain some already allocated storage. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. Previously allocated storage is reused, if its size is compatible with expected number of non-zeros K. -- ALGLIB PROJECT -- Copyright 14.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const ae_int_t k, const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatebuf(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This version of SparseCreate function creates sparse matrix in Hash-Table format, reusing previously allocated storage as much as possible. Read comments for SparseCreate() for more information. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. S - SparseMatrix structure which MAY contain some already allocated storage. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. Previously allocated storage is reused, if its size is compatible with expected number of non-zeros K. -- ALGLIB PROJECT -- Copyright 14.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; k = 0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatebuf(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateCRSBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatecrs(m, n, const_cast(ner.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This version of CRS matrix creation function may reuse memory already allocated in S. This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 S - sparse matrix structure with possibly preallocated memory. OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrsbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatecrsbuf(m, n, const_cast(ner.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], D[I]>=0. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], U[I]>=0. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseRewriteExisting() to change their values. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateSKSBuf function. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesks(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatesks(m, n, const_cast(d.c_ptr()), const_cast(u.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is "buffered" version of SparseCreateSKS() which reuses memory previously allocated in S (of course, memory is reallocated if needed). This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], 0<=D[I]<=I. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], 0<=U[I]<=I. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseSet()/SparseAdd() to change their values. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesksbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecreatesksbuf(m, n, const_cast(d.c_ptr()), const_cast(u.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function copies S0 to S1. This function completely deallocates memory owned by S1 before creating a copy of S0. If you want to reuse memory, use SparseCopyBuf. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopy(const sparsematrix &s0, sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopy(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function copies S0 to S1. Memory already allocated in S1 is reused as much as possible. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopybuf(const sparsematrix &s0, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopybuf(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function efficiently swaps contents of S0 and S1. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseswap(const sparsematrix &s0, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseswap(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds value to S[i,j] - element of the sparse matrix. Matrix must be in a Hash-Table mode. In case S[i,j] already exists in the table, V i added to its value. In case S[i,j] is non-existent, it is inserted in the table. Table automatically grows when necessary. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function modifies S[i,j] - element of the sparse matrix. For Hash-based storage format: * this function can be called at any moment - during matrix initialization or later * new value can be zero or non-zero. In case new value of S[i,j] is zero, this element is deleted from the table. * this function has no effect when called with zero V for non-existent element. For CRS-bases storage format: * this function can be called ONLY DURING MATRIX INITIALIZATION * new value MUST be non-zero. Exception will be thrown for zero V. * elements must be initialized in correct order - from top row to bottom, within row - from left to right. For SKS storage: NOT SUPPORTED! Use SparseRewriteExisting() to work with SKS matrices. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns S[i,j] - element of the sparse matrix. Matrix can be in any mode (Hash-Table, CRS, SKS), but this function is less efficient for CRS matrices. Hash-Table and SKS matrices can find element in O(1) time, while CRS matrices need O(log(RS)) time, where RS is an number of non-zero elements in a row. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns I-th diagonal element of the sparse matrix. Matrix can be in any mode (Hash-Table or CRS storage), but this function is most efficient for CRS matrices - it requires less than 50 CPU cycles to extract diagonal element. For Hash-Table matrices we still have O(1) query time, but function is many times slower. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - index of the element to modify, 0<=I(s.c_ptr()), i, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-vector product S*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemv(const sparsematrix &s, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemv(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-vector product S^T*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[M], input vector. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemtv(const sparsematrix &s, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemtv(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function simultaneously calculates two matrix-vector products: S*x and S^T*x. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. Y1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y0 - array[N], S*x Y1 - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemv2(const sparsematrix &s, const real_1d_array &x, real_1d_array &y0, real_1d_array &y1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemv2(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y0.c_ptr()), const_cast(y1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-vector product S*x, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsesmv(const_cast(s.c_ptr()), isupper, const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates vector-matrix-vector product x'*S*x, where S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. RESULT x'*S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 27.01.2014 by Bochkanov Sergey *************************************************************************/ double sparsevsmv(const sparsematrix &s, const bool isupper, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::sparsevsmv(const_cast(s.c_ptr()), isupper, const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-matrix product S*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemm(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-matrix product S^T*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[M][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemtm(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function simultaneously calculates two matrix-matrix products: S*A and S^T*A. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. B1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B0 - array[N][K], S*A B1 - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsemm2(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b0.c_ptr()), const_cast(b1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-matrix product S*A, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsesmm(const_cast(s.c_ptr()), isupper, const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates matrix-vector product op(S)*x, when x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - possibly preallocated input buffer. Automatically resized if its size is too small. OUTPUT PARAMETERS Y - array[N], op(S)*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrmv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsetrmv(const_cast(s.c_ptr()), isupper, isunit, optype, const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves linear system op(S)*y=x where x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used. It is your responsibility to make sure that diagonal is non-zero. OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. OUTPUT PARAMETERS X - array[N], inv(op(S))*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. NOTE: no assertion or tests are done during algorithm operation. It is your responsibility to provide invertible matrix to algorithm. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrsv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsetrsv(const_cast(s.c_ptr()), isupper, isunit, optype, const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This procedure resizes Hash-Table matrix. It can be called when you have deleted too many elements from the matrix, and you want to free unneeded memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparseresizematrix(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseresizematrix(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to enumerate all elements of the sparse matrix. Before first call user initializes T0 and T1 counters by zero. These counters are used to remember current position in a matrix; after each call they are updated by the function. Subsequent calls to this function return non-zero elements of the sparse matrix, one by one. If you enumerate CRS matrix, matrix is traversed from left to right, from top to bottom. In case you enumerate matrix stored as Hash table, elements are returned in random order. EXAMPLE > T0=0 > T1=0 > while SparseEnumerate(S,T0,T1,I,J,V) do > ....do something with I,J,V INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. T0 - internal counter T1 - internal counter OUTPUT PARAMETERS T0 - new value of the internal counter T1 - new value of the internal counter I - row index of non-zero element, 0<=I(s.c_ptr()), &t0, &t1, &i, &j, &v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function rewrites existing (non-zero) element. It returns True if element exists or False, when it is called for non-existing (zero) element. This function works with any kind of the matrix. The purpose of this function is to provide convenient thread-safe way to modify sparse matrix. Such modification (already existing element is rewritten) is guaranteed to be thread-safe without any synchronization, as long as different threads modify different elements. INPUT PARAMETERS S - sparse M*N matrix in any kind of representation (Hash, SKS, CRS). I - row index of non-zero element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns I-th row of the sparse matrix. Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=I(s.c_ptr()), i, const_cast(irow.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns I-th row of the sparse matrix IN COMPRESSED FORMAT - only non-zero elements are returned (with their indexes). Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=I(s.c_ptr()), i, const_cast(colidx.c_ptr()), const_cast(vals.c_ptr()), &nzcnt, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs efficient in-place transpose of SKS matrix. No additional memory is allocated during transposition. This function supports only skyline storage format (SKS). INPUT PARAMETERS S - sparse matrix in SKS format. OUTPUT PARAMETERS S - sparse matrix, transposed. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetransposesks(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsetransposesks(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs in-place conversion to desired sparse storage format. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S0 - sparse matrix in requested format. NOTE: in-place conversion wastes a lot of memory which is used to store temporaries. If you perform a lot of repeated conversions, we recommend to use out-of-place buffered conversion functions, like SparseCopyToBuf(), which can reuse already allocated memory. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseconvertto(const sparsematrix &s0, const ae_int_t fmt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseconvertto(const_cast(s0.c_ptr()), fmt, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to desired sparse storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S1 - sparse matrix in requested format. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecopytobuf(const sparsematrix &s0, const ae_int_t fmt, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytobuf(const_cast(s0.c_ptr()), fmt, const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs in-place conversion to Hash table storage. INPUT PARAMETERS S - sparse matrix in CRS format. OUTPUT PARAMETERS S - sparse matrix in Hash table format. NOTE: this function has no effect when called with matrix which is already in Hash table mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToHashBuf() function in this case. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparseconverttohash(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseconverttohash(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToHashBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytohash(const sparsematrix &s0, sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytohash(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytohashbuf(const sparsematrix &s0, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytohashbuf(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function converts matrix to CRS format. Some algorithms (linear algebra ones, for example) require matrices in CRS format. This function allows to perform in-place conversion. INPUT PARAMETERS S - sparse M*N matrix in any format OUTPUT PARAMETERS S - matrix in CRS format NOTE: this function has no effect when called with matrix which is already in CRS mode. NOTE: this function allocates temporary memory to store a copy of the matrix. If you perform a lot of repeated conversions, we recommend you to use SparseCopyToCRSBuf() function, which can reuse previously allocated memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparseconverttocrs(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseconverttocrs(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting CRS conversion. If you perform a lot of repeated CRS conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToCRSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytocrs(const sparsematrix &s0, sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytocrs(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. S1 - matrix which may contain some pre-allocated memory, or can be just uninitialized structure. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytocrsbuf(const sparsematrix &s0, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytocrsbuf(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs in-place conversion to SKS format. INPUT PARAMETERS S - sparse matrix in any format. OUTPUT PARAMETERS S - sparse matrix in SKS format. NOTE: this function has no effect when called with matrix which is already in SKS mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToSKSBuf() function in this case. -- ALGLIB PROJECT -- Copyright 15.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseconverttosks(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparseconverttosks(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to SKS storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToSKSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytosks(const sparsematrix &s0, sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytosks(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs out-of-place conversion to SKS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytosksbuf(const sparsematrix &s0, const sparsematrix &s1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsecopytosksbuf(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns type of the matrix storage format. INPUT PARAMETERS: S - sparse matrix. RESULT: sparse storage format used by matrix: 0 - Hash-table 1 - CRS (compressed row storage) 2 - SKS (skyline) NOTE: future versions of ALGLIB may include additional sparse storage formats. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetmatrixtype(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::sparsegetmatrixtype(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using Hash table representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is Hash table False if matrix type is not Hash table -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ bool sparseishash(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::sparseishash(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using CRS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is CRS False if matrix type is not CRS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ bool sparseiscrs(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::sparseiscrs(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using SKS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is SKS False if matrix type is not SKS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ bool sparseissks(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::sparseissks(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The function frees all memory occupied by sparse matrix. Sparse matrix structure becomes unusable after this call. OUTPUT PARAMETERS S - sparse matrix to delete -- ALGLIB PROJECT -- Copyright 24.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsefree(sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sparsefree(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The function returns number of rows of a sparse matrix. RESULT: number of rows of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetnrows(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::sparsegetnrows(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The function returns number of columns of a sparse matrix. RESULT: number of columns of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetncols(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::sparsegetncols(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The function returns number of strictly upper triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly above main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetuppercount(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::sparsegetuppercount(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The function returns number of strictly lower triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly below main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetlowercount(const sparsematrix &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::sparsegetlowercount(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LU decomposition of a general real matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LU decomposition of a general complex matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a Hermitian positive- definite matrix. The result of an algorithm is a representation of A as A=U'*U or A=L*L' (here X' detones conj(X^T)). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U'*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::hpdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } bool smp_hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::_pexec_hpdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a symmetric positive- definite matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U^T*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::spdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } bool smp_spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::_pexec_spdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateAdd1Buf(). INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyupdateadd1(const_cast(a.c_ptr()), n, isupper, const_cast(u.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Update of Cholesky decomposition: "fixing" some variables. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateFixBuf(). "FIXING" EXPLAINED: Suppose we have N*N positive definite matrix A. "Fixing" some variable means filling corresponding row/column of A by zeros, and setting diagonal element to 1. For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) ( A10 A11 A12 A13 ) ( 0 1 0 0 ) ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) If we have Cholesky decomposition of A, it must be recalculated after variables were fixed. However, it is possible to use efficient algorithm, which needs O(K*N^2) time to "fix" K variables, given Cholesky decomposition of original, "unfixed" A. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. NOTE: this function is efficient only for moderate amount of updated variables - say, 0.1*N or 0.3*N. For larger amount of variables it will still work, but you may get better performance with straightforward Cholesky. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefix(const real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyupdatefix(const_cast(a.c_ptr()), n, isupper, const_cast(fix.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateAdd1() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1buf(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, real_1d_array &bufr) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyupdateadd1buf(const_cast(a.c_ptr()), n, isupper, const_cast(u.c_ptr()), const_cast(bufr.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Update of Cholesky decomposition: "fixing" some variables. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateFix() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefixbuf(const real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, real_1d_array &bufr) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyupdatefixbuf(const_cast(a.c_ptr()), n, isupper, const_cast(fix.c_ptr()), const_cast(bufr.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Sparse Cholesky decomposition for skyline matrixm using in-place algorithm without allocating additional storage. The algorithm computes Cholesky decomposition of a symmetric positive- definite sparse matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T This function is a more efficient alternative to general, but slower SparseCholeskyX(), because it does not create temporary copies of the target. It performs factorization in-place, which gives best performance on low-profile matrices. Its drawback, however, is that it can not perform profile-reducing permutation of input matrix. INPUT PARAMETERS: A - sparse matrix in skyline storage (SKS) format. N - size of matrix A (can be smaller than actual size of A) IsUpper - if IsUpper=True, then factorization is performed on upper triangle. Another triangle is ignored (it may contant some data, but it is not changed). OUTPUT PARAMETERS: A - the result of factorization, stored in SKS. If IsUpper=True, then the upper triangle contains matrix U, such that A = U^T*U. Lower triangle is not changed. Similarly, if IsUpper = False. In this case L is returned, and we have A = L*(L^T). Note that THIS function does not perform permutation of rows to reduce bandwidth. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. NOTE: for performance reasons this function does NOT check that input matrix includes only finite values. It is your responsibility to make sure that there are no infinite or NAN values in the matrix. -- ALGLIB routine -- 16.01.2014 Bochkanov Sergey *************************************************************************/ bool sparsecholeskyskyline(const sparsematrix &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::sparsecholeskyskyline(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcond1(const real_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixrcond1(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixrcondinf(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Condition number estimate of a symmetric positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - symmetric positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixtrrcond1(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixtrrcondinf(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Condition number estimate of a Hermitian positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - Hermitian positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hpdmatrixrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixrcond1(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixrcondinf(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixlurcond1(const_cast(lua.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixlurcondinf(const_cast(lua.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Condition number estimate of a symmetric positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixcholeskyrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Condition number estimate of a Hermitian positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hpdmatrixcholeskyrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixlurcond1(const_cast(lua.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixlurcondinf(const_cast(lua.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixtrrcond1(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cmatrixtrrcondinf(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Matrix inverse report: * R1 reciprocal of condition number in 1-norm * RInf reciprocal of condition number in inf-norm *************************************************************************/ _matinvreport_owner::_matinvreport_owner() { p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_matinvreport_init(p_struct, NULL); } _matinvreport_owner::_matinvreport_owner(const _matinvreport_owner &rhs) { p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _matinvreport_owner& _matinvreport_owner::operator=(const _matinvreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_matinvreport_clear(p_struct); alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _matinvreport_owner::~_matinvreport_owner() { alglib_impl::_matinvreport_clear(p_struct); ae_free(p_struct); } alglib_impl::matinvreport* _matinvreport_owner::c_ptr() { return p_struct; } alglib_impl::matinvreport* _matinvreport_owner::c_ptr() const { return const_cast(p_struct); } matinvreport::matinvreport() : _matinvreport_owner() ,r1(p_struct->r1),rinf(p_struct->rinf) { } matinvreport::matinvreport(const matinvreport &rhs):_matinvreport_owner(rhs) ,r1(p_struct->r1),rinf(p_struct->rinf) { } matinvreport& matinvreport::operator=(const matinvreport &rhs) { if( this==&rhs ) return *this; _matinvreport_owner::operator=(rhs); return *this; } matinvreport::~matinvreport() { } /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations (the output of RMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. it is filled by zeros in such cases. * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - solver report, see below for more info A - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. SOLVER REPORT Subroutine sets following fields of the Rep structure: * R1 reciprocal of condition number: 1/cond(A), 1-norm. * RInf reciprocal of condition number: 1/cond(A), inf-norm. -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations (the output of RMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. it is filled by zeros in such cases. * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - solver report, see below for more info A - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. SOLVER REPORT Subroutine sets following fields of the Rep structure: * R1 reciprocal of condition number: 1/cond(A), 1-norm. * RInf reciprocal of condition number: 1/cond(A), inf-norm. -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) throw ap_error("Error while calling 'rmatrixluinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) throw ap_error("Error while calling 'rmatrixluinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse Result: True, if the matrix is not singular. False, if the matrix is singular. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse Result: True, if the matrix is not singular. False, if the matrix is singular. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'rmatrixinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'rmatrixinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of CMatrixLU subroutine). Pivots - table of permutations (the output of CMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of CMatrixLU subroutine). Pivots - table of permutations (the output of CMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) throw ap_error("Error while calling 'cmatrixluinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) throw ap_error("Error while calling 'cmatrixluinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'cmatrixinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'cmatrixinverse': looks like one of arguments has wrong size"); n = a.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a symmetric positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of SPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a symmetric positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of SPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'spdmatrixcholeskyinverse': looks like one of arguments has wrong size"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'spdmatrixcholeskyinverse': looks like one of arguments has wrong size"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a symmetric positive definite matrix. Given an upper or lower triangle of a symmetric positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a symmetric positive definite matrix. Given an upper or lower triangle of a symmetric positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'spdmatrixinverse': looks like one of arguments has wrong size"); if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not symmetric matrix"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); if( !alglib_impl::ae_force_symmetric(const_cast(a.c_ptr())) ) throw ap_error("Internal error while forcing symmetricity of 'a' parameter"); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'spdmatrixinverse': looks like one of arguments has wrong size"); if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not symmetric matrix"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); if( !alglib_impl::ae_force_symmetric(const_cast(a.c_ptr())) ) throw ap_error("Internal error while forcing symmetricity of 'a' parameter"); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a Hermitian positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of HPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a Hermitian positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of HPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'hpdmatrixcholeskyinverse': looks like one of arguments has wrong size"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'hpdmatrixcholeskyinverse': looks like one of arguments has wrong size"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a Hermitian positive definite matrix. Given an upper or lower triangle of a Hermitian positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inversion of a Hermitian positive definite matrix. Given an upper or lower triangle of a Hermitian positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'hpdmatrixinverse': looks like one of arguments has wrong size"); if( !alglib_impl::ae_is_hermitian(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not Hermitian matrix"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); if( !alglib_impl::ae_force_hermitian(const_cast(a.c_ptr())) ) throw ap_error("Internal error while forcing Hermitian properties of 'a' parameter"); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'hpdmatrixinverse': looks like one of arguments has wrong size"); if( !alglib_impl::ae_is_hermitian(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not Hermitian matrix"); n = a.cols(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); if( !alglib_impl::ae_force_hermitian(const_cast(a.c_ptr())) ) throw ap_error("Internal error while forcing Hermitian properties of 'a' parameter"); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix inverse (real) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix inverse (real) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isunit; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'rmatrixtrinverse': looks like one of arguments has wrong size"); n = a.cols(); isunit = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isunit; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'rmatrixtrinverse': looks like one of arguments has wrong size"); n = a.cols(); isunit = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix inverse (complex) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Triangular matrix inverse (complex) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isunit; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'cmatrixtrinverse': looks like one of arguments has wrong size"); n = a.cols(); isunit = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isunit; if( (a.cols()!=a.rows())) throw ap_error("Error while calling 'cmatrixtrinverse': looks like one of arguments has wrong size"); n = a.cols(); isunit = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores state of the iterative norm estimation algorithm. You should use ALGLIB functions to work with this object. *************************************************************************/ _normestimatorstate_owner::_normestimatorstate_owner() { p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_normestimatorstate_init(p_struct, NULL); } _normestimatorstate_owner::_normestimatorstate_owner(const _normestimatorstate_owner &rhs) { p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _normestimatorstate_owner& _normestimatorstate_owner::operator=(const _normestimatorstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_normestimatorstate_clear(p_struct); alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _normestimatorstate_owner::~_normestimatorstate_owner() { alglib_impl::_normestimatorstate_clear(p_struct); ae_free(p_struct); } alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() { return p_struct; } alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() const { return const_cast(p_struct); } normestimatorstate::normestimatorstate() : _normestimatorstate_owner() { } normestimatorstate::normestimatorstate(const normestimatorstate &rhs):_normestimatorstate_owner(rhs) { } normestimatorstate& normestimatorstate::operator=(const normestimatorstate &rhs) { if( this==&rhs ) return *this; _normestimatorstate_owner::operator=(rhs); return *this; } normestimatorstate::~normestimatorstate() { } /************************************************************************* This procedure initializes matrix norm estimator. USAGE: 1. User initializes algorithm state with NormEstimatorCreate() call 2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) 3. User calls NormEstimatorResults() to get solution. INPUT PARAMETERS: M - number of rows in the matrix being estimated, M>0 N - number of columns in the matrix being estimated, N>0 NStart - number of random starting vectors recommended value - at least 5. NIts - number of iterations to do with best starting vector recommended value - at least 5. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: this algorithm is effectively deterministic, i.e. it always returns same result when repeatedly called for the same matrix. In fact, algorithm uses randomized starting vectors, but internal random numbers generator always generates same sequence of the random values (it is a feature, not bug). Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::normestimatorcreate(m, n, nstart, nits, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function changes seed value used by algorithm. In some cases we need deterministic processing, i.e. subsequent calls must return equal results, in other cases we need non-deterministic algorithm which returns different results for the same matrix on every pass. Setting zero seed will lead to non-deterministic algorithm, while non-zero value will make our algorithm deterministic. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() SeedVal - seed value, >=0. Zero value = non-deterministic algo. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorsetseed(const normestimatorstate &state, const ae_int_t seedval) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::normestimatorsetseed(const_cast(state.c_ptr()), seedval, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function estimates norm of the sparse M*N matrix A. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() A - sparse M*N matrix, must be converted to CRS format prior to calling this function. After this function is over you can call NormEstimatorResults() to get estimate of the norm(A). -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorestimatesparse(const normestimatorstate &state, const sparsematrix &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::normestimatorestimatesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Matrix norm estimation results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Nrm - estimate of the matrix norm, Nrm>=0 -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorresults(const normestimatorstate &state, double &nrm) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::normestimatorresults(const_cast(state.c_ptr()), &nrm, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) throw ap_error("Error while calling 'rmatrixludet': looks like one of arguments has wrong size"); n = a.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixdet(const real_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixdet(const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.rows()!=a.cols())) throw ap_error("Error while calling 'rmatrixdet': looks like one of arguments has wrong size"); n = a.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::cmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) throw ap_error("Error while calling 'cmatrixludet': looks like one of arguments has wrong size"); n = a.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::cmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::cmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixdet(const complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.rows()!=a.cols())) throw ap_error("Error while calling 'cmatrixdet': looks like one of arguments has wrong size"); n = a.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::cmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by the Cholesky decomposition. Input parameters: A - Cholesky decomposition, output of SMatrixCholesky subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) As the determinant is equal to the product of squares of diagonal elements, its not necessary to specify which triangle - lower or upper - the matrix is stored in. Result: matrix determinant. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixcholeskydet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the matrix given by the Cholesky decomposition. Input parameters: A - Cholesky decomposition, output of SMatrixCholesky subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) As the determinant is equal to the product of squares of diagonal elements, its not necessary to specify which triangle - lower or upper - the matrix is stored in. Result: matrix determinant. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixcholeskydet(const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (a.rows()!=a.cols())) throw ap_error("Error while calling 'spdmatrixcholeskydet': looks like one of arguments has wrong size"); n = a.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixcholeskydet(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Result: determinant of matrix A. If matrix A is not positive definite, exception is thrown. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixdet(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Result: determinant of matrix A. If matrix A is not positive definite, exception is thrown. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixdet(const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; bool isupper; if( (a.rows()!=a.cols())) throw ap_error("Error while calling 'spdmatrixdet': looks like one of arguments has wrong size"); if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not symmetric matrix"); n = a.rows(); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spdmatrixdet(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Algorithm for solving the following generalized symmetric positive-definite eigenproblem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3). where A is a symmetric matrix, B - symmetric positive-definite matrix. The problem is solved by reducing it to an ordinary symmetric eigenvalue problem. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ZNeeded - if ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in matrix columns. It should be noted that the eigenvectors in such problems do not form an orthogonal system. Result: True, if the problem was solved successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix isnt positive-definite) or during the work of the iterative algorithm for solving the symmetric eigenproblem. See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixgevd(const_cast(a.c_ptr()), n, isuppera, const_cast(b.c_ptr()), isupperb, zneeded, problemtype, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Algorithm for reduction of the following generalized symmetric positive- definite eigenvalue problem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3) to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and the given problems are the same, and the eigenvectors of the given problem could be obtained by multiplying the obtained eigenvectors by the transformation matrix x = R*y). Here A is a symmetric matrix, B - symmetric positive-definite matrix. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: A - symmetric matrix which is given by its upper or lower triangle depending on IsUpperA. Contains matrix C. Array whose indexes range within [0..N-1, 0..N-1]. R - upper triangular or low triangular transformation matrix which is used to obtain the eigenvectors of a given problem as the product of eigenvectors of C (from the right) and matrix R (from the left). If the matrix is upper triangular, the elements below the main diagonal are equal to 0 (and vice versa). Thus, we can perform the multiplication without taking into account the internal structure (which is an easier though less effective way). Array whose indexes range within [0..N-1, 0..N-1]. IsUpperR - type of matrix R (upper or lower triangular). Result: True, if the problem was reduced successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix is not positive-definite). -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::smatrixgevdreduce(const_cast(a.c_ptr()), n, isuppera, const_cast(b.c_ptr()), isupperb, problemtype, const_cast(r.c_ptr()), &isupperr, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a number to an element of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - row where the element to be updated is stored. UpdColumn - column where the element to be updated is stored. UpdVal - a number to be added to the element. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinvupdatesimple(const_cast(inva.c_ptr()), n, updrow, updcolumn, updval, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a row of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - the row of A whose vector V was added. 0 <= Row <= N-1 V - the vector to be added to a row. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinvupdaterow(const_cast(inva.c_ptr()), n, updrow, const_cast(v.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a column of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdColumn - the column of A whose vector U was added. 0 <= UpdColumn <= N-1 U - the vector to be added to a column. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinvupdatecolumn(const_cast(inva.c_ptr()), n, updcolumn, const_cast(u.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm computes the inverse of matrix A+u*v by using the given matrix A^-1 and the vectors u and v. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. U - the vector modifying the matrix. Array whose index ranges within [0..N-1]. V - the vector modifying the matrix. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of matrix A + u*v'. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixinvupdateuv(const_cast(inva.c_ptr()), n, const_cast(u.c_ptr()), const_cast(v.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Subroutine performing the Schur decomposition of a general matrix by using the QR algorithm with multiple shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The source matrix A is represented as S'*A*S = T, where S is an orthogonal matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..N-1, 0..N-1]. N - size of A, N>=0. Output parameters: A - contains matrix T. Array whose indexes range within [0..N-1, 0..N-1]. S - contains Schur vectors. Array whose indexes range within [0..N-1, 0..N-1]. Note 1: The block structure of matrix T can be easily recognized: since all the elements below the blocks are zeros, the elements a[i+1,i] which are equal to 0 show the block border. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms in linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. Result: True, if the algorithm has converged and parameters A and S contain the result. False, if the algorithm has not converged. Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). *************************************************************************/ bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::rmatrixschur(const_cast(a.c_ptr()), n, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static ae_int_t ablas_rgemmparallelsize = 64; static ae_int_t ablas_cgemmparallelsize = 64; static void ablas_ablasinternalsplitlength(ae_int_t n, ae_int_t nb, ae_int_t* n1, ae_int_t* n2, ae_state *_state); static void ablas_cmatrixrighttrsm2(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); static void ablas_cmatrixlefttrsm2(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); static void ablas_rmatrixrighttrsm2(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); static void ablas_rmatrixlefttrsm2(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); static void ablas_cmatrixherk2(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); static void ablas_rmatrixsyrk2(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* work, /* Complex */ ae_vector* t, /* Complex */ ae_vector* tau, ae_state *_state); static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* work, /* Complex */ ae_vector* t, /* Complex */ ae_vector* tau, ae_state *_state); static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, /* Real */ ae_vector* tau, ae_bool columnwisea, ae_int_t lengtha, ae_int_t blocksize, /* Real */ ae_matrix* t, /* Real */ ae_vector* work, ae_state *_state); static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, /* Complex */ ae_vector* tau, ae_bool columnwisea, ae_int_t lengtha, ae_int_t blocksize, /* Complex */ ae_matrix* t, /* Complex */ ae_vector* work, ae_state *_state); static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* uu, ae_int_t ustart, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t cstart, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t vstart, ae_int_t ncvt, ae_state *_state); static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state); static void bdsvd_svd2x2(double f, double g, double h, double* ssmin, double* ssmax, ae_state *_state); static void bdsvd_svdv2x2(double f, double g, double h, double* ssmin, double* ssmax, double* snr, double* csr, double* snl, double* csl, ae_state *_state); static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_state *_state); static void evd_tdevde2(double a, double b, double c, double* rt1, double* rt2, ae_state *_state); static void evd_tdevdev2(double a, double b, double c, double* rt1, double* rt2, double* cs1, double* sn1, ae_state *_state); static double evd_tdevdpythag(double a, double b, ae_state *_state); static double evd_tdevdextsign(double a, double b, ae_state *_state); static ae_bool evd_internalbisectioneigenvalues(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t irange, ae_int_t iorder, double vl, double vu, ae_int_t il, ae_int_t iu, double abstol, /* Real */ ae_vector* w, ae_int_t* m, ae_int_t* nsplit, /* Integer */ ae_vector* iblock, /* Integer */ ae_vector* isplit, ae_int_t* errorcode, ae_state *_state); static void evd_internaldstein(ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t m, /* Real */ ae_vector* w, /* Integer */ ae_vector* iblock, /* Integer */ ae_vector* isplit, /* Real */ ae_matrix* z, /* Integer */ ae_vector* ifail, ae_int_t* info, ae_state *_state); static void evd_tdininternaldlagtf(ae_int_t n, /* Real */ ae_vector* a, double lambdav, /* Real */ ae_vector* b, /* Real */ ae_vector* c, double tol, /* Real */ ae_vector* d, /* Integer */ ae_vector* iin, ae_int_t* info, ae_state *_state); static void evd_tdininternaldlagts(ae_int_t n, /* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, /* Integer */ ae_vector* iin, /* Real */ ae_vector* y, double* tol, ae_int_t* info, ae_state *_state); static void evd_internaldlaebz(ae_int_t ijob, ae_int_t nitmax, ae_int_t n, ae_int_t mmax, ae_int_t minp, double abstol, double reltol, double pivmin, /* Real */ ae_vector* d, /* Real */ ae_vector* e, /* Real */ ae_vector* e2, /* Integer */ ae_vector* nval, /* Real */ ae_matrix* ab, /* Real */ ae_vector* c, ae_int_t* mout, /* Integer */ ae_matrix* nab, /* Real */ ae_vector* work, /* Integer */ ae_vector* iwork, ae_int_t* info, ae_state *_state); static void evd_rmatrixinternaltrevc(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Boolean */ ae_vector* vselect, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state); static void evd_internaltrevc(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Boolean */ ae_vector* vselect, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state); static void evd_internalhsevdlaln2(ae_bool ltrans, ae_int_t na, ae_int_t nw, double smin, double ca, /* Real */ ae_matrix* a, double d1, double d2, /* Real */ ae_matrix* b, double wr, double wi, /* Boolean */ ae_vector* rswap4, /* Boolean */ ae_vector* zswap4, /* Integer */ ae_matrix* ipivot44, /* Real */ ae_vector* civ4, /* Real */ ae_vector* crv4, /* Real */ ae_matrix* x, double* scl, double* xnorm, ae_int_t* info, ae_state *_state); static void evd_internalhsevdladiv(double a, double b, double c, double d, double* p, double* q, ae_state *_state); static double sparse_desiredloadfactor = 0.66; static double sparse_maxloadfactor = 0.75; static double sparse_growfactor = 2.00; static ae_int_t sparse_additional = 10; static ae_int_t sparse_linalgswitch = 16; static void sparse_sparseinitduidx(sparsematrix* s, ae_state *_state); static ae_int_t sparse_hash(ae_int_t i, ae_int_t j, ae_int_t tabsize, ae_state *_state); static void trfac_cmatrixluprec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state); static void trfac_rmatrixluprec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state); static void trfac_cmatrixplurec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state); static void trfac_rmatrixplurec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state); static void trfac_cmatrixlup2(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state); static void trfac_rmatrixlup2(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state); static void trfac_cmatrixplu2(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state); static void trfac_rmatrixplu2(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state); static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state); static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state); static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state); static void rcond_rmatrixrcondtrinternal(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_bool onenorm, double anorm, double* rc, ae_state *_state); static void rcond_cmatrixrcondtrinternal(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_bool onenorm, double anorm, double* rc, ae_state *_state); static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, ae_bool isnormprovided, double anorm, double* rc, ae_state *_state); static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, ae_bool isnormprovided, double anorm, double* rc, ae_state *_state); static void rcond_rmatrixrcondluinternal(/* Real */ ae_matrix* lua, ae_int_t n, ae_bool onenorm, ae_bool isanormprovided, double anorm, double* rc, ae_state *_state); static void rcond_cmatrixrcondluinternal(/* Complex */ ae_matrix* lua, ae_int_t n, ae_bool onenorm, ae_bool isanormprovided, double anorm, double* rc, ae_state *_state); static void rcond_rmatrixestimatenorm(ae_int_t n, /* Real */ ae_vector* v, /* Real */ ae_vector* x, /* Integer */ ae_vector* isgn, double* est, ae_int_t* kase, ae_state *_state); static void rcond_cmatrixestimatenorm(ae_int_t n, /* Complex */ ae_vector* v, /* Complex */ ae_vector* x, double* est, ae_int_t* kase, /* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_state *_state); static double rcond_internalcomplexrcondscsum1(/* Complex */ ae_vector* x, ae_int_t n, ae_state *_state); static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ ae_vector* x, ae_int_t n, ae_state *_state); static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_int_t* i, ae_int_t* iter, ae_int_t* j, ae_int_t* jlast, ae_int_t* jump, double* absxi, double* altsgn, double* estold, double* temp, ae_state *_state); static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_int_t* i, ae_int_t* iter, ae_int_t* j, ae_int_t* jlast, ae_int_t* jump, double* absxi, double* altsgn, double* estold, double* temp, ae_state *_state); static ae_int_t matinv_parallelsize = 64; static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool isunit, /* Real */ ae_vector* tmp, sinteger* info, matinvreport* rep, ae_state *_state); static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool isunit, /* Complex */ ae_vector* tmp, ae_int_t* info, matinvreport* rep, ae_state *_state); static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, /* Real */ ae_vector* work, sinteger* info, matinvreport* rep, ae_state *_state); static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, /* Complex */ ae_vector* work, ae_int_t* info, matinvreport* rep, ae_state *_state); static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state); /************************************************************************* Splits matrix length in two parts, left part should match ABLAS block size INPUT PARAMETERS A - real matrix, is passed to ensure that we didn't split complex matrix using real splitting subroutine. matrix itself is not changed. N - length, N>0 OUTPUT PARAMETERS N1 - length N2 - length N1+N2=N, N1>=N2, N2 may be zero -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void ablassplitlength(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t* n1, ae_int_t* n2, ae_state *_state) { *n1 = 0; *n2 = 0; if( n>ablasblocksize(a, _state) ) { ablas_ablasinternalsplitlength(n, ablasblocksize(a, _state), n1, n2, _state); } else { ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); } } /************************************************************************* Complex ABLASSplitLength -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void ablascomplexsplitlength(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t* n1, ae_int_t* n2, ae_state *_state) { *n1 = 0; *n2 = 0; if( n>ablascomplexblocksize(a, _state) ) { ablas_ablasinternalsplitlength(n, ablascomplexblocksize(a, _state), n1, n2, _state); } else { ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); } } /************************************************************************* Returns block size - subdivision size where cache-oblivious soubroutines switch to the optimized kernel. INPUT PARAMETERS A - real matrix, is passed to ensure that we didn't split complex matrix using real splitting subroutine. matrix itself is not changed. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_int_t ablasblocksize(/* Real */ ae_matrix* a, ae_state *_state) { ae_int_t result; result = 32; return result; } /************************************************************************* Block size for complex subroutines. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_int_t ablascomplexblocksize(/* Complex */ ae_matrix* a, ae_state *_state) { ae_int_t result; result = 24; return result; } /************************************************************************* Microblock size -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_int_t ablasmicroblocksize(ae_state *_state) { ae_int_t result; result = 8; return result; } /************************************************************************* Cache-oblivous complex "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixtranspose(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state) { ae_int_t i; ae_int_t s1; ae_int_t s2; if( m<=2*ablascomplexblocksize(a, _state)&&n<=2*ablascomplexblocksize(a, _state) ) { /* * base case */ for(i=0; i<=m-1; i++) { ae_v_cmove(&b->ptr.pp_complex[ib][jb+i], b->stride, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(ib,ib+n-1)); } } else { /* * Cache-oblivious recursion */ if( m>n ) { ablascomplexsplitlength(a, m, &s1, &s2, _state); cmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); cmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); } else { ablascomplexsplitlength(a, n, &s1, &s2, _state); cmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); cmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); } } } /************************************************************************* Cache-oblivous real "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixtranspose(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state) { ae_int_t i; ae_int_t s1; ae_int_t s2; if( m<=2*ablasblocksize(a, _state)&&n<=2*ablasblocksize(a, _state) ) { /* * base case */ for(i=0; i<=m-1; i++) { ae_v_move(&b->ptr.pp_double[ib][jb+i], b->stride, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(ib,ib+n-1)); } } else { /* * Cache-oblivious recursion */ if( m>n ) { ablassplitlength(a, m, &s1, &s2, _state); rmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); rmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); } else { ablassplitlength(a, n, &s1, &s2, _state); rmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); rmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); } } } /************************************************************************* This code enforces symmetricy of the matrix by copying Upper part to lower one (or vice versa). INPUT PARAMETERS: A - matrix N - number of rows/columns IsUpper - whether we want to copy upper triangle to lower one (True) or vice versa (False). *************************************************************************/ void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j; if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { a->ptr.pp_double[j][i] = a->ptr.pp_double[i][j]; } } } else { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { a->ptr.pp_double[i][j] = a->ptr.pp_double[j][i]; } } } } /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixcopy(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state) { ae_int_t i; if( m==0||n==0 ) { return; } for(i=0; i<=m-1; i++) { ae_v_cmove(&b->ptr.pp_complex[ib+i][jb], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(jb,jb+n-1)); } } /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixcopy(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state) { ae_int_t i; if( m==0||n==0 ) { return; } for(i=0; i<=m-1; i++) { ae_v_move(&b->ptr.pp_double[ib+i][jb], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(jb,jb+n-1)); } } /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void cmatrixrank1(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_vector* u, ae_int_t iu, /* Complex */ ae_vector* v, ae_int_t iv, ae_state *_state) { ae_int_t i; ae_complex s; if( m==0||n==0 ) { return; } if( cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) { return; } for(i=0; i<=m-1; i++) { s = u->ptr.p_complex[iu+i]; ae_v_caddc(&a->ptr.pp_complex[ia+i][ja], 1, &v->ptr.p_complex[iv], 1, "N", ae_v_len(ja,ja+n-1), s); } } /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void rmatrixrank1(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_vector* u, ae_int_t iu, /* Real */ ae_vector* v, ae_int_t iv, ae_state *_state) { ae_int_t i; double s; if( m==0||n==0 ) { return; } if( rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) { return; } for(i=0; i<=m-1; i++) { s = u->ptr.p_double[iu+i]; ae_v_addd(&a->ptr.pp_double[ia+i][ja], 1, &v->ptr.p_double[iv], 1, ae_v_len(ja,ja+n-1), s); } } /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) M>=0 N - number of columns of op(A) N>=0 A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T * OpA=2 => op(A) = A^H X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixmv(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Complex */ ae_vector* x, ae_int_t ix, /* Complex */ ae_vector* y, ae_int_t iy, ae_state *_state) { ae_int_t i; ae_complex v; if( m==0 ) { return; } if( n==0 ) { for(i=0; i<=m-1; i++) { y->ptr.p_complex[iy+i] = ae_complex_from_i(0); } return; } if( cmatrixmvf(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) { return; } if( opa==0 ) { /* * y = A*x */ for(i=0; i<=m-1; i++) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &x->ptr.p_complex[ix], 1, "N", ae_v_len(ja,ja+n-1)); y->ptr.p_complex[iy+i] = v; } return; } if( opa==1 ) { /* * y = A^T*x */ for(i=0; i<=m-1; i++) { y->ptr.p_complex[iy+i] = ae_complex_from_i(0); } for(i=0; i<=n-1; i++) { v = x->ptr.p_complex[ix+i]; ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(iy,iy+m-1), v); } return; } if( opa==2 ) { /* * y = A^H*x */ for(i=0; i<=m-1; i++) { y->ptr.p_complex[iy+i] = ae_complex_from_i(0); } for(i=0; i<=n-1; i++) { v = x->ptr.p_complex[ix+i]; ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "Conj", ae_v_len(iy,iy+m-1), v); } return; } } /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) N - number of columns of op(A) A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixmv(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Real */ ae_vector* x, ae_int_t ix, /* Real */ ae_vector* y, ae_int_t iy, ae_state *_state) { ae_int_t i; double v; if( m==0 ) { return; } if( n==0 ) { for(i=0; i<=m-1; i++) { y->ptr.p_double[iy+i] = (double)(0); } return; } if( rmatrixmvf(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) { return; } if( opa==0 ) { /* * y = A*x */ for(i=0; i<=m-1; i++) { v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &x->ptr.p_double[ix], 1, ae_v_len(ja,ja+n-1)); y->ptr.p_double[iy+i] = v; } return; } if( opa==1 ) { /* * y = A^T*x */ for(i=0; i<=m-1; i++) { y->ptr.p_double[iy+i] = (double)(0); } for(i=0; i<=n-1; i++) { v = x->ptr.p_double[ix+i]; ae_v_addd(&y->ptr.p_double[iy], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(iy,iy+m-1), v); } return; } } /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablascomplexblocksize(a, _state); /* * Basecase: either MKL-supported code or ALGLIB basecase code */ if( cmatrixrighttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } if( m<=bs&&n<=bs ) { ablas_cmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } /* * Recursive subdivision */ if( m>=n ) { /* * Split X: X*A = (X1 X2)^T*A */ ablascomplexsplitlength(a, m, &s1, &s2, _state); cmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } else { /* * Split A: * (A1 A12) * X*op(A) = X*op( ) * ( A2) * * Different variants depending on * IsUpper/OpType combinations */ ablascomplexsplitlength(a, n, &s1, &s2, _state); if( isupper&&optype==0 ) { /* * (A1 A12)-1 * X*A^-1 = (X1 X2)*( ) * ( A2) */ cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1, j1+s1, 0, ae_complex_from_d(1.0), x, i2, j2+s1, _state); cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); return; } if( isupper&&optype!=0 ) { /* * (A1' )-1 * X*A^-1 = (X1 X2)*( ) * (A12' A2') */ cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1, j1+s1, optype, ae_complex_from_d(1.0), x, i2, j2, _state); cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( !isupper&&optype==0 ) { /* * (A1 )-1 * X*A^-1 = (X1 X2)*( ) * (A21 A2) */ cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1+s1, j1, 0, ae_complex_from_d(1.0), x, i2, j2, _state); cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( !isupper&&optype!=0 ) { /* * (A1' A21')-1 * X*A^-1 = (X1 X2)*( ) * ( A2') */ cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1+s1, j1, optype, ae_complex_from_d(1.0), x, i2, j2+s1, _state); cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { cmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); } /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablascomplexblocksize(a, _state); /* * Basecase: either MKL-supported code or ALGLIB basecase code */ if( cmatrixlefttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } if( m<=bs&&n<=bs ) { ablas_cmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } /* * Recursive subdivision */ if( n>=m ) { /* * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) */ ablascomplexsplitlength(x, n, &s1, &s2, _state); cmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); return; } else { /* * Split A */ ablascomplexsplitlength(a, m, &s1, &s2, _state); if( isupper&&optype==0 ) { /* * (A1 A12)-1 ( X1 ) * A^-1*X* = ( ) *( ) * ( A2) ( X2 ) */ cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1, j1+s1, 0, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( isupper&&optype!=0 ) { /* * (A1' )-1 ( X1 ) * A^-1*X = ( ) *( ) * (A12' A2') ( X2 ) */ cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1, j1+s1, optype, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } if( !isupper&&optype==0 ) { /* * (A1 )-1 ( X1 ) * A^-1*X = ( ) *( ) * (A21 A2) ( X2 ) */ cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1+s1, j1, 0, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } if( !isupper&&optype!=0 ) { /* * (A1' A21')-1 ( X1 ) * A^-1*X = ( ) *( ) * ( A2') ( X2 ) */ cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1+s1, j1, optype, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { cmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); } /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablasblocksize(a, _state); /* * Basecase: MKL or ALGLIB code */ if( rmatrixrighttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } if( m<=bs&&n<=bs ) { ablas_rmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } /* * Recursive subdivision */ if( m>=n ) { /* * Split X: X*A = (X1 X2)^T*A */ ablassplitlength(a, m, &s1, &s2, _state); rmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } else { /* * Split A: * (A1 A12) * X*op(A) = X*op( ) * ( A2) * * Different variants depending on * IsUpper/OpType combinations */ ablassplitlength(a, n, &s1, &s2, _state); if( isupper&&optype==0 ) { /* * (A1 A12)-1 * X*A^-1 = (X1 X2)*( ) * ( A2) */ rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1, j1+s1, 0, 1.0, x, i2, j2+s1, _state); rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); return; } if( isupper&&optype!=0 ) { /* * (A1' )-1 * X*A^-1 = (X1 X2)*( ) * (A12' A2') */ rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1, j1+s1, optype, 1.0, x, i2, j2, _state); rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( !isupper&&optype==0 ) { /* * (A1 )-1 * X*A^-1 = (X1 X2)*( ) * (A21 A2) */ rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1+s1, j1, 0, 1.0, x, i2, j2, _state); rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( !isupper&&optype!=0 ) { /* * (A1' A21')-1 * X*A^-1 = (X1 X2)*( ) * ( A2') */ rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1+s1, j1, optype, 1.0, x, i2, j2+s1, _state); rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { rmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); } /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablasblocksize(a, _state); /* * Basecase: MKL or ALGLIB code */ if( rmatrixlefttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } if( m<=bs&&n<=bs ) { ablas_rmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } /* * Recursive subdivision */ if( n>=m ) { /* * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) */ ablassplitlength(x, n, &s1, &s2, _state); rmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); } else { /* * Split A */ ablassplitlength(a, m, &s1, &s2, _state); if( isupper&&optype==0 ) { /* * (A1 A12)-1 ( X1 ) * A^-1*X* = ( ) *( ) * ( A2) ( X2 ) */ rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); rmatrixgemm(s1, n, s2, -1.0, a, i1, j1+s1, 0, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } if( isupper&&optype!=0 ) { /* * (A1' )-1 ( X1 ) * A^-1*X = ( ) *( ) * (A12' A2') ( X2 ) */ rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixgemm(s2, n, s1, -1.0, a, i1, j1+s1, optype, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } if( !isupper&&optype==0 ) { /* * (A1 )-1 ( X1 ) * A^-1*X = ( ) *( ) * (A21 A2) ( X2 ) */ rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); rmatrixgemm(s2, n, s1, -1.0, a, i1+s1, j1, 0, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); return; } if( !isupper&&optype!=0 ) { /* * (A1' A21')-1 ( X1 ) * A^-1*X = ( ) *( ) * ( A2') ( X2 ) */ rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); rmatrixgemm(s1, n, s2, -1.0, a, i1+s1, j1, optype, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { rmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); } /************************************************************************* This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C where: * C is NxN Hermitian matrix given by its upper/lower triangle * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^H is calculated * 2 - A^H*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether upper or lower triangle of C is updated; this function updates only one half of C, leaving other half unchanged (not referenced at all). -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixherk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablascomplexblocksize(a, _state); /* * Use MKL or ALGLIB basecase code */ if( cmatrixherkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) { return; } if( n<=bs&&k<=bs ) { ablas_cmatrixherk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); return; } /* * Recursive division of the problem */ if( k>=n ) { /* * Split K */ ablascomplexsplitlength(a, k, &s1, &s2, _state); if( optypea==0 ) { cmatrixherk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixherk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); } else { cmatrixherk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixherk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); } } else { /* * Split N */ ablascomplexsplitlength(a, n, &s1, &s2, _state); if( optypea==0&&isupper ) { cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 0, a, ia+s1, ja, 2, ae_complex_from_d(beta), c, ic, jc+s1, _state); cmatrixherk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea==0&&!isupper ) { cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia+s1, ja, 0, a, ia, ja, 2, ae_complex_from_d(beta), c, ic+s1, jc, _state); cmatrixherk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea!=0&&isupper ) { cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 2, a, ia, ja+s1, 0, ae_complex_from_d(beta), c, ic, jc+s1, _state); cmatrixherk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea!=0&&!isupper ) { cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia, ja+s1, 2, a, ia, ja, 0, ae_complex_from_d(beta), c, ic+s1, jc, _state); cmatrixherk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixherk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { cmatrixherk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state); } /************************************************************************* This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C where: * C is NxN symmetric matrix given by its upper/lower triangle * A is NxK matrix when A*A^T is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^T is calculated * 2 - A^T*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether C is upper triangular or lower triangular -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablasblocksize(a, _state); /* * Use MKL or generic basecase code */ if( rmatrixsyrkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) { return; } if( n<=bs&&k<=bs ) { ablas_rmatrixsyrk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); return; } /* * Recursive subdivision of the problem */ if( k>=n ) { /* * Split K */ ablassplitlength(a, k, &s1, &s2, _state); if( optypea==0 ) { rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixsyrk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); } else { rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixsyrk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); } } else { /* * Split N */ ablassplitlength(a, n, &s1, &s2, _state); if( optypea==0&&isupper ) { rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 0, a, ia+s1, ja, 1, beta, c, ic, jc+s1, _state); rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea==0&&!isupper ) { rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixgemm(s2, s1, k, alpha, a, ia+s1, ja, 0, a, ia, ja, 1, beta, c, ic+s1, jc, _state); rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea!=0&&isupper ) { rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 1, a, ia, ja+s1, 0, beta, c, ic, jc+s1, _state); rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } if( optypea!=0&&!isupper ) { rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); rmatrixgemm(s2, s1, k, alpha, a, ia, ja+s1, 1, a, ia, ja, 0, beta, c, ic+s1, jc, _state); rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); return; } } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { rmatrixsyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state); } /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition, conjugate transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition Beta - coefficient C - matrix (PREALLOCATED, large enough to store result) IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablascomplexblocksize(a, _state); /* * Use MKL or ALGLIB basecase code */ if( cmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) { return; } if( (m<=bs&&n<=bs)&&k<=bs ) { cmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); return; } /* * SMP support is turned on when M or N are larger than some boundary value. * Magnitude of K is not taken into account because splitting on K does not * allow us to spawn child tasks. */ /* * Recursive algorithm: parallel splitting on M/N */ if( m>=n&&m>=k ) { /* * A*B = (A1 A2)^T*B */ ablascomplexsplitlength(a, m, &s1, &s2, _state); cmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); if( optypea==0 ) { cmatrixgemm(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); } else { cmatrixgemm(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); } return; } if( n>=m&&n>=k ) { /* * A*B = A*(B1 B2) */ ablascomplexsplitlength(a, n, &s1, &s2, _state); if( optypeb==0 ) { cmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); } else { cmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); } return; } /* * Recursive algorithm: serial splitting on K */ /* * A*B = (A1 A2)*(B1 B2)^T */ ablascomplexsplitlength(a, k, &s1, &s2, _state); if( optypea==0&&optypeb==0 ) { cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); } if( optypea==0&&optypeb!=0 ) { cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); } if( optypea!=0&&optypeb==0 ) { cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); } if( optypea!=0&&optypeb!=0 ) { cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); cmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); } return; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { cmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state); } /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition Beta - coefficient C - PREALLOCATED output matrix, large enough to store result IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 2009-2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t s1; ae_int_t s2; ae_int_t bs; bs = ablasblocksize(a, _state); /* * Check input sizes for correctness */ ae_assert(optypea==0||optypea==1, "RMatrixGEMM: incorrect OpTypeA (must be 0 or 1)", _state); ae_assert(optypeb==0||optypeb==1, "RMatrixGEMM: incorrect OpTypeB (must be 0 or 1)", _state); ae_assert(ic+m<=c->rows, "RMatrixGEMM: incorect size of output matrix C", _state); ae_assert(jc+n<=c->cols, "RMatrixGEMM: incorect size of output matrix C", _state); /* * Use MKL or ALGLIB basecase code */ if( rmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) { return; } if( (m<=bs&&n<=bs)&&k<=bs ) { rmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); return; } /* * SMP support is turned on when M or N are larger than some boundary value. * Magnitude of K is not taken into account because splitting on K does not * allow us to spawn child tasks. */ /* * Recursive algorithm: split on M or N */ if( m>=n&&m>=k ) { /* * A*B = (A1 A2)^T*B */ ablassplitlength(a, m, &s1, &s2, _state); if( optypea==0 ) { rmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); } else { rmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); } return; } if( n>=m&&n>=k ) { /* * A*B = A*(B1 B2) */ ablassplitlength(a, n, &s1, &s2, _state); if( optypeb==0 ) { rmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); } else { rmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); } return; } /* * Recursive algorithm: split on K */ /* * A*B = (A1 A2)*(B1 B2)^T */ ablassplitlength(a, k, &s1, &s2, _state); if( optypea==0&&optypeb==0 ) { rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); } if( optypea==0&&optypeb!=0 ) { rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); } if( optypea!=0&&optypeb==0 ) { rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); } if( optypea!=0&&optypeb!=0 ) { rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); rmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); } return; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { rmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state); } /************************************************************************* This subroutine is an older version of CMatrixHERK(), one with wrong name (it is HErmitian update, not SYmmetric). It is left here for backward compatibility. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { cmatrixherk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { cmatrixsyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state); } /************************************************************************* Complex ABLASSplitLength -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void ablas_ablasinternalsplitlength(ae_int_t n, ae_int_t nb, ae_int_t* n1, ae_int_t* n2, ae_state *_state) { ae_int_t r; *n1 = 0; *n2 = 0; if( n<=nb ) { /* * Block size, no further splitting */ *n1 = n; *n2 = 0; } else { /* * Greater than block size */ if( n%nb!=0 ) { /* * Split remainder */ *n2 = n%nb; *n1 = n-(*n2); } else { /* * Split on block boundaries */ *n2 = n/2; *n1 = n-(*n2); if( *n1%nb==0 ) { return; } r = nb-*n1%nb; *n1 = *n1+r; *n2 = *n2-r; } } } /************************************************************************* Level 2 variant of CMatrixRightTRSM *************************************************************************/ static void ablas_cmatrixrighttrsm2(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex vc; ae_complex vd; /* * Special case */ if( n*m==0 ) { return; } /* * Try to call fast TRSM */ if( cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } /* * General case */ if( isupper ) { /* * Upper triangular matrix */ if( optype==0 ) { /* * X*A^(-1) */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = a->ptr.pp_complex[i1+j][j1+j]; } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); if( jptr.pp_complex[i2+i][j2+j]; ae_v_csubc(&x->ptr.pp_complex[i2+i][j2+j+1], 1, &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1), vc); } } } return; } if( optype==1 ) { /* * X*A^(-T) */ for(i=0; i<=m-1; i++) { for(j=n-1; j>=0; j--) { vc = ae_complex_from_i(0); vd = ae_complex_from_i(1); if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1)); } if( !isunit ) { vd = a->ptr.pp_complex[i1+j][j1+j]; } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); } } return; } if( optype==2 ) { /* * X*A^(-H) */ for(i=0; i<=m-1; i++) { for(j=n-1; j>=0; j--) { vc = ae_complex_from_i(0); vd = ae_complex_from_i(1); if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "Conj", ae_v_len(j2+j+1,j2+n-1)); } if( !isunit ) { vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); } } return; } } else { /* * Lower triangular matrix */ if( optype==0 ) { /* * X*A^(-1) */ for(i=0; i<=m-1; i++) { for(j=n-1; j>=0; j--) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = a->ptr.pp_complex[i1+j][j1+j]; } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); if( j>0 ) { vc = x->ptr.pp_complex[i2+i][j2+j]; ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1), vc); } } } return; } if( optype==1 ) { /* * X*A^(-T) */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { vc = ae_complex_from_i(0); vd = ae_complex_from_i(1); if( j>0 ) { vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1)); } if( !isunit ) { vd = a->ptr.pp_complex[i1+j][j1+j]; } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); } } return; } if( optype==2 ) { /* * X*A^(-H) */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { vc = ae_complex_from_i(0); vd = ae_complex_from_i(1); if( j>0 ) { vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "Conj", ae_v_len(j2,j2+j-1)); } if( !isunit ) { vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); } x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); } } return; } } } /************************************************************************* Level-2 subroutine *************************************************************************/ static void ablas_cmatrixlefttrsm2(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex vc; ae_complex vd; /* * Special case */ if( n*m==0 ) { return; } /* * Try to call fast TRSM */ if( cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } /* * General case */ if( isupper ) { /* * Upper triangular matrix */ if( optype==0 ) { /* * A^(-1)*X */ for(i=m-1; i>=0; i--) { for(j=i+1; j<=m-1; j++) { vc = a->ptr.pp_complex[i1+i][j1+j]; ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } if( !isunit ) { vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); } } return; } if( optype==1 ) { /* * A^(-T)*X */ for(i=0; i<=m-1; i++) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); } ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i+1; j<=m-1; j++) { vc = a->ptr.pp_complex[i1+i][j1+j]; ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } } return; } if( optype==2 ) { /* * A^(-H)*X */ for(i=0; i<=m-1; i++) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = ae_c_d_div(1,ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); } ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i+1; j<=m-1; j++) { vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } } return; } } else { /* * Lower triangular matrix */ if( optype==0 ) { /* * A^(-1)*X */ for(i=0; i<=m-1; i++) { for(j=0; j<=i-1; j++) { vc = a->ptr.pp_complex[i1+i][j1+j]; ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } if( isunit ) { vd = ae_complex_from_i(1); } else { vd = ae_c_d_div(1,a->ptr.pp_complex[i1+j][j1+j]); } ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); } return; } if( optype==1 ) { /* * A^(-T)*X */ for(i=m-1; i>=0; i--) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); } ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i-1; j>=0; j--) { vc = a->ptr.pp_complex[i1+i][j1+j]; ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } } return; } if( optype==2 ) { /* * A^(-H)*X */ for(i=m-1; i>=0; i--) { if( isunit ) { vd = ae_complex_from_i(1); } else { vd = ae_c_d_div(1,ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); } ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i-1; j>=0; j--) { vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); } } return; } } } /************************************************************************* Level 2 subroutine -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void ablas_rmatrixrighttrsm2(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t i; ae_int_t j; double vr; double vd; /* * Special case */ if( n*m==0 ) { return; } /* * Try to use "fast" code */ if( rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } /* * General case */ if( isupper ) { /* * Upper triangular matrix */ if( optype==0 ) { /* * X*A^(-1) */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( isunit ) { vd = (double)(1); } else { vd = a->ptr.pp_double[i1+j][j1+j]; } x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; if( jptr.pp_double[i2+i][j2+j]; ae_v_subd(&x->ptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1), vr); } } } return; } if( optype==1 ) { /* * X*A^(-T) */ for(i=0; i<=m-1; i++) { for(j=n-1; j>=0; j--) { vr = (double)(0); vd = (double)(1); if( jptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1)); } if( !isunit ) { vd = a->ptr.pp_double[i1+j][j1+j]; } x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; } } return; } } else { /* * Lower triangular matrix */ if( optype==0 ) { /* * X*A^(-1) */ for(i=0; i<=m-1; i++) { for(j=n-1; j>=0; j--) { if( isunit ) { vd = (double)(1); } else { vd = a->ptr.pp_double[i1+j][j1+j]; } x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; if( j>0 ) { vr = x->ptr.pp_double[i2+i][j2+j]; ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1), vr); } } } return; } if( optype==1 ) { /* * X*A^(-T) */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { vr = (double)(0); vd = (double)(1); if( j>0 ) { vr = ae_v_dotproduct(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1)); } if( !isunit ) { vd = a->ptr.pp_double[i1+j][j1+j]; } x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; } } return; } } } /************************************************************************* Level 2 subroutine *************************************************************************/ static void ablas_rmatrixlefttrsm2(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_int_t i; ae_int_t j; double vr; double vd; /* * Special case */ if( n==0||m==0 ) { return; } /* * Try fast code */ if( rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) { return; } /* * General case */ if( isupper ) { /* * Upper triangular matrix */ if( optype==0 ) { /* * A^(-1)*X */ for(i=m-1; i>=0; i--) { for(j=i+1; j<=m-1; j++) { vr = a->ptr.pp_double[i1+i][j1+j]; ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); } if( !isunit ) { vd = 1/a->ptr.pp_double[i1+i][j1+i]; ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); } } return; } if( optype==1 ) { /* * A^(-T)*X */ for(i=0; i<=m-1; i++) { if( isunit ) { vd = (double)(1); } else { vd = 1/a->ptr.pp_double[i1+i][j1+i]; } ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i+1; j<=m-1; j++) { vr = a->ptr.pp_double[i1+i][j1+j]; ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); } } return; } } else { /* * Lower triangular matrix */ if( optype==0 ) { /* * A^(-1)*X */ for(i=0; i<=m-1; i++) { for(j=0; j<=i-1; j++) { vr = a->ptr.pp_double[i1+i][j1+j]; ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); } if( isunit ) { vd = (double)(1); } else { vd = 1/a->ptr.pp_double[i1+j][j1+j]; } ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); } return; } if( optype==1 ) { /* * A^(-T)*X */ for(i=m-1; i>=0; i--) { if( isunit ) { vd = (double)(1); } else { vd = 1/a->ptr.pp_double[i1+i][j1+i]; } ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); for(j=i-1; j>=0; j--) { vr = a->ptr.pp_double[i1+i][j1+j]; ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); } } return; } } } /************************************************************************* Level 2 subroutine *************************************************************************/ static void ablas_cmatrixherk2(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_complex v; /* * Fast exit (nothing to be done) */ if( (ae_fp_eq(alpha,(double)(0))||k==0)&&ae_fp_eq(beta,(double)(1)) ) { return; } /* * Try to call fast SYRK */ if( cmatrixherkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) { return; } /* * SYRK */ if( optypea==0 ) { /* * C=alpha*A*A^H+beta*C */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( ae_fp_neq(alpha,(double)(0))&&k>0 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &a->ptr.pp_complex[ia+j][ja], 1, "Conj", ae_v_len(ja,ja+k-1)); } else { v = ae_complex_from_i(0); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul_d(v,alpha); } else { c->ptr.pp_complex[ic+i][jc+j] = ae_c_add(ae_c_mul_d(c->ptr.pp_complex[ic+i][jc+j],beta),ae_c_mul_d(v,alpha)); } } } return; } else { /* * C=alpha*A^H*A+beta*C */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } if( ae_fp_eq(beta,(double)(0)) ) { for(j=j1; j<=j2; j++) { c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_i(0); } } else { ae_v_cmuld(&c->ptr.pp_complex[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); } } for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { if( isupper ) { j1 = j; j2 = n-1; } else { j1 = 0; j2 = j; } v = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[ia+i][ja+j], _state),alpha); ae_v_caddc(&c->ptr.pp_complex[ic+j][jc+j1], 1, &a->ptr.pp_complex[ia+i][ja+j1], 1, "N", ae_v_len(jc+j1,jc+j2), v); } } return; } } /************************************************************************* Level 2 subrotuine *************************************************************************/ static void ablas_rmatrixsyrk2(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; double v; /* * Fast exit (nothing to be done) */ if( (ae_fp_eq(alpha,(double)(0))||k==0)&&ae_fp_eq(beta,(double)(1)) ) { return; } /* * Try to call fast SYRK */ if( rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) { return; } /* * SYRK */ if( optypea==0 ) { /* * C=alpha*A*A^H+beta*C */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( ae_fp_neq(alpha,(double)(0))&&k>0 ) { v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &a->ptr.pp_double[ia+j][ja], 1, ae_v_len(ja,ja+k-1)); } else { v = (double)(0); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+i][jc+j] = alpha*v; } else { c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]+alpha*v; } } } return; } else { /* * C=alpha*A^H*A+beta*C */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } if( ae_fp_eq(beta,(double)(0)) ) { for(j=j1; j<=j2; j++) { c->ptr.pp_double[ic+i][jc+j] = (double)(0); } } else { ae_v_muld(&c->ptr.pp_double[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); } } for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { if( isupper ) { j1 = j; j2 = n-1; } else { j1 = 0; j2 = j; } v = alpha*a->ptr.pp_double[ia+i][ja+j]; ae_v_addd(&c->ptr.pp_double[ic+j][jc+j1], 1, &a->ptr.pp_double[ia+i][ja+j1], 1, ae_v_len(jc+j1,jc+j2), v); } } return; } } /************************************************************************* QR decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. The elements of matrix R are located on and above the main diagonal of matrix A. The elements which are located in Tau array and below the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(k-1), where k = min(m,n), and each H(i) is in the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t rowscount; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&taubuf, 0, DT_REAL, _state); ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } minmn = ae_minint(m, n, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(tau, minmn, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, m, ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, 2*ablasblocksize(a, _state), n, _state); /* * Blocked code */ blockstart = 0; while(blockstart!=minmn) { /* * Determine block size */ blocksize = minmn-blockstart; if( blocksize>ablasblocksize(a, _state) ) { blocksize = ablasblocksize(a, _state); } rowscount = m-blockstart; /* * QR decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); rmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); rmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); /* * Update the rest, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( blockstart+blocksize<=n-1 ) { if( n-blockstart-blocksize>=2*ablasblocksize(a, _state)||rowscount>=4*ablasblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q'. * * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' */ rmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, 1.0, &tmpa, 0, 0, 1, a, blockstart, blockstart+blocksize, 0, 0.0, &tmpr, 0, 0, _state); rmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, 1.0, &tmpt, 0, 0, 1, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); rmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, a, blockstart, blockstart+blocksize, _state); } else { /* * Level 2 algorithm */ for(i=0; i<=blocksize-1; i++) { ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); t.ptr.p_double[1] = (double)(1); applyreflectionfromtheleft(a, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart+blocksize; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixqr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { rmatrixqr(a,m,n,tau, _state); } /************************************************************************* LQ decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices L and Q in compact form (see below) Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..Min(M,N)-1]. Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. The elements of matrix L are located on and below the main diagonal of matrix A. The elements which are located in Tau array and above the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(k-1)*H(k-2)*...*H(1)*H(0), where k = min(m,n), and each H(i) is of the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t columnscount; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&taubuf, 0, DT_REAL, _state); ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } minmn = ae_minint(m, n, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(tau, minmn, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, ablasblocksize(a, _state), n, _state); ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, m, 2*ablasblocksize(a, _state), _state); /* * Blocked code */ blockstart = 0; while(blockstart!=minmn) { /* * Determine block size */ blocksize = minmn-blockstart; if( blocksize>ablasblocksize(a, _state) ) { blocksize = ablasblocksize(a, _state); } columnscount = n-blockstart; /* * LQ decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); rmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); rmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); /* * Update the rest, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( blockstart+blocksize<=m-1 ) { if( m-blockstart-blocksize>=2*ablasblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q. * * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA */ rmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, 1.0, a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); rmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, 0.0, &tmpr, 0, blocksize, _state); rmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, a, blockstart+blocksize, blockstart, _state); } else { /* * Level 2 algorithm */ for(i=0; i<=blocksize-1; i++) { ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); t.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(a, taubuf.ptr.p_double[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart+blocksize; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { rmatrixlq(a,m,n,tau, _state); } /************************************************************************* QR decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixqr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t rowscount; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_init(&work, 0, DT_COMPLEX, _state); ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&taubuf, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } minmn = ae_minint(m, n, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(tau, minmn, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, m, ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, 2*ablascomplexblocksize(a, _state), n, _state); /* * Blocked code */ blockstart = 0; while(blockstart!=minmn) { /* * Determine block size */ blocksize = minmn-blockstart; if( blocksize>ablascomplexblocksize(a, _state) ) { blocksize = ablascomplexblocksize(a, _state); } rowscount = m-blockstart; /* * QR decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); ortfac_cmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); cmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); /* * Update the rest, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( blockstart+blocksize<=n-1 ) { if( n-blockstart-blocksize>=2*ablascomplexblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q'. * * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' */ cmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, a, blockstart, blockstart+blocksize, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); cmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 2, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); cmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), a, blockstart, blockstart+blocksize, _state); } else { /* * Level 2 algorithm */ for(i=0; i<=blocksize-1; i++) { ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); t.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(a, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart+blocksize; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixqr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state) { cmatrixqr(a,m,n,tau, _state); } /************************************************************************* LQ decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and L in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixlq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t columnscount; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_init(&work, 0, DT_COMPLEX, _state); ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&taubuf, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } minmn = ae_minint(m, n, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(tau, minmn, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, ablascomplexblocksize(a, _state), n, _state); ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, m, 2*ablascomplexblocksize(a, _state), _state); /* * Blocked code */ blockstart = 0; while(blockstart!=minmn) { /* * Determine block size */ blocksize = minmn-blockstart; if( blocksize>ablascomplexblocksize(a, _state) ) { blocksize = ablascomplexblocksize(a, _state); } columnscount = n-blockstart; /* * LQ decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); ortfac_cmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); cmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); /* * Update the rest, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( blockstart+blocksize<=m-1 ) { if( m-blockstart-blocksize>=2*ablascomplexblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q. * * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA */ cmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); cmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); cmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, _state); } else { /* * Level 2 algorithm */ for(i=0; i<=blocksize-1; i++) { ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); t.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheright(a, taubuf.ptr.p_complex[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart+blocksize; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state) { cmatrixlq(a,m,n,tau, _state); } /************************************************************************* Partial unpacking of matrix Q from the QR decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixQR subroutine. QColumns - required number of columns of matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose indexes range within [0..M-1, 0..QColumns-1]. If QColumns=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_int_t refcnt; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t rowscount; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&taubuf, 0, DT_REAL, _state); ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state); ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); if( (m<=0||n<=0)||qcolumns<=0 ) { ae_frame_leave(_state); return; } /* * init */ minmn = ae_minint(m, n, _state); refcnt = ae_minint(minmn, qcolumns, _state); ae_matrix_set_length(q, m, qcolumns, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=qcolumns-1; j++) { if( i==j ) { q->ptr.pp_double[i][j] = (double)(1); } else { q->ptr.pp_double[i][j] = (double)(0); } } } ae_vector_set_length(&work, ae_maxint(m, qcolumns, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, qcolumns, _state)+1, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, m, ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, 2*ablasblocksize(a, _state), qcolumns, _state); /* * Blocked code */ blockstart = ablasblocksize(a, _state)*(refcnt/ablasblocksize(a, _state)); blocksize = refcnt-blockstart; while(blockstart>=0) { rowscount = m-blockstart; if( blocksize>0 ) { /* * Copy current block */ rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); /* * Update, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( qcolumns>=2*ablasblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); /* * Multiply matrix by Q. * * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' */ rmatrixgemm(blocksize, qcolumns, rowscount, 1.0, &tmpa, 0, 0, 1, q, blockstart, 0, 0, 0.0, &tmpr, 0, 0, _state); rmatrixgemm(blocksize, qcolumns, blocksize, 1.0, &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); rmatrixgemm(rowscount, qcolumns, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, q, blockstart, 0, _state); } else { /* * Level 2 algorithm */ for(i=blocksize-1; i>=0; i--) { ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); t.ptr.p_double[1] = (double)(1); applyreflectionfromtheleft(q, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); } } } /* * Advance */ blockstart = blockstart-ablasblocksize(a, _state); blocksize = ablasblocksize(a, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixqrunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state) { rmatrixqrunpackq(a,m,n,tau,qcolumns,q, _state); } /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* r, ae_state *_state) { ae_int_t i; ae_int_t k; ae_matrix_clear(r); if( m<=0||n<=0 ) { return; } k = ae_minint(m, n, _state); ae_matrix_set_length(r, m, n, _state); for(i=0; i<=n-1; i++) { r->ptr.pp_double[0][i] = (double)(0); } for(i=1; i<=m-1; i++) { ae_v_move(&r->ptr.pp_double[i][0], 1, &r->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); } for(i=0; i<=k-1; i++) { ae_v_move(&r->ptr.pp_double[i][i], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); } } /************************************************************************* Partial unpacking of matrix Q from the LQ decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices L and Q in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixLQ subroutine. QRows - required number of rows in matrix Q. N>=QRows>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose indexes range within [0..QRows-1, 0..N-1]. If QRows=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qrows, /* Real */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_int_t refcnt; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t columnscount; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&taubuf, 0, DT_REAL, _state); ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state); ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state); ae_assert(qrows<=n, "RMatrixLQUnpackQ: QRows>N!", _state); if( (m<=0||n<=0)||qrows<=0 ) { ae_frame_leave(_state); return; } /* * init */ minmn = ae_minint(m, n, _state); refcnt = ae_minint(minmn, qrows, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, ablasblocksize(a, _state), n, _state); ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, qrows, 2*ablasblocksize(a, _state), _state); ae_matrix_set_length(q, qrows, n, _state); for(i=0; i<=qrows-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { q->ptr.pp_double[i][j] = (double)(1); } else { q->ptr.pp_double[i][j] = (double)(0); } } } /* * Blocked code */ blockstart = ablasblocksize(a, _state)*(refcnt/ablasblocksize(a, _state)); blocksize = refcnt-blockstart; while(blockstart>=0) { columnscount = n-blockstart; if( blocksize>0 ) { /* * Copy submatrix */ rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); /* * Update matrix, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( qrows>=2*ablasblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q'. * * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA */ rmatrixgemm(qrows, blocksize, columnscount, 1.0, q, 0, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); rmatrixgemm(qrows, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 1, 0.0, &tmpr, 0, blocksize, _state); rmatrixgemm(qrows, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, q, 0, blockstart, _state); } else { /* * Level 2 algorithm */ for(i=blocksize-1; i>=0; i--) { ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); t.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(q, taubuf.ptr.p_double[i], &t, 0, qrows-1, blockstart+i, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart-ablasblocksize(a, _state); blocksize = ablasblocksize(a, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlqunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qrows, /* Real */ ae_matrix* q, ae_state *_state) { rmatrixlqunpackq(a,m,n,tau,qrows,q, _state); } /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackl(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* l, ae_state *_state) { ae_int_t i; ae_int_t k; ae_matrix_clear(l); if( m<=0||n<=0 ) { return; } ae_matrix_set_length(l, m, n, _state); for(i=0; i<=n-1; i++) { l->ptr.pp_double[0][i] = (double)(0); } for(i=1; i<=m-1; i++) { ae_v_move(&l->ptr.pp_double[i][0], 1, &l->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); } for(i=0; i<=m-1; i++) { k = ae_minint(i, n-1, _state); ae_v_move(&l->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k)); } } /************************************************************************* Partial unpacking of matrix Q from QR decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixQR subroutine . QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose index ranges within [0..M-1, 0..QColumns-1]. If QColumns=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qcolumns, /* Complex */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_int_t refcnt; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t rowscount; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&work, 0, DT_COMPLEX, _state); ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&taubuf, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state); ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } /* * init */ minmn = ae_minint(m, n, _state); refcnt = ae_minint(minmn, qcolumns, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, m, ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, 2*ablascomplexblocksize(a, _state), qcolumns, _state); ae_matrix_set_length(q, m, qcolumns, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=qcolumns-1; j++) { if( i==j ) { q->ptr.pp_complex[i][j] = ae_complex_from_i(1); } else { q->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } /* * Blocked code */ blockstart = ablascomplexblocksize(a, _state)*(refcnt/ablascomplexblocksize(a, _state)); blocksize = refcnt-blockstart; while(blockstart>=0) { rowscount = m-blockstart; if( blocksize>0 ) { /* * QR decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); /* * Update matrix, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( qcolumns>=2*ablascomplexblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q. * * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' */ cmatrixgemm(blocksize, qcolumns, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, q, blockstart, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); cmatrixgemm(blocksize, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); cmatrixgemm(rowscount, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), q, blockstart, 0, _state); } else { /* * Level 2 algorithm */ for(i=blocksize-1; i>=0; i--) { ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); t.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(q, taubuf.ptr.p_complex[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); } } } /* * Advance */ blockstart = blockstart-ablascomplexblocksize(a, _state); blocksize = ablascomplexblocksize(a, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixqrunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qcolumns, /* Complex */ ae_matrix* q, ae_state *_state) { cmatrixqrunpackq(a,m,n,tau,qcolumns,q, _state); } /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* r, ae_state *_state) { ae_int_t i; ae_int_t k; ae_matrix_clear(r); if( m<=0||n<=0 ) { return; } k = ae_minint(m, n, _state); ae_matrix_set_length(r, m, n, _state); for(i=0; i<=n-1; i++) { r->ptr.pp_complex[0][i] = ae_complex_from_i(0); } for(i=1; i<=m-1; i++) { ae_v_cmove(&r->ptr.pp_complex[i][0], 1, &r->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); } for(i=0; i<=k-1; i++) { ae_v_cmove(&r->ptr.pp_complex[i][i], 1, &a->ptr.pp_complex[i][i], 1, "N", ae_v_len(i,n-1)); } } /************************************************************************* Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixLQ subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixLQ subroutine . QRows - required number of rows in matrix Q. N>=QColumns>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose index ranges within [0..QRows-1, 0..N-1]. If QRows=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qrows, /* Complex */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_vector taubuf; ae_int_t minmn; ae_int_t refcnt; ae_matrix tmpa; ae_matrix tmpt; ae_matrix tmpr; ae_int_t blockstart; ae_int_t blocksize; ae_int_t columnscount; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&work, 0, DT_COMPLEX, _state); ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&taubuf, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state); if( m<=0||n<=0 ) { ae_frame_leave(_state); return; } /* * Init */ minmn = ae_minint(m, n, _state); refcnt = ae_minint(minmn, qrows, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); ae_vector_set_length(&taubuf, minmn, _state); ae_matrix_set_length(&tmpa, ablascomplexblocksize(a, _state), n, _state); ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(&tmpr, qrows, 2*ablascomplexblocksize(a, _state), _state); ae_matrix_set_length(q, qrows, n, _state); for(i=0; i<=qrows-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { q->ptr.pp_complex[i][j] = ae_complex_from_i(1); } else { q->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } /* * Blocked code */ blockstart = ablascomplexblocksize(a, _state)*(refcnt/ablascomplexblocksize(a, _state)); blocksize = refcnt-blockstart; while(blockstart>=0) { columnscount = n-blockstart; if( blocksize>0 ) { /* * LQ decomposition of submatrix. * Matrix is copied to temporary storage to solve * some TLB issues arising from non-contiguous memory * access pattern. */ cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); /* * Update matrix, choose between: * a) Level 2 algorithm (when the rest of the matrix is small enough) * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY * representation for products of Householder transformations', * by R. Schreiber and C. Van Loan. */ if( qrows>=2*ablascomplexblocksize(a, _state) ) { /* * Prepare block reflector */ ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); /* * Multiply the rest of A by Q'. * * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA */ cmatrixgemm(qrows, blocksize, columnscount, ae_complex_from_d(1.0), q, 0, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); cmatrixgemm(qrows, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); cmatrixgemm(qrows, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), q, 0, blockstart, _state); } else { /* * Level 2 algorithm */ for(i=blocksize-1; i>=0; i--) { ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); t.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheright(q, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, 0, qrows-1, blockstart+i, n-1, &work, _state); } } } /* * Advance */ blockstart = blockstart-ablascomplexblocksize(a, _state); blocksize = ablascomplexblocksize(a, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlqunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qrows, /* Complex */ ae_matrix* q, ae_state *_state) { cmatrixlqunpackq(a,m,n,tau,qrows,q, _state); } /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of CMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackl(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* l, ae_state *_state) { ae_int_t i; ae_int_t k; ae_matrix_clear(l); if( m<=0||n<=0 ) { return; } ae_matrix_set_length(l, m, n, _state); for(i=0; i<=n-1; i++) { l->ptr.pp_complex[0][i] = ae_complex_from_i(0); } for(i=1; i<=m-1; i++) { ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &l->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); } for(i=0; i<=m-1; i++) { k = ae_minint(i, n-1, _state); ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,k)); } } /************************************************************************* Base case for real QR -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ void rmatrixqrbasecase(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* work, /* Real */ ae_vector* t, /* Real */ ae_vector* tau, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t minmn; double tmp; minmn = ae_minint(m, n, _state); /* * Test the input arguments */ k = minmn; for(i=0; i<=k-1; i++) { /* * Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); generatereflection(t, m-i, &tmp, _state); tau->ptr.p_double[i] = tmp; ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t->ptr.p_double[1], 1, ae_v_len(i,m-1)); t->ptr.p_double[1] = (double)(1); if( iptr.p_double[i], t, i, m-1, i+1, n-1, work, _state); } } } /************************************************************************* Base case for real LQ -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ void rmatrixlqbasecase(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* work, /* Real */ ae_vector* t, /* Real */ ae_vector* tau, ae_state *_state) { ae_int_t i; ae_int_t k; double tmp; k = ae_minint(m, n, _state); for(i=0; i<=k-1; i++) { /* * Generate elementary reflector H(i) to annihilate A(i,i+1:n-1) */ ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); generatereflection(t, n-i, &tmp, _state); tau->ptr.p_double[i] = tmp; ae_v_move(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[1], 1, ae_v_len(i,n-1)); t->ptr.p_double[1] = (double)(1); if( iptr.p_double[i], t, i+1, m-1, i, n-1, work, _state); } } } /************************************************************************* Reduction of a rectangular matrix to bidiagonal form The algorithm reduces the rectangular matrix A to bidiagonal form by orthogonal transformations P and Q: A = Q*B*(P^T). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function because ! bidiagonal decompostion is inherently sequential in nature. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - source matrix. array[0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q, B, P in compact form (see below). TauQ - scalar factors which are used to form matrix Q. TauP - scalar factors which are used to form matrix P. The main diagonal and one of the secondary diagonals of matrix A are replaced with bidiagonal matrix B. Other elements contain elementary reflections which form MxM matrix Q and NxN matrix P, respectively. If M>=N, B is the upper bidiagonal MxN matrix and is stored in the corresponding elements of matrix A. Matrix Q is represented as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i). Matrix P is as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). If M n): m=5, n=6 (m < n): ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) ( v1 v2 v3 v4 v5 ) Here vi and ui are vectors which form H(i) and G(i), and d and e - are the diagonal and off-diagonal elements of matrix B. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ void rmatrixbd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_vector t; ae_int_t maxmn; ae_int_t i; double ltau; ae_frame_make(_state, &_frame_block); ae_vector_clear(tauq); ae_vector_clear(taup); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); /* * Prepare */ if( n<=0||m<=0 ) { ae_frame_leave(_state); return; } maxmn = ae_maxint(m, n, _state); ae_vector_set_length(&work, maxmn+1, _state); ae_vector_set_length(&t, maxmn+1, _state); if( m>=n ) { ae_vector_set_length(tauq, n, _state); ae_vector_set_length(taup, n, _state); for(i=0; i<=n-1; i++) { tauq->ptr.p_double[i] = 0.0; taup->ptr.p_double[i] = 0.0; } } else { ae_vector_set_length(tauq, m, _state); ae_vector_set_length(taup, m, _state); for(i=0; i<=m-1; i++) { tauq->ptr.p_double[i] = 0.0; taup->ptr.p_double[i] = 0.0; } } /* * Try to use MKL code * * NOTE: buffers Work[] and T[] are used for temporary storage of diagonals; * because they are present in A[], we do not use them. */ if( rmatrixbdmkl(a, m, n, &work, &t, tauq, taup, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB code */ if( m>=n ) { /* * Reduce to upper bidiagonal form */ for(i=0; i<=n-1; i++) { /* * Generate elementary reflector H(i) to annihilate A(i+1:m-1,i) */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); generatereflection(&t, m-i, <au, _state); tauq->ptr.p_double[i] = ltau; ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i,m-1)); t.ptr.p_double[1] = (double)(1); /* * Apply H(i) to A(i:m-1,i+1:n-1) from the left */ applyreflectionfromtheleft(a, ltau, &t, i, m-1, i+1, n-1, &work, _state); if( iptr.pp_double[i][i+1], 1, ae_v_len(1,n-i-1)); generatereflection(&t, n-1-i, <au, _state); taup->ptr.p_double[i] = ltau; ae_v_move(&a->ptr.pp_double[i][i+1], 1, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); t.ptr.p_double[1] = (double)(1); /* * Apply G(i) to A(i+1:m-1,i+1:n-1) from the right */ applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); } else { taup->ptr.p_double[i] = (double)(0); } } } else { /* * Reduce to lower bidiagonal form */ for(i=0; i<=m-1; i++) { /* * Generate elementary reflector G(i) to annihilate A(i,i+1:n-1) */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); generatereflection(&t, n-i, <au, _state); taup->ptr.p_double[i] = ltau; ae_v_move(&a->ptr.pp_double[i][i], 1, &t.ptr.p_double[1], 1, ae_v_len(i,n-1)); t.ptr.p_double[1] = (double)(1); /* * Apply G(i) to A(i+1:m-1,i:n-1) from the right */ applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i, n-1, &work, _state); if( iptr.pp_double[i+1][i], a->stride, ae_v_len(1,m-1-i)); generatereflection(&t, m-1-i, <au, _state); tauq->ptr.p_double[i] = ltau; ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,m-1)); t.ptr.p_double[1] = (double)(1); /* * Apply H(i) to A(i+1:m-1,i+1:n-1) from the left */ applyreflectionfromtheleft(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); } else { tauq->ptr.p_double[i] = (double)(0); } } } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix Q which reduces a matrix to bidiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array[0..M-1, 0..QColumns-1] If QColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackq(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(q); ae_assert(qcolumns<=m, "RMatrixBDUnpackQ: QColumns>M!", _state); ae_assert(qcolumns>=0, "RMatrixBDUnpackQ: QColumns<0!", _state); if( (m==0||n==0)||qcolumns==0 ) { return; } /* * prepare Q */ ae_matrix_set_length(q, m, qcolumns, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=qcolumns-1; j++) { if( i==j ) { q->ptr.pp_double[i][j] = (double)(1); } else { q->ptr.pp_double[i][j] = (double)(0); } } } /* * Calculate */ rmatrixbdmultiplybyq(qp, m, n, tauq, q, m, qcolumns, ae_false, ae_false, _state); } /************************************************************************* Multiplication by matrix Q which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by Q or Q'. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. Z - multiplied matrix. array[0..ZRows-1,0..ZColumns-1] ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=M, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=M, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by Q or Q'. Output parameters: Z - product of Z and Q. Array[0..ZRows-1,0..ZColumns-1] If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyq(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t istep; ae_vector v; ae_vector work; ae_vector dummy; ae_int_t mx; ae_frame_make(_state, &_frame_block); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&dummy, 0, DT_REAL, _state); if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) { ae_frame_leave(_state); return; } ae_assert((fromtheright&&zcolumns==m)||(!fromtheright&&zrows==m), "RMatrixBDMultiplyByQ: incorrect Z size!", _state); /* * Try to use MKL code */ if( rmatrixbdmultiplybymkl(qp, m, n, tauq, &dummy, z, zrows, zcolumns, ae_true, fromtheright, dotranspose, _state) ) { ae_frame_leave(_state); return; } /* * init */ mx = ae_maxint(m, n, _state); mx = ae_maxint(mx, zrows, _state); mx = ae_maxint(mx, zcolumns, _state); ae_vector_set_length(&v, mx+1, _state); ae_vector_set_length(&work, mx+1, _state); if( m>=n ) { /* * setup */ if( fromtheright ) { i1 = 0; i2 = n-1; istep = 1; } else { i1 = n-1; i2 = 0; istep = -1; } if( dotranspose ) { i = i1; i1 = i2; i2 = i; istep = -istep; } /* * Process */ i = i1; do { ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], qp->stride, ae_v_len(1,m-i)); v.ptr.p_double[1] = (double)(1); if( fromtheright ) { applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i, m-1, &work, _state); } else { applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i, m-1, 0, zcolumns-1, &work, _state); } i = i+istep; } while(i!=i2+istep); } else { /* * setup */ if( fromtheright ) { i1 = 0; i2 = m-2; istep = 1; } else { i1 = m-2; i2 = 0; istep = -1; } if( dotranspose ) { i = i1; i1 = i2; i2 = i; istep = -istep; } /* * Process */ if( m-1>0 ) { i = i1; do { ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i+1][i], qp->stride, ae_v_len(1,m-i-1)); v.ptr.p_double[1] = (double)(1); if( fromtheright ) { applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i+1, m-1, &work, _state); } else { applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i+1, m-1, 0, zcolumns-1, &work, _state); } i = i+istep; } while(i!=i2+istep); } } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix P which reduces matrix A to bidiagonal form. The subroutine returns transposed matrix P. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of ToBidiagonal subroutine. PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. Output parameters: PT - first PTRows columns of matrix P^T Array[0..PTRows-1, 0..N-1] If PTRows=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackpt(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* taup, ae_int_t ptrows, /* Real */ ae_matrix* pt, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(pt); ae_assert(ptrows<=n, "RMatrixBDUnpackPT: PTRows>N!", _state); ae_assert(ptrows>=0, "RMatrixBDUnpackPT: PTRows<0!", _state); if( (m==0||n==0)||ptrows==0 ) { return; } /* * prepare PT */ ae_matrix_set_length(pt, ptrows, n, _state); for(i=0; i<=ptrows-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { pt->ptr.pp_double[i][j] = (double)(1); } else { pt->ptr.pp_double[i][j] = (double)(0); } } } /* * Calculate */ rmatrixbdmultiplybyp(qp, m, n, taup, pt, ptrows, n, ae_true, ae_true, _state); } /************************************************************************* Multiplication by matrix P which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by P or P'. Input parameters: QP - matrices Q and P in compact form. Output of RMatrixBD subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of RMatrixBD subroutine. Z - multiplied matrix. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=N, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=N, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by P or P'. Output parameters: Z - product of Z and P. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyp(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* taup, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector v; ae_vector work; ae_vector dummy; ae_int_t mx; ae_int_t i1; ae_int_t i2; ae_int_t istep; ae_frame_make(_state, &_frame_block); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&dummy, 0, DT_REAL, _state); if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) { ae_frame_leave(_state); return; } ae_assert((fromtheright&&zcolumns==n)||(!fromtheright&&zrows==n), "RMatrixBDMultiplyByP: incorrect Z size!", _state); /* * init */ mx = ae_maxint(m, n, _state); mx = ae_maxint(mx, zrows, _state); mx = ae_maxint(mx, zcolumns, _state); ae_vector_set_length(&v, mx+1, _state); ae_vector_set_length(&work, mx+1, _state); if( m>=n ) { /* * setup */ if( fromtheright ) { i1 = n-2; i2 = 0; istep = -1; } else { i1 = 0; i2 = n-2; istep = 1; } if( !dotranspose ) { i = i1; i1 = i2; i2 = i; istep = -istep; } /* * Process */ if( n-1>0 ) { i = i1; do { ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i+1], 1, ae_v_len(1,n-1-i)); v.ptr.p_double[1] = (double)(1); if( fromtheright ) { applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i+1, n-1, &work, _state); } else { applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i+1, n-1, 0, zcolumns-1, &work, _state); } i = i+istep; } while(i!=i2+istep); } } else { /* * setup */ if( fromtheright ) { i1 = m-1; i2 = 0; istep = -1; } else { i1 = 0; i2 = m-1; istep = 1; } if( !dotranspose ) { i = i1; i1 = i2; i2 = i; istep = -istep; } /* * Process */ i = i1; do { ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); v.ptr.p_double[1] = (double)(1); if( fromtheright ) { applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i, n-1, &work, _state); } else { applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i, n-1, 0, zcolumns-1, &work, _state); } i = i+istep; } while(i!=i2+istep); } ae_frame_leave(_state); } /************************************************************************* Unpacking of the main and secondary diagonals of bidiagonal decomposition of matrix A. Input parameters: B - output of RMatrixBD subroutine. M - number of rows in matrix B. N - number of columns in matrix B. Output parameters: IsUpper - True, if the matrix is upper bidiagonal. otherwise IsUpper is False. D - the main diagonal. Array whose index ranges within [0..Min(M,N)-1]. E - the secondary diagonal (upper or lower, depending on the value of IsUpper). Array index ranges within [0..Min(M,N)-1], the last element is not used. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackdiagonals(/* Real */ ae_matrix* b, ae_int_t m, ae_int_t n, ae_bool* isupper, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state) { ae_int_t i; *isupper = ae_false; ae_vector_clear(d); ae_vector_clear(e); *isupper = m>=n; if( m<=0||n<=0 ) { return; } if( *isupper ) { ae_vector_set_length(d, n, _state); ae_vector_set_length(e, n, _state); for(i=0; i<=n-2; i++) { d->ptr.p_double[i] = b->ptr.pp_double[i][i]; e->ptr.p_double[i] = b->ptr.pp_double[i][i+1]; } d->ptr.p_double[n-1] = b->ptr.pp_double[n-1][n-1]; } else { ae_vector_set_length(d, m, _state); ae_vector_set_length(e, m, _state); for(i=0; i<=m-2; i++) { d->ptr.p_double[i] = b->ptr.pp_double[i][i]; e->ptr.p_double[i] = b->ptr.pp_double[i+1][i]; } d->ptr.p_double[m-1] = b->ptr.pp_double[m-1][m-1]; } } /************************************************************************* Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, where Q is an orthogonal matrix, H - Hessenberg matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A with elements [0..N-1, 0..N-1] N - size of matrix A. Output parameters: A - matrices Q and P in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..N-2] Matrix H is located on the main diagonal, on the lower secondary diagonal and above the main diagonal of matrix A. The elements which are used to form matrix Q are situated in array Tau and below the lower secondary diagonal of matrix A as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(n-2), where each H(i) is given by H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - is a real vector, so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void rmatrixhessenberg(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { ae_frame _frame_block; ae_int_t i; double v; ae_vector t; ae_vector work; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_assert(n>=0, "RMatrixHessenberg: incorrect N!", _state); /* * Quick return if possible */ if( n<=1 ) { ae_frame_leave(_state); return; } /* * Allocate place */ ae_vector_set_length(tau, n-2+1, _state); ae_vector_set_length(&t, n+1, _state); ae_vector_set_length(&work, n-1+1, _state); /* * MKL version */ if( rmatrixhessenbergmkl(a, n, tau, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ for(i=0; i<=n-2; i++) { /* * Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); generatereflection(&t, n-i-1, &v, _state); ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); tau->ptr.p_double[i] = v; t.ptr.p_double[1] = (double)(1); /* * Apply H(i) to A(1:ihi,i+1:ihi) from the right */ applyreflectionfromtheright(a, v, &t, 0, n-1, i+1, n-1, &work, _state); /* * Apply H(i) to A(i+1:ihi,i+1:n) from the left */ applyreflectionfromtheleft(a, v, &t, i+1, n-1, i+1, n-1, &work, _state); } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix Q which reduces matrix A to upper Hessenberg form COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Tau - scalar factors which are used to form Q. Output of RMatrixHessenberg subroutine. Output parameters: Q - matrix Q. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackq(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector v; ae_vector work; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); if( n==0 ) { ae_frame_leave(_state); return; } /* * init */ ae_matrix_set_length(q, n-1+1, n-1+1, _state); ae_vector_set_length(&v, n-1+1, _state); ae_vector_set_length(&work, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { q->ptr.pp_double[i][j] = (double)(1); } else { q->ptr.pp_double[i][j] = (double)(0); } } } /* * MKL version */ if( rmatrixhessenbergunpackqmkl(a, n, tau, q, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version: unpack Q */ for(i=0; i<=n-2; i++) { /* * Apply H(i) */ ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); v.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(q, tau->ptr.p_double[i], &v, 0, n-1, i+1, n-1, &work, _state); } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Output parameters: H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackh(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* h, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector v; ae_vector work; ae_frame_make(_state, &_frame_block); ae_matrix_clear(h); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); if( n==0 ) { ae_frame_leave(_state); return; } ae_matrix_set_length(h, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=i-2; j++) { h->ptr.pp_double[i][j] = (double)(0); } j = ae_maxint(0, i-1, _state); ae_v_move(&h->ptr.pp_double[i][j], 1, &a->ptr.pp_double[i][j], 1, ae_v_len(j,n-1)); } ae_frame_leave(_state); } /************************************************************************* Reduction of a symmetric matrix which is given by its higher or lower triangular part to a tridiagonal matrix using orthogonal similarity transformation: Q'*A*Q=T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void smatrixtd(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state) { ae_frame _frame_block; ae_int_t i; double alpha; double taui; double v; ae_vector t; ae_vector t2; ae_vector t3; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_clear(d); ae_vector_clear(e); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_init(&t3, 0, DT_REAL, _state); if( n<=0 ) { ae_frame_leave(_state); return; } ae_vector_set_length(&t, n+1, _state); ae_vector_set_length(&t2, n+1, _state); ae_vector_set_length(&t3, n+1, _state); if( n>1 ) { ae_vector_set_length(tau, n-2+1, _state); } ae_vector_set_length(d, n-1+1, _state); if( n>1 ) { ae_vector_set_length(e, n-2+1, _state); } /* * Try to use MKL */ if( smatrixtdmkl(a, n, isupper, tau, d, e, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ if( isupper ) { /* * Reduce the upper triangle of A */ for(i=n-2; i>=0; i--) { /* * Generate elementary reflector H() = E - tau * v * v' */ if( i>=1 ) { ae_v_move(&t.ptr.p_double[2], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(2,i+1)); } t.ptr.p_double[1] = a->ptr.pp_double[i][i+1]; generatereflection(&t, i+1, &taui, _state); if( i>=1 ) { ae_v_move(&a->ptr.pp_double[0][i+1], a->stride, &t.ptr.p_double[2], 1, ae_v_len(0,i-1)); } a->ptr.pp_double[i][i+1] = t.ptr.p_double[1]; e->ptr.p_double[i] = a->ptr.pp_double[i][i+1]; if( ae_fp_neq(taui,(double)(0)) ) { /* * Apply H from both sides to A */ a->ptr.pp_double[i][i+1] = (double)(1); /* * Compute x := tau * A * v storing x in TAU */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); symmetricmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t3, _state); ae_v_move(&tau->ptr.p_double[0], 1, &t3.ptr.p_double[1], 1, ae_v_len(0,i)); /* * Compute w := x - 1/2 * tau * (x'*v) * v */ v = ae_v_dotproduct(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i)); alpha = -0.5*taui*v; ae_v_addd(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i), alpha); /* * Apply the transformation as a rank-2 update: * A := A - v * w' - w * v' */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); ae_v_move(&t3.ptr.p_double[1], 1, &tau->ptr.p_double[0], 1, ae_v_len(1,i+1)); symmetricrank2update(a, isupper, 0, i, &t, &t3, &t2, (double)(-1), _state); a->ptr.pp_double[i][i+1] = e->ptr.p_double[i]; } d->ptr.p_double[i+1] = a->ptr.pp_double[i+1][i+1]; tau->ptr.p_double[i] = taui; } d->ptr.p_double[0] = a->ptr.pp_double[0][0]; } else { /* * Reduce the lower triangle of A */ for(i=0; i<=n-2; i++) { /* * Generate elementary reflector H = E - tau * v * v' */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); generatereflection(&t, n-i-1, &taui, _state); ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); e->ptr.p_double[i] = a->ptr.pp_double[i+1][i]; if( ae_fp_neq(taui,(double)(0)) ) { /* * Apply H from both sides to A */ a->ptr.pp_double[i+1][i] = (double)(1); /* * Compute x := tau * A * v storing y in TAU */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); symmetricmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); ae_v_move(&tau->ptr.p_double[i], 1, &t2.ptr.p_double[1], 1, ae_v_len(i,n-2)); /* * Compute w := x - 1/2 * tau * (x'*v) * v */ v = ae_v_dotproduct(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2)); alpha = -0.5*taui*v; ae_v_addd(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2), alpha); /* * Apply the transformation as a rank-2 update: * A := A - v * w' - w * v' * */ ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); ae_v_move(&t2.ptr.p_double[1], 1, &tau->ptr.p_double[i], 1, ae_v_len(1,n-i-1)); symmetricrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, (double)(-1), _state); a->ptr.pp_double[i+1][i] = e->ptr.p_double[i]; } d->ptr.p_double[i] = a->ptr.pp_double[i][i]; tau->ptr.p_double[i] = taui; } d->ptr.p_double[n-1] = a->ptr.pp_double[n-1][n-1]; } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix Q which reduces symmetric matrix to a tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a SMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of SMatrixTD subroutine) Tau - the result of a SMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void smatrixtdunpackq(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector v; ae_vector work; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); if( n==0 ) { ae_frame_leave(_state); return; } /* * init */ ae_matrix_set_length(q, n-1+1, n-1+1, _state); ae_vector_set_length(&v, n+1, _state); ae_vector_set_length(&work, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { q->ptr.pp_double[i][j] = (double)(1); } else { q->ptr.pp_double[i][j] = (double)(0); } } } /* * MKL version */ if( smatrixtdunpackqmkl(a, n, isupper, tau, q, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version: unpack Q */ if( isupper ) { for(i=0; i<=n-2; i++) { /* * Apply H(i) */ ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); v.ptr.p_double[i+1] = (double)(1); applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, 0, i, 0, n-1, &work, _state); } } else { for(i=n-2; i>=0; i--) { /* * Apply H(i) */ ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); v.ptr.p_double[1] = (double)(1); applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, i+1, n-1, 0, n-1, &work, _state); } } ae_frame_leave(_state); } /************************************************************************* Reduction of a Hermitian matrix which is given by its higher or lower triangular part to a real tridiagonal matrix using unitary similarity transformation: Q'*A*Q = T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of real symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of real symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void hmatrixtd(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_complex alpha; ae_complex taui; ae_complex v; ae_vector t; ae_vector t2; ae_vector t3; ae_frame_make(_state, &_frame_block); ae_vector_clear(tau); ae_vector_clear(d); ae_vector_clear(e); ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&t2, 0, DT_COMPLEX, _state); ae_vector_init(&t3, 0, DT_COMPLEX, _state); /* * Init and test */ if( n<=0 ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { ae_assert(ae_fp_eq(a->ptr.pp_complex[i][i].y,(double)(0)), "Assertion failed", _state); } if( n>1 ) { ae_vector_set_length(tau, n-2+1, _state); ae_vector_set_length(e, n-2+1, _state); } ae_vector_set_length(d, n-1+1, _state); ae_vector_set_length(&t, n-1+1, _state); ae_vector_set_length(&t2, n-1+1, _state); ae_vector_set_length(&t3, n-1+1, _state); /* * MKL version */ if( hmatrixtdmkl(a, n, isupper, tau, d, e, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ if( isupper ) { /* * Reduce the upper triangle of A */ a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(a->ptr.pp_complex[n-1][n-1].x); for(i=n-2; i>=0; i--) { /* * Generate elementary reflector H = I+1 - tau * v * v' */ alpha = a->ptr.pp_complex[i][i+1]; t.ptr.p_complex[1] = alpha; if( i>=1 ) { ae_v_cmove(&t.ptr.p_complex[2], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(2,i+1)); } complexgeneratereflection(&t, i+1, &taui, _state); if( i>=1 ) { ae_v_cmove(&a->ptr.pp_complex[0][i+1], a->stride, &t.ptr.p_complex[2], 1, "N", ae_v_len(0,i-1)); } alpha = t.ptr.p_complex[1]; e->ptr.p_double[i] = alpha.x; if( ae_c_neq_d(taui,(double)(0)) ) { /* * Apply H(I+1) from both sides to A */ a->ptr.pp_complex[i][i+1] = ae_complex_from_i(1); /* * Compute x := tau * A * v storing x in TAU */ ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); hermitianmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t2, _state); ae_v_cmove(&tau->ptr.p_complex[0], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(0,i)); /* * Compute w := x - 1/2 * tau * (x'*v) * v */ v = ae_v_cdotproduct(&tau->ptr.p_complex[0], 1, "Conj", &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i)); alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); ae_v_caddc(&tau->ptr.p_complex[0], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i), alpha); /* * Apply the transformation as a rank-2 update: * A := A - v * w' - w * v' */ ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); ae_v_cmove(&t3.ptr.p_complex[1], 1, &tau->ptr.p_complex[0], 1, "N", ae_v_len(1,i+1)); hermitianrank2update(a, isupper, 0, i, &t, &t3, &t2, ae_complex_from_i(-1), _state); } else { a->ptr.pp_complex[i][i] = ae_complex_from_d(a->ptr.pp_complex[i][i].x); } a->ptr.pp_complex[i][i+1] = ae_complex_from_d(e->ptr.p_double[i]); d->ptr.p_double[i+1] = a->ptr.pp_complex[i+1][i+1].x; tau->ptr.p_complex[i] = taui; } d->ptr.p_double[0] = a->ptr.pp_complex[0][0].x; } else { /* * Reduce the lower triangle of A */ a->ptr.pp_complex[0][0] = ae_complex_from_d(a->ptr.pp_complex[0][0].x); for(i=0; i<=n-2; i++) { /* * Generate elementary reflector H = I - tau * v * v' */ ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); complexgeneratereflection(&t, n-i-1, &taui, _state); ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &t.ptr.p_complex[1], 1, "N", ae_v_len(i+1,n-1)); e->ptr.p_double[i] = a->ptr.pp_complex[i+1][i].x; if( ae_c_neq_d(taui,(double)(0)) ) { /* * Apply H(i) from both sides to A(i+1:n,i+1:n) */ a->ptr.pp_complex[i+1][i] = ae_complex_from_i(1); /* * Compute x := tau * A * v storing y in TAU */ ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); hermitianmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); ae_v_cmove(&tau->ptr.p_complex[i], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(i,n-2)); /* * Compute w := x - 1/2 * tau * (x'*v) * v */ v = ae_v_cdotproduct(&tau->ptr.p_complex[i], 1, "Conj", &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2)); alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); ae_v_caddc(&tau->ptr.p_complex[i], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2), alpha); /* * Apply the transformation as a rank-2 update: * A := A - v * w' - w * v' */ ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); ae_v_cmove(&t2.ptr.p_complex[1], 1, &tau->ptr.p_complex[i], 1, "N", ae_v_len(1,n-i-1)); hermitianrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, ae_complex_from_i(-1), _state); } else { a->ptr.pp_complex[i+1][i+1] = ae_complex_from_d(a->ptr.pp_complex[i+1][i+1].x); } a->ptr.pp_complex[i+1][i] = ae_complex_from_d(e->ptr.p_double[i]); d->ptr.p_double[i] = a->ptr.pp_complex[i][i].x; tau->ptr.p_complex[i] = taui; } d->ptr.p_double[n-1] = a->ptr.pp_complex[n-1][n-1].x; } ae_frame_leave(_state); } /************************************************************************* Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a HMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of HMatrixTD subroutine) Tau - the result of a HMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void hmatrixtdunpackq(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Complex */ ae_matrix* q, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector v; ae_vector work; ae_frame_make(_state, &_frame_block); ae_matrix_clear(q); ae_vector_init(&v, 0, DT_COMPLEX, _state); ae_vector_init(&work, 0, DT_COMPLEX, _state); if( n==0 ) { ae_frame_leave(_state); return; } /* * init */ ae_matrix_set_length(q, n-1+1, n-1+1, _state); ae_vector_set_length(&v, n+1, _state); ae_vector_set_length(&work, n-1+1, _state); /* * MKL version */ if( hmatrixtdunpackqmkl(a, n, isupper, tau, q, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { q->ptr.pp_complex[i][j] = ae_complex_from_i(1); } else { q->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( isupper ) { for(i=0; i<=n-2; i++) { /* * Apply H(i) */ ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); v.ptr.p_complex[i+1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, 0, i, 0, n-1, &work, _state); } } else { for(i=n-2; i>=0; i--) { /* * Apply H(i) */ ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, i+1, n-1, 0, n-1, &work, _state); } } ae_frame_leave(_state); } /************************************************************************* Base case for complex QR -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* work, /* Complex */ ae_vector* t, /* Complex */ ae_vector* tau, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t mmi; ae_int_t minmn; ae_complex tmp; minmn = ae_minint(m, n, _state); if( minmn<=0 ) { return; } /* * Test the input arguments */ k = ae_minint(m, n, _state); for(i=0; i<=k-1; i++) { /* * Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ mmi = m-i; ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], a->stride, "N", ae_v_len(1,mmi)); complexgeneratereflection(t, mmi, &tmp, _state); tau->ptr.p_complex[i] = tmp; ae_v_cmove(&a->ptr.pp_complex[i][i], a->stride, &t->ptr.p_complex[1], 1, "N", ae_v_len(i,m-1)); t->ptr.p_complex[1] = ae_complex_from_i(1); if( iptr.p_complex[i], _state), t, i, m-1, i+1, n-1, work, _state); } } } /************************************************************************* Base case for complex LQ -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* work, /* Complex */ ae_vector* t, /* Complex */ ae_vector* tau, ae_state *_state) { ae_int_t i; ae_int_t minmn; ae_complex tmp; minmn = ae_minint(m, n, _state); if( minmn<=0 ) { return; } /* * Test the input arguments */ for(i=0; i<=minmn-1; i++) { /* * Generate elementary reflector H(i) * * NOTE: ComplexGenerateReflection() generates left reflector, * i.e. H which reduces x by applyiong from the left, but we * need RIGHT reflector. So we replace H=E-tau*v*v' by H^H, * which changes v to conj(v). */ ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,n-i)); complexgeneratereflection(t, n-i, &tmp, _state); tau->ptr.p_complex[i] = tmp; ae_v_cmove(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[1], 1, "Conj", ae_v_len(i,n-1)); t->ptr.p_complex[1] = ae_complex_from_i(1); if( iptr.p_complex[i], t, i+1, m-1, i, n-1, work, _state); } } } /************************************************************************* Generate block reflector: * fill unused parts of reflectors matrix by zeros * fill diagonal of reflectors matrix by ones * generate triangular factor T PARAMETERS: A - either LengthA*BlockSize (if ColumnwiseA) or BlockSize*LengthA (if not ColumnwiseA) matrix of elementary reflectors. Modified on exit. Tau - scalar factors ColumnwiseA - reflectors are stored in rows or in columns LengthA - length of largest reflector BlockSize - number of reflectors T - array[BlockSize,2*BlockSize]. Left BlockSize*BlockSize submatrix stores triangular factor on exit. WORK - array[BlockSize] -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, /* Real */ ae_vector* tau, ae_bool columnwisea, ae_int_t lengtha, ae_int_t blocksize, /* Real */ ae_matrix* t, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double v; /* * fill beginning of new column with zeros, * load 1.0 in the first non-zero element */ for(k=0; k<=blocksize-1; k++) { if( columnwisea ) { for(i=0; i<=k-1; i++) { a->ptr.pp_double[i][k] = (double)(0); } } else { for(i=0; i<=k-1; i++) { a->ptr.pp_double[k][i] = (double)(0); } } a->ptr.pp_double[k][k] = (double)(1); } /* * Calculate Gram matrix of A */ for(i=0; i<=blocksize-1; i++) { for(j=0; j<=blocksize-1; j++) { t->ptr.pp_double[i][blocksize+j] = (double)(0); } } for(k=0; k<=lengtha-1; k++) { for(j=1; j<=blocksize-1; j++) { if( columnwisea ) { v = a->ptr.pp_double[k][j]; if( ae_fp_neq(v,(double)(0)) ) { ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[k][0], 1, ae_v_len(blocksize,blocksize+j-1), v); } } else { v = a->ptr.pp_double[j][k]; if( ae_fp_neq(v,(double)(0)) ) { ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[0][k], a->stride, ae_v_len(blocksize,blocksize+j-1), v); } } } } /* * Prepare Y (stored in TmpA) and T (stored in TmpT) */ for(k=0; k<=blocksize-1; k++) { /* * fill non-zero part of T, use pre-calculated Gram matrix */ ae_v_move(&work->ptr.p_double[0], 1, &t->ptr.pp_double[k][blocksize], 1, ae_v_len(0,k-1)); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&t->ptr.pp_double[i][i], 1, &work->ptr.p_double[i], 1, ae_v_len(i,k-1)); t->ptr.pp_double[i][k] = -tau->ptr.p_double[k]*v; } t->ptr.pp_double[k][k] = -tau->ptr.p_double[k]; /* * Rest of T is filled by zeros */ for(i=k+1; i<=blocksize-1; i++) { t->ptr.pp_double[i][k] = (double)(0); } } } /************************************************************************* Generate block reflector (complex): * fill unused parts of reflectors matrix by zeros * fill diagonal of reflectors matrix by ones * generate triangular factor T -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, /* Complex */ ae_vector* tau, ae_bool columnwisea, ae_int_t lengtha, ae_int_t blocksize, /* Complex */ ae_matrix* t, /* Complex */ ae_vector* work, ae_state *_state) { ae_int_t i; ae_int_t k; ae_complex v; /* * Prepare Y (stored in TmpA) and T (stored in TmpT) */ for(k=0; k<=blocksize-1; k++) { /* * fill beginning of new column with zeros, * load 1.0 in the first non-zero element */ if( columnwisea ) { for(i=0; i<=k-1; i++) { a->ptr.pp_complex[i][k] = ae_complex_from_i(0); } } else { for(i=0; i<=k-1; i++) { a->ptr.pp_complex[k][i] = ae_complex_from_i(0); } } a->ptr.pp_complex[k][k] = ae_complex_from_i(1); /* * fill non-zero part of T, */ for(i=0; i<=k-1; i++) { if( columnwisea ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[k][i], a->stride, "Conj", &a->ptr.pp_complex[k][k], a->stride, "N", ae_v_len(k,lengtha-1)); } else { v = ae_v_cdotproduct(&a->ptr.pp_complex[i][k], 1, "N", &a->ptr.pp_complex[k][k], 1, "Conj", ae_v_len(k,lengtha-1)); } work->ptr.p_complex[i] = v; } for(i=0; i<=k-1; i++) { v = ae_v_cdotproduct(&t->ptr.pp_complex[i][i], 1, "N", &work->ptr.p_complex[i], 1, "N", ae_v_len(i,k-1)); t->ptr.pp_complex[i][k] = ae_c_neg(ae_c_mul(tau->ptr.p_complex[k],v)); } t->ptr.pp_complex[k][k] = ae_c_neg(tau->ptr.p_complex[k]); /* * Rest of T is filled by zeros */ for(i=k+1; i<=blocksize-1; i++) { t->ptr.pp_complex[i][k] = ae_complex_from_i(0); } } } /************************************************************************* Singular value decomposition of a bidiagonal matrix (extended algorithm) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm performs the singular value decomposition of a bidiagonal matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - orthogonal matrices, S - diagonal matrix with non-negative elements on the main diagonal, in descending order. The algorithm finds singular values. In addition, the algorithm can calculate matrices Q and P (more precisely, not the matrices, but their product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, matrices U and VT can be of any type, including identity. Furthermore, the algorithm can calculate Q'*C (this product is calculated more effectively than U*Q, because this calculation operates with rows instead of matrix columns). The feature of the algorithm is its ability to find all singular values including those which are arbitrarily close to 0 with relative accuracy close to machine precision. If the parameter IsFractionalAccuracyRequired is set to True, all singular values will have high relative accuracy close to machine precision. If the parameter is set to False, only the biggest singular value will have relative accuracy close to machine precision. The absolute error of other singular values is equal to the absolute error of the biggest singular value. Input parameters: D - main diagonal of matrix B. Array whose index ranges within [0..N-1]. E - superdiagonal (or subdiagonal) of matrix B. Array whose index ranges within [0..N-2]. N - size of matrix B. IsUpper - True, if the matrix is upper bidiagonal. IsFractionalAccuracyRequired - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. U - matrix to be multiplied by Q. Array whose indexes range within [0..NRU-1, 0..N-1]. The matrix can be bigger, in that case only the submatrix [0..NRU-1, 0..N-1] will be multiplied by Q. NRU - number of rows in matrix U. C - matrix to be multiplied by Q'. Array whose indexes range within [0..N-1, 0..NCC-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCC-1] will be multiplied by Q'. NCC - number of columns in matrix C. VT - matrix to be multiplied by P^T. Array whose indexes range within [0..N-1, 0..NCVT-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCVT-1] will be multiplied by P^T. NCVT - number of columns in matrix VT. Output parameters: D - singular values of matrix B in descending order. U - if NRU>0, contains matrix U*Q. VT - if NCVT>0, contains matrix (P^T)*VT. C - if NCC>0, contains matrix Q'*C. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). NOTE: multiplication U*Q is performed by means of transposition to internal buffer, multiplication and backward transposition. It helps to avoid costly columnwise operations and speed-up algorithm. Additional information: The type of convergence is controlled by the internal parameter TOL. If the parameter is greater than 0, the singular values will have relative accuracy TOL. If TOL<0, the singular values will have absolute accuracy ABS(TOL)*norm(B). By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, where Epsilon is the machine precision. It is not recommended to use TOL less than 10*Epsilon since this will considerably slow down the algorithm and may not lead to error decreasing. History: * 31 March, 2007. changed MAXITR from 6 to 12. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1999. *************************************************************************/ ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_int_t i; ae_vector en; ae_vector d1; ae_vector e1; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_init(&en, 0, DT_REAL, _state); ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&e1, 0, DT_REAL, _state); result = ae_false; /* * Try to use MKL */ ae_vector_set_length(&en, n, _state); for(i=0; i<=n-2; i++) { en.ptr.p_double[i] = e->ptr.p_double[i]; } en.ptr.p_double[n-1] = 0.0; if( rmatrixbdsvdmkl(d, &en, n, isupper, u, nru, c, ncc, vt, ncvt, &result, _state) ) { ae_frame_leave(_state); return result; } /* * Use ALGLIB code */ ae_vector_set_length(&d1, n+1, _state); ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); if( n>1 ) { ae_vector_set_length(&e1, n-1+1, _state); ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); } result = bdsvd_bidiagonalsvddecompositioninternal(&d1, &e1, n, isupper, isfractionalaccuracyrequired, u, 0, nru, c, 0, ncc, vt, 0, ncvt, _state); ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); return result; } ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; result = bdsvd_bidiagonalsvddecompositioninternal(d, e, n, isupper, isfractionalaccuracyrequired, u, 1, nru, c, 1, ncc, vt, 1, ncvt, _state); ae_frame_leave(_state); return result; } /************************************************************************* Internal working subroutine for bidiagonal decomposition *************************************************************************/ static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* uu, ae_int_t ustart, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t cstart, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t vstart, ae_int_t ncvt, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_int_t i; ae_int_t idir; ae_int_t isub; ae_int_t iter; ae_int_t j; ae_int_t ll; ae_int_t lll; ae_int_t m; ae_int_t maxit; ae_int_t oldll; ae_int_t oldm; double abse; double abss; double cosl; double cosr; double cs; double eps; double f; double g; double h; double mu; double oldcs; double oldsn; double r; double shift; double sigmn; double sigmx; double sinl; double sinr; double sll; double smax; double smin; double sminl; double sminoa; double sn; double thresh; double tol; double tolmul; double unfl; ae_vector work0; ae_vector work1; ae_vector work2; ae_vector work3; ae_int_t maxitr; ae_bool matrixsplitflag; ae_bool iterflag; ae_vector utemp; ae_vector vttemp; ae_vector ctemp; ae_vector etemp; ae_matrix ut; ae_bool fwddir; double tmp; ae_int_t mm1; ae_int_t mm0; ae_bool bchangedir; ae_int_t uend; ae_int_t cend; ae_int_t vend; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_init(&work0, 0, DT_REAL, _state); ae_vector_init(&work1, 0, DT_REAL, _state); ae_vector_init(&work2, 0, DT_REAL, _state); ae_vector_init(&work3, 0, DT_REAL, _state); ae_vector_init(&utemp, 0, DT_REAL, _state); ae_vector_init(&vttemp, 0, DT_REAL, _state); ae_vector_init(&ctemp, 0, DT_REAL, _state); ae_vector_init(&etemp, 0, DT_REAL, _state); ae_matrix_init(&ut, 0, 0, DT_REAL, _state); result = ae_true; if( n==0 ) { ae_frame_leave(_state); return result; } if( n==1 ) { if( ae_fp_less(d->ptr.p_double[1],(double)(0)) ) { d->ptr.p_double[1] = -d->ptr.p_double[1]; if( ncvt>0 ) { ae_v_muld(&vt->ptr.pp_double[vstart][vstart], 1, ae_v_len(vstart,vstart+ncvt-1), -1); } } ae_frame_leave(_state); return result; } /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ ll = 0; oldsn = (double)(0); /* * init */ ae_vector_set_length(&work0, n-1+1, _state); ae_vector_set_length(&work1, n-1+1, _state); ae_vector_set_length(&work2, n-1+1, _state); ae_vector_set_length(&work3, n-1+1, _state); uend = ustart+ae_maxint(nru-1, 0, _state); vend = vstart+ae_maxint(ncvt-1, 0, _state); cend = cstart+ae_maxint(ncc-1, 0, _state); ae_vector_set_length(&utemp, uend+1, _state); ae_vector_set_length(&vttemp, vend+1, _state); ae_vector_set_length(&ctemp, cend+1, _state); maxitr = 12; fwddir = ae_true; if( nru>0 ) { ae_matrix_set_length(&ut, ustart+n, ustart+nru, _state); rmatrixtranspose(nru, n, uu, ustart, ustart, &ut, ustart, ustart, _state); } /* * resize E from N-1 to N */ ae_vector_set_length(&etemp, n+1, _state); for(i=1; i<=n-1; i++) { etemp.ptr.p_double[i] = e->ptr.p_double[i]; } ae_vector_set_length(e, n+1, _state); for(i=1; i<=n-1; i++) { e->ptr.p_double[i] = etemp.ptr.p_double[i]; } e->ptr.p_double[n] = (double)(0); idir = 0; /* * Get machine constants */ eps = ae_machineepsilon; unfl = ae_minrealnumber; /* * If matrix lower bidiagonal, rotate to be upper bidiagonal * by applying Givens rotations on the left */ if( !isupper ) { for(i=1; i<=n-1; i++) { generaterotation(d->ptr.p_double[i], e->ptr.p_double[i], &cs, &sn, &r, _state); d->ptr.p_double[i] = r; e->ptr.p_double[i] = sn*d->ptr.p_double[i+1]; d->ptr.p_double[i+1] = cs*d->ptr.p_double[i+1]; work0.ptr.p_double[i] = cs; work1.ptr.p_double[i] = sn; } /* * Update singular vectors if desired */ if( nru>0 ) { applyrotationsfromtheleft(fwddir, 1+ustart-1, n+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); } if( ncc>0 ) { applyrotationsfromtheleft(fwddir, 1+cstart-1, n+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); } } /* * Compute singular values to relative accuracy TOL * (By setting TOL to be negative, algorithm will compute * singular values to absolute accuracy ABS(TOL)*norm(input matrix)) */ tolmul = ae_maxreal((double)(10), ae_minreal((double)(100), ae_pow(eps, -0.125, _state), _state), _state); tol = tolmul*eps; /* * Compute approximate maximum, minimum singular values */ smax = (double)(0); for(i=1; i<=n; i++) { smax = ae_maxreal(smax, ae_fabs(d->ptr.p_double[i], _state), _state); } for(i=1; i<=n-1; i++) { smax = ae_maxreal(smax, ae_fabs(e->ptr.p_double[i], _state), _state); } sminl = (double)(0); if( ae_fp_greater_eq(tol,(double)(0)) ) { /* * Relative accuracy desired */ sminoa = ae_fabs(d->ptr.p_double[1], _state); if( ae_fp_neq(sminoa,(double)(0)) ) { mu = sminoa; for(i=2; i<=n; i++) { mu = ae_fabs(d->ptr.p_double[i], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[i-1], _state))); sminoa = ae_minreal(sminoa, mu, _state); if( ae_fp_eq(sminoa,(double)(0)) ) { break; } } } sminoa = sminoa/ae_sqrt((double)(n), _state); thresh = ae_maxreal(tol*sminoa, maxitr*n*n*unfl, _state); } else { /* * Absolute accuracy desired */ thresh = ae_maxreal(ae_fabs(tol, _state)*smax, maxitr*n*n*unfl, _state); } /* * Prepare for main iteration loop for the singular values * (MAXIT is the maximum number of passes through the inner * loop permitted before nonconvergence signalled.) */ maxit = maxitr*n*n; iter = 0; oldll = -1; oldm = -1; /* * M points to last element of unconverged part of matrix */ m = n; /* * Begin main iteration loop */ for(;;) { /* * Check for convergence or exceeding iteration count */ if( m<=1 ) { break; } if( iter>maxit ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Find diagonal block of matrix to work on */ if( ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[m], _state),thresh) ) { d->ptr.p_double[m] = (double)(0); } smax = ae_fabs(d->ptr.p_double[m], _state); smin = smax; matrixsplitflag = ae_false; for(lll=1; lll<=m-1; lll++) { ll = m-lll; abss = ae_fabs(d->ptr.p_double[ll], _state); abse = ae_fabs(e->ptr.p_double[ll], _state); if( ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(abss,thresh) ) { d->ptr.p_double[ll] = (double)(0); } if( ae_fp_less_eq(abse,thresh) ) { matrixsplitflag = ae_true; break; } smin = ae_minreal(smin, abss, _state); smax = ae_maxreal(smax, ae_maxreal(abss, abse, _state), _state); } if( !matrixsplitflag ) { ll = 0; } else { /* * Matrix splits since E(LL) = 0 */ e->ptr.p_double[ll] = (double)(0); if( ll==m-1 ) { /* * Convergence of bottom singular value, return to top of loop */ m = m-1; continue; } } ll = ll+1; /* * E(LL) through E(M-1) are nonzero, E(LL-1) is zero */ if( ll==m-1 ) { /* * 2 by 2 block, handle separately */ bdsvd_svdv2x2(d->ptr.p_double[m-1], e->ptr.p_double[m-1], d->ptr.p_double[m], &sigmn, &sigmx, &sinr, &cosr, &sinl, &cosl, _state); d->ptr.p_double[m-1] = sigmx; e->ptr.p_double[m-1] = (double)(0); d->ptr.p_double[m] = sigmn; /* * Compute singular vectors, if desired */ if( ncvt>0 ) { mm0 = m+(vstart-1); mm1 = m-1+(vstart-1); ae_v_moved(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), cosr); ae_v_addd(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), sinr); ae_v_muld(&vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), cosr); ae_v_subd(&vt->ptr.pp_double[mm0][vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), sinr); ae_v_move(&vt->ptr.pp_double[mm1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); } if( nru>0 ) { mm0 = m+ustart-1; mm1 = m-1+ustart-1; ae_v_moved(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[mm1][ustart], 1, ae_v_len(ustart,uend), cosl); ae_v_addd(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[mm0][ustart], 1, ae_v_len(ustart,uend), sinl); ae_v_muld(&ut.ptr.pp_double[mm0][ustart], 1, ae_v_len(ustart,uend), cosl); ae_v_subd(&ut.ptr.pp_double[mm0][ustart], 1, &ut.ptr.pp_double[mm1][ustart], 1, ae_v_len(ustart,uend), sinl); ae_v_move(&ut.ptr.pp_double[mm1][ustart], 1, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); } if( ncc>0 ) { mm0 = m+cstart-1; mm1 = m-1+cstart-1; ae_v_moved(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), cosl); ae_v_addd(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), sinl); ae_v_muld(&c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), cosl); ae_v_subd(&c->ptr.pp_double[mm0][cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), sinl); ae_v_move(&c->ptr.pp_double[mm1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); } m = m-2; continue; } /* * If working on new submatrix, choose shift direction * (from larger end diagonal element towards smaller) * * Previously was * "if (LL>OLDM) or (M * Very strange that LAPACK still contains it. */ bchangedir = ae_false; if( idir==1&&ae_fp_less(ae_fabs(d->ptr.p_double[ll], _state),1.0E-3*ae_fabs(d->ptr.p_double[m], _state)) ) { bchangedir = ae_true; } if( idir==2&&ae_fp_less(ae_fabs(d->ptr.p_double[m], _state),1.0E-3*ae_fabs(d->ptr.p_double[ll], _state)) ) { bchangedir = ae_true; } if( (ll!=oldll||m!=oldm)||bchangedir ) { if( ae_fp_greater_eq(ae_fabs(d->ptr.p_double[ll], _state),ae_fabs(d->ptr.p_double[m], _state)) ) { /* * Chase bulge from top (big end) to bottom (small end) */ idir = 1; } else { /* * Chase bulge from bottom (big end) to top (small end) */ idir = 2; } } /* * Apply convergence tests */ if( idir==1 ) { /* * Run convergence test in forward direction * First apply standard test to bottom of matrix */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[m], _state))||(ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh)) ) { e->ptr.p_double[m-1] = (double)(0); continue; } if( ae_fp_greater_eq(tol,(double)(0)) ) { /* * If relative accuracy desired, * apply convergence criterion forward */ mu = ae_fabs(d->ptr.p_double[ll], _state); sminl = mu; iterflag = ae_false; for(lll=ll; lll<=m-1; lll++) { if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[lll], _state),tol*mu) ) { e->ptr.p_double[lll] = (double)(0); iterflag = ae_true; break; } mu = ae_fabs(d->ptr.p_double[lll+1], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[lll], _state))); sminl = ae_minreal(sminl, mu, _state); } if( iterflag ) { continue; } } } else { /* * Run convergence test in backward direction * First apply standard test to top of matrix */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[ll], _state))||(ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh)) ) { e->ptr.p_double[ll] = (double)(0); continue; } if( ae_fp_greater_eq(tol,(double)(0)) ) { /* * If relative accuracy desired, * apply convergence criterion backward */ mu = ae_fabs(d->ptr.p_double[m], _state); sminl = mu; iterflag = ae_false; for(lll=m-1; lll>=ll; lll--) { if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[lll], _state),tol*mu) ) { e->ptr.p_double[lll] = (double)(0); iterflag = ae_true; break; } mu = ae_fabs(d->ptr.p_double[lll], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[lll], _state))); sminl = ae_minreal(sminl, mu, _state); } if( iterflag ) { continue; } } } oldll = ll; oldm = m; /* * Compute shift. First, test if shifting would ruin relative * accuracy, and if so set the shift to zero. */ if( ae_fp_greater_eq(tol,(double)(0))&&ae_fp_less_eq(n*tol*(sminl/smax),ae_maxreal(eps, 0.01*tol, _state)) ) { /* * Use a zero shift to avoid loss of relative accuracy */ shift = (double)(0); } else { /* * Compute the shift from 2-by-2 block at end of matrix */ if( idir==1 ) { sll = ae_fabs(d->ptr.p_double[ll], _state); bdsvd_svd2x2(d->ptr.p_double[m-1], e->ptr.p_double[m-1], d->ptr.p_double[m], &shift, &r, _state); } else { sll = ae_fabs(d->ptr.p_double[m], _state); bdsvd_svd2x2(d->ptr.p_double[ll], e->ptr.p_double[ll], d->ptr.p_double[ll+1], &shift, &r, _state); } /* * Test if shift negligible, and if so set to zero */ if( ae_fp_greater(sll,(double)(0)) ) { if( ae_fp_less(ae_sqr(shift/sll, _state),eps) ) { shift = (double)(0); } } } /* * Increment iteration count */ iter = iter+m-ll; /* * If SHIFT = 0, do simplified QR iteration */ if( ae_fp_eq(shift,(double)(0)) ) { if( idir==1 ) { /* * Chase bulge from top to bottom * Save cosines and sines for later singular vector updates */ cs = (double)(1); oldcs = (double)(1); for(i=ll; i<=m-1; i++) { generaterotation(d->ptr.p_double[i]*cs, e->ptr.p_double[i], &cs, &sn, &r, _state); if( i>ll ) { e->ptr.p_double[i-1] = oldsn*r; } generaterotation(oldcs*r, d->ptr.p_double[i+1]*sn, &oldcs, &oldsn, &tmp, _state); d->ptr.p_double[i] = tmp; work0.ptr.p_double[i-ll+1] = cs; work1.ptr.p_double[i-ll+1] = sn; work2.ptr.p_double[i-ll+1] = oldcs; work3.ptr.p_double[i-ll+1] = oldsn; } h = d->ptr.p_double[m]*cs; d->ptr.p_double[m] = h*oldcs; e->ptr.p_double[m-1] = h*oldsn; /* * Update singular vectors */ if( ncvt>0 ) { applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); } if( nru>0 ) { applyrotationsfromtheleft(fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work2, &work3, &ut, &utemp, _state); } if( ncc>0 ) { applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); } /* * Test convergence */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh) ) { e->ptr.p_double[m-1] = (double)(0); } } else { /* * Chase bulge from bottom to top * Save cosines and sines for later singular vector updates */ cs = (double)(1); oldcs = (double)(1); for(i=m; i>=ll+1; i--) { generaterotation(d->ptr.p_double[i]*cs, e->ptr.p_double[i-1], &cs, &sn, &r, _state); if( iptr.p_double[i] = oldsn*r; } generaterotation(oldcs*r, d->ptr.p_double[i-1]*sn, &oldcs, &oldsn, &tmp, _state); d->ptr.p_double[i] = tmp; work0.ptr.p_double[i-ll] = cs; work1.ptr.p_double[i-ll] = -sn; work2.ptr.p_double[i-ll] = oldcs; work3.ptr.p_double[i-ll] = -oldsn; } h = d->ptr.p_double[ll]*cs; d->ptr.p_double[ll] = h*oldcs; e->ptr.p_double[ll] = h*oldsn; /* * Update singular vectors */ if( ncvt>0 ) { applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); } if( nru>0 ) { applyrotationsfromtheleft(!fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); } if( ncc>0 ) { applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); } /* * Test convergence */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh) ) { e->ptr.p_double[ll] = (double)(0); } } } else { /* * Use nonzero shift */ if( idir==1 ) { /* * Chase bulge from top to bottom * Save cosines and sines for later singular vector updates */ f = (ae_fabs(d->ptr.p_double[ll], _state)-shift)*(bdsvd_extsignbdsqr((double)(1), d->ptr.p_double[ll], _state)+shift/d->ptr.p_double[ll]); g = e->ptr.p_double[ll]; for(i=ll; i<=m-1; i++) { generaterotation(f, g, &cosr, &sinr, &r, _state); if( i>ll ) { e->ptr.p_double[i-1] = r; } f = cosr*d->ptr.p_double[i]+sinr*e->ptr.p_double[i]; e->ptr.p_double[i] = cosr*e->ptr.p_double[i]-sinr*d->ptr.p_double[i]; g = sinr*d->ptr.p_double[i+1]; d->ptr.p_double[i+1] = cosr*d->ptr.p_double[i+1]; generaterotation(f, g, &cosl, &sinl, &r, _state); d->ptr.p_double[i] = r; f = cosl*e->ptr.p_double[i]+sinl*d->ptr.p_double[i+1]; d->ptr.p_double[i+1] = cosl*d->ptr.p_double[i+1]-sinl*e->ptr.p_double[i]; if( iptr.p_double[i+1]; e->ptr.p_double[i+1] = cosl*e->ptr.p_double[i+1]; } work0.ptr.p_double[i-ll+1] = cosr; work1.ptr.p_double[i-ll+1] = sinr; work2.ptr.p_double[i-ll+1] = cosl; work3.ptr.p_double[i-ll+1] = sinl; } e->ptr.p_double[m-1] = f; /* * Update singular vectors */ if( ncvt>0 ) { applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); } if( nru>0 ) { applyrotationsfromtheleft(fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work2, &work3, &ut, &utemp, _state); } if( ncc>0 ) { applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); } /* * Test convergence */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh) ) { e->ptr.p_double[m-1] = (double)(0); } } else { /* * Chase bulge from bottom to top * Save cosines and sines for later singular vector updates */ f = (ae_fabs(d->ptr.p_double[m], _state)-shift)*(bdsvd_extsignbdsqr((double)(1), d->ptr.p_double[m], _state)+shift/d->ptr.p_double[m]); g = e->ptr.p_double[m-1]; for(i=m; i>=ll+1; i--) { generaterotation(f, g, &cosr, &sinr, &r, _state); if( iptr.p_double[i] = r; } f = cosr*d->ptr.p_double[i]+sinr*e->ptr.p_double[i-1]; e->ptr.p_double[i-1] = cosr*e->ptr.p_double[i-1]-sinr*d->ptr.p_double[i]; g = sinr*d->ptr.p_double[i-1]; d->ptr.p_double[i-1] = cosr*d->ptr.p_double[i-1]; generaterotation(f, g, &cosl, &sinl, &r, _state); d->ptr.p_double[i] = r; f = cosl*e->ptr.p_double[i-1]+sinl*d->ptr.p_double[i-1]; d->ptr.p_double[i-1] = cosl*d->ptr.p_double[i-1]-sinl*e->ptr.p_double[i-1]; if( i>ll+1 ) { g = sinl*e->ptr.p_double[i-2]; e->ptr.p_double[i-2] = cosl*e->ptr.p_double[i-2]; } work0.ptr.p_double[i-ll] = cosr; work1.ptr.p_double[i-ll] = -sinr; work2.ptr.p_double[i-ll] = cosl; work3.ptr.p_double[i-ll] = -sinl; } e->ptr.p_double[ll] = f; /* * Test convergence */ if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh) ) { e->ptr.p_double[ll] = (double)(0); } /* * Update singular vectors if desired */ if( ncvt>0 ) { applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); } if( nru>0 ) { applyrotationsfromtheleft(!fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); } if( ncc>0 ) { applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); } } } /* * QR iteration finished, go back and check convergence */ continue; } /* * All singular values converged, so make them positive */ for(i=1; i<=n; i++) { if( ae_fp_less(d->ptr.p_double[i],(double)(0)) ) { d->ptr.p_double[i] = -d->ptr.p_double[i]; /* * Change sign of singular vectors, if desired */ if( ncvt>0 ) { ae_v_muld(&vt->ptr.pp_double[i+vstart-1][vstart], 1, ae_v_len(vstart,vend), -1); } } } /* * Sort the singular values into decreasing order (insertion sort on * singular values, but only one transposition per singular vector) */ for(i=1; i<=n-1; i++) { /* * Scan for smallest D(I) */ isub = 1; smin = d->ptr.p_double[1]; for(j=2; j<=n+1-i; j++) { if( ae_fp_less_eq(d->ptr.p_double[j],smin) ) { isub = j; smin = d->ptr.p_double[j]; } } if( isub!=n+1-i ) { /* * Swap singular values and vectors */ d->ptr.p_double[isub] = d->ptr.p_double[n+1-i]; d->ptr.p_double[n+1-i] = smin; if( ncvt>0 ) { j = n+1-i; ae_v_move(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[isub+vstart-1][vstart], 1, ae_v_len(vstart,vend)); ae_v_move(&vt->ptr.pp_double[isub+vstart-1][vstart], 1, &vt->ptr.pp_double[j+vstart-1][vstart], 1, ae_v_len(vstart,vend)); ae_v_move(&vt->ptr.pp_double[j+vstart-1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); } if( nru>0 ) { j = n+1-i; ae_v_move(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[isub+ustart-1][ustart], 1, ae_v_len(ustart,uend)); ae_v_move(&ut.ptr.pp_double[isub+ustart-1][ustart], 1, &ut.ptr.pp_double[j+ustart-1][ustart], 1, ae_v_len(ustart,uend)); ae_v_move(&ut.ptr.pp_double[j+ustart-1][ustart], 1, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); } if( ncc>0 ) { j = n+1-i; ae_v_move(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[isub+cstart-1][cstart], 1, ae_v_len(cstart,cend)); ae_v_move(&c->ptr.pp_double[isub+cstart-1][cstart], 1, &c->ptr.pp_double[j+cstart-1][cstart], 1, ae_v_len(cstart,cend)); ae_v_move(&c->ptr.pp_double[j+cstart-1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); } } } /* * Copy U back from temporary storage */ if( nru>0 ) { rmatrixtranspose(n, nru, &ut, ustart, ustart, uu, ustart, ustart, _state); } ae_frame_leave(_state); return result; } static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state) { double result; if( ae_fp_greater_eq(b,(double)(0)) ) { result = ae_fabs(a, _state); } else { result = -ae_fabs(a, _state); } return result; } static void bdsvd_svd2x2(double f, double g, double h, double* ssmin, double* ssmax, ae_state *_state) { double aas; double at; double au; double c; double fa; double fhmn; double fhmx; double ga; double ha; *ssmin = 0; *ssmax = 0; fa = ae_fabs(f, _state); ga = ae_fabs(g, _state); ha = ae_fabs(h, _state); fhmn = ae_minreal(fa, ha, _state); fhmx = ae_maxreal(fa, ha, _state); if( ae_fp_eq(fhmn,(double)(0)) ) { *ssmin = (double)(0); if( ae_fp_eq(fhmx,(double)(0)) ) { *ssmax = ga; } else { *ssmax = ae_maxreal(fhmx, ga, _state)*ae_sqrt(1+ae_sqr(ae_minreal(fhmx, ga, _state)/ae_maxreal(fhmx, ga, _state), _state), _state); } } else { if( ae_fp_less(ga,fhmx) ) { aas = 1+fhmn/fhmx; at = (fhmx-fhmn)/fhmx; au = ae_sqr(ga/fhmx, _state); c = 2/(ae_sqrt(aas*aas+au, _state)+ae_sqrt(at*at+au, _state)); *ssmin = fhmn*c; *ssmax = fhmx/c; } else { au = fhmx/ga; if( ae_fp_eq(au,(double)(0)) ) { /* * Avoid possible harmful underflow if exponent range * asymmetric (true SSMIN may not underflow even if * AU underflows) */ *ssmin = fhmn*fhmx/ga; *ssmax = ga; } else { aas = 1+fhmn/fhmx; at = (fhmx-fhmn)/fhmx; c = 1/(ae_sqrt(1+ae_sqr(aas*au, _state), _state)+ae_sqrt(1+ae_sqr(at*au, _state), _state)); *ssmin = fhmn*c*au; *ssmin = *ssmin+(*ssmin); *ssmax = ga/(c+c); } } } } static void bdsvd_svdv2x2(double f, double g, double h, double* ssmin, double* ssmax, double* snr, double* csr, double* snl, double* csl, ae_state *_state) { ae_bool gasmal; ae_bool swp; ae_int_t pmax; double a; double clt; double crt; double d; double fa; double ft; double ga; double gt; double ha; double ht; double l; double m; double mm; double r; double s; double slt; double srt; double t; double temp; double tsign; double tt; double v; *ssmin = 0; *ssmax = 0; *snr = 0; *csr = 0; *snl = 0; *csl = 0; ft = f; fa = ae_fabs(ft, _state); ht = h; ha = ae_fabs(h, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ clt = (double)(0); crt = (double)(0); slt = (double)(0); srt = (double)(0); tsign = (double)(0); /* * PMAX points to the maximum absolute element of matrix * PMAX = 1 if F largest in absolute values * PMAX = 2 if G largest in absolute values * PMAX = 3 if H largest in absolute values */ pmax = 1; swp = ae_fp_greater(ha,fa); if( swp ) { /* * Now FA .ge. HA */ pmax = 3; temp = ft; ft = ht; ht = temp; temp = fa; fa = ha; ha = temp; } gt = g; ga = ae_fabs(gt, _state); if( ae_fp_eq(ga,(double)(0)) ) { /* * Diagonal matrix */ *ssmin = ha; *ssmax = fa; clt = (double)(1); crt = (double)(1); slt = (double)(0); srt = (double)(0); } else { gasmal = ae_true; if( ae_fp_greater(ga,fa) ) { pmax = 2; if( ae_fp_less(fa/ga,ae_machineepsilon) ) { /* * Case of very large GA */ gasmal = ae_false; *ssmax = ga; if( ae_fp_greater(ha,(double)(1)) ) { v = ga/ha; *ssmin = fa/v; } else { v = fa/ga; *ssmin = v*ha; } clt = (double)(1); slt = ht/gt; srt = (double)(1); crt = ft/gt; } } if( gasmal ) { /* * Normal case */ d = fa-ha; if( ae_fp_eq(d,fa) ) { l = (double)(1); } else { l = d/fa; } m = gt/ft; t = 2-l; mm = m*m; tt = t*t; s = ae_sqrt(tt+mm, _state); if( ae_fp_eq(l,(double)(0)) ) { r = ae_fabs(m, _state); } else { r = ae_sqrt(l*l+mm, _state); } a = 0.5*(s+r); *ssmin = ha/a; *ssmax = fa*a; if( ae_fp_eq(mm,(double)(0)) ) { /* * Note that M is very tiny */ if( ae_fp_eq(l,(double)(0)) ) { t = bdsvd_extsignbdsqr((double)(2), ft, _state)*bdsvd_extsignbdsqr((double)(1), gt, _state); } else { t = gt/bdsvd_extsignbdsqr(d, ft, _state)+m/t; } } else { t = (m/(s+t)+m/(r+l))*(1+a); } l = ae_sqrt(t*t+4, _state); crt = 2/l; srt = t/l; clt = (crt+srt*m)/a; v = ht/ft; slt = v*srt/a; } } if( swp ) { *csl = srt; *snl = crt; *csr = slt; *snr = clt; } else { *csl = clt; *snl = slt; *csr = crt; *snr = srt; } /* * Correct signs of SSMAX and SSMIN */ if( pmax==1 ) { tsign = bdsvd_extsignbdsqr((double)(1), *csr, _state)*bdsvd_extsignbdsqr((double)(1), *csl, _state)*bdsvd_extsignbdsqr((double)(1), f, _state); } if( pmax==2 ) { tsign = bdsvd_extsignbdsqr((double)(1), *snr, _state)*bdsvd_extsignbdsqr((double)(1), *csl, _state)*bdsvd_extsignbdsqr((double)(1), g, _state); } if( pmax==3 ) { tsign = bdsvd_extsignbdsqr((double)(1), *snr, _state)*bdsvd_extsignbdsqr((double)(1), *snl, _state)*bdsvd_extsignbdsqr((double)(1), h, _state); } *ssmax = bdsvd_extsignbdsqr(*ssmax, tsign, _state); *ssmin = bdsvd_extsignbdsqr(*ssmin, tsign*bdsvd_extsignbdsqr((double)(1), f, _state)*bdsvd_extsignbdsqr((double)(1), h, _state), _state); } /************************************************************************* Singular value decomposition of a rectangular matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm calculates the singular value decomposition of a matrix of size MxN: A = U * S * V^T The algorithm finds the singular values and, optionally, matrices U and V^T. The algorithm can find both first min(M,N) columns of matrix U and rows of matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM and NxN respectively). Take into account that the subroutine does not return matrix V but V^T. Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. UNeeded - 0, 1 or 2. See the description of the parameter U. VTNeeded - 0, 1 or 2. See the description of the parameter VT. AdditionalMemory - If the parameter: * equals 0, the algorithm doesnt use additional memory (lower requirements, lower performance). * equals 1, the algorithm uses additional memory of size min(M,N)*min(M,N) of real numbers. It often speeds up the algorithm. * equals 2, the algorithm uses additional memory of size M*min(M,N) of real numbers. It allows to get a maximum performance. The recommended value of the parameter is 2. Output parameters: W - contains singular values in descending order. U - if UNeeded=0, U isn't changed, the left singular vectors are not calculated. if Uneeded=1, U contains left singular vectors (first min(M,N) columns of matrix U). Array whose indexes range within [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U contains matrix U wholly. Array whose indexes range within [0..M-1, 0..M-1]. VT - if VTNeeded=0, VT isnt changed, the right singular vectors are not calculated. if VTNeeded=1, VT contains right singular vectors (first min(M,N) rows of matrix V^T). Array whose indexes range within [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT contains matrix V^T wholly. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ ae_bool rmatrixsvd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, /* Real */ ae_vector* w, /* Real */ ae_matrix* u, /* Real */ ae_matrix* vt, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector tauq; ae_vector taup; ae_vector tau; ae_vector e; ae_vector work; ae_matrix t2; ae_bool isupper; ae_int_t minmn; ae_int_t ncu; ae_int_t nrvt; ae_int_t nru; ae_int_t ncvt; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(w); ae_matrix_clear(u); ae_matrix_clear(vt); ae_vector_init(&tauq, 0, DT_REAL, _state); ae_vector_init(&taup, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_matrix_init(&t2, 0, 0, DT_REAL, _state); result = ae_true; if( m==0||n==0 ) { ae_frame_leave(_state); return result; } ae_assert(uneeded>=0&&uneeded<=2, "SVDDecomposition: wrong parameters!", _state); ae_assert(vtneeded>=0&&vtneeded<=2, "SVDDecomposition: wrong parameters!", _state); ae_assert(additionalmemory>=0&&additionalmemory<=2, "SVDDecomposition: wrong parameters!", _state); /* * initialize */ minmn = ae_minint(m, n, _state); ae_vector_set_length(w, minmn+1, _state); ncu = 0; nru = 0; if( uneeded==1 ) { nru = m; ncu = minmn; ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); } if( uneeded==2 ) { nru = m; ncu = m; ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); } nrvt = 0; ncvt = 0; if( vtneeded==1 ) { nrvt = minmn; ncvt = n; ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); } if( vtneeded==2 ) { nrvt = n; ncvt = n; ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); } /* * M much larger than N * Use bidiagonal reduction with QR-decomposition */ if( ae_fp_greater((double)(m),1.6*n) ) { if( uneeded==0 ) { /* * No left singular vectors to be computed */ rmatrixqr(a, m, n, &tau, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rmatrixbd(a, n, n, &tauq, &taup, _state); rmatrixbdunpackpt(a, n, n, &taup, nrvt, vt, _state); rmatrixbdunpackdiagonals(a, n, n, &isupper, w, &e, _state); result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, a, 0, vt, ncvt, _state); ae_frame_leave(_state); return result; } else { /* * Left singular vectors (may be full matrix U) to be computed */ rmatrixqr(a, m, n, &tau, _state); rmatrixqrunpackq(a, m, n, &tau, ncu, u, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rmatrixbd(a, n, n, &tauq, &taup, _state); rmatrixbdunpackpt(a, n, n, &taup, nrvt, vt, _state); rmatrixbdunpackdiagonals(a, n, n, &isupper, w, &e, _state); if( additionalmemory<1 ) { /* * No additional memory can be used */ rmatrixbdmultiplybyq(a, n, n, &tauq, u, m, n, ae_true, ae_false, _state); result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, m, a, 0, vt, ncvt, _state); } else { /* * Large U. Transforming intermediate matrix T2 */ ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); rmatrixbdunpackq(a, n, n, &tauq, n, &t2, _state); copymatrix(u, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1, _state); inplacetranspose(&t2, 0, n-1, 0, n-1, &work, _state); result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, &t2, n, vt, ncvt, _state); rmatrixgemm(m, n, n, 1.0, a, 0, 0, 0, &t2, 0, 0, 1, 0.0, u, 0, 0, _state); } ae_frame_leave(_state); return result; } } /* * N much larger than M * Use bidiagonal reduction with LQ-decomposition */ if( ae_fp_greater((double)(n),1.6*m) ) { if( vtneeded==0 ) { /* * No right singular vectors to be computed */ rmatrixlq(a, m, n, &tau, _state); for(i=0; i<=m-1; i++) { for(j=i+1; j<=m-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rmatrixbd(a, m, m, &tauq, &taup, _state); rmatrixbdunpackq(a, m, m, &tauq, ncu, u, _state); rmatrixbdunpackdiagonals(a, m, m, &isupper, w, &e, _state); ae_vector_set_length(&work, m+1, _state); inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, vt, 0, _state); inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); ae_frame_leave(_state); return result; } else { /* * Right singular vectors (may be full matrix VT) to be computed */ rmatrixlq(a, m, n, &tau, _state); rmatrixlqunpackq(a, m, n, &tau, nrvt, vt, _state); for(i=0; i<=m-1; i++) { for(j=i+1; j<=m-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rmatrixbd(a, m, m, &tauq, &taup, _state); rmatrixbdunpackq(a, m, m, &tauq, ncu, u, _state); rmatrixbdunpackdiagonals(a, m, m, &isupper, w, &e, _state); ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); if( additionalmemory<1 ) { /* * No additional memory available */ rmatrixbdmultiplybyp(a, m, m, &taup, vt, m, n, ae_false, ae_true, _state); result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, vt, n, _state); } else { /* * Large VT. Transforming intermediate matrix T2 */ rmatrixbdunpackpt(a, m, m, &taup, m, &t2, _state); result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, &t2, m, _state); copymatrix(vt, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1, _state); rmatrixgemm(m, n, m, 1.0, &t2, 0, 0, 0, a, 0, 0, 0, 0.0, vt, 0, 0, _state); } inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); ae_frame_leave(_state); return result; } } /* * M<=N * We can use inplace transposition of U to get rid of columnwise operations */ if( m<=n ) { rmatrixbd(a, m, n, &tauq, &taup, _state); rmatrixbdunpackq(a, m, n, &tauq, ncu, u, _state); rmatrixbdunpackpt(a, m, n, &taup, nrvt, vt, _state); rmatrixbdunpackdiagonals(a, m, n, &isupper, w, &e, _state); ae_vector_set_length(&work, m+1, _state); inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, a, 0, u, nru, vt, ncvt, _state); inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); ae_frame_leave(_state); return result; } /* * Simple bidiagonal reduction */ rmatrixbd(a, m, n, &tauq, &taup, _state); rmatrixbdunpackq(a, m, n, &tauq, ncu, u, _state); rmatrixbdunpackpt(a, m, n, &taup, nrvt, vt, _state); rmatrixbdunpackdiagonals(a, m, n, &isupper, w, &e, _state); if( additionalmemory<2||uneeded==0 ) { /* * We cant use additional memory or there is no need in such operations */ result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, nru, a, 0, vt, ncvt, _state); } else { /* * We can use additional memory */ ae_matrix_set_length(&t2, minmn-1+1, m-1+1, _state); copyandtranspose(u, 0, m-1, 0, minmn-1, &t2, 0, minmn-1, 0, m-1, _state); result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, 0, &t2, m, vt, ncvt, _state); copyandtranspose(&t2, 0, minmn-1, 0, m-1, u, 0, m-1, 0, minmn-1, _state); } ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_rmatrixsvd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, /* Real */ ae_vector* w, /* Real */ ae_matrix* u, /* Real */ ae_matrix* vt, ae_state *_state) { return rmatrixsvd(a,m,n,uneeded,vtneeded,additionalmemory,w,u,vt, _state); } /************************************************************************* Finding the eigenvalues and eigenvectors of a symmetric matrix The algorithm finds eigen pairs of a symmetric matrix by reducing it to tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpper - storage format. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixevd(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, /* Real */ ae_vector* d, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector tau; ae_vector e; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(d); ae_matrix_clear(z); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_assert(zneeded==0||zneeded==1, "SMatrixEVD: incorrect ZNeeded", _state); smatrixtd(a, n, isupper, &tau, d, &e, _state); if( zneeded==1 ) { smatrixtdunpackq(a, n, isupper, &tau, z, _state); } result = smatrixtdevd(d, &e, n, zneeded, z, _state); ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric matrix in a given half open interval (A, B] by using a bisection and inverse iteration Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half open interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval (M>=0). W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixevdr(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, double b1, double b2, ae_int_t* m, /* Real */ ae_vector* w, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector tau; ae_vector e; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *m = 0; ae_vector_clear(w); ae_matrix_clear(z); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_assert(zneeded==0||zneeded==1, "SMatrixTDEVDR: incorrect ZNeeded", _state); smatrixtd(a, n, isupper, &tau, w, &e, _state); if( zneeded==1 ) { smatrixtdunpackq(a, n, isupper, &tau, z, _state); } result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, z, _state); ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a symmetric matrix with given indexes by using bisection and inverse iteration methods. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixevdi(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* w, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector tau; ae_vector e; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(w); ae_matrix_clear(z); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_assert(zneeded==0||zneeded==1, "SMatrixEVDI: incorrect ZNeeded", _state); smatrixtd(a, n, isupper, &tau, w, &e, _state); if( zneeded==1 ) { smatrixtdunpackq(a, n, isupper, &tau, z, _state); } result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, z, _state); ae_frame_leave(_state); return result; } /************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/ ae_bool hmatrixevd(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, /* Real */ ae_vector* d, /* Complex */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector tau; ae_vector e; ae_matrix t; ae_matrix qz; ae_matrix q; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(d); ae_matrix_clear(z); ae_vector_init(&tau, 0, DT_COMPLEX, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_matrix_init(&qz, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_assert(zneeded==0||zneeded==1, "HermitianEVD: incorrect ZNeeded", _state); /* * Reduce to tridiagonal form */ hmatrixtd(a, n, isupper, &tau, d, &e, _state); if( zneeded==1 ) { hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); zneeded = 2; } /* * TDEVD */ result = smatrixtdevd(d, &e, n, zneeded, &t, _state); /* * Eigenvectors are needed * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T */ if( result&&zneeded!=0 ) { ae_matrix_set_length(z, n, n, _state); ae_matrix_set_length(&qz, n, 2*n, _state); /* * Calculate Re(Q)*T */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { qz.ptr.pp_double[i][j] = q.ptr.pp_complex[i][j].x; } } rmatrixgemm(n, n, n, 1.0, &qz, 0, 0, 0, &t, 0, 0, 0, 0.0, &qz, 0, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z->ptr.pp_complex[i][j].x = qz.ptr.pp_double[i][n+j]; } } /* * Calculate Im(Q)*T */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { qz.ptr.pp_double[i][j] = q.ptr.pp_complex[i][j].y; } } rmatrixgemm(n, n, n, 1.0, &qz, 0, 0, 0, &t, 0, 0, 0, 0.0, &qz, 0, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z->ptr.pp_complex[i][j].y = qz.ptr.pp_double[i][n+j]; } } } ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian matrix in a given half-interval (A, B] by using a bisection and inverse iteration Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half-interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval, M>=0 W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ ae_bool hmatrixevdr(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, double b1, double b2, ae_int_t* m, /* Real */ ae_vector* w, /* Complex */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_matrix q; ae_matrix t; ae_vector tau; ae_vector e; ae_vector work; ae_int_t i; ae_int_t k; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *m = 0; ae_vector_clear(w); ae_matrix_clear(z); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_COMPLEX, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsInInterval: incorrect ZNeeded", _state); /* * Reduce to tridiagonal form */ hmatrixtd(a, n, isupper, &tau, w, &e, _state); if( zneeded==1 ) { hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); zneeded = 2; } /* * Bisection and inverse iteration */ result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, &t, _state); /* * Eigenvectors are needed * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T */ if( (result&&zneeded!=0)&&*m!=0 ) { ae_vector_set_length(&work, *m-1+1, _state); ae_matrix_set_length(z, n-1+1, *m-1+1, _state); for(i=0; i<=n-1; i++) { /* * Calculate real part */ for(k=0; k<=*m-1; k++) { work.ptr.p_double[k] = (double)(0); } for(k=0; k<=n-1; k++) { v = q.ptr.pp_complex[i][k].x; ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); } for(k=0; k<=*m-1; k++) { z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; } /* * Calculate imaginary part */ for(k=0; k<=*m-1; k++) { work.ptr.p_double[k] = (double)(0); } for(k=0; k<=n-1; k++) { v = q.ptr.pp_complex[i][k].y; ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); } for(k=0; k<=*m-1; k++) { z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; } } } ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a Hermitian matrix with given indexes by using bisection and inverse iteration methods Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ ae_bool hmatrixevdi(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* w, /* Complex */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_matrix q; ae_matrix t; ae_vector tau; ae_vector e; ae_vector work; ae_int_t i; ae_int_t k; double v; ae_int_t m; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(w); ae_matrix_clear(z); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_COMPLEX, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded", _state); /* * Reduce to tridiagonal form */ hmatrixtd(a, n, isupper, &tau, w, &e, _state); if( zneeded==1 ) { hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); zneeded = 2; } /* * Bisection and inverse iteration */ result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, &t, _state); /* * Eigenvectors are needed * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T */ m = i2-i1+1; if( result&&zneeded!=0 ) { ae_vector_set_length(&work, m-1+1, _state); ae_matrix_set_length(z, n-1+1, m-1+1, _state); for(i=0; i<=n-1; i++) { /* * Calculate real part */ for(k=0; k<=m-1; k++) { work.ptr.p_double[k] = (double)(0); } for(k=0; k<=n-1; k++) { v = q.ptr.pp_complex[i][k].x; ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); } for(k=0; k<=m-1; k++) { z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; } /* * Calculate imaginary part */ for(k=0; k<=m-1; k++) { work.ptr.p_double[k] = (double)(0); } for(k=0; k<=n-1; k++) { v = q.ptr.pp_complex[i][k].y; ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); } for(k=0; k<=m-1; k++) { z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; } } } ae_frame_leave(_state); return result; } /************************************************************************* Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by using an QL/QR algorithm with implicit shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix; * 2, the eigenvectors of a tridiagonal matrix replace the square matrix Z; * 3, matrix Z contains the first row of the eigenvectors matrix. Z - if ZNeeded=1, Z contains the square matrix by which the eigenvectors are multiplied. Array whose indexes range within [0..N-1, 0..N-1]. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the product of a given matrix (from the left) and the eigenvectors matrix (from the right); * 2, Z contains the eigenvectors. * 3, Z contains the first row of the eigenvectors matrix. If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. In that case, the eigenvectors are stored in the matrix columns. If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ ae_bool smatrixtdevd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_vector d1; ae_vector e1; ae_vector ex; ae_matrix z1; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&e1, 0, DT_REAL, _state); ae_vector_init(&ex, 0, DT_REAL, _state); ae_matrix_init(&z1, 0, 0, DT_REAL, _state); ae_assert(n>=1, "SMatrixTDEVD: N<=0", _state); ae_assert(zneeded>=0&&zneeded<=3, "SMatrixTDEVD: incorrect ZNeeded", _state); result = ae_false; /* * Preprocess Z: make ZNeeded equal to 0, 1 or 3. * Ensure that memory for Z is allocated. */ if( zneeded==2 ) { /* * Load identity to Z */ rmatrixsetlengthatleast(z, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z->ptr.pp_double[i][j] = 0.0; } z->ptr.pp_double[i][i] = 1.0; } zneeded = 1; } if( zneeded==3 ) { /* * Allocate memory */ rmatrixsetlengthatleast(z, 1, n, _state); } /* * Try to solve problem with MKL */ ae_vector_set_length(&ex, n, _state); for(i=0; i<=n-2; i++) { ex.ptr.p_double[i] = e->ptr.p_double[i]; } if( smatrixtdevdmkl(d, &ex, n, zneeded, z, &result, _state) ) { ae_frame_leave(_state); return result; } /* * Prepare 1-based task */ ae_vector_set_length(&d1, n+1, _state); ae_vector_set_length(&e1, n+1, _state); ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); if( n>1 ) { ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); } if( zneeded==1 ) { ae_matrix_set_length(&z1, n+1, n+1, _state); for(i=1; i<=n; i++) { ae_v_move(&z1.ptr.pp_double[i][1], 1, &z->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); } } /* * Solve 1-based task */ result = evd_tridiagonalevd(&d1, &e1, n, zneeded, &z1, _state); if( !result ) { ae_frame_leave(_state); return result; } /* * Convert back to 0-based result */ ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); if( zneeded!=0 ) { if( zneeded==1 ) { for(i=1; i<=n; i++) { ae_v_move(&z->ptr.pp_double[i-1][0], 1, &z1.ptr.pp_double[i][1], 1, ae_v_len(0,n-1)); } ae_frame_leave(_state); return result; } if( zneeded==2 ) { ae_matrix_set_length(z, n-1+1, n-1+1, _state); for(i=1; i<=n; i++) { ae_v_move(&z->ptr.pp_double[i-1][0], 1, &z1.ptr.pp_double[i][1], 1, ae_v_len(0,n-1)); } ae_frame_leave(_state); return result; } if( zneeded==3 ) { ae_matrix_set_length(z, 0+1, n-1+1, _state); ae_v_move(&z->ptr.pp_double[0][0], 1, &z1.ptr.pp_double[1][1], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); return result; } ae_assert(ae_false, "SMatrixTDEVD: Incorrect ZNeeded!", _state); } ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a given half-interval (A, B] by using bisection and inverse iteration. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix, N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. A, B - half-interval (A, B] to search eigenvalues in. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..M-1]. M - number of eigenvalues found in the given half-interval (M>=0). Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and NxM matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..M-1]. * 2, contains the matrix of the eigenvectors found. Array whose indexes range within [0..N-1, 0..M-1]. Result: True, if successful. In that case, M contains the number of eigenvalues in the given half-interval (could be equal to 0), D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 31.03.2008 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixtdevdr(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, double a, double b, ae_int_t* m, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_int_t errorcode; ae_int_t nsplit; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t cr; ae_vector iblock; ae_vector isplit; ae_vector ifail; ae_vector d1; ae_vector e1; ae_vector w; ae_matrix z2; ae_matrix z3; double v; ae_bool result; ae_frame_make(_state, &_frame_block); *m = 0; ae_vector_init(&iblock, 0, DT_INT, _state); ae_vector_init(&isplit, 0, DT_INT, _state); ae_vector_init(&ifail, 0, DT_INT, _state); ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&e1, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_matrix_init(&z2, 0, 0, DT_REAL, _state); ae_matrix_init(&z3, 0, 0, DT_REAL, _state); ae_assert(zneeded>=0&&zneeded<=2, "SMatrixTDEVDR: incorrect ZNeeded!", _state); /* * Special cases */ if( ae_fp_less_eq(b,a) ) { *m = 0; result = ae_true; ae_frame_leave(_state); return result; } if( n<=0 ) { *m = 0; result = ae_true; ae_frame_leave(_state); return result; } /* * Copy D,E to D1, E1 */ ae_vector_set_length(&d1, n+1, _state); ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); if( n>1 ) { ae_vector_set_length(&e1, n-1+1, _state); ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); } /* * No eigen vectors */ if( zneeded==0 ) { result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 1, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result||*m==0 ) { *m = 0; ae_frame_leave(_state); return result; } ae_vector_set_length(d, *m-1+1, _state); ae_v_move(&d->ptr.p_double[0], 1, &w.ptr.p_double[1], 1, ae_v_len(0,*m-1)); ae_frame_leave(_state); return result; } /* * Eigen vectors are multiplied by Z */ if( zneeded==1 ) { /* * Find eigen pairs */ result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result||*m==0 ) { *m = 0; ae_frame_leave(_state); return result; } evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); if( cr!=0 ) { *m = 0; result = ae_false; ae_frame_leave(_state); return result; } /* * Sort eigen values and vectors */ for(i=1; i<=*m; i++) { k = i; for(j=i; j<=*m; j++) { if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) { k = j; } } v = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = v; for(j=1; j<=n; j++) { v = z2.ptr.pp_double[j][i]; z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; z2.ptr.pp_double[j][k] = v; } } /* * Transform Z2 and overwrite Z */ ae_matrix_set_length(&z3, *m+1, n+1, _state); for(i=1; i<=*m; i++) { ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); } for(i=1; i<=n; i++) { for(j=1; j<=*m; j++) { v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); z2.ptr.pp_double[i][j] = v; } } ae_matrix_set_length(z, n-1+1, *m-1+1, _state); for(i=1; i<=*m; i++) { ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); } /* * Store W */ ae_vector_set_length(d, *m-1+1, _state); for(i=1; i<=*m; i++) { d->ptr.p_double[i-1] = w.ptr.p_double[i]; } ae_frame_leave(_state); return result; } /* * Eigen vectors are stored in Z */ if( zneeded==2 ) { /* * Find eigen pairs */ result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result||*m==0 ) { *m = 0; ae_frame_leave(_state); return result; } evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); if( cr!=0 ) { *m = 0; result = ae_false; ae_frame_leave(_state); return result; } /* * Sort eigen values and vectors */ for(i=1; i<=*m; i++) { k = i; for(j=i; j<=*m; j++) { if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) { k = j; } } v = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = v; for(j=1; j<=n; j++) { v = z2.ptr.pp_double[j][i]; z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; z2.ptr.pp_double[j][k] = v; } } /* * Store W */ ae_vector_set_length(d, *m-1+1, _state); for(i=1; i<=*m; i++) { d->ptr.p_double[i-1] = w.ptr.p_double[i]; } ae_matrix_set_length(z, n-1+1, *m-1+1, _state); for(i=1; i<=*m; i++) { ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); } ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Subroutine for finding tridiagonal matrix eigenvalues/vectors with given indexes (in ascending order) by using the bisection and inverse iteraion. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix. N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and Nx(I2-I1) matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..I2-I1]. * 2, contains the matrix of the eigenvalues found. Array whose indexes range within [0..N-1, 0..I2-I1]. Result: True, if successful. In that case, D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 25.12.2005 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixtdevdi(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, ae_int_t i1, ae_int_t i2, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_int_t errorcode; ae_int_t nsplit; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t m; ae_int_t cr; ae_vector iblock; ae_vector isplit; ae_vector ifail; ae_vector w; ae_vector d1; ae_vector e1; ae_matrix z2; ae_matrix z3; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&iblock, 0, DT_INT, _state); ae_vector_init(&isplit, 0, DT_INT, _state); ae_vector_init(&ifail, 0, DT_INT, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&e1, 0, DT_REAL, _state); ae_matrix_init(&z2, 0, 0, DT_REAL, _state); ae_matrix_init(&z3, 0, 0, DT_REAL, _state); ae_assert((0<=i1&&i1<=i2)&&i2ptr.p_double[0], 1, ae_v_len(1,n)); if( n>1 ) { ae_vector_set_length(&e1, n-1+1, _state); ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); } /* * No eigen vectors */ if( zneeded==0 ) { result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 1, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result ) { ae_frame_leave(_state); return result; } if( m!=i2-i1+1 ) { result = ae_false; ae_frame_leave(_state); return result; } ae_vector_set_length(d, m-1+1, _state); for(i=1; i<=m; i++) { d->ptr.p_double[i-1] = w.ptr.p_double[i]; } ae_frame_leave(_state); return result; } /* * Eigen vectors are multiplied by Z */ if( zneeded==1 ) { /* * Find eigen pairs */ result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result ) { ae_frame_leave(_state); return result; } if( m!=i2-i1+1 ) { result = ae_false; ae_frame_leave(_state); return result; } evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); if( cr!=0 ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Sort eigen values and vectors */ for(i=1; i<=m; i++) { k = i; for(j=i; j<=m; j++) { if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) { k = j; } } v = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = v; for(j=1; j<=n; j++) { v = z2.ptr.pp_double[j][i]; z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; z2.ptr.pp_double[j][k] = v; } } /* * Transform Z2 and overwrite Z */ ae_matrix_set_length(&z3, m+1, n+1, _state); for(i=1; i<=m; i++) { ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); } for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); z2.ptr.pp_double[i][j] = v; } } ae_matrix_set_length(z, n-1+1, m-1+1, _state); for(i=1; i<=m; i++) { ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); } /* * Store W */ ae_vector_set_length(d, m-1+1, _state); for(i=1; i<=m; i++) { d->ptr.p_double[i-1] = w.ptr.p_double[i]; } ae_frame_leave(_state); return result; } /* * Eigen vectors are stored in Z */ if( zneeded==2 ) { /* * Find eigen pairs */ result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); if( !result ) { ae_frame_leave(_state); return result; } if( m!=i2-i1+1 ) { result = ae_false; ae_frame_leave(_state); return result; } evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); if( cr!=0 ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Sort eigen values and vectors */ for(i=1; i<=m; i++) { k = i; for(j=i; j<=m; j++) { if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) { k = j; } } v = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = v; for(j=1; j<=n; j++) { v = z2.ptr.pp_double[j][i]; z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; z2.ptr.pp_double[j][k] = v; } } /* * Store Z */ ae_matrix_set_length(z, n-1+1, m-1+1, _state); for(i=1; i<=m; i++) { ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); } /* * Store W */ ae_vector_set_length(d, m-1+1, _state); for(i=1; i<=m; i++) { d->ptr.p_double[i-1] = w.ptr.p_double[i]; } ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Speed-up provided by MKL for this particular problem (EVD) ! is really high, because MKL uses combination of (a) better low-level ! optimizations, and (b) better EVD algorithms. ! ! On one particular SSE-capable machine for N=1024, commercial MKL- ! -capable ALGLIB was: ! * 7-10 times faster than open source "generic C" version ! * 15-18 times faster than "pure C#" version ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm finds eigenvalues and eigenvectors of a general matrix by using the QR algorithm with multiple shifts. The algorithm can find eigenvalues and both left and right eigenvectors. The right eigenvector is a vector x such that A*x = w*x, and the left eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex conjugate transposition of vector y). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. VNeeded - flag controlling whether eigenvectors are needed or not. If VNeeded is equal to: * 0, eigenvectors are not returned; * 1, right eigenvectors are returned; * 2, left eigenvectors are returned; * 3, both left and right eigenvectors are returned. Output parameters: WR - real parts of eigenvalues. Array whose index ranges within [0..N-1]. WR - imaginary parts of eigenvalues. Array whose index ranges within [0..N-1]. VL, VR - arrays of left and right eigenvectors (if they are needed). If WI[i]=0, the respective eigenvalue is a real number, and it corresponds to the column number I of matrices VL/VR. If WI[i]>0, we have a pair of complex conjugate numbers with positive and negative imaginary parts: the first eigenvalue WR[i] + sqrt(-1)*WI[i]; the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; WI[i]>0 WI[i+1] = -WI[i] < 0 In that case, the eigenvector corresponding to the first eigenvalue is located in i and i+1 columns of matrices VL/VR (the column number i contains the real part, and the column number i+1 contains the imaginary part), and the vector corresponding to the second eigenvalue is a complex conjugate to the first vector. Arrays whose indexes range within [0..N-1, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm has not converged. Note 1: Some users may ask the following question: what if WI[N-1]>0? WI[N] must contain an eigenvalue which is complex conjugate to the N-th eigenvalue, but the array has only size N? The answer is as follows: such a situation cannot occur because the algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is strictly less than N-1. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms of linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. See also the InternalTREVC subroutine. The algorithm is based on the LAPACK 3.0 library. *************************************************************************/ ae_bool rmatrixevd(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t vneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_matrix a1; ae_matrix vl1; ae_matrix vr1; ae_matrix s1; ae_matrix s; ae_matrix dummy; ae_vector wr1; ae_vector wi1; ae_vector tau; ae_int_t i; ae_int_t info; ae_vector sel1; ae_int_t m1; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(wr); ae_vector_clear(wi); ae_matrix_clear(vl); ae_matrix_clear(vr); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&vl1, 0, 0, DT_REAL, _state); ae_matrix_init(&vr1, 0, 0, DT_REAL, _state); ae_matrix_init(&s1, 0, 0, DT_REAL, _state); ae_matrix_init(&s, 0, 0, DT_REAL, _state); ae_matrix_init(&dummy, 0, 0, DT_REAL, _state); ae_vector_init(&wr1, 0, DT_REAL, _state); ae_vector_init(&wi1, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&sel1, 0, DT_BOOL, _state); ae_assert(vneeded>=0&&vneeded<=3, "RMatrixEVD: incorrect VNeeded!", _state); if( vneeded==0 ) { /* * Eigen values only */ rmatrixhessenberg(a, n, &tau, _state); rmatrixinternalschurdecomposition(a, n, 0, 0, wr, wi, &dummy, &info, _state); result = info==0; ae_frame_leave(_state); return result; } /* * Eigen values and vectors */ rmatrixhessenberg(a, n, &tau, _state); rmatrixhessenbergunpackq(a, n, &tau, &s, _state); rmatrixinternalschurdecomposition(a, n, 1, 1, wr, wi, &s, &info, _state); result = info==0; if( !result ) { ae_frame_leave(_state); return result; } if( vneeded==1||vneeded==3 ) { ae_matrix_set_length(vr, n, n, _state); for(i=0; i<=n-1; i++) { ae_v_move(&vr->ptr.pp_double[i][0], 1, &s.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } if( vneeded==2||vneeded==3 ) { ae_matrix_set_length(vl, n, n, _state); for(i=0; i<=n-1; i++) { ae_v_move(&vl->ptr.pp_double[i][0], 1, &s.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } evd_rmatrixinternaltrevc(a, n, vneeded, 1, &sel1, vl, vr, &m1, &info, _state); result = info==0; ae_frame_leave(_state); return result; } static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_int_t maxit; ae_int_t i; ae_int_t ii; ae_int_t iscale; ae_int_t j; ae_int_t jtot; ae_int_t k; ae_int_t t; ae_int_t l; ae_int_t l1; ae_int_t lend; ae_int_t lendm1; ae_int_t lendp1; ae_int_t lendsv; ae_int_t lm1; ae_int_t lsv; ae_int_t m; ae_int_t mm1; ae_int_t nm1; ae_int_t nmaxit; ae_int_t tmpint; double anorm; double b; double c; double eps; double eps2; double f; double g; double p; double r; double rt1; double rt2; double s; double safmax; double safmin; double ssfmax; double ssfmin; double tst; double tmp; ae_vector work1; ae_vector work2; ae_vector workc; ae_vector works; ae_vector wtemp; ae_bool gotoflag; ae_int_t zrows; ae_bool wastranspose; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_init(&work1, 0, DT_REAL, _state); ae_vector_init(&work2, 0, DT_REAL, _state); ae_vector_init(&workc, 0, DT_REAL, _state); ae_vector_init(&works, 0, DT_REAL, _state); ae_vector_init(&wtemp, 0, DT_REAL, _state); ae_assert(zneeded>=0&&zneeded<=3, "TridiagonalEVD: Incorrent ZNeeded", _state); /* * Quick return if possible */ if( zneeded<0||zneeded>3 ) { result = ae_false; ae_frame_leave(_state); return result; } result = ae_true; if( n==0 ) { ae_frame_leave(_state); return result; } if( n==1 ) { if( zneeded==2||zneeded==3 ) { ae_matrix_set_length(z, 1+1, 1+1, _state); z->ptr.pp_double[1][1] = (double)(1); } ae_frame_leave(_state); return result; } maxit = 30; /* * Initialize arrays */ ae_vector_set_length(&wtemp, n+1, _state); ae_vector_set_length(&work1, n-1+1, _state); ae_vector_set_length(&work2, n-1+1, _state); ae_vector_set_length(&workc, n+1, _state); ae_vector_set_length(&works, n+1, _state); /* * Determine the unit roundoff and over/underflow thresholds. */ eps = ae_machineepsilon; eps2 = ae_sqr(eps, _state); safmin = ae_minrealnumber; safmax = ae_maxrealnumber; ssfmax = ae_sqrt(safmax, _state)/3; ssfmin = ae_sqrt(safmin, _state)/eps2; /* * Prepare Z * * Here we are using transposition to get rid of column operations * */ wastranspose = ae_false; zrows = 0; if( zneeded==1 ) { zrows = n; } if( zneeded==2 ) { zrows = n; } if( zneeded==3 ) { zrows = 1; } if( zneeded==1 ) { wastranspose = ae_true; inplacetranspose(z, 1, n, 1, n, &wtemp, _state); } if( zneeded==2 ) { wastranspose = ae_true; ae_matrix_set_length(z, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { z->ptr.pp_double[i][j] = (double)(1); } else { z->ptr.pp_double[i][j] = (double)(0); } } } } if( zneeded==3 ) { wastranspose = ae_false; ae_matrix_set_length(z, 1+1, n+1, _state); for(j=1; j<=n; j++) { if( j==1 ) { z->ptr.pp_double[1][j] = (double)(1); } else { z->ptr.pp_double[1][j] = (double)(0); } } } nmaxit = n*maxit; jtot = 0; /* * Determine where the matrix splits and choose QL or QR iteration * for each block, according to whether top or bottom diagonal * element is smaller. */ l1 = 1; nm1 = n-1; for(;;) { if( l1>n ) { break; } if( l1>1 ) { e->ptr.p_double[l1-1] = (double)(0); } gotoflag = ae_false; m = l1; if( l1<=nm1 ) { for(m=l1; m<=nm1; m++) { tst = ae_fabs(e->ptr.p_double[m], _state); if( ae_fp_eq(tst,(double)(0)) ) { gotoflag = ae_true; break; } if( ae_fp_less_eq(tst,ae_sqrt(ae_fabs(d->ptr.p_double[m], _state), _state)*ae_sqrt(ae_fabs(d->ptr.p_double[m+1], _state), _state)*eps) ) { e->ptr.p_double[m] = (double)(0); gotoflag = ae_true; break; } } } if( !gotoflag ) { m = n; } /* * label 30: */ l = l1; lsv = l; lend = m; lendsv = lend; l1 = m+1; if( lend==l ) { continue; } /* * Scale submatrix in rows and columns L to LEND */ if( l==lend ) { anorm = ae_fabs(d->ptr.p_double[l], _state); } else { anorm = ae_maxreal(ae_fabs(d->ptr.p_double[l], _state)+ae_fabs(e->ptr.p_double[l], _state), ae_fabs(e->ptr.p_double[lend-1], _state)+ae_fabs(d->ptr.p_double[lend], _state), _state); for(i=l+1; i<=lend-1; i++) { anorm = ae_maxreal(anorm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i-1], _state), _state); } } iscale = 0; if( ae_fp_eq(anorm,(double)(0)) ) { continue; } if( ae_fp_greater(anorm,ssfmax) ) { iscale = 1; tmp = ssfmax/anorm; tmpint = lend-1; ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); ae_v_muld(&e->ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); } if( ae_fp_less(anorm,ssfmin) ) { iscale = 2; tmp = ssfmin/anorm; tmpint = lend-1; ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); ae_v_muld(&e->ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); } /* * Choose between QL and QR iteration */ if( ae_fp_less(ae_fabs(d->ptr.p_double[lend], _state),ae_fabs(d->ptr.p_double[l], _state)) ) { lend = lsv; l = lendsv; } if( lend>l ) { /* * QL Iteration * * Look for small subdiagonal element. */ for(;;) { gotoflag = ae_false; if( l!=lend ) { lendm1 = lend-1; for(m=l; m<=lendm1; m++) { tst = ae_sqr(ae_fabs(e->ptr.p_double[m], _state), _state); if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m+1], _state)+safmin) ) { gotoflag = ae_true; break; } } } if( !gotoflag ) { m = lend; } if( mptr.p_double[m] = (double)(0); } p = d->ptr.p_double[l]; if( m!=l ) { /* * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 * to compute its eigensystem. */ if( m==l+1 ) { if( zneeded>0 ) { evd_tdevdev2(d->ptr.p_double[l], e->ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, &c, &s, _state); work1.ptr.p_double[l] = c; work2.ptr.p_double[l] = s; workc.ptr.p_double[1] = work1.ptr.p_double[l]; works.ptr.p_double[1] = work2.ptr.p_double[l]; if( !wastranspose ) { applyrotationsfromtheright(ae_false, 1, zrows, l, l+1, &workc, &works, z, &wtemp, _state); } else { applyrotationsfromtheleft(ae_false, l, l+1, 1, zrows, &workc, &works, z, &wtemp, _state); } } else { evd_tdevde2(d->ptr.p_double[l], e->ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, _state); } d->ptr.p_double[l] = rt1; d->ptr.p_double[l+1] = rt2; e->ptr.p_double[l] = (double)(0); l = l+2; if( l<=lend ) { continue; } /* * GOTO 140 */ break; } if( jtot==nmaxit ) { /* * GOTO 140 */ break; } jtot = jtot+1; /* * Form shift. */ g = (d->ptr.p_double[l+1]-p)/(2*e->ptr.p_double[l]); r = evd_tdevdpythag(g, (double)(1), _state); g = d->ptr.p_double[m]-p+e->ptr.p_double[l]/(g+evd_tdevdextsign(r, g, _state)); s = (double)(1); c = (double)(1); p = (double)(0); /* * Inner loop */ mm1 = m-1; for(i=mm1; i>=l; i--) { f = s*e->ptr.p_double[i]; b = c*e->ptr.p_double[i]; generaterotation(g, f, &c, &s, &r, _state); if( i!=m-1 ) { e->ptr.p_double[i+1] = r; } g = d->ptr.p_double[i+1]-p; r = (d->ptr.p_double[i]-g)*s+2*c*b; p = s*r; d->ptr.p_double[i+1] = g+p; g = c*r-b; /* * If eigenvectors are desired, then save rotations. */ if( zneeded>0 ) { work1.ptr.p_double[i] = c; work2.ptr.p_double[i] = -s; } } /* * If eigenvectors are desired, then apply saved rotations. */ if( zneeded>0 ) { for(i=l; i<=m-1; i++) { workc.ptr.p_double[i-l+1] = work1.ptr.p_double[i]; works.ptr.p_double[i-l+1] = work2.ptr.p_double[i]; } if( !wastranspose ) { applyrotationsfromtheright(ae_false, 1, zrows, l, m, &workc, &works, z, &wtemp, _state); } else { applyrotationsfromtheleft(ae_false, l, m, 1, zrows, &workc, &works, z, &wtemp, _state); } } d->ptr.p_double[l] = d->ptr.p_double[l]-p; e->ptr.p_double[l] = g; continue; } /* * Eigenvalue found. */ d->ptr.p_double[l] = p; l = l+1; if( l<=lend ) { continue; } break; } } else { /* * QR Iteration * * Look for small superdiagonal element. */ for(;;) { gotoflag = ae_false; if( l!=lend ) { lendp1 = lend+1; for(m=l; m>=lendp1; m--) { tst = ae_sqr(ae_fabs(e->ptr.p_double[m-1], _state), _state); if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m-1], _state)+safmin) ) { gotoflag = ae_true; break; } } } if( !gotoflag ) { m = lend; } if( m>lend ) { e->ptr.p_double[m-1] = (double)(0); } p = d->ptr.p_double[l]; if( m!=l ) { /* * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 * to compute its eigensystem. */ if( m==l-1 ) { if( zneeded>0 ) { evd_tdevdev2(d->ptr.p_double[l-1], e->ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, &c, &s, _state); work1.ptr.p_double[m] = c; work2.ptr.p_double[m] = s; workc.ptr.p_double[1] = c; works.ptr.p_double[1] = s; if( !wastranspose ) { applyrotationsfromtheright(ae_true, 1, zrows, l-1, l, &workc, &works, z, &wtemp, _state); } else { applyrotationsfromtheleft(ae_true, l-1, l, 1, zrows, &workc, &works, z, &wtemp, _state); } } else { evd_tdevde2(d->ptr.p_double[l-1], e->ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, _state); } d->ptr.p_double[l-1] = rt1; d->ptr.p_double[l] = rt2; e->ptr.p_double[l-1] = (double)(0); l = l-2; if( l>=lend ) { continue; } break; } if( jtot==nmaxit ) { break; } jtot = jtot+1; /* * Form shift. */ g = (d->ptr.p_double[l-1]-p)/(2*e->ptr.p_double[l-1]); r = evd_tdevdpythag(g, (double)(1), _state); g = d->ptr.p_double[m]-p+e->ptr.p_double[l-1]/(g+evd_tdevdextsign(r, g, _state)); s = (double)(1); c = (double)(1); p = (double)(0); /* * Inner loop */ lm1 = l-1; for(i=m; i<=lm1; i++) { f = s*e->ptr.p_double[i]; b = c*e->ptr.p_double[i]; generaterotation(g, f, &c, &s, &r, _state); if( i!=m ) { e->ptr.p_double[i-1] = r; } g = d->ptr.p_double[i]-p; r = (d->ptr.p_double[i+1]-g)*s+2*c*b; p = s*r; d->ptr.p_double[i] = g+p; g = c*r-b; /* * If eigenvectors are desired, then save rotations. */ if( zneeded>0 ) { work1.ptr.p_double[i] = c; work2.ptr.p_double[i] = s; } } /* * If eigenvectors are desired, then apply saved rotations. */ if( zneeded>0 ) { for(i=m; i<=l-1; i++) { workc.ptr.p_double[i-m+1] = work1.ptr.p_double[i]; works.ptr.p_double[i-m+1] = work2.ptr.p_double[i]; } if( !wastranspose ) { applyrotationsfromtheright(ae_true, 1, zrows, m, l, &workc, &works, z, &wtemp, _state); } else { applyrotationsfromtheleft(ae_true, m, l, 1, zrows, &workc, &works, z, &wtemp, _state); } } d->ptr.p_double[l] = d->ptr.p_double[l]-p; e->ptr.p_double[lm1] = g; continue; } /* * Eigenvalue found. */ d->ptr.p_double[l] = p; l = l-1; if( l>=lend ) { continue; } break; } } /* * Undo scaling if necessary */ if( iscale==1 ) { tmp = anorm/ssfmax; tmpint = lendsv-1; ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); ae_v_muld(&e->ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); } if( iscale==2 ) { tmp = anorm/ssfmin; tmpint = lendsv-1; ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); ae_v_muld(&e->ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); } /* * Check for no convergence to an eigenvalue after a total * of N*MAXIT iterations. */ if( jtot>=nmaxit ) { result = ae_false; if( wastranspose ) { inplacetranspose(z, 1, n, 1, n, &wtemp, _state); } ae_frame_leave(_state); return result; } } /* * Order eigenvalues and eigenvectors. */ if( zneeded==0 ) { /* * Sort */ if( n==1 ) { ae_frame_leave(_state); return result; } if( n==2 ) { if( ae_fp_greater(d->ptr.p_double[1],d->ptr.p_double[2]) ) { tmp = d->ptr.p_double[1]; d->ptr.p_double[1] = d->ptr.p_double[2]; d->ptr.p_double[2] = tmp; } ae_frame_leave(_state); return result; } i = 2; do { t = i; while(t!=1) { k = t/2; if( ae_fp_greater_eq(d->ptr.p_double[k],d->ptr.p_double[t]) ) { t = 1; } else { tmp = d->ptr.p_double[k]; d->ptr.p_double[k] = d->ptr.p_double[t]; d->ptr.p_double[t] = tmp; t = k; } } i = i+1; } while(i<=n); i = n-1; do { tmp = d->ptr.p_double[i+1]; d->ptr.p_double[i+1] = d->ptr.p_double[1]; d->ptr.p_double[1] = tmp; t = 1; while(t!=0) { k = 2*t; if( k>i ) { t = 0; } else { if( kptr.p_double[k+1],d->ptr.p_double[k]) ) { k = k+1; } } if( ae_fp_greater_eq(d->ptr.p_double[t],d->ptr.p_double[k]) ) { t = 0; } else { tmp = d->ptr.p_double[k]; d->ptr.p_double[k] = d->ptr.p_double[t]; d->ptr.p_double[t] = tmp; t = k; } } } i = i-1; } while(i>=1); } else { /* * Use Selection Sort to minimize swaps of eigenvectors */ for(ii=2; ii<=n; ii++) { i = ii-1; k = i; p = d->ptr.p_double[i]; for(j=ii; j<=n; j++) { if( ae_fp_less(d->ptr.p_double[j],p) ) { k = j; p = d->ptr.p_double[j]; } } if( k!=i ) { d->ptr.p_double[k] = d->ptr.p_double[i]; d->ptr.p_double[i] = p; if( wastranspose ) { ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[i][1], 1, ae_v_len(1,n)); ae_v_move(&z->ptr.pp_double[i][1], 1, &z->ptr.pp_double[k][1], 1, ae_v_len(1,n)); ae_v_move(&z->ptr.pp_double[k][1], 1, &wtemp.ptr.p_double[1], 1, ae_v_len(1,n)); } else { ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[1][i], z->stride, ae_v_len(1,zrows)); ae_v_move(&z->ptr.pp_double[1][i], z->stride, &z->ptr.pp_double[1][k], z->stride, ae_v_len(1,zrows)); ae_v_move(&z->ptr.pp_double[1][k], z->stride, &wtemp.ptr.p_double[1], 1, ae_v_len(1,zrows)); } } } if( wastranspose ) { inplacetranspose(z, 1, n, 1, n, &wtemp, _state); } } ae_frame_leave(_state); return result; } /************************************************************************* DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix [ A B ] [ B C ]. On return, RT1 is the eigenvalue of larger absolute value, and RT2 is the eigenvalue of smaller absolute value. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ static void evd_tdevde2(double a, double b, double c, double* rt1, double* rt2, ae_state *_state) { double ab; double acmn; double acmx; double adf; double df; double rt; double sm; double tb; *rt1 = 0; *rt2 = 0; sm = a+c; df = a-c; adf = ae_fabs(df, _state); tb = b+b; ab = ae_fabs(tb, _state); if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) { acmx = a; acmn = c; } else { acmx = c; acmn = a; } if( ae_fp_greater(adf,ab) ) { rt = adf*ae_sqrt(1+ae_sqr(ab/adf, _state), _state); } else { if( ae_fp_less(adf,ab) ) { rt = ab*ae_sqrt(1+ae_sqr(adf/ab, _state), _state); } else { /* * Includes case AB=ADF=0 */ rt = ab*ae_sqrt((double)(2), _state); } } if( ae_fp_less(sm,(double)(0)) ) { *rt1 = 0.5*(sm-rt); /* * Order of execution important. * To get fully accurate smaller eigenvalue, * next line needs to be executed in higher precision. */ *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; } else { if( ae_fp_greater(sm,(double)(0)) ) { *rt1 = 0.5*(sm+rt); /* * Order of execution important. * To get fully accurate smaller eigenvalue, * next line needs to be executed in higher precision. */ *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; } else { /* * Includes case RT1 = RT2 = 0 */ *rt1 = 0.5*rt; *rt2 = -0.5*rt; } } } /************************************************************************* DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix [ A B ] [ B C ]. On return, RT1 is the eigenvalue of larger absolute value, RT2 is the eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right eigenvector for RT1, giving the decomposition [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ static void evd_tdevdev2(double a, double b, double c, double* rt1, double* rt2, double* cs1, double* sn1, ae_state *_state) { ae_int_t sgn1; ae_int_t sgn2; double ab; double acmn; double acmx; double acs; double adf; double cs; double ct; double df; double rt; double sm; double tb; double tn; *rt1 = 0; *rt2 = 0; *cs1 = 0; *sn1 = 0; /* * Compute the eigenvalues */ sm = a+c; df = a-c; adf = ae_fabs(df, _state); tb = b+b; ab = ae_fabs(tb, _state); if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) { acmx = a; acmn = c; } else { acmx = c; acmn = a; } if( ae_fp_greater(adf,ab) ) { rt = adf*ae_sqrt(1+ae_sqr(ab/adf, _state), _state); } else { if( ae_fp_less(adf,ab) ) { rt = ab*ae_sqrt(1+ae_sqr(adf/ab, _state), _state); } else { /* * Includes case AB=ADF=0 */ rt = ab*ae_sqrt((double)(2), _state); } } if( ae_fp_less(sm,(double)(0)) ) { *rt1 = 0.5*(sm-rt); sgn1 = -1; /* * Order of execution important. * To get fully accurate smaller eigenvalue, * next line needs to be executed in higher precision. */ *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; } else { if( ae_fp_greater(sm,(double)(0)) ) { *rt1 = 0.5*(sm+rt); sgn1 = 1; /* * Order of execution important. * To get fully accurate smaller eigenvalue, * next line needs to be executed in higher precision. */ *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; } else { /* * Includes case RT1 = RT2 = 0 */ *rt1 = 0.5*rt; *rt2 = -0.5*rt; sgn1 = 1; } } /* * Compute the eigenvector */ if( ae_fp_greater_eq(df,(double)(0)) ) { cs = df+rt; sgn2 = 1; } else { cs = df-rt; sgn2 = -1; } acs = ae_fabs(cs, _state); if( ae_fp_greater(acs,ab) ) { ct = -tb/cs; *sn1 = 1/ae_sqrt(1+ct*ct, _state); *cs1 = ct*(*sn1); } else { if( ae_fp_eq(ab,(double)(0)) ) { *cs1 = (double)(1); *sn1 = (double)(0); } else { tn = -cs/tb; *cs1 = 1/ae_sqrt(1+tn*tn, _state); *sn1 = tn*(*cs1); } } if( sgn1==sgn2 ) { tn = *cs1; *cs1 = -*sn1; *sn1 = tn; } } /************************************************************************* Internal routine *************************************************************************/ static double evd_tdevdpythag(double a, double b, ae_state *_state) { double result; if( ae_fp_less(ae_fabs(a, _state),ae_fabs(b, _state)) ) { result = ae_fabs(b, _state)*ae_sqrt(1+ae_sqr(a/b, _state), _state); } else { result = ae_fabs(a, _state)*ae_sqrt(1+ae_sqr(b/a, _state), _state); } return result; } /************************************************************************* Internal routine *************************************************************************/ static double evd_tdevdextsign(double a, double b, ae_state *_state) { double result; if( ae_fp_greater_eq(b,(double)(0)) ) { result = ae_fabs(a, _state); } else { result = -ae_fabs(a, _state); } return result; } static ae_bool evd_internalbisectioneigenvalues(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t irange, ae_int_t iorder, double vl, double vu, ae_int_t il, ae_int_t iu, double abstol, /* Real */ ae_vector* w, ae_int_t* m, ae_int_t* nsplit, /* Integer */ ae_vector* iblock, /* Integer */ ae_vector* isplit, ae_int_t* errorcode, ae_state *_state) { ae_frame _frame_block; ae_vector _d; ae_vector _e; double fudge; double relfac; ae_bool ncnvrg; ae_bool toofew; ae_int_t ib; ae_int_t ibegin; ae_int_t idiscl; ae_int_t idiscu; ae_int_t ie; ae_int_t iend; ae_int_t iinfo; ae_int_t im; ae_int_t iin; ae_int_t ioff; ae_int_t iout; ae_int_t itmax; ae_int_t iw; ae_int_t iwoff; ae_int_t j; ae_int_t itmp1; ae_int_t jb; ae_int_t jdisc; ae_int_t je; ae_int_t nwl; ae_int_t nwu; double atoli; double bnorm; double gl; double gu; double pivmin; double rtoli; double safemn; double tmp1; double tmp2; double tnorm; double ulp; double wkill; double wl; double wlu; double wu; double wul; double scalefactor; double t; ae_vector idumma; ae_vector work; ae_vector iwork; ae_vector ia1s2; ae_vector ra1s2; ae_matrix ra1s2x2; ae_matrix ia1s2x2; ae_vector ra1siin; ae_vector ra2siin; ae_vector ra3siin; ae_vector ra4siin; ae_matrix ra1siinx2; ae_matrix ia1siinx2; ae_vector iworkspace; ae_vector rworkspace; ae_int_t tmpi; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_d, d, _state); d = &_d; ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_clear(w); *m = 0; *nsplit = 0; ae_vector_clear(iblock); ae_vector_clear(isplit); *errorcode = 0; ae_vector_init(&idumma, 0, DT_INT, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&iwork, 0, DT_INT, _state); ae_vector_init(&ia1s2, 0, DT_INT, _state); ae_vector_init(&ra1s2, 0, DT_REAL, _state); ae_matrix_init(&ra1s2x2, 0, 0, DT_REAL, _state); ae_matrix_init(&ia1s2x2, 0, 0, DT_INT, _state); ae_vector_init(&ra1siin, 0, DT_REAL, _state); ae_vector_init(&ra2siin, 0, DT_REAL, _state); ae_vector_init(&ra3siin, 0, DT_REAL, _state); ae_vector_init(&ra4siin, 0, DT_REAL, _state); ae_matrix_init(&ra1siinx2, 0, 0, DT_REAL, _state); ae_matrix_init(&ia1siinx2, 0, 0, DT_INT, _state); ae_vector_init(&iworkspace, 0, DT_INT, _state); ae_vector_init(&rworkspace, 0, DT_REAL, _state); /* * Quick return if possible */ *m = 0; if( n==0 ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Get machine constants * NB is the minimum vector length for vector bisection, or 0 * if only scalar is to be done. */ fudge = (double)(2); relfac = (double)(2); safemn = ae_minrealnumber; ulp = 2*ae_machineepsilon; rtoli = ulp*relfac; ae_vector_set_length(&idumma, 1+1, _state); ae_vector_set_length(&work, 4*n+1, _state); ae_vector_set_length(&iwork, 3*n+1, _state); ae_vector_set_length(w, n+1, _state); ae_vector_set_length(iblock, n+1, _state); ae_vector_set_length(isplit, n+1, _state); ae_vector_set_length(&ia1s2, 2+1, _state); ae_vector_set_length(&ra1s2, 2+1, _state); ae_matrix_set_length(&ra1s2x2, 2+1, 2+1, _state); ae_matrix_set_length(&ia1s2x2, 2+1, 2+1, _state); ae_vector_set_length(&ra1siin, n+1, _state); ae_vector_set_length(&ra2siin, n+1, _state); ae_vector_set_length(&ra3siin, n+1, _state); ae_vector_set_length(&ra4siin, n+1, _state); ae_matrix_set_length(&ra1siinx2, n+1, 2+1, _state); ae_matrix_set_length(&ia1siinx2, n+1, 2+1, _state); ae_vector_set_length(&iworkspace, n+1, _state); ae_vector_set_length(&rworkspace, n+1, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ wlu = (double)(0); wul = (double)(0); /* * Check for Errors */ result = ae_false; *errorcode = 0; if( irange<=0||irange>=4 ) { *errorcode = -4; } if( iorder<=0||iorder>=3 ) { *errorcode = -5; } if( n<0 ) { *errorcode = -3; } if( irange==2&&ae_fp_greater_eq(vl,vu) ) { *errorcode = -6; } if( irange==3&&(il<1||il>ae_maxint(1, n, _state)) ) { *errorcode = -8; } if( irange==3&&(iun) ) { *errorcode = -9; } if( *errorcode!=0 ) { ae_frame_leave(_state); return result; } /* * Initialize error flags */ ncnvrg = ae_false; toofew = ae_false; /* * Simplifications: */ if( (irange==3&&il==1)&&iu==n ) { irange = 1; } /* * Special Case when N=1 */ if( n==1 ) { *nsplit = 1; isplit->ptr.p_int[1] = 1; if( irange==2&&(ae_fp_greater_eq(vl,d->ptr.p_double[1])||ae_fp_less(vu,d->ptr.p_double[1])) ) { *m = 0; } else { w->ptr.p_double[1] = d->ptr.p_double[1]; iblock->ptr.p_int[1] = 1; *m = 1; } result = ae_true; ae_frame_leave(_state); return result; } /* * Scaling */ t = ae_fabs(d->ptr.p_double[n], _state); for(j=1; j<=n-1; j++) { t = ae_maxreal(t, ae_fabs(d->ptr.p_double[j], _state), _state); t = ae_maxreal(t, ae_fabs(e->ptr.p_double[j], _state), _state); } scalefactor = (double)(1); if( ae_fp_neq(t,(double)(0)) ) { if( ae_fp_greater(t,ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state)*ae_sqrt(ae_maxrealnumber, _state)) ) { scalefactor = t; } if( ae_fp_less(t,ae_sqrt(ae_sqrt(ae_maxrealnumber, _state), _state)*ae_sqrt(ae_minrealnumber, _state)) ) { scalefactor = t; } for(j=1; j<=n-1; j++) { d->ptr.p_double[j] = d->ptr.p_double[j]/scalefactor; e->ptr.p_double[j] = e->ptr.p_double[j]/scalefactor; } d->ptr.p_double[n] = d->ptr.p_double[n]/scalefactor; } /* * Compute Splitting Points */ *nsplit = 1; work.ptr.p_double[n] = (double)(0); pivmin = (double)(1); for(j=2; j<=n; j++) { tmp1 = ae_sqr(e->ptr.p_double[j-1], _state); if( ae_fp_greater(ae_fabs(d->ptr.p_double[j]*d->ptr.p_double[j-1], _state)*ae_sqr(ulp, _state)+safemn,tmp1) ) { isplit->ptr.p_int[*nsplit] = j-1; *nsplit = *nsplit+1; work.ptr.p_double[j-1] = (double)(0); } else { work.ptr.p_double[j-1] = tmp1; pivmin = ae_maxreal(pivmin, tmp1, _state); } } isplit->ptr.p_int[*nsplit] = n; pivmin = pivmin*safemn; /* * Compute Interval and ATOLI */ if( irange==3 ) { /* * RANGE='I': Compute the interval containing eigenvalues * IL through IU. * * Compute Gershgorin interval for entire (split) matrix * and use it as the initial interval */ gu = d->ptr.p_double[1]; gl = d->ptr.p_double[1]; tmp1 = (double)(0); for(j=1; j<=n-1; j++) { tmp2 = ae_sqrt(work.ptr.p_double[j], _state); gu = ae_maxreal(gu, d->ptr.p_double[j]+tmp1+tmp2, _state); gl = ae_minreal(gl, d->ptr.p_double[j]-tmp1-tmp2, _state); tmp1 = tmp2; } gu = ae_maxreal(gu, d->ptr.p_double[n]+tmp1, _state); gl = ae_minreal(gl, d->ptr.p_double[n]-tmp1, _state); tnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); gl = gl-fudge*tnorm*ulp*n-fudge*2*pivmin; gu = gu+fudge*tnorm*ulp*n+fudge*pivmin; /* * Compute Iteration parameters */ itmax = ae_iceil((ae_log(tnorm+pivmin, _state)-ae_log(pivmin, _state))/ae_log((double)(2), _state), _state)+2; if( ae_fp_less_eq(abstol,(double)(0)) ) { atoli = ulp*tnorm; } else { atoli = abstol; } work.ptr.p_double[n+1] = gl; work.ptr.p_double[n+2] = gl; work.ptr.p_double[n+3] = gu; work.ptr.p_double[n+4] = gu; work.ptr.p_double[n+5] = gl; work.ptr.p_double[n+6] = gu; iwork.ptr.p_int[1] = -1; iwork.ptr.p_int[2] = -1; iwork.ptr.p_int[3] = n+1; iwork.ptr.p_int[4] = n+1; iwork.ptr.p_int[5] = il-1; iwork.ptr.p_int[6] = iu; /* * Calling DLAEBZ * * DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN, D, E, * WORK, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT, * IWORK, W, IBLOCK, IINFO ) */ ia1s2.ptr.p_int[1] = iwork.ptr.p_int[5]; ia1s2.ptr.p_int[2] = iwork.ptr.p_int[6]; ra1s2.ptr.p_double[1] = work.ptr.p_double[n+5]; ra1s2.ptr.p_double[2] = work.ptr.p_double[n+6]; ra1s2x2.ptr.pp_double[1][1] = work.ptr.p_double[n+1]; ra1s2x2.ptr.pp_double[2][1] = work.ptr.p_double[n+2]; ra1s2x2.ptr.pp_double[1][2] = work.ptr.p_double[n+3]; ra1s2x2.ptr.pp_double[2][2] = work.ptr.p_double[n+4]; ia1s2x2.ptr.pp_int[1][1] = iwork.ptr.p_int[1]; ia1s2x2.ptr.pp_int[2][1] = iwork.ptr.p_int[2]; ia1s2x2.ptr.pp_int[1][2] = iwork.ptr.p_int[3]; ia1s2x2.ptr.pp_int[2][2] = iwork.ptr.p_int[4]; evd_internaldlaebz(3, itmax, n, 2, 2, atoli, rtoli, pivmin, d, e, &work, &ia1s2, &ra1s2x2, &ra1s2, &iout, &ia1s2x2, w, iblock, &iinfo, _state); iwork.ptr.p_int[5] = ia1s2.ptr.p_int[1]; iwork.ptr.p_int[6] = ia1s2.ptr.p_int[2]; work.ptr.p_double[n+5] = ra1s2.ptr.p_double[1]; work.ptr.p_double[n+6] = ra1s2.ptr.p_double[2]; work.ptr.p_double[n+1] = ra1s2x2.ptr.pp_double[1][1]; work.ptr.p_double[n+2] = ra1s2x2.ptr.pp_double[2][1]; work.ptr.p_double[n+3] = ra1s2x2.ptr.pp_double[1][2]; work.ptr.p_double[n+4] = ra1s2x2.ptr.pp_double[2][2]; iwork.ptr.p_int[1] = ia1s2x2.ptr.pp_int[1][1]; iwork.ptr.p_int[2] = ia1s2x2.ptr.pp_int[2][1]; iwork.ptr.p_int[3] = ia1s2x2.ptr.pp_int[1][2]; iwork.ptr.p_int[4] = ia1s2x2.ptr.pp_int[2][2]; if( iwork.ptr.p_int[6]==iu ) { wl = work.ptr.p_double[n+1]; wlu = work.ptr.p_double[n+3]; nwl = iwork.ptr.p_int[1]; wu = work.ptr.p_double[n+4]; wul = work.ptr.p_double[n+2]; nwu = iwork.ptr.p_int[4]; } else { wl = work.ptr.p_double[n+2]; wlu = work.ptr.p_double[n+4]; nwl = iwork.ptr.p_int[2]; wu = work.ptr.p_double[n+3]; wul = work.ptr.p_double[n+1]; nwu = iwork.ptr.p_int[3]; } if( ((nwl<0||nwl>=n)||nwu<1)||nwu>n ) { *errorcode = 4; result = ae_false; ae_frame_leave(_state); return result; } } else { /* * RANGE='A' or 'V' -- Set ATOLI */ tnorm = ae_maxreal(ae_fabs(d->ptr.p_double[1], _state)+ae_fabs(e->ptr.p_double[1], _state), ae_fabs(d->ptr.p_double[n], _state)+ae_fabs(e->ptr.p_double[n-1], _state), _state); for(j=2; j<=n-1; j++) { tnorm = ae_maxreal(tnorm, ae_fabs(d->ptr.p_double[j], _state)+ae_fabs(e->ptr.p_double[j-1], _state)+ae_fabs(e->ptr.p_double[j], _state), _state); } if( ae_fp_less_eq(abstol,(double)(0)) ) { atoli = ulp*tnorm; } else { atoli = abstol; } if( irange==2 ) { wl = vl; wu = vu; } else { wl = (double)(0); wu = (double)(0); } } /* * Find Eigenvalues -- Loop Over Blocks and recompute NWL and NWU. * NWL accumulates the number of eigenvalues .le. WL, * NWU accumulates the number of eigenvalues .le. WU */ *m = 0; iend = 0; *errorcode = 0; nwl = 0; nwu = 0; for(jb=1; jb<=*nsplit; jb++) { ioff = iend; ibegin = ioff+1; iend = isplit->ptr.p_int[jb]; iin = iend-ioff; if( iin==1 ) { /* * Special Case -- IIN=1 */ if( irange==1||ae_fp_greater_eq(wl,d->ptr.p_double[ibegin]-pivmin) ) { nwl = nwl+1; } if( irange==1||ae_fp_greater_eq(wu,d->ptr.p_double[ibegin]-pivmin) ) { nwu = nwu+1; } if( irange==1||(ae_fp_less(wl,d->ptr.p_double[ibegin]-pivmin)&&ae_fp_greater_eq(wu,d->ptr.p_double[ibegin]-pivmin)) ) { *m = *m+1; w->ptr.p_double[*m] = d->ptr.p_double[ibegin]; iblock->ptr.p_int[*m] = jb; } } else { /* * General Case -- IIN > 1 * * Compute Gershgorin Interval * and use it as the initial interval */ gu = d->ptr.p_double[ibegin]; gl = d->ptr.p_double[ibegin]; tmp1 = (double)(0); for(j=ibegin; j<=iend-1; j++) { tmp2 = ae_fabs(e->ptr.p_double[j], _state); gu = ae_maxreal(gu, d->ptr.p_double[j]+tmp1+tmp2, _state); gl = ae_minreal(gl, d->ptr.p_double[j]-tmp1-tmp2, _state); tmp1 = tmp2; } gu = ae_maxreal(gu, d->ptr.p_double[iend]+tmp1, _state); gl = ae_minreal(gl, d->ptr.p_double[iend]-tmp1, _state); bnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); gl = gl-fudge*bnorm*ulp*iin-fudge*pivmin; gu = gu+fudge*bnorm*ulp*iin+fudge*pivmin; /* * Compute ATOLI for the current submatrix */ if( ae_fp_less_eq(abstol,(double)(0)) ) { atoli = ulp*ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); } else { atoli = abstol; } if( irange>1 ) { if( ae_fp_less(gu,wl) ) { nwl = nwl+iin; nwu = nwu+iin; continue; } gl = ae_maxreal(gl, wl, _state); gu = ae_minreal(gu, wu, _state); if( ae_fp_greater_eq(gl,gu) ) { continue; } } /* * Set Up Initial Interval */ work.ptr.p_double[n+1] = gl; work.ptr.p_double[n+iin+1] = gu; /* * Calling DLAEBZ * * CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM, * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) */ for(tmpi=1; tmpi<=iin; tmpi++) { ra1siin.ptr.p_double[tmpi] = d->ptr.p_double[ibegin-1+tmpi]; if( ibegin-1+tmpiptr.p_double[ibegin-1+tmpi]; } ra3siin.ptr.p_double[tmpi] = work.ptr.p_double[ibegin-1+tmpi]; ra1siinx2.ptr.pp_double[tmpi][1] = work.ptr.p_double[n+tmpi]; ra1siinx2.ptr.pp_double[tmpi][2] = work.ptr.p_double[n+tmpi+iin]; ra4siin.ptr.p_double[tmpi] = work.ptr.p_double[n+2*iin+tmpi]; rworkspace.ptr.p_double[tmpi] = w->ptr.p_double[*m+tmpi]; iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; } evd_internaldlaebz(1, 0, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &im, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); for(tmpi=1; tmpi<=iin; tmpi++) { work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; } nwl = nwl+iwork.ptr.p_int[1]; nwu = nwu+iwork.ptr.p_int[iin+1]; iwoff = *m-iwork.ptr.p_int[1]; /* * Compute Eigenvalues */ itmax = ae_iceil((ae_log(gu-gl+pivmin, _state)-ae_log(pivmin, _state))/ae_log((double)(2), _state), _state)+2; /* * Calling DLAEBZ * *CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT, * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) */ for(tmpi=1; tmpi<=iin; tmpi++) { ra1siin.ptr.p_double[tmpi] = d->ptr.p_double[ibegin-1+tmpi]; if( ibegin-1+tmpiptr.p_double[ibegin-1+tmpi]; } ra3siin.ptr.p_double[tmpi] = work.ptr.p_double[ibegin-1+tmpi]; ra1siinx2.ptr.pp_double[tmpi][1] = work.ptr.p_double[n+tmpi]; ra1siinx2.ptr.pp_double[tmpi][2] = work.ptr.p_double[n+tmpi+iin]; ra4siin.ptr.p_double[tmpi] = work.ptr.p_double[n+2*iin+tmpi]; rworkspace.ptr.p_double[tmpi] = w->ptr.p_double[*m+tmpi]; iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; } evd_internaldlaebz(2, itmax, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &iout, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); for(tmpi=1; tmpi<=iin; tmpi++) { work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; } /* * Copy Eigenvalues Into W and IBLOCK * Use -JB for block number for unconverged eigenvalues. */ for(j=1; j<=iout; j++) { tmp1 = 0.5*(work.ptr.p_double[j+n]+work.ptr.p_double[j+iin+n]); /* * Flag non-convergence. */ if( j>iout-iinfo ) { ncnvrg = ae_true; ib = -jb; } else { ib = jb; } for(je=iwork.ptr.p_int[j]+1+iwoff; je<=iwork.ptr.p_int[j+iin]+iwoff; je++) { w->ptr.p_double[je] = tmp1; iblock->ptr.p_int[je] = ib; } } *m = *m+im; } } /* * If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU * If NWL+1 < IL or NWU > IU, discard extra eigenvalues. */ if( irange==3 ) { im = 0; idiscl = il-1-nwl; idiscu = nwu-iu; if( idiscl>0||idiscu>0 ) { for(je=1; je<=*m; je++) { if( ae_fp_less_eq(w->ptr.p_double[je],wlu)&&idiscl>0 ) { idiscl = idiscl-1; } else { if( ae_fp_greater_eq(w->ptr.p_double[je],wul)&&idiscu>0 ) { idiscu = idiscu-1; } else { im = im+1; w->ptr.p_double[im] = w->ptr.p_double[je]; iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; } } } *m = im; } if( idiscl>0||idiscu>0 ) { /* * Code to deal with effects of bad arithmetic: * Some low eigenvalues to be discarded are not in (WL,WLU], * or high eigenvalues to be discarded are not in (WUL,WU] * so just kill off the smallest IDISCL/largest IDISCU * eigenvalues, by simply finding the smallest/largest * eigenvalue(s). * * (If N(w) is monotone non-decreasing, this should never * happen.) */ if( idiscl>0 ) { wkill = wu; for(jdisc=1; jdisc<=idiscl; jdisc++) { iw = 0; for(je=1; je<=*m; je++) { if( iblock->ptr.p_int[je]!=0&&(ae_fp_less(w->ptr.p_double[je],wkill)||iw==0) ) { iw = je; wkill = w->ptr.p_double[je]; } } iblock->ptr.p_int[iw] = 0; } } if( idiscu>0 ) { wkill = wl; for(jdisc=1; jdisc<=idiscu; jdisc++) { iw = 0; for(je=1; je<=*m; je++) { if( iblock->ptr.p_int[je]!=0&&(ae_fp_greater(w->ptr.p_double[je],wkill)||iw==0) ) { iw = je; wkill = w->ptr.p_double[je]; } } iblock->ptr.p_int[iw] = 0; } } im = 0; for(je=1; je<=*m; je++) { if( iblock->ptr.p_int[je]!=0 ) { im = im+1; w->ptr.p_double[im] = w->ptr.p_double[je]; iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; } } *m = im; } if( idiscl<0||idiscu<0 ) { toofew = ae_true; } } /* * If ORDER='B', do nothing -- the eigenvalues are already sorted * by block. * If ORDER='E', sort the eigenvalues from smallest to largest */ if( iorder==1&&*nsplit>1 ) { for(je=1; je<=*m-1; je++) { ie = 0; tmp1 = w->ptr.p_double[je]; for(j=je+1; j<=*m; j++) { if( ae_fp_less(w->ptr.p_double[j],tmp1) ) { ie = j; tmp1 = w->ptr.p_double[j]; } } if( ie!=0 ) { itmp1 = iblock->ptr.p_int[ie]; w->ptr.p_double[ie] = w->ptr.p_double[je]; iblock->ptr.p_int[ie] = iblock->ptr.p_int[je]; w->ptr.p_double[je] = tmp1; iblock->ptr.p_int[je] = itmp1; } } } for(j=1; j<=*m; j++) { w->ptr.p_double[j] = w->ptr.p_double[j]*scalefactor; } *errorcode = 0; if( ncnvrg ) { *errorcode = *errorcode+1; } if( toofew ) { *errorcode = *errorcode+2; } result = *errorcode==0; ae_frame_leave(_state); return result; } static void evd_internaldstein(ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t m, /* Real */ ae_vector* w, /* Integer */ ae_vector* iblock, /* Integer */ ae_vector* isplit, /* Real */ ae_matrix* z, /* Integer */ ae_vector* ifail, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_vector _e; ae_vector _w; ae_int_t maxits; ae_int_t extra; ae_int_t b1; ae_int_t blksiz; ae_int_t bn; ae_int_t gpind; ae_int_t i; ae_int_t iinfo; ae_int_t its; ae_int_t j; ae_int_t j1; ae_int_t jblk; ae_int_t jmax; ae_int_t nblk; ae_int_t nrmchk; double dtpcrt; double eps; double eps1; double nrm; double onenrm; double ortol; double pertol; double scl; double sep; double tol; double xj; double xjm; double ztr; ae_vector work1; ae_vector work2; ae_vector work3; ae_vector work4; ae_vector work5; ae_vector iwork; ae_bool tmpcriterion; ae_int_t ti; ae_int_t i1; ae_int_t i2; double v; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_e, e, _state); e = &_e; ae_vector_init_copy(&_w, w, _state); w = &_w; ae_matrix_clear(z); ae_vector_clear(ifail); *info = 0; ae_vector_init(&work1, 0, DT_REAL, _state); ae_vector_init(&work2, 0, DT_REAL, _state); ae_vector_init(&work3, 0, DT_REAL, _state); ae_vector_init(&work4, 0, DT_REAL, _state); ae_vector_init(&work5, 0, DT_REAL, _state); ae_vector_init(&iwork, 0, DT_INT, _state); maxits = 5; extra = 2; ae_vector_set_length(&work1, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&work2, ae_maxint(n-1, 1, _state)+1, _state); ae_vector_set_length(&work3, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&work4, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&work5, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&iwork, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(ifail, ae_maxint(m, 1, _state)+1, _state); ae_matrix_set_length(z, ae_maxint(n, 1, _state)+1, ae_maxint(m, 1, _state)+1, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ gpind = 0; onenrm = (double)(0); ortol = (double)(0); dtpcrt = (double)(0); xjm = (double)(0); /* * Test the input parameters. */ *info = 0; for(i=1; i<=m; i++) { ifail->ptr.p_int[i] = 0; } if( n<0 ) { *info = -1; ae_frame_leave(_state); return; } if( m<0||m>n ) { *info = -4; ae_frame_leave(_state); return; } for(j=2; j<=m; j++) { if( iblock->ptr.p_int[j]ptr.p_int[j-1] ) { *info = -6; break; } if( iblock->ptr.p_int[j]==iblock->ptr.p_int[j-1]&&ae_fp_less(w->ptr.p_double[j],w->ptr.p_double[j-1]) ) { *info = -5; break; } } if( *info!=0 ) { ae_frame_leave(_state); return; } /* * Quick return if possible */ if( n==0||m==0 ) { ae_frame_leave(_state); return; } if( n==1 ) { z->ptr.pp_double[1][1] = (double)(1); ae_frame_leave(_state); return; } /* * Some preparations */ ti = n-1; ae_v_move(&work1.ptr.p_double[1], 1, &e->ptr.p_double[1], 1, ae_v_len(1,ti)); ae_vector_set_length(e, n+1, _state); ae_v_move(&e->ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,ti)); ae_v_move(&work1.ptr.p_double[1], 1, &w->ptr.p_double[1], 1, ae_v_len(1,m)); ae_vector_set_length(w, n+1, _state); ae_v_move(&w->ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,m)); /* * Get machine constants. */ eps = ae_machineepsilon; /* * Compute eigenvectors of matrix blocks. */ j1 = 1; for(nblk=1; nblk<=iblock->ptr.p_int[m]; nblk++) { /* * Find starting and ending indices of block nblk. */ if( nblk==1 ) { b1 = 1; } else { b1 = isplit->ptr.p_int[nblk-1]+1; } bn = isplit->ptr.p_int[nblk]; blksiz = bn-b1+1; if( blksiz!=1 ) { /* * Compute reorthogonalization criterion and stopping criterion. */ gpind = b1; onenrm = ae_fabs(d->ptr.p_double[b1], _state)+ae_fabs(e->ptr.p_double[b1], _state); onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[bn], _state)+ae_fabs(e->ptr.p_double[bn-1], _state), _state); for(i=b1+1; i<=bn-1; i++) { onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i-1], _state)+ae_fabs(e->ptr.p_double[i], _state), _state); } ortol = 0.001*onenrm; dtpcrt = ae_sqrt(0.1/blksiz, _state); } /* * Loop through eigenvalues of block nblk. */ jblk = 0; for(j=j1; j<=m; j++) { if( iblock->ptr.p_int[j]!=nblk ) { j1 = j; break; } jblk = jblk+1; xj = w->ptr.p_double[j]; if( blksiz==1 ) { /* * Skip all the work if the block size is one. */ work1.ptr.p_double[1] = (double)(1); } else { /* * If eigenvalues j and j-1 are too close, add a relatively * small perturbation. */ if( jblk>1 ) { eps1 = ae_fabs(eps*xj, _state); pertol = 10*eps1; sep = xj-xjm; if( ae_fp_less(sep,pertol) ) { xj = xjm+pertol; } } its = 0; nrmchk = 0; /* * Get random starting vector. */ for(ti=1; ti<=blksiz; ti++) { work1.ptr.p_double[ti] = 2*ae_randomreal(_state)-1; } /* * Copy the matrix T so it won't be destroyed in factorization. */ for(ti=1; ti<=blksiz-1; ti++) { work2.ptr.p_double[ti] = e->ptr.p_double[b1+ti-1]; work3.ptr.p_double[ti] = e->ptr.p_double[b1+ti-1]; work4.ptr.p_double[ti] = d->ptr.p_double[b1+ti-1]; } work4.ptr.p_double[blksiz] = d->ptr.p_double[b1+blksiz-1]; /* * Compute LU factors with partial pivoting ( PT = LU ) */ tol = (double)(0); evd_tdininternaldlagtf(blksiz, &work4, xj, &work2, &work3, tol, &work5, &iwork, &iinfo, _state); /* * Update iteration count. */ do { its = its+1; if( its>maxits ) { /* * If stopping criterion was not satisfied, update info and * store eigenvector number in array ifail. */ *info = *info+1; ifail->ptr.p_int[*info] = j; break; } /* * Normalize and scale the righthand side vector Pb. */ v = (double)(0); for(ti=1; ti<=blksiz; ti++) { v = v+ae_fabs(work1.ptr.p_double[ti], _state); } scl = blksiz*onenrm*ae_maxreal(eps, ae_fabs(work4.ptr.p_double[blksiz], _state), _state)/v; ae_v_muld(&work1.ptr.p_double[1], 1, ae_v_len(1,blksiz), scl); /* * Solve the system LU = Pb. */ evd_tdininternaldlagts(blksiz, &work4, &work2, &work3, &work5, &iwork, &work1, &tol, &iinfo, _state); /* * Reorthogonalize by modified Gram-Schmidt if eigenvalues are * close enough. */ if( jblk!=1 ) { if( ae_fp_greater(ae_fabs(xj-xjm, _state),ortol) ) { gpind = j; } if( gpind!=j ) { for(i=gpind; i<=j-1; i++) { i1 = b1; i2 = b1+blksiz-1; ztr = ae_v_dotproduct(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz)); ae_v_subd(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz), ztr); touchint(&i2, _state); } } } /* * Check the infinity norm of the iterate. */ jmax = vectoridxabsmax(&work1, 1, blksiz, _state); nrm = ae_fabs(work1.ptr.p_double[jmax], _state); /* * Continue for additional iterations after norm reaches * stopping criterion. */ tmpcriterion = ae_false; if( ae_fp_less(nrm,dtpcrt) ) { tmpcriterion = ae_true; } else { nrmchk = nrmchk+1; if( nrmchkptr.pp_double[i][j] = (double)(0); } for(i=1; i<=blksiz; i++) { z->ptr.pp_double[b1+i-1][j] = work1.ptr.p_double[i]; } /* * Save the shift to check eigenvalue spacing at next * iteration. */ xjm = xj; } } ae_frame_leave(_state); } static void evd_tdininternaldlagtf(ae_int_t n, /* Real */ ae_vector* a, double lambdav, /* Real */ ae_vector* b, /* Real */ ae_vector* c, double tol, /* Real */ ae_vector* d, /* Integer */ ae_vector* iin, ae_int_t* info, ae_state *_state) { ae_int_t k; double eps; double mult; double piv1; double piv2; double scale1; double scale2; double temp; double tl; *info = 0; *info = 0; if( n<0 ) { *info = -1; return; } if( n==0 ) { return; } a->ptr.p_double[1] = a->ptr.p_double[1]-lambdav; iin->ptr.p_int[n] = 0; if( n==1 ) { if( ae_fp_eq(a->ptr.p_double[1],(double)(0)) ) { iin->ptr.p_int[1] = 1; } return; } eps = ae_machineepsilon; tl = ae_maxreal(tol, eps, _state); scale1 = ae_fabs(a->ptr.p_double[1], _state)+ae_fabs(b->ptr.p_double[1], _state); for(k=1; k<=n-1; k++) { a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-lambdav; scale2 = ae_fabs(c->ptr.p_double[k], _state)+ae_fabs(a->ptr.p_double[k+1], _state); if( kptr.p_double[k+1], _state); } if( ae_fp_eq(a->ptr.p_double[k],(double)(0)) ) { piv1 = (double)(0); } else { piv1 = ae_fabs(a->ptr.p_double[k], _state)/scale1; } if( ae_fp_eq(c->ptr.p_double[k],(double)(0)) ) { iin->ptr.p_int[k] = 0; piv2 = (double)(0); scale1 = scale2; if( kptr.p_double[k] = (double)(0); } } else { piv2 = ae_fabs(c->ptr.p_double[k], _state)/scale2; if( ae_fp_less_eq(piv2,piv1) ) { iin->ptr.p_int[k] = 0; scale1 = scale2; c->ptr.p_double[k] = c->ptr.p_double[k]/a->ptr.p_double[k]; a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-c->ptr.p_double[k]*b->ptr.p_double[k]; if( kptr.p_double[k] = (double)(0); } } else { iin->ptr.p_int[k] = 1; mult = a->ptr.p_double[k]/c->ptr.p_double[k]; a->ptr.p_double[k] = c->ptr.p_double[k]; temp = a->ptr.p_double[k+1]; a->ptr.p_double[k+1] = b->ptr.p_double[k]-mult*temp; if( kptr.p_double[k] = b->ptr.p_double[k+1]; b->ptr.p_double[k+1] = -mult*d->ptr.p_double[k]; } b->ptr.p_double[k] = temp; c->ptr.p_double[k] = mult; } } if( ae_fp_less_eq(ae_maxreal(piv1, piv2, _state),tl)&&iin->ptr.p_int[n]==0 ) { iin->ptr.p_int[n] = k; } } if( ae_fp_less_eq(ae_fabs(a->ptr.p_double[n], _state),scale1*tl)&&iin->ptr.p_int[n]==0 ) { iin->ptr.p_int[n] = n; } } static void evd_tdininternaldlagts(ae_int_t n, /* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, /* Integer */ ae_vector* iin, /* Real */ ae_vector* y, double* tol, ae_int_t* info, ae_state *_state) { ae_int_t k; double absak; double ak; double bignum; double eps; double pert; double sfmin; double temp; *info = 0; *info = 0; if( n<0 ) { *info = -1; return; } if( n==0 ) { return; } eps = ae_machineepsilon; sfmin = ae_minrealnumber; bignum = 1/sfmin; if( ae_fp_less_eq(*tol,(double)(0)) ) { *tol = ae_fabs(a->ptr.p_double[1], _state); if( n>1 ) { *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[2], _state), ae_fabs(b->ptr.p_double[1], _state), _state), _state); } for(k=3; k<=n; k++) { *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[k], _state), ae_maxreal(ae_fabs(b->ptr.p_double[k-1], _state), ae_fabs(d->ptr.p_double[k-2], _state), _state), _state), _state); } *tol = *tol*eps; if( ae_fp_eq(*tol,(double)(0)) ) { *tol = eps; } } for(k=2; k<=n; k++) { if( iin->ptr.p_int[k-1]==0 ) { y->ptr.p_double[k] = y->ptr.p_double[k]-c->ptr.p_double[k-1]*y->ptr.p_double[k-1]; } else { temp = y->ptr.p_double[k-1]; y->ptr.p_double[k-1] = y->ptr.p_double[k]; y->ptr.p_double[k] = temp-c->ptr.p_double[k-1]*y->ptr.p_double[k]; } } for(k=n; k>=1; k--) { if( k<=n-2 ) { temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]-d->ptr.p_double[k]*y->ptr.p_double[k+2]; } else { if( k==n-1 ) { temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]; } else { temp = y->ptr.p_double[k]; } } ak = a->ptr.p_double[k]; pert = ae_fabs(*tol, _state); if( ae_fp_less(ak,(double)(0)) ) { pert = -pert; } for(;;) { absak = ae_fabs(ak, _state); if( ae_fp_less(absak,(double)(1)) ) { if( ae_fp_less(absak,sfmin) ) { if( ae_fp_eq(absak,(double)(0))||ae_fp_greater(ae_fabs(temp, _state)*sfmin,absak) ) { ak = ak+pert; pert = 2*pert; continue; } else { temp = temp*bignum; ak = ak*bignum; } } else { if( ae_fp_greater(ae_fabs(temp, _state),absak*bignum) ) { ak = ak+pert; pert = 2*pert; continue; } } } break; } y->ptr.p_double[k] = temp/ak; } } static void evd_internaldlaebz(ae_int_t ijob, ae_int_t nitmax, ae_int_t n, ae_int_t mmax, ae_int_t minp, double abstol, double reltol, double pivmin, /* Real */ ae_vector* d, /* Real */ ae_vector* e, /* Real */ ae_vector* e2, /* Integer */ ae_vector* nval, /* Real */ ae_matrix* ab, /* Real */ ae_vector* c, ae_int_t* mout, /* Integer */ ae_matrix* nab, /* Real */ ae_vector* work, /* Integer */ ae_vector* iwork, ae_int_t* info, ae_state *_state) { ae_int_t itmp1; ae_int_t itmp2; ae_int_t j; ae_int_t ji; ae_int_t jit; ae_int_t jp; ae_int_t kf; ae_int_t kfnew; ae_int_t kl; ae_int_t klnew; double tmp1; double tmp2; *mout = 0; *info = 0; *info = 0; if( ijob<1||ijob>3 ) { *info = -1; return; } /* * Initialize NAB */ if( ijob==1 ) { /* * Compute the number of eigenvalues in the initial intervals. */ *mout = 0; /* *DIR$ NOVECTOR */ for(ji=1; ji<=minp; ji++) { for(jp=1; jp<=2; jp++) { tmp1 = d->ptr.p_double[1]-ab->ptr.pp_double[ji][jp]; if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) { tmp1 = -pivmin; } nab->ptr.pp_int[ji][jp] = 0; if( ae_fp_less_eq(tmp1,(double)(0)) ) { nab->ptr.pp_int[ji][jp] = 1; } for(j=2; j<=n; j++) { tmp1 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp1-ab->ptr.pp_double[ji][jp]; if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) { tmp1 = -pivmin; } if( ae_fp_less_eq(tmp1,(double)(0)) ) { nab->ptr.pp_int[ji][jp] = nab->ptr.pp_int[ji][jp]+1; } } } *mout = *mout+nab->ptr.pp_int[ji][2]-nab->ptr.pp_int[ji][1]; } return; } /* * Initialize for loop * * KF and KL have the following meaning: * Intervals 1,...,KF-1 have converged. * Intervals KF,...,KL still need to be refined. */ kf = 1; kl = minp; /* * If IJOB=2, initialize C. * If IJOB=3, use the user-supplied starting point. */ if( ijob==2 ) { for(ji=1; ji<=minp; ji++) { c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); } } /* * Iteration loop */ for(jit=1; jit<=nitmax; jit++) { /* * Loop over intervals * * * Serial Version of the loop */ klnew = kl; for(ji=kf; ji<=kl; ji++) { /* * Compute N(w), the number of eigenvalues less than w */ tmp1 = c->ptr.p_double[ji]; tmp2 = d->ptr.p_double[1]-tmp1; itmp1 = 0; if( ae_fp_less_eq(tmp2,pivmin) ) { itmp1 = 1; tmp2 = ae_minreal(tmp2, -pivmin, _state); } /* * A series of compiler directives to defeat vectorization * for the next loop * **$PL$ CMCHAR=' ' *CDIR$ NEXTSCALAR *C$DIR SCALAR *CDIR$ NEXT SCALAR *CVD$L NOVECTOR *CDEC$ NOVECTOR *CVD$ NOVECTOR **VDIR NOVECTOR **VOCL LOOP,SCALAR *CIBM PREFER SCALAR **$PL$ CMCHAR='*' */ for(j=2; j<=n; j++) { tmp2 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp2-tmp1; if( ae_fp_less_eq(tmp2,pivmin) ) { itmp1 = itmp1+1; tmp2 = ae_minreal(tmp2, -pivmin, _state); } } if( ijob<=2 ) { /* * IJOB=2: Choose all intervals containing eigenvalues. * * Insure that N(w) is monotone */ itmp1 = ae_minint(nab->ptr.pp_int[ji][2], ae_maxint(nab->ptr.pp_int[ji][1], itmp1, _state), _state); /* * Update the Queue -- add intervals if both halves * contain eigenvalues. */ if( itmp1==nab->ptr.pp_int[ji][2] ) { /* * No eigenvalue in the upper interval: * just use the lower interval. */ ab->ptr.pp_double[ji][2] = tmp1; } else { if( itmp1==nab->ptr.pp_int[ji][1] ) { /* * No eigenvalue in the lower interval: * just use the upper interval. */ ab->ptr.pp_double[ji][1] = tmp1; } else { if( klnewptr.pp_double[klnew][2] = ab->ptr.pp_double[ji][2]; nab->ptr.pp_int[klnew][2] = nab->ptr.pp_int[ji][2]; ab->ptr.pp_double[klnew][1] = tmp1; nab->ptr.pp_int[klnew][1] = itmp1; ab->ptr.pp_double[ji][2] = tmp1; nab->ptr.pp_int[ji][2] = itmp1; } else { *info = mmax+1; return; } } } } else { /* * IJOB=3: Binary search. Keep only the interval * containing w s.t. N(w) = NVAL */ if( itmp1<=nval->ptr.p_int[ji] ) { ab->ptr.pp_double[ji][1] = tmp1; nab->ptr.pp_int[ji][1] = itmp1; } if( itmp1>=nval->ptr.p_int[ji] ) { ab->ptr.pp_double[ji][2] = tmp1; nab->ptr.pp_int[ji][2] = itmp1; } } } kl = klnew; /* * Check for convergence */ kfnew = kf; for(ji=kf; ji<=kl; ji++) { tmp1 = ae_fabs(ab->ptr.pp_double[ji][2]-ab->ptr.pp_double[ji][1], _state); tmp2 = ae_maxreal(ae_fabs(ab->ptr.pp_double[ji][2], _state), ae_fabs(ab->ptr.pp_double[ji][1], _state), _state); if( ae_fp_less(tmp1,ae_maxreal(abstol, ae_maxreal(pivmin, reltol*tmp2, _state), _state))||nab->ptr.pp_int[ji][1]>=nab->ptr.pp_int[ji][2] ) { /* * Converged -- Swap with position KFNEW, * then increment KFNEW */ if( ji>kfnew ) { tmp1 = ab->ptr.pp_double[ji][1]; tmp2 = ab->ptr.pp_double[ji][2]; itmp1 = nab->ptr.pp_int[ji][1]; itmp2 = nab->ptr.pp_int[ji][2]; ab->ptr.pp_double[ji][1] = ab->ptr.pp_double[kfnew][1]; ab->ptr.pp_double[ji][2] = ab->ptr.pp_double[kfnew][2]; nab->ptr.pp_int[ji][1] = nab->ptr.pp_int[kfnew][1]; nab->ptr.pp_int[ji][2] = nab->ptr.pp_int[kfnew][2]; ab->ptr.pp_double[kfnew][1] = tmp1; ab->ptr.pp_double[kfnew][2] = tmp2; nab->ptr.pp_int[kfnew][1] = itmp1; nab->ptr.pp_int[kfnew][2] = itmp2; if( ijob==3 ) { itmp1 = nval->ptr.p_int[ji]; nval->ptr.p_int[ji] = nval->ptr.p_int[kfnew]; nval->ptr.p_int[kfnew] = itmp1; } } kfnew = kfnew+1; } } kf = kfnew; /* * Choose Midpoints */ for(ji=kf; ji<=kl; ji++) { c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); } /* * If no more intervals to refine, quit. */ if( kf>kl ) { break; } } /* * Converged */ *info = ae_maxint(kl+1-kf, 0, _state); *mout = kl; } /************************************************************************* Internal subroutine -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1999 *************************************************************************/ static void evd_rmatrixinternaltrevc(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Boolean */ ae_vector* vselect, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_vector _vselect; ae_int_t i; ae_int_t j; ae_matrix t1; ae_matrix vl1; ae_matrix vr1; ae_vector vselect1; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_vselect, vselect, _state); vselect = &_vselect; *m = 0; *info = 0; ae_matrix_init(&t1, 0, 0, DT_REAL, _state); ae_matrix_init(&vl1, 0, 0, DT_REAL, _state); ae_matrix_init(&vr1, 0, 0, DT_REAL, _state); ae_vector_init(&vselect1, 0, DT_BOOL, _state); /* * Allocate VL/VR, if needed */ if( howmny==2||howmny==3 ) { if( side==1||side==3 ) { rmatrixsetlengthatleast(vr, n, n, _state); } if( side==2||side==3 ) { rmatrixsetlengthatleast(vl, n, n, _state); } } /* * Try to use MKL kernel */ if( rmatrixinternaltrevcmkl(t, n, side, howmny, vl, vr, m, info, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ ae_matrix_set_length(&t1, n+1, n+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t1.ptr.pp_double[i+1][j+1] = t->ptr.pp_double[i][j]; } } if( howmny==3 ) { ae_vector_set_length(&vselect1, n+1, _state); for(i=0; i<=n-1; i++) { vselect1.ptr.p_bool[1+i] = vselect->ptr.p_bool[i]; } } if( (side==2||side==3)&&howmny==1 ) { ae_matrix_set_length(&vl1, n+1, n+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vl1.ptr.pp_double[i+1][j+1] = vl->ptr.pp_double[i][j]; } } } if( (side==1||side==3)&&howmny==1 ) { ae_matrix_set_length(&vr1, n+1, n+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vr1.ptr.pp_double[i+1][j+1] = vr->ptr.pp_double[i][j]; } } } evd_internaltrevc(&t1, n, side, howmny, &vselect1, &vl1, &vr1, m, info, _state); if( side!=1 ) { rmatrixsetlengthatleast(vl, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vl->ptr.pp_double[i][j] = vl1.ptr.pp_double[i+1][j+1]; } } } if( side!=2 ) { rmatrixsetlengthatleast(vr, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vr->ptr.pp_double[i][j] = vr1.ptr.pp_double[i+1][j+1]; } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1999 *************************************************************************/ static void evd_internaltrevc(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Boolean */ ae_vector* vselect, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_vector _vselect; ae_bool allv; ae_bool bothv; ae_bool leftv; ae_bool over; ae_bool pair; ae_bool rightv; ae_bool somev; ae_int_t i; ae_int_t ierr; ae_int_t ii; ae_int_t ip; ae_int_t iis; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_int_t jnxt; ae_int_t k; ae_int_t ki; ae_int_t n2; double beta; double bignum; double emax; double rec; double remax; double scl; double smin; double smlnum; double ulp; double unfl; double vcrit; double vmax; double wi; double wr; double xnorm; ae_matrix x; ae_vector work; ae_vector temp; ae_matrix temp11; ae_matrix temp22; ae_matrix temp11b; ae_matrix temp21b; ae_matrix temp12b; ae_matrix temp22b; ae_bool skipflag; ae_int_t k1; ae_int_t k2; ae_int_t k3; ae_int_t k4; double vt; ae_vector rswap4; ae_vector zswap4; ae_matrix ipivot44; ae_vector civ4; ae_vector crv4; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_vselect, vselect, _state); vselect = &_vselect; *m = 0; *info = 0; ae_matrix_init(&x, 0, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_vector_init(&temp, 0, DT_REAL, _state); ae_matrix_init(&temp11, 0, 0, DT_REAL, _state); ae_matrix_init(&temp22, 0, 0, DT_REAL, _state); ae_matrix_init(&temp11b, 0, 0, DT_REAL, _state); ae_matrix_init(&temp21b, 0, 0, DT_REAL, _state); ae_matrix_init(&temp12b, 0, 0, DT_REAL, _state); ae_matrix_init(&temp22b, 0, 0, DT_REAL, _state); ae_vector_init(&rswap4, 0, DT_BOOL, _state); ae_vector_init(&zswap4, 0, DT_BOOL, _state); ae_matrix_init(&ipivot44, 0, 0, DT_INT, _state); ae_vector_init(&civ4, 0, DT_REAL, _state); ae_vector_init(&crv4, 0, DT_REAL, _state); ae_matrix_set_length(&x, 2+1, 2+1, _state); ae_matrix_set_length(&temp11, 1+1, 1+1, _state); ae_matrix_set_length(&temp11b, 1+1, 1+1, _state); ae_matrix_set_length(&temp21b, 2+1, 1+1, _state); ae_matrix_set_length(&temp12b, 1+1, 2+1, _state); ae_matrix_set_length(&temp22b, 2+1, 2+1, _state); ae_matrix_set_length(&temp22, 2+1, 2+1, _state); ae_vector_set_length(&work, 3*n+1, _state); ae_vector_set_length(&temp, n+1, _state); ae_vector_set_length(&rswap4, 4+1, _state); ae_vector_set_length(&zswap4, 4+1, _state); ae_matrix_set_length(&ipivot44, 4+1, 4+1, _state); ae_vector_set_length(&civ4, 4+1, _state); ae_vector_set_length(&crv4, 4+1, _state); if( howmny!=1 ) { if( side==1||side==3 ) { ae_matrix_set_length(vr, n+1, n+1, _state); } if( side==2||side==3 ) { ae_matrix_set_length(vl, n+1, n+1, _state); } } /* * Decode and test the input parameters */ bothv = side==3; rightv = side==1||bothv; leftv = side==2||bothv; allv = howmny==2; over = howmny==1; somev = howmny==3; *info = 0; if( n<0 ) { *info = -2; ae_frame_leave(_state); return; } if( !rightv&&!leftv ) { *info = -3; ae_frame_leave(_state); return; } if( (!allv&&!over)&&!somev ) { *info = -4; ae_frame_leave(_state); return; } /* * Set M to the number of columns required to store the selected * eigenvectors, standardize the array SELECT if necessary, and * test MM. */ if( somev ) { *m = 0; pair = ae_false; for(j=1; j<=n; j++) { if( pair ) { pair = ae_false; vselect->ptr.p_bool[j] = ae_false; } else { if( jptr.pp_double[j+1][j],(double)(0)) ) { if( vselect->ptr.p_bool[j] ) { *m = *m+1; } } else { pair = ae_true; if( vselect->ptr.p_bool[j]||vselect->ptr.p_bool[j+1] ) { vselect->ptr.p_bool[j] = ae_true; *m = *m+2; } } } else { if( vselect->ptr.p_bool[n] ) { *m = *m+1; } } } } } else { *m = n; } /* * Quick return if possible. */ if( n==0 ) { ae_frame_leave(_state); return; } /* * Set the constants to control overflow. */ unfl = ae_minrealnumber; ulp = ae_machineepsilon; smlnum = unfl*(n/ulp); bignum = (1-ulp)/smlnum; /* * Compute 1-norm of each column of strictly upper triangular * part of T to control overflow in triangular solver. */ work.ptr.p_double[1] = (double)(0); for(j=2; j<=n; j++) { work.ptr.p_double[j] = (double)(0); for(i=1; i<=j-1; i++) { work.ptr.p_double[j] = work.ptr.p_double[j]+ae_fabs(t->ptr.pp_double[i][j], _state); } } /* * Index IP is used to specify the real or complex eigenvalue: * IP = 0, real eigenvalue, * 1, first of conjugate complex pair: (wr,wi) * -1, second of conjugate complex pair: (wr,wi) */ n2 = 2*n; if( rightv ) { /* * Compute right eigenvectors. */ ip = 0; iis = *m; for(ki=n; ki>=1; ki--) { skipflag = ae_false; if( ip==1 ) { skipflag = ae_true; } else { if( ki!=1 ) { if( ae_fp_neq(t->ptr.pp_double[ki][ki-1],(double)(0)) ) { ip = -1; } } if( somev ) { if( ip==0 ) { if( !vselect->ptr.p_bool[ki] ) { skipflag = ae_true; } } else { if( !vselect->ptr.p_bool[ki-1] ) { skipflag = ae_true; } } } } if( !skipflag ) { /* * Compute the KI-th eigenvalue (WR,WI). */ wr = t->ptr.pp_double[ki][ki]; wi = (double)(0); if( ip!=0 ) { wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki-1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki-1][ki], _state), _state); } smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); if( ip==0 ) { /* * Real right eigenvector */ work.ptr.p_double[ki+n] = (double)(1); /* * Form right-hand side */ for(k=1; k<=ki-1; k++) { work.ptr.p_double[k+n] = -t->ptr.pp_double[k][ki]; } /* * Solve the upper quasi-triangular system: * (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. */ jnxt = ki-1; for(j=ki-1; j>=1; j--) { if( j>jnxt ) { continue; } j1 = j; j2 = j; jnxt = j-1; if( j>1 ) { if( ae_fp_neq(t->ptr.pp_double[j][j-1],(double)(0)) ) { j1 = j-1; jnxt = j-2; } } if( j1==j2 ) { /* * 1-by-1 diagonal block */ temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; evd_internalhsevdlaln2(ae_false, 1, 1, smin, (double)(1), &temp11, 1.0, 1.0, &temp11b, wr, 0.0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale X(1,1) to avoid overflow when updating * the right-hand side. */ if( ae_fp_greater(xnorm,(double)(1)) ) { if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) { x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; scl = scl/xnorm; } } /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { k1 = n+1; k2 = n+ki; ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; /* * Update right-hand side */ k1 = 1+n; k2 = j-1+n; k3 = j-1; vt = -x.ptr.pp_double[1][1]; ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); } else { /* * 2-by-2 diagonal block */ temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; evd_internalhsevdlaln2(ae_false, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale X(1,1) and X(2,1) to avoid overflow when * updating the right-hand side. */ if( ae_fp_greater(xnorm,(double)(1)) ) { beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); if( ae_fp_greater(beta,bignum/xnorm) ) { x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]/xnorm; scl = scl/xnorm; } } /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { k1 = 1+n; k2 = ki+n; ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); } work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; /* * Update right-hand side */ k1 = 1+n; k2 = j-2+n; k3 = j-2; k4 = j-1; vt = -x.ptr.pp_double[1][1]; ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][k4], t->stride, ae_v_len(k1,k2), vt); vt = -x.ptr.pp_double[2][1]; ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); } } /* * Copy the vector x or Q*x to VR and normalize. */ if( !over ) { k1 = 1+n; k2 = ki+n; ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[k1], 1, ae_v_len(1,ki)); ii = columnidxabsmax(vr, 1, ki, iis, _state); remax = 1/ae_fabs(vr->ptr.pp_double[ii][iis], _state); ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); for(k=ki+1; k<=n; k++) { vr->ptr.pp_double[k][iis] = (double)(0); } } else { if( ki>1 ) { ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); matrixvectormultiply(vr, 1, n, 1, ki-1, ae_false, &work, 1+n, ki-1+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); } ii = columnidxabsmax(vr, 1, n, ki, _state); remax = 1/ae_fabs(vr->ptr.pp_double[ii][ki], _state); ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); } } else { /* * Complex right eigenvector. * * Initial solve * [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. * [ (T(KI,KI-1) T(KI,KI) ) ] */ if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki-1][ki], _state),ae_fabs(t->ptr.pp_double[ki][ki-1], _state)) ) { work.ptr.p_double[ki-1+n] = (double)(1); work.ptr.p_double[ki+n2] = wi/t->ptr.pp_double[ki-1][ki]; } else { work.ptr.p_double[ki-1+n] = -wi/t->ptr.pp_double[ki][ki-1]; work.ptr.p_double[ki+n2] = (double)(1); } work.ptr.p_double[ki+n] = (double)(0); work.ptr.p_double[ki-1+n2] = (double)(0); /* * Form right-hand side */ for(k=1; k<=ki-2; k++) { work.ptr.p_double[k+n] = -work.ptr.p_double[ki-1+n]*t->ptr.pp_double[k][ki-1]; work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+n2]*t->ptr.pp_double[k][ki]; } /* * Solve upper quasi-triangular system: * (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) */ jnxt = ki-2; for(j=ki-2; j>=1; j--) { if( j>jnxt ) { continue; } j1 = j; j2 = j; jnxt = j-1; if( j>1 ) { if( ae_fp_neq(t->ptr.pp_double[j][j-1],(double)(0)) ) { j1 = j-1; jnxt = j-2; } } if( j1==j2 ) { /* * 1-by-1 diagonal block */ temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale X(1,1) and X(1,2) to avoid overflow when * updating the right-hand side. */ if( ae_fp_greater(xnorm,(double)(1)) ) { if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) { x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]/xnorm; scl = scl/xnorm; } } /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { k1 = 1+n; k2 = ki+n; ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); k1 = 1+n2; k2 = ki+n2; ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; /* * Update the right-hand side */ k1 = 1+n; k2 = j-1+n; k3 = 1; k4 = j-1; vt = -x.ptr.pp_double[1][1]; ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); k1 = 1+n2; k2 = j-1+n2; k3 = 1; k4 = j-1; vt = -x.ptr.pp_double[1][2]; ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); } else { /* * 2-by-2 diagonal block */ temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j-1+n+n]; temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+n+n]; evd_internalhsevdlaln2(ae_false, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale X to avoid overflow when updating * the right-hand side. */ if( ae_fp_greater(xnorm,(double)(1)) ) { beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); if( ae_fp_greater(beta,bignum/xnorm) ) { rec = 1/xnorm; x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]*rec; x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]*rec; x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]*rec; x.ptr.pp_double[2][2] = x.ptr.pp_double[2][2]*rec; scl = scl*rec; } } /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { ae_v_muld(&work.ptr.p_double[1+n], 1, ae_v_len(1+n,ki+n), scl); ae_v_muld(&work.ptr.p_double[1+n2], 1, ae_v_len(1+n2,ki+n2), scl); } work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; work.ptr.p_double[j-1+n2] = x.ptr.pp_double[1][2]; work.ptr.p_double[j+n2] = x.ptr.pp_double[2][2]; /* * Update the right-hand side */ vt = -x.ptr.pp_double[1][1]; ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n+1,n+j-2), vt); vt = -x.ptr.pp_double[2][1]; ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n+1,n+j-2), vt); vt = -x.ptr.pp_double[1][2]; ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n2+1,n2+j-2), vt); vt = -x.ptr.pp_double[2][2]; ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n2+1,n2+j-2), vt); } } /* * Copy the vector x or Q*x to VR and normalize. */ if( !over ) { ae_v_move(&vr->ptr.pp_double[1][iis-1], vr->stride, &work.ptr.p_double[n+1], 1, ae_v_len(1,ki)); ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[n2+1], 1, ae_v_len(1,ki)); emax = (double)(0); for(k=1; k<=ki; k++) { emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][iis-1], _state)+ae_fabs(vr->ptr.pp_double[k][iis], _state), _state); } remax = 1/emax; ae_v_muld(&vr->ptr.pp_double[1][iis-1], vr->stride, ae_v_len(1,ki), remax); ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); for(k=ki+1; k<=n; k++) { vr->ptr.pp_double[k][iis-1] = (double)(0); vr->ptr.pp_double[k][iis] = (double)(0); } } else { if( ki>2 ) { ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n)); matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n, ki-2+n, 1.0, &temp, 1, n, work.ptr.p_double[ki-1+n], _state); ae_v_move(&vr->ptr.pp_double[1][ki-1], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n2, ki-2+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+n2], _state); ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); } else { vt = work.ptr.p_double[ki-1+n]; ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), vt); vt = work.ptr.p_double[ki+n2]; ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), vt); } emax = (double)(0); for(k=1; k<=n; k++) { emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][ki-1], _state)+ae_fabs(vr->ptr.pp_double[k][ki], _state), _state); } remax = 1/emax; ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), remax); ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); } } iis = iis-1; if( ip!=0 ) { iis = iis-1; } } if( ip==1 ) { ip = 0; } if( ip==-1 ) { ip = 1; } } } if( leftv ) { /* * Compute left eigenvectors. */ ip = 0; iis = 1; for(ki=1; ki<=n; ki++) { skipflag = ae_false; if( ip==-1 ) { skipflag = ae_true; } else { if( ki!=n ) { if( ae_fp_neq(t->ptr.pp_double[ki+1][ki],(double)(0)) ) { ip = 1; } } if( somev ) { if( !vselect->ptr.p_bool[ki] ) { skipflag = ae_true; } } } if( !skipflag ) { /* * Compute the KI-th eigenvalue (WR,WI). */ wr = t->ptr.pp_double[ki][ki]; wi = (double)(0); if( ip!=0 ) { wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki+1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki+1][ki], _state), _state); } smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); if( ip==0 ) { /* * Real left eigenvector. */ work.ptr.p_double[ki+n] = (double)(1); /* * Form right-hand side */ for(k=ki+1; k<=n; k++) { work.ptr.p_double[k+n] = -t->ptr.pp_double[ki][k]; } /* * Solve the quasi-triangular system: * (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK */ vmax = (double)(1); vcrit = bignum; jnxt = ki+1; for(j=ki+1; j<=n; j++) { if( jptr.pp_double[j+1][j],(double)(0)) ) { j2 = j+1; jnxt = j+2; } } if( j1==j2 ) { /* * 1-by-1 diagonal block * * Scale if necessary to avoid overflow when forming * the right-hand side. */ if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) { rec = 1/vmax; ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); vmax = (double)(1); vcrit = bignum; } vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; /* * Solve (T(J,J)-WR)'*X = WORK */ temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; evd_internalhsevdlaln2(ae_false, 1, 1, smin, 1.0, &temp11, 1.0, 1.0, &temp11b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), vmax, _state); vcrit = bignum/vmax; } else { /* * 2-by-2 diagonal block * * Scale if necessary to avoid overflow when forming * the right-hand side. */ beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); if( ae_fp_greater(beta,vcrit) ) { rec = 1/vmax; ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); vmax = (double)(1); vcrit = bignum; } vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j+1], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; /* * Solve * [T(J,J)-WR T(J,J+1) ]'* X = SCALE*( WORK1 ) * [T(J+1,J) T(J+1,J+1)-WR] ( WORK2 ) */ temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; evd_internalhsevdlaln2(ae_true, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+1+n], _state), vmax, _state), _state); vcrit = bignum/vmax; } } /* * Copy the vector x or Q*x to VL and normalize. */ if( !over ) { ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); ii = columnidxabsmax(vl, ki, n, iis, _state); remax = 1/ae_fabs(vl->ptr.pp_double[ii][iis], _state); ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); for(k=1; k<=ki-1; k++) { vl->ptr.pp_double[k][iis] = (double)(0); } } else { if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); matrixvectormultiply(vl, 1, n, ki+1, n, ae_false, &work, ki+1+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); } ii = columnidxabsmax(vl, 1, n, ki, _state); remax = 1/ae_fabs(vl->ptr.pp_double[ii][ki], _state); ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); } } else { /* * Complex left eigenvector. * * Initial solve: * ((T(KI,KI) T(KI,KI+1) )' - (WR - I* WI))*X = 0. * ((T(KI+1,KI) T(KI+1,KI+1)) ) */ if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki][ki+1], _state),ae_fabs(t->ptr.pp_double[ki+1][ki], _state)) ) { work.ptr.p_double[ki+n] = wi/t->ptr.pp_double[ki][ki+1]; work.ptr.p_double[ki+1+n2] = (double)(1); } else { work.ptr.p_double[ki+n] = (double)(1); work.ptr.p_double[ki+1+n2] = -wi/t->ptr.pp_double[ki+1][ki]; } work.ptr.p_double[ki+1+n] = (double)(0); work.ptr.p_double[ki+n2] = (double)(0); /* * Form right-hand side */ for(k=ki+2; k<=n; k++) { work.ptr.p_double[k+n] = -work.ptr.p_double[ki+n]*t->ptr.pp_double[ki][k]; work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+1+n2]*t->ptr.pp_double[ki+1][k]; } /* * Solve complex quasi-triangular system: * ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 */ vmax = (double)(1); vcrit = bignum; jnxt = ki+2; for(j=ki+2; j<=n; j++) { if( jptr.pp_double[j+1][j],(double)(0)) ) { j2 = j+1; jnxt = j+2; } } if( j1==j2 ) { /* * 1-by-1 diagonal block * * Scale if necessary to avoid overflow when * forming the right-hand side elements. */ if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) { rec = 1/vmax; ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); vmax = (double)(1); vcrit = bignum; } vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; /* * Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 */ temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+n2], _state), vmax, _state), _state); vcrit = bignum/vmax; } else { /* * 2-by-2 diagonal block * * Scale if necessary to avoid overflow when forming * the right-hand side elements. */ beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); if( ae_fp_greater(beta,vcrit) ) { rec = 1/vmax; ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); vmax = (double)(1); vcrit = bignum; } vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); work.ptr.p_double[j+1+n2] = work.ptr.p_double[j+1+n2]-vt; /* * Solve 2-by-2 complex linear equation * ([T(j,j) T(j,j+1) ]'-(wr-i*wi)*I)*X = SCALE*B * ([T(j+1,j) T(j+1,j+1)] ) */ temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+1+n+n]; evd_internalhsevdlaln2(ae_true, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); /* * Scale if necessary */ if( ae_fp_neq(scl,(double)(1)) ) { ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); } work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; work.ptr.p_double[j+1+n2] = x.ptr.pp_double[2][2]; vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][1], _state), vmax, _state); vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][2], _state), vmax, _state); vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][1], _state), vmax, _state); vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][2], _state), vmax, _state); vcrit = bignum/vmax; } } /* * Copy the vector x or Q*x to VL and normalize. */ if( !over ) { ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); ae_v_move(&vl->ptr.pp_double[ki][iis+1], vl->stride, &work.ptr.p_double[ki+n2], 1, ae_v_len(ki,n)); emax = (double)(0); for(k=ki; k<=n; k++) { emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][iis], _state)+ae_fabs(vl->ptr.pp_double[k][iis+1], _state), _state); } remax = 1/emax; ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); ae_v_muld(&vl->ptr.pp_double[ki][iis+1], vl->stride, ae_v_len(ki,n), remax); for(k=1; k<=ki-1; k++) { vl->ptr.pp_double[k][iis] = (double)(0); vl->ptr.pp_double[k][iis+1] = (double)(0); } } else { if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); ae_v_move(&temp.ptr.p_double[1], 1, &vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n)); matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n2, n+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+1+n2], _state); ae_v_move(&vl->ptr.pp_double[1][ki+1], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); } else { vt = work.ptr.p_double[ki+n]; ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), vt); vt = work.ptr.p_double[ki+1+n2]; ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), vt); } emax = (double)(0); for(k=1; k<=n; k++) { emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][ki], _state)+ae_fabs(vl->ptr.pp_double[k][ki+1], _state), _state); } remax = 1/emax; ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), remax); } } iis = iis+1; if( ip!=0 ) { iis = iis+1; } } if( ip==-1 ) { ip = 0; } if( ip==1 ) { ip = -1; } } } ae_frame_leave(_state); } /************************************************************************* DLALN2 solves a system of the form (ca A - w D ) X = s B or (ca A' - w D) X = s B with possible scaling ("s") and perturbation of A. (A' means A-transpose.) A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA real diagonal matrix, w is a real or complex value, and X and B are NA x 1 matrices -- real if w is real, complex if w is complex. NA may be 1 or 2. If w is complex, X and B are represented as NA x 2 matrices, the first column of each being the real part and the second being the imaginary part. "s" is a scaling factor (.LE. 1), computed by DLALN2, which is so chosen that X can be computed without overflow. X is further scaled if necessary to assure that norm(ca A - w D)*norm(X) is less than overflow. If both singular values of (ca A - w D) are less than SMIN, SMIN*identity will be used instead of (ca A - w D). If only one singular value is less than SMIN, one element of (ca A - w D) will be perturbed enough to make the smallest singular value roughly SMIN. If both singular values are at least SMIN, (ca A - w D) will not be perturbed. In any case, the perturbation will be at most some small multiple of max( SMIN, ulp*norm(ca A - w D) ). The singular values are computed by infinity-norm approximations, and thus will only be correct to a factor of 2 or so. Note: all input quantities are assumed to be smaller than overflow by a reasonable factor. (See BIGNUM.) -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ static void evd_internalhsevdlaln2(ae_bool ltrans, ae_int_t na, ae_int_t nw, double smin, double ca, /* Real */ ae_matrix* a, double d1, double d2, /* Real */ ae_matrix* b, double wr, double wi, /* Boolean */ ae_vector* rswap4, /* Boolean */ ae_vector* zswap4, /* Integer */ ae_matrix* ipivot44, /* Real */ ae_vector* civ4, /* Real */ ae_vector* crv4, /* Real */ ae_matrix* x, double* scl, double* xnorm, ae_int_t* info, ae_state *_state) { ae_int_t icmax; ae_int_t j; double bbnd; double bi1; double bi2; double bignum; double bnorm; double br1; double br2; double ci21; double ci22; double cmax; double cnorm; double cr21; double cr22; double csi; double csr; double li21; double lr21; double smini; double smlnum; double temp; double u22abs; double ui11; double ui11r; double ui12; double ui12s; double ui22; double ur11; double ur11r; double ur12; double ur12s; double ur22; double xi1; double xi2; double xr1; double xr2; double tmp1; double tmp2; *scl = 0; *xnorm = 0; *info = 0; zswap4->ptr.p_bool[1] = ae_false; zswap4->ptr.p_bool[2] = ae_false; zswap4->ptr.p_bool[3] = ae_true; zswap4->ptr.p_bool[4] = ae_true; rswap4->ptr.p_bool[1] = ae_false; rswap4->ptr.p_bool[2] = ae_true; rswap4->ptr.p_bool[3] = ae_false; rswap4->ptr.p_bool[4] = ae_true; ipivot44->ptr.pp_int[1][1] = 1; ipivot44->ptr.pp_int[2][1] = 2; ipivot44->ptr.pp_int[3][1] = 3; ipivot44->ptr.pp_int[4][1] = 4; ipivot44->ptr.pp_int[1][2] = 2; ipivot44->ptr.pp_int[2][2] = 1; ipivot44->ptr.pp_int[3][2] = 4; ipivot44->ptr.pp_int[4][2] = 3; ipivot44->ptr.pp_int[1][3] = 3; ipivot44->ptr.pp_int[2][3] = 4; ipivot44->ptr.pp_int[3][3] = 1; ipivot44->ptr.pp_int[4][3] = 2; ipivot44->ptr.pp_int[1][4] = 4; ipivot44->ptr.pp_int[2][4] = 3; ipivot44->ptr.pp_int[3][4] = 2; ipivot44->ptr.pp_int[4][4] = 1; smlnum = 2*ae_minrealnumber; bignum = 1/smlnum; smini = ae_maxreal(smin, smlnum, _state); /* * Don't check for input errors */ *info = 0; /* * Standard Initializations */ *scl = (double)(1); if( na==1 ) { /* * 1 x 1 (i.e., scalar) system C X = B */ if( nw==1 ) { /* * Real 1x1 system. * * C = ca A - w D */ csr = ca*a->ptr.pp_double[1][1]-wr*d1; cnorm = ae_fabs(csr, _state); /* * If | C | < SMINI, use C = SMINI */ if( ae_fp_less(cnorm,smini) ) { csr = smini; cnorm = smini; *info = 1; } /* * Check scaling for X = B / C */ bnorm = ae_fabs(b->ptr.pp_double[1][1], _state); if( ae_fp_less(cnorm,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) { if( ae_fp_greater(bnorm,bignum*cnorm) ) { *scl = 1/bnorm; } } /* * Compute X */ x->ptr.pp_double[1][1] = b->ptr.pp_double[1][1]*(*scl)/csr; *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state); } else { /* * Complex 1x1 system (w is complex) * * C = ca A - w D */ csr = ca*a->ptr.pp_double[1][1]-wr*d1; csi = -wi*d1; cnorm = ae_fabs(csr, _state)+ae_fabs(csi, _state); /* * If | C | < SMINI, use C = SMINI */ if( ae_fp_less(cnorm,smini) ) { csr = smini; csi = (double)(0); cnorm = smini; *info = 1; } /* * Check scaling for X = B / C */ bnorm = ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state); if( ae_fp_less(cnorm,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) { if( ae_fp_greater(bnorm,bignum*cnorm) ) { *scl = 1/bnorm; } } /* * Compute X */ evd_internalhsevdladiv(*scl*b->ptr.pp_double[1][1], *scl*b->ptr.pp_double[1][2], csr, csi, &tmp1, &tmp2, _state); x->ptr.pp_double[1][1] = tmp1; x->ptr.pp_double[1][2] = tmp2; *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state)+ae_fabs(x->ptr.pp_double[1][2], _state); } } else { /* * 2x2 System * * Compute the real part of C = ca A - w D (or ca A' - w D ) */ crv4->ptr.p_double[1+0] = ca*a->ptr.pp_double[1][1]-wr*d1; crv4->ptr.p_double[2+2] = ca*a->ptr.pp_double[2][2]-wr*d2; if( ltrans ) { crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[2][1]; crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[1][2]; } else { crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[2][1]; crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[1][2]; } if( nw==1 ) { /* * Real 2x2 system (w is real) * * Find the largest element in C */ cmax = (double)(0); icmax = 0; for(j=1; j<=4; j++) { if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state),cmax) ) { cmax = ae_fabs(crv4->ptr.p_double[j], _state); icmax = j; } } /* * If norm(C) < SMINI, use SMINI*identity. */ if( ae_fp_less(cmax,smini) ) { bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state), ae_fabs(b->ptr.pp_double[2][1], _state), _state); if( ae_fp_less(smini,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) { if( ae_fp_greater(bnorm,bignum*smini) ) { *scl = 1/bnorm; } } temp = *scl/smini; x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; *xnorm = temp*bnorm; *info = 1; return; } /* * Gaussian elimination with complete pivoting. */ ur11 = crv4->ptr.p_double[icmax]; cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; ur11r = 1/ur11; lr21 = ur11r*cr21; ur22 = cr22-ur12*lr21; /* * If smaller pivot < SMINI, use SMINI */ if( ae_fp_less(ae_fabs(ur22, _state),smini) ) { ur22 = smini; *info = 1; } if( rswap4->ptr.p_bool[icmax] ) { br1 = b->ptr.pp_double[2][1]; br2 = b->ptr.pp_double[1][1]; } else { br1 = b->ptr.pp_double[1][1]; br2 = b->ptr.pp_double[2][1]; } br2 = br2-lr21*br1; bbnd = ae_maxreal(ae_fabs(br1*(ur22*ur11r), _state), ae_fabs(br2, _state), _state); if( ae_fp_greater(bbnd,(double)(1))&&ae_fp_less(ae_fabs(ur22, _state),(double)(1)) ) { if( ae_fp_greater_eq(bbnd,bignum*ae_fabs(ur22, _state)) ) { *scl = 1/bbnd; } } xr2 = br2*(*scl)/ur22; xr1 = *scl*br1*ur11r-xr2*(ur11r*ur12); if( zswap4->ptr.p_bool[icmax] ) { x->ptr.pp_double[1][1] = xr2; x->ptr.pp_double[2][1] = xr1; } else { x->ptr.pp_double[1][1] = xr1; x->ptr.pp_double[2][1] = xr2; } *xnorm = ae_maxreal(ae_fabs(xr1, _state), ae_fabs(xr2, _state), _state); /* * Further scaling if norm(A) norm(X) > overflow */ if( ae_fp_greater(*xnorm,(double)(1))&&ae_fp_greater(cmax,(double)(1)) ) { if( ae_fp_greater(*xnorm,bignum/cmax) ) { temp = cmax/bignum; x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; *xnorm = temp*(*xnorm); *scl = temp*(*scl); } } } else { /* * Complex 2x2 system (w is complex) * * Find the largest element in C */ civ4->ptr.p_double[1+0] = -wi*d1; civ4->ptr.p_double[2+0] = (double)(0); civ4->ptr.p_double[1+2] = (double)(0); civ4->ptr.p_double[2+2] = -wi*d2; cmax = (double)(0); icmax = 0; for(j=1; j<=4; j++) { if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state),cmax) ) { cmax = ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state); icmax = j; } } /* * If norm(C) < SMINI, use SMINI*identity. */ if( ae_fp_less(cmax,smini) ) { bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state), ae_fabs(b->ptr.pp_double[2][1], _state)+ae_fabs(b->ptr.pp_double[2][2], _state), _state); if( ae_fp_less(smini,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) { if( ae_fp_greater(bnorm,bignum*smini) ) { *scl = 1/bnorm; } } temp = *scl/smini; x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; x->ptr.pp_double[1][2] = temp*b->ptr.pp_double[1][2]; x->ptr.pp_double[2][2] = temp*b->ptr.pp_double[2][2]; *xnorm = temp*bnorm; *info = 1; return; } /* * Gaussian elimination with complete pivoting. */ ur11 = crv4->ptr.p_double[icmax]; ui11 = civ4->ptr.p_double[icmax]; cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; ci21 = civ4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; ui12 = civ4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; ci22 = civ4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; if( icmax==1||icmax==4 ) { /* * Code when off-diagonals of pivoted C are real */ if( ae_fp_greater(ae_fabs(ur11, _state),ae_fabs(ui11, _state)) ) { temp = ui11/ur11; ur11r = 1/(ur11*(1+ae_sqr(temp, _state))); ui11r = -temp*ur11r; } else { temp = ur11/ui11; ui11r = -1/(ui11*(1+ae_sqr(temp, _state))); ur11r = -temp*ui11r; } lr21 = cr21*ur11r; li21 = cr21*ui11r; ur12s = ur12*ur11r; ui12s = ur12*ui11r; ur22 = cr22-ur12*lr21; ui22 = ci22-ur12*li21; } else { /* * Code when diagonals of pivoted C are real */ ur11r = 1/ur11; ui11r = (double)(0); lr21 = cr21*ur11r; li21 = ci21*ur11r; ur12s = ur12*ur11r; ui12s = ui12*ur11r; ur22 = cr22-ur12*lr21+ui12*li21; ui22 = -ur12*li21-ui12*lr21; } u22abs = ae_fabs(ur22, _state)+ae_fabs(ui22, _state); /* * If smaller pivot < SMINI, use SMINI */ if( ae_fp_less(u22abs,smini) ) { ur22 = smini; ui22 = (double)(0); *info = 1; } if( rswap4->ptr.p_bool[icmax] ) { br2 = b->ptr.pp_double[1][1]; br1 = b->ptr.pp_double[2][1]; bi2 = b->ptr.pp_double[1][2]; bi1 = b->ptr.pp_double[2][2]; } else { br1 = b->ptr.pp_double[1][1]; br2 = b->ptr.pp_double[2][1]; bi1 = b->ptr.pp_double[1][2]; bi2 = b->ptr.pp_double[2][2]; } br2 = br2-lr21*br1+li21*bi1; bi2 = bi2-li21*br1-lr21*bi1; bbnd = ae_maxreal((ae_fabs(br1, _state)+ae_fabs(bi1, _state))*(u22abs*(ae_fabs(ur11r, _state)+ae_fabs(ui11r, _state))), ae_fabs(br2, _state)+ae_fabs(bi2, _state), _state); if( ae_fp_greater(bbnd,(double)(1))&&ae_fp_less(u22abs,(double)(1)) ) { if( ae_fp_greater_eq(bbnd,bignum*u22abs) ) { *scl = 1/bbnd; br1 = *scl*br1; bi1 = *scl*bi1; br2 = *scl*br2; bi2 = *scl*bi2; } } evd_internalhsevdladiv(br2, bi2, ur22, ui22, &xr2, &xi2, _state); xr1 = ur11r*br1-ui11r*bi1-ur12s*xr2+ui12s*xi2; xi1 = ui11r*br1+ur11r*bi1-ui12s*xr2-ur12s*xi2; if( zswap4->ptr.p_bool[icmax] ) { x->ptr.pp_double[1][1] = xr2; x->ptr.pp_double[2][1] = xr1; x->ptr.pp_double[1][2] = xi2; x->ptr.pp_double[2][2] = xi1; } else { x->ptr.pp_double[1][1] = xr1; x->ptr.pp_double[2][1] = xr2; x->ptr.pp_double[1][2] = xi1; x->ptr.pp_double[2][2] = xi2; } *xnorm = ae_maxreal(ae_fabs(xr1, _state)+ae_fabs(xi1, _state), ae_fabs(xr2, _state)+ae_fabs(xi2, _state), _state); /* * Further scaling if norm(A) norm(X) > overflow */ if( ae_fp_greater(*xnorm,(double)(1))&&ae_fp_greater(cmax,(double)(1)) ) { if( ae_fp_greater(*xnorm,bignum/cmax) ) { temp = cmax/bignum; x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; x->ptr.pp_double[1][2] = temp*x->ptr.pp_double[1][2]; x->ptr.pp_double[2][2] = temp*x->ptr.pp_double[2][2]; *xnorm = temp*(*xnorm); *scl = temp*(*scl); } } } } } /************************************************************************* performs complex division in real arithmetic a + i*b p + i*q = --------- c + i*d The algorithm is due to Robert L. Smith and can be found in D. Knuth, The art of Computer Programming, Vol.2, p.195 -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ static void evd_internalhsevdladiv(double a, double b, double c, double d, double* p, double* q, ae_state *_state) { double e; double f; *p = 0; *q = 0; if( ae_fp_less(ae_fabs(d, _state),ae_fabs(c, _state)) ) { e = d/c; f = c+d*e; *p = (a+b*e)/f; *q = (b-a*e)/f; } else { e = c/d; f = d+c*e; *p = (b+a*e)/f; *q = (-a+b*e)/f; } } /************************************************************************* Generation of a random uniformly distributed (Haar) orthogonal matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonal(ae_int_t n, /* Real */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_assert(n>=1, "RMatrixRndOrthogonal: N<1!", _state); ae_matrix_set_length(a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a->ptr.pp_double[i][j] = (double)(1); } else { a->ptr.pp_double[i][j] = (double)(0); } } } rmatrixrndorthogonalfromtheright(a, n, n, _state); } /************************************************************************* Generation of random NxN matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&rs, _state); ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "RMatrixRndCond: N<1 or C<1!", _state); ae_matrix_set_length(a, n, n, _state); if( n==1 ) { /* * special case */ a->ptr.pp_double[0][0] = (double)(2*ae_randominteger(2, _state)-1); ae_frame_leave(_state); return; } hqrndrandomize(&rs, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } a->ptr.pp_double[0][0] = ae_exp(l1, _state); for(i=1; i<=n-2; i++) { a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); } a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); rmatrixrndorthogonalfromtheleft(a, n, n, _state); rmatrixrndorthogonalfromtheright(a, n, n, _state); ae_frame_leave(_state); } /************************************************************************* Generation of a random Haar distributed orthogonal complex matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonal(ae_int_t n, /* Complex */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_assert(n>=1, "CMatrixRndOrthogonal: N<1!", _state); ae_matrix_set_length(a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a->ptr.pp_complex[i][j] = ae_complex_from_i(1); } else { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } cmatrixrndorthogonalfromtheright(a, n, n, _state); } /************************************************************************* Generation of random NxN complex matrix with given condition number C and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate state; ae_complex v; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&state, _state); ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "CMatrixRndCond: N<1 or C<1!", _state); ae_matrix_set_length(a, n, n, _state); if( n==1 ) { /* * special case */ hqrndrandomize(&state, _state); hqrndunit2(&state, &v.x, &v.y, _state); a->ptr.pp_complex[0][0] = v; ae_frame_leave(_state); return; } hqrndrandomize(&state, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); for(i=1; i<=n-2; i++) { a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&state, _state)*(l2-l1)+l1, _state)); } a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); cmatrixrndorthogonalfromtheleft(a, n, n, _state); cmatrixrndorthogonalfromtheright(a, n, n, _state); ae_frame_leave(_state); } /************************************************************************* Generation of random NxN symmetric matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&rs, _state); ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "SMatrixRndCond: N<1 or C<1!", _state); ae_matrix_set_length(a, n, n, _state); if( n==1 ) { /* * special case */ a->ptr.pp_double[0][0] = (double)(2*ae_randominteger(2, _state)-1); ae_frame_leave(_state); return; } /* * Prepare matrix */ hqrndrandomize(&rs, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } a->ptr.pp_double[0][0] = ae_exp(l1, _state); for(i=1; i<=n-2; i++) { a->ptr.pp_double[i][i] = (2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); } a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); /* * Multiply */ smatrixrndmultiply(a, n, _state); ae_frame_leave(_state); } /************************************************************************* Generation of random NxN symmetric positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random SPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void spdmatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&rs, _state); /* * Special cases */ if( n<=0||ae_fp_less(c,(double)(1)) ) { ae_frame_leave(_state); return; } ae_matrix_set_length(a, n, n, _state); if( n==1 ) { a->ptr.pp_double[0][0] = (double)(1); ae_frame_leave(_state); return; } /* * Prepare matrix */ hqrndrandomize(&rs, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } a->ptr.pp_double[0][0] = ae_exp(l1, _state); for(i=1; i<=n-2; i++) { a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); } a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); /* * Multiply */ smatrixrndmultiply(a, n, _state); ae_frame_leave(_state); } /************************************************************************* Generation of random NxN Hermitian matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&rs, _state); ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "HMatrixRndCond: N<1 or C<1!", _state); ae_matrix_set_length(a, n, n, _state); if( n==1 ) { /* * special case */ a->ptr.pp_complex[0][0] = ae_complex_from_i(2*ae_randominteger(2, _state)-1); ae_frame_leave(_state); return; } /* * Prepare matrix */ hqrndrandomize(&rs, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); for(i=1; i<=n-2; i++) { a->ptr.pp_complex[i][i] = ae_complex_from_d((2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); } a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); /* * Multiply */ hmatrixrndmultiply(a, n, _state); /* * post-process to ensure that matrix diagonal is real */ for(i=0; i<=n-1; i++) { a->ptr.pp_complex[i][i].y = (double)(0); } ae_frame_leave(_state); } /************************************************************************* Generation of random NxN Hermitian positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random HPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hpdmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double l1; double l2; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_clear(a); _hqrndstate_init(&rs, _state); /* * Special cases */ if( n<=0||ae_fp_less(c,(double)(1)) ) { ae_frame_leave(_state); return; } ae_matrix_set_length(a, n, n, _state); if( n==1 ) { a->ptr.pp_complex[0][0] = ae_complex_from_i(1); ae_frame_leave(_state); return; } /* * Prepare matrix */ hqrndrandomize(&rs, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); for(i=1; i<=n-2; i++) { a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); } a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); /* * Multiply */ hmatrixrndmultiply(a, n, _state); /* * post-process to ensure that matrix diagonal is real */ for(i=0; i<=n-1; i++) { a->ptr.pp_complex[i][i].y = (double)(0); } ae_frame_leave(_state); } /************************************************************************* Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state) { ae_frame _frame_block; double tau; double lambdav; ae_int_t s; ae_int_t i; double u1; double u2; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); _hqrndstate_init(&state, _state); ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); if( n==1 ) { /* * Special case */ tau = (double)(2*ae_randominteger(2, _state)-1); for(i=0; i<=m-1; i++) { a->ptr.pp_double[i][0] = a->ptr.pp_double[i][0]*tau; } ae_frame_leave(_state); return; } /* * General case. * First pass. */ ae_vector_set_length(&w, m, _state); ae_vector_set_length(&v, n+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=n; s++) { /* * Prepare random normal v */ do { i = 1; while(i<=s) { hqrndnormal2(&state, &u1, &u2, _state); v.ptr.p_double[i] = u1; if( i+1<=s ) { v.ptr.p_double[i+1] = u2; } i = i+2; } lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); } while(ae_fp_eq(lambdav,(double)(0))); /* * Prepare and apply reflection */ generatereflection(&v, s, &tau, _state); v.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=n-1; i++) { tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,m-1), tau); } ae_frame_leave(_state); } /************************************************************************* Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state) { ae_frame _frame_block; double tau; double lambdav; ae_int_t s; ae_int_t i; ae_int_t j; double u1; double u2; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); _hqrndstate_init(&state, _state); ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); if( m==1 ) { /* * special case */ tau = (double)(2*ae_randominteger(2, _state)-1); for(j=0; j<=n-1; j++) { a->ptr.pp_double[0][j] = a->ptr.pp_double[0][j]*tau; } ae_frame_leave(_state); return; } /* * General case. * First pass. */ ae_vector_set_length(&w, n, _state); ae_vector_set_length(&v, m+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=m; s++) { /* * Prepare random normal v */ do { i = 1; while(i<=s) { hqrndnormal2(&state, &u1, &u2, _state); v.ptr.p_double[i] = u1; if( i+1<=s ) { v.ptr.p_double[i+1] = u2; } i = i+2; } lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); } while(ae_fp_eq(lambdav,(double)(0))); /* * Prepare and apply reflection */ generatereflection(&v, s, &tau, _state); v.ptr.p_double[1] = (double)(1); applyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=m-1; i++) { tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); } ae_frame_leave(_state); } /************************************************************************* Multiplication of MxN complex matrix by NxN random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_complex lambdav; ae_complex tau; ae_int_t s; ae_int_t i; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_COMPLEX, _state); ae_vector_init(&v, 0, DT_COMPLEX, _state); _hqrndstate_init(&state, _state); ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); if( n==1 ) { /* * Special case */ hqrndrandomize(&state, _state); hqrndunit2(&state, &tau.x, &tau.y, _state); for(i=0; i<=m-1; i++) { a->ptr.pp_complex[i][0] = ae_c_mul(a->ptr.pp_complex[i][0],tau); } ae_frame_leave(_state); return; } /* * General case. * First pass. */ ae_vector_set_length(&w, m, _state); ae_vector_set_length(&v, n+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=n; s++) { /* * Prepare random normal v */ do { for(i=1; i<=s; i++) { hqrndnormal2(&state, &tau.x, &tau.y, _state); v.ptr.p_complex[i] = tau; } lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); } while(ae_c_eq_d(lambdav,(double)(0))); /* * Prepare and apply reflection */ complexgeneratereflection(&v, s, &tau, _state); v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=n-1; i++) { hqrndunit2(&state, &tau.x, &tau.y, _state); ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,m-1), tau); } ae_frame_leave(_state); } /************************************************************************* Multiplication of MxN complex matrix by MxM random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_complex tau; ae_complex lambdav; ae_int_t s; ae_int_t i; ae_int_t j; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_COMPLEX, _state); ae_vector_init(&v, 0, DT_COMPLEX, _state); _hqrndstate_init(&state, _state); ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); if( m==1 ) { /* * special case */ hqrndrandomize(&state, _state); hqrndunit2(&state, &tau.x, &tau.y, _state); for(j=0; j<=n-1; j++) { a->ptr.pp_complex[0][j] = ae_c_mul(a->ptr.pp_complex[0][j],tau); } ae_frame_leave(_state); return; } /* * General case. * First pass. */ ae_vector_set_length(&w, n, _state); ae_vector_set_length(&v, m+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=m; s++) { /* * Prepare random normal v */ do { for(i=1; i<=s; i++) { hqrndnormal2(&state, &tau.x, &tau.y, _state); v.ptr.p_complex[i] = tau; } lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); } while(ae_c_eq_d(lambdav,(double)(0))); /* * Prepare and apply reflection */ complexgeneratereflection(&v, s, &tau, _state); v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=m-1; i++) { hqrndunit2(&state, &tau.x, &tau.y, _state); ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); } ae_frame_leave(_state); } /************************************************************************* Symmetric multiplication of NxN matrix by random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q'*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndmultiply(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; double tau; double lambdav; ae_int_t s; ae_int_t i; double u1; double u2; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); _hqrndstate_init(&state, _state); /* * General case. */ ae_vector_set_length(&w, n, _state); ae_vector_set_length(&v, n+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=n; s++) { /* * Prepare random normal v */ do { i = 1; while(i<=s) { hqrndnormal2(&state, &u1, &u2, _state); v.ptr.p_double[i] = u1; if( i+1<=s ) { v.ptr.p_double[i+1] = u2; } i = i+2; } lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); } while(ae_fp_eq(lambdav,(double)(0))); /* * Prepare and apply reflection */ generatereflection(&v, s, &tau, _state); v.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); applyreflectionfromtheleft(a, tau, &v, n-s, n-1, 0, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=n-1; i++) { tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,n-1), tau); ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); } /* * Copy upper triangle to lower */ for(i=0; i<=n-2; i++) { ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &a->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1)); } ae_frame_leave(_state); } /************************************************************************* Hermitian multiplication of NxN matrix by random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q^H*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndmultiply(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_complex tau; ae_complex lambdav; ae_int_t s; ae_int_t i; ae_vector w; ae_vector v; hqrndstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_COMPLEX, _state); ae_vector_init(&v, 0, DT_COMPLEX, _state); _hqrndstate_init(&state, _state); /* * General case. */ ae_vector_set_length(&w, n, _state); ae_vector_set_length(&v, n+1, _state); hqrndrandomize(&state, _state); for(s=2; s<=n; s++) { /* * Prepare random normal v */ do { for(i=1; i<=s; i++) { hqrndnormal2(&state, &tau.x, &tau.y, _state); v.ptr.p_complex[i] = tau; } lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); } while(ae_c_eq_d(lambdav,(double)(0))); /* * Prepare and apply reflection */ complexgeneratereflection(&v, s, &tau, _state); v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); complexapplyreflectionfromtheleft(a, ae_c_conj(tau, _state), &v, n-s, n-1, 0, n-1, &w, _state); } /* * Second pass. */ for(i=0; i<=n-1; i++) { hqrndunit2(&state, &tau.x, &tau.y, _state); ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,n-1), tau); tau = ae_c_conj(tau, _state); ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); } /* * Change all values from lower triangle by complex-conjugate values * from upper one */ for(i=0; i<=n-2; i++) { ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &a->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1)); } for(s=0; s<=n-2; s++) { for(i=s+1; i<=n-1; i++) { a->ptr.pp_complex[i][s].y = -a->ptr.pp_complex[i][s].y; } } ae_frame_leave(_state); } /************************************************************************* This function creates sparse matrix in a Hash-Table format. This function creates Hast-Table matrix, which can be converted to CRS format after its initialization is over. Typical usage scenario for a sparse matrix is: 1. creation in a Hash-Table format 2. insertion of the matrix elements 3. conversion to the CRS representation 4. matrix is passed to some linear algebra algorithm Some information about different matrix formats can be found below, in the "NOTES" section. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. NOTE 1 Hash-tables use memory inefficiently, and they have to keep some amount of the "spare memory" in order to have good performance. Hash table for matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, where C is a small constant, about 1.5-2 in magnitude. CRS storage, from the other side, is more memory-efficient, and needs just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows in a matrix. When you convert from the Hash-Table to CRS representation, all unneeded memory will be freed. NOTE 2 Comments of SparseMatrix structure outline information about different sparse storage formats. We recommend you to read them before starting to use ALGLIB sparse matrices. NOTE 3 This function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreate(ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix* s, ae_state *_state) { _sparsematrix_clear(s); sparsecreatebuf(m, n, k, s, _state); } /************************************************************************* This version of SparseCreate function creates sparse matrix in Hash-Table format, reusing previously allocated storage as much as possible. Read comments for SparseCreate() for more information. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. S - SparseMatrix structure which MAY contain some already allocated storage. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. Previously allocated storage is reused, if its size is compatible with expected number of non-zeros K. -- ALGLIB PROJECT -- Copyright 14.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatebuf(ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix* s, ae_state *_state) { ae_int_t i; ae_assert(m>0, "SparseCreateBuf: M<=0", _state); ae_assert(n>0, "SparseCreateBuf: N<=0", _state); ae_assert(k>=0, "SparseCreateBuf: K<0", _state); /* * Hash-table size is max(existing_size,requested_size) * * NOTE: it is important to use ALL available memory for hash table * because it is impossible to efficiently reallocate table * without temporary storage. So, if we want table with up to * 1.000.000 elements, we have to create such table from the * very beginning. Otherwise, the very idea of memory reuse * will be compromised. */ s->tablesize = ae_round(k/sparse_desiredloadfactor+sparse_additional, _state); rvectorsetlengthatleast(&s->vals, s->tablesize, _state); s->tablesize = s->vals.cnt; /* * Initialize other fields */ s->matrixtype = 0; s->m = m; s->n = n; s->nfree = s->tablesize; ivectorsetlengthatleast(&s->idx, 2*s->tablesize, _state); for(i=0; i<=s->tablesize-1; i++) { s->idx.ptr.p_int[2*i] = -1; } } /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateCRSBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrs(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* ner, sparsematrix* s, ae_state *_state) { ae_int_t i; _sparsematrix_clear(s); ae_assert(m>0, "SparseCreateCRS: M<=0", _state); ae_assert(n>0, "SparseCreateCRS: N<=0", _state); ae_assert(ner->cnt>=m, "SparseCreateCRS: Length(NER)ptr.p_int[i]>=0, "SparseCreateCRS: NER[] contains negative elements", _state); } sparsecreatecrsbuf(m, n, ner, s, _state); } /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This version of CRS matrix creation function may reuse memory already allocated in S. This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 S - sparse matrix structure with possibly preallocated memory. OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrsbuf(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* ner, sparsematrix* s, ae_state *_state) { ae_int_t i; ae_int_t noe; ae_assert(m>0, "SparseCreateCRSBuf: M<=0", _state); ae_assert(n>0, "SparseCreateCRSBuf: N<=0", _state); ae_assert(ner->cnt>=m, "SparseCreateCRSBuf: Length(NER)matrixtype = 1; s->ninitialized = 0; s->m = m; s->n = n; ivectorsetlengthatleast(&s->ridx, s->m+1, _state); s->ridx.ptr.p_int[0] = 0; for(i=0; i<=s->m-1; i++) { ae_assert(ner->ptr.p_int[i]>=0, "SparseCreateCRSBuf: NER[] contains negative elements", _state); noe = noe+ner->ptr.p_int[i]; s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+ner->ptr.p_int[i]; } rvectorsetlengthatleast(&s->vals, noe, _state); ivectorsetlengthatleast(&s->idx, noe, _state); if( noe==0 ) { sparse_sparseinitduidx(s, _state); } } /************************************************************************* This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], D[I]>=0. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], U[I]>=0. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseRewriteExisting() to change their values. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateSKSBuf function. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesks(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* d, /* Integer */ ae_vector* u, sparsematrix* s, ae_state *_state) { ae_int_t i; _sparsematrix_clear(s); ae_assert(m>0, "SparseCreateSKS: M<=0", _state); ae_assert(n>0, "SparseCreateSKS: N<=0", _state); ae_assert(m==n, "SparseCreateSKS: M<>N", _state); ae_assert(d->cnt>=m, "SparseCreateSKS: Length(D)cnt>=n, "SparseCreateSKS: Length(U)ptr.p_int[i]>=0, "SparseCreateSKS: D[] contains negative elements", _state); ae_assert(d->ptr.p_int[i]<=i, "SparseCreateSKS: D[I]>I for some I", _state); } for(i=0; i<=n-1; i++) { ae_assert(u->ptr.p_int[i]>=0, "SparseCreateSKS: U[] contains negative elements", _state); ae_assert(u->ptr.p_int[i]<=i, "SparseCreateSKS: U[I]>I for some I", _state); } sparsecreatesksbuf(m, n, d, u, s, _state); } /************************************************************************* This is "buffered" version of SparseCreateSKS() which reuses memory previously allocated in S (of course, memory is reallocated if needed). This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], 0<=D[I]<=I. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], 0<=U[I]<=I. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseSet()/SparseAdd() to change their values. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesksbuf(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* d, /* Integer */ ae_vector* u, sparsematrix* s, ae_state *_state) { ae_int_t i; ae_int_t minmn; ae_int_t nz; ae_int_t mxd; ae_int_t mxu; ae_assert(m>0, "SparseCreateSKSBuf: M<=0", _state); ae_assert(n>0, "SparseCreateSKSBuf: N<=0", _state); ae_assert(m==n, "SparseCreateSKSBuf: M<>N", _state); ae_assert(d->cnt>=m, "SparseCreateSKSBuf: Length(D)cnt>=n, "SparseCreateSKSBuf: Length(U)ptr.p_int[i]>=0, "SparseCreateSKSBuf: D[] contains negative elements", _state); ae_assert(d->ptr.p_int[i]<=i, "SparseCreateSKSBuf: D[I]>I for some I", _state); } for(i=0; i<=n-1; i++) { ae_assert(u->ptr.p_int[i]>=0, "SparseCreateSKSBuf: U[] contains negative elements", _state); ae_assert(u->ptr.p_int[i]<=i, "SparseCreateSKSBuf: U[I]>I for some I", _state); } minmn = ae_minint(m, n, _state); s->matrixtype = 2; s->ninitialized = 0; s->m = m; s->n = n; ivectorsetlengthatleast(&s->ridx, minmn+1, _state); s->ridx.ptr.p_int[0] = 0; nz = 0; for(i=0; i<=minmn-1; i++) { nz = nz+1+d->ptr.p_int[i]+u->ptr.p_int[i]; s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+1+d->ptr.p_int[i]+u->ptr.p_int[i]; } rvectorsetlengthatleast(&s->vals, nz, _state); for(i=0; i<=nz-1; i++) { s->vals.ptr.p_double[i] = 0.0; } ivectorsetlengthatleast(&s->didx, m+1, _state); mxd = 0; for(i=0; i<=m-1; i++) { s->didx.ptr.p_int[i] = d->ptr.p_int[i]; mxd = ae_maxint(mxd, d->ptr.p_int[i], _state); } s->didx.ptr.p_int[m] = mxd; ivectorsetlengthatleast(&s->uidx, n+1, _state); mxu = 0; for(i=0; i<=n-1; i++) { s->uidx.ptr.p_int[i] = u->ptr.p_int[i]; mxu = ae_maxint(mxu, u->ptr.p_int[i], _state); } s->uidx.ptr.p_int[n] = mxu; } /************************************************************************* This function copies S0 to S1. This function completely deallocates memory owned by S1 before creating a copy of S0. If you want to reuse memory, use SparseCopyBuf. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopy(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { _sparsematrix_clear(s1); sparsecopybuf(s0, s1, _state); } /************************************************************************* This function copies S0 to S1. Memory already allocated in S1 is reused as much as possible. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopybuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { ae_int_t l; ae_int_t i; s1->matrixtype = s0->matrixtype; s1->m = s0->m; s1->n = s0->n; s1->nfree = s0->nfree; s1->ninitialized = s0->ninitialized; s1->tablesize = s0->tablesize; /* * Initialization for arrays */ l = s0->vals.cnt; rvectorsetlengthatleast(&s1->vals, l, _state); for(i=0; i<=l-1; i++) { s1->vals.ptr.p_double[i] = s0->vals.ptr.p_double[i]; } l = s0->ridx.cnt; ivectorsetlengthatleast(&s1->ridx, l, _state); for(i=0; i<=l-1; i++) { s1->ridx.ptr.p_int[i] = s0->ridx.ptr.p_int[i]; } l = s0->idx.cnt; ivectorsetlengthatleast(&s1->idx, l, _state); for(i=0; i<=l-1; i++) { s1->idx.ptr.p_int[i] = s0->idx.ptr.p_int[i]; } /* * Initalization for CRS-parameters */ l = s0->uidx.cnt; ivectorsetlengthatleast(&s1->uidx, l, _state); for(i=0; i<=l-1; i++) { s1->uidx.ptr.p_int[i] = s0->uidx.ptr.p_int[i]; } l = s0->didx.cnt; ivectorsetlengthatleast(&s1->didx, l, _state); for(i=0; i<=l-1; i++) { s1->didx.ptr.p_int[i] = s0->didx.ptr.p_int[i]; } } /************************************************************************* This function efficiently swaps contents of S0 and S1. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseswap(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { swapi(&s1->matrixtype, &s0->matrixtype, _state); swapi(&s1->m, &s0->m, _state); swapi(&s1->n, &s0->n, _state); swapi(&s1->nfree, &s0->nfree, _state); swapi(&s1->ninitialized, &s0->ninitialized, _state); swapi(&s1->tablesize, &s0->tablesize, _state); ae_swap_vectors(&s1->vals, &s0->vals); ae_swap_vectors(&s1->ridx, &s0->ridx); ae_swap_vectors(&s1->idx, &s0->idx); ae_swap_vectors(&s1->uidx, &s0->uidx); ae_swap_vectors(&s1->didx, &s0->didx); } /************************************************************************* This function adds value to S[i,j] - element of the sparse matrix. Matrix must be in a Hash-Table mode. In case S[i,j] already exists in the table, V i added to its value. In case S[i,j] is non-existent, it is inserted in the table. Table automatically grows when necessary. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=Imatrixtype==0, "SparseAdd: matrix must be in the Hash-Table mode to do this operation", _state); ae_assert(i>=0, "SparseAdd: I<0", _state); ae_assert(im, "SparseAdd: I>=M", _state); ae_assert(j>=0, "SparseAdd: J<0", _state); ae_assert(jn, "SparseAdd: J>=N", _state); ae_assert(ae_isfinite(v, _state), "SparseAdd: V is not finite number", _state); if( ae_fp_eq(v,(double)(0)) ) { return; } tcode = -1; k = s->tablesize; if( ae_fp_greater_eq((1-sparse_maxloadfactor)*k,(double)(s->nfree)) ) { sparseresizematrix(s, _state); k = s->tablesize; } hashcode = sparse_hash(i, j, k, _state); for(;;) { if( s->idx.ptr.p_int[2*hashcode]==-1 ) { if( tcode!=-1 ) { hashcode = tcode; } s->vals.ptr.p_double[hashcode] = v; s->idx.ptr.p_int[2*hashcode] = i; s->idx.ptr.p_int[2*hashcode+1] = j; if( tcode==-1 ) { s->nfree = s->nfree-1; } return; } else { if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) { s->vals.ptr.p_double[hashcode] = s->vals.ptr.p_double[hashcode]+v; if( ae_fp_eq(s->vals.ptr.p_double[hashcode],(double)(0)) ) { s->idx.ptr.p_int[2*hashcode] = -2; } return; } /* * Is it deleted element? */ if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) { tcode = hashcode; } /* * Next step */ hashcode = (hashcode+1)%k; } } } /************************************************************************* This function modifies S[i,j] - element of the sparse matrix. For Hash-based storage format: * this function can be called at any moment - during matrix initialization or later * new value can be zero or non-zero. In case new value of S[i,j] is zero, this element is deleted from the table. * this function has no effect when called with zero V for non-existent element. For CRS-bases storage format: * this function can be called ONLY DURING MATRIX INITIALIZATION * new value MUST be non-zero. Exception will be thrown for zero V. * elements must be initialized in correct order - from top row to bottom, within row - from left to right. For SKS storage: NOT SUPPORTED! Use SparseRewriteExisting() to work with SKS matrices. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. I - row index of the element to modify, 0<=Imatrixtype==0||s->matrixtype==1, "SparseSet: unsupported matrix storage format", _state); ae_assert(i>=0, "SparseSet: I<0", _state); ae_assert(im, "SparseSet: I>=M", _state); ae_assert(j>=0, "SparseSet: J<0", _state); ae_assert(jn, "SparseSet: J>=N", _state); ae_assert(ae_isfinite(v, _state), "SparseSet: V is not finite number", _state); /* * Hash-table matrix */ if( s->matrixtype==0 ) { tcode = -1; k = s->tablesize; if( ae_fp_greater_eq((1-sparse_maxloadfactor)*k,(double)(s->nfree)) ) { sparseresizematrix(s, _state); k = s->tablesize; } hashcode = sparse_hash(i, j, k, _state); for(;;) { if( s->idx.ptr.p_int[2*hashcode]==-1 ) { if( ae_fp_neq(v,(double)(0)) ) { if( tcode!=-1 ) { hashcode = tcode; } s->vals.ptr.p_double[hashcode] = v; s->idx.ptr.p_int[2*hashcode] = i; s->idx.ptr.p_int[2*hashcode+1] = j; if( tcode==-1 ) { s->nfree = s->nfree-1; } } return; } else { if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) { if( ae_fp_eq(v,(double)(0)) ) { s->idx.ptr.p_int[2*hashcode] = -2; } else { s->vals.ptr.p_double[hashcode] = v; } return; } if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) { tcode = hashcode; } /* * Next step */ hashcode = (hashcode+1)%k; } } } /* * CRS matrix */ if( s->matrixtype==1 ) { ae_assert(ae_fp_neq(v,(double)(0)), "SparseSet: CRS format does not allow you to write zero elements", _state); ae_assert(s->ridx.ptr.p_int[i]<=s->ninitialized, "SparseSet: too few initialized elements at some row (you have promised more when called SparceCreateCRS)", _state); ae_assert(s->ridx.ptr.p_int[i+1]>s->ninitialized, "SparseSet: too many initialized elements at some row (you have promised less when called SparceCreateCRS)", _state); ae_assert(s->ninitialized==s->ridx.ptr.p_int[i]||s->idx.ptr.p_int[s->ninitialized-1]vals.ptr.p_double[s->ninitialized] = v; s->idx.ptr.p_int[s->ninitialized] = j; s->ninitialized = s->ninitialized+1; /* * If matrix has been created then * initiale 'S.UIdx' and 'S.DIdx' */ if( s->ninitialized==s->ridx.ptr.p_int[s->m] ) { sparse_sparseinitduidx(s, _state); } } } /************************************************************************* This function returns S[i,j] - element of the sparse matrix. Matrix can be in any mode (Hash-Table, CRS, SKS), but this function is less efficient for CRS matrices. Hash-Table and SKS matrices can find element in O(1) time, while CRS matrices need O(log(RS)) time, where RS is an number of non-zero elements in a row. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I=0, "SparseGet: I<0", _state); ae_assert(im, "SparseGet: I>=M", _state); ae_assert(j>=0, "SparseGet: J<0", _state); ae_assert(jn, "SparseGet: J>=N", _state); result = 0.0; if( s->matrixtype==0 ) { /* * Hash-based storage */ result = (double)(0); k = s->tablesize; hashcode = sparse_hash(i, j, k, _state); for(;;) { if( s->idx.ptr.p_int[2*hashcode]==-1 ) { return result; } if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) { result = s->vals.ptr.p_double[hashcode]; return result; } hashcode = (hashcode+1)%k; } } if( s->matrixtype==1 ) { /* * CRS */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGet: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); k0 = s->ridx.ptr.p_int[i]; k1 = s->ridx.ptr.p_int[i+1]-1; result = (double)(0); while(k0<=k1) { k = (k0+k1)/2; if( s->idx.ptr.p_int[k]==j ) { result = s->vals.ptr.p_double[k]; return result; } if( s->idx.ptr.p_int[k]matrixtype==2 ) { /* * SKS */ ae_assert(s->m==s->n, "SparseGet: non-square SKS matrix not supported", _state); result = (double)(0); if( i==j ) { /* * Return diagonal element */ result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]]; return result; } if( jdidx.ptr.p_int[i]; if( i-j<=k ) { result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+k+j-i]; } } else { /* * Return superdiagonal element at J-th "skyline block" */ k = s->uidx.ptr.p_int[j]; if( j-i<=k ) { result = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; } return result; } return result; } ae_assert(ae_false, "SparseGet: unexpected matrix type", _state); return result; } /************************************************************************* This function returns I-th diagonal element of the sparse matrix. Matrix can be in any mode (Hash-Table or CRS storage), but this function is most efficient for CRS matrices - it requires less than 50 CPU cycles to extract diagonal element. For Hash-Table matrices we still have O(1) query time, but function is many times slower. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - index of the element to modify, 0<=I=0, "SparseGetDiagonal: I<0", _state); ae_assert(im, "SparseGetDiagonal: I>=M", _state); ae_assert(in, "SparseGetDiagonal: I>=N", _state); result = (double)(0); if( s->matrixtype==0 ) { result = sparseget(s, i, i, _state); return result; } if( s->matrixtype==1 ) { if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) { result = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; } return result; } if( s->matrixtype==2 ) { ae_assert(s->m==s->n, "SparseGetDiagonal: non-square SKS matrix not supported", _state); result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]]; return result; } ae_assert(ae_false, "SparseGetDiagonal: unexpected matrix type", _state); return result; } /************************************************************************* This function calculates matrix-vector product S*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemv(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { double tval; double v; double vv; ae_int_t i; ae_int_t j; ae_int_t lt; ae_int_t rt; ae_int_t lt1; ae_int_t rt1; ae_int_t n; ae_int_t m; ae_int_t d; ae_int_t u; ae_int_t ri; ae_int_t ri1; ae_assert(x->cnt>=s->n, "SparseMV: length(X)matrixtype==1||s->matrixtype==2, "SparseMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); rvectorsetlengthatleast(y, s->m, _state); n = s->n; m = s->m; if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=m-1; i++) { tval = (double)(0); lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]-1; for(j=lt; j<=rt; j++) { tval = tval+x->ptr.p_double[s->idx.ptr.p_int[j]]*s->vals.ptr.p_double[j]; } y->ptr.p_double[i] = tval; } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseMV: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; v = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); v = v+vv; } y->ptr.p_double[i] = v; if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); } } return; } } /************************************************************************* This function calculates matrix-vector product S^T*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[M], input vector. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemtv(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t lt; ae_int_t rt; ae_int_t ct; ae_int_t lt1; ae_int_t rt1; double v; double vv; ae_int_t n; ae_int_t m; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMTV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(x->cnt>=s->m, "SparseMTV: Length(X)n; m = s->m; rvectorsetlengthatleast(y, n, _state); for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = (double)(0); } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMTV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=m-1; i++) { lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; v = x->ptr.p_double[i]; for(j=lt; j<=rt-1; j++) { ct = s->idx.ptr.p_int[j]; y->ptr.p_double[ct] = y->ptr.p_double[ct]+v*s->vals.ptr.p_double[j]; } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseMV: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); } v = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); v = v+vv; } y->ptr.p_double[i] = v; } return; } } /************************************************************************* This function simultaneously calculates two matrix-vector products: S*x and S^T*x. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. Y1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y0 - array[N], S*x Y1 - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemv2(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y0, /* Real */ ae_vector* y1, ae_state *_state) { ae_int_t l; double tval; ae_int_t i; ae_int_t j; double vx; double vs; double v; double vv; double vd0; double vd1; ae_int_t vi; ae_int_t j0; ae_int_t j1; ae_int_t n; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_int_t lt; ae_int_t rt; ae_int_t lt1; ae_int_t rt1; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMV2: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(s->m==s->n, "SparseMV2: matrix is non-square", _state); l = x->cnt; ae_assert(l>=s->n, "SparseMV2: Length(X)n; rvectorsetlengthatleast(y0, l, _state); rvectorsetlengthatleast(y1, l, _state); for(i=0; i<=n-1; i++) { y0->ptr.p_double[i] = (double)(0); y1->ptr.p_double[i] = (double)(0); } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV2: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=s->m-1; i++) { tval = (double)(0); vx = x->ptr.p_double[i]; j0 = s->ridx.ptr.p_int[i]; j1 = s->ridx.ptr.p_int[i+1]-1; for(j=j0; j<=j1; j++) { vi = s->idx.ptr.p_int[j]; vs = s->vals.ptr.p_double[j]; tval = tval+x->ptr.p_double[vi]*vs; y1->ptr.p_double[vi] = y1->ptr.p_double[vi]+vx*vs; } y0->ptr.p_double[i] = tval; } return; } if( s->matrixtype==2 ) { /* * SKS format */ for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; vd0 = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; vd1 = vd0; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y1->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); vd0 = vd0+vv; } if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y0->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); vd1 = vd1+vv; } y0->ptr.p_double[i] = vd0; y1->ptr.p_double[i] = vd1; } return; } } /************************************************************************* This function calculates matrix-vector product S*x, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmv(sparsematrix* s, ae_bool isupper, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t id; ae_int_t lt; ae_int_t rt; double v; double vv; double vy; double vx; double vd; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_int_t lt1; ae_int_t rt1; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseSMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(x->cnt>=s->n, "SparseSMV: length(X)m==s->n, "SparseSMV: non-square matrix", _state); n = s->n; rvectorsetlengthatleast(y, n, _state); for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = (double)(0); } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=n-1; i++) { if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) { y->ptr.p_double[i] = y->ptr.p_double[i]+s->vals.ptr.p_double[s->didx.ptr.p_int[i]]*x->ptr.p_double[s->idx.ptr.p_int[s->didx.ptr.p_int[i]]]; } if( isupper ) { lt = s->uidx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; vy = (double)(0); vx = x->ptr.p_double[i]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v = s->vals.ptr.p_double[j]; vy = vy+x->ptr.p_double[id]*v; y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; } y->ptr.p_double[i] = y->ptr.p_double[i]+vy; } else { lt = s->ridx.ptr.p_int[i]; rt = s->didx.ptr.p_int[i]; vy = (double)(0); vx = x->ptr.p_double[i]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v = s->vals.ptr.p_double[j]; vy = vy+x->ptr.p_double[id]*v; y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; } y->ptr.p_double[i] = y->ptr.p_double[i]+vy; } } return; } if( s->matrixtype==2 ) { /* * SKS format */ for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; vd = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; if( d>0&&!isupper ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); vd = vd+vv; } if( u>0&&isupper ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); vd = vd+vv; } y->ptr.p_double[i] = vd; } return; } } /************************************************************************* This function calculates vector-matrix-vector product x'*S*x, where S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. RESULT x'*S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 27.01.2014 by Bochkanov Sergey *************************************************************************/ double sparsevsmv(sparsematrix* s, ae_bool isupper, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t id; ae_int_t lt; ae_int_t rt; double v; double v0; double v1; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_int_t lt1; double result; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseVSMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(x->cnt>=s->n, "SparseVSMV: length(X)m==s->n, "SparseVSMV: non-square matrix", _state); n = s->n; result = 0.0; if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseVSMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=n-1; i++) { if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) { v = x->ptr.p_double[s->idx.ptr.p_int[s->didx.ptr.p_int[i]]]; result = result+v*s->vals.ptr.p_double[s->didx.ptr.p_int[i]]*v; } if( isupper ) { lt = s->uidx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; } else { lt = s->ridx.ptr.p_int[i]; rt = s->didx.ptr.p_int[i]; } v0 = x->ptr.p_double[i]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v1 = x->ptr.p_double[id]; v = s->vals.ptr.p_double[j]; result = result+2*v0*v1*v; } } return result; } if( s->matrixtype==2 ) { /* * SKS format */ for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; v = x->ptr.p_double[i]; result = result+v*s->vals.ptr.p_double[ri+d]*v; if( d>0&&!isupper ) { lt = ri; rt = ri+d-1; lt1 = i-d; k = d-1; v0 = x->ptr.p_double[i]; v = 0.0; for(j=0; j<=k; j++) { v = v+x->ptr.p_double[lt1+j]*s->vals.ptr.p_double[lt+j]; } result = result+2*v0*v; } if( u>0&&isupper ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; k = u-1; v0 = x->ptr.p_double[i]; v = 0.0; for(j=0; j<=k; j++) { v = v+x->ptr.p_double[lt1+j]*s->vals.ptr.p_double[lt+j]; } result = result+2*v0*v; } } return result; } return result; } /************************************************************************* This function calculates matrix-matrix product S*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state) { double tval; double v; ae_int_t id; ae_int_t i; ae_int_t j; ae_int_t k0; ae_int_t k1; ae_int_t lt; ae_int_t rt; ae_int_t m; ae_int_t n; ae_int_t ri; ae_int_t ri1; ae_int_t lt1; ae_int_t rt1; ae_int_t d; ae_int_t u; double vd; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(a->rows>=s->n, "SparseMM: Rows(A)0, "SparseMM: K<=0", _state); m = s->m; n = s->n; k1 = k-1; rmatrixsetlengthatleast(b, m, k, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { b->ptr.pp_double[i][j] = (double)(0); } } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( kridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(k0=lt; k0<=rt-1; k0++) { tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[s->idx.ptr.p_int[k0]][j]; } b->ptr.pp_double[i][j] = tval; } } } else { for(i=0; i<=m-1; i++) { lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v = s->vals.ptr.p_double[j]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); } } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(m==n, "SparseMM: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); } } } if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } vd = s->vals.ptr.p_double[ri+d]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), vd); } return; } } /************************************************************************* This function calculates matrix-matrix product S^T*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[M][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemtm(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k0; ae_int_t k1; ae_int_t lt; ae_int_t rt; ae_int_t ct; double v; ae_int_t m; ae_int_t n; ae_int_t ri; ae_int_t ri1; ae_int_t lt1; ae_int_t rt1; ae_int_t d; ae_int_t u; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMTM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(a->rows>=s->m, "SparseMTM: Rows(A)0, "SparseMTM: K<=0", _state); m = s->m; n = s->n; k1 = k-1; rmatrixsetlengthatleast(b, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { b->ptr.pp_double[i][j] = (double)(0); } } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMTM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( kridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(k0=lt; k0<=rt-1; k0++) { v = s->vals.ptr.p_double[k0]; ct = s->idx.ptr.p_int[k0]; for(j=0; j<=k-1; j++) { b->ptr.pp_double[ct][j] = b->ptr.pp_double[ct][j]+v*a->ptr.pp_double[i][j]; } } } } else { for(i=0; i<=m-1; i++) { lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(j=lt; j<=rt-1; j++) { v = s->vals.ptr.p_double[j]; ct = s->idx.ptr.p_int[j]; ae_v_addd(&b->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(m==n, "SparseMTM: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); } } } v = s->vals.ptr.p_double[ri+d]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } return; } } /************************************************************************* This function simultaneously calculates two matrix-matrix products: S*A and S^T*A. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. B1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B0 - array[N][K], S*A B1 - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm2(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b0, /* Real */ ae_matrix* b1, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k0; ae_int_t lt; ae_int_t rt; ae_int_t ct; double v; double tval; ae_int_t n; ae_int_t k1; ae_int_t ri; ae_int_t ri1; ae_int_t lt1; ae_int_t rt1; ae_int_t d; ae_int_t u; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMM2: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(s->m==s->n, "SparseMM2: matrix is non-square", _state); ae_assert(a->rows>=s->n, "SparseMM2: Rows(A)0, "SparseMM2: K<=0", _state); n = s->n; k1 = k-1; rmatrixsetlengthatleast(b0, n, k, _state); rmatrixsetlengthatleast(b1, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { b1->ptr.pp_double[i][j] = (double)(0); b0->ptr.pp_double[i][j] = (double)(0); } } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMM2: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( kridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; v = a->ptr.pp_double[i][j]; for(k0=lt; k0<=rt-1; k0++) { ct = s->idx.ptr.p_int[k0]; b1->ptr.pp_double[ct][j] = b1->ptr.pp_double[ct][j]+s->vals.ptr.p_double[k0]*v; tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[ct][j]; } b0->ptr.pp_double[i][j] = tval; } } } else { for(i=0; i<=n-1; i++) { lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(j=lt; j<=rt-1; j++) { v = s->vals.ptr.p_double[j]; ct = s->idx.ptr.p_int[j]; ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[ct][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b1->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseMM2: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( d>0 ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[i][k0] = b0->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; b1->ptr.pp_double[j][k0] = b1->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b1->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } if( u>0 ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[j][k0] = b0->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; b1->ptr.pp_double[i][k0] = b1->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b0->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b1->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); } } } v = s->vals.ptr.p_double[ri+d]; ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b1->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } return; } } /************************************************************************* This function calculates matrix-matrix product S*A, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmm(sparsematrix* s, ae_bool isupper, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k0; ae_int_t id; ae_int_t k1; ae_int_t lt; ae_int_t rt; double v; double vb; double va; ae_int_t n; ae_int_t ri; ae_int_t ri1; ae_int_t lt1; ae_int_t rt1; ae_int_t d; ae_int_t u; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseSMM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(a->rows>=s->n, "SparseSMM: Rows(X)m==s->n, "SparseSMM: matrix is non-square", _state); n = s->n; k1 = k-1; rmatrixsetlengthatleast(b, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { b->ptr.pp_double[i][j] = (double)(0); } } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( k>sparse_linalgswitch ) { for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) { id = s->didx.ptr.p_int[i]; b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+s->vals.ptr.p_double[id]*a->ptr.pp_double[s->idx.ptr.p_int[id]][j]; } if( isupper ) { lt = s->uidx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; vb = (double)(0); va = a->ptr.pp_double[i][j]; for(k0=lt; k0<=rt-1; k0++) { id = s->idx.ptr.p_int[k0]; v = s->vals.ptr.p_double[k0]; vb = vb+a->ptr.pp_double[id][j]*v; b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; } b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; } else { lt = s->ridx.ptr.p_int[i]; rt = s->didx.ptr.p_int[i]; vb = (double)(0); va = a->ptr.pp_double[i][j]; for(k0=lt; k0<=rt-1; k0++) { id = s->idx.ptr.p_int[k0]; v = s->vals.ptr.p_double[k0]; vb = vb+a->ptr.pp_double[id][j]*v; b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; } b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; } } } } else { for(i=0; i<=n-1; i++) { if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) { id = s->didx.ptr.p_int[i]; v = s->vals.ptr.p_double[id]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[s->idx.ptr.p_int[id]][0], 1, ae_v_len(0,k-1), v); } if( isupper ) { lt = s->uidx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v = s->vals.ptr.p_double[j]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } else { lt = s->ridx.ptr.p_int[i]; rt = s->didx.ptr.p_int[i]; for(j=lt; j<=rt-1; j++) { id = s->idx.ptr.p_int[j]; v = s->vals.ptr.p_double[j]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseMM2: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( d>0&&!isupper ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; b->ptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } } } if( u>0&&isupper ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; for(j=lt1; j<=rt1; j++) { v = s->vals.ptr.p_double[lt+(j-lt1)]; if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; b->ptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; } } else { /* * Use vector operation */ ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); } } } v = s->vals.ptr.p_double[ri+d]; ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } return; } } /************************************************************************* This function calculates matrix-vector product op(S)*x, when x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - possibly preallocated input buffer. Automatically resized if its size is too small. OUTPUT PARAMETERS Y - array[N], op(S)*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrmv(sparsematrix* s, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t j0; ae_int_t j1; double v; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_int_t lt; ae_int_t rt; ae_int_t lt1; ae_int_t rt1; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseTRMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(optype==0||optype==1, "SparseTRMV: incorrect operation type (must be 0 or 1)", _state); ae_assert(x->cnt>=s->n, "SparseTRMV: Length(X)m==s->n, "SparseTRMV: matrix is non-square", _state); n = s->n; rvectorsetlengthatleast(y, n, _state); if( isunit ) { /* * Set initial value of y to x */ for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = x->ptr.p_double[i]; } } else { /* * Set initial value of y to 0 */ for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = (double)(0); } } if( s->matrixtype==1 ) { /* * CRS format */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseTRMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); for(i=0; i<=n-1; i++) { /* * Depending on IsUpper/IsUnit, select range of indexes to process */ if( isupper ) { if( isunit||s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) { j0 = s->uidx.ptr.p_int[i]; } else { j0 = s->didx.ptr.p_int[i]; } j1 = s->ridx.ptr.p_int[i+1]-1; } else { j0 = s->ridx.ptr.p_int[i]; if( isunit||s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) { j1 = s->didx.ptr.p_int[i]-1; } else { j1 = s->didx.ptr.p_int[i]; } } /* * Depending on OpType, process subset of I-th row of input matrix */ if( optype==0 ) { v = 0.0; for(j=j0; j<=j1; j++) { v = v+s->vals.ptr.p_double[j]*x->ptr.p_double[s->idx.ptr.p_int[j]]; } y->ptr.p_double[i] = y->ptr.p_double[i]+v; } else { v = x->ptr.p_double[i]; for(j=j0; j<=j1; j++) { k = s->idx.ptr.p_int[j]; y->ptr.p_double[k] = y->ptr.p_double[k]+v*s->vals.ptr.p_double[j]; } } } return; } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseTRMV: non-square SKS matrices are not supported", _state); for(i=0; i<=n-1; i++) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( !isunit ) { y->ptr.p_double[i] = y->ptr.p_double[i]+s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; } if( d>0&&!isupper ) { lt = ri; rt = ri+d-1; lt1 = i-d; rt1 = i-1; if( optype==0 ) { v = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); y->ptr.p_double[i] = y->ptr.p_double[i]+v; } else { v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); } } if( u>0&&isupper ) { lt = ri1-u; rt = ri1-1; lt1 = i-u; rt1 = i-1; if( optype==0 ) { v = x->ptr.p_double[i]; ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); } else { v = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); y->ptr.p_double[i] = y->ptr.p_double[i]+v; } } } return; } } /************************************************************************* This function solves linear system op(S)*y=x where x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used. It is your responsibility to make sure that diagonal is non-zero. OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. OUTPUT PARAMETERS X - array[N], inv(op(S))*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. NOTE: no assertion or tests are done during algorithm operation. It is your responsibility to provide invertible matrix to algorithm. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrsv(sparsematrix* s, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t fst; ae_int_t lst; ae_int_t stp; ae_int_t i; ae_int_t j; ae_int_t k; double v; double vd; ae_int_t j0; ae_int_t j1; ae_int_t ri; ae_int_t ri1; ae_int_t d; ae_int_t u; ae_int_t lt; ae_int_t lt1; ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseTRSV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); ae_assert(optype==0||optype==1, "SparseTRSV: incorrect operation type (must be 0 or 1)", _state); ae_assert(x->cnt>=s->n, "SparseTRSV: Length(X)m==s->n, "SparseTRSV: matrix is non-square", _state); n = s->n; if( s->matrixtype==1 ) { /* * CRS format. * * Several branches for different combinations of IsUpper and OpType */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseTRSV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( optype==0 ) { /* * No transposition. * * S*x=y with upper or lower triangular S. */ if( isupper ) { fst = n-1; lst = 0; stp = -1; } else { fst = 0; lst = n-1; stp = 1; } i = fst; while((stp>0&&i<=lst)||(stp<0&&i>=lst)) { /* * Select range of indexes to process */ if( isupper ) { j0 = s->uidx.ptr.p_int[i]; j1 = s->ridx.ptr.p_int[i+1]-1; } else { j0 = s->ridx.ptr.p_int[i]; j1 = s->didx.ptr.p_int[i]-1; } /* * Calculate X[I] */ v = 0.0; for(j=j0; j<=j1; j++) { v = v+s->vals.ptr.p_double[j]*x->ptr.p_double[s->idx.ptr.p_int[j]]; } if( !isunit ) { if( s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) { vd = (double)(0); } else { vd = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; } } else { vd = 1.0; } k = saferdiv(x->ptr.p_double[i]-v, vd, &v, _state); ae_assert(k<=0, "SparseTRSV: near-overflow or division by exact zero", _state); x->ptr.p_double[i] = v; /* * Next I */ i = i+stp; } return; } if( optype==1 ) { /* * Transposition. * * (S^T)*x=y with upper or lower triangular S. */ if( isupper ) { fst = 0; lst = n-1; stp = 1; } else { fst = n-1; lst = 0; stp = -1; } i = fst; while((stp>0&&i<=lst)||(stp<0&&i>=lst)) { /* * X[i] already stores A[i,i]*Y[i], the only thing left * is to divide by diagonal element. */ if( !isunit ) { if( s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) { vd = (double)(0); } else { vd = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; } } else { vd = 1.0; } k = saferdiv(x->ptr.p_double[i], vd, &v, _state); ae_assert(k<=0, "SparseTRSV: near-overflow or division by exact zero", _state); x->ptr.p_double[i] = v; /* * For upper triangular case: * subtract X[i]*Ai from X[i+1:N-1] * * For lower triangular case: * subtract X[i]*Ai from X[0:i-1] * * (here Ai is I-th row of original, untransposed A). */ if( isupper ) { j0 = s->uidx.ptr.p_int[i]; j1 = s->ridx.ptr.p_int[i+1]-1; } else { j0 = s->ridx.ptr.p_int[i]; j1 = s->didx.ptr.p_int[i]-1; } v = x->ptr.p_double[i]; for(j=j0; j<=j1; j++) { k = s->idx.ptr.p_int[j]; x->ptr.p_double[k] = x->ptr.p_double[k]-s->vals.ptr.p_double[j]*v; } /* * Next I */ i = i+stp; } return; } ae_assert(ae_false, "SparseTRSV: internal error", _state); } if( s->matrixtype==2 ) { /* * SKS format */ ae_assert(s->m==s->n, "SparseTRSV: non-square SKS matrices are not supported", _state); if( (optype==0&&!isupper)||(optype==1&&isupper) ) { /* * Lower triangular op(S) (matrix itself can be upper triangular). */ for(i=0; i<=n-1; i++) { /* * Select range of indexes to process */ ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; if( isupper ) { lt = i-u; lt1 = ri1-u; k = u-1; } else { lt = i-d; lt1 = ri; k = d-1; } /* * Calculate X[I] */ v = 0.0; for(j=0; j<=k; j++) { v = v+s->vals.ptr.p_double[lt1+j]*x->ptr.p_double[lt+j]; } if( isunit ) { vd = (double)(1); } else { vd = s->vals.ptr.p_double[ri+d]; } k = saferdiv(x->ptr.p_double[i]-v, vd, &v, _state); ae_assert(k<=0, "SparseTRSV: near-overflow or division by exact zero", _state); x->ptr.p_double[i] = v; } return; } if( (optype==1&&!isupper)||(optype==0&&isupper) ) { /* * Upper triangular op(S) (matrix itself can be lower triangular). */ for(i=n-1; i>=0; i--) { ri = s->ridx.ptr.p_int[i]; ri1 = s->ridx.ptr.p_int[i+1]; d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; /* * X[i] already stores A[i,i]*Y[i], the only thing left * is to divide by diagonal element. */ if( isunit ) { vd = (double)(1); } else { vd = s->vals.ptr.p_double[ri+d]; } k = saferdiv(x->ptr.p_double[i], vd, &v, _state); ae_assert(k<=0, "SparseTRSV: near-overflow or division by exact zero", _state); x->ptr.p_double[i] = v; /* * Subtract product of X[i] and I-th column of "effective" A from * unprocessed variables. */ v = x->ptr.p_double[i]; if( isupper ) { lt = i-u; lt1 = ri1-u; k = u-1; } else { lt = i-d; lt1 = ri; k = d-1; } for(j=0; j<=k; j++) { x->ptr.p_double[lt+j] = x->ptr.p_double[lt+j]-v*s->vals.ptr.p_double[lt1+j]; } } return; } ae_assert(ae_false, "SparseTRSV: internal error", _state); } ae_assert(ae_false, "SparseTRSV: internal error", _state); } /************************************************************************* This procedure resizes Hash-Table matrix. It can be called when you have deleted too many elements from the matrix, and you want to free unneeded memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparseresizematrix(sparsematrix* s, ae_state *_state) { ae_frame _frame_block; ae_int_t k; ae_int_t k1; ae_int_t i; ae_vector tvals; ae_vector tidx; ae_frame_make(_state, &_frame_block); ae_vector_init(&tvals, 0, DT_REAL, _state); ae_vector_init(&tidx, 0, DT_INT, _state); ae_assert(s->matrixtype==0, "SparseResizeMatrix: incorrect matrix type", _state); /* * Initialization for length and number of non-null elementd */ k = s->tablesize; k1 = 0; /* * Calculating number of non-null elements */ for(i=0; i<=k-1; i++) { if( s->idx.ptr.p_int[2*i]>=0 ) { k1 = k1+1; } } /* * Initialization value for free space */ s->tablesize = ae_round(k1/sparse_desiredloadfactor*sparse_growfactor+sparse_additional, _state); s->nfree = s->tablesize-k1; ae_vector_set_length(&tvals, s->tablesize, _state); ae_vector_set_length(&tidx, 2*s->tablesize, _state); ae_swap_vectors(&s->vals, &tvals); ae_swap_vectors(&s->idx, &tidx); for(i=0; i<=s->tablesize-1; i++) { s->idx.ptr.p_int[2*i] = -1; } for(i=0; i<=k-1; i++) { if( tidx.ptr.p_int[2*i]>=0 ) { sparseset(s, tidx.ptr.p_int[2*i], tidx.ptr.p_int[2*i+1], tvals.ptr.p_double[i], _state); } } ae_frame_leave(_state); } /************************************************************************* This function return average length of chain at hash-table. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ double sparsegetaveragelengthofchain(sparsematrix* s, ae_state *_state) { ae_int_t nchains; ae_int_t talc; ae_int_t l; ae_int_t i; ae_int_t ind0; ae_int_t ind1; ae_int_t hashcode; double result; /* * If matrix represent in CRS then return zero and exit */ if( s->matrixtype!=0 ) { result = (double)(0); return result; } nchains = 0; talc = 0; l = s->tablesize; for(i=0; i<=l-1; i++) { ind0 = 2*i; if( s->idx.ptr.p_int[ind0]!=-1 ) { nchains = nchains+1; hashcode = sparse_hash(s->idx.ptr.p_int[ind0], s->idx.ptr.p_int[ind0+1], l, _state); for(;;) { talc = talc+1; ind1 = 2*hashcode; if( s->idx.ptr.p_int[ind0]==s->idx.ptr.p_int[ind1]&&s->idx.ptr.p_int[ind0+1]==s->idx.ptr.p_int[ind1+1] ) { break; } hashcode = (hashcode+1)%l; } } } if( nchains==0 ) { result = (double)(0); } else { result = (double)talc/(double)nchains; } return result; } /************************************************************************* This function is used to enumerate all elements of the sparse matrix. Before first call user initializes T0 and T1 counters by zero. These counters are used to remember current position in a matrix; after each call they are updated by the function. Subsequent calls to this function return non-zero elements of the sparse matrix, one by one. If you enumerate CRS matrix, matrix is traversed from left to right, from top to bottom. In case you enumerate matrix stored as Hash table, elements are returned in random order. EXAMPLE > T0=0 > T1=0 > while SparseEnumerate(S,T0,T1,I,J,V) do > ....do something with I,J,V INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. T0 - internal counter T1 - internal counter OUTPUT PARAMETERS T0 - new value of the internal counter T1 - new value of the internal counter I - row index of non-zero element, 0<=Imatrixtype!=0&&*t1<0) ) { /* * Incorrect T0/T1, terminate enumeration */ result = ae_false; return result; } if( s->matrixtype==0 ) { /* * Hash-table matrix */ sz = s->tablesize; for(i0=*t0; i0<=sz-1; i0++) { if( s->idx.ptr.p_int[2*i0]==-1||s->idx.ptr.p_int[2*i0]==-2 ) { continue; } else { *i = s->idx.ptr.p_int[2*i0]; *j = s->idx.ptr.p_int[2*i0+1]; *v = s->vals.ptr.p_double[i0]; *t0 = i0+1; result = ae_true; return result; } } *t0 = 0; *t1 = 0; result = ae_false; return result; } if( s->matrixtype==1 ) { /* * CRS matrix */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseEnumerate: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); if( *t0>=s->ninitialized ) { *t0 = 0; *t1 = 0; result = ae_false; return result; } while(*t0>s->ridx.ptr.p_int[*t1+1]-1&&*t1m) { *t1 = *t1+1; } *i = *t1; *j = s->idx.ptr.p_int[*t0]; *v = s->vals.ptr.p_double[*t0]; *t0 = *t0+1; result = ae_true; return result; } if( s->matrixtype==2 ) { /* * SKS matrix: * * T0 stores current offset in Vals[] array * * T1 stores index of the diagonal block */ ae_assert(s->m==s->n, "SparseEnumerate: non-square SKS matrices are not supported", _state); if( *t0>=s->ridx.ptr.p_int[s->m] ) { *t0 = 0; *t1 = 0; result = ae_false; return result; } while(*t0>s->ridx.ptr.p_int[*t1+1]-1&&*t1m) { *t1 = *t1+1; } i0 = *t0-s->ridx.ptr.p_int[*t1]; if( i0didx.ptr.p_int[*t1]+1 ) { /* * subdiagonal or diagonal element, row index is T1. */ *i = *t1; *j = *t1-s->didx.ptr.p_int[*t1]+i0; } else { /* * superdiagonal element, column index is T1. */ *i = *t1-(s->ridx.ptr.p_int[*t1+1]-(*t0)); *j = *t1; } *v = s->vals.ptr.p_double[*t0]; *t0 = *t0+1; result = ae_true; return result; } ae_assert(ae_false, "SparseEnumerate: unexpected matrix type", _state); return result; } /************************************************************************* This function rewrites existing (non-zero) element. It returns True if element exists or False, when it is called for non-existing (zero) element. This function works with any kind of the matrix. The purpose of this function is to provide convenient thread-safe way to modify sparse matrix. Such modification (already existing element is rewritten) is guaranteed to be thread-safe without any synchronization, as long as different threads modify different elements. INPUT PARAMETERS S - sparse M*N matrix in any kind of representation (Hash, SKS, CRS). I - row index of non-zero element to modify, 0<=Im, "SparseRewriteExisting: invalid argument I(either I<0 or I>=S.M)", _state); ae_assert(0<=j&&jn, "SparseRewriteExisting: invalid argument J(either J<0 or J>=S.N)", _state); ae_assert(ae_isfinite(v, _state), "SparseRewriteExisting: invalid argument V(either V is infinite or V is NaN)", _state); result = ae_false; /* * Hash-table matrix */ if( s->matrixtype==0 ) { k = s->tablesize; hashcode = sparse_hash(i, j, k, _state); for(;;) { if( s->idx.ptr.p_int[2*hashcode]==-1 ) { return result; } if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) { s->vals.ptr.p_double[hashcode] = v; result = ae_true; return result; } hashcode = (hashcode+1)%k; } } /* * CRS matrix */ if( s->matrixtype==1 ) { ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseRewriteExisting: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); k0 = s->ridx.ptr.p_int[i]; k1 = s->ridx.ptr.p_int[i+1]-1; while(k0<=k1) { k = (k0+k1)/2; if( s->idx.ptr.p_int[k]==j ) { s->vals.ptr.p_double[k] = v; result = ae_true; return result; } if( s->idx.ptr.p_int[k]matrixtype==2 ) { ae_assert(s->m==s->n, "SparseRewriteExisting: non-square SKS matrix not supported", _state); if( i==j ) { /* * Rewrite diagonal element */ result = ae_true; s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]] = v; return result; } if( jdidx.ptr.p_int[i]; if( i-j<=k ) { s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+k+j-i] = v; result = ae_true; } } else { /* * Return superdiagonal element at J-th "skyline block" */ k = s->uidx.ptr.p_int[j]; if( j-i<=k ) { s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)] = v; result = ae_true; } } return result; } return result; } /************************************************************************* This function returns I-th row of the sparse matrix. Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=Imatrixtype==1||s->matrixtype==2, "SparseGetRow: S must be CRS/SKS-based matrix", _state); ae_assert(i>=0&&im, "SparseGetRow: I<0 or I>=M", _state); /* * Prepare output buffer */ rvectorsetlengthatleast(irow, s->n, _state); for(i0=0; i0<=s->n-1; i0++) { irow->ptr.p_double[i0] = (double)(0); } /* * Output */ if( s->matrixtype==1 ) { for(i0=s->ridx.ptr.p_int[i]; i0<=s->ridx.ptr.p_int[i+1]-1; i0++) { irow->ptr.p_double[s->idx.ptr.p_int[i0]] = s->vals.ptr.p_double[i0]; } return; } if( s->matrixtype==2 ) { /* * Copy subdiagonal and diagonal parts */ ae_assert(s->n==s->m, "SparseGetRow: non-square SKS matrices are not supported", _state); j0 = i-s->didx.ptr.p_int[i]; i0 = -j0+s->ridx.ptr.p_int[i]; for(j=j0; j<=i; j++) { irow->ptr.p_double[j] = s->vals.ptr.p_double[j+i0]; } /* * Copy superdiagonal part */ upperprofile = s->uidx.ptr.p_int[s->n]; j0 = i+1; j1 = ae_minint(s->n-1, i+upperprofile, _state); for(j=j0; j<=j1; j++) { if( j-i<=s->uidx.ptr.p_int[j] ) { irow->ptr.p_double[j] = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; } } return; } } /************************************************************************* This function returns I-th row of the sparse matrix IN COMPRESSED FORMAT - only non-zero elements are returned (with their indexes). Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=Imatrixtype==1||s->matrixtype==2, "SparseGetRow: S must be CRS/SKS-based matrix", _state); ae_assert(i>=0&&im, "SparseGetRow: I<0 or I>=M", _state); /* * Initialize NZCnt */ *nzcnt = 0; /* * CRS matrix - just copy data */ if( s->matrixtype==1 ) { *nzcnt = s->ridx.ptr.p_int[i+1]-s->ridx.ptr.p_int[i]; ivectorsetlengthatleast(colidx, *nzcnt, _state); rvectorsetlengthatleast(vals, *nzcnt, _state); k0 = s->ridx.ptr.p_int[i]; for(k=0; k<=*nzcnt-1; k++) { colidx->ptr.p_int[k] = s->idx.ptr.p_int[k0+k]; vals->ptr.p_double[k] = s->vals.ptr.p_double[k0+k]; } return; } /* * SKS matrix - a bit more complex sequence */ if( s->matrixtype==2 ) { ae_assert(s->n==s->m, "SparseGetCompressedRow: non-square SKS matrices are not supported", _state); /* * Allocate enough place for storage */ upperprofile = s->uidx.ptr.p_int[s->n]; ivectorsetlengthatleast(colidx, s->didx.ptr.p_int[i]+1+upperprofile, _state); rvectorsetlengthatleast(vals, s->didx.ptr.p_int[i]+1+upperprofile, _state); /* * Copy subdiagonal and diagonal parts */ j0 = i-s->didx.ptr.p_int[i]; i0 = -j0+s->ridx.ptr.p_int[i]; for(j=j0; j<=i; j++) { colidx->ptr.p_int[*nzcnt] = j; vals->ptr.p_double[*nzcnt] = s->vals.ptr.p_double[j+i0]; *nzcnt = *nzcnt+1; } /* * Copy superdiagonal part */ j0 = i+1; j1 = ae_minint(s->n-1, i+upperprofile, _state); for(j=j0; j<=j1; j++) { if( j-i<=s->uidx.ptr.p_int[j] ) { colidx->ptr.p_int[*nzcnt] = j; vals->ptr.p_double[*nzcnt] = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; *nzcnt = *nzcnt+1; } } return; } } /************************************************************************* This function performs efficient in-place transpose of SKS matrix. No additional memory is allocated during transposition. This function supports only skyline storage format (SKS). INPUT PARAMETERS S - sparse matrix in SKS format. OUTPUT PARAMETERS S - sparse matrix, transposed. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetransposesks(sparsematrix* s, ae_state *_state) { ae_int_t n; ae_int_t d; ae_int_t u; ae_int_t i; ae_int_t k; ae_int_t t0; ae_int_t t1; double v; ae_assert(s->matrixtype==2, "SparseTransposeSKS: only SKS matrices are supported", _state); ae_assert(s->m==s->n, "SparseTransposeSKS: non-square SKS matrices are not supported", _state); n = s->n; for(i=1; i<=n-1; i++) { d = s->didx.ptr.p_int[i]; u = s->uidx.ptr.p_int[i]; k = s->uidx.ptr.p_int[i]; s->uidx.ptr.p_int[i] = s->didx.ptr.p_int[i]; s->didx.ptr.p_int[i] = k; if( d==u ) { /* * Upper skyline height equal to lower skyline height, * simple exchange is needed for transposition */ t0 = s->ridx.ptr.p_int[i]; for(k=0; k<=d-1; k++) { v = s->vals.ptr.p_double[t0+k]; s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t0+d+1+k]; s->vals.ptr.p_double[t0+d+1+k] = v; } } if( d>u ) { /* * Upper skyline height is less than lower skyline height. * * Transposition becomes a bit tricky: we have to rearrange * "L0 L1 D U" to "U D L0 L1", where |L0|=|U|=u, |L1|=d-u. * * In order to do this we perform a sequence of swaps and * in-place reversals: * * swap(L0,U) => "U L1 D L0" * * reverse("L1 D L0") => "U L0~ D L1~" (where X~ is a reverse of X) * * reverse("L0~ D") => "U D L0 L1~" * * reverse("L1") => "U D L0 L1" */ t0 = s->ridx.ptr.p_int[i]; t1 = s->ridx.ptr.p_int[i]+d+1; for(k=0; k<=u-1; k++) { v = s->vals.ptr.p_double[t0+k]; s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t1+k]; s->vals.ptr.p_double[t1+k] = v; } t0 = s->ridx.ptr.p_int[i]+u; t1 = s->ridx.ptr.p_int[i+1]-1; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } t0 = s->ridx.ptr.p_int[i]+u; t1 = s->ridx.ptr.p_int[i]+u+u; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } t0 = s->ridx.ptr.p_int[i+1]-(d-u); t1 = s->ridx.ptr.p_int[i+1]-1; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } } if( d "U1 D U0 L" * * reverse("U1 D U0") => "U0~ D U1~ L" (where X~ is a reverse of X) * * reverse("U0~") => "U0 D U1~ L" * * reverse("D U1~") => "U0 U1 D L" */ t0 = s->ridx.ptr.p_int[i]; t1 = s->ridx.ptr.p_int[i+1]-d; for(k=0; k<=d-1; k++) { v = s->vals.ptr.p_double[t0+k]; s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t1+k]; s->vals.ptr.p_double[t1+k] = v; } t0 = s->ridx.ptr.p_int[i]; t1 = s->ridx.ptr.p_int[i]+u; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } t0 = s->ridx.ptr.p_int[i]; t1 = s->ridx.ptr.p_int[i]+u-d-1; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } t0 = s->ridx.ptr.p_int[i]+u-d; t1 = s->ridx.ptr.p_int[i+1]-d-1; while(t1>t0) { v = s->vals.ptr.p_double[t0]; s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; s->vals.ptr.p_double[t1] = v; t0 = t0+1; t1 = t1-1; } } } k = s->uidx.ptr.p_int[n]; s->uidx.ptr.p_int[n] = s->didx.ptr.p_int[n]; s->didx.ptr.p_int[n] = k; } /************************************************************************* This function performs in-place conversion to desired sparse storage format. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S0 - sparse matrix in requested format. NOTE: in-place conversion wastes a lot of memory which is used to store temporaries. If you perform a lot of repeated conversions, we recommend to use out-of-place buffered conversion functions, like SparseCopyToBuf(), which can reuse already allocated memory. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseconvertto(sparsematrix* s0, ae_int_t fmt, ae_state *_state) { ae_assert((fmt==0||fmt==1)||fmt==2, "SparseConvertTo: invalid fmt parameter", _state); if( fmt==0 ) { sparseconverttohash(s0, _state); return; } if( fmt==1 ) { sparseconverttocrs(s0, _state); return; } if( fmt==2 ) { sparseconverttosks(s0, _state); return; } ae_assert(ae_false, "SparseConvertTo: invalid matrix type", _state); } /************************************************************************* This function performs out-of-place conversion to desired sparse storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S1 - sparse matrix in requested format. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecopytobuf(sparsematrix* s0, ae_int_t fmt, sparsematrix* s1, ae_state *_state) { ae_assert((fmt==0||fmt==1)||fmt==2, "SparseCopyToBuf: invalid fmt parameter", _state); if( fmt==0 ) { sparsecopytohashbuf(s0, s1, _state); return; } if( fmt==1 ) { sparsecopytocrsbuf(s0, s1, _state); return; } if( fmt==2 ) { sparsecopytosksbuf(s0, s1, _state); return; } ae_assert(ae_false, "SparseCopyToBuf: invalid matrix type", _state); } /************************************************************************* This function performs in-place conversion to Hash table storage. INPUT PARAMETERS S - sparse matrix in CRS format. OUTPUT PARAMETERS S - sparse matrix in Hash table format. NOTE: this function has no effect when called with matrix which is already in Hash table mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToHashBuf() function in this case. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparseconverttohash(sparsematrix* s, ae_state *_state) { ae_frame _frame_block; ae_vector tidx; ae_vector tridx; ae_vector tdidx; ae_vector tuidx; ae_vector tvals; ae_int_t n; ae_int_t m; ae_int_t offs0; ae_int_t i; ae_int_t j; ae_int_t k; ae_frame_make(_state, &_frame_block); ae_vector_init(&tidx, 0, DT_INT, _state); ae_vector_init(&tridx, 0, DT_INT, _state); ae_vector_init(&tdidx, 0, DT_INT, _state); ae_vector_init(&tuidx, 0, DT_INT, _state); ae_vector_init(&tvals, 0, DT_REAL, _state); ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseConvertToHash: invalid matrix type", _state); if( s->matrixtype==0 ) { /* * Already in Hash mode */ ae_frame_leave(_state); return; } if( s->matrixtype==1 ) { /* * From CRS to Hash */ s->matrixtype = 0; m = s->m; n = s->n; ae_swap_vectors(&s->idx, &tidx); ae_swap_vectors(&s->ridx, &tridx); ae_swap_vectors(&s->vals, &tvals); sparsecreatebuf(m, n, tridx.ptr.p_int[m], s, _state); for(i=0; i<=m-1; i++) { for(j=tridx.ptr.p_int[i]; j<=tridx.ptr.p_int[i+1]-1; j++) { sparseset(s, i, tidx.ptr.p_int[j], tvals.ptr.p_double[j], _state); } } ae_frame_leave(_state); return; } if( s->matrixtype==2 ) { /* * From SKS to Hash */ s->matrixtype = 0; m = s->m; n = s->n; ae_swap_vectors(&s->ridx, &tridx); ae_swap_vectors(&s->didx, &tdidx); ae_swap_vectors(&s->uidx, &tuidx); ae_swap_vectors(&s->vals, &tvals); sparsecreatebuf(m, n, tridx.ptr.p_int[m], s, _state); for(i=0; i<=m-1; i++) { /* * copy subdiagonal and diagonal parts of I-th block */ offs0 = tridx.ptr.p_int[i]; k = tdidx.ptr.p_int[i]+1; for(j=0; j<=k-1; j++) { sparseset(s, i, i-tdidx.ptr.p_int[i]+j, tvals.ptr.p_double[offs0+j], _state); } /* * Copy superdiagonal part of I-th block */ offs0 = tridx.ptr.p_int[i]+tdidx.ptr.p_int[i]+1; k = tuidx.ptr.p_int[i]; for(j=0; j<=k-1; j++) { sparseset(s, i-k+j, i, tvals.ptr.p_double[offs0+j], _state); } } ae_frame_leave(_state); return; } ae_assert(ae_false, "SparseConvertToHash: invalid matrix type", _state); ae_frame_leave(_state); } /************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToHashBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytohash(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { _sparsematrix_clear(s1); ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToHash: invalid matrix type", _state); sparsecopytohashbuf(s0, s1, _state); } /************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytohashbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { double val; ae_int_t t0; ae_int_t t1; ae_int_t i; ae_int_t j; ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToHashBuf: invalid matrix type", _state); if( s0->matrixtype==0 ) { /* * Already hash, just copy */ sparsecopybuf(s0, s1, _state); return; } if( s0->matrixtype==1 ) { /* * CRS storage */ t0 = 0; t1 = 0; sparsecreatebuf(s0->m, s0->n, s0->ridx.ptr.p_int[s0->m], s1, _state); while(sparseenumerate(s0, &t0, &t1, &i, &j, &val, _state)) { sparseset(s1, i, j, val, _state); } return; } if( s0->matrixtype==2 ) { /* * SKS storage */ t0 = 0; t1 = 0; sparsecreatebuf(s0->m, s0->n, s0->ridx.ptr.p_int[s0->m], s1, _state); while(sparseenumerate(s0, &t0, &t1, &i, &j, &val, _state)) { sparseset(s1, i, j, val, _state); } return; } ae_assert(ae_false, "SparseCopyToHashBuf: invalid matrix type", _state); } /************************************************************************* This function converts matrix to CRS format. Some algorithms (linear algebra ones, for example) require matrices in CRS format. This function allows to perform in-place conversion. INPUT PARAMETERS S - sparse M*N matrix in any format OUTPUT PARAMETERS S - matrix in CRS format NOTE: this function has no effect when called with matrix which is already in CRS mode. NOTE: this function allocates temporary memory to store a copy of the matrix. If you perform a lot of repeated conversions, we recommend you to use SparseCopyToCRSBuf() function, which can reuse previously allocated memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparseconverttocrs(sparsematrix* s, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t i; ae_int_t j; ae_vector tvals; ae_vector tidx; ae_vector temp; ae_vector tridx; ae_int_t nonne; ae_int_t k; ae_int_t offs0; ae_int_t offs1; ae_frame_make(_state, &_frame_block); ae_vector_init(&tvals, 0, DT_REAL, _state); ae_vector_init(&tidx, 0, DT_INT, _state); ae_vector_init(&temp, 0, DT_INT, _state); ae_vector_init(&tridx, 0, DT_INT, _state); m = s->m; if( s->matrixtype==0 ) { /* * From Hash-table to CRS. * First, create local copy of the hash table. */ s->matrixtype = 1; k = s->tablesize; ae_swap_vectors(&s->vals, &tvals); ae_swap_vectors(&s->idx, &tidx); /* * Fill RIdx by number of elements per row: * RIdx[I+1] stores number of elements in I-th row. * * Convert RIdx from row sizes to row offsets. * Set NInitialized */ nonne = 0; ivectorsetlengthatleast(&s->ridx, s->m+1, _state); for(i=0; i<=s->m; i++) { s->ridx.ptr.p_int[i] = 0; } for(i=0; i<=k-1; i++) { if( tidx.ptr.p_int[2*i]>=0 ) { s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1] = s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1]+1; nonne = nonne+1; } } for(i=0; i<=s->m-1; i++) { s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; } s->ninitialized = s->ridx.ptr.p_int[s->m]; /* * Allocate memory and move elements to Vals/Idx. * Initially, elements are sorted by rows, but unsorted within row. * After initial insertion we sort elements within row. */ ae_vector_set_length(&temp, s->m, _state); for(i=0; i<=s->m-1; i++) { temp.ptr.p_int[i] = 0; } rvectorsetlengthatleast(&s->vals, nonne, _state); ivectorsetlengthatleast(&s->idx, nonne, _state); for(i=0; i<=k-1; i++) { if( tidx.ptr.p_int[2*i]>=0 ) { s->vals.ptr.p_double[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tvals.ptr.p_double[i]; s->idx.ptr.p_int[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tidx.ptr.p_int[2*i+1]; temp.ptr.p_int[tidx.ptr.p_int[2*i]] = temp.ptr.p_int[tidx.ptr.p_int[2*i]]+1; } } for(i=0; i<=s->m-1; i++) { tagsortmiddleir(&s->idx, &s->vals, s->ridx.ptr.p_int[i], s->ridx.ptr.p_int[i+1]-s->ridx.ptr.p_int[i], _state); } /* * Initialization 'S.UIdx' and 'S.DIdx' */ sparse_sparseinitduidx(s, _state); ae_frame_leave(_state); return; } if( s->matrixtype==1 ) { /* * Already CRS */ ae_frame_leave(_state); return; } if( s->matrixtype==2 ) { ae_assert(s->m==s->n, "SparseConvertToCRS: non-square SKS matrices are not supported", _state); /* * From SKS to CRS. * * First, create local copy of the SKS matrix (Vals, * Idx, RIdx are stored; DIdx/UIdx for some time are * left in the SparseMatrix structure). */ s->matrixtype = 1; ae_swap_vectors(&s->vals, &tvals); ae_swap_vectors(&s->idx, &tidx); ae_swap_vectors(&s->ridx, &tridx); /* * Fill RIdx by number of elements per row: * RIdx[I+1] stores number of elements in I-th row. * * Convert RIdx from row sizes to row offsets. * Set NInitialized */ ivectorsetlengthatleast(&s->ridx, m+1, _state); s->ridx.ptr.p_int[0] = 0; for(i=1; i<=m; i++) { s->ridx.ptr.p_int[i] = 1; } nonne = 0; for(i=0; i<=m-1; i++) { s->ridx.ptr.p_int[i+1] = s->didx.ptr.p_int[i]+s->ridx.ptr.p_int[i+1]; for(j=i-s->uidx.ptr.p_int[i]; j<=i-1; j++) { s->ridx.ptr.p_int[j+1] = s->ridx.ptr.p_int[j+1]+1; } nonne = nonne+s->didx.ptr.p_int[i]+1+s->uidx.ptr.p_int[i]; } for(i=0; i<=s->m-1; i++) { s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; } s->ninitialized = s->ridx.ptr.p_int[s->m]; /* * Allocate memory and move elements to Vals/Idx. * Initially, elements are sorted by rows, and are sorted within row too. * No additional post-sorting is required. */ ae_vector_set_length(&temp, m, _state); for(i=0; i<=m-1; i++) { temp.ptr.p_int[i] = 0; } rvectorsetlengthatleast(&s->vals, nonne, _state); ivectorsetlengthatleast(&s->idx, nonne, _state); for(i=0; i<=m-1; i++) { /* * copy subdiagonal and diagonal parts of I-th block */ offs0 = tridx.ptr.p_int[i]; offs1 = s->ridx.ptr.p_int[i]+temp.ptr.p_int[i]; k = s->didx.ptr.p_int[i]+1; for(j=0; j<=k-1; j++) { s->vals.ptr.p_double[offs1+j] = tvals.ptr.p_double[offs0+j]; s->idx.ptr.p_int[offs1+j] = i-s->didx.ptr.p_int[i]+j; } temp.ptr.p_int[i] = temp.ptr.p_int[i]+s->didx.ptr.p_int[i]+1; /* * Copy superdiagonal part of I-th block */ offs0 = tridx.ptr.p_int[i]+s->didx.ptr.p_int[i]+1; k = s->uidx.ptr.p_int[i]; for(j=0; j<=k-1; j++) { offs1 = s->ridx.ptr.p_int[i-k+j]+temp.ptr.p_int[i-k+j]; s->vals.ptr.p_double[offs1] = tvals.ptr.p_double[offs0+j]; s->idx.ptr.p_int[offs1] = i; temp.ptr.p_int[i-k+j] = temp.ptr.p_int[i-k+j]+1; } } /* * Initialization 'S.UIdx' and 'S.DIdx' */ sparse_sparseinitduidx(s, _state); ae_frame_leave(_state); return; } ae_assert(ae_false, "SparseConvertToCRS: invalid matrix type", _state); ae_frame_leave(_state); } /************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting CRS conversion. If you perform a lot of repeated CRS conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToCRSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytocrs(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { _sparsematrix_clear(s1); ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToCRS: invalid matrix type", _state); sparsecopytocrsbuf(s0, s1, _state); } /************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. S1 - matrix which may contain some pre-allocated memory, or can be just uninitialized structure. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytocrsbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { ae_frame _frame_block; ae_vector temp; ae_int_t nonne; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t offs0; ae_int_t offs1; ae_int_t m; ae_frame_make(_state, &_frame_block); ae_vector_init(&temp, 0, DT_INT, _state); ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToCRSBuf: invalid matrix type", _state); m = s0->m; if( s0->matrixtype==0 ) { /* * Convert from hash-table to CRS * Done like ConvertToCRS function */ s1->matrixtype = 1; s1->m = s0->m; s1->n = s0->n; s1->nfree = s0->nfree; nonne = 0; k = s0->tablesize; ivectorsetlengthatleast(&s1->ridx, s1->m+1, _state); for(i=0; i<=s1->m; i++) { s1->ridx.ptr.p_int[i] = 0; } ae_vector_set_length(&temp, s1->m, _state); for(i=0; i<=s1->m-1; i++) { temp.ptr.p_int[i] = 0; } /* * Number of elements per row */ for(i=0; i<=k-1; i++) { if( s0->idx.ptr.p_int[2*i]>=0 ) { s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1] = s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1]+1; nonne = nonne+1; } } /* * Fill RIdx (offsets of rows) */ for(i=0; i<=s1->m-1; i++) { s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; } /* * Allocate memory */ rvectorsetlengthatleast(&s1->vals, nonne, _state); ivectorsetlengthatleast(&s1->idx, nonne, _state); for(i=0; i<=k-1; i++) { if( s0->idx.ptr.p_int[2*i]>=0 ) { s1->vals.ptr.p_double[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->vals.ptr.p_double[i]; s1->idx.ptr.p_int[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->idx.ptr.p_int[2*i+1]; temp.ptr.p_int[s0->idx.ptr.p_int[2*i]] = temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]+1; } } /* * Set NInitialized */ s1->ninitialized = s1->ridx.ptr.p_int[s1->m]; /* * Sorting of elements */ for(i=0; i<=s1->m-1; i++) { tagsortmiddleir(&s1->idx, &s1->vals, s1->ridx.ptr.p_int[i], s1->ridx.ptr.p_int[i+1]-s1->ridx.ptr.p_int[i], _state); } /* * Initialization 'S.UIdx' and 'S.DIdx' */ sparse_sparseinitduidx(s1, _state); ae_frame_leave(_state); return; } if( s0->matrixtype==1 ) { /* * Already CRS, just copy */ sparsecopybuf(s0, s1, _state); ae_frame_leave(_state); return; } if( s0->matrixtype==2 ) { ae_assert(s0->m==s0->n, "SparseCopyToCRS: non-square SKS matrices are not supported", _state); /* * From SKS to CRS. */ s1->m = s0->m; s1->n = s0->n; s1->matrixtype = 1; /* * Fill RIdx by number of elements per row: * RIdx[I+1] stores number of elements in I-th row. * * Convert RIdx from row sizes to row offsets. * Set NInitialized */ ivectorsetlengthatleast(&s1->ridx, m+1, _state); s1->ridx.ptr.p_int[0] = 0; for(i=1; i<=m; i++) { s1->ridx.ptr.p_int[i] = 1; } nonne = 0; for(i=0; i<=m-1; i++) { s1->ridx.ptr.p_int[i+1] = s0->didx.ptr.p_int[i]+s1->ridx.ptr.p_int[i+1]; for(j=i-s0->uidx.ptr.p_int[i]; j<=i-1; j++) { s1->ridx.ptr.p_int[j+1] = s1->ridx.ptr.p_int[j+1]+1; } nonne = nonne+s0->didx.ptr.p_int[i]+1+s0->uidx.ptr.p_int[i]; } for(i=0; i<=m-1; i++) { s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; } s1->ninitialized = s1->ridx.ptr.p_int[m]; /* * Allocate memory and move elements to Vals/Idx. * Initially, elements are sorted by rows, and are sorted within row too. * No additional post-sorting is required. */ ae_vector_set_length(&temp, m, _state); for(i=0; i<=m-1; i++) { temp.ptr.p_int[i] = 0; } rvectorsetlengthatleast(&s1->vals, nonne, _state); ivectorsetlengthatleast(&s1->idx, nonne, _state); for(i=0; i<=m-1; i++) { /* * copy subdiagonal and diagonal parts of I-th block */ offs0 = s0->ridx.ptr.p_int[i]; offs1 = s1->ridx.ptr.p_int[i]+temp.ptr.p_int[i]; k = s0->didx.ptr.p_int[i]+1; for(j=0; j<=k-1; j++) { s1->vals.ptr.p_double[offs1+j] = s0->vals.ptr.p_double[offs0+j]; s1->idx.ptr.p_int[offs1+j] = i-s0->didx.ptr.p_int[i]+j; } temp.ptr.p_int[i] = temp.ptr.p_int[i]+s0->didx.ptr.p_int[i]+1; /* * Copy superdiagonal part of I-th block */ offs0 = s0->ridx.ptr.p_int[i]+s0->didx.ptr.p_int[i]+1; k = s0->uidx.ptr.p_int[i]; for(j=0; j<=k-1; j++) { offs1 = s1->ridx.ptr.p_int[i-k+j]+temp.ptr.p_int[i-k+j]; s1->vals.ptr.p_double[offs1] = s0->vals.ptr.p_double[offs0+j]; s1->idx.ptr.p_int[offs1] = i; temp.ptr.p_int[i-k+j] = temp.ptr.p_int[i-k+j]+1; } } /* * Initialization 'S.UIdx' and 'S.DIdx' */ sparse_sparseinitduidx(s1, _state); ae_frame_leave(_state); return; } ae_assert(ae_false, "SparseCopyToCRSBuf: unexpected matrix type", _state); ae_frame_leave(_state); } /************************************************************************* This function performs in-place conversion to SKS format. INPUT PARAMETERS S - sparse matrix in any format. OUTPUT PARAMETERS S - sparse matrix in SKS format. NOTE: this function has no effect when called with matrix which is already in SKS mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToSKSBuf() function in this case. -- ALGLIB PROJECT -- Copyright 15.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseconverttosks(sparsematrix* s, ae_state *_state) { ae_frame _frame_block; ae_vector tridx; ae_vector tdidx; ae_vector tuidx; ae_vector tvals; ae_int_t n; ae_int_t t0; ae_int_t t1; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_frame_make(_state, &_frame_block); ae_vector_init(&tridx, 0, DT_INT, _state); ae_vector_init(&tdidx, 0, DT_INT, _state); ae_vector_init(&tuidx, 0, DT_INT, _state); ae_vector_init(&tvals, 0, DT_REAL, _state); ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseConvertToSKS: invalid matrix type", _state); ae_assert(s->m==s->n, "SparseConvertToSKS: rectangular matrices are not supported", _state); n = s->n; if( s->matrixtype==2 ) { /* * Already in SKS mode */ ae_frame_leave(_state); return; } /* * Generate internal copy of SKS matrix */ ivectorsetlengthatleast(&tdidx, n+1, _state); ivectorsetlengthatleast(&tuidx, n+1, _state); for(i=0; i<=n; i++) { tdidx.ptr.p_int[i] = 0; tuidx.ptr.p_int[i] = 0; } t0 = 0; t1 = 0; while(sparseenumerate(s, &t0, &t1, &i, &j, &v, _state)) { if( jmatrixtype = 2; s->ninitialized = 0; s->nfree = 0; s->m = n; s->n = n; ae_swap_vectors(&s->didx, &tdidx); ae_swap_vectors(&s->uidx, &tuidx); ae_swap_vectors(&s->ridx, &tridx); ae_swap_vectors(&s->vals, &tvals); ae_frame_leave(_state); } /************************************************************************* This function performs out-of-place conversion to SKS storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToSKSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytosks(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { _sparsematrix_clear(s1); ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToSKS: invalid matrix type", _state); sparsecopytosksbuf(s0, s1, _state); } /************************************************************************* This function performs out-of-place conversion to SKS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsecopytosksbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state) { double v; ae_int_t n; ae_int_t t0; ae_int_t t1; ae_int_t i; ae_int_t j; ae_int_t k; ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToSKSBuf: invalid matrix type", _state); ae_assert(s0->m==s0->n, "SparseCopyToSKSBuf: rectangular matrices are not supported", _state); n = s0->n; if( s0->matrixtype==2 ) { /* * Already SKS, just copy */ sparsecopybuf(s0, s1, _state); return; } /* * Generate copy of matrix in the SKS format */ ivectorsetlengthatleast(&s1->didx, n+1, _state); ivectorsetlengthatleast(&s1->uidx, n+1, _state); for(i=0; i<=n; i++) { s1->didx.ptr.p_int[i] = 0; s1->uidx.ptr.p_int[i] = 0; } t0 = 0; t1 = 0; while(sparseenumerate(s0, &t0, &t1, &i, &j, &v, _state)) { if( jdidx.ptr.p_int[i] = ae_maxint(s1->didx.ptr.p_int[i], i-j, _state); } else { s1->uidx.ptr.p_int[j] = ae_maxint(s1->uidx.ptr.p_int[j], j-i, _state); } } ivectorsetlengthatleast(&s1->ridx, n+1, _state); s1->ridx.ptr.p_int[0] = 0; for(i=1; i<=n; i++) { s1->ridx.ptr.p_int[i] = s1->ridx.ptr.p_int[i-1]+s1->didx.ptr.p_int[i-1]+1+s1->uidx.ptr.p_int[i-1]; } rvectorsetlengthatleast(&s1->vals, s1->ridx.ptr.p_int[n], _state); k = s1->ridx.ptr.p_int[n]; for(i=0; i<=k-1; i++) { s1->vals.ptr.p_double[i] = 0.0; } t0 = 0; t1 = 0; while(sparseenumerate(s0, &t0, &t1, &i, &j, &v, _state)) { if( j<=i ) { s1->vals.ptr.p_double[s1->ridx.ptr.p_int[i]+s1->didx.ptr.p_int[i]-(i-j)] = v; } else { s1->vals.ptr.p_double[s1->ridx.ptr.p_int[j+1]-(j-i)] = v; } } for(i=0; i<=n-1; i++) { s1->didx.ptr.p_int[n] = ae_maxint(s1->didx.ptr.p_int[n], s1->didx.ptr.p_int[i], _state); s1->uidx.ptr.p_int[n] = ae_maxint(s1->uidx.ptr.p_int[n], s1->uidx.ptr.p_int[i], _state); } s1->matrixtype = 2; s1->ninitialized = 0; s1->nfree = 0; s1->m = n; s1->n = n; } /************************************************************************* This function returns type of the matrix storage format. INPUT PARAMETERS: S - sparse matrix. RESULT: sparse storage format used by matrix: 0 - Hash-table 1 - CRS (compressed row storage) 2 - SKS (skyline) NOTE: future versions of ALGLIB may include additional sparse storage formats. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetmatrixtype(sparsematrix* s, ae_state *_state) { ae_int_t result; ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseGetMatrixType: invalid matrix type", _state); result = s->matrixtype; return result; } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using Hash table representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is Hash table False if matrix type is not Hash table -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ ae_bool sparseishash(sparsematrix* s, ae_state *_state) { ae_bool result; ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseIsHash: invalid matrix type", _state); result = s->matrixtype==0; return result; } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using CRS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is CRS False if matrix type is not CRS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ ae_bool sparseiscrs(sparsematrix* s, ae_state *_state) { ae_bool result; ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseIsCRS: invalid matrix type", _state); result = s->matrixtype==1; return result; } /************************************************************************* This function checks matrix storage format and returns True when matrix is stored using SKS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is SKS False if matrix type is not SKS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/ ae_bool sparseissks(sparsematrix* s, ae_state *_state) { ae_bool result; ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseIsSKS: invalid matrix type", _state); result = s->matrixtype==2; return result; } /************************************************************************* The function frees all memory occupied by sparse matrix. Sparse matrix structure becomes unusable after this call. OUTPUT PARAMETERS S - sparse matrix to delete -- ALGLIB PROJECT -- Copyright 24.07.2012 by Bochkanov Sergey *************************************************************************/ void sparsefree(sparsematrix* s, ae_state *_state) { _sparsematrix_clear(s); s->matrixtype = -1; s->m = 0; s->n = 0; s->nfree = 0; s->ninitialized = 0; s->tablesize = 0; } /************************************************************************* The function returns number of rows of a sparse matrix. RESULT: number of rows of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetnrows(sparsematrix* s, ae_state *_state) { ae_int_t result; result = s->m; return result; } /************************************************************************* The function returns number of columns of a sparse matrix. RESULT: number of columns of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetncols(sparsematrix* s, ae_state *_state) { ae_int_t result; result = s->n; return result; } /************************************************************************* The function returns number of strictly upper triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly above main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetuppercount(sparsematrix* s, ae_state *_state) { ae_int_t sz; ae_int_t i0; ae_int_t i; ae_int_t result; result = -1; if( s->matrixtype==0 ) { /* * Hash-table matrix */ result = 0; sz = s->tablesize; for(i0=0; i0<=sz-1; i0++) { i = s->idx.ptr.p_int[2*i0]; if( i>=0&&s->idx.ptr.p_int[2*i0+1]>i ) { result = result+1; } } return result; } if( s->matrixtype==1 ) { /* * CRS matrix */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGetUpperCount: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); result = 0; sz = s->m; for(i=0; i<=sz-1; i++) { result = result+(s->ridx.ptr.p_int[i+1]-s->uidx.ptr.p_int[i]); } return result; } if( s->matrixtype==2 ) { /* * SKS matrix */ ae_assert(s->m==s->n, "SparseGetUpperCount: non-square SKS matrices are not supported", _state); result = 0; sz = s->m; for(i=0; i<=sz-1; i++) { result = result+s->uidx.ptr.p_int[i]; } return result; } ae_assert(ae_false, "SparseGetUpperCount: internal error", _state); return result; } /************************************************************************* The function returns number of strictly lower triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly below main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/ ae_int_t sparsegetlowercount(sparsematrix* s, ae_state *_state) { ae_int_t sz; ae_int_t i0; ae_int_t i; ae_int_t result; result = -1; if( s->matrixtype==0 ) { /* * Hash-table matrix */ result = 0; sz = s->tablesize; for(i0=0; i0<=sz-1; i0++) { i = s->idx.ptr.p_int[2*i0]; if( i>=0&&s->idx.ptr.p_int[2*i0+1]matrixtype==1 ) { /* * CRS matrix */ ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGetUpperCount: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); result = 0; sz = s->m; for(i=0; i<=sz-1; i++) { result = result+(s->didx.ptr.p_int[i]-s->ridx.ptr.p_int[i]); } return result; } if( s->matrixtype==2 ) { /* * SKS matrix */ ae_assert(s->m==s->n, "SparseGetUpperCount: non-square SKS matrices are not supported", _state); result = 0; sz = s->m; for(i=0; i<=sz-1; i++) { result = result+s->didx.ptr.p_int[i]; } return result; } ae_assert(ae_false, "SparseGetUpperCount: internal error", _state); return result; } /************************************************************************* Procedure for initialization 'S.DIdx' and 'S.UIdx' -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ static void sparse_sparseinitduidx(sparsematrix* s, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t lt; ae_int_t rt; ae_assert(s->matrixtype==1, "SparseInitDUIdx: internal error, incorrect matrix type", _state); ivectorsetlengthatleast(&s->didx, s->m, _state); ivectorsetlengthatleast(&s->uidx, s->m, _state); for(i=0; i<=s->m-1; i++) { s->uidx.ptr.p_int[i] = -1; s->didx.ptr.p_int[i] = -1; lt = s->ridx.ptr.p_int[i]; rt = s->ridx.ptr.p_int[i+1]; for(j=lt; j<=rt-1; j++) { if( iidx.ptr.p_int[j]&&s->uidx.ptr.p_int[i]==-1 ) { s->uidx.ptr.p_int[i] = j; break; } else { if( i==s->idx.ptr.p_int[j] ) { s->didx.ptr.p_int[i] = j; } } } if( s->uidx.ptr.p_int[i]==-1 ) { s->uidx.ptr.p_int[i] = s->ridx.ptr.p_int[i+1]; } if( s->didx.ptr.p_int[i]==-1 ) { s->didx.ptr.p_int[i] = s->uidx.ptr.p_int[i]; } } } /************************************************************************* This is hash function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ static ae_int_t sparse_hash(ae_int_t i, ae_int_t j, ae_int_t tabsize, ae_state *_state) { ae_frame _frame_block; hqrndstate r; ae_int_t result; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&r, _state); hqrndseed(i, j, &r, _state); result = hqrnduniformi(&r, tabsize, _state); ae_frame_leave(_state); return result; } void _sparsematrix_init(void* _p, ae_state *_state) { sparsematrix *p = (sparsematrix*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->vals, 0, DT_REAL, _state); ae_vector_init(&p->idx, 0, DT_INT, _state); ae_vector_init(&p->ridx, 0, DT_INT, _state); ae_vector_init(&p->didx, 0, DT_INT, _state); ae_vector_init(&p->uidx, 0, DT_INT, _state); } void _sparsematrix_init_copy(void* _dst, void* _src, ae_state *_state) { sparsematrix *dst = (sparsematrix*)_dst; sparsematrix *src = (sparsematrix*)_src; ae_vector_init_copy(&dst->vals, &src->vals, _state); ae_vector_init_copy(&dst->idx, &src->idx, _state); ae_vector_init_copy(&dst->ridx, &src->ridx, _state); ae_vector_init_copy(&dst->didx, &src->didx, _state); ae_vector_init_copy(&dst->uidx, &src->uidx, _state); dst->matrixtype = src->matrixtype; dst->m = src->m; dst->n = src->n; dst->nfree = src->nfree; dst->ninitialized = src->ninitialized; dst->tablesize = src->tablesize; } void _sparsematrix_clear(void* _p) { sparsematrix *p = (sparsematrix*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->vals); ae_vector_clear(&p->idx); ae_vector_clear(&p->ridx); ae_vector_clear(&p->didx); ae_vector_clear(&p->uidx); } void _sparsematrix_destroy(void* _p) { sparsematrix *p = (sparsematrix*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->vals); ae_vector_destroy(&p->idx); ae_vector_destroy(&p->ridx); ae_vector_destroy(&p->didx); ae_vector_destroy(&p->uidx); } void _sparsebuffers_init(void* _p, ae_state *_state) { sparsebuffers *p = (sparsebuffers*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->d, 0, DT_INT, _state); ae_vector_init(&p->u, 0, DT_INT, _state); _sparsematrix_init(&p->s, _state); } void _sparsebuffers_init_copy(void* _dst, void* _src, ae_state *_state) { sparsebuffers *dst = (sparsebuffers*)_dst; sparsebuffers *src = (sparsebuffers*)_src; ae_vector_init_copy(&dst->d, &src->d, _state); ae_vector_init_copy(&dst->u, &src->u, _state); _sparsematrix_init_copy(&dst->s, &src->s, _state); } void _sparsebuffers_clear(void* _p) { sparsebuffers *p = (sparsebuffers*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->d); ae_vector_clear(&p->u); _sparsematrix_clear(&p->s); } void _sparsebuffers_destroy(void* _p) { sparsebuffers *p = (sparsebuffers*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->d); ae_vector_destroy(&p->u); _sparsematrix_destroy(&p->s); } /************************************************************************* LU decomposition of a general real matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_vector_clear(pivots); ae_assert(m>0, "RMatrixLU: incorrect M!", _state); ae_assert(n>0, "RMatrixLU: incorrect N!", _state); rmatrixplu(a, m, n, pivots, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { rmatrixlu(a,m,n,pivots, _state); } /************************************************************************* LU decomposition of a general complex matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_vector_clear(pivots); ae_assert(m>0, "CMatrixLU: incorrect M!", _state); ae_assert(n>0, "CMatrixLU: incorrect N!", _state); cmatrixplu(a, m, n, pivots, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { cmatrixlu(a,m,n,pivots, _state); } /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a Hermitian positive- definite matrix. The result of an algorithm is a representation of A as A=U'*U or A=L*L' (here X' detones conj(X^T)). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U'*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_bool hpdmatrixcholesky(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); if( n<1 ) { result = ae_false; ae_frame_leave(_state); return result; } result = trfac_hpdmatrixcholeskyrec(a, 0, n, isupper, &tmp, _state); ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_hpdmatrixcholesky(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { return hpdmatrixcholesky(a,n,isupper, _state); } /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a symmetric positive- definite matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U^T*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_bool spdmatrixcholesky(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_REAL, _state); if( n<1 ) { result = ae_false; ae_frame_leave(_state); return result; } result = spdmatrixcholeskyrec(a, 0, n, isupper, &tmp, _state); ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_spdmatrixcholesky(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { return spdmatrixcholesky(a,n,isupper, _state); } /************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateAdd1Buf(). INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* u, ae_state *_state) { ae_frame _frame_block; ae_vector bufr; ae_frame_make(_state, &_frame_block); ae_vector_init(&bufr, 0, DT_REAL, _state); ae_assert(n>0, "SPDMatrixCholeskyUpdateAdd1: N<=0", _state); ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateAdd1: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateAdd1: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateAdd1: Length(U) ( Af20 0 Af22 Af23 ) ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) If we have Cholesky decomposition of A, it must be recalculated after variables were fixed. However, it is possible to use efficient algorithm, which needs O(K*N^2) time to "fix" K variables, given Cholesky decomposition of original, "unfixed" A. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. NOTE: this function is efficient only for moderate amount of updated variables - say, 0.1*N or 0.3*N. For larger amount of variables it will still work, but you may get better performance with straightforward Cholesky. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefix(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Boolean */ ae_vector* fix, ae_state *_state) { ae_frame _frame_block; ae_vector bufr; ae_frame_make(_state, &_frame_block); ae_vector_init(&bufr, 0, DT_REAL, _state); ae_assert(n>0, "SPDMatrixCholeskyUpdateFix: N<=0", _state); ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateFix: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateFix: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateFix: Length(Fix)0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1buf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* u, /* Real */ ae_vector* bufr, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t nz; double cs; double sn; double v; double vv; ae_assert(n>0, "SPDMatrixCholeskyUpdateAdd1Buf: N<=0", _state); ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Length(U)ptr.p_double[i],(double)(0)) ) { nz = i; break; } } if( nz==n ) { /* * Nothing to update */ return; } /* * If working with upper triangular matrix */ if( isupper ) { /* * Perform a sequence of updates which fix variables one by one. * This approach is different from one which is used when we work * with lower triangular matrix. */ rvectorsetlengthatleast(bufr, n, _state); for(j=nz; j<=n-1; j++) { bufr->ptr.p_double[j] = u->ptr.p_double[j]; } for(i=nz; i<=n-1; i++) { if( ae_fp_neq(bufr->ptr.p_double[i],(double)(0)) ) { generaterotation(a->ptr.pp_double[i][i], bufr->ptr.p_double[i], &cs, &sn, &v, _state); a->ptr.pp_double[i][i] = v; bufr->ptr.p_double[i] = 0.0; for(j=i+1; j<=n-1; j++) { v = a->ptr.pp_double[i][j]; vv = bufr->ptr.p_double[j]; a->ptr.pp_double[i][j] = cs*v+sn*vv; bufr->ptr.p_double[j] = -sn*v+cs*vv; } } } } else { /* * Calculate rows of modified Cholesky factor, row-by-row * (updates performed during variable fixing are applied * simultaneously to each row) */ rvectorsetlengthatleast(bufr, 3*n, _state); for(j=nz; j<=n-1; j++) { bufr->ptr.p_double[j] = u->ptr.p_double[j]; } for(i=nz; i<=n-1; i++) { /* * Update all previous updates [Idx+1...I-1] to I-th row */ vv = bufr->ptr.p_double[i]; for(j=nz; j<=i-1; j++) { cs = bufr->ptr.p_double[n+2*j+0]; sn = bufr->ptr.p_double[n+2*j+1]; v = a->ptr.pp_double[i][j]; a->ptr.pp_double[i][j] = cs*v+sn*vv; vv = -sn*v+cs*vv; } /* * generate rotation applied to I-th element of update vector */ generaterotation(a->ptr.pp_double[i][i], vv, &cs, &sn, &v, _state); a->ptr.pp_double[i][i] = v; bufr->ptr.p_double[n+2*i+0] = cs; bufr->ptr.p_double[n+2*i+1] = sn; } } } /************************************************************************* Update of Cholesky decomposition: "fixing" some variables. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateFix() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefixbuf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Boolean */ ae_vector* fix, /* Real */ ae_vector* bufr, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t nfix; ae_int_t idx; double cs; double sn; double v; double vv; ae_assert(n>0, "SPDMatrixCholeskyUpdateFixBuf: N<=0", _state); ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateFixBuf: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateFixBuf: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateFixBuf: Length(Fix)ptr.p_bool[i] ) { inc(&nfix, _state); } } if( nfix==0 ) { /* * Nothing to fix */ return; } if( nfix==n ) { /* * All variables are fixed. * Set A to identity and exit. */ if( isupper ) { for(i=0; i<=n-1; i++) { a->ptr.pp_double[i][i] = (double)(1); for(j=i+1; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } a->ptr.pp_double[i][i] = (double)(1); } } return; } /* * If working with upper triangular matrix */ if( isupper ) { /* * Perform a sequence of updates which fix variables one by one. * This approach is different from one which is used when we work * with lower triangular matrix. */ rvectorsetlengthatleast(bufr, n, _state); for(k=0; k<=n-1; k++) { if( fix->ptr.p_bool[k] ) { idx = k; /* * Quick exit if it is last variable */ if( idx==n-1 ) { for(i=0; i<=idx-1; i++) { a->ptr.pp_double[i][idx] = 0.0; } a->ptr.pp_double[idx][idx] = 1.0; continue; } /* * We have Cholesky decomposition of quadratic term in A, * with upper triangle being stored as given below: * * ( U00 u01 U02 ) * U = ( u11 u12 ) * ( U22 ) * * Here u11 is diagonal element corresponding to variable K. We * want to fix this variable, and we do so by modifying U as follows: * * ( U00 0 U02 ) * U_mod = ( 1 0 ) * ( U_m ) * * with U_m = CHOLESKY [ (U22^T)*U22 + (u12^T)*u12 ] * * Of course, we can calculate U_m by calculating (U22^T)*U22 explicitly, * modifying it and performing Cholesky decomposition of modified matrix. * However, we can treat it as follows: * * we already have CHOLESKY[(U22^T)*U22], which is equal to U22 * * we have rank-1 update (u12^T)*u12 applied to (U22^T)*U22 * * thus, we can calculate updated Cholesky with O(N^2) algorithm * instead of O(N^3) one */ for(j=idx+1; j<=n-1; j++) { bufr->ptr.p_double[j] = a->ptr.pp_double[idx][j]; } for(i=0; i<=idx-1; i++) { a->ptr.pp_double[i][idx] = 0.0; } a->ptr.pp_double[idx][idx] = 1.0; for(i=idx+1; i<=n-1; i++) { a->ptr.pp_double[idx][i] = 0.0; } for(i=idx+1; i<=n-1; i++) { if( ae_fp_neq(bufr->ptr.p_double[i],(double)(0)) ) { generaterotation(a->ptr.pp_double[i][i], bufr->ptr.p_double[i], &cs, &sn, &v, _state); a->ptr.pp_double[i][i] = v; bufr->ptr.p_double[i] = 0.0; for(j=i+1; j<=n-1; j++) { v = a->ptr.pp_double[i][j]; vv = bufr->ptr.p_double[j]; a->ptr.pp_double[i][j] = cs*v+sn*vv; bufr->ptr.p_double[j] = -sn*v+cs*vv; } } } } } } else { /* * Calculate rows of modified Cholesky factor, row-by-row * (updates performed during variable fixing are applied * simultaneously to each row) */ rvectorsetlengthatleast(bufr, 3*n, _state); for(k=0; k<=n-1; k++) { if( fix->ptr.p_bool[k] ) { idx = k; /* * Quick exit if it is last variable */ if( idx==n-1 ) { for(i=0; i<=idx-1; i++) { a->ptr.pp_double[idx][i] = 0.0; } a->ptr.pp_double[idx][idx] = 1.0; continue; } /* * store column to buffer and clear row/column of A */ for(j=idx+1; j<=n-1; j++) { bufr->ptr.p_double[j] = a->ptr.pp_double[j][idx]; } for(i=0; i<=idx-1; i++) { a->ptr.pp_double[idx][i] = 0.0; } a->ptr.pp_double[idx][idx] = 1.0; for(i=idx+1; i<=n-1; i++) { a->ptr.pp_double[i][idx] = 0.0; } /* * Apply update to rows of A */ for(i=idx+1; i<=n-1; i++) { /* * Update all previous updates [Idx+1...I-1] to I-th row */ vv = bufr->ptr.p_double[i]; for(j=idx+1; j<=i-1; j++) { cs = bufr->ptr.p_double[n+2*j+0]; sn = bufr->ptr.p_double[n+2*j+1]; v = a->ptr.pp_double[i][j]; a->ptr.pp_double[i][j] = cs*v+sn*vv; vv = -sn*v+cs*vv; } /* * generate rotation applied to I-th element of update vector */ generaterotation(a->ptr.pp_double[i][i], vv, &cs, &sn, &v, _state); a->ptr.pp_double[i][i] = v; bufr->ptr.p_double[n+2*i+0] = cs; bufr->ptr.p_double[n+2*i+1] = sn; } } } } } /************************************************************************* Sparse Cholesky decomposition for skyline matrixm using in-place algorithm without allocating additional storage. The algorithm computes Cholesky decomposition of a symmetric positive- definite sparse matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T This function is a more efficient alternative to general, but slower SparseCholeskyX(), because it does not create temporary copies of the target. It performs factorization in-place, which gives best performance on low-profile matrices. Its drawback, however, is that it can not perform profile-reducing permutation of input matrix. INPUT PARAMETERS: A - sparse matrix in skyline storage (SKS) format. N - size of matrix A (can be smaller than actual size of A) IsUpper - if IsUpper=True, then factorization is performed on upper triangle. Another triangle is ignored (it may contant some data, but it is not changed). OUTPUT PARAMETERS: A - the result of factorization, stored in SKS. If IsUpper=True, then the upper triangle contains matrix U, such that A = U^T*U. Lower triangle is not changed. Similarly, if IsUpper = False. In this case L is returned, and we have A = L*(L^T). Note that THIS function does not perform permutation of rows to reduce bandwidth. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. NOTE: for performance reasons this function does NOT check that input matrix includes only finite values. It is your responsibility to make sure that there are no infinite or NAN values in the matrix. -- ALGLIB routine -- 16.01.2014 Bochkanov Sergey *************************************************************************/ ae_bool sparsecholeskyskyline(sparsematrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t jnz; ae_int_t jnza; ae_int_t jnzl; double v; double vv; double a12; ae_int_t nready; ae_int_t nadd; ae_int_t banda; ae_int_t offsa; ae_int_t offsl; ae_bool result; ae_assert(n>=0, "SparseCholeskySkyline: N<0", _state); ae_assert(sparsegetnrows(a, _state)>=n, "SparseCholeskySkyline: rows(A)=n, "SparseCholeskySkyline: cols(A)=BANDWIDTH(A1), I-th equation is reduced from * L[I,0]*A1[0] + L[I,1]*A1[1] + ... + L[I,I]*A1[I] = A[I] * to * L[I,JNZ]*A1[JNZ] + ... + L[I,I]*A1[I] = A[I] * where JNZ = max(NReady-BANDWIDTH(A1),I-BANDWIDTH(L[i])) * (JNZ is an index of the firts column where both A and L become * nonzero). * * NOTE: we rely on details of SparseMatrix internal storage format. * This is allowed by SparseMatrix specification. */ a12 = 0.0; if( a->didx.ptr.p_int[nready]>0 ) { banda = a->didx.ptr.p_int[nready]; for(i=nready-banda; i<=nready-1; i++) { /* * Elements of A1[0:I-1] were computed: * * A1[0:NReady-BandA-1] are zero (sparse) * * A1[NReady-BandA:I-1] replaced corresponding elements of A * * Now it is time to get I-th one. * * First, we calculate: * * JNZA - index of the first column where A become nonzero * * JNZL - index of the first column where L become nonzero * * JNZ - index of the first column where both A and L become nonzero * * OffsA - offset of A[JNZ] in A.Vals * * OffsL - offset of L[I,JNZ] in A.Vals * * Then, we solve SUM(A1[j]*L[I,j],j=JNZ..I-1) + A1[I]*L[I,I] = A[I], * with A1[JNZ..I-1] already known, and A1[I] unknown. */ jnza = nready-banda; jnzl = i-a->didx.ptr.p_int[i]; jnz = ae_maxint(jnza, jnzl, _state); offsa = a->ridx.ptr.p_int[nready]+(jnz-jnza); offsl = a->ridx.ptr.p_int[i]+(jnz-jnzl); v = 0.0; k = i-1-jnz; for(j=0; j<=k; j++) { v = v+a->vals.ptr.p_double[offsa+j]*a->vals.ptr.p_double[offsl+j]; } vv = (a->vals.ptr.p_double[offsa+k+1]-v)/a->vals.ptr.p_double[offsl+k+1]; a->vals.ptr.p_double[offsa+k+1] = vv; a12 = a12+vv*vv; } } /* * Calculate CHOLESKY(B-A1*A1') */ offsa = a->ridx.ptr.p_int[nready]+a->didx.ptr.p_int[nready]; v = a->vals.ptr.p_double[offsa]; if( ae_fp_less_eq(v,a12) ) { result = ae_false; return result; } a->vals.ptr.p_double[offsa] = ae_sqrt(v-a12, _state); /* * Increase size of the updated matrix */ inc(&nready, _state); } /* * transpose if needed */ if( isupper ) { sparsetransposesks(a, _state); } result = ae_true; return result; } /************************************************************************* Sparse Cholesky decomposition: "expert" function. The algorithm computes Cholesky decomposition of a symmetric positive- definite sparse matrix. The result is representation of A as A=U^T*U or A=L*L^T Triangular factor L or U is written to separate SparseMatrix structure. If output buffer already contrains enough memory to store L/U, this memory is reused. INPUT PARAMETERS: A - upper or lower triangle of sparse matrix. Matrix can be in any sparse storage format. N - size of matrix A (can be smaller than actual size of A) IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. Another triangle is ignored. P0, P1 - integer arrays: * for Ordering=-3 - user-supplied permutation of rows/ columns, which complies to requirements stated in the "OUTPUT PARAMETERS" section. Both P0 and P1 must be initialized by user. * for other values of Ordering - possibly preallocated buffer, which is filled by internally generated permutation. Automatically resized if its size is too small to store data. Ordering- sparse matrix reordering algorithm which is used to reduce fill-in amount: * -3 use ordering supplied by user in P0/P1 * -2 use random ordering * -1 use original order * 0 use best algorithm implemented so far If input matrix is given in SKS format, factorization function ignores Ordering and uses original order of the columns. The idea is that if you already store matrix in SKS format, it is better not to perform costly reordering. Algo - type of algorithm which is used during factorization: * 0 use best algorithm (for SKS input or output matrices Algo=2 is used; otherwise Algo=1 is used) * 1 use CRS-based algorithm * 2 use skyline-based factorization algorithm. This algorithm is a fastest one for low-profile matrices, but requires too much of memory for matrices with large bandwidth. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS If you do not know what format to choose, use 1 (CRS). Buf - SparseBuffers structure which is used to store temporaries. This function may reuse previously allocated storage, so if you perform repeated factorizations it is beneficial to reuse Buf. C - SparseMatrix structure which can be just some random garbage. In case in contains enough memory to store triangular factors, this memory will be reused. Othwerwise, algorithm will automatically allocate enough memory. OUTPUT PARAMETERS: C - the result of factorization, stored in desired format. If IsUpper=True, then the upper triangle contains matrix U, such that (P'*A*P) = U^T*U, where P is a permutation matrix (see below). The elements below the main diagonal are zero. Similarly, if IsUpper = False. In this case L is returned, and we have (P'*A*P) = L*(L^T). P0 - permutation (according to Ordering parameter) which minimizes amount of fill-in: * P0 is array[N] * permutation is applied to A before factorization takes place, i.e. we have U'*U = L*L' = P'*A*P * P0[k]=j means that column/row j of A is moved to k-th position before starting factorization. P1 - permutation P in another format, array[N]: * P1[k]=j means that k-th column/row of A is moved to j-th position RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of C is not determined in such case. NOTE: for performance reasons this function does NOT check that input matrix includes only finite values. It is your responsibility to make sure that there are no infinite or NAN values in the matrix. -- ALGLIB routine -- 16.01.2014 Bochkanov Sergey *************************************************************************/ ae_bool sparsecholeskyx(sparsematrix* a, ae_int_t n, ae_bool isupper, /* Integer */ ae_vector* p0, /* Integer */ ae_vector* p1, ae_int_t ordering, ae_int_t algo, ae_int_t fmt, sparsebuffers* buf, sparsematrix* c, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t t0; ae_int_t t1; double v; hqrndstate rs; ae_bool result; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&rs, _state); ae_assert(n>=0, "SparseMatrixCholeskyBuf: N<0", _state); ae_assert(sparsegetnrows(a, _state)>=n, "SparseMatrixCholeskyBuf: rows(A)=n, "SparseMatrixCholeskyBuf: cols(A)=-3&&ordering<=0, "SparseMatrixCholeskyBuf: invalid Ordering parameter", _state); ae_assert(algo>=0&&algo<=2, "SparseMatrixCholeskyBuf: invalid Algo parameter", _state); hqrndrandomize(&rs, _state); /* * Perform some quick checks. * Because sparse matrices are expensive data structures, these * checks are better to perform during early stages of the factorization. */ result = ae_false; if( n<1 ) { ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { if( ae_fp_less_eq(sparsegetdiagonal(a, i, _state),(double)(0)) ) { ae_frame_leave(_state); return result; } } /* * First, determine appropriate ordering: * * for SKS inputs, Ordering=-1 is automatically chosen (overrides user settings) */ if( ordering==0 ) { ordering = -1; } if( sparseissks(a, _state) ) { ordering = -1; } if( ordering==-3 ) { /* * User-supplied ordering. * Check its correctness. */ ae_assert(p0->cnt>=n, "SparseCholeskyX: user-supplied permutation is too short", _state); ae_assert(p1->cnt>=n, "SparseCholeskyX: user-supplied permutation is too short", _state); for(i=0; i<=n-1; i++) { ae_assert(p0->ptr.p_int[i]>=0&&p0->ptr.p_int[i]ptr.p_int[i]>=0&&p1->ptr.p_int[i]ptr.p_int[p0->ptr.p_int[i]]==i, "SparseCholeskyX: user-supplied permutation is inconsistent - P1 is not inverse of P0", _state); } } if( ordering==-2 ) { /* * Use random ordering */ ivectorsetlengthatleast(p0, n, _state); ivectorsetlengthatleast(p1, n, _state); for(i=0; i<=n-1; i++) { p0->ptr.p_int[i] = i; } for(i=0; i<=n-1; i++) { j = i+hqrnduniformi(&rs, n-i, _state); if( j!=i ) { k = p0->ptr.p_int[i]; p0->ptr.p_int[i] = p0->ptr.p_int[j]; p0->ptr.p_int[j] = k; } } for(i=0; i<=n-1; i++) { p1->ptr.p_int[p0->ptr.p_int[i]] = i; } } if( ordering==-1 ) { /* * Use initial ordering */ ivectorsetlengthatleast(p0, n, _state); ivectorsetlengthatleast(p1, n, _state); for(i=0; i<=n-1; i++) { p0->ptr.p_int[i] = i; p1->ptr.p_int[i] = i; } } /* * Determine algorithm to use: * * for SKS input or output - use SKS solver (overrides user settings) * * default is to use Algo=1 */ if( algo==0 ) { algo = 1; } if( sparseissks(a, _state)||fmt==2 ) { algo = 2; } algo = 2; if( algo==2 ) { /* * Skyline Cholesky with non-skyline output. * * Call CholeskyX() recursively with Buf.S as output matrix, * then perform conversion from SKS to desired format. We can * use Buf.S in reccurrent call because SKS-to-SKS CholeskyX() * does not uses this field. */ if( fmt!=2 ) { result = sparsecholeskyx(a, n, isupper, p0, p1, -3, algo, 2, buf, &buf->s, _state); if( result ) { sparsecopytobuf(&buf->s, fmt, c, _state); } ae_frame_leave(_state); return result; } /* * Skyline Cholesky with skyline output */ if( sparseissks(a, _state)&&ordering==-1 ) { /* * Non-permuted skyline matrix. * * Quickly copy matrix to output buffer without permutation. * * NOTE: Buf.D is used as dummy vector filled with zeros. */ ivectorsetlengthatleast(&buf->d, n, _state); for(i=0; i<=n-1; i++) { buf->d.ptr.p_int[i] = 0; } if( isupper ) { /* * Create strictly upper-triangular matrix, * copy upper triangle of input. */ sparsecreatesksbuf(n, n, &buf->d, &a->uidx, c, _state); for(i=0; i<=n-1; i++) { t0 = a->ridx.ptr.p_int[i+1]-a->uidx.ptr.p_int[i]-1; t1 = a->ridx.ptr.p_int[i+1]-1; k = c->ridx.ptr.p_int[i+1]-c->uidx.ptr.p_int[i]-1; for(j=t0; j<=t1; j++) { c->vals.ptr.p_double[k] = a->vals.ptr.p_double[j]; k = k+1; } } } else { /* * Create strictly lower-triangular matrix, * copy lower triangle of input. */ sparsecreatesksbuf(n, n, &a->didx, &buf->d, c, _state); for(i=0; i<=n-1; i++) { t0 = a->ridx.ptr.p_int[i]; t1 = a->ridx.ptr.p_int[i]+a->didx.ptr.p_int[i]; k = c->ridx.ptr.p_int[i]; for(j=t0; j<=t1; j++) { c->vals.ptr.p_double[k] = a->vals.ptr.p_double[j]; k = k+1; } } } } else { /* * Non-identity permutations OR non-skyline input: * * investigate profile of permuted A * * create skyline matrix in output buffer * * copy input with permutation */ ivectorsetlengthatleast(&buf->d, n, _state); ivectorsetlengthatleast(&buf->u, n, _state); for(i=0; i<=n-1; i++) { buf->d.ptr.p_int[i] = 0; buf->u.ptr.p_int[i] = 0; } t0 = 0; t1 = 0; while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) { if( (isupper&&j>=i)||(!isupper&&j<=i) ) { i = p1->ptr.p_int[i]; j = p1->ptr.p_int[j]; if( (ji&&!isupper) ) { swapi(&i, &j, _state); } if( i>j ) { buf->d.ptr.p_int[i] = ae_maxint(buf->d.ptr.p_int[i], i-j, _state); } else { buf->u.ptr.p_int[j] = ae_maxint(buf->u.ptr.p_int[j], j-i, _state); } } } sparsecreatesksbuf(n, n, &buf->d, &buf->u, c, _state); t0 = 0; t1 = 0; while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) { if( (isupper&&j>=i)||(!isupper&&j<=i) ) { i = p1->ptr.p_int[i]; j = p1->ptr.p_int[j]; if( (ji&&!isupper) ) { swapi(&j, &i, _state); } sparserewriteexisting(c, i, j, v, _state); } } } result = sparsecholeskyskyline(c, n, isupper, _state); ae_frame_leave(_state); return result; } ae_assert(ae_false, "SparseCholeskyX: internal error - unexpected algorithm", _state); ae_frame_leave(_state); return result; } void rmatrixlup(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_int_t j; double mx; double v; ae_frame_make(_state, &_frame_block); ae_vector_clear(pivots); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * Internal LU decomposition subroutine. * Never call it directly. */ ae_assert(m>0, "RMatrixLUP: incorrect M!", _state); ae_assert(n>0, "RMatrixLUP: incorrect N!", _state); /* * Scale matrix to avoid overflows, * decompose it, then scale back. */ mx = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); } } if( ae_fp_neq(mx,(double)(0)) ) { v = 1/mx; for(i=0; i<=m-1; i++) { ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } } ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); trfac_rmatrixluprec(a, 0, m, n, pivots, &tmp, _state); if( ae_fp_neq(mx,(double)(0)) ) { v = mx; for(i=0; i<=m-1; i++) { ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); } } ae_frame_leave(_state); } void cmatrixlup(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_int_t j; double mx; double v; ae_frame_make(_state, &_frame_block); ae_vector_clear(pivots); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); /* * Internal LU decomposition subroutine. * Never call it directly. */ ae_assert(m>0, "CMatrixLUP: incorrect M!", _state); ae_assert(n>0, "CMatrixLUP: incorrect N!", _state); /* * Scale matrix to avoid overflows, * decompose it, then scale back. */ mx = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); } } if( ae_fp_neq(mx,(double)(0)) ) { v = 1/mx; for(i=0; i<=m-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); } } ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); trfac_cmatrixluprec(a, 0, m, n, pivots, &tmp, _state); if( ae_fp_neq(mx,(double)(0)) ) { v = mx; for(i=0; i<=m-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); } } ae_frame_leave(_state); } void rmatrixplu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_int_t j; double mx; double v; ae_frame_make(_state, &_frame_block); ae_vector_clear(pivots); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * Internal LU decomposition subroutine. * Never call it directly. */ ae_assert(m>0, "RMatrixPLU: incorrect M!", _state); ae_assert(n>0, "RMatrixPLU: incorrect N!", _state); ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); /* * Scale matrix to avoid overflows, * decompose it, then scale back. */ mx = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); } } if( ae_fp_neq(mx,(double)(0)) ) { v = 1/mx; for(i=0; i<=m-1; i++) { ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } } trfac_rmatrixplurec(a, 0, m, n, pivots, &tmp, _state); if( ae_fp_neq(mx,(double)(0)) ) { v = mx; for(i=0; i<=ae_minint(m, n, _state)-1; i++) { ae_v_muld(&a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); } } ae_frame_leave(_state); } void cmatrixplu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_int_t j; double mx; ae_complex v; ae_frame_make(_state, &_frame_block); ae_vector_clear(pivots); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); /* * Internal LU decomposition subroutine. * Never call it directly. */ ae_assert(m>0, "CMatrixPLU: incorrect M!", _state); ae_assert(n>0, "CMatrixPLU: incorrect N!", _state); ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); /* * Scale matrix to avoid overflows, * decompose it, then scale back. */ mx = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); } } if( ae_fp_neq(mx,(double)(0)) ) { v = ae_complex_from_d(1/mx); for(i=0; i<=m-1; i++) { ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); } } trfac_cmatrixplurec(a, 0, m, n, pivots, &tmp, _state); if( ae_fp_neq(mx,(double)(0)) ) { v = ae_complex_from_d(mx); for(i=0; i<=ae_minint(m, n, _state)-1; i++) { ae_v_cmulc(&a->ptr.pp_complex[i][i], 1, ae_v_len(i,n-1), v); } } ae_frame_leave(_state); } /************************************************************************* Recursive computational subroutine for SPDMatrixCholesky. INPUT PARAMETERS: A - matrix given by upper or lower triangle Offs - offset of diagonal block to decompose N - diagonal block size IsUpper - what half is given Tmp - temporary array; allocated by function, if its size is too small; can be reused on subsequent calls. OUTPUT PARAMETERS: A - upper (or lower) triangle contains Cholesky decomposition RESULT: True, on success False, on failure -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t n1; ae_int_t n2; ae_bool result; /* * check N */ if( n<1 ) { result = ae_false; return result; } /* * Prepare buffer */ if( tmp->cnt<2*n ) { ae_vector_set_length(tmp, 2*n, _state); } /* * special cases * * NOTE: we do not use MKL to accelerate Cholesky basecase * because basecase cost is negligible when compared to * the cost of entire decomposition (most time is spent * in GEMM snd SYRK). */ if( n==1 ) { if( ae_fp_greater(a->ptr.pp_double[offs][offs],(double)(0)) ) { a->ptr.pp_double[offs][offs] = ae_sqrt(a->ptr.pp_double[offs][offs], _state); result = ae_true; } else { result = ae_false; } return result; } if( n<=ablasblocksize(a, _state) ) { result = trfac_spdmatrixcholesky2(a, offs, n, isupper, tmp, _state); return result; } /* * general case: split task in cache-oblivious manner */ result = ae_true; ablassplitlength(a, n, &n1, &n2, _state); result = spdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); if( !result ) { return result; } if( n2>0 ) { if( isupper ) { rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 1, a, offs, offs+n1, _state); rmatrixsyrk(n2, n1, -1.0, a, offs, offs+n1, 1, 1.0, a, offs+n1, offs+n1, isupper, _state); } else { rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 1, a, offs+n1, offs, _state); rmatrixsyrk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); } result = spdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); if( !result ) { return result; } } return result; } /************************************************************************* Recurrent complex LU subroutine. Never call it directly. -- ALGLIB routine -- 04.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_cmatrixluprec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t m1; ae_int_t m2; /* * Kernel case */ if( ae_minint(m, n, _state)<=ablascomplexblocksize(a, _state) ) { trfac_cmatrixlup2(a, offs, m, n, pivots, tmp, _state); return; } /* * Preliminary step, make N>=M * * ( A1 ) * A = ( ), where A1 is square * ( A2 ) * * Factorize A1, update A2 */ if( m>n ) { trfac_cmatrixluprec(a, offs, n, n, pivots, tmp, _state); for(i=0; i<=n-1; i++) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n][offs+i], a->stride, "N", ae_v_len(0,m-n-1)); ae_v_cmove(&a->ptr.pp_complex[offs+n][offs+i], a->stride, &a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+n,offs+m-1)); ae_v_cmove(&a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n,offs+m-1)); } cmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); return; } /* * Non-kernel case */ ablascomplexsplitlength(a, m, &m1, &m2, _state); trfac_cmatrixluprec(a, offs, m1, n, pivots, tmp, _state); if( m2>0 ) { for(i=0; i<=m1-1; i++) { if( offs+i!=pivots->ptr.p_int[offs+i] ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+m1][offs+i], a->stride, "N", ae_v_len(0,m2-1)); ae_v_cmove(&a->ptr.pp_complex[offs+m1][offs+i], a->stride, &a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+m1,offs+m-1)); ae_v_cmove(&a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m1,offs+m-1)); } } cmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); cmatrixgemm(m-m1, n-m1, m1, ae_complex_from_d(-1.0), a, offs+m1, offs, 0, a, offs, offs+m1, 0, ae_complex_from_d(1.0), a, offs+m1, offs+m1, _state); trfac_cmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); for(i=0; i<=m2-1; i++) { if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+m1+i], a->stride, "N", ae_v_len(0,m1-1)); ae_v_cmove(&a->ptr.pp_complex[offs][offs+m1+i], a->stride, &a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, "N", ae_v_len(offs,offs+m1-1)); ae_v_cmove(&a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m1-1)); } } } } /************************************************************************* Recurrent real LU subroutine. Never call it directly. -- ALGLIB routine -- 04.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_rmatrixluprec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t m1; ae_int_t m2; /* * Kernel case */ if( ae_minint(m, n, _state)<=ablasblocksize(a, _state) ) { trfac_rmatrixlup2(a, offs, m, n, pivots, tmp, _state); return; } /* * Preliminary step, make N>=M * * ( A1 ) * A = ( ), where A1 is square * ( A2 ) * * Factorize A1, update A2 */ if( m>n ) { trfac_rmatrixluprec(a, offs, n, n, pivots, tmp, _state); for(i=0; i<=n-1; i++) { if( offs+i!=pivots->ptr.p_int[offs+i] ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n][offs+i], a->stride, ae_v_len(0,m-n-1)); ae_v_move(&a->ptr.pp_double[offs+n][offs+i], a->stride, &a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+n,offs+m-1)); ae_v_move(&a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n,offs+m-1)); } } rmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); return; } /* * Non-kernel case */ ablassplitlength(a, m, &m1, &m2, _state); trfac_rmatrixluprec(a, offs, m1, n, pivots, tmp, _state); if( m2>0 ) { for(i=0; i<=m1-1; i++) { if( offs+i!=pivots->ptr.p_int[offs+i] ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+m1][offs+i], a->stride, ae_v_len(0,m2-1)); ae_v_move(&a->ptr.pp_double[offs+m1][offs+i], a->stride, &a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+m1,offs+m-1)); ae_v_move(&a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m1,offs+m-1)); } } rmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); rmatrixgemm(m-m1, n-m1, m1, -1.0, a, offs+m1, offs, 0, a, offs, offs+m1, 0, 1.0, a, offs+m1, offs+m1, _state); trfac_rmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); for(i=0; i<=m2-1; i++) { if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+m1+i], a->stride, ae_v_len(0,m1-1)); ae_v_move(&a->ptr.pp_double[offs][offs+m1+i], a->stride, &a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, ae_v_len(offs,offs+m1-1)); ae_v_move(&a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m1-1)); } } } } /************************************************************************* Recurrent complex LU subroutine. Never call it directly. -- ALGLIB routine -- 04.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_cmatrixplurec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t n1; ae_int_t n2; /* * Kernel case */ if( ae_minint(m, n, _state)<=ablascomplexblocksize(a, _state) ) { trfac_cmatrixplu2(a, offs, m, n, pivots, tmp, _state); return; } /* * Preliminary step, make M>=N. * * A = (A1 A2), where A1 is square * Factorize A1, update A2 */ if( n>m ) { trfac_cmatrixplurec(a, offs, m, m, pivots, tmp, _state); for(i=0; i<=m-1; i++) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+m], 1, "N", ae_v_len(0,n-m-1)); ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+m], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, "N", ae_v_len(offs+m,offs+n-1)); ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m,offs+n-1)); } cmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); return; } /* * Non-kernel case */ ablascomplexsplitlength(a, n, &n1, &n2, _state); trfac_cmatrixplurec(a, offs, m, n1, pivots, tmp, _state); if( n2>0 ) { for(i=0; i<=n1-1; i++) { if( offs+i!=pivots->ptr.p_int[offs+i] ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+n1], 1, "N", ae_v_len(0,n2-1)); ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+n1], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, "N", ae_v_len(offs+n1,offs+n-1)); ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n1,offs+n-1)); } } cmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); cmatrixgemm(m-n1, n-n1, n1, ae_complex_from_d(-1.0), a, offs+n1, offs, 0, a, offs, offs+n1, 0, ae_complex_from_d(1.0), a, offs+n1, offs+n1, _state); trfac_cmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); for(i=0; i<=n2-1; i++) { if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n1+i][offs], 1, "N", ae_v_len(0,n1-1)); ae_v_cmove(&a->ptr.pp_complex[offs+n1+i][offs], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, "N", ae_v_len(offs,offs+n1-1)); ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+n1-1)); } } } } /************************************************************************* Recurrent real LU subroutine. Never call it directly. -- ALGLIB routine -- 04.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_rmatrixplurec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t n1; ae_int_t n2; /* * Basecases */ if( rmatrixplumkl(a, offs, m, n, pivots, _state) ) { return; } if( ae_minint(m, n, _state)<=ablasblocksize(a, _state) ) { trfac_rmatrixplu2(a, offs, m, n, pivots, tmp, _state); return; } /* * Preliminary step, make M>=N. * * A = (A1 A2), where A1 is square * Factorize A1, update A2 */ if( n>m ) { trfac_rmatrixplurec(a, offs, m, m, pivots, tmp, _state); for(i=0; i<=m-1; i++) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+m], 1, ae_v_len(0,n-m-1)); ae_v_move(&a->ptr.pp_double[offs+i][offs+m], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, ae_v_len(offs+m,offs+n-1)); ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m,offs+n-1)); } rmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); return; } /* * Non-kernel case */ ablassplitlength(a, n, &n1, &n2, _state); trfac_rmatrixplurec(a, offs, m, n1, pivots, tmp, _state); if( n2>0 ) { for(i=0; i<=n1-1; i++) { if( offs+i!=pivots->ptr.p_int[offs+i] ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(0,n2-1)); ae_v_move(&a->ptr.pp_double[offs+i][offs+n1], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, ae_v_len(offs+n1,offs+n-1)); ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n1,offs+n-1)); } } rmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); rmatrixgemm(m-n1, n-n1, n1, -1.0, a, offs+n1, offs, 0, a, offs, offs+n1, 0, 1.0, a, offs+n1, offs+n1, _state); trfac_rmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); for(i=0; i<=n2-1; i++) { if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(0,n1-1)); ae_v_move(&a->ptr.pp_double[offs+n1+i][offs], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, ae_v_len(offs,offs+n1-1)); ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+n1-1)); } } } } /************************************************************************* Complex LUP kernel -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_cmatrixlup2(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t jp; ae_complex s; /* * Quick return if possible */ if( m==0||n==0 ) { return; } /* * main cycle */ for(j=0; j<=ae_minint(m-1, n-1, _state); j++) { /* * Find pivot, swap columns */ jp = j; for(i=j+1; i<=n-1; i++) { if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+j][offs+i], _state),ae_c_abs(a->ptr.pp_complex[offs+j][offs+jp], _state)) ) { jp = i; } } pivots->ptr.p_int[offs+j] = offs+jp; if( jp!=j ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+j], a->stride, "N", ae_v_len(0,m-1)); ae_v_cmove(&a->ptr.pp_complex[offs][offs+j], a->stride, &a->ptr.pp_complex[offs][offs+jp], a->stride, "N", ae_v_len(offs,offs+m-1)); ae_v_cmove(&a->ptr.pp_complex[offs][offs+jp], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m-1)); } /* * LU decomposition of 1x(N-J) matrix */ if( ae_c_neq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0))&&j+1<=n-1 ) { s = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); ae_v_cmulc(&a->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); } /* * Update trailing (M-J-1)x(N-J-1) matrix */ if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); } } } /************************************************************************* Real LUP kernel -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ static void trfac_rmatrixlup2(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t jp; double s; /* * Quick return if possible */ if( m==0||n==0 ) { return; } /* * main cycle */ for(j=0; j<=ae_minint(m-1, n-1, _state); j++) { /* * Find pivot, swap columns */ jp = j; for(i=j+1; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+j][offs+i], _state),ae_fabs(a->ptr.pp_double[offs+j][offs+jp], _state)) ) { jp = i; } } pivots->ptr.p_int[offs+j] = offs+jp; if( jp!=j ) { ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+j], a->stride, ae_v_len(0,m-1)); ae_v_move(&a->ptr.pp_double[offs][offs+j], a->stride, &a->ptr.pp_double[offs][offs+jp], a->stride, ae_v_len(offs,offs+m-1)); ae_v_move(&a->ptr.pp_double[offs][offs+jp], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m-1)); } /* * LU decomposition of 1x(N-J) matrix */ if( ae_fp_neq(a->ptr.pp_double[offs+j][offs+j],(double)(0))&&j+1<=n-1 ) { s = 1/a->ptr.pp_double[offs+j][offs+j]; ae_v_muld(&a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); } /* * Update trailing (M-J-1)x(N-J-1) matrix */ if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); } } } /************************************************************************* Complex PLU kernel -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1992 *************************************************************************/ static void trfac_cmatrixplu2(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t jp; ae_complex s; /* * Quick return if possible */ if( m==0||n==0 ) { return; } for(j=0; j<=ae_minint(m-1, n-1, _state); j++) { /* * Find pivot and test for singularity. */ jp = j; for(i=j+1; i<=m-1; i++) { if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+i][offs+j], _state),ae_c_abs(a->ptr.pp_complex[offs+jp][offs+j], _state)) ) { jp = i; } } pivots->ptr.p_int[offs+j] = offs+jp; if( ae_c_neq_d(a->ptr.pp_complex[offs+jp][offs+j],(double)(0)) ) { /* *Apply the interchange to rows */ if( jp!=j ) { for(i=0; i<=n-1; i++) { s = a->ptr.pp_complex[offs+j][offs+i]; a->ptr.pp_complex[offs+j][offs+i] = a->ptr.pp_complex[offs+jp][offs+i]; a->ptr.pp_complex[offs+jp][offs+i] = s; } } /* *Compute elements J+1:M of J-th column. */ if( j+1<=m-1 ) { s = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); } } if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); } } } /************************************************************************* Real PLU kernel -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1992 *************************************************************************/ static void trfac_rmatrixplu2(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t jp; double s; /* * Quick return if possible */ if( m==0||n==0 ) { return; } for(j=0; j<=ae_minint(m-1, n-1, _state); j++) { /* * Find pivot and test for singularity. */ jp = j; for(i=j+1; i<=m-1; i++) { if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+i][offs+j], _state),ae_fabs(a->ptr.pp_double[offs+jp][offs+j], _state)) ) { jp = i; } } pivots->ptr.p_int[offs+j] = offs+jp; if( ae_fp_neq(a->ptr.pp_double[offs+jp][offs+j],(double)(0)) ) { /* *Apply the interchange to rows */ if( jp!=j ) { for(i=0; i<=n-1; i++) { s = a->ptr.pp_double[offs+j][offs+i]; a->ptr.pp_double[offs+j][offs+i] = a->ptr.pp_double[offs+jp][offs+i]; a->ptr.pp_double[offs+jp][offs+i] = s; } } /* *Compute elements J+1:M of J-th column. */ if( j+1<=m-1 ) { s = 1/a->ptr.pp_double[offs+j][offs+j]; ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); } } if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); } } } /************************************************************************* Recursive computational subroutine for HPDMatrixCholesky -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t n1; ae_int_t n2; ae_bool result; /* * check N */ if( n<1 ) { result = ae_false; return result; } /* * Prepare buffer */ if( tmp->cnt<2*n ) { ae_vector_set_length(tmp, 2*n, _state); } /* * special cases * * NOTE: we do not use MKL for basecases because their price is only * minor part of overall running time for N>256. */ if( n==1 ) { if( ae_fp_greater(a->ptr.pp_complex[offs][offs].x,(double)(0)) ) { a->ptr.pp_complex[offs][offs] = ae_complex_from_d(ae_sqrt(a->ptr.pp_complex[offs][offs].x, _state)); result = ae_true; } else { result = ae_false; } return result; } if( n<=ablascomplexblocksize(a, _state) ) { result = trfac_hpdmatrixcholesky2(a, offs, n, isupper, tmp, _state); return result; } /* * general case: split task in cache-oblivious manner */ result = ae_true; ablascomplexsplitlength(a, n, &n1, &n2, _state); result = trfac_hpdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); if( !result ) { return result; } if( n2>0 ) { if( isupper ) { cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 2, a, offs, offs+n1, _state); cmatrixherk(n2, n1, -1.0, a, offs, offs+n1, 2, 1.0, a, offs+n1, offs+n1, isupper, _state); } else { cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 2, a, offs+n1, offs, _state); cmatrixherk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); } result = trfac_hpdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); if( !result ) { return result; } } return result; } /************************************************************************* Level-2 Hermitian Cholesky subroutine. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; double ajj; ae_complex v; double r; ae_bool result; result = ae_true; if( n<0 ) { result = ae_false; return result; } /* * Quick return if possible */ if( n==0 ) { return result; } if( isupper ) { /* * Compute the Cholesky factorization A = U'*U. */ for(j=0; j<=n-1; j++) { /* * Compute U(J,J) and test for non-positive-definiteness. */ v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "N", ae_v_len(offs,offs+j-1)); ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; if( ae_fp_less_eq(ajj,(double)(0)) ) { aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); result = ae_false; return result; } ajj = ae_sqrt(ajj, _state); aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); /* * Compute elements J+1:N-1 of row J. */ if( j0 ) { ae_v_cmoveneg(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", ae_v_len(0,j-1)); cmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); ae_v_cadd(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, &tmp->ptr.p_complex[n], 1, "N", ae_v_len(offs+j+1,offs+n-1)); } r = 1/ajj; ae_v_cmuld(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); } } } else { /* * Compute the Cholesky factorization A = L*L'. */ for(j=0; j<=n-1; j++) { /* * Compute L(J+1,J+1) and test for non-positive-definiteness. */ v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", &aaa->ptr.pp_complex[offs+j][offs], 1, "N", ae_v_len(offs,offs+j-1)); ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; if( ae_fp_less_eq(ajj,(double)(0)) ) { aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); result = ae_false; return result; } ajj = ae_sqrt(ajj, _state); aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); /* * Compute elements J+1:N of column J. */ if( j0 ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", ae_v_len(0,j-1)); cmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); for(i=0; i<=n-j-2; i++) { aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_div_d(ae_c_sub(aaa->ptr.pp_complex[offs+j+1+i][offs+j],tmp->ptr.p_complex[n+i]),ajj); } } else { for(i=0; i<=n-j-2; i++) { aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_div_d(aaa->ptr.pp_complex[offs+j+1+i][offs+j],ajj); } } } } } return result; } /************************************************************************* Level-2 Cholesky subroutine -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; double ajj; double v; double r; ae_bool result; result = ae_true; if( n<0 ) { result = ae_false; return result; } /* * Quick return if possible */ if( n==0 ) { return result; } if( isupper ) { /* * Compute the Cholesky factorization A = U'*U. */ for(j=0; j<=n-1; j++) { /* * Compute U(J,J) and test for non-positive-definiteness. */ v = ae_v_dotproduct(&aaa->ptr.pp_double[offs][offs+j], aaa->stride, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(offs,offs+j-1)); ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; if( ae_fp_less_eq(ajj,(double)(0)) ) { aaa->ptr.pp_double[offs+j][offs+j] = ajj; result = ae_false; return result; } ajj = ae_sqrt(ajj, _state); aaa->ptr.pp_double[offs+j][offs+j] = ajj; /* * Compute elements J+1:N-1 of row J. */ if( j0 ) { ae_v_moveneg(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(0,j-1)); rmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); ae_v_add(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, &tmp->ptr.p_double[n], 1, ae_v_len(offs+j+1,offs+n-1)); } r = 1/ajj; ae_v_muld(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); } } } else { /* * Compute the Cholesky factorization A = L*L'. */ for(j=0; j<=n-1; j++) { /* * Compute L(J+1,J+1) and test for non-positive-definiteness. */ v = ae_v_dotproduct(&aaa->ptr.pp_double[offs+j][offs], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(offs,offs+j-1)); ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; if( ae_fp_less_eq(ajj,(double)(0)) ) { aaa->ptr.pp_double[offs+j][offs+j] = ajj; result = ae_false; return result; } ajj = ae_sqrt(ajj, _state); aaa->ptr.pp_double[offs+j][offs+j] = ajj; /* * Compute elements J+1:N of column J. */ if( j0 ) { ae_v_move(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(0,j-1)); rmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); for(i=0; i<=n-j-2; i++) { aaa->ptr.pp_double[offs+j+1+i][offs+j] = (aaa->ptr.pp_double[offs+j+1+i][offs+j]-tmp->ptr.p_double[n+i])/ajj; } } else { for(i=0; i<=n-j-2; i++) { aaa->ptr.pp_double[offs+j+1+i][offs+j] = aaa->ptr.pp_double[offs+j+1+i][offs+j]/ajj; } } } } } return result; } /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcond1(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_vector t; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=1, "RMatrixRCond1: N<1!", _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } rmatrixlu(a, n, n, &pivots, _state); rcond_rmatrixrcondluinternal(a, n, ae_true, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcondinf(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "RMatrixRCondInf: N<1!", _state); nrm = (double)(0); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+ae_fabs(a->ptr.pp_double[i][j], _state); } nrm = ae_maxreal(nrm, v, _state); } rmatrixlu(a, n, n, &pivots, _state); rcond_rmatrixrcondluinternal(a, n, ae_false, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Condition number estimate of a symmetric positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - symmetric positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixrcond(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; double v; double nrm; ae_vector t; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( i==j ) { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][i], _state); } else { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][j], _state); t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); } } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } if( spdmatrixcholesky(a, n, isupper, _state) ) { rcond_spdmatrixrcondcholeskyinternal(a, n, isupper, ae_true, nrm, &v, _state); result = v; } else { result = (double)(-1); } ae_frame_leave(_state); return result; } /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcond1(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_vector t; ae_int_t j1; ae_int_t j2; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } for(j=j1; j<=j2; j++) { t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); } if( isunit ) { t.ptr.p_double[i] = t.ptr.p_double[i]+1; } else { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][i], _state); } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcondinf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_int_t j1; ae_int_t j2; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); nrm = (double)(0); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } v = (double)(0); for(j=j1; j<=j2; j++) { v = v+ae_fabs(a->ptr.pp_double[i][j], _state); } if( isunit ) { v = v+1; } else { v = v+ae_fabs(a->ptr.pp_double[i][i], _state); } nrm = ae_maxreal(nrm, v, _state); } rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Condition number estimate of a Hermitian positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - Hermitian positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixrcond(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; double v; double nrm; ae_vector t; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( i==j ) { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][i], _state); } else { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][j], _state); t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); } } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } if( hpdmatrixcholesky(a, n, isupper, _state) ) { rcond_hpdmatrixrcondcholeskyinternal(a, n, isupper, ae_true, nrm, &v, _state); result = v; } else { result = (double)(-1); } ae_frame_leave(_state); return result; } /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcond1(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_vector t; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=1, "CMatrixRCond1: N<1!", _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } cmatrixlu(a, n, n, &pivots, _state); rcond_cmatrixrcondluinternal(a, n, ae_true, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcondinf(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "CMatrixRCondInf: N<1!", _state); nrm = (double)(0); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+ae_c_abs(a->ptr.pp_complex[i][j], _state); } nrm = ae_maxreal(nrm, v, _state); } cmatrixlu(a, n, n, &pivots, _state); rcond_cmatrixrcondluinternal(a, n, ae_false, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcond1(/* Real */ ae_matrix* lua, ae_int_t n, ae_state *_state) { double v; double result; rcond_rmatrixrcondluinternal(lua, n, ae_true, ae_false, (double)(0), &v, _state); result = v; return result; } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcondinf(/* Real */ ae_matrix* lua, ae_int_t n, ae_state *_state) { double v; double result; rcond_rmatrixrcondluinternal(lua, n, ae_false, ae_false, (double)(0), &v, _state); result = v; return result; } /************************************************************************* Condition number estimate of a symmetric positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixcholeskyrcond(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { double v; double result; rcond_spdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, (double)(0), &v, _state); result = v; return result; } /************************************************************************* Condition number estimate of a Hermitian positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixcholeskyrcond(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { double v; double result; rcond_hpdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, (double)(0), &v, _state); result = v; return result; } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcond1(/* Complex */ ae_matrix* lua, ae_int_t n, ae_state *_state) { double v; double result; ae_assert(n>=1, "CMatrixLURCond1: N<1!", _state); rcond_cmatrixrcondluinternal(lua, n, ae_true, ae_false, 0.0, &v, _state); result = v; return result; } /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcondinf(/* Complex */ ae_matrix* lua, ae_int_t n, ae_state *_state) { double v; double result; ae_assert(n>=1, "CMatrixLURCondInf: N<1!", _state); rcond_cmatrixrcondluinternal(lua, n, ae_false, ae_false, 0.0, &v, _state); result = v; return result; } /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcond1(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_vector t; ae_int_t j1; ae_int_t j2; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); ae_vector_set_length(&t, n, _state); for(i=0; i<=n-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } for(j=j1; j<=j2; j++) { t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); } if( isunit ) { t.ptr.p_double[i] = t.ptr.p_double[i]+1; } else { t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][i], _state); } } nrm = (double)(0); for(i=0; i<=n-1; i++) { nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); } rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcondinf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double nrm; ae_vector pivots; ae_int_t j1; ae_int_t j2; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); nrm = (double)(0); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } v = (double)(0); for(j=j1; j<=j2; j++) { v = v+ae_c_abs(a->ptr.pp_complex[i][j], _state); } if( isunit ) { v = v+1; } else { v = v+ae_c_abs(a->ptr.pp_complex[i][i], _state); } nrm = ae_maxreal(nrm, v, _state); } rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); result = v; ae_frame_leave(_state); return result; } /************************************************************************* Threshold for rcond: matrices with condition number beyond this threshold are considered singular. Threshold must be far enough from underflow, at least Sqr(Threshold) must be greater than underflow. *************************************************************************/ double rcondthreshold(ae_state *_state) { double result; result = ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state); return result; } /************************************************************************* Internal subroutine for condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static void rcond_rmatrixrcondtrinternal(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_bool onenorm, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_vector ex; ae_vector ev; ae_vector iwork; ae_vector tmp; ae_int_t i; ae_int_t j; ae_int_t kase; ae_int_t kase1; ae_int_t j1; ae_int_t j2; double ainvnm; double maxgrowth; double s; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&ex, 0, DT_REAL, _state); ae_vector_init(&ev, 0, DT_REAL, _state); ae_vector_init(&iwork, 0, DT_INT, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * RC=0 if something happens */ *rc = (double)(0); /* * init */ if( onenorm ) { kase1 = 1; } else { kase1 = 2; } ae_vector_set_length(&iwork, n+1, _state); ae_vector_set_length(&tmp, n, _state); /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); s = (double)(0); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } for(j=j1; j<=j2; j++) { s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][j], _state), _state); } if( isunit ) { s = ae_maxreal(s, (double)(1), _state); } else { s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][i], _state), _state); } } if( ae_fp_eq(s,(double)(0)) ) { s = (double)(1); } s = 1/s; /* * Scale according to S */ anorm = anorm*s; /* * Quick return if possible * We assume that ANORM<>0 after this block */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } if( n==1 ) { *rc = (double)(1); ae_frame_leave(_state); return; } /* * Estimate the norm of inv(A). */ ainvnm = (double)(0); kase = 0; for(;;) { rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); if( kase==0 ) { break; } /* * from 1-based array to 0-based */ for(i=0; i<=n-1; i++) { ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; } /* * multiply by inv(A) or inv(A') */ if( kase==kase1 ) { /* * multiply by inv(A) */ if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } else { /* * multiply by inv(A') */ if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 1, isunit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } /* * from 0-based array to 1-based */ for(i=n-1; i>=0; i--) { ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { *rc = 1/ainvnm; *rc = *rc/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University March 31, 1993 *************************************************************************/ static void rcond_cmatrixrcondtrinternal(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_bool onenorm, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_vector ex; ae_vector cwork2; ae_vector cwork3; ae_vector cwork4; ae_vector isave; ae_vector rsave; ae_int_t kase; ae_int_t kase1; double ainvnm; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; double s; double maxgrowth; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&ex, 0, DT_COMPLEX, _state); ae_vector_init(&cwork2, 0, DT_COMPLEX, _state); ae_vector_init(&cwork3, 0, DT_COMPLEX, _state); ae_vector_init(&cwork4, 0, DT_COMPLEX, _state); ae_vector_init(&isave, 0, DT_INT, _state); ae_vector_init(&rsave, 0, DT_REAL, _state); /* * RC=0 if something happens */ *rc = (double)(0); /* * init */ if( n<=0 ) { ae_frame_leave(_state); return; } if( n==0 ) { *rc = (double)(1); ae_frame_leave(_state); return; } ae_vector_set_length(&cwork2, n+1, _state); /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); s = (double)(0); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i+1; j2 = n-1; } else { j1 = 0; j2 = i-1; } for(j=j1; j<=j2; j++) { s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); } if( isunit ) { s = ae_maxreal(s, (double)(1), _state); } else { s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][i], _state), _state); } } if( ae_fp_eq(s,(double)(0)) ) { s = (double)(1); } s = 1/s; /* * Scale according to S */ anorm = anorm*s; /* * Quick return if possible */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } /* * Estimate the norm of inv(A). */ ainvnm = (double)(0); if( onenorm ) { kase1 = 1; } else { kase1 = 2; } kase = 0; for(;;) { rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); if( kase==0 ) { break; } /* * From 1-based to 0-based */ for(i=0; i<=n-1; i++) { ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; } /* * multiply by inv(A) or inv(A') */ if( kase==kase1 ) { /* * multiply by inv(A) */ if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } else { /* * multiply by inv(A') */ if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 2, isunit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } /* * from 0-based to 1-based */ for(i=n-1; i>=0; i--) { ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { *rc = 1/ainvnm; *rc = *rc/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine for condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, ae_bool isnormprovided, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t kase; double ainvnm; ae_vector ex; ae_vector ev; ae_vector tmp; ae_vector iwork; double sa; double v; double maxgrowth; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&ex, 0, DT_REAL, _state); ae_vector_init(&ev, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&iwork, 0, DT_INT, _state); ae_assert(n>=1, "Assertion failed", _state); ae_vector_set_length(&tmp, n, _state); /* * RC=0 if something happens */ *rc = (double)(0); /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); sa = (double)(0); if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); } } } if( ae_fp_eq(sa,(double)(0)) ) { sa = (double)(1); } sa = 1/sa; /* * Estimate the norm of A. */ if( !isnormprovided ) { kase = 0; anorm = (double)(0); for(;;) { rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); if( kase==0 ) { break; } if( isupper ) { /* * Multiply by U */ for(i=1; i<=n; i++) { v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); ex.ptr.p_double[i] = v; } ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); /* * Multiply by U' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_double[i+1]; ae_v_addd(&tmp.ptr.p_double[i], 1, &cha->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); } ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); } else { /* * Multiply by L' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_double[i+1]; ae_v_addd(&tmp.ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i), v); } ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); /* * Multiply by L */ for(i=n; i>=1; i--) { v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-1)); ex.ptr.p_double[i] = v; } ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); } } } /* * Quick return if possible */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } if( n==1 ) { *rc = (double)(1); ae_frame_leave(_state); return; } /* * Estimate the 1-norm of inv(A). */ kase = 0; for(;;) { rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); if( kase==0 ) { break; } for(i=0; i<=n-1; i++) { ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; } if( isupper ) { /* * Multiply by inv(U'). */ if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(U). */ if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } else { /* * Multiply by inv(L). */ if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(L'). */ if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } for(i=n-1; i>=0; i--) { ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { v = 1/ainvnm; *rc = v/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine for condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, ae_bool isnormprovided, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_vector isave; ae_vector rsave; ae_vector ex; ae_vector ev; ae_vector tmp; ae_int_t kase; double ainvnm; ae_complex v; ae_int_t i; ae_int_t j; double sa; double maxgrowth; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&isave, 0, DT_INT, _state); ae_vector_init(&rsave, 0, DT_REAL, _state); ae_vector_init(&ex, 0, DT_COMPLEX, _state); ae_vector_init(&ev, 0, DT_COMPLEX, _state); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); ae_assert(n>=1, "Assertion failed", _state); ae_vector_set_length(&tmp, n, _state); /* * RC=0 if something happens */ *rc = (double)(0); /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); sa = (double)(0); if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); } } } if( ae_fp_eq(sa,(double)(0)) ) { sa = (double)(1); } sa = 1/sa; /* * Estimate the norm of A */ if( !isnormprovided ) { anorm = (double)(0); kase = 0; for(;;) { rcond_cmatrixestimatenorm(n, &ev, &ex, &anorm, &kase, &isave, &rsave, _state); if( kase==0 ) { break; } if( isupper ) { /* * Multiply by U */ for(i=1; i<=n; i++) { v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); ex.ptr.p_complex[i] = v; } ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); /* * Multiply by U' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_complex[i] = ae_complex_from_i(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_complex[i+1]; ae_v_caddc(&tmp.ptr.p_complex[i], 1, &cha->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(i,n-1), v); } ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); } else { /* * Multiply by L' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_complex[i] = ae_complex_from_i(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_complex[i+1]; ae_v_caddc(&tmp.ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i), v); } ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); /* * Multiply by L */ for(i=n; i>=1; i--) { v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-1)); ex.ptr.p_complex[i] = v; } ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); } } } /* * Quick return if possible * After this block we assume that ANORM<>0 */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } if( n==1 ) { *rc = (double)(1); ae_frame_leave(_state); return; } /* * Estimate the norm of inv(A). */ ainvnm = (double)(0); kase = 0; for(;;) { rcond_cmatrixestimatenorm(n, &ev, &ex, &ainvnm, &kase, &isave, &rsave, _state); if( kase==0 ) { break; } for(i=0; i<=n-1; i++) { ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; } if( isupper ) { /* * Multiply by inv(U'). */ if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(U). */ if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } else { /* * Multiply by inv(L). */ if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(L'). */ if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } for(i=n-1; i>=0; i--) { ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { *rc = 1/ainvnm; *rc = *rc/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine for condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static void rcond_rmatrixrcondluinternal(/* Real */ ae_matrix* lua, ae_int_t n, ae_bool onenorm, ae_bool isanormprovided, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_vector ex; ae_vector ev; ae_vector iwork; ae_vector tmp; double v; ae_int_t i; ae_int_t j; ae_int_t kase; ae_int_t kase1; double ainvnm; double maxgrowth; double su; double sl; ae_bool mupper; ae_bool munit; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&ex, 0, DT_REAL, _state); ae_vector_init(&ev, 0, DT_REAL, _state); ae_vector_init(&iwork, 0, DT_INT, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * RC=0 if something happens */ *rc = (double)(0); /* * init */ if( onenorm ) { kase1 = 1; } else { kase1 = 2; } mupper = ae_true; munit = ae_true; ae_vector_set_length(&iwork, n+1, _state); ae_vector_set_length(&tmp, n, _state); /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); su = (double)(0); sl = (double)(1); for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { sl = ae_maxreal(sl, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); } for(j=i; j<=n-1; j++) { su = ae_maxreal(su, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); } } if( ae_fp_eq(su,(double)(0)) ) { su = (double)(1); } su = 1/su; sl = 1/sl; /* * Estimate the norm of A. */ if( !isanormprovided ) { kase = 0; anorm = (double)(0); for(;;) { rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); if( kase==0 ) { break; } if( kase==kase1 ) { /* * Multiply by U */ for(i=1; i<=n; i++) { v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); ex.ptr.p_double[i] = v; } /* * Multiply by L */ for(i=n; i>=1; i--) { if( i>1 ) { v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-2)); } else { v = (double)(0); } ex.ptr.p_double[i] = ex.ptr.p_double[i]+v; } } else { /* * Multiply by L' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_double[i+1]; if( i>=1 ) { ae_v_addd(&tmp.ptr.p_double[0], 1, &lua->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v); } tmp.ptr.p_double[i] = tmp.ptr.p_double[i]+v; } ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); /* * Multiply by U' */ for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = ex.ptr.p_double[i+1]; ae_v_addd(&tmp.ptr.p_double[i], 1, &lua->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); } ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); } } } /* * Scale according to SU/SL */ anorm = anorm*su*sl; /* * Quick return if possible * We assume that ANORM<>0 after this block */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } if( n==1 ) { *rc = (double)(1); ae_frame_leave(_state); return; } /* * Estimate the norm of inv(A). */ ainvnm = (double)(0); kase = 0; for(;;) { rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); if( kase==0 ) { break; } /* * from 1-based array to 0-based */ for(i=0; i<=n-1; i++) { ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; } /* * multiply by inv(A) or inv(A') */ if( kase==kase1 ) { /* * Multiply by inv(L). */ if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 0, munit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(U). */ if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 0, !munit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } else { /* * Multiply by inv(U'). */ if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 1, !munit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } /* * Multiply by inv(L'). */ if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 1, munit, maxgrowth, _state) ) { ae_frame_leave(_state); return; } } /* * from 0-based array to 1-based */ for(i=n-1; i>=0; i--) { ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { *rc = 1/ainvnm; *rc = *rc/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Condition number estimation -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University March 31, 1993 *************************************************************************/ static void rcond_cmatrixrcondluinternal(/* Complex */ ae_matrix* lua, ae_int_t n, ae_bool onenorm, ae_bool isanormprovided, double anorm, double* rc, ae_state *_state) { ae_frame _frame_block; ae_vector ex; ae_vector cwork2; ae_vector cwork3; ae_vector cwork4; ae_vector isave; ae_vector rsave; ae_int_t kase; ae_int_t kase1; double ainvnm; ae_complex v; ae_int_t i; ae_int_t j; double su; double sl; double maxgrowth; ae_frame_make(_state, &_frame_block); *rc = 0; ae_vector_init(&ex, 0, DT_COMPLEX, _state); ae_vector_init(&cwork2, 0, DT_COMPLEX, _state); ae_vector_init(&cwork3, 0, DT_COMPLEX, _state); ae_vector_init(&cwork4, 0, DT_COMPLEX, _state); ae_vector_init(&isave, 0, DT_INT, _state); ae_vector_init(&rsave, 0, DT_REAL, _state); if( n<=0 ) { ae_frame_leave(_state); return; } ae_vector_set_length(&cwork2, n+1, _state); *rc = (double)(0); if( n==0 ) { *rc = (double)(1); ae_frame_leave(_state); return; } /* * prepare parameters for triangular solver */ maxgrowth = 1/rcondthreshold(_state); su = (double)(0); sl = (double)(1); for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { sl = ae_maxreal(sl, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); } for(j=i; j<=n-1; j++) { su = ae_maxreal(su, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); } } if( ae_fp_eq(su,(double)(0)) ) { su = (double)(1); } su = 1/su; sl = 1/sl; /* * Estimate the norm of SU*SL*A. */ if( !isanormprovided ) { anorm = (double)(0); if( onenorm ) { kase1 = 1; } else { kase1 = 2; } kase = 0; do { rcond_cmatrixestimatenorm(n, &cwork4, &ex, &anorm, &kase, &isave, &rsave, _state); if( kase!=0 ) { if( kase==kase1 ) { /* * Multiply by U */ for(i=1; i<=n; i++) { v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); ex.ptr.p_complex[i] = v; } /* * Multiply by L */ for(i=n; i>=1; i--) { v = ae_complex_from_i(0); if( i>1 ) { v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-2)); } ex.ptr.p_complex[i] = ae_c_add(v,ex.ptr.p_complex[i]); } } else { /* * Multiply by L' */ for(i=1; i<=n; i++) { cwork2.ptr.p_complex[i] = ae_complex_from_i(0); } for(i=1; i<=n; i++) { v = ex.ptr.p_complex[i]; if( i>1 ) { ae_v_caddc(&cwork2.ptr.p_complex[1], 1, &lua->ptr.pp_complex[i-1][0], 1, "Conj", ae_v_len(1,i-1), v); } cwork2.ptr.p_complex[i] = ae_c_add(cwork2.ptr.p_complex[i],v); } /* * Multiply by U' */ for(i=1; i<=n; i++) { ex.ptr.p_complex[i] = ae_complex_from_i(0); } for(i=1; i<=n; i++) { v = cwork2.ptr.p_complex[i]; ae_v_caddc(&ex.ptr.p_complex[i], 1, &lua->ptr.pp_complex[i-1][i-1], 1, "Conj", ae_v_len(i,n), v); } } } } while(kase!=0); } /* * Scale according to SU/SL */ anorm = anorm*su*sl; /* * Quick return if possible */ if( ae_fp_eq(anorm,(double)(0)) ) { ae_frame_leave(_state); return; } /* * Estimate the norm of inv(A). */ ainvnm = (double)(0); if( onenorm ) { kase1 = 1; } else { kase1 = 2; } kase = 0; for(;;) { rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); if( kase==0 ) { break; } /* * From 1-based to 0-based */ for(i=0; i<=n-1; i++) { ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; } /* * multiply by inv(A) or inv(A') */ if( kase==kase1 ) { /* * Multiply by inv(L). */ if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 0, ae_true, maxgrowth, _state) ) { *rc = (double)(0); ae_frame_leave(_state); return; } /* * Multiply by inv(U). */ if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 0, ae_false, maxgrowth, _state) ) { *rc = (double)(0); ae_frame_leave(_state); return; } } else { /* * Multiply by inv(U'). */ if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 2, ae_false, maxgrowth, _state) ) { *rc = (double)(0); ae_frame_leave(_state); return; } /* * Multiply by inv(L'). */ if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 2, ae_true, maxgrowth, _state) ) { *rc = (double)(0); ae_frame_leave(_state); return; } } /* * from 0-based to 1-based */ for(i=n-1; i>=0; i--) { ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; } } /* * Compute the estimate of the reciprocal condition number. */ if( ae_fp_neq(ainvnm,(double)(0)) ) { *rc = 1/ainvnm; *rc = *rc/anorm; if( ae_fp_less(*rc,rcondthreshold(_state)) ) { *rc = (double)(0); } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine for matrix norm estimation -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static void rcond_rmatrixestimatenorm(ae_int_t n, /* Real */ ae_vector* v, /* Real */ ae_vector* x, /* Integer */ ae_vector* isgn, double* est, ae_int_t* kase, ae_state *_state) { ae_int_t itmax; ae_int_t i; double t; ae_bool flg; ae_int_t positer; ae_int_t posj; ae_int_t posjlast; ae_int_t posjump; ae_int_t posaltsgn; ae_int_t posestold; ae_int_t postemp; itmax = 5; posaltsgn = n+1; posestold = n+2; postemp = n+3; positer = n+1; posj = n+2; posjlast = n+3; posjump = n+4; if( *kase==0 ) { ae_vector_set_length(v, n+4, _state); ae_vector_set_length(x, n+1, _state); ae_vector_set_length(isgn, n+5, _state); t = (double)1/(double)n; for(i=1; i<=n; i++) { x->ptr.p_double[i] = t; } *kase = 1; isgn->ptr.p_int[posjump] = 1; return; } /* * ................ ENTRY (JUMP = 1) * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. */ if( isgn->ptr.p_int[posjump]==1 ) { if( n==1 ) { v->ptr.p_double[1] = x->ptr.p_double[1]; *est = ae_fabs(v->ptr.p_double[1], _state); *kase = 0; return; } *est = (double)(0); for(i=1; i<=n; i++) { *est = *est+ae_fabs(x->ptr.p_double[i], _state); } for(i=1; i<=n; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)) ) { x->ptr.p_double[i] = (double)(1); } else { x->ptr.p_double[i] = (double)(-1); } isgn->ptr.p_int[i] = ae_sign(x->ptr.p_double[i], _state); } *kase = 2; isgn->ptr.p_int[posjump] = 2; return; } /* * ................ ENTRY (JUMP = 2) * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. */ if( isgn->ptr.p_int[posjump]==2 ) { isgn->ptr.p_int[posj] = 1; for(i=2; i<=n; i++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) { isgn->ptr.p_int[posj] = i; } } isgn->ptr.p_int[positer] = 2; /* * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. */ for(i=1; i<=n; i++) { x->ptr.p_double[i] = (double)(0); } x->ptr.p_double[isgn->ptr.p_int[posj]] = (double)(1); *kase = 1; isgn->ptr.p_int[posjump] = 3; return; } /* * ................ ENTRY (JUMP = 3) * X HAS BEEN OVERWRITTEN BY A*X. */ if( isgn->ptr.p_int[posjump]==3 ) { ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); v->ptr.p_double[posestold] = *est; *est = (double)(0); for(i=1; i<=n; i++) { *est = *est+ae_fabs(v->ptr.p_double[i], _state); } flg = ae_false; for(i=1; i<=n; i++) { if( (ae_fp_greater_eq(x->ptr.p_double[i],(double)(0))&&isgn->ptr.p_int[i]<0)||(ae_fp_less(x->ptr.p_double[i],(double)(0))&&isgn->ptr.p_int[i]>=0) ) { flg = ae_true; } } /* * REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. * OR MAY BE CYCLING. */ if( !flg||ae_fp_less_eq(*est,v->ptr.p_double[posestold]) ) { v->ptr.p_double[posaltsgn] = (double)(1); for(i=1; i<=n; i++) { x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*(1+(double)(i-1)/(double)(n-1)); v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; } *kase = 1; isgn->ptr.p_int[posjump] = 5; return; } for(i=1; i<=n; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)) ) { x->ptr.p_double[i] = (double)(1); isgn->ptr.p_int[i] = 1; } else { x->ptr.p_double[i] = (double)(-1); isgn->ptr.p_int[i] = -1; } } *kase = 2; isgn->ptr.p_int[posjump] = 4; return; } /* * ................ ENTRY (JUMP = 4) * X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. */ if( isgn->ptr.p_int[posjump]==4 ) { isgn->ptr.p_int[posjlast] = isgn->ptr.p_int[posj]; isgn->ptr.p_int[posj] = 1; for(i=2; i<=n; i++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) { isgn->ptr.p_int[posj] = i; } } if( ae_fp_neq(x->ptr.p_double[isgn->ptr.p_int[posjlast]],ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state))&&isgn->ptr.p_int[positer]ptr.p_int[positer] = isgn->ptr.p_int[positer]+1; for(i=1; i<=n; i++) { x->ptr.p_double[i] = (double)(0); } x->ptr.p_double[isgn->ptr.p_int[posj]] = (double)(1); *kase = 1; isgn->ptr.p_int[posjump] = 3; return; } /* * ITERATION COMPLETE. FINAL STAGE. */ v->ptr.p_double[posaltsgn] = (double)(1); for(i=1; i<=n; i++) { x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*(1+(double)(i-1)/(double)(n-1)); v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; } *kase = 1; isgn->ptr.p_int[posjump] = 5; return; } /* * ................ ENTRY (JUMP = 5) * X HAS BEEN OVERWRITTEN BY A*X. */ if( isgn->ptr.p_int[posjump]==5 ) { v->ptr.p_double[postemp] = (double)(0); for(i=1; i<=n; i++) { v->ptr.p_double[postemp] = v->ptr.p_double[postemp]+ae_fabs(x->ptr.p_double[i], _state); } v->ptr.p_double[postemp] = 2*v->ptr.p_double[postemp]/(3*n); if( ae_fp_greater(v->ptr.p_double[postemp],*est) ) { ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); *est = v->ptr.p_double[postemp]; } *kase = 0; return; } } static void rcond_cmatrixestimatenorm(ae_int_t n, /* Complex */ ae_vector* v, /* Complex */ ae_vector* x, double* est, ae_int_t* kase, /* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_state *_state) { ae_int_t itmax; ae_int_t i; ae_int_t iter; ae_int_t j; ae_int_t jlast; ae_int_t jump; double absxi; double altsgn; double estold; double safmin; double temp; /* *Executable Statements .. */ itmax = 5; safmin = ae_minrealnumber; if( *kase==0 ) { ae_vector_set_length(v, n+1, _state); ae_vector_set_length(x, n+1, _state); ae_vector_set_length(isave, 5, _state); ae_vector_set_length(rsave, 4, _state); for(i=1; i<=n; i++) { x->ptr.p_complex[i] = ae_complex_from_d((double)1/(double)n); } *kase = 1; jump = 1; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } rcond_internalcomplexrcondloadall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); /* * ENTRY (JUMP = 1) * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. */ if( jump==1 ) { if( n==1 ) { v->ptr.p_complex[1] = x->ptr.p_complex[1]; *est = ae_c_abs(v->ptr.p_complex[1], _state); *kase = 0; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } *est = rcond_internalcomplexrcondscsum1(x, n, _state); for(i=1; i<=n; i++) { absxi = ae_c_abs(x->ptr.p_complex[i], _state); if( ae_fp_greater(absxi,safmin) ) { x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); } else { x->ptr.p_complex[i] = ae_complex_from_i(1); } } *kase = 2; jump = 2; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } /* * ENTRY (JUMP = 2) * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. */ if( jump==2 ) { j = rcond_internalcomplexrcondicmax1(x, n, _state); iter = 2; /* * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. */ for(i=1; i<=n; i++) { x->ptr.p_complex[i] = ae_complex_from_i(0); } x->ptr.p_complex[j] = ae_complex_from_i(1); *kase = 1; jump = 3; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } /* * ENTRY (JUMP = 3) * X HAS BEEN OVERWRITTEN BY A*X. */ if( jump==3 ) { ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); estold = *est; *est = rcond_internalcomplexrcondscsum1(v, n, _state); /* * TEST FOR CYCLING. */ if( ae_fp_less_eq(*est,estold) ) { /* * ITERATION COMPLETE. FINAL STAGE. */ altsgn = (double)(1); for(i=1; i<=n; i++) { x->ptr.p_complex[i] = ae_complex_from_d(altsgn*(1+(double)(i-1)/(double)(n-1))); altsgn = -altsgn; } *kase = 1; jump = 5; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } for(i=1; i<=n; i++) { absxi = ae_c_abs(x->ptr.p_complex[i], _state); if( ae_fp_greater(absxi,safmin) ) { x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); } else { x->ptr.p_complex[i] = ae_complex_from_i(1); } } *kase = 2; jump = 4; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } /* * ENTRY (JUMP = 4) * X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. */ if( jump==4 ) { jlast = j; j = rcond_internalcomplexrcondicmax1(x, n, _state); if( ae_fp_neq(ae_c_abs(x->ptr.p_complex[jlast], _state),ae_c_abs(x->ptr.p_complex[j], _state))&&iterptr.p_complex[i] = ae_complex_from_i(0); } x->ptr.p_complex[j] = ae_complex_from_i(1); *kase = 1; jump = 3; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } /* * ITERATION COMPLETE. FINAL STAGE. */ altsgn = (double)(1); for(i=1; i<=n; i++) { x->ptr.p_complex[i] = ae_complex_from_d(altsgn*(1+(double)(i-1)/(double)(n-1))); altsgn = -altsgn; } *kase = 1; jump = 5; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } /* * ENTRY (JUMP = 5) * X HAS BEEN OVERWRITTEN BY A*X. */ if( jump==5 ) { temp = 2*(rcond_internalcomplexrcondscsum1(x, n, _state)/(3*n)); if( ae_fp_greater(temp,*est) ) { ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); *est = temp; } *kase = 0; rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); return; } } static double rcond_internalcomplexrcondscsum1(/* Complex */ ae_vector* x, ae_int_t n, ae_state *_state) { ae_int_t i; double result; result = (double)(0); for(i=1; i<=n; i++) { result = result+ae_c_abs(x->ptr.p_complex[i], _state); } return result; } static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ ae_vector* x, ae_int_t n, ae_state *_state) { ae_int_t i; double m; ae_int_t result; result = 1; m = ae_c_abs(x->ptr.p_complex[1], _state); for(i=2; i<=n; i++) { if( ae_fp_greater(ae_c_abs(x->ptr.p_complex[i], _state),m) ) { result = i; m = ae_c_abs(x->ptr.p_complex[i], _state); } } return result; } static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_int_t* i, ae_int_t* iter, ae_int_t* j, ae_int_t* jlast, ae_int_t* jump, double* absxi, double* altsgn, double* estold, double* temp, ae_state *_state) { isave->ptr.p_int[0] = *i; isave->ptr.p_int[1] = *iter; isave->ptr.p_int[2] = *j; isave->ptr.p_int[3] = *jlast; isave->ptr.p_int[4] = *jump; rsave->ptr.p_double[0] = *absxi; rsave->ptr.p_double[1] = *altsgn; rsave->ptr.p_double[2] = *estold; rsave->ptr.p_double[3] = *temp; } static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, /* Real */ ae_vector* rsave, ae_int_t* i, ae_int_t* iter, ae_int_t* j, ae_int_t* jlast, ae_int_t* jump, double* absxi, double* altsgn, double* estold, double* temp, ae_state *_state) { *i = isave->ptr.p_int[0]; *iter = isave->ptr.p_int[1]; *j = isave->ptr.p_int[2]; *jlast = isave->ptr.p_int[3]; *jump = isave->ptr.p_int[4]; *absxi = rsave->ptr.p_double[0]; *altsgn = rsave->ptr.p_double[1]; *estold = rsave->ptr.p_double[2]; *temp = rsave->ptr.p_double[3]; } /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations (the output of RMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. it is filled by zeros in such cases. * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - solver report, see below for more info A - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. SOLVER REPORT Subroutine sets following fields of the Rep structure: * R1 reciprocal of condition number: 1/cond(A), 1-norm. * RInf reciprocal of condition number: 1/cond(A), inf-norm. -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixluinverse(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_int_t i; ae_int_t j; ae_int_t k; double v; sinteger sinfo; ae_frame_make(_state, &_frame_block); *info = 0; _matinvreport_clear(rep); ae_vector_init(&work, 0, DT_REAL, _state); _sinteger_init(&sinfo, _state); ae_assert(n>0, "RMatrixLUInverse: N<=0!", _state); ae_assert(a->cols>=n, "RMatrixLUInverse: cols(A)rows>=n, "RMatrixLUInverse: rows(A)cnt>=n, "RMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]0, "RMatrixLUInverse: incorrect Pivots array!", _state); /* * calculate condition numbers */ rep->r1 = rmatrixlurcond1(a, n, _state); rep->rinf = rmatrixlurcondinf(a, n, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Call cache-oblivious code */ ae_vector_set_length(&work, n, _state); sinfo.val = 1; matinv_rmatrixluinverserec(a, 0, n, &work, &sinfo, rep, _state); *info = sinfo.val; /* * apply permutations */ for(i=0; i<=n-1; i++) { for(j=n-2; j>=0; j--) { k = pivots->ptr.p_int[j]; v = a->ptr.pp_double[i][j]; a->ptr.pp_double[i][j] = a->ptr.pp_double[i][k]; a->ptr.pp_double[i][k] = v; } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixluinverse(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state) { rmatrixluinverse(a,pivots,n,info,rep, _state); } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse Result: True, if the matrix is not singular. False, if the matrix is singular. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void rmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_frame_make(_state, &_frame_block); *info = 0; _matinvreport_clear(rep); ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>0, "RMatrixInverse: N<=0!", _state); ae_assert(a->cols>=n, "RMatrixInverse: cols(A)rows>=n, "RMatrixInverse: rows(A)0, "CMatrixLUInverse: N<=0!", _state); ae_assert(a->cols>=n, "CMatrixLUInverse: cols(A)rows>=n, "CMatrixLUInverse: rows(A)cnt>=n, "CMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]0, "CMatrixLUInverse: incorrect Pivots array!", _state); /* * calculate condition numbers */ rep->r1 = cmatrixlurcond1(a, n, _state); rep->rinf = cmatrixlurcondinf(a, n, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Call cache-oblivious code */ ae_vector_set_length(&work, n, _state); matinv_cmatrixluinverserec(a, 0, n, &work, info, rep, _state); /* * apply permutations */ for(i=0; i<=n-1; i++) { for(j=n-2; j>=0; j--) { k = pivots->ptr.p_int[j]; v = a->ptr.pp_complex[i][j]; a->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][k]; a->ptr.pp_complex[i][k] = v; } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixluinverse(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state) { cmatrixluinverse(a,pivots,n,info,rep, _state); } /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void cmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_frame_make(_state, &_frame_block); *info = 0; _matinvreport_clear(rep); ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>0, "CRMatrixInverse: N<=0!", _state); ae_assert(a->cols>=n, "CRMatrixInverse: cols(A)rows>=n, "CRMatrixInverse: rows(A)0, "SPDMatrixCholeskyInverse: N<=0!", _state); ae_assert(a->cols>=n, "SPDMatrixCholeskyInverse: cols(A)rows>=n, "SPDMatrixCholeskyInverse: rows(A)ptr.pp_double[i][i], _state); } ae_assert(f, "SPDMatrixCholeskyInverse: A contains infinite or NaN values!", _state); /* * calculate condition numbers */ rep->r1 = spdmatrixcholeskyrcond(a, n, isupper, _state); rep->rinf = rep->r1; if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { a->ptr.pp_double[i][j] = (double)(0); } } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Inverse */ ae_vector_set_length(&tmp, n, _state); spdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state) { spdmatrixcholeskyinverse(a,n,isupper,info,rep, _state); } /************************************************************************* Inversion of a symmetric positive definite matrix. Given an upper or lower triangle of a symmetric positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state) { *info = 0; _matinvreport_clear(rep); ae_assert(n>0, "SPDMatrixInverse: N<=0!", _state); ae_assert(a->cols>=n, "SPDMatrixInverse: cols(A)rows>=n, "SPDMatrixInverse: rows(A)0, "HPDMatrixCholeskyInverse: N<=0!", _state); ae_assert(a->cols>=n, "HPDMatrixCholeskyInverse: cols(A)rows>=n, "HPDMatrixCholeskyInverse: rows(A)ptr.pp_complex[i][i].x, _state))&&ae_isfinite(a->ptr.pp_complex[i][i].y, _state); } ae_assert(f, "HPDMatrixCholeskyInverse: A contains infinite or NaN values!", _state); *info = 1; /* * calculate condition numbers */ rep->r1 = hpdmatrixcholeskyrcond(a, n, isupper, _state); rep->rinf = rep->r1; if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Inverse */ ae_vector_set_length(&tmp, n, _state); matinv_hpdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state) { hpdmatrixcholeskyinverse(a,n,isupper,info,rep, _state); } /************************************************************************* Inversion of a Hermitian positive definite matrix. Given an upper or lower triangle of a Hermitian positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state) { *info = 0; _matinvreport_clear(rep); ae_assert(n>0, "HPDMatrixInverse: N<=0!", _state); ae_assert(a->cols>=n, "HPDMatrixInverse: cols(A)rows>=n, "HPDMatrixInverse: rows(A)0, "RMatrixTRInverse: N<=0!", _state); ae_assert(a->cols>=n, "RMatrixTRInverse: cols(A)rows>=n, "RMatrixTRInverse: rows(A)r1 = rmatrixtrrcond1(a, n, isupper, isunit, _state); rep->rinf = rmatrixtrrcondinf(a, n, isupper, isunit, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = (double)(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Invert */ ae_vector_set_length(&tmp, n, _state); sinfo.val = 1; matinv_rmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, &sinfo, rep, _state); *info = sinfo.val; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixtrinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state) { rmatrixtrinverse(a,n,isupper,isunit,info,rep, _state); } /************************************************************************* Triangular matrix inverse (complex) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixtrinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector tmp; ae_frame_make(_state, &_frame_block); *info = 0; _matinvreport_clear(rep); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); ae_assert(n>0, "CMatrixTRInverse: N<=0!", _state); ae_assert(a->cols>=n, "CMatrixTRInverse: cols(A)rows>=n, "CMatrixTRInverse: rows(A)r1 = cmatrixtrrcond1(a, n, isupper, isunit, _state); rep->rinf = cmatrixtrrcondinf(a, n, isupper, isunit, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } /* * Invert */ ae_vector_set_length(&tmp, n, _state); matinv_cmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, info, rep, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixtrinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state) { cmatrixtrinverse(a,n,isupper,isunit,info,rep, _state); } /************************************************************************* Recursive subroutine for SPD inversion. NOTE: this function expects that matris is strictly positive-definite. -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; ae_int_t n1; ae_int_t n2; sinteger sinfo2; matinvreport rep2; ae_frame_make(_state, &_frame_block); _sinteger_init(&sinfo2, _state); _matinvreport_init(&rep2, _state); if( n<1 ) { ae_frame_leave(_state); return; } /* * Base case */ if( n<=ablasblocksize(a, _state) ) { sinfo2.val = 1; matinv_rmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, &sinfo2, &rep2, _state); ae_assert(sinfo2.val>0, "SPDMatrixCholeskyInverseRec: integrity check failed", _state); if( isupper ) { /* * Compute the product U * U'. * NOTE: we never assume that diagonal of U is real */ for(i=0; i<=n-1; i++) { if( i==0 ) { /* * 1x1 matrix */ a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); } else { /* * (I+1)x(I+1) matrix, * * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) * ( ) * ( ) = ( ) * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) * * A11 is IxI, A22 is 1x1. */ ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(0,i-1)); for(j=0; j<=i-1; j++) { v = a->ptr.pp_double[offs+j][offs+i]; ae_v_addd(&a->ptr.pp_double[offs+j][offs+j], 1, &tmp->ptr.p_double[j], 1, ae_v_len(offs+j,offs+i-1), v); } v = a->ptr.pp_double[offs+i][offs+i]; ae_v_muld(&a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); } } } else { /* * Compute the product L' * L * NOTE: we never assume that diagonal of L is real */ for(i=0; i<=n-1; i++) { if( i==0 ) { /* * 1x1 matrix */ a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); } else { /* * (I+1)x(I+1) matrix, * * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) * ( ) * ( ) = ( ) * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) * * A11 is IxI, A22 is 1x1. */ ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs], 1, ae_v_len(0,i-1)); for(j=0; j<=i-1; j++) { v = a->ptr.pp_double[offs+i][offs+j]; ae_v_addd(&a->ptr.pp_double[offs+j][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+j), v); } v = a->ptr.pp_double[offs+i][offs+i]; ae_v_muld(&a->ptr.pp_double[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); } } } ae_frame_leave(_state); return; } /* * Recursive code: triangular factor inversion merged with * UU' or L'L multiplication */ ablassplitlength(a, n, &n1, &n2, _state); /* * form off-diagonal block of trangular inverse */ if( isupper ) { for(i=0; i<=n1-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); } else { for(i=0; i<=n2-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); } /* * invert first diagonal block */ spdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, _state); /* * update first diagonal block with off-diagonal block, * update off-diagonal block */ if( isupper ) { rmatrixsyrk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs, offs+n1, _state); } else { rmatrixsyrk(n1, n2, 1.0, a, offs+n1, offs, 1, 1.0, a, offs, offs, isupper, _state); rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs+n1, offs, _state); } /* * invert second diagonal block */ spdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, _state); ae_frame_leave(_state); } /************************************************************************* Triangular matrix inversion, recursive subroutine NOTE: this function sets Info on failure, leaves it unchanged on success. NOTE: only Tmp[Offs:Offs+N-1] is modified, other entries of the temporary array are not modified -- ALGLIB -- 05.02.2010, Bochkanov Sergey. Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992. *************************************************************************/ static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool isunit, /* Real */ ae_vector* tmp, sinteger* info, matinvreport* rep, ae_state *_state) { ae_int_t n1; ae_int_t n2; ae_int_t i; ae_int_t j; double v; double ajj; if( n<1 ) { info->val = -1; return; } /* * Base case */ if( n<=ablasblocksize(a, _state) ) { if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( !isunit ) { if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],(double)(0)) ) { info->val = -3; return; } a->ptr.pp_double[offs+j][offs+j] = 1/a->ptr.pp_double[offs+j][offs+j]; ajj = -a->ptr.pp_double[offs+j][offs+j]; } else { ajj = (double)(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_move(&tmp->ptr.p_double[offs+0], 1, &a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_double[offs+i][offs+i+1], 1, &tmp->ptr.p_double[offs+i+1], 1, ae_v_len(offs+i+1,offs+j-1)); } else { v = (double)(0); } if( !isunit ) { a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[offs+i]; } else { a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[offs+i]; } } ae_v_muld(&a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( !isunit ) { if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],(double)(0)) ) { info->val = -3; return; } a->ptr.pp_double[offs+j][offs+j] = 1/a->ptr.pp_double[offs+j][offs+j]; ajj = -a->ptr.pp_double[offs+j][offs+j]; } else { ajj = (double)(-1); } if( jptr.p_double[offs+j+1], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_dotproduct(&a->ptr.pp_double[offs+i][offs+j+1], 1, &tmp->ptr.p_double[offs+j+1], 1, ae_v_len(offs+j+1,offs+i-1)); } else { v = (double)(0); } if( !isunit ) { a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[offs+i]; } else { a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[offs+i]; } } ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); } } } return; } /* * Recursive case */ ablassplitlength(a, n, &n1, &n2, _state); if( n2>0 ) { if( isupper ) { for(i=0; i<=n1-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); matinv_rmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, info, rep, _state); } else { for(i=0; i<=n2-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); matinv_rmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, info, rep, _state); } } matinv_rmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, info, rep, _state); } /************************************************************************* Triangular matrix inversion, recursive subroutine -- ALGLIB -- 05.02.2010, Bochkanov Sergey. Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992. *************************************************************************/ static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool isunit, /* Complex */ ae_vector* tmp, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_int_t n1; ae_int_t n2; ae_int_t i; ae_int_t j; ae_complex v; ae_complex ajj; if( n<1 ) { *info = -1; return; } /* * Base case */ if( n<=ablascomplexblocksize(a, _state) ) { if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( !isunit ) { if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0)) ) { *info = -3; return; } a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); } else { ajj = ae_complex_from_i(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+0][offs+j], a->stride, "N", ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_complex[offs+i][offs+i+1], 1, "N", &tmp->ptr.p_complex[i+1], 1, "N", ae_v_len(offs+i+1,offs+j-1)); } else { v = ae_complex_from_i(0); } if( !isunit ) { a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[i])); } else { a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( !isunit ) { if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0)) ) { *info = -3; return; } a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); } else { ajj = ae_complex_from_i(-1); } if( jptr.p_complex[j+1], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[offs+i][offs+j+1], 1, "N", &tmp->ptr.p_complex[j+1], 1, "N", ae_v_len(offs+j+1,offs+i-1)); } else { v = ae_complex_from_i(0); } if( !isunit ) { a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[i])); } else { a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); } } } return; } /* * Recursive case */ ablascomplexsplitlength(a, n, &n1, &n2, _state); if( n2>0 ) { if( isupper ) { for(i=0; i<=n1-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); } else { for(i=0; i<=n2-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); } matinv_cmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, info, rep, _state); } matinv_cmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, info, rep, _state); } static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, /* Real */ ae_vector* work, sinteger* info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_int_t n1; ae_int_t n2; if( n<1 ) { info->val = -1; return; } /* * Base case */ if( n<=ablasblocksize(a, _state) ) { /* * Form inv(U) */ matinv_rmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, info, rep, _state); if( info->val<=0 ) { return; } /* * Solve the equation inv(A)*L = inv(U) for inv(A). */ for(j=n-1; j>=0; j--) { /* * Copy current column of L to WORK and replace with zeros. */ for(i=j+1; i<=n-1; i++) { work->ptr.p_double[i] = a->ptr.pp_double[offs+i][offs+j]; a->ptr.pp_double[offs+i][offs+j] = (double)(0); } /* * Compute current column of inv(A). */ if( jptr.pp_double[offs+i][offs+j+1], 1, &work->ptr.p_double[j+1], 1, ae_v_len(offs+j+1,offs+n-1)); a->ptr.pp_double[offs+i][offs+j] = a->ptr.pp_double[offs+i][offs+j]-v; } } } return; } /* * Recursive code: * * ( L1 ) ( U1 U12 ) * A = ( ) * ( ) * ( L12 L2 ) ( U2 ) * * ( W X ) * A^-1 = ( ) * ( Y Z ) */ ablassplitlength(a, n, &n1, &n2, _state); ae_assert(n2>0, "LUInverseRec: internal error!", _state); /* * X := inv(U1)*U12*inv(U2) */ rmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); /* * Y := inv(L2)*L12*inv(L1) */ rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); rmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); /* * W := inv(L1*U1)+X*Y */ matinv_rmatrixluinverserec(a, offs, n1, work, info, rep, _state); if( info->val<=0 ) { return; } rmatrixgemm(n1, n1, n2, 1.0, a, offs, offs+n1, 0, a, offs+n1, offs, 0, 1.0, a, offs, offs, _state); /* * X := -X*inv(L2) * Y := -inv(U2)*Y */ rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); for(i=0; i<=n1-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); for(i=0; i<=n2-1; i++) { ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } /* * Z := inv(L2*U2) */ matinv_rmatrixluinverserec(a, offs+n1, n2, work, info, rep, _state); } static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, /* Complex */ ae_vector* work, ae_int_t* info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex v; ae_int_t n1; ae_int_t n2; if( n<1 ) { *info = -1; return; } /* * Base case */ if( n<=ablascomplexblocksize(a, _state) ) { /* * Form inv(U) */ matinv_cmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, info, rep, _state); if( *info<=0 ) { return; } /* * Solve the equation inv(A)*L = inv(U) for inv(A). */ for(j=n-1; j>=0; j--) { /* * Copy current column of L to WORK and replace with zeros. */ for(i=j+1; i<=n-1; i++) { work->ptr.p_complex[i] = a->ptr.pp_complex[offs+i][offs+j]; a->ptr.pp_complex[offs+i][offs+j] = ae_complex_from_i(0); } /* * Compute current column of inv(A). */ if( jptr.pp_complex[offs+i][offs+j+1], 1, "N", &work->ptr.p_complex[j+1], 1, "N", ae_v_len(offs+j+1,offs+n-1)); a->ptr.pp_complex[offs+i][offs+j] = ae_c_sub(a->ptr.pp_complex[offs+i][offs+j],v); } } } return; } /* * Recursive code: * * ( L1 ) ( U1 U12 ) * A = ( ) * ( ) * ( L12 L2 ) ( U2 ) * * ( W X ) * A^-1 = ( ) * ( Y Z ) */ ablascomplexsplitlength(a, n, &n1, &n2, _state); ae_assert(n2>0, "LUInverseRec: internal error!", _state); /* * X := inv(U1)*U12*inv(U2) */ cmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); /* * Y := inv(L2)*L12*inv(L1) */ cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); cmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); /* * W := inv(L1*U1)+X*Y */ matinv_cmatrixluinverserec(a, offs, n1, work, info, rep, _state); if( *info<=0 ) { return; } cmatrixgemm(n1, n1, n2, ae_complex_from_d(1.0), a, offs, offs+n1, 0, a, offs+n1, offs, 0, ae_complex_from_d(1.0), a, offs, offs, _state); /* * X := -X*inv(L2) * Y := -inv(U2)*Y */ cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); for(i=0; i<=n1-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); for(i=0; i<=n2-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } /* * Z := inv(L2*U2) */ matinv_cmatrixluinverserec(a, offs+n1, n2, work, info, rep, _state); } /************************************************************************* Recursive subroutine for HPD inversion. -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tmp, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_complex v; ae_int_t n1; ae_int_t n2; ae_int_t info2; matinvreport rep2; ae_frame_make(_state, &_frame_block); _matinvreport_init(&rep2, _state); if( n<1 ) { ae_frame_leave(_state); return; } /* * Base case */ if( n<=ablascomplexblocksize(a, _state) ) { matinv_cmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, &info2, &rep2, _state); if( isupper ) { /* * Compute the product U * U'. * NOTE: we never assume that diagonal of U is real */ for(i=0; i<=n-1; i++) { if( i==0 ) { /* * 1x1 matrix */ a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); } else { /* * (I+1)x(I+1) matrix, * * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) * ( ) * ( ) = ( ) * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) * * A11 is IxI, A22 is 1x1. */ ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+i], a->stride, "Conj", ae_v_len(0,i-1)); for(j=0; j<=i-1; j++) { v = a->ptr.pp_complex[offs+j][offs+i]; ae_v_caddc(&a->ptr.pp_complex[offs+j][offs+j], 1, &tmp->ptr.p_complex[j], 1, "N", ae_v_len(offs+j,offs+i-1), v); } v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); ae_v_cmulc(&a->ptr.pp_complex[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); } } } else { /* * Compute the product L' * L * NOTE: we never assume that diagonal of L is real */ for(i=0; i<=n-1; i++) { if( i==0 ) { /* * 1x1 matrix */ a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); } else { /* * (I+1)x(I+1) matrix, * * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) * ( ) * ( ) = ( ) * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) * * A11 is IxI, A22 is 1x1. */ ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs], 1, "N", ae_v_len(0,i-1)); for(j=0; j<=i-1; j++) { v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+j], _state); ae_v_caddc(&a->ptr.pp_complex[offs+j][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+j), v); } v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); ae_v_cmulc(&a->ptr.pp_complex[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); } } } ae_frame_leave(_state); return; } /* * Recursive code: triangular factor inversion merged with * UU' or L'L multiplication */ ablascomplexsplitlength(a, n, &n1, &n2, _state); /* * form off-diagonal block of trangular inverse */ if( isupper ) { for(i=0; i<=n1-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); } cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); } else { for(i=0; i<=n2-1; i++) { ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); } cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); } /* * invert first diagonal block */ matinv_hpdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, _state); /* * update first diagonal block with off-diagonal block, * update off-diagonal block */ if( isupper ) { cmatrixherk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs, offs+n1, _state); } else { cmatrixherk(n1, n2, 1.0, a, offs+n1, offs, 2, 1.0, a, offs, offs, isupper, _state); cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs+n1, offs, _state); } /* * invert second diagonal block */ matinv_hpdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, _state); ae_frame_leave(_state); } void _matinvreport_init(void* _p, ae_state *_state) { matinvreport *p = (matinvreport*)_p; ae_touch_ptr((void*)p); } void _matinvreport_init_copy(void* _dst, void* _src, ae_state *_state) { matinvreport *dst = (matinvreport*)_dst; matinvreport *src = (matinvreport*)_src; dst->r1 = src->r1; dst->rinf = src->rinf; } void _matinvreport_clear(void* _p) { matinvreport *p = (matinvreport*)_p; ae_touch_ptr((void*)p); } void _matinvreport_destroy(void* _p) { matinvreport *p = (matinvreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. This subroutine assumes that: * A*ScaleA is well scaled * A is well-conditioned, so no zero divisions or overflow may occur INPUT PARAMETERS: CHA - Cholesky decomposition of A SqrtScaleA- square root of scale factor ScaleA N - matrix size, N>=0. IsUpper - storage type XB - right part Tmp - buffer; function automatically allocates it, if it is too small. It can be reused if function is called several times. OUTPUT PARAMETERS: XB - solution NOTE 1: no assertion or tests are done during algorithm operation NOTE 2: N=0 will force algorithm to silently return -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void fblscholeskysolve(/* Real */ ae_matrix* cha, double sqrtscalea, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* xb, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; double v; if( n==0 ) { return; } if( tmp->cntptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); if( iptr.p_double[i]; ae_v_moved(&tmp->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); ae_v_subd(&xb->ptr.p_double[i+1], 1, &tmp->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), v); } } /* * Solve U*x=y then. */ for(i=n-1; i>=0; i--) { if( iptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; } xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); } } else { /* * Solve L*y=b first */ for(i=0; i<=n-1; i++) { if( i>0 ) { ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); v = ae_v_dotproduct(&tmp->ptr.p_double[0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; } xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); } /* * Solve L'*x=y then. */ for(i=n-1; i>=0; i--) { xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); if( i>0 ) { v = xb->ptr.p_double[i]; ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); ae_v_subd(&xb->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,i-1), v); } } } } /************************************************************************* Fast basic linear solver: linear SPD CG Solves (A^T*A + alpha*I)*x = b where: * A is MxN matrix * alpha>0 is a scalar * I is NxN identity matrix * b is Nx1 vector * X is Nx1 unknown vector. N iterations of linear conjugate gradient are used to solve problem. INPUT PARAMETERS: A - array[M,N], matrix M - number of rows N - number of unknowns B - array[N], right part X - initial approxumation, array[N] Buf - buffer; function automatically allocates it, if it is too small. It can be reused if function is called several times with same M and N. OUTPUT PARAMETERS: X - improved solution NOTES: * solver checks quality of improved solution. If (because of problem condition number, numerical noise, etc.) new solution is WORSE than original approximation, then original approximation is returned. * solver assumes that both A, B, Alpha are well scaled (i.e. they are less than sqrt(overflow) and greater than sqrt(underflow)). -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void fblssolvecgx(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double alpha, /* Real */ ae_vector* b, /* Real */ ae_vector* x, /* Real */ ae_vector* buf, ae_state *_state) { ae_int_t k; ae_int_t offsrk; ae_int_t offsrk1; ae_int_t offsxk; ae_int_t offsxk1; ae_int_t offspk; ae_int_t offspk1; ae_int_t offstmp1; ae_int_t offstmp2; ae_int_t bs; double e1; double e2; double rk2; double rk12; double pap; double s; double betak; double v1; double v2; /* * Test for special case: B=0 */ v1 = ae_v_dotproduct(&b->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_eq(v1,(double)(0)) ) { for(k=0; k<=n-1; k++) { x->ptr.p_double[k] = (double)(0); } return; } /* * Offsets inside Buf for: * * R[K], R[K+1] * * X[K], X[K+1] * * P[K], P[K+1] * * Tmp1 - array[M], Tmp2 - array[N] */ offsrk = 0; offsrk1 = offsrk+n; offsxk = offsrk1+n; offsxk1 = offsxk+n; offspk = offsxk1+n; offspk1 = offspk+n; offstmp1 = offspk1+n; offstmp2 = offstmp1+m; bs = offstmp2+n; if( buf->cntptr.p_double[offsxk], 1, &x->ptr.p_double[0], 1, ae_v_len(offsxk,offsxk+n-1)); /* * r(0) = b-A*x(0) * RK2 = r(0)'*r(0) */ rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); rk2 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offspk,offspk+n-1)); e1 = ae_sqrt(rk2, _state); /* * Cycle */ for(k=0; k<=n-1; k++) { /* * Calculate A*p(k) - store in Buf[OffsTmp2:OffsTmp2+N-1] * and p(k)'*A*p(k) - store in PAP * * If PAP=0, break (iteration is over) */ rmatrixmv(m, n, a, 0, 0, 0, buf, offspk, buf, offstmp1, _state); v1 = ae_v_dotproduct(&buf->ptr.p_double[offstmp1], 1, &buf->ptr.p_double[offstmp1], 1, ae_v_len(offstmp1,offstmp1+m-1)); v2 = ae_v_dotproduct(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk,offspk+n-1)); pap = v1+alpha*v2; rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); if( ae_fp_eq(pap,(double)(0)) ) { break; } /* * S = (r(k)'*r(k))/(p(k)'*A*p(k)) */ s = rk2/pap; /* * x(k+1) = x(k) + S*p(k) */ ae_v_move(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offsxk1,offsxk1+n-1)); ae_v_addd(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offsxk1,offsxk1+n-1), s); /* * r(k+1) = r(k) - S*A*p(k) * RK12 = r(k+1)'*r(k+1) * * Break if r(k+1) small enough (when compared to r(k)) */ ae_v_move(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk1,offsrk1+n-1)); ae_v_subd(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk1,offsrk1+n-1), s); rk12 = ae_v_dotproduct(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk1,offsrk1+n-1)); if( ae_fp_less_eq(ae_sqrt(rk12, _state),100*ae_machineepsilon*ae_sqrt(rk2, _state)) ) { /* * X(k) = x(k+1) before exit - * - because we expect to find solution at x(k) */ ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); break; } /* * BetaK = RK12/RK2 * p(k+1) = r(k+1)+betak*p(k) */ betak = rk12/rk2; ae_v_move(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offspk1,offspk1+n-1)); ae_v_addd(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk1,offspk1+n-1), betak); /* * r(k) := r(k+1) * x(k) := x(k+1) * p(k) := p(k+1) */ ae_v_move(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk,offsrk+n-1)); ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk1], 1, ae_v_len(offspk,offspk+n-1)); rk2 = rk12; } /* * Calculate E2 */ rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); v1 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); e2 = ae_sqrt(v1, _state); /* * Output result (if it was improved) */ if( ae_fp_less(e2,e1) ) { ae_v_move(&x->ptr.p_double[0], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(0,n-1)); } } /************************************************************************* Construction of linear conjugate gradient solver. State parameter passed using "var" semantics (i.e. previous state is NOT erased). When it is already initialized, we can reause prevously allocated memory. INPUT PARAMETERS: X - initial solution B - right part N - system size State - structure; may be preallocated, if we want to reuse memory OUTPUT PARAMETERS: State - structure which is used by FBLSCGIteration() to store algorithm state between subsequent calls. NOTE: no error checking is done; caller must check all parameters, prevent overflows, and so on. -- ALGLIB -- Copyright 22.10.2009 by Bochkanov Sergey *************************************************************************/ void fblscgcreate(/* Real */ ae_vector* x, /* Real */ ae_vector* b, ae_int_t n, fblslincgstate* state, ae_state *_state) { if( state->b.cntb, n, _state); } if( state->rk.cntrk, n, _state); } if( state->rk1.cntrk1, n, _state); } if( state->xk.cntxk, n, _state); } if( state->xk1.cntxk1, n, _state); } if( state->pk.cntpk, n, _state); } if( state->pk1.cntpk1, n, _state); } if( state->tmp2.cnttmp2, n, _state); } if( state->x.cntx, n, _state); } if( state->ax.cntax, n, _state); } state->n = n; ae_v_move(&state->xk.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_vector_set_length(&state->rstate.ia, 1+1, _state); ae_vector_set_length(&state->rstate.ra, 6+1, _state); state->rstate.stage = -1; } /************************************************************************* Linear CG solver, function relying on reverse communication to calculate matrix-vector products. See comments for FBLSLinCGState structure for more info. -- ALGLIB -- Copyright 22.10.2009 by Bochkanov Sergey *************************************************************************/ ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state) { ae_int_t n; ae_int_t k; double rk2; double rk12; double pap; double s; double betak; double v1; double v2; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; k = state->rstate.ia.ptr.p_int[1]; rk2 = state->rstate.ra.ptr.p_double[0]; rk12 = state->rstate.ra.ptr.p_double[1]; pap = state->rstate.ra.ptr.p_double[2]; s = state->rstate.ra.ptr.p_double[3]; betak = state->rstate.ra.ptr.p_double[4]; v1 = state->rstate.ra.ptr.p_double[5]; v2 = state->rstate.ra.ptr.p_double[6]; } else { n = -983; k = -989; rk2 = -834; rk12 = 900; pap = -287; s = 364; betak = 214; v1 = -338; v2 = -686; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } /* * Routine body */ /* * prepare locals */ n = state->n; /* * Test for special case: B=0 */ v1 = ae_v_dotproduct(&state->b.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_eq(v1,(double)(0)) ) { for(k=0; k<=n-1; k++) { state->xk.ptr.p_double[k] = (double)(0); } result = ae_false; return result; } /* * r(0) = b-A*x(0) * RK2 = r(0)'*r(0) */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 0; goto lbl_rcomm; lbl_0: ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); rk2 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->pk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->e1 = ae_sqrt(rk2, _state); /* * Cycle */ k = 0; lbl_3: if( k>n-1 ) { goto lbl_5; } /* * Calculate A*p(k) - store in State.Tmp2 * and p(k)'*A*p(k) - store in PAP * * If PAP=0, break (iteration is over) */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 1; goto lbl_rcomm; lbl_1: ae_v_move(&state->tmp2.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); pap = state->xax; if( !ae_isfinite(pap, _state) ) { goto lbl_5; } if( ae_fp_less_eq(pap,(double)(0)) ) { goto lbl_5; } /* * S = (r(k)'*r(k))/(p(k)'*A*p(k)) */ s = rk2/pap; /* * x(k+1) = x(k) + S*p(k) */ ae_v_move(&state->xk1.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->xk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), s); /* * r(k+1) = r(k) - S*A*p(k) * RK12 = r(k+1)'*r(k+1) * * Break if r(k+1) small enough (when compared to r(k)) */ ae_v_move(&state->rk1.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_subd(&state->rk1.ptr.p_double[0], 1, &state->tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1), s); rk12 = ae_v_dotproduct(&state->rk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_less_eq(ae_sqrt(rk12, _state),100*ae_machineepsilon*state->e1) ) { /* * X(k) = x(k+1) before exit - * - because we expect to find solution at x(k) */ ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); goto lbl_5; } /* * BetaK = RK12/RK2 * p(k+1) = r(k+1)+betak*p(k) * * NOTE: we expect that BetaK won't overflow because of * "Sqrt(RK12)<=100*MachineEpsilon*E1" test above. */ betak = rk12/rk2; ae_v_move(&state->pk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->pk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); /* * r(k) := r(k+1) * x(k) := x(k+1) * p(k) := p(k+1) */ ae_v_move(&state->rk.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->pk.ptr.p_double[0], 1, &state->pk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); rk2 = rk12; k = k+1; goto lbl_3; lbl_5: /* * Calculate E2 */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 2; goto lbl_rcomm; lbl_2: ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); v1 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->e2 = ae_sqrt(v1, _state); result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = k; state->rstate.ra.ptr.p_double[0] = rk2; state->rstate.ra.ptr.p_double[1] = rk12; state->rstate.ra.ptr.p_double[2] = pap; state->rstate.ra.ptr.p_double[3] = s; state->rstate.ra.ptr.p_double[4] = betak; state->rstate.ra.ptr.p_double[5] = v1; state->rstate.ra.ptr.p_double[6] = v2; return result; } /************************************************************************* Fast least squares solver, solves well conditioned system without performing any checks for degeneracy, and using user-provided buffers (which are automatically reallocated if too small). This function is intended for solution of moderately sized systems. It uses factorization algorithms based on Level 2 BLAS operations, thus it won't work efficiently on large scale systems. INPUT PARAMETERS: A - array[M,N], system matrix. Contents of A is destroyed during solution. B - array[M], right part M - number of equations N - number of variables, N<=M Tmp0, Tmp1, Tmp2- buffers; function automatically allocates them, if they are too small. They can be reused if function is called several times. OUTPUT PARAMETERS: B - solution (first N components, next M-N are zero) -- ALGLIB -- Copyright 20.01.2012 by Bochkanov Sergey *************************************************************************/ void fblssolvels(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tmp0, /* Real */ ae_vector* tmp1, /* Real */ ae_vector* tmp2, ae_state *_state) { ae_int_t i; ae_int_t k; double v; ae_assert(n>0, "FBLSSolveLS: N<=0", _state); ae_assert(m>=n, "FBLSSolveLS: Mrows>=m, "FBLSSolveLS: Rows(A)cols>=n, "FBLSSolveLS: Cols(A)cnt>=m, "FBLSSolveLS: Length(B)ptr.p_double[i] = (double)(0); } ae_v_move(&tmp0->ptr.p_double[k], 1, &a->ptr.pp_double[k][k], a->stride, ae_v_len(k,m-1)); tmp0->ptr.p_double[k] = (double)(1); v = ae_v_dotproduct(&tmp0->ptr.p_double[k], 1, &b->ptr.p_double[k], 1, ae_v_len(k,m-1)); v = v*tmp2->ptr.p_double[k]; ae_v_subd(&b->ptr.p_double[k], 1, &tmp0->ptr.p_double[k], 1, ae_v_len(k,m-1), v); } /* * Solve triangular system */ b->ptr.p_double[n-1] = b->ptr.p_double[n-1]/a->ptr.pp_double[n-1][n-1]; for(i=n-2; i>=0; i--) { v = ae_v_dotproduct(&a->ptr.pp_double[i][i+1], 1, &b->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); b->ptr.p_double[i] = (b->ptr.p_double[i]-v)/a->ptr.pp_double[i][i]; } for(i=n; i<=m-1; i++) { b->ptr.p_double[i] = 0.0; } } void _fblslincgstate_init(void* _p, ae_state *_state) { fblslincgstate *p = (fblslincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->ax, 0, DT_REAL, _state); ae_vector_init(&p->rk, 0, DT_REAL, _state); ae_vector_init(&p->rk1, 0, DT_REAL, _state); ae_vector_init(&p->xk, 0, DT_REAL, _state); ae_vector_init(&p->xk1, 0, DT_REAL, _state); ae_vector_init(&p->pk, 0, DT_REAL, _state); ae_vector_init(&p->pk1, 0, DT_REAL, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); ae_vector_init(&p->tmp2, 0, DT_REAL, _state); } void _fblslincgstate_init_copy(void* _dst, void* _src, ae_state *_state) { fblslincgstate *dst = (fblslincgstate*)_dst; fblslincgstate *src = (fblslincgstate*)_src; dst->e1 = src->e1; dst->e2 = src->e2; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->ax, &src->ax, _state); dst->xax = src->xax; dst->n = src->n; ae_vector_init_copy(&dst->rk, &src->rk, _state); ae_vector_init_copy(&dst->rk1, &src->rk1, _state); ae_vector_init_copy(&dst->xk, &src->xk, _state); ae_vector_init_copy(&dst->xk1, &src->xk1, _state); ae_vector_init_copy(&dst->pk, &src->pk, _state); ae_vector_init_copy(&dst->pk1, &src->pk1, _state); ae_vector_init_copy(&dst->b, &src->b, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state); } void _fblslincgstate_clear(void* _p) { fblslincgstate *p = (fblslincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->ax); ae_vector_clear(&p->rk); ae_vector_clear(&p->rk1); ae_vector_clear(&p->xk); ae_vector_clear(&p->xk1); ae_vector_clear(&p->pk); ae_vector_clear(&p->pk1); ae_vector_clear(&p->b); _rcommstate_clear(&p->rstate); ae_vector_clear(&p->tmp2); } void _fblslincgstate_destroy(void* _p) { fblslincgstate *p = (fblslincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->ax); ae_vector_destroy(&p->rk); ae_vector_destroy(&p->rk1); ae_vector_destroy(&p->xk); ae_vector_destroy(&p->xk1); ae_vector_destroy(&p->pk); ae_vector_destroy(&p->pk1); ae_vector_destroy(&p->b); _rcommstate_destroy(&p->rstate); ae_vector_destroy(&p->tmp2); } /************************************************************************* This procedure initializes matrix norm estimator. USAGE: 1. User initializes algorithm state with NormEstimatorCreate() call 2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) 3. User calls NormEstimatorResults() to get solution. INPUT PARAMETERS: M - number of rows in the matrix being estimated, M>0 N - number of columns in the matrix being estimated, N>0 NStart - number of random starting vectors recommended value - at least 5. NIts - number of iterations to do with best starting vector recommended value - at least 5. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: this algorithm is effectively deterministic, i.e. it always returns same result when repeatedly called for the same matrix. In fact, algorithm uses randomized starting vectors, but internal random numbers generator always generates same sequence of the random values (it is a feature, not bug). Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorcreate(ae_int_t m, ae_int_t n, ae_int_t nstart, ae_int_t nits, normestimatorstate* state, ae_state *_state) { _normestimatorstate_clear(state); ae_assert(m>0, "NormEstimatorCreate: M<=0", _state); ae_assert(n>0, "NormEstimatorCreate: N<=0", _state); ae_assert(nstart>0, "NormEstimatorCreate: NStart<=0", _state); ae_assert(nits>0, "NormEstimatorCreate: NIts<=0", _state); state->m = m; state->n = n; state->nstart = nstart; state->nits = nits; state->seedval = 11; hqrndrandomize(&state->r, _state); ae_vector_set_length(&state->x0, state->n, _state); ae_vector_set_length(&state->t, state->m, _state); ae_vector_set_length(&state->x1, state->n, _state); ae_vector_set_length(&state->xbest, state->n, _state); ae_vector_set_length(&state->x, ae_maxint(state->n, state->m, _state), _state); ae_vector_set_length(&state->mv, state->m, _state); ae_vector_set_length(&state->mtv, state->n, _state); ae_vector_set_length(&state->rstate.ia, 3+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; } /************************************************************************* This function changes seed value used by algorithm. In some cases we need deterministic processing, i.e. subsequent calls must return equal results, in other cases we need non-deterministic algorithm which returns different results for the same matrix on every pass. Setting zero seed will lead to non-deterministic algorithm, while non-zero value will make our algorithm deterministic. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() SeedVal - seed value, >=0. Zero value = non-deterministic algo. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorsetseed(normestimatorstate* state, ae_int_t seedval, ae_state *_state) { ae_assert(seedval>=0, "NormEstimatorSetSeed: SeedVal<0", _state); state->seedval = seedval; } /************************************************************************* -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ ae_bool normestimatoriteration(normestimatorstate* state, ae_state *_state) { ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t itcnt; double v; double growth; double bestgrowth; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; i = state->rstate.ia.ptr.p_int[2]; itcnt = state->rstate.ia.ptr.p_int[3]; v = state->rstate.ra.ptr.p_double[0]; growth = state->rstate.ra.ptr.p_double[1]; bestgrowth = state->rstate.ra.ptr.p_double[2]; } else { n = -983; m = -989; i = -834; itcnt = 900; v = -287; growth = 364; bestgrowth = 214; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } /* * Routine body */ n = state->n; m = state->m; if( state->seedval>0 ) { hqrndseed(state->seedval, state->seedval+2, &state->r, _state); } bestgrowth = (double)(0); state->xbest.ptr.p_double[0] = (double)(1); for(i=1; i<=n-1; i++) { state->xbest.ptr.p_double[i] = (double)(0); } itcnt = 0; lbl_4: if( itcnt>state->nstart-1 ) { goto lbl_6; } do { v = (double)(0); for(i=0; i<=n-1; i++) { state->x0.ptr.p_double[i] = hqrndnormal(&state->r, _state); v = v+ae_sqr(state->x0.ptr.p_double[i], _state); } } while(ae_fp_eq(v,(double)(0))); v = 1/ae_sqrt(v, _state); ae_v_muld(&state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1), v); ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->needmv = ae_true; state->needmtv = ae_false; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->needmv = ae_false; state->needmtv = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->x1.ptr.p_double[i], _state); } growth = ae_sqrt(ae_sqrt(v, _state), _state); if( ae_fp_greater(growth,bestgrowth) ) { v = 1/ae_sqrt(v, _state); ae_v_moved(&state->xbest.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); bestgrowth = growth; } itcnt = itcnt+1; goto lbl_4; lbl_6: ae_v_move(&state->x0.ptr.p_double[0], 1, &state->xbest.ptr.p_double[0], 1, ae_v_len(0,n-1)); itcnt = 0; lbl_7: if( itcnt>state->nits-1 ) { goto lbl_9; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->needmv = ae_true; state->needmtv = ae_false; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->needmv = ae_false; state->needmtv = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->x1.ptr.p_double[i], _state); } state->repnorm = ae_sqrt(ae_sqrt(v, _state), _state); if( ae_fp_neq(v,(double)(0)) ) { v = 1/ae_sqrt(v, _state); ae_v_moved(&state->x0.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); } itcnt = itcnt+1; goto lbl_7; lbl_9: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = i; state->rstate.ia.ptr.p_int[3] = itcnt; state->rstate.ra.ptr.p_double[0] = v; state->rstate.ra.ptr.p_double[1] = growth; state->rstate.ra.ptr.p_double[2] = bestgrowth; return result; } /************************************************************************* This function estimates norm of the sparse M*N matrix A. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() A - sparse M*N matrix, must be converted to CRS format prior to calling this function. After this function is over you can call NormEstimatorResults() to get estimate of the norm(A). -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorestimatesparse(normestimatorstate* state, sparsematrix* a, ae_state *_state) { normestimatorrestart(state, _state); while(normestimatoriteration(state, _state)) { if( state->needmv ) { sparsemv(a, &state->x, &state->mv, _state); continue; } if( state->needmtv ) { sparsemtv(a, &state->x, &state->mtv, _state); continue; } } } /************************************************************************* Matrix norm estimation results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Nrm - estimate of the matrix norm, Nrm>=0 -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorresults(normestimatorstate* state, double* nrm, ae_state *_state) { *nrm = 0; *nrm = state->repnorm; } /************************************************************************* This function restarts estimator and prepares it for the next estimation round. INPUT PARAMETERS: State - algorithm state -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorrestart(normestimatorstate* state, ae_state *_state) { ae_vector_set_length(&state->rstate.ia, 3+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; } void _normestimatorstate_init(void* _p, ae_state *_state) { normestimatorstate *p = (normestimatorstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x0, 0, DT_REAL, _state); ae_vector_init(&p->x1, 0, DT_REAL, _state); ae_vector_init(&p->t, 0, DT_REAL, _state); ae_vector_init(&p->xbest, 0, DT_REAL, _state); _hqrndstate_init(&p->r, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->mv, 0, DT_REAL, _state); ae_vector_init(&p->mtv, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _normestimatorstate_init_copy(void* _dst, void* _src, ae_state *_state) { normestimatorstate *dst = (normestimatorstate*)_dst; normestimatorstate *src = (normestimatorstate*)_src; dst->n = src->n; dst->m = src->m; dst->nstart = src->nstart; dst->nits = src->nits; dst->seedval = src->seedval; ae_vector_init_copy(&dst->x0, &src->x0, _state); ae_vector_init_copy(&dst->x1, &src->x1, _state); ae_vector_init_copy(&dst->t, &src->t, _state); ae_vector_init_copy(&dst->xbest, &src->xbest, _state); _hqrndstate_init_copy(&dst->r, &src->r, _state); ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->mv, &src->mv, _state); ae_vector_init_copy(&dst->mtv, &src->mtv, _state); dst->needmv = src->needmv; dst->needmtv = src->needmtv; dst->repnorm = src->repnorm; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _normestimatorstate_clear(void* _p) { normestimatorstate *p = (normestimatorstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x0); ae_vector_clear(&p->x1); ae_vector_clear(&p->t); ae_vector_clear(&p->xbest); _hqrndstate_clear(&p->r); ae_vector_clear(&p->x); ae_vector_clear(&p->mv); ae_vector_clear(&p->mtv); _rcommstate_clear(&p->rstate); } void _normestimatorstate_destroy(void* _p) { normestimatorstate *p = (normestimatorstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x0); ae_vector_destroy(&p->x1); ae_vector_destroy(&p->t); ae_vector_destroy(&p->xbest); _hqrndstate_destroy(&p->r); ae_vector_destroy(&p->x); ae_vector_destroy(&p->mv); ae_vector_destroy(&p->mtv); _rcommstate_destroy(&p->rstate); } /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixludet(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t s; double result; ae_assert(n>=1, "RMatrixLUDet: N<1!", _state); ae_assert(pivots->cnt>=n, "RMatrixLUDet: Pivots array is too short!", _state); ae_assert(a->rows>=n, "RMatrixLUDet: rows(A)cols>=n, "RMatrixLUDet: cols(A)ptr.pp_double[i][i]; if( pivots->ptr.p_int[i]!=i ) { s = -s; } } result = result*s; return result; } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixdet(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector pivots; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "RMatrixDet: N<1!", _state); ae_assert(a->rows>=n, "RMatrixDet: rows(A)cols>=n, "RMatrixDet: cols(A)=1, "CMatrixLUDet: N<1!", _state); ae_assert(pivots->cnt>=n, "CMatrixLUDet: Pivots array is too short!", _state); ae_assert(a->rows>=n, "CMatrixLUDet: rows(A)cols>=n, "CMatrixLUDet: cols(A)ptr.pp_complex[i][i]); if( pivots->ptr.p_int[i]!=i ) { s = -s; } } result = ae_c_mul_d(result,(double)(s)); return result; } /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ ae_complex cmatrixdet(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_vector pivots; ae_complex result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&pivots, 0, DT_INT, _state); ae_assert(n>=1, "CMatrixDet: N<1!", _state); ae_assert(a->rows>=n, "CMatrixDet: rows(A)cols>=n, "CMatrixDet: cols(A)=1, "SPDMatrixCholeskyDet: N<1!", _state); ae_assert(a->rows>=n, "SPDMatrixCholeskyDet: rows(A)cols>=n, "SPDMatrixCholeskyDet: cols(A)ptr.pp_double[i][i], _state); } ae_assert(f, "SPDMatrixCholeskyDet: A contains infinite or NaN values!", _state); result = (double)(1); for(i=0; i<=n-1; i++) { result = result*ae_sqr(a->ptr.pp_double[i][i], _state); } return result; } /************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Result: determinant of matrix A. If matrix A is not positive definite, exception is thrown. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixdet(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_bool b; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_assert(n>=1, "SPDMatrixDet: N<1!", _state); ae_assert(a->rows>=n, "SPDMatrixDet: rows(A)cols>=n, "SPDMatrixDet: cols(A)ptr.pp_double[0][j] = 0.0; } for(i=1; i<=n-1; i++) { ae_v_move(&z->ptr.pp_double[i][0], 1, &z->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); } /* * Setup R properties */ if( isupperr ) { j1 = 0; j2 = n-1; j1inc = 1; j2inc = 0; } else { j1 = 0; j2 = 0; j1inc = 0; j2inc = 1; } /* * Calculate R*Z */ for(i=0; i<=n-1; i++) { for(j=j1; j<=j2; j++) { v = r.ptr.pp_double[i][j]; ae_v_addd(&z->ptr.pp_double[i][0], 1, &t.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); } j1 = j1+j1inc; j2 = j2+j2inc; } } ae_frame_leave(_state); return result; } /************************************************************************* Algorithm for reduction of the following generalized symmetric positive- definite eigenvalue problem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3) to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and the given problems are the same, and the eigenvectors of the given problem could be obtained by multiplying the obtained eigenvectors by the transformation matrix x = R*y). Here A is a symmetric matrix, B - symmetric positive-definite matrix. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: A - symmetric matrix which is given by its upper or lower triangle depending on IsUpperA. Contains matrix C. Array whose indexes range within [0..N-1, 0..N-1]. R - upper triangular or low triangular transformation matrix which is used to obtain the eigenvectors of a given problem as the product of eigenvectors of C (from the right) and matrix R (from the left). If the matrix is upper triangular, the elements below the main diagonal are equal to 0 (and vice versa). Thus, we can perform the multiplication without taking into account the internal structure (which is an easier though less effective way). Array whose indexes range within [0..N-1, 0..N-1]. IsUpperR - type of matrix R (upper or lower triangular). Result: True, if the problem was reduced successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix is not positive-definite). -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isuppera, /* Real */ ae_matrix* b, ae_bool isupperb, ae_int_t problemtype, /* Real */ ae_matrix* r, ae_bool* isupperr, ae_state *_state) { ae_frame _frame_block; ae_matrix t; ae_vector w1; ae_vector w2; ae_vector w3; ae_int_t i; ae_int_t j; double v; matinvreport rep; ae_int_t info; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_clear(r); *isupperr = ae_false; ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_vector_init(&w1, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&w3, 0, DT_REAL, _state); _matinvreport_init(&rep, _state); ae_assert(n>0, "SMatrixGEVDReduce: N<=0!", _state); ae_assert((problemtype==1||problemtype==2)||problemtype==3, "SMatrixGEVDReduce: incorrect ProblemType!", _state); result = ae_true; /* * Problem 1: A*x = lambda*B*x * * Reducing to: * C*y = lambda*y * C = L^(-1) * A * L^(-T) * x = L^(-T) * y */ if( problemtype==1 ) { /* * Factorize B in T: B = LL' */ ae_matrix_set_length(&t, n-1+1, n-1+1, _state); if( isupperb ) { for(i=0; i<=n-1; i++) { ae_v_move(&t.ptr.pp_double[i][i], t.stride, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); } } else { for(i=0; i<=n-1; i++) { ae_v_move(&t.ptr.pp_double[i][0], 1, &b->ptr.pp_double[i][0], 1, ae_v_len(0,i)); } } if( !spdmatrixcholesky(&t, n, ae_false, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Invert L in T */ rmatrixtrinverse(&t, n, ae_false, ae_false, &info, &rep, _state); if( info<=0 ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Build L^(-1) * A * L^(-T) in R */ ae_vector_set_length(&w1, n+1, _state); ae_vector_set_length(&w2, n+1, _state); ae_matrix_set_length(r, n-1+1, n-1+1, _state); for(j=1; j<=n; j++) { /* * Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T)) */ ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][0], 1, ae_v_len(1,j)); symmetricmatrixvectormultiply(a, isuppera, 0, j-1, &w1, 1.0, &w2, _state); if( isuppera ) { matrixvectormultiply(a, 0, j-1, j, n-1, ae_true, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); } else { matrixvectormultiply(a, j, n-1, 0, j-1, ae_false, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); } /* * Form l(i)*w2 (here l(i) is i-th row of L^(-1)) */ for(i=1; i<=n; i++) { v = ae_v_dotproduct(&t.ptr.pp_double[i-1][0], 1, &w2.ptr.p_double[1], 1, ae_v_len(0,i-1)); r->ptr.pp_double[i-1][j-1] = v; } } /* * Copy R to A */ for(i=0; i<=n-1; i++) { ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } /* * Copy L^(-1) from T to R and transpose */ *isupperr = ae_true; for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { r->ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], t.stride, ae_v_len(i,n-1)); } ae_frame_leave(_state); return result; } /* * Problem 2: A*B*x = lambda*x * or * problem 3: B*A*x = lambda*x * * Reducing to: * C*y = lambda*y * C = U * A * U' * B = U'* U */ if( problemtype==2||problemtype==3 ) { /* * Factorize B in T: B = U'*U */ ae_matrix_set_length(&t, n-1+1, n-1+1, _state); if( isupperb ) { for(i=0; i<=n-1; i++) { ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); } } else { for(i=0; i<=n-1; i++) { ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], b->stride, ae_v_len(i,n-1)); } } if( !spdmatrixcholesky(&t, n, ae_true, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Build U * A * U' in R */ ae_vector_set_length(&w1, n+1, _state); ae_vector_set_length(&w2, n+1, _state); ae_vector_set_length(&w3, n+1, _state); ae_matrix_set_length(r, n-1+1, n-1+1, _state); for(j=1; j<=n; j++) { /* * Form w2 = A * u'(j) (here u'(j) is j-th column of U') */ ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(1,n-j+1)); symmetricmatrixvectormultiply(a, isuppera, j-1, n-1, &w1, 1.0, &w3, _state); ae_v_move(&w2.ptr.p_double[j], 1, &w3.ptr.p_double[1], 1, ae_v_len(j,n)); ae_v_move(&w1.ptr.p_double[j], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(j,n)); if( isuppera ) { matrixvectormultiply(a, 0, j-2, j-1, n-1, ae_false, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); } else { matrixvectormultiply(a, j-1, n-1, 0, j-2, ae_true, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); } /* * Form u(i)*w2 (here u(i) is i-th row of U) */ for(i=1; i<=n; i++) { v = ae_v_dotproduct(&t.ptr.pp_double[i-1][i-1], 1, &w2.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); r->ptr.pp_double[i-1][j-1] = v; } } /* * Copy R to A */ for(i=0; i<=n-1; i++) { ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } if( problemtype==2 ) { /* * Invert U in T */ rmatrixtrinverse(&t, n, ae_true, ae_false, &info, &rep, _state); if( info<=0 ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Copy U^-1 from T to R */ *isupperr = ae_true; for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { r->ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); } } else { /* * Copy U from T to R and transpose */ *isupperr = ae_false; for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { r->ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { ae_v_move(&r->ptr.pp_double[i][i], r->stride, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); } } } ae_frame_leave(_state); return result; } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a number to an element of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - row where the element to be updated is stored. UpdColumn - column where the element to be updated is stored. UpdVal - a number to be added to the element. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updrow, ae_int_t updcolumn, double updval, ae_state *_state) { ae_frame _frame_block; ae_vector t1; ae_vector t2; ae_int_t i; double lambdav; double vt; ae_frame_make(_state, &_frame_block); ae_vector_init(&t1, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_assert(updrow>=0&&updrow=0&&updcolumnptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); /* * T2 = v*InvA */ ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); /* * Lambda = v * InvA * U */ lambdav = updval*inva->ptr.pp_double[updcolumn][updrow]; /* * InvA = InvA - correction */ for(i=0; i<=n-1; i++) { vt = updval*t1.ptr.p_double[i]; vt = vt/(1+lambdav); ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); } ae_frame_leave(_state); } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a row of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - the row of A whose vector V was added. 0 <= Row <= N-1 V - the vector to be added to a row. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updrow, /* Real */ ae_vector* v, ae_state *_state) { ae_frame _frame_block; ae_vector t1; ae_vector t2; ae_int_t i; ae_int_t j; double lambdav; double vt; ae_frame_make(_state, &_frame_block); ae_vector_init(&t1, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_set_length(&t1, n-1+1, _state); ae_vector_set_length(&t2, n-1+1, _state); /* * T1 = InvA * U */ ae_v_move(&t1.ptr.p_double[0], 1, &inva->ptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); /* * T2 = v*InvA * Lambda = v * InvA * U */ for(j=0; j<=n-1; j++) { vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); t2.ptr.p_double[j] = vt; } lambdav = t2.ptr.p_double[updrow]; /* * InvA = InvA - correction */ for(i=0; i<=n-1; i++) { vt = t1.ptr.p_double[i]/(1+lambdav); ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); } ae_frame_leave(_state); } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a column of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdColumn - the column of A whose vector U was added. 0 <= UpdColumn <= N-1 U - the vector to be added to a column. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updcolumn, /* Real */ ae_vector* u, ae_state *_state) { ae_frame _frame_block; ae_vector t1; ae_vector t2; ae_int_t i; double lambdav; double vt; ae_frame_make(_state, &_frame_block); ae_vector_init(&t1, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_set_length(&t1, n-1+1, _state); ae_vector_set_length(&t2, n-1+1, _state); /* * T1 = InvA * U * Lambda = v * InvA * U */ for(i=0; i<=n-1; i++) { vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); t1.ptr.p_double[i] = vt; } lambdav = t1.ptr.p_double[updcolumn]; /* * T2 = v*InvA */ ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); /* * InvA = InvA - correction */ for(i=0; i<=n-1; i++) { vt = t1.ptr.p_double[i]/(1+lambdav); ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); } ae_frame_leave(_state); } /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm computes the inverse of matrix A+u*v by using the given matrix A^-1 and the vectors u and v. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. U - the vector modifying the matrix. Array whose index ranges within [0..N-1]. V - the vector modifying the matrix. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of matrix A + u*v'. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, ae_int_t n, /* Real */ ae_vector* u, /* Real */ ae_vector* v, ae_state *_state) { ae_frame _frame_block; ae_vector t1; ae_vector t2; ae_int_t i; ae_int_t j; double lambdav; double vt; ae_frame_make(_state, &_frame_block); ae_vector_init(&t1, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_set_length(&t1, n-1+1, _state); ae_vector_set_length(&t2, n-1+1, _state); /* * T1 = InvA * U * Lambda = v * T1 */ for(i=0; i<=n-1; i++) { vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); t1.ptr.p_double[i] = vt; } lambdav = ae_v_dotproduct(&v->ptr.p_double[0], 1, &t1.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * T2 = v*InvA */ for(j=0; j<=n-1; j++) { vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); t2.ptr.p_double[j] = vt; } /* * InvA = InvA - correction */ for(i=0; i<=n-1; i++) { vt = t1.ptr.p_double[i]/(1+lambdav); ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); } ae_frame_leave(_state); } /************************************************************************* Subroutine performing the Schur decomposition of a general matrix by using the QR algorithm with multiple shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The source matrix A is represented as S'*A*S = T, where S is an orthogonal matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..N-1, 0..N-1]. N - size of A, N>=0. Output parameters: A - contains matrix T. Array whose indexes range within [0..N-1, 0..N-1]. S - contains Schur vectors. Array whose indexes range within [0..N-1, 0..N-1]. Note 1: The block structure of matrix T can be easily recognized: since all the elements below the blocks are zeros, the elements a[i+1,i] which are equal to 0 show the block border. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms in linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. Result: True, if the algorithm has converged and parameters A and S contain the result. False, if the algorithm has not converged. Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). *************************************************************************/ ae_bool rmatrixschur(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* s, ae_state *_state) { ae_frame _frame_block; ae_vector tau; ae_vector wi; ae_vector wr; ae_int_t info; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_clear(s); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&wi, 0, DT_REAL, _state); ae_vector_init(&wr, 0, DT_REAL, _state); /* * Upper Hessenberg form of the 0-based matrix */ rmatrixhessenberg(a, n, &tau, _state); rmatrixhessenbergunpackq(a, n, &tau, s, _state); /* * Schur decomposition */ rmatrixinternalschurdecomposition(a, n, 1, 1, &wr, &wi, s, &info, _state); result = info==0; ae_frame_leave(_state); return result; } } qmapshack-1.10.0/3rdparty/alglib/src/ap.cpp000755 001750 000144 00001171707 13024173403 021635 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "ap.h" #include #include using namespace std; #if defined(AE_CPU) #if (AE_CPU==AE_INTEL) #if AE_COMPILER==AE_MSVC #include #endif #endif #endif // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif ///////////////////////////////////////////////////////////////////////// // // THIS SECTION IMPLEMENTS BASIC FUNCTIONALITY LIKE // MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS // SHARED BETWEEN C++ AND PURE C LIBRARIES // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { /* * OS-specific includes */ #ifdef AE_USE_CPP } #endif #if AE_OS==AE_WINDOWS #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #include #include #elif AE_OS==AE_POSIX #include #include #include #include #endif /* Debugging helpers for Windows */ #ifdef AE_DEBUG4WINDOWS #include #include #endif #ifdef AE_USE_CPP namespace alglib_impl { #endif /* * local definitions */ #define x_nb 16 #define AE_DATA_ALIGN 64 #define AE_PTR_ALIGN sizeof(void*) #define DYN_BOTTOM ((void*)1) #define DYN_FRAME ((void*)2) #define AE_LITTLE_ENDIAN 1 #define AE_BIG_ENDIAN 2 #define AE_MIXED_ENDIAN 3 #define AE_SER_ENTRY_LENGTH 11 #define AE_SER_ENTRIES_PER_ROW 5 #define AE_SM_DEFAULT 0 #define AE_SM_ALLOC 1 #define AE_SM_READY2S 2 #define AE_SM_TO_STRING 10 #define AE_SM_FROM_STRING 20 #define AE_SM_TO_CPPSTRING 11 #define AE_LOCK_CYCLES 512 #define AE_LOCK_TESTS_BEFORE_YIELD 16 #define AE_CRITICAL_ASSERT(x) if( !(x) ) abort() /************************************************************************* Lock. This is internal structure which implements lock functionality. *************************************************************************/ typedef struct { #if AE_OS==AE_WINDOWS volatile ae_int_t * volatile p_lock; char buf[sizeof(ae_int_t)+AE_LOCK_ALIGNMENT]; #elif AE_OS==AE_POSIX pthread_mutex_t mutex; #else ae_bool is_locked; #endif } _lock; /* * alloc counter */ ae_int64_t _alloc_counter = 0; ae_bool _use_alloc_counter = ae_false; #ifdef AE_SMP_DEBUGCOUNTERS __declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_acquisitions = 0; __declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_spinwaits = 0; __declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_yields = 0; #endif /* * These declarations are used to ensure that * sizeof(ae_bool)=1, sizeof(ae_int32_t)==4, sizeof(ae_int64_t)==8, sizeof(ae_int_t)==sizeof(void*). * they will lead to syntax error otherwise (array size will be negative). * * you can remove them, if you want - they are not used anywhere. * */ static char _ae_bool_must_be_8_bits_wide[1-2*((int)(sizeof(ae_bool))-1)*((int)(sizeof(ae_bool))-1)]; static char _ae_int32_t_must_be_32_bits_wide[1-2*((int)(sizeof(ae_int32_t))-4)*((int)(sizeof(ae_int32_t))-4)]; static char _ae_int64_t_must_be_64_bits_wide[1-2*((int)(sizeof(ae_int64_t))-8)*((int)(sizeof(ae_int64_t))-8)]; static char _ae_int_t_must_be_pointer_sized [1-2*((int)(sizeof(ae_int_t))-(int)sizeof(void*))*((int)(sizeof(ae_int_t))-(int)(sizeof(void*)))]; /* * This variable is used to prevent some tricky optimizations which may degrade multithreaded performance. * It is touched once in the ae_init_pool() function from smp.c in order to prevent optimizations. * */ static volatile ae_int_t ae_never_change_it = 1; ae_int_t ae_misalignment(const void *ptr, size_t alignment) { union _u { const void *ptr; ae_int_t iptr; } u; u.ptr = ptr; return (ae_int_t)(u.iptr%alignment); } void* ae_align(void *ptr, size_t alignment) { char *result = (char*)ptr; if( (result-(char*)0)%alignment!=0 ) result += alignment - (result-(char*)0)%alignment; return result; } /************************************************************************* This function abnormally aborts program, using one of several ways: * for AE_USE_CPP_ERROR_HANDLING being NOT defined: * for state!=NULL and state->break_jump being initialized with call to ae_state_set_break_jump() - it performs longjmp() to return site. * otherwise, abort() is called * for AE_USE_CPP_ERROR_HANDLING being DEFINED - an instance of ae_error_type() class is throw'ed. In all cases, for state!=NULL function sets state->last_error and state->error_msg fields. It also clears state with ae_state_clear(). If state is not NULL and state->thread_exception_handler is set, it is called prior to handling error and clearing state. *************************************************************************/ void ae_break(ae_state *state, ae_error_type error_type, const char *msg) { #ifndef AE_USE_CPP_ERROR_HANDLING if( state!=NULL ) { if( state->thread_exception_handler!=NULL ) state->thread_exception_handler(state); ae_state_clear(state); state->last_error = error_type; state->error_msg = msg; if( state->break_jump!=NULL ) longjmp(*(state->break_jump), 1); else abort(); } else abort(); #else if( state!=NULL ) { if( state->thread_exception_handler!=NULL ) state->thread_exception_handler(state); ae_state_clear(state); state->last_error = error_type; state->error_msg = msg; } throw error_type; #endif } void* aligned_malloc(size_t size, size_t alignment) { if( size==0 ) return NULL; if( alignment<=1 ) { /* no alignment, just call malloc */ void *block; void **p; ; block = malloc(sizeof(void*)+size); if( block==NULL ) return NULL; p = (void**)block; *p = block; if( _use_alloc_counter ) { #if AE_OS==AE_WINDOWS InterlockedIncrement((LONG volatile *)&_alloc_counter); #else #endif } return (void*)((char*)block+sizeof(void*)); } else { /* align */ void *block; char *result; block = malloc(alignment-1+sizeof(void*)+size); if( block==NULL ) return NULL; result = (char*)block+sizeof(void*); /*if( (result-(char*)0)%alignment!=0 ) result += alignment - (result-(char*)0)%alignment;*/ result = (char*)ae_align(result, alignment); *((void**)(result-sizeof(void*))) = block; if( _use_alloc_counter ) { #if AE_OS==AE_WINDOWS InterlockedIncrement((LONG volatile *)&_alloc_counter); #else #endif } return result; } } void aligned_free(void *block) { void *p; if( block==NULL ) return; p = *((void**)((char*)block-sizeof(void*))); free(p); if( _use_alloc_counter ) { #if AE_OS==AE_WINDOWS InterlockedDecrement((LONG volatile *)&_alloc_counter); #else #endif } } /************************************************************************ Malloc's memory with automatic alignment. Returns NULL when zero size is specified. Error handling: * if state is NULL, returns NULL on allocation error * if state is not NULL, calls ae_break() on allocation error ************************************************************************/ void* ae_malloc(size_t size, ae_state *state) { void *result; if( size==0 ) return NULL; result = aligned_malloc(size,AE_DATA_ALIGN); if( result==NULL && state!=NULL) ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); return result; } void ae_free(void *p) { if( p!=NULL ) aligned_free(p); } /************************************************************************ Sets pointers to the matrix rows. * dst must be correctly initialized matrix * dst->data.ptr points to the beginning of memory block allocated for row pointers. * dst->ptr - undefined (initialized during algorithm processing) * storage parameter points to the beginning of actual storage ************************************************************************/ void ae_matrix_update_row_pointers(ae_matrix *dst, void *storage) { char *p_base; void **pp_ptr; ae_int_t i; if( dst->rows>0 && dst->cols>0 ) { p_base = (char*)storage; pp_ptr = (void**)dst->data.ptr; dst->ptr.pp_void = pp_ptr; for(i=0; irows; i++, p_base+=dst->stride*ae_sizeof(dst->datatype)) pp_ptr[i] = p_base; } else dst->ptr.pp_void = NULL; } /************************************************************************ Returns size of datatype. Zero for dynamic types like strings or multiple precision types. ************************************************************************/ ae_int_t ae_sizeof(ae_datatype datatype) { switch(datatype) { case DT_BOOL: return (ae_int_t)sizeof(ae_bool); case DT_INT: return (ae_int_t)sizeof(ae_int_t); case DT_REAL: return (ae_int_t)sizeof(double); case DT_COMPLEX: return 2*(ae_int_t)sizeof(double); default: return 0; } } /************************************************************************ This dummy function is used to prevent compiler messages about unused locals in automatically generated code. It makes nothing - just accepts pointer, "touches" it - and that is all. It performs several tricky operations without side effects which confuse compiler so it does not compain about unused locals in THIS function. ************************************************************************/ void ae_touch_ptr(void *p) { void * volatile fake_variable0 = p; void * volatile fake_variable1 = fake_variable0; fake_variable0 = fake_variable1; } /************************************************************************ This function initializes ALGLIB environment state. NOTES: * stacks contain no frames, so ae_make_frame() must be called before attaching dynamic blocks. Without it ae_leave_frame() will cycle forever (which is intended behavior). ************************************************************************/ void ae_state_init(ae_state *state) { ae_int32_t *vp; /* * p_next points to itself because: * * correct program should be able to detect end of the list * by looking at the ptr field. * * NULL p_next may be used to distinguish automatic blocks * (in the list) from non-automatic (not in the list) */ state->last_block.p_next = &(state->last_block); state->last_block.deallocator = NULL; state->last_block.ptr = DYN_BOTTOM; state->p_top_block = &(state->last_block); #ifndef AE_USE_CPP_ERROR_HANDLING state->break_jump = NULL; #endif state->error_msg = ""; /* * determine endianness and initialize precomputed IEEE special quantities. */ state->endianness = ae_get_endianness(); if( state->endianness==AE_LITTLE_ENDIAN ) { vp = (ae_int32_t*)(&state->v_nan); vp[0] = 0; vp[1] = (ae_int32_t)0x7FF80000; vp = (ae_int32_t*)(&state->v_posinf); vp[0] = 0; vp[1] = (ae_int32_t)0x7FF00000; vp = (ae_int32_t*)(&state->v_neginf); vp[0] = 0; vp[1] = (ae_int32_t)0xFFF00000; } else if( state->endianness==AE_BIG_ENDIAN ) { vp = (ae_int32_t*)(&state->v_nan); vp[1] = 0; vp[0] = (ae_int32_t)0x7FF80000; vp = (ae_int32_t*)(&state->v_posinf); vp[1] = 0; vp[0] = (ae_int32_t)0x7FF00000; vp = (ae_int32_t*)(&state->v_neginf); vp[1] = 0; vp[0] = (ae_int32_t)0xFFF00000; } else abort(); /* * set threading information */ state->worker_thread = NULL; state->parent_task = NULL; state->thread_exception_handler = NULL; } /************************************************************************ This function clears ALGLIB environment state. All dynamic data controlled by state are freed. ************************************************************************/ void ae_state_clear(ae_state *state) { while( state->p_top_block->ptr!=DYN_BOTTOM ) ae_frame_leave(state); } #ifndef AE_USE_CPP_ERROR_HANDLING /************************************************************************ This function sets jump buffer for error handling. buf may be NULL. ************************************************************************/ void ae_state_set_break_jump(ae_state *state, jmp_buf *buf) { state->break_jump = buf; } #endif /************************************************************************ This function makes new stack frame. This function takes two parameters: environment state and pointer to the dynamic block which will be used as indicator of the frame beginning. This dynamic block must be initialized by caller and mustn't be changed/ deallocated/reused till ae_leave_frame called. It may be global or local variable (local is even better). ************************************************************************/ void ae_frame_make(ae_state *state, ae_frame *tmp) { tmp->db_marker.p_next = state->p_top_block; tmp->db_marker.deallocator = NULL; tmp->db_marker.ptr = DYN_FRAME; state->p_top_block = &tmp->db_marker; } /************************************************************************ This function leaves current stack frame and deallocates all automatic dynamic blocks which were attached to this frame. ************************************************************************/ void ae_frame_leave(ae_state *state) { while( state->p_top_block->ptr!=DYN_FRAME && state->p_top_block->ptr!=DYN_BOTTOM) { if( state->p_top_block->ptr!=NULL && state->p_top_block->deallocator!=NULL) ((ae_deallocator)(state->p_top_block->deallocator))(state->p_top_block->ptr); state->p_top_block = state->p_top_block->p_next; } state->p_top_block = state->p_top_block->p_next; } /************************************************************************ This function attaches block to the dynamic block list block block state ALGLIB environment state NOTES: * never call it for special blocks which marks frame boundaries! ************************************************************************/ void ae_db_attach(ae_dyn_block *block, ae_state *state) { block->p_next = state->p_top_block; state->p_top_block = block; } /************************************************************************ This function malloc's dynamic block: block destination block, assumed to be uninitialized size size (in bytes) state ALGLIB environment state. May be NULL. make_automatic if true, vector is added to the dynamic block list block is assumed to be uninitialized, its fields are ignored. Error handling: * if state is NULL, returns ae_false on allocation error * if state is not NULL, calls ae_break() on allocation error * returns ae_true on success NOTES: * never call it for blocks which are already in the list ************************************************************************/ ae_bool ae_db_malloc(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic) { /* ensure that size is >=0 two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ if( state!=NULL ) ae_assert(size>=0, "ae_db_malloc(): negative size", state); if( size<0 ) return ae_false; /* allocation */ block->ptr = ae_malloc((size_t)size, state); if( block->ptr==NULL && size!=0 ) { /* for state!=NULL exception is thrown from ae_malloc(), so we have to handle only situation when state is NULL */ return ae_false; } if( make_automatic && state!=NULL ) ae_db_attach(block, state); else block->p_next = NULL; block->deallocator = ae_free; return ae_true; } /************************************************************************ This function realloc's dynamic block: block destination block (initialized) size new size (in bytes) state ALGLIB environment state block is assumed to be initialized. This function: * deletes old contents * preserves automatic state Error handling: * if state is NULL, returns ae_false on allocation error * if state is not NULL, calls ae_break() on allocation error * returns ae_true on success NOTES: * never call it for special blocks which mark frame boundaries! ************************************************************************/ ae_bool ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state) { /* ensure that size is >=0 two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ if( state!=NULL ) ae_assert(size>=0, "ae_db_realloc(): negative size", state); if( size<0 ) return ae_false; /* realloc */ if( block->ptr!=NULL ) ((ae_deallocator)block->deallocator)(block->ptr); block->ptr = ae_malloc((size_t)size, state); if( block->ptr==NULL && size!=0 ) { /* for state!=NULL exception is thrown from ae_malloc(), so we have to handle only situation when state is NULL */ return ae_false; } block->deallocator = ae_free; return ae_true; } /************************************************************************ This function clears dynamic block (releases all dynamically allocated memory). Dynamic block may be in automatic management list - in this case it will NOT be removed from list. block destination block (initialized) NOTES: * never call it for special blocks which marks frame boundaries! ************************************************************************/ void ae_db_free(ae_dyn_block *block) { if( block->ptr!=NULL ) ((ae_deallocator)block->deallocator)(block->ptr); block->ptr = NULL; block->deallocator = ae_free; } /************************************************************************ This function swaps contents of two dynamic blocks (pointers and deallocators) leaving other parameters (automatic management settings, etc.) unchanged. NOTES: * never call it for special blocks which marks frame boundaries! ************************************************************************/ void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2) { void (*deallocator)(void*) = NULL; void * volatile ptr; ptr = block1->ptr; deallocator = block1->deallocator; block1->ptr = block2->ptr; block1->deallocator = block2->deallocator; block2->ptr = ptr; block2->deallocator = deallocator; } /************************************************************************* This function creates ae_vector. Vector size may be zero. Vector contents is uninitialized. dst destination vector, assumed to be uninitialized, its fields are ignored. size vector size, may be zero datatype guess what... state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure (size<0 or unable to allocate memory) - calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is *************************************************************************/ void ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state) { /* ensure that size is >=0 two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ ae_assert( size>=0, "ae_vector_init(): negative size", NULL); /* init */ dst->cnt = size; dst->datatype = datatype; ae_assert( ae_db_malloc(&dst->data, size*ae_sizeof(datatype), state, state!=NULL), /* TODO: change ae_db_malloc() */ "ae_vector_init(): failed to allocate memory", NULL); dst->ptr.p_ptr = dst->data.ptr; dst->is_attached = ae_false; } /************************************************************************ This function creates copy of ae_vector. New copy of the data is created, which is managed and owned by newly initialized vector. dst destination vector src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_vector_init_copy(ae_vector *dst, ae_vector *src, ae_state *state) { ae_vector_init(dst, src->cnt, src->datatype, state); if( src->cnt!=0 ) memcpy(dst->ptr.p_ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); } /************************************************************************ This function initializes ae_vector using X-structure as source. New copy of data is created, which is owned/managed by ae_vector structure. Both structures (source and destination) remain completely independent after this call. dst destination matrix src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state) { ae_vector_init(dst, (ae_int_t)src->cnt, (ae_datatype)src->datatype, state); if( src->cnt>0 ) memcpy(dst->ptr.p_ptr, src->ptr, (size_t)(((ae_int_t)src->cnt)*ae_sizeof((ae_datatype)src->datatype))); } /************************************************************************ This function initializes ae_vector using X-structure as source. New vector is attached to source: * DST shares memory with SRC * both DST and SRC are writable - all writes to DST change elements of SRC and vice versa. * DST can be reallocated with ae_vector_set_length(), in this case SRC remains untouched * SRC, however, CAN NOT BE REALLOCATED AS LONG AS DST EXISTS NOTE: is_attached field is set to ae_true in order to indicate that vector does not own its memory. dst destination vector src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_vector_attach_to_x(ae_vector *dst, x_vector *src, ae_state *state) { volatile ae_int_t cnt; cnt = (ae_int_t)src->cnt; /* ensure that size is correct */ ae_assert(cnt==src->cnt, "ae_vector_attach_to_x(): 32/64 overflow", NULL); ae_assert(cnt>=0, "ae_vector_attach_to_x(): negative length", NULL); /* init */ dst->cnt = cnt; dst->datatype = (ae_datatype)src->datatype; dst->ptr.p_ptr = src->ptr; dst->is_attached = ae_true; ae_assert( ae_db_malloc(&dst->data, 0, state, state!=NULL), "ae_vector_attach_to_x(): malloc error", NULL); } /************************************************************************ This function changes length of ae_vector. dst destination vector newsize vector size, may be zero state ALGLIB environment state Error handling: * if state is NULL, returns ae_false on allocation error * if state is not NULL, calls ae_break() on allocation error * returns ae_true on success NOTES: * vector must be initialized * all contents is destroyed during setlength() call * new size may be zero. ************************************************************************/ ae_bool ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state) { /* ensure that size is >=0 two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ if( state!=NULL ) ae_assert(newsize>=0, "ae_vector_set_length(): negative size", state); if( newsize<0 ) return ae_false; /* set length */ if( dst->cnt==newsize ) return ae_true; dst->cnt = newsize; if( !ae_db_realloc(&dst->data, newsize*ae_sizeof(dst->datatype), state) ) return ae_false; dst->ptr.p_ptr = dst->data.ptr; return ae_true; } /************************************************************************ This function provides "CLEAR" functionality for vector (contents is cleared, but structure still left in valid state). The function clears vector contents (releases all dynamically allocated memory). Vector may be in automatic management list - in this case it will NOT be removed from list. IMPORTANT: this function does NOT invalidates dst; it just releases all dynamically allocated storage, but dst still may be used after call to ae_vector_set_length(). dst destination vector ************************************************************************/ void ae_vector_clear(ae_vector *dst) { dst->cnt = 0; ae_db_free(&dst->data); dst->ptr.p_ptr = 0; dst->is_attached = ae_false; } /************************************************************************ This function provides "DESTROY" functionality for vector (contents is cleared, all internal structures are destroyed). For vectors it is same as CLEAR. dst destination vector ************************************************************************/ void ae_vector_destroy(ae_vector *dst) { ae_vector_clear(dst); } /************************************************************************ This function efficiently swaps contents of two vectors, leaving other pararemeters (automatic management, etc.) unchanged. ************************************************************************/ void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2) { ae_int_t cnt; ae_datatype datatype; void *p_ptr; ae_assert(!vec1->is_attached, "ALGLIB: internal error, attempt to swap vectors attached to X-object", NULL); ae_assert(!vec2->is_attached, "ALGLIB: internal error, attempt to swap vectors attached to X-object", NULL); ae_db_swap(&vec1->data, &vec2->data); cnt = vec1->cnt; datatype = vec1->datatype; p_ptr = vec1->ptr.p_ptr; vec1->cnt = vec2->cnt; vec1->datatype = vec2->datatype; vec1->ptr.p_ptr = vec2->ptr.p_ptr; vec2->cnt = cnt; vec2->datatype = datatype; vec2->ptr.p_ptr = p_ptr; } /************************************************************************ This function creates ae_matrix. Matrix size may be zero, in such cases both rows and cols are zero. Matrix contents is uninitialized. dst destination matrix, assumed to be unitialized, its fields are ignored rows rows count cols cols count datatype element type state depending on your desire to register matrix in the current frame: * pointer to ALGLIB environment state, if you want the matrix to be automatically managed * NULL, if you do not want it to be automatically managed Error handling: * calls ae_break() with NULL state; usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state) { ae_assert(rows>=0 && cols>=0, "ae_matrix_init(): negative length", NULL); /* if one of rows/cols is zero, another MUST be too */ if( rows==0 || cols==0 ) { rows = 0; cols = 0; } /* init */ dst->is_attached = ae_false; dst->rows = rows; dst->cols = cols; dst->stride = cols; while( dst->stride*ae_sizeof(datatype)%AE_DATA_ALIGN!=0 ) dst->stride++; dst->datatype = datatype; ae_assert( ae_db_malloc(&dst->data, dst->rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(datatype))+AE_DATA_ALIGN-1, state, state!=NULL), /* TODO: change ae_db_malloc() */ "ae_matrix_init(): failed to allocate memory", NULL); ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+dst->rows*sizeof(void*),AE_DATA_ALIGN)); } /************************************************************************ This function creates copy of ae_matrix. A new copy of the data is created. dst destination matrix src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_matrix_init_copy(ae_matrix *dst, ae_matrix *src, ae_state *state) { ae_int_t i; ae_matrix_init(dst, src->rows, src->cols, src->datatype, state); if( src->rows!=0 && src->cols!=0 ) { if( dst->stride==src->stride ) memcpy(dst->ptr.pp_void[0], src->ptr.pp_void[0], (size_t)(src->rows*src->stride*ae_sizeof(src->datatype))); else for(i=0; irows; i++) memcpy(dst->ptr.pp_void[i], src->ptr.pp_void[i], (size_t)(dst->cols*ae_sizeof(dst->datatype))); } } /************************************************************************ This function initializes ae_matrix using X-structure as source. New copy of data is created, which is owned/managed by ae_matrix structure. Both structures (source and destination) remain completely independent after this call. dst destination matrix src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state) { char *p_src_row; char *p_dst_row; ae_int_t row_size; ae_int_t i; ae_matrix_init(dst, (ae_int_t)src->rows, (ae_int_t)src->cols, (ae_datatype)src->datatype, state); if( src->rows!=0 && src->cols!=0 ) { p_src_row = (char*)src->ptr; p_dst_row = (char*)(dst->ptr.pp_void[0]); row_size = ae_sizeof((ae_datatype)src->datatype)*(ae_int_t)src->cols; for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof((ae_datatype)src->datatype), p_dst_row+=dst->stride*ae_sizeof((ae_datatype)src->datatype)) memcpy(p_dst_row, p_src_row, (size_t)(row_size)); } } /************************************************************************ This function initializes ae_matrix using X-structure as source. New matrix is attached to source: * DST shares memory with SRC * both DST and SRC are writable - all writes to DST change elements of SRC and vice versa. * DST can be reallocated with ae_matrix_set_length(), in this case SRC remains untouched * SRC, however, CAN NOT BE REALLOCATED AS LONG AS DST EXISTS dst destination matrix src well, it is source state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_matrix_attach_to_x(ae_matrix *dst, x_matrix *src, ae_state *state) { ae_int_t rows, cols; rows = (ae_int_t)src->rows; cols = (ae_int_t)src->cols; /* ensure that size is correct */ ae_assert(rows==src->rows, "ae_matrix_attach_to_x(): 32/64 overflow", NULL); ae_assert(cols==src->cols, "ae_matrix_attach_to_x(): 32/64 overflow", NULL); ae_assert(rows>=0 && cols>=0, "ae_matrix_attach_to_x(): negative length", NULL); /* if one of rows/cols is zero, another MUST be too */ if( rows==0 || cols==0 ) { rows = 0; cols = 0; } /* init */ dst->is_attached = ae_true; dst->rows = rows; dst->cols = cols; dst->stride = cols; dst->datatype = (ae_datatype)src->datatype; dst->ptr.pp_void = NULL; ae_assert( ae_db_malloc(&dst->data, dst->rows*(ae_int_t)sizeof(void*), state, state!=NULL), "ae_matrix_attach_to_x(): malloc error", NULL); if( dst->rows>0 && dst->cols>0 ) { ae_int_t i, rowsize; char *p_row; void **pp_ptr; p_row = (char*)src->ptr; rowsize = dst->stride*ae_sizeof(dst->datatype); pp_ptr = (void**)dst->data.ptr; dst->ptr.pp_void = pp_ptr; for(i=0; irows; i++, p_row+=rowsize) pp_ptr[i] = p_row; } } /************************************************************************ This function changes length of ae_matrix. dst destination matrix rows size, may be zero cols size, may be zero state ALGLIB environment state Error handling: * if state is NULL, returns ae_false on allocation error * if state is not NULL, calls ae_break() on allocation error * returns ae_true on success NOTES: * matrix must be initialized * all contents is destroyed during setlength() call * new size may be zero. ************************************************************************/ ae_bool ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state) { /* ensure that size is >=0 two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ if( state!=NULL ) ae_assert(rows>=0 && cols>=0, "ae_matrix_set_length(): negative length", state); if( rows<0 || cols<0 ) return ae_false; if( dst->rows==rows && dst->cols==cols ) return ae_true; dst->rows = rows; dst->cols = cols; dst->stride = cols; while( dst->stride*ae_sizeof(dst->datatype)%AE_DATA_ALIGN!=0 ) dst->stride++; if( !ae_db_realloc(&dst->data, dst->rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(dst->datatype))+AE_DATA_ALIGN-1, state) ) return ae_false; ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+dst->rows*sizeof(void*),AE_DATA_ALIGN)); return ae_true; } /************************************************************************ This function provides "CLEAR" functionality for vector (contents is cleared, but structure still left in valid state). The function clears matrix contents (releases all dynamically allocated memory). Matrix may be in automatic management list - in this case it will NOT be removed from list. IMPORTANT: this function does NOT invalidates dst; it just releases all dynamically allocated storage, but dst still may be used after call to ae_matrix_set_length(). dst destination matrix ************************************************************************/ void ae_matrix_clear(ae_matrix *dst) { dst->rows = 0; dst->cols = 0; dst->stride = 0; ae_db_free(&dst->data); dst->ptr.p_ptr = 0; dst->is_attached = ae_false; } /************************************************************************ This function provides "DESTROY" functionality for matrix (contents is cleared, but structure still left in valid state). For matrices it is same as CLEAR. dst destination matrix ************************************************************************/ void ae_matrix_destroy(ae_matrix *dst) { ae_matrix_clear(dst); } /************************************************************************ This function efficiently swaps contents of two vectors, leaving other pararemeters (automatic management, etc.) unchanged. ************************************************************************/ void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2) { ae_int_t rows; ae_int_t cols; ae_int_t stride; ae_datatype datatype; void *p_ptr; ae_assert(!mat1->is_attached, "ALGLIB: internal error, attempt to swap matrices attached to X-object", NULL); ae_assert(!mat2->is_attached, "ALGLIB: internal error, attempt to swap matrices attached to X-object", NULL); ae_db_swap(&mat1->data, &mat2->data); rows = mat1->rows; cols = mat1->cols; stride = mat1->stride; datatype = mat1->datatype; p_ptr = mat1->ptr.p_ptr; mat1->rows = mat2->rows; mat1->cols = mat2->cols; mat1->stride = mat2->stride; mat1->datatype = mat2->datatype; mat1->ptr.p_ptr = mat2->ptr.p_ptr; mat2->rows = rows; mat2->cols = cols; mat2->stride = stride; mat2->datatype = datatype; mat2->ptr.p_ptr = p_ptr; } /************************************************************************ This function creates smart pointer structure. dst destination smart pointer. already allocated, but not initialized. subscriber pointer to pointer which receives updates in the internal object stored in ae_smart_ptr. Any update to dst->ptr is translated to subscriber. Can be NULL. state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. After initialization, smart pointer stores NULL pointer. ************************************************************************/ void ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_state *state) { dst->subscriber = subscriber; dst->ptr = NULL; if( dst->subscriber!=NULL ) *(dst->subscriber) = dst->ptr; dst->is_owner = ae_false; dst->is_dynamic = ae_false; dst->frame_entry.deallocator = ae_smart_ptr_destroy; dst->frame_entry.ptr = dst; if( state!=NULL ) ae_db_attach(&dst->frame_entry, state); } /************************************************************************ This function clears smart pointer structure. dst destination smart pointer. After call to this function smart pointer contains NULL reference, which is propagated to its subscriber (in cases non-NULL subscruber was specified during pointer creation). ************************************************************************/ void ae_smart_ptr_clear(void *_dst) { ae_smart_ptr *dst = (ae_smart_ptr*)_dst; if( dst->is_owner && dst->ptr!=NULL ) { dst->destroy(dst->ptr); if( dst->is_dynamic ) ae_free(dst->ptr); } dst->is_owner = ae_false; dst->is_dynamic = ae_false; dst->ptr = NULL; dst->destroy = NULL; if( dst->subscriber!=NULL ) *(dst->subscriber) = NULL; } /************************************************************************ This function dstroys smart pointer structure (same as clearing it). dst destination smart pointer. ************************************************************************/ void ae_smart_ptr_destroy(void *_dst) { ae_smart_ptr_clear(_dst); } /************************************************************************ This function assigns pointer to ae_smart_ptr structure. dst destination smart pointer. new_ptr new pointer to assign is_owner whether smart pointer owns new_ptr is_dynamic whether object is dynamic - clearing such object requires BOTH calling destructor function AND calling ae_free() for memory occupied by object. destroy destructor function In case smart pointer already contains non-NULL value and owns this value, it is freed before assigning new pointer. Changes in pointer are propagated to its subscriber (in case non-NULL subscriber was specified during pointer creation). You can specify NULL new_ptr, in which case is_owner/destroy are ignored. ************************************************************************/ void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, void (*destroy)(void*)) { if( dst->is_owner && dst->ptr!=NULL ) dst->destroy(dst->ptr); if( new_ptr!=NULL ) { dst->ptr = new_ptr; dst->is_owner = is_owner; dst->is_dynamic = is_dynamic; dst->destroy = destroy; } else { dst->ptr = NULL; dst->is_owner = ae_false; dst->is_dynamic = ae_false; dst->destroy = NULL; } if( dst->subscriber!=NULL ) *(dst->subscriber) = dst->ptr; } /************************************************************************ This function releases pointer owned by ae_smart_ptr structure: * all internal fields are set to NULL * destructor function for internal pointer is NOT called even when we own this pointer. After this call ae_smart_ptr releases ownership of its pointer and passes it to caller. * changes in pointer are propagated to its subscriber (in case non-NULL subscriber was specified during pointer creation). dst destination smart pointer. ************************************************************************/ void ae_smart_ptr_release(ae_smart_ptr *dst) { dst->is_owner = ae_false; dst->is_dynamic = ae_false; dst->ptr = NULL; dst->destroy = NULL; if( dst->subscriber!=NULL ) *(dst->subscriber) = NULL; } /************************************************************************ This function copies contents of ae_vector (SRC) to x_vector (DST). This function should not be called for DST which is attached to SRC (opposite situation, when SRC is attached to DST, is possible). Depending on situation, following actions are performed * for SRC attached to DST, this function performs no actions (no need to do anything) * for independent vectors of different sizes it allocates storage in DST and copy contents of SRC to DST. DST->last_action field is set to ACT_NEW_LOCATION, and DST->owner is set to OWN_AE. * for independent vectors of same sizes it does not perform memory (re)allocation. It just copies SRC to already existing place. DST->last_action is set to ACT_SAME_LOCATION (unless it was ACT_NEW_LOCATION), DST->owner is unmodified. dst destination vector src source, vector in x-format state ALGLIB environment state NOTES: * dst is assumed to be initialized. Its contents is freed before copying data from src (if size / type are different) or overwritten (if possible given destination size). ************************************************************************/ void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state) { if( src->ptr.p_ptr == dst->ptr ) { /* src->ptr points to the beginning of dst, attached matrices, no need to copy */ return; } if( dst->cnt!=src->cnt || dst->datatype!=src->datatype ) { if( dst->owner==OWN_AE ) ae_free(dst->ptr); dst->ptr = ae_malloc((size_t)(src->cnt*ae_sizeof(src->datatype)), state); if( src->cnt!=0 && dst->ptr==NULL ) ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); dst->last_action = ACT_NEW_LOCATION; dst->cnt = src->cnt; dst->datatype = src->datatype; dst->owner = OWN_AE; } else { if( dst->last_action==ACT_UNCHANGED ) dst->last_action = ACT_SAME_LOCATION; else if( dst->last_action==ACT_SAME_LOCATION ) dst->last_action = ACT_SAME_LOCATION; else if( dst->last_action==ACT_NEW_LOCATION ) dst->last_action = ACT_NEW_LOCATION; else ae_assert(ae_false, "ALGLIB: internal error in ae_x_set_vector()", state); } if( src->cnt ) memcpy(dst->ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); } /************************************************************************ This function copies contents of ae_matrix to x_matrix. This function should not be called for DST which is attached to SRC (opposite situation, when SRC is attached to DST, is possible). Depending on situation, following actions are performed * for SRC attached to DST, this function performs no actions (no need to do anything) * for independent matrices of different sizes it allocates storage in DST and copy contents of SRC to DST. DST->last_action field is set to ACT_NEW_LOCATION, and DST->owner is set to OWN_AE. * for independent matrices of same sizes it does not perform memory (re)allocation. It just copies SRC to already existing place. DST->last_action is set to ACT_SAME_LOCATION (unless it was ACT_NEW_LOCATION), DST->owner is unmodified. dst destination vector src source, matrix in x-format state ALGLIB environment state NOTES: * dst is assumed to be initialized. Its contents is freed before copying data from src (if size / type are different) or overwritten (if possible given destination size). ************************************************************************/ void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state) { char *p_src_row; char *p_dst_row; ae_int_t i; ae_int_t row_size; if( src->ptr.pp_void!=NULL && src->ptr.pp_void[0] == dst->ptr ) { /* src->ptr points to the beginning of dst, attached matrices, no need to copy */ return; } if( dst->rows!=src->rows || dst->cols!=src->cols || dst->datatype!=src->datatype ) { if( dst->owner==OWN_AE ) ae_free(dst->ptr); dst->rows = src->rows; dst->cols = src->cols; dst->stride = src->cols; dst->datatype = src->datatype; dst->ptr = ae_malloc((size_t)(dst->rows*((ae_int_t)dst->stride)*ae_sizeof(src->datatype)), state); if( dst->rows!=0 && dst->stride!=0 && dst->ptr==NULL ) ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); dst->last_action = ACT_NEW_LOCATION; dst->owner = OWN_AE; } else { if( dst->last_action==ACT_UNCHANGED ) dst->last_action = ACT_SAME_LOCATION; else if( dst->last_action==ACT_SAME_LOCATION ) dst->last_action = ACT_SAME_LOCATION; else if( dst->last_action==ACT_NEW_LOCATION ) dst->last_action = ACT_NEW_LOCATION; else ae_assert(ae_false, "ALGLIB: internal error in ae_x_set_vector()", state); } if( src->rows!=0 && src->cols!=0 ) { p_src_row = (char*)(src->ptr.pp_void[0]); p_dst_row = (char*)dst->ptr; row_size = ae_sizeof(src->datatype)*src->cols; for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof(src->datatype), p_dst_row+=dst->stride*ae_sizeof(src->datatype)) memcpy(p_dst_row, p_src_row, (size_t)(row_size)); } } /************************************************************************ This function attaches x_vector to ae_vector's contents. Ownership of memory allocated is not changed (it is still managed by ae_matrix). dst destination vector src source, vector in x-format state ALGLIB environment state NOTES: * dst is assumed to be initialized. Its contents is freed before attaching to src. * this function doesn't need ae_state parameter because it can't fail (assuming correctly initialized src) ************************************************************************/ void ae_x_attach_to_vector(x_vector *dst, ae_vector *src) { if( dst->owner==OWN_AE ) ae_free(dst->ptr); dst->ptr = src->ptr.p_ptr; dst->last_action = ACT_NEW_LOCATION; dst->cnt = src->cnt; dst->datatype = src->datatype; dst->owner = OWN_CALLER; } /************************************************************************ This function attaches x_matrix to ae_matrix's contents. Ownership of memory allocated is not changed (it is still managed by ae_matrix). dst destination vector src source, matrix in x-format state ALGLIB environment state NOTES: * dst is assumed to be initialized. Its contents is freed before attaching to src. * this function doesn't need ae_state parameter because it can't fail (assuming correctly initialized src) ************************************************************************/ void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src) { if( dst->owner==OWN_AE ) ae_free(dst->ptr); dst->rows = src->rows; dst->cols = src->cols; dst->stride = src->stride; dst->datatype = src->datatype; dst->ptr = &(src->ptr.pp_double[0][0]); dst->last_action = ACT_NEW_LOCATION; dst->owner = OWN_CALLER; } /************************************************************************ This function clears x_vector. It does nothing if vector is not owned by ALGLIB environment. dst vector ************************************************************************/ void x_vector_clear(x_vector *dst) { if( dst->owner==OWN_AE ) aligned_free(dst->ptr); dst->ptr = NULL; dst->cnt = 0; } /************************************************************************ Assertion For non-NULL state it allows to gracefully leave ALGLIB session, removing all frames and deallocating registered dynamic data structure. For NULL state it just abort()'s program. ************************************************************************/ void ae_assert(ae_bool cond, const char *msg, ae_state *state) { if( !cond ) ae_break(state, ERR_ASSERTION_FAILED, msg); } /************************************************************************ CPUID Returns information about features CPU and compiler support. You must tell ALGLIB what CPU family is used by defining AE_CPU symbol (without this hint zero will be returned). Note: results of this function depend on both CPU and compiler; if compiler doesn't support SSE intrinsics, function won't set corresponding flag. ************************************************************************/ static volatile ae_bool _ae_cpuid_initialized = ae_false; static volatile ae_bool _ae_cpuid_has_sse2 = ae_false; ae_int_t ae_cpuid() { /* * to speed up CPU detection we cache results from previous attempts * there is no synchronization, but it is still thread safe. * * thread safety is guaranteed on all modern architectures which * have following property: simultaneous writes by different cores * to the same location will be executed in serial manner. * */ ae_int_t result; /* * if not initialized, determine system properties */ if( !_ae_cpuid_initialized ) { /* * SSE2 */ #if defined(AE_CPU) #if (AE_CPU==AE_INTEL) && defined(AE_HAS_SSE2_INTRINSICS) #if AE_COMPILER==AE_MSVC { int CPUInfo[4]; __cpuid(CPUInfo, 1); if( (CPUInfo[3]&0x04000000)!=0 ) _ae_cpuid_has_sse2 = ae_true; } #elif AE_COMPILER==AE_GNUC { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); if( (d&0x04000000)!=0 ) _ae_cpuid_has_sse2 = ae_true; } #elif AE_COMPILER==AE_SUNC { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); if( (d&0x04000000)!=0 ) _ae_cpuid_has_sse2 = ae_true; } #else #endif #endif #endif /* * Perform one more CPUID call to generate memory fence */ #if AE_CPU==AE_INTEL #if AE_COMPILER==AE_MSVC { int CPUInfo[4]; __cpuid(CPUInfo, 1); } #elif AE_COMPILER==AE_GNUC { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); } #elif AE_COMPILER==AE_SUNC { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); } #else #endif #endif /* * set initialization flag */ _ae_cpuid_initialized = ae_true; } /* * return */ result = 0; if( _ae_cpuid_has_sse2 ) result = result|CPU_SSE2; return result; } /************************************************************************ Real math functions ************************************************************************/ ae_bool ae_fp_eq(double v1, double v2) { /* IEEE-strict floating point comparison */ volatile double x = v1; volatile double y = v2; return x==y; } ae_bool ae_fp_neq(double v1, double v2) { /* IEEE-strict floating point comparison */ return !ae_fp_eq(v1,v2); } ae_bool ae_fp_less(double v1, double v2) { /* IEEE-strict floating point comparison */ volatile double x = v1; volatile double y = v2; return xy; } ae_bool ae_fp_greater_eq(double v1, double v2) { /* IEEE-strict floating point comparison */ volatile double x = v1; volatile double y = v2; return x>=y; } ae_bool ae_isfinite_stateless(double x, ae_int_t endianness) { union _u { double a; ae_int32_t p[2]; } u; ae_int32_t high; u.a = x; if( endianness==AE_LITTLE_ENDIAN ) high = u.p[1]; else high = u.p[0]; return (high & (ae_int32_t)0x7FF00000)!=(ae_int32_t)0x7FF00000; } ae_bool ae_isnan_stateless(double x, ae_int_t endianness) { union _u { double a; ae_int32_t p[2]; } u; ae_int32_t high, low; u.a = x; if( endianness==AE_LITTLE_ENDIAN ) { high = u.p[1]; low = u.p[0]; } else { high = u.p[0]; low = u.p[1]; } return ((high &0x7FF00000)==0x7FF00000) && (((high &0x000FFFFF)!=0) || (low!=0)); } ae_bool ae_isinf_stateless(double x, ae_int_t endianness) { union _u { double a; ae_int32_t p[2]; } u; ae_int32_t high, low; u.a = x; if( endianness==AE_LITTLE_ENDIAN ) { high = u.p[1]; low = u.p[0]; } else { high = u.p[0]; low = u.p[1]; } /* 31 least significant bits of high are compared */ return ((high&0x7FFFFFFF)==0x7FF00000) && (low==0); } ae_bool ae_isposinf_stateless(double x, ae_int_t endianness) { union _u { double a; ae_int32_t p[2]; } u; ae_int32_t high, low; u.a = x; if( endianness==AE_LITTLE_ENDIAN ) { high = u.p[1]; low = u.p[0]; } else { high = u.p[0]; low = u.p[1]; } /* all 32 bits of high are compared */ return (high==(ae_int32_t)0x7FF00000) && (low==0); } ae_bool ae_isneginf_stateless(double x, ae_int_t endianness) { union _u { double a; ae_int32_t p[2]; } u; ae_int32_t high, low; u.a = x; if( endianness==AE_LITTLE_ENDIAN ) { high = u.p[1]; low = u.p[0]; } else { high = u.p[0]; low = u.p[1]; } /* this code is a bit tricky to avoid comparison of high with 0xFFF00000, which may be unsafe with some buggy compilers */ return ((high&0x7FFFFFFF)==0x7FF00000) && (high!=(ae_int32_t)0x7FF00000) && (low==0); } ae_int_t ae_get_endianness() { union { double a; ae_int32_t p[2]; } u; /* * determine endianness * two types are supported: big-endian and little-endian. * mixed-endian hardware is NOT supported. * * 1983 is used as magic number because its non-periodic double * representation allow us to easily distinguish between upper * and lower halfs and to detect mixed endian hardware. * */ u.a = 1.0/1983.0; if( u.p[1]==(ae_int32_t)0x3f408642 ) return AE_LITTLE_ENDIAN; if( u.p[0]==(ae_int32_t)0x3f408642 ) return AE_BIG_ENDIAN; return AE_MIXED_ENDIAN; } ae_bool ae_isfinite(double x,ae_state *state) { return ae_isfinite_stateless(x, state->endianness); } ae_bool ae_isnan(double x, ae_state *state) { return ae_isnan_stateless(x, state->endianness); } ae_bool ae_isinf(double x, ae_state *state) { return ae_isinf_stateless(x, state->endianness); } ae_bool ae_isposinf(double x,ae_state *state) { return ae_isposinf_stateless(x, state->endianness); } ae_bool ae_isneginf(double x,ae_state *state) { return ae_isneginf_stateless(x, state->endianness); } double ae_fabs(double x, ae_state *state) { return fabs(x); } ae_int_t ae_iabs(ae_int_t x, ae_state *state) { return x>=0 ? x : -x; } double ae_sqr(double x, ae_state *state) { return x*x; } double ae_sqrt(double x, ae_state *state) { return sqrt(x); } ae_int_t ae_sign(double x, ae_state *state) { if( x>0 ) return 1; if( x<0 ) return -1; return 0; } ae_int_t ae_round(double x, ae_state *state) { return (ae_int_t)(ae_ifloor(x+0.5,state)); } ae_int_t ae_trunc(double x, ae_state *state) { return (ae_int_t)(x>0 ? ae_ifloor(x,state) : ae_iceil(x,state)); } ae_int_t ae_ifloor(double x, ae_state *state) { return (ae_int_t)(floor(x)); } ae_int_t ae_iceil(double x, ae_state *state) { return (ae_int_t)(ceil(x)); } ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state) { return m1>m2 ? m1 : m2; } ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state) { return m1>m2 ? m2 : m1; } double ae_maxreal(double m1, double m2, ae_state *state) { return m1>m2 ? m1 : m2; } double ae_minreal(double m1, double m2, ae_state *state) { return m1>m2 ? m2 : m1; } double ae_randomreal(ae_state *state) { int i1 = rand(); int i2 = rand(); double mx = (double)(RAND_MAX)+1.0; volatile double tmp0 = i2/mx; volatile double tmp1 = i1+tmp0; return tmp1/mx; } ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state) { return rand()%maxv; } double ae_sin(double x, ae_state *state) { return sin(x); } double ae_cos(double x, ae_state *state) { return cos(x); } double ae_tan(double x, ae_state *state) { return tan(x); } double ae_sinh(double x, ae_state *state) { return sinh(x); } double ae_cosh(double x, ae_state *state) { return cosh(x); } double ae_tanh(double x, ae_state *state) { return tanh(x); } double ae_asin(double x, ae_state *state) { return asin(x); } double ae_acos(double x, ae_state *state) { return acos(x); } double ae_atan(double x, ae_state *state) { return atan(x); } double ae_atan2(double y, double x, ae_state *state) { return atan2(y,x); } double ae_log(double x, ae_state *state) { return log(x); } double ae_pow(double x, double y, ae_state *state) { return pow(x,y); } double ae_exp(double x, ae_state *state) { return exp(x); } /************************************************************************ Symmetric/Hermitian properties: check and force ************************************************************************/ static void x_split_length(ae_int_t n, ae_int_t nb, ae_int_t* n1, ae_int_t* n2) { ae_int_t r; if( n<=nb ) { *n1 = n; *n2 = 0; } else { if( n%nb!=0 ) { *n2 = n%nb; *n1 = n-(*n2); } else { *n2 = n/2; *n1 = n-(*n2); if( *n1%nb==0 ) { return; } r = nb-*n1%nb; *n1 = *n1+r; *n2 = *n2-r; } } } static double x_safepythag2(double x, double y) { double w; double xabs; double yabs; double z; xabs = fabs(x); yabs = fabs(y); w = xabs>yabs ? xabs : yabs; z = xabsx_nb || len1>x_nb ) { ae_int_t n1, n2; if( len0>len1 ) { x_split_length(len0, x_nb, &n1, &n2); is_symmetric_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); is_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); } else { x_split_length(len1, x_nb, &n1, &n2); is_symmetric_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); is_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); } return; } else { /* base case */ double *p1, *p2, *prow, *pcol; double v; ae_int_t i, j; p1 = (double*)(a->ptr)+offset0*a->stride+offset1; p2 = (double*)(a->ptr)+offset1*a->stride+offset0; for(i=0; istride; for(j=0; jv ? *mx : v; v = fabs(*prow); *mx = *mx>v ? *mx : v; v = fabs(*pcol-*prow); *err = *err>v ? *err : v; } pcol += a->stride; prow++; } } } } /* * this function checks that diagonal block A0 is symmetric. * Block A0 is specified by its offset and size. * * [ . ] * [ A0 ] * A = [ . ] * [ . ] * * this subroutine updates current values of: * a) mx maximum value of A[i,j] found so far * b) err componentwise difference between A0 and A0^T * */ static void is_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) { double *p, *prow, *pcol; double v; ae_int_t i, j; /* try to split problem into two smaller ones */ if( len>x_nb ) { ae_int_t n1, n2; x_split_length(len, x_nb, &n1, &n2); is_symmetric_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); is_symmetric_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); is_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); return; } /* base case */ p = (double*)(a->ptr)+offset*a->stride+offset; for(i=0; istride; for(j=0; jstride,prow++) { if( !ae_isfinite(*pcol,_state) || !ae_isfinite(*prow,_state) ) { *nonfinite = ae_true; } else { v = fabs(*pcol); *mx = *mx>v ? *mx : v; v = fabs(*prow); *mx = *mx>v ? *mx : v; v = fabs(*pcol-*prow); *err = *err>v ? *err : v; } } v = fabs(p[i+i*a->stride]); *mx = *mx>v ? *mx : v; } } /* * this function checks difference between offdiagonal blocks BL and BU * (see below). Block BL is specified by offsets (offset0,offset1) and * sizes (len0,len1). * * [ . ] * [ A0 BU ] * A = [ BL A1 ] * [ . ] * * this subroutine updates current values of: * a) mx maximum value of A[i,j] found so far * b) err componentwise difference between elements of BL and BU^H * */ static void is_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) { /* try to split problem into two smaller ones */ if( len0>x_nb || len1>x_nb ) { ae_int_t n1, n2; if( len0>len1 ) { x_split_length(len0, x_nb, &n1, &n2); is_hermitian_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); is_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); } else { x_split_length(len1, x_nb, &n1, &n2); is_hermitian_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); is_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); } return; } else { /* base case */ ae_complex *p1, *p2, *prow, *pcol; double v; ae_int_t i, j; p1 = (ae_complex*)(a->ptr)+offset0*a->stride+offset1; p2 = (ae_complex*)(a->ptr)+offset1*a->stride+offset0; for(i=0; istride; for(j=0; jx, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) { *nonfinite = ae_true; } else { v = x_safepythag2(pcol->x, pcol->y); *mx = *mx>v ? *mx : v; v = x_safepythag2(prow->x, prow->y); *mx = *mx>v ? *mx : v; v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); *err = *err>v ? *err : v; } pcol += a->stride; prow++; } } } } /* * this function checks that diagonal block A0 is Hermitian. * Block A0 is specified by its offset and size. * * [ . ] * [ A0 ] * A = [ . ] * [ . ] * * this subroutine updates current values of: * a) mx maximum value of A[i,j] found so far * b) err componentwise difference between A0 and A0^H * */ static void is_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) { ae_complex *p, *prow, *pcol; double v; ae_int_t i, j; /* try to split problem into two smaller ones */ if( len>x_nb ) { ae_int_t n1, n2; x_split_length(len, x_nb, &n1, &n2); is_hermitian_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); is_hermitian_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); is_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); return; } /* base case */ p = (ae_complex*)(a->ptr)+offset*a->stride+offset; for(i=0; istride; for(j=0; jstride,prow++) { if( !ae_isfinite(pcol->x, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) { *nonfinite = ae_true; } else { v = x_safepythag2(pcol->x, pcol->y); *mx = *mx>v ? *mx : v; v = x_safepythag2(prow->x, prow->y); *mx = *mx>v ? *mx : v; v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); *err = *err>v ? *err : v; } } if( !ae_isfinite(p[i+i*a->stride].x, _state) || !ae_isfinite(p[i+i*a->stride].y, _state) ) { *nonfinite = ae_true; } else { v = fabs(p[i+i*a->stride].x); *mx = *mx>v ? *mx : v; v = fabs(p[i+i*a->stride].y); *err = *err>v ? *err : v; } } } /* * this function copies offdiagonal block BL to its symmetric counterpart * BU (see below). Block BL is specified by offsets (offset0,offset1) * and sizes (len0,len1). * * [ . ] * [ A0 BU ] * A = [ BL A1 ] * [ . ] * */ static void force_symmetric_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) { /* try to split problem into two smaller ones */ if( len0>x_nb || len1>x_nb ) { ae_int_t n1, n2; if( len0>len1 ) { x_split_length(len0, x_nb, &n1, &n2); force_symmetric_rec_off_stat(a, offset0, offset1, n1, len1); force_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1); } else { x_split_length(len1, x_nb, &n1, &n2); force_symmetric_rec_off_stat(a, offset0, offset1, len0, n1); force_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2); } return; } else { /* base case */ double *p1, *p2, *prow, *pcol; ae_int_t i, j; p1 = (double*)(a->ptr)+offset0*a->stride+offset1; p2 = (double*)(a->ptr)+offset1*a->stride+offset0; for(i=0; istride; for(j=0; jstride; prow++; } } } } /* * this function copies lower part of diagonal block A0 to its upper part * Block is specified by offset and size. * * [ . ] * [ A0 ] * A = [ . ] * [ . ] * */ static void force_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) { double *p, *prow, *pcol; ae_int_t i, j; /* try to split problem into two smaller ones */ if( len>x_nb ) { ae_int_t n1, n2; x_split_length(len, x_nb, &n1, &n2); force_symmetric_rec_diag_stat(a, offset, n1); force_symmetric_rec_diag_stat(a, offset+n1, n2); force_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1); return; } /* base case */ p = (double*)(a->ptr)+offset*a->stride+offset; for(i=0; istride; for(j=0; jstride,prow++) *pcol = *prow; } } /* * this function copies Hermitian transpose of offdiagonal block BL to * its symmetric counterpart BU (see below). Block BL is specified by * offsets (offset0,offset1) and sizes (len0,len1). * * [ . ] * [ A0 BU ] * A = [ BL A1 ] * [ . ] */ static void force_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) { /* try to split problem into two smaller ones */ if( len0>x_nb || len1>x_nb ) { ae_int_t n1, n2; if( len0>len1 ) { x_split_length(len0, x_nb, &n1, &n2); force_hermitian_rec_off_stat(a, offset0, offset1, n1, len1); force_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1); } else { x_split_length(len1, x_nb, &n1, &n2); force_hermitian_rec_off_stat(a, offset0, offset1, len0, n1); force_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2); } return; } else { /* base case */ ae_complex *p1, *p2, *prow, *pcol; ae_int_t i, j; p1 = (ae_complex*)(a->ptr)+offset0*a->stride+offset1; p2 = (ae_complex*)(a->ptr)+offset1*a->stride+offset0; for(i=0; istride; for(j=0; jstride; prow++; } } } } /* * this function copies Hermitian transpose of lower part of * diagonal block A0 to its upper part Block is specified by offset and size. * * [ . ] * [ A0 ] * A = [ . ] * [ . ] * */ static void force_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) { ae_complex *p, *prow, *pcol; ae_int_t i, j; /* try to split problem into two smaller ones */ if( len>x_nb ) { ae_int_t n1, n2; x_split_length(len, x_nb, &n1, &n2); force_hermitian_rec_diag_stat(a, offset, n1); force_hermitian_rec_diag_stat(a, offset+n1, n2); force_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1); return; } /* base case */ p = (ae_complex*)(a->ptr)+offset*a->stride+offset; for(i=0; istride; for(j=0; jstride,prow++) *pcol = *prow; } } ae_bool x_is_symmetric(x_matrix *a) { double mx, err; ae_bool nonfinite; ae_state _alglib_env_state; if( a->datatype!=DT_REAL ) return ae_false; if( a->cols!=a->rows ) return ae_false; if( a->cols==0 || a->rows==0 ) return ae_true; ae_state_init(&_alglib_env_state); mx = 0; err = 0; nonfinite = ae_false; is_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); if( nonfinite ) return ae_false; if( mx==0 ) return ae_true; return err/mx<=1.0E-14; } ae_bool x_is_hermitian(x_matrix *a) { double mx, err; ae_bool nonfinite; ae_state _alglib_env_state; if( a->datatype!=DT_COMPLEX ) return ae_false; if( a->cols!=a->rows ) return ae_false; if( a->cols==0 || a->rows==0 ) return ae_true; ae_state_init(&_alglib_env_state); mx = 0; err = 0; nonfinite = ae_false; is_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); if( nonfinite ) return ae_false; if( mx==0 ) return ae_true; return err/mx<=1.0E-14; } ae_bool x_force_symmetric(x_matrix *a) { if( a->datatype!=DT_REAL ) return ae_false; if( a->cols!=a->rows ) return ae_false; if( a->cols==0 || a->rows==0 ) return ae_true; force_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows); return ae_true; } ae_bool x_force_hermitian(x_matrix *a) { if( a->datatype!=DT_COMPLEX ) return ae_false; if( a->cols!=a->rows ) return ae_false; if( a->cols==0 || a->rows==0 ) return ae_true; force_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows); return ae_true; } ae_bool ae_is_symmetric(ae_matrix *a) { x_matrix x; x.owner = OWN_CALLER; ae_x_attach_to_matrix(&x, a); return x_is_symmetric(&x); } ae_bool ae_is_hermitian(ae_matrix *a) { x_matrix x; x.owner = OWN_CALLER; ae_x_attach_to_matrix(&x, a); return x_is_hermitian(&x); } ae_bool ae_force_symmetric(ae_matrix *a) { x_matrix x; x.owner = OWN_CALLER; ae_x_attach_to_matrix(&x, a); return x_force_symmetric(&x); } ae_bool ae_force_hermitian(ae_matrix *a) { x_matrix x; x.owner = OWN_CALLER; ae_x_attach_to_matrix(&x, a); return x_force_hermitian(&x); } /************************************************************************ This function converts six-bit value (from 0 to 63) to character (only digits, lowercase and uppercase letters, minus and underscore are used). If v is negative or greater than 63, this function returns '?'. ************************************************************************/ static char _sixbits2char_tbl[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-', '_' }; char ae_sixbits2char(ae_int_t v) { if( v<0 || v>63 ) return '?'; return _sixbits2char_tbl[v]; /* v is correct, process it */ /*if( v<10 ) return '0'+v; v -= 10; if( v<26 ) return 'A'+v; v -= 26; if( v<26 ) return 'a'+v; v -= 26; return v==0 ? '-' : '_';*/ } /************************************************************************ This function converts character to six-bit value (from 0 to 63). This function is inverse of ae_sixbits2char() If c is not correct character, this function returns -1. ************************************************************************/ static ae_int_t _ae_char2sixbits_tbl[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 63, -1, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1 }; ae_int_t ae_char2sixbits(char c) { return (c>=0 && c<127) ? _ae_char2sixbits_tbl[(int)c] : -1; } /************************************************************************ This function converts three bytes (24 bits) to four six-bit values (24 bits again). src pointer to three bytes dst pointer to four ints ************************************************************************/ void ae_threebytes2foursixbits(const unsigned char *src, ae_int_t *dst) { dst[0] = src[0] & 0x3F; dst[1] = (src[0]>>6) | ((src[1]&0x0F)<<2); dst[2] = (src[1]>>4) | ((src[2]&0x03)<<4); dst[3] = src[2]>>2; } /************************************************************************ This function converts four six-bit values (24 bits) to three bytes (24 bits again). src pointer to four ints dst pointer to three bytes ************************************************************************/ void ae_foursixbits2threebytes(const ae_int_t *src, unsigned char *dst) { dst[0] = (unsigned char)( src[0] | ((src[1]&0x03)<<6)); dst[1] = (unsigned char)((src[1]>>2) | ((src[2]&0x0F)<<4)); dst[2] = (unsigned char)((src[2]>>4) | (src[3]<<2)); } /************************************************************************ This function serializes boolean value into buffer v boolean value to be serialized buf buffer, at least 12 characters wide (11 chars for value, one for trailing zero) state ALGLIB environment state ************************************************************************/ void ae_bool2str(ae_bool v, char *buf, ae_state *state) { char c = v ? '1' : '0'; ae_int_t i; for(i=0; iendianness==AE_BIG_ENDIAN ) { for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) { unsigned char tc; tc = u.bytes[i]; u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i]; u.bytes[sizeof(ae_int_t)-1-i] = tc; } } /* * convert to six-bit representation, output * * NOTE: last 12th element of sixbits is always zero, we do not output it */ ae_threebytes2foursixbits(u.bytes+0, sixbits+0); ae_threebytes2foursixbits(u.bytes+3, sixbits+4); ae_threebytes2foursixbits(u.bytes+6, sixbits+8); for(i=0; i=AE_SER_ENTRY_LENGTH ) ae_break(state, ERR_ASSERTION_FAILED, emsg); sixbits[sixbitsread] = d; sixbitsread++; buf++; } *pasttheend = buf; if( sixbitsread==0 ) ae_break(state, ERR_ASSERTION_FAILED, emsg); for(i=sixbitsread; i<12; i++) sixbits[i] = 0; ae_foursixbits2threebytes(sixbits+0, u.bytes+0); ae_foursixbits2threebytes(sixbits+4, u.bytes+3); ae_foursixbits2threebytes(sixbits+8, u.bytes+6); if( state->endianness==AE_BIG_ENDIAN ) { for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) { unsigned char tc; tc = u.bytes[i]; u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i]; u.bytes[sizeof(ae_int_t)-1-i] = tc; } } return u.ival; } /************************************************************************ This function serializes double value into buffer v double value to be serialized buf buffer, at least 12 characters wide (11 chars for value, one for trailing zero) state ALGLIB environment state ************************************************************************/ void ae_double2str(double v, char *buf, ae_state *state) { union _u { double dval; unsigned char bytes[9]; } u; ae_int_t i; ae_int_t sixbits[12]; /* * handle special quantities */ if( ae_isnan(v, state) ) { const char *s = ".nan_______"; memcpy(buf, s, strlen(s)+1); return; } if( ae_isposinf(v, state) ) { const char *s = ".posinf____"; memcpy(buf, s, strlen(s)+1); return; } if( ae_isneginf(v, state) ) { const char *s = ".neginf____"; memcpy(buf, s, strlen(s)+1); return; } /* * process general case: * 1. copy v to array of chars * 2. set 9th byte of u.bytes to zero in order to * simplify conversion to six-bit representation * 3. convert to little endian (if needed) * 4. convert to six-bit representation * (last 12th element of sixbits is always zero, we do not output it) */ u.dval = v; u.bytes[8] = 0; if( state->endianness==AE_BIG_ENDIAN ) { for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) { unsigned char tc; tc = u.bytes[i]; u.bytes[i] = u.bytes[sizeof(double)-1-i]; u.bytes[sizeof(double)-1-i] = tc; } } ae_threebytes2foursixbits(u.bytes+0, sixbits+0); ae_threebytes2foursixbits(u.bytes+3, sixbits+4); ae_threebytes2foursixbits(u.bytes+6, sixbits+8); for(i=0; iv_nan; } if( strncmp(buf, s_posinf, strlen(s_posinf))==0 ) { *pasttheend = buf+strlen(s_posinf); return state->v_posinf; } if( strncmp(buf, s_neginf, strlen(s_neginf))==0 ) { *pasttheend = buf+strlen(s_neginf); return state->v_neginf; } ae_break(state, ERR_ASSERTION_FAILED, emsg); } /* * General case: * 1. read and decode six-bit digits * 2. check that all 11 digits were read * 3. set last 12th digit to zero (needed for simplicity of conversion) * 4. convert to 8 bytes * 5. convert to big endian representation, if needed */ sixbitsread = 0; while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 ) { ae_int_t d; d = ae_char2sixbits(*buf); if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH ) ae_break(state, ERR_ASSERTION_FAILED, emsg); sixbits[sixbitsread] = d; sixbitsread++; buf++; } *pasttheend = buf; if( sixbitsread!=AE_SER_ENTRY_LENGTH ) ae_break(state, ERR_ASSERTION_FAILED, emsg); sixbits[AE_SER_ENTRY_LENGTH] = 0; ae_foursixbits2threebytes(sixbits+0, u.bytes+0); ae_foursixbits2threebytes(sixbits+4, u.bytes+3); ae_foursixbits2threebytes(sixbits+8, u.bytes+6); if( state->endianness==AE_BIG_ENDIAN ) { for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) { unsigned char tc; tc = u.bytes[i]; u.bytes[i] = u.bytes[sizeof(double)-1-i]; u.bytes[sizeof(double)-1-i] = tc; } } return u.dval; } /************************************************************************ This function performs given number of spin-wait iterations ************************************************************************/ void ae_spin_wait(ae_int_t cnt) { /* * these strange operations with ae_never_change_it are necessary to * prevent compiler optimization of the loop. */ volatile ae_int_t i; /* very unlikely because no one will wait for such amount of cycles */ if( cnt>0x12345678 ) ae_never_change_it = cnt%10; /* spin wait, test condition which will never be true */ for(i=0; i0 ) ae_never_change_it--; } /************************************************************************ This function causes the calling thread to relinquish the CPU. The thread is moved to the end of the queue and some other thread gets to run. NOTE: this function should NOT be called when AE_OS is AE_UNKNOWN - the whole program will be abnormally terminated. ************************************************************************/ void ae_yield() { #if AE_OS==AE_WINDOWS if( !SwitchToThread() ) Sleep(0); #elif AE_OS==AE_POSIX sched_yield(); #else abort(); #endif } /************************************************************************ This function initializes ae_lock structure and sets lock in a free mode. ************************************************************************/ void ae_init_lock(ae_lock *lock) { _lock *p; lock->ptr = malloc(sizeof(_lock)); AE_CRITICAL_ASSERT(lock->ptr!=NULL); p = (_lock*)lock->ptr; #if AE_OS==AE_WINDOWS p->p_lock = (ae_int_t*)ae_align((void*)(&p->buf),AE_LOCK_ALIGNMENT); p->p_lock[0] = 0; #elif AE_OS==AE_POSIX pthread_mutex_init(&p->mutex, NULL); #else p->is_locked = ae_false; #endif } /************************************************************************ This function acquires lock. In case lock is busy, we perform several iterations inside tight loop before trying again. ************************************************************************/ void ae_acquire_lock(ae_lock *lock) { #if AE_OS==AE_WINDOWS ae_int_t cnt = 0; #endif _lock *p; p = (_lock*)lock->ptr; #if AE_OS==AE_WINDOWS #ifdef AE_SMP_DEBUGCOUNTERS InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_acquisitions); #endif for(;;) { if( InterlockedCompareExchange((LONG volatile *)p->p_lock, 1, 0)==0 ) return; ae_spin_wait(AE_LOCK_CYCLES); #ifdef AE_SMP_DEBUGCOUNTERS InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_spinwaits); #endif cnt++; if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) { #ifdef AE_SMP_DEBUGCOUNTERS InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_yields); #endif ae_yield(); } } #elif AE_OS==AE_POSIX ae_int_t cnt = 0; for(;;) { if( pthread_mutex_trylock(&p->mutex)==0 ) return; ae_spin_wait(AE_LOCK_CYCLES); cnt++; if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) ae_yield(); } ; #else AE_CRITICAL_ASSERT(!p->is_locked); p->is_locked = ae_true; #endif } /************************************************************************ This function releases lock. ************************************************************************/ void ae_release_lock(ae_lock *lock) { _lock *p; p = (_lock*)lock->ptr; #if AE_OS==AE_WINDOWS InterlockedExchange((LONG volatile *)p->p_lock, 0); #elif AE_OS==AE_POSIX pthread_mutex_unlock(&p->mutex); #else p->is_locked = ae_false; #endif } /************************************************************************ This function frees ae_lock structure. ************************************************************************/ void ae_free_lock(ae_lock *lock) { _lock *p; p = (_lock*)lock->ptr; #if AE_OS==AE_POSIX pthread_mutex_destroy(&p->mutex); #endif free(p); } /************************************************************************ This function creates ae_shared_pool structure. dst destination shared pool; already allocated, but not initialized. state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. ************************************************************************/ void ae_shared_pool_init(void *_dst, ae_state *state) { ae_shared_pool *dst; dst = (ae_shared_pool*)_dst; /* init */ dst->seed_object = NULL; dst->recycled_objects = NULL; dst->recycled_entries = NULL; dst->enumeration_counter = NULL; dst->size_of_object = 0; dst->init = NULL; dst->init_copy = NULL; dst->destroy = NULL; dst->frame_entry.deallocator = ae_shared_pool_destroy; dst->frame_entry.ptr = dst; if( state!=NULL ) ae_db_attach(&dst->frame_entry, state); ae_init_lock(&dst->pool_lock); } /************************************************************************ This function clears all dynamically allocated fields of the pool except for the lock. It does NOT try to acquire pool_lock. NOTE: this function is NOT thread-safe, it is not protected by lock. ************************************************************************/ static void ae_shared_pool_internalclear(ae_shared_pool *dst) { ae_shared_pool_entry *ptr, *tmp; /* destroy seed */ if( dst->seed_object!=NULL ) { dst->destroy((void*)dst->seed_object); ae_free((void*)dst->seed_object); dst->seed_object = NULL; } /* destroy recycled objects */ for(ptr=dst->recycled_objects; ptr!=NULL;) { tmp = (ae_shared_pool_entry*)ptr->next_entry; dst->destroy(ptr->obj); ae_free(ptr->obj); ae_free(ptr); ptr = tmp; } dst->recycled_objects = NULL; /* destroy recycled entries */ for(ptr=dst->recycled_entries; ptr!=NULL;) { tmp = (ae_shared_pool_entry*)ptr->next_entry; ae_free(ptr); ptr = tmp; } dst->recycled_entries = NULL; } /************************************************************************ This function creates copy of ae_shared_pool. dst destination pool, allocated but not initialized src source pool state this parameter can be: * pointer to current instance of ae_state, if you want to automatically destroy this object after leaving current frame * NULL, if you do NOT want this vector to be automatically managed (say, if it is field of some object) Error handling: * on failure calls ae_break() with NULL state pointer. Usually it results in abort() call. dst is assumed to be uninitialized, its fields are ignored. NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_init_copy(void *_dst, void *_src, ae_state *state) { ae_shared_pool *dst, *src; ae_shared_pool_entry *ptr; /* state!=NULL, allocation errors result in exception */ /* AE_CRITICAL_ASSERT(state!=NULL); */ dst = (ae_shared_pool*)_dst; src = (ae_shared_pool*)_src; ae_shared_pool_init(dst, state); /* copy non-pointer fields */ dst->size_of_object = src->size_of_object; dst->init = src->init; dst->init_copy = src->init_copy; dst->destroy = src->destroy; ae_init_lock(&dst->pool_lock); /* copy seed object */ if( src->seed_object!=NULL ) { dst->seed_object = ae_malloc(dst->size_of_object, state); dst->init_copy(dst->seed_object, src->seed_object, NULL); } /* copy recycled objects */ dst->recycled_objects = NULL; for(ptr=src->recycled_objects; ptr!=NULL; ptr=(ae_shared_pool_entry*)ptr->next_entry) { ae_shared_pool_entry *tmp; tmp = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); tmp->obj = ae_malloc(dst->size_of_object, state); dst->init_copy(tmp->obj, ptr->obj, NULL); tmp->next_entry = dst->recycled_objects; dst->recycled_objects = tmp; } /* recycled entries are not copied because they do not store any information */ dst->recycled_entries = NULL; /* enumeration counter is reset on copying */ dst->enumeration_counter = NULL; /* initialize frame record */ dst->frame_entry.deallocator = ae_shared_pool_destroy; dst->frame_entry.ptr = dst; } /************************************************************************ This function clears contents of the pool, but pool remain usable. IMPORTANT: this function invalidates dst, it can not be used after it is cleared. NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_clear(void *_dst) { ae_shared_pool *dst = (ae_shared_pool*)_dst; /* clear seed and lists */ ae_shared_pool_internalclear(dst); /* clear fields */ dst->seed_object = NULL; dst->recycled_objects = NULL; dst->recycled_entries = NULL; dst->enumeration_counter = NULL; dst->size_of_object = 0; dst->init = NULL; dst->init_copy = NULL; dst->destroy = NULL; } /************************************************************************ This function destroys pool (object is left in invalid state, all dynamically allocated memory is freed). NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_destroy(void *_dst) { ae_shared_pool *dst = (ae_shared_pool*)_dst; ae_shared_pool_clear(_dst); ae_free_lock(&dst->pool_lock); } /************************************************************************ This function returns True, if internal seed object was set. It returns False for un-seeded pool. dst destination pool (initialized by constructor function) NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ ae_bool ae_shared_pool_is_initialized(void *_dst) { ae_shared_pool *dst = (ae_shared_pool*)_dst; return dst->seed_object!=NULL; } /************************************************************************ This function sets internal seed object. All objects owned by the pool (current seed object, recycled objects) are automatically freed. dst destination pool (initialized by constructor function) seed_object new seed object size_of_object sizeof(), used to allocate memory init constructor function init_copy copy constructor clear destructor function state ALGLIB environment state NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_set_seed( ae_shared_pool *dst, void *seed_object, ae_int_t size_of_object, void (*init)(void* dst, ae_state* state), void (*init_copy)(void* dst, void* src, ae_state* state), void (*destroy)(void* ptr), ae_state *state) { /* state!=NULL, allocation errors result in exception */ AE_CRITICAL_ASSERT(state!=NULL); /* destroy internal objects */ ae_shared_pool_internalclear(dst); /* set non-pointer fields */ dst->size_of_object = size_of_object; dst->init = init; dst->init_copy = init_copy; dst->destroy = destroy; /* set seed object */ dst->seed_object = ae_malloc(size_of_object, state); init_copy(dst->seed_object, seed_object, NULL); } /************************************************************************ This function retrieves a copy of the seed object from the pool and stores it to target smart pointer ptr. In case target pointer owns non-NULL value, it is deallocated before storing value retrieved from pool. Target pointer becomes owner of the value which was retrieved from pool. pool pool pptr pointer to ae_smart_ptr structure state ALGLIB environment state NOTE: this function IS thread-safe. It acquires pool lock during its operation and can be used simultaneously from several threads. ************************************************************************/ void ae_shared_pool_retrieve( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state) { void *new_obj; /* state!=NULL, allocation errors are handled by throwing exception from ae_malloc() */ AE_CRITICAL_ASSERT(state!=NULL); /* assert that pool was seeded */ ae_assert( pool->seed_object!=NULL, "ALGLIB: shared pool is not seeded, PoolRetrieve() failed", state); /* acquire lock */ ae_acquire_lock(&pool->pool_lock); /* try to reuse recycled objects */ if( pool->recycled_objects!=NULL ) { void *new_obj; ae_shared_pool_entry *result; /* retrieve entry/object from list of recycled objects */ result = pool->recycled_objects; pool->recycled_objects = (ae_shared_pool_entry*)pool->recycled_objects->next_entry; new_obj = result->obj; result->obj = NULL; /* move entry to list of recycled entries */ result->next_entry = pool->recycled_entries; pool->recycled_entries = result; /* release lock */ ae_release_lock(&pool->pool_lock); /* assign object to smart pointer */ ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->destroy); return; } /* release lock; we do not need it anymore because copy constructor does not modify source variable */ ae_release_lock(&pool->pool_lock); /* create new object from seed */ new_obj = ae_malloc(pool->size_of_object, state); pool->init_copy(new_obj, pool->seed_object, NULL); /* assign object to smart pointer and return */ ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->destroy); } /************************************************************************ This function recycles object owned by smart pointer by moving it to internal storage of the shared pool. Source pointer must own the object. After function is over, it owns NULL pointer. pool pool pptr pointer to ae_smart_ptr structure state ALGLIB environment state NOTE: this function IS thread-safe. It acquires pool lock during its operation and can be used simultaneously from several threads. ************************************************************************/ void ae_shared_pool_recycle( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state) { ae_shared_pool_entry *new_entry; /* state!=NULL, allocation errors are handled by throwing exception from ae_malloc() */ AE_CRITICAL_ASSERT(state!=NULL); /* assert that pool was seeded */ ae_assert( pool->seed_object!=NULL, "ALGLIB: shared pool is not seeded, PoolRecycle() failed", state); /* assert that pointer non-null and owns the object */ ae_assert(pptr->is_owner, "ALGLIB: pptr in ae_shared_pool_recycle() does not own its pointer", state); ae_assert(pptr->ptr!=NULL, "ALGLIB: pptr in ae_shared_pool_recycle() is NULL", state); /* acquire lock */ ae_acquire_lock(&pool->pool_lock); /* acquire shared pool entry (reuse one from recycled_entries or malloc new one) */ if( pool->recycled_entries!=NULL ) { /* reuse previously allocated entry */ new_entry = pool->recycled_entries; pool->recycled_entries = (ae_shared_pool_entry*)new_entry->next_entry; } else { /* * Allocate memory for new entry. * * NOTE: we release pool lock during allocation because ae_malloc() may raise * exception and we do not want our pool to be left in the locked state. */ ae_release_lock(&pool->pool_lock); new_entry = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); ae_acquire_lock(&pool->pool_lock); } /* add object to the list of recycled objects */ new_entry->obj = pptr->ptr; new_entry->next_entry = pool->recycled_objects; pool->recycled_objects = new_entry; /* release lock object */ ae_release_lock(&pool->pool_lock); /* release source pointer */ ae_smart_ptr_release(pptr); } /************************************************************************ This function clears internal list of recycled objects, but does not change seed object managed by the pool. pool pool state ALGLIB environment state NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_clear_recycled( ae_shared_pool *pool, ae_state *state) { ae_shared_pool_entry *ptr, *tmp; /* clear recycled objects */ for(ptr=pool->recycled_objects; ptr!=NULL;) { tmp = (ae_shared_pool_entry*)ptr->next_entry; pool->destroy(ptr->obj); ae_free(ptr->obj); ae_free(ptr); ptr = tmp; } pool->recycled_objects = NULL; } /************************************************************************ This function allows to enumerate recycled elements of the shared pool. It stores pointer to the first recycled object in the smart pointer. IMPORTANT: * in case target pointer owns non-NULL value, it is deallocated before storing value retrieved from pool. * recycled object IS NOT removed from pool * target pointer DOES NOT become owner of the new value * this function IS NOT thread-safe * you SHOULD NOT modify shared pool during enumeration (although you can modify state of the objects retrieved from pool) * in case there is no recycled objects in the pool, NULL is stored to pptr * in case pool is not seeded, NULL is stored to pptr pool pool pptr pointer to ae_smart_ptr structure state ALGLIB environment state ************************************************************************/ void ae_shared_pool_first_recycled( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state) { /* modify internal enumeration counter */ pool->enumeration_counter = pool->recycled_objects; /* exit on empty list */ if( pool->enumeration_counter==NULL ) { ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); return; } /* assign object to smart pointer */ ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, pool->destroy); } /************************************************************************ This function allows to enumerate recycled elements of the shared pool. It stores pointer to the next recycled object in the smart pointer. IMPORTANT: * in case target pointer owns non-NULL value, it is deallocated before storing value retrieved from pool. * recycled object IS NOT removed from pool * target pointer DOES NOT become owner of the new value * this function IS NOT thread-safe * you SHOULD NOT modify shared pool during enumeration (although you can modify state of the objects retrieved from pool) * in case there is no recycled objects left in the pool, NULL is stored. * in case pool is not seeded, NULL is stored. pool pool pptr pointer to ae_smart_ptr structure state ALGLIB environment state ************************************************************************/ void ae_shared_pool_next_recycled( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state) { /* exit on end of list */ if( pool->enumeration_counter==NULL ) { ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); return; } /* modify internal enumeration counter */ pool->enumeration_counter = (ae_shared_pool_entry*)pool->enumeration_counter->next_entry; /* exit on empty list */ if( pool->enumeration_counter==NULL ) { ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); return; } /* assign object to smart pointer */ ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, pool->destroy); } /************************************************************************ This function clears internal list of recycled objects and seed object. However, pool still can be used (after initialization with another seed). pool pool state ALGLIB environment state NOTE: this function is NOT thread-safe. It does not acquire pool lock, so you should NOT call it when lock can be used by another thread. ************************************************************************/ void ae_shared_pool_reset( ae_shared_pool *pool, ae_state *state) { /* clear seed and lists */ ae_shared_pool_internalclear(pool); /* clear fields */ pool->seed_object = NULL; pool->recycled_objects = NULL; pool->recycled_entries = NULL; pool->enumeration_counter = NULL; pool->size_of_object = 0; pool->init = NULL; pool->init_copy = NULL; pool->destroy = NULL; } /************************************************************************ This function initializes serializer ************************************************************************/ void ae_serializer_init(ae_serializer *serializer) { serializer->mode = AE_SM_DEFAULT; serializer->entries_needed = 0; serializer->bytes_asked = 0; } void ae_serializer_clear(ae_serializer *serializer) { } void ae_serializer_alloc_start(ae_serializer *serializer) { serializer->entries_needed = 0; serializer->bytes_asked = 0; serializer->mode = AE_SM_ALLOC; } void ae_serializer_alloc_entry(ae_serializer *serializer) { serializer->entries_needed++; } ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer) { ae_int_t rows, lastrowsize, result; serializer->mode = AE_SM_READY2S; /* if no entries needes (degenerate case) */ if( serializer->entries_needed==0 ) { serializer->bytes_asked = 1; return serializer->bytes_asked; } /* non-degenerate case */ rows = serializer->entries_needed/AE_SER_ENTRIES_PER_ROW; lastrowsize = AE_SER_ENTRIES_PER_ROW; if( serializer->entries_needed%AE_SER_ENTRIES_PER_ROW ) { lastrowsize = serializer->entries_needed%AE_SER_ENTRIES_PER_ROW; rows++; } /* calculate result size */ result = ((rows-1)*AE_SER_ENTRIES_PER_ROW+lastrowsize)*AE_SER_ENTRY_LENGTH; result += (rows-1)*(AE_SER_ENTRIES_PER_ROW-1)+(lastrowsize-1); result += rows*2; serializer->bytes_asked = result; return result; } #ifdef AE_USE_CPP_SERIALIZATION void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf) { serializer->mode = AE_SM_TO_CPPSTRING; serializer->out_cppstr = buf; serializer->entries_saved = 0; serializer->bytes_written = 0; } #endif #ifdef AE_USE_CPP_SERIALIZATION void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf) { serializer->mode = AE_SM_FROM_STRING; serializer->in_str = buf->c_str(); } #endif void ae_serializer_sstart_str(ae_serializer *serializer, char *buf) { serializer->mode = AE_SM_TO_STRING; serializer->out_str = buf; serializer->out_str[0] = 0; serializer->entries_saved = 0; serializer->bytes_written = 0; } void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf) { serializer->mode = AE_SM_FROM_STRING; serializer->in_str = buf; } void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state) { char buf[AE_SER_ENTRY_LENGTH+2+1]; const char *emsg = "ALGLIB: serialization integrity error"; ae_int_t bytes_appended; /* prepare serialization, check consistency */ ae_bool2str(v, buf, state); serializer->entries_saved++; if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) strcat(buf, " "); else strcat(buf, "\r\n"); bytes_appended = (ae_int_t)strlen(buf); if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) ae_break(state, ERR_ASSERTION_FAILED, emsg); serializer->bytes_written += bytes_appended; /* append to buffer */ #ifdef AE_USE_CPP_SERIALIZATION if( serializer->mode==AE_SM_TO_CPPSTRING ) { *(serializer->out_cppstr) += buf; return; } #endif if( serializer->mode==AE_SM_TO_STRING ) { strcat(serializer->out_str, buf); serializer->out_str += bytes_appended; return; } ae_break(state, ERR_ASSERTION_FAILED, emsg); } void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state) { char buf[AE_SER_ENTRY_LENGTH+2+1]; const char *emsg = "ALGLIB: serialization integrity error"; ae_int_t bytes_appended; /* prepare serialization, check consistency */ ae_int2str(v, buf, state); serializer->entries_saved++; if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) strcat(buf, " "); else strcat(buf, "\r\n"); bytes_appended = (ae_int_t)strlen(buf); if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) ae_break(state, ERR_ASSERTION_FAILED, emsg); serializer->bytes_written += bytes_appended; /* append to buffer */ #ifdef AE_USE_CPP_SERIALIZATION if( serializer->mode==AE_SM_TO_CPPSTRING ) { *(serializer->out_cppstr) += buf; return; } #endif if( serializer->mode==AE_SM_TO_STRING ) { strcat(serializer->out_str, buf); serializer->out_str += bytes_appended; return; } ae_break(state, ERR_ASSERTION_FAILED, emsg); } void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state) { char buf[AE_SER_ENTRY_LENGTH+2+1]; const char *emsg = "ALGLIB: serialization integrity error"; ae_int_t bytes_appended; /* prepare serialization, check consistency */ ae_double2str(v, buf, state); serializer->entries_saved++; if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) strcat(buf, " "); else strcat(buf, "\r\n"); bytes_appended = (ae_int_t)strlen(buf); if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) ae_break(state, ERR_ASSERTION_FAILED, emsg); serializer->bytes_written += bytes_appended; /* append to buffer */ #ifdef AE_USE_CPP_SERIALIZATION if( serializer->mode==AE_SM_TO_CPPSTRING ) { *(serializer->out_cppstr) += buf; return; } #endif if( serializer->mode==AE_SM_TO_STRING ) { strcat(serializer->out_str, buf); serializer->out_str += bytes_appended; return; } ae_break(state, ERR_ASSERTION_FAILED, emsg); } void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state) { *v = ae_str2bool(serializer->in_str, state, &serializer->in_str); } void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state) { *v = ae_str2int(serializer->in_str, state, &serializer->in_str); } void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state) { *v = ae_str2double(serializer->in_str, state, &serializer->in_str); } void ae_serializer_stop(ae_serializer *serializer) { } /************************************************************************ Complex math functions ************************************************************************/ ae_complex ae_complex_from_i(ae_int_t v) { ae_complex r; r.x = (double)v; r.y = 0.0; return r; } ae_complex ae_complex_from_d(double v) { ae_complex r; r.x = v; r.y = 0.0; return r; } ae_complex ae_c_neg(ae_complex lhs) { ae_complex result; result.x = -lhs.x; result.y = -lhs.y; return result; } ae_complex ae_c_conj(ae_complex lhs, ae_state *state) { ae_complex result; result.x = +lhs.x; result.y = -lhs.y; return result; } ae_complex ae_c_sqr(ae_complex lhs, ae_state *state) { ae_complex result; result.x = lhs.x*lhs.x-lhs.y*lhs.y; result.y = 2*lhs.x*lhs.y; return result; } double ae_c_abs(ae_complex z, ae_state *state) { double w; double xabs; double yabs; double v; xabs = fabs(z.x); yabs = fabs(z.y); w = xabs>yabs ? xabs : yabs; v = xabsx; v0y = -v0->y; v1x = v1->x; v1y = -v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( !bconj0 && bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = v0->y; v1x = v1->x; v1y = -v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( bconj0 && !bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = -v0->y; v1x = v1->x; v1y = v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( !bconj0 && !bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = v0->y; v1x = v1->x; v1y = v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } result.x = rx; result.y = ry; return result; } void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { for(i=0; ix = vsrc->x; vdst->y = -vsrc->y; } } else { for(i=0; ix = vsrc->x; vdst->y = -vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = -vsrc->y; } } } else { /* * optimized case */ if( bconj ) { for(i=0; ix = -vsrc->x; vdst->y = vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = -vsrc->y; } } } } void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { for(i=0; ix = alpha*vsrc->x; vdst->y = -alpha*vsrc->y; } } else { for(i=0; ix = alpha*vsrc->x; vdst->y = alpha*vsrc->y; } } } else { /* * optimized case */ if( bconj ) { for(i=0; ix = alpha*vsrc->x; vdst->y = -alpha*vsrc->y; } } else { for(i=0; ix = alpha*vsrc->x; vdst->y = alpha*vsrc->y; } } } } void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x+ay*vsrc->y; vdst->y = -ax*vsrc->y+ay*vsrc->x; } } else { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x-ay*vsrc->y; vdst->y = ax*vsrc->y+ay*vsrc->x; } } } else { /* * highly optimized case */ if( bconj ) { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x+ay*vsrc->y; vdst->y = -ax*vsrc->y+ay*vsrc->x; } } else { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x-ay*vsrc->y; vdst->y = ax*vsrc->y+ay*vsrc->x; } } } } void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { for(i=0; ix += vsrc->x; vdst->y -= vsrc->y; } } else { for(i=0; ix += vsrc->x; vdst->y += vsrc->y; } } } else { /* * optimized case */ if( bconj ) { for(i=0; ix += vsrc->x; vdst->y -= vsrc->y; } } else { for(i=0; ix += vsrc->x; vdst->y += vsrc->y; } } } } void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { for(i=0; ix += alpha*vsrc->x; vdst->y -= alpha*vsrc->y; } } else { for(i=0; ix += alpha*vsrc->x; vdst->y += alpha*vsrc->y; } } } else { /* * optimized case */ if( bconj ) { for(i=0; ix += alpha*vsrc->x; vdst->y -= alpha*vsrc->y; } } else { for(i=0; ix += alpha*vsrc->x; vdst->y += alpha*vsrc->y; } } } } void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ double ax = alpha.x, ay = alpha.y; if( bconj ) { for(i=0; ix += ax*vsrc->x+ay*vsrc->y; vdst->y -= ax*vsrc->y-ay*vsrc->x; } } else { for(i=0; ix += ax*vsrc->x-ay*vsrc->y; vdst->y += ax*vsrc->y+ay*vsrc->x; } } } else { /* * highly optimized case */ double ax = alpha.x, ay = alpha.y; if( bconj ) { for(i=0; ix += ax*vsrc->x+ay*vsrc->y; vdst->y -= ax*vsrc->y-ay*vsrc->x; } } else { for(i=0; ix += ax*vsrc->x-ay*vsrc->y; vdst->y += ax*vsrc->y+ay*vsrc->x; } } } } void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) { ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { /* * general unoptimized case */ if( bconj ) { for(i=0; ix -= vsrc->x; vdst->y += vsrc->y; } } else { for(i=0; ix -= vsrc->x; vdst->y -= vsrc->y; } } } else { /* * highly optimized case */ if( bconj ) { for(i=0; ix -= vsrc->x; vdst->y += vsrc->y; } } else { for(i=0; ix -= vsrc->x; vdst->y -= vsrc->y; } } } } void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) { ae_v_caddd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); } void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) { alpha.x = -alpha.x; alpha.y = -alpha.y; ae_v_caddc(vdst, stride_dst, vsrc, stride_src, conj_src, n, alpha); } void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) { ae_int_t i; if( stride_dst!=1 ) { /* * general unoptimized case */ for(i=0; ix *= alpha; vdst->y *= alpha; } } else { /* * optimized case */ for(i=0; ix *= alpha; vdst->y *= alpha; } } } void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha) { ae_int_t i; if( stride_dst!=1 ) { /* * general unoptimized case */ double ax = alpha.x, ay = alpha.y; for(i=0; ix, dsty = vdst->y; vdst->x = ax*dstx-ay*dsty; vdst->y = ax*dsty+ay*dstx; } } else { /* * highly optimized case */ double ax = alpha.x, ay = alpha.y; for(i=0; ix, dsty = vdst->y; vdst->x = ax*dstx-ay*dsty; vdst->y = ax*dsty+ay*dstx; } } } /************************************************************************ Real BLAS operations ************************************************************************/ double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n) { double result = 0; ae_int_t i; if( stride0!=1 || stride1!=1 ) { /* * slow general code */ for(i=0; iba, 0, DT_BOOL, _state); ae_vector_init(&p->ia, 0, DT_INT, _state); ae_vector_init(&p->ra, 0, DT_REAL, _state); ae_vector_init(&p->ca, 0, DT_COMPLEX, _state); } void _rcommstate_init_copy(rcommstate* dst, rcommstate* src, ae_state *_state) { ae_vector_init_copy(&dst->ba, &src->ba, _state); ae_vector_init_copy(&dst->ia, &src->ia, _state); ae_vector_init_copy(&dst->ra, &src->ra, _state); ae_vector_init_copy(&dst->ca, &src->ca, _state); dst->stage = src->stage; } void _rcommstate_clear(rcommstate* p) { ae_vector_clear(&p->ba); ae_vector_clear(&p->ia); ae_vector_clear(&p->ra); ae_vector_clear(&p->ca); } void _rcommstate_destroy(rcommstate* p) { _rcommstate_clear(p); } #ifdef AE_DEBUG4WINDOWS int _tickcount() { return GetTickCount(); } #endif #ifdef AE_DEBUG4POSIX #include int _tickcount() { struct timeval now; ae_int64_t r, v; gettimeofday(&now, NULL); v = now.tv_sec; r = v*1000; v = now.tv_usec/1000; r = r+v; return r; /*struct timespec now; if (clock_gettime(CLOCK_MONOTONIC, &now) ) return 0; return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0;*/ } #endif } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ RELATED FUNCTIONALITY // ///////////////////////////////////////////////////////////////////////// /******************************************************************** Internal forwards ********************************************************************/ namespace alglib { double get_aenv_nan(); double get_aenv_posinf(); double get_aenv_neginf(); ae_int_t my_stricmp(const char *s1, const char *s2); char* filter_spaces(const char *s); void str_vector_create(const char *src, bool match_head_only, std::vector *p_vec); void str_matrix_create(const char *src, std::vector< std::vector > *p_mat); ae_bool parse_bool_delim(const char *s, const char *delim); ae_int_t parse_int_delim(const char *s, const char *delim); bool _parse_real_delim(const char *s, const char *delim, double *result, const char **new_s); double parse_real_delim(const char *s, const char *delim); alglib::complex parse_complex_delim(const char *s, const char *delim); std::string arraytostring(const bool *ptr, ae_int_t n); std::string arraytostring(const ae_int_t *ptr, ae_int_t n); std::string arraytostring(const double *ptr, ae_int_t n, int dps); std::string arraytostring(const alglib::complex *ptr, ae_int_t n, int dps); } /******************************************************************** Global and local constants ********************************************************************/ const double alglib::machineepsilon = 5E-16; const double alglib::maxrealnumber = 1E300; const double alglib::minrealnumber = 1E-300; const alglib::ae_int_t alglib::endianness = alglib_impl::ae_get_endianness(); const double alglib::fp_nan = alglib::get_aenv_nan(); const double alglib::fp_posinf = alglib::get_aenv_posinf(); const double alglib::fp_neginf = alglib::get_aenv_neginf(); /******************************************************************** ap_error ********************************************************************/ alglib::ap_error::ap_error() { } alglib::ap_error::ap_error(const char *s) { msg = s; } void alglib::ap_error::make_assertion(bool bClause) { if(!bClause) throw ap_error(); } void alglib::ap_error::make_assertion(bool bClause, const char *p_msg) { if(!bClause) throw ap_error(p_msg); } /******************************************************************** Complex number with double precision. ********************************************************************/ alglib::complex::complex():x(0.0),y(0.0) { } alglib::complex::complex(const double &_x):x(_x),y(0.0) { } alglib::complex::complex(const double &_x, const double &_y):x(_x),y(_y) { } alglib::complex::complex(const alglib::complex &z):x(z.x),y(z.y) { } alglib::complex& alglib::complex::operator= (const double& v) { x = v; y = 0.0; return *this; } alglib::complex& alglib::complex::operator+=(const double& v) { x += v; return *this; } alglib::complex& alglib::complex::operator-=(const double& v) { x -= v; return *this; } alglib::complex& alglib::complex::operator*=(const double& v) { x *= v; y *= v; return *this; } alglib::complex& alglib::complex::operator/=(const double& v) { x /= v; y /= v; return *this; } alglib::complex& alglib::complex::operator= (const alglib::complex& z) { x = z.x; y = z.y; return *this; } alglib::complex& alglib::complex::operator+=(const alglib::complex& z) { x += z.x; y += z.y; return *this; } alglib::complex& alglib::complex::operator-=(const alglib::complex& z) { x -= z.x; y -= z.y; return *this; } alglib::complex& alglib::complex::operator*=(const alglib::complex& z) { double t = x*z.x-y*z.y; y = x*z.y+y*z.x; x = t; return *this; } alglib::complex& alglib::complex::operator/=(const alglib::complex& z) { alglib::complex result; double e; double f; if( fabs(z.y)=0 ? _dps : -_dps; if( dps<=0 || dps>=20 ) throw ap_error("complex::tostring(): incorrect dps"); // handle IEEE special quantities if( fp_isnan(x) || fp_isnan(y) ) return "NAN"; if( fp_isinf(x) || fp_isinf(y) ) return "INF"; // generate mask if( sprintf(mask, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask) ) throw ap_error("complex::tostring(): buffer overflow"); // print |x|, |y| and zero with same mask and compare if( sprintf(buf_x, mask, (double)(fabs(x)))>=(int)sizeof(buf_x) ) throw ap_error("complex::tostring(): buffer overflow"); if( sprintf(buf_y, mask, (double)(fabs(y)))>=(int)sizeof(buf_y) ) throw ap_error("complex::tostring(): buffer overflow"); if( sprintf(buf_zero, mask, (double)0)>=(int)sizeof(buf_zero) ) throw ap_error("complex::tostring(): buffer overflow"); // different zero/nonzero patterns if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)!=0 ) return std::string(x>0 ? "" : "-")+buf_x+(y>0 ? "+" : "-")+buf_y+"i"; if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)==0 ) return std::string(x>0 ? "" : "-")+buf_x; if( strcmp(buf_x,buf_zero)==0 && strcmp(buf_y,buf_zero)!=0 ) return std::string(y>0 ? "" : "-")+buf_y+"i"; return std::string("0"); } const bool alglib::operator==(const alglib::complex& lhs, const alglib::complex& rhs) { volatile double x1 = lhs.x; volatile double x2 = rhs.x; volatile double y1 = lhs.y; volatile double y2 = rhs.y; return x1==x2 && y1==y2; } const bool alglib::operator!=(const alglib::complex& lhs, const alglib::complex& rhs) { return !(lhs==rhs); } const alglib::complex alglib::operator+(const alglib::complex& lhs) { return lhs; } const alglib::complex alglib::operator-(const alglib::complex& lhs) { return alglib::complex(-lhs.x, -lhs.y); } const alglib::complex alglib::operator+(const alglib::complex& lhs, const alglib::complex& rhs) { alglib::complex r = lhs; r += rhs; return r; } const alglib::complex alglib::operator+(const alglib::complex& lhs, const double& rhs) { alglib::complex r = lhs; r += rhs; return r; } const alglib::complex alglib::operator+(const double& lhs, const alglib::complex& rhs) { alglib::complex r = rhs; r += lhs; return r; } const alglib::complex alglib::operator-(const alglib::complex& lhs, const alglib::complex& rhs) { alglib::complex r = lhs; r -= rhs; return r; } const alglib::complex alglib::operator-(const alglib::complex& lhs, const double& rhs) { alglib::complex r = lhs; r -= rhs; return r; } const alglib::complex alglib::operator-(const double& lhs, const alglib::complex& rhs) { alglib::complex r = lhs; r -= rhs; return r; } const alglib::complex alglib::operator*(const alglib::complex& lhs, const alglib::complex& rhs) { return alglib::complex(lhs.x*rhs.x - lhs.y*rhs.y, lhs.x*rhs.y + lhs.y*rhs.x); } const alglib::complex alglib::operator*(const alglib::complex& lhs, const double& rhs) { return alglib::complex(lhs.x*rhs, lhs.y*rhs); } const alglib::complex alglib::operator*(const double& lhs, const alglib::complex& rhs) { return alglib::complex(lhs*rhs.x, lhs*rhs.y); } const alglib::complex alglib::operator/(const alglib::complex& lhs, const alglib::complex& rhs) { alglib::complex result; double e; double f; if( fabs(rhs.y)yabs ? xabs : yabs; v = xabsx; v0y = -v0->y; v1x = v1->x; v1y = -v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( !bconj0 && bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = v0->y; v1x = v1->x; v1y = -v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( bconj0 && !bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = -v0->y; v1x = v1->x; v1y = v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } if( !bconj0 && !bconj1 ) { double v0x, v0y, v1x, v1y; for(i=0; ix; v0y = v0->y; v1x = v1->x; v1y = v1->y; rx += v0x*v1x-v0y*v1y; ry += v0x*v1y+v0y*v1x; } } return alglib::complex(rx,ry); } alglib::complex alglib::vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N) { return vdotproduct(v1, 1, "N", v2, 1, "N", N); } void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n) { ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // for(i=0; ix = vsrc->x; vdst->y = -vsrc->y; } } else { for(i=0; ix = vsrc->x; vdst->y = -vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = -vsrc->y; } } } else { // // optimized case // if( bconj ) { for(i=0; ix = -vsrc->x; vdst->y = vsrc->y; } } else { for(i=0; ix = -vsrc->x; vdst->y = -vsrc->y; } } } } void alglib::vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) { vmoveneg(vdst, 1, vsrc, 1, "N", N); } void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha) { ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // for(i=0; ix = alpha*vsrc->x; vdst->y = -alpha*vsrc->y; } } else { for(i=0; ix = alpha*vsrc->x; vdst->y = alpha*vsrc->y; } } } else { // // optimized case // if( bconj ) { for(i=0; ix = alpha*vsrc->x; vdst->y = -alpha*vsrc->y; } } else { for(i=0; ix = alpha*vsrc->x; vdst->y = alpha*vsrc->y; } } } } void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) { vmove(vdst, 1, vsrc, 1, "N", N, alpha); } void alglib::vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) { bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // if( bconj ) { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x+ay*vsrc->y; vdst->y = -ax*vsrc->y+ay*vsrc->x; } } else { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x-ay*vsrc->y; vdst->y = ax*vsrc->y+ay*vsrc->x; } } } else { // // optimized case // if( bconj ) { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x+ay*vsrc->y; vdst->y = -ax*vsrc->y+ay*vsrc->x; } } else { double ax = alpha.x, ay = alpha.y; for(i=0; ix = ax*vsrc->x-ay*vsrc->y; vdst->y = ax*vsrc->y+ay*vsrc->x; } } } } void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) { vmove(vdst, 1, vsrc, 1, "N", N, alpha); } void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) { ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // for(i=0; ix += vsrc->x; vdst->y -= vsrc->y; } } else { for(i=0; ix += vsrc->x; vdst->y += vsrc->y; } } } else { // // optimized case // if( bconj ) { for(i=0; ix += vsrc->x; vdst->y -= vsrc->y; } } else { for(i=0; ix += vsrc->x; vdst->y += vsrc->y; } } } } void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) { vadd(vdst, 1, vsrc, 1, "N", N); } void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) { ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // for(i=0; ix += alpha*vsrc->x; vdst->y -= alpha*vsrc->y; } } else { for(i=0; ix += alpha*vsrc->x; vdst->y += alpha*vsrc->y; } } } else { // // optimized case // if( bconj ) { for(i=0; ix += alpha*vsrc->x; vdst->y -= alpha*vsrc->y; } } else { for(i=0; ix += alpha*vsrc->x; vdst->y += alpha*vsrc->y; } } } } void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) { vadd(vdst, 1, vsrc, 1, "N", N, alpha); } void alglib::vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) { bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // double ax = alpha.x, ay = alpha.y; if( bconj ) { for(i=0; ix += ax*vsrc->x+ay*vsrc->y; vdst->y -= ax*vsrc->y-ay*vsrc->x; } } else { for(i=0; ix += ax*vsrc->x-ay*vsrc->y; vdst->y += ax*vsrc->y+ay*vsrc->x; } } } else { // // optimized case // double ax = alpha.x, ay = alpha.y; if( bconj ) { for(i=0; ix += ax*vsrc->x+ay*vsrc->y; vdst->y -= ax*vsrc->y-ay*vsrc->x; } } else { for(i=0; ix += ax*vsrc->x-ay*vsrc->y; vdst->y += ax*vsrc->y+ay*vsrc->x; } } } } void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) { vadd(vdst, 1, vsrc, 1, "N", N, alpha); } void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) { ae_int_t i; if( stride_dst!=1 || stride_src!=1 ) { // // general unoptimized case // for(i=0; ix -= vsrc->x; vdst->y += vsrc->y; } } else { for(i=0; ix -= vsrc->x; vdst->y -= vsrc->y; } } } else { // // optimized case // if( bconj ) { for(i=0; ix -= vsrc->x; vdst->y += vsrc->y; } } else { for(i=0; ix -= vsrc->x; vdst->y -= vsrc->y; } } } } void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) { vsub(vdst, 1, vsrc, 1, "N", N); } void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) { vadd(vdst, stride_dst, vsrc, stride_src, n, -alpha); } void alglib::vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha) { vadd(vdst, 1, vsrc, 1, N, -alpha); } void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) { vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); } void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, double alpha) { vadd(vdst, 1, vsrc, 1, "N", n, -alpha); } void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) { vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); } void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, alglib::complex alpha) { vadd(vdst, 1, vsrc, 1, "N", n, -alpha); } void alglib::vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) { ae_int_t i; if( stride_dst!=1 ) { // // general unoptimized case // for(i=0; ix *= alpha; vdst->y *= alpha; } } else { // // optimized case // for(i=0; ix *= alpha; vdst->y *= alpha; } } } void alglib::vmul(alglib::complex *vdst, ae_int_t N, double alpha) { vmul(vdst, 1, N, alpha); } void alglib::vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha) { ae_int_t i; if( stride_dst!=1 ) { // // general unoptimized case // double ax = alpha.x, ay = alpha.y; for(i=0; ix, dsty = vdst->y; vdst->x = ax*dstx-ay*dsty; vdst->y = ax*dsty+ay*dstx; } } else { // // optimized case // double ax = alpha.x, ay = alpha.y; for(i=0; ix, dsty = vdst->y; vdst->x = ax*dstx-ay*dsty; vdst->y = ax*dsty+ay*dstx; } } } void alglib::vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha) { vmul(vdst, 1, N, alpha); } /******************************************************************** Matrices and vectors ********************************************************************/ alglib::ae_vector_wrapper::ae_vector_wrapper() { p_vec = NULL; } alglib::ae_vector_wrapper::~ae_vector_wrapper() { if( p_vec==&vec ) ae_vector_clear(p_vec); } void alglib::ae_vector_wrapper::setlength(ae_int_t iLen) { if( p_vec==NULL ) throw alglib::ap_error("ALGLIB: setlength() error, p_vec==NULL (array was not correctly initialized)"); if( p_vec!=&vec ) throw alglib::ap_error("ALGLIB: setlength() error, p_vec!=&vec (attempt to resize frozen array)"); if( !ae_vector_set_length(p_vec, iLen, NULL) ) throw alglib::ap_error("ALGLIB: malloc error"); } alglib::ae_int_t alglib::ae_vector_wrapper::length() const { if( p_vec==NULL ) return 0; return p_vec->cnt; } void alglib::ae_vector_wrapper::attach_to(alglib_impl::ae_vector *ptr) { if( ptr==&vec ) throw alglib::ap_error("ALGLIB: attempt to attach vector to itself"); if( p_vec==&vec ) ae_vector_clear(p_vec); p_vec = ptr; } void alglib::ae_vector_wrapper::allocate_own(ae_int_t size, alglib_impl::ae_datatype datatype) { if( p_vec==&vec ) ae_vector_clear(p_vec); p_vec = &vec; ae_vector_init(p_vec, size, datatype, NULL); } const alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() const { return p_vec; } alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() { return p_vec; } void alglib::ae_vector_wrapper::create(const alglib::ae_vector_wrapper &rhs) { if( rhs.p_vec!=NULL ) { p_vec = &vec; ae_vector_init_copy(p_vec, rhs.p_vec, NULL); } else p_vec = NULL; } void alglib::ae_vector_wrapper::create(const char *s, alglib_impl::ae_datatype datatype) { std::vector svec; size_t i; char *p = filter_spaces(s); try { str_vector_create(p, true, &svec); allocate_own((ae_int_t)(svec.size()), datatype); for(i=0; iptr.p_bool[i] = parse_bool_delim(svec[i],",]"); if( datatype==alglib_impl::DT_INT ) p_vec->ptr.p_int[i] = parse_int_delim(svec[i],",]"); if( datatype==alglib_impl::DT_REAL ) p_vec->ptr.p_double[i] = parse_real_delim(svec[i],",]"); if( datatype==alglib_impl::DT_COMPLEX ) { alglib::complex t = parse_complex_delim(svec[i],",]"); p_vec->ptr.p_complex[i].x = t.x; p_vec->ptr.p_complex[i].y = t.y; } } alglib_impl::ae_free(p); } catch(...) { alglib_impl::ae_free(p); throw; } } void alglib::ae_vector_wrapper::assign(const alglib::ae_vector_wrapper &rhs) { if( this==&rhs ) return; if( p_vec==&vec || p_vec==NULL ) { // // Assignment to non-proxy object // ae_vector_clear(p_vec); if( rhs.p_vec!=NULL ) { p_vec = &vec; ae_vector_init_copy(p_vec, rhs.p_vec, NULL); } else p_vec = NULL; } else { // // Assignment to proxy object // if( rhs.p_vec==NULL ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes don't match)"); if( rhs.p_vec->datatype!=p_vec->datatype ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (types don't match)"); if( rhs.p_vec->cnt!=p_vec->cnt ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes don't match)"); memcpy(p_vec->ptr.p_ptr, rhs.p_vec->ptr.p_ptr, p_vec->cnt*alglib_impl::ae_sizeof(p_vec->datatype)); } } alglib::boolean_1d_array::boolean_1d_array() { allocate_own(0, alglib_impl::DT_BOOL); } alglib::boolean_1d_array::boolean_1d_array(const char *s) { create(s, alglib_impl::DT_BOOL); } alglib::boolean_1d_array::boolean_1d_array(const alglib::boolean_1d_array &rhs) { create(rhs); } alglib::boolean_1d_array::boolean_1d_array(alglib_impl::ae_vector *p) { p_vec = NULL; attach_to(p); } const alglib::boolean_1d_array& alglib::boolean_1d_array::operator=(const alglib::boolean_1d_array &rhs) { assign(rhs); return *this; } alglib::boolean_1d_array::~boolean_1d_array() { } const ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) const { return p_vec->ptr.p_bool[i]; } ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) { return p_vec->ptr.p_bool[i]; } const ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) const { return p_vec->ptr.p_bool[i]; } ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) { return p_vec->ptr.p_bool[i]; } void alglib::boolean_1d_array::setcontent(ae_int_t iLen, const bool *pContent ) { ae_int_t i; setlength(iLen); for(i=0; iptr.p_bool[i] = pContent[i]; } ae_bool* alglib::boolean_1d_array::getcontent() { return p_vec->ptr.p_bool; } const ae_bool* alglib::boolean_1d_array::getcontent() const { return p_vec->ptr.p_bool; } std::string alglib::boolean_1d_array::tostring() const { if( length()==0 ) return "[]"; return arraytostring(&(operator()(0)), length()); } alglib::integer_1d_array::integer_1d_array() { allocate_own(0, alglib_impl::DT_INT); } alglib::integer_1d_array::integer_1d_array(alglib_impl::ae_vector *p) { p_vec = NULL; attach_to(p); } alglib::integer_1d_array::integer_1d_array(const char *s) { create(s, alglib_impl::DT_INT); } alglib::integer_1d_array::integer_1d_array(const alglib::integer_1d_array &rhs) { create(rhs); } const alglib::integer_1d_array& alglib::integer_1d_array::operator=(const alglib::integer_1d_array &rhs) { assign(rhs); return *this; } alglib::integer_1d_array::~integer_1d_array() { } const alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) const { return p_vec->ptr.p_int[i]; } alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) { return p_vec->ptr.p_int[i]; } const alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) const { return p_vec->ptr.p_int[i]; } alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) { return p_vec->ptr.p_int[i]; } void alglib::integer_1d_array::setcontent(ae_int_t iLen, const ae_int_t *pContent ) { ae_int_t i; setlength(iLen); for(i=0; iptr.p_int[i] = pContent[i]; } alglib::ae_int_t* alglib::integer_1d_array::getcontent() { return p_vec->ptr.p_int; } const alglib::ae_int_t* alglib::integer_1d_array::getcontent() const { return p_vec->ptr.p_int; } std::string alglib::integer_1d_array::tostring() const { if( length()==0 ) return "[]"; return arraytostring(&operator()(0), length()); } alglib::real_1d_array::real_1d_array() { allocate_own(0, alglib_impl::DT_REAL); } alglib::real_1d_array::real_1d_array(alglib_impl::ae_vector *p) { p_vec = NULL; attach_to(p); } alglib::real_1d_array::real_1d_array(const char *s) { create(s, alglib_impl::DT_REAL); } alglib::real_1d_array::real_1d_array(const alglib::real_1d_array &rhs) { create(rhs); } const alglib::real_1d_array& alglib::real_1d_array::operator=(const alglib::real_1d_array &rhs) { assign(rhs); return *this; } alglib::real_1d_array::~real_1d_array() { } const double& alglib::real_1d_array::operator()(ae_int_t i) const { return p_vec->ptr.p_double[i]; } double& alglib::real_1d_array::operator()(ae_int_t i) { return p_vec->ptr.p_double[i]; } const double& alglib::real_1d_array::operator[](ae_int_t i) const { return p_vec->ptr.p_double[i]; } double& alglib::real_1d_array::operator[](ae_int_t i) { return p_vec->ptr.p_double[i]; } void alglib::real_1d_array::setcontent(ae_int_t iLen, const double *pContent ) { ae_int_t i; setlength(iLen); for(i=0; iptr.p_double[i] = pContent[i]; } double* alglib::real_1d_array::getcontent() { return p_vec->ptr.p_double; } const double* alglib::real_1d_array::getcontent() const { return p_vec->ptr.p_double; } std::string alglib::real_1d_array::tostring(int dps) const { if( length()==0 ) return "[]"; return arraytostring(&operator()(0), length(), dps); } alglib::complex_1d_array::complex_1d_array() { allocate_own(0, alglib_impl::DT_COMPLEX); } alglib::complex_1d_array::complex_1d_array(alglib_impl::ae_vector *p) { p_vec = NULL; attach_to(p); } alglib::complex_1d_array::complex_1d_array(const char *s) { create(s, alglib_impl::DT_COMPLEX); } alglib::complex_1d_array::complex_1d_array(const alglib::complex_1d_array &rhs) { create(rhs); } const alglib::complex_1d_array& alglib::complex_1d_array::operator=(const alglib::complex_1d_array &rhs) { assign(rhs); return *this; } alglib::complex_1d_array::~complex_1d_array() { } const alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) const { return *((const alglib::complex*)(p_vec->ptr.p_complex+i)); } alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) { return *((alglib::complex*)(p_vec->ptr.p_complex+i)); } const alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) const { return *((const alglib::complex*)(p_vec->ptr.p_complex+i)); } alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) { return *((alglib::complex*)(p_vec->ptr.p_complex+i)); } void alglib::complex_1d_array::setcontent(ae_int_t iLen, const alglib::complex *pContent ) { ae_int_t i; setlength(iLen); for(i=0; iptr.p_complex[i].x = pContent[i].x; p_vec->ptr.p_complex[i].y = pContent[i].y; } } alglib::complex* alglib::complex_1d_array::getcontent() { return (alglib::complex*)p_vec->ptr.p_complex; } const alglib::complex* alglib::complex_1d_array::getcontent() const { return (const alglib::complex*)p_vec->ptr.p_complex; } std::string alglib::complex_1d_array::tostring(int dps) const { if( length()==0 ) return "[]"; return arraytostring(&operator()(0), length(), dps); } alglib::ae_matrix_wrapper::ae_matrix_wrapper() { p_mat = NULL; } alglib::ae_matrix_wrapper::~ae_matrix_wrapper() { if( p_mat==&mat ) ae_matrix_clear(p_mat); } const alglib::ae_matrix_wrapper& alglib::ae_matrix_wrapper::operator=(const alglib::ae_matrix_wrapper &rhs) { assign(rhs); return *this; } void alglib::ae_matrix_wrapper::create(const ae_matrix_wrapper &rhs) { if( rhs.p_mat!=NULL ) { p_mat = &mat; ae_matrix_init_copy(p_mat, rhs.p_mat, NULL); } else p_mat = NULL; } void alglib::ae_matrix_wrapper::create(const char *s, alglib_impl::ae_datatype datatype) { std::vector< std::vector > smat; size_t i, j; char *p = filter_spaces(s); try { str_matrix_create(p, &smat); if( smat.size()!=0 ) { allocate_own((ae_int_t)(smat.size()), (ae_int_t)(smat[0].size()), datatype); for(i=0; iptr.pp_bool[i][j] = parse_bool_delim(smat[i][j],",]"); if( datatype==alglib_impl::DT_INT ) p_mat->ptr.pp_int[i][j] = parse_int_delim(smat[i][j],",]"); if( datatype==alglib_impl::DT_REAL ) p_mat->ptr.pp_double[i][j] = parse_real_delim(smat[i][j],",]"); if( datatype==alglib_impl::DT_COMPLEX ) { alglib::complex t = parse_complex_delim(smat[i][j],",]"); p_mat->ptr.pp_complex[i][j].x = t.x; p_mat->ptr.pp_complex[i][j].y = t.y; } } } else allocate_own(0, 0, datatype); alglib_impl::ae_free(p); } catch(...) { alglib_impl::ae_free(p); throw; } } void alglib::ae_matrix_wrapper::assign(const alglib::ae_matrix_wrapper &rhs) { if( this==&rhs ) return; if( p_mat==&mat || p_mat==NULL ) { // // Assignment to non-proxy object // ae_matrix_clear(p_mat); if( rhs.p_mat!=NULL ) { p_mat = &mat; ae_matrix_init_copy(p_mat, rhs.p_mat, NULL); } else p_mat = NULL; } else { // // Assignment to proxy object // ae_int_t i; if( rhs.p_mat==NULL ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes don't match)"); if( rhs.p_mat->datatype!=p_mat->datatype ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (types don't match)"); if( rhs.p_mat->rows!=p_mat->rows ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes don't match)"); if( rhs.p_mat->cols!=p_mat->cols ) throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes don't match)"); for(i=0; irows; i++) memcpy(p_mat->ptr.pp_void[i], rhs.p_mat->ptr.pp_void[i], p_mat->cols*alglib_impl::ae_sizeof(p_mat->datatype)); } } void alglib::ae_matrix_wrapper::setlength(ae_int_t rows, ae_int_t cols) { if( p_mat==NULL ) throw alglib::ap_error("ALGLIB: setlength() error, p_mat==NULL (array was not correctly initialized)"); if( p_mat!=&mat ) throw alglib::ap_error("ALGLIB: setlength() error, p_mat!=&mat (attempt to resize frozen array)"); if( !ae_matrix_set_length(p_mat, rows, cols, NULL) ) throw alglib::ap_error("ALGLIB: malloc error"); } alglib::ae_int_t alglib::ae_matrix_wrapper::rows() const { if( p_mat==NULL ) return 0; return p_mat->rows; } alglib::ae_int_t alglib::ae_matrix_wrapper::cols() const { if( p_mat==NULL ) return 0; return p_mat->cols; } bool alglib::ae_matrix_wrapper::isempty() const { return rows()==0 || cols()==0; } alglib::ae_int_t alglib::ae_matrix_wrapper::getstride() const { if( p_mat==NULL ) return 0; return p_mat->stride; } void alglib::ae_matrix_wrapper::attach_to(alglib_impl::ae_matrix *ptr) { if( ptr==&mat ) throw alglib::ap_error("ALGLIB: attempt to attach matrix to itself"); if( p_mat==&mat ) ae_matrix_clear(p_mat); p_mat = ptr; } void alglib::ae_matrix_wrapper::allocate_own(ae_int_t rows, ae_int_t cols, alglib_impl::ae_datatype datatype) { if( p_mat==&mat ) ae_matrix_clear(p_mat); p_mat = &mat; ae_matrix_init(p_mat, rows, cols, datatype, NULL); } const alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() const { return p_mat; } alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() { return p_mat; } alglib::boolean_2d_array::boolean_2d_array() { allocate_own(0, 0, alglib_impl::DT_BOOL); } alglib::boolean_2d_array::boolean_2d_array(const alglib::boolean_2d_array &rhs) { create(rhs); } alglib::boolean_2d_array::boolean_2d_array(alglib_impl::ae_matrix *p) { p_mat = NULL; attach_to(p); } alglib::boolean_2d_array::boolean_2d_array(const char *s) { create(s, alglib_impl::DT_BOOL); } alglib::boolean_2d_array::~boolean_2d_array() { } const ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) const { return p_mat->ptr.pp_bool[i][j]; } ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) { return p_mat->ptr.pp_bool[i][j]; } const ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) const { return p_mat->ptr.pp_bool[i]; } ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) { return p_mat->ptr.pp_bool[i]; } void alglib::boolean_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ) { ae_int_t i, j; setlength(irows, icols); for(i=0; iptr.pp_bool[i][j] = pContent[i*icols+j]; } std::string alglib::boolean_2d_array::tostring() const { std::string result; ae_int_t i; if( isempty() ) return "[[]]"; result = "["; for(i=0; iptr.pp_int[i][j]; } alglib::ae_int_t& alglib::integer_2d_array::operator()(ae_int_t i, ae_int_t j) { return p_mat->ptr.pp_int[i][j]; } const alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) const { return p_mat->ptr.pp_int[i]; } alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) { return p_mat->ptr.pp_int[i]; } void alglib::integer_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ) { ae_int_t i, j; setlength(irows, icols); for(i=0; iptr.pp_int[i][j] = pContent[i*icols+j]; } std::string alglib::integer_2d_array::tostring() const { std::string result; ae_int_t i; if( isempty() ) return "[[]]"; result = "["; for(i=0; iptr.pp_double[i][j]; } double& alglib::real_2d_array::operator()(ae_int_t i, ae_int_t j) { return p_mat->ptr.pp_double[i][j]; } const double* alglib::real_2d_array::operator[](ae_int_t i) const { return p_mat->ptr.pp_double[i]; } double* alglib::real_2d_array::operator[](ae_int_t i) { return p_mat->ptr.pp_double[i]; } void alglib::real_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const double *pContent ) { ae_int_t i, j; setlength(irows, icols); for(i=0; iptr.pp_double[i][j] = pContent[i*icols+j]; } std::string alglib::real_2d_array::tostring(int dps) const { std::string result; ae_int_t i; if( isempty() ) return "[[]]"; result = "["; for(i=0; iptr.pp_complex[i]+j)); } alglib::complex& alglib::complex_2d_array::operator()(ae_int_t i, ae_int_t j) { return *((alglib::complex*)(p_mat->ptr.pp_complex[i]+j)); } const alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) const { return (const alglib::complex*)(p_mat->ptr.pp_complex[i]); } alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) { return (alglib::complex*)(p_mat->ptr.pp_complex[i]); } void alglib::complex_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ) { ae_int_t i, j; setlength(irows, icols); for(i=0; iptr.pp_complex[i][j].x = pContent[i*icols+j].x; p_mat->ptr.pp_complex[i][j].y = pContent[i*icols+j].y; } } std::string alglib::complex_2d_array::tostring(int dps) const { std::string result; ae_int_t i; if( isempty() ) return "[[]]"; result = "["; for(i=0; ic2 ) return +1; } } char* alglib::filter_spaces(const char *s) { size_t i, n; char *r; char *r0; n = strlen(s); r = (char*)alglib_impl::ae_malloc(n+1, NULL); if( r==NULL ) throw ap_error("malloc error"); for(i=0,r0=r; i<=n; i++,s++) if( !isspace(*s) ) { *r0 = *s; r0++; } return r; } void alglib::str_vector_create(const char *src, bool match_head_only, std::vector *p_vec) { // // parse beginning of the string. // try to handle "[]" string // p_vec->clear(); if( *src!='[' ) throw alglib::ap_error("Incorrect initializer for vector"); src++; if( *src==']' ) return; p_vec->push_back(src); for(;;) { if( *src==0 ) throw alglib::ap_error("Incorrect initializer for vector"); if( *src==']' ) { if( src[1]==0 || !match_head_only) return; throw alglib::ap_error("Incorrect initializer for vector"); } if( *src==',' ) { p_vec->push_back(src+1); src++; continue; } src++; } } void alglib::str_matrix_create(const char *src, std::vector< std::vector > *p_mat) { p_mat->clear(); // // Try to handle "[[]]" string // if( strcmp(src, "[[]]")==0 ) return; // // Parse non-empty string // if( *src!='[' ) throw alglib::ap_error("Incorrect initializer for matrix"); src++; for(;;) { p_mat->push_back(std::vector()); str_vector_create(src, false, &p_mat->back()); if( p_mat->back().size()==0 || p_mat->back().size()!=(*p_mat)[0].size() ) throw alglib::ap_error("Incorrect initializer for matrix"); src = strchr(src, ']'); if( src==NULL ) throw alglib::ap_error("Incorrect initializer for matrix"); src++; if( *src==',' ) { src++; continue; } if( *src==']' ) break; throw alglib::ap_error("Incorrect initializer for matrix"); } src++; if( *src!=0 ) throw alglib::ap_error("Incorrect initializer for matrix"); } ae_bool alglib::parse_bool_delim(const char *s, const char *delim) { const char *p; char buf[8]; // try to parse false p = "false"; memset(buf, 0, sizeof(buf)); strncpy(buf, s, strlen(p)); if( my_stricmp(buf, p)==0 ) { if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) throw alglib::ap_error("Cannot parse value"); return ae_false; } // try to parse true p = "true"; memset(buf, 0, sizeof(buf)); strncpy(buf, s, strlen(p)); if( my_stricmp(buf, p)==0 ) { if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) throw alglib::ap_error("Cannot parse value"); return ae_true; } // error throw alglib::ap_error("Cannot parse value"); } alglib::ae_int_t alglib::parse_int_delim(const char *s, const char *delim) { const char *p; long long_val; volatile ae_int_t ae_val; p = s; // // check string structure: // * leading sign // * at least one digit // * delimiter // if( *s=='-' || *s=='+' ) s++; if( *s==0 || strchr("1234567890",*s)==NULL) throw alglib::ap_error("Cannot parse value"); while( *s!=0 && strchr("1234567890",*s)!=NULL ) s++; if( *s==0 || strchr(delim,*s)==NULL ) throw alglib::ap_error("Cannot parse value"); // convert and ensure that value fits into ae_int_t s = p; long_val = atol(s); ae_val = long_val; if( ae_val!=long_val ) throw alglib::ap_error("Cannot parse value"); return ae_val; } bool alglib::_parse_real_delim(const char *s, const char *delim, double *result, const char **new_s) { const char *p; char *t; bool has_digits; char buf[64]; int isign; lconv *loc; p = s; // // check string structure and decide what to do // isign = 1; if( *s=='-' || *s=='+' ) { isign = *s=='-' ? -1 : +1; s++; } memset(buf, 0, sizeof(buf)); strncpy(buf, s, 3); if( my_stricmp(buf,"nan")!=0 && my_stricmp(buf,"inf")!=0 ) { // // [sign] [ddd] [.] [ddd] [e|E[sign]ddd] // has_digits = false; if( *s!=0 && strchr("1234567890",*s)!=NULL ) { has_digits = true; while( *s!=0 && strchr("1234567890",*s)!=NULL ) s++; } if( *s=='.' ) s++; if( *s!=0 && strchr("1234567890",*s)!=NULL ) { has_digits = true; while( *s!=0 && strchr("1234567890",*s)!=NULL ) s++; } if (!has_digits ) return false; if( *s=='e' || *s=='E' ) { s++; if( *s=='-' || *s=='+' ) s++; if( *s==0 || strchr("1234567890",*s)==NULL ) return false; while( *s!=0 && strchr("1234567890",*s)!=NULL ) s++; } if( *s==0 || strchr(delim,*s)==NULL ) return false; *new_s = s; // // finite value conversion // if( *new_s-p>=(int)sizeof(buf) ) return false; strncpy(buf, p, (size_t)(*new_s-p)); buf[*new_s-p] = 0; loc = localeconv(); t = strchr(buf,'.'); if( t!=NULL ) *t = *loc->decimal_point; *result = atof(buf); return true; } else { // // check delimiter and update *new_s // s += 3; if( *s==0 || strchr(delim,*s)==NULL ) return false; *new_s = s; // // NAN, INF conversion // if( my_stricmp(buf,"nan")==0 ) *result = fp_nan; if( my_stricmp(buf,"inf")==0 ) *result = isign>0 ? fp_posinf : fp_neginf; return true; } } double alglib::parse_real_delim(const char *s, const char *delim) { double result; const char *new_s; if( !_parse_real_delim(s, delim, &result, &new_s) ) throw alglib::ap_error("Cannot parse value"); return result; } alglib::complex alglib::parse_complex_delim(const char *s, const char *delim) { double d_result; const char *new_s; alglib::complex c_result; // parse as real value if( _parse_real_delim(s, delim, &d_result, &new_s) ) return d_result; // parse as "a+bi" or "a-bi" if( _parse_real_delim(s, "+-", &c_result.x, &new_s) ) { s = new_s; if( !_parse_real_delim(s, "i", &c_result.y, &new_s) ) throw alglib::ap_error("Cannot parse value"); s = new_s+1; if( *s==0 || strchr(delim,*s)==NULL ) throw alglib::ap_error("Cannot parse value"); return c_result; } // parse as complex value "bi+a" or "bi-a" if( _parse_real_delim(s, "i", &c_result.y, &new_s) ) { s = new_s+1; if( *s==0 ) throw alglib::ap_error("Cannot parse value"); if( strchr(delim,*s)!=NULL ) { c_result.x = 0; return c_result; } if( strchr("+-",*s)!=NULL ) { if( !_parse_real_delim(s, delim, &c_result.x, &new_s) ) throw alglib::ap_error("Cannot parse value"); return c_result; } throw alglib::ap_error("Cannot parse value"); } // error throw alglib::ap_error("Cannot parse value"); } std::string alglib::arraytostring(const bool *ptr, ae_int_t n) { std::string result; ae_int_t i; result = "["; for(i=0; i=(int)sizeof(buf) ) throw ap_error("arraytostring(): buffer overflow"); result += buf; } result += "]"; return result; } std::string alglib::arraytostring(const double *ptr, ae_int_t n, int _dps) { std::string result; ae_int_t i; char buf[64]; char mask1[64]; char mask2[64]; int dps = _dps>=0 ? _dps : -_dps; result = "["; if( sprintf(mask1, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask1) ) throw ap_error("arraytostring(): buffer overflow"); if( sprintf(mask2, ",%s", mask1)>=(int)sizeof(mask2) ) throw ap_error("arraytostring(): buffer overflow"); for(i=0; i=(int)sizeof(buf) ) throw ap_error("arraytostring(): buffer overflow"); } else if( fp_isnan(ptr[i]) ) strcpy(buf, i==0 ? "NAN" : ",NAN"); else if( fp_isposinf(ptr[i]) ) strcpy(buf, i==0 ? "+INF" : ",+INF"); else if( fp_isneginf(ptr[i]) ) strcpy(buf, i==0 ? "-INF" : ",-INF"); result += buf; } result += "]"; return result; } std::string alglib::arraytostring(const alglib::complex *ptr, ae_int_t n, int dps) { std::string result; ae_int_t i; result = "["; for(i=0; i0 ) return 1; if( x<0 ) return -1; return 0; } double alglib::randomreal() { int i1 = rand(); int i2 = rand(); double mx = (double)(RAND_MAX)+1.0; volatile double tmp0 = i2/mx; volatile double tmp1 = i1+tmp0; return tmp1/mx; } alglib::ae_int_t alglib::randominteger(alglib::ae_int_t maxv) { return ((alglib::ae_int_t)rand())%maxv; } int alglib::round(double x) { return int(floor(x+0.5)); } int alglib::trunc(double x) { return int(x>0 ? floor(x) : ceil(x)); } int alglib::ifloor(double x) { return int(floor(x)); } int alglib::iceil(double x) { return int(ceil(x)); } double alglib::pi() { return 3.14159265358979323846; } double alglib::sqr(double x) { return x*x; } int alglib::maxint(int m1, int m2) { return m1>m2 ? m1 : m2; } int alglib::minint(int m1, int m2) { return m1>m2 ? m2 : m1; } double alglib::maxreal(double m1, double m2) { return m1>m2 ? m1 : m2; } double alglib::minreal(double m1, double m2) { return m1>m2 ? m2 : m1; } bool alglib::fp_eq(double v1, double v2) { // IEEE-strict floating point comparison volatile double x = v1; volatile double y = v2; return x==y; } bool alglib::fp_neq(double v1, double v2) { // IEEE-strict floating point comparison return !fp_eq(v1,v2); } bool alglib::fp_less(double v1, double v2) { // IEEE-strict floating point comparison volatile double x = v1; volatile double y = v2; return xy; } bool alglib::fp_greater_eq(double v1, double v2) { // IEEE-strict floating point comparison volatile double x = v1; volatile double y = v2; return x>=y; } bool alglib::fp_isnan(double x) { return alglib_impl::ae_isnan_stateless(x,endianness); } bool alglib::fp_isposinf(double x) { return alglib_impl::ae_isposinf_stateless(x,endianness); } bool alglib::fp_isneginf(double x) { return alglib_impl::ae_isneginf_stateless(x,endianness); } bool alglib::fp_isinf(double x) { return alglib_impl::ae_isinf_stateless(x,endianness); } bool alglib::fp_isfinite(double x) { return alglib_impl::ae_isfinite_stateless(x,endianness); } /******************************************************************** CSV functions ********************************************************************/ void alglib::read_csv(const char *filename, char separator, int flags, alglib::real_2d_array &out) { int flag; // // Parameters // bool skip_first_row = (flags&CSV_SKIP_HEADERS)!=0; // // Prepare empty output array // out.setlength(0,0); // // Open file, determine size, read contents // FILE *f_in = fopen(filename, "rb"); if( f_in==NULL ) throw alglib::ap_error("read_csv: unable to open input file"); flag = fseek(f_in, 0, SEEK_END); AE_CRITICAL_ASSERT(flag==0); long int _filesize = ftell(f_in); AE_CRITICAL_ASSERT(_filesize>=0); if( _filesize==0 ) { // empty file, return empty array, success fclose(f_in); return; } size_t filesize = _filesize; std::vector v_buf; v_buf.resize(filesize+2, 0); char *p_buf = &v_buf[0]; flag = fseek(f_in, 0, SEEK_SET); AE_CRITICAL_ASSERT(flag==0); size_t bytes_read = fread ((void*)p_buf, 1, filesize, f_in); AE_CRITICAL_ASSERT(bytes_read==filesize); fclose(f_in); // // Normalize file contents: // * replace 0x0 by spaces // * remove trailing spaces and newlines // * append trailing '\n' and '\0' characters // Return if file contains only spaces/newlines. // for(size_t i=0; i0; ) { char c = p_buf[filesize-1]; if( c==' ' || c=='\t' || c=='\n' || c=='\r' ) { filesize--; continue; } break; } if( filesize==0 ) return; p_buf[filesize+0] = '\n'; p_buf[filesize+1] = '\0'; filesize+=2; // // Scan dataset. // size_t rows_count = 0, cols_count = 0, max_length = 0; std::vector offsets, lengths; for(size_t row_start=0; p_buf[row_start]!=0x0; ) { // determine row length size_t row_length; for(row_length=0; p_buf[row_start+row_length]!='\n'; row_length++); // determine cols count, perform integrity check size_t cur_cols_cnt=1; for(size_t idx=0; idx0 && cols_count!=cur_cols_cnt ) throw alglib::ap_error("read_csv: non-rectangular contents, rows have different sizes"); cols_count = cur_cols_cnt; // store offsets and lengths of the fields size_t cur_offs = 0; for(size_t idx=0; idxmax_length ? idx-cur_offs : max_length; cur_offs = idx+1; } // advance row start rows_count++; row_start = row_start+row_length+1; } AE_CRITICAL_ASSERT(rows_count>=1); AE_CRITICAL_ASSERT(cols_count>=1); AE_CRITICAL_ASSERT(cols_count*rows_count==offsets.size()); AE_CRITICAL_ASSERT(cols_count*rows_count==lengths.size()); if( rows_count==1 && skip_first_row ) // empty output, return return; // // Convert // size_t row0 = skip_first_row ? 1 : 0; size_t row1 = rows_count; lconv *loc = localeconv(); out.setlength(row1-row0, cols_count); for(size_t ridx=row0; ridxdecimal_point; out[ridx-row0][cidx] = atof(p_field); } } /******************************************************************** Dataset functions ********************************************************************/ /*bool alglib::readstrings(std::string file, std::list *pOutput) { return readstrings(file, pOutput, ""); } bool alglib::readstrings(std::string file, std::list *pOutput, std::string comment) { std::string cmd, s; FILE *f; char buf[32768]; char *str; f = fopen(file.c_str(), "rb"); if( !f ) return false; s = ""; pOutput->clear(); while(str=fgets(buf, sizeof(buf), f)) { // TODO: read file by small chunks, combine in one large string if( strlen(str)==0 ) continue; // // trim trailing newline chars // char *eos = str+strlen(str)-1; if( *eos=='\n' ) { *eos = 0; eos--; } if( *eos=='\r' ) { *eos = 0; eos--; } s = str; // // skip comments // if( comment.length()>0 ) if( strncmp(s.c_str(), comment.c_str(), comment.length())==0 ) { s = ""; continue; } // // read data // if( s.length()<1 ) { fclose(f); throw alglib::ap_error("internal error in read_strings"); } pOutput->push_back(s); } fclose(f); return true; } void alglib::explodestring(std::string s, char sep, std::vector *pOutput) { std::string tmp; int i; tmp = ""; pOutput->clear(); for(i=0; ipush_back(tmp); tmp = ""; } if( tmp.length()!=0 ) pOutput->push_back(tmp); } std::string alglib::strtolower(const std::string &s) { std::string r = s; for(int i=0; i Lines; std::vector Values, RowsArr, ColsArr, VarsArr, HeadArr; std::list::iterator i; std::string s; int TrnFirst, TrnLast, ValFirst, ValLast, TstFirst, TstLast, LinesRead, j; // // Read data // if( pdataset==NULL ) return false; if( !readstrings(file, &Lines, "//") ) return false; i = Lines.begin(); *pdataset = dataset(); // // Read header // if( i==Lines.end() ) return false; s = alglib::xtrim(*i); alglib::explodestring(s, '#', &HeadArr); if( HeadArr.size()!=2 ) return false; // // Rows info // alglib::explodestring(alglib::xtrim(HeadArr[0]), ' ', &RowsArr); if( RowsArr.size()==0 || RowsArr.size()>3 ) return false; if( RowsArr.size()==1 ) { pdataset->totalsize = atol(RowsArr[0].c_str()); pdataset->trnsize = pdataset->totalsize; } if( RowsArr.size()==2 ) { pdataset->trnsize = atol(RowsArr[0].c_str()); pdataset->tstsize = atol(RowsArr[1].c_str()); pdataset->totalsize = pdataset->trnsize + pdataset->tstsize; } if( RowsArr.size()==3 ) { pdataset->trnsize = atol(RowsArr[0].c_str()); pdataset->valsize = atol(RowsArr[1].c_str()); pdataset->tstsize = atol(RowsArr[2].c_str()); pdataset->totalsize = pdataset->trnsize + pdataset->valsize + pdataset->tstsize; } if( pdataset->totalsize<=0 || pdataset->trnsize<0 || pdataset->valsize<0 || pdataset->tstsize<0 ) return false; TrnFirst = 0; TrnLast = TrnFirst + pdataset->trnsize; ValFirst = TrnLast; ValLast = ValFirst + pdataset->valsize; TstFirst = ValLast; TstLast = TstFirst + pdataset->tstsize; // // columns // alglib::explodestring(alglib::xtrim(HeadArr[1]), ' ', &ColsArr); if( ColsArr.size()!=1 && ColsArr.size()!=4 ) return false; if( ColsArr.size()==1 ) { pdataset->nin = atoi(ColsArr[0].c_str()); if( pdataset->nin<=0 ) return false; } if( ColsArr.size()==4 ) { if( alglib::strtolower(ColsArr[0])!="reg" && alglib::strtolower(ColsArr[0])!="cls" ) return false; if( ColsArr[2]!="=>" ) return false; pdataset->nin = atol(ColsArr[1].c_str()); if( pdataset->nin<1 ) return false; if( alglib::strtolower(ColsArr[0])=="reg" ) { pdataset->nclasses = 0; pdataset->nout = atol(ColsArr[3].c_str()); if( pdataset->nout<1 ) return false; } else { pdataset->nclasses = atol(ColsArr[3].c_str()); pdataset->nout = 1; if( pdataset->nclasses<2 ) return false; } } // // initialize arrays // pdataset->all.setlength(pdataset->totalsize, pdataset->nin+pdataset->nout); if( pdataset->trnsize>0 ) pdataset->trn.setlength(pdataset->trnsize, pdataset->nin+pdataset->nout); if( pdataset->valsize>0 ) pdataset->val.setlength(pdataset->valsize, pdataset->nin+pdataset->nout); if( pdataset->tstsize>0 ) pdataset->tst.setlength(pdataset->tstsize, pdataset->nin+pdataset->nout); // // read data // for(LinesRead=0, i++; i!=Lines.end() && LinesReadtotalsize; i++, LinesRead++) { std::string sss = *i; alglib::explodestring(alglib::xtrim(*i), ' ', &VarsArr); if( VarsArr.size()!=pdataset->nin+pdataset->nout ) return false; int tmpc = alglib::round(atof(VarsArr[pdataset->nin+pdataset->nout-1].c_str())); if( pdataset->nclasses>0 && (tmpc<0 || tmpc>=pdataset->nclasses) ) return false; for(j=0; jnin+pdataset->nout; j++) { pdataset->all(LinesRead,j) = atof(VarsArr[j].c_str()); if( LinesRead>=TrnFirst && LinesReadtrn(LinesRead-TrnFirst,j) = atof(VarsArr[j].c_str()); if( LinesRead>=ValFirst && LinesReadval(LinesRead-ValFirst,j) = atof(VarsArr[j].c_str()); if( LinesRead>=TstFirst && LinesReadtst(LinesRead-TstFirst,j) = atof(VarsArr[j].c_str()); } } if( LinesRead!=pdataset->totalsize ) return false; return true; }*/ /* previous variant bool alglib::opendataset(std::string file, dataset *pdataset) { std::list Lines; std::vector Values; std::list::iterator i; int nCol, nRow, nSplitted; int nColumns, nRows; // // Read data // if( pdataset==NULL ) return false; if( !readstrings(file, &Lines, "//") ) return false; i = Lines.begin(); *pdataset = dataset(); // // Read columns info // if( i==Lines.end() ) return false; if( sscanf(i->c_str(), " columns = %d %d ", &pdataset->nin, &pdataset->nout)!=2 ) return false; if( pdataset->nin<=0 || pdataset->nout==0 || pdataset->nout==-1) return false; if( pdataset->nout<0 ) { pdataset->nclasses = -pdataset->nout; pdataset->nout = 1; pdataset->iscls = true; } else { pdataset->isreg = true; } nColumns = pdataset->nin+pdataset->nout; i++; // // Read rows info // if( i==Lines.end() ) return false; if( sscanf(i->c_str(), " rows = %d %d %d ", &pdataset->trnsize, &pdataset->valsize, &pdataset->tstsize)!=3 ) return false; if( (pdataset->trnsize<0) || (pdataset->valsize<0) || (pdataset->tstsize<0) ) return false; if( (pdataset->trnsize==0) && (pdataset->valsize==0) && (pdataset->tstsize==0) ) return false; nRows = pdataset->trnsize+pdataset->valsize+pdataset->tstsize; pdataset->size = nRows; if( Lines.size()!=nRows+2 ) return false; i++; // // Read all cases // alglib::real_2d_array &arr = pdataset->all; arr.setbounds(0, nRows-1, 0, nColumns-1); for(nRow=0; nRowiscls && ((round(v)<0) || (round(v)>=pdataset->nclasses)) ) return false; if( (nCol==nColumns-1) && pdataset->iscls ) arr(nRow, nCol) = round(v); else arr(nRow, nCol) = v; } i++; } // // Split to training, validation and test sets // if( pdataset->trnsize>0 ) pdataset->trn.setbounds(0, pdataset->trnsize-1, 0, nColumns-1); if( pdataset->valsize>0 ) pdataset->val.setbounds(0, pdataset->valsize-1, 0, nColumns-1); if( pdataset->tstsize>0 ) pdataset->tst.setbounds(0, pdataset->tstsize-1, 0, nColumns-1); nSplitted=0; for(nRow=0; nRow<=pdataset->trnsize-1; nRow++, nSplitted++) for(nCol=0; nCol<=nColumns-1; nCol++) pdataset->trn(nRow,nCol) = arr(nSplitted,nCol); for(nRow=0; nRow<=pdataset->valsize-1; nRow++, nSplitted++) for(nCol=0; nCol<=nColumns-1; nCol++) pdataset->val(nRow,nCol) = arr(nSplitted,nCol); for(nRow=0; nRow<=pdataset->tstsize-1; nRow++, nSplitted++) for(nCol=0; nCol<=nColumns-1; nCol++) pdataset->tst(nRow,nCol) = arr(nSplitted,nCol); return true; }*/ alglib::ae_int_t alglib::vlen(ae_int_t n1, ae_int_t n2) { return n2-n1+1; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTIONS CONTAINS OPTIMIZED LINEAR ALGEBRA CODE // IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { #define alglib_simd_alignment 16 #define alglib_r_block 32 #define alglib_half_r_block 16 #define alglib_twice_r_block 64 #define alglib_c_block 24 #define alglib_half_c_block 12 #define alglib_twice_c_block 48 /******************************************************************** This subroutine calculates fast 32x32 real matrix-vector product: y := beta*y + alpha*A*x using either generic C code or native optimizations (if available) IMPORTANT: * A must be stored in row-major order, stride is alglib_r_block, aligned on alglib_simd_alignment boundary * X must be aligned on alglib_simd_alignment boundary * Y may be non-aligned ********************************************************************/ void _ialglib_mv_32(const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) { ae_int_t i, k; const double *pa0, *pa1, *pb; pa0 = a; pa1 = a+alglib_r_block; pb = x; for(i=0; i<16; i++) { double v0 = 0, v1 = 0; for(k=0; k<4; k++) { v0 += pa0[0]*pb[0]; v1 += pa1[0]*pb[0]; v0 += pa0[1]*pb[1]; v1 += pa1[1]*pb[1]; v0 += pa0[2]*pb[2]; v1 += pa1[2]*pb[2]; v0 += pa0[3]*pb[3]; v1 += pa1[3]*pb[3]; v0 += pa0[4]*pb[4]; v1 += pa1[4]*pb[4]; v0 += pa0[5]*pb[5]; v1 += pa1[5]*pb[5]; v0 += pa0[6]*pb[6]; v1 += pa1[6]*pb[6]; v0 += pa0[7]*pb[7]; v1 += pa1[7]*pb[7]; pa0 += 8; pa1 += 8; pb += 8; } y[0] = beta*y[0]+alpha*v0; y[stride] = beta*y[stride]+alpha*v1; /* * now we've processed rows I and I+1, * pa0 and pa1 are pointing to rows I+1 and I+2. * move to I+2 and I+3. */ pa0 += alglib_r_block; pa1 += alglib_r_block; pb = x; y+=2*stride; } } /************************************************************************* This function calculates MxN real matrix-vector product: y := beta*y + alpha*A*x using generic C code. It calls _ialglib_mv_32 if both M=32 and N=32. If beta is zero, we do not use previous values of y (they are overwritten by alpha*A*x without ever being read). If alpha is zero, no matrix-vector product is calculated (only beta is updated); however, this update is not efficient and this function should NOT be used for multiplication of vector and scalar. IMPORTANT: * 0<=M<=alglib_r_block, 0<=N<=alglib_r_block * A must be stored in row-major order with stride equal to alglib_r_block *************************************************************************/ void _ialglib_rmv(ae_int_t m, ae_int_t n, const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) { /* * Handle special cases: * - alpha is zero or n is zero * - m is zero */ if( m==0 ) return; if( alpha==0.0 || n==0 ) { ae_int_t i; if( beta==0.0 ) { for(i=0; ix-beta.y*cy->y)+(alpha.x*v0-alpha.y*v1); double ty = (beta.x*cy->y+beta.y*cy->x)+(alpha.x*v1+alpha.y*v0); cy->x = tx; cy->y = ty; cy+=stride; } else { double tx = (beta.x*dy[0]-beta.y*dy[1])+(alpha.x*v0-alpha.y*v1); double ty = (beta.x*dy[1]+beta.y*dy[0])+(alpha.x*v1+alpha.y*v0); dy[0] = tx; dy[1] = ty; dy += 2*stride; } parow += 2*alglib_c_block; } } /************************************************************************* This subroutine calculates fast MxN complex matrix-vector product: y := beta*y + alpha*A*x using generic C code, where A, x, y, alpha and beta are complex. If beta is zero, we do not use previous values of y (they are overwritten by alpha*A*x without ever being read). However, when alpha is zero, we still calculate A*x and multiply it by alpha (this distinction can be important when A or x contain infinities/NANs). IMPORTANT: * 0<=M<=alglib_c_block, 0<=N<=alglib_c_block * A must be stored in row-major order, as sequence of double precision pairs. Stride is alglib_c_block (it is measured in pairs of doubles, not in doubles). * Y may be referenced by cy (pointer to ae_complex) or dy (pointer to array of double precision pair) depending on what type of output you wish. Pass pointer to Y as one of these parameters, AND SET OTHER PARAMETER TO NULL. * both A and x must be aligned; y may be non-aligned. This function supports SSE2; it can be used when: 1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time) 2. ae_cpuid() result contains CPU_SSE2 (checked at run-time) If (1) is failed, this function will be undefined. If (2) is failed, call to this function will probably crash your system. If you want to know whether it is safe to call it, you should check results of ae_cpuid(). If CPU_SSE2 bit is set, this function is callable and will do its work. *************************************************************************/ #if defined(AE_HAS_SSE2_INTRINSICS) void _ialglib_cmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x, ae_complex *cy, double *dy, ae_int_t stride, ae_complex alpha, ae_complex beta) { ae_int_t i, j, m2; const double *pa0, *pa1, *parow, *pb; __m128d vbeta, vbetax, vbetay; __m128d valpha, valphax, valphay; m2 = m/2; parow = a; if( cy!=NULL ) { dy = (double*)cy; cy = NULL; } vbeta = _mm_loadh_pd(_mm_load_sd(&beta.x),&beta.y); vbetax = _mm_unpacklo_pd(vbeta,vbeta); vbetay = _mm_unpackhi_pd(vbeta,vbeta); valpha = _mm_loadh_pd(_mm_load_sd(&alpha.x),&alpha.y); valphax = _mm_unpacklo_pd(valpha,valpha); valphay = _mm_unpackhi_pd(valpha,valpha); for(i=0; ix = 0.0; p->y = 0.0; } } else { for(i=0; ix = 0.0; p->y = 0.0; } } } /******************************************************************** This subroutine copies unaligned real vector ********************************************************************/ void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb) { ae_int_t i, n2; if( stridea==1 && strideb==1 ) { n2 = n/2; for(i=n2; i!=0; i--, a+=2, b+=2) { b[0] = a[0]; b[1] = a[1]; } if( n%2!=0 ) b[0] = a[0]; } else { for(i=0; ix; b[1] = a->y; } } else { for(i=0; ix; b[1] = -a->y; } } } /******************************************************************** This subroutine copies unaligned complex vector (passed as double*) 1. strideb is stride measured in complex numbers, not doubles 2. conj may be "N" (no conj.) or "C" (conj.) ********************************************************************/ void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj) { ae_int_t i; /* * more general case */ if( conj[0]=='N' || conj[0]=='n' ) { for(i=0; ix; pdst[1] = psrc->y; } } if( op==1 ) { for(i=0,psrc=a; ix; pdst[1] = psrc->y; } } if( op==2 ) { for(i=0,psrc=a; ix; pdst[1] = -psrc->y; } } if( op==3 ) { for(i=0,psrc=a; ix; pdst[1] = -psrc->y; } } } /******************************************************************** This subroutine copies matrix from aligned contigous storage to non-aligned non-contigous storage A: * 2*alglib_c_block*alglib_c_block doubles (only MxN submatrix is used) * aligned * stride is alglib_c_block * pointer to double is passed * may be transformed during copying (as prescribed by op) B: * MxN * non-aligned * non-contigous * pointer to ae_complex is passed Transformation types: * 0 - no transform * 1 - transposition * 2 - conjugate transposition * 3 - conjugate, but no transposition ********************************************************************/ void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride) { ae_int_t i, j; const double *psrc; ae_complex *pdst; if( op==0 ) { for(i=0,psrc=a; ix = psrc[0]; pdst->y = psrc[1]; } } if( op==1 ) { for(i=0,psrc=a; ix = psrc[0]; pdst->y = psrc[1]; } } if( op==2 ) { for(i=0,psrc=a; ix = psrc[0]; pdst->y = -psrc[1]; } } if( op==3 ) { for(i=0,psrc=a; ix = psrc[0]; pdst->y = -psrc[1]; } } } /******************************************************************** Real GEMM kernel ********************************************************************/ ae_bool _ialglib_rmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, double *_a, ae_int_t _a_stride, ae_int_t optypea, double *_b, ae_int_t _b_stride, ae_int_t optypeb, double beta, double *_c, ae_int_t _c_stride) { int i; double *crow; double _abuf[alglib_r_block+alglib_simd_alignment]; double _bbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; double * const abuf = (double * const) ae_align(_abuf,alglib_simd_alignment); double * const b = (double * const) ae_align(_bbuf,alglib_simd_alignment); void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; if( m>alglib_r_block || n>alglib_r_block || k>alglib_r_block || m<=0 || n<=0 || k<=0 || alpha==0.0 ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { rmv = &_ialglib_rmv_sse2; mcopyblock = &_ialglib_mcopyblock_sse2; } #endif /* * copy b */ if( optypeb==0 ) mcopyblock(k, n, _b, 1, _b_stride, b); else mcopyblock(n, k, _b, 0, _b_stride, b); /* * multiply B by A (from the right, by rows) * and store result in C */ crow = _c; if( optypea==0 ) { const double *arow = _a; for(i=0; ialglib_c_block || n>alglib_c_block || k>alglib_c_block ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { cmv = &_ialglib_cmv_sse2; } #endif /* * copy b */ brows = optypeb==0 ? k : n; bcols = optypeb==0 ? n : k; if( optypeb==0 ) _ialglib_mcopyblock_complex(brows, bcols, _b, 1, _b_stride, b); if( optypeb==1 ) _ialglib_mcopyblock_complex(brows, bcols, _b, 0, _b_stride, b); if( optypeb==2 ) _ialglib_mcopyblock_complex(brows, bcols, _b, 3, _b_stride, b); /* * multiply B by A (from the right, by rows) * and store result in C */ arow = _a; crow = _c; for(i=0; ialglib_c_block || n>alglib_c_block ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { cmv = &_ialglib_cmv_sse2; } #endif /* * Prepare */ _ialglib_mcopyblock_complex(n, n, _a, optype, _a_stride, abuf); _ialglib_mcopyblock_complex(m, n, _x, 0, _x_stride, xbuf); if( isunit ) for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) { ae_complex tmp_c; ae_complex beta; ae_complex alpha; tmp_c.x = pdiag[0]; tmp_c.y = pdiag[1]; beta = ae_c_d_div(1.0, tmp_c); alpha.x = -beta.x; alpha.y = -beta.y; _ialglib_vcopy_dcomplex(n-1-i, pdiag+2*alglib_c_block, alglib_c_block, tmpbuf, 1, "No conj"); cmv(m, n-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); } _ialglib_mcopyunblock_complex(m, n, xbuf, 0, _x, _x_stride); } return ae_true; } /******************************************************************** real TRSM kernel ********************************************************************/ ae_bool _ialglib_rmatrixrighttrsm(ae_int_t m, ae_int_t n, double *_a, ae_int_t _a_stride, ae_bool isupper, ae_bool isunit, ae_int_t optype, double *_x, ae_int_t _x_stride) { /* * local buffers */ double *pdiag; ae_int_t i; double _loc_abuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; double _loc_xbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; double _loc_tmpbuf[alglib_r_block+alglib_simd_alignment]; double * const abuf = (double * const) ae_align(_loc_abuf, alglib_simd_alignment); double * const xbuf = (double * const) ae_align(_loc_xbuf, alglib_simd_alignment); double * const tmpbuf = (double * const) ae_align(_loc_tmpbuf,alglib_simd_alignment); ae_bool uppera; void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; if( m>alglib_r_block || n>alglib_r_block ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { rmv = &_ialglib_rmv_sse2; mcopyblock = &_ialglib_mcopyblock_sse2; } #endif /* * Prepare */ mcopyblock(n, n, _a, optype, _a_stride, abuf); mcopyblock(m, n, _x, 0, _x_stride, xbuf); if( isunit ) for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) { double beta = 1.0/(*pdiag); double alpha = -beta; _ialglib_vcopy(n-1-i, pdiag+alglib_r_block, alglib_r_block, tmpbuf+i+1, 1); rmv(m, n-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); } _ialglib_mcopyunblock(m, n, xbuf, 0, _x, _x_stride); } return ae_true; } /******************************************************************** complex TRSM kernel ********************************************************************/ ae_bool _ialglib_cmatrixlefttrsm(ae_int_t m, ae_int_t n, ae_complex *_a, ae_int_t _a_stride, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_complex *_x, ae_int_t _x_stride) { /* * local buffers */ double *pdiag, *arow; ae_int_t i; double _loc_abuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; double _loc_xbuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; double _loc_tmpbuf[2*alglib_c_block+alglib_simd_alignment]; double * const abuf = (double * const) ae_align(_loc_abuf, alglib_simd_alignment); double * const xbuf = (double * const) ae_align(_loc_xbuf, alglib_simd_alignment); double * const tmpbuf = (double * const) ae_align(_loc_tmpbuf,alglib_simd_alignment); ae_bool uppera; void (*cmv)(ae_int_t, ae_int_t, const double *, const double *, ae_complex *, double *, ae_int_t, ae_complex, ae_complex) = &_ialglib_cmv; if( m>alglib_c_block || n>alglib_c_block ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { cmv = &_ialglib_cmv_sse2; } #endif /* * Prepare * Transpose X (so we may use mv, which calculates A*x, but not x*A) */ _ialglib_mcopyblock_complex(m, m, _a, optype, _a_stride, abuf); _ialglib_mcopyblock_complex(m, n, _x, 1, _x_stride, xbuf); if( isunit ) for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) { ae_complex tmp_c; ae_complex beta; ae_complex alpha; tmp_c.x = pdiag[0]; tmp_c.y = pdiag[1]; beta = ae_c_d_div(1.0, tmp_c); alpha.x = -beta.x; alpha.y = -beta.y; _ialglib_vcopy_dcomplex(m-1-i, pdiag+2, 1, tmpbuf, 1, "No conj"); cmv(n, m-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); } _ialglib_mcopyunblock_complex(m, n, xbuf, 1, _x, _x_stride); } else { for(i=0,pdiag=abuf,arow=abuf; ialglib_r_block || n>alglib_r_block ) return ae_false; /* * Check for SSE2 support */ #ifdef AE_HAS_SSE2_INTRINSICS if( ae_cpuid() & CPU_SSE2 ) { rmv = &_ialglib_rmv_sse2; mcopyblock = &_ialglib_mcopyblock_sse2; } #endif /* * Prepare * Transpose X (so we may use mv, which calculates A*x, but not x*A) */ mcopyblock(m, m, _a, optype, _a_stride, abuf); mcopyblock(m, n, _x, 1, _x_stride, xbuf); if( isunit ) for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) { double beta = 1.0/(*pdiag); double alpha = -beta; _ialglib_vcopy(m-1-i, pdiag+1, 1, tmpbuf+i+1, 1); rmv(n, m-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); } _ialglib_mcopyunblock(m, n, xbuf, 1, _x, _x_stride); } else { for(i=0,pdiag=abuf,arow=abuf; ialglib_c_block || k>alglib_c_block ) return ae_false; if( n==0 ) return ae_true; /* * copy A and C, task is transformed to "A*A^H"-form. * if beta==0, then C is filled by zeros (and not referenced) * * alpha==0 or k==0 are correctly processed (A is not referenced) */ c_alpha.x = alpha; c_alpha.y = 0; c_beta.x = beta; c_beta.y = 0; if( alpha==0 ) k = 0; if( k>0 ) { if( optypea==0 ) _ialglib_mcopyblock_complex(n, k, _a, 3, _a_stride, abuf); else _ialglib_mcopyblock_complex(k, n, _a, 1, _a_stride, abuf); } _ialglib_mcopyblock_complex(n, n, _c, 0, _c_stride, cbuf); if( beta==0 ) { for(i=0,crow=cbuf; ialglib_r_block || k>alglib_r_block ) return ae_false; if( n==0 ) return ae_true; /* * copy A and C, task is transformed to "A*A^T"-form. * if beta==0, then C is filled by zeros (and not referenced) * * alpha==0 or k==0 are correctly processed (A is not referenced) */ if( alpha==0 ) k = 0; if( k>0 ) { if( optypea==0 ) _ialglib_mcopyblock(n, k, _a, 0, _a_stride, abuf); else _ialglib_mcopyblock(k, n, _a, 1, _a_stride, abuf); } _ialglib_mcopyblock(n, n, _c, 0, _c_stride, cbuf); if( beta==0 ) { for(i=0,crow=cbuf; iptr.pp_double[ia]+ja, _a->stride, optypea, _b->ptr.pp_double[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_double[ic]+jc, _c->stride); } ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, ae_matrix *_a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, ae_matrix *_b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, ae_matrix *_c, ae_int_t ic, ae_int_t jc) { return _ialglib_cmatrixgemm(m, n, k, alpha, _a->ptr.pp_complex[ia]+ja, _a->stride, optypea, _b->ptr.pp_complex[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_complex[ic]+jc, _c->stride); } ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2) { return _ialglib_cmatrixrighttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); } ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2) { return _ialglib_rmatrixrighttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); } ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2) { return _ialglib_cmatrixlefttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); } ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2) { return _ialglib_rmatrixlefttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); } ae_bool _ialglib_i_cmatrixherkf(ae_int_t n, ae_int_t k, double alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, ae_matrix *c, ae_int_t ic, ae_int_t jc, ae_bool isupper) { return _ialglib_cmatrixherk(n, k, alpha, &a->ptr.pp_complex[ia][ja], a->stride, optypea, beta, &c->ptr.pp_complex[ic][jc], c->stride, isupper); } ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, ae_int_t k, double alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, ae_matrix *c, ae_int_t ic, ae_int_t jc, ae_bool isupper) { return _ialglib_rmatrixsyrk(n, k, alpha, &a->ptr.pp_double[ia][ja], a->stride, optypea, beta, &c->ptr.pp_double[ic][jc], c->stride, isupper); } ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_vector *u, ae_int_t uoffs, ae_vector *v, ae_int_t voffs) { return _ialglib_cmatrixrank1(m, n, &a->ptr.pp_complex[ia][ja], a->stride, &u->ptr.p_complex[uoffs], &v->ptr.p_complex[voffs]); } ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_vector *u, ae_int_t uoffs, ae_vector *v, ae_int_t voffs) { return _ialglib_rmatrixrank1(m, n, &a->ptr.pp_double[ia][ja], a->stride, &u->ptr.p_double[uoffs], &v->ptr.p_double[voffs]); } /******************************************************************** This function reads rectangular matrix A given by two column pointers col0 and col1 and stride src_stride and moves it into contiguous row- by-row storage given by dst. It can handle following special cases: * col1==NULL in this case second column of A is filled by zeros ********************************************************************/ void _ialglib_pack_n2( double *col0, double *col1, ae_int_t n, ae_int_t src_stride, double *dst) { ae_int_t n2, j, stride2; /* * handle special case */ if( col1==NULL ) { for(j=0; j>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "diffequations.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* *************************************************************************/ _odesolverstate_owner::_odesolverstate_owner() { p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_odesolverstate_init(p_struct, NULL); } _odesolverstate_owner::_odesolverstate_owner(const _odesolverstate_owner &rhs) { p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _odesolverstate_owner& _odesolverstate_owner::operator=(const _odesolverstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_odesolverstate_clear(p_struct); alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _odesolverstate_owner::~_odesolverstate_owner() { alglib_impl::_odesolverstate_clear(p_struct); ae_free(p_struct); } alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() { return p_struct; } alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() const { return const_cast(p_struct); } odesolverstate::odesolverstate() : _odesolverstate_owner() ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) { } odesolverstate::odesolverstate(const odesolverstate &rhs):_odesolverstate_owner(rhs) ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) { } odesolverstate& odesolverstate::operator=(const odesolverstate &rhs) { if( this==&rhs ) return *this; _odesolverstate_owner::operator=(rhs); return *this; } odesolverstate::~odesolverstate() { } /************************************************************************* *************************************************************************/ _odesolverreport_owner::_odesolverreport_owner() { p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_odesolverreport_init(p_struct, NULL); } _odesolverreport_owner::_odesolverreport_owner(const _odesolverreport_owner &rhs) { p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _odesolverreport_owner& _odesolverreport_owner::operator=(const _odesolverreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_odesolverreport_clear(p_struct); alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _odesolverreport_owner::~_odesolverreport_owner() { alglib_impl::_odesolverreport_clear(p_struct); ae_free(p_struct); } alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() { return p_struct; } alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() const { return const_cast(p_struct); } odesolverreport::odesolverreport() : _odesolverreport_owner() ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) { } odesolverreport::odesolverreport(const odesolverreport &rhs):_odesolverreport_owner(rhs) ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) { } odesolverreport& odesolverreport::operator=(const odesolverreport &rhs) { if( this==&rhs ) return *this; _odesolverreport_owner::operator=(rhs); return *this; } odesolverreport::~odesolverreport() { } /************************************************************************* Cash-Karp adaptive ODE solver. This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys (here Y may be single variable or vector of N variables). INPUT PARAMETERS: Y - initial conditions, array[0..N-1]. contains values of Y[] at X[0] N - system size X - points at which Y should be tabulated, array[0..M-1] integrations starts at X[0], ends at X[M-1], intermediate values at X[i] are returned too. SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! M - number of intermediate points + first point + last point: * M>2 means that you need both Y(X[M-1]) and M-2 values at intermediate points * M=2 means that you want just to integrate from X[0] to X[1] and don't interested in intermediate values. * M=1 means that you don't want to integrate :) it is degenerate case, but it will be handled correctly. * M<1 means error Eps - tolerance (absolute/relative error on each step will be less than Eps). When passing: * Eps>0, it means desired ABSOLUTE error * Eps<0, it means desired RELATIVE error. Relative errors are calculated with respect to maximum values of Y seen so far. Be careful to use this criterion when starting from Y[] that are close to zero. H - initial step lenth, it will be adjusted automatically after the first step. If H=0, step will be selected automatically (usualy it will be equal to 0.001 of min(x[i]-x[j])). OUTPUT PARAMETERS State - structure which stores algorithm state between subsequent calls of OdeSolverIteration. Used for reverse communication. This structure should be passed to the OdeSolverIteration subroutine. SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::odesolverrkck(const_cast(y.c_ptr()), n, const_cast(x.c_ptr()), m, eps, h, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cash-Karp adaptive ODE solver. This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys (here Y may be single variable or vector of N variables). INPUT PARAMETERS: Y - initial conditions, array[0..N-1]. contains values of Y[] at X[0] N - system size X - points at which Y should be tabulated, array[0..M-1] integrations starts at X[0], ends at X[M-1], intermediate values at X[i] are returned too. SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! M - number of intermediate points + first point + last point: * M>2 means that you need both Y(X[M-1]) and M-2 values at intermediate points * M=2 means that you want just to integrate from X[0] to X[1] and don't interested in intermediate values. * M=1 means that you don't want to integrate :) it is degenerate case, but it will be handled correctly. * M<1 means error Eps - tolerance (absolute/relative error on each step will be less than Eps). When passing: * Eps>0, it means desired ABSOLUTE error * Eps<0, it means desired RELATIVE error. Relative errors are calculated with respect to maximum values of Y seen so far. Be careful to use this criterion when starting from Y[] that are close to zero. H - initial step lenth, it will be adjusted automatically after the first step. If H=0, step will be selected automatically (usualy it will be equal to 0.001 of min(x[i]-x[j])). OUTPUT PARAMETERS State - structure which stores algorithm state between subsequent calls of OdeSolverIteration. Used for reverse communication. This structure should be passed to the OdeSolverIteration subroutine. SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = y.length(); m = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::odesolverrkck(const_cast(y.c_ptr()), n, const_cast(x.c_ptr()), m, eps, h, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool odesolveriteration(const odesolverstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::odesolveriteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void odesolversolve(odesolverstate &state, void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), void *ptr){ alglib_impl::ae_state _alglib_env_state; if( diff==NULL ) throw ap_error("ALGLIB: error in 'odesolversolve()' (diff is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::odesolveriteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needdy ) { diff(state.y, state.x, state.dy, ptr); continue; } throw ap_error("ALGLIB: unexpected error in 'odesolversolve'"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* ODE solver results Called after OdeSolverIteration returned False. INPUT PARAMETERS: State - algorithm state (used by OdeSolverIteration). OUTPUT PARAMETERS: M - number of tabulated values, M>=1 XTbl - array[0..M-1], values of X YTbl - array[0..M-1,0..N-1], values of Y in X[i] Rep - solver report: * Rep.TerminationType completetion code: * -2 X is not ordered by ascending/descending or there are non-distinct X[], i.e. X[i]=X[i+1] * -1 incorrect parameters were specified * 1 task has been solved * Rep.NFEV contains number of function calculations -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::odesolverresults(const_cast(state.c_ptr()), &m, const_cast(xtbl.c_ptr()), const_cast(ytbl.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static double odesolver_odesolvermaxgrow = 3.0; static double odesolver_odesolvermaxshrink = 10.0; static void odesolver_odesolverinit(ae_int_t solvertype, /* Real */ ae_vector* y, ae_int_t n, /* Real */ ae_vector* x, ae_int_t m, double eps, double h, odesolverstate* state, ae_state *_state); /************************************************************************* Cash-Karp adaptive ODE solver. This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys (here Y may be single variable or vector of N variables). INPUT PARAMETERS: Y - initial conditions, array[0..N-1]. contains values of Y[] at X[0] N - system size X - points at which Y should be tabulated, array[0..M-1] integrations starts at X[0], ends at X[M-1], intermediate values at X[i] are returned too. SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! M - number of intermediate points + first point + last point: * M>2 means that you need both Y(X[M-1]) and M-2 values at intermediate points * M=2 means that you want just to integrate from X[0] to X[1] and don't interested in intermediate values. * M=1 means that you don't want to integrate :) it is degenerate case, but it will be handled correctly. * M<1 means error Eps - tolerance (absolute/relative error on each step will be less than Eps). When passing: * Eps>0, it means desired ABSOLUTE error * Eps<0, it means desired RELATIVE error. Relative errors are calculated with respect to maximum values of Y seen so far. Be careful to use this criterion when starting from Y[] that are close to zero. H - initial step lenth, it will be adjusted automatically after the first step. If H=0, step will be selected automatically (usualy it will be equal to 0.001 of min(x[i]-x[j])). OUTPUT PARAMETERS State - structure which stores algorithm state between subsequent calls of OdeSolverIteration. Used for reverse communication. This structure should be passed to the OdeSolverIteration subroutine. SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverrkck(/* Real */ ae_vector* y, ae_int_t n, /* Real */ ae_vector* x, ae_int_t m, double eps, double h, odesolverstate* state, ae_state *_state) { _odesolverstate_clear(state); ae_assert(n>=1, "ODESolverRKCK: N<1!", _state); ae_assert(m>=1, "ODESolverRKCK: M<1!", _state); ae_assert(y->cnt>=n, "ODESolverRKCK: Length(Y)cnt>=m, "ODESolverRKCK: Length(X)rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; i = state->rstate.ia.ptr.p_int[2]; j = state->rstate.ia.ptr.p_int[3]; k = state->rstate.ia.ptr.p_int[4]; klimit = state->rstate.ia.ptr.p_int[5]; gridpoint = state->rstate.ba.ptr.p_bool[0]; xc = state->rstate.ra.ptr.p_double[0]; v = state->rstate.ra.ptr.p_double[1]; h = state->rstate.ra.ptr.p_double[2]; h2 = state->rstate.ra.ptr.p_double[3]; err = state->rstate.ra.ptr.p_double[4]; maxgrowpow = state->rstate.ra.ptr.p_double[5]; } else { n = -983; m = -989; i = -834; j = 900; k = -287; klimit = 364; gridpoint = ae_false; xc = -338; v = -686; h = 912; h2 = 585; err = 497; maxgrowpow = -271; } if( state->rstate.stage==0 ) { goto lbl_0; } /* * Routine body */ /* * prepare */ if( state->repterminationtype!=0 ) { result = ae_false; return result; } n = state->n; m = state->m; h = state->h; maxgrowpow = ae_pow(odesolver_odesolvermaxgrow, (double)(5), _state); state->repnfev = 0; /* * some preliminary checks for internal errors * after this we assume that H>0 and M>1 */ ae_assert(ae_fp_greater(state->h,(double)(0)), "ODESolver: internal error", _state); ae_assert(m>1, "ODESolverIteration: internal error", _state); /* * choose solver */ if( state->solvertype!=0 ) { goto lbl_1; } /* * Cask-Karp solver * Prepare coefficients table. * Check it for errors */ ae_vector_set_length(&state->rka, 6, _state); state->rka.ptr.p_double[0] = (double)(0); state->rka.ptr.p_double[1] = (double)1/(double)5; state->rka.ptr.p_double[2] = (double)3/(double)10; state->rka.ptr.p_double[3] = (double)3/(double)5; state->rka.ptr.p_double[4] = (double)(1); state->rka.ptr.p_double[5] = (double)7/(double)8; ae_matrix_set_length(&state->rkb, 6, 5, _state); state->rkb.ptr.pp_double[1][0] = (double)1/(double)5; state->rkb.ptr.pp_double[2][0] = (double)3/(double)40; state->rkb.ptr.pp_double[2][1] = (double)9/(double)40; state->rkb.ptr.pp_double[3][0] = (double)3/(double)10; state->rkb.ptr.pp_double[3][1] = -(double)9/(double)10; state->rkb.ptr.pp_double[3][2] = (double)6/(double)5; state->rkb.ptr.pp_double[4][0] = -(double)11/(double)54; state->rkb.ptr.pp_double[4][1] = (double)5/(double)2; state->rkb.ptr.pp_double[4][2] = -(double)70/(double)27; state->rkb.ptr.pp_double[4][3] = (double)35/(double)27; state->rkb.ptr.pp_double[5][0] = (double)1631/(double)55296; state->rkb.ptr.pp_double[5][1] = (double)175/(double)512; state->rkb.ptr.pp_double[5][2] = (double)575/(double)13824; state->rkb.ptr.pp_double[5][3] = (double)44275/(double)110592; state->rkb.ptr.pp_double[5][4] = (double)253/(double)4096; ae_vector_set_length(&state->rkc, 6, _state); state->rkc.ptr.p_double[0] = (double)37/(double)378; state->rkc.ptr.p_double[1] = (double)(0); state->rkc.ptr.p_double[2] = (double)250/(double)621; state->rkc.ptr.p_double[3] = (double)125/(double)594; state->rkc.ptr.p_double[4] = (double)(0); state->rkc.ptr.p_double[5] = (double)512/(double)1771; ae_vector_set_length(&state->rkcs, 6, _state); state->rkcs.ptr.p_double[0] = (double)2825/(double)27648; state->rkcs.ptr.p_double[1] = (double)(0); state->rkcs.ptr.p_double[2] = (double)18575/(double)48384; state->rkcs.ptr.p_double[3] = (double)13525/(double)55296; state->rkcs.ptr.p_double[4] = (double)277/(double)14336; state->rkcs.ptr.p_double[5] = (double)1/(double)4; ae_matrix_set_length(&state->rkk, 6, n, _state); /* * Main cycle consists of two iterations: * * outer where we travel from X[i-1] to X[i] * * inner where we travel inside [X[i-1],X[i]] */ ae_matrix_set_length(&state->ytbl, m, n, _state); ae_vector_set_length(&state->escale, n, _state); ae_vector_set_length(&state->yn, n, _state); ae_vector_set_length(&state->yns, n, _state); xc = state->xg.ptr.p_double[0]; ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(j=0; j<=n-1; j++) { state->escale.ptr.p_double[j] = (double)(0); } i = 1; lbl_3: if( i>m-1 ) { goto lbl_5; } /* * begin inner iteration */ lbl_6: if( ae_false ) { goto lbl_7; } /* * truncate step if needed (beyond right boundary). * determine should we store X or not */ if( ae_fp_greater_eq(xc+h,state->xg.ptr.p_double[i]) ) { h = state->xg.ptr.p_double[i]-xc; gridpoint = ae_true; } else { gridpoint = ae_false; } /* * Update error scale maximums * * These maximums are initialized by zeros, * then updated every iterations. */ for(j=0; j<=n-1; j++) { state->escale.ptr.p_double[j] = ae_maxreal(state->escale.ptr.p_double[j], ae_fabs(state->yc.ptr.p_double[j], _state), _state); } /* * make one step: * 1. calculate all info needed to do step * 2. update errors scale maximums using values/derivatives * obtained during (1) * * Take into account that we use scaling of X to reduce task * to the form where x[0] < x[1] < ... < x[n-1]. So X is * replaced by x=xscale*t, and dy/dx=f(y,x) is replaced * by dy/dt=xscale*f(y,xscale*t). */ ae_v_move(&state->yn.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->yns.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); k = 0; lbl_8: if( k>5 ) { goto lbl_10; } /* * prepare data for the next update of YN/YNS */ state->x = state->xscale*(xc+state->rka.ptr.p_double[k]*h); ae_v_move(&state->y.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(j=0; j<=k-1; j++) { v = state->rkb.ptr.pp_double[k][j]; ae_v_addd(&state->y.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); } state->needdy = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needdy = ae_false; state->repnfev = state->repnfev+1; v = h*state->xscale; ae_v_moved(&state->rkk.ptr.pp_double[k][0], 1, &state->dy.ptr.p_double[0], 1, ae_v_len(0,n-1), v); /* * update YN/YNS */ v = state->rkc.ptr.p_double[k]; ae_v_addd(&state->yn.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); v = state->rkcs.ptr.p_double[k]; ae_v_addd(&state->yns.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); k = k+1; goto lbl_8; lbl_10: /* * estimate error */ err = (double)(0); for(j=0; j<=n-1; j++) { if( !state->fraceps ) { /* * absolute error is estimated */ err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state), _state); } else { /* * Relative error is estimated */ v = state->escale.ptr.p_double[j]; if( ae_fp_eq(v,(double)(0)) ) { v = (double)(1); } err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state)/v, _state); } } /* * calculate new step, restart if necessary */ if( ae_fp_less_eq(maxgrowpow*err,state->eps) ) { h2 = odesolver_odesolvermaxgrow*h; } else { h2 = h*ae_pow(state->eps/err, 0.2, _state); } if( ae_fp_less(h2,h/odesolver_odesolvermaxshrink) ) { h2 = h/odesolver_odesolvermaxshrink; } if( ae_fp_greater(err,state->eps) ) { h = h2; goto lbl_6; } /* * advance position */ xc = xc+h; ae_v_move(&state->yc.ptr.p_double[0], 1, &state->yn.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * update H */ h = h2; /* * break on grid point */ if( gridpoint ) { goto lbl_7; } goto lbl_6; lbl_7: /* * save result */ ae_v_move(&state->ytbl.ptr.pp_double[i][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); i = i+1; goto lbl_3; lbl_5: state->repterminationtype = 1; result = ae_false; return result; lbl_1: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = i; state->rstate.ia.ptr.p_int[3] = j; state->rstate.ia.ptr.p_int[4] = k; state->rstate.ia.ptr.p_int[5] = klimit; state->rstate.ba.ptr.p_bool[0] = gridpoint; state->rstate.ra.ptr.p_double[0] = xc; state->rstate.ra.ptr.p_double[1] = v; state->rstate.ra.ptr.p_double[2] = h; state->rstate.ra.ptr.p_double[3] = h2; state->rstate.ra.ptr.p_double[4] = err; state->rstate.ra.ptr.p_double[5] = maxgrowpow; return result; } /************************************************************************* ODE solver results Called after OdeSolverIteration returned False. INPUT PARAMETERS: State - algorithm state (used by OdeSolverIteration). OUTPUT PARAMETERS: M - number of tabulated values, M>=1 XTbl - array[0..M-1], values of X YTbl - array[0..M-1,0..N-1], values of Y in X[i] Rep - solver report: * Rep.TerminationType completetion code: * -2 X is not ordered by ascending/descending or there are non-distinct X[], i.e. X[i]=X[i+1] * -1 incorrect parameters were specified * 1 task has been solved * Rep.NFEV contains number of function calculations -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverresults(odesolverstate* state, ae_int_t* m, /* Real */ ae_vector* xtbl, /* Real */ ae_matrix* ytbl, odesolverreport* rep, ae_state *_state) { double v; ae_int_t i; *m = 0; ae_vector_clear(xtbl); ae_matrix_clear(ytbl); _odesolverreport_clear(rep); rep->terminationtype = state->repterminationtype; if( rep->terminationtype>0 ) { *m = state->m; rep->nfev = state->repnfev; ae_vector_set_length(xtbl, state->m, _state); v = state->xscale; ae_v_moved(&xtbl->ptr.p_double[0], 1, &state->xg.ptr.p_double[0], 1, ae_v_len(0,state->m-1), v); ae_matrix_set_length(ytbl, state->m, state->n, _state); for(i=0; i<=state->m-1; i++) { ae_v_move(&ytbl->ptr.pp_double[i][0], 1, &state->ytbl.ptr.pp_double[i][0], 1, ae_v_len(0,state->n-1)); } } else { rep->nfev = 0; } } /************************************************************************* Internal initialization subroutine *************************************************************************/ static void odesolver_odesolverinit(ae_int_t solvertype, /* Real */ ae_vector* y, ae_int_t n, /* Real */ ae_vector* x, ae_int_t m, double eps, double h, odesolverstate* state, ae_state *_state) { ae_int_t i; double v; _odesolverstate_clear(state); /* * Prepare RComm */ ae_vector_set_length(&state->rstate.ia, 5+1, _state); ae_vector_set_length(&state->rstate.ba, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 5+1, _state); state->rstate.stage = -1; state->needdy = ae_false; /* * check parameters. */ if( (n<=0||m<1)||ae_fp_eq(eps,(double)(0)) ) { state->repterminationtype = -1; return; } if( ae_fp_less(h,(double)(0)) ) { h = -h; } /* * quick exit if necessary. * after this block we assume that M>1 */ if( m==1 ) { state->repnfev = 0; state->repterminationtype = 1; ae_matrix_set_length(&state->ytbl, 1, n, _state); ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_vector_set_length(&state->xg, m, _state); ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); return; } /* * check again: correct order of X[] */ if( ae_fp_eq(x->ptr.p_double[1],x->ptr.p_double[0]) ) { state->repterminationtype = -2; return; } for(i=1; i<=m-1; i++) { if( (ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_less_eq(x->ptr.p_double[i],x->ptr.p_double[i-1]))||(ae_fp_less(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i-1])) ) { state->repterminationtype = -2; return; } } /* * auto-select H if necessary */ if( ae_fp_eq(h,(double)(0)) ) { v = ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state); for(i=2; i<=m-1; i++) { v = ae_minreal(v, ae_fabs(x->ptr.p_double[i]-x->ptr.p_double[i-1], _state), _state); } h = 0.001*v; } /* * store parameters */ state->n = n; state->m = m; state->h = h; state->eps = ae_fabs(eps, _state); state->fraceps = ae_fp_less(eps,(double)(0)); ae_vector_set_length(&state->xg, m, _state); ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); if( ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0]) ) { state->xscale = (double)(1); } else { state->xscale = (double)(-1); ae_v_muld(&state->xg.ptr.p_double[0], 1, ae_v_len(0,m-1), -1); } ae_vector_set_length(&state->yc, n, _state); ae_v_move(&state->yc.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->solvertype = solvertype; state->repterminationtype = 0; /* * Allocate arrays */ ae_vector_set_length(&state->y, n, _state); ae_vector_set_length(&state->dy, n, _state); } void _odesolverstate_init(void* _p, ae_state *_state) { odesolverstate *p = (odesolverstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->yc, 0, DT_REAL, _state); ae_vector_init(&p->escale, 0, DT_REAL, _state); ae_vector_init(&p->xg, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_vector_init(&p->dy, 0, DT_REAL, _state); ae_matrix_init(&p->ytbl, 0, 0, DT_REAL, _state); ae_vector_init(&p->yn, 0, DT_REAL, _state); ae_vector_init(&p->yns, 0, DT_REAL, _state); ae_vector_init(&p->rka, 0, DT_REAL, _state); ae_vector_init(&p->rkc, 0, DT_REAL, _state); ae_vector_init(&p->rkcs, 0, DT_REAL, _state); ae_matrix_init(&p->rkb, 0, 0, DT_REAL, _state); ae_matrix_init(&p->rkk, 0, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _odesolverstate_init_copy(void* _dst, void* _src, ae_state *_state) { odesolverstate *dst = (odesolverstate*)_dst; odesolverstate *src = (odesolverstate*)_src; dst->n = src->n; dst->m = src->m; dst->xscale = src->xscale; dst->h = src->h; dst->eps = src->eps; dst->fraceps = src->fraceps; ae_vector_init_copy(&dst->yc, &src->yc, _state); ae_vector_init_copy(&dst->escale, &src->escale, _state); ae_vector_init_copy(&dst->xg, &src->xg, _state); dst->solvertype = src->solvertype; dst->needdy = src->needdy; dst->x = src->x; ae_vector_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->dy, &src->dy, _state); ae_matrix_init_copy(&dst->ytbl, &src->ytbl, _state); dst->repterminationtype = src->repterminationtype; dst->repnfev = src->repnfev; ae_vector_init_copy(&dst->yn, &src->yn, _state); ae_vector_init_copy(&dst->yns, &src->yns, _state); ae_vector_init_copy(&dst->rka, &src->rka, _state); ae_vector_init_copy(&dst->rkc, &src->rkc, _state); ae_vector_init_copy(&dst->rkcs, &src->rkcs, _state); ae_matrix_init_copy(&dst->rkb, &src->rkb, _state); ae_matrix_init_copy(&dst->rkk, &src->rkk, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _odesolverstate_clear(void* _p) { odesolverstate *p = (odesolverstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->yc); ae_vector_clear(&p->escale); ae_vector_clear(&p->xg); ae_vector_clear(&p->y); ae_vector_clear(&p->dy); ae_matrix_clear(&p->ytbl); ae_vector_clear(&p->yn); ae_vector_clear(&p->yns); ae_vector_clear(&p->rka); ae_vector_clear(&p->rkc); ae_vector_clear(&p->rkcs); ae_matrix_clear(&p->rkb); ae_matrix_clear(&p->rkk); _rcommstate_clear(&p->rstate); } void _odesolverstate_destroy(void* _p) { odesolverstate *p = (odesolverstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->yc); ae_vector_destroy(&p->escale); ae_vector_destroy(&p->xg); ae_vector_destroy(&p->y); ae_vector_destroy(&p->dy); ae_matrix_destroy(&p->ytbl); ae_vector_destroy(&p->yn); ae_vector_destroy(&p->yns); ae_vector_destroy(&p->rka); ae_vector_destroy(&p->rkc); ae_vector_destroy(&p->rkcs); ae_matrix_destroy(&p->rkb); ae_matrix_destroy(&p->rkk); _rcommstate_destroy(&p->rstate); } void _odesolverreport_init(void* _p, ae_state *_state) { odesolverreport *p = (odesolverreport*)_p; ae_touch_ptr((void*)p); } void _odesolverreport_init_copy(void* _dst, void* _src, ae_state *_state) { odesolverreport *dst = (odesolverreport*)_dst; odesolverreport *src = (odesolverreport*)_src; dst->nfev = src->nfev; dst->terminationtype = src->terminationtype; } void _odesolverreport_clear(void* _p) { odesolverreport *p = (odesolverreport*)_p; ae_touch_ptr((void*)p); } void _odesolverreport_destroy(void* _p) { odesolverreport *p = (odesolverreport*)_p; ae_touch_ptr((void*)p); } } qmapshack-1.10.0/3rdparty/alglib/src/stdafx.h000755 001750 000144 00000000004 13015033052 022142 0ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/3rdparty/alglib/src/ap.h000755 001750 000144 00000165356 13015033052 021277 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _ap_h #define _ap_h #include #include #include #include #include #include #if defined(__CODEGEARC__) #include #include #elif defined(__BORLANDC__) #include #include #else #include #include #endif #define AE_USE_CPP /* Definitions */ #define AE_UNKNOWN 0 #define AE_MSVC 1 #define AE_GNUC 2 #define AE_SUNC 3 #define AE_INTEL 1 #define AE_SPARC 2 #define AE_WINDOWS 1 #define AE_POSIX 2 #define AE_LOCK_ALIGNMENT 16 /* in case no OS is defined, use AE_UNKNOWN */ #ifndef AE_OS #define AE_OS AE_UNKNOWN #endif /* automatically determine compiler */ #define AE_COMPILER AE_UNKNOWN #ifdef __GNUC__ #undef AE_COMPILER #define AE_COMPILER AE_GNUC #endif #if defined(__SUNPRO_C)||defined(__SUNPRO_CC) #undef AE_COMPILER #define AE_COMPILER AE_SUNC #endif #ifdef _MSC_VER #undef AE_COMPILER #define AE_COMPILER AE_MSVC #endif /* compiler-specific definitions */ #if AE_COMPILER==AE_MSVC #define ALIGNED __declspec(align(8)) #elif AE_COMPILER==AE_GNUC #define ALIGNED __attribute__((aligned(8))) #else #define ALIGNED #endif /* now we are ready to include headers */ #include #include #include #include #include #include #if defined(AE_HAVE_STDINT) #include #endif /* * SSE2 intrinsics * * Preprocessor directives below: * - include headers for SSE2 intrinsics * - define AE_HAS_SSE2_INTRINSICS definition * * These actions are performed when we have: * - x86 architecture definition (AE_CPU==AE_INTEL) * - compiler which supports intrinsics * * Presence of AE_HAS_SSE2_INTRINSICS does NOT mean that our CPU * actually supports SSE2 - such things should be determined at runtime * with ae_cpuid() call. It means that we are working under Intel and * out compiler can issue SSE2-capable code. * */ #if defined(AE_CPU) #if AE_CPU==AE_INTEL #if AE_COMPILER==AE_MSVC #include #define AE_HAS_SSE2_INTRINSICS #endif #if AE_COMPILER==AE_GNUC #include #define AE_HAS_SSE2_INTRINSICS #endif #if AE_COMPILER==AE_SUNC #include #include #define AE_HAS_SSE2_INTRINSICS #endif #endif #endif ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS DECLARATIONS FOR BASIC FUNCTIONALITY // LIKE MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS SHARED // BETWEEN C++ AND PURE C LIBRARIES // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { /* if we work under C++ environment, define several conditions */ #ifdef AE_USE_CPP #define AE_USE_CPP_BOOL #define AE_USE_CPP_ERROR_HANDLING #define AE_USE_CPP_SERIALIZATION #endif /* * define ae_int32_t, ae_int64_t, ae_int_t, ae_bool, ae_complex, ae_error_type and ae_datatype */ #if defined(AE_INT32_T) typedef AE_INT32_T ae_int32_t; #endif #if defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) typedef int32_t ae_int32_t; #endif #if !defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) #if AE_COMPILER==AE_MSVC typedef __int32 ae_int32_t; #endif #if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) typedef int ae_int32_t; #endif #endif #if defined(AE_INT64_T) typedef AE_INT64_T ae_int64_t; #endif #if defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) typedef int64_t ae_int64_t; #endif #if !defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) #if AE_COMPILER==AE_MSVC typedef __int64 ae_int64_t; #endif #if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) typedef signed long long ae_int64_t; #endif #endif #if !defined(AE_INT_T) typedef ptrdiff_t ae_int_t; #endif #if !defined(AE_USE_CPP_BOOL) #define ae_bool char #define ae_true 1 #define ae_false 0 #else #define ae_bool bool #define ae_true true #define ae_false false #endif typedef struct { double x, y; } ae_complex; typedef enum { ERR_OK = 0, ERR_OUT_OF_MEMORY = 1, ERR_XARRAY_TOO_LARGE = 2, ERR_ASSERTION_FAILED = 3 } ae_error_type; typedef ae_int_t ae_datatype; /* * other definitions */ enum { OWN_CALLER=1, OWN_AE=2 }; enum { ACT_UNCHANGED=1, ACT_SAME_LOCATION=2, ACT_NEW_LOCATION=3 }; enum { DT_BOOL=1, DT_INT=2, DT_REAL=3, DT_COMPLEX=4 }; enum { CPU_SSE2=1 }; /************************************************************************ x-string (zero-terminated): owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). If vector is owned by caller, X-interface will just set ptr to NULL before realloc(). If it is owned by X, it will call ae_free/x_free/aligned_free family functions. last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION contents is either: unchanged, stored at the same location, stored at the new location. this field is set on return from X. ptr pointer to the actual data Members of this structure are ae_int64_t to avoid alignment problems. ************************************************************************/ typedef struct { ALIGNED ae_int64_t owner; ALIGNED ae_int64_t last_action; ALIGNED char *ptr; } x_string; /************************************************************************ x-vector: cnt number of elements datatype one of the DT_XXXX values owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). If vector is owned by caller, X-interface will just set ptr to NULL before realloc(). If it is owned by X, it will call ae_free/x_free/aligned_free family functions. last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION contents is either: unchanged, stored at the same location, stored at the new location. this field is set on return from X interface and may be used by caller as hint when deciding what to do with data (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array reallocation or copying is required). ptr pointer to the actual data Members of this structure are ae_int64_t to avoid alignment problems. ************************************************************************/ typedef struct { ALIGNED ae_int64_t cnt; ALIGNED ae_int64_t datatype; ALIGNED ae_int64_t owner; ALIGNED ae_int64_t last_action; ALIGNED void *ptr; } x_vector; /************************************************************************ x-matrix: rows number of rows. may be zero only when cols is zero too. cols number of columns. may be zero only when rows is zero too. stride stride, i.e. distance between first elements of rows (in bytes) datatype one of the DT_XXXX values owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). If vector is owned by caller, X-interface will just set ptr to NULL before realloc(). If it is owned by X, it will call ae_free/x_free/aligned_free family functions. last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION contents is either: unchanged, stored at the same location, stored at the new location. this field is set on return from X interface and may be used by caller as hint when deciding what to do with data (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array reallocation or copying is required). ptr pointer to the actual data, stored rowwise Members of this structure are ae_int64_t to avoid alignment problems. ************************************************************************/ typedef struct { ALIGNED ae_int64_t rows; ALIGNED ae_int64_t cols; ALIGNED ae_int64_t stride; ALIGNED ae_int64_t datatype; ALIGNED ae_int64_t owner; ALIGNED ae_int64_t last_action; ALIGNED void *ptr; } x_matrix; /************************************************************************ dynamic block which may be automatically deallocated during stack unwinding p_next next block in the stack unwinding list. NULL means that this block is not in the list deallocator deallocator function which should be used to deallocate block. NULL for "special" blocks (frame/stack boundaries) ptr pointer which should be passed to the deallocator. may be null (for zero-size block), DYN_BOTTOM or DYN_FRAME for "special" blocks (frame/stack boundaries). ************************************************************************/ typedef struct ae_dyn_block { struct ae_dyn_block * volatile p_next; /* void *deallocator; */ void (*deallocator)(void*); void * volatile ptr; } ae_dyn_block; /************************************************************************ frame marker ************************************************************************/ typedef struct ae_frame { ae_dyn_block db_marker; } ae_frame; /************************************************************************ ALGLIB environment state ************************************************************************/ typedef struct ae_state { /* * endianness type: AE_LITTLE_ENDIAN or AE_BIG_ENDIAN */ ae_int_t endianness; /* * double value for NAN */ double v_nan; /* * double value for +INF */ double v_posinf; /* * double value for -INF */ double v_neginf; /* * pointer to the top block in a stack of frames * which hold dynamically allocated objects */ ae_dyn_block * volatile p_top_block; ae_dyn_block last_block; /* * jmp_buf for cases when C-style exception handling is used */ #ifndef AE_USE_CPP_ERROR_HANDLING jmp_buf * volatile break_jump; #endif /* * ae_error_type of the last error (filled when exception is thrown) */ ae_error_type volatile last_error; /* * human-readable message (filled when exception is thrown) */ const char* volatile error_msg; /* * threading information: * a) current thread pool * b) current worker thread * c) parent task (one we are solving right now) * d) thread exception handler (function which must be called * by ae_assert before raising exception). * * NOTE: we use void* to store pointers in order to avoid explicit dependency on smp.h */ void *worker_thread; void *parent_task; void (*thread_exception_handler)(void*); } ae_state; /************************************************************************ Serializer ************************************************************************/ typedef struct { ae_int_t mode; ae_int_t entries_needed; ae_int_t entries_saved; ae_int_t bytes_asked; ae_int_t bytes_written; #ifdef AE_USE_CPP_SERIALIZATION std::string *out_cppstr; #endif char *out_str; const char *in_str; } ae_serializer; typedef void(*ae_deallocator)(void*); typedef struct ae_vector { /* * Number of elements in array, cnt>=0 */ ae_int_t cnt; /* * Either DT_BOOL, DT_INT, DT_REAL or DT_COMPLEX */ ae_datatype datatype; /* * If ptr points to memory owned and managed by ae_vector itself, * this field is ae_false. If vector was attached to x_vector structure * with ae_vector_attach_to_x(), this field is ae_true. */ ae_bool is_attached; /* * ae_dyn_block structure which manages data in ptr. This structure * is responsible for automatic deletion of object when its frame * is destroyed. */ ae_dyn_block data; /* * Pointer to data. * User usually works with this field. */ union { void *p_ptr; ae_bool *p_bool; ae_int_t *p_int; double *p_double; ae_complex *p_complex; } ptr; } ae_vector; typedef struct ae_matrix { ae_int_t rows; ae_int_t cols; ae_int_t stride; ae_datatype datatype; /* * If ptr points to memory owned and managed by ae_vector itself, * this field is ae_false. If vector was attached to x_vector structure * with ae_vector_attach_to_x(), this field is ae_true. */ ae_bool is_attached; ae_dyn_block data; union { void *p_ptr; void **pp_void; ae_bool **pp_bool; ae_int_t **pp_int; double **pp_double; ae_complex **pp_complex; } ptr; } ae_matrix; typedef struct ae_smart_ptr { /* pointer to subscriber; all changes in ptr are translated to subscriber */ void **subscriber; /* pointer to object */ void *ptr; /* whether smart pointer owns ptr */ ae_bool is_owner; /* whether object pointed by ptr is dynamic - clearing such object requires BOTH calling destructor function AND calling ae_free for memory occupied by object. */ ae_bool is_dynamic; /* destructor function for pointer; clears all dynamically allocated memory */ void (*destroy)(void*); /* frame entry; used to ensure automatic deallocation of smart pointer in case of exception/exit */ ae_dyn_block frame_entry; } ae_smart_ptr; /************************************************************************* Lock. This structure provides OS-independent non-reentrant lock: * under Windows/Posix systems it uses system-provided locks * under Boost it uses OS-independent lock provided by Boost package * when no OS is defined, it uses "fake lock" (just stub which is not thread-safe): a) "fake lock" can be in locked or free mode b) "fake lock" can be used only from one thread - one which created lock c) when thread acquires free lock, it immediately returns d) when thread acquires busy lock, program is terminated (because lock is already acquired and no one else can free it) *************************************************************************/ typedef struct { /* * Pointer to _lock structure. This pointer has type void* in order to * make header file OS-independent (lock declaration depends on OS). */ void *ptr; } ae_lock; /************************************************************************* Shared pool: data structure used to provide thread-safe access to pool of temporary variables. *************************************************************************/ typedef struct ae_shared_pool_entry { void * volatile obj; void * volatile next_entry; } ae_shared_pool_entry; typedef struct ae_shared_pool { /* lock object which protects pool */ ae_lock pool_lock; /* seed object (used to create new instances of temporaries) */ void * volatile seed_object; /* * list of recycled OBJECTS: * 1. entries in this list store pointers to recycled objects * 2. every time we retrieve object, we retrieve first entry from this list, * move it to recycled_entries and return its obj field to caller/ */ ae_shared_pool_entry * volatile recycled_objects; /* * list of recycled ENTRIES: * 1. this list holds entries which are not used to store recycled objects; * every time recycled object is retrieved, its entry is moved to this list. * 2. every time object is recycled, we try to fetch entry for him from this list * before allocating it with malloc() */ ae_shared_pool_entry * volatile recycled_entries; /* enumeration pointer, points to current recycled object*/ ae_shared_pool_entry * volatile enumeration_counter; /* size of object; this field is used when we call malloc() for new objects */ ae_int_t size_of_object; /* initializer function; accepts pointer to malloc'ed object, initializes its fields */ void (*init)(void* dst, ae_state* state); /* copy constructor; accepts pointer to malloc'ed, but not initialized object */ void (*init_copy)(void* dst, void* src, ae_state* state); /* destructor function; */ void (*destroy)(void* ptr); /* frame entry; contains pointer to the pool object itself */ ae_dyn_block frame_entry; } ae_shared_pool; ae_int_t ae_misalignment(const void *ptr, size_t alignment); void* ae_align(void *ptr, size_t alignment); void* aligned_malloc(size_t size, size_t alignment); void aligned_free(void *block); void* ae_malloc(size_t size, ae_state *state); void ae_free(void *p); ae_int_t ae_sizeof(ae_datatype datatype); void ae_touch_ptr(void *p); void ae_state_init(ae_state *state); void ae_state_clear(ae_state *state); #ifndef AE_USE_CPP_ERROR_HANDLING void ae_state_set_break_jump(ae_state *state, jmp_buf *buf); #endif void ae_break(ae_state *state, ae_error_type error_type, const char *msg); void ae_frame_make(ae_state *state, ae_frame *tmp); void ae_frame_leave(ae_state *state); void ae_db_attach(ae_dyn_block *block, ae_state *state); ae_bool ae_db_malloc(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic); ae_bool ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state); void ae_db_free(ae_dyn_block *block); void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2); void ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state); void ae_vector_init_copy(ae_vector *dst, ae_vector *src, ae_state *state); void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state); void ae_vector_attach_to_x(ae_vector *dst, x_vector *src, ae_state *state); ae_bool ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state); void ae_vector_clear(ae_vector *dst); void ae_vector_destroy(ae_vector *dst); void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2); void ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state); void ae_matrix_init_copy(ae_matrix *dst, ae_matrix *src, ae_state *state); void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state); void ae_matrix_attach_to_x(ae_matrix *dst, x_matrix *src, ae_state *state); ae_bool ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state); void ae_matrix_clear(ae_matrix *dst); void ae_matrix_destroy(ae_matrix *dst); void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2); void ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_state *state); void ae_smart_ptr_clear(void *_dst); /* accepts ae_smart_ptr* */ void ae_smart_ptr_destroy(void *_dst); void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, void (*destroy)(void*)); void ae_smart_ptr_release(ae_smart_ptr *dst); void ae_yield(); void ae_init_lock(ae_lock *lock); void ae_acquire_lock(ae_lock *lock); void ae_release_lock(ae_lock *lock); void ae_free_lock(ae_lock *lock); void ae_shared_pool_init(void *_dst, ae_state *state); void ae_shared_pool_init_copy(void *_dst, void *_src, ae_state *state); void ae_shared_pool_clear(void *dst); void ae_shared_pool_destroy(void *dst); ae_bool ae_shared_pool_is_initialized(void *_dst); void ae_shared_pool_set_seed( ae_shared_pool *dst, void *seed_object, ae_int_t size_of_object, void (*init)(void* dst, ae_state* state), void (*init_copy)(void* dst, void* src, ae_state* state), void (*destroy)(void* ptr), ae_state *state); void ae_shared_pool_retrieve( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state); void ae_shared_pool_recycle( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state); void ae_shared_pool_clear_recycled( ae_shared_pool *pool, ae_state *state); void ae_shared_pool_first_recycled( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state); void ae_shared_pool_next_recycled( ae_shared_pool *pool, ae_smart_ptr *pptr, ae_state *state); void ae_shared_pool_reset( ae_shared_pool *pool, ae_state *state); void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state); void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state); void ae_x_attach_to_vector(x_vector *dst, ae_vector *src); void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src); void x_vector_clear(x_vector *dst); ae_bool x_is_symmetric(x_matrix *a); ae_bool x_is_hermitian(x_matrix *a); ae_bool x_force_symmetric(x_matrix *a); ae_bool x_force_hermitian(x_matrix *a); ae_bool ae_is_symmetric(ae_matrix *a); ae_bool ae_is_hermitian(ae_matrix *a); ae_bool ae_force_symmetric(ae_matrix *a); ae_bool ae_force_hermitian(ae_matrix *a); void ae_serializer_init(ae_serializer *serializer); void ae_serializer_clear(ae_serializer *serializer); void ae_serializer_alloc_start(ae_serializer *serializer); void ae_serializer_alloc_entry(ae_serializer *serializer); ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer); #ifdef AE_USE_CPP_SERIALIZATION void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf); void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf); #endif void ae_serializer_sstart_str(ae_serializer *serializer, char *buf); void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf); void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state); void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state); void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state); void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state); void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state); void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state); void ae_serializer_stop(ae_serializer *serializer); /************************************************************************ Service functions ************************************************************************/ void ae_assert(ae_bool cond, const char *msg, ae_state *state); ae_int_t ae_cpuid(); /************************************************************************ Real math functions: * IEEE-compliant floating point comparisons * standard functions ************************************************************************/ ae_bool ae_fp_eq(double v1, double v2); ae_bool ae_fp_neq(double v1, double v2); ae_bool ae_fp_less(double v1, double v2); ae_bool ae_fp_less_eq(double v1, double v2); ae_bool ae_fp_greater(double v1, double v2); ae_bool ae_fp_greater_eq(double v1, double v2); ae_bool ae_isfinite_stateless(double x, ae_int_t endianness); ae_bool ae_isnan_stateless(double x, ae_int_t endianness); ae_bool ae_isinf_stateless(double x, ae_int_t endianness); ae_bool ae_isposinf_stateless(double x, ae_int_t endianness); ae_bool ae_isneginf_stateless(double x, ae_int_t endianness); ae_int_t ae_get_endianness(); ae_bool ae_isfinite(double x,ae_state *state); ae_bool ae_isnan(double x, ae_state *state); ae_bool ae_isinf(double x, ae_state *state); ae_bool ae_isposinf(double x,ae_state *state); ae_bool ae_isneginf(double x,ae_state *state); double ae_fabs(double x, ae_state *state); ae_int_t ae_iabs(ae_int_t x, ae_state *state); double ae_sqr(double x, ae_state *state); double ae_sqrt(double x, ae_state *state); ae_int_t ae_sign(double x, ae_state *state); ae_int_t ae_round(double x, ae_state *state); ae_int_t ae_trunc(double x, ae_state *state); ae_int_t ae_ifloor(double x, ae_state *state); ae_int_t ae_iceil(double x, ae_state *state); ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state); ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state); double ae_maxreal(double m1, double m2, ae_state *state); double ae_minreal(double m1, double m2, ae_state *state); double ae_randomreal(ae_state *state); ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state); double ae_sin(double x, ae_state *state); double ae_cos(double x, ae_state *state); double ae_tan(double x, ae_state *state); double ae_sinh(double x, ae_state *state); double ae_cosh(double x, ae_state *state); double ae_tanh(double x, ae_state *state); double ae_asin(double x, ae_state *state); double ae_acos(double x, ae_state *state); double ae_atan(double x, ae_state *state); double ae_atan2(double y, double x, ae_state *state); double ae_log(double x, ae_state *state); double ae_pow(double x, double y, ae_state *state); double ae_exp(double x, ae_state *state); /************************************************************************ Complex math functions: * basic arithmetic operations * standard functions ************************************************************************/ ae_complex ae_complex_from_i(ae_int_t v); ae_complex ae_complex_from_d(double v); ae_complex ae_c_neg(ae_complex lhs); ae_bool ae_c_eq(ae_complex lhs, ae_complex rhs); ae_bool ae_c_neq(ae_complex lhs, ae_complex rhs); ae_complex ae_c_add(ae_complex lhs, ae_complex rhs); ae_complex ae_c_mul(ae_complex lhs, ae_complex rhs); ae_complex ae_c_sub(ae_complex lhs, ae_complex rhs); ae_complex ae_c_div(ae_complex lhs, ae_complex rhs); ae_bool ae_c_eq_d(ae_complex lhs, double rhs); ae_bool ae_c_neq_d(ae_complex lhs, double rhs); ae_complex ae_c_add_d(ae_complex lhs, double rhs); ae_complex ae_c_mul_d(ae_complex lhs, double rhs); ae_complex ae_c_sub_d(ae_complex lhs, double rhs); ae_complex ae_c_d_sub(double lhs, ae_complex rhs); ae_complex ae_c_div_d(ae_complex lhs, double rhs); ae_complex ae_c_d_div(double lhs, ae_complex rhs); ae_complex ae_c_conj(ae_complex lhs, ae_state *state); ae_complex ae_c_sqr(ae_complex lhs, ae_state *state); double ae_c_abs(ae_complex z, ae_state *state); /************************************************************************ Complex BLAS operations ************************************************************************/ ae_complex ae_v_cdotproduct(const ae_complex *v0, ae_int_t stride0, const char *conj0, const ae_complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void ae_v_cmoveneg(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha); /************************************************************************ Real BLAS operations ************************************************************************/ double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); void ae_v_move(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); void ae_v_moveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); void ae_v_moved(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void ae_v_add(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); void ae_v_addd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void ae_v_sub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); void ae_v_subd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void ae_v_muld(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); /************************************************************************ Other functions ************************************************************************/ ae_int_t ae_v_len(ae_int_t a, ae_int_t b); /* extern const double ae_machineepsilon; extern const double ae_maxrealnumber; extern const double ae_minrealnumber; extern const double ae_pi; */ #define ae_machineepsilon 5E-16 #define ae_maxrealnumber 1E300 #define ae_minrealnumber 1E-300 #define ae_pi 3.1415926535897932384626433832795 /************************************************************************ RComm functions ************************************************************************/ typedef struct rcommstate { int stage; ae_vector ia; ae_vector ba; ae_vector ra; ae_vector ca; } rcommstate; void _rcommstate_init(rcommstate* p, ae_state *_state); void _rcommstate_init_copy(rcommstate* dst, rcommstate* src, ae_state *_state); void _rcommstate_clear(rcommstate* p); void _rcommstate_destroy(rcommstate* p); /************************************************************************ Allocation counter, inactive by default. Turned on when needed for debugging purposes. ************************************************************************/ extern ae_int64_t _alloc_counter; extern ae_bool _use_alloc_counter; /************************************************************************ debug functions (must be turned on by preprocessor definitions): * tickcount(), which is wrapper around GetTickCount() * flushconsole(), fluches console * ae_debugrng(), returns random number generated with high-quality random numbers generator * ae_set_seed(), sets seed of the debug RNG (NON-THREAD-SAFE!!!) * ae_get_seed(), returns two seed values of the debug RNG (NON-THREAD-SAFE!!!) ************************************************************************/ #ifdef AE_DEBUG4WINDOWS #define flushconsole(s) fflush(stdout) #define tickcount(s) _tickcount() int _tickcount(); #endif #ifdef AE_DEBUG4POSIX #define flushconsole(s) fflush(stdout) #define tickcount(s) _tickcount() int _tickcount(); #endif } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS DECLARATIONS FOR C++ RELATED FUNCTIONALITY // ///////////////////////////////////////////////////////////////////////// namespace alglib { typedef alglib_impl::ae_int_t ae_int_t; /******************************************************************** Class forwards ********************************************************************/ class complex; ae_int_t vlen(ae_int_t n1, ae_int_t n2); /******************************************************************** Exception class. ********************************************************************/ class ap_error { public: std::string msg; ap_error(); ap_error(const char *s); static void make_assertion(bool bClause); static void make_assertion(bool bClause, const char *p_msg); private: }; /******************************************************************** Complex number with double precision. ********************************************************************/ class complex { public: complex(); complex(const double &_x); complex(const double &_x, const double &_y); complex(const complex &z); complex& operator= (const double& v); complex& operator+=(const double& v); complex& operator-=(const double& v); complex& operator*=(const double& v); complex& operator/=(const double& v); complex& operator= (const complex& z); complex& operator+=(const complex& z); complex& operator-=(const complex& z); complex& operator*=(const complex& z); complex& operator/=(const complex& z); alglib_impl::ae_complex* c_ptr(); const alglib_impl::ae_complex* c_ptr() const; std::string tostring(int dps) const; double x, y; }; const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); const bool operator==(const alglib::complex& lhs, const alglib::complex& rhs); const bool operator!=(const alglib::complex& lhs, const alglib::complex& rhs); const alglib::complex operator+(const alglib::complex& lhs); const alglib::complex operator-(const alglib::complex& lhs); const alglib::complex operator+(const alglib::complex& lhs, const alglib::complex& rhs); const alglib::complex operator+(const alglib::complex& lhs, const double& rhs); const alglib::complex operator+(const double& lhs, const alglib::complex& rhs); const alglib::complex operator-(const alglib::complex& lhs, const alglib::complex& rhs); const alglib::complex operator-(const alglib::complex& lhs, const double& rhs); const alglib::complex operator-(const double& lhs, const alglib::complex& rhs); const alglib::complex operator*(const alglib::complex& lhs, const alglib::complex& rhs); const alglib::complex operator*(const alglib::complex& lhs, const double& rhs); const alglib::complex operator*(const double& lhs, const alglib::complex& rhs); const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); const alglib::complex operator/(const double& lhs, const alglib::complex& rhs); const alglib::complex operator/(const alglib::complex& lhs, const double& rhs); double abscomplex(const alglib::complex &z); alglib::complex conj(const alglib::complex &z); alglib::complex csqr(const alglib::complex &z); void setnworkers(alglib::ae_int_t nworkers); /******************************************************************** Level 1 BLAS functions NOTES: * destination and source should NOT overlap * stride is assumed to be positive, but it is not assert'ed within function * conj_src parameter specifies whether complex source is conjugated before processing or not. Pass string which starts with 'N' or 'n' ("No conj", for example) to use unmodified parameter. All other values will result in conjugation of input, but it is recommended to use "Conj" in such cases. ********************************************************************/ double vdotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); double vdotproduct(const double *v1, const double *v2, ae_int_t N); alglib::complex vdotproduct(const alglib::complex *v0, ae_int_t stride0, const char *conj0, const alglib::complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); alglib::complex vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N); void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); void vmove(double *vdst, const double* vsrc, ae_int_t N); void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void vmove(alglib::complex *vdst, const alglib::complex* vsrc, ae_int_t N); void vmoveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); void vmoveneg(double *vdst, const double *vsrc, ae_int_t N); void vmoveneg(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void vmove(double *vdst, const double *vsrc, ae_int_t N, double alpha); void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); void vadd(double *vdst, const double *vsrc, ae_int_t N); void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void vadd(double *vdst, const double *vsrc, ae_int_t N, double alpha); void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); void vsub(double *vdst, const double *vsrc, ae_int_t N); void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); void vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha); void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); void vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); void vmul(double *vdst, ae_int_t N, double alpha); void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); void vmul(alglib::complex *vdst, ae_int_t N, double alpha); void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha); void vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha); /******************************************************************** string conversion functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ********************************************************************/ /******************************************************************** 1- and 2-dimensional arrays ********************************************************************/ class ae_vector_wrapper { public: ae_vector_wrapper(); virtual ~ae_vector_wrapper(); void setlength(ae_int_t iLen); ae_int_t length() const; void attach_to(alglib_impl::ae_vector *ptr); void allocate_own(ae_int_t size, alglib_impl::ae_datatype datatype); const alglib_impl::ae_vector* c_ptr() const; alglib_impl::ae_vector* c_ptr(); private: ae_vector_wrapper(const ae_vector_wrapper &rhs); const ae_vector_wrapper& operator=(const ae_vector_wrapper &rhs); protected: // // Copies source vector RHS into current object. // // Current object is considered empty (this function should be // called from copy constructor). // void create(const ae_vector_wrapper &rhs); // // Copies array given by string into current object. Additional // parameter DATATYPE contains information about type of the data // in S and type of the array to create. // // Current object is considered empty (this function should be // called from copy constructor). // void create(const char *s, alglib_impl::ae_datatype datatype); // // Assigns RHS to current object. // // It has several branches depending on target object status: // * in case it is proxy object, data are copied into memory pointed by // proxy. Function checks that source has exactly same size as target // (exception is thrown on failure). // * in case it is non-proxy object, data allocated by object are cleared // and a copy of RHS is created in target. // // NOTE: this function correctly handles assignments of the object to itself. // void assign(const ae_vector_wrapper &rhs); alglib_impl::ae_vector *p_vec; alglib_impl::ae_vector vec; }; class boolean_1d_array : public ae_vector_wrapper { public: boolean_1d_array(); boolean_1d_array(const char *s); boolean_1d_array(const boolean_1d_array &rhs); boolean_1d_array(alglib_impl::ae_vector *p); const boolean_1d_array& operator=(const boolean_1d_array &rhs); virtual ~boolean_1d_array() ; const ae_bool& operator()(ae_int_t i) const; ae_bool& operator()(ae_int_t i); const ae_bool& operator[](ae_int_t i) const; ae_bool& operator[](ae_int_t i); void setcontent(ae_int_t iLen, const bool *pContent ); ae_bool* getcontent(); const ae_bool* getcontent() const; std::string tostring() const; }; class integer_1d_array : public ae_vector_wrapper { public: integer_1d_array(); integer_1d_array(const char *s); integer_1d_array(const integer_1d_array &rhs); integer_1d_array(alglib_impl::ae_vector *p); const integer_1d_array& operator=(const integer_1d_array &rhs); virtual ~integer_1d_array(); const ae_int_t& operator()(ae_int_t i) const; ae_int_t& operator()(ae_int_t i); const ae_int_t& operator[](ae_int_t i) const; ae_int_t& operator[](ae_int_t i); void setcontent(ae_int_t iLen, const ae_int_t *pContent ); ae_int_t* getcontent(); const ae_int_t* getcontent() const; std::string tostring() const; }; class real_1d_array : public ae_vector_wrapper { public: real_1d_array(); real_1d_array(const char *s); real_1d_array(const real_1d_array &rhs); real_1d_array(alglib_impl::ae_vector *p); const real_1d_array& operator=(const real_1d_array &rhs); virtual ~real_1d_array(); const double& operator()(ae_int_t i) const; double& operator()(ae_int_t i); const double& operator[](ae_int_t i) const; double& operator[](ae_int_t i); void setcontent(ae_int_t iLen, const double *pContent ); double* getcontent(); const double* getcontent() const; std::string tostring(int dps) const; }; class complex_1d_array : public ae_vector_wrapper { public: complex_1d_array(); complex_1d_array(const char *s); complex_1d_array(const complex_1d_array &rhs); complex_1d_array(alglib_impl::ae_vector *p); const complex_1d_array& operator=(const complex_1d_array &rhs); virtual ~complex_1d_array(); const alglib::complex& operator()(ae_int_t i) const; alglib::complex& operator()(ae_int_t i); const alglib::complex& operator[](ae_int_t i) const; alglib::complex& operator[](ae_int_t i); void setcontent(ae_int_t iLen, const alglib::complex *pContent ); alglib::complex* getcontent(); const alglib::complex* getcontent() const; std::string tostring(int dps) const; }; class ae_matrix_wrapper { public: ae_matrix_wrapper(); virtual ~ae_matrix_wrapper(); const ae_matrix_wrapper& operator=(const ae_matrix_wrapper &rhs); void setlength(ae_int_t rows, ae_int_t cols); ae_int_t rows() const; ae_int_t cols() const; bool isempty() const; ae_int_t getstride() const; void attach_to(alglib_impl::ae_matrix *ptr); void allocate_own(ae_int_t rows, ae_int_t cols, alglib_impl::ae_datatype datatype); const alglib_impl::ae_matrix* c_ptr() const; alglib_impl::ae_matrix* c_ptr(); private: ae_matrix_wrapper(const ae_matrix_wrapper &rhs); protected: // // Copies source matrix RHS into current object. // // Current object is considered empty (this function should be // called from copy constructor). // void create(const ae_matrix_wrapper &rhs); // // Copies array given by string into current object. Additional // parameter DATATYPE contains information about type of the data // in S and type of the array to create. // // Current object is considered empty (this function should be // called from copy constructor). // void create(const char *s, alglib_impl::ae_datatype datatype); // // Assigns RHS to current object. // // It has several branches depending on target object status: // * in case it is proxy object, data are copied into memory pointed by // proxy. Function checks that source has exactly same size as target // (exception is thrown on failure). // * in case it is non-proxy object, data allocated by object are cleared // and a copy of RHS is created in target. // // NOTE: this function correctly handles assignments of the object to itself. // void assign(const ae_matrix_wrapper &rhs); alglib_impl::ae_matrix *p_mat; alglib_impl::ae_matrix mat; }; class boolean_2d_array : public ae_matrix_wrapper { public: boolean_2d_array(); boolean_2d_array(const boolean_2d_array &rhs); boolean_2d_array(alglib_impl::ae_matrix *p); boolean_2d_array(const char *s); virtual ~boolean_2d_array(); const ae_bool& operator()(ae_int_t i, ae_int_t j) const; ae_bool& operator()(ae_int_t i, ae_int_t j); const ae_bool* operator[](ae_int_t i) const; ae_bool* operator[](ae_int_t i); void setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ); std::string tostring() const ; }; class integer_2d_array : public ae_matrix_wrapper { public: integer_2d_array(); integer_2d_array(const integer_2d_array &rhs); integer_2d_array(alglib_impl::ae_matrix *p); integer_2d_array(const char *s); virtual ~integer_2d_array(); const ae_int_t& operator()(ae_int_t i, ae_int_t j) const; ae_int_t& operator()(ae_int_t i, ae_int_t j); const ae_int_t* operator[](ae_int_t i) const; ae_int_t* operator[](ae_int_t i); void setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ); std::string tostring() const; }; class real_2d_array : public ae_matrix_wrapper { public: real_2d_array(); real_2d_array(const real_2d_array &rhs); real_2d_array(alglib_impl::ae_matrix *p); real_2d_array(const char *s); virtual ~real_2d_array(); const double& operator()(ae_int_t i, ae_int_t j) const; double& operator()(ae_int_t i, ae_int_t j); const double* operator[](ae_int_t i) const; double* operator[](ae_int_t i); void setcontent(ae_int_t irows, ae_int_t icols, const double *pContent ); std::string tostring(int dps) const; }; class complex_2d_array : public ae_matrix_wrapper { public: complex_2d_array(); complex_2d_array(const complex_2d_array &rhs); complex_2d_array(alglib_impl::ae_matrix *p); complex_2d_array(const char *s); virtual ~complex_2d_array(); const alglib::complex& operator()(ae_int_t i, ae_int_t j) const; alglib::complex& operator()(ae_int_t i, ae_int_t j); const alglib::complex* operator[](ae_int_t i) const; alglib::complex* operator[](ae_int_t i); void setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ); std::string tostring(int dps) const; }; /******************************************************************** CSV operations: reading CSV file to real matrix. This function reads CSV file and stores its contents to double precision 2D array. Format of the data file must conform to RFC 4180 specification, with additional notes: * file size should be less than 2GB * ASCI encoding, UTF-8 without BOM (in header names) are supported * any character (comma/tab/space) may be used as field separator, as long as it is distinct from one used for decimal point * multiple subsequent field separators (say, two spaces) are treated as MULTIPLE separators, not one big separator * both comma and full stop may be used as decimal point. Parser will automatically determine specific character being used. Both fixed and exponential number formats are allowed. Thousand separators are NOT allowed. * line may end with \n (Unix style) or \r\n (Windows style), parser will automatically adapt to chosen convention * escaped fields (ones in double quotes) are not supported INPUT PARAMETERS: filename relative/absolute path separator character used to separate fields. May be ' ', ',', '\t'. Other separators are possible too. flags several values combined with bitwise OR: * alglib::CSV_SKIP_HEADERS - if present, first row contains headers and will be skipped. Its contents is used to determine fields count, and that's all. If no flags are specified, default value 0x0 (or alglib::CSV_DEFAULT, which is same) should be used. OUTPUT PARAMETERS: out 2D matrix, CSV file parsed with atof() HANDLING OF SPECIAL CASES: * file does not exist - alglib::ap_error exception is thrown * empty file - empty array is returned (no exception) * skip_first_row=true, only one row in file - empty array is returned * field contents is not recognized by atof() - field value is replaced by 0.0 ********************************************************************/ void read_csv(const char *filename, char separator, int flags, alglib::real_2d_array &out); /******************************************************************** dataset information. can store regression dataset, classification dataset, or non-labeled task: * nout==0 means non-labeled task (clustering, for example) * nout>0 && nclasses==0 means regression task * nout>0 && nclasses>0 means classification task ********************************************************************/ /*class dataset { public: dataset():nin(0), nout(0), nclasses(0), trnsize(0), valsize(0), tstsize(0), totalsize(0){}; int nin, nout, nclasses; int trnsize; int valsize; int tstsize; int totalsize; alglib::real_2d_array trn; alglib::real_2d_array val; alglib::real_2d_array tst; alglib::real_2d_array all; }; bool opendataset(std::string file, dataset *pdataset); // // internal functions // std::string strtolower(const std::string &s); bool readstrings(std::string file, std::list *pOutput); bool readstrings(std::string file, std::list *pOutput, std::string comment); void explodestring(std::string s, char sep, std::vector *pOutput); std::string xtrim(std::string s);*/ /******************************************************************** Constants and functions introduced for compatibility with AlgoPascal ********************************************************************/ extern const double machineepsilon; extern const double maxrealnumber; extern const double minrealnumber; extern const double fp_nan; extern const double fp_posinf; extern const double fp_neginf; extern const ae_int_t endianness; static const int CSV_DEFAULT = 0x0; static const int CSV_SKIP_HEADERS = 0x1; int sign(double x); double randomreal(); ae_int_t randominteger(ae_int_t maxv); int round(double x); int trunc(double x); int ifloor(double x); int iceil(double x); double pi(); double sqr(double x); int maxint(int m1, int m2); int minint(int m1, int m2); double maxreal(double m1, double m2); double minreal(double m1, double m2); bool fp_eq(double v1, double v2); bool fp_neq(double v1, double v2); bool fp_less(double v1, double v2); bool fp_less_eq(double v1, double v2); bool fp_greater(double v1, double v2); bool fp_greater_eq(double v1, double v2); bool fp_isnan(double x); bool fp_isposinf(double x); bool fp_isneginf(double x); bool fp_isinf(double x); bool fp_isfinite(double x); }//namespace alglib ///////////////////////////////////////////////////////////////////////// // // THIS SECTIONS CONTAINS DECLARATIONS FOR OPTIMIZED LINEAR ALGEBRA CODES // IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { #define ALGLIB_INTERCEPTS_ABLAS void _ialglib_vzero(ae_int_t n, double *p, ae_int_t stride); void _ialglib_vzero_complex(ae_int_t n, ae_complex *p, ae_int_t stride); void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb); void _ialglib_vcopy_complex(ae_int_t n, const ae_complex *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); void _ialglib_mcopyblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_int_t stride, double *b); void _ialglib_mcopyunblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, double *b, ae_int_t stride); void _ialglib_mcopyblock_complex(ae_int_t m, ae_int_t n, const ae_complex *a, ae_int_t op, ae_int_t stride, double *b); void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride); ae_bool _ialglib_i_rmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, ae_matrix *b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, ae_matrix *c, ae_int_t ic, ae_int_t jc); ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, ae_matrix *b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, ae_matrix *c, ae_int_t ic, ae_int_t jc); ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2); ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2); ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2); ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, ae_matrix *x, ae_int_t i2, ae_int_t j2); ae_bool _ialglib_i_cmatrixherkf(ae_int_t n, ae_int_t k, double alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, ae_matrix *c, ae_int_t ic, ae_int_t jc, ae_bool isupper); ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, ae_int_t k, double alpha, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, ae_matrix *c, ae_int_t ic, ae_int_t jc, ae_bool isupper); ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_vector *u, ae_int_t uoffs, ae_vector *v, ae_int_t voffs); ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, ae_int_t n, ae_matrix *a, ae_int_t ia, ae_int_t ja, ae_vector *u, ae_int_t uoffs, ae_vector *v, ae_int_t voffs); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS PARALLEL SUBROUTINES // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { } #endif qmapshack-1.10.0/3rdparty/alglib/src/fasttransforms.cpp000755 001750 000144 00000347336 13015033052 024306 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "fasttransforms.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* 1-dimensional complex FFT. Array size N may be arbitrary number (composite or prime). Composite N's are handled with cache-oblivious variation of a Cooley-Tukey algorithm. Small prime-factors are transformed using hard coded codelets (similar to FFTW codelets, but without low-level optimization), large prime-factors are handled with Bluestein's algorithm. Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), most fast for powers of 2. When N have prime factors larger than these, but orders of magnitude smaller than N, computations will be about 4 times slower than for nearby highly composite N's. When N itself is prime, speed will be 6 times lower. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS A - DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1d(complex_1d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftc1d(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex FFT. Array size N may be arbitrary number (composite or prime). Composite N's are handled with cache-oblivious variation of a Cooley-Tukey algorithm. Small prime-factors are transformed using hard coded codelets (similar to FFTW codelets, but without low-level optimization), large prime-factors are handled with Bluestein's algorithm. Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), most fast for powers of 2. When N have prime factors larger than these, but orders of magnitude smaller than N, computations will be about 4 times slower than for nearby highly composite N's. When N itself is prime, speed will be 6 times lower. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS A - DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1d(complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = a.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftc1d(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex inverse FFT. Array size N may be arbitrary number (composite or prime). Algorithm has O(N*logN) complexity for any N (composite or prime). See FFTC1D() description for more information about algorithm performance. INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1dinv(complex_1d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftc1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex inverse FFT. Array size N may be arbitrary number (composite or prime). Algorithm has O(N*logN) complexity for any N (composite or prime). See FFTC1D() description for more information about algorithm performance. INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1dinv(complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = a.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftc1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS F - DFT of a input array, array[0..N-1] F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) NOTE: F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half of array is usually needed. But for convinience subroutine returns full complex array (with frequencies above N/2), so its result may be used by other FFT-related subroutines. -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftr1d(const_cast(a.c_ptr()), n, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS F - DFT of a input array, array[0..N-1] F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) NOTE: F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half of array is usually needed. But for convinience subroutine returns full complex array (with frequencies above N/2), so its result may be used by other FFT-related subroutines. -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1d(const real_1d_array &a, complex_1d_array &f) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = a.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftr1d(const_cast(a.c_ptr()), n, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real inverse FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS F - array[0..floor(N/2)] - frequencies from forward real FFT N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] NOTE: F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one half of frequencies array is needed - elements from 0 to floor(N/2). F[0] is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then F[floor(N/2)] has no special properties. Relying on properties noted above, FFTR1DInv subroutine uses only elements from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case N is even it ignores imaginary part of F[floor(N/2)] too. When you call this function using full arguments list - "FFTR1DInv(F,N,A)" - you can pass either either frequencies array with N elements or reduced array with roughly N/2 elements - subroutine will successfully transform both. If you call this function using reduced arguments list - "FFTR1DInv(F,A)" - you must pass FULL array with N elements (although higher N/2 are still not used) because array size is used to automatically determine FFT length -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftr1dinv(const_cast(f.c_ptr()), n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real inverse FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS F - array[0..floor(N/2)] - frequencies from forward real FFT N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] NOTE: F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one half of frequencies array is needed - elements from 0 to floor(N/2). F[0] is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then F[floor(N/2)] has no special properties. Relying on properties noted above, FFTR1DInv subroutine uses only elements from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case N is even it ignores imaginary part of F[floor(N/2)] too. When you call this function using full arguments list - "FFTR1DInv(F,N,A)" - you can pass either either frequencies array with N elements or reduced array with roughly N/2 elements - subroutine will successfully transform both. If you call this function using reduced arguments list - "FFTR1DInv(F,A)" - you must pass FULL array with N elements (although higher N/2 are still not used) because array size is used to automatically determine FFT length -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinv(const complex_1d_array &f, real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = f.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fftr1dinv(const_cast(f.c_ptr()), n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex convolution. For given A/B returns conv(A,B) (non-circular). Subroutine can automatically choose between three implementations: straightforward O(M*N) formula for very small N (or M), overlap-add algorithm for cases where max(M,N) is significantly larger than min(M,N), but O(M*N) algorithm is too slow, and general FFT-based formula for cases where two previois algorithms are too slow. Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convc1d(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convc1dinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional circular complex convolution. For given S/R returns conv(S,R) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: normal convolution is commutative, i.e. it is symmetric - conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a signal, periodic function, and another - R - is a response, non-periodic function with limited length. INPUT PARAMETERS S - array[0..M-1] - complex periodic signal M - problem size B - array[0..N-1] - complex non-periodic response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convc1dcircular(const_cast(s.c_ptr()), m, const_cast(r.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved periodic signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - non-periodic response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-1]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convc1dcircularinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real convolution. Analogous to ConvC1D(), see ConvC1D() comments for more details. INPUT PARAMETERS A - array[0..M-1] - real function to be transformed M - problem size B - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convr1d(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convr1dinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional circular real convolution. Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. INPUT PARAMETERS S - array[0..M-1] - real signal M - problem size B - array[0..N-1] - real response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convr1dcircular(const_cast(s.c_ptr()), m, const_cast(r.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::convr1dcircularinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(conj(pattern[j])*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::corrc1d(const_cast(signal.c_ptr()), n, const_cast(pattern.c_ptr()), m, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional circular complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::corrc1dcircular(const_cast(signal.c_ptr()), m, const_cast(pattern.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(pattern[j]*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(pattern[j]*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::corrr1d(const_cast(signal.c_ptr()), n, const_cast(pattern.c_ptr()), m, const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional circular real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::corrr1dcircular(const_cast(signal.c_ptr()), m, const_cast(pattern.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional Fast Hartley Transform. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS A - FHT of a input array, array[0..N-1], A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) -- ALGLIB -- Copyright 04.06.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1d(real_1d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fhtr1d(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional inverse FHT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse FHT of a input array, array[0..N-1] -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1dinv(real_1d_array &a, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fhtr1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { /************************************************************************* 1-dimensional complex FFT. Array size N may be arbitrary number (composite or prime). Composite N's are handled with cache-oblivious variation of a Cooley-Tukey algorithm. Small prime-factors are transformed using hard coded codelets (similar to FFTW codelets, but without low-level optimization), large prime-factors are handled with Bluestein's algorithm. Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), most fast for powers of 2. When N have prime factors larger than these, but orders of magnitude smaller than N, computations will be about 4 times slower than for nearby highly composite N's. When N itself is prime, speed will be 6 times lower. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS A - DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; fasttransformplan plan; ae_int_t i; ae_vector buf; ae_frame_make(_state, &_frame_block); _fasttransformplan_init(&plan, _state); ae_vector_init(&buf, 0, DT_REAL, _state); ae_assert(n>0, "FFTC1D: incorrect N!", _state); ae_assert(a->cnt>=n, "FFTC1D: Length(A)ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } /* * Generate plan and execute it. * * Plan is a combination of a successive factorizations of N and * precomputed data. It is much like a FFTW plan, but is not stored * between subroutine calls and is much simpler. */ ftcomplexfftplan(n, 1, &plan, _state); ftapplyplan(&plan, &buf, 0, 1, _state); /* * result */ for(i=0; i<=n-1; i++) { a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0]; a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional complex inverse FFT. Array size N may be arbitrary number (composite or prime). Algorithm has O(N*logN) complexity for any N (composite or prime). See FFTC1D() description for more information about algorithm performance. INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_int_t i; ae_assert(n>0, "FFTC1DInv: incorrect N!", _state); ae_assert(a->cnt>=n, "FFTC1DInv: Length(A)ptr.p_complex[i].y = -a->ptr.p_complex[i].y; } fftc1d(a, n, _state); for(i=0; i<=n-1; i++) { a->ptr.p_complex[i].x = a->ptr.p_complex[i].x/n; a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y/n; } } /************************************************************************* 1-dimensional real FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS F - DFT of a input array, array[0..N-1] F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) NOTE: F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half of array is usually needed. But for convinience subroutine returns full complex array (with frequencies above N/2), so its result may be used by other FFT-related subroutines. -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1d(/* Real */ ae_vector* a, ae_int_t n, /* Complex */ ae_vector* f, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t n2; ae_int_t idx; ae_complex hn; ae_complex hmnc; ae_complex v; ae_vector buf; fasttransformplan plan; ae_frame_make(_state, &_frame_block); ae_vector_clear(f); ae_vector_init(&buf, 0, DT_REAL, _state); _fasttransformplan_init(&plan, _state); ae_assert(n>0, "FFTR1D: incorrect N!", _state); ae_assert(a->cnt>=n, "FFTR1D: Length(A)ptr.p_complex[0] = ae_complex_from_d(a->ptr.p_double[0]); ae_frame_leave(_state); return; } if( n==2 ) { ae_vector_set_length(f, 2, _state); f->ptr.p_complex[0].x = a->ptr.p_double[0]+a->ptr.p_double[1]; f->ptr.p_complex[0].y = (double)(0); f->ptr.p_complex[1].x = a->ptr.p_double[0]-a->ptr.p_double[1]; f->ptr.p_complex[1].y = (double)(0); ae_frame_leave(_state); return; } /* * Choose between odd-size and even-size FFTs */ if( n%2==0 ) { /* * even-size real FFT, use reduction to the complex task */ n2 = n/2; ae_vector_set_length(&buf, n, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); ftcomplexfftplan(n2, 1, &plan, _state); ftapplyplan(&plan, &buf, 0, 1, _state); ae_vector_set_length(f, n, _state); for(i=0; i<=n2; i++) { idx = 2*(i%n2); hn.x = buf.ptr.p_double[idx+0]; hn.y = buf.ptr.p_double[idx+1]; idx = 2*((n2-i)%n2); hmnc.x = buf.ptr.p_double[idx+0]; hmnc.y = -buf.ptr.p_double[idx+1]; v.x = -ae_sin(-2*ae_pi*i/n, _state); v.y = ae_cos(-2*ae_pi*i/n, _state); f->ptr.p_complex[i] = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); f->ptr.p_complex[i].x = 0.5*f->ptr.p_complex[i].x; f->ptr.p_complex[i].y = 0.5*f->ptr.p_complex[i].y; } for(i=n2+1; i<=n-1; i++) { f->ptr.p_complex[i] = ae_c_conj(f->ptr.p_complex[n-i], _state); } } else { /* * use complex FFT */ ae_vector_set_length(f, n, _state); for(i=0; i<=n-1; i++) { f->ptr.p_complex[i] = ae_complex_from_d(a->ptr.p_double[i]); } fftc1d(f, n, _state); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional real inverse FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS F - array[0..floor(N/2)] - frequencies from forward real FFT N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] NOTE: F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one half of frequencies array is needed - elements from 0 to floor(N/2). F[0] is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then F[floor(N/2)] has no special properties. Relying on properties noted above, FFTR1DInv subroutine uses only elements from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case N is even it ignores imaginary part of F[floor(N/2)] too. When you call this function using full arguments list - "FFTR1DInv(F,N,A)" - you can pass either either frequencies array with N elements or reduced array with roughly N/2 elements - subroutine will successfully transform both. If you call this function using reduced arguments list - "FFTR1DInv(F,A)" - you must pass FULL array with N elements (although higher N/2 are still not used) because array size is used to automatically determine FFT length -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinv(/* Complex */ ae_vector* f, ae_int_t n, /* Real */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector h; ae_vector fh; ae_frame_make(_state, &_frame_block); ae_vector_clear(a); ae_vector_init(&h, 0, DT_REAL, _state); ae_vector_init(&fh, 0, DT_COMPLEX, _state); ae_assert(n>0, "FFTR1DInv: incorrect N!", _state); ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInv: Length(F)ptr.p_complex[0].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) { ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); } ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); if( n%2!=0 ) { ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); } /* * Special case: N=1, FFT is just identity transform. * After this block we assume that N is strictly greater than 1. */ if( n==1 ) { ae_vector_set_length(a, 1, _state); a->ptr.p_double[0] = f->ptr.p_complex[0].x; ae_frame_leave(_state); return; } /* * inverse real FFT is reduced to the inverse real FHT, * which is reduced to the forward real FHT, * which is reduced to the forward real FFT. * * Don't worry, it is really compact and efficient reduction :) */ ae_vector_set_length(&h, n, _state); ae_vector_set_length(a, n, _state); h.ptr.p_double[0] = f->ptr.p_complex[0].x; for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) { h.ptr.p_double[i] = f->ptr.p_complex[i].x-f->ptr.p_complex[i].y; h.ptr.p_double[n-i] = f->ptr.p_complex[i].x+f->ptr.p_complex[i].y; } if( n%2==0 ) { h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x; } else { h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x-f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)+1] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x+f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; } fftr1d(&h, n, &fh, _state); for(i=0; i<=n-1; i++) { a->ptr.p_double[i] = (fh.ptr.p_complex[i].x-fh.ptr.p_complex[i].y)/n; } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Never call it directly! -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinternaleven(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* buf, fasttransformplan* plan, ae_state *_state) { double x; double y; ae_int_t i; ae_int_t n2; ae_int_t idx; ae_complex hn; ae_complex hmnc; ae_complex v; ae_assert(n>0&&n%2==0, "FFTR1DEvenInplace: incorrect N!", _state); /* * Special cases: * * N=2 * * After this block we assume that N is strictly greater than 2 */ if( n==2 ) { x = a->ptr.p_double[0]+a->ptr.p_double[1]; y = a->ptr.p_double[0]-a->ptr.p_double[1]; a->ptr.p_double[0] = x; a->ptr.p_double[1] = y; return; } /* * even-size real FFT, use reduction to the complex task */ n2 = n/2; ae_v_move(&buf->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); ftapplyplan(plan, buf, 0, 1, _state); a->ptr.p_double[0] = buf->ptr.p_double[0]+buf->ptr.p_double[1]; for(i=1; i<=n2-1; i++) { idx = 2*(i%n2); hn.x = buf->ptr.p_double[idx+0]; hn.y = buf->ptr.p_double[idx+1]; idx = 2*(n2-i); hmnc.x = buf->ptr.p_double[idx+0]; hmnc.y = -buf->ptr.p_double[idx+1]; v.x = -ae_sin(-2*ae_pi*i/n, _state); v.y = ae_cos(-2*ae_pi*i/n, _state); v = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); a->ptr.p_double[2*i+0] = 0.5*v.x; a->ptr.p_double[2*i+1] = 0.5*v.y; } a->ptr.p_double[1] = buf->ptr.p_double[0]-buf->ptr.p_double[1]; } /************************************************************************* Internal subroutine. Never call it directly! -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinvinternaleven(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* buf, fasttransformplan* plan, ae_state *_state) { double x; double y; double t; ae_int_t i; ae_int_t n2; ae_assert(n>0&&n%2==0, "FFTR1DInvInternalEven: incorrect N!", _state); /* * Special cases: * * N=2 * * After this block we assume that N is strictly greater than 2 */ if( n==2 ) { x = 0.5*(a->ptr.p_double[0]+a->ptr.p_double[1]); y = 0.5*(a->ptr.p_double[0]-a->ptr.p_double[1]); a->ptr.p_double[0] = x; a->ptr.p_double[1] = y; return; } /* * inverse real FFT is reduced to the inverse real FHT, * which is reduced to the forward real FHT, * which is reduced to the forward real FFT. * * Don't worry, it is really compact and efficient reduction :) */ n2 = n/2; buf->ptr.p_double[0] = a->ptr.p_double[0]; for(i=1; i<=n2-1; i++) { x = a->ptr.p_double[2*i+0]; y = a->ptr.p_double[2*i+1]; buf->ptr.p_double[i] = x-y; buf->ptr.p_double[n-i] = x+y; } buf->ptr.p_double[n2] = a->ptr.p_double[1]; fftr1dinternaleven(buf, n, a, plan, _state); a->ptr.p_double[0] = buf->ptr.p_double[0]/n; t = (double)1/(double)n; for(i=1; i<=n2-1; i++) { x = buf->ptr.p_double[2*i+0]; y = buf->ptr.p_double[2*i+1]; a->ptr.p_double[i] = t*(x-y); a->ptr.p_double[n-i] = t*(x+y); } a->ptr.p_double[n2] = buf->ptr.p_double[1]/n; } /************************************************************************* 1-dimensional complex convolution. For given A/B returns conv(A,B) (non-circular). Subroutine can automatically choose between three implementations: straightforward O(M*N) formula for very small N (or M), overlap-add algorithm for cases where max(M,N) is significantly larger than min(M,N), but O(M*N) algorithm is too slow, and general FFT-based formula for cases where two previois algorithms are too slow. Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1d(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state) { ae_vector_clear(r); ae_assert(n>0&&m>0, "ConvC1D: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer that B. */ if( m0&&m>0)&&n<=m, "ConvC1DInv: incorrect N or M!", _state); p = ftbasefindsmooth(m, _state); ftcomplexfftplan(p, 1, &plan, _state); ae_vector_set_length(&buf, 2*p, _state); for(i=0; i<=m-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } for(i=m; i<=p-1; i++) { buf.ptr.p_double[2*i+0] = (double)(0); buf.ptr.p_double[2*i+1] = (double)(0); } ae_vector_set_length(&buf2, 2*p, _state); for(i=0; i<=n-1; i++) { buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; } for(i=n; i<=p-1; i++) { buf2.ptr.p_double[2*i+0] = (double)(0); buf2.ptr.p_double[2*i+1] = (double)(0); } ftapplyplan(&plan, &buf, 0, 1, _state); ftapplyplan(&plan, &buf2, 0, 1, _state); for(i=0; i<=p-1; i++) { c1.x = buf.ptr.p_double[2*i+0]; c1.y = buf.ptr.p_double[2*i+1]; c2.x = buf2.ptr.p_double[2*i+0]; c2.y = buf2.ptr.p_double[2*i+1]; c3 = ae_c_div(c1,c2); buf.ptr.p_double[2*i+0] = c3.x; buf.ptr.p_double[2*i+1] = -c3.y; } ftapplyplan(&plan, &buf, 0, 1, _state); t = (double)1/(double)p; ae_vector_set_length(r, m-n+1, _state); for(i=0; i<=m-n; i++) { r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional circular complex convolution. For given S/R returns conv(S,R) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: normal convolution is commutative, i.e. it is symmetric - conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a signal, periodic function, and another - R - is a response, non-periodic function with limited length. INPUT PARAMETERS S - array[0..M-1] - complex periodic signal M - problem size B - array[0..N-1] - complex non-periodic response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircular(/* Complex */ ae_vector* s, ae_int_t m, /* Complex */ ae_vector* r, ae_int_t n, /* Complex */ ae_vector* c, ae_state *_state) { ae_frame _frame_block; ae_vector buf; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_frame_make(_state, &_frame_block); ae_vector_clear(c); ae_vector_init(&buf, 0, DT_COMPLEX, _state); ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); i1 = i1+m; } convc1dcircular(s, m, &buf, m, c, _state); ae_frame_leave(_state); return; } convc1dx(s, m, r, n, ae_true, -1, 0, c, _state); ae_frame_leave(_state); } /************************************************************************* 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved periodic signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - non-periodic response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-1]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircularinv(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_vector buf; ae_vector buf2; ae_vector cbuf; fasttransformplan plan; ae_complex c1; ae_complex c2; ae_complex c3; double t; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&buf2, 0, DT_REAL, _state); ae_vector_init(&cbuf, 0, DT_COMPLEX, _state); _fasttransformplan_init(&plan, _state); ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); i1 = i1+m; } convc1dcircularinv(a, m, &cbuf, m, r, _state); ae_frame_leave(_state); return; } /* * Task is normalized */ ftcomplexfftplan(m, 1, &plan, _state); ae_vector_set_length(&buf, 2*m, _state); for(i=0; i<=m-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } ae_vector_set_length(&buf2, 2*m, _state); for(i=0; i<=n-1; i++) { buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; } for(i=n; i<=m-1; i++) { buf2.ptr.p_double[2*i+0] = (double)(0); buf2.ptr.p_double[2*i+1] = (double)(0); } ftapplyplan(&plan, &buf, 0, 1, _state); ftapplyplan(&plan, &buf2, 0, 1, _state); for(i=0; i<=m-1; i++) { c1.x = buf.ptr.p_double[2*i+0]; c1.y = buf.ptr.p_double[2*i+1]; c2.x = buf2.ptr.p_double[2*i+0]; c2.y = buf2.ptr.p_double[2*i+1]; c3 = ae_c_div(c1,c2); buf.ptr.p_double[2*i+0] = c3.x; buf.ptr.p_double[2*i+1] = -c3.y; } ftapplyplan(&plan, &buf, 0, 1, _state); t = (double)1/(double)m; ae_vector_set_length(r, m, _state); for(i=0; i<=m-1; i++) { r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional real convolution. Analogous to ConvC1D(), see ConvC1D() comments for more details. INPUT PARAMETERS A - array[0..M-1] - real function to be transformed M - problem size B - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1d(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state) { ae_vector_clear(r); ae_assert(n>0&&m>0, "ConvR1D: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer that B. */ if( m0&&m>0)&&n<=m, "ConvR1DInv: incorrect N or M!", _state); p = ftbasefindsmootheven(m, _state); ae_vector_set_length(&buf, p, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); for(i=m; i<=p-1; i++) { buf.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf2, p, _state); ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=p-1; i++) { buf2.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf3, p, _state); ftcomplexfftplan(p/2, 1, &plan, _state); fftr1dinternaleven(&buf, p, &buf3, &plan, _state); fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; for(i=1; i<=p/2-1; i++) { c1.x = buf.ptr.p_double[2*i+0]; c1.y = buf.ptr.p_double[2*i+1]; c2.x = buf2.ptr.p_double[2*i+0]; c2.y = buf2.ptr.p_double[2*i+1]; c3 = ae_c_div(c1,c2); buf.ptr.p_double[2*i+0] = c3.x; buf.ptr.p_double[2*i+1] = c3.y; } fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); ae_vector_set_length(r, m-n+1, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-n)); ae_frame_leave(_state); } /************************************************************************* 1-dimensional circular real convolution. Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. INPUT PARAMETERS S - array[0..M-1] - real signal M - problem size B - array[0..N-1] - real response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircular(/* Real */ ae_vector* s, ae_int_t m, /* Real */ ae_vector* r, ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_frame _frame_block; ae_vector buf; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_frame_make(_state, &_frame_block); ae_vector_clear(c); ae_vector_init(&buf, 0, DT_REAL, _state); ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_double[i1], 1, ae_v_len(0,j2)); i1 = i1+m; } convr1dcircular(s, m, &buf, m, c, _state); ae_frame_leave(_state); return; } /* * reduce to usual convolution */ convr1dx(s, m, r, n, ae_true, -1, 0, c, _state); ae_frame_leave(_state); } /************************************************************************* 1-dimensional complex deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircularinv(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_vector buf; ae_vector buf2; ae_vector buf3; ae_vector cbuf; ae_vector cbuf2; fasttransformplan plan; ae_complex c1; ae_complex c2; ae_complex c3; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&buf2, 0, DT_REAL, _state); ae_vector_init(&buf3, 0, DT_REAL, _state); ae_vector_init(&cbuf, 0, DT_COMPLEX, _state); ae_vector_init(&cbuf2, 0, DT_COMPLEX, _state); _fasttransformplan_init(&plan, _state); ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_double[i1], 1, ae_v_len(0,j2)); i1 = i1+m; } convr1dcircularinv(a, m, &buf, m, r, _state); ae_frame_leave(_state); return; } /* * Task is normalized */ if( m%2==0 ) { /* * size is even, use fast even-size FFT */ ae_vector_set_length(&buf, m, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_vector_set_length(&buf2, m, _state); ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=m-1; i++) { buf2.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf3, m, _state); ftcomplexfftplan(m/2, 1, &plan, _state); fftr1dinternaleven(&buf, m, &buf3, &plan, _state); fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; for(i=1; i<=m/2-1; i++) { c1.x = buf.ptr.p_double[2*i+0]; c1.y = buf.ptr.p_double[2*i+1]; c2.x = buf2.ptr.p_double[2*i+0]; c2.y = buf2.ptr.p_double[2*i+1]; c3 = ae_c_div(c1,c2); buf.ptr.p_double[2*i+0] = c3.x; buf.ptr.p_double[2*i+1] = c3.y; } fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); ae_vector_set_length(r, m, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); } else { /* * odd-size, use general real FFT */ fftr1d(a, m, &cbuf, _state); ae_vector_set_length(&buf2, m, _state); ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=m-1; i++) { buf2.ptr.p_double[i] = (double)(0); } fftr1d(&buf2, m, &cbuf2, _state); for(i=0; i<=ae_ifloor((double)m/(double)2, _state); i++) { cbuf.ptr.p_complex[i] = ae_c_div(cbuf.ptr.p_complex[i],cbuf2.ptr.p_complex[i]); } fftr1dinv(&cbuf, m, r, _state); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional complex convolution. Extended subroutine which allows to choose convolution algorithm. Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular(). INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size, N<=M Alg - algorithm type: *-2 auto-select Q for overlap-add *-1 auto-select algorithm and parameters * 0 straightforward formula for small N's * 1 general FFT-based code * 2 overlap-add with length Q Q - length for overlap-add OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dx(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, ae_bool circular, ae_int_t alg, ae_int_t q, /* Complex */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t p; ae_int_t ptotal; ae_int_t i1; ae_int_t i2; ae_int_t j1; ae_int_t j2; ae_vector bbuf; ae_complex v; double ax; double ay; double bx; double by; double t; double tx; double ty; double flopcand; double flopbest; ae_int_t algbest; fasttransformplan plan; ae_vector buf; ae_vector buf2; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&bbuf, 0, DT_COMPLEX, _state); _fasttransformplan_init(&plan, _state); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&buf2, 0, DT_REAL, _state); ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state); ae_assert(n<=m, "ConvC1DX: Nptr.p_complex[0]; ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); ae_frame_leave(_state); return; } /* * use straightforward formula */ if( circular ) { /* * circular convolution */ ae_vector_set_length(r, m, _state); v = b->ptr.p_complex[0]; ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); for(i=1; i<=n-1; i++) { v = b->ptr.p_complex[i]; i1 = 0; i2 = i-1; j1 = m-i; j2 = m-1; ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); i1 = i; i2 = m-1; j1 = 0; j2 = m-i-1; ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); } } else { /* * non-circular convolution */ ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_complex[i] = ae_complex_from_i(0); } for(i=0; i<=n-1; i++) { v = b->ptr.p_complex[i]; ae_v_caddc(&r->ptr.p_complex[i], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(i,i+m-1), v); } } ae_frame_leave(_state); return; } /* * general FFT-based code for * circular and non-circular convolutions. * * First, if convolution is circular, we test whether M is smooth or not. * If it is smooth, we just use M-length FFT to calculate convolution. * If it is not, we calculate non-circular convolution and wrap it arount. * * IF convolution is non-circular, we use zero-padding + FFT. */ if( alg==1 ) { if( circular&&ftbaseissmooth(m, _state) ) { /* * special code for circular convolution with smooth M */ ftcomplexfftplan(m, 1, &plan, _state); ae_vector_set_length(&buf, 2*m, _state); for(i=0; i<=m-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } ae_vector_set_length(&buf2, 2*m, _state); for(i=0; i<=n-1; i++) { buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; } for(i=n; i<=m-1; i++) { buf2.ptr.p_double[2*i+0] = (double)(0); buf2.ptr.p_double[2*i+1] = (double)(0); } ftapplyplan(&plan, &buf, 0, 1, _state); ftapplyplan(&plan, &buf2, 0, 1, _state); for(i=0; i<=m-1; i++) { ax = buf.ptr.p_double[2*i+0]; ay = buf.ptr.p_double[2*i+1]; bx = buf2.ptr.p_double[2*i+0]; by = buf2.ptr.p_double[2*i+1]; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*i+0] = tx; buf.ptr.p_double[2*i+1] = -ty; } ftapplyplan(&plan, &buf, 0, 1, _state); t = (double)1/(double)m; ae_vector_set_length(r, m, _state); for(i=0; i<=m-1; i++) { r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; } } else { /* * M is non-smooth, general code (circular/non-circular): * * first part is the same for circular and non-circular * convolutions. zero padding, FFTs, inverse FFTs * * second part differs: * * for non-circular convolution we just copy array * * for circular convolution we add array tail to its head */ p = ftbasefindsmooth(m+n-1, _state); ftcomplexfftplan(p, 1, &plan, _state); ae_vector_set_length(&buf, 2*p, _state); for(i=0; i<=m-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } for(i=m; i<=p-1; i++) { buf.ptr.p_double[2*i+0] = (double)(0); buf.ptr.p_double[2*i+1] = (double)(0); } ae_vector_set_length(&buf2, 2*p, _state); for(i=0; i<=n-1; i++) { buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; } for(i=n; i<=p-1; i++) { buf2.ptr.p_double[2*i+0] = (double)(0); buf2.ptr.p_double[2*i+1] = (double)(0); } ftapplyplan(&plan, &buf, 0, 1, _state); ftapplyplan(&plan, &buf2, 0, 1, _state); for(i=0; i<=p-1; i++) { ax = buf.ptr.p_double[2*i+0]; ay = buf.ptr.p_double[2*i+1]; bx = buf2.ptr.p_double[2*i+0]; by = buf2.ptr.p_double[2*i+1]; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*i+0] = tx; buf.ptr.p_double[2*i+1] = -ty; } ftapplyplan(&plan, &buf, 0, 1, _state); t = (double)1/(double)p; if( circular ) { /* * circular, add tail to head */ ae_vector_set_length(r, m, _state); for(i=0; i<=m-1; i++) { r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; } for(i=m; i<=m+n-2; i++) { r->ptr.p_complex[i-m].x = r->ptr.p_complex[i-m].x+t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i-m].y = r->ptr.p_complex[i-m].y-t*buf.ptr.p_double[2*i+1]; } } else { /* * non-circular, just copy */ ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; } } } ae_frame_leave(_state); return; } /* * overlap-add method for * circular and non-circular convolutions. * * First part of code (separate FFTs of input blocks) is the same * for all types of convolution. Second part (overlapping outputs) * differs for different types of convolution. We just copy output * when convolution is non-circular. We wrap it around, if it is * circular. */ if( alg==2 ) { ae_vector_set_length(&buf, 2*(q+n-1), _state); /* * prepare R */ if( circular ) { ae_vector_set_length(r, m, _state); for(i=0; i<=m-1; i++) { r->ptr.p_complex[i] = ae_complex_from_i(0); } } else { ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_complex[i] = ae_complex_from_i(0); } } /* * pre-calculated FFT(B) */ ae_vector_set_length(&bbuf, q+n-1, _state); ae_v_cmove(&bbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); for(j=n; j<=q+n-2; j++) { bbuf.ptr.p_complex[j] = ae_complex_from_i(0); } fftc1d(&bbuf, q+n-1, _state); /* * prepare FFT plan for chunks of A */ ftcomplexfftplan(q+n-1, 1, &plan, _state); /* * main overlap-add cycle */ i = 0; while(i<=m-1) { p = ae_minint(q, m-i, _state); for(j=0; j<=p-1; j++) { buf.ptr.p_double[2*j+0] = a->ptr.p_complex[i+j].x; buf.ptr.p_double[2*j+1] = a->ptr.p_complex[i+j].y; } for(j=p; j<=q+n-2; j++) { buf.ptr.p_double[2*j+0] = (double)(0); buf.ptr.p_double[2*j+1] = (double)(0); } ftapplyplan(&plan, &buf, 0, 1, _state); for(j=0; j<=q+n-2; j++) { ax = buf.ptr.p_double[2*j+0]; ay = buf.ptr.p_double[2*j+1]; bx = bbuf.ptr.p_complex[j].x; by = bbuf.ptr.p_complex[j].y; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*j+0] = tx; buf.ptr.p_double[2*j+1] = -ty; } ftapplyplan(&plan, &buf, 0, 1, _state); t = (double)1/(double)(q+n-1); if( circular ) { j1 = ae_minint(i+p+n-2, m-1, _state)-i; j2 = j1+1; } else { j1 = p+n-2; j2 = j1+1; } for(j=0; j<=j1; j++) { r->ptr.p_complex[i+j].x = r->ptr.p_complex[i+j].x+buf.ptr.p_double[2*j+0]*t; r->ptr.p_complex[i+j].y = r->ptr.p_complex[i+j].y-buf.ptr.p_double[2*j+1]*t; } for(j=j2; j<=p+n-2; j++) { r->ptr.p_complex[j-j2].x = r->ptr.p_complex[j-j2].x+buf.ptr.p_double[2*j+0]*t; r->ptr.p_complex[j-j2].y = r->ptr.p_complex[j-j2].y-buf.ptr.p_double[2*j+1]*t; } i = i+p; } ae_frame_leave(_state); return; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional real convolution. Extended subroutine which allows to choose convolution algorithm. Intended for internal use, ALGLIB users should call ConvR1D(). INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size, N<=M Alg - algorithm type: *-2 auto-select Q for overlap-add *-1 auto-select algorithm and parameters * 0 straightforward formula for small N's * 1 general FFT-based code * 2 overlap-add with length Q Q - length for overlap-add OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dx(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, ae_bool circular, ae_int_t alg, ae_int_t q, /* Real */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; double v; ae_int_t i; ae_int_t j; ae_int_t p; ae_int_t ptotal; ae_int_t i1; ae_int_t i2; ae_int_t j1; ae_int_t j2; double ax; double ay; double bx; double by; double tx; double ty; double flopcand; double flopbest; ae_int_t algbest; fasttransformplan plan; ae_vector buf; ae_vector buf2; ae_vector buf3; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); _fasttransformplan_init(&plan, _state); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&buf2, 0, DT_REAL, _state); ae_vector_init(&buf3, 0, DT_REAL, _state); ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state); ae_assert(n<=m, "ConvC1DX: Nptr.p_double[0]; ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); ae_frame_leave(_state); return; } /* * use straightforward formula */ if( circular ) { /* * circular convolution */ ae_vector_set_length(r, m, _state); v = b->ptr.p_double[0]; ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); for(i=1; i<=n-1; i++) { v = b->ptr.p_double[i]; i1 = 0; i2 = i-1; j1 = m-i; j2 = m-1; ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); i1 = i; i2 = m-1; j1 = 0; j2 = m-i-1; ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); } } else { /* * non-circular convolution */ ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = b->ptr.p_double[i]; ae_v_addd(&r->ptr.p_double[i], 1, &a->ptr.p_double[0], 1, ae_v_len(i,i+m-1), v); } } ae_frame_leave(_state); return; } /* * general FFT-based code for * circular and non-circular convolutions. * * First, if convolution is circular, we test whether M is smooth or not. * If it is smooth, we just use M-length FFT to calculate convolution. * If it is not, we calculate non-circular convolution and wrap it arount. * * If convolution is non-circular, we use zero-padding + FFT. * * We assume that M+N-1>2 - we should call small case code otherwise */ if( alg==1 ) { ae_assert(m+n-1>2, "ConvR1DX: internal error!", _state); if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 ) { /* * special code for circular convolution with smooth even M */ ae_vector_set_length(&buf, m, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_vector_set_length(&buf2, m, _state); ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=m-1; i++) { buf2.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf3, m, _state); ftcomplexfftplan(m/2, 1, &plan, _state); fftr1dinternaleven(&buf, m, &buf3, &plan, _state); fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; for(i=1; i<=m/2-1; i++) { ax = buf.ptr.p_double[2*i+0]; ay = buf.ptr.p_double[2*i+1]; bx = buf2.ptr.p_double[2*i+0]; by = buf2.ptr.p_double[2*i+1]; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*i+0] = tx; buf.ptr.p_double[2*i+1] = ty; } fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); ae_vector_set_length(r, m, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); } else { /* * M is non-smooth or non-even, general code (circular/non-circular): * * first part is the same for circular and non-circular * convolutions. zero padding, FFTs, inverse FFTs * * second part differs: * * for non-circular convolution we just copy array * * for circular convolution we add array tail to its head */ p = ftbasefindsmootheven(m+n-1, _state); ae_vector_set_length(&buf, p, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); for(i=m; i<=p-1; i++) { buf.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf2, p, _state); ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=p-1; i++) { buf2.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&buf3, p, _state); ftcomplexfftplan(p/2, 1, &plan, _state); fftr1dinternaleven(&buf, p, &buf3, &plan, _state); fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; for(i=1; i<=p/2-1; i++) { ax = buf.ptr.p_double[2*i+0]; ay = buf.ptr.p_double[2*i+1]; bx = buf2.ptr.p_double[2*i+0]; by = buf2.ptr.p_double[2*i+1]; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*i+0] = tx; buf.ptr.p_double[2*i+1] = ty; } fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); if( circular ) { /* * circular, add tail to head */ ae_vector_set_length(r, m, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); if( n>=2 ) { ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[m], 1, ae_v_len(0,n-2)); } } else { /* * non-circular, just copy */ ae_vector_set_length(r, m+n-1, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m+n-2)); } } ae_frame_leave(_state); return; } /* * overlap-add method */ if( alg==2 ) { ae_assert((q+n-1)%2==0, "ConvR1DX: internal error!", _state); ae_vector_set_length(&buf, q+n-1, _state); ae_vector_set_length(&buf2, q+n-1, _state); ae_vector_set_length(&buf3, q+n-1, _state); ftcomplexfftplan((q+n-1)/2, 1, &plan, _state); /* * prepare R */ if( circular ) { ae_vector_set_length(r, m, _state); for(i=0; i<=m-1; i++) { r->ptr.p_double[i] = (double)(0); } } else { ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_double[i] = (double)(0); } } /* * pre-calculated FFT(B) */ ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(j=n; j<=q+n-2; j++) { buf2.ptr.p_double[j] = (double)(0); } fftr1dinternaleven(&buf2, q+n-1, &buf3, &plan, _state); /* * main overlap-add cycle */ i = 0; while(i<=m-1) { p = ae_minint(q, m-i, _state); ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[i], 1, ae_v_len(0,p-1)); for(j=p; j<=q+n-2; j++) { buf.ptr.p_double[j] = (double)(0); } fftr1dinternaleven(&buf, q+n-1, &buf3, &plan, _state); buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; for(j=1; j<=(q+n-1)/2-1; j++) { ax = buf.ptr.p_double[2*j+0]; ay = buf.ptr.p_double[2*j+1]; bx = buf2.ptr.p_double[2*j+0]; by = buf2.ptr.p_double[2*j+1]; tx = ax*bx-ay*by; ty = ax*by+ay*bx; buf.ptr.p_double[2*j+0] = tx; buf.ptr.p_double[2*j+1] = ty; } fftr1dinvinternaleven(&buf, q+n-1, &buf3, &plan, _state); if( circular ) { j1 = ae_minint(i+p+n-2, m-1, _state)-i; j2 = j1+1; } else { j1 = p+n-2; j2 = j1+1; } ae_v_add(&r->ptr.p_double[i], 1, &buf.ptr.p_double[0], 1, ae_v_len(i,i+j1)); if( p+n-2>=j2 ) { ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[j2], 1, ae_v_len(0,p+n-2-j2)); } i = i+p; } ae_frame_leave(_state); return; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(conj(pattern[j])*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1d(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_vector p; ae_vector b; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&p, 0, DT_COMPLEX, _state); ae_vector_init(&b, 0, DT_COMPLEX, _state); ae_assert(n>0&&m>0, "CorrC1D: incorrect N or M!", _state); ae_vector_set_length(&p, m, _state); for(i=0; i<=m-1; i++) { p.ptr.p_complex[m-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); } convc1d(&p, m, signal, n, &b, _state); ae_vector_set_length(r, m+n-1, _state); ae_v_cmove(&r->ptr.p_complex[0], 1, &b.ptr.p_complex[m-1], 1, "N", ae_v_len(0,n-1)); if( m+n-2>=n ) { ae_v_cmove(&r->ptr.p_complex[n], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(n,m+n-2)); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional circular complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1dcircular(/* Complex */ ae_vector* signal, ae_int_t m, /* Complex */ ae_vector* pattern, ae_int_t n, /* Complex */ ae_vector* c, ae_state *_state) { ae_frame _frame_block; ae_vector p; ae_vector b; ae_int_t i1; ae_int_t i2; ae_int_t i; ae_int_t j2; ae_frame_make(_state, &_frame_block); ae_vector_clear(c); ae_vector_init(&p, 0, DT_COMPLEX, _state); ae_vector_init(&b, 0, DT_COMPLEX, _state); ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); i1 = i1+m; } corrc1dcircular(signal, m, &b, m, c, _state); ae_frame_leave(_state); return; } /* * Task is normalized */ ae_vector_set_length(&p, n, _state); for(i=0; i<=n-1; i++) { p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); } convc1dcircular(signal, m, &p, n, &b, _state); ae_vector_set_length(c, m, _state); ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n)); if( m-n+1<=m-1 ) { ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1)); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(pattern[j]*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(pattern[j]*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1d(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_vector p; ae_vector b; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&p, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_assert(n>0&&m>0, "CorrR1D: incorrect N or M!", _state); ae_vector_set_length(&p, m, _state); for(i=0; i<=m-1; i++) { p.ptr.p_double[m-1-i] = pattern->ptr.p_double[i]; } convr1d(&p, m, signal, n, &b, _state); ae_vector_set_length(r, m+n-1, _state); ae_v_move(&r->ptr.p_double[0], 1, &b.ptr.p_double[m-1], 1, ae_v_len(0,n-1)); if( m+n-2>=n ) { ae_v_move(&r->ptr.p_double[n], 1, &b.ptr.p_double[0], 1, ae_v_len(n,m+n-2)); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional circular real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1dcircular(/* Real */ ae_vector* signal, ae_int_t m, /* Real */ ae_vector* pattern, ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_frame _frame_block; ae_vector p; ae_vector b; ae_int_t i1; ae_int_t i2; ae_int_t i; ae_int_t j2; ae_frame_make(_state, &_frame_block); ae_vector_clear(c); ae_vector_init(&p, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); /* * normalize task: make M>=N, * so A will be longer (at least - not shorter) that B. */ if( mptr.p_double[i1], 1, ae_v_len(0,j2)); i1 = i1+m; } corrr1dcircular(signal, m, &b, m, c, _state); ae_frame_leave(_state); return; } /* * Task is normalized */ ae_vector_set_length(&p, n, _state); for(i=0; i<=n-1; i++) { p.ptr.p_double[n-1-i] = pattern->ptr.p_double[i]; } convr1dcircular(signal, m, &p, n, &b, _state); ae_vector_set_length(c, m, _state); ae_v_move(&c->ptr.p_double[0], 1, &b.ptr.p_double[n-1], 1, ae_v_len(0,m-n)); if( m-n+1<=m-1 ) { ae_v_move(&c->ptr.p_double[m-n+1], 1, &b.ptr.p_double[0], 1, ae_v_len(m-n+1,m-1)); } ae_frame_leave(_state); } /************************************************************************* 1-dimensional Fast Hartley Transform. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS A - FHT of a input array, array[0..N-1], A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) -- ALGLIB -- Copyright 04.06.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector fa; ae_frame_make(_state, &_frame_block); ae_vector_init(&fa, 0, DT_COMPLEX, _state); ae_assert(n>0, "FHTR1D: incorrect N!", _state); /* * Special case: N=1, FHT is just identity transform. * After this block we assume that N is strictly greater than 1. */ if( n==1 ) { ae_frame_leave(_state); return; } /* * Reduce FHt to real FFT */ fftr1d(a, n, &fa, _state); for(i=0; i<=n-1; i++) { a->ptr.p_double[i] = fa.ptr.p_complex[i].x-fa.ptr.p_complex[i].y; } ae_frame_leave(_state); } /************************************************************************* 1-dimensional inverse FHT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse FHT of a input array, array[0..N-1] -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_int_t i; ae_assert(n>0, "FHTR1DInv: incorrect N!", _state); /* * Special case: N=1, iFHT is just identity transform. * After this block we assume that N is strictly greater than 1. */ if( n==1 ) { return; } /* * Inverse FHT can be expressed in terms of the FHT as * * invfht(x) = fht(x)/N */ fhtr1d(a, n, _state); for(i=0; i<=n-1; i++) { a->ptr.p_double[i] = a->ptr.p_double[i]/n; } } } qmapshack-1.10.0/3rdparty/alglib/src/alglibinternal.cpp000755 001750 000144 00001712465 13024173403 024226 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "alglibinternal.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static void tsort_tagsortfastirec(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, /* Real */ ae_vector* bufa, /* Integer */ ae_vector* bufb, ae_int_t i1, ae_int_t i2, ae_state *_state); static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* bufa, /* Real */ ae_vector* bufb, ae_int_t i1, ae_int_t i2, ae_state *_state); static void tsort_tagsortfastrec(/* Real */ ae_vector* a, /* Real */ ae_vector* bufa, ae_int_t i1, ae_int_t i2, ae_state *_state); static void hsschur_internalauxschur(ae_bool wantt, ae_bool wantz, ae_int_t n, ae_int_t ilo, ae_int_t ihi, /* Real */ ae_matrix* h, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, ae_int_t iloz, ae_int_t ihiz, /* Real */ ae_matrix* z, /* Real */ ae_vector* work, /* Real */ ae_vector* workv3, /* Real */ ae_vector* workc1, /* Real */ ae_vector* works1, ae_int_t* info, ae_state *_state); static void hsschur_aux2x2schur(double* a, double* b, double* c, double* d, double* rt1r, double* rt1i, double* rt2r, double* rt2i, double* cs, double* sn, ae_state *_state); static double hsschur_extschursign(double a, double b, ae_state *_state); static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state); static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, ae_complex beta, double lnmax, double bnorm, double maxgrowth, double* xnorm, ae_complex* x, ae_state *_state); static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ ae_vector* weights, ae_int_t wcount, /* Real */ ae_vector* hpcbuf, ae_state *_state); static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ ae_vector* buf, ae_int_t wcount, /* Real */ ae_vector* grad, ae_state *_state); static void xblas_xsum(/* Real */ ae_vector* w, double mx, ae_int_t n, double* r, double* rerr, ae_state *_state); static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state); static double linmin_ftol = 0.001; static double linmin_xtol = 100*ae_machineepsilon; static ae_int_t linmin_maxfev = 20; static double linmin_stpmin = 1.0E-50; static double linmin_defstpmax = 1.0E+50; static double linmin_armijofactor = 1.3; static void linmin_mcstep(double* stx, double* fx, double* dx, double* sty, double* fy, double* dy, double* stp, double fp, double dp, ae_bool* brackt, double stmin, double stmax, ae_int_t* info, ae_state *_state); static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state); static ae_int_t ntheory_modmul(ae_int_t a, ae_int_t b, ae_int_t n, ae_state *_state); static ae_int_t ntheory_modexp(ae_int_t a, ae_int_t b, ae_int_t n, ae_state *_state); static ae_int_t ftbase_coltype = 0; static ae_int_t ftbase_coloperandscnt = 1; static ae_int_t ftbase_coloperandsize = 2; static ae_int_t ftbase_colmicrovectorsize = 3; static ae_int_t ftbase_colparam0 = 4; static ae_int_t ftbase_colparam1 = 5; static ae_int_t ftbase_colparam2 = 6; static ae_int_t ftbase_colparam3 = 7; static ae_int_t ftbase_colscnt = 8; static ae_int_t ftbase_opend = 0; static ae_int_t ftbase_opcomplexreffft = 1; static ae_int_t ftbase_opbluesteinsfft = 2; static ae_int_t ftbase_opcomplexcodeletfft = 3; static ae_int_t ftbase_opcomplexcodelettwfft = 4; static ae_int_t ftbase_opradersfft = 5; static ae_int_t ftbase_opcomplextranspose = -1; static ae_int_t ftbase_opcomplexfftfactors = -2; static ae_int_t ftbase_opstart = -3; static ae_int_t ftbase_opjmp = -4; static ae_int_t ftbase_opparallelcall = -5; static ae_int_t ftbase_maxradix = 6; static ae_int_t ftbase_updatetw = 16; static ae_int_t ftbase_recursivethreshold = 1024; static ae_int_t ftbase_raderthreshold = 19; static ae_int_t ftbase_ftbasecodeletrecommended = 5; static double ftbase_ftbaseinefficiencyfactor = 1.3; static ae_int_t ftbase_ftbasemaxsmoothfactor = 5; static void ftbase_ftdeterminespacerequirements(ae_int_t n, ae_int_t* precrsize, ae_int_t* precisize, ae_state *_state); static void ftbase_ftcomplexfftplanrec(ae_int_t n, ae_int_t k, ae_bool childplan, ae_bool topmostplan, ae_int_t* rowptr, ae_int_t* bluesteinsize, ae_int_t* precrptr, ae_int_t* preciptr, fasttransformplan* plan, ae_state *_state); static void ftbase_ftpushentry(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_state *_state); static void ftbase_ftpushentry2(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_int_t eparam1, ae_state *_state); static void ftbase_ftpushentry4(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_int_t eparam1, ae_int_t eparam2, ae_int_t eparam3, ae_state *_state); static void ftbase_ftapplysubplan(fasttransformplan* plan, ae_int_t subplan, /* Real */ ae_vector* a, ae_int_t abase, ae_int_t aoffset, /* Real */ ae_vector* buf, ae_int_t repcnt, ae_state *_state); static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, /* Real */ ae_vector* buf, ae_state *_state); static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, ae_state *_state); static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, ae_state *_state); static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, ae_int_t m, /* Real */ ae_vector* precr, ae_int_t offs, ae_state *_state); static void ftbase_ftbluesteinsfft(fasttransformplan* plan, /* Real */ ae_vector* a, ae_int_t abase, ae_int_t aoffset, ae_int_t operandscnt, ae_int_t n, ae_int_t m, ae_int_t precoffs, ae_int_t subplan, /* Real */ ae_vector* bufa, /* Real */ ae_vector* bufb, /* Real */ ae_vector* bufc, /* Real */ ae_vector* bufd, ae_state *_state); static void ftbase_ftprecomputeradersfft(ae_int_t n, ae_int_t rq, ae_int_t riq, /* Real */ ae_vector* precr, ae_int_t offs, ae_state *_state); static void ftbase_ftradersfft(fasttransformplan* plan, /* Real */ ae_vector* a, ae_int_t abase, ae_int_t aoffset, ae_int_t operandscnt, ae_int_t n, ae_int_t subplan, ae_int_t rq, ae_int_t riq, ae_int_t precoffs, /* Real */ ae_vector* buf, ae_state *_state); static void ftbase_ftfactorize(ae_int_t n, ae_bool isroot, ae_int_t* n1, ae_int_t* n2, ae_state *_state); static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state); static void ftbase_ffttwcalc(/* Real */ ae_vector* a, ae_int_t aoffset, ae_int_t n1, ae_int_t n2, ae_state *_state); static void ftbase_internalcomplexlintranspose(/* Real */ ae_vector* a, ae_int_t m, ae_int_t n, ae_int_t astart, /* Real */ ae_vector* buf, ae_state *_state); static void ftbase_ffticltrec(/* Real */ ae_vector* a, ae_int_t astart, ae_int_t astride, /* Real */ ae_vector* b, ae_int_t bstart, ae_int_t bstride, ae_int_t m, ae_int_t n, ae_state *_state); static void ftbase_fftirltrec(/* Real */ ae_vector* a, ae_int_t astart, ae_int_t astride, /* Real */ ae_vector* b, ae_int_t bstart, ae_int_t bstride, ae_int_t m, ae_int_t n, ae_state *_state); static void ftbase_ftbasefindsmoothrec(ae_int_t n, ae_int_t seed, ae_int_t leastfactor, ae_int_t* best, ae_state *_state); /************************************************************************* This function is used to set error flags during unit tests. When COND parameter is True, FLAG variable is set to True. When COND is False, FLAG is unchanged. The purpose of this function is to have single point where failures of unit tests can be detected. This function returns value of COND. *************************************************************************/ ae_bool seterrorflag(ae_bool* flag, ae_bool cond, ae_state *_state) { ae_bool result; if( cond ) { *flag = ae_true; } result = cond; return result; } /************************************************************************* Internally calls SetErrorFlag() with condition: Abs(Val-RefVal)>Tol*Max(Abs(RefVal),S) This function is used to test relative error in Val against RefVal, with relative error being replaced by absolute when scale of RefVal is less than S. This function returns value of COND. *************************************************************************/ ae_bool seterrorflagdiff(ae_bool* flag, double val, double refval, double tol, double s, ae_state *_state) { ae_bool result; result = seterrorflag(flag, ae_fp_greater(ae_fabs(val-refval, _state),tol*ae_maxreal(ae_fabs(refval, _state), s, _state)), _state); return result; } /************************************************************************* The function "touches" integer - it is used to avoid compiler messages about unused variables (in rare cases when we do NOT want to remove these variables). -- ALGLIB -- Copyright 17.09.2012 by Bochkanov Sergey *************************************************************************/ void touchint(ae_int_t* a, ae_state *_state) { } /************************************************************************* The function "touches" real - it is used to avoid compiler messages about unused variables (in rare cases when we do NOT want to remove these variables). -- ALGLIB -- Copyright 17.09.2012 by Bochkanov Sergey *************************************************************************/ void touchreal(double* a, ae_state *_state) { } /************************************************************************* The function performs zero-coalescing on real value. NOTE: no check is performed for B<>0 -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ double coalesce(double a, double b, ae_state *_state) { double result; result = a; if( ae_fp_eq(a,0.0) ) { result = b; } return result; } /************************************************************************* The function convert integer value to real value. -- ALGLIB -- Copyright 17.09.2012 by Bochkanov Sergey *************************************************************************/ double inttoreal(ae_int_t a, ae_state *_state) { double result; result = (double)(a); return result; } /************************************************************************* The function calculates binary logarithm. NOTE: it costs twice as much as Ln(x) -- ALGLIB -- Copyright 17.09.2012 by Bochkanov Sergey *************************************************************************/ double logbase2(double x, ae_state *_state) { double result; result = ae_log(x, _state)/ae_log((double)(2), _state); return result; } /************************************************************************* This function compares two numbers for approximate equality, with tolerance to errors as large as max(|a|,|b|)*tol. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_bool approxequalrel(double a, double b, double tol, ae_state *_state) { ae_bool result; result = ae_fp_less_eq(ae_fabs(a-b, _state),ae_maxreal(ae_fabs(a, _state), ae_fabs(b, _state), _state)*tol); return result; } /************************************************************************* This function generates 1-dimensional general interpolation task with moderate Lipshitz constant (close to 1.0) If N=1 then suborutine generates only one point at the middle of [A,B] -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void taskgenint1d(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; double h; ae_vector_clear(x); ae_vector_clear(y); ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); ae_vector_set_length(x, n, _state); ae_vector_set_length(y, n, _state); if( n>1 ) { x->ptr.p_double[0] = a; y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; h = (b-a)/(n-1); for(i=1; i<=n-1; i++) { if( i!=n-1 ) { x->ptr.p_double[i] = a+(i+0.2*(2*ae_randomreal(_state)-1))*h; } else { x->ptr.p_double[i] = b; } y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); } } else { x->ptr.p_double[0] = 0.5*(a+b); y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; } } /************************************************************************* This function generates 1-dimensional equidistant interpolation task with moderate Lipshitz constant (close to 1.0) If N=1 then suborutine generates only one point at the middle of [A,B] -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void taskgenint1dequidist(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; double h; ae_vector_clear(x); ae_vector_clear(y); ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); ae_vector_set_length(x, n, _state); ae_vector_set_length(y, n, _state); if( n>1 ) { x->ptr.p_double[0] = a; y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; h = (b-a)/(n-1); for(i=1; i<=n-1; i++) { x->ptr.p_double[i] = a+i*h; y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*h; } } else { x->ptr.p_double[0] = 0.5*(a+b); y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; } } /************************************************************************* This function generates 1-dimensional Chebyshev-1 interpolation task with moderate Lipshitz constant (close to 1.0) If N=1 then suborutine generates only one point at the middle of [A,B] -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void taskgenint1dcheb1(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_vector_clear(x); ae_vector_clear(y); ae_assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!", _state); ae_vector_set_length(x, n, _state); ae_vector_set_length(y, n, _state); if( n>1 ) { for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(2*i+1)/(2*n), _state); if( i==0 ) { y->ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); } } } else { x->ptr.p_double[0] = 0.5*(a+b); y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; } } /************************************************************************* This function generates 1-dimensional Chebyshev-2 interpolation task with moderate Lipshitz constant (close to 1.0) If N=1 then suborutine generates only one point at the middle of [A,B] -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void taskgenint1dcheb2(double a, double b, ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_vector_clear(x); ae_vector_clear(y); ae_assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!", _state); ae_vector_set_length(x, n, _state); ae_vector_set_length(y, n, _state); if( n>1 ) { for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state); if( i==0 ) { y->ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); } } } else { x->ptr.p_double[0] = 0.5*(a+b); y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; } } /************************************************************************* This function checks that all values from X[] are distinct. It does more than just usual floating point comparison: * first, it calculates max(X) and min(X) * second, it maps X[] from [min,max] to [1,2] * only at this stage actual comparison is done The meaning of such check is to ensure that all values are "distinct enough" and will not cause interpolation subroutine to fail. NOTE: X[] must be sorted by ascending (subroutine ASSERT's it) -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_bool aredistinct(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double a; double b; ae_int_t i; ae_bool nonsorted; ae_bool result; ae_assert(n>=1, "APSERVAreDistinct: internal error (N<1)", _state); if( n==1 ) { /* * everything is alright, it is up to caller to decide whether it * can interpolate something with just one point */ result = ae_true; return result; } a = x->ptr.p_double[0]; b = x->ptr.p_double[0]; nonsorted = ae_false; for(i=1; i<=n-1; i++) { a = ae_minreal(a, x->ptr.p_double[i], _state); b = ae_maxreal(b, x->ptr.p_double[i], _state); nonsorted = nonsorted||ae_fp_greater_eq(x->ptr.p_double[i-1],x->ptr.p_double[i]); } ae_assert(!nonsorted, "APSERVAreDistinct: internal error (not sorted)", _state); for(i=1; i<=n-1; i++) { if( ae_fp_eq((x->ptr.p_double[i]-a)/(b-a)+1,(x->ptr.p_double[i-1]-a)/(b-a)+1) ) { result = ae_false; return result; } } result = ae_true; return result; } /************************************************************************* This function checks that two boolean values are the same (both are True or both are False). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state) { ae_bool result; result = (v1&&v2)||(!v1&&!v2); return result; } /************************************************************************* If Length(X)cntcntcnt0&&n>0 ) { if( x->rowscolsrows; n2 = x->cols; ae_swap_matrices(x, &oldx); ae_matrix_set_length(x, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( iptr.pp_double[i][j] = oldx.ptr.pp_double[i][j]; } else { x->ptr.pp_double[i][j] = 0.0; } } } ae_frame_leave(_state); } /************************************************************************* Resizes X and: * preserves old contents of X * fills new elements by zeros -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void imatrixresize(/* Integer */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix oldx; ae_int_t i; ae_int_t j; ae_int_t m2; ae_int_t n2; ae_frame_make(_state, &_frame_block); ae_matrix_init(&oldx, 0, 0, DT_INT, _state); m2 = x->rows; n2 = x->cols; ae_swap_matrices(x, &oldx); ae_matrix_set_length(x, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( iptr.pp_int[i][j] = oldx.ptr.pp_int[i][j]; } else { x->ptr.pp_int[i][j] = 0; } } } ae_frame_leave(_state); } /************************************************************************* This function checks that length(X) is at least N and first N values from X[] are finite -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool isfinitevector(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { ae_int_t i; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state); if( n==0 ) { result = ae_true; return result; } if( x->cntptr.p_double[i], _state) ) { result = ae_false; return result; } } result = ae_true; return result; } /************************************************************************* This function checks that first N values from X[] are finite -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool isfinitecvector(/* Complex */ ae_vector* z, ae_int_t n, ae_state *_state) { ae_int_t i; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteCVector: internal error (N<0)", _state); for(i=0; i<=n-1; i++) { if( !ae_isfinite(z->ptr.p_complex[i].x, _state)||!ae_isfinite(z->ptr.p_complex[i].y, _state) ) { result = ae_false; return result; } } result = ae_true; return result; } /************************************************************************* This function checks that size of X is at least MxN and values from X[0..M-1,0..N-1] are finite. -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool apservisfinitematrix(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteMatrix: internal error (N<0)", _state); ae_assert(m>=0, "APSERVIsFiniteMatrix: internal error (M<0)", _state); if( m==0||n==0 ) { result = ae_true; return result; } if( x->rowscolsptr.pp_double[i][j], _state) ) { result = ae_false; return result; } } } result = ae_true; return result; } /************************************************************************* This function checks that all values from X[0..M-1,0..N-1] are finite -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteCMatrix: internal error (N<0)", _state); ae_assert(m>=0, "APSERVIsFiniteCMatrix: internal error (M<0)", _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) { result = ae_false; return result; } } } result = ae_true; return result; } /************************************************************************* This function checks that size of X is at least NxN and all values from upper/lower triangle of X[0..N-1,0..N-1] are finite -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool isfinitertrmatrix(/* Real */ ae_matrix* x, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j1; ae_int_t j2; ae_int_t j; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteRTRMatrix: internal error (N<0)", _state); if( n==0 ) { result = ae_true; return result; } if( x->rowscolsptr.pp_double[i][j], _state) ) { result = ae_false; return result; } } } result = ae_true; return result; } /************************************************************************* This function checks that all values from upper/lower triangle of X[0..N-1,0..N-1] are finite -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j1; ae_int_t j2; ae_int_t j; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) { result = ae_false; return result; } } } result = ae_true; return result; } /************************************************************************* This function checks that all values from X[0..M-1,0..N-1] are finite or NaN's. -- ALGLIB -- Copyright 18.06.2010 by Bochkanov Sergey *************************************************************************/ ae_bool apservisfiniteornanmatrix(/* Real */ ae_matrix* x, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; ae_assert(n>=0, "APSERVIsFiniteOrNaNMatrix: internal error (N<0)", _state); ae_assert(m>=0, "APSERVIsFiniteOrNaNMatrix: internal error (M<0)", _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( !(ae_isfinite(x->ptr.pp_double[i][j], _state)||ae_isnan(x->ptr.pp_double[i][j], _state)) ) { result = ae_false; return result; } } } result = ae_true; return result; } /************************************************************************* Safe sqrt(x^2+y^2) -- ALGLIB -- Copyright by Bochkanov Sergey *************************************************************************/ double safepythag2(double x, double y, ae_state *_state) { double w; double xabs; double yabs; double z; double result; xabs = ae_fabs(x, _state); yabs = ae_fabs(y, _state); w = ae_maxreal(xabs, yabs, _state); z = ae_minreal(xabs, yabs, _state); if( ae_fp_eq(z,(double)(0)) ) { result = w; } else { result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state); } return result; } /************************************************************************* Safe sqrt(x^2+y^2) -- ALGLIB -- Copyright by Bochkanov Sergey *************************************************************************/ double safepythag3(double x, double y, double z, ae_state *_state) { double w; double result; w = ae_maxreal(ae_fabs(x, _state), ae_maxreal(ae_fabs(y, _state), ae_fabs(z, _state), _state), _state); if( ae_fp_eq(w,(double)(0)) ) { result = (double)(0); return result; } x = x/w; y = y/w; z = z/w; result = w*ae_sqrt(ae_sqr(x, _state)+ae_sqr(y, _state)+ae_sqr(z, _state), _state); return result; } /************************************************************************* Safe division. This function attempts to calculate R=X/Y without overflow. It returns: * +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like situation (no overlfow is generated, R is either NAN, PosINF, NegINF) * 0, if MinRealNumber0 (R contains result, may be zero) * -1, if 00 */ if( ae_fp_eq(y,(double)(0)) ) { result = 1; if( ae_fp_eq(x,(double)(0)) ) { *r = _state->v_nan; } if( ae_fp_greater(x,(double)(0)) ) { *r = _state->v_posinf; } if( ae_fp_less(x,(double)(0)) ) { *r = _state->v_neginf; } return result; } if( ae_fp_eq(x,(double)(0)) ) { *r = (double)(0); result = 0; return result; } /* * make Y>0 */ if( ae_fp_less(y,(double)(0)) ) { x = -x; y = -y; } /* * */ if( ae_fp_greater_eq(y,(double)(1)) ) { *r = x/y; if( ae_fp_less_eq(ae_fabs(*r, _state),ae_minrealnumber) ) { result = -1; *r = (double)(0); } else { result = 0; } } else { if( ae_fp_greater_eq(ae_fabs(x, _state),ae_maxrealnumber*y) ) { if( ae_fp_greater(x,(double)(0)) ) { *r = _state->v_posinf; } else { *r = _state->v_neginf; } result = 1; } else { *r = x/y; result = 0; } } return result; } /************************************************************************* This function calculates "safe" min(X/Y,V) for positive finite X, Y, V. No overflow is generated in any case. -- ALGLIB -- Copyright by Bochkanov Sergey *************************************************************************/ double safeminposrv(double x, double y, double v, ae_state *_state) { double r; double result; if( ae_fp_greater_eq(y,(double)(1)) ) { /* * Y>=1, we can safely divide by Y */ r = x/y; result = v; if( ae_fp_greater(v,r) ) { result = r; } else { result = v; } } else { /* * Y<1, we can safely multiply by Y */ if( ae_fp_less(x,v*y) ) { result = x/y; } else { result = v; } } return result; } /************************************************************************* This function makes periodic mapping of X to [A,B]. It accepts X, A, B (A>B). It returns T which lies in [A,B] and integer K, such that X = T + K*(B-A). NOTES: * K is represented as real value, although actually it is integer * T is guaranteed to be in [A,B] * T replaces X -- ALGLIB -- Copyright by Bochkanov Sergey *************************************************************************/ void apperiodicmap(double* x, double a, double b, double* k, ae_state *_state) { *k = 0; ae_assert(ae_fp_less(a,b), "APPeriodicMap: internal error!", _state); *k = (double)(ae_ifloor((*x-a)/(b-a), _state)); *x = *x-*k*(b-a); while(ae_fp_less(*x,a)) { *x = *x+(b-a); *k = *k-1; } while(ae_fp_greater(*x,b)) { *x = *x-(b-a); *k = *k+1; } *x = ae_maxreal(*x, a, _state); *x = ae_minreal(*x, b, _state); } /************************************************************************* Returns random normal number using low-quality system-provided generator -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ double randomnormal(ae_state *_state) { double u; double v; double s; double result; for(;;) { u = 2*ae_randomreal(_state)-1; v = 2*ae_randomreal(_state)-1; s = ae_sqr(u, _state)+ae_sqr(v, _state); if( ae_fp_greater(s,(double)(0))&&ae_fp_less(s,(double)(1)) ) { /* * two Sqrt's instead of one to * avoid overflow when S is too small */ s = ae_sqrt(-2*ae_log(s, _state), _state)/ae_sqrt(s, _state); result = u*s; break; } } return result; } /************************************************************************* Generates random unit vector using low-quality system-provided generator. Reallocates array if its size is too short. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; double v; double vv; ae_assert(n>0, "RandomUnit: N<=0", _state); if( x->cntptr.p_double[i] = vv; v = v+vv*vv; } } while(ae_fp_less_eq(v,(double)(0))); v = 1/ae_sqrt(v, _state); for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]*v; } } /************************************************************************* This function is used to swap two integer values *************************************************************************/ void swapi(ae_int_t* v0, ae_int_t* v1, ae_state *_state) { ae_int_t v; v = *v0; *v0 = *v1; *v1 = v; } /************************************************************************* This function is used to swap two real values *************************************************************************/ void swapr(double* v0, double* v1, ae_state *_state) { double v; v = *v0; *v0 = *v1; *v1 = v; } /************************************************************************* This function is used to return maximum of three real values *************************************************************************/ double maxreal3(double v0, double v1, double v2, ae_state *_state) { double result; result = v0; if( ae_fp_less(result,v1) ) { result = v1; } if( ae_fp_less(result,v2) ) { result = v2; } return result; } /************************************************************************* This function is used to increment value of integer variable *************************************************************************/ void inc(ae_int_t* v, ae_state *_state) { *v = *v+1; } /************************************************************************* This function is used to decrement value of integer variable *************************************************************************/ void dec(ae_int_t* v, ae_state *_state) { *v = *v-1; } /************************************************************************* This function performs two operations: 1. decrements value of integer variable, if it is positive 2. explicitly sets variable to zero if it is non-positive It is used by some algorithms to decrease value of internal counters. *************************************************************************/ void countdown(ae_int_t* v, ae_state *_state) { if( *v>0 ) { *v = *v-1; } else { *v = 0; } } /************************************************************************* 'bounds' value: maps X to [B1,B2] -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ double boundval(double x, double b1, double b2, ae_state *_state) { double result; if( ae_fp_less_eq(x,b1) ) { result = b1; return result; } if( ae_fp_greater_eq(x,b2) ) { result = b2; return result; } result = x; return result; } /************************************************************************* Allocation of serializer: complex value *************************************************************************/ void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state) { ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); } /************************************************************************* Serialization: complex value *************************************************************************/ void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state) { ae_serializer_serialize_double(s, v.x, _state); ae_serializer_serialize_double(s, v.y, _state); } /************************************************************************* Unserialization: complex value *************************************************************************/ ae_complex unserializecomplex(ae_serializer* s, ae_state *_state) { ae_complex result; ae_serializer_unserialize_double(s, &result.x, _state); ae_serializer_unserialize_double(s, &result.y, _state); return result; } /************************************************************************* Allocation of serializer: real array *************************************************************************/ void allocrealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_int_t n, ae_state *_state) { ae_int_t i; if( n<0 ) { n = v->cnt; } ae_serializer_alloc_entry(s); for(i=0; i<=n-1; i++) { ae_serializer_alloc_entry(s); } } /************************************************************************* Serialization: complex value *************************************************************************/ void serializerealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_int_t n, ae_state *_state) { ae_int_t i; if( n<0 ) { n = v->cnt; } ae_serializer_serialize_int(s, n, _state); for(i=0; i<=n-1; i++) { ae_serializer_serialize_double(s, v->ptr.p_double[i], _state); } } /************************************************************************* Unserialization: complex value *************************************************************************/ void unserializerealarray(ae_serializer* s, /* Real */ ae_vector* v, ae_state *_state) { ae_int_t n; ae_int_t i; double t; ae_vector_clear(v); ae_serializer_unserialize_int(s, &n, _state); if( n==0 ) { return; } ae_vector_set_length(v, n, _state); for(i=0; i<=n-1; i++) { ae_serializer_unserialize_double(s, &t, _state); v->ptr.p_double[i] = t; } } /************************************************************************* Allocation of serializer: Integer array *************************************************************************/ void allocintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_int_t n, ae_state *_state) { ae_int_t i; if( n<0 ) { n = v->cnt; } ae_serializer_alloc_entry(s); for(i=0; i<=n-1; i++) { ae_serializer_alloc_entry(s); } } /************************************************************************* Serialization: Integer array *************************************************************************/ void serializeintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_int_t n, ae_state *_state) { ae_int_t i; if( n<0 ) { n = v->cnt; } ae_serializer_serialize_int(s, n, _state); for(i=0; i<=n-1; i++) { ae_serializer_serialize_int(s, v->ptr.p_int[i], _state); } } /************************************************************************* Unserialization: complex value *************************************************************************/ void unserializeintegerarray(ae_serializer* s, /* Integer */ ae_vector* v, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t t; ae_vector_clear(v); ae_serializer_unserialize_int(s, &n, _state); if( n==0 ) { return; } ae_vector_set_length(v, n, _state); for(i=0; i<=n-1; i++) { ae_serializer_unserialize_int(s, &t, _state); v->ptr.p_int[i] = t; } } /************************************************************************* Allocation of serializer: real matrix *************************************************************************/ void allocrealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_int_t n0, ae_int_t n1, ae_state *_state) { ae_int_t i; ae_int_t j; if( n0<0 ) { n0 = v->rows; } if( n1<0 ) { n1 = v->cols; } ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); for(i=0; i<=n0-1; i++) { for(j=0; j<=n1-1; j++) { ae_serializer_alloc_entry(s); } } } /************************************************************************* Serialization: complex value *************************************************************************/ void serializerealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_int_t n0, ae_int_t n1, ae_state *_state) { ae_int_t i; ae_int_t j; if( n0<0 ) { n0 = v->rows; } if( n1<0 ) { n1 = v->cols; } ae_serializer_serialize_int(s, n0, _state); ae_serializer_serialize_int(s, n1, _state); for(i=0; i<=n0-1; i++) { for(j=0; j<=n1-1; j++) { ae_serializer_serialize_double(s, v->ptr.pp_double[i][j], _state); } } } /************************************************************************* Unserialization: complex value *************************************************************************/ void unserializerealmatrix(ae_serializer* s, /* Real */ ae_matrix* v, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n0; ae_int_t n1; double t; ae_matrix_clear(v); ae_serializer_unserialize_int(s, &n0, _state); ae_serializer_unserialize_int(s, &n1, _state); if( n0==0||n1==0 ) { return; } ae_matrix_set_length(v, n0, n1, _state); for(i=0; i<=n0-1; i++) { for(j=0; j<=n1-1; j++) { ae_serializer_unserialize_double(s, &t, _state); v->ptr.pp_double[i][j] = t; } } } /************************************************************************* Copy integer array *************************************************************************/ void copyintegerarray(/* Integer */ ae_vector* src, /* Integer */ ae_vector* dst, ae_state *_state) { ae_int_t i; ae_vector_clear(dst); if( src->cnt>0 ) { ae_vector_set_length(dst, src->cnt, _state); for(i=0; i<=src->cnt-1; i++) { dst->ptr.p_int[i] = src->ptr.p_int[i]; } } } /************************************************************************* Copy real array *************************************************************************/ void copyrealarray(/* Real */ ae_vector* src, /* Real */ ae_vector* dst, ae_state *_state) { ae_int_t i; ae_vector_clear(dst); if( src->cnt>0 ) { ae_vector_set_length(dst, src->cnt, _state); for(i=0; i<=src->cnt-1; i++) { dst->ptr.p_double[i] = src->ptr.p_double[i]; } } } /************************************************************************* Copy real matrix *************************************************************************/ void copyrealmatrix(/* Real */ ae_matrix* src, /* Real */ ae_matrix* dst, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(dst); if( src->rows>0&&src->cols>0 ) { ae_matrix_set_length(dst, src->rows, src->cols, _state); for(i=0; i<=src->rows-1; i++) { for(j=0; j<=src->cols-1; j++) { dst->ptr.pp_double[i][j] = src->ptr.pp_double[i][j]; } } } } /************************************************************************* This function searches integer array. Elements in this array are actually records, each NRec elements wide. Each record has unique header - NHeader integer values, which identify it. Records are lexicographically sorted by header. Records are identified by their index, not offset (offset = NRec*index). This function searches A (records with indices [I0,I1)) for a record with header B. It returns index of this record (not offset!), or -1 on failure. -- ALGLIB -- Copyright 28.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t recsearch(/* Integer */ ae_vector* a, ae_int_t nrec, ae_int_t nheader, ae_int_t i0, ae_int_t i1, /* Integer */ ae_vector* b, ae_state *_state) { ae_int_t mididx; ae_int_t cflag; ae_int_t k; ae_int_t offs; ae_int_t result; result = -1; for(;;) { if( i0>=i1 ) { break; } mididx = (i0+i1)/2; offs = nrec*mididx; cflag = 0; for(k=0; k<=nheader-1; k++) { if( a->ptr.p_int[offs+k]ptr.p_int[k] ) { cflag = -1; break; } if( a->ptr.p_int[offs+k]>b->ptr.p_int[k] ) { cflag = 1; break; } } if( cflag==0 ) { result = mididx; return result; } if( cflag<0 ) { i0 = mididx+1; } else { i1 = mididx; } } return result; } /************************************************************************* This function is used in parallel functions for recurrent division of large task into two smaller tasks. It has following properties: * it works only for TaskSize>=2 (assertion is thrown otherwise) * for TaskSize=2, it returns Task0=1, Task1=1 * in case TaskSize is odd, Task0=TaskSize-1, Task1=1 * in case TaskSize is even, Task0 and Task1 are approximately TaskSize/2 and both Task0 and Task1 are even, Task0>=Task1 -- ALGLIB -- Copyright 07.04.2013 by Bochkanov Sergey *************************************************************************/ void splitlengtheven(ae_int_t tasksize, ae_int_t* task0, ae_int_t* task1, ae_state *_state) { *task0 = 0; *task1 = 0; ae_assert(tasksize>=2, "SplitLengthEven: TaskSize<2", _state); if( tasksize==2 ) { *task0 = 1; *task1 = 1; return; } if( tasksize%2==0 ) { /* * Even division */ *task0 = tasksize/2; *task1 = tasksize/2; if( *task0%2!=0 ) { *task0 = *task0+1; *task1 = *task1-1; } } else { /* * Odd task size, split trailing odd part from it. */ *task0 = tasksize-1; *task1 = 1; } ae_assert(*task0>=1, "SplitLengthEven: internal error", _state); ae_assert(*task1>=1, "SplitLengthEven: internal error", _state); } /************************************************************************* This function is used in parallel functions for recurrent division of large task into two smaller tasks. It has following properties: * it works only for TaskSize>=2 and ChunkSize>=2 (assertion is thrown otherwise) * Task0+Task1=TaskSize, Task0>0, Task1>0 * Task0 and Task1 are close to each other * in case TaskSize>ChunkSize, Task0 is always divisible by ChunkSize -- ALGLIB -- Copyright 07.04.2013 by Bochkanov Sergey *************************************************************************/ void splitlength(ae_int_t tasksize, ae_int_t chunksize, ae_int_t* task0, ae_int_t* task1, ae_state *_state) { *task0 = 0; *task1 = 0; ae_assert(chunksize>=2, "SplitLength: ChunkSize<2", _state); ae_assert(tasksize>=2, "SplitLength: TaskSize<2", _state); *task0 = tasksize/2; if( *task0>chunksize&&*task0%chunksize!=0 ) { *task0 = *task0-*task0%chunksize; } *task1 = tasksize-(*task0); ae_assert(*task0>=1, "SplitLength: internal error", _state); ae_assert(*task1>=1, "SplitLength: internal error", _state); } /************************************************************************* This function is used to calculate number of chunks (including partial, non-complete chunks) in some set. It expects that ChunkSize>=1, TaskSize>=0. Assertion is thrown otherwise. Function result is equivalent to Ceil(TaskSize/ChunkSize), but with guarantees that rounding errors won't ruin results. -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ ae_int_t chunkscount(ae_int_t tasksize, ae_int_t chunksize, ae_state *_state) { ae_int_t result; ae_assert(tasksize>=0, "ChunksCount: TaskSize<0", _state); ae_assert(chunksize>=1, "ChunksCount: ChunkSize<1", _state); result = tasksize/chunksize; if( tasksize%chunksize!=0 ) { result = result+1; } return result; } void _apbuffers_init(void* _p, ae_state *_state) { apbuffers *p = (apbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->ba0, 0, DT_BOOL, _state); ae_vector_init(&p->ia0, 0, DT_INT, _state); ae_vector_init(&p->ia1, 0, DT_INT, _state); ae_vector_init(&p->ia2, 0, DT_INT, _state); ae_vector_init(&p->ia3, 0, DT_INT, _state); ae_vector_init(&p->ra0, 0, DT_REAL, _state); ae_vector_init(&p->ra1, 0, DT_REAL, _state); ae_vector_init(&p->ra2, 0, DT_REAL, _state); ae_vector_init(&p->ra3, 0, DT_REAL, _state); ae_matrix_init(&p->rm0, 0, 0, DT_REAL, _state); ae_matrix_init(&p->rm1, 0, 0, DT_REAL, _state); } void _apbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { apbuffers *dst = (apbuffers*)_dst; apbuffers *src = (apbuffers*)_src; ae_vector_init_copy(&dst->ba0, &src->ba0, _state); ae_vector_init_copy(&dst->ia0, &src->ia0, _state); ae_vector_init_copy(&dst->ia1, &src->ia1, _state); ae_vector_init_copy(&dst->ia2, &src->ia2, _state); ae_vector_init_copy(&dst->ia3, &src->ia3, _state); ae_vector_init_copy(&dst->ra0, &src->ra0, _state); ae_vector_init_copy(&dst->ra1, &src->ra1, _state); ae_vector_init_copy(&dst->ra2, &src->ra2, _state); ae_vector_init_copy(&dst->ra3, &src->ra3, _state); ae_matrix_init_copy(&dst->rm0, &src->rm0, _state); ae_matrix_init_copy(&dst->rm1, &src->rm1, _state); } void _apbuffers_clear(void* _p) { apbuffers *p = (apbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->ba0); ae_vector_clear(&p->ia0); ae_vector_clear(&p->ia1); ae_vector_clear(&p->ia2); ae_vector_clear(&p->ia3); ae_vector_clear(&p->ra0); ae_vector_clear(&p->ra1); ae_vector_clear(&p->ra2); ae_vector_clear(&p->ra3); ae_matrix_clear(&p->rm0); ae_matrix_clear(&p->rm1); } void _apbuffers_destroy(void* _p) { apbuffers *p = (apbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->ba0); ae_vector_destroy(&p->ia0); ae_vector_destroy(&p->ia1); ae_vector_destroy(&p->ia2); ae_vector_destroy(&p->ia3); ae_vector_destroy(&p->ra0); ae_vector_destroy(&p->ra1); ae_vector_destroy(&p->ra2); ae_vector_destroy(&p->ra3); ae_matrix_destroy(&p->rm0); ae_matrix_destroy(&p->rm1); } void _sboolean_init(void* _p, ae_state *_state) { sboolean *p = (sboolean*)_p; ae_touch_ptr((void*)p); } void _sboolean_init_copy(void* _dst, void* _src, ae_state *_state) { sboolean *dst = (sboolean*)_dst; sboolean *src = (sboolean*)_src; dst->val = src->val; } void _sboolean_clear(void* _p) { sboolean *p = (sboolean*)_p; ae_touch_ptr((void*)p); } void _sboolean_destroy(void* _p) { sboolean *p = (sboolean*)_p; ae_touch_ptr((void*)p); } void _sbooleanarray_init(void* _p, ae_state *_state) { sbooleanarray *p = (sbooleanarray*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->val, 0, DT_BOOL, _state); } void _sbooleanarray_init_copy(void* _dst, void* _src, ae_state *_state) { sbooleanarray *dst = (sbooleanarray*)_dst; sbooleanarray *src = (sbooleanarray*)_src; ae_vector_init_copy(&dst->val, &src->val, _state); } void _sbooleanarray_clear(void* _p) { sbooleanarray *p = (sbooleanarray*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->val); } void _sbooleanarray_destroy(void* _p) { sbooleanarray *p = (sbooleanarray*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->val); } void _sinteger_init(void* _p, ae_state *_state) { sinteger *p = (sinteger*)_p; ae_touch_ptr((void*)p); } void _sinteger_init_copy(void* _dst, void* _src, ae_state *_state) { sinteger *dst = (sinteger*)_dst; sinteger *src = (sinteger*)_src; dst->val = src->val; } void _sinteger_clear(void* _p) { sinteger *p = (sinteger*)_p; ae_touch_ptr((void*)p); } void _sinteger_destroy(void* _p) { sinteger *p = (sinteger*)_p; ae_touch_ptr((void*)p); } void _sintegerarray_init(void* _p, ae_state *_state) { sintegerarray *p = (sintegerarray*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->val, 0, DT_INT, _state); } void _sintegerarray_init_copy(void* _dst, void* _src, ae_state *_state) { sintegerarray *dst = (sintegerarray*)_dst; sintegerarray *src = (sintegerarray*)_src; ae_vector_init_copy(&dst->val, &src->val, _state); } void _sintegerarray_clear(void* _p) { sintegerarray *p = (sintegerarray*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->val); } void _sintegerarray_destroy(void* _p) { sintegerarray *p = (sintegerarray*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->val); } void _sreal_init(void* _p, ae_state *_state) { sreal *p = (sreal*)_p; ae_touch_ptr((void*)p); } void _sreal_init_copy(void* _dst, void* _src, ae_state *_state) { sreal *dst = (sreal*)_dst; sreal *src = (sreal*)_src; dst->val = src->val; } void _sreal_clear(void* _p) { sreal *p = (sreal*)_p; ae_touch_ptr((void*)p); } void _sreal_destroy(void* _p) { sreal *p = (sreal*)_p; ae_touch_ptr((void*)p); } void _srealarray_init(void* _p, ae_state *_state) { srealarray *p = (srealarray*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->val, 0, DT_REAL, _state); } void _srealarray_init_copy(void* _dst, void* _src, ae_state *_state) { srealarray *dst = (srealarray*)_dst; srealarray *src = (srealarray*)_src; ae_vector_init_copy(&dst->val, &src->val, _state); } void _srealarray_clear(void* _p) { srealarray *p = (srealarray*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->val); } void _srealarray_destroy(void* _p) { srealarray *p = (srealarray*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->val); } void _scomplex_init(void* _p, ae_state *_state) { scomplex *p = (scomplex*)_p; ae_touch_ptr((void*)p); } void _scomplex_init_copy(void* _dst, void* _src, ae_state *_state) { scomplex *dst = (scomplex*)_dst; scomplex *src = (scomplex*)_src; dst->val = src->val; } void _scomplex_clear(void* _p) { scomplex *p = (scomplex*)_p; ae_touch_ptr((void*)p); } void _scomplex_destroy(void* _p) { scomplex *p = (scomplex*)_p; ae_touch_ptr((void*)p); } void _scomplexarray_init(void* _p, ae_state *_state) { scomplexarray *p = (scomplexarray*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->val, 0, DT_COMPLEX, _state); } void _scomplexarray_init_copy(void* _dst, void* _src, ae_state *_state) { scomplexarray *dst = (scomplexarray*)_dst; scomplexarray *src = (scomplexarray*)_src; ae_vector_init_copy(&dst->val, &src->val, _state); } void _scomplexarray_clear(void* _p) { scomplexarray *p = (scomplexarray*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->val); } void _scomplexarray_destroy(void* _p) { scomplexarray *p = (scomplexarray*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->val); } ae_int_t getrdfserializationcode(ae_state *_state) { ae_int_t result; result = 1; return result; } ae_int_t getkdtreeserializationcode(ae_state *_state) { ae_int_t result; result = 2; return result; } ae_int_t getmlpserializationcode(ae_state *_state) { ae_int_t result; result = 3; return result; } ae_int_t getmlpeserializationcode(ae_state *_state) { ae_int_t result; result = 4; return result; } ae_int_t getrbfserializationcode(ae_state *_state) { ae_int_t result; result = 5; return result; } /************************************************************************* This function sorts array of real keys by ascending. Its results are: * sorted array A * permutation tables P1, P2 Algorithm outputs permutation tables using two formats: * as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i] contains value which was moved there from J-th position. * as a sequence of pairwise permutations. Sorted A[] may be obtained by swaping A[i] and A[P2[i]] for all i from 0 to N-1. INPUT PARAMETERS: A - unsorted array N - array size OUPUT PARAMETERS: A - sorted array P1, P2 - permutation tables, array[N] NOTES: this function assumes that A[] is finite; it doesn't checks that condition. All other conditions (size of input arrays, etc.) are not checked too. -- ALGLIB -- Copyright 14.05.2008 by Bochkanov Sergey *************************************************************************/ void tagsort(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, ae_state *_state) { ae_frame _frame_block; apbuffers buf; ae_frame_make(_state, &_frame_block); ae_vector_clear(p1); ae_vector_clear(p2); _apbuffers_init(&buf, _state); tagsortbuf(a, n, p1, p2, &buf, _state); ae_frame_leave(_state); } /************************************************************************* Buffered variant of TagSort, which accepts preallocated output arrays as well as special structure for buffered allocations. If arrays are too short, they are reallocated. If they are large enough, no memory allocation is done. It is intended to be used in the performance-critical parts of code, where additional allocations can lead to severe performance degradation -- ALGLIB -- Copyright 14.05.2008 by Bochkanov Sergey *************************************************************************/ void tagsortbuf(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, apbuffers* buf, ae_state *_state) { ae_int_t i; ae_int_t lv; ae_int_t lp; ae_int_t rv; ae_int_t rp; /* * Special cases */ if( n<=0 ) { return; } if( n==1 ) { ivectorsetlengthatleast(p1, 1, _state); ivectorsetlengthatleast(p2, 1, _state); p1->ptr.p_int[0] = 0; p2->ptr.p_int[0] = 0; return; } /* * General case, N>1: prepare permutations table P1 */ ivectorsetlengthatleast(p1, n, _state); for(i=0; i<=n-1; i++) { p1->ptr.p_int[i] = i; } /* * General case, N>1: sort, update P1 */ rvectorsetlengthatleast(&buf->ra0, n, _state); ivectorsetlengthatleast(&buf->ia0, n, _state); tagsortfasti(a, p1, &buf->ra0, &buf->ia0, n, _state); /* * General case, N>1: fill permutations table P2 * * To fill P2 we maintain two arrays: * * PV (Buf.IA0), Position(Value). PV[i] contains position of I-th key at the moment * * VP (Buf.IA1), Value(Position). VP[i] contains key which has position I at the moment * * At each step we making permutation of two items: * Left, which is given by position/value pair LP/LV * and Right, which is given by RP/RV * and updating PV[] and VP[] correspondingly. */ ivectorsetlengthatleast(&buf->ia0, n, _state); ivectorsetlengthatleast(&buf->ia1, n, _state); ivectorsetlengthatleast(p2, n, _state); for(i=0; i<=n-1; i++) { buf->ia0.ptr.p_int[i] = i; buf->ia1.ptr.p_int[i] = i; } for(i=0; i<=n-1; i++) { /* * calculate LP, LV, RP, RV */ lp = i; lv = buf->ia1.ptr.p_int[lp]; rv = p1->ptr.p_int[i]; rp = buf->ia0.ptr.p_int[rv]; /* * Fill P2 */ p2->ptr.p_int[i] = rp; /* * update PV and VP */ buf->ia1.ptr.p_int[lp] = rv; buf->ia1.ptr.p_int[rp] = lv; buf->ia0.ptr.p_int[lv] = rp; buf->ia0.ptr.p_int[rv] = lp; } } /************************************************************************* Same as TagSort, but optimized for real keys and integer labels. A is sorted, and same permutations are applied to B. NOTES: 1. this function assumes that A[] is finite; it doesn't checks that condition. All other conditions (size of input arrays, etc.) are not checked too. 2. this function uses two buffers, BufA and BufB, each is N elements large. They may be preallocated (which will save some time) or not, in which case function will automatically allocate memory. -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/ void tagsortfasti(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, /* Real */ ae_vector* bufa, /* Integer */ ae_vector* bufb, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool isascending; ae_bool isdescending; double tmpr; ae_int_t tmpi; /* * Special case */ if( n<=1 ) { return; } /* * Test for already sorted set */ isascending = ae_true; isdescending = ae_true; for(i=1; i<=n-1; i++) { isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1]; isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; } if( isascending ) { return; } if( isdescending ) { for(i=0; i<=n-1; i++) { j = n-1-i; if( j<=i ) { break; } tmpr = a->ptr.p_double[i]; a->ptr.p_double[i] = a->ptr.p_double[j]; a->ptr.p_double[j] = tmpr; tmpi = b->ptr.p_int[i]; b->ptr.p_int[i] = b->ptr.p_int[j]; b->ptr.p_int[j] = tmpi; } return; } /* * General case */ if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; } if( isascending ) { return; } if( isdescending ) { for(i=0; i<=n-1; i++) { j = n-1-i; if( j<=i ) { break; } tmpr = a->ptr.p_double[i]; a->ptr.p_double[i] = a->ptr.p_double[j]; a->ptr.p_double[j] = tmpr; tmpr = b->ptr.p_double[i]; b->ptr.p_double[i] = b->ptr.p_double[j]; b->ptr.p_double[j] = tmpr; } return; } /* * General case */ if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; } if( isascending ) { return; } if( isdescending ) { for(i=0; i<=n-1; i++) { j = n-1-i; if( j<=i ) { break; } tmpr = a->ptr.p_double[i]; a->ptr.p_double[i] = a->ptr.p_double[j]; a->ptr.p_double[j] = tmpr; } return; } /* * General case */ if( bufa->cnt1: sort, update B */ i = 2; do { t = i; while(t!=1) { k = t/2; if( a->ptr.p_int[offset+k-1]>=a->ptr.p_int[offset+t-1] ) { t = 1; } else { tmp = a->ptr.p_int[offset+k-1]; a->ptr.p_int[offset+k-1] = a->ptr.p_int[offset+t-1]; a->ptr.p_int[offset+t-1] = tmp; tmpr = b->ptr.p_double[offset+k-1]; b->ptr.p_double[offset+k-1] = b->ptr.p_double[offset+t-1]; b->ptr.p_double[offset+t-1] = tmpr; t = k; } } i = i+1; } while(i<=n); i = n-1; do { tmp = a->ptr.p_int[offset+i]; a->ptr.p_int[offset+i] = a->ptr.p_int[offset+0]; a->ptr.p_int[offset+0] = tmp; tmpr = b->ptr.p_double[offset+i]; b->ptr.p_double[offset+i] = b->ptr.p_double[offset+0]; b->ptr.p_double[offset+0] = tmpr; t = 1; while(t!=0) { k = 2*t; if( k>i ) { t = 0; } else { if( kptr.p_int[offset+k]>a->ptr.p_int[offset+k-1] ) { k = k+1; } } if( a->ptr.p_int[offset+t-1]>=a->ptr.p_int[offset+k-1] ) { t = 0; } else { tmp = a->ptr.p_int[offset+k-1]; a->ptr.p_int[offset+k-1] = a->ptr.p_int[offset+t-1]; a->ptr.p_int[offset+t-1] = tmp; tmpr = b->ptr.p_double[offset+k-1]; b->ptr.p_double[offset+k-1] = b->ptr.p_double[offset+t-1]; b->ptr.p_double[offset+t-1] = tmpr; t = k; } } } i = i-1; } while(i>=1); } /************************************************************************* Heap operations: adds element to the heap PARAMETERS: A - heap itself, must be at least array[0..N] B - array of integer tags, which are updated according to permutations in the heap N - size of the heap (without new element). updated on output VA - value of the element being added VB - value of the tag -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void tagheappushi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t* n, double va, ae_int_t vb, ae_state *_state) { ae_int_t j; ae_int_t k; double v; if( *n<0 ) { return; } /* * N=0 is a special case */ if( *n==0 ) { a->ptr.p_double[0] = va; b->ptr.p_int[0] = vb; *n = *n+1; return; } /* * add current point to the heap * (add to the bottom, then move up) * * we don't write point to the heap * until its final position is determined * (it allow us to reduce number of array access operations) */ j = *n; *n = *n+1; while(j>0) { k = (j-1)/2; v = a->ptr.p_double[k]; if( ae_fp_less(v,va) ) { /* * swap with higher element */ a->ptr.p_double[j] = v; b->ptr.p_int[j] = b->ptr.p_int[k]; j = k; } else { /* * element in its place. terminate. */ break; } } a->ptr.p_double[j] = va; b->ptr.p_int[j] = vb; } /************************************************************************* Heap operations: replaces top element with new element (which is moved down) PARAMETERS: A - heap itself, must be at least array[0..N-1] B - array of integer tags, which are updated according to permutations in the heap N - size of the heap VA - value of the element which replaces top element VB - value of the tag -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void tagheapreplacetopi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t n, double va, ae_int_t vb, ae_state *_state) { ae_int_t j; ae_int_t k1; ae_int_t k2; double v; double v1; double v2; if( n<1 ) { return; } /* * N=1 is a special case */ if( n==1 ) { a->ptr.p_double[0] = va; b->ptr.p_int[0] = vb; return; } /* * move down through heap: * * J - current element * * K1 - first child (always exists) * * K2 - second child (may not exists) * * we don't write point to the heap * until its final position is determined * (it allow us to reduce number of array access operations) */ j = 0; k1 = 1; k2 = 2; while(k1=n ) { /* * only one child. * * swap and terminate (because this child * have no siblings due to heap structure) */ v = a->ptr.p_double[k1]; if( ae_fp_greater(v,va) ) { a->ptr.p_double[j] = v; b->ptr.p_int[j] = b->ptr.p_int[k1]; j = k1; } break; } else { /* * two childs */ v1 = a->ptr.p_double[k1]; v2 = a->ptr.p_double[k2]; if( ae_fp_greater(v1,v2) ) { if( ae_fp_less(va,v1) ) { a->ptr.p_double[j] = v1; b->ptr.p_int[j] = b->ptr.p_int[k1]; j = k1; } else { break; } } else { if( ae_fp_less(va,v2) ) { a->ptr.p_double[j] = v2; b->ptr.p_int[j] = b->ptr.p_int[k2]; j = k2; } else { break; } } k1 = 2*j+1; k2 = 2*j+2; } } a->ptr.p_double[j] = va; b->ptr.p_int[j] = vb; } /************************************************************************* Heap operations: pops top element from the heap PARAMETERS: A - heap itself, must be at least array[0..N-1] B - array of integer tags, which are updated according to permutations in the heap N - size of the heap, N>=1 On output top element is moved to A[N-1], B[N-1], heap is reordered, N is decreased by 1. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void tagheappopi(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t* n, ae_state *_state) { double va; ae_int_t vb; if( *n<1 ) { return; } /* * N=1 is a special case */ if( *n==1 ) { *n = 0; return; } /* * swap top element and last element, * then reorder heap */ va = a->ptr.p_double[*n-1]; vb = b->ptr.p_int[*n-1]; a->ptr.p_double[*n-1] = a->ptr.p_double[0]; b->ptr.p_int[*n-1] = b->ptr.p_int[0]; *n = *n-1; tagheapreplacetopi(a, b, *n, va, vb, _state); } /************************************************************************* Search first element less than T in sorted array. PARAMETERS: A - sorted array by ascending from 0 to N-1 N - number of elements in array T - the desired element RESULT: The very first element's index, which isn't less than T. In the case when there aren't such elements, returns N. *************************************************************************/ ae_int_t lowerbound(/* Real */ ae_vector* a, ae_int_t n, double t, ae_state *_state) { ae_int_t l; ae_int_t half; ae_int_t first; ae_int_t middle; ae_int_t result; l = n; first = 0; while(l>0) { half = l/2; middle = first+half; if( ae_fp_less(a->ptr.p_double[middle],t) ) { first = middle+1; l = l-half-1; } else { l = half; } } result = first; return result; } /************************************************************************* Search first element more than T in sorted array. PARAMETERS: A - sorted array by ascending from 0 to N-1 N - number of elements in array T - the desired element RESULT: The very first element's index, which more than T. In the case when there aren't such elements, returns N. *************************************************************************/ ae_int_t upperbound(/* Real */ ae_vector* a, ae_int_t n, double t, ae_state *_state) { ae_int_t l; ae_int_t half; ae_int_t first; ae_int_t middle; ae_int_t result; l = n; first = 0; while(l>0) { half = l/2; middle = first+half; if( ae_fp_less(t,a->ptr.p_double[middle]) ) { l = half; } else { first = middle+1; l = l-half-1; } } result = first; return result; } /************************************************************************* Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), applies same permutations to B. -- ALGLIB -- Copyright 06.09.2010 by Bochkanov Sergey *************************************************************************/ static void tsort_tagsortfastirec(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, /* Real */ ae_vector* bufa, /* Integer */ ae_vector* bufb, ae_int_t i1, ae_int_t i2, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t cntless; ae_int_t cnteq; ae_int_t cntgreater; double tmpr; ae_int_t tmpi; double v0; double v1; double v2; double vp; /* * Fast exit */ if( i2<=i1 ) { return; } /* * Non-recursive sort for small arrays */ if( i2-i1<=16 ) { for(j=i1+1; j<=i2; j++) { /* * Search elements [I1..J-1] for place to insert Jth element. * * This code stops immediately if we can leave A[J] at J-th position * (all elements have same value of A[J] larger than any of them) */ tmpr = a->ptr.p_double[j]; tmpi = j; for(k=j-1; k>=i1; k--) { if( a->ptr.p_double[k]<=tmpr ) { break; } tmpi = k; } k = tmpi; /* * Insert Jth element into Kth position */ if( k!=j ) { tmpr = a->ptr.p_double[j]; tmpi = b->ptr.p_int[j]; for(i=j-1; i>=k; i--) { a->ptr.p_double[i+1] = a->ptr.p_double[i]; b->ptr.p_int[i+1] = b->ptr.p_int[i]; } a->ptr.p_double[k] = tmpr; b->ptr.p_int[k] = tmpi; } } return; } /* * Quicksort: choose pivot * Here we assume that I2-I1>=2 */ v0 = a->ptr.p_double[i1]; v1 = a->ptr.p_double[i1+(i2-i1)/2]; v2 = a->ptr.p_double[i2]; if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } if( v1>v2 ) { tmpr = v2; v2 = v1; v1 = tmpr; } if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } vp = v1; /* * now pass through A/B and: * * move elements that are LESS than VP to the left of A/B * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) * * move elements from the left of BufA/BufB to the end of A/B */ cntless = 0; cnteq = 0; cntgreater = 0; for(i=i1; i<=i2; i++) { v0 = a->ptr.p_double[i]; if( v0ptr.p_double[k] = v0; b->ptr.p_int[k] = b->ptr.p_int[i]; } cntless = cntless+1; continue; } if( v0==vp ) { /* * EQUAL */ k = i2-cnteq; bufa->ptr.p_double[k] = v0; bufb->ptr.p_int[k] = b->ptr.p_int[i]; cnteq = cnteq+1; continue; } /* * GREATER */ k = i1+cntgreater; bufa->ptr.p_double[k] = v0; bufb->ptr.p_int[k] = b->ptr.p_int[i]; cntgreater = cntgreater+1; } for(i=0; i<=cnteq-1; i++) { j = i1+cntless+cnteq-1-i; k = i2+i-(cnteq-1); a->ptr.p_double[j] = bufa->ptr.p_double[k]; b->ptr.p_int[j] = bufb->ptr.p_int[k]; } for(i=0; i<=cntgreater-1; i++) { j = i1+cntless+cnteq+i; k = i1+i; a->ptr.p_double[j] = bufa->ptr.p_double[k]; b->ptr.p_int[j] = bufb->ptr.p_int[k]; } /* * Sort left and right parts of the array (ignoring middle part) */ tsort_tagsortfastirec(a, b, bufa, bufb, i1, i1+cntless-1, _state); tsort_tagsortfastirec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); } /************************************************************************* Internal TagSortFastR: sorts A[I1...I2] (both bounds are included), applies same permutations to B. -- ALGLIB -- Copyright 06.09.2010 by Bochkanov Sergey *************************************************************************/ static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* bufa, /* Real */ ae_vector* bufb, ae_int_t i1, ae_int_t i2, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double tmpr; double tmpr2; ae_int_t tmpi; ae_int_t cntless; ae_int_t cnteq; ae_int_t cntgreater; double v0; double v1; double v2; double vp; /* * Fast exit */ if( i2<=i1 ) { return; } /* * Non-recursive sort for small arrays */ if( i2-i1<=16 ) { for(j=i1+1; j<=i2; j++) { /* * Search elements [I1..J-1] for place to insert Jth element. * * This code stops immediatly if we can leave A[J] at J-th position * (all elements have same value of A[J] larger than any of them) */ tmpr = a->ptr.p_double[j]; tmpi = j; for(k=j-1; k>=i1; k--) { if( a->ptr.p_double[k]<=tmpr ) { break; } tmpi = k; } k = tmpi; /* * Insert Jth element into Kth position */ if( k!=j ) { tmpr = a->ptr.p_double[j]; tmpr2 = b->ptr.p_double[j]; for(i=j-1; i>=k; i--) { a->ptr.p_double[i+1] = a->ptr.p_double[i]; b->ptr.p_double[i+1] = b->ptr.p_double[i]; } a->ptr.p_double[k] = tmpr; b->ptr.p_double[k] = tmpr2; } } return; } /* * Quicksort: choose pivot * Here we assume that I2-I1>=16 */ v0 = a->ptr.p_double[i1]; v1 = a->ptr.p_double[i1+(i2-i1)/2]; v2 = a->ptr.p_double[i2]; if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } if( v1>v2 ) { tmpr = v2; v2 = v1; v1 = tmpr; } if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } vp = v1; /* * now pass through A/B and: * * move elements that are LESS than VP to the left of A/B * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) * * move elements from the left of BufA/BufB to the end of A/B */ cntless = 0; cnteq = 0; cntgreater = 0; for(i=i1; i<=i2; i++) { v0 = a->ptr.p_double[i]; if( v0ptr.p_double[k] = v0; b->ptr.p_double[k] = b->ptr.p_double[i]; } cntless = cntless+1; continue; } if( v0==vp ) { /* * EQUAL */ k = i2-cnteq; bufa->ptr.p_double[k] = v0; bufb->ptr.p_double[k] = b->ptr.p_double[i]; cnteq = cnteq+1; continue; } /* * GREATER */ k = i1+cntgreater; bufa->ptr.p_double[k] = v0; bufb->ptr.p_double[k] = b->ptr.p_double[i]; cntgreater = cntgreater+1; } for(i=0; i<=cnteq-1; i++) { j = i1+cntless+cnteq-1-i; k = i2+i-(cnteq-1); a->ptr.p_double[j] = bufa->ptr.p_double[k]; b->ptr.p_double[j] = bufb->ptr.p_double[k]; } for(i=0; i<=cntgreater-1; i++) { j = i1+cntless+cnteq+i; k = i1+i; a->ptr.p_double[j] = bufa->ptr.p_double[k]; b->ptr.p_double[j] = bufb->ptr.p_double[k]; } /* * Sort left and right parts of the array (ignoring middle part) */ tsort_tagsortfastrrec(a, b, bufa, bufb, i1, i1+cntless-1, _state); tsort_tagsortfastrrec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); } /************************************************************************* Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), applies same permutations to B. -- ALGLIB -- Copyright 06.09.2010 by Bochkanov Sergey *************************************************************************/ static void tsort_tagsortfastrec(/* Real */ ae_vector* a, /* Real */ ae_vector* bufa, ae_int_t i1, ae_int_t i2, ae_state *_state) { ae_int_t cntless; ae_int_t cnteq; ae_int_t cntgreater; ae_int_t i; ae_int_t j; ae_int_t k; double tmpr; ae_int_t tmpi; double v0; double v1; double v2; double vp; /* * Fast exit */ if( i2<=i1 ) { return; } /* * Non-recursive sort for small arrays */ if( i2-i1<=16 ) { for(j=i1+1; j<=i2; j++) { /* * Search elements [I1..J-1] for place to insert Jth element. * * This code stops immediatly if we can leave A[J] at J-th position * (all elements have same value of A[J] larger than any of them) */ tmpr = a->ptr.p_double[j]; tmpi = j; for(k=j-1; k>=i1; k--) { if( a->ptr.p_double[k]<=tmpr ) { break; } tmpi = k; } k = tmpi; /* * Insert Jth element into Kth position */ if( k!=j ) { tmpr = a->ptr.p_double[j]; for(i=j-1; i>=k; i--) { a->ptr.p_double[i+1] = a->ptr.p_double[i]; } a->ptr.p_double[k] = tmpr; } } return; } /* * Quicksort: choose pivot * Here we assume that I2-I1>=16 */ v0 = a->ptr.p_double[i1]; v1 = a->ptr.p_double[i1+(i2-i1)/2]; v2 = a->ptr.p_double[i2]; if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } if( v1>v2 ) { tmpr = v2; v2 = v1; v1 = tmpr; } if( v0>v1 ) { tmpr = v1; v1 = v0; v0 = tmpr; } vp = v1; /* * now pass through A/B and: * * move elements that are LESS than VP to the left of A/B * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) * * move elements from the left of BufA/BufB to the end of A/B */ cntless = 0; cnteq = 0; cntgreater = 0; for(i=i1; i<=i2; i++) { v0 = a->ptr.p_double[i]; if( v0ptr.p_double[k] = v0; } cntless = cntless+1; continue; } if( v0==vp ) { /* * EQUAL */ k = i2-cnteq; bufa->ptr.p_double[k] = v0; cnteq = cnteq+1; continue; } /* * GREATER */ k = i1+cntgreater; bufa->ptr.p_double[k] = v0; cntgreater = cntgreater+1; } for(i=0; i<=cnteq-1; i++) { j = i1+cntless+cnteq-1-i; k = i2+i-(cnteq-1); a->ptr.p_double[j] = bufa->ptr.p_double[k]; } for(i=0; i<=cntgreater-1; i++) { j = i1+cntless+cnteq+i; k = i1+i; a->ptr.p_double[j] = bufa->ptr.p_double[k]; } /* * Sort left and right parts of the array (ignoring middle part) */ tsort_tagsortfastrec(a, bufa, i1, i1+cntless-1, _state); tsort_tagsortfastrec(a, bufa, i1+cntless+cnteq, i2, _state); } /************************************************************************* Internal ranking subroutine. INPUT PARAMETERS: X - array to rank N - array size IsCentered- whether ranks are centered or not: * True - ranks are centered in such way that their sum is zero * False - ranks are not centered Buf - temporary buffers NOTE: when IsCentered is True and all X[] are equal, this function fills X by zeros (exact zeros are used, not sum which is only approximately equal to zero). *************************************************************************/ void rankx(/* Real */ ae_vector* x, ae_int_t n, ae_bool iscentered, apbuffers* buf, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double tmp; double voffs; /* * Prepare */ if( n<1 ) { return; } if( n==1 ) { x->ptr.p_double[0] = (double)(0); return; } if( buf->ra1.cntra1, n, _state); } if( buf->ia1.cntia1, n, _state); } for(i=0; i<=n-1; i++) { buf->ra1.ptr.p_double[i] = x->ptr.p_double[i]; buf->ia1.ptr.p_int[i] = i; } tagsortfasti(&buf->ra1, &buf->ia1, &buf->ra2, &buf->ia2, n, _state); /* * Special test for all values being equal */ if( ae_fp_eq(buf->ra1.ptr.p_double[0],buf->ra1.ptr.p_double[n-1]) ) { if( iscentered ) { tmp = 0.0; } else { tmp = (double)(n-1)/(double)2; } for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = tmp; } return; } /* * compute tied ranks */ i = 0; while(i<=n-1) { j = i+1; while(j<=n-1) { if( ae_fp_neq(buf->ra1.ptr.p_double[j],buf->ra1.ptr.p_double[i]) ) { break; } j = j+1; } for(k=i; k<=j-1; k++) { buf->ra1.ptr.p_double[k] = (double)(i+j-1)/(double)2; } i = j; } /* * back to x */ if( iscentered ) { voffs = (double)(n-1)/(double)2; } else { voffs = 0.0; } for(i=0; i<=n-1; i++) { x->ptr.p_double[buf->ia1.ptr.p_int[i]] = buf->ra1.ptr.p_double[i]-voffs; } } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixrank1f(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_vector* u, ae_int_t iu, /* Complex */ ae_vector* v, ae_int_t iv, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixrank1f(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_vector* u, ae_int_t iu, /* Real */ ae_vector* v, ae_int_t iv, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixmvf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Complex */ ae_vector* x, ae_int_t ix, /* Complex */ ae_vector* y, ae_int_t iy, ae_state *_state) { ae_bool result; result = ae_false; return result; } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixmvf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Real */ ae_vector* x, ae_int_t ix, /* Real */ ae_vector* y, ae_int_t iy, ae_state *_state) { ae_bool result; result = ae_false; return result; } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixrighttrsmf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixlefttrsmf(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixrighttrsmf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixlefttrsmf(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixherkf(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixherkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixsyrkf(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); #endif } /************************************************************************* Fast kernel -- ALGLIB routine -- 19.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixgemmf(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_ABLAS ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); #endif } /************************************************************************* CMatrixGEMM kernel, basecase code for CMatrixGEMM. This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition, conjugate transposition Additional info: * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void cmatrixgemmk(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex v; ae_complex v00; ae_complex v01; ae_complex v10; ae_complex v11; double v00x; double v00y; double v01x; double v01y; double v10x; double v10y; double v11x; double v11y; double a0x; double a0y; double a1x; double a1y; double b0x; double b0y; double b1x; double b1y; ae_int_t idxa0; ae_int_t idxa1; ae_int_t idxb0; ae_int_t idxb1; ae_int_t i0; ae_int_t i1; ae_int_t ik; ae_int_t j0; ae_int_t j1; ae_int_t jk; ae_int_t t; ae_int_t offsa; ae_int_t offsb; /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * Try optimized code */ if( cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) { return; } /* * if K=0, then C=Beta*C */ if( k==0 ) { if( ae_c_neq_d(beta,(double)(1)) ) { if( ae_c_neq_d(beta,(double)(0)) ) { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul(beta,c->ptr.pp_complex[ic+i][jc+j]); } } } else { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_i(0); } } } } return; } /* * This phase is not really necessary, but compiler complains * about "possibly uninitialized variables" */ a0x = (double)(0); a0y = (double)(0); a1x = (double)(0); a1y = (double)(0); b0x = (double)(0); b0y = (double)(0); b1x = (double)(0); b1y = (double)(0); /* * General case */ i = 0; while(iptr.pp_complex[idxa0][offsa].x; a0y = a->ptr.pp_complex[idxa0][offsa].y; a1x = a->ptr.pp_complex[idxa1][offsa].x; a1y = a->ptr.pp_complex[idxa1][offsa].y; } if( optypea==1 ) { a0x = a->ptr.pp_complex[offsa][idxa0].x; a0y = a->ptr.pp_complex[offsa][idxa0].y; a1x = a->ptr.pp_complex[offsa][idxa1].x; a1y = a->ptr.pp_complex[offsa][idxa1].y; } if( optypea==2 ) { a0x = a->ptr.pp_complex[offsa][idxa0].x; a0y = -a->ptr.pp_complex[offsa][idxa0].y; a1x = a->ptr.pp_complex[offsa][idxa1].x; a1y = -a->ptr.pp_complex[offsa][idxa1].y; } if( optypeb==0 ) { b0x = b->ptr.pp_complex[offsb][idxb0].x; b0y = b->ptr.pp_complex[offsb][idxb0].y; b1x = b->ptr.pp_complex[offsb][idxb1].x; b1y = b->ptr.pp_complex[offsb][idxb1].y; } if( optypeb==1 ) { b0x = b->ptr.pp_complex[idxb0][offsb].x; b0y = b->ptr.pp_complex[idxb0][offsb].y; b1x = b->ptr.pp_complex[idxb1][offsb].x; b1y = b->ptr.pp_complex[idxb1][offsb].y; } if( optypeb==2 ) { b0x = b->ptr.pp_complex[idxb0][offsb].x; b0y = -b->ptr.pp_complex[idxb0][offsb].y; b1x = b->ptr.pp_complex[idxb1][offsb].x; b1y = -b->ptr.pp_complex[idxb1][offsb].y; } v00x = v00x+a0x*b0x-a0y*b0y; v00y = v00y+a0x*b0y+a0y*b0x; v01x = v01x+a0x*b1x-a0y*b1y; v01y = v01y+a0x*b1y+a0y*b1x; v10x = v10x+a1x*b0x-a1y*b0y; v10y = v10y+a1x*b0y+a1y*b0x; v11x = v11x+a1x*b1x-a1y*b1y; v11y = v11y+a1x*b1y+a1y*b1x; offsa = offsa+1; offsb = offsb+1; } v00.x = v00x; v00.y = v00y; v10.x = v10x; v10.y = v10y; v01.x = v01x; v01.y = v01y; v11.x = v11x; v11.y = v11y; if( ae_c_eq_d(beta,(double)(0)) ) { c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_mul(alpha,v00); c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_mul(alpha,v01); c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_mul(alpha,v10); c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_mul(alpha,v11); } else { c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+0]),ae_c_mul(alpha,v00)); c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+1]),ae_c_mul(alpha,v01)); c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+0]),ae_c_mul(alpha,v10)); c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+1]),ae_c_mul(alpha,v11)); } } else { /* * Determine submatrix [I0..I1]x[J0..J1] to process */ i0 = i; i1 = ae_minint(i+1, m-1, _state); j0 = j; j1 = ae_minint(j+1, n-1, _state); /* * Process submatrix */ for(ik=i0; ik<=i1; ik++) { for(jk=j0; jk<=j1; jk++) { if( k==0||ae_c_eq_d(alpha,(double)(0)) ) { v = ae_complex_from_i(0); } else { v = ae_complex_from_d(0.0); if( optypea==0&&optypeb==0 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ja,ja+k-1)); } if( optypea==0&&optypeb==1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ja,ja+k-1)); } if( optypea==0&&optypeb==2 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ja,ja+k-1)); } if( optypea==1&&optypeb==0 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); } if( optypea==1&&optypeb==1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); } if( optypea==1&&optypeb==2 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); } if( optypea==2&&optypeb==0 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); } if( optypea==2&&optypeb==1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); } if( optypea==2&&optypeb==2 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); } } if( ae_c_eq_d(beta,(double)(0)) ) { c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_mul(alpha,v); } else { c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+ik][jc+jk]),ae_c_mul(alpha,v)); } } } } j = j+2; } i = i+2; } } /************************************************************************* RMatrixGEMM kernel, basecase code for RMatrixGEMM. This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition Additional info: * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemmk(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * Try optimized code */ if( rmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) { return; } /* * if K=0, then C=Beta*C */ if( k==0||ae_fp_eq(alpha,(double)(0)) ) { if( ae_fp_neq(beta,(double)(1)) ) { if( ae_fp_neq(beta,(double)(0)) ) { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]; } } } else { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { c->ptr.pp_double[ic+i][jc+j] = (double)(0); } } } } return; } /* * Call specialized code. * * NOTE: specialized code was moved to separate function because of strange * issues with instructions cache on some systems; Having too long * functions significantly slows down internal loop of the algorithm. */ if( optypea==0&&optypeb==0 ) { rmatrixgemmk44v00(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); } if( optypea==0&&optypeb!=0 ) { rmatrixgemmk44v01(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); } if( optypea!=0&&optypeb==0 ) { rmatrixgemmk44v10(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); } if( optypea!=0&&optypeb!=0 ) { rmatrixgemmk44v11(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); } } /************************************************************************* RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation with OpTypeA=0 and OpTypeB=0. Additional info: * this function requires that Alpha<>0 (assertion is thrown otherwise) INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset B - matrix IB - submatrix offset JB - submatrix offset Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemmk44v00(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double v00; double v01; double v02; double v03; double v10; double v11; double v12; double v13; double v20; double v21; double v22; double v23; double v30; double v31; double v32; double v33; double a0; double a1; double a2; double a3; double b0; double b1; double b2; double b3; ae_int_t idxa0; ae_int_t idxa1; ae_int_t idxa2; ae_int_t idxa3; ae_int_t idxb0; ae_int_t idxb1; ae_int_t idxb2; ae_int_t idxb3; ae_int_t i0; ae_int_t i1; ae_int_t ik; ae_int_t j0; ae_int_t j1; ae_int_t jk; ae_int_t t; ae_int_t offsa; ae_int_t offsb; ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * A*B */ i = 0; while(iptr.pp_double[idxa0][offsa]; a1 = a->ptr.pp_double[idxa1][offsa]; b0 = b->ptr.pp_double[offsb][idxb0]; b1 = b->ptr.pp_double[offsb][idxb1]; v00 = v00+a0*b0; v01 = v01+a0*b1; v10 = v10+a1*b0; v11 = v11+a1*b1; a2 = a->ptr.pp_double[idxa2][offsa]; a3 = a->ptr.pp_double[idxa3][offsa]; v20 = v20+a2*b0; v21 = v21+a2*b1; v30 = v30+a3*b0; v31 = v31+a3*b1; b2 = b->ptr.pp_double[offsb][idxb2]; b3 = b->ptr.pp_double[offsb][idxb3]; v22 = v22+a2*b2; v23 = v23+a2*b3; v32 = v32+a3*b2; v33 = v33+a3*b3; v02 = v02+a0*b2; v03 = v03+a0*b3; v12 = v12+a1*b2; v13 = v13+a1*b3; offsa = offsa+1; offsb = offsb+1; } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; } else { c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; } } else { /* * Determine submatrix [I0..I1]x[J0..J1] to process */ i0 = i; i1 = ae_minint(i+3, m-1, _state); j0 = j; j1 = ae_minint(j+3, n-1, _state); /* * Process submatrix */ for(ik=i0; ik<=i1; ik++) { for(jk=j0; jk<=j1; jk++) { if( k==0||ae_fp_eq(alpha,(double)(0)) ) { v = (double)(0); } else { v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ja,ja+k-1)); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; } else { c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; } } } } j = j+4; } i = i+4; } } /************************************************************************* RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation with OpTypeA=0 and OpTypeB=1. Additional info: * this function requires that Alpha<>0 (assertion is thrown otherwise) INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset B - matrix IB - submatrix offset JB - submatrix offset Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemmk44v01(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double v00; double v01; double v02; double v03; double v10; double v11; double v12; double v13; double v20; double v21; double v22; double v23; double v30; double v31; double v32; double v33; double a0; double a1; double a2; double a3; double b0; double b1; double b2; double b3; ae_int_t idxa0; ae_int_t idxa1; ae_int_t idxa2; ae_int_t idxa3; ae_int_t idxb0; ae_int_t idxb1; ae_int_t idxb2; ae_int_t idxb3; ae_int_t i0; ae_int_t i1; ae_int_t ik; ae_int_t j0; ae_int_t j1; ae_int_t jk; ae_int_t t; ae_int_t offsa; ae_int_t offsb; ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * A*B' */ i = 0; while(iptr.pp_double[idxa0][offsa]; a1 = a->ptr.pp_double[idxa1][offsa]; b0 = b->ptr.pp_double[idxb0][offsb]; b1 = b->ptr.pp_double[idxb1][offsb]; v00 = v00+a0*b0; v01 = v01+a0*b1; v10 = v10+a1*b0; v11 = v11+a1*b1; a2 = a->ptr.pp_double[idxa2][offsa]; a3 = a->ptr.pp_double[idxa3][offsa]; v20 = v20+a2*b0; v21 = v21+a2*b1; v30 = v30+a3*b0; v31 = v31+a3*b1; b2 = b->ptr.pp_double[idxb2][offsb]; b3 = b->ptr.pp_double[idxb3][offsb]; v22 = v22+a2*b2; v23 = v23+a2*b3; v32 = v32+a3*b2; v33 = v33+a3*b3; v02 = v02+a0*b2; v03 = v03+a0*b3; v12 = v12+a1*b2; v13 = v13+a1*b3; offsa = offsa+1; offsb = offsb+1; } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; } else { c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; } } else { /* * Determine submatrix [I0..I1]x[J0..J1] to process */ i0 = i; i1 = ae_minint(i+3, m-1, _state); j0 = j; j1 = ae_minint(j+3, n-1, _state); /* * Process submatrix */ for(ik=i0; ik<=i1; ik++) { for(jk=j0; jk<=j1; jk++) { if( k==0||ae_fp_eq(alpha,(double)(0)) ) { v = (double)(0); } else { v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ja,ja+k-1)); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; } else { c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; } } } } j = j+4; } i = i+4; } } /************************************************************************* RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation with OpTypeA=1 and OpTypeB=0. Additional info: * this function requires that Alpha<>0 (assertion is thrown otherwise) INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset B - matrix IB - submatrix offset JB - submatrix offset Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemmk44v10(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double v00; double v01; double v02; double v03; double v10; double v11; double v12; double v13; double v20; double v21; double v22; double v23; double v30; double v31; double v32; double v33; double a0; double a1; double a2; double a3; double b0; double b1; double b2; double b3; ae_int_t idxa0; ae_int_t idxa1; ae_int_t idxa2; ae_int_t idxa3; ae_int_t idxb0; ae_int_t idxb1; ae_int_t idxb2; ae_int_t idxb3; ae_int_t i0; ae_int_t i1; ae_int_t ik; ae_int_t j0; ae_int_t j1; ae_int_t jk; ae_int_t t; ae_int_t offsa; ae_int_t offsb; ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * A'*B */ i = 0; while(iptr.pp_double[offsa][idxa0]; a1 = a->ptr.pp_double[offsa][idxa1]; b0 = b->ptr.pp_double[offsb][idxb0]; b1 = b->ptr.pp_double[offsb][idxb1]; v00 = v00+a0*b0; v01 = v01+a0*b1; v10 = v10+a1*b0; v11 = v11+a1*b1; a2 = a->ptr.pp_double[offsa][idxa2]; a3 = a->ptr.pp_double[offsa][idxa3]; v20 = v20+a2*b0; v21 = v21+a2*b1; v30 = v30+a3*b0; v31 = v31+a3*b1; b2 = b->ptr.pp_double[offsb][idxb2]; b3 = b->ptr.pp_double[offsb][idxb3]; v22 = v22+a2*b2; v23 = v23+a2*b3; v32 = v32+a3*b2; v33 = v33+a3*b3; v02 = v02+a0*b2; v03 = v03+a0*b3; v12 = v12+a1*b2; v13 = v13+a1*b3; offsa = offsa+1; offsb = offsb+1; } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; } else { c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; } } else { /* * Determine submatrix [I0..I1]x[J0..J1] to process */ i0 = i; i1 = ae_minint(i+3, m-1, _state); j0 = j; j1 = ae_minint(j+3, n-1, _state); /* * Process submatrix */ for(ik=i0; ik<=i1; ik++) { for(jk=j0; jk<=j1; jk++) { if( k==0||ae_fp_eq(alpha,(double)(0)) ) { v = (double)(0); } else { v = 0.0; v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ia,ia+k-1)); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; } else { c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; } } } } j = j+4; } i = i+4; } } /************************************************************************* RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation with OpTypeA=1 and OpTypeB=1. Additional info: * this function requires that Alpha<>0 (assertion is thrown otherwise) INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset B - matrix IB - submatrix offset JB - submatrix offset Beta - coefficient C - PREALLOCATED output matrix IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 27.03.2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemmk44v11(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double v00; double v01; double v02; double v03; double v10; double v11; double v12; double v13; double v20; double v21; double v22; double v23; double v30; double v31; double v32; double v33; double a0; double a1; double a2; double a3; double b0; double b1; double b2; double b3; ae_int_t idxa0; ae_int_t idxa1; ae_int_t idxa2; ae_int_t idxa3; ae_int_t idxb0; ae_int_t idxb1; ae_int_t idxb2; ae_int_t idxb3; ae_int_t i0; ae_int_t i1; ae_int_t ik; ae_int_t j0; ae_int_t j1; ae_int_t jk; ae_int_t t; ae_int_t offsa; ae_int_t offsb; ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); /* * if matrix size is zero */ if( m==0||n==0 ) { return; } /* * A'*B' */ i = 0; while(iptr.pp_double[offsa][idxa0]; a1 = a->ptr.pp_double[offsa][idxa1]; b0 = b->ptr.pp_double[idxb0][offsb]; b1 = b->ptr.pp_double[idxb1][offsb]; v00 = v00+a0*b0; v01 = v01+a0*b1; v10 = v10+a1*b0; v11 = v11+a1*b1; a2 = a->ptr.pp_double[offsa][idxa2]; a3 = a->ptr.pp_double[offsa][idxa3]; v20 = v20+a2*b0; v21 = v21+a2*b1; v30 = v30+a3*b0; v31 = v31+a3*b1; b2 = b->ptr.pp_double[idxb2][offsb]; b3 = b->ptr.pp_double[idxb3][offsb]; v22 = v22+a2*b2; v23 = v23+a2*b3; v32 = v32+a3*b2; v33 = v33+a3*b3; v02 = v02+a0*b2; v03 = v03+a0*b3; v12 = v12+a1*b2; v13 = v13+a1*b3; offsa = offsa+1; offsb = offsb+1; } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; } else { c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; } } else { /* * Determine submatrix [I0..I1]x[J0..J1] to process */ i0 = i; i1 = ae_minint(i+3, m-1, _state); j0 = j; j1 = ae_minint(j+3, n-1, _state); /* * Process submatrix */ for(ik=i0; ik<=i1; ik++) { for(jk=j0; jk<=j1; jk++) { if( k==0||ae_fp_eq(alpha,(double)(0)) ) { v = (double)(0); } else { v = 0.0; v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ia,ia+k-1)); } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; } else { c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; } } } } j = j+4; } i = i+4; } } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 01.10.2013 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixsyrkmkl(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixsyrkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 01.10.2013 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixherkmkl(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixherkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 01.10.2013 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixgemmmkl(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixgemmmkl(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixlefttrsmmkl(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixlefttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixrighttrsmmkl(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_cmatrixrighttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixlefttrsmmkl(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixlefttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* MKL-based kernel -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixrighttrsmmkl(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixrighttrsmmkl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); #endif } /************************************************************************* MKL-based kernel. NOTE: if function returned False, CholResult is NOT modified. Not ever referenced! if function returned True, CholResult is set to status of Cholesky decomposition (True on succeess). -- ALGLIB routine -- 16.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool spdmatrixcholeskymkl(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, ae_bool* cholresult, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_spdmatrixcholeskymkl(a, offs, n, isupper, cholresult); #endif } /************************************************************************* MKL-based kernel. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixplumkl(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixplumkl(a, offs, m, n, pivots); #endif } /************************************************************************* MKL-based kernel. NOTE: this function needs preallocated output/temporary arrays. D and E must be at least max(M,N)-wide. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixbdmkl(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* e, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixbdmkl(a, m, n, d, e, tauq, taup); #endif } /************************************************************************* MKL-based kernel. If ByQ is True, TauP is not used (can be empty array). If ByQ is False, TauQ is not used (can be empty array). -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixbdmultiplybymkl(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool byq, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixbdmultiplybymkl(qp, m, n, tauq, taup, z, zrows, zcolumns, byq, fromtheright, dotranspose); #endif } /************************************************************************* MKL-based kernel. NOTE: Tau must be preallocated array with at least N-1 elements. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixhessenbergmkl(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixhessenbergmkl(a, n, tau); #endif } /************************************************************************* MKL-based kernel. NOTE: Q must be preallocated N*N array -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixhessenbergunpackqmkl(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixhessenbergunpackqmkl(a, n, tau, q); #endif } /************************************************************************* MKL-based kernel. NOTE: Tau, D, E must be preallocated arrays; length(E)=length(Tau)=N-1 (or larger) length(D)=N (or larger) -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool smatrixtdmkl(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_smatrixtdmkl(a, n, isupper, tau, d, e); #endif } /************************************************************************* MKL-based kernel. NOTE: Q must be preallocated N*N array -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool smatrixtdunpackqmkl(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_smatrixtdunpackqmkl(a, n, isupper, tau, q); #endif } /************************************************************************* MKL-based kernel. NOTE: Tau, D, E must be preallocated arrays; length(E)=length(Tau)=N-1 (or larger) length(D)=N (or larger) -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool hmatrixtdmkl(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_hmatrixtdmkl(a, n, isupper, tau, d, e); #endif } /************************************************************************* MKL-based kernel. NOTE: Q must be preallocated N*N array -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool hmatrixtdunpackqmkl(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Complex */ ae_matrix* q, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_hmatrixtdunpackqmkl(a, n, isupper, tau, q); #endif } /************************************************************************* MKL-based kernel. Returns True if MKL was present and handled request (MKL completion code is returned as separate output parameter). D and E are pre-allocated arrays with length N (both of them!). On output, D constraints singular values, and E is destroyed. SVDResult is modified if and only if MKL is present. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixbdsvdmkl(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_bool* svdresult, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixbdsvdmkl(d, e, n, isupper, u, nru, c, ncc, vt, ncvt, svdresult); #endif } /************************************************************************* MKL-based DHSEQR kernel. Returns True if MKL was present and handled request. WR and WI are pre-allocated arrays with length N. Z is pre-allocated array[N,N]. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixinternalschurdecompositionmkl(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixinternalschurdecompositionmkl(h, n, tneeded, zneeded, wr, wi, z, info); #endif } /************************************************************************* MKL-based DTREVC kernel. Returns True if MKL was present and handled request. NOTE: this function does NOT support HOWMNY=3!!!! VL and VR are pre-allocated arrays with length N*N, if required. If particalar variables is not required, it can be dummy (empty) array. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixinternaltrevcmkl(/* Real */ ae_matrix* t, ae_int_t n, ae_int_t side, ae_int_t howmny, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_int_t* m, ae_int_t* info, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_rmatrixinternaltrevcmkl(t, n, side, howmny, vl, vr, m, info); #endif } /************************************************************************* MKL-based kernel. Returns True if MKL was present and handled request (MKL completion code is returned as separate output parameter). D and E are pre-allocated arrays with length N (both of them!). On output, D constraints eigenvalues, and E is destroyed. Z is preallocated array[N,N] for ZNeeded<>0; ignored for ZNeeded=0. EVDResult is modified if and only if MKL is present. -- ALGLIB routine -- 20.10.2014 Bochkanov Sergey *************************************************************************/ ae_bool smatrixtdevdmkl(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_bool* evdresult, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_MKL ae_bool result; result = ae_false; return result; #else return _ialglib_i_smatrixtdevdmkl(d, e, n, zneeded, z, evdresult); #endif } double vectornorm2(/* Real */ ae_vector* x, ae_int_t i1, ae_int_t i2, ae_state *_state) { ae_int_t n; ae_int_t ix; double absxi; double scl; double ssq; double result; n = i2-i1+1; if( n<1 ) { result = (double)(0); return result; } if( n==1 ) { result = ae_fabs(x->ptr.p_double[i1], _state); return result; } scl = (double)(0); ssq = (double)(1); for(ix=i1; ix<=i2; ix++) { if( ae_fp_neq(x->ptr.p_double[ix],(double)(0)) ) { absxi = ae_fabs(x->ptr.p_double[ix], _state); if( ae_fp_less(scl,absxi) ) { ssq = 1+ssq*ae_sqr(scl/absxi, _state); scl = absxi; } else { ssq = ssq+ae_sqr(absxi/scl, _state); } } } result = scl*ae_sqrt(ssq, _state); return result; } ae_int_t vectoridxabsmax(/* Real */ ae_vector* x, ae_int_t i1, ae_int_t i2, ae_state *_state) { ae_int_t i; ae_int_t result; result = i1; for(i=i1+1; i<=i2; i++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[result], _state)) ) { result = i; } } return result; } ae_int_t columnidxabsmax(/* Real */ ae_matrix* x, ae_int_t i1, ae_int_t i2, ae_int_t j, ae_state *_state) { ae_int_t i; ae_int_t result; result = i1; for(i=i1+1; i<=i2; i++) { if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[result][j], _state)) ) { result = i; } } return result; } ae_int_t rowidxabsmax(/* Real */ ae_matrix* x, ae_int_t j1, ae_int_t j2, ae_int_t i, ae_state *_state) { ae_int_t j; ae_int_t result; result = j1; for(j=j1+1; j<=j2; j++) { if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[i][result], _state)) ) { result = j; } } return result; } double upperhessenberg1norm(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t i; ae_int_t j; double result; ae_assert(i2-i1==j2-j1, "UpperHessenberg1Norm: I2-I1<>J2-J1!", _state); for(j=j1; j<=j2; j++) { work->ptr.p_double[j] = (double)(0); } for(i=i1; i<=i2; i++) { for(j=ae_maxint(j1, j1+i-i1-1, _state); j<=j2; j++) { work->ptr.p_double[j] = work->ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); } } result = (double)(0); for(j=j1; j<=j2; j++) { result = ae_maxreal(result, work->ptr.p_double[j], _state); } return result; } void copymatrix(/* Real */ ae_matrix* a, ae_int_t is1, ae_int_t is2, ae_int_t js1, ae_int_t js2, /* Real */ ae_matrix* b, ae_int_t id1, ae_int_t id2, ae_int_t jd1, ae_int_t jd2, ae_state *_state) { ae_int_t isrc; ae_int_t idst; if( is1>is2||js1>js2 ) { return; } ae_assert(is2-is1==id2-id1, "CopyMatrix: different sizes!", _state); ae_assert(js2-js1==jd2-jd1, "CopyMatrix: different sizes!", _state); for(isrc=is1; isrc<=is2; isrc++) { idst = isrc-is1+id1; ae_v_move(&b->ptr.pp_double[idst][jd1], 1, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(jd1,jd2)); } } void inplacetranspose(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t ips; ae_int_t jps; ae_int_t l; if( i1>i2||j1>j2 ) { return; } ae_assert(i1-i2==j1-j2, "InplaceTranspose error: incorrect array size!", _state); for(i=i1; i<=i2-1; i++) { j = j1+i-i1; ips = i+1; jps = j1+ips-i1; l = i2-i; ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ips][j], a->stride, ae_v_len(1,l)); ae_v_move(&a->ptr.pp_double[ips][j], a->stride, &a->ptr.pp_double[i][jps], 1, ae_v_len(ips,i2)); ae_v_move(&a->ptr.pp_double[i][jps], 1, &work->ptr.p_double[1], 1, ae_v_len(jps,j2)); } } void copyandtranspose(/* Real */ ae_matrix* a, ae_int_t is1, ae_int_t is2, ae_int_t js1, ae_int_t js2, /* Real */ ae_matrix* b, ae_int_t id1, ae_int_t id2, ae_int_t jd1, ae_int_t jd2, ae_state *_state) { ae_int_t isrc; ae_int_t jdst; if( is1>is2||js1>js2 ) { return; } ae_assert(is2-is1==jd2-jd1, "CopyAndTranspose: different sizes!", _state); ae_assert(js2-js1==id2-id1, "CopyAndTranspose: different sizes!", _state); for(isrc=is1; isrc<=is2; isrc++) { jdst = isrc-is1+jd1; ae_v_move(&b->ptr.pp_double[id1][jdst], b->stride, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(id1,id2)); } } void matrixvectormultiply(/* Real */ ae_matrix* a, ae_int_t i1, ae_int_t i2, ae_int_t j1, ae_int_t j2, ae_bool trans, /* Real */ ae_vector* x, ae_int_t ix1, ae_int_t ix2, double alpha, /* Real */ ae_vector* y, ae_int_t iy1, ae_int_t iy2, double beta, ae_state *_state) { ae_int_t i; double v; if( !trans ) { /* * y := alpha*A*x + beta*y; */ if( i1>i2||j1>j2 ) { return; } ae_assert(j2-j1==ix2-ix1, "MatrixVectorMultiply: A and X don't match!", _state); ae_assert(i2-i1==iy2-iy1, "MatrixVectorMultiply: A and Y don't match!", _state); /* * beta*y */ if( ae_fp_eq(beta,(double)(0)) ) { for(i=iy1; i<=iy2; i++) { y->ptr.p_double[i] = (double)(0); } } else { ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); } /* * alpha*A*x */ for(i=i1; i<=i2; i++) { v = ae_v_dotproduct(&a->ptr.pp_double[i][j1], 1, &x->ptr.p_double[ix1], 1, ae_v_len(j1,j2)); y->ptr.p_double[iy1+i-i1] = y->ptr.p_double[iy1+i-i1]+alpha*v; } } else { /* * y := alpha*A'*x + beta*y; */ if( i1>i2||j1>j2 ) { return; } ae_assert(i2-i1==ix2-ix1, "MatrixVectorMultiply: A and X don't match!", _state); ae_assert(j2-j1==iy2-iy1, "MatrixVectorMultiply: A and Y don't match!", _state); /* * beta*y */ if( ae_fp_eq(beta,(double)(0)) ) { for(i=iy1; i<=iy2; i++) { y->ptr.p_double[i] = (double)(0); } } else { ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); } /* * alpha*A'*x */ for(i=i1; i<=i2; i++) { v = alpha*x->ptr.p_double[ix1+i-i1]; ae_v_addd(&y->ptr.p_double[iy1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(iy1,iy2), v); } } } double pythag2(double x, double y, ae_state *_state) { double w; double xabs; double yabs; double z; double result; xabs = ae_fabs(x, _state); yabs = ae_fabs(y, _state); w = ae_maxreal(xabs, yabs, _state); z = ae_minreal(xabs, yabs, _state); if( ae_fp_eq(z,(double)(0)) ) { result = w; } else { result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state); } return result; } void matrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, double alpha, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, double beta, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t arows; ae_int_t acols; ae_int_t brows; ae_int_t bcols; ae_int_t crows; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_int_t r; double v; /* * Setup */ if( !transa ) { arows = ai2-ai1+1; acols = aj2-aj1+1; } else { arows = aj2-aj1+1; acols = ai2-ai1+1; } if( !transb ) { brows = bi2-bi1+1; bcols = bj2-bj1+1; } else { brows = bj2-bj1+1; bcols = bi2-bi1+1; } ae_assert(acols==brows, "MatrixMatrixMultiply: incorrect matrix sizes!", _state); if( ((arows<=0||acols<=0)||brows<=0)||bcols<=0 ) { return; } crows = arows; /* * Test WORK */ i = ae_maxint(arows, acols, _state); i = ae_maxint(brows, i, _state); i = ae_maxint(i, bcols, _state); work->ptr.p_double[1] = (double)(0); work->ptr.p_double[i] = (double)(0); /* * Prepare C */ if( ae_fp_eq(beta,(double)(0)) ) { for(i=ci1; i<=ci2; i++) { for(j=cj1; j<=cj2; j++) { c->ptr.pp_double[i][j] = (double)(0); } } } else { for(i=ci1; i<=ci2; i++) { ae_v_muld(&c->ptr.pp_double[i][cj1], 1, ae_v_len(cj1,cj2), beta); } } /* * A*B */ if( !transa&&!transb ) { for(l=ai1; l<=ai2; l++) { for(r=bi1; r<=bi2; r++) { v = alpha*a->ptr.pp_double[l][aj1+r-bi1]; k = ci1+l-ai1; ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); } } return; } /* * A*B' */ if( !transa&&transb ) { if( arows*acolsptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; } } return; } else { for(l=ai1; l<=ai2; l++) { for(r=bi1; r<=bi2; r++) { v = ae_v_dotproduct(&a->ptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; } } return; } } /* * A'*B */ if( transa&&!transb ) { for(l=aj1; l<=aj2; l++) { for(r=bi1; r<=bi2; r++) { v = alpha*a->ptr.pp_double[ai1+r-bi1][l]; k = ci1+l-aj1; ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); } } return; } /* * A'*B' */ if( transa&&transb ) { if( arows*acolsptr.p_double[i] = 0.0; } for(l=ai1; l<=ai2; l++) { v = alpha*b->ptr.pp_double[r][bj1+l-ai1]; ae_v_addd(&work->ptr.p_double[1], 1, &a->ptr.pp_double[l][aj1], 1, ae_v_len(1,crows), v); } ae_v_add(&c->ptr.pp_double[ci1][k], c->stride, &work->ptr.p_double[1], 1, ae_v_len(ci1,ci2)); } return; } else { for(l=aj1; l<=aj2; l++) { k = ai2-ai1+1; ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ai1][l], a->stride, ae_v_len(1,k)); for(r=bi1; r<=bi2; r++) { v = ae_v_dotproduct(&work->ptr.p_double[1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(1,k)); c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1]+alpha*v; } } return; } } } void hermitianmatrixvectormultiply(/* Complex */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Complex */ ae_vector* x, ae_complex alpha, /* Complex */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t ba1; ae_int_t by1; ae_int_t by2; ae_int_t bx1; ae_int_t bx2; ae_int_t n; ae_complex v; n = i2-i1+1; if( n<=0 ) { return; } /* * Let A = L + D + U, where * L is strictly lower triangular (main diagonal is zero) * D is diagonal * U is strictly upper triangular (main diagonal is zero) * * A*x = L*x + D*x + U*x * * Calculate D*x first */ for(i=i1; i<=i2; i++) { y->ptr.p_complex[i-i1+1] = ae_c_mul(a->ptr.pp_complex[i][i],x->ptr.p_complex[i-i1+1]); } /* * Add L*x + U*x */ if( isupper ) { for(i=i1; i<=i2-1; i++) { /* * Add L*x to the result */ v = x->ptr.p_complex[i-i1+1]; by1 = i-i1+2; by2 = n; ba1 = i+1; ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); /* * Add U*x to the result */ bx1 = i-i1+2; bx2 = n; ba1 = i+1; v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); } } else { for(i=i1+1; i<=i2; i++) { /* * Add L*x to the result */ bx1 = 1; bx2 = i-i1; ba1 = i1; v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); /* * Add U*x to the result */ v = x->ptr.p_complex[i-i1+1]; by1 = 1; by2 = i-i1; ba1 = i1; ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); } } ae_v_cmulc(&y->ptr.p_complex[1], 1, ae_v_len(1,n), alpha); } void hermitianrank2update(/* Complex */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Complex */ ae_vector* x, /* Complex */ ae_vector* y, /* Complex */ ae_vector* t, ae_complex alpha, ae_state *_state) { ae_int_t i; ae_int_t tp1; ae_int_t tp2; ae_complex v; if( isupper ) { for(i=i1; i<=i2; i++) { tp1 = i+1-i1; tp2 = i2-i1+1; v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); ae_v_cadd(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i,i2)); } } else { for(i=i1; i<=i2; i++) { tp1 = 1; tp2 = i+1-i1; v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); ae_v_cadd(&a->ptr.pp_complex[i][i1], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i1,i)); } } } /************************************************************************* Generation of an elementary reflection transformation The subroutine generates elementary reflection H of order N, so that, for a given X, the following equality holds true: ( X(1) ) ( Beta ) H * ( .. ) = ( 0 ) ( X(n) ) ( 0 ) where ( V(1) ) H = 1 - Tau * ( .. ) * ( V(1), ..., V(n) ) ( V(n) ) where the first component of vector V equals 1. Input parameters: X - vector. Array whose index ranges within [1..N]. N - reflection order. Output parameters: X - components from 2 to N are replaced with vector V. The first component is replaced with parameter Beta. Tau - scalar value Tau. If X is a null vector, Tau equals 0, otherwise 1 <= Tau <= 2. This subroutine is the modification of the DLARFG subroutines from the LAPACK library. MODIFICATIONS: 24.12.2005 sign(Alpha) was replaced with an analogous to the Fortran SIGN code. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void generatereflection(/* Real */ ae_vector* x, ae_int_t n, double* tau, ae_state *_state) { ae_int_t j; double alpha; double xnorm; double v; double beta; double mx; double s; *tau = 0; if( n<=1 ) { *tau = (double)(0); return; } /* * Scale if needed (to avoid overflow/underflow during intermediate * calculations). */ mx = (double)(0); for(j=1; j<=n; j++) { mx = ae_maxreal(ae_fabs(x->ptr.p_double[j], _state), mx, _state); } s = (double)(1); if( ae_fp_neq(mx,(double)(0)) ) { if( ae_fp_less_eq(mx,ae_minrealnumber/ae_machineepsilon) ) { s = ae_minrealnumber/ae_machineepsilon; v = 1/s; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); mx = mx*v; } else { if( ae_fp_greater_eq(mx,ae_maxrealnumber*ae_machineepsilon) ) { s = ae_maxrealnumber*ae_machineepsilon; v = 1/s; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); mx = mx*v; } } } /* * XNORM = DNRM2( N-1, X, INCX ) */ alpha = x->ptr.p_double[1]; xnorm = (double)(0); if( ae_fp_neq(mx,(double)(0)) ) { for(j=2; j<=n; j++) { xnorm = xnorm+ae_sqr(x->ptr.p_double[j]/mx, _state); } xnorm = ae_sqrt(xnorm, _state)*mx; } if( ae_fp_eq(xnorm,(double)(0)) ) { /* * H = I */ *tau = (double)(0); x->ptr.p_double[1] = x->ptr.p_double[1]*s; return; } /* * general case */ mx = ae_maxreal(ae_fabs(alpha, _state), ae_fabs(xnorm, _state), _state); beta = -mx*ae_sqrt(ae_sqr(alpha/mx, _state)+ae_sqr(xnorm/mx, _state), _state); if( ae_fp_less(alpha,(double)(0)) ) { beta = -beta; } *tau = (beta-alpha)/beta; v = 1/(alpha-beta); ae_v_muld(&x->ptr.p_double[2], 1, ae_v_len(2,n), v); x->ptr.p_double[1] = beta; /* * Scale back outputs */ x->ptr.p_double[1] = x->ptr.p_double[1]*s; } /************************************************************************* Application of an elementary reflection to a rectangular matrix of size MxN The algorithm pre-multiplies the matrix by an elementary reflection transformation which is given by column V and scalar Tau (see the description of the GenerateReflection procedure). Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Input parameters: C - matrix to be transformed. Tau - scalar defining the transformation. V - column defining the transformation. Array whose index ranges within [1..M2-M1+1]. M1, M2 - range of rows to be transformed. N1, N2 - range of columns to be transformed. WORK - working array whose indexes goes from N1 to N2. Output parameters: C - the result of multiplying the input matrix C by the transformation matrix which is given by Tau and V. If N1>N2 or M1>M2, C is not modified. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void applyreflectionfromtheleft(/* Real */ ae_matrix* c, double tau, /* Real */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* work, ae_state *_state) { double t; ae_int_t i; if( (ae_fp_eq(tau,(double)(0))||n1>n2)||m1>m2 ) { return; } /* * w := C' * v */ for(i=n1; i<=n2; i++) { work->ptr.p_double[i] = (double)(0); } for(i=m1; i<=m2; i++) { t = v->ptr.p_double[i+1-m1]; ae_v_addd(&work->ptr.p_double[n1], 1, &c->ptr.pp_double[i][n1], 1, ae_v_len(n1,n2), t); } /* * C := C - tau * v * w' */ for(i=m1; i<=m2; i++) { t = v->ptr.p_double[i-m1+1]*tau; ae_v_subd(&c->ptr.pp_double[i][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2), t); } } /************************************************************************* Application of an elementary reflection to a rectangular matrix of size MxN The algorithm post-multiplies the matrix by an elementary reflection transformation which is given by column V and scalar Tau (see the description of the GenerateReflection procedure). Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Input parameters: C - matrix to be transformed. Tau - scalar defining the transformation. V - column defining the transformation. Array whose index ranges within [1..N2-N1+1]. M1, M2 - range of rows to be transformed. N1, N2 - range of columns to be transformed. WORK - working array whose indexes goes from M1 to M2. Output parameters: C - the result of multiplying the input matrix C by the transformation matrix which is given by Tau and V. If N1>N2 or M1>M2, C is not modified. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void applyreflectionfromtheright(/* Real */ ae_matrix* c, double tau, /* Real */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* work, ae_state *_state) { double t; ae_int_t i; ae_int_t vm; if( (ae_fp_eq(tau,(double)(0))||n1>n2)||m1>m2 ) { return; } vm = n2-n1+1; for(i=m1; i<=m2; i++) { t = ae_v_dotproduct(&c->ptr.pp_double[i][n1], 1, &v->ptr.p_double[1], 1, ae_v_len(n1,n2)); t = t*tau; ae_v_subd(&c->ptr.pp_double[i][n1], 1, &v->ptr.p_double[1], 1, ae_v_len(n1,n2), t); } /* * This line is necessary to avoid spurious compiler warnings */ touchint(&vm, _state); } /************************************************************************* Generation of an elementary complex reflection transformation The subroutine generates elementary complex reflection H of order N, so that, for a given X, the following equality holds true: ( X(1) ) ( Beta ) H' * ( .. ) = ( 0 ), H'*H = I, Beta is a real number ( X(n) ) ( 0 ) where ( V(1) ) H = 1 - Tau * ( .. ) * ( conj(V(1)), ..., conj(V(n)) ) ( V(n) ) where the first component of vector V equals 1. Input parameters: X - vector. Array with elements [1..N]. N - reflection order. Output parameters: X - components from 2 to N are replaced by vector V. The first component is replaced with parameter Beta. Tau - scalar value Tau. This subroutine is the modification of CLARFG subroutines from the LAPACK library. It has similar functionality except for the fact that it doesnt handle errors when intermediate results cause an overflow. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void complexgeneratereflection(/* Complex */ ae_vector* x, ae_int_t n, ae_complex* tau, ae_state *_state) { ae_int_t j; ae_complex alpha; double alphi; double alphr; double beta; double xnorm; double mx; ae_complex t; double s; ae_complex v; tau->x = 0; tau->y = 0; if( n<=0 ) { *tau = ae_complex_from_i(0); return; } /* * Scale if needed (to avoid overflow/underflow during intermediate * calculations). */ mx = (double)(0); for(j=1; j<=n; j++) { mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); } s = (double)(1); if( ae_fp_neq(mx,(double)(0)) ) { if( ae_fp_less(mx,(double)(1)) ) { s = ae_sqrt(ae_minrealnumber, _state); v = ae_complex_from_d(1/s); ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); } else { s = ae_sqrt(ae_maxrealnumber, _state); v = ae_complex_from_d(1/s); ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); } } /* * calculate */ alpha = x->ptr.p_complex[1]; mx = (double)(0); for(j=2; j<=n; j++) { mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); } xnorm = (double)(0); if( ae_fp_neq(mx,(double)(0)) ) { for(j=2; j<=n; j++) { t = ae_c_div_d(x->ptr.p_complex[j],mx); xnorm = xnorm+ae_c_mul(t,ae_c_conj(t, _state)).x; } xnorm = ae_sqrt(xnorm, _state)*mx; } alphr = alpha.x; alphi = alpha.y; if( ae_fp_eq(xnorm,(double)(0))&&ae_fp_eq(alphi,(double)(0)) ) { *tau = ae_complex_from_i(0); x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); return; } mx = ae_maxreal(ae_fabs(alphr, _state), ae_fabs(alphi, _state), _state); mx = ae_maxreal(mx, ae_fabs(xnorm, _state), _state); beta = -mx*ae_sqrt(ae_sqr(alphr/mx, _state)+ae_sqr(alphi/mx, _state)+ae_sqr(xnorm/mx, _state), _state); if( ae_fp_less(alphr,(double)(0)) ) { beta = -beta; } tau->x = (beta-alphr)/beta; tau->y = -alphi/beta; alpha = ae_c_d_div(1,ae_c_sub_d(alpha,beta)); if( n>1 ) { ae_v_cmulc(&x->ptr.p_complex[2], 1, ae_v_len(2,n), alpha); } alpha = ae_complex_from_d(beta); x->ptr.p_complex[1] = alpha; /* * Scale back */ x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); } /************************************************************************* Application of an elementary reflection to a rectangular matrix of size MxN The algorithm pre-multiplies the matrix by an elementary reflection transformation which is given by column V and scalar Tau (see the description of the GenerateReflection). Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Note: the matrix is multiplied by H, not by H'. If it is required to multiply the matrix by H', it is necessary to pass Conj(Tau) instead of Tau. Input parameters: C - matrix to be transformed. Tau - scalar defining transformation. V - column defining transformation. Array whose index ranges within [1..M2-M1+1] M1, M2 - range of rows to be transformed. N1, N2 - range of columns to be transformed. WORK - working array whose index goes from N1 to N2. Output parameters: C - the result of multiplying the input matrix C by the transformation matrix which is given by Tau and V. If N1>N2 or M1>M2, C is not modified. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, ae_complex tau, /* Complex */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Complex */ ae_vector* work, ae_state *_state) { ae_complex t; ae_int_t i; if( (ae_c_eq_d(tau,(double)(0))||n1>n2)||m1>m2 ) { return; } /* * w := C^T * conj(v) */ for(i=n1; i<=n2; i++) { work->ptr.p_complex[i] = ae_complex_from_i(0); } for(i=m1; i<=m2; i++) { t = ae_c_conj(v->ptr.p_complex[i+1-m1], _state); ae_v_caddc(&work->ptr.p_complex[n1], 1, &c->ptr.pp_complex[i][n1], 1, "N", ae_v_len(n1,n2), t); } /* * C := C - tau * v * w^T */ for(i=m1; i<=m2; i++) { t = ae_c_mul(v->ptr.p_complex[i-m1+1],tau); ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &work->ptr.p_complex[n1], 1, "N", ae_v_len(n1,n2), t); } } /************************************************************************* Application of an elementary reflection to a rectangular matrix of size MxN The algorithm post-multiplies the matrix by an elementary reflection transformation which is given by column V and scalar Tau (see the description of the GenerateReflection). Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Input parameters: C - matrix to be transformed. Tau - scalar defining transformation. V - column defining transformation. Array whose index ranges within [1..N2-N1+1] M1, M2 - range of rows to be transformed. N1, N2 - range of columns to be transformed. WORK - working array whose index goes from M1 to M2. Output parameters: C - the result of multiplying the input matrix C by the transformation matrix which is given by Tau and V. If N1>N2 or M1>M2, C is not modified. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, ae_complex tau, /* Complex */ ae_vector* v, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Complex */ ae_vector* work, ae_state *_state) { ae_complex t; ae_int_t i; ae_int_t vm; if( (ae_c_eq_d(tau,(double)(0))||n1>n2)||m1>m2 ) { return; } /* * w := C * v */ vm = n2-n1+1; for(i=m1; i<=m2; i++) { t = ae_v_cdotproduct(&c->ptr.pp_complex[i][n1], 1, "N", &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2)); work->ptr.p_complex[i] = t; } /* * C := C - w * conj(v^T) */ ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); for(i=m1; i<=m2; i++) { t = ae_c_mul(work->ptr.p_complex[i],tau); ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2), t); } ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); } void symmetricmatrixvectormultiply(/* Real */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* x, double alpha, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t ba1; ae_int_t ba2; ae_int_t by1; ae_int_t by2; ae_int_t bx1; ae_int_t bx2; ae_int_t n; double v; n = i2-i1+1; if( n<=0 ) { return; } /* * Let A = L + D + U, where * L is strictly lower triangular (main diagonal is zero) * D is diagonal * U is strictly upper triangular (main diagonal is zero) * * A*x = L*x + D*x + U*x * * Calculate D*x first */ for(i=i1; i<=i2; i++) { y->ptr.p_double[i-i1+1] = a->ptr.pp_double[i][i]*x->ptr.p_double[i-i1+1]; } /* * Add L*x + U*x */ if( isupper ) { for(i=i1; i<=i2-1; i++) { /* * Add L*x to the result */ v = x->ptr.p_double[i-i1+1]; by1 = i-i1+2; by2 = n; ba1 = i+1; ba2 = i2; ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); /* * Add U*x to the result */ bx1 = i-i1+2; bx2 = n; ba1 = i+1; ba2 = i2; v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; } } else { for(i=i1+1; i<=i2; i++) { /* * Add L*x to the result */ bx1 = 1; bx2 = i-i1; ba1 = i1; ba2 = i-1; v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; /* * Add U*x to the result */ v = x->ptr.p_double[i-i1+1]; by1 = 1; by2 = i-i1; ba1 = i1; ba2 = i-1; ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); } } ae_v_muld(&y->ptr.p_double[1], 1, ae_v_len(1,n), alpha); touchint(&ba2, _state); } void symmetricrank2update(/* Real */ ae_matrix* a, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* t, double alpha, ae_state *_state) { ae_int_t i; ae_int_t tp1; ae_int_t tp2; double v; if( isupper ) { for(i=i1; i<=i2; i++) { tp1 = i+1-i1; tp2 = i2-i1+1; v = x->ptr.p_double[i+1-i1]; ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); v = y->ptr.p_double[i+1-i1]; ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); ae_v_add(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i,i2)); } } else { for(i=i1; i<=i2; i++) { tp1 = 1; tp2 = i+1-i1; v = x->ptr.p_double[i+1-i1]; ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); v = y->ptr.p_double[i+1-i1]; ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); ae_v_add(&a->ptr.pp_double[i][i1], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i1,i)); } } } /************************************************************************* Application of a sequence of elementary rotations to a matrix The algorithm pre-multiplies the matrix by a sequence of rotation transformations which is given by arrays C and S. Depending on the value of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) rows are rotated, or the rows N and N-1, N-2 and N-3 and so on, are rotated. Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Input parameters: IsForward - the sequence of the rotation application. M1,M2 - the range of rows to be transformed. N1, N2 - the range of columns to be transformed. C,S - transformation coefficients. Array whose index ranges within [1..M2-M1]. A - processed matrix. WORK - working array whose index ranges within [N1..N2]. Output parameters: A - transformed matrix. Utility subroutine. *************************************************************************/ void applyrotationsfromtheleft(ae_bool isforward, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* c, /* Real */ ae_vector* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t j; ae_int_t jp1; double ctemp; double stemp; double temp; if( m1>m2||n1>n2 ) { return; } /* * Form P * A */ if( isforward ) { if( n1!=n2 ) { /* * Common case: N1<>N2 */ for(j=m1; j<=m2-1; j++) { ctemp = c->ptr.p_double[j-m1+1]; stemp = s->ptr.p_double[j-m1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { jp1 = j+1; ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); } } } else { /* * Special case: N1=N2 */ for(j=m1; j<=m2-1; j++) { ctemp = c->ptr.p_double[j-m1+1]; stemp = s->ptr.p_double[j-m1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { temp = a->ptr.pp_double[j+1][n1]; a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; } } } } else { if( n1!=n2 ) { /* * Common case: N1<>N2 */ for(j=m2-1; j>=m1; j--) { ctemp = c->ptr.p_double[j-m1+1]; stemp = s->ptr.p_double[j-m1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { jp1 = j+1; ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); } } } else { /* * Special case: N1=N2 */ for(j=m2-1; j>=m1; j--) { ctemp = c->ptr.p_double[j-m1+1]; stemp = s->ptr.p_double[j-m1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { temp = a->ptr.pp_double[j+1][n1]; a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; } } } } } /************************************************************************* Application of a sequence of elementary rotations to a matrix The algorithm post-multiplies the matrix by a sequence of rotation transformations which is given by arrays C and S. Depending on the value of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) rows are rotated, or the rows N and N-1, N-2 and N-3 and so on are rotated. Not the whole matrix but only a part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements of this submatrix are changed. Input parameters: IsForward - the sequence of the rotation application. M1,M2 - the range of rows to be transformed. N1, N2 - the range of columns to be transformed. C,S - transformation coefficients. Array whose index ranges within [1..N2-N1]. A - processed matrix. WORK - working array whose index ranges within [M1..M2]. Output parameters: A - transformed matrix. Utility subroutine. *************************************************************************/ void applyrotationsfromtheright(ae_bool isforward, ae_int_t m1, ae_int_t m2, ae_int_t n1, ae_int_t n2, /* Real */ ae_vector* c, /* Real */ ae_vector* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* work, ae_state *_state) { ae_int_t j; ae_int_t jp1; double ctemp; double stemp; double temp; /* * Form A * P' */ if( isforward ) { if( m1!=m2 ) { /* * Common case: M1<>M2 */ for(j=n1; j<=n2-1; j++) { ctemp = c->ptr.p_double[j-n1+1]; stemp = s->ptr.p_double[j-n1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { jp1 = j+1; ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); } } } else { /* * Special case: M1=M2 */ for(j=n1; j<=n2-1; j++) { ctemp = c->ptr.p_double[j-n1+1]; stemp = s->ptr.p_double[j-n1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { temp = a->ptr.pp_double[m1][j+1]; a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; } } } } else { if( m1!=m2 ) { /* * Common case: M1<>M2 */ for(j=n2-1; j>=n1; j--) { ctemp = c->ptr.p_double[j-n1+1]; stemp = s->ptr.p_double[j-n1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { jp1 = j+1; ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); } } } else { /* * Special case: M1=M2 */ for(j=n2-1; j>=n1; j--) { ctemp = c->ptr.p_double[j-n1+1]; stemp = s->ptr.p_double[j-n1+1]; if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) { temp = a->ptr.pp_double[m1][j+1]; a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; } } } } } /************************************************************************* The subroutine generates the elementary rotation, so that: [ CS SN ] . [ F ] = [ R ] [ -SN CS ] [ G ] [ 0 ] CS**2 + SN**2 = 1 *************************************************************************/ void generaterotation(double f, double g, double* cs, double* sn, double* r, ae_state *_state) { double f1; double g1; *cs = 0; *sn = 0; *r = 0; if( ae_fp_eq(g,(double)(0)) ) { *cs = (double)(1); *sn = (double)(0); *r = f; } else { if( ae_fp_eq(f,(double)(0)) ) { *cs = (double)(0); *sn = (double)(1); *r = g; } else { f1 = f; g1 = g; if( ae_fp_greater(ae_fabs(f1, _state),ae_fabs(g1, _state)) ) { *r = ae_fabs(f1, _state)*ae_sqrt(1+ae_sqr(g1/f1, _state), _state); } else { *r = ae_fabs(g1, _state)*ae_sqrt(1+ae_sqr(f1/g1, _state), _state); } *cs = f1/(*r); *sn = g1/(*r); if( ae_fp_greater(ae_fabs(f, _state),ae_fabs(g, _state))&&ae_fp_less(*cs,(double)(0)) ) { *cs = -*cs; *sn = -*sn; *r = -*r; } } } } void rmatrixinternalschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix h1; ae_matrix z1; ae_vector wr1; ae_vector wi1; ae_frame_make(_state, &_frame_block); ae_vector_clear(wr); ae_vector_clear(wi); *info = 0; ae_matrix_init(&h1, 0, 0, DT_REAL, _state); ae_matrix_init(&z1, 0, 0, DT_REAL, _state); ae_vector_init(&wr1, 0, DT_REAL, _state); ae_vector_init(&wi1, 0, DT_REAL, _state); /* * Allocate space */ ae_vector_set_length(wr, n, _state); ae_vector_set_length(wi, n, _state); if( zneeded==2 ) { rmatrixsetlengthatleast(z, n, n, _state); } /* * MKL version */ if( rmatrixinternalschurdecompositionmkl(h, n, tneeded, zneeded, wr, wi, z, info, _state) ) { ae_frame_leave(_state); return; } /* * ALGLIB version */ ae_matrix_set_length(&h1, n+1, n+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { h1.ptr.pp_double[1+i][1+j] = h->ptr.pp_double[i][j]; } } if( zneeded==1 ) { ae_matrix_set_length(&z1, n+1, n+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z1.ptr.pp_double[1+i][1+j] = z->ptr.pp_double[i][j]; } } } internalschurdecomposition(&h1, n, tneeded, zneeded, &wr1, &wi1, &z1, info, _state); for(i=0; i<=n-1; i++) { wr->ptr.p_double[i] = wr1.ptr.p_double[i+1]; wi->ptr.p_double[i] = wi1.ptr.p_double[i+1]; } if( tneeded!=0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { h->ptr.pp_double[i][j] = h1.ptr.pp_double[1+i][1+j]; } } } if( zneeded!=0 ) { rmatrixsetlengthatleast(z, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z->ptr.pp_double[i][j] = z1.ptr.pp_double[1+i][1+j]; } } } ae_frame_leave(_state); } /************************************************************************* Subroutine performing the Schur decomposition of a matrix in upper Hessenberg form using the QR algorithm with multiple shifts. The source matrix H is represented as S'*H*S = T, where H - matrix in upper Hessenberg form, S - orthogonal matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). Input parameters: H - matrix to be decomposed. Array whose indexes range within [1..N, 1..N]. N - size of H, N>=0. Output parameters: H contains the matrix T. Array whose indexes range within [1..N, 1..N]. All elements below the blocks on the main diagonal are equal to 0. S - contains Schur vectors. Array whose indexes range within [1..N, 1..N]. Note 1: The block structure of matrix T could be easily recognized: since all the elements below the blocks are zeros, the elements a[i+1,i] which are equal to 0 show the block border. Note 2: the algorithm performance depends on the value of the internal parameter NS of InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (analog of the block width in block matrix algorithms in linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. Result: True, if the algorithm has converged and the parameters H and S contain the result. False, if the algorithm has not converged. Algorithm implemented on the basis of subroutine DHSEQR (LAPACK 3.0 library). *************************************************************************/ ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, /* Real */ ae_matrix* s, ae_state *_state) { ae_frame _frame_block; ae_vector wi; ae_vector wr; ae_int_t info; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_clear(s); ae_vector_init(&wi, 0, DT_REAL, _state); ae_vector_init(&wr, 0, DT_REAL, _state); internalschurdecomposition(h, n, 1, 2, &wr, &wi, s, &info, _state); result = info==0; ae_frame_leave(_state); return result; } void internalschurdecomposition(/* Real */ ae_matrix* h, ae_int_t n, ae_int_t tneeded, ae_int_t zneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* z, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t ierr; ae_int_t ii; ae_int_t itemp; ae_int_t itn; ae_int_t its; ae_int_t j; ae_int_t k; ae_int_t l; ae_int_t maxb; ae_int_t nr; ae_int_t ns; ae_int_t nv; double absw; double smlnum; double tau; double temp; double tst1; double ulp; double unfl; ae_matrix s; ae_vector v; ae_vector vv; ae_vector workc1; ae_vector works1; ae_vector workv3; ae_vector tmpwr; ae_vector tmpwi; ae_bool initz; ae_bool wantt; ae_bool wantz; double cnst; ae_bool failflag; ae_int_t p1; ae_int_t p2; double vt; ae_frame_make(_state, &_frame_block); ae_vector_clear(wr); ae_vector_clear(wi); *info = 0; ae_vector_init(&work, 0, DT_REAL, _state); ae_matrix_init(&s, 0, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&vv, 0, DT_REAL, _state); ae_vector_init(&workc1, 0, DT_REAL, _state); ae_vector_init(&works1, 0, DT_REAL, _state); ae_vector_init(&workv3, 0, DT_REAL, _state); ae_vector_init(&tmpwr, 0, DT_REAL, _state); ae_vector_init(&tmpwi, 0, DT_REAL, _state); /* * Set the order of the multi-shift QR algorithm to be used. * If you want to tune algorithm, change this values */ ns = 12; maxb = 50; /* * Now 2 < NS <= MAXB < NH. */ maxb = ae_maxint(3, maxb, _state); ns = ae_minint(maxb, ns, _state); /* * Initialize */ cnst = 1.5; ae_vector_set_length(&work, ae_maxint(n, 1, _state)+1, _state); ae_matrix_set_length(&s, ns+1, ns+1, _state); ae_vector_set_length(&v, ns+1+1, _state); ae_vector_set_length(&vv, ns+1+1, _state); ae_vector_set_length(wr, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(wi, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&workc1, 1+1, _state); ae_vector_set_length(&works1, 1+1, _state); ae_vector_set_length(&workv3, 3+1, _state); ae_vector_set_length(&tmpwr, ae_maxint(n, 1, _state)+1, _state); ae_vector_set_length(&tmpwi, ae_maxint(n, 1, _state)+1, _state); ae_assert(n>=0, "InternalSchurDecomposition: incorrect N!", _state); ae_assert(tneeded==0||tneeded==1, "InternalSchurDecomposition: incorrect TNeeded!", _state); ae_assert((zneeded==0||zneeded==1)||zneeded==2, "InternalSchurDecomposition: incorrect ZNeeded!", _state); wantt = tneeded==1; initz = zneeded==2; wantz = zneeded!=0; *info = 0; /* * Initialize Z, if necessary */ if( initz ) { rmatrixsetlengthatleast(z, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { z->ptr.pp_double[i][j] = (double)(1); } else { z->ptr.pp_double[i][j] = (double)(0); } } } } /* * Quick return if possible */ if( n==0 ) { ae_frame_leave(_state); return; } if( n==1 ) { wr->ptr.p_double[1] = h->ptr.pp_double[1][1]; wi->ptr.p_double[1] = (double)(0); ae_frame_leave(_state); return; } /* * Set rows and columns 1 to N to zero below the first * subdiagonal. */ for(j=1; j<=n-2; j++) { for(i=j+2; i<=n; i++) { h->ptr.pp_double[i][j] = (double)(0); } } /* * Test if N is sufficiently small */ if( (ns<=2||ns>n)||maxb>=n ) { /* * Use the standard double-shift algorithm */ hsschur_internalauxschur(wantt, wantz, n, 1, n, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); /* * fill entries under diagonal blocks of T with zeros */ if( wantt ) { j = 1; while(j<=n) { if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) { for(i=j+1; i<=n; i++) { h->ptr.pp_double[i][j] = (double)(0); } j = j+1; } else { for(i=j+2; i<=n; i++) { h->ptr.pp_double[i][j] = (double)(0); h->ptr.pp_double[i][j+1] = (double)(0); } j = j+2; } } } ae_frame_leave(_state); return; } unfl = ae_minrealnumber; ulp = 2*ae_machineepsilon; smlnum = unfl*(n/ulp); /* * I1 and I2 are the indices of the first row and last column of H * to which transformations must be applied. If eigenvalues only are * being computed, I1 and I2 are set inside the main loop. */ i1 = 1; i2 = n; /* * ITN is the total number of multiple-shift QR iterations allowed. */ itn = 30*n; /* * The main loop begins here. I is the loop index and decreases from * IHI to ILO in steps of at most MAXB. Each iteration of the loop * works with the active submatrix in rows and columns L to I. * Eigenvalues I+1 to IHI have already converged. Either L = ILO or * H(L,L-1) is negligible so that the matrix splits. */ i = n; for(;;) { l = 1; if( i<1 ) { /* * fill entries under diagonal blocks of T with zeros */ if( wantt ) { j = 1; while(j<=n) { if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) { for(i=j+1; i<=n; i++) { h->ptr.pp_double[i][j] = (double)(0); } j = j+1; } else { for(i=j+2; i<=n; i++) { h->ptr.pp_double[i][j] = (double)(0); h->ptr.pp_double[i][j+1] = (double)(0); } j = j+2; } } } /* * Exit */ ae_frame_leave(_state); return; } /* * Perform multiple-shift QR iterations on rows and columns ILO to I * until a submatrix of order at most MAXB splits off at the bottom * because a subdiagonal element has become negligible. */ failflag = ae_true; for(its=0; its<=itn; its++) { /* * Look for a single small subdiagonal element. */ for(k=i; k>=l+1; k--) { tst1 = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); if( ae_fp_eq(tst1,(double)(0)) ) { tst1 = upperhessenberg1norm(h, l, i, l, i, &work, _state); } if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ae_maxreal(ulp*tst1, smlnum, _state)) ) { break; } } l = k; if( l>1 ) { /* * H(L,L-1) is negligible. */ h->ptr.pp_double[l][l-1] = (double)(0); } /* * Exit from loop if a submatrix of order <= MAXB has split off. */ if( l>=i-maxb+1 ) { failflag = ae_false; break; } /* * Now the active submatrix is in rows and columns L to I. If * eigenvalues only are being computed, only the active submatrix * need be transformed. */ if( its==20||its==30 ) { /* * Exceptional shifts. */ for(ii=i-ns+1; ii<=i; ii++) { wr->ptr.p_double[ii] = cnst*(ae_fabs(h->ptr.pp_double[ii][ii-1], _state)+ae_fabs(h->ptr.pp_double[ii][ii], _state)); wi->ptr.p_double[ii] = (double)(0); } } else { /* * Use eigenvalues of trailing submatrix of order NS as shifts. */ copymatrix(h, i-ns+1, i, i-ns+1, i, &s, 1, ns, 1, ns, _state); hsschur_internalauxschur(ae_false, ae_false, ns, 1, ns, &s, &tmpwr, &tmpwi, 1, ns, z, &work, &workv3, &workc1, &works1, &ierr, _state); for(p1=1; p1<=ns; p1++) { wr->ptr.p_double[i-ns+p1] = tmpwr.ptr.p_double[p1]; wi->ptr.p_double[i-ns+p1] = tmpwi.ptr.p_double[p1]; } if( ierr>0 ) { /* * If DLAHQR failed to compute all NS eigenvalues, use the * unconverged diagonal elements as the remaining shifts. */ for(ii=1; ii<=ierr; ii++) { wr->ptr.p_double[i-ns+ii] = s.ptr.pp_double[ii][ii]; wi->ptr.p_double[i-ns+ii] = (double)(0); } } } /* * Form the first column of (G-w(1)) (G-w(2)) . . . (G-w(ns)) * where G is the Hessenberg submatrix H(L:I,L:I) and w is * the vector of shifts (stored in WR and WI). The result is * stored in the local array V. */ v.ptr.p_double[1] = (double)(1); for(ii=2; ii<=ns+1; ii++) { v.ptr.p_double[ii] = (double)(0); } nv = 1; for(j=i-ns+1; j<=i; j++) { if( ae_fp_greater_eq(wi->ptr.p_double[j],(double)(0)) ) { if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) { /* * real shift */ p1 = nv+1; ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &vv, 1, nv, 1.0, &v, 1, nv+1, -wr->ptr.p_double[j], _state); nv = nv+1; } else { if( ae_fp_greater(wi->ptr.p_double[j],(double)(0)) ) { /* * complex conjugate pair of shifts */ p1 = nv+1; ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &v, 1, nv, 1.0, &vv, 1, nv+1, -2*wr->ptr.p_double[j], _state); itemp = vectoridxabsmax(&vv, 1, nv+1, _state); temp = 1/ae_maxreal(ae_fabs(vv.ptr.p_double[itemp], _state), smlnum, _state); p1 = nv+1; ae_v_muld(&vv.ptr.p_double[1], 1, ae_v_len(1,p1), temp); absw = pythag2(wr->ptr.p_double[j], wi->ptr.p_double[j], _state); temp = temp*absw*absw; matrixvectormultiply(h, l, l+nv+1, l, l+nv, ae_false, &vv, 1, nv+1, 1.0, &v, 1, nv+2, temp, _state); nv = nv+2; } } /* * Scale V(1:NV) so that max(abs(V(i))) = 1. If V is zero, * reset it to the unit vector. */ itemp = vectoridxabsmax(&v, 1, nv, _state); temp = ae_fabs(v.ptr.p_double[itemp], _state); if( ae_fp_eq(temp,(double)(0)) ) { v.ptr.p_double[1] = (double)(1); for(ii=2; ii<=nv; ii++) { v.ptr.p_double[ii] = (double)(0); } } else { temp = ae_maxreal(temp, smlnum, _state); vt = 1/temp; ae_v_muld(&v.ptr.p_double[1], 1, ae_v_len(1,nv), vt); } } } /* * Multiple-shift QR step */ for(k=l; k<=i-1; k++) { /* * The first iteration of this loop determines a reflection G * from the vector V and applies it from left and right to H, * thus creating a nonzero bulge below the subdiagonal. * * Each subsequent iteration determines a reflection G to * restore the Hessenberg form in the (K-1)th column, and thus * chases the bulge one step toward the bottom of the active * submatrix. NR is the order of G. */ nr = ae_minint(ns+1, i-k+1, _state); if( k>l ) { p1 = k-1; p2 = k+nr-1; ae_v_move(&v.ptr.p_double[1], 1, &h->ptr.pp_double[k][p1], h->stride, ae_v_len(1,nr)); touchint(&p2, _state); } generatereflection(&v, nr, &tau, _state); if( k>l ) { h->ptr.pp_double[k][k-1] = v.ptr.p_double[1]; for(ii=k+1; ii<=i; ii++) { h->ptr.pp_double[ii][k-1] = (double)(0); } } v.ptr.p_double[1] = (double)(1); /* * Apply G from the left to transform the rows of the matrix in * columns K to I2. */ applyreflectionfromtheleft(h, tau, &v, k, k+nr-1, k, i2, &work, _state); /* * Apply G from the right to transform the columns of the * matrix in rows I1 to min(K+NR,I). */ applyreflectionfromtheright(h, tau, &v, i1, ae_minint(k+nr, i, _state), k, k+nr-1, &work, _state); if( wantz ) { /* * Accumulate transformations in the matrix Z */ applyreflectionfromtheright(z, tau, &v, 1, n, k, k+nr-1, &work, _state); } } } /* * Failure to converge in remaining number of iterations */ if( failflag ) { *info = i; ae_frame_leave(_state); return; } /* * A submatrix of order <= MAXB in rows and columns L to I has split * off. Use the double-shift QR algorithm to handle it. */ hsschur_internalauxschur(wantt, wantz, n, l, i, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); if( *info>0 ) { ae_frame_leave(_state); return; } /* * Decrement number of remaining iterations, and return to start of * the main loop with a new value of I. */ itn = itn-its; i = l-1; } ae_frame_leave(_state); } static void hsschur_internalauxschur(ae_bool wantt, ae_bool wantz, ae_int_t n, ae_int_t ilo, ae_int_t ihi, /* Real */ ae_matrix* h, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, ae_int_t iloz, ae_int_t ihiz, /* Real */ ae_matrix* z, /* Real */ ae_vector* work, /* Real */ ae_vector* workv3, /* Real */ ae_vector* workc1, /* Real */ ae_vector* works1, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t itn; ae_int_t its; ae_int_t j; ae_int_t k; ae_int_t l; ae_int_t m; ae_int_t nh; ae_int_t nr; ae_int_t nz; double ave; double cs; double disc; double h00; double h10; double h11; double h12; double h21; double h22; double h33; double h33s; double h43h34; double h44; double h44s; double s; double smlnum; double sn; double sum; double t1; double t2; double t3; double tst1; double unfl; double v1; double v2; double v3; ae_bool failflag; double dat1; double dat2; ae_int_t p1; double him1im1; double him1i; double hiim1; double hii; double wrim1; double wri; double wiim1; double wii; double ulp; *info = 0; *info = 0; dat1 = 0.75; dat2 = -0.4375; ulp = ae_machineepsilon; /* * Quick return if possible */ if( n==0 ) { return; } if( ilo==ihi ) { wr->ptr.p_double[ilo] = h->ptr.pp_double[ilo][ilo]; wi->ptr.p_double[ilo] = (double)(0); return; } nh = ihi-ilo+1; nz = ihiz-iloz+1; /* * Set machine-dependent constants for the stopping criterion. * If norm(H) <= sqrt(MaxRealNumber), overflow should not occur. */ unfl = ae_minrealnumber; smlnum = unfl*(nh/ulp); /* * I1 and I2 are the indices of the first row and last column of H * to which transformations must be applied. If eigenvalues only are * being computed, I1 and I2 are set inside the main loop. */ i1 = 1; i2 = n; /* * ITN is the total number of QR iterations allowed. */ itn = 30*nh; /* * The main loop begins here. I is the loop index and decreases from * IHI to ILO in steps of 1 or 2. Each iteration of the loop works * with the active submatrix in rows and columns L to I. * Eigenvalues I+1 to IHI have already converged. Either L = ILO or * H(L,L-1) is negligible so that the matrix splits. */ i = ihi; for(;;) { l = ilo; if( i=l+1; k--) { tst1 = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); if( ae_fp_eq(tst1,(double)(0)) ) { tst1 = upperhessenberg1norm(h, l, i, l, i, work, _state); } if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ae_maxreal(ulp*tst1, smlnum, _state)) ) { break; } } l = k; if( l>ilo ) { /* * H(L,L-1) is negligible */ h->ptr.pp_double[l][l-1] = (double)(0); } /* * Exit from loop if a submatrix of order 1 or 2 has split off. */ if( l>=i-1 ) { failflag = ae_false; break; } /* * Now the active submatrix is in rows and columns L to I. If * eigenvalues only are being computed, only the active submatrix * need be transformed. */ if( its==10||its==20 ) { /* * Exceptional shift. */ s = ae_fabs(h->ptr.pp_double[i][i-1], _state)+ae_fabs(h->ptr.pp_double[i-1][i-2], _state); h44 = dat1*s+h->ptr.pp_double[i][i]; h33 = h44; h43h34 = dat2*s*s; } else { /* * Prepare to use Francis' double shift * (i.e. 2nd degree generalized Rayleigh quotient) */ h44 = h->ptr.pp_double[i][i]; h33 = h->ptr.pp_double[i-1][i-1]; h43h34 = h->ptr.pp_double[i][i-1]*h->ptr.pp_double[i-1][i]; s = h->ptr.pp_double[i-1][i-2]*h->ptr.pp_double[i-1][i-2]; disc = (h33-h44)*0.5; disc = disc*disc+h43h34; if( ae_fp_greater(disc,(double)(0)) ) { /* * Real roots: use Wilkinson's shift twice */ disc = ae_sqrt(disc, _state); ave = 0.5*(h33+h44); if( ae_fp_greater(ae_fabs(h33, _state)-ae_fabs(h44, _state),(double)(0)) ) { h33 = h33*h44-h43h34; h44 = h33/(hsschur_extschursign(disc, ave, _state)+ave); } else { h44 = hsschur_extschursign(disc, ave, _state)+ave; } h33 = h44; h43h34 = (double)(0); } } /* * Look for two consecutive small subdiagonal elements. */ for(m=i-2; m>=l; m--) { /* * Determine the effect of starting the double-shift QR * iteration at row M, and see if this would make H(M,M-1) * negligible. */ h11 = h->ptr.pp_double[m][m]; h22 = h->ptr.pp_double[m+1][m+1]; h21 = h->ptr.pp_double[m+1][m]; h12 = h->ptr.pp_double[m][m+1]; h44s = h44-h11; h33s = h33-h11; v1 = (h33s*h44s-h43h34)/h21+h12; v2 = h22-h11-h33s-h44s; v3 = h->ptr.pp_double[m+2][m+1]; s = ae_fabs(v1, _state)+ae_fabs(v2, _state)+ae_fabs(v3, _state); v1 = v1/s; v2 = v2/s; v3 = v3/s; workv3->ptr.p_double[1] = v1; workv3->ptr.p_double[2] = v2; workv3->ptr.p_double[3] = v3; if( m==l ) { break; } h00 = h->ptr.pp_double[m-1][m-1]; h10 = h->ptr.pp_double[m][m-1]; tst1 = ae_fabs(v1, _state)*(ae_fabs(h00, _state)+ae_fabs(h11, _state)+ae_fabs(h22, _state)); if( ae_fp_less_eq(ae_fabs(h10, _state)*(ae_fabs(v2, _state)+ae_fabs(v3, _state)),ulp*tst1) ) { break; } } /* * Double-shift QR step */ for(k=m; k<=i-1; k++) { /* * The first iteration of this loop determines a reflection G * from the vector V and applies it from left and right to H, * thus creating a nonzero bulge below the subdiagonal. * * Each subsequent iteration determines a reflection G to * restore the Hessenberg form in the (K-1)th column, and thus * chases the bulge one step toward the bottom of the active * submatrix. NR is the order of G. */ nr = ae_minint(3, i-k+1, _state); if( k>m ) { for(p1=1; p1<=nr; p1++) { workv3->ptr.p_double[p1] = h->ptr.pp_double[k+p1-1][k-1]; } } generatereflection(workv3, nr, &t1, _state); if( k>m ) { h->ptr.pp_double[k][k-1] = workv3->ptr.p_double[1]; h->ptr.pp_double[k+1][k-1] = (double)(0); if( kptr.pp_double[k+2][k-1] = (double)(0); } } else { if( m>l ) { h->ptr.pp_double[k][k-1] = -h->ptr.pp_double[k][k-1]; } } v2 = workv3->ptr.p_double[2]; t2 = t1*v2; if( nr==3 ) { v3 = workv3->ptr.p_double[3]; t3 = t1*v3; /* * Apply G from the left to transform the rows of the matrix * in columns K to I2. */ for(j=k; j<=i2; j++) { sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]+v3*h->ptr.pp_double[k+2][j]; h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; h->ptr.pp_double[k+2][j] = h->ptr.pp_double[k+2][j]-sum*t3; } /* * Apply G from the right to transform the columns of the * matrix in rows I1 to min(K+3,I). */ for(j=i1; j<=ae_minint(k+3, i, _state); j++) { sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]+v3*h->ptr.pp_double[j][k+2]; h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; h->ptr.pp_double[j][k+2] = h->ptr.pp_double[j][k+2]-sum*t3; } if( wantz ) { /* * Accumulate transformations in the matrix Z */ for(j=iloz; j<=ihiz; j++) { sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]+v3*z->ptr.pp_double[j][k+2]; z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; z->ptr.pp_double[j][k+2] = z->ptr.pp_double[j][k+2]-sum*t3; } } } else { if( nr==2 ) { /* * Apply G from the left to transform the rows of the matrix * in columns K to I2. */ for(j=k; j<=i2; j++) { sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]; h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; } /* * Apply G from the right to transform the columns of the * matrix in rows I1 to min(K+3,I). */ for(j=i1; j<=i; j++) { sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]; h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; } if( wantz ) { /* * Accumulate transformations in the matrix Z */ for(j=iloz; j<=ihiz; j++) { sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]; z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; } } } } } } if( failflag ) { /* * Failure to converge in remaining number of iterations */ *info = i; return; } if( l==i ) { /* * H(I,I-1) is negligible: one eigenvalue has converged. */ wr->ptr.p_double[i] = h->ptr.pp_double[i][i]; wi->ptr.p_double[i] = (double)(0); } else { if( l==i-1 ) { /* * H(I-1,I-2) is negligible: a pair of eigenvalues have converged. * * Transform the 2-by-2 submatrix to standard Schur form, * and compute and store the eigenvalues. */ him1im1 = h->ptr.pp_double[i-1][i-1]; him1i = h->ptr.pp_double[i-1][i]; hiim1 = h->ptr.pp_double[i][i-1]; hii = h->ptr.pp_double[i][i]; hsschur_aux2x2schur(&him1im1, &him1i, &hiim1, &hii, &wrim1, &wiim1, &wri, &wii, &cs, &sn, _state); wr->ptr.p_double[i-1] = wrim1; wi->ptr.p_double[i-1] = wiim1; wr->ptr.p_double[i] = wri; wi->ptr.p_double[i] = wii; h->ptr.pp_double[i-1][i-1] = him1im1; h->ptr.pp_double[i-1][i] = him1i; h->ptr.pp_double[i][i-1] = hiim1; h->ptr.pp_double[i][i] = hii; if( wantt ) { /* * Apply the transformation to the rest of H. */ if( i2>i ) { workc1->ptr.p_double[1] = cs; works1->ptr.p_double[1] = sn; applyrotationsfromtheleft(ae_true, i-1, i, i+1, i2, workc1, works1, h, work, _state); } workc1->ptr.p_double[1] = cs; works1->ptr.p_double[1] = sn; applyrotationsfromtheright(ae_true, i1, i-2, i-1, i, workc1, works1, h, work, _state); } if( wantz ) { /* * Apply the transformation to Z. */ workc1->ptr.p_double[1] = cs; works1->ptr.p_double[1] = sn; applyrotationsfromtheright(ae_true, iloz, iloz+nz-1, i-1, i, workc1, works1, z, work, _state); } } } /* * Decrement number of remaining iterations, and return to start of * the main loop with new value of I. */ itn = itn-its; i = l-1; } } static void hsschur_aux2x2schur(double* a, double* b, double* c, double* d, double* rt1r, double* rt1i, double* rt2r, double* rt2i, double* cs, double* sn, ae_state *_state) { double multpl; double aa; double bb; double bcmax; double bcmis; double cc; double cs1; double dd; double eps; double p; double sab; double sac; double scl; double sigma; double sn1; double tau; double temp; double z; *rt1r = 0; *rt1i = 0; *rt2r = 0; *rt2i = 0; *cs = 0; *sn = 0; multpl = 4.0; eps = ae_machineepsilon; if( ae_fp_eq(*c,(double)(0)) ) { *cs = (double)(1); *sn = (double)(0); } else { if( ae_fp_eq(*b,(double)(0)) ) { /* * Swap rows and columns */ *cs = (double)(0); *sn = (double)(1); temp = *d; *d = *a; *a = temp; *b = -*c; *c = (double)(0); } else { if( ae_fp_eq(*a-(*d),(double)(0))&&hsschur_extschursigntoone(*b, _state)!=hsschur_extschursigntoone(*c, _state) ) { *cs = (double)(1); *sn = (double)(0); } else { temp = *a-(*d); p = 0.5*temp; bcmax = ae_maxreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state); bcmis = ae_minreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state)*hsschur_extschursigntoone(*b, _state)*hsschur_extschursigntoone(*c, _state); scl = ae_maxreal(ae_fabs(p, _state), bcmax, _state); z = p/scl*p+bcmax/scl*bcmis; /* * If Z is of the order of the machine accuracy, postpone the * decision on the nature of eigenvalues */ if( ae_fp_greater_eq(z,multpl*eps) ) { /* * Real eigenvalues. Compute A and D. */ z = p+hsschur_extschursign(ae_sqrt(scl, _state)*ae_sqrt(z, _state), p, _state); *a = *d+z; *d = *d-bcmax/z*bcmis; /* * Compute B and the rotation matrix */ tau = pythag2(*c, z, _state); *cs = z/tau; *sn = *c/tau; *b = *b-(*c); *c = (double)(0); } else { /* * Complex eigenvalues, or real (almost) equal eigenvalues. * Make diagonal elements equal. */ sigma = *b+(*c); tau = pythag2(sigma, temp, _state); *cs = ae_sqrt(0.5*(1+ae_fabs(sigma, _state)/tau), _state); *sn = -p/(tau*(*cs))*hsschur_extschursign((double)(1), sigma, _state); /* * Compute [ AA BB ] = [ A B ] [ CS -SN ] * [ CC DD ] [ C D ] [ SN CS ] */ aa = *a*(*cs)+*b*(*sn); bb = -*a*(*sn)+*b*(*cs); cc = *c*(*cs)+*d*(*sn); dd = -*c*(*sn)+*d*(*cs); /* * Compute [ A B ] = [ CS SN ] [ AA BB ] * [ C D ] [-SN CS ] [ CC DD ] */ *a = aa*(*cs)+cc*(*sn); *b = bb*(*cs)+dd*(*sn); *c = -aa*(*sn)+cc*(*cs); *d = -bb*(*sn)+dd*(*cs); temp = 0.5*(*a+(*d)); *a = temp; *d = temp; if( ae_fp_neq(*c,(double)(0)) ) { if( ae_fp_neq(*b,(double)(0)) ) { if( hsschur_extschursigntoone(*b, _state)==hsschur_extschursigntoone(*c, _state) ) { /* * Real eigenvalues: reduce to upper triangular form */ sab = ae_sqrt(ae_fabs(*b, _state), _state); sac = ae_sqrt(ae_fabs(*c, _state), _state); p = hsschur_extschursign(sab*sac, *c, _state); tau = 1/ae_sqrt(ae_fabs(*b+(*c), _state), _state); *a = temp+p; *d = temp-p; *b = *b-(*c); *c = (double)(0); cs1 = sab*tau; sn1 = sac*tau; temp = *cs*cs1-*sn*sn1; *sn = *cs*sn1+*sn*cs1; *cs = temp; } } else { *b = -*c; *c = (double)(0); temp = *cs; *cs = -*sn; *sn = temp; } } } } } } /* * Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). */ *rt1r = *a; *rt2r = *d; if( ae_fp_eq(*c,(double)(0)) ) { *rt1i = (double)(0); *rt2i = (double)(0); } else { *rt1i = ae_sqrt(ae_fabs(*b, _state), _state)*ae_sqrt(ae_fabs(*c, _state), _state); *rt2i = -*rt1i; } } static double hsschur_extschursign(double a, double b, ae_state *_state) { double result; if( ae_fp_greater_eq(b,(double)(0)) ) { result = ae_fabs(a, _state); } else { result = -ae_fabs(a, _state); } return result; } static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state) { ae_int_t result; if( ae_fp_greater_eq(b,(double)(0)) ) { result = 1; } else { result = -1; } return result; } /************************************************************************* Utility subroutine performing the "safe" solution of system of linear equations with triangular coefficient matrices. The subroutine uses scaling and solves the scaled system A*x=s*b (where s is a scalar value) instead of A*x=b, choosing s so that x can be represented by a floating-point number. The closer the system gets to a singular, the less s is. If the system is singular, s=0 and x contains the non-trivial solution of equation A*x=0. The feature of an algorithm is that it could not cause an overflow or a division by zero regardless of the matrix used as the input. The algorithm can solve systems of equations with upper/lower triangular matrices, with/without unit diagonal, and systems of type A*x=b or A'*x=b (where A' is a transposed matrix A). Input parameters: A - system matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. X - right-hand member of a system. Array whose index ranges within [0..N-1]. IsUpper - matrix type. If it is True, the system matrix is the upper triangular and is located in the corresponding part of matrix A. Trans - problem type. If it is True, the problem to be solved is A'*x=b, otherwise it is A*x=b. Isunit - matrix type. If it is True, the system matrix has a unit diagonal (the elements on the main diagonal are not used in the calculation process), otherwise the matrix is considered to be a general triangular matrix. Output parameters: X - solution. Array whose index ranges within [0..N-1]. S - scaling factor. -- LAPACK auxiliary routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University June 30, 1992 *************************************************************************/ void rmatrixtrsafesolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, double* s, ae_bool isupper, ae_bool istrans, ae_bool isunit, ae_state *_state) { ae_frame _frame_block; ae_bool normin; ae_vector cnorm; ae_matrix a1; ae_vector x1; ae_int_t i; ae_frame_make(_state, &_frame_block); *s = 0; ae_vector_init(&cnorm, 0, DT_REAL, _state); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); /* * From 0-based to 1-based */ normin = ae_false; ae_matrix_set_length(&a1, n+1, n+1, _state); ae_vector_set_length(&x1, n+1, _state); for(i=1; i<=n; i++) { ae_v_move(&a1.ptr.pp_double[i][1], 1, &a->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); } ae_v_move(&x1.ptr.p_double[1], 1, &x->ptr.p_double[0], 1, ae_v_len(1,n)); /* * Solve 1-based */ safesolvetriangular(&a1, n, &x1, s, isupper, istrans, isunit, normin, &cnorm, _state); /* * From 1-based to 0-based */ ae_v_move(&x->ptr.p_double[0], 1, &x1.ptr.p_double[1], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Obsolete 1-based subroutine. See RMatrixTRSafeSolve for 0-based replacement. *************************************************************************/ void safesolvetriangular(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, double* s, ae_bool isupper, ae_bool istrans, ae_bool isunit, ae_bool normin, /* Real */ ae_vector* cnorm, ae_state *_state) { ae_int_t i; ae_int_t imax; ae_int_t j; ae_int_t jfirst; ae_int_t jinc; ae_int_t jlast; ae_int_t jm1; ae_int_t jp1; ae_int_t ip1; ae_int_t im1; ae_int_t k; ae_int_t flg; double v; double vd; double bignum; double grow; double rec; double smlnum; double sumj; double tjj; double tjjs; double tmax; double tscal; double uscal; double xbnd; double xj; double xmax; ae_bool notran; ae_bool upper; ae_bool nounit; *s = 0; upper = isupper; notran = !istrans; nounit = !isunit; /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ tjjs = (double)(0); /* * Quick return if possible */ if( n==0 ) { return; } /* * Determine machine dependent parameters to control overflow. */ smlnum = ae_minrealnumber/(ae_machineepsilon*2); bignum = 1/smlnum; *s = (double)(1); if( !normin ) { ae_vector_set_length(cnorm, n+1, _state); /* * Compute the 1-norm of each column, not including the diagonal. */ if( upper ) { /* * A is upper triangular. */ for(j=1; j<=n; j++) { v = (double)(0); for(k=1; k<=j-1; k++) { v = v+ae_fabs(a->ptr.pp_double[k][j], _state); } cnorm->ptr.p_double[j] = v; } } else { /* * A is lower triangular. */ for(j=1; j<=n-1; j++) { v = (double)(0); for(k=j+1; k<=n; k++) { v = v+ae_fabs(a->ptr.pp_double[k][j], _state); } cnorm->ptr.p_double[j] = v; } cnorm->ptr.p_double[n] = (double)(0); } } /* * Scale the column norms by TSCAL if the maximum element in CNORM is * greater than BIGNUM. */ imax = 1; for(k=2; k<=n; k++) { if( ae_fp_greater(cnorm->ptr.p_double[k],cnorm->ptr.p_double[imax]) ) { imax = k; } } tmax = cnorm->ptr.p_double[imax]; if( ae_fp_less_eq(tmax,bignum) ) { tscal = (double)(1); } else { tscal = 1/(smlnum*tmax); ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), tscal); } /* * Compute a bound on the computed solution vector to see if the * Level 2 BLAS routine DTRSV can be used. */ j = 1; for(k=2; k<=n; k++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[j], _state)) ) { j = k; } } xmax = ae_fabs(x->ptr.p_double[j], _state); xbnd = xmax; if( notran ) { /* * Compute the growth in A * x = b. */ if( upper ) { jfirst = n; jlast = 1; jinc = -1; } else { jfirst = 1; jlast = n; jinc = 1; } if( ae_fp_neq(tscal,(double)(1)) ) { grow = (double)(0); } else { if( nounit ) { /* * A is non-unit triangular. * * Compute GROW = 1/G(j) and XBND = 1/M(j). * Initially, G(0) = max{x(i), i=1,...,n}. */ grow = 1/ae_maxreal(xbnd, smlnum, _state); xbnd = grow; j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Exit the loop if the growth factor is too small. */ if( ae_fp_less_eq(grow,smlnum) ) { break; } /* * M(j) = G(j-1) / abs(A(j,j)) */ tjj = ae_fabs(a->ptr.pp_double[j][j], _state); xbnd = ae_minreal(xbnd, ae_minreal((double)(1), tjj, _state)*grow, _state); if( ae_fp_greater_eq(tjj+cnorm->ptr.p_double[j],smlnum) ) { /* * G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) */ grow = grow*(tjj/(tjj+cnorm->ptr.p_double[j])); } else { /* * G(j) could overflow, set GROW to 0. */ grow = (double)(0); } if( j==jlast ) { grow = xbnd; } j = j+jinc; } } else { /* * A is unit triangular. * * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ grow = ae_minreal((double)(1), 1/ae_maxreal(xbnd, smlnum, _state), _state); j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Exit the loop if the growth factor is too small. */ if( ae_fp_less_eq(grow,smlnum) ) { break; } /* * G(j) = G(j-1)*( 1 + CNORM(j) ) */ grow = grow*(1/(1+cnorm->ptr.p_double[j])); j = j+jinc; } } } } else { /* * Compute the growth in A' * x = b. */ if( upper ) { jfirst = 1; jlast = n; jinc = 1; } else { jfirst = n; jlast = 1; jinc = -1; } if( ae_fp_neq(tscal,(double)(1)) ) { grow = (double)(0); } else { if( nounit ) { /* * A is non-unit triangular. * * Compute GROW = 1/G(j) and XBND = 1/M(j). * Initially, M(0) = max{x(i), i=1,...,n}. */ grow = 1/ae_maxreal(xbnd, smlnum, _state); xbnd = grow; j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Exit the loop if the growth factor is too small. */ if( ae_fp_less_eq(grow,smlnum) ) { break; } /* * G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) */ xj = 1+cnorm->ptr.p_double[j]; grow = ae_minreal(grow, xbnd/xj, _state); /* * M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) */ tjj = ae_fabs(a->ptr.pp_double[j][j], _state); if( ae_fp_greater(xj,tjj) ) { xbnd = xbnd*(tjj/xj); } if( j==jlast ) { grow = ae_minreal(grow, xbnd, _state); } j = j+jinc; } } else { /* * A is unit triangular. * * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. */ grow = ae_minreal((double)(1), 1/ae_maxreal(xbnd, smlnum, _state), _state); j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Exit the loop if the growth factor is too small. */ if( ae_fp_less_eq(grow,smlnum) ) { break; } /* * G(j) = ( 1 + CNORM(j) )*G(j-1) */ xj = 1+cnorm->ptr.p_double[j]; grow = grow/xj; j = j+jinc; } } } } if( ae_fp_greater(grow*tscal,smlnum) ) { /* * Use the Level 2 BLAS solve if the reciprocal of the bound on * elements of X is not too small. */ if( (upper&¬ran)||(!upper&&!notran) ) { if( nounit ) { vd = a->ptr.pp_double[n][n]; } else { vd = (double)(1); } x->ptr.p_double[n] = x->ptr.p_double[n]/vd; for(i=n-1; i>=1; i--) { ip1 = i+1; if( upper ) { v = ae_v_dotproduct(&a->ptr.pp_double[i][ip1], 1, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); } else { v = ae_v_dotproduct(&a->ptr.pp_double[ip1][i], a->stride, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); } if( nounit ) { vd = a->ptr.pp_double[i][i]; } else { vd = (double)(1); } x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; } } else { if( nounit ) { vd = a->ptr.pp_double[1][1]; } else { vd = (double)(1); } x->ptr.p_double[1] = x->ptr.p_double[1]/vd; for(i=2; i<=n; i++) { im1 = i-1; if( upper ) { v = ae_v_dotproduct(&a->ptr.pp_double[1][i], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); } else { v = ae_v_dotproduct(&a->ptr.pp_double[i][1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); } if( nounit ) { vd = a->ptr.pp_double[i][i]; } else { vd = (double)(1); } x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; } } } else { /* * Use a Level 1 BLAS solve, scaling intermediate results. */ if( ae_fp_greater(xmax,bignum) ) { /* * Scale X so that its components are less than or equal to * BIGNUM in absolute value. */ *s = bignum/xmax; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), *s); xmax = bignum; } if( notran ) { /* * Solve A * x = b */ j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Compute x(j) = b(j) / A(j,j), scaling x if necessary. */ xj = ae_fabs(x->ptr.p_double[j], _state); flg = 0; if( nounit ) { tjjs = a->ptr.pp_double[j][j]*tscal; } else { tjjs = tscal; if( ae_fp_eq(tscal,(double)(1)) ) { flg = 100; } } if( flg!=100 ) { tjj = ae_fabs(tjjs, _state); if( ae_fp_greater(tjj,smlnum) ) { /* * abs(A(j,j)) > SMLNUM: */ if( ae_fp_less(tjj,(double)(1)) ) { if( ae_fp_greater(xj,tjj*bignum) ) { /* * Scale x by 1/b(j). */ rec = 1/xj; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; xmax = xmax*rec; } } x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; xj = ae_fabs(x->ptr.p_double[j], _state); } else { if( ae_fp_greater(tjj,(double)(0)) ) { /* * 0 < abs(A(j,j)) <= SMLNUM: */ if( ae_fp_greater(xj,tjj*bignum) ) { /* * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM * to avoid overflow when dividing by A(j,j). */ rec = tjj*bignum/xj; if( ae_fp_greater(cnorm->ptr.p_double[j],(double)(1)) ) { /* * Scale by 1/CNORM(j) to avoid overflow when * multiplying x(j) times column j. */ rec = rec/cnorm->ptr.p_double[j]; } ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; xmax = xmax*rec; } x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; xj = ae_fabs(x->ptr.p_double[j], _state); } else { /* * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and * scale = 0, and compute a solution to A*x = 0. */ for(i=1; i<=n; i++) { x->ptr.p_double[i] = (double)(0); } x->ptr.p_double[j] = (double)(1); xj = (double)(1); *s = (double)(0); xmax = (double)(0); } } } /* * Scale x if necessary to avoid overflow when adding a * multiple of column j of A. */ if( ae_fp_greater(xj,(double)(1)) ) { rec = 1/xj; if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xmax)*rec) ) { /* * Scale x by 1/(2*abs(x(j))). */ rec = rec*0.5; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; } } else { if( ae_fp_greater(xj*cnorm->ptr.p_double[j],bignum-xmax) ) { /* * Scale x by 1/2. */ ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), 0.5); *s = *s*0.5; } } if( upper ) { if( j>1 ) { /* * Compute the update * x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) */ v = x->ptr.p_double[j]*tscal; jm1 = j-1; ae_v_subd(&x->ptr.p_double[1], 1, &a->ptr.pp_double[1][j], a->stride, ae_v_len(1,jm1), v); i = 1; for(k=2; k<=j-1; k++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) { i = k; } } xmax = ae_fabs(x->ptr.p_double[i], _state); } } else { if( jptr.p_double[j]*tscal; ae_v_subd(&x->ptr.p_double[jp1], 1, &a->ptr.pp_double[jp1][j], a->stride, ae_v_len(jp1,n), v); i = j+1; for(k=j+2; k<=n; k++) { if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) { i = k; } } xmax = ae_fabs(x->ptr.p_double[i], _state); } } j = j+jinc; } } else { /* * Solve A' * x = b */ j = jfirst; while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) { /* * Compute x(j) = b(j) - sum A(k,j)*x(k). * k<>j */ xj = ae_fabs(x->ptr.p_double[j], _state); uscal = tscal; rec = 1/ae_maxreal(xmax, (double)(1), _state); if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xj)*rec) ) { /* * If x(j) could overflow, scale x by 1/(2*XMAX). */ rec = rec*0.5; if( nounit ) { tjjs = a->ptr.pp_double[j][j]*tscal; } else { tjjs = tscal; } tjj = ae_fabs(tjjs, _state); if( ae_fp_greater(tjj,(double)(1)) ) { /* * Divide by A(j,j) when scaling x if A(j,j) > 1. */ rec = ae_minreal((double)(1), rec*tjj, _state); uscal = uscal/tjjs; } if( ae_fp_less(rec,(double)(1)) ) { ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; xmax = xmax*rec; } } sumj = (double)(0); if( ae_fp_eq(uscal,(double)(1)) ) { /* * If the scaling needed for A in the dot product is 1, * call DDOT to perform the dot product. */ if( upper ) { if( j>1 ) { jm1 = j-1; sumj = ae_v_dotproduct(&a->ptr.pp_double[1][j], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,jm1)); } else { sumj = (double)(0); } } else { if( jptr.pp_double[jp1][j], a->stride, &x->ptr.p_double[jp1], 1, ae_v_len(jp1,n)); } } } else { /* * Otherwise, use in-line code for the dot product. */ if( upper ) { for(i=1; i<=j-1; i++) { v = a->ptr.pp_double[i][j]*uscal; sumj = sumj+v*x->ptr.p_double[i]; } } else { if( jptr.pp_double[i][j]*uscal; sumj = sumj+v*x->ptr.p_double[i]; } } } } if( ae_fp_eq(uscal,tscal) ) { /* * Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) * was not used to scale the dotproduct. */ x->ptr.p_double[j] = x->ptr.p_double[j]-sumj; xj = ae_fabs(x->ptr.p_double[j], _state); flg = 0; if( nounit ) { tjjs = a->ptr.pp_double[j][j]*tscal; } else { tjjs = tscal; if( ae_fp_eq(tscal,(double)(1)) ) { flg = 150; } } /* * Compute x(j) = x(j) / A(j,j), scaling if necessary. */ if( flg!=150 ) { tjj = ae_fabs(tjjs, _state); if( ae_fp_greater(tjj,smlnum) ) { /* * abs(A(j,j)) > SMLNUM: */ if( ae_fp_less(tjj,(double)(1)) ) { if( ae_fp_greater(xj,tjj*bignum) ) { /* * Scale X by 1/abs(x(j)). */ rec = 1/xj; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; xmax = xmax*rec; } } x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; } else { if( ae_fp_greater(tjj,(double)(0)) ) { /* * 0 < abs(A(j,j)) <= SMLNUM: */ if( ae_fp_greater(xj,tjj*bignum) ) { /* * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ rec = tjj*bignum/xj; ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); *s = *s*rec; xmax = xmax*rec; } x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; } else { /* * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and * scale = 0, and compute a solution to A'*x = 0. */ for(i=1; i<=n; i++) { x->ptr.p_double[i] = (double)(0); } x->ptr.p_double[j] = (double)(1); *s = (double)(0); xmax = (double)(0); } } } } else { /* * Compute x(j) := x(j) / A(j,j) - sumj if the dot * product has already been divided by 1/A(j,j). */ x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs-sumj; } xmax = ae_maxreal(xmax, ae_fabs(x->ptr.p_double[j], _state), _state); j = j+jinc; } } *s = *s/tscal; } /* * Scale the column norms by 1/TSCAL for return. */ if( ae_fp_neq(tscal,(double)(1)) ) { v = 1/tscal; ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), v); } } /************************************************************************* Real implementation of CMatrixScaledTRSafeSolve -- ALGLIB routine -- 21.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool rmatrixscaledtrsafesolve(/* Real */ ae_matrix* a, double sa, ae_int_t n, /* Real */ ae_vector* x, ae_bool isupper, ae_int_t trans, ae_bool isunit, double maxgrowth, ae_state *_state) { ae_frame _frame_block; double lnmax; double nrmb; double nrmx; ae_int_t i; ae_complex alpha; ae_complex beta; double vr; ae_complex cx; ae_vector tmp; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_assert(n>0, "RMatrixTRSafeSolve: incorrect N!", _state); ae_assert(trans==0||trans==1, "RMatrixTRSafeSolve: incorrect Trans!", _state); result = ae_true; lnmax = ae_log(ae_maxrealnumber, _state); /* * Quick return if possible */ if( n<=0 ) { ae_frame_leave(_state); return result; } /* * Load norms: right part and X */ nrmb = (double)(0); for(i=0; i<=n-1; i++) { nrmb = ae_maxreal(nrmb, ae_fabs(x->ptr.p_double[i], _state), _state); } nrmx = (double)(0); /* * Solve */ ae_vector_set_length(&tmp, n, _state); result = ae_true; if( isupper&&trans==0 ) { /* * U*x = b */ for(i=n-1; i>=0; i--) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); } if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); vr = ae_v_dotproduct(&tmp.ptr.p_double[i+1], 1, &x->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); beta = ae_complex_from_d(x->ptr.p_double[i]-vr); } else { beta = ae_complex_from_d(x->ptr.p_double[i]); } /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_double[i] = cx.x; } ae_frame_leave(_state); return result; } if( !isupper&&trans==0 ) { /* * L*x = b */ for(i=0; i<=n-1; i++) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); } if( i>0 ) { ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); vr = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,i-1)); beta = ae_complex_from_d(x->ptr.p_double[i]-vr); } else { beta = ae_complex_from_d(x->ptr.p_double[i]); } /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_double[i] = cx.x; } ae_frame_leave(_state); return result; } if( isupper&&trans==1 ) { /* * U^T*x = b */ for(i=0; i<=n-1; i++) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); } beta = ae_complex_from_d(x->ptr.p_double[i]); /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_double[i] = cx.x; /* * update the rest of right part */ if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); ae_v_subd(&x->ptr.p_double[i+1], 1, &tmp.ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), vr); } } ae_frame_leave(_state); return result; } if( !isupper&&trans==1 ) { /* * L^T*x = b */ for(i=n-1; i>=0; i--) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); } beta = ae_complex_from_d(x->ptr.p_double[i]); /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_double[i] = cx.x; /* * update the rest of right part */ if( i>0 ) { vr = cx.x; ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); ae_v_subd(&x->ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1), vr); } } ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Internal subroutine for safe solution of SA*op(A)=b where A is NxN upper/lower triangular/unitriangular matrix, op(A) is either identity transform, transposition or Hermitian transposition, SA is a scaling factor such that max(|SA*A[i,j]|) is close to 1.0 in magnutude. This subroutine limits relative growth of solution (in inf-norm) by MaxGrowth, returning False if growth exceeds MaxGrowth. Degenerate or near-degenerate matrices are handled correctly (False is returned) as long as MaxGrowth is significantly less than MaxRealNumber/norm(b). -- ALGLIB routine -- 21.01.2010 Bochkanov Sergey *************************************************************************/ ae_bool cmatrixscaledtrsafesolve(/* Complex */ ae_matrix* a, double sa, ae_int_t n, /* Complex */ ae_vector* x, ae_bool isupper, ae_int_t trans, ae_bool isunit, double maxgrowth, ae_state *_state) { ae_frame _frame_block; double lnmax; double nrmb; double nrmx; ae_int_t i; ae_complex alpha; ae_complex beta; ae_complex vc; ae_vector tmp; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_COMPLEX, _state); ae_assert(n>0, "CMatrixTRSafeSolve: incorrect N!", _state); ae_assert((trans==0||trans==1)||trans==2, "CMatrixTRSafeSolve: incorrect Trans!", _state); result = ae_true; lnmax = ae_log(ae_maxrealnumber, _state); /* * Quick return if possible */ if( n<=0 ) { ae_frame_leave(_state); return result; } /* * Load norms: right part and X */ nrmb = (double)(0); for(i=0; i<=n-1; i++) { nrmb = ae_maxreal(nrmb, ae_c_abs(x->ptr.p_complex[i], _state), _state); } nrmx = (double)(0); /* * Solve */ ae_vector_set_length(&tmp, n, _state); result = ae_true; if( isupper&&trans==0 ) { /* * U*x = b */ for(i=n-1; i>=0; i--) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); } if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); vc = ae_v_cdotproduct(&tmp.ptr.p_complex[i+1], 1, "N", &x->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); beta = ae_c_sub(x->ptr.p_complex[i],vc); } else { beta = x->ptr.p_complex[i]; } /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; } ae_frame_leave(_state); return result; } if( !isupper&&trans==0 ) { /* * L*x = b */ for(i=0; i<=n-1; i++) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); } if( i>0 ) { ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); vc = ae_v_cdotproduct(&tmp.ptr.p_complex[0], 1, "N", &x->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); beta = ae_c_sub(x->ptr.p_complex[i],vc); } else { beta = x->ptr.p_complex[i]; } /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; } ae_frame_leave(_state); return result; } if( isupper&&trans==1 ) { /* * U^T*x = b */ for(i=0; i<=n-1; i++) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); } beta = x->ptr.p_complex[i]; /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; /* * update the rest of right part */ if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); } } ae_frame_leave(_state); return result; } if( !isupper&&trans==1 ) { /* * L^T*x = b */ for(i=n-1; i>=0; i--) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); } beta = x->ptr.p_complex[i]; /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; /* * update the rest of right part */ if( i>0 ) { ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); } } ae_frame_leave(_state); return result; } if( isupper&&trans==2 ) { /* * U^H*x = b */ for(i=0; i<=n-1; i++) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); } beta = x->ptr.p_complex[i]; /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; /* * update the rest of right part */ if( iptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), sa); ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); } } ae_frame_leave(_state); return result; } if( !isupper&&trans==2 ) { /* * L^T*x = b */ for(i=n-1; i>=0; i--) { /* * Task is reduced to alpha*x[i] = beta */ if( isunit ) { alpha = ae_complex_from_d(sa); } else { alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); } beta = x->ptr.p_complex[i]; /* * solve alpha*x[i] = beta */ result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); if( !result ) { ae_frame_leave(_state); return result; } x->ptr.p_complex[i] = vc; /* * update the rest of right part */ if( i>0 ) { ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), sa); ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); } } ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* complex basic solver-updater for reduced linear system alpha*x[i] = beta solves this equation and updates it in overlfow-safe manner (keeping track of relative growth of solution). Parameters: Alpha - alpha Beta - beta LnMax - precomputed Ln(MaxRealNumber) BNorm - inf-norm of b (right part of original system) MaxGrowth- maximum growth of norm(x) relative to norm(b) XNorm - inf-norm of other components of X (which are already processed) it is updated by CBasicSolveAndUpdate. X - solution -- ALGLIB routine -- 26.01.2009 Bochkanov Sergey *************************************************************************/ static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, ae_complex beta, double lnmax, double bnorm, double maxgrowth, double* xnorm, ae_complex* x, ae_state *_state) { double v; ae_bool result; x->x = 0; x->y = 0; result = ae_false; if( ae_c_eq_d(alpha,(double)(0)) ) { return result; } if( ae_c_neq_d(beta,(double)(0)) ) { /* * alpha*x[i]=beta */ v = ae_log(ae_c_abs(beta, _state), _state)-ae_log(ae_c_abs(alpha, _state), _state); if( ae_fp_greater(v,lnmax) ) { return result; } *x = ae_c_div(beta,alpha); } else { /* * alpha*x[i]=0 */ *x = ae_complex_from_i(0); } /* * update NrmX, test growth limit */ *xnorm = ae_maxreal(*xnorm, ae_c_abs(*x, _state), _state); if( ae_fp_greater(*xnorm,maxgrowth*bnorm) ) { return result; } result = ae_true; return result; } /************************************************************************* Prepares HPC compuations of chunked gradient with HPCChunkedGradient(). You have to call this function before calling HPCChunkedGradient() for a new set of weights. You have to call it only once, see example below: HOW TO PROCESS DATASET WITH THIS FUNCTION: Grad:=0 HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) foreach chunk-of-dataset do HPCChunkedGradient(...) HPCFinalizeChunkedGradient(Buf, Grad) *************************************************************************/ void hpcpreparechunkedgradient(/* Real */ ae_vector* weights, ae_int_t wcount, ae_int_t ntotal, ae_int_t nin, ae_int_t nout, mlpbuffers* buf, ae_state *_state) { ae_int_t i; ae_int_t batch4size; ae_int_t chunksize; chunksize = 4; batch4size = 3*chunksize*ntotal+chunksize*(2*nout+1); if( buf->xy.rowsxy.colsxy, chunksize, nin+nout, _state); } if( buf->xy2.rowsxy2.colsxy2, chunksize, nin+nout, _state); } if( buf->xyrow.cntxyrow, nin+nout, _state); } if( buf->x.cntx, nin, _state); } if( buf->y.cnty, nout, _state); } if( buf->desiredy.cntdesiredy, nout, _state); } if( buf->batch4buf.cntbatch4buf, batch4size, _state); } if( buf->hpcbuf.cnthpcbuf, wcount, _state); } if( buf->g.cntg, wcount, _state); } if( !hpccores_hpcpreparechunkedgradientx(weights, wcount, &buf->hpcbuf, _state) ) { for(i=0; i<=wcount-1; i++) { buf->hpcbuf.ptr.p_double[i] = 0.0; } } buf->wcount = wcount; buf->ntotal = ntotal; buf->nin = nin; buf->nout = nout; buf->chunksize = chunksize; } /************************************************************************* Finalizes HPC compuations of chunked gradient with HPCChunkedGradient(). You have to call this function after calling HPCChunkedGradient() for a new set of weights. You have to call it only once, see example below: HOW TO PROCESS DATASET WITH THIS FUNCTION: Grad:=0 HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) foreach chunk-of-dataset do HPCChunkedGradient(...) HPCFinalizeChunkedGradient(Buf, Grad) *************************************************************************/ void hpcfinalizechunkedgradient(mlpbuffers* buf, /* Real */ ae_vector* grad, ae_state *_state) { ae_int_t i; if( !hpccores_hpcfinalizechunkedgradientx(&buf->hpcbuf, buf->wcount, grad, _state) ) { for(i=0; i<=buf->wcount-1; i++) { grad->ptr.p_double[i] = grad->ptr.p_double[i]+buf->hpcbuf.ptr.p_double[i]; } } } /************************************************************************* Fast kernel for chunked gradient. *************************************************************************/ ae_bool hpcchunkedgradient(/* Real */ ae_vector* weights, /* Integer */ ae_vector* structinfo, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, double* e, ae_bool naturalerrorfunc, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SSE2 ae_bool result; result = ae_false; return result; #else return _ialglib_i_hpcchunkedgradient(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc); #endif } /************************************************************************* Fast kernel for chunked processing. *************************************************************************/ ae_bool hpcchunkedprocess(/* Real */ ae_vector* weights, /* Integer */ ae_vector* structinfo, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SSE2 ae_bool result; result = ae_false; return result; #else return _ialglib_i_hpcchunkedprocess(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf); #endif } /************************************************************************* Stub function. -- ALGLIB routine -- 14.06.2013 Bochkanov Sergey *************************************************************************/ static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ ae_vector* weights, ae_int_t wcount, /* Real */ ae_vector* hpcbuf, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SSE2 ae_bool result; result = ae_false; return result; #else return _ialglib_i_hpcpreparechunkedgradientx(weights, wcount, hpcbuf); #endif } /************************************************************************* Stub function. -- ALGLIB routine -- 14.06.2013 Bochkanov Sergey *************************************************************************/ static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ ae_vector* buf, ae_int_t wcount, /* Real */ ae_vector* grad, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SSE2 ae_bool result; result = ae_false; return result; #else return _ialglib_i_hpcfinalizechunkedgradientx(buf, wcount, grad); #endif } void _mlpbuffers_init(void* _p, ae_state *_state) { mlpbuffers *p = (mlpbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->batch4buf, 0, DT_REAL, _state); ae_vector_init(&p->hpcbuf, 0, DT_REAL, _state); ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state); ae_matrix_init(&p->xy2, 0, 0, DT_REAL, _state); ae_vector_init(&p->xyrow, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_vector_init(&p->desiredy, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); } void _mlpbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { mlpbuffers *dst = (mlpbuffers*)_dst; mlpbuffers *src = (mlpbuffers*)_src; dst->chunksize = src->chunksize; dst->ntotal = src->ntotal; dst->nin = src->nin; dst->nout = src->nout; dst->wcount = src->wcount; ae_vector_init_copy(&dst->batch4buf, &src->batch4buf, _state); ae_vector_init_copy(&dst->hpcbuf, &src->hpcbuf, _state); ae_matrix_init_copy(&dst->xy, &src->xy, _state); ae_matrix_init_copy(&dst->xy2, &src->xy2, _state); ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state); ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->desiredy, &src->desiredy, _state); dst->e = src->e; ae_vector_init_copy(&dst->g, &src->g, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); } void _mlpbuffers_clear(void* _p) { mlpbuffers *p = (mlpbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->batch4buf); ae_vector_clear(&p->hpcbuf); ae_matrix_clear(&p->xy); ae_matrix_clear(&p->xy2); ae_vector_clear(&p->xyrow); ae_vector_clear(&p->x); ae_vector_clear(&p->y); ae_vector_clear(&p->desiredy); ae_vector_clear(&p->g); ae_vector_clear(&p->tmp0); } void _mlpbuffers_destroy(void* _p) { mlpbuffers *p = (mlpbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->batch4buf); ae_vector_destroy(&p->hpcbuf); ae_matrix_destroy(&p->xy); ae_matrix_destroy(&p->xy2); ae_vector_destroy(&p->xyrow); ae_vector_destroy(&p->x); ae_vector_destroy(&p->y); ae_vector_destroy(&p->desiredy); ae_vector_destroy(&p->g); ae_vector_destroy(&p->tmp0); } /************************************************************************* More precise dot-product. Absolute error of subroutine result is about 1 ulp of max(MX,V), where: MX = max( |a[i]*b[i]| ) V = |(a,b)| INPUT PARAMETERS A - array[0..N-1], vector 1 B - array[0..N-1], vector 2 N - vectors length, N<2^29. Temp - array[0..N-1], pre-allocated temporary storage OUTPUT PARAMETERS R - (A,B) RErr - estimate of error. This estimate accounts for both errors during calculation of (A,B) and errors introduced by rounding of A and B to fit in double (about 1 ulp). -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ void xdot(/* Real */ ae_vector* a, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* temp, double* r, double* rerr, ae_state *_state) { ae_int_t i; double mx; double v; *r = 0; *rerr = 0; /* * special cases: * * N=0 */ if( n==0 ) { *r = (double)(0); *rerr = (double)(0); return; } mx = (double)(0); for(i=0; i<=n-1; i++) { v = a->ptr.p_double[i]*b->ptr.p_double[i]; temp->ptr.p_double[i] = v; mx = ae_maxreal(mx, ae_fabs(v, _state), _state); } if( ae_fp_eq(mx,(double)(0)) ) { *r = (double)(0); *rerr = (double)(0); return; } xblas_xsum(temp, mx, n, r, rerr, _state); } /************************************************************************* More precise complex dot-product. Absolute error of subroutine result is about 1 ulp of max(MX,V), where: MX = max( |a[i]*b[i]| ) V = |(a,b)| INPUT PARAMETERS A - array[0..N-1], vector 1 B - array[0..N-1], vector 2 N - vectors length, N<2^29. Temp - array[0..2*N-1], pre-allocated temporary storage OUTPUT PARAMETERS R - (A,B) RErr - estimate of error. This estimate accounts for both errors during calculation of (A,B) and errors introduced by rounding of A and B to fit in double (about 1 ulp). -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void xcdot(/* Complex */ ae_vector* a, /* Complex */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* temp, ae_complex* r, double* rerr, ae_state *_state) { ae_int_t i; double mx; double v; double rerrx; double rerry; r->x = 0; r->y = 0; *rerr = 0; /* * special cases: * * N=0 */ if( n==0 ) { *r = ae_complex_from_i(0); *rerr = (double)(0); return; } /* * calculate real part */ mx = (double)(0); for(i=0; i<=n-1; i++) { v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].x; temp->ptr.p_double[2*i+0] = v; mx = ae_maxreal(mx, ae_fabs(v, _state), _state); v = -a->ptr.p_complex[i].y*b->ptr.p_complex[i].y; temp->ptr.p_double[2*i+1] = v; mx = ae_maxreal(mx, ae_fabs(v, _state), _state); } if( ae_fp_eq(mx,(double)(0)) ) { r->x = (double)(0); rerrx = (double)(0); } else { xblas_xsum(temp, mx, 2*n, &r->x, &rerrx, _state); } /* * calculate imaginary part */ mx = (double)(0); for(i=0; i<=n-1; i++) { v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].y; temp->ptr.p_double[2*i+0] = v; mx = ae_maxreal(mx, ae_fabs(v, _state), _state); v = a->ptr.p_complex[i].y*b->ptr.p_complex[i].x; temp->ptr.p_double[2*i+1] = v; mx = ae_maxreal(mx, ae_fabs(v, _state), _state); } if( ae_fp_eq(mx,(double)(0)) ) { r->y = (double)(0); rerry = (double)(0); } else { xblas_xsum(temp, mx, 2*n, &r->y, &rerry, _state); } /* * total error */ if( ae_fp_eq(rerrx,(double)(0))&&ae_fp_eq(rerry,(double)(0)) ) { *rerr = (double)(0); } else { *rerr = ae_maxreal(rerrx, rerry, _state)*ae_sqrt(1+ae_sqr(ae_minreal(rerrx, rerry, _state)/ae_maxreal(rerrx, rerry, _state), _state), _state); } } /************************************************************************* Internal subroutine for extra-precise calculation of SUM(w[i]). INPUT PARAMETERS: W - array[0..N-1], values to be added W is modified during calculations. MX - max(W[i]) N - array size OUTPUT PARAMETERS: R - SUM(w[i]) RErr- error estimate for R -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ static void xblas_xsum(/* Real */ ae_vector* w, double mx, ae_int_t n, double* r, double* rerr, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t ks; double v; double s; double ln2; double chunk; double invchunk; ae_bool allzeros; *r = 0; *rerr = 0; /* * special cases: * * N=0 * * N is too large to use integer arithmetics */ if( n==0 ) { *r = (double)(0); *rerr = (double)(0); return; } if( ae_fp_eq(mx,(double)(0)) ) { *r = (double)(0); *rerr = (double)(0); return; } ae_assert(n<536870912, "XDot: N is too large!", _state); /* * Prepare */ ln2 = ae_log((double)(2), _state); *rerr = mx*ae_machineepsilon; /* * 1. find S such that 0.5<=S*MX<1 * 2. multiply W by S, so task is normalized in some sense * 3. S:=1/S so we can obtain original vector multiplying by S */ k = ae_round(ae_log(mx, _state)/ln2, _state); s = xblas_xfastpow((double)(2), -k, _state); while(ae_fp_greater_eq(s*mx,(double)(1))) { s = 0.5*s; } while(ae_fp_less(s*mx,0.5)) { s = 2*s; } ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), s); s = 1/s; /* * find Chunk=2^M such that N*Chunk<2^29 * * we have chosen upper limit (2^29) with enough space left * to tolerate possible problems with rounding and N's close * to the limit, so we don't want to be very strict here. */ k = ae_trunc(ae_log((double)536870912/(double)n, _state)/ln2, _state); chunk = xblas_xfastpow((double)(2), k, _state); if( ae_fp_less(chunk,(double)(2)) ) { chunk = (double)(2); } invchunk = 1/chunk; /* * calculate result */ *r = (double)(0); ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), chunk); for(;;) { s = s*invchunk; allzeros = ae_true; ks = 0; for(i=0; i<=n-1; i++) { v = w->ptr.p_double[i]; k = ae_trunc(v, _state); if( ae_fp_neq(v,(double)(k)) ) { allzeros = ae_false; } w->ptr.p_double[i] = chunk*(v-k); ks = ks+k; } *r = *r+s*ks; v = ae_fabs(*r, _state); if( allzeros||ae_fp_eq(s*n+mx,mx) ) { break; } } /* * correct error */ *rerr = ae_maxreal(*rerr, ae_fabs(*r, _state)*ae_machineepsilon, _state); } /************************************************************************* Fast Pow -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state) { double result; result = (double)(0); if( n>0 ) { if( n%2==0 ) { result = ae_sqr(xblas_xfastpow(r, n/2, _state), _state); } else { result = r*xblas_xfastpow(r, n-1, _state); } return result; } if( n==0 ) { result = (double)(1); } if( n<0 ) { result = xblas_xfastpow(1/r, -n, _state); } return result; } /************************************************************************* Normalizes direction/step pair: makes |D|=1, scales Stp. If |D|=0, it returns, leavind D/Stp unchanged. -- ALGLIB -- Copyright 01.04.2010 by Bochkanov Sergey *************************************************************************/ void linminnormalized(/* Real */ ae_vector* d, double* stp, ae_int_t n, ae_state *_state) { double mx; double s; ae_int_t i; /* * first, scale D to avoid underflow/overflow durng squaring */ mx = (double)(0); for(i=0; i<=n-1; i++) { mx = ae_maxreal(mx, ae_fabs(d->ptr.p_double[i], _state), _state); } if( ae_fp_eq(mx,(double)(0)) ) { return; } s = 1/mx; ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); *stp = *stp/s; /* * normalize D */ s = ae_v_dotproduct(&d->ptr.p_double[0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); s = 1/ae_sqrt(s, _state); ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); *stp = *stp/s; } /************************************************************************* THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT DECREASE CONDITION AND A CURVATURE CONDITION. AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT DECREASE CONDITION F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), AND THE CURVATURE CONDITION ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. :::::::::::::IMPORTANT NOTES::::::::::::: NOTE 1: This routine guarantees that it will stop at the last point where function value was calculated. It won't make several additional function evaluations after finding good point. So if you store function evaluations requested by this routine, you can be sure that last one is the point where we've stopped. NOTE 2: when 0initial_point - after rounding to machine precision ::::::::::::::::::::::::::::::::::::::::: PARAMETERS DESCRIPRION STAGE IS ZERO ON FIRST CALL, ZERO ON FINAL EXIT N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES. X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S. F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT IT CONTAINS THE VALUE OF F AT X + STP*S. G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X. ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S. S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION. STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE. FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE SATISFIED. XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND UPPER BOUNDS FOR THE STEP. MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION. INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS: INFO = 0 IMPROPER INPUT PARAMETERS. INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION HOLD. INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV. INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN. INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX. INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS. THERE MAY NOT BE A STEP WHICH SATISFIES THE SUFFICIENT DECREASE AND CURVATURE CONDITIONS. TOLERANCES MAY BE TOO SMALL. NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN. WA IS A WORK ARRAY OF LENGTH N. ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983 JORGE J. MORE', DAVID J. THUENTE *************************************************************************/ void mcsrch(ae_int_t n, /* Real */ ae_vector* x, double* f, /* Real */ ae_vector* g, /* Real */ ae_vector* s, double* stp, double stpmax, double gtol, ae_int_t* info, ae_int_t* nfev, /* Real */ ae_vector* wa, linminstate* state, ae_int_t* stage, ae_state *_state) { ae_int_t i; double v; double p5; double p66; double zero; /* * init */ p5 = 0.5; p66 = 0.66; state->xtrapf = 4.0; zero = (double)(0); if( ae_fp_eq(stpmax,(double)(0)) ) { stpmax = linmin_defstpmax; } if( ae_fp_less(*stp,linmin_stpmin) ) { *stp = linmin_stpmin; } if( ae_fp_greater(*stp,stpmax) ) { *stp = stpmax; } /* * Main cycle */ for(;;) { if( *stage==0 ) { /* * NEXT */ *stage = 2; continue; } if( *stage==2 ) { state->infoc = 1; *info = 0; /* * CHECK THE INPUT PARAMETERS FOR ERRORS. */ if( ae_fp_less(stpmax,linmin_stpmin)&&ae_fp_greater(stpmax,(double)(0)) ) { *info = 5; *stp = stpmax; *stage = 0; return; } if( ((((((n<=0||ae_fp_less_eq(*stp,(double)(0)))||ae_fp_less(linmin_ftol,(double)(0)))||ae_fp_less(gtol,zero))||ae_fp_less(linmin_xtol,zero))||ae_fp_less(linmin_stpmin,zero))||ae_fp_less(stpmax,linmin_stpmin))||linmin_maxfev<=0 ) { *stage = 0; return; } /* * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION * AND CHECK THAT S IS A DESCENT DIRECTION. */ v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->dginit = v; if( ae_fp_greater_eq(state->dginit,(double)(0)) ) { *stage = 0; return; } /* * INITIALIZE LOCAL VARIABLES. */ state->brackt = ae_false; state->stage1 = ae_true; *nfev = 0; state->finit = *f; state->dgtest = linmin_ftol*state->dginit; state->width = stpmax-linmin_stpmin; state->width1 = state->width/p5; ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF * THE INTERVAL OF UNCERTAINTY. * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. */ state->stx = (double)(0); state->fx = state->finit; state->dgx = state->dginit; state->sty = (double)(0); state->fy = state->finit; state->dgy = state->dginit; /* * NEXT */ *stage = 3; continue; } if( *stage==3 ) { /* * START OF ITERATION. * * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND * TO THE PRESENT INTERVAL OF UNCERTAINTY. */ if( state->brackt ) { if( ae_fp_less(state->stx,state->sty) ) { state->stmin = state->stx; state->stmax = state->sty; } else { state->stmin = state->sty; state->stmax = state->stx; } } else { state->stmin = state->stx; state->stmax = *stp+state->xtrapf*(*stp-state->stx); } /* * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. */ if( ae_fp_greater(*stp,stpmax) ) { *stp = stpmax; } if( ae_fp_less(*stp,linmin_stpmin) ) { *stp = linmin_stpmin; } /* * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET * STP BE THE LOWEST POINT OBTAINED SO FAR. */ if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=linmin_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax)) ) { *stp = state->stx; } /* * EVALUATE THE FUNCTION AND GRADIENT AT STP * AND COMPUTE THE DIRECTIONAL DERIVATIVE. */ ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); /* * NEXT */ *stage = 4; return; } if( *stage==4 ) { *info = 0; *nfev = *nfev+1; v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->dg = v; state->ftest1 = state->finit+*stp*state->dgtest; /* * TEST FOR CONVERGENCE. */ if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) { *info = 6; } if( ((ae_fp_eq(*stp,stpmax)&&ae_fp_less(*f,state->finit))&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) { *info = 5; } if( ae_fp_eq(*stp,linmin_stpmin)&&((ae_fp_greater_eq(*f,state->finit)||ae_fp_greater(*f,state->ftest1))||ae_fp_greater_eq(state->dg,state->dgtest)) ) { *info = 4; } if( *nfev>=linmin_maxfev ) { *info = 3; } if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax) ) { *info = 2; } if( (ae_fp_less(*f,state->finit)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(ae_fabs(state->dg, _state),-gtol*state->dginit) ) { *info = 1; } /* * CHECK FOR TERMINATION. */ if( *info!=0 ) { /* * Check guarantees provided by the function for INFO=1 or INFO=5 */ if( *info==1||*info==5 ) { v = 0.0; for(i=0; i<=n-1; i++) { v = v+(wa->ptr.p_double[i]-x->ptr.p_double[i])*(wa->ptr.p_double[i]-x->ptr.p_double[i]); } if( ae_fp_greater_eq(*f,state->finit)||ae_fp_eq(v,0.0) ) { *info = 6; } } *stage = 0; return; } /* * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. */ if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(linmin_ftol, gtol, _state)*state->dginit) ) { state->stage1 = ae_false; } /* * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. */ if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) { /* * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. */ state->fm = *f-*stp*state->dgtest; state->fxm = state->fx-state->stx*state->dgtest; state->fym = state->fy-state->sty*state->dgtest; state->dgm = state->dg-state->dgtest; state->dgxm = state->dgx-state->dgtest; state->dgym = state->dgy-state->dgtest; /* * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY * AND TO COMPUTE THE NEW STEP. */ linmin_mcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); /* * RESET THE FUNCTION AND GRADIENT VALUES FOR F. */ state->fx = state->fxm+state->stx*state->dgtest; state->fy = state->fym+state->sty*state->dgtest; state->dgx = state->dgxm+state->dgtest; state->dgy = state->dgym+state->dgtest; } else { /* * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY * AND TO COMPUTE THE NEW STEP. */ linmin_mcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); } /* * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE * INTERVAL OF UNCERTAINTY. */ if( state->brackt ) { if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) { *stp = state->stx+p5*(state->sty-state->stx); } state->width1 = state->width; state->width = ae_fabs(state->sty-state->stx, _state); } /* * NEXT. */ *stage = 3; continue; } } } /************************************************************************* These functions perform Armijo line search using at most FMAX function evaluations. It doesn't enforce some kind of " sufficient decrease" criterion - it just tries different Armijo steps and returns optimum found so far. Optimization is done using F-rcomm interface: * ArmijoCreate initializes State structure (reusing previously allocated buffers) * ArmijoIteration is subsequently called * ArmijoResults returns results INPUT PARAMETERS: N - problem size X - array[N], starting point F - F(X+S*STP) S - step direction, S>0 STP - step length STPMAX - maximum value for STP or zero (if no limit is imposed) FMAX - maximum number of function evaluations State - optimization state -- ALGLIB -- Copyright 05.10.2010 by Bochkanov Sergey *************************************************************************/ void armijocreate(ae_int_t n, /* Real */ ae_vector* x, double f, /* Real */ ae_vector* s, double stp, double stpmax, ae_int_t fmax, armijostate* state, ae_state *_state) { if( state->x.cntx, n, _state); } if( state->xbase.cntxbase, n, _state); } if( state->s.cnts, n, _state); } state->stpmax = stpmax; state->fmax = fmax; state->stplen = stp; state->fcur = f; state->n = n; ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->s.ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_vector_set_length(&state->rstate.ia, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 0+1, _state); state->rstate.stage = -1; } /************************************************************************* This is rcomm-based search function -- ALGLIB -- Copyright 05.10.2010 by Bochkanov Sergey *************************************************************************/ ae_bool armijoiteration(armijostate* state, ae_state *_state) { double v; ae_int_t n; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; v = state->rstate.ra.ptr.p_double[0]; } else { n = -983; v = -989; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } /* * Routine body */ if( (ae_fp_less_eq(state->stplen,(double)(0))||ae_fp_less(state->stpmax,(double)(0)))||state->fmax<2 ) { state->info = 0; result = ae_false; return result; } if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) { state->info = 4; result = ae_false; return result; } n = state->n; state->nfev = 0; /* * We always need F */ state->needf = ae_true; /* * Bound StpLen */ if( ae_fp_greater(state->stplen,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) { state->stplen = state->stpmax; } /* * Increase length */ v = state->stplen*linmin_armijofactor; if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) { v = state->stpmax; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->nfev = state->nfev+1; if( ae_fp_greater_eq(state->f,state->fcur) ) { goto lbl_4; } state->stplen = v; state->fcur = state->f; lbl_6: if( ae_false ) { goto lbl_7; } /* * test stopping conditions */ if( state->nfev>=state->fmax ) { state->info = 3; result = ae_false; return result; } if( ae_fp_greater_eq(state->stplen,state->stpmax) ) { state->info = 5; result = ae_false; return result; } /* * evaluate F */ v = state->stplen*linmin_armijofactor; if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) { v = state->stpmax; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->nfev = state->nfev+1; /* * make decision */ if( ae_fp_less(state->f,state->fcur) ) { state->stplen = v; state->fcur = state->f; } else { state->info = 1; result = ae_false; return result; } goto lbl_6; lbl_7: lbl_4: /* * Decrease length */ v = state->stplen/linmin_armijofactor; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->nfev = state->nfev+1; if( ae_fp_greater_eq(state->f,state->fcur) ) { goto lbl_8; } state->stplen = state->stplen/linmin_armijofactor; state->fcur = state->f; lbl_10: if( ae_false ) { goto lbl_11; } /* * test stopping conditions */ if( state->nfev>=state->fmax ) { state->info = 3; result = ae_false; return result; } if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) { state->info = 4; result = ae_false; return result; } /* * evaluate F */ v = state->stplen/linmin_armijofactor; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->nfev = state->nfev+1; /* * make decision */ if( ae_fp_less(state->f,state->fcur) ) { state->stplen = state->stplen/linmin_armijofactor; state->fcur = state->f; } else { state->info = 1; result = ae_false; return result; } goto lbl_10; lbl_11: lbl_8: /* * Nothing to be done */ state->info = 1; result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ra.ptr.p_double[0] = v; return result; } /************************************************************************* Results of Armijo search OUTPUT PARAMETERS: INFO - on output it is set to one of the return codes: * 0 improper input params * 1 optimum step is found with at most FMAX evaluations * 3 FMAX evaluations were used, X contains optimum found so far * 4 step is at lower bound STPMIN * 5 step is at upper bound STP - step length (in case of failure it is still returned) F - function value (in case of failure it is still returned) -- ALGLIB -- Copyright 05.10.2010 by Bochkanov Sergey *************************************************************************/ void armijoresults(armijostate* state, ae_int_t* info, double* stp, double* f, ae_state *_state) { *info = state->info; *stp = state->stplen; *f = state->fcur; } static void linmin_mcstep(double* stx, double* fx, double* dx, double* sty, double* fy, double* dy, double* stp, double fp, double dp, ae_bool* brackt, double stmin, double stmax, ae_int_t* info, ae_state *_state) { ae_bool bound; double gamma; double p; double q; double r; double s; double sgnd; double stpc; double stpf; double stpq; double theta; *info = 0; /* * CHECK THE INPUT PARAMETERS FOR ERRORS. */ if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),(double)(0)))||ae_fp_less(stmax,stmin) ) { return; } /* * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. */ sgnd = dp*(*dx/ae_fabs(*dx, _state)); /* * FIRST CASE. A HIGHER FUNCTION VALUE. * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. */ if( ae_fp_greater(fp,*fx) ) { *info = 1; bound = ae_true; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); if( ae_fp_less(*stp,*stx) ) { gamma = -gamma; } p = gamma-(*dx)+theta; q = gamma-(*dx)+gamma+dp; r = p/q; stpc = *stx+r*(*stp-(*stx)); stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/2*(*stp-(*stx)); if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) { stpf = stpc; } else { stpf = stpc+(stpq-stpc)/2; } *brackt = ae_true; } else { if( ae_fp_less(sgnd,(double)(0)) ) { /* * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. */ *info = 2; bound = ae_false; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); if( ae_fp_greater(*stp,*stx) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma-dp+gamma+(*dx); r = p/q; stpc = *stp+r*(*stx-(*stp)); stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) { stpf = stpc; } else { stpf = stpq; } *brackt = ae_true; } else { if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) { /* * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. */ *info = 3; bound = ae_true; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); /* * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND * TO INFINITY IN THE DIRECTION OF THE STEP. */ gamma = s*ae_sqrt(ae_maxreal((double)(0), ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); if( ae_fp_greater(*stp,*stx) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma+(*dx-dp)+gamma; r = p/q; if( ae_fp_less(r,(double)(0))&&ae_fp_neq(gamma,(double)(0)) ) { stpc = *stp+r*(*stx-(*stp)); } else { if( ae_fp_greater(*stp,*stx) ) { stpc = stmax; } else { stpc = stmin; } } stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); if( *brackt ) { if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) { stpf = stpc; } else { stpf = stpq; } } else { if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) { stpf = stpc; } else { stpf = stpq; } } } else { /* * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. */ *info = 4; bound = ae_false; if( *brackt ) { theta = 3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); if( ae_fp_greater(*stp,*sty) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma-dp+gamma+(*dy); r = p/q; stpc = *stp+r*(*sty-(*stp)); stpf = stpc; } else { if( ae_fp_greater(*stp,*stx) ) { stpf = stmax; } else { stpf = stmin; } } } } } /* * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. */ if( ae_fp_greater(fp,*fx) ) { *sty = *stp; *fy = fp; *dy = dp; } else { if( ae_fp_less(sgnd,0.0) ) { *sty = *stx; *fy = *fx; *dy = *dx; } *stx = *stp; *fx = fp; *dx = dp; } /* * COMPUTE THE NEW STEP AND SAFEGUARD IT. */ stpf = ae_minreal(stmax, stpf, _state); stpf = ae_maxreal(stmin, stpf, _state); *stp = stpf; if( *brackt&&bound ) { if( ae_fp_greater(*sty,*stx) ) { *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); } else { *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); } } } void _linminstate_init(void* _p, ae_state *_state) { linminstate *p = (linminstate*)_p; ae_touch_ptr((void*)p); } void _linminstate_init_copy(void* _dst, void* _src, ae_state *_state) { linminstate *dst = (linminstate*)_dst; linminstate *src = (linminstate*)_src; dst->brackt = src->brackt; dst->stage1 = src->stage1; dst->infoc = src->infoc; dst->dg = src->dg; dst->dgm = src->dgm; dst->dginit = src->dginit; dst->dgtest = src->dgtest; dst->dgx = src->dgx; dst->dgxm = src->dgxm; dst->dgy = src->dgy; dst->dgym = src->dgym; dst->finit = src->finit; dst->ftest1 = src->ftest1; dst->fm = src->fm; dst->fx = src->fx; dst->fxm = src->fxm; dst->fy = src->fy; dst->fym = src->fym; dst->stx = src->stx; dst->sty = src->sty; dst->stmin = src->stmin; dst->stmax = src->stmax; dst->width = src->width; dst->width1 = src->width1; dst->xtrapf = src->xtrapf; } void _linminstate_clear(void* _p) { linminstate *p = (linminstate*)_p; ae_touch_ptr((void*)p); } void _linminstate_destroy(void* _p) { linminstate *p = (linminstate*)_p; ae_touch_ptr((void*)p); } void _armijostate_init(void* _p, ae_state *_state) { armijostate *p = (armijostate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->xbase, 0, DT_REAL, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _armijostate_init_copy(void* _dst, void* _src, ae_state *_state) { armijostate *dst = (armijostate*)_dst; armijostate *src = (armijostate*)_src; dst->needf = src->needf; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; dst->n = src->n; ae_vector_init_copy(&dst->xbase, &src->xbase, _state); ae_vector_init_copy(&dst->s, &src->s, _state); dst->stplen = src->stplen; dst->fcur = src->fcur; dst->stpmax = src->stpmax; dst->fmax = src->fmax; dst->nfev = src->nfev; dst->info = src->info; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _armijostate_clear(void* _p) { armijostate *p = (armijostate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->xbase); ae_vector_clear(&p->s); _rcommstate_clear(&p->rstate); } void _armijostate_destroy(void* _p) { armijostate *p = (armijostate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->xbase); ae_vector_destroy(&p->s); _rcommstate_destroy(&p->rstate); } void findprimitiverootandinverse(ae_int_t n, ae_int_t* proot, ae_int_t* invproot, ae_state *_state) { ae_int_t candroot; ae_int_t phin; ae_int_t q; ae_int_t f; ae_bool allnonone; ae_int_t x; ae_int_t lastx; ae_int_t y; ae_int_t lasty; ae_int_t a; ae_int_t b; ae_int_t t; ae_int_t n2; *proot = 0; *invproot = 0; ae_assert(n>=3, "FindPrimitiveRootAndInverse: N<3", _state); *proot = 0; *invproot = 0; /* * check that N is prime */ ae_assert(ntheory_isprime(n, _state), "FindPrimitiveRoot: N is not prime", _state); /* * Because N is prime, Euler totient function is equal to N-1 */ phin = n-1; /* * Test different values of PRoot - from 2 to N-1. * One of these values MUST be primitive root. * * For testing we use algorithm from Wiki (Primitive root modulo n): * * compute phi(N) * * determine the different prime factors of phi(N), say p1, ..., pk * * for every element m of Zn*, compute m^(phi(N)/pi) mod N for i=1..k * using a fast algorithm for modular exponentiation. * * a number m for which these k results are all different from 1 is a * primitive root. */ for(candroot=2; candroot<=n-1; candroot++) { /* * We have current candidate root in CandRoot. * * Scan different prime factors of PhiN. Here: * * F is a current candidate factor * * Q is a current quotient - amount which was left after dividing PhiN * by all previous factors * * For each factor, perform test mentioned above. */ q = phin; f = 2; allnonone = ae_true; while(q>1) { if( q%f==0 ) { t = ntheory_modexp(candroot, phin/f, n, _state); if( t==1 ) { allnonone = ae_false; break; } while(q%f==0) { q = q/f; } } f = f+1; } if( allnonone ) { *proot = candroot; break; } } ae_assert(*proot>=2, "FindPrimitiveRoot: internal error (root not found)", _state); /* * Use extended Euclidean algorithm to find multiplicative inverse of primitive root */ x = 0; lastx = 1; y = 1; lasty = 0; a = *proot; b = n; while(b!=0) { q = a/b; t = a%b; a = b; b = t; t = lastx-q*x; lastx = x; x = t; t = lasty-q*y; lasty = y; y = t; } while(lastx<0) { lastx = lastx+n; } *invproot = lastx; /* * Check that it is safe to perform multiplication modulo N. * Check results for consistency. */ n2 = (n-1)*(n-1); ae_assert(n2/(n-1)==n-1, "FindPrimitiveRoot: internal error", _state); ae_assert(*proot*(*invproot)/(*proot)==(*invproot), "FindPrimitiveRoot: internal error", _state); ae_assert(*proot*(*invproot)/(*invproot)==(*proot), "FindPrimitiveRoot: internal error", _state); ae_assert(*proot*(*invproot)%n==1, "FindPrimitiveRoot: internal error", _state); } static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state) { ae_int_t p; ae_bool result; result = ae_false; p = 2; while(p*p<=n) { if( n%p==0 ) { return result; } p = p+1; } result = ae_true; return result; } static ae_int_t ntheory_modmul(ae_int_t a, ae_int_t b, ae_int_t n, ae_state *_state) { ae_int_t t; double ra; double rb; ae_int_t result; ae_assert(a>=0&&a=N", _state); ae_assert(b>=0&&b=N", _state); /* * Base cases */ ra = (double)(a); rb = (double)(b); if( b==0||a==0 ) { result = 0; return result; } if( b==1||a==1 ) { result = a*b; return result; } if( ae_fp_eq(ra*rb,(double)(a*b)) ) { result = a*b%n; return result; } /* * Non-base cases */ if( b%2==0 ) { /* * A*B = (A*(B/2)) * 2 * * Product T=A*(B/2) is calculated recursively, product T*2 is * calculated as follows: * * result:=T-N * * result:=result+T * * if result<0 then result:=result+N * * In case integer result overflows, we generate exception */ t = ntheory_modmul(a, b/2, n, _state); result = t-n; result = result+t; if( result<0 ) { result = result+n; } } else { /* * A*B = (A*(B div 2)) * 2 + A * * Product T=A*(B/2) is calculated recursively, product T*2 is * calculated as follows: * * result:=T-N * * result:=result+T * * if result<0 then result:=result+N * * In case integer result overflows, we generate exception */ t = ntheory_modmul(a, b/2, n, _state); result = t-n; result = result+t; if( result<0 ) { result = result+n; } result = result-n; result = result+a; if( result<0 ) { result = result+n; } } return result; } static ae_int_t ntheory_modexp(ae_int_t a, ae_int_t b, ae_int_t n, ae_state *_state) { ae_int_t t; ae_int_t result; ae_assert(a>=0&&a=N", _state); ae_assert(b>=0, "ModExp: B<0", _state); /* * Base cases */ if( b==0 ) { result = 1; return result; } if( b==1 ) { result = a; return result; } /* * Non-base cases */ if( b%2==0 ) { t = ntheory_modmul(a, a, n, _state); result = ntheory_modexp(t, b/2, n, _state); } else { t = ntheory_modmul(a, a, n, _state); result = ntheory_modexp(t, b/2, n, _state); result = ntheory_modmul(result, a, n, _state); } return result; } /************************************************************************* This subroutine generates FFT plan for K complex FFT's with length N each. INPUT PARAMETERS: N - FFT length (in complex numbers), N>=1 K - number of repetitions, K>=1 OUTPUT PARAMETERS: Plan - plan -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ void ftcomplexfftplan(ae_int_t n, ae_int_t k, fasttransformplan* plan, ae_state *_state) { ae_frame _frame_block; srealarray bluesteinbuf; ae_int_t rowptr; ae_int_t bluesteinsize; ae_int_t precrptr; ae_int_t preciptr; ae_int_t precrsize; ae_int_t precisize; ae_frame_make(_state, &_frame_block); _fasttransformplan_clear(plan); _srealarray_init(&bluesteinbuf, _state); /* * Initial check for parameters */ ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); /* * Determine required sizes of precomputed real and integer * buffers. This stage of code is highly dependent on internals * of FTComplexFFTPlanRec() and must be kept synchronized with * possible changes in internals of plan generation function. * * Buffer size is determined as follows: * * N is factorized * * we factor out anything which is less or equal to MaxRadix * * prime factor F>RaderThreshold requires 4*FTBaseFindSmooth(2*F-1) * real entries to store precomputed Quantities for Bluestein's * transformation * * prime factor F<=RaderThreshold does NOT require * precomputed storage */ precrsize = 0; precisize = 0; ftbase_ftdeterminespacerequirements(n, &precrsize, &precisize, _state); if( precrsize>0 ) { ae_vector_set_length(&plan->precr, precrsize, _state); } if( precisize>0 ) { ae_vector_set_length(&plan->preci, precisize, _state); } /* * Generate plan */ rowptr = 0; precrptr = 0; preciptr = 0; bluesteinsize = 1; ae_vector_set_length(&plan->buffer, 2*n*k, _state); ftbase_ftcomplexfftplanrec(n, k, ae_true, ae_true, &rowptr, &bluesteinsize, &precrptr, &preciptr, plan, _state); ae_vector_set_length(&bluesteinbuf.val, bluesteinsize, _state); ae_shared_pool_set_seed(&plan->bluesteinpool, &bluesteinbuf, sizeof(bluesteinbuf), _srealarray_init, _srealarray_init_copy, _srealarray_destroy, _state); /* * Check that actual amount of precomputed space used by transformation * plan is EXACTLY equal to amount of space allocated by us. */ ae_assert(precrptr==precrsize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); ae_assert(preciptr==precisize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); ae_frame_leave(_state); } /************************************************************************* This subroutine applies transformation plan to input/output array A. INPUT PARAMETERS: Plan - transformation plan A - array, must be large enough for plan to work OffsA - offset of the subarray to process RepCnt - repetition count (transformation is repeatedly applied to subsequent subarrays) OUTPUT PARAMETERS: Plan - plan (temporary buffers can be modified, plan itself is unchanged and can be reused) A - transformed array -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ void ftapplyplan(fasttransformplan* plan, /* Real */ ae_vector* a, ae_int_t offsa, ae_int_t repcnt, ae_state *_state) { ae_int_t plansize; ae_int_t i; plansize = plan->entries.ptr.pp_int[0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[0][ftbase_colmicrovectorsize]; for(i=0; i<=repcnt-1; i++) { ftbase_ftapplysubplan(plan, 0, a, offsa+plansize*i, 0, &plan->buffer, 1, _state); } } /************************************************************************* Returns good factorization N=N1*N2. Usually N1<=N2 (but not always - small N's may be exception). if N1<>1 then N2<>1. Factorization is chosen depending on task type and codelets we have. -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ void ftbasefactorize(ae_int_t n, ae_int_t tasktype, ae_int_t* n1, ae_int_t* n2, ae_state *_state) { ae_int_t j; *n1 = 0; *n2 = 0; *n1 = 0; *n2 = 0; /* * try to find good codelet */ if( *n1*(*n2)!=n ) { for(j=ftbase_ftbasecodeletrecommended; j>=2; j--) { if( n%j==0 ) { *n1 = j; *n2 = n/j; break; } } } /* * try to factorize N */ if( *n1*(*n2)!=n ) { for(j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) { if( n%j==0 ) { *n1 = j; *n2 = n/j; break; } } } /* * looks like N is prime :( */ if( *n1*(*n2)!=n ) { *n1 = 1; *n2 = n; } /* * normalize */ if( *n2==1&&*n1!=1 ) { *n2 = *n1; *n1 = 1; } } /************************************************************************* Is number smooth? -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state) { ae_int_t i; ae_bool result; for(i=2; i<=ftbase_ftbasemaxsmoothfactor; i++) { while(n%i==0) { n = n/i; } } result = n==1; return result; } /************************************************************************* Returns smallest smooth (divisible only by 2, 3, 5) number that is greater than or equal to max(N,2) -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state) { ae_int_t best; ae_int_t result; best = 2; while(bestRaderThreshold requires 4*FTBaseFindSmooth(2*F-1) * real entries to store precomputed Quantities for Bluestein's * transformation * * prime factor F<=RaderThreshold requires 2*(F-1)+ESTIMATE(F-1) * precomputed storage */ ncur = n; for(i=2; i<=ftbase_maxradix; i++) { while(ncur%i==0) { ncur = ncur/i; } } f = 2; while(f<=ncur) { while(ncur%f==0) { if( f>ftbase_raderthreshold ) { *precrsize = *precrsize+4*ftbasefindsmooth(2*f-1, _state); } else { *precrsize = *precrsize+2*(f-1); ftbase_ftdeterminespacerequirements(f-1, precrsize, precisize, _state); } ncur = ncur/f; } f = f+1; } } /************************************************************************* Recurrent function called by FTComplexFFTPlan() and other functions. It recursively builds transformation plan INPUT PARAMETERS: N - FFT length (in complex numbers), N>=1 K - number of repetitions, K>=1 ChildPlan - if True, plan generator inserts OpStart/opEnd in the plan header/footer. TopmostPlan - if True, plan generator assumes that it is topmost plan: * it may use global buffer for transpositions and there is no other plan which executes in parallel RowPtr - index which points to past-the-last entry generated so far BluesteinSize- amount of storage (in real numbers) required for Bluestein buffer PrecRPtr - pointer to unused part of precomputed real buffer (Plan.PrecR): * when this function stores some data to precomputed buffer, it advances pointer. * it is responsibility of the function to assert that Plan.PrecR has enough space to store data before actually writing to buffer. * it is responsibility of the caller to allocate enough space before calling this function PrecIPtr - pointer to unused part of precomputed integer buffer (Plan.PrecI): * when this function stores some data to precomputed buffer, it advances pointer. * it is responsibility of the function to assert that Plan.PrecR has enough space to store data before actually writing to buffer. * it is responsibility of the caller to allocate enough space before calling this function Plan - plan (generated so far) OUTPUT PARAMETERS: RowPtr - updated pointer (advanced by number of entries generated by function) BluesteinSize- updated amount (may be increased, but may never be decreased) NOTE: in case TopmostPlan is True, ChildPlan is also must be True. -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftcomplexfftplanrec(ae_int_t n, ae_int_t k, ae_bool childplan, ae_bool topmostplan, ae_int_t* rowptr, ae_int_t* bluesteinsize, ae_int_t* precrptr, ae_int_t* preciptr, fasttransformplan* plan, ae_state *_state) { ae_frame _frame_block; srealarray localbuf; ae_int_t m; ae_int_t n1; ae_int_t n2; ae_int_t gq; ae_int_t giq; ae_int_t row0; ae_int_t row1; ae_int_t row2; ae_int_t row3; ae_frame_make(_state, &_frame_block); _srealarray_init(&localbuf, _state); ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); ae_assert(!topmostplan||childplan, "FTComplexFFTPlan: ChildPlan is inconsistent with TopmostPlan", _state); /* * Try to generate "topmost" plan */ if( topmostplan&&n>ftbase_recursivethreshold ) { ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); if( n1*n2==0 ) { /* * Handle prime-factor FFT with Bluestein's FFT. * Determine size of Bluestein's buffer. */ m = ftbasefindsmooth(2*n-1, _state); *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); /* * Generate plan */ ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); row0 = *rowptr; ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_true, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); row1 = *rowptr; plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); /* * Fill precomputed buffer */ ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); /* * Update pointer to the precomputed area */ *precrptr = *precrptr+4*m; } else { /* * Handle composite FFT with recursive Cooley-Tukey which * uses global buffer instead of local one. */ ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); row0 = *rowptr; ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); row2 = *rowptr; ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); row1 = *rowptr; ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; row3 = *rowptr; ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; } ae_frame_leave(_state); return; } /* * Prepare "non-topmost" plan: * * calculate factorization * * use local (shared) buffer * * update buffer size - ANY plan will need at least * 2*N temporaries, additional requirements can be * applied later */ ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); /* * Handle FFT's with N1*N2=0: either small-N or prime-factor */ if( n1*n2==0 ) { if( n<=ftbase_maxradix ) { /* * Small-N FFT */ if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodeletfft, k, n, 2, 0, _state); if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } ae_frame_leave(_state); return; } if( n<=ftbase_raderthreshold ) { /* * Handle prime-factor FFT's with Rader's FFT */ m = n-1; if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } findprimitiverootandinverse(n, &gq, &giq, _state); ftbase_ftpushentry4(plan, rowptr, ftbase_opradersfft, k, n, 2, 2, gq, giq, *precrptr, _state); ftbase_ftprecomputeradersfft(n, gq, giq, &plan->precr, *precrptr, _state); *precrptr = *precrptr+2*(n-1); row0 = *rowptr; ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); row1 = *rowptr; plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } } else { /* * Handle prime-factor FFT's with Bluestein's FFT */ m = ftbasefindsmooth(2*n-1, _state); *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); *precrptr = *precrptr+4*m; row0 = *rowptr; ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); row1 = *rowptr; plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } } ae_frame_leave(_state); return; } /* * Handle Cooley-Tukey FFT with small N1 */ if( n1<=ftbase_maxradix ) { /* * Specialized transformation for small N1: * * N2 short inplace FFT's, each N1-point, with integrated twiddle factors * * N1 long FFT's * * final transposition */ if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodelettwfft, k, n1, 2*n2, 0, _state); ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } ae_frame_leave(_state); return; } /* * Handle general Cooley-Tukey FFT, either "flat" or "recursive" */ if( n<=ftbase_recursivethreshold ) { /* * General code for large N1/N2, "flat" version without explicit recurrence * (nested subplans are inserted directly into the body of the plan) */ if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); ftbase_ftcomplexfftplanrec(n1, k*n2, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } } else { /* * General code for large N1/N2, "recursive" version - nested subplans * are separated from the plan body. * * Generate parent plan. */ if( childplan ) { ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); } ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); row0 = *rowptr; ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); row2 = *rowptr; ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); if( childplan ) { ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); } /* * Generate child subplans, insert refence to parent plans */ row1 = *rowptr; ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; row3 = *rowptr; ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; } ae_frame_leave(_state); } /************************************************************************* This function pushes one more entry to the plan. It resizes Entries matrix if needed. INPUT PARAMETERS: Plan - plan (generated so far) RowPtr - index which points to past-the-last entry generated so far EType - entry type EOpCnt - operands count EOpSize - operand size EMcvSize - microvector size EParam0 - parameter 0 OUTPUT PARAMETERS: Plan - updated plan RowPtr - updated pointer NOTE: Param1 is set to -1. -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftpushentry(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_state *_state) { ftbase_ftpushentry2(plan, rowptr, etype, eopcnt, eopsize, emcvsize, eparam0, -1, _state); } /************************************************************************* Same as FTPushEntry(), but sets Param0 AND Param1. This function pushes one more entry to the plan. It resized Entries matrix if needed. INPUT PARAMETERS: Plan - plan (generated so far) RowPtr - index which points to past-the-last entry generated so far EType - entry type EOpCnt - operands count EOpSize - operand size EMcvSize - microvector size EParam0 - parameter 0 EParam1 - parameter 1 OUTPUT PARAMETERS: Plan - updated plan RowPtr - updated pointer -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftpushentry2(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_int_t eparam1, ae_state *_state) { if( *rowptr>=plan->entries.rows ) { imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); } plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = 0; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = 0; *rowptr = *rowptr+1; } /************************************************************************* Same as FTPushEntry(), but sets Param0, Param1, Param2 and Param3. This function pushes one more entry to the plan. It resized Entries matrix if needed. INPUT PARAMETERS: Plan - plan (generated so far) RowPtr - index which points to past-the-last entry generated so far EType - entry type EOpCnt - operands count EOpSize - operand size EMcvSize - microvector size EParam0 - parameter 0 EParam1 - parameter 1 EParam2 - parameter 2 EParam3 - parameter 3 OUTPUT PARAMETERS: Plan - updated plan RowPtr - updated pointer -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftpushentry4(fasttransformplan* plan, ae_int_t* rowptr, ae_int_t etype, ae_int_t eopcnt, ae_int_t eopsize, ae_int_t emcvsize, ae_int_t eparam0, ae_int_t eparam1, ae_int_t eparam2, ae_int_t eparam3, ae_state *_state) { if( *rowptr>=plan->entries.rows ) { imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); } plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = eparam2; plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = eparam3; *rowptr = *rowptr+1; } /************************************************************************* This subroutine applies subplan to input/output array A. INPUT PARAMETERS: Plan - transformation plan SubPlan - subplan index A - array, must be large enough for plan to work ABase - base offset in array A, this value points to start of subarray whose length is equal to length of the plan AOffset - offset with respect to ABase, 0<=AOffsetentries.ptr.pp_int[subplan][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect subplan header", _state); rowidx = subplan+1; while(plan->entries.ptr.pp_int[rowidx][ftbase_coltype]!=ftbase_opend) { operation = plan->entries.ptr.pp_int[rowidx][ftbase_coltype]; operandscnt = repcnt*plan->entries.ptr.pp_int[rowidx][ftbase_coloperandscnt]; operandsize = plan->entries.ptr.pp_int[rowidx][ftbase_coloperandsize]; microvectorsize = plan->entries.ptr.pp_int[rowidx][ftbase_colmicrovectorsize]; param0 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; param1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam1]; touchint(¶m1, _state); /* * Process "jump" operation */ if( operation==ftbase_opjmp ) { rowidx = rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; continue; } /* * Process "parallel call" operation: * * we perform initial check for consistency between parent and child plans * * we call FTSplitAndApplyParallelPlan(), which splits parallel plan into * several parallel tasks */ if( operation==ftbase_opparallelcall ) { parentsize = operandsize*microvectorsize; childsize = plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_colmicrovectorsize]; ae_assert(plan->entries.ptr.pp_int[rowidx+param0][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect child subplan header", _state); ae_assert(parentsize==childsize, "FTApplySubPlan: incorrect child subplan header", _state); chunksize = ae_maxint(ftbase_recursivethreshold/childsize, 1, _state); lastchunksize = operandscnt%chunksize; if( lastchunksize==0 ) { lastchunksize = chunksize; } i = 0; while(ibluesteinpool, &_bufa, _state); ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufb, _state); ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufc, _state); ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufd, _state); ftbase_ftbluesteinsfft(plan, a, abase, aoffset, operandscnt, operandsize, plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], &bufa->val, &bufb->val, &bufc->val, &bufd->val, _state); ae_shared_pool_recycle(&plan->bluesteinpool, &_bufa, _state); ae_shared_pool_recycle(&plan->bluesteinpool, &_bufb, _state); ae_shared_pool_recycle(&plan->bluesteinpool, &_bufc, _state); ae_shared_pool_recycle(&plan->bluesteinpool, &_bufd, _state); rowidx = rowidx+1; continue; } /* * Process Rader's FFT */ if( operation==ftbase_opradersfft ) { ftbase_ftradersfft(plan, a, abase, aoffset, operandscnt, operandsize, rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], plan->entries.ptr.pp_int[rowidx][ftbase_colparam3], buf, _state); rowidx = rowidx+1; continue; } /* * Process "complex twiddle factors" operation */ if( operation==ftbase_opcomplexfftfactors ) { ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; n2 = operandsize/n1; for(i=0; i<=operandscnt-1; i++) { ftbase_ffttwcalc(a, abase+aoffset+i*operandsize*2, n1, n2, _state); } rowidx = rowidx+1; continue; } /* * Process "complex transposition" operation */ if( operation==ftbase_opcomplextranspose ) { ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; n2 = operandsize/n1; for(i=0; i<=operandscnt-1; i++) { ftbase_internalcomplexlintranspose(a, n1, n2, abase+aoffset+i*operandsize*2, buf, _state); } rowidx = rowidx+1; continue; } /* * Error */ ae_assert(ae_false, "FTApplySubPlan: unexpected plan type", _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine applies complex reference FFT to input/output array A. VERY SLOW OPERATION, do not use it in real life plans :) INPUT PARAMETERS: A - array, must be large enough for plan to work Offs - offset of the subarray to process OperandsCnt - operands count (see description of FastTransformPlan) OperandSize - operand size (see description of FastTransformPlan) MicrovectorSize-microvector size (see description of FastTransformPlan) Buf - temporary array, must be at least OperandsCnt*OperandSize*MicrovectorSize OUTPUT PARAMETERS: A - transformed array -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, /* Real */ ae_vector* buf, ae_state *_state) { ae_int_t opidx; ae_int_t i; ae_int_t k; double hre; double him; double c; double s; double re; double im; ae_int_t n; ae_assert(operandscnt>=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); ae_assert(operandsize>=1, "FTApplyComplexRefFFT: OperandSize<1", _state); ae_assert(microvectorsize==2, "FTApplyComplexRefFFT: MicrovectorSize<>2", _state); n = operandsize; for(opidx=0; opidx<=operandscnt-1; opidx++) { for(i=0; i<=n-1; i++) { hre = (double)(0); him = (double)(0); for(k=0; k<=n-1; k++) { re = a->ptr.p_double[offs+opidx*operandsize*2+2*k+0]; im = a->ptr.p_double[offs+opidx*operandsize*2+2*k+1]; c = ae_cos(-2*ae_pi*k*i/n, _state); s = ae_sin(-2*ae_pi*k*i/n, _state); hre = hre+c*re-s*im; him = him+c*im+s*re; } buf->ptr.p_double[2*i+0] = hre; buf->ptr.p_double[2*i+1] = him; } for(i=0; i<=operandsize*2-1; i++) { a->ptr.p_double[offs+opidx*operandsize*2+i] = buf->ptr.p_double[i]; } } } /************************************************************************* This subroutine applies complex codelet FFT to input/output array A. INPUT PARAMETERS: A - array, must be large enough for plan to work Offs - offset of the subarray to process OperandsCnt - operands count (see description of FastTransformPlan) OperandSize - operand size (see description of FastTransformPlan) MicrovectorSize-microvector size, must be 2 OUTPUT PARAMETERS: A - transformed array -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, ae_state *_state) { ae_int_t opidx; ae_int_t n; ae_int_t aoffset; double a0x; double a0y; double a1x; double a1y; double a2x; double a2y; double a3x; double a3y; double a4x; double a4y; double a5x; double a5y; double v0; double v1; double v2; double v3; double t1x; double t1y; double t2x; double t2y; double t3x; double t3y; double t4x; double t4y; double t5x; double t5y; double m1x; double m1y; double m2x; double m2y; double m3x; double m3y; double m4x; double m4y; double m5x; double m5y; double s1x; double s1y; double s2x; double s2y; double s3x; double s3y; double s4x; double s4y; double s5x; double s5y; double c1; double c2; double c3; double c4; double c5; double v; ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); ae_assert(microvectorsize==2, "FTApplyComplexCodeletFFT: MicrovectorSize<>2", _state); n = operandsize; /* * Hard-coded transforms for different N's */ ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletFFT: N>MaxRadix", _state); if( n==2 ) { for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset = offs+opidx*operandsize*2; a0x = a->ptr.p_double[aoffset+0]; a0y = a->ptr.p_double[aoffset+1]; a1x = a->ptr.p_double[aoffset+2]; a1y = a->ptr.p_double[aoffset+3]; v0 = a0x+a1x; v1 = a0y+a1y; v2 = a0x-a1x; v3 = a0y-a1y; a->ptr.p_double[aoffset+0] = v0; a->ptr.p_double[aoffset+1] = v1; a->ptr.p_double[aoffset+2] = v2; a->ptr.p_double[aoffset+3] = v3; } return; } if( n==3 ) { c1 = ae_cos(2*ae_pi/3, _state)-1; c2 = ae_sin(2*ae_pi/3, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset = offs+opidx*operandsize*2; a0x = a->ptr.p_double[aoffset+0]; a0y = a->ptr.p_double[aoffset+1]; a1x = a->ptr.p_double[aoffset+2]; a1y = a->ptr.p_double[aoffset+3]; a2x = a->ptr.p_double[aoffset+4]; a2y = a->ptr.p_double[aoffset+5]; t1x = a1x+a2x; t1y = a1y+a2y; a0x = a0x+t1x; a0y = a0y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a1y-a2y); m2y = c2*(a2x-a1x); s1x = a0x+m1x; s1y = a0y+m1y; a1x = s1x+m2x; a1y = s1y+m2y; a2x = s1x-m2x; a2y = s1y-m2y; a->ptr.p_double[aoffset+0] = a0x; a->ptr.p_double[aoffset+1] = a0y; a->ptr.p_double[aoffset+2] = a1x; a->ptr.p_double[aoffset+3] = a1y; a->ptr.p_double[aoffset+4] = a2x; a->ptr.p_double[aoffset+5] = a2y; } return; } if( n==4 ) { for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset = offs+opidx*operandsize*2; a0x = a->ptr.p_double[aoffset+0]; a0y = a->ptr.p_double[aoffset+1]; a1x = a->ptr.p_double[aoffset+2]; a1y = a->ptr.p_double[aoffset+3]; a2x = a->ptr.p_double[aoffset+4]; a2y = a->ptr.p_double[aoffset+5]; a3x = a->ptr.p_double[aoffset+6]; a3y = a->ptr.p_double[aoffset+7]; t1x = a0x+a2x; t1y = a0y+a2y; t2x = a1x+a3x; t2y = a1y+a3y; m2x = a0x-a2x; m2y = a0y-a2y; m3x = a1y-a3y; m3y = a3x-a1x; a->ptr.p_double[aoffset+0] = t1x+t2x; a->ptr.p_double[aoffset+1] = t1y+t2y; a->ptr.p_double[aoffset+4] = t1x-t2x; a->ptr.p_double[aoffset+5] = t1y-t2y; a->ptr.p_double[aoffset+2] = m2x+m3x; a->ptr.p_double[aoffset+3] = m2y+m3y; a->ptr.p_double[aoffset+6] = m2x-m3x; a->ptr.p_double[aoffset+7] = m2y-m3y; } return; } if( n==5 ) { v = 2*ae_pi/5; c1 = (ae_cos(v, _state)+ae_cos(2*v, _state))/2-1; c2 = (ae_cos(v, _state)-ae_cos(2*v, _state))/2; c3 = -ae_sin(v, _state); c4 = -(ae_sin(v, _state)+ae_sin(2*v, _state)); c5 = ae_sin(v, _state)-ae_sin(2*v, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset = offs+opidx*operandsize*2; t1x = a->ptr.p_double[aoffset+2]+a->ptr.p_double[aoffset+8]; t1y = a->ptr.p_double[aoffset+3]+a->ptr.p_double[aoffset+9]; t2x = a->ptr.p_double[aoffset+4]+a->ptr.p_double[aoffset+6]; t2y = a->ptr.p_double[aoffset+5]+a->ptr.p_double[aoffset+7]; t3x = a->ptr.p_double[aoffset+2]-a->ptr.p_double[aoffset+8]; t3y = a->ptr.p_double[aoffset+3]-a->ptr.p_double[aoffset+9]; t4x = a->ptr.p_double[aoffset+6]-a->ptr.p_double[aoffset+4]; t4y = a->ptr.p_double[aoffset+7]-a->ptr.p_double[aoffset+5]; t5x = t1x+t2x; t5y = t1y+t2y; a->ptr.p_double[aoffset+0] = a->ptr.p_double[aoffset+0]+t5x; a->ptr.p_double[aoffset+1] = a->ptr.p_double[aoffset+1]+t5y; m1x = c1*t5x; m1y = c1*t5y; m2x = c2*(t1x-t2x); m2y = c2*(t1y-t2y); m3x = -c3*(t3y+t4y); m3y = c3*(t3x+t4x); m4x = -c4*t4y; m4y = c4*t4x; m5x = -c5*t3y; m5y = c5*t3x; s3x = m3x-m4x; s3y = m3y-m4y; s5x = m3x+m5x; s5y = m3y+m5y; s1x = a->ptr.p_double[aoffset+0]+m1x; s1y = a->ptr.p_double[aoffset+1]+m1y; s2x = s1x+m2x; s2y = s1y+m2y; s4x = s1x-m2x; s4y = s1y-m2y; a->ptr.p_double[aoffset+2] = s2x+s3x; a->ptr.p_double[aoffset+3] = s2y+s3y; a->ptr.p_double[aoffset+4] = s4x+s5x; a->ptr.p_double[aoffset+5] = s4y+s5y; a->ptr.p_double[aoffset+6] = s4x-s5x; a->ptr.p_double[aoffset+7] = s4y-s5y; a->ptr.p_double[aoffset+8] = s2x-s3x; a->ptr.p_double[aoffset+9] = s2y-s3y; } return; } if( n==6 ) { c1 = ae_cos(2*ae_pi/3, _state)-1; c2 = ae_sin(2*ae_pi/3, _state); c3 = ae_cos(-ae_pi/3, _state); c4 = ae_sin(-ae_pi/3, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset = offs+opidx*operandsize*2; a0x = a->ptr.p_double[aoffset+0]; a0y = a->ptr.p_double[aoffset+1]; a1x = a->ptr.p_double[aoffset+2]; a1y = a->ptr.p_double[aoffset+3]; a2x = a->ptr.p_double[aoffset+4]; a2y = a->ptr.p_double[aoffset+5]; a3x = a->ptr.p_double[aoffset+6]; a3y = a->ptr.p_double[aoffset+7]; a4x = a->ptr.p_double[aoffset+8]; a4y = a->ptr.p_double[aoffset+9]; a5x = a->ptr.p_double[aoffset+10]; a5y = a->ptr.p_double[aoffset+11]; v0 = a0x; v1 = a0y; a0x = a0x+a3x; a0y = a0y+a3y; a3x = v0-a3x; a3y = v1-a3y; v0 = a1x; v1 = a1y; a1x = a1x+a4x; a1y = a1y+a4y; a4x = v0-a4x; a4y = v1-a4y; v0 = a2x; v1 = a2y; a2x = a2x+a5x; a2y = a2y+a5y; a5x = v0-a5x; a5y = v1-a5y; t4x = a4x*c3-a4y*c4; t4y = a4x*c4+a4y*c3; a4x = t4x; a4y = t4y; t5x = -a5x*c3-a5y*c4; t5y = a5x*c4-a5y*c3; a5x = t5x; a5y = t5y; t1x = a1x+a2x; t1y = a1y+a2y; a0x = a0x+t1x; a0y = a0y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a1y-a2y); m2y = c2*(a2x-a1x); s1x = a0x+m1x; s1y = a0y+m1y; a1x = s1x+m2x; a1y = s1y+m2y; a2x = s1x-m2x; a2y = s1y-m2y; t1x = a4x+a5x; t1y = a4y+a5y; a3x = a3x+t1x; a3y = a3y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a4y-a5y); m2y = c2*(a5x-a4x); s1x = a3x+m1x; s1y = a3y+m1y; a4x = s1x+m2x; a4y = s1y+m2y; a5x = s1x-m2x; a5y = s1y-m2y; a->ptr.p_double[aoffset+0] = a0x; a->ptr.p_double[aoffset+1] = a0y; a->ptr.p_double[aoffset+2] = a3x; a->ptr.p_double[aoffset+3] = a3y; a->ptr.p_double[aoffset+4] = a1x; a->ptr.p_double[aoffset+5] = a1y; a->ptr.p_double[aoffset+6] = a4x; a->ptr.p_double[aoffset+7] = a4y; a->ptr.p_double[aoffset+8] = a2x; a->ptr.p_double[aoffset+9] = a2y; a->ptr.p_double[aoffset+10] = a5x; a->ptr.p_double[aoffset+11] = a5y; } return; } } /************************************************************************* This subroutine applies complex "integrated" codelet FFT to input/output array A. "Integrated" codelet differs from "normal" one in following ways: * it can work with MicrovectorSize>1 * hence, it can be used in Cooley-Tukey FFT without transpositions * it performs inlined multiplication by twiddle factors of Cooley-Tukey FFT with N2=MicrovectorSize/2. INPUT PARAMETERS: A - array, must be large enough for plan to work Offs - offset of the subarray to process OperandsCnt - operands count (see description of FastTransformPlan) OperandSize - operand size (see description of FastTransformPlan) MicrovectorSize-microvector size, must be 1 OUTPUT PARAMETERS: A - transformed array -- ALGLIB -- Copyright 05.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, ae_int_t offs, ae_int_t operandscnt, ae_int_t operandsize, ae_int_t microvectorsize, ae_state *_state) { ae_int_t opidx; ae_int_t mvidx; ae_int_t n; ae_int_t m; ae_int_t aoffset0; ae_int_t aoffset2; ae_int_t aoffset4; ae_int_t aoffset6; ae_int_t aoffset8; ae_int_t aoffset10; double a0x; double a0y; double a1x; double a1y; double a2x; double a2y; double a3x; double a3y; double a4x; double a4y; double a5x; double a5y; double v0; double v1; double v2; double v3; double q0x; double q0y; double t1x; double t1y; double t2x; double t2y; double t3x; double t3y; double t4x; double t4y; double t5x; double t5y; double m1x; double m1y; double m2x; double m2y; double m3x; double m3y; double m4x; double m4y; double m5x; double m5y; double s1x; double s1y; double s2x; double s2y; double s3x; double s3y; double s4x; double s4y; double s5x; double s5y; double c1; double c2; double c3; double c4; double c5; double v; double tw0; double tw1; double twx; double twxm1; double twy; double tw2x; double tw2y; double tw3x; double tw3y; double tw4x; double tw4y; double tw5x; double tw5y; ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); ae_assert(microvectorsize>=1, "FTApplyComplexCodeletFFT: MicrovectorSize<>1", _state); ae_assert(microvectorsize%2==0, "FTApplyComplexCodeletFFT: MicrovectorSize is not even", _state); n = operandsize; m = microvectorsize/2; /* * Hard-coded transforms for different N's */ ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletTwFFT: N>MaxRadix", _state); if( n==2 ) { v = -2*ae_pi/(n*m); tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); tw1 = ae_sin(v, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset0 = offs+opidx*operandsize*microvectorsize; aoffset2 = aoffset0+microvectorsize; twxm1 = 0.0; twy = 0.0; for(mvidx=0; mvidx<=m-1; mvidx++) { a0x = a->ptr.p_double[aoffset0]; a0y = a->ptr.p_double[aoffset0+1]; a1x = a->ptr.p_double[aoffset2]; a1y = a->ptr.p_double[aoffset2+1]; v0 = a0x+a1x; v1 = a0y+a1y; v2 = a0x-a1x; v3 = a0y-a1y; a->ptr.p_double[aoffset0] = v0; a->ptr.p_double[aoffset0+1] = v1; a->ptr.p_double[aoffset2] = v2*(1+twxm1)-v3*twy; a->ptr.p_double[aoffset2+1] = v3*(1+twxm1)+v2*twy; aoffset0 = aoffset0+2; aoffset2 = aoffset2+2; if( (mvidx+1)%ftbase_updatetw==0 ) { v = -2*ae_pi*(mvidx+1)/(n*m); twxm1 = ae_sin(0.5*v, _state); twxm1 = -2*twxm1*twxm1; twy = ae_sin(v, _state); } else { v = twxm1+tw0+twxm1*tw0-twy*tw1; twy = twy+tw1+twxm1*tw1+twy*tw0; twxm1 = v; } } } return; } if( n==3 ) { v = -2*ae_pi/(n*m); tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); tw1 = ae_sin(v, _state); c1 = ae_cos(2*ae_pi/3, _state)-1; c2 = ae_sin(2*ae_pi/3, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset0 = offs+opidx*operandsize*microvectorsize; aoffset2 = aoffset0+microvectorsize; aoffset4 = aoffset2+microvectorsize; twx = 1.0; twxm1 = 0.0; twy = 0.0; for(mvidx=0; mvidx<=m-1; mvidx++) { a0x = a->ptr.p_double[aoffset0]; a0y = a->ptr.p_double[aoffset0+1]; a1x = a->ptr.p_double[aoffset2]; a1y = a->ptr.p_double[aoffset2+1]; a2x = a->ptr.p_double[aoffset4]; a2y = a->ptr.p_double[aoffset4+1]; t1x = a1x+a2x; t1y = a1y+a2y; a0x = a0x+t1x; a0y = a0y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a1y-a2y); m2y = c2*(a2x-a1x); s1x = a0x+m1x; s1y = a0y+m1y; a1x = s1x+m2x; a1y = s1y+m2y; a2x = s1x-m2x; a2y = s1y-m2y; tw2x = twx*twx-twy*twy; tw2y = 2*twx*twy; a->ptr.p_double[aoffset0] = a0x; a->ptr.p_double[aoffset0+1] = a0y; a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; aoffset0 = aoffset0+2; aoffset2 = aoffset2+2; aoffset4 = aoffset4+2; if( (mvidx+1)%ftbase_updatetw==0 ) { v = -2*ae_pi*(mvidx+1)/(n*m); twxm1 = ae_sin(0.5*v, _state); twxm1 = -2*twxm1*twxm1; twy = ae_sin(v, _state); twx = twxm1+1; } else { v = twxm1+tw0+twxm1*tw0-twy*tw1; twy = twy+tw1+twxm1*tw1+twy*tw0; twxm1 = v; twx = v+1; } } } return; } if( n==4 ) { v = -2*ae_pi/(n*m); tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); tw1 = ae_sin(v, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset0 = offs+opidx*operandsize*microvectorsize; aoffset2 = aoffset0+microvectorsize; aoffset4 = aoffset2+microvectorsize; aoffset6 = aoffset4+microvectorsize; twx = 1.0; twxm1 = 0.0; twy = 0.0; for(mvidx=0; mvidx<=m-1; mvidx++) { a0x = a->ptr.p_double[aoffset0]; a0y = a->ptr.p_double[aoffset0+1]; a1x = a->ptr.p_double[aoffset2]; a1y = a->ptr.p_double[aoffset2+1]; a2x = a->ptr.p_double[aoffset4]; a2y = a->ptr.p_double[aoffset4+1]; a3x = a->ptr.p_double[aoffset6]; a3y = a->ptr.p_double[aoffset6+1]; t1x = a0x+a2x; t1y = a0y+a2y; t2x = a1x+a3x; t2y = a1y+a3y; m2x = a0x-a2x; m2y = a0y-a2y; m3x = a1y-a3y; m3y = a3x-a1x; tw2x = twx*twx-twy*twy; tw2y = 2*twx*twy; tw3x = twx*tw2x-twy*tw2y; tw3y = twx*tw2y+twy*tw2x; a1x = m2x+m3x; a1y = m2y+m3y; a2x = t1x-t2x; a2y = t1y-t2y; a3x = m2x-m3x; a3y = m2y-m3y; a->ptr.p_double[aoffset0] = t1x+t2x; a->ptr.p_double[aoffset0+1] = t1y+t2y; a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; a->ptr.p_double[aoffset6+1] = a3y*tw3x+a3x*tw3y; aoffset0 = aoffset0+2; aoffset2 = aoffset2+2; aoffset4 = aoffset4+2; aoffset6 = aoffset6+2; if( (mvidx+1)%ftbase_updatetw==0 ) { v = -2*ae_pi*(mvidx+1)/(n*m); twxm1 = ae_sin(0.5*v, _state); twxm1 = -2*twxm1*twxm1; twy = ae_sin(v, _state); twx = twxm1+1; } else { v = twxm1+tw0+twxm1*tw0-twy*tw1; twy = twy+tw1+twxm1*tw1+twy*tw0; twxm1 = v; twx = v+1; } } } return; } if( n==5 ) { v = -2*ae_pi/(n*m); tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); tw1 = ae_sin(v, _state); v = 2*ae_pi/5; c1 = (ae_cos(v, _state)+ae_cos(2*v, _state))/2-1; c2 = (ae_cos(v, _state)-ae_cos(2*v, _state))/2; c3 = -ae_sin(v, _state); c4 = -(ae_sin(v, _state)+ae_sin(2*v, _state)); c5 = ae_sin(v, _state)-ae_sin(2*v, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset0 = offs+opidx*operandsize*microvectorsize; aoffset2 = aoffset0+microvectorsize; aoffset4 = aoffset2+microvectorsize; aoffset6 = aoffset4+microvectorsize; aoffset8 = aoffset6+microvectorsize; twx = 1.0; twxm1 = 0.0; twy = 0.0; for(mvidx=0; mvidx<=m-1; mvidx++) { a0x = a->ptr.p_double[aoffset0]; a0y = a->ptr.p_double[aoffset0+1]; a1x = a->ptr.p_double[aoffset2]; a1y = a->ptr.p_double[aoffset2+1]; a2x = a->ptr.p_double[aoffset4]; a2y = a->ptr.p_double[aoffset4+1]; a3x = a->ptr.p_double[aoffset6]; a3y = a->ptr.p_double[aoffset6+1]; a4x = a->ptr.p_double[aoffset8]; a4y = a->ptr.p_double[aoffset8+1]; t1x = a1x+a4x; t1y = a1y+a4y; t2x = a2x+a3x; t2y = a2y+a3y; t3x = a1x-a4x; t3y = a1y-a4y; t4x = a3x-a2x; t4y = a3y-a2y; t5x = t1x+t2x; t5y = t1y+t2y; q0x = a0x+t5x; q0y = a0y+t5y; m1x = c1*t5x; m1y = c1*t5y; m2x = c2*(t1x-t2x); m2y = c2*(t1y-t2y); m3x = -c3*(t3y+t4y); m3y = c3*(t3x+t4x); m4x = -c4*t4y; m4y = c4*t4x; m5x = -c5*t3y; m5y = c5*t3x; s3x = m3x-m4x; s3y = m3y-m4y; s5x = m3x+m5x; s5y = m3y+m5y; s1x = q0x+m1x; s1y = q0y+m1y; s2x = s1x+m2x; s2y = s1y+m2y; s4x = s1x-m2x; s4y = s1y-m2y; tw2x = twx*twx-twy*twy; tw2y = 2*twx*twy; tw3x = twx*tw2x-twy*tw2y; tw3y = twx*tw2y+twy*tw2x; tw4x = tw2x*tw2x-tw2y*tw2y; tw4y = tw2x*tw2y+tw2y*tw2x; a1x = s2x+s3x; a1y = s2y+s3y; a2x = s4x+s5x; a2y = s4y+s5y; a3x = s4x-s5x; a3y = s4y-s5y; a4x = s2x-s3x; a4y = s2y-s3y; a->ptr.p_double[aoffset0] = q0x; a->ptr.p_double[aoffset0+1] = q0y; a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; a->ptr.p_double[aoffset2+1] = a1x*twy+a1y*twx; a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; a->ptr.p_double[aoffset4+1] = a2x*tw2y+a2y*tw2x; a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; a->ptr.p_double[aoffset6+1] = a3x*tw3y+a3y*tw3x; a->ptr.p_double[aoffset8] = a4x*tw4x-a4y*tw4y; a->ptr.p_double[aoffset8+1] = a4x*tw4y+a4y*tw4x; aoffset0 = aoffset0+2; aoffset2 = aoffset2+2; aoffset4 = aoffset4+2; aoffset6 = aoffset6+2; aoffset8 = aoffset8+2; if( (mvidx+1)%ftbase_updatetw==0 ) { v = -2*ae_pi*(mvidx+1)/(n*m); twxm1 = ae_sin(0.5*v, _state); twxm1 = -2*twxm1*twxm1; twy = ae_sin(v, _state); twx = twxm1+1; } else { v = twxm1+tw0+twxm1*tw0-twy*tw1; twy = twy+tw1+twxm1*tw1+twy*tw0; twxm1 = v; twx = v+1; } } } return; } if( n==6 ) { c1 = ae_cos(2*ae_pi/3, _state)-1; c2 = ae_sin(2*ae_pi/3, _state); c3 = ae_cos(-ae_pi/3, _state); c4 = ae_sin(-ae_pi/3, _state); v = -2*ae_pi/(n*m); tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); tw1 = ae_sin(v, _state); for(opidx=0; opidx<=operandscnt-1; opidx++) { aoffset0 = offs+opidx*operandsize*microvectorsize; aoffset2 = aoffset0+microvectorsize; aoffset4 = aoffset2+microvectorsize; aoffset6 = aoffset4+microvectorsize; aoffset8 = aoffset6+microvectorsize; aoffset10 = aoffset8+microvectorsize; twx = 1.0; twxm1 = 0.0; twy = 0.0; for(mvidx=0; mvidx<=m-1; mvidx++) { a0x = a->ptr.p_double[aoffset0+0]; a0y = a->ptr.p_double[aoffset0+1]; a1x = a->ptr.p_double[aoffset2+0]; a1y = a->ptr.p_double[aoffset2+1]; a2x = a->ptr.p_double[aoffset4+0]; a2y = a->ptr.p_double[aoffset4+1]; a3x = a->ptr.p_double[aoffset6+0]; a3y = a->ptr.p_double[aoffset6+1]; a4x = a->ptr.p_double[aoffset8+0]; a4y = a->ptr.p_double[aoffset8+1]; a5x = a->ptr.p_double[aoffset10+0]; a5y = a->ptr.p_double[aoffset10+1]; v0 = a0x; v1 = a0y; a0x = a0x+a3x; a0y = a0y+a3y; a3x = v0-a3x; a3y = v1-a3y; v0 = a1x; v1 = a1y; a1x = a1x+a4x; a1y = a1y+a4y; a4x = v0-a4x; a4y = v1-a4y; v0 = a2x; v1 = a2y; a2x = a2x+a5x; a2y = a2y+a5y; a5x = v0-a5x; a5y = v1-a5y; t4x = a4x*c3-a4y*c4; t4y = a4x*c4+a4y*c3; a4x = t4x; a4y = t4y; t5x = -a5x*c3-a5y*c4; t5y = a5x*c4-a5y*c3; a5x = t5x; a5y = t5y; t1x = a1x+a2x; t1y = a1y+a2y; a0x = a0x+t1x; a0y = a0y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a1y-a2y); m2y = c2*(a2x-a1x); s1x = a0x+m1x; s1y = a0y+m1y; a1x = s1x+m2x; a1y = s1y+m2y; a2x = s1x-m2x; a2y = s1y-m2y; t1x = a4x+a5x; t1y = a4y+a5y; a3x = a3x+t1x; a3y = a3y+t1y; m1x = c1*t1x; m1y = c1*t1y; m2x = c2*(a4y-a5y); m2y = c2*(a5x-a4x); s1x = a3x+m1x; s1y = a3y+m1y; a4x = s1x+m2x; a4y = s1y+m2y; a5x = s1x-m2x; a5y = s1y-m2y; tw2x = twx*twx-twy*twy; tw2y = 2*twx*twy; tw3x = twx*tw2x-twy*tw2y; tw3y = twx*tw2y+twy*tw2x; tw4x = tw2x*tw2x-tw2y*tw2y; tw4y = 2*tw2x*tw2y; tw5x = tw3x*tw2x-tw3y*tw2y; tw5y = tw3x*tw2y+tw3y*tw2x; a->ptr.p_double[aoffset0+0] = a0x; a->ptr.p_double[aoffset0+1] = a0y; a->ptr.p_double[aoffset2+0] = a3x*twx-a3y*twy; a->ptr.p_double[aoffset2+1] = a3y*twx+a3x*twy; a->ptr.p_double[aoffset4+0] = a1x*tw2x-a1y*tw2y; a->ptr.p_double[aoffset4+1] = a1y*tw2x+a1x*tw2y; a->ptr.p_double[aoffset6+0] = a4x*tw3x-a4y*tw3y; a->ptr.p_double[aoffset6+1] = a4y*tw3x+a4x*tw3y; a->ptr.p_double[aoffset8+0] = a2x*tw4x-a2y*tw4y; a->ptr.p_double[aoffset8+1] = a2y*tw4x+a2x*tw4y; a->ptr.p_double[aoffset10+0] = a5x*tw5x-a5y*tw5y; a->ptr.p_double[aoffset10+1] = a5y*tw5x+a5x*tw5y; aoffset0 = aoffset0+2; aoffset2 = aoffset2+2; aoffset4 = aoffset4+2; aoffset6 = aoffset6+2; aoffset8 = aoffset8+2; aoffset10 = aoffset10+2; if( (mvidx+1)%ftbase_updatetw==0 ) { v = -2*ae_pi*(mvidx+1)/(n*m); twxm1 = ae_sin(0.5*v, _state); twxm1 = -2*twxm1*twxm1; twy = ae_sin(v, _state); twx = twxm1+1; } else { v = twxm1+tw0+twxm1*tw0-twy*tw1; twy = twy+tw1+twxm1*tw1+twy*tw0; twxm1 = v; twx = v+1; } } } return; } } /************************************************************************* This subroutine precomputes data for complex Bluestein's FFT and writes them to array PrecR[] at specified offset. It is responsibility of the caller to make sure that PrecR[] is large enough. INPUT PARAMETERS: N - original size of the transform M - size of the "padded" Bluestein's transform PrecR - preallocated array Offs - offset OUTPUT PARAMETERS: PrecR - data at Offs:Offs+4*M-1 are modified: * PrecR[Offs:Offs+2*M-1] stores Z[k]=exp(i*pi*k^2/N) * PrecR[Offs+2*M:Offs+4*M-1] stores FFT of the Z Other parts of PrecR are unchanged. NOTE: this function performs internal M-point FFT. It allocates temporary plan which is destroyed after leaving this function. -- ALGLIB -- Copyright 08.05.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, ae_int_t m, /* Real */ ae_vector* precr, ae_int_t offs, ae_state *_state) { ae_frame _frame_block; ae_int_t i; double bx; double by; fasttransformplan plan; ae_frame_make(_state, &_frame_block); _fasttransformplan_init(&plan, _state); /* * Fill first half of PrecR with b[k] = exp(i*pi*k^2/N) */ for(i=0; i<=2*m-1; i++) { precr->ptr.p_double[offs+i] = (double)(0); } for(i=0; i<=n-1; i++) { bx = ae_cos(ae_pi/n*i*i, _state); by = ae_sin(ae_pi/n*i*i, _state); precr->ptr.p_double[offs+2*i+0] = bx; precr->ptr.p_double[offs+2*i+1] = by; precr->ptr.p_double[offs+2*((m-i)%m)+0] = bx; precr->ptr.p_double[offs+2*((m-i)%m)+1] = by; } /* * Precomputed FFT */ ftcomplexfftplan(m, 1, &plan, _state); for(i=0; i<=2*m-1; i++) { precr->ptr.p_double[offs+2*m+i] = precr->ptr.p_double[offs+i]; } ftbase_ftapplysubplan(&plan, 0, precr, offs+2*m, 0, &plan.buffer, 1, _state); ae_frame_leave(_state); } /************************************************************************* This subroutine applies complex Bluestein's FFT to input/output array A. INPUT PARAMETERS: Plan - transformation plan A - array, must be large enough for plan to work ABase - base offset in array A, this value points to start of subarray whose length is equal to length of the plan AOffset - offset with respect to ABase, 0<=AOffsetptr.p_double[p0+0]; y = a->ptr.p_double[p0+1]; bx = plan->precr.ptr.p_double[p1+0]; by = -plan->precr.ptr.p_double[p1+1]; bufa->ptr.p_double[2*i+0] = x*bx-y*by; bufa->ptr.p_double[2*i+1] = x*by+y*bx; p0 = p0+2; p1 = p1+2; } for(i=2*n; i<=2*m-1; i++) { bufa->ptr.p_double[i] = (double)(0); } /* * Perform convolution of A and Z (using precomputed * FFT of Z stored in Plan structure). */ ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); p0 = 0; p1 = precoffs+2*m; for(i=0; i<=m-1; i++) { ax = bufa->ptr.p_double[p0+0]; ay = bufa->ptr.p_double[p0+1]; bx = plan->precr.ptr.p_double[p1+0]; by = plan->precr.ptr.p_double[p1+1]; bufa->ptr.p_double[p0+0] = ax*bx-ay*by; bufa->ptr.p_double[p0+1] = -(ax*by+ay*bx); p0 = p0+2; p1 = p1+2; } ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); /* * Post processing: * A:=conj(Z)*conj(A)/M * Here conj(A)/M corresponds to last stage of inverse DFT, * and conj(Z) comes from Bluestein's FFT algorithm. */ p0 = precoffs; p1 = 0; p2 = abase+aoffset+op*2*n; for(i=0; i<=n-1; i++) { bx = plan->precr.ptr.p_double[p0+0]; by = plan->precr.ptr.p_double[p0+1]; rx = bufa->ptr.p_double[p1+0]/m; ry = -bufa->ptr.p_double[p1+1]/m; a->ptr.p_double[p2+0] = rx*bx-ry*(-by); a->ptr.p_double[p2+1] = rx*(-by)+ry*bx; p0 = p0+2; p1 = p1+2; p2 = p2+2; } } } /************************************************************************* This subroutine precomputes data for complex Rader's FFT and writes them to array PrecR[] at specified offset. It is responsibility of the caller to make sure that PrecR[] is large enough. INPUT PARAMETERS: N - original size of the transform (before reduction to N-1) RQ - primitive root modulo N RIQ - inverse of primitive root modulo N PrecR - preallocated array Offs - offset OUTPUT PARAMETERS: PrecR - data at Offs:Offs+2*(N-1)-1 store FFT of Rader's factors, other parts of PrecR are unchanged. NOTE: this function performs internal (N-1)-point FFT. It allocates temporary plan which is destroyed after leaving this function. -- ALGLIB -- Copyright 08.05.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftprecomputeradersfft(ae_int_t n, ae_int_t rq, ae_int_t riq, /* Real */ ae_vector* precr, ae_int_t offs, ae_state *_state) { ae_frame _frame_block; ae_int_t q; fasttransformplan plan; ae_int_t kiq; double v; ae_frame_make(_state, &_frame_block); _fasttransformplan_init(&plan, _state); /* * Fill PrecR with Rader factors, perform FFT */ kiq = 1; for(q=0; q<=n-2; q++) { v = -2*ae_pi*kiq/n; precr->ptr.p_double[offs+2*q+0] = ae_cos(v, _state); precr->ptr.p_double[offs+2*q+1] = ae_sin(v, _state); kiq = kiq*riq%n; } ftcomplexfftplan(n-1, 1, &plan, _state); ftbase_ftapplysubplan(&plan, 0, precr, offs, 0, &plan.buffer, 1, _state); ae_frame_leave(_state); } /************************************************************************* This subroutine applies complex Rader's FFT to input/output array A. INPUT PARAMETERS: A - array, must be large enough for plan to work ABase - base offset in array A, this value points to start of subarray whose length is equal to length of the plan AOffset - offset with respect to ABase, 0<=AOffset=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); /* * Process operands */ for(opidx=0; opidx<=operandscnt-1; opidx++) { /* * fill QA */ kq = 1; p0 = abase+aoffset+opidx*n*2; p1 = aoffset+opidx*n*2; rx = a->ptr.p_double[p0+0]; ry = a->ptr.p_double[p0+1]; x0 = rx; y0 = ry; for(q=0; q<=n-2; q++) { ax = a->ptr.p_double[p0+2*kq+0]; ay = a->ptr.p_double[p0+2*kq+1]; buf->ptr.p_double[p1+0] = ax; buf->ptr.p_double[p1+1] = ay; rx = rx+ax; ry = ry+ay; kq = kq*rq%n; p1 = p1+2; } p0 = abase+aoffset+opidx*n*2; p1 = aoffset+opidx*n*2; for(q=0; q<=n-2; q++) { a->ptr.p_double[p0] = buf->ptr.p_double[p1]; a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; p0 = p0+2; p1 = p1+2; } /* * Convolution */ ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); p0 = abase+aoffset+opidx*n*2; p1 = precoffs; for(i=0; i<=n-2; i++) { ax = a->ptr.p_double[p0+0]; ay = a->ptr.p_double[p0+1]; bx = plan->precr.ptr.p_double[p1+0]; by = plan->precr.ptr.p_double[p1+1]; a->ptr.p_double[p0+0] = ax*bx-ay*by; a->ptr.p_double[p0+1] = -(ax*by+ay*bx); p0 = p0+2; p1 = p1+2; } ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); p0 = abase+aoffset+opidx*n*2; for(i=0; i<=n-2; i++) { a->ptr.p_double[p0+0] = a->ptr.p_double[p0+0]/(n-1); a->ptr.p_double[p0+1] = -a->ptr.p_double[p0+1]/(n-1); p0 = p0+2; } /* * Result */ buf->ptr.p_double[aoffset+opidx*n*2+0] = rx; buf->ptr.p_double[aoffset+opidx*n*2+1] = ry; kiq = 1; p0 = aoffset+opidx*n*2; p1 = abase+aoffset+opidx*n*2; for(q=0; q<=n-2; q++) { buf->ptr.p_double[p0+2*kiq+0] = x0+a->ptr.p_double[p1+0]; buf->ptr.p_double[p0+2*kiq+1] = y0+a->ptr.p_double[p1+1]; kiq = kiq*riq%n; p1 = p1+2; } p0 = abase+aoffset+opidx*n*2; p1 = aoffset+opidx*n*2; for(q=0; q<=n-1; q++) { a->ptr.p_double[p0] = buf->ptr.p_double[p1]; a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; p0 = p0+2; p1 = p1+2; } } } /************************************************************************* Factorizes task size N into product of two smaller sizes N1 and N2 INPUT PARAMETERS: N - task size, N>0 IsRoot - whether taks is root task (first one in a sequence) OUTPUT PARAMETERS: N1, N2 - such numbers that: * for prime N: N1=N2=0 * for composite N<=MaxRadix: N1=N2=0 * for composite N>MaxRadix: 1<=N1<=N2, N1*N2=N -- ALGLIB -- Copyright 08.04.2013 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftfactorize(ae_int_t n, ae_bool isroot, ae_int_t* n1, ae_int_t* n2, ae_state *_state) { ae_int_t j; ae_int_t k; *n1 = 0; *n2 = 0; ae_assert(n>0, "FTFactorize: N<=0", _state); *n1 = 0; *n2 = 0; /* * Small N */ if( n<=ftbase_maxradix ) { return; } /* * Large N, recursive split */ if( n>ftbase_recursivethreshold ) { k = ae_iceil(ae_sqrt((double)(n), _state), _state)+1; ae_assert(k*k>=n, "FTFactorize: internal error during recursive factorization", _state); for(j=k; j>=2; j--) { if( n%j==0 ) { *n1 = ae_minint(n/j, j, _state); *n2 = ae_maxint(n/j, j, _state); return; } } } /* * N>MaxRadix, try to find good codelet */ for(j=ftbase_maxradix; j>=2; j--) { if( n%j==0 ) { *n1 = j; *n2 = n/j; break; } } /* * In case no good codelet was found, * try to factorize N into product of ANY primes. */ if( *n1*(*n2)!=n ) { for(j=2; j<=n-1; j++) { if( n%j==0 ) { *n1 = j; *n2 = n/j; break; } if( j*j>n ) { break; } } } /* * normalize */ if( *n1>(*n2) ) { j = *n1; *n1 = *n2; *n2 = j; } } /************************************************************************* Returns optimistic estimate of the FFT cost, in UNITs (1 UNIT = 100 KFLOPs) INPUT PARAMETERS: N - task size, N>0 RESULU: cost in UNITs, rounded down to nearest integer NOTE: If FFT cost is less than 1 UNIT, it will return 0 as result. -- ALGLIB -- Copyright 08.04.2013 by Bochkanov Sergey *************************************************************************/ static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state) { ae_int_t result; ae_assert(n>0, "FTOptimisticEstimate: N<=0", _state); result = ae_ifloor(1.0E-5*5*n*ae_log((double)(n), _state)/ae_log((double)(2), _state), _state); return result; } /************************************************************************* Twiddle factors calculation -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ static void ftbase_ffttwcalc(/* Real */ ae_vector* a, ae_int_t aoffset, ae_int_t n1, ae_int_t n2, ae_state *_state) { ae_int_t i; ae_int_t j2; ae_int_t n; ae_int_t halfn1; ae_int_t offs; double x; double y; double twxm1; double twy; double twbasexm1; double twbasey; double twrowxm1; double twrowy; double tmpx; double tmpy; double v; ae_int_t updatetw2; /* * Multiplication by twiddle factors for complex Cooley-Tukey FFT * with N factorized as N1*N2. * * Naive solution to this problem is given below: * * > for K:=1 to N2-1 do * > for J:=1 to N1-1 do * > begin * > Idx:=K*N1+J; * > X:=A[AOffset+2*Idx+0]; * > Y:=A[AOffset+2*Idx+1]; * > TwX:=Cos(-2*Pi()*K*J/(N1*N2)); * > TwY:=Sin(-2*Pi()*K*J/(N1*N2)); * > A[AOffset+2*Idx+0]:=X*TwX-Y*TwY; * > A[AOffset+2*Idx+1]:=X*TwY+Y*TwX; * > end; * * However, there are exist more efficient solutions. * * Each pass of the inner cycle corresponds to multiplication of one * entry of A by W[k,j]=exp(-I*2*pi*k*j/N). This factor can be rewritten * as exp(-I*2*pi*k/N)^j. So we can replace costly exponentiation by * repeated multiplication: W[k,j+1]=W[k,j]*exp(-I*2*pi*k/N), with * second factor being computed once in the beginning of the iteration. * * Also, exp(-I*2*pi*k/N) can be represented as exp(-I*2*pi/N)^k, i.e. * we have W[K+1,1]=W[K,1]*W[1,1]. * * In our loop we use following variables: * * [TwBaseXM1,TwBaseY] = [cos(2*pi/N)-1, sin(2*pi/N)] * * [TwRowXM1, TwRowY] = [cos(2*pi*I/N)-1, sin(2*pi*I/N)] * * [TwXM1, TwY] = [cos(2*pi*I*J/N)-1, sin(2*pi*I*J/N)] * * Meaning of the variables: * * [TwXM1,TwY] is current twiddle factor W[I,J] * * [TwRowXM1, TwRowY] is W[I,1] * * [TwBaseXM1,TwBaseY] is W[1,1] * * During inner loop we multiply current twiddle factor by W[I,1], * during outer loop we update W[I,1]. * */ ae_assert(ftbase_updatetw>=2, "FFTTwCalc: internal error - UpdateTw<2", _state); updatetw2 = ftbase_updatetw/2; halfn1 = n1/2; n = n1*n2; v = -2*ae_pi/n; twbasexm1 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); twbasey = ae_sin(v, _state); twrowxm1 = (double)(0); twrowy = (double)(0); offs = aoffset; for(i=0; i<=n2-1; i++) { /* * Initialize twiddle factor for current row */ twxm1 = (double)(0); twy = (double)(0); /* * N1-point block is separated into 2-point chunks and residual 1-point chunk * (in case N1 is odd). Unrolled loop is several times faster. */ for(j2=0; j2<=halfn1-1; j2++) { /* * Processing: * * process first element in a chunk. * * update twiddle factor (unconditional update) * * process second element * * conditional update of the twiddle factor */ x = a->ptr.p_double[offs+0]; y = a->ptr.p_double[offs+1]; tmpx = x*(1+twxm1)-y*twy; tmpy = x*twy+y*(1+twxm1); a->ptr.p_double[offs+0] = tmpx; a->ptr.p_double[offs+1] = tmpy; tmpx = (1+twxm1)*twrowxm1-twy*twrowy; twy = twy+(1+twxm1)*twrowy+twy*twrowxm1; twxm1 = twxm1+tmpx; x = a->ptr.p_double[offs+2]; y = a->ptr.p_double[offs+3]; tmpx = x*(1+twxm1)-y*twy; tmpy = x*twy+y*(1+twxm1); a->ptr.p_double[offs+2] = tmpx; a->ptr.p_double[offs+3] = tmpy; offs = offs+4; if( (j2+1)%updatetw2==0&&j2ptr.p_double[offs+0]; y = a->ptr.p_double[offs+1]; tmpx = x*(1+twxm1)-y*twy; tmpy = x*twy+y*(1+twxm1); a->ptr.p_double[offs+0] = tmpx; a->ptr.p_double[offs+1] = tmpy; offs = offs+2; } /* * update TwRow: TwRow(new) = TwRow(old)*TwBase */ if( iptr.p_double[astart], 1, &buf->ptr.p_double[0], 1, ae_v_len(astart,astart+2*m*n-1)); } /************************************************************************* Recurrent subroutine for a InternalComplexLinTranspose Write A^T to B, where: * A is m*n complex matrix stored in array A as pairs of real/image values, beginning from AStart position, with AStride stride * B is n*m complex matrix stored in array B as pairs of real/image values, beginning from BStart position, with BStride stride stride is measured in complex numbers, i.e. in real/image pairs. -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ static void ftbase_ffticltrec(/* Real */ ae_vector* a, ae_int_t astart, ae_int_t astride, /* Real */ ae_vector* b, ae_int_t bstart, ae_int_t bstride, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t idx1; ae_int_t idx2; ae_int_t m2; ae_int_t m1; ae_int_t n1; if( m==0||n==0 ) { return; } if( ae_maxint(m, n, _state)<=8 ) { m2 = 2*bstride; for(i=0; i<=m-1; i++) { idx1 = bstart+2*i; idx2 = astart+2*i*astride; for(j=0; j<=n-1; j++) { b->ptr.p_double[idx1+0] = a->ptr.p_double[idx2+0]; b->ptr.p_double[idx1+1] = a->ptr.p_double[idx2+1]; idx1 = idx1+m2; idx2 = idx2+2; } } return; } if( n>m ) { /* * New partition: * * "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) * ( B2 ) */ n1 = n/2; if( n-n1>=8&&n1%8!=0 ) { n1 = n1+(8-n1%8); } ae_assert(n-n1>0, "Assertion failed", _state); ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1, _state); ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1, _state); } else { /* * New partition: * * "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) * ( A2 ) */ m1 = m/2; if( m-m1>=8&&m1%8!=0 ) { m1 = m1+(8-m1%8); } ae_assert(m-m1>0, "Assertion failed", _state); ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n, _state); ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n, _state); } } /************************************************************************* Recurrent subroutine for a InternalRealLinTranspose -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ static void ftbase_fftirltrec(/* Real */ ae_vector* a, ae_int_t astart, ae_int_t astride, /* Real */ ae_vector* b, ae_int_t bstart, ae_int_t bstride, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t idx1; ae_int_t idx2; ae_int_t m1; ae_int_t n1; if( m==0||n==0 ) { return; } if( ae_maxint(m, n, _state)<=8 ) { for(i=0; i<=m-1; i++) { idx1 = bstart+i; idx2 = astart+i*astride; for(j=0; j<=n-1; j++) { b->ptr.p_double[idx1] = a->ptr.p_double[idx2]; idx1 = idx1+bstride; idx2 = idx2+1; } } return; } if( n>m ) { /* * New partition: * * "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) * ( B2 ) */ n1 = n/2; if( n-n1>=8&&n1%8!=0 ) { n1 = n1+(8-n1%8); } ae_assert(n-n1>0, "Assertion failed", _state); ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m, n1, _state); ftbase_fftirltrec(a, astart+n1, astride, b, bstart+n1*bstride, bstride, m, n-n1, _state); } else { /* * New partition: * * "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) * ( A2 ) */ m1 = m/2; if( m-m1>=8&&m1%8!=0 ) { m1 = m1+(8-m1%8); } ae_assert(m-m1>0, "Assertion failed", _state); ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m1, n, _state); ftbase_fftirltrec(a, astart+m1*astride, astride, b, bstart+m1, bstride, m-m1, n, _state); } } /************************************************************************* recurrent subroutine for FFTFindSmoothRec -- ALGLIB -- Copyright 01.05.2009 by Bochkanov Sergey *************************************************************************/ static void ftbase_ftbasefindsmoothrec(ae_int_t n, ae_int_t seed, ae_int_t leastfactor, ae_int_t* best, ae_state *_state) { ae_assert(ftbase_ftbasemaxsmoothfactor<=5, "FTBaseFindSmoothRec: internal error!", _state); if( seed>=n ) { *best = ae_minint(*best, seed, _state); return; } if( leastfactor<=2 ) { ftbase_ftbasefindsmoothrec(n, seed*2, 2, best, _state); } if( leastfactor<=3 ) { ftbase_ftbasefindsmoothrec(n, seed*3, 3, best, _state); } if( leastfactor<=5 ) { ftbase_ftbasefindsmoothrec(n, seed*5, 5, best, _state); } } void _fasttransformplan_init(void* _p, ae_state *_state) { fasttransformplan *p = (fasttransformplan*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->entries, 0, 0, DT_INT, _state); ae_vector_init(&p->buffer, 0, DT_REAL, _state); ae_vector_init(&p->precr, 0, DT_REAL, _state); ae_vector_init(&p->preci, 0, DT_REAL, _state); ae_shared_pool_init(&p->bluesteinpool, _state); } void _fasttransformplan_init_copy(void* _dst, void* _src, ae_state *_state) { fasttransformplan *dst = (fasttransformplan*)_dst; fasttransformplan *src = (fasttransformplan*)_src; ae_matrix_init_copy(&dst->entries, &src->entries, _state); ae_vector_init_copy(&dst->buffer, &src->buffer, _state); ae_vector_init_copy(&dst->precr, &src->precr, _state); ae_vector_init_copy(&dst->preci, &src->preci, _state); ae_shared_pool_init_copy(&dst->bluesteinpool, &src->bluesteinpool, _state); } void _fasttransformplan_clear(void* _p) { fasttransformplan *p = (fasttransformplan*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->entries); ae_vector_clear(&p->buffer); ae_vector_clear(&p->precr); ae_vector_clear(&p->preci); ae_shared_pool_clear(&p->bluesteinpool); } void _fasttransformplan_destroy(void* _p) { fasttransformplan *p = (fasttransformplan*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->entries); ae_vector_destroy(&p->buffer); ae_vector_destroy(&p->precr); ae_vector_destroy(&p->preci); ae_shared_pool_destroy(&p->bluesteinpool); } double nulog1p(double x, ae_state *_state) { double z; double lp; double lq; double result; z = 1.0+x; if( ae_fp_less(z,0.70710678118654752440)||ae_fp_greater(z,1.41421356237309504880) ) { result = ae_log(z, _state); return result; } z = x*x; lp = 4.5270000862445199635215E-5; lp = lp*x+4.9854102823193375972212E-1; lp = lp*x+6.5787325942061044846969E0; lp = lp*x+2.9911919328553073277375E1; lp = lp*x+6.0949667980987787057556E1; lp = lp*x+5.7112963590585538103336E1; lp = lp*x+2.0039553499201281259648E1; lq = 1.0000000000000000000000E0; lq = lq*x+1.5062909083469192043167E1; lq = lq*x+8.3047565967967209469434E1; lq = lq*x+2.2176239823732856465394E2; lq = lq*x+3.0909872225312059774938E2; lq = lq*x+2.1642788614495947685003E2; lq = lq*x+6.0118660497603843919306E1; z = -0.5*z+x*(z*lp/lq); result = x+z; return result; } double nuexpm1(double x, ae_state *_state) { double r; double xx; double ep; double eq; double result; if( ae_fp_less(x,-0.5)||ae_fp_greater(x,0.5) ) { result = ae_exp(x, _state)-1.0; return result; } xx = x*x; ep = 1.2617719307481059087798E-4; ep = ep*xx+3.0299440770744196129956E-2; ep = ep*xx+9.9999999999999999991025E-1; eq = 3.0019850513866445504159E-6; eq = eq*xx+2.5244834034968410419224E-3; eq = eq*xx+2.2726554820815502876593E-1; eq = eq*xx+2.0000000000000000000897E0; r = x*ep; r = r/(eq-r); result = r+r; return result; } double nucosm1(double x, ae_state *_state) { double xx; double c; double result; if( ae_fp_less(x,-0.25*ae_pi)||ae_fp_greater(x,0.25*ae_pi) ) { result = ae_cos(x, _state)-1; return result; } xx = x*x; c = 4.7377507964246204691685E-14; c = c*xx-1.1470284843425359765671E-11; c = c*xx+2.0876754287081521758361E-9; c = c*xx-2.7557319214999787979814E-7; c = c*xx+2.4801587301570552304991E-5; c = c*xx-1.3888888888888872993737E-3; c = c*xx+4.1666666666666666609054E-2; result = -0.5*xx+xx*xx*c; return result; } } qmapshack-1.10.0/3rdparty/alglib/src/solvers.h000755 001750 000144 00000515601 13015033052 022364 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _solvers_pkg_h #define _solvers_pkg_h #include "ap.h" #include "alglibinternal.h" #include "linalg.h" #include "alglibmisc.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { double r1; double rinf; } densesolverreport; typedef struct { double r2; ae_matrix cx; ae_int_t n; ae_int_t k; } densesolverlsreport; typedef struct { normestimatorstate nes; ae_vector rx; ae_vector b; ae_int_t n; ae_int_t m; ae_int_t prectype; ae_vector ui; ae_vector uip1; ae_vector vi; ae_vector vip1; ae_vector omegai; ae_vector omegaip1; double alphai; double alphaip1; double betai; double betaip1; double phibari; double phibarip1; double phii; double rhobari; double rhobarip1; double rhoi; double ci; double si; double theta; double lambdai; ae_vector d; double anorm; double bnorm2; double dnorm; double r2; ae_vector x; ae_vector mv; ae_vector mtv; double epsa; double epsb; double epsc; ae_int_t maxits; ae_bool xrep; ae_bool xupdated; ae_bool needmv; ae_bool needmtv; ae_bool needmv2; ae_bool needvmv; ae_bool needprec; ae_int_t repiterationscount; ae_int_t repnmv; ae_int_t repterminationtype; ae_bool running; ae_vector tmpd; ae_vector tmpx; rcommstate rstate; } linlsqrstate; typedef struct { ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; } linlsqrreport; typedef struct { ae_vector rx; ae_vector b; ae_int_t n; ae_int_t prectype; ae_vector cx; ae_vector cr; ae_vector cz; ae_vector p; ae_vector r; ae_vector z; double alpha; double beta; double r2; double meritfunction; ae_vector x; ae_vector mv; ae_vector pv; double vmv; ae_vector startx; double epsf; ae_int_t maxits; ae_int_t itsbeforerestart; ae_int_t itsbeforerupdate; ae_bool xrep; ae_bool xupdated; ae_bool needmv; ae_bool needmtv; ae_bool needmv2; ae_bool needvmv; ae_bool needprec; ae_int_t repiterationscount; ae_int_t repnmv; ae_int_t repterminationtype; ae_bool running; ae_vector tmpd; rcommstate rstate; } lincgstate; typedef struct { ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; double r2; } lincgreport; typedef struct { ae_int_t n; ae_int_t m; double epsf; ae_int_t maxits; ae_bool xrep; double stpmax; ae_vector x; double f; ae_vector fi; ae_matrix j; ae_bool needf; ae_bool needfij; ae_bool xupdated; rcommstate rstate; ae_int_t repiterationscount; ae_int_t repnfunc; ae_int_t repnjac; ae_int_t repterminationtype; ae_vector xbase; double fbase; double fprev; ae_vector candstep; ae_vector rightpart; ae_vector cgbuf; } nleqstate; typedef struct { ae_int_t iterationscount; ae_int_t nfunc; ae_int_t njac; ae_int_t terminationtype; } nleqreport; typedef struct { double maxerr; } polynomialsolverreport; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* *************************************************************************/ class _densesolverreport_owner { public: _densesolverreport_owner(); _densesolverreport_owner(const _densesolverreport_owner &rhs); _densesolverreport_owner& operator=(const _densesolverreport_owner &rhs); virtual ~_densesolverreport_owner(); alglib_impl::densesolverreport* c_ptr(); alglib_impl::densesolverreport* c_ptr() const; protected: alglib_impl::densesolverreport *p_struct; }; class densesolverreport : public _densesolverreport_owner { public: densesolverreport(); densesolverreport(const densesolverreport &rhs); densesolverreport& operator=(const densesolverreport &rhs); virtual ~densesolverreport(); double &r1; double &rinf; }; /************************************************************************* *************************************************************************/ class _densesolverlsreport_owner { public: _densesolverlsreport_owner(); _densesolverlsreport_owner(const _densesolverlsreport_owner &rhs); _densesolverlsreport_owner& operator=(const _densesolverlsreport_owner &rhs); virtual ~_densesolverlsreport_owner(); alglib_impl::densesolverlsreport* c_ptr(); alglib_impl::densesolverlsreport* c_ptr() const; protected: alglib_impl::densesolverlsreport *p_struct; }; class densesolverlsreport : public _densesolverlsreport_owner { public: densesolverlsreport(); densesolverlsreport(const densesolverlsreport &rhs); densesolverlsreport& operator=(const densesolverlsreport &rhs); virtual ~densesolverlsreport(); double &r2; real_2d_array cx; ae_int_t &n; ae_int_t &k; }; /************************************************************************* This object stores state of the LinLSQR method. You should use ALGLIB functions to work with this object. *************************************************************************/ class _linlsqrstate_owner { public: _linlsqrstate_owner(); _linlsqrstate_owner(const _linlsqrstate_owner &rhs); _linlsqrstate_owner& operator=(const _linlsqrstate_owner &rhs); virtual ~_linlsqrstate_owner(); alglib_impl::linlsqrstate* c_ptr(); alglib_impl::linlsqrstate* c_ptr() const; protected: alglib_impl::linlsqrstate *p_struct; }; class linlsqrstate : public _linlsqrstate_owner { public: linlsqrstate(); linlsqrstate(const linlsqrstate &rhs); linlsqrstate& operator=(const linlsqrstate &rhs); virtual ~linlsqrstate(); }; /************************************************************************* *************************************************************************/ class _linlsqrreport_owner { public: _linlsqrreport_owner(); _linlsqrreport_owner(const _linlsqrreport_owner &rhs); _linlsqrreport_owner& operator=(const _linlsqrreport_owner &rhs); virtual ~_linlsqrreport_owner(); alglib_impl::linlsqrreport* c_ptr(); alglib_impl::linlsqrreport* c_ptr() const; protected: alglib_impl::linlsqrreport *p_struct; }; class linlsqrreport : public _linlsqrreport_owner { public: linlsqrreport(); linlsqrreport(const linlsqrreport &rhs); linlsqrreport& operator=(const linlsqrreport &rhs); virtual ~linlsqrreport(); ae_int_t &iterationscount; ae_int_t &nmv; ae_int_t &terminationtype; }; /************************************************************************* This object stores state of the linear CG method. You should use ALGLIB functions to work with this object. Never try to access its fields directly! *************************************************************************/ class _lincgstate_owner { public: _lincgstate_owner(); _lincgstate_owner(const _lincgstate_owner &rhs); _lincgstate_owner& operator=(const _lincgstate_owner &rhs); virtual ~_lincgstate_owner(); alglib_impl::lincgstate* c_ptr(); alglib_impl::lincgstate* c_ptr() const; protected: alglib_impl::lincgstate *p_struct; }; class lincgstate : public _lincgstate_owner { public: lincgstate(); lincgstate(const lincgstate &rhs); lincgstate& operator=(const lincgstate &rhs); virtual ~lincgstate(); }; /************************************************************************* *************************************************************************/ class _lincgreport_owner { public: _lincgreport_owner(); _lincgreport_owner(const _lincgreport_owner &rhs); _lincgreport_owner& operator=(const _lincgreport_owner &rhs); virtual ~_lincgreport_owner(); alglib_impl::lincgreport* c_ptr(); alglib_impl::lincgreport* c_ptr() const; protected: alglib_impl::lincgreport *p_struct; }; class lincgreport : public _lincgreport_owner { public: lincgreport(); lincgreport(const lincgreport &rhs); lincgreport& operator=(const lincgreport &rhs); virtual ~lincgreport(); ae_int_t &iterationscount; ae_int_t &nmv; ae_int_t &terminationtype; double &r2; }; /************************************************************************* *************************************************************************/ class _nleqstate_owner { public: _nleqstate_owner(); _nleqstate_owner(const _nleqstate_owner &rhs); _nleqstate_owner& operator=(const _nleqstate_owner &rhs); virtual ~_nleqstate_owner(); alglib_impl::nleqstate* c_ptr(); alglib_impl::nleqstate* c_ptr() const; protected: alglib_impl::nleqstate *p_struct; }; class nleqstate : public _nleqstate_owner { public: nleqstate(); nleqstate(const nleqstate &rhs); nleqstate& operator=(const nleqstate &rhs); virtual ~nleqstate(); ae_bool &needf; ae_bool &needfij; ae_bool &xupdated; double &f; real_1d_array fi; real_2d_array j; real_1d_array x; }; /************************************************************************* *************************************************************************/ class _nleqreport_owner { public: _nleqreport_owner(); _nleqreport_owner(const _nleqreport_owner &rhs); _nleqreport_owner& operator=(const _nleqreport_owner &rhs); virtual ~_nleqreport_owner(); alglib_impl::nleqreport* c_ptr(); alglib_impl::nleqreport* c_ptr() const; protected: alglib_impl::nleqreport *p_struct; }; class nleqreport : public _nleqreport_owner { public: nleqreport(); nleqreport(const nleqreport &rhs); nleqreport& operator=(const nleqreport &rhs); virtual ~nleqreport(); ae_int_t &iterationscount; ae_int_t &nfunc; ae_int_t &njac; ae_int_t &terminationtype; }; /************************************************************************* *************************************************************************/ class _polynomialsolverreport_owner { public: _polynomialsolverreport_owner(); _polynomialsolverreport_owner(const _polynomialsolverreport_owner &rhs); _polynomialsolverreport_owner& operator=(const _polynomialsolverreport_owner &rhs); virtual ~_polynomialsolverreport_owner(); alglib_impl::polynomialsolverreport* c_ptr(); alglib_impl::polynomialsolverreport* c_ptr() const; protected: alglib_impl::polynomialsolverreport *p_struct; }; class polynomialsolverreport : public _polynomialsolverreport_owner { public: polynomialsolverreport(); polynomialsolverreport(const polynomialsolverreport &rhs); polynomialsolverreport& operator=(const polynomialsolverreport &rhs); virtual ~polynomialsolverreport(); double &maxerr; }; /************************************************************************* Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and b. This is "slow-but-feature rich" version of the linear solver. Faster version is RMatrixSolveFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); void smp_rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix, x and b are vectors. This is a "fast" version of linear solver which does NOT provide any additional functions like condition number estimation or iterative refinement. Algorithm features: * efficient algorithm O(N^3) complexity * no performance overhead from additional functionality If you need condition number estimation or iterative refinement, use more feature-rich version - RMatrixSolve(). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info); void smp_rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "slow-but-robust" version of linear solver with additional functionality like condition number estimation. There also exists faster version - RMatrixSolveMFast(). Algorithm features: * automatic detection of degenerate cases * condition number estimation * optional iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 A is ill conditioned or singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x); void smp_rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x); /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "fast" version of linear solver which does NOT offer additional functions like condition number estimation or iterative refinement. Algorithm features: * O(N^3+M*N^2) complexity * no additional functionality, highest performance COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "slow-but-robust" version of the linear LU-based solver. Faster version is RMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "fast-without-any-checks" version of the linear LU-based solver. Slower but more robust version is RMatrixLUSolve() function. Algorithm features: * O(N^2) complexity * fast algorithm without ANY additional checks, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "robust-but-slow" version of LU-based solver which performs additional checks for non-degeneracy of inputs (condition number estimation). If you need best performance, use "fast-without-any-checks" version, RMatrixLUSolveMFast(). Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); void smp_rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts, where b and x are NxM matrices. This is "fast-without-any-checks" version of LU-based solver. It does not estimate condition number of a system, so it is extremely fast. If you need better detection of near-degenerate cases, use RMatrixLUSolveM() function. Algorithm features: * O(M*N^2) complexity * fast algorithm without ANY additional checks, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have both A and its LU decomposition. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); /************************************************************************* Dense solver. Similar to RMatrixMixedSolve() but solves task with multiple right parts (where b and x are NxM matrices). Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Slow-but-feature-rich" version which provides additional functions, at the cost of slower performance. Faster version may be invoked with CMatrixSolveMFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); void smp_cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Fast-but-lightweight" version which provides just triangular solver - and no additional functions like iterative refinement or condition number estimation. Algorithm features: * O(N^3+M*N^2) complexity * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); void smp_cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * no additional time consuming features, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info); void smp_cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); void smp_cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * no additional time-consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Complex dense linear solver for A*x=b with complex N*N A given by its LU decomposition and N*1 vectors x and b. This is "slow-but-robust" version of the complex linear solver with additional features which add significant performance overhead. Faster version is CMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); /************************************************************************* Complex dense linear solver for A*x=b with N*N complex A given by its LU decomposition and N*1 vectors x and b. This is fast lightweight version of solver, which is significantly faster than CMatrixLUSolve(), but does not provide additional information (like condition numbers). Algorithm features: * O(N^2) complexity * no additional time-consuming features, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros NOTE: unlike CMatrixLUSolve(), this function does NOT check for near-degeneracy of input matrix. It checks for EXACT degeneracy, because this check is easy to do. However, very badly conditioned matrices may went unnoticed. -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); /************************************************************************* Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); void smp_spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular * -1 N<=0 was passed * 1 task was solved B - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); void smp_spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or non-SPD * -1 N<=0 was passed * 1 task was solved B - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info); void smp_spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); void smp_spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- lightweight" version of the solver which just solves linear system, without any additional functions. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional functionality INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- but-feature-rich" version of the solver which, in addition to the solution, performs condition number estimation. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvefast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems (N<100). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - same as in RMatrixSolve. Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); void smp_hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or is not positive definite. B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[0..N-1]: * overwritten by solution * zeros, if problem was not solved -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, HPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - same as in RMatrixSolve Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); void smp_hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver without additional functions. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or not positive definite X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[0..N-1]: * overwritten by solution * zeros, if A is exactly singular (diagonal of its LU decomposition has exact zeros). -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info); void smp_hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "slow-but-feature-rich" version of the solver which, in addition to the solution, estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large Cholesky decomposition. However, if you call ! this function many times for the same left side, this ! overhead BECOMES significant. It also becomes significant ! for small-scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); void smp_hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); void smp_hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info); /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "slow-but-feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info); /************************************************************************* Dense solver. This subroutine finds solution of the linear system A*X=B with non-square, possibly degenerate A. System is solved in the least squares sense, and general least squares solution X = X0 + CX*y which minimizes |A*X-B| is returned. If A is non-degenerate, solution in the usual sense is returned. Algorithm features: * automatic detection (and correct handling!) of degenerate cases * iterative refinement * O(N^3) complexity COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..NRows-1,0..NCols-1], system matrix NRows - vertical size of A NCols - horizontal size of A B - array[0..NCols-1], right part Threshold- a number in [0,1]. Singular values beyond Threshold are considered zero. Set it to 0.0, if you don't understand what it means, so the solver will choose good value on its own. OUTPUT PARAMETERS Info - return code: * -4 SVD subroutine failed * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed * 1 if task is solved Rep - solver report, see below for more info X - array[0..N-1,0..M-1], it contains: * solution of A*X=B (even for singular A) * zeros, if SVD subroutine failed SOLVER REPORT Subroutine sets following fields of the Rep structure: * R2 reciprocal of condition number: 1/cond(A), 2-norm. * N = NCols * K dim(Null(A)) * CX array[0..N-1,0..K-1], kernel of A. Columns of CX store such vectors that A*CX[i]=0. -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x); void smp_rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x); /************************************************************************* This function initializes linear LSQR Solver. This solver is used to solve non-symmetric (and, possibly, non-square) problems. Least squares solution is returned for non-compatible systems. USAGE: 1. User initializes algorithm state with LinLSQRCreate() call 2. User tunes solver parameters with LinLSQRSetCond() and other functions 3. User calls LinLSQRSolveSparse() function which takes algorithm state and SparseMatrix object. 4. User calls LinLSQRResults() to get solution 5. Optionally, user may call LinLSQRSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinLSQRState structure. INPUT PARAMETERS: M - number of rows in A N - number of variables, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state); /************************************************************************* This function changes preconditioning settings of LinLSQQSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecunit(const linlsqrstate &state); /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecdiag(const linlsqrstate &state); /************************************************************************* This function sets optional Tikhonov regularization coefficient. It is zero by default. INPUT PARAMETERS: LambdaI - regularization factor, LambdaI>=0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetlambdai(const linlsqrstate &state, const double lambdai); /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse M*N matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function BEFORE you pass it to this function). B - right part, array[M] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinLSQRSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsolvesparse(const linlsqrstate &state, const sparsematrix &a, const real_1d_array &b); /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| MaxIts - algorithm will be stopped if number of iterations more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will be setted as default values. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetcond(const linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits); /************************************************************************* LSQR solver: results. This function must be called after LinLSQRSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * 1 ||Rk||<=EpsB*||B|| * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, X contains best point found so far. (sometimes returned on singular systems) * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetxrep(const linlsqrstate &state, const bool needxrep); /************************************************************************* This function initializes linear CG Solver. This solver is used to solve symmetric positive definite problems. If you want to solve nonsymmetric (or non-positive definite) problem you may use LinLSQR solver provided by ALGLIB. USAGE: 1. User initializes algorithm state with LinCGCreate() call 2. User tunes solver parameters with LinCGSetCond() and other functions 3. Optionally, user sets starting point with LinCGSetStartingPoint() 4. User calls LinCGSolveSparse() function which takes algorithm state and SparseMatrix object. 5. User calls LinCGResults() to get solution 6. Optionally, user may call LinCGSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinCGState structure. INPUT PARAMETERS: N - problem dimension, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgcreate(const ae_int_t n, lincgstate &state); /************************************************************************* This function sets starting point. By default, zero starting point is used. INPUT PARAMETERS: X - starting point, array[N] OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetstartingpoint(const lincgstate &state, const real_1d_array &x); /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecunit(const lincgstate &state); /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecdiag(const lincgstate &state); /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsF - algorithm will be stopped if norm of residual is less than EpsF*||b||. MaxIts - algorithm will be stopped if number of iterations is more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: If both EpsF and MaxIts are zero then small EpsF will be set to small value. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetcond(const lincgstate &state, const double epsf, const ae_int_t maxits); /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function). IsUpper - whether upper or lower triangle of A is used: * IsUpper=True => only upper triangle is used and lower triangle is not referenced at all * IsUpper=False => only lower triangle is used and upper triangle is not referenced at all B - right part, array[N] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinCGSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsolvesparse(const lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b); /************************************************************************* CG-solver: results. This function must be called after LinCGSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * -5 input matrix is either not positive definite, too large or too small * -4 overflow/underflow during solution (ill conditioned problem) * 1 ||residual||<=EpsF*||b|| * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, best point found is returned * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep); /************************************************************************* This function sets restart frequency. By default, algorithm is restarted after N subsequent iterations. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrestartfreq(const lincgstate &state, const ae_int_t srf); /************************************************************************* This function sets frequency of residual recalculations. Algorithm updates residual r_k using iterative formula, but recalculates it from scratch after each 10 iterations. It is done to avoid accumulation of numerical errors and to stop algorithm when r_k starts to grow. Such low update frequence (1/10) gives very little overhead, but makes algorithm a bit more robust against numerical errors. However, you may change it INPUT PARAMETERS: Freq - desired update frequency, Freq>=0. Zero value means that no updates will be done. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrupdatefreq(const lincgstate &state, const ae_int_t freq); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetxrep(const lincgstate &state, const bool needxrep); /************************************************************************* LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER DESCRIPTION: This algorithm solves system of nonlinear equations F[0](x[0], ..., x[n-1]) = 0 F[1](x[0], ..., x[n-1]) = 0 ... F[M-1](x[0], ..., x[n-1]) = 0 with M/N do not necessarily coincide. Algorithm converges quadratically under following conditions: * the solution set XS is nonempty * for some xs in XS there exist such neighbourhood N(xs) that: * vector function F(x) and its Jacobian J(x) are continuously differentiable on N * ||F(x)|| provides local error bound on N, i.e. there exists such c1, that ||F(x)||>c1*distance(x,XS) Note that these conditions are much more weaker than usual non-singularity conditions. For example, algorithm will converge for any affine function F (whether its Jacobian singular or not). REQUIREMENTS: Algorithm will request following information during its operation: * function vector F[] and Jacobian matrix at given point X * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X USAGE: 1. User initializes algorithm state with NLEQCreateLM() call 2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and other functions 3. User calls NLEQSolve() function which takes algorithm state and pointers (delegates, etc.) to callback functions which calculate merit function value and Jacobian. 4. User calls NLEQResults() to get solution 5. Optionally, user may call NLEQRestartFrom() to solve another problem with same parameters (N/M) but another starting point and/or another function vector. NLEQRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - space dimension, N>1: * if provided, only leading N elements of X are used * if not provided, determined automatically from size of X M - system size X - starting point OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with NLEQSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use NLEQSetStpMax() function to bound algorithm's steps. 3. this algorithm is a slightly modified implementation of the method described in 'Levenberg-Marquardt method for constrained nonlinear equations with strong local convergence properties' by Christian Kanzow Nobuo Yamashita and Masao Fukushima and further developed in 'On the convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang Yuan. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state); void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state); /************************************************************************* This function sets stopping conditions for the nonlinear solver INPUT PARAMETERS: State - structure which stores algorithm state EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition ||F||<=EpsF is satisfied MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic stopping criterion selection (small EpsF). NOTES: -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetcond(const nleqstate &state, const double epsf, const ae_int_t maxits); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to NLEQSolve(). -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetxrep(const nleqstate &state, const bool needxrep); /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when target function contains exp() or other fast growing functions, and algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetstpmax(const nleqstate &state, const double stpmax); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool nleqiteration(const nleqstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear solver These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void nleqsolve(nleqstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* NLEQ solver results INPUT PARAMETERS: State - algorithm state. OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -4 ERROR: algorithm has converged to the stationary point Xf which is local minimum of f=F[0]^2+...+F[m-1]^2, but is not solution of nonlinear system. * 1 sqrt(f)<=EpsF. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations * ActiveConstraints contains number of active constraints -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep); /************************************************************************* NLEQ solver results Buffered implementation of NLEQResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep); /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinCGCreate call. X - new starting point. BndL - new lower bounds BndU - new upper bounds -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void nleqrestartfrom(const nleqstate &state, const real_1d_array &x); /************************************************************************* Polynomial root finding. This function returns all roots of the polynomial P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n Both real and complex roots are returned (see below). INPUT PARAMETERS: A - array[N+1], polynomial coefficients: * A[0] is constant term * A[N] is a coefficient of X^N N - polynomial degree OUTPUT PARAMETERS: X - array of complex roots: * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 * complex roots are always returned in pairs - roots occupy positions I and I+1, with: * X[I+1]=Conj(X[I]) * IMAGE(X[I]) > 0 * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 * multiple real roots may have non-zero imaginary part due to roundoff errors. There is no reliable way to distinguish real root of multiplicity 2 from two complex roots in the presence of roundoff errors. Rep - report, additional information, following fields are set: * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field allows to quickly estimate "quality" of the roots being returned. NOTE: this function uses companion matrix method to find roots. In case internal EVD solver fails do find eigenvalues, exception is generated. NOTE: roots are not "polished" and no matrix balancing is performed for them. -- ALGLIB -- Copyright 24.02.2014 by Bochkanov Sergey *************************************************************************/ void polynomialsolve(const real_1d_array &a, const ae_int_t n, complex_1d_array &x, polynomialsolverreport &rep); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void rmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void _pexec_rmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void rmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void _pexec_rmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void rmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void _pexec_rmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void rmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_rmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void rmatrixlusolve(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void rmatrixlusolvefast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void rmatrixlusolvem(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void _pexec_rmatrixlusolvem(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void rmatrixlusolvemfast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_rmatrixlusolvemfast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void rmatrixmixedsolve(/* Real */ ae_matrix* a, /* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void rmatrixmixedsolvem(/* Real */ ae_matrix* a, /* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void cmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void _pexec_cmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void cmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_cmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void cmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void _pexec_cmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void cmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void _pexec_cmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void cmatrixlusolvem(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void _pexec_cmatrixlusolvem(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void cmatrixlusolvemfast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_cmatrixlusolvemfast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void cmatrixlusolve(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void cmatrixlusolvefast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void cmatrixmixedsolve(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void spdmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void _pexec_spdmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void spdmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_spdmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void spdmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void _pexec_spdmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void spdmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void _pexec_spdmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void _pexec_spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); void spdmatrixcholeskysolvemfast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_spdmatrixcholeskysolvemfast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state); void spdmatrixcholeskysolvefast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state); void hpdmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void _pexec_hpdmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void hpdmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_hpdmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void hpdmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void _pexec_hpdmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void hpdmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void _pexec_hpdmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void _pexec_hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); void hpdmatrixcholeskysolvemfast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void _pexec_hpdmatrixcholeskysolvemfast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state); void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state); void hpdmatrixcholeskysolvefast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state); void rmatrixsolvels(/* Real */ ae_matrix* a, ae_int_t nrows, ae_int_t ncols, /* Real */ ae_vector* b, double threshold, ae_int_t* info, densesolverlsreport* rep, /* Real */ ae_vector* x, ae_state *_state); void _pexec_rmatrixsolvels(/* Real */ ae_matrix* a, ae_int_t nrows, ae_int_t ncols, /* Real */ ae_vector* b, double threshold, ae_int_t* info, densesolverlsreport* rep, /* Real */ ae_vector* x, ae_state *_state); void _densesolverreport_init(void* _p, ae_state *_state); void _densesolverreport_init_copy(void* _dst, void* _src, ae_state *_state); void _densesolverreport_clear(void* _p); void _densesolverreport_destroy(void* _p); void _densesolverlsreport_init(void* _p, ae_state *_state); void _densesolverlsreport_init_copy(void* _dst, void* _src, ae_state *_state); void _densesolverlsreport_clear(void* _p); void _densesolverlsreport_destroy(void* _p); void linlsqrcreate(ae_int_t m, ae_int_t n, linlsqrstate* state, ae_state *_state); void linlsqrsetb(linlsqrstate* state, /* Real */ ae_vector* b, ae_state *_state); void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state); void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state); void linlsqrsetlambdai(linlsqrstate* state, double lambdai, ae_state *_state); ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state); void linlsqrsolvesparse(linlsqrstate* state, sparsematrix* a, /* Real */ ae_vector* b, ae_state *_state); void linlsqrsetcond(linlsqrstate* state, double epsa, double epsb, ae_int_t maxits, ae_state *_state); void linlsqrresults(linlsqrstate* state, /* Real */ ae_vector* x, linlsqrreport* rep, ae_state *_state); void linlsqrsetxrep(linlsqrstate* state, ae_bool needxrep, ae_state *_state); void linlsqrrestart(linlsqrstate* state, ae_state *_state); void _linlsqrstate_init(void* _p, ae_state *_state); void _linlsqrstate_init_copy(void* _dst, void* _src, ae_state *_state); void _linlsqrstate_clear(void* _p); void _linlsqrstate_destroy(void* _p); void _linlsqrreport_init(void* _p, ae_state *_state); void _linlsqrreport_init_copy(void* _dst, void* _src, ae_state *_state); void _linlsqrreport_clear(void* _p); void _linlsqrreport_destroy(void* _p); void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state); void lincgsetstartingpoint(lincgstate* state, /* Real */ ae_vector* x, ae_state *_state); void lincgsetb(lincgstate* state, /* Real */ ae_vector* b, ae_state *_state); void lincgsetprecunit(lincgstate* state, ae_state *_state); void lincgsetprecdiag(lincgstate* state, ae_state *_state); void lincgsetcond(lincgstate* state, double epsf, ae_int_t maxits, ae_state *_state); ae_bool lincgiteration(lincgstate* state, ae_state *_state); void lincgsolvesparse(lincgstate* state, sparsematrix* a, ae_bool isupper, /* Real */ ae_vector* b, ae_state *_state); void lincgresults(lincgstate* state, /* Real */ ae_vector* x, lincgreport* rep, ae_state *_state); void lincgsetrestartfreq(lincgstate* state, ae_int_t srf, ae_state *_state); void lincgsetrupdatefreq(lincgstate* state, ae_int_t freq, ae_state *_state); void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state); void lincgrestart(lincgstate* state, ae_state *_state); void _lincgstate_init(void* _p, ae_state *_state); void _lincgstate_init_copy(void* _dst, void* _src, ae_state *_state); void _lincgstate_clear(void* _p); void _lincgstate_destroy(void* _p); void _lincgreport_init(void* _p, ae_state *_state); void _lincgreport_init_copy(void* _dst, void* _src, ae_state *_state); void _lincgreport_clear(void* _p); void _lincgreport_destroy(void* _p); void nleqcreatelm(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, nleqstate* state, ae_state *_state); void nleqsetcond(nleqstate* state, double epsf, ae_int_t maxits, ae_state *_state); void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state); void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state); ae_bool nleqiteration(nleqstate* state, ae_state *_state); void nleqresults(nleqstate* state, /* Real */ ae_vector* x, nleqreport* rep, ae_state *_state); void nleqresultsbuf(nleqstate* state, /* Real */ ae_vector* x, nleqreport* rep, ae_state *_state); void nleqrestartfrom(nleqstate* state, /* Real */ ae_vector* x, ae_state *_state); void _nleqstate_init(void* _p, ae_state *_state); void _nleqstate_init_copy(void* _dst, void* _src, ae_state *_state); void _nleqstate_clear(void* _p); void _nleqstate_destroy(void* _p); void _nleqreport_init(void* _p, ae_state *_state); void _nleqreport_init_copy(void* _dst, void* _src, ae_state *_state); void _nleqreport_clear(void* _p); void _nleqreport_destroy(void* _p); void polynomialsolve(/* Real */ ae_vector* a, ae_int_t n, /* Complex */ ae_vector* x, polynomialsolverreport* rep, ae_state *_state); void _polynomialsolverreport_init(void* _p, ae_state *_state); void _polynomialsolverreport_init_copy(void* _dst, void* _src, ae_state *_state); void _polynomialsolverreport_clear(void* _p); void _polynomialsolverreport_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/statistics.h000755 001750 000144 00000157177 13015033052 023073 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _statistics_pkg_h #define _statistics_pkg_h #include "ap.h" #include "alglibinternal.h" #include "linalg.h" #include "specialfunctions.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Calculation of the distribution moments: mean, variance, skewness, kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X OUTPUT PARAMETERS Mean - mean. Variance- variance. Skewness- skewness (if variance<>0; zero otherwise). Kurtosis- kurtosis (if variance<>0; zero otherwise). NOTE: variance is calculated by dividing sum of squares by N-1, not N. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis); void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis); /************************************************************************* Calculation of the mean. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Mean' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplemean(const real_1d_array &x, const ae_int_t n); double samplemean(const real_1d_array &x); /************************************************************************* Calculation of the variance. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Variance' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplevariance(const real_1d_array &x, const ae_int_t n); double samplevariance(const real_1d_array &x); /************************************************************************* Calculation of the skewness. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Skewness' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double sampleskewness(const real_1d_array &x, const ae_int_t n); double sampleskewness(const real_1d_array &x); /************************************************************************* Calculation of the kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Kurtosis' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplekurtosis(const real_1d_array &x, const ae_int_t n); double samplekurtosis(const real_1d_array &x); /************************************************************************* ADev Input parameters: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: ADev- ADev -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev); void sampleadev(const real_1d_array &x, double &adev); /************************************************************************* Median calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: Median -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemedian(const real_1d_array &x, const ae_int_t n, double &median); void samplemedian(const real_1d_array &x, double &median); /************************************************************************* Percentile calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X P - percentile (0<=P<=1) Output parameters: V - percentile -- ALGLIB -- Copyright 01.03.2008 by Bochkanov Sergey *************************************************************************/ void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v); void samplepercentile(const real_1d_array &x, const double p, double &v); /************************************************************************* 2-sample covariance Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: covariance (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); double cov2(const real_1d_array &x, const real_1d_array &y); /************************************************************************* Pearson product-moment correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Pearson product-moment correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); double pearsoncorr2(const real_1d_array &x, const real_1d_array &y); /************************************************************************* Spearman's rank correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Spearman's rank correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); double spearmancorr2(const real_1d_array &x, const real_1d_array &y); /************************************************************************* Covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void smp_covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void covm(const real_2d_array &x, real_2d_array &c); void smp_covm(const real_2d_array &x, real_2d_array &c); /************************************************************************* Pearson product-moment correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void smp_pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void pearsoncorrm(const real_2d_array &x, real_2d_array &c); void smp_pearsoncorrm(const real_2d_array &x, real_2d_array &c); /************************************************************************* Spearman's rank correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void smp_spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); void spearmancorrm(const real_2d_array &x, real_2d_array &c); void smp_spearmancorrm(const real_2d_array &x, real_2d_array &c); /************************************************************************* Cross-covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void smp_covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); void smp_covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); /************************************************************************* Pearson product-moment cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); /************************************************************************* Spearman's rank cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); /************************************************************************* This function replaces data in XY by their ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * ranking starts from 0, ends at NFeatures-1 * sum of within-row values is equal to (NFeatures-1)*NFeatures/2 SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); void smp_rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); void rankdata(real_2d_array &xy); void smp_rankdata(real_2d_array &xy); /************************************************************************* This function replaces data in XY by their CENTERED ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * centered ranks are just usual ranks, but centered in such way that sum of within-row values is equal to 0.0. * centering is performed by subtracting mean from each row, i.e it changes mean value, but does NOT change higher moments SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); void smp_rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); void rankdatacentered(real_2d_array &xy); void smp_rankdatacentered(real_2d_array &xy); /************************************************************************* Obsolete function, we recommend to use PearsonCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); /************************************************************************* Obsolete function, we recommend to use SpearmanCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); /************************************************************************* Pearson's correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5 * normality of distributions of X and Y. Input parameters: R - Pearson's correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Spearman's rank correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5. The test is non-parametric and doesn't require distributions X and Y to be normal. Input parameters: R - Spearman's rank correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Jarque-Bera test This test checks hypotheses about the fact that a given sample X is a sample of normal random variable. Requirements: * the number of elements in the sample is not less than 5. Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Output parameters: P - p-value for the test Accuracy of the approximation used (5<=N<=1951): p-value relative error (5<=N<=1951) [1, 0.1] < 1% [0.1, 0.01] < 2% [0.01, 0.001] < 6% [0.001, 0] wasn't measured For N>1951 accuracy wasn't measured but it shouldn't be sharply different from table values. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p); /************************************************************************* Mann-Whitney U-test This test checks hypotheses about whether X and Y are samples of two continuous distributions of the same shape and same median or whether their medians are different. The following tests are performed: * two-tailed test (null hypothesis - the medians are equal) * left-tailed test (null hypothesis - the median of the first sample is greater than or equal to the median of the second sample) * right-tailed test (null hypothesis - the median of the first sample is less than or equal to the median of the second sample). Requirements: * the samples are independent * X and Y are continuous distributions (or discrete distributions well- approximating continuous distributions) * distributions of X and Y have the same shape. The only possible difference is their position (i.e. the value of the median) * the number of elements in each sample is not less than 5 * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distributions to be normal. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. M>=5 Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with satisfactory accuracy in interval [0.0001, 1]. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. Relative precision of approximation of p-value: N M Max.err. Rms.err. 5..10 N..10 1.4e-02 6.0e-04 5..10 N..100 2.2e-02 5.3e-06 10..15 N..15 1.0e-02 3.2e-04 10..15 N..100 1.0e-02 2.2e-05 15..100 N..100 6.1e-03 2.7e-06 For N,M>100 accuracy checks weren't put into practice, but taking into account characteristics of asymptotic approximation used, precision should not be sharply different from the values for interval [5, 100]. NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, P's outside of this interval are enforced to these bounds. Say, you may quite often get P equal to exactly 0.25 or 0.0001. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Sign test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. While calculating p-values high-precision binomial distribution approximation is used, so significance levels have about 15 exact digits. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail); /************************************************************************* One-sample t-test This test checks three hypotheses about the mean of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the mean is equal to the given value) * left-tailed test (null hypothesis - the mean is greater than or equal to the given value) * right-tailed test (null hypothesis - the mean is less than or equal to the given value). The test is based on the assumption that a given sample has a normal distribution and an unknown dispersion. If the distribution sharply differs from normal, the test will work incorrectly. INPUT PARAMETERS: X - sample. Array whose index goes from 0 to N-1. N - size of sample, N>=0 Mean - assumed value of the mean. OUTPUT PARAMETERS: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0, all p-values are set to 1.0 * when variance of X[] is exactly zero, p-values are set to 1.0 or 0.0, depending on difference between sample mean and value of mean being tested. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Two-sample pooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * dispersions are equal * samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has exactly zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Two-sample unpooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * samples are independent. Equality of variances is NOT required. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. * when only one sample has zero variance, test reduces to 1-sample version. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Two-sample F-test This test checks three hypotheses about dispersions of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the dispersions are equal) * left-tailed test (null hypothesis - the dispersion of the first sample is greater than or equal to the dispersion of the second sample). * right-tailed test (null hypothesis - the dispersion of the first sample is less than or equal to the dispersion of the second sample) The test is based on the following assumptions: * the given samples have normal distributions * the samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - sample size. Y - sample 2. Array whose index goes from 0 to M-1. M - sample size. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); /************************************************************************* One-sample chi-square test This test checks three hypotheses about the dispersion of the given sample The following tests are performed: * two-tailed test (null hypothesis - the dispersion equals the given number) * left-tailed test (null hypothesis - the dispersion is greater than or equal to the given number) * right-tailed test (null hypothesis - dispersion is less than or equal to the given number). Test is based on the following assumptions: * the given sample has a normal distribution. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Variance - dispersion value to compare with. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail); /************************************************************************* Wilcoxon signed-rank test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). * the distribution should be continuous and symmetric relative to its median. * number of distinct values in the X array should be greater than 4 The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with two decimal places in interval [0.0001, 1]. "Two decimal places" does not sound very impressive, but in practice the relative error of less than 1% is enough to make a decision. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void samplemoments(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* variance, double* skewness, double* kurtosis, ae_state *_state); double samplemean(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); double samplevariance(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); double sampleskewness(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); double samplekurtosis(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state); void sampleadev(/* Real */ ae_vector* x, ae_int_t n, double* adev, ae_state *_state); void samplemedian(/* Real */ ae_vector* x, ae_int_t n, double* median, ae_state *_state); void samplepercentile(/* Real */ ae_vector* x, ae_int_t n, double p, double* v, ae_state *_state); double cov2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); double pearsoncorr2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); double spearmancorr2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); void covm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_covm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void pearsoncorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_pearsoncorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void spearmancorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_spearmancorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state); void covm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_covm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void pearsoncorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_pearsoncorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void spearmancorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void _pexec_spearmancorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state); void rankdata(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_state *_state); void _pexec_rankdata(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_state *_state); void rankdatacentered(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_state *_state); void _pexec_rankdatacentered(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_state *_state); double pearsoncorrelation(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); double spearmanrankcorrelation(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); void pearsoncorrelationsignificance(double r, ae_int_t n, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void spearmanrankcorrelationsignificance(double r, ae_int_t n, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void jarqueberatest(/* Real */ ae_vector* x, ae_int_t n, double* p, ae_state *_state); void mannwhitneyutest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void onesamplesigntest(/* Real */ ae_vector* x, ae_int_t n, double median, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void studentttest1(/* Real */ ae_vector* x, ae_int_t n, double mean, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void studentttest2(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void unequalvariancettest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void ftest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void onesamplevariancetest(/* Real */ ae_vector* x, ae_int_t n, double variance, double* bothtails, double* lefttail, double* righttail, ae_state *_state); void wilcoxonsignedranktest(/* Real */ ae_vector* x, ae_int_t n, double e, double* bothtails, double* lefttail, double* righttail, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/specialfunctions.cpp000755 001750 000144 00001071413 13015033052 024572 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "specialfunctions.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Gamma function Input parameters: X - argument Domain: 0 < X < 171.6 -170 < X < 0, X is not an integer. Relative error: arithmetic domain # trials peak rms IEEE -170,-33 20000 2.3e-15 3.3e-16 IEEE -33, 33 20000 9.4e-16 2.2e-16 IEEE 33, 171.6 20000 2.3e-15 3.2e-16 Cephes Math Library Release 2.8: June, 2000 Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double gammafunction(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::gammafunction(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Natural logarithm of gamma function Input parameters: X - argument Result: logarithm of the absolute value of the Gamma(X). Output parameters: SgnGam - sign(Gamma(X)) Domain: 0 < X < 2.55e305 -2.55e305 < X < 0, X is not an integer. ACCURACY: arithmetic domain # trials peak rms IEEE 0, 3 28000 5.4e-16 1.1e-16 IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 The error criterion was relative when the function magnitude was greater than one but absolute when it was less than one. The following test used the relative error criterion, though at certain points the relative error could be much higher than indicated. IEEE -200, -4 10000 4.8e-16 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double lngamma(const double x, double &sgngam) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::lngamma(x, &sgngam, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Error function The integral is x - 2 | | 2 erf(x) = -------- | exp( - t ) dt. sqrt(pi) | | - 0 For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise erf(x) = 1 - erfc(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 3.7e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunction(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::errorfunction(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complementary error function 1 - erf(x) = inf. - 2 | | 2 erfc(x) = -------- | exp( - t ) dt sqrt(pi) | | - x For small x, erfc(x) = 1 - erf(x); otherwise rational approximations are computed. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,26.6417 30000 5.7e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunctionc(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::errorfunctionc(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Normal distribution function Returns the area under the Gaussian probability density function, integrated from minus infinity to x: x - 1 | | 2 ndtr(x) = --------- | exp( - t /2 ) dt sqrt(2pi) | | - -inf. = ( 1 + erf(z) ) / 2 = erfc(z) / 2 where z = x/sqrt(2). Computation is via the functions erf and erfc. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE -13,0 30000 3.4e-14 6.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double normaldistribution(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::normaldistribution(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of the error function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double inverf(const double e) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::inverf(e, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of Normal distribution function Returns the argument, x, for which the area under the Gaussian probability density function (integrated from minus infinity to x) is equal to y. For small arguments 0 < y < exp(-2), the program computes z = sqrt( -2.0 * log(y) ); then the approximation is x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). There are two rational functions P/Q, one for 0 < y < exp(-32) and the other for y up to exp(-2). For larger arguments, w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0.125, 1 20000 7.2e-16 1.3e-16 IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double invnormaldistribution(const double y0) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invnormaldistribution(y0, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Incomplete gamma integral The function is defined by x - 1 | | -t a-1 igam(a,x) = ----- | e t dt. - | | | (a) - 0 In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 200000 3.6e-14 2.9e-15 IEEE 0,100 300000 9.9e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegamma(const double a, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::incompletegamma(a, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complemented incomplete gamma integral The function is defined by igamc(a,x) = 1 - igam(a,x) inf. - 1 | | -t a-1 = ----- | e t dt. - | | | (a) - x In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Tested at random a, x. a x Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegammac(const double a, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::incompletegammac(a, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of complemented imcomplete gamma integral Given p, the function finds x such that igamc( a, x ) = p. Starting with the approximate value 3 x = a t where t = 1 - d - ndtri(p) sqrt(d) and d = 1/9a, the routine performs up to 10 Newton iterations to find the root of igamc(a,x) - p = 0. ACCURACY: Tested at random a, p in the intervals indicated. a p Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletegammac(const double a, const double y0) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invincompletegammac(a, y0, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Airy function Solution of the differential equation y"(x) = xy. The function returns the two independent solutions Ai, Bi and their first derivatives Ai'(x), Bi'(x). Evaluation is by power series summation for small x, by rational minimax approximations for large x. ACCURACY: Error criterion is absolute when function <= 1, relative when function > 1, except * denotes relative error criterion. For large negative x, the absolute error increases as x^1.5. For large positive x, the relative error increases as x^1.5. Arithmetic domain function # trials peak rms IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void airy(const double x, double &ai, double &aip, double &bi, double &bip) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::airy(x, &ai, &aip, &bi, &bip, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of order zero Returns Bessel function of order zero of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval the following rational approximation is used: 2 2 (w - r ) (w - r ) P (w) / Q (w) 1 2 3 8 2 where w = x and the two r's are zeros of the function. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 60000 4.2e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj0(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselj0(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of order one Returns Bessel function of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 24 term Chebyshev expansion is used. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 2.6e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj1(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselj1(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The ratio of jn(x) to j0(x) is computed by backward recurrence. First the ratio jn/jn-1 is found by a continued fraction expansion. Then the recurrence relating successive orders is applied until j0 or j1 is reached. If n = 0 or 1 the routine for j0 or j1 is called directly. ACCURACY: Absolute error: arithmetic range # trials peak rms IEEE 0, 30 5000 4.4e-16 7.9e-17 Not suitable for large n or x. Use jv() (fractional order) instead. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseljn(const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besseljn(n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of the second kind, order zero Returns Bessel function of the second kind, of order zero, of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval a rational approximation R(x) is employed to compute y0(x) = R(x) + 2 * log(x) * j0(x) / PI. Thus a call to j0() is required. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error, when y0(x) < 1; else relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.3e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely0(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::bessely0(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of second kind of order one Returns Bessel function of the second kind of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 25 term Chebyshev expansion is used, and a call to j1() is required. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.0e-15 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely1(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::bessely1(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bessel function of second kind of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The function is evaluated by forward recurrence on n, starting with values computed by the routines y0() and y1(). If n = 0 or 1 the routine for y0 or y1 is called directly. ACCURACY: Absolute error, except relative when y > 1: arithmetic domain # trials peak rms IEEE 0, 30 30000 3.4e-15 4.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselyn(const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselyn(n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modified Bessel function of order zero Returns modified Bessel function of order zero of the argument. The function is defined as i0(x) = j0( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 5.8e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli0(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besseli0(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modified Bessel function of order one Returns modified Bessel function of order one of the argument. The function is defined as i1(x) = -i j1( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.9e-15 2.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli1(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besseli1(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modified Bessel function, second kind, order zero Returns modified Bessel function of the second kind of order zero of the argument. The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Tested at 2000 random points between 0 and 8. Peak absolute error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk0(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselk0(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modified Bessel function, second kind, order one Computes the modified Bessel function of the second kind of order one of the argument. The range is partitioned into the two intervals [0,2] and (2, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk1(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselk1(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modified Bessel function, second kind, integer order Returns modified Bessel function of the second kind of order n of the argument. The range is partitioned into the two intervals [0,9.55] and (9.55, infinity). An ascending power series is used in the low range, and an asymptotic expansion in the high range. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 90000 1.8e-8 3.0e-10 Error is high only near the crossover point x = 9.55 between the two expansions used. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier *************************************************************************/ double besselkn(const ae_int_t nn, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::besselkn(nn, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Beta function - - | (a) | (b) beta( a, b ) = -----------. - | (a+b) For large arguments the logarithm of the function is evaluated using lgam(), then exponentiated. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 8.1e-14 1.1e-14 Cephes Math Library Release 2.0: April, 1987 Copyright 1984, 1987 by Stephen L. Moshier *************************************************************************/ double beta(const double a, const double b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::beta(a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Incomplete beta integral Returns incomplete beta integral of the arguments, evaluated from zero to x. The function is defined as x - - | (a+b) | | a-1 b-1 ----------- | t (1-t) dt. - - | | | (a) | (b) - 0 The domain of definition is 0 <= x <= 1. In this implementation a and b are restricted to positive values. The integral from x to 1 may be obtained by the symmetry relation 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). The integral is evaluated by a continued fraction expansion or, when b*x is small, by a power series. ACCURACY: Tested at uniformly distributed random points (a,b,x) with a and b in "domain" and x between 0 and 1. Relative error arithmetic domain # trials peak rms IEEE 0,5 10000 6.9e-15 4.5e-16 IEEE 0,85 250000 2.2e-13 1.7e-14 IEEE 0,1000 30000 5.3e-12 6.3e-13 IEEE 0,10000 250000 9.3e-11 7.1e-12 IEEE 0,100000 10000 8.7e-10 4.8e-11 Outputs smaller than the IEEE gradual underflow threshold were excluded from these statistics. Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double incompletebeta(const double a, const double b, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::incompletebeta(a, b, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of imcomplete beta integral Given y, the function finds x such that incbet( a, b, x ) = y . The routine performs interval halving or Newton iterations to find the root of incbet(a,b,x) - y = 0. ACCURACY: Relative error: x a,b arithmetic domain domain # trials peak rms IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 With a and b constrained to half-integer or integer values: IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 With a = .5, b constrained to half-integer or integer values: IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1996, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletebeta(const double a, const double b, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invincompletebeta(a, b, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Binomial distribution Returns the sum of the terms 0 through k of the Binomial probability density: k -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=0 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p), with p between 0 and 1. a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 4.3e-15 2.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::binomialdistribution(k, n, p, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complemented binomial distribution Returns the sum of the terms k+1 through n of the Binomial probability density: n -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=k+1 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 6.7e-15 8.2e-16 For p between 0 and .001: IEEE 0,100 100000 1.5e-13 2.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::binomialcdistribution(k, n, p, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse binomial distribution Finds the event probability p such that the sum of the terms 0 through k of the Binomial probability density is equal to the given cumulative probability y. This is accomplished using the inverse beta integral function and the relation 1 - p = incbi( n-k, k+1, y ). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 2.3e-14 6.4e-16 IEEE 0,10000 100000 6.6e-12 1.2e-13 For p between 10^-6 and 0.001: IEEE 0,100 100000 2.0e-12 1.3e-14 IEEE 0,10000 100000 1.5e-12 3.2e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invbinomialdistribution(k, n, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the value of the Chebyshev polynomials of the first and second kinds. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument, -1 <= x <= 1 Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::chebyshevcalculate(r, n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Summation of Chebyshev polynomials using Clenshaws recurrence formula. This routine calculates c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) or c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) depending on the R. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::chebyshevsum(const_cast(c.c_ptr()), r, n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void chebyshevcoefficients(const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::chebyshevcoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion of a series of Chebyshev polynomials to a power series. Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as B[0] + B[1]*X + ... + B[N]*X^N. Input parameters: A - Chebyshev series coefficients N - degree, N>=0 Output parameters B - power series coefficients *************************************************************************/ void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fromchebyshev(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Chi-square distribution Returns the area under the left hand tail (from 0 to x) of the Chi square probability density function with v degrees of freedom. x - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - 0 where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquaredistribution(const double v, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::chisquaredistribution(v, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complemented Chi-square distribution Returns the area under the right hand tail (from x to infinity) of the Chi square probability density function with v degrees of freedom: inf. - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - x where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquarecdistribution(const double v, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::chisquarecdistribution(v, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of complemented Chi-square distribution Finds the Chi-square argument x such that the integral from x to infinity of the Chi-square density is equal to the given cumulative probability y. This is accomplished using the inverse gamma integral function and the relation x/2 = igami( df/2, y ); ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double invchisquaredistribution(const double v, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invchisquaredistribution(v, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dawson's Integral Approximates the integral x - 2 | | 2 dawsn(x) = exp( -x ) | exp( t ) dt | | - 0 Three different rational approximations are employed, for the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,10 10000 6.9e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double dawsonintegral(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dawsonintegral(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 using the approximation P(x) - log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralk(const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::ellipticintegralk(m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 where m = 1 - m1, using the approximation P(x) - log x Q(x). The argument m1 is used rather than m so that the logarithmic singularity at m = 1 will be shifted to the origin; this preserves maximum accuracy. K(0) = pi/2. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralkhighprecision(const double m1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::ellipticintegralkhighprecision(m1, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Incomplete elliptic integral of the first kind F(phi|m) Approximates the integral phi - | | | dt F(phi_\m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random points with m in [0, 1] and phi as indicated. Relative error: arithmetic domain # trials peak rms IEEE -10,10 200000 7.4e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegralk(const double phi, const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::incompleteellipticintegralk(phi, m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complete elliptic integral of the second kind Approximates the integral pi/2 - | | 2 E(m) = | sqrt( 1 - m sin t ) dt | | - 0 using the approximation P(x) - x log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 1 10000 2.1e-16 7.3e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegrale(const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::ellipticintegrale(m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Incomplete elliptic integral of the second kind Approximates the integral phi - | | | 2 E(phi_\m) = | sqrt( 1 - m sin t ) dt | | | - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random arguments with phi in [-10, 10] and m in [0, 1]. Relative error: arithmetic domain # trials peak rms IEEE -10,10 150000 3.3e-15 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegrale(const double phi, const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::incompleteellipticintegrale(phi, m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Exponential integral Ei(x) x - t | | e Ei(x) = -|- --- dt . | | t - -inf Not defined for x <= 0. See also expn.c. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,100 50000 8.6e-16 1.3e-16 Cephes Math Library Release 2.8: May, 1999 Copyright 1999 by Stephen L. Moshier *************************************************************************/ double exponentialintegralei(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::exponentialintegralei(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Exponential integral En(x) Evaluates the exponential integral inf. - | | -xt | e E (x) = | ---- dt. n | n | | t - 1 Both n and x must be nonnegative. The routine employs either a power series, a continued fraction, or an asymptotic formula depending on the relative values of n and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 10000 1.7e-15 3.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 2000 by Stephen L. Moshier *************************************************************************/ double exponentialintegralen(const double x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::exponentialintegralen(x, n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* F distribution Returns the area from zero to x under the F density function (also known as Snedcor's density or the variance ratio density). This is the density of x = (u1/df1)/(u2/df2), where u1 and u2 are random variables having Chi square distributions with df1 and df2 degrees of freedom, respectively. The incomplete beta integral is used, according to the formula P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). The arguments a and b are greater than zero, and x is nonnegative. ACCURACY: Tested at random points (a,b,x). x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fdistribution(const ae_int_t a, const ae_int_t b, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::fdistribution(a, b, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complemented F distribution Returns the area from x to infinity under the F density function (also known as Snedcor's density or the variance ratio density). inf. - 1 | | a-1 b-1 1-P(x) = ------ | t (1-t) dt B(a,b) | | - x The incomplete beta integral is used, according to the formula P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). ACCURACY: Tested at random points (a,b,x) in the indicated intervals. x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fcdistribution(const ae_int_t a, const ae_int_t b, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::fcdistribution(a, b, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse of complemented F distribution Finds the F density argument x such that the integral from x to infinity of the F density is equal to the given probability p. This is accomplished using the inverse beta integral function and the relations z = incbi( df2/2, df1/2, p ) x = df2 (1-z) / (df1 z). Note: the following relations hold for the inverse of the uncomplemented F distribution: z = incbi( df1/2, df2/2, p ) x = df2 z / (df1 (1-z)). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between .001 and 1: IEEE 1,100 100000 8.3e-15 4.7e-16 IEEE 1,10000 100000 2.1e-11 1.4e-13 For p between 10^-6 and 10^-3: IEEE 1,100 50000 1.3e-12 8.4e-15 IEEE 1,10000 50000 3.0e-12 4.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invfdistribution(const ae_int_t a, const ae_int_t b, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invfdistribution(a, b, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fresnel integral Evaluates the Fresnel integrals x - | | C(x) = | cos(pi/2 t**2) dt, | | - 0 x - | | S(x) = | sin(pi/2 t**2) dt. | | - 0 The integrals are evaluated by a power series for x < 1. For x >= 1 auxiliary functions f(x) and g(x) are employed such that C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) ACCURACY: Relative error. Arithmetic function domain # trials peak rms IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void fresnelintegral(const double x, double &c, double &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fresnelintegral(x, &c, &s, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the value of the Hermite polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial Hn at x *************************************************************************/ double hermitecalculate(const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hermitecalculate(n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Summation of Hermite polynomials using Clenshaws recurrence formula. This routine calculates c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial at x *************************************************************************/ double hermitesum(const real_1d_array &c, const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hermitesum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void hermitecoefficients(const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hermitecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Jacobian Elliptic Functions Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), and dn(u|m) of parameter m between 0 and 1, and real argument u. These functions are periodic, with quarter-period on the real axis equal to the complete elliptic integral ellpk(1.0-m). Relation to incomplete elliptic integral: If u = ellik(phi,m), then sn(u|m) = sin(phi), and cn(u|m) = cos(phi). Phi is called the amplitude of u. Computation is by means of the arithmetic-geometric mean algorithm, except when m is within 1e-9 of 0 or 1. In the latter case with m close to 1, the approximation applies only for phi < pi/2. ACCURACY: Tested at random points with u between 0 and 10, m between 0 and 1. Absolute error (* = relative error): arithmetic function # trials peak rms IEEE phi 10000 9.2e-16* 1.4e-16* IEEE sn 50000 4.1e-15 4.6e-16 IEEE cn 40000 3.6e-15 4.4e-16 IEEE dn 10000 1.3e-12 1.8e-14 Peak error observed in consistency check using addition theorem for sn(u+v) was 4e-16 (absolute). Also tested by the above relation to the incomplete elliptic integral. Accuracy deteriorates when u is large. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::jacobianellipticfunctions(u, m, &sn, &cn, &dn, &ph, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the value of the Laguerre polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial Ln at x *************************************************************************/ double laguerrecalculate(const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::laguerrecalculate(n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Summation of Laguerre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial at x *************************************************************************/ double laguerresum(const real_1d_array &c, const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::laguerresum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void laguerrecoefficients(const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::laguerrecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the value of the Legendre polynomial Pn. Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial Pn at x *************************************************************************/ double legendrecalculate(const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::legendrecalculate(n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Summation of Legendre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial at x *************************************************************************/ double legendresum(const real_1d_array &c, const ae_int_t n, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::legendresum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void legendrecoefficients(const ae_int_t n, real_1d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::legendrecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Poisson distribution Returns the sum of the first k+1 terms of the Poisson distribution: k j -- -m m > e -- -- j! j=0 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the relation y = pdtr( k, m ) = igamc( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissondistribution(const ae_int_t k, const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::poissondistribution(k, m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complemented Poisson distribution Returns the sum of the terms k+1 to infinity of the Poisson distribution: inf. j -- -m m > e -- -- j! j=k+1 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the formula y = pdtrc( k, m ) = igam( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissoncdistribution(const ae_int_t k, const double m) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::poissoncdistribution(k, m, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Inverse Poisson distribution Finds the Poisson variable x such that the integral from 0 to x of the Poisson density is equal to the given probability y. This is accomplished using the inverse gamma integral function and the relation m = igami( k+1, y ). ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invpoissondistribution(const ae_int_t k, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invpoissondistribution(k, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Psi (digamma) function d - psi(x) = -- ln | (x) dx is the logarithmic derivative of the gamma function. For integer x, n-1 - psi(n) = -EUL + > 1/k. - k=1 This formula is used for 0 < n <= 10. If x is negative, it is transformed to a positive argument by the reflection formula psi(1-x) = psi(x) + pi cot(pi x). For general positive x, the argument is made greater than 10 using the recurrence psi(x+1) = psi(x) + 1/x. Then the following asymptotic expansion is applied: inf. B - 2k psi(x) = log(x) - 1/2x - > ------- - 2k k=1 2k x where the B2k are Bernoulli numbers. ACCURACY: Relative error (except absolute when |psi| < 1): arithmetic domain # trials peak rms IEEE 0,30 30000 1.3e-15 1.4e-16 IEEE -30,0 40000 1.5e-15 2.2e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double psi(const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::psi(x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Student's t distribution Computes the integral from minus infinity to t of the Student t distribution with integer k > 0 degrees of freedom: t - | | - | 2 -(k+1)/2 | ( (k+1)/2 ) | ( x ) ---------------------- | ( 1 + --- ) dx - | ( k ) sqrt( k pi ) | ( k/2 ) | | | - -inf. Relation to incomplete beta integral: 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) where z = k/(k + t**2). For t < -2, this is the method of computation. For higher t, a direct method is derived from integration by parts. Since the function is symmetric about t=0, the area under the right tail of the density is found by calling the function with -t instead of t. ACCURACY: Tested at random 1 <= k <= 25. The "domain" refers to t. Relative error: arithmetic domain # trials peak rms IEEE -100,-2 50000 5.9e-15 1.4e-15 IEEE -2,100 500000 2.7e-15 4.9e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double studenttdistribution(const ae_int_t k, const double t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::studenttdistribution(k, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Functional inverse of Student's t distribution Given probability p, finds the argument t such that stdtr(k,t) is equal to p. ACCURACY: Tested at random 1 <= k <= 100. The "domain" refers to p: Relative error: arithmetic domain # trials peak rms IEEE .001,.999 25000 5.7e-15 8.0e-16 IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invstudenttdistribution(const ae_int_t k, const double p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::invstudenttdistribution(k, p, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Sine and cosine integrals Evaluates the integrals x - | cos t - 1 Ci(x) = eul + ln x + | --------- dt, | t - 0 x - | sin t Si(x) = | ----- dt | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are approximated by rational functions. For x > 8 auxiliary functions f(x) and g(x) are employed such that Ci(x) = f(x) sin(x) - g(x) cos(x) Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) ACCURACY: Test interval = [0,50]. Absolute error, except relative when > 1: arithmetic function # trials peak rms IEEE Si 30000 4.4e-16 7.3e-17 IEEE Ci 30000 6.9e-16 5.1e-17 Cephes Math Library Release 2.1: January, 1989 Copyright 1984, 1987, 1989 by Stephen L. Moshier *************************************************************************/ void sinecosineintegrals(const double x, double &si, double &ci) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sinecosineintegrals(x, &si, &ci, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Hyperbolic sine and cosine integrals Approximates the integrals x - | | cosh t - 1 Chi(x) = eul + ln x + | ----------- dt, | | t - 0 x - | | sinh t Shi(x) = | ------ dt | | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are evaluated by power series for x < 8 and by Chebyshev expansions for x between 8 and 88. For large x, both functions approach exp(x)/2x. Arguments greater than 88 in magnitude return MAXNUM. ACCURACY: Test interval 0 to 88. Relative error: arithmetic function # trials peak rms IEEE Shi 30000 6.9e-16 1.6e-16 Absolute error, except relative when |Chi| > 1: IEEE Chi 30000 8.4e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hyperbolicsinecosineintegrals(x, &shi, &chi, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static double gammafunc_gammastirf(double x, ae_state *_state); static void bessel_besselmfirstcheb(double c, double* b0, double* b1, double* b2, ae_state *_state); static void bessel_besselmnextcheb(double x, double c, double* b0, double* b1, double* b2, ae_state *_state); static void bessel_besselm1firstcheb(double c, double* b0, double* b1, double* b2, ae_state *_state); static void bessel_besselm1nextcheb(double x, double c, double* b0, double* b1, double* b2, ae_state *_state); static void bessel_besselasympt0(double x, double* pzero, double* qzero, ae_state *_state); static void bessel_besselasympt1(double x, double* pzero, double* qzero, ae_state *_state); static double ibetaf_incompletebetafe(double a, double b, double x, double big, double biginv, ae_state *_state); static double ibetaf_incompletebetafe2(double a, double b, double x, double big, double biginv, ae_state *_state); static double ibetaf_incompletebetaps(double a, double b, double x, double maxgam, ae_state *_state); static void trigintegrals_chebiterationshichi(double x, double c, double* b0, double* b1, double* b2, ae_state *_state); /************************************************************************* Gamma function Input parameters: X - argument Domain: 0 < X < 171.6 -170 < X < 0, X is not an integer. Relative error: arithmetic domain # trials peak rms IEEE -170,-33 20000 2.3e-15 3.3e-16 IEEE -33, 33 20000 9.4e-16 2.2e-16 IEEE 33, 171.6 20000 2.3e-15 3.2e-16 Cephes Math Library Release 2.8: June, 2000 Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double gammafunction(double x, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SPECFUNCS double p; double pp; double q; double qq; double z; ae_int_t i; double sgngam; double result; sgngam = (double)(1); q = ae_fabs(x, _state); if( ae_fp_greater(q,33.0) ) { if( ae_fp_less(x,0.0) ) { p = (double)(ae_ifloor(q, _state)); i = ae_round(p, _state); if( i%2==0 ) { sgngam = (double)(-1); } z = q-p; if( ae_fp_greater(z,0.5) ) { p = p+1; z = q-p; } z = q*ae_sin(ae_pi*z, _state); z = ae_fabs(z, _state); z = ae_pi/(z*gammafunc_gammastirf(q, _state)); } else { z = gammafunc_gammastirf(x, _state); } result = sgngam*z; return result; } z = (double)(1); while(ae_fp_greater_eq(x,(double)(3))) { x = x-1; z = z*x; } while(ae_fp_less(x,(double)(0))) { if( ae_fp_greater(x,-0.000000001) ) { result = z/((1+0.5772156649015329*x)*x); return result; } z = z/x; x = x+1; } while(ae_fp_less(x,(double)(2))) { if( ae_fp_less(x,0.000000001) ) { result = z/((1+0.5772156649015329*x)*x); return result; } z = z/x; x = x+1.0; } if( ae_fp_eq(x,(double)(2)) ) { result = z; return result; } x = x-2.0; pp = 1.60119522476751861407E-4; pp = 1.19135147006586384913E-3+x*pp; pp = 1.04213797561761569935E-2+x*pp; pp = 4.76367800457137231464E-2+x*pp; pp = 2.07448227648435975150E-1+x*pp; pp = 4.94214826801497100753E-1+x*pp; pp = 9.99999999999999996796E-1+x*pp; qq = -2.31581873324120129819E-5; qq = 5.39605580493303397842E-4+x*qq; qq = -4.45641913851797240494E-3+x*qq; qq = 1.18139785222060435552E-2+x*qq; qq = 3.58236398605498653373E-2+x*qq; qq = -2.34591795718243348568E-1+x*qq; qq = 7.14304917030273074085E-2+x*qq; qq = 1.00000000000000000320+x*qq; result = z*pp/qq; return result; #else return _ialglib_i_gammafunction(x); #endif } /************************************************************************* Natural logarithm of gamma function Input parameters: X - argument Result: logarithm of the absolute value of the Gamma(X). Output parameters: SgnGam - sign(Gamma(X)) Domain: 0 < X < 2.55e305 -2.55e305 < X < 0, X is not an integer. ACCURACY: arithmetic domain # trials peak rms IEEE 0, 3 28000 5.4e-16 1.1e-16 IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 The error criterion was relative when the function magnitude was greater than one but absolute when it was less than one. The following test used the relative error criterion, though at certain points the relative error could be much higher than indicated. IEEE -200, -4 10000 4.8e-16 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/ double lngamma(double x, double* sgngam, ae_state *_state) { #ifndef ALGLIB_INTERCEPTS_SPECFUNCS double a; double b; double c; double p; double q; double u; double w; double z; ae_int_t i; double logpi; double ls2pi; double tmp; double result; *sgngam = 0; *sgngam = (double)(1); logpi = 1.14472988584940017414; ls2pi = 0.91893853320467274178; if( ae_fp_less(x,-34.0) ) { q = -x; w = lngamma(q, &tmp, _state); p = (double)(ae_ifloor(q, _state)); i = ae_round(p, _state); if( i%2==0 ) { *sgngam = (double)(-1); } else { *sgngam = (double)(1); } z = q-p; if( ae_fp_greater(z,0.5) ) { p = p+1; z = p-q; } z = q*ae_sin(ae_pi*z, _state); result = logpi-ae_log(z, _state)-w; return result; } if( ae_fp_less(x,(double)(13)) ) { z = (double)(1); p = (double)(0); u = x; while(ae_fp_greater_eq(u,(double)(3))) { p = p-1; u = x+p; z = z*u; } while(ae_fp_less(u,(double)(2))) { z = z/u; p = p+1; u = x+p; } if( ae_fp_less(z,(double)(0)) ) { *sgngam = (double)(-1); z = -z; } else { *sgngam = (double)(1); } if( ae_fp_eq(u,(double)(2)) ) { result = ae_log(z, _state); return result; } p = p-2; x = x+p; b = -1378.25152569120859100; b = -38801.6315134637840924+x*b; b = -331612.992738871184744+x*b; b = -1162370.97492762307383+x*b; b = -1721737.00820839662146+x*b; b = -853555.664245765465627+x*b; c = (double)(1); c = -351.815701436523470549+x*c; c = -17064.2106651881159223+x*c; c = -220528.590553854454839+x*c; c = -1139334.44367982507207+x*c; c = -2532523.07177582951285+x*c; c = -2018891.41433532773231+x*c; p = x*b/c; result = ae_log(z, _state)+p; return result; } q = (x-0.5)*ae_log(x, _state)-x+ls2pi; if( ae_fp_greater(x,(double)(100000000)) ) { result = q; return result; } p = 1/(x*x); if( ae_fp_greater_eq(x,1000.0) ) { q = q+((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x; } else { a = 8.11614167470508450300*0.0001; a = -5.95061904284301438324*0.0001+p*a; a = 7.93650340457716943945*0.0001+p*a; a = -2.77777777730099687205*0.001+p*a; a = 8.33333333333331927722*0.01+p*a; q = q+a/x; } result = q; return result; #else return _ialglib_i_lngamma(x, sgngam); #endif } static double gammafunc_gammastirf(double x, ae_state *_state) { double y; double w; double v; double stir; double result; w = 1/x; stir = 7.87311395793093628397E-4; stir = -2.29549961613378126380E-4+w*stir; stir = -2.68132617805781232825E-3+w*stir; stir = 3.47222221605458667310E-3+w*stir; stir = 8.33333333333482257126E-2+w*stir; w = 1+w*stir; y = ae_exp(x, _state); if( ae_fp_greater(x,143.01608) ) { v = ae_pow(x, 0.5*x-0.25, _state); y = v*(v/y); } else { y = ae_pow(x, x-0.5, _state)/y; } result = 2.50662827463100050242*y*w; return result; } /************************************************************************* Error function The integral is x - 2 | | 2 erf(x) = -------- | exp( - t ) dt. sqrt(pi) | | - 0 For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise erf(x) = 1 - erfc(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 3.7e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunction(double x, ae_state *_state) { double xsq; double s; double p; double q; double result; s = (double)(ae_sign(x, _state)); x = ae_fabs(x, _state); if( ae_fp_less(x,0.5) ) { xsq = x*x; p = 0.007547728033418631287834; p = -0.288805137207594084924010+xsq*p; p = 14.3383842191748205576712+xsq*p; p = 38.0140318123903008244444+xsq*p; p = 3017.82788536507577809226+xsq*p; p = 7404.07142710151470082064+xsq*p; p = 80437.3630960840172832162+xsq*p; q = 0.0; q = 1.00000000000000000000000+xsq*q; q = 38.0190713951939403753468+xsq*q; q = 658.070155459240506326937+xsq*q; q = 6379.60017324428279487120+xsq*q; q = 34216.5257924628539769006+xsq*q; q = 80437.3630960840172826266+xsq*q; result = s*1.1283791670955125738961589031*x*p/q; return result; } if( ae_fp_greater_eq(x,(double)(10)) ) { result = s; return result; } result = s*(1-errorfunctionc(x, _state)); return result; } /************************************************************************* Complementary error function 1 - erf(x) = inf. - 2 | | 2 erfc(x) = -------- | exp( - t ) dt sqrt(pi) | | - x For small x, erfc(x) = 1 - erf(x); otherwise rational approximations are computed. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,26.6417 30000 5.7e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double errorfunctionc(double x, ae_state *_state) { double p; double q; double result; if( ae_fp_less(x,(double)(0)) ) { result = 2-errorfunctionc(-x, _state); return result; } if( ae_fp_less(x,0.5) ) { result = 1.0-errorfunction(x, _state); return result; } if( ae_fp_greater_eq(x,(double)(10)) ) { result = (double)(0); return result; } p = 0.0; p = 0.5641877825507397413087057563+x*p; p = 9.675807882987265400604202961+x*p; p = 77.08161730368428609781633646+x*p; p = 368.5196154710010637133875746+x*p; p = 1143.262070703886173606073338+x*p; p = 2320.439590251635247384768711+x*p; p = 2898.0293292167655611275846+x*p; p = 1826.3348842295112592168999+x*p; q = 1.0; q = 17.14980943627607849376131193+x*q; q = 137.1255960500622202878443578+x*q; q = 661.7361207107653469211984771+x*q; q = 2094.384367789539593790281779+x*q; q = 4429.612803883682726711528526+x*q; q = 6089.5424232724435504633068+x*q; q = 4958.82756472114071495438422+x*q; q = 1826.3348842295112595576438+x*q; result = ae_exp(-ae_sqr(x, _state), _state)*p/q; return result; } /************************************************************************* Normal distribution function Returns the area under the Gaussian probability density function, integrated from minus infinity to x: x - 1 | | 2 ndtr(x) = --------- | exp( - t /2 ) dt sqrt(2pi) | | - -inf. = ( 1 + erf(z) ) / 2 = erfc(z) / 2 where z = x/sqrt(2). Computation is via the functions erf and erfc. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE -13,0 30000 3.4e-14 6.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double normaldistribution(double x, ae_state *_state) { double result; result = 0.5*(errorfunction(x/1.41421356237309504880, _state)+1); return result; } /************************************************************************* Inverse of the error function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double inverf(double e, ae_state *_state) { double result; result = invnormaldistribution(0.5*(e+1), _state)/ae_sqrt((double)(2), _state); return result; } /************************************************************************* Inverse of Normal distribution function Returns the argument, x, for which the area under the Gaussian probability density function (integrated from minus infinity to x) is equal to y. For small arguments 0 < y < exp(-2), the program computes z = sqrt( -2.0 * log(y) ); then the approximation is x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). There are two rational functions P/Q, one for 0 < y < exp(-32) and the other for y up to exp(-2). For larger arguments, w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0.125, 1 20000 7.2e-16 1.3e-16 IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double invnormaldistribution(double y0, ae_state *_state) { double expm2; double s2pi; double x; double y; double z; double y2; double x0; double x1; ae_int_t code; double p0; double q0; double p1; double q1; double p2; double q2; double result; expm2 = 0.13533528323661269189; s2pi = 2.50662827463100050242; if( ae_fp_less_eq(y0,(double)(0)) ) { result = -ae_maxrealnumber; return result; } if( ae_fp_greater_eq(y0,(double)(1)) ) { result = ae_maxrealnumber; return result; } code = 1; y = y0; if( ae_fp_greater(y,1.0-expm2) ) { y = 1.0-y; code = 0; } if( ae_fp_greater(y,expm2) ) { y = y-0.5; y2 = y*y; p0 = -59.9633501014107895267; p0 = 98.0010754185999661536+y2*p0; p0 = -56.6762857469070293439+y2*p0; p0 = 13.9312609387279679503+y2*p0; p0 = -1.23916583867381258016+y2*p0; q0 = (double)(1); q0 = 1.95448858338141759834+y2*q0; q0 = 4.67627912898881538453+y2*q0; q0 = 86.3602421390890590575+y2*q0; q0 = -225.462687854119370527+y2*q0; q0 = 200.260212380060660359+y2*q0; q0 = -82.0372256168333339912+y2*q0; q0 = 15.9056225126211695515+y2*q0; q0 = -1.18331621121330003142+y2*q0; x = y+y*y2*p0/q0; x = x*s2pi; result = x; return result; } x = ae_sqrt(-2.0*ae_log(y, _state), _state); x0 = x-ae_log(x, _state)/x; z = 1.0/x; if( ae_fp_less(x,8.0) ) { p1 = 4.05544892305962419923; p1 = 31.5251094599893866154+z*p1; p1 = 57.1628192246421288162+z*p1; p1 = 44.0805073893200834700+z*p1; p1 = 14.6849561928858024014+z*p1; p1 = 2.18663306850790267539+z*p1; p1 = -1.40256079171354495875*0.1+z*p1; p1 = -3.50424626827848203418*0.01+z*p1; p1 = -8.57456785154685413611*0.0001+z*p1; q1 = (double)(1); q1 = 15.7799883256466749731+z*q1; q1 = 45.3907635128879210584+z*q1; q1 = 41.3172038254672030440+z*q1; q1 = 15.0425385692907503408+z*q1; q1 = 2.50464946208309415979+z*q1; q1 = -1.42182922854787788574*0.1+z*q1; q1 = -3.80806407691578277194*0.01+z*q1; q1 = -9.33259480895457427372*0.0001+z*q1; x1 = z*p1/q1; } else { p2 = 3.23774891776946035970; p2 = 6.91522889068984211695+z*p2; p2 = 3.93881025292474443415+z*p2; p2 = 1.33303460815807542389+z*p2; p2 = 2.01485389549179081538*0.1+z*p2; p2 = 1.23716634817820021358*0.01+z*p2; p2 = 3.01581553508235416007*0.0001+z*p2; p2 = 2.65806974686737550832*0.000001+z*p2; p2 = 6.23974539184983293730*0.000000001+z*p2; q2 = (double)(1); q2 = 6.02427039364742014255+z*q2; q2 = 3.67983563856160859403+z*q2; q2 = 1.37702099489081330271+z*q2; q2 = 2.16236993594496635890*0.1+z*q2; q2 = 1.34204006088543189037*0.01+z*q2; q2 = 3.28014464682127739104*0.0001+z*q2; q2 = 2.89247864745380683936*0.000001+z*q2; q2 = 6.79019408009981274425*0.000000001+z*q2; x1 = z*p2/q2; } x = x0-x1; if( code!=0 ) { x = -x; } result = x; return result; } /************************************************************************* Incomplete gamma integral The function is defined by x - 1 | | -t a-1 igam(a,x) = ----- | e t dt. - | | | (a) - 0 In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 200000 3.6e-14 2.9e-15 IEEE 0,100 300000 9.9e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegamma(double a, double x, ae_state *_state) { double igammaepsilon; double ans; double ax; double c; double r; double tmp; double result; igammaepsilon = 0.000000000000001; if( ae_fp_less_eq(x,(double)(0))||ae_fp_less_eq(a,(double)(0)) ) { result = (double)(0); return result; } if( ae_fp_greater(x,(double)(1))&&ae_fp_greater(x,a) ) { result = 1-incompletegammac(a, x, _state); return result; } ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); if( ae_fp_less(ax,-709.78271289338399) ) { result = (double)(0); return result; } ax = ae_exp(ax, _state); r = a; c = (double)(1); ans = (double)(1); do { r = r+1; c = c*x/r; ans = ans+c; } while(ae_fp_greater(c/ans,igammaepsilon)); result = ans*ax/a; return result; } /************************************************************************* Complemented incomplete gamma integral The function is defined by igamc(a,x) = 1 - igam(a,x) inf. - 1 | | -t a-1 = ----- | e t dt. - | | | (a) - x In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Tested at random a, x. a x Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompletegammac(double a, double x, ae_state *_state) { double igammaepsilon; double igammabignumber; double igammabignumberinv; double ans; double ax; double c; double yc; double r; double t; double y; double z; double pk; double pkm1; double pkm2; double qk; double qkm1; double qkm2; double tmp; double result; igammaepsilon = 0.000000000000001; igammabignumber = 4503599627370496.0; igammabignumberinv = 2.22044604925031308085*0.0000000000000001; if( ae_fp_less_eq(x,(double)(0))||ae_fp_less_eq(a,(double)(0)) ) { result = (double)(1); return result; } if( ae_fp_less(x,(double)(1))||ae_fp_less(x,a) ) { result = 1-incompletegamma(a, x, _state); return result; } ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); if( ae_fp_less(ax,-709.78271289338399) ) { result = (double)(0); return result; } ax = ae_exp(ax, _state); y = 1-a; z = x+y+1; c = (double)(0); pkm2 = (double)(1); qkm2 = x; pkm1 = x+1; qkm1 = z*x; ans = pkm1/qkm1; do { c = c+1; y = y+1; z = z+2; yc = y*c; pk = pkm1*z-pkm2*yc; qk = qkm1*z-qkm2*yc; if( ae_fp_neq(qk,(double)(0)) ) { r = pk/qk; t = ae_fabs((ans-r)/r, _state); ans = r; } else { t = (double)(1); } pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( ae_fp_greater(ae_fabs(pk, _state),igammabignumber) ) { pkm2 = pkm2*igammabignumberinv; pkm1 = pkm1*igammabignumberinv; qkm2 = qkm2*igammabignumberinv; qkm1 = qkm1*igammabignumberinv; } } while(ae_fp_greater(t,igammaepsilon)); result = ans*ax; return result; } /************************************************************************* Inverse of complemented imcomplete gamma integral Given p, the function finds x such that igamc( a, x ) = p. Starting with the approximate value 3 x = a t where t = 1 - d - ndtri(p) sqrt(d) and d = 1/9a, the routine performs up to 10 Newton iterations to find the root of igamc(a,x) - p = 0. ACCURACY: Tested at random a, p in the intervals indicated. a p Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletegammac(double a, double y0, ae_state *_state) { double igammaepsilon; double iinvgammabignumber; double x0; double x1; double x; double yl; double yh; double y; double d; double lgm; double dithresh; ae_int_t i; ae_int_t dir; double tmp; double result; igammaepsilon = 0.000000000000001; iinvgammabignumber = 4503599627370496.0; x0 = iinvgammabignumber; yl = (double)(0); x1 = (double)(0); yh = (double)(1); dithresh = 5*igammaepsilon; d = 1/(9*a); y = 1-d-invnormaldistribution(y0, _state)*ae_sqrt(d, _state); x = a*y*y*y; lgm = lngamma(a, &tmp, _state); i = 0; while(i<10) { if( ae_fp_greater(x,x0)||ae_fp_less(x,x1) ) { d = 0.0625; break; } y = incompletegammac(a, x, _state); if( ae_fp_less(y,yl)||ae_fp_greater(y,yh) ) { d = 0.0625; break; } if( ae_fp_less(y,y0) ) { x0 = x; yl = y; } else { x1 = x; yh = y; } d = (a-1)*ae_log(x, _state)-x-lgm; if( ae_fp_less(d,-709.78271289338399) ) { d = 0.0625; break; } d = -ae_exp(d, _state); d = (y-y0)/d; if( ae_fp_less(ae_fabs(d/x, _state),igammaepsilon) ) { result = x; return result; } x = x-d; i = i+1; } if( ae_fp_eq(x0,iinvgammabignumber) ) { if( ae_fp_less_eq(x,(double)(0)) ) { x = (double)(1); } while(ae_fp_eq(x0,iinvgammabignumber)) { x = (1+d)*x; y = incompletegammac(a, x, _state); if( ae_fp_less(y,y0) ) { x0 = x; yl = y; break; } d = d+d; } } d = 0.5; dir = 0; i = 0; while(i<400) { x = x1+d*(x0-x1); y = incompletegammac(a, x, _state); lgm = (x0-x1)/(x1+x0); if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) { break; } lgm = (y-y0)/y0; if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) { break; } if( ae_fp_less_eq(x,0.0) ) { break; } if( ae_fp_greater_eq(y,y0) ) { x1 = x; yh = y; if( dir<0 ) { dir = 0; d = 0.5; } else { if( dir>1 ) { d = 0.5*d+0.5; } else { d = (y0-yl)/(yh-yl); } } dir = dir+1; } else { x0 = x; yl = y; if( dir>0 ) { dir = 0; d = 0.5; } else { if( dir<-1 ) { d = 0.5*d; } else { d = (y0-yl)/(yh-yl); } } dir = dir-1; } i = i+1; } result = x; return result; } /************************************************************************* Airy function Solution of the differential equation y"(x) = xy. The function returns the two independent solutions Ai, Bi and their first derivatives Ai'(x), Bi'(x). Evaluation is by power series summation for small x, by rational minimax approximations for large x. ACCURACY: Error criterion is absolute when function <= 1, relative when function > 1, except * denotes relative error criterion. For large negative x, the absolute error increases as x^1.5. For large positive x, the relative error increases as x^1.5. Arithmetic domain function # trials peak rms IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void airy(double x, double* ai, double* aip, double* bi, double* bip, ae_state *_state) { double z; double zz; double t; double f; double g; double uf; double ug; double k; double zeta; double theta; ae_int_t domflg; double c1; double c2; double sqrt3; double sqpii; double afn; double afd; double agn; double agd; double apfn; double apfd; double apgn; double apgd; double an; double ad; double apn; double apd; double bn16; double bd16; double bppn; double bppd; *ai = 0; *aip = 0; *bi = 0; *bip = 0; sqpii = 5.64189583547756286948E-1; c1 = 0.35502805388781723926; c2 = 0.258819403792806798405; sqrt3 = 1.732050807568877293527; domflg = 0; if( ae_fp_greater(x,25.77) ) { *ai = (double)(0); *aip = (double)(0); *bi = ae_maxrealnumber; *bip = ae_maxrealnumber; return; } if( ae_fp_less(x,-2.09) ) { domflg = 15; t = ae_sqrt(-x, _state); zeta = -2.0*x*t/3.0; t = ae_sqrt(t, _state); k = sqpii/t; z = 1.0/zeta; zz = z*z; afn = -1.31696323418331795333E-1; afn = afn*zz-6.26456544431912369773E-1; afn = afn*zz-6.93158036036933542233E-1; afn = afn*zz-2.79779981545119124951E-1; afn = afn*zz-4.91900132609500318020E-2; afn = afn*zz-4.06265923594885404393E-3; afn = afn*zz-1.59276496239262096340E-4; afn = afn*zz-2.77649108155232920844E-6; afn = afn*zz-1.67787698489114633780E-8; afd = 1.00000000000000000000E0; afd = afd*zz+1.33560420706553243746E1; afd = afd*zz+3.26825032795224613948E1; afd = afd*zz+2.67367040941499554804E1; afd = afd*zz+9.18707402907259625840E0; afd = afd*zz+1.47529146771666414581E0; afd = afd*zz+1.15687173795188044134E-1; afd = afd*zz+4.40291641615211203805E-3; afd = afd*zz+7.54720348287414296618E-5; afd = afd*zz+4.51850092970580378464E-7; uf = 1.0+zz*afn/afd; agn = 1.97339932091685679179E-2; agn = agn*zz+3.91103029615688277255E-1; agn = agn*zz+1.06579897599595591108E0; agn = agn*zz+9.39169229816650230044E-1; agn = agn*zz+3.51465656105547619242E-1; agn = agn*zz+6.33888919628925490927E-2; agn = agn*zz+5.85804113048388458567E-3; agn = agn*zz+2.82851600836737019778E-4; agn = agn*zz+6.98793669997260967291E-6; agn = agn*zz+8.11789239554389293311E-8; agn = agn*zz+3.41551784765923618484E-10; agd = 1.00000000000000000000E0; agd = agd*zz+9.30892908077441974853E0; agd = agd*zz+1.98352928718312140417E1; agd = agd*zz+1.55646628932864612953E1; agd = agd*zz+5.47686069422975497931E0; agd = agd*zz+9.54293611618961883998E-1; agd = agd*zz+8.64580826352392193095E-2; agd = agd*zz+4.12656523824222607191E-3; agd = agd*zz+1.01259085116509135510E-4; agd = agd*zz+1.17166733214413521882E-6; agd = agd*zz+4.91834570062930015649E-9; ug = z*agn/agd; theta = zeta+0.25*ae_pi; f = ae_sin(theta, _state); g = ae_cos(theta, _state); *ai = k*(f*uf-g*ug); *bi = k*(g*uf+f*ug); apfn = 1.85365624022535566142E-1; apfn = apfn*zz+8.86712188052584095637E-1; apfn = apfn*zz+9.87391981747398547272E-1; apfn = apfn*zz+4.01241082318003734092E-1; apfn = apfn*zz+7.10304926289631174579E-2; apfn = apfn*zz+5.90618657995661810071E-3; apfn = apfn*zz+2.33051409401776799569E-4; apfn = apfn*zz+4.08718778289035454598E-6; apfn = apfn*zz+2.48379932900442457853E-8; apfd = 1.00000000000000000000E0; apfd = apfd*zz+1.47345854687502542552E1; apfd = apfd*zz+3.75423933435489594466E1; apfd = apfd*zz+3.14657751203046424330E1; apfd = apfd*zz+1.09969125207298778536E1; apfd = apfd*zz+1.78885054766999417817E0; apfd = apfd*zz+1.41733275753662636873E-1; apfd = apfd*zz+5.44066067017226003627E-3; apfd = apfd*zz+9.39421290654511171663E-5; apfd = apfd*zz+5.65978713036027009243E-7; uf = 1.0+zz*apfn/apfd; apgn = -3.55615429033082288335E-2; apgn = apgn*zz-6.37311518129435504426E-1; apgn = apgn*zz-1.70856738884312371053E0; apgn = apgn*zz-1.50221872117316635393E0; apgn = apgn*zz-5.63606665822102676611E-1; apgn = apgn*zz-1.02101031120216891789E-1; apgn = apgn*zz-9.48396695961445269093E-3; apgn = apgn*zz-4.60325307486780994357E-4; apgn = apgn*zz-1.14300836484517375919E-5; apgn = apgn*zz-1.33415518685547420648E-7; apgn = apgn*zz-5.63803833958893494476E-10; apgd = 1.00000000000000000000E0; apgd = apgd*zz+9.85865801696130355144E0; apgd = apgd*zz+2.16401867356585941885E1; apgd = apgd*zz+1.73130776389749389525E1; apgd = apgd*zz+6.17872175280828766327E0; apgd = apgd*zz+1.08848694396321495475E0; apgd = apgd*zz+9.95005543440888479402E-2; apgd = apgd*zz+4.78468199683886610842E-3; apgd = apgd*zz+1.18159633322838625562E-4; apgd = apgd*zz+1.37480673554219441465E-6; apgd = apgd*zz+5.79912514929147598821E-9; ug = z*apgn/apgd; k = sqpii*t; *aip = -k*(g*uf+f*ug); *bip = k*(f*uf-g*ug); return; } if( ae_fp_greater_eq(x,2.09) ) { domflg = 5; t = ae_sqrt(x, _state); zeta = 2.0*x*t/3.0; g = ae_exp(zeta, _state); t = ae_sqrt(t, _state); k = 2.0*t*g; z = 1.0/zeta; an = 3.46538101525629032477E-1; an = an*z+1.20075952739645805542E1; an = an*z+7.62796053615234516538E1; an = an*z+1.68089224934630576269E2; an = an*z+1.59756391350164413639E2; an = an*z+7.05360906840444183113E1; an = an*z+1.40264691163389668864E1; an = an*z+9.99999999999999995305E-1; ad = 5.67594532638770212846E-1; ad = ad*z+1.47562562584847203173E1; ad = ad*z+8.45138970141474626562E1; ad = ad*z+1.77318088145400459522E2; ad = ad*z+1.64234692871529701831E2; ad = ad*z+7.14778400825575695274E1; ad = ad*z+1.40959135607834029598E1; ad = ad*z+1.00000000000000000470E0; f = an/ad; *ai = sqpii*f/k; k = -0.5*sqpii*t/g; apn = 6.13759184814035759225E-1; apn = apn*z+1.47454670787755323881E1; apn = apn*z+8.20584123476060982430E1; apn = apn*z+1.71184781360976385540E2; apn = apn*z+1.59317847137141783523E2; apn = apn*z+6.99778599330103016170E1; apn = apn*z+1.39470856980481566958E1; apn = apn*z+1.00000000000000000550E0; apd = 3.34203677749736953049E-1; apd = apd*z+1.11810297306158156705E1; apd = apd*z+7.11727352147859965283E1; apd = apd*z+1.58778084372838313640E2; apd = apd*z+1.53206427475809220834E2; apd = apd*z+6.86752304592780337944E1; apd = apd*z+1.38498634758259442477E1; apd = apd*z+9.99999999999999994502E-1; f = apn/apd; *aip = f*k; if( ae_fp_greater(x,8.3203353) ) { bn16 = -2.53240795869364152689E-1; bn16 = bn16*z+5.75285167332467384228E-1; bn16 = bn16*z-3.29907036873225371650E-1; bn16 = bn16*z+6.44404068948199951727E-2; bn16 = bn16*z-3.82519546641336734394E-3; bd16 = 1.00000000000000000000E0; bd16 = bd16*z-7.15685095054035237902E0; bd16 = bd16*z+1.06039580715664694291E1; bd16 = bd16*z-5.23246636471251500874E0; bd16 = bd16*z+9.57395864378383833152E-1; bd16 = bd16*z-5.50828147163549611107E-2; f = z*bn16/bd16; k = sqpii*g; *bi = k*(1.0+f)/t; bppn = 4.65461162774651610328E-1; bppn = bppn*z-1.08992173800493920734E0; bppn = bppn*z+6.38800117371827987759E-1; bppn = bppn*z-1.26844349553102907034E-1; bppn = bppn*z+7.62487844342109852105E-3; bppd = 1.00000000000000000000E0; bppd = bppd*z-8.70622787633159124240E0; bppd = bppd*z+1.38993162704553213172E1; bppd = bppd*z-7.14116144616431159572E0; bppd = bppd*z+1.34008595960680518666E0; bppd = bppd*z-7.84273211323341930448E-2; f = z*bppn/bppd; *bip = k*t*(1.0+f); return; } } f = 1.0; g = x; t = 1.0; uf = 1.0; ug = x; k = 1.0; z = x*x*x; while(ae_fp_greater(t,ae_machineepsilon)) { uf = uf*z; k = k+1.0; uf = uf/k; ug = ug*z; k = k+1.0; ug = ug/k; uf = uf/k; f = f+uf; k = k+1.0; ug = ug/k; g = g+ug; t = ae_fabs(uf/f, _state); } uf = c1*f; ug = c2*g; if( domflg%2==0 ) { *ai = uf-ug; } if( domflg/2%2==0 ) { *bi = sqrt3*(uf+ug); } k = 4.0; uf = x*x/2.0; ug = z/3.0; f = uf; g = 1.0+ug; uf = uf/3.0; t = 1.0; while(ae_fp_greater(t,ae_machineepsilon)) { uf = uf*z; ug = ug/k; k = k+1.0; ug = ug*z; uf = uf/k; f = f+uf; k = k+1.0; ug = ug/k; uf = uf/k; g = g+ug; k = k+1.0; t = ae_fabs(ug/g, _state); } uf = c1*f; ug = c2*g; if( domflg/4%2==0 ) { *aip = uf-ug; } if( domflg/8%2==0 ) { *bip = sqrt3*(uf+ug); } } /************************************************************************* Bessel function of order zero Returns Bessel function of order zero of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval the following rational approximation is used: 2 2 (w - r ) (w - r ) P (w) / Q (w) 1 2 3 8 2 where w = x and the two r's are zeros of the function. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 60000 4.2e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj0(double x, ae_state *_state) { double xsq; double nn; double pzero; double qzero; double p1; double q1; double result; if( ae_fp_less(x,(double)(0)) ) { x = -x; } if( ae_fp_greater(x,8.0) ) { bessel_besselasympt0(x, &pzero, &qzero, _state); nn = x-ae_pi/4; result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); return result; } xsq = ae_sqr(x, _state); p1 = 26857.86856980014981415848441; p1 = -40504123.71833132706360663322+xsq*p1; p1 = 25071582855.36881945555156435+xsq*p1; p1 = -8085222034853.793871199468171+xsq*p1; p1 = 1434354939140344.111664316553+xsq*p1; p1 = -136762035308817138.6865416609+xsq*p1; p1 = 6382059341072356562.289432465+xsq*p1; p1 = -117915762910761053603.8440800+xsq*p1; p1 = 493378725179413356181.6813446+xsq*p1; q1 = 1.0; q1 = 1363.063652328970604442810507+xsq*q1; q1 = 1114636.098462985378182402543+xsq*q1; q1 = 669998767.2982239671814028660+xsq*q1; q1 = 312304311494.1213172572469442+xsq*q1; q1 = 112775673967979.8507056031594+xsq*q1; q1 = 30246356167094626.98627330784+xsq*q1; q1 = 5428918384092285160.200195092+xsq*q1; q1 = 493378725179413356211.3278438+xsq*q1; result = p1/q1; return result; } /************************************************************************* Bessel function of order one Returns Bessel function of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 24 term Chebyshev expansion is used. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 2.6e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double besselj1(double x, ae_state *_state) { double s; double xsq; double nn; double pzero; double qzero; double p1; double q1; double result; s = (double)(ae_sign(x, _state)); if( ae_fp_less(x,(double)(0)) ) { x = -x; } if( ae_fp_greater(x,8.0) ) { bessel_besselasympt1(x, &pzero, &qzero, _state); nn = x-3*ae_pi/4; result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); if( ae_fp_less(s,(double)(0)) ) { result = -result; } return result; } xsq = ae_sqr(x, _state); p1 = 2701.122710892323414856790990; p1 = -4695753.530642995859767162166+xsq*p1; p1 = 3413234182.301700539091292655+xsq*p1; p1 = -1322983480332.126453125473247+xsq*p1; p1 = 290879526383477.5409737601689+xsq*p1; p1 = -35888175699101060.50743641413+xsq*p1; p1 = 2316433580634002297.931815435+xsq*p1; p1 = -66721065689249162980.20941484+xsq*p1; p1 = 581199354001606143928.050809+xsq*p1; q1 = 1.0; q1 = 1606.931573481487801970916749+xsq*q1; q1 = 1501793.594998585505921097578+xsq*q1; q1 = 1013863514.358673989967045588+xsq*q1; q1 = 524371026216.7649715406728642+xsq*q1; q1 = 208166122130760.7351240184229+xsq*q1; q1 = 60920613989175217.46105196863+xsq*q1; q1 = 11857707121903209998.37113348+xsq*q1; q1 = 1162398708003212287858.529400+xsq*q1; result = s*x*p1/q1; return result; } /************************************************************************* Bessel function of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The ratio of jn(x) to j0(x) is computed by backward recurrence. First the ratio jn/jn-1 is found by a continued fraction expansion. Then the recurrence relating successive orders is applied until j0 or j1 is reached. If n = 0 or 1 the routine for j0 or j1 is called directly. ACCURACY: Absolute error: arithmetic range # trials peak rms IEEE 0, 30 5000 4.4e-16 7.9e-17 Not suitable for large n or x. Use jv() (fractional order) instead. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseljn(ae_int_t n, double x, ae_state *_state) { double pkm2; double pkm1; double pk; double xk; double r; double ans; ae_int_t k; ae_int_t sg; double result; if( n<0 ) { n = -n; if( n%2==0 ) { sg = 1; } else { sg = -1; } } else { sg = 1; } if( ae_fp_less(x,(double)(0)) ) { if( n%2!=0 ) { sg = -sg; } x = -x; } if( n==0 ) { result = sg*besselj0(x, _state); return result; } if( n==1 ) { result = sg*besselj1(x, _state); return result; } if( n==2 ) { if( ae_fp_eq(x,(double)(0)) ) { result = (double)(0); } else { result = sg*(2.0*besselj1(x, _state)/x-besselj0(x, _state)); } return result; } if( ae_fp_less(x,ae_machineepsilon) ) { result = (double)(0); return result; } k = 53; pk = (double)(2*(n+k)); ans = pk; xk = x*x; do { pk = pk-2.0; ans = pk-xk/ans; k = k-1; } while(k!=0); ans = x/ans; pk = 1.0; pkm1 = 1.0/ans; k = n-1; r = (double)(2*k); do { pkm2 = (pkm1*r-pk*x)/x; pk = pkm1; pkm1 = pkm2; r = r-2.0; k = k-1; } while(k!=0); if( ae_fp_greater(ae_fabs(pk, _state),ae_fabs(pkm1, _state)) ) { ans = besselj1(x, _state)/pk; } else { ans = besselj0(x, _state)/pkm1; } result = sg*ans; return result; } /************************************************************************* Bessel function of the second kind, order zero Returns Bessel function of the second kind, of order zero, of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval a rational approximation R(x) is employed to compute y0(x) = R(x) + 2 * log(x) * j0(x) / PI. Thus a call to j0() is required. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error, when y0(x) < 1; else relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.3e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely0(double x, ae_state *_state) { double nn; double xsq; double pzero; double qzero; double p4; double q4; double result; if( ae_fp_greater(x,8.0) ) { bessel_besselasympt0(x, &pzero, &qzero, _state); nn = x-ae_pi/4; result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); return result; } xsq = ae_sqr(x, _state); p4 = -41370.35497933148554125235152; p4 = 59152134.65686889654273830069+xsq*p4; p4 = -34363712229.79040378171030138+xsq*p4; p4 = 10255208596863.94284509167421+xsq*p4; p4 = -1648605817185729.473122082537+xsq*p4; p4 = 137562431639934407.8571335453+xsq*p4; p4 = -5247065581112764941.297350814+xsq*p4; p4 = 65874732757195549259.99402049+xsq*p4; p4 = -27502866786291095837.01933175+xsq*p4; q4 = 1.0; q4 = 1282.452772478993804176329391+xsq*q4; q4 = 1001702.641288906265666651753+xsq*q4; q4 = 579512264.0700729537480087915+xsq*q4; q4 = 261306575504.1081249568482092+xsq*q4; q4 = 91620380340751.85262489147968+xsq*q4; q4 = 23928830434997818.57439356652+xsq*q4; q4 = 4192417043410839973.904769661+xsq*q4; q4 = 372645883898616588198.9980+xsq*q4; result = p4/q4+2/ae_pi*besselj0(x, _state)*ae_log(x, _state); return result; } /************************************************************************* Bessel function of second kind of order one Returns Bessel function of the second kind of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 25 term Chebyshev expansion is used, and a call to j1() is required. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.0e-15 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double bessely1(double x, ae_state *_state) { double nn; double xsq; double pzero; double qzero; double p4; double q4; double result; if( ae_fp_greater(x,8.0) ) { bessel_besselasympt1(x, &pzero, &qzero, _state); nn = x-3*ae_pi/4; result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); return result; } xsq = ae_sqr(x, _state); p4 = -2108847.540133123652824139923; p4 = 3639488548.124002058278999428+xsq*p4; p4 = -2580681702194.450950541426399+xsq*p4; p4 = 956993023992168.3481121552788+xsq*p4; p4 = -196588746272214065.8820322248+xsq*p4; p4 = 21931073399177975921.11427556+xsq*p4; p4 = -1212297555414509577913.561535+xsq*p4; p4 = 26554738314348543268942.48968+xsq*p4; p4 = -99637534243069222259967.44354+xsq*p4; q4 = 1.0; q4 = 1612.361029677000859332072312+xsq*q4; q4 = 1563282.754899580604737366452+xsq*q4; q4 = 1128686837.169442121732366891+xsq*q4; q4 = 646534088126.5275571961681500+xsq*q4; q4 = 297663212564727.6729292742282+xsq*q4; q4 = 108225825940881955.2553850180+xsq*q4; q4 = 29549879358971486742.90758119+xsq*q4; q4 = 5435310377188854170800.653097+xsq*q4; q4 = 508206736694124324531442.4152+xsq*q4; result = x*p4/q4+2/ae_pi*(besselj1(x, _state)*ae_log(x, _state)-1/x); return result; } /************************************************************************* Bessel function of second kind of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The function is evaluated by forward recurrence on n, starting with values computed by the routines y0() and y1(). If n = 0 or 1 the routine for y0 or y1 is called directly. ACCURACY: Absolute error, except relative when y > 1: arithmetic domain # trials peak rms IEEE 0, 30 30000 3.4e-15 4.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselyn(ae_int_t n, double x, ae_state *_state) { ae_int_t i; double a; double b; double tmp; double s; double result; s = (double)(1); if( n<0 ) { n = -n; if( n%2!=0 ) { s = (double)(-1); } } if( n==0 ) { result = bessely0(x, _state); return result; } if( n==1 ) { result = s*bessely1(x, _state); return result; } a = bessely0(x, _state); b = bessely1(x, _state); for(i=1; i<=n-1; i++) { tmp = b; b = 2*i/x*b-a; a = tmp; } result = s*b; return result; } /************************************************************************* Modified Bessel function of order zero Returns modified Bessel function of order zero of the argument. The function is defined as i0(x) = j0( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 5.8e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli0(double x, ae_state *_state) { double y; double v; double z; double b0; double b1; double b2; double result; if( ae_fp_less(x,(double)(0)) ) { x = -x; } if( ae_fp_less_eq(x,8.0) ) { y = x/2.0-2.0; bessel_besselmfirstcheb(-4.41534164647933937950E-18, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 3.33079451882223809783E-17, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -2.43127984654795469359E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.71539128555513303061E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -1.16853328779934516808E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 7.67618549860493561688E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -4.85644678311192946090E-13, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 2.95505266312963983461E-12, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -1.72682629144155570723E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 9.67580903537323691224E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -5.18979560163526290666E-10, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 2.65982372468238665035E-9, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -1.30002500998624804212E-8, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 6.04699502254191894932E-8, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -2.67079385394061173391E-7, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.11738753912010371815E-6, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -4.41673835845875056359E-6, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.64484480707288970893E-5, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -5.75419501008210370398E-5, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.88502885095841655729E-4, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -5.76375574538582365885E-4, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.63947561694133579842E-3, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -4.32430999505057594430E-3, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.05464603945949983183E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -2.37374148058994688156E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 4.93052842396707084878E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -9.49010970480476444210E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.71620901522208775349E-1, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -3.04682672343198398683E-1, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 6.76795274409476084995E-1, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); result = ae_exp(x, _state)*v; return result; } z = 32.0/x-2.0; bessel_besselmfirstcheb(-7.23318048787475395456E-18, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -4.83050448594418207126E-18, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 4.46562142029675999901E-17, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.46122286769746109310E-17, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -2.82762398051658348494E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -3.42548561967721913462E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.77256013305652638360E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.81168066935262242075E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -9.55484669882830764870E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -4.15056934728722208663E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.54008621752140982691E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.85277838274214270114E-13, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 7.18012445138366623367E-13, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.79417853150680611778E-12, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.32158118404477131188E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -3.14991652796324136454E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.18891471078464383424E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 4.94060238822496958910E-10, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.39623202570838634515E-9, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 2.26666899049817806459E-8, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 2.04891858946906374183E-7, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 2.89137052083475648297E-6, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 6.88975834691682398426E-5, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.36911647825569408990E-3, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 8.04490411014108831608E-1, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); result = ae_exp(x, _state)*v/ae_sqrt(x, _state); return result; } /************************************************************************* Modified Bessel function of order one Returns modified Bessel function of order one of the argument. The function is defined as i1(x) = -i j1( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.9e-15 2.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besseli1(double x, ae_state *_state) { double y; double z; double v; double b0; double b1; double b2; double result; z = ae_fabs(x, _state); if( ae_fp_less_eq(z,8.0) ) { y = z/2.0-2.0; bessel_besselm1firstcheb(2.77791411276104639959E-18, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.11142121435816608115E-17, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.55363195773620046921E-16, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.10559694773538630805E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 7.60068429473540693410E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -5.04218550472791168711E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.22379336594557470981E-13, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.98397439776494371520E-12, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.17361862988909016308E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -6.66348972350202774223E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.62559028155211703701E-10, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.88724975172282928790E-9, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 9.38153738649577178388E-9, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -4.44505912879632808065E-8, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.00329475355213526229E-7, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -8.56872026469545474066E-7, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.47025130813767847674E-6, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.32731636560394358279E-5, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 4.78156510755005422638E-5, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.61760815825896745588E-4, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 5.12285956168575772895E-4, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.51357245063125314899E-3, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 4.15642294431288815669E-3, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.05640848946261981558E-2, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.47264490306265168283E-2, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -5.29459812080949914269E-2, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.02643658689847095384E-1, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.76416518357834055153E-1, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.52587186443633654823E-1, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); z = v*z*ae_exp(z, _state); } else { y = 32.0/z-2.0; bessel_besselm1firstcheb(7.51729631084210481353E-18, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 4.41434832307170791151E-18, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -4.65030536848935832153E-17, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.20952592199342395980E-17, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.96262899764595013876E-16, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.30820231092092828324E-16, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.88035477551078244854E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.81440307243700780478E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.04202769841288027642E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 4.27244001671195135429E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.10154184277266431302E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -4.08355111109219731823E-13, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -7.19855177624590851209E-13, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.03562854414708950722E-12, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.41258074366137813316E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.25260358301548823856E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.89749581235054123450E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -5.58974346219658380687E-10, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.83538038596423702205E-9, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.63146884688951950684E-8, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.51223623787020892529E-7, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.88256480887769039346E-6, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.10588938762623716291E-4, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -9.76109749136146840777E-3, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 7.78576235018280120474E-1, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); z = v*ae_exp(z, _state)/ae_sqrt(z, _state); } if( ae_fp_less(x,(double)(0)) ) { z = -z; } result = z; return result; } /************************************************************************* Modified Bessel function, second kind, order zero Returns modified Bessel function of the second kind of order zero of the argument. The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Tested at 2000 random points between 0 and 8. Peak absolute error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk0(double x, ae_state *_state) { double y; double z; double v; double b0; double b1; double b2; double result; ae_assert(ae_fp_greater(x,(double)(0)), "Domain error in BesselK0: x<=0", _state); if( ae_fp_less_eq(x,(double)(2)) ) { y = x*x-2.0; bessel_besselmfirstcheb(1.37446543561352307156E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 4.25981614279661018399E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.03496952576338420167E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.90451637722020886025E-9, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 2.53479107902614945675E-7, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 2.28621210311945178607E-5, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 1.26461541144692592338E-3, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 3.59799365153615016266E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, 3.44289899924628486886E-1, &b0, &b1, &b2, _state); bessel_besselmnextcheb(y, -5.35327393233902768720E-1, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); v = v-ae_log(0.5*x, _state)*besseli0(x, _state); } else { z = 8.0/x-2.0; bessel_besselmfirstcheb(5.30043377268626276149E-18, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.64758043015242134646E-17, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 5.21039150503902756861E-17, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.67823109680541210385E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 5.51205597852431940784E-16, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.84859337734377901440E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 6.34007647740507060557E-15, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -2.22751332699166985548E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 8.03289077536357521100E-14, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -2.98009692317273043925E-13, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.14034058820847496303E-12, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -4.51459788337394416547E-12, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.85594911495471785253E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -7.95748924447710747776E-11, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 3.57739728140030116597E-10, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.69753450938905987466E-9, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 8.57403401741422608519E-9, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -4.66048989768794782956E-8, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 2.76681363944501510342E-7, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.83175552271911948767E-6, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.39498137188764993662E-5, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -1.28495495816278026384E-4, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 1.56988388573005337491E-3, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, -3.14481013119645005427E-2, &b0, &b1, &b2, _state); bessel_besselmnextcheb(z, 2.44030308206595545468E0, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); v = v*ae_exp(-x, _state)/ae_sqrt(x, _state); } result = v; return result; } /************************************************************************* Modified Bessel function, second kind, order one Computes the modified Bessel function of the second kind of order one of the argument. The range is partitioned into the two intervals [0,2] and (2, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double besselk1(double x, ae_state *_state) { double y; double z; double v; double b0; double b1; double b2; double result; z = 0.5*x; ae_assert(ae_fp_greater(z,(double)(0)), "Domain error in K1", _state); if( ae_fp_less_eq(x,(double)(2)) ) { y = x*x-2.0; bessel_besselm1firstcheb(-7.02386347938628759343E-18, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.42744985051936593393E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -6.66690169419932900609E-13, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.41148839263352776110E-10, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.21338763073472585583E-8, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.43340614156596823496E-6, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.73028895751305206302E-4, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -6.97572385963986435018E-3, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.22611180822657148235E-1, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.53155960776544875667E-1, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.52530022733894777053E0, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); result = ae_log(z, _state)*besseli1(x, _state)+v/x; } else { y = 8.0/x-2.0; bessel_besselm1firstcheb(-5.75674448366501715755E-18, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.79405087314755922667E-17, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -5.68946255844285935196E-17, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.83809354436663880070E-16, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -6.05704724837331885336E-16, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.03870316562433424052E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -7.01983709041831346144E-15, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.47715442448130437068E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -8.97670518232499435011E-14, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 3.34841966607842919884E-13, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.28917396095102890680E-12, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 5.13963967348173025100E-12, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.12996783842756842877E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 9.21831518760500529508E-11, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -4.19035475934189648750E-10, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.01504975519703286596E-9, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.03457624656780970260E-8, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 5.74108412545004946722E-8, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -3.50196060308781257119E-7, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.40648494783721712015E-6, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -1.93619797416608296024E-5, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.95215518471351631108E-4, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, -2.85781685962277938680E-3, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 1.03923736576817238437E-1, &b0, &b1, &b2, _state); bessel_besselm1nextcheb(y, 2.72062619048444266945E0, &b0, &b1, &b2, _state); v = 0.5*(b0-b2); result = ae_exp(-x, _state)*v/ae_sqrt(x, _state); } return result; } /************************************************************************* Modified Bessel function, second kind, integer order Returns modified Bessel function of the second kind of order n of the argument. The range is partitioned into the two intervals [0,9.55] and (9.55, infinity). An ascending power series is used in the low range, and an asymptotic expansion in the high range. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 90000 1.8e-8 3.0e-10 Error is high only near the crossover point x = 9.55 between the two expansions used. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier *************************************************************************/ double besselkn(ae_int_t nn, double x, ae_state *_state) { double k; double kf; double nk1f; double nkf; double zn; double t; double s; double z0; double z; double ans; double fn; double pn; double pk; double zmn; double tlg; double tox; ae_int_t i; ae_int_t n; double eul; double result; eul = 5.772156649015328606065e-1; if( nn<0 ) { n = -nn; } else { n = nn; } ae_assert(n<=31, "Overflow in BesselKN", _state); ae_assert(ae_fp_greater(x,(double)(0)), "Domain error in BesselKN", _state); if( ae_fp_less_eq(x,9.55) ) { ans = 0.0; z0 = 0.25*x*x; fn = 1.0; pn = 0.0; zmn = 1.0; tox = 2.0/x; if( n>0 ) { pn = -eul; k = 1.0; for(i=1; i<=n-1; i++) { pn = pn+1.0/k; k = k+1.0; fn = fn*k; } zmn = tox; if( n==1 ) { ans = 1.0/x; } else { nk1f = fn/n; kf = 1.0; s = nk1f; z = -z0; zn = 1.0; for(i=1; i<=n-1; i++) { nk1f = nk1f/(n-i); kf = kf*i; zn = zn*z; t = nk1f*zn/kf; s = s+t; ae_assert(ae_fp_greater(ae_maxrealnumber-ae_fabs(t, _state),ae_fabs(s, _state)), "Overflow in BesselKN", _state); ae_assert(!(ae_fp_greater(tox,1.0)&&ae_fp_less(ae_maxrealnumber/tox,zmn)), "Overflow in BesselKN", _state); zmn = zmn*tox; } s = s*0.5; t = ae_fabs(s, _state); ae_assert(!(ae_fp_greater(zmn,1.0)&&ae_fp_less(ae_maxrealnumber/zmn,t)), "Overflow in BesselKN", _state); ae_assert(!(ae_fp_greater(t,1.0)&&ae_fp_less(ae_maxrealnumber/t,zmn)), "Overflow in BesselKN", _state); ans = s*zmn; } } tlg = 2.0*ae_log(0.5*x, _state); pk = -eul; if( n==0 ) { pn = pk; t = 1.0; } else { pn = pn+1.0/n; t = 1.0/fn; } s = (pk+pn-tlg)*t; k = 1.0; do { t = t*(z0/(k*(k+n))); pk = pk+1.0/k; pn = pn+1.0/(k+n); s = s+(pk+pn-tlg)*t; k = k+1.0; } while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); s = 0.5*s/zmn; if( n%2!=0 ) { s = -s; } ans = ans+s; result = ans; return result; } if( ae_fp_greater(x,ae_log(ae_maxrealnumber, _state)) ) { result = (double)(0); return result; } k = (double)(n); pn = 4.0*k*k; pk = 1.0; z0 = 8.0*x; fn = 1.0; t = 1.0; s = t; nkf = ae_maxrealnumber; i = 0; do { z = pn-pk*pk; t = t*z/(fn*z0); nk1f = ae_fabs(t, _state); if( i>=n&&ae_fp_greater(nk1f,nkf) ) { break; } nkf = nk1f; s = s+t; fn = fn+1.0; pk = pk+2.0; i = i+1; } while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); result = ae_exp(-x, _state)*ae_sqrt(ae_pi/(2.0*x), _state)*s; return result; } /************************************************************************* Internal subroutine Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ static void bessel_besselmfirstcheb(double c, double* b0, double* b1, double* b2, ae_state *_state) { *b0 = c; *b1 = 0.0; *b2 = 0.0; } /************************************************************************* Internal subroutine Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ static void bessel_besselmnextcheb(double x, double c, double* b0, double* b1, double* b2, ae_state *_state) { *b2 = *b1; *b1 = *b0; *b0 = x*(*b1)-(*b2)+c; } /************************************************************************* Internal subroutine Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ static void bessel_besselm1firstcheb(double c, double* b0, double* b1, double* b2, ae_state *_state) { *b0 = c; *b1 = 0.0; *b2 = 0.0; } /************************************************************************* Internal subroutine Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ static void bessel_besselm1nextcheb(double x, double c, double* b0, double* b1, double* b2, ae_state *_state) { *b2 = *b1; *b1 = *b0; *b0 = x*(*b1)-(*b2)+c; } static void bessel_besselasympt0(double x, double* pzero, double* qzero, ae_state *_state) { double xsq; double p2; double q2; double p3; double q3; *pzero = 0; *qzero = 0; xsq = 64.0/(x*x); p2 = 0.0; p2 = 2485.271928957404011288128951+xsq*p2; p2 = 153982.6532623911470917825993+xsq*p2; p2 = 2016135.283049983642487182349+xsq*p2; p2 = 8413041.456550439208464315611+xsq*p2; p2 = 12332384.76817638145232406055+xsq*p2; p2 = 5393485.083869438325262122897+xsq*p2; q2 = 1.0; q2 = 2615.700736920839685159081813+xsq*q2; q2 = 156001.7276940030940592769933+xsq*q2; q2 = 2025066.801570134013891035236+xsq*q2; q2 = 8426449.050629797331554404810+xsq*q2; q2 = 12338310.22786324960844856182+xsq*q2; q2 = 5393485.083869438325560444960+xsq*q2; p3 = -0.0; p3 = -4.887199395841261531199129300+xsq*p3; p3 = -226.2630641933704113967255053+xsq*p3; p3 = -2365.956170779108192723612816+xsq*p3; p3 = -8239.066313485606568803548860+xsq*p3; p3 = -10381.41698748464093880530341+xsq*p3; p3 = -3984.617357595222463506790588+xsq*p3; q3 = 1.0; q3 = 408.7714673983499223402830260+xsq*q3; q3 = 15704.89191515395519392882766+xsq*q3; q3 = 156021.3206679291652539287109+xsq*q3; q3 = 533291.3634216897168722255057+xsq*q3; q3 = 666745.4239319826986004038103+xsq*q3; q3 = 255015.5108860942382983170882+xsq*q3; *pzero = p2/q2; *qzero = 8*p3/q3/x; } static void bessel_besselasympt1(double x, double* pzero, double* qzero, ae_state *_state) { double xsq; double p2; double q2; double p3; double q3; *pzero = 0; *qzero = 0; xsq = 64.0/(x*x); p2 = -1611.616644324610116477412898; p2 = -109824.0554345934672737413139+xsq*p2; p2 = -1523529.351181137383255105722+xsq*p2; p2 = -6603373.248364939109255245434+xsq*p2; p2 = -9942246.505077641195658377899+xsq*p2; p2 = -4435757.816794127857114720794+xsq*p2; q2 = 1.0; q2 = -1455.009440190496182453565068+xsq*q2; q2 = -107263.8599110382011903063867+xsq*q2; q2 = -1511809.506634160881644546358+xsq*q2; q2 = -6585339.479723087072826915069+xsq*q2; q2 = -9934124.389934585658967556309+xsq*q2; q2 = -4435757.816794127856828016962+xsq*q2; p3 = 35.26513384663603218592175580; p3 = 1706.375429020768002061283546+xsq*p3; p3 = 18494.26287322386679652009819+xsq*p3; p3 = 66178.83658127083517939992166+xsq*p3; p3 = 85145.16067533570196555001171+xsq*p3; p3 = 33220.91340985722351859704442+xsq*p3; q3 = 1.0; q3 = 863.8367769604990967475517183+xsq*q3; q3 = 37890.22974577220264142952256+xsq*q3; q3 = 400294.4358226697511708610813+xsq*q3; q3 = 1419460.669603720892855755253+xsq*q3; q3 = 1819458.042243997298924553839+xsq*q3; q3 = 708712.8194102874357377502472+xsq*q3; *pzero = p2/q2; *qzero = 8*p3/q3/x; } /************************************************************************* Beta function - - | (a) | (b) beta( a, b ) = -----------. - | (a+b) For large arguments the logarithm of the function is evaluated using lgam(), then exponentiated. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 8.1e-14 1.1e-14 Cephes Math Library Release 2.0: April, 1987 Copyright 1984, 1987 by Stephen L. Moshier *************************************************************************/ double beta(double a, double b, ae_state *_state) { double y; double sg; double s; double result; sg = (double)(1); ae_assert(ae_fp_greater(a,(double)(0))||ae_fp_neq(a,(double)(ae_ifloor(a, _state))), "Overflow in Beta", _state); ae_assert(ae_fp_greater(b,(double)(0))||ae_fp_neq(b,(double)(ae_ifloor(b, _state))), "Overflow in Beta", _state); y = a+b; if( ae_fp_greater(ae_fabs(y, _state),171.624376956302725) ) { y = lngamma(y, &s, _state); sg = sg*s; y = lngamma(b, &s, _state)-y; sg = sg*s; y = lngamma(a, &s, _state)+y; sg = sg*s; ae_assert(ae_fp_less_eq(y,ae_log(ae_maxrealnumber, _state)), "Overflow in Beta", _state); result = sg*ae_exp(y, _state); return result; } y = gammafunction(y, _state); ae_assert(ae_fp_neq(y,(double)(0)), "Overflow in Beta", _state); if( ae_fp_greater(a,b) ) { y = gammafunction(a, _state)/y; y = y*gammafunction(b, _state); } else { y = gammafunction(b, _state)/y; y = y*gammafunction(a, _state); } result = y; return result; } /************************************************************************* Incomplete beta integral Returns incomplete beta integral of the arguments, evaluated from zero to x. The function is defined as x - - | (a+b) | | a-1 b-1 ----------- | t (1-t) dt. - - | | | (a) | (b) - 0 The domain of definition is 0 <= x <= 1. In this implementation a and b are restricted to positive values. The integral from x to 1 may be obtained by the symmetry relation 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). The integral is evaluated by a continued fraction expansion or, when b*x is small, by a power series. ACCURACY: Tested at uniformly distributed random points (a,b,x) with a and b in "domain" and x between 0 and 1. Relative error arithmetic domain # trials peak rms IEEE 0,5 10000 6.9e-15 4.5e-16 IEEE 0,85 250000 2.2e-13 1.7e-14 IEEE 0,1000 30000 5.3e-12 6.3e-13 IEEE 0,10000 250000 9.3e-11 7.1e-12 IEEE 0,100000 10000 8.7e-10 4.8e-11 Outputs smaller than the IEEE gradual underflow threshold were excluded from these statistics. Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double incompletebeta(double a, double b, double x, ae_state *_state) { double t; double xc; double w; double y; ae_int_t flag; double sg; double big; double biginv; double maxgam; double minlog; double maxlog; double result; big = 4.503599627370496e15; biginv = 2.22044604925031308085e-16; maxgam = 171.624376956302725; minlog = ae_log(ae_minrealnumber, _state); maxlog = ae_log(ae_maxrealnumber, _state); ae_assert(ae_fp_greater(a,(double)(0))&&ae_fp_greater(b,(double)(0)), "Domain error in IncompleteBeta", _state); ae_assert(ae_fp_greater_eq(x,(double)(0))&&ae_fp_less_eq(x,(double)(1)), "Domain error in IncompleteBeta", _state); if( ae_fp_eq(x,(double)(0)) ) { result = (double)(0); return result; } if( ae_fp_eq(x,(double)(1)) ) { result = (double)(1); return result; } flag = 0; if( ae_fp_less_eq(b*x,1.0)&&ae_fp_less_eq(x,0.95) ) { result = ibetaf_incompletebetaps(a, b, x, maxgam, _state); return result; } w = 1.0-x; if( ae_fp_greater(x,a/(a+b)) ) { flag = 1; t = a; a = b; b = t; xc = x; x = w; } else { xc = w; } if( (flag==1&&ae_fp_less_eq(b*x,1.0))&&ae_fp_less_eq(x,0.95) ) { t = ibetaf_incompletebetaps(a, b, x, maxgam, _state); if( ae_fp_less_eq(t,ae_machineepsilon) ) { result = 1.0-ae_machineepsilon; } else { result = 1.0-t; } return result; } y = x*(a+b-2.0)-(a-1.0); if( ae_fp_less(y,0.0) ) { w = ibetaf_incompletebetafe(a, b, x, big, biginv, _state); } else { w = ibetaf_incompletebetafe2(a, b, x, big, biginv, _state)/xc; } y = a*ae_log(x, _state); t = b*ae_log(xc, _state); if( (ae_fp_less(a+b,maxgam)&&ae_fp_less(ae_fabs(y, _state),maxlog))&&ae_fp_less(ae_fabs(t, _state),maxlog) ) { t = ae_pow(xc, b, _state); t = t*ae_pow(x, a, _state); t = t/a; t = t*w; t = t*(gammafunction(a+b, _state)/(gammafunction(a, _state)*gammafunction(b, _state))); if( flag==1 ) { if( ae_fp_less_eq(t,ae_machineepsilon) ) { result = 1.0-ae_machineepsilon; } else { result = 1.0-t; } } else { result = t; } return result; } y = y+t+lngamma(a+b, &sg, _state)-lngamma(a, &sg, _state)-lngamma(b, &sg, _state); y = y+ae_log(w/a, _state); if( ae_fp_less(y,minlog) ) { t = 0.0; } else { t = ae_exp(y, _state); } if( flag==1 ) { if( ae_fp_less_eq(t,ae_machineepsilon) ) { t = 1.0-ae_machineepsilon; } else { t = 1.0-t; } } result = t; return result; } /************************************************************************* Inverse of imcomplete beta integral Given y, the function finds x such that incbet( a, b, x ) = y . The routine performs interval halving or Newton iterations to find the root of incbet(a,b,x) - y = 0. ACCURACY: Relative error: x a,b arithmetic domain domain # trials peak rms IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 With a and b constrained to half-integer or integer values: IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 With a = .5, b constrained to half-integer or integer values: IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1996, 2000 by Stephen L. Moshier *************************************************************************/ double invincompletebeta(double a, double b, double y, ae_state *_state) { double aaa; double bbb; double y0; double d; double yyy; double x; double x0; double x1; double lgm; double yp; double di; double dithresh; double yl; double yh; double xt; ae_int_t i; ae_int_t rflg; ae_int_t dir; ae_int_t nflg; double s; ae_int_t mainlooppos; ae_int_t ihalve; ae_int_t ihalvecycle; ae_int_t newt; ae_int_t newtcycle; ae_int_t breaknewtcycle; ae_int_t breakihalvecycle; double result; i = 0; ae_assert(ae_fp_greater_eq(y,(double)(0))&&ae_fp_less_eq(y,(double)(1)), "Domain error in InvIncompleteBeta", _state); /* * special cases */ if( ae_fp_eq(y,(double)(0)) ) { result = (double)(0); return result; } if( ae_fp_eq(y,1.0) ) { result = (double)(1); return result; } /* * these initializations are not really necessary, * but without them compiler complains about 'possibly uninitialized variables'. */ dithresh = (double)(0); rflg = 0; aaa = (double)(0); bbb = (double)(0); y0 = (double)(0); x = (double)(0); yyy = (double)(0); lgm = (double)(0); dir = 0; di = (double)(0); /* * normal initializations */ x0 = 0.0; yl = 0.0; x1 = 1.0; yh = 1.0; nflg = 0; mainlooppos = 0; ihalve = 1; ihalvecycle = 2; newt = 3; newtcycle = 4; breaknewtcycle = 5; breakihalvecycle = 6; /* * main loop */ for(;;) { /* * start */ if( mainlooppos==0 ) { if( ae_fp_less_eq(a,1.0)||ae_fp_less_eq(b,1.0) ) { dithresh = 1.0e-6; rflg = 0; aaa = a; bbb = b; y0 = y; x = aaa/(aaa+bbb); yyy = incompletebeta(aaa, bbb, x, _state); mainlooppos = ihalve; continue; } else { dithresh = 1.0e-4; } yp = -invnormaldistribution(y, _state); if( ae_fp_greater(y,0.5) ) { rflg = 1; aaa = b; bbb = a; y0 = 1.0-y; yp = -yp; } else { rflg = 0; aaa = a; bbb = b; y0 = y; } lgm = (yp*yp-3.0)/6.0; x = 2.0/(1.0/(2.0*aaa-1.0)+1.0/(2.0*bbb-1.0)); d = yp*ae_sqrt(x+lgm, _state)/x-(1.0/(2.0*bbb-1.0)-1.0/(2.0*aaa-1.0))*(lgm+5.0/6.0-2.0/(3.0*x)); d = 2.0*d; if( ae_fp_less(d,ae_log(ae_minrealnumber, _state)) ) { x = (double)(0); break; } x = aaa/(aaa+bbb*ae_exp(d, _state)); yyy = incompletebeta(aaa, bbb, x, _state); yp = (yyy-y0)/y0; if( ae_fp_less(ae_fabs(yp, _state),0.2) ) { mainlooppos = newt; continue; } mainlooppos = ihalve; continue; } /* * ihalve */ if( mainlooppos==ihalve ) { dir = 0; di = 0.5; i = 0; mainlooppos = ihalvecycle; continue; } /* * ihalvecycle */ if( mainlooppos==ihalvecycle ) { if( i<=99 ) { if( i!=0 ) { x = x0+di*(x1-x0); if( ae_fp_eq(x,1.0) ) { x = 1.0-ae_machineepsilon; } if( ae_fp_eq(x,0.0) ) { di = 0.5; x = x0+di*(x1-x0); if( ae_fp_eq(x,0.0) ) { break; } } yyy = incompletebeta(aaa, bbb, x, _state); yp = (x1-x0)/(x1+x0); if( ae_fp_less(ae_fabs(yp, _state),dithresh) ) { mainlooppos = newt; continue; } yp = (yyy-y0)/y0; if( ae_fp_less(ae_fabs(yp, _state),dithresh) ) { mainlooppos = newt; continue; } } if( ae_fp_less(yyy,y0) ) { x0 = x; yl = yyy; if( dir<0 ) { dir = 0; di = 0.5; } else { if( dir>3 ) { di = 1.0-(1.0-di)*(1.0-di); } else { if( dir>1 ) { di = 0.5*di+0.5; } else { di = (y0-yyy)/(yh-yl); } } } dir = dir+1; if( ae_fp_greater(x0,0.75) ) { if( rflg==1 ) { rflg = 0; aaa = a; bbb = b; y0 = y; } else { rflg = 1; aaa = b; bbb = a; y0 = 1.0-y; } x = 1.0-x; yyy = incompletebeta(aaa, bbb, x, _state); x0 = 0.0; yl = 0.0; x1 = 1.0; yh = 1.0; mainlooppos = ihalve; continue; } } else { x1 = x; if( rflg==1&&ae_fp_less(x1,ae_machineepsilon) ) { x = 0.0; break; } yh = yyy; if( dir>0 ) { dir = 0; di = 0.5; } else { if( dir<-3 ) { di = di*di; } else { if( dir<-1 ) { di = 0.5*di; } else { di = (yyy-y0)/(yh-yl); } } } dir = dir-1; } i = i+1; mainlooppos = ihalvecycle; continue; } else { mainlooppos = breakihalvecycle; continue; } } /* * breakihalvecycle */ if( mainlooppos==breakihalvecycle ) { if( ae_fp_greater_eq(x0,1.0) ) { x = 1.0-ae_machineepsilon; break; } if( ae_fp_less_eq(x,0.0) ) { x = 0.0; break; } mainlooppos = newt; continue; } /* * newt */ if( mainlooppos==newt ) { if( nflg!=0 ) { break; } nflg = 1; lgm = lngamma(aaa+bbb, &s, _state)-lngamma(aaa, &s, _state)-lngamma(bbb, &s, _state); i = 0; mainlooppos = newtcycle; continue; } /* * newtcycle */ if( mainlooppos==newtcycle ) { if( i<=7 ) { if( i!=0 ) { yyy = incompletebeta(aaa, bbb, x, _state); } if( ae_fp_less(yyy,yl) ) { x = x0; yyy = yl; } else { if( ae_fp_greater(yyy,yh) ) { x = x1; yyy = yh; } else { if( ae_fp_less(yyy,y0) ) { x0 = x; yl = yyy; } else { x1 = x; yh = yyy; } } } if( ae_fp_eq(x,1.0)||ae_fp_eq(x,0.0) ) { mainlooppos = breaknewtcycle; continue; } d = (aaa-1.0)*ae_log(x, _state)+(bbb-1.0)*ae_log(1.0-x, _state)+lgm; if( ae_fp_less(d,ae_log(ae_minrealnumber, _state)) ) { break; } if( ae_fp_greater(d,ae_log(ae_maxrealnumber, _state)) ) { mainlooppos = breaknewtcycle; continue; } d = ae_exp(d, _state); d = (yyy-y0)/d; xt = x-d; if( ae_fp_less_eq(xt,x0) ) { yyy = (x-x0)/(x1-x0); xt = x0+0.5*yyy*(x-x0); if( ae_fp_less_eq(xt,0.0) ) { mainlooppos = breaknewtcycle; continue; } } if( ae_fp_greater_eq(xt,x1) ) { yyy = (x1-x)/(x1-x0); xt = x1-0.5*yyy*(x1-x); if( ae_fp_greater_eq(xt,1.0) ) { mainlooppos = breaknewtcycle; continue; } } x = xt; if( ae_fp_less(ae_fabs(d/x, _state),128.0*ae_machineepsilon) ) { break; } i = i+1; mainlooppos = newtcycle; continue; } else { mainlooppos = breaknewtcycle; continue; } } /* * breaknewtcycle */ if( mainlooppos==breaknewtcycle ) { dithresh = 256.0*ae_machineepsilon; mainlooppos = ihalve; continue; } } /* * done */ if( rflg!=0 ) { if( ae_fp_less_eq(x,ae_machineepsilon) ) { x = 1.0-ae_machineepsilon; } else { x = 1.0-x; } } result = x; return result; } /************************************************************************* Continued fraction expansion #1 for incomplete beta integral Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ static double ibetaf_incompletebetafe(double a, double b, double x, double big, double biginv, ae_state *_state) { double xk; double pk; double pkm1; double pkm2; double qk; double qkm1; double qkm2; double k1; double k2; double k3; double k4; double k5; double k6; double k7; double k8; double r; double t; double ans; double thresh; ae_int_t n; double result; k1 = a; k2 = a+b; k3 = a; k4 = a+1.0; k5 = 1.0; k6 = b-1.0; k7 = k4; k8 = a+2.0; pkm2 = 0.0; qkm2 = 1.0; pkm1 = 1.0; qkm1 = 1.0; ans = 1.0; r = 1.0; n = 0; thresh = 3.0*ae_machineepsilon; do { xk = -x*k1*k2/(k3*k4); pk = pkm1+pkm2*xk; qk = qkm1+qkm2*xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; xk = x*k5*k6/(k7*k8); pk = pkm1+pkm2*xk; qk = qkm1+qkm2*xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( ae_fp_neq(qk,(double)(0)) ) { r = pk/qk; } if( ae_fp_neq(r,(double)(0)) ) { t = ae_fabs((ans-r)/r, _state); ans = r; } else { t = 1.0; } if( ae_fp_less(t,thresh) ) { break; } k1 = k1+1.0; k2 = k2+1.0; k3 = k3+2.0; k4 = k4+2.0; k5 = k5+1.0; k6 = k6-1.0; k7 = k7+2.0; k8 = k8+2.0; if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) { pkm2 = pkm2*biginv; pkm1 = pkm1*biginv; qkm2 = qkm2*biginv; qkm1 = qkm1*biginv; } if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) { pkm2 = pkm2*big; pkm1 = pkm1*big; qkm2 = qkm2*big; qkm1 = qkm1*big; } n = n+1; } while(n!=300); result = ans; return result; } /************************************************************************* Continued fraction expansion #2 for incomplete beta integral Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ static double ibetaf_incompletebetafe2(double a, double b, double x, double big, double biginv, ae_state *_state) { double xk; double pk; double pkm1; double pkm2; double qk; double qkm1; double qkm2; double k1; double k2; double k3; double k4; double k5; double k6; double k7; double k8; double r; double t; double ans; double z; double thresh; ae_int_t n; double result; k1 = a; k2 = b-1.0; k3 = a; k4 = a+1.0; k5 = 1.0; k6 = a+b; k7 = a+1.0; k8 = a+2.0; pkm2 = 0.0; qkm2 = 1.0; pkm1 = 1.0; qkm1 = 1.0; z = x/(1.0-x); ans = 1.0; r = 1.0; n = 0; thresh = 3.0*ae_machineepsilon; do { xk = -z*k1*k2/(k3*k4); pk = pkm1+pkm2*xk; qk = qkm1+qkm2*xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; xk = z*k5*k6/(k7*k8); pk = pkm1+pkm2*xk; qk = qkm1+qkm2*xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( ae_fp_neq(qk,(double)(0)) ) { r = pk/qk; } if( ae_fp_neq(r,(double)(0)) ) { t = ae_fabs((ans-r)/r, _state); ans = r; } else { t = 1.0; } if( ae_fp_less(t,thresh) ) { break; } k1 = k1+1.0; k2 = k2-1.0; k3 = k3+2.0; k4 = k4+2.0; k5 = k5+1.0; k6 = k6+1.0; k7 = k7+2.0; k8 = k8+2.0; if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) { pkm2 = pkm2*biginv; pkm1 = pkm1*biginv; qkm2 = qkm2*biginv; qkm1 = qkm1*biginv; } if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) { pkm2 = pkm2*big; pkm1 = pkm1*big; qkm2 = qkm2*big; qkm1 = qkm1*big; } n = n+1; } while(n!=300); result = ans; return result; } /************************************************************************* Power series for incomplete beta integral. Use when b*x is small and x not too close to 1. Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/ static double ibetaf_incompletebetaps(double a, double b, double x, double maxgam, ae_state *_state) { double s; double t; double u; double v; double n; double t1; double z; double ai; double sg; double result; ai = 1.0/a; u = (1.0-b)*x; v = u/(a+1.0); t1 = v; t = u; n = 2.0; s = 0.0; z = ae_machineepsilon*ai; while(ae_fp_greater(ae_fabs(v, _state),z)) { u = (n-b)*x/n; t = t*u; v = t/(a+n); s = s+v; n = n+1.0; } s = s+t1; s = s+ai; u = a*ae_log(x, _state); if( ae_fp_less(a+b,maxgam)&&ae_fp_less(ae_fabs(u, _state),ae_log(ae_maxrealnumber, _state)) ) { t = gammafunction(a+b, _state)/(gammafunction(a, _state)*gammafunction(b, _state)); s = s*t*ae_pow(x, a, _state); } else { t = lngamma(a+b, &sg, _state)-lngamma(a, &sg, _state)-lngamma(b, &sg, _state)+u+ae_log(s, _state); if( ae_fp_less(t,ae_log(ae_minrealnumber, _state)) ) { s = 0.0; } else { s = ae_exp(t, _state); } } result = s; return result; } /************************************************************************* Binomial distribution Returns the sum of the terms 0 through k of the Binomial probability density: k -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=0 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p), with p between 0 and 1. a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 4.3e-15 2.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialdistribution(ae_int_t k, ae_int_t n, double p, ae_state *_state) { double dk; double dn; double result; ae_assert(ae_fp_greater_eq(p,(double)(0))&&ae_fp_less_eq(p,(double)(1)), "Domain error in BinomialDistribution", _state); ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistribution", _state); if( k==-1 ) { result = (double)(0); return result; } if( k==n ) { result = (double)(1); return result; } dn = (double)(n-k); if( k==0 ) { dk = ae_pow(1.0-p, dn, _state); } else { dk = (double)(k+1); dk = incompletebeta(dn, dk, 1.0-p, _state); } result = dk; return result; } /************************************************************************* Complemented binomial distribution Returns the sum of the terms k+1 through n of the Binomial probability density: n -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=k+1 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 6.7e-15 8.2e-16 For p between 0 and .001: IEEE 0,100 100000 1.5e-13 2.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double binomialcdistribution(ae_int_t k, ae_int_t n, double p, ae_state *_state) { double dk; double dn; double result; ae_assert(ae_fp_greater_eq(p,(double)(0))&&ae_fp_less_eq(p,(double)(1)), "Domain error in BinomialDistributionC", _state); ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistributionC", _state); if( k==-1 ) { result = (double)(1); return result; } if( k==n ) { result = (double)(0); return result; } dn = (double)(n-k); if( k==0 ) { if( ae_fp_less(p,0.01) ) { dk = -nuexpm1(dn*nulog1p(-p, _state), _state); } else { dk = 1.0-ae_pow(1.0-p, dn, _state); } } else { dk = (double)(k+1); dk = incompletebeta(dk, dn, p, _state); } result = dk; return result; } /************************************************************************* Inverse binomial distribution Finds the event probability p such that the sum of the terms 0 through k of the Binomial probability density is equal to the given cumulative probability y. This is accomplished using the inverse beta integral function and the relation 1 - p = incbi( n-k, k+1, y ). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 2.3e-14 6.4e-16 IEEE 0,10000 100000 6.6e-12 1.2e-13 For p between 10^-6 and 0.001: IEEE 0,100 100000 2.0e-12 1.3e-14 IEEE 0,10000 100000 1.5e-12 3.2e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invbinomialdistribution(ae_int_t k, ae_int_t n, double y, ae_state *_state) { double dk; double dn; double p; double result; ae_assert(k>=0&&k=0 x - argument, -1 <= x <= 1 Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevcalculate(ae_int_t r, ae_int_t n, double x, ae_state *_state) { ae_int_t i; double a; double b; double result; result = (double)(0); /* * Prepare A and B */ if( r==1 ) { a = (double)(1); b = x; } else { a = (double)(1); b = 2*x; } /* * Special cases: N=0 or N=1 */ if( n==0 ) { result = a; return result; } if( n==1 ) { result = b; return result; } /* * General case: N>=2 */ for(i=2; i<=n; i++) { result = 2*x*b-a; a = b; b = result; } return result; } /************************************************************************* Summation of Chebyshev polynomials using Clenshaws recurrence formula. This routine calculates c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) or c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) depending on the R. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument Result: the value of the Chebyshev polynomial at x *************************************************************************/ double chebyshevsum(/* Real */ ae_vector* c, ae_int_t r, ae_int_t n, double x, ae_state *_state) { double b1; double b2; ae_int_t i; double result; b1 = (double)(0); b2 = (double)(0); for(i=n; i>=1; i--) { result = 2*x*b1-b2+c->ptr.p_double[i]; b2 = b1; b1 = result; } if( r==1 ) { result = -b2+x*b1+c->ptr.p_double[0]; } else { result = -b2+2*x*b1+c->ptr.p_double[0]; } return result; } /************************************************************************* Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void chebyshevcoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_int_t i; ae_vector_clear(c); ae_vector_set_length(c, n+1, _state); for(i=0; i<=n; i++) { c->ptr.p_double[i] = (double)(0); } if( n==0||n==1 ) { c->ptr.p_double[n] = (double)(1); } else { c->ptr.p_double[n] = ae_exp((n-1)*ae_log((double)(2), _state), _state); for(i=0; i<=n/2-1; i++) { c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1)/(n-i-1); } } } /************************************************************************* Conversion of a series of Chebyshev polynomials to a power series. Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as B[0] + B[1]*X + ... + B[N]*X^N. Input parameters: A - Chebyshev series coefficients N - degree, N>=0 Output parameters B - power series coefficients *************************************************************************/ void fromchebyshev(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t i; ae_int_t k; double e; double d; ae_vector_clear(b); ae_vector_set_length(b, n+1, _state); for(i=0; i<=n; i++) { b->ptr.p_double[i] = (double)(0); } d = (double)(0); i = 0; do { k = i; do { e = b->ptr.p_double[k]; b->ptr.p_double[k] = (double)(0); if( i<=1&&k==i ) { b->ptr.p_double[k] = (double)(1); } else { if( i!=0 ) { b->ptr.p_double[k] = 2*d; } if( k>i+1 ) { b->ptr.p_double[k] = b->ptr.p_double[k]-b->ptr.p_double[k-2]; } } d = e; k = k+1; } while(k<=n); d = b->ptr.p_double[i]; e = (double)(0); k = i; while(k<=n) { e = e+b->ptr.p_double[k]*a->ptr.p_double[k]; k = k+2; } b->ptr.p_double[i] = e; i = i+1; } while(i<=n); } /************************************************************************* Chi-square distribution Returns the area under the left hand tail (from 0 to x) of the Chi square probability density function with v degrees of freedom. x - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - 0 where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquaredistribution(double v, double x, ae_state *_state) { double result; ae_assert(ae_fp_greater_eq(x,(double)(0))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in ChiSquareDistribution", _state); result = incompletegamma(v/2.0, x/2.0, _state); return result; } /************************************************************************* Complemented Chi-square distribution Returns the area under the right hand tail (from x to infinity) of the Chi square probability density function with v degrees of freedom: inf. - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - x where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double chisquarecdistribution(double v, double x, ae_state *_state) { double result; ae_assert(ae_fp_greater_eq(x,(double)(0))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in ChiSquareDistributionC", _state); result = incompletegammac(v/2.0, x/2.0, _state); return result; } /************************************************************************* Inverse of complemented Chi-square distribution Finds the Chi-square argument x such that the integral from x to infinity of the Chi-square density is equal to the given cumulative probability y. This is accomplished using the inverse gamma integral function and the relation x/2 = igami( df/2, y ); ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double invchisquaredistribution(double v, double y, ae_state *_state) { double result; ae_assert((ae_fp_greater_eq(y,(double)(0))&&ae_fp_less_eq(y,(double)(1)))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in InvChiSquareDistribution", _state); result = 2*invincompletegammac(0.5*v, y, _state); return result; } /************************************************************************* Dawson's Integral Approximates the integral x - 2 | | 2 dawsn(x) = exp( -x ) | exp( t ) dt | | - 0 Three different rational approximations are employed, for the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,10 10000 6.9e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double dawsonintegral(double x, ae_state *_state) { double x2; double y; ae_int_t sg; double an; double ad; double bn; double bd; double cn; double cd; double result; sg = 1; if( ae_fp_less(x,(double)(0)) ) { sg = -1; x = -x; } if( ae_fp_less(x,3.25) ) { x2 = x*x; an = 1.13681498971755972054E-11; an = an*x2+8.49262267667473811108E-10; an = an*x2+1.94434204175553054283E-8; an = an*x2+9.53151741254484363489E-7; an = an*x2+3.07828309874913200438E-6; an = an*x2+3.52513368520288738649E-4; an = an*x2+(-8.50149846724410912031E-4); an = an*x2+4.22618223005546594270E-2; an = an*x2+(-9.17480371773452345351E-2); an = an*x2+9.99999999999999994612E-1; ad = 2.40372073066762605484E-11; ad = ad*x2+1.48864681368493396752E-9; ad = ad*x2+5.21265281010541664570E-8; ad = ad*x2+1.27258478273186970203E-6; ad = ad*x2+2.32490249820789513991E-5; ad = ad*x2+3.25524741826057911661E-4; ad = ad*x2+3.48805814657162590916E-3; ad = ad*x2+2.79448531198828973716E-2; ad = ad*x2+1.58874241960120565368E-1; ad = ad*x2+5.74918629489320327824E-1; ad = ad*x2+1.00000000000000000539E0; y = x*an/ad; result = sg*y; return result; } x2 = 1.0/(x*x); if( ae_fp_less(x,6.25) ) { bn = 5.08955156417900903354E-1; bn = bn*x2-2.44754418142697847934E-1; bn = bn*x2+9.41512335303534411857E-2; bn = bn*x2-2.18711255142039025206E-2; bn = bn*x2+3.66207612329569181322E-3; bn = bn*x2-4.23209114460388756528E-4; bn = bn*x2+3.59641304793896631888E-5; bn = bn*x2-2.14640351719968974225E-6; bn = bn*x2+9.10010780076391431042E-8; bn = bn*x2-2.40274520828250956942E-9; bn = bn*x2+3.59233385440928410398E-11; bd = 1.00000000000000000000E0; bd = bd*x2-6.31839869873368190192E-1; bd = bd*x2+2.36706788228248691528E-1; bd = bd*x2-5.31806367003223277662E-2; bd = bd*x2+8.48041718586295374409E-3; bd = bd*x2-9.47996768486665330168E-4; bd = bd*x2+7.81025592944552338085E-5; bd = bd*x2-4.55875153252442634831E-6; bd = bd*x2+1.89100358111421846170E-7; bd = bd*x2-4.91324691331920606875E-9; bd = bd*x2+7.18466403235734541950E-11; y = 1.0/x+x2*bn/(bd*x); result = sg*0.5*y; return result; } if( ae_fp_greater(x,1.0E9) ) { result = sg*0.5/x; return result; } cn = -5.90592860534773254987E-1; cn = cn*x2+6.29235242724368800674E-1; cn = cn*x2-1.72858975380388136411E-1; cn = cn*x2+1.64837047825189632310E-2; cn = cn*x2-4.86827613020462700845E-4; cd = 1.00000000000000000000E0; cd = cd*x2-2.69820057197544900361E0; cd = cd*x2+1.73270799045947845857E0; cd = cd*x2-3.93708582281939493482E-1; cd = cd*x2+3.44278924041233391079E-2; cd = cd*x2-9.73655226040941223894E-4; y = 1.0/x+x2*cn/(cd*x); result = sg*0.5*y; return result; } /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 using the approximation P(x) - log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralk(double m, ae_state *_state) { double result; result = ellipticintegralkhighprecision(1.0-m, _state); return result; } /************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 where m = 1 - m1, using the approximation P(x) - log x Q(x). The argument m1 is used rather than m so that the logarithmic singularity at m = 1 will be shifted to the origin; this preserves maximum accuracy. K(0) = pi/2. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegralkhighprecision(double m1, ae_state *_state) { double p; double q; double result; if( ae_fp_less_eq(m1,ae_machineepsilon) ) { result = 1.3862943611198906188E0-0.5*ae_log(m1, _state); } else { p = 1.37982864606273237150E-4; p = p*m1+2.28025724005875567385E-3; p = p*m1+7.97404013220415179367E-3; p = p*m1+9.85821379021226008714E-3; p = p*m1+6.87489687449949877925E-3; p = p*m1+6.18901033637687613229E-3; p = p*m1+8.79078273952743772254E-3; p = p*m1+1.49380448916805252718E-2; p = p*m1+3.08851465246711995998E-2; p = p*m1+9.65735902811690126535E-2; p = p*m1+1.38629436111989062502E0; q = 2.94078955048598507511E-5; q = q*m1+9.14184723865917226571E-4; q = q*m1+5.94058303753167793257E-3; q = q*m1+1.54850516649762399335E-2; q = q*m1+2.39089602715924892727E-2; q = q*m1+3.01204715227604046988E-2; q = q*m1+3.73774314173823228969E-2; q = q*m1+4.88280347570998239232E-2; q = q*m1+7.03124996963957469739E-2; q = q*m1+1.24999999999870820058E-1; q = q*m1+4.99999999999999999821E-1; result = p-q*ae_log(m1, _state); } return result; } /************************************************************************* Incomplete elliptic integral of the first kind F(phi|m) Approximates the integral phi - | | | dt F(phi_\m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random points with m in [0, 1] and phi as indicated. Relative error: arithmetic domain # trials peak rms IEEE -10,10 200000 7.4e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegralk(double phi, double m, ae_state *_state) { double a; double b; double c; double e; double temp; double pio2; double t; double k; ae_int_t d; ae_int_t md; ae_int_t s; ae_int_t npio2; double result; pio2 = 1.57079632679489661923; if( ae_fp_eq(m,(double)(0)) ) { result = phi; return result; } a = 1-m; if( ae_fp_eq(a,(double)(0)) ) { result = ae_log(ae_tan(0.5*(pio2+phi), _state), _state); return result; } npio2 = ae_ifloor(phi/pio2, _state); if( npio2%2!=0 ) { npio2 = npio2+1; } if( npio2!=0 ) { k = ellipticintegralk(1-a, _state); phi = phi-npio2*pio2; } else { k = (double)(0); } if( ae_fp_less(phi,(double)(0)) ) { phi = -phi; s = -1; } else { s = 0; } b = ae_sqrt(a, _state); t = ae_tan(phi, _state); if( ae_fp_greater(ae_fabs(t, _state),(double)(10)) ) { e = 1.0/(b*t); if( ae_fp_less(ae_fabs(e, _state),(double)(10)) ) { e = ae_atan(e, _state); if( npio2==0 ) { k = ellipticintegralk(1-a, _state); } temp = k-incompleteellipticintegralk(e, m, _state); if( s<0 ) { temp = -temp; } result = temp+npio2*k; return result; } } a = 1.0; c = ae_sqrt(m, _state); d = 1; md = 0; while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) { temp = b/a; phi = phi+ae_atan(t*temp, _state)+md*ae_pi; md = ae_trunc((phi+pio2)/ae_pi, _state); t = t*(1.0+temp)/(1.0-temp*t*t); c = 0.5*(a-b); temp = ae_sqrt(a*b, _state); a = 0.5*(a+b); b = temp; d = d+d; } temp = (ae_atan(t, _state)+md*ae_pi)/(d*a); if( s<0 ) { temp = -temp; } result = temp+npio2*k; return result; } /************************************************************************* Complete elliptic integral of the second kind Approximates the integral pi/2 - | | 2 E(m) = | sqrt( 1 - m sin t ) dt | | - 0 using the approximation P(x) - x log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 1 10000 2.1e-16 7.3e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ double ellipticintegrale(double m, ae_state *_state) { double p; double q; double result; ae_assert(ae_fp_greater_eq(m,(double)(0))&&ae_fp_less_eq(m,(double)(1)), "Domain error in EllipticIntegralE: m<0 or m>1", _state); m = 1-m; if( ae_fp_eq(m,(double)(0)) ) { result = (double)(1); return result; } p = 1.53552577301013293365E-4; p = p*m+2.50888492163602060990E-3; p = p*m+8.68786816565889628429E-3; p = p*m+1.07350949056076193403E-2; p = p*m+7.77395492516787092951E-3; p = p*m+7.58395289413514708519E-3; p = p*m+1.15688436810574127319E-2; p = p*m+2.18317996015557253103E-2; p = p*m+5.68051945617860553470E-2; p = p*m+4.43147180560990850618E-1; p = p*m+1.00000000000000000299E0; q = 3.27954898576485872656E-5; q = q*m+1.00962792679356715133E-3; q = q*m+6.50609489976927491433E-3; q = q*m+1.68862163993311317300E-2; q = q*m+2.61769742454493659583E-2; q = q*m+3.34833904888224918614E-2; q = q*m+4.27180926518931511717E-2; q = q*m+5.85936634471101055642E-2; q = q*m+9.37499997197644278445E-2; q = q*m+2.49999999999888314361E-1; result = p-q*m*ae_log(m, _state); return result; } /************************************************************************* Incomplete elliptic integral of the second kind Approximates the integral phi - | | | 2 E(phi_\m) = | sqrt( 1 - m sin t ) dt | | | - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random arguments with phi in [-10, 10] and m in [0, 1]. Relative error: arithmetic domain # trials peak rms IEEE -10,10 150000 3.3e-15 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier *************************************************************************/ double incompleteellipticintegrale(double phi, double m, ae_state *_state) { double pio2; double a; double b; double c; double e; double temp; double lphi; double t; double ebig; ae_int_t d; ae_int_t md; ae_int_t npio2; ae_int_t s; double result; pio2 = 1.57079632679489661923; if( ae_fp_eq(m,(double)(0)) ) { result = phi; return result; } lphi = phi; npio2 = ae_ifloor(lphi/pio2, _state); if( npio2%2!=0 ) { npio2 = npio2+1; } lphi = lphi-npio2*pio2; if( ae_fp_less(lphi,(double)(0)) ) { lphi = -lphi; s = -1; } else { s = 1; } a = 1.0-m; ebig = ellipticintegrale(m, _state); if( ae_fp_eq(a,(double)(0)) ) { temp = ae_sin(lphi, _state); if( s<0 ) { temp = -temp; } result = temp+npio2*ebig; return result; } t = ae_tan(lphi, _state); b = ae_sqrt(a, _state); /* * Thanks to Brian Fitzgerald * for pointing out an instability near odd multiples of pi/2 */ if( ae_fp_greater(ae_fabs(t, _state),(double)(10)) ) { /* * Transform the amplitude */ e = 1.0/(b*t); /* * ... but avoid multiple recursions. */ if( ae_fp_less(ae_fabs(e, _state),(double)(10)) ) { e = ae_atan(e, _state); temp = ebig+m*ae_sin(lphi, _state)*ae_sin(e, _state)-incompleteellipticintegrale(e, m, _state); if( s<0 ) { temp = -temp; } result = temp+npio2*ebig; return result; } } c = ae_sqrt(m, _state); a = 1.0; d = 1; e = 0.0; md = 0; while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) { temp = b/a; lphi = lphi+ae_atan(t*temp, _state)+md*ae_pi; md = ae_trunc((lphi+pio2)/ae_pi, _state); t = t*(1.0+temp)/(1.0-temp*t*t); c = 0.5*(a-b); temp = ae_sqrt(a*b, _state); a = 0.5*(a+b); b = temp; d = d+d; e = e+c*ae_sin(lphi, _state); } temp = ebig/ellipticintegralk(m, _state); temp = temp*((ae_atan(t, _state)+md*ae_pi)/(d*a)); temp = temp+e; if( s<0 ) { temp = -temp; } result = temp+npio2*ebig; return result; } /************************************************************************* Exponential integral Ei(x) x - t | | e Ei(x) = -|- --- dt . | | t - -inf Not defined for x <= 0. See also expn.c. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,100 50000 8.6e-16 1.3e-16 Cephes Math Library Release 2.8: May, 1999 Copyright 1999 by Stephen L. Moshier *************************************************************************/ double exponentialintegralei(double x, ae_state *_state) { double eul; double f; double f1; double f2; double w; double result; eul = 0.5772156649015328606065; if( ae_fp_less_eq(x,(double)(0)) ) { result = (double)(0); return result; } if( ae_fp_less(x,(double)(2)) ) { f1 = -5.350447357812542947283; f1 = f1*x+218.5049168816613393830; f1 = f1*x-4176.572384826693777058; f1 = f1*x+55411.76756393557601232; f1 = f1*x-331338.1331178144034309; f1 = f1*x+1592627.163384945414220; f2 = 1.000000000000000000000; f2 = f2*x-52.50547959112862969197; f2 = f2*x+1259.616186786790571525; f2 = f2*x-17565.49581973534652631; f2 = f2*x+149306.2117002725991967; f2 = f2*x-729494.9239640527645655; f2 = f2*x+1592627.163384945429726; f = f1/f2; result = eul+ae_log(x, _state)+x*f; return result; } if( ae_fp_less(x,(double)(4)) ) { w = 1/x; f1 = 1.981808503259689673238E-2; f1 = f1*w-1.271645625984917501326; f1 = f1*w-2.088160335681228318920; f1 = f1*w+2.755544509187936721172; f1 = f1*w-4.409507048701600257171E-1; f1 = f1*w+4.665623805935891391017E-2; f1 = f1*w-1.545042679673485262580E-3; f1 = f1*w+7.059980605299617478514E-5; f2 = 1.000000000000000000000; f2 = f2*w+1.476498670914921440652; f2 = f2*w+5.629177174822436244827E-1; f2 = f2*w+1.699017897879307263248E-1; f2 = f2*w+2.291647179034212017463E-2; f2 = f2*w+4.450150439728752875043E-3; f2 = f2*w+1.727439612206521482874E-4; f2 = f2*w+3.953167195549672482304E-5; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } if( ae_fp_less(x,(double)(8)) ) { w = 1/x; f1 = -1.373215375871208729803; f1 = f1*w-7.084559133740838761406E-1; f1 = f1*w+1.580806855547941010501; f1 = f1*w-2.601500427425622944234E-1; f1 = f1*w+2.994674694113713763365E-2; f1 = f1*w-1.038086040188744005513E-3; f1 = f1*w+4.371064420753005429514E-5; f1 = f1*w+2.141783679522602903795E-6; f2 = 1.000000000000000000000; f2 = f2*w+8.585231423622028380768E-1; f2 = f2*w+4.483285822873995129957E-1; f2 = f2*w+7.687932158124475434091E-2; f2 = f2*w+2.449868241021887685904E-2; f2 = f2*w+8.832165941927796567926E-4; f2 = f2*w+4.590952299511353531215E-4; f2 = f2*w+(-4.729848351866523044863E-6); f2 = f2*w+2.665195537390710170105E-6; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } if( ae_fp_less(x,(double)(16)) ) { w = 1/x; f1 = -2.106934601691916512584; f1 = f1*w+1.732733869664688041885; f1 = f1*w-2.423619178935841904839E-1; f1 = f1*w+2.322724180937565842585E-2; f1 = f1*w+2.372880440493179832059E-4; f1 = f1*w-8.343219561192552752335E-5; f1 = f1*w+1.363408795605250394881E-5; f1 = f1*w-3.655412321999253963714E-7; f1 = f1*w+1.464941733975961318456E-8; f1 = f1*w+6.176407863710360207074E-10; f2 = 1.000000000000000000000; f2 = f2*w-2.298062239901678075778E-1; f2 = f2*w+1.105077041474037862347E-1; f2 = f2*w-1.566542966630792353556E-2; f2 = f2*w+2.761106850817352773874E-3; f2 = f2*w-2.089148012284048449115E-4; f2 = f2*w+1.708528938807675304186E-5; f2 = f2*w-4.459311796356686423199E-7; f2 = f2*w+1.394634930353847498145E-8; f2 = f2*w+6.150865933977338354138E-10; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } if( ae_fp_less(x,(double)(32)) ) { w = 1/x; f1 = -2.458119367674020323359E-1; f1 = f1*w-1.483382253322077687183E-1; f1 = f1*w+7.248291795735551591813E-2; f1 = f1*w-1.348315687380940523823E-2; f1 = f1*w+1.342775069788636972294E-3; f1 = f1*w-7.942465637159712264564E-5; f1 = f1*w+2.644179518984235952241E-6; f1 = f1*w-4.239473659313765177195E-8; f2 = 1.000000000000000000000; f2 = f2*w-1.044225908443871106315E-1; f2 = f2*w-2.676453128101402655055E-1; f2 = f2*w+9.695000254621984627876E-2; f2 = f2*w-1.601745692712991078208E-2; f2 = f2*w+1.496414899205908021882E-3; f2 = f2*w-8.462452563778485013756E-5; f2 = f2*w+2.728938403476726394024E-6; f2 = f2*w-4.239462431819542051337E-8; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } if( ae_fp_less(x,(double)(64)) ) { w = 1/x; f1 = 1.212561118105456670844E-1; f1 = f1*w-5.823133179043894485122E-1; f1 = f1*w+2.348887314557016779211E-1; f1 = f1*w-3.040034318113248237280E-2; f1 = f1*w+1.510082146865190661777E-3; f1 = f1*w-2.523137095499571377122E-5; f2 = 1.000000000000000000000; f2 = f2*w-1.002252150365854016662; f2 = f2*w+2.928709694872224144953E-1; f2 = f2*w-3.337004338674007801307E-2; f2 = f2*w+1.560544881127388842819E-3; f2 = f2*w-2.523137093603234562648E-5; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } w = 1/x; f1 = -7.657847078286127362028E-1; f1 = f1*w+6.886192415566705051750E-1; f1 = f1*w-2.132598113545206124553E-1; f1 = f1*w+3.346107552384193813594E-2; f1 = f1*w-3.076541477344756050249E-3; f1 = f1*w+1.747119316454907477380E-4; f1 = f1*w-6.103711682274170530369E-6; f1 = f1*w+1.218032765428652199087E-7; f1 = f1*w-1.086076102793290233007E-9; f2 = 1.000000000000000000000; f2 = f2*w-1.888802868662308731041; f2 = f2*w+1.066691687211408896850; f2 = f2*w-2.751915982306380647738E-1; f2 = f2*w+3.930852688233823569726E-2; f2 = f2*w-3.414684558602365085394E-3; f2 = f2*w+1.866844370703555398195E-4; f2 = f2*w-6.345146083130515357861E-6; f2 = f2*w+1.239754287483206878024E-7; f2 = f2*w-1.086076102793126632978E-9; f = f1/f2; result = ae_exp(x, _state)*w*(1+w*f); return result; } /************************************************************************* Exponential integral En(x) Evaluates the exponential integral inf. - | | -xt | e E (x) = | ---- dt. n | n | | t - 1 Both n and x must be nonnegative. The routine employs either a power series, a continued fraction, or an asymptotic formula depending on the relative values of n and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 10000 1.7e-15 3.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 2000 by Stephen L. Moshier *************************************************************************/ double exponentialintegralen(double x, ae_int_t n, ae_state *_state) { double r; double t; double yk; double xk; double pk; double pkm1; double pkm2; double qk; double qkm1; double qkm2; double psi; double z; ae_int_t i; ae_int_t k; double big; double eul; double result; eul = 0.57721566490153286060; big = 1.44115188075855872*ae_pow((double)(10), (double)(17), _state); if( ((n<0||ae_fp_less(x,(double)(0)))||ae_fp_greater(x,(double)(170)))||(ae_fp_eq(x,(double)(0))&&n<2) ) { result = (double)(-1); return result; } if( ae_fp_eq(x,(double)(0)) ) { result = (double)1/(double)(n-1); return result; } if( n==0 ) { result = ae_exp(-x, _state)/x; return result; } if( n>5000 ) { xk = x+n; yk = 1/(xk*xk); t = (double)(n); result = yk*t*(6*x*x-8*t*x+t*t); result = yk*(result+t*(t-2.0*x)); result = yk*(result+t); result = (result+1)*ae_exp(-x, _state)/xk; return result; } if( ae_fp_less_eq(x,(double)(1)) ) { psi = -eul-ae_log(x, _state); for(i=1; i<=n-1; i++) { psi = psi+(double)1/(double)i; } z = -x; xk = (double)(0); yk = (double)(1); pk = (double)(1-n); if( n==1 ) { result = 0.0; } else { result = 1.0/pk; } do { xk = xk+1; yk = yk*z/xk; pk = pk+1; if( ae_fp_neq(pk,(double)(0)) ) { result = result+yk/pk; } if( ae_fp_neq(result,(double)(0)) ) { t = ae_fabs(yk/result, _state); } else { t = (double)(1); } } while(ae_fp_greater_eq(t,ae_machineepsilon)); t = (double)(1); for(i=1; i<=n-1; i++) { t = t*z/i; } result = psi*t-result; return result; } else { k = 1; pkm2 = (double)(1); qkm2 = x; pkm1 = 1.0; qkm1 = x+n; result = pkm1/qkm1; do { k = k+1; if( k%2==1 ) { yk = (double)(1); xk = n+(double)(k-1)/(double)2; } else { yk = x; xk = (double)k/(double)2; } pk = pkm1*yk+pkm2*xk; qk = qkm1*yk+qkm2*xk; if( ae_fp_neq(qk,(double)(0)) ) { r = pk/qk; t = ae_fabs((result-r)/r, _state); result = r; } else { t = (double)(1); } pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( ae_fp_greater(ae_fabs(pk, _state),big) ) { pkm2 = pkm2/big; pkm1 = pkm1/big; qkm2 = qkm2/big; qkm1 = qkm1/big; } } while(ae_fp_greater_eq(t,ae_machineepsilon)); result = result*ae_exp(-x, _state); } return result; } /************************************************************************* F distribution Returns the area from zero to x under the F density function (also known as Snedcor's density or the variance ratio density). This is the density of x = (u1/df1)/(u2/df2), where u1 and u2 are random variables having Chi square distributions with df1 and df2 degrees of freedom, respectively. The incomplete beta integral is used, according to the formula P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). The arguments a and b are greater than zero, and x is nonnegative. ACCURACY: Tested at random points (a,b,x). x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) { double w; double result; ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,(double)(0)), "Domain error in FDistribution", _state); w = a*x; w = w/(b+w); result = incompletebeta(0.5*a, 0.5*b, w, _state); return result; } /************************************************************************* Complemented F distribution Returns the area from x to infinity under the F density function (also known as Snedcor's density or the variance ratio density). inf. - 1 | | a-1 b-1 1-P(x) = ------ | t (1-t) dt B(a,b) | | - x The incomplete beta integral is used, according to the formula P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). ACCURACY: Tested at random points (a,b,x) in the indicated intervals. x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) { double w; double result; ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,(double)(0)), "Domain error in FCDistribution", _state); w = b/(b+a*x); result = incompletebeta(0.5*b, 0.5*a, w, _state); return result; } /************************************************************************* Inverse of complemented F distribution Finds the F density argument x such that the integral from x to infinity of the F density is equal to the given probability p. This is accomplished using the inverse beta integral function and the relations z = incbi( df2/2, df1/2, p ) x = df2 (1-z) / (df1 z). Note: the following relations hold for the inverse of the uncomplemented F distribution: z = incbi( df1/2, df2/2, p ) x = df2 z / (df1 (1-z)). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between .001 and 1: IEEE 1,100 100000 8.3e-15 4.7e-16 IEEE 1,10000 100000 2.1e-11 1.4e-13 For p between 10^-6 and 10^-3: IEEE 1,100 50000 1.3e-12 8.4e-15 IEEE 1,10000 50000 3.0e-12 4.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invfdistribution(ae_int_t a, ae_int_t b, double y, ae_state *_state) { double w; double result; ae_assert(((a>=1&&b>=1)&&ae_fp_greater(y,(double)(0)))&&ae_fp_less_eq(y,(double)(1)), "Domain error in InvFDistribution", _state); /* * Compute probability for x = 0.5 */ w = incompletebeta(0.5*b, 0.5*a, 0.5, _state); /* * If that is greater than y, then the solution w < .5 * Otherwise, solve at 1-y to remove cancellation in (b - b*w) */ if( ae_fp_greater(w,y)||ae_fp_less(y,0.001) ) { w = invincompletebeta(0.5*b, 0.5*a, y, _state); result = (b-b*w)/(a*w); } else { w = invincompletebeta(0.5*a, 0.5*b, 1.0-y, _state); result = b*w/(a*(1.0-w)); } return result; } /************************************************************************* Fresnel integral Evaluates the Fresnel integrals x - | | C(x) = | cos(pi/2 t**2) dt, | | - 0 x - | | S(x) = | sin(pi/2 t**2) dt. | | - 0 The integrals are evaluated by a power series for x < 1. For x >= 1 auxiliary functions f(x) and g(x) are employed such that C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) ACCURACY: Relative error. Arithmetic function domain # trials peak rms IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/ void fresnelintegral(double x, double* c, double* s, ae_state *_state) { double xxa; double f; double g; double cc; double ss; double t; double u; double x2; double sn; double sd; double cn; double cd; double fn; double fd; double gn; double gd; double mpi; double mpio2; mpi = 3.14159265358979323846; mpio2 = 1.57079632679489661923; xxa = x; x = ae_fabs(xxa, _state); x2 = x*x; if( ae_fp_less(x2,2.5625) ) { t = x2*x2; sn = -2.99181919401019853726E3; sn = sn*t+7.08840045257738576863E5; sn = sn*t-6.29741486205862506537E7; sn = sn*t+2.54890880573376359104E9; sn = sn*t-4.42979518059697779103E10; sn = sn*t+3.18016297876567817986E11; sd = 1.00000000000000000000E0; sd = sd*t+2.81376268889994315696E2; sd = sd*t+4.55847810806532581675E4; sd = sd*t+5.17343888770096400730E6; sd = sd*t+4.19320245898111231129E8; sd = sd*t+2.24411795645340920940E10; sd = sd*t+6.07366389490084639049E11; cn = -4.98843114573573548651E-8; cn = cn*t+9.50428062829859605134E-6; cn = cn*t-6.45191435683965050962E-4; cn = cn*t+1.88843319396703850064E-2; cn = cn*t-2.05525900955013891793E-1; cn = cn*t+9.99999999999999998822E-1; cd = 3.99982968972495980367E-12; cd = cd*t+9.15439215774657478799E-10; cd = cd*t+1.25001862479598821474E-7; cd = cd*t+1.22262789024179030997E-5; cd = cd*t+8.68029542941784300606E-4; cd = cd*t+4.12142090722199792936E-2; cd = cd*t+1.00000000000000000118E0; *s = ae_sign(xxa, _state)*x*x2*sn/sd; *c = ae_sign(xxa, _state)*x*cn/cd; return; } if( ae_fp_greater(x,36974.0) ) { *c = ae_sign(xxa, _state)*0.5; *s = ae_sign(xxa, _state)*0.5; return; } x2 = x*x; t = mpi*x2; u = 1/(t*t); t = 1/t; fn = 4.21543555043677546506E-1; fn = fn*u+1.43407919780758885261E-1; fn = fn*u+1.15220955073585758835E-2; fn = fn*u+3.45017939782574027900E-4; fn = fn*u+4.63613749287867322088E-6; fn = fn*u+3.05568983790257605827E-8; fn = fn*u+1.02304514164907233465E-10; fn = fn*u+1.72010743268161828879E-13; fn = fn*u+1.34283276233062758925E-16; fn = fn*u+3.76329711269987889006E-20; fd = 1.00000000000000000000E0; fd = fd*u+7.51586398353378947175E-1; fd = fd*u+1.16888925859191382142E-1; fd = fd*u+6.44051526508858611005E-3; fd = fd*u+1.55934409164153020873E-4; fd = fd*u+1.84627567348930545870E-6; fd = fd*u+1.12699224763999035261E-8; fd = fd*u+3.60140029589371370404E-11; fd = fd*u+5.88754533621578410010E-14; fd = fd*u+4.52001434074129701496E-17; fd = fd*u+1.25443237090011264384E-20; gn = 5.04442073643383265887E-1; gn = gn*u+1.97102833525523411709E-1; gn = gn*u+1.87648584092575249293E-2; gn = gn*u+6.84079380915393090172E-4; gn = gn*u+1.15138826111884280931E-5; gn = gn*u+9.82852443688422223854E-8; gn = gn*u+4.45344415861750144738E-10; gn = gn*u+1.08268041139020870318E-12; gn = gn*u+1.37555460633261799868E-15; gn = gn*u+8.36354435630677421531E-19; gn = gn*u+1.86958710162783235106E-22; gd = 1.00000000000000000000E0; gd = gd*u+1.47495759925128324529E0; gd = gd*u+3.37748989120019970451E-1; gd = gd*u+2.53603741420338795122E-2; gd = gd*u+8.14679107184306179049E-4; gd = gd*u+1.27545075667729118702E-5; gd = gd*u+1.04314589657571990585E-7; gd = gd*u+4.60680728146520428211E-10; gd = gd*u+1.10273215066240270757E-12; gd = gd*u+1.38796531259578871258E-15; gd = gd*u+8.39158816283118707363E-19; gd = gd*u+1.86958710162783236342E-22; f = 1-u*fn/fd; g = t*gn/gd; t = mpio2*x2; cc = ae_cos(t, _state); ss = ae_sin(t, _state); t = mpi*x; *c = 0.5+(f*ss-g*cc)/t; *s = 0.5-(f*cc+g*ss)/t; *c = *c*ae_sign(xxa, _state); *s = *s*ae_sign(xxa, _state); } /************************************************************************* Calculation of the value of the Hermite polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial Hn at x *************************************************************************/ double hermitecalculate(ae_int_t n, double x, ae_state *_state) { ae_int_t i; double a; double b; double result; result = (double)(0); /* * Prepare A and B */ a = (double)(1); b = 2*x; /* * Special cases: N=0 or N=1 */ if( n==0 ) { result = a; return result; } if( n==1 ) { result = b; return result; } /* * General case: N>=2 */ for(i=2; i<=n; i++) { result = 2*x*b-2*(i-1)*a; a = b; b = result; } return result; } /************************************************************************* Summation of Hermite polynomials using Clenshaws recurrence formula. This routine calculates c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial at x *************************************************************************/ double hermitesum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state) { double b1; double b2; ae_int_t i; double result; b1 = (double)(0); b2 = (double)(0); result = (double)(0); for(i=n; i>=0; i--) { result = 2*(x*b1-(i+1)*b2)+c->ptr.p_double[i]; b2 = b1; b1 = result; } return result; } /************************************************************************* Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void hermitecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_int_t i; ae_vector_clear(c); ae_vector_set_length(c, n+1, _state); for(i=0; i<=n; i++) { c->ptr.p_double[i] = (double)(0); } c->ptr.p_double[n] = ae_exp(n*ae_log((double)(2), _state), _state); for(i=0; i<=n/2-1; i++) { c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1); } } /************************************************************************* Jacobian Elliptic Functions Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), and dn(u|m) of parameter m between 0 and 1, and real argument u. These functions are periodic, with quarter-period on the real axis equal to the complete elliptic integral ellpk(1.0-m). Relation to incomplete elliptic integral: If u = ellik(phi,m), then sn(u|m) = sin(phi), and cn(u|m) = cos(phi). Phi is called the amplitude of u. Computation is by means of the arithmetic-geometric mean algorithm, except when m is within 1e-9 of 0 or 1. In the latter case with m close to 1, the approximation applies only for phi < pi/2. ACCURACY: Tested at random points with u between 0 and 10, m between 0 and 1. Absolute error (* = relative error): arithmetic function # trials peak rms IEEE phi 10000 9.2e-16* 1.4e-16* IEEE sn 50000 4.1e-15 4.6e-16 IEEE cn 40000 3.6e-15 4.4e-16 IEEE dn 10000 1.3e-12 1.8e-14 Peak error observed in consistency check using addition theorem for sn(u+v) was 4e-16 (absolute). Also tested by the above relation to the incomplete elliptic integral. Accuracy deteriorates when u is large. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void jacobianellipticfunctions(double u, double m, double* sn, double* cn, double* dn, double* ph, ae_state *_state) { ae_frame _frame_block; double ai; double b; double phi; double t; double twon; ae_vector a; ae_vector c; ae_int_t i; ae_frame_make(_state, &_frame_block); *sn = 0; *cn = 0; *dn = 0; *ph = 0; ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_assert(ae_fp_greater_eq(m,(double)(0))&&ae_fp_less_eq(m,(double)(1)), "Domain error in JacobianEllipticFunctions: m<0 or m>1", _state); ae_vector_set_length(&a, 8+1, _state); ae_vector_set_length(&c, 8+1, _state); if( ae_fp_less(m,1.0e-9) ) { t = ae_sin(u, _state); b = ae_cos(u, _state); ai = 0.25*m*(u-t*b); *sn = t-ai*b; *cn = b+ai*t; *ph = u-ai; *dn = 1.0-0.5*m*t*t; ae_frame_leave(_state); return; } if( ae_fp_greater_eq(m,0.9999999999) ) { ai = 0.25*(1.0-m); b = ae_cosh(u, _state); t = ae_tanh(u, _state); phi = 1.0/b; twon = b*ae_sinh(u, _state); *sn = t+ai*(twon-u)/(b*b); *ph = 2.0*ae_atan(ae_exp(u, _state), _state)-1.57079632679489661923+ai*(twon-u)/b; ai = ai*t*phi; *cn = phi-ai*(twon-u); *dn = phi+ai*(twon+u); ae_frame_leave(_state); return; } a.ptr.p_double[0] = 1.0; b = ae_sqrt(1.0-m, _state); c.ptr.p_double[0] = ae_sqrt(m, _state); twon = 1.0; i = 0; while(ae_fp_greater(ae_fabs(c.ptr.p_double[i]/a.ptr.p_double[i], _state),ae_machineepsilon)) { if( i>7 ) { ae_assert(ae_false, "Overflow in JacobianEllipticFunctions", _state); break; } ai = a.ptr.p_double[i]; i = i+1; c.ptr.p_double[i] = 0.5*(ai-b); t = ae_sqrt(ai*b, _state); a.ptr.p_double[i] = 0.5*(ai+b); b = t; twon = twon*2.0; } phi = twon*a.ptr.p_double[i]*u; do { t = c.ptr.p_double[i]*ae_sin(phi, _state)/a.ptr.p_double[i]; b = phi; phi = (ae_asin(t, _state)+phi)/2.0; i = i-1; } while(i!=0); *sn = ae_sin(phi, _state); t = ae_cos(phi, _state); *cn = t; *dn = t/ae_cos(phi-b, _state); *ph = phi; ae_frame_leave(_state); } /************************************************************************* Calculation of the value of the Laguerre polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial Ln at x *************************************************************************/ double laguerrecalculate(ae_int_t n, double x, ae_state *_state) { double a; double b; double i; double result; result = (double)(1); a = (double)(1); b = 1-x; if( n==1 ) { result = b; } i = (double)(2); while(ae_fp_less_eq(i,(double)(n))) { result = ((2*i-1-x)*b-(i-1)*a)/i; a = b; b = result; i = i+1; } return result; } /************************************************************************* Summation of Laguerre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial at x *************************************************************************/ double laguerresum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state) { double b1; double b2; ae_int_t i; double result; b1 = (double)(0); b2 = (double)(0); result = (double)(0); for(i=n; i>=0; i--) { result = (2*i+1-x)*b1/(i+1)-(i+1)*b2/(i+2)+c->ptr.p_double[i]; b2 = b1; b1 = result; } return result; } /************************************************************************* Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void laguerrecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_int_t i; ae_vector_clear(c); ae_vector_set_length(c, n+1, _state); c->ptr.p_double[0] = (double)(1); for(i=0; i<=n-1; i++) { c->ptr.p_double[i+1] = -c->ptr.p_double[i]*(n-i)/(i+1)/(i+1); } } /************************************************************************* Calculation of the value of the Legendre polynomial Pn. Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial Pn at x *************************************************************************/ double legendrecalculate(ae_int_t n, double x, ae_state *_state) { double a; double b; ae_int_t i; double result; result = (double)(1); a = (double)(1); b = x; if( n==0 ) { result = a; return result; } if( n==1 ) { result = b; return result; } for(i=2; i<=n; i++) { result = ((2*i-1)*x*b-(i-1)*a)/i; a = b; b = result; } return result; } /************************************************************************* Summation of Legendre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial at x *************************************************************************/ double legendresum(/* Real */ ae_vector* c, ae_int_t n, double x, ae_state *_state) { double b1; double b2; ae_int_t i; double result; b1 = (double)(0); b2 = (double)(0); result = (double)(0); for(i=n; i>=0; i--) { result = (2*i+1)*x*b1/(i+1)-(i+1)*b2/(i+2)+c->ptr.p_double[i]; b2 = b1; b1 = result; } return result; } /************************************************************************* Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/ void legendrecoefficients(ae_int_t n, /* Real */ ae_vector* c, ae_state *_state) { ae_int_t i; ae_vector_clear(c); ae_vector_set_length(c, n+1, _state); for(i=0; i<=n; i++) { c->ptr.p_double[i] = (double)(0); } c->ptr.p_double[n] = (double)(1); for(i=1; i<=n; i++) { c->ptr.p_double[n] = c->ptr.p_double[n]*(n+i)/2/i; } for(i=0; i<=n/2-1; i++) { c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/2/(i+1)/(2*(n-i)-1); } } /************************************************************************* Poisson distribution Returns the sum of the first k+1 terms of the Poisson distribution: k j -- -m m > e -- -- j! j=0 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the relation y = pdtr( k, m ) = igamc( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissondistribution(ae_int_t k, double m, ae_state *_state) { double result; ae_assert(k>=0&&ae_fp_greater(m,(double)(0)), "Domain error in PoissonDistribution", _state); result = incompletegammac((double)(k+1), m, _state); return result; } /************************************************************************* Complemented Poisson distribution Returns the sum of the terms k+1 to infinity of the Poisson distribution: inf. j -- -m m > e -- -- j! j=k+1 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the formula y = pdtrc( k, m ) = igam( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double poissoncdistribution(ae_int_t k, double m, ae_state *_state) { double result; ae_assert(k>=0&&ae_fp_greater(m,(double)(0)), "Domain error in PoissonDistributionC", _state); result = incompletegamma((double)(k+1), m, _state); return result; } /************************************************************************* Inverse Poisson distribution Finds the Poisson variable x such that the integral from 0 to x of the Poisson density is equal to the given probability y. This is accomplished using the inverse gamma integral function and the relation m = igami( k+1, y ). ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invpoissondistribution(ae_int_t k, double y, ae_state *_state) { double result; ae_assert((k>=0&&ae_fp_greater_eq(y,(double)(0)))&&ae_fp_less(y,(double)(1)), "Domain error in InvPoissonDistribution", _state); result = invincompletegammac((double)(k+1), y, _state); return result; } /************************************************************************* Psi (digamma) function d - psi(x) = -- ln | (x) dx is the logarithmic derivative of the gamma function. For integer x, n-1 - psi(n) = -EUL + > 1/k. - k=1 This formula is used for 0 < n <= 10. If x is negative, it is transformed to a positive argument by the reflection formula psi(1-x) = psi(x) + pi cot(pi x). For general positive x, the argument is made greater than 10 using the recurrence psi(x+1) = psi(x) + 1/x. Then the following asymptotic expansion is applied: inf. B - 2k psi(x) = log(x) - 1/2x - > ------- - 2k k=1 2k x where the B2k are Bernoulli numbers. ACCURACY: Relative error (except absolute when |psi| < 1): arithmetic domain # trials peak rms IEEE 0,30 30000 1.3e-15 1.4e-16 IEEE -30,0 40000 1.5e-15 2.2e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier *************************************************************************/ double psi(double x, ae_state *_state) { double p; double q; double nz; double s; double w; double y; double z; double polv; ae_int_t i; ae_int_t n; ae_int_t negative; double result; negative = 0; nz = 0.0; if( ae_fp_less_eq(x,(double)(0)) ) { negative = 1; q = x; p = (double)(ae_ifloor(q, _state)); if( ae_fp_eq(p,q) ) { ae_assert(ae_false, "Singularity in Psi(x)", _state); result = ae_maxrealnumber; return result; } nz = q-p; if( ae_fp_neq(nz,0.5) ) { if( ae_fp_greater(nz,0.5) ) { p = p+1.0; nz = q-p; } nz = ae_pi/ae_tan(ae_pi*nz, _state); } else { nz = 0.0; } x = 1.0-x; } if( ae_fp_less_eq(x,10.0)&&ae_fp_eq(x,(double)(ae_ifloor(x, _state))) ) { y = 0.0; n = ae_ifloor(x, _state); for(i=1; i<=n-1; i++) { w = (double)(i); y = y+1.0/w; } y = y-0.57721566490153286061; } else { s = x; w = 0.0; while(ae_fp_less(s,10.0)) { w = w+1.0/s; s = s+1.0; } if( ae_fp_less(s,1.0E17) ) { z = 1.0/(s*s); polv = 8.33333333333333333333E-2; polv = polv*z-2.10927960927960927961E-2; polv = polv*z+7.57575757575757575758E-3; polv = polv*z-4.16666666666666666667E-3; polv = polv*z+3.96825396825396825397E-3; polv = polv*z-8.33333333333333333333E-3; polv = polv*z+8.33333333333333333333E-2; y = z*polv; } else { y = 0.0; } y = ae_log(s, _state)-0.5/s-y-w; } if( negative!=0 ) { y = y-nz; } result = y; return result; } /************************************************************************* Student's t distribution Computes the integral from minus infinity to t of the Student t distribution with integer k > 0 degrees of freedom: t - | | - | 2 -(k+1)/2 | ( (k+1)/2 ) | ( x ) ---------------------- | ( 1 + --- ) dx - | ( k ) sqrt( k pi ) | ( k/2 ) | | | - -inf. Relation to incomplete beta integral: 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) where z = k/(k + t**2). For t < -2, this is the method of computation. For higher t, a direct method is derived from integration by parts. Since the function is symmetric about t=0, the area under the right tail of the density is found by calling the function with -t instead of t. ACCURACY: Tested at random 1 <= k <= 25. The "domain" refers to t. Relative error: arithmetic domain # trials peak rms IEEE -100,-2 50000 5.9e-15 1.4e-15 IEEE -2,100 500000 2.7e-15 4.9e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double studenttdistribution(ae_int_t k, double t, ae_state *_state) { double x; double rk; double z; double f; double tz; double p; double xsqk; ae_int_t j; double result; ae_assert(k>0, "Domain error in StudentTDistribution", _state); if( ae_fp_eq(t,(double)(0)) ) { result = 0.5; return result; } if( ae_fp_less(t,-2.0) ) { rk = (double)(k); z = rk/(rk+t*t); result = 0.5*incompletebeta(0.5*rk, 0.5, z, _state); return result; } if( ae_fp_less(t,(double)(0)) ) { x = -t; } else { x = t; } rk = (double)(k); z = 1.0+x*x/rk; if( k%2!=0 ) { xsqk = x/ae_sqrt(rk, _state); p = ae_atan(xsqk, _state); if( k>1 ) { f = 1.0; tz = 1.0; j = 3; while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) { tz = tz*((j-1)/(z*j)); f = f+tz; j = j+2; } p = p+f*xsqk/z; } p = p*2.0/ae_pi; } else { f = 1.0; tz = 1.0; j = 2; while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) { tz = tz*((j-1)/(z*j)); f = f+tz; j = j+2; } p = f*x/ae_sqrt(z*rk, _state); } if( ae_fp_less(t,(double)(0)) ) { p = -p; } result = 0.5+0.5*p; return result; } /************************************************************************* Functional inverse of Student's t distribution Given probability p, finds the argument t such that stdtr(k,t) is equal to p. ACCURACY: Tested at random 1 <= k <= 100. The "domain" refers to p: Relative error: arithmetic domain # trials peak rms IEEE .001,.999 25000 5.7e-15 8.0e-16 IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/ double invstudenttdistribution(ae_int_t k, double p, ae_state *_state) { double t; double rk; double z; ae_int_t rflg; double result; ae_assert((k>0&&ae_fp_greater(p,(double)(0)))&&ae_fp_less(p,(double)(1)), "Domain error in InvStudentTDistribution", _state); rk = (double)(k); if( ae_fp_greater(p,0.25)&&ae_fp_less(p,0.75) ) { if( ae_fp_eq(p,0.5) ) { result = (double)(0); return result; } z = 1.0-2.0*p; z = invincompletebeta(0.5, 0.5*rk, ae_fabs(z, _state), _state); t = ae_sqrt(rk*z/(1.0-z), _state); if( ae_fp_less(p,0.5) ) { t = -t; } result = t; return result; } rflg = -1; if( ae_fp_greater_eq(p,0.5) ) { p = 1.0-p; rflg = 1; } z = invincompletebeta(0.5*rk, 0.5, 2.0*p, _state); if( ae_fp_less(ae_maxrealnumber*z,rk) ) { result = rflg*ae_maxrealnumber; return result; } t = ae_sqrt(rk/z-rk, _state); result = rflg*t; return result; } /************************************************************************* Sine and cosine integrals Evaluates the integrals x - | cos t - 1 Ci(x) = eul + ln x + | --------- dt, | t - 0 x - | sin t Si(x) = | ----- dt | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are approximated by rational functions. For x > 8 auxiliary functions f(x) and g(x) are employed such that Ci(x) = f(x) sin(x) - g(x) cos(x) Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) ACCURACY: Test interval = [0,50]. Absolute error, except relative when > 1: arithmetic function # trials peak rms IEEE Si 30000 4.4e-16 7.3e-17 IEEE Ci 30000 6.9e-16 5.1e-17 Cephes Math Library Release 2.1: January, 1989 Copyright 1984, 1987, 1989 by Stephen L. Moshier *************************************************************************/ void sinecosineintegrals(double x, double* si, double* ci, ae_state *_state) { double z; double c; double s; double f; double g; ae_int_t sg; double sn; double sd; double cn; double cd; double fn; double fd; double gn; double gd; *si = 0; *ci = 0; if( ae_fp_less(x,(double)(0)) ) { sg = -1; x = -x; } else { sg = 0; } if( ae_fp_eq(x,(double)(0)) ) { *si = (double)(0); *ci = -ae_maxrealnumber; return; } if( ae_fp_greater(x,1.0E9) ) { *si = 1.570796326794896619-ae_cos(x, _state)/x; *ci = ae_sin(x, _state)/x; return; } if( ae_fp_less_eq(x,(double)(4)) ) { z = x*x; sn = -8.39167827910303881427E-11; sn = sn*z+4.62591714427012837309E-8; sn = sn*z-9.75759303843632795789E-6; sn = sn*z+9.76945438170435310816E-4; sn = sn*z-4.13470316229406538752E-2; sn = sn*z+1.00000000000000000302E0; sd = 2.03269266195951942049E-12; sd = sd*z+1.27997891179943299903E-9; sd = sd*z+4.41827842801218905784E-7; sd = sd*z+9.96412122043875552487E-5; sd = sd*z+1.42085239326149893930E-2; sd = sd*z+9.99999999999999996984E-1; s = x*sn/sd; cn = 2.02524002389102268789E-11; cn = cn*z-1.35249504915790756375E-8; cn = cn*z+3.59325051419993077021E-6; cn = cn*z-4.74007206873407909465E-4; cn = cn*z+2.89159652607555242092E-2; cn = cn*z-1.00000000000000000080E0; cd = 4.07746040061880559506E-12; cd = cd*z+3.06780997581887812692E-9; cd = cd*z+1.23210355685883423679E-6; cd = cd*z+3.17442024775032769882E-4; cd = cd*z+5.10028056236446052392E-2; cd = cd*z+4.00000000000000000080E0; c = z*cn/cd; if( sg!=0 ) { s = -s; } *si = s; *ci = 0.57721566490153286061+ae_log(x, _state)+c; return; } s = ae_sin(x, _state); c = ae_cos(x, _state); z = 1.0/(x*x); if( ae_fp_less(x,(double)(8)) ) { fn = 4.23612862892216586994E0; fn = fn*z+5.45937717161812843388E0; fn = fn*z+1.62083287701538329132E0; fn = fn*z+1.67006611831323023771E-1; fn = fn*z+6.81020132472518137426E-3; fn = fn*z+1.08936580650328664411E-4; fn = fn*z+5.48900223421373614008E-7; fd = 1.00000000000000000000E0; fd = fd*z+8.16496634205391016773E0; fd = fd*z+7.30828822505564552187E0; fd = fd*z+1.86792257950184183883E0; fd = fd*z+1.78792052963149907262E-1; fd = fd*z+7.01710668322789753610E-3; fd = fd*z+1.10034357153915731354E-4; fd = fd*z+5.48900252756255700982E-7; f = fn/(x*fd); gn = 8.71001698973114191777E-2; gn = gn*z+6.11379109952219284151E-1; gn = gn*z+3.97180296392337498885E-1; gn = gn*z+7.48527737628469092119E-2; gn = gn*z+5.38868681462177273157E-3; gn = gn*z+1.61999794598934024525E-4; gn = gn*z+1.97963874140963632189E-6; gn = gn*z+7.82579040744090311069E-9; gd = 1.00000000000000000000E0; gd = gd*z+1.64402202413355338886E0; gd = gd*z+6.66296701268987968381E-1; gd = gd*z+9.88771761277688796203E-2; gd = gd*z+6.22396345441768420760E-3; gd = gd*z+1.73221081474177119497E-4; gd = gd*z+2.02659182086343991969E-6; gd = gd*z+7.82579218933534490868E-9; g = z*gn/gd; } else { fn = 4.55880873470465315206E-1; fn = fn*z+7.13715274100146711374E-1; fn = fn*z+1.60300158222319456320E-1; fn = fn*z+1.16064229408124407915E-2; fn = fn*z+3.49556442447859055605E-4; fn = fn*z+4.86215430826454749482E-6; fn = fn*z+3.20092790091004902806E-8; fn = fn*z+9.41779576128512936592E-11; fn = fn*z+9.70507110881952024631E-14; fd = 1.00000000000000000000E0; fd = fd*z+9.17463611873684053703E-1; fd = fd*z+1.78685545332074536321E-1; fd = fd*z+1.22253594771971293032E-2; fd = fd*z+3.58696481881851580297E-4; fd = fd*z+4.92435064317881464393E-6; fd = fd*z+3.21956939101046018377E-8; fd = fd*z+9.43720590350276732376E-11; fd = fd*z+9.70507110881952025725E-14; f = fn/(x*fd); gn = 6.97359953443276214934E-1; gn = gn*z+3.30410979305632063225E-1; gn = gn*z+3.84878767649974295920E-2; gn = gn*z+1.71718239052347903558E-3; gn = gn*z+3.48941165502279436777E-5; gn = gn*z+3.47131167084116673800E-7; gn = gn*z+1.70404452782044526189E-9; gn = gn*z+3.85945925430276600453E-12; gn = gn*z+3.14040098946363334640E-15; gd = 1.00000000000000000000E0; gd = gd*z+1.68548898811011640017E0; gd = gd*z+4.87852258695304967486E-1; gd = gd*z+4.67913194259625806320E-2; gd = gd*z+1.90284426674399523638E-3; gd = gd*z+3.68475504442561108162E-5; gd = gd*z+3.57043223443740838771E-7; gd = gd*z+1.72693748966316146736E-9; gd = gd*z+3.87830166023954706752E-12; gd = gd*z+3.14040098946363335242E-15; g = z*gn/gd; } *si = 1.570796326794896619-f*c-g*s; if( sg!=0 ) { *si = -*si; } *ci = f*s-g*c; } /************************************************************************* Hyperbolic sine and cosine integrals Approximates the integrals x - | | cosh t - 1 Chi(x) = eul + ln x + | ----------- dt, | | t - 0 x - | | sinh t Shi(x) = | ------ dt | | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are evaluated by power series for x < 8 and by Chebyshev expansions for x between 8 and 88. For large x, both functions approach exp(x)/2x. Arguments greater than 88 in magnitude return MAXNUM. ACCURACY: Test interval 0 to 88. Relative error: arithmetic function # trials peak rms IEEE Shi 30000 6.9e-16 1.6e-16 Absolute error, except relative when |Chi| > 1: IEEE Chi 30000 8.4e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/ void hyperbolicsinecosineintegrals(double x, double* shi, double* chi, ae_state *_state) { double k; double z; double c; double s; double a; ae_int_t sg; double b0; double b1; double b2; *shi = 0; *chi = 0; if( ae_fp_less(x,(double)(0)) ) { sg = -1; x = -x; } else { sg = 0; } if( ae_fp_eq(x,(double)(0)) ) { *shi = (double)(0); *chi = -ae_maxrealnumber; return; } if( ae_fp_less(x,8.0) ) { z = x*x; a = 1.0; s = 1.0; c = 0.0; k = 2.0; do { a = a*z/k; c = c+a/k; k = k+1.0; a = a/k; s = s+a/k; k = k+1.0; } while(ae_fp_greater_eq(ae_fabs(a/s, _state),ae_machineepsilon)); s = s*x; } else { if( ae_fp_less(x,18.0) ) { a = (576.0/x-52.0)/10.0; k = ae_exp(x, _state)/x; b0 = 1.83889230173399459482E-17; b1 = 0.0; trigintegrals_chebiterationshichi(a, -9.55485532279655569575E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.04326105980879882648E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.09896949074905343022E-15, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.31313534344092599234E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 5.93976226264314278932E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.47197010497749154755E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.40059764613117131000E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 9.49044626224223543299E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.61596181145435454033E-11, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.77899784436430310321E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.35455469767246947469E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.03257121792819495123E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.56699611114982536845E-8, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.44818877384267342057E-7, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 7.82018215184051295296E-7, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -5.39919118403805073710E-6, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.12458202168959833422E-5, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 8.90136741950727517826E-5, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.02558474743846862168E-3, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.96064440855633256972E-2, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.11847751047257036625E0, &b0, &b1, &b2, _state); s = k*0.5*(b0-b2); b0 = -8.12435385225864036372E-18; b1 = 0.0; trigintegrals_chebiterationshichi(a, 2.17586413290339214377E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 5.22624394924072204667E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -9.48812110591690559363E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 5.35546311647465209166E-15, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.21009970113732918701E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -6.00865178553447437951E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 7.16339649156028587775E-13, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -2.93496072607599856104E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.40359438136491256904E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 8.76302288609054966081E-11, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -4.40092476213282340617E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.87992075640569295479E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.31458150989474594064E-8, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -4.75513930924765465590E-8, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -2.21775018801848880741E-7, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.94635531373272490962E-6, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 4.33505889257316408893E-6, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -6.13387001076494349496E-5, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.13085477492997465138E-4, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 4.97164789823116062801E-4, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.64347496031374526641E-2, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.11446150876699213025E0, &b0, &b1, &b2, _state); c = k*0.5*(b0-b2); } else { if( ae_fp_less_eq(x,88.0) ) { a = (6336.0/x-212.0)/70.0; k = ae_exp(x, _state)/x; b0 = -1.05311574154850938805E-17; b1 = 0.0; trigintegrals_chebiterationshichi(a, 2.62446095596355225821E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 8.82090135625368160657E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.38459811878103047136E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -8.30608026366935789136E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 3.93397875437050071776E-15, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.01765565969729044505E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -4.21128170307640802703E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.60818204519802480035E-13, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 3.34714954175994481761E-13, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.72600352129153073807E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.66894954752839083608E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.49278141024730899554E-11, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.58580661666482709598E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.79289437183355633342E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.76281629144264523277E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.69050228879421288846E-8, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.25391771228487041649E-7, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.16229947068677338732E-6, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.61038260117376323993E-5, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 3.49810375601053973070E-4, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.28478065259647610779E-2, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.03665722588798326712E0, &b0, &b1, &b2, _state); s = k*0.5*(b0-b2); b0 = 8.06913408255155572081E-18; b1 = 0.0; trigintegrals_chebiterationshichi(a, -2.08074168180148170312E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -5.98111329658272336816E-17, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.68533951085945765591E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 4.52313941698904694774E-16, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.10734917335299464535E-15, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -4.42823207332531972288E-15, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 3.49639695410806959872E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 6.63406731718911586609E-14, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.71902448093119218395E-13, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.27135418132338309016E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.74851141935315395333E-12, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.33781843985453438400E-11, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 2.71436006377612442764E-11, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -2.56600180000355990529E-10, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -1.61021375163803438552E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -4.72543064876271773512E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, -3.00095178028681682282E-9, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 7.79387474390914922337E-8, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.06942765566401507066E-6, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.59503164802313196374E-5, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 3.49592575153777996871E-4, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.28475387530065247392E-2, &b0, &b1, &b2, _state); trigintegrals_chebiterationshichi(a, 1.03665693917934275131E0, &b0, &b1, &b2, _state); c = k*0.5*(b0-b2); } else { if( sg!=0 ) { *shi = -ae_maxrealnumber; } else { *shi = ae_maxrealnumber; } *chi = ae_maxrealnumber; return; } } } if( sg!=0 ) { s = -s; } *shi = s; *chi = 0.57721566490153286061+ae_log(x, _state)+c; } static void trigintegrals_chebiterationshichi(double x, double c, double* b0, double* b1, double* b2, ae_state *_state) { *b2 = *b1; *b1 = *b0; *b0 = x*(*b1)-(*b2)+c; } } qmapshack-1.10.0/3rdparty/alglib/src/linalg.h000755 001750 000144 00001216167 13015033052 022143 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _linalg_pkg_h #define _linalg_pkg_h #include "ap.h" #include "alglibinternal.h" #include "alglibmisc.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_vector vals; ae_vector idx; ae_vector ridx; ae_vector didx; ae_vector uidx; ae_int_t matrixtype; ae_int_t m; ae_int_t n; ae_int_t nfree; ae_int_t ninitialized; ae_int_t tablesize; } sparsematrix; typedef struct { ae_vector d; ae_vector u; sparsematrix s; } sparsebuffers; typedef struct { double r1; double rinf; } matinvreport; typedef struct { double e1; double e2; ae_vector x; ae_vector ax; double xax; ae_int_t n; ae_vector rk; ae_vector rk1; ae_vector xk; ae_vector xk1; ae_vector pk; ae_vector pk1; ae_vector b; rcommstate rstate; ae_vector tmp2; } fblslincgstate; typedef struct { ae_int_t n; ae_int_t m; ae_int_t nstart; ae_int_t nits; ae_int_t seedval; ae_vector x0; ae_vector x1; ae_vector t; ae_vector xbest; hqrndstate r; ae_vector x; ae_vector mv; ae_vector mtv; ae_bool needmv; ae_bool needmtv; double repnorm; rcommstate rstate; } normestimatorstate; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Sparse matrix structure. You should use ALGLIB functions to work with sparse matrix. Never try to access its fields directly! NOTES ON THE SPARSE STORAGE FORMATS Sparse matrices can be stored using several formats: * Hash-Table representation * Compressed Row Storage (CRS) * Skyline matrix storage (SKS) Each of the formats has benefits and drawbacks: * Hash-table is good for dynamic operations (insertion of new elements), but does not support linear algebra operations * CRS is good for operations like matrix-vector or matrix-matrix products, but its initialization is less convenient - you have to tell row sizes at the initialization, and you have to fill matrix only row by row, from left to right. * SKS is a special format which is used to store triangular factors from Cholesky factorization. It does not support dynamic modification, and support for linear algebra operations is very limited. Tables below outline information about these two formats: OPERATIONS WITH MATRIX HASH CRS SKS creation + + + SparseGet + + + SparseRewriteExisting + + + SparseSet + SparseAdd + SparseGetRow + + SparseGetCompressedRow + + sparse-dense linear algebra + + *************************************************************************/ class _sparsematrix_owner { public: _sparsematrix_owner(); _sparsematrix_owner(const _sparsematrix_owner &rhs); _sparsematrix_owner& operator=(const _sparsematrix_owner &rhs); virtual ~_sparsematrix_owner(); alglib_impl::sparsematrix* c_ptr(); alglib_impl::sparsematrix* c_ptr() const; protected: alglib_impl::sparsematrix *p_struct; }; class sparsematrix : public _sparsematrix_owner { public: sparsematrix(); sparsematrix(const sparsematrix &rhs); sparsematrix& operator=(const sparsematrix &rhs); virtual ~sparsematrix(); }; /************************************************************************* Temporary buffers for sparse matrix operations. You should pass an instance of this structure to factorization functions. It allows to reuse memory during repeated sparse factorizations. You do not have to call some initialization function - simply passing an instance to factorization function is enough. *************************************************************************/ class _sparsebuffers_owner { public: _sparsebuffers_owner(); _sparsebuffers_owner(const _sparsebuffers_owner &rhs); _sparsebuffers_owner& operator=(const _sparsebuffers_owner &rhs); virtual ~_sparsebuffers_owner(); alglib_impl::sparsebuffers* c_ptr(); alglib_impl::sparsebuffers* c_ptr() const; protected: alglib_impl::sparsebuffers *p_struct; }; class sparsebuffers : public _sparsebuffers_owner { public: sparsebuffers(); sparsebuffers(const sparsebuffers &rhs); sparsebuffers& operator=(const sparsebuffers &rhs); virtual ~sparsebuffers(); }; /************************************************************************* Matrix inverse report: * R1 reciprocal of condition number in 1-norm * RInf reciprocal of condition number in inf-norm *************************************************************************/ class _matinvreport_owner { public: _matinvreport_owner(); _matinvreport_owner(const _matinvreport_owner &rhs); _matinvreport_owner& operator=(const _matinvreport_owner &rhs); virtual ~_matinvreport_owner(); alglib_impl::matinvreport* c_ptr(); alglib_impl::matinvreport* c_ptr() const; protected: alglib_impl::matinvreport *p_struct; }; class matinvreport : public _matinvreport_owner { public: matinvreport(); matinvreport(const matinvreport &rhs); matinvreport& operator=(const matinvreport &rhs); virtual ~matinvreport(); double &r1; double &rinf; }; /************************************************************************* This object stores state of the iterative norm estimation algorithm. You should use ALGLIB functions to work with this object. *************************************************************************/ class _normestimatorstate_owner { public: _normestimatorstate_owner(); _normestimatorstate_owner(const _normestimatorstate_owner &rhs); _normestimatorstate_owner& operator=(const _normestimatorstate_owner &rhs); virtual ~_normestimatorstate_owner(); alglib_impl::normestimatorstate* c_ptr(); alglib_impl::normestimatorstate* c_ptr() const; protected: alglib_impl::normestimatorstate *p_struct; }; class normestimatorstate : public _normestimatorstate_owner { public: normestimatorstate(); normestimatorstate(const normestimatorstate &rhs); normestimatorstate& operator=(const normestimatorstate &rhs); virtual ~normestimatorstate(); }; /************************************************************************* Cache-oblivous complex "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb); /************************************************************************* Cache-oblivous real "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb); /************************************************************************* This code enforces symmetricy of the matrix by copying Upper part to lower one (or vice versa). INPUT PARAMETERS: A - matrix N - number of rows/columns IsUpper - whether we want to copy upper triangle to lower one (True) or vice versa (False). *************************************************************************/ void rmatrixenforcesymmetricity(const real_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb); /************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/ void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb); /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_1d_array &u, const ae_int_t iu, complex_1d_array &v, const ae_int_t iv); /************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/ void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_1d_array &u, const ae_int_t iu, real_1d_array &v, const ae_int_t iv); /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) M>=0 N - number of columns of op(A) N>=0 A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T * OpA=2 => op(A) = A^H X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy); /************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) N - number of columns of op(A) A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy); /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); void smp_cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); void smp_cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); /************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); void smp_rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); /************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); void smp_rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); /************************************************************************* This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C where: * C is NxN Hermitian matrix given by its upper/lower triangle * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^H is calculated * 2 - A^H*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether upper or lower triangle of C is updated; this function updates only one half of C, leaving other half unchanged (not referenced at all). -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); void smp_cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); /************************************************************************* This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C where: * C is NxN symmetric matrix given by its upper/lower triangle * A is NxK matrix when A*A^T is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^T is calculated * 2 - A^T*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether C is upper triangular or lower triangular -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); void smp_rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition, conjugate transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition Beta - coefficient C - matrix (PREALLOCATED, large enough to store result) IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc); void smp_cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc); /************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition Beta - coefficient C - PREALLOCATED output matrix, large enough to store result IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 2009-2013 Bochkanov Sergey *************************************************************************/ void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc); void smp_rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc); /************************************************************************* This subroutine is an older version of CMatrixHERK(), one with wrong name (it is HErmitian update, not SYmmetric). It is left here for backward compatibility. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); void smp_cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); /************************************************************************* QR decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. The elements of matrix R are located on and above the main diagonal of matrix A. The elements which are located in Tau array and below the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(k-1), where k = min(m,n), and each H(i) is in the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); void smp_rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); /************************************************************************* LQ decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices L and Q in compact form (see below) Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..Min(M,N)-1]. Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. The elements of matrix L are located on and below the main diagonal of matrix A. The elements which are located in Tau array and above the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(k-1)*H(k-2)*...*H(1)*H(0), where k = min(m,n), and each H(i) is of the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); void smp_rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); /************************************************************************* QR decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); void smp_cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); /************************************************************************* LQ decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and L in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); void smp_cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); /************************************************************************* Partial unpacking of matrix Q from the QR decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixQR subroutine. QColumns - required number of columns of matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose indexes range within [0..M-1, 0..QColumns-1]. If QColumns=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q); void smp_rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q); /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r); /************************************************************************* Partial unpacking of matrix Q from the LQ decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices L and Q in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixLQ subroutine. QRows - required number of rows in matrix Q. N>=QRows>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose indexes range within [0..QRows-1, 0..N-1]. If QRows=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q); void smp_rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q); /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l); /************************************************************************* Partial unpacking of matrix Q from QR decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixQR subroutine . QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose index ranges within [0..M-1, 0..QColumns-1]. If QColumns=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q); void smp_cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q); /************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r); /************************************************************************* Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixLQ subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixLQ subroutine . QRows - required number of rows in matrix Q. N>=QColumns>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose index ranges within [0..QRows-1, 0..N-1]. If QRows=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q); void smp_cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q); /************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of CMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l); /************************************************************************* Reduction of a rectangular matrix to bidiagonal form The algorithm reduces the rectangular matrix A to bidiagonal form by orthogonal transformations P and Q: A = Q*B*(P^T). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function because ! bidiagonal decompostion is inherently sequential in nature. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - source matrix. array[0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q, B, P in compact form (see below). TauQ - scalar factors which are used to form matrix Q. TauP - scalar factors which are used to form matrix P. The main diagonal and one of the secondary diagonals of matrix A are replaced with bidiagonal matrix B. Other elements contain elementary reflections which form MxM matrix Q and NxN matrix P, respectively. If M>=N, B is the upper bidiagonal MxN matrix and is stored in the corresponding elements of matrix A. Matrix Q is represented as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i). Matrix P is as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). If M n): m=5, n=6 (m < n): ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) ( v1 v2 v3 v4 v5 ) Here vi and ui are vectors which form H(i) and G(i), and d and e - are the diagonal and off-diagonal elements of matrix B. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/ void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup); /************************************************************************* Unpacking matrix Q which reduces a matrix to bidiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array[0..M-1, 0..QColumns-1] If QColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q); /************************************************************************* Multiplication by matrix Q which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by Q or Q'. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. Z - multiplied matrix. array[0..ZRows-1,0..ZColumns-1] ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=M, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=M, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by Q or Q'. Output parameters: Z - product of Z and Q. Array[0..ZRows-1,0..ZColumns-1] If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose); /************************************************************************* Unpacking matrix P which reduces matrix A to bidiagonal form. The subroutine returns transposed matrix P. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of ToBidiagonal subroutine. PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. Output parameters: PT - first PTRows columns of matrix P^T Array[0..PTRows-1, 0..N-1] If PTRows=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt); /************************************************************************* Multiplication by matrix P which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by P or P'. Input parameters: QP - matrices Q and P in compact form. Output of RMatrixBD subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of RMatrixBD subroutine. Z - multiplied matrix. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=N, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=N, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by P or P'. Output parameters: Z - product of Z and P. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose); /************************************************************************* Unpacking of the main and secondary diagonals of bidiagonal decomposition of matrix A. Input parameters: B - output of RMatrixBD subroutine. M - number of rows in matrix B. N - number of columns in matrix B. Output parameters: IsUpper - True, if the matrix is upper bidiagonal. otherwise IsUpper is False. D - the main diagonal. Array whose index ranges within [0..Min(M,N)-1]. E - the secondary diagonal (upper or lower, depending on the value of IsUpper). Array index ranges within [0..Min(M,N)-1], the last element is not used. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e); /************************************************************************* Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, where Q is an orthogonal matrix, H - Hessenberg matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A with elements [0..N-1, 0..N-1] N - size of matrix A. Output parameters: A - matrices Q and P in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..N-2] Matrix H is located on the main diagonal, on the lower secondary diagonal and above the main diagonal of matrix A. The elements which are used to form matrix Q are situated in array Tau and below the lower secondary diagonal of matrix A as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(n-2), where each H(i) is given by H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - is a real vector, so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau); /************************************************************************* Unpacking matrix Q which reduces matrix A to upper Hessenberg form COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Tau - scalar factors which are used to form Q. Output of RMatrixHessenberg subroutine. Output parameters: Q - matrix Q. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q); /************************************************************************* Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Output parameters: H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/ void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h); /************************************************************************* Reduction of a symmetric matrix which is given by its higher or lower triangular part to a tridiagonal matrix using orthogonal similarity transformation: Q'*A*Q=T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e); /************************************************************************* Unpacking matrix Q which reduces symmetric matrix to a tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a SMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of SMatrixTD subroutine) Tau - the result of a SMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q); /************************************************************************* Reduction of a Hermitian matrix which is given by its higher or lower triangular part to a real tridiagonal matrix using unitary similarity transformation: Q'*A*Q = T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of real symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of real symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/ void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e); /************************************************************************* Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a HMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of HMatrixTD subroutine) Tau - the result of a HMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q); /************************************************************************* Singular value decomposition of a bidiagonal matrix (extended algorithm) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm performs the singular value decomposition of a bidiagonal matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - orthogonal matrices, S - diagonal matrix with non-negative elements on the main diagonal, in descending order. The algorithm finds singular values. In addition, the algorithm can calculate matrices Q and P (more precisely, not the matrices, but their product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, matrices U and VT can be of any type, including identity. Furthermore, the algorithm can calculate Q'*C (this product is calculated more effectively than U*Q, because this calculation operates with rows instead of matrix columns). The feature of the algorithm is its ability to find all singular values including those which are arbitrarily close to 0 with relative accuracy close to machine precision. If the parameter IsFractionalAccuracyRequired is set to True, all singular values will have high relative accuracy close to machine precision. If the parameter is set to False, only the biggest singular value will have relative accuracy close to machine precision. The absolute error of other singular values is equal to the absolute error of the biggest singular value. Input parameters: D - main diagonal of matrix B. Array whose index ranges within [0..N-1]. E - superdiagonal (or subdiagonal) of matrix B. Array whose index ranges within [0..N-2]. N - size of matrix B. IsUpper - True, if the matrix is upper bidiagonal. IsFractionalAccuracyRequired - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. U - matrix to be multiplied by Q. Array whose indexes range within [0..NRU-1, 0..N-1]. The matrix can be bigger, in that case only the submatrix [0..NRU-1, 0..N-1] will be multiplied by Q. NRU - number of rows in matrix U. C - matrix to be multiplied by Q'. Array whose indexes range within [0..N-1, 0..NCC-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCC-1] will be multiplied by Q'. NCC - number of columns in matrix C. VT - matrix to be multiplied by P^T. Array whose indexes range within [0..N-1, 0..NCVT-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCVT-1] will be multiplied by P^T. NCVT - number of columns in matrix VT. Output parameters: D - singular values of matrix B in descending order. U - if NRU>0, contains matrix U*Q. VT - if NCVT>0, contains matrix (P^T)*VT. C - if NCC>0, contains matrix Q'*C. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). NOTE: multiplication U*Q is performed by means of transposition to internal buffer, multiplication and backward transposition. It helps to avoid costly columnwise operations and speed-up algorithm. Additional information: The type of convergence is controlled by the internal parameter TOL. If the parameter is greater than 0, the singular values will have relative accuracy TOL. If TOL<0, the singular values will have absolute accuracy ABS(TOL)*norm(B). By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, where Epsilon is the machine precision. It is not recommended to use TOL less than 10*Epsilon since this will considerably slow down the algorithm and may not lead to error decreasing. History: * 31 March, 2007. changed MAXITR from 6 to 12. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1999. *************************************************************************/ bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt); /************************************************************************* Singular value decomposition of a rectangular matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm calculates the singular value decomposition of a matrix of size MxN: A = U * S * V^T The algorithm finds the singular values and, optionally, matrices U and V^T. The algorithm can find both first min(M,N) columns of matrix U and rows of matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM and NxN respectively). Take into account that the subroutine does not return matrix V but V^T. Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. UNeeded - 0, 1 or 2. See the description of the parameter U. VTNeeded - 0, 1 or 2. See the description of the parameter VT. AdditionalMemory - If the parameter: * equals 0, the algorithm doesnt use additional memory (lower requirements, lower performance). * equals 1, the algorithm uses additional memory of size min(M,N)*min(M,N) of real numbers. It often speeds up the algorithm. * equals 2, the algorithm uses additional memory of size M*min(M,N) of real numbers. It allows to get a maximum performance. The recommended value of the parameter is 2. Output parameters: W - contains singular values in descending order. U - if UNeeded=0, U isn't changed, the left singular vectors are not calculated. if Uneeded=1, U contains left singular vectors (first min(M,N) columns of matrix U). Array whose indexes range within [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U contains matrix U wholly. Array whose indexes range within [0..M-1, 0..M-1]. VT - if VTNeeded=0, VT isnt changed, the right singular vectors are not calculated. if VTNeeded=1, VT contains right singular vectors (first min(M,N) rows of matrix V^T). Array whose indexes range within [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT contains matrix V^T wholly. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt); bool smp_rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt); /************************************************************************* Finding the eigenvalues and eigenvectors of a symmetric matrix The algorithm finds eigen pairs of a symmetric matrix by reducing it to tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpper - storage format. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z); /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric matrix in a given half open interval (A, B] by using a bisection and inverse iteration Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half open interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval (M>=0). W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z); /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a symmetric matrix with given indexes by using bisection and inverse iteration methods. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z); /************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/ bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z); /************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian matrix in a given half-interval (A, B] by using a bisection and inverse iteration Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half-interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval, M>=0 W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z); /************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a Hermitian matrix with given indexes by using bisection and inverse iteration methods Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z); /************************************************************************* Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by using an QL/QR algorithm with implicit shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix; * 2, the eigenvectors of a tridiagonal matrix replace the square matrix Z; * 3, matrix Z contains the first row of the eigenvectors matrix. Z - if ZNeeded=1, Z contains the square matrix by which the eigenvectors are multiplied. Array whose indexes range within [0..N-1, 0..N-1]. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the product of a given matrix (from the left) and the eigenvectors matrix (from the right); * 2, Z contains the eigenvectors. * 3, Z contains the first row of the eigenvectors matrix. If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. In that case, the eigenvectors are stored in the matrix columns. If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/ bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z); /************************************************************************* Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a given half-interval (A, B] by using bisection and inverse iteration. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix, N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. A, B - half-interval (A, B] to search eigenvalues in. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..M-1]. M - number of eigenvalues found in the given half-interval (M>=0). Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and NxM matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..M-1]. * 2, contains the matrix of the eigenvectors found. Array whose indexes range within [0..N-1, 0..M-1]. Result: True, if successful. In that case, M contains the number of eigenvalues in the given half-interval (could be equal to 0), D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 31.03.2008 by Bochkanov Sergey *************************************************************************/ bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z); /************************************************************************* Subroutine for finding tridiagonal matrix eigenvalues/vectors with given indexes (in ascending order) by using the bisection and inverse iteraion. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix. N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and Nx(I2-I1) matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..I2-I1]. * 2, contains the matrix of the eigenvalues found. Array whose indexes range within [0..N-1, 0..I2-I1]. Result: True, if successful. In that case, D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 25.12.2005 by Bochkanov Sergey *************************************************************************/ bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z); /************************************************************************* Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Speed-up provided by MKL for this particular problem (EVD) ! is really high, because MKL uses combination of (a) better low-level ! optimizations, and (b) better EVD algorithms. ! ! On one particular SSE-capable machine for N=1024, commercial MKL- ! -capable ALGLIB was: ! * 7-10 times faster than open source "generic C" version ! * 15-18 times faster than "pure C#" version ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm finds eigenvalues and eigenvectors of a general matrix by using the QR algorithm with multiple shifts. The algorithm can find eigenvalues and both left and right eigenvectors. The right eigenvector is a vector x such that A*x = w*x, and the left eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex conjugate transposition of vector y). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. VNeeded - flag controlling whether eigenvectors are needed or not. If VNeeded is equal to: * 0, eigenvectors are not returned; * 1, right eigenvectors are returned; * 2, left eigenvectors are returned; * 3, both left and right eigenvectors are returned. Output parameters: WR - real parts of eigenvalues. Array whose index ranges within [0..N-1]. WR - imaginary parts of eigenvalues. Array whose index ranges within [0..N-1]. VL, VR - arrays of left and right eigenvectors (if they are needed). If WI[i]=0, the respective eigenvalue is a real number, and it corresponds to the column number I of matrices VL/VR. If WI[i]>0, we have a pair of complex conjugate numbers with positive and negative imaginary parts: the first eigenvalue WR[i] + sqrt(-1)*WI[i]; the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; WI[i]>0 WI[i+1] = -WI[i] < 0 In that case, the eigenvector corresponding to the first eigenvalue is located in i and i+1 columns of matrices VL/VR (the column number i contains the real part, and the column number i+1 contains the imaginary part), and the vector corresponding to the second eigenvalue is a complex conjugate to the first vector. Arrays whose indexes range within [0..N-1, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm has not converged. Note 1: Some users may ask the following question: what if WI[N-1]>0? WI[N] must contain an eigenvalue which is complex conjugate to the N-th eigenvalue, but the array has only size N? The answer is as follows: such a situation cannot occur because the algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is strictly less than N-1. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms of linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. See also the InternalTREVC subroutine. The algorithm is based on the LAPACK 3.0 library. *************************************************************************/ bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr); /************************************************************************* Generation of a random uniformly distributed (Haar) orthogonal matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a); /************************************************************************* Generation of random NxN matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); /************************************************************************* Generation of a random Haar distributed orthogonal complex matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a); /************************************************************************* Generation of random NxN complex matrix with given condition number C and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); /************************************************************************* Generation of random NxN symmetric matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); /************************************************************************* Generation of random NxN symmetric positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random SPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); /************************************************************************* Generation of random NxN Hermitian matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); /************************************************************************* Generation of random NxN Hermitian positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random HPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); /************************************************************************* Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n); /************************************************************************* Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n); /************************************************************************* Multiplication of MxN complex matrix by NxN random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n); /************************************************************************* Multiplication of MxN complex matrix by MxM random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n); /************************************************************************* Symmetric multiplication of NxN matrix by random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q'*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void smatrixrndmultiply(real_2d_array &a, const ae_int_t n); /************************************************************************* Hermitian multiplication of NxN matrix by random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q^H*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/ void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n); /************************************************************************* This function creates sparse matrix in a Hash-Table format. This function creates Hast-Table matrix, which can be converted to CRS format after its initialization is over. Typical usage scenario for a sparse matrix is: 1. creation in a Hash-Table format 2. insertion of the matrix elements 3. conversion to the CRS representation 4. matrix is passed to some linear algebra algorithm Some information about different matrix formats can be found below, in the "NOTES" section. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. NOTE 1 Hash-tables use memory inefficiently, and they have to keep some amount of the "spare memory" in order to have good performance. Hash table for matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, where C is a small constant, about 1.5-2 in magnitude. CRS storage, from the other side, is more memory-efficient, and needs just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows in a matrix. When you convert from the Hash-Table to CRS representation, all unneeded memory will be freed. NOTE 2 Comments of SparseMatrix structure outline information about different sparse storage formats. We recommend you to read them before starting to use ALGLIB sparse matrices. NOTE 3 This function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s); void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s); /************************************************************************* This version of SparseCreate function creates sparse matrix in Hash-Table format, reusing previously allocated storage as much as possible. Read comments for SparseCreate() for more information. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. S - SparseMatrix structure which MAY contain some already allocated storage. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. Previously allocated storage is reused, if its size is compatible with expected number of non-zeros K. -- ALGLIB PROJECT -- Copyright 14.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const ae_int_t k, const sparsematrix &s); void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const sparsematrix &s); /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateCRSBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s); /************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This version of CRS matrix creation function may reuse memory already allocated in S. This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 S - sparse matrix structure with possibly preallocated memory. OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecreatecrsbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, const sparsematrix &s); /************************************************************************* This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], D[I]>=0. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], U[I]>=0. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseRewriteExisting() to change their values. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateSKSBuf function. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesks(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s); /************************************************************************* This is "buffered" version of SparseCreateSKS() which reuses memory previously allocated in S (of course, memory is reallocated if needed). This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], 0<=D[I]<=I. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], 0<=U[I]<=I. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseSet()/SparseAdd() to change their values. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsecreatesksbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, const sparsematrix &s); /************************************************************************* This function copies S0 to S1. This function completely deallocates memory owned by S1 before creating a copy of S0. If you want to reuse memory, use SparseCopyBuf. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopy(const sparsematrix &s0, sparsematrix &s1); /************************************************************************* This function copies S0 to S1. Memory already allocated in S1 is reused as much as possible. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsecopybuf(const sparsematrix &s0, const sparsematrix &s1); /************************************************************************* This function efficiently swaps contents of S0 and S1. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/ void sparseswap(const sparsematrix &s0, const sparsematrix &s1); /************************************************************************* This function adds value to S[i,j] - element of the sparse matrix. Matrix must be in a Hash-Table mode. In case S[i,j] already exists in the table, V i added to its value. In case S[i,j] is non-existent, it is inserted in the table. Table automatically grows when necessary. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y); /************************************************************************* This function calculates vector-matrix-vector product x'*S*x, where S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. RESULT x'*S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 27.01.2014 by Bochkanov Sergey *************************************************************************/ double sparsevsmv(const sparsematrix &s, const bool isupper, const real_1d_array &x); /************************************************************************* This function calculates matrix-matrix product S*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b); /************************************************************************* This function calculates matrix-matrix product S^T*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[M][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b); /************************************************************************* This function simultaneously calculates two matrix-matrix products: S*A and S^T*A. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. B1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B0 - array[N][K], S*A B1 - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1); /************************************************************************* This function calculates matrix-matrix product S*A, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b); /************************************************************************* This function calculates matrix-vector product op(S)*x, when x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - possibly preallocated input buffer. Automatically resized if its size is too small. OUTPUT PARAMETERS Y - array[N], op(S)*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrmv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, const real_1d_array &x, real_1d_array &y); /************************************************************************* This function solves linear system op(S)*y=x where x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used. It is your responsibility to make sure that diagonal is non-zero. OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. OUTPUT PARAMETERS X - array[N], inv(op(S))*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. NOTE: no assertion or tests are done during algorithm operation. It is your responsibility to provide invertible matrix to algorithm. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ void sparsetrsv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, const real_1d_array &x); /************************************************************************* This procedure resizes Hash-Table matrix. It can be called when you have deleted too many elements from the matrix, and you want to free unneeded memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ void sparseresizematrix(const sparsematrix &s); /************************************************************************* This function is used to enumerate all elements of the sparse matrix. Before first call user initializes T0 and T1 counters by zero. These counters are used to remember current position in a matrix; after each call they are updated by the function. Subsequent calls to this function return non-zero elements of the sparse matrix, one by one. If you enumerate CRS matrix, matrix is traversed from left to right, from top to bottom. In case you enumerate matrix stored as Hash table, elements are returned in random order. EXAMPLE > T0=0 > T1=0 > while SparseEnumerate(S,T0,T1,I,J,V) do > ....do something with I,J,V INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. T0 - internal counter T1 - internal counter OUTPUT PARAMETERS T0 - new value of the internal counter T1 - new value of the internal counter I - row index of non-zero element, 0<=I>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); void smp_rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); /************************************************************************* LU decomposition of a general complex matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/ void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); void smp_cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a Hermitian positive- definite matrix. The result of an algorithm is a representation of A as A=U'*U or A=L*L' (here X' detones conj(X^T)). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U'*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper); bool smp_hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a symmetric positive- definite matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U^T*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper); bool smp_spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateAdd1Buf(). INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u); /************************************************************************* Update of Cholesky decomposition: "fixing" some variables. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateFixBuf(). "FIXING" EXPLAINED: Suppose we have N*N positive definite matrix A. "Fixing" some variable means filling corresponding row/column of A by zeros, and setting diagonal element to 1. For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) ( A10 A11 A12 A13 ) ( 0 1 0 0 ) ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) If we have Cholesky decomposition of A, it must be recalculated after variables were fixed. However, it is possible to use efficient algorithm, which needs O(K*N^2) time to "fix" K variables, given Cholesky decomposition of original, "unfixed" A. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. NOTE: this function is efficient only for moderate amount of updated variables - say, 0.1*N or 0.3*N. For larger amount of variables it will still work, but you may get better performance with straightforward Cholesky. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefix(const real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix); /************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateAdd1() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdateadd1buf(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, real_1d_array &bufr); /************************************************************************* Update of Cholesky decomposition: "fixing" some variables. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateFix() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/ void spdmatrixcholeskyupdatefixbuf(const real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, real_1d_array &bufr); /************************************************************************* Sparse Cholesky decomposition for skyline matrixm using in-place algorithm without allocating additional storage. The algorithm computes Cholesky decomposition of a symmetric positive- definite sparse matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T This function is a more efficient alternative to general, but slower SparseCholeskyX(), because it does not create temporary copies of the target. It performs factorization in-place, which gives best performance on low-profile matrices. Its drawback, however, is that it can not perform profile-reducing permutation of input matrix. INPUT PARAMETERS: A - sparse matrix in skyline storage (SKS) format. N - size of matrix A (can be smaller than actual size of A) IsUpper - if IsUpper=True, then factorization is performed on upper triangle. Another triangle is ignored (it may contant some data, but it is not changed). OUTPUT PARAMETERS: A - the result of factorization, stored in SKS. If IsUpper=True, then the upper triangle contains matrix U, such that A = U^T*U. Lower triangle is not changed. Similarly, if IsUpper = False. In this case L is returned, and we have A = L*(L^T). Note that THIS function does not perform permutation of rows to reduce bandwidth. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. NOTE: for performance reasons this function does NOT check that input matrix includes only finite values. It is your responsibility to make sure that there are no infinite or NAN values in the matrix. -- ALGLIB routine -- 16.01.2014 Bochkanov Sergey *************************************************************************/ bool sparsecholeskyskyline(const sparsematrix &a, const ae_int_t n, const bool isupper); /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcond1(const real_2d_array &a, const ae_int_t n); /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n); /************************************************************************* Condition number estimate of a symmetric positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - symmetric positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); /************************************************************************* Condition number estimate of a Hermitian positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - Hermitian positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n); /************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n); /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n); /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n); /************************************************************************* Condition number estimate of a symmetric positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Condition number estimate of a Hermitian positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper); /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n); /************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n); /************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); /************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations (the output of RMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. it is filled by zeros in such cases. * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - solver report, see below for more info A - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. SOLVER REPORT Subroutine sets following fields of the Rep structure: * R1 reciprocal of condition number: 1/cond(A), 1-norm. * RInf reciprocal of condition number: 1/cond(A), inf-norm. -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); void smp_rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); void smp_rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse Result: True, if the matrix is not singular. False, if the matrix is singular. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/ void rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); void smp_rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); void rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of CMatrixLU subroutine). Pivots - table of permutations (the output of CMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/ void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); void smp_cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); void smp_cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); void smp_cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); void cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a symmetric positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of SPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a symmetric positive definite matrix. Given an upper or lower triangle of a symmetric positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a Hermitian positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of HPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Inversion of a Hermitian positive definite matrix. Given an upper or lower triangle of a Hermitian positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/ void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); void hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); void smp_hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); /************************************************************************* Triangular matrix inverse (real) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); void smp_rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); void rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); /************************************************************************* Triangular matrix inverse (complex) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); void smp_cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); void cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); void smp_cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); /************************************************************************* This procedure initializes matrix norm estimator. USAGE: 1. User initializes algorithm state with NormEstimatorCreate() call 2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) 3. User calls NormEstimatorResults() to get solution. INPUT PARAMETERS: M - number of rows in the matrix being estimated, M>0 N - number of columns in the matrix being estimated, N>0 NStart - number of random starting vectors recommended value - at least 5. NIts - number of iterations to do with best starting vector recommended value - at least 5. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: this algorithm is effectively deterministic, i.e. it always returns same result when repeatedly called for the same matrix. In fact, algorithm uses randomized starting vectors, but internal random numbers generator always generates same sequence of the random values (it is a feature, not bug). Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state); /************************************************************************* This function changes seed value used by algorithm. In some cases we need deterministic processing, i.e. subsequent calls must return equal results, in other cases we need non-deterministic algorithm which returns different results for the same matrix on every pass. Setting zero seed will lead to non-deterministic algorithm, while non-zero value will make our algorithm deterministic. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() SeedVal - seed value, >=0. Zero value = non-deterministic algo. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorsetseed(const normestimatorstate &state, const ae_int_t seedval); /************************************************************************* This function estimates norm of the sparse M*N matrix A. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() A - sparse M*N matrix, must be converted to CRS format prior to calling this function. After this function is over you can call NormEstimatorResults() to get estimate of the norm(A). -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorestimatesparse(const normestimatorstate &state, const sparsematrix &a); /************************************************************************* Matrix norm estimation results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Nrm - estimate of the matrix norm, Nrm>=0 -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/ void normestimatorresults(const normestimatorstate &state, double &nrm); /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n); double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots); /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ double rmatrixdet(const real_2d_array &a, const ae_int_t n); double rmatrixdet(const real_2d_array &a); /************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n); alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots); /************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n); alglib::complex cmatrixdet(const complex_2d_array &a); /************************************************************************* Determinant calculation of the matrix given by the Cholesky decomposition. Input parameters: A - Cholesky decomposition, output of SMatrixCholesky subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) As the determinant is equal to the product of squares of diagonal elements, its not necessary to specify which triangle - lower or upper - the matrix is stored in. Result: matrix determinant. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n); double spdmatrixcholeskydet(const real_2d_array &a); /************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Result: determinant of matrix A. If matrix A is not positive definite, exception is thrown. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/ double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper); double spdmatrixdet(const real_2d_array &a); /************************************************************************* Algorithm for solving the following generalized symmetric positive-definite eigenproblem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3). where A is a symmetric matrix, B - symmetric positive-definite matrix. The problem is solved by reducing it to an ordinary symmetric eigenvalue problem. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ZNeeded - if ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in matrix columns. It should be noted that the eigenvectors in such problems do not form an orthogonal system. Result: True, if the problem was solved successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix isnt positive-definite) or during the work of the iterative algorithm for solving the symmetric eigenproblem. See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z); /************************************************************************* Algorithm for reduction of the following generalized symmetric positive- definite eigenvalue problem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3) to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and the given problems are the same, and the eigenvectors of the given problem could be obtained by multiplying the obtained eigenvectors by the transformation matrix x = R*y). Here A is a symmetric matrix, B - symmetric positive-definite matrix. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: A - symmetric matrix which is given by its upper or lower triangle depending on IsUpperA. Contains matrix C. Array whose indexes range within [0..N-1, 0..N-1]. R - upper triangular or low triangular transformation matrix which is used to obtain the eigenvectors of a given problem as the product of eigenvectors of C (from the right) and matrix R (from the left). If the matrix is upper triangular, the elements below the main diagonal are equal to 0 (and vice versa). Thus, we can perform the multiplication without taking into account the internal structure (which is an easier though less effective way). Array whose indexes range within [0..N-1, 0..N-1]. IsUpperR - type of matrix R (upper or lower triangular). Result: True, if the problem was reduced successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix is not positive-definite). -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/ bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr); /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a number to an element of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - row where the element to be updated is stored. UpdColumn - column where the element to be updated is stored. UpdVal - a number to be added to the element. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval); /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a row of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - the row of A whose vector V was added. 0 <= Row <= N-1 V - the vector to be added to a row. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v); /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a column of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdColumn - the column of A whose vector U was added. 0 <= UpdColumn <= N-1 U - the vector to be added to a column. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u); /************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm computes the inverse of matrix A+u*v by using the given matrix A^-1 and the vectors u and v. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. U - the vector modifying the matrix. Array whose index ranges within [0..N-1]. V - the vector modifying the matrix. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of matrix A + u*v'. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v); /************************************************************************* Subroutine performing the Schur decomposition of a general matrix by using the QR algorithm with multiple shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The source matrix A is represented as S'*A*S = T, where S is an orthogonal matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..N-1, 0..N-1]. N - size of A, N>=0. Output parameters: A - contains matrix T. Array whose indexes range within [0..N-1, 0..N-1]. S - contains Schur vectors. Array whose indexes range within [0..N-1, 0..N-1]. Note 1: The block structure of matrix T can be easily recognized: since all the elements below the blocks are zeros, the elements a[i+1,i] which are equal to 0 show the block border. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms in linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. Result: True, if the algorithm has converged and parameters A and S contain the result. False, if the algorithm has not converged. Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). *************************************************************************/ bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void ablassplitlength(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t* n1, ae_int_t* n2, ae_state *_state); void ablascomplexsplitlength(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t* n1, ae_int_t* n2, ae_state *_state); ae_int_t ablasblocksize(/* Real */ ae_matrix* a, ae_state *_state); ae_int_t ablascomplexblocksize(/* Complex */ ae_matrix* a, ae_state *_state); ae_int_t ablasmicroblocksize(ae_state *_state); void cmatrixtranspose(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state); void rmatrixtranspose(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state); void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); void cmatrixcopy(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state); void rmatrixcopy(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_state *_state); void cmatrixrank1(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Complex */ ae_vector* u, ae_int_t iu, /* Complex */ ae_vector* v, ae_int_t iv, ae_state *_state); void rmatrixrank1(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, /* Real */ ae_vector* u, ae_int_t iu, /* Real */ ae_vector* v, ae_int_t iv, ae_state *_state); void cmatrixmv(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Complex */ ae_vector* x, ae_int_t ix, /* Complex */ ae_vector* y, ae_int_t iy, ae_state *_state); void rmatrixmv(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t opa, /* Real */ ae_vector* x, ae_int_t ix, /* Real */ ae_vector* y, ae_int_t iy, ae_state *_state); void cmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void _pexec_cmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void cmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void _pexec_cmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void rmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void _pexec_rmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void rmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void _pexec_rmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state); void cmatrixherk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void _pexec_cmatrixherk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void rmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void _pexec_rmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void cmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void _pexec_cmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void rmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void _pexec_rmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state); void cmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void _pexec_cmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state); void rmatrixqr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); void _pexec_rmatrixqr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); void rmatrixlq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); void _pexec_rmatrixlq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); void cmatrixqr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state); void _pexec_cmatrixqr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state); void cmatrixlq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state); void _pexec_cmatrixlq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_state *_state); void rmatrixqrunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state); void _pexec_rmatrixqrunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state); void rmatrixqrunpackr(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* r, ae_state *_state); void rmatrixlqunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qrows, /* Real */ ae_matrix* q, ae_state *_state); void _pexec_rmatrixlqunpackq(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tau, ae_int_t qrows, /* Real */ ae_matrix* q, ae_state *_state); void rmatrixlqunpackl(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* l, ae_state *_state); void cmatrixqrunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qcolumns, /* Complex */ ae_matrix* q, ae_state *_state); void _pexec_cmatrixqrunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qcolumns, /* Complex */ ae_matrix* q, ae_state *_state); void cmatrixqrunpackr(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* r, ae_state *_state); void cmatrixlqunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qrows, /* Complex */ ae_matrix* q, ae_state *_state); void _pexec_cmatrixlqunpackq(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_vector* tau, ae_int_t qrows, /* Complex */ ae_matrix* q, ae_state *_state); void cmatrixlqunpackl(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* l, ae_state *_state); void rmatrixqrbasecase(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* work, /* Real */ ae_vector* t, /* Real */ ae_vector* tau, ae_state *_state); void rmatrixlqbasecase(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* work, /* Real */ ae_vector* t, /* Real */ ae_vector* tau, ae_state *_state); void rmatrixbd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_vector* taup, ae_state *_state); void rmatrixbdunpackq(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, ae_int_t qcolumns, /* Real */ ae_matrix* q, ae_state *_state); void rmatrixbdmultiplybyq(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tauq, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state); void rmatrixbdunpackpt(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* taup, ae_int_t ptrows, /* Real */ ae_matrix* pt, ae_state *_state); void rmatrixbdmultiplybyp(/* Real */ ae_matrix* qp, ae_int_t m, ae_int_t n, /* Real */ ae_vector* taup, /* Real */ ae_matrix* z, ae_int_t zrows, ae_int_t zcolumns, ae_bool fromtheright, ae_bool dotranspose, ae_state *_state); void rmatrixbdunpackdiagonals(/* Real */ ae_matrix* b, ae_int_t m, ae_int_t n, ae_bool* isupper, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state); void rmatrixhessenberg(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, ae_state *_state); void rmatrixhessenbergunpackq(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state); void rmatrixhessenbergunpackh(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* h, ae_state *_state); void smatrixtd(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state); void smatrixtdunpackq(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tau, /* Real */ ae_matrix* q, ae_state *_state); void hmatrixtd(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_state *_state); void hmatrixtdunpackq(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* tau, /* Complex */ ae_matrix* q, ae_state *_state); ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_state *_state); ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, ae_bool isfractionalaccuracyrequired, /* Real */ ae_matrix* u, ae_int_t nru, /* Real */ ae_matrix* c, ae_int_t ncc, /* Real */ ae_matrix* vt, ae_int_t ncvt, ae_state *_state); ae_bool rmatrixsvd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, /* Real */ ae_vector* w, /* Real */ ae_matrix* u, /* Real */ ae_matrix* vt, ae_state *_state); ae_bool _pexec_rmatrixsvd(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, /* Real */ ae_vector* w, /* Real */ ae_matrix* u, /* Real */ ae_matrix* vt, ae_state *_state); ae_bool smatrixevd(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, /* Real */ ae_vector* d, /* Real */ ae_matrix* z, ae_state *_state); ae_bool smatrixevdr(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, double b1, double b2, ae_int_t* m, /* Real */ ae_vector* w, /* Real */ ae_matrix* z, ae_state *_state); ae_bool smatrixevdi(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* w, /* Real */ ae_matrix* z, ae_state *_state); ae_bool hmatrixevd(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, /* Real */ ae_vector* d, /* Complex */ ae_matrix* z, ae_state *_state); ae_bool hmatrixevdr(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, double b1, double b2, ae_int_t* m, /* Real */ ae_vector* w, /* Complex */ ae_matrix* z, ae_state *_state); ae_bool hmatrixevdi(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t zneeded, ae_bool isupper, ae_int_t i1, ae_int_t i2, /* Real */ ae_vector* w, /* Complex */ ae_matrix* z, ae_state *_state); ae_bool smatrixtdevd(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, /* Real */ ae_matrix* z, ae_state *_state); ae_bool smatrixtdevdr(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, double a, double b, ae_int_t* m, /* Real */ ae_matrix* z, ae_state *_state); ae_bool smatrixtdevdi(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_int_t zneeded, ae_int_t i1, ae_int_t i2, /* Real */ ae_matrix* z, ae_state *_state); ae_bool rmatrixevd(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t vneeded, /* Real */ ae_vector* wr, /* Real */ ae_vector* wi, /* Real */ ae_matrix* vl, /* Real */ ae_matrix* vr, ae_state *_state); void rmatrixrndorthogonal(ae_int_t n, /* Real */ ae_matrix* a, ae_state *_state); void rmatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state); void cmatrixrndorthogonal(ae_int_t n, /* Complex */ ae_matrix* a, ae_state *_state); void cmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state); void smatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state); void spdmatrixrndcond(ae_int_t n, double c, /* Real */ ae_matrix* a, ae_state *_state); void hmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state); void hpdmatrixrndcond(ae_int_t n, double c, /* Complex */ ae_matrix* a, ae_state *_state); void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state); void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state); void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state); void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, ae_state *_state); void smatrixrndmultiply(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); void hmatrixrndmultiply(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); void sparsecreate(ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix* s, ae_state *_state); void sparsecreatebuf(ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix* s, ae_state *_state); void sparsecreatecrs(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* ner, sparsematrix* s, ae_state *_state); void sparsecreatecrsbuf(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* ner, sparsematrix* s, ae_state *_state); void sparsecreatesks(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* d, /* Integer */ ae_vector* u, sparsematrix* s, ae_state *_state); void sparsecreatesksbuf(ae_int_t m, ae_int_t n, /* Integer */ ae_vector* d, /* Integer */ ae_vector* u, sparsematrix* s, ae_state *_state); void sparsecopy(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparsecopybuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparseswap(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparseadd(sparsematrix* s, ae_int_t i, ae_int_t j, double v, ae_state *_state); void sparseset(sparsematrix* s, ae_int_t i, ae_int_t j, double v, ae_state *_state); double sparseget(sparsematrix* s, ae_int_t i, ae_int_t j, ae_state *_state); double sparsegetdiagonal(sparsematrix* s, ae_int_t i, ae_state *_state); void sparsemv(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void sparsemtv(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void sparsemv2(sparsematrix* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y0, /* Real */ ae_vector* y1, ae_state *_state); void sparsesmv(sparsematrix* s, ae_bool isupper, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); double sparsevsmv(sparsematrix* s, ae_bool isupper, /* Real */ ae_vector* x, ae_state *_state); void sparsemm(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state); void sparsemtm(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state); void sparsemm2(sparsematrix* s, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b0, /* Real */ ae_matrix* b1, ae_state *_state); void sparsesmm(sparsematrix* s, ae_bool isupper, /* Real */ ae_matrix* a, ae_int_t k, /* Real */ ae_matrix* b, ae_state *_state); void sparsetrmv(sparsematrix* s, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void sparsetrsv(sparsematrix* s, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_vector* x, ae_state *_state); void sparseresizematrix(sparsematrix* s, ae_state *_state); double sparsegetaveragelengthofchain(sparsematrix* s, ae_state *_state); ae_bool sparseenumerate(sparsematrix* s, ae_int_t* t0, ae_int_t* t1, ae_int_t* i, ae_int_t* j, double* v, ae_state *_state); ae_bool sparserewriteexisting(sparsematrix* s, ae_int_t i, ae_int_t j, double v, ae_state *_state); void sparsegetrow(sparsematrix* s, ae_int_t i, /* Real */ ae_vector* irow, ae_state *_state); void sparsegetcompressedrow(sparsematrix* s, ae_int_t i, /* Integer */ ae_vector* colidx, /* Real */ ae_vector* vals, ae_int_t* nzcnt, ae_state *_state); void sparsetransposesks(sparsematrix* s, ae_state *_state); void sparseconvertto(sparsematrix* s0, ae_int_t fmt, ae_state *_state); void sparsecopytobuf(sparsematrix* s0, ae_int_t fmt, sparsematrix* s1, ae_state *_state); void sparseconverttohash(sparsematrix* s, ae_state *_state); void sparsecopytohash(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparsecopytohashbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparseconverttocrs(sparsematrix* s, ae_state *_state); void sparsecopytocrs(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparsecopytocrsbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparseconverttosks(sparsematrix* s, ae_state *_state); void sparsecopytosks(sparsematrix* s0, sparsematrix* s1, ae_state *_state); void sparsecopytosksbuf(sparsematrix* s0, sparsematrix* s1, ae_state *_state); ae_int_t sparsegetmatrixtype(sparsematrix* s, ae_state *_state); ae_bool sparseishash(sparsematrix* s, ae_state *_state); ae_bool sparseiscrs(sparsematrix* s, ae_state *_state); ae_bool sparseissks(sparsematrix* s, ae_state *_state); void sparsefree(sparsematrix* s, ae_state *_state); ae_int_t sparsegetnrows(sparsematrix* s, ae_state *_state); ae_int_t sparsegetncols(sparsematrix* s, ae_state *_state); ae_int_t sparsegetuppercount(sparsematrix* s, ae_state *_state); ae_int_t sparsegetlowercount(sparsematrix* s, ae_state *_state); void _sparsematrix_init(void* _p, ae_state *_state); void _sparsematrix_init_copy(void* _dst, void* _src, ae_state *_state); void _sparsematrix_clear(void* _p); void _sparsematrix_destroy(void* _p); void _sparsebuffers_init(void* _p, ae_state *_state); void _sparsebuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _sparsebuffers_clear(void* _p); void _sparsebuffers_destroy(void* _p); void rmatrixlu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void _pexec_rmatrixlu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void cmatrixlu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void _pexec_cmatrixlu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); ae_bool hpdmatrixcholesky(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool _pexec_hpdmatrixcholesky(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool spdmatrixcholesky(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool _pexec_spdmatrixcholesky(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); void spdmatrixcholeskyupdateadd1(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* u, ae_state *_state); void spdmatrixcholeskyupdatefix(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Boolean */ ae_vector* fix, ae_state *_state); void spdmatrixcholeskyupdateadd1buf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* u, /* Real */ ae_vector* bufr, ae_state *_state); void spdmatrixcholeskyupdatefixbuf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Boolean */ ae_vector* fix, /* Real */ ae_vector* bufr, ae_state *_state); ae_bool sparsecholeskyskyline(sparsematrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool sparsecholeskyx(sparsematrix* a, ae_int_t n, ae_bool isupper, /* Integer */ ae_vector* p0, /* Integer */ ae_vector* p1, ae_int_t ordering, ae_int_t algo, ae_int_t fmt, sparsebuffers* buf, sparsematrix* c, ae_state *_state); void rmatrixlup(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void cmatrixlup(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void rmatrixplu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); void cmatrixplu(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state); ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state); double rmatrixrcond1(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); double rmatrixrcondinf(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); double spdmatrixrcond(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); double rmatrixtrrcond1(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state); double rmatrixtrrcondinf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state); double hpdmatrixrcond(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); double cmatrixrcond1(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); double cmatrixrcondinf(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); double rmatrixlurcond1(/* Real */ ae_matrix* lua, ae_int_t n, ae_state *_state); double rmatrixlurcondinf(/* Real */ ae_matrix* lua, ae_int_t n, ae_state *_state); double spdmatrixcholeskyrcond(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); double hpdmatrixcholeskyrcond(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); double cmatrixlurcond1(/* Complex */ ae_matrix* lua, ae_int_t n, ae_state *_state); double cmatrixlurcondinf(/* Complex */ ae_matrix* lua, ae_int_t n, ae_state *_state); double cmatrixtrrcond1(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state); double cmatrixtrrcondinf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_state *_state); double rcondthreshold(ae_state *_state); void rmatrixluinverse(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_rmatrixluinverse(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void rmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_rmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void cmatrixluinverse(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_cmatrixluinverse(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void cmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_cmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_int_t* info, matinvreport* rep, ae_state *_state); void spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void spdmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_spdmatrixinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void hpdmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_hpdmatrixinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_int_t* info, matinvreport* rep, ae_state *_state); void rmatrixtrinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_rmatrixtrinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state); void cmatrixtrinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state); void _pexec_cmatrixtrinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunit, ae_int_t* info, matinvreport* rep, ae_state *_state); void spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, ae_int_t offs, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* tmp, ae_state *_state); void _matinvreport_init(void* _p, ae_state *_state); void _matinvreport_init_copy(void* _dst, void* _src, ae_state *_state); void _matinvreport_clear(void* _p); void _matinvreport_destroy(void* _p); void fblscholeskysolve(/* Real */ ae_matrix* cha, double sqrtscalea, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* xb, /* Real */ ae_vector* tmp, ae_state *_state); void fblssolvecgx(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double alpha, /* Real */ ae_vector* b, /* Real */ ae_vector* x, /* Real */ ae_vector* buf, ae_state *_state); void fblscgcreate(/* Real */ ae_vector* x, /* Real */ ae_vector* b, ae_int_t n, fblslincgstate* state, ae_state *_state); ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state); void fblssolvels(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t m, ae_int_t n, /* Real */ ae_vector* tmp0, /* Real */ ae_vector* tmp1, /* Real */ ae_vector* tmp2, ae_state *_state); void _fblslincgstate_init(void* _p, ae_state *_state); void _fblslincgstate_init_copy(void* _dst, void* _src, ae_state *_state); void _fblslincgstate_clear(void* _p); void _fblslincgstate_destroy(void* _p); void normestimatorcreate(ae_int_t m, ae_int_t n, ae_int_t nstart, ae_int_t nits, normestimatorstate* state, ae_state *_state); void normestimatorsetseed(normestimatorstate* state, ae_int_t seedval, ae_state *_state); ae_bool normestimatoriteration(normestimatorstate* state, ae_state *_state); void normestimatorestimatesparse(normestimatorstate* state, sparsematrix* a, ae_state *_state); void normestimatorresults(normestimatorstate* state, double* nrm, ae_state *_state); void normestimatorrestart(normestimatorstate* state, ae_state *_state); void _normestimatorstate_init(void* _p, ae_state *_state); void _normestimatorstate_init_copy(void* _dst, void* _src, ae_state *_state); void _normestimatorstate_clear(void* _p); void _normestimatorstate_destroy(void* _p); double rmatrixludet(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state); double rmatrixdet(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); ae_complex cmatrixludet(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state); ae_complex cmatrixdet(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); double spdmatrixcholeskydet(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); double spdmatrixdet(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); ae_bool smatrixgevd(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isuppera, /* Real */ ae_matrix* b, ae_bool isupperb, ae_int_t zneeded, ae_int_t problemtype, /* Real */ ae_vector* d, /* Real */ ae_matrix* z, ae_state *_state); ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isuppera, /* Real */ ae_matrix* b, ae_bool isupperb, ae_int_t problemtype, /* Real */ ae_matrix* r, ae_bool* isupperr, ae_state *_state); void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updrow, ae_int_t updcolumn, double updval, ae_state *_state); void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updrow, /* Real */ ae_vector* v, ae_state *_state); void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, ae_int_t n, ae_int_t updcolumn, /* Real */ ae_vector* u, ae_state *_state); void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, ae_int_t n, /* Real */ ae_vector* u, /* Real */ ae_vector* v, ae_state *_state); ae_bool rmatrixschur(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* s, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/integration.h000755 001750 000144 00000076243 13015033052 023216 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _integration_pkg_h #define _integration_pkg_h #include "ap.h" #include "alglibinternal.h" #include "linalg.h" #include "specialfunctions.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_int_t terminationtype; ae_int_t nfev; ae_int_t nintervals; } autogkreport; typedef struct { double a; double b; double eps; double xwidth; double x; double f; ae_int_t info; double r; ae_matrix heap; ae_int_t heapsize; ae_int_t heapwidth; ae_int_t heapused; double sumerr; double sumabs; ae_vector qn; ae_vector wg; ae_vector wk; ae_vector wr; ae_int_t n; rcommstate rstate; } autogkinternalstate; typedef struct { double a; double b; double alpha; double beta; double xwidth; double x; double xminusa; double bminusx; ae_bool needf; double f; ae_int_t wrappermode; autogkinternalstate internalstate; rcommstate rstate; double v; ae_int_t terminationtype; ae_int_t nfev; ae_int_t nintervals; } autogkstate; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Integration report: * TerminationType = completetion code: * -5 non-convergence of Gauss-Kronrod nodes calculation subroutine. * -1 incorrect parameters were specified * 1 OK * Rep.NFEV countains number of function calculations * Rep.NIntervals contains number of intervals [a,b] was partitioned into. *************************************************************************/ class _autogkreport_owner { public: _autogkreport_owner(); _autogkreport_owner(const _autogkreport_owner &rhs); _autogkreport_owner& operator=(const _autogkreport_owner &rhs); virtual ~_autogkreport_owner(); alglib_impl::autogkreport* c_ptr(); alglib_impl::autogkreport* c_ptr() const; protected: alglib_impl::autogkreport *p_struct; }; class autogkreport : public _autogkreport_owner { public: autogkreport(); autogkreport(const autogkreport &rhs); autogkreport& operator=(const autogkreport &rhs); virtual ~autogkreport(); ae_int_t &terminationtype; ae_int_t &nfev; ae_int_t &nintervals; }; /************************************************************************* This structure stores state of the integration algorithm. Although this class has public fields, they are not intended for external use. You should use ALGLIB functions to work with this class: * autogksmooth()/AutoGKSmoothW()/... to create objects * autogkintegrate() to begin integration * autogkresults() to get results *************************************************************************/ class _autogkstate_owner { public: _autogkstate_owner(); _autogkstate_owner(const _autogkstate_owner &rhs); _autogkstate_owner& operator=(const _autogkstate_owner &rhs); virtual ~_autogkstate_owner(); alglib_impl::autogkstate* c_ptr(); alglib_impl::autogkstate* c_ptr() const; protected: alglib_impl::autogkstate *p_struct; }; class autogkstate : public _autogkstate_owner { public: autogkstate(); autogkstate(const autogkstate &rhs); autogkstate& operator=(const autogkstate &rhs); virtual ~autogkstate(); ae_bool &needf; double &x; double &xminusa; double &bminusx; double &f; }; /************************************************************************* Computation of nodes and weights for a Gauss quadrature formula The algorithm generates the N-point Gauss quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-1], alpha coefficients Beta array[0..N-1], beta coefficients Zero-indexed element is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the quadrature formula, N>=1 OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Computation of nodes and weights for a Gauss-Lobatto quadrature formula The algorithm generates the N-point Gauss-Lobatto quadrature formula with weight function given by coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients Beta array[0..N-2], beta coefficients. Zero-indexed element is not used, may be arbitrary. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. B right boundary of the integration interval. N number of nodes of the quadrature formula, N>=3 (including the left and right boundary nodes). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Computation of nodes and weights for a Gauss-Radau quadrature formula The algorithm generates the N-point Gauss-Radau quadrature formula with weight function given by the coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients. Beta array[0..N-1], beta coefficients Zero-indexed element is not used. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. N number of nodes of the quadrature formula, N>=2 (including the left boundary node). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N nodes. INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha/Beta was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with weight function W(x)=Power(x,Alpha)*Exp(-x) INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha is too close to -1 to obtain weights/nodes with high enough accuracy or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with weight function W(x)=Exp(-x*x) INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. May be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); /************************************************************************* Computation of nodes and weights of a Gauss-Kronrod quadrature formula The algorithm generates the N-point Gauss-Kronrod quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zero moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha alpha coefficients, array[0..floor(3*K/2)]. Beta beta coefficients, array[0..ceil(3*K/2)]. Beta[0] is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the Gauss-Kronrod quadrature formula, N >= 3, N = 2*K+1. OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 N is too large, task may be ill conditioned - x[i]=x[i+1] found. * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 08.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre quadrature with N points. GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is used depending on machine precision and number of nodes. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK * +2 OK, but quadrature rule have exterior nodes, x[0]<-1 or x[n-1]>+1 X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. Reduction to tridiagonal eigenproblem is used. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using pre-calculated table. Nodes/weights were computed with accuracy up to 1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision accuracy reduces to something about 2.0E-16 (depending on your compiler's handling of long floating point constants). INPUT PARAMETERS: N - number of Kronrod nodes. N can be 15, 21, 31, 41, 51, 61. OUTPUT PARAMETERS: X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps); /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. Algorithm works well only with smooth integrands. It may be used with continuous non-smooth integrands, but with less performance. It should never be used with integrands which have integrable singularities at lower or upper limits - algorithm may crash. Use AutoGKSingular in such cases. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmooth(const double a, const double b, autogkstate &state); /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. This subroutine is same as AutoGKSmooth(), but it guarantees that interval [a,b] is partitioned into subintervals which have width at most XWidth. Subroutine can be used when integrating nearly-constant function with narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth subroutine can overlook them. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state); /************************************************************************* Integration on a finite interval [A,B]. Integrand have integrable singularities at A/B. F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates from below can be used (but these estimates should be greater than -1 too). One of alpha/beta variables (or even both alpha/beta) may be equal to 0, which means than function F(x) is non-singular at A/B. Anyway (singular at bounds or not), function F(x) is supposed to be continuous on (A,B). Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. INPUT PARAMETERS: A, B - interval boundaries (AB) Alpha - power-law coefficient of the F(x) at A, Alpha>-1 Beta - power-law coefficient of the F(x) at B, Beta>-1 OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSmoothW, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool autogkiteration(const autogkstate &state); /************************************************************************* This function is used to launcn iterations of the 1-dimensional integrator It accepts following parameters: func - callback which calculates f(x) for given x ptr - optional pointer which is passed to func; can be NULL -- ALGLIB -- Copyright 07.05.2009 by Bochkanov Sergey *************************************************************************/ void autogkintegrate(autogkstate &state, void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), void *ptr = NULL); /************************************************************************* Adaptive integration results Called after AutoGKIteration returned False. Input parameters: State - algorithm state (used by AutoGKIteration). Output parameters: V - integral(f(x)dx,a,b) Rep - optimization report (see AutoGKReport description) -- ALGLIB -- Copyright 14.11.2007 by Bochkanov Sergey *************************************************************************/ void autogkresults(const autogkstate &state, double &v, autogkreport &rep); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void gqgeneraterec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategausslobattorec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, double a, double b, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategaussradaurec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, double a, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategausslegendre(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategaussjacobi(ae_int_t n, double alpha, double beta, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategausslaguerre(ae_int_t n, double alpha, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gqgenerategausshermite(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); void gkqgeneraterec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state); void gkqgenerategausslegendre(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state); void gkqgenerategaussjacobi(ae_int_t n, double alpha, double beta, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state); void gkqlegendrecalc(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state); void gkqlegendretbl(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, double* eps, ae_state *_state); void autogksmooth(double a, double b, autogkstate* state, ae_state *_state); void autogksmoothw(double a, double b, double xwidth, autogkstate* state, ae_state *_state); void autogksingular(double a, double b, double alpha, double beta, autogkstate* state, ae_state *_state); ae_bool autogkiteration(autogkstate* state, ae_state *_state); void autogkresults(autogkstate* state, double* v, autogkreport* rep, ae_state *_state); void _autogkreport_init(void* _p, ae_state *_state); void _autogkreport_init_copy(void* _dst, void* _src, ae_state *_state); void _autogkreport_clear(void* _p); void _autogkreport_destroy(void* _p); void _autogkinternalstate_init(void* _p, ae_state *_state); void _autogkinternalstate_init_copy(void* _dst, void* _src, ae_state *_state); void _autogkinternalstate_clear(void* _p); void _autogkinternalstate_destroy(void* _p); void _autogkstate_init(void* _p, ae_state *_state); void _autogkstate_init_copy(void* _dst, void* _src, ae_state *_state); void _autogkstate_clear(void* _p); void _autogkstate_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/alglibmisc.h000755 001750 000144 00000141307 13015033052 022773 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _alglibmisc_pkg_h #define _alglibmisc_pkg_h #include "ap.h" #include "alglibinternal.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_int_t s1; ae_int_t s2; ae_int_t magicv; } hqrndstate; typedef struct { ae_int_t n; ae_int_t nx; ae_int_t ny; ae_int_t normtype; ae_matrix xy; ae_vector tags; ae_vector boxmin; ae_vector boxmax; ae_vector nodes; ae_vector splits; ae_vector x; ae_int_t kneeded; double rneeded; ae_bool selfmatch; double approxf; ae_int_t kcur; ae_vector idx; ae_vector r; ae_vector buf; ae_vector curboxmin; ae_vector curboxmax; double curdist; ae_int_t debugcounter; } kdtree; typedef struct { ae_int_t i; ae_complex c; ae_vector a; } xdebugrecord1; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Portable high quality random number generator state. Initialized with HQRNDRandomize() or HQRNDSeed(). Fields: S1, S2 - seed values V - precomputed value MagicV - 'magic' value used to determine whether State structure was correctly initialized. *************************************************************************/ class _hqrndstate_owner { public: _hqrndstate_owner(); _hqrndstate_owner(const _hqrndstate_owner &rhs); _hqrndstate_owner& operator=(const _hqrndstate_owner &rhs); virtual ~_hqrndstate_owner(); alglib_impl::hqrndstate* c_ptr(); alglib_impl::hqrndstate* c_ptr() const; protected: alglib_impl::hqrndstate *p_struct; }; class hqrndstate : public _hqrndstate_owner { public: hqrndstate(); hqrndstate(const hqrndstate &rhs); hqrndstate& operator=(const hqrndstate &rhs); virtual ~hqrndstate(); }; /************************************************************************* *************************************************************************/ class _kdtree_owner { public: _kdtree_owner(); _kdtree_owner(const _kdtree_owner &rhs); _kdtree_owner& operator=(const _kdtree_owner &rhs); virtual ~_kdtree_owner(); alglib_impl::kdtree* c_ptr(); alglib_impl::kdtree* c_ptr() const; protected: alglib_impl::kdtree *p_struct; }; class kdtree : public _kdtree_owner { public: kdtree(); kdtree(const kdtree &rhs); kdtree& operator=(const kdtree &rhs); virtual ~kdtree(); }; /************************************************************************* *************************************************************************/ class _xdebugrecord1_owner { public: _xdebugrecord1_owner(); _xdebugrecord1_owner(const _xdebugrecord1_owner &rhs); _xdebugrecord1_owner& operator=(const _xdebugrecord1_owner &rhs); virtual ~_xdebugrecord1_owner(); alglib_impl::xdebugrecord1* c_ptr(); alglib_impl::xdebugrecord1* c_ptr() const; protected: alglib_impl::xdebugrecord1 *p_struct; }; class xdebugrecord1 : public _xdebugrecord1_owner { public: xdebugrecord1(); xdebugrecord1(const xdebugrecord1 &rhs); xdebugrecord1& operator=(const xdebugrecord1 &rhs); virtual ~xdebugrecord1(); ae_int_t &i; alglib::complex &c; real_1d_array a; }; /************************************************************************* HQRNDState initialization with random values which come from standard RNG. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndrandomize(hqrndstate &state); /************************************************************************* HQRNDState initialization with seed values -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state); /************************************************************************* This function generates random real number in (0,1), not including interval boundaries State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrnduniformr(const hqrndstate &state); /************************************************************************* This function generates random integer number in [0, N) 1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() 2. N can be any positive number except for very large numbers: * close to 2^31 on 32-bit systems * close to 2^62 on 64-bit systems An exception will be generated if N is too large. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_int_t hqrnduniformi(const hqrndstate &state, const ae_int_t n); /************************************************************************* Random number generator: normal numbers This function generates one random number from normal distribution. Its performance is equal to that of HQRNDNormal2() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrndnormal(const hqrndstate &state); /************************************************************************* Random number generator: random X and Y such that X^2+Y^2=1 State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndunit2(const hqrndstate &state, double &x, double &y); /************************************************************************* Random number generator: normal numbers This function generates two independent random numbers from normal distribution. Its performance is equal to that of HQRNDNormal() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndnormal2(const hqrndstate &state, double &x1, double &x2); /************************************************************************* Random number generator: exponential distribution State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 11.08.2007 by Bochkanov Sergey *************************************************************************/ double hqrndexponential(const hqrndstate &state, const double lambdav); /************************************************************************* This function generates random number from discrete distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample N - number of elements to use, N>=1 RESULT this function returns one of the X[i] for random i=0..N-1 -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrnddiscrete(const hqrndstate &state, const real_1d_array &x, const ae_int_t n); /************************************************************************* This function generates random number from continuous distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample, array[N] (can be larger, in this case only leading N elements are used). THIS ARRAY MUST BE SORTED BY ASCENDING. N - number of elements to use, N>=1 RESULT this function returns random number from continuous distribution which tries to approximate X as mush as possible. min(X)<=Result<=max(X). -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrndcontinuous(const hqrndstate &state, const real_1d_array &x, const ae_int_t n); /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void kdtreeserialize(kdtree &obj, std::string &s_out); /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void kdtreeunserialize(std::string &s_in, kdtree &obj); /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values N - number of points, N>=0. NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values, integer tags and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values Tags - tags, array[0..N-1], contains integer tags associated with points. N - number of points, N>=0 NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); /************************************************************************* K-NN query: K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of actual neighbors found (either K or N, if K>N). This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch); ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k); /************************************************************************* R-NN query: all points within R-sphere centered at X INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. R - radius of sphere (in corresponding norm), R>0 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of neighbors found, >=0 This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain actual results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch); ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r); /************************************************************************* K-NN query: approximate K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True Eps - approximation factor, Eps>=0. eps-approximate nearest neighbor is a neighbor whose distance from X is at most (1+eps) times distance of true nearest neighbor. RESULT number of actual neighbors found (either K or N, if K>N). NOTES significant performance gain may be achieved only when Eps is is on the order of magnitude of 1 or larger. This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps); ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps); /************************************************************************* X-values from last query INPUT PARAMETERS KDT - KD-tree X - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS X - rows are filled with X-values NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x); /************************************************************************* X- and Y-values from last query INPUT PARAMETERS KDT - KD-tree XY - possibly pre-allocated buffer. If XY is too small to store result, it is resized. If size(XY) is enough to store result, it is left unchanged. OUTPUT PARAMETERS XY - rows are filled with points: first NX columns with X-values, next NY columns - with Y-values. NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy); /************************************************************************* Tags from last query INPUT PARAMETERS KDT - KD-tree Tags - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS Tags - filled with tags associated with points, or, when no tags were supplied, with zeros NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags); /************************************************************************* Distances from last query INPUT PARAMETERS KDT - KD-tree R - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS R - filled with distances (in corresponding norm) NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r); /************************************************************************* X-values from last query; 'interactive' variant for languages like Python which support constructs like "X = KDTreeQueryResultsXI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x); /************************************************************************* XY-values from last query; 'interactive' variant for languages like Python which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy); /************************************************************************* Tags from last query; 'interactive' variant for languages like Python which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags); /************************************************************************* Distances from last query; 'interactive' variant for languages like Python which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Creates and returns XDebugRecord1 structure: * integer and complex fields of Rec1 are set to 1 and 1+i correspondingly * array field of Rec1 is set to [2,3] -- ALGLIB -- Copyright 27.05.2014 by Bochkanov Sergey *************************************************************************/ void xdebuginitrecord1(xdebugrecord1 &rec1); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 1D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb1count(const boolean_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1not(const boolean_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1appendcopy(boolean_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered elements set to True. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1outeven(const ae_int_t n, boolean_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi1sum(const integer_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1neg(const integer_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1appendcopy(integer_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I, and odd-numbered ones set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1outeven(const ae_int_t n, integer_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr1sum(const real_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1neg(const real_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1appendcopy(real_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I*0.25, and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1outeven(const ae_int_t n, real_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ alglib::complex xdebugc1sum(const complex_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1neg(const complex_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1appendcopy(complex_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1outeven(const ae_int_t n, complex_1d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 2D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb2count(const boolean_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2not(const boolean_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2transpose(boolean_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2outsin(const ae_int_t m, const ae_int_t n, boolean_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi2sum(const integer_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2neg(const integer_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2transpose(integer_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2outsin(const ae_int_t m, const ae_int_t n, integer_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr2sum(const real_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2neg(const real_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2transpose(real_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2outsin(const ae_int_t m, const ae_int_t n, real_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ alglib::complex xdebugc2sum(const complex_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2neg(const complex_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2transpose(complex_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2outsincos(const ae_int_t m, const ae_int_t n, complex_2d_array &a); /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugmaskedbiasedproductsum(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const real_2d_array &b, const boolean_2d_array &c); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void hqrndrandomize(hqrndstate* state, ae_state *_state); void hqrndseed(ae_int_t s1, ae_int_t s2, hqrndstate* state, ae_state *_state); double hqrnduniformr(hqrndstate* state, ae_state *_state); ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state); double hqrndnormal(hqrndstate* state, ae_state *_state); void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state); void hqrndnormal2(hqrndstate* state, double* x1, double* x2, ae_state *_state); double hqrndexponential(hqrndstate* state, double lambdav, ae_state *_state); double hqrnddiscrete(hqrndstate* state, /* Real */ ae_vector* x, ae_int_t n, ae_state *_state); double hqrndcontinuous(hqrndstate* state, /* Real */ ae_vector* x, ae_int_t n, ae_state *_state); void _hqrndstate_init(void* _p, ae_state *_state); void _hqrndstate_init_copy(void* _dst, void* _src, ae_state *_state); void _hqrndstate_clear(void* _p); void _hqrndstate_destroy(void* _p); void kdtreebuild(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree* kdt, ae_state *_state); void kdtreebuildtagged(/* Real */ ae_matrix* xy, /* Integer */ ae_vector* tags, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree* kdt, ae_state *_state); ae_int_t kdtreequeryknn(kdtree* kdt, /* Real */ ae_vector* x, ae_int_t k, ae_bool selfmatch, ae_state *_state); ae_int_t kdtreequeryrnn(kdtree* kdt, /* Real */ ae_vector* x, double r, ae_bool selfmatch, ae_state *_state); ae_int_t kdtreequeryaknn(kdtree* kdt, /* Real */ ae_vector* x, ae_int_t k, ae_bool selfmatch, double eps, ae_state *_state); void kdtreequeryresultsx(kdtree* kdt, /* Real */ ae_matrix* x, ae_state *_state); void kdtreequeryresultsxy(kdtree* kdt, /* Real */ ae_matrix* xy, ae_state *_state); void kdtreequeryresultstags(kdtree* kdt, /* Integer */ ae_vector* tags, ae_state *_state); void kdtreequeryresultsdistances(kdtree* kdt, /* Real */ ae_vector* r, ae_state *_state); void kdtreequeryresultsxi(kdtree* kdt, /* Real */ ae_matrix* x, ae_state *_state); void kdtreequeryresultsxyi(kdtree* kdt, /* Real */ ae_matrix* xy, ae_state *_state); void kdtreequeryresultstagsi(kdtree* kdt, /* Integer */ ae_vector* tags, ae_state *_state); void kdtreequeryresultsdistancesi(kdtree* kdt, /* Real */ ae_vector* r, ae_state *_state); void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state); void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state); void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state); void _kdtree_init(void* _p, ae_state *_state); void _kdtree_init_copy(void* _dst, void* _src, ae_state *_state); void _kdtree_clear(void* _p); void _kdtree_destroy(void* _p); void xdebuginitrecord1(xdebugrecord1* rec1, ae_state *_state); ae_int_t xdebugb1count(/* Boolean */ ae_vector* a, ae_state *_state); void xdebugb1not(/* Boolean */ ae_vector* a, ae_state *_state); void xdebugb1appendcopy(/* Boolean */ ae_vector* a, ae_state *_state); void xdebugb1outeven(ae_int_t n, /* Boolean */ ae_vector* a, ae_state *_state); ae_int_t xdebugi1sum(/* Integer */ ae_vector* a, ae_state *_state); void xdebugi1neg(/* Integer */ ae_vector* a, ae_state *_state); void xdebugi1appendcopy(/* Integer */ ae_vector* a, ae_state *_state); void xdebugi1outeven(ae_int_t n, /* Integer */ ae_vector* a, ae_state *_state); double xdebugr1sum(/* Real */ ae_vector* a, ae_state *_state); void xdebugr1neg(/* Real */ ae_vector* a, ae_state *_state); void xdebugr1appendcopy(/* Real */ ae_vector* a, ae_state *_state); void xdebugr1outeven(ae_int_t n, /* Real */ ae_vector* a, ae_state *_state); ae_complex xdebugc1sum(/* Complex */ ae_vector* a, ae_state *_state); void xdebugc1neg(/* Complex */ ae_vector* a, ae_state *_state); void xdebugc1appendcopy(/* Complex */ ae_vector* a, ae_state *_state); void xdebugc1outeven(ae_int_t n, /* Complex */ ae_vector* a, ae_state *_state); ae_int_t xdebugb2count(/* Boolean */ ae_matrix* a, ae_state *_state); void xdebugb2not(/* Boolean */ ae_matrix* a, ae_state *_state); void xdebugb2transpose(/* Boolean */ ae_matrix* a, ae_state *_state); void xdebugb2outsin(ae_int_t m, ae_int_t n, /* Boolean */ ae_matrix* a, ae_state *_state); ae_int_t xdebugi2sum(/* Integer */ ae_matrix* a, ae_state *_state); void xdebugi2neg(/* Integer */ ae_matrix* a, ae_state *_state); void xdebugi2transpose(/* Integer */ ae_matrix* a, ae_state *_state); void xdebugi2outsin(ae_int_t m, ae_int_t n, /* Integer */ ae_matrix* a, ae_state *_state); double xdebugr2sum(/* Real */ ae_matrix* a, ae_state *_state); void xdebugr2neg(/* Real */ ae_matrix* a, ae_state *_state); void xdebugr2transpose(/* Real */ ae_matrix* a, ae_state *_state); void xdebugr2outsin(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_state *_state); ae_complex xdebugc2sum(/* Complex */ ae_matrix* a, ae_state *_state); void xdebugc2neg(/* Complex */ ae_matrix* a, ae_state *_state); void xdebugc2transpose(/* Complex */ ae_matrix* a, ae_state *_state); void xdebugc2outsincos(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_state *_state); double xdebugmaskedbiasedproductsum(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, /* Real */ ae_matrix* b, /* Boolean */ ae_matrix* c, ae_state *_state); void _xdebugrecord1_init(void* _p, ae_state *_state); void _xdebugrecord1_init_copy(void* _dst, void* _src, ae_state *_state); void _xdebugrecord1_clear(void* _p); void _xdebugrecord1_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/interpolation.cpp000755 001750 000144 00005077523 13024173403 024131 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "interpolation.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* IDW interpolant. *************************************************************************/ _idwinterpolant_owner::_idwinterpolant_owner() { p_struct = (alglib_impl::idwinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_idwinterpolant_init(p_struct, NULL); } _idwinterpolant_owner::_idwinterpolant_owner(const _idwinterpolant_owner &rhs) { p_struct = (alglib_impl::idwinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_idwinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _idwinterpolant_owner& _idwinterpolant_owner::operator=(const _idwinterpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_idwinterpolant_clear(p_struct); alglib_impl::_idwinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _idwinterpolant_owner::~_idwinterpolant_owner() { alglib_impl::_idwinterpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::idwinterpolant* _idwinterpolant_owner::c_ptr() { return p_struct; } alglib_impl::idwinterpolant* _idwinterpolant_owner::c_ptr() const { return const_cast(p_struct); } idwinterpolant::idwinterpolant() : _idwinterpolant_owner() { } idwinterpolant::idwinterpolant(const idwinterpolant &rhs):_idwinterpolant_owner(rhs) { } idwinterpolant& idwinterpolant::operator=(const idwinterpolant &rhs) { if( this==&rhs ) return *this; _idwinterpolant_owner::operator=(rhs); return *this; } idwinterpolant::~idwinterpolant() { } /************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ double idwcalc(const idwinterpolant &z, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::idwcalc(const_cast(z.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IDW interpolant using modified Shepard method for uniform point distributions. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function type, either: * 0 constant model. Just for demonstration only, worst model ever. * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is significantly faster than linear/quadratic and better than constant model. But it is less robust (especially in the presence of noise). NQ - number of points used to calculate nodal functions (ignored for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, worst - with constant models * when N is large, NQ and NW must be significantly smaller than N both to obtain optimal performance and to obtain optimal accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be automatically decreased. * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small scales. If it isn't - for example, points are concentrated along "lines", but "lines" distribution is uniform at the larger scale - then you should use IDWBuildModifiedShepardR() -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepard(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::idwbuildmodifiedshepard(const_cast(xy.c_ptr()), n, nx, d, nq, nw, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepardr(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const double r, idwinterpolant &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::idwbuildmodifiedshepardr(const_cast(xy.c_ptr()), n, nx, r, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildnoisy(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::idwbuildnoisy(const_cast(xy.c_ptr()), n, nx, d, nq, nw, const_cast(z.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Barycentric interpolant. *************************************************************************/ _barycentricinterpolant_owner::_barycentricinterpolant_owner() { p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_barycentricinterpolant_init(p_struct, NULL); } _barycentricinterpolant_owner::_barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs) { p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _barycentricinterpolant_owner& _barycentricinterpolant_owner::operator=(const _barycentricinterpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_barycentricinterpolant_clear(p_struct); alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _barycentricinterpolant_owner::~_barycentricinterpolant_owner() { alglib_impl::_barycentricinterpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() { return p_struct; } alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() const { return const_cast(p_struct); } barycentricinterpolant::barycentricinterpolant() : _barycentricinterpolant_owner() { } barycentricinterpolant::barycentricinterpolant(const barycentricinterpolant &rhs):_barycentricinterpolant_owner(rhs) { } barycentricinterpolant& barycentricinterpolant::operator=(const barycentricinterpolant &rhs) { if( this==&rhs ) return *this; _barycentricinterpolant_owner::operator=(rhs); return *this; } barycentricinterpolant::~barycentricinterpolant() { } /************************************************************************* Rational interpolation using barycentric formula F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) Input parameters: B - barycentric interpolant built with one of model building subroutines. T - interpolation point Result: barycentric interpolant F(t) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ double barycentriccalc(const barycentricinterpolant &b, const double t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::barycentriccalc(const_cast(b.c_ptr()), t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Differentiation of barycentric interpolant: first derivative. Algorithm used in this subroutine is very robust and should not fail until provided with values too close to MaxRealNumber (usually MaxRealNumber/N or greater will overflow). INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative NOTE -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricdiff1(const_cast(b.c_ptr()), t, &f, &df, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Differentiation of barycentric interpolant: first/second derivatives. INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative D2F - second derivative NOTE: this algorithm may fail due to overflow/underflor if used on data whose values are close to MaxRealNumber or MinRealNumber. Use more robust BarycentricDiff1() subroutine in such cases. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricdiff2(const_cast(b.c_ptr()), t, &f, &df, &d2f, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the argument. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: x = CA*t + CB OUTPUT PARAMETERS: B - transformed interpolant with X replaced by T -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentriclintransx(const_cast(b.c_ptr()), ca, cb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the barycentric interpolant. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB OUTPUT PARAMETERS: B - transformed interpolant -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentriclintransy(const_cast(b.c_ptr()), ca, cb, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Extracts X/Y/W arrays from rational interpolant INPUT PARAMETERS: B - barycentric interpolant OUTPUT PARAMETERS: N - nodes count, N>0 X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricunpack(const_cast(b.c_ptr()), &n, const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Rational interpolant from X/Y/W arrays F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) INPUT PARAMETERS: X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] N - nodes count, N>0 OUTPUT PARAMETERS: B - barycentric interpolant built from (X, Y, W) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricbuildxyw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Rational interpolant without poles The subroutine constructs the rational interpolating function without real poles (see 'Barycentric rational interpolation with no poles and high rates of approximation', Michael S. Floater. and Kai Hormann, for more information on this subject). Input parameters: X - interpolation nodes, array[0..N-1]. Y - function values, array[0..N-1]. N - number of nodes, N>0. D - order of the interpolation scheme, 0 <= D <= N-1. D<0 will cause an error. D>=N it will be replaced with D=N-1. if you don't know what D to choose, use small value about 3-5. Output parameters: B - barycentric interpolant. Note: this algorithm always succeeds and calculates the weights with close to machine precision. -- ALGLIB PROJECT -- Copyright 17.06.2007 by Bochkanov Sergey *************************************************************************/ void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricbuildfloaterhormann(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, d, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from barycentric representation to Chebyshev basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form A,B - base interval for Chebyshev polynomials (see below) A<>B OUTPUT PARAMETERS T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, where Ti - I-th Chebyshev polynomial. NOTES: barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbar2cheb(const_cast(p.c_ptr()), a, b, const_cast(t.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from Chebyshev basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, where Ti - I-th Chebyshev polynomial. N - number of coefficients: * if given, only leading N elements of T are used * if not given, automatically determined from size of T A,B - base interval for Chebyshev polynomials (see above) A(t.c_ptr()), n, a, b, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from Chebyshev basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, where Ti - I-th Chebyshev polynomial. N - number of coefficients: * if given, only leading N elements of T are used * if not given, automatically determined from size of T A,B - base interval for Chebyshev polynomials (see above) A(t.c_ptr()), n, a, b, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from barycentric representation to power basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if P was obtained as result of interpolation on [-1,+1], you can set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such representation can be obtained by using 1000.0 as offset C and 1.0 as scale S. 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return coefficients in any case, but for N>8 they will become unreliable. However, N's less than 5 are pretty safe. 3. barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbar2pow(const_cast(p.c_ptr()), c, s, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from barycentric representation to power basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if P was obtained as result of interpolation on [-1,+1], you can set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such representation can be obtained by using 1000.0 as offset C and 1.0 as scale S. 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return coefficients in any case, but for N>8 they will become unreliable. However, N's less than 5 are pretty safe. 3. barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; double c; double s; c = 0; s = 1; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbar2pow(const_cast(p.c_ptr()), c, s, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from power basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) * if given, only leading N elements of A are used * if not given, automatically determined from size of A C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS P - polynomial in barycentric form NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if you interpolate on [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option (you have to specify 1000.0 as offset C and 1.0 as scale S). 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return barycentric model in any case, but for N>8 accuracy well degrade. However, N's less than 5 are pretty safe. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialpow2bar(const_cast(a.c_ptr()), n, c, s, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conversion from power basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) * if given, only leading N elements of A are used * if not given, automatically determined from size of A C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS P - polynomial in barycentric form NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if you interpolate on [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option (you have to specify 1000.0 as offset C and 1.0 as scale S). 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return barycentric model in any case, but for N>8 accuracy well degrade. However, N's less than 5 are pretty safe. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; double c; double s; n = a.length(); c = 0; s = 1; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialpow2bar(const_cast(a.c_ptr()), n, c, s, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant: generation of the model on the general grid. This function has O(N^2) complexity. INPUT PARAMETERS: X - abscissas, array[0..N-1] Y - function values, array[0..N-1] N - number of points, N>=1 OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuild(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant: generation of the model on the general grid. This function has O(N^2) complexity. INPUT PARAMETERS: X - abscissas, array[0..N-1] Y - function values, array[0..N-1] N - number of points, N>=1 OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'polynomialbuild': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuild(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant: generation of the model on equidistant grid. This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1] N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildeqdist(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant: generation of the model on equidistant grid. This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1] N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = y.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildeqdist(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant on Chebyshev grid (first kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildcheb1(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant on Chebyshev grid (first kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = y.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildcheb1(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant on Chebyshev grid (second kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildcheb2(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Lagrange intepolant on Chebyshev grid (second kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = y.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialbuildcheb2(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast equidistant polynomial interpolation function with O(N) complexity INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on equidistant grid, N>=1 for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolynomialBuildEqDist()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalceqdist(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast equidistant polynomial interpolation function with O(N) complexity INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on equidistant grid, N>=1 for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolynomialBuildEqDist()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = f.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalceqdist(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (first kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (first kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb1()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalccheb1(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (first kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (first kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb1()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = f.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalccheb1(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (second kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (second kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb2()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalccheb2(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (second kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (second kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb2()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = f.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::polynomialcalccheb2(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 1-dimensional spline interpolant *************************************************************************/ _spline1dinterpolant_owner::_spline1dinterpolant_owner() { p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline1dinterpolant_init(p_struct, NULL); } _spline1dinterpolant_owner::_spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs) { p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _spline1dinterpolant_owner& _spline1dinterpolant_owner::operator=(const _spline1dinterpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_spline1dinterpolant_clear(p_struct); alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _spline1dinterpolant_owner::~_spline1dinterpolant_owner() { alglib_impl::_spline1dinterpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() { return p_struct; } alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() const { return const_cast(p_struct); } spline1dinterpolant::spline1dinterpolant() : _spline1dinterpolant_owner() { } spline1dinterpolant::spline1dinterpolant(const spline1dinterpolant &rhs):_spline1dinterpolant_owner(rhs) { } spline1dinterpolant& spline1dinterpolant::operator=(const spline1dinterpolant &rhs) { if( this==&rhs ) return *this; _spline1dinterpolant_owner::operator=(rhs); return *this; } spline1dinterpolant::~spline1dinterpolant() { } /************************************************************************* This subroutine builds linear spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildlinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds linear spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dbuildlinear': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildlinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds cubic spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds cubic spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dbuildcubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns table of function derivatives d[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D - derivative values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dgriddiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns table of function derivatives d[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D - derivative values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dgriddiffcubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dgriddiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns tables of first and second function derivatives d1[] and d2[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D1 - S' values at X[] D2 - S'' values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dgriddiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d1.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns tables of first and second function derivatives d1[] and d2[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D1 - S' values at X[] D2 - S'' values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dgriddiff2cubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dgriddiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d1.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; ae_int_t n2; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dconvcubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; n2 = x2.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] and derivatives d2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvdiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] and derivatives d2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; ae_int_t n2; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dconvdiffcubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; n2 = x2.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvdiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[], first and second derivatives d2[] and dd2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] DD2 - second derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvdiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), const_cast(dd2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[], first and second derivatives d2[] and dd2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] DD2 - second derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t boundltype; double boundl; ae_int_t boundrtype; double boundr; ae_int_t n2; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dconvdiff2cubic': looks like one of arguments has wrong size"); n = x.length(); boundltype = 0; boundl = 0; boundrtype = 0; boundr = 0; n2 = x2.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dconvdiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), const_cast(dd2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Catmull-Rom spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundType - boundary condition type: * -1 for periodic boundary condition * 0 for parabolically terminated spline (default) Tension - tension parameter: * tension=0 corresponds to classic Catmull-Rom spline (default) * 0(x.c_ptr()), const_cast(y.c_ptr()), n, boundtype, tension, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Catmull-Rom spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundType - boundary condition type: * -1 for periodic boundary condition * 0 for parabolically terminated spline (default) Tension - tension parameter: * tension=0 corresponds to classic Catmull-Rom spline (default) * 0(x.c_ptr()), const_cast(y.c_ptr()), n, boundtype, tension, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Hermite spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] D - derivatives, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildhermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(d.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Hermite spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] D - derivatives, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length()) || (x.length()!=d.length())) throw ap_error("Error while calling 'spline1dbuildhermite': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildhermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(d.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Akima spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildakima(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds Akima spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dbuildakima': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildakima(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates the value of the spline at the given point X. INPUT PARAMETERS: C - spline interpolant X - point Result: S(x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dcalc(const spline1dinterpolant &c, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spline1dcalc(const_cast(c.c_ptr()), x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine differentiates the spline. INPUT PARAMETERS: C - spline interpolant. X - point Result: S - S(x) DS - S'(x) D2S - S''(x) -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1ddiff(const_cast(c.c_ptr()), x, &s, &ds, &d2s, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine unpacks the spline into the coefficients table. INPUT PARAMETERS: C - spline interpolant. X - point OUTPUT PARAMETERS: Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. For I = 0...N-2: Tbl[I,0] = X[i] Tbl[I,1] = X[i+1] Tbl[I,2] = C0 Tbl[I,3] = C1 Tbl[I,4] = C2 Tbl[I,5] = C3 On [x[i], x[i+1]] spline is equals to: S(x) = C0 + C1*t + C2*t^2 + C3*t^3 t = x-x[i] NOTE: You can rebuild spline with Spline1DBuildHermite() function, which accepts as inputs function values and derivatives at nodes, which are easy to calculate when you have coefficients. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dunpack(const_cast(c.c_ptr()), &n, const_cast(tbl.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: x = A*t + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dlintransx(const_cast(c.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x) = A*S(x) + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dlintransy(const_cast(c.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine integrates the spline. INPUT PARAMETERS: C - spline interpolant. X - right bound of the integration interval [a, x], here 'a' denotes min(x[]) Result: integral(S(t)dt,a,x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dintegrate(const spline1dinterpolant &c, const double x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spline1dintegrate(const_cast(c.c_ptr()), x, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds monotone cubic Hermite interpolant. This interpolant is monotonic in [x(0),x(n-1)] and is constant outside of this interval. In case y[] form non-monotonic sequence, interpolant is piecewise monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will monotonically grow at [0..2] and monotonically decrease at [2..4]. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Subroutine automatically sorts points, so caller may pass unsorted array. Y - function values, array[0..N-1] N - the number of points(N>=2). OUTPUT PARAMETERS: C - spline interpolant. -- ALGLIB PROJECT -- Copyright 21.06.2012 by Bochkanov Sergey *************************************************************************/ void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildmonotone(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds monotone cubic Hermite interpolant. This interpolant is monotonic in [x(0),x(n-1)] and is constant outside of this interval. In case y[] form non-monotonic sequence, interpolant is piecewise monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will monotonically grow at [0..2] and monotonically decrease at [2..4]. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Subroutine automatically sorts points, so caller may pass unsorted array. Y - function values, array[0..N-1] N - the number of points(N>=2). OUTPUT PARAMETERS: C - spline interpolant. -- ALGLIB PROJECT -- Copyright 21.06.2012 by Bochkanov Sergey *************************************************************************/ void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dbuildmonotone': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dbuildmonotone(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Polynomial fitting report: TaskRCond reciprocal of task's condition number RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error *************************************************************************/ _polynomialfitreport_owner::_polynomialfitreport_owner() { p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_polynomialfitreport_init(p_struct, NULL); } _polynomialfitreport_owner::_polynomialfitreport_owner(const _polynomialfitreport_owner &rhs) { p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _polynomialfitreport_owner& _polynomialfitreport_owner::operator=(const _polynomialfitreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_polynomialfitreport_clear(p_struct); alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _polynomialfitreport_owner::~_polynomialfitreport_owner() { alglib_impl::_polynomialfitreport_clear(p_struct); ae_free(p_struct); } alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() { return p_struct; } alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() const { return const_cast(p_struct); } polynomialfitreport::polynomialfitreport() : _polynomialfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } polynomialfitreport::polynomialfitreport(const polynomialfitreport &rhs):_polynomialfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } polynomialfitreport& polynomialfitreport::operator=(const polynomialfitreport &rhs) { if( this==&rhs ) return *this; _polynomialfitreport_owner::operator=(rhs); return *this; } polynomialfitreport::~polynomialfitreport() { } /************************************************************************* Barycentric fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error TaskRCond reciprocal of task's condition number *************************************************************************/ _barycentricfitreport_owner::_barycentricfitreport_owner() { p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_barycentricfitreport_init(p_struct, NULL); } _barycentricfitreport_owner::_barycentricfitreport_owner(const _barycentricfitreport_owner &rhs) { p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _barycentricfitreport_owner& _barycentricfitreport_owner::operator=(const _barycentricfitreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_barycentricfitreport_clear(p_struct); alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _barycentricfitreport_owner::~_barycentricfitreport_owner() { alglib_impl::_barycentricfitreport_clear(p_struct); ae_free(p_struct); } alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() { return p_struct; } alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() const { return const_cast(p_struct); } barycentricfitreport::barycentricfitreport() : _barycentricfitreport_owner() ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } barycentricfitreport::barycentricfitreport(const barycentricfitreport &rhs):_barycentricfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } barycentricfitreport& barycentricfitreport::operator=(const barycentricfitreport &rhs) { if( this==&rhs ) return *this; _barycentricfitreport_owner::operator=(rhs); return *this; } barycentricfitreport::~barycentricfitreport() { } /************************************************************************* Spline fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error Fields below are filled by obsolete functions (Spline1DFitCubic, Spline1DFitHermite). Modern fitting functions do NOT fill these fields: TaskRCond reciprocal of task's condition number *************************************************************************/ _spline1dfitreport_owner::_spline1dfitreport_owner() { p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline1dfitreport_init(p_struct, NULL); } _spline1dfitreport_owner::_spline1dfitreport_owner(const _spline1dfitreport_owner &rhs) { p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _spline1dfitreport_owner& _spline1dfitreport_owner::operator=(const _spline1dfitreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_spline1dfitreport_clear(p_struct); alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _spline1dfitreport_owner::~_spline1dfitreport_owner() { alglib_impl::_spline1dfitreport_clear(p_struct); ae_free(p_struct); } alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() { return p_struct; } alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() const { return const_cast(p_struct); } spline1dfitreport::spline1dfitreport() : _spline1dfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } spline1dfitreport::spline1dfitreport(const spline1dfitreport &rhs):_spline1dfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) { } spline1dfitreport& spline1dfitreport::operator=(const spline1dfitreport &rhs) { if( this==&rhs ) return *this; _spline1dfitreport_owner::operator=(rhs); return *this; } spline1dfitreport::~spline1dfitreport() { } /************************************************************************* Least squares fitting report. This structure contains informational fields which are set by fitting functions provided by this unit. Different functions initialize different sets of fields, so you should read documentation on specific function you used in order to know which fields are initialized. TaskRCond reciprocal of task's condition number IterationsCount number of internal iterations VarIdx if user-supplied gradient contains errors which were detected by nonlinear fitter, this field is set to index of the first component of gradient which is suspected to be spoiled by bugs. RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error WRMSError weighted RMS error CovPar covariance matrix for parameters, filled by some solvers ErrPar vector of errors in parameters, filled by some solvers ErrCurve vector of fit errors - variability of the best-fit curve, filled by some solvers. Noise vector of per-point noise estimates, filled by some solvers. R2 coefficient of determination (non-weighted, non-adjusted), filled by some solvers. *************************************************************************/ _lsfitreport_owner::_lsfitreport_owner() { p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lsfitreport_init(p_struct, NULL); } _lsfitreport_owner::_lsfitreport_owner(const _lsfitreport_owner &rhs) { p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _lsfitreport_owner& _lsfitreport_owner::operator=(const _lsfitreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_lsfitreport_clear(p_struct); alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _lsfitreport_owner::~_lsfitreport_owner() { alglib_impl::_lsfitreport_clear(p_struct); ae_free(p_struct); } alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() { return p_struct; } alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() const { return const_cast(p_struct); } lsfitreport::lsfitreport() : _lsfitreport_owner() ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) { } lsfitreport::lsfitreport(const lsfitreport &rhs):_lsfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) { } lsfitreport& lsfitreport::operator=(const lsfitreport &rhs) { if( this==&rhs ) return *this; _lsfitreport_owner::operator=(rhs); return *this; } lsfitreport::~lsfitreport() { } /************************************************************************* Nonlinear fitter. You should use ALGLIB functions to work with fitter. Never try to access its fields directly! *************************************************************************/ _lsfitstate_owner::_lsfitstate_owner() { p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lsfitstate_init(p_struct, NULL); } _lsfitstate_owner::_lsfitstate_owner(const _lsfitstate_owner &rhs) { p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _lsfitstate_owner& _lsfitstate_owner::operator=(const _lsfitstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_lsfitstate_clear(p_struct); alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _lsfitstate_owner::~_lsfitstate_owner() { alglib_impl::_lsfitstate_clear(p_struct); ae_free(p_struct); } alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() { return p_struct; } alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() const { return const_cast(p_struct); } lsfitstate::lsfitstate() : _lsfitstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x) { } lsfitstate::lsfitstate(const lsfitstate &rhs):_lsfitstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x) { } lsfitstate& lsfitstate::operator=(const lsfitstate &rhs) { if( this==&rhs ) return *this; _lsfitstate_owner::operator=(rhs); return *this; } lsfitstate::~lsfitstate() { } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after generating specified number of linear sections. IMPORTANT: * it does NOT perform least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y M - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N(x.c_ptr()), const_cast(y.c_ptr()), n, m, const_cast(x2.c_ptr()), const_cast(y2.c_ptr()), &nsections, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after achieving desired precision. IMPORTANT: * it performs non-least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y Eps - positive number, desired precision. OUTPUT PARAMETERS: X2 - X-values of corner points for piecewise approximation, has length NSections+1 or zero (for NSections=0). Y2 - Y-values of corner points, has length NSections+1 or zero (for NSections=0). NSections- number of sections found by algorithm, NSections can be zero for degenerate datasets (N<=1 or all X[] are non-distinct). NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is a first point of curve, (X2[NSection-1],Y2[NSection-1]) is the last point. -- ALGLIB -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/ void lstfitpiecewiselinearrdp(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double eps, real_1d_array &x2, real_1d_array &y2, ae_int_t &nsections) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lstfitpiecewiselinearrdp(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, eps, const_cast(x2.c_ptr()), const_cast(y2.c_ptr()), &nsections, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fitting by polynomials in barycentric form. This function provides simple unterface for unconstrained unweighted fitting. See PolynomialFitWC() if you need constrained fitting. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFitWC() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0 * if given, only leading N elements of X/Y are used * if not given, automatically determined from sizes of X/Y M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fitting by polynomials in barycentric form. This function provides simple unterface for unconstrained unweighted fitting. See PolynomialFitWC() if you need constrained fitting. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFitWC() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0 * if given, only leading N elements of X/Y are used * if not given, automatically determined from sizes of X/Y M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'polynomialfit': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'polynomialfit': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by polynomials in barycentric form, with constraints on function values or first derivatives. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFit() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. * if given, only leading N elements of X/Y/W are used * if not given, automatically determined from sizes of X/Y/W XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * even simple constraints can be inconsistent, see Wikipedia article on this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the one special cases, however, we can guarantee consistency. This case is: M>1 and constraints on the function values (NOT DERIVATIVES) Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by polynomials in barycentric form, with constraints on function values or first derivatives. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFit() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. * if given, only leading N elements of X/Y/W are used * if not given, automatically determined from sizes of X/Y/W XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * even simple constraints can be inconsistent, see Wikipedia article on this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the one special cases, however, we can guarantee consistency. This case is: M>1 and constraints on the function values (NOT DERIVATIVES) Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates value of four-parameter logistic (4PL) model at specified point X. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D- parameters of 4PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc4(const double x, const double a, const double b, const double c, const double d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::logisticcalc4(x, a, b, c, d, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates value of five-parameter logistic (5PL) model at specified point X. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D, G- parameters of 5PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained * G>0, non-positive value results in exception RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::logisticcalc5(x, a, b, c, d, g, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::logisticfit4(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &a, &b, &c, &d, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user, with optional constraints on parameters A and D. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - with optional equality constraints * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::logisticfit4ec(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, cnstrleft, cnstrright, &a, &b, &c, &d, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - unconstrained * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::logisticfit5(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &a, &b, &c, &d, &g, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user, subject to optional equality constraints on parameters A and D. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - with optional equality constraints * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::logisticfit5ec(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, cnstrleft, cnstrright, &a, &b, &c, &d, &g, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is "expert" 4PL/5PL fitting function, which can be used if you need better control over fitting process than provided by LogisticFit4() or LogisticFit5(). This function fits model of the form F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) or F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) Here: * A, D - unconstrained * B>=0 for 4PL, unconstrained for 5PL * C>0 * G>0 (if present) INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. Is4PL - whether 4PL or 5PL models are fitted LambdaV - regularization coefficient, LambdaV>=0. Set it to zero unless you know what you are doing. EpsX - stopping condition (step size), EpsX>=0. Zero value means that small step is automatically chosen. See notes below for more information. RsCnt - number of repeated restarts from random points. 4PL/5PL models are prone to problem of bad local extrema. Utilizing multiple random restarts allows us to improve algorithm convergence. RsCnt>=0. Zero value means that function automatically choose small amount of restarts (recommended). OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model G - parameter of 5PL model; for Is4PL=True, G=1 is returned. Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. For 5PL model things are different. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit45x(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, const bool is4pl, const double lambdav, const double epsx, const ae_int_t rscnt, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::logisticfit45x(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, cnstrleft, cnstrright, is4pl, lambdav, epsx, rscnt, &a, &b, &c, &d, &g, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricfitfloaterhormannwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_barycentricfitfloaterhormannwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::barycentricfitfloaterhormann(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_barycentricfitfloaterhormann(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points (optional): * N>0 * if given, only first N elements of X/Y are processed * if not given, automatically determined from X/Y sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points (optional): * N>0 * if given, only first N elements of X/Y are processed * if not given, automatically determined from X/Y sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted problem. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 19.10.2010 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted problem. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 19.10.2010 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by cubic spline, with constraints on function values or derivatives. Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with continuous second derivatives and non-fixed first derivatives at interval ends. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, less smooth) Spline1DFitCubic() - "lightweight" fitting by cubic splines, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints S - spline interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function values AND/OR its derivatives at the interval boundaries. * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by cubic spline, with constraints on function values or derivatives. Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with continuous second derivatives and non-fixed first derivatives at interval ends. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, less smooth) Spline1DFitCubic() - "lightweight" fitting by cubic splines, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints S - spline interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function values AND/OR its derivatives at the interval boundaries. * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by Hermite spline, with constraints on function values or first derivatives. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are Hermite splines. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, more smooth) Spline1DFitHermite() - "lightweight" Hermite fitting, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4, M IS EVEN! OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -2 means odd M was passed (which is not supported) -1 means another errors in parameters passed (N<=0, for example) S - spline interpolant. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. IMPORTANT: this subroitine supports only even M's ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the several special cases, however, we can guarantee consistency. * one of this cases is M>=4 and constraints on the function value (AND/OR its derivative) at the interval boundaries. * another special case is M>=4 and ONE constraint on the function value (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted fitting by Hermite spline, with constraints on function values or first derivatives. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are Hermite splines. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, more smooth) Spline1DFitHermite() - "lightweight" Hermite fitting, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4, M IS EVEN! OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -2 means odd M was passed (which is not supported) -1 means another errors in parameters passed (N<=0, for example) S - spline interpolant. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. IMPORTANT: this subroitine supports only even M's ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the several special cases, however, we can guarantee consistency. * one of this cases is M>=4 and constraints on the function value (AND/OR its derivative) at the interval boundaries. * another special case is M>=4 and ONE constraint on the function value (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t k; if( (x.length()!=y.length()) || (x.length()!=w.length())) throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); n = x.length(); k = xc.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Least squares fitting by cubic spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information about subroutine parameters (we don't duplicate it here because of length) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Least squares fitting by cubic spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information about subroutine parameters (we don't duplicate it here because of length) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Least squares fitting by Hermite spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for more information about subroutine parameters (we don't duplicate it here because of length). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Least squares fitting by Hermite spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for more information about subroutine parameters (we don't duplicate it here because of length). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -1 incorrect N/M were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -1 incorrect N/M were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted constained linear least squares fitting. This is variation of LSFitLinearW(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted constained linear least squares fitting. This is variation of LSFitLinearW(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); if( (fmatrix.cols()!=cmatrix.cols()-1)) throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); k = cmatrix.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); if( (fmatrix.cols()!=cmatrix.cols()-1)) throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); k = cmatrix.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; if( (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinear': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; if( (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinear': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Constained linear least squares fitting. This is variation of LSFitLinear(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Constained linear least squares fitting. This is variation of LSFitLinear(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); if( (fmatrix.cols()!=cmatrix.cols()-1)) throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); k = cmatrix.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (y.length()!=fmatrix.rows())) throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); if( (fmatrix.cols()!=cmatrix.cols()-1)) throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); n = y.length(); m = fmatrix.cols(); k = cmatrix.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewf(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length()) || (x.rows()!=w.length())) throw ap_error("Error while calling 'lsfitcreatewf': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewf(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatef(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length())) throw ap_error("Error while calling 'lsfitcreatef': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatef(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewfg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const bool cheapfg, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length()) || (x.rows()!=w.length())) throw ap_error("Error while calling 'lsfitcreatewfg': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewfg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using gradient only, without individual weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatefg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using gradient only, without individual weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const bool cheapfg, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length())) throw ap_error("Error while calling 'lsfitcreatefg': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatefg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using gradient/Hessian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewfgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Weighted nonlinear least squares fitting using gradient/Hessian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length()) || (x.rows()!=w.length())) throw ap_error("Error while calling 'lsfitcreatewfgh': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatewfgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatefgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; ae_int_t k; if( (x.rows()!=y.length())) throw ap_error("Error while calling 'lsfitcreatefgh': looks like one of arguments has wrong size"); n = x.rows(); m = x.cols(); k = c.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitcreatefgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by LSFitSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitsetcond(const lsfitstate &state, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetcond(const_cast(state.c_ptr()), epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetstpmax(const lsfitstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetxrep(const lsfitstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for underlying optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetscale(const lsfitstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints for underlying optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[K]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[K]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: unlike other constrained optimization algorithms, this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool lsfititeration(const lsfitstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::lsfititeration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.c, state.x, state.f, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.c, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); if( grad==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (grad is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.c, state.x, state.f, ptr); continue; } if( state.needfg ) { grad(state.c, state.x, state.f, state.g, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.c, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); if( grad==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (grad is NULL)"); if( hess==NULL ) throw ap_error("ALGLIB: error in 'lsfitfit()' (hess is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.c, state.x, state.f, ptr); continue; } if( state.needfg ) { grad(state.c, state.x, state.f, state.g, ptr); continue; } if( state.needfgh ) { hess(state.c, state.x, state.f, state.g, state.h, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.c, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. On success following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitresults(const_cast(state.c_ptr()), &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before fitting begins * LSFitFit() is called * prior to actual fitting, for each point in data set X_i and each component of parameters being fited C_j algorithm performs following steps: * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], where C_j is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on C[] * F(X_i|C) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N*K (points count * parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with LSFitSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. NOTE 4: this function works only for optimizers created with LSFitCreateWFG() or LSFitCreateFG() constructors. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void lsfitsetgradientcheck(const lsfitstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lsfitsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Parametric spline inteprolant: 2-dimensional curve. You should not try to access its members directly - use PSpline2XXXXXXXX() functions instead. *************************************************************************/ _pspline2interpolant_owner::_pspline2interpolant_owner() { p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_pspline2interpolant_init(p_struct, NULL); } _pspline2interpolant_owner::_pspline2interpolant_owner(const _pspline2interpolant_owner &rhs) { p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _pspline2interpolant_owner& _pspline2interpolant_owner::operator=(const _pspline2interpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_pspline2interpolant_clear(p_struct); alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _pspline2interpolant_owner::~_pspline2interpolant_owner() { alglib_impl::_pspline2interpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() { return p_struct; } alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() const { return const_cast(p_struct); } pspline2interpolant::pspline2interpolant() : _pspline2interpolant_owner() { } pspline2interpolant::pspline2interpolant(const pspline2interpolant &rhs):_pspline2interpolant_owner(rhs) { } pspline2interpolant& pspline2interpolant::operator=(const pspline2interpolant &rhs) { if( this==&rhs ) return *this; _pspline2interpolant_owner::operator=(rhs); return *this; } pspline2interpolant::~pspline2interpolant() { } /************************************************************************* Parametric spline inteprolant: 3-dimensional curve. You should not try to access its members directly - use PSpline3XXXXXXXX() functions instead. *************************************************************************/ _pspline3interpolant_owner::_pspline3interpolant_owner() { p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_pspline3interpolant_init(p_struct, NULL); } _pspline3interpolant_owner::_pspline3interpolant_owner(const _pspline3interpolant_owner &rhs) { p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _pspline3interpolant_owner& _pspline3interpolant_owner::operator=(const _pspline3interpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_pspline3interpolant_clear(p_struct); alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _pspline3interpolant_owner::~_pspline3interpolant_owner() { alglib_impl::_pspline3interpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() { return p_struct; } alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() const { return const_cast(p_struct); } pspline3interpolant::pspline3interpolant() : _pspline3interpolant_owner() { } pspline3interpolant::pspline3interpolant(const pspline3interpolant &rhs):_pspline3interpolant_owner(rhs) { } pspline3interpolant& pspline3interpolant::operator=(const pspline3interpolant &rhs) { if( this==&rhs ) return *this; _pspline3interpolant_owner::operator=(rhs); return *this; } pspline3interpolant::~pspline3interpolant() { } /************************************************************************* This function builds non-periodic 2-dimensional parametric spline which starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. Order of points is important! N - points count, N>=5 for Akima splines, N>=2 for other types of splines. ST - spline type: * 0 Akima spline * 1 parabolically terminated Catmull-Rom spline (Tension=0) * 2 parabolically terminated cubic spline PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2build(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds non-periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3build(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds periodic 2-dimensional parametric spline which starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then back to (X[0],Y[0]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. XY[N-1,0:1] must be different from XY[0,0:1]. Order of points is important! N - points count, N>=3 for other types of splines. ST - spline type: * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions * 2 cubic spline with cyclic boundary conditions PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). * last point of sequence is NOT equal to the first point. You shouldn't make curve "explicitly periodic" by making them equal. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2buildperiodic(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) and then back to (X[0],Y[0],Z[0]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3buildperiodic(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns vector of parameter values correspoding to points. I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we have (X[0],Y[0]) = PSpline2Calc(P,U[0]), (X[1],Y[1]) = PSpline2Calc(P,U[1]), (X[2],Y[2]) = PSpline2Calc(P,U[2]), ... INPUT PARAMETERS: P - parametric spline interpolant OUTPUT PARAMETERS: N - array size T - array[0..N-1] NOTES: * for non-periodic splines U[0]=0, U[0](p.c_ptr()), &n, const_cast(t.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns vector of parameter values correspoding to points. Same as PSpline2ParameterValues(), but for 3D. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3parametervalues(const pspline3interpolant &p, ae_int_t &n, real_1d_array &t) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3parametervalues(const_cast(p.c_ptr()), &n, const_cast(t.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2calc(const_cast(p.c_ptr()), t, &x, &y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position Z - Z-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3calc(const_cast(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) NOTE: X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2tangent(const_cast(p.c_ptr()), t, &x, &y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) Z - Z-component of tangent vector (normalized) NOTE: X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3tangent(const_cast(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2diff(const_cast(p.c_ptr()), t, &x, &dx, &y, &dy, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative Z - Z-value DZ - Z-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3diff(const_cast(p.c_ptr()), t, &x, &dx, &y, &dy, &z, &dz, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline2diff2(const_cast(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative Z - Z-value DZ - derivative D2Z - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pspline3diff2(const_cast(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &z, &dz, &d2z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * B(p.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * B(p.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm. This function performs PARAMETRIC fit, i.e. it can be used to fit curves like circles. On input it accepts dataset which describes parametric multidimensional curve X(t), with X being vector, and t taking values in [0,N), where N is a number of points in dataset. As result, it returns reduced dataset X2, which can be used to build parametric curve X2(t), which approximates X(t) with desired precision (or has specified number of sections). INPUT PARAMETERS: X - array of multidimensional points: * at least N elements, leading N elements are used if more than N elements were specified * order of points is IMPORTANT because it is parametric fit * each row of array is one point which has D coordinates N - number of elements in X D - number of dimensions (elements per row of X) StopM - stopping condition - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N(x.c_ptr()), n, d, stopm, stopeps, const_cast(x2.c_ptr()), const_cast(idx2.c_ptr()), &nsections, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RBF model. Never try to directly work with fields of this object - always use ALGLIB functions to use this object. *************************************************************************/ _rbfmodel_owner::_rbfmodel_owner() { p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_rbfmodel_init(p_struct, NULL); } _rbfmodel_owner::_rbfmodel_owner(const _rbfmodel_owner &rhs) { p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _rbfmodel_owner& _rbfmodel_owner::operator=(const _rbfmodel_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_rbfmodel_clear(p_struct); alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _rbfmodel_owner::~_rbfmodel_owner() { alglib_impl::_rbfmodel_clear(p_struct); ae_free(p_struct); } alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() { return p_struct; } alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() const { return const_cast(p_struct); } rbfmodel::rbfmodel() : _rbfmodel_owner() { } rbfmodel::rbfmodel(const rbfmodel &rhs):_rbfmodel_owner(rhs) { } rbfmodel& rbfmodel::operator=(const rbfmodel &rhs) { if( this==&rhs ) return *this; _rbfmodel_owner::operator=(rhs); return *this; } rbfmodel::~rbfmodel() { } /************************************************************************* RBF solution report: * TerminationType - termination type, positive values - success, non-positive - failure. *************************************************************************/ _rbfreport_owner::_rbfreport_owner() { p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_rbfreport_init(p_struct, NULL); } _rbfreport_owner::_rbfreport_owner(const _rbfreport_owner &rhs) { p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _rbfreport_owner& _rbfreport_owner::operator=(const _rbfreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_rbfreport_clear(p_struct); alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _rbfreport_owner::~_rbfreport_owner() { alglib_impl::_rbfreport_clear(p_struct); ae_free(p_struct); } alglib_impl::rbfreport* _rbfreport_owner::c_ptr() { return p_struct; } alglib_impl::rbfreport* _rbfreport_owner::c_ptr() const { return const_cast(p_struct); } rbfreport::rbfreport() : _rbfreport_owner() ,arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) { } rbfreport::rbfreport(const rbfreport &rhs):_rbfreport_owner(rhs) ,arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) { } rbfreport& rbfreport::operator=(const rbfreport &rhs) { if( this==&rhs ) return *this; _rbfreport_owner::operator=(rhs); return *this; } rbfreport::~rbfreport() { } /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void rbfserialize(rbfmodel &obj, std::string &s_out) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_int_t ssize; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_alloc_start(&serializer); alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state); ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); s_out.clear(); s_out.reserve((size_t)(ssize+1)); alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); if( s_out.length()>(size_t)ssize ) throw ap_error("ALGLIB: serialization integrity error"); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void rbfunserialize(std::string &s_in, rbfmodel &obj) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function creates RBF model for a scalar (NY=1) or vector (NY>1) function in a NX-dimensional space (NX=2 or NX=3). Newly created model is empty. It can be used for interpolation right after creation, but it just returns zeros. You have to add points to the model, tune interpolation settings, and then call model construction function RBFBuildModel() which will update model according to your specification. USAGE: 1. User creates model with RBFCreate() 2. User adds dataset with RBFSetPoints() (points do NOT have to be on a regular grid) 3. (OPTIONAL) User chooses polynomial term by calling: * RBFLinTerm() to set linear term * RBFConstTerm() to set constant term * RBFZeroTerm() to set zero term By default, linear term is used. 4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) or ML (RBFSetAlgoMultiLayer). 5. User calls RBFBuildModel() function which rebuilds model according to the specification 6. User may call RBFCalc() to calculate model value at the specified point, RBFGridCalc() to calculate model values at the points of the regular grid. User may extract model coefficients with RBFUnpack() call. INPUT PARAMETERS: NX - dimension of the space, NX=2 or NX=3 NY - function dimension, NY>=1 OUTPUT PARAMETERS: S - RBF model (initially equals to zero) NOTE 1: memory requirements. RBF models require amount of memory which is proportional to the number of data points. Memory is allocated during model construction, but most of this memory is freed after model coefficients are calculated. Some approximate estimates for N centers with default settings are given below: * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is needed during model construction stage. * about 15*N*sizeof(double) bytes is needed after model is built. For example, for N=100000 we may need 0.6 GB of memory to build model, but just about 0.012 GB to store it. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfcreate(nx, ny, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset. This function overrides results of the previous calls, i.e. multiple calls of this function will result in only the last set being added. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call. XY - points, array[N,NX+NY]. One row corresponds to one point in the dataset. First NX elements are coordinates, next NY elements are function values. Array may be larger than specific, in this case only leading [N,NX+NY] elements will be used. N - number of points in the dataset After you've added dataset and (optionally) tuned algorithm settings you should call RBFBuildModel() in order to build a model for you. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset. This function overrides results of the previous calls, i.e. multiple calls of this function will result in only the last set being added. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call. XY - points, array[N,NX+NY]. One row corresponds to one point in the dataset. First NX elements are coordinates, next NY elements are function values. Array may be larger than specific, in this case only leading [N,NX+NY] elements will be used. N - number of points in the dataset After you've added dataset and (optionally) tuned algorithm settings you should call RBFBuildModel() in order to build a model for you. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = xy.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-QNN and it is good for point sets with following properties: a) all points are distinct b) all points are well separated. c) points distribution is approximately uniform. There is no "contour lines", clusters of points, or other small-scale structures. Algorithm description: 1) interpolation centers are allocated to data points 2) interpolation radii are calculated as distances to the nearest centers times Q coefficient (where Q is a value from [0.75,1.50]). 3) after performing (2) radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across all dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. When (a) is violated, we will be unable to build RBF model. When (b) or (c) are violated, model will be built, but interpolation quality will be low. See http://www.alglib.net/interpolation/ for more information on this subject. This algorithm is used by default. Additional Q parameter controls smoothness properties of the RBF basis: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q around 1.0 gives good balance between smoothness and condition number * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q>2.0 will effectively make optimizer useless because it won't converge within reasonable amount of iterations. It is possible to set such large Q, but it is advised not to do so. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - Q parameter, Q>0, recommended value - 1.0 Z - Z parameter, Z>0, recommended value - 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetalgoqnn(const_cast(s.c_ptr()), q, z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-QNN and it is good for point sets with following properties: a) all points are distinct b) all points are well separated. c) points distribution is approximately uniform. There is no "contour lines", clusters of points, or other small-scale structures. Algorithm description: 1) interpolation centers are allocated to data points 2) interpolation radii are calculated as distances to the nearest centers times Q coefficient (where Q is a value from [0.75,1.50]). 3) after performing (2) radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across all dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. When (a) is violated, we will be unable to build RBF model. When (b) or (c) are violated, model will be built, but interpolation quality will be low. See http://www.alglib.net/interpolation/ for more information on this subject. This algorithm is used by default. Additional Q parameter controls smoothness properties of the RBF basis: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q around 1.0 gives good balance between smoothness and condition number * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q>2.0 will effectively make optimizer useless because it won't converge within reasonable amount of iterations. It is possible to set such large Q, but it is advised not to do so. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - Q parameter, Q>0, recommended value - 1.0 Z - Z parameter, Z>0, recommended value - 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetalgoqnn(const rbfmodel &s) { alglib_impl::ae_state _alglib_env_state; double q; double z; q = 1.0; z = 5.0; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetalgoqnn(const_cast(s.c_ptr()), q, z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. model with subsequently decreasing radii, which allows us to combine smoothness (due to large radii of the first layers) with exactness (due to small radii of the last layers) and fast convergence. Internally RBF-ML uses many different means of acceleration, from sparse matrices to KD-trees, which results in algorithm whose working time is roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a number of points, Density is an average density if points per unit of the interpolation space, RBase is an initial radius, NLayers is a number of layers. RBF-ML is good for following kinds of interpolation problems: 1. "exact" problems (perfect fit) with well separated points 2. least squares problems with arbitrary distribution of points (algorithm gives perfect fit where it is possible, and resorts to least squares fit in the hard areas). 3. noisy problems where we want to apply some controlled amount of smoothing. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call RBase - RBase parameter, RBase>0 NLayers - NLayers parameter, NLayers>0, recommended value to start with - about 5. LambdaV - regularization value, can be useful when solving problem in the least squares sense. Optimal lambda is problem- dependent and require trial and error. In our experience, good lambda can be as large as 0.1, and you can use 0.001 as initial guess. Default value - 0.01, which is used when LambdaV is not given. You can specify zero value, but it is not recommended to do so. TUNING ALGORITHM In order to use this algorithm you have to choose three parameters: * initial radius RBase * number of layers in the model NLayers * regularization coefficient LambdaV Initial radius is easy to choose - you can pick any number several times larger than the average distance between points. Algorithm won't break down if you choose radius which is too large (model construction time will increase, but model will be built correctly). Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used by the last layer) will be smaller than the typical distance between points. In case model error is too large, you can increase number of layers. Having more layers will make model construction and evaluation proportionally slower, but it will allow you to have model which precisely fits your data. From the other side, if you want to suppress noise, you can DECREASE number of layers to make your model less flexible. Regularization coefficient LambdaV controls smoothness of the individual models built for each layer. We recommend you to use default value in case you don't want to tune this parameter, because having non-zero LambdaV accelerates and stabilizes internal iterative algorithm. In case you want to suppress noise you can use LambdaV as additional parameter (larger value = more smoothness) to tune. TYPICAL ERRORS 1. Using initial radius which is too large. Memory requirements of the RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is an average density of points per unit of the interpolation space). In the extreme case of the very large RBase we will need O(N^2) units of memory - and many layers in order to decrease radius to some reasonably small value. 2. Using too small number of layers - RBF models with large radius are not flexible enough to reproduce small variations in the target function. You need many layers with different radii, from large to small, in order to have good model. 3. Using initial radius which is too small. You will get model with "holes" in the areas which are too far away from interpolation centers. However, algorithm will work correctly (and quickly) in this case. 4. Using too many layers - you will get too large and too slow model. This model will perfectly reproduce your function, but maybe you will be able to achieve similar results with less layers (and less memory). -- ALGLIB -- Copyright 02.03.2012 by Bochkanov Sergey *************************************************************************/ void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetalgomultilayer(const_cast(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. model with subsequently decreasing radii, which allows us to combine smoothness (due to large radii of the first layers) with exactness (due to small radii of the last layers) and fast convergence. Internally RBF-ML uses many different means of acceleration, from sparse matrices to KD-trees, which results in algorithm whose working time is roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a number of points, Density is an average density if points per unit of the interpolation space, RBase is an initial radius, NLayers is a number of layers. RBF-ML is good for following kinds of interpolation problems: 1. "exact" problems (perfect fit) with well separated points 2. least squares problems with arbitrary distribution of points (algorithm gives perfect fit where it is possible, and resorts to least squares fit in the hard areas). 3. noisy problems where we want to apply some controlled amount of smoothing. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call RBase - RBase parameter, RBase>0 NLayers - NLayers parameter, NLayers>0, recommended value to start with - about 5. LambdaV - regularization value, can be useful when solving problem in the least squares sense. Optimal lambda is problem- dependent and require trial and error. In our experience, good lambda can be as large as 0.1, and you can use 0.001 as initial guess. Default value - 0.01, which is used when LambdaV is not given. You can specify zero value, but it is not recommended to do so. TUNING ALGORITHM In order to use this algorithm you have to choose three parameters: * initial radius RBase * number of layers in the model NLayers * regularization coefficient LambdaV Initial radius is easy to choose - you can pick any number several times larger than the average distance between points. Algorithm won't break down if you choose radius which is too large (model construction time will increase, but model will be built correctly). Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used by the last layer) will be smaller than the typical distance between points. In case model error is too large, you can increase number of layers. Having more layers will make model construction and evaluation proportionally slower, but it will allow you to have model which precisely fits your data. From the other side, if you want to suppress noise, you can DECREASE number of layers to make your model less flexible. Regularization coefficient LambdaV controls smoothness of the individual models built for each layer. We recommend you to use default value in case you don't want to tune this parameter, because having non-zero LambdaV accelerates and stabilizes internal iterative algorithm. In case you want to suppress noise you can use LambdaV as additional parameter (larger value = more smoothness) to tune. TYPICAL ERRORS 1. Using initial radius which is too large. Memory requirements of the RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is an average density of points per unit of the interpolation space). In the extreme case of the very large RBase we will need O(N^2) units of memory - and many layers in order to decrease radius to some reasonably small value. 2. Using too small number of layers - RBF models with large radius are not flexible enough to reproduce small variations in the target function. You need many layers with different radii, from large to small, in order to have good model. 3. Using initial radius which is too small. You will get model with "holes" in the areas which are too far away from interpolation centers. However, algorithm will work correctly (and quickly) in this case. 4. Using too many layers - you will get too large and too slow model. This model will perfectly reproduce your function, but maybe you will be able to achieve similar results with less layers (and less memory). -- ALGLIB -- Copyright 02.03.2012 by Bochkanov Sergey *************************************************************************/ void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers) { alglib_impl::ae_state _alglib_env_state; double lambdav; lambdav = 0.01; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetalgomultilayer(const_cast(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear term (model is a sum of radial basis functions plus linear polynomial). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetlinterm(const rbfmodel &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetlinterm(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets constant term (model is a sum of radial basis functions plus constant). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetconstterm(const rbfmodel &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetconstterm(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets zero term (model is a sum of radial basis functions without polynomial term). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetzeroterm(const rbfmodel &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfsetzeroterm(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function builds RBF model and returns report (contains some information which can be used for evaluation of the algorithm properties). Call to this function modifies RBF model by calculating its centers/radii/ weights and saving them into RBFModel structure. Initially RBFModel contain zero coefficients, but after call to this function we will have coefficients which were calculated in order to fit our dataset. After you called this function you can call RBFCalc(), RBFGridCalc() and other model calculation functions. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Rep - report: * Rep.TerminationType: * -5 - non-distinct basis function centers were detected, interpolation aborted * -4 - nonconvergence of the internal SVD solver * 1 - successful termination Fields are used for debugging purposes: * Rep.IterationsCount - iterations count of the LSQR solver * Rep.NMV - number of matrix-vector products * Rep.ARows - rows count for the system matrix * Rep.ACols - columns count for the system matrix * Rep.ANNZ - number of significantly non-zero elements (elements above some algorithm-determined threshold) NOTE: failure to build model will leave current state of the structure unchanged. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfbuildmodel(const rbfmodel &s, rbfreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfbuildmodel(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=2 (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). If you want to calculate function values many times, consider using RBFGridCalc2(), which is far more efficient than many subsequent calls to RBFCalc2(). This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc2(const rbfmodel &s, const double x0, const double x1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rbfcalc2(const_cast(s.c_ptr()), x0, x1, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=3 (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). This function returns 0.0 when: * model is not initialized * NX<>3 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number X2 - third coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::rbfcalc3(const_cast(s.c_ptr()), x0, x1, x2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates values of the RBF model at the given point. This is general function which can be used for arbitrary NX (dimension of the space of arguments) and NY (dimension of the function itself). However when you have NY=1 you may find more convenient to use RBFCalc2() or RBFCalc3(). This function returns 0.0 when model is not initialized. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. OUTPUT PARAMETERS: Y - function value, array[NY]. Y is out-parameter and reallocated after call to this function. In case you want to reuse previously allocated Y, you may use RBFCalcBuf(), which reallocates Y only when it is too small. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfcalc(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates values of the RBF model at the given point. Same as RBFCalc(), but does not reallocate Y when in is large enough to store function values. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. Y - possibly preallocated array OUTPUT PARAMETERS: Y - function value, array[NY]. Y is not reallocated when it is larger than NY. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfcalcbuf(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function calculates values of the RBF model at the regular grid. Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - array of grid nodes, first coordinates, array[N0] N0 - grid size (number of nodes) in the first dimension X1 - array of grid nodes, second coordinates, array[N1] N1 - grid size (number of nodes) in the second dimension OUTPUT PARAMETERS: Y - function values, array[N0,N1]. Y is out-variable and is reallocated by this function. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfgridcalc2(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_2d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfgridcalc2(const_cast(s.c_ptr()), const_cast(x0.c_ptr()), n0, const_cast(x1.c_ptr()), n1, const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function "unpacks" RBF model by extracting its coefficients. INPUT PARAMETERS: S - RBF model OUTPUT PARAMETERS: NX - dimensionality of argument NY - dimensionality of the target function XWR - model information, array[NC,NX+NY+1]. One row of the array corresponds to one basis function: * first NX columns - coordinates of the center * next NY columns - weights, one per dimension of the function being modelled * last column - radius, same for all dimensions of the function being modelled NC - number of the centers V - polynomial term , array[NY,NX+1]. One row per one dimension of the function being modelled. First NX elements are linear coefficients, V[NX] is equal to the constant part. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfunpack(const rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rbfunpack(const_cast(s.c_ptr()), &nx, &ny, const_cast(xwr.c_ptr()), &nc, const_cast(v.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 2-dimensional spline inteprolant *************************************************************************/ _spline2dinterpolant_owner::_spline2dinterpolant_owner() { p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline2dinterpolant_init(p_struct, NULL); } _spline2dinterpolant_owner::_spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs) { p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _spline2dinterpolant_owner& _spline2dinterpolant_owner::operator=(const _spline2dinterpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_spline2dinterpolant_clear(p_struct); alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _spline2dinterpolant_owner::~_spline2dinterpolant_owner() { alglib_impl::_spline2dinterpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() { return p_struct; } alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() const { return const_cast(p_struct); } spline2dinterpolant::spline2dinterpolant() : _spline2dinterpolant_owner() { } spline2dinterpolant::spline2dinterpolant(const spline2dinterpolant &rhs):_spline2dinterpolant_owner(rhs) { } spline2dinterpolant& spline2dinterpolant::operator=(const spline2dinterpolant &rhs) { if( this==&rhs ) return *this; _spline2dinterpolant_owner::operator=(rhs); return *this; } spline2dinterpolant::~spline2dinterpolant() { } /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X. Input parameters: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y- point Result: S(x,y) -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ double spline2dcalc(const spline2dinterpolant &c, const double x, const double y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spline2dcalc(const_cast(c.c_ptr()), x, y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X and its derivatives. Input parameters: C - spline interpolant. X, Y- point Output parameters: F - S(x,y) FX - dS(x,y)/dX FY - dS(x,y)/dY FXY - d2S(x,y)/dXdY -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2ddiff(const_cast(c.c_ptr()), x, y, &f, &fx, &fy, &fxy, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline argument. Input parameters: C - spline interpolant AX, BX - transformation coefficients: x = A*t + B AY, BY - transformation coefficients: y = A*u + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dlintransxy(const_cast(c.c_ptr()), ax, bx, ay, by, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline. Input parameters: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B Output parameters: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dlintransf(const_cast(c.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine makes the copy of the spline model. Input parameters: C - spline interpolant Output parameters: CC - spline copy -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dcopy(const_cast(c.c_ptr()), const_cast(cc.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bicubic spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 15 May, 2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dresamplebicubic(const_cast(a.c_ptr()), oldheight, oldwidth, const_cast(b.c_ptr()), newheight, newwidth, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Bilinear spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 09.07.2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dresamplebilinear(const_cast(a.c_ptr()), oldheight, oldwidth, const_cast(b.c_ptr()), newheight, newwidth, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds bilinear vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dbuildbilinearv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds bicubic vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dbuildbicubicv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dcalcvbuf(const_cast(c.c_ptr()), x, y, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dcalcv(const_cast(c.c_ptr()), x, y, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine unpacks two-dimensional spline into the coefficients table Input parameters: C - spline interpolant. Result: M, N- grid size (x-axis and y-axis) D - number of components Tbl - coefficients table, unpacked format, D - components: [0..(N-1)*(M-1)*D-1, 0..19]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index): K := T + I*D + J*D*(N-1) K-th row stores decomposition for T-th component of the vector-valued function Tbl[K,0] = X[i] Tbl[K,1] = X[i+1] Tbl[K,2] = Y[j] Tbl[K,3] = Y[j+1] Tbl[K,4] = C00 Tbl[K,5] = C01 Tbl[K,6] = C02 Tbl[K,7] = C03 Tbl[K,8] = C10 Tbl[K,9] = C11 ... Tbl[K,19] = C33 On each grid square spline is equals to: S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) t = x-x[j] u = y-y[i] -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dunpackv(const_cast(c.c_ptr()), &m, &n, &d, const_cast(tbl.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBilinearV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dbuildbilinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(f.c_ptr()), m, n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBicubicV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dbuildbicubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(f.c_ptr()), m, n, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DUnpackV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline2dunpack(const_cast(c.c_ptr()), &m, &n, const_cast(tbl.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 3-dimensional spline inteprolant *************************************************************************/ _spline3dinterpolant_owner::_spline3dinterpolant_owner() { p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline3dinterpolant_init(p_struct, NULL); } _spline3dinterpolant_owner::_spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs) { p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _spline3dinterpolant_owner& _spline3dinterpolant_owner::operator=(const _spline3dinterpolant_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_spline3dinterpolant_clear(p_struct); alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _spline3dinterpolant_owner::~_spline3dinterpolant_owner() { alglib_impl::_spline3dinterpolant_clear(p_struct); ae_free(p_struct); } alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() { return p_struct; } alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() const { return const_cast(p_struct); } spline3dinterpolant::spline3dinterpolant() : _spline3dinterpolant_owner() { } spline3dinterpolant::spline3dinterpolant(const spline3dinterpolant &rhs):_spline3dinterpolant_owner(rhs) { } spline3dinterpolant& spline3dinterpolant::operator=(const spline3dinterpolant &rhs) { if( this==&rhs ) return *this; _spline3dinterpolant_owner::operator=(rhs); return *this; } spline3dinterpolant::~spline3dinterpolant() { } /************************************************************************* This subroutine calculates the value of the trilinear or tricubic spline at the given point (X,Y,Z). INPUT PARAMETERS: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y, Z - point Result: S(x,y,z) -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spline3dcalc(const_cast(c.c_ptr()), x, y, z, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant AX, BX - transformation coefficients: x = A*u + B AY, BY - transformation coefficients: y = A*v + B AZ, BZ - transformation coefficients: z = A*w + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dlintransxyz(const_cast(c.c_ptr()), ax, bx, ay, by, az, bz, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dlintransf(const_cast(c.c_ptr()), a, b, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Trilinear spline resampling INPUT PARAMETERS: A - array[0..OldXCount*OldYCount*OldZCount-1], function values at the old grid, : A[0] x=0,y=0,z=0 A[1] x=1,y=0,z=0 A[..] ... A[..] x=oldxcount-1,y=0,z=0 A[..] x=0,y=1,z=0 A[..] ... ... OldZCount - old Z-count, OldZCount>1 OldYCount - old Y-count, OldYCount>1 OldXCount - old X-count, OldXCount>1 NewZCount - new Z-count, NewZCount>1 NewYCount - new Y-count, NewYCount>1 NewXCount - new X-count, NewXCount>1 OUTPUT PARAMETERS: B - array[0..NewXCount*NewYCount*NewZCount-1], function values at the new grid: B[0] x=0,y=0,z=0 B[1] x=1,y=0,z=0 B[..] ... B[..] x=newxcount-1,y=0,z=0 B[..] x=0,y=1,z=0 B[..] ... ... -- ALGLIB routine -- 26.04.2012 Copyright by Bochkanov Sergey *************************************************************************/ void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dresampletrilinear(const_cast(a.c_ptr()), oldzcount, oldycount, oldxcount, newzcount, newycount, newxcount, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds trilinear vector-valued spline. INPUT PARAMETERS: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] Z - spline applicates, array[0..L-1] F - function values, array[0..M*N*L*D-1]: * first D elements store D values at (X[0],Y[0],Z[0]) * next D elements store D values at (X[1],Y[0],Z[0]) * next D elements store D values at (X[2],Y[0],Z[0]) * ... * next D elements store D values at (X[0],Y[1],Z[0]) * next D elements store D values at (X[1],Y[1],Z[0]) * next D elements store D values at (X[2],Y[1],Z[0]) * ... * next D elements store D values at (X[0],Y[0],Z[1]) * next D elements store D values at (X[1],Y[0],Z[1]) * next D elements store D values at (X[2],Y[0],Z[1]) * ... * general form - D function values at (X[i],Y[j]) are stored at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. M,N, L - grid size, M>=2, N>=2, L>=2 D - vector dimension, D>=1 OUTPUT PARAMETERS: C - spline interpolant -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dbuildtrilinearv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(z.c_ptr()), l, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dcalcvbuf(const_cast(c.c_ptr()), x, y, z, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine calculates trilinear or tricubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dcalcv(const_cast(c.c_ptr()), x, y, z, const_cast(f.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine unpacks tri-dimensional spline into the coefficients table INPUT PARAMETERS: C - spline interpolant. Result: N - grid size (X) M - grid size (Y) L - grid size (Z) D - number of components SType- spline type. Currently, only one spline type is supported: trilinear spline, as indicated by SType=1. Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index), K=0..L-2 (z index): Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), Q-th row stores decomposition for T-th component of the vector-valued function Tbl[Q,0] = X[i] Tbl[Q,1] = X[i+1] Tbl[Q,2] = Y[j] Tbl[Q,3] = Y[j+1] Tbl[Q,4] = Z[k] Tbl[Q,5] = Z[k+1] Tbl[Q,6] = C000 Tbl[Q,7] = C100 Tbl[Q,8] = C010 Tbl[Q,9] = C110 Tbl[Q,10]= C001 Tbl[Q,11]= C101 Tbl[Q,12]= C011 Tbl[Q,13]= C111 On each grid square spline is equals to: S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) t = x-x[j] u = y-y[i] v = z-z[k] NOTE: format of Tbl is given for SType=1. Future versions of ALGLIB can use different formats for different values of SType. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spline3dunpackv(const_cast(c.c_ptr()), &n, &m, &l, &d, &stype, const_cast(tbl.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static double idwint_idwqfactor = 1.5; static ae_int_t idwint_idwkmin = 5; static double idwint_idwcalcq(idwinterpolant* z, /* Real */ ae_vector* x, ae_int_t k, ae_state *_state); static void idwint_idwinit1(ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state); static void idwint_idwinternalsolver(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_vector* temp, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* x, double* taskrcond, ae_state *_state); static void ratint_barycentricnormalize(barycentricinterpolant* b, ae_state *_state); static void spline1d_spline1dgriddiffcubicinternal(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d, /* Real */ ae_vector* a1, /* Real */ ae_vector* a2, /* Real */ ae_vector* a3, /* Real */ ae_vector* b, /* Real */ ae_vector* dt, ae_state *_state); static void spline1d_heapsortpoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state); static void spline1d_heapsortppoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Integer */ ae_vector* p, ae_int_t n, ae_state *_state); static void spline1d_solvetridiagonal(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); static void spline1d_solvecyclictridiagonal(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); static double spline1d_diffthreepoint(double t, double x0, double f0, double x1, double f1, double x2, double f2, ae_state *_state); static void spline1d_hermitecalc(double p0, double m0, double p1, double m1, double t, double* s, double* ds, ae_state *_state); static double spline1d_rescaleval(double a0, double b0, double a1, double b1, double t, ae_state *_state); static void lsfit_rdpanalyzesection(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t i0, ae_int_t i1, ae_int_t* worstidx, double* worsterror, ae_state *_state); static void lsfit_rdprecursive(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t i0, ae_int_t i1, double eps, /* Real */ ae_vector* xout, /* Real */ ae_vector* yout, ae_int_t* nout, ae_state *_state); static void lsfit_logisticfitinternal(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_bool is4pl, double lambdav, minlmstate* state, minlmreport* replm, /* Real */ ae_vector* p1, double* flast, ae_state *_state); static void lsfit_spline1dfitinternal(ae_int_t st, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); static void lsfit_lsfitlinearinternal(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); static void lsfit_lsfitclearrequestfields(lsfitstate* state, ae_state *_state); static void lsfit_barycentriccalcbasis(barycentricinterpolant* b, double t, /* Real */ ae_vector* y, ae_state *_state); static void lsfit_internalchebyshevfit(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); static void lsfit_barycentricfitwcfixedd(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t d, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state); static void lsfit_clearreport(lsfitreport* rep, ae_state *_state); static void lsfit_estimateerrors(/* Real */ ae_matrix* f1, /* Real */ ae_vector* f0, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* x, /* Real */ ae_vector* s, ae_int_t n, ae_int_t k, lsfitreport* rep, /* Real */ ae_matrix* z, ae_int_t zkind, ae_state *_state); static void parametric_pspline2par(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t pt, /* Real */ ae_vector* p, ae_state *_state); static void parametric_pspline3par(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t pt, /* Real */ ae_vector* p, ae_state *_state); static void parametric_rdpanalyzesectionpar(/* Real */ ae_matrix* xy, ae_int_t i0, ae_int_t i1, ae_int_t d, ae_int_t* worstidx, double* worsterror, ae_state *_state); static double rbf_eps = 1.0E-6; static ae_int_t rbf_mxnx = 3; static double rbf_rbffarradius = 6; static double rbf_rbfnearradius = 2.1; static double rbf_rbfmlradius = 3; static ae_int_t rbf_rbffirstversion = 0; static void rbf_rbfgridpoints(rbfmodel* s, ae_state *_state); static void rbf_rbfradnn(rbfmodel* s, double q, double z, ae_state *_state); static ae_bool rbf_buildlinearmodel(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t ny, ae_int_t modeltype, /* Real */ ae_matrix* v, ae_state *_state); static void rbf_buildrbfmodellsqr(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, /* Real */ ae_matrix* xc, /* Real */ ae_vector* r, ae_int_t n, ae_int_t nc, ae_int_t ny, kdtree* pointstree, kdtree* centerstree, double epsort, double epserr, ae_int_t maxits, ae_int_t* gnnz, ae_int_t* snnz, /* Real */ ae_matrix* w, ae_int_t* info, ae_int_t* iterationscount, ae_int_t* nmv, ae_state *_state); static void rbf_buildrbfmlayersmodellsqr(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, /* Real */ ae_matrix* xc, double rval, /* Real */ ae_vector* r, ae_int_t n, ae_int_t* nc, ae_int_t ny, ae_int_t nlayers, kdtree* centerstree, double epsort, double epserr, ae_int_t maxits, double lambdav, ae_int_t* annz, /* Real */ ae_matrix* w, ae_int_t* info, ae_int_t* iterationscount, ae_int_t* nmv, ae_state *_state); static void spline2d_bicubiccalcderivatives(/* Real */ ae_matrix* a, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* dx, /* Real */ ae_matrix* dy, /* Real */ ae_matrix* dxy, ae_state *_state); static void spline3d_spline3ddiff(spline3dinterpolant* c, double x, double y, double z, double* f, double* fx, double* fy, double* fxy, ae_state *_state); /************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ double idwcalc(idwinterpolant* z, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; ae_int_t k; double r; double s; double w; double v1; double v2; double d0; double di; double result; /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ k = 0; /* * Query */ if( z->modeltype==0 ) { /* * NQ/NW-based model */ k = kdtreequeryknn(&z->tree, x, z->nw, ae_true, _state); kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); kdtreequeryresultstags(&z->tree, &z->tbuf, _state); } if( z->modeltype==1 ) { /* * R-based model */ k = kdtreequeryrnn(&z->tree, x, z->r, ae_true, _state); kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); kdtreequeryresultstags(&z->tree, &z->tbuf, _state); if( ktree, x, idwint_idwkmin, ae_true, _state); kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); kdtreequeryresultstags(&z->tree, &z->tbuf, _state); } } /* * initialize weights for linear/quadratic members calculation. * * NOTE 1: weights are calculated using NORMALIZED modified * Shepard's formula. Original formula gives w(i) = sqr((R-di)/(R*di)), * where di is i-th distance, R is max(di). Modified formula have * following form: * w_mod(i) = 1, if di=d0 * w_mod(i) = w(i)/w(0), if di<>d0 * * NOTE 2: self-match is USED for this query * * NOTE 3: last point almost always gain zero weight, but it MUST * be used for fitting because sometimes it will gain NON-ZERO * weight - for example, when all distances are equal. */ r = z->rbuf.ptr.p_double[k-1]; d0 = z->rbuf.ptr.p_double[0]; result = (double)(0); s = (double)(0); for(i=0; i<=k-1; i++) { di = z->rbuf.ptr.p_double[i]; if( ae_fp_eq(di,d0) ) { /* * distance is equal to shortest, set it 1.0 * without explicitly calculating (which would give * us same result, but 'll expose us to the risk of * division by zero). */ w = (double)(1); } else { /* * use normalized formula */ v1 = (r-di)/(r-d0); v2 = d0/di; w = ae_sqr(v1*v2, _state); } result = result+w*idwint_idwcalcq(z, x, z->tbuf.ptr.p_int[i], _state); s = s+w; } result = result/s; return result; } /************************************************************************* IDW interpolant using modified Shepard method for uniform point distributions. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function type, either: * 0 constant model. Just for demonstration only, worst model ever. * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is significantly faster than linear/quadratic and better than constant model. But it is less robust (especially in the presence of noise). NQ - number of points used to calculate nodal functions (ignored for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, worst - with constant models * when N is large, NQ and NW must be significantly smaller than N both to obtain optimal performance and to obtain optimal accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be automatically decreased. * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small scales. If it isn't - for example, points are concentrated along "lines", but "lines" distribution is uniform at the larger scale - then you should use IDWBuildModifiedShepardR() -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepard(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t j2; ae_int_t j3; double v; double r; double s; double d0; double di; double v1; double v2; ae_int_t nc; ae_int_t offs; ae_vector x; ae_vector qrbuf; ae_matrix qxybuf; ae_vector y; ae_matrix fmatrix; ae_vector w; ae_vector qsol; ae_vector temp; ae_vector tags; ae_int_t info; double taskrcond; ae_frame_make(_state, &_frame_block); _idwinterpolant_clear(z); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&qrbuf, 0, DT_REAL, _state); ae_matrix_init(&qxybuf, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&qsol, 0, DT_REAL, _state); ae_vector_init(&temp, 0, DT_REAL, _state); ae_vector_init(&tags, 0, DT_INT, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ nc = 0; /* * assertions */ ae_assert(n>0, "IDWBuildModifiedShepard: N<=0!", _state); ae_assert(nx>=1, "IDWBuildModifiedShepard: NX<1!", _state); ae_assert(d>=-1&&d<=2, "IDWBuildModifiedShepard: D<>-1 and D<>0 and D<>1 and D<>2!", _state); /* * Correct parameters if needed */ if( d==1 ) { nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(1+nx), _state)+1, _state); nq = ae_maxint(nq, ae_round(ae_pow((double)(2), (double)(nx), _state), _state)+1, _state); } if( d==2 ) { nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(nx+2)*(nx+1)/2, _state)+1, _state); nq = ae_maxint(nq, ae_round(ae_pow((double)(2), (double)(nx), _state), _state)+1, _state); } nw = ae_maxint(nw, ae_round(ae_pow((double)(2), (double)(nx), _state), _state)+1, _state); nq = ae_minint(nq, n, _state); nw = ae_minint(nw, n, _state); /* * primary initialization of Z */ idwint_idwinit1(n, nx, d, nq, nw, z, _state); z->modeltype = 0; /* * Create KD-tree */ ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { tags.ptr.p_int[i] = i; } kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); /* * build nodal functions */ ae_vector_set_length(&temp, nq+1, _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&qrbuf, nq, _state); ae_matrix_set_length(&qxybuf, nq, nx+1, _state); if( d==-1 ) { ae_vector_set_length(&w, nq, _state); } if( d==1 ) { ae_vector_set_length(&y, nq, _state); ae_vector_set_length(&w, nq, _state); ae_vector_set_length(&qsol, nx, _state); /* * NX for linear members, * 1 for temporary storage */ ae_matrix_set_length(&fmatrix, nq, nx+1, _state); } if( d==2 ) { ae_vector_set_length(&y, nq, _state); ae_vector_set_length(&w, nq, _state); ae_vector_set_length(&qsol, nx+ae_round(nx*(nx+1)*0.5, _state), _state); /* * NX for linear members, * Round(NX*(NX+1)*0.5) for quadratic model, * 1 for temporary storage */ ae_matrix_set_length(&fmatrix, nq, nx+ae_round(nx*(nx+1)*0.5, _state)+1, _state); } for(i=0; i<=n-1; i++) { /* * Initialize center and function value. * If D=0 it is all what we need */ ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx)); if( d==0 ) { continue; } /* * calculate weights for linear/quadratic members calculation. * * NOTE 1: weights are calculated using NORMALIZED modified * Shepard's formula. Original formula is w(i) = sqr((R-di)/(R*di)), * where di is i-th distance, R is max(di). Modified formula have * following form: * w_mod(i) = 1, if di=d0 * w_mod(i) = w(i)/w(0), if di<>d0 * * NOTE 2: self-match is NOT used for this query * * NOTE 3: last point almost always gain zero weight, but it MUST * be used for fitting because sometimes it will gain NON-ZERO * weight - for example, when all distances are equal. */ ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); k = kdtreequeryknn(&z->tree, &x, nq, ae_false, _state); kdtreequeryresultsxy(&z->tree, &qxybuf, _state); kdtreequeryresultsdistances(&z->tree, &qrbuf, _state); r = qrbuf.ptr.p_double[k-1]; d0 = qrbuf.ptr.p_double[0]; for(j=0; j<=k-1; j++) { di = qrbuf.ptr.p_double[j]; if( ae_fp_eq(di,d0) ) { /* * distance is equal to shortest, set it 1.0 * without explicitly calculating (which would give * us same result, but 'll expose us to the risk of * division by zero). */ w.ptr.p_double[j] = (double)(1); } else { /* * use normalized formula */ v1 = (r-di)/(r-d0); v2 = d0/di; w.ptr.p_double[j] = ae_sqr(v1*v2, _state); } } /* * calculate linear/quadratic members */ if( d==-1 ) { /* * "Fast" linear nodal function calculated using * inverse distance weighting */ for(j=0; j<=nx-1; j++) { x.ptr.p_double[j] = (double)(0); } s = (double)(0); for(j=0; j<=k-1; j++) { /* * calculate J-th inverse distance weighted gradient: * grad_k = (y_j-y_k)*(x_j-x_k)/sqr(norm(x_j-x_k)) * grad = sum(wk*grad_k)/sum(w_k) */ v = (double)(0); for(j2=0; j2<=nx-1; j2++) { v = v+ae_sqr(qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2], _state); } /* * Although x_j<>x_k, sqr(norm(x_j-x_k)) may be zero due to * underflow. If it is, we assume than J-th gradient is zero * (i.e. don't add anything) */ if( ae_fp_neq(v,(double)(0)) ) { for(j2=0; j2<=nx-1; j2++) { x.ptr.p_double[j2] = x.ptr.p_double[j2]+w.ptr.p_double[j]*(qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx])*(qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])/v; } } s = s+w.ptr.p_double[j]; } for(j=0; j<=nx-1; j++) { z->q.ptr.pp_double[i][nx+1+j] = x.ptr.p_double[j]/s; } } else { /* * Least squares models: build */ if( d==1 ) { /* * Linear nodal function calculated using * least squares fitting to its neighbors */ for(j=0; j<=k-1; j++) { for(j2=0; j2<=nx-1; j2++) { fmatrix.ptr.pp_double[j][j2] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; } y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx]; } nc = nx; } if( d==2 ) { /* * Quadratic nodal function calculated using * least squares fitting to its neighbors */ for(j=0; j<=k-1; j++) { offs = 0; for(j2=0; j2<=nx-1; j2++) { fmatrix.ptr.pp_double[j][offs] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; offs = offs+1; } for(j2=0; j2<=nx-1; j2++) { for(j3=j2; j3<=nx-1; j3++) { fmatrix.ptr.pp_double[j][offs] = (qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])*(qxybuf.ptr.pp_double[j][j3]-xy->ptr.pp_double[i][j3]); offs = offs+1; } } y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx]; } nc = nx+ae_round(nx*(nx+1)*0.5, _state); } idwint_idwinternalsolver(&y, &w, &fmatrix, &temp, k, nc, &info, &qsol, &taskrcond, _state); /* * Least squares models: copy results */ if( info>0 ) { /* * LLS task is solved, copy results */ z->debugworstrcond = ae_minreal(z->debugworstrcond, taskrcond, _state); z->debugbestrcond = ae_maxreal(z->debugbestrcond, taskrcond, _state); for(j=0; j<=nc-1; j++) { z->q.ptr.pp_double[i][nx+1+j] = qsol.ptr.p_double[j]; } } else { /* * Solver failure, very strange, but we will use * zero values to handle it. */ z->debugsolverfailures = z->debugsolverfailures+1; for(j=0; j<=nc-1; j++) { z->q.ptr.pp_double[i][nx+1+j] = (double)(0); } } } } ae_frame_leave(_state); } /************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepardr(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, double r, idwinterpolant* z, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector tags; ae_frame_make(_state, &_frame_block); _idwinterpolant_clear(z); ae_vector_init(&tags, 0, DT_INT, _state); /* * assertions */ ae_assert(n>0, "IDWBuildModifiedShepardR: N<=0!", _state); ae_assert(nx>=1, "IDWBuildModifiedShepardR: NX<1!", _state); ae_assert(ae_fp_greater(r,(double)(0)), "IDWBuildModifiedShepardR: R<=0!", _state); /* * primary initialization of Z */ idwint_idwinit1(n, nx, 0, 0, n, z, _state); z->modeltype = 1; z->r = r; /* * Create KD-tree */ ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { tags.ptr.p_int[i] = i; } kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); /* * build nodal functions */ for(i=0; i<=n-1; i++) { ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx)); } ae_frame_leave(_state); } /************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildnoisy(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t j2; ae_int_t j3; double v; ae_int_t nc; ae_int_t offs; double taskrcond; ae_vector x; ae_vector qrbuf; ae_matrix qxybuf; ae_vector y; ae_vector w; ae_matrix fmatrix; ae_vector qsol; ae_vector tags; ae_vector temp; ae_int_t info; ae_frame_make(_state, &_frame_block); _idwinterpolant_clear(z); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&qrbuf, 0, DT_REAL, _state); ae_matrix_init(&qxybuf, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&qsol, 0, DT_REAL, _state); ae_vector_init(&tags, 0, DT_INT, _state); ae_vector_init(&temp, 0, DT_REAL, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ nc = 0; /* * assertions */ ae_assert(n>0, "IDWBuildNoisy: N<=0!", _state); ae_assert(nx>=1, "IDWBuildNoisy: NX<1!", _state); ae_assert(d>=1&&d<=2, "IDWBuildNoisy: D<>1 and D<>2!", _state); /* * Correct parameters if needed */ if( d==1 ) { nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(1+nx), _state)+1, _state); } if( d==2 ) { nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(nx+2)*(nx+1)/2, _state)+1, _state); } nw = ae_maxint(nw, ae_round(ae_pow((double)(2), (double)(nx), _state), _state)+1, _state); nq = ae_minint(nq, n, _state); nw = ae_minint(nw, n, _state); /* * primary initialization of Z */ idwint_idwinit1(n, nx, d, nq, nw, z, _state); z->modeltype = 0; /* * Create KD-tree */ ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { tags.ptr.p_int[i] = i; } kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); /* * build nodal functions * (special algorithm for noisy data is used) */ ae_vector_set_length(&temp, nq+1, _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&qrbuf, nq, _state); ae_matrix_set_length(&qxybuf, nq, nx+1, _state); if( d==1 ) { ae_vector_set_length(&y, nq, _state); ae_vector_set_length(&w, nq, _state); ae_vector_set_length(&qsol, 1+nx, _state); /* * 1 for constant member, * NX for linear members, * 1 for temporary storage */ ae_matrix_set_length(&fmatrix, nq, 1+nx+1, _state); } if( d==2 ) { ae_vector_set_length(&y, nq, _state); ae_vector_set_length(&w, nq, _state); ae_vector_set_length(&qsol, 1+nx+ae_round(nx*(nx+1)*0.5, _state), _state); /* * 1 for constant member, * NX for linear members, * Round(NX*(NX+1)*0.5) for quadratic model, * 1 for temporary storage */ ae_matrix_set_length(&fmatrix, nq, 1+nx+ae_round(nx*(nx+1)*0.5, _state)+1, _state); } for(i=0; i<=n-1; i++) { /* * Initialize center. */ ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); /* * Calculate linear/quadratic members * using least squares fit * NOTE 1: all weight are equal to 1.0 * NOTE 2: self-match is USED for this query */ ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); k = kdtreequeryknn(&z->tree, &x, nq, ae_true, _state); kdtreequeryresultsxy(&z->tree, &qxybuf, _state); kdtreequeryresultsdistances(&z->tree, &qrbuf, _state); if( d==1 ) { /* * Linear nodal function calculated using * least squares fitting to its neighbors */ for(j=0; j<=k-1; j++) { fmatrix.ptr.pp_double[j][0] = 1.0; for(j2=0; j2<=nx-1; j2++) { fmatrix.ptr.pp_double[j][1+j2] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; } y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]; w.ptr.p_double[j] = (double)(1); } nc = 1+nx; } if( d==2 ) { /* * Quadratic nodal function calculated using * least squares fitting to its neighbors */ for(j=0; j<=k-1; j++) { fmatrix.ptr.pp_double[j][0] = (double)(1); offs = 1; for(j2=0; j2<=nx-1; j2++) { fmatrix.ptr.pp_double[j][offs] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; offs = offs+1; } for(j2=0; j2<=nx-1; j2++) { for(j3=j2; j3<=nx-1; j3++) { fmatrix.ptr.pp_double[j][offs] = (qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])*(qxybuf.ptr.pp_double[j][j3]-xy->ptr.pp_double[i][j3]); offs = offs+1; } } y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]; w.ptr.p_double[j] = (double)(1); } nc = 1+nx+ae_round(nx*(nx+1)*0.5, _state); } idwint_idwinternalsolver(&y, &w, &fmatrix, &temp, k, nc, &info, &qsol, &taskrcond, _state); /* * Least squares models: copy results */ if( info>0 ) { /* * LLS task is solved, copy results */ z->debugworstrcond = ae_minreal(z->debugworstrcond, taskrcond, _state); z->debugbestrcond = ae_maxreal(z->debugbestrcond, taskrcond, _state); for(j=0; j<=nc-1; j++) { z->q.ptr.pp_double[i][nx+j] = qsol.ptr.p_double[j]; } } else { /* * Solver failure, very strange, but we will use * zero values to handle it. */ z->debugsolverfailures = z->debugsolverfailures+1; v = (double)(0); for(j=0; j<=k-1; j++) { v = v+qxybuf.ptr.pp_double[j][nx]; } z->q.ptr.pp_double[i][nx] = v/k; for(j=0; j<=nc-2; j++) { z->q.ptr.pp_double[i][nx+1+j] = (double)(0); } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine: K-th nodal function calculation -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ static double idwint_idwcalcq(idwinterpolant* z, /* Real */ ae_vector* x, ae_int_t k, ae_state *_state) { ae_int_t nx; ae_int_t i; ae_int_t j; ae_int_t offs; double result; nx = z->nx; /* * constant member */ result = z->q.ptr.pp_double[k][nx]; /* * linear members */ if( z->d>=1 ) { for(i=0; i<=nx-1; i++) { result = result+z->q.ptr.pp_double[k][nx+1+i]*(x->ptr.p_double[i]-z->q.ptr.pp_double[k][i]); } } /* * quadratic members */ if( z->d>=2 ) { offs = nx+1+nx; for(i=0; i<=nx-1; i++) { for(j=i; j<=nx-1; j++) { result = result+z->q.ptr.pp_double[k][offs]*(x->ptr.p_double[i]-z->q.ptr.pp_double[k][i])*(x->ptr.p_double[j]-z->q.ptr.pp_double[k][j]); offs = offs+1; } } } return result; } /************************************************************************* Initialization of internal structures. It assumes correctness of all parameters. -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ static void idwint_idwinit1(ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state) { z->debugsolverfailures = 0; z->debugworstrcond = 1.0; z->debugbestrcond = (double)(0); z->n = n; z->nx = nx; z->d = 0; if( d==1 ) { z->d = 1; } if( d==2 ) { z->d = 2; } if( d==-1 ) { z->d = 1; } z->nw = nw; if( d==-1 ) { ae_matrix_set_length(&z->q, n, nx+1+nx, _state); } if( d==0 ) { ae_matrix_set_length(&z->q, n, nx+1, _state); } if( d==1 ) { ae_matrix_set_length(&z->q, n, nx+1+nx, _state); } if( d==2 ) { ae_matrix_set_length(&z->q, n, nx+1+nx+ae_round(nx*(nx+1)*0.5, _state), _state); } ae_vector_set_length(&z->tbuf, nw, _state); ae_vector_set_length(&z->rbuf, nw, _state); ae_matrix_set_length(&z->xybuf, nw, nx+1, _state); ae_vector_set_length(&z->xbuf, nx, _state); } /************************************************************************* Linear least squares solver for small tasks. Works faster than standard ALGLIB solver in non-degenerate cases (due to absense of internal allocations and optimized row/colums). In degenerate cases it calls standard solver, which results in small performance penalty associated with preliminary steps. INPUT PARAMETERS: Y array[0..N-1] W array[0..N-1] FMatrix array[0..N-1,0..M], have additional column for temporary values Temp array[0..N] *************************************************************************/ static void idwint_idwinternalsolver(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_vector* temp, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* x, double* taskrcond, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double tau; ae_vector b; densesolverlsreport srep; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_init(&b, 0, DT_REAL, _state); _densesolverlsreport_init(&srep, _state); /* * set up info */ *info = 1; /* * prepare matrix */ for(i=0; i<=n-1; i++) { fmatrix->ptr.pp_double[i][m] = y->ptr.p_double[i]; v = w->ptr.p_double[i]; ae_v_muld(&fmatrix->ptr.pp_double[i][0], 1, ae_v_len(0,m), v); } /* * use either fast algorithm or general algorithm */ if( m<=n ) { /* * QR decomposition * We assume that M<=N (we would have called LSFit() otherwise) */ for(i=0; i<=m-1; i++) { if( iptr.p_double[1], 1, &fmatrix->ptr.pp_double[i][i], fmatrix->stride, ae_v_len(1,n-i)); generatereflection(temp, n-i, &tau, _state); fmatrix->ptr.pp_double[i][i] = temp->ptr.p_double[1]; temp->ptr.p_double[1] = (double)(1); for(j=i+1; j<=m; j++) { v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][j], fmatrix->stride, &temp->ptr.p_double[1], 1, ae_v_len(i,n-1)); v = tau*v; ae_v_subd(&fmatrix->ptr.pp_double[i][j], fmatrix->stride, &temp->ptr.p_double[1], 1, ae_v_len(i,n-1), v); } } } /* * Check condition number */ *taskrcond = rmatrixtrrcondinf(fmatrix, m, ae_true, ae_false, _state); /* * use either fast algorithm for non-degenerate cases * or slow algorithm for degenerate cases */ if( ae_fp_greater(*taskrcond,10000*n*ae_machineepsilon) ) { /* * solve triangular system R*x = FMatrix[0:M-1,M] * using fast algorithm, then exit */ x->ptr.p_double[m-1] = fmatrix->ptr.pp_double[m-1][m]/fmatrix->ptr.pp_double[m-1][m-1]; for(i=m-2; i>=0; i--) { v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][i+1], 1, &x->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1)); x->ptr.p_double[i] = (fmatrix->ptr.pp_double[i][m]-v)/fmatrix->ptr.pp_double[i][i]; } } else { /* * use more general algorithm */ ae_vector_set_length(&b, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=i-1; j++) { fmatrix->ptr.pp_double[i][j] = 0.0; } b.ptr.p_double[i] = fmatrix->ptr.pp_double[i][m]; } rmatrixsolvels(fmatrix, m, m, &b, 10000*ae_machineepsilon, info, &srep, x, _state); } } else { /* * use more general algorithm */ ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = fmatrix->ptr.pp_double[i][m]; } rmatrixsolvels(fmatrix, n, m, &b, 10000*ae_machineepsilon, info, &srep, x, _state); *taskrcond = srep.r2; } ae_frame_leave(_state); } void _idwinterpolant_init(void* _p, ae_state *_state) { idwinterpolant *p = (idwinterpolant*)_p; ae_touch_ptr((void*)p); _kdtree_init(&p->tree, _state); ae_matrix_init(&p->q, 0, 0, DT_REAL, _state); ae_vector_init(&p->xbuf, 0, DT_REAL, _state); ae_vector_init(&p->tbuf, 0, DT_INT, _state); ae_vector_init(&p->rbuf, 0, DT_REAL, _state); ae_matrix_init(&p->xybuf, 0, 0, DT_REAL, _state); } void _idwinterpolant_init_copy(void* _dst, void* _src, ae_state *_state) { idwinterpolant *dst = (idwinterpolant*)_dst; idwinterpolant *src = (idwinterpolant*)_src; dst->n = src->n; dst->nx = src->nx; dst->d = src->d; dst->r = src->r; dst->nw = src->nw; _kdtree_init_copy(&dst->tree, &src->tree, _state); dst->modeltype = src->modeltype; ae_matrix_init_copy(&dst->q, &src->q, _state); ae_vector_init_copy(&dst->xbuf, &src->xbuf, _state); ae_vector_init_copy(&dst->tbuf, &src->tbuf, _state); ae_vector_init_copy(&dst->rbuf, &src->rbuf, _state); ae_matrix_init_copy(&dst->xybuf, &src->xybuf, _state); dst->debugsolverfailures = src->debugsolverfailures; dst->debugworstrcond = src->debugworstrcond; dst->debugbestrcond = src->debugbestrcond; } void _idwinterpolant_clear(void* _p) { idwinterpolant *p = (idwinterpolant*)_p; ae_touch_ptr((void*)p); _kdtree_clear(&p->tree); ae_matrix_clear(&p->q); ae_vector_clear(&p->xbuf); ae_vector_clear(&p->tbuf); ae_vector_clear(&p->rbuf); ae_matrix_clear(&p->xybuf); } void _idwinterpolant_destroy(void* _p) { idwinterpolant *p = (idwinterpolant*)_p; ae_touch_ptr((void*)p); _kdtree_destroy(&p->tree); ae_matrix_destroy(&p->q); ae_vector_destroy(&p->xbuf); ae_vector_destroy(&p->tbuf); ae_vector_destroy(&p->rbuf); ae_matrix_destroy(&p->xybuf); } /************************************************************************* Rational interpolation using barycentric formula F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) Input parameters: B - barycentric interpolant built with one of model building subroutines. T - interpolation point Result: barycentric interpolant F(t) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ double barycentriccalc(barycentricinterpolant* b, double t, ae_state *_state) { double s1; double s2; double s; double v; ae_int_t i; double result; ae_assert(!ae_isinf(t, _state), "BarycentricCalc: infinite T!", _state); /* * special case: NaN */ if( ae_isnan(t, _state) ) { result = _state->v_nan; return result; } /* * special case: N=1 */ if( b->n==1 ) { result = b->sy*b->y.ptr.p_double[0]; return result; } /* * Here we assume that task is normalized, i.e.: * 1. abs(Y[i])<=1 * 2. abs(W[i])<=1 * 3. X[] is ordered */ s = ae_fabs(t-b->x.ptr.p_double[0], _state); for(i=0; i<=b->n-1; i++) { v = b->x.ptr.p_double[i]; if( ae_fp_eq(v,t) ) { result = b->sy*b->y.ptr.p_double[i]; return result; } v = ae_fabs(t-v, _state); if( ae_fp_less(v,s) ) { s = v; } } s1 = (double)(0); s2 = (double)(0); for(i=0; i<=b->n-1; i++) { v = s/(t-b->x.ptr.p_double[i]); v = v*b->w.ptr.p_double[i]; s1 = s1+v*b->y.ptr.p_double[i]; s2 = s2+v; } result = b->sy*s1/s2; return result; } /************************************************************************* Differentiation of barycentric interpolant: first derivative. Algorithm used in this subroutine is very robust and should not fail until provided with values too close to MaxRealNumber (usually MaxRealNumber/N or greater will overflow). INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative NOTE -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff1(barycentricinterpolant* b, double t, double* f, double* df, ae_state *_state) { double v; double vv; ae_int_t i; ae_int_t k; double n0; double n1; double d0; double d1; double s0; double s1; double xk; double xi; double xmin; double xmax; double xscale1; double xoffs1; double xscale2; double xoffs2; double xprev; *f = 0; *df = 0; ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); /* * special case: NaN */ if( ae_isnan(t, _state) ) { *f = _state->v_nan; *df = _state->v_nan; return; } /* * special case: N=1 */ if( b->n==1 ) { *f = b->sy*b->y.ptr.p_double[0]; *df = (double)(0); return; } if( ae_fp_eq(b->sy,(double)(0)) ) { *f = (double)(0); *df = (double)(0); return; } ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff1: internal error", _state); /* * We assume than N>1 and B.SY>0. Find: * 1. pivot point (X[i] closest to T) * 2. width of interval containing X[i] */ v = ae_fabs(b->x.ptr.p_double[0]-t, _state); k = 0; xmin = b->x.ptr.p_double[0]; xmax = b->x.ptr.p_double[0]; for(i=1; i<=b->n-1; i++) { vv = b->x.ptr.p_double[i]; if( ae_fp_less(ae_fabs(vv-t, _state),v) ) { v = ae_fabs(vv-t, _state); k = i; } xmin = ae_minreal(xmin, vv, _state); xmax = ae_maxreal(xmax, vv, _state); } /* * pivot point found, calculate dNumerator and dDenominator */ xscale1 = 1/(xmax-xmin); xoffs1 = -xmin/(xmax-xmin)+1; xscale2 = (double)(2); xoffs2 = (double)(-3); t = t*xscale1+xoffs1; t = t*xscale2+xoffs2; xk = b->x.ptr.p_double[k]; xk = xk*xscale1+xoffs1; xk = xk*xscale2+xoffs2; v = t-xk; n0 = (double)(0); n1 = (double)(0); d0 = (double)(0); d1 = (double)(0); xprev = (double)(-2); for(i=0; i<=b->n-1; i++) { xi = b->x.ptr.p_double[i]; xi = xi*xscale1+xoffs1; xi = xi*xscale2+xoffs2; ae_assert(ae_fp_greater(xi,xprev), "BarycentricDiff1: points are too close!", _state); xprev = xi; if( i!=k ) { vv = ae_sqr(t-xi, _state); s0 = (t-xk)/(t-xi); s1 = (xk-xi)/vv; } else { s0 = (double)(1); s1 = (double)(0); } vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; n0 = n0+s0*vv; n1 = n1+s1*vv; vv = b->w.ptr.p_double[i]; d0 = d0+s0*vv; d1 = d1+s1*vv; } *f = b->sy*n0/d0; *df = (n1*d0-n0*d1)/ae_sqr(d0, _state); if( ae_fp_neq(*df,(double)(0)) ) { *df = ae_sign(*df, _state)*ae_exp(ae_log(ae_fabs(*df, _state), _state)+ae_log(b->sy, _state)+ae_log(xscale1, _state)+ae_log(xscale2, _state), _state); } } /************************************************************************* Differentiation of barycentric interpolant: first/second derivatives. INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative D2F - second derivative NOTE: this algorithm may fail due to overflow/underflor if used on data whose values are close to MaxRealNumber or MinRealNumber. Use more robust BarycentricDiff1() subroutine in such cases. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff2(barycentricinterpolant* b, double t, double* f, double* df, double* d2f, ae_state *_state) { double v; double vv; ae_int_t i; ae_int_t k; double n0; double n1; double n2; double d0; double d1; double d2; double s0; double s1; double s2; double xk; double xi; *f = 0; *df = 0; *d2f = 0; ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); /* * special case: NaN */ if( ae_isnan(t, _state) ) { *f = _state->v_nan; *df = _state->v_nan; *d2f = _state->v_nan; return; } /* * special case: N=1 */ if( b->n==1 ) { *f = b->sy*b->y.ptr.p_double[0]; *df = (double)(0); *d2f = (double)(0); return; } if( ae_fp_eq(b->sy,(double)(0)) ) { *f = (double)(0); *df = (double)(0); *d2f = (double)(0); return; } /* * We assume than N>1 and B.SY>0. Find: * 1. pivot point (X[i] closest to T) * 2. width of interval containing X[i] */ ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff: internal error", _state); *f = (double)(0); *df = (double)(0); *d2f = (double)(0); v = ae_fabs(b->x.ptr.p_double[0]-t, _state); k = 0; for(i=1; i<=b->n-1; i++) { vv = b->x.ptr.p_double[i]; if( ae_fp_less(ae_fabs(vv-t, _state),v) ) { v = ae_fabs(vv-t, _state); k = i; } } /* * pivot point found, calculate dNumerator and dDenominator */ xk = b->x.ptr.p_double[k]; v = t-xk; n0 = (double)(0); n1 = (double)(0); n2 = (double)(0); d0 = (double)(0); d1 = (double)(0); d2 = (double)(0); for(i=0; i<=b->n-1; i++) { if( i!=k ) { xi = b->x.ptr.p_double[i]; vv = ae_sqr(t-xi, _state); s0 = (t-xk)/(t-xi); s1 = (xk-xi)/vv; s2 = -2*(xk-xi)/(vv*(t-xi)); } else { s0 = (double)(1); s1 = (double)(0); s2 = (double)(0); } vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; n0 = n0+s0*vv; n1 = n1+s1*vv; n2 = n2+s2*vv; vv = b->w.ptr.p_double[i]; d0 = d0+s0*vv; d1 = d1+s1*vv; d2 = d2+s2*vv; } *f = b->sy*n0/d0; *df = b->sy*(n1*d0-n0*d1)/ae_sqr(d0, _state); *d2f = b->sy*((n2*d0-n0*d2)*ae_sqr(d0, _state)-(n1*d0-n0*d1)*2*d0*d1)/ae_sqr(ae_sqr(d0, _state), _state); } /************************************************************************* This subroutine performs linear transformation of the argument. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: x = CA*t + CB OUTPUT PARAMETERS: B - transformed interpolant with X replaced by T -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransx(barycentricinterpolant* b, double ca, double cb, ae_state *_state) { ae_int_t i; ae_int_t j; double v; /* * special case, replace by constant F(CB) */ if( ae_fp_eq(ca,(double)(0)) ) { b->sy = barycentriccalc(b, cb, _state); v = (double)(1); for(i=0; i<=b->n-1; i++) { b->y.ptr.p_double[i] = (double)(1); b->w.ptr.p_double[i] = v; v = -v; } return; } /* * general case: CA<>0 */ for(i=0; i<=b->n-1; i++) { b->x.ptr.p_double[i] = (b->x.ptr.p_double[i]-cb)/ca; } if( ae_fp_less(ca,(double)(0)) ) { for(i=0; i<=b->n-1; i++) { if( in-1-i ) { j = b->n-1-i; v = b->x.ptr.p_double[i]; b->x.ptr.p_double[i] = b->x.ptr.p_double[j]; b->x.ptr.p_double[j] = v; v = b->y.ptr.p_double[i]; b->y.ptr.p_double[i] = b->y.ptr.p_double[j]; b->y.ptr.p_double[j] = v; v = b->w.ptr.p_double[i]; b->w.ptr.p_double[i] = b->w.ptr.p_double[j]; b->w.ptr.p_double[j] = v; } else { break; } } } } /************************************************************************* This subroutine performs linear transformation of the barycentric interpolant. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB OUTPUT PARAMETERS: B - transformed interpolant -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransy(barycentricinterpolant* b, double ca, double cb, ae_state *_state) { ae_int_t i; double v; for(i=0; i<=b->n-1; i++) { b->y.ptr.p_double[i] = ca*b->sy*b->y.ptr.p_double[i]+cb; } b->sy = (double)(0); for(i=0; i<=b->n-1; i++) { b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); } if( ae_fp_greater(b->sy,(double)(0)) ) { v = 1/b->sy; ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); } } /************************************************************************* Extracts X/Y/W arrays from rational interpolant INPUT PARAMETERS: B - barycentric interpolant OUTPUT PARAMETERS: N - nodes count, N>0 X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricunpack(barycentricinterpolant* b, ae_int_t* n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_state *_state) { double v; *n = 0; ae_vector_clear(x); ae_vector_clear(y); ae_vector_clear(w); *n = b->n; ae_vector_set_length(x, *n, _state); ae_vector_set_length(y, *n, _state); ae_vector_set_length(w, *n, _state); v = b->sy; ae_v_move(&x->ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,*n-1)); ae_v_moved(&y->ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,*n-1), v); ae_v_move(&w->ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,*n-1)); } /************************************************************************* Rational interpolant from X/Y/W arrays F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) INPUT PARAMETERS: X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] N - nodes count, N>0 OUTPUT PARAMETERS: B - barycentric interpolant built from (X, Y, W) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricbuildxyw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, barycentricinterpolant* b, ae_state *_state) { _barycentricinterpolant_clear(b); ae_assert(n>0, "BarycentricBuildXYW: incorrect N!", _state); /* * fill X/Y/W */ ae_vector_set_length(&b->x, n, _state); ae_vector_set_length(&b->y, n, _state); ae_vector_set_length(&b->w, n, _state); ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&b->w.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); b->n = n; /* * Normalize */ ratint_barycentricnormalize(b, _state); } /************************************************************************* Rational interpolant without poles The subroutine constructs the rational interpolating function without real poles (see 'Barycentric rational interpolation with no poles and high rates of approximation', Michael S. Floater. and Kai Hormann, for more information on this subject). Input parameters: X - interpolation nodes, array[0..N-1]. Y - function values, array[0..N-1]. N - number of nodes, N>0. D - order of the interpolation scheme, 0 <= D <= N-1. D<0 will cause an error. D>=N it will be replaced with D=N-1. if you don't know what D to choose, use small value about 3-5. Output parameters: B - barycentric interpolant. Note: this algorithm always succeeds and calculates the weights with close to machine precision. -- ALGLIB PROJECT -- Copyright 17.06.2007 by Bochkanov Sergey *************************************************************************/ void barycentricbuildfloaterhormann(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t d, barycentricinterpolant* b, ae_state *_state) { ae_frame _frame_block; double s0; double s; double v; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector perm; ae_vector wtemp; ae_vector sortrbuf; ae_vector sortrbuf2; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_clear(b); ae_vector_init(&perm, 0, DT_INT, _state); ae_vector_init(&wtemp, 0, DT_REAL, _state); ae_vector_init(&sortrbuf, 0, DT_REAL, _state); ae_vector_init(&sortrbuf2, 0, DT_REAL, _state); ae_assert(n>0, "BarycentricFloaterHormann: N<=0!", _state); ae_assert(d>=0, "BarycentricFloaterHormann: incorrect D!", _state); /* * Prepare */ if( d>n-1 ) { d = n-1; } b->n = n; /* * special case: N=1 */ if( n==1 ) { ae_vector_set_length(&b->x, n, _state); ae_vector_set_length(&b->y, n, _state); ae_vector_set_length(&b->w, n, _state); b->x.ptr.p_double[0] = x->ptr.p_double[0]; b->y.ptr.p_double[0] = y->ptr.p_double[0]; b->w.ptr.p_double[0] = (double)(1); ratint_barycentricnormalize(b, _state); ae_frame_leave(_state); return; } /* * Fill X/Y */ ae_vector_set_length(&b->x, n, _state); ae_vector_set_length(&b->y, n, _state); ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); tagsortfastr(&b->x, &b->y, &sortrbuf, &sortrbuf2, n, _state); /* * Calculate Wk */ ae_vector_set_length(&b->w, n, _state); s0 = (double)(1); for(k=1; k<=d; k++) { s0 = -s0; } for(k=0; k<=n-1; k++) { /* * Wk */ s = (double)(0); for(i=ae_maxint(k-d, 0, _state); i<=ae_minint(k, n-1-d, _state); i++) { v = (double)(1); for(j=i; j<=i+d; j++) { if( j!=k ) { v = v/ae_fabs(b->x.ptr.p_double[k]-b->x.ptr.p_double[j], _state); } } s = s+v; } b->w.ptr.p_double[k] = s0*s; /* * Next S0 */ s0 = -s0; } /* * Normalize */ ratint_barycentricnormalize(b, _state); ae_frame_leave(_state); } /************************************************************************* Copying of the barycentric interpolant (for internal use only) INPUT PARAMETERS: B - barycentric interpolant OUTPUT PARAMETERS: B2 - copy(B1) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriccopy(barycentricinterpolant* b, barycentricinterpolant* b2, ae_state *_state) { _barycentricinterpolant_clear(b2); b2->n = b->n; b2->sy = b->sy; ae_vector_set_length(&b2->x, b2->n, _state); ae_vector_set_length(&b2->y, b2->n, _state); ae_vector_set_length(&b2->w, b2->n, _state); ae_v_move(&b2->x.ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); ae_v_move(&b2->y.ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); ae_v_move(&b2->w.ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); } /************************************************************************* Normalization of barycentric interpolant: * B.N, B.X, B.Y and B.W are initialized * B.SY is NOT initialized * Y[] is normalized, scaling coefficient is stored in B.SY * W[] is normalized, no scaling coefficient is stored * X[] is sorted Internal subroutine. *************************************************************************/ static void ratint_barycentricnormalize(barycentricinterpolant* b, ae_state *_state) { ae_frame _frame_block; ae_vector p1; ae_vector p2; ae_int_t i; ae_int_t j; ae_int_t j2; double v; ae_frame_make(_state, &_frame_block); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * Normalize task: |Y|<=1, |W|<=1, sort X[] */ b->sy = (double)(0); for(i=0; i<=b->n-1; i++) { b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); } if( ae_fp_greater(b->sy,(double)(0))&&ae_fp_greater(ae_fabs(b->sy-1, _state),10*ae_machineepsilon) ) { v = 1/b->sy; ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); } v = (double)(0); for(i=0; i<=b->n-1; i++) { v = ae_maxreal(v, ae_fabs(b->w.ptr.p_double[i], _state), _state); } if( ae_fp_greater(v,(double)(0))&&ae_fp_greater(ae_fabs(v-1, _state),10*ae_machineepsilon) ) { v = 1/v; ae_v_muld(&b->w.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); } for(i=0; i<=b->n-2; i++) { if( ae_fp_less(b->x.ptr.p_double[i+1],b->x.ptr.p_double[i]) ) { tagsort(&b->x, b->n, &p1, &p2, _state); for(j=0; j<=b->n-1; j++) { j2 = p2.ptr.p_int[j]; v = b->y.ptr.p_double[j]; b->y.ptr.p_double[j] = b->y.ptr.p_double[j2]; b->y.ptr.p_double[j2] = v; v = b->w.ptr.p_double[j]; b->w.ptr.p_double[j] = b->w.ptr.p_double[j2]; b->w.ptr.p_double[j2] = v; } break; } } ae_frame_leave(_state); } void _barycentricinterpolant_init(void* _p, ae_state *_state) { barycentricinterpolant *p = (barycentricinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_vector_init(&p->w, 0, DT_REAL, _state); } void _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state) { barycentricinterpolant *dst = (barycentricinterpolant*)_dst; barycentricinterpolant *src = (barycentricinterpolant*)_src; dst->n = src->n; dst->sy = src->sy; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->w, &src->w, _state); } void _barycentricinterpolant_clear(void* _p) { barycentricinterpolant *p = (barycentricinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->y); ae_vector_clear(&p->w); } void _barycentricinterpolant_destroy(void* _p) { barycentricinterpolant *p = (barycentricinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->y); ae_vector_destroy(&p->w); } /************************************************************************* Conversion from barycentric representation to Chebyshev basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form A,B - base interval for Chebyshev polynomials (see below) A<>B OUTPUT PARAMETERS T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, where Ti - I-th Chebyshev polynomial. NOTES: barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2cheb(barycentricinterpolant* p, double a, double b, /* Real */ ae_vector* t, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; ae_vector vp; ae_vector vx; ae_vector tk; ae_vector tk1; double v; ae_frame_make(_state, &_frame_block); ae_vector_clear(t); ae_vector_init(&vp, 0, DT_REAL, _state); ae_vector_init(&vx, 0, DT_REAL, _state); ae_vector_init(&tk, 0, DT_REAL, _state); ae_vector_init(&tk1, 0, DT_REAL, _state); ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state); ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state); ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state); ae_assert(p->n>0, "PolynomialBar2Cheb: P is not correctly initialized barycentric interpolant!", _state); /* * Calculate function values on a Chebyshev grid */ ae_vector_set_length(&vp, p->n, _state); ae_vector_set_length(&vx, p->n, _state); for(i=0; i<=p->n-1; i++) { vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state); vp.ptr.p_double[i] = barycentriccalc(p, 0.5*(vx.ptr.p_double[i]+1)*(b-a)+a, _state); } /* * T[0] */ ae_vector_set_length(t, p->n, _state); v = (double)(0); for(i=0; i<=p->n-1; i++) { v = v+vp.ptr.p_double[i]; } t->ptr.p_double[0] = v/p->n; /* * other T's. * * NOTES: * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX * 2. we can do same calculations with fast DCT, but it * * adds dependencies * * still leaves us with O(N^2) algorithm because * preparation of function values is O(N^2) process */ if( p->n>1 ) { ae_vector_set_length(&tk, p->n, _state); ae_vector_set_length(&tk1, p->n, _state); for(i=0; i<=p->n-1; i++) { tk.ptr.p_double[i] = vx.ptr.p_double[i]; tk1.ptr.p_double[i] = (double)(1); } for(k=1; k<=p->n-1; k++) { /* * calculate discrete product of function vector and TK */ v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); t->ptr.p_double[k] = v/(0.5*p->n); /* * Update TK and TK1 */ for(i=0; i<=p->n-1; i++) { v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; tk1.ptr.p_double[i] = tk.ptr.p_double[i]; tk.ptr.p_double[i] = v; } } } ae_frame_leave(_state); } /************************************************************************* Conversion from Chebyshev basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, where Ti - I-th Chebyshev polynomial. N - number of coefficients: * if given, only leading N elements of T are used * if not given, automatically determined from size of T A,B - base interval for Chebyshev polynomials (see above) A=1, "PolynomialBar2Cheb: N<1", _state); ae_assert(t->cnt>=n, "PolynomialBar2Cheb: Length(T)ptr.p_double[0]; tk1 = (double)(1); tk = vx; for(k=1; k<=n-1; k++) { vy = vy+t->ptr.p_double[k]*tk; v = 2*vx*tk-tk1; tk1 = tk; tk = v; } y.ptr.p_double[i] = vy; } /* * Build barycentric interpolant, map grid from [-1,+1] to [A,B] */ polynomialbuildcheb1(a, b, &y, n, p, _state); ae_frame_leave(_state); } /************************************************************************* Conversion from barycentric representation to power basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if P was obtained as result of interpolation on [-1,+1], you can set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such representation can be obtained by using 1000.0 as offset C and 1.0 as scale S. 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return coefficients in any case, but for N>8 they will become unreliable. However, N's less than 5 are pretty safe. 3. barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2pow(barycentricinterpolant* p, double c, double s, /* Real */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; double e; double d; ae_vector vp; ae_vector vx; ae_vector tk; ae_vector tk1; ae_vector t; double v; double c0; double s0; double va; double vb; ae_vector vai; ae_vector vbi; double minx; double maxx; ae_frame_make(_state, &_frame_block); ae_vector_clear(a); ae_vector_init(&vp, 0, DT_REAL, _state); ae_vector_init(&vx, 0, DT_REAL, _state); ae_vector_init(&tk, 0, DT_REAL, _state); ae_vector_init(&tk1, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&vai, 0, DT_REAL, _state); ae_vector_init(&vbi, 0, DT_REAL, _state); /* * We have barycentric model built using set of points X[], and we * want to convert it to power basis centered about point C with * scale S: I-th basis function is ((X-C)/S)^i. * * We use following three-stage algorithm: * * 1. we build Chebyshev representation of polynomial using * intermediate center C0 and scale S0, which are derived from X[]: * C0 = 0.5*(min(X)+max(X)), S0 = 0.5*(max(X)-min(X)). Chebyshev * representation is built by sampling points around center C0, * with typical distance between them proportional to S0. * 2. then we transform form Chebyshev basis to intermediate power * basis, using same center/scale C0/S0. * 3. after that, we apply linear transformation to intermediate * power basis which moves it to final center/scale C/S. * * The idea of such multi-stage algorithm is that it is much easier to * transform barycentric model to Chebyshev basis, and only later to * power basis, than transforming it directly to power basis. It is * also more numerically stable to sample points using intermediate C0/S0, * which are derived from user-supplied model, than using "final" C/S, * which may be unsuitable for sampling (say, if S=1, we may have stability * problems when working with models built from dataset with non-unit * scale of abscissas). */ ae_assert(ae_isfinite(c, _state), "PolynomialBar2Pow: C is not finite!", _state); ae_assert(ae_isfinite(s, _state), "PolynomialBar2Pow: S is not finite!", _state); ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialBar2Pow: S=0!", _state); ae_assert(p->n>0, "PolynomialBar2Pow: P is not correctly initialized barycentric interpolant!", _state); /* * Select intermediate center/scale */ minx = p->x.ptr.p_double[0]; maxx = p->x.ptr.p_double[0]; for(i=1; i<=p->n-1; i++) { minx = ae_minreal(minx, p->x.ptr.p_double[i], _state); maxx = ae_maxreal(maxx, p->x.ptr.p_double[i], _state); } if( ae_fp_eq(minx,maxx) ) { c0 = minx; s0 = 1.0; } else { c0 = 0.5*(maxx+minx); s0 = 0.5*(maxx-minx); } /* * Calculate function values on a Chebyshev grid using intermediate C0/S0 */ ae_vector_set_length(&vp, p->n+1, _state); ae_vector_set_length(&vx, p->n, _state); for(i=0; i<=p->n-1; i++) { vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state); vp.ptr.p_double[i] = barycentriccalc(p, s0*vx.ptr.p_double[i]+c0, _state); } /* * T[0] */ ae_vector_set_length(&t, p->n, _state); v = (double)(0); for(i=0; i<=p->n-1; i++) { v = v+vp.ptr.p_double[i]; } t.ptr.p_double[0] = v/p->n; /* * other T's. * * NOTES: * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX * 2. we can do same calculations with fast DCT, but it * * adds dependencies * * still leaves us with O(N^2) algorithm because * preparation of function values is O(N^2) process */ if( p->n>1 ) { ae_vector_set_length(&tk, p->n, _state); ae_vector_set_length(&tk1, p->n, _state); for(i=0; i<=p->n-1; i++) { tk.ptr.p_double[i] = vx.ptr.p_double[i]; tk1.ptr.p_double[i] = (double)(1); } for(k=1; k<=p->n-1; k++) { /* * calculate discrete product of function vector and TK */ v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); t.ptr.p_double[k] = v/(0.5*p->n); /* * Update TK and TK1 */ for(i=0; i<=p->n-1; i++) { v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; tk1.ptr.p_double[i] = tk.ptr.p_double[i]; tk.ptr.p_double[i] = v; } } } /* * Convert from Chebyshev basis to power basis */ ae_vector_set_length(a, p->n, _state); for(i=0; i<=p->n-1; i++) { a->ptr.p_double[i] = (double)(0); } d = (double)(0); for(i=0; i<=p->n-1; i++) { for(k=i; k<=p->n-1; k++) { e = a->ptr.p_double[k]; a->ptr.p_double[k] = (double)(0); if( i<=1&&k==i ) { a->ptr.p_double[k] = (double)(1); } else { if( i!=0 ) { a->ptr.p_double[k] = 2*d; } if( k>i+1 ) { a->ptr.p_double[k] = a->ptr.p_double[k]-a->ptr.p_double[k-2]; } } d = e; } d = a->ptr.p_double[i]; e = (double)(0); k = i; while(k<=p->n-1) { e = e+a->ptr.p_double[k]*t.ptr.p_double[k]; k = k+2; } a->ptr.p_double[i] = e; } /* * Apply linear transformation which converts basis from intermediate * one Fi=((x-C0)/S0)^i to final one Fi=((x-C)/S)^i. * * We have y=(x-C0)/S0, z=(x-C)/S, and coefficients A[] for basis Fi(y). * Because we have y=A*z+B, for A=s/s0 and B=c/s0-c0/s0, we can perform * substitution and get coefficients A_new[] in basis Fi(z). */ ae_assert(vp.cnt>=p->n+1, "PolynomialBar2Pow: internal error", _state); ae_assert(t.cnt>=p->n, "PolynomialBar2Pow: internal error", _state); for(i=0; i<=p->n-1; i++) { t.ptr.p_double[i] = 0.0; } va = s/s0; vb = c/s0-c0/s0; ae_vector_set_length(&vai, p->n, _state); ae_vector_set_length(&vbi, p->n, _state); vai.ptr.p_double[0] = (double)(1); vbi.ptr.p_double[0] = (double)(1); for(k=1; k<=p->n-1; k++) { vai.ptr.p_double[k] = vai.ptr.p_double[k-1]*va; vbi.ptr.p_double[k] = vbi.ptr.p_double[k-1]*vb; } for(k=0; k<=p->n-1; k++) { /* * Generate set of binomial coefficients in VP[] */ if( k>0 ) { vp.ptr.p_double[k] = (double)(1); for(i=k-1; i>=1; i--) { vp.ptr.p_double[i] = vp.ptr.p_double[i]+vp.ptr.p_double[i-1]; } vp.ptr.p_double[0] = (double)(1); } else { vp.ptr.p_double[0] = (double)(1); } /* * Update T[] with expansion of K-th basis function */ for(i=0; i<=k; i++) { t.ptr.p_double[i] = t.ptr.p_double[i]+a->ptr.p_double[k]*vai.ptr.p_double[i]*vbi.ptr.p_double[k-i]*vp.ptr.p_double[i]; } } for(k=0; k<=p->n-1; k++) { a->ptr.p_double[k] = t.ptr.p_double[k]; } ae_frame_leave(_state); } /************************************************************************* Conversion from power basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) * if given, only leading N elements of A are used * if not given, automatically determined from size of A C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS P - polynomial in barycentric form NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if you interpolate on [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option (you have to specify 1000.0 as offset C and 1.0 as scale S). 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return barycentric model in any case, but for N>8 accuracy well degrade. However, N's less than 5 are pretty safe. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialpow2bar(/* Real */ ae_vector* a, ae_int_t n, double c, double s, barycentricinterpolant* p, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; ae_vector y; double vx; double vy; double px; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_clear(p); ae_vector_init(&y, 0, DT_REAL, _state); ae_assert(ae_isfinite(c, _state), "PolynomialPow2Bar: C is not finite!", _state); ae_assert(ae_isfinite(s, _state), "PolynomialPow2Bar: S is not finite!", _state); ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialPow2Bar: S is zero!", _state); ae_assert(n>=1, "PolynomialPow2Bar: N<1", _state); ae_assert(a->cnt>=n, "PolynomialPow2Bar: Length(A)ptr.p_double[0]; px = vx; for(k=1; k<=n-1; k++) { vy = vy+px*a->ptr.p_double[k]; px = px*vx; } y.ptr.p_double[i] = vy; } /* * Build barycentric interpolant, map grid from [-1,+1] to [A,B] */ polynomialbuildcheb1(c-s, c+s, &y, n, p, _state); ae_frame_leave(_state); } /************************************************************************* Lagrange intepolant: generation of the model on the general grid. This function has O(N^2) complexity. INPUT PARAMETERS: X - abscissas, array[0..N-1] Y - function values, array[0..N-1] N - number of points, N>=1 OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuild(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_int_t j; ae_int_t k; ae_vector w; double b; double a; double v; double mx; ae_vector sortrbuf; ae_vector sortrbuf2; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _barycentricinterpolant_clear(p); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&sortrbuf, 0, DT_REAL, _state); ae_vector_init(&sortrbuf2, 0, DT_REAL, _state); ae_assert(n>0, "PolynomialBuild: N<=0!", _state); ae_assert(x->cnt>=n, "PolynomialBuild: Length(X)cnt>=n, "PolynomialBuild: Length(Y)ptr.p_double[0]; b = x->ptr.p_double[0]; for(j=0; j<=n-1; j++) { w.ptr.p_double[j] = (double)(1); a = ae_minreal(a, x->ptr.p_double[j], _state); b = ae_maxreal(b, x->ptr.p_double[j], _state); } for(k=0; k<=n-1; k++) { /* * W[K] is used instead of 0.0 because * cycle on J does not touch K-th element * and we MUST get maximum from ALL elements */ mx = ae_fabs(w.ptr.p_double[k], _state); for(j=0; j<=n-1; j++) { if( j!=k ) { v = (b-a)/(x->ptr.p_double[j]-x->ptr.p_double[k]); w.ptr.p_double[j] = w.ptr.p_double[j]*v; mx = ae_maxreal(mx, ae_fabs(w.ptr.p_double[j], _state), _state); } } if( k%5==0 ) { /* * every 5-th run we renormalize W[] */ v = 1/mx; ae_v_muld(&w.ptr.p_double[0], 1, ae_v_len(0,n-1), v); } } barycentricbuildxyw(x, y, &w, n, p, _state); ae_frame_leave(_state); } /************************************************************************* Lagrange intepolant: generation of the model on equidistant grid. This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1] N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildeqdist(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector w; ae_vector x; double v; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_clear(p); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_assert(n>0, "PolynomialBuildEqDist: N<=0!", _state); ae_assert(y->cnt>=n, "PolynomialBuildEqDist: Length(Y)=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb1(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector w; ae_vector x; double v; double t; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_clear(p); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_assert(n>0, "PolynomialBuildCheb1: N<=0!", _state); ae_assert(y->cnt>=n, "PolynomialBuildCheb1: Length(Y)=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb2(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector w; ae_vector x; double v; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_clear(p); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_assert(n>0, "PolynomialBuildCheb2: N<=0!", _state); ae_assert(y->cnt>=n, "PolynomialBuildCheb2: Length(Y)=1 for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolynomialBuildEqDist()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalceqdist(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state) { double s1; double s2; double v; double threshold; double s; double h; ae_int_t i; ae_int_t j; double w; double x; double result; ae_assert(n>0, "PolynomialCalcEqDist: N<=0!", _state); ae_assert(f->cnt>=n, "PolynomialCalcEqDist: Length(F)v_nan; return result; } /* * Special case: N=1 */ if( n==1 ) { result = f->ptr.p_double[0]; return result; } /* * First, decide: should we use "safe" formula (guarded * against overflow) or fast one? */ threshold = ae_sqrt(ae_minrealnumber, _state); j = 0; s = t-a; for(i=1; i<=n-1; i++) { x = a+(double)i/(double)(n-1)*(b-a); if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) { s = t-x; j = i; } } if( ae_fp_eq(s,(double)(0)) ) { result = f->ptr.p_double[j]; return result; } if( ae_fp_greater(ae_fabs(s, _state),threshold) ) { /* * use fast formula */ j = -1; s = 1.0; } /* * Calculate using safe or fast barycentric formula */ s1 = (double)(0); s2 = (double)(0); w = 1.0; h = (b-a)/(n-1); for(i=0; i<=n-1; i++) { if( i!=j ) { v = s*w/(t-(a+i*h)); s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } else { v = w; s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } w = -w*(n-1-i); w = w/(i+1); } result = s1/s2; return result; } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (first kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (first kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb1()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb1(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state) { double s1; double s2; double v; double threshold; double s; ae_int_t i; ae_int_t j; double a0; double delta; double alpha; double beta; double ca; double sa; double tempc; double temps; double x; double w; double p1; double result; ae_assert(n>0, "PolynomialCalcCheb1: N<=0!", _state); ae_assert(f->cnt>=n, "PolynomialCalcCheb1: Length(F)v_nan; return result; } /* * Special case: N=1 */ if( n==1 ) { result = f->ptr.p_double[0]; return result; } /* * Prepare information for the recurrence formula * used to calculate sin(pi*(2j+1)/(2n+2)) and * cos(pi*(2j+1)/(2n+2)): * * A0 = pi/(2n+2) * Delta = pi/(n+1) * Alpha = 2 sin^2 (Delta/2) * Beta = sin(Delta) * * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). * Then we use * * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) * * to repeatedly calculate sin(..) and cos(..). */ threshold = ae_sqrt(ae_minrealnumber, _state); t = (t-0.5*(a+b))/(0.5*(b-a)); a0 = ae_pi/(2*(n-1)+2); delta = 2*ae_pi/(2*(n-1)+2); alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state); beta = ae_sin(delta, _state); /* * First, decide: should we use "safe" formula (guarded * against overflow) or fast one? */ ca = ae_cos(a0, _state); sa = ae_sin(a0, _state); j = 0; x = ca; s = t-x; for(i=1; i<=n-1; i++) { /* * Next X[i] */ temps = sa-(alpha*sa-beta*ca); tempc = ca-(alpha*ca+beta*sa); sa = temps; ca = tempc; x = ca; /* * Use X[i] */ if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) { s = t-x; j = i; } } if( ae_fp_eq(s,(double)(0)) ) { result = f->ptr.p_double[j]; return result; } if( ae_fp_greater(ae_fabs(s, _state),threshold) ) { /* * use fast formula */ j = -1; s = 1.0; } /* * Calculate using safe or fast barycentric formula */ s1 = (double)(0); s2 = (double)(0); ca = ae_cos(a0, _state); sa = ae_sin(a0, _state); p1 = 1.0; for(i=0; i<=n-1; i++) { /* * Calculate X[i], W[i] */ x = ca; w = p1*sa; /* * Proceed */ if( i!=j ) { v = s*w/(t-x); s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } else { v = w; s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } /* * Next CA, SA, P1 */ temps = sa-(alpha*sa-beta*ca); tempc = ca-(alpha*ca+beta*sa); sa = temps; ca = tempc; p1 = -p1; } result = s1/s2; return result; } /************************************************************************* Fast polynomial interpolation function on Chebyshev points (second kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (second kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb2()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb2(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state) { double s1; double s2; double v; double threshold; double s; ae_int_t i; ae_int_t j; double a0; double delta; double alpha; double beta; double ca; double sa; double tempc; double temps; double x; double w; double p1; double result; ae_assert(n>0, "PolynomialCalcCheb2: N<=0!", _state); ae_assert(f->cnt>=n, "PolynomialCalcCheb2: Length(F)v_nan; return result; } /* * Special case: N=1 */ if( n==1 ) { result = f->ptr.p_double[0]; return result; } /* * Prepare information for the recurrence formula * used to calculate sin(pi*i/n) and * cos(pi*i/n): * * A0 = 0 * Delta = pi/n * Alpha = 2 sin^2 (Delta/2) * Beta = sin(Delta) * * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). * Then we use * * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) * * to repeatedly calculate sin(..) and cos(..). */ threshold = ae_sqrt(ae_minrealnumber, _state); t = (t-0.5*(a+b))/(0.5*(b-a)); a0 = 0.0; delta = ae_pi/(n-1); alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state); beta = ae_sin(delta, _state); /* * First, decide: should we use "safe" formula (guarded * against overflow) or fast one? */ ca = ae_cos(a0, _state); sa = ae_sin(a0, _state); j = 0; x = ca; s = t-x; for(i=1; i<=n-1; i++) { /* * Next X[i] */ temps = sa-(alpha*sa-beta*ca); tempc = ca-(alpha*ca+beta*sa); sa = temps; ca = tempc; x = ca; /* * Use X[i] */ if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) { s = t-x; j = i; } } if( ae_fp_eq(s,(double)(0)) ) { result = f->ptr.p_double[j]; return result; } if( ae_fp_greater(ae_fabs(s, _state),threshold) ) { /* * use fast formula */ j = -1; s = 1.0; } /* * Calculate using safe or fast barycentric formula */ s1 = (double)(0); s2 = (double)(0); ca = ae_cos(a0, _state); sa = ae_sin(a0, _state); p1 = 1.0; for(i=0; i<=n-1; i++) { /* * Calculate X[i], W[i] */ x = ca; if( i==0||i==n-1 ) { w = 0.5*p1; } else { w = 1.0*p1; } /* * Proceed */ if( i!=j ) { v = s*w/(t-x); s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } else { v = w; s1 = s1+v*f->ptr.p_double[i]; s2 = s2+v; } /* * Next CA, SA, P1 */ temps = sa-(alpha*sa-beta*ca); tempc = ca-(alpha*ca+beta*sa); sa = temps; ca = tempc; p1 = -p1; } result = s1/s2; return result; } /************************************************************************* This subroutine builds linear spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildlinear(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _spline1dinterpolant_clear(c); ae_assert(n>1, "Spline1DBuildLinear: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DBuildLinear: Length(X)cnt>=n, "Spline1DBuildLinear: Length(Y)periodic = ae_false; c->n = n; c->k = 3; c->continuity = 0; ae_vector_set_length(&c->x, n, _state); ae_vector_set_length(&c->c, 4*(n-1)+2, _state); for(i=0; i<=n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i]; c->c.ptr.p_double[4*i+1] = (y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]); c->c.ptr.p_double[4*i+2] = (double)(0); c->c.ptr.p_double[4*i+3] = (double)(0); } c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1]; c->c.ptr.p_double[4*(n-1)+1] = c->c.ptr.p_double[4*(n-2)+1]; ae_frame_leave(_state); } /************************************************************************* This subroutine builds cubic spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector dt; ae_vector d; ae_vector p; ae_int_t ylen; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _spline1dinterpolant_clear(c); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DBuildCubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DBuildCubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DBuildCubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DBuildCubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DBuildCubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DBuildCubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DBuildCubic: Length(X)cnt>=n, "Spline1DBuildCubic: Length(Y)ptr.p_double[n-1] = y->ptr.p_double[0]; } spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); spline1dbuildhermite(x, y, &d, n, c, _state); c->periodic = boundltype==-1||boundrtype==-1; c->continuity = 2; ae_frame_leave(_state); } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns table of function derivatives d[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D - derivative values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiffcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector dt; ae_vector p; ae_int_t i; ae_int_t ylen; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_clear(d); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiffCubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiffCubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiffCubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiffCubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiffCubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DGridDiffCubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DGridDiffCubic: Length(X)cnt>=n, "Spline1DGridDiffCubic: Length(Y)ptr.p_double[i]; } ae_v_move(&d->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns tables of first and second function derivatives d1[] and d2[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D1 - S' values at X[] D2 - S'' values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiff2cubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d1, /* Real */ ae_vector* d2, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector dt; ae_vector p; ae_int_t i; ae_int_t ylen; double delta; double delta2; double delta3; double s2; double s3; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_clear(d1); ae_vector_clear(d2); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiff2Cubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiff2Cubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiff2Cubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiff2Cubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiff2Cubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DGridDiff2Cubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DGridDiff2Cubic: Length(X)cnt>=n, "Spline1DGridDiff2Cubic: Length(Y)ptr.p_double[i+1]-x->ptr.p_double[i]; delta2 = ae_sqr(delta, _state); delta3 = delta*delta2; s2 = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d1->ptr.p_double[i]*delta-d1->ptr.p_double[i+1]*delta)/delta2; s3 = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d1->ptr.p_double[i]*delta+d1->ptr.p_double[i+1]*delta)/delta3; d2->ptr.p_double[i] = 2*s2; } d2->ptr.p_double[n-1] = 2*s2+6*s3*delta; /* * Remember that HeapSortPPoints() call? * Now we have to reorder them back. */ if( dt.cntptr.p_double[i]; } ae_v_move(&d1->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { dt.ptr.p_double[p.ptr.p_int[i]] = d2->ptr.p_double[i]; } ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _x2; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector d; ae_vector dt; ae_vector d1; ae_vector d2; ae_vector p; ae_vector p2; ae_int_t i; ae_int_t ylen; double t; double t2; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_x2, x2, _state); x2 = &_x2; ae_vector_clear(y2); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&d2, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvCubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvCubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvCubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DConvCubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DConvCubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DConvCubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DConvCubic: Length(X)cnt>=n, "Spline1DConvCubic: Length(Y)=2, "Spline1DConvCubic: N2<2!", _state); ae_assert(x2->cnt>=n2, "Spline1DConvCubic: Length(X2)ptr.p_double[i]; apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); x2->ptr.p_double[i] = t; } } spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); /* * Now we've checked and preordered everything, so we: * * call internal GridDiff() function to get Hermite form of spline * * convert using internal Conv() function * * convert Y2 back to original order */ spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, &d1, ae_false, &d2, ae_false, _state); ae_assert(dt.cnt>=n2, "Spline1DConvCubic: internal error!", _state); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; } ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); ae_frame_leave(_state); } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] and derivatives d2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiffcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, /* Real */ ae_vector* d2, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _x2; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector d; ae_vector dt; ae_vector rt1; ae_vector p; ae_vector p2; ae_int_t i; ae_int_t ylen; double t; double t2; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_x2, x2, _state); x2 = &_x2; ae_vector_clear(y2); ae_vector_clear(d2); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&rt1, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiffCubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiffCubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiffCubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiffCubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiffCubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DConvDiffCubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DConvDiffCubic: Length(X)cnt>=n, "Spline1DConvDiffCubic: Length(Y)=2, "Spline1DConvDiffCubic: N2<2!", _state); ae_assert(x2->cnt>=n2, "Spline1DConvDiffCubic: Length(X2)ptr.p_double[i]; apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); x2->ptr.p_double[i] = t; } } spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); /* * Now we've checked and preordered everything, so we: * * call internal GridDiff() function to get Hermite form of spline * * convert using internal Conv() function * * convert Y2 back to original order */ spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, &rt1, ae_false, _state); ae_assert(dt.cnt>=n2, "Spline1DConvDiffCubic: internal error!", _state); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; } ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; } ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); ae_frame_leave(_state); } /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[], first and second derivatives d2[] and dd2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] DD2 - second derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiff2cubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, /* Real */ ae_vector* d2, /* Real */ ae_vector* dd2, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _x2; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector b; ae_vector d; ae_vector dt; ae_vector p; ae_vector p2; ae_int_t i; ae_int_t ylen; double t; double t2; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_x2, x2, _state); x2 = &_x2; ae_vector_clear(y2); ae_vector_clear(d2); ae_vector_clear(dd2); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&dt, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * check correctness of boundary conditions */ ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiff2Cubic: incorrect BoundLType!", _state); ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiff2Cubic: incorrect BoundRType!", _state); ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiff2Cubic: incorrect BoundLType/BoundRType!", _state); if( boundltype==1||boundltype==2 ) { ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiff2Cubic: BoundL is infinite or NAN!", _state); } if( boundrtype==1||boundrtype==2 ) { ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiff2Cubic: BoundR is infinite or NAN!", _state); } /* * check lengths of arguments */ ae_assert(n>=2, "Spline1DConvDiff2Cubic: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DConvDiff2Cubic: Length(X)cnt>=n, "Spline1DConvDiff2Cubic: Length(Y)=2, "Spline1DConvDiff2Cubic: N2<2!", _state); ae_assert(x2->cnt>=n2, "Spline1DConvDiff2Cubic: Length(X2)ptr.p_double[i]; apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); x2->ptr.p_double[i] = t; } } spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); /* * Now we've checked and preordered everything, so we: * * call internal GridDiff() function to get Hermite form of spline * * convert using internal Conv() function * * convert Y2 back to original order */ spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, dd2, ae_true, _state); ae_assert(dt.cnt>=n2, "Spline1DConvDiff2Cubic: internal error!", _state); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; } ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; } ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); for(i=0; i<=n2-1; i++) { dt.ptr.p_double[p2.ptr.p_int[i]] = dd2->ptr.p_double[i]; } ae_v_move(&dd2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); ae_frame_leave(_state); } /************************************************************************* This subroutine builds Catmull-Rom spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundType - boundary condition type: * -1 for periodic boundary condition * 0 for parabolically terminated spline (default) Tension - tension parameter: * tension=0 corresponds to classic Catmull-Rom spline (default) * 0=2, "Spline1DBuildCatmullRom: N<2!", _state); ae_assert(boundtype==-1||boundtype==0, "Spline1DBuildCatmullRom: incorrect BoundType!", _state); ae_assert(ae_fp_greater_eq(tension,(double)(0)), "Spline1DBuildCatmullRom: Tension<0!", _state); ae_assert(ae_fp_less_eq(tension,(double)(1)), "Spline1DBuildCatmullRom: Tension>1!", _state); ae_assert(x->cnt>=n, "Spline1DBuildCatmullRom: Length(X)cnt>=n, "Spline1DBuildCatmullRom: Length(Y)ptr.p_double[n-1] = y->ptr.p_double[0]; ae_vector_set_length(&d, n, _state); d.ptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[n-2])/(2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2])); for(i=1; i<=n-2; i++) { d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); } d.ptr.p_double[n-1] = d.ptr.p_double[0]; /* * Now problem is reduced to the cubic Hermite spline */ spline1dbuildhermite(x, y, &d, n, c, _state); c->periodic = ae_true; } else { /* * Non-periodic boundary conditions */ ae_vector_set_length(&d, n, _state); for(i=1; i<=n-2; i++) { d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); } d.ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-d.ptr.p_double[1]; d.ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])-d.ptr.p_double[n-2]; /* * Now problem is reduced to the cubic Hermite spline */ spline1dbuildhermite(x, y, &d, n, c, _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine builds Hermite spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] D - derivatives, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildhermite(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* d, ae_int_t n, spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _d; ae_int_t i; double delta; double delta2; double delta3; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_d, d, _state); d = &_d; _spline1dinterpolant_clear(c); ae_assert(n>=2, "Spline1DBuildHermite: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DBuildHermite: Length(X)cnt>=n, "Spline1DBuildHermite: Length(Y)cnt>=n, "Spline1DBuildHermite: Length(D)x, n, _state); ae_vector_set_length(&c->c, 4*(n-1)+2, _state); c->periodic = ae_false; c->k = 3; c->n = n; c->continuity = 1; for(i=0; i<=n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { delta = x->ptr.p_double[i+1]-x->ptr.p_double[i]; delta2 = ae_sqr(delta, _state); delta3 = delta*delta2; c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i]; c->c.ptr.p_double[4*i+1] = d->ptr.p_double[i]; c->c.ptr.p_double[4*i+2] = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d->ptr.p_double[i]*delta-d->ptr.p_double[i+1]*delta)/delta2; c->c.ptr.p_double[4*i+3] = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d->ptr.p_double[i]*delta+d->ptr.p_double[i+1]*delta)/delta3; } c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1]; c->c.ptr.p_double[4*(n-1)+1] = d->ptr.p_double[n-1]; ae_frame_leave(_state); } /************************************************************************* This subroutine builds Akima spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildakima(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_int_t i; ae_vector d; ae_vector w; ae_vector diff; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _spline1dinterpolant_clear(c); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&diff, 0, DT_REAL, _state); ae_assert(n>=2, "Spline1DBuildAkima: N<2!", _state); ae_assert(x->cnt>=n, "Spline1DBuildAkima: Length(X)cnt>=n, "Spline1DBuildAkima: Length(Y)ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]); } for(i=1; i<=n-2; i++) { w.ptr.p_double[i] = ae_fabs(diff.ptr.p_double[i]-diff.ptr.p_double[i-1], _state); } /* * Prepare Hermite interpolation scheme */ ae_vector_set_length(&d, n, _state); for(i=2; i<=n-3; i++) { if( ae_fp_neq(ae_fabs(w.ptr.p_double[i-1], _state)+ae_fabs(w.ptr.p_double[i+1], _state),(double)(0)) ) { d.ptr.p_double[i] = (w.ptr.p_double[i+1]*diff.ptr.p_double[i-1]+w.ptr.p_double[i-1]*diff.ptr.p_double[i])/(w.ptr.p_double[i+1]+w.ptr.p_double[i-1]); } else { d.ptr.p_double[i] = ((x->ptr.p_double[i+1]-x->ptr.p_double[i])*diff.ptr.p_double[i-1]+(x->ptr.p_double[i]-x->ptr.p_double[i-1])*diff.ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); } } d.ptr.p_double[0] = spline1d_diffthreepoint(x->ptr.p_double[0], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state); d.ptr.p_double[1] = spline1d_diffthreepoint(x->ptr.p_double[1], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state); d.ptr.p_double[n-2] = spline1d_diffthreepoint(x->ptr.p_double[n-2], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state); d.ptr.p_double[n-1] = spline1d_diffthreepoint(x->ptr.p_double[n-1], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state); /* * Build Akima spline using Hermite interpolation scheme */ spline1dbuildhermite(x, y, &d, n, c, _state); ae_frame_leave(_state); } /************************************************************************* This subroutine calculates the value of the spline at the given point X. INPUT PARAMETERS: C - spline interpolant X - point Result: S(x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state) { ae_int_t l; ae_int_t r; ae_int_t m; double t; double result; ae_assert(c->k==3, "Spline1DCalc: internal error", _state); ae_assert(!ae_isinf(x, _state), "Spline1DCalc: infinite X!", _state); /* * special case: NaN */ if( ae_isnan(x, _state) ) { result = _state->v_nan; return result; } /* * correct if periodic */ if( c->periodic ) { apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); } /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = c->n-2+1; while(l!=r-1) { m = (l+r)/2; if( c->x.ptr.p_double[m]>=x ) { r = m; } else { l = m; } } /* * Interpolation */ x = x-c->x.ptr.p_double[l]; m = 4*l; result = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); return result; } /************************************************************************* This subroutine differentiates the spline. INPUT PARAMETERS: C - spline interpolant. X - point Result: S - S(x) DS - S'(x) D2S - S''(x) -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1ddiff(spline1dinterpolant* c, double x, double* s, double* ds, double* d2s, ae_state *_state) { ae_int_t l; ae_int_t r; ae_int_t m; double t; *s = 0; *ds = 0; *d2s = 0; ae_assert(c->k==3, "Spline1DDiff: internal error", _state); ae_assert(!ae_isinf(x, _state), "Spline1DDiff: infinite X!", _state); /* * special case: NaN */ if( ae_isnan(x, _state) ) { *s = _state->v_nan; *ds = _state->v_nan; *d2s = _state->v_nan; return; } /* * correct if periodic */ if( c->periodic ) { apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); } /* * Binary search */ l = 0; r = c->n-2+1; while(l!=r-1) { m = (l+r)/2; if( c->x.ptr.p_double[m]>=x ) { r = m; } else { l = m; } } /* * Differentiation */ x = x-c->x.ptr.p_double[l]; m = 4*l; *s = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); *ds = c->c.ptr.p_double[m+1]+2*x*c->c.ptr.p_double[m+2]+3*ae_sqr(x, _state)*c->c.ptr.p_double[m+3]; *d2s = 2*c->c.ptr.p_double[m+2]+6*x*c->c.ptr.p_double[m+3]; } /************************************************************************* This subroutine makes the copy of the spline. INPUT PARAMETERS: C - spline interpolant. Result: CC - spline copy -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dcopy(spline1dinterpolant* c, spline1dinterpolant* cc, ae_state *_state) { ae_int_t s; _spline1dinterpolant_clear(cc); cc->periodic = c->periodic; cc->n = c->n; cc->k = c->k; cc->continuity = c->continuity; ae_vector_set_length(&cc->x, cc->n, _state); ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); s = c->c.cnt; ae_vector_set_length(&cc->c, s, _state); ae_v_move(&cc->c.ptr.p_double[0], 1, &c->c.ptr.p_double[0], 1, ae_v_len(0,s-1)); } /************************************************************************* This subroutine unpacks the spline into the coefficients table. INPUT PARAMETERS: C - spline interpolant. X - point OUTPUT PARAMETERS: Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. For I = 0...N-2: Tbl[I,0] = X[i] Tbl[I,1] = X[i+1] Tbl[I,2] = C0 Tbl[I,3] = C1 Tbl[I,4] = C2 Tbl[I,5] = C3 On [x[i], x[i+1]] spline is equals to: S(x) = C0 + C1*t + C2*t^2 + C3*t^3 t = x-x[i] NOTE: You can rebuild spline with Spline1DBuildHermite() function, which accepts as inputs function values and derivatives at nodes, which are easy to calculate when you have coefficients. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dunpack(spline1dinterpolant* c, ae_int_t* n, /* Real */ ae_matrix* tbl, ae_state *_state) { ae_int_t i; ae_int_t j; *n = 0; ae_matrix_clear(tbl); ae_matrix_set_length(tbl, c->n-2+1, 2+c->k+1, _state); *n = c->n; /* * Fill */ for(i=0; i<=*n-2; i++) { tbl->ptr.pp_double[i][0] = c->x.ptr.p_double[i]; tbl->ptr.pp_double[i][1] = c->x.ptr.p_double[i+1]; for(j=0; j<=c->k; j++) { tbl->ptr.pp_double[i][2+j] = c->c.ptr.p_double[(c->k+1)*i+j]; } } } /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: x = A*t + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransx(spline1dinterpolant* c, double a, double b, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t n; double v; double dv; double d2v; ae_vector x; ae_vector y; ae_vector d; ae_bool isperiodic; ae_int_t contval; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); n = c->n; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&d, n, _state); /* * Unpack, X, Y, dY/dX. * Scale and pack with Spline1DBuildHermite again. */ if( ae_fp_eq(a,(double)(0)) ) { /* * Special case: A=0 */ v = spline1dcalc(c, b, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = c->x.ptr.p_double[i]; y.ptr.p_double[i] = v; d.ptr.p_double[i] = 0.0; } } else { /* * General case, A<>0 */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = c->x.ptr.p_double[i]; spline1ddiff(c, x.ptr.p_double[i], &v, &dv, &d2v, _state); x.ptr.p_double[i] = (x.ptr.p_double[i]-b)/a; y.ptr.p_double[i] = v; d.ptr.p_double[i] = a*dv; } } isperiodic = c->periodic; contval = c->continuity; if( contval>0 ) { spline1dbuildhermite(&x, &y, &d, n, c, _state); } else { spline1dbuildlinear(&x, &y, n, c, _state); } c->periodic = isperiodic; c->continuity = contval; ae_frame_leave(_state); } /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x) = A*S(x) + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransy(spline1dinterpolant* c, double a, double b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); n = c->n; for(i=0; i<=n-2; i++) { c->c.ptr.p_double[4*i] = a*c->c.ptr.p_double[4*i]+b; for(j=1; j<=3; j++) { c->c.ptr.p_double[4*i+j] = a*c->c.ptr.p_double[4*i+j]; } } c->c.ptr.p_double[4*(n-1)+0] = a*c->c.ptr.p_double[4*(n-1)+0]+b; c->c.ptr.p_double[4*(n-1)+1] = a*c->c.ptr.p_double[4*(n-1)+1]; } /************************************************************************* This subroutine integrates the spline. INPUT PARAMETERS: C - spline interpolant. X - right bound of the integration interval [a, x], here 'a' denotes min(x[]) Result: integral(S(t)dt,a,x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dintegrate(spline1dinterpolant* c, double x, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t l; ae_int_t r; ae_int_t m; double w; double v; double t; double intab; double additionalterm; double result; n = c->n; /* * Periodic splines require special treatment. We make * following transformation: * * integral(S(t)dt,A,X) = integral(S(t)dt,A,Z)+AdditionalTerm * * here X may lie outside of [A,B], Z lies strictly in [A,B], * AdditionalTerm is equals to integral(S(t)dt,A,B) times some * integer number (may be zero). */ if( c->periodic&&(ae_fp_less(x,c->x.ptr.p_double[0])||ae_fp_greater(x,c->x.ptr.p_double[c->n-1])) ) { /* * compute integral(S(x)dx,A,B) */ intab = (double)(0); for(i=0; i<=c->n-2; i++) { w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; m = (c->k+1)*i; intab = intab+c->c.ptr.p_double[m]*w; v = w; for(j=1; j<=c->k; j++) { v = v*w; intab = intab+c->c.ptr.p_double[m+j]*v/(j+1); } } /* * map X into [A,B] */ apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); additionalterm = t*intab; } else { additionalterm = (double)(0); } /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = n-2+1; while(l!=r-1) { m = (l+r)/2; if( ae_fp_greater_eq(c->x.ptr.p_double[m],x) ) { r = m; } else { l = m; } } /* * Integration */ result = (double)(0); for(i=0; i<=l-1; i++) { w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; m = (c->k+1)*i; result = result+c->c.ptr.p_double[m]*w; v = w; for(j=1; j<=c->k; j++) { v = v*w; result = result+c->c.ptr.p_double[m+j]*v/(j+1); } } w = x-c->x.ptr.p_double[l]; m = (c->k+1)*l; v = w; result = result+c->c.ptr.p_double[m]*w; for(j=1; j<=c->k; j++) { v = v*w; result = result+c->c.ptr.p_double[m+j]*v/(j+1); } result = result+additionalterm; return result; } /************************************************************************* Internal version of Spline1DConvDiff Converts from Hermite spline given by grid XOld to new grid X2 INPUT PARAMETERS: XOld - old grid YOld - values at old grid DOld - first derivative at old grid N - grid size X2 - new grid N2 - new grid size Y - possibly preallocated output array (reallocate if too small) NeedY - do we need Y? D1 - possibly preallocated output array (reallocate if too small) NeedD1 - do we need D1? D2 - possibly preallocated output array (reallocate if too small) NeedD2 - do we need D1? OUTPUT ARRAYS: Y - values, if needed D1 - first derivative, if needed D2 - second derivative, if needed -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiffinternal(/* Real */ ae_vector* xold, /* Real */ ae_vector* yold, /* Real */ ae_vector* dold, ae_int_t n, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y, ae_bool needy, /* Real */ ae_vector* d1, ae_bool needd1, /* Real */ ae_vector* d2, ae_bool needd2, ae_state *_state) { ae_int_t intervalindex; ae_int_t pointindex; ae_bool havetoadvance; double c0; double c1; double c2; double c3; double a; double b; double w; double w2; double w3; double fa; double fb; double da; double db; double t; /* * Prepare space */ if( needy&&y->cntcntcnt=n2 ) { break; } t = x2->ptr.p_double[pointindex]; /* * do we need to advance interval? */ havetoadvance = ae_false; if( intervalindex==-1 ) { havetoadvance = ae_true; } else { if( intervalindexptr.p_double[intervalindex]; b = xold->ptr.p_double[intervalindex+1]; w = b-a; w2 = w*w; w3 = w*w2; fa = yold->ptr.p_double[intervalindex]; fb = yold->ptr.p_double[intervalindex+1]; da = dold->ptr.p_double[intervalindex]; db = dold->ptr.p_double[intervalindex+1]; c0 = fa; c1 = da; c2 = (3*(fb-fa)-2*da*w-db*w)/w2; c3 = (2*(fa-fb)+da*w+db*w)/w3; continue; } /* * Calculate spline and its derivatives using power basis */ t = t-a; if( needy ) { y->ptr.p_double[pointindex] = c0+t*(c1+t*(c2+t*c3)); } if( needd1 ) { d1->ptr.p_double[pointindex] = c1+2*t*c2+3*t*t*c3; } if( needd2 ) { d2->ptr.p_double[pointindex] = 2*c2+6*t*c3; } pointindex = pointindex+1; } } /************************************************************************* This function finds all roots and extrema of the spline S(x) defined at [A,B] (interval which contains spline nodes). It does not extrapolates function, so roots and extrema located outside of [A,B] will not be found. It returns all isolated (including multiple) roots and extrema. INPUT PARAMETERS C - spline interpolant OUTPUT PARAMETERS R - array[NR], contains roots of the spline. In case there is no roots, this array has zero length. NR - number of roots, >=0 DR - is set to True in case there is at least one interval where spline is just a zero constant. Such degenerate cases are not reported in the R/NR E - array[NE], contains extrema (maximums/minimums) of the spline. In case there is no extrema, this array has zero length. ET - array[NE], extrema types: * ET[i]>0 in case I-th extrema is a minimum * ET[i]<0 in case I-th extrema is a maximum NE - number of extrema, >=0 DE - is set to True in case there is at least one interval where spline is a constant. Such degenerate cases are not reported in the E/NE. NOTES: 1. This function does NOT report following kinds of roots: * intervals where function is constantly zero * roots which are outside of [A,B] (note: it CAN return A or B) 2. This function does NOT report following kinds of extrema: * intervals where function is a constant * extrema which are outside of (A,B) (note: it WON'T return A or B) -- ALGLIB PROJECT -- Copyright 26.09.2011 by Bochkanov Sergey *************************************************************************/ void spline1drootsandextrema(spline1dinterpolant* c, /* Real */ ae_vector* r, ae_int_t* nr, ae_bool* dr, /* Real */ ae_vector* e, /* Integer */ ae_vector* et, ae_int_t* ne, ae_bool* de, ae_state *_state) { ae_frame _frame_block; double pl; double ml; double pll; double pr; double mr; ae_vector tr; ae_vector tmpr; ae_vector tmpe; ae_vector tmpet; ae_vector tmpc; double x0; double x1; double x2; double ex0; double ex1; ae_int_t tne; ae_int_t tnr; ae_int_t i; ae_int_t j; ae_bool nstep; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); *nr = 0; *dr = ae_false; ae_vector_clear(e); ae_vector_clear(et); *ne = 0; *de = ae_false; ae_vector_init(&tr, 0, DT_REAL, _state); ae_vector_init(&tmpr, 0, DT_REAL, _state); ae_vector_init(&tmpe, 0, DT_REAL, _state); ae_vector_init(&tmpet, 0, DT_INT, _state); ae_vector_init(&tmpc, 0, DT_REAL, _state); /* *exception handling */ ae_assert(c->k==3, "Spline1DRootsAndExtrema : incorrect parameter C.K!", _state); ae_assert(c->continuity>=0, "Spline1DRootsAndExtrema : parameter C.Continuity must not be less than 0!", _state); /* *initialization of variable */ *nr = 0; *ne = 0; *dr = ae_false; *de = ae_false; nstep = ae_true; /* *consider case, when C.Continuty=0 */ if( c->continuity==0 ) { /* *allocation for auxiliary arrays *'TmpR ' - it stores a time value for roots *'TmpE ' - it stores a time value for extremums *'TmpET '- it stores a time value for extremums type */ rvectorsetlengthatleast(&tmpr, 3*(c->n-1), _state); rvectorsetlengthatleast(&tmpe, 2*(c->n-1), _state); ivectorsetlengthatleast(&tmpet, 2*(c->n-1), _state); /* *start calculating */ for(i=0; i<=c->n-2; i++) { /* *initialization pL, mL, pR, mR */ pl = c->c.ptr.p_double[4*i]; ml = c->c.ptr.p_double[4*i+1]; pr = c->c.ptr.p_double[4*(i+1)]; mr = c->c.ptr.p_double[4*i+1]+2*c->c.ptr.p_double[4*i+2]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])+3*c->c.ptr.p_double[4*i+3]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]); /* *pre-searching roots and extremums */ solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); *dr = *dr||tnr==-1; *de = *de||tne==-1; /* *searching of roots */ if( tnr==1&&nstep ) { /* *is there roots? */ if( *nr>0 ) { /* *is a next root equal a previous root? *if is't, then write new root */ if( ae_fp_neq(x0,tmpr.ptr.p_double[*nr-1]) ) { tmpr.ptr.p_double[*nr] = x0; *nr = *nr+1; } } else { /* *write a first root */ tmpr.ptr.p_double[*nr] = x0; *nr = *nr+1; } } else { /* *case when function at a segment identically to zero *then we have to clear a root, if the one located on a *constant segment */ if( tnr==-1 ) { /* *safe state variable as constant */ if( nstep ) { nstep = ae_false; } /* *clear the root, if there is */ if( *nr>0 ) { if( ae_fp_eq(c->x.ptr.p_double[i],tmpr.ptr.p_double[*nr-1]) ) { *nr = *nr-1; } } /* *change state for 'DR' */ if( !*dr ) { *dr = ae_true; } } else { nstep = ae_true; } } /* *searching of extremums */ if( i>0 ) { pll = c->c.ptr.p_double[4*(i-1)]; /* *if pL=pLL or pL=pR then */ if( tne==-1 ) { if( !*de ) { *de = ae_true; } } else { if( ae_fp_greater(pl,pll)&&ae_fp_greater(pl,pr) ) { /* *maximum */ tmpet.ptr.p_int[*ne] = -1; tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; *ne = *ne+1; } else { if( ae_fp_less(pl,pll)&&ae_fp_less(pl,pr) ) { /* *minimum */ tmpet.ptr.p_int[*ne] = 1; tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; *ne = *ne+1; } } } } } /* *write final result */ rvectorsetlengthatleast(r, *nr, _state); rvectorsetlengthatleast(e, *ne, _state); ivectorsetlengthatleast(et, *ne, _state); /* *write roots */ for(i=0; i<=*nr-1; i++) { r->ptr.p_double[i] = tmpr.ptr.p_double[i]; } /* *write extremums and their types */ for(i=0; i<=*ne-1; i++) { e->ptr.p_double[i] = tmpe.ptr.p_double[i]; et->ptr.p_int[i] = tmpet.ptr.p_int[i]; } } else { /* *case, when C.Continuity>=1 *'TmpR ' - it stores a time value for roots *'TmpC' - it stores a time value for extremums and *their function value (TmpC={EX0,F(EX0), EX1,F(EX1), ..., EXn,F(EXn)};) *'TmpE' - it stores a time value for extremums only *'TmpET'- it stores a time value for extremums type */ rvectorsetlengthatleast(&tmpr, 2*c->n-1, _state); rvectorsetlengthatleast(&tmpc, 4*c->n, _state); rvectorsetlengthatleast(&tmpe, 2*c->n, _state); ivectorsetlengthatleast(&tmpet, 2*c->n, _state); /* *start calculating */ for(i=0; i<=c->n-2; i++) { /* *we calculate pL,mL, pR,mR as Fi+1(F'i+1) at left border */ pl = c->c.ptr.p_double[4*i]; ml = c->c.ptr.p_double[4*i+1]; pr = c->c.ptr.p_double[4*(i+1)]; mr = c->c.ptr.p_double[4*(i+1)+1]; /* *calculating roots and extremums at [X[i],X[i+1]] */ solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); /* *searching roots */ if( tnr>0 ) { /* *re-init tR */ if( tnr>=1 ) { tr.ptr.p_double[0] = x0; } if( tnr>=2 ) { tr.ptr.p_double[1] = x1; } if( tnr==3 ) { tr.ptr.p_double[2] = x2; } /* *start root selection */ if( *nr>0 ) { if( ae_fp_neq(tmpr.ptr.p_double[*nr-1],x0) ) { /* *previous segment was't constant identical zero */ if( nstep ) { for(j=0; j<=tnr-1; j++) { tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; } *nr = *nr+tnr; } else { /* *previous segment was constant identical zero *and we must ignore [NR+j-1] root */ for(j=1; j<=tnr-1; j++) { tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; } *nr = *nr+tnr-1; nstep = ae_true; } } else { for(j=1; j<=tnr-1; j++) { tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; } *nr = *nr+tnr-1; } } else { /* *write first root */ for(j=0; j<=tnr-1; j++) { tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; } *nr = *nr+tnr; } } else { if( tnr==-1 ) { /* *decrement 'NR' if at previous step was writen a root *(previous segment identical zero) */ if( *nr>0&&nstep ) { *nr = *nr-1; } /* *previous segment is't constant */ if( nstep ) { nstep = ae_false; } /* *rewrite 'DR' */ if( !*dr ) { *dr = ae_true; } } } /* *searching extremums *write all term like extremums */ if( tne==1 ) { if( *ne>0 ) { /* *just ignore identical extremums *because he must be one */ if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) { tmpc.ptr.p_double[*ne] = ex0; tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); *ne = *ne+2; } } else { /* *write first extremum and it function value */ tmpc.ptr.p_double[*ne] = ex0; tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); *ne = *ne+2; } } else { if( tne==2 ) { if( *ne>0 ) { /* *ignore identical extremum */ if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) { tmpc.ptr.p_double[*ne] = ex0; tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); *ne = *ne+2; } } else { /* *write first extremum */ tmpc.ptr.p_double[*ne] = ex0; tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); *ne = *ne+2; } /* *write second extremum */ tmpc.ptr.p_double[*ne] = ex1; tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i]); *ne = *ne+2; } else { if( tne==-1 ) { if( !*de ) { *de = ae_true; } } } } } /* *checking of arrays *get number of extremums (tNe=NE/2) *initialize pL as value F0(X[0]) and *initialize pR as value Fn-1(X[N]) */ tne = *ne/2; *ne = 0; pl = c->c.ptr.p_double[0]; pr = c->c.ptr.p_double[4*(c->n-1)]; for(i=0; i<=tne-1; i++) { if( i>0&&ix.ptr.p_double[0]) ) { if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) { /* *maximum */ tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; tmpet.ptr.p_int[*ne] = -1; *ne = *ne+1; } else { if( ae_fp_less(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) { /* *minimum */ tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; tmpet.ptr.p_int[*ne] = 1; *ne = *ne+1; } } } } else { if( i==tne-1 ) { if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[c->n-1]) ) { if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],pr) ) { /* *maximum */ tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; tmpet.ptr.p_int[*ne] = -1; *ne = *ne+1; } else { if( ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_less(tmpc.ptr.p_double[2*i+1],pr) ) { /* *minimum */ tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; tmpet.ptr.p_int[*ne] = 1; *ne = *ne+1; } } } } } } } /* *final results *allocate R, E, ET */ rvectorsetlengthatleast(r, *nr, _state); rvectorsetlengthatleast(e, *ne, _state); ivectorsetlengthatleast(et, *ne, _state); /* *write result for extremus and their types */ for(i=0; i<=*ne-1; i++) { e->ptr.p_double[i] = tmpe.ptr.p_double[i]; et->ptr.p_int[i] = tmpet.ptr.p_int[i]; } /* *write result for roots */ for(i=0; i<=*nr-1; i++) { r->ptr.p_double[i] = tmpr.ptr.p_double[i]; } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Heap sort. *************************************************************************/ void heapsortdpoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* d, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector rbuf; ae_vector ibuf; ae_vector rbuf2; ae_vector ibuf2; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&rbuf, 0, DT_REAL, _state); ae_vector_init(&ibuf, 0, DT_INT, _state); ae_vector_init(&rbuf2, 0, DT_REAL, _state); ae_vector_init(&ibuf2, 0, DT_INT, _state); ae_vector_set_length(&ibuf, n, _state); ae_vector_set_length(&rbuf, n, _state); for(i=0; i<=n-1; i++) { ibuf.ptr.p_int[i] = i; } tagsortfasti(x, &ibuf, &rbuf2, &ibuf2, n, _state); for(i=0; i<=n-1; i++) { rbuf.ptr.p_double[i] = y->ptr.p_double[ibuf.ptr.p_int[i]]; } ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { rbuf.ptr.p_double[i] = d->ptr.p_double[ibuf.ptr.p_int[i]]; } ae_v_move(&d->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* This procedure search roots of an quadratic equation inside [0;1] and it number of roots. INPUT PARAMETERS: P0 - value of a function at 0 M0 - value of a derivative at 0 P1 - value of a function at 1 M1 - value of a derivative at 1 OUTPUT PARAMETERS: X0 - first root of an equation X1 - second root of an equation NR - number of roots RESTRICTIONS OF PARAMETERS: Parameters for this procedure has't to be zero simultaneously. Is expected, that input polinom is't degenerate or constant identicaly ZERO. REMARK: The procedure always fill value for X1 and X2, even if it is't belongs to [0;1]. But first true root(even if existing one) is in X1. Number of roots is NR. -- ALGLIB PROJECT -- Copyright 26.09.2011 by Bochkanov Sergey *************************************************************************/ void solvepolinom2(double p0, double m0, double p1, double m1, double* x0, double* x1, ae_int_t* nr, ae_state *_state) { double a; double b; double c; double dd; double tmp; double exf; double extr; *x0 = 0; *x1 = 0; *nr = 0; /* *calculate parameters for equation: A, B and C */ a = 6*p0+3*m0-6*p1+3*m1; b = -6*p0-4*m0+6*p1-2*m1; c = m0; /* *check case, when A=0 *we are considering the linear equation */ if( ae_fp_eq(a,(double)(0)) ) { /* *B<>0 and root inside [0;1] *one root */ if( (ae_fp_neq(b,(double)(0))&&ae_sign(c, _state)*ae_sign(b, _state)<=0)&&ae_fp_greater_eq(ae_fabs(b, _state),ae_fabs(c, _state)) ) { *x0 = -c/b; *nr = 1; return; } else { *nr = 0; return; } } /* *consider case, when extremumu outside (0;1) *exist one root only */ if( ae_fp_less_eq(ae_fabs(2*a, _state),ae_fabs(b, _state))||ae_sign(b, _state)*ae_sign(a, _state)>=0 ) { if( ae_sign(m0, _state)*ae_sign(m1, _state)>0 ) { *nr = 0; return; } /* *consider case, when the one exist *same sign of derivative */ if( ae_sign(m0, _state)*ae_sign(m1, _state)<0 ) { *nr = 1; extr = -b/(2*a); dd = b*b-4*a*c; if( ae_fp_less(dd,(double)(0)) ) { return; } *x0 = (-b-ae_sqrt(dd, _state))/(2*a); *x1 = (-b+ae_sqrt(dd, _state))/(2*a); if( (ae_fp_greater_eq(extr,(double)(1))&&ae_fp_less_eq(*x1,extr))||(ae_fp_less_eq(extr,(double)(0))&&ae_fp_greater_eq(*x1,extr)) ) { *x0 = *x1; } return; } /* *consider case, when the one is 0 */ if( ae_fp_eq(m0,(double)(0)) ) { *x0 = (double)(0); *nr = 1; return; } if( ae_fp_eq(m1,(double)(0)) ) { *x0 = (double)(1); *nr = 1; return; } } else { /* *consider case, when both of derivatives is 0 */ if( ae_fp_eq(m0,(double)(0))&&ae_fp_eq(m1,(double)(0)) ) { *x0 = (double)(0); *x1 = (double)(1); *nr = 2; return; } /* *consider case, when derivative at 0 is 0, and derivative at 1 is't 0 */ if( ae_fp_eq(m0,(double)(0))&&ae_fp_neq(m1,(double)(0)) ) { dd = b*b-4*a*c; if( ae_fp_less(dd,(double)(0)) ) { *x0 = (double)(0); *nr = 1; return; } *x0 = (-b-ae_sqrt(dd, _state))/(2*a); *x1 = (-b+ae_sqrt(dd, _state))/(2*a); extr = -b/(2*a); exf = a*extr*extr+b*extr+c; if( ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) { *x0 = (double)(0); *nr = 1; return; } else { if( ae_fp_greater(extr,*x0) ) { *x0 = (double)(0); } else { *x1 = (double)(0); } *nr = 2; /* *roots must placed ascending */ if( ae_fp_greater(*x0,*x1) ) { tmp = *x0; *x0 = *x1; *x1 = tmp; } return; } } if( ae_fp_eq(m1,(double)(0))&&ae_fp_neq(m0,(double)(0)) ) { dd = b*b-4*a*c; if( ae_fp_less(dd,(double)(0)) ) { *x0 = (double)(1); *nr = 1; return; } *x0 = (-b-ae_sqrt(dd, _state))/(2*a); *x1 = (-b+ae_sqrt(dd, _state))/(2*a); extr = -b/(2*a); exf = a*extr*extr+b*extr+c; if( ae_sign(exf, _state)*ae_sign(m0, _state)>0 ) { *x0 = (double)(1); *nr = 1; return; } else { if( ae_fp_less(extr,*x0) ) { *x0 = (double)(1); } else { *x1 = (double)(1); } *nr = 2; /* *roots must placed ascending */ if( ae_fp_greater(*x0,*x1) ) { tmp = *x0; *x0 = *x1; *x1 = tmp; } return; } } else { extr = -b/(2*a); exf = a*extr*extr+b*extr+c; if( ae_sign(exf, _state)*ae_sign(m0, _state)>0&&ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) { *nr = 0; return; } dd = b*b-4*a*c; if( ae_fp_less(dd,(double)(0)) ) { *nr = 0; return; } *x0 = (-b-ae_sqrt(dd, _state))/(2*a); *x1 = (-b+ae_sqrt(dd, _state))/(2*a); /* *if EXF and m0, EXF and m1 has different signs, then equation has two roots */ if( ae_sign(exf, _state)*ae_sign(m0, _state)<0&&ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) { *nr = 2; /* *roots must placed ascending */ if( ae_fp_greater(*x0,*x1) ) { tmp = *x0; *x0 = *x1; *x1 = tmp; } return; } else { *nr = 1; if( ae_sign(exf, _state)*ae_sign(m0, _state)<0 ) { if( ae_fp_less(*x1,extr) ) { *x0 = *x1; } return; } if( ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) { if( ae_fp_greater(*x1,extr) ) { *x0 = *x1; } return; } } } } } /************************************************************************* This procedure search roots of an cubic equation inside [A;B], it number of roots and number of extremums. INPUT PARAMETERS: pA - value of a function at A mA - value of a derivative at A pB - value of a function at B mB - value of a derivative at B A0 - left border [A0;B0] B0 - right border [A0;B0] OUTPUT PARAMETERS: X0 - first root of an equation X1 - second root of an equation X2 - third root of an equation EX0 - first extremum of a function EX0 - second extremum of a function NR - number of roots NR - number of extrmums RESTRICTIONS OF PARAMETERS: Length of [A;B] must be positive and is't zero, i.e. A<>B and AB */ ae_assert(ae_fp_less(a,b), "\nSolveCubicPolinom: incorrect borders for [A;B]!\n", _state); /* *case 1 *function can be identicaly to ZERO */ if( ((ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb))&&ae_fp_eq(pa,(double)(0)) ) { *nr = -1; *ne = -1; return; } if( (ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb) ) { *nr = 0; *ne = -1; return; } tmpma = ma*(b-a); tmpmb = mb*(b-a); solvepolinom2(pa, tmpma, pb, tmpmb, ex0, ex1, ne, _state); *ex0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex0, _state); *ex1 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex1, _state); /* *case 3.1 *no extremums at [A;B] */ if( *ne==0 ) { *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); if( *nr==1 ) { *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); } return; } /* *case 3.2 *one extremum */ if( *ne==1 ) { if( ae_fp_eq(*ex0,a)||ae_fp_eq(*ex0,b) ) { *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); if( *nr==1 ) { *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); } return; } else { *nr = 0; i = 0; tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); if( *nr>i ) { tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); i = i+1; } *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr); if( *nr>i ) { *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state); if( i>0 ) { if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) { tempdata->ptr.p_double[i] = *x0; i = i+1; } else { *nr = *nr-1; } } else { tempdata->ptr.p_double[i] = *x0; i = i+1; } } if( *nr>0 ) { *x0 = tempdata->ptr.p_double[0]; if( *nr>1 ) { *x1 = tempdata->ptr.p_double[1]; } return; } } return; } else { /* *case 3.3 *two extremums(or more, but it's impossible) * * *case 3.3.0 *both extremums at the border */ if( ae_fp_eq(*ex0,a)&&ae_fp_eq(*ex1,b) ) { *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); if( *nr==1 ) { *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); } return; } if( ae_fp_eq(*ex0,a)&&ae_fp_neq(*ex1,b) ) { *nr = 0; i = 0; tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state); *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex1, x0, _state)+(*nr); if( *nr>i ) { tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex1, a, *ex1, *x0, _state); i = i+1; } *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr); if( *nr>i ) { *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state); if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) { tempdata->ptr.p_double[i] = *x0; i = i+1; } else { *nr = *nr-1; } } if( *nr>0 ) { *x0 = tempdata->ptr.p_double[0]; if( *nr>1 ) { *x1 = tempdata->ptr.p_double[1]; } return; } } if( ae_fp_eq(*ex1,b)&&ae_fp_neq(*ex0,a) ) { *nr = 0; i = 0; tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); if( *nr>i ) { tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); i = i+1; } *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr); if( *nr>i ) { *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state); if( i>0 ) { if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) { tempdata->ptr.p_double[i] = *x0; i = i+1; } else { *nr = *nr-1; } } else { tempdata->ptr.p_double[i] = *x0; i = i+1; } } if( *nr>0 ) { *x0 = tempdata->ptr.p_double[0]; if( *nr>1 ) { *x1 = tempdata->ptr.p_double[1]; } return; } } else { /* *case 3.3.2 *both extremums inside (0;1) */ *nr = 0; i = 0; tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state); *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); if( *nr>i ) { tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); i = i+1; } *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, tex1, x0, _state)+(*nr); if( *nr>i ) { *x0 = spline1d_rescaleval(tex0, tex1, *ex0, *ex1, *x0, _state); if( i>0 ) { if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) { tempdata->ptr.p_double[i] = *x0; i = i+1; } else { *nr = *nr-1; } } else { tempdata->ptr.p_double[i] = *x0; i = i+1; } } *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr); if( *nr>i ) { *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state); if( i>0 ) { if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) { tempdata->ptr.p_double[i] = *x0; i = i+1; } else { *nr = *nr-1; } } else { tempdata->ptr.p_double[i] = *x0; i = i+1; } } /* *write are found roots */ if( *nr>0 ) { *x0 = tempdata->ptr.p_double[0]; if( *nr>1 ) { *x1 = tempdata->ptr.p_double[1]; } if( *nr>2 ) { *x2 = tempdata->ptr.p_double[2]; } return; } } } } /************************************************************************* Function for searching a root at [A;B] by bisection method and return number of roots (0 or 1) INPUT PARAMETERS: pA - value of a function at A mA - value of a derivative at A pB - value of a function at B mB - value of a derivative at B A0 - left border [A0;B0] B0 - right border [A0;B0] RESTRICTIONS OF PARAMETERS: We assume, that B0>A0. REMARK: Assume, that exist one root only at [A;B], else function may be work incorrectly. The function don't check value A0,B0! -- ALGLIB PROJECT -- Copyright 26.09.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t bisectmethod(double pa, double ma, double pb, double mb, double a, double b, double* x, ae_state *_state) { double vacuum; double eps; double a0; double b0; double m; double lf; double rf; double mf; ae_int_t result; *x = 0; /* *accuracy */ eps = 1000*(b-a)*ae_machineepsilon; /* *initialization left and right borders */ a0 = a; b0 = b; /* *initialize function value at 'A' and 'B' */ spline1d_hermitecalc(pa, ma, pb, mb, a, &lf, &vacuum, _state); spline1d_hermitecalc(pa, ma, pb, mb, b, &rf, &vacuum, _state); /* *check, that 'A' and 'B' are't roots, *and that root exist */ if( ae_sign(lf, _state)*ae_sign(rf, _state)>0 ) { result = 0; return result; } else { if( ae_fp_eq(lf,(double)(0)) ) { *x = a; result = 1; return result; } else { if( ae_fp_eq(rf,(double)(0)) ) { *x = b; result = 1; return result; } } } /* *searching a root */ do { m = (b0+a0)/2; spline1d_hermitecalc(pa, ma, pb, mb, a0, &lf, &vacuum, _state); spline1d_hermitecalc(pa, ma, pb, mb, b0, &rf, &vacuum, _state); spline1d_hermitecalc(pa, ma, pb, mb, m, &mf, &vacuum, _state); if( ae_sign(mf, _state)*ae_sign(lf, _state)<0 ) { b0 = m; } else { if( ae_sign(mf, _state)*ae_sign(rf, _state)<0 ) { a0 = m; } else { if( ae_fp_eq(lf,(double)(0)) ) { *x = a0; result = 1; return result; } if( ae_fp_eq(rf,(double)(0)) ) { *x = b0; result = 1; return result; } if( ae_fp_eq(mf,(double)(0)) ) { *x = m; result = 1; return result; } } } } while(ae_fp_greater_eq(ae_fabs(b0-a0, _state),eps)); *x = m; result = 1; return result; } /************************************************************************* This function builds monotone cubic Hermite interpolant. This interpolant is monotonic in [x(0),x(n-1)] and is constant outside of this interval. In case y[] form non-monotonic sequence, interpolant is piecewise monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will monotonically grow at [0..2] and monotonically decrease at [2..4]. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Subroutine automatically sorts points, so caller may pass unsorted array. Y - function values, array[0..N-1] N - the number of points(N>=2). OUTPUT PARAMETERS: C - spline interpolant. -- ALGLIB PROJECT -- Copyright 21.06.2012 by Bochkanov Sergey *************************************************************************/ void spline1dbuildmonotone(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector d; ae_vector ex; ae_vector ey; ae_vector p; double delta; double alpha; double beta; ae_int_t tmpn; ae_int_t sn; double ca; double cb; double epsilon; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _spline1dinterpolant_clear(c); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&ex, 0, DT_REAL, _state); ae_vector_init(&ey, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * Check lengths of arguments */ ae_assert(n>=2, "Spline1DBuildMonotone: N<2", _state); ae_assert(x->cnt>=n, "Spline1DBuildMonotone: Length(X)cnt>=n, "Spline1DBuildMonotone: Length(Y)ptr.p_double[0]-ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state); ex.ptr.p_double[n-1] = x->ptr.p_double[n-3]+ae_fabs(x->ptr.p_double[n-3]-x->ptr.p_double[n-4], _state); ey.ptr.p_double[0] = y->ptr.p_double[0]; ey.ptr.p_double[n-1] = y->ptr.p_double[n-3]; for(i=1; i<=n-2; i++) { ex.ptr.p_double[i] = x->ptr.p_double[i-1]; ey.ptr.p_double[i] = y->ptr.p_double[i-1]; } /* * Init sign of the function for first segment */ i = 0; ca = (double)(0); do { ca = ey.ptr.p_double[i+1]-ey.ptr.p_double[i]; i = i+1; } while(!(ae_fp_neq(ca,(double)(0))||i>n-2)); if( ae_fp_neq(ca,(double)(0)) ) { ca = ca/ae_fabs(ca, _state); } i = 0; while(i=2, "Spline1DBuildMonotone: internal error", _state); /* * Calculate derivatives for current segment */ d.ptr.p_double[i] = (double)(0); d.ptr.p_double[sn-1] = (double)(0); for(j=i+1; j<=sn-2; j++) { d.ptr.p_double[j] = ((ey.ptr.p_double[j]-ey.ptr.p_double[j-1])/(ex.ptr.p_double[j]-ex.ptr.p_double[j-1])+(ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]))/2; } for(j=i; j<=sn-2; j++) { delta = (ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]); if( ae_fp_less_eq(ae_fabs(delta, _state),epsilon) ) { d.ptr.p_double[j] = (double)(0); d.ptr.p_double[j+1] = (double)(0); } else { alpha = d.ptr.p_double[j]/delta; beta = d.ptr.p_double[j+1]/delta; if( ae_fp_neq(alpha,(double)(0)) ) { cb = alpha*ae_sqrt(1+ae_sqr(beta/alpha, _state), _state); } else { if( ae_fp_neq(beta,(double)(0)) ) { cb = beta; } else { continue; } } if( ae_fp_greater(cb,(double)(3)) ) { d.ptr.p_double[j] = 3*alpha*delta/cb; d.ptr.p_double[j+1] = 3*beta*delta/cb; } } } /* * Transition to next segment */ i = sn-1; } spline1dbuildhermite(&ex, &ey, &d, n, c, _state); c->continuity = 2; ae_frame_leave(_state); } /************************************************************************* Internal version of Spline1DGridDiffCubic. Accepts pre-ordered X/Y, temporary arrays (which may be preallocated, if you want to save time, or not) and output array (which may be preallocated too). Y is passed as var-parameter because we may need to force last element to be equal to the first one (if periodic boundary conditions are specified). -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ static void spline1d_spline1dgriddiffcubicinternal(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d, /* Real */ ae_vector* a1, /* Real */ ae_vector* a2, /* Real */ ae_vector* a3, /* Real */ ae_vector* b, /* Real */ ae_vector* dt, ae_state *_state) { ae_int_t i; /* * allocate arrays */ if( d->cntcntcntcntcntcntptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); d->ptr.p_double[1] = d->ptr.p_double[0]; return; } if( (n==2&&boundltype==-1)&&boundrtype==-1 ) { d->ptr.p_double[0] = (double)(0); d->ptr.p_double[1] = (double)(0); return; } /* * Periodic and non-periodic boundary conditions are * two separate classes */ if( boundrtype==-1&&boundltype==-1 ) { /* * Periodic boundary conditions */ y->ptr.p_double[n-1] = y->ptr.p_double[0]; /* * Boundary conditions at N-1 points * (one point less because last point is the same as first point). */ a1->ptr.p_double[0] = x->ptr.p_double[1]-x->ptr.p_double[0]; a2->ptr.p_double[0] = 2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); a3->ptr.p_double[0] = x->ptr.p_double[n-1]-x->ptr.p_double[n-2]; b->ptr.p_double[0] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])*(x->ptr.p_double[1]-x->ptr.p_double[0])+3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); for(i=1; i<=n-2; i++) { /* * Altough last point is [N-2], we use X[N-1] and Y[N-1] * (because of periodicity) */ a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); } /* * Solve, add last point (with index N-1) */ spline1d_solvecyclictridiagonal(a1, a2, a3, b, n-1, dt, _state); ae_v_move(&d->ptr.p_double[0], 1, &dt->ptr.p_double[0], 1, ae_v_len(0,n-2)); d->ptr.p_double[n-1] = d->ptr.p_double[0]; } else { /* * Non-periodic boundary condition. * Left boundary conditions. */ if( boundltype==0 ) { a1->ptr.p_double[0] = (double)(0); a2->ptr.p_double[0] = (double)(1); a3->ptr.p_double[0] = (double)(1); b->ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); } if( boundltype==1 ) { a1->ptr.p_double[0] = (double)(0); a2->ptr.p_double[0] = (double)(1); a3->ptr.p_double[0] = (double)(0); b->ptr.p_double[0] = boundl; } if( boundltype==2 ) { a1->ptr.p_double[0] = (double)(0); a2->ptr.p_double[0] = (double)(2); a3->ptr.p_double[0] = (double)(1); b->ptr.p_double[0] = 3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-0.5*boundl*(x->ptr.p_double[1]-x->ptr.p_double[0]); } /* * Central conditions */ for(i=1; i<=n-2; i++) { a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); } /* * Right boundary conditions */ if( boundrtype==0 ) { a1->ptr.p_double[n-1] = (double)(1); a2->ptr.p_double[n-1] = (double)(1); a3->ptr.p_double[n-1] = (double)(0); b->ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); } if( boundrtype==1 ) { a1->ptr.p_double[n-1] = (double)(0); a2->ptr.p_double[n-1] = (double)(1); a3->ptr.p_double[n-1] = (double)(0); b->ptr.p_double[n-1] = boundr; } if( boundrtype==2 ) { a1->ptr.p_double[n-1] = (double)(1); a2->ptr.p_double[n-1] = (double)(2); a3->ptr.p_double[n-1] = (double)(0); b->ptr.p_double[n-1] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])+0.5*boundr*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); } /* * Solve */ spline1d_solvetridiagonal(a1, a2, a3, b, n, d, _state); } } /************************************************************************* Internal subroutine. Heap sort. *************************************************************************/ static void spline1d_heapsortpoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector bufx; ae_vector bufy; ae_frame_make(_state, &_frame_block); ae_vector_init(&bufx, 0, DT_REAL, _state); ae_vector_init(&bufy, 0, DT_REAL, _state); tagsortfastr(x, y, &bufx, &bufy, n, _state); ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Heap sort. Accepts: X, Y - points P - empty or preallocated array Returns: X, Y - sorted by X P - array of permutations; I-th position of output arrays X/Y contains (X[P[I]],Y[P[I]]) *************************************************************************/ static void spline1d_heapsortppoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Integer */ ae_vector* p, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector rbuf; ae_vector ibuf; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&rbuf, 0, DT_REAL, _state); ae_vector_init(&ibuf, 0, DT_INT, _state); if( p->cntptr.p_int[i] = i; } tagsortfasti(x, p, &rbuf, &ibuf, n, _state); for(i=0; i<=n-1; i++) { rbuf.ptr.p_double[i] = y->ptr.p_double[p->ptr.p_int[i]]; } ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Tridiagonal solver. Solves ( B[0] C[0] ( A[1] B[1] C[1] ) ( A[2] B[2] C[2] ) ( .......... ) * X = D ( .......... ) ( A[N-2] B[N-2] C[N-2] ) ( A[N-1] B[N-1] ) *************************************************************************/ static void spline1d_solvetridiagonal(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_vector _b; ae_vector _d; ae_int_t k; double t; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_b, b, _state); b = &_b; ae_vector_init_copy(&_d, d, _state); d = &_d; if( x->cntptr.p_double[k]/b->ptr.p_double[k-1]; b->ptr.p_double[k] = b->ptr.p_double[k]-t*c->ptr.p_double[k-1]; d->ptr.p_double[k] = d->ptr.p_double[k]-t*d->ptr.p_double[k-1]; } x->ptr.p_double[n-1] = d->ptr.p_double[n-1]/b->ptr.p_double[n-1]; for(k=n-2; k>=0; k--) { x->ptr.p_double[k] = (d->ptr.p_double[k]-c->ptr.p_double[k]*x->ptr.p_double[k+1])/b->ptr.p_double[k]; } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Cyclic tridiagonal solver. Solves ( B[0] C[0] A[0] ) ( A[1] B[1] C[1] ) ( A[2] B[2] C[2] ) ( .......... ) * X = D ( .......... ) ( A[N-2] B[N-2] C[N-2] ) ( C[N-1] A[N-1] B[N-1] ) *************************************************************************/ static void spline1d_solvecyclictridiagonal(/* Real */ ae_vector* a, /* Real */ ae_vector* b, /* Real */ ae_vector* c, /* Real */ ae_vector* d, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_vector _b; ae_int_t k; double alpha; double beta; double gamma; ae_vector y; ae_vector z; ae_vector u; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_b, b, _state); b = &_b; ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&u, 0, DT_REAL, _state); if( x->cntptr.p_double[0]; alpha = c->ptr.p_double[n-1]; gamma = -b->ptr.p_double[0]; b->ptr.p_double[0] = 2*b->ptr.p_double[0]; b->ptr.p_double[n-1] = b->ptr.p_double[n-1]-alpha*beta/gamma; ae_vector_set_length(&u, n, _state); for(k=0; k<=n-1; k++) { u.ptr.p_double[k] = (double)(0); } u.ptr.p_double[0] = gamma; u.ptr.p_double[n-1] = alpha; spline1d_solvetridiagonal(a, b, c, d, n, &y, _state); spline1d_solvetridiagonal(a, b, c, &u, n, &z, _state); for(k=0; k<=n-1; k++) { x->ptr.p_double[k] = y.ptr.p_double[k]-(y.ptr.p_double[0]+beta/gamma*y.ptr.p_double[n-1])/(1+z.ptr.p_double[0]+beta/gamma*z.ptr.p_double[n-1])*z.ptr.p_double[k]; } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Three-point differentiation *************************************************************************/ static double spline1d_diffthreepoint(double t, double x0, double f0, double x1, double f1, double x2, double f2, ae_state *_state) { double a; double b; double result; t = t-x0; x1 = x1-x0; x2 = x2-x0; a = (f2-f0-x2/x1*(f1-f0))/(ae_sqr(x2, _state)-x1*x2); b = (f1-f0-a*ae_sqr(x1, _state))/x1; result = 2*a*t+b; return result; } /************************************************************************* Procedure for calculating value of a function is providet in the form of Hermite polinom INPUT PARAMETERS: P0 - value of a function at 0 M0 - value of a derivative at 0 P1 - value of a function at 1 M1 - value of a derivative at 1 T - point inside [0;1] OUTPUT PARAMETERS: S - value of a function at T B0 - value of a derivative function at T -- ALGLIB PROJECT -- Copyright 26.09.2011 by Bochkanov Sergey *************************************************************************/ static void spline1d_hermitecalc(double p0, double m0, double p1, double m1, double t, double* s, double* ds, ae_state *_state) { *s = 0; *ds = 0; *s = p0*(1+2*t)*(1-t)*(1-t)+m0*t*(1-t)*(1-t)+p1*(3-2*t)*t*t+m1*t*t*(t-1); *ds = -p0*6*t*(1-t)+m0*(1-t)*(1-3*t)+p1*6*t*(1-t)+m1*t*(3*t-2); } /************************************************************************* Function for mapping from [A0;B0] to [A1;B1] INPUT PARAMETERS: A0 - left border [A0;B0] B0 - right border [A0;B0] A1 - left border [A1;B1] B1 - right border [A1;B1] T - value inside [A0;B0] RESTRICTIONS OF PARAMETERS: We assume, that B0>A0 and B1>A1. But we chech, that T is inside [A0;B0], and if TB0 then T - B1. INPUT PARAMETERS: A0 - left border for segment [A0;B0] from 'T' is converted to [A1;B1] B0 - right border for segment [A0;B0] from 'T' is converted to [A1;B1] A1 - left border for segment [A1;B1] to 'T' is converted from [A0;B0] B1 - right border for segment [A1;B1] to 'T' is converted from [A0;B0] T - the parameter is mapped from [A0;B0] to [A1;B1] Result: is converted value for 'T' from [A0;B0] to [A1;B1] REMARK: The function don't check value A0,B0 and A1,B1! -- ALGLIB PROJECT -- Copyright 26.09.2011 by Bochkanov Sergey *************************************************************************/ static double spline1d_rescaleval(double a0, double b0, double a1, double b1, double t, ae_state *_state) { double result; /* *return left border */ if( ae_fp_less_eq(t,a0) ) { result = a1; return result; } /* *return right border */ if( ae_fp_greater_eq(t,b0) ) { result = b1; return result; } /* *return value between left and right borders */ result = (b1-a1)*(t-a0)/(b0-a0)+a1; return result; } void _spline1dinterpolant_init(void* _p, ae_state *_state) { spline1dinterpolant *p = (spline1dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->c, 0, DT_REAL, _state); } void _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state) { spline1dinterpolant *dst = (spline1dinterpolant*)_dst; spline1dinterpolant *src = (spline1dinterpolant*)_src; dst->periodic = src->periodic; dst->n = src->n; dst->k = src->k; dst->continuity = src->continuity; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->c, &src->c, _state); } void _spline1dinterpolant_clear(void* _p) { spline1dinterpolant *p = (spline1dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->c); } void _spline1dinterpolant_destroy(void* _p) { spline1dinterpolant *p = (spline1dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->c); } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after generating specified number of linear sections. IMPORTANT: * it does NOT perform least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y M - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N=0, "LSTFitPiecewiseLinearRDPFixed: N<0", _state); ae_assert(m>=1, "LSTFitPiecewiseLinearRDPFixed: M<1", _state); ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(X)cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(Y)ptr.p_double[i]; while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i])) { v = v+y->ptr.p_double[j]; j = j+1; } v = v/(j-i); for(k=i; k<=j-1; k++) { y->ptr.p_double[k] = v; } i = j; } /* * Handle degenerate case x[0]=x[N-1] */ if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) ) { *nsections = 0; ae_frame_leave(_state); return; } /* * Prepare first section */ lsfit_rdpanalyzesection(x, y, 0, n-1, &worstidx, &worsterror, _state); ae_matrix_set_length(§ions, m, 4, _state); ae_vector_set_length(&heaperrors, m, _state); ae_vector_set_length(&heaptags, m, _state); *nsections = 1; sections.ptr.pp_double[0][0] = (double)(0); sections.ptr.pp_double[0][1] = (double)(n-1); sections.ptr.pp_double[0][2] = (double)(worstidx); sections.ptr.pp_double[0][3] = worsterror; heaperrors.ptr.p_double[0] = worsterror; heaptags.ptr.p_int[0] = 0; ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state); /* * Main loop. * Repeatedly find section with worst error and divide it. * Terminate after M-th section, or because of other reasons (see loop internals). */ while(*nsectionsptr.p_double[ae_round(sections.ptr.pp_double[i][1], _state)],x->ptr.p_double[k]) ) { k = ae_round(sections.ptr.pp_double[i][1], _state); } } points.ptr.p_double[*nsections] = (double)(k); tagsortfast(&points, &buf0, *nsections+1, _state); /* * Output sections: * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections * * last element of X2/Y2 is filled by right boundary of rightmost section * * X2/Y2 is sorted by ascending of X2 */ ae_vector_set_length(x2, *nsections+1, _state); ae_vector_set_length(y2, *nsections+1, _state); for(i=0; i<=*nsections; i++) { x2->ptr.p_double[i] = x->ptr.p_double[ae_round(points.ptr.p_double[i], _state)]; y2->ptr.p_double[i] = y->ptr.p_double[ae_round(points.ptr.p_double[i], _state)]; } ae_frame_leave(_state); } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after achieving desired precision. IMPORTANT: * it performs non-least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y Eps - positive number, desired precision. OUTPUT PARAMETERS: X2 - X-values of corner points for piecewise approximation, has length NSections+1 or zero (for NSections=0). Y2 - Y-values of corner points, has length NSections+1 or zero (for NSections=0). NSections- number of sections found by algorithm, NSections can be zero for degenerate datasets (N<=1 or all X[] are non-distinct). NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is a first point of curve, (X2[NSection-1],Y2[NSection-1]) is the last point. -- ALGLIB -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/ void lstfitpiecewiselinearrdp(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double eps, /* Real */ ae_vector* x2, /* Real */ ae_vector* y2, ae_int_t* nsections, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector buf0; ae_vector buf1; ae_vector xtmp; ae_vector ytmp; double v; ae_int_t npts; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_clear(x2); ae_vector_clear(y2); *nsections = 0; ae_vector_init(&buf0, 0, DT_REAL, _state); ae_vector_init(&buf1, 0, DT_REAL, _state); ae_vector_init(&xtmp, 0, DT_REAL, _state); ae_vector_init(&ytmp, 0, DT_REAL, _state); ae_assert(n>=0, "LSTFitPiecewiseLinearRDP: N<0", _state); ae_assert(ae_fp_greater(eps,(double)(0)), "LSTFitPiecewiseLinearRDP: Eps<=0", _state); ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDP: Length(X)cnt>=n, "LSTFitPiecewiseLinearRDP: Length(Y)ptr.p_double[i]; while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i])) { v = v+y->ptr.p_double[j]; j = j+1; } v = v/(j-i); for(k=i; k<=j-1; k++) { y->ptr.p_double[k] = v; } i = j; } /* * Handle degenerate case x[0]=x[N-1] */ if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) ) { *nsections = 0; ae_frame_leave(_state); return; } /* * Prepare data for recursive algorithm */ ae_vector_set_length(&xtmp, n, _state); ae_vector_set_length(&ytmp, n, _state); npts = 2; xtmp.ptr.p_double[0] = x->ptr.p_double[0]; ytmp.ptr.p_double[0] = y->ptr.p_double[0]; xtmp.ptr.p_double[1] = x->ptr.p_double[n-1]; ytmp.ptr.p_double[1] = y->ptr.p_double[n-1]; lsfit_rdprecursive(x, y, 0, n-1, eps, &xtmp, &ytmp, &npts, _state); /* * Output sections: * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections * * last element of X2/Y2 is filled by right boundary of rightmost section * * X2/Y2 is sorted by ascending of X2 */ *nsections = npts-1; ae_vector_set_length(x2, npts, _state); ae_vector_set_length(y2, npts, _state); for(i=0; i<=*nsections; i++) { x2->ptr.p_double[i] = xtmp.ptr.p_double[i]; y2->ptr.p_double[i] = ytmp.ptr.p_double[i]; } tagsortfastr(x2, y2, &buf0, &buf1, npts, _state); ae_frame_leave(_state); } /************************************************************************* Fitting by polynomials in barycentric form. This function provides simple unterface for unconstrained unweighted fitting. See PolynomialFitWC() if you need constrained fitting. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFitWC() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0 * if given, only leading N elements of X/Y are used * if not given, automatically determined from sizes of X/Y M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfit(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector w; ae_vector xc; ae_vector yc; ae_vector dc; ae_frame_make(_state, &_frame_block); *info = 0; _barycentricinterpolant_clear(p); _polynomialfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); ae_assert(n>0, "PolynomialFit: N<=0!", _state); ae_assert(m>0, "PolynomialFit: M<=0!", _state); ae_assert(x->cnt>=n, "PolynomialFit: Length(X)cnt>=n, "PolynomialFit: Length(Y)0. * if given, only leading N elements of X/Y/W are used * if not given, automatically determined from sizes of X/Y/W XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * even simple constraints can be inconsistent, see Wikipedia article on this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the one special cases, however, we can guarantee consistency. This case is: M>1 and constraints on the function values (NOT DERIVATIVES) Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfitwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _w; ae_vector _xc; ae_vector _yc; double xa; double xb; double sa; double sb; ae_vector xoriginal; ae_vector yoriginal; ae_vector y2; ae_vector w2; ae_vector tmp; ae_vector tmp2; ae_vector bx; ae_vector by; ae_vector bw; ae_int_t i; ae_int_t j; double u; double v; double s; ae_int_t relcnt; lsfitreport lrep; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_w, w, _state); w = &_w; ae_vector_init_copy(&_xc, xc, _state); xc = &_xc; ae_vector_init_copy(&_yc, yc, _state); yc = &_yc; *info = 0; _barycentricinterpolant_clear(p); _polynomialfitreport_clear(rep); ae_vector_init(&xoriginal, 0, DT_REAL, _state); ae_vector_init(&yoriginal, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); ae_vector_init(&bx, 0, DT_REAL, _state); ae_vector_init(&by, 0, DT_REAL, _state); ae_vector_init(&bw, 0, DT_REAL, _state); _lsfitreport_init(&lrep, _state); ae_assert(n>0, "PolynomialFitWC: N<=0!", _state); ae_assert(m>0, "PolynomialFitWC: M<=0!", _state); ae_assert(k>=0, "PolynomialFitWC: K<0!", _state); ae_assert(k=M!", _state); ae_assert(x->cnt>=n, "PolynomialFitWC: Length(X)cnt>=n, "PolynomialFitWC: Length(Y)cnt>=n, "PolynomialFitWC: Length(W)cnt>=k, "PolynomialFitWC: Length(XC)cnt>=k, "PolynomialFitWC: Length(YC)cnt>=k, "PolynomialFitWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "PolynomialFitWC: one of DC[] is not 0 or 1!", _state); } /* * Scale X, Y, XC, YC. * Solve scaled problem using internal Chebyshev fitting function. */ lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); lsfit_internalchebyshevfit(x, y, w, n, xc, yc, dc, k, m, info, &tmp, &lrep, _state); if( *info<0 ) { ae_frame_leave(_state); return; } /* * Generate barycentric model and scale it * * BX, BY store barycentric model nodes * * FMatrix is reused (remember - it is at least MxM, what we need) * * Model intialization is done in O(M^2). In principle, it can be * done in O(M*log(M)), but before it we solved task with O(N*M^2) * complexity, so it is only a small amount of total time spent. */ ae_vector_set_length(&bx, m, _state); ae_vector_set_length(&by, m, _state); ae_vector_set_length(&bw, m, _state); ae_vector_set_length(&tmp2, m, _state); s = (double)(1); for(i=0; i<=m-1; i++) { if( m!=1 ) { u = ae_cos(ae_pi*i/(m-1), _state); } else { u = (double)(0); } v = (double)(0); for(j=0; j<=m-1; j++) { if( j==0 ) { tmp2.ptr.p_double[j] = (double)(1); } else { if( j==1 ) { tmp2.ptr.p_double[j] = u; } else { tmp2.ptr.p_double[j] = 2*u*tmp2.ptr.p_double[j-1]-tmp2.ptr.p_double[j-2]; } } v = v+tmp.ptr.p_double[j]*tmp2.ptr.p_double[j]; } bx.ptr.p_double[i] = u; by.ptr.p_double[i] = v; bw.ptr.p_double[i] = s; if( i==0||i==m-1 ) { bw.ptr.p_double[i] = 0.5*bw.ptr.p_double[i]; } s = -s; } barycentricbuildxyw(&bx, &by, &bw, m, p, _state); barycentriclintransx(p, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); barycentriclintransy(p, sb-sa, sa, _state); /* * Scale absolute errors obtained from LSFitLinearW. * Relative error should be calculated separately * (because of shifting/scaling of the task) */ rep->taskrcond = lrep.taskrcond; rep->rmserror = lrep.rmserror*(sb-sa); rep->avgerror = lrep.avgerror*(sb-sa); rep->maxerror = lrep.maxerror*(sb-sa); rep->avgrelerror = (double)(0); relcnt = 0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(p, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); relcnt = relcnt+1; } } if( relcnt!=0 ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_polynomialfitwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state) { polynomialfitwc(x,y,w,n,xc,yc,dc,k,m,info,p,rep, _state); } /************************************************************************* This function calculates value of four-parameter logistic (4PL) model at specified point X. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D- parameters of 4PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc4(double x, double a, double b, double c, double d, ae_state *_state) { double result; ae_assert(ae_isfinite(x, _state), "LogisticCalc4: X is not finite", _state); ae_assert(ae_isfinite(a, _state), "LogisticCalc4: A is not finite", _state); ae_assert(ae_isfinite(b, _state), "LogisticCalc4: B is not finite", _state); ae_assert(ae_isfinite(c, _state), "LogisticCalc4: C is not finite", _state); ae_assert(ae_isfinite(d, _state), "LogisticCalc4: D is not finite", _state); ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc4: X is negative", _state); ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc4: C is non-positive", _state); /* * Check for degenerate cases */ if( ae_fp_eq(b,(double)(0)) ) { result = 0.5*(a+d); return result; } if( ae_fp_eq(x,(double)(0)) ) { if( ae_fp_greater(b,(double)(0)) ) { result = a; } else { result = d; } return result; } /* * General case */ result = d+(a-d)/(1.0+ae_pow(x/c, b, _state)); ae_assert(ae_isfinite(result, _state), "LogisticCalc4: overflow during calculations", _state); return result; } /************************************************************************* This function calculates value of five-parameter logistic (5PL) model at specified point X. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D, G- parameters of 5PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained * G>0, non-positive value results in exception RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc5(double x, double a, double b, double c, double d, double g, ae_state *_state) { double result; ae_assert(ae_isfinite(x, _state), "LogisticCalc5: X is not finite", _state); ae_assert(ae_isfinite(a, _state), "LogisticCalc5: A is not finite", _state); ae_assert(ae_isfinite(b, _state), "LogisticCalc5: B is not finite", _state); ae_assert(ae_isfinite(c, _state), "LogisticCalc5: C is not finite", _state); ae_assert(ae_isfinite(d, _state), "LogisticCalc5: D is not finite", _state); ae_assert(ae_isfinite(g, _state), "LogisticCalc5: G is not finite", _state); ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc5: X is negative", _state); ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc5: C is non-positive", _state); ae_assert(ae_fp_greater(g,(double)(0)), "LogisticCalc5: G is non-positive", _state); /* * Check for degenerate cases */ if( ae_fp_eq(b,(double)(0)) ) { result = d+(a-d)/ae_pow(2.0, g, _state); return result; } if( ae_fp_eq(x,(double)(0)) ) { if( ae_fp_greater(b,(double)(0)) ) { result = a; } else { result = d; } return result; } /* * General case */ result = d+(a-d)/ae_pow(1.0+ae_pow(x/c, b, _state), g, _state); ae_assert(ae_isfinite(result, _state), "LogisticCalc5: overflow during calculations", _state); return result; } /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double* a, double* b, double* c, double* d, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; double g; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *a = 0; *b = 0; *c = 0; *d = 0; _lsfitreport_clear(rep); logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state); ae_frame_leave(_state); } /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user, with optional constraints on parameters A and D. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - with optional equality constraints * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4ec(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, double* a, double* b, double* c, double* d, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; double g; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *a = 0; *b = 0; *c = 0; *d = 0; _lsfitreport_clear(rep); logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state); ae_frame_leave(_state); } /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - unconstrained * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *a = 0; *b = 0; *c = 0; *d = 0; *g = 0; _lsfitreport_clear(rep); logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state); ae_frame_leave(_state); } /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user, subject to optional equality constraints on parameters A and D. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - with optional equality constraints * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5ec(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *a = 0; *b = 0; *c = 0; *d = 0; *g = 0; _lsfitreport_clear(rep); logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state); ae_frame_leave(_state); } /************************************************************************* This is "expert" 4PL/5PL fitting function, which can be used if you need better control over fitting process than provided by LogisticFit4() or LogisticFit5(). This function fits model of the form F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) or F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) Here: * A, D - unconstrained * B>=0 for 4PL, unconstrained for 5PL * C>0 * G>0 (if present) INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. Is4PL - whether 4PL or 5PL models are fitted LambdaV - regularization coefficient, LambdaV>=0. Set it to zero unless you know what you are doing. EpsX - stopping condition (step size), EpsX>=0. Zero value means that small step is automatically chosen. See notes below for more information. RsCnt - number of repeated restarts from random points. 4PL/5PL models are prone to problem of bad local extrema. Utilizing multiple random restarts allows us to improve algorithm convergence. RsCnt>=0. Zero value means that function automatically choose small amount of restarts (recommended). OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model G - parameter of 5PL model; for Is4PL=True, G=1 is returned. Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. For 5PL model things are different. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit45x(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, ae_bool is4pl, double lambdav, double epsx, ae_int_t rscnt, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_int_t i; ae_int_t k; ae_int_t innerit; ae_int_t outerit; ae_int_t nz; double v; double b00; double b01; double b10; double b11; double b30; double b31; ae_vector p0; ae_vector p1; ae_vector p2; ae_vector bndl; ae_vector bndu; ae_vector s; ae_matrix z; hqrndstate rs; minlmstate state; minlmreport replm; ae_int_t maxits; double fbest; double flast; double flast2; double scalex; double scaley; ae_vector bufx; ae_vector bufy; double rss; double tss; double meany; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *a = 0; *b = 0; *c = 0; *d = 0; *g = 0; _lsfitreport_clear(rep); ae_vector_init(&p0, 0, DT_REAL, _state); ae_vector_init(&p1, 0, DT_REAL, _state); ae_vector_init(&p2, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); _minlmstate_init(&state, _state); _minlmreport_init(&replm, _state); ae_vector_init(&bufx, 0, DT_REAL, _state); ae_vector_init(&bufy, 0, DT_REAL, _state); ae_assert(ae_isfinite(epsx, _state), "LogisticFitX: EpsX is infinite/NAN", _state); ae_assert(ae_isfinite(lambdav, _state), "LogisticFitX: LambdaV is infinite/NAN", _state); ae_assert(ae_isfinite(cnstrleft, _state)||ae_isnan(cnstrleft, _state), "LogisticFitX: CnstrLeft is NOT finite or NAN", _state); ae_assert(ae_isfinite(cnstrright, _state)||ae_isnan(cnstrright, _state), "LogisticFitX: CnstrRight is NOT finite or NAN", _state); ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "LogisticFitX: negative LambdaV", _state); ae_assert(n>0, "LogisticFitX: N<=0", _state); ae_assert(rscnt>=0, "LogisticFitX: RsCnt<0", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LogisticFitX: EpsX<0", _state); ae_assert(x->cnt>=n, "LogisticFitX: Length(X)cnt>=n, "LogisticFitX: Length(Y)ptr.p_double[0],(double)(0)), "LogisticFitX: some X[] are negative", _state); nz = n; for(i=0; i<=n-1; i++) { if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) { nz = i; break; } } /* * For NZ=N (all X[] are zero) special code is used. * For NZiterationscount = 0; if( nz==n ) { /* * NZ=N, degenerate problem. * No need to run optimizer. */ v = 0.0; for(i=0; i<=n-1; i++) { v = v+y->ptr.p_double[i]; } v = v/n; if( ae_isfinite(cnstrleft, _state) ) { *a = cnstrleft; } else { *a = v; } *b = (double)(1); *c = (double)(1); if( ae_isfinite(cnstrright, _state) ) { *d = cnstrright; } else { *d = *a; } *g = (double)(1); } else { /* * Non-degenerate problem. * Determine scale of data. */ scalex = x->ptr.p_double[nz+(n-nz)/2]; ae_assert(ae_fp_greater(scalex,(double)(0)), "LogisticFitX: internal error", _state); v = 0.0; for(i=0; i<=n-1; i++) { v = v+y->ptr.p_double[i]; } v = v/n; scaley = 0.0; for(i=0; i<=n-1; i++) { scaley = scaley+ae_sqr(y->ptr.p_double[i]-v, _state); } scaley = ae_sqrt(scaley/n, _state); if( ae_fp_eq(scaley,(double)(0)) ) { scaley = 1.0; } ae_vector_set_length(&s, 5, _state); s.ptr.p_double[0] = scaley; s.ptr.p_double[1] = 0.1; s.ptr.p_double[2] = scalex; s.ptr.p_double[3] = scaley; s.ptr.p_double[4] = 0.1; ae_vector_set_length(&p0, 5, _state); p0.ptr.p_double[0] = (double)(0); p0.ptr.p_double[1] = (double)(0); p0.ptr.p_double[2] = (double)(0); p0.ptr.p_double[3] = (double)(0); p0.ptr.p_double[4] = (double)(0); ae_vector_set_length(&bndl, 5, _state); ae_vector_set_length(&bndu, 5, _state); minlmcreatevj(5, n+5, &p0, &state, _state); minlmsetscale(&state, &s, _state); minlmsetcond(&state, 0.0, 0.0, epsx, maxits, _state); minlmsetxrep(&state, ae_true, _state); /* * Main loop - includes THREE (!) nested iterations: * * 1. Inner iteration is minimization of target function from * the current initial point P1 subject to boundary constraints * given by arrays BndL and BndU. * * 2. Middle iteration changes boundary constraints from tight to * relaxed ones: * * at the first middle iteration we optimize with "tight" * constraints on parameters B and C (P[1] and P[2]). It * allows us to find good initial point for the next middle * iteration without risk of running into "hard" points (B=0, C=0). * Initial point is initialized by outer iteration. * Solution is placed to P1. * * at the second middle iteration we relax boundary constraints * on B and C. Solution P1 from the first middle iteration is * used as initial point for the second one. * * both first and second iterations are 4PL models, even when * we fit 5PL. * * additionally, for 5PL models, we use results from the second * middle iteration is initial guess for 5PL fit. * * after middle iteration is over we compare quality of the * solution stored in P1 and offload it to A/B/C/D/G, if it * is better. * * 3. Outer iteration (starts below) changes following parameters: * * initial point * * "tight" constraints BndL/BndU * * "relaxed" constraints BndL/BndU * * Below we prepare combined matrix Z of optimization settings for * outer/middle iterations: * * [ P00 BndL00 BndU00 BndL01 BndU01 ] * [ ] * [ P10 BndL10 BndU10 BndL11 BndU11 ] * * Here: * * Pi0 is initial point for I-th outer iteration * * BndLij is lower boundary for I-th outer iteration, J-th inner iteration * * BndUij - same as BndLij */ ae_matrix_set_length(&z, rscnt, 5+4*5, _state); for(i=0; i<=rscnt-1; i++) { if( ae_isfinite(cnstrleft, _state) ) { z.ptr.pp_double[i][0] = cnstrleft; } else { z.ptr.pp_double[i][0] = y->ptr.p_double[0]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5); } z.ptr.pp_double[i][1] = 0.5+hqrnduniformr(&rs, _state); z.ptr.pp_double[i][2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)]; if( ae_isfinite(cnstrright, _state) ) { z.ptr.pp_double[i][3] = cnstrright; } else { z.ptr.pp_double[i][3] = y->ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5); } z.ptr.pp_double[i][4] = 1.0; if( ae_isfinite(cnstrleft, _state) ) { z.ptr.pp_double[i][5+0] = cnstrleft; z.ptr.pp_double[i][10+0] = cnstrleft; } else { z.ptr.pp_double[i][5+0] = _state->v_neginf; z.ptr.pp_double[i][10+0] = _state->v_posinf; } z.ptr.pp_double[i][5+1] = 0.5; z.ptr.pp_double[i][10+1] = 2.0; z.ptr.pp_double[i][5+2] = 0.5*scalex; z.ptr.pp_double[i][10+2] = 2.0*scalex; if( ae_isfinite(cnstrright, _state) ) { z.ptr.pp_double[i][5+3] = cnstrright; z.ptr.pp_double[i][10+3] = cnstrright; } else { z.ptr.pp_double[i][5+3] = _state->v_neginf; z.ptr.pp_double[i][10+3] = _state->v_posinf; } z.ptr.pp_double[i][5+4] = 1.0; z.ptr.pp_double[i][10+4] = 1.0; if( ae_isfinite(cnstrleft, _state) ) { z.ptr.pp_double[i][15+0] = cnstrleft; z.ptr.pp_double[i][20+0] = cnstrleft; } else { z.ptr.pp_double[i][15+0] = _state->v_neginf; z.ptr.pp_double[i][20+0] = _state->v_posinf; } z.ptr.pp_double[i][15+1] = 0.01; z.ptr.pp_double[i][20+1] = _state->v_posinf; z.ptr.pp_double[i][15+2] = ae_machineepsilon*scalex; z.ptr.pp_double[i][20+2] = _state->v_posinf; if( ae_isfinite(cnstrright, _state) ) { z.ptr.pp_double[i][15+3] = cnstrright; z.ptr.pp_double[i][20+3] = cnstrright; } else { z.ptr.pp_double[i][15+3] = _state->v_neginf; z.ptr.pp_double[i][20+3] = _state->v_posinf; } z.ptr.pp_double[i][15+4] = 1.0; z.ptr.pp_double[i][20+4] = 1.0; } /* * Run outer iterations */ *a = (double)(0); *b = (double)(1); *c = (double)(1); *d = (double)(1); *g = (double)(1); fbest = ae_maxrealnumber; ae_vector_set_length(&p1, 5, _state); ae_vector_set_length(&p2, 5, _state); for(outerit=0; outerit<=z.rows-1; outerit++) { /* * Beginning of the middle iterations. * Prepare initial point P1. */ for(i=0; i<=4; i++) { p1.ptr.p_double[i] = z.ptr.pp_double[outerit][i]; } flast = ae_maxrealnumber; for(innerit=0; innerit<=1; innerit++) { /* * Set current boundary constraints. * Run inner iteration. */ for(i=0; i<=4; i++) { bndl.ptr.p_double[i] = z.ptr.pp_double[outerit][5+innerit*10+0+i]; bndu.ptr.p_double[i] = z.ptr.pp_double[outerit][5+innerit*10+5+i]; } minlmsetbc(&state, &bndl, &bndu, _state); lsfit_logisticfitinternal(x, y, n, ae_true, lambdav, &state, &replm, &p1, &flast, _state); rep->iterationscount = rep->iterationscount+replm.iterationscount; } /* * Middle iteration: try to fit with 5-parameter logistic model (if needed). * * We perform two attempts to fit: one with B>0, another one with B<0. * For PL4, these are equivalent up to transposition of A/D, but for 5PL * sign of B is very important. * * NOTE: results of 4PL fit are used as initial point for 5PL. */ if( !is4pl ) { /* * Loosen constraints on G, * save constraints on A/B/D to B0/B1 */ bndl.ptr.p_double[4] = 0.1; bndu.ptr.p_double[4] = 10.0; b00 = bndl.ptr.p_double[0]; b01 = bndu.ptr.p_double[0]; b10 = bndl.ptr.p_double[1]; b11 = bndu.ptr.p_double[1]; b30 = bndl.ptr.p_double[3]; b31 = bndu.ptr.p_double[3]; /* * First attempt: fitting with positive B */ p2.ptr.p_double[0] = p1.ptr.p_double[0]; p2.ptr.p_double[1] = p1.ptr.p_double[1]; p2.ptr.p_double[2] = p1.ptr.p_double[2]; p2.ptr.p_double[3] = p1.ptr.p_double[3]; p2.ptr.p_double[4] = p1.ptr.p_double[4]; bndl.ptr.p_double[0] = b00; bndu.ptr.p_double[0] = b01; bndl.ptr.p_double[1] = b10; bndu.ptr.p_double[1] = b11; bndl.ptr.p_double[3] = b30; bndu.ptr.p_double[3] = b31; minlmsetbc(&state, &bndl, &bndu, _state); lsfit_logisticfitinternal(x, y, n, ae_false, lambdav, &state, &replm, &p2, &flast2, _state); rep->iterationscount = rep->iterationscount+replm.iterationscount; if( ae_fp_less(flast2,flast) ) { for(i=0; i<=4; i++) { p1.ptr.p_double[i] = p2.ptr.p_double[i]; } flast = flast2; } /* * First attempt: fitting with negative B */ p2.ptr.p_double[0] = p1.ptr.p_double[3]; p2.ptr.p_double[1] = -p1.ptr.p_double[1]; p2.ptr.p_double[2] = p1.ptr.p_double[2]; p2.ptr.p_double[3] = p1.ptr.p_double[0]; p2.ptr.p_double[4] = p1.ptr.p_double[4]; bndl.ptr.p_double[0] = b30; bndu.ptr.p_double[0] = b31; bndl.ptr.p_double[1] = -b11; bndu.ptr.p_double[1] = -b10; bndl.ptr.p_double[3] = b00; bndu.ptr.p_double[3] = b01; minlmsetbc(&state, &bndl, &bndu, _state); lsfit_logisticfitinternal(x, y, n, ae_false, lambdav, &state, &replm, &p2, &flast2, _state); rep->iterationscount = rep->iterationscount+replm.iterationscount; if( ae_fp_less(flast2,flast) ) { for(i=0; i<=4; i++) { p1.ptr.p_double[i] = p2.ptr.p_double[i]; } flast = flast2; } } /* * Middle iteration is done, compare its results with best value * found so far. */ if( ae_fp_less(flast,fbest) ) { *a = p1.ptr.p_double[0]; *b = p1.ptr.p_double[1]; *c = p1.ptr.p_double[2]; *d = p1.ptr.p_double[3]; *g = p1.ptr.p_double[4]; fbest = flast; } } } /* * Calculate errors */ rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); rep->maxerror = (double)(0); k = 0; rss = 0.0; tss = 0.0; meany = 0.0; for(i=0; i<=n-1; i++) { meany = meany+y->ptr.p_double[i]; } meany = meany/n; for(i=0; i<=n-1; i++) { /* * Calculate residual from regression */ if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) { v = *d+(*a-(*d))/ae_pow(1.0+ae_pow(x->ptr.p_double[i]/(*c), *b, _state), *g, _state)-y->ptr.p_double[i]; } else { if( ae_fp_greater_eq(*b,(double)(0)) ) { v = *a-y->ptr.p_double[i]; } else { v = *d-y->ptr.p_double[i]; } } /* * Update RSS (residual sum of squares) and TSS (total sum of squares) * which are used to calculate coefficient of determination. * * NOTE: we use formula R2 = 1-RSS/TSS because it has nice property of * being equal to 0.0 if and only if model perfectly fits data. * * When we fit nonlinear models, there are exist multiple ways of * determining R2, each of them giving different results. Formula * above is the most intuitive one. */ rss = rss+v*v; tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state); /* * Update errors */ rep->rmserror = rep->rmserror+ae_sqr(v, _state); rep->avgerror = rep->avgerror+ae_fabs(v, _state); if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state); k = k+1; } rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); } rep->rmserror = ae_sqrt(rep->rmserror/n, _state); rep->avgerror = rep->avgerror/n; if( k>0 ) { rep->avgrelerror = rep->avgrelerror/k; } rep->r2 = 1.0-rss/tss; ae_frame_leave(_state); } /************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t d; ae_int_t i; double wrmscur; double wrmsbest; barycentricinterpolant locb; barycentricfitreport locrep; ae_int_t locinfo; ae_frame_make(_state, &_frame_block); *info = 0; _barycentricinterpolant_clear(b); _barycentricfitreport_clear(rep); _barycentricinterpolant_init(&locb, _state); _barycentricfitreport_init(&locrep, _state); ae_assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!", _state); ae_assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!", _state); ae_assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!", _state); ae_assert(k=M!", _state); ae_assert(x->cnt>=n, "BarycentricFitFloaterHormannWC: Length(X)cnt>=n, "BarycentricFitFloaterHormannWC: Length(Y)cnt>=n, "BarycentricFitFloaterHormannWC: Length(W)cnt>=k, "BarycentricFitFloaterHormannWC: Length(XC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(YC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!", _state); } /* * Find optimal D * * Info is -3 by default (degenerate constraints). * If LocInfo will always be equal to -3, Info will remain equal to -3. * If at least once LocInfo will be -4, Info will be -4. */ wrmsbest = ae_maxrealnumber; rep->dbest = -1; *info = -3; for(d=0; d<=ae_minint(9, n-1, _state); d++) { lsfit_barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, &locinfo, &locb, &locrep, _state); ae_assert((locinfo==-4||locinfo==-3)||locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!", _state); if( locinfo>0 ) { /* * Calculate weghted RMS */ wrmscur = (double)(0); for(i=0; i<=n-1; i++) { wrmscur = wrmscur+ae_sqr(w->ptr.p_double[i]*(y->ptr.p_double[i]-barycentriccalc(&locb, x->ptr.p_double[i], _state)), _state); } wrmscur = ae_sqrt(wrmscur/n, _state); if( ae_fp_less(wrmscur,wrmsbest)||rep->dbest<0 ) { barycentriccopy(&locb, b, _state); rep->dbest = d; *info = 1; rep->rmserror = locrep.rmserror; rep->avgerror = locrep.avgerror; rep->avgrelerror = locrep.avgrelerror; rep->maxerror = locrep.maxerror; rep->taskrcond = locrep.taskrcond; wrmsbest = wrmscur; } } else { if( locinfo!=-3&&*info<0 ) { *info = locinfo; } } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state) { barycentricfitfloaterhormannwc(x,y,w,n,xc,yc,dc,k,m,info,b,rep, _state); } /************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormann(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector w; ae_vector xc; ae_vector yc; ae_vector dc; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; _barycentricinterpolant_clear(b); _barycentricfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); ae_assert(n>0, "BarycentricFitFloaterHormann: N<=0!", _state); ae_assert(m>0, "BarycentricFitFloaterHormann: M<=0!", _state); ae_assert(x->cnt>=n, "BarycentricFitFloaterHormann: Length(X)cnt>=n, "BarycentricFitFloaterHormann: Length(Y)0 * if given, only first N elements of X/Y are processed * if not given, automatically determined from X/Y sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalized(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector w; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_assert(n>=1, "Spline1DFitPenalized: N<1!", _state); ae_assert(m>=4, "Spline1DFitPenalized: M<4!", _state); ae_assert(x->cnt>=n, "Spline1DFitPenalized: Length(X)cnt>=n, "Spline1DFitPenalized: Length(Y)0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 19.10.2010 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalizedw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _w; ae_int_t i; ae_int_t j; ae_int_t b; double v; double relcnt; double xa; double xb; double sa; double sb; ae_vector xoriginal; ae_vector yoriginal; double pdecay; double tdecay; ae_matrix fmatrix; ae_vector fcolumn; ae_vector y2; ae_vector w2; ae_vector xc; ae_vector yc; ae_vector dc; double fdmax; double admax; ae_matrix amatrix; ae_matrix d2matrix; double fa; double ga; double fb; double gb; double lambdav; ae_vector bx; ae_vector by; ae_vector bd1; ae_vector bd2; ae_vector tx; ae_vector ty; ae_vector td; spline1dinterpolant bs; ae_matrix nmatrix; ae_vector rightpart; fblslincgstate cgstate; ae_vector c; ae_vector tmp0; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_w, w, _state); w = &_w; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_vector_init(&xoriginal, 0, DT_REAL, _state); ae_vector_init(&yoriginal, 0, DT_REAL, _state); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&fcolumn, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); ae_matrix_init(&amatrix, 0, 0, DT_REAL, _state); ae_matrix_init(&d2matrix, 0, 0, DT_REAL, _state); ae_vector_init(&bx, 0, DT_REAL, _state); ae_vector_init(&by, 0, DT_REAL, _state); ae_vector_init(&bd1, 0, DT_REAL, _state); ae_vector_init(&bd2, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); ae_vector_init(&ty, 0, DT_REAL, _state); ae_vector_init(&td, 0, DT_REAL, _state); _spline1dinterpolant_init(&bs, _state); ae_matrix_init(&nmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&rightpart, 0, DT_REAL, _state); _fblslincgstate_init(&cgstate, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_assert(n>=1, "Spline1DFitPenalizedW: N<1!", _state); ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state); ae_assert(x->cnt>=n, "Spline1DFitPenalizedW: Length(X)cnt>=n, "Spline1DFitPenalizedW: Length(Y)cnt>=n, "Spline1DFitPenalizedW: Length(W)ptr.p_double[i]*fcolumn.ptr.p_double[i], _state); } fdmax = ae_maxreal(fdmax, v, _state); /* * Fill temporary with second derivatives of basis function */ ae_v_move(&d2matrix.ptr.pp_double[b][0], 1, &bd2.ptr.p_double[0], 1, ae_v_len(0,m-1)); } /* * * calculate penalty matrix A * * calculate max of diagonal elements of A * * calculate PDecay - coefficient before penalty matrix */ for(i=0; i<=m-1; i++) { for(j=i; j<=m-1; j++) { /* * calculate integral(B_i''*B_j'') where B_i and B_j are * i-th and j-th basis splines. * B_i and B_j are piecewise linear functions. */ v = (double)(0); for(b=0; b<=m-2; b++) { fa = d2matrix.ptr.pp_double[i][b]; fb = d2matrix.ptr.pp_double[i][b+1]; ga = d2matrix.ptr.pp_double[j][b]; gb = d2matrix.ptr.pp_double[j][b+1]; v = v+(bx.ptr.p_double[b+1]-bx.ptr.p_double[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3); } amatrix.ptr.pp_double[i][j] = v; amatrix.ptr.pp_double[j][i] = v; } } admax = (double)(0); for(i=0; i<=m-1; i++) { admax = ae_maxreal(admax, ae_fabs(amatrix.ptr.pp_double[i][i], _state), _state); } pdecay = lambdav*fdmax/admax; /* * Calculate TDecay for Tikhonov regularization */ tdecay = fdmax*(1+pdecay)*10*ae_machineepsilon; /* * Prepare system * * NOTE: FMatrix is spoiled during this process */ for(i=0; i<=n-1; i++) { v = w->ptr.p_double[i]; ae_v_muld(&fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } rmatrixgemm(m, m, n, 1.0, &fmatrix, 0, 0, 1, &fmatrix, 0, 0, 0, 0.0, &nmatrix, 0, 0, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { nmatrix.ptr.pp_double[i][j] = nmatrix.ptr.pp_double[i][j]+pdecay*amatrix.ptr.pp_double[i][j]; } } for(i=0; i<=m-1; i++) { nmatrix.ptr.pp_double[i][i] = nmatrix.ptr.pp_double[i][i]+tdecay; } for(i=0; i<=m-1; i++) { rightpart.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = y->ptr.p_double[i]*w->ptr.p_double[i]; ae_v_addd(&rightpart.ptr.p_double[0], 1, &fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } /* * Solve system */ if( !spdmatrixcholesky(&nmatrix, m, ae_true, _state) ) { *info = -4; ae_frame_leave(_state); return; } fblscholeskysolve(&nmatrix, 1.0, m, ae_true, &rightpart, &tmp0, _state); ae_v_move(&c.ptr.p_double[0], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(0,m-1)); /* * add nodes to force linearity outside of the fitting interval */ spline1dgriddiffcubic(&bx, &c, m, 2, 0.0, 2, 0.0, &bd1, _state); ae_vector_set_length(&tx, m+2, _state); ae_vector_set_length(&ty, m+2, _state); ae_vector_set_length(&td, m+2, _state); ae_v_move(&tx.ptr.p_double[1], 1, &bx.ptr.p_double[0], 1, ae_v_len(1,m)); ae_v_move(&ty.ptr.p_double[1], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(1,m)); ae_v_move(&td.ptr.p_double[1], 1, &bd1.ptr.p_double[0], 1, ae_v_len(1,m)); tx.ptr.p_double[0] = tx.ptr.p_double[1]-(tx.ptr.p_double[2]-tx.ptr.p_double[1]); ty.ptr.p_double[0] = ty.ptr.p_double[1]-td.ptr.p_double[1]*(tx.ptr.p_double[2]-tx.ptr.p_double[1]); td.ptr.p_double[0] = td.ptr.p_double[1]; tx.ptr.p_double[m+1] = tx.ptr.p_double[m]+(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); ty.ptr.p_double[m+1] = ty.ptr.p_double[m]+td.ptr.p_double[m]*(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); td.ptr.p_double[m+1] = td.ptr.p_double[m]; spline1dbuildhermite(&tx, &ty, &td, m+2, s, _state); spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); spline1dlintransy(s, sb-sa, sa, _state); *info = 1; /* * Fill report */ rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); rep->maxerror = (double)(0); relcnt = (double)(0); spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state); for(i=0; i<=n-1; i++) { v = (sb-sa)*fcolumn.ptr.p_double[i]+sa; rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state); rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state); if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); relcnt = relcnt+1; } rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state); } rep->rmserror = ae_sqrt(rep->rmserror/n, _state); rep->avgerror = rep->avgerror/n; if( ae_fp_neq(relcnt,(double)(0)) ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spline1dfitpenalizedw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { spline1dfitpenalizedw(x,y,w,n,m,rho,info,s,rep, _state); } /************************************************************************* Weighted fitting by cubic spline, with constraints on function values or derivatives. Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with continuous second derivatives and non-fixed first derivatives at interval ends. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, less smooth) Spline1DFitCubic() - "lightweight" fitting by cubic splines, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints S - spline interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function values AND/OR its derivatives at the interval boundaries. * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubicwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_int_t i; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_assert(n>=1, "Spline1DFitCubicWC: N<1!", _state); ae_assert(m>=4, "Spline1DFitCubicWC: M<4!", _state); ae_assert(k>=0, "Spline1DFitCubicWC: K<0!", _state); ae_assert(k=M!", _state); ae_assert(x->cnt>=n, "Spline1DFitCubicWC: Length(X)cnt>=n, "Spline1DFitCubicWC: Length(Y)cnt>=n, "Spline1DFitCubicWC: Length(W)cnt>=k, "Spline1DFitCubicWC: Length(XC)cnt>=k, "Spline1DFitCubicWC: Length(YC)cnt>=k, "Spline1DFitCubicWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitCubicWC: DC[i] is neither 0 or 1!", _state); } lsfit_spline1dfitinternal(0, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spline1dfitcubicwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { spline1dfitcubicwc(x,y,w,n,xc,yc,dc,k,m,info,s,rep, _state); } /************************************************************************* Weighted fitting by Hermite spline, with constraints on function values or first derivatives. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are Hermite splines. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, more smooth) Spline1DFitHermite() - "lightweight" Hermite fitting, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4, M IS EVEN! OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -2 means odd M was passed (which is not supported) -1 means another errors in parameters passed (N<=0, for example) S - spline interpolant. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. IMPORTANT: this subroitine supports only even M's ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the several special cases, however, we can guarantee consistency. * one of this cases is M>=4 and constraints on the function value (AND/OR its derivative) at the interval boundaries. * another special case is M>=4 and ONE constraint on the function value (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermitewc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_int_t i; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_assert(n>=1, "Spline1DFitHermiteWC: N<1!", _state); ae_assert(m>=4, "Spline1DFitHermiteWC: M<4!", _state); ae_assert(m%2==0, "Spline1DFitHermiteWC: M is odd!", _state); ae_assert(k>=0, "Spline1DFitHermiteWC: K<0!", _state); ae_assert(k=M!", _state); ae_assert(x->cnt>=n, "Spline1DFitHermiteWC: Length(X)cnt>=n, "Spline1DFitHermiteWC: Length(Y)cnt>=n, "Spline1DFitHermiteWC: Length(W)cnt>=k, "Spline1DFitHermiteWC: Length(XC)cnt>=k, "Spline1DFitHermiteWC: Length(YC)cnt>=k, "Spline1DFitHermiteWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitHermiteWC: DC[i] is neither 0 or 1!", _state); } lsfit_spline1dfitinternal(1, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spline1dfithermitewc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { spline1dfithermitewc(x,y,w,n,xc,yc,dc,k,m,info,s,rep, _state); } /************************************************************************* Least squares fitting by cubic spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information about subroutine parameters (we don't duplicate it here because of length) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector w; ae_vector xc; ae_vector yc; ae_vector dc; ae_frame_make(_state, &_frame_block); *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); ae_assert(n>=1, "Spline1DFitCubic: N<1!", _state); ae_assert(m>=4, "Spline1DFitCubic: M<4!", _state); ae_assert(x->cnt>=n, "Spline1DFitCubic: Length(X)cnt>=n, "Spline1DFitCubic: Length(Y)=1, "Spline1DFitHermite: N<1!", _state); ae_assert(m>=4, "Spline1DFitHermite: M<4!", _state); ae_assert(m%2==0, "Spline1DFitHermite: M is odd!", _state); ae_assert(x->cnt>=n, "Spline1DFitHermite: Length(X)cnt>=n, "Spline1DFitHermite: Length(Y)=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -1 incorrect N/M were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearw(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_assert(n>=1, "LSFitLinearW: N<1!", _state); ae_assert(m>=1, "LSFitLinearW: M<1!", _state); ae_assert(y->cnt>=n, "LSFitLinearW: length(Y)cnt>=n, "LSFitLinearW: length(W)rows>=n, "LSFitLinearW: rows(FMatrix)cols>=m, "LSFitLinearW: cols(FMatrix)=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearwc(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _y; ae_matrix _cmatrix; ae_int_t i; ae_int_t j; ae_vector tau; ae_matrix q; ae_matrix f2; ae_vector tmp; ae_vector c0; double v; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_y, y, _state); y = &_y; ae_matrix_init_copy(&_cmatrix, cmatrix, _state); cmatrix = &_cmatrix; *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_vector_init(&tau, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&f2, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&c0, 0, DT_REAL, _state); ae_assert(n>=1, "LSFitLinearWC: N<1!", _state); ae_assert(m>=1, "LSFitLinearWC: M<1!", _state); ae_assert(k>=0, "LSFitLinearWC: K<0!", _state); ae_assert(y->cnt>=n, "LSFitLinearWC: length(Y)cnt>=n, "LSFitLinearWC: length(W)rows>=n, "LSFitLinearWC: rows(FMatrix)cols>=m, "LSFitLinearWC: cols(FMatrix)rows>=k, "LSFitLinearWC: rows(CMatrix)cols>=m+1||k==0, "LSFitLinearWC: cols(CMatrix)=m ) { *info = -3; ae_frame_leave(_state); return; } /* * Solve */ if( k==0 ) { /* * no constraints */ lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state); } else { /* * First, find general form solution of constraints system: * * factorize C = L*Q * * unpack Q * * fill upper part of C with zeros (for RCond) * * We got C=C0+Q2'*y where Q2 is lower M-K rows of Q. */ rmatrixlq(cmatrix, k, m, &tau, _state); rmatrixlqunpackq(cmatrix, k, m, &tau, m, &q, _state); for(i=0; i<=k-1; i++) { for(j=i+1; j<=m-1; j++) { cmatrix->ptr.pp_double[i][j] = 0.0; } } if( ae_fp_less(rmatrixlurcondinf(cmatrix, k, _state),1000*ae_machineepsilon) ) { *info = -3; ae_frame_leave(_state); return; } ae_vector_set_length(&tmp, k, _state); for(i=0; i<=k-1; i++) { if( i>0 ) { v = ae_v_dotproduct(&cmatrix->ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1)); } else { v = (double)(0); } tmp.ptr.p_double[i] = (cmatrix->ptr.pp_double[i][m]-v)/cmatrix->ptr.pp_double[i][i]; } ae_vector_set_length(&c0, m, _state); for(i=0; i<=m-1; i++) { c0.ptr.p_double[i] = (double)(0); } for(i=0; i<=k-1; i++) { v = tmp.ptr.p_double[i]; ae_v_addd(&c0.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } /* * Second, prepare modified matrix F2 = F*Q2' and solve modified task */ ae_vector_set_length(&tmp, ae_maxint(n, m, _state)+1, _state); ae_matrix_set_length(&f2, n, m-k, _state); matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &c0, 0, m-1, -1.0, y, 0, n-1, 1.0, _state); rmatrixgemm(n, m-k, m, 1.0, fmatrix, 0, 0, 0, &q, k, 0, 1, 0.0, &f2, 0, 0, _state); lsfit_lsfitlinearinternal(y, w, &f2, n, m-k, info, &tmp, rep, _state); rep->taskrcond = (double)(-1); if( *info<=0 ) { ae_frame_leave(_state); return; } /* * then, convert back to original answer: C = C0 + Q2'*Y0 */ ae_vector_set_length(c, m, _state); ae_v_move(&c->ptr.p_double[0], 1, &c0.ptr.p_double[0], 1, ae_v_len(0,m-1)); matrixvectormultiply(&q, k, m-1, 0, m-1, ae_true, &tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_lsfitlinearwc(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { lsfitlinearwc(y,w,fmatrix,cmatrix,n,m,k,info,c,rep, _state); } /************************************************************************* Linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinear(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector w; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_assert(n>=1, "LSFitLinear: N<1!", _state); ae_assert(m>=1, "LSFitLinear: M<1!", _state); ae_assert(y->cnt>=n, "LSFitLinear: length(Y)rows>=n, "LSFitLinear: rows(FMatrix)cols>=m, "LSFitLinear: cols(FMatrix)=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearc(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _y; ae_vector w; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_y, y, _state); y = &_y; *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_assert(n>=1, "LSFitLinearC: N<1!", _state); ae_assert(m>=1, "LSFitLinearC: M<1!", _state); ae_assert(k>=0, "LSFitLinearC: K<0!", _state); ae_assert(y->cnt>=n, "LSFitLinearC: length(Y)rows>=n, "LSFitLinearC: rows(FMatrix)cols>=m, "LSFitLinearC: cols(FMatrix)rows>=k, "LSFitLinearC: rows(CMatrix)cols>=m+1||k==0, "LSFitLinearC: cols(CMatrix)1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewf(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateWF: N<1!", _state); ae_assert(m>=1, "LSFitCreateWF: M<1!", _state); ae_assert(k>=1, "LSFitCreateWF: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateWF: length(C)cnt>=n, "LSFitCreateWF: length(Y)cnt>=n, "LSFitCreateWF: length(W)rows>=n, "LSFitCreateWF: rows(X)cols>=m, "LSFitCreateWF: cols(X)teststep = (double)(0); state->diffstep = diffstep; state->npoints = n; state->nweights = n; state->wkind = 1; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->taskw, n, _state); ae_vector_set_length(&state->c, k, _state); ae_vector_set_length(&state->x, m, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 0; state->prevnpt = -1; state->prevalgo = -1; minlmcreatev(k, n, &state->c, diffstep, &state->optstate, _state); lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatef(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateF: N<1!", _state); ae_assert(m>=1, "LSFitCreateF: M<1!", _state); ae_assert(k>=1, "LSFitCreateF: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateF: length(C)cnt>=n, "LSFitCreateF: length(Y)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)teststep = (double)(0); state->diffstep = diffstep; state->npoints = n; state->wkind = 0; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->c, k, _state); ae_vector_set_length(&state->x, m, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 0; state->prevnpt = -1; state->prevalgo = -1; minlmcreatev(k, n, &state->c, diffstep, &state->optstate, _state); lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfg(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, ae_bool cheapfg, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateWFG: N<1!", _state); ae_assert(m>=1, "LSFitCreateWFG: M<1!", _state); ae_assert(k>=1, "LSFitCreateWFG: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateWFG: length(C)cnt>=n, "LSFitCreateWFG: length(Y)cnt>=n, "LSFitCreateWFG: length(W)rows>=n, "LSFitCreateWFG: rows(X)cols>=m, "LSFitCreateWFG: cols(X)teststep = (double)(0); state->diffstep = (double)(0); state->npoints = n; state->nweights = n; state->wkind = 1; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->taskw, n, _state); ae_vector_set_length(&state->c, k, _state); ae_vector_set_length(&state->x, m, _state); ae_vector_set_length(&state->g, k, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 1; state->prevnpt = -1; state->prevalgo = -1; if( cheapfg ) { minlmcreatevgj(k, n, &state->c, &state->optstate, _state); } else { minlmcreatevj(k, n, &state->c, &state->optstate, _state); } lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Nonlinear least squares fitting using gradient only, without individual weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefg(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, ae_bool cheapfg, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateFG: N<1!", _state); ae_assert(m>=1, "LSFitCreateFG: M<1!", _state); ae_assert(k>=1, "LSFitCreateFG: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateFG: length(C)cnt>=n, "LSFitCreateFG: length(Y)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)teststep = (double)(0); state->diffstep = (double)(0); state->npoints = n; state->wkind = 0; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->c, k, _state); ae_vector_set_length(&state->x, m, _state); ae_vector_set_length(&state->g, k, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 1; state->prevnpt = -1; state->prevalgo = -1; if( cheapfg ) { minlmcreatevgj(k, n, &state->c, &state->optstate, _state); } else { minlmcreatevj(k, n, &state->c, &state->optstate, _state); } lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Weighted nonlinear least squares fitting using gradient/Hessian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfgh(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateWFGH: N<1!", _state); ae_assert(m>=1, "LSFitCreateWFGH: M<1!", _state); ae_assert(k>=1, "LSFitCreateWFGH: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateWFGH: length(C)cnt>=n, "LSFitCreateWFGH: length(Y)cnt>=n, "LSFitCreateWFGH: length(W)rows>=n, "LSFitCreateWFGH: rows(X)cols>=m, "LSFitCreateWFGH: cols(X)teststep = (double)(0); state->diffstep = (double)(0); state->npoints = n; state->nweights = n; state->wkind = 1; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->taskw, n, _state); ae_vector_set_length(&state->c, k, _state); ae_matrix_set_length(&state->h, k, k, _state); ae_vector_set_length(&state->x, m, _state); ae_vector_set_length(&state->g, k, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 2; state->prevnpt = -1; state->prevalgo = -1; minlmcreatefgh(k, &state->c, &state->optstate, _state); lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefgh(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate* state, ae_state *_state) { ae_int_t i; _lsfitstate_clear(state); ae_assert(n>=1, "LSFitCreateFGH: N<1!", _state); ae_assert(m>=1, "LSFitCreateFGH: M<1!", _state); ae_assert(k>=1, "LSFitCreateFGH: K<1!", _state); ae_assert(c->cnt>=k, "LSFitCreateFGH: length(C)cnt>=n, "LSFitCreateFGH: length(Y)rows>=n, "LSFitCreateFGH: rows(X)cols>=m, "LSFitCreateFGH: cols(X)teststep = (double)(0); state->diffstep = (double)(0); state->npoints = n; state->wkind = 0; state->m = m; state->k = k; lsfitsetcond(state, 0.0, 0.0, 0, _state); lsfitsetstpmax(state, 0.0, _state); lsfitsetxrep(state, ae_false, _state); ae_matrix_set_length(&state->taskx, n, m, _state); ae_vector_set_length(&state->tasky, n, _state); ae_vector_set_length(&state->c, k, _state); ae_matrix_set_length(&state->h, k, k, _state); ae_vector_set_length(&state->x, m, _state); ae_vector_set_length(&state->g, k, _state); ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); for(i=0; i<=n-1; i++) { ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; } ae_vector_set_length(&state->s, k, _state); ae_vector_set_length(&state->bndl, k, _state); ae_vector_set_length(&state->bndu, k, _state); for(i=0; i<=k-1; i++) { state->s.ptr.p_double[i] = 1.0; state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; } state->optalgo = 2; state->prevnpt = -1; state->prevalgo = -1; minlmcreatefgh(k, &state->c, &state->optstate, _state); lsfit_lsfitclearrequestfields(state, _state); ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by LSFitSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitsetcond(lsfitstate* state, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsf, _state), "LSFitSetCond: EpsF is not finite!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "LSFitSetCond: negative EpsF!", _state); ae_assert(ae_isfinite(epsx, _state), "LSFitSetCond: EpsX is not finite!", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LSFitSetCond: negative EpsX!", _state); ae_assert(maxits>=0, "LSFitSetCond: negative MaxIts!", _state); state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state) { ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "LSFitSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function sets scaling coefficients for underlying optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetscale(lsfitstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->k, "LSFitSetScale: Length(S)k-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "LSFitSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "LSFitSetScale: S contains infinite or NAN elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function sets boundary constraints for underlying optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[K]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[K]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: unlike other constrained optimization algorithms, this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetbc(lsfitstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_int_t i; ae_int_t k; k = state->k; ae_assert(bndl->cnt>=k, "LSFitSetBC: Length(BndL)cnt>=k, "LSFitSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "LSFitSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "LSFitSetBC: BndU contains NAN or -INF", _state); if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) ) { ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "LSFitSetBC: BndL[i]>BndU[i]", _state); } state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; } } /************************************************************************* NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ ae_bool lsfititeration(lsfitstate* state, ae_state *_state) { double lx; double lf; double ld; double rx; double rf; double rd; ae_int_t n; ae_int_t m; ae_int_t k; double v; double vv; double relcnt; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t info; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; k = state->rstate.ia.ptr.p_int[2]; i = state->rstate.ia.ptr.p_int[3]; j = state->rstate.ia.ptr.p_int[4]; j1 = state->rstate.ia.ptr.p_int[5]; info = state->rstate.ia.ptr.p_int[6]; lx = state->rstate.ra.ptr.p_double[0]; lf = state->rstate.ra.ptr.p_double[1]; ld = state->rstate.ra.ptr.p_double[2]; rx = state->rstate.ra.ptr.p_double[3]; rf = state->rstate.ra.ptr.p_double[4]; rd = state->rstate.ra.ptr.p_double[5]; v = state->rstate.ra.ptr.p_double[6]; vv = state->rstate.ra.ptr.p_double[7]; relcnt = state->rstate.ra.ptr.p_double[8]; } else { n = -983; m = -989; k = -834; i = 900; j = -287; j1 = 364; info = 214; lx = -338; lf = -686; ld = 912; rx = 585; rf = 497; rd = -271; v = -581; vv = 745; relcnt = -533; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } /* * Routine body */ /* * Init */ if( state->wkind==1 ) { ae_assert(state->npoints==state->nweights, "LSFitFit: number of points is not equal to the number of weights", _state); } state->repvaridx = -1; n = state->npoints; m = state->m; k = state->k; minlmsetcond(&state->optstate, 0.0, state->epsf, state->epsx, state->maxits, _state); minlmsetstpmax(&state->optstate, state->stpmax, _state); minlmsetxrep(&state->optstate, state->xrep, _state); minlmsetscale(&state->optstate, &state->s, _state); minlmsetbc(&state->optstate, &state->bndl, &state->bndu, _state); /* * Check that user-supplied gradient is correct */ lsfit_lsfitclearrequestfields(state, _state); if( !(ae_fp_greater(state->teststep,(double)(0))&&state->optalgo==1) ) { goto lbl_14; } for(i=0; i<=k-1; i++) { if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } } state->needfg = ae_true; i = 0; lbl_16: if( i>k-1 ) { goto lbl_18; } ae_assert(ae_fp_less_eq(state->bndl.ptr.p_double[i],state->c.ptr.p_double[i])&&ae_fp_less_eq(state->c.ptr.p_double[i],state->bndu.ptr.p_double[i]), "LSFitIteration: internal error(State.C is out of bounds)", _state); v = state->c.ptr.p_double[i]; j = 0; lbl_19: if( j>n-1 ) { goto lbl_21; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[j][0], 1, ae_v_len(0,m-1)); state->c.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } lx = state->c.ptr.p_double[i]; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: lf = state->f; ld = state->g.ptr.p_double[i]; state->c.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } rx = state->c.ptr.p_double[i]; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: rf = state->f; rd = state->g.ptr.p_double[i]; state->c.ptr.p_double[i] = (lx+rx)/2; if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) { state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->c.ptr.p_double[i] = v; if( !derivativecheck(lf, ld, rf, rd, state->f, state->g.ptr.p_double[i], rx-lx, _state) ) { state->repvaridx = i; state->repterminationtype = -7; result = ae_false; return result; } j = j+1; goto lbl_19; lbl_21: i = i+1; goto lbl_16; lbl_18: state->needfg = ae_false; lbl_14: /* * Fill WCur by weights: * * for WKind=0 unit weights are chosen * * for WKind=1 we use user-supplied weights stored in State.TaskW */ rvectorsetlengthatleast(&state->wcur, n, _state); for(i=0; i<=n-1; i++) { state->wcur.ptr.p_double[i] = 1.0; if( state->wkind==1 ) { state->wcur.ptr.p_double[i] = state->taskw.ptr.p_double[i]; } } /* * Optimize */ lbl_22: if( !minlmiteration(&state->optstate, _state) ) { goto lbl_23; } if( !state->optstate.needfi ) { goto lbl_24; } /* * calculate f[] = wi*(f(xi,c)-yi) */ i = 0; lbl_26: if( i>n-1 ) { goto lbl_28; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needf = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needf = ae_false; vv = state->wcur.ptr.p_double[i]; state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); i = i+1; goto lbl_26; lbl_28: goto lbl_22; lbl_24: if( !state->optstate.needf ) { goto lbl_29; } /* * calculate F = sum (wi*(f(xi,c)-yi))^2 */ state->optstate.f = (double)(0); i = 0; lbl_31: if( i>n-1 ) { goto lbl_33; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needf = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->needf = ae_false; vv = state->wcur.ptr.p_double[i]; state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); i = i+1; goto lbl_31; lbl_33: goto lbl_22; lbl_29: if( !state->optstate.needfg ) { goto lbl_34; } /* * calculate F/gradF */ state->optstate.f = (double)(0); for(i=0; i<=k-1; i++) { state->optstate.g.ptr.p_double[i] = (double)(0); } i = 0; lbl_36: if( i>n-1 ) { goto lbl_38; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->needfg = ae_false; vv = state->wcur.ptr.p_double[i]; state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]); ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); i = i+1; goto lbl_36; lbl_38: goto lbl_22; lbl_34: if( !state->optstate.needfij ) { goto lbl_39; } /* * calculate Fi/jac(Fi) */ i = 0; lbl_41: if( i>n-1 ) { goto lbl_43; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->needfg = ae_false; vv = state->wcur.ptr.p_double[i]; state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); ae_v_moved(&state->optstate.j.ptr.pp_double[i][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), vv); i = i+1; goto lbl_41; lbl_43: goto lbl_22; lbl_39: if( !state->optstate.needfgh ) { goto lbl_44; } /* * calculate F/grad(F)/hess(F) */ state->optstate.f = (double)(0); for(i=0; i<=k-1; i++) { state->optstate.g.ptr.p_double[i] = (double)(0); } for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { state->optstate.h.ptr.pp_double[i][j] = (double)(0); } } i = 0; lbl_46: if( i>n-1 ) { goto lbl_48; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needfgh = ae_true; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->needfgh = ae_false; vv = state->wcur.ptr.p_double[i]; state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]); ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); for(j=0; j<=k-1; j++) { v = 2*ae_sqr(vv, _state)*state->g.ptr.p_double[j]; ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); v = 2*ae_sqr(vv, _state)*(state->f-state->tasky.ptr.p_double[i]); ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->h.ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); } i = i+1; goto lbl_46; lbl_48: goto lbl_22; lbl_44: if( !state->optstate.xupdated ) { goto lbl_49; } /* * Report new iteration */ ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); state->f = state->optstate.f; lsfit_lsfitclearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->xupdated = ae_false; goto lbl_22; lbl_49: goto lbl_22; lbl_23: minlmresults(&state->optstate, &state->c, &state->optrep, _state); state->repterminationtype = state->optrep.terminationtype; state->repiterationscount = state->optrep.iterationscount; /* * calculate errors */ if( state->repterminationtype<=0 ) { goto lbl_51; } /* * Calculate RMS/Avg/Max/... errors */ state->reprmserror = (double)(0); state->repwrmserror = (double)(0); state->repavgerror = (double)(0); state->repavgrelerror = (double)(0); state->repmaxerror = (double)(0); relcnt = (double)(0); i = 0; lbl_53: if( i>n-1 ) { goto lbl_55; } ae_v_move(&state->c.ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,k-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; lsfit_lsfitclearrequestfields(state, _state); state->needf = ae_true; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->needf = ae_false; v = state->f; vv = state->wcur.ptr.p_double[i]; state->reprmserror = state->reprmserror+ae_sqr(v-state->tasky.ptr.p_double[i], _state); state->repwrmserror = state->repwrmserror+ae_sqr(vv*(v-state->tasky.ptr.p_double[i]), _state); state->repavgerror = state->repavgerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state); if( ae_fp_neq(state->tasky.ptr.p_double[i],(double)(0)) ) { state->repavgrelerror = state->repavgrelerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state)/ae_fabs(state->tasky.ptr.p_double[i], _state); relcnt = relcnt+1; } state->repmaxerror = ae_maxreal(state->repmaxerror, ae_fabs(v-state->tasky.ptr.p_double[i], _state), _state); i = i+1; goto lbl_53; lbl_55: state->reprmserror = ae_sqrt(state->reprmserror/n, _state); state->repwrmserror = ae_sqrt(state->repwrmserror/n, _state); state->repavgerror = state->repavgerror/n; if( ae_fp_neq(relcnt,(double)(0)) ) { state->repavgrelerror = state->repavgrelerror/relcnt; } /* * Calculate covariance matrix */ rmatrixsetlengthatleast(&state->tmpjac, n, k, _state); rvectorsetlengthatleast(&state->tmpf, n, _state); rvectorsetlengthatleast(&state->tmp, k, _state); if( ae_fp_less_eq(state->diffstep,(double)(0)) ) { goto lbl_56; } /* * Compute Jacobian by means of numerical differentiation */ lsfit_lsfitclearrequestfields(state, _state); state->needf = ae_true; i = 0; lbl_58: if( i>n-1 ) { goto lbl_60; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->tmpf.ptr.p_double[i] = state->f; j = 0; lbl_61: if( j>k-1 ) { goto lbl_63; } v = state->c.ptr.p_double[j]; lx = v-state->diffstep*state->s.ptr.p_double[j]; state->c.ptr.p_double[j] = lx; if( ae_isfinite(state->bndl.ptr.p_double[j], _state) ) { state->c.ptr.p_double[j] = ae_maxreal(state->c.ptr.p_double[j], state->bndl.ptr.p_double[j], _state); } state->rstate.stage = 11; goto lbl_rcomm; lbl_11: lf = state->f; rx = v+state->diffstep*state->s.ptr.p_double[j]; state->c.ptr.p_double[j] = rx; if( ae_isfinite(state->bndu.ptr.p_double[j], _state) ) { state->c.ptr.p_double[j] = ae_minreal(state->c.ptr.p_double[j], state->bndu.ptr.p_double[j], _state); } state->rstate.stage = 12; goto lbl_rcomm; lbl_12: rf = state->f; state->c.ptr.p_double[j] = v; if( ae_fp_neq(rx,lx) ) { state->tmpjac.ptr.pp_double[i][j] = (rf-lf)/(rx-lx); } else { state->tmpjac.ptr.pp_double[i][j] = (double)(0); } j = j+1; goto lbl_61; lbl_63: i = i+1; goto lbl_58; lbl_60: state->needf = ae_false; goto lbl_57; lbl_56: /* * Jacobian is calculated with user-provided analytic gradient */ lsfit_lsfitclearrequestfields(state, _state); state->needfg = ae_true; i = 0; lbl_64: if( i>n-1 ) { goto lbl_66; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); state->pointindex = i; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->tmpf.ptr.p_double[i] = state->f; for(j=0; j<=k-1; j++) { state->tmpjac.ptr.pp_double[i][j] = state->g.ptr.p_double[j]; } i = i+1; goto lbl_64; lbl_66: state->needfg = ae_false; lbl_57: for(i=0; i<=k-1; i++) { state->tmp.ptr.p_double[i] = 0.0; } lsfit_estimateerrors(&state->tmpjac, &state->tmpf, &state->tasky, &state->wcur, &state->tmp, &state->s, n, k, &state->rep, &state->tmpjacw, 0, _state); lbl_51: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = k; state->rstate.ia.ptr.p_int[3] = i; state->rstate.ia.ptr.p_int[4] = j; state->rstate.ia.ptr.p_int[5] = j1; state->rstate.ia.ptr.p_int[6] = info; state->rstate.ra.ptr.p_double[0] = lx; state->rstate.ra.ptr.p_double[1] = lf; state->rstate.ra.ptr.p_double[2] = ld; state->rstate.ra.ptr.p_double[3] = rx; state->rstate.ra.ptr.p_double[4] = rf; state->rstate.ra.ptr.p_double[5] = rd; state->rstate.ra.ptr.p_double[6] = v; state->rstate.ra.ptr.p_double[7] = vv; state->rstate.ra.ptr.p_double[8] = relcnt; return result; } /************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. On success following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitresults(lsfitstate* state, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); lsfit_clearreport(rep, _state); *info = state->repterminationtype; rep->varidx = state->repvaridx; if( *info>0 ) { ae_vector_set_length(c, state->k, _state); ae_v_move(&c->ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,state->k-1)); rep->rmserror = state->reprmserror; rep->wrmserror = state->repwrmserror; rep->avgerror = state->repavgerror; rep->avgrelerror = state->repavgrelerror; rep->maxerror = state->repmaxerror; rep->iterationscount = state->repiterationscount; ae_matrix_set_length(&rep->covpar, state->k, state->k, _state); ae_vector_set_length(&rep->errpar, state->k, _state); ae_vector_set_length(&rep->errcurve, state->npoints, _state); ae_vector_set_length(&rep->noise, state->npoints, _state); rep->r2 = state->rep.r2; for(i=0; i<=state->k-1; i++) { for(j=0; j<=state->k-1; j++) { rep->covpar.ptr.pp_double[i][j] = state->rep.covpar.ptr.pp_double[i][j]; } rep->errpar.ptr.p_double[i] = state->rep.errpar.ptr.p_double[i]; } for(i=0; i<=state->npoints-1; i++) { rep->errcurve.ptr.p_double[i] = state->rep.errcurve.ptr.p_double[i]; rep->noise.ptr.p_double[i] = state->rep.noise.ptr.p_double[i]; } } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before fitting begins * LSFitFit() is called * prior to actual fitting, for each point in data set X_i and each component of parameters being fited C_j algorithm performs following steps: * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], where C_j is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on C[] * F(X_i|C) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N*K (points count * parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with LSFitSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. NOTE 4: this function works only for optimizers created with LSFitCreateWFG() or LSFitCreateFG() constructors. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void lsfitsetgradientcheck(lsfitstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "LSFitSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Internal subroutine: automatic scaling for LLS tasks. NEVER CALL IT DIRECTLY! Maps abscissas to [-1,1], standartizes ordinates and correspondingly scales constraints. It also scales weights so that max(W[i])=1 Transformations performed: * X, XC [XA,XB] => [-1,+1] transformation makes min(X)=-1, max(X)=+1 * Y [SA,SB] => [0,1] transformation makes mean(Y)=0, stddev(Y)=1 * YC transformed accordingly to SA, SB, DC[I] -- ALGLIB PROJECT -- Copyright 08.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitscalexy(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, double* xa, double* xb, double* sa, double* sb, /* Real */ ae_vector* xoriginal, /* Real */ ae_vector* yoriginal, ae_state *_state) { double xmin; double xmax; ae_int_t i; double mx; *xa = 0; *xb = 0; *sa = 0; *sb = 0; ae_vector_clear(xoriginal); ae_vector_clear(yoriginal); ae_assert(n>=1, "LSFitScaleXY: incorrect N", _state); ae_assert(k>=0, "LSFitScaleXY: incorrect K", _state); /* * Calculate xmin/xmax. * Force xmin<>xmax. */ xmin = x->ptr.p_double[0]; xmax = x->ptr.p_double[0]; for(i=1; i<=n-1; i++) { xmin = ae_minreal(xmin, x->ptr.p_double[i], _state); xmax = ae_maxreal(xmax, x->ptr.p_double[i], _state); } for(i=0; i<=k-1; i++) { xmin = ae_minreal(xmin, xc->ptr.p_double[i], _state); xmax = ae_maxreal(xmax, xc->ptr.p_double[i], _state); } if( ae_fp_eq(xmin,xmax) ) { if( ae_fp_eq(xmin,(double)(0)) ) { xmin = (double)(-1); xmax = (double)(1); } else { if( ae_fp_greater(xmin,(double)(0)) ) { xmin = 0.5*xmin; } else { xmax = 0.5*xmax; } } } /* * Transform abscissas: map [XA,XB] to [0,1] * * Store old X[] in XOriginal[] (it will be used * to calculate relative error). */ ae_vector_set_length(xoriginal, n, _state); ae_v_move(&xoriginal->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); *xa = xmin; *xb = xmax; for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = 2*(x->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); } for(i=0; i<=k-1; i++) { ae_assert(dc->ptr.p_int[i]>=0, "LSFitScaleXY: internal error!", _state); xc->ptr.p_double[i] = 2*(xc->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); yc->ptr.p_double[i] = yc->ptr.p_double[i]*ae_pow(0.5*(*xb-(*xa)), (double)(dc->ptr.p_int[i]), _state); } /* * Transform function values: map [SA,SB] to [0,1] * SA = mean(Y), * SB = SA+stddev(Y). * * Store old Y[] in YOriginal[] (it will be used * to calculate relative error). */ ae_vector_set_length(yoriginal, n, _state); ae_v_move(&yoriginal->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); *sa = (double)(0); for(i=0; i<=n-1; i++) { *sa = *sa+y->ptr.p_double[i]; } *sa = *sa/n; *sb = (double)(0); for(i=0; i<=n-1; i++) { *sb = *sb+ae_sqr(y->ptr.p_double[i]-(*sa), _state); } *sb = ae_sqrt(*sb/n, _state)+(*sa); if( ae_fp_eq(*sb,*sa) ) { *sb = 2*(*sa); } if( ae_fp_eq(*sb,*sa) ) { *sb = *sa+1; } for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = (y->ptr.p_double[i]-(*sa))/(*sb-(*sa)); } for(i=0; i<=k-1; i++) { if( dc->ptr.p_int[i]==0 ) { yc->ptr.p_double[i] = (yc->ptr.p_double[i]-(*sa))/(*sb-(*sa)); } else { yc->ptr.p_double[i] = yc->ptr.p_double[i]/(*sb-(*sa)); } } /* * Scale weights */ mx = (double)(0); for(i=0; i<=n-1; i++) { mx = ae_maxreal(mx, ae_fabs(w->ptr.p_double[i], _state), _state); } if( ae_fp_neq(mx,(double)(0)) ) { for(i=0; i<=n-1; i++) { w->ptr.p_double[i] = w->ptr.p_double[i]/mx; } } } /************************************************************************* This function analyzes section of curve for processing by RDP algorithm: given set of points X,Y with indexes [I0,I1] it returns point with worst deviation from linear model (non-parametric version which sees curve as Y(x)). Input parameters: X, Y - SORTED arrays. I0,I1 - interval (boundaries included) to process Eps - desired precision OUTPUT PARAMETERS: WorstIdx - index of worst point WorstError - error at worst point NOTE: this function guarantees that it returns exactly zero for a section with less than 3 points. -- ALGLIB PROJECT -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/ static void lsfit_rdpanalyzesection(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t i0, ae_int_t i1, ae_int_t* worstidx, double* worsterror, ae_state *_state) { ae_int_t i; double xleft; double xright; double vx; double ve; double a; double b; *worstidx = 0; *worsterror = 0; xleft = x->ptr.p_double[i0]; xright = x->ptr.p_double[i1]; if( i1-i0+1<3||ae_fp_eq(xright,xleft) ) { *worstidx = i0; *worsterror = 0.0; return; } a = (y->ptr.p_double[i1]-y->ptr.p_double[i0])/(xright-xleft); b = (y->ptr.p_double[i0]*xright-y->ptr.p_double[i1]*xleft)/(xright-xleft); *worstidx = -1; *worsterror = (double)(0); for(i=i0+1; i<=i1-1; i++) { vx = x->ptr.p_double[i]; ve = ae_fabs(a*vx+b-y->ptr.p_double[i], _state); if( (ae_fp_greater(vx,xleft)&&ae_fp_less(vx,xright))&&ae_fp_greater(ve,*worsterror) ) { *worsterror = ve; *worstidx = i; } } } /************************************************************************* Recursive splitting of interval [I0,I1] (right boundary included) with RDP algorithm (non-parametric version which sees curve as Y(x)). Input parameters: X, Y - SORTED arrays. I0,I1 - interval (boundaries included) to process Eps - desired precision XOut,YOut - preallocated output arrays large enough to store result; XOut[0..1], YOut[0..1] contain first and last points of curve NOut - must contain 2 on input OUTPUT PARAMETERS: XOut, YOut - curve generated by RDP algorithm, UNSORTED NOut - number of points in curve -- ALGLIB PROJECT -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/ static void lsfit_rdprecursive(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t i0, ae_int_t i1, double eps, /* Real */ ae_vector* xout, /* Real */ ae_vector* yout, ae_int_t* nout, ae_state *_state) { ae_int_t worstidx; double worsterror; ae_assert(ae_fp_greater(eps,(double)(0)), "RDPRecursive: internal error, Eps<0", _state); lsfit_rdpanalyzesection(x, y, i0, i1, &worstidx, &worsterror, _state); if( ae_fp_less_eq(worsterror,eps) ) { return; } xout->ptr.p_double[*nout] = x->ptr.p_double[worstidx]; yout->ptr.p_double[*nout] = y->ptr.p_double[worstidx]; *nout = *nout+1; if( worstidx-i0x.ptr.p_double[0]; tb = state->x.ptr.p_double[1]; tc = state->x.ptr.p_double[2]; td = state->x.ptr.p_double[3]; tg = state->x.ptr.p_double[4]; if( state->xupdated ) { /* * Save best function value obtained so far. */ *flast = state->f; continue; } if( state->needfi ) { /* * Function vector */ for(i=0; i<=n-1; i++) { if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) { state->fi.ptr.p_double[i] = td+(ta-td)/ae_pow(1.0+ae_pow(x->ptr.p_double[i]/tc, tb, _state), tg, _state)-y->ptr.p_double[i]; } else { if( ae_fp_greater_eq(tb,(double)(0)) ) { state->fi.ptr.p_double[i] = ta-y->ptr.p_double[i]; } else { state->fi.ptr.p_double[i] = td-y->ptr.p_double[i]; } } } for(i=0; i<=4; i++) { state->fi.ptr.p_double[n+i] = lambdav*state->x.ptr.p_double[i]; } continue; } if( state->needfij ) { /* * Function vector and Jacobian */ for(i=0; i<=n-1; i++) { if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) { if( is4pl ) { vp = ae_pow(x->ptr.p_double[i]/tc, tb, _state); state->fi.ptr.p_double[i] = td+(ta-td)/(1+vp)-y->ptr.p_double[i]; state->j.ptr.pp_double[i][0] = 1/(1+vp); state->j.ptr.pp_double[i][1] = -(ta-td)*vp*ae_log(x->ptr.p_double[i]/tc, _state)/ae_sqr(1+vp, _state); state->j.ptr.pp_double[i][2] = (ta-td)*(tb/tc)*vp/ae_sqr(1+vp, _state); state->j.ptr.pp_double[i][3] = 1-1/(1+vp); state->j.ptr.pp_double[i][4] = (double)(0); } else { vp0 = ae_pow(x->ptr.p_double[i]/tc, tb, _state); vp1 = ae_pow(1+vp0, tg, _state); state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i]; state->j.ptr.pp_double[i][0] = 1/vp1; state->j.ptr.pp_double[i][1] = (ta-td)*(-tg)*ae_pow(1+vp0, -tg-1, _state)*vp0*ae_log(x->ptr.p_double[i]/tc, _state); state->j.ptr.pp_double[i][2] = (ta-td)*(-tg)*ae_pow(1+vp0, -tg-1, _state)*vp0*(-tb/tc); state->j.ptr.pp_double[i][3] = 1-1/vp1; state->j.ptr.pp_double[i][4] = -(ta-td)/vp1*ae_log(1+vp0, _state); } } else { if( ae_fp_greater_eq(tb,(double)(0)) ) { state->fi.ptr.p_double[i] = ta-y->ptr.p_double[i]; state->j.ptr.pp_double[i][0] = (double)(1); state->j.ptr.pp_double[i][1] = (double)(0); state->j.ptr.pp_double[i][2] = (double)(0); state->j.ptr.pp_double[i][3] = (double)(0); state->j.ptr.pp_double[i][4] = (double)(0); } else { state->fi.ptr.p_double[i] = td-y->ptr.p_double[i]; state->j.ptr.pp_double[i][0] = (double)(0); state->j.ptr.pp_double[i][1] = (double)(0); state->j.ptr.pp_double[i][2] = (double)(0); state->j.ptr.pp_double[i][3] = (double)(1); state->j.ptr.pp_double[i][4] = (double)(0); } } } for(i=0; i<=4; i++) { for(j=0; j<=4; j++) { state->j.ptr.pp_double[n+i][j] = 0.0; } } for(i=0; i<=4; i++) { state->fi.ptr.p_double[n+i] = lambdav*state->x.ptr.p_double[i]; state->j.ptr.pp_double[n+i][i] = lambdav; } continue; } ae_assert(ae_false, "LogisticFitX: internal error", _state); } minlmresultsbuf(state, p1, replm, _state); ae_assert(replm->terminationtype>0, "LogisticFitX: internal error", _state); } /************************************************************************* Internal spline fitting subroutine -- ALGLIB PROJECT -- Copyright 08.09.2009 by Bochkanov Sergey *************************************************************************/ static void lsfit_spline1dfitinternal(ae_int_t st, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _w; ae_vector _xc; ae_vector _yc; ae_matrix fmatrix; ae_matrix cmatrix; ae_vector y2; ae_vector w2; ae_vector sx; ae_vector sy; ae_vector sd; ae_vector tmp; ae_vector xoriginal; ae_vector yoriginal; lsfitreport lrep; double v0; double v1; double v2; double mx; spline1dinterpolant s2; ae_int_t i; ae_int_t j; ae_int_t relcnt; double xa; double xb; double sa; double sb; double bl; double br; double decay; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_w, w, _state); w = &_w; ae_vector_init_copy(&_xc, xc, _state); xc = &_xc; ae_vector_init_copy(&_yc, yc, _state); yc = &_yc; *info = 0; _spline1dinterpolant_clear(s); _spline1dfitreport_clear(rep); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&sx, 0, DT_REAL, _state); ae_vector_init(&sy, 0, DT_REAL, _state); ae_vector_init(&sd, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&xoriginal, 0, DT_REAL, _state); ae_vector_init(&yoriginal, 0, DT_REAL, _state); _lsfitreport_init(&lrep, _state); _spline1dinterpolant_init(&s2, _state); ae_assert(st==0||st==1, "Spline1DFit: internal error!", _state); if( st==0&&m<4 ) { *info = -1; ae_frame_leave(_state); return; } if( st==1&&m<4 ) { *info = -1; ae_frame_leave(_state); return; } if( (n<1||k<0)||k>=m ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=k-1; i++) { *info = 0; if( dc->ptr.p_int[i]<0 ) { *info = -1; } if( dc->ptr.p_int[i]>1 ) { *info = -1; } if( *info<0 ) { ae_frame_leave(_state); return; } } if( st==1&&m%2!=0 ) { /* * Hermite fitter must have even number of basis functions */ *info = -2; ae_frame_leave(_state); return; } /* * weight decay for correct handling of task which becomes * degenerate after constraints are applied */ decay = 10000*ae_machineepsilon; /* * Scale X, Y, XC, YC */ lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); /* * allocate space, initialize: * * SX - grid for basis functions * * SY - values of basis functions at grid points * * FMatrix- values of basis functions at X[] * * CMatrix- values (derivatives) of basis functions at XC[] */ ae_vector_set_length(&y2, n+m, _state); ae_vector_set_length(&w2, n+m, _state); ae_matrix_set_length(&fmatrix, n+m, m, _state); if( k>0 ) { ae_matrix_set_length(&cmatrix, k, m+1, _state); } if( st==0 ) { /* * allocate space for cubic spline */ ae_vector_set_length(&sx, m-2, _state); ae_vector_set_length(&sy, m-2, _state); for(j=0; j<=m-2-1; j++) { sx.ptr.p_double[j] = (double)(2*j)/(double)(m-2-1)-1; } } if( st==1 ) { /* * allocate space for Hermite spline */ ae_vector_set_length(&sx, m/2, _state); ae_vector_set_length(&sy, m/2, _state); ae_vector_set_length(&sd, m/2, _state); for(j=0; j<=m/2-1; j++) { sx.ptr.p_double[j] = (double)(2*j)/(double)(m/2-1)-1; } } /* * Prepare design and constraints matrices: * * fill constraints matrix * * fill first N rows of design matrix with values * * fill next M rows of design matrix with regularizing term * * append M zeros to Y * * append M elements, mean(abs(W)) each, to W */ for(j=0; j<=m-1; j++) { /* * prepare Jth basis function */ if( st==0 ) { /* * cubic spline basis */ for(i=0; i<=m-2-1; i++) { sy.ptr.p_double[i] = (double)(0); } bl = (double)(0); br = (double)(0); if( jptr.p_double[i], _state); } for(i=0; i<=k-1; i++) { ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=2, "Spline1DFit: internal error!", _state); spline1ddiff(&s2, xc->ptr.p_double[i], &v0, &v1, &v2, _state); if( dc->ptr.p_int[i]==0 ) { cmatrix.ptr.pp_double[i][j] = v0; } if( dc->ptr.p_int[i]==1 ) { cmatrix.ptr.pp_double[i][j] = v1; } if( dc->ptr.p_int[i]==2 ) { cmatrix.ptr.pp_double[i][j] = v2; } } } for(i=0; i<=k-1; i++) { cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { if( i==j ) { fmatrix.ptr.pp_double[n+i][j] = decay; } else { fmatrix.ptr.pp_double[n+i][j] = (double)(0); } } } ae_vector_set_length(&y2, n+m, _state); ae_vector_set_length(&w2, n+m, _state); ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); mx = (double)(0); for(i=0; i<=n-1; i++) { mx = mx+ae_fabs(w->ptr.p_double[i], _state); } mx = mx/n; for(i=0; i<=m-1; i++) { y2.ptr.p_double[n+i] = (double)(0); w2.ptr.p_double[n+i] = mx; } /* * Solve constrained task */ if( k>0 ) { /* * solve using regularization */ lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state); } else { /* * no constraints, no regularization needed */ lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state); } if( *info<0 ) { ae_frame_leave(_state); return; } /* * Generate spline and scale it */ if( st==0 ) { /* * cubic spline basis */ ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-2-1)); spline1dbuildcubic(&sx, &sy, m-2, 1, tmp.ptr.p_double[m-2], 1, tmp.ptr.p_double[m-1], s, _state); } if( st==1 ) { /* * Hermite basis */ for(i=0; i<=m/2-1; i++) { sy.ptr.p_double[i] = tmp.ptr.p_double[2*i]; sd.ptr.p_double[i] = tmp.ptr.p_double[2*i+1]; } spline1dbuildhermite(&sx, &sy, &sd, m/2, s, _state); } spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); spline1dlintransy(s, sb-sa, sa, _state); /* * Scale absolute errors obtained from LSFitLinearW. * Relative error should be calculated separately * (because of shifting/scaling of the task) */ rep->taskrcond = lrep.taskrcond; rep->rmserror = lrep.rmserror*(sb-sa); rep->avgerror = lrep.avgerror*(sb-sa); rep->maxerror = lrep.maxerror*(sb-sa); rep->avgrelerror = (double)(0); relcnt = 0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(spline1dcalc(s, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); relcnt = relcnt+1; } } if( relcnt!=0 ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_frame_leave(_state); } /************************************************************************* Internal fitting subroutine *************************************************************************/ static void lsfit_lsfitlinearinternal(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; double threshold; ae_matrix ft; ae_matrix q; ae_matrix l; ae_matrix r; ae_vector b; ae_vector wmod; ae_vector tau; ae_vector nzeros; ae_vector s; ae_int_t i; ae_int_t j; double v; ae_vector sv; ae_matrix u; ae_matrix vt; ae_vector tmp; ae_vector utb; ae_vector sutb; ae_int_t relcnt; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_matrix_init(&ft, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&l, 0, 0, DT_REAL, _state); ae_matrix_init(&r, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&wmod, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&nzeros, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&sv, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&utb, 0, DT_REAL, _state); ae_vector_init(&sutb, 0, DT_REAL, _state); lsfit_clearreport(rep, _state); if( n<1||m<1 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; threshold = ae_sqrt(ae_machineepsilon, _state); /* * Degenerate case, needs special handling */ if( nptr.p_double[j]; ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; wmod.ptr.p_double[j] = (double)(1); } /* * LQ decomposition and reduction to M=N */ ae_vector_set_length(c, m, _state); for(i=0; i<=m-1; i++) { c->ptr.p_double[i] = (double)(0); } rep->taskrcond = (double)(0); rmatrixlq(&ft, n, m, &tau, _state); rmatrixlqunpackq(&ft, n, m, &tau, n, &q, _state); rmatrixlqunpackl(&ft, n, m, &l, _state); lsfit_lsfitlinearinternal(&b, &wmod, &l, n, n, info, &tmp, rep, _state); if( *info<=0 ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { v = tmp.ptr.p_double[i]; ae_v_addd(&c->ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } ae_frame_leave(_state); return; } /* * N>=M. Generate design matrix and reduce to N=M using * QR decomposition. */ ae_matrix_set_length(&ft, n, m, _state); ae_vector_set_length(&b, n, _state); for(j=0; j<=n-1; j++) { v = w->ptr.p_double[j]; ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; } rmatrixqr(&ft, n, m, &tau, _state); rmatrixqrunpackq(&ft, n, m, &tau, m, &q, _state); rmatrixqrunpackr(&ft, n, m, &r, _state); ae_vector_set_length(&tmp, m, _state); for(i=0; i<=m-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = b.ptr.p_double[i]; ae_v_addd(&tmp.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } ae_vector_set_length(&b, m, _state); ae_v_move(&b.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); /* * R contains reduced MxM design upper triangular matrix, * B contains reduced Mx1 right part. * * Determine system condition number and decide * should we use triangular solver (faster) or * SVD-based solver (more stable). * * We can use LU-based RCond estimator for this task. */ rep->taskrcond = rmatrixlurcondinf(&r, m, _state); if( ae_fp_greater(rep->taskrcond,threshold) ) { /* * use QR-based solver */ ae_vector_set_length(c, m, _state); c->ptr.p_double[m-1] = b.ptr.p_double[m-1]/r.ptr.pp_double[m-1][m-1]; for(i=m-2; i>=0; i--) { v = ae_v_dotproduct(&r.ptr.pp_double[i][i+1], 1, &c->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1)); c->ptr.p_double[i] = (b.ptr.p_double[i]-v)/r.ptr.pp_double[i][i]; } } else { /* * use SVD-based solver */ if( !rmatrixsvd(&r, m, m, 1, 1, 2, &sv, &u, &vt, _state) ) { *info = -4; ae_frame_leave(_state); return; } ae_vector_set_length(&utb, m, _state); ae_vector_set_length(&sutb, m, _state); for(i=0; i<=m-1; i++) { utb.ptr.p_double[i] = (double)(0); } for(i=0; i<=m-1; i++) { v = b.ptr.p_double[i]; ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } if( ae_fp_greater(sv.ptr.p_double[0],(double)(0)) ) { rep->taskrcond = sv.ptr.p_double[m-1]/sv.ptr.p_double[0]; for(i=0; i<=m-1; i++) { if( ae_fp_greater(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) { sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i]; } else { sutb.ptr.p_double[i] = (double)(0); } } } else { rep->taskrcond = (double)(0); for(i=0; i<=m-1; i++) { sutb.ptr.p_double[i] = (double)(0); } } ae_vector_set_length(c, m, _state); for(i=0; i<=m-1; i++) { c->ptr.p_double[i] = (double)(0); } for(i=0; i<=m-1; i++) { v = sutb.ptr.p_double[i]; ae_v_addd(&c->ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } } /* * calculate errors */ rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); rep->maxerror = (double)(0); relcnt = 0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); rep->rmserror = rep->rmserror+ae_sqr(v-y->ptr.p_double[i], _state); rep->avgerror = rep->avgerror+ae_fabs(v-y->ptr.p_double[i], _state); if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(v-y->ptr.p_double[i], _state)/ae_fabs(y->ptr.p_double[i], _state); relcnt = relcnt+1; } rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-y->ptr.p_double[i], _state), _state); } rep->rmserror = ae_sqrt(rep->rmserror/n, _state); rep->avgerror = rep->avgerror/n; if( relcnt!=0 ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_vector_set_length(&nzeros, n, _state); ae_vector_set_length(&s, m, _state); for(i=0; i<=m-1; i++) { s.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { s.ptr.p_double[j] = s.ptr.p_double[j]+ae_sqr(fmatrix->ptr.pp_double[i][j], _state); } nzeros.ptr.p_double[i] = (double)(0); } for(i=0; i<=m-1; i++) { if( ae_fp_neq(s.ptr.p_double[i],(double)(0)) ) { s.ptr.p_double[i] = ae_sqrt(1/s.ptr.p_double[i], _state); } else { s.ptr.p_double[i] = (double)(1); } } lsfit_estimateerrors(fmatrix, &nzeros, y, w, c, &s, n, m, rep, &r, 1, _state); ae_frame_leave(_state); } /************************************************************************* Internal subroutine *************************************************************************/ static void lsfit_lsfitclearrequestfields(lsfitstate* state, ae_state *_state) { state->needf = ae_false; state->needfg = ae_false; state->needfgh = ae_false; state->xupdated = ae_false; } /************************************************************************* Internal subroutine, calculates barycentric basis functions. Used for efficient simultaneous calculation of N basis functions. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ static void lsfit_barycentriccalcbasis(barycentricinterpolant* b, double t, /* Real */ ae_vector* y, ae_state *_state) { double s2; double s; double v; ae_int_t i; ae_int_t j; /* * special case: N=1 */ if( b->n==1 ) { y->ptr.p_double[0] = (double)(1); return; } /* * Here we assume that task is normalized, i.e.: * 1. abs(Y[i])<=1 * 2. abs(W[i])<=1 * 3. X[] is ordered * * First, we decide: should we use "safe" formula (guarded * against overflow) or fast one? */ s = ae_fabs(t-b->x.ptr.p_double[0], _state); for(i=0; i<=b->n-1; i++) { v = b->x.ptr.p_double[i]; if( ae_fp_eq(v,t) ) { for(j=0; j<=b->n-1; j++) { y->ptr.p_double[j] = (double)(0); } y->ptr.p_double[i] = (double)(1); return; } v = ae_fabs(t-v, _state); if( ae_fp_less(v,s) ) { s = v; } } s2 = (double)(0); for(i=0; i<=b->n-1; i++) { v = s/(t-b->x.ptr.p_double[i]); v = v*b->w.ptr.p_double[i]; y->ptr.p_double[i] = v; s2 = s2+v; } v = 1/s2; ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); } /************************************************************************* This is internal function for Chebyshev fitting. It assumes that input data are normalized: * X/XC belong to [-1,+1], * mean(Y)=0, stddev(Y)=1. It does not checks inputs for errors. This function is used to fit general (shifted) Chebyshev models, power basis models or barycentric models. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] N - number of points, N>0. XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] K - number of constraints, 0<=K=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints C - interpolant in Chebyshev form; [-1,+1] is used as base interval Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ static void lsfit_internalchebyshevfit(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _xc; ae_vector _yc; ae_vector y2; ae_vector w2; ae_vector tmp; ae_vector tmp2; ae_vector tmpdiff; ae_vector bx; ae_vector by; ae_vector bw; ae_matrix fmatrix; ae_matrix cmatrix; ae_int_t i; ae_int_t j; double mx; double decay; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_xc, xc, _state); xc = &_xc; ae_vector_init_copy(&_yc, yc, _state); yc = &_yc; *info = 0; ae_vector_clear(c); _lsfitreport_clear(rep); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); ae_vector_init(&tmpdiff, 0, DT_REAL, _state); ae_vector_init(&bx, 0, DT_REAL, _state); ae_vector_init(&by, 0, DT_REAL, _state); ae_vector_init(&bw, 0, DT_REAL, _state); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state); lsfit_clearreport(rep, _state); /* * weight decay for correct handling of task which becomes * degenerate after constraints are applied */ decay = 10000*ae_machineepsilon; /* * allocate space, initialize/fill: * * FMatrix- values of basis functions at X[] * * CMatrix- values (derivatives) of basis functions at XC[] * * fill constraints matrix * * fill first N rows of design matrix with values * * fill next M rows of design matrix with regularizing term * * append M zeros to Y * * append M elements, mean(abs(W)) each, to W */ ae_vector_set_length(&y2, n+m, _state); ae_vector_set_length(&w2, n+m, _state); ae_vector_set_length(&tmp, m, _state); ae_vector_set_length(&tmpdiff, m, _state); ae_matrix_set_length(&fmatrix, n+m, m, _state); if( k>0 ) { ae_matrix_set_length(&cmatrix, k, m+1, _state); } /* * Fill design matrix, Y2, W2: * * first N rows with basis functions for original points * * next M rows with decay terms */ for(i=0; i<=n-1; i++) { /* * prepare Ith row * use Tmp for calculations to avoid multidimensional arrays overhead */ for(j=0; j<=m-1; j++) { if( j==0 ) { tmp.ptr.p_double[j] = (double)(1); } else { if( j==1 ) { tmp.ptr.p_double[j] = x->ptr.p_double[i]; } else { tmp.ptr.p_double[j] = 2*x->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; } } } ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { if( i==j ) { fmatrix.ptr.pp_double[n+i][j] = decay; } else { fmatrix.ptr.pp_double[n+i][j] = (double)(0); } } } ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); mx = (double)(0); for(i=0; i<=n-1; i++) { mx = mx+ae_fabs(w->ptr.p_double[i], _state); } mx = mx/n; for(i=0; i<=m-1; i++) { y2.ptr.p_double[n+i] = (double)(0); w2.ptr.p_double[n+i] = mx; } /* * fill constraints matrix */ for(i=0; i<=k-1; i++) { /* * prepare Ith row * use Tmp for basis function values, * TmpDiff for basos function derivatives */ for(j=0; j<=m-1; j++) { if( j==0 ) { tmp.ptr.p_double[j] = (double)(1); tmpdiff.ptr.p_double[j] = (double)(0); } else { if( j==1 ) { tmp.ptr.p_double[j] = xc->ptr.p_double[i]; tmpdiff.ptr.p_double[j] = (double)(1); } else { tmp.ptr.p_double[j] = 2*xc->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; tmpdiff.ptr.p_double[j] = 2*(tmp.ptr.p_double[j-1]+xc->ptr.p_double[i]*tmpdiff.ptr.p_double[j-1])-tmpdiff.ptr.p_double[j-2]; } } } if( dc->ptr.p_int[i]==0 ) { ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); } if( dc->ptr.p_int[i]==1 ) { ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmpdiff.ptr.p_double[0], 1, ae_v_len(0,m-1)); } cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; } /* * Solve constrained task */ if( k>0 ) { /* * solve using regularization */ lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, c, rep, _state); } else { /* * no constraints, no regularization needed */ lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, 0, info, c, rep, _state); } if( *info<0 ) { ae_frame_leave(_state); return; } ae_frame_leave(_state); } /************************************************************************* Internal Floater-Hormann fitting subroutine for fixed D *************************************************************************/ static void lsfit_barycentricfitwcfixedd(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t d, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; ae_vector _w; ae_vector _xc; ae_vector _yc; ae_matrix fmatrix; ae_matrix cmatrix; ae_vector y2; ae_vector w2; ae_vector sx; ae_vector sy; ae_vector sbf; ae_vector xoriginal; ae_vector yoriginal; ae_vector tmp; lsfitreport lrep; double v0; double v1; double mx; barycentricinterpolant b2; ae_int_t i; ae_int_t j; ae_int_t relcnt; double xa; double xb; double sa; double sb; double decay; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; ae_vector_init_copy(&_w, w, _state); w = &_w; ae_vector_init_copy(&_xc, xc, _state); xc = &_xc; ae_vector_init_copy(&_yc, yc, _state); yc = &_yc; *info = 0; _barycentricinterpolant_clear(b); _barycentricfitreport_clear(rep); ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state); ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&sx, 0, DT_REAL, _state); ae_vector_init(&sy, 0, DT_REAL, _state); ae_vector_init(&sbf, 0, DT_REAL, _state); ae_vector_init(&xoriginal, 0, DT_REAL, _state); ae_vector_init(&yoriginal, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); _lsfitreport_init(&lrep, _state); _barycentricinterpolant_init(&b2, _state); if( ((n<1||m<2)||k<0)||k>=m ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=k-1; i++) { *info = 0; if( dc->ptr.p_int[i]<0 ) { *info = -1; } if( dc->ptr.p_int[i]>1 ) { *info = -1; } if( *info<0 ) { ae_frame_leave(_state); return; } } /* * weight decay for correct handling of task which becomes * degenerate after constraints are applied */ decay = 10000*ae_machineepsilon; /* * Scale X, Y, XC, YC */ lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); /* * allocate space, initialize: * * FMatrix- values of basis functions at X[] * * CMatrix- values (derivatives) of basis functions at XC[] */ ae_vector_set_length(&y2, n+m, _state); ae_vector_set_length(&w2, n+m, _state); ae_matrix_set_length(&fmatrix, n+m, m, _state); if( k>0 ) { ae_matrix_set_length(&cmatrix, k, m+1, _state); } ae_vector_set_length(&y2, n+m, _state); ae_vector_set_length(&w2, n+m, _state); /* * Prepare design and constraints matrices: * * fill constraints matrix * * fill first N rows of design matrix with values * * fill next M rows of design matrix with regularizing term * * append M zeros to Y * * append M elements, mean(abs(W)) each, to W */ ae_vector_set_length(&sx, m, _state); ae_vector_set_length(&sy, m, _state); ae_vector_set_length(&sbf, m, _state); for(j=0; j<=m-1; j++) { sx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1; } for(i=0; i<=m-1; i++) { sy.ptr.p_double[i] = (double)(1); } barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); mx = (double)(0); for(i=0; i<=n-1; i++) { lsfit_barycentriccalcbasis(&b2, x->ptr.p_double[i], &sbf, _state); ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &sbf.ptr.p_double[0], 1, ae_v_len(0,m-1)); y2.ptr.p_double[i] = y->ptr.p_double[i]; w2.ptr.p_double[i] = w->ptr.p_double[i]; mx = mx+ae_fabs(w->ptr.p_double[i], _state)/n; } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { if( i==j ) { fmatrix.ptr.pp_double[n+i][j] = decay; } else { fmatrix.ptr.pp_double[n+i][j] = (double)(0); } } y2.ptr.p_double[n+i] = (double)(0); w2.ptr.p_double[n+i] = mx; } if( k>0 ) { for(j=0; j<=m-1; j++) { for(i=0; i<=m-1; i++) { sy.ptr.p_double[i] = (double)(0); } sy.ptr.p_double[j] = (double)(1); barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); for(i=0; i<=k-1; i++) { ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=1, "BarycentricFit: internal error!", _state); barycentricdiff1(&b2, xc->ptr.p_double[i], &v0, &v1, _state); if( dc->ptr.p_int[i]==0 ) { cmatrix.ptr.pp_double[i][j] = v0; } if( dc->ptr.p_int[i]==1 ) { cmatrix.ptr.pp_double[i][j] = v1; } } } for(i=0; i<=k-1; i++) { cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; } } /* * Solve constrained task */ if( k>0 ) { /* * solve using regularization */ lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state); } else { /* * no constraints, no regularization needed */ lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state); } if( *info<0 ) { ae_frame_leave(_state); return; } /* * Generate interpolant and scale it */ ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); barycentricbuildfloaterhormann(&sx, &sy, m, d, b, _state); barycentriclintransx(b, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); barycentriclintransy(b, sb-sa, sa, _state); /* * Scale absolute errors obtained from LSFitLinearW. * Relative error should be calculated separately * (because of shifting/scaling of the task) */ rep->taskrcond = lrep.taskrcond; rep->rmserror = lrep.rmserror*(sb-sa); rep->avgerror = lrep.avgerror*(sb-sa); rep->maxerror = lrep.maxerror*(sb-sa); rep->avgrelerror = (double)(0); relcnt = 0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) { rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(b, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); relcnt = relcnt+1; } } if( relcnt!=0 ) { rep->avgrelerror = rep->avgrelerror/relcnt; } ae_frame_leave(_state); } static void lsfit_clearreport(lsfitreport* rep, ae_state *_state) { rep->taskrcond = (double)(0); rep->iterationscount = 0; rep->varidx = -1; rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); rep->maxerror = (double)(0); rep->wrmserror = (double)(0); rep->r2 = (double)(0); ae_matrix_set_length(&rep->covpar, 0, 0, _state); ae_vector_set_length(&rep->errpar, 0, _state); ae_vector_set_length(&rep->errcurve, 0, _state); ae_vector_set_length(&rep->noise, 0, _state); } /************************************************************************* This internal function estimates covariance matrix and other error-related information for linear/nonlinear least squares model. It has a bit awkward interface, but it can be used for both linear and nonlinear problems. INPUT PARAMETERS: F1 - array[0..N-1,0..K-1]: * for linear problems - matrix of function values * for nonlinear problems - Jacobian matrix F0 - array[0..N-1]: * for linear problems - must be filled with zeros * for nonlinear problems - must store values of function being fitted Y - array[0..N-1]: * for linear and nonlinear problems - must store target values W - weights, array[0..N-1]: * for linear and nonlinear problems - weights X - array[0..K-1]: * for linear and nonlinear problems - current solution S - array[0..K-1]: * its components should be strictly positive * squared inverse of this diagonal matrix is used as damping factor for covariance matrix (linear and nonlinear problems) * for nonlinear problems, when scale of the variables is usually explicitly given by user, you may use scale vector for this parameter * for linear problems you may set this parameter to S=sqrt(1/diag(F'*F)) * this parameter is automatically rescaled by this function, only relative magnitudes of its components (with respect to each other) matter. N - number of points, N>0. K - number of dimensions Rep - structure which is used to store results Z - additional matrix which, depending on ZKind, may contain some information used to accelerate calculations - or just can be temporary buffer: * for ZKind=0 Z contains no information, just temporary buffer which can be resized and used as needed * for ZKind=1 Z contains triangular matrix from QR decomposition of W*F1. This matrix can be used to speedup calculation of covariance matrix. It should not be changed by algorithm. ZKind- contents of Z OUTPUT PARAMETERS: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] * Rep.R2 coefficient of determination (non-weighted) Other fields of Rep are not changed. IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ static void lsfit_estimateerrors(/* Real */ ae_matrix* f1, /* Real */ ae_vector* f0, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* x, /* Real */ ae_vector* s, ae_int_t n, ae_int_t k, lsfitreport* rep, /* Real */ ae_matrix* z, ae_int_t zkind, ae_state *_state) { ae_frame _frame_block; ae_vector _s; ae_int_t i; ae_int_t j; ae_int_t j1; double v; double noisec; ae_int_t info; matinvreport invrep; ae_int_t nzcnt; double avg; double rss; double tss; double sz; double ss; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_s, s, _state); s = &_s; _matinvreport_init(&invrep, _state); /* * Compute NZCnt - count of non-zero weights */ nzcnt = 0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) { nzcnt = nzcnt+1; } } /* * Compute R2 */ if( nzcnt>0 ) { avg = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) { avg = avg+y->ptr.p_double[i]; } } avg = avg/nzcnt; rss = 0.0; tss = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) { v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); v = v+f0->ptr.p_double[i]; rss = rss+ae_sqr(v-y->ptr.p_double[i], _state); tss = tss+ae_sqr(y->ptr.p_double[i]-avg, _state); } } if( ae_fp_neq(tss,(double)(0)) ) { rep->r2 = ae_maxreal(1.0-rss/tss, 0.0, _state); } else { rep->r2 = 1.0; } } else { rep->r2 = (double)(0); } /* * Compute estimate of proportionality between noise in the data and weights: * NoiseC = mean(per-point-noise*per-point-weight) * Noise level (standard deviation) at each point is equal to NoiseC/W[I]. */ if( nzcnt>k ) { noisec = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) { v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); v = v+f0->ptr.p_double[i]; noisec = noisec+ae_sqr((v-y->ptr.p_double[i])*w->ptr.p_double[i], _state); } } noisec = ae_sqrt(noisec/(nzcnt-k), _state); } else { noisec = 0.0; } /* * Two branches on noise level: * * NoiseC>0 normal situation * * NoiseC=0 degenerate case CovPar is filled by zeros */ rmatrixsetlengthatleast(&rep->covpar, k, k, _state); if( ae_fp_greater(noisec,(double)(0)) ) { /* * Normal situation: non-zero noise level */ ae_assert(zkind==0||zkind==1, "LSFit: internal error in EstimateErrors() function", _state); if( zkind==0 ) { /* * Z contains no additional information which can be used to speed up * calculations. We have to calculate covariance matrix on our own: * * Compute scaled Jacobian N*J, where N[i,i]=WCur[I]/NoiseC, store in Z * * Compute Z'*Z, store in CovPar * * Apply moderate regularization to CovPar and compute matrix inverse. * In case inverse failed, increase regularization parameter and try * again. */ rmatrixsetlengthatleast(z, n, k, _state); for(i=0; i<=n-1; i++) { v = w->ptr.p_double[i]/noisec; ae_v_moved(&z->ptr.pp_double[i][0], 1, &f1->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); } /* * Convert S to automatically scaled damped matrix: * * calculate SZ - sum of diagonal elements of Z'*Z * * calculate SS - sum of diagonal elements of S^(-2) * * overwrite S by (SZ/SS)*S^(-2) * * now S has approximately same magnitude as giagonal of Z'*Z */ sz = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { sz = sz+z->ptr.pp_double[i][j]*z->ptr.pp_double[i][j]; } } if( ae_fp_eq(sz,(double)(0)) ) { sz = (double)(1); } ss = (double)(0); for(j=0; j<=k-1; j++) { ss = ss+1/ae_sqr(s->ptr.p_double[j], _state); } for(j=0; j<=k-1; j++) { s->ptr.p_double[j] = sz/ss/ae_sqr(s->ptr.p_double[j], _state); } /* * Calculate damped inverse inv(Z'*Z+S). * We increase damping factor V until Z'*Z become well-conditioned. */ v = 1.0E3*ae_machineepsilon; do { rmatrixsyrk(k, n, 1.0, z, 0, 0, 2, 0.0, &rep->covpar, 0, 0, ae_true, _state); for(i=0; i<=k-1; i++) { rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i]; } spdmatrixinverse(&rep->covpar, k, ae_true, &info, &invrep, _state); v = 10*v; } while(info<=0); for(i=0; i<=k-1; i++) { for(j=i+1; j<=k-1; j++) { rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; } } } if( zkind==1 ) { /* * We can reuse additional information: * * Z contains R matrix from QR decomposition of W*F1 * * After multiplication by 1/NoiseC we get Z_mod = N*F1, where diag(N)=w[i]/NoiseC * * Such triangular Z_mod is a Cholesky factor from decomposition of J'*N'*N*J. * Thus, we can calculate covariance matrix as inverse of the matrix given by * its Cholesky decomposition. It allow us to avoid time-consuming calculation * of J'*N'*N*J in CovPar - complexity is reduced from O(N*K^2) to O(K^3), which * is quite good because K is usually orders of magnitude smaller than N. * * First, convert S to automatically scaled damped matrix: * * calculate SZ - sum of magnitudes of diagonal elements of Z/NoiseC * * calculate SS - sum of diagonal elements of S^(-1) * * overwrite S by (SZ/SS)*S^(-1) * * now S has approximately same magnitude as giagonal of Z'*Z */ sz = (double)(0); for(j=0; j<=k-1; j++) { sz = sz+ae_fabs(z->ptr.pp_double[j][j]/noisec, _state); } if( ae_fp_eq(sz,(double)(0)) ) { sz = (double)(1); } ss = (double)(0); for(j=0; j<=k-1; j++) { ss = ss+1/s->ptr.p_double[j]; } for(j=0; j<=k-1; j++) { s->ptr.p_double[j] = sz/ss/s->ptr.p_double[j]; } /* * Calculate damped inverse of inv((Z+v*S)'*(Z+v*S)) * We increase damping factor V until matrix become well-conditioned. */ v = 1.0E3*ae_machineepsilon; do { for(i=0; i<=k-1; i++) { for(j=i; j<=k-1; j++) { rep->covpar.ptr.pp_double[i][j] = z->ptr.pp_double[i][j]/noisec; } rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i]; } spdmatrixcholeskyinverse(&rep->covpar, k, ae_true, &info, &invrep, _state); v = 10*v; } while(info<=0); for(i=0; i<=k-1; i++) { for(j=i+1; j<=k-1; j++) { rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; } } } } else { /* * Degenerate situation: zero noise level, covariance matrix is zero. */ for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { rep->covpar.ptr.pp_double[j][i] = (double)(0); } } } /* * Estimate erorrs in parameters, curve and per-point noise */ rvectorsetlengthatleast(&rep->errpar, k, _state); rvectorsetlengthatleast(&rep->errcurve, n, _state); rvectorsetlengthatleast(&rep->noise, n, _state); for(i=0; i<=k-1; i++) { rep->errpar.ptr.p_double[i] = ae_sqrt(rep->covpar.ptr.pp_double[i][i], _state); } for(i=0; i<=n-1; i++) { /* * ErrCurve[I] is sqrt(P[i,i]) where P=J*CovPar*J' */ v = 0.0; for(j=0; j<=k-1; j++) { for(j1=0; j1<=k-1; j1++) { v = v+f1->ptr.pp_double[i][j]*rep->covpar.ptr.pp_double[j][j1]*f1->ptr.pp_double[i][j1]; } } rep->errcurve.ptr.p_double[i] = ae_sqrt(v, _state); /* * Noise[i] is filled using weights and current estimate of noise level */ if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) { rep->noise.ptr.p_double[i] = noisec/w->ptr.p_double[i]; } else { rep->noise.ptr.p_double[i] = (double)(0); } } ae_frame_leave(_state); } void _polynomialfitreport_init(void* _p, ae_state *_state) { polynomialfitreport *p = (polynomialfitreport*)_p; ae_touch_ptr((void*)p); } void _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state) { polynomialfitreport *dst = (polynomialfitreport*)_dst; polynomialfitreport *src = (polynomialfitreport*)_src; dst->taskrcond = src->taskrcond; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->maxerror = src->maxerror; } void _polynomialfitreport_clear(void* _p) { polynomialfitreport *p = (polynomialfitreport*)_p; ae_touch_ptr((void*)p); } void _polynomialfitreport_destroy(void* _p) { polynomialfitreport *p = (polynomialfitreport*)_p; ae_touch_ptr((void*)p); } void _barycentricfitreport_init(void* _p, ae_state *_state) { barycentricfitreport *p = (barycentricfitreport*)_p; ae_touch_ptr((void*)p); } void _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state) { barycentricfitreport *dst = (barycentricfitreport*)_dst; barycentricfitreport *src = (barycentricfitreport*)_src; dst->taskrcond = src->taskrcond; dst->dbest = src->dbest; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->maxerror = src->maxerror; } void _barycentricfitreport_clear(void* _p) { barycentricfitreport *p = (barycentricfitreport*)_p; ae_touch_ptr((void*)p); } void _barycentricfitreport_destroy(void* _p) { barycentricfitreport *p = (barycentricfitreport*)_p; ae_touch_ptr((void*)p); } void _spline1dfitreport_init(void* _p, ae_state *_state) { spline1dfitreport *p = (spline1dfitreport*)_p; ae_touch_ptr((void*)p); } void _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state) { spline1dfitreport *dst = (spline1dfitreport*)_dst; spline1dfitreport *src = (spline1dfitreport*)_src; dst->taskrcond = src->taskrcond; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->maxerror = src->maxerror; } void _spline1dfitreport_clear(void* _p) { spline1dfitreport *p = (spline1dfitreport*)_p; ae_touch_ptr((void*)p); } void _spline1dfitreport_destroy(void* _p) { spline1dfitreport *p = (spline1dfitreport*)_p; ae_touch_ptr((void*)p); } void _lsfitreport_init(void* _p, ae_state *_state) { lsfitreport *p = (lsfitreport*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->covpar, 0, 0, DT_REAL, _state); ae_vector_init(&p->errpar, 0, DT_REAL, _state); ae_vector_init(&p->errcurve, 0, DT_REAL, _state); ae_vector_init(&p->noise, 0, DT_REAL, _state); } void _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state) { lsfitreport *dst = (lsfitreport*)_dst; lsfitreport *src = (lsfitreport*)_src; dst->taskrcond = src->taskrcond; dst->iterationscount = src->iterationscount; dst->varidx = src->varidx; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->maxerror = src->maxerror; dst->wrmserror = src->wrmserror; ae_matrix_init_copy(&dst->covpar, &src->covpar, _state); ae_vector_init_copy(&dst->errpar, &src->errpar, _state); ae_vector_init_copy(&dst->errcurve, &src->errcurve, _state); ae_vector_init_copy(&dst->noise, &src->noise, _state); dst->r2 = src->r2; } void _lsfitreport_clear(void* _p) { lsfitreport *p = (lsfitreport*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->covpar); ae_vector_clear(&p->errpar); ae_vector_clear(&p->errcurve); ae_vector_clear(&p->noise); } void _lsfitreport_destroy(void* _p) { lsfitreport *p = (lsfitreport*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->covpar); ae_vector_destroy(&p->errpar); ae_vector_destroy(&p->errcurve); ae_vector_destroy(&p->noise); } void _lsfitstate_init(void* _p, ae_state *_state) { lsfitstate *p = (lsfitstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_matrix_init(&p->taskx, 0, 0, DT_REAL, _state); ae_vector_init(&p->tasky, 0, DT_REAL, _state); ae_vector_init(&p->taskw, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->c, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); ae_matrix_init(&p->h, 0, 0, DT_REAL, _state); ae_vector_init(&p->wcur, 0, DT_REAL, _state); ae_vector_init(&p->tmp, 0, DT_REAL, _state); ae_vector_init(&p->tmpf, 0, DT_REAL, _state); ae_matrix_init(&p->tmpjac, 0, 0, DT_REAL, _state); ae_matrix_init(&p->tmpjacw, 0, 0, DT_REAL, _state); _matinvreport_init(&p->invrep, _state); _lsfitreport_init(&p->rep, _state); _minlmstate_init(&p->optstate, _state); _minlmreport_init(&p->optrep, _state); _rcommstate_init(&p->rstate, _state); } void _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state) { lsfitstate *dst = (lsfitstate*)_dst; lsfitstate *src = (lsfitstate*)_src; dst->optalgo = src->optalgo; dst->m = src->m; dst->k = src->k; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->stpmax = src->stpmax; dst->xrep = src->xrep; ae_vector_init_copy(&dst->s, &src->s, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_matrix_init_copy(&dst->taskx, &src->taskx, _state); ae_vector_init_copy(&dst->tasky, &src->tasky, _state); dst->npoints = src->npoints; ae_vector_init_copy(&dst->taskw, &src->taskw, _state); dst->nweights = src->nweights; dst->wkind = src->wkind; dst->wits = src->wits; dst->diffstep = src->diffstep; dst->teststep = src->teststep; dst->xupdated = src->xupdated; dst->needf = src->needf; dst->needfg = src->needfg; dst->needfgh = src->needfgh; dst->pointindex = src->pointindex; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->c, &src->c, _state); dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); ae_matrix_init_copy(&dst->h, &src->h, _state); ae_vector_init_copy(&dst->wcur, &src->wcur, _state); ae_vector_init_copy(&dst->tmp, &src->tmp, _state); ae_vector_init_copy(&dst->tmpf, &src->tmpf, _state); ae_matrix_init_copy(&dst->tmpjac, &src->tmpjac, _state); ae_matrix_init_copy(&dst->tmpjacw, &src->tmpjacw, _state); dst->tmpnoise = src->tmpnoise; _matinvreport_init_copy(&dst->invrep, &src->invrep, _state); dst->repiterationscount = src->repiterationscount; dst->repterminationtype = src->repterminationtype; dst->repvaridx = src->repvaridx; dst->reprmserror = src->reprmserror; dst->repavgerror = src->repavgerror; dst->repavgrelerror = src->repavgrelerror; dst->repmaxerror = src->repmaxerror; dst->repwrmserror = src->repwrmserror; _lsfitreport_init_copy(&dst->rep, &src->rep, _state); _minlmstate_init_copy(&dst->optstate, &src->optstate, _state); _minlmreport_init_copy(&dst->optrep, &src->optrep, _state); dst->prevnpt = src->prevnpt; dst->prevalgo = src->prevalgo; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _lsfitstate_clear(void* _p) { lsfitstate *p = (lsfitstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->s); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_matrix_clear(&p->taskx); ae_vector_clear(&p->tasky); ae_vector_clear(&p->taskw); ae_vector_clear(&p->x); ae_vector_clear(&p->c); ae_vector_clear(&p->g); ae_matrix_clear(&p->h); ae_vector_clear(&p->wcur); ae_vector_clear(&p->tmp); ae_vector_clear(&p->tmpf); ae_matrix_clear(&p->tmpjac); ae_matrix_clear(&p->tmpjacw); _matinvreport_clear(&p->invrep); _lsfitreport_clear(&p->rep); _minlmstate_clear(&p->optstate); _minlmreport_clear(&p->optrep); _rcommstate_clear(&p->rstate); } void _lsfitstate_destroy(void* _p) { lsfitstate *p = (lsfitstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->s); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_matrix_destroy(&p->taskx); ae_vector_destroy(&p->tasky); ae_vector_destroy(&p->taskw); ae_vector_destroy(&p->x); ae_vector_destroy(&p->c); ae_vector_destroy(&p->g); ae_matrix_destroy(&p->h); ae_vector_destroy(&p->wcur); ae_vector_destroy(&p->tmp); ae_vector_destroy(&p->tmpf); ae_matrix_destroy(&p->tmpjac); ae_matrix_destroy(&p->tmpjacw); _matinvreport_destroy(&p->invrep); _lsfitreport_destroy(&p->rep); _minlmstate_destroy(&p->optstate); _minlmreport_destroy(&p->optrep); _rcommstate_destroy(&p->rstate); } /************************************************************************* This function builds non-periodic 2-dimensional parametric spline which starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. Order of points is important! N - points count, N>=5 for Akima splines, N>=2 for other types of splines. ST - spline type: * 0 Akima spline * 1 parabolically terminated Catmull-Rom spline (Tension=0) * 2 parabolically terminated cubic spline PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2build(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix _xy; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_xy, xy, _state); xy = &_xy; _pspline2interpolant_clear(p); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_assert(st>=0&&st<=2, "PSpline2Build: incorrect spline type!", _state); ae_assert(pt>=0&&pt<=2, "PSpline2Build: incorrect parameterization type!", _state); if( st==0 ) { ae_assert(n>=5, "PSpline2Build: N<5 (minimum value for Akima splines)!", _state); } else { ae_assert(n>=2, "PSpline2Build: N<2!", _state); } /* * Prepare */ p->n = n; p->periodic = ae_false; ae_vector_set_length(&tmp, n, _state); /* * Build parameterization, check that all parameters are distinct */ parametric_pspline2par(xy, n, pt, &p->p, _state); ae_assert(aredistinct(&p->p, n, _state), "PSpline2Build: consequent points are too close!", _state); /* * Build splines */ if( st==0 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); } if( st==1 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); } if( st==2 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); } ae_frame_leave(_state); } /************************************************************************* This function builds non-periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3build(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix _xy; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_xy, xy, _state); xy = &_xy; _pspline3interpolant_clear(p); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_assert(st>=0&&st<=2, "PSpline3Build: incorrect spline type!", _state); ae_assert(pt>=0&&pt<=2, "PSpline3Build: incorrect parameterization type!", _state); if( st==0 ) { ae_assert(n>=5, "PSpline3Build: N<5 (minimum value for Akima splines)!", _state); } else { ae_assert(n>=2, "PSpline3Build: N<2!", _state); } /* * Prepare */ p->n = n; p->periodic = ae_false; ae_vector_set_length(&tmp, n, _state); /* * Build parameterization, check that all parameters are distinct */ parametric_pspline3par(xy, n, pt, &p->p, _state); ae_assert(aredistinct(&p->p, n, _state), "PSpline3Build: consequent points are too close!", _state); /* * Build splines */ if( st==0 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); spline1dbuildakima(&p->p, &tmp, n, &p->z, _state); } if( st==1 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->z, _state); } if( st==2 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->z, _state); } ae_frame_leave(_state); } /************************************************************************* This function builds periodic 2-dimensional parametric spline which starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then back to (X[0],Y[0]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. XY[N-1,0:1] must be different from XY[0,0:1]. Order of points is important! N - points count, N>=3 for other types of splines. ST - spline type: * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions * 2 cubic spline with cyclic boundary conditions PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). * last point of sequence is NOT equal to the first point. You shouldn't make curve "explicitly periodic" by making them equal. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2buildperiodic(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix _xy; ae_matrix xyp; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_xy, xy, _state); xy = &_xy; _pspline2interpolant_clear(p); ae_matrix_init(&xyp, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_assert(st>=1&&st<=2, "PSpline2BuildPeriodic: incorrect spline type!", _state); ae_assert(pt>=0&&pt<=2, "PSpline2BuildPeriodic: incorrect parameterization type!", _state); ae_assert(n>=3, "PSpline2BuildPeriodic: N<3!", _state); /* * Prepare */ p->n = n; p->periodic = ae_true; ae_vector_set_length(&tmp, n+1, _state); ae_matrix_set_length(&xyp, n+1, 2, _state); ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,1)); /* * Build parameterization, check that all parameters are distinct */ parametric_pspline2par(&xyp, n+1, pt, &p->p, _state); ae_assert(aredistinct(&p->p, n+1, _state), "PSpline2BuildPeriodic: consequent (or first and last) points are too close!", _state); /* * Build splines */ if( st==1 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); } if( st==2 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); } ae_frame_leave(_state); } /************************************************************************* This function builds periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) and then back to (X[0],Y[0],Z[0]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3buildperiodic(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix _xy; ae_matrix xyp; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_xy, xy, _state); xy = &_xy; _pspline3interpolant_clear(p); ae_matrix_init(&xyp, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_assert(st>=1&&st<=2, "PSpline3BuildPeriodic: incorrect spline type!", _state); ae_assert(pt>=0&&pt<=2, "PSpline3BuildPeriodic: incorrect parameterization type!", _state); ae_assert(n>=3, "PSpline3BuildPeriodic: N<3!", _state); /* * Prepare */ p->n = n; p->periodic = ae_true; ae_vector_set_length(&tmp, n+1, _state); ae_matrix_set_length(&xyp, n+1, 3, _state); ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); ae_v_move(&xyp.ptr.pp_double[0][2], xyp.stride, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,2)); /* * Build parameterization, check that all parameters are distinct */ parametric_pspline3par(&xyp, n+1, pt, &p->p, _state); ae_assert(aredistinct(&p->p, n+1, _state), "PSplineBuild2Periodic: consequent (or first and last) points are too close!", _state); /* * Build splines */ if( st==1 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->z, _state); } if( st==2 ) { ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->z, _state); } ae_frame_leave(_state); } /************************************************************************* This function returns vector of parameter values correspoding to points. I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we have (X[0],Y[0]) = PSpline2Calc(P,U[0]), (X[1],Y[1]) = PSpline2Calc(P,U[1]), (X[2],Y[2]) = PSpline2Calc(P,U[2]), ... INPUT PARAMETERS: P - parametric spline interpolant OUTPUT PARAMETERS: N - array size T - array[0..N-1] NOTES: * for non-periodic splines U[0]=0, U[0]n>=2, "PSpline2ParameterValues: internal error!", _state); *n = p->n; ae_vector_set_length(t, *n, _state); ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); t->ptr.p_double[0] = (double)(0); if( !p->periodic ) { t->ptr.p_double[*n-1] = (double)(1); } } /************************************************************************* This function returns vector of parameter values correspoding to points. Same as PSpline2ParameterValues(), but for 3D. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3parametervalues(pspline3interpolant* p, ae_int_t* n, /* Real */ ae_vector* t, ae_state *_state) { *n = 0; ae_vector_clear(t); ae_assert(p->n>=2, "PSpline3ParameterValues: internal error!", _state); *n = p->n; ae_vector_set_length(t, *n, _state); ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); t->ptr.p_double[0] = (double)(0); if( !p->periodic ) { t->ptr.p_double[*n-1] = (double)(1); } } /************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2calc(pspline2interpolant* p, double t, double* x, double* y, ae_state *_state) { *x = 0; *y = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } *x = spline1dcalc(&p->x, t, _state); *y = spline1dcalc(&p->y, t, _state); } /************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position Z - Z-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3calc(pspline3interpolant* p, double t, double* x, double* y, double* z, ae_state *_state) { *x = 0; *y = 0; *z = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } *x = spline1dcalc(&p->x, t, _state); *y = spline1dcalc(&p->y, t, _state); *z = spline1dcalc(&p->z, t, _state); } /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) NOTE: X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2tangent(pspline2interpolant* p, double t, double* x, double* y, ae_state *_state) { double v; double v0; double v1; *x = 0; *y = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } pspline2diff(p, t, &v0, x, &v1, y, _state); if( ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)) ) { /* * this code is a bit more complex than X^2+Y^2 to avoid * overflow for large values of X and Y. */ v = safepythag2(*x, *y, _state); *x = *x/v; *y = *y/v; } } /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) Z - Z-component of tangent vector (normalized) NOTE: X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3tangent(pspline3interpolant* p, double t, double* x, double* y, double* z, ae_state *_state) { double v; double v0; double v1; double v2; *x = 0; *y = 0; *z = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } pspline3diff(p, t, &v0, x, &v1, y, &v2, z, _state); if( (ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))||ae_fp_neq(*z,(double)(0)) ) { v = safepythag3(*x, *y, *z, _state); *x = *x/v; *y = *y/v; *z = *z/v; } } /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff(pspline2interpolant* p, double t, double* x, double* dx, double* y, double* dy, ae_state *_state) { double d2s; *x = 0; *dx = 0; *y = 0; *dy = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } spline1ddiff(&p->x, t, x, dx, &d2s, _state); spline1ddiff(&p->y, t, y, dy, &d2s, _state); } /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative Z - Z-value DZ - Z-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff(pspline3interpolant* p, double t, double* x, double* dx, double* y, double* dy, double* z, double* dz, ae_state *_state) { double d2s; *x = 0; *dx = 0; *y = 0; *dy = 0; *z = 0; *dz = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } spline1ddiff(&p->x, t, x, dx, &d2s, _state); spline1ddiff(&p->y, t, y, dy, &d2s, _state); spline1ddiff(&p->z, t, z, dz, &d2s, _state); } /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff2(pspline2interpolant* p, double t, double* x, double* dx, double* d2x, double* y, double* dy, double* d2y, ae_state *_state) { *x = 0; *dx = 0; *d2x = 0; *y = 0; *dy = 0; *d2y = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } spline1ddiff(&p->x, t, x, dx, d2x, _state); spline1ddiff(&p->y, t, y, dy, d2y, _state); } /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative Z - Z-value DZ - derivative D2Z - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff2(pspline3interpolant* p, double t, double* x, double* dx, double* d2x, double* y, double* dy, double* d2y, double* z, double* dz, double* d2z, ae_state *_state) { *x = 0; *dx = 0; *d2x = 0; *y = 0; *dy = 0; *d2y = 0; *z = 0; *dz = 0; *d2z = 0; if( p->periodic ) { t = t-ae_ifloor(t, _state); } spline1ddiff(&p->x, t, x, dx, d2x, _state); spline1ddiff(&p->y, t, y, dy, d2y, _state); spline1ddiff(&p->z, t, z, dz, d2z, _state); } /************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * Bx, state.x, &sx, &dsx, &d2sx, _state); spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); state.f = safepythag2(dsx, dsy, _state); } autogkresults(&state, &result, &rep, _state); ae_assert(rep.terminationtype>0, "PSpline2ArcLength: internal error!", _state); ae_frame_leave(_state); return result; } /************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * Bx, state.x, &sx, &dsx, &d2sx, _state); spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); spline1ddiff(&p->z, state.x, &sz, &dsz, &d2sz, _state); state.f = safepythag3(dsx, dsy, dsz, _state); } autogkresults(&state, &result, &rep, _state); ae_assert(rep.terminationtype>0, "PSpline3ArcLength: internal error!", _state); ae_frame_leave(_state); return result; } /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm. This function performs PARAMETRIC fit, i.e. it can be used to fit curves like circles. On input it accepts dataset which describes parametric multidimensional curve X(t), with X being vector, and t taking values in [0,N), where N is a number of points in dataset. As result, it returns reduced dataset X2, which can be used to build parametric curve X2(t), which approximates X(t) with desired precision (or has specified number of sections). INPUT PARAMETERS: X - array of multidimensional points: * at least N elements, leading N elements are used if more than N elements were specified * order of points is IMPORTANT because it is parametric fit * each row of array is one point which has D coordinates N - number of elements in X D - number of dimensions (elements per row of X) StopM - stopping condition - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N=0, "LSTFitPiecewiseLinearParametricRDP: N<0", _state); ae_assert(d>=1, "LSTFitPiecewiseLinearParametricRDP: D<=0", _state); ae_assert(stopm>=0, "LSTFitPiecewiseLinearParametricRDP: StopM<1", _state); ae_assert(ae_isfinite(stopeps, _state)&&ae_fp_greater_eq(stopeps,(double)(0)), "LSTFitPiecewiseLinearParametricRDP: StopEps<0 or is infinite", _state); ae_assert(x->rows>=n, "LSTFitPiecewiseLinearParametricRDP: Rows(X)cols>=d, "LSTFitPiecewiseLinearParametricRDP: Cols(X)ptr.pp_double[i][j],x->ptr.pp_double[0][j]); } } if( allsame ) { *nsections = 0; ae_frame_leave(_state); return; } /* * Prepare first section */ parametric_rdpanalyzesectionpar(x, 0, n-1, d, &worstidx, &worsterror, _state); ae_matrix_set_length(§ions, n, 4, _state); ae_vector_set_length(&heaperrors, n, _state); ae_vector_set_length(&heaptags, n, _state); *nsections = 1; sections.ptr.pp_double[0][0] = (double)(0); sections.ptr.pp_double[0][1] = (double)(n-1); sections.ptr.pp_double[0][2] = (double)(worstidx); sections.ptr.pp_double[0][3] = worsterror; heaperrors.ptr.p_double[0] = worsterror; heaptags.ptr.p_int[0] = 0; ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state); /* * Main loop. * Repeatedly find section with worst error and divide it. * Terminate after M-th section, or because of other reasons (see loop internals). */ for(;;) { /* * Break loop if one of the stopping conditions was met. * Store index of worst section to K. */ if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) ) { break; } if( ae_fp_greater(stopeps,(double)(0))&&ae_fp_less_eq(heaperrors.ptr.p_double[0],stopeps) ) { break; } if( stopm>0&&*nsections>=stopm ) { break; } k = heaptags.ptr.p_int[0]; /* * K-th section is divided in two: * * first one spans interval from X[Sections[K,0]] to X[Sections[K,2]] * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]] * * First section is stored at K-th position, second one is appended to the table. * Then we update heap which stores pairs of (error,section_index) */ k0 = ae_round(sections.ptr.pp_double[k][0], _state); k1 = ae_round(sections.ptr.pp_double[k][1], _state); k2 = ae_round(sections.ptr.pp_double[k][2], _state); parametric_rdpanalyzesectionpar(x, k0, k2, d, &idx0, &e0, _state); parametric_rdpanalyzesectionpar(x, k2, k1, d, &idx1, &e1, _state); sections.ptr.pp_double[k][0] = (double)(k0); sections.ptr.pp_double[k][1] = (double)(k2); sections.ptr.pp_double[k][2] = (double)(idx0); sections.ptr.pp_double[k][3] = e0; tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state); sections.ptr.pp_double[*nsections][0] = (double)(k2); sections.ptr.pp_double[*nsections][1] = (double)(k1); sections.ptr.pp_double[*nsections][2] = (double)(idx1); sections.ptr.pp_double[*nsections][3] = e1; tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state); } /* * Convert from sections to indexes */ ae_vector_set_length(&buf0, *nsections+1, _state); for(i=0; i<=*nsections-1; i++) { buf0.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state)); } buf0.ptr.p_double[*nsections] = (double)(n-1); tagsortfast(&buf0, &buf1, *nsections+1, _state); ae_vector_set_length(idx2, *nsections+1, _state); for(i=0; i<=*nsections; i++) { idx2->ptr.p_int[i] = ae_round(buf0.ptr.p_double[i], _state); } ae_assert(idx2->ptr.p_int[0]==0, "RDP algorithm: integrity check failed", _state); ae_assert(idx2->ptr.p_int[*nsections]==n-1, "RDP algorithm: integrity check failed", _state); /* * Output sections: * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections * * last element of X2/Y2 is filled by right boundary of rightmost section * * X2/Y2 is sorted by ascending of X2 */ ae_matrix_set_length(x2, *nsections+1, d, _state); for(i=0; i<=*nsections; i++) { for(j=0; j<=d-1; j++) { x2->ptr.pp_double[i][j] = x->ptr.pp_double[idx2->ptr.p_int[i]][j]; } } ae_frame_leave(_state); } /************************************************************************* Builds non-periodic parameterization for 2-dimensional spline *************************************************************************/ static void parametric_pspline2par(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t pt, /* Real */ ae_vector* p, ae_state *_state) { double v; ae_int_t i; ae_vector_clear(p); ae_assert(pt>=0&&pt<=2, "PSpline2Par: internal error!", _state); /* * Build parameterization: * * fill by non-normalized values * * normalize them so we have P[0]=0, P[N-1]=1. */ ae_vector_set_length(p, n, _state); if( pt==0 ) { for(i=0; i<=n-1; i++) { p->ptr.p_double[i] = (double)(i); } } if( pt==1 ) { p->ptr.p_double[0] = (double)(0); for(i=1; i<=n-1; i++) { p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state); } } if( pt==2 ) { p->ptr.p_double[0] = (double)(0); for(i=1; i<=n-1; i++) { p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state), _state); } } v = 1/p->ptr.p_double[n-1]; ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); } /************************************************************************* Builds non-periodic parameterization for 3-dimensional spline *************************************************************************/ static void parametric_pspline3par(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t pt, /* Real */ ae_vector* p, ae_state *_state) { double v; ae_int_t i; ae_vector_clear(p); ae_assert(pt>=0&&pt<=2, "PSpline3Par: internal error!", _state); /* * Build parameterization: * * fill by non-normalized values * * normalize them so we have P[0]=0, P[N-1]=1. */ ae_vector_set_length(p, n, _state); if( pt==0 ) { for(i=0; i<=n-1; i++) { p->ptr.p_double[i] = (double)(i); } } if( pt==1 ) { p->ptr.p_double[0] = (double)(0); for(i=1; i<=n-1; i++) { p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state); } } if( pt==2 ) { p->ptr.p_double[0] = (double)(0); for(i=1; i<=n-1; i++) { p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state), _state); } } v = 1/p->ptr.p_double[n-1]; ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); } /************************************************************************* This function analyzes section of curve for processing by RDP algorithm: given set of points X,Y with indexes [I0,I1] it returns point with worst deviation from linear model (PARAMETRIC version which sees curve as X(t) with vector X). Input parameters: XY - array I0,I1 - interval (boundaries included) to process D - number of dimensions OUTPUT PARAMETERS: WorstIdx - index of worst point WorstError - error at worst point NOTE: this function guarantees that it returns exactly zero for a section with less than 3 points. -- ALGLIB PROJECT -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/ static void parametric_rdpanalyzesectionpar(/* Real */ ae_matrix* xy, ae_int_t i0, ae_int_t i1, ae_int_t d, ae_int_t* worstidx, double* worsterror, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double d2; double ts; double vv; *worstidx = 0; *worsterror = 0; /* * Quick exit for 0, 1, 2 points */ if( i1-i0+1<3 ) { *worstidx = i0; *worsterror = 0.0; return; } /* * Estimate D2 - squared distance between XY[I1] and XY[I0]. * In case D2=0 handle it as special case. */ d2 = 0.0; for(j=0; j<=d-1; j++) { d2 = d2+ae_sqr(xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j], _state); } if( ae_fp_eq(d2,(double)(0)) ) { /* * First and last points are equal, interval evaluation is * trivial - we just calculate distance from all points to * the first/last one. */ *worstidx = i0; *worsterror = 0.0; for(i=i0+1; i<=i1-1; i++) { vv = 0.0; for(j=0; j<=d-1; j++) { v = xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j]; vv = vv+v*v; } vv = ae_sqrt(vv, _state); if( ae_fp_greater(vv,*worsterror) ) { *worsterror = vv; *worstidx = i; } } return; } /* * General case * * Current section of curve is modeled as x(t) = d*t+c, where * d = XY[I1]-XY[I0] * c = XY[I0] * t is in [0,1] */ *worstidx = i0; *worsterror = 0.0; for(i=i0+1; i<=i1-1; i++) { /* * Determine t_s - parameter value for projected point. */ ts = (double)(i-i0)/(double)(i1-i0); /* * Estimate error norm */ vv = 0.0; for(j=0; j<=d-1; j++) { v = (xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j])*ts-(xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j]); vv = vv+ae_sqr(v, _state); } vv = ae_sqrt(vv, _state); if( ae_fp_greater(vv,*worsterror) ) { *worsterror = vv; *worstidx = i; } } } void _pspline2interpolant_init(void* _p, ae_state *_state) { pspline2interpolant *p = (pspline2interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->p, 0, DT_REAL, _state); _spline1dinterpolant_init(&p->x, _state); _spline1dinterpolant_init(&p->y, _state); } void _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state) { pspline2interpolant *dst = (pspline2interpolant*)_dst; pspline2interpolant *src = (pspline2interpolant*)_src; dst->n = src->n; dst->periodic = src->periodic; ae_vector_init_copy(&dst->p, &src->p, _state); _spline1dinterpolant_init_copy(&dst->x, &src->x, _state); _spline1dinterpolant_init_copy(&dst->y, &src->y, _state); } void _pspline2interpolant_clear(void* _p) { pspline2interpolant *p = (pspline2interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->p); _spline1dinterpolant_clear(&p->x); _spline1dinterpolant_clear(&p->y); } void _pspline2interpolant_destroy(void* _p) { pspline2interpolant *p = (pspline2interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->p); _spline1dinterpolant_destroy(&p->x); _spline1dinterpolant_destroy(&p->y); } void _pspline3interpolant_init(void* _p, ae_state *_state) { pspline3interpolant *p = (pspline3interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->p, 0, DT_REAL, _state); _spline1dinterpolant_init(&p->x, _state); _spline1dinterpolant_init(&p->y, _state); _spline1dinterpolant_init(&p->z, _state); } void _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state) { pspline3interpolant *dst = (pspline3interpolant*)_dst; pspline3interpolant *src = (pspline3interpolant*)_src; dst->n = src->n; dst->periodic = src->periodic; ae_vector_init_copy(&dst->p, &src->p, _state); _spline1dinterpolant_init_copy(&dst->x, &src->x, _state); _spline1dinterpolant_init_copy(&dst->y, &src->y, _state); _spline1dinterpolant_init_copy(&dst->z, &src->z, _state); } void _pspline3interpolant_clear(void* _p) { pspline3interpolant *p = (pspline3interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->p); _spline1dinterpolant_clear(&p->x); _spline1dinterpolant_clear(&p->y); _spline1dinterpolant_clear(&p->z); } void _pspline3interpolant_destroy(void* _p) { pspline3interpolant *p = (pspline3interpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->p); _spline1dinterpolant_destroy(&p->x); _spline1dinterpolant_destroy(&p->y); _spline1dinterpolant_destroy(&p->z); } /************************************************************************* This function creates RBF model for a scalar (NY=1) or vector (NY>1) function in a NX-dimensional space (NX=2 or NX=3). Newly created model is empty. It can be used for interpolation right after creation, but it just returns zeros. You have to add points to the model, tune interpolation settings, and then call model construction function RBFBuildModel() which will update model according to your specification. USAGE: 1. User creates model with RBFCreate() 2. User adds dataset with RBFSetPoints() (points do NOT have to be on a regular grid) 3. (OPTIONAL) User chooses polynomial term by calling: * RBFLinTerm() to set linear term * RBFConstTerm() to set constant term * RBFZeroTerm() to set zero term By default, linear term is used. 4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) or ML (RBFSetAlgoMultiLayer). 5. User calls RBFBuildModel() function which rebuilds model according to the specification 6. User may call RBFCalc() to calculate model value at the specified point, RBFGridCalc() to calculate model values at the points of the regular grid. User may extract model coefficients with RBFUnpack() call. INPUT PARAMETERS: NX - dimension of the space, NX=2 or NX=3 NY - function dimension, NY>=1 OUTPUT PARAMETERS: S - RBF model (initially equals to zero) NOTE 1: memory requirements. RBF models require amount of memory which is proportional to the number of data points. Memory is allocated during model construction, but most of this memory is freed after model coefficients are calculated. Some approximate estimates for N centers with default settings are given below: * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is needed during model construction stage. * about 15*N*sizeof(double) bytes is needed after model is built. For example, for N=100000 we may need 0.6 GB of memory to build model, but just about 0.012 GB to store it. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state) { ae_int_t i; ae_int_t j; _rbfmodel_clear(s); ae_assert(nx==2||nx==3, "RBFCreate: NX<>2 and NX<>3", _state); ae_assert(ny>=1, "RBFCreate: NY<1", _state); s->nx = nx; s->ny = ny; s->nl = 0; s->nc = 0; ae_matrix_set_length(&s->v, ny, rbf_mxnx+1, _state); for(i=0; i<=ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { s->v.ptr.pp_double[i][j] = (double)(0); } } s->n = 0; s->rmax = (double)(0); s->gridtype = 2; s->fixrad = ae_false; s->radvalue = (double)(1); s->radzvalue = (double)(5); s->aterm = 1; s->algorithmtype = 1; /* * stopping criteria */ s->epsort = rbf_eps; s->epserr = rbf_eps; s->maxits = 0; } /************************************************************************* This function adds dataset. This function overrides results of the previous calls, i.e. multiple calls of this function will result in only the last set being added. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call. XY - points, array[N,NX+NY]. One row corresponds to one point in the dataset. First NX elements are coordinates, next NY elements are function values. Array may be larger than specific, in this case only leading [N,NX+NY] elements will be used. N - number of points in the dataset After you've added dataset and (optionally) tuned algorithm settings you should call RBFBuildModel() in order to build a model for you. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetpoints(rbfmodel* s, /* Real */ ae_matrix* xy, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_assert(n>0, "RBFSetPoints: N<0", _state); ae_assert(xy->rows>=n, "RBFSetPoints: Rows(XY)cols>=s->nx+s->ny, "RBFSetPoints: Cols(XY)n = n; ae_matrix_set_length(&s->x, s->n, rbf_mxnx, _state); ae_matrix_set_length(&s->y, s->n, s->ny, _state); for(i=0; i<=s->n-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { s->x.ptr.pp_double[i][j] = (double)(0); } for(j=0; j<=s->nx-1; j++) { s->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; } for(j=0; j<=s->ny-1; j++) { s->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+s->nx]; } } } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-QNN and it is good for point sets with following properties: a) all points are distinct b) all points are well separated. c) points distribution is approximately uniform. There is no "contour lines", clusters of points, or other small-scale structures. Algorithm description: 1) interpolation centers are allocated to data points 2) interpolation radii are calculated as distances to the nearest centers times Q coefficient (where Q is a value from [0.75,1.50]). 3) after performing (2) radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across all dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. When (a) is violated, we will be unable to build RBF model. When (b) or (c) are violated, model will be built, but interpolation quality will be low. See http://www.alglib.net/interpolation/ for more information on this subject. This algorithm is used by default. Additional Q parameter controls smoothness properties of the RBF basis: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q around 1.0 gives good balance between smoothness and condition number * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q>2.0 will effectively make optimizer useless because it won't converge within reasonable amount of iterations. It is possible to set such large Q, but it is advised not to do so. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - Q parameter, Q>0, recommended value - 1.0 Z - Z parameter, Z>0, recommended value - 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state) { ae_assert(ae_isfinite(q, _state), "RBFSetAlgoQNN: Q is infinite or NAN", _state); ae_assert(ae_fp_greater(q,(double)(0)), "RBFSetAlgoQNN: Q<=0", _state); rbf_rbfgridpoints(s, _state); rbf_rbfradnn(s, q, z, _state); s->algorithmtype = 1; } /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. model with subsequently decreasing radii, which allows us to combine smoothness (due to large radii of the first layers) with exactness (due to small radii of the last layers) and fast convergence. Internally RBF-ML uses many different means of acceleration, from sparse matrices to KD-trees, which results in algorithm whose working time is roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a number of points, Density is an average density if points per unit of the interpolation space, RBase is an initial radius, NLayers is a number of layers. RBF-ML is good for following kinds of interpolation problems: 1. "exact" problems (perfect fit) with well separated points 2. least squares problems with arbitrary distribution of points (algorithm gives perfect fit where it is possible, and resorts to least squares fit in the hard areas). 3. noisy problems where we want to apply some controlled amount of smoothing. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call RBase - RBase parameter, RBase>0 NLayers - NLayers parameter, NLayers>0, recommended value to start with - about 5. LambdaV - regularization value, can be useful when solving problem in the least squares sense. Optimal lambda is problem- dependent and require trial and error. In our experience, good lambda can be as large as 0.1, and you can use 0.001 as initial guess. Default value - 0.01, which is used when LambdaV is not given. You can specify zero value, but it is not recommended to do so. TUNING ALGORITHM In order to use this algorithm you have to choose three parameters: * initial radius RBase * number of layers in the model NLayers * regularization coefficient LambdaV Initial radius is easy to choose - you can pick any number several times larger than the average distance between points. Algorithm won't break down if you choose radius which is too large (model construction time will increase, but model will be built correctly). Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used by the last layer) will be smaller than the typical distance between points. In case model error is too large, you can increase number of layers. Having more layers will make model construction and evaluation proportionally slower, but it will allow you to have model which precisely fits your data. From the other side, if you want to suppress noise, you can DECREASE number of layers to make your model less flexible. Regularization coefficient LambdaV controls smoothness of the individual models built for each layer. We recommend you to use default value in case you don't want to tune this parameter, because having non-zero LambdaV accelerates and stabilizes internal iterative algorithm. In case you want to suppress noise you can use LambdaV as additional parameter (larger value = more smoothness) to tune. TYPICAL ERRORS 1. Using initial radius which is too large. Memory requirements of the RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is an average density of points per unit of the interpolation space). In the extreme case of the very large RBase we will need O(N^2) units of memory - and many layers in order to decrease radius to some reasonably small value. 2. Using too small number of layers - RBF models with large radius are not flexible enough to reproduce small variations in the target function. You need many layers with different radii, from large to small, in order to have good model. 3. Using initial radius which is too small. You will get model with "holes" in the areas which are too far away from interpolation centers. However, algorithm will work correctly (and quickly) in this case. 4. Using too many layers - you will get too large and too slow model. This model will perfectly reproduce your function, but maybe you will be able to achieve similar results with less layers (and less memory). -- ALGLIB -- Copyright 02.03.2012 by Bochkanov Sergey *************************************************************************/ void rbfsetalgomultilayer(rbfmodel* s, double rbase, ae_int_t nlayers, double lambdav, ae_state *_state) { ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoMultiLayer: RBase is infinite or NaN", _state); ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoMultiLayer: RBase<=0", _state); ae_assert(nlayers>=0, "RBFSetAlgoMultiLayer: NLayers<0", _state); ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiLayer: LambdaV is infinite or NAN", _state); ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiLayer: LambdaV<0", _state); s->radvalue = rbase; s->nlayers = nlayers; s->algorithmtype = 2; s->lambdav = lambdav; } /************************************************************************* This function sets linear term (model is a sum of radial basis functions plus linear polynomial). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetlinterm(rbfmodel* s, ae_state *_state) { s->aterm = 1; } /************************************************************************* This function sets constant term (model is a sum of radial basis functions plus constant). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetconstterm(rbfmodel* s, ae_state *_state) { s->aterm = 2; } /************************************************************************* This function sets zero term (model is a sum of radial basis functions without polynomial term). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetzeroterm(rbfmodel* s, ae_state *_state) { s->aterm = 3; } /************************************************************************* This function sets stopping criteria of the underlying linear solver. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call EpsOrt - orthogonality stopping criterion, EpsOrt>=0. Algorithm will stop when ||A'*r||<=EpsOrt where A' is a transpose of the system matrix, r is a residual vector. Recommended value of EpsOrt is equal to 1E-6. This criterion will stop algorithm when we have "bad fit" situation, i.e. when we should stop in a point with large, nonzero residual. EpsErr - residual stopping criterion. Algorithm will stop when ||r||<=EpsErr*||b||, where r is a residual vector, b is a right part of the system (function values). Recommended value of EpsErr is equal to 1E-3 or 1E-6. This criterion will stop algorithm in a "good fit" situation when we have near-zero residual near the desired solution. MaxIts - this criterion will stop algorithm after MaxIts iterations. It should be used for debugging purposes only! Zero MaxIts means that no limit is placed on the number of iterations. We recommend to set moderate non-zero values EpsOrt and EpsErr simultaneously. Values equal to 10E-6 are good to start with. In case you need high performance and do not need high precision , you may decrease EpsErr down to 0.001. However, we do not recommend decreasing EpsOrt. As for MaxIts, we recommend to leave it zero unless you know what you do. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetcond(rbfmodel* s, double epsort, double epserr, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsort, _state)&&ae_fp_greater_eq(epsort,(double)(0)), "RBFSetCond: EpsOrt is negative, INF or NAN", _state); ae_assert(ae_isfinite(epserr, _state)&&ae_fp_greater_eq(epserr,(double)(0)), "RBFSetCond: EpsB is negative, INF or NAN", _state); ae_assert(maxits>=0, "RBFSetCond: MaxIts is negative", _state); if( (ae_fp_eq(epsort,(double)(0))&&ae_fp_eq(epserr,(double)(0)))&&maxits==0 ) { s->epsort = rbf_eps; s->epserr = rbf_eps; s->maxits = 0; } else { s->epsort = epsort; s->epserr = epserr; s->maxits = maxits; } } /************************************************************************* This function builds RBF model and returns report (contains some information which can be used for evaluation of the algorithm properties). Call to this function modifies RBF model by calculating its centers/radii/ weights and saving them into RBFModel structure. Initially RBFModel contain zero coefficients, but after call to this function we will have coefficients which were calculated in order to fit our dataset. After you called this function you can call RBFCalc(), RBFGridCalc() and other model calculation functions. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Rep - report: * Rep.TerminationType: * -5 - non-distinct basis function centers were detected, interpolation aborted * -4 - nonconvergence of the internal SVD solver * 1 - successful termination Fields are used for debugging purposes: * Rep.IterationsCount - iterations count of the LSQR solver * Rep.NMV - number of matrix-vector products * Rep.ARows - rows count for the system matrix * Rep.ACols - columns count for the system matrix * Rep.ANNZ - number of significantly non-zero elements (elements above some algorithm-determined threshold) NOTE: failure to build model will leave current state of the structure unchanged. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state) { ae_frame _frame_block; kdtree tree; kdtree ctree; ae_vector dist; ae_vector xcx; ae_matrix a; ae_matrix v; ae_matrix omega; ae_vector y; ae_matrix residualy; ae_vector radius; ae_matrix xc; ae_vector mnx; ae_vector mxx; ae_vector edge; ae_vector mxsteps; ae_int_t nc; double rmax; ae_vector tags; ae_vector ctags; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t k2; ae_int_t snnz; ae_vector tmp0; ae_vector tmp1; ae_int_t layerscnt; ae_frame_make(_state, &_frame_block); _rbfreport_clear(rep); _kdtree_init(&tree, _state); _kdtree_init(&ctree, _state); ae_vector_init(&dist, 0, DT_REAL, _state); ae_vector_init(&xcx, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_matrix_init(&omega, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&residualy, 0, 0, DT_REAL, _state); ae_vector_init(&radius, 0, DT_REAL, _state); ae_matrix_init(&xc, 0, 0, DT_REAL, _state); ae_vector_init(&mnx, 0, DT_REAL, _state); ae_vector_init(&mxx, 0, DT_REAL, _state); ae_vector_init(&edge, 0, DT_REAL, _state); ae_vector_init(&mxsteps, 0, DT_INT, _state); ae_vector_init(&tags, 0, DT_INT, _state); ae_vector_init(&ctags, 0, DT_INT, _state); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_vector_init(&tmp1, 0, DT_REAL, _state); ae_assert(s->nx==2||s->nx==3, "RBFBuildModel: S.NX<>2 or S.NX<>3!", _state); /* * Quick exit when we have no points */ if( s->n==0 ) { rep->terminationtype = 1; rep->iterationscount = 0; rep->nmv = 0; rep->arows = 0; rep->acols = 0; kdtreebuildtagged(&s->xc, &tags, 0, rbf_mxnx, 0, 2, &s->tree, _state); ae_matrix_set_length(&s->xc, 0, 0, _state); ae_matrix_set_length(&s->wr, 0, 0, _state); s->nc = 0; s->rmax = (double)(0); ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); for(i=0; i<=s->ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { s->v.ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * General case, N>0 */ rep->annz = 0; rep->iterationscount = 0; rep->nmv = 0; ae_vector_set_length(&xcx, rbf_mxnx, _state); /* * First model in a sequence - linear model. * Residuals from linear regression are stored in the ResidualY variable * (used later to build RBF models). */ ae_matrix_set_length(&residualy, s->n, s->ny, _state); for(i=0; i<=s->n-1; i++) { for(j=0; j<=s->ny-1; j++) { residualy.ptr.pp_double[i][j] = s->y.ptr.pp_double[i][j]; } } if( !rbf_buildlinearmodel(&s->x, &residualy, s->n, s->ny, s->aterm, &v, _state) ) { rep->terminationtype = -5; ae_frame_leave(_state); return; } /* * Handle special case: multilayer model with NLayers=0. * Quick exit. */ if( s->algorithmtype==2&&s->nlayers==0 ) { rep->terminationtype = 1; rep->iterationscount = 0; rep->nmv = 0; rep->arows = 0; rep->acols = 0; kdtreebuildtagged(&s->xc, &tags, 0, rbf_mxnx, 0, 2, &s->tree, _state); ae_matrix_set_length(&s->xc, 0, 0, _state); ae_matrix_set_length(&s->wr, 0, 0, _state); s->nc = 0; s->rmax = (double)(0); ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); for(i=0; i<=s->ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; } } ae_frame_leave(_state); return; } /* * Second model in a sequence - RBF term. * * NOTE: assignments below are not necessary, but without them * MSVC complains about unitialized variables. */ nc = 0; rmax = (double)(0); layerscnt = 0; if( s->algorithmtype==1 ) { /* * Add RBF model. * This model uses local KD-trees to speed-up nearest neighbor searches. */ if( s->gridtype==1 ) { ae_vector_set_length(&mxx, s->nx, _state); ae_vector_set_length(&mnx, s->nx, _state); ae_vector_set_length(&mxsteps, s->nx, _state); ae_vector_set_length(&edge, s->nx, _state); for(i=0; i<=s->nx-1; i++) { mxx.ptr.p_double[i] = s->x.ptr.pp_double[0][i]; mnx.ptr.p_double[i] = s->x.ptr.pp_double[0][i]; } for(i=0; i<=s->n-1; i++) { for(j=0; j<=s->nx-1; j++) { if( ae_fp_less(mxx.ptr.p_double[j],s->x.ptr.pp_double[i][j]) ) { mxx.ptr.p_double[j] = s->x.ptr.pp_double[i][j]; } if( ae_fp_greater(mnx.ptr.p_double[j],s->x.ptr.pp_double[i][j]) ) { mnx.ptr.p_double[j] = s->x.ptr.pp_double[i][j]; } } } for(i=0; i<=s->nx-1; i++) { mxsteps.ptr.p_int[i] = ae_trunc((mxx.ptr.p_double[i]-mnx.ptr.p_double[i])/(2*s->h), _state)+1; edge.ptr.p_double[i] = (mxx.ptr.p_double[i]+mnx.ptr.p_double[i])/2-s->h*mxsteps.ptr.p_int[i]; } nc = 1; for(i=0; i<=s->nx-1; i++) { mxsteps.ptr.p_int[i] = 2*mxsteps.ptr.p_int[i]+1; nc = nc*mxsteps.ptr.p_int[i]; } ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); if( s->nx==2 ) { for(i=0; i<=mxsteps.ptr.p_int[0]-1; i++) { for(j=0; j<=mxsteps.ptr.p_int[1]-1; j++) { for(k2=0; k2<=rbf_mxnx-1; k2++) { xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][k2] = (double)(0); } xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][0] = edge.ptr.p_double[0]+s->h*i; xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][1] = edge.ptr.p_double[1]+s->h*j; } } } if( s->nx==3 ) { for(i=0; i<=mxsteps.ptr.p_int[0]-1; i++) { for(j=0; j<=mxsteps.ptr.p_int[1]-1; j++) { for(k=0; k<=mxsteps.ptr.p_int[2]-1; k++) { for(k2=0; k2<=rbf_mxnx-1; k2++) { xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][k2] = (double)(0); } xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][0] = edge.ptr.p_double[0]+s->h*i; xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][1] = edge.ptr.p_double[1]+s->h*j; xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][2] = edge.ptr.p_double[2]+s->h*k; } } } } } else { if( s->gridtype==2 ) { nc = s->n; ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); for(i=0; i<=nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xc.ptr.pp_double[i][j] = s->x.ptr.pp_double[i][j]; } } } else { if( s->gridtype==3 ) { nc = s->nc; ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); for(i=0; i<=nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xc.ptr.pp_double[i][j] = s->xc.ptr.pp_double[i][j]; } } } else { ae_assert(ae_false, "RBFBuildModel: either S.GridType<1 or S.GridType>3!", _state); } } } rmax = (double)(0); ae_vector_set_length(&radius, nc, _state); ae_vector_set_length(&ctags, nc, _state); for(i=0; i<=nc-1; i++) { ctags.ptr.p_int[i] = i; } kdtreebuildtagged(&xc, &ctags, nc, rbf_mxnx, 0, 2, &ctree, _state); if( s->fixrad ) { /* * Fixed radius */ for(i=0; i<=nc-1; i++) { radius.ptr.p_double[i] = s->radvalue; } rmax = radius.ptr.p_double[0]; } else { /* * Dynamic radius */ if( nc==0 ) { rmax = (double)(1); } else { if( nc==1 ) { radius.ptr.p_double[0] = s->radvalue; rmax = radius.ptr.p_double[0]; } else { /* * NC>1, calculate radii using distances to nearest neigbors */ for(i=0; i<=nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xcx.ptr.p_double[j] = xc.ptr.pp_double[i][j]; } if( kdtreequeryknn(&ctree, &xcx, 1, ae_false, _state)>0 ) { kdtreequeryresultsdistances(&ctree, &dist, _state); radius.ptr.p_double[i] = s->radvalue*dist.ptr.p_double[0]; } else { /* * No neighbors found (it will happen when we have only one center). * Initialize radius with default value. */ radius.ptr.p_double[i] = 1.0; } } /* * Apply filtering */ rvectorsetlengthatleast(&tmp0, nc, _state); for(i=0; i<=nc-1; i++) { tmp0.ptr.p_double[i] = radius.ptr.p_double[i]; } tagsortfast(&tmp0, &tmp1, nc, _state); for(i=0; i<=nc-1; i++) { radius.ptr.p_double[i] = ae_minreal(radius.ptr.p_double[i], s->radzvalue*tmp0.ptr.p_double[nc/2], _state); } /* * Calculate RMax, check that all radii are non-zero */ for(i=0; i<=nc-1; i++) { rmax = ae_maxreal(rmax, radius.ptr.p_double[i], _state); } for(i=0; i<=nc-1; i++) { if( ae_fp_eq(radius.ptr.p_double[i],(double)(0)) ) { rep->terminationtype = -5; ae_frame_leave(_state); return; } } } } } ivectorsetlengthatleast(&tags, s->n, _state); for(i=0; i<=s->n-1; i++) { tags.ptr.p_int[i] = i; } kdtreebuildtagged(&s->x, &tags, s->n, rbf_mxnx, 0, 2, &tree, _state); rbf_buildrbfmodellsqr(&s->x, &residualy, &xc, &radius, s->n, nc, s->ny, &tree, &ctree, s->epsort, s->epserr, s->maxits, &rep->annz, &snnz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); layerscnt = 1; } else { if( s->algorithmtype==2 ) { rmax = s->radvalue; rbf_buildrbfmlayersmodellsqr(&s->x, &residualy, &xc, s->radvalue, &radius, s->n, &nc, s->ny, s->nlayers, &ctree, 1.0E-6, 1.0E-6, 50, s->lambdav, &rep->annz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); layerscnt = s->nlayers; } else { ae_assert(ae_false, "RBFBuildModel: internal error(AlgorithmType neither 1 nor 2)", _state); } } if( rep->terminationtype<=0 ) { ae_frame_leave(_state); return; } /* * Model is built */ s->nc = nc/layerscnt; s->rmax = rmax; s->nl = layerscnt; ae_matrix_set_length(&s->xc, s->nc, rbf_mxnx, _state); ae_matrix_set_length(&s->wr, s->nc, 1+s->nl*s->ny, _state); ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); for(i=0; i<=s->nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { s->xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]; } } ivectorsetlengthatleast(&tags, s->nc, _state); for(i=0; i<=s->nc-1; i++) { tags.ptr.p_int[i] = i; } kdtreebuildtagged(&s->xc, &tags, s->nc, rbf_mxnx, 0, 2, &s->tree, _state); for(i=0; i<=s->nc-1; i++) { s->wr.ptr.pp_double[i][0] = radius.ptr.p_double[i]; for(k=0; k<=layerscnt-1; k++) { for(j=0; j<=s->ny-1; j++) { s->wr.ptr.pp_double[i][1+k*s->ny+j] = omega.ptr.pp_double[k*s->nc+i][j]; } } } for(i=0; i<=s->ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; } } rep->terminationtype = 1; rep->arows = s->n; rep->acols = s->nc; ae_frame_leave(_state); } /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=2 (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). If you want to calculate function values many times, consider using RBFGridCalc2(), which is far more efficient than many subsequent calls to RBFCalc2(). This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t lx; ae_int_t tg; double d2; double t; double bfcur; double rcur; double result; ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); if( s->ny!=1||s->nx!=2 ) { result = (double)(0); return result; } result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][rbf_mxnx]; if( s->nc==0 ) { return result; } rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); for(i=0; i<=rbf_mxnx-1; i++) { s->calcbufxcx.ptr.p_double[i] = 0.0; } s->calcbufxcx.ptr.p_double[0] = x0; s->calcbufxcx.ptr.p_double[1] = x1; lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); for(i=0; i<=lx-1; i++) { tg = s->calcbuftags.ptr.p_int[i]; d2 = ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state); rcur = s->wr.ptr.pp_double[tg][0]; bfcur = ae_exp(-d2/(rcur*rcur), _state); for(j=0; j<=s->nl-1; j++) { result = result+bfcur*s->wr.ptr.pp_double[tg][1+j]; rcur = 0.5*rcur; t = bfcur*bfcur; bfcur = t*t; } } return result; } /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=3 (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). This function returns 0.0 when: * model is not initialized * NX<>3 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number X2 - third coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc3(rbfmodel* s, double x0, double x1, double x2, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t lx; ae_int_t tg; double t; double rcur; double bf; double result; ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); if( s->ny!=1||s->nx!=3 ) { result = (double)(0); return result; } result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][rbf_mxnx]; if( s->nc==0 ) { return result; } /* * calculating value for F(X) */ rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); for(i=0; i<=rbf_mxnx-1; i++) { s->calcbufxcx.ptr.p_double[i] = 0.0; } s->calcbufxcx.ptr.p_double[0] = x0; s->calcbufxcx.ptr.p_double[1] = x1; s->calcbufxcx.ptr.p_double[2] = x2; lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); for(i=0; i<=lx-1; i++) { tg = s->calcbuftags.ptr.p_int[i]; rcur = s->wr.ptr.pp_double[tg][0]; bf = ae_exp(-(ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state)+ae_sqr(x2-s->calcbufx.ptr.pp_double[i][2], _state))/ae_sqr(rcur, _state), _state); for(j=0; j<=s->nl-1; j++) { result = result+bf*s->wr.ptr.pp_double[tg][1+j]; t = bf*bf; bf = t*t; } } return result; } /************************************************************************* This function calculates values of the RBF model at the given point. This is general function which can be used for arbitrary NX (dimension of the space of arguments) and NY (dimension of the function itself). However when you have NY=1 you may find more convenient to use RBFCalc2() or RBFCalc3(). This function returns 0.0 when model is not initialized. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. OUTPUT PARAMETERS: Y - function value, array[NY]. Y is out-parameter and reallocated after call to this function. In case you want to reuse previously allocated Y, you may use RBFCalcBuf(), which reallocates Y only when it is too small. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalc(rbfmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_vector_clear(y); ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)nx, _state), "RBFCalc: X contains infinite or NaN values", _state); rbfcalcbuf(s, x, y, _state); } /************************************************************************* This function calculates values of the RBF model at the given point. Same as RBFCalc(), but does not reallocate Y when in is large enough to store function values. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. Y - possibly preallocated array OUTPUT PARAMETERS: Y - function value, array[NY]. Y is not reallocated when it is larger than NY. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalcbuf(rbfmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t lx; ae_int_t tg; double t; double rcur; double bf; ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); if( y->cntny ) { ae_vector_set_length(y, s->ny, _state); } for(i=0; i<=s->ny-1; i++) { y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbf_mxnx]; for(j=0; j<=s->nx-1; j++) { y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; } } if( s->nc==0 ) { return; } rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); for(i=0; i<=rbf_mxnx-1; i++) { s->calcbufxcx.ptr.p_double[i] = 0.0; } for(i=0; i<=s->nx-1; i++) { s->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; } lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); for(i=0; i<=s->ny-1; i++) { for(j=0; j<=lx-1; j++) { tg = s->calcbuftags.ptr.p_int[j]; rcur = s->wr.ptr.pp_double[tg][0]; bf = ae_exp(-(ae_sqr(s->calcbufxcx.ptr.p_double[0]-s->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[1]-s->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[2]-s->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state); for(k=0; k<=s->nl-1; k++) { y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i]; t = bf*bf; bf = t*t; } } } } /************************************************************************* This function calculates values of the RBF model at the regular grid. Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - array of grid nodes, first coordinates, array[N0] N0 - grid size (number of nodes) in the first dimension X1 - array of grid nodes, second coordinates, array[N1] N1 - grid size (number of nodes) in the second dimension OUTPUT PARAMETERS: Y - function values, array[N0,N1]. Y is out-variable and is reallocated by this function. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfgridcalc2(rbfmodel* s, /* Real */ ae_vector* x0, ae_int_t n0, /* Real */ ae_vector* x1, ae_int_t n1, /* Real */ ae_matrix* y, ae_state *_state) { ae_frame _frame_block; ae_vector cpx0; ae_vector cpx1; ae_vector p01; ae_vector p11; ae_vector p2; double rlimit; double xcnorm2; ae_int_t hp01; double hcpx0; double xc0; double xc1; double omega; double radius; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t d; ae_int_t i00; ae_int_t i01; ae_int_t i10; ae_int_t i11; ae_frame_make(_state, &_frame_block); ae_matrix_clear(y); ae_vector_init(&cpx0, 0, DT_REAL, _state); ae_vector_init(&cpx1, 0, DT_REAL, _state); ae_vector_init(&p01, 0, DT_INT, _state); ae_vector_init(&p11, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state); ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state); ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)cnt>=n1, "RBFGridCalc2: Length(X1)ptr.pp_double[i][j] = (double)(0); } } if( (s->ny!=1||s->nx!=2)||s->nc==0 ) { ae_frame_leave(_state); return; } /* *create and sort arrays */ ae_vector_set_length(&cpx0, n0, _state); for(i=0; i<=n0-1; i++) { cpx0.ptr.p_double[i] = x0->ptr.p_double[i]; } tagsort(&cpx0, n0, &p01, &p2, _state); ae_vector_set_length(&cpx1, n1, _state); for(i=0; i<=n1-1; i++) { cpx1.ptr.p_double[i] = x1->ptr.p_double[i]; } tagsort(&cpx1, n1, &p11, &p2, _state); /* *calculate function's value */ for(i=0; i<=s->nc-1; i++) { radius = s->wr.ptr.pp_double[i][0]; for(d=0; d<=s->nl-1; d++) { omega = s->wr.ptr.pp_double[i][1+d]; rlimit = radius*rbf_rbffarradius; /* *search lower and upper indexes */ i00 = lowerbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]-rlimit, _state); i01 = upperbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]+rlimit, _state); i10 = lowerbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]-rlimit, _state); i11 = upperbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]+rlimit, _state); xc0 = s->xc.ptr.pp_double[i][0]; xc1 = s->xc.ptr.pp_double[i][1]; for(j=i00; j<=i01-1; j++) { hcpx0 = cpx0.ptr.p_double[j]; hp01 = p01.ptr.p_int[j]; for(k=i10; k<=i11-1; k++) { xcnorm2 = ae_sqr(hcpx0-xc0, _state)+ae_sqr(cpx1.ptr.p_double[k]-xc1, _state); if( ae_fp_less_eq(xcnorm2,rlimit*rlimit) ) { y->ptr.pp_double[hp01][p11.ptr.p_int[k]] = y->ptr.pp_double[hp01][p11.ptr.p_int[k]]+ae_exp(-xcnorm2/ae_sqr(radius, _state), _state)*omega; } } } radius = 0.5*radius; } } /* *add linear term */ for(i=0; i<=n0-1; i++) { for(j=0; j<=n1-1; j++) { y->ptr.pp_double[i][j] = y->ptr.pp_double[i][j]+s->v.ptr.pp_double[0][0]*x0->ptr.p_double[i]+s->v.ptr.pp_double[0][1]*x1->ptr.p_double[j]+s->v.ptr.pp_double[0][rbf_mxnx]; } } ae_frame_leave(_state); } /************************************************************************* This function "unpacks" RBF model by extracting its coefficients. INPUT PARAMETERS: S - RBF model OUTPUT PARAMETERS: NX - dimensionality of argument NY - dimensionality of the target function XWR - model information, array[NC,NX+NY+1]. One row of the array corresponds to one basis function: * first NX columns - coordinates of the center * next NY columns - weights, one per dimension of the function being modelled * last column - radius, same for all dimensions of the function being modelled NC - number of the centers V - polynomial term , array[NY,NX+1]. One row per one dimension of the function being modelled. First NX elements are linear coefficients, V[NX] is equal to the constant part. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfunpack(rbfmodel* s, ae_int_t* nx, ae_int_t* ny, /* Real */ ae_matrix* xwr, ae_int_t* nc, /* Real */ ae_matrix* v, ae_state *_state) { ae_int_t i; ae_int_t j; double rcur; *nx = 0; *ny = 0; ae_matrix_clear(xwr); *nc = 0; ae_matrix_clear(v); *nx = s->nx; *ny = s->ny; *nc = s->nc; /* * Fill V */ ae_matrix_set_length(v, s->ny, s->nx+1, _state); for(i=0; i<=s->ny-1; i++) { ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); v->ptr.pp_double[i][s->nx] = s->v.ptr.pp_double[i][rbf_mxnx]; } /* * Fill XWR and V */ if( *nc*s->nl>0 ) { ae_matrix_set_length(xwr, s->nc*s->nl, s->nx+s->ny+1, _state); for(i=0; i<=s->nc-1; i++) { rcur = s->wr.ptr.pp_double[i][0]; for(j=0; j<=s->nl-1; j++) { ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][0], 1, &s->xc.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][s->nx], 1, &s->wr.ptr.pp_double[i][1+j*s->ny], 1, ae_v_len(s->nx,s->nx+s->ny-1)); xwr->ptr.pp_double[i*s->nl+j][s->nx+s->ny] = rcur; rcur = 0.5*rcur; } } } } /************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 02.02.2012 by Bochkanov Sergey *************************************************************************/ void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state) { /* * Header */ ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); /* * Data */ ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); kdtreealloc(s, &model->tree, _state); allocrealmatrix(s, &model->xc, -1, -1, _state); allocrealmatrix(s, &model->wr, -1, -1, _state); ae_serializer_alloc_entry(s); allocrealmatrix(s, &model->v, -1, -1, _state); } /************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 02.02.2012 by Bochkanov Sergey *************************************************************************/ void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state) { /* * Header */ ae_serializer_serialize_int(s, getrbfserializationcode(_state), _state); ae_serializer_serialize_int(s, rbf_rbffirstversion, _state); /* * Data */ ae_serializer_serialize_int(s, model->nx, _state); ae_serializer_serialize_int(s, model->ny, _state); ae_serializer_serialize_int(s, model->nc, _state); ae_serializer_serialize_int(s, model->nl, _state); kdtreeserialize(s, &model->tree, _state); serializerealmatrix(s, &model->xc, -1, -1, _state); serializerealmatrix(s, &model->wr, -1, -1, _state); ae_serializer_serialize_double(s, model->rmax, _state); serializerealmatrix(s, &model->v, -1, -1, _state); } /************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 02.02.2012 by Bochkanov Sergey *************************************************************************/ void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state) { ae_int_t i0; ae_int_t i1; ae_int_t nx; ae_int_t ny; _rbfmodel_clear(model); /* * Header */ ae_serializer_unserialize_int(s, &i0, _state); ae_assert(i0==getrbfserializationcode(_state), "RBFUnserialize: stream header corrupted", _state); ae_serializer_unserialize_int(s, &i1, _state); ae_assert(i1==rbf_rbffirstversion, "RBFUnserialize: stream header corrupted", _state); /* * Unserialize primary model parameters, initialize model. * * It is necessary to call RBFCreate() because some internal fields * which are NOT unserialized will need initialization. */ ae_serializer_unserialize_int(s, &nx, _state); ae_serializer_unserialize_int(s, &ny, _state); rbfcreate(nx, ny, model, _state); ae_serializer_unserialize_int(s, &model->nc, _state); ae_serializer_unserialize_int(s, &model->nl, _state); kdtreeunserialize(s, &model->tree, _state); unserializerealmatrix(s, &model->xc, _state); unserializerealmatrix(s, &model->wr, _state); ae_serializer_unserialize_double(s, &model->rmax, _state); unserializerealmatrix(s, &model->v, _state); } /************************************************************************* This function changes centers allocation algorithm to one which allocates centers exactly at the dataset points (one input point = one center). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static void rbf_rbfgridpoints(rbfmodel* s, ae_state *_state) { s->gridtype = 2; } /************************************************************************* This function changes radii calculation algorithm to one which makes radius for I-th node equal to R[i]=DistNN[i]*Q, where: * R[i] is a radius calculated by the algorithm * DistNN[i] is distance from I-th center to its nearest neighbor center * Q is a scale parameter, which should be within [0.75,1.50], with recommended value equal to 1.0 * after performing radii calculation, radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across entire dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. This function won't have effect until next call to RBFBuildModel(). The idea behind this algorithm is to choose radii corresponding to basis functions is such way that I-th radius is approximately equal to distance from I-th center to its nearest neighbor. In this case interactions with distant points will be insignificant, and we will get well conditioned basis. Properties of this basis depend on the value of Q: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q around 1.0 gives good balance between smoothness and condition number INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - radius coefficient, Q>0 Z - z-parameter, Z>0 Default value of Q is equal to 1.0 Default value of Z is equal to 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static void rbf_rbfradnn(rbfmodel* s, double q, double z, ae_state *_state) { ae_assert(ae_isfinite(q, _state)&&ae_fp_greater(q,(double)(0)), "RBFRadNN: Q<=0, infinite or NAN", _state); ae_assert(ae_isfinite(z, _state)&&ae_fp_greater(z,(double)(0)), "RBFRadNN: Z<=0, infinite or NAN", _state); s->fixrad = ae_false; s->radvalue = q; s->radzvalue = z; } static ae_bool rbf_buildlinearmodel(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t ny, ae_int_t modeltype, /* Real */ ae_matrix* v, ae_state *_state) { ae_frame _frame_block; ae_vector tmpy; ae_matrix a; double scaling; ae_vector shifting; double mn; double mx; ae_vector c; lsfitreport rep; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t info; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_clear(v); ae_vector_init(&tmpy, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&shifting, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); _lsfitreport_init(&rep, _state); ae_assert(n>=0, "BuildLinearModel: N<0", _state); ae_assert(ny>0, "BuildLinearModel: NY<=0", _state); /* * Handle degenerate case (N=0) */ result = ae_true; ae_matrix_set_length(v, ny, rbf_mxnx+1, _state); if( n==0 ) { for(j=0; j<=rbf_mxnx; j++) { for(i=0; i<=ny-1; i++) { v->ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return result; } /* * Allocate temporaries */ ae_vector_set_length(&tmpy, n, _state); /* * General linear model. */ if( modeltype==1 ) { /* * Calculate scaling/shifting, transform variables, prepare LLS problem */ ae_matrix_set_length(&a, n, rbf_mxnx+1, _state); ae_vector_set_length(&shifting, rbf_mxnx, _state); scaling = (double)(0); for(i=0; i<=rbf_mxnx-1; i++) { mn = x->ptr.pp_double[0][i]; mx = mn; for(j=1; j<=n-1; j++) { if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) ) { mn = x->ptr.pp_double[j][i]; } if( ae_fp_less(mx,x->ptr.pp_double[j][i]) ) { mx = x->ptr.pp_double[j][i]; } } scaling = ae_maxreal(scaling, mx-mn, _state); shifting.ptr.p_double[i] = 0.5*(mx+mn); } if( ae_fp_eq(scaling,(double)(0)) ) { scaling = (double)(1); } else { scaling = 0.5*scaling; } for(i=0; i<=n-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][rbf_mxnx] = (double)(1); } /* * Solve linear system in transformed variables, make backward */ for(i=0; i<=ny-1; i++) { for(j=0; j<=n-1; j++) { tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; } lsfitlinear(&tmpy, &a, n, rbf_mxnx+1, &info, &c, &rep, _state); if( info<=0 ) { result = ae_false; ae_frame_leave(_state); return result; } for(j=0; j<=rbf_mxnx-1; j++) { v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling; } v->ptr.pp_double[i][rbf_mxnx] = c.ptr.p_double[rbf_mxnx]; for(j=0; j<=rbf_mxnx-1; j++) { v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j]; } for(j=0; j<=n-1; j++) { for(k=0; k<=rbf_mxnx-1; k++) { y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k]; } y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbf_mxnx]; } } ae_frame_leave(_state); return result; } /* * Constant model, very simple */ if( modeltype==2 ) { for(i=0; i<=ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { v->ptr.pp_double[i][j] = (double)(0); } for(j=0; j<=n-1; j++) { v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]+y->ptr.pp_double[j][i]; } if( n>0 ) { v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]/n; } for(j=0; j<=n-1; j++) { y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbf_mxnx]; } } ae_frame_leave(_state); return result; } /* * Zero model */ ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state); for(i=0; i<=ny-1; i++) { for(j=0; j<=rbf_mxnx; j++) { v->ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return result; } static void rbf_buildrbfmodellsqr(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, /* Real */ ae_matrix* xc, /* Real */ ae_vector* r, ae_int_t n, ae_int_t nc, ae_int_t ny, kdtree* pointstree, kdtree* centerstree, double epsort, double epserr, ae_int_t maxits, ae_int_t* gnnz, ae_int_t* snnz, /* Real */ ae_matrix* w, ae_int_t* info, ae_int_t* iterationscount, ae_int_t* nmv, ae_state *_state) { ae_frame _frame_block; linlsqrstate state; linlsqrreport lsqrrep; sparsematrix spg; sparsematrix sps; ae_vector nearcenterscnt; ae_vector nearpointscnt; ae_vector skipnearpointscnt; ae_vector farpointscnt; ae_int_t maxnearcenterscnt; ae_int_t maxnearpointscnt; ae_int_t maxfarpointscnt; ae_int_t sumnearcenterscnt; ae_int_t sumnearpointscnt; ae_int_t sumfarpointscnt; double maxrad; ae_vector pointstags; ae_vector centerstags; ae_matrix nearpoints; ae_matrix nearcenters; ae_matrix farpoints; ae_int_t tmpi; ae_int_t pointscnt; ae_int_t centerscnt; ae_vector xcx; ae_vector tmpy; ae_vector tc; ae_vector g; ae_vector c; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t sind; ae_matrix a; double vv; double vx; double vy; double vz; double vr; double gnorm2; ae_vector tmp0; ae_vector tmp1; ae_vector tmp2; double fx; ae_matrix xx; ae_matrix cx; double mrad; ae_frame_make(_state, &_frame_block); *gnnz = 0; *snnz = 0; ae_matrix_clear(w); *info = 0; *iterationscount = 0; *nmv = 0; _linlsqrstate_init(&state, _state); _linlsqrreport_init(&lsqrrep, _state); _sparsematrix_init(&spg, _state); _sparsematrix_init(&sps, _state); ae_vector_init(&nearcenterscnt, 0, DT_INT, _state); ae_vector_init(&nearpointscnt, 0, DT_INT, _state); ae_vector_init(&skipnearpointscnt, 0, DT_INT, _state); ae_vector_init(&farpointscnt, 0, DT_INT, _state); ae_vector_init(&pointstags, 0, DT_INT, _state); ae_vector_init(¢erstags, 0, DT_INT, _state); ae_matrix_init(&nearpoints, 0, 0, DT_REAL, _state); ae_matrix_init(&nearcenters, 0, 0, DT_REAL, _state); ae_matrix_init(&farpoints, 0, 0, DT_REAL, _state); ae_vector_init(&xcx, 0, DT_REAL, _state); ae_vector_init(&tmpy, 0, DT_REAL, _state); ae_vector_init(&tc, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_vector_init(&tmp1, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); ae_matrix_init(&xx, 0, 0, DT_REAL, _state); ae_matrix_init(&cx, 0, 0, DT_REAL, _state); /* * Handle special cases: NC=0 */ if( nc==0 ) { *info = 1; *iterationscount = 0; *nmv = 0; ae_frame_leave(_state); return; } /* * Prepare for general case, NC>0 */ ae_vector_set_length(&xcx, rbf_mxnx, _state); ae_vector_set_length(&pointstags, n, _state); ae_vector_set_length(¢erstags, nc, _state); *info = -1; *iterationscount = 0; *nmv = 0; /* * This block prepares quantities used to compute approximate cardinal basis functions (ACBFs): * * NearCentersCnt[] - array[NC], whose elements store number of near centers used to build ACBF * * NearPointsCnt[] - array[NC], number of near points used to build ACBF * * FarPointsCnt[] - array[NC], number of far points (ones where ACBF is nonzero) * * MaxNearCentersCnt - max(NearCentersCnt) * * MaxNearPointsCnt - max(NearPointsCnt) * * SumNearCentersCnt - sum(NearCentersCnt) * * SumNearPointsCnt - sum(NearPointsCnt) * * SumFarPointsCnt - sum(FarPointsCnt) */ ae_vector_set_length(&nearcenterscnt, nc, _state); ae_vector_set_length(&nearpointscnt, nc, _state); ae_vector_set_length(&skipnearpointscnt, nc, _state); ae_vector_set_length(&farpointscnt, nc, _state); maxnearcenterscnt = 0; maxnearpointscnt = 0; maxfarpointscnt = 0; sumnearcenterscnt = 0; sumnearpointscnt = 0; sumfarpointscnt = 0; for(i=0; i<=nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; } /* * Determine number of near centers and maximum radius of near centers */ nearcenterscnt.ptr.p_int[i] = kdtreequeryrnn(centerstree, &xcx, r->ptr.p_double[i]*rbf_rbfnearradius, ae_true, _state); kdtreequeryresultstags(centerstree, ¢erstags, _state); maxrad = (double)(0); for(j=0; j<=nearcenterscnt.ptr.p_int[i]-1; j++) { maxrad = ae_maxreal(maxrad, ae_fabs(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); } /* * Determine number of near points (ones which used to build ACBF) * and skipped points (the most near points which are NOT used to build ACBF * and are NOT included in the near points count */ skipnearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, 0.1*r->ptr.p_double[i], ae_true, _state); nearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, (r->ptr.p_double[i]+maxrad)*rbf_rbfnearradius, ae_true, _state)-skipnearpointscnt.ptr.p_int[i]; ae_assert(nearpointscnt.ptr.p_int[i]>=0, "BuildRBFModelLSQR: internal error", _state); /* * Determine number of far points */ farpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, ae_maxreal(r->ptr.p_double[i]*rbf_rbfnearradius+maxrad*rbf_rbffarradius, r->ptr.p_double[i]*rbf_rbffarradius, _state), ae_true, _state); /* * calculate sum and max, make some basic checks */ ae_assert(nearcenterscnt.ptr.p_int[i]>0, "BuildRBFModelLSQR: internal error", _state); maxnearcenterscnt = ae_maxint(maxnearcenterscnt, nearcenterscnt.ptr.p_int[i], _state); maxnearpointscnt = ae_maxint(maxnearpointscnt, nearpointscnt.ptr.p_int[i], _state); maxfarpointscnt = ae_maxint(maxfarpointscnt, farpointscnt.ptr.p_int[i], _state); sumnearcenterscnt = sumnearcenterscnt+nearcenterscnt.ptr.p_int[i]; sumnearpointscnt = sumnearpointscnt+nearpointscnt.ptr.p_int[i]; sumfarpointscnt = sumfarpointscnt+farpointscnt.ptr.p_int[i]; } *snnz = sumnearcenterscnt; *gnnz = sumfarpointscnt; ae_assert(maxnearcenterscnt>0, "BuildRBFModelLSQR: internal error", _state); /* * Allocate temporaries. * * NOTE: we want to avoid allocation of zero-size arrays, so we * use max(desired_size,1) instead of desired_size when performing * memory allocation. */ ae_matrix_set_length(&a, maxnearpointscnt+maxnearcenterscnt, maxnearcenterscnt, _state); ae_vector_set_length(&tmpy, maxnearpointscnt+maxnearcenterscnt, _state); ae_vector_set_length(&g, maxnearcenterscnt, _state); ae_vector_set_length(&c, maxnearcenterscnt, _state); ae_matrix_set_length(&nearcenters, maxnearcenterscnt, rbf_mxnx, _state); ae_matrix_set_length(&nearpoints, ae_maxint(maxnearpointscnt, 1, _state), rbf_mxnx, _state); ae_matrix_set_length(&farpoints, ae_maxint(maxfarpointscnt, 1, _state), rbf_mxnx, _state); /* * fill matrix SpG */ sparsecreate(n, nc, *gnnz, &spg, _state); sparsecreate(nc, nc, *snnz, &sps, _state); for(i=0; i<=nc-1; i++) { centerscnt = nearcenterscnt.ptr.p_int[i]; /* * main center */ for(j=0; j<=rbf_mxnx-1; j++) { xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; } /* * center's tree */ tmpi = kdtreequeryknn(centerstree, &xcx, centerscnt, ae_true, _state); ae_assert(tmpi==centerscnt, "BuildRBFModelLSQR: internal error", _state); kdtreequeryresultsx(centerstree, &cx, _state); kdtreequeryresultstags(centerstree, ¢erstags, _state); /* * point's tree */ mrad = (double)(0); for(j=0; j<=centerscnt-1; j++) { mrad = ae_maxreal(mrad, r->ptr.p_double[centerstags.ptr.p_int[j]], _state); } /* * we need to be sure that 'CTree' contains * at least one side center */ sparseset(&sps, i, i, (double)(1), _state); c.ptr.p_double[0] = 1.0; for(j=1; j<=centerscnt-1; j++) { c.ptr.p_double[j] = 0.0; } if( centerscnt>1&&nearpointscnt.ptr.p_int[i]>0 ) { /* * first KDTree request for points */ pointscnt = nearpointscnt.ptr.p_int[i]; tmpi = kdtreequeryknn(pointstree, &xcx, skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], ae_true, _state); ae_assert(tmpi==skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], "BuildRBFModelLSQR: internal error", _state); kdtreequeryresultsx(pointstree, &xx, _state); sind = skipnearpointscnt.ptr.p_int[i]; for(j=0; j<=pointscnt-1; j++) { vx = xx.ptr.pp_double[sind+j][0]; vy = xx.ptr.pp_double[sind+j][1]; vz = xx.ptr.pp_double[sind+j][2]; for(k=0; k<=centerscnt-1; k++) { vr = 0.0; vv = vx-cx.ptr.pp_double[k][0]; vr = vr+vv*vv; vv = vy-cx.ptr.pp_double[k][1]; vr = vr+vv*vv; vv = vz-cx.ptr.pp_double[k][2]; vr = vr+vv*vv; vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; a.ptr.pp_double[j][k] = ae_exp(-vr/(vv*vv), _state); } } for(j=0; j<=centerscnt-1; j++) { g.ptr.p_double[j] = ae_exp(-(ae_sqr(xcx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xcx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xcx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); } /* * calculate the problem */ gnorm2 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); for(j=0; j<=pointscnt-1; j++) { vv = ae_v_dotproduct(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); vv = vv/gnorm2; tmpy.ptr.p_double[j] = -vv; ae_v_subd(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); } for(j=pointscnt; j<=pointscnt+centerscnt-1; j++) { for(k=0; k<=centerscnt-1; k++) { a.ptr.pp_double[j][k] = 0.0; } a.ptr.pp_double[j][j-pointscnt] = 1.0E-6; tmpy.ptr.p_double[j] = 0.0; } fblssolvels(&a, &tmpy, pointscnt+centerscnt, centerscnt, &tmp0, &tmp1, &tmp2, _state); ae_v_move(&c.ptr.p_double[0], 1, &tmpy.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); vv = vv/gnorm2; ae_v_subd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); vv = 1/gnorm2; ae_v_addd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); for(j=0; j<=centerscnt-1; j++) { sparseset(&sps, i, centerstags.ptr.p_int[j], c.ptr.p_double[j], _state); } } /* * second KDTree request for points */ pointscnt = farpointscnt.ptr.p_int[i]; tmpi = kdtreequeryknn(pointstree, &xcx, pointscnt, ae_true, _state); ae_assert(tmpi==pointscnt, "BuildRBFModelLSQR: internal error", _state); kdtreequeryresultsx(pointstree, &xx, _state); kdtreequeryresultstags(pointstree, &pointstags, _state); /* *fill SpG matrix */ for(j=0; j<=pointscnt-1; j++) { fx = (double)(0); vx = xx.ptr.pp_double[j][0]; vy = xx.ptr.pp_double[j][1]; vz = xx.ptr.pp_double[j][2]; for(k=0; k<=centerscnt-1; k++) { vr = 0.0; vv = vx-cx.ptr.pp_double[k][0]; vr = vr+vv*vv; vv = vy-cx.ptr.pp_double[k][1]; vr = vr+vv*vv; vv = vz-cx.ptr.pp_double[k][2]; vr = vr+vv*vv; vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; vv = vv*vv; fx = fx+c.ptr.p_double[k]*ae_exp(-vr/vv, _state); } sparseset(&spg, pointstags.ptr.p_int[j], i, fx, _state); } } sparseconverttocrs(&spg, _state); sparseconverttocrs(&sps, _state); /* * solve by LSQR method */ ae_vector_set_length(&tmpy, n, _state); ae_vector_set_length(&tc, nc, _state); ae_matrix_set_length(w, nc, ny, _state); linlsqrcreate(n, nc, &state, _state); linlsqrsetcond(&state, epsort, epserr, maxits, _state); for(i=0; i<=ny-1; i++) { for(j=0; j<=n-1; j++) { tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; } linlsqrsolvesparse(&state, &spg, &tmpy, _state); linlsqrresults(&state, &c, &lsqrrep, _state); if( lsqrrep.terminationtype<=0 ) { *info = -4; ae_frame_leave(_state); return; } sparsemtv(&sps, &c, &tc, _state); for(j=0; j<=nc-1; j++) { w->ptr.pp_double[j][i] = tc.ptr.p_double[j]; } *iterationscount = *iterationscount+lsqrrep.iterationscount; *nmv = *nmv+lsqrrep.nmv; } *info = 1; ae_frame_leave(_state); } static void rbf_buildrbfmlayersmodellsqr(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, /* Real */ ae_matrix* xc, double rval, /* Real */ ae_vector* r, ae_int_t n, ae_int_t* nc, ae_int_t ny, ae_int_t nlayers, kdtree* centerstree, double epsort, double epserr, ae_int_t maxits, double lambdav, ae_int_t* annz, /* Real */ ae_matrix* w, ae_int_t* info, ae_int_t* iterationscount, ae_int_t* nmv, ae_state *_state) { ae_frame _frame_block; linlsqrstate state; linlsqrreport lsqrrep; sparsematrix spa; double anorm; ae_vector omega; ae_vector xx; ae_vector tmpy; ae_matrix cx; double yval; ae_int_t nec; ae_vector centerstags; ae_int_t layer; ae_int_t i; ae_int_t j; ae_int_t k; double v; double rmaxbefore; double rmaxafter; ae_frame_make(_state, &_frame_block); ae_matrix_clear(xc); ae_vector_clear(r); *nc = 0; *annz = 0; ae_matrix_clear(w); *info = 0; *iterationscount = 0; *nmv = 0; _linlsqrstate_init(&state, _state); _linlsqrreport_init(&lsqrrep, _state); _sparsematrix_init(&spa, _state); ae_vector_init(&omega, 0, DT_REAL, _state); ae_vector_init(&xx, 0, DT_REAL, _state); ae_vector_init(&tmpy, 0, DT_REAL, _state); ae_matrix_init(&cx, 0, 0, DT_REAL, _state); ae_vector_init(¢erstags, 0, DT_INT, _state); ae_assert(nlayers>=0, "BuildRBFMLayersModelLSQR: invalid argument(NLayers<0)", _state); ae_assert(n>=0, "BuildRBFMLayersModelLSQR: invalid argument(N<0)", _state); ae_assert(rbf_mxnx>0&&rbf_mxnx<=3, "BuildRBFMLayersModelLSQR: internal error(invalid global const MxNX: either MxNX<=0 or MxNX>3)", _state); *annz = 0; if( n==0||nlayers==0 ) { *info = 1; *iterationscount = 0; *nmv = 0; ae_frame_leave(_state); return; } *nc = n*nlayers; ae_vector_set_length(&xx, rbf_mxnx, _state); ae_vector_set_length(¢erstags, n, _state); ae_matrix_set_length(xc, *nc, rbf_mxnx, _state); ae_vector_set_length(r, *nc, _state); for(i=0; i<=*nc-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xc->ptr.pp_double[i][j] = x->ptr.pp_double[i%n][j]; } } for(i=0; i<=*nc-1; i++) { r->ptr.p_double[i] = rval/ae_pow((double)(2), (double)(i/n), _state); } for(i=0; i<=n-1; i++) { centerstags.ptr.p_int[i] = i; } kdtreebuildtagged(xc, ¢erstags, n, rbf_mxnx, 0, 2, centerstree, _state); ae_vector_set_length(&omega, n, _state); ae_vector_set_length(&tmpy, n, _state); ae_matrix_set_length(w, *nc, ny, _state); *info = -1; *iterationscount = 0; *nmv = 0; linlsqrcreate(n, n, &state, _state); linlsqrsetcond(&state, epsort, epserr, maxits, _state); linlsqrsetlambdai(&state, 1.0E-6, _state); /* * calculate number of non-zero elements for sparse matrix */ for(i=0; i<=n-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; } *annz = *annz+kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[0]*rbf_rbfmlradius, ae_true, _state); } for(layer=0; layer<=nlayers-1; layer++) { /* * Fill sparse matrix, calculate norm(A) */ anorm = 0.0; sparsecreate(n, n, *annz, &spa, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=rbf_mxnx-1; j++) { xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; } nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbf_rbfmlradius, ae_true, _state); kdtreequeryresultsx(centerstree, &cx, _state); kdtreequeryresultstags(centerstree, ¢erstags, _state); for(j=0; j<=nec-1; j++) { v = ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[j]], _state), _state); sparseset(&spa, i, centerstags.ptr.p_int[j], v, _state); anorm = anorm+ae_sqr(v, _state); } } anorm = ae_sqrt(anorm, _state); sparseconverttocrs(&spa, _state); /* * Calculate maximum residual before adding new layer. * This value is not used by algorithm, the only purpose is to make debugging easier. */ rmaxbefore = 0.0; for(j=0; j<=n-1; j++) { for(i=0; i<=ny-1; i++) { rmaxbefore = ae_maxreal(rmaxbefore, ae_fabs(y->ptr.pp_double[j][i], _state), _state); } } /* * Process NY dimensions of the target function */ for(i=0; i<=ny-1; i++) { for(j=0; j<=n-1; j++) { tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; } /* * calculate Omega for current layer */ linlsqrsetlambdai(&state, lambdav*anorm/n, _state); linlsqrsolvesparse(&state, &spa, &tmpy, _state); linlsqrresults(&state, &omega, &lsqrrep, _state); if( lsqrrep.terminationtype<=0 ) { *info = -4; ae_frame_leave(_state); return; } /* * calculate error for current layer */ for(j=0; j<=n-1; j++) { yval = (double)(0); for(k=0; k<=rbf_mxnx-1; k++) { xx.ptr.p_double[k] = x->ptr.pp_double[j][k]; } nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbf_rbffarradius, ae_true, _state); kdtreequeryresultsx(centerstree, &cx, _state); kdtreequeryresultstags(centerstree, ¢erstags, _state); for(k=0; k<=nec-1; k++) { yval = yval+omega.ptr.p_double[centerstags.ptr.p_int[k]]*ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[k][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[k][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[k][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[k]], _state), _state); } y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-yval; } /* * write Omega in out parameter W */ for(j=0; j<=n-1; j++) { w->ptr.pp_double[layer*n+j][i] = omega.ptr.p_double[j]; } *iterationscount = *iterationscount+lsqrrep.iterationscount; *nmv = *nmv+lsqrrep.nmv; } /* * Calculate maximum residual before adding new layer. * This value is not used by algorithm, the only purpose is to make debugging easier. */ rmaxafter = 0.0; for(j=0; j<=n-1; j++) { for(i=0; i<=ny-1; i++) { rmaxafter = ae_maxreal(rmaxafter, ae_fabs(y->ptr.pp_double[j][i], _state), _state); } } } *info = 1; ae_frame_leave(_state); } void _rbfmodel_init(void* _p, ae_state *_state) { rbfmodel *p = (rbfmodel*)_p; ae_touch_ptr((void*)p); _kdtree_init(&p->tree, _state); ae_matrix_init(&p->xc, 0, 0, DT_REAL, _state); ae_matrix_init(&p->wr, 0, 0, DT_REAL, _state); ae_matrix_init(&p->v, 0, 0, DT_REAL, _state); ae_matrix_init(&p->x, 0, 0, DT_REAL, _state); ae_matrix_init(&p->y, 0, 0, DT_REAL, _state); ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state); ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state); ae_vector_init(&p->calcbuftags, 0, DT_INT, _state); } void _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state) { rbfmodel *dst = (rbfmodel*)_dst; rbfmodel *src = (rbfmodel*)_src; dst->ny = src->ny; dst->nx = src->nx; dst->nc = src->nc; dst->nl = src->nl; _kdtree_init_copy(&dst->tree, &src->tree, _state); ae_matrix_init_copy(&dst->xc, &src->xc, _state); ae_matrix_init_copy(&dst->wr, &src->wr, _state); dst->rmax = src->rmax; ae_matrix_init_copy(&dst->v, &src->v, _state); dst->gridtype = src->gridtype; dst->fixrad = src->fixrad; dst->lambdav = src->lambdav; dst->radvalue = src->radvalue; dst->radzvalue = src->radzvalue; dst->nlayers = src->nlayers; dst->aterm = src->aterm; dst->algorithmtype = src->algorithmtype; dst->epsort = src->epsort; dst->epserr = src->epserr; dst->maxits = src->maxits; dst->h = src->h; dst->n = src->n; ae_matrix_init_copy(&dst->x, &src->x, _state); ae_matrix_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state); ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state); ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state); } void _rbfmodel_clear(void* _p) { rbfmodel *p = (rbfmodel*)_p; ae_touch_ptr((void*)p); _kdtree_clear(&p->tree); ae_matrix_clear(&p->xc); ae_matrix_clear(&p->wr); ae_matrix_clear(&p->v); ae_matrix_clear(&p->x); ae_matrix_clear(&p->y); ae_vector_clear(&p->calcbufxcx); ae_matrix_clear(&p->calcbufx); ae_vector_clear(&p->calcbuftags); } void _rbfmodel_destroy(void* _p) { rbfmodel *p = (rbfmodel*)_p; ae_touch_ptr((void*)p); _kdtree_destroy(&p->tree); ae_matrix_destroy(&p->xc); ae_matrix_destroy(&p->wr); ae_matrix_destroy(&p->v); ae_matrix_destroy(&p->x); ae_matrix_destroy(&p->y); ae_vector_destroy(&p->calcbufxcx); ae_matrix_destroy(&p->calcbufx); ae_vector_destroy(&p->calcbuftags); } void _rbfreport_init(void* _p, ae_state *_state) { rbfreport *p = (rbfreport*)_p; ae_touch_ptr((void*)p); } void _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state) { rbfreport *dst = (rbfreport*)_dst; rbfreport *src = (rbfreport*)_src; dst->arows = src->arows; dst->acols = src->acols; dst->annz = src->annz; dst->iterationscount = src->iterationscount; dst->nmv = src->nmv; dst->terminationtype = src->terminationtype; } void _rbfreport_clear(void* _p) { rbfreport *p = (rbfreport*)_p; ae_touch_ptr((void*)p); } void _rbfreport_destroy(void* _p) { rbfreport *p = (rbfreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X. Input parameters: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y- point Result: S(x,y) -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ double spline2dcalc(spline2dinterpolant* c, double x, double y, ae_state *_state) { double v; double vx; double vy; double vxy; double result; ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalc: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalc: X or Y contains NaN or Infinite value", _state); if( c->d!=1 ) { result = (double)(0); return result; } spline2ddiff(c, x, y, &v, &vx, &vy, &vxy, _state); result = v; return result; } /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X and its derivatives. Input parameters: C - spline interpolant. X, Y- point Output parameters: F - S(x,y) FX - dS(x,y)/dX FY - dS(x,y)/dY FXY - d2S(x,y)/dXdY -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2ddiff(spline2dinterpolant* c, double x, double y, double* f, double* fx, double* fy, double* fxy, ae_state *_state) { double t; double dt; double u; double du; ae_int_t ix; ae_int_t iy; ae_int_t l; ae_int_t r; ae_int_t h; ae_int_t s1; ae_int_t s2; ae_int_t s3; ae_int_t s4; ae_int_t sfx; ae_int_t sfy; ae_int_t sfxy; double y1; double y2; double y3; double y4; double v; double t0; double t1; double t2; double t3; double u0; double u1; double u2; double u3; *f = 0; *fx = 0; *fy = 0; *fxy = 0; ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state); /* * Prepare F, dF/dX, dF/dY, d2F/dXdY */ *f = (double)(0); *fx = (double)(0); *fy = (double)(0); *fxy = (double)(0); if( c->d!=1 ) { return; } /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = c->n-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) { r = h; } else { l = h; } } t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); ix = l; /* * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) */ l = 0; r = c->m-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) { r = h; } else { l = h; } } u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); iy = l; /* * Bilinear interpolation */ if( c->stype==-1 ) { y1 = c->f.ptr.p_double[c->n*iy+ix]; y2 = c->f.ptr.p_double[c->n*iy+(ix+1)]; y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)]; y4 = c->f.ptr.p_double[c->n*(iy+1)+ix]; *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4; *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt; *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du; *fxy = (y1-y2+y3-y4)*du*dt; return; } /* * Bicubic interpolation */ if( c->stype==-3 ) { /* * Prepare info */ t0 = (double)(1); t1 = t; t2 = ae_sqr(t, _state); t3 = t*t2; u0 = (double)(1); u1 = u; u2 = ae_sqr(u, _state); u3 = u*u2; sfx = c->n*c->m; sfy = 2*c->n*c->m; sfxy = 3*c->n*c->m; s1 = c->n*iy+ix; s2 = c->n*iy+(ix+1); s3 = c->n*(iy+1)+(ix+1); s4 = c->n*(iy+1)+ix; /* * Calculate */ v = c->f.ptr.p_double[s1]; *f = *f+v*t0*u0; v = c->f.ptr.p_double[sfy+s1]/du; *f = *f+v*t0*u1; *fy = *fy+v*t0*u0*du; v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; *f = *f+v*t0*u2; *fy = *fy+2*v*t0*u1*du; v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; *f = *f+v*t0*u3; *fy = *fy+3*v*t0*u2*du; v = c->f.ptr.p_double[sfx+s1]/dt; *f = *f+v*t1*u0; *fx = *fx+v*t0*u0*dt; v = c->f.ptr.p_double[sfxy+s1]/(dt*du); *f = *f+v*t1*u1; *fx = *fx+v*t0*u1*dt; *fy = *fy+v*t1*u0*du; *fxy = *fxy+v*t0*u0*dt*du; v = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t1*u2; *fx = *fx+v*t0*u2*dt; *fy = *fy+2*v*t1*u1*du; *fxy = *fxy+2*v*t0*u1*dt*du; v = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t1*u3; *fx = *fx+v*t0*u3*dt; *fy = *fy+3*v*t1*u2*du; *fxy = *fxy+3*v*t0*u2*dt*du; v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; *f = *f+v*t2*u0; *fx = *fx+2*v*t1*u0*dt; v = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); *f = *f+v*t2*u1; *fx = *fx+2*v*t1*u1*dt; *fy = *fy+v*t2*u0*du; *fxy = *fxy+2*v*t1*u0*dt*du; v = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t2*u2; *fx = *fx+2*v*t1*u2*dt; *fy = *fy+2*v*t2*u1*du; *fxy = *fxy+4*v*t1*u1*dt*du; v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t2*u3; *fx = *fx+2*v*t1*u3*dt; *fy = *fy+3*v*t2*u2*du; *fxy = *fxy+6*v*t1*u2*dt*du; v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; *f = *f+v*t3*u0; *fx = *fx+3*v*t2*u0*dt; v = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); *f = *f+v*t3*u1; *fx = *fx+3*v*t2*u1*dt; *fy = *fy+v*t3*u0*du; *fxy = *fxy+3*v*t2*u0*dt*du; v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t3*u2; *fx = *fx+3*v*t2*u2*dt; *fy = *fy+2*v*t3*u1*du; *fxy = *fxy+6*v*t2*u1*dt*du; v = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); *f = *f+v*t3*u3; *fx = *fx+3*v*t2*u3*dt; *fy = *fy+3*v*t3*u2*du; *fxy = *fxy+9*v*t2*u2*dt*du; return; } } /************************************************************************* This subroutine performs linear transformation of the spline argument. Input parameters: C - spline interpolant AX, BX - transformation coefficients: x = A*t + B AY, BY - transformation coefficients: y = A*u + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransxy(spline2dinterpolant* c, double ax, double bx, double ay, double by, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector f; ae_vector v; ae_int_t i; ae_int_t j; ae_int_t k; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransXY: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(ax, _state), "Spline2DLinTransXY: AX is infinite or NaN", _state); ae_assert(ae_isfinite(bx, _state), "Spline2DLinTransXY: BX is infinite or NaN", _state); ae_assert(ae_isfinite(ay, _state), "Spline2DLinTransXY: AY is infinite or NaN", _state); ae_assert(ae_isfinite(by, _state), "Spline2DLinTransXY: BY is infinite or NaN", _state); ae_vector_set_length(&x, c->n, _state); ae_vector_set_length(&y, c->m, _state); ae_vector_set_length(&f, c->m*c->n*c->d, _state); for(j=0; j<=c->n-1; j++) { x.ptr.p_double[j] = c->x.ptr.p_double[j]; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = c->y.ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { for(k=0; k<=c->d-1; k++) { f.ptr.p_double[c->d*(i*c->n+j)+k] = c->f.ptr.p_double[c->d*(i*c->n+j)+k]; } } } /* * Handle different combinations of AX/AY */ if( ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) ) { for(i=0; i<=c->m-1; i++) { spline2dcalcvbuf(c, bx, y.ptr.p_double[i], &v, _state); y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; for(j=0; j<=c->n-1; j++) { for(k=0; k<=c->d-1; k++) { f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; } } } } if( ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) ) { for(j=0; j<=c->n-1; j++) { spline2dcalcvbuf(c, x.ptr.p_double[j], by, &v, _state); x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; for(i=0; i<=c->m-1; i++) { for(k=0; k<=c->d-1; k++) { f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; } } } } if( ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) ) { for(j=0; j<=c->n-1; j++) { x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; } } if( ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) ) { spline2dcalcvbuf(c, bx, by, &v, _state); for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { for(k=0; k<=c->d-1; k++) { f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; } } } } /* * Rebuild spline */ if( c->stype==-3 ) { spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state); } if( c->stype==-1 ) { spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine performs linear transformation of the spline. Input parameters: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B Output parameters: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransf(spline2dinterpolant* c, double a, double b, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector f; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransF: incorrect C (incorrect parameter C.SType)", _state); ae_vector_set_length(&x, c->n, _state); ae_vector_set_length(&y, c->m, _state); ae_vector_set_length(&f, c->m*c->n*c->d, _state); for(j=0; j<=c->n-1; j++) { x.ptr.p_double[j] = c->x.ptr.p_double[j]; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = c->y.ptr.p_double[i]; } for(i=0; i<=c->m*c->n*c->d-1; i++) { f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; } if( c->stype==-3 ) { spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state); } if( c->stype==-1 ) { spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine makes the copy of the spline model. Input parameters: C - spline interpolant Output parameters: CC - spline copy -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dcopy(spline2dinterpolant* c, spline2dinterpolant* cc, ae_state *_state) { ae_int_t tblsize; _spline2dinterpolant_clear(cc); ae_assert(c->k==1||c->k==3, "Spline2DCopy: incorrect C (incorrect parameter C.K)", _state); cc->k = c->k; cc->n = c->n; cc->m = c->m; cc->d = c->d; cc->stype = c->stype; tblsize = -1; if( c->stype==-3 ) { tblsize = 4*c->n*c->m*c->d; } if( c->stype==-1 ) { tblsize = c->n*c->m*c->d; } ae_assert(tblsize>0, "Spline2DCopy: internal error", _state); ae_vector_set_length(&cc->x, cc->n, _state); ae_vector_set_length(&cc->y, cc->m, _state); ae_vector_set_length(&cc->f, tblsize, _state); ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); } /************************************************************************* Bicubic spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 15 May, 2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebicubic(/* Real */ ae_matrix* a, ae_int_t oldheight, ae_int_t oldwidth, /* Real */ ae_matrix* b, ae_int_t newheight, ae_int_t newwidth, ae_state *_state) { ae_frame _frame_block; ae_matrix buf; ae_vector x; ae_vector y; spline1dinterpolant c; ae_int_t mw; ae_int_t mh; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_clear(b); ae_matrix_init(&buf, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _spline1dinterpolant_init(&c, _state); ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); /* * Prepare */ mw = ae_maxint(oldwidth, newwidth, _state); mh = ae_maxint(oldheight, newheight, _state); ae_matrix_set_length(b, newheight, newwidth, _state); ae_matrix_set_length(&buf, oldheight, newwidth, _state); ae_vector_set_length(&x, ae_maxint(mw, mh, _state), _state); ae_vector_set_length(&y, ae_maxint(mw, mh, _state), _state); /* * Horizontal interpolation */ for(i=0; i<=oldheight-1; i++) { /* * Fill X, Y */ for(j=0; j<=oldwidth-1; j++) { x.ptr.p_double[j] = (double)j/(double)(oldwidth-1); y.ptr.p_double[j] = a->ptr.pp_double[i][j]; } /* * Interpolate and place result into temporary matrix */ spline1dbuildcubic(&x, &y, oldwidth, 0, 0.0, 0, 0.0, &c, _state); for(j=0; j<=newwidth-1; j++) { buf.ptr.pp_double[i][j] = spline1dcalc(&c, (double)j/(double)(newwidth-1), _state); } } /* * Vertical interpolation */ for(j=0; j<=newwidth-1; j++) { /* * Fill X, Y */ for(i=0; i<=oldheight-1; i++) { x.ptr.p_double[i] = (double)i/(double)(oldheight-1); y.ptr.p_double[i] = buf.ptr.pp_double[i][j]; } /* * Interpolate and place result into B */ spline1dbuildcubic(&x, &y, oldheight, 0, 0.0, 0, 0.0, &c, _state); for(i=0; i<=newheight-1; i++) { b->ptr.pp_double[i][j] = spline1dcalc(&c, (double)i/(double)(newheight-1), _state); } } ae_frame_leave(_state); } /************************************************************************* Bilinear spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 09.07.2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebilinear(/* Real */ ae_matrix* a, ae_int_t oldheight, ae_int_t oldwidth, /* Real */ ae_matrix* b, ae_int_t newheight, ae_int_t newwidth, ae_state *_state) { ae_int_t l; ae_int_t c; double t; double u; ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); ae_matrix_set_length(b, newheight, newwidth, _state); for(i=0; i<=newheight-1; i++) { for(j=0; j<=newwidth-1; j++) { l = i*(oldheight-1)/(newheight-1); if( l==oldheight-1 ) { l = oldheight-2; } u = (double)i/(double)(newheight-1)*(oldheight-1)-l; c = j*(oldwidth-1)/(newwidth-1); if( c==oldwidth-1 ) { c = oldwidth-2; } t = (double)(j*(oldwidth-1))/(double)(newwidth-1)-c; b->ptr.pp_double[i][j] = (1-t)*(1-u)*a->ptr.pp_double[l][c]+t*(1-u)*a->ptr.pp_double[l][c+1]+t*u*a->ptr.pp_double[l+1][c+1]+(1-t)*u*a->ptr.pp_double[l+1][c]; } } } /************************************************************************* This subroutine builds bilinear vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinearv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* f, ae_int_t d, spline2dinterpolant* c, ae_state *_state) { double t; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t i0; _spline2dinterpolant_clear(c); ae_assert(n>=2, "Spline2DBuildBilinearV: N is less then 2", _state); ae_assert(m>=2, "Spline2DBuildBilinearV: M is less then 2", _state); ae_assert(d>=1, "Spline2DBuildBilinearV: invalid argument D (D<1)", _state); ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearV: length of X or Y is too short (Length(X/Y)cnt>=k, "Spline2DBuildBilinearV: length of F is too short (Length(F)k = 1; c->n = n; c->m = m; c->d = d; c->stype = -1; ae_vector_set_length(&c->x, c->n, _state); ae_vector_set_length(&c->y, c->m, _state); ae_vector_set_length(&c->f, k, _state); for(i=0; i<=c->n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { c->y.ptr.p_double[i] = y->ptr.p_double[i]; } for(i=0; i<=k-1; i++) { c->f.ptr.p_double[i] = f->ptr.p_double[i]; } /* * Sort points */ for(j=0; j<=c->n-1; j++) { k = j; for(i=j+1; i<=c->n-1; i++) { if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) { k = i; } } if( k!=j ) { for(i=0; i<=c->m-1; i++) { for(i0=0; i0<=c->d-1; i0++) { t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0]; c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t; } } t = c->x.ptr.p_double[j]; c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; c->x.ptr.p_double[k] = t; } } for(i=0; i<=c->m-1; i++) { k = i; for(j=i+1; j<=c->m-1; j++) { if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) { k = j; } } if( k!=i ) { for(j=0; j<=c->n-1; j++) { for(i0=0; i0<=c->d-1; i0++) { t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0]; c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t; } } t = c->y.ptr.p_double[i]; c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; c->y.ptr.p_double[k] = t; } } } /************************************************************************* This subroutine builds bicubic vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubicv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* f, ae_int_t d, spline2dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector _f; ae_matrix tf; ae_matrix dx; ae_matrix dy; ae_matrix dxy; double t; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t di; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_f, f, _state); f = &_f; _spline2dinterpolant_clear(c); ae_matrix_init(&tf, 0, 0, DT_REAL, _state); ae_matrix_init(&dx, 0, 0, DT_REAL, _state); ae_matrix_init(&dy, 0, 0, DT_REAL, _state); ae_matrix_init(&dxy, 0, 0, DT_REAL, _state); ae_assert(n>=2, "Spline2DBuildBicubicV: N is less than 2", _state); ae_assert(m>=2, "Spline2DBuildBicubicV: M is less than 2", _state); ae_assert(d>=1, "Spline2DBuildBicubicV: invalid argument D (D<1)", _state); ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicV: length of X or Y is too short (Length(X/Y)cnt>=k, "Spline2DBuildBicubicV: length of F is too short (Length(F)k = 3; c->d = d; c->n = n; c->m = m; c->stype = -3; k = 4*k; ae_vector_set_length(&c->x, c->n, _state); ae_vector_set_length(&c->y, c->m, _state); ae_vector_set_length(&c->f, k, _state); ae_matrix_set_length(&tf, c->m, c->n, _state); for(i=0; i<=c->n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { c->y.ptr.p_double[i] = y->ptr.p_double[i]; } /* * Sort points */ for(j=0; j<=c->n-1; j++) { k = j; for(i=j+1; i<=c->n-1; i++) { if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) { k = i; } } if( k!=j ) { for(i=0; i<=c->m-1; i++) { for(di=0; di<=c->d-1; di++) { t = f->ptr.p_double[c->d*(i*c->n+j)+di]; f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(i*c->n+k)+di]; f->ptr.p_double[c->d*(i*c->n+k)+di] = t; } } t = c->x.ptr.p_double[j]; c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; c->x.ptr.p_double[k] = t; } } for(i=0; i<=c->m-1; i++) { k = i; for(j=i+1; j<=c->m-1; j++) { if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) { k = j; } } if( k!=i ) { for(j=0; j<=c->n-1; j++) { for(di=0; di<=c->d-1; di++) { t = f->ptr.p_double[c->d*(i*c->n+j)+di]; f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(k*c->n+j)+di]; f->ptr.p_double[c->d*(k*c->n+j)+di] = t; } } t = c->y.ptr.p_double[i]; c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; c->y.ptr.p_double[k] = t; } } for(di=0; di<=c->d-1; di++) { for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { tf.ptr.pp_double[i][j] = f->ptr.p_double[c->d*(i*c->n+j)+di]; } } spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state); for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { k = c->d*(i*c->n+j)+di; c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j]; c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j]; c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j]; c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j]; } } } ae_frame_leave(_state); } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcvbuf(spline2dinterpolant* c, double x, double y, /* Real */ ae_vector* f, ae_state *_state) { double t; double dt; double u; double du; ae_int_t ix; ae_int_t iy; ae_int_t l; ae_int_t r; ae_int_t h; ae_int_t s1; ae_int_t s2; ae_int_t s3; ae_int_t s4; ae_int_t sfx; ae_int_t sfy; ae_int_t sfxy; double y1; double y2; double y3; double y4; double v; double t0; double t1; double t2; double t3; double u0; double u1; double u2; double u3; ae_int_t i; ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVBuf: either X=NaN/Infinite or Y=NaN/Infinite", _state); rvectorsetlengthatleast(f, c->d, _state); /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = c->n-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) { r = h; } else { l = h; } } t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); ix = l; /* * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) */ l = 0; r = c->m-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) { r = h; } else { l = h; } } u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); iy = l; /* * Bilinear interpolation */ if( c->stype==-1 ) { for(i=0; i<=c->d-1; i++) { y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i]; y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i]; y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i]; y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i]; f->ptr.p_double[i] = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4; } return; } /* * Bicubic interpolation */ if( c->stype==-3 ) { /* * Prepare info */ t0 = (double)(1); t1 = t; t2 = ae_sqr(t, _state); t3 = t*t2; u0 = (double)(1); u1 = u; u2 = ae_sqr(u, _state); u3 = u*u2; sfx = c->n*c->m*c->d; sfy = 2*c->n*c->m*c->d; sfxy = 3*c->n*c->m*c->d; for(i=0; i<=c->d-1; i++) { /* * Prepare F, dF/dX, dF/dY, d2F/dXdY */ f->ptr.p_double[i] = (double)(0); s1 = c->d*(c->n*iy+ix)+i; s2 = c->d*(c->n*iy+(ix+1))+i; s3 = c->d*(c->n*(iy+1)+(ix+1))+i; s4 = c->d*(c->n*(iy+1)+ix)+i; /* * Calculate */ v = c->f.ptr.p_double[s1]; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u0; v = c->f.ptr.p_double[sfy+s1]/du; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u1; v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u2; v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u3; v = c->f.ptr.p_double[sfx+s1]/dt; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u0; v = c->f.ptr.p_double[sfxy+s1]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u1; v = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u2; v = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u3; v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u0; v = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u1; v = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u2; v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u3; v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u0; v = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u1; v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u2; v = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u3; } return; } } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcv(spline2dinterpolant* c, double x, double y, /* Real */ ae_vector* f, ae_state *_state) { ae_vector_clear(f); ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcV: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcV: either X=NaN/Infinite or Y=NaN/Infinite", _state); ae_vector_set_length(f, c->d, _state); spline2dcalcvbuf(c, x, y, f, _state); } /************************************************************************* This subroutine unpacks two-dimensional spline into the coefficients table Input parameters: C - spline interpolant. Result: M, N- grid size (x-axis and y-axis) D - number of components Tbl - coefficients table, unpacked format, D - components: [0..(N-1)*(M-1)*D-1, 0..19]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index): K := T + I*D + J*D*(N-1) K-th row stores decomposition for T-th component of the vector-valued function Tbl[K,0] = X[i] Tbl[K,1] = X[i+1] Tbl[K,2] = Y[j] Tbl[K,3] = Y[j+1] Tbl[K,4] = C00 Tbl[K,5] = C01 Tbl[K,6] = C02 Tbl[K,7] = C03 Tbl[K,8] = C10 Tbl[K,9] = C11 ... Tbl[K,19] = C33 On each grid square spline is equals to: S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) t = x-x[j] u = y-y[i] -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dunpackv(spline2dinterpolant* c, ae_int_t* m, ae_int_t* n, ae_int_t* d, /* Real */ ae_matrix* tbl, ae_state *_state) { ae_int_t k; ae_int_t p; ae_int_t ci; ae_int_t cj; ae_int_t s1; ae_int_t s2; ae_int_t s3; ae_int_t s4; ae_int_t sfx; ae_int_t sfy; ae_int_t sfxy; double y1; double y2; double y3; double y4; double dt; double du; ae_int_t i; ae_int_t j; ae_int_t k0; *m = 0; *n = 0; *d = 0; ae_matrix_clear(tbl); ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpackV: incorrect C (incorrect parameter C.SType)", _state); *n = c->n; *m = c->m; *d = c->d; ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*d), 20, _state); sfx = *n*(*m)*(*d); sfy = 2*(*n)*(*m)*(*d); sfxy = 3*(*n)*(*m)*(*d); for(i=0; i<=*m-2; i++) { for(j=0; j<=*n-2; j++) { for(k=0; k<=*d-1; k++) { p = *d*(i*(*n-1)+j)+k; tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); /* * Bilinear interpolation */ if( c->stype==-1 ) { for(k0=4; k0<=19; k0++) { tbl->ptr.pp_double[p][k0] = (double)(0); } y1 = c->f.ptr.p_double[*d*(*n*i+j)+k]; y2 = c->f.ptr.p_double[*d*(*n*i+(j+1))+k]; y3 = c->f.ptr.p_double[*d*(*n*(i+1)+(j+1))+k]; y4 = c->f.ptr.p_double[*d*(*n*(i+1)+j)+k]; tbl->ptr.pp_double[p][4] = y1; tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; } /* * Bicubic interpolation */ if( c->stype==-3 ) { s1 = *d*(*n*i+j)+k; s2 = *d*(*n*i+(j+1))+k; s3 = *d*(*n*(i+1)+(j+1))+k; s4 = *d*(*n*(i+1)+j)+k; tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); } /* * Rescale Cij */ for(ci=0; ci<=3; ci++) { for(cj=0; cj<=3; cj++) { tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state); } } } } } } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBilinearV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinear(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_matrix* f, ae_int_t m, ae_int_t n, spline2dinterpolant* c, ae_state *_state) { double t; ae_int_t i; ae_int_t j; ae_int_t k; _spline2dinterpolant_clear(c); ae_assert(n>=2, "Spline2DBuildBilinear: N<2", _state); ae_assert(m>=2, "Spline2DBuildBilinear: M<2", _state); ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinear: length of X or Y is too short (Length(X/Y)rows>=m&&f->cols>=n, "Spline2DBuildBilinear: size of F is too small (rows(F)k = 1; c->n = n; c->m = m; c->d = 1; c->stype = -1; ae_vector_set_length(&c->x, c->n, _state); ae_vector_set_length(&c->y, c->m, _state); ae_vector_set_length(&c->f, c->n*c->m, _state); for(i=0; i<=c->n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { c->y.ptr.p_double[i] = y->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { c->f.ptr.p_double[i*c->n+j] = f->ptr.pp_double[i][j]; } } /* * Sort points */ for(j=0; j<=c->n-1; j++) { k = j; for(i=j+1; i<=c->n-1; i++) { if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) { k = i; } } if( k!=j ) { for(i=0; i<=c->m-1; i++) { t = c->f.ptr.p_double[i*c->n+j]; c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[i*c->n+k]; c->f.ptr.p_double[i*c->n+k] = t; } t = c->x.ptr.p_double[j]; c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; c->x.ptr.p_double[k] = t; } } for(i=0; i<=c->m-1; i++) { k = i; for(j=i+1; j<=c->m-1; j++) { if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) { k = j; } } if( k!=i ) { for(j=0; j<=c->n-1; j++) { t = c->f.ptr.p_double[i*c->n+j]; c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[k*c->n+j]; c->f.ptr.p_double[k*c->n+j] = t; } t = c->y.ptr.p_double[i]; c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; c->y.ptr.p_double[k] = t; } } } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBicubicV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_matrix* f, ae_int_t m, ae_int_t n, spline2dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_matrix _f; ae_int_t sfx; ae_int_t sfy; ae_int_t sfxy; ae_matrix dx; ae_matrix dy; ae_matrix dxy; double t; ae_int_t i; ae_int_t j; ae_int_t k; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_f, f, _state); f = &_f; _spline2dinterpolant_clear(c); ae_matrix_init(&dx, 0, 0, DT_REAL, _state); ae_matrix_init(&dy, 0, 0, DT_REAL, _state); ae_matrix_init(&dxy, 0, 0, DT_REAL, _state); ae_assert(n>=2, "Spline2DBuildBicubicSpline: N<2", _state); ae_assert(m>=2, "Spline2DBuildBicubicSpline: M<2", _state); ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubic: length of X or Y is too short (Length(X/Y)rows>=m&&f->cols>=n, "Spline2DBuildBicubic: size of F is too small (rows(F)k = 3; c->d = 1; c->n = n; c->m = m; c->stype = -3; sfx = c->n*c->m; sfy = 2*c->n*c->m; sfxy = 3*c->n*c->m; ae_vector_set_length(&c->x, c->n, _state); ae_vector_set_length(&c->y, c->m, _state); ae_vector_set_length(&c->f, 4*c->n*c->m, _state); for(i=0; i<=c->n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { c->y.ptr.p_double[i] = y->ptr.p_double[i]; } /* * Sort points */ for(j=0; j<=c->n-1; j++) { k = j; for(i=j+1; i<=c->n-1; i++) { if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) { k = i; } } if( k!=j ) { for(i=0; i<=c->m-1; i++) { t = f->ptr.pp_double[i][j]; f->ptr.pp_double[i][j] = f->ptr.pp_double[i][k]; f->ptr.pp_double[i][k] = t; } t = c->x.ptr.p_double[j]; c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; c->x.ptr.p_double[k] = t; } } for(i=0; i<=c->m-1; i++) { k = i; for(j=i+1; j<=c->m-1; j++) { if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) { k = j; } } if( k!=i ) { for(j=0; j<=c->n-1; j++) { t = f->ptr.pp_double[i][j]; f->ptr.pp_double[i][j] = f->ptr.pp_double[k][j]; f->ptr.pp_double[k][j] = t; } t = c->y.ptr.p_double[i]; c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; c->y.ptr.p_double[k] = t; } } spline2d_bicubiccalcderivatives(f, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state); for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->n-1; j++) { k = i*c->n+j; c->f.ptr.p_double[k] = f->ptr.pp_double[i][j]; c->f.ptr.p_double[sfx+k] = dx.ptr.pp_double[i][j]; c->f.ptr.p_double[sfy+k] = dy.ptr.pp_double[i][j]; c->f.ptr.p_double[sfxy+k] = dxy.ptr.pp_double[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DUnpackV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dunpack(spline2dinterpolant* c, ae_int_t* m, ae_int_t* n, /* Real */ ae_matrix* tbl, ae_state *_state) { ae_int_t k; ae_int_t p; ae_int_t ci; ae_int_t cj; ae_int_t s1; ae_int_t s2; ae_int_t s3; ae_int_t s4; ae_int_t sfx; ae_int_t sfy; ae_int_t sfxy; double y1; double y2; double y3; double y4; double dt; double du; ae_int_t i; ae_int_t j; *m = 0; *n = 0; ae_matrix_clear(tbl); ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpack: incorrect C (incorrect parameter C.SType)", _state); if( c->d!=1 ) { *n = 0; *m = 0; return; } *n = c->n; *m = c->m; ae_matrix_set_length(tbl, (*n-1)*(*m-1), 20, _state); sfx = *n*(*m); sfy = 2*(*n)*(*m); sfxy = 3*(*n)*(*m); /* * Fill */ for(i=0; i<=*m-2; i++) { for(j=0; j<=*n-2; j++) { p = i*(*n-1)+j; tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); /* * Bilinear interpolation */ if( c->stype==-1 ) { for(k=4; k<=19; k++) { tbl->ptr.pp_double[p][k] = (double)(0); } y1 = c->f.ptr.p_double[*n*i+j]; y2 = c->f.ptr.p_double[*n*i+(j+1)]; y3 = c->f.ptr.p_double[*n*(i+1)+(j+1)]; y4 = c->f.ptr.p_double[*n*(i+1)+j]; tbl->ptr.pp_double[p][4] = y1; tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; } /* * Bicubic interpolation */ if( c->stype==-3 ) { s1 = *n*i+j; s2 = *n*i+(j+1); s3 = *n*(i+1)+(j+1); s4 = *n*(i+1)+j; tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); } /* * Rescale Cij */ for(ci=0; ci<=3; ci++) { for(cj=0; cj<=3; cj++) { tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state); } } } } } /************************************************************************* Internal subroutine. Calculation of the first derivatives and the cross-derivative. *************************************************************************/ static void spline2d_bicubiccalcderivatives(/* Real */ ae_matrix* a, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* dx, /* Real */ ae_matrix* dy, /* Real */ ae_matrix* dxy, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector xt; ae_vector ft; double s; double ds; double d2s; spline1dinterpolant c; ae_frame_make(_state, &_frame_block); ae_matrix_clear(dx); ae_matrix_clear(dy); ae_matrix_clear(dxy); ae_vector_init(&xt, 0, DT_REAL, _state); ae_vector_init(&ft, 0, DT_REAL, _state); _spline1dinterpolant_init(&c, _state); ae_matrix_set_length(dx, m, n, _state); ae_matrix_set_length(dy, m, n, _state); ae_matrix_set_length(dxy, m, n, _state); /* * dF/dX */ ae_vector_set_length(&xt, n, _state); ae_vector_set_length(&ft, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { xt.ptr.p_double[j] = x->ptr.p_double[j]; ft.ptr.p_double[j] = a->ptr.pp_double[i][j]; } spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state); for(j=0; j<=n-1; j++) { spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state); dx->ptr.pp_double[i][j] = ds; } } /* * dF/dY */ ae_vector_set_length(&xt, m, _state); ae_vector_set_length(&ft, m, _state); for(j=0; j<=n-1; j++) { for(i=0; i<=m-1; i++) { xt.ptr.p_double[i] = y->ptr.p_double[i]; ft.ptr.p_double[i] = a->ptr.pp_double[i][j]; } spline1dbuildcubic(&xt, &ft, m, 0, 0.0, 0, 0.0, &c, _state); for(i=0; i<=m-1; i++) { spline1ddiff(&c, y->ptr.p_double[i], &s, &ds, &d2s, _state); dy->ptr.pp_double[i][j] = ds; } } /* * d2F/dXdY */ ae_vector_set_length(&xt, n, _state); ae_vector_set_length(&ft, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { xt.ptr.p_double[j] = x->ptr.p_double[j]; ft.ptr.p_double[j] = dy->ptr.pp_double[i][j]; } spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state); for(j=0; j<=n-1; j++) { spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state); dxy->ptr.pp_double[i][j] = ds; } } ae_frame_leave(_state); } void _spline2dinterpolant_init(void* _p, ae_state *_state) { spline2dinterpolant *p = (spline2dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_vector_init(&p->f, 0, DT_REAL, _state); } void _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state) { spline2dinterpolant *dst = (spline2dinterpolant*)_dst; spline2dinterpolant *src = (spline2dinterpolant*)_src; dst->k = src->k; dst->stype = src->stype; dst->n = src->n; dst->m = src->m; dst->d = src->d; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->f, &src->f, _state); } void _spline2dinterpolant_clear(void* _p) { spline2dinterpolant *p = (spline2dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->y); ae_vector_clear(&p->f); } void _spline2dinterpolant_destroy(void* _p) { spline2dinterpolant *p = (spline2dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->y); ae_vector_destroy(&p->f); } /************************************************************************* This subroutine calculates the value of the trilinear or tricubic spline at the given point (X,Y,Z). INPUT PARAMETERS: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y, Z - point Result: S(x,y,z) -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ double spline3dcalc(spline3dinterpolant* c, double x, double y, double z, ae_state *_state) { double v; double vx; double vy; double vxy; double result; ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalc: incorrect C (incorrect parameter C.SType)", _state); ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalc: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); if( c->d!=1 ) { result = (double)(0); return result; } spline3d_spline3ddiff(c, x, y, z, &v, &vx, &vy, &vxy, _state); result = v; return result; } /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant AX, BX - transformation coefficients: x = A*u + B AY, BY - transformation coefficients: y = A*v + B AZ, BZ - transformation coefficients: z = A*w + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransxyz(spline3dinterpolant* c, double ax, double bx, double ay, double by, double az, double bz, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector z; ae_vector f; ae_vector v; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t di; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransXYZ: incorrect C (incorrect parameter C.SType)", _state); ae_vector_set_length(&x, c->n, _state); ae_vector_set_length(&y, c->m, _state); ae_vector_set_length(&z, c->l, _state); ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); for(j=0; j<=c->n-1; j++) { x.ptr.p_double[j] = c->x.ptr.p_double[j]; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = c->y.ptr.p_double[i]; } for(i=0; i<=c->l-1; i++) { z.ptr.p_double[i] = c->z.ptr.p_double[i]; } /* * Handle different combinations of zero/nonzero AX/AY/AZ */ if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) { ae_v_move(&f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,c->m*c->n*c->l*c->d-1)); } if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) { for(i=0; i<=c->m-1; i++) { for(j=0; j<=c->l-1; j++) { spline3dcalcv(c, bx, y.ptr.p_double[i], z.ptr.p_double[j], &v, _state); for(k=0; k<=c->n-1; k++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*j+i)+k)+di] = v.ptr.p_double[di]; } } } } ax = (double)(1); bx = (double)(0); } if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) { for(i=0; i<=c->n-1; i++) { for(j=0; j<=c->l-1; j++) { spline3dcalcv(c, x.ptr.p_double[i], by, z.ptr.p_double[j], &v, _state); for(k=0; k<=c->m-1; k++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*j+k)+i)+di] = v.ptr.p_double[di]; } } } } ay = (double)(1); by = (double)(0); } if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) { for(i=0; i<=c->n-1; i++) { for(j=0; j<=c->m-1; j++) { spline3dcalcv(c, x.ptr.p_double[i], y.ptr.p_double[j], bz, &v, _state); for(k=0; k<=c->l-1; k++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; } } } } az = (double)(1); bz = (double)(0); } if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) { for(i=0; i<=c->l-1; i++) { spline3dcalcv(c, bx, by, z.ptr.p_double[i], &v, _state); for(k=0; k<=c->m-1; k++) { for(j=0; j<=c->n-1; j++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*i+k)+j)+di] = v.ptr.p_double[di]; } } } } ax = (double)(1); bx = (double)(0); ay = (double)(1); by = (double)(0); } if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) { for(i=0; i<=c->m-1; i++) { spline3dcalcv(c, bx, y.ptr.p_double[i], bz, &v, _state); for(k=0; k<=c->l-1; k++) { for(j=0; j<=c->n-1; j++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*k+i)+j)+di] = v.ptr.p_double[di]; } } } } ax = (double)(1); bx = (double)(0); az = (double)(1); bz = (double)(0); } if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) { for(i=0; i<=c->n-1; i++) { spline3dcalcv(c, x.ptr.p_double[i], by, bz, &v, _state); for(k=0; k<=c->l-1; k++) { for(j=0; j<=c->m-1; j++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; } } } } ay = (double)(1); by = (double)(0); az = (double)(1); bz = (double)(0); } if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) { spline3dcalcv(c, bx, by, bz, &v, _state); for(k=0; k<=c->l-1; k++) { for(j=0; j<=c->m-1; j++) { for(i=0; i<=c->n-1; i++) { for(di=0; di<=c->d-1; di++) { f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; } } } } ax = (double)(1); bx = (double)(0); ay = (double)(1); by = (double)(0); az = (double)(1); bz = (double)(0); } /* * General case: AX<>0, AY<>0, AZ<>0 * Unpack, scale and pack again. */ for(i=0; i<=c->n-1; i++) { x.ptr.p_double[i] = (x.ptr.p_double[i]-bx)/ax; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; } for(i=0; i<=c->l-1; i++) { z.ptr.p_double[i] = (z.ptr.p_double[i]-bz)/az; } if( c->stype==-1 ) { spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransf(spline3dinterpolant* c, double a, double b, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector z; ae_vector f; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransF: incorrect C (incorrect parameter C.SType)", _state); ae_vector_set_length(&x, c->n, _state); ae_vector_set_length(&y, c->m, _state); ae_vector_set_length(&z, c->l, _state); ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); for(j=0; j<=c->n-1; j++) { x.ptr.p_double[j] = c->x.ptr.p_double[j]; } for(i=0; i<=c->m-1; i++) { y.ptr.p_double[i] = c->y.ptr.p_double[i]; } for(i=0; i<=c->l-1; i++) { z.ptr.p_double[i] = c->z.ptr.p_double[i]; } for(i=0; i<=c->m*c->n*c->l*c->d-1; i++) { f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; } if( c->stype==-1 ) { spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); } ae_frame_leave(_state); } /************************************************************************* This subroutine makes the copy of the spline model. INPUT PARAMETERS: C - spline interpolant OUTPUT PARAMETERS: CC - spline copy -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcopy(spline3dinterpolant* c, spline3dinterpolant* cc, ae_state *_state) { ae_int_t tblsize; _spline3dinterpolant_clear(cc); ae_assert(c->k==1||c->k==3, "Spline3DCopy: incorrect C (incorrect parameter C.K)", _state); cc->k = c->k; cc->n = c->n; cc->m = c->m; cc->l = c->l; cc->d = c->d; tblsize = c->n*c->m*c->l*c->d; cc->stype = c->stype; ae_vector_set_length(&cc->x, cc->n, _state); ae_vector_set_length(&cc->y, cc->m, _state); ae_vector_set_length(&cc->z, cc->l, _state); ae_vector_set_length(&cc->f, tblsize, _state); ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); ae_v_move(&cc->z.ptr.p_double[0], 1, &c->z.ptr.p_double[0], 1, ae_v_len(0,cc->l-1)); ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); } /************************************************************************* Trilinear spline resampling INPUT PARAMETERS: A - array[0..OldXCount*OldYCount*OldZCount-1], function values at the old grid, : A[0] x=0,y=0,z=0 A[1] x=1,y=0,z=0 A[..] ... A[..] x=oldxcount-1,y=0,z=0 A[..] x=0,y=1,z=0 A[..] ... ... OldZCount - old Z-count, OldZCount>1 OldYCount - old Y-count, OldYCount>1 OldXCount - old X-count, OldXCount>1 NewZCount - new Z-count, NewZCount>1 NewYCount - new Y-count, NewYCount>1 NewXCount - new X-count, NewXCount>1 OUTPUT PARAMETERS: B - array[0..NewXCount*NewYCount*NewZCount-1], function values at the new grid: B[0] x=0,y=0,z=0 B[1] x=1,y=0,z=0 B[..] ... B[..] x=newxcount-1,y=0,z=0 B[..] x=0,y=1,z=0 B[..] ... ... -- ALGLIB routine -- 26.04.2012 Copyright by Bochkanov Sergey *************************************************************************/ void spline3dresampletrilinear(/* Real */ ae_vector* a, ae_int_t oldzcount, ae_int_t oldycount, ae_int_t oldxcount, ae_int_t newzcount, ae_int_t newycount, ae_int_t newxcount, /* Real */ ae_vector* b, ae_state *_state) { double xd; double yd; double zd; double c0; double c1; double c2; double c3; ae_int_t ix; ae_int_t iy; ae_int_t iz; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector_clear(b); ae_assert((oldycount>1&&oldzcount>1)&&oldxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); ae_assert((newycount>1&&newzcount>1)&&newxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); ae_assert(a->cnt>=oldycount*oldzcount*oldxcount, "Spline3DResampleTrilinear: length/width/height less than 1", _state); ae_vector_set_length(b, newxcount*newycount*newzcount, _state); for(i=0; i<=newxcount-1; i++) { for(j=0; j<=newycount-1; j++) { for(k=0; k<=newzcount-1; k++) { ix = i*(oldxcount-1)/(newxcount-1); if( ix==oldxcount-1 ) { ix = oldxcount-2; } xd = (double)(i*(oldxcount-1))/(double)(newxcount-1)-ix; iy = j*(oldycount-1)/(newycount-1); if( iy==oldycount-1 ) { iy = oldycount-2; } yd = (double)(j*(oldycount-1))/(double)(newycount-1)-iy; iz = k*(oldzcount-1)/(newzcount-1); if( iz==oldzcount-1 ) { iz = oldzcount-2; } zd = (double)(k*(oldzcount-1))/(double)(newzcount-1)-iz; c0 = a->ptr.p_double[oldxcount*(oldycount*iz+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+iy)+(ix+1)]*xd; c1 = a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+(ix+1)]*xd; c2 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+(ix+1)]*xd; c3 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+(ix+1)]*xd; c0 = c0*(1-yd)+c1*yd; c1 = c2*(1-yd)+c3*yd; b->ptr.p_double[newxcount*(newycount*k+j)+i] = c0*(1-zd)+c1*zd; } } } } /************************************************************************* This subroutine builds trilinear vector-valued spline. INPUT PARAMETERS: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] Z - spline applicates, array[0..L-1] F - function values, array[0..M*N*L*D-1]: * first D elements store D values at (X[0],Y[0],Z[0]) * next D elements store D values at (X[1],Y[0],Z[0]) * next D elements store D values at (X[2],Y[0],Z[0]) * ... * next D elements store D values at (X[0],Y[1],Z[0]) * next D elements store D values at (X[1],Y[1],Z[0]) * next D elements store D values at (X[2],Y[1],Z[0]) * ... * next D elements store D values at (X[0],Y[0],Z[1]) * next D elements store D values at (X[1],Y[0],Z[1]) * next D elements store D values at (X[2],Y[0],Z[1]) * ... * general form - D function values at (X[i],Y[j]) are stored at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. M,N, L - grid size, M>=2, N>=2, L>=2 D - vector dimension, D>=1 OUTPUT PARAMETERS: C - spline interpolant -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dbuildtrilinearv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* z, ae_int_t l, /* Real */ ae_vector* f, ae_int_t d, spline3dinterpolant* c, ae_state *_state) { double t; ae_int_t tblsize; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t i0; ae_int_t j0; _spline3dinterpolant_clear(c); ae_assert(m>=2, "Spline3DBuildTrilinearV: M<2", _state); ae_assert(n>=2, "Spline3DBuildTrilinearV: N<2", _state); ae_assert(l>=2, "Spline3DBuildTrilinearV: L<2", _state); ae_assert(d>=1, "Spline3DBuildTrilinearV: D<1", _state); ae_assert((x->cnt>=n&&y->cnt>=m)&&z->cnt>=l, "Spline3DBuildTrilinearV: length of X, Y or Z is too short (Length(X/Y/Z)cnt>=tblsize, "Spline3DBuildTrilinearV: length of F is too short (Length(F)k = 1; c->n = n; c->m = m; c->l = l; c->d = d; c->stype = -1; ae_vector_set_length(&c->x, c->n, _state); ae_vector_set_length(&c->y, c->m, _state); ae_vector_set_length(&c->z, c->l, _state); ae_vector_set_length(&c->f, tblsize, _state); for(i=0; i<=c->n-1; i++) { c->x.ptr.p_double[i] = x->ptr.p_double[i]; } for(i=0; i<=c->m-1; i++) { c->y.ptr.p_double[i] = y->ptr.p_double[i]; } for(i=0; i<=c->l-1; i++) { c->z.ptr.p_double[i] = z->ptr.p_double[i]; } for(i=0; i<=tblsize-1; i++) { c->f.ptr.p_double[i] = f->ptr.p_double[i]; } /* * Sort points: * * sort x; * * sort y; * * sort z. */ for(j=0; j<=c->n-1; j++) { k = j; for(i=j+1; i<=c->n-1; i++) { if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) { k = i; } } if( k!=j ) { for(i=0; i<=c->m-1; i++) { for(j0=0; j0<=c->l-1; j0++) { for(i0=0; i0<=c->d-1; i0++) { t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0] = t; } } } t = c->x.ptr.p_double[j]; c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; c->x.ptr.p_double[k] = t; } } for(i=0; i<=c->m-1; i++) { k = i; for(j=i+1; j<=c->m-1; j++) { if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) { k = j; } } if( k!=i ) { for(j=0; j<=c->n-1; j++) { for(j0=0; j0<=c->l-1; j0++) { for(i0=0; i0<=c->d-1; i0++) { t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0] = t; } } } t = c->y.ptr.p_double[i]; c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; c->y.ptr.p_double[k] = t; } } for(k=0; k<=c->l-1; k++) { i = k; for(j=i+1; j<=c->l-1; j++) { if( ae_fp_less(c->z.ptr.p_double[j],c->z.ptr.p_double[i]) ) { i = j; } } if( i!=k ) { for(j=0; j<=c->m-1; j++) { for(j0=0; j0<=c->n-1; j0++) { for(i0=0; i0<=c->d-1; i0++) { t = c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0]; c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0] = t; } } } t = c->z.ptr.p_double[k]; c->z.ptr.p_double[k] = c->z.ptr.p_double[i]; c->z.ptr.p_double[i] = t; } } } /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcvbuf(spline3dinterpolant* c, double x, double y, double z, /* Real */ ae_vector* f, ae_state *_state) { double xd; double yd; double zd; double c0; double c1; double c2; double c3; ae_int_t ix; ae_int_t iy; ae_int_t iz; ae_int_t l; ae_int_t r; ae_int_t h; ae_int_t i; ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcVBuf: X, Y or Z contains NaN/Infinite", _state); rvectorsetlengthatleast(f, c->d, _state); /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = c->n-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) { r = h; } else { l = h; } } ix = l; /* * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) */ l = 0; r = c->m-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) { r = h; } else { l = h; } } iy = l; /* * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) */ l = 0; r = c->l-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) { r = h; } else { l = h; } } iz = l; xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); for(i=0; i<=c->d-1; i++) { /* * Trilinear interpolation */ if( c->stype==-1 ) { c0 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+(ix+1))+i]*xd; c1 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+(ix+1))+i]*xd; c2 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+(ix+1))+i]*xd; c3 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+(ix+1))+i]*xd; c0 = c0*(1-yd)+c1*yd; c1 = c2*(1-yd)+c3*yd; f->ptr.p_double[i] = c0*(1-zd)+c1*zd; } } } /************************************************************************* This subroutine calculates trilinear or tricubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcv(spline3dinterpolant* c, double x, double y, double z, /* Real */ ae_vector* f, ae_state *_state) { ae_vector_clear(f); ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcV: incorrect C (incorrect parameter C.SType)", _state); ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcV: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); ae_vector_set_length(f, c->d, _state); spline3dcalcvbuf(c, x, y, z, f, _state); } /************************************************************************* This subroutine unpacks tri-dimensional spline into the coefficients table INPUT PARAMETERS: C - spline interpolant. Result: N - grid size (X) M - grid size (Y) L - grid size (Z) D - number of components SType- spline type. Currently, only one spline type is supported: trilinear spline, as indicated by SType=1. Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index), K=0..L-2 (z index): Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), Q-th row stores decomposition for T-th component of the vector-valued function Tbl[Q,0] = X[i] Tbl[Q,1] = X[i+1] Tbl[Q,2] = Y[j] Tbl[Q,3] = Y[j+1] Tbl[Q,4] = Z[k] Tbl[Q,5] = Z[k+1] Tbl[Q,6] = C000 Tbl[Q,7] = C100 Tbl[Q,8] = C010 Tbl[Q,9] = C110 Tbl[Q,10]= C001 Tbl[Q,11]= C101 Tbl[Q,12]= C011 Tbl[Q,13]= C111 On each grid square spline is equals to: S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) t = x-x[j] u = y-y[i] v = z-z[k] NOTE: format of Tbl is given for SType=1. Future versions of ALGLIB can use different formats for different values of SType. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dunpackv(spline3dinterpolant* c, ae_int_t* n, ae_int_t* m, ae_int_t* l, ae_int_t* d, ae_int_t* stype, /* Real */ ae_matrix* tbl, ae_state *_state) { ae_int_t p; ae_int_t ci; ae_int_t cj; ae_int_t ck; double du; double dv; double dw; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t di; ae_int_t i0; *n = 0; *m = 0; *l = 0; *d = 0; *stype = 0; ae_matrix_clear(tbl); ae_assert(c->stype==-1, "Spline3DUnpackV: incorrect C (incorrect parameter C.SType)", _state); *n = c->n; *m = c->m; *l = c->l; *d = c->d; *stype = ae_iabs(c->stype, _state); ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*l-1)*(*d), 14, _state); /* * Fill */ for(i=0; i<=*n-2; i++) { for(j=0; j<=*m-2; j++) { for(k=0; k<=*l-2; k++) { for(di=0; di<=*d-1; di++) { p = *d*((*n-1)*((*m-1)*k+j)+i)+di; tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[i]; tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[i+1]; tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[j]; tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[j+1]; tbl->ptr.pp_double[p][4] = c->z.ptr.p_double[k]; tbl->ptr.pp_double[p][5] = c->z.ptr.p_double[k+1]; du = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); dv = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); dw = 1/(tbl->ptr.pp_double[p][5]-tbl->ptr.pp_double[p][4]); /* * Trilinear interpolation */ if( c->stype==-1 ) { for(i0=6; i0<=13; i0++) { tbl->ptr.pp_double[p][i0] = (double)(0); } tbl->ptr.pp_double[p][6+2*(2*0+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*0+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*0+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*0+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*1+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*1+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*1+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; tbl->ptr.pp_double[p][6+2*(2*1+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; } /* * Rescale Cij */ for(ci=0; ci<=1; ci++) { for(cj=0; cj<=1; cj++) { for(ck=0; ck<=1; ck++) { tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci] = tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci]*ae_pow(du, (double)(ci), _state)*ae_pow(dv, (double)(cj), _state)*ae_pow(dw, (double)(ck), _state); } } } } } } } } /************************************************************************* This subroutine calculates the value of the trilinear(or tricubic;possible will be later) spline at the given point X(and its derivatives; possible will be later). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point OUTPUT PARAMETERS: F - S(x,y,z) FX - dS(x,y,z)/dX FY - dS(x,y,z)/dY FXY - d2S(x,y,z)/dXdY -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ static void spline3d_spline3ddiff(spline3dinterpolant* c, double x, double y, double z, double* f, double* fx, double* fy, double* fxy, ae_state *_state) { double xd; double yd; double zd; double c0; double c1; double c2; double c3; ae_int_t ix; ae_int_t iy; ae_int_t iz; ae_int_t l; ae_int_t r; ae_int_t h; *f = 0; *fx = 0; *fy = 0; *fxy = 0; ae_assert(c->stype==-1||c->stype==-3, "Spline3DDiff: incorrect C (incorrect parameter C.SType)", _state); ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline3DDiff: X or Y contains NaN or Infinite value", _state); /* * Prepare F, dF/dX, dF/dY, d2F/dXdY */ *f = (double)(0); *fx = (double)(0); *fy = (double)(0); *fxy = (double)(0); if( c->d!=1 ) { return; } /* * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) */ l = 0; r = c->n-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) { r = h; } else { l = h; } } ix = l; /* * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) */ l = 0; r = c->m-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) { r = h; } else { l = h; } } iy = l; /* * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) */ l = 0; r = c->l-1; while(l!=r-1) { h = (l+r)/2; if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) { r = h; } else { l = h; } } iz = l; xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); /* * Trilinear interpolation */ if( c->stype==-1 ) { c0 = c->f.ptr.p_double[c->n*(c->m*iz+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+iy)+(ix+1)]*xd; c1 = c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+(ix+1)]*xd; c2 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+(ix+1)]*xd; c3 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+(ix+1)]*xd; c0 = c0*(1-yd)+c1*yd; c1 = c2*(1-yd)+c3*yd; *f = c0*(1-zd)+c1*zd; } } void _spline3dinterpolant_init(void* _p, ae_state *_state) { spline3dinterpolant *p = (spline3dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_vector_init(&p->z, 0, DT_REAL, _state); ae_vector_init(&p->f, 0, DT_REAL, _state); } void _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state) { spline3dinterpolant *dst = (spline3dinterpolant*)_dst; spline3dinterpolant *src = (spline3dinterpolant*)_src; dst->k = src->k; dst->stype = src->stype; dst->n = src->n; dst->m = src->m; dst->l = src->l; dst->d = src->d; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->y, &src->y, _state); ae_vector_init_copy(&dst->z, &src->z, _state); ae_vector_init_copy(&dst->f, &src->f, _state); } void _spline3dinterpolant_clear(void* _p) { spline3dinterpolant *p = (spline3dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->y); ae_vector_clear(&p->z); ae_vector_clear(&p->f); } void _spline3dinterpolant_destroy(void* _p) { spline3dinterpolant *p = (spline3dinterpolant*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->y); ae_vector_destroy(&p->z); ae_vector_destroy(&p->f); } } qmapshack-1.10.0/3rdparty/alglib/src/statistics.cpp000755 001750 000144 00002253206 13015033052 023416 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "statistics.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Calculation of the distribution moments: mean, variance, skewness, kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X OUTPUT PARAMETERS Mean - mean. Variance- variance. Skewness- skewness (if variance<>0; zero otherwise). Kurtosis- kurtosis (if variance<>0; zero otherwise). NOTE: variance is calculated by dividing sum of squares by N-1, not N. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplemoments(const_cast(x.c_ptr()), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the distribution moments: mean, variance, skewness, kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X OUTPUT PARAMETERS Mean - mean. Variance- variance. Skewness- skewness (if variance<>0; zero otherwise). Kurtosis- kurtosis (if variance<>0; zero otherwise). NOTE: variance is calculated by dividing sum of squares by N-1, not N. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplemoments(const_cast(x.c_ptr()), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the mean. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Mean' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplemean(const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplemean(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the mean. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Mean' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplemean(const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplemean(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the variance. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Variance' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplevariance(const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplevariance(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the variance. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Variance' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplevariance(const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplevariance(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the skewness. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Skewness' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double sampleskewness(const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::sampleskewness(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the skewness. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Skewness' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double sampleskewness(const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::sampleskewness(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Kurtosis' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplekurtosis(const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplekurtosis(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of the kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Kurtosis' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplekurtosis(const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::samplekurtosis(const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* ADev Input parameters: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: ADev- ADev -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sampleadev(const_cast(x.c_ptr()), n, &adev, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* ADev Input parameters: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: ADev- ADev -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void sampleadev(const real_1d_array &x, double &adev) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::sampleadev(const_cast(x.c_ptr()), n, &adev, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Median calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: Median -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemedian(const real_1d_array &x, const ae_int_t n, double &median) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplemedian(const_cast(x.c_ptr()), n, &median, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Median calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: Median -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemedian(const real_1d_array &x, double &median) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplemedian(const_cast(x.c_ptr()), n, &median, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Percentile calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X P - percentile (0<=P<=1) Output parameters: V - percentile -- ALGLIB -- Copyright 01.03.2008 by Bochkanov Sergey *************************************************************************/ void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplepercentile(const_cast(x.c_ptr()), n, p, &v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Percentile calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X P - percentile (0<=P<=1) Output parameters: V - percentile -- ALGLIB -- Copyright 01.03.2008 by Bochkanov Sergey *************************************************************************/ void samplepercentile(const real_1d_array &x, const double p, double &v) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::samplepercentile(const_cast(x.c_ptr()), n, p, &v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 2-sample covariance Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: covariance (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cov2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 2-sample covariance Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: covariance (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double cov2(const real_1d_array &x, const real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'cov2': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::cov2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Pearson product-moment correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::pearsoncorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Pearson product-moment correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double pearsoncorr2(const real_1d_array &x, const real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'pearsoncorr2': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::pearsoncorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Spearman's rank correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spearmancorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Spearman's rank correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmancorr2(const real_1d_array &x, const real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=y.length())) throw ap_error("Error while calling 'spearmancorr2': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spearmancorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_covm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_pearsoncorrm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spearmancorrm(const real_2d_array &x, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m; n = x.rows(); m = x.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cross-covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cross-covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'covm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'covm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson product-moment cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'pearsoncorrm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'pearsoncorrm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'spearmancorrm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; ae_int_t m1; ae_int_t m2; if( (x.rows()!=y.rows())) throw ap_error("Error while calling 'spearmancorrm2': looks like one of arguments has wrong size"); n = x.rows(); m1 = x.cols(); m2 = y.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function replaces data in XY by their ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * ranking starts from 0, ends at NFeatures-1 * sum of within-row values is equal to (NFeatures-1)*NFeatures/2 SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function replaces data in XY by their ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * ranking starts from 0, ends at NFeatures-1 * sum of within-row values is equal to (NFeatures-1)*NFeatures/2 SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdata(real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; ae_int_t nfeatures; npoints = xy.rows(); nfeatures = xy.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rankdata(real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; ae_int_t nfeatures; npoints = xy.rows(); nfeatures = xy.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function replaces data in XY by their CENTERED ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * centered ranks are just usual ranks, but centered in such way that sum of within-row values is equal to 0.0. * centering is performed by subtracting mean from each row, i.e it changes mean value, but does NOT change higher moments SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function replaces data in XY by their CENTERED ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * centered ranks are just usual ranks, but centered in such way that sum of within-row values is equal to 0.0. * centering is performed by subtracting mean from each row, i.e it changes mean value, but does NOT change higher moments SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdatacentered(real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; ae_int_t nfeatures; npoints = xy.rows(); nfeatures = xy.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rankdatacentered(real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; ae_int_t nfeatures; npoints = xy.rows(); nfeatures = xy.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete function, we recommend to use PearsonCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::pearsoncorrelation(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete function, we recommend to use SpearmanCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::spearmanrankcorrelation(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Pearson's correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5 * normality of distributions of X and Y. Input parameters: R - Pearson's correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pearsoncorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Spearman's rank correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5. The test is non-parametric and doesn't require distributions X and Y to be normal. Input parameters: R - Spearman's rank correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spearmanrankcorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Jarque-Bera test This test checks hypotheses about the fact that a given sample X is a sample of normal random variable. Requirements: * the number of elements in the sample is not less than 5. Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Output parameters: P - p-value for the test Accuracy of the approximation used (5<=N<=1951): p-value relative error (5<=N<=1951) [1, 0.1] < 1% [0.1, 0.01] < 2% [0.01, 0.001] < 6% [0.001, 0] wasn't measured For N>1951 accuracy wasn't measured but it shouldn't be sharply different from table values. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::jarqueberatest(const_cast(x.c_ptr()), n, &p, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Mann-Whitney U-test This test checks hypotheses about whether X and Y are samples of two continuous distributions of the same shape and same median or whether their medians are different. The following tests are performed: * two-tailed test (null hypothesis - the medians are equal) * left-tailed test (null hypothesis - the median of the first sample is greater than or equal to the median of the second sample) * right-tailed test (null hypothesis - the median of the first sample is less than or equal to the median of the second sample). Requirements: * the samples are independent * X and Y are continuous distributions (or discrete distributions well- approximating continuous distributions) * distributions of X and Y have the same shape. The only possible difference is their position (i.e. the value of the median) * the number of elements in each sample is not less than 5 * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distributions to be normal. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. M>=5 Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with satisfactory accuracy in interval [0.0001, 1]. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. Relative precision of approximation of p-value: N M Max.err. Rms.err. 5..10 N..10 1.4e-02 6.0e-04 5..10 N..100 2.2e-02 5.3e-06 10..15 N..15 1.0e-02 3.2e-04 10..15 N..100 1.0e-02 2.2e-05 15..100 N..100 6.1e-03 2.7e-06 For N,M>100 accuracy checks weren't put into practice, but taking into account characteristics of asymptotic approximation used, precision should not be sharply different from the values for interval [5, 100]. NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, P's outside of this interval are enforced to these bounds. Say, you may quite often get P equal to exactly 0.25 or 0.0001. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mannwhitneyutest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Sign test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. While calculating p-values high-precision binomial distribution approximation is used, so significance levels have about 15 exact digits. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::onesamplesigntest(const_cast(x.c_ptr()), n, median, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* One-sample t-test This test checks three hypotheses about the mean of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the mean is equal to the given value) * left-tailed test (null hypothesis - the mean is greater than or equal to the given value) * right-tailed test (null hypothesis - the mean is less than or equal to the given value). The test is based on the assumption that a given sample has a normal distribution and an unknown dispersion. If the distribution sharply differs from normal, the test will work incorrectly. INPUT PARAMETERS: X - sample. Array whose index goes from 0 to N-1. N - size of sample, N>=0 Mean - assumed value of the mean. OUTPUT PARAMETERS: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0, all p-values are set to 1.0 * when variance of X[] is exactly zero, p-values are set to 1.0 or 0.0, depending on difference between sample mean and value of mean being tested. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::studentttest1(const_cast(x.c_ptr()), n, mean, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Two-sample pooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * dispersions are equal * samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has exactly zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::studentttest2(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Two-sample unpooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * samples are independent. Equality of variances is NOT required. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. * when only one sample has zero variance, test reduces to 1-sample version. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::unequalvariancettest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Two-sample F-test This test checks three hypotheses about dispersions of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the dispersions are equal) * left-tailed test (null hypothesis - the dispersion of the first sample is greater than or equal to the dispersion of the second sample). * right-tailed test (null hypothesis - the dispersion of the first sample is less than or equal to the dispersion of the second sample) The test is based on the following assumptions: * the given samples have normal distributions * the samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - sample size. Y - sample 2. Array whose index goes from 0 to M-1. M - sample size. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ftest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* One-sample chi-square test This test checks three hypotheses about the dispersion of the given sample The following tests are performed: * two-tailed test (null hypothesis - the dispersion equals the given number) * left-tailed test (null hypothesis - the dispersion is greater than or equal to the given number) * right-tailed test (null hypothesis - dispersion is less than or equal to the given number). Test is based on the following assumptions: * the given sample has a normal distribution. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Variance - dispersion value to compare with. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::onesamplevariancetest(const_cast(x.c_ptr()), n, variance, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Wilcoxon signed-rank test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). * the distribution should be continuous and symmetric relative to its median. * number of distinct values in the X array should be greater than 4 The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with two decimal places in interval [0.0001, 1]. "Two decimal places" does not sound very impressive, but in practice the relative error of less than 1% is enough to make a decision. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::wilcoxonsignedranktest(const_cast(x.c_ptr()), n, e, &bothtails, &lefttail, &righttail, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static void basestat_rankdatarec(/* Real */ ae_matrix* xy, ae_int_t i0, ae_int_t i1, ae_int_t nfeatures, ae_bool iscentered, ae_shared_pool* pool, ae_int_t basecasecost, ae_state *_state); static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, ae_int_t i0, ae_int_t i1, ae_int_t nfeatures, ae_bool iscentered, apbuffers* buf0, apbuffers* buf1, ae_state *_state); static double correlationtests_spearmantail5(double s, ae_state *_state); static double correlationtests_spearmantail6(double s, ae_state *_state); static double correlationtests_spearmantail7(double s, ae_state *_state); static double correlationtests_spearmantail8(double s, ae_state *_state); static double correlationtests_spearmantail9(double s, ae_state *_state); static double correlationtests_spearmantail(double t, ae_int_t n, ae_state *_state); static void jarquebera_jarqueberastatistic(/* Real */ ae_vector* x, ae_int_t n, double* s, ae_state *_state); static double jarquebera_jarqueberaapprox(ae_int_t n, double s, ae_state *_state); static double jarquebera_jbtbl5(double s, ae_state *_state); static double jarquebera_jbtbl6(double s, ae_state *_state); static double jarquebera_jbtbl7(double s, ae_state *_state); static double jarquebera_jbtbl8(double s, ae_state *_state); static double jarquebera_jbtbl9(double s, ae_state *_state); static double jarquebera_jbtbl10(double s, ae_state *_state); static double jarquebera_jbtbl11(double s, ae_state *_state); static double jarquebera_jbtbl12(double s, ae_state *_state); static double jarquebera_jbtbl13(double s, ae_state *_state); static double jarquebera_jbtbl14(double s, ae_state *_state); static double jarquebera_jbtbl15(double s, ae_state *_state); static double jarquebera_jbtbl16(double s, ae_state *_state); static double jarquebera_jbtbl17(double s, ae_state *_state); static double jarquebera_jbtbl18(double s, ae_state *_state); static double jarquebera_jbtbl19(double s, ae_state *_state); static double jarquebera_jbtbl20(double s, ae_state *_state); static double jarquebera_jbtbl30(double s, ae_state *_state); static double jarquebera_jbtbl50(double s, ae_state *_state); static double jarquebera_jbtbl65(double s, ae_state *_state); static double jarquebera_jbtbl100(double s, ae_state *_state); static double jarquebera_jbtbl130(double s, ae_state *_state); static double jarquebera_jbtbl200(double s, ae_state *_state); static double jarquebera_jbtbl301(double s, ae_state *_state); static double jarquebera_jbtbl501(double s, ae_state *_state); static double jarquebera_jbtbl701(double s, ae_state *_state); static double jarquebera_jbtbl1401(double s, ae_state *_state); static void jarquebera_jbcheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state); static void mannwhitneyu_ucheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state); static double mannwhitneyu_uninterpolate(double p1, double p2, double p3, ae_int_t n, ae_state *_state); static double mannwhitneyu_usigma000(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma075(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma150(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma225(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma300(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma333(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma367(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_usigma400(ae_int_t n1, ae_int_t n2, ae_state *_state); static double mannwhitneyu_utbln5n5(double s, ae_state *_state); static double mannwhitneyu_utbln5n6(double s, ae_state *_state); static double mannwhitneyu_utbln5n7(double s, ae_state *_state); static double mannwhitneyu_utbln5n8(double s, ae_state *_state); static double mannwhitneyu_utbln5n9(double s, ae_state *_state); static double mannwhitneyu_utbln5n10(double s, ae_state *_state); static double mannwhitneyu_utbln5n11(double s, ae_state *_state); static double mannwhitneyu_utbln5n12(double s, ae_state *_state); static double mannwhitneyu_utbln5n13(double s, ae_state *_state); static double mannwhitneyu_utbln5n14(double s, ae_state *_state); static double mannwhitneyu_utbln5n15(double s, ae_state *_state); static double mannwhitneyu_utbln5n16(double s, ae_state *_state); static double mannwhitneyu_utbln5n17(double s, ae_state *_state); static double mannwhitneyu_utbln5n18(double s, ae_state *_state); static double mannwhitneyu_utbln5n19(double s, ae_state *_state); static double mannwhitneyu_utbln5n20(double s, ae_state *_state); static double mannwhitneyu_utbln5n21(double s, ae_state *_state); static double mannwhitneyu_utbln5n22(double s, ae_state *_state); static double mannwhitneyu_utbln5n23(double s, ae_state *_state); static double mannwhitneyu_utbln5n24(double s, ae_state *_state); static double mannwhitneyu_utbln5n25(double s, ae_state *_state); static double mannwhitneyu_utbln5n26(double s, ae_state *_state); static double mannwhitneyu_utbln5n27(double s, ae_state *_state); static double mannwhitneyu_utbln5n28(double s, ae_state *_state); static double mannwhitneyu_utbln5n29(double s, ae_state *_state); static double mannwhitneyu_utbln5n30(double s, ae_state *_state); static double mannwhitneyu_utbln5n100(double s, ae_state *_state); static double mannwhitneyu_utbln6n6(double s, ae_state *_state); static double mannwhitneyu_utbln6n7(double s, ae_state *_state); static double mannwhitneyu_utbln6n8(double s, ae_state *_state); static double mannwhitneyu_utbln6n9(double s, ae_state *_state); static double mannwhitneyu_utbln6n10(double s, ae_state *_state); static double mannwhitneyu_utbln6n11(double s, ae_state *_state); static double mannwhitneyu_utbln6n12(double s, ae_state *_state); static double mannwhitneyu_utbln6n13(double s, ae_state *_state); static double mannwhitneyu_utbln6n14(double s, ae_state *_state); static double mannwhitneyu_utbln6n15(double s, ae_state *_state); static double mannwhitneyu_utbln6n30(double s, ae_state *_state); static double mannwhitneyu_utbln6n100(double s, ae_state *_state); static double mannwhitneyu_utbln7n7(double s, ae_state *_state); static double mannwhitneyu_utbln7n8(double s, ae_state *_state); static double mannwhitneyu_utbln7n9(double s, ae_state *_state); static double mannwhitneyu_utbln7n10(double s, ae_state *_state); static double mannwhitneyu_utbln7n11(double s, ae_state *_state); static double mannwhitneyu_utbln7n12(double s, ae_state *_state); static double mannwhitneyu_utbln7n13(double s, ae_state *_state); static double mannwhitneyu_utbln7n14(double s, ae_state *_state); static double mannwhitneyu_utbln7n15(double s, ae_state *_state); static double mannwhitneyu_utbln7n30(double s, ae_state *_state); static double mannwhitneyu_utbln7n100(double s, ae_state *_state); static double mannwhitneyu_utbln8n8(double s, ae_state *_state); static double mannwhitneyu_utbln8n9(double s, ae_state *_state); static double mannwhitneyu_utbln8n10(double s, ae_state *_state); static double mannwhitneyu_utbln8n11(double s, ae_state *_state); static double mannwhitneyu_utbln8n12(double s, ae_state *_state); static double mannwhitneyu_utbln8n13(double s, ae_state *_state); static double mannwhitneyu_utbln8n14(double s, ae_state *_state); static double mannwhitneyu_utbln8n15(double s, ae_state *_state); static double mannwhitneyu_utbln8n30(double s, ae_state *_state); static double mannwhitneyu_utbln8n100(double s, ae_state *_state); static double mannwhitneyu_utbln9n9(double s, ae_state *_state); static double mannwhitneyu_utbln9n10(double s, ae_state *_state); static double mannwhitneyu_utbln9n11(double s, ae_state *_state); static double mannwhitneyu_utbln9n12(double s, ae_state *_state); static double mannwhitneyu_utbln9n13(double s, ae_state *_state); static double mannwhitneyu_utbln9n14(double s, ae_state *_state); static double mannwhitneyu_utbln9n15(double s, ae_state *_state); static double mannwhitneyu_utbln9n30(double s, ae_state *_state); static double mannwhitneyu_utbln9n100(double s, ae_state *_state); static double mannwhitneyu_utbln10n10(double s, ae_state *_state); static double mannwhitneyu_utbln10n11(double s, ae_state *_state); static double mannwhitneyu_utbln10n12(double s, ae_state *_state); static double mannwhitneyu_utbln10n13(double s, ae_state *_state); static double mannwhitneyu_utbln10n14(double s, ae_state *_state); static double mannwhitneyu_utbln10n15(double s, ae_state *_state); static double mannwhitneyu_utbln10n30(double s, ae_state *_state); static double mannwhitneyu_utbln10n100(double s, ae_state *_state); static double mannwhitneyu_utbln11n11(double s, ae_state *_state); static double mannwhitneyu_utbln11n12(double s, ae_state *_state); static double mannwhitneyu_utbln11n13(double s, ae_state *_state); static double mannwhitneyu_utbln11n14(double s, ae_state *_state); static double mannwhitneyu_utbln11n15(double s, ae_state *_state); static double mannwhitneyu_utbln11n30(double s, ae_state *_state); static double mannwhitneyu_utbln11n100(double s, ae_state *_state); static double mannwhitneyu_utbln12n12(double s, ae_state *_state); static double mannwhitneyu_utbln12n13(double s, ae_state *_state); static double mannwhitneyu_utbln12n14(double s, ae_state *_state); static double mannwhitneyu_utbln12n15(double s, ae_state *_state); static double mannwhitneyu_utbln12n30(double s, ae_state *_state); static double mannwhitneyu_utbln12n100(double s, ae_state *_state); static double mannwhitneyu_utbln13n13(double s, ae_state *_state); static double mannwhitneyu_utbln13n14(double s, ae_state *_state); static double mannwhitneyu_utbln13n15(double s, ae_state *_state); static double mannwhitneyu_utbln13n30(double s, ae_state *_state); static double mannwhitneyu_utbln13n100(double s, ae_state *_state); static double mannwhitneyu_utbln14n14(double s, ae_state *_state); static double mannwhitneyu_utbln14n15(double s, ae_state *_state); static double mannwhitneyu_utbln14n30(double s, ae_state *_state); static double mannwhitneyu_utbln14n100(double s, ae_state *_state); static double mannwhitneyu_usigma(double s, ae_int_t n1, ae_int_t n2, ae_state *_state); static void wsr_wcheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state); static double wsr_w5(double s, ae_state *_state); static double wsr_w6(double s, ae_state *_state); static double wsr_w7(double s, ae_state *_state); static double wsr_w8(double s, ae_state *_state); static double wsr_w9(double s, ae_state *_state); static double wsr_w10(double s, ae_state *_state); static double wsr_w11(double s, ae_state *_state); static double wsr_w12(double s, ae_state *_state); static double wsr_w13(double s, ae_state *_state); static double wsr_w14(double s, ae_state *_state); static double wsr_w15(double s, ae_state *_state); static double wsr_w16(double s, ae_state *_state); static double wsr_w17(double s, ae_state *_state); static double wsr_w18(double s, ae_state *_state); static double wsr_w19(double s, ae_state *_state); static double wsr_w20(double s, ae_state *_state); static double wsr_w21(double s, ae_state *_state); static double wsr_w22(double s, ae_state *_state); static double wsr_w23(double s, ae_state *_state); static double wsr_w24(double s, ae_state *_state); static double wsr_w25(double s, ae_state *_state); static double wsr_w26(double s, ae_state *_state); static double wsr_w27(double s, ae_state *_state); static double wsr_w28(double s, ae_state *_state); static double wsr_w29(double s, ae_state *_state); static double wsr_w30(double s, ae_state *_state); static double wsr_w40(double s, ae_state *_state); static double wsr_w60(double s, ae_state *_state); static double wsr_w120(double s, ae_state *_state); static double wsr_w200(double s, ae_state *_state); static double wsr_wsigma(double s, ae_int_t n, ae_state *_state); /************************************************************************* Calculation of the distribution moments: mean, variance, skewness, kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X OUTPUT PARAMETERS Mean - mean. Variance- variance. Skewness- skewness (if variance<>0; zero otherwise). Kurtosis- kurtosis (if variance<>0; zero otherwise). NOTE: variance is calculated by dividing sum of squares by N-1, not N. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemoments(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* variance, double* skewness, double* kurtosis, ae_state *_state) { ae_int_t i; double v; double v1; double v2; double stddev; *mean = 0; *variance = 0; *skewness = 0; *kurtosis = 0; ae_assert(n>=0, "SampleMoments: N<0", _state); ae_assert(x->cnt>=n, "SampleMoments: Length(X)ptr.p_double[i]; } *mean = *mean/n; /* * Variance (using corrected two-pass algorithm) */ if( n!=1 ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-(*mean)); } v2 = ae_sqr(v2, _state)/n; *variance = (v1-v2)/(n-1); if( ae_fp_less(*variance,(double)(0)) ) { *variance = (double)(0); } stddev = ae_sqrt(*variance, _state); } /* * Skewness and kurtosis */ if( ae_fp_neq(stddev,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = (x->ptr.p_double[i]-(*mean))/stddev; v2 = ae_sqr(v, _state); *skewness = *skewness+v2*v; *kurtosis = *kurtosis+ae_sqr(v2, _state); } *skewness = *skewness/n; *kurtosis = *kurtosis/n-3; } } /************************************************************************* Calculation of the mean. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Mean' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplemean(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double mean; double tmp0; double tmp1; double tmp2; double result; samplemoments(x, n, &mean, &tmp0, &tmp1, &tmp2, _state); result = mean; return result; } /************************************************************************* Calculation of the variance. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Variance' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplevariance(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double variance; double tmp0; double tmp1; double tmp2; double result; samplemoments(x, n, &tmp0, &variance, &tmp1, &tmp2, _state); result = variance; return result; } /************************************************************************* Calculation of the skewness. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Skewness' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double sampleskewness(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double skewness; double tmp0; double tmp1; double tmp2; double result; samplemoments(x, n, &tmp0, &tmp1, &skewness, &tmp2, _state); result = skewness; return result; } /************************************************************************* Calculation of the kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Kurtosis' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ double samplekurtosis(/* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double kurtosis; double tmp0; double tmp1; double tmp2; double result; samplemoments(x, n, &tmp0, &tmp1, &tmp2, &kurtosis, _state); result = kurtosis; return result; } /************************************************************************* ADev Input parameters: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: ADev- ADev -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void sampleadev(/* Real */ ae_vector* x, ae_int_t n, double* adev, ae_state *_state) { ae_int_t i; double mean; *adev = 0; ae_assert(n>=0, "SampleADev: N<0", _state); ae_assert(x->cnt>=n, "SampleADev: Length(X)ptr.p_double[i]; } mean = mean/n; /* * ADev */ for(i=0; i<=n-1; i++) { *adev = *adev+ae_fabs(x->ptr.p_double[i]-mean, _state); } *adev = *adev/n; } /************************************************************************* Median calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: Median -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/ void samplemedian(/* Real */ ae_vector* x, ae_int_t n, double* median, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_int_t i; ae_int_t ir; ae_int_t j; ae_int_t l; ae_int_t midp; ae_int_t k; double a; double tval; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; *median = 0; ae_assert(n>=0, "SampleMedian: N<0", _state); ae_assert(x->cnt>=n, "SampleMedian: Length(X)ptr.p_double[0]; ae_frame_leave(_state); return; } if( n==2 ) { *median = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[1]); ae_frame_leave(_state); return; } /* * Common case, N>=3. * Choose X[(N-1)/2] */ l = 0; ir = n-1; k = (n-1)/2; for(;;) { if( ir<=l+1 ) { /* * 1 or 2 elements in partition */ if( ir==l+1&&ae_fp_less(x->ptr.p_double[ir],x->ptr.p_double[l]) ) { tval = x->ptr.p_double[l]; x->ptr.p_double[l] = x->ptr.p_double[ir]; x->ptr.p_double[ir] = tval; } break; } else { midp = (l+ir)/2; tval = x->ptr.p_double[midp]; x->ptr.p_double[midp] = x->ptr.p_double[l+1]; x->ptr.p_double[l+1] = tval; if( ae_fp_greater(x->ptr.p_double[l],x->ptr.p_double[ir]) ) { tval = x->ptr.p_double[l]; x->ptr.p_double[l] = x->ptr.p_double[ir]; x->ptr.p_double[ir] = tval; } if( ae_fp_greater(x->ptr.p_double[l+1],x->ptr.p_double[ir]) ) { tval = x->ptr.p_double[l+1]; x->ptr.p_double[l+1] = x->ptr.p_double[ir]; x->ptr.p_double[ir] = tval; } if( ae_fp_greater(x->ptr.p_double[l],x->ptr.p_double[l+1]) ) { tval = x->ptr.p_double[l]; x->ptr.p_double[l] = x->ptr.p_double[l+1]; x->ptr.p_double[l+1] = tval; } i = l+1; j = ir; a = x->ptr.p_double[l+1]; for(;;) { do { i = i+1; } while(ae_fp_less(x->ptr.p_double[i],a)); do { j = j-1; } while(ae_fp_greater(x->ptr.p_double[j],a)); if( jptr.p_double[i]; x->ptr.p_double[i] = x->ptr.p_double[j]; x->ptr.p_double[j] = tval; } x->ptr.p_double[l+1] = x->ptr.p_double[j]; x->ptr.p_double[j] = a; if( j>=k ) { ir = j-1; } if( j<=k ) { l = i; } } } /* * If N is odd, return result */ if( n%2==1 ) { *median = x->ptr.p_double[k]; ae_frame_leave(_state); return; } a = x->ptr.p_double[n-1]; for(i=k+1; i<=n-1; i++) { if( ae_fp_less(x->ptr.p_double[i],a) ) { a = x->ptr.p_double[i]; } } *median = 0.5*(x->ptr.p_double[k]+a); ae_frame_leave(_state); } /************************************************************************* Percentile calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X P - percentile (0<=P<=1) Output parameters: V - percentile -- ALGLIB -- Copyright 01.03.2008 by Bochkanov Sergey *************************************************************************/ void samplepercentile(/* Real */ ae_vector* x, ae_int_t n, double p, double* v, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_int_t i1; double t; ae_vector rbuf; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; *v = 0; ae_vector_init(&rbuf, 0, DT_REAL, _state); ae_assert(n>=0, "SamplePercentile: N<0", _state); ae_assert(x->cnt>=n, "SamplePercentile: Length(X)ptr.p_double[0]; ae_frame_leave(_state); return; } if( ae_fp_eq(p,(double)(1)) ) { *v = x->ptr.p_double[n-1]; ae_frame_leave(_state); return; } t = p*(n-1); i1 = ae_ifloor(t, _state); t = t-ae_ifloor(t, _state); *v = x->ptr.p_double[i1]*(1-t)+x->ptr.p_double[i1+1]*t; ae_frame_leave(_state); } /************************************************************************* 2-sample covariance Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: covariance (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double cov2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state) { ae_int_t i; double xmean; double ymean; double v; double x0; double y0; double s; ae_bool samex; ae_bool samey; double result; ae_assert(n>=0, "Cov2: N<0", _state); ae_assert(x->cnt>=n, "Cov2: Length(X)cnt>=n, "Cov2: Length(Y)ptr.p_double[0]; y0 = y->ptr.p_double[0]; v = (double)1/(double)n; for(i=0; i<=n-1; i++) { s = x->ptr.p_double[i]; samex = samex&&ae_fp_eq(s,x0); xmean = xmean+s*v; s = y->ptr.p_double[i]; samey = samey&&ae_fp_eq(s,y0); ymean = ymean+s*v; } if( samex||samey ) { result = (double)(0); return result; } /* * covariance */ v = (double)1/(double)(n-1); result = (double)(0); for(i=0; i<=n-1; i++) { result = result+v*(x->ptr.p_double[i]-xmean)*(y->ptr.p_double[i]-ymean); } return result; } /************************************************************************* Pearson product-moment correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Pearson product-moment correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ double pearsoncorr2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state) { ae_int_t i; double xmean; double ymean; double v; double x0; double y0; double s; ae_bool samex; ae_bool samey; double xv; double yv; double t1; double t2; double result; ae_assert(n>=0, "PearsonCorr2: N<0", _state); ae_assert(x->cnt>=n, "PearsonCorr2: Length(X)cnt>=n, "PearsonCorr2: Length(Y)ptr.p_double[0]; y0 = y->ptr.p_double[0]; v = (double)1/(double)n; for(i=0; i<=n-1; i++) { s = x->ptr.p_double[i]; samex = samex&&ae_fp_eq(s,x0); xmean = xmean+s*v; s = y->ptr.p_double[i]; samey = samey&&ae_fp_eq(s,y0); ymean = ymean+s*v; } if( samex||samey ) { result = (double)(0); return result; } /* * numerator and denominator */ s = (double)(0); xv = (double)(0); yv = (double)(0); for(i=0; i<=n-1; i++) { t1 = x->ptr.p_double[i]-xmean; t2 = y->ptr.p_double[i]-ymean; xv = xv+ae_sqr(t1, _state); yv = yv+ae_sqr(t2, _state); s = s+t1*t2; } if( ae_fp_eq(xv,(double)(0))||ae_fp_eq(yv,(double)(0)) ) { result = (double)(0); } else { result = s/(ae_sqrt(xv, _state)*ae_sqrt(yv, _state)); } return result; } /************************************************************************* Spearman's rank correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Spearman's rank correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ double spearmancorr2(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_vector _y; apbuffers buf; double result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; ae_vector_init_copy(&_y, y, _state); y = &_y; _apbuffers_init(&buf, _state); ae_assert(n>=0, "SpearmanCorr2: N<0", _state); ae_assert(x->cnt>=n, "SpearmanCorr2: Length(X)cnt>=n, "SpearmanCorr2: Length(Y)=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_matrix _x; ae_int_t i; ae_int_t j; double v; ae_vector t; ae_vector x0; ae_vector same; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_x, x, _state); x = &_x; ae_matrix_clear(c); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&same, 0, DT_BOOL, _state); ae_assert(n>=0, "CovM: N<0", _state); ae_assert(m>=1, "CovM: M<1", _state); ae_assert(x->rows>=n, "CovM: Rows(X)cols>=m||n==0, "CovM: Cols(X)ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * Calculate means, * check for constant columns */ ae_vector_set_length(&t, m, _state); ae_vector_set_length(&x0, m, _state); ae_vector_set_length(&same, m, _state); ae_matrix_set_length(c, m, m, _state); for(i=0; i<=m-1; i++) { t.ptr.p_double[i] = (double)(0); same.ptr.p_bool[i] = ae_true; } ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m-1)); v = (double)1/(double)n; for(i=0; i<=n-1; i++) { ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); for(j=0; j<=m-1; j++) { same.ptr.p_bool[j] = same.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); } } /* * * center variables; * * if we have constant columns, these columns are * artificially zeroed (they must be zero in exact arithmetics, * but unfortunately floating point ops are not exact). * * calculate upper half of symmetric covariance matrix */ for(i=0; i<=n-1; i++) { ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m-1)); for(j=0; j<=m-1; j++) { if( same.ptr.p_bool[j] ) { x->ptr.pp_double[i][j] = (double)(0); } } } rmatrixsyrk(m, n, (double)1/(double)(n-1), x, 0, 0, 1, 0.0, c, 0, 0, ae_true, _state); rmatrixenforcesymmetricity(c, m, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_covm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { covm(x,n,m,c, _state); } /************************************************************************* Pearson product-moment correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_vector t; ae_int_t i; ae_int_t j; double v; ae_frame_make(_state, &_frame_block); ae_matrix_clear(c); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=0, "PearsonCorrM: N<0", _state); ae_assert(m>=1, "PearsonCorrM: M<1", _state); ae_assert(x->rows>=n, "PearsonCorrM: Rows(X)cols>=m||n==0, "PearsonCorrM: Cols(X)ptr.pp_double[i][i],(double)(0)) ) { t.ptr.p_double[i] = 1/ae_sqrt(c->ptr.pp_double[i][i], _state); } else { t.ptr.p_double[i] = 0.0; } } for(i=0; i<=m-1; i++) { v = t.ptr.p_double[i]; for(j=0; j<=m-1; j++) { c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_pearsoncorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { pearsoncorrm(x,n,m,c, _state); } /************************************************************************* Spearman's rank correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; apbuffers buf; ae_matrix xc; ae_vector t; double v; double vv; double x0; ae_bool b; ae_frame_make(_state, &_frame_block); ae_matrix_clear(c); _apbuffers_init(&buf, _state); ae_matrix_init(&xc, 0, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_assert(n>=0, "SpearmanCorrM: N<0", _state); ae_assert(m>=1, "SpearmanCorrM: M<1", _state); ae_assert(x->rows>=n, "SpearmanCorrM: Rows(X)cols>=m||n==0, "SpearmanCorrM: Cols(X)ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * Allocate */ ae_vector_set_length(&t, ae_maxint(n, m, _state), _state); ae_matrix_set_length(c, m, m, _state); /* * Replace data with ranks */ ae_matrix_set_length(&xc, m, n, _state); rmatrixtranspose(n, m, x, 0, 0, &xc, 0, 0, _state); rankdata(&xc, m, n, _state); /* * 1. Calculate means, check for constant columns * 2. Center variables, constant columns are * artificialy zeroed (they must be zero in exact arithmetics, * but unfortunately floating point is not exact). */ for(i=0; i<=m-1; i++) { /* * Calculate: * * V - mean value of I-th variable * * B - True in case all variable values are same */ v = (double)(0); b = ae_true; x0 = xc.ptr.pp_double[i][0]; for(j=0; j<=n-1; j++) { vv = xc.ptr.pp_double[i][j]; v = v+vv; b = b&&ae_fp_eq(vv,x0); } v = v/n; /* * Center/zero I-th variable */ if( b ) { /* * Zero */ for(j=0; j<=n-1; j++) { xc.ptr.pp_double[i][j] = 0.0; } } else { /* * Center */ for(j=0; j<=n-1; j++) { xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]-v; } } } /* * Calculate upper half of symmetric covariance matrix */ rmatrixsyrk(m, n, (double)1/(double)(n-1), &xc, 0, 0, 0, 0.0, c, 0, 0, ae_true, _state); /* * Calculate Pearson coefficients (upper triangle) */ for(i=0; i<=m-1; i++) { if( ae_fp_greater(c->ptr.pp_double[i][i],(double)(0)) ) { t.ptr.p_double[i] = 1/ae_sqrt(c->ptr.pp_double[i][i], _state); } else { t.ptr.p_double[i] = 0.0; } } for(i=0; i<=m-1; i++) { v = t.ptr.p_double[i]; for(j=i; j<=m-1; j++) { c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; } } /* * force symmetricity */ rmatrixenforcesymmetricity(c, m, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spearmancorrm(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t m, /* Real */ ae_matrix* c, ae_state *_state) { spearmancorrm(x,n,m,c, _state); } /************************************************************************* Cross-covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void covm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_matrix _x; ae_matrix _y; ae_int_t i; ae_int_t j; double v; ae_vector t; ae_vector x0; ae_vector y0; ae_vector samex; ae_vector samey; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_x, x, _state); x = &_x; ae_matrix_init_copy(&_y, y, _state); y = &_y; ae_matrix_clear(c); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&samex, 0, DT_BOOL, _state); ae_vector_init(&samey, 0, DT_BOOL, _state); ae_assert(n>=0, "CovM2: N<0", _state); ae_assert(m1>=1, "CovM2: M1<1", _state); ae_assert(m2>=1, "CovM2: M2<1", _state); ae_assert(x->rows>=n, "CovM2: Rows(X)cols>=m1||n==0, "CovM2: Cols(X)rows>=n, "CovM2: Rows(Y)cols>=m2||n==0, "CovM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * Allocate */ ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); ae_vector_set_length(&x0, m1, _state); ae_vector_set_length(&y0, m2, _state); ae_vector_set_length(&samex, m1, _state); ae_vector_set_length(&samey, m2, _state); ae_matrix_set_length(c, m1, m2, _state); /* * * calculate means of X * * center X * * if we have constant columns, these columns are * artificially zeroed (they must be zero in exact arithmetics, * but unfortunately floating point ops are not exact). */ for(i=0; i<=m1-1; i++) { t.ptr.p_double[i] = (double)(0); samex.ptr.p_bool[i] = ae_true; } ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); v = (double)1/(double)n; for(i=0; i<=n-1; i++) { ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); for(j=0; j<=m1-1; j++) { samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); } } for(i=0; i<=n-1; i++) { ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); for(j=0; j<=m1-1; j++) { if( samex.ptr.p_bool[j] ) { x->ptr.pp_double[i][j] = (double)(0); } } } /* * Repeat same steps for Y */ for(i=0; i<=m2-1; i++) { t.ptr.p_double[i] = (double)(0); samey.ptr.p_bool[i] = ae_true; } ae_v_move(&y0.ptr.p_double[0], 1, &y->ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); v = (double)1/(double)n; for(i=0; i<=n-1; i++) { ae_v_addd(&t.ptr.p_double[0], 1, &y->ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); for(j=0; j<=m2-1; j++) { samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y->ptr.pp_double[i][j],y0.ptr.p_double[j]); } } for(i=0; i<=n-1; i++) { ae_v_sub(&y->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); for(j=0; j<=m2-1; j++) { if( samey.ptr.p_bool[j] ) { y->ptr.pp_double[i][j] = (double)(0); } } } /* * calculate cross-covariance matrix */ rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), x, 0, 0, 1, y, 0, 0, 0, 0.0, c, 0, 0, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_covm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { covm2(x,y,n,m1,m2,c, _state); } /************************************************************************* Pearson product-moment cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void pearsoncorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_matrix _x; ae_matrix _y; ae_int_t i; ae_int_t j; double v; ae_vector t; ae_vector x0; ae_vector y0; ae_vector sx; ae_vector sy; ae_vector samex; ae_vector samey; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_x, x, _state); x = &_x; ae_matrix_init_copy(&_y, y, _state); y = &_y; ae_matrix_clear(c); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&sx, 0, DT_REAL, _state); ae_vector_init(&sy, 0, DT_REAL, _state); ae_vector_init(&samex, 0, DT_BOOL, _state); ae_vector_init(&samey, 0, DT_BOOL, _state); ae_assert(n>=0, "PearsonCorrM2: N<0", _state); ae_assert(m1>=1, "PearsonCorrM2: M1<1", _state); ae_assert(m2>=1, "PearsonCorrM2: M2<1", _state); ae_assert(x->rows>=n, "PearsonCorrM2: Rows(X)cols>=m1||n==0, "PearsonCorrM2: Cols(X)rows>=n, "PearsonCorrM2: Rows(Y)cols>=m2||n==0, "PearsonCorrM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * Allocate */ ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); ae_vector_set_length(&x0, m1, _state); ae_vector_set_length(&y0, m2, _state); ae_vector_set_length(&sx, m1, _state); ae_vector_set_length(&sy, m2, _state); ae_vector_set_length(&samex, m1, _state); ae_vector_set_length(&samey, m2, _state); ae_matrix_set_length(c, m1, m2, _state); /* * * calculate means of X * * center X * * if we have constant columns, these columns are * artificially zeroed (they must be zero in exact arithmetics, * but unfortunately floating point ops are not exact). * * calculate column variances */ for(i=0; i<=m1-1; i++) { t.ptr.p_double[i] = (double)(0); samex.ptr.p_bool[i] = ae_true; sx.ptr.p_double[i] = (double)(0); } ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); v = (double)1/(double)n; for(i=0; i<=n-1; i++) { ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); for(j=0; j<=m1-1; j++) { samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); } } for(i=0; i<=n-1; i++) { ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); for(j=0; j<=m1-1; j++) { if( samex.ptr.p_bool[j] ) { x->ptr.pp_double[i][j] = (double)(0); } sx.ptr.p_double[j] = sx.ptr.p_double[j]+x->ptr.pp_double[i][j]*x->ptr.pp_double[i][j]; } } for(j=0; j<=m1-1; j++) { sx.ptr.p_double[j] = ae_sqrt(sx.ptr.p_double[j]/(n-1), _state); } /* * Repeat same steps for Y */ for(i=0; i<=m2-1; i++) { t.ptr.p_double[i] = (double)(0); samey.ptr.p_bool[i] = ae_true; sy.ptr.p_double[i] = (double)(0); } ae_v_move(&y0.ptr.p_double[0], 1, &y->ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); v = (double)1/(double)n; for(i=0; i<=n-1; i++) { ae_v_addd(&t.ptr.p_double[0], 1, &y->ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); for(j=0; j<=m2-1; j++) { samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y->ptr.pp_double[i][j],y0.ptr.p_double[j]); } } for(i=0; i<=n-1; i++) { ae_v_sub(&y->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); for(j=0; j<=m2-1; j++) { if( samey.ptr.p_bool[j] ) { y->ptr.pp_double[i][j] = (double)(0); } sy.ptr.p_double[j] = sy.ptr.p_double[j]+y->ptr.pp_double[i][j]*y->ptr.pp_double[i][j]; } } for(j=0; j<=m2-1; j++) { sy.ptr.p_double[j] = ae_sqrt(sy.ptr.p_double[j]/(n-1), _state); } /* * calculate cross-covariance matrix */ rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), x, 0, 0, 1, y, 0, 0, 0, 0.0, c, 0, 0, _state); /* * Divide by standard deviations */ for(i=0; i<=m1-1; i++) { if( ae_fp_neq(sx.ptr.p_double[i],(double)(0)) ) { sx.ptr.p_double[i] = 1/sx.ptr.p_double[i]; } else { sx.ptr.p_double[i] = 0.0; } } for(i=0; i<=m2-1; i++) { if( ae_fp_neq(sy.ptr.p_double[i],(double)(0)) ) { sy.ptr.p_double[i] = 1/sy.ptr.p_double[i]; } else { sy.ptr.p_double[i] = 0.0; } } for(i=0; i<=m1-1; i++) { v = sx.ptr.p_double[i]; for(j=0; j<=m2-1; j++) { c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_pearsoncorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { pearsoncorrm2(x,y,n,m1,m2,c, _state); } /************************************************************************* Spearman's rank cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/ void spearmancorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; double v2; double vv; ae_bool b; ae_vector t; double x0; double y0; ae_vector sx; ae_vector sy; ae_matrix xc; ae_matrix yc; apbuffers buf; ae_frame_make(_state, &_frame_block); ae_matrix_clear(c); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&sx, 0, DT_REAL, _state); ae_vector_init(&sy, 0, DT_REAL, _state); ae_matrix_init(&xc, 0, 0, DT_REAL, _state); ae_matrix_init(&yc, 0, 0, DT_REAL, _state); _apbuffers_init(&buf, _state); ae_assert(n>=0, "SpearmanCorrM2: N<0", _state); ae_assert(m1>=1, "SpearmanCorrM2: M1<1", _state); ae_assert(m2>=1, "SpearmanCorrM2: M2<1", _state); ae_assert(x->rows>=n, "SpearmanCorrM2: Rows(X)cols>=m1||n==0, "SpearmanCorrM2: Cols(X)rows>=n, "SpearmanCorrM2: Rows(Y)cols>=m2||n==0, "SpearmanCorrM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } /* * Allocate */ ae_vector_set_length(&t, ae_maxint(ae_maxint(m1, m2, _state), n, _state), _state); ae_vector_set_length(&sx, m1, _state); ae_vector_set_length(&sy, m2, _state); ae_matrix_set_length(c, m1, m2, _state); /* * Replace data with ranks */ ae_matrix_set_length(&xc, m1, n, _state); ae_matrix_set_length(&yc, m2, n, _state); rmatrixtranspose(n, m1, x, 0, 0, &xc, 0, 0, _state); rmatrixtranspose(n, m2, y, 0, 0, &yc, 0, 0, _state); rankdata(&xc, m1, n, _state); rankdata(&yc, m2, n, _state); /* * 1. Calculate means, variances, check for constant columns * 2. Center variables, constant columns are * artificialy zeroed (they must be zero in exact arithmetics, * but unfortunately floating point is not exact). * * Description of variables: * * V - mean value of I-th variable * * V2- variance * * VV-temporary * * B - True in case all variable values are same */ for(i=0; i<=m1-1; i++) { v = (double)(0); v2 = 0.0; b = ae_true; x0 = xc.ptr.pp_double[i][0]; for(j=0; j<=n-1; j++) { vv = xc.ptr.pp_double[i][j]; v = v+vv; b = b&&ae_fp_eq(vv,x0); } v = v/n; if( b ) { for(j=0; j<=n-1; j++) { xc.ptr.pp_double[i][j] = 0.0; } } else { for(j=0; j<=n-1; j++) { vv = xc.ptr.pp_double[i][j]; xc.ptr.pp_double[i][j] = vv-v; v2 = v2+(vv-v)*(vv-v); } } sx.ptr.p_double[i] = ae_sqrt(v2/(n-1), _state); } for(i=0; i<=m2-1; i++) { v = (double)(0); v2 = 0.0; b = ae_true; y0 = yc.ptr.pp_double[i][0]; for(j=0; j<=n-1; j++) { vv = yc.ptr.pp_double[i][j]; v = v+vv; b = b&&ae_fp_eq(vv,y0); } v = v/n; if( b ) { for(j=0; j<=n-1; j++) { yc.ptr.pp_double[i][j] = 0.0; } } else { for(j=0; j<=n-1; j++) { vv = yc.ptr.pp_double[i][j]; yc.ptr.pp_double[i][j] = vv-v; v2 = v2+(vv-v)*(vv-v); } } sy.ptr.p_double[i] = ae_sqrt(v2/(n-1), _state); } /* * calculate cross-covariance matrix */ rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), &xc, 0, 0, 0, &yc, 0, 0, 1, 0.0, c, 0, 0, _state); /* * Divide by standard deviations */ for(i=0; i<=m1-1; i++) { if( ae_fp_neq(sx.ptr.p_double[i],(double)(0)) ) { sx.ptr.p_double[i] = 1/sx.ptr.p_double[i]; } else { sx.ptr.p_double[i] = 0.0; } } for(i=0; i<=m2-1; i++) { if( ae_fp_neq(sy.ptr.p_double[i],(double)(0)) ) { sy.ptr.p_double[i] = 1/sy.ptr.p_double[i]; } else { sy.ptr.p_double[i] = 0.0; } } for(i=0; i<=m1-1; i++) { v = sx.ptr.p_double[i]; for(j=0; j<=m2-1; j++) { c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spearmancorrm2(/* Real */ ae_matrix* x, /* Real */ ae_matrix* y, ae_int_t n, ae_int_t m1, ae_int_t m2, /* Real */ ae_matrix* c, ae_state *_state) { spearmancorrm2(x,y,n,m1,m2,c, _state); } /************************************************************************* This function replaces data in XY by their ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * ranking starts from 0, ends at NFeatures-1 * sum of within-row values is equal to (NFeatures-1)*NFeatures/2 SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ void rankdata(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_state *_state) { ae_frame _frame_block; apbuffers buf0; apbuffers buf1; ae_int_t basecasecost; ae_shared_pool pool; ae_frame_make(_state, &_frame_block); _apbuffers_init(&buf0, _state); _apbuffers_init(&buf1, _state); ae_shared_pool_init(&pool, _state); ae_assert(npoints>=0, "RankData: NPoints<0", _state); ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=0, "RankData: NPoints<0", _state); ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=i0, "RankDataRec: internal error", _state); /* * Recursively split problem, if it is too large */ problemcost = inttoreal(i1-i0, _state)*inttoreal(nfeatures, _state)*logbase2((double)(nfeatures), _state); if( i1-i0>=2&&ae_fp_greater(problemcost,(double)(basecasecost)) ) { im = (i1+i0)/2; basestat_rankdatarec(xy, i0, im, nfeatures, iscentered, pool, basecasecost, _state); basestat_rankdatarec(xy, im, i1, nfeatures, iscentered, pool, basecasecost, _state); ae_frame_leave(_state); return; } /* * Retrieve buffers from pool, call serial code, return buffers to pool */ ae_shared_pool_retrieve(pool, &_buf0, _state); ae_shared_pool_retrieve(pool, &_buf1, _state); basestat_rankdatabasecase(xy, i0, i1, nfeatures, iscentered, buf0, buf1, _state); ae_shared_pool_recycle(pool, &_buf0, _state); ae_shared_pool_recycle(pool, &_buf1, _state); ae_frame_leave(_state); } /************************************************************************* Basecase code for RankData(), performs actual work on subset of data using temporary buffer passed as parameter. INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset I0 - index of first row to process I1 - index of past-the-last row to process; this function processes half-interval [I0,I1). NFeatures- number of features IsCentered- whether ranks are centered or not: * True - ranks are centered in such way that their within-row sum is zero * False - ranks are not centered Buf0 - temporary buffers, may be empty (this function automatically allocates/reuses buffers). Buf1 - temporary buffers, may be empty (this function automatically allocates/reuses buffers). OUTPUT PARAMETERS: XY - data in [I0,I1) are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/ static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, ae_int_t i0, ae_int_t i1, ae_int_t nfeatures, ae_bool iscentered, apbuffers* buf0, apbuffers* buf1, ae_state *_state) { ae_int_t i; ae_assert(i1>=i0, "RankDataBasecase: internal error", _state); if( buf1->ra0.cntra0, nfeatures, _state); } for(i=i0; i<=i1-1; i++) { ae_v_move(&buf1->ra0.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); rankx(&buf1->ra0, nfeatures, iscentered, buf0, _state); ae_v_move(&xy->ptr.pp_double[i][0], 1, &buf1->ra0.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); } } /************************************************************************* Pearson's correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5 * normality of distributions of X and Y. Input parameters: R - Pearson's correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void pearsoncorrelationsignificance(double r, ae_int_t n, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { double t; double p; *bothtails = 0; *lefttail = 0; *righttail = 0; /* * Some special cases */ if( ae_fp_greater_eq(r,(double)(1)) ) { *bothtails = 0.0; *lefttail = 1.0; *righttail = 0.0; return; } if( ae_fp_less_eq(r,(double)(-1)) ) { *bothtails = 0.0; *lefttail = 0.0; *righttail = 1.0; return; } if( n<5 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * General case */ t = r*ae_sqrt((n-2)/(1-ae_sqr(r, _state)), _state); p = studenttdistribution(n-2, t, _state); *bothtails = 2*ae_minreal(p, 1-p, _state); *lefttail = p; *righttail = 1-p; } /************************************************************************* Spearman's rank correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5. The test is non-parametric and doesn't require distributions X and Y to be normal. Input parameters: R - Spearman's rank correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void spearmanrankcorrelationsignificance(double r, ae_int_t n, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { double t; double p; *bothtails = 0; *lefttail = 0; *righttail = 0; /* * Special case */ if( n<5 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * General case */ if( ae_fp_greater_eq(r,(double)(1)) ) { t = 1.0E10; } else { if( ae_fp_less_eq(r,(double)(-1)) ) { t = -1.0E10; } else { t = r*ae_sqrt((n-2)/(1-ae_sqr(r, _state)), _state); } } if( ae_fp_less(t,(double)(0)) ) { p = correlationtests_spearmantail(t, n, _state); *bothtails = 2*p; *lefttail = p; *righttail = 1-p; } else { p = correlationtests_spearmantail(-t, n, _state); *bothtails = 2*p; *lefttail = 1-p; *righttail = p; } } /************************************************************************* Tail(S, 5) *************************************************************************/ static double correlationtests_spearmantail5(double s, ae_state *_state) { double result; if( ae_fp_less(s,0.000e+00) ) { result = studenttdistribution(3, -s, _state); return result; } if( ae_fp_greater_eq(s,3.580e+00) ) { result = 8.304e-03; return result; } if( ae_fp_greater_eq(s,2.322e+00) ) { result = 4.163e-02; return result; } if( ae_fp_greater_eq(s,1.704e+00) ) { result = 6.641e-02; return result; } if( ae_fp_greater_eq(s,1.303e+00) ) { result = 1.164e-01; return result; } if( ae_fp_greater_eq(s,1.003e+00) ) { result = 1.748e-01; return result; } if( ae_fp_greater_eq(s,7.584e-01) ) { result = 2.249e-01; return result; } if( ae_fp_greater_eq(s,5.468e-01) ) { result = 2.581e-01; return result; } if( ae_fp_greater_eq(s,3.555e-01) ) { result = 3.413e-01; return result; } if( ae_fp_greater_eq(s,1.759e-01) ) { result = 3.911e-01; return result; } if( ae_fp_greater_eq(s,1.741e-03) ) { result = 4.747e-01; return result; } if( ae_fp_greater_eq(s,0.000e+00) ) { result = 5.248e-01; return result; } result = (double)(0); return result; } /************************************************************************* Tail(S, 6) *************************************************************************/ static double correlationtests_spearmantail6(double s, ae_state *_state) { double result; if( ae_fp_less(s,1.001e+00) ) { result = studenttdistribution(4, -s, _state); return result; } if( ae_fp_greater_eq(s,5.663e+00) ) { result = 1.366e-03; return result; } if( ae_fp_greater_eq(s,3.834e+00) ) { result = 8.350e-03; return result; } if( ae_fp_greater_eq(s,2.968e+00) ) { result = 1.668e-02; return result; } if( ae_fp_greater_eq(s,2.430e+00) ) { result = 2.921e-02; return result; } if( ae_fp_greater_eq(s,2.045e+00) ) { result = 5.144e-02; return result; } if( ae_fp_greater_eq(s,1.747e+00) ) { result = 6.797e-02; return result; } if( ae_fp_greater_eq(s,1.502e+00) ) { result = 8.752e-02; return result; } if( ae_fp_greater_eq(s,1.295e+00) ) { result = 1.210e-01; return result; } if( ae_fp_greater_eq(s,1.113e+00) ) { result = 1.487e-01; return result; } if( ae_fp_greater_eq(s,1.001e+00) ) { result = 1.780e-01; return result; } result = (double)(0); return result; } /************************************************************************* Tail(S, 7) *************************************************************************/ static double correlationtests_spearmantail7(double s, ae_state *_state) { double result; if( ae_fp_less(s,1.001e+00) ) { result = studenttdistribution(5, -s, _state); return result; } if( ae_fp_greater_eq(s,8.159e+00) ) { result = 2.081e-04; return result; } if( ae_fp_greater_eq(s,5.620e+00) ) { result = 1.393e-03; return result; } if( ae_fp_greater_eq(s,4.445e+00) ) { result = 3.398e-03; return result; } if( ae_fp_greater_eq(s,3.728e+00) ) { result = 6.187e-03; return result; } if( ae_fp_greater_eq(s,3.226e+00) ) { result = 1.200e-02; return result; } if( ae_fp_greater_eq(s,2.844e+00) ) { result = 1.712e-02; return result; } if( ae_fp_greater_eq(s,2.539e+00) ) { result = 2.408e-02; return result; } if( ae_fp_greater_eq(s,2.285e+00) ) { result = 3.320e-02; return result; } if( ae_fp_greater_eq(s,2.068e+00) ) { result = 4.406e-02; return result; } if( ae_fp_greater_eq(s,1.879e+00) ) { result = 5.478e-02; return result; } if( ae_fp_greater_eq(s,1.710e+00) ) { result = 6.946e-02; return result; } if( ae_fp_greater_eq(s,1.559e+00) ) { result = 8.331e-02; return result; } if( ae_fp_greater_eq(s,1.420e+00) ) { result = 1.001e-01; return result; } if( ae_fp_greater_eq(s,1.292e+00) ) { result = 1.180e-01; return result; } if( ae_fp_greater_eq(s,1.173e+00) ) { result = 1.335e-01; return result; } if( ae_fp_greater_eq(s,1.062e+00) ) { result = 1.513e-01; return result; } if( ae_fp_greater_eq(s,1.001e+00) ) { result = 1.770e-01; return result; } result = (double)(0); return result; } /************************************************************************* Tail(S, 8) *************************************************************************/ static double correlationtests_spearmantail8(double s, ae_state *_state) { double result; if( ae_fp_less(s,2.001e+00) ) { result = studenttdistribution(6, -s, _state); return result; } if( ae_fp_greater_eq(s,1.103e+01) ) { result = 2.194e-05; return result; } if( ae_fp_greater_eq(s,7.685e+00) ) { result = 2.008e-04; return result; } if( ae_fp_greater_eq(s,6.143e+00) ) { result = 5.686e-04; return result; } if( ae_fp_greater_eq(s,5.213e+00) ) { result = 1.138e-03; return result; } if( ae_fp_greater_eq(s,4.567e+00) ) { result = 2.310e-03; return result; } if( ae_fp_greater_eq(s,4.081e+00) ) { result = 3.634e-03; return result; } if( ae_fp_greater_eq(s,3.697e+00) ) { result = 5.369e-03; return result; } if( ae_fp_greater_eq(s,3.381e+00) ) { result = 7.708e-03; return result; } if( ae_fp_greater_eq(s,3.114e+00) ) { result = 1.087e-02; return result; } if( ae_fp_greater_eq(s,2.884e+00) ) { result = 1.397e-02; return result; } if( ae_fp_greater_eq(s,2.682e+00) ) { result = 1.838e-02; return result; } if( ae_fp_greater_eq(s,2.502e+00) ) { result = 2.288e-02; return result; } if( ae_fp_greater_eq(s,2.340e+00) ) { result = 2.883e-02; return result; } if( ae_fp_greater_eq(s,2.192e+00) ) { result = 3.469e-02; return result; } if( ae_fp_greater_eq(s,2.057e+00) ) { result = 4.144e-02; return result; } if( ae_fp_greater_eq(s,2.001e+00) ) { result = 4.804e-02; return result; } result = (double)(0); return result; } /************************************************************************* Tail(S, 9) *************************************************************************/ static double correlationtests_spearmantail9(double s, ae_state *_state) { double result; if( ae_fp_less(s,2.001e+00) ) { result = studenttdistribution(7, -s, _state); return result; } if( ae_fp_greater_eq(s,9.989e+00) ) { result = 2.306e-05; return result; } if( ae_fp_greater_eq(s,8.069e+00) ) { result = 8.167e-05; return result; } if( ae_fp_greater_eq(s,6.890e+00) ) { result = 1.744e-04; return result; } if( ae_fp_greater_eq(s,6.077e+00) ) { result = 3.625e-04; return result; } if( ae_fp_greater_eq(s,5.469e+00) ) { result = 6.450e-04; return result; } if( ae_fp_greater_eq(s,4.991e+00) ) { result = 1.001e-03; return result; } if( ae_fp_greater_eq(s,4.600e+00) ) { result = 1.514e-03; return result; } if( ae_fp_greater_eq(s,4.272e+00) ) { result = 2.213e-03; return result; } if( ae_fp_greater_eq(s,3.991e+00) ) { result = 2.990e-03; return result; } if( ae_fp_greater_eq(s,3.746e+00) ) { result = 4.101e-03; return result; } if( ae_fp_greater_eq(s,3.530e+00) ) { result = 5.355e-03; return result; } if( ae_fp_greater_eq(s,3.336e+00) ) { result = 6.887e-03; return result; } if( ae_fp_greater_eq(s,3.161e+00) ) { result = 8.598e-03; return result; } if( ae_fp_greater_eq(s,3.002e+00) ) { result = 1.065e-02; return result; } if( ae_fp_greater_eq(s,2.855e+00) ) { result = 1.268e-02; return result; } if( ae_fp_greater_eq(s,2.720e+00) ) { result = 1.552e-02; return result; } if( ae_fp_greater_eq(s,2.595e+00) ) { result = 1.836e-02; return result; } if( ae_fp_greater_eq(s,2.477e+00) ) { result = 2.158e-02; return result; } if( ae_fp_greater_eq(s,2.368e+00) ) { result = 2.512e-02; return result; } if( ae_fp_greater_eq(s,2.264e+00) ) { result = 2.942e-02; return result; } if( ae_fp_greater_eq(s,2.166e+00) ) { result = 3.325e-02; return result; } if( ae_fp_greater_eq(s,2.073e+00) ) { result = 3.800e-02; return result; } if( ae_fp_greater_eq(s,2.001e+00) ) { result = 4.285e-02; return result; } result = (double)(0); return result; } /************************************************************************* Tail(T,N), accepts T<0 *************************************************************************/ static double correlationtests_spearmantail(double t, ae_int_t n, ae_state *_state) { double result; if( n==5 ) { result = correlationtests_spearmantail5(-t, _state); return result; } if( n==6 ) { result = correlationtests_spearmantail6(-t, _state); return result; } if( n==7 ) { result = correlationtests_spearmantail7(-t, _state); return result; } if( n==8 ) { result = correlationtests_spearmantail8(-t, _state); return result; } if( n==9 ) { result = correlationtests_spearmantail9(-t, _state); return result; } result = studenttdistribution(n-2, t, _state); return result; } /************************************************************************* Jarque-Bera test This test checks hypotheses about the fact that a given sample X is a sample of normal random variable. Requirements: * the number of elements in the sample is not less than 5. Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Output parameters: P - p-value for the test Accuracy of the approximation used (5<=N<=1951): p-value relative error (5<=N<=1951) [1, 0.1] < 1% [0.1, 0.01] < 2% [0.01, 0.001] < 6% [0.001, 0] wasn't measured For N>1951 accuracy wasn't measured but it shouldn't be sharply different from table values. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void jarqueberatest(/* Real */ ae_vector* x, ae_int_t n, double* p, ae_state *_state) { double s; *p = 0; /* * N is too small */ if( n<5 ) { *p = 1.0; return; } /* * N is large enough */ jarquebera_jarqueberastatistic(x, n, &s, _state); *p = jarquebera_jarqueberaapprox(n, s, _state); } static void jarquebera_jarqueberastatistic(/* Real */ ae_vector* x, ae_int_t n, double* s, ae_state *_state) { ae_int_t i; double v; double v1; double v2; double stddev; double mean; double variance; double skewness; double kurtosis; *s = 0; mean = (double)(0); variance = (double)(0); skewness = (double)(0); kurtosis = (double)(0); stddev = (double)(0); ae_assert(n>1, "Assertion failed", _state); /* * Mean */ for(i=0; i<=n-1; i++) { mean = mean+x->ptr.p_double[i]; } mean = mean/n; /* * Variance (using corrected two-pass algorithm) */ if( n!=1 ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-mean, _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-mean); } v2 = ae_sqr(v2, _state)/n; variance = (v1-v2)/(n-1); if( ae_fp_less(variance,(double)(0)) ) { variance = (double)(0); } stddev = ae_sqrt(variance, _state); } /* * Skewness and kurtosis */ if( ae_fp_neq(stddev,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = (x->ptr.p_double[i]-mean)/stddev; v2 = ae_sqr(v, _state); skewness = skewness+v2*v; kurtosis = kurtosis+ae_sqr(v2, _state); } skewness = skewness/n; kurtosis = kurtosis/n-3; } /* * Statistic */ *s = (double)n/(double)6*(ae_sqr(skewness, _state)+ae_sqr(kurtosis, _state)/4); } static double jarquebera_jarqueberaapprox(ae_int_t n, double s, ae_state *_state) { ae_frame _frame_block; ae_vector vx; ae_vector vy; ae_matrix ctbl; double t1; double t2; double t3; double t; double f1; double f2; double f3; double f12; double f23; double x; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&vx, 0, DT_REAL, _state); ae_vector_init(&vy, 0, DT_REAL, _state); ae_matrix_init(&ctbl, 0, 0, DT_REAL, _state); result = (double)(1); x = s; if( n<5 ) { ae_frame_leave(_state); return result; } /* * N = 5..20 are tabulated */ if( n>=5&&n<=20 ) { if( n==5 ) { result = ae_exp(jarquebera_jbtbl5(x, _state), _state); } if( n==6 ) { result = ae_exp(jarquebera_jbtbl6(x, _state), _state); } if( n==7 ) { result = ae_exp(jarquebera_jbtbl7(x, _state), _state); } if( n==8 ) { result = ae_exp(jarquebera_jbtbl8(x, _state), _state); } if( n==9 ) { result = ae_exp(jarquebera_jbtbl9(x, _state), _state); } if( n==10 ) { result = ae_exp(jarquebera_jbtbl10(x, _state), _state); } if( n==11 ) { result = ae_exp(jarquebera_jbtbl11(x, _state), _state); } if( n==12 ) { result = ae_exp(jarquebera_jbtbl12(x, _state), _state); } if( n==13 ) { result = ae_exp(jarquebera_jbtbl13(x, _state), _state); } if( n==14 ) { result = ae_exp(jarquebera_jbtbl14(x, _state), _state); } if( n==15 ) { result = ae_exp(jarquebera_jbtbl15(x, _state), _state); } if( n==16 ) { result = ae_exp(jarquebera_jbtbl16(x, _state), _state); } if( n==17 ) { result = ae_exp(jarquebera_jbtbl17(x, _state), _state); } if( n==18 ) { result = ae_exp(jarquebera_jbtbl18(x, _state), _state); } if( n==19 ) { result = ae_exp(jarquebera_jbtbl19(x, _state), _state); } if( n==20 ) { result = ae_exp(jarquebera_jbtbl20(x, _state), _state); } ae_frame_leave(_state); return result; } /* * N = 20, 30, 50 are tabulated. * In-between values are interpolated * using interpolating polynomial of the second degree. */ if( n>20&&n<=50 ) { t1 = -1.0/20.0; t2 = -1.0/30.0; t3 = -1.0/50.0; t = -1.0/n; f1 = jarquebera_jbtbl20(x, _state); f2 = jarquebera_jbtbl30(x, _state); f3 = jarquebera_jbtbl50(x, _state); f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } /* * N = 50, 65, 100 are tabulated. * In-between values are interpolated * using interpolating polynomial of the second degree. */ if( n>50&&n<=100 ) { t1 = -1.0/50.0; t2 = -1.0/65.0; t3 = -1.0/100.0; t = -1.0/n; f1 = jarquebera_jbtbl50(x, _state); f2 = jarquebera_jbtbl65(x, _state); f3 = jarquebera_jbtbl100(x, _state); f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } /* * N = 100, 130, 200 are tabulated. * In-between values are interpolated * using interpolating polynomial of the second degree. */ if( n>100&&n<=200 ) { t1 = -1.0/100.0; t2 = -1.0/130.0; t3 = -1.0/200.0; t = -1.0/n; f1 = jarquebera_jbtbl100(x, _state); f2 = jarquebera_jbtbl130(x, _state); f3 = jarquebera_jbtbl200(x, _state); f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } /* * N = 200, 301, 501 are tabulated. * In-between values are interpolated * using interpolating polynomial of the second degree. */ if( n>200&&n<=501 ) { t1 = -1.0/200.0; t2 = -1.0/301.0; t3 = -1.0/501.0; t = -1.0/n; f1 = jarquebera_jbtbl200(x, _state); f2 = jarquebera_jbtbl301(x, _state); f3 = jarquebera_jbtbl501(x, _state); f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } /* * N = 501, 701, 1401 are tabulated. * In-between values are interpolated * using interpolating polynomial of the second degree. */ if( n>501&&n<=1401 ) { t1 = -1.0/501.0; t2 = -1.0/701.0; t3 = -1.0/1401.0; t = -1.0/n; f1 = jarquebera_jbtbl501(x, _state); f2 = jarquebera_jbtbl701(x, _state); f3 = jarquebera_jbtbl1401(x, _state); f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } /* * Asymptotic expansion */ if( n>1401 ) { result = -0.5*x+(jarquebera_jbtbl1401(x, _state)+0.5*x)*ae_sqrt((double)1401/(double)n, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } result = ae_exp(result, _state); ae_frame_leave(_state); return result; } ae_frame_leave(_state); return result; } static double jarquebera_jbtbl5(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,0.4000) ) { x = 2*(s-0.000000)/0.400000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.097885e-20, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.854501e-20, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.756616e-20, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,1.1000) ) { x = 2*(s-0.400000)/0.700000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.324545e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.075941e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.772272e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.175686e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.576162e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.126861e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.434425e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.790359e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.809178e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.479704e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.717040e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.294170e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.880632e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.023344e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.601531e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.920403e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -5.188419e+02*(s-1.100000e+00)-4.767297e+00; return result; } static double jarquebera_jbtbl6(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,0.2500) ) { x = 2*(s-0.000000)/0.250000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.274707e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.700471e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.425764e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,1.3000) ) { x = 2*(s-0.250000)/1.050000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.339000e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.011104e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.168177e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.085666e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.738606e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.022876e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.462402e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.908270e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.230772e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.006996e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.410222e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.893768e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.114564e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,1.8500) ) { x = 2*(s-1.300000)/0.550000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.794311e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.578700e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.394664e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.928290e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.813273e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.076063e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.835380e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.013013e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.058903e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.856915e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.710887e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.770029e+02*(s-1.850000e+00)-1.371015e+01; return result; } static double jarquebera_jbtbl7(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.4000) ) { x = 2*(s-0.000000)/1.400000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.093681e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.695911e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.473192e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.203236e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.590379e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.291876e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.132007e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.411147e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.180067e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.487610e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.436561e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-1.400000)/1.600000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.947854e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.772675e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.707912e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.691171e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.132795e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.481310e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.867536e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.772327e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.033387e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.378277e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.497964e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.636814e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.581640e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,3.2000) ) { x = 2*(s-3.000000)/0.200000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -7.511008e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.895025e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.824116e+03*(s-3.200000e+00)-1.440330e+01; return result; } static double jarquebera_jbtbl8(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.3000) ) { x = 2*(s-0.000000)/1.300000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -7.199015e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.095921e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.736828e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.047438e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.484320e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.937923e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.810470e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.139780e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.708443e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,2.0000) ) { x = 2*(s-1.300000)/0.700000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.378966e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.802461e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.547593e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.241042e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.203274e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.201990e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.125597e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.584426e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.546069e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,5.0000) ) { x = 2*(s-2.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.828366e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.137533e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.016671e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.745637e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.189801e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.621610e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.741122e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.516368e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.552085e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.787029e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.359774e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -5.087028e+00*(s-5.000000e+00)-1.071300e+01; return result; } static double jarquebera_jbtbl9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.3000) ) { x = 2*(s-0.000000)/1.300000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.279320e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.277151e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.669339e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.086149e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.333816e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.871249e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.007048e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.482245e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.355615e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,2.0000) ) { x = 2*(s-1.300000)/0.700000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.981430e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.972248e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.747737e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.808530e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.888305e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.001302e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.378767e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.108510e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.915372e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,7.0000) ) { x = 2*(s-2.000000)/5.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.387463e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.845231e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.809956e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.543461e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.880397e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.160074e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.356527e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.394428e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.619892e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.758763e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.790977e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.020952e+00*(s-7.000000e+00)-9.516623e+00; return result; } static double jarquebera_jbtbl10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.2000) ) { x = 2*(s-0.000000)/1.200000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.590993e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.562730e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.353934e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.069933e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.849151e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.931406e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.636295e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.178340e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.917749e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,2.0000) ) { x = 2*(s-1.200000)/0.800000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.537658e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.962401e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.838715e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.055792e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.580316e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.781701e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.770362e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.838983e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.999052e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,7.0000) ) { x = 2*(s-2.000000)/5.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.337524e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.877029e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.734650e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.249254e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.320250e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.432266e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -8.711035e-01*(s-7.000000e+00)-7.212811e+00; return result; } static double jarquebera_jbtbl11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.2000) ) { x = 2*(s-0.000000)/1.200000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.339517e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.051558e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.000992e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.022547e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.808401e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.592870e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.575081e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.086173e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.089011e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,2.2500) ) { x = 2*(s-1.200000)/1.050000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.523221e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.068388e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.179661e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.555524e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.238964e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.364320e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.895771e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.762774e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.201340e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,8.0000) ) { x = 2*(s-2.250000)/5.750000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.212179e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.684579e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.299519e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.606261e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.310869e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.320115e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -5.715445e-01*(s-8.000000e+00)-6.845834e+00; return result; } static double jarquebera_jbtbl12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.0000) ) { x = 2*(s-0.000000)/1.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.736742e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.657836e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.047209e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.319599e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.545631e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.280445e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.815679e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.213519e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.256838e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-1.000000)/2.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.573947e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.515287e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.611880e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.271311e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.495815e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.141186e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.180886e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.388211e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.890761e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.233175e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.946156e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,12.0000) ) { x = 2*(s-3.000000)/9.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.947819e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.034157e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.878986e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.078603e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.990977e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.866215e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.897866e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.512252e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.073743e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.022621e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.501343e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.877243e-01*(s-1.200000e+01)-7.936839e+00; return result; } static double jarquebera_jbtbl13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.0000) ) { x = 2*(s-0.000000)/1.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.713276e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.557541e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.459092e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.044145e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.546132e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.002374e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.349456e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.025669e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.590242e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-1.000000)/2.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.454383e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.467539e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.270774e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.075763e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.611647e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.990785e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.109212e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.135031e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.915919e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.522390e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.144701e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,13.0000) ) { x = 2*(s-3.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.736127e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.920809e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.175858e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.002049e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.158966e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.157781e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.762172e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.780347e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.193310e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.442421e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.547756e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.799944e-01*(s-1.300000e+01)-7.566269e+00; return result; } static double jarquebera_jbtbl14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,1.0000) ) { x = 2*(s-0.000000)/1.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.698527e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.479081e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.640733e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.466899e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.469485e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.150009e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.965975e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.710210e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.327808e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-1.000000)/2.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -2.350359e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.421365e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.960468e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.149167e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.361109e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.976022e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.082700e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.563328e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.453123e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.917559e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.151067e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-3.000000)/12.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.746892e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.010441e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.566146e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.129690e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.929724e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.524227e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.192933e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.254730e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.620685e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.289618e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.112350e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.590621e-01*(s-1.500000e+01)-7.632238e+00; return result; } static double jarquebera_jbtbl15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,2.0000) ) { x = 2*(s-0.000000)/2.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.043660e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.361653e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.009497e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.951784e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.377903e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.003253e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.271309e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,5.0000) ) { x = 2*(s-2.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.582778e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.349578e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.476514e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.717385e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.222591e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.635124e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.815993e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,17.0000) ) { x = 2*(s-5.000000)/12.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.115476e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.655936e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.404310e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.663794e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.868618e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.381447e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.444801e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.581503e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.468696e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.728509e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.206470e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.927937e-01*(s-1.700000e+01)-7.700983e+00; return result; } static double jarquebera_jbtbl16(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,2.0000) ) { x = 2*(s-0.000000)/2.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.002570e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.298141e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.832803e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.877026e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.539436e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.439658e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.756911e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,5.0000) ) { x = 2*(s-2.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.486198e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.242944e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.020002e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.130531e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.512373e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.054876e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.556839e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,20.0000) ) { x = 2*(s-5.000000)/15.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.241608e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.832655e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.340545e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.361143e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.283219e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.484549e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.805968e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.057243e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.454439e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.177513e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.819209e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.391580e-01*(s-2.000000e+01)-7.963205e+00; return result; } static double jarquebera_jbtbl17(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-0.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.566973e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.810330e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.840039e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.337294e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.383549e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.556515e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.656965e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.404569e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.447867e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,6.0000) ) { x = 2*(s-3.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.905684e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.222920e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.146667e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.809176e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.057028e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.211838e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.099683e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.161105e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.225465e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,24.0000) ) { x = 2*(s-6.000000)/18.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.594282e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.917838e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.455980e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.999589e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.604263e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.484445e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.819937e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.930390e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.771761e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.232581e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.029083e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.127771e-01*(s-2.400000e+01)-8.400197e+00; return result; } static double jarquebera_jbtbl18(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-0.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.526802e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.762373e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.598890e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.189437e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.971721e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.823067e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.064501e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.014932e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.953513e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,6.0000) ) { x = 2*(s-3.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.818669e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.070918e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.277196e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.879817e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.887357e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.638451e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.502800e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.165796e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.034960e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,20.0000) ) { x = 2*(s-6.000000)/14.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.010656e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.496296e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.002227e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.338250e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.137036e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.586202e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.736384e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.332251e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.877982e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.160963e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.547247e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.684623e-01*(s-2.000000e+01)-7.428883e+00; return result; } static double jarquebera_jbtbl19(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,3.0000) ) { x = 2*(s-0.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.490213e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.719633e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.459123e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.034878e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.113868e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.030922e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.054022e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.525623e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.277360e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,6.0000) ) { x = 2*(s-3.000000)/3.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -3.744750e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.977749e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.223716e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.363889e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.711774e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.557257e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.254794e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.034207e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.498107e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,20.0000) ) { x = 2*(s-6.000000)/14.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.872768e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.430689e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.136575e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.726627e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.421110e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.581510e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.559520e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.838208e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.428839e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.170682e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.006647e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.539373e-01*(s-2.000000e+01)-7.206941e+00; return result; } static double jarquebera_jbtbl20(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.854794e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.948947e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.632184e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.139397e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.006237e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.810031e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.573620e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.951242e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.274092e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.464196e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.882139e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.575144e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.822804e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.061348e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.908404e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.978353e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.030989e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.327151e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.346404e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.840051e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.578551e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.813886e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.905973e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.358489e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.450795e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.941157e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.432418e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.070537e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.375654e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.367378e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.890859e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.679782e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -7.015854e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.487737e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.244254e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.318007e-01*(s-2.500000e+01)-7.742185e+00; return result; } static double jarquebera_jbtbl30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.630822e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.724298e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.872756e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.658268e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.573597e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.994157e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.994825e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.394303e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.785029e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.990264e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.037838e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.755546e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.774473e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.821395e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.392603e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.353313e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.539322e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.197018e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.396848e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.804293e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.867928e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.768758e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.211792e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.925799e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.046235e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.536469e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.489642e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.263462e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.177316e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.590637e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.028212e-01*(s-2.500000e+01)-6.855288e+00; return result; } static double jarquebera_jbtbl50(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.436279e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.519711e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.148699e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.001204e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.207620e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.034778e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.220322e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.033260e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.588280e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.851653e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.287733e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.234645e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.189127e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.429738e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.058822e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 9.086776e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.445783e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.311671e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.261298e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.496987e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.605249e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.162282e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.921095e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.888603e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.080113e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -9.313116e-02*(s-2.500000e+01)-6.479154e+00; return result; } static double jarquebera_jbtbl65(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.360024e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.434631e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.514580e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 7.332038e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.158197e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.121233e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.051056e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.148601e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.214233e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.487977e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.424720e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.116715e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.043152e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.718149e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.313701e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.097305e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.181031e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.256975e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.858951e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.895179e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.933237e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -9.443768e-02*(s-2.500000e+01)-6.419137e+00; return result; } static double jarquebera_jbtbl100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.257021e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.313418e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.628931e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.264287e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.518487e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.499826e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.836044e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.056508e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.279690e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.665746e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.290012e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.487632e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.704465e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.211669e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.866099e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.399767e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.498208e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.080097e-01*(s-2.500000e+01)-6.481094e+00; return result; } static double jarquebera_jbtbl130(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.207999e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.253864e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.618032e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.112729e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.210546e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.732602e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.410527e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.026324e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.331990e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.779129e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.674749e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.669077e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.679136e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 8.833221e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -5.893951e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.475304e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.116734e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.045722e-01*(s-2.500000e+01)-6.510314e+00; return result; } static double jarquebera_jbtbl200(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.146155e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.177398e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.297970e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.869745e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.717288e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.982108e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.427636e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.034235e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.455006e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.942996e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.973795e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.418812e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.156778e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.896705e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.086071e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.152176e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.725393e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.132404e-01*(s-2.500000e+01)-6.764034e+00; return result; } static double jarquebera_jbtbl301(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.104290e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.125800e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.595847e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.219666e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.502210e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.414543e-05, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.754115e-05, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.065955e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.582060e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.004472e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -4.709092e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.105779e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.197391e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.386780e-04, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.311384e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.918763e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.626584e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.293626e-01*(s-2.500000e+01)-7.066995e+00; return result; } static double jarquebera_jbtbl501(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.067426e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.079765e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -5.463005e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 6.875659e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.127574e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.740694e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.044502e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.746714e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 3.810594e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.197111e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.628194e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -8.846221e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.386405e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.418332e-01*(s-2.500000e+01)-7.468952e+00; return result; } static double jarquebera_jbtbl701(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.050999e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.059769e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -3.922680e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 4.847054e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.192182e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.860007e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.963942e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.838711e-02, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.893112e-04, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.159788e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -6.917851e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -9.817020e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.383727e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -1.532706e-01*(s-2.500000e+01)-7.845715e+00; return result; } static double jarquebera_jbtbl1401(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); if( ae_fp_less_eq(s,4.0000) ) { x = 2*(s-0.000000)/4.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -1.026266e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.030061e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.259222e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 2.536254e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,15.0000) ) { x = 2*(s-4.000000)/11.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -4.329849e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -2.095443e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 1.759363e-01, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -7.751359e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -6.124368e-03, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.793114e-03, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } if( ae_fp_less_eq(s,25.0000) ) { x = 2*(s-15.000000)/10.000000-1; tj = (double)(1); tj1 = x; jarquebera_jbcheb(x, -7.544330e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, -1.225382e+00, &tj, &tj1, &result, _state); jarquebera_jbcheb(x, 5.392349e-02, &tj, &tj1, &result, _state); if( ae_fp_greater(result,(double)(0)) ) { result = (double)(0); } return result; } result = -2.019375e-01*(s-2.500000e+01)-8.715788e+00; return result; } static void jarquebera_jbcheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state) { double t; *r = *r+c*(*tj); t = 2*x*(*tj1)-(*tj); *tj = *tj1; *tj1 = t; } /************************************************************************* Mann-Whitney U-test This test checks hypotheses about whether X and Y are samples of two continuous distributions of the same shape and same median or whether their medians are different. The following tests are performed: * two-tailed test (null hypothesis - the medians are equal) * left-tailed test (null hypothesis - the median of the first sample is greater than or equal to the median of the second sample) * right-tailed test (null hypothesis - the median of the first sample is less than or equal to the median of the second sample). Requirements: * the samples are independent * X and Y are continuous distributions (or discrete distributions well- approximating continuous distributions) * distributions of X and Y have the same shape. The only possible difference is their position (i.e. the value of the median) * the number of elements in each sample is not less than 5 * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distributions to be normal. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. M>=5 Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with satisfactory accuracy in interval [0.0001, 1]. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. Relative precision of approximation of p-value: N M Max.err. Rms.err. 5..10 N..10 1.4e-02 6.0e-04 5..10 N..100 2.2e-02 5.3e-06 10..15 N..15 1.0e-02 3.2e-04 10..15 N..100 1.0e-02 2.2e-05 15..100 N..100 6.1e-03 2.7e-06 For N,M>100 accuracy checks weren't put into practice, but taking into account characteristics of asymptotic approximation used, precision should not be sharply different from the values for interval [5, 100]. NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, P's outside of this interval are enforced to these bounds. Say, you may quite often get P equal to exactly 0.25 or 0.0001. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/ void mannwhitneyutest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t t; double tmp; ae_int_t tmpi; ae_int_t ns; ae_vector r; ae_vector c; double u; double p; double mp; double s; double sigma; double mu; ae_int_t tiecount; ae_vector tiesize; ae_frame_make(_state, &_frame_block); *bothtails = 0; *lefttail = 0; *righttail = 0; ae_vector_init(&r, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_INT, _state); ae_vector_init(&tiesize, 0, DT_INT, _state); /* * Prepare */ if( n<=4||m<=4 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; ae_frame_leave(_state); return; } ns = n+m; ae_vector_set_length(&r, ns-1+1, _state); ae_vector_set_length(&c, ns-1+1, _state); for(i=0; i<=n-1; i++) { r.ptr.p_double[i] = x->ptr.p_double[i]; c.ptr.p_int[i] = 0; } for(i=0; i<=m-1; i++) { r.ptr.p_double[n+i] = y->ptr.p_double[i]; c.ptr.p_int[n+i] = 1; } /* * sort {R, C} */ if( ns!=1 ) { i = 2; do { t = i; while(t!=1) { k = t/2; if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) { t = 1; } else { tmp = r.ptr.p_double[k-1]; r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; r.ptr.p_double[t-1] = tmp; tmpi = c.ptr.p_int[k-1]; c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; c.ptr.p_int[t-1] = tmpi; t = k; } } i = i+1; } while(i<=ns); i = ns-1; do { tmp = r.ptr.p_double[i]; r.ptr.p_double[i] = r.ptr.p_double[0]; r.ptr.p_double[0] = tmp; tmpi = c.ptr.p_int[i]; c.ptr.p_int[i] = c.ptr.p_int[0]; c.ptr.p_int[0] = tmpi; t = 1; while(t!=0) { k = 2*t; if( k>i ) { t = 0; } else { if( k=1); } /* * compute tied ranks */ i = 0; tiecount = 0; ae_vector_set_length(&tiesize, ns-1+1, _state); while(i<=ns-1) { j = i+1; while(j<=ns-1) { if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) { break; } j = j+1; } for(k=i; k<=j-1; k++) { r.ptr.p_double[k] = 1+(double)(i+j-1)/(double)2; } tiesize.ptr.p_int[tiecount] = j-i; tiecount = tiecount+1; i = j; } /* * Compute U */ u = (double)(0); for(i=0; i<=ns-1; i++) { if( c.ptr.p_int[i]==0 ) { u = u+r.ptr.p_double[i]; } } u = n*m+n*(n+1)/2-u; /* * Result */ mu = (double)(n*m)/(double)2; tmp = ns*(ae_sqr((double)(ns), _state)-1)/12; for(i=0; i<=tiecount-1; i++) { tmp = tmp-tiesize.ptr.p_int[i]*(ae_sqr((double)(tiesize.ptr.p_int[i]), _state)-1)/12; } sigma = ae_sqrt((double)(m*n)/(double)ns/(ns-1)*tmp, _state); s = (u-mu)/sigma; if( ae_fp_less_eq(s,(double)(0)) ) { p = ae_exp(mannwhitneyu_usigma(-(u-mu)/sigma, n, m, _state), _state); mp = 1-ae_exp(mannwhitneyu_usigma(-(u-1-mu)/sigma, n, m, _state), _state); } else { mp = ae_exp(mannwhitneyu_usigma((u-mu)/sigma, n, m, _state), _state); p = 1-ae_exp(mannwhitneyu_usigma((u+1-mu)/sigma, n, m, _state), _state); } *bothtails = boundval(ae_maxreal(2*ae_minreal(p, mp, _state), 1.0E-4, _state), 0.0001, 0.2500, _state); *lefttail = boundval(ae_maxreal(mp, 1.0E-4, _state), 0.0001, 0.2500, _state); *righttail = boundval(ae_maxreal(p, 1.0E-4, _state), 0.0001, 0.2500, _state); ae_frame_leave(_state); } /************************************************************************* Sequential Chebyshev interpolation. *************************************************************************/ static void mannwhitneyu_ucheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state) { double t; *r = *r+c*(*tj); t = 2*x*(*tj1)-(*tj); *tj = *tj1; *tj1 = t; } /************************************************************************* Three-point polynomial interpolation. *************************************************************************/ static double mannwhitneyu_uninterpolate(double p1, double p2, double p3, ae_int_t n, ae_state *_state) { double t1; double t2; double t3; double t; double p12; double p23; double result; t1 = 1.0/15.0; t2 = 1.0/30.0; t3 = 1.0/100.0; t = 1.0/n; p12 = ((t-t2)*p1+(t1-t)*p2)/(t1-t2); p23 = ((t-t3)*p2+(t2-t)*p3)/(t2-t3); result = ((t-t3)*p12+(t1-t)*p23)/(t1-t3); return result; } /************************************************************************* Tail(0, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma000(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-6.76984e-01, -6.83700e-01, -6.89873e-01, n2, _state); p2 = mannwhitneyu_uninterpolate(-6.83700e-01, -6.87311e-01, -6.90957e-01, n2, _state); p3 = mannwhitneyu_uninterpolate(-6.89873e-01, -6.90957e-01, -6.92175e-01, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(0.75, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma075(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-1.44500e+00, -1.45906e+00, -1.47063e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-1.45906e+00, -1.46856e+00, -1.47644e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-1.47063e+00, -1.47644e+00, -1.48100e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(1.5, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma150(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-2.65380e+00, -2.67352e+00, -2.69011e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-2.67352e+00, -2.68591e+00, -2.69659e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-2.69011e+00, -2.69659e+00, -2.70192e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(2.25, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma225(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-4.41465e+00, -4.42260e+00, -4.43702e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-4.42260e+00, -4.41639e+00, -4.41928e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-4.43702e+00, -4.41928e+00, -4.41030e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(3.0, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma300(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-6.89839e+00, -6.83477e+00, -6.82340e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-6.83477e+00, -6.74559e+00, -6.71117e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-6.82340e+00, -6.71117e+00, -6.64929e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(3.33, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma333(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-8.31272e+00, -8.17096e+00, -8.13125e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-8.17096e+00, -8.00156e+00, -7.93245e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-8.13125e+00, -7.93245e+00, -7.82502e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(3.66, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma367(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-9.98837e+00, -9.70844e+00, -9.62087e+00, n2, _state); p2 = mannwhitneyu_uninterpolate(-9.70844e+00, -9.41156e+00, -9.28998e+00, n2, _state); p3 = mannwhitneyu_uninterpolate(-9.62087e+00, -9.28998e+00, -9.11686e+00, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(4.0, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma400(ae_int_t n1, ae_int_t n2, ae_state *_state) { double p1; double p2; double p3; double result; p1 = mannwhitneyu_uninterpolate(-1.20250e+01, -1.14911e+01, -1.13231e+01, n2, _state); p2 = mannwhitneyu_uninterpolate(-1.14911e+01, -1.09927e+01, -1.07937e+01, n2, _state); p3 = mannwhitneyu_uninterpolate(-1.13231e+01, -1.07937e+01, -1.05285e+01, n2, _state); result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); return result; } /************************************************************************* Tail(S, 5, 5) *************************************************************************/ static double mannwhitneyu_utbln5n5(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/2.611165e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -2.596264e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.412086e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.858542e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.614282e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.372686e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.524731e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.435331e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.284665e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.184141e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.298360e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 7.447272e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.938769e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.276205e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.138481e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.684625e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.558104e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 6) *************************************************************************/ static double mannwhitneyu_utbln5n6(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/2.738613e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -2.810459e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.684429e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.712858e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.009324e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.644391e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.034173e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.953498e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.279293e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.563485e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.971952e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.506309e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.541406e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.283205e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.016347e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.221626e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.286752e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 7) *************************************************************************/ static double mannwhitneyu_utbln5n7(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/2.841993e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -2.994677e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.923264e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.506190e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.054280e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.794587e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.726290e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.534180e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.517845e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.904428e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.882443e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.482988e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.114875e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.515082e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.996056e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.293581e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.349444e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 8) *************************************************************************/ static double mannwhitneyu_utbln5n8(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/2.927700e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.155727e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.135078e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.247203e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.309697e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.993725e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.567219e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.383704e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.002188e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.487322e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.443899e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.688270e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.600339e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.874948e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.811593e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.072353e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.659457e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 9) *************************************************************************/ static double mannwhitneyu_utbln5n9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.298162e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.325016e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.939852e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.563029e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.222652e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.195200e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.445665e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.204792e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.775217e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.527781e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.221948e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.242968e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.607959e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.771285e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.694026e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.481190e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 10) *************************************************************************/ static double mannwhitneyu_utbln5n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.061862e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.425360e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.496710e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.587658e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.812005e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.427637e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.515702e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.406867e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.796295e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.237591e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.654249e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.181165e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.011665e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.417927e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.534880e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.791255e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.871512e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 11) *************************************************************************/ static double mannwhitneyu_utbln5n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.115427e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.539959e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.652998e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.196503e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.054363e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.618848e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.109411e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.786668e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.215648e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.484220e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.935991e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.396191e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.894177e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.206979e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.519055e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.210326e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.189679e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 12) *************************************************************************/ static double mannwhitneyu_utbln5n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.162278e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.644007e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.796173e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.771177e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.290043e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.794686e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.702110e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.185959e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.416259e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.592056e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.201530e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.754365e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.978945e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.012032e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.304579e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.100378e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.728269e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 13) *************************************************************************/ static double mannwhitneyu_utbln5n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.203616e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.739120e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.928117e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.031605e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.519403e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.962648e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.292183e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.809293e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.465156e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.456278e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.446055e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.109490e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.218256e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.941479e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.058603e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.824402e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.830947e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 14) *************************************************************************/ static double mannwhitneyu_utbln5n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.240370e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.826559e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.050370e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.083408e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.743164e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.012030e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.884686e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.059656e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.327521e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.134026e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.584201e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.440618e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.524133e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.990007e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.887334e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.534977e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.705395e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 15) *************************************************************************/ static double mannwhitneyu_utbln5n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.851572e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.082033e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.095983e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.814595e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.073148e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.420213e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.517175e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.344180e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.371393e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.711443e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.228569e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.683483e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.267112e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.156044e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.131316e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.301023e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 16) *************************************************************************/ static double mannwhitneyu_utbln5n16(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.852210e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.077482e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.091186e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.797282e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.084994e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.667054e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.843909e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.456732e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.039830e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.723508e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.940608e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.478285e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.649144e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.237703e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.707410e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.874293e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 17) *************************************************************************/ static double mannwhitneyu_utbln5n17(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.851752e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.071259e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.084700e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.758898e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.073846e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.684838e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.964936e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.782442e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.956362e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.984727e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.196936e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.558262e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.690746e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.364855e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.401006e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.546748e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 18) *************************************************************************/ static double mannwhitneyu_utbln5n18(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.850840e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.064799e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.077651e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.712659e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.049217e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.571333e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.929809e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.752044e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.949464e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.896101e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.614460e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.384357e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.489113e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.445725e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.945636e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.424653e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 19) *************************************************************************/ static double mannwhitneyu_utbln5n19(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.850027e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.059159e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.071106e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.669960e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.022780e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.442555e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.851335e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.433865e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.514465e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.332989e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.606099e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.341945e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.402164e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.039761e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.512831e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.284427e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 20) *************************************************************************/ static double mannwhitneyu_utbln5n20(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.849651e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.054729e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.065747e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.636243e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.003234e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.372789e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.831551e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.763090e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.830626e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.122384e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.108328e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.557983e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.945666e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.965696e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.493236e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.162591e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 21) *************************************************************************/ static double mannwhitneyu_utbln5n21(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.849649e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.051155e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.061430e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.608869e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.902788e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.346562e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.874709e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.682887e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.026206e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.534551e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.990575e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.713334e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.737011e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.304571e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.133110e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.123457e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 22) *************************************************************************/ static double mannwhitneyu_utbln5n22(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.849598e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.047605e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.057264e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.579513e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.749602e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.275137e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.881768e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.177374e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.981056e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.696290e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.886803e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.085378e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.675242e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.426367e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.039613e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.662378e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 23) *************************************************************************/ static double mannwhitneyu_utbln5n23(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.849269e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.043761e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.052735e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.544683e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.517503e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.112082e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.782070e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.549483e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.747329e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.694263e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.147141e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.526209e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.039173e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.235615e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.656546e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.014423e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 24) *************************************************************************/ static double mannwhitneyu_utbln5n24(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.848925e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.040178e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.048355e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.510198e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.261134e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.915864e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.627423e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.307345e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.732992e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.869652e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.494176e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.047533e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.178439e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.424171e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.829195e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.840810e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 25) *************************************************************************/ static double mannwhitneyu_utbln5n25(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.848937e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.037512e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.044866e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.483269e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.063682e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.767778e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.508540e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.332756e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.881511e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.124041e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.368456e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.930499e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.779630e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.029528e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.658678e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.289695e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 26) *************************************************************************/ static double mannwhitneyu_utbln5n26(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.849416e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.035915e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.042493e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.466021e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.956432e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.698914e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.465689e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.035254e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.674614e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.492734e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.014021e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.944953e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.255750e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.075841e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.989330e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.134862e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 27) *************************************************************************/ static double mannwhitneyu_utbln5n27(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.850070e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.034815e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.040650e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.453117e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.886426e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.661702e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.452346e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.002476e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.720126e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.001400e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.729826e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.740640e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.206333e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.366093e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.193471e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.804091e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 28) *************************************************************************/ static double mannwhitneyu_utbln5n28(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.850668e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.033786e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.038853e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.440281e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.806020e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.612883e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.420436e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.787982e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.535230e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.263121e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.849609e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.863967e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.391610e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.720294e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.952273e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.901413e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 29) *************************************************************************/ static double mannwhitneyu_utbln5n29(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.851217e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.032834e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.037113e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.427762e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.719146e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.557172e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.375498e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.452033e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.187516e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.916936e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.065533e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.067301e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.615824e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.432244e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.417795e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.710038e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 30) *************************************************************************/ static double mannwhitneyu_utbln5n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.851845e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.032148e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.035679e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.417758e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.655330e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.522132e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.352106e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.326911e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.064969e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.813321e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.683881e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.813346e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.627085e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.832107e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.519336e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.888530e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 5, 100) *************************************************************************/ static double mannwhitneyu_utbln5n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.877940e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.039324e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.022243e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.305825e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.960119e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.112000e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.138868e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.418164e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.174520e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.489617e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.878301e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.302233e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.054113e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.458862e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.186591e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.623412e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 6) *************************************************************************/ static double mannwhitneyu_utbln6n6(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/2.882307e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.054075e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.998804e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.681518e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.067578e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.709435e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.952661e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.641700e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.304572e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.336275e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.770385e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.401891e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.246148e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.442663e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.502866e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.105855e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.739371e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 7) *************************************************************************/ static double mannwhitneyu_utbln6n7(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.265287e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.274613e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.582352e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.334293e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.915502e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.108091e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.546701e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.298827e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.891501e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.313717e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.989501e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.914594e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.062372e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.158841e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.596443e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.185662e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 8) *************************************************************************/ static double mannwhitneyu_utbln6n8(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.098387e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.450954e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.520462e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.420299e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.604853e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.165840e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.008756e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.723402e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.843521e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.883405e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.720980e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.301709e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.948034e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.776243e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.623736e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.742068e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.796927e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 9) *************************************************************************/ static double mannwhitneyu_utbln6n9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.181981e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.616113e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.741650e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.204487e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.873068e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.446794e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.632286e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.266481e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.280067e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.780687e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.480242e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.592200e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.581019e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.264231e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.347174e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.167535e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.092185e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 10) *************************************************************************/ static double mannwhitneyu_utbln6n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.253957e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.764382e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.942366e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.939896e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.137812e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.720270e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.281070e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.901060e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.824937e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.802812e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.258132e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.233536e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.085530e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.212151e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.001329e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.226048e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.035298e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 11) *************************************************************************/ static double mannwhitneyu_utbln6n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.316625e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.898597e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.125710e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.063297e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.396852e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.990126e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.927977e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.726500e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.858745e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.654590e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.217736e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.989770e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.768493e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.924364e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.140215e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.647914e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.924802e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 12) *************************************************************************/ static double mannwhitneyu_utbln6n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.371709e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.020941e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.294250e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.128842e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.650389e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.248611e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.578510e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.162852e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.746982e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.454209e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.128042e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.936650e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.530794e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.665192e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.994144e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.662249e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.368541e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 13) *************************************************************************/ static double mannwhitneyu_utbln6n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.420526e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.133167e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.450016e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.191088e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.898220e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.050249e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.226901e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.471113e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.007470e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.049420e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.059074e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.881249e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.452780e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.441805e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.787493e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.483957e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.481590e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 14) *************************************************************************/ static double mannwhitneyu_utbln6n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.201268e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.542568e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.226965e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.046029e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.136657e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.786757e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.843748e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.588022e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.253029e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.667188e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.788330e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.474545e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.540494e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.951188e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.863323e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.220904e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 15) *************************************************************************/ static double mannwhitneyu_utbln6n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.195689e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.526567e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.213617e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.975035e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.118480e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.859142e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.083312e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.298720e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.766708e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.026356e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.093113e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.135168e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.136376e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.190870e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.435972e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.413129e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 30) *************************************************************************/ static double mannwhitneyu_utbln6n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.166269e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.427399e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.118239e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.360847e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.745885e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.025041e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.187179e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.432089e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.408451e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.388774e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.795560e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.304136e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.258516e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.180236e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.388679e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.836027e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 6, 100) *************************************************************************/ static double mannwhitneyu_utbln6n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.181350e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.417919e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.094201e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.195883e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.818937e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.514202e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.125047e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.022148e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.284181e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.157766e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.023752e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.127985e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.221690e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.516179e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.501398e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.380220e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 7) *************************************************************************/ static double mannwhitneyu_utbln7n7(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.130495e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.501264e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.584790e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.577311e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.617002e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.145186e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.023462e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.408251e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.626515e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.072492e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.722926e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.095445e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.842602e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.751427e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.008927e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.892431e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.772386e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 8) *************************************************************************/ static double mannwhitneyu_utbln7n8(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.240370e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.709965e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.862154e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.504541e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.900195e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.439995e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.678028e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.485540e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.437047e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.440092e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.114227e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.516569e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.829457e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.787550e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.761866e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.991911e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.533481e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 9) *************************************************************************/ static double mannwhitneyu_utbln7n9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.334314e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.896550e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.112671e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.037277e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.181695e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.765190e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.360116e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.695960e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.780578e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.963843e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.616148e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.852104e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.390744e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.014041e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.888101e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.467474e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.004611e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 10) *************************************************************************/ static double mannwhitneyu_utbln7n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.415650e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.064844e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.340749e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.118888e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.459730e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.097781e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.057688e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.097406e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.209262e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.065641e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.196677e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.313994e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.827157e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.822284e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.389090e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.340850e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.395172e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 11) *************************************************************************/ static double mannwhitneyu_utbln7n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.486817e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.217795e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.549783e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.195905e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.733093e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.428447e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.760093e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.431676e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.717152e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.032199e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.832423e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.905979e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.302799e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.464371e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.456211e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.736244e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.140712e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 12) *************************************************************************/ static double mannwhitneyu_utbln7n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.235822e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.564100e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.190813e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.686546e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.395083e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.967359e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.747096e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.304144e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.903198e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.134906e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.175035e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.266224e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.892931e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.604706e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.070459e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.427010e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 13) *************************************************************************/ static double mannwhitneyu_utbln7n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.222204e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.532300e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.164642e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.523768e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.531984e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.467857e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.483804e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.524136e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.077740e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.745218e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.602085e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.828831e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.994070e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.873879e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.341937e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.706444e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 14) *************************************************************************/ static double mannwhitneyu_utbln7n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.211763e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.507542e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.143640e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.395755e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.808020e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.044259e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.182308e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.057325e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.724255e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.303900e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.113148e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.102514e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.559442e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.634986e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.776476e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.054489e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 15) *************************************************************************/ static double mannwhitneyu_utbln7n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.204898e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.489960e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.129172e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.316741e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.506107e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.983676e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.258013e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.262515e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.984156e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.912108e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.974023e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.056195e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.090842e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.232620e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.816339e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.020421e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 30) *************************************************************************/ static double mannwhitneyu_utbln7n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.176536e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.398705e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.045481e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.821982e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.962304e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.698132e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.062667e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.282353e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.014836e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.035683e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.004137e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.801453e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.920705e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.518735e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.821501e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.801008e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 7, 100) *************************************************************************/ static double mannwhitneyu_utbln7n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.188337e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.386949e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.022834e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.686517e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.323516e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.399392e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.644333e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.617044e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.031396e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.792066e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.675457e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.673416e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.258552e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.174214e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.073644e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.349958e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 8) *************************************************************************/ static double mannwhitneyu_utbln8n8(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.360672e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -3.940217e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.168913e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.051485e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.195325e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.775196e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.385506e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.244902e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.525632e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.771275e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.332874e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.079599e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.882551e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.407944e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.769844e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.062433e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.872535e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 9) *************************************************************************/ static double mannwhitneyu_utbln8n9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.464102e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.147004e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.446939e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.146155e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.488561e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.144561e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.116917e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.205667e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.515661e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.618616e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.599011e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.457324e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.482917e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.488267e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.469823e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.957591e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.058326e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 10) *************************************************************************/ static double mannwhitneyu_utbln8n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.554093e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.334282e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.700860e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.235253e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.778489e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.527324e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.862885e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.589781e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.507355e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.717526e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.215726e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.848696e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.918854e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.219614e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.753761e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.573688e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.602177e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 11) *************************************************************************/ static double mannwhitneyu_utbln8n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.421882e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.812457e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.266153e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.849344e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.971527e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.258944e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.944820e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.894685e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.031836e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.514330e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.351660e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.206748e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.492600e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.005338e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.780099e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.673599e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 12) *************************************************************************/ static double mannwhitneyu_utbln8n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.398211e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.762214e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.226296e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.603837e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.643223e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.502438e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.544574e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.647734e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.442259e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.011484e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.384758e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.998259e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.659985e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.331046e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.638478e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.056785e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 13) *************************************************************************/ static double mannwhitneyu_utbln8n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.380670e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.724511e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.195851e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.420511e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.609928e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.893999e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.115919e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.291410e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.339664e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.801548e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.534710e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.793250e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.806718e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.384624e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.120582e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.936453e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 14) *************************************************************************/ static double mannwhitneyu_utbln8n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.368494e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.697171e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.174440e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.300621e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.087393e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.685826e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.085254e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.525658e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.966647e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.453388e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.826066e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.501958e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.336297e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.251972e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.118456e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.415959e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 15) *************************************************************************/ static double mannwhitneyu_utbln8n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.358397e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.674485e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.155941e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.195780e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.544830e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.426183e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.309902e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.650956e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.068874e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.538544e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.192525e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.073905e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.079673e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.423572e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.579647e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.765904e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 30) *************************************************************************/ static double mannwhitneyu_utbln8n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.318823e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.567159e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.064864e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.688413e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.153712e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.309389e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.226861e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.523815e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.780987e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.166866e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.922431e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.466397e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.690036e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.008185e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.271903e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.534751e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 8, 100) *************************************************************************/ static double mannwhitneyu_utbln8n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.324531e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.547071e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.038129e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.541549e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.525605e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.044992e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.085713e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.017871e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.459226e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.092064e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.024349e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 7.366347e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.385637e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.321722e-08, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.439286e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.058079e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 9) *************************************************************************/ static double mannwhitneyu_utbln9n9(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.576237e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.372857e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.750859e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.248233e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.792868e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.559372e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.894941e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.643256e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.091370e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.285034e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.112997e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.806229e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.150741e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.509825e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.891051e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.485013e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.343653e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 10) *************************************************************************/ static double mannwhitneyu_utbln9n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.516726e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.939333e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.305046e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.935326e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.029141e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.420592e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.053140e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.065930e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.523581e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.544888e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.813741e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.510631e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.536057e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.833815e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.189692e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.615050e-03, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 11) *************************************************************************/ static double mannwhitneyu_utbln9n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.481308e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.867483e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.249072e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.591790e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.400128e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.341992e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.463680e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.487211e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.671196e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.343472e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.544146e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.802335e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.117084e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.217443e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.858766e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.193687e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 12) *************************************************************************/ static double mannwhitneyu_utbln9n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.456776e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.817037e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.209788e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.362108e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.171356e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.661557e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.026141e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.361908e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.093885e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.298389e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.663603e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.768522e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.579015e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.868677e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.440652e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.523037e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 13) *************************************************************************/ static double mannwhitneyu_utbln9n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.438840e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.779308e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.180614e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.196489e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.346621e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.234857e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.796211e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.575715e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.525647e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.964651e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.275235e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.299124e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.397416e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.295781e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.237619e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 7.269692e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 14) *************************************************************************/ static double mannwhitneyu_utbln9n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.425981e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.751545e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.159543e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.086570e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.917446e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.120112e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.175519e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.515473e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.727772e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.070629e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.677569e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.876953e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.233502e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.508182e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.120389e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.847212e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 15) *************************************************************************/ static double mannwhitneyu_utbln9n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.414952e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.727612e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.140634e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.981231e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.382635e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.853575e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.571051e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.567625e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.214197e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.448700e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.712669e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.015050e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.438610e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.301363e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.309386e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.164772e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 30) *************************************************************************/ static double mannwhitneyu_utbln9n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.370720e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.615712e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.050023e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.504775e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.318265e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.646826e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.741492e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.735360e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.966911e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.100738e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.348991e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.527687e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.917286e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.397466e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.360175e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.892252e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 9, 100) *************************************************************************/ static double mannwhitneyu_utbln9n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.372506e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.590966e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.021758e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.359849e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.755519e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.533166e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.936659e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.634913e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.730053e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.791845e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.030682e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.228663e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.631175e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.636749e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.404599e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.789872e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 10) *************************************************************************/ static double mannwhitneyu_utbln10n10(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.468831e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.844398e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.231728e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.486073e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.781321e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.971425e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.215371e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.828451e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.419872e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.430165e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.740363e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.049211e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.269371e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.211393e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.232314e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.016081e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 11) *************************************************************************/ static double mannwhitneyu_utbln10n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.437998e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.782296e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.184732e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.219585e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.457012e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.296008e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.481501e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.527940e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.953426e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.563840e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.574403e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.535775e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.338037e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.002654e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.852676e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.318132e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 12) *************************************************************************/ static double mannwhitneyu_utbln10n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.416082e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.737458e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.150952e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.036884e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.609030e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.908684e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.439666e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.162647e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.451601e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.148757e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.803981e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.731621e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.346903e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.013151e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.956148e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.438381e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 13) *************************************************************************/ static double mannwhitneyu_utbln10n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.399480e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.702863e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.124829e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.897428e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.979802e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.634368e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.180461e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.484926e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.864376e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.186576e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.886925e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.836828e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.074756e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.209547e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.883266e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.380143e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 14) *************************************************************************/ static double mannwhitneyu_utbln10n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.386924e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.676124e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.104740e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.793826e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.558886e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.492462e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.052903e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.917782e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.878696e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.576046e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.764551e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.288778e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.757658e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.299101e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.265197e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.384503e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 15) *************************************************************************/ static double mannwhitneyu_utbln10n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.376846e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.654247e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.088083e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.705945e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.169677e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.317213e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.264836e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.548024e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.633910e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.505621e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.658588e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.320254e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.175277e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.122317e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.675688e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.661363e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 30) *************************************************************************/ static double mannwhitneyu_utbln10n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.333977e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.548099e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.004444e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.291014e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.523674e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.828211e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.716917e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.894256e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.433371e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.522675e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.764192e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.140235e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.629230e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.541895e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.944946e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.726360e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 10, 100) *************************************************************************/ static double mannwhitneyu_utbln10n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.334008e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.522316e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.769627e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.158110e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.053650e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.242235e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.173571e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.033661e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.824732e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.084420e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.610036e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.728155e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.217130e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.340966e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.001235e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.694052e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 11) *************************************************************************/ static double mannwhitneyu_utbln11n11(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.519760e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.880694e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.200698e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.174092e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.072304e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.054773e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.506613e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.813942e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.223644e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.417416e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.499166e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.194332e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 7.369096e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.968590e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.630532e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.061000e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 12) *************************************************************************/ static double mannwhitneyu_utbln11n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.495790e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.832622e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.165420e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.987306e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.265621e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.723537e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.347406e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.353464e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.613369e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.102522e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.237709e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.665652e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.626903e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.167518e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.564455e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.047320e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 13) *************************************************************************/ static double mannwhitneyu_utbln11n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.477880e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.796242e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.138769e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.851739e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.722104e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.548304e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.176683e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.817895e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.842451e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.935870e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.421777e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.238831e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.867026e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.458255e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.306259e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.961487e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 14) *************************************************************************/ static double mannwhitneyu_utbln11n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.463683e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.766969e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.117082e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.739574e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.238865e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.350306e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.425871e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.640172e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.660633e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.879883e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.349658e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.271795e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.304544e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.024201e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.816867e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.596787e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 15) *************************************************************************/ static double mannwhitneyu_utbln11n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.452526e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.743570e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.099705e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.650612e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.858285e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.187036e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.689241e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.294360e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.072623e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.278008e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.322382e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.131558e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.305669e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.825627e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.332689e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.120973e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 30) *************************************************************************/ static double mannwhitneyu_utbln11n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.402621e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.627440e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.011333e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.224126e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.232856e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.859347e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.377381e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.756709e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.033230e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.875472e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.608399e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.102943e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.740693e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.343139e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.196878e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.658062e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 11, 100) *************************************************************************/ static double mannwhitneyu_utbln11n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.398795e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.596486e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.814761e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.085187e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.766529e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.379425e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.986351e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.214705e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.360075e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.260869e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.033307e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.727087e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.393883e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.242989e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.111928e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.898823e-09, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 12) *************************************************************************/ static double mannwhitneyu_utbln12n12(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.472616e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.786627e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.132099e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.817523e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.570179e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.479511e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.799492e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.565350e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.530139e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.380132e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.242761e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.576269e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.018771e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.933911e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.002799e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.022048e-06, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 13) *************************************************************************/ static double mannwhitneyu_utbln12n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.454800e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.750794e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.105988e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.684754e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.011826e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.262579e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.044492e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.478741e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.322165e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.621104e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.068753e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.468396e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.056235e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.327375e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.914877e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.784191e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 14) *************************************************************************/ static double mannwhitneyu_utbln12n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.440910e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.722404e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.085254e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.579439e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.563738e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.066730e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.129346e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.014531e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.129679e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.000909e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.996174e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.377924e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.936304e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.051098e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.025820e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 8.730585e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 15) *************************************************************************/ static double mannwhitneyu_utbln12n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.430123e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.700008e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.068971e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.499725e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.250897e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.473145e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.680008e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.483350e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.766992e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.891081e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.015140e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.977756e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.707414e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.114786e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.238865e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.381445e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 30) *************************************************************************/ static double mannwhitneyu_utbln12n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.380023e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.585782e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.838583e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.103394e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.834015e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.635212e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.948212e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.574169e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.747980e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.833672e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.722433e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.181038e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.206473e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.716003e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.476434e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.217700e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 12, 100) *************************************************************************/ static double mannwhitneyu_utbln12n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.374567e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.553481e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.541334e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.701907e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.414757e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.404103e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.234388e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.453762e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.311060e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.317501e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.713888e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.309583e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.019804e-08, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.224829e-09, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.349019e-08, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.893302e-08, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 13, 13) *************************************************************************/ static double mannwhitneyu_utbln13n13(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.541046e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.859047e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.130164e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.689719e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.950693e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.231455e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.976550e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.538455e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.245603e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.142647e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.831434e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.032483e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.488405e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.156927e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.949279e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.532700e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 13, 14) *************************************************************************/ static double mannwhitneyu_utbln13n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.525655e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.828341e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.108110e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.579552e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.488307e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.032328e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.988741e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.766394e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.388950e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.338179e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.133440e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.023518e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.110570e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.202332e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.056132e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.536323e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 13, 15) *************************************************************************/ static double mannwhitneyu_utbln13n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.513585e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.803952e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.090686e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.495310e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.160314e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.073124e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.480313e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.478239e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.140914e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.311541e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.677105e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.115464e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.578563e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.044604e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.888939e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 2.395644e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 13, 30) *************************************************************************/ static double mannwhitneyu_utbln13n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.455999e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.678434e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.995491e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.078100e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.705220e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.258739e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.671526e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.185458e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.507764e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.411446e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.044355e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.285765e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.345282e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.066940e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.962037e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.723644e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 13, 100) *************************************************************************/ static double mannwhitneyu_utbln13n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.446787e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.640804e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.671552e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.364990e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.274444e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.047440e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.161439e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.171729e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.562171e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.359762e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.275494e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.747635e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.700292e-08, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.565559e-09, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 5.005396e-09, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 3.335794e-09, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 14, 14) *************************************************************************/ static double mannwhitneyu_utbln14n14(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.510624e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.798584e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.087107e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.478532e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.098050e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.855986e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.409083e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.299536e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.176177e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.479417e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.812761e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -5.225872e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 4.516521e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 6.730551e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 9.237563e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.611820e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 14, 15) *************************************************************************/ static double mannwhitneyu_utbln14n15(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.498681e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.774668e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.070267e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.399348e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.807239e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.845763e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.071773e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.261698e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.011695e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.305946e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.879295e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.999439e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.904438e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.944986e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.373908e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.140794e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 14, 30) *************************************************************************/ static double mannwhitneyu_utbln14n30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.440378e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.649587e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.807829e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.989753e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.463646e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.586580e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -6.745917e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.635398e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.923172e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.446699e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.613892e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.214073e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.651683e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.272777e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.464988e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.109803e-07, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 14, 100) *************************************************************************/ static double mannwhitneyu_utbln14n100(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; mannwhitneyu_ucheb(x, -4.429701e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -4.610577e+00, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -9.482675e-01, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.605550e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.062151e-02, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.525154e-03, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.835983e-04, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -8.411440e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.744901e-05, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.318850e-06, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.692100e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -1.536270e-07, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -3.705888e-08, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -7.999599e-09, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, -2.908395e-09, &tj, &tj1, &result, _state); mannwhitneyu_ucheb(x, 1.546923e-09, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, N1, N2) *************************************************************************/ static double mannwhitneyu_usigma(double s, ae_int_t n1, ae_int_t n2, ae_state *_state) { double f0; double f1; double f2; double f3; double f4; double s0; double s1; double s2; double s3; double s4; double result; result = (double)(0); /* * N1=5, N2 = 5, 6, 7, ... */ if( ae_minint(n1, n2, _state)==5 ) { if( ae_maxint(n1, n2, _state)==5 ) { result = mannwhitneyu_utbln5n5(s, _state); } if( ae_maxint(n1, n2, _state)==6 ) { result = mannwhitneyu_utbln5n6(s, _state); } if( ae_maxint(n1, n2, _state)==7 ) { result = mannwhitneyu_utbln5n7(s, _state); } if( ae_maxint(n1, n2, _state)==8 ) { result = mannwhitneyu_utbln5n8(s, _state); } if( ae_maxint(n1, n2, _state)==9 ) { result = mannwhitneyu_utbln5n9(s, _state); } if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln5n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln5n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln5n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln5n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln5n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln5n15(s, _state); } if( ae_maxint(n1, n2, _state)==16 ) { result = mannwhitneyu_utbln5n16(s, _state); } if( ae_maxint(n1, n2, _state)==17 ) { result = mannwhitneyu_utbln5n17(s, _state); } if( ae_maxint(n1, n2, _state)==18 ) { result = mannwhitneyu_utbln5n18(s, _state); } if( ae_maxint(n1, n2, _state)==19 ) { result = mannwhitneyu_utbln5n19(s, _state); } if( ae_maxint(n1, n2, _state)==20 ) { result = mannwhitneyu_utbln5n20(s, _state); } if( ae_maxint(n1, n2, _state)==21 ) { result = mannwhitneyu_utbln5n21(s, _state); } if( ae_maxint(n1, n2, _state)==22 ) { result = mannwhitneyu_utbln5n22(s, _state); } if( ae_maxint(n1, n2, _state)==23 ) { result = mannwhitneyu_utbln5n23(s, _state); } if( ae_maxint(n1, n2, _state)==24 ) { result = mannwhitneyu_utbln5n24(s, _state); } if( ae_maxint(n1, n2, _state)==25 ) { result = mannwhitneyu_utbln5n25(s, _state); } if( ae_maxint(n1, n2, _state)==26 ) { result = mannwhitneyu_utbln5n26(s, _state); } if( ae_maxint(n1, n2, _state)==27 ) { result = mannwhitneyu_utbln5n27(s, _state); } if( ae_maxint(n1, n2, _state)==28 ) { result = mannwhitneyu_utbln5n28(s, _state); } if( ae_maxint(n1, n2, _state)==29 ) { result = mannwhitneyu_utbln5n29(s, _state); } if( ae_maxint(n1, n2, _state)>29 ) { f0 = mannwhitneyu_utbln5n15(s, _state); f1 = mannwhitneyu_utbln5n30(s, _state); f2 = mannwhitneyu_utbln5n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=6, N2 = 6, 7, 8, ... */ if( ae_minint(n1, n2, _state)==6 ) { if( ae_maxint(n1, n2, _state)==6 ) { result = mannwhitneyu_utbln6n6(s, _state); } if( ae_maxint(n1, n2, _state)==7 ) { result = mannwhitneyu_utbln6n7(s, _state); } if( ae_maxint(n1, n2, _state)==8 ) { result = mannwhitneyu_utbln6n8(s, _state); } if( ae_maxint(n1, n2, _state)==9 ) { result = mannwhitneyu_utbln6n9(s, _state); } if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln6n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln6n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln6n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln6n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln6n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln6n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln6n15(s, _state); f1 = mannwhitneyu_utbln6n30(s, _state); f2 = mannwhitneyu_utbln6n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=7, N2 = 7, 8, ... */ if( ae_minint(n1, n2, _state)==7 ) { if( ae_maxint(n1, n2, _state)==7 ) { result = mannwhitneyu_utbln7n7(s, _state); } if( ae_maxint(n1, n2, _state)==8 ) { result = mannwhitneyu_utbln7n8(s, _state); } if( ae_maxint(n1, n2, _state)==9 ) { result = mannwhitneyu_utbln7n9(s, _state); } if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln7n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln7n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln7n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln7n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln7n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln7n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln7n15(s, _state); f1 = mannwhitneyu_utbln7n30(s, _state); f2 = mannwhitneyu_utbln7n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=8, N2 = 8, 9, 10, ... */ if( ae_minint(n1, n2, _state)==8 ) { if( ae_maxint(n1, n2, _state)==8 ) { result = mannwhitneyu_utbln8n8(s, _state); } if( ae_maxint(n1, n2, _state)==9 ) { result = mannwhitneyu_utbln8n9(s, _state); } if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln8n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln8n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln8n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln8n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln8n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln8n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln8n15(s, _state); f1 = mannwhitneyu_utbln8n30(s, _state); f2 = mannwhitneyu_utbln8n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=9, N2 = 9, 10, ... */ if( ae_minint(n1, n2, _state)==9 ) { if( ae_maxint(n1, n2, _state)==9 ) { result = mannwhitneyu_utbln9n9(s, _state); } if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln9n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln9n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln9n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln9n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln9n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln9n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln9n15(s, _state); f1 = mannwhitneyu_utbln9n30(s, _state); f2 = mannwhitneyu_utbln9n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=10, N2 = 10, 11, ... */ if( ae_minint(n1, n2, _state)==10 ) { if( ae_maxint(n1, n2, _state)==10 ) { result = mannwhitneyu_utbln10n10(s, _state); } if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln10n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln10n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln10n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln10n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln10n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln10n15(s, _state); f1 = mannwhitneyu_utbln10n30(s, _state); f2 = mannwhitneyu_utbln10n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=11, N2 = 11, 12, ... */ if( ae_minint(n1, n2, _state)==11 ) { if( ae_maxint(n1, n2, _state)==11 ) { result = mannwhitneyu_utbln11n11(s, _state); } if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln11n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln11n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln11n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln11n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln11n15(s, _state); f1 = mannwhitneyu_utbln11n30(s, _state); f2 = mannwhitneyu_utbln11n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=12, N2 = 12, 13, ... */ if( ae_minint(n1, n2, _state)==12 ) { if( ae_maxint(n1, n2, _state)==12 ) { result = mannwhitneyu_utbln12n12(s, _state); } if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln12n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln12n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln12n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln12n15(s, _state); f1 = mannwhitneyu_utbln12n30(s, _state); f2 = mannwhitneyu_utbln12n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=13, N2 = 13, 14, ... */ if( ae_minint(n1, n2, _state)==13 ) { if( ae_maxint(n1, n2, _state)==13 ) { result = mannwhitneyu_utbln13n13(s, _state); } if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln13n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln13n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln13n15(s, _state); f1 = mannwhitneyu_utbln13n30(s, _state); f2 = mannwhitneyu_utbln13n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1=14, N2 = 14, 15, ... */ if( ae_minint(n1, n2, _state)==14 ) { if( ae_maxint(n1, n2, _state)==14 ) { result = mannwhitneyu_utbln14n14(s, _state); } if( ae_maxint(n1, n2, _state)==15 ) { result = mannwhitneyu_utbln14n15(s, _state); } if( ae_maxint(n1, n2, _state)>15 ) { f0 = mannwhitneyu_utbln14n15(s, _state); f1 = mannwhitneyu_utbln14n30(s, _state); f2 = mannwhitneyu_utbln14n100(s, _state); result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); } return result; } /* * N1 >= 15, N2 >= 15 */ if( ae_fp_greater(s,(double)(4)) ) { s = (double)(4); } if( ae_fp_less(s,(double)(3)) ) { s0 = 0.000000e+00; f0 = mannwhitneyu_usigma000(n1, n2, _state); s1 = 7.500000e-01; f1 = mannwhitneyu_usigma075(n1, n2, _state); s2 = 1.500000e+00; f2 = mannwhitneyu_usigma150(n1, n2, _state); s3 = 2.250000e+00; f3 = mannwhitneyu_usigma225(n1, n2, _state); s4 = 3.000000e+00; f4 = mannwhitneyu_usigma300(n1, n2, _state); f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); f4 = ((s-s0)*f4-(s-s4)*f0)/(s4-s0); f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); f4 = ((s-s1)*f4-(s-s4)*f1)/(s4-s1); f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); f4 = ((s-s2)*f4-(s-s4)*f2)/(s4-s2); f4 = ((s-s3)*f4-(s-s4)*f3)/(s4-s3); result = f4; } else { s0 = 3.000000e+00; f0 = mannwhitneyu_usigma300(n1, n2, _state); s1 = 3.333333e+00; f1 = mannwhitneyu_usigma333(n1, n2, _state); s2 = 3.666667e+00; f2 = mannwhitneyu_usigma367(n1, n2, _state); s3 = 4.000000e+00; f3 = mannwhitneyu_usigma400(n1, n2, _state); f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); result = f3; } return result; } /************************************************************************* Sign test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. While calculating p-values high-precision binomial distribution approximation is used, so significance levels have about 15 exact digits. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplesigntest(/* Real */ ae_vector* x, ae_int_t n, double median, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; ae_int_t gtcnt; ae_int_t necnt; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=1 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Calculate: * GTCnt - count of x[i]>Median * NECnt - count of x[i]<>Median */ gtcnt = 0; necnt = 0; for(i=0; i<=n-1; i++) { if( ae_fp_greater(x->ptr.p_double[i],median) ) { gtcnt = gtcnt+1; } if( ae_fp_neq(x->ptr.p_double[i],median) ) { necnt = necnt+1; } } if( necnt==0 ) { /* * all x[i] are equal to Median. * So we can conclude that Median is a true median :) */ *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } *bothtails = ae_minreal(2*binomialdistribution(ae_minint(gtcnt, necnt-gtcnt, _state), necnt, 0.5, _state), 1.0, _state); *lefttail = binomialdistribution(gtcnt, necnt, 0.5, _state); *righttail = binomialcdistribution(gtcnt-1, necnt, 0.5, _state); } /************************************************************************* One-sample t-test This test checks three hypotheses about the mean of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the mean is equal to the given value) * left-tailed test (null hypothesis - the mean is greater than or equal to the given value) * right-tailed test (null hypothesis - the mean is less than or equal to the given value). The test is based on the assumption that a given sample has a normal distribution and an unknown dispersion. If the distribution sharply differs from normal, the test will work incorrectly. INPUT PARAMETERS: X - sample. Array whose index goes from 0 to N-1. N - size of sample, N>=0 Mean - assumed value of the mean. OUTPUT PARAMETERS: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0, all p-values are set to 1.0 * when variance of X[] is exactly zero, p-values are set to 1.0 or 0.0, depending on difference between sample mean and value of mean being tested. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest1(/* Real */ ae_vector* x, ae_int_t n, double mean, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; double xmean; double x0; double v; ae_bool samex; double xvariance; double xstddev; double v1; double v2; double stat; double s; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=0 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Mean */ xmean = (double)(0); x0 = x->ptr.p_double[0]; samex = ae_true; for(i=0; i<=n-1; i++) { v = x->ptr.p_double[i]; xmean = xmean+v; samex = samex&&ae_fp_eq(v,x0); } if( samex ) { xmean = x0; } else { xmean = xmean/n; } /* * Variance (using corrected two-pass algorithm) */ xvariance = (double)(0); xstddev = (double)(0); if( n!=1&&!samex ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-xmean, _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-xmean); } v2 = ae_sqr(v2, _state)/n; xvariance = (v1-v2)/(n-1); if( ae_fp_less(xvariance,(double)(0)) ) { xvariance = (double)(0); } xstddev = ae_sqrt(xvariance, _state); } if( ae_fp_eq(xstddev,(double)(0)) ) { if( ae_fp_eq(xmean,mean) ) { *bothtails = 1.0; } else { *bothtails = 0.0; } if( ae_fp_greater_eq(xmean,mean) ) { *lefttail = 1.0; } else { *lefttail = 0.0; } if( ae_fp_less_eq(xmean,mean) ) { *righttail = 1.0; } else { *righttail = 0.0; } return; } /* * Statistic */ stat = (xmean-mean)/(xstddev/ae_sqrt((double)(n), _state)); s = studenttdistribution(n-1, stat, _state); *bothtails = 2*ae_minreal(s, 1-s, _state); *lefttail = s; *righttail = 1-s; } /************************************************************************* Two-sample pooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * dispersions are equal * samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has exactly zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void studentttest2(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; ae_bool samex; ae_bool samey; double x0; double y0; double xmean; double ymean; double v; double stat; double s; double p; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=0||m<=0 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Mean */ xmean = (double)(0); x0 = x->ptr.p_double[0]; samex = ae_true; for(i=0; i<=n-1; i++) { v = x->ptr.p_double[i]; xmean = xmean+v; samex = samex&&ae_fp_eq(v,x0); } if( samex ) { xmean = x0; } else { xmean = xmean/n; } ymean = (double)(0); y0 = y->ptr.p_double[0]; samey = ae_true; for(i=0; i<=m-1; i++) { v = y->ptr.p_double[i]; ymean = ymean+v; samey = samey&&ae_fp_eq(v,y0); } if( samey ) { ymean = y0; } else { ymean = ymean/m; } /* * S */ s = (double)(0); if( n+m>2 ) { for(i=0; i<=n-1; i++) { s = s+ae_sqr(x->ptr.p_double[i]-xmean, _state); } for(i=0; i<=m-1; i++) { s = s+ae_sqr(y->ptr.p_double[i]-ymean, _state); } s = ae_sqrt(s*((double)1/(double)n+(double)1/(double)m)/(n+m-2), _state); } if( ae_fp_eq(s,(double)(0)) ) { if( ae_fp_eq(xmean,ymean) ) { *bothtails = 1.0; } else { *bothtails = 0.0; } if( ae_fp_greater_eq(xmean,ymean) ) { *lefttail = 1.0; } else { *lefttail = 0.0; } if( ae_fp_less_eq(xmean,ymean) ) { *righttail = 1.0; } else { *righttail = 0.0; } return; } /* * Statistic */ stat = (xmean-ymean)/s; p = studenttdistribution(n+m-2, stat, _state); *bothtails = 2*ae_minreal(p, 1-p, _state); *lefttail = p; *righttail = 1-p; } /************************************************************************* Two-sample unpooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * samples are independent. Equality of variances is NOT required. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. * when only one sample has zero variance, test reduces to 1-sample version. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/ void unequalvariancettest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; ae_bool samex; ae_bool samey; double x0; double y0; double xmean; double ymean; double xvar; double yvar; double v; double df; double p; double stat; double c; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=0||m<=0 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Mean */ xmean = (double)(0); x0 = x->ptr.p_double[0]; samex = ae_true; for(i=0; i<=n-1; i++) { v = x->ptr.p_double[i]; xmean = xmean+v; samex = samex&&ae_fp_eq(v,x0); } if( samex ) { xmean = x0; } else { xmean = xmean/n; } ymean = (double)(0); y0 = y->ptr.p_double[0]; samey = ae_true; for(i=0; i<=m-1; i++) { v = y->ptr.p_double[i]; ymean = ymean+v; samey = samey&&ae_fp_eq(v,y0); } if( samey ) { ymean = y0; } else { ymean = ymean/m; } /* * Variance (using corrected two-pass algorithm) */ xvar = (double)(0); if( n>=2&&!samex ) { for(i=0; i<=n-1; i++) { xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); } xvar = xvar/(n-1); } yvar = (double)(0); if( m>=2&&!samey ) { for(i=0; i<=m-1; i++) { yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); } yvar = yvar/(m-1); } /* * Handle different special cases * (one or both variances are zero). */ if( ae_fp_eq(xvar,(double)(0))&&ae_fp_eq(yvar,(double)(0)) ) { if( ae_fp_eq(xmean,ymean) ) { *bothtails = 1.0; } else { *bothtails = 0.0; } if( ae_fp_greater_eq(xmean,ymean) ) { *lefttail = 1.0; } else { *lefttail = 0.0; } if( ae_fp_less_eq(xmean,ymean) ) { *righttail = 1.0; } else { *righttail = 0.0; } return; } if( ae_fp_eq(xvar,(double)(0)) ) { /* * X is constant, unpooled 2-sample test reduces to 1-sample test. * * NOTE: right-tail and left-tail must be passed to 1-sample * t-test in reverse order because we reverse order of * of samples. */ studentttest1(y, m, xmean, bothtails, righttail, lefttail, _state); return; } if( ae_fp_eq(yvar,(double)(0)) ) { /* * Y is constant, unpooled 2-sample test reduces to 1-sample test. */ studentttest1(x, n, ymean, bothtails, lefttail, righttail, _state); return; } /* * Statistic */ stat = (xmean-ymean)/ae_sqrt(xvar/n+yvar/m, _state); c = xvar/n/(xvar/n+yvar/m); df = (n-1)*(m-1)/((m-1)*ae_sqr(c, _state)+(n-1)*ae_sqr(1-c, _state)); if( ae_fp_greater(stat,(double)(0)) ) { p = 1-0.5*incompletebeta(df/2, 0.5, df/(df+ae_sqr(stat, _state)), _state); } else { p = 0.5*incompletebeta(df/2, 0.5, df/(df+ae_sqr(stat, _state)), _state); } *bothtails = 2*ae_minreal(p, 1-p, _state); *lefttail = p; *righttail = 1-p; } /************************************************************************* Two-sample F-test This test checks three hypotheses about dispersions of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the dispersions are equal) * left-tailed test (null hypothesis - the dispersion of the first sample is greater than or equal to the dispersion of the second sample). * right-tailed test (null hypothesis - the dispersion of the first sample is less than or equal to the dispersion of the second sample) The test is based on the following assumptions: * the given samples have normal distributions * the samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - sample size. Y - sample 2. Array whose index goes from 0 to M-1. M - sample size. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void ftest(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; double xmean; double ymean; double xvar; double yvar; ae_int_t df1; ae_int_t df2; double stat; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=2||m<=2 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Mean */ xmean = (double)(0); for(i=0; i<=n-1; i++) { xmean = xmean+x->ptr.p_double[i]; } xmean = xmean/n; ymean = (double)(0); for(i=0; i<=m-1; i++) { ymean = ymean+y->ptr.p_double[i]; } ymean = ymean/m; /* * Variance (using corrected two-pass algorithm) */ xvar = (double)(0); for(i=0; i<=n-1; i++) { xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); } xvar = xvar/(n-1); yvar = (double)(0); for(i=0; i<=m-1; i++) { yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); } yvar = yvar/(m-1); if( ae_fp_eq(xvar,(double)(0))||ae_fp_eq(yvar,(double)(0)) ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Statistic */ df1 = n-1; df2 = m-1; stat = ae_minreal(xvar/yvar, yvar/xvar, _state); *bothtails = 1-(fdistribution(df1, df2, 1/stat, _state)-fdistribution(df1, df2, stat, _state)); *lefttail = fdistribution(df1, df2, xvar/yvar, _state); *righttail = 1-(*lefttail); } /************************************************************************* One-sample chi-square test This test checks three hypotheses about the dispersion of the given sample The following tests are performed: * two-tailed test (null hypothesis - the dispersion equals the given number) * left-tailed test (null hypothesis - the dispersion is greater than or equal to the given number) * right-tailed test (null hypothesis - dispersion is less than or equal to the given number). Test is based on the following assumptions: * the given sample has a normal distribution. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Variance - dispersion value to compare with. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/ void onesamplevariancetest(/* Real */ ae_vector* x, ae_int_t n, double variance, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_int_t i; double xmean; double xvar; double s; double stat; *bothtails = 0; *lefttail = 0; *righttail = 0; if( n<=1 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Mean */ xmean = (double)(0); for(i=0; i<=n-1; i++) { xmean = xmean+x->ptr.p_double[i]; } xmean = xmean/n; /* * Variance */ xvar = (double)(0); for(i=0; i<=n-1; i++) { xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); } xvar = xvar/(n-1); if( ae_fp_eq(xvar,(double)(0)) ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; return; } /* * Statistic */ stat = (n-1)*xvar/variance; s = chisquaredistribution((double)(n-1), stat, _state); *bothtails = 2*ae_minreal(s, 1-s, _state); *lefttail = s; *righttail = 1-(*lefttail); } /************************************************************************* Wilcoxon signed-rank test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). * the distribution should be continuous and symmetric relative to its median. * number of distinct values in the X array should be greater than 4 The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with two decimal places in interval [0.0001, 1]. "Two decimal places" does not sound very impressive, but in practice the relative error of less than 1% is enough to make a decision. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/ void wilcoxonsignedranktest(/* Real */ ae_vector* x, ae_int_t n, double e, double* bothtails, double* lefttail, double* righttail, ae_state *_state) { ae_frame _frame_block; ae_vector _x; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t t; double tmp; ae_int_t tmpi; ae_int_t ns; ae_vector r; ae_vector c; double w; double p; double mp; double s; double sigma; double mu; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_x, x, _state); x = &_x; *bothtails = 0; *lefttail = 0; *righttail = 0; ae_vector_init(&r, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_INT, _state); /* * Prepare */ if( n<5 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; ae_frame_leave(_state); return; } ns = 0; for(i=0; i<=n-1; i++) { if( ae_fp_eq(x->ptr.p_double[i],e) ) { continue; } x->ptr.p_double[ns] = x->ptr.p_double[i]; ns = ns+1; } if( ns<5 ) { *bothtails = 1.0; *lefttail = 1.0; *righttail = 1.0; ae_frame_leave(_state); return; } ae_vector_set_length(&r, ns-1+1, _state); ae_vector_set_length(&c, ns-1+1, _state); for(i=0; i<=ns-1; i++) { r.ptr.p_double[i] = ae_fabs(x->ptr.p_double[i]-e, _state); c.ptr.p_int[i] = i; } /* * sort {R, C} */ if( ns!=1 ) { i = 2; do { t = i; while(t!=1) { k = t/2; if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) { t = 1; } else { tmp = r.ptr.p_double[k-1]; r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; r.ptr.p_double[t-1] = tmp; tmpi = c.ptr.p_int[k-1]; c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; c.ptr.p_int[t-1] = tmpi; t = k; } } i = i+1; } while(i<=ns); i = ns-1; do { tmp = r.ptr.p_double[i]; r.ptr.p_double[i] = r.ptr.p_double[0]; r.ptr.p_double[0] = tmp; tmpi = c.ptr.p_int[i]; c.ptr.p_int[i] = c.ptr.p_int[0]; c.ptr.p_int[0] = tmpi; t = 1; while(t!=0) { k = 2*t; if( k>i ) { t = 0; } else { if( k=1); } /* * compute tied ranks */ i = 0; while(i<=ns-1) { j = i+1; while(j<=ns-1) { if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) { break; } j = j+1; } for(k=i; k<=j-1; k++) { r.ptr.p_double[k] = 1+(double)(i+j-1)/(double)2; } i = j; } /* * Compute W+ */ w = (double)(0); for(i=0; i<=ns-1; i++) { if( ae_fp_greater(x->ptr.p_double[c.ptr.p_int[i]],e) ) { w = w+r.ptr.p_double[i]; } } /* * Result */ mu = (double)(ns*(ns+1))/(double)4; sigma = ae_sqrt((double)(ns*(ns+1)*(2*ns+1))/(double)24, _state); s = (w-mu)/sigma; if( ae_fp_less_eq(s,(double)(0)) ) { p = ae_exp(wsr_wsigma(-(w-mu)/sigma, ns, _state), _state); mp = 1-ae_exp(wsr_wsigma(-(w-1-mu)/sigma, ns, _state), _state); } else { mp = ae_exp(wsr_wsigma((w-mu)/sigma, ns, _state), _state); p = 1-ae_exp(wsr_wsigma((w+1-mu)/sigma, ns, _state), _state); } *bothtails = ae_maxreal(2*ae_minreal(p, mp, _state), 1.0E-4, _state); *lefttail = ae_maxreal(p, 1.0E-4, _state); *righttail = ae_maxreal(mp, 1.0E-4, _state); ae_frame_leave(_state); } /************************************************************************* Sequential Chebyshev interpolation. *************************************************************************/ static void wsr_wcheb(double x, double c, double* tj, double* tj1, double* r, ae_state *_state) { double t; *r = *r+c*(*tj); t = 2*x*(*tj1)-(*tj); *tj = *tj1; *tj1 = t; } /************************************************************************* Tail(S, 5) *************************************************************************/ static double wsr_w5(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-3.708099e+00*s+7.500000e+00, _state); if( w>=7 ) { r = -6.931e-01; } if( w==6 ) { r = -9.008e-01; } if( w==5 ) { r = -1.163e+00; } if( w==4 ) { r = -1.520e+00; } if( w==3 ) { r = -1.856e+00; } if( w==2 ) { r = -2.367e+00; } if( w==1 ) { r = -2.773e+00; } if( w<=0 ) { r = -3.466e+00; } result = r; return result; } /************************************************************************* Tail(S, 6) *************************************************************************/ static double wsr_w6(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-4.769696e+00*s+1.050000e+01, _state); if( w>=10 ) { r = -6.931e-01; } if( w==9 ) { r = -8.630e-01; } if( w==8 ) { r = -1.068e+00; } if( w==7 ) { r = -1.269e+00; } if( w==6 ) { r = -1.520e+00; } if( w==5 ) { r = -1.856e+00; } if( w==4 ) { r = -2.213e+00; } if( w==3 ) { r = -2.549e+00; } if( w==2 ) { r = -3.060e+00; } if( w==1 ) { r = -3.466e+00; } if( w<=0 ) { r = -4.159e+00; } result = r; return result; } /************************************************************************* Tail(S, 7) *************************************************************************/ static double wsr_w7(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-5.916080e+00*s+1.400000e+01, _state); if( w>=14 ) { r = -6.325e-01; } if( w==13 ) { r = -7.577e-01; } if( w==12 ) { r = -9.008e-01; } if( w==11 ) { r = -1.068e+00; } if( w==10 ) { r = -1.241e+00; } if( w==9 ) { r = -1.451e+00; } if( w==8 ) { r = -1.674e+00; } if( w==7 ) { r = -1.908e+00; } if( w==6 ) { r = -2.213e+00; } if( w==5 ) { r = -2.549e+00; } if( w==4 ) { r = -2.906e+00; } if( w==3 ) { r = -3.243e+00; } if( w==2 ) { r = -3.753e+00; } if( w==1 ) { r = -4.159e+00; } if( w<=0 ) { r = -4.852e+00; } result = r; return result; } /************************************************************************* Tail(S, 8) *************************************************************************/ static double wsr_w8(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-7.141428e+00*s+1.800000e+01, _state); if( w>=18 ) { r = -6.399e-01; } if( w==17 ) { r = -7.494e-01; } if( w==16 ) { r = -8.630e-01; } if( w==15 ) { r = -9.913e-01; } if( w==14 ) { r = -1.138e+00; } if( w==13 ) { r = -1.297e+00; } if( w==12 ) { r = -1.468e+00; } if( w==11 ) { r = -1.653e+00; } if( w==10 ) { r = -1.856e+00; } if( w==9 ) { r = -2.079e+00; } if( w==8 ) { r = -2.326e+00; } if( w==7 ) { r = -2.601e+00; } if( w==6 ) { r = -2.906e+00; } if( w==5 ) { r = -3.243e+00; } if( w==4 ) { r = -3.599e+00; } if( w==3 ) { r = -3.936e+00; } if( w==2 ) { r = -4.447e+00; } if( w==1 ) { r = -4.852e+00; } if( w<=0 ) { r = -5.545e+00; } result = r; return result; } /************************************************************************* Tail(S, 9) *************************************************************************/ static double wsr_w9(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-8.440972e+00*s+2.250000e+01, _state); if( w>=22 ) { r = -6.931e-01; } if( w==21 ) { r = -7.873e-01; } if( w==20 ) { r = -8.912e-01; } if( w==19 ) { r = -1.002e+00; } if( w==18 ) { r = -1.120e+00; } if( w==17 ) { r = -1.255e+00; } if( w==16 ) { r = -1.394e+00; } if( w==15 ) { r = -1.547e+00; } if( w==14 ) { r = -1.717e+00; } if( w==13 ) { r = -1.895e+00; } if( w==12 ) { r = -2.079e+00; } if( w==11 ) { r = -2.287e+00; } if( w==10 ) { r = -2.501e+00; } if( w==9 ) { r = -2.742e+00; } if( w==8 ) { r = -3.019e+00; } if( w==7 ) { r = -3.294e+00; } if( w==6 ) { r = -3.599e+00; } if( w==5 ) { r = -3.936e+00; } if( w==4 ) { r = -4.292e+00; } if( w==3 ) { r = -4.629e+00; } if( w==2 ) { r = -5.140e+00; } if( w==1 ) { r = -5.545e+00; } if( w<=0 ) { r = -6.238e+00; } result = r; return result; } /************************************************************************* Tail(S, 10) *************************************************************************/ static double wsr_w10(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-9.810708e+00*s+2.750000e+01, _state); if( w>=27 ) { r = -6.931e-01; } if( w==26 ) { r = -7.745e-01; } if( w==25 ) { r = -8.607e-01; } if( w==24 ) { r = -9.551e-01; } if( w==23 ) { r = -1.057e+00; } if( w==22 ) { r = -1.163e+00; } if( w==21 ) { r = -1.279e+00; } if( w==20 ) { r = -1.402e+00; } if( w==19 ) { r = -1.533e+00; } if( w==18 ) { r = -1.674e+00; } if( w==17 ) { r = -1.826e+00; } if( w==16 ) { r = -1.983e+00; } if( w==15 ) { r = -2.152e+00; } if( w==14 ) { r = -2.336e+00; } if( w==13 ) { r = -2.525e+00; } if( w==12 ) { r = -2.727e+00; } if( w==11 ) { r = -2.942e+00; } if( w==10 ) { r = -3.170e+00; } if( w==9 ) { r = -3.435e+00; } if( w==8 ) { r = -3.713e+00; } if( w==7 ) { r = -3.987e+00; } if( w==6 ) { r = -4.292e+00; } if( w==5 ) { r = -4.629e+00; } if( w==4 ) { r = -4.986e+00; } if( w==3 ) { r = -5.322e+00; } if( w==2 ) { r = -5.833e+00; } if( w==1 ) { r = -6.238e+00; } if( w<=0 ) { r = -6.931e+00; } result = r; return result; } /************************************************************************* Tail(S, 11) *************************************************************************/ static double wsr_w11(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.124722e+01*s+3.300000e+01, _state); if( w>=33 ) { r = -6.595e-01; } if( w==32 ) { r = -7.279e-01; } if( w==31 ) { r = -8.002e-01; } if( w==30 ) { r = -8.782e-01; } if( w==29 ) { r = -9.615e-01; } if( w==28 ) { r = -1.050e+00; } if( w==27 ) { r = -1.143e+00; } if( w==26 ) { r = -1.243e+00; } if( w==25 ) { r = -1.348e+00; } if( w==24 ) { r = -1.459e+00; } if( w==23 ) { r = -1.577e+00; } if( w==22 ) { r = -1.700e+00; } if( w==21 ) { r = -1.832e+00; } if( w==20 ) { r = -1.972e+00; } if( w==19 ) { r = -2.119e+00; } if( w==18 ) { r = -2.273e+00; } if( w==17 ) { r = -2.437e+00; } if( w==16 ) { r = -2.607e+00; } if( w==15 ) { r = -2.788e+00; } if( w==14 ) { r = -2.980e+00; } if( w==13 ) { r = -3.182e+00; } if( w==12 ) { r = -3.391e+00; } if( w==11 ) { r = -3.617e+00; } if( w==10 ) { r = -3.863e+00; } if( w==9 ) { r = -4.128e+00; } if( w==8 ) { r = -4.406e+00; } if( w==7 ) { r = -4.680e+00; } if( w==6 ) { r = -4.986e+00; } if( w==5 ) { r = -5.322e+00; } if( w==4 ) { r = -5.679e+00; } if( w==3 ) { r = -6.015e+00; } if( w==2 ) { r = -6.526e+00; } if( w==1 ) { r = -6.931e+00; } if( w<=0 ) { r = -7.625e+00; } result = r; return result; } /************************************************************************* Tail(S, 12) *************************************************************************/ static double wsr_w12(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.274755e+01*s+3.900000e+01, _state); if( w>=39 ) { r = -6.633e-01; } if( w==38 ) { r = -7.239e-01; } if( w==37 ) { r = -7.878e-01; } if( w==36 ) { r = -8.556e-01; } if( w==35 ) { r = -9.276e-01; } if( w==34 ) { r = -1.003e+00; } if( w==33 ) { r = -1.083e+00; } if( w==32 ) { r = -1.168e+00; } if( w==31 ) { r = -1.256e+00; } if( w==30 ) { r = -1.350e+00; } if( w==29 ) { r = -1.449e+00; } if( w==28 ) { r = -1.552e+00; } if( w==27 ) { r = -1.660e+00; } if( w==26 ) { r = -1.774e+00; } if( w==25 ) { r = -1.893e+00; } if( w==24 ) { r = -2.017e+00; } if( w==23 ) { r = -2.148e+00; } if( w==22 ) { r = -2.285e+00; } if( w==21 ) { r = -2.429e+00; } if( w==20 ) { r = -2.581e+00; } if( w==19 ) { r = -2.738e+00; } if( w==18 ) { r = -2.902e+00; } if( w==17 ) { r = -3.076e+00; } if( w==16 ) { r = -3.255e+00; } if( w==15 ) { r = -3.443e+00; } if( w==14 ) { r = -3.645e+00; } if( w==13 ) { r = -3.852e+00; } if( w==12 ) { r = -4.069e+00; } if( w==11 ) { r = -4.310e+00; } if( w==10 ) { r = -4.557e+00; } if( w==9 ) { r = -4.821e+00; } if( w==8 ) { r = -5.099e+00; } if( w==7 ) { r = -5.373e+00; } if( w==6 ) { r = -5.679e+00; } if( w==5 ) { r = -6.015e+00; } if( w==4 ) { r = -6.372e+00; } if( w==3 ) { r = -6.708e+00; } if( w==2 ) { r = -7.219e+00; } if( w==1 ) { r = -7.625e+00; } if( w<=0 ) { r = -8.318e+00; } result = r; return result; } /************************************************************************* Tail(S, 13) *************************************************************************/ static double wsr_w13(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.430909e+01*s+4.550000e+01, _state); if( w>=45 ) { r = -6.931e-01; } if( w==44 ) { r = -7.486e-01; } if( w==43 ) { r = -8.068e-01; } if( w==42 ) { r = -8.683e-01; } if( w==41 ) { r = -9.328e-01; } if( w==40 ) { r = -1.001e+00; } if( w==39 ) { r = -1.072e+00; } if( w==38 ) { r = -1.146e+00; } if( w==37 ) { r = -1.224e+00; } if( w==36 ) { r = -1.306e+00; } if( w==35 ) { r = -1.392e+00; } if( w==34 ) { r = -1.481e+00; } if( w==33 ) { r = -1.574e+00; } if( w==32 ) { r = -1.672e+00; } if( w==31 ) { r = -1.773e+00; } if( w==30 ) { r = -1.879e+00; } if( w==29 ) { r = -1.990e+00; } if( w==28 ) { r = -2.104e+00; } if( w==27 ) { r = -2.224e+00; } if( w==26 ) { r = -2.349e+00; } if( w==25 ) { r = -2.479e+00; } if( w==24 ) { r = -2.614e+00; } if( w==23 ) { r = -2.755e+00; } if( w==22 ) { r = -2.902e+00; } if( w==21 ) { r = -3.055e+00; } if( w==20 ) { r = -3.215e+00; } if( w==19 ) { r = -3.380e+00; } if( w==18 ) { r = -3.551e+00; } if( w==17 ) { r = -3.733e+00; } if( w==16 ) { r = -3.917e+00; } if( w==15 ) { r = -4.113e+00; } if( w==14 ) { r = -4.320e+00; } if( w==13 ) { r = -4.534e+00; } if( w==12 ) { r = -4.762e+00; } if( w==11 ) { r = -5.004e+00; } if( w==10 ) { r = -5.250e+00; } if( w==9 ) { r = -5.514e+00; } if( w==8 ) { r = -5.792e+00; } if( w==7 ) { r = -6.066e+00; } if( w==6 ) { r = -6.372e+00; } if( w==5 ) { r = -6.708e+00; } if( w==4 ) { r = -7.065e+00; } if( w==3 ) { r = -7.401e+00; } if( w==2 ) { r = -7.912e+00; } if( w==1 ) { r = -8.318e+00; } if( w<=0 ) { r = -9.011e+00; } result = r; return result; } /************************************************************************* Tail(S, 14) *************************************************************************/ static double wsr_w14(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.592953e+01*s+5.250000e+01, _state); if( w>=52 ) { r = -6.931e-01; } if( w==51 ) { r = -7.428e-01; } if( w==50 ) { r = -7.950e-01; } if( w==49 ) { r = -8.495e-01; } if( w==48 ) { r = -9.067e-01; } if( w==47 ) { r = -9.664e-01; } if( w==46 ) { r = -1.029e+00; } if( w==45 ) { r = -1.094e+00; } if( w==44 ) { r = -1.162e+00; } if( w==43 ) { r = -1.233e+00; } if( w==42 ) { r = -1.306e+00; } if( w==41 ) { r = -1.383e+00; } if( w==40 ) { r = -1.463e+00; } if( w==39 ) { r = -1.546e+00; } if( w==38 ) { r = -1.632e+00; } if( w==37 ) { r = -1.722e+00; } if( w==36 ) { r = -1.815e+00; } if( w==35 ) { r = -1.911e+00; } if( w==34 ) { r = -2.011e+00; } if( w==33 ) { r = -2.115e+00; } if( w==32 ) { r = -2.223e+00; } if( w==31 ) { r = -2.334e+00; } if( w==30 ) { r = -2.450e+00; } if( w==29 ) { r = -2.570e+00; } if( w==28 ) { r = -2.694e+00; } if( w==27 ) { r = -2.823e+00; } if( w==26 ) { r = -2.956e+00; } if( w==25 ) { r = -3.095e+00; } if( w==24 ) { r = -3.238e+00; } if( w==23 ) { r = -3.387e+00; } if( w==22 ) { r = -3.541e+00; } if( w==21 ) { r = -3.700e+00; } if( w==20 ) { r = -3.866e+00; } if( w==19 ) { r = -4.038e+00; } if( w==18 ) { r = -4.215e+00; } if( w==17 ) { r = -4.401e+00; } if( w==16 ) { r = -4.592e+00; } if( w==15 ) { r = -4.791e+00; } if( w==14 ) { r = -5.004e+00; } if( w==13 ) { r = -5.227e+00; } if( w==12 ) { r = -5.456e+00; } if( w==11 ) { r = -5.697e+00; } if( w==10 ) { r = -5.943e+00; } if( w==9 ) { r = -6.208e+00; } if( w==8 ) { r = -6.485e+00; } if( w==7 ) { r = -6.760e+00; } if( w==6 ) { r = -7.065e+00; } if( w==5 ) { r = -7.401e+00; } if( w==4 ) { r = -7.758e+00; } if( w==3 ) { r = -8.095e+00; } if( w==2 ) { r = -8.605e+00; } if( w==1 ) { r = -9.011e+00; } if( w<=0 ) { r = -9.704e+00; } result = r; return result; } /************************************************************************* Tail(S, 15) *************************************************************************/ static double wsr_w15(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.760682e+01*s+6.000000e+01, _state); if( w>=60 ) { r = -6.714e-01; } if( w==59 ) { r = -7.154e-01; } if( w==58 ) { r = -7.613e-01; } if( w==57 ) { r = -8.093e-01; } if( w==56 ) { r = -8.593e-01; } if( w==55 ) { r = -9.114e-01; } if( w==54 ) { r = -9.656e-01; } if( w==53 ) { r = -1.022e+00; } if( w==52 ) { r = -1.081e+00; } if( w==51 ) { r = -1.142e+00; } if( w==50 ) { r = -1.205e+00; } if( w==49 ) { r = -1.270e+00; } if( w==48 ) { r = -1.339e+00; } if( w==47 ) { r = -1.409e+00; } if( w==46 ) { r = -1.482e+00; } if( w==45 ) { r = -1.558e+00; } if( w==44 ) { r = -1.636e+00; } if( w==43 ) { r = -1.717e+00; } if( w==42 ) { r = -1.801e+00; } if( w==41 ) { r = -1.888e+00; } if( w==40 ) { r = -1.977e+00; } if( w==39 ) { r = -2.070e+00; } if( w==38 ) { r = -2.166e+00; } if( w==37 ) { r = -2.265e+00; } if( w==36 ) { r = -2.366e+00; } if( w==35 ) { r = -2.472e+00; } if( w==34 ) { r = -2.581e+00; } if( w==33 ) { r = -2.693e+00; } if( w==32 ) { r = -2.809e+00; } if( w==31 ) { r = -2.928e+00; } if( w==30 ) { r = -3.051e+00; } if( w==29 ) { r = -3.179e+00; } if( w==28 ) { r = -3.310e+00; } if( w==27 ) { r = -3.446e+00; } if( w==26 ) { r = -3.587e+00; } if( w==25 ) { r = -3.732e+00; } if( w==24 ) { r = -3.881e+00; } if( w==23 ) { r = -4.036e+00; } if( w==22 ) { r = -4.195e+00; } if( w==21 ) { r = -4.359e+00; } if( w==20 ) { r = -4.531e+00; } if( w==19 ) { r = -4.707e+00; } if( w==18 ) { r = -4.888e+00; } if( w==17 ) { r = -5.079e+00; } if( w==16 ) { r = -5.273e+00; } if( w==15 ) { r = -5.477e+00; } if( w==14 ) { r = -5.697e+00; } if( w==13 ) { r = -5.920e+00; } if( w==12 ) { r = -6.149e+00; } if( w==11 ) { r = -6.390e+00; } if( w==10 ) { r = -6.636e+00; } if( w==9 ) { r = -6.901e+00; } if( w==8 ) { r = -7.178e+00; } if( w==7 ) { r = -7.453e+00; } if( w==6 ) { r = -7.758e+00; } if( w==5 ) { r = -8.095e+00; } if( w==4 ) { r = -8.451e+00; } if( w==3 ) { r = -8.788e+00; } if( w==2 ) { r = -9.299e+00; } if( w==1 ) { r = -9.704e+00; } if( w<=0 ) { r = -1.040e+01; } result = r; return result; } /************************************************************************* Tail(S, 16) *************************************************************************/ static double wsr_w16(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-1.933908e+01*s+6.800000e+01, _state); if( w>=68 ) { r = -6.733e-01; } if( w==67 ) { r = -7.134e-01; } if( w==66 ) { r = -7.551e-01; } if( w==65 ) { r = -7.986e-01; } if( w==64 ) { r = -8.437e-01; } if( w==63 ) { r = -8.905e-01; } if( w==62 ) { r = -9.391e-01; } if( w==61 ) { r = -9.895e-01; } if( w==60 ) { r = -1.042e+00; } if( w==59 ) { r = -1.096e+00; } if( w==58 ) { r = -1.152e+00; } if( w==57 ) { r = -1.210e+00; } if( w==56 ) { r = -1.270e+00; } if( w==55 ) { r = -1.331e+00; } if( w==54 ) { r = -1.395e+00; } if( w==53 ) { r = -1.462e+00; } if( w==52 ) { r = -1.530e+00; } if( w==51 ) { r = -1.600e+00; } if( w==50 ) { r = -1.673e+00; } if( w==49 ) { r = -1.748e+00; } if( w==48 ) { r = -1.825e+00; } if( w==47 ) { r = -1.904e+00; } if( w==46 ) { r = -1.986e+00; } if( w==45 ) { r = -2.071e+00; } if( w==44 ) { r = -2.158e+00; } if( w==43 ) { r = -2.247e+00; } if( w==42 ) { r = -2.339e+00; } if( w==41 ) { r = -2.434e+00; } if( w==40 ) { r = -2.532e+00; } if( w==39 ) { r = -2.632e+00; } if( w==38 ) { r = -2.735e+00; } if( w==37 ) { r = -2.842e+00; } if( w==36 ) { r = -2.951e+00; } if( w==35 ) { r = -3.064e+00; } if( w==34 ) { r = -3.179e+00; } if( w==33 ) { r = -3.298e+00; } if( w==32 ) { r = -3.420e+00; } if( w==31 ) { r = -3.546e+00; } if( w==30 ) { r = -3.676e+00; } if( w==29 ) { r = -3.810e+00; } if( w==28 ) { r = -3.947e+00; } if( w==27 ) { r = -4.088e+00; } if( w==26 ) { r = -4.234e+00; } if( w==25 ) { r = -4.383e+00; } if( w==24 ) { r = -4.538e+00; } if( w==23 ) { r = -4.697e+00; } if( w==22 ) { r = -4.860e+00; } if( w==21 ) { r = -5.029e+00; } if( w==20 ) { r = -5.204e+00; } if( w==19 ) { r = -5.383e+00; } if( w==18 ) { r = -5.569e+00; } if( w==17 ) { r = -5.762e+00; } if( w==16 ) { r = -5.960e+00; } if( w==15 ) { r = -6.170e+00; } if( w==14 ) { r = -6.390e+00; } if( w==13 ) { r = -6.613e+00; } if( w==12 ) { r = -6.842e+00; } if( w==11 ) { r = -7.083e+00; } if( w==10 ) { r = -7.329e+00; } if( w==9 ) { r = -7.594e+00; } if( w==8 ) { r = -7.871e+00; } if( w==7 ) { r = -8.146e+00; } if( w==6 ) { r = -8.451e+00; } if( w==5 ) { r = -8.788e+00; } if( w==4 ) { r = -9.144e+00; } if( w==3 ) { r = -9.481e+00; } if( w==2 ) { r = -9.992e+00; } if( w==1 ) { r = -1.040e+01; } if( w<=0 ) { r = -1.109e+01; } result = r; return result; } /************************************************************************* Tail(S, 17) *************************************************************************/ static double wsr_w17(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-2.112463e+01*s+7.650000e+01, _state); if( w>=76 ) { r = -6.931e-01; } if( w==75 ) { r = -7.306e-01; } if( w==74 ) { r = -7.695e-01; } if( w==73 ) { r = -8.097e-01; } if( w==72 ) { r = -8.514e-01; } if( w==71 ) { r = -8.946e-01; } if( w==70 ) { r = -9.392e-01; } if( w==69 ) { r = -9.853e-01; } if( w==68 ) { r = -1.033e+00; } if( w==67 ) { r = -1.082e+00; } if( w==66 ) { r = -1.133e+00; } if( w==65 ) { r = -1.185e+00; } if( w==64 ) { r = -1.240e+00; } if( w==63 ) { r = -1.295e+00; } if( w==62 ) { r = -1.353e+00; } if( w==61 ) { r = -1.412e+00; } if( w==60 ) { r = -1.473e+00; } if( w==59 ) { r = -1.536e+00; } if( w==58 ) { r = -1.600e+00; } if( w==57 ) { r = -1.666e+00; } if( w==56 ) { r = -1.735e+00; } if( w==55 ) { r = -1.805e+00; } if( w==54 ) { r = -1.877e+00; } if( w==53 ) { r = -1.951e+00; } if( w==52 ) { r = -2.028e+00; } if( w==51 ) { r = -2.106e+00; } if( w==50 ) { r = -2.186e+00; } if( w==49 ) { r = -2.269e+00; } if( w==48 ) { r = -2.353e+00; } if( w==47 ) { r = -2.440e+00; } if( w==46 ) { r = -2.530e+00; } if( w==45 ) { r = -2.621e+00; } if( w==44 ) { r = -2.715e+00; } if( w==43 ) { r = -2.812e+00; } if( w==42 ) { r = -2.911e+00; } if( w==41 ) { r = -3.012e+00; } if( w==40 ) { r = -3.116e+00; } if( w==39 ) { r = -3.223e+00; } if( w==38 ) { r = -3.332e+00; } if( w==37 ) { r = -3.445e+00; } if( w==36 ) { r = -3.560e+00; } if( w==35 ) { r = -3.678e+00; } if( w==34 ) { r = -3.799e+00; } if( w==33 ) { r = -3.924e+00; } if( w==32 ) { r = -4.052e+00; } if( w==31 ) { r = -4.183e+00; } if( w==30 ) { r = -4.317e+00; } if( w==29 ) { r = -4.456e+00; } if( w==28 ) { r = -4.597e+00; } if( w==27 ) { r = -4.743e+00; } if( w==26 ) { r = -4.893e+00; } if( w==25 ) { r = -5.047e+00; } if( w==24 ) { r = -5.204e+00; } if( w==23 ) { r = -5.367e+00; } if( w==22 ) { r = -5.534e+00; } if( w==21 ) { r = -5.706e+00; } if( w==20 ) { r = -5.884e+00; } if( w==19 ) { r = -6.066e+00; } if( w==18 ) { r = -6.254e+00; } if( w==17 ) { r = -6.451e+00; } if( w==16 ) { r = -6.654e+00; } if( w==15 ) { r = -6.864e+00; } if( w==14 ) { r = -7.083e+00; } if( w==13 ) { r = -7.306e+00; } if( w==12 ) { r = -7.535e+00; } if( w==11 ) { r = -7.776e+00; } if( w==10 ) { r = -8.022e+00; } if( w==9 ) { r = -8.287e+00; } if( w==8 ) { r = -8.565e+00; } if( w==7 ) { r = -8.839e+00; } if( w==6 ) { r = -9.144e+00; } if( w==5 ) { r = -9.481e+00; } if( w==4 ) { r = -9.838e+00; } if( w==3 ) { r = -1.017e+01; } if( w==2 ) { r = -1.068e+01; } if( w==1 ) { r = -1.109e+01; } if( w<=0 ) { r = -1.178e+01; } result = r; return result; } /************************************************************************* Tail(S, 18) *************************************************************************/ static double wsr_w18(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-2.296193e+01*s+8.550000e+01, _state); if( w>=85 ) { r = -6.931e-01; } if( w==84 ) { r = -7.276e-01; } if( w==83 ) { r = -7.633e-01; } if( w==82 ) { r = -8.001e-01; } if( w==81 ) { r = -8.381e-01; } if( w==80 ) { r = -8.774e-01; } if( w==79 ) { r = -9.179e-01; } if( w==78 ) { r = -9.597e-01; } if( w==77 ) { r = -1.003e+00; } if( w==76 ) { r = -1.047e+00; } if( w==75 ) { r = -1.093e+00; } if( w==74 ) { r = -1.140e+00; } if( w==73 ) { r = -1.188e+00; } if( w==72 ) { r = -1.238e+00; } if( w==71 ) { r = -1.289e+00; } if( w==70 ) { r = -1.342e+00; } if( w==69 ) { r = -1.396e+00; } if( w==68 ) { r = -1.452e+00; } if( w==67 ) { r = -1.509e+00; } if( w==66 ) { r = -1.568e+00; } if( w==65 ) { r = -1.628e+00; } if( w==64 ) { r = -1.690e+00; } if( w==63 ) { r = -1.753e+00; } if( w==62 ) { r = -1.818e+00; } if( w==61 ) { r = -1.885e+00; } if( w==60 ) { r = -1.953e+00; } if( w==59 ) { r = -2.023e+00; } if( w==58 ) { r = -2.095e+00; } if( w==57 ) { r = -2.168e+00; } if( w==56 ) { r = -2.244e+00; } if( w==55 ) { r = -2.321e+00; } if( w==54 ) { r = -2.400e+00; } if( w==53 ) { r = -2.481e+00; } if( w==52 ) { r = -2.564e+00; } if( w==51 ) { r = -2.648e+00; } if( w==50 ) { r = -2.735e+00; } if( w==49 ) { r = -2.824e+00; } if( w==48 ) { r = -2.915e+00; } if( w==47 ) { r = -3.008e+00; } if( w==46 ) { r = -3.104e+00; } if( w==45 ) { r = -3.201e+00; } if( w==44 ) { r = -3.301e+00; } if( w==43 ) { r = -3.403e+00; } if( w==42 ) { r = -3.508e+00; } if( w==41 ) { r = -3.615e+00; } if( w==40 ) { r = -3.724e+00; } if( w==39 ) { r = -3.836e+00; } if( w==38 ) { r = -3.950e+00; } if( w==37 ) { r = -4.068e+00; } if( w==36 ) { r = -4.188e+00; } if( w==35 ) { r = -4.311e+00; } if( w==34 ) { r = -4.437e+00; } if( w==33 ) { r = -4.565e+00; } if( w==32 ) { r = -4.698e+00; } if( w==31 ) { r = -4.833e+00; } if( w==30 ) { r = -4.971e+00; } if( w==29 ) { r = -5.113e+00; } if( w==28 ) { r = -5.258e+00; } if( w==27 ) { r = -5.408e+00; } if( w==26 ) { r = -5.561e+00; } if( w==25 ) { r = -5.717e+00; } if( w==24 ) { r = -5.878e+00; } if( w==23 ) { r = -6.044e+00; } if( w==22 ) { r = -6.213e+00; } if( w==21 ) { r = -6.388e+00; } if( w==20 ) { r = -6.569e+00; } if( w==19 ) { r = -6.753e+00; } if( w==18 ) { r = -6.943e+00; } if( w==17 ) { r = -7.144e+00; } if( w==16 ) { r = -7.347e+00; } if( w==15 ) { r = -7.557e+00; } if( w==14 ) { r = -7.776e+00; } if( w==13 ) { r = -7.999e+00; } if( w==12 ) { r = -8.228e+00; } if( w==11 ) { r = -8.469e+00; } if( w==10 ) { r = -8.715e+00; } if( w==9 ) { r = -8.980e+00; } if( w==8 ) { r = -9.258e+00; } if( w==7 ) { r = -9.532e+00; } if( w==6 ) { r = -9.838e+00; } if( w==5 ) { r = -1.017e+01; } if( w==4 ) { r = -1.053e+01; } if( w==3 ) { r = -1.087e+01; } if( w==2 ) { r = -1.138e+01; } if( w==1 ) { r = -1.178e+01; } if( w<=0 ) { r = -1.248e+01; } result = r; return result; } /************************************************************************* Tail(S, 19) *************************************************************************/ static double wsr_w19(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-2.484955e+01*s+9.500000e+01, _state); if( w>=95 ) { r = -6.776e-01; } if( w==94 ) { r = -7.089e-01; } if( w==93 ) { r = -7.413e-01; } if( w==92 ) { r = -7.747e-01; } if( w==91 ) { r = -8.090e-01; } if( w==90 ) { r = -8.445e-01; } if( w==89 ) { r = -8.809e-01; } if( w==88 ) { r = -9.185e-01; } if( w==87 ) { r = -9.571e-01; } if( w==86 ) { r = -9.968e-01; } if( w==85 ) { r = -1.038e+00; } if( w==84 ) { r = -1.080e+00; } if( w==83 ) { r = -1.123e+00; } if( w==82 ) { r = -1.167e+00; } if( w==81 ) { r = -1.213e+00; } if( w==80 ) { r = -1.259e+00; } if( w==79 ) { r = -1.307e+00; } if( w==78 ) { r = -1.356e+00; } if( w==77 ) { r = -1.407e+00; } if( w==76 ) { r = -1.458e+00; } if( w==75 ) { r = -1.511e+00; } if( w==74 ) { r = -1.565e+00; } if( w==73 ) { r = -1.621e+00; } if( w==72 ) { r = -1.678e+00; } if( w==71 ) { r = -1.736e+00; } if( w==70 ) { r = -1.796e+00; } if( w==69 ) { r = -1.857e+00; } if( w==68 ) { r = -1.919e+00; } if( w==67 ) { r = -1.983e+00; } if( w==66 ) { r = -2.048e+00; } if( w==65 ) { r = -2.115e+00; } if( w==64 ) { r = -2.183e+00; } if( w==63 ) { r = -2.253e+00; } if( w==62 ) { r = -2.325e+00; } if( w==61 ) { r = -2.398e+00; } if( w==60 ) { r = -2.472e+00; } if( w==59 ) { r = -2.548e+00; } if( w==58 ) { r = -2.626e+00; } if( w==57 ) { r = -2.706e+00; } if( w==56 ) { r = -2.787e+00; } if( w==55 ) { r = -2.870e+00; } if( w==54 ) { r = -2.955e+00; } if( w==53 ) { r = -3.042e+00; } if( w==52 ) { r = -3.130e+00; } if( w==51 ) { r = -3.220e+00; } if( w==50 ) { r = -3.313e+00; } if( w==49 ) { r = -3.407e+00; } if( w==48 ) { r = -3.503e+00; } if( w==47 ) { r = -3.601e+00; } if( w==46 ) { r = -3.702e+00; } if( w==45 ) { r = -3.804e+00; } if( w==44 ) { r = -3.909e+00; } if( w==43 ) { r = -4.015e+00; } if( w==42 ) { r = -4.125e+00; } if( w==41 ) { r = -4.236e+00; } if( w==40 ) { r = -4.350e+00; } if( w==39 ) { r = -4.466e+00; } if( w==38 ) { r = -4.585e+00; } if( w==37 ) { r = -4.706e+00; } if( w==36 ) { r = -4.830e+00; } if( w==35 ) { r = -4.957e+00; } if( w==34 ) { r = -5.086e+00; } if( w==33 ) { r = -5.219e+00; } if( w==32 ) { r = -5.355e+00; } if( w==31 ) { r = -5.493e+00; } if( w==30 ) { r = -5.634e+00; } if( w==29 ) { r = -5.780e+00; } if( w==28 ) { r = -5.928e+00; } if( w==27 ) { r = -6.080e+00; } if( w==26 ) { r = -6.235e+00; } if( w==25 ) { r = -6.394e+00; } if( w==24 ) { r = -6.558e+00; } if( w==23 ) { r = -6.726e+00; } if( w==22 ) { r = -6.897e+00; } if( w==21 ) { r = -7.074e+00; } if( w==20 ) { r = -7.256e+00; } if( w==19 ) { r = -7.443e+00; } if( w==18 ) { r = -7.636e+00; } if( w==17 ) { r = -7.837e+00; } if( w==16 ) { r = -8.040e+00; } if( w==15 ) { r = -8.250e+00; } if( w==14 ) { r = -8.469e+00; } if( w==13 ) { r = -8.692e+00; } if( w==12 ) { r = -8.921e+00; } if( w==11 ) { r = -9.162e+00; } if( w==10 ) { r = -9.409e+00; } if( w==9 ) { r = -9.673e+00; } if( w==8 ) { r = -9.951e+00; } if( w==7 ) { r = -1.023e+01; } if( w==6 ) { r = -1.053e+01; } if( w==5 ) { r = -1.087e+01; } if( w==4 ) { r = -1.122e+01; } if( w==3 ) { r = -1.156e+01; } if( w==2 ) { r = -1.207e+01; } if( w==1 ) { r = -1.248e+01; } if( w<=0 ) { r = -1.317e+01; } result = r; return result; } /************************************************************************* Tail(S, 20) *************************************************************************/ static double wsr_w20(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-2.678619e+01*s+1.050000e+02, _state); if( w>=105 ) { r = -6.787e-01; } if( w==104 ) { r = -7.078e-01; } if( w==103 ) { r = -7.378e-01; } if( w==102 ) { r = -7.686e-01; } if( w==101 ) { r = -8.004e-01; } if( w==100 ) { r = -8.330e-01; } if( w==99 ) { r = -8.665e-01; } if( w==98 ) { r = -9.010e-01; } if( w==97 ) { r = -9.363e-01; } if( w==96 ) { r = -9.726e-01; } if( w==95 ) { r = -1.010e+00; } if( w==94 ) { r = -1.048e+00; } if( w==93 ) { r = -1.087e+00; } if( w==92 ) { r = -1.128e+00; } if( w==91 ) { r = -1.169e+00; } if( w==90 ) { r = -1.211e+00; } if( w==89 ) { r = -1.254e+00; } if( w==88 ) { r = -1.299e+00; } if( w==87 ) { r = -1.344e+00; } if( w==86 ) { r = -1.390e+00; } if( w==85 ) { r = -1.438e+00; } if( w==84 ) { r = -1.486e+00; } if( w==83 ) { r = -1.536e+00; } if( w==82 ) { r = -1.587e+00; } if( w==81 ) { r = -1.639e+00; } if( w==80 ) { r = -1.692e+00; } if( w==79 ) { r = -1.746e+00; } if( w==78 ) { r = -1.802e+00; } if( w==77 ) { r = -1.859e+00; } if( w==76 ) { r = -1.916e+00; } if( w==75 ) { r = -1.976e+00; } if( w==74 ) { r = -2.036e+00; } if( w==73 ) { r = -2.098e+00; } if( w==72 ) { r = -2.161e+00; } if( w==71 ) { r = -2.225e+00; } if( w==70 ) { r = -2.290e+00; } if( w==69 ) { r = -2.357e+00; } if( w==68 ) { r = -2.426e+00; } if( w==67 ) { r = -2.495e+00; } if( w==66 ) { r = -2.566e+00; } if( w==65 ) { r = -2.639e+00; } if( w==64 ) { r = -2.713e+00; } if( w==63 ) { r = -2.788e+00; } if( w==62 ) { r = -2.865e+00; } if( w==61 ) { r = -2.943e+00; } if( w==60 ) { r = -3.023e+00; } if( w==59 ) { r = -3.104e+00; } if( w==58 ) { r = -3.187e+00; } if( w==57 ) { r = -3.272e+00; } if( w==56 ) { r = -3.358e+00; } if( w==55 ) { r = -3.446e+00; } if( w==54 ) { r = -3.536e+00; } if( w==53 ) { r = -3.627e+00; } if( w==52 ) { r = -3.721e+00; } if( w==51 ) { r = -3.815e+00; } if( w==50 ) { r = -3.912e+00; } if( w==49 ) { r = -4.011e+00; } if( w==48 ) { r = -4.111e+00; } if( w==47 ) { r = -4.214e+00; } if( w==46 ) { r = -4.318e+00; } if( w==45 ) { r = -4.425e+00; } if( w==44 ) { r = -4.534e+00; } if( w==43 ) { r = -4.644e+00; } if( w==42 ) { r = -4.757e+00; } if( w==41 ) { r = -4.872e+00; } if( w==40 ) { r = -4.990e+00; } if( w==39 ) { r = -5.109e+00; } if( w==38 ) { r = -5.232e+00; } if( w==37 ) { r = -5.356e+00; } if( w==36 ) { r = -5.484e+00; } if( w==35 ) { r = -5.614e+00; } if( w==34 ) { r = -5.746e+00; } if( w==33 ) { r = -5.882e+00; } if( w==32 ) { r = -6.020e+00; } if( w==31 ) { r = -6.161e+00; } if( w==30 ) { r = -6.305e+00; } if( w==29 ) { r = -6.453e+00; } if( w==28 ) { r = -6.603e+00; } if( w==27 ) { r = -6.757e+00; } if( w==26 ) { r = -6.915e+00; } if( w==25 ) { r = -7.076e+00; } if( w==24 ) { r = -7.242e+00; } if( w==23 ) { r = -7.411e+00; } if( w==22 ) { r = -7.584e+00; } if( w==21 ) { r = -7.763e+00; } if( w==20 ) { r = -7.947e+00; } if( w==19 ) { r = -8.136e+00; } if( w==18 ) { r = -8.330e+00; } if( w==17 ) { r = -8.530e+00; } if( w==16 ) { r = -8.733e+00; } if( w==15 ) { r = -8.943e+00; } if( w==14 ) { r = -9.162e+00; } if( w==13 ) { r = -9.386e+00; } if( w==12 ) { r = -9.614e+00; } if( w==11 ) { r = -9.856e+00; } if( w==10 ) { r = -1.010e+01; } if( w==9 ) { r = -1.037e+01; } if( w==8 ) { r = -1.064e+01; } if( w==7 ) { r = -1.092e+01; } if( w==6 ) { r = -1.122e+01; } if( w==5 ) { r = -1.156e+01; } if( w==4 ) { r = -1.192e+01; } if( w==3 ) { r = -1.225e+01; } if( w==2 ) { r = -1.276e+01; } if( w==1 ) { r = -1.317e+01; } if( w<=0 ) { r = -1.386e+01; } result = r; return result; } /************************************************************************* Tail(S, 21) *************************************************************************/ static double wsr_w21(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-2.877064e+01*s+1.155000e+02, _state); if( w>=115 ) { r = -6.931e-01; } if( w==114 ) { r = -7.207e-01; } if( w==113 ) { r = -7.489e-01; } if( w==112 ) { r = -7.779e-01; } if( w==111 ) { r = -8.077e-01; } if( w==110 ) { r = -8.383e-01; } if( w==109 ) { r = -8.697e-01; } if( w==108 ) { r = -9.018e-01; } if( w==107 ) { r = -9.348e-01; } if( w==106 ) { r = -9.685e-01; } if( w==105 ) { r = -1.003e+00; } if( w==104 ) { r = -1.039e+00; } if( w==103 ) { r = -1.075e+00; } if( w==102 ) { r = -1.112e+00; } if( w==101 ) { r = -1.150e+00; } if( w==100 ) { r = -1.189e+00; } if( w==99 ) { r = -1.229e+00; } if( w==98 ) { r = -1.269e+00; } if( w==97 ) { r = -1.311e+00; } if( w==96 ) { r = -1.353e+00; } if( w==95 ) { r = -1.397e+00; } if( w==94 ) { r = -1.441e+00; } if( w==93 ) { r = -1.486e+00; } if( w==92 ) { r = -1.533e+00; } if( w==91 ) { r = -1.580e+00; } if( w==90 ) { r = -1.628e+00; } if( w==89 ) { r = -1.677e+00; } if( w==88 ) { r = -1.728e+00; } if( w==87 ) { r = -1.779e+00; } if( w==86 ) { r = -1.831e+00; } if( w==85 ) { r = -1.884e+00; } if( w==84 ) { r = -1.939e+00; } if( w==83 ) { r = -1.994e+00; } if( w==82 ) { r = -2.051e+00; } if( w==81 ) { r = -2.108e+00; } if( w==80 ) { r = -2.167e+00; } if( w==79 ) { r = -2.227e+00; } if( w==78 ) { r = -2.288e+00; } if( w==77 ) { r = -2.350e+00; } if( w==76 ) { r = -2.414e+00; } if( w==75 ) { r = -2.478e+00; } if( w==74 ) { r = -2.544e+00; } if( w==73 ) { r = -2.611e+00; } if( w==72 ) { r = -2.679e+00; } if( w==71 ) { r = -2.748e+00; } if( w==70 ) { r = -2.819e+00; } if( w==69 ) { r = -2.891e+00; } if( w==68 ) { r = -2.964e+00; } if( w==67 ) { r = -3.039e+00; } if( w==66 ) { r = -3.115e+00; } if( w==65 ) { r = -3.192e+00; } if( w==64 ) { r = -3.270e+00; } if( w==63 ) { r = -3.350e+00; } if( w==62 ) { r = -3.432e+00; } if( w==61 ) { r = -3.515e+00; } if( w==60 ) { r = -3.599e+00; } if( w==59 ) { r = -3.685e+00; } if( w==58 ) { r = -3.772e+00; } if( w==57 ) { r = -3.861e+00; } if( w==56 ) { r = -3.952e+00; } if( w==55 ) { r = -4.044e+00; } if( w==54 ) { r = -4.138e+00; } if( w==53 ) { r = -4.233e+00; } if( w==52 ) { r = -4.330e+00; } if( w==51 ) { r = -4.429e+00; } if( w==50 ) { r = -4.530e+00; } if( w==49 ) { r = -4.632e+00; } if( w==48 ) { r = -4.736e+00; } if( w==47 ) { r = -4.842e+00; } if( w==46 ) { r = -4.950e+00; } if( w==45 ) { r = -5.060e+00; } if( w==44 ) { r = -5.172e+00; } if( w==43 ) { r = -5.286e+00; } if( w==42 ) { r = -5.402e+00; } if( w==41 ) { r = -5.520e+00; } if( w==40 ) { r = -5.641e+00; } if( w==39 ) { r = -5.763e+00; } if( w==38 ) { r = -5.889e+00; } if( w==37 ) { r = -6.016e+00; } if( w==36 ) { r = -6.146e+00; } if( w==35 ) { r = -6.278e+00; } if( w==34 ) { r = -6.413e+00; } if( w==33 ) { r = -6.551e+00; } if( w==32 ) { r = -6.692e+00; } if( w==31 ) { r = -6.835e+00; } if( w==30 ) { r = -6.981e+00; } if( w==29 ) { r = -7.131e+00; } if( w==28 ) { r = -7.283e+00; } if( w==27 ) { r = -7.439e+00; } if( w==26 ) { r = -7.599e+00; } if( w==25 ) { r = -7.762e+00; } if( w==24 ) { r = -7.928e+00; } if( w==23 ) { r = -8.099e+00; } if( w==22 ) { r = -8.274e+00; } if( w==21 ) { r = -8.454e+00; } if( w==20 ) { r = -8.640e+00; } if( w==19 ) { r = -8.829e+00; } if( w==18 ) { r = -9.023e+00; } if( w==17 ) { r = -9.223e+00; } if( w==16 ) { r = -9.426e+00; } if( w==15 ) { r = -9.636e+00; } if( w==14 ) { r = -9.856e+00; } if( w==13 ) { r = -1.008e+01; } if( w==12 ) { r = -1.031e+01; } if( w==11 ) { r = -1.055e+01; } if( w==10 ) { r = -1.079e+01; } if( w==9 ) { r = -1.106e+01; } if( w==8 ) { r = -1.134e+01; } if( w==7 ) { r = -1.161e+01; } if( w==6 ) { r = -1.192e+01; } if( w==5 ) { r = -1.225e+01; } if( w==4 ) { r = -1.261e+01; } if( w==3 ) { r = -1.295e+01; } if( w==2 ) { r = -1.346e+01; } if( w==1 ) { r = -1.386e+01; } if( w<=0 ) { r = -1.456e+01; } result = r; return result; } /************************************************************************* Tail(S, 22) *************************************************************************/ static double wsr_w22(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-3.080179e+01*s+1.265000e+02, _state); if( w>=126 ) { r = -6.931e-01; } if( w==125 ) { r = -7.189e-01; } if( w==124 ) { r = -7.452e-01; } if( w==123 ) { r = -7.722e-01; } if( w==122 ) { r = -7.999e-01; } if( w==121 ) { r = -8.283e-01; } if( w==120 ) { r = -8.573e-01; } if( w==119 ) { r = -8.871e-01; } if( w==118 ) { r = -9.175e-01; } if( w==117 ) { r = -9.486e-01; } if( w==116 ) { r = -9.805e-01; } if( w==115 ) { r = -1.013e+00; } if( w==114 ) { r = -1.046e+00; } if( w==113 ) { r = -1.080e+00; } if( w==112 ) { r = -1.115e+00; } if( w==111 ) { r = -1.151e+00; } if( w==110 ) { r = -1.187e+00; } if( w==109 ) { r = -1.224e+00; } if( w==108 ) { r = -1.262e+00; } if( w==107 ) { r = -1.301e+00; } if( w==106 ) { r = -1.340e+00; } if( w==105 ) { r = -1.381e+00; } if( w==104 ) { r = -1.422e+00; } if( w==103 ) { r = -1.464e+00; } if( w==102 ) { r = -1.506e+00; } if( w==101 ) { r = -1.550e+00; } if( w==100 ) { r = -1.594e+00; } if( w==99 ) { r = -1.640e+00; } if( w==98 ) { r = -1.686e+00; } if( w==97 ) { r = -1.733e+00; } if( w==96 ) { r = -1.781e+00; } if( w==95 ) { r = -1.830e+00; } if( w==94 ) { r = -1.880e+00; } if( w==93 ) { r = -1.930e+00; } if( w==92 ) { r = -1.982e+00; } if( w==91 ) { r = -2.034e+00; } if( w==90 ) { r = -2.088e+00; } if( w==89 ) { r = -2.142e+00; } if( w==88 ) { r = -2.198e+00; } if( w==87 ) { r = -2.254e+00; } if( w==86 ) { r = -2.312e+00; } if( w==85 ) { r = -2.370e+00; } if( w==84 ) { r = -2.429e+00; } if( w==83 ) { r = -2.490e+00; } if( w==82 ) { r = -2.551e+00; } if( w==81 ) { r = -2.614e+00; } if( w==80 ) { r = -2.677e+00; } if( w==79 ) { r = -2.742e+00; } if( w==78 ) { r = -2.808e+00; } if( w==77 ) { r = -2.875e+00; } if( w==76 ) { r = -2.943e+00; } if( w==75 ) { r = -3.012e+00; } if( w==74 ) { r = -3.082e+00; } if( w==73 ) { r = -3.153e+00; } if( w==72 ) { r = -3.226e+00; } if( w==71 ) { r = -3.300e+00; } if( w==70 ) { r = -3.375e+00; } if( w==69 ) { r = -3.451e+00; } if( w==68 ) { r = -3.529e+00; } if( w==67 ) { r = -3.607e+00; } if( w==66 ) { r = -3.687e+00; } if( w==65 ) { r = -3.769e+00; } if( w==64 ) { r = -3.851e+00; } if( w==63 ) { r = -3.935e+00; } if( w==62 ) { r = -4.021e+00; } if( w==61 ) { r = -4.108e+00; } if( w==60 ) { r = -4.196e+00; } if( w==59 ) { r = -4.285e+00; } if( w==58 ) { r = -4.376e+00; } if( w==57 ) { r = -4.469e+00; } if( w==56 ) { r = -4.563e+00; } if( w==55 ) { r = -4.659e+00; } if( w==54 ) { r = -4.756e+00; } if( w==53 ) { r = -4.855e+00; } if( w==52 ) { r = -4.955e+00; } if( w==51 ) { r = -5.057e+00; } if( w==50 ) { r = -5.161e+00; } if( w==49 ) { r = -5.266e+00; } if( w==48 ) { r = -5.374e+00; } if( w==47 ) { r = -5.483e+00; } if( w==46 ) { r = -5.594e+00; } if( w==45 ) { r = -5.706e+00; } if( w==44 ) { r = -5.821e+00; } if( w==43 ) { r = -5.938e+00; } if( w==42 ) { r = -6.057e+00; } if( w==41 ) { r = -6.177e+00; } if( w==40 ) { r = -6.300e+00; } if( w==39 ) { r = -6.426e+00; } if( w==38 ) { r = -6.553e+00; } if( w==37 ) { r = -6.683e+00; } if( w==36 ) { r = -6.815e+00; } if( w==35 ) { r = -6.949e+00; } if( w==34 ) { r = -7.086e+00; } if( w==33 ) { r = -7.226e+00; } if( w==32 ) { r = -7.368e+00; } if( w==31 ) { r = -7.513e+00; } if( w==30 ) { r = -7.661e+00; } if( w==29 ) { r = -7.813e+00; } if( w==28 ) { r = -7.966e+00; } if( w==27 ) { r = -8.124e+00; } if( w==26 ) { r = -8.285e+00; } if( w==25 ) { r = -8.449e+00; } if( w==24 ) { r = -8.617e+00; } if( w==23 ) { r = -8.789e+00; } if( w==22 ) { r = -8.965e+00; } if( w==21 ) { r = -9.147e+00; } if( w==20 ) { r = -9.333e+00; } if( w==19 ) { r = -9.522e+00; } if( w==18 ) { r = -9.716e+00; } if( w==17 ) { r = -9.917e+00; } if( w==16 ) { r = -1.012e+01; } if( w==15 ) { r = -1.033e+01; } if( w==14 ) { r = -1.055e+01; } if( w==13 ) { r = -1.077e+01; } if( w==12 ) { r = -1.100e+01; } if( w==11 ) { r = -1.124e+01; } if( w==10 ) { r = -1.149e+01; } if( w==9 ) { r = -1.175e+01; } if( w==8 ) { r = -1.203e+01; } if( w==7 ) { r = -1.230e+01; } if( w==6 ) { r = -1.261e+01; } if( w==5 ) { r = -1.295e+01; } if( w==4 ) { r = -1.330e+01; } if( w==3 ) { r = -1.364e+01; } if( w==2 ) { r = -1.415e+01; } if( w==1 ) { r = -1.456e+01; } if( w<=0 ) { r = -1.525e+01; } result = r; return result; } /************************************************************************* Tail(S, 23) *************************************************************************/ static double wsr_w23(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-3.287856e+01*s+1.380000e+02, _state); if( w>=138 ) { r = -6.813e-01; } if( w==137 ) { r = -7.051e-01; } if( w==136 ) { r = -7.295e-01; } if( w==135 ) { r = -7.544e-01; } if( w==134 ) { r = -7.800e-01; } if( w==133 ) { r = -8.061e-01; } if( w==132 ) { r = -8.328e-01; } if( w==131 ) { r = -8.601e-01; } if( w==130 ) { r = -8.880e-01; } if( w==129 ) { r = -9.166e-01; } if( w==128 ) { r = -9.457e-01; } if( w==127 ) { r = -9.755e-01; } if( w==126 ) { r = -1.006e+00; } if( w==125 ) { r = -1.037e+00; } if( w==124 ) { r = -1.069e+00; } if( w==123 ) { r = -1.101e+00; } if( w==122 ) { r = -1.134e+00; } if( w==121 ) { r = -1.168e+00; } if( w==120 ) { r = -1.202e+00; } if( w==119 ) { r = -1.237e+00; } if( w==118 ) { r = -1.273e+00; } if( w==117 ) { r = -1.309e+00; } if( w==116 ) { r = -1.347e+00; } if( w==115 ) { r = -1.384e+00; } if( w==114 ) { r = -1.423e+00; } if( w==113 ) { r = -1.462e+00; } if( w==112 ) { r = -1.502e+00; } if( w==111 ) { r = -1.543e+00; } if( w==110 ) { r = -1.585e+00; } if( w==109 ) { r = -1.627e+00; } if( w==108 ) { r = -1.670e+00; } if( w==107 ) { r = -1.714e+00; } if( w==106 ) { r = -1.758e+00; } if( w==105 ) { r = -1.804e+00; } if( w==104 ) { r = -1.850e+00; } if( w==103 ) { r = -1.897e+00; } if( w==102 ) { r = -1.944e+00; } if( w==101 ) { r = -1.993e+00; } if( w==100 ) { r = -2.042e+00; } if( w==99 ) { r = -2.093e+00; } if( w==98 ) { r = -2.144e+00; } if( w==97 ) { r = -2.195e+00; } if( w==96 ) { r = -2.248e+00; } if( w==95 ) { r = -2.302e+00; } if( w==94 ) { r = -2.356e+00; } if( w==93 ) { r = -2.412e+00; } if( w==92 ) { r = -2.468e+00; } if( w==91 ) { r = -2.525e+00; } if( w==90 ) { r = -2.583e+00; } if( w==89 ) { r = -2.642e+00; } if( w==88 ) { r = -2.702e+00; } if( w==87 ) { r = -2.763e+00; } if( w==86 ) { r = -2.825e+00; } if( w==85 ) { r = -2.888e+00; } if( w==84 ) { r = -2.951e+00; } if( w==83 ) { r = -3.016e+00; } if( w==82 ) { r = -3.082e+00; } if( w==81 ) { r = -3.149e+00; } if( w==80 ) { r = -3.216e+00; } if( w==79 ) { r = -3.285e+00; } if( w==78 ) { r = -3.355e+00; } if( w==77 ) { r = -3.426e+00; } if( w==76 ) { r = -3.498e+00; } if( w==75 ) { r = -3.571e+00; } if( w==74 ) { r = -3.645e+00; } if( w==73 ) { r = -3.721e+00; } if( w==72 ) { r = -3.797e+00; } if( w==71 ) { r = -3.875e+00; } if( w==70 ) { r = -3.953e+00; } if( w==69 ) { r = -4.033e+00; } if( w==68 ) { r = -4.114e+00; } if( w==67 ) { r = -4.197e+00; } if( w==66 ) { r = -4.280e+00; } if( w==65 ) { r = -4.365e+00; } if( w==64 ) { r = -4.451e+00; } if( w==63 ) { r = -4.539e+00; } if( w==62 ) { r = -4.628e+00; } if( w==61 ) { r = -4.718e+00; } if( w==60 ) { r = -4.809e+00; } if( w==59 ) { r = -4.902e+00; } if( w==58 ) { r = -4.996e+00; } if( w==57 ) { r = -5.092e+00; } if( w==56 ) { r = -5.189e+00; } if( w==55 ) { r = -5.287e+00; } if( w==54 ) { r = -5.388e+00; } if( w==53 ) { r = -5.489e+00; } if( w==52 ) { r = -5.592e+00; } if( w==51 ) { r = -5.697e+00; } if( w==50 ) { r = -5.804e+00; } if( w==49 ) { r = -5.912e+00; } if( w==48 ) { r = -6.022e+00; } if( w==47 ) { r = -6.133e+00; } if( w==46 ) { r = -6.247e+00; } if( w==45 ) { r = -6.362e+00; } if( w==44 ) { r = -6.479e+00; } if( w==43 ) { r = -6.598e+00; } if( w==42 ) { r = -6.719e+00; } if( w==41 ) { r = -6.842e+00; } if( w==40 ) { r = -6.967e+00; } if( w==39 ) { r = -7.094e+00; } if( w==38 ) { r = -7.224e+00; } if( w==37 ) { r = -7.355e+00; } if( w==36 ) { r = -7.489e+00; } if( w==35 ) { r = -7.625e+00; } if( w==34 ) { r = -7.764e+00; } if( w==33 ) { r = -7.905e+00; } if( w==32 ) { r = -8.049e+00; } if( w==31 ) { r = -8.196e+00; } if( w==30 ) { r = -8.345e+00; } if( w==29 ) { r = -8.498e+00; } if( w==28 ) { r = -8.653e+00; } if( w==27 ) { r = -8.811e+00; } if( w==26 ) { r = -8.974e+00; } if( w==25 ) { r = -9.139e+00; } if( w==24 ) { r = -9.308e+00; } if( w==23 ) { r = -9.481e+00; } if( w==22 ) { r = -9.658e+00; } if( w==21 ) { r = -9.840e+00; } if( w==20 ) { r = -1.003e+01; } if( w==19 ) { r = -1.022e+01; } if( w==18 ) { r = -1.041e+01; } if( w==17 ) { r = -1.061e+01; } if( w==16 ) { r = -1.081e+01; } if( w==15 ) { r = -1.102e+01; } if( w==14 ) { r = -1.124e+01; } if( w==13 ) { r = -1.147e+01; } if( w==12 ) { r = -1.169e+01; } if( w==11 ) { r = -1.194e+01; } if( w==10 ) { r = -1.218e+01; } if( w==9 ) { r = -1.245e+01; } if( w==8 ) { r = -1.272e+01; } if( w==7 ) { r = -1.300e+01; } if( w==6 ) { r = -1.330e+01; } if( w==5 ) { r = -1.364e+01; } if( w==4 ) { r = -1.400e+01; } if( w==3 ) { r = -1.433e+01; } if( w==2 ) { r = -1.484e+01; } if( w==1 ) { r = -1.525e+01; } if( w<=0 ) { r = -1.594e+01; } result = r; return result; } /************************************************************************* Tail(S, 24) *************************************************************************/ static double wsr_w24(double s, ae_state *_state) { ae_int_t w; double r; double result; r = (double)(0); w = ae_round(-3.500000e+01*s+1.500000e+02, _state); if( w>=150 ) { r = -6.820e-01; } if( w==149 ) { r = -7.044e-01; } if( w==148 ) { r = -7.273e-01; } if( w==147 ) { r = -7.507e-01; } if( w==146 ) { r = -7.746e-01; } if( w==145 ) { r = -7.990e-01; } if( w==144 ) { r = -8.239e-01; } if( w==143 ) { r = -8.494e-01; } if( w==142 ) { r = -8.754e-01; } if( w==141 ) { r = -9.020e-01; } if( w==140 ) { r = -9.291e-01; } if( w==139 ) { r = -9.567e-01; } if( w==138 ) { r = -9.849e-01; } if( w==137 ) { r = -1.014e+00; } if( w==136 ) { r = -1.043e+00; } if( w==135 ) { r = -1.073e+00; } if( w==134 ) { r = -1.103e+00; } if( w==133 ) { r = -1.135e+00; } if( w==132 ) { r = -1.166e+00; } if( w==131 ) { r = -1.198e+00; } if( w==130 ) { r = -1.231e+00; } if( w==129 ) { r = -1.265e+00; } if( w==128 ) { r = -1.299e+00; } if( w==127 ) { r = -1.334e+00; } if( w==126 ) { r = -1.369e+00; } if( w==125 ) { r = -1.405e+00; } if( w==124 ) { r = -1.441e+00; } if( w==123 ) { r = -1.479e+00; } if( w==122 ) { r = -1.517e+00; } if( w==121 ) { r = -1.555e+00; } if( w==120 ) { r = -1.594e+00; } if( w==119 ) { r = -1.634e+00; } if( w==118 ) { r = -1.675e+00; } if( w==117 ) { r = -1.716e+00; } if( w==116 ) { r = -1.758e+00; } if( w==115 ) { r = -1.800e+00; } if( w==114 ) { r = -1.844e+00; } if( w==113 ) { r = -1.888e+00; } if( w==112 ) { r = -1.932e+00; } if( w==111 ) { r = -1.978e+00; } if( w==110 ) { r = -2.024e+00; } if( w==109 ) { r = -2.070e+00; } if( w==108 ) { r = -2.118e+00; } if( w==107 ) { r = -2.166e+00; } if( w==106 ) { r = -2.215e+00; } if( w==105 ) { r = -2.265e+00; } if( w==104 ) { r = -2.316e+00; } if( w==103 ) { r = -2.367e+00; } if( w==102 ) { r = -2.419e+00; } if( w==101 ) { r = -2.472e+00; } if( w==100 ) { r = -2.526e+00; } if( w==99 ) { r = -2.580e+00; } if( w==98 ) { r = -2.636e+00; } if( w==97 ) { r = -2.692e+00; } if( w==96 ) { r = -2.749e+00; } if( w==95 ) { r = -2.806e+00; } if( w==94 ) { r = -2.865e+00; } if( w==93 ) { r = -2.925e+00; } if( w==92 ) { r = -2.985e+00; } if( w==91 ) { r = -3.046e+00; } if( w==90 ) { r = -3.108e+00; } if( w==89 ) { r = -3.171e+00; } if( w==88 ) { r = -3.235e+00; } if( w==87 ) { r = -3.300e+00; } if( w==86 ) { r = -3.365e+00; } if( w==85 ) { r = -3.432e+00; } if( w==84 ) { r = -3.499e+00; } if( w==83 ) { r = -3.568e+00; } if( w==82 ) { r = -3.637e+00; } if( w==81 ) { r = -3.708e+00; } if( w==80 ) { r = -3.779e+00; } if( w==79 ) { r = -3.852e+00; } if( w==78 ) { r = -3.925e+00; } if( w==77 ) { r = -4.000e+00; } if( w==76 ) { r = -4.075e+00; } if( w==75 ) { r = -4.151e+00; } if( w==74 ) { r = -4.229e+00; } if( w==73 ) { r = -4.308e+00; } if( w==72 ) { r = -4.387e+00; } if( w==71 ) { r = -4.468e+00; } if( w==70 ) { r = -4.550e+00; } if( w==69 ) { r = -4.633e+00; } if( w==68 ) { r = -4.718e+00; } if( w==67 ) { r = -4.803e+00; } if( w==66 ) { r = -4.890e+00; } if( w==65 ) { r = -4.978e+00; } if( w==64 ) { r = -5.067e+00; } if( w==63 ) { r = -5.157e+00; } if( w==62 ) { r = -5.249e+00; } if( w==61 ) { r = -5.342e+00; } if( w==60 ) { r = -5.436e+00; } if( w==59 ) { r = -5.531e+00; } if( w==58 ) { r = -5.628e+00; } if( w==57 ) { r = -5.727e+00; } if( w==56 ) { r = -5.826e+00; } if( w==55 ) { r = -5.927e+00; } if( w==54 ) { r = -6.030e+00; } if( w==53 ) { r = -6.134e+00; } if( w==52 ) { r = -6.240e+00; } if( w==51 ) { r = -6.347e+00; } if( w==50 ) { r = -6.456e+00; } if( w==49 ) { r = -6.566e+00; } if( w==48 ) { r = -6.678e+00; } if( w==47 ) { r = -6.792e+00; } if( w==46 ) { r = -6.907e+00; } if( w==45 ) { r = -7.025e+00; } if( w==44 ) { r = -7.144e+00; } if( w==43 ) { r = -7.265e+00; } if( w==42 ) { r = -7.387e+00; } if( w==41 ) { r = -7.512e+00; } if( w==40 ) { r = -7.639e+00; } if( w==39 ) { r = -7.768e+00; } if( w==38 ) { r = -7.899e+00; } if( w==37 ) { r = -8.032e+00; } if( w==36 ) { r = -8.167e+00; } if( w==35 ) { r = -8.305e+00; } if( w==34 ) { r = -8.445e+00; } if( w==33 ) { r = -8.588e+00; } if( w==32 ) { r = -8.733e+00; } if( w==31 ) { r = -8.881e+00; } if( w==30 ) { r = -9.031e+00; } if( w==29 ) { r = -9.185e+00; } if( w==28 ) { r = -9.341e+00; } if( w==27 ) { r = -9.501e+00; } if( w==26 ) { r = -9.664e+00; } if( w==25 ) { r = -9.830e+00; } if( w==24 ) { r = -1.000e+01; } if( w==23 ) { r = -1.017e+01; } if( w==22 ) { r = -1.035e+01; } if( w==21 ) { r = -1.053e+01; } if( w==20 ) { r = -1.072e+01; } if( w==19 ) { r = -1.091e+01; } if( w==18 ) { r = -1.110e+01; } if( w==17 ) { r = -1.130e+01; } if( w==16 ) { r = -1.151e+01; } if( w==15 ) { r = -1.172e+01; } if( w==14 ) { r = -1.194e+01; } if( w==13 ) { r = -1.216e+01; } if( w==12 ) { r = -1.239e+01; } if( w==11 ) { r = -1.263e+01; } if( w==10 ) { r = -1.287e+01; } if( w==9 ) { r = -1.314e+01; } if( w==8 ) { r = -1.342e+01; } if( w==7 ) { r = -1.369e+01; } if( w==6 ) { r = -1.400e+01; } if( w==5 ) { r = -1.433e+01; } if( w==4 ) { r = -1.469e+01; } if( w==3 ) { r = -1.503e+01; } if( w==2 ) { r = -1.554e+01; } if( w==1 ) { r = -1.594e+01; } if( w<=0 ) { r = -1.664e+01; } result = r; return result; } /************************************************************************* Tail(S, 25) *************************************************************************/ static double wsr_w25(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.150509e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.695528e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.437637e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.611906e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -7.625722e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.579892e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.086876e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.906543e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.354881e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 1.007195e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -8.437327e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 26) *************************************************************************/ static double wsr_w26(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.117622e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.635159e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.395167e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.382823e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -6.531987e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.060112e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -8.203697e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.516523e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.431364e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 6.384553e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -3.238369e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 27) *************************************************************************/ static double wsr_w27(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.089731e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.584248e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.359966e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.203696e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.753344e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.761891e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -7.096897e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.419108e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.581214e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 3.033766e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.901441e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 28) *************************************************************************/ static double wsr_w28(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.065046e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.539163e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.328939e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.046376e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.061515e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.469271e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.711578e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -8.389153e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.250575e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 4.047245e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.128555e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 29) *************************************************************************/ static double wsr_w29(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.043413e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.499756e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.302137e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.915129e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.516329e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.260064e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.817269e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.478130e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.111668e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 4.093451e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.135860e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 30) *************************************************************************/ static double wsr_w30(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -5.024071e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.464515e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.278342e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.800030e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.046294e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.076162e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -3.968677e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.911679e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -8.619185e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, 5.125362e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -3.984370e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 40) *************************************************************************/ static double wsr_w40(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -4.904809e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.248327e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.136698e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.170982e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.824427e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -3.888648e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.344929e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, 2.790407e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.619858e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, 3.359121e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.883026e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 60) *************************************************************************/ static double wsr_w60(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -4.809656e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.077191e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.029402e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -7.507931e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, -6.506226e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.391278e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.263635e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, 2.302271e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.384348e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, 1.865587e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.622355e-04, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 120) *************************************************************************/ static double wsr_w120(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -4.729426e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.934426e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -9.433231e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.492504e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, 1.673948e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, -6.077014e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -7.215768e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, 9.086734e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, -8.447980e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, 6.705028e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.828507e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S, 200) *************************************************************************/ static double wsr_w200(double s, ae_state *_state) { double x; double tj; double tj1; double result; result = (double)(0); x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); tj = (double)(1); tj1 = x; wsr_wcheb(x, -4.700240e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.883080e+00, &tj, &tj1, &result, _state); wsr_wcheb(x, -9.132168e-01, &tj, &tj1, &result, _state); wsr_wcheb(x, -3.512684e-02, &tj, &tj1, &result, _state); wsr_wcheb(x, 1.726342e-03, &tj, &tj1, &result, _state); wsr_wcheb(x, -5.189796e-04, &tj, &tj1, &result, _state); wsr_wcheb(x, -1.628659e-06, &tj, &tj1, &result, _state); wsr_wcheb(x, 4.261786e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, -4.002498e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, 3.146287e-05, &tj, &tj1, &result, _state); wsr_wcheb(x, -2.727576e-05, &tj, &tj1, &result, _state); return result; } /************************************************************************* Tail(S,N), S>=0 *************************************************************************/ static double wsr_wsigma(double s, ae_int_t n, ae_state *_state) { double f0; double f1; double f2; double f3; double f4; double x0; double x1; double x2; double x3; double x4; double x; double result; result = (double)(0); if( n==5 ) { result = wsr_w5(s, _state); } if( n==6 ) { result = wsr_w6(s, _state); } if( n==7 ) { result = wsr_w7(s, _state); } if( n==8 ) { result = wsr_w8(s, _state); } if( n==9 ) { result = wsr_w9(s, _state); } if( n==10 ) { result = wsr_w10(s, _state); } if( n==11 ) { result = wsr_w11(s, _state); } if( n==12 ) { result = wsr_w12(s, _state); } if( n==13 ) { result = wsr_w13(s, _state); } if( n==14 ) { result = wsr_w14(s, _state); } if( n==15 ) { result = wsr_w15(s, _state); } if( n==16 ) { result = wsr_w16(s, _state); } if( n==17 ) { result = wsr_w17(s, _state); } if( n==18 ) { result = wsr_w18(s, _state); } if( n==19 ) { result = wsr_w19(s, _state); } if( n==20 ) { result = wsr_w20(s, _state); } if( n==21 ) { result = wsr_w21(s, _state); } if( n==22 ) { result = wsr_w22(s, _state); } if( n==23 ) { result = wsr_w23(s, _state); } if( n==24 ) { result = wsr_w24(s, _state); } if( n==25 ) { result = wsr_w25(s, _state); } if( n==26 ) { result = wsr_w26(s, _state); } if( n==27 ) { result = wsr_w27(s, _state); } if( n==28 ) { result = wsr_w28(s, _state); } if( n==29 ) { result = wsr_w29(s, _state); } if( n==30 ) { result = wsr_w30(s, _state); } if( n>30 ) { x = 1.0/n; x0 = 1.0/30; f0 = wsr_w30(s, _state); x1 = 1.0/40; f1 = wsr_w40(s, _state); x2 = 1.0/60; f2 = wsr_w60(s, _state); x3 = 1.0/120; f3 = wsr_w120(s, _state); x4 = 1.0/200; f4 = wsr_w200(s, _state); f1 = ((x-x0)*f1-(x-x1)*f0)/(x1-x0); f2 = ((x-x0)*f2-(x-x2)*f0)/(x2-x0); f3 = ((x-x0)*f3-(x-x3)*f0)/(x3-x0); f4 = ((x-x0)*f4-(x-x4)*f0)/(x4-x0); f2 = ((x-x1)*f2-(x-x2)*f1)/(x2-x1); f3 = ((x-x1)*f3-(x-x3)*f1)/(x3-x1); f4 = ((x-x1)*f4-(x-x4)*f1)/(x4-x1); f3 = ((x-x2)*f3-(x-x3)*f2)/(x3-x2); f4 = ((x-x2)*f4-(x-x4)*f2)/(x4-x2); f4 = ((x-x3)*f4-(x-x4)*f3)/(x4-x3); result = f4; } return result; } } qmapshack-1.10.0/3rdparty/alglib/src/fasttransforms.h000755 001750 000144 00000062053 13015033052 023741 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _fasttransforms_pkg_h #define _fasttransforms_pkg_h #include "ap.h" #include "alglibinternal.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* 1-dimensional complex FFT. Array size N may be arbitrary number (composite or prime). Composite N's are handled with cache-oblivious variation of a Cooley-Tukey algorithm. Small prime-factors are transformed using hard coded codelets (similar to FFTW codelets, but without low-level optimization), large prime-factors are handled with Bluestein's algorithm. Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), most fast for powers of 2. When N have prime factors larger than these, but orders of magnitude smaller than N, computations will be about 4 times slower than for nearby highly composite N's. When N itself is prime, speed will be 6 times lower. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS A - DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1d(complex_1d_array &a, const ae_int_t n); void fftc1d(complex_1d_array &a); /************************************************************************* 1-dimensional complex inverse FFT. Array size N may be arbitrary number (composite or prime). Algorithm has O(N*logN) complexity for any N (composite or prime). See FFTC1D() description for more information about algorithm performance. INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fftc1dinv(complex_1d_array &a, const ae_int_t n); void fftc1dinv(complex_1d_array &a); /************************************************************************* 1-dimensional real FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS F - DFT of a input array, array[0..N-1] F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) NOTE: F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half of array is usually needed. But for convinience subroutine returns full complex array (with frequencies above N/2), so its result may be used by other FFT-related subroutines. -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f); void fftr1d(const real_1d_array &a, complex_1d_array &f); /************************************************************************* 1-dimensional real inverse FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS F - array[0..floor(N/2)] - frequencies from forward real FFT N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] NOTE: F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one half of frequencies array is needed - elements from 0 to floor(N/2). F[0] is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then F[floor(N/2)] has no special properties. Relying on properties noted above, FFTR1DInv subroutine uses only elements from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case N is even it ignores imaginary part of F[floor(N/2)] too. When you call this function using full arguments list - "FFTR1DInv(F,N,A)" - you can pass either either frequencies array with N elements or reduced array with roughly N/2 elements - subroutine will successfully transform both. If you call this function using reduced arguments list - "FFTR1DInv(F,A)" - you must pass FULL array with N elements (although higher N/2 are still not used) because array size is used to automatically determine FFT length -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/ void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a); void fftr1dinv(const complex_1d_array &f, real_1d_array &a); /************************************************************************* 1-dimensional complex convolution. For given A/B returns conv(A,B) (non-circular). Subroutine can automatically choose between three implementations: straightforward O(M*N) formula for very small N (or M), overlap-add algorithm for cases where max(M,N) is significantly larger than min(M,N), but O(M*N) algorithm is too slow, and general FFT-based formula for cases where two previois algorithms are too slow. Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); /************************************************************************* 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); /************************************************************************* 1-dimensional circular complex convolution. For given S/R returns conv(S,R) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: normal convolution is commutative, i.e. it is symmetric - conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a signal, periodic function, and another - R - is a response, non-periodic function with limited length. INPUT PARAMETERS S - array[0..M-1] - complex periodic signal M - problem size B - array[0..N-1] - complex non-periodic response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c); /************************************************************************* 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved periodic signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - non-periodic response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-1]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); /************************************************************************* 1-dimensional real convolution. Analogous to ConvC1D(), see ConvC1D() comments for more details. INPUT PARAMETERS A - array[0..M-1] - real function to be transformed M - problem size B - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); /************************************************************************* 1-dimensional real deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); /************************************************************************* 1-dimensional circular real convolution. Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. INPUT PARAMETERS S - array[0..M-1] - real signal M - problem size B - array[0..N-1] - real response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c); /************************************************************************* 1-dimensional complex deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); /************************************************************************* 1-dimensional complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(conj(pattern[j])*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r); /************************************************************************* 1-dimensional circular complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c); /************************************************************************* 1-dimensional real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(pattern[j]*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(pattern[j]*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r); /************************************************************************* 1-dimensional circular real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/ void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c); /************************************************************************* 1-dimensional Fast Hartley Transform. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS A - FHT of a input array, array[0..N-1], A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) -- ALGLIB -- Copyright 04.06.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1d(real_1d_array &a, const ae_int_t n); /************************************************************************* 1-dimensional inverse FHT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse FHT of a input array, array[0..N-1] -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1dinv(real_1d_array &a, const ae_int_t n); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); void fftr1d(/* Real */ ae_vector* a, ae_int_t n, /* Complex */ ae_vector* f, ae_state *_state); void fftr1dinv(/* Complex */ ae_vector* f, ae_int_t n, /* Real */ ae_vector* a, ae_state *_state); void fftr1dinternaleven(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* buf, fasttransformplan* plan, ae_state *_state); void fftr1dinvinternaleven(/* Real */ ae_vector* a, ae_int_t n, /* Real */ ae_vector* buf, fasttransformplan* plan, ae_state *_state); void convc1d(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state); void convc1dinv(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state); void convc1dcircular(/* Complex */ ae_vector* s, ae_int_t m, /* Complex */ ae_vector* r, ae_int_t n, /* Complex */ ae_vector* c, ae_state *_state); void convc1dcircularinv(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state); void convr1d(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state); void convr1dinv(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state); void convr1dcircular(/* Real */ ae_vector* s, ae_int_t m, /* Real */ ae_vector* r, ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); void convr1dcircularinv(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state); void convc1dx(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, ae_bool circular, ae_int_t alg, ae_int_t q, /* Complex */ ae_vector* r, ae_state *_state); void convr1dx(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, ae_bool circular, ae_int_t alg, ae_int_t q, /* Real */ ae_vector* r, ae_state *_state); void corrc1d(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state); void corrc1dcircular(/* Complex */ ae_vector* signal, ae_int_t m, /* Complex */ ae_vector* pattern, ae_int_t n, /* Complex */ ae_vector* c, ae_state *_state); void corrr1d(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state); void corrr1dcircular(/* Real */ ae_vector* signal, ae_int_t m, /* Real */ ae_vector* pattern, ae_int_t n, /* Real */ ae_vector* c, ae_state *_state); void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/interpolation.h000755 001750 000144 00001130647 13015033052 023562 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _interpolation_pkg_h #define _interpolation_pkg_h #include "ap.h" #include "alglibinternal.h" #include "alglibmisc.h" #include "linalg.h" #include "solvers.h" #include "optimization.h" #include "specialfunctions.h" #include "integration.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_int_t n; ae_int_t nx; ae_int_t d; double r; ae_int_t nw; kdtree tree; ae_int_t modeltype; ae_matrix q; ae_vector xbuf; ae_vector tbuf; ae_vector rbuf; ae_matrix xybuf; ae_int_t debugsolverfailures; double debugworstrcond; double debugbestrcond; } idwinterpolant; typedef struct { ae_int_t n; double sy; ae_vector x; ae_vector y; ae_vector w; } barycentricinterpolant; typedef struct { ae_bool periodic; ae_int_t n; ae_int_t k; ae_int_t continuity; ae_vector x; ae_vector c; } spline1dinterpolant; typedef struct { double taskrcond; double rmserror; double avgerror; double avgrelerror; double maxerror; } polynomialfitreport; typedef struct { double taskrcond; ae_int_t dbest; double rmserror; double avgerror; double avgrelerror; double maxerror; } barycentricfitreport; typedef struct { double taskrcond; double rmserror; double avgerror; double avgrelerror; double maxerror; } spline1dfitreport; typedef struct { double taskrcond; ae_int_t iterationscount; ae_int_t varidx; double rmserror; double avgerror; double avgrelerror; double maxerror; double wrmserror; ae_matrix covpar; ae_vector errpar; ae_vector errcurve; ae_vector noise; double r2; } lsfitreport; typedef struct { ae_int_t optalgo; ae_int_t m; ae_int_t k; double epsf; double epsx; ae_int_t maxits; double stpmax; ae_bool xrep; ae_vector s; ae_vector bndl; ae_vector bndu; ae_matrix taskx; ae_vector tasky; ae_int_t npoints; ae_vector taskw; ae_int_t nweights; ae_int_t wkind; ae_int_t wits; double diffstep; double teststep; ae_bool xupdated; ae_bool needf; ae_bool needfg; ae_bool needfgh; ae_int_t pointindex; ae_vector x; ae_vector c; double f; ae_vector g; ae_matrix h; ae_vector wcur; ae_vector tmp; ae_vector tmpf; ae_matrix tmpjac; ae_matrix tmpjacw; double tmpnoise; matinvreport invrep; ae_int_t repiterationscount; ae_int_t repterminationtype; ae_int_t repvaridx; double reprmserror; double repavgerror; double repavgrelerror; double repmaxerror; double repwrmserror; lsfitreport rep; minlmstate optstate; minlmreport optrep; ae_int_t prevnpt; ae_int_t prevalgo; rcommstate rstate; } lsfitstate; typedef struct { ae_int_t n; ae_bool periodic; ae_vector p; spline1dinterpolant x; spline1dinterpolant y; } pspline2interpolant; typedef struct { ae_int_t n; ae_bool periodic; ae_vector p; spline1dinterpolant x; spline1dinterpolant y; spline1dinterpolant z; } pspline3interpolant; typedef struct { ae_int_t ny; ae_int_t nx; ae_int_t nc; ae_int_t nl; kdtree tree; ae_matrix xc; ae_matrix wr; double rmax; ae_matrix v; ae_int_t gridtype; ae_bool fixrad; double lambdav; double radvalue; double radzvalue; ae_int_t nlayers; ae_int_t aterm; ae_int_t algorithmtype; double epsort; double epserr; ae_int_t maxits; double h; ae_int_t n; ae_matrix x; ae_matrix y; ae_vector calcbufxcx; ae_matrix calcbufx; ae_vector calcbuftags; } rbfmodel; typedef struct { ae_int_t arows; ae_int_t acols; ae_int_t annz; ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; } rbfreport; typedef struct { ae_int_t k; ae_int_t stype; ae_int_t n; ae_int_t m; ae_int_t d; ae_vector x; ae_vector y; ae_vector f; } spline2dinterpolant; typedef struct { ae_int_t k; ae_int_t stype; ae_int_t n; ae_int_t m; ae_int_t l; ae_int_t d; ae_vector x; ae_vector y; ae_vector z; ae_vector f; } spline3dinterpolant; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* IDW interpolant. *************************************************************************/ class _idwinterpolant_owner { public: _idwinterpolant_owner(); _idwinterpolant_owner(const _idwinterpolant_owner &rhs); _idwinterpolant_owner& operator=(const _idwinterpolant_owner &rhs); virtual ~_idwinterpolant_owner(); alglib_impl::idwinterpolant* c_ptr(); alglib_impl::idwinterpolant* c_ptr() const; protected: alglib_impl::idwinterpolant *p_struct; }; class idwinterpolant : public _idwinterpolant_owner { public: idwinterpolant(); idwinterpolant(const idwinterpolant &rhs); idwinterpolant& operator=(const idwinterpolant &rhs); virtual ~idwinterpolant(); }; /************************************************************************* Barycentric interpolant. *************************************************************************/ class _barycentricinterpolant_owner { public: _barycentricinterpolant_owner(); _barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs); _barycentricinterpolant_owner& operator=(const _barycentricinterpolant_owner &rhs); virtual ~_barycentricinterpolant_owner(); alglib_impl::barycentricinterpolant* c_ptr(); alglib_impl::barycentricinterpolant* c_ptr() const; protected: alglib_impl::barycentricinterpolant *p_struct; }; class barycentricinterpolant : public _barycentricinterpolant_owner { public: barycentricinterpolant(); barycentricinterpolant(const barycentricinterpolant &rhs); barycentricinterpolant& operator=(const barycentricinterpolant &rhs); virtual ~barycentricinterpolant(); }; /************************************************************************* 1-dimensional spline interpolant *************************************************************************/ class _spline1dinterpolant_owner { public: _spline1dinterpolant_owner(); _spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs); _spline1dinterpolant_owner& operator=(const _spline1dinterpolant_owner &rhs); virtual ~_spline1dinterpolant_owner(); alglib_impl::spline1dinterpolant* c_ptr(); alglib_impl::spline1dinterpolant* c_ptr() const; protected: alglib_impl::spline1dinterpolant *p_struct; }; class spline1dinterpolant : public _spline1dinterpolant_owner { public: spline1dinterpolant(); spline1dinterpolant(const spline1dinterpolant &rhs); spline1dinterpolant& operator=(const spline1dinterpolant &rhs); virtual ~spline1dinterpolant(); }; /************************************************************************* Polynomial fitting report: TaskRCond reciprocal of task's condition number RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error *************************************************************************/ class _polynomialfitreport_owner { public: _polynomialfitreport_owner(); _polynomialfitreport_owner(const _polynomialfitreport_owner &rhs); _polynomialfitreport_owner& operator=(const _polynomialfitreport_owner &rhs); virtual ~_polynomialfitreport_owner(); alglib_impl::polynomialfitreport* c_ptr(); alglib_impl::polynomialfitreport* c_ptr() const; protected: alglib_impl::polynomialfitreport *p_struct; }; class polynomialfitreport : public _polynomialfitreport_owner { public: polynomialfitreport(); polynomialfitreport(const polynomialfitreport &rhs); polynomialfitreport& operator=(const polynomialfitreport &rhs); virtual ~polynomialfitreport(); double &taskrcond; double &rmserror; double &avgerror; double &avgrelerror; double &maxerror; }; /************************************************************************* Barycentric fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error TaskRCond reciprocal of task's condition number *************************************************************************/ class _barycentricfitreport_owner { public: _barycentricfitreport_owner(); _barycentricfitreport_owner(const _barycentricfitreport_owner &rhs); _barycentricfitreport_owner& operator=(const _barycentricfitreport_owner &rhs); virtual ~_barycentricfitreport_owner(); alglib_impl::barycentricfitreport* c_ptr(); alglib_impl::barycentricfitreport* c_ptr() const; protected: alglib_impl::barycentricfitreport *p_struct; }; class barycentricfitreport : public _barycentricfitreport_owner { public: barycentricfitreport(); barycentricfitreport(const barycentricfitreport &rhs); barycentricfitreport& operator=(const barycentricfitreport &rhs); virtual ~barycentricfitreport(); double &taskrcond; ae_int_t &dbest; double &rmserror; double &avgerror; double &avgrelerror; double &maxerror; }; /************************************************************************* Spline fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error Fields below are filled by obsolete functions (Spline1DFitCubic, Spline1DFitHermite). Modern fitting functions do NOT fill these fields: TaskRCond reciprocal of task's condition number *************************************************************************/ class _spline1dfitreport_owner { public: _spline1dfitreport_owner(); _spline1dfitreport_owner(const _spline1dfitreport_owner &rhs); _spline1dfitreport_owner& operator=(const _spline1dfitreport_owner &rhs); virtual ~_spline1dfitreport_owner(); alglib_impl::spline1dfitreport* c_ptr(); alglib_impl::spline1dfitreport* c_ptr() const; protected: alglib_impl::spline1dfitreport *p_struct; }; class spline1dfitreport : public _spline1dfitreport_owner { public: spline1dfitreport(); spline1dfitreport(const spline1dfitreport &rhs); spline1dfitreport& operator=(const spline1dfitreport &rhs); virtual ~spline1dfitreport(); double &taskrcond; double &rmserror; double &avgerror; double &avgrelerror; double &maxerror; }; /************************************************************************* Least squares fitting report. This structure contains informational fields which are set by fitting functions provided by this unit. Different functions initialize different sets of fields, so you should read documentation on specific function you used in order to know which fields are initialized. TaskRCond reciprocal of task's condition number IterationsCount number of internal iterations VarIdx if user-supplied gradient contains errors which were detected by nonlinear fitter, this field is set to index of the first component of gradient which is suspected to be spoiled by bugs. RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error WRMSError weighted RMS error CovPar covariance matrix for parameters, filled by some solvers ErrPar vector of errors in parameters, filled by some solvers ErrCurve vector of fit errors - variability of the best-fit curve, filled by some solvers. Noise vector of per-point noise estimates, filled by some solvers. R2 coefficient of determination (non-weighted, non-adjusted), filled by some solvers. *************************************************************************/ class _lsfitreport_owner { public: _lsfitreport_owner(); _lsfitreport_owner(const _lsfitreport_owner &rhs); _lsfitreport_owner& operator=(const _lsfitreport_owner &rhs); virtual ~_lsfitreport_owner(); alglib_impl::lsfitreport* c_ptr(); alglib_impl::lsfitreport* c_ptr() const; protected: alglib_impl::lsfitreport *p_struct; }; class lsfitreport : public _lsfitreport_owner { public: lsfitreport(); lsfitreport(const lsfitreport &rhs); lsfitreport& operator=(const lsfitreport &rhs); virtual ~lsfitreport(); double &taskrcond; ae_int_t &iterationscount; ae_int_t &varidx; double &rmserror; double &avgerror; double &avgrelerror; double &maxerror; double &wrmserror; real_2d_array covpar; real_1d_array errpar; real_1d_array errcurve; real_1d_array noise; double &r2; }; /************************************************************************* Nonlinear fitter. You should use ALGLIB functions to work with fitter. Never try to access its fields directly! *************************************************************************/ class _lsfitstate_owner { public: _lsfitstate_owner(); _lsfitstate_owner(const _lsfitstate_owner &rhs); _lsfitstate_owner& operator=(const _lsfitstate_owner &rhs); virtual ~_lsfitstate_owner(); alglib_impl::lsfitstate* c_ptr(); alglib_impl::lsfitstate* c_ptr() const; protected: alglib_impl::lsfitstate *p_struct; }; class lsfitstate : public _lsfitstate_owner { public: lsfitstate(); lsfitstate(const lsfitstate &rhs); lsfitstate& operator=(const lsfitstate &rhs); virtual ~lsfitstate(); ae_bool &needf; ae_bool &needfg; ae_bool &needfgh; ae_bool &xupdated; real_1d_array c; double &f; real_1d_array g; real_2d_array h; real_1d_array x; }; /************************************************************************* Parametric spline inteprolant: 2-dimensional curve. You should not try to access its members directly - use PSpline2XXXXXXXX() functions instead. *************************************************************************/ class _pspline2interpolant_owner { public: _pspline2interpolant_owner(); _pspline2interpolant_owner(const _pspline2interpolant_owner &rhs); _pspline2interpolant_owner& operator=(const _pspline2interpolant_owner &rhs); virtual ~_pspline2interpolant_owner(); alglib_impl::pspline2interpolant* c_ptr(); alglib_impl::pspline2interpolant* c_ptr() const; protected: alglib_impl::pspline2interpolant *p_struct; }; class pspline2interpolant : public _pspline2interpolant_owner { public: pspline2interpolant(); pspline2interpolant(const pspline2interpolant &rhs); pspline2interpolant& operator=(const pspline2interpolant &rhs); virtual ~pspline2interpolant(); }; /************************************************************************* Parametric spline inteprolant: 3-dimensional curve. You should not try to access its members directly - use PSpline3XXXXXXXX() functions instead. *************************************************************************/ class _pspline3interpolant_owner { public: _pspline3interpolant_owner(); _pspline3interpolant_owner(const _pspline3interpolant_owner &rhs); _pspline3interpolant_owner& operator=(const _pspline3interpolant_owner &rhs); virtual ~_pspline3interpolant_owner(); alglib_impl::pspline3interpolant* c_ptr(); alglib_impl::pspline3interpolant* c_ptr() const; protected: alglib_impl::pspline3interpolant *p_struct; }; class pspline3interpolant : public _pspline3interpolant_owner { public: pspline3interpolant(); pspline3interpolant(const pspline3interpolant &rhs); pspline3interpolant& operator=(const pspline3interpolant &rhs); virtual ~pspline3interpolant(); }; /************************************************************************* RBF model. Never try to directly work with fields of this object - always use ALGLIB functions to use this object. *************************************************************************/ class _rbfmodel_owner { public: _rbfmodel_owner(); _rbfmodel_owner(const _rbfmodel_owner &rhs); _rbfmodel_owner& operator=(const _rbfmodel_owner &rhs); virtual ~_rbfmodel_owner(); alglib_impl::rbfmodel* c_ptr(); alglib_impl::rbfmodel* c_ptr() const; protected: alglib_impl::rbfmodel *p_struct; }; class rbfmodel : public _rbfmodel_owner { public: rbfmodel(); rbfmodel(const rbfmodel &rhs); rbfmodel& operator=(const rbfmodel &rhs); virtual ~rbfmodel(); }; /************************************************************************* RBF solution report: * TerminationType - termination type, positive values - success, non-positive - failure. *************************************************************************/ class _rbfreport_owner { public: _rbfreport_owner(); _rbfreport_owner(const _rbfreport_owner &rhs); _rbfreport_owner& operator=(const _rbfreport_owner &rhs); virtual ~_rbfreport_owner(); alglib_impl::rbfreport* c_ptr(); alglib_impl::rbfreport* c_ptr() const; protected: alglib_impl::rbfreport *p_struct; }; class rbfreport : public _rbfreport_owner { public: rbfreport(); rbfreport(const rbfreport &rhs); rbfreport& operator=(const rbfreport &rhs); virtual ~rbfreport(); ae_int_t &arows; ae_int_t &acols; ae_int_t &annz; ae_int_t &iterationscount; ae_int_t &nmv; ae_int_t &terminationtype; }; /************************************************************************* 2-dimensional spline inteprolant *************************************************************************/ class _spline2dinterpolant_owner { public: _spline2dinterpolant_owner(); _spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs); _spline2dinterpolant_owner& operator=(const _spline2dinterpolant_owner &rhs); virtual ~_spline2dinterpolant_owner(); alglib_impl::spline2dinterpolant* c_ptr(); alglib_impl::spline2dinterpolant* c_ptr() const; protected: alglib_impl::spline2dinterpolant *p_struct; }; class spline2dinterpolant : public _spline2dinterpolant_owner { public: spline2dinterpolant(); spline2dinterpolant(const spline2dinterpolant &rhs); spline2dinterpolant& operator=(const spline2dinterpolant &rhs); virtual ~spline2dinterpolant(); }; /************************************************************************* 3-dimensional spline inteprolant *************************************************************************/ class _spline3dinterpolant_owner { public: _spline3dinterpolant_owner(); _spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs); _spline3dinterpolant_owner& operator=(const _spline3dinterpolant_owner &rhs); virtual ~_spline3dinterpolant_owner(); alglib_impl::spline3dinterpolant* c_ptr(); alglib_impl::spline3dinterpolant* c_ptr() const; protected: alglib_impl::spline3dinterpolant *p_struct; }; class spline3dinterpolant : public _spline3dinterpolant_owner { public: spline3dinterpolant(); spline3dinterpolant(const spline3dinterpolant &rhs); spline3dinterpolant& operator=(const spline3dinterpolant &rhs); virtual ~spline3dinterpolant(); }; /************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ double idwcalc(const idwinterpolant &z, const real_1d_array &x); /************************************************************************* IDW interpolant using modified Shepard method for uniform point distributions. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function type, either: * 0 constant model. Just for demonstration only, worst model ever. * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is significantly faster than linear/quadratic and better than constant model. But it is less robust (especially in the presence of noise). NQ - number of points used to calculate nodal functions (ignored for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, worst - with constant models * when N is large, NQ and NW must be significantly smaller than N both to obtain optimal performance and to obtain optimal accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be automatically decreased. * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small scales. If it isn't - for example, points are concentrated along "lines", but "lines" distribution is uniform at the larger scale - then you should use IDWBuildModifiedShepardR() -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepard(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z); /************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildmodifiedshepardr(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const double r, idwinterpolant &z); /************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/ void idwbuildnoisy(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z); /************************************************************************* Rational interpolation using barycentric formula F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) Input parameters: B - barycentric interpolant built with one of model building subroutines. T - interpolation point Result: barycentric interpolant F(t) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ double barycentriccalc(const barycentricinterpolant &b, const double t); /************************************************************************* Differentiation of barycentric interpolant: first derivative. Algorithm used in this subroutine is very robust and should not fail until provided with values too close to MaxRealNumber (usually MaxRealNumber/N or greater will overflow). INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative NOTE -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df); /************************************************************************* Differentiation of barycentric interpolant: first/second derivatives. INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative D2F - second derivative NOTE: this algorithm may fail due to overflow/underflor if used on data whose values are close to MaxRealNumber or MinRealNumber. Use more robust BarycentricDiff1() subroutine in such cases. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f); /************************************************************************* This subroutine performs linear transformation of the argument. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: x = CA*t + CB OUTPUT PARAMETERS: B - transformed interpolant with X replaced by T -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb); /************************************************************************* This subroutine performs linear transformation of the barycentric interpolant. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB OUTPUT PARAMETERS: B - transformed interpolant -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb); /************************************************************************* Extracts X/Y/W arrays from rational interpolant INPUT PARAMETERS: B - barycentric interpolant OUTPUT PARAMETERS: N - nodes count, N>0 X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w); /************************************************************************* Rational interpolant from X/Y/W arrays F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) INPUT PARAMETERS: X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] N - nodes count, N>0 OUTPUT PARAMETERS: B - barycentric interpolant built from (X, Y, W) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b); /************************************************************************* Rational interpolant without poles The subroutine constructs the rational interpolating function without real poles (see 'Barycentric rational interpolation with no poles and high rates of approximation', Michael S. Floater. and Kai Hormann, for more information on this subject). Input parameters: X - interpolation nodes, array[0..N-1]. Y - function values, array[0..N-1]. N - number of nodes, N>0. D - order of the interpolation scheme, 0 <= D <= N-1. D<0 will cause an error. D>=N it will be replaced with D=N-1. if you don't know what D to choose, use small value about 3-5. Output parameters: B - barycentric interpolant. Note: this algorithm always succeeds and calculates the weights with close to machine precision. -- ALGLIB PROJECT -- Copyright 17.06.2007 by Bochkanov Sergey *************************************************************************/ void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b); /************************************************************************* Conversion from barycentric representation to Chebyshev basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form A,B - base interval for Chebyshev polynomials (see below) A<>B OUTPUT PARAMETERS T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, where Ti - I-th Chebyshev polynomial. NOTES: barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t); /************************************************************************* Conversion from Chebyshev basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, where Ti - I-th Chebyshev polynomial. N - number of coefficients: * if given, only leading N elements of T are used * if not given, automatically determined from size of T A,B - base interval for Chebyshev polynomials (see above) A0. OUTPUT PARAMETERS A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if P was obtained as result of interpolation on [-1,+1], you can set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such representation can be obtained by using 1000.0 as offset C and 1.0 as scale S. 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return coefficients in any case, but for N>8 they will become unreliable. However, N's less than 5 are pretty safe. 3. barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a); void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a); /************************************************************************* Conversion from power basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) * if given, only leading N elements of A are used * if not given, automatically determined from size of A C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS P - polynomial in barycentric form NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if you interpolate on [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option (you have to specify 1000.0 as offset C and 1.0 as scale S). 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return barycentric model in any case, but for N>8 accuracy well degrade. However, N's less than 5 are pretty safe. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/ void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p); void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p); /************************************************************************* Lagrange intepolant: generation of the model on the general grid. This function has O(N^2) complexity. INPUT PARAMETERS: X - abscissas, array[0..N-1] Y - function values, array[0..N-1] N - number of points, N>=1 OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p); /************************************************************************* Lagrange intepolant: generation of the model on equidistant grid. This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1] N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); /************************************************************************* Lagrange intepolant on Chebyshev grid (first kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); /************************************************************************* Lagrange intepolant on Chebyshev grid (second kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); /************************************************************************* Fast equidistant polynomial interpolation function with O(N) complexity INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on equidistant grid, N>=1 for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolynomialBuildEqDist()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t); /************************************************************************* Fast polynomial interpolation function on Chebyshev points (first kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (first kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb1()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t); /************************************************************************* Fast polynomial interpolation function on Chebyshev points (second kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (second kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb2()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t); /************************************************************************* This subroutine builds linear spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); /************************************************************************* This subroutine builds cubic spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c); void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns table of function derivatives d[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D - derivative values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d); void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d); /************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns tables of first and second function derivatives d1[] and d2[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D1 - S' values at X[] D2 - S'' values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2); void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2); /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2); void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2); /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] and derivatives d2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2); void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2); /************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[], first and second derivatives d2[] and dd2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] DD2 - second derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/ void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2); void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2); /************************************************************************* This subroutine builds Catmull-Rom spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundType - boundary condition type: * -1 for periodic boundary condition * 0 for parabolically terminated spline (default) Tension - tension parameter: * tension=0 corresponds to classic Catmull-Rom spline (default) * 0=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c); void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c); /************************************************************************* This subroutine builds Akima spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); /************************************************************************* This subroutine calculates the value of the spline at the given point X. INPUT PARAMETERS: C - spline interpolant X - point Result: S(x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dcalc(const spline1dinterpolant &c, const double x); /************************************************************************* This subroutine differentiates the spline. INPUT PARAMETERS: C - spline interpolant. X - point Result: S - S(x) DS - S'(x) D2S - S''(x) -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s); /************************************************************************* This subroutine unpacks the spline into the coefficients table. INPUT PARAMETERS: C - spline interpolant. X - point OUTPUT PARAMETERS: Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. For I = 0...N-2: Tbl[I,0] = X[i] Tbl[I,1] = X[i+1] Tbl[I,2] = C0 Tbl[I,3] = C1 Tbl[I,4] = C2 Tbl[I,5] = C3 On [x[i], x[i+1]] spline is equals to: S(x) = C0 + C1*t + C2*t^2 + C3*t^3 t = x-x[i] NOTE: You can rebuild spline with Spline1DBuildHermite() function, which accepts as inputs function values and derivatives at nodes, which are easy to calculate when you have coefficients. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl); /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: x = A*t + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b); /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x) = A*S(x) + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b); /************************************************************************* This subroutine integrates the spline. INPUT PARAMETERS: C - spline interpolant. X - right bound of the integration interval [a, x], here 'a' denotes min(x[]) Result: integral(S(t)dt,a,x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/ double spline1dintegrate(const spline1dinterpolant &c, const double x); /************************************************************************* This function builds monotone cubic Hermite interpolant. This interpolant is monotonic in [x(0),x(n-1)] and is constant outside of this interval. In case y[] form non-monotonic sequence, interpolant is piecewise monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will monotonically grow at [0..2] and monotonically decrease at [2..4]. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Subroutine automatically sorts points, so caller may pass unsorted array. Y - function values, array[0..N-1] N - the number of points(N>=2). OUTPUT PARAMETERS: C - spline interpolant. -- ALGLIB PROJECT -- Copyright 21.06.2012 by Bochkanov Sergey *************************************************************************/ void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); /************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after generating specified number of linear sections. IMPORTANT: * it does NOT perform least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y M - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N0 * if given, only leading N elements of X/Y are used * if not given, automatically determined from sizes of X/Y M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void smp_polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void smp_polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); /************************************************************************* Weighted fitting by polynomials in barycentric form, with constraints on function values or first derivatives. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFit() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. * if given, only leading N elements of X/Y/W are used * if not given, automatically determined from sizes of X/Y/W XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * even simple constraints can be inconsistent, see Wikipedia article on this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the one special cases, however, we can guarantee consistency. This case is: M>1 and constraints on the function values (NOT DERIVATIVES) Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/ void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void smp_polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); void smp_polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); /************************************************************************* This function calculates value of four-parameter logistic (4PL) model at specified point X. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D- parameters of 4PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc4(const double x, const double a, const double b, const double c, const double d); /************************************************************************* This function calculates value of five-parameter logistic (5PL) model at specified point X. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D, G- parameters of 5PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained * G>0, non-positive value results in exception RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g); /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, lsfitreport &rep); /************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user, with optional constraints on parameters A and D. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - with optional equality constraints * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit4ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, lsfitreport &rep); /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - unconstrained * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep); /************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user, subject to optional equality constraints on parameters A and D. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - with optional equality constraints * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit5ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep); /************************************************************************* This is "expert" 4PL/5PL fitting function, which can be used if you need better control over fitting process than provided by LogisticFit4() or LogisticFit5(). This function fits model of the form F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) or F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) Here: * A, D - unconstrained * B>=0 for 4PL, unconstrained for 5PL * C>0 * G>0 (if present) INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. Is4PL - whether 4PL or 5PL models are fitted LambdaV - regularization coefficient, LambdaV>=0. Set it to zero unless you know what you are doing. EpsX - stopping condition (step size), EpsX>=0. Zero value means that small step is automatically chosen. See notes below for more information. RsCnt - number of repeated restarts from random points. 4PL/5PL models are prone to problem of bad local extrema. Utilizing multiple random restarts allows us to improve algorithm convergence. RsCnt>=0. Zero value means that function automatically choose small amount of restarts (recommended). OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model G - parameter of 5PL model; for Is4PL=True, G=1 is returned. Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. For 5PL model things are different. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/ void logisticfit45x(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, const bool is4pl, const double lambdav, const double epsx, const ae_int_t rscnt, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep); /************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); void smp_barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); /************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); void smp_barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); /************************************************************************* Fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points (optional): * N>0 * if given, only first N elements of X/Y are processed * if not given, automatically determined from X/Y sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Weighted fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted problem. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 19.10.2010 by Bochkanov Sergey *************************************************************************/ void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Weighted fitting by cubic spline, with constraints on function values or derivatives. Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with continuous second derivatives and non-fixed first derivatives at interval ends. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, less smooth) Spline1DFitCubic() - "lightweight" fitting by cubic splines, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints S - spline interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function values AND/OR its derivatives at the interval boundaries. * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Weighted fitting by Hermite spline, with constraints on function values or first derivatives. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are Hermite splines. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, more smooth) Spline1DFitHermite() - "lightweight" Hermite fitting, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K=4, M IS EVEN! OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -2 means odd M was passed (which is not supported) -1 means another errors in parameters passed (N<=0, for example) S - spline interpolant. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. IMPORTANT: this subroitine supports only even M's ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the several special cases, however, we can guarantee consistency. * one of this cases is M>=4 and constraints on the function value (AND/OR its derivative) at the interval boundaries. * another special case is M>=4 and ONE constraint on the function value (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Least squares fitting by cubic spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information about subroutine parameters (we don't duplicate it here because of length) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Least squares fitting by Hermite spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for more information about subroutine parameters (we don't duplicate it here because of length). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/ void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); void smp_spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); /************************************************************************* Weighted linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -1 incorrect N/M were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); /************************************************************************* Weighted constained linear least squares fitting. This is variation of LSFitLinearW(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); /************************************************************************* Linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); /************************************************************************* Constained linear least squares fitting. This is variation of LSFitLinear(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/ void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); void smp_lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); /************************************************************************* Weighted nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state); void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state); /************************************************************************* Nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state); void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state); /************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state); void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const bool cheapfg, lsfitstate &state); /************************************************************************* Nonlinear least squares fitting using gradient only, without individual weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state); void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const bool cheapfg, lsfitstate &state); /************************************************************************* Weighted nonlinear least squares fitting using gradient/Hessian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state); void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state); /************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state); void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state); /************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by LSFitSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitsetcond(const lsfitstate &state, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetstpmax(const lsfitstate &state, const double stpmax); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/ void lsfitsetxrep(const lsfitstate &state, const bool needxrep); /************************************************************************* This function sets scaling coefficients for underlying optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetscale(const lsfitstate &state, const real_1d_array &s); /************************************************************************* This function sets boundary constraints for underlying optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[K]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[K]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: unlike other constrained optimization algorithms, this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool lsfititeration(const lsfitstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear fitter These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x hess - callback which calculates function (or merit function) value func, gradient grad and Hessian hess at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL); void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL); void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. On success following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before fitting begins * LSFitFit() is called * prior to actual fitting, for each point in data set X_i and each component of parameters being fited C_j algorithm performs following steps: * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], where C_j is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on C[] * F(X_i|C) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N*K (points count * parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with LSFitSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. NOTE 4: this function works only for optimizers created with LSFitCreateWFG() or LSFitCreateFG() constructors. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void lsfitsetgradientcheck(const lsfitstate &state, const double teststep); /************************************************************************* This function builds non-periodic 2-dimensional parametric spline which starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. Order of points is important! N - points count, N>=5 for Akima splines, N>=2 for other types of splines. ST - spline type: * 0 Akima spline * 1 parabolically terminated Catmull-Rom spline (Tension=0) * 2 parabolically terminated cubic spline PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p); /************************************************************************* This function builds non-periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p); /************************************************************************* This function builds periodic 2-dimensional parametric spline which starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then back to (X[0],Y[0]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. XY[N-1,0:1] must be different from XY[0,0:1]. Order of points is important! N - points count, N>=3 for other types of splines. ST - spline type: * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions * 2 cubic spline with cyclic boundary conditions PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). * last point of sequence is NOT equal to the first point. You shouldn't make curve "explicitly periodic" by making them equal. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p); /************************************************************************* This function builds periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) and then back to (X[0],Y[0],Z[0]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p); /************************************************************************* This function returns vector of parameter values correspoding to points. I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we have (X[0],Y[0]) = PSpline2Calc(P,U[0]), (X[1],Y[1]) = PSpline2Calc(P,U[1]), (X[2],Y[2]) = PSpline2Calc(P,U[2]), ... INPUT PARAMETERS: P - parametric spline interpolant OUTPUT PARAMETERS: N - array size T - array[0..N-1] NOTES: * for non-periodic splines U[0]=0, U[0]1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y); /************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position Z - Z-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z); /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) NOTE: X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y); /************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) Z - Z-component of tangent vector (normalized) NOTE: X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z); /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy); /************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative Z - Z-value DZ - Z-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz); /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y); /************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative Z - Z-value DZ - derivative D2Z - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/ void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z); /************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * BA will result in positive length returned * B1) function in a NX-dimensional space (NX=2 or NX=3). Newly created model is empty. It can be used for interpolation right after creation, but it just returns zeros. You have to add points to the model, tune interpolation settings, and then call model construction function RBFBuildModel() which will update model according to your specification. USAGE: 1. User creates model with RBFCreate() 2. User adds dataset with RBFSetPoints() (points do NOT have to be on a regular grid) 3. (OPTIONAL) User chooses polynomial term by calling: * RBFLinTerm() to set linear term * RBFConstTerm() to set constant term * RBFZeroTerm() to set zero term By default, linear term is used. 4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) or ML (RBFSetAlgoMultiLayer). 5. User calls RBFBuildModel() function which rebuilds model according to the specification 6. User may call RBFCalc() to calculate model value at the specified point, RBFGridCalc() to calculate model values at the points of the regular grid. User may extract model coefficients with RBFUnpack() call. INPUT PARAMETERS: NX - dimension of the space, NX=2 or NX=3 NY - function dimension, NY>=1 OUTPUT PARAMETERS: S - RBF model (initially equals to zero) NOTE 1: memory requirements. RBF models require amount of memory which is proportional to the number of data points. Memory is allocated during model construction, but most of this memory is freed after model coefficients are calculated. Some approximate estimates for N centers with default settings are given below: * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is needed during model construction stage. * about 15*N*sizeof(double) bytes is needed after model is built. For example, for N=100000 we may need 0.6 GB of memory to build model, but just about 0.012 GB to store it. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s); /************************************************************************* This function adds dataset. This function overrides results of the previous calls, i.e. multiple calls of this function will result in only the last set being added. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call. XY - points, array[N,NX+NY]. One row corresponds to one point in the dataset. First NX elements are coordinates, next NY elements are function values. Array may be larger than specific, in this case only leading [N,NX+NY] elements will be used. N - number of points in the dataset After you've added dataset and (optionally) tuned algorithm settings you should call RBFBuildModel() in order to build a model for you. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n); void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy); /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-QNN and it is good for point sets with following properties: a) all points are distinct b) all points are well separated. c) points distribution is approximately uniform. There is no "contour lines", clusters of points, or other small-scale structures. Algorithm description: 1) interpolation centers are allocated to data points 2) interpolation radii are calculated as distances to the nearest centers times Q coefficient (where Q is a value from [0.75,1.50]). 3) after performing (2) radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across all dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. When (a) is violated, we will be unable to build RBF model. When (b) or (c) are violated, model will be built, but interpolation quality will be low. See http://www.alglib.net/interpolation/ for more information on this subject. This algorithm is used by default. Additional Q parameter controls smoothness properties of the RBF basis: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q around 1.0 gives good balance between smoothness and condition number * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q>2.0 will effectively make optimizer useless because it won't converge within reasonable amount of iterations. It is possible to set such large Q, but it is advised not to do so. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - Q parameter, Q>0, recommended value - 1.0 Z - Z parameter, Z>0, recommended value - 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z); void rbfsetalgoqnn(const rbfmodel &s); /************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. model with subsequently decreasing radii, which allows us to combine smoothness (due to large radii of the first layers) with exactness (due to small radii of the last layers) and fast convergence. Internally RBF-ML uses many different means of acceleration, from sparse matrices to KD-trees, which results in algorithm whose working time is roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a number of points, Density is an average density if points per unit of the interpolation space, RBase is an initial radius, NLayers is a number of layers. RBF-ML is good for following kinds of interpolation problems: 1. "exact" problems (perfect fit) with well separated points 2. least squares problems with arbitrary distribution of points (algorithm gives perfect fit where it is possible, and resorts to least squares fit in the hard areas). 3. noisy problems where we want to apply some controlled amount of smoothing. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call RBase - RBase parameter, RBase>0 NLayers - NLayers parameter, NLayers>0, recommended value to start with - about 5. LambdaV - regularization value, can be useful when solving problem in the least squares sense. Optimal lambda is problem- dependent and require trial and error. In our experience, good lambda can be as large as 0.1, and you can use 0.001 as initial guess. Default value - 0.01, which is used when LambdaV is not given. You can specify zero value, but it is not recommended to do so. TUNING ALGORITHM In order to use this algorithm you have to choose three parameters: * initial radius RBase * number of layers in the model NLayers * regularization coefficient LambdaV Initial radius is easy to choose - you can pick any number several times larger than the average distance between points. Algorithm won't break down if you choose radius which is too large (model construction time will increase, but model will be built correctly). Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used by the last layer) will be smaller than the typical distance between points. In case model error is too large, you can increase number of layers. Having more layers will make model construction and evaluation proportionally slower, but it will allow you to have model which precisely fits your data. From the other side, if you want to suppress noise, you can DECREASE number of layers to make your model less flexible. Regularization coefficient LambdaV controls smoothness of the individual models built for each layer. We recommend you to use default value in case you don't want to tune this parameter, because having non-zero LambdaV accelerates and stabilizes internal iterative algorithm. In case you want to suppress noise you can use LambdaV as additional parameter (larger value = more smoothness) to tune. TYPICAL ERRORS 1. Using initial radius which is too large. Memory requirements of the RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is an average density of points per unit of the interpolation space). In the extreme case of the very large RBase we will need O(N^2) units of memory - and many layers in order to decrease radius to some reasonably small value. 2. Using too small number of layers - RBF models with large radius are not flexible enough to reproduce small variations in the target function. You need many layers with different radii, from large to small, in order to have good model. 3. Using initial radius which is too small. You will get model with "holes" in the areas which are too far away from interpolation centers. However, algorithm will work correctly (and quickly) in this case. 4. Using too many layers - you will get too large and too slow model. This model will perfectly reproduce your function, but maybe you will be able to achieve similar results with less layers (and less memory). -- ALGLIB -- Copyright 02.03.2012 by Bochkanov Sergey *************************************************************************/ void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav); void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers); /************************************************************************* This function sets linear term (model is a sum of radial basis functions plus linear polynomial). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetlinterm(const rbfmodel &s); /************************************************************************* This function sets constant term (model is a sum of radial basis functions plus constant). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetconstterm(const rbfmodel &s); /************************************************************************* This function sets zero term (model is a sum of radial basis functions without polynomial term). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfsetzeroterm(const rbfmodel &s); /************************************************************************* This function builds RBF model and returns report (contains some information which can be used for evaluation of the algorithm properties). Call to this function modifies RBF model by calculating its centers/radii/ weights and saving them into RBFModel structure. Initially RBFModel contain zero coefficients, but after call to this function we will have coefficients which were calculated in order to fit our dataset. After you called this function you can call RBFCalc(), RBFGridCalc() and other model calculation functions. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Rep - report: * Rep.TerminationType: * -5 - non-distinct basis function centers were detected, interpolation aborted * -4 - nonconvergence of the internal SVD solver * 1 - successful termination Fields are used for debugging purposes: * Rep.IterationsCount - iterations count of the LSQR solver * Rep.NMV - number of matrix-vector products * Rep.ARows - rows count for the system matrix * Rep.ACols - columns count for the system matrix * Rep.ANNZ - number of significantly non-zero elements (elements above some algorithm-determined threshold) NOTE: failure to build model will leave current state of the structure unchanged. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfbuildmodel(const rbfmodel &s, rbfreport &rep); /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=2 (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). If you want to calculate function values many times, consider using RBFGridCalc2(), which is far more efficient than many subsequent calls to RBFCalc2(). This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc2(const rbfmodel &s, const double x0, const double x1); /************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=3 (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). This function returns 0.0 when: * model is not initialized * NX<>3 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number X2 - third coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2); /************************************************************************* This function calculates values of the RBF model at the given point. This is general function which can be used for arbitrary NX (dimension of the space of arguments) and NY (dimension of the function itself). However when you have NY=1 you may find more convenient to use RBFCalc2() or RBFCalc3(). This function returns 0.0 when model is not initialized. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. OUTPUT PARAMETERS: Y - function value, array[NY]. Y is out-parameter and reallocated after call to this function. In case you want to reuse previously allocated Y, you may use RBFCalcBuf(), which reallocates Y only when it is too small. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y); /************************************************************************* This function calculates values of the RBF model at the given point. Same as RBFCalc(), but does not reallocate Y when in is large enough to store function values. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. Y - possibly preallocated array OUTPUT PARAMETERS: Y - function value, array[NY]. Y is not reallocated when it is larger than NY. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y); /************************************************************************* This function calculates values of the RBF model at the regular grid. Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - array of grid nodes, first coordinates, array[N0] N0 - grid size (number of nodes) in the first dimension X1 - array of grid nodes, second coordinates, array[N1] N1 - grid size (number of nodes) in the second dimension OUTPUT PARAMETERS: Y - function values, array[N0,N1]. Y is out-variable and is reallocated by this function. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfgridcalc2(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_2d_array &y); /************************************************************************* This function "unpacks" RBF model by extracting its coefficients. INPUT PARAMETERS: S - RBF model OUTPUT PARAMETERS: NX - dimensionality of argument NY - dimensionality of the target function XWR - model information, array[NC,NX+NY+1]. One row of the array corresponds to one basis function: * first NX columns - coordinates of the center * next NY columns - weights, one per dimension of the function being modelled * last column - radius, same for all dimensions of the function being modelled NC - number of the centers V - polynomial term , array[NY,NX+1]. One row per one dimension of the function being modelled. First NX elements are linear coefficients, V[NX] is equal to the constant part. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ void rbfunpack(const rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v); /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X. Input parameters: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y- point Result: S(x,y) -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ double spline2dcalc(const spline2dinterpolant &c, const double x, const double y); /************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X and its derivatives. Input parameters: C - spline interpolant. X, Y- point Output parameters: F - S(x,y) FX - dS(x,y)/dX FY - dS(x,y)/dY FXY - d2S(x,y)/dXdY -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy); /************************************************************************* This subroutine performs linear transformation of the spline argument. Input parameters: C - spline interpolant AX, BX - transformation coefficients: x = A*t + B AY, BY - transformation coefficients: y = A*u + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by); /************************************************************************* This subroutine performs linear transformation of the spline. Input parameters: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B Output parameters: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b); /************************************************************************* This subroutine makes the copy of the spline model. Input parameters: C - spline interpolant Output parameters: CC - spline copy -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc); /************************************************************************* Bicubic spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 15 May, 2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth); /************************************************************************* Bilinear spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 09.07.2007 Copyright by Bochkanov Sergey *************************************************************************/ void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth); /************************************************************************* This subroutine builds bilinear vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c); /************************************************************************* This subroutine builds bicubic vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c); /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f); /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f); /************************************************************************* This subroutine unpacks two-dimensional spline into the coefficients table Input parameters: C - spline interpolant. Result: M, N- grid size (x-axis and y-axis) D - number of components Tbl - coefficients table, unpacked format, D - components: [0..(N-1)*(M-1)*D-1, 0..19]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index): K := T + I*D + J*D*(N-1) K-th row stores decomposition for T-th component of the vector-valued function Tbl[K,0] = X[i] Tbl[K,1] = X[i+1] Tbl[K,2] = Y[j] Tbl[K,3] = Y[j+1] Tbl[K,4] = C00 Tbl[K,5] = C01 Tbl[K,6] = C02 Tbl[K,7] = C03 Tbl[K,8] = C10 Tbl[K,9] = C11 ... Tbl[K,19] = C33 On each grid square spline is equals to: S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) t = x-x[j] u = y-y[i] -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/ void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl); /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBilinearV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c); /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBicubicV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/ void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c); /************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DUnpackV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/ void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl); /************************************************************************* This subroutine calculates the value of the trilinear or tricubic spline at the given point (X,Y,Z). INPUT PARAMETERS: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y, Z - point Result: S(x,y,z) -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z); /************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant AX, BX - transformation coefficients: x = A*u + B AY, BY - transformation coefficients: y = A*v + B AZ, BZ - transformation coefficients: z = A*w + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz); /************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b); /************************************************************************* Trilinear spline resampling INPUT PARAMETERS: A - array[0..OldXCount*OldYCount*OldZCount-1], function values at the old grid, : A[0] x=0,y=0,z=0 A[1] x=1,y=0,z=0 A[..] ... A[..] x=oldxcount-1,y=0,z=0 A[..] x=0,y=1,z=0 A[..] ... ... OldZCount - old Z-count, OldZCount>1 OldYCount - old Y-count, OldYCount>1 OldXCount - old X-count, OldXCount>1 NewZCount - new Z-count, NewZCount>1 NewYCount - new Y-count, NewYCount>1 NewXCount - new X-count, NewXCount>1 OUTPUT PARAMETERS: B - array[0..NewXCount*NewYCount*NewZCount-1], function values at the new grid: B[0] x=0,y=0,z=0 B[1] x=1,y=0,z=0 B[..] ... B[..] x=newxcount-1,y=0,z=0 B[..] x=0,y=1,z=0 B[..] ... ... -- ALGLIB routine -- 26.04.2012 Copyright by Bochkanov Sergey *************************************************************************/ void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b); /************************************************************************* This subroutine builds trilinear vector-valued spline. INPUT PARAMETERS: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] Z - spline applicates, array[0..L-1] F - function values, array[0..M*N*L*D-1]: * first D elements store D values at (X[0],Y[0],Z[0]) * next D elements store D values at (X[1],Y[0],Z[0]) * next D elements store D values at (X[2],Y[0],Z[0]) * ... * next D elements store D values at (X[0],Y[1],Z[0]) * next D elements store D values at (X[1],Y[1],Z[0]) * next D elements store D values at (X[2],Y[1],Z[0]) * ... * next D elements store D values at (X[0],Y[0],Z[1]) * next D elements store D values at (X[1],Y[0],Z[1]) * next D elements store D values at (X[2],Y[0],Z[1]) * ... * general form - D function values at (X[i],Y[j]) are stored at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. M,N, L - grid size, M>=2, N>=2, L>=2 D - vector dimension, D>=1 OUTPUT PARAMETERS: C - spline interpolant -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c); /************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f); /************************************************************************* This subroutine calculates trilinear or tricubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f); /************************************************************************* This subroutine unpacks tri-dimensional spline into the coefficients table INPUT PARAMETERS: C - spline interpolant. Result: N - grid size (X) M - grid size (Y) L - grid size (Z) D - number of components SType- spline type. Currently, only one spline type is supported: trilinear spline, as indicated by SType=1. Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index), K=0..L-2 (z index): Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), Q-th row stores decomposition for T-th component of the vector-valued function Tbl[Q,0] = X[i] Tbl[Q,1] = X[i+1] Tbl[Q,2] = Y[j] Tbl[Q,3] = Y[j+1] Tbl[Q,4] = Z[k] Tbl[Q,5] = Z[k+1] Tbl[Q,6] = C000 Tbl[Q,7] = C100 Tbl[Q,8] = C010 Tbl[Q,9] = C110 Tbl[Q,10]= C001 Tbl[Q,11]= C101 Tbl[Q,12]= C011 Tbl[Q,13]= C111 On each grid square spline is equals to: S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) t = x-x[j] u = y-y[i] v = z-z[k] NOTE: format of Tbl is given for SType=1. Future versions of ALGLIB can use different formats for different values of SType. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/ void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { double idwcalc(idwinterpolant* z, /* Real */ ae_vector* x, ae_state *_state); void idwbuildmodifiedshepard(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state); void idwbuildmodifiedshepardr(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, double r, idwinterpolant* z, ae_state *_state); void idwbuildnoisy(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant* z, ae_state *_state); void _idwinterpolant_init(void* _p, ae_state *_state); void _idwinterpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _idwinterpolant_clear(void* _p); void _idwinterpolant_destroy(void* _p); double barycentriccalc(barycentricinterpolant* b, double t, ae_state *_state); void barycentricdiff1(barycentricinterpolant* b, double t, double* f, double* df, ae_state *_state); void barycentricdiff2(barycentricinterpolant* b, double t, double* f, double* df, double* d2f, ae_state *_state); void barycentriclintransx(barycentricinterpolant* b, double ca, double cb, ae_state *_state); void barycentriclintransy(barycentricinterpolant* b, double ca, double cb, ae_state *_state); void barycentricunpack(barycentricinterpolant* b, ae_int_t* n, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_state *_state); void barycentricbuildxyw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, barycentricinterpolant* b, ae_state *_state); void barycentricbuildfloaterhormann(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t d, barycentricinterpolant* b, ae_state *_state); void barycentriccopy(barycentricinterpolant* b, barycentricinterpolant* b2, ae_state *_state); void _barycentricinterpolant_init(void* _p, ae_state *_state); void _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _barycentricinterpolant_clear(void* _p); void _barycentricinterpolant_destroy(void* _p); void polynomialbar2cheb(barycentricinterpolant* p, double a, double b, /* Real */ ae_vector* t, ae_state *_state); void polynomialcheb2bar(/* Real */ ae_vector* t, ae_int_t n, double a, double b, barycentricinterpolant* p, ae_state *_state); void polynomialbar2pow(barycentricinterpolant* p, double c, double s, /* Real */ ae_vector* a, ae_state *_state); void polynomialpow2bar(/* Real */ ae_vector* a, ae_int_t n, double c, double s, barycentricinterpolant* p, ae_state *_state); void polynomialbuild(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state); void polynomialbuildeqdist(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state); void polynomialbuildcheb1(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state); void polynomialbuildcheb2(double a, double b, /* Real */ ae_vector* y, ae_int_t n, barycentricinterpolant* p, ae_state *_state); double polynomialcalceqdist(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state); double polynomialcalccheb1(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state); double polynomialcalccheb2(double a, double b, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state); void spline1dbuildlinear(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state); void spline1dbuildcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, spline1dinterpolant* c, ae_state *_state); void spline1dgriddiffcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d, ae_state *_state); void spline1dgriddiff2cubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* d1, /* Real */ ae_vector* d2, ae_state *_state); void spline1dconvcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, ae_state *_state); void spline1dconvdiffcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, /* Real */ ae_vector* d2, ae_state *_state); void spline1dconvdiff2cubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y2, /* Real */ ae_vector* d2, /* Real */ ae_vector* dd2, ae_state *_state); void spline1dbuildcatmullrom(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t boundtype, double tension, spline1dinterpolant* c, ae_state *_state); void spline1dbuildhermite(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* d, ae_int_t n, spline1dinterpolant* c, ae_state *_state); void spline1dbuildakima(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state); double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state); void spline1ddiff(spline1dinterpolant* c, double x, double* s, double* ds, double* d2s, ae_state *_state); void spline1dcopy(spline1dinterpolant* c, spline1dinterpolant* cc, ae_state *_state); void spline1dunpack(spline1dinterpolant* c, ae_int_t* n, /* Real */ ae_matrix* tbl, ae_state *_state); void spline1dlintransx(spline1dinterpolant* c, double a, double b, ae_state *_state); void spline1dlintransy(spline1dinterpolant* c, double a, double b, ae_state *_state); double spline1dintegrate(spline1dinterpolant* c, double x, ae_state *_state); void spline1dconvdiffinternal(/* Real */ ae_vector* xold, /* Real */ ae_vector* yold, /* Real */ ae_vector* dold, ae_int_t n, /* Real */ ae_vector* x2, ae_int_t n2, /* Real */ ae_vector* y, ae_bool needy, /* Real */ ae_vector* d1, ae_bool needd1, /* Real */ ae_vector* d2, ae_bool needd2, ae_state *_state); void spline1drootsandextrema(spline1dinterpolant* c, /* Real */ ae_vector* r, ae_int_t* nr, ae_bool* dr, /* Real */ ae_vector* e, /* Integer */ ae_vector* et, ae_int_t* ne, ae_bool* de, ae_state *_state); void heapsortdpoints(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* d, ae_int_t n, ae_state *_state); void solvepolinom2(double p0, double m0, double p1, double m1, double* x0, double* x1, ae_int_t* nr, ae_state *_state); void solvecubicpolinom(double pa, double ma, double pb, double mb, double a, double b, double* x0, double* x1, double* x2, double* ex0, double* ex1, ae_int_t* nr, ae_int_t* ne, /* Real */ ae_vector* tempdata, ae_state *_state); ae_int_t bisectmethod(double pa, double ma, double pb, double mb, double a, double b, double* x, ae_state *_state); void spline1dbuildmonotone(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, spline1dinterpolant* c, ae_state *_state); void _spline1dinterpolant_init(void* _p, ae_state *_state); void _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _spline1dinterpolant_clear(void* _p); void _spline1dinterpolant_destroy(void* _p); void lstfitpiecewiselinearrdpfixed(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, /* Real */ ae_vector* x2, /* Real */ ae_vector* y2, ae_int_t* nsections, ae_state *_state); void lstfitpiecewiselinearrdp(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double eps, /* Real */ ae_vector* x2, /* Real */ ae_vector* y2, ae_int_t* nsections, ae_state *_state); void polynomialfit(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state); void _pexec_polynomialfit(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state); void polynomialfitwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state); void _pexec_polynomialfitwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* p, polynomialfitreport* rep, ae_state *_state); double logisticcalc4(double x, double a, double b, double c, double d, ae_state *_state); double logisticcalc5(double x, double a, double b, double c, double d, double g, ae_state *_state); void logisticfit4(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double* a, double* b, double* c, double* d, lsfitreport* rep, ae_state *_state); void logisticfit4ec(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, double* a, double* b, double* c, double* d, lsfitreport* rep, ae_state *_state); void logisticfit5(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state); void logisticfit5ec(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state); void logisticfit45x(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, double cnstrleft, double cnstrright, ae_bool is4pl, double lambdav, double epsx, ae_int_t rscnt, double* a, double* b, double* c, double* d, double* g, lsfitreport* rep, ae_state *_state); void barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state); void _pexec_barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state); void barycentricfitfloaterhormann(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state); void _pexec_barycentricfitfloaterhormann(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, barycentricinterpolant* b, barycentricfitreport* rep, ae_state *_state); void spline1dfitpenalized(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfitpenalized(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void spline1dfitpenalizedw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfitpenalizedw(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, ae_int_t m, double rho, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void spline1dfitcubicwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfitcubicwc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void spline1dfithermitewc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfithermitewc(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void spline1dfitcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfitcubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void spline1dfithermite(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void _pexec_spline1dfithermite(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t m, ae_int_t* info, spline1dinterpolant* s, spline1dfitreport* rep, ae_state *_state); void lsfitlinearw(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void _pexec_lsfitlinearw(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void lsfitlinearwc(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void _pexec_lsfitlinearwc(/* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void lsfitlinear(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void _pexec_lsfitlinear(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, ae_int_t n, ae_int_t m, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void lsfitlinearc(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void _pexec_lsfitlinearc(/* Real */ ae_vector* y, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void lsfitcreatewf(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate* state, ae_state *_state); void lsfitcreatef(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate* state, ae_state *_state); void lsfitcreatewfg(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, ae_bool cheapfg, lsfitstate* state, ae_state *_state); void lsfitcreatefg(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, ae_bool cheapfg, lsfitstate* state, ae_state *_state); void lsfitcreatewfgh(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate* state, ae_state *_state); void lsfitcreatefgh(/* Real */ ae_matrix* x, /* Real */ ae_vector* y, /* Real */ ae_vector* c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate* state, ae_state *_state); void lsfitsetcond(lsfitstate* state, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state); void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state); void lsfitsetscale(lsfitstate* state, /* Real */ ae_vector* s, ae_state *_state); void lsfitsetbc(lsfitstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); ae_bool lsfititeration(lsfitstate* state, ae_state *_state); void lsfitresults(lsfitstate* state, ae_int_t* info, /* Real */ ae_vector* c, lsfitreport* rep, ae_state *_state); void lsfitsetgradientcheck(lsfitstate* state, double teststep, ae_state *_state); void lsfitscalexy(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* w, ae_int_t n, /* Real */ ae_vector* xc, /* Real */ ae_vector* yc, /* Integer */ ae_vector* dc, ae_int_t k, double* xa, double* xb, double* sa, double* sb, /* Real */ ae_vector* xoriginal, /* Real */ ae_vector* yoriginal, ae_state *_state); void _polynomialfitreport_init(void* _p, ae_state *_state); void _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state); void _polynomialfitreport_clear(void* _p); void _polynomialfitreport_destroy(void* _p); void _barycentricfitreport_init(void* _p, ae_state *_state); void _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state); void _barycentricfitreport_clear(void* _p); void _barycentricfitreport_destroy(void* _p); void _spline1dfitreport_init(void* _p, ae_state *_state); void _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state); void _spline1dfitreport_clear(void* _p); void _spline1dfitreport_destroy(void* _p); void _lsfitreport_init(void* _p, ae_state *_state); void _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state); void _lsfitreport_clear(void* _p); void _lsfitreport_destroy(void* _p); void _lsfitstate_init(void* _p, ae_state *_state); void _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state); void _lsfitstate_clear(void* _p); void _lsfitstate_destroy(void* _p); void pspline2build(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant* p, ae_state *_state); void pspline3build(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant* p, ae_state *_state); void pspline2buildperiodic(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant* p, ae_state *_state); void pspline3buildperiodic(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant* p, ae_state *_state); void pspline2parametervalues(pspline2interpolant* p, ae_int_t* n, /* Real */ ae_vector* t, ae_state *_state); void pspline3parametervalues(pspline3interpolant* p, ae_int_t* n, /* Real */ ae_vector* t, ae_state *_state); void pspline2calc(pspline2interpolant* p, double t, double* x, double* y, ae_state *_state); void pspline3calc(pspline3interpolant* p, double t, double* x, double* y, double* z, ae_state *_state); void pspline2tangent(pspline2interpolant* p, double t, double* x, double* y, ae_state *_state); void pspline3tangent(pspline3interpolant* p, double t, double* x, double* y, double* z, ae_state *_state); void pspline2diff(pspline2interpolant* p, double t, double* x, double* dx, double* y, double* dy, ae_state *_state); void pspline3diff(pspline3interpolant* p, double t, double* x, double* dx, double* y, double* dy, double* z, double* dz, ae_state *_state); void pspline2diff2(pspline2interpolant* p, double t, double* x, double* dx, double* d2x, double* y, double* dy, double* d2y, ae_state *_state); void pspline3diff2(pspline3interpolant* p, double t, double* x, double* dx, double* d2x, double* y, double* dy, double* d2y, double* z, double* dz, double* d2z, ae_state *_state); double pspline2arclength(pspline2interpolant* p, double a, double b, ae_state *_state); double pspline3arclength(pspline3interpolant* p, double a, double b, ae_state *_state); void parametricrdpfixed(/* Real */ ae_matrix* x, ae_int_t n, ae_int_t d, ae_int_t stopm, double stopeps, /* Real */ ae_matrix* x2, /* Integer */ ae_vector* idx2, ae_int_t* nsections, ae_state *_state); void _pspline2interpolant_init(void* _p, ae_state *_state); void _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _pspline2interpolant_clear(void* _p); void _pspline2interpolant_destroy(void* _p); void _pspline3interpolant_init(void* _p, ae_state *_state); void _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _pspline3interpolant_clear(void* _p); void _pspline3interpolant_destroy(void* _p); void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state); void rbfsetpoints(rbfmodel* s, /* Real */ ae_matrix* xy, ae_int_t n, ae_state *_state); void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state); void rbfsetalgomultilayer(rbfmodel* s, double rbase, ae_int_t nlayers, double lambdav, ae_state *_state); void rbfsetlinterm(rbfmodel* s, ae_state *_state); void rbfsetconstterm(rbfmodel* s, ae_state *_state); void rbfsetzeroterm(rbfmodel* s, ae_state *_state); void rbfsetcond(rbfmodel* s, double epsort, double epserr, ae_int_t maxits, ae_state *_state); void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state); double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state); double rbfcalc3(rbfmodel* s, double x0, double x1, double x2, ae_state *_state); void rbfcalc(rbfmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void rbfcalcbuf(rbfmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void rbfgridcalc2(rbfmodel* s, /* Real */ ae_vector* x0, ae_int_t n0, /* Real */ ae_vector* x1, ae_int_t n1, /* Real */ ae_matrix* y, ae_state *_state); void rbfunpack(rbfmodel* s, ae_int_t* nx, ae_int_t* ny, /* Real */ ae_matrix* xwr, ae_int_t* nc, /* Real */ ae_matrix* v, ae_state *_state); void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state); void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state); void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state); void _rbfmodel_init(void* _p, ae_state *_state); void _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state); void _rbfmodel_clear(void* _p); void _rbfmodel_destroy(void* _p); void _rbfreport_init(void* _p, ae_state *_state); void _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state); void _rbfreport_clear(void* _p); void _rbfreport_destroy(void* _p); double spline2dcalc(spline2dinterpolant* c, double x, double y, ae_state *_state); void spline2ddiff(spline2dinterpolant* c, double x, double y, double* f, double* fx, double* fy, double* fxy, ae_state *_state); void spline2dlintransxy(spline2dinterpolant* c, double ax, double bx, double ay, double by, ae_state *_state); void spline2dlintransf(spline2dinterpolant* c, double a, double b, ae_state *_state); void spline2dcopy(spline2dinterpolant* c, spline2dinterpolant* cc, ae_state *_state); void spline2dresamplebicubic(/* Real */ ae_matrix* a, ae_int_t oldheight, ae_int_t oldwidth, /* Real */ ae_matrix* b, ae_int_t newheight, ae_int_t newwidth, ae_state *_state); void spline2dresamplebilinear(/* Real */ ae_matrix* a, ae_int_t oldheight, ae_int_t oldwidth, /* Real */ ae_matrix* b, ae_int_t newheight, ae_int_t newwidth, ae_state *_state); void spline2dbuildbilinearv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* f, ae_int_t d, spline2dinterpolant* c, ae_state *_state); void spline2dbuildbicubicv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* f, ae_int_t d, spline2dinterpolant* c, ae_state *_state); void spline2dcalcvbuf(spline2dinterpolant* c, double x, double y, /* Real */ ae_vector* f, ae_state *_state); void spline2dcalcv(spline2dinterpolant* c, double x, double y, /* Real */ ae_vector* f, ae_state *_state); void spline2dunpackv(spline2dinterpolant* c, ae_int_t* m, ae_int_t* n, ae_int_t* d, /* Real */ ae_matrix* tbl, ae_state *_state); void spline2dbuildbilinear(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_matrix* f, ae_int_t m, ae_int_t n, spline2dinterpolant* c, ae_state *_state); void spline2dbuildbicubic(/* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_matrix* f, ae_int_t m, ae_int_t n, spline2dinterpolant* c, ae_state *_state); void spline2dunpack(spline2dinterpolant* c, ae_int_t* m, ae_int_t* n, /* Real */ ae_matrix* tbl, ae_state *_state); void _spline2dinterpolant_init(void* _p, ae_state *_state); void _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _spline2dinterpolant_clear(void* _p); void _spline2dinterpolant_destroy(void* _p); double spline3dcalc(spline3dinterpolant* c, double x, double y, double z, ae_state *_state); void spline3dlintransxyz(spline3dinterpolant* c, double ax, double bx, double ay, double by, double az, double bz, ae_state *_state); void spline3dlintransf(spline3dinterpolant* c, double a, double b, ae_state *_state); void spline3dcopy(spline3dinterpolant* c, spline3dinterpolant* cc, ae_state *_state); void spline3dresampletrilinear(/* Real */ ae_vector* a, ae_int_t oldzcount, ae_int_t oldycount, ae_int_t oldxcount, ae_int_t newzcount, ae_int_t newycount, ae_int_t newxcount, /* Real */ ae_vector* b, ae_state *_state); void spline3dbuildtrilinearv(/* Real */ ae_vector* x, ae_int_t n, /* Real */ ae_vector* y, ae_int_t m, /* Real */ ae_vector* z, ae_int_t l, /* Real */ ae_vector* f, ae_int_t d, spline3dinterpolant* c, ae_state *_state); void spline3dcalcvbuf(spline3dinterpolant* c, double x, double y, double z, /* Real */ ae_vector* f, ae_state *_state); void spline3dcalcv(spline3dinterpolant* c, double x, double y, double z, /* Real */ ae_vector* f, ae_state *_state); void spline3dunpackv(spline3dinterpolant* c, ae_int_t* n, ae_int_t* m, ae_int_t* l, ae_int_t* d, ae_int_t* stype, /* Real */ ae_matrix* tbl, ae_state *_state); void _spline3dinterpolant_init(void* _p, ae_state *_state); void _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state); void _spline3dinterpolant_clear(void* _p); void _spline3dinterpolant_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/alglibmisc.cpp000755 001750 000144 00000545631 13015033052 023336 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "alglibmisc.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Portable high quality random number generator state. Initialized with HQRNDRandomize() or HQRNDSeed(). Fields: S1, S2 - seed values V - precomputed value MagicV - 'magic' value used to determine whether State structure was correctly initialized. *************************************************************************/ _hqrndstate_owner::_hqrndstate_owner() { p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_hqrndstate_init(p_struct, NULL); } _hqrndstate_owner::_hqrndstate_owner(const _hqrndstate_owner &rhs) { p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _hqrndstate_owner& _hqrndstate_owner::operator=(const _hqrndstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_hqrndstate_clear(p_struct); alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _hqrndstate_owner::~_hqrndstate_owner() { alglib_impl::_hqrndstate_clear(p_struct); ae_free(p_struct); } alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() { return p_struct; } alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() const { return const_cast(p_struct); } hqrndstate::hqrndstate() : _hqrndstate_owner() { } hqrndstate::hqrndstate(const hqrndstate &rhs):_hqrndstate_owner(rhs) { } hqrndstate& hqrndstate::operator=(const hqrndstate &rhs) { if( this==&rhs ) return *this; _hqrndstate_owner::operator=(rhs); return *this; } hqrndstate::~hqrndstate() { } /************************************************************************* HQRNDState initialization with random values which come from standard RNG. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndrandomize(hqrndstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hqrndrandomize(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* HQRNDState initialization with seed values -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hqrndseed(s1, s2, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function generates random real number in (0,1), not including interval boundaries State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrnduniformr(const hqrndstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hqrnduniformr(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function generates random integer number in [0, N) 1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() 2. N can be any positive number except for very large numbers: * close to 2^31 on 32-bit systems * close to 2^62 on 64-bit systems An exception will be generated if N is too large. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_int_t hqrnduniformi(const hqrndstate &state, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::hqrnduniformi(const_cast(state.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Random number generator: normal numbers This function generates one random number from normal distribution. Its performance is equal to that of HQRNDNormal2() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrndnormal(const hqrndstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hqrndnormal(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Random number generator: random X and Y such that X^2+Y^2=1 State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndunit2(const hqrndstate &state, double &x, double &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hqrndunit2(const_cast(state.c_ptr()), &x, &y, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Random number generator: normal numbers This function generates two independent random numbers from normal distribution. Its performance is equal to that of HQRNDNormal() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndnormal2(const hqrndstate &state, double &x1, double &x2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hqrndnormal2(const_cast(state.c_ptr()), &x1, &x2, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Random number generator: exponential distribution State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 11.08.2007 by Bochkanov Sergey *************************************************************************/ double hqrndexponential(const hqrndstate &state, const double lambdav) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hqrndexponential(const_cast(state.c_ptr()), lambdav, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function generates random number from discrete distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample N - number of elements to use, N>=1 RESULT this function returns one of the X[i] for random i=0..N-1 -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrnddiscrete(const hqrndstate &state, const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hqrnddiscrete(const_cast(state.c_ptr()), const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function generates random number from continuous distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample, array[N] (can be larger, in this case only leading N elements are used). THIS ARRAY MUST BE SORTED BY ASCENDING. N - number of elements to use, N>=1 RESULT this function returns random number from continuous distribution which tries to approximate X as mush as possible. min(X)<=Result<=max(X). -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrndcontinuous(const hqrndstate &state, const real_1d_array &x, const ae_int_t n) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::hqrndcontinuous(const_cast(state.c_ptr()), const_cast(x.c_ptr()), n, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _kdtree_owner::_kdtree_owner() { p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_kdtree_init(p_struct, NULL); } _kdtree_owner::_kdtree_owner(const _kdtree_owner &rhs) { p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _kdtree_owner& _kdtree_owner::operator=(const _kdtree_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_kdtree_clear(p_struct); alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _kdtree_owner::~_kdtree_owner() { alglib_impl::_kdtree_clear(p_struct); ae_free(p_struct); } alglib_impl::kdtree* _kdtree_owner::c_ptr() { return p_struct; } alglib_impl::kdtree* _kdtree_owner::c_ptr() const { return const_cast(p_struct); } kdtree::kdtree() : _kdtree_owner() { } kdtree::kdtree(const kdtree &rhs):_kdtree_owner(rhs) { } kdtree& kdtree::operator=(const kdtree &rhs) { if( this==&rhs ) return *this; _kdtree_owner::operator=(rhs); return *this; } kdtree::~kdtree() { } /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void kdtreeserialize(kdtree &obj, std::string &s_out) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_int_t ssize; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_alloc_start(&serializer); alglib_impl::kdtreealloc(&serializer, obj.c_ptr(), &state); ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); s_out.clear(); s_out.reserve((size_t)(ssize+1)); alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); alglib_impl::kdtreeserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); if( s_out.length()>(size_t)ssize ) throw ap_error("ALGLIB: serialization integrity error"); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void kdtreeunserialize(std::string &s_in, kdtree &obj) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); alglib_impl::kdtreeunserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values N - number of points, N>=0. NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreebuild(const_cast(xy.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values N - number of points, N>=0. NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = xy.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreebuild(const_cast(xy.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values, integer tags and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values Tags - tags, array[0..N-1], contains integer tags associated with points. N - number of points, N>=0 NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreebuildtagged(const_cast(xy.c_ptr()), const_cast(tags.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values, integer tags and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values Tags - tags, array[0..N-1], contains integer tags associated with points. N - number of points, N>=0 NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (xy.rows()!=tags.length())) throw ap_error("Error while calling 'kdtreebuildtagged': looks like one of arguments has wrong size"); n = xy.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreebuildtagged(const_cast(xy.c_ptr()), const_cast(tags.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* K-NN query: K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of actual neighbors found (either K or N, if K>N). This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* K-NN query: K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of actual neighbors found (either K or N, if K>N). This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; bool selfmatch; selfmatch = true; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* R-NN query: all points within R-sphere centered at X INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. R - radius of sphere (in corresponding norm), R>0 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of neighbors found, >=0 This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain actual results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), r, selfmatch, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* R-NN query: all points within R-sphere centered at X INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. R - radius of sphere (in corresponding norm), R>0 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of neighbors found, >=0 This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain actual results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r) { alglib_impl::ae_state _alglib_env_state; bool selfmatch; selfmatch = true; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), r, selfmatch, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* K-NN query: approximate K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True Eps - approximation factor, Eps>=0. eps-approximate nearest neighbor is a neighbor whose distance from X is at most (1+eps) times distance of true nearest neighbor. RESULT number of actual neighbors found (either K or N, if K>N). NOTES significant performance gain may be achieved only when Eps is is on the order of magnitude of 1 or larger. This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, eps, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* K-NN query: approximate K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True Eps - approximation factor, Eps>=0. eps-approximate nearest neighbor is a neighbor whose distance from X is at most (1+eps) times distance of true nearest neighbor. RESULT number of actual neighbors found (either K or N, if K>N). NOTES significant performance gain may be achieved only when Eps is is on the order of magnitude of 1 or larger. This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps) { alglib_impl::ae_state _alglib_env_state; bool selfmatch; selfmatch = true; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, eps, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* X-values from last query INPUT PARAMETERS KDT - KD-tree X - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS X - rows are filled with X-values NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsx(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* X- and Y-values from last query INPUT PARAMETERS KDT - KD-tree XY - possibly pre-allocated buffer. If XY is too small to store result, it is resized. If size(XY) is enough to store result, it is left unchanged. OUTPUT PARAMETERS XY - rows are filled with points: first NX columns with X-values, next NY columns - with Y-values. NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsxy(const_cast(kdt.c_ptr()), const_cast(xy.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Tags from last query INPUT PARAMETERS KDT - KD-tree Tags - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS Tags - filled with tags associated with points, or, when no tags were supplied, with zeros NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultstags(const_cast(kdt.c_ptr()), const_cast(tags.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Distances from last query INPUT PARAMETERS KDT - KD-tree R - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS R - filled with distances (in corresponding norm) NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsdistances(const_cast(kdt.c_ptr()), const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* X-values from last query; 'interactive' variant for languages like Python which support constructs like "X = KDTreeQueryResultsXI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsxi(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* XY-values from last query; 'interactive' variant for languages like Python which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsxyi(const_cast(kdt.c_ptr()), const_cast(xy.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Tags from last query; 'interactive' variant for languages like Python which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultstagsi(const_cast(kdt.c_ptr()), const_cast(tags.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Distances from last query; 'interactive' variant for languages like Python which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kdtreequeryresultsdistancesi(const_cast(kdt.c_ptr()), const_cast(r.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _xdebugrecord1_owner::_xdebugrecord1_owner() { p_struct = (alglib_impl::xdebugrecord1*)alglib_impl::ae_malloc(sizeof(alglib_impl::xdebugrecord1), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_xdebugrecord1_init(p_struct, NULL); } _xdebugrecord1_owner::_xdebugrecord1_owner(const _xdebugrecord1_owner &rhs) { p_struct = (alglib_impl::xdebugrecord1*)alglib_impl::ae_malloc(sizeof(alglib_impl::xdebugrecord1), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_xdebugrecord1_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _xdebugrecord1_owner& _xdebugrecord1_owner::operator=(const _xdebugrecord1_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_xdebugrecord1_clear(p_struct); alglib_impl::_xdebugrecord1_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _xdebugrecord1_owner::~_xdebugrecord1_owner() { alglib_impl::_xdebugrecord1_clear(p_struct); ae_free(p_struct); } alglib_impl::xdebugrecord1* _xdebugrecord1_owner::c_ptr() { return p_struct; } alglib_impl::xdebugrecord1* _xdebugrecord1_owner::c_ptr() const { return const_cast(p_struct); } xdebugrecord1::xdebugrecord1() : _xdebugrecord1_owner() ,i(p_struct->i),c(*((alglib::complex*)(&p_struct->c))),a(&p_struct->a) { } xdebugrecord1::xdebugrecord1(const xdebugrecord1 &rhs):_xdebugrecord1_owner(rhs) ,i(p_struct->i),c(*((alglib::complex*)(&p_struct->c))),a(&p_struct->a) { } xdebugrecord1& xdebugrecord1::operator=(const xdebugrecord1 &rhs) { if( this==&rhs ) return *this; _xdebugrecord1_owner::operator=(rhs); return *this; } xdebugrecord1::~xdebugrecord1() { } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Creates and returns XDebugRecord1 structure: * integer and complex fields of Rec1 are set to 1 and 1+i correspondingly * array field of Rec1 is set to [2,3] -- ALGLIB -- Copyright 27.05.2014 by Bochkanov Sergey *************************************************************************/ void xdebuginitrecord1(xdebugrecord1 &rec1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebuginitrecord1(const_cast(rec1.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 1D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb1count(const boolean_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::xdebugb1count(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1not(const boolean_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb1not(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1appendcopy(boolean_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb1appendcopy(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered elements set to True. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1outeven(const ae_int_t n, boolean_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb1outeven(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi1sum(const integer_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::xdebugi1sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1neg(const integer_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi1neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1appendcopy(integer_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi1appendcopy(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I, and odd-numbered ones set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1outeven(const ae_int_t n, integer_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi1outeven(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr1sum(const real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::xdebugr1sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1neg(const real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr1neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1appendcopy(real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr1appendcopy(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I*0.25, and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1outeven(const ae_int_t n, real_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr1outeven(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ alglib::complex xdebugc1sum(const complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::xdebugc1sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1neg(const complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc1neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1appendcopy(complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc1appendcopy(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1outeven(const ae_int_t n, complex_1d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc1outeven(n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 2D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb2count(const boolean_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::xdebugb2count(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2not(const boolean_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb2not(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2transpose(boolean_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb2transpose(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2outsin(const ae_int_t m, const ae_int_t n, boolean_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugb2outsin(m, n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi2sum(const integer_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::xdebugi2sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2neg(const integer_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi2neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2transpose(integer_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi2transpose(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2outsin(const ae_int_t m, const ae_int_t n, integer_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugi2outsin(m, n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr2sum(const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::xdebugr2sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2neg(const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr2neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2transpose(real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr2transpose(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2outsin(const ae_int_t m, const ae_int_t n, real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugr2outsin(m, n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ alglib::complex xdebugc2sum(const complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_complex result = alglib_impl::xdebugc2sum(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2neg(const complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc2neg(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2transpose(complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc2transpose(const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2outsincos(const ae_int_t m, const ae_int_t n, complex_2d_array &a) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::xdebugc2outsincos(m, n, const_cast(a.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugmaskedbiasedproductsum(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const real_2d_array &b, const boolean_2d_array &c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::xdebugmaskedbiasedproductsum(m, n, const_cast(a.c_ptr()), const_cast(b.c_ptr()), const_cast(c.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static ae_int_t hqrnd_hqrndmax = 2147483561; static ae_int_t hqrnd_hqrndm1 = 2147483563; static ae_int_t hqrnd_hqrndm2 = 2147483399; static ae_int_t hqrnd_hqrndmagic = 1634357784; static ae_int_t hqrnd_hqrndintegerbase(hqrndstate* state, ae_state *_state); static ae_int_t nearestneighbor_splitnodesize = 6; static ae_int_t nearestneighbor_kdtreefirstversion = 0; static void nearestneighbor_kdtreesplit(kdtree* kdt, ae_int_t i1, ae_int_t i2, ae_int_t d, double s, ae_int_t* i3, ae_state *_state); static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, ae_int_t* nodesoffs, ae_int_t* splitsoffs, ae_int_t i1, ae_int_t i2, ae_int_t maxleafsize, ae_state *_state); static void nearestneighbor_kdtreequerynnrec(kdtree* kdt, ae_int_t offs, ae_state *_state); static void nearestneighbor_kdtreeinitbox(kdtree* kdt, /* Real */ ae_vector* x, ae_state *_state); static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, ae_int_t nx, ae_int_t ny, ae_state *_state); static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state); static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state); /************************************************************************* HQRNDState initialization with random values which come from standard RNG. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndrandomize(hqrndstate* state, ae_state *_state) { ae_int_t s0; ae_int_t s1; _hqrndstate_clear(state); s0 = ae_randominteger(hqrnd_hqrndm1, _state); s1 = ae_randominteger(hqrnd_hqrndm2, _state); hqrndseed(s0, s1, state, _state); } /************************************************************************* HQRNDState initialization with seed values -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndseed(ae_int_t s1, ae_int_t s2, hqrndstate* state, ae_state *_state) { _hqrndstate_clear(state); /* * Protection against negative seeds: * * SEED := -(SEED+1) * * We can use just "-SEED" because there exists such integer number N * that N<0, -N=N<0 too. (This number is equal to 0x800...000). Need * to handle such seed correctly forces us to use a bit complicated * formula. */ if( s1<0 ) { s1 = -(s1+1); } if( s2<0 ) { s2 = -(s2+1); } state->s1 = s1%(hqrnd_hqrndm1-1)+1; state->s2 = s2%(hqrnd_hqrndm2-1)+1; state->magicv = hqrnd_hqrndmagic; } /************************************************************************* This function generates random real number in (0,1), not including interval boundaries State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrnduniformr(hqrndstate* state, ae_state *_state) { double result; result = (double)(hqrnd_hqrndintegerbase(state, _state)+1)/(double)(hqrnd_hqrndmax+2); return result; } /************************************************************************* This function generates random integer number in [0, N) 1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() 2. N can be any positive number except for very large numbers: * close to 2^31 on 32-bit systems * close to 2^62 on 64-bit systems An exception will be generated if N is too large. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state) { ae_int_t maxcnt; ae_int_t mx; ae_int_t a; ae_int_t b; ae_int_t result; ae_assert(n>0, "HQRNDUniformI: N<=0!", _state); maxcnt = hqrnd_hqrndmax+1; /* * Two branches: one for N<=MaxCnt, another for N>MaxCnt. */ if( n>maxcnt ) { /* * N>=MaxCnt. * * We have two options here: * a) N is exactly divisible by MaxCnt * b) N is not divisible by MaxCnt * * In both cases we reduce problem on interval spanning [0,N) * to several subproblems on intervals spanning [0,MaxCnt). */ if( n%maxcnt==0 ) { /* * N is exactly divisible by MaxCnt. * * [0,N) range is dividided into N/MaxCnt bins, * each of them having length equal to MaxCnt. * * We generate: * * random bin number B * * random offset within bin A * Both random numbers are generated by recursively * calling HQRNDUniformI(). * * Result is equal to A+MaxCnt*B. */ ae_assert(n/maxcnt<=maxcnt, "HQRNDUniformI: N is too large", _state); a = hqrnduniformi(state, maxcnt, _state); b = hqrnduniformi(state, n/maxcnt, _state); result = a+maxcnt*b; } else { /* * N is NOT exactly divisible by MaxCnt. * * [0,N) range is dividided into Ceil(N/MaxCnt) bins, * each of them having length equal to MaxCnt. * * We generate: * * random bin number B in [0, Ceil(N/MaxCnt)-1] * * random offset within bin A * * if both of what is below is true * 1) bin number B is that of the last bin * 2) A >= N mod MaxCnt * then we repeat generation of A/B. * This stage is essential in order to avoid bias in the result. * * otherwise, we return A*MaxCnt+N */ ae_assert(n/maxcnt+1<=maxcnt, "HQRNDUniformI: N is too large", _state); result = -1; do { a = hqrnduniformi(state, maxcnt, _state); b = hqrnduniformi(state, n/maxcnt+1, _state); if( b==n/maxcnt&&a>=n%maxcnt ) { continue; } result = a+maxcnt*b; } while(result<0); } } else { /* * N<=MaxCnt * * Code below is a bit complicated because we can not simply * return "HQRNDIntegerBase() mod N" - it will be skewed for * large N's in [0.1*HQRNDMax...HQRNDMax]. */ mx = maxcnt-maxcnt%n; do { result = hqrnd_hqrndintegerbase(state, _state); } while(result>=mx); result = result%n; } return result; } /************************************************************************* Random number generator: normal numbers This function generates one random number from normal distribution. Its performance is equal to that of HQRNDNormal2() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ double hqrndnormal(hqrndstate* state, ae_state *_state) { double v1; double v2; double result; hqrndnormal2(state, &v1, &v2, _state); result = v1; return result; } /************************************************************************* Random number generator: random X and Y such that X^2+Y^2=1 State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state) { double v; double mx; double mn; *x = 0; *y = 0; do { hqrndnormal2(state, x, y, _state); } while(!(ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))); mx = ae_maxreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); mn = ae_minreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); v = mx*ae_sqrt(1+ae_sqr(mn/mx, _state), _state); *x = *x/v; *y = *y/v; } /************************************************************************* Random number generator: normal numbers This function generates two independent random numbers from normal distribution. Its performance is equal to that of HQRNDNormal() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/ void hqrndnormal2(hqrndstate* state, double* x1, double* x2, ae_state *_state) { double u; double v; double s; *x1 = 0; *x2 = 0; for(;;) { u = 2*hqrnduniformr(state, _state)-1; v = 2*hqrnduniformr(state, _state)-1; s = ae_sqr(u, _state)+ae_sqr(v, _state); if( ae_fp_greater(s,(double)(0))&&ae_fp_less(s,(double)(1)) ) { /* * two Sqrt's instead of one to * avoid overflow when S is too small */ s = ae_sqrt(-2*ae_log(s, _state), _state)/ae_sqrt(s, _state); *x1 = u*s; *x2 = v*s; return; } } } /************************************************************************* Random number generator: exponential distribution State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 11.08.2007 by Bochkanov Sergey *************************************************************************/ double hqrndexponential(hqrndstate* state, double lambdav, ae_state *_state) { double result; ae_assert(ae_fp_greater(lambdav,(double)(0)), "HQRNDExponential: LambdaV<=0!", _state); result = -ae_log(hqrnduniformr(state, _state), _state)/lambdav; return result; } /************************************************************************* This function generates random number from discrete distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample N - number of elements to use, N>=1 RESULT this function returns one of the X[i] for random i=0..N-1 -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrnddiscrete(hqrndstate* state, /* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double result; ae_assert(n>0, "HQRNDDiscrete: N<=0", _state); ae_assert(n<=x->cnt, "HQRNDDiscrete: Length(X)ptr.p_double[hqrnduniformi(state, n, _state)]; return result; } /************************************************************************* This function generates random number from continuous distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample, array[N] (can be larger, in this case only leading N elements are used). THIS ARRAY MUST BE SORTED BY ASCENDING. N - number of elements to use, N>=1 RESULT this function returns random number from continuous distribution which tries to approximate X as mush as possible. min(X)<=Result<=max(X). -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/ double hqrndcontinuous(hqrndstate* state, /* Real */ ae_vector* x, ae_int_t n, ae_state *_state) { double mx; double mn; ae_int_t i; double result; ae_assert(n>0, "HQRNDContinuous: N<=0", _state); ae_assert(n<=x->cnt, "HQRNDContinuous: Length(X)ptr.p_double[0]; return result; } i = hqrnduniformi(state, n-1, _state); mn = x->ptr.p_double[i]; mx = x->ptr.p_double[i+1]; ae_assert(ae_fp_greater_eq(mx,mn), "HQRNDDiscrete: X is not sorted by ascending", _state); if( ae_fp_neq(mx,mn) ) { result = (mx-mn)*hqrnduniformr(state, _state)+mn; } else { result = mn; } return result; } /************************************************************************* This function returns random integer in [0,HQRNDMax] L'Ecuyer, Efficient and portable combined random number generators *************************************************************************/ static ae_int_t hqrnd_hqrndintegerbase(hqrndstate* state, ae_state *_state) { ae_int_t k; ae_int_t result; ae_assert(state->magicv==hqrnd_hqrndmagic, "HQRNDIntegerBase: State is not correctly initialized!", _state); k = state->s1/53668; state->s1 = 40014*(state->s1-k*53668)-k*12211; if( state->s1<0 ) { state->s1 = state->s1+2147483563; } k = state->s2/52774; state->s2 = 40692*(state->s2-k*52774)-k*3791; if( state->s2<0 ) { state->s2 = state->s2+2147483399; } /* * Result */ result = state->s1-state->s2; if( result<1 ) { result = result+2147483562; } result = result-1; return result; } void _hqrndstate_init(void* _p, ae_state *_state) { hqrndstate *p = (hqrndstate*)_p; ae_touch_ptr((void*)p); } void _hqrndstate_init_copy(void* _dst, void* _src, ae_state *_state) { hqrndstate *dst = (hqrndstate*)_dst; hqrndstate *src = (hqrndstate*)_src; dst->s1 = src->s1; dst->s2 = src->s2; dst->magicv = src->magicv; } void _hqrndstate_clear(void* _p) { hqrndstate *p = (hqrndstate*)_p; ae_touch_ptr((void*)p); } void _hqrndstate_destroy(void* _p) { hqrndstate *p = (hqrndstate*)_p; ae_touch_ptr((void*)p); } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values N - number of points, N>=0. NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuild(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree* kdt, ae_state *_state) { ae_frame _frame_block; ae_vector tags; ae_int_t i; ae_frame_make(_state, &_frame_block); _kdtree_clear(kdt); ae_vector_init(&tags, 0, DT_INT, _state); ae_assert(n>=0, "KDTreeBuild: N<0", _state); ae_assert(nx>=1, "KDTreeBuild: NX<1", _state); ae_assert(ny>=0, "KDTreeBuild: NY<0", _state); ae_assert(normtype>=0&&normtype<=2, "KDTreeBuild: incorrect NormType", _state); ae_assert(xy->rows>=n, "KDTreeBuild: rows(X)cols>=nx+ny||n==0, "KDTreeBuild: cols(X)0 ) { ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { tags.ptr.p_int[i] = 0; } } kdtreebuildtagged(xy, &tags, n, nx, ny, normtype, kdt, _state); ae_frame_leave(_state); } /************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values, integer tags and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values Tags - tags, array[0..N-1], contains integer tags associated with points. N - number of points, N>=0 NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreebuildtagged(/* Real */ ae_matrix* xy, /* Integer */ ae_vector* tags, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree* kdt, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t maxnodes; ae_int_t nodesoffs; ae_int_t splitsoffs; _kdtree_clear(kdt); ae_assert(n>=0, "KDTreeBuildTagged: N<0", _state); ae_assert(nx>=1, "KDTreeBuildTagged: NX<1", _state); ae_assert(ny>=0, "KDTreeBuildTagged: NY<0", _state); ae_assert(normtype>=0&&normtype<=2, "KDTreeBuildTagged: incorrect NormType", _state); ae_assert(xy->rows>=n, "KDTreeBuildTagged: rows(X)cols>=nx+ny||n==0, "KDTreeBuildTagged: cols(X)n = n; kdt->nx = nx; kdt->ny = ny; kdt->normtype = normtype; kdt->kcur = 0; /* * N=0 => quick exit */ if( n==0 ) { return; } /* * Allocate */ nearestneighbor_kdtreeallocdatasetindependent(kdt, nx, ny, _state); nearestneighbor_kdtreeallocdatasetdependent(kdt, n, nx, ny, _state); /* * Initial fill */ for(i=0; i<=n-1; i++) { ae_v_move(&kdt->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); ae_v_move(&kdt->xy.ptr.pp_double[i][nx], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(nx,2*nx+ny-1)); kdt->tags.ptr.p_int[i] = tags->ptr.p_int[i]; } /* * Determine bounding box */ ae_v_move(&kdt->boxmin.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); ae_v_move(&kdt->boxmax.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); for(i=1; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { kdt->boxmin.ptr.p_double[j] = ae_minreal(kdt->boxmin.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); kdt->boxmax.ptr.p_double[j] = ae_maxreal(kdt->boxmax.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); } } /* * prepare tree structure * * MaxNodes=N because we guarantee no trivial splits, i.e. * every split will generate two non-empty boxes */ maxnodes = n; ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*maxnodes, _state); ae_vector_set_length(&kdt->splits, 2*maxnodes, _state); nodesoffs = 0; splitsoffs = 0; ae_v_move(&kdt->curboxmin.ptr.p_double[0], 1, &kdt->boxmin.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_move(&kdt->curboxmax.ptr.p_double[0], 1, &kdt->boxmax.ptr.p_double[0], 1, ae_v_len(0,nx-1)); nearestneighbor_kdtreegeneratetreerec(kdt, &nodesoffs, &splitsoffs, 0, n, 8, _state); } /************************************************************************* K-NN query: K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of actual neighbors found (either K or N, if K>N). This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryknn(kdtree* kdt, /* Real */ ae_vector* x, ae_int_t k, ae_bool selfmatch, ae_state *_state) { ae_int_t result; ae_assert(k>=1, "KDTreeQueryKNN: K<1!", _state); ae_assert(x->cnt>=kdt->nx, "KDTreeQueryKNN: Length(X)nx, _state), "KDTreeQueryKNN: X contains infinite or NaN values!", _state); result = kdtreequeryaknn(kdt, x, k, selfmatch, 0.0, _state); return result; } /************************************************************************* R-NN query: all points within R-sphere centered at X INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. R - radius of sphere (in corresponding norm), R>0 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of neighbors found, >=0 This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain actual results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryrnn(kdtree* kdt, /* Real */ ae_vector* x, double r, ae_bool selfmatch, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t result; ae_assert(ae_fp_greater(r,(double)(0)), "KDTreeQueryRNN: incorrect R!", _state); ae_assert(x->cnt>=kdt->nx, "KDTreeQueryRNN: Length(X)nx, _state), "KDTreeQueryRNN: X contains infinite or NaN values!", _state); /* * Handle special case: KDT.N=0 */ if( kdt->n==0 ) { kdt->kcur = 0; result = 0; return result; } /* * Prepare parameters */ kdt->kneeded = 0; if( kdt->normtype!=2 ) { kdt->rneeded = r; } else { kdt->rneeded = ae_sqr(r, _state); } kdt->selfmatch = selfmatch; kdt->approxf = (double)(1); kdt->kcur = 0; /* * calculate distance from point to current bounding box */ nearestneighbor_kdtreeinitbox(kdt, x, _state); /* * call recursive search * results are returned as heap */ nearestneighbor_kdtreequerynnrec(kdt, 0, _state); /* * pop from heap to generate ordered representation * * last element is not pop'ed because it is already in * its place */ result = kdt->kcur; j = kdt->kcur; for(i=kdt->kcur; i>=2; i--) { tagheappopi(&kdt->r, &kdt->idx, &j, _state); } return result; } /************************************************************************* K-NN query: approximate K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True Eps - approximation factor, Eps>=0. eps-approximate nearest neighbor is a neighbor whose distance from X is at most (1+eps) times distance of true nearest neighbor. RESULT number of actual neighbors found (either K or N, if K>N). NOTES significant performance gain may be achieved only when Eps is is on the order of magnitude of 1 or larger. This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ ae_int_t kdtreequeryaknn(kdtree* kdt, /* Real */ ae_vector* x, ae_int_t k, ae_bool selfmatch, double eps, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t result; ae_assert(k>0, "KDTreeQueryAKNN: incorrect K!", _state); ae_assert(ae_fp_greater_eq(eps,(double)(0)), "KDTreeQueryAKNN: incorrect Eps!", _state); ae_assert(x->cnt>=kdt->nx, "KDTreeQueryAKNN: Length(X)nx, _state), "KDTreeQueryAKNN: X contains infinite or NaN values!", _state); /* * Handle special case: KDT.N=0 */ if( kdt->n==0 ) { kdt->kcur = 0; result = 0; return result; } /* * Prepare parameters */ k = ae_minint(k, kdt->n, _state); kdt->kneeded = k; kdt->rneeded = (double)(0); kdt->selfmatch = selfmatch; if( kdt->normtype==2 ) { kdt->approxf = 1/ae_sqr(1+eps, _state); } else { kdt->approxf = 1/(1+eps); } kdt->kcur = 0; /* * calculate distance from point to current bounding box */ nearestneighbor_kdtreeinitbox(kdt, x, _state); /* * call recursive search * results are returned as heap */ nearestneighbor_kdtreequerynnrec(kdt, 0, _state); /* * pop from heap to generate ordered representation * * last element is non pop'ed because it is already in * its place */ result = kdt->kcur; j = kdt->kcur; for(i=kdt->kcur; i>=2; i--) { tagheappopi(&kdt->r, &kdt->idx, &j, _state); } return result; } /************************************************************************* X-values from last query INPUT PARAMETERS KDT - KD-tree X - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS X - rows are filled with X-values NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsx(kdtree* kdt, /* Real */ ae_matrix* x, ae_state *_state) { ae_int_t i; ae_int_t k; if( kdt->kcur==0 ) { return; } if( x->rowskcur||x->colsnx ) { ae_matrix_set_length(x, kdt->kcur, kdt->nx, _state); } k = kdt->kcur; for(i=0; i<=k-1; i++) { ae_v_move(&x->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[kdt->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx-1)); } } /************************************************************************* X- and Y-values from last query INPUT PARAMETERS KDT - KD-tree XY - possibly pre-allocated buffer. If XY is too small to store result, it is resized. If size(XY) is enough to store result, it is left unchanged. OUTPUT PARAMETERS XY - rows are filled with points: first NX columns with X-values, next NY columns - with Y-values. NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxy(kdtree* kdt, /* Real */ ae_matrix* xy, ae_state *_state) { ae_int_t i; ae_int_t k; if( kdt->kcur==0 ) { return; } if( xy->rowskcur||xy->colsnx+kdt->ny ) { ae_matrix_set_length(xy, kdt->kcur, kdt->nx+kdt->ny, _state); } k = kdt->kcur; for(i=0; i<=k-1; i++) { ae_v_move(&xy->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[kdt->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx+kdt->ny-1)); } } /************************************************************************* Tags from last query INPUT PARAMETERS KDT - KD-tree Tags - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS Tags - filled with tags associated with points, or, when no tags were supplied, with zeros NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstags(kdtree* kdt, /* Integer */ ae_vector* tags, ae_state *_state) { ae_int_t i; ae_int_t k; if( kdt->kcur==0 ) { return; } if( tags->cntkcur ) { ae_vector_set_length(tags, kdt->kcur, _state); } k = kdt->kcur; for(i=0; i<=k-1; i++) { tags->ptr.p_int[i] = kdt->tags.ptr.p_int[kdt->idx.ptr.p_int[i]]; } } /************************************************************************* Distances from last query INPUT PARAMETERS KDT - KD-tree R - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS R - filled with distances (in corresponding norm) NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistances(kdtree* kdt, /* Real */ ae_vector* r, ae_state *_state) { ae_int_t i; ae_int_t k; if( kdt->kcur==0 ) { return; } if( r->cntkcur ) { ae_vector_set_length(r, kdt->kcur, _state); } k = kdt->kcur; /* * unload norms * * Abs() call is used to handle cases with negative norms * (generated during KFN requests) */ if( kdt->normtype==0 ) { for(i=0; i<=k-1; i++) { r->ptr.p_double[i] = ae_fabs(kdt->r.ptr.p_double[i], _state); } } if( kdt->normtype==1 ) { for(i=0; i<=k-1; i++) { r->ptr.p_double[i] = ae_fabs(kdt->r.ptr.p_double[i], _state); } } if( kdt->normtype==2 ) { for(i=0; i<=k-1; i++) { r->ptr.p_double[i] = ae_sqrt(ae_fabs(kdt->r.ptr.p_double[i], _state), _state); } } } /************************************************************************* X-values from last query; 'interactive' variant for languages like Python which support constructs like "X = KDTreeQueryResultsXI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxi(kdtree* kdt, /* Real */ ae_matrix* x, ae_state *_state) { ae_matrix_clear(x); kdtreequeryresultsx(kdt, x, _state); } /************************************************************************* XY-values from last query; 'interactive' variant for languages like Python which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsxyi(kdtree* kdt, /* Real */ ae_matrix* xy, ae_state *_state) { ae_matrix_clear(xy); kdtreequeryresultsxy(kdt, xy, _state); } /************************************************************************* Tags from last query; 'interactive' variant for languages like Python which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultstagsi(kdtree* kdt, /* Integer */ ae_vector* tags, ae_state *_state) { ae_vector_clear(tags); kdtreequeryresultstags(kdt, tags, _state); } /************************************************************************* Distances from last query; 'interactive' variant for languages like Python which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void kdtreequeryresultsdistancesi(kdtree* kdt, /* Real */ ae_vector* r, ae_state *_state) { ae_vector_clear(r); kdtreequeryresultsdistances(kdt, r, _state); } /************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state) { /* * Header */ ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); /* * Data */ ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); allocrealmatrix(s, &tree->xy, -1, -1, _state); allocintegerarray(s, &tree->tags, -1, _state); allocrealarray(s, &tree->boxmin, -1, _state); allocrealarray(s, &tree->boxmax, -1, _state); allocintegerarray(s, &tree->nodes, -1, _state); allocrealarray(s, &tree->splits, -1, _state); } /************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state) { /* * Header */ ae_serializer_serialize_int(s, getkdtreeserializationcode(_state), _state); ae_serializer_serialize_int(s, nearestneighbor_kdtreefirstversion, _state); /* * Data */ ae_serializer_serialize_int(s, tree->n, _state); ae_serializer_serialize_int(s, tree->nx, _state); ae_serializer_serialize_int(s, tree->ny, _state); ae_serializer_serialize_int(s, tree->normtype, _state); serializerealmatrix(s, &tree->xy, -1, -1, _state); serializeintegerarray(s, &tree->tags, -1, _state); serializerealarray(s, &tree->boxmin, -1, _state); serializerealarray(s, &tree->boxmax, -1, _state); serializeintegerarray(s, &tree->nodes, -1, _state); serializerealarray(s, &tree->splits, -1, _state); } /************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state) { ae_int_t i0; ae_int_t i1; _kdtree_clear(tree); /* * check correctness of header */ ae_serializer_unserialize_int(s, &i0, _state); ae_assert(i0==getkdtreeserializationcode(_state), "KDTreeUnserialize: stream header corrupted", _state); ae_serializer_unserialize_int(s, &i1, _state); ae_assert(i1==nearestneighbor_kdtreefirstversion, "KDTreeUnserialize: stream header corrupted", _state); /* * Unserialize data */ ae_serializer_unserialize_int(s, &tree->n, _state); ae_serializer_unserialize_int(s, &tree->nx, _state); ae_serializer_unserialize_int(s, &tree->ny, _state); ae_serializer_unserialize_int(s, &tree->normtype, _state); unserializerealmatrix(s, &tree->xy, _state); unserializeintegerarray(s, &tree->tags, _state); unserializerealarray(s, &tree->boxmin, _state); unserializerealarray(s, &tree->boxmax, _state); unserializeintegerarray(s, &tree->nodes, _state); unserializerealarray(s, &tree->splits, _state); nearestneighbor_kdtreealloctemporaries(tree, tree->n, tree->nx, tree->ny, _state); } /************************************************************************* Rearranges nodes [I1,I2) using partition in D-th dimension with S as threshold. Returns split position I3: [I1,I3) and [I3,I2) are created as result. This subroutine doesn't create tree structures, just rearranges nodes. *************************************************************************/ static void nearestneighbor_kdtreesplit(kdtree* kdt, ae_int_t i1, ae_int_t i2, ae_int_t d, double s, ae_int_t* i3, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t ileft; ae_int_t iright; double v; *i3 = 0; ae_assert(kdt->n>0, "KDTreeSplit: internal error", _state); /* * split XY/Tags in two parts: * * [ILeft,IRight] is non-processed part of XY/Tags * * After cycle is done, we have Ileft=IRight. We deal with * this element separately. * * After this, [I1,ILeft) contains left part, and [ILeft,I2) * contains right part. */ ileft = i1; iright = i2-1; while(ileftxy.ptr.pp_double[ileft][d],s) ) { /* * XY[ILeft] is on its place. * Advance ILeft. */ ileft = ileft+1; } else { /* * XY[ILeft,..] must be at IRight. * Swap and advance IRight. */ for(i=0; i<=2*kdt->nx+kdt->ny-1; i++) { v = kdt->xy.ptr.pp_double[ileft][i]; kdt->xy.ptr.pp_double[ileft][i] = kdt->xy.ptr.pp_double[iright][i]; kdt->xy.ptr.pp_double[iright][i] = v; } j = kdt->tags.ptr.p_int[ileft]; kdt->tags.ptr.p_int[ileft] = kdt->tags.ptr.p_int[iright]; kdt->tags.ptr.p_int[iright] = j; iright = iright-1; } } if( ae_fp_less_eq(kdt->xy.ptr.pp_double[ileft][d],s) ) { ileft = ileft+1; } else { iright = iright-1; } *i3 = ileft; } /************************************************************************* Recursive kd-tree generation subroutine. PARAMETERS KDT tree NodesOffs unused part of Nodes[] which must be filled by tree SplitsOffs unused part of Splits[] I1, I2 points from [I1,I2) are processed NodesOffs[] and SplitsOffs[] must be large enough. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, ae_int_t* nodesoffs, ae_int_t* splitsoffs, ae_int_t i1, ae_int_t i2, ae_int_t maxleafsize, ae_state *_state) { ae_int_t n; ae_int_t nx; ae_int_t ny; ae_int_t i; ae_int_t j; ae_int_t oldoffs; ae_int_t i3; ae_int_t cntless; ae_int_t cntgreater; double minv; double maxv; ae_int_t minidx; ae_int_t maxidx; ae_int_t d; double ds; double s; double v; double v0; double v1; ae_assert(kdt->n>0, "KDTreeGenerateTreeRec: internal error", _state); ae_assert(i2>i1, "KDTreeGenerateTreeRec: internal error", _state); /* * Generate leaf if needed */ if( i2-i1<=maxleafsize ) { kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; *nodesoffs = *nodesoffs+2; return; } /* * Load values for easier access */ nx = kdt->nx; ny = kdt->ny; /* * Select dimension to split: * * D is a dimension number * In case bounding box has zero size, we enforce creation of the leaf node. */ d = 0; ds = kdt->curboxmax.ptr.p_double[0]-kdt->curboxmin.ptr.p_double[0]; for(i=1; i<=nx-1; i++) { v = kdt->curboxmax.ptr.p_double[i]-kdt->curboxmin.ptr.p_double[i]; if( ae_fp_greater(v,ds) ) { ds = v; d = i; } } if( ae_fp_eq(ds,(double)(0)) ) { kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; *nodesoffs = *nodesoffs+2; return; } /* * Select split position S using sliding midpoint rule, * rearrange points into [I1,I3) and [I3,I2). * * In case all points has same value of D-th component * (MinV=MaxV) we enforce D-th dimension of bounding * box to become exactly zero and repeat tree construction. */ s = kdt->curboxmin.ptr.p_double[d]+0.5*ds; ae_v_move(&kdt->buf.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[i1][d], kdt->xy.stride, ae_v_len(0,i2-i1-1)); n = i2-i1; cntless = 0; cntgreater = 0; minv = kdt->buf.ptr.p_double[0]; maxv = kdt->buf.ptr.p_double[0]; minidx = i1; maxidx = i1; for(i=0; i<=n-1; i++) { v = kdt->buf.ptr.p_double[i]; if( ae_fp_less(v,minv) ) { minv = v; minidx = i1+i; } if( ae_fp_greater(v,maxv) ) { maxv = v; maxidx = i1+i; } if( ae_fp_less(v,s) ) { cntless = cntless+1; } if( ae_fp_greater(v,s) ) { cntgreater = cntgreater+1; } } if( ae_fp_eq(minv,maxv) ) { /* * In case all points has same value of D-th component * (MinV=MaxV) we enforce D-th dimension of bounding * box to become exactly zero and repeat tree construction. */ v0 = kdt->curboxmin.ptr.p_double[d]; v1 = kdt->curboxmax.ptr.p_double[d]; kdt->curboxmin.ptr.p_double[d] = minv; kdt->curboxmax.ptr.p_double[d] = maxv; nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i2, maxleafsize, _state); kdt->curboxmin.ptr.p_double[d] = v0; kdt->curboxmax.ptr.p_double[d] = v1; return; } if( cntless>0&&cntgreater>0 ) { /* * normal midpoint split */ nearestneighbor_kdtreesplit(kdt, i1, i2, d, s, &i3, _state); } else { /* * sliding midpoint */ if( cntless==0 ) { /* * 1. move split to MinV, * 2. place one point to the left bin (move to I1), * others - to the right bin */ s = minv; if( minidx!=i1 ) { for(i=0; i<=2*nx+ny-1; i++) { v = kdt->xy.ptr.pp_double[minidx][i]; kdt->xy.ptr.pp_double[minidx][i] = kdt->xy.ptr.pp_double[i1][i]; kdt->xy.ptr.pp_double[i1][i] = v; } j = kdt->tags.ptr.p_int[minidx]; kdt->tags.ptr.p_int[minidx] = kdt->tags.ptr.p_int[i1]; kdt->tags.ptr.p_int[i1] = j; } i3 = i1+1; } else { /* * 1. move split to MaxV, * 2. place one point to the right bin (move to I2-1), * others - to the left bin */ s = maxv; if( maxidx!=i2-1 ) { for(i=0; i<=2*nx+ny-1; i++) { v = kdt->xy.ptr.pp_double[maxidx][i]; kdt->xy.ptr.pp_double[maxidx][i] = kdt->xy.ptr.pp_double[i2-1][i]; kdt->xy.ptr.pp_double[i2-1][i] = v; } j = kdt->tags.ptr.p_int[maxidx]; kdt->tags.ptr.p_int[maxidx] = kdt->tags.ptr.p_int[i2-1]; kdt->tags.ptr.p_int[i2-1] = j; } i3 = i2-1; } } /* * Generate 'split' node */ kdt->nodes.ptr.p_int[*nodesoffs+0] = 0; kdt->nodes.ptr.p_int[*nodesoffs+1] = d; kdt->nodes.ptr.p_int[*nodesoffs+2] = *splitsoffs; kdt->splits.ptr.p_double[*splitsoffs+0] = s; oldoffs = *nodesoffs; *nodesoffs = *nodesoffs+nearestneighbor_splitnodesize; *splitsoffs = *splitsoffs+1; /* * Recirsive generation: * * update CurBox * * call subroutine * * restore CurBox */ kdt->nodes.ptr.p_int[oldoffs+3] = *nodesoffs; v = kdt->curboxmax.ptr.p_double[d]; kdt->curboxmax.ptr.p_double[d] = s; nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i3, maxleafsize, _state); kdt->curboxmax.ptr.p_double[d] = v; kdt->nodes.ptr.p_int[oldoffs+4] = *nodesoffs; v = kdt->curboxmin.ptr.p_double[d]; kdt->curboxmin.ptr.p_double[d] = s; nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i3, i2, maxleafsize, _state); kdt->curboxmin.ptr.p_double[d] = v; } /************************************************************************* Recursive subroutine for NN queries. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreequerynnrec(kdtree* kdt, ae_int_t offs, ae_state *_state) { double ptdist; ae_int_t i; ae_int_t j; ae_int_t nx; ae_int_t i1; ae_int_t i2; ae_int_t d; double s; double v; double t1; ae_int_t childbestoffs; ae_int_t childworstoffs; ae_int_t childoffs; double prevdist; ae_bool todive; ae_bool bestisleft; ae_bool updatemin; ae_assert(kdt->n>0, "KDTreeQueryNNRec: internal error", _state); /* * Leaf node. * Process points. */ if( kdt->nodes.ptr.p_int[offs]>0 ) { i1 = kdt->nodes.ptr.p_int[offs+1]; i2 = i1+kdt->nodes.ptr.p_int[offs]; for(i=i1; i<=i2-1; i++) { /* * Calculate distance */ ptdist = (double)(0); nx = kdt->nx; if( kdt->normtype==0 ) { for(j=0; j<=nx-1; j++) { ptdist = ae_maxreal(ptdist, ae_fabs(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state), _state); } } if( kdt->normtype==1 ) { for(j=0; j<=nx-1; j++) { ptdist = ptdist+ae_fabs(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state); } } if( kdt->normtype==2 ) { for(j=0; j<=nx-1; j++) { ptdist = ptdist+ae_sqr(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state); } } /* * Skip points with zero distance if self-matches are turned off */ if( ae_fp_eq(ptdist,(double)(0))&&!kdt->selfmatch ) { continue; } /* * We CAN'T process point if R-criterion isn't satisfied, * i.e. (RNeeded<>0) AND (PtDist>R). */ if( ae_fp_eq(kdt->rneeded,(double)(0))||ae_fp_less_eq(ptdist,kdt->rneeded) ) { /* * R-criterion is satisfied, we must either: * * replace worst point, if (KNeeded<>0) AND (KCur=KNeeded) * (or skip, if worst point is better) * * add point without replacement otherwise */ if( kdt->kcurkneeded||kdt->kneeded==0 ) { /* * add current point to heap without replacement */ tagheappushi(&kdt->r, &kdt->idx, &kdt->kcur, ptdist, i, _state); } else { /* * New points are added or not, depending on their distance. * If added, they replace element at the top of the heap */ if( ae_fp_less(ptdist,kdt->r.ptr.p_double[0]) ) { if( kdt->kneeded==1 ) { kdt->idx.ptr.p_int[0] = i; kdt->r.ptr.p_double[0] = ptdist; } else { tagheapreplacetopi(&kdt->r, &kdt->idx, kdt->kneeded, ptdist, i, _state); } } } } } return; } /* * Simple split */ if( kdt->nodes.ptr.p_int[offs]==0 ) { /* * Load: * * D dimension to split * * S split position */ d = kdt->nodes.ptr.p_int[offs+1]; s = kdt->splits.ptr.p_double[kdt->nodes.ptr.p_int[offs+2]]; /* * Calculate: * * ChildBestOffs child box with best chances * * ChildWorstOffs child box with worst chances */ if( ae_fp_less_eq(kdt->x.ptr.p_double[d],s) ) { childbestoffs = kdt->nodes.ptr.p_int[offs+3]; childworstoffs = kdt->nodes.ptr.p_int[offs+4]; bestisleft = ae_true; } else { childbestoffs = kdt->nodes.ptr.p_int[offs+4]; childworstoffs = kdt->nodes.ptr.p_int[offs+3]; bestisleft = ae_false; } /* * Navigate through childs */ for(i=0; i<=1; i++) { /* * Select child to process: * * ChildOffs current child offset in Nodes[] * * UpdateMin whether minimum or maximum value * of bounding box is changed on update */ if( i==0 ) { childoffs = childbestoffs; updatemin = !bestisleft; } else { updatemin = bestisleft; childoffs = childworstoffs; } /* * Update bounding box and current distance */ if( updatemin ) { prevdist = kdt->curdist; t1 = kdt->x.ptr.p_double[d]; v = kdt->curboxmin.ptr.p_double[d]; if( ae_fp_less_eq(t1,s) ) { if( kdt->normtype==0 ) { kdt->curdist = ae_maxreal(kdt->curdist, s-t1, _state); } if( kdt->normtype==1 ) { kdt->curdist = kdt->curdist-ae_maxreal(v-t1, (double)(0), _state)+s-t1; } if( kdt->normtype==2 ) { kdt->curdist = kdt->curdist-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(s-t1, _state); } } kdt->curboxmin.ptr.p_double[d] = s; } else { prevdist = kdt->curdist; t1 = kdt->x.ptr.p_double[d]; v = kdt->curboxmax.ptr.p_double[d]; if( ae_fp_greater_eq(t1,s) ) { if( kdt->normtype==0 ) { kdt->curdist = ae_maxreal(kdt->curdist, t1-s, _state); } if( kdt->normtype==1 ) { kdt->curdist = kdt->curdist-ae_maxreal(t1-v, (double)(0), _state)+t1-s; } if( kdt->normtype==2 ) { kdt->curdist = kdt->curdist-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-s, _state); } } kdt->curboxmax.ptr.p_double[d] = s; } /* * Decide: to dive into cell or not to dive */ if( ae_fp_neq(kdt->rneeded,(double)(0))&&ae_fp_greater(kdt->curdist,kdt->rneeded) ) { todive = ae_false; } else { if( kdt->kcurkneeded||kdt->kneeded==0 ) { /* * KCurcurdist,kdt->r.ptr.p_double[0]*kdt->approxf); } } if( todive ) { nearestneighbor_kdtreequerynnrec(kdt, childoffs, _state); } /* * Restore bounding box and distance */ if( updatemin ) { kdt->curboxmin.ptr.p_double[d] = v; } else { kdt->curboxmax.ptr.p_double[d] = v; } kdt->curdist = prevdist; } return; } } /************************************************************************* Copies X[] to KDT.X[] Loads distance from X[] to bounding box. Initializes CurBox[]. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreeinitbox(kdtree* kdt, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; double vx; double vmin; double vmax; ae_assert(kdt->n>0, "KDTreeInitBox: internal error", _state); /* * calculate distance from point to current bounding box */ kdt->curdist = (double)(0); if( kdt->normtype==0 ) { for(i=0; i<=kdt->nx-1; i++) { vx = x->ptr.p_double[i]; vmin = kdt->boxmin.ptr.p_double[i]; vmax = kdt->boxmax.ptr.p_double[i]; kdt->x.ptr.p_double[i] = vx; kdt->curboxmin.ptr.p_double[i] = vmin; kdt->curboxmax.ptr.p_double[i] = vmax; if( ae_fp_less(vx,vmin) ) { kdt->curdist = ae_maxreal(kdt->curdist, vmin-vx, _state); } else { if( ae_fp_greater(vx,vmax) ) { kdt->curdist = ae_maxreal(kdt->curdist, vx-vmax, _state); } } } } if( kdt->normtype==1 ) { for(i=0; i<=kdt->nx-1; i++) { vx = x->ptr.p_double[i]; vmin = kdt->boxmin.ptr.p_double[i]; vmax = kdt->boxmax.ptr.p_double[i]; kdt->x.ptr.p_double[i] = vx; kdt->curboxmin.ptr.p_double[i] = vmin; kdt->curboxmax.ptr.p_double[i] = vmax; if( ae_fp_less(vx,vmin) ) { kdt->curdist = kdt->curdist+vmin-vx; } else { if( ae_fp_greater(vx,vmax) ) { kdt->curdist = kdt->curdist+vx-vmax; } } } } if( kdt->normtype==2 ) { for(i=0; i<=kdt->nx-1; i++) { vx = x->ptr.p_double[i]; vmin = kdt->boxmin.ptr.p_double[i]; vmax = kdt->boxmax.ptr.p_double[i]; kdt->x.ptr.p_double[i] = vx; kdt->curboxmin.ptr.p_double[i] = vmin; kdt->curboxmax.ptr.p_double[i] = vmax; if( ae_fp_less(vx,vmin) ) { kdt->curdist = kdt->curdist+ae_sqr(vmin-vx, _state); } else { if( ae_fp_greater(vx,vmax) ) { kdt->curdist = kdt->curdist+ae_sqr(vx-vmax, _state); } } } } } /************************************************************************* This function allocates all dataset-independent array fields of KDTree, i.e. such array fields that their dimensions do not depend on dataset size. This function do not sets KDT.NX or KDT.NY - it just allocates arrays -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, ae_int_t nx, ae_int_t ny, ae_state *_state) { ae_assert(kdt->n>0, "KDTreeAllocDatasetIndependent: internal error", _state); ae_vector_set_length(&kdt->x, nx, _state); ae_vector_set_length(&kdt->boxmin, nx, _state); ae_vector_set_length(&kdt->boxmax, nx, _state); ae_vector_set_length(&kdt->curboxmin, nx, _state); ae_vector_set_length(&kdt->curboxmax, nx, _state); } /************************************************************************* This function allocates all dataset-dependent array fields of KDTree, i.e. such array fields that their dimensions depend on dataset size. This function do not sets KDT.N, KDT.NX or KDT.NY - it just allocates arrays. -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state) { ae_assert(n>0, "KDTreeAllocDatasetDependent: internal error", _state); ae_matrix_set_length(&kdt->xy, n, 2*nx+ny, _state); ae_vector_set_length(&kdt->tags, n, _state); ae_vector_set_length(&kdt->idx, n, _state); ae_vector_set_length(&kdt->r, n, _state); ae_vector_set_length(&kdt->x, nx, _state); ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state); ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*n, _state); ae_vector_set_length(&kdt->splits, 2*n, _state); } /************************************************************************* This function allocates temporaries. This function do not sets KDT.N, KDT.NX or KDT.NY - it just allocates arrays. -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state) { ae_assert(n>0, "KDTreeAllocTemporaries: internal error", _state); ae_vector_set_length(&kdt->x, nx, _state); ae_vector_set_length(&kdt->idx, n, _state); ae_vector_set_length(&kdt->r, n, _state); ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state); ae_vector_set_length(&kdt->curboxmin, nx, _state); ae_vector_set_length(&kdt->curboxmax, nx, _state); } void _kdtree_init(void* _p, ae_state *_state) { kdtree *p = (kdtree*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state); ae_vector_init(&p->tags, 0, DT_INT, _state); ae_vector_init(&p->boxmin, 0, DT_REAL, _state); ae_vector_init(&p->boxmax, 0, DT_REAL, _state); ae_vector_init(&p->nodes, 0, DT_INT, _state); ae_vector_init(&p->splits, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->idx, 0, DT_INT, _state); ae_vector_init(&p->r, 0, DT_REAL, _state); ae_vector_init(&p->buf, 0, DT_REAL, _state); ae_vector_init(&p->curboxmin, 0, DT_REAL, _state); ae_vector_init(&p->curboxmax, 0, DT_REAL, _state); } void _kdtree_init_copy(void* _dst, void* _src, ae_state *_state) { kdtree *dst = (kdtree*)_dst; kdtree *src = (kdtree*)_src; dst->n = src->n; dst->nx = src->nx; dst->ny = src->ny; dst->normtype = src->normtype; ae_matrix_init_copy(&dst->xy, &src->xy, _state); ae_vector_init_copy(&dst->tags, &src->tags, _state); ae_vector_init_copy(&dst->boxmin, &src->boxmin, _state); ae_vector_init_copy(&dst->boxmax, &src->boxmax, _state); ae_vector_init_copy(&dst->nodes, &src->nodes, _state); ae_vector_init_copy(&dst->splits, &src->splits, _state); ae_vector_init_copy(&dst->x, &src->x, _state); dst->kneeded = src->kneeded; dst->rneeded = src->rneeded; dst->selfmatch = src->selfmatch; dst->approxf = src->approxf; dst->kcur = src->kcur; ae_vector_init_copy(&dst->idx, &src->idx, _state); ae_vector_init_copy(&dst->r, &src->r, _state); ae_vector_init_copy(&dst->buf, &src->buf, _state); ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state); ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state); dst->curdist = src->curdist; dst->debugcounter = src->debugcounter; } void _kdtree_clear(void* _p) { kdtree *p = (kdtree*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->xy); ae_vector_clear(&p->tags); ae_vector_clear(&p->boxmin); ae_vector_clear(&p->boxmax); ae_vector_clear(&p->nodes); ae_vector_clear(&p->splits); ae_vector_clear(&p->x); ae_vector_clear(&p->idx); ae_vector_clear(&p->r); ae_vector_clear(&p->buf); ae_vector_clear(&p->curboxmin); ae_vector_clear(&p->curboxmax); } void _kdtree_destroy(void* _p) { kdtree *p = (kdtree*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->xy); ae_vector_destroy(&p->tags); ae_vector_destroy(&p->boxmin); ae_vector_destroy(&p->boxmax); ae_vector_destroy(&p->nodes); ae_vector_destroy(&p->splits); ae_vector_destroy(&p->x); ae_vector_destroy(&p->idx); ae_vector_destroy(&p->r); ae_vector_destroy(&p->buf); ae_vector_destroy(&p->curboxmin); ae_vector_destroy(&p->curboxmax); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Creates and returns XDebugRecord1 structure: * integer and complex fields of Rec1 are set to 1 and 1+i correspondingly * array field of Rec1 is set to [2,3] -- ALGLIB -- Copyright 27.05.2014 by Bochkanov Sergey *************************************************************************/ void xdebuginitrecord1(xdebugrecord1* rec1, ae_state *_state) { _xdebugrecord1_clear(rec1); rec1->i = 1; rec1->c.x = (double)(1); rec1->c.y = (double)(1); ae_vector_set_length(&rec1->a, 2, _state); rec1->a.ptr.p_double[0] = (double)(2); rec1->a.ptr.p_double[1] = (double)(3); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 1D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb1count(/* Boolean */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_int_t result; result = 0; for(i=0; i<=a->cnt-1; i++) { if( a->ptr.p_bool[i] ) { result = result+1; } } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1not(/* Boolean */ ae_vector* a, ae_state *_state) { ae_int_t i; for(i=0; i<=a->cnt-1; i++) { a->ptr.p_bool[i] = !a->ptr.p_bool[i]; } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1appendcopy(/* Boolean */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector b; ae_frame_make(_state, &_frame_block); ae_vector_init(&b, 0, DT_BOOL, _state); ae_vector_set_length(&b, a->cnt, _state); for(i=0; i<=b.cnt-1; i++) { b.ptr.p_bool[i] = a->ptr.p_bool[i]; } ae_vector_set_length(a, 2*b.cnt, _state); for(i=0; i<=a->cnt-1; i++) { a->ptr.p_bool[i] = b.ptr.p_bool[i%b.cnt]; } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered elements set to True. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb1outeven(ae_int_t n, /* Boolean */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_vector_clear(a); ae_vector_set_length(a, n, _state); for(i=0; i<=a->cnt-1; i++) { a->ptr.p_bool[i] = i%2==0; } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi1sum(/* Integer */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_int_t result; result = 0; for(i=0; i<=a->cnt-1; i++) { result = result+a->ptr.p_int[i]; } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1neg(/* Integer */ ae_vector* a, ae_state *_state) { ae_int_t i; for(i=0; i<=a->cnt-1; i++) { a->ptr.p_int[i] = -a->ptr.p_int[i]; } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1appendcopy(/* Integer */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector b; ae_frame_make(_state, &_frame_block); ae_vector_init(&b, 0, DT_INT, _state); ae_vector_set_length(&b, a->cnt, _state); for(i=0; i<=b.cnt-1; i++) { b.ptr.p_int[i] = a->ptr.p_int[i]; } ae_vector_set_length(a, 2*b.cnt, _state); for(i=0; i<=a->cnt-1; i++) { a->ptr.p_int[i] = b.ptr.p_int[i%b.cnt]; } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I, and odd-numbered ones set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi1outeven(ae_int_t n, /* Integer */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_vector_clear(a); ae_vector_set_length(a, n, _state); for(i=0; i<=a->cnt-1; i++) { if( i%2==0 ) { a->ptr.p_int[i] = i; } else { a->ptr.p_int[i] = 0; } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr1sum(/* Real */ ae_vector* a, ae_state *_state) { ae_int_t i; double result; result = (double)(0); for(i=0; i<=a->cnt-1; i++) { result = result+a->ptr.p_double[i]; } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1neg(/* Real */ ae_vector* a, ae_state *_state) { ae_int_t i; for(i=0; i<=a->cnt-1; i++) { a->ptr.p_double[i] = -a->ptr.p_double[i]; } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1appendcopy(/* Real */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector b; ae_frame_make(_state, &_frame_block); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_set_length(&b, a->cnt, _state); for(i=0; i<=b.cnt-1; i++) { b.ptr.p_double[i] = a->ptr.p_double[i]; } ae_vector_set_length(a, 2*b.cnt, _state); for(i=0; i<=a->cnt-1; i++) { a->ptr.p_double[i] = b.ptr.p_double[i%b.cnt]; } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I*0.25, and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr1outeven(ae_int_t n, /* Real */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_vector_clear(a); ae_vector_set_length(a, n, _state); for(i=0; i<=a->cnt-1; i++) { if( i%2==0 ) { a->ptr.p_double[i] = i*0.25; } else { a->ptr.p_double[i] = (double)(0); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_complex xdebugc1sum(/* Complex */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_complex result; result = ae_complex_from_i(0); for(i=0; i<=a->cnt-1; i++) { result = ae_c_add(result,a->ptr.p_complex[i]); } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1neg(/* Complex */ ae_vector* a, ae_state *_state) { ae_int_t i; for(i=0; i<=a->cnt-1; i++) { a->ptr.p_complex[i] = ae_c_neg(a->ptr.p_complex[i]); } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1appendcopy(/* Complex */ ae_vector* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector b; ae_frame_make(_state, &_frame_block); ae_vector_init(&b, 0, DT_COMPLEX, _state); ae_vector_set_length(&b, a->cnt, _state); for(i=0; i<=b.cnt-1; i++) { b.ptr.p_complex[i] = a->ptr.p_complex[i]; } ae_vector_set_length(a, 2*b.cnt, _state); for(i=0; i<=a->cnt-1; i++) { a->ptr.p_complex[i] = b.ptr.p_complex[i%b.cnt]; } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc1outeven(ae_int_t n, /* Complex */ ae_vector* a, ae_state *_state) { ae_int_t i; ae_vector_clear(a); ae_vector_set_length(a, n, _state); for(i=0; i<=a->cnt-1; i++) { if( i%2==0 ) { a->ptr.p_complex[i].x = i*0.250; a->ptr.p_complex[i].y = i*0.125; } else { a->ptr.p_complex[i] = ae_complex_from_i(0); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 2D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugb2count(/* Boolean */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t result; result = 0; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { if( a->ptr.pp_bool[i][j] ) { result = result+1; } } } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2not(/* Boolean */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_bool[i][j] = !a->ptr.pp_bool[i][j]; } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2transpose(/* Boolean */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix b; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_BOOL, _state); ae_matrix_set_length(&b, a->rows, a->cols, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { b.ptr.pp_bool[i][j] = a->ptr.pp_bool[i][j]; } } ae_matrix_set_length(a, b.cols, b.rows, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { a->ptr.pp_bool[j][i] = b.ptr.pp_bool[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugb2outsin(ae_int_t m, ae_int_t n, /* Boolean */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_matrix_set_length(a, m, n, _state); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_bool[i][j] = ae_fp_greater(ae_sin((double)(3*i+5*j), _state),(double)(0)); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_int_t xdebugi2sum(/* Integer */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t result; result = 0; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { result = result+a->ptr.pp_int[i][j]; } } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2neg(/* Integer */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_int[i][j] = -a->ptr.pp_int[i][j]; } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2transpose(/* Integer */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix b; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_INT, _state); ae_matrix_set_length(&b, a->rows, a->cols, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { b.ptr.pp_int[i][j] = a->ptr.pp_int[i][j]; } } ae_matrix_set_length(a, b.cols, b.rows, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { a->ptr.pp_int[j][i] = b.ptr.pp_int[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugi2outsin(ae_int_t m, ae_int_t n, /* Integer */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_matrix_set_length(a, m, n, _state); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_int[i][j] = ae_sign(ae_sin((double)(3*i+5*j), _state), _state); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugr2sum(/* Real */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; double result; result = (double)(0); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { result = result+a->ptr.pp_double[i][j]; } } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2neg(/* Real */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_double[i][j] = -a->ptr.pp_double[i][j]; } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2transpose(/* Real */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix b; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_set_length(&b, a->rows, a->cols, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { b.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } ae_matrix_set_length(a, b.cols, b.rows, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { a->ptr.pp_double[j][i] = b.ptr.pp_double[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugr2outsin(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_matrix_set_length(a, m, n, _state); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_double[i][j] = ae_sin((double)(3*i+5*j), _state); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ ae_complex xdebugc2sum(/* Complex */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex result; result = ae_complex_from_i(0); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { result = ae_c_add(result,a->ptr.pp_complex[i][j]); } } return result; } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2neg(/* Complex */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_complex[i][j] = ae_c_neg(a->ptr.pp_complex[i][j]); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2transpose(/* Complex */ ae_matrix* a, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix b; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&b, a->rows, a->cols, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { b.ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } ae_matrix_set_length(a, b.cols, b.rows, _state); for(i=0; i<=b.rows-1; i++) { for(j=0; j<=b.cols-1; j++) { a->ptr.pp_complex[j][i] = b.ptr.pp_complex[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ void xdebugc2outsincos(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(a); ae_matrix_set_length(a, m, n, _state); for(i=0; i<=a->rows-1; i++) { for(j=0; j<=a->cols-1; j++) { a->ptr.pp_complex[i][j].x = ae_sin((double)(3*i+5*j), _state); a->ptr.pp_complex[i][j].y = ae_cos((double)(3*i+5*j), _state); } } } /************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/ double xdebugmaskedbiasedproductsum(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, /* Real */ ae_matrix* b, /* Boolean */ ae_matrix* c, ae_state *_state) { ae_int_t i; ae_int_t j; double result; ae_assert(m>=a->rows, "Assertion failed", _state); ae_assert(m>=b->rows, "Assertion failed", _state); ae_assert(m>=c->rows, "Assertion failed", _state); ae_assert(n>=a->cols, "Assertion failed", _state); ae_assert(n>=b->cols, "Assertion failed", _state); ae_assert(n>=c->cols, "Assertion failed", _state); result = 0.0; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( c->ptr.pp_bool[i][j] ) { result = result+a->ptr.pp_double[i][j]*(1+b->ptr.pp_double[i][j]); } } } return result; } void _xdebugrecord1_init(void* _p, ae_state *_state) { xdebugrecord1 *p = (xdebugrecord1*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->a, 0, DT_REAL, _state); } void _xdebugrecord1_init_copy(void* _dst, void* _src, ae_state *_state) { xdebugrecord1 *dst = (xdebugrecord1*)_dst; xdebugrecord1 *src = (xdebugrecord1*)_src; dst->i = src->i; dst->c = src->c; ae_vector_init_copy(&dst->a, &src->a, _state); } void _xdebugrecord1_clear(void* _p) { xdebugrecord1 *p = (xdebugrecord1*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->a); } void _xdebugrecord1_destroy(void* _p) { xdebugrecord1 *p = (xdebugrecord1*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->a); } } qmapshack-1.10.0/3rdparty/alglib/src/diffequations.h000755 001750 000144 00000023137 13015033052 023526 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _diffequations_pkg_h #define _diffequations_pkg_h #include "ap.h" #include "alglibinternal.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_int_t n; ae_int_t m; double xscale; double h; double eps; ae_bool fraceps; ae_vector yc; ae_vector escale; ae_vector xg; ae_int_t solvertype; ae_bool needdy; double x; ae_vector y; ae_vector dy; ae_matrix ytbl; ae_int_t repterminationtype; ae_int_t repnfev; ae_vector yn; ae_vector yns; ae_vector rka; ae_vector rkc; ae_vector rkcs; ae_matrix rkb; ae_matrix rkk; rcommstate rstate; } odesolverstate; typedef struct { ae_int_t nfev; ae_int_t terminationtype; } odesolverreport; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* *************************************************************************/ class _odesolverstate_owner { public: _odesolverstate_owner(); _odesolverstate_owner(const _odesolverstate_owner &rhs); _odesolverstate_owner& operator=(const _odesolverstate_owner &rhs); virtual ~_odesolverstate_owner(); alglib_impl::odesolverstate* c_ptr(); alglib_impl::odesolverstate* c_ptr() const; protected: alglib_impl::odesolverstate *p_struct; }; class odesolverstate : public _odesolverstate_owner { public: odesolverstate(); odesolverstate(const odesolverstate &rhs); odesolverstate& operator=(const odesolverstate &rhs); virtual ~odesolverstate(); ae_bool &needdy; real_1d_array y; real_1d_array dy; double &x; }; /************************************************************************* *************************************************************************/ class _odesolverreport_owner { public: _odesolverreport_owner(); _odesolverreport_owner(const _odesolverreport_owner &rhs); _odesolverreport_owner& operator=(const _odesolverreport_owner &rhs); virtual ~_odesolverreport_owner(); alglib_impl::odesolverreport* c_ptr(); alglib_impl::odesolverreport* c_ptr() const; protected: alglib_impl::odesolverreport *p_struct; }; class odesolverreport : public _odesolverreport_owner { public: odesolverreport(); odesolverreport(const odesolverreport &rhs); odesolverreport& operator=(const odesolverreport &rhs); virtual ~odesolverreport(); ae_int_t &nfev; ae_int_t &terminationtype; }; /************************************************************************* Cash-Karp adaptive ODE solver. This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys (here Y may be single variable or vector of N variables). INPUT PARAMETERS: Y - initial conditions, array[0..N-1]. contains values of Y[] at X[0] N - system size X - points at which Y should be tabulated, array[0..M-1] integrations starts at X[0], ends at X[M-1], intermediate values at X[i] are returned too. SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! M - number of intermediate points + first point + last point: * M>2 means that you need both Y(X[M-1]) and M-2 values at intermediate points * M=2 means that you want just to integrate from X[0] to X[1] and don't interested in intermediate values. * M=1 means that you don't want to integrate :) it is degenerate case, but it will be handled correctly. * M<1 means error Eps - tolerance (absolute/relative error on each step will be less than Eps). When passing: * Eps>0, it means desired ABSOLUTE error * Eps<0, it means desired RELATIVE error. Relative errors are calculated with respect to maximum values of Y seen so far. Be careful to use this criterion when starting from Y[] that are close to zero. H - initial step lenth, it will be adjusted automatically after the first step. If H=0, step will be selected automatically (usualy it will be equal to 0.001 of min(x[i]-x[j])). OUTPUT PARAMETERS State - structure which stores algorithm state between subsequent calls of OdeSolverIteration. Used for reverse communication. This structure should be passed to the OdeSolverIteration subroutine. SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state); void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool odesolveriteration(const odesolverstate &state); /************************************************************************* This function is used to launcn iterations of ODE solver It accepts following parameters: diff - callback which calculates dy/dx for given y and x ptr - optional pointer which is passed to diff; can be NULL -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolversolve(odesolverstate &state, void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), void *ptr = NULL); /************************************************************************* ODE solver results Called after OdeSolverIteration returned False. INPUT PARAMETERS: State - algorithm state (used by OdeSolverIteration). OUTPUT PARAMETERS: M - number of tabulated values, M>=1 XTbl - array[0..M-1], values of X YTbl - array[0..M-1,0..N-1], values of Y in X[i] Rep - solver report: * Rep.TerminationType completetion code: * -2 X is not ordered by ascending/descending or there are non-distinct X[], i.e. X[i]=X[i+1] * -1 incorrect parameters were specified * 1 task has been solved * Rep.NFEV contains number of function calculations -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/ void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void odesolverrkck(/* Real */ ae_vector* y, ae_int_t n, /* Real */ ae_vector* x, ae_int_t m, double eps, double h, odesolverstate* state, ae_state *_state); ae_bool odesolveriteration(odesolverstate* state, ae_state *_state); void odesolverresults(odesolverstate* state, ae_int_t* m, /* Real */ ae_vector* xtbl, /* Real */ ae_matrix* ytbl, odesolverreport* rep, ae_state *_state); void _odesolverstate_init(void* _p, ae_state *_state); void _odesolverstate_init_copy(void* _dst, void* _src, ae_state *_state); void _odesolverstate_clear(void* _p); void _odesolverstate_destroy(void* _p); void _odesolverreport_init(void* _p, ae_state *_state); void _odesolverreport_init_copy(void* _dst, void* _src, ae_state *_state); void _odesolverreport_clear(void* _p); void _odesolverreport_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/integration.cpp000755 001750 000144 00000413073 13015033052 023545 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "integration.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Computation of nodes and weights for a Gauss quadrature formula The algorithm generates the N-point Gauss quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-1], alpha coefficients Beta array[0..N-1], beta coefficients Zero-indexed element is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the quadrature formula, N>=1 OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgeneraterec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Computation of nodes and weights for a Gauss-Lobatto quadrature formula The algorithm generates the N-point Gauss-Lobatto quadrature formula with weight function given by coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients Beta array[0..N-2], beta coefficients. Zero-indexed element is not used, may be arbitrary. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. B right boundary of the integration interval. N number of nodes of the quadrature formula, N>=3 (including the left and right boundary nodes). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategausslobattorec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, a, b, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Computation of nodes and weights for a Gauss-Radau quadrature formula The algorithm generates the N-point Gauss-Radau quadrature formula with weight function given by the coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients. Beta array[0..N-1], beta coefficients Zero-indexed element is not used. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. N number of nodes of the quadrature formula, N>=2 (including the left boundary node). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategaussradaurec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, a, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N nodes. INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategausslegendre(n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha/Beta was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategaussjacobi(n, alpha, beta, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with weight function W(x)=Power(x,Alpha)*Exp(-x) INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha is too close to -1 to obtain weights/nodes with high enough accuracy or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategausslaguerre(n, alpha, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with weight function W(x)=Exp(-x*x) INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. May be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gqgenerategausshermite(n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Computation of nodes and weights of a Gauss-Kronrod quadrature formula The algorithm generates the N-point Gauss-Kronrod quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zero moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha alpha coefficients, array[0..floor(3*K/2)]. Beta beta coefficients, array[0..ceil(3*K/2)]. Beta[0] is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the Gauss-Kronrod quadrature formula, N >= 3, N = 2*K+1. OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 N is too large, task may be ill conditioned - x[i]=x[i+1] found. * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 08.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gkqgeneraterec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre quadrature with N points. GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is used depending on machine precision and number of nodes. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gkqgenerategausslegendre(n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK * +2 OK, but quadrature rule have exterior nodes, x[0]<-1 or x[n-1]>+1 X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gkqgenerategaussjacobi(n, alpha, beta, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. Reduction to tridiagonal eigenproblem is used. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gkqlegendrecalc(n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using pre-calculated table. Nodes/weights were computed with accuracy up to 1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision accuracy reduces to something about 2.0E-16 (depending on your compiler's handling of long floating point constants). INPUT PARAMETERS: N - number of Kronrod nodes. N can be 15, 21, 31, 41, 51, 61. OUTPUT PARAMETERS: X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::gkqlegendretbl(n, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &eps, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Integration report: * TerminationType = completetion code: * -5 non-convergence of Gauss-Kronrod nodes calculation subroutine. * -1 incorrect parameters were specified * 1 OK * Rep.NFEV countains number of function calculations * Rep.NIntervals contains number of intervals [a,b] was partitioned into. *************************************************************************/ _autogkreport_owner::_autogkreport_owner() { p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_autogkreport_init(p_struct, NULL); } _autogkreport_owner::_autogkreport_owner(const _autogkreport_owner &rhs) { p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _autogkreport_owner& _autogkreport_owner::operator=(const _autogkreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_autogkreport_clear(p_struct); alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _autogkreport_owner::~_autogkreport_owner() { alglib_impl::_autogkreport_clear(p_struct); ae_free(p_struct); } alglib_impl::autogkreport* _autogkreport_owner::c_ptr() { return p_struct; } alglib_impl::autogkreport* _autogkreport_owner::c_ptr() const { return const_cast(p_struct); } autogkreport::autogkreport() : _autogkreport_owner() ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) { } autogkreport::autogkreport(const autogkreport &rhs):_autogkreport_owner(rhs) ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) { } autogkreport& autogkreport::operator=(const autogkreport &rhs) { if( this==&rhs ) return *this; _autogkreport_owner::operator=(rhs); return *this; } autogkreport::~autogkreport() { } /************************************************************************* This structure stores state of the integration algorithm. Although this class has public fields, they are not intended for external use. You should use ALGLIB functions to work with this class: * autogksmooth()/AutoGKSmoothW()/... to create objects * autogkintegrate() to begin integration * autogkresults() to get results *************************************************************************/ _autogkstate_owner::_autogkstate_owner() { p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_autogkstate_init(p_struct, NULL); } _autogkstate_owner::_autogkstate_owner(const _autogkstate_owner &rhs) { p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _autogkstate_owner& _autogkstate_owner::operator=(const _autogkstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_autogkstate_clear(p_struct); alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _autogkstate_owner::~_autogkstate_owner() { alglib_impl::_autogkstate_clear(p_struct); ae_free(p_struct); } alglib_impl::autogkstate* _autogkstate_owner::c_ptr() { return p_struct; } alglib_impl::autogkstate* _autogkstate_owner::c_ptr() const { return const_cast(p_struct); } autogkstate::autogkstate() : _autogkstate_owner() ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) { } autogkstate::autogkstate(const autogkstate &rhs):_autogkstate_owner(rhs) ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) { } autogkstate& autogkstate::operator=(const autogkstate &rhs) { if( this==&rhs ) return *this; _autogkstate_owner::operator=(rhs); return *this; } autogkstate::~autogkstate() { } /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. Algorithm works well only with smooth integrands. It may be used with continuous non-smooth integrands, but with less performance. It should never be used with integrands which have integrable singularities at lower or upper limits - algorithm may crash. Use AutoGKSingular in such cases. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmooth(const double a, const double b, autogkstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::autogksmooth(a, b, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. This subroutine is same as AutoGKSmooth(), but it guarantees that interval [a,b] is partitioned into subintervals which have width at most XWidth. Subroutine can be used when integrating nearly-constant function with narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth subroutine can overlook them. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::autogksmoothw(a, b, xwidth, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Integration on a finite interval [A,B]. Integrand have integrable singularities at A/B. F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates from below can be used (but these estimates should be greater than -1 too). One of alpha/beta variables (or even both alpha/beta) may be equal to 0, which means than function F(x) is non-singular at A/B. Anyway (singular at bounds or not), function F(x) is supposed to be continuous on (A,B). Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. INPUT PARAMETERS: A, B - interval boundaries (AB) Alpha - power-law coefficient of the F(x) at A, Alpha>-1 Beta - power-law coefficient of the F(x) at B, Beta>-1 OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSmoothW, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::autogksingular(a, b, alpha, beta, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool autogkiteration(const autogkstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::autogkiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void autogkintegrate(autogkstate &state, void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), void *ptr){ alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'autogkintegrate()' (func is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::autogkiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.xminusa, state.bminusx, state.f, ptr); continue; } throw ap_error("ALGLIB: unexpected error in 'autogkintegrate()'"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Adaptive integration results Called after AutoGKIteration returned False. Input parameters: State - algorithm state (used by AutoGKIteration). Output parameters: V - integral(f(x)dx,a,b) Rep - optimization report (see AutoGKReport description) -- ALGLIB -- Copyright 14.11.2007 by Bochkanov Sergey *************************************************************************/ void autogkresults(const autogkstate &state, double &v, autogkreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::autogkresults(const_cast(state.c_ptr()), &v, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static ae_int_t autogk_maxsubintervals = 10000; static void autogk_autogkinternalprepare(double a, double b, double eps, double xwidth, autogkinternalstate* state, ae_state *_state); static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, ae_state *_state); static void autogk_mheappop(/* Real */ ae_matrix* heap, ae_int_t heapsize, ae_int_t heapwidth, ae_state *_state); static void autogk_mheappush(/* Real */ ae_matrix* heap, ae_int_t heapsize, ae_int_t heapwidth, ae_state *_state); static void autogk_mheapresize(/* Real */ ae_matrix* heap, ae_int_t* heapsize, ae_int_t newheapsize, ae_int_t heapwidth, ae_state *_state); /************************************************************************* Computation of nodes and weights for a Gauss quadrature formula The algorithm generates the N-point Gauss quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-1], alpha coefficients Beta array[0..N-1], beta coefficients Zero-indexed element is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the quadrature formula, N>=1 OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgeneraterec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector d; ae_vector e; ae_matrix z; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); if( n<1 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Initialize */ ae_vector_set_length(&d, n, _state); ae_vector_set_length(&e, n, _state); for(i=1; i<=n-1; i++) { d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; if( ae_fp_less_eq(beta->ptr.p_double[i],(double)(0)) ) { *info = -2; ae_frame_leave(_state); return; } e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); } d.ptr.p_double[n-1] = alpha->ptr.p_double[n-1]; /* * EVD */ if( !smatrixtdevd(&d, &e, n, 3, &z, _state) ) { *info = -3; ae_frame_leave(_state); return; } /* * Generate */ ae_vector_set_length(x, n, _state); ae_vector_set_length(w, n, _state); for(i=1; i<=n; i++) { x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); } ae_frame_leave(_state); } /************************************************************************* Computation of nodes and weights for a Gauss-Lobatto quadrature formula The algorithm generates the N-point Gauss-Lobatto quadrature formula with weight function given by coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients Beta array[0..N-2], beta coefficients. Zero-indexed element is not used, may be arbitrary. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. B right boundary of the integration interval. N number of nodes of the quadrature formula, N>=3 (including the left and right boundary nodes). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslobattorec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, double a, double b, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector _alpha; ae_vector _beta; ae_int_t i; ae_vector d; ae_vector e; ae_matrix z; double pim1a; double pia; double pim1b; double pib; double t; double a11; double a12; double a21; double a22; double b1; double b2; double alph; double bet; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_alpha, alpha, _state); alpha = &_alpha; ae_vector_init_copy(&_beta, beta, _state); beta = &_beta; *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); if( n<=2 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Initialize, D[1:N+1], E[1:N] */ n = n-2; ae_vector_set_length(&d, n+2, _state); ae_vector_set_length(&e, n+1, _state); for(i=1; i<=n+1; i++) { d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; } for(i=1; i<=n; i++) { if( ae_fp_less_eq(beta->ptr.p_double[i],(double)(0)) ) { *info = -2; ae_frame_leave(_state); return; } e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); } /* * Caclulate Pn(a), Pn+1(a), Pn(b), Pn+1(b) */ beta->ptr.p_double[0] = (double)(0); pim1a = (double)(0); pia = (double)(1); pim1b = (double)(0); pib = (double)(1); for(i=1; i<=n+1; i++) { /* * Pi(a) */ t = (a-alpha->ptr.p_double[i-1])*pia-beta->ptr.p_double[i-1]*pim1a; pim1a = pia; pia = t; /* * Pi(b) */ t = (b-alpha->ptr.p_double[i-1])*pib-beta->ptr.p_double[i-1]*pim1b; pim1b = pib; pib = t; } /* * Calculate alpha'(n+1), beta'(n+1) */ a11 = pia; a12 = pim1a; a21 = pib; a22 = pim1b; b1 = a*pia; b2 = b*pib; if( ae_fp_greater(ae_fabs(a11, _state),ae_fabs(a21, _state)) ) { a22 = a22-a12*a21/a11; b2 = b2-b1*a21/a11; bet = b2/a22; alph = (b1-bet*a12)/a11; } else { a12 = a12-a22*a11/a21; b1 = b1-b2*a11/a21; bet = b1/a12; alph = (b2-bet*a22)/a21; } if( ae_fp_less(bet,(double)(0)) ) { *info = -3; ae_frame_leave(_state); return; } d.ptr.p_double[n+1] = alph; e.ptr.p_double[n] = ae_sqrt(bet, _state); /* * EVD */ if( !smatrixtdevd(&d, &e, n+2, 3, &z, _state) ) { *info = -3; ae_frame_leave(_state); return; } /* * Generate */ ae_vector_set_length(x, n+2, _state); ae_vector_set_length(w, n+2, _state); for(i=1; i<=n+2; i++) { x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); } ae_frame_leave(_state); } /************************************************************************* Computation of nodes and weights for a Gauss-Radau quadrature formula The algorithm generates the N-point Gauss-Radau quadrature formula with weight function given by the coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients. Beta array[0..N-1], beta coefficients Zero-indexed element is not used. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. N number of nodes of the quadrature formula, N>=2 (including the left boundary node). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussradaurec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, double a, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector _alpha; ae_vector _beta; ae_int_t i; ae_vector d; ae_vector e; ae_matrix z; double polim1; double poli; double t; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_alpha, alpha, _state); alpha = &_alpha; ae_vector_init_copy(&_beta, beta, _state); beta = &_beta; *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); if( n<2 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Initialize, D[1:N], E[1:N] */ n = n-1; ae_vector_set_length(&d, n+1, _state); ae_vector_set_length(&e, n, _state); for(i=1; i<=n; i++) { d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; if( ae_fp_less_eq(beta->ptr.p_double[i],(double)(0)) ) { *info = -2; ae_frame_leave(_state); return; } e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); } /* * Caclulate Pn(a), Pn-1(a), and D[N+1] */ beta->ptr.p_double[0] = (double)(0); polim1 = (double)(0); poli = (double)(1); for(i=1; i<=n; i++) { t = (a-alpha->ptr.p_double[i-1])*poli-beta->ptr.p_double[i-1]*polim1; polim1 = poli; poli = t; } d.ptr.p_double[n] = a-beta->ptr.p_double[n]*polim1/poli; /* * EVD */ if( !smatrixtdevd(&d, &e, n+1, 3, &z, _state) ) { *info = -3; ae_frame_leave(_state); return; } /* * Generate */ ae_vector_set_length(x, n+1, _state); ae_vector_set_length(w, n+1, _state); for(i=1; i<=n+1; i++) { x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); } ae_frame_leave(_state); } /************************************************************************* Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N nodes. INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslegendre(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector alpha; ae_vector beta; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&alpha, 0, DT_REAL, _state); ae_vector_init(&beta, 0, DT_REAL, _state); if( n<1 ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&alpha, n, _state); ae_vector_set_length(&beta, n, _state); for(i=0; i<=n-1; i++) { alpha.ptr.p_double[i] = (double)(0); } beta.ptr.p_double[0] = (double)(2); for(i=1; i<=n-1; i++) { beta.ptr.p_double[i] = 1/(4-1/ae_sqr((double)(i), _state)); } gqgeneraterec(&alpha, &beta, beta.ptr.p_double[0], n, info, x, w, _state); /* * test basic properties to detect errors */ if( *info>0 ) { if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) { *info = -4; } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha/Beta was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategaussjacobi(ae_int_t n, double alpha, double beta, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector b; double alpha2; double beta2; double apb; double t; ae_int_t i; double s; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); if( (n<1||ae_fp_less_eq(alpha,(double)(-1)))||ae_fp_less_eq(beta,(double)(-1)) ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&a, n, _state); ae_vector_set_length(&b, n, _state); apb = alpha+beta; a.ptr.p_double[0] = (beta-alpha)/(apb+2); t = (apb+1)*ae_log((double)(2), _state)+lngamma(alpha+1, &s, _state)+lngamma(beta+1, &s, _state)-lngamma(apb+2, &s, _state); if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) { *info = -4; ae_frame_leave(_state); return; } b.ptr.p_double[0] = ae_exp(t, _state); if( n>1 ) { alpha2 = ae_sqr(alpha, _state); beta2 = ae_sqr(beta, _state); a.ptr.p_double[1] = (beta2-alpha2)/((apb+2)*(apb+4)); b.ptr.p_double[1] = 4*(alpha+1)*(beta+1)/((apb+3)*ae_sqr(apb+2, _state)); for(i=2; i<=n-1; i++) { a.ptr.p_double[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i)); b.ptr.p_double[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*ae_sqr(1+0.5*apb/i, _state)); } } gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); /* * test basic properties to detect errors */ if( *info>0 ) { if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) { *info = -4; } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with weight function W(x)=Power(x,Alpha)*Exp(-x) INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha is too close to -1 to obtain weights/nodes with high enough accuracy or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausslaguerre(ae_int_t n, double alpha, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector b; double t; ae_int_t i; double s; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); if( n<1||ae_fp_less_eq(alpha,(double)(-1)) ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&a, n, _state); ae_vector_set_length(&b, n, _state); a.ptr.p_double[0] = alpha+1; t = lngamma(alpha+1, &s, _state); if( ae_fp_greater_eq(t,ae_log(ae_maxrealnumber, _state)) ) { *info = -4; ae_frame_leave(_state); return; } b.ptr.p_double[0] = ae_exp(t, _state); if( n>1 ) { for(i=1; i<=n-1; i++) { a.ptr.p_double[i] = 2*i+alpha+1; b.ptr.p_double[i] = i*(i+alpha); } } gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); /* * test basic properties to detect errors */ if( *info>0 ) { if( ae_fp_less(x->ptr.p_double[0],(double)(0)) ) { *info = -4; } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with weight function W(x)=Exp(-x*x) INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. May be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gqgenerategausshermite(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector b; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(w); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); if( n<1 ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&a, n, _state); ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(0); } b.ptr.p_double[0] = ae_sqrt(4*ae_atan((double)(1), _state), _state); if( n>1 ) { for(i=1; i<=n-1; i++) { b.ptr.p_double[i] = 0.5*i; } } gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); /* * test basic properties to detect errors */ if( *info>0 ) { for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Computation of nodes and weights of a Gauss-Kronrod quadrature formula The algorithm generates the N-point Gauss-Kronrod quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zero moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha alpha coefficients, array[0..floor(3*K/2)]. Beta beta coefficients, array[0..ceil(3*K/2)]. Beta[0] is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the Gauss-Kronrod quadrature formula, N >= 3, N = 2*K+1. OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 N is too large, task may be ill conditioned - x[i]=x[i+1] found. * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 08.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgeneraterec(/* Real */ ae_vector* alpha, /* Real */ ae_vector* beta, double mu0, ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state) { ae_frame _frame_block; ae_vector _alpha; ae_vector _beta; ae_vector ta; ae_int_t i; ae_int_t j; ae_vector t; ae_vector s; ae_int_t wlen; ae_int_t woffs; double u; ae_int_t m; ae_int_t l; ae_int_t k; ae_vector xgtmp; ae_vector wgtmp; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_alpha, alpha, _state); alpha = &_alpha; ae_vector_init_copy(&_beta, beta, _state); beta = &_beta; *info = 0; ae_vector_clear(x); ae_vector_clear(wkronrod); ae_vector_clear(wgauss); ae_vector_init(&ta, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&xgtmp, 0, DT_REAL, _state); ae_vector_init(&wgtmp, 0, DT_REAL, _state); if( n%2!=1||n<3 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=ae_iceil((double)(3*(n/2))/(double)2, _state); i++) { if( ae_fp_less_eq(beta->ptr.p_double[i],(double)(0)) ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * from external conventions about N/Beta/Mu0 to internal */ n = n/2; beta->ptr.p_double[0] = mu0; /* * Calculate Gauss nodes/weights, save them for later processing */ gqgeneraterec(alpha, beta, mu0, n, info, &xgtmp, &wgtmp, _state); if( *info<0 ) { ae_frame_leave(_state); return; } /* * Resize: * * A from 0..floor(3*n/2) to 0..2*n * * B from 0..ceil(3*n/2) to 0..2*n */ ae_vector_set_length(&ta, ae_ifloor((double)(3*n)/(double)2, _state)+1, _state); ae_v_move(&ta.ptr.p_double[0], 1, &alpha->ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); ae_vector_set_length(alpha, 2*n+1, _state); ae_v_move(&alpha->ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); for(i=ae_ifloor((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) { alpha->ptr.p_double[i] = (double)(0); } ae_vector_set_length(&ta, ae_iceil((double)(3*n)/(double)2, _state)+1, _state); ae_v_move(&ta.ptr.p_double[0], 1, &beta->ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); ae_vector_set_length(beta, 2*n+1, _state); ae_v_move(&beta->ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); for(i=ae_iceil((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) { beta->ptr.p_double[i] = (double)(0); } /* * Initialize T, S */ wlen = 2+n/2; ae_vector_set_length(&t, wlen, _state); ae_vector_set_length(&s, wlen, _state); ae_vector_set_length(&ta, wlen, _state); woffs = 1; for(i=0; i<=wlen-1; i++) { t.ptr.p_double[i] = (double)(0); s.ptr.p_double[i] = (double)(0); } /* * Algorithm from Dirk P. Laurie, "Calculation of Gauss-Kronrod quadrature rules", 1997. */ t.ptr.p_double[woffs+0] = beta->ptr.p_double[n+1]; for(m=0; m<=n-2; m++) { u = (double)(0); for(k=(m+1)/2; k>=0; k--) { l = m-k; u = u+(alpha->ptr.p_double[k+n+1]-alpha->ptr.p_double[l])*t.ptr.p_double[woffs+k]+beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+k-1]-beta->ptr.p_double[l]*s.ptr.p_double[woffs+k]; s.ptr.p_double[woffs+k] = u; } ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); } for(j=n/2; j>=0; j--) { s.ptr.p_double[woffs+j] = s.ptr.p_double[woffs+j-1]; } for(m=n-1; m<=2*n-3; m++) { u = (double)(0); for(k=m+1-n; k<=(m-1)/2; k++) { l = m-k; j = n-1-l; u = u-(alpha->ptr.p_double[k+n+1]-alpha->ptr.p_double[l])*t.ptr.p_double[woffs+j]-beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j]+beta->ptr.p_double[l]*s.ptr.p_double[woffs+j+1]; s.ptr.p_double[woffs+j] = u; } if( m%2==0 ) { k = m/2; alpha->ptr.p_double[k+n+1] = alpha->ptr.p_double[k]+(s.ptr.p_double[woffs+j]-beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j+1])/t.ptr.p_double[woffs+j+1]; } else { k = (m+1)/2; beta->ptr.p_double[k+n+1] = s.ptr.p_double[woffs+j]/s.ptr.p_double[woffs+j+1]; } ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); } alpha->ptr.p_double[2*n] = alpha->ptr.p_double[n-1]-beta->ptr.p_double[2*n]*s.ptr.p_double[woffs+0]/t.ptr.p_double[woffs+0]; /* * calculation of Kronrod nodes and weights, unpacking of Gauss weights */ gqgeneraterec(alpha, beta, mu0, 2*n+1, info, x, wkronrod, _state); if( *info==-2 ) { *info = -5; } if( *info<0 ) { ae_frame_leave(_state); return; } for(i=0; i<=2*n-1; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } if( *info<0 ) { ae_frame_leave(_state); return; } ae_vector_set_length(wgauss, 2*n+1, _state); for(i=0; i<=2*n; i++) { wgauss->ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { wgauss->ptr.p_double[2*i+1] = wgtmp.ptr.p_double[i]; } ae_frame_leave(_state); } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre quadrature with N points. GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is used depending on machine precision and number of nodes. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategausslegendre(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state) { double eps; *info = 0; ae_vector_clear(x); ae_vector_clear(wkronrod); ae_vector_clear(wgauss); if( ae_fp_greater(ae_machineepsilon,1.0E-32)&&(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61) ) { *info = 1; gkqlegendretbl(n, x, wkronrod, wgauss, &eps, _state); } else { gkqlegendrecalc(n, info, x, wkronrod, wgauss, _state); } } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK * +2 OK, but quadrature rule have exterior nodes, x[0]<-1 or x[n-1]>+1 X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqgenerategaussjacobi(ae_int_t n, double alpha, double beta, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state) { ae_frame _frame_block; ae_int_t clen; ae_vector a; ae_vector b; double alpha2; double beta2; double apb; double t; ae_int_t i; double s; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(wkronrod); ae_vector_clear(wgauss); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); if( n%2!=1||n<3 ) { *info = -1; ae_frame_leave(_state); return; } if( ae_fp_less_eq(alpha,(double)(-1))||ae_fp_less_eq(beta,(double)(-1)) ) { *info = -1; ae_frame_leave(_state); return; } clen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; ae_vector_set_length(&a, clen, _state); ae_vector_set_length(&b, clen, _state); for(i=0; i<=clen-1; i++) { a.ptr.p_double[i] = (double)(0); } apb = alpha+beta; a.ptr.p_double[0] = (beta-alpha)/(apb+2); t = (apb+1)*ae_log((double)(2), _state)+lngamma(alpha+1, &s, _state)+lngamma(beta+1, &s, _state)-lngamma(apb+2, &s, _state); if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) { *info = -4; ae_frame_leave(_state); return; } b.ptr.p_double[0] = ae_exp(t, _state); if( clen>1 ) { alpha2 = ae_sqr(alpha, _state); beta2 = ae_sqr(beta, _state); a.ptr.p_double[1] = (beta2-alpha2)/((apb+2)*(apb+4)); b.ptr.p_double[1] = 4*(alpha+1)*(beta+1)/((apb+3)*ae_sqr(apb+2, _state)); for(i=2; i<=clen-1; i++) { a.ptr.p_double[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i)); b.ptr.p_double[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*ae_sqr(1+0.5*apb/i, _state)); } } gkqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, wkronrod, wgauss, _state); /* * test basic properties to detect errors */ if( *info>0 ) { if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) { *info = 2; } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. Reduction to tridiagonal eigenproblem is used. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendrecalc(ae_int_t n, ae_int_t* info, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, ae_state *_state) { ae_frame _frame_block; ae_vector alpha; ae_vector beta; ae_int_t alen; ae_int_t blen; double mu0; ae_int_t k; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(x); ae_vector_clear(wkronrod); ae_vector_clear(wgauss); ae_vector_init(&alpha, 0, DT_REAL, _state); ae_vector_init(&beta, 0, DT_REAL, _state); if( n%2!=1||n<3 ) { *info = -1; ae_frame_leave(_state); return; } mu0 = (double)(2); alen = ae_ifloor((double)(3*(n/2))/(double)2, _state)+1; blen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; ae_vector_set_length(&alpha, alen, _state); ae_vector_set_length(&beta, blen, _state); for(k=0; k<=alen-1; k++) { alpha.ptr.p_double[k] = (double)(0); } beta.ptr.p_double[0] = (double)(2); for(k=1; k<=blen-1; k++) { beta.ptr.p_double[k] = 1/(4-1/ae_sqr((double)(k), _state)); } gkqgeneraterec(&alpha, &beta, mu0, n, info, x, wkronrod, wgauss, _state); /* * test basic properties to detect errors */ if( *info>0 ) { if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) { *info = -4; } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) { *info = -4; } } } ae_frame_leave(_state); } /************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using pre-calculated table. Nodes/weights were computed with accuracy up to 1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision accuracy reduces to something about 2.0E-16 (depending on your compiler's handling of long floating point constants). INPUT PARAMETERS: N - number of Kronrod nodes. N can be 15, 21, 31, 41, 51, 61. OUTPUT PARAMETERS: X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/ void gkqlegendretbl(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* wkronrod, /* Real */ ae_vector* wgauss, double* eps, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t ng; ae_vector p1; ae_vector p2; double tmp; ae_frame_make(_state, &_frame_block); ae_vector_clear(x); ae_vector_clear(wkronrod); ae_vector_clear(wgauss); *eps = 0; ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ ng = 0; /* * Process */ ae_assert(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61, "GKQNodesTbl: incorrect N!", _state); ae_vector_set_length(x, n, _state); ae_vector_set_length(wkronrod, n, _state); ae_vector_set_length(wgauss, n, _state); for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = (double)(0); wkronrod->ptr.p_double[i] = (double)(0); wgauss->ptr.p_double[i] = (double)(0); } *eps = ae_maxreal(ae_machineepsilon, 1.0E-32, _state); if( n==15 ) { ng = 4; wgauss->ptr.p_double[0] = 0.129484966168869693270611432679082; wgauss->ptr.p_double[1] = 0.279705391489276667901467771423780; wgauss->ptr.p_double[2] = 0.381830050505118944950369775488975; wgauss->ptr.p_double[3] = 0.417959183673469387755102040816327; x->ptr.p_double[0] = 0.991455371120812639206854697526329; x->ptr.p_double[1] = 0.949107912342758524526189684047851; x->ptr.p_double[2] = 0.864864423359769072789712788640926; x->ptr.p_double[3] = 0.741531185599394439863864773280788; x->ptr.p_double[4] = 0.586087235467691130294144838258730; x->ptr.p_double[5] = 0.405845151377397166906606412076961; x->ptr.p_double[6] = 0.207784955007898467600689403773245; x->ptr.p_double[7] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.022935322010529224963732008058970; wkronrod->ptr.p_double[1] = 0.063092092629978553290700663189204; wkronrod->ptr.p_double[2] = 0.104790010322250183839876322541518; wkronrod->ptr.p_double[3] = 0.140653259715525918745189590510238; wkronrod->ptr.p_double[4] = 0.169004726639267902826583426598550; wkronrod->ptr.p_double[5] = 0.190350578064785409913256402421014; wkronrod->ptr.p_double[6] = 0.204432940075298892414161999234649; wkronrod->ptr.p_double[7] = 0.209482141084727828012999174891714; } if( n==21 ) { ng = 5; wgauss->ptr.p_double[0] = 0.066671344308688137593568809893332; wgauss->ptr.p_double[1] = 0.149451349150580593145776339657697; wgauss->ptr.p_double[2] = 0.219086362515982043995534934228163; wgauss->ptr.p_double[3] = 0.269266719309996355091226921569469; wgauss->ptr.p_double[4] = 0.295524224714752870173892994651338; x->ptr.p_double[0] = 0.995657163025808080735527280689003; x->ptr.p_double[1] = 0.973906528517171720077964012084452; x->ptr.p_double[2] = 0.930157491355708226001207180059508; x->ptr.p_double[3] = 0.865063366688984510732096688423493; x->ptr.p_double[4] = 0.780817726586416897063717578345042; x->ptr.p_double[5] = 0.679409568299024406234327365114874; x->ptr.p_double[6] = 0.562757134668604683339000099272694; x->ptr.p_double[7] = 0.433395394129247190799265943165784; x->ptr.p_double[8] = 0.294392862701460198131126603103866; x->ptr.p_double[9] = 0.148874338981631210884826001129720; x->ptr.p_double[10] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.011694638867371874278064396062192; wkronrod->ptr.p_double[1] = 0.032558162307964727478818972459390; wkronrod->ptr.p_double[2] = 0.054755896574351996031381300244580; wkronrod->ptr.p_double[3] = 0.075039674810919952767043140916190; wkronrod->ptr.p_double[4] = 0.093125454583697605535065465083366; wkronrod->ptr.p_double[5] = 0.109387158802297641899210590325805; wkronrod->ptr.p_double[6] = 0.123491976262065851077958109831074; wkronrod->ptr.p_double[7] = 0.134709217311473325928054001771707; wkronrod->ptr.p_double[8] = 0.142775938577060080797094273138717; wkronrod->ptr.p_double[9] = 0.147739104901338491374841515972068; wkronrod->ptr.p_double[10] = 0.149445554002916905664936468389821; } if( n==31 ) { ng = 8; wgauss->ptr.p_double[0] = 0.030753241996117268354628393577204; wgauss->ptr.p_double[1] = 0.070366047488108124709267416450667; wgauss->ptr.p_double[2] = 0.107159220467171935011869546685869; wgauss->ptr.p_double[3] = 0.139570677926154314447804794511028; wgauss->ptr.p_double[4] = 0.166269205816993933553200860481209; wgauss->ptr.p_double[5] = 0.186161000015562211026800561866423; wgauss->ptr.p_double[6] = 0.198431485327111576456118326443839; wgauss->ptr.p_double[7] = 0.202578241925561272880620199967519; x->ptr.p_double[0] = 0.998002298693397060285172840152271; x->ptr.p_double[1] = 0.987992518020485428489565718586613; x->ptr.p_double[2] = 0.967739075679139134257347978784337; x->ptr.p_double[3] = 0.937273392400705904307758947710209; x->ptr.p_double[4] = 0.897264532344081900882509656454496; x->ptr.p_double[5] = 0.848206583410427216200648320774217; x->ptr.p_double[6] = 0.790418501442465932967649294817947; x->ptr.p_double[7] = 0.724417731360170047416186054613938; x->ptr.p_double[8] = 0.650996741297416970533735895313275; x->ptr.p_double[9] = 0.570972172608538847537226737253911; x->ptr.p_double[10] = 0.485081863640239680693655740232351; x->ptr.p_double[11] = 0.394151347077563369897207370981045; x->ptr.p_double[12] = 0.299180007153168812166780024266389; x->ptr.p_double[13] = 0.201194093997434522300628303394596; x->ptr.p_double[14] = 0.101142066918717499027074231447392; x->ptr.p_double[15] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.005377479872923348987792051430128; wkronrod->ptr.p_double[1] = 0.015007947329316122538374763075807; wkronrod->ptr.p_double[2] = 0.025460847326715320186874001019653; wkronrod->ptr.p_double[3] = 0.035346360791375846222037948478360; wkronrod->ptr.p_double[4] = 0.044589751324764876608227299373280; wkronrod->ptr.p_double[5] = 0.053481524690928087265343147239430; wkronrod->ptr.p_double[6] = 0.062009567800670640285139230960803; wkronrod->ptr.p_double[7] = 0.069854121318728258709520077099147; wkronrod->ptr.p_double[8] = 0.076849680757720378894432777482659; wkronrod->ptr.p_double[9] = 0.083080502823133021038289247286104; wkronrod->ptr.p_double[10] = 0.088564443056211770647275443693774; wkronrod->ptr.p_double[11] = 0.093126598170825321225486872747346; wkronrod->ptr.p_double[12] = 0.096642726983623678505179907627589; wkronrod->ptr.p_double[13] = 0.099173598721791959332393173484603; wkronrod->ptr.p_double[14] = 0.100769845523875595044946662617570; wkronrod->ptr.p_double[15] = 0.101330007014791549017374792767493; } if( n==41 ) { ng = 10; wgauss->ptr.p_double[0] = 0.017614007139152118311861962351853; wgauss->ptr.p_double[1] = 0.040601429800386941331039952274932; wgauss->ptr.p_double[2] = 0.062672048334109063569506535187042; wgauss->ptr.p_double[3] = 0.083276741576704748724758143222046; wgauss->ptr.p_double[4] = 0.101930119817240435036750135480350; wgauss->ptr.p_double[5] = 0.118194531961518417312377377711382; wgauss->ptr.p_double[6] = 0.131688638449176626898494499748163; wgauss->ptr.p_double[7] = 0.142096109318382051329298325067165; wgauss->ptr.p_double[8] = 0.149172986472603746787828737001969; wgauss->ptr.p_double[9] = 0.152753387130725850698084331955098; x->ptr.p_double[0] = 0.998859031588277663838315576545863; x->ptr.p_double[1] = 0.993128599185094924786122388471320; x->ptr.p_double[2] = 0.981507877450250259193342994720217; x->ptr.p_double[3] = 0.963971927277913791267666131197277; x->ptr.p_double[4] = 0.940822633831754753519982722212443; x->ptr.p_double[5] = 0.912234428251325905867752441203298; x->ptr.p_double[6] = 0.878276811252281976077442995113078; x->ptr.p_double[7] = 0.839116971822218823394529061701521; x->ptr.p_double[8] = 0.795041428837551198350638833272788; x->ptr.p_double[9] = 0.746331906460150792614305070355642; x->ptr.p_double[10] = 0.693237656334751384805490711845932; x->ptr.p_double[11] = 0.636053680726515025452836696226286; x->ptr.p_double[12] = 0.575140446819710315342946036586425; x->ptr.p_double[13] = 0.510867001950827098004364050955251; x->ptr.p_double[14] = 0.443593175238725103199992213492640; x->ptr.p_double[15] = 0.373706088715419560672548177024927; x->ptr.p_double[16] = 0.301627868114913004320555356858592; x->ptr.p_double[17] = 0.227785851141645078080496195368575; x->ptr.p_double[18] = 0.152605465240922675505220241022678; x->ptr.p_double[19] = 0.076526521133497333754640409398838; x->ptr.p_double[20] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.003073583718520531501218293246031; wkronrod->ptr.p_double[1] = 0.008600269855642942198661787950102; wkronrod->ptr.p_double[2] = 0.014626169256971252983787960308868; wkronrod->ptr.p_double[3] = 0.020388373461266523598010231432755; wkronrod->ptr.p_double[4] = 0.025882133604951158834505067096153; wkronrod->ptr.p_double[5] = 0.031287306777032798958543119323801; wkronrod->ptr.p_double[6] = 0.036600169758200798030557240707211; wkronrod->ptr.p_double[7] = 0.041668873327973686263788305936895; wkronrod->ptr.p_double[8] = 0.046434821867497674720231880926108; wkronrod->ptr.p_double[9] = 0.050944573923728691932707670050345; wkronrod->ptr.p_double[10] = 0.055195105348285994744832372419777; wkronrod->ptr.p_double[11] = 0.059111400880639572374967220648594; wkronrod->ptr.p_double[12] = 0.062653237554781168025870122174255; wkronrod->ptr.p_double[13] = 0.065834597133618422111563556969398; wkronrod->ptr.p_double[14] = 0.068648672928521619345623411885368; wkronrod->ptr.p_double[15] = 0.071054423553444068305790361723210; wkronrod->ptr.p_double[16] = 0.073030690332786667495189417658913; wkronrod->ptr.p_double[17] = 0.074582875400499188986581418362488; wkronrod->ptr.p_double[18] = 0.075704497684556674659542775376617; wkronrod->ptr.p_double[19] = 0.076377867672080736705502835038061; wkronrod->ptr.p_double[20] = 0.076600711917999656445049901530102; } if( n==51 ) { ng = 13; wgauss->ptr.p_double[0] = 0.011393798501026287947902964113235; wgauss->ptr.p_double[1] = 0.026354986615032137261901815295299; wgauss->ptr.p_double[2] = 0.040939156701306312655623487711646; wgauss->ptr.p_double[3] = 0.054904695975835191925936891540473; wgauss->ptr.p_double[4] = 0.068038333812356917207187185656708; wgauss->ptr.p_double[5] = 0.080140700335001018013234959669111; wgauss->ptr.p_double[6] = 0.091028261982963649811497220702892; wgauss->ptr.p_double[7] = 0.100535949067050644202206890392686; wgauss->ptr.p_double[8] = 0.108519624474263653116093957050117; wgauss->ptr.p_double[9] = 0.114858259145711648339325545869556; wgauss->ptr.p_double[10] = 0.119455763535784772228178126512901; wgauss->ptr.p_double[11] = 0.122242442990310041688959518945852; wgauss->ptr.p_double[12] = 0.123176053726715451203902873079050; x->ptr.p_double[0] = 0.999262104992609834193457486540341; x->ptr.p_double[1] = 0.995556969790498097908784946893902; x->ptr.p_double[2] = 0.988035794534077247637331014577406; x->ptr.p_double[3] = 0.976663921459517511498315386479594; x->ptr.p_double[4] = 0.961614986425842512418130033660167; x->ptr.p_double[5] = 0.942974571228974339414011169658471; x->ptr.p_double[6] = 0.920747115281701561746346084546331; x->ptr.p_double[7] = 0.894991997878275368851042006782805; x->ptr.p_double[8] = 0.865847065293275595448996969588340; x->ptr.p_double[9] = 0.833442628760834001421021108693570; x->ptr.p_double[10] = 0.797873797998500059410410904994307; x->ptr.p_double[11] = 0.759259263037357630577282865204361; x->ptr.p_double[12] = 0.717766406813084388186654079773298; x->ptr.p_double[13] = 0.673566368473468364485120633247622; x->ptr.p_double[14] = 0.626810099010317412788122681624518; x->ptr.p_double[15] = 0.577662930241222967723689841612654; x->ptr.p_double[16] = 0.526325284334719182599623778158010; x->ptr.p_double[17] = 0.473002731445714960522182115009192; x->ptr.p_double[18] = 0.417885382193037748851814394594572; x->ptr.p_double[19] = 0.361172305809387837735821730127641; x->ptr.p_double[20] = 0.303089538931107830167478909980339; x->ptr.p_double[21] = 0.243866883720988432045190362797452; x->ptr.p_double[22] = 0.183718939421048892015969888759528; x->ptr.p_double[23] = 0.122864692610710396387359818808037; x->ptr.p_double[24] = 0.061544483005685078886546392366797; x->ptr.p_double[25] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.001987383892330315926507851882843; wkronrod->ptr.p_double[1] = 0.005561932135356713758040236901066; wkronrod->ptr.p_double[2] = 0.009473973386174151607207710523655; wkronrod->ptr.p_double[3] = 0.013236229195571674813656405846976; wkronrod->ptr.p_double[4] = 0.016847817709128298231516667536336; wkronrod->ptr.p_double[5] = 0.020435371145882835456568292235939; wkronrod->ptr.p_double[6] = 0.024009945606953216220092489164881; wkronrod->ptr.p_double[7] = 0.027475317587851737802948455517811; wkronrod->ptr.p_double[8] = 0.030792300167387488891109020215229; wkronrod->ptr.p_double[9] = 0.034002130274329337836748795229551; wkronrod->ptr.p_double[10] = 0.037116271483415543560330625367620; wkronrod->ptr.p_double[11] = 0.040083825504032382074839284467076; wkronrod->ptr.p_double[12] = 0.042872845020170049476895792439495; wkronrod->ptr.p_double[13] = 0.045502913049921788909870584752660; wkronrod->ptr.p_double[14] = 0.047982537138836713906392255756915; wkronrod->ptr.p_double[15] = 0.050277679080715671963325259433440; wkronrod->ptr.p_double[16] = 0.052362885806407475864366712137873; wkronrod->ptr.p_double[17] = 0.054251129888545490144543370459876; wkronrod->ptr.p_double[18] = 0.055950811220412317308240686382747; wkronrod->ptr.p_double[19] = 0.057437116361567832853582693939506; wkronrod->ptr.p_double[20] = 0.058689680022394207961974175856788; wkronrod->ptr.p_double[21] = 0.059720340324174059979099291932562; wkronrod->ptr.p_double[22] = 0.060539455376045862945360267517565; wkronrod->ptr.p_double[23] = 0.061128509717053048305859030416293; wkronrod->ptr.p_double[24] = 0.061471189871425316661544131965264; wkronrod->ptr.p_double[25] = 0.061580818067832935078759824240055; } if( n==61 ) { ng = 15; wgauss->ptr.p_double[0] = 0.007968192496166605615465883474674; wgauss->ptr.p_double[1] = 0.018466468311090959142302131912047; wgauss->ptr.p_double[2] = 0.028784707883323369349719179611292; wgauss->ptr.p_double[3] = 0.038799192569627049596801936446348; wgauss->ptr.p_double[4] = 0.048402672830594052902938140422808; wgauss->ptr.p_double[5] = 0.057493156217619066481721689402056; wgauss->ptr.p_double[6] = 0.065974229882180495128128515115962; wgauss->ptr.p_double[7] = 0.073755974737705206268243850022191; wgauss->ptr.p_double[8] = 0.080755895229420215354694938460530; wgauss->ptr.p_double[9] = 0.086899787201082979802387530715126; wgauss->ptr.p_double[10] = 0.092122522237786128717632707087619; wgauss->ptr.p_double[11] = 0.096368737174644259639468626351810; wgauss->ptr.p_double[12] = 0.099593420586795267062780282103569; wgauss->ptr.p_double[13] = 0.101762389748405504596428952168554; wgauss->ptr.p_double[14] = 0.102852652893558840341285636705415; x->ptr.p_double[0] = 0.999484410050490637571325895705811; x->ptr.p_double[1] = 0.996893484074649540271630050918695; x->ptr.p_double[2] = 0.991630996870404594858628366109486; x->ptr.p_double[3] = 0.983668123279747209970032581605663; x->ptr.p_double[4] = 0.973116322501126268374693868423707; x->ptr.p_double[5] = 0.960021864968307512216871025581798; x->ptr.p_double[6] = 0.944374444748559979415831324037439; x->ptr.p_double[7] = 0.926200047429274325879324277080474; x->ptr.p_double[8] = 0.905573307699907798546522558925958; x->ptr.p_double[9] = 0.882560535792052681543116462530226; x->ptr.p_double[10] = 0.857205233546061098958658510658944; x->ptr.p_double[11] = 0.829565762382768397442898119732502; x->ptr.p_double[12] = 0.799727835821839083013668942322683; x->ptr.p_double[13] = 0.767777432104826194917977340974503; x->ptr.p_double[14] = 0.733790062453226804726171131369528; x->ptr.p_double[15] = 0.697850494793315796932292388026640; x->ptr.p_double[16] = 0.660061064126626961370053668149271; x->ptr.p_double[17] = 0.620526182989242861140477556431189; x->ptr.p_double[18] = 0.579345235826361691756024932172540; x->ptr.p_double[19] = 0.536624148142019899264169793311073; x->ptr.p_double[20] = 0.492480467861778574993693061207709; x->ptr.p_double[21] = 0.447033769538089176780609900322854; x->ptr.p_double[22] = 0.400401254830394392535476211542661; x->ptr.p_double[23] = 0.352704725530878113471037207089374; x->ptr.p_double[24] = 0.304073202273625077372677107199257; x->ptr.p_double[25] = 0.254636926167889846439805129817805; x->ptr.p_double[26] = 0.204525116682309891438957671002025; x->ptr.p_double[27] = 0.153869913608583546963794672743256; x->ptr.p_double[28] = 0.102806937966737030147096751318001; x->ptr.p_double[29] = 0.051471842555317695833025213166723; x->ptr.p_double[30] = 0.000000000000000000000000000000000; wkronrod->ptr.p_double[0] = 0.001389013698677007624551591226760; wkronrod->ptr.p_double[1] = 0.003890461127099884051267201844516; wkronrod->ptr.p_double[2] = 0.006630703915931292173319826369750; wkronrod->ptr.p_double[3] = 0.009273279659517763428441146892024; wkronrod->ptr.p_double[4] = 0.011823015253496341742232898853251; wkronrod->ptr.p_double[5] = 0.014369729507045804812451432443580; wkronrod->ptr.p_double[6] = 0.016920889189053272627572289420322; wkronrod->ptr.p_double[7] = 0.019414141193942381173408951050128; wkronrod->ptr.p_double[8] = 0.021828035821609192297167485738339; wkronrod->ptr.p_double[9] = 0.024191162078080601365686370725232; wkronrod->ptr.p_double[10] = 0.026509954882333101610601709335075; wkronrod->ptr.p_double[11] = 0.028754048765041292843978785354334; wkronrod->ptr.p_double[12] = 0.030907257562387762472884252943092; wkronrod->ptr.p_double[13] = 0.032981447057483726031814191016854; wkronrod->ptr.p_double[14] = 0.034979338028060024137499670731468; wkronrod->ptr.p_double[15] = 0.036882364651821229223911065617136; wkronrod->ptr.p_double[16] = 0.038678945624727592950348651532281; wkronrod->ptr.p_double[17] = 0.040374538951535959111995279752468; wkronrod->ptr.p_double[18] = 0.041969810215164246147147541285970; wkronrod->ptr.p_double[19] = 0.043452539701356069316831728117073; wkronrod->ptr.p_double[20] = 0.044814800133162663192355551616723; wkronrod->ptr.p_double[21] = 0.046059238271006988116271735559374; wkronrod->ptr.p_double[22] = 0.047185546569299153945261478181099; wkronrod->ptr.p_double[23] = 0.048185861757087129140779492298305; wkronrod->ptr.p_double[24] = 0.049055434555029778887528165367238; wkronrod->ptr.p_double[25] = 0.049795683427074206357811569379942; wkronrod->ptr.p_double[26] = 0.050405921402782346840893085653585; wkronrod->ptr.p_double[27] = 0.050881795898749606492297473049805; wkronrod->ptr.p_double[28] = 0.051221547849258772170656282604944; wkronrod->ptr.p_double[29] = 0.051426128537459025933862879215781; wkronrod->ptr.p_double[30] = 0.051494729429451567558340433647099; } /* * copy nodes */ for(i=n-1; i>=n/2; i--) { x->ptr.p_double[i] = -x->ptr.p_double[n-1-i]; } /* * copy Kronrod weights */ for(i=n-1; i>=n/2; i--) { wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[n-1-i]; } /* * copy Gauss weights */ for(i=ng-1; i>=0; i--) { wgauss->ptr.p_double[n-2-2*i] = wgauss->ptr.p_double[i]; wgauss->ptr.p_double[1+2*i] = wgauss->ptr.p_double[i]; } for(i=0; i<=n/2; i++) { wgauss->ptr.p_double[2*i] = (double)(0); } /* * reorder */ tagsort(x, n, &p1, &p2, _state); for(i=0; i<=n-1; i++) { tmp = wkronrod->ptr.p_double[i]; wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[p2.ptr.p_int[i]]; wkronrod->ptr.p_double[p2.ptr.p_int[i]] = tmp; tmp = wgauss->ptr.p_double[i]; wgauss->ptr.p_double[i] = wgauss->ptr.p_double[p2.ptr.p_int[i]]; wgauss->ptr.p_double[p2.ptr.p_int[i]] = tmp; } ae_frame_leave(_state); } /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. Algorithm works well only with smooth integrands. It may be used with continuous non-smooth integrands, but with less performance. It should never be used with integrands which have integrable singularities at lower or upper limits - algorithm may crash. Use AutoGKSingular in such cases. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmooth(double a, double b, autogkstate* state, ae_state *_state) { _autogkstate_clear(state); ae_assert(ae_isfinite(a, _state), "AutoGKSmooth: A is not finite!", _state); ae_assert(ae_isfinite(b, _state), "AutoGKSmooth: B is not finite!", _state); autogksmoothw(a, b, 0.0, state, _state); } /************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. This subroutine is same as AutoGKSmooth(), but it guarantees that interval [a,b] is partitioned into subintervals which have width at most XWidth. Subroutine can be used when integrating nearly-constant function with narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth subroutine can overlook them. INPUT PARAMETERS: A, B - interval boundaries (AB) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksmoothw(double a, double b, double xwidth, autogkstate* state, ae_state *_state) { _autogkstate_clear(state); ae_assert(ae_isfinite(a, _state), "AutoGKSmoothW: A is not finite!", _state); ae_assert(ae_isfinite(b, _state), "AutoGKSmoothW: B is not finite!", _state); ae_assert(ae_isfinite(xwidth, _state), "AutoGKSmoothW: XWidth is not finite!", _state); state->wrappermode = 0; state->a = a; state->b = b; state->xwidth = xwidth; state->needf = ae_false; ae_vector_set_length(&state->rstate.ra, 10+1, _state); state->rstate.stage = -1; } /************************************************************************* Integration on a finite interval [A,B]. Integrand have integrable singularities at A/B. F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates from below can be used (but these estimates should be greater than -1 too). One of alpha/beta variables (or even both alpha/beta) may be equal to 0, which means than function F(x) is non-singular at A/B. Anyway (singular at bounds or not), function F(x) is supposed to be continuous on (A,B). Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. INPUT PARAMETERS: A, B - interval boundaries (AB) Alpha - power-law coefficient of the F(x) at A, Alpha>-1 Beta - power-law coefficient of the F(x) at B, Beta>-1 OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSmoothW, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/ void autogksingular(double a, double b, double alpha, double beta, autogkstate* state, ae_state *_state) { _autogkstate_clear(state); ae_assert(ae_isfinite(a, _state), "AutoGKSingular: A is not finite!", _state); ae_assert(ae_isfinite(b, _state), "AutoGKSingular: B is not finite!", _state); ae_assert(ae_isfinite(alpha, _state), "AutoGKSingular: Alpha is not finite!", _state); ae_assert(ae_isfinite(beta, _state), "AutoGKSingular: Beta is not finite!", _state); state->wrappermode = 1; state->a = a; state->b = b; state->alpha = alpha; state->beta = beta; state->xwidth = 0.0; state->needf = ae_false; ae_vector_set_length(&state->rstate.ra, 10+1, _state); state->rstate.stage = -1; } /************************************************************************* -- ALGLIB -- Copyright 07.05.2009 by Bochkanov Sergey *************************************************************************/ ae_bool autogkiteration(autogkstate* state, ae_state *_state) { double s; double tmp; double eps; double a; double b; double x; double t; double alpha; double beta; double v1; double v2; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { s = state->rstate.ra.ptr.p_double[0]; tmp = state->rstate.ra.ptr.p_double[1]; eps = state->rstate.ra.ptr.p_double[2]; a = state->rstate.ra.ptr.p_double[3]; b = state->rstate.ra.ptr.p_double[4]; x = state->rstate.ra.ptr.p_double[5]; t = state->rstate.ra.ptr.p_double[6]; alpha = state->rstate.ra.ptr.p_double[7]; beta = state->rstate.ra.ptr.p_double[8]; v1 = state->rstate.ra.ptr.p_double[9]; v2 = state->rstate.ra.ptr.p_double[10]; } else { s = -983; tmp = -989; eps = -834; a = 900; b = -287; x = 364; t = 214; alpha = -338; beta = -686; v1 = 912; v2 = 585; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } /* * Routine body */ eps = (double)(0); a = state->a; b = state->b; alpha = state->alpha; beta = state->beta; state->terminationtype = -1; state->nfev = 0; state->nintervals = 0; /* * smooth function at a finite interval */ if( state->wrappermode!=0 ) { goto lbl_3; } /* * special case */ if( ae_fp_eq(a,b) ) { state->terminationtype = 1; state->v = (double)(0); result = ae_false; return result; } /* * general case */ autogk_autogkinternalprepare(a, b, eps, state->xwidth, &state->internalstate, _state); lbl_5: if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) { goto lbl_6; } x = state->internalstate.x; state->x = x; state->xminusa = x-a; state->bminusx = b-x; state->needf = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needf = ae_false; state->nfev = state->nfev+1; state->internalstate.f = state->f; goto lbl_5; lbl_6: state->v = state->internalstate.r; state->terminationtype = state->internalstate.info; state->nintervals = state->internalstate.heapused; result = ae_false; return result; lbl_3: /* * function with power-law singularities at the ends of a finite interval */ if( state->wrappermode!=1 ) { goto lbl_7; } /* * test coefficients */ if( ae_fp_less_eq(alpha,(double)(-1))||ae_fp_less_eq(beta,(double)(-1)) ) { state->terminationtype = -1; state->v = (double)(0); result = ae_false; return result; } /* * special cases */ if( ae_fp_eq(a,b) ) { state->terminationtype = 1; state->v = (double)(0); result = ae_false; return result; } /* * reduction to general form */ if( ae_fp_less(a,b) ) { s = (double)(1); } else { s = (double)(-1); tmp = a; a = b; b = tmp; tmp = alpha; alpha = beta; beta = tmp; } alpha = ae_minreal(alpha, (double)(0), _state); beta = ae_minreal(beta, (double)(0), _state); /* * first, integrate left half of [a,b]: * integral(f(x)dx, a, (b+a)/2) = * = 1/(1+alpha) * integral(t^(-alpha/(1+alpha))*f(a+t^(1/(1+alpha)))dt, 0, (0.5*(b-a))^(1+alpha)) */ autogk_autogkinternalprepare((double)(0), ae_pow(0.5*(b-a), 1+alpha, _state), eps, state->xwidth, &state->internalstate, _state); lbl_9: if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) { goto lbl_10; } /* * Fill State.X, State.XMinusA, State.BMinusX. * Latter two are filled correctly even if Binternalstate.x; t = ae_pow(x, 1/(1+alpha), _state); state->x = a+t; if( ae_fp_greater(s,(double)(0)) ) { state->xminusa = t; state->bminusx = b-(a+t); } else { state->xminusa = a+t-b; state->bminusx = -t; } state->needf = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->needf = ae_false; if( ae_fp_neq(alpha,(double)(0)) ) { state->internalstate.f = state->f*ae_pow(x, -alpha/(1+alpha), _state)/(1+alpha); } else { state->internalstate.f = state->f; } state->nfev = state->nfev+1; goto lbl_9; lbl_10: v1 = state->internalstate.r; state->nintervals = state->nintervals+state->internalstate.heapused; /* * then, integrate right half of [a,b]: * integral(f(x)dx, (b+a)/2, b) = * = 1/(1+beta) * integral(t^(-beta/(1+beta))*f(b-t^(1/(1+beta)))dt, 0, (0.5*(b-a))^(1+beta)) */ autogk_autogkinternalprepare((double)(0), ae_pow(0.5*(b-a), 1+beta, _state), eps, state->xwidth, &state->internalstate, _state); lbl_11: if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) { goto lbl_12; } /* * Fill State.X, State.XMinusA, State.BMinusX. * Latter two are filled correctly (X-A, B-X) even if Binternalstate.x; t = ae_pow(x, 1/(1+beta), _state); state->x = b-t; if( ae_fp_greater(s,(double)(0)) ) { state->xminusa = b-t-a; state->bminusx = t; } else { state->xminusa = -t; state->bminusx = a-(b-t); } state->needf = ae_true; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->needf = ae_false; if( ae_fp_neq(beta,(double)(0)) ) { state->internalstate.f = state->f*ae_pow(x, -beta/(1+beta), _state)/(1+beta); } else { state->internalstate.f = state->f; } state->nfev = state->nfev+1; goto lbl_11; lbl_12: v2 = state->internalstate.r; state->nintervals = state->nintervals+state->internalstate.heapused; /* * final result */ state->v = s*(v1+v2); state->terminationtype = 1; result = ae_false; return result; lbl_7: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ra.ptr.p_double[0] = s; state->rstate.ra.ptr.p_double[1] = tmp; state->rstate.ra.ptr.p_double[2] = eps; state->rstate.ra.ptr.p_double[3] = a; state->rstate.ra.ptr.p_double[4] = b; state->rstate.ra.ptr.p_double[5] = x; state->rstate.ra.ptr.p_double[6] = t; state->rstate.ra.ptr.p_double[7] = alpha; state->rstate.ra.ptr.p_double[8] = beta; state->rstate.ra.ptr.p_double[9] = v1; state->rstate.ra.ptr.p_double[10] = v2; return result; } /************************************************************************* Adaptive integration results Called after AutoGKIteration returned False. Input parameters: State - algorithm state (used by AutoGKIteration). Output parameters: V - integral(f(x)dx,a,b) Rep - optimization report (see AutoGKReport description) -- ALGLIB -- Copyright 14.11.2007 by Bochkanov Sergey *************************************************************************/ void autogkresults(autogkstate* state, double* v, autogkreport* rep, ae_state *_state) { *v = 0; _autogkreport_clear(rep); *v = state->v; rep->terminationtype = state->terminationtype; rep->nfev = state->nfev; rep->nintervals = state->nintervals; } /************************************************************************* Internal AutoGK subroutine eps<0 - error eps=0 - automatic eps selection width<0 - error width=0 - no width requirements *************************************************************************/ static void autogk_autogkinternalprepare(double a, double b, double eps, double xwidth, autogkinternalstate* state, ae_state *_state) { /* * Save settings */ state->a = a; state->b = b; state->eps = eps; state->xwidth = xwidth; /* * Prepare RComm structure */ ae_vector_set_length(&state->rstate.ia, 3+1, _state); ae_vector_set_length(&state->rstate.ra, 8+1, _state); state->rstate.stage = -1; } /************************************************************************* Internal AutoGK subroutine *************************************************************************/ static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, ae_state *_state) { double c1; double c2; ae_int_t i; ae_int_t j; double intg; double intk; double inta; double v; double ta; double tb; ae_int_t ns; double qeps; ae_int_t info; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { i = state->rstate.ia.ptr.p_int[0]; j = state->rstate.ia.ptr.p_int[1]; ns = state->rstate.ia.ptr.p_int[2]; info = state->rstate.ia.ptr.p_int[3]; c1 = state->rstate.ra.ptr.p_double[0]; c2 = state->rstate.ra.ptr.p_double[1]; intg = state->rstate.ra.ptr.p_double[2]; intk = state->rstate.ra.ptr.p_double[3]; inta = state->rstate.ra.ptr.p_double[4]; v = state->rstate.ra.ptr.p_double[5]; ta = state->rstate.ra.ptr.p_double[6]; tb = state->rstate.ra.ptr.p_double[7]; qeps = state->rstate.ra.ptr.p_double[8]; } else { i = 497; j = -271; ns = -581; info = 745; c1 = -533; c2 = -77; intg = 678; intk = -293; inta = 316; v = 647; ta = -756; tb = 830; qeps = -871; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } /* * Routine body */ /* * initialize quadratures. * use 15-point Gauss-Kronrod formula. */ state->n = 15; gkqgenerategausslegendre(state->n, &info, &state->qn, &state->wk, &state->wg, _state); if( info<0 ) { state->info = -5; state->r = (double)(0); result = ae_false; return result; } ae_vector_set_length(&state->wr, state->n, _state); for(i=0; i<=state->n-1; i++) { if( i==0 ) { state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[1]-state->qn.ptr.p_double[0], _state); continue; } if( i==state->n-1 ) { state->wr.ptr.p_double[state->n-1] = 0.5*ae_fabs(state->qn.ptr.p_double[state->n-1]-state->qn.ptr.p_double[state->n-2], _state); continue; } state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[i-1]-state->qn.ptr.p_double[i+1], _state); } /* * special case */ if( ae_fp_eq(state->a,state->b) ) { state->info = 1; state->r = (double)(0); result = ae_false; return result; } /* * test parameters */ if( ae_fp_less(state->eps,(double)(0))||ae_fp_less(state->xwidth,(double)(0)) ) { state->info = -1; state->r = (double)(0); result = ae_false; return result; } state->info = 1; if( ae_fp_eq(state->eps,(double)(0)) ) { state->eps = 100000*ae_machineepsilon; } /* * First, prepare heap * * column 0 - absolute error * * column 1 - integral of a F(x) (calculated using Kronrod extension nodes) * * column 2 - integral of a |F(x)| (calculated using modified rect. method) * * column 3 - left boundary of a subinterval * * column 4 - right boundary of a subinterval */ if( ae_fp_neq(state->xwidth,(double)(0)) ) { goto lbl_3; } /* * no maximum width requirements * start from one big subinterval */ state->heapwidth = 5; state->heapsize = 1; state->heapused = 1; ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); c1 = 0.5*(state->b-state->a); c2 = 0.5*(state->b+state->a); intg = (double)(0); intk = (double)(0); inta = (double)(0); i = 0; lbl_5: if( i>state->n-1 ) { goto lbl_7; } /* * obtain F */ state->x = c1*state->qn.ptr.p_double[i]+c2; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: v = state->f; /* * Gauss-Kronrod formula */ intk = intk+v*state->wk.ptr.p_double[i]; if( i%2==1 ) { intg = intg+v*state->wg.ptr.p_double[i]; } /* * Integral |F(x)| * Use rectangles method */ inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; i = i+1; goto lbl_5; lbl_7: intk = intk*(state->b-state->a)*0.5; intg = intg*(state->b-state->a)*0.5; inta = inta*(state->b-state->a)*0.5; state->heap.ptr.pp_double[0][0] = ae_fabs(intg-intk, _state); state->heap.ptr.pp_double[0][1] = intk; state->heap.ptr.pp_double[0][2] = inta; state->heap.ptr.pp_double[0][3] = state->a; state->heap.ptr.pp_double[0][4] = state->b; state->sumerr = state->heap.ptr.pp_double[0][0]; state->sumabs = ae_fabs(inta, _state); goto lbl_4; lbl_3: /* * maximum subinterval should be no more than XWidth. * so we create Ceil((B-A)/XWidth)+1 small subintervals */ ns = ae_iceil(ae_fabs(state->b-state->a, _state)/state->xwidth, _state)+1; state->heapsize = ns; state->heapused = ns; state->heapwidth = 5; ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); state->sumerr = (double)(0); state->sumabs = (double)(0); j = 0; lbl_8: if( j>ns-1 ) { goto lbl_10; } ta = state->a+j*(state->b-state->a)/ns; tb = state->a+(j+1)*(state->b-state->a)/ns; c1 = 0.5*(tb-ta); c2 = 0.5*(tb+ta); intg = (double)(0); intk = (double)(0); inta = (double)(0); i = 0; lbl_11: if( i>state->n-1 ) { goto lbl_13; } /* * obtain F */ state->x = c1*state->qn.ptr.p_double[i]+c2; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: v = state->f; /* * Gauss-Kronrod formula */ intk = intk+v*state->wk.ptr.p_double[i]; if( i%2==1 ) { intg = intg+v*state->wg.ptr.p_double[i]; } /* * Integral |F(x)| * Use rectangles method */ inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; i = i+1; goto lbl_11; lbl_13: intk = intk*(tb-ta)*0.5; intg = intg*(tb-ta)*0.5; inta = inta*(tb-ta)*0.5; state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); state->heap.ptr.pp_double[j][1] = intk; state->heap.ptr.pp_double[j][2] = inta; state->heap.ptr.pp_double[j][3] = ta; state->heap.ptr.pp_double[j][4] = tb; state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; state->sumabs = state->sumabs+ae_fabs(inta, _state); j = j+1; goto lbl_8; lbl_10: lbl_4: /* * method iterations */ lbl_14: if( ae_false ) { goto lbl_15; } /* * additional memory if needed */ if( state->heapused==state->heapsize ) { autogk_mheapresize(&state->heap, &state->heapsize, 4*state->heapsize, state->heapwidth, _state); } /* * TODO: every 20 iterations recalculate errors/sums */ if( ae_fp_less_eq(state->sumerr,state->eps*state->sumabs)||state->heapused>=autogk_maxsubintervals ) { state->r = (double)(0); for(j=0; j<=state->heapused-1; j++) { state->r = state->r+state->heap.ptr.pp_double[j][1]; } result = ae_false; return result; } /* * Exclude interval with maximum absolute error */ autogk_mheappop(&state->heap, state->heapused, state->heapwidth, _state); state->sumerr = state->sumerr-state->heap.ptr.pp_double[state->heapused-1][0]; state->sumabs = state->sumabs-state->heap.ptr.pp_double[state->heapused-1][2]; /* * Divide interval, create subintervals */ ta = state->heap.ptr.pp_double[state->heapused-1][3]; tb = state->heap.ptr.pp_double[state->heapused-1][4]; state->heap.ptr.pp_double[state->heapused-1][3] = ta; state->heap.ptr.pp_double[state->heapused-1][4] = 0.5*(ta+tb); state->heap.ptr.pp_double[state->heapused][3] = 0.5*(ta+tb); state->heap.ptr.pp_double[state->heapused][4] = tb; j = state->heapused-1; lbl_16: if( j>state->heapused ) { goto lbl_18; } c1 = 0.5*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3]); c2 = 0.5*(state->heap.ptr.pp_double[j][4]+state->heap.ptr.pp_double[j][3]); intg = (double)(0); intk = (double)(0); inta = (double)(0); i = 0; lbl_19: if( i>state->n-1 ) { goto lbl_21; } /* * F(x) */ state->x = c1*state->qn.ptr.p_double[i]+c2; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: v = state->f; /* * Gauss-Kronrod formula */ intk = intk+v*state->wk.ptr.p_double[i]; if( i%2==1 ) { intg = intg+v*state->wg.ptr.p_double[i]; } /* * Integral |F(x)| * Use rectangles method */ inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; i = i+1; goto lbl_19; lbl_21: intk = intk*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; intg = intg*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; inta = inta*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); state->heap.ptr.pp_double[j][1] = intk; state->heap.ptr.pp_double[j][2] = inta; state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; state->sumabs = state->sumabs+state->heap.ptr.pp_double[j][2]; j = j+1; goto lbl_16; lbl_18: autogk_mheappush(&state->heap, state->heapused-1, state->heapwidth, _state); autogk_mheappush(&state->heap, state->heapused, state->heapwidth, _state); state->heapused = state->heapused+1; goto lbl_14; lbl_15: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = i; state->rstate.ia.ptr.p_int[1] = j; state->rstate.ia.ptr.p_int[2] = ns; state->rstate.ia.ptr.p_int[3] = info; state->rstate.ra.ptr.p_double[0] = c1; state->rstate.ra.ptr.p_double[1] = c2; state->rstate.ra.ptr.p_double[2] = intg; state->rstate.ra.ptr.p_double[3] = intk; state->rstate.ra.ptr.p_double[4] = inta; state->rstate.ra.ptr.p_double[5] = v; state->rstate.ra.ptr.p_double[6] = ta; state->rstate.ra.ptr.p_double[7] = tb; state->rstate.ra.ptr.p_double[8] = qeps; return result; } static void autogk_mheappop(/* Real */ ae_matrix* heap, ae_int_t heapsize, ae_int_t heapwidth, ae_state *_state) { ae_int_t i; ae_int_t p; double t; ae_int_t maxcp; if( heapsize==1 ) { return; } for(i=0; i<=heapwidth-1; i++) { t = heap->ptr.pp_double[heapsize-1][i]; heap->ptr.pp_double[heapsize-1][i] = heap->ptr.pp_double[0][i]; heap->ptr.pp_double[0][i] = t; } p = 0; while(2*p+1ptr.pp_double[2*p+2][0],heap->ptr.pp_double[2*p+1][0]) ) { maxcp = 2*p+2; } } if( ae_fp_less(heap->ptr.pp_double[p][0],heap->ptr.pp_double[maxcp][0]) ) { for(i=0; i<=heapwidth-1; i++) { t = heap->ptr.pp_double[p][i]; heap->ptr.pp_double[p][i] = heap->ptr.pp_double[maxcp][i]; heap->ptr.pp_double[maxcp][i] = t; } p = maxcp; } else { break; } } } static void autogk_mheappush(/* Real */ ae_matrix* heap, ae_int_t heapsize, ae_int_t heapwidth, ae_state *_state) { ae_int_t i; ae_int_t p; double t; ae_int_t parent; if( heapsize==0 ) { return; } p = heapsize; while(p!=0) { parent = (p-1)/2; if( ae_fp_greater(heap->ptr.pp_double[p][0],heap->ptr.pp_double[parent][0]) ) { for(i=0; i<=heapwidth-1; i++) { t = heap->ptr.pp_double[p][i]; heap->ptr.pp_double[p][i] = heap->ptr.pp_double[parent][i]; heap->ptr.pp_double[parent][i] = t; } p = parent; } else { break; } } } static void autogk_mheapresize(/* Real */ ae_matrix* heap, ae_int_t* heapsize, ae_int_t newheapsize, ae_int_t heapwidth, ae_state *_state) { ae_frame _frame_block; ae_matrix tmp; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_matrix_init(&tmp, 0, 0, DT_REAL, _state); ae_matrix_set_length(&tmp, *heapsize, heapwidth, _state); for(i=0; i<=*heapsize-1; i++) { ae_v_move(&tmp.ptr.pp_double[i][0], 1, &heap->ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); } ae_matrix_set_length(heap, newheapsize, heapwidth, _state); for(i=0; i<=*heapsize-1; i++) { ae_v_move(&heap->ptr.pp_double[i][0], 1, &tmp.ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); } *heapsize = newheapsize; ae_frame_leave(_state); } void _autogkreport_init(void* _p, ae_state *_state) { autogkreport *p = (autogkreport*)_p; ae_touch_ptr((void*)p); } void _autogkreport_init_copy(void* _dst, void* _src, ae_state *_state) { autogkreport *dst = (autogkreport*)_dst; autogkreport *src = (autogkreport*)_src; dst->terminationtype = src->terminationtype; dst->nfev = src->nfev; dst->nintervals = src->nintervals; } void _autogkreport_clear(void* _p) { autogkreport *p = (autogkreport*)_p; ae_touch_ptr((void*)p); } void _autogkreport_destroy(void* _p) { autogkreport *p = (autogkreport*)_p; ae_touch_ptr((void*)p); } void _autogkinternalstate_init(void* _p, ae_state *_state) { autogkinternalstate *p = (autogkinternalstate*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->heap, 0, 0, DT_REAL, _state); ae_vector_init(&p->qn, 0, DT_REAL, _state); ae_vector_init(&p->wg, 0, DT_REAL, _state); ae_vector_init(&p->wk, 0, DT_REAL, _state); ae_vector_init(&p->wr, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _autogkinternalstate_init_copy(void* _dst, void* _src, ae_state *_state) { autogkinternalstate *dst = (autogkinternalstate*)_dst; autogkinternalstate *src = (autogkinternalstate*)_src; dst->a = src->a; dst->b = src->b; dst->eps = src->eps; dst->xwidth = src->xwidth; dst->x = src->x; dst->f = src->f; dst->info = src->info; dst->r = src->r; ae_matrix_init_copy(&dst->heap, &src->heap, _state); dst->heapsize = src->heapsize; dst->heapwidth = src->heapwidth; dst->heapused = src->heapused; dst->sumerr = src->sumerr; dst->sumabs = src->sumabs; ae_vector_init_copy(&dst->qn, &src->qn, _state); ae_vector_init_copy(&dst->wg, &src->wg, _state); ae_vector_init_copy(&dst->wk, &src->wk, _state); ae_vector_init_copy(&dst->wr, &src->wr, _state); dst->n = src->n; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _autogkinternalstate_clear(void* _p) { autogkinternalstate *p = (autogkinternalstate*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->heap); ae_vector_clear(&p->qn); ae_vector_clear(&p->wg); ae_vector_clear(&p->wk); ae_vector_clear(&p->wr); _rcommstate_clear(&p->rstate); } void _autogkinternalstate_destroy(void* _p) { autogkinternalstate *p = (autogkinternalstate*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->heap); ae_vector_destroy(&p->qn); ae_vector_destroy(&p->wg); ae_vector_destroy(&p->wk); ae_vector_destroy(&p->wr); _rcommstate_destroy(&p->rstate); } void _autogkstate_init(void* _p, ae_state *_state) { autogkstate *p = (autogkstate*)_p; ae_touch_ptr((void*)p); _autogkinternalstate_init(&p->internalstate, _state); _rcommstate_init(&p->rstate, _state); } void _autogkstate_init_copy(void* _dst, void* _src, ae_state *_state) { autogkstate *dst = (autogkstate*)_dst; autogkstate *src = (autogkstate*)_src; dst->a = src->a; dst->b = src->b; dst->alpha = src->alpha; dst->beta = src->beta; dst->xwidth = src->xwidth; dst->x = src->x; dst->xminusa = src->xminusa; dst->bminusx = src->bminusx; dst->needf = src->needf; dst->f = src->f; dst->wrappermode = src->wrappermode; _autogkinternalstate_init_copy(&dst->internalstate, &src->internalstate, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->v = src->v; dst->terminationtype = src->terminationtype; dst->nfev = src->nfev; dst->nintervals = src->nintervals; } void _autogkstate_clear(void* _p) { autogkstate *p = (autogkstate*)_p; ae_touch_ptr((void*)p); _autogkinternalstate_clear(&p->internalstate); _rcommstate_clear(&p->rstate); } void _autogkstate_destroy(void* _p) { autogkstate *p = (autogkstate*)_p; ae_touch_ptr((void*)p); _autogkinternalstate_destroy(&p->internalstate); _rcommstate_destroy(&p->rstate); } } qmapshack-1.10.0/3rdparty/alglib/src/dataanalysis.cpp000755 001750 000144 00004771575 13024173403 023726 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "dataanalysis.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* Optimal binary classification Algorithms finds optimal (=with minimal cross-entropy) binary partition. Internal subroutine. INPUT PARAMETERS: A - array[0..N-1], variable C - array[0..N-1], class numbers (0 or 1). N - array size OUTPUT PARAMETERS: Info - completetion code: * -3, all values of A[] are same (partition is impossible) * -2, one of C[] is incorrect (<0, >1) * -1, incorrect pararemets were passed (N<=0). * 1, OK Threshold- partiton boundary. Left part contains values which are strictly less than Threshold. Right part contains values which are greater than or equal to Threshold. PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) CVE - cross-validation estimate of cross-entropy -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dsoptimalsplit2(const_cast(a.c_ptr()), const_cast(c.c_ptr()), n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Optimal partition, internal subroutine. Fast version. Accepts: A array[0..N-1] array of attributes array[0..N-1] C array[0..N-1] array of class labels TiesBuf array[0..N] temporaries (ties) CntBuf array[0..2*NC-1] temporaries (counts) Alpha centering factor (0<=alpha<=1, recommended value - 0.05) BufR array[0..N-1] temporaries BufI array[0..N-1] temporaries Output: Info error code (">0"=OK, "<0"=bad) RMS training set RMS error CVRMS leave-one-out RMS error Note: content of all arrays is changed by subroutine; it doesn't allocate temporaries. -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dsoptimalsplit2fast(const_cast(a.c_ptr()), const_cast(c.c_ptr()), const_cast(tiesbuf.c_ptr()), const_cast(cntbuf.c_ptr()), const_cast(bufr.c_ptr()), const_cast(bufi.c_ptr()), n, nc, alpha, &info, &threshold, &rms, &cvrms, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This structure is a clusterization engine. You should not try to access its fields directly. Use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ _clusterizerstate_owner::_clusterizerstate_owner() { p_struct = (alglib_impl::clusterizerstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::clusterizerstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_clusterizerstate_init(p_struct, NULL); } _clusterizerstate_owner::_clusterizerstate_owner(const _clusterizerstate_owner &rhs) { p_struct = (alglib_impl::clusterizerstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::clusterizerstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_clusterizerstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _clusterizerstate_owner& _clusterizerstate_owner::operator=(const _clusterizerstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_clusterizerstate_clear(p_struct); alglib_impl::_clusterizerstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _clusterizerstate_owner::~_clusterizerstate_owner() { alglib_impl::_clusterizerstate_clear(p_struct); ae_free(p_struct); } alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() { return p_struct; } alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() const { return const_cast(p_struct); } clusterizerstate::clusterizerstate() : _clusterizerstate_owner() { } clusterizerstate::clusterizerstate(const clusterizerstate &rhs):_clusterizerstate_owner(rhs) { } clusterizerstate& clusterizerstate::operator=(const clusterizerstate &rhs) { if( this==&rhs ) return *this; _clusterizerstate_owner::operator=(rhs); return *this; } clusterizerstate::~clusterizerstate() { } /************************************************************************* This structure is used to store results of the agglomerative hierarchical clustering (AHC). Following information is returned: * TerminationType - completion code: * 1 for successful completion of algorithm * -5 inappropriate combination of clustering algorithm and distance function was used. As for now, it is possible only when Ward's method is called for dataset with non-Euclidean distance function. In case negative completion code is returned, other fields of report structure are invalid and should not be used. * NPoints contains number of points in the original dataset * Z contains information about merges performed (see below). Z contains indexes from the original (unsorted) dataset and it can be used when you need to know what points were merged. However, it is not convenient when you want to build a dendrograd (see below). * if you want to build dendrogram, you can use Z, but it is not good option, because Z contains indexes from unsorted dataset. Dendrogram built from such dataset is likely to have intersections. So, you have to reorder you points before building dendrogram. Permutation which reorders point is returned in P. Another representation of merges, which is more convenient for dendorgram construction, is returned in PM. * more information on format of Z, P and PM can be found below and in the examples from ALGLIB Reference Manual. FORMAL DESCRIPTION OF FIELDS: NPoints number of points Z array[NPoints-1,2], contains indexes of clusters linked in pairs to form clustering tree. I-th row corresponds to I-th merge: * Z[I,0] - index of the first cluster to merge * Z[I,1] - index of the second cluster to merge * Z[I,0](rhs.p_struct), NULL); } _ahcreport_owner& _ahcreport_owner::operator=(const _ahcreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_ahcreport_clear(p_struct); alglib_impl::_ahcreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _ahcreport_owner::~_ahcreport_owner() { alglib_impl::_ahcreport_clear(p_struct); ae_free(p_struct); } alglib_impl::ahcreport* _ahcreport_owner::c_ptr() { return p_struct; } alglib_impl::ahcreport* _ahcreport_owner::c_ptr() const { return const_cast(p_struct); } ahcreport::ahcreport() : _ahcreport_owner() ,terminationtype(p_struct->terminationtype),npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) { } ahcreport::ahcreport(const ahcreport &rhs):_ahcreport_owner(rhs) ,terminationtype(p_struct->terminationtype),npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) { } ahcreport& ahcreport::operator=(const ahcreport &rhs) { if( this==&rhs ) return *this; _ahcreport_owner::operator=(rhs); return *this; } ahcreport::~ahcreport() { } /************************************************************************* This structure is used to store results of the k-means clustering algorithm. Following information is always returned: * NPoints contains number of points in the original dataset * TerminationType contains completion code, negative on failure, positive on success * K contains number of clusters For positive TerminationType we return: * NFeatures contains number of variables in the original dataset * C, which contains centers found by algorithm * CIdx, which maps points of the original dataset to clusters FORMAL DESCRIPTION OF FIELDS: NPoints number of points, >=0 NFeatures number of variables, >=1 TerminationType completion code: * -5 if distance type is anything different from Euclidean metric * -3 for degenerate dataset: a) less than K distinct points, b) K=0 for non-empty dataset. * +1 for successful completion K number of clusters C array[K,NFeatures], rows of the array store centers CIdx array[NPoints], which contains cluster indexes IterationsCount actual number of iterations performed by clusterizer. If algorithm performed more than one random restart, total number of iterations is returned. Energy merit function, "energy", sum of squared deviations from cluster centers -- ALGLIB -- Copyright 27.11.2012 by Bochkanov Sergey *************************************************************************/ _kmeansreport_owner::_kmeansreport_owner() { p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_kmeansreport_init(p_struct, NULL); } _kmeansreport_owner::_kmeansreport_owner(const _kmeansreport_owner &rhs) { p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _kmeansreport_owner& _kmeansreport_owner::operator=(const _kmeansreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_kmeansreport_clear(p_struct); alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _kmeansreport_owner::~_kmeansreport_owner() { alglib_impl::_kmeansreport_clear(p_struct); ae_free(p_struct); } alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() { return p_struct; } alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() const { return const_cast(p_struct); } kmeansreport::kmeansreport() : _kmeansreport_owner() ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),iterationscount(p_struct->iterationscount),energy(p_struct->energy),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) { } kmeansreport::kmeansreport(const kmeansreport &rhs):_kmeansreport_owner(rhs) ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),iterationscount(p_struct->iterationscount),energy(p_struct->energy),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) { } kmeansreport& kmeansreport::operator=(const kmeansreport &rhs) { if( this==&rhs ) return *this; _kmeansreport_owner::operator=(rhs); return *this; } kmeansreport::~kmeansreport() { } /************************************************************************* This function initializes clusterizer object. Newly initialized object is empty, i.e. it does not contain dataset. You should use it as follows: 1. creation 2. dataset is added with ClusterizerSetPoints() 3. additional parameters are set 3. clusterization is performed with one of the clustering functions -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizercreate(clusterizerstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizercreate(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset to the clusterizer structure. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm), non-squared * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| NOTE 1: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. NOTE 2: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric * k-means++ clustering algorithm may be used only with Euclidean distance function Thus, list of specific clustering algorithms you may use depends on distance function you specify when you set your dataset. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, nfeatures, disttype, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset to the clusterizer structure. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm), non-squared * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| NOTE 1: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. NOTE 2: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric * k-means++ clustering algorithm may be used only with Euclidean distance function Thus, list of specific clustering algorithms you may use depends on distance function you specify when you set your dataset. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; ae_int_t nfeatures; npoints = xy.rows(); nfeatures = xy.cols(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, nfeatures, disttype, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset given by distance matrix to the clusterizer structure. It is important that dataset is not given explicitly - only distance matrix is given. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - array[NPoints,NPoints], distance matrix given by its upper or lower triangle (main diagonal is ignored because its entries are expected to be zero). NPoints - number of points IsUpper - whether upper or lower triangle of D is given. NOTE 1: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric, including one which is given by distance matrix * k-means++ clustering algorithm may be used only with Euclidean distance function and explicitly given points - it can not be used with dataset given by distance matrix Thus, if you call this function, you will be unable to use k-means clustering algorithm to process your problem. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetdistances(const_cast(s.c_ptr()), const_cast(d.c_ptr()), npoints, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function adds dataset given by distance matrix to the clusterizer structure. It is important that dataset is not given explicitly - only distance matrix is given. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - array[NPoints,NPoints], distance matrix given by its upper or lower triangle (main diagonal is ignored because its entries are expected to be zero). NPoints - number of points IsUpper - whether upper or lower triangle of D is given. NOTE 1: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric, including one which is given by distance matrix * k-means++ clustering algorithm may be used only with Euclidean distance function and explicitly given points - it can not be used with dataset given by distance matrix Thus, if you call this function, you will be unable to use k-means clustering algorithm to process your problem. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const bool isupper) { alglib_impl::ae_state _alglib_env_state; ae_int_t npoints; if( (d.rows()!=d.cols())) throw ap_error("Error while calling 'clusterizersetdistances': looks like one of arguments has wrong size"); npoints = d.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetdistances(const_cast(s.c_ptr()), const_cast(d.c_ptr()), npoints, isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets agglomerative hierarchical clustering algorithm INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Algo - algorithm type: * 0 complete linkage (default algorithm) * 1 single linkage * 2 unweighted average linkage * 3 weighted average linkage * 4 Ward's method NOTE: Ward's method works correctly only with Euclidean distance, that's why algorithm will return negative termination code (failure) for any other distance type. It is possible, however, to use this method with user-supplied distance matrix. It is your responsibility to pass one which was calculated with Euclidean distance function. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetahcalgo(const clusterizerstate &s, const ae_int_t algo) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetahcalgo(const_cast(s.c_ptr()), algo, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets k-means properties: number of restarts and maximum number of iterations per one run. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Restarts- restarts count, >=1. k-means++ algorithm performs several restarts and chooses best set of centers (one with minimum squared distance). MaxIts - maximum number of k-means iterations performed during one run. >=0, zero value means that algorithm performs unlimited number of iterations. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeanslimits(const clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetkmeanslimits(const_cast(s.c_ptr()), restarts, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets k-means initialization algorithm. Several different algorithms can be chosen, including k-means++. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() InitAlgo- initialization algorithm: * 0 automatic selection ( different versions of ALGLIB may select different algorithms) * 1 random initialization * 2 k-means++ initialization (best quality of initial centers, but long non-parallelizable initialization phase with bad cache locality) * 3 "fast-greedy" algorithm with efficient, easy to parallelize initialization. Quality of initial centers is somewhat worse than that of k-means++. This algorithm is a default one in the current version of ALGLIB. *-1 "debug" algorithm which always selects first K rows of dataset; this algorithm is used for debug purposes only. Do not use it in the industrial code! -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeansinit(const clusterizerstate &s, const ae_int_t initalgo) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizersetkmeansinit(const_cast(s.c_ptr()), initalgo, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs agglomerative hierarchical clustering COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() OUTPUT PARAMETERS: Rep - clustering results; see description of AHCReport structure for more information. NOTE 1: hierarchical clustering algorithms require large amounts of memory. In particular, this implementation needs sizeof(double)*NPoints^2 bytes, which are used to store distance matrix. In case we work with user-supplied matrix, this amount is multiplied by 2 (we have to store original matrix and to work with its copy). For example, problem with 10000 points would require 800M of RAM, even when working in a 1-dimensional space. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunahc(const clusterizerstate &s, ahcreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizerrunahc(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_clusterizerrunahc(const clusterizerstate &s, ahcreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_clusterizerrunahc(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function performs clustering by k-means++ algorithm. You may change algorithm properties by calling: * ClusterizerSetKMeansLimits() to change number of restarts or iterations * ClusterizerSetKMeansInit() to change initialization algorithm By default, one restart and unlimited number of iterations are used. Initialization algorithm is chosen automatically. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (can be used from C# and C++) ! * access to high-performance C++ core (actual for C# users) ! ! K-means clustering algorithm has two phases: selection of initial ! centers and clustering itself. ALGLIB parallelizes both phases. ! Parallel version is optimized for the following scenario: medium or ! high-dimensional problem (20 or more dimensions) with large number of ! points and clusters. However, some speed-up can be obtained even when ! assumptions above are violated. ! ! As for native-vs-managed comparison, working with native core brings ! 30-40% improvement in speed over pure C# version of ALGLIB. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() K - number of clusters, K>=0. K can be zero only when algorithm is called for empty dataset, in this case completion code is set to success (+1). If K=0 and dataset size is non-zero, we can not meaningfully assign points to some center (there are no centers because K=0) and return -3 as completion code (failure). OUTPUT PARAMETERS: Rep - clustering results; see description of KMeansReport structure for more information. NOTE 1: k-means clustering can be performed only for datasets with Euclidean distance function. Algorithm will return negative completion code in Rep.TerminationType in case dataset was added to clusterizer with DistType other than Euclidean (or dataset was specified by distance matrix instead of explicitly given points). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizerrunkmeans(const_cast(s.c_ptr()), k, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_clusterizerrunkmeans(const_cast(s.c_ptr()), k, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns distance matrix for dataset COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm, non-squared) * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| OUTPUT PARAMETERS: D - array[NPoints,NPoints], distance matrix (full matrix is returned, with lower and upper triangles) NOTE: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::clusterizergetdistances(const_cast(xy.c_ptr()), npoints, nfeatures, disttype, const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_clusterizergetdistances(const_cast(xy.c_ptr()), npoints, nfeatures, disttype, const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function takes as input clusterization report Rep, desired clusters count K, and builds top K clusters from hierarchical clusterization tree. It returns assignment of points to clusters (array of cluster indexes). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY K - desired number of clusters, 1<=K<=NPoints. K can be zero only when NPoints=0. OUTPUT PARAMETERS: CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I](rep.c_ptr()), k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function accepts AHC report Rep, desired minimum intercluster distance and returns top clusters from hierarchical clusterization tree which are separated by distance R or HIGHER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByCorr, which returns clusters with intercluster correlation equal to R or LOWER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired minimum intercluster distance, R>=0 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I](rep.c_ptr()), r, &k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function accepts AHC report Rep, desired maximum intercluster correlation and returns top clusters from hierarchical clusterization tree which are separated by correlation R or LOWER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByDist, which returns clusters with intercluster distance equal to R or HIGHER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired maximum intercluster correlation, -1<=R<=+1 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I](rep.c_ptr()), r, &k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* k-means++ clusterization. Backward compatibility function, we recommend to use CLUSTERING subpackage as better replacement. -- ALGLIB -- Copyright 21.03.2009 by Bochkanov Sergey *************************************************************************/ void kmeansgenerate(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t k, const ae_int_t restarts, ae_int_t &info, real_2d_array &c, integer_1d_array &xyc) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::kmeansgenerate(const_cast(xy.c_ptr()), npoints, nvars, k, restarts, &info, const_cast(c.c_ptr()), const_cast(xyc.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _decisionforest_owner::_decisionforest_owner() { p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_decisionforest_init(p_struct, NULL); } _decisionforest_owner::_decisionforest_owner(const _decisionforest_owner &rhs) { p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _decisionforest_owner& _decisionforest_owner::operator=(const _decisionforest_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_decisionforest_clear(p_struct); alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _decisionforest_owner::~_decisionforest_owner() { alglib_impl::_decisionforest_clear(p_struct); ae_free(p_struct); } alglib_impl::decisionforest* _decisionforest_owner::c_ptr() { return p_struct; } alglib_impl::decisionforest* _decisionforest_owner::c_ptr() const { return const_cast(p_struct); } decisionforest::decisionforest() : _decisionforest_owner() { } decisionforest::decisionforest(const decisionforest &rhs):_decisionforest_owner(rhs) { } decisionforest& decisionforest::operator=(const decisionforest &rhs) { if( this==&rhs ) return *this; _decisionforest_owner::operator=(rhs); return *this; } decisionforest::~decisionforest() { } /************************************************************************* *************************************************************************/ _dfreport_owner::_dfreport_owner() { p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_dfreport_init(p_struct, NULL); } _dfreport_owner::_dfreport_owner(const _dfreport_owner &rhs) { p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _dfreport_owner& _dfreport_owner::operator=(const _dfreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_dfreport_clear(p_struct); alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _dfreport_owner::~_dfreport_owner() { alglib_impl::_dfreport_clear(p_struct); ae_free(p_struct); } alglib_impl::dfreport* _dfreport_owner::c_ptr() { return p_struct; } alglib_impl::dfreport* _dfreport_owner::c_ptr() const { return const_cast(p_struct); } dfreport::dfreport() : _dfreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror) { } dfreport::dfreport(const dfreport &rhs):_dfreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror) { } dfreport& dfreport::operator=(const dfreport &rhs) { if( this==&rhs ) return *this; _dfreport_owner::operator=(rhs); return *this; } dfreport::~dfreport() { } /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void dfserialize(decisionforest &obj, std::string &s_out) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_int_t ssize; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_alloc_start(&serializer); alglib_impl::dfalloc(&serializer, obj.c_ptr(), &state); ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); s_out.clear(); s_out.reserve((size_t)(ssize+1)); alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); alglib_impl::dfserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); if( s_out.length()>(size_t)ssize ) throw ap_error("ALGLIB: serialization integrity error"); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void dfunserialize(std::string &s_in, decisionforest &obj) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); alglib_impl::dfunserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This subroutine builds random decision forest. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dfbuildrandomdecisionforest(const_cast(xy.c_ptr()), npoints, nvars, nclasses, ntrees, r, &info, const_cast(df.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine builds random decision forest. This function gives ability to tune number of variables used when choosing best split. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. NRndVars - number of variables used when choosing best split R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dfbuildrandomdecisionforestx1(const_cast(xy.c_ptr()), npoints, nvars, nclasses, ntrees, nrndvars, r, &info, const_cast(df.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procesing INPUT PARAMETERS: DF - decision forest model X - input vector, array[0..NVars-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also DFProcessI. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dfprocess(const_cast(df.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 'interactive' variant of DFProcess for languages like Python which support constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::dfprocessi(const_cast(df.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dfrelclserror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dfavgce(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dfrmserror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dfavgerror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::dfavgrelerror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _linearmodel_owner::_linearmodel_owner() { p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linearmodel_init(p_struct, NULL); } _linearmodel_owner::_linearmodel_owner(const _linearmodel_owner &rhs) { p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _linearmodel_owner& _linearmodel_owner::operator=(const _linearmodel_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_linearmodel_clear(p_struct); alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _linearmodel_owner::~_linearmodel_owner() { alglib_impl::_linearmodel_clear(p_struct); ae_free(p_struct); } alglib_impl::linearmodel* _linearmodel_owner::c_ptr() { return p_struct; } alglib_impl::linearmodel* _linearmodel_owner::c_ptr() const { return const_cast(p_struct); } linearmodel::linearmodel() : _linearmodel_owner() { } linearmodel::linearmodel(const linearmodel &rhs):_linearmodel_owner(rhs) { } linearmodel& linearmodel::operator=(const linearmodel &rhs) { if( this==&rhs ) return *this; _linearmodel_owner::operator=(rhs); return *this; } linearmodel::~linearmodel() { } /************************************************************************* LRReport structure contains additional information about linear model: * C - covariation matrix, array[0..NVars,0..NVars]. C[i,j] = Cov(A[i],A[j]) * RMSError - root mean square error on a training set * AvgError - average error on a training set * AvgRelError - average relative error on a training set (excluding observations with zero function value). * CVRMSError - leave-one-out cross-validation estimate of generalization error. Calculated using fast algorithm with O(NVars*NPoints) complexity. * CVAvgError - cross-validation estimate of average error * CVAvgRelError - cross-validation estimate of average relative error All other fields of the structure are intended for internal use and should not be used outside ALGLIB. *************************************************************************/ _lrreport_owner::_lrreport_owner() { p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lrreport_init(p_struct, NULL); } _lrreport_owner::_lrreport_owner(const _lrreport_owner &rhs) { p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _lrreport_owner& _lrreport_owner::operator=(const _lrreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_lrreport_clear(p_struct); alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _lrreport_owner::~_lrreport_owner() { alglib_impl::_lrreport_clear(p_struct); ae_free(p_struct); } alglib_impl::lrreport* _lrreport_owner::c_ptr() { return p_struct; } alglib_impl::lrreport* _lrreport_owner::c_ptr() const { return const_cast(p_struct); } lrreport::lrreport() : _lrreport_owner() ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) { } lrreport::lrreport(const lrreport &rhs):_lrreport_owner(rhs) ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) { } lrreport& lrreport::operator=(const lrreport &rhs) { if( this==&rhs ) return *this; _lrreport_owner::operator=(rhs); return *this; } lrreport::~lrreport() { } /************************************************************************* Linear regression Subroutine builds model: Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) and model found in ALGLIB format, covariation matrix, training set errors (rms, average, average relative) and leave-one-out cross-validation estimate of the generalization error. CV estimate calculated using fast algorithm with O(NPoints*NVars) complexity. When covariation matrix is calculated standard deviations of function values are assumed to be equal to RMS error on the training set. INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints(xy.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Linear regression Variant of LRBuild which uses vector of standatd deviations (errors in function values). INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable S - standard deviations (errors in function values) array[0..NPoints-1], S[i]>0. NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints(xy.c_ptr()), const_cast(s.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like LRBuildS, but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/ void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, linearmodel &lm, lrreport &ar) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lrbuildzs(const_cast(xy.c_ptr()), const_cast(s.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like LRBuild but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/ void lrbuildz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, linearmodel &lm, lrreport &ar) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lrbuildz(const_cast(xy.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacks coefficients of linear model. INPUT PARAMETERS: LM - linear model in ALGLIB format OUTPUT PARAMETERS: V - coefficients, array[0..NVars] constant term (intercept) is stored in the V[NVars]. NVars - number of independent variables (one less than number of coefficients) -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ void lrunpack(const linearmodel &lm, real_1d_array &v, ae_int_t &nvars) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lrunpack(const_cast(lm.c_ptr()), const_cast(v.c_ptr()), &nvars, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* "Packs" coefficients and creates linear model in ALGLIB format (LRUnpack reversed). INPUT PARAMETERS: V - coefficients, array[0..NVars] NVars - number of independent variables OUTPUT PAREMETERS: LM - linear model. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ void lrpack(const real_1d_array &v, const ae_int_t nvars, linearmodel &lm) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lrpack(const_cast(v.c_ptr()), nvars, const_cast(lm.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procesing INPUT PARAMETERS: LM - linear model X - input vector, array[0..NVars-1]. Result: value of linear model regression estimate -- ALGLIB -- Copyright 03.09.2008 by Bochkanov Sergey *************************************************************************/ double lrprocess(const linearmodel &lm, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::lrprocess(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: root mean square error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lrrmserror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::lrrmserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lravgerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::lravgerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average relative error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lravgrelerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::lravgrelerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: simple moving averages (unsymmetric). This filter replaces array by results of SMA(K) filter. SMA(K) is defined as filter which averages at most K previous points (previous - not points AROUND central point) - or less, in case of the first K-1 points. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::filtersma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: simple moving averages (unsymmetric). This filter replaces array by results of SMA(K) filter. SMA(K) is defined as filter which averages at most K previous points (previous - not points AROUND central point) - or less, in case of the first K-1 points. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filtersma(real_1d_array &x, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::filtersma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: exponential moving averages. This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is defined as filter which replaces X[] by S[]: S[0] = X[0] S[t] = alpha*X[t] + (1-alpha)*S[t-1] INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 alpha - 0(x.c_ptr()), n, alpha, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: exponential moving averages. This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is defined as filter which replaces X[] by S[]: S[0] = X[0] S[t] = alpha*X[t] + (1-alpha)*S[t-1] INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 alpha - 0(x.c_ptr()), n, alpha, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: linear regression moving averages. This filter replaces array by results of LRMA(K) filter. LRMA(K) is defined as filter which, for each data point, builds linear regression model using K prevous points (point itself is included in these K points) and calculates value of this linear model at the point in question. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::filterlrma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Filters: linear regression moving averages. This filter replaces array by results of LRMA(K) filter. LRMA(K) is defined as filter which, for each data point, builds linear regression model using K prevous points (point itself is included in these K points) and calculates value of this linear model at the point in question. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filterlrma(real_1d_array &x, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::filterlrma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Multiclass Fisher LDA Subroutine finds coefficients of linear combination which optimally separates training set on classes. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - linear combination coefficients, array[0..NVars-1] -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_1d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fisherlda(const_cast(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* N-dimensional multiclass Fisher LDA Subroutine finds coefficients of linear combinations which optimally separates training set on classes. It returns N-dimensional basis whose vector are sorted by quality of training set separation (in descending order). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - basis, array[0..NVars-1,0..NVars-1] columns of matrix stores basis vectors, sorted by quality of training set separation (in descending order) -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::fisherldan(const_cast(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_fisherldan(const_cast(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(w.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Model's errors: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/ _modelerrors_owner::_modelerrors_owner() { p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_modelerrors_init(p_struct, NULL); } _modelerrors_owner::_modelerrors_owner(const _modelerrors_owner &rhs) { p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _modelerrors_owner& _modelerrors_owner::operator=(const _modelerrors_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_modelerrors_clear(p_struct); alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _modelerrors_owner::~_modelerrors_owner() { alglib_impl::_modelerrors_clear(p_struct); ae_free(p_struct); } alglib_impl::modelerrors* _modelerrors_owner::c_ptr() { return p_struct; } alglib_impl::modelerrors* _modelerrors_owner::c_ptr() const { return const_cast(p_struct); } modelerrors::modelerrors() : _modelerrors_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) { } modelerrors::modelerrors(const modelerrors &rhs):_modelerrors_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) { } modelerrors& modelerrors::operator=(const modelerrors &rhs) { if( this==&rhs ) return *this; _modelerrors_owner::operator=(rhs); return *this; } modelerrors::~modelerrors() { } /************************************************************************* *************************************************************************/ _multilayerperceptron_owner::_multilayerperceptron_owner() { p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_multilayerperceptron_init(p_struct, NULL); } _multilayerperceptron_owner::_multilayerperceptron_owner(const _multilayerperceptron_owner &rhs) { p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _multilayerperceptron_owner& _multilayerperceptron_owner::operator=(const _multilayerperceptron_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_multilayerperceptron_clear(p_struct); alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _multilayerperceptron_owner::~_multilayerperceptron_owner() { alglib_impl::_multilayerperceptron_clear(p_struct); ae_free(p_struct); } alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() { return p_struct; } alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() const { return const_cast(p_struct); } multilayerperceptron::multilayerperceptron() : _multilayerperceptron_owner() { } multilayerperceptron::multilayerperceptron(const multilayerperceptron &rhs):_multilayerperceptron_owner(rhs) { } multilayerperceptron& multilayerperceptron::operator=(const multilayerperceptron &rhs) { if( this==&rhs ) return *this; _multilayerperceptron_owner::operator=(rhs); return *this; } multilayerperceptron::~multilayerperceptron() { } /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void mlpserialize(multilayerperceptron &obj, std::string &s_out) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_int_t ssize; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_alloc_start(&serializer); alglib_impl::mlpalloc(&serializer, obj.c_ptr(), &state); ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); s_out.clear(); s_out.reserve((size_t)(ssize+1)); alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); alglib_impl::mlpserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); if( s_out.length()>(size_t)ssize ) throw ap_error("ALGLIB: serialization integrity error"); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void mlpunserialize(std::string &s_in, multilayerperceptron &obj) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); alglib_impl::mlpunserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers, with linear output layer. Network weights are filled with small random values. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreate0(nin, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreate0, but with one hidden layer (NHid neurons) with non-linear activation function. Output layer is linear. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreate1(nin, nhid, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) with non-linear activation function. Output layer is linear. $ALL -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreate2(nin, nhid1, nhid2, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values: (B, +INF), if D>=0 or (-INF, B), if D<0. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreateb0(nin, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateB0 but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreateb1(nin, nhid, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateB0 but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreateb2(nin, nhid1, nhid2, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values [A,B]. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreater0(nin, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateR0, but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreater1(nin, nhid, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateR0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreater2(nin, nhid1, nhid2, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creates classifier network with NIn inputs and NOut possible classes. Network contains no hidden layers and linear output layer with SOFTMAX- normalization (so outputs sums up to 1.0 and converge to posterior probabilities). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreatec0(nin, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateC0, but with one non-linear hidden layer. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreatec1(nin, nhid, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Same as MLPCreateC0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreatec2(nin, nhid1, nhid2, nout, const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Copying of neural network INPUT PARAMETERS: Network1 - original OUTPUT PARAMETERS: Network2 - copy -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcopy(const multilayerperceptron &network1, multilayerperceptron &network2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcopy(const_cast(network1.c_ptr()), const_cast(network2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function copies tunable parameters (weights/means/sigmas) from one network to another with same architecture. It performs some rudimentary checks that architectures are same, and throws exception if check fails. It is intended for fast copying of states between two network which are known to have same geometry. INPUT PARAMETERS: Network1 - source, must be correctly initialized Network2 - target, must have same architecture OUTPUT PARAMETERS: Network2 - network state is copied from source to target -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ void mlpcopytunableparameters(const multilayerperceptron &network1, const multilayerperceptron &network2) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcopytunableparameters(const_cast(network1.c_ptr()), const_cast(network2.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Randomization of neural network weights -- ALGLIB -- Copyright 06.11.2007 by Bochkanov Sergey *************************************************************************/ void mlprandomize(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlprandomize(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Randomization of neural network weights and standartisator -- ALGLIB -- Copyright 10.03.2008 by Bochkanov Sergey *************************************************************************/ void mlprandomizefull(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlprandomizefull(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Internal subroutine. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessor(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpinitpreprocessor(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns information about initialized network: number of inputs, outputs, weights. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpproperties(const_cast(network.c_ptr()), &nin, &nout, &wcount, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns number of inputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetinputscount(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpgetinputscount(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns number of outputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetoutputscount(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpgetoutputscount(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Returns number of weights. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetweightscount(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpgetweightscount(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ bool mlpissoftmax(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::mlpissoftmax(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns total number of layers (including input, hidden and output layers). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayerscount(const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpgetlayerscount(const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns size of K-th layer. K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. Size of the output layer is always equal to the number of outputs, although when we have softmax-normalized network, last neuron doesn't have any connections - it is just zero. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpgetlayersize(const_cast(network.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgetinputscaling(const_cast(network.c_ptr()), i, &mean, &sigma, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. In case we have SOFTMAX-normalized network, we return (Mean,Sigma)=(0.0,1.0). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgetoutputscaling(const_cast(network.c_ptr()), i, &mean, &sigma, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) OUTPUT PARAMETERS: FKind - activation function type (used by MLPActivationFunction()) this value is zero for input or linear neurons Threshold - also called offset, bias zero for input neurons NOTE: this function throws exception if layer or neuron with given index do not exists. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgetneuroninfo(const_cast(network.c_ptr()), k, i, &fkind, &threshold, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function returns information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) RESULT: connection weight (zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. returns zero if neurons exist, but there is no connection between them -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ double mlpgetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpgetweight(const_cast(network.c_ptr()), k0, i0, k1, i1, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) NTE: I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network. This function sets Mean and Sigma. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetinputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetinputscaling(const_cast(network.c_ptr()), i, mean, sigma, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) OUTPUT PARAMETERS: NOTE: I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. This function sets Sigma/Mean. In case we have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything other than(0.0,1.0) - this function will throw exception. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetoutputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetoutputscaling(const_cast(network.c_ptr()), i, mean, sigma, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function modifies information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) FKind - activation function type (used by MLPActivationFunction()) this value must be zero for input neurons (you can not set activation function for input neurons) Threshold - also called offset, bias this value must be zero for input neurons (you can not set threshold for input neurons) NOTES: 1. this function throws exception if layer or neuron with given index do not exists. 2. this function also throws exception when you try to set non-linear activation function for input neurons (any kind of network) or for output neurons of classifier network. 3. this function throws exception when you try to set non-zero threshold for input neurons (any kind of network). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetneuroninfo(const_cast(network.c_ptr()), k, i, fkind, threshold, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function modifies information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) W - connection weight (must be zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. throws exception if you try to set non-zero weight for non-existent connection -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetweight(const_cast(network.c_ptr()), k0, i0, k1, i1, w, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Neural network activation function INPUT PARAMETERS: NET - neuron input K - function index (zero for linear function) OUTPUT PARAMETERS: F - function DF - its derivative D2F - its second derivative -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpactivationfunction(net, k, &f, &df, &d2f, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procesing INPUT PARAMETERS: Network - neural network X - input vector, array[0..NIn-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also MLPProcessI -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpprocess(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpprocess(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 'interactive' variant of MLPProcess for languages like Python which support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 21.09.2010 by Bochkanov Sergey *************************************************************************/ void mlpprocessi(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpprocessi(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlperror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Error of the neural network on dataset given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0 RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlperrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Natural error function for neural network, internal subroutine. NOTE: this function is single-threaded. Unlike other error function, it receives no speed-up from being executed in SMP mode. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperrorn(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperrorn(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Classification error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: classification error (number of misclassified cases) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mlpclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } ae_int_t smp_mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::_pexec_mlpclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Relative classification error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 25.12.2008 by Bochkanov Sergey *************************************************************************/ double mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlprelclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlprelclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Relative classification error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlprelclserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlprelclserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average cross-entropy (in bits per element) on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 08.01.2009 by Bochkanov Sergey *************************************************************************/ double mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgce(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgce(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average cross-entropy (in bits per element) on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 9.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgcesparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgcesparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set given. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlprmserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlprmserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlprmserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlprmserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average absolute error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average absolute error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average relative error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgrelerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgrelerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average relative error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpavgrelerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlpavgrelerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Gradient calculation INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgrad(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgrad(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(desiredy.c_ptr()), &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Gradient calculation (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradn(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradn(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(desiredy.c_ptr()), &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch gradient calculation for a set of inputs/outputs FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpgradbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch gradient calculation for a set of inputs/outputs given by sparse matrices FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs. * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradbatchsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpgradbatchsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch gradient calculation for a subset of dataset FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradbatchsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpgradbatchsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch gradient calculation for a set of inputs/outputs for a subset of dataset given by set of indexes. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse function. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradbatchsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpgradbatchsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch gradient calculation for a set of inputs/outputs (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - set of inputs/outputs; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradnbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpgradnbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch Hessian calculation (natural error function) using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessiannbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlphessiannbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), const_cast(h.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Batch Hessian calculation using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessianbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlphessianbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), const_cast(h.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpallerrorssubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpallerrorssubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset given by sparse matrix; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpallerrorssparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpallerrorssparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Error of the neural network on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperrorsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlperrorsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Error of the neural network on subset of sparse dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. SetSize - real size of XY, SetSize>=0; it is used when SubsetSize<0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperrorsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } double smp_mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::_pexec_mlperrorsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _logitmodel_owner::_logitmodel_owner() { p_struct = (alglib_impl::logitmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::logitmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_logitmodel_init(p_struct, NULL); } _logitmodel_owner::_logitmodel_owner(const _logitmodel_owner &rhs) { p_struct = (alglib_impl::logitmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::logitmodel), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_logitmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _logitmodel_owner& _logitmodel_owner::operator=(const _logitmodel_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_logitmodel_clear(p_struct); alglib_impl::_logitmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _logitmodel_owner::~_logitmodel_owner() { alglib_impl::_logitmodel_clear(p_struct); ae_free(p_struct); } alglib_impl::logitmodel* _logitmodel_owner::c_ptr() { return p_struct; } alglib_impl::logitmodel* _logitmodel_owner::c_ptr() const { return const_cast(p_struct); } logitmodel::logitmodel() : _logitmodel_owner() { } logitmodel::logitmodel(const logitmodel &rhs):_logitmodel_owner(rhs) { } logitmodel& logitmodel::operator=(const logitmodel &rhs) { if( this==&rhs ) return *this; _logitmodel_owner::operator=(rhs); return *this; } logitmodel::~logitmodel() { } /************************************************************************* MNLReport structure contains information about training process: * NGrad - number of gradient calculations * NHess - number of Hessian calculations *************************************************************************/ _mnlreport_owner::_mnlreport_owner() { p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mnlreport_init(p_struct, NULL); } _mnlreport_owner::_mnlreport_owner(const _mnlreport_owner &rhs) { p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mnlreport_owner& _mnlreport_owner::operator=(const _mnlreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mnlreport_clear(p_struct); alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mnlreport_owner::~_mnlreport_owner() { alglib_impl::_mnlreport_clear(p_struct); ae_free(p_struct); } alglib_impl::mnlreport* _mnlreport_owner::c_ptr() { return p_struct; } alglib_impl::mnlreport* _mnlreport_owner::c_ptr() const { return const_cast(p_struct); } mnlreport::mnlreport() : _mnlreport_owner() ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) { } mnlreport::mnlreport(const mnlreport &rhs):_mnlreport_owner(rhs) ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) { } mnlreport& mnlreport::operator=(const mnlreport &rhs) { if( this==&rhs ) return *this; _mnlreport_owner::operator=(rhs); return *this; } mnlreport::~mnlreport() { } /************************************************************************* This subroutine trains logit model. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars] First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(lm.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procesing INPUT PARAMETERS: LM - logit model, passed by non-constant reference (some fields of structure are used as temporaries when calculating model output). X - input vector, array[0..NVars-1]. Y - (possibly) preallocated buffer; if size of Y is less than NClasses, it will be reallocated.If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result, array[0..NClasses-1] Vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlprocess(const logitmodel &lm, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mnlprocess(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 'interactive' variant of MNLProcess for languages like Python which support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlprocessi(const logitmodel &lm, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mnlprocessi(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Unpacks coefficients of logit model. Logit model have form: P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when i(lm.c_ptr()), const_cast(a.c_ptr()), &nvars, &nclasses, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* "Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack reversed). INPUT PARAMETERS: A - model (see MNLUnpack) NVars - number of independent variables NClasses - number of classes OUTPUT PARAMETERS: LM - logit model. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlpack(const real_2d_array &a, const ae_int_t nvars, const ae_int_t nclasses, logitmodel &lm) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mnlpack(const_cast(a.c_ptr()), nvars, nclasses, const_cast(lm.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*ln(2)). -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgce(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mnlavgce(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ double mnlrelclserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mnlrelclserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: root mean square error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlrmserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mnlrmserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgerror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mnlavgerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average relative error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgrelerror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t ssize) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mnlavgrelerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), ssize, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Classification error on test set = MNLRelClsError*NPoints -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ ae_int_t mnlclserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::ae_int_t result = alglib_impl::mnlclserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This structure is a MCPD (Markov Chains for Population Data) solver. You should use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ _mcpdstate_owner::_mcpdstate_owner() { p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mcpdstate_init(p_struct, NULL); } _mcpdstate_owner::_mcpdstate_owner(const _mcpdstate_owner &rhs) { p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mcpdstate_owner& _mcpdstate_owner::operator=(const _mcpdstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mcpdstate_clear(p_struct); alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mcpdstate_owner::~_mcpdstate_owner() { alglib_impl::_mcpdstate_clear(p_struct); ae_free(p_struct); } alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() { return p_struct; } alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() const { return const_cast(p_struct); } mcpdstate::mcpdstate() : _mcpdstate_owner() { } mcpdstate::mcpdstate(const mcpdstate &rhs):_mcpdstate_owner(rhs) { } mcpdstate& mcpdstate::operator=(const mcpdstate &rhs) { if( this==&rhs ) return *this; _mcpdstate_owner::operator=(rhs); return *this; } mcpdstate::~mcpdstate() { } /************************************************************************* This structure is a MCPD training report: InnerIterationsCount - number of inner iterations of the underlying optimization algorithm OuterIterationsCount - number of outer iterations of the underlying optimization algorithm NFEV - number of merit function evaluations TerminationType - termination type (same as for MinBLEIC optimizer, positive values denote success, negative ones - failure) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ _mcpdreport_owner::_mcpdreport_owner() { p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mcpdreport_init(p_struct, NULL); } _mcpdreport_owner::_mcpdreport_owner(const _mcpdreport_owner &rhs) { p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mcpdreport_owner& _mcpdreport_owner::operator=(const _mcpdreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mcpdreport_clear(p_struct); alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mcpdreport_owner::~_mcpdreport_owner() { alglib_impl::_mcpdreport_clear(p_struct); ae_free(p_struct); } alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() { return p_struct; } alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() const { return const_cast(p_struct); } mcpdreport::mcpdreport() : _mcpdreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) { } mcpdreport::mcpdreport(const mcpdreport &rhs):_mcpdreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) { } mcpdreport& mcpdreport::operator=(const mcpdreport &rhs) { if( this==&rhs ) return *this; _mcpdreport_owner::operator=(rhs); return *this; } mcpdreport::~mcpdreport() { } /************************************************************************* DESCRIPTION: This function creates MCPD (Markov Chains for Population Data) solver. This solver can be used to find transition matrix P for N-dimensional prediction problem where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional population vectors (components of each X are non-negative), and P is a N*N transition matrix (elements of P are non-negative, each column sums to 1.0). Such models arise when when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is constant, i.e. there is no new individuals and no one leaves population * you want to model transitions of individuals from one state into another USAGE: Here we give very brief outline of the MCPD. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on data analysis which is available at http://www.alglib.net/dataanalysis/ 1. User initializes algorithm state with MCPDCreate() call 2. User adds one or more tracks - sequences of states which describe evolution of a system being modelled from different starting conditions 3. User may add optional boundary, equality and/or linear constraints on the coefficients of P by calling one of the following functions: * MCPDSetEC() to set equality constraints * MCPDSetBC() to set bound constraints * MCPDSetLC() to set linear constraints 4. Optionally, user may set custom weights for prediction errors (by default, algorithm assigns non-equal, automatically chosen weights for errors in the prediction of different components of X). It can be done with a call of MCPDSetPredictionWeights() function. 5. User calls MCPDSolve() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 6. User calls MCPDResults() to get solution INPUT PARAMETERS: N - problem dimension, N>=1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreate(const ae_int_t n, mcpdstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdcreate(n, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state Such conditions basically mean that row of P which corresponds to "entry" state is zero. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn, but still no one leaves population * you want to model transitions of individuals from one state into another * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdcreateentry(n, entrystate, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "exit" state and is treated in a special way: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that column of P which corresponds to "exit" state is zero. Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - individuals can move into "exit" state and leave population at the next turn, but there are no new individuals * amount of individuals which leave population can be predicted * you want to model transitions of individuals from one state into another (including transitions into the "exit" state) This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdcreateexit(n, exitstate, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-Exit-states" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state and another one component of X[] is called "exit" state and is treated in a special way too: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that: row of P which corresponds to "entry" state is zero column of P which corresponds to "exit" state is zero Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant * at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn * some individuals can move (predictably) into "exit" state and leave population at the next turn * you want to model transitions of individuals from one state into another, including transitions from the "entry" state and into the "exit" state. * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdcreateentryexit(n, entrystate, exitstate, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add a track - sequence of system states at the different moments of its evolution. You may add one or several tracks to the MCPD solver. In case you have several tracks, they won't overwrite each other. For example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont try to model transition from t=A+3 to t=B+1. INPUT PARAMETERS: S - solver XY - track, array[K,N]: * I-th row is a state at t=I * elements of XY must be non-negative (exception will be thrown on negative elements) K - number of points in a track * if given, only leading K rows of XY are used * if not given, automatically determined from size of XY NOTES: 1. Track may contain either proportional or population data: * with proportional data all rows of XY must sum to 1.0, i.e. we have proportions instead of absolute population values * with population data rows of XY contain population counts and generally do not sum to 1.0 (although they still must be non-negative) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdaddtrack(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add a track - sequence of system states at the different moments of its evolution. You may add one or several tracks to the MCPD solver. In case you have several tracks, they won't overwrite each other. For example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont try to model transition from t=A+3 to t=B+1. INPUT PARAMETERS: S - solver XY - track, array[K,N]: * I-th row is a state at t=I * elements of XY must be non-negative (exception will be thrown on negative elements) K - number of points in a track * if given, only leading K rows of XY are used * if not given, automatically determined from size of XY NOTES: 1. Track may contain either proportional or population data: * with proportional data all rows of XY must sum to 1.0, i.e. we have proportions instead of absolute population values * with population data rows of XY contain population counts and generally do not sum to 1.0 (although they still must be non-negative) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; k = xy.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdaddtrack(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place equality constraints on arbitrary subset of elements of P. Set of constraints is specified by EC, which may contain either NAN's or finite numbers from [0,1]. NAN denotes absence of constraint, finite number denotes equality constraint on specific element of P. You can also use MCPDAddEC() function which allows to ADD equality constraint for one element of P without changing constraints for other elements. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver EC - equality constraints, array[N,N]. Elements of EC can be either NAN's or finite numbers from [0,1]. NAN denotes absence of constraints, while finite value denotes equality constraint on the corresponding element of P. NOTES: 1. infinite values of EC will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetec(const mcpdstate &s, const real_2d_array &ec) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsetec(const_cast(s.c_ptr()), const_cast(ec.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD equality constraint for one element of P without changing constraints for other elements. You can also use MCPDSetEC() function which allows you to specify arbitrary set of equality constraints in one call. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver I - row index of element being constrained J - column index of element being constrained C - value (constraint for P[I,J]). Can be either NAN (no constraint) or finite value from [0,1]. NOTES: 1. infinite values of C will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddec(const mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdaddec(const_cast(s.c_ptr()), i, j, c, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF(s.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD bound constraint for one element of P without changing constraints for other elements. You can also use MCPDSetBC() function which allows to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF(s.c_ptr()), i, j, bndl, bndu, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to set linear equality/inequality constraints on the elements of the transition matrix P. This function can be used to set one or several general linear constraints on the elements of P. Two types of constraints are supported: * equality constraints * inequality constraints (both less-or-equal and greater-or-equal) Coefficients of constraints are specified by matrix C (one of the parameters). One row of C corresponds to one constraint. Because transition matrix P has N*N elements, we need N*N columns to store all coefficients (they are stored row by row), and one more column to store right part - hence C has N*N+1 columns. Constraint kind is stored in the CT array. Thus, I-th linear constraint is P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). Your constraint may involve only some subset of P (less than N*N elements). For example it can be something like P[0,0] + P[0,1] = 0.5 In this case you still should pass matrix with N*N+1 columns, but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. INPUT PARAMETERS: S - solver C - array[K,N*N+1] - coefficients of constraints (see above for complete description) CT - array[K] - constraint types (see above for complete description) K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsetlc(const_cast(s.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to set linear equality/inequality constraints on the elements of the transition matrix P. This function can be used to set one or several general linear constraints on the elements of P. Two types of constraints are supported: * equality constraints * inequality constraints (both less-or-equal and greater-or-equal) Coefficients of constraints are specified by matrix C (one of the parameters). One row of C corresponds to one constraint. Because transition matrix P has N*N elements, we need N*N columns to store all coefficients (they are stored row by row), and one more column to store right part - hence C has N*N+1 columns. Constraint kind is stored in the CT array. Thus, I-th linear constraint is P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). Your constraint may involve only some subset of P (less than N*N elements). For example it can be something like P[0,0] + P[0,1] = 0.5 In this case you still should pass matrix with N*N+1 columns, but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. INPUT PARAMETERS: S - solver C - array[K,N*N+1] - coefficients of constraints (see above for complete description) CT - array[K] - constraint types (see above for complete description) K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; if( (c.rows()!=ct.length())) throw ap_error("Error while calling 'mcpdsetlc': looks like one of arguments has wrong size"); k = c.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsetlc(const_cast(s.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function allows to tune amount of Tikhonov regularization being applied to your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change coefficient r. You can also change prior values with MCPDSetPrior() function. INPUT PARAMETERS: S - solver V - regularization coefficient, finite non-negative value. It is not recommended to specify zero value unless you are pretty sure that you want it. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsettikhonovregularizer(const mcpdstate &s, const double v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsettikhonovregularizer(const_cast(s.c_ptr()), v, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function allows to set prior values used for regularization of your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change prior values prior_P. You can also change r with MCPDSetTikhonovRegularizer() function. INPUT PARAMETERS: S - solver PP - array[N,N], matrix of prior values: 1. elements must be real numbers from [0,1] 2. columns must sum to 1.0. First property is checked (exception is thrown otherwise), while second one is not checked/enforced. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetprior(const mcpdstate &s, const real_2d_array &pp) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsetprior(const_cast(s.c_ptr()), const_cast(pp.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to change prediction weights MCPD solver scales prediction errors as follows Error(P) = ||W*(y-P*x)||^2 where x is a system state at time t y is a system state at time t+1 P is a transition matrix W is a diagonal scaling matrix By default, weights are chosen in order to minimize relative prediction error instead of absolute one. For example, if one component of state is about 0.5 in magnitude and another one is about 0.05, then algorithm will make corresponding weights equal to 2.0 and 20.0. INPUT PARAMETERS: S - solver PW - array[N], weights: * must be non-negative values (exception will be thrown otherwise) * zero values will be replaced by automatically chosen values -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetpredictionweights(const mcpdstate &s, const real_1d_array &pw) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsetpredictionweights(const_cast(s.c_ptr()), const_cast(pw.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to start solution of the MCPD problem. After return from this function, you can use MCPDResults() to get solution and completion code. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsolve(const mcpdstate &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdsolve(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* MCPD results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: P - array[N,N], transition matrix Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one. Speaking short, positive values denote success, negative ones are failures. More information about fields of this structure can be found in the comments on MCPDReport datatype. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mcpdresults(const_cast(s.c_ptr()), const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Neural networks ensemble *************************************************************************/ _mlpensemble_owner::_mlpensemble_owner() { p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpensemble_init(p_struct, NULL); } _mlpensemble_owner::_mlpensemble_owner(const _mlpensemble_owner &rhs) { p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mlpensemble_owner& _mlpensemble_owner::operator=(const _mlpensemble_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mlpensemble_clear(p_struct); alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mlpensemble_owner::~_mlpensemble_owner() { alglib_impl::_mlpensemble_clear(p_struct); ae_free(p_struct); } alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() { return p_struct; } alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() const { return const_cast(p_struct); } mlpensemble::mlpensemble() : _mlpensemble_owner() { } mlpensemble::mlpensemble(const mlpensemble &rhs):_mlpensemble_owner(rhs) { } mlpensemble& mlpensemble::operator=(const mlpensemble &rhs) { if( this==&rhs ) return *this; _mlpensemble_owner::operator=(rhs); return *this; } mlpensemble::~mlpensemble() { } /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void mlpeserialize(mlpensemble &obj, std::string &s_out) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_int_t ssize; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_alloc_start(&serializer); alglib_impl::mlpealloc(&serializer, obj.c_ptr(), &state); ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); s_out.clear(); s_out.reserve((size_t)(ssize+1)); alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); alglib_impl::mlpeserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); if( s_out.length()>(size_t)ssize ) throw ap_error("ALGLIB: serialization integrity error"); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void mlpeunserialize(std::string &s_in, mlpensemble &obj) { alglib_impl::ae_state state; alglib_impl::ae_serializer serializer; alglib_impl::ae_state_init(&state); try { alglib_impl::ae_serializer_init(&serializer); alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); alglib_impl::mlpeunserialize(&serializer, obj.c_ptr(), &state); alglib_impl::ae_serializer_stop(&serializer); alglib_impl::ae_serializer_clear(&serializer); alglib_impl::ae_state_clear(&state); } catch(alglib_impl::ae_error_type) { throw ap_error(state.error_msg); } } /************************************************************************* Like MLPCreate0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreate0(nin, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreate1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreate1(nin, nhid, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreate2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreate2(nin, nhid1, nhid2, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateB0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreateb0(nin, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateB1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreateb1(nin, nhid, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateB2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreateb2(nin, nhid1, nhid2, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateR0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreater0(nin, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateR1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreater1(nin, nhid, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateR2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreater2(nin, nhid1, nhid2, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateC0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreatec0(nin, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateC1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreatec1(nin, nhid, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Like MLPCreateC2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreatec2(nin, nhid1, nhid2, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpecreatefromnetwork(const_cast(network.c_ptr()), ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlperandomize(const mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlperandomize(const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpeproperties(const_cast(ensemble.c_ptr()), &nin, &nout, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ bool mlpeissoftmax(const mlpensemble &ensemble) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::mlpeissoftmax(const_cast(ensemble.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocess(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpeprocess(const_cast(ensemble.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* 'interactive' variant of MLPEProcess for languages like Python which support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocessi(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpeprocessi(const_cast(ensemble.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Works both for classifier betwork and for regression networks which are used as classifiers. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlperelclserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlperelclserror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if ensemble solves regression task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgce(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpeavgce(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* RMS error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpermserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpermserror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpeavgerror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgrelerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { double result = alglib_impl::mlpeavgrelerror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Training report: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error * NGrad - number of gradient calculations * NHess - number of Hessian calculations * NCholesky - number of Cholesky decompositions NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/ _mlpreport_owner::_mlpreport_owner() { p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpreport_init(p_struct, NULL); } _mlpreport_owner::_mlpreport_owner(const _mlpreport_owner &rhs) { p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mlpreport_owner& _mlpreport_owner::operator=(const _mlpreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mlpreport_clear(p_struct); alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mlpreport_owner::~_mlpreport_owner() { alglib_impl::_mlpreport_clear(p_struct); ae_free(p_struct); } alglib_impl::mlpreport* _mlpreport_owner::c_ptr() { return p_struct; } alglib_impl::mlpreport* _mlpreport_owner::c_ptr() const { return const_cast(p_struct); } mlpreport::mlpreport() : _mlpreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) { } mlpreport::mlpreport(const mlpreport &rhs):_mlpreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) { } mlpreport& mlpreport::operator=(const mlpreport &rhs) { if( this==&rhs ) return *this; _mlpreport_owner::operator=(rhs); return *this; } mlpreport::~mlpreport() { } /************************************************************************* Cross-validation estimates of generalization error *************************************************************************/ _mlpcvreport_owner::_mlpcvreport_owner() { p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpcvreport_init(p_struct, NULL); } _mlpcvreport_owner::_mlpcvreport_owner(const _mlpcvreport_owner &rhs) { p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mlpcvreport_owner& _mlpcvreport_owner::operator=(const _mlpcvreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mlpcvreport_clear(p_struct); alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mlpcvreport_owner::~_mlpcvreport_owner() { alglib_impl::_mlpcvreport_clear(p_struct); ae_free(p_struct); } alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() { return p_struct; } alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() const { return const_cast(p_struct); } mlpcvreport::mlpcvreport() : _mlpcvreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) { } mlpcvreport::mlpcvreport(const mlpcvreport &rhs):_mlpcvreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) { } mlpcvreport& mlpcvreport::operator=(const mlpcvreport &rhs) { if( this==&rhs ) return *this; _mlpcvreport_owner::operator=(rhs); return *this; } mlpcvreport::~mlpcvreport() { } /************************************************************************* Trainer object for neural network. You should not try to access fields of this object directly - use ALGLIB functions to work with this object. *************************************************************************/ _mlptrainer_owner::_mlptrainer_owner() { p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlptrainer_init(p_struct, NULL); } _mlptrainer_owner::_mlptrainer_owner(const _mlptrainer_owner &rhs) { p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mlptrainer_owner& _mlptrainer_owner::operator=(const _mlptrainer_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mlptrainer_clear(p_struct); alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mlptrainer_owner::~_mlptrainer_owner() { alglib_impl::_mlptrainer_clear(p_struct); ae_free(p_struct); } alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() { return p_struct; } alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() const { return const_cast(p_struct); } mlptrainer::mlptrainer() : _mlptrainer_owner() { } mlptrainer::mlptrainer(const mlptrainer &rhs):_mlptrainer_owner(rhs) { } mlptrainer& mlptrainer::operator=(const mlptrainer &rhs) { if( this==&rhs ) return *this; _mlptrainer_owner::operator=(rhs); return *this; } mlptrainer::~mlptrainer() { } /************************************************************************* Neural network training using modified Levenberg-Marquardt with exact Hessian calculation and regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for small and medium scale problems (hundreds of weights). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -9, if internal matrix inverse subroutine failed * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptrainlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlptrainlm(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Neural network training using L-BFGS algorithm with regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for problems of any dimensionality (memory requirements and step complexity are linear by weights number). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. MaxIts - stopping criterion. Algorithm stops after MaxIts iterations (NOT gradient calculations). Zero MaxIts means stopping when step is sufficiently small. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlptrainlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlptrainlbfgs(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Neural network training using early stopping (base algorithm - L-BFGS with regularization). INPUT PARAMETERS: Network - neural network with initialized geometry TrnXY - training set TrnSize - training set size, TrnSize>0 ValXY - validation set ValSize - validation set size, ValSize>0 Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts, either: * strictly positive number - algorithm make specified number of restarts from random position. * -1, in which case algorithm makes exactly one run from the initial state of the network (no randomization). If you don't know what Restarts to choose, choose one one the following: * -1 (deterministic start) * +1 (one random restart) * +5 (moderate amount of random restarts) OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1, ...). * 2, task has been solved, stopping criterion met - sufficiently small step size. Not expected (we use EARLY stopping) but possible and not an error. * 6, task has been solved, stopping criterion met - increasing of validation set error. Rep - training report NOTE: Algorithm stops if validation set error increases for a long enough or step size is small enought (there are task where validation set may decrease for eternity). In any case solution returned corresponds to the minimum of validation set error. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptraines(const multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlptraines(const_cast(network.c_ptr()), const_cast(trnxy.c_ptr()), trnsize, const_cast(valxy.c_ptr()), valsize, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - L-BFGS. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpkfoldcvlbfgs(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, foldscount, &info, const_cast(rep.c_ptr()), const_cast(cvrep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - Levenberg-Marquardt. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpkfoldcvlm(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, foldscount, &info, const_cast(rep.c_ptr()), const_cast(cvrep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function estimates generalization error using cross-validation on the current dataset with current training settings. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * FoldsCount cross-validation rounds (always) ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. Network is not changed during cross- validation and is not trained - it is used only as representative of its architecture. I.e., we estimate generalization properties of ARCHITECTURE, not some specific network. NRestarts - number of restarts, >=0: * NRestarts>0 means that for each cross-validation round specified number of random restarts is performed, with best network being chosen after training. * NRestarts=0 is same as NRestarts=1 FoldsCount - number of folds in k-fold cross-validation: * 2<=FoldsCount<=size of dataset * recommended value: 10. * values larger than dataset size will be silently truncated down to dataset size OUTPUT PARAMETERS: Rep - structure which contains cross-validation estimates: * Rep.RelCLSError - fraction of misclassified cases. * Rep.AvgCE - acerage cross-entropy * Rep.RMSError - root-mean-square error * Rep.AvgError - average error * Rep.AvgRelError - average relative error NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or subset with only one point was given, zeros are returned as estimates. NOTE: this method performs FoldsCount cross-validation rounds, each one with NRestarts random starts. Thus, FoldsCount*NRestarts networks are trained in total. NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError contain errors in prediction of posterior probabilities. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpkfoldcv(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, foldscount, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlpkfoldcv(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, foldscount, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creation of the network trainer object for regression networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NOut - number of outputs, NOut>=1 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any regression network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreatetrainer(nin, nout, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Creation of the network trainer object for classification networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any classification network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpcreatetrainercls(nin, nclasses, const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user. INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. NPoints - points count, >=0. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdataset(const mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetdataset(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user (sparse matrix is used to store dataset). INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Any sparse storage format can be used: Hash-table, CRS... NPoints - points count, >=0 DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetsparsedataset(const mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetsparsedataset(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets weight decay coefficient which is used for training. INPUT PARAMETERS: S - trainer object Decay - weight decay coefficient, >=0. Weight decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 1.0E-3. Weight decay can be set to zero, in this case network is trained without weight decay. NOTE: by default network uses some small nonzero value for weight decay. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdecay(const mlptrainer &s, const double decay) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetdecay(const_cast(s.c_ptr()), decay, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping criteria for the optimizer. INPUT PARAMETERS: S - trainer object WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. WStep>=0. MaxIts - stopping criterion. Algorithm stops after MaxIts epochs (full passes over entire dataset). Zero MaxIts means stopping when step is sufficiently small. MaxIts>=0. NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also used when MLPSetCond() is called with WStep=0 and MaxIts=0. NOTE: these stopping criteria are used for all kinds of neural training - from "conventional" networks to early stopping ensembles. When used for "conventional" networks, they are used as the only stopping criteria. When combined with early stopping, they used as ADDITIONAL stopping criteria which can terminate early stopping algorithm. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetcond(const mlptrainer &s, const double wstep, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetcond(const_cast(s.c_ptr()), wstep, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets training algorithm: batch training using L-BFGS will be used. This algorithm: * the most robust for small-scale problems, but may be too slow for large scale ones. * perfoms full pass through the dataset before performing step * uses conditions specified by MLPSetCond() for stopping * is default one used by trainer object INPUT PARAMETERS: S - trainer object -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetalgobatch(const mlptrainer &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpsetalgobatch(const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function trains neural network passed to this function, using current dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) and current training settings. Training from NRestarts random starting positions is performed, best network is chosen. Training is performed using current training algorithm. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed, best network is chosen after training * NRestarts=0 means that current state of the network is used for training. OUTPUT PARAMETERS: Network - trained network NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), network is filled by zero values. Same behavior for functions MLPStartTraining and MLPContinueTraining. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlptrainnetwork(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlptrainnetwork(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. After call to this function trainer object remembers network and is ready to train it. However, no training is performed until first call to MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() will advance training progress one iteration further. EXAMPLE: > > ...initialize network and trainer object.... > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > ...visualize training progress... > INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. RandomStart - randomize network before training or not: * True means that network is randomized and its initial state (one which was passed to the trainer object) is lost. * False means that training is started from the current state of the network OUTPUT PARAMETERS: Network - neural network which is ready to training (weights are initialized, preprocessor is initialized using current training set) NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpstarttraining(const mlptrainer &s, const multilayerperceptron &network, const bool randomstart) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpstarttraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), randomstart, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. This function performs one more iteration of the training and returns either True (training continues) or False (training stopped). In case True was returned, Network weights are updated according to the current state of the optimization progress. In case False was returned, no additional updates is performed (previous update of the network weights moved us to the final point, and no additional updates is needed). EXAMPLE: > > [initialize network and trainer object] > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > [visualize training progress] > INPUT PARAMETERS: S - trainer object Network - neural network structure, which is used to store current state of the training process. OUTPUT PARAMETERS: Network - weights of the neural network are rewritten by the current approximation. NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. NOTE: It is expected that Network is the same one which was passed to MLPStartTraining() function. However, THIS function checks only following: * that number of network inputs is consistent with trainer object settings * that number of network outputs/classes is consistent with trainer object settings * that number of network weights is the same as number of weights in the network passed to MLPStartTraining() function Exception is thrown when these conditions are violated. It is also expected that you do not change state of the network on your own - the only party who has right to change network during its training is a trainer object. Any attempt to interfere with trainer may lead to unpredictable results. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ bool mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::mlpcontinuetraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } bool smp_mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::_pexec_mlpcontinuetraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). Modified Levenberg-Marquardt algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglm(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpebagginglm(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), const_cast(ooberrors.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). L-BFGS algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglbfgs(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpebagginglbfgs(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, &info, const_cast(rep.c_ptr()), const_cast(ooberrors.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Training neural networks ensemble using early stopping. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 6, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlpetraines(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlpetraines(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function trains neural network ensemble passed to this function using current dataset and early stopping training algorithm. Each early stopping round performs NRestarts random restarts (thus, EnsembleSize*NRestarts training rounds is performed in total). FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * EnsembleSize training sessions performed for each of ensemble ! members (always parallelized) ! * NRestarts training sessions performed within each of training ! sessions (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object; Ensemble - neural network ensemble. It must have same number of inputs and outputs/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed during each ES round; * NRestarts=0 is silently replaced by 1. OUTPUT PARAMETERS: Ensemble - trained ensemble; Rep - it contains all type of errors. NOTE: this training method uses BOTH early stopping and weight decay! So, you should select weight decay before starting training just as you select it before training "conventional" networks. NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or single-point dataset was passed, ensemble is filled by zero values. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 22.08.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mlptrainensemblees(const_cast(s.c_ptr()), const_cast(ensemble.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_mlptrainensemblees(const_cast(s.c_ptr()), const_cast(ensemble.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Principal components analysis Subroutine builds orthogonal basis where first axis corresponds to direction with maximum variance, second axis maximizes variance in subspace orthogonal to first axis and so on. It should be noted that, unlike LDA, PCA does not use class labels. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - dataset, array[0..NPoints-1,0..NVars-1]. matrix contains ONLY INDEPENDENT VARIABLES. NPoints - dataset size, NPoints>=0 NVars - number of independent variables, NVars>=1 OUTPUT PARAMETERS: Info - return code: * -4, if SVD subroutine haven't converged * -1, if wrong parameters has been passed (NPoints<0, NVars<1) * 1, if task is solved S2 - array[0..NVars-1]. variance values corresponding to basis vectors. V - array[0..NVars-1,0..NVars-1] matrix, whose columns store basis vectors. -- ALGLIB -- Copyright 25.08.2008 by Bochkanov Sergey *************************************************************************/ void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, real_1d_array &s2, real_2d_array &v) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::pcabuildbasis(const_cast(x.c_ptr()), npoints, nvars, &info, const_cast(s2.c_ptr()), const_cast(v.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static double bdss_xlny(double x, double y, ae_state *_state); static double bdss_getcv(/* Integer */ ae_vector* cnt, ae_int_t nc, ae_state *_state); static void bdss_tieaddc(/* Integer */ ae_vector* c, /* Integer */ ae_vector* ties, ae_int_t ntie, ae_int_t nc, /* Integer */ ae_vector* cnt, ae_state *_state); static void bdss_tiesubc(/* Integer */ ae_vector* c, /* Integer */ ae_vector* ties, ae_int_t ntie, ae_int_t nc, /* Integer */ ae_vector* cnt, ae_state *_state); static double clustering_parallelcomplexity = 200000; static ae_int_t clustering_kmeansblocksize = 32; static ae_int_t clustering_kmeansparalleldim = 8; static ae_int_t clustering_kmeansparallelk = 8; static void clustering_selectinitialcenters(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t initalgo, ae_int_t k, /* Real */ ae_matrix* ct, apbuffers* initbuf, ae_shared_pool* updatepool, ae_state *_state); static ae_bool clustering_fixcenters(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t k, apbuffers* initbuf, ae_shared_pool* updatepool, ae_state *_state); static void clustering_clusterizerrunahcinternal(clusterizerstate* s, /* Real */ ae_matrix* d, ahcreport* rep, ae_state *_state); static void clustering_evaluatedistancematrixrec(/* Real */ ae_matrix* xy, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_int_t i0, ae_int_t i1, ae_int_t j0, ae_int_t j1, ae_state *_state); static ae_int_t dforest_innernodewidth = 3; static ae_int_t dforest_leafnodewidth = 2; static ae_int_t dforest_dfusestrongsplits = 1; static ae_int_t dforest_dfuseevs = 2; static ae_int_t dforest_dffirstversion = 0; static ae_int_t dforest_dfclserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); static void dforest_dfprocessinternal(decisionforest* df, ae_int_t offs, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); static void dforest_dfbuildtree(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t nfeatures, ae_int_t nvarsinpool, ae_int_t flags, dfinternalbuffers* bufs, hqrndstate* rs, ae_state *_state); static void dforest_dfbuildtreerec(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t nfeatures, ae_int_t nvarsinpool, ae_int_t flags, ae_int_t* numprocessed, ae_int_t idx1, ae_int_t idx2, dfinternalbuffers* bufs, hqrndstate* rs, ae_state *_state); static void dforest_dfsplitc(/* Real */ ae_vector* x, /* Integer */ ae_vector* c, /* Integer */ ae_vector* cntbuf, ae_int_t n, ae_int_t nc, ae_int_t flags, ae_int_t* info, double* threshold, double* e, /* Real */ ae_vector* sortrbuf, /* Integer */ ae_vector* sortibuf, ae_state *_state); static void dforest_dfsplitr(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t flags, ae_int_t* info, double* threshold, double* e, /* Real */ ae_vector* sortrbuf, /* Real */ ae_vector* sortrbuf2, ae_state *_state); static ae_int_t linreg_lrvnum = 5; static void linreg_lrinternal(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state); static ae_int_t mlpbase_mlpvnum = 7; static ae_int_t mlpbase_mlpfirstversion = 0; static ae_int_t mlpbase_nfieldwidth = 4; static ae_int_t mlpbase_hlconnfieldwidth = 5; static ae_int_t mlpbase_hlnfieldwidth = 4; static ae_int_t mlpbase_gradbasecasecost = 50000; static ae_int_t mlpbase_microbatchsize = 64; static void mlpbase_addinputlayer(ae_int_t ncount, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state); static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state); static void mlpbase_addactivationlayer(ae_int_t functype, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state); static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state); static void mlpbase_hladdinputlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t nin, ae_state *_state); static void mlpbase_hladdoutputlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t* weightsidx, ae_int_t k, ae_int_t nprev, ae_int_t nout, ae_bool iscls, ae_bool islinearout, ae_state *_state); static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t* weightsidx, ae_int_t k, ae_int_t nprev, ae_int_t ncur, ae_state *_state); static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_bool iscls, ae_bool islinearout, ae_state *_state); static void mlpbase_mlpcreate(ae_int_t nin, ae_int_t nout, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t layerscount, ae_bool isclsnet, multilayerperceptron* network, ae_state *_state); static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_bool naturalerr, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state); static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, /* Real */ ae_vector* neurons, /* Real */ ae_vector* weights, /* Real */ ae_vector* derror, /* Real */ ae_vector* grad, ae_bool naturalerrorfunc, ae_state *_state); static void mlpbase_mlpchunkedgradient(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, double* e, ae_bool naturalerrorfunc, ae_state *_state); static void mlpbase_mlpchunkedprocess(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, ae_state *_state); static double mlpbase_safecrossentropy(double t, double z, ae_state *_state); static void mlpbase_randomizebackwardpass(multilayerperceptron* network, ae_int_t neuronidx, double v, ae_state *_state); static double logit_xtol = 100*ae_machineepsilon; static double logit_ftol = 0.0001; static double logit_gtol = 0.3; static ae_int_t logit_maxfev = 20; static double logit_stpmin = 1.0E-2; static double logit_stpmax = 1.0E5; static ae_int_t logit_logitvnum = 6; static void logit_mnliexp(/* Real */ ae_vector* w, /* Real */ ae_vector* x, ae_state *_state); static void logit_mnlallerrors(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, double* relcls, double* avgce, double* rms, double* avg, double* avgrel, ae_state *_state); static void logit_mnlmcsrch(ae_int_t n, /* Real */ ae_vector* x, double* f, /* Real */ ae_vector* g, /* Real */ ae_vector* s, double* stp, ae_int_t* info, ae_int_t* nfev, /* Real */ ae_vector* wa, logitmcstate* state, ae_int_t* stage, ae_state *_state); static void logit_mnlmcstep(double* stx, double* fx, double* dx, double* sty, double* fy, double* dy, double* stp, double fp, double dp, ae_bool* brackt, double stmin, double stmax, ae_int_t* info, ae_state *_state); static double mcpd_xtol = 1.0E-8; static void mcpd_mcpdinit(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state); static ae_int_t mlpe_mlpefirstversion = 1; static double mlptrain_mindecay = 0.001; static ae_int_t mlptrain_defaultlbfgsfactor = 6; static void mlptrain_mlpkfoldcvgeneral(multilayerperceptron* n, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t foldscount, ae_bool lmalgorithm, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state); static void mlptrain_mlpkfoldsplit(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nclasses, ae_int_t foldscount, ae_bool stratifiedsplits, /* Integer */ ae_vector* folds, ae_state *_state); static void mlptrain_mthreadcv(mlptrainer* s, ae_int_t rowsize, ae_int_t nrestarts, /* Integer */ ae_vector* folds, ae_int_t fold, ae_int_t dfold, /* Real */ ae_matrix* cvy, ae_shared_pool* pooldatacv, ae_state *_state); static void mlptrain_mlptrainnetworkx(mlptrainer* s, ae_int_t nrestarts, ae_int_t algokind, /* Integer */ ae_vector* trnsubset, ae_int_t trnsubsetsize, /* Integer */ ae_vector* valsubset, ae_int_t valsubsetsize, multilayerperceptron* network, mlpreport* rep, ae_bool isrootcall, ae_shared_pool* sessions, ae_state *_state); static void mlptrain_mlptrainensemblex(mlptrainer* s, mlpensemble* ensemble, ae_int_t idx0, ae_int_t idx1, ae_int_t nrestarts, ae_int_t trainingmethod, sinteger* ngrad, ae_bool isrootcall, ae_shared_pool* esessions, ae_state *_state); static void mlptrain_mlpstarttrainingx(mlptrainer* s, ae_bool randomstart, ae_int_t algokind, /* Integer */ ae_vector* subset, ae_int_t subsetsize, smlptrnsession* session, ae_state *_state); static ae_bool mlptrain_mlpcontinuetrainingx(mlptrainer* s, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_int_t* ngradbatch, smlptrnsession* session, ae_state *_state); static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_bool lmalgorithm, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state); static void mlptrain_initmlptrnsession(multilayerperceptron* networktrained, ae_bool randomizenetwork, mlptrainer* trainer, smlptrnsession* session, ae_state *_state); static void mlptrain_initmlptrnsessions(multilayerperceptron* networktrained, ae_bool randomizenetwork, mlptrainer* trainer, ae_shared_pool* sessions, ae_state *_state); static void mlptrain_initmlpetrnsession(multilayerperceptron* individualnetwork, mlptrainer* trainer, mlpetrnsession* session, ae_state *_state); static void mlptrain_initmlpetrnsessions(multilayerperceptron* individualnetwork, mlptrainer* trainer, ae_shared_pool* sessions, ae_state *_state); /************************************************************************* This set of routines (DSErrAllocate, DSErrAccumulate, DSErrFinish) calculates different error functions (classification error, cross-entropy, rms, avg, avg.rel errors). 1. DSErrAllocate prepares buffer. 2. DSErrAccumulate accumulates individual errors: * Y contains predicted output (posterior probabilities for classification) * DesiredY contains desired output (class number for classification) 3. DSErrFinish outputs results: * Buf[0] contains relative classification error (zero for regression tasks) * Buf[1] contains avg. cross-entropy (zero for regression tasks) * Buf[2] contains rms error (regression, classification) * Buf[3] contains average error (regression, classification) * Buf[4] contains average relative error (regression, classification) NOTES(1): "NClasses>0" means that we have classification task. "NClasses<0" means regression task with -NClasses real outputs. NOTES(2): rms. avg, avg.rel errors for classification tasks are interpreted as errors in posterior probabilities with respect to probabilities given by training/test set. -- ALGLIB -- Copyright 11.01.2009 by Bochkanov Sergey *************************************************************************/ void dserrallocate(ae_int_t nclasses, /* Real */ ae_vector* buf, ae_state *_state) { ae_vector_clear(buf); ae_vector_set_length(buf, 7+1, _state); buf->ptr.p_double[0] = (double)(0); buf->ptr.p_double[1] = (double)(0); buf->ptr.p_double[2] = (double)(0); buf->ptr.p_double[3] = (double)(0); buf->ptr.p_double[4] = (double)(0); buf->ptr.p_double[5] = (double)(nclasses); buf->ptr.p_double[6] = (double)(0); buf->ptr.p_double[7] = (double)(0); } /************************************************************************* See DSErrAllocate for comments on this routine. -- ALGLIB -- Copyright 11.01.2009 by Bochkanov Sergey *************************************************************************/ void dserraccumulate(/* Real */ ae_vector* buf, /* Real */ ae_vector* y, /* Real */ ae_vector* desiredy, ae_state *_state) { ae_int_t nclasses; ae_int_t nout; ae_int_t offs; ae_int_t mmax; ae_int_t rmax; ae_int_t j; double v; double ev; offs = 5; nclasses = ae_round(buf->ptr.p_double[offs], _state); if( nclasses>0 ) { /* * Classification */ rmax = ae_round(desiredy->ptr.p_double[0], _state); mmax = 0; for(j=1; j<=nclasses-1; j++) { if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) { mmax = j; } } if( mmax!=rmax ) { buf->ptr.p_double[0] = buf->ptr.p_double[0]+1; } if( ae_fp_greater(y->ptr.p_double[rmax],(double)(0)) ) { buf->ptr.p_double[1] = buf->ptr.p_double[1]-ae_log(y->ptr.p_double[rmax], _state); } else { buf->ptr.p_double[1] = buf->ptr.p_double[1]+ae_log(ae_maxrealnumber, _state); } for(j=0; j<=nclasses-1; j++) { v = y->ptr.p_double[j]; if( j==rmax ) { ev = (double)(1); } else { ev = (double)(0); } buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); if( ae_fp_neq(ev,(double)(0)) ) { buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+1; } } buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+1; } else { /* * Regression */ nout = -nclasses; rmax = 0; for(j=1; j<=nout-1; j++) { if( ae_fp_greater(desiredy->ptr.p_double[j],desiredy->ptr.p_double[rmax]) ) { rmax = j; } } mmax = 0; for(j=1; j<=nout-1; j++) { if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) { mmax = j; } } if( mmax!=rmax ) { buf->ptr.p_double[0] = buf->ptr.p_double[0]+1; } for(j=0; j<=nout-1; j++) { v = y->ptr.p_double[j]; ev = desiredy->ptr.p_double[j]; buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); if( ae_fp_neq(ev,(double)(0)) ) { buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+1; } } buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+1; } } /************************************************************************* See DSErrAllocate for comments on this routine. -- ALGLIB -- Copyright 11.01.2009 by Bochkanov Sergey *************************************************************************/ void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state) { ae_int_t nout; ae_int_t offs; offs = 5; nout = ae_iabs(ae_round(buf->ptr.p_double[offs], _state), _state); if( ae_fp_neq(buf->ptr.p_double[offs+1],(double)(0)) ) { buf->ptr.p_double[0] = buf->ptr.p_double[0]/buf->ptr.p_double[offs+1]; buf->ptr.p_double[1] = buf->ptr.p_double[1]/buf->ptr.p_double[offs+1]; buf->ptr.p_double[2] = ae_sqrt(buf->ptr.p_double[2]/(nout*buf->ptr.p_double[offs+1]), _state); buf->ptr.p_double[3] = buf->ptr.p_double[3]/(nout*buf->ptr.p_double[offs+1]); } if( ae_fp_neq(buf->ptr.p_double[offs+2],(double)(0)) ) { buf->ptr.p_double[4] = buf->ptr.p_double[4]/buf->ptr.p_double[offs+2]; } } /************************************************************************* -- ALGLIB -- Copyright 19.05.2008 by Bochkanov Sergey *************************************************************************/ void dsnormalize(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* means, /* Real */ ae_vector* sigmas, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector tmp; double mean; double variance; double skewness; double kurtosis; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(means); ae_vector_clear(sigmas); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * Test parameters */ if( npoints<=0||nvars<1 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Standartization */ ae_vector_set_length(means, nvars-1+1, _state); ae_vector_set_length(sigmas, nvars-1+1, _state); ae_vector_set_length(&tmp, npoints-1+1, _state); for(j=0; j<=nvars-1; j++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); means->ptr.p_double[j] = mean; sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); if( ae_fp_eq(sigmas->ptr.p_double[j],(double)(0)) ) { sigmas->ptr.p_double[j] = (double)(1); } for(i=0; i<=npoints-1; i++) { xy->ptr.pp_double[i][j] = (xy->ptr.pp_double[i][j]-means->ptr.p_double[j])/sigmas->ptr.p_double[j]; } } ae_frame_leave(_state); } /************************************************************************* -- ALGLIB -- Copyright 19.05.2008 by Bochkanov Sergey *************************************************************************/ void dsnormalizec(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* means, /* Real */ ae_vector* sigmas, ae_state *_state) { ae_frame _frame_block; ae_int_t j; ae_vector tmp; double mean; double variance; double skewness; double kurtosis; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(means); ae_vector_clear(sigmas); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * Test parameters */ if( npoints<=0||nvars<1 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Standartization */ ae_vector_set_length(means, nvars-1+1, _state); ae_vector_set_length(sigmas, nvars-1+1, _state); ae_vector_set_length(&tmp, npoints-1+1, _state); for(j=0; j<=nvars-1; j++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); means->ptr.p_double[j] = mean; sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); if( ae_fp_eq(sigmas->ptr.p_double[j],(double)(0)) ) { sigmas->ptr.p_double[j] = (double)(1); } } ae_frame_leave(_state); } /************************************************************************* -- ALGLIB -- Copyright 19.05.2008 by Bochkanov Sergey *************************************************************************/ double dsgetmeanmindistance(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector tmp; ae_vector tmp2; double v; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); /* * Test parameters */ if( npoints<=0||nvars<1 ) { result = (double)(0); ae_frame_leave(_state); return result; } /* * Process */ ae_vector_set_length(&tmp, npoints-1+1, _state); for(i=0; i<=npoints-1; i++) { tmp.ptr.p_double[i] = ae_maxrealnumber; } ae_vector_set_length(&tmp2, nvars-1+1, _state); for(i=0; i<=npoints-1; i++) { for(j=i+1; j<=npoints-1; j++) { ae_v_move(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); v = ae_sqrt(v, _state); tmp.ptr.p_double[i] = ae_minreal(tmp.ptr.p_double[i], v, _state); tmp.ptr.p_double[j] = ae_minreal(tmp.ptr.p_double[j], v, _state); } } result = (double)(0); for(i=0; i<=npoints-1; i++) { result = result+tmp.ptr.p_double[i]/npoints; } ae_frame_leave(_state); return result; } /************************************************************************* -- ALGLIB -- Copyright 19.05.2008 by Bochkanov Sergey *************************************************************************/ void dstie(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* ties, ae_int_t* tiecount, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_vector_clear(ties); *tiecount = 0; ae_vector_clear(p1); ae_vector_clear(p2); ae_vector_init(&tmp, 0, DT_INT, _state); /* * Special case */ if( n<=0 ) { *tiecount = 0; ae_frame_leave(_state); return; } /* * Sort A */ tagsort(a, n, p1, p2, _state); /* * Process ties */ *tiecount = 1; for(i=1; i<=n-1; i++) { if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) { *tiecount = *tiecount+1; } } ae_vector_set_length(ties, *tiecount+1, _state); ties->ptr.p_int[0] = 0; k = 1; for(i=1; i<=n-1; i++) { if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) { ties->ptr.p_int[k] = i; k = k+1; } } ties->ptr.p_int[*tiecount] = n; ae_frame_leave(_state); } /************************************************************************* -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/ void dstiefasti(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t n, /* Integer */ ae_vector* ties, ae_int_t* tiecount, /* Real */ ae_vector* bufr, /* Integer */ ae_vector* bufi, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; ae_vector tmp; ae_frame_make(_state, &_frame_block); *tiecount = 0; ae_vector_init(&tmp, 0, DT_INT, _state); /* * Special case */ if( n<=0 ) { *tiecount = 0; ae_frame_leave(_state); return; } /* * Sort A */ tagsortfasti(a, b, bufr, bufi, n, _state); /* * Process ties */ ties->ptr.p_int[0] = 0; k = 1; for(i=1; i<=n-1; i++) { if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) { ties->ptr.p_int[k] = i; k = k+1; } } ties->ptr.p_int[k] = n; *tiecount = k; ae_frame_leave(_state); } /************************************************************************* Optimal binary classification Algorithms finds optimal (=with minimal cross-entropy) binary partition. Internal subroutine. INPUT PARAMETERS: A - array[0..N-1], variable C - array[0..N-1], class numbers (0 or 1). N - array size OUTPUT PARAMETERS: Info - completetion code: * -3, all values of A[] are same (partition is impossible) * -2, one of C[] is incorrect (<0, >1) * -1, incorrect pararemets were passed (N<=0). * 1, OK Threshold- partiton boundary. Left part contains values which are strictly less than Threshold. Right part contains values which are greater than or equal to Threshold. PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) CVE - cross-validation estimate of cross-entropy -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t* info, double* threshold, double* pal, double* pbl, double* par, double* pbr, double* cve, ae_state *_state) { ae_frame _frame_block; ae_vector _a; ae_vector _c; ae_int_t i; ae_int_t t; double s; ae_vector ties; ae_int_t tiecount; ae_vector p1; ae_vector p2; ae_int_t k; ae_int_t koptimal; double pak; double pbk; double cvoptimal; double cv; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_a, a, _state); a = &_a; ae_vector_init_copy(&_c, c, _state); c = &_c; *info = 0; *threshold = 0; *pal = 0; *pbl = 0; *par = 0; *pbr = 0; *cve = 0; ae_vector_init(&ties, 0, DT_INT, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); /* * Test for errors in inputs */ if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { if( c->ptr.p_int[i]!=0&&c->ptr.p_int[i]!=1 ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Tie */ dstie(a, n, &ties, &tiecount, &p1, &p2, _state); for(i=0; i<=n-1; i++) { if( p2.ptr.p_int[i]!=i ) { t = c->ptr.p_int[i]; c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; c->ptr.p_int[p2.ptr.p_int[i]] = t; } } /* * Special case: number of ties is 1. * * NOTE: we assume that P[i,j] equals to 0 or 1, * intermediate values are not allowed. */ if( tiecount==1 ) { *info = -3; ae_frame_leave(_state); return; } /* * General case, number of ties > 1 * * NOTE: we assume that P[i,j] equals to 0 or 1, * intermediate values are not allowed. */ *pal = (double)(0); *pbl = (double)(0); *par = (double)(0); *pbr = (double)(0); for(i=0; i<=n-1; i++) { if( c->ptr.p_int[i]==0 ) { *par = *par+1; } if( c->ptr.p_int[i]==1 ) { *pbr = *pbr+1; } } koptimal = -1; cvoptimal = ae_maxrealnumber; for(k=0; k<=tiecount-2; k++) { /* * first, obtain information about K-th tie which is * moved from R-part to L-part */ pak = (double)(0); pbk = (double)(0); for(i=ties.ptr.p_int[k]; i<=ties.ptr.p_int[k+1]-1; i++) { if( c->ptr.p_int[i]==0 ) { pak = pak+1; } if( c->ptr.p_int[i]==1 ) { pbk = pbk+1; } } /* * Calculate cross-validation CE */ cv = (double)(0); cv = cv-bdss_xlny(*pal+pak, (*pal+pak)/(*pal+pak+(*pbl)+pbk+1), _state); cv = cv-bdss_xlny(*pbl+pbk, (*pbl+pbk)/(*pal+pak+1+(*pbl)+pbk), _state); cv = cv-bdss_xlny(*par-pak, (*par-pak)/(*par-pak+(*pbr)-pbk+1), _state); cv = cv-bdss_xlny(*pbr-pbk, (*pbr-pbk)/(*par-pak+1+(*pbr)-pbk), _state); /* * Compare with best */ if( ae_fp_less(cv,cvoptimal) ) { cvoptimal = cv; koptimal = k; } /* * update */ *pal = *pal+pak; *pbl = *pbl+pbk; *par = *par-pak; *pbr = *pbr-pbk; } *cve = cvoptimal; *threshold = 0.5*(a->ptr.p_double[ties.ptr.p_int[koptimal]]+a->ptr.p_double[ties.ptr.p_int[koptimal+1]]); *pal = (double)(0); *pbl = (double)(0); *par = (double)(0); *pbr = (double)(0); for(i=0; i<=n-1; i++) { if( ae_fp_less(a->ptr.p_double[i],*threshold) ) { if( c->ptr.p_int[i]==0 ) { *pal = *pal+1; } else { *pbl = *pbl+1; } } else { if( c->ptr.p_int[i]==0 ) { *par = *par+1; } else { *pbr = *pbr+1; } } } s = *pal+(*pbl); *pal = *pal/s; *pbl = *pbl/s; s = *par+(*pbr); *par = *par/s; *pbr = *pbr/s; ae_frame_leave(_state); } /************************************************************************* Optimal partition, internal subroutine. Fast version. Accepts: A array[0..N-1] array of attributes array[0..N-1] C array[0..N-1] array of class labels TiesBuf array[0..N] temporaries (ties) CntBuf array[0..2*NC-1] temporaries (counts) Alpha centering factor (0<=alpha<=1, recommended value - 0.05) BufR array[0..N-1] temporaries BufI array[0..N-1] temporaries Output: Info error code (">0"=OK, "<0"=bad) RMS training set RMS error CVRMS leave-one-out RMS error Note: content of all arrays is changed by subroutine; it doesn't allocate temporaries. -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2fast(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, /* Integer */ ae_vector* tiesbuf, /* Integer */ ae_vector* cntbuf, /* Real */ ae_vector* bufr, /* Integer */ ae_vector* bufi, ae_int_t n, ae_int_t nc, double alpha, ae_int_t* info, double* threshold, double* rms, double* cvrms, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t cl; ae_int_t tiecount; double cbest; double cc; ae_int_t koptimal; ae_int_t sl; ae_int_t sr; double v; double w; double x; *info = 0; *threshold = 0; *rms = 0; *cvrms = 0; /* * Test for errors in inputs */ if( n<=0||nc<2 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) { *info = -2; return; } } *info = 1; /* * Tie */ dstiefasti(a, c, n, tiesbuf, &tiecount, bufr, bufi, _state); /* * Special case: number of ties is 1. */ if( tiecount==1 ) { *info = -3; return; } /* * General case, number of ties > 1 */ for(i=0; i<=2*nc-1; i++) { cntbuf->ptr.p_int[i] = 0; } for(i=0; i<=n-1; i++) { cntbuf->ptr.p_int[nc+c->ptr.p_int[i]] = cntbuf->ptr.p_int[nc+c->ptr.p_int[i]]+1; } koptimal = -1; *threshold = a->ptr.p_double[n-1]; cbest = ae_maxrealnumber; sl = 0; sr = n; for(k=0; k<=tiecount-2; k++) { /* * first, move Kth tie from right to left */ for(i=tiesbuf->ptr.p_int[k]; i<=tiesbuf->ptr.p_int[k+1]-1; i++) { cl = c->ptr.p_int[i]; cntbuf->ptr.p_int[cl] = cntbuf->ptr.p_int[cl]+1; cntbuf->ptr.p_int[nc+cl] = cntbuf->ptr.p_int[nc+cl]-1; } sl = sl+(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); sr = sr-(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); /* * Calculate RMS error */ v = (double)(0); for(i=0; i<=nc-1; i++) { w = (double)(cntbuf->ptr.p_int[i]); v = v+w*ae_sqr(w/sl-1, _state); v = v+(sl-w)*ae_sqr(w/sl, _state); w = (double)(cntbuf->ptr.p_int[nc+i]); v = v+w*ae_sqr(w/sr-1, _state); v = v+(sr-w)*ae_sqr(w/sr, _state); } v = ae_sqrt(v/(nc*n), _state); /* * Compare with best */ x = (double)(2*sl)/(double)(sl+sr)-1; cc = v*(1-alpha+alpha*ae_sqr(x, _state)); if( ae_fp_less(cc,cbest) ) { /* * store split */ *rms = v; koptimal = k; cbest = cc; /* * calculate CVRMS error */ *cvrms = (double)(0); for(i=0; i<=nc-1; i++) { if( sl>1 ) { w = (double)(cntbuf->ptr.p_int[i]); *cvrms = *cvrms+w*ae_sqr((w-1)/(sl-1)-1, _state); *cvrms = *cvrms+(sl-w)*ae_sqr(w/(sl-1), _state); } else { w = (double)(cntbuf->ptr.p_int[i]); *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-1, _state); *cvrms = *cvrms+(sl-w)*ae_sqr((double)1/(double)nc, _state); } if( sr>1 ) { w = (double)(cntbuf->ptr.p_int[nc+i]); *cvrms = *cvrms+w*ae_sqr((w-1)/(sr-1)-1, _state); *cvrms = *cvrms+(sr-w)*ae_sqr(w/(sr-1), _state); } else { w = (double)(cntbuf->ptr.p_int[nc+i]); *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-1, _state); *cvrms = *cvrms+(sr-w)*ae_sqr((double)1/(double)nc, _state); } } *cvrms = ae_sqrt(*cvrms/(nc*n), _state); } } /* * Calculate threshold. * Code is a bit complicated because there can be such * numbers that 0.5(A+B) equals to A or B (if A-B=epsilon) */ *threshold = 0.5*(a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]+a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]); if( ae_fp_less_eq(*threshold,a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]) ) { *threshold = a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]; } } /************************************************************************* Automatic non-optimal discretization, internal subroutine. -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/ void dssplitk(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t nc, ae_int_t kmax, ae_int_t* info, /* Real */ ae_vector* thresholds, ae_int_t* ni, double* cve, ae_state *_state) { ae_frame _frame_block; ae_vector _a; ae_vector _c; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t k; ae_vector ties; ae_int_t tiecount; ae_vector p1; ae_vector p2; ae_vector cnt; double v2; ae_int_t bestk; double bestcve; ae_vector bestsizes; double curcve; ae_vector cursizes; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_a, a, _state); a = &_a; ae_vector_init_copy(&_c, c, _state); c = &_c; *info = 0; ae_vector_clear(thresholds); *ni = 0; *cve = 0; ae_vector_init(&ties, 0, DT_INT, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); ae_vector_init(&cnt, 0, DT_INT, _state); ae_vector_init(&bestsizes, 0, DT_INT, _state); ae_vector_init(&cursizes, 0, DT_INT, _state); /* * Test for errors in inputs */ if( (n<=0||nc<2)||kmax<2 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Tie */ dstie(a, n, &ties, &tiecount, &p1, &p2, _state); for(i=0; i<=n-1; i++) { if( p2.ptr.p_int[i]!=i ) { k = c->ptr.p_int[i]; c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; c->ptr.p_int[p2.ptr.p_int[i]] = k; } } /* * Special cases */ if( tiecount==1 ) { *info = -3; ae_frame_leave(_state); return; } /* * General case: * 0. allocate arrays */ kmax = ae_minint(kmax, tiecount, _state); ae_vector_set_length(&bestsizes, kmax-1+1, _state); ae_vector_set_length(&cursizes, kmax-1+1, _state); ae_vector_set_length(&cnt, nc-1+1, _state); /* * General case: * 1. prepare "weak" solution (two subintervals, divided at median) */ v2 = ae_maxrealnumber; j = -1; for(i=1; i<=tiecount-1; i++) { if( ae_fp_less(ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state),v2) ) { v2 = ae_fabs(ties.ptr.p_int[i]-0.5*n, _state); j = i; } } ae_assert(j>0, "DSSplitK: internal error #1!", _state); bestk = 2; bestsizes.ptr.p_int[0] = ties.ptr.p_int[j]; bestsizes.ptr.p_int[1] = n-j; bestcve = (double)(0); for(i=0; i<=nc-1; i++) { cnt.ptr.p_int[i] = 0; } for(i=0; i<=j-1; i++) { bdss_tieaddc(c, &ties, i, nc, &cnt, _state); } bestcve = bestcve+bdss_getcv(&cnt, nc, _state); for(i=0; i<=nc-1; i++) { cnt.ptr.p_int[i] = 0; } for(i=j; i<=tiecount-1; i++) { bdss_tieaddc(c, &ties, i, nc, &cnt, _state); } bestcve = bestcve+bdss_getcv(&cnt, nc, _state); /* * General case: * 2. Use greedy algorithm to find sub-optimal split in O(KMax*N) time */ for(k=2; k<=kmax; k++) { /* * Prepare greedy K-interval split */ for(i=0; i<=k-1; i++) { cursizes.ptr.p_int[i] = 0; } i = 0; j = 0; while(j<=tiecount-1&&i<=k-1) { /* * Rule: I-th bin is empty, fill it */ if( cursizes.ptr.p_int[i]==0 ) { cursizes.ptr.p_int[i] = ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; j = j+1; continue; } /* * Rule: (K-1-I) bins left, (K-1-I) ties left (1 tie per bin); next bin */ if( tiecount-j==k-1-i ) { i = i+1; continue; } /* * Rule: last bin, always place in current */ if( i==k-1 ) { cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; j = j+1; continue; } /* * Place J-th tie in I-th bin, or leave for I+1-th bin. */ if( ae_fp_less(ae_fabs(cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]-(double)n/(double)k, _state),ae_fabs(cursizes.ptr.p_int[i]-(double)n/(double)k, _state)) ) { cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; j = j+1; } else { i = i+1; } } ae_assert(cursizes.ptr.p_int[k-1]!=0&&j==tiecount, "DSSplitK: internal error #1", _state); /* * Calculate CVE */ curcve = (double)(0); j = 0; for(i=0; i<=k-1; i++) { for(j1=0; j1<=nc-1; j1++) { cnt.ptr.p_int[j1] = 0; } for(j1=j; j1<=j+cursizes.ptr.p_int[i]-1; j1++) { cnt.ptr.p_int[c->ptr.p_int[j1]] = cnt.ptr.p_int[c->ptr.p_int[j1]]+1; } curcve = curcve+bdss_getcv(&cnt, nc, _state); j = j+cursizes.ptr.p_int[i]; } /* * Choose best variant */ if( ae_fp_less(curcve,bestcve) ) { for(i=0; i<=k-1; i++) { bestsizes.ptr.p_int[i] = cursizes.ptr.p_int[i]; } bestcve = curcve; bestk = k; } } /* * Transform from sizes to thresholds */ *cve = bestcve; *ni = bestk; ae_vector_set_length(thresholds, *ni-2+1, _state); j = bestsizes.ptr.p_int[0]; for(i=1; i<=bestk-1; i++) { thresholds->ptr.p_double[i-1] = 0.5*(a->ptr.p_double[j-1]+a->ptr.p_double[j]); j = j+bestsizes.ptr.p_int[i]; } ae_frame_leave(_state); } /************************************************************************* Automatic optimal discretization, internal subroutine. -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplitk(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t nc, ae_int_t kmax, ae_int_t* info, /* Real */ ae_vector* thresholds, ae_int_t* ni, double* cve, ae_state *_state) { ae_frame _frame_block; ae_vector _a; ae_vector _c; ae_int_t i; ae_int_t j; ae_int_t s; ae_int_t jl; ae_int_t jr; double v2; ae_vector ties; ae_int_t tiecount; ae_vector p1; ae_vector p2; double cvtemp; ae_vector cnt; ae_vector cnt2; ae_matrix cv; ae_matrix splits; ae_int_t k; ae_int_t koptimal; double cvoptimal; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_a, a, _state); a = &_a; ae_vector_init_copy(&_c, c, _state); c = &_c; *info = 0; ae_vector_clear(thresholds); *ni = 0; *cve = 0; ae_vector_init(&ties, 0, DT_INT, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); ae_vector_init(&cnt, 0, DT_INT, _state); ae_vector_init(&cnt2, 0, DT_INT, _state); ae_matrix_init(&cv, 0, 0, DT_REAL, _state); ae_matrix_init(&splits, 0, 0, DT_INT, _state); /* * Test for errors in inputs */ if( (n<=0||nc<2)||kmax<2 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Tie */ dstie(a, n, &ties, &tiecount, &p1, &p2, _state); for(i=0; i<=n-1; i++) { if( p2.ptr.p_int[i]!=i ) { k = c->ptr.p_int[i]; c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; c->ptr.p_int[p2.ptr.p_int[i]] = k; } } /* * Special cases */ if( tiecount==1 ) { *info = -3; ae_frame_leave(_state); return; } /* * General case * Use dynamic programming to find best split in O(KMax*NC*TieCount^2) time */ kmax = ae_minint(kmax, tiecount, _state); ae_matrix_set_length(&cv, kmax-1+1, tiecount-1+1, _state); ae_matrix_set_length(&splits, kmax-1+1, tiecount-1+1, _state); ae_vector_set_length(&cnt, nc-1+1, _state); ae_vector_set_length(&cnt2, nc-1+1, _state); for(j=0; j<=nc-1; j++) { cnt.ptr.p_int[j] = 0; } for(j=0; j<=tiecount-1; j++) { bdss_tieaddc(c, &ties, j, nc, &cnt, _state); splits.ptr.pp_int[0][j] = 0; cv.ptr.pp_double[0][j] = bdss_getcv(&cnt, nc, _state); } for(k=1; k<=kmax-1; k++) { for(j=0; j<=nc-1; j++) { cnt.ptr.p_int[j] = 0; } /* * Subtask size J in [K..TieCount-1]: * optimal K-splitting on ties from 0-th to J-th. */ for(j=k; j<=tiecount-1; j++) { /* * Update Cnt - let it contain classes of ties from K-th to J-th */ bdss_tieaddc(c, &ties, j, nc, &cnt, _state); /* * Search for optimal split point S in [K..J] */ for(i=0; i<=nc-1; i++) { cnt2.ptr.p_int[i] = cnt.ptr.p_int[i]; } cv.ptr.pp_double[k][j] = cv.ptr.pp_double[k-1][j-1]+bdss_getcv(&cnt2, nc, _state); splits.ptr.pp_int[k][j] = j; for(s=k+1; s<=j; s++) { /* * Update Cnt2 - let it contain classes of ties from S-th to J-th */ bdss_tiesubc(c, &ties, s-1, nc, &cnt2, _state); /* * Calculate CVE */ cvtemp = cv.ptr.pp_double[k-1][s-1]+bdss_getcv(&cnt2, nc, _state); if( ae_fp_less(cvtemp,cv.ptr.pp_double[k][j]) ) { cv.ptr.pp_double[k][j] = cvtemp; splits.ptr.pp_int[k][j] = s; } } } } /* * Choose best partition, output result */ koptimal = -1; cvoptimal = ae_maxrealnumber; for(k=0; k<=kmax-1; k++) { if( ae_fp_less(cv.ptr.pp_double[k][tiecount-1],cvoptimal) ) { cvoptimal = cv.ptr.pp_double[k][tiecount-1]; koptimal = k; } } ae_assert(koptimal>=0, "DSOptimalSplitK: internal error #1!", _state); if( koptimal==0 ) { /* * Special case: best partition is one big interval. * Even 2-partition is not better. * This is possible when dealing with "weak" predictor variables. * * Make binary split as close to the median as possible. */ v2 = ae_maxrealnumber; j = -1; for(i=1; i<=tiecount-1; i++) { if( ae_fp_less(ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state),v2) ) { v2 = ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state); j = i; } } ae_assert(j>0, "DSOptimalSplitK: internal error #2!", _state); ae_vector_set_length(thresholds, 0+1, _state); thresholds->ptr.p_double[0] = 0.5*(a->ptr.p_double[ties.ptr.p_int[j-1]]+a->ptr.p_double[ties.ptr.p_int[j]]); *ni = 2; *cve = (double)(0); for(i=0; i<=nc-1; i++) { cnt.ptr.p_int[i] = 0; } for(i=0; i<=j-1; i++) { bdss_tieaddc(c, &ties, i, nc, &cnt, _state); } *cve = *cve+bdss_getcv(&cnt, nc, _state); for(i=0; i<=nc-1; i++) { cnt.ptr.p_int[i] = 0; } for(i=j; i<=tiecount-1; i++) { bdss_tieaddc(c, &ties, i, nc, &cnt, _state); } *cve = *cve+bdss_getcv(&cnt, nc, _state); } else { /* * General case: 2 or more intervals * * NOTE: we initialize both JL and JR (left and right bounds), * altough algorithm needs only JL. */ ae_vector_set_length(thresholds, koptimal-1+1, _state); *ni = koptimal+1; *cve = cv.ptr.pp_double[koptimal][tiecount-1]; jl = splits.ptr.pp_int[koptimal][tiecount-1]; jr = tiecount-1; for(k=koptimal; k>=1; k--) { thresholds->ptr.p_double[k-1] = 0.5*(a->ptr.p_double[ties.ptr.p_int[jl-1]]+a->ptr.p_double[ties.ptr.p_int[jl]]); jr = jl-1; jl = splits.ptr.pp_int[k-1][jl-1]; } touchint(&jr, _state); } ae_frame_leave(_state); } /************************************************************************* Internal function *************************************************************************/ static double bdss_xlny(double x, double y, ae_state *_state) { double result; if( ae_fp_eq(x,(double)(0)) ) { result = (double)(0); } else { result = x*ae_log(y, _state); } return result; } /************************************************************************* Internal function, returns number of samples of class I in Cnt[I] *************************************************************************/ static double bdss_getcv(/* Integer */ ae_vector* cnt, ae_int_t nc, ae_state *_state) { ae_int_t i; double s; double result; s = (double)(0); for(i=0; i<=nc-1; i++) { s = s+cnt->ptr.p_int[i]; } result = (double)(0); for(i=0; i<=nc-1; i++) { result = result-bdss_xlny((double)(cnt->ptr.p_int[i]), cnt->ptr.p_int[i]/(s+nc-1), _state); } return result; } /************************************************************************* Internal function, adds number of samples of class I in tie NTie to Cnt[I] *************************************************************************/ static void bdss_tieaddc(/* Integer */ ae_vector* c, /* Integer */ ae_vector* ties, ae_int_t ntie, ae_int_t nc, /* Integer */ ae_vector* cnt, ae_state *_state) { ae_int_t i; for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) { cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]+1; } } /************************************************************************* Internal function, subtracts number of samples of class I in tie NTie to Cnt[I] *************************************************************************/ static void bdss_tiesubc(/* Integer */ ae_vector* c, /* Integer */ ae_vector* ties, ae_int_t ntie, ae_int_t nc, /* Integer */ ae_vector* cnt, ae_state *_state) { ae_int_t i; for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) { cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]-1; } } void _cvreport_init(void* _p, ae_state *_state) { cvreport *p = (cvreport*)_p; ae_touch_ptr((void*)p); } void _cvreport_init_copy(void* _dst, void* _src, ae_state *_state) { cvreport *dst = (cvreport*)_dst; cvreport *src = (cvreport*)_src; dst->relclserror = src->relclserror; dst->avgce = src->avgce; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; } void _cvreport_clear(void* _p) { cvreport *p = (cvreport*)_p; ae_touch_ptr((void*)p); } void _cvreport_destroy(void* _p) { cvreport *p = (cvreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* This function initializes clusterizer object. Newly initialized object is empty, i.e. it does not contain dataset. You should use it as follows: 1. creation 2. dataset is added with ClusterizerSetPoints() 3. additional parameters are set 3. clusterization is performed with one of the clustering functions -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizercreate(clusterizerstate* s, ae_state *_state) { _clusterizerstate_clear(s); s->npoints = 0; s->nfeatures = 0; s->disttype = 2; s->ahcalgo = 0; s->kmeansrestarts = 1; s->kmeansmaxits = 0; s->kmeansinitalgo = 0; s->kmeansdbgnoits = ae_false; kmeansinitbuf(&s->kmeanstmp, _state); } /************************************************************************* This function adds dataset to the clusterizer structure. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm), non-squared * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| NOTE 1: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. NOTE 2: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric * k-means++ clustering algorithm may be used only with Euclidean distance function Thus, list of specific clustering algorithms you may use depends on distance function you specify when you set your dataset. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetpoints(clusterizerstate* s, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, ae_state *_state) { ae_int_t i; ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerSetPoints: incorrect DistType", _state); ae_assert(npoints>=0, "ClusterizerSetPoints: NPoints<0", _state); ae_assert(nfeatures>=1, "ClusterizerSetPoints: NFeatures<1", _state); ae_assert(xy->rows>=npoints, "ClusterizerSetPoints: Rows(XY)cols>=nfeatures, "ClusterizerSetPoints: Cols(XY)npoints = npoints; s->nfeatures = nfeatures; s->disttype = disttype; rmatrixsetlengthatleast(&s->xy, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { ae_v_move(&s->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); } } /************************************************************************* This function adds dataset given by distance matrix to the clusterizer structure. It is important that dataset is not given explicitly - only distance matrix is given. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - array[NPoints,NPoints], distance matrix given by its upper or lower triangle (main diagonal is ignored because its entries are expected to be zero). NPoints - number of points IsUpper - whether upper or lower triangle of D is given. NOTE 1: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric, including one which is given by distance matrix * k-means++ clustering algorithm may be used only with Euclidean distance function and explicitly given points - it can not be used with dataset given by distance matrix Thus, if you call this function, you will be unable to use k-means clustering algorithm to process your problem. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetdistances(clusterizerstate* s, /* Real */ ae_matrix* d, ae_int_t npoints, ae_bool isupper, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t j0; ae_int_t j1; ae_assert(npoints>=0, "ClusterizerSetDistances: NPoints<0", _state); ae_assert(d->rows>=npoints, "ClusterizerSetDistances: Rows(D)cols>=npoints, "ClusterizerSetDistances: Cols(D)npoints = npoints; s->nfeatures = 0; s->disttype = -1; rmatrixsetlengthatleast(&s->d, npoints, npoints, _state); for(i=0; i<=npoints-1; i++) { if( isupper ) { j0 = i+1; j1 = npoints-1; } else { j0 = 0; j1 = i-1; } for(j=j0; j<=j1; j++) { ae_assert(ae_isfinite(d->ptr.pp_double[i][j], _state)&&ae_fp_greater_eq(d->ptr.pp_double[i][j],(double)(0)), "ClusterizerSetDistances: D contains infinite, NAN or negative elements", _state); s->d.ptr.pp_double[i][j] = d->ptr.pp_double[i][j]; s->d.ptr.pp_double[j][i] = d->ptr.pp_double[i][j]; } s->d.ptr.pp_double[i][i] = (double)(0); } } /************************************************************************* This function sets agglomerative hierarchical clustering algorithm INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Algo - algorithm type: * 0 complete linkage (default algorithm) * 1 single linkage * 2 unweighted average linkage * 3 weighted average linkage * 4 Ward's method NOTE: Ward's method works correctly only with Euclidean distance, that's why algorithm will return negative termination code (failure) for any other distance type. It is possible, however, to use this method with user-supplied distance matrix. It is your responsibility to pass one which was calculated with Euclidean distance function. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetahcalgo(clusterizerstate* s, ae_int_t algo, ae_state *_state) { ae_assert((((algo==0||algo==1)||algo==2)||algo==3)||algo==4, "ClusterizerSetHCAlgo: incorrect algorithm type", _state); s->ahcalgo = algo; } /************************************************************************* This function sets k-means properties: number of restarts and maximum number of iterations per one run. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Restarts- restarts count, >=1. k-means++ algorithm performs several restarts and chooses best set of centers (one with minimum squared distance). MaxIts - maximum number of k-means iterations performed during one run. >=0, zero value means that algorithm performs unlimited number of iterations. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeanslimits(clusterizerstate* s, ae_int_t restarts, ae_int_t maxits, ae_state *_state) { ae_assert(restarts>=1, "ClusterizerSetKMeansLimits: Restarts<=0", _state); ae_assert(maxits>=0, "ClusterizerSetKMeansLimits: MaxIts<0", _state); s->kmeansrestarts = restarts; s->kmeansmaxits = maxits; } /************************************************************************* This function sets k-means initialization algorithm. Several different algorithms can be chosen, including k-means++. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() InitAlgo- initialization algorithm: * 0 automatic selection ( different versions of ALGLIB may select different algorithms) * 1 random initialization * 2 k-means++ initialization (best quality of initial centers, but long non-parallelizable initialization phase with bad cache locality) * 3 "fast-greedy" algorithm with efficient, easy to parallelize initialization. Quality of initial centers is somewhat worse than that of k-means++. This algorithm is a default one in the current version of ALGLIB. *-1 "debug" algorithm which always selects first K rows of dataset; this algorithm is used for debug purposes only. Do not use it in the industrial code! -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeansinit(clusterizerstate* s, ae_int_t initalgo, ae_state *_state) { ae_assert(initalgo>=-1&&initalgo<=3, "ClusterizerSetKMeansInit: InitAlgo is incorrect", _state); s->kmeansinitalgo = initalgo; } /************************************************************************* This function performs agglomerative hierarchical clustering COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() OUTPUT PARAMETERS: Rep - clustering results; see description of AHCReport structure for more information. NOTE 1: hierarchical clustering algorithms require large amounts of memory. In particular, this implementation needs sizeof(double)*NPoints^2 bytes, which are used to store distance matrix. In case we work with user-supplied matrix, this amount is multiplied by 2 (we have to store original matrix and to work with its copy). For example, problem with 10000 points would require 800M of RAM, even when working in a 1-dimensional space. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunahc(clusterizerstate* s, ahcreport* rep, ae_state *_state) { ae_int_t npoints; ae_int_t nfeatures; _ahcreport_clear(rep); npoints = s->npoints; nfeatures = s->nfeatures; /* * Fill Rep.NPoints, quick exit when NPoints<=1 */ rep->npoints = npoints; if( npoints==0 ) { ae_vector_set_length(&rep->p, 0, _state); ae_matrix_set_length(&rep->z, 0, 0, _state); ae_matrix_set_length(&rep->pz, 0, 0, _state); ae_matrix_set_length(&rep->pm, 0, 0, _state); ae_vector_set_length(&rep->mergedist, 0, _state); rep->terminationtype = 1; return; } if( npoints==1 ) { ae_vector_set_length(&rep->p, 1, _state); ae_matrix_set_length(&rep->z, 0, 0, _state); ae_matrix_set_length(&rep->pz, 0, 0, _state); ae_matrix_set_length(&rep->pm, 0, 0, _state); ae_vector_set_length(&rep->mergedist, 0, _state); rep->p.ptr.p_int[0] = 0; rep->terminationtype = 1; return; } /* * More than one point */ if( s->disttype==-1 ) { /* * Run clusterizer with user-supplied distance matrix */ clustering_clusterizerrunahcinternal(s, &s->d, rep, _state); return; } else { /* * Check combination of AHC algo and distance type */ if( s->ahcalgo==4&&s->disttype!=2 ) { rep->terminationtype = -5; return; } /* * Build distance matrix D. */ clusterizergetdistancesbuf(&s->distbuf, &s->xy, npoints, nfeatures, s->disttype, &s->tmpd, _state); /* * Run clusterizer */ clustering_clusterizerrunahcinternal(s, &s->tmpd, rep, _state); return; } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_clusterizerrunahc(clusterizerstate* s, ahcreport* rep, ae_state *_state) { clusterizerrunahc(s,rep, _state); } /************************************************************************* This function performs clustering by k-means++ algorithm. You may change algorithm properties by calling: * ClusterizerSetKMeansLimits() to change number of restarts or iterations * ClusterizerSetKMeansInit() to change initialization algorithm By default, one restart and unlimited number of iterations are used. Initialization algorithm is chosen automatically. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (can be used from C# and C++) ! * access to high-performance C++ core (actual for C# users) ! ! K-means clustering algorithm has two phases: selection of initial ! centers and clustering itself. ALGLIB parallelizes both phases. ! Parallel version is optimized for the following scenario: medium or ! high-dimensional problem (20 or more dimensions) with large number of ! points and clusters. However, some speed-up can be obtained even when ! assumptions above are violated. ! ! As for native-vs-managed comparison, working with native core brings ! 30-40% improvement in speed over pure C# version of ALGLIB. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() K - number of clusters, K>=0. K can be zero only when algorithm is called for empty dataset, in this case completion code is set to success (+1). If K=0 and dataset size is non-zero, we can not meaningfully assign points to some center (there are no centers because K=0) and return -3 as completion code (failure). OUTPUT PARAMETERS: Rep - clustering results; see description of KMeansReport structure for more information. NOTE 1: k-means clustering can be performed only for datasets with Euclidean distance function. Algorithm will return negative completion code in Rep.TerminationType in case dataset was added to clusterizer with DistType other than Euclidean (or dataset was specified by distance matrix instead of explicitly given points). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunkmeans(clusterizerstate* s, ae_int_t k, kmeansreport* rep, ae_state *_state) { ae_frame _frame_block; ae_matrix dummy; ae_frame_make(_state, &_frame_block); _kmeansreport_clear(rep); ae_matrix_init(&dummy, 0, 0, DT_REAL, _state); ae_assert(k>=0, "ClusterizerRunKMeans: K<0", _state); /* * Incorrect distance type */ if( s->disttype!=2 ) { rep->npoints = s->npoints; rep->terminationtype = -5; rep->k = k; rep->iterationscount = 0; rep->energy = 0.0; ae_frame_leave(_state); return; } /* * K>NPoints or (K=0 and NPoints>0) */ if( k>s->npoints||(k==0&&s->npoints>0) ) { rep->npoints = s->npoints; rep->terminationtype = -3; rep->k = k; rep->iterationscount = 0; rep->energy = 0.0; ae_frame_leave(_state); return; } /* * No points */ if( s->npoints==0 ) { rep->npoints = 0; rep->terminationtype = 1; rep->k = k; rep->iterationscount = 0; rep->energy = 0.0; ae_frame_leave(_state); return; } /* * Normal case: * 1<=K<=NPoints, Euclidean distance */ rep->npoints = s->npoints; rep->nfeatures = s->nfeatures; rep->k = k; rep->npoints = s->npoints; rep->nfeatures = s->nfeatures; kmeansgenerateinternal(&s->xy, s->npoints, s->nfeatures, k, s->kmeansinitalgo, s->kmeansmaxits, s->kmeansrestarts, s->kmeansdbgnoits, &rep->terminationtype, &rep->iterationscount, &dummy, ae_false, &rep->c, ae_true, &rep->cidx, &rep->energy, &s->kmeanstmp, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_clusterizerrunkmeans(clusterizerstate* s, ae_int_t k, kmeansreport* rep, ae_state *_state) { clusterizerrunkmeans(s,k,rep, _state); } /************************************************************************* This function returns distance matrix for dataset COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm, non-squared) * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| OUTPUT PARAMETERS: D - array[NPoints,NPoints], distance matrix (full matrix is returned, with lower and upper triangles) NOTE: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizergetdistances(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_state *_state) { ae_frame _frame_block; apbuffers buf; ae_frame_make(_state, &_frame_block); ae_matrix_clear(d); _apbuffers_init(&buf, _state); ae_assert(nfeatures>=1, "ClusterizerGetDistances: NFeatures<1", _state); ae_assert(npoints>=0, "ClusterizerGetDistances: NPoints<1", _state); ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerGetDistances: incorrect DistType", _state); ae_assert(xy->rows>=npoints, "ClusterizerGetDistances: Rows(XY)cols>=nfeatures, "ClusterizerGetDistances: Cols(XY)=1, "ClusterizerGetDistancesBuf: NFeatures<1", _state); ae_assert(npoints>=0, "ClusterizerGetDistancesBuf: NPoints<1", _state); ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerGetDistancesBuf: incorrect DistType", _state); ae_assert(xy->rows>=npoints, "ClusterizerGetDistancesBuf: Rows(XY)cols>=nfeatures, "ClusterizerGetDistancesBuf: Cols(XY)ptr.pp_double[0][0] = (double)(0); return; } /* * Build distance matrix D. */ if( disttype==0||disttype==1 ) { /* * Chebyshev or city-block distances: * * recursively calculate upper triangle (with main diagonal) * * copy it to the bottom part of the matrix */ rmatrixsetlengthatleast(d, npoints, npoints, _state); clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, 0, npoints, 0, npoints, _state); rmatrixenforcesymmetricity(d, npoints, ae_true, _state); return; } if( disttype==2 ) { /* * Euclidean distance * * NOTE: parallelization is done within RMatrixSYRK */ rmatrixsetlengthatleast(d, npoints, npoints, _state); rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); rvectorsetlengthatleast(&buf->ra1, nfeatures, _state); rvectorsetlengthatleast(&buf->ra0, npoints, _state); for(j=0; j<=nfeatures-1; j++) { buf->ra1.ptr.p_double[j] = 0.0; } v = (double)1/(double)npoints; for(i=0; i<=npoints-1; i++) { ae_v_addd(&buf->ra1.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1), v); } for(i=0; i<=npoints-1; i++) { ae_v_move(&buf->rm0.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); ae_v_sub(&buf->rm0.ptr.pp_double[i][0], 1, &buf->ra1.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); } rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); for(i=0; i<=npoints-1; i++) { buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; } for(i=0; i<=npoints-1; i++) { d->ptr.pp_double[i][i] = 0.0; for(j=i+1; j<=npoints-1; j++) { v = ae_sqrt(ae_maxreal(buf->ra0.ptr.p_double[i]+buf->ra0.ptr.p_double[j]-2*d->ptr.pp_double[i][j], 0.0, _state), _state); d->ptr.pp_double[i][j] = v; } } rmatrixenforcesymmetricity(d, npoints, ae_true, _state); return; } if( disttype==10||disttype==11 ) { /* * Absolute/nonabsolute Pearson correlation distance * * NOTE: parallelization is done within PearsonCorrM, which calls RMatrixSYRK internally */ rmatrixsetlengthatleast(d, npoints, npoints, _state); rvectorsetlengthatleast(&buf->ra0, npoints, _state); rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { v = 0.0; for(j=0; j<=nfeatures-1; j++) { v = v+xy->ptr.pp_double[i][j]; } v = v/nfeatures; for(j=0; j<=nfeatures-1; j++) { buf->rm0.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]-v; } } rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); for(i=0; i<=npoints-1; i++) { buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; } for(i=0; i<=npoints-1; i++) { d->ptr.pp_double[i][i] = 0.0; for(j=i+1; j<=npoints-1; j++) { v = d->ptr.pp_double[i][j]/ae_sqrt(buf->ra0.ptr.p_double[i]*buf->ra0.ptr.p_double[j], _state); if( disttype==10 ) { v = 1-v; } else { v = 1-ae_fabs(v, _state); } v = ae_maxreal(v, 0.0, _state); d->ptr.pp_double[i][j] = v; } } rmatrixenforcesymmetricity(d, npoints, ae_true, _state); return; } if( disttype==12||disttype==13 ) { /* * Absolute/nonabsolute uncentered Pearson correlation distance * * NOTE: parallelization is done within RMatrixSYRK */ rmatrixsetlengthatleast(d, npoints, npoints, _state); rvectorsetlengthatleast(&buf->ra0, npoints, _state); rmatrixsyrk(npoints, nfeatures, 1.0, xy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); for(i=0; i<=npoints-1; i++) { buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; } for(i=0; i<=npoints-1; i++) { d->ptr.pp_double[i][i] = 0.0; for(j=i+1; j<=npoints-1; j++) { v = d->ptr.pp_double[i][j]/ae_sqrt(buf->ra0.ptr.p_double[i]*buf->ra0.ptr.p_double[j], _state); if( disttype==13 ) { v = ae_fabs(v, _state); } v = ae_minreal(v, 1.0, _state); d->ptr.pp_double[i][j] = 1-v; } } rmatrixenforcesymmetricity(d, npoints, ae_true, _state); return; } if( disttype==20||disttype==21 ) { /* * Spearman rank correlation * * NOTE: parallelization of correlation matrix is done within * PearsonCorrM, which calls RMatrixSYRK internally */ rmatrixsetlengthatleast(d, npoints, npoints, _state); rvectorsetlengthatleast(&buf->ra0, npoints, _state); rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); rmatrixcopy(npoints, nfeatures, xy, 0, 0, &buf->rm0, 0, 0, _state); rankdatacentered(&buf->rm0, npoints, nfeatures, _state); rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); for(i=0; i<=npoints-1; i++) { if( ae_fp_greater(d->ptr.pp_double[i][i],(double)(0)) ) { buf->ra0.ptr.p_double[i] = 1/ae_sqrt(d->ptr.pp_double[i][i], _state); } else { buf->ra0.ptr.p_double[i] = 0.0; } } for(i=0; i<=npoints-1; i++) { v = buf->ra0.ptr.p_double[i]; d->ptr.pp_double[i][i] = 0.0; for(j=i+1; j<=npoints-1; j++) { vv = d->ptr.pp_double[i][j]*v*buf->ra0.ptr.p_double[j]; if( disttype==20 ) { vr = 1-vv; } else { vr = 1-ae_fabs(vv, _state); } if( ae_fp_less(vr,(double)(0)) ) { vr = 0.0; } d->ptr.pp_double[i][j] = vr; } } rmatrixenforcesymmetricity(d, npoints, ae_true, _state); return; } ae_assert(ae_false, "Assertion failed", _state); } /************************************************************************* This function takes as input clusterization report Rep, desired clusters count K, and builds top K clusters from hierarchical clusterization tree. It returns assignment of points to clusters (array of cluster indexes). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY K - desired number of clusters, 1<=K<=NPoints. K can be zero only when NPoints=0. OUTPUT PARAMETERS: CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]npoints; ae_assert(npoints>=0, "ClusterizerGetKClusters: internal error in Rep integrity", _state); ae_assert(k>=0, "ClusterizerGetKClusters: K<=0", _state); ae_assert(k<=npoints, "ClusterizerGetKClusters: K>NPoints", _state); ae_assert(k>0||npoints==0, "ClusterizerGetKClusters: K<=0", _state); ae_assert(npoints==rep->npoints, "ClusterizerGetKClusters: NPoints<>Rep.NPoints", _state); /* * Quick exit */ if( npoints==0 ) { ae_frame_leave(_state); return; } if( npoints==1 ) { ae_vector_set_length(cz, 1, _state); ae_vector_set_length(cidx, 1, _state); cz->ptr.p_int[0] = 0; cidx->ptr.p_int[0] = 0; ae_frame_leave(_state); return; } /* * Replay merges, from top to bottom, * keep track of clusters being present at the moment */ ae_vector_set_length(&presentclusters, 2*npoints-1, _state); ae_vector_set_length(&tmpidx, npoints, _state); for(i=0; i<=2*npoints-3; i++) { presentclusters.ptr.p_bool[i] = ae_false; } presentclusters.ptr.p_bool[2*npoints-2] = ae_true; for(i=0; i<=npoints-1; i++) { tmpidx.ptr.p_int[i] = 2*npoints-2; } for(mergeidx=npoints-2; mergeidx>=npoints-k; mergeidx--) { /* * Update information about clusters being present at the moment */ presentclusters.ptr.p_bool[npoints+mergeidx] = ae_false; presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][0]] = ae_true; presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][1]] = ae_true; /* * Update TmpIdx according to the current state of the dataset * * NOTE: TmpIdx contains cluster indexes from [0..2*NPoints-2]; * we will convert them to [0..K-1] later. */ i0 = rep->pm.ptr.pp_int[mergeidx][0]; i1 = rep->pm.ptr.pp_int[mergeidx][1]; t = rep->z.ptr.pp_int[mergeidx][0]; for(i=i0; i<=i1; i++) { tmpidx.ptr.p_int[i] = t; } i0 = rep->pm.ptr.pp_int[mergeidx][2]; i1 = rep->pm.ptr.pp_int[mergeidx][3]; t = rep->z.ptr.pp_int[mergeidx][1]; for(i=i0; i<=i1; i++) { tmpidx.ptr.p_int[i] = t; } } /* * Fill CZ - array which allows us to convert cluster indexes * from one system to another. */ ae_vector_set_length(cz, k, _state); ae_vector_set_length(&clusterindexes, 2*npoints-1, _state); t = 0; for(i=0; i<=2*npoints-2; i++) { if( presentclusters.ptr.p_bool[i] ) { cz->ptr.p_int[t] = i; clusterindexes.ptr.p_int[i] = t; t = t+1; } } ae_assert(t==k, "ClusterizerGetKClusters: internal error", _state); /* * Convert indexes stored in CIdx */ ae_vector_set_length(cidx, npoints, _state); for(i=0; i<=npoints-1; i++) { cidx->ptr.p_int[i] = clusterindexes.ptr.p_int[tmpidx.ptr.p_int[rep->p.ptr.p_int[i]]]; } ae_frame_leave(_state); } /************************************************************************* This function accepts AHC report Rep, desired minimum intercluster distance and returns top clusters from hierarchical clusterization tree which are separated by distance R or HIGHER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByCorr, which returns clusters with intercluster correlation equal to R or LOWER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired minimum intercluster distance, R>=0 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],r)) { *k = *k+1; } clusterizergetkclusters(rep, *k, cidx, cz, _state); } /************************************************************************* This function accepts AHC report Rep, desired maximum intercluster correlation and returns top clusters from hierarchical clusterization tree which are separated by correlation R or LOWER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByDist, which returns clusters with intercluster distance equal to R or HIGHER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired maximum intercluster correlation, -1<=R<=+1 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],1-r)) { *k = *k+1; } clusterizergetkclusters(rep, *k, cidx, cz, _state); } /************************************************************************* K-means++ initialization INPUT PARAMETERS: Buf - special reusable structure which stores previously allocated memory, intended to avoid memory fragmentation when solving multiple subsequent problems. Must be initialized prior to usage. OUTPUT PARAMETERS: Buf - initialized structure -- ALGLIB -- Copyright 24.07.2015 by Bochkanov Sergey *************************************************************************/ void kmeansinitbuf(kmeansbuffers* buf, ae_state *_state) { ae_frame _frame_block; apbuffers updateseed; ae_frame_make(_state, &_frame_block); _apbuffers_init(&updateseed, _state); ae_shared_pool_set_seed(&buf->updatepool, &updateseed, sizeof(updateseed), _apbuffers_init, _apbuffers_init_copy, _apbuffers_destroy, _state); ae_frame_leave(_state); } /************************************************************************* K-means++ clusterization INPUT PARAMETERS: XY - dataset, array [0..NPoints-1,0..NVars-1]. NPoints - dataset size, NPoints>=K NVars - number of variables, NVars>=1 K - desired number of clusters, K>=1 InitAlgo - initialization algorithm: * 0 - automatic selection of best algorithm * 1 - random selection of centers * 2 - k-means++ * 3 - fast-greedy init *-1 - first K rows of dataset are used (special debug algorithm) MaxIts - iterations limit or zero for no limit Restarts - number of restarts, Restarts>=1 KMeansDbgNoIts- debug flag; if set, Lloyd's iteration is not performed, only initialization phase. Buf - special reusable structure which stores previously allocated memory, intended to avoid memory fragmentation when solving multiple subsequent problems: * MUST BE INITIALIZED WITH KMeansInitBuffers() CALL BEFORE FIRST PASS TO THIS FUNCTION! * subsequent passes must be made without re-initialization OUTPUT PARAMETERS: Info - return code: * -3, if task is degenerate (number of distinct points is less than K) * -1, if incorrect NPoints/NFeatures/K/Restarts was passed * 1, if subroutine finished successfully IterationsCount- actual number of iterations performed by clusterizer CCol - array[0..NVars-1,0..K-1].matrix whose columns store cluster's centers NeedCCol - True in case caller requires to store result in CCol CRow - array[0..K-1,0..NVars-1], same as CCol, but centers are stored in rows NeedCRow - True in case caller requires to store result in CCol XYC - array[NPoints], which contains cluster indexes Energy - merit function of clusterization -- ALGLIB -- Copyright 21.03.2009 by Bochkanov Sergey *************************************************************************/ void kmeansgenerateinternal(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t k, ae_int_t initalgo, ae_int_t maxits, ae_int_t restarts, ae_bool kmeansdbgnoits, ae_int_t* info, ae_int_t* iterationscount, /* Real */ ae_matrix* ccol, ae_bool needccol, /* Real */ ae_matrix* crow, ae_bool needcrow, /* Integer */ ae_vector* xyc, double* energy, kmeansbuffers* buf, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t i1; double e; double eprev; double v; double vv; ae_bool waschanges; ae_bool zerosizeclusters; ae_int_t pass; ae_int_t itcnt; hqrndstate rs; ae_frame_make(_state, &_frame_block); *info = 0; *iterationscount = 0; ae_matrix_clear(ccol); ae_matrix_clear(crow); ae_vector_clear(xyc); *energy = 0; _hqrndstate_init(&rs, _state); /* * Test parameters */ if( ((npointsct, k, nvars, _state); rmatrixsetlengthatleast(&buf->ctbest, k, nvars, _state); ivectorsetlengthatleast(&buf->xycprev, npoints, _state); ivectorsetlengthatleast(&buf->xycbest, npoints, _state); rvectorsetlengthatleast(&buf->d2, npoints, _state); ivectorsetlengthatleast(&buf->csizes, k, _state); *energy = ae_maxrealnumber; hqrndrandomize(&rs, _state); for(pass=1; pass<=restarts; pass++) { /* * Select initial centers. * * Note that for performance reasons centers are stored in ROWS of CT, not * in columns. We'll transpose CT in the end and store it in the C. * * Also note that SelectInitialCenters() may return degenerate set of centers * (some of them have no corresponding points in dataset, some are non-distinct). * Algorithm below is robust enough to deal with such set. */ clustering_selectinitialcenters(xy, npoints, nvars, initalgo, k, &buf->ct, &buf->initbuf, &buf->updatepool, _state); /* * Lloyd's iteration */ if( !kmeansdbgnoits ) { /* * Perform iteration as usual, in normal mode */ for(i=0; i<=npoints-1; i++) { xyc->ptr.p_int[i] = -1; } eprev = ae_maxrealnumber; e = ae_maxrealnumber; itcnt = 0; while(maxits==0||itcntxycprev.ptr.p_int[i] = xyc->ptr.p_int[i]; } kmeansupdatedistances(xy, 0, npoints, nvars, &buf->ct, 0, k, xyc, &buf->d2, &buf->updatepool, _state); waschanges = ae_false; for(i=0; i<=npoints-1; i++) { waschanges = waschanges||xyc->ptr.p_int[i]!=buf->xycprev.ptr.p_int[i]; } /* * Update centers */ for(j=0; j<=k-1; j++) { buf->csizes.ptr.p_int[j] = 0; } for(i=0; i<=k-1; i++) { for(j=0; j<=nvars-1; j++) { buf->ct.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=npoints-1; i++) { buf->csizes.ptr.p_int[xyc->ptr.p_int[i]] = buf->csizes.ptr.p_int[xyc->ptr.p_int[i]]+1; ae_v_add(&buf->ct.ptr.pp_double[xyc->ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); } zerosizeclusters = ae_false; for(j=0; j<=k-1; j++) { if( buf->csizes.ptr.p_int[j]!=0 ) { v = (double)1/(double)buf->csizes.ptr.p_int[j]; ae_v_muld(&buf->ct.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), v); } zerosizeclusters = zerosizeclusters||buf->csizes.ptr.p_int[j]==0; } if( zerosizeclusters ) { /* * Some clusters have zero size - rare, but possible. * We'll choose new centers for such clusters using k-means++ rule * and restart algorithm */ if( !clustering_fixcenters(xy, npoints, nvars, &buf->ct, k, &buf->initbuf, &buf->updatepool, _state) ) { *info = -3; ae_frame_leave(_state); return; } continue; } /* * Stop if one of two conditions is met: * 1. nothing has changed during iteration * 2. energy function increased after recalculation on new centers */ e = (double)(0); for(i=0; i<=npoints-1; i++) { v = 0.0; i1 = xyc->ptr.p_int[i]; for(j=0; j<=nvars-1; j++) { vv = xy->ptr.pp_double[i][j]-buf->ct.ptr.pp_double[i1][j]; v = v+vv*vv; } e = e+v; } if( !waschanges||ae_fp_greater_eq(e,eprev) ) { break; } /* * Update EPrev */ eprev = e; } } else { /* * Debug mode: no Lloyd's iteration. * We just calculate potential E. */ kmeansupdatedistances(xy, 0, npoints, nvars, &buf->ct, 0, k, xyc, &buf->d2, &buf->updatepool, _state); e = (double)(0); for(i=0; i<=npoints-1; i++) { e = e+buf->d2.ptr.p_double[i]; } } /* * Compare E with best centers found so far */ if( ae_fp_less(e,*energy) ) { /* * store partition. */ *energy = e; copymatrix(&buf->ct, 0, k-1, 0, nvars-1, &buf->ctbest, 0, k-1, 0, nvars-1, _state); for(i=0; i<=npoints-1; i++) { buf->xycbest.ptr.p_int[i] = xyc->ptr.p_int[i]; } } } /* * Copy and transpose */ if( needccol ) { ae_matrix_set_length(ccol, nvars, k, _state); copyandtranspose(&buf->ctbest, 0, k-1, 0, nvars-1, ccol, 0, nvars-1, 0, k-1, _state); } if( needcrow ) { ae_matrix_set_length(crow, k, nvars, _state); rmatrixcopy(k, nvars, &buf->ctbest, 0, 0, crow, 0, 0, _state); } for(i=0; i<=npoints-1; i++) { xyc->ptr.p_int[i] = buf->xycbest.ptr.p_int[i]; } ae_frame_leave(_state); } /************************************************************************* This procedure recalculates distances from points to centers and assigns each point to closest center. INPUT PARAMETERS: XY - dataset, array [0..NPoints-1,0..NVars-1]. Idx0,Idx1 - define range of dataset [Idx0,Idx1) to process; right boundary is not included. NVars - number of variables, NVars>=1 CT - matrix of centers, centers are stored in rows CIdx0,CIdx1 - define range of centers [CIdx0,CIdx1) to process; right boundary is not included. XYC - preallocated output buffer, XYDist2 - preallocated output buffer Tmp - temporary buffer, automatically reallocated if needed BufferPool - shared pool seeded with instance of APBuffers structure (seed instance can be unitialized). It is recommended to use this pool only with KMeansUpdateDistances() function. OUTPUT PARAMETERS: XYC - new assignment of points to centers are stored in [Idx0,Idx1) XYDist2 - squared distances from points to their centers are stored in [Idx0,Idx1) -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ void kmeansupdatedistances(/* Real */ ae_matrix* xy, ae_int_t idx0, ae_int_t idx1, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t cidx0, ae_int_t cidx1, /* Integer */ ae_vector* xyc, /* Real */ ae_vector* xydist2, ae_shared_pool* bufferpool, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t i0; ae_int_t i1; ae_int_t j; ae_int_t cclosest; double dclosest; double vv; apbuffers *buf; ae_smart_ptr _buf; double rcomplexity; ae_int_t task0; ae_int_t task1; ae_int_t pblkcnt; ae_int_t cblkcnt; ae_int_t vblkcnt; ae_int_t pblk; ae_int_t cblk; ae_int_t vblk; ae_int_t p0; ae_int_t p1; ae_int_t c0; ae_int_t c1; ae_int_t v0; ae_int_t v1; double v00; double v01; double v10; double v11; double vp0; double vp1; double vc0; double vc1; ae_int_t pcnt; ae_int_t pcntpadded; ae_int_t ccnt; ae_int_t ccntpadded; ae_int_t offs0; ae_int_t offs00; ae_int_t offs01; ae_int_t offs10; ae_int_t offs11; ae_int_t vcnt; ae_int_t stride; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_buf, (void**)&buf, _state); /* * Quick exit for special cases */ if( idx1<=idx0 ) { ae_frame_leave(_state); return; } if( cidx1<=cidx0 ) { ae_frame_leave(_state); return; } if( nvars<=0 ) { ae_frame_leave(_state); return; } /* * Try to recursively divide/process dataset * * NOTE: real arithmetics is used to avoid integer overflow on large problem sizes */ rcomplexity = (double)(idx1-idx0); rcomplexity = rcomplexity*(cidx1-cidx0); rcomplexity = rcomplexity*nvars; if( ((ae_fp_greater_eq(rcomplexity,clustering_parallelcomplexity)&&idx1-idx0>=2*clustering_kmeansblocksize)&&nvars>=clustering_kmeansparalleldim)&&cidx1-cidx0>=clustering_kmeansparallelk ) { splitlength(idx1-idx0, clustering_kmeansblocksize, &task0, &task1, _state); kmeansupdatedistances(xy, idx0, idx0+task0, nvars, ct, cidx0, cidx1, xyc, xydist2, bufferpool, _state); kmeansupdatedistances(xy, idx0+task0, idx1, nvars, ct, cidx0, cidx1, xyc, xydist2, bufferpool, _state); ae_frame_leave(_state); return; } /* * Dataset chunk is selected. * * Process it with blocked algorithm: * * iterate over points, process them in KMeansBlockSize-ed chunks * * for each chunk of dataset, iterate over centers, process them in KMeansBlockSize-ed chunks * * for each chunk of dataset/centerset, iterate over variables, process them in KMeansBlockSize-ed chunks */ ae_assert(clustering_kmeansblocksize%2==0, "KMeansUpdateDistances: internal error", _state); ae_shared_pool_retrieve(bufferpool, &_buf, _state); rvectorsetlengthatleast(&buf->ra0, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); rvectorsetlengthatleast(&buf->ra1, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); rvectorsetlengthatleast(&buf->ra2, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); rvectorsetlengthatleast(&buf->ra3, clustering_kmeansblocksize, _state); ivectorsetlengthatleast(&buf->ia3, clustering_kmeansblocksize, _state); pblkcnt = chunkscount(idx1-idx0, clustering_kmeansblocksize, _state); cblkcnt = chunkscount(cidx1-cidx0, clustering_kmeansblocksize, _state); vblkcnt = chunkscount(nvars, clustering_kmeansblocksize, _state); for(pblk=0; pblk<=pblkcnt-1; pblk++) { /* * Process PBlk-th chunk of dataset. */ p0 = idx0+pblk*clustering_kmeansblocksize; p1 = ae_minint(p0+clustering_kmeansblocksize, idx1, _state); /* * Prepare RA3[]/IA3[] for storage of best distances and best cluster numbers. */ for(i=0; i<=clustering_kmeansblocksize-1; i++) { buf->ra3.ptr.p_double[i] = ae_maxrealnumber; buf->ia3.ptr.p_int[i] = -1; } /* * Iterare over chunks of centerset. */ for(cblk=0; cblk<=cblkcnt-1; cblk++) { /* * Process CBlk-th chunk of centerset */ c0 = cidx0+cblk*clustering_kmeansblocksize; c1 = ae_minint(c0+clustering_kmeansblocksize, cidx1, _state); /* * At this point we have to calculate a set of pairwise distances * between points [P0,P1) and centers [C0,C1) and select best center * for each point. It can also be done with blocked algorithm * (blocking for variables). * * Following arrays are used: * * RA0[] - matrix of distances, padded by zeros for even size, * rows are stored with stride KMeansBlockSize. * * RA1[] - matrix of points (variables corresponding to current * block are extracted), padded by zeros for even size, * rows are stored with stride KMeansBlockSize. * * RA2[] - matrix of centers (variables corresponding to current * block are extracted), padded by zeros for even size, * rows are stored with stride KMeansBlockSize. * */ pcnt = p1-p0; pcntpadded = pcnt+pcnt%2; ccnt = c1-c0; ccntpadded = ccnt+ccnt%2; stride = clustering_kmeansblocksize; ae_assert(pcntpadded<=clustering_kmeansblocksize, "KMeansUpdateDistances: integrity error", _state); ae_assert(ccntpadded<=clustering_kmeansblocksize, "KMeansUpdateDistances: integrity error", _state); for(i=0; i<=pcntpadded-1; i++) { for(j=0; j<=ccntpadded-1; j++) { buf->ra0.ptr.p_double[i*stride+j] = 0.0; } } for(vblk=0; vblk<=vblkcnt-1; vblk++) { /* * Fetch VBlk-th block of variables to arrays RA1 (points) and RA2 (centers). * Pad points and centers with zeros. */ v0 = vblk*clustering_kmeansblocksize; v1 = ae_minint(v0+clustering_kmeansblocksize, nvars, _state); vcnt = v1-v0; for(i=0; i<=pcnt-1; i++) { for(j=0; j<=vcnt-1; j++) { buf->ra1.ptr.p_double[i*stride+j] = xy->ptr.pp_double[p0+i][v0+j]; } } for(i=pcnt; i<=pcntpadded-1; i++) { for(j=0; j<=vcnt-1; j++) { buf->ra1.ptr.p_double[i*stride+j] = 0.0; } } for(i=0; i<=ccnt-1; i++) { for(j=0; j<=vcnt-1; j++) { buf->ra2.ptr.p_double[i*stride+j] = ct->ptr.pp_double[c0+i][v0+j]; } } for(i=ccnt; i<=ccntpadded-1; i++) { for(j=0; j<=vcnt-1; j++) { buf->ra2.ptr.p_double[i*stride+j] = 0.0; } } /* * Update distance matrix with sums-of-squared-differences of RA1 and RA2 */ i0 = 0; while(i0ra0.ptr.p_double[offs0]; v01 = buf->ra0.ptr.p_double[offs0+1]; v10 = buf->ra0.ptr.p_double[offs0+stride]; v11 = buf->ra0.ptr.p_double[offs0+stride+1]; offs00 = i0*stride; offs01 = offs00+stride; offs10 = i1*stride; offs11 = offs10+stride; for(j=0; j<=vcnt-1; j++) { vp0 = buf->ra1.ptr.p_double[offs00+j]; vp1 = buf->ra1.ptr.p_double[offs01+j]; vc0 = buf->ra2.ptr.p_double[offs10+j]; vc1 = buf->ra2.ptr.p_double[offs11+j]; vv = vp0-vc0; v00 = v00+vv*vv; vv = vp0-vc1; v01 = v01+vv*vv; vv = vp1-vc0; v10 = v10+vv*vv; vv = vp1-vc1; v11 = v11+vv*vv; } offs0 = i0*stride+i1; buf->ra0.ptr.p_double[offs0] = v00; buf->ra0.ptr.p_double[offs0+1] = v01; buf->ra0.ptr.p_double[offs0+stride] = v10; buf->ra0.ptr.p_double[offs0+stride+1] = v11; i1 = i1+2; } i0 = i0+2; } } for(i=0; i<=pcnt-1; i++) { cclosest = buf->ia3.ptr.p_int[i]; dclosest = buf->ra3.ptr.p_double[i]; for(j=0; j<=ccnt-1; j++) { if( ae_fp_less(buf->ra0.ptr.p_double[i*stride+j],dclosest) ) { dclosest = buf->ra0.ptr.p_double[i*stride+j]; cclosest = c0+j; } } buf->ia3.ptr.p_int[i] = cclosest; buf->ra3.ptr.p_double[i] = dclosest; } } /* * Store best centers to XYC[] */ for(i=p0; i<=p1-1; i++) { xyc->ptr.p_int[i] = buf->ia3.ptr.p_int[i-p0]; xydist2->ptr.p_double[i] = buf->ra3.ptr.p_double[i-p0]; } } ae_shared_pool_recycle(bufferpool, &_buf, _state); ae_frame_leave(_state); } /************************************************************************* This function selects initial centers according to specified initialization algorithm. IMPORTANT: this function provides no guarantees regarding selection of DIFFERENT centers. Centers returned by this function may include duplicates (say, when random sampling is used). It is also possible that some centers are empty. Algorithm which uses this function must be able to deal with it. Say, you may want to use FixCenters() in order to fix empty centers. INPUT PARAMETERS: XY - dataset, array [0..NPoints-1,0..NVars-1]. NPoints - points count NVars - number of variables, NVars>=1 InitAlgo - initialization algorithm: * 0 - automatic selection of best algorithm * 1 - random selection * 2 - k-means++ * 3 - fast-greedy init *-1 - first K rows of dataset are used (debug algorithm) K - number of centers, K>=1 CT - possibly preallocated output buffer, resized if needed InitBuf - internal buffer, possibly unitialized instance of APBuffers. It is recommended to use this instance only with SelectInitialCenters() and FixCenters() functions, because these functions may allocate really large storage. UpdatePool - shared pool seeded with instance of APBuffers structure (seed instance can be unitialized). Used internally with KMeansUpdateDistances() function. It is recommended to use this pool ONLY with KMeansUpdateDistances() function. OUTPUT PARAMETERS: CT - set of K clusters, one per row RESULT: True on success, False on failure (impossible to create K independent clusters) -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ static void clustering_selectinitialcenters(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t initalgo, ae_int_t k, /* Real */ ae_matrix* ct, apbuffers* initbuf, ae_shared_pool* updatepool, ae_state *_state) { ae_frame _frame_block; ae_int_t cidx; ae_int_t i; ae_int_t j; double v; double vv; double s; ae_int_t lastnz; ae_int_t ptidx; ae_int_t samplesize; ae_int_t samplescntnew; ae_int_t samplescntall; double samplescale; hqrndstate rs; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Check parameters */ ae_assert(npoints>0, "SelectInitialCenters: internal error", _state); ae_assert(nvars>0, "SelectInitialCenters: internal error", _state); ae_assert(k>0, "SelectInitialCenters: internal error", _state); if( initalgo==0 ) { initalgo = 3; } rmatrixsetlengthatleast(ct, k, nvars, _state); /* * Random initialization */ if( initalgo==-1 ) { for(i=0; i<=k-1; i++) { ae_v_move(&ct->ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i%npoints][0], 1, ae_v_len(0,nvars-1)); } ae_frame_leave(_state); return; } /* * Random initialization */ if( initalgo==1 ) { for(i=0; i<=k-1; i++) { j = hqrnduniformi(&rs, npoints, _state); ae_v_move(&ct->ptr.pp_double[i][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); } ae_frame_leave(_state); return; } /* * k-means++ initialization */ if( initalgo==2 ) { /* * Prepare distances array. * Select initial center at random. */ rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); for(i=0; i<=npoints-1; i++) { initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; } ptidx = hqrnduniformi(&rs, npoints, _state); ae_v_move(&ct->ptr.pp_double[0][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); /* * For each newly added center repeat: * * reevaluate distances from points to best centers * * sample points with probability dependent on distance * * add new center */ for(cidx=0; cidx<=k-2; cidx++) { /* * Reevaluate distances */ s = 0.0; for(i=0; i<=npoints-1; i++) { v = 0.0; for(j=0; j<=nvars-1; j++) { vv = xy->ptr.pp_double[i][j]-ct->ptr.pp_double[cidx][j]; v = v+vv*vv; } if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) { initbuf->ra0.ptr.p_double[i] = v; } s = s+initbuf->ra0.ptr.p_double[i]; } /* * If all distances are zero, it means that we can not find enough * distinct points. In this case we just select non-distinct center * at random and continue iterations. This issue will be handled * later in the FixCenters() function. */ if( ae_fp_eq(s,0.0) ) { ptidx = hqrnduniformi(&rs, npoints, _state); ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); continue; } /* * Select point as center using its distance. * We also handle situation when because of rounding errors * no point was selected - in this case, last non-zero one * will be used. */ v = hqrnduniformr(&rs, _state); vv = 0.0; lastnz = -1; ptidx = -1; for(i=0; i<=npoints-1; i++) { if( ae_fp_eq(initbuf->ra0.ptr.p_double[i],0.0) ) { continue; } lastnz = i; vv = vv+initbuf->ra0.ptr.p_double[i]; if( ae_fp_less_eq(v,vv/s) ) { ptidx = i; break; } } ae_assert(lastnz>=0, "SelectInitialCenters: integrity error", _state); if( ptidx<0 ) { ptidx = lastnz; } ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); } ae_frame_leave(_state); return; } /* * "Fast-greedy" algorithm based on "Scalable k-means++". * * We perform several rounds, within each round we sample about 0.5*K points * (not exactly 0.5*K) until we have 2*K points sampled. Before each round * we calculate distances from dataset points to closest points sampled so far. * We sample dataset points independently using distance xtimes 0.5*K divided by total * as probability (similar to k-means++, but each point is sampled independently; * after each round we have roughtly 0.5*K points added to sample). * * After sampling is done, we run "greedy" version of k-means++ on this subsample * which selects most distant point on every round. */ if( initalgo==3 ) { /* * Prepare arrays. * Select initial center at random, add it to "new" part of sample, * which is stored at the beginning of the array */ samplesize = 2*k; samplescale = 0.5*k; rmatrixsetlengthatleast(&initbuf->rm0, samplesize, nvars, _state); ptidx = hqrnduniformi(&rs, npoints, _state); ae_v_move(&initbuf->rm0.ptr.pp_double[0][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); samplescntnew = 1; samplescntall = 1; rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); rvectorsetlengthatleast(&initbuf->ra1, npoints, _state); ivectorsetlengthatleast(&initbuf->ia1, npoints, _state); for(i=0; i<=npoints-1; i++) { initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; } /* * Repeat until samples count is 2*K */ while(samplescntallrm0, samplescntall-samplescntnew, samplescntall, &initbuf->ia1, &initbuf->ra1, updatepool, _state); samplescntnew = 0; /* * Merge new distances with old ones. * Calculate sum of distances, if sum is exactly zero - fill sample * by randomly selected points and terminate. */ s = 0.0; for(i=0; i<=npoints-1; i++) { initbuf->ra0.ptr.p_double[i] = ae_minreal(initbuf->ra0.ptr.p_double[i], initbuf->ra1.ptr.p_double[i], _state); s = s+initbuf->ra0.ptr.p_double[i]; } if( ae_fp_eq(s,0.0) ) { while(samplescntallrm0.ptr.pp_double[samplescntall][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); inc(&samplescntall, _state); inc(&samplescntnew, _state); } break; } /* * Sample points independently. */ for(i=0; i<=npoints-1; i++) { if( samplescntall==samplesize ) { break; } if( ae_fp_eq(initbuf->ra0.ptr.p_double[i],0.0) ) { continue; } if( ae_fp_less_eq(hqrnduniformr(&rs, _state),samplescale*initbuf->ra0.ptr.p_double[i]/s) ) { ae_v_move(&initbuf->rm0.ptr.pp_double[samplescntall][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); inc(&samplescntall, _state); inc(&samplescntnew, _state); } } } /* * Run greedy version of k-means on sampled points */ rvectorsetlengthatleast(&initbuf->ra0, samplescntall, _state); for(i=0; i<=samplescntall-1; i++) { initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; } ptidx = hqrnduniformi(&rs, samplescntall, _state); ae_v_move(&ct->ptr.pp_double[0][0], 1, &initbuf->rm0.ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); for(cidx=0; cidx<=k-2; cidx++) { /* * Reevaluate distances */ for(i=0; i<=samplescntall-1; i++) { v = 0.0; for(j=0; j<=nvars-1; j++) { vv = initbuf->rm0.ptr.pp_double[i][j]-ct->ptr.pp_double[cidx][j]; v = v+vv*vv; } if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) { initbuf->ra0.ptr.p_double[i] = v; } } /* * Select point as center in greedy manner - most distant * point is selected. */ ptidx = 0; for(i=0; i<=samplescntall-1; i++) { if( ae_fp_greater(initbuf->ra0.ptr.p_double[i],initbuf->ra0.ptr.p_double[ptidx]) ) { ptidx = i; } } ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &initbuf->rm0.ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); } ae_frame_leave(_state); return; } /* * Internal error */ ae_assert(ae_false, "SelectInitialCenters: internal error", _state); ae_frame_leave(_state); } /************************************************************************* This function "fixes" centers, i.e. replaces ones which have no neighbor points by new centers which have at least one neighbor. If it is impossible to fix centers (not enough distinct points in the dataset), this function returns False. INPUT PARAMETERS: XY - dataset, array [0..NPoints-1,0..NVars-1]. NPoints - points count, >=1 NVars - number of variables, NVars>=1 CT - centers K - number of centers, K>=1 InitBuf - internal buffer, possibly unitialized instance of APBuffers. It is recommended to use this instance only with SelectInitialCenters() and FixCenters() functions, because these functions may allocate really large storage. UpdatePool - shared pool seeded with instance of APBuffers structure (seed instance can be unitialized). Used internally with KMeansUpdateDistances() function. It is recommended to use this pool ONLY with KMeansUpdateDistances() function. OUTPUT PARAMETERS: CT - set of K centers, one per row RESULT: True on success, False on failure (impossible to create K independent clusters) -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ static ae_bool clustering_fixcenters(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t k, apbuffers* initbuf, ae_shared_pool* updatepool, ae_state *_state) { ae_int_t fixiteration; ae_int_t centertofix; ae_int_t i; ae_int_t j; ae_int_t pdistant; double ddistant; double v; ae_bool result; ae_assert(npoints>=1, "FixCenters: internal error", _state); ae_assert(nvars>=1, "FixCenters: internal error", _state); ae_assert(k>=1, "FixCenters: internal error", _state); /* * Calculate distances from points to best centers (RA0) * and best center indexes (IA0) */ ivectorsetlengthatleast(&initbuf->ia0, npoints, _state); rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); kmeansupdatedistances(xy, 0, npoints, nvars, ct, 0, k, &initbuf->ia0, &initbuf->ra0, updatepool, _state); /* * Repeat loop: * * find first center which has no corresponding point * * set it to the most distant (from the rest of the centerset) point * * recalculate distances, update IA0/RA0 * * repeat * * Loop is repeated for at most 2*K iterations. It is stopped once we have * no "empty" clusters. */ bvectorsetlengthatleast(&initbuf->ba0, k, _state); for(fixiteration=0; fixiteration<=2*k; fixiteration++) { /* * Select center to fix (one which is not mentioned in IA0), * terminate if there is no such center. * BA0[] stores True for centers which have at least one point. */ for(i=0; i<=k-1; i++) { initbuf->ba0.ptr.p_bool[i] = ae_false; } for(i=0; i<=npoints-1; i++) { initbuf->ba0.ptr.p_bool[initbuf->ia0.ptr.p_int[i]] = ae_true; } centertofix = -1; for(i=0; i<=k-1; i++) { if( !initbuf->ba0.ptr.p_bool[i] ) { centertofix = i; break; } } if( centertofix<0 ) { result = ae_true; return result; } /* * Replace center to fix by the most distant point. * Update IA0/RA0 */ pdistant = 0; ddistant = initbuf->ra0.ptr.p_double[pdistant]; for(i=0; i<=npoints-1; i++) { if( ae_fp_greater(initbuf->ra0.ptr.p_double[i],ddistant) ) { ddistant = initbuf->ra0.ptr.p_double[i]; pdistant = i; } } if( ae_fp_eq(ddistant,0.0) ) { break; } ae_v_move(&ct->ptr.pp_double[centertofix][0], 1, &xy->ptr.pp_double[pdistant][0], 1, ae_v_len(0,nvars-1)); for(i=0; i<=npoints-1; i++) { v = 0.0; for(j=0; j<=nvars-1; j++) { v = v+ae_sqr(xy->ptr.pp_double[i][j]-ct->ptr.pp_double[centertofix][j], _state); } if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) { initbuf->ra0.ptr.p_double[i] = v; initbuf->ia0.ptr.p_int[i] = centertofix; } } } result = ae_false; return result; } /************************************************************************* This function performs agglomerative hierarchical clustering using precomputed distance matrix. Internal function, should not be called directly. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - distance matrix, array[S.NFeatures,S.NFeatures] Contents of the matrix is destroyed during algorithm operation. OUTPUT PARAMETERS: Rep - clustering results; see description of AHCReport structure for more information. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ static void clustering_clusterizerrunahcinternal(clusterizerstate* s, /* Real */ ae_matrix* d, ahcreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_int_t mergeidx; ae_int_t c0; ae_int_t c1; ae_int_t s0; ae_int_t s1; ae_int_t ar; ae_int_t br; ae_int_t npoints; ae_vector cidx; ae_vector csizes; ae_vector nnidx; ae_matrix cinfo; ae_int_t n0; ae_int_t n1; ae_int_t ni; double d01; ae_frame_make(_state, &_frame_block); ae_vector_init(&cidx, 0, DT_INT, _state); ae_vector_init(&csizes, 0, DT_INT, _state); ae_vector_init(&nnidx, 0, DT_INT, _state); ae_matrix_init(&cinfo, 0, 0, DT_INT, _state); npoints = s->npoints; /* * Fill Rep.NPoints, quick exit when NPoints<=1 */ rep->npoints = npoints; if( npoints==0 ) { ae_vector_set_length(&rep->p, 0, _state); ae_matrix_set_length(&rep->z, 0, 0, _state); ae_matrix_set_length(&rep->pz, 0, 0, _state); ae_matrix_set_length(&rep->pm, 0, 0, _state); ae_vector_set_length(&rep->mergedist, 0, _state); rep->terminationtype = 1; ae_frame_leave(_state); return; } if( npoints==1 ) { ae_vector_set_length(&rep->p, 1, _state); ae_matrix_set_length(&rep->z, 0, 0, _state); ae_matrix_set_length(&rep->pz, 0, 0, _state); ae_matrix_set_length(&rep->pm, 0, 0, _state); ae_vector_set_length(&rep->mergedist, 0, _state); rep->p.ptr.p_int[0] = 0; rep->terminationtype = 1; ae_frame_leave(_state); return; } ae_matrix_set_length(&rep->z, npoints-1, 2, _state); ae_vector_set_length(&rep->mergedist, npoints-1, _state); rep->terminationtype = 1; /* * Build list of nearest neighbors */ ae_vector_set_length(&nnidx, npoints, _state); for(i=0; i<=npoints-1; i++) { /* * Calculate index of the nearest neighbor */ k = -1; v = ae_maxrealnumber; for(j=0; j<=npoints-1; j++) { if( j!=i&&ae_fp_less(d->ptr.pp_double[i][j],v) ) { k = j; v = d->ptr.pp_double[i][j]; } } ae_assert(ae_fp_less(v,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); nnidx.ptr.p_int[i] = k; } /* * For AHCAlgo=4 (Ward's method) replace distances by their squares times 0.5 */ if( s->ahcalgo==4 ) { for(i=0; i<=npoints-1; i++) { for(j=0; j<=npoints-1; j++) { d->ptr.pp_double[i][j] = 0.5*d->ptr.pp_double[i][j]*d->ptr.pp_double[i][j]; } } } /* * Distance matrix is built, perform merges. * * NOTE 1: CIdx is array[NPoints] which maps rows/columns of the * distance matrix D to indexes of clusters. Values of CIdx * from [0,NPoints) denote single-point clusters, and values * from [NPoints,2*NPoints-1) denote ones obtained by merging * smaller clusters. Negative calues correspond to absent clusters. * * Initially it contains [0...NPoints-1], after each merge * one element of CIdx (one with index C0) is replaced by * NPoints+MergeIdx, and another one with index C1 is * rewritten by -1. * * NOTE 2: CSizes is array[NPoints] which stores sizes of clusters. * */ ae_vector_set_length(&cidx, npoints, _state); ae_vector_set_length(&csizes, npoints, _state); for(i=0; i<=npoints-1; i++) { cidx.ptr.p_int[i] = i; csizes.ptr.p_int[i] = 1; } for(mergeidx=0; mergeidx<=npoints-2; mergeidx++) { /* * Select pair of clusters (C0,C1) with CIdx[C0]=0 ) { if( ae_fp_less(d->ptr.pp_double[i][nnidx.ptr.p_int[i]],d01) ) { c0 = i; c1 = nnidx.ptr.p_int[i]; d01 = d->ptr.pp_double[i][nnidx.ptr.p_int[i]]; } } } ae_assert(ae_fp_less(d01,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); if( cidx.ptr.p_int[c0]>cidx.ptr.p_int[c1] ) { i = c1; c1 = c0; c0 = i; } /* * Fill one row of Rep.Z and one element of Rep.MergeDist */ rep->z.ptr.pp_int[mergeidx][0] = cidx.ptr.p_int[c0]; rep->z.ptr.pp_int[mergeidx][1] = cidx.ptr.p_int[c1]; rep->mergedist.ptr.p_double[mergeidx] = d01; /* * Update distance matrix: * * row/column C0 are updated by distances to the new cluster * * row/column C1 are considered empty (we can fill them by zeros, * but do not want to spend time - we just ignore them) * * NOTE: it is important to update distance matrix BEFORE CIdx/CSizes * are updated. */ ae_assert((((s->ahcalgo==0||s->ahcalgo==1)||s->ahcalgo==2)||s->ahcalgo==3)||s->ahcalgo==4, "ClusterizerRunAHC: internal error", _state); for(i=0; i<=npoints-1; i++) { if( i!=c0&&i!=c1 ) { n0 = csizes.ptr.p_int[c0]; n1 = csizes.ptr.p_int[c1]; ni = csizes.ptr.p_int[i]; if( s->ahcalgo==0 ) { d->ptr.pp_double[i][c0] = ae_maxreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); } if( s->ahcalgo==1 ) { d->ptr.pp_double[i][c0] = ae_minreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); } if( s->ahcalgo==2 ) { d->ptr.pp_double[i][c0] = (csizes.ptr.p_int[c0]*d->ptr.pp_double[i][c0]+csizes.ptr.p_int[c1]*d->ptr.pp_double[i][c1])/(csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]); } if( s->ahcalgo==3 ) { d->ptr.pp_double[i][c0] = (d->ptr.pp_double[i][c0]+d->ptr.pp_double[i][c1])/2; } if( s->ahcalgo==4 ) { d->ptr.pp_double[i][c0] = ((n0+ni)*d->ptr.pp_double[i][c0]+(n1+ni)*d->ptr.pp_double[i][c1]-ni*d01)/(n0+n1+ni); } d->ptr.pp_double[c0][i] = d->ptr.pp_double[i][c0]; } } /* * Update CIdx and CSizes */ cidx.ptr.p_int[c0] = npoints+mergeidx; cidx.ptr.p_int[c1] = -1; csizes.ptr.p_int[c0] = csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]; csizes.ptr.p_int[c1] = 0; /* * Update nearest neighbors array: * * update nearest neighbors of everything except for C0/C1 * * update neighbors of C0/C1 */ for(i=0; i<=npoints-1; i++) { if( (cidx.ptr.p_int[i]>=0&&i!=c0)&&(nnidx.ptr.p_int[i]==c0||nnidx.ptr.p_int[i]==c1) ) { /* * I-th cluster which is distinct from C0/C1 has former C0/C1 cluster as its nearest * neighbor. We handle this issue depending on specific AHC algorithm being used. */ if( s->ahcalgo==1 ) { /* * Single linkage. Merging of two clusters together * does NOT change distances between new cluster and * other clusters. * * The only thing we have to do is to update nearest neighbor index */ nnidx.ptr.p_int[i] = c0; } else { /* * Something other than single linkage. We have to re-examine * all the row to find nearest neighbor. */ k = -1; v = ae_maxrealnumber; for(j=0; j<=npoints-1; j++) { if( (cidx.ptr.p_int[j]>=0&&j!=i)&&ae_fp_less(d->ptr.pp_double[i][j],v) ) { k = j; v = d->ptr.pp_double[i][j]; } } ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); nnidx.ptr.p_int[i] = k; } } } k = -1; v = ae_maxrealnumber; for(j=0; j<=npoints-1; j++) { if( (cidx.ptr.p_int[j]>=0&&j!=c0)&&ae_fp_less(d->ptr.pp_double[c0][j],v) ) { k = j; v = d->ptr.pp_double[c0][j]; } } ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); nnidx.ptr.p_int[c0] = k; } /* * Calculate Rep.P and Rep.PM. * * In order to do that, we fill CInfo matrix - (2*NPoints-1)*3 matrix, * with I-th row containing: * * CInfo[I,0] - size of I-th cluster * * CInfo[I,1] - beginning of I-th cluster * * CInfo[I,2] - end of I-th cluster * * CInfo[I,3] - height of I-th cluster * * We perform it as follows: * * first NPoints clusters have unit size (CInfo[I,0]=1) and zero * height (CInfo[I,3]=0) * * we replay NPoints-1 merges from first to last and fill sizes of * corresponding clusters (new size is a sum of sizes of clusters * being merged) and height (new height is max(heights)+1). * * now we ready to determine locations of clusters. Last cluster * spans entire dataset, we know it. We replay merges from last to * first, during each merge we already know location of the merge * result, and we can position first cluster to the left part of * the result, and second cluster to the right part. */ ae_vector_set_length(&rep->p, npoints, _state); ae_matrix_set_length(&rep->pm, npoints-1, 6, _state); ae_matrix_set_length(&cinfo, 2*npoints-1, 4, _state); for(i=0; i<=npoints-1; i++) { cinfo.ptr.pp_int[i][0] = 1; cinfo.ptr.pp_int[i][3] = 0; } for(i=0; i<=npoints-2; i++) { cinfo.ptr.pp_int[npoints+i][0] = cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][0]+cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][0]; cinfo.ptr.pp_int[npoints+i][3] = ae_maxint(cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][3], cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][3], _state)+1; } cinfo.ptr.pp_int[2*npoints-2][1] = 0; cinfo.ptr.pp_int[2*npoints-2][2] = npoints-1; for(i=npoints-2; i>=0; i--) { /* * We merge C0 which spans [A0,B0] and C1 (spans [A1,B1]), * with unknown A0, B0, A1, B1. However, we know that result * is CR, which spans [AR,BR] with known AR/BR, and we know * sizes of C0, C1, CR (denotes as S0, S1, SR). */ c0 = rep->z.ptr.pp_int[i][0]; c1 = rep->z.ptr.pp_int[i][1]; s0 = cinfo.ptr.pp_int[c0][0]; s1 = cinfo.ptr.pp_int[c1][0]; ar = cinfo.ptr.pp_int[npoints+i][1]; br = cinfo.ptr.pp_int[npoints+i][2]; cinfo.ptr.pp_int[c0][1] = ar; cinfo.ptr.pp_int[c0][2] = ar+s0-1; cinfo.ptr.pp_int[c1][1] = br-(s1-1); cinfo.ptr.pp_int[c1][2] = br; rep->pm.ptr.pp_int[i][0] = cinfo.ptr.pp_int[c0][1]; rep->pm.ptr.pp_int[i][1] = cinfo.ptr.pp_int[c0][2]; rep->pm.ptr.pp_int[i][2] = cinfo.ptr.pp_int[c1][1]; rep->pm.ptr.pp_int[i][3] = cinfo.ptr.pp_int[c1][2]; rep->pm.ptr.pp_int[i][4] = cinfo.ptr.pp_int[c0][3]; rep->pm.ptr.pp_int[i][5] = cinfo.ptr.pp_int[c1][3]; } for(i=0; i<=npoints-1; i++) { ae_assert(cinfo.ptr.pp_int[i][1]==cinfo.ptr.pp_int[i][2], "Assertion failed", _state); rep->p.ptr.p_int[i] = cinfo.ptr.pp_int[i][1]; } /* * Calculate Rep.PZ */ ae_matrix_set_length(&rep->pz, npoints-1, 2, _state); for(i=0; i<=npoints-2; i++) { rep->pz.ptr.pp_int[i][0] = rep->z.ptr.pp_int[i][0]; rep->pz.ptr.pp_int[i][1] = rep->z.ptr.pp_int[i][1]; if( rep->pz.ptr.pp_int[i][0]pz.ptr.pp_int[i][0] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][0]]; } if( rep->pz.ptr.pp_int[i][1]pz.ptr.pp_int[i][1] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][1]]; } } ae_frame_leave(_state); } /************************************************************************* This function recursively evaluates distance matrix for SOME (not all!) distance types. INPUT PARAMETERS: XY - array[?,NFeatures], dataset NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) D - preallocated output matrix I0,I1 - half interval of rows to calculate: [I0,I1) is processed J0,J1 - half interval of cols to calculate: [J0,J1) is processed OUTPUT PARAMETERS: D - array[NPoints,NPoints], distance matrix upper triangle and main diagonal are initialized with data. NOTE: intersection of [I0,I1) and [J0,J1) may completely lie in upper triangle, only partially intersect with it, or have zero intersection. In any case, only intersection of submatrix given by [I0,I1)*[J0,J1) with upper triangle of the matrix is evaluated. Say, for 4x4 distance matrix A: * [0,2)*[0,2) will result in evaluation of A00, A01, A11 * [2,4)*[2,4) will result in evaluation of A22, A23, A32, A33 * [2,4)*[0,2) will result in evaluation of empty set of elements -- ALGLIB -- Copyright 07.04.2013 by Bochkanov Sergey *************************************************************************/ static void clustering_evaluatedistancematrixrec(/* Real */ ae_matrix* xy, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_int_t i0, ae_int_t i1, ae_int_t j0, ae_int_t j1, ae_state *_state) { double rcomplexity; ae_int_t len0; ae_int_t len1; ae_int_t i; ae_int_t j; ae_int_t k; double v; double vv; ae_assert(disttype==0||disttype==1, "EvaluateDistanceMatrixRec: incorrect DistType", _state); /* * Normalize J0/J1: * * J0:=max(J0,I0) - we ignore lower triangle * * J1:=max(J1,J0) - normalize J1 */ j0 = ae_maxint(j0, i0, _state); j1 = ae_maxint(j1, j0, _state); if( j1<=j0||i1<=i0 ) { return; } /* * Try to process in parallel. Two condtions must hold in order to * activate parallel processing: * 1. I1-I0>2 or J1-J0>2 * 2. (I1-I0)*(J1-J0)*NFeatures>=ParallelComplexity * * NOTE: all quantities are converted to reals in order to avoid * integer overflow during multiplication * * NOTE: strict inequality in (1) is necessary to reduce task to 2x2 * basecases. In future versions we will be able to handle such * basecases more efficiently than 1x1 cases. */ rcomplexity = (double)(i1-i0); rcomplexity = rcomplexity*(j1-j0); rcomplexity = rcomplexity*nfeatures; if( ae_fp_greater_eq(rcomplexity,clustering_parallelcomplexity)&&(i1-i0>2||j1-j0>2) ) { /* * Recursive division along largest of dimensions */ if( i1-i0>j1-j0 ) { splitlengtheven(i1-i0, &len0, &len1, _state); clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i0+len0, j0, j1, _state); clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0+len0, i1, j0, j1, _state); } else { splitlengtheven(j1-j0, &len0, &len1, _state); clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0, j0+len0, _state); clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0+len0, j1, _state); } return; } /* * Sequential processing */ for(i=i0; i<=i1-1; i++) { for(j=j0; j<=j1-1; j++) { if( j>=i ) { v = 0.0; if( disttype==0 ) { for(k=0; k<=nfeatures-1; k++) { vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; if( ae_fp_less(vv,(double)(0)) ) { vv = -vv; } if( ae_fp_greater(vv,v) ) { v = vv; } } } if( disttype==1 ) { for(k=0; k<=nfeatures-1; k++) { vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; if( ae_fp_less(vv,(double)(0)) ) { vv = -vv; } v = v+vv; } } d->ptr.pp_double[i][j] = v; } } } } void _kmeansbuffers_init(void* _p, ae_state *_state) { kmeansbuffers *p = (kmeansbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->ct, 0, 0, DT_REAL, _state); ae_matrix_init(&p->ctbest, 0, 0, DT_REAL, _state); ae_vector_init(&p->xycbest, 0, DT_INT, _state); ae_vector_init(&p->xycprev, 0, DT_INT, _state); ae_vector_init(&p->d2, 0, DT_REAL, _state); ae_vector_init(&p->csizes, 0, DT_INT, _state); _apbuffers_init(&p->initbuf, _state); ae_shared_pool_init(&p->updatepool, _state); } void _kmeansbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { kmeansbuffers *dst = (kmeansbuffers*)_dst; kmeansbuffers *src = (kmeansbuffers*)_src; ae_matrix_init_copy(&dst->ct, &src->ct, _state); ae_matrix_init_copy(&dst->ctbest, &src->ctbest, _state); ae_vector_init_copy(&dst->xycbest, &src->xycbest, _state); ae_vector_init_copy(&dst->xycprev, &src->xycprev, _state); ae_vector_init_copy(&dst->d2, &src->d2, _state); ae_vector_init_copy(&dst->csizes, &src->csizes, _state); _apbuffers_init_copy(&dst->initbuf, &src->initbuf, _state); ae_shared_pool_init_copy(&dst->updatepool, &src->updatepool, _state); } void _kmeansbuffers_clear(void* _p) { kmeansbuffers *p = (kmeansbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->ct); ae_matrix_clear(&p->ctbest); ae_vector_clear(&p->xycbest); ae_vector_clear(&p->xycprev); ae_vector_clear(&p->d2); ae_vector_clear(&p->csizes); _apbuffers_clear(&p->initbuf); ae_shared_pool_clear(&p->updatepool); } void _kmeansbuffers_destroy(void* _p) { kmeansbuffers *p = (kmeansbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->ct); ae_matrix_destroy(&p->ctbest); ae_vector_destroy(&p->xycbest); ae_vector_destroy(&p->xycprev); ae_vector_destroy(&p->d2); ae_vector_destroy(&p->csizes); _apbuffers_destroy(&p->initbuf); ae_shared_pool_destroy(&p->updatepool); } void _clusterizerstate_init(void* _p, ae_state *_state) { clusterizerstate *p = (clusterizerstate*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state); ae_matrix_init(&p->d, 0, 0, DT_REAL, _state); ae_matrix_init(&p->tmpd, 0, 0, DT_REAL, _state); _apbuffers_init(&p->distbuf, _state); _kmeansbuffers_init(&p->kmeanstmp, _state); } void _clusterizerstate_init_copy(void* _dst, void* _src, ae_state *_state) { clusterizerstate *dst = (clusterizerstate*)_dst; clusterizerstate *src = (clusterizerstate*)_src; dst->npoints = src->npoints; dst->nfeatures = src->nfeatures; dst->disttype = src->disttype; ae_matrix_init_copy(&dst->xy, &src->xy, _state); ae_matrix_init_copy(&dst->d, &src->d, _state); dst->ahcalgo = src->ahcalgo; dst->kmeansrestarts = src->kmeansrestarts; dst->kmeansmaxits = src->kmeansmaxits; dst->kmeansinitalgo = src->kmeansinitalgo; dst->kmeansdbgnoits = src->kmeansdbgnoits; ae_matrix_init_copy(&dst->tmpd, &src->tmpd, _state); _apbuffers_init_copy(&dst->distbuf, &src->distbuf, _state); _kmeansbuffers_init_copy(&dst->kmeanstmp, &src->kmeanstmp, _state); } void _clusterizerstate_clear(void* _p) { clusterizerstate *p = (clusterizerstate*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->xy); ae_matrix_clear(&p->d); ae_matrix_clear(&p->tmpd); _apbuffers_clear(&p->distbuf); _kmeansbuffers_clear(&p->kmeanstmp); } void _clusterizerstate_destroy(void* _p) { clusterizerstate *p = (clusterizerstate*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->xy); ae_matrix_destroy(&p->d); ae_matrix_destroy(&p->tmpd); _apbuffers_destroy(&p->distbuf); _kmeansbuffers_destroy(&p->kmeanstmp); } void _ahcreport_init(void* _p, ae_state *_state) { ahcreport *p = (ahcreport*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->p, 0, DT_INT, _state); ae_matrix_init(&p->z, 0, 0, DT_INT, _state); ae_matrix_init(&p->pz, 0, 0, DT_INT, _state); ae_matrix_init(&p->pm, 0, 0, DT_INT, _state); ae_vector_init(&p->mergedist, 0, DT_REAL, _state); } void _ahcreport_init_copy(void* _dst, void* _src, ae_state *_state) { ahcreport *dst = (ahcreport*)_dst; ahcreport *src = (ahcreport*)_src; dst->terminationtype = src->terminationtype; dst->npoints = src->npoints; ae_vector_init_copy(&dst->p, &src->p, _state); ae_matrix_init_copy(&dst->z, &src->z, _state); ae_matrix_init_copy(&dst->pz, &src->pz, _state); ae_matrix_init_copy(&dst->pm, &src->pm, _state); ae_vector_init_copy(&dst->mergedist, &src->mergedist, _state); } void _ahcreport_clear(void* _p) { ahcreport *p = (ahcreport*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->p); ae_matrix_clear(&p->z); ae_matrix_clear(&p->pz); ae_matrix_clear(&p->pm); ae_vector_clear(&p->mergedist); } void _ahcreport_destroy(void* _p) { ahcreport *p = (ahcreport*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->p); ae_matrix_destroy(&p->z); ae_matrix_destroy(&p->pz); ae_matrix_destroy(&p->pm); ae_vector_destroy(&p->mergedist); } void _kmeansreport_init(void* _p, ae_state *_state) { kmeansreport *p = (kmeansreport*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->c, 0, 0, DT_REAL, _state); ae_vector_init(&p->cidx, 0, DT_INT, _state); } void _kmeansreport_init_copy(void* _dst, void* _src, ae_state *_state) { kmeansreport *dst = (kmeansreport*)_dst; kmeansreport *src = (kmeansreport*)_src; dst->npoints = src->npoints; dst->nfeatures = src->nfeatures; dst->terminationtype = src->terminationtype; dst->iterationscount = src->iterationscount; dst->energy = src->energy; dst->k = src->k; ae_matrix_init_copy(&dst->c, &src->c, _state); ae_vector_init_copy(&dst->cidx, &src->cidx, _state); } void _kmeansreport_clear(void* _p) { kmeansreport *p = (kmeansreport*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->c); ae_vector_clear(&p->cidx); } void _kmeansreport_destroy(void* _p) { kmeansreport *p = (kmeansreport*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->c); ae_vector_destroy(&p->cidx); } /************************************************************************* k-means++ clusterization. Backward compatibility function, we recommend to use CLUSTERING subpackage as better replacement. -- ALGLIB -- Copyright 21.03.2009 by Bochkanov Sergey *************************************************************************/ void kmeansgenerate(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t k, ae_int_t restarts, ae_int_t* info, /* Real */ ae_matrix* c, /* Integer */ ae_vector* xyc, ae_state *_state) { ae_frame _frame_block; ae_matrix dummy; ae_int_t itscnt; double e; kmeansbuffers buf; ae_frame_make(_state, &_frame_block); *info = 0; ae_matrix_clear(c); ae_vector_clear(xyc); ae_matrix_init(&dummy, 0, 0, DT_REAL, _state); _kmeansbuffers_init(&buf, _state); kmeansinitbuf(&buf, _state); kmeansgenerateinternal(xy, npoints, nvars, k, 0, 0, restarts, ae_false, info, &itscnt, c, ae_true, &dummy, ae_false, xyc, &e, &buf, _state); ae_frame_leave(_state); } /************************************************************************* This subroutine builds random decision forest. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforest(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, double r, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state) { ae_int_t samplesize; *info = 0; _decisionforest_clear(df); _dfreport_clear(rep); if( ae_fp_less_eq(r,(double)(0))||ae_fp_greater(r,(double)(1)) ) { *info = -1; return; } samplesize = ae_maxint(ae_round(r*npoints, _state), 1, _state); dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, ae_maxint(nvars/2, 1, _state), dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); } /************************************************************************* This subroutine builds random decision forest. This function gives ability to tune number of variables used when choosing best split. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. NRndVars - number of variables used when choosing best split R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforestx1(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, ae_int_t nrndvars, double r, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state) { ae_int_t samplesize; *info = 0; _decisionforest_clear(df); _dfreport_clear(rep); if( ae_fp_less_eq(r,(double)(0))||ae_fp_greater(r,(double)(1)) ) { *info = -1; return; } if( nrndvars<=0||nrndvars>nvars ) { *info = -1; return; } samplesize = ae_maxint(ae_round(r*npoints, _state), 1, _state); dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, nrndvars, dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); } void dfbuildinternal(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, ae_int_t samplesize, ae_int_t nfeatures, ae_int_t flags, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t tmpi; ae_int_t lasttreeoffs; ae_int_t offs; ae_int_t ooboffs; ae_int_t treesize; ae_int_t nvarsinpool; ae_bool useevs; dfinternalbuffers bufs; ae_vector permbuf; ae_vector oobbuf; ae_vector oobcntbuf; ae_matrix xys; ae_vector x; ae_vector y; ae_int_t oobcnt; ae_int_t oobrelcnt; double v; double vmin; double vmax; ae_bool bflag; hqrndstate rs; ae_frame_make(_state, &_frame_block); *info = 0; _decisionforest_clear(df); _dfreport_clear(rep); _dfinternalbuffers_init(&bufs, _state); ae_vector_init(&permbuf, 0, DT_INT, _state); ae_vector_init(&oobbuf, 0, DT_REAL, _state); ae_vector_init(&oobcntbuf, 0, DT_INT, _state); ae_matrix_init(&xys, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); /* * Test for inputs */ if( (((((npoints<1||samplesize<1)||samplesize>npoints)||nvars<1)||nclasses<1)||ntrees<1)||nfeatures<1 ) { *info = -1; ae_frame_leave(_state); return; } if( nclasses>1 ) { for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) { *info = -2; ae_frame_leave(_state); return; } } } *info = 1; /* * Flags */ useevs = flags/dforest_dfuseevs%2!=0; /* * Allocate data, prepare header */ treesize = 1+dforest_innernodewidth*(samplesize-1)+dforest_leafnodewidth*samplesize; ae_vector_set_length(&permbuf, npoints-1+1, _state); ae_vector_set_length(&bufs.treebuf, treesize-1+1, _state); ae_vector_set_length(&bufs.idxbuf, npoints-1+1, _state); ae_vector_set_length(&bufs.tmpbufr, npoints-1+1, _state); ae_vector_set_length(&bufs.tmpbufr2, npoints-1+1, _state); ae_vector_set_length(&bufs.tmpbufi, npoints-1+1, _state); ae_vector_set_length(&bufs.sortrbuf, npoints, _state); ae_vector_set_length(&bufs.sortrbuf2, npoints, _state); ae_vector_set_length(&bufs.sortibuf, npoints, _state); ae_vector_set_length(&bufs.varpool, nvars-1+1, _state); ae_vector_set_length(&bufs.evsbin, nvars-1+1, _state); ae_vector_set_length(&bufs.evssplits, nvars-1+1, _state); ae_vector_set_length(&bufs.classibuf, 2*nclasses-1+1, _state); ae_vector_set_length(&oobbuf, nclasses*npoints-1+1, _state); ae_vector_set_length(&oobcntbuf, npoints-1+1, _state); ae_vector_set_length(&df->trees, ntrees*treesize-1+1, _state); ae_matrix_set_length(&xys, samplesize-1+1, nvars+1, _state); ae_vector_set_length(&x, nvars-1+1, _state); ae_vector_set_length(&y, nclasses-1+1, _state); for(i=0; i<=npoints-1; i++) { permbuf.ptr.p_int[i] = i; } for(i=0; i<=npoints*nclasses-1; i++) { oobbuf.ptr.p_double[i] = (double)(0); } for(i=0; i<=npoints-1; i++) { oobcntbuf.ptr.p_int[i] = 0; } /* * Prepare variable pool and EVS (extended variable selection/splitting) buffers * (whether EVS is turned on or not): * 1. detect binary variables and pre-calculate splits for them * 2. detect variables with non-distinct values and exclude them from pool */ for(i=0; i<=nvars-1; i++) { bufs.varpool.ptr.p_int[i] = i; } nvarsinpool = nvars; if( useevs ) { for(j=0; j<=nvars-1; j++) { vmin = xy->ptr.pp_double[0][j]; vmax = vmin; for(i=0; i<=npoints-1; i++) { v = xy->ptr.pp_double[i][j]; vmin = ae_minreal(vmin, v, _state); vmax = ae_maxreal(vmax, v, _state); } if( ae_fp_eq(vmin,vmax) ) { /* * exclude variable from pool */ bufs.varpool.ptr.p_int[j] = bufs.varpool.ptr.p_int[nvarsinpool-1]; bufs.varpool.ptr.p_int[nvarsinpool-1] = -1; nvarsinpool = nvarsinpool-1; continue; } bflag = ae_false; for(i=0; i<=npoints-1; i++) { v = xy->ptr.pp_double[i][j]; if( ae_fp_neq(v,vmin)&&ae_fp_neq(v,vmax) ) { bflag = ae_true; break; } } if( bflag ) { /* * non-binary variable */ bufs.evsbin.ptr.p_bool[j] = ae_false; } else { /* * Prepare */ bufs.evsbin.ptr.p_bool[j] = ae_true; bufs.evssplits.ptr.p_double[j] = 0.5*(vmin+vmax); if( ae_fp_less_eq(bufs.evssplits.ptr.p_double[j],vmin) ) { bufs.evssplits.ptr.p_double[j] = vmax; } } } } /* * RANDOM FOREST FORMAT * W[0] - size of array * W[1] - version number * W[2] - NVars * W[3] - NClasses (1 for regression) * W[4] - NTrees * W[5] - trees offset * * * TREE FORMAT * W[Offs] - size of sub-array * node info: * W[K+0] - variable number (-1 for leaf mode) * W[K+1] - threshold (class/value for leaf node) * W[K+2] - ">=" branch index (absent for leaf node) * */ df->nvars = nvars; df->nclasses = nclasses; df->ntrees = ntrees; /* * Build forest */ hqrndrandomize(&rs, _state); offs = 0; for(i=0; i<=ntrees-1; i++) { /* * Prepare sample */ for(k=0; k<=samplesize-1; k++) { j = k+hqrnduniformi(&rs, npoints-k, _state); tmpi = permbuf.ptr.p_int[k]; permbuf.ptr.p_int[k] = permbuf.ptr.p_int[j]; permbuf.ptr.p_int[j] = tmpi; j = permbuf.ptr.p_int[k]; ae_v_move(&xys.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars)); } /* * build tree, copy */ dforest_dfbuildtree(&xys, samplesize, nvars, nclasses, nfeatures, nvarsinpool, flags, &bufs, &rs, _state); j = ae_round(bufs.treebuf.ptr.p_double[0], _state); ae_v_move(&df->trees.ptr.p_double[offs], 1, &bufs.treebuf.ptr.p_double[0], 1, ae_v_len(offs,offs+j-1)); lasttreeoffs = offs; offs = offs+j; /* * OOB estimates */ for(k=samplesize; k<=npoints-1; k++) { for(j=0; j<=nclasses-1; j++) { y.ptr.p_double[j] = (double)(0); } j = permbuf.ptr.p_int[k]; ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); dforest_dfprocessinternal(df, lasttreeoffs, &x, &y, _state); ae_v_add(&oobbuf.ptr.p_double[j*nclasses], 1, &y.ptr.p_double[0], 1, ae_v_len(j*nclasses,(j+1)*nclasses-1)); oobcntbuf.ptr.p_int[j] = oobcntbuf.ptr.p_int[j]+1; } } df->bufsize = offs; /* * Normalize OOB results */ for(i=0; i<=npoints-1; i++) { if( oobcntbuf.ptr.p_int[i]!=0 ) { v = (double)1/(double)oobcntbuf.ptr.p_int[i]; ae_v_muld(&oobbuf.ptr.p_double[i*nclasses], 1, ae_v_len(i*nclasses,i*nclasses+nclasses-1), v); } } /* * Calculate training set estimates */ rep->relclserror = dfrelclserror(df, xy, npoints, _state); rep->avgce = dfavgce(df, xy, npoints, _state); rep->rmserror = dfrmserror(df, xy, npoints, _state); rep->avgerror = dfavgerror(df, xy, npoints, _state); rep->avgrelerror = dfavgrelerror(df, xy, npoints, _state); /* * Calculate OOB estimates. */ rep->oobrelclserror = (double)(0); rep->oobavgce = (double)(0); rep->oobrmserror = (double)(0); rep->oobavgerror = (double)(0); rep->oobavgrelerror = (double)(0); oobcnt = 0; oobrelcnt = 0; for(i=0; i<=npoints-1; i++) { if( oobcntbuf.ptr.p_int[i]!=0 ) { ooboffs = i*nclasses; if( nclasses>1 ) { /* * classification-specific code */ k = ae_round(xy->ptr.pp_double[i][nvars], _state); tmpi = 0; for(j=1; j<=nclasses-1; j++) { if( ae_fp_greater(oobbuf.ptr.p_double[ooboffs+j],oobbuf.ptr.p_double[ooboffs+tmpi]) ) { tmpi = j; } } if( tmpi!=k ) { rep->oobrelclserror = rep->oobrelclserror+1; } if( ae_fp_neq(oobbuf.ptr.p_double[ooboffs+k],(double)(0)) ) { rep->oobavgce = rep->oobavgce-ae_log(oobbuf.ptr.p_double[ooboffs+k], _state); } else { rep->oobavgce = rep->oobavgce-ae_log(ae_minrealnumber, _state); } for(j=0; j<=nclasses-1; j++) { if( j==k ) { rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs+j]-1, _state); rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j]-1, _state); rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j]-1, _state); oobrelcnt = oobrelcnt+1; } else { rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs+j], _state); rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j], _state); } } } else { /* * regression-specific code */ rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars], _state); rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars], _state); if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) { rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs((oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); oobrelcnt = oobrelcnt+1; } } /* * update OOB estimates count. */ oobcnt = oobcnt+1; } } if( oobcnt>0 ) { rep->oobrelclserror = rep->oobrelclserror/oobcnt; rep->oobavgce = rep->oobavgce/oobcnt; rep->oobrmserror = ae_sqrt(rep->oobrmserror/(oobcnt*nclasses), _state); rep->oobavgerror = rep->oobavgerror/(oobcnt*nclasses); if( oobrelcnt>0 ) { rep->oobavgrelerror = rep->oobavgrelerror/oobrelcnt; } } ae_frame_leave(_state); } /************************************************************************* Procesing INPUT PARAMETERS: DF - decision forest model X - input vector, array[0..NVars-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also DFProcessI. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ void dfprocess(decisionforest* df, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t offs; ae_int_t i; double v; /* * Proceed */ if( y->cntnclasses ) { ae_vector_set_length(y, df->nclasses, _state); } offs = 0; for(i=0; i<=df->nclasses-1; i++) { y->ptr.p_double[i] = (double)(0); } for(i=0; i<=df->ntrees-1; i++) { /* * Process basic tree */ dforest_dfprocessinternal(df, offs, x, y, _state); /* * Next tree */ offs = offs+ae_round(df->trees.ptr.p_double[offs], _state); } v = (double)1/(double)df->ntrees; ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,df->nclasses-1), v); } /************************************************************************* 'interactive' variant of DFProcess for languages like Python which support constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void dfprocessi(decisionforest* df, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_vector_clear(y); dfprocess(df, x, y, _state); } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrelclserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; result = (double)dforest_dfclserror(df, xy, npoints, _state)/(double)npoints; return result; } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgce(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t tmpi; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_set_length(&x, df->nvars-1+1, _state); ae_vector_set_length(&y, df->nclasses-1+1, _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); dfprocess(df, &x, &y, _state); if( df->nclasses>1 ) { /* * classification-specific code */ k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); tmpi = 0; for(j=1; j<=df->nclasses-1; j++) { if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) { tmpi = j; } } if( ae_fp_neq(y.ptr.p_double[k],(double)(0)) ) { result = result-ae_log(y.ptr.p_double[k], _state); } else { result = result-ae_log(ae_minrealnumber, _state); } } } result = result/npoints; ae_frame_leave(_state); return result; } /************************************************************************* RMS error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrmserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t tmpi; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_set_length(&x, df->nvars-1+1, _state); ae_vector_set_length(&y, df->nclasses-1+1, _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); dfprocess(df, &x, &y, _state); if( df->nclasses>1 ) { /* * classification-specific code */ k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); tmpi = 0; for(j=1; j<=df->nclasses-1; j++) { if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) { tmpi = j; } } for(j=0; j<=df->nclasses-1; j++) { if( j==k ) { result = result+ae_sqr(y.ptr.p_double[j]-1, _state); } else { result = result+ae_sqr(y.ptr.p_double[j], _state); } } } else { /* * regression-specific code */ result = result+ae_sqr(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); } } result = ae_sqrt(result/(npoints*df->nclasses), _state); ae_frame_leave(_state); return result; } /************************************************************************* Average error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgerror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_int_t i; ae_int_t j; ae_int_t k; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_set_length(&x, df->nvars-1+1, _state); ae_vector_set_length(&y, df->nclasses-1+1, _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); dfprocess(df, &x, &y, _state); if( df->nclasses>1 ) { /* * classification-specific code */ k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); for(j=0; j<=df->nclasses-1; j++) { if( j==k ) { result = result+ae_fabs(y.ptr.p_double[j]-1, _state); } else { result = result+ae_fabs(y.ptr.p_double[j], _state); } } } else { /* * regression-specific code */ result = result+ae_fabs(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); } } result = result/(npoints*df->nclasses); ae_frame_leave(_state); return result; } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgrelerror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_int_t relcnt; ae_int_t i; ae_int_t j; ae_int_t k; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_set_length(&x, df->nvars-1+1, _state); ae_vector_set_length(&y, df->nclasses-1+1, _state); result = (double)(0); relcnt = 0; for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); dfprocess(df, &x, &y, _state); if( df->nclasses>1 ) { /* * classification-specific code */ k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); for(j=0; j<=df->nclasses-1; j++) { if( j==k ) { result = result+ae_fabs(y.ptr.p_double[j]-1, _state); relcnt = relcnt+1; } } } else { /* * regression-specific code */ if( ae_fp_neq(xy->ptr.pp_double[i][df->nvars],(double)(0)) ) { result = result+ae_fabs((y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars])/xy->ptr.pp_double[i][df->nvars], _state); relcnt = relcnt+1; } } } if( relcnt>0 ) { result = result/relcnt; } ae_frame_leave(_state); return result; } /************************************************************************* Copying of DecisionForest strucure INPUT PARAMETERS: DF1 - original OUTPUT PARAMETERS: DF2 - copy -- ALGLIB -- Copyright 13.02.2009 by Bochkanov Sergey *************************************************************************/ void dfcopy(decisionforest* df1, decisionforest* df2, ae_state *_state) { _decisionforest_clear(df2); df2->nvars = df1->nvars; df2->nclasses = df1->nclasses; df2->ntrees = df1->ntrees; df2->bufsize = df1->bufsize; ae_vector_set_length(&df2->trees, df1->bufsize-1+1, _state); ae_v_move(&df2->trees.ptr.p_double[0], 1, &df1->trees.ptr.p_double[0], 1, ae_v_len(0,df1->bufsize-1)); } /************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void dfalloc(ae_serializer* s, decisionforest* forest, ae_state *_state) { ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); allocrealarray(s, &forest->trees, forest->bufsize, _state); } /************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void dfserialize(ae_serializer* s, decisionforest* forest, ae_state *_state) { ae_serializer_serialize_int(s, getrdfserializationcode(_state), _state); ae_serializer_serialize_int(s, dforest_dffirstversion, _state); ae_serializer_serialize_int(s, forest->nvars, _state); ae_serializer_serialize_int(s, forest->nclasses, _state); ae_serializer_serialize_int(s, forest->ntrees, _state); ae_serializer_serialize_int(s, forest->bufsize, _state); serializerealarray(s, &forest->trees, forest->bufsize, _state); } /************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void dfunserialize(ae_serializer* s, decisionforest* forest, ae_state *_state) { ae_int_t i0; ae_int_t i1; _decisionforest_clear(forest); /* * check correctness of header */ ae_serializer_unserialize_int(s, &i0, _state); ae_assert(i0==getrdfserializationcode(_state), "DFUnserialize: stream header corrupted", _state); ae_serializer_unserialize_int(s, &i1, _state); ae_assert(i1==dforest_dffirstversion, "DFUnserialize: stream header corrupted", _state); /* * Unserialize data */ ae_serializer_unserialize_int(s, &forest->nvars, _state); ae_serializer_unserialize_int(s, &forest->nclasses, _state); ae_serializer_unserialize_int(s, &forest->ntrees, _state); ae_serializer_unserialize_int(s, &forest->bufsize, _state); unserializerealarray(s, &forest->trees, _state); } /************************************************************************* Classification error *************************************************************************/ static ae_int_t dforest_dfclserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t tmpi; ae_int_t result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); if( df->nclasses<=1 ) { result = 0; ae_frame_leave(_state); return result; } ae_vector_set_length(&x, df->nvars-1+1, _state); ae_vector_set_length(&y, df->nclasses-1+1, _state); result = 0; for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); dfprocess(df, &x, &y, _state); k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); tmpi = 0; for(j=1; j<=df->nclasses-1; j++) { if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) { tmpi = j; } } if( tmpi!=k ) { result = result+1; } } ae_frame_leave(_state); return result; } /************************************************************************* Internal subroutine for processing one decision tree starting at Offs *************************************************************************/ static void dforest_dfprocessinternal(decisionforest* df, ae_int_t offs, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t k; ae_int_t idx; /* * Set pointer to the root */ k = offs+1; /* * Navigate through the tree */ for(;;) { if( ae_fp_eq(df->trees.ptr.p_double[k],(double)(-1)) ) { if( df->nclasses==1 ) { y->ptr.p_double[0] = y->ptr.p_double[0]+df->trees.ptr.p_double[k+1]; } else { idx = ae_round(df->trees.ptr.p_double[k+1], _state); y->ptr.p_double[idx] = y->ptr.p_double[idx]+1; } break; } if( ae_fp_less(x->ptr.p_double[ae_round(df->trees.ptr.p_double[k], _state)],df->trees.ptr.p_double[k+1]) ) { k = k+dforest_innernodewidth; } else { k = offs+ae_round(df->trees.ptr.p_double[k+2], _state); } } } /************************************************************************* Builds one decision tree. Just a wrapper for the DFBuildTreeRec. *************************************************************************/ static void dforest_dfbuildtree(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t nfeatures, ae_int_t nvarsinpool, ae_int_t flags, dfinternalbuffers* bufs, hqrndstate* rs, ae_state *_state) { ae_int_t numprocessed; ae_int_t i; ae_assert(npoints>0, "Assertion failed", _state); /* * Prepare IdxBuf. It stores indices of the training set elements. * When training set is being split, contents of IdxBuf is * correspondingly reordered so we can know which elements belong * to which branch of decision tree. */ for(i=0; i<=npoints-1; i++) { bufs->idxbuf.ptr.p_int[i] = i; } /* * Recursive procedure */ numprocessed = 1; dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, &numprocessed, 0, npoints-1, bufs, rs, _state); bufs->treebuf.ptr.p_double[0] = (double)(numprocessed); } /************************************************************************* Builds one decision tree (internal recursive subroutine) Parameters: TreeBuf - large enough array, at least TreeSize IdxBuf - at least NPoints elements TmpBufR - at least NPoints TmpBufR2 - at least NPoints TmpBufI - at least NPoints TmpBufI2 - at least NPoints+1 *************************************************************************/ static void dforest_dfbuildtreerec(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t nfeatures, ae_int_t nvarsinpool, ae_int_t flags, ae_int_t* numprocessed, ae_int_t idx1, ae_int_t idx2, dfinternalbuffers* bufs, hqrndstate* rs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_bool bflag; ae_int_t i1; ae_int_t i2; ae_int_t info; double sl; double sr; double w; ae_int_t idxbest; double ebest; double tbest; ae_int_t varcur; double s; double v; double v1; double v2; double threshold; ae_int_t oldnp; double currms; ae_bool useevs; /* * these initializers are not really necessary, * but without them compiler complains about uninitialized locals */ tbest = (double)(0); /* * Prepare */ ae_assert(npoints>0, "Assertion failed", _state); ae_assert(idx2>=idx1, "Assertion failed", _state); useevs = flags/dforest_dfuseevs%2!=0; /* * Leaf node */ if( idx2==idx1 ) { bufs->treebuf.ptr.p_double[*numprocessed] = (double)(-1); bufs->treebuf.ptr.p_double[*numprocessed+1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[idx1]][nvars]; *numprocessed = *numprocessed+dforest_leafnodewidth; return; } /* * Non-leaf node. * Select random variable, prepare split: * 1. prepare default solution - no splitting, class at random * 2. investigate possible splits, compare with default/best */ idxbest = -1; if( nclasses>1 ) { /* * default solution for classification */ for(i=0; i<=nclasses-1; i++) { bufs->classibuf.ptr.p_int[i] = 0; } s = (double)(idx2-idx1+1); for(i=idx1; i<=idx2; i++) { j = ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars], _state); bufs->classibuf.ptr.p_int[j] = bufs->classibuf.ptr.p_int[j]+1; } ebest = (double)(0); for(i=0; i<=nclasses-1; i++) { ebest = ebest+bufs->classibuf.ptr.p_int[i]*ae_sqr(1-bufs->classibuf.ptr.p_int[i]/s, _state)+(s-bufs->classibuf.ptr.p_int[i])*ae_sqr(bufs->classibuf.ptr.p_int[i]/s, _state); } ebest = ae_sqrt(ebest/(nclasses*(idx2-idx1+1)), _state); } else { /* * default solution for regression */ v = (double)(0); for(i=idx1; i<=idx2; i++) { v = v+xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]; } v = v/(idx2-idx1+1); ebest = (double)(0); for(i=idx1; i<=idx2; i++) { ebest = ebest+ae_sqr(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]-v, _state); } ebest = ae_sqrt(ebest/(idx2-idx1+1), _state); } i = 0; while(i<=ae_minint(nfeatures, nvarsinpool, _state)-1) { /* * select variables from pool */ j = i+hqrnduniformi(rs, nvarsinpool-i, _state); k = bufs->varpool.ptr.p_int[i]; bufs->varpool.ptr.p_int[i] = bufs->varpool.ptr.p_int[j]; bufs->varpool.ptr.p_int[j] = k; varcur = bufs->varpool.ptr.p_int[i]; /* * load variable values to working array * * apply EVS preprocessing: if all variable values are same, * variable is excluded from pool. * * This is necessary for binary pre-splits (see later) to work. */ for(j=idx1; j<=idx2; j++) { bufs->tmpbufr.ptr.p_double[j-idx1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][varcur]; } if( useevs ) { bflag = ae_false; v = bufs->tmpbufr.ptr.p_double[0]; for(j=0; j<=idx2-idx1; j++) { if( ae_fp_neq(bufs->tmpbufr.ptr.p_double[j],v) ) { bflag = ae_true; break; } } if( !bflag ) { /* * exclude variable from pool, * go to the next iteration. * I is not increased. */ k = bufs->varpool.ptr.p_int[i]; bufs->varpool.ptr.p_int[i] = bufs->varpool.ptr.p_int[nvarsinpool-1]; bufs->varpool.ptr.p_int[nvarsinpool-1] = k; nvarsinpool = nvarsinpool-1; continue; } } /* * load labels to working array */ if( nclasses>1 ) { for(j=idx1; j<=idx2; j++) { bufs->tmpbufi.ptr.p_int[j-idx1] = ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][nvars], _state); } } else { for(j=idx1; j<=idx2; j++) { bufs->tmpbufr2.ptr.p_double[j-idx1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][nvars]; } } /* * calculate split */ if( useevs&&bufs->evsbin.ptr.p_bool[varcur] ) { /* * Pre-calculated splits for binary variables. * Threshold is already known, just calculate RMS error */ threshold = bufs->evssplits.ptr.p_double[varcur]; if( nclasses>1 ) { /* * classification-specific code */ for(j=0; j<=2*nclasses-1; j++) { bufs->classibuf.ptr.p_int[j] = 0; } sl = (double)(0); sr = (double)(0); for(j=0; j<=idx2-idx1; j++) { k = bufs->tmpbufi.ptr.p_int[j]; if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) { bufs->classibuf.ptr.p_int[k] = bufs->classibuf.ptr.p_int[k]+1; sl = sl+1; } else { bufs->classibuf.ptr.p_int[k+nclasses] = bufs->classibuf.ptr.p_int[k+nclasses]+1; sr = sr+1; } } ae_assert(ae_fp_neq(sl,(double)(0))&&ae_fp_neq(sr,(double)(0)), "DFBuildTreeRec: something strange!", _state); currms = (double)(0); for(j=0; j<=nclasses-1; j++) { w = (double)(bufs->classibuf.ptr.p_int[j]); currms = currms+w*ae_sqr(w/sl-1, _state); currms = currms+(sl-w)*ae_sqr(w/sl, _state); w = (double)(bufs->classibuf.ptr.p_int[nclasses+j]); currms = currms+w*ae_sqr(w/sr-1, _state); currms = currms+(sr-w)*ae_sqr(w/sr, _state); } currms = ae_sqrt(currms/(nclasses*(idx2-idx1+1)), _state); } else { /* * regression-specific code */ sl = (double)(0); sr = (double)(0); v1 = (double)(0); v2 = (double)(0); for(j=0; j<=idx2-idx1; j++) { if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) { v1 = v1+bufs->tmpbufr2.ptr.p_double[j]; sl = sl+1; } else { v2 = v2+bufs->tmpbufr2.ptr.p_double[j]; sr = sr+1; } } ae_assert(ae_fp_neq(sl,(double)(0))&&ae_fp_neq(sr,(double)(0)), "DFBuildTreeRec: something strange!", _state); v1 = v1/sl; v2 = v2/sr; currms = (double)(0); for(j=0; j<=idx2-idx1; j++) { if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) { currms = currms+ae_sqr(v1-bufs->tmpbufr2.ptr.p_double[j], _state); } else { currms = currms+ae_sqr(v2-bufs->tmpbufr2.ptr.p_double[j], _state); } } currms = ae_sqrt(currms/(idx2-idx1+1), _state); } info = 1; } else { /* * Generic splits */ if( nclasses>1 ) { dforest_dfsplitc(&bufs->tmpbufr, &bufs->tmpbufi, &bufs->classibuf, idx2-idx1+1, nclasses, dforest_dfusestrongsplits, &info, &threshold, &currms, &bufs->sortrbuf, &bufs->sortibuf, _state); } else { dforest_dfsplitr(&bufs->tmpbufr, &bufs->tmpbufr2, idx2-idx1+1, dforest_dfusestrongsplits, &info, &threshold, &currms, &bufs->sortrbuf, &bufs->sortrbuf2, _state); } } if( info>0 ) { if( ae_fp_less_eq(currms,ebest) ) { ebest = currms; idxbest = varcur; tbest = threshold; } } /* * Next iteration */ i = i+1; } /* * to split or not to split */ if( idxbest<0 ) { /* * All values are same, cannot split. */ bufs->treebuf.ptr.p_double[*numprocessed] = (double)(-1); if( nclasses>1 ) { /* * Select random class label (randomness allows us to * approximate distribution of the classes) */ bufs->treebuf.ptr.p_double[*numprocessed+1] = (double)(ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[idx1+hqrnduniformi(rs, idx2-idx1+1, _state)]][nvars], _state)); } else { /* * Select average (for regression task). */ v = (double)(0); for(i=idx1; i<=idx2; i++) { v = v+xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]/(idx2-idx1+1); } bufs->treebuf.ptr.p_double[*numprocessed+1] = v; } *numprocessed = *numprocessed+dforest_leafnodewidth; } else { /* * we can split */ bufs->treebuf.ptr.p_double[*numprocessed] = (double)(idxbest); bufs->treebuf.ptr.p_double[*numprocessed+1] = tbest; i1 = idx1; i2 = idx2; while(i1<=i2) { /* * Reorder indices so that left partition is in [Idx1..I1-1], * and right partition is in [I2+1..Idx2] */ if( ae_fp_less(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i1]][idxbest],tbest) ) { i1 = i1+1; continue; } if( ae_fp_greater_eq(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i2]][idxbest],tbest) ) { i2 = i2-1; continue; } j = bufs->idxbuf.ptr.p_int[i1]; bufs->idxbuf.ptr.p_int[i1] = bufs->idxbuf.ptr.p_int[i2]; bufs->idxbuf.ptr.p_int[i2] = j; i1 = i1+1; i2 = i2-1; } oldnp = *numprocessed; *numprocessed = *numprocessed+dforest_innernodewidth; dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, numprocessed, idx1, i1-1, bufs, rs, _state); bufs->treebuf.ptr.p_double[oldnp+2] = (double)(*numprocessed); dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, numprocessed, i2+1, idx2, bufs, rs, _state); } } /************************************************************************* Makes split on attribute *************************************************************************/ static void dforest_dfsplitc(/* Real */ ae_vector* x, /* Integer */ ae_vector* c, /* Integer */ ae_vector* cntbuf, ae_int_t n, ae_int_t nc, ae_int_t flags, ae_int_t* info, double* threshold, double* e, /* Real */ ae_vector* sortrbuf, /* Integer */ ae_vector* sortibuf, ae_state *_state) { ae_int_t i; ae_int_t neq; ae_int_t nless; ae_int_t ngreater; ae_int_t q; ae_int_t qmin; ae_int_t qmax; ae_int_t qcnt; double cursplit; ae_int_t nleft; double v; double cure; double w; double sl; double sr; *info = 0; *threshold = 0; *e = 0; tagsortfasti(x, c, sortrbuf, sortibuf, n, _state); *e = ae_maxrealnumber; *threshold = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); *info = -3; if( flags/dforest_dfusestrongsplits%2==0 ) { /* * weak splits, split at half */ qcnt = 2; qmin = 1; qmax = 1; } else { /* * strong splits: choose best quartile */ qcnt = 4; qmin = 1; qmax = 3; } for(q=qmin; q<=qmax; q++) { cursplit = x->ptr.p_double[n*q/qcnt]; neq = 0; nless = 0; ngreater = 0; for(i=0; i<=n-1; i++) { if( ae_fp_less(x->ptr.p_double[i],cursplit) ) { nless = nless+1; } if( ae_fp_eq(x->ptr.p_double[i],cursplit) ) { neq = neq+1; } if( ae_fp_greater(x->ptr.p_double[i],cursplit) ) { ngreater = ngreater+1; } } ae_assert(neq!=0, "DFSplitR: NEq=0, something strange!!!", _state); if( nless!=0||ngreater!=0 ) { /* * set threshold between two partitions, with * some tweaking to avoid problems with floating point * arithmetics. * * The problem is that when you calculates C = 0.5*(A+B) there * can be no C which lies strictly between A and B (for example, * there is no floating point number which is * greater than 1 and less than 1+eps). In such situations * we choose right side as theshold (remember that * points which lie on threshold falls to the right side). */ if( nlessptr.p_double[nless+neq-1]+x->ptr.p_double[nless+neq]); nleft = nless+neq; if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless+neq-1]) ) { cursplit = x->ptr.p_double[nless+neq]; } } else { cursplit = 0.5*(x->ptr.p_double[nless-1]+x->ptr.p_double[nless]); nleft = nless; if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless-1]) ) { cursplit = x->ptr.p_double[nless]; } } *info = 1; cure = (double)(0); for(i=0; i<=2*nc-1; i++) { cntbuf->ptr.p_int[i] = 0; } for(i=0; i<=nleft-1; i++) { cntbuf->ptr.p_int[c->ptr.p_int[i]] = cntbuf->ptr.p_int[c->ptr.p_int[i]]+1; } for(i=nleft; i<=n-1; i++) { cntbuf->ptr.p_int[nc+c->ptr.p_int[i]] = cntbuf->ptr.p_int[nc+c->ptr.p_int[i]]+1; } sl = (double)(nleft); sr = (double)(n-nleft); v = (double)(0); for(i=0; i<=nc-1; i++) { w = (double)(cntbuf->ptr.p_int[i]); v = v+w*ae_sqr(w/sl-1, _state); v = v+(sl-w)*ae_sqr(w/sl, _state); w = (double)(cntbuf->ptr.p_int[nc+i]); v = v+w*ae_sqr(w/sr-1, _state); v = v+(sr-w)*ae_sqr(w/sr, _state); } cure = ae_sqrt(v/(nc*n), _state); if( ae_fp_less(cure,*e) ) { *threshold = cursplit; *e = cure; } } } } /************************************************************************* Makes split on attribute *************************************************************************/ static void dforest_dfsplitr(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t flags, ae_int_t* info, double* threshold, double* e, /* Real */ ae_vector* sortrbuf, /* Real */ ae_vector* sortrbuf2, ae_state *_state) { ae_int_t i; ae_int_t neq; ae_int_t nless; ae_int_t ngreater; ae_int_t q; ae_int_t qmin; ae_int_t qmax; ae_int_t qcnt; double cursplit; ae_int_t nleft; double v; double cure; *info = 0; *threshold = 0; *e = 0; tagsortfastr(x, y, sortrbuf, sortrbuf2, n, _state); *e = ae_maxrealnumber; *threshold = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); *info = -3; if( flags/dforest_dfusestrongsplits%2==0 ) { /* * weak splits, split at half */ qcnt = 2; qmin = 1; qmax = 1; } else { /* * strong splits: choose best quartile */ qcnt = 4; qmin = 1; qmax = 3; } for(q=qmin; q<=qmax; q++) { cursplit = x->ptr.p_double[n*q/qcnt]; neq = 0; nless = 0; ngreater = 0; for(i=0; i<=n-1; i++) { if( ae_fp_less(x->ptr.p_double[i],cursplit) ) { nless = nless+1; } if( ae_fp_eq(x->ptr.p_double[i],cursplit) ) { neq = neq+1; } if( ae_fp_greater(x->ptr.p_double[i],cursplit) ) { ngreater = ngreater+1; } } ae_assert(neq!=0, "DFSplitR: NEq=0, something strange!!!", _state); if( nless!=0||ngreater!=0 ) { /* * set threshold between two partitions, with * some tweaking to avoid problems with floating point * arithmetics. * * The problem is that when you calculates C = 0.5*(A+B) there * can be no C which lies strictly between A and B (for example, * there is no floating point number which is * greater than 1 and less than 1+eps). In such situations * we choose right side as theshold (remember that * points which lie on threshold falls to the right side). */ if( nlessptr.p_double[nless+neq-1]+x->ptr.p_double[nless+neq]); nleft = nless+neq; if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless+neq-1]) ) { cursplit = x->ptr.p_double[nless+neq]; } } else { cursplit = 0.5*(x->ptr.p_double[nless-1]+x->ptr.p_double[nless]); nleft = nless; if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless-1]) ) { cursplit = x->ptr.p_double[nless]; } } *info = 1; cure = (double)(0); v = (double)(0); for(i=0; i<=nleft-1; i++) { v = v+y->ptr.p_double[i]; } v = v/nleft; for(i=0; i<=nleft-1; i++) { cure = cure+ae_sqr(y->ptr.p_double[i]-v, _state); } v = (double)(0); for(i=nleft; i<=n-1; i++) { v = v+y->ptr.p_double[i]; } v = v/(n-nleft); for(i=nleft; i<=n-1; i++) { cure = cure+ae_sqr(y->ptr.p_double[i]-v, _state); } cure = ae_sqrt(cure/n, _state); if( ae_fp_less(cure,*e) ) { *threshold = cursplit; *e = cure; } } } } void _decisionforest_init(void* _p, ae_state *_state) { decisionforest *p = (decisionforest*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->trees, 0, DT_REAL, _state); } void _decisionforest_init_copy(void* _dst, void* _src, ae_state *_state) { decisionforest *dst = (decisionforest*)_dst; decisionforest *src = (decisionforest*)_src; dst->nvars = src->nvars; dst->nclasses = src->nclasses; dst->ntrees = src->ntrees; dst->bufsize = src->bufsize; ae_vector_init_copy(&dst->trees, &src->trees, _state); } void _decisionforest_clear(void* _p) { decisionforest *p = (decisionforest*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->trees); } void _decisionforest_destroy(void* _p) { decisionforest *p = (decisionforest*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->trees); } void _dfreport_init(void* _p, ae_state *_state) { dfreport *p = (dfreport*)_p; ae_touch_ptr((void*)p); } void _dfreport_init_copy(void* _dst, void* _src, ae_state *_state) { dfreport *dst = (dfreport*)_dst; dfreport *src = (dfreport*)_src; dst->relclserror = src->relclserror; dst->avgce = src->avgce; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->oobrelclserror = src->oobrelclserror; dst->oobavgce = src->oobavgce; dst->oobrmserror = src->oobrmserror; dst->oobavgerror = src->oobavgerror; dst->oobavgrelerror = src->oobavgrelerror; } void _dfreport_clear(void* _p) { dfreport *p = (dfreport*)_p; ae_touch_ptr((void*)p); } void _dfreport_destroy(void* _p) { dfreport *p = (dfreport*)_p; ae_touch_ptr((void*)p); } void _dfinternalbuffers_init(void* _p, ae_state *_state) { dfinternalbuffers *p = (dfinternalbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->treebuf, 0, DT_REAL, _state); ae_vector_init(&p->idxbuf, 0, DT_INT, _state); ae_vector_init(&p->tmpbufr, 0, DT_REAL, _state); ae_vector_init(&p->tmpbufr2, 0, DT_REAL, _state); ae_vector_init(&p->tmpbufi, 0, DT_INT, _state); ae_vector_init(&p->classibuf, 0, DT_INT, _state); ae_vector_init(&p->sortrbuf, 0, DT_REAL, _state); ae_vector_init(&p->sortrbuf2, 0, DT_REAL, _state); ae_vector_init(&p->sortibuf, 0, DT_INT, _state); ae_vector_init(&p->varpool, 0, DT_INT, _state); ae_vector_init(&p->evsbin, 0, DT_BOOL, _state); ae_vector_init(&p->evssplits, 0, DT_REAL, _state); } void _dfinternalbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { dfinternalbuffers *dst = (dfinternalbuffers*)_dst; dfinternalbuffers *src = (dfinternalbuffers*)_src; ae_vector_init_copy(&dst->treebuf, &src->treebuf, _state); ae_vector_init_copy(&dst->idxbuf, &src->idxbuf, _state); ae_vector_init_copy(&dst->tmpbufr, &src->tmpbufr, _state); ae_vector_init_copy(&dst->tmpbufr2, &src->tmpbufr2, _state); ae_vector_init_copy(&dst->tmpbufi, &src->tmpbufi, _state); ae_vector_init_copy(&dst->classibuf, &src->classibuf, _state); ae_vector_init_copy(&dst->sortrbuf, &src->sortrbuf, _state); ae_vector_init_copy(&dst->sortrbuf2, &src->sortrbuf2, _state); ae_vector_init_copy(&dst->sortibuf, &src->sortibuf, _state); ae_vector_init_copy(&dst->varpool, &src->varpool, _state); ae_vector_init_copy(&dst->evsbin, &src->evsbin, _state); ae_vector_init_copy(&dst->evssplits, &src->evssplits, _state); } void _dfinternalbuffers_clear(void* _p) { dfinternalbuffers *p = (dfinternalbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->treebuf); ae_vector_clear(&p->idxbuf); ae_vector_clear(&p->tmpbufr); ae_vector_clear(&p->tmpbufr2); ae_vector_clear(&p->tmpbufi); ae_vector_clear(&p->classibuf); ae_vector_clear(&p->sortrbuf); ae_vector_clear(&p->sortrbuf2); ae_vector_clear(&p->sortibuf); ae_vector_clear(&p->varpool); ae_vector_clear(&p->evsbin); ae_vector_clear(&p->evssplits); } void _dfinternalbuffers_destroy(void* _p) { dfinternalbuffers *p = (dfinternalbuffers*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->treebuf); ae_vector_destroy(&p->idxbuf); ae_vector_destroy(&p->tmpbufr); ae_vector_destroy(&p->tmpbufr2); ae_vector_destroy(&p->tmpbufi); ae_vector_destroy(&p->classibuf); ae_vector_destroy(&p->sortrbuf); ae_vector_destroy(&p->sortrbuf2); ae_vector_destroy(&p->sortibuf); ae_vector_destroy(&p->varpool); ae_vector_destroy(&p->evsbin); ae_vector_destroy(&p->evssplits); } /************************************************************************* Linear regression Subroutine builds model: Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) and model found in ALGLIB format, covariation matrix, training set errors (rms, average, average relative) and leave-one-out cross-validation estimate of the generalization error. CV estimate calculated using fast algorithm with O(NPoints*NVars) complexity. When covariation matrix is calculated standard deviations of function values are assumed to be equal to RMS error on the training set. INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPointsrmserror, _state)*npoints/(npoints-nvars-1); for(i=0; i<=nvars; i++) { ae_v_muld(&ar->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); } ae_frame_leave(_state); } /************************************************************************* Linear regression Variant of LRBuild which uses vector of standatd deviations (errors in function values). INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable S - standard deviations (errors in function values) array[0..NPoints-1], S[i]>0. NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPointsptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); xyi.ptr.pp_double[i][nvars] = (double)(1); xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; } /* * Standartization */ ae_vector_set_length(&x, npoints-1+1, _state); ae_vector_set_length(&means, nvars-1+1, _state); ae_vector_set_length(&sigmas, nvars-1+1, _state); for(j=0; j<=nvars-1; j++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); means.ptr.p_double[j] = mean; sigmas.ptr.p_double[j] = ae_sqrt(variance, _state); if( ae_fp_eq(sigmas.ptr.p_double[j],(double)(0)) ) { sigmas.ptr.p_double[j] = (double)(1); } for(i=0; i<=npoints-1; i++) { xyi.ptr.pp_double[i][j] = (xyi.ptr.pp_double[i][j]-means.ptr.p_double[j])/sigmas.ptr.p_double[j]; } } /* * Internal processing */ linreg_lrinternal(&xyi, s, npoints, nvars+1, info, lm, ar, _state); if( *info<0 ) { ae_frame_leave(_state); return; } /* * Un-standartization */ offs = ae_round(lm->w.ptr.p_double[3], _state); for(j=0; j<=nvars-1; j++) { /* * Constant term is updated (and its covariance too, * since it gets some variance from J-th component) */ lm->w.ptr.p_double[offs+nvars] = lm->w.ptr.p_double[offs+nvars]-lm->w.ptr.p_double[offs+j]*means.ptr.p_double[j]/sigmas.ptr.p_double[j]; v = means.ptr.p_double[j]/sigmas.ptr.p_double[j]; ae_v_subd(&ar->c.ptr.pp_double[nvars][0], 1, &ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); ae_v_subd(&ar->c.ptr.pp_double[0][nvars], ar->c.stride, &ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); /* * J-th term is updated */ lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/sigmas.ptr.p_double[j]; v = 1/sigmas.ptr.p_double[j]; ae_v_muld(&ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); ae_v_muld(&ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); } ae_frame_leave(_state); } /************************************************************************* Like LRBuildS, but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/ void lrbuildzs(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state) { ae_frame _frame_block; ae_matrix xyi; ae_vector x; ae_vector c; ae_int_t i; ae_int_t j; double v; ae_int_t offs; double mean; double variance; double skewness; double kurtosis; ae_frame_make(_state, &_frame_block); *info = 0; _linearmodel_clear(lm); _lrreport_clear(ar); ae_matrix_init(&xyi, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); /* * Test parameters */ if( npoints<=nvars+1||nvars<1 ) { *info = -1; ae_frame_leave(_state); return; } /* * Copy data, add one more column (constant term) */ ae_matrix_set_length(&xyi, npoints-1+1, nvars+1+1, _state); for(i=0; i<=npoints-1; i++) { ae_v_move(&xyi.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); xyi.ptr.pp_double[i][nvars] = (double)(0); xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; } /* * Standartization: unusual scaling */ ae_vector_set_length(&x, npoints-1+1, _state); ae_vector_set_length(&c, nvars-1+1, _state); for(j=0; j<=nvars-1; j++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); if( ae_fp_greater(ae_fabs(mean, _state),ae_sqrt(variance, _state)) ) { /* * variation is relatively small, it is better to * bring mean value to 1 */ c.ptr.p_double[j] = mean; } else { /* * variation is large, it is better to bring variance to 1 */ if( ae_fp_eq(variance,(double)(0)) ) { variance = (double)(1); } c.ptr.p_double[j] = ae_sqrt(variance, _state); } for(i=0; i<=npoints-1; i++) { xyi.ptr.pp_double[i][j] = xyi.ptr.pp_double[i][j]/c.ptr.p_double[j]; } } /* * Internal processing */ linreg_lrinternal(&xyi, s, npoints, nvars+1, info, lm, ar, _state); if( *info<0 ) { ae_frame_leave(_state); return; } /* * Un-standartization */ offs = ae_round(lm->w.ptr.p_double[3], _state); for(j=0; j<=nvars-1; j++) { /* * J-th term is updated */ lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/c.ptr.p_double[j]; v = 1/c.ptr.p_double[j]; ae_v_muld(&ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); ae_v_muld(&ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); } ae_frame_leave(_state); } /************************************************************************* Like LRBuild but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/ void lrbuildz(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state) { ae_frame _frame_block; ae_vector s; ae_int_t i; double sigma2; ae_frame_make(_state, &_frame_block); *info = 0; _linearmodel_clear(lm); _lrreport_clear(ar); ae_vector_init(&s, 0, DT_REAL, _state); if( npoints<=nvars+1||nvars<1 ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&s, npoints-1+1, _state); for(i=0; i<=npoints-1; i++) { s.ptr.p_double[i] = (double)(1); } lrbuildzs(xy, &s, npoints, nvars, info, lm, ar, _state); if( *info<0 ) { ae_frame_leave(_state); return; } sigma2 = ae_sqr(ar->rmserror, _state)*npoints/(npoints-nvars-1); for(i=0; i<=nvars; i++) { ae_v_muld(&ar->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); } ae_frame_leave(_state); } /************************************************************************* Unpacks coefficients of linear model. INPUT PARAMETERS: LM - linear model in ALGLIB format OUTPUT PARAMETERS: V - coefficients, array[0..NVars] constant term (intercept) is stored in the V[NVars]. NVars - number of independent variables (one less than number of coefficients) -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ void lrunpack(linearmodel* lm, /* Real */ ae_vector* v, ae_int_t* nvars, ae_state *_state) { ae_int_t offs; ae_vector_clear(v); *nvars = 0; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); *nvars = ae_round(lm->w.ptr.p_double[2], _state); offs = ae_round(lm->w.ptr.p_double[3], _state); ae_vector_set_length(v, *nvars+1, _state); ae_v_move(&v->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,*nvars)); } /************************************************************************* "Packs" coefficients and creates linear model in ALGLIB format (LRUnpack reversed). INPUT PARAMETERS: V - coefficients, array[0..NVars] NVars - number of independent variables OUTPUT PAREMETERS: LM - linear model. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ void lrpack(/* Real */ ae_vector* v, ae_int_t nvars, linearmodel* lm, ae_state *_state) { ae_int_t offs; _linearmodel_clear(lm); ae_vector_set_length(&lm->w, 4+nvars+1, _state); offs = 4; lm->w.ptr.p_double[0] = (double)(4+nvars+1); lm->w.ptr.p_double[1] = (double)(linreg_lrvnum); lm->w.ptr.p_double[2] = (double)(nvars); lm->w.ptr.p_double[3] = (double)(offs); ae_v_move(&lm->w.ptr.p_double[offs], 1, &v->ptr.p_double[0], 1, ae_v_len(offs,offs+nvars)); } /************************************************************************* Procesing INPUT PARAMETERS: LM - linear model X - input vector, array[0..NVars-1]. Result: value of linear model regression estimate -- ALGLIB -- Copyright 03.09.2008 by Bochkanov Sergey *************************************************************************/ double lrprocess(linearmodel* lm, /* Real */ ae_vector* x, ae_state *_state) { double v; ae_int_t offs; ae_int_t nvars; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); offs = ae_round(lm->w.ptr.p_double[3], _state); v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); result = v+lm->w.ptr.p_double[offs+nvars]; return result; } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: root mean square error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lrrmserror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_int_t i; double v; ae_int_t offs; ae_int_t nvars; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); offs = ae_round(lm->w.ptr.p_double[3], _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); v = v+lm->w.ptr.p_double[offs+nvars]; result = result+ae_sqr(v-xy->ptr.pp_double[i][nvars], _state); } result = ae_sqrt(result/npoints, _state); return result; } /************************************************************************* Average error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lravgerror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_int_t i; double v; ae_int_t offs; ae_int_t nvars; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); offs = ae_round(lm->w.ptr.p_double[3], _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); v = v+lm->w.ptr.p_double[offs+nvars]; result = result+ae_fabs(v-xy->ptr.pp_double[i][nvars], _state); } result = result/npoints; return result; } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average relative error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double lravgrelerror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_int_t i; ae_int_t k; double v; ae_int_t offs; ae_int_t nvars; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); offs = ae_round(lm->w.ptr.p_double[3], _state); result = (double)(0); k = 0; for(i=0; i<=npoints-1; i++) { if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) { v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); v = v+lm->w.ptr.p_double[offs+nvars]; result = result+ae_fabs((v-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); k = k+1; } } if( k!=0 ) { result = result/k; } return result; } /************************************************************************* Copying of LinearModel strucure INPUT PARAMETERS: LM1 - original OUTPUT PARAMETERS: LM2 - copy -- ALGLIB -- Copyright 15.03.2009 by Bochkanov Sergey *************************************************************************/ void lrcopy(linearmodel* lm1, linearmodel* lm2, ae_state *_state) { ae_int_t k; _linearmodel_clear(lm2); k = ae_round(lm1->w.ptr.p_double[0], _state); ae_vector_set_length(&lm2->w, k-1+1, _state); ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); } void lrlines(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t n, ae_int_t* info, double* a, double* b, double* vara, double* varb, double* covab, double* corrab, double* p, ae_state *_state) { ae_int_t i; double ss; double sx; double sxx; double sy; double stt; double e1; double e2; double t; double chi2; *info = 0; *a = 0; *b = 0; *vara = 0; *varb = 0; *covab = 0; *corrab = 0; *p = 0; if( n<2 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( ae_fp_less_eq(s->ptr.p_double[i],(double)(0)) ) { *info = -2; return; } } *info = 1; /* * Calculate S, SX, SY, SXX */ ss = (double)(0); sx = (double)(0); sy = (double)(0); sxx = (double)(0); for(i=0; i<=n-1; i++) { t = ae_sqr(s->ptr.p_double[i], _state); ss = ss+1/t; sx = sx+xy->ptr.pp_double[i][0]/t; sy = sy+xy->ptr.pp_double[i][1]/t; sxx = sxx+ae_sqr(xy->ptr.pp_double[i][0], _state)/t; } /* * Test for condition number */ t = ae_sqrt(4*ae_sqr(sx, _state)+ae_sqr(ss-sxx, _state), _state); e1 = 0.5*(ss+sxx+t); e2 = 0.5*(ss+sxx-t); if( ae_fp_less_eq(ae_minreal(e1, e2, _state),1000*ae_machineepsilon*ae_maxreal(e1, e2, _state)) ) { *info = -3; return; } /* * Calculate A, B */ *a = (double)(0); *b = (double)(0); stt = (double)(0); for(i=0; i<=n-1; i++) { t = (xy->ptr.pp_double[i][0]-sx/ss)/s->ptr.p_double[i]; *b = *b+t*xy->ptr.pp_double[i][1]/s->ptr.p_double[i]; stt = stt+ae_sqr(t, _state); } *b = *b/stt; *a = (sy-sx*(*b))/ss; /* * Calculate goodness-of-fit */ if( n>2 ) { chi2 = (double)(0); for(i=0; i<=n-1; i++) { chi2 = chi2+ae_sqr((xy->ptr.pp_double[i][1]-(*a)-*b*xy->ptr.pp_double[i][0])/s->ptr.p_double[i], _state); } *p = incompletegammac((double)(n-2)/(double)2, chi2/2, _state); } else { *p = (double)(1); } /* * Calculate other parameters */ *vara = (1+ae_sqr(sx, _state)/(ss*stt))/ss; *varb = 1/stt; *covab = -sx/(ss*stt); *corrab = *covab/ae_sqrt(*vara*(*varb), _state); } void lrline(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t* info, double* a, double* b, ae_state *_state) { ae_frame _frame_block; ae_vector s; ae_int_t i; double vara; double varb; double covab; double corrab; double p; ae_frame_make(_state, &_frame_block); *info = 0; *a = 0; *b = 0; ae_vector_init(&s, 0, DT_REAL, _state); if( n<2 ) { *info = -1; ae_frame_leave(_state); return; } ae_vector_set_length(&s, n-1+1, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = (double)(1); } lrlines(xy, &s, n, info, a, b, &vara, &varb, &covab, &corrab, &p, _state); ae_frame_leave(_state); } /************************************************************************* Internal linear regression subroutine *************************************************************************/ static void linreg_lrinternal(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix u; ae_matrix vt; ae_matrix vm; ae_matrix xym; ae_vector b; ae_vector sv; ae_vector t; ae_vector svi; ae_vector work; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t ncv; ae_int_t na; ae_int_t nacv; double r; double p; double epstol; lrreport ar2; ae_int_t offs; linearmodel tlm; ae_frame_make(_state, &_frame_block); *info = 0; _linearmodel_clear(lm); _lrreport_clear(ar); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_matrix_init(&vm, 0, 0, DT_REAL, _state); ae_matrix_init(&xym, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&sv, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&svi, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); _lrreport_init(&ar2, _state); _linearmodel_init(&tlm, _state); epstol = (double)(1000); /* * Check for errors in data */ if( npointsptr.p_double[i],(double)(0)) ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Create design matrix */ ae_matrix_set_length(&a, npoints-1+1, nvars-1+1, _state); ae_vector_set_length(&b, npoints-1+1, _state); for(i=0; i<=npoints-1; i++) { r = 1/s->ptr.p_double[i]; ae_v_moved(&a.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); b.ptr.p_double[i] = xy->ptr.pp_double[i][nvars]/s->ptr.p_double[i]; } /* * Allocate W: * W[0] array size * W[1] version number, 0 * W[2] NVars (minus 1, to be compatible with external representation) * W[3] coefficients offset */ ae_vector_set_length(&lm->w, 4+nvars-1+1, _state); offs = 4; lm->w.ptr.p_double[0] = (double)(4+nvars); lm->w.ptr.p_double[1] = (double)(linreg_lrvnum); lm->w.ptr.p_double[2] = (double)(nvars-1); lm->w.ptr.p_double[3] = (double)(offs); /* * Solve problem using SVD: * * 0. check for degeneracy (different types) * 1. A = U*diag(sv)*V' * 2. T = b'*U * 3. w = SUM((T[i]/sv[i])*V[..,i]) * 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M) * * see $15.4 of "Numerical Recipes in C" for more information */ ae_vector_set_length(&t, nvars-1+1, _state); ae_vector_set_length(&svi, nvars-1+1, _state); ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); ae_matrix_set_length(&vm, nvars-1+1, nvars-1+1, _state); if( !rmatrixsvd(&a, npoints, nvars, 1, 1, 2, &sv, &u, &vt, _state) ) { *info = -4; ae_frame_leave(_state); return; } if( ae_fp_less_eq(sv.ptr.p_double[0],(double)(0)) ) { /* * Degenerate case: zero design matrix. */ for(i=offs; i<=offs+nvars-1; i++) { lm->w.ptr.p_double[i] = (double)(0); } ar->rmserror = lrrmserror(lm, xy, npoints, _state); ar->avgerror = lravgerror(lm, xy, npoints, _state); ar->avgrelerror = lravgrelerror(lm, xy, npoints, _state); ar->cvrmserror = ar->rmserror; ar->cvavgerror = ar->avgerror; ar->cvavgrelerror = ar->avgrelerror; ar->ncvdefects = 0; ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); for(i=0; i<=nvars-1; i++) { ar->cvdefects.ptr.p_int[i] = -1; } ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { ar->c.ptr.pp_double[i][j] = (double)(0); } } ae_frame_leave(_state); return; } if( ae_fp_less_eq(sv.ptr.p_double[nvars-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) { /* * Degenerate case, non-zero design matrix. * * We can leave it and solve task in SVD least squares fashion. * Solution and covariance matrix will be obtained correctly, * but CV error estimates - will not. It is better to reduce * it to non-degenerate task and to obtain correct CV estimates. */ for(k=nvars; k>=1; k--) { if( ae_fp_greater(sv.ptr.p_double[k-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) { /* * Reduce */ ae_matrix_set_length(&xym, npoints-1+1, k+1, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=k-1; j++) { r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); xym.ptr.pp_double[i][j] = r; } xym.ptr.pp_double[i][k] = xy->ptr.pp_double[i][nvars]; } /* * Solve */ linreg_lrinternal(&xym, s, npoints, k, info, &tlm, &ar2, _state); if( *info!=1 ) { ae_frame_leave(_state); return; } /* * Convert back to un-reduced format */ for(j=0; j<=nvars-1; j++) { lm->w.ptr.p_double[offs+j] = (double)(0); } for(j=0; j<=k-1; j++) { r = tlm.w.ptr.p_double[offs+j]; ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(offs,offs+nvars-1), r); } ar->rmserror = ar2.rmserror; ar->avgerror = ar2.avgerror; ar->avgrelerror = ar2.avgrelerror; ar->cvrmserror = ar2.cvrmserror; ar->cvavgerror = ar2.cvavgerror; ar->cvavgrelerror = ar2.cvavgrelerror; ar->ncvdefects = ar2.ncvdefects; ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); for(j=0; j<=ar->ncvdefects-1; j++) { ar->cvdefects.ptr.p_int[j] = ar2.cvdefects.ptr.p_int[j]; } for(j=ar->ncvdefects; j<=nvars-1; j++) { ar->cvdefects.ptr.p_int[j] = -1; } ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); ae_vector_set_length(&work, nvars+1, _state); matrixmatrixmultiply(&ar2.c, 0, k-1, 0, k-1, ae_false, &vt, 0, k-1, 0, nvars-1, ae_false, 1.0, &vm, 0, k-1, 0, nvars-1, 0.0, &work, _state); matrixmatrixmultiply(&vt, 0, k-1, 0, nvars-1, ae_true, &vm, 0, k-1, 0, nvars-1, ae_false, 1.0, &ar->c, 0, nvars-1, 0, nvars-1, 0.0, &work, _state); ae_frame_leave(_state); return; } } *info = -255; ae_frame_leave(_state); return; } for(i=0; i<=nvars-1; i++) { if( ae_fp_greater(sv.ptr.p_double[i],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) { svi.ptr.p_double[i] = 1/sv.ptr.p_double[i]; } else { svi.ptr.p_double[i] = (double)(0); } } for(i=0; i<=nvars-1; i++) { t.ptr.p_double[i] = (double)(0); } for(i=0; i<=npoints-1; i++) { r = b.ptr.p_double[i]; ae_v_addd(&t.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); } for(i=0; i<=nvars-1; i++) { lm->w.ptr.p_double[offs+i] = (double)(0); } for(i=0; i<=nvars-1; i++) { r = t.ptr.p_double[i]*svi.ptr.p_double[i]; ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(offs,offs+nvars-1), r); } for(j=0; j<=nvars-1; j++) { r = svi.ptr.p_double[j]; ae_v_moved(&vm.ptr.pp_double[0][j], vm.stride, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), r); } for(i=0; i<=nvars-1; i++) { for(j=i; j<=nvars-1; j++) { r = ae_v_dotproduct(&vm.ptr.pp_double[i][0], 1, &vm.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); ar->c.ptr.pp_double[i][j] = r; ar->c.ptr.pp_double[j][i] = r; } } /* * Leave-1-out cross-validation error. * * NOTATIONS: * A design matrix * A*x = b original linear least squares task * U*S*V' SVD of A * ai i-th row of the A * bi i-th element of the b * xf solution of the original LLS task * * Cross-validation error of i-th element from a sample is * calculated using following formula: * * ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) * * This formula can be derived from normal equations of the * original task * * (A'*A)x = A'*b (2) * * by applying modification (zeroing out i-th row of A) to (2): * * (A-ai)'*(A-ai) = (A-ai)'*b * * and using Sherman-Morrison formula for updating matrix inverse * * NOTE 1: b is not zeroed out since it is much simpler and * does not influence final result. * * NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. * Formula (1) can't be applied for such cases and they are skipped * from CV calculation (which distorts resulting CV estimate). * But from the properties of U we can conclude that there can * be no more than NVars such vectors. Usually * NVars << NPoints, so in a normal case it only slightly * influences result. */ ncv = 0; na = 0; nacv = 0; ar->rmserror = (double)(0); ar->avgerror = (double)(0); ar->avgrelerror = (double)(0); ar->cvrmserror = (double)(0); ar->cvavgerror = (double)(0); ar->cvavgrelerror = (double)(0); ar->ncvdefects = 0; ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); for(i=0; i<=nvars-1; i++) { ar->cvdefects.ptr.p_int[i] = -1; } for(i=0; i<=npoints-1; i++) { /* * Error on a training set */ r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); ar->rmserror = ar->rmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); ar->avgerror = ar->avgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) { ar->avgrelerror = ar->avgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); na = na+1; } /* * Error using fast leave-one-out cross-validation */ p = ae_v_dotproduct(&u.ptr.pp_double[i][0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); if( ae_fp_greater(p,1-epstol*ae_machineepsilon) ) { ar->cvdefects.ptr.p_int[ar->ncvdefects] = i; ar->ncvdefects = ar->ncvdefects+1; continue; } r = s->ptr.p_double[i]*(r/s->ptr.p_double[i]-b.ptr.p_double[i]*p)/(1-p); ar->cvrmserror = ar->cvrmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); ar->cvavgerror = ar->cvavgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) { ar->cvavgrelerror = ar->cvavgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); nacv = nacv+1; } ncv = ncv+1; } if( ncv==0 ) { /* * Something strange: ALL ui are degenerate. * Unexpected... */ *info = -255; ae_frame_leave(_state); return; } ar->rmserror = ae_sqrt(ar->rmserror/npoints, _state); ar->avgerror = ar->avgerror/npoints; if( na!=0 ) { ar->avgrelerror = ar->avgrelerror/na; } ar->cvrmserror = ae_sqrt(ar->cvrmserror/ncv, _state); ar->cvavgerror = ar->cvavgerror/ncv; if( nacv!=0 ) { ar->cvavgrelerror = ar->cvavgrelerror/nacv; } ae_frame_leave(_state); } void _linearmodel_init(void* _p, ae_state *_state) { linearmodel *p = (linearmodel*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->w, 0, DT_REAL, _state); } void _linearmodel_init_copy(void* _dst, void* _src, ae_state *_state) { linearmodel *dst = (linearmodel*)_dst; linearmodel *src = (linearmodel*)_src; ae_vector_init_copy(&dst->w, &src->w, _state); } void _linearmodel_clear(void* _p) { linearmodel *p = (linearmodel*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->w); } void _linearmodel_destroy(void* _p) { linearmodel *p = (linearmodel*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->w); } void _lrreport_init(void* _p, ae_state *_state) { lrreport *p = (lrreport*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->c, 0, 0, DT_REAL, _state); ae_vector_init(&p->cvdefects, 0, DT_INT, _state); } void _lrreport_init_copy(void* _dst, void* _src, ae_state *_state) { lrreport *dst = (lrreport*)_dst; lrreport *src = (lrreport*)_src; ae_matrix_init_copy(&dst->c, &src->c, _state); dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->cvrmserror = src->cvrmserror; dst->cvavgerror = src->cvavgerror; dst->cvavgrelerror = src->cvavgrelerror; dst->ncvdefects = src->ncvdefects; ae_vector_init_copy(&dst->cvdefects, &src->cvdefects, _state); } void _lrreport_clear(void* _p) { lrreport *p = (lrreport*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->c); ae_vector_clear(&p->cvdefects); } void _lrreport_destroy(void* _p) { lrreport *p = (lrreport*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->c); ae_vector_destroy(&p->cvdefects); } /************************************************************************* Filters: simple moving averages (unsymmetric). This filter replaces array by results of SMA(K) filter. SMA(K) is defined as filter which averages at most K previous points (previous - not points AROUND central point) - or less, in case of the first K-1 points. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filtersma(/* Real */ ae_vector* x, ae_int_t n, ae_int_t k, ae_state *_state) { ae_int_t i; double runningsum; double termsinsum; ae_int_t zeroprefix; double v; ae_assert(n>=0, "FilterSMA: N<0", _state); ae_assert(x->cnt>=n, "FilterSMA: Length(X)=1, "FilterSMA: K<1", _state); /* * Quick exit, if necessary */ if( n<=1||k==1 ) { return; } /* * Prepare variables (see below for explanation) */ runningsum = 0.0; termsinsum = (double)(0); for(i=ae_maxint(n-k, 0, _state); i<=n-1; i++) { runningsum = runningsum+x->ptr.p_double[i]; termsinsum = termsinsum+1; } i = ae_maxint(n-k, 0, _state); zeroprefix = 0; while(i<=n-1&&ae_fp_eq(x->ptr.p_double[i],(double)(0))) { zeroprefix = zeroprefix+1; i = i+1; } /* * General case: we assume that N>1 and K>1 * * Make one pass through all elements. At the beginning of * the iteration we have: * * I element being processed * * RunningSum current value of the running sum * (including I-th element) * * TermsInSum number of terms in sum, 0<=TermsInSum<=K * * ZeroPrefix length of the sequence of zero elements * which starts at X[I-K+1] and continues towards X[I]. * Equal to zero in case X[I-K+1] is non-zero. * This value is used to make RunningSum exactly zero * when it follows from the problem properties. */ for(i=n-1; i>=0; i--) { /* * Store new value of X[i], save old value in V */ v = x->ptr.p_double[i]; x->ptr.p_double[i] = runningsum/termsinsum; /* * Update RunningSum and TermsInSum */ if( i-k>=0 ) { runningsum = runningsum-v+x->ptr.p_double[i-k]; } else { runningsum = runningsum-v; termsinsum = termsinsum-1; } /* * Update ZeroPrefix. * In case we have ZeroPrefix=TermsInSum, * RunningSum is reset to zero. */ if( i-k>=0 ) { if( ae_fp_neq(x->ptr.p_double[i-k],(double)(0)) ) { zeroprefix = 0; } else { zeroprefix = ae_minint(zeroprefix+1, k, _state); } } else { zeroprefix = ae_minint(zeroprefix, i+1, _state); } if( ae_fp_eq((double)(zeroprefix),termsinsum) ) { runningsum = (double)(0); } } } /************************************************************************* Filters: exponential moving averages. This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is defined as filter which replaces X[] by S[]: S[0] = X[0] S[t] = alpha*X[t] + (1-alpha)*S[t-1] INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 alpha - 0=0, "FilterEMA: N<0", _state); ae_assert(x->cnt>=n, "FilterEMA: Length(X)1", _state); /* * Quick exit, if necessary */ if( n<=1||ae_fp_eq(alpha,(double)(1)) ) { return; } /* * Process */ for(i=1; i<=n-1; i++) { x->ptr.p_double[i] = alpha*x->ptr.p_double[i]+(1-alpha)*x->ptr.p_double[i-1]; } } /************************************************************************* Filters: linear regression moving averages. This filter replaces array by results of LRMA(K) filter. LRMA(K) is defined as filter which, for each data point, builds linear regression model using K prevous points (point itself is included in these K points) and calculates value of this linear model at the point in question. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filterlrma(/* Real */ ae_vector* x, ae_int_t n, ae_int_t k, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t m; ae_matrix xy; ae_vector s; ae_int_t info; double a; double b; double vara; double varb; double covab; double corrab; double p; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_assert(n>=0, "FilterLRMA: N<0", _state); ae_assert(x->cnt>=n, "FilterLRMA: Length(X)=1, "FilterLRMA: K<1", _state); /* * Quick exit, if necessary: * * either N is equal to 1 (nothing to average) * * or K is 1 (only point itself is used) or 2 (model is too simple, * we will always get identity transformation) */ if( n<=1||k<=2 ) { ae_frame_leave(_state); return; } /* * General case: K>2, N>1. * We do not process points with I<2 because first two points (I=0 and I=1) will be * left unmodified by LRMA filter in any case. */ ae_matrix_set_length(&xy, k, 2, _state); ae_vector_set_length(&s, k, _state); for(i=0; i<=k-1; i++) { xy.ptr.pp_double[i][0] = (double)(i); s.ptr.p_double[i] = 1.0; } for(i=n-1; i>=2; i--) { m = ae_minint(i+1, k, _state); ae_v_move(&xy.ptr.pp_double[0][1], xy.stride, &x->ptr.p_double[i-m+1], 1, ae_v_len(0,m-1)); lrlines(&xy, &s, m, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); ae_assert(info==1, "FilterLRMA: internal error", _state); x->ptr.p_double[i] = a+b*(m-1); } ae_frame_leave(_state); } /************************************************************************* Multiclass Fisher LDA Subroutine finds coefficients of linear combination which optimally separates training set on classes. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - linear combination coefficients, array[0..NVars-1] -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherlda(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_vector* w, ae_state *_state) { ae_frame _frame_block; ae_matrix w2; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(w); ae_matrix_init(&w2, 0, 0, DT_REAL, _state); fisherldan(xy, npoints, nvars, nclasses, info, &w2, _state); if( *info>0 ) { ae_vector_set_length(w, nvars, _state); ae_v_move(&w->ptr.p_double[0], 1, &w2.ptr.pp_double[0][0], w2.stride, ae_v_len(0,nvars-1)); } ae_frame_leave(_state); } /************************************************************************* N-dimensional multiclass Fisher LDA Subroutine finds coefficients of linear combinations which optimally separates training set on classes. It returns N-dimensional basis whose vector are sorted by quality of training set separation (in descending order). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - basis, array[0..NVars-1,0..NVars-1] columns of matrix stores basis vectors, sorted by quality of training set separation (in descending order) -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherldan(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_matrix* w, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t m; double v; ae_vector c; ae_vector mu; ae_matrix muc; ae_vector nc; ae_matrix sw; ae_matrix st; ae_matrix z; ae_matrix z2; ae_matrix tm; ae_matrix sbroot; ae_matrix a; ae_matrix xyc; ae_matrix xyproj; ae_matrix wproj; ae_vector tf; ae_vector d; ae_vector d2; ae_vector work; ae_frame_make(_state, &_frame_block); *info = 0; ae_matrix_clear(w); ae_vector_init(&c, 0, DT_INT, _state); ae_vector_init(&mu, 0, DT_REAL, _state); ae_matrix_init(&muc, 0, 0, DT_REAL, _state); ae_vector_init(&nc, 0, DT_INT, _state); ae_matrix_init(&sw, 0, 0, DT_REAL, _state); ae_matrix_init(&st, 0, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); ae_matrix_init(&z2, 0, 0, DT_REAL, _state); ae_matrix_init(&tm, 0, 0, DT_REAL, _state); ae_matrix_init(&sbroot, 0, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&xyc, 0, 0, DT_REAL, _state); ae_matrix_init(&xyproj, 0, 0, DT_REAL, _state); ae_matrix_init(&wproj, 0, 0, DT_REAL, _state); ae_vector_init(&tf, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&d2, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); /* * Test data */ if( (npoints<0||nvars<1)||nclasses<2 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Special case: NPoints<=1 * Degenerate task. */ if( npoints<=1 ) { *info = 2; ae_matrix_set_length(w, nvars, nvars, _state); for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { if( i==j ) { w->ptr.pp_double[i][j] = (double)(1); } else { w->ptr.pp_double[i][j] = (double)(0); } } } ae_frame_leave(_state); return; } /* * Prepare temporaries */ ae_vector_set_length(&tf, nvars, _state); ae_vector_set_length(&work, ae_maxint(nvars, npoints, _state)+1, _state); ae_matrix_set_length(&xyc, npoints, nvars, _state); /* * Convert class labels from reals to integers (just for convenience) */ ae_vector_set_length(&c, npoints, _state); for(i=0; i<=npoints-1; i++) { c.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nvars], _state); } /* * Calculate class sizes, class means */ ae_vector_set_length(&mu, nvars, _state); ae_matrix_set_length(&muc, nclasses, nvars, _state); ae_vector_set_length(&nc, nclasses, _state); for(j=0; j<=nvars-1; j++) { mu.ptr.p_double[j] = (double)(0); } for(i=0; i<=nclasses-1; i++) { nc.ptr.p_int[i] = 0; for(j=0; j<=nvars-1; j++) { muc.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=npoints-1; i++) { ae_v_add(&mu.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_add(&muc.ptr.pp_double[c.ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); nc.ptr.p_int[c.ptr.p_int[i]] = nc.ptr.p_int[c.ptr.p_int[i]]+1; } for(i=0; i<=nclasses-1; i++) { v = (double)1/(double)nc.ptr.p_int[i]; ae_v_muld(&muc.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); } v = (double)1/(double)npoints; ae_v_muld(&mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1), v); /* * Create ST matrix */ ae_matrix_set_length(&st, nvars, nvars, _state); for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { st.ptr.pp_double[i][j] = (double)(0); } } for(k=0; k<=npoints-1; k++) { ae_v_move(&xyc.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&xyc.ptr.pp_double[k][0], 1, &mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); } rmatrixgemm(nvars, nvars, npoints, 1.0, &xyc, 0, 0, 1, &xyc, 0, 0, 0, 0.0, &st, 0, 0, _state); /* * Create SW matrix */ ae_matrix_set_length(&sw, nvars, nvars, _state); for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { sw.ptr.pp_double[i][j] = (double)(0); } } for(k=0; k<=npoints-1; k++) { ae_v_move(&xyc.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&xyc.ptr.pp_double[k][0], 1, &muc.ptr.pp_double[c.ptr.p_int[k]][0], 1, ae_v_len(0,nvars-1)); } rmatrixgemm(nvars, nvars, npoints, 1.0, &xyc, 0, 0, 1, &xyc, 0, 0, 0, 0.0, &sw, 0, 0, _state); /* * Maximize ratio J=(w'*ST*w)/(w'*SW*w). * * First, make transition from w to v such that w'*ST*w becomes v'*v: * v = root(ST)*w = R*w * R = root(D)*Z' * w = (root(ST)^-1)*v = RI*v * RI = Z*inv(root(D)) * J = (v'*v)/(v'*(RI'*SW*RI)*v) * ST = Z*D*Z' * * so we have * * J = (v'*v) / (v'*(inv(root(D))*Z'*SW*Z*inv(root(D)))*v) = * = (v'*v) / (v'*A*v) */ if( !smatrixevd(&st, nvars, 1, ae_true, &d, &z, _state) ) { *info = -4; ae_frame_leave(_state); return; } ae_matrix_set_length(w, nvars, nvars, _state); if( ae_fp_less_eq(d.ptr.p_double[nvars-1],(double)(0))||ae_fp_less_eq(d.ptr.p_double[0],1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) { /* * Special case: D[NVars-1]<=0 * Degenerate task (all variables takes the same value). */ if( ae_fp_less_eq(d.ptr.p_double[nvars-1],(double)(0)) ) { *info = 2; for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { if( i==j ) { w->ptr.pp_double[i][j] = (double)(1); } else { w->ptr.pp_double[i][j] = (double)(0); } } } ae_frame_leave(_state); return; } /* * Special case: degenerate ST matrix, multicollinearity found. * Since we know ST eigenvalues/vectors we can translate task to * non-degenerate form. * * Let WG is orthogonal basis of the non zero variance subspace * of the ST and let WZ is orthogonal basis of the zero variance * subspace. * * Projection on WG allows us to use LDA on reduced M-dimensional * subspace, N-M vectors of WZ allows us to update reduced LDA * factors to full N-dimensional subspace. */ m = 0; for(k=0; k<=nvars-1; k++) { if( ae_fp_less_eq(d.ptr.p_double[k],1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) { m = k+1; } } ae_assert(m!=0, "FisherLDAN: internal error #1", _state); ae_matrix_set_length(&xyproj, npoints, nvars-m+1, _state); rmatrixgemm(npoints, nvars-m, nvars, 1.0, xy, 0, 0, 0, &z, 0, m, 0, 0.0, &xyproj, 0, 0, _state); for(i=0; i<=npoints-1; i++) { xyproj.ptr.pp_double[i][nvars-m] = xy->ptr.pp_double[i][nvars]; } fisherldan(&xyproj, npoints, nvars-m, nclasses, info, &wproj, _state); if( *info<0 ) { ae_frame_leave(_state); return; } rmatrixgemm(nvars, nvars-m, nvars-m, 1.0, &z, 0, m, 0, &wproj, 0, 0, 0, 0.0, w, 0, 0, _state); for(k=nvars-m; k<=nvars-1; k++) { ae_v_move(&w->ptr.pp_double[0][k], w->stride, &z.ptr.pp_double[0][k-(nvars-m)], z.stride, ae_v_len(0,nvars-1)); } *info = 2; } else { /* * General case: no multicollinearity */ ae_matrix_set_length(&tm, nvars, nvars, _state); ae_matrix_set_length(&a, nvars, nvars, _state); rmatrixgemm(nvars, nvars, nvars, 1.0, &sw, 0, 0, 0, &z, 0, 0, 0, 0.0, &tm, 0, 0, _state); rmatrixgemm(nvars, nvars, nvars, 1.0, &z, 0, 0, 1, &tm, 0, 0, 0, 0.0, &a, 0, 0, _state); for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]/ae_sqrt(d.ptr.p_double[i]*d.ptr.p_double[j], _state); } } if( !smatrixevd(&a, nvars, 1, ae_true, &d2, &z2, _state) ) { *info = -4; ae_frame_leave(_state); return; } for(i=0; i<=nvars-1; i++) { for(k=0; k<=nvars-1; k++) { z2.ptr.pp_double[i][k] = z2.ptr.pp_double[i][k]/ae_sqrt(d.ptr.p_double[i], _state); } } rmatrixgemm(nvars, nvars, nvars, 1.0, &z, 0, 0, 0, &z2, 0, 0, 0, 0.0, w, 0, 0, _state); } /* * Post-processing: * * normalization * * converting to non-negative form, if possible */ for(k=0; k<=nvars-1; k++) { v = ae_v_dotproduct(&w->ptr.pp_double[0][k], w->stride, &w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1)); v = 1/ae_sqrt(v, _state); ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), v); v = (double)(0); for(i=0; i<=nvars-1; i++) { v = v+w->ptr.pp_double[i][k]; } if( ae_fp_less(v,(double)(0)) ) { ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), -1); } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_fisherldan(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_matrix* w, ae_state *_state) { fisherldan(xy,npoints,nvars,nclasses,info,w, _state); } /************************************************************************* This function returns number of weights updates which is required for gradient calculation problem to be splitted. *************************************************************************/ ae_int_t mlpgradsplitcost(ae_state *_state) { ae_int_t result; result = mlpbase_gradbasecasecost; return result; } /************************************************************************* This function returns number of elements in subset of dataset which is required for gradient calculation problem to be splitted. *************************************************************************/ ae_int_t mlpgradsplitsize(ae_state *_state) { ae_int_t result; result = mlpbase_microbatchsize; return result; } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers, with linear output layer. Network weights are filled with small random values. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate0(ae_int_t nin, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Same as MLPCreate0, but with one hidden layer (NHid neurons) with non-linear activation function. Output layer is linear. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) with non-linear activation function. Output layer is linear. $ALL -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values: (B, +INF), if D>=0 or (-INF, B), if D<0. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb0(ae_int_t nin, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3; if( ae_fp_greater_eq(d,(double)(0)) ) { d = (double)(1); } else { d = (double)(-1); } /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); /* * Turn on ouputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = b; network->columnsigmas.ptr.p_double[i] = d; } ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateB0 but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3; if( ae_fp_greater_eq(d,(double)(0)) ) { d = (double)(1); } else { d = (double)(-1); } /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); /* * Turn on ouputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = b; network->columnsigmas.ptr.p_double[i] = d; } ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateB0 but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3+3; if( ae_fp_greater_eq(d,(double)(0)) ) { d = (double)(1); } else { d = (double)(-1); } /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); /* * Turn on ouputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = b; network->columnsigmas.ptr.p_double[i] = d; } ae_frame_leave(_state); } /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values [A,B]. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater0(ae_int_t nin, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); /* * Turn on outputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = 0.5*(a+b); network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); } ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateR0, but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); /* * Turn on outputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = 0.5*(a+b); network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); } ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateR0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); layerscount = 1+3+3+3; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); /* * Turn on outputs shift/scaling. */ for(i=nin; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = 0.5*(a+b); network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); } ae_frame_leave(_state); } /************************************************************************* Creates classifier network with NIn inputs and NOut possible classes. Network contains no hidden layers and linear output layer with SOFTMAX- normalization (so outputs sums up to 1.0 and converge to posterior probabilities). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec0(ae_int_t nin, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); ae_assert(nout>=2, "MLPCreateC0: NOut<2!", _state); layerscount = 1+2+1; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_true, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateC0, but with one non-linear hidden layer. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); ae_assert(nout>=2, "MLPCreateC1: NOut<2!", _state); layerscount = 1+3+2+1; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_true, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Same as MLPCreateC0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_vector lsizes; ae_vector ltypes; ae_vector lconnfirst; ae_vector lconnlast; ae_int_t layerscount; ae_int_t lastproc; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&lsizes, 0, DT_INT, _state); ae_vector_init(<ypes, 0, DT_INT, _state); ae_vector_init(&lconnfirst, 0, DT_INT, _state); ae_vector_init(&lconnlast, 0, DT_INT, _state); ae_assert(nout>=2, "MLPCreateC2: NOut<2!", _state); layerscount = 1+3+3+2+1; /* * Allocate arrays */ ae_vector_set_length(&lsizes, layerscount-1+1, _state); ae_vector_set_length(<ypes, layerscount-1+1, _state); ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); ae_vector_set_length(&lconnlast, layerscount-1+1, _state); /* * Layers */ mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); /* * Create */ mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_true, ae_true, _state); ae_frame_leave(_state); } /************************************************************************* Copying of neural network INPUT PARAMETERS: Network1 - original OUTPUT PARAMETERS: Network2 - copy -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcopy(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state) { _multilayerperceptron_clear(network2); mlpcopyshared(network1, network2, _state); } /************************************************************************* Copying of neural network (second parameter is passed as shared object). INPUT PARAMETERS: Network1 - original OUTPUT PARAMETERS: Network2 - copy -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcopyshared(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state) { ae_frame _frame_block; ae_int_t wcount; ae_int_t i; mlpbuffers buf; smlpgrad sgrad; ae_frame_make(_state, &_frame_block); _mlpbuffers_init(&buf, _state); _smlpgrad_init(&sgrad, _state); /* * Copy scalar and array fields */ network2->hlnetworktype = network1->hlnetworktype; network2->hlnormtype = network1->hlnormtype; copyintegerarray(&network1->hllayersizes, &network2->hllayersizes, _state); copyintegerarray(&network1->hlconnections, &network2->hlconnections, _state); copyintegerarray(&network1->hlneurons, &network2->hlneurons, _state); copyintegerarray(&network1->structinfo, &network2->structinfo, _state); copyrealarray(&network1->weights, &network2->weights, _state); copyrealarray(&network1->columnmeans, &network2->columnmeans, _state); copyrealarray(&network1->columnsigmas, &network2->columnsigmas, _state); copyrealarray(&network1->neurons, &network2->neurons, _state); copyrealarray(&network1->dfdnet, &network2->dfdnet, _state); copyrealarray(&network1->derror, &network2->derror, _state); copyrealarray(&network1->x, &network2->x, _state); copyrealarray(&network1->y, &network2->y, _state); copyrealarray(&network1->nwbuf, &network2->nwbuf, _state); copyintegerarray(&network1->integerbuf, &network2->integerbuf, _state); /* * copy buffers */ wcount = mlpgetweightscount(network1, _state); ae_shared_pool_set_seed(&network2->buf, &buf, sizeof(buf), _mlpbuffers_init, _mlpbuffers_init_copy, _mlpbuffers_destroy, _state); ae_vector_set_length(&sgrad.g, wcount, _state); sgrad.f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad.g.ptr.p_double[i] = 0.0; } ae_shared_pool_set_seed(&network2->gradbuf, &sgrad, sizeof(sgrad), _smlpgrad_init, _smlpgrad_init_copy, _smlpgrad_destroy, _state); ae_frame_leave(_state); } /************************************************************************* This function compares architectures of neural networks. Only geometries are compared, weights and other parameters are not tested. -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ ae_bool mlpsamearchitecture(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state) { ae_int_t i; ae_int_t ninfo; ae_bool result; ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network1 is uninitialized", _state); ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network2 is uninitialized", _state); result = ae_false; if( network1->structinfo.ptr.p_int[0]!=network2->structinfo.ptr.p_int[0] ) { return result; } ninfo = network1->structinfo.ptr.p_int[0]; for(i=0; i<=ninfo-1; i++) { if( network1->structinfo.ptr.p_int[i]!=network2->structinfo.ptr.p_int[i] ) { return result; } } result = ae_true; return result; } /************************************************************************* This function copies tunable parameters (weights/means/sigmas) from one network to another with same architecture. It performs some rudimentary checks that architectures are same, and throws exception if check fails. It is intended for fast copying of states between two network which are known to have same geometry. INPUT PARAMETERS: Network1 - source, must be correctly initialized Network2 - target, must have same architecture OUTPUT PARAMETERS: Network2 - network state is copied from source to target -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ void mlpcopytunableparameters(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state) { ae_int_t i; ae_int_t ninfo; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 is uninitialized", _state); ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network2 is uninitialized", _state); ae_assert(network1->structinfo.ptr.p_int[0]==network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); ninfo = network1->structinfo.ptr.p_int[0]; for(i=0; i<=ninfo-1; i++) { ae_assert(network1->structinfo.ptr.p_int[i]==network2->structinfo.ptr.p_int[i], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); } mlpproperties(network1, &nin, &nout, &wcount, _state); for(i=0; i<=wcount-1; i++) { network2->weights.ptr.p_double[i] = network1->weights.ptr.p_double[i]; } if( mlpissoftmax(network1, _state) ) { for(i=0; i<=nin-1; i++) { network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; } } else { for(i=0; i<=nin+nout-1; i++) { network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; } } } /************************************************************************* This function exports tunable parameters (weights/means/sigmas) from network to contiguous array. Nothing is guaranteed about array format, the only thing you can count for is that MLPImportTunableParameters() will be able to parse it. It is intended for fast copying of states between network and backup array INPUT PARAMETERS: Network - source, must be correctly initialized P - array to use. If its size is enough to store data, it is reused. OUTPUT PARAMETERS: P - array which stores network parameters, resized if needed PCount - number of parameters stored in array. -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ void mlpexporttunableparameters(multilayerperceptron* network, /* Real */ ae_vector* p, ae_int_t* pcount, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t nin; ae_int_t nout; ae_int_t wcount; *pcount = 0; ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPExportTunableParameters: Network is uninitialized", _state); mlpproperties(network, &nin, &nout, &wcount, _state); if( mlpissoftmax(network, _state) ) { *pcount = wcount+2*nin; rvectorsetlengthatleast(p, *pcount, _state); k = 0; for(i=0; i<=wcount-1; i++) { p->ptr.p_double[k] = network->weights.ptr.p_double[i]; k = k+1; } for(i=0; i<=nin-1; i++) { p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; k = k+1; p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; k = k+1; } } else { *pcount = wcount+2*(nin+nout); rvectorsetlengthatleast(p, *pcount, _state); k = 0; for(i=0; i<=wcount-1; i++) { p->ptr.p_double[k] = network->weights.ptr.p_double[i]; k = k+1; } for(i=0; i<=nin+nout-1; i++) { p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; k = k+1; p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; k = k+1; } } } /************************************************************************* This function imports tunable parameters (weights/means/sigmas) which were exported by MLPExportTunableParameters(). It is intended for fast copying of states between network and backup array INPUT PARAMETERS: Network - target: * must be correctly initialized * must have same geometry as network used to export params P - array with parameters -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ void mlpimporttunableparameters(multilayerperceptron* network, /* Real */ ae_vector* p, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPImportTunableParameters: Network is uninitialized", _state); mlpproperties(network, &nin, &nout, &wcount, _state); if( mlpissoftmax(network, _state) ) { k = 0; for(i=0; i<=wcount-1; i++) { network->weights.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; } for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; } } else { k = 0; for(i=0; i<=wcount-1; i++) { network->weights.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; } for(i=0; i<=nin+nout-1; i++) { network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; k = k+1; } } } /************************************************************************* Serialization of MultiLayerPerceptron strucure INPUT PARAMETERS: Network - original OUTPUT PARAMETERS: RA - array of real numbers which stores network, array[0..RLen-1] RLen - RA lenght -- ALGLIB -- Copyright 29.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpserializeold(multilayerperceptron* network, /* Real */ ae_vector* ra, ae_int_t* rlen, ae_state *_state) { ae_int_t i; ae_int_t ssize; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t sigmalen; ae_int_t offs; ae_vector_clear(ra); *rlen = 0; /* * Unload info */ ssize = network->structinfo.ptr.p_int[0]; nin = network->structinfo.ptr.p_int[1]; nout = network->structinfo.ptr.p_int[2]; wcount = network->structinfo.ptr.p_int[4]; if( mlpissoftmax(network, _state) ) { sigmalen = nin; } else { sigmalen = nin+nout; } /* * RA format: * LEN DESRC. * 1 RLen * 1 version (MLPVNum) * 1 StructInfo size * SSize StructInfo * WCount Weights * SigmaLen ColumnMeans * SigmaLen ColumnSigmas */ *rlen = 3+ssize+wcount+2*sigmalen; ae_vector_set_length(ra, *rlen-1+1, _state); ra->ptr.p_double[0] = (double)(*rlen); ra->ptr.p_double[1] = (double)(mlpbase_mlpvnum); ra->ptr.p_double[2] = (double)(ssize); offs = 3; for(i=0; i<=ssize-1; i++) { ra->ptr.p_double[offs+i] = (double)(network->structinfo.ptr.p_int[i]); } offs = offs+ssize; ae_v_move(&ra->ptr.p_double[offs], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); offs = offs+wcount; ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); offs = offs+sigmalen; ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); offs = offs+sigmalen; } /************************************************************************* Unserialization of MultiLayerPerceptron strucure INPUT PARAMETERS: RA - real array which stores network OUTPUT PARAMETERS: Network - restored network -- ALGLIB -- Copyright 29.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpunserializeold(/* Real */ ae_vector* ra, multilayerperceptron* network, ae_state *_state) { ae_int_t i; ae_int_t ssize; ae_int_t ntotal; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t sigmalen; ae_int_t offs; _multilayerperceptron_clear(network); ae_assert(ae_round(ra->ptr.p_double[1], _state)==mlpbase_mlpvnum, "MLPUnserialize: incorrect array!", _state); /* * Unload StructInfo from IA */ offs = 3; ssize = ae_round(ra->ptr.p_double[2], _state); ae_vector_set_length(&network->structinfo, ssize-1+1, _state); for(i=0; i<=ssize-1; i++) { network->structinfo.ptr.p_int[i] = ae_round(ra->ptr.p_double[offs+i], _state); } offs = offs+ssize; /* * Unload info from StructInfo */ ssize = network->structinfo.ptr.p_int[0]; nin = network->structinfo.ptr.p_int[1]; nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; wcount = network->structinfo.ptr.p_int[4]; if( network->structinfo.ptr.p_int[6]==0 ) { sigmalen = nin+nout; } else { sigmalen = nin; } /* * Allocate space for other fields */ ae_vector_set_length(&network->weights, wcount-1+1, _state); ae_vector_set_length(&network->columnmeans, sigmalen-1+1, _state); ae_vector_set_length(&network->columnsigmas, sigmalen-1+1, _state); ae_vector_set_length(&network->neurons, ntotal-1+1, _state); ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); ae_vector_set_length(&network->x, nin-1+1, _state); ae_vector_set_length(&network->y, nout-1+1, _state); ae_vector_set_length(&network->derror, ntotal-1+1, _state); /* * Copy parameters from RA */ ae_v_move(&network->weights.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,wcount-1)); offs = offs+wcount; ae_v_move(&network->columnmeans.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); offs = offs+sigmalen; ae_v_move(&network->columnsigmas.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); offs = offs+sigmalen; } /************************************************************************* Randomization of neural network weights -- ALGLIB -- Copyright 06.11.2007 by Bochkanov Sergey *************************************************************************/ void mlprandomize(multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; hqrndstate r; ae_int_t entrysize; ae_int_t entryoffs; ae_int_t neuronidx; ae_int_t neurontype; double vmean; double vvar; ae_int_t i; ae_int_t n1; ae_int_t n2; double desiredsigma; ae_int_t montecarlocnt; double ef; double ef2; double v; double wscale; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&r, _state); hqrndrandomize(&r, _state); mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; desiredsigma = 0.5; montecarlocnt = 20; /* * Stage 1: * * Network.Weights is filled by standard deviation of weights * * default values: sigma=1 */ for(i=0; i<=wcount-1; i++) { network->weights.ptr.p_double[i] = 1.0; } /* * Stage 2: * * assume that input neurons have zero mean and unit standard deviation * * assume that constant neurons have zero standard deviation * * perform forward pass along neurons * * for each non-input non-constant neuron: * * calculate mean and standard deviation of neuron's output * assuming that we know means/deviations of neurons which feed it * and assuming that weights has unit variance and zero mean. * * for each nonlinear neuron additionally we perform backward pass: * * scale variances of weights which feed it in such way that neuron's * input has unit standard deviation * * NOTE: this algorithm assumes that each connection feeds at most one * non-linear neuron. This assumption can be incorrect in upcoming * architectures with strong neurons. However, algorithm should * work smoothly even in this case. * * During this stage we use Network.RndBuf, which is grouped into NTotal * entries, each of them having following format: * * Buf[Offset+0] mean value of neuron's output * Buf[Offset+1] standard deviation of neuron's output * * */ entrysize = 2; rvectorsetlengthatleast(&network->rndbuf, entrysize*ntotal, _state); for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) { neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; entryoffs = entrysize*neuronidx; if( neurontype==-2 ) { /* * Input neuron: zero mean, unit variance. */ network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; network->rndbuf.ptr.p_double[entryoffs+1] = 1.0; continue; } if( neurontype==-3 ) { /* * "-1" neuron: mean=-1, zero variance. */ network->rndbuf.ptr.p_double[entryoffs+0] = -1.0; network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; continue; } if( neurontype==-4 ) { /* * "0" neuron: mean=0, zero variance. */ network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; continue; } if( neurontype==0 ) { /* * Adaptive summator neuron: * * calculate its mean and variance. * * we assume that weights of this neuron have unit variance and zero mean. * * thus, neuron's output is always have zero mean * * as for variance, it is a bit more interesting: * * let n[i] is i-th input neuron * * let w[i] is i-th weight * * we assume that n[i] and w[i] are independently distributed * * Var(n0*w0+n1*w1+...) = Var(n0*w0)+Var(n1*w1)+... * * Var(X*Y) = mean(X)^2*Var(Y) + mean(Y)^2*Var(X) + Var(X)*Var(Y) * * mean(w[i])=0, var(w[i])=1 * * Var(n[i]*w[i]) = mean(n[i])^2 + Var(n[i]) */ n1 = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; n2 = n1+network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+1]-1; vmean = 0.0; vvar = 0.0; for(i=n1; i<=n2; i++) { vvar = vvar+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+0], _state)+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); } network->rndbuf.ptr.p_double[entryoffs+0] = vmean; network->rndbuf.ptr.p_double[entryoffs+1] = ae_sqrt(vvar, _state); continue; } if( neurontype==-5 ) { /* * Linear activation function */ i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); if( ae_fp_greater(vvar,(double)(0)) ) { wscale = desiredsigma/ae_sqrt(vvar, _state); } else { wscale = 1.0; } mlpbase_randomizebackwardpass(network, i, wscale, _state); network->rndbuf.ptr.p_double[entryoffs+0] = vmean*wscale; network->rndbuf.ptr.p_double[entryoffs+1] = desiredsigma; continue; } if( neurontype>0 ) { /* * Nonlinear activation function: * * scale its inputs * * estimate mean/sigma of its output using Monte-Carlo method * (we simulate different inputs with unit deviation and * sample activation function output on such inputs) */ i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); if( ae_fp_greater(vvar,(double)(0)) ) { wscale = desiredsigma/ae_sqrt(vvar, _state); } else { wscale = 1.0; } mlpbase_randomizebackwardpass(network, i, wscale, _state); ef = 0.0; ef2 = 0.0; vmean = vmean*wscale; for(i=0; i<=montecarlocnt-1; i++) { v = vmean+desiredsigma*hqrndnormal(&r, _state); ef = ef+v; ef2 = ef2+v*v; } ef = ef/montecarlocnt; ef2 = ef2/montecarlocnt; network->rndbuf.ptr.p_double[entryoffs+0] = ef; network->rndbuf.ptr.p_double[entryoffs+1] = ae_maxreal(ef2-ef*ef, 0.0, _state); continue; } ae_assert(ae_false, "MLPRandomize: unexpected neuron type", _state); } /* * Stage 3: generate weights. */ for(i=0; i<=wcount-1; i++) { network->weights.ptr.p_double[i] = network->weights.ptr.p_double[i]*hqrndnormal(&r, _state); } ae_frame_leave(_state); } /************************************************************************* Randomization of neural network weights and standartisator -- ALGLIB -- Copyright 10.03.2008 by Bochkanov Sergey *************************************************************************/ void mlprandomizefull(multilayerperceptron* network, ae_state *_state) { ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t offs; ae_int_t ntype; mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Process network */ mlprandomize(network, _state); for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = ae_randomreal(_state)-0.5; network->columnsigmas.ptr.p_double[i] = ae_randomreal(_state)+0.5; } if( !mlpissoftmax(network, _state) ) { for(i=0; i<=nout-1; i++) { offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; ntype = network->structinfo.ptr.p_int[offs+0]; if( ntype==0 ) { /* * Shifts are changed only for linear outputs neurons */ network->columnmeans.ptr.p_double[nin+i] = 2*ae_randomreal(_state)-1; } if( ntype==0||ntype==3 ) { /* * Scales are changed only for linear or bounded outputs neurons. * Note that scale randomization preserves sign. */ network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*(1.5*ae_randomreal(_state)+0.5); } } } } /************************************************************************* Internal subroutine. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessor(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t jmax; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t offs; ae_int_t ntype; ae_vector means; ae_vector sigmas; double s; ae_frame_make(_state, &_frame_block); ae_vector_init(&means, 0, DT_REAL, _state); ae_vector_init(&sigmas, 0, DT_REAL, _state); mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Means/Sigmas */ if( mlpissoftmax(network, _state) ) { jmax = nin-1; } else { jmax = nin+nout-1; } ae_vector_set_length(&means, jmax+1, _state); ae_vector_set_length(&sigmas, jmax+1, _state); for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = (double)(0); sigmas.ptr.p_double[i] = (double)(0); } for(i=0; i<=ssize-1; i++) { for(j=0; j<=jmax; j++) { means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[i][j]; } } for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = means.ptr.p_double[i]/ssize; } for(i=0; i<=ssize-1; i++) { for(j=0; j<=jmax; j++) { sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[i][j]-means.ptr.p_double[j], _state); } } for(i=0; i<=jmax; i++) { sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/ssize, _state); } /* * Inputs */ for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) { network->columnsigmas.ptr.p_double[i] = (double)(1); } } /* * Outputs */ if( !mlpissoftmax(network, _state) ) { for(i=0; i<=nout-1; i++) { offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; ntype = network->structinfo.ptr.p_int[offs+0]; /* * Linear outputs */ if( ntype==0 ) { network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } /* * Bounded outputs (half-interval) */ if( ntype==3 ) { s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; if( ae_fp_eq(s,(double)(0)) ) { s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); } if( ae_fp_eq(s,(double)(0)) ) { s = 1.0; } network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Initialization for preprocessor based on a sample. INPUT Network - initialized neural network; XY - sample, given by sparse matrix; SSize - sample size. OUTPUT Network - neural network with initialised preprocessor. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, ae_state *_state) { ae_frame _frame_block; ae_int_t jmax; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t offs; ae_int_t ntype; ae_vector means; ae_vector sigmas; double s; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init(&means, 0, DT_REAL, _state); ae_vector_init(&sigmas, 0, DT_REAL, _state); mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Means/Sigmas */ if( mlpissoftmax(network, _state) ) { jmax = nin-1; } else { jmax = nin+nout-1; } ae_vector_set_length(&means, jmax+1, _state); ae_vector_set_length(&sigmas, jmax+1, _state); for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = (double)(0); sigmas.ptr.p_double[i] = (double)(0); } for(i=0; i<=ssize-1; i++) { sparsegetrow(xy, i, &network->xyrow, _state); for(j=0; j<=jmax; j++) { means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; } } for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = means.ptr.p_double[i]/ssize; } for(i=0; i<=ssize-1; i++) { sparsegetrow(xy, i, &network->xyrow, _state); for(j=0; j<=jmax; j++) { sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); } } for(i=0; i<=jmax; i++) { sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/ssize, _state); } /* * Inputs */ for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) { network->columnsigmas.ptr.p_double[i] = (double)(1); } } /* * Outputs */ if( !mlpissoftmax(network, _state) ) { for(i=0; i<=nout-1; i++) { offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; ntype = network->structinfo.ptr.p_int[offs+0]; /* * Linear outputs */ if( ntype==0 ) { network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } /* * Bounded outputs (half-interval) */ if( ntype==3 ) { s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; if( ae_fp_eq(s,(double)(0)) ) { s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); } if( ae_fp_eq(s,(double)(0)) ) { s = 1.0; } network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Initialization for preprocessor based on a subsample. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array. OUTPUT: Network - neural network with initialised preprocessor. NOTE: when SubsetSize<0 is used full dataset by call MLPInitPreprocessor function. -- ALGLIB -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, ae_state *_state) { ae_frame _frame_block; ae_int_t jmax; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t offs; ae_int_t ntype; ae_vector means; ae_vector sigmas; double s; ae_int_t npoints; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init(&means, 0, DT_REAL, _state); ae_vector_init(&sigmas, 0, DT_REAL, _state); ae_assert(setsize>=0, "MLPInitPreprocessorSubset: SetSize<0", _state); if( subsetsize<0 ) { mlpinitpreprocessor(network, xy, setsize, _state); ae_frame_leave(_state); return; } ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSubset: SubsetSize>Length(Idx)", _state); npoints = setsize; for(i=0; i<=subsetsize-1; i++) { ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]<0)", _state); ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); } mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Means/Sigmas */ if( mlpissoftmax(network, _state) ) { jmax = nin-1; } else { jmax = nin+nout-1; } ae_vector_set_length(&means, jmax+1, _state); ae_vector_set_length(&sigmas, jmax+1, _state); for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = (double)(0); sigmas.ptr.p_double[i] = (double)(0); } for(i=0; i<=subsetsize-1; i++) { for(j=0; j<=jmax; j++) { means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[idx->ptr.p_int[i]][j]; } } for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = means.ptr.p_double[i]/subsetsize; } for(i=0; i<=subsetsize-1; i++) { for(j=0; j<=jmax; j++) { sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[idx->ptr.p_int[i]][j]-means.ptr.p_double[j], _state); } } for(i=0; i<=jmax; i++) { sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/subsetsize, _state); } /* * Inputs */ for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) { network->columnsigmas.ptr.p_double[i] = (double)(1); } } /* * Outputs */ if( !mlpissoftmax(network, _state) ) { for(i=0; i<=nout-1; i++) { offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; ntype = network->structinfo.ptr.p_int[offs+0]; /* * Linear outputs */ if( ntype==0 ) { network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } /* * Bounded outputs (half-interval) */ if( ntype==3 ) { s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; if( ae_fp_eq(s,(double)(0)) ) { s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); } if( ae_fp_eq(s,(double)(0)) ) { s = 1.0; } network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Initialization for preprocessor based on a subsample. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset, given by sparse matrix; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array. OUTPUT: Network - neural network with initialised preprocessor. NOTE: when SubsetSize<0 is used full dataset by call MLPInitPreprocessorSparse function. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, ae_state *_state) { ae_frame _frame_block; ae_int_t jmax; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t offs; ae_int_t ntype; ae_vector means; ae_vector sigmas; double s; ae_int_t npoints; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_vector_init(&means, 0, DT_REAL, _state); ae_vector_init(&sigmas, 0, DT_REAL, _state); ae_assert(setsize>=0, "MLPInitPreprocessorSparseSubset: SetSize<0", _state); if( subsetsize<0 ) { mlpinitpreprocessorsparse(network, xy, setsize, _state); ae_frame_leave(_state); return; } ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSparseSubset: SubsetSize>Length(Idx)", _state); npoints = setsize; for(i=0; i<=subsetsize-1; i++) { ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); } mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Means/Sigmas */ if( mlpissoftmax(network, _state) ) { jmax = nin-1; } else { jmax = nin+nout-1; } ae_vector_set_length(&means, jmax+1, _state); ae_vector_set_length(&sigmas, jmax+1, _state); for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = (double)(0); sigmas.ptr.p_double[i] = (double)(0); } for(i=0; i<=subsetsize-1; i++) { sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); for(j=0; j<=jmax; j++) { means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; } } for(i=0; i<=jmax; i++) { means.ptr.p_double[i] = means.ptr.p_double[i]/subsetsize; } for(i=0; i<=subsetsize-1; i++) { sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); for(j=0; j<=jmax; j++) { sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); } } for(i=0; i<=jmax; i++) { sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/subsetsize, _state); } /* * Inputs */ for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) { network->columnsigmas.ptr.p_double[i] = (double)(1); } } /* * Outputs */ if( !mlpissoftmax(network, _state) ) { for(i=0; i<=nout-1; i++) { offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; ntype = network->structinfo.ptr.p_int[offs+0]; /* * Linear outputs */ if( ntype==0 ) { network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } /* * Bounded outputs (half-interval) */ if( ntype==3 ) { s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; if( ae_fp_eq(s,(double)(0)) ) { s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); } if( ae_fp_eq(s,(double)(0)) ) { s = 1.0; } network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) { network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } } } ae_frame_leave(_state); } /************************************************************************* Returns information about initialized network: number of inputs, outputs, weights. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpproperties(multilayerperceptron* network, ae_int_t* nin, ae_int_t* nout, ae_int_t* wcount, ae_state *_state) { *nin = 0; *nout = 0; *wcount = 0; *nin = network->structinfo.ptr.p_int[1]; *nout = network->structinfo.ptr.p_int[2]; *wcount = network->structinfo.ptr.p_int[4]; } /************************************************************************* Returns number of "internal", low-level neurons in the network (one which is stored in StructInfo). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpntotal(multilayerperceptron* network, ae_state *_state) { ae_int_t result; result = network->structinfo.ptr.p_int[3]; return result; } /************************************************************************* Returns number of inputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetinputscount(multilayerperceptron* network, ae_state *_state) { ae_int_t result; result = network->structinfo.ptr.p_int[1]; return result; } /************************************************************************* Returns number of outputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetoutputscount(multilayerperceptron* network, ae_state *_state) { ae_int_t result; result = network->structinfo.ptr.p_int[2]; return result; } /************************************************************************* Returns number of weights. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetweightscount(multilayerperceptron* network, ae_state *_state) { ae_int_t result; result = network->structinfo.ptr.p_int[4]; return result; } /************************************************************************* Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ ae_bool mlpissoftmax(multilayerperceptron* network, ae_state *_state) { ae_bool result; result = network->structinfo.ptr.p_int[6]==1; return result; } /************************************************************************* This function returns total number of layers (including input, hidden and output layers). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayerscount(multilayerperceptron* network, ae_state *_state) { ae_int_t result; result = network->hllayersizes.cnt; return result; } /************************************************************************* This function returns size of K-th layer. K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. Size of the output layer is always equal to the number of outputs, although when we have softmax-normalized network, last neuron doesn't have any connections - it is just zero. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayersize(multilayerperceptron* network, ae_int_t k, ae_state *_state) { ae_int_t result; ae_assert(k>=0&&khllayersizes.cnt, "MLPGetLayerSize: incorrect layer index", _state); result = network->hllayersizes.ptr.p_int[k]; return result; } /************************************************************************* This function returns offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetinputscaling(multilayerperceptron* network, ae_int_t i, double* mean, double* sigma, ae_state *_state) { *mean = 0; *sigma = 0; ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPGetInputScaling: incorrect (nonexistent) I", _state); *mean = network->columnmeans.ptr.p_double[i]; *sigma = network->columnsigmas.ptr.p_double[i]; if( ae_fp_eq(*sigma,(double)(0)) ) { *sigma = (double)(1); } } /************************************************************************* This function returns offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. In case we have SOFTMAX-normalized network, we return (Mean,Sigma)=(0.0,1.0). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetoutputscaling(multilayerperceptron* network, ae_int_t i, double* mean, double* sigma, ae_state *_state) { *mean = 0; *sigma = 0; ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPGetOutputScaling: incorrect (nonexistent) I", _state); if( network->structinfo.ptr.p_int[6]==1 ) { *mean = (double)(0); *sigma = (double)(1); } else { *mean = network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; *sigma = network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; } } /************************************************************************* This function returns information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) OUTPUT PARAMETERS: FKind - activation function type (used by MLPActivationFunction()) this value is zero for input or linear neurons Threshold - also called offset, bias zero for input neurons NOTE: this function throws exception if layer or neuron with given index do not exists. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetneuroninfo(multilayerperceptron* network, ae_int_t k, ae_int_t i, ae_int_t* fkind, double* threshold, ae_state *_state) { ae_int_t ncnt; ae_int_t istart; ae_int_t highlevelidx; ae_int_t activationoffset; *fkind = 0; *threshold = 0; ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; istart = network->structinfo.ptr.p_int[5]; /* * search */ network->integerbuf.ptr.p_int[0] = k; network->integerbuf.ptr.p_int[1] = i; highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, &network->integerbuf, _state); ae_assert(highlevelidx>=0, "MLPGetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); /* * 1. find offset of the activation function record in the */ if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) { activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; *fkind = network->structinfo.ptr.p_int[activationoffset+0]; } else { *fkind = 0; } if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) { *threshold = network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]]; } else { *threshold = (double)(0); } } /************************************************************************* This function returns information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) RESULT: connection weight (zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. returns zero if neurons exist, but there is no connection between them -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ double mlpgetweight(multilayerperceptron* network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1, ae_state *_state) { ae_int_t ccnt; ae_int_t highlevelidx; double result; ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; /* * check params */ ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K0", _state); ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPGetWeight: incorrect (nonexistent) I0", _state); ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K1", _state); ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPGetWeight: incorrect (nonexistent) I1", _state); /* * search */ network->integerbuf.ptr.p_int[0] = k0; network->integerbuf.ptr.p_int[1] = i0; network->integerbuf.ptr.p_int[2] = k1; network->integerbuf.ptr.p_int[3] = i1; highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, &network->integerbuf, _state); if( highlevelidx>=0 ) { result = network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]]; } else { result = (double)(0); } return result; } /************************************************************************* This function sets offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) NTE: I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network. This function sets Mean and Sigma. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetinputscaling(multilayerperceptron* network, ae_int_t i, double mean, double sigma, ae_state *_state) { ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPSetInputScaling: incorrect (nonexistent) I", _state); ae_assert(ae_isfinite(mean, _state), "MLPSetInputScaling: infinite or NAN Mean", _state); ae_assert(ae_isfinite(sigma, _state), "MLPSetInputScaling: infinite or NAN Sigma", _state); if( ae_fp_eq(sigma,(double)(0)) ) { sigma = (double)(1); } network->columnmeans.ptr.p_double[i] = mean; network->columnsigmas.ptr.p_double[i] = sigma; } /************************************************************************* This function sets offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) OUTPUT PARAMETERS: NOTE: I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. This function sets Sigma/Mean. In case we have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything other than(0.0,1.0) - this function will throw exception. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetoutputscaling(multilayerperceptron* network, ae_int_t i, double mean, double sigma, ae_state *_state) { ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPSetOutputScaling: incorrect (nonexistent) I", _state); ae_assert(ae_isfinite(mean, _state), "MLPSetOutputScaling: infinite or NAN Mean", _state); ae_assert(ae_isfinite(sigma, _state), "MLPSetOutputScaling: infinite or NAN Sigma", _state); if( network->structinfo.ptr.p_int[6]==1 ) { ae_assert(ae_fp_eq(mean,(double)(0)), "MLPSetOutputScaling: you can not set non-zero Mean term for classifier network", _state); ae_assert(ae_fp_eq(sigma,(double)(1)), "MLPSetOutputScaling: you can not set non-unit Sigma term for classifier network", _state); } else { if( ae_fp_eq(sigma,(double)(0)) ) { sigma = (double)(1); } network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = mean; network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = sigma; } } /************************************************************************* This function modifies information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) FKind - activation function type (used by MLPActivationFunction()) this value must be zero for input neurons (you can not set activation function for input neurons) Threshold - also called offset, bias this value must be zero for input neurons (you can not set threshold for input neurons) NOTES: 1. this function throws exception if layer or neuron with given index do not exists. 2. this function also throws exception when you try to set non-linear activation function for input neurons (any kind of network) or for output neurons of classifier network. 3. this function throws exception when you try to set non-zero threshold for input neurons (any kind of network). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetneuroninfo(multilayerperceptron* network, ae_int_t k, ae_int_t i, ae_int_t fkind, double threshold, ae_state *_state) { ae_int_t ncnt; ae_int_t istart; ae_int_t highlevelidx; ae_int_t activationoffset; ae_assert(ae_isfinite(threshold, _state), "MLPSetNeuronInfo: infinite or NAN Threshold", _state); /* * convenience vars */ ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; istart = network->structinfo.ptr.p_int[5]; /* * search */ network->integerbuf.ptr.p_int[0] = k; network->integerbuf.ptr.p_int[1] = i; highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, &network->integerbuf, _state); ae_assert(highlevelidx>=0, "MLPSetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); /* * activation function */ if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) { activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; network->structinfo.ptr.p_int[activationoffset+0] = fkind; } else { ae_assert(fkind==0, "MLPSetNeuronInfo: you try to set activation function for neuron which can not have one", _state); } /* * Threshold */ if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) { network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]] = threshold; } else { ae_assert(ae_fp_eq(threshold,(double)(0)), "MLPSetNeuronInfo: you try to set non-zero threshold for neuron which can not have one", _state); } } /************************************************************************* This function modifies information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) W - connection weight (must be zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. throws exception if you try to set non-zero weight for non-existent connection -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetweight(multilayerperceptron* network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1, double w, ae_state *_state) { ae_int_t ccnt; ae_int_t highlevelidx; ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; /* * check params */ ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K0", _state); ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPSetWeight: incorrect (nonexistent) I0", _state); ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K1", _state); ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPSetWeight: incorrect (nonexistent) I1", _state); ae_assert(ae_isfinite(w, _state), "MLPSetWeight: infinite or NAN weight", _state); /* * search */ network->integerbuf.ptr.p_int[0] = k0; network->integerbuf.ptr.p_int[1] = i0; network->integerbuf.ptr.p_int[2] = k1; network->integerbuf.ptr.p_int[3] = i1; highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, &network->integerbuf, _state); if( highlevelidx>=0 ) { network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]] = w; } else { ae_assert(ae_fp_eq(w,(double)(0)), "MLPSetWeight: you try to set non-zero weight for non-existent connection", _state); } } /************************************************************************* Neural network activation function INPUT PARAMETERS: NET - neuron input K - function index (zero for linear function) OUTPUT PARAMETERS: F - function DF - its derivative D2F - its second derivative -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpactivationfunction(double net, ae_int_t k, double* f, double* df, double* d2f, ae_state *_state) { double net2; double arg; double root; double r; *f = 0; *df = 0; *d2f = 0; if( k==0||k==-5 ) { *f = net; *df = (double)(1); *d2f = (double)(0); return; } if( k==1 ) { /* * TanH activation function */ if( ae_fp_less(ae_fabs(net, _state),(double)(100)) ) { *f = ae_tanh(net, _state); } else { *f = (double)(ae_sign(net, _state)); } *df = 1-*f*(*f); *d2f = -2*(*f)*(*df); return; } if( k==3 ) { /* * EX activation function */ if( ae_fp_greater_eq(net,(double)(0)) ) { net2 = net*net; arg = net2+1; root = ae_sqrt(arg, _state); *f = net+root; r = net/root; *df = 1+r; *d2f = (root-net*r)/arg; } else { *f = ae_exp(net, _state); *df = *f; *d2f = *f; } return; } if( k==2 ) { *f = ae_exp(-ae_sqr(net, _state), _state); *df = -2*net*(*f); *d2f = -2*(*f+*df*net); return; } *f = (double)(0); *df = (double)(0); *d2f = (double)(0); } /************************************************************************* Procesing INPUT PARAMETERS: Network - neural network X - input vector, array[0..NIn-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also MLPProcessI -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpprocess(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { if( y->cntstructinfo.ptr.p_int[2] ) { ae_vector_set_length(y, network->structinfo.ptr.p_int[2], _state); } mlpinternalprocessvector(&network->structinfo, &network->weights, &network->columnmeans, &network->columnsigmas, &network->neurons, &network->dfdnet, x, y, _state); } /************************************************************************* 'interactive' variant of MLPProcess for languages like Python which support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 21.09.2010 by Bochkanov Sergey *************************************************************************/ void mlpprocessi(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_vector_clear(y); mlpprocess(network, x, y, _state); } /************************************************************************* Error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPError: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = ae_sqr(network->err.rmserror, _state)*npoints*mlpgetoutputscount(network, _state)/2; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlperror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlperror(network,xy,npoints, _state); } /************************************************************************* Error of the neural network on dataset given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0 RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPErrorSparse: XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPErrorSparse: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparse: XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparse: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = ae_sqr(network->err.rmserror, _state)*npoints*mlpgetoutputscount(network, _state)/2; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlperrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlperrorsparse(network,xy,npoints, _state); } /************************************************************************* Natural error function for neural network, internal subroutine. NOTE: this function is single-threaded. Unlike other error function, it receives no speed-up from being executed in SMP mode. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperrorn(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t nin; ae_int_t nout; ae_int_t wcount; double e; double result; mlpproperties(network, &nin, &nout, &wcount, _state); result = (double)(0); for(i=0; i<=ssize-1; i++) { /* * Process vector */ ae_v_move(&network->x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); mlpprocess(network, &network->x, &network->y, _state); /* * Update error function */ if( network->structinfo.ptr.p_int[6]==0 ) { /* * Least squares error function */ ae_v_sub(&network->y.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1)); e = ae_v_dotproduct(&network->y.ptr.p_double[0], 1, &network->y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); result = result+e/2; } else { /* * Cross-entropy error function */ k = ae_round(xy->ptr.pp_double[i][nin], _state); if( k>=0&&ky.ptr.p_double[k], _state); } } } return result; } /************************************************************************* Classification error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: classification error (number of misclassified cases) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_int_t result; ae_assert(xy->rows>=npoints, "MLPClsError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPClsError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPClsError: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = ae_round(npoints*network->err.relclserror, _state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_int_t _pexec_mlpclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlpclserror(network,xy,npoints, _state); } /************************************************************************* Relative classification error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 25.12.2008 by Bochkanov Sergey *************************************************************************/ double mlprelclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPRelClsError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRelClsError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsError: XY has less than NIn+NOut columns", _state); } } if( npoints>0 ) { result = (double)mlpclserror(network, xy, npoints, _state)/(double)npoints; } else { result = 0.0; } return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlprelclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlprelclserror(network,xy,npoints, _state); } /************************************************************************* Relative classification error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprelclserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPRelClsErrorSparse: sparse matrix XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRelClsErrorSparse: sparse matrix XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.relclserror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlprelclserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlprelclserrorsparse(network,xy,npoints, _state); } /************************************************************************* Average cross-entropy (in bits per element) on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 08.01.2009 by Bochkanov Sergey *************************************************************************/ double mlpavgce(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPAvgCE: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgCE: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCE: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgce; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgce(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgce(network,xy,npoints, _state); } /************************************************************************* Average cross-entropy (in bits per element) on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 9.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgcesparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPAvgCESparse: sparse matrix XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgCESparse: sparse matrix XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgCESparse: sparse matrix XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCESparse: sparse matrix XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgce; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgcesparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgcesparse(network,xy,npoints, _state); } /************************************************************************* RMS error on the test set given. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlprmserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPRMSError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRMSError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSError: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.rmserror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlprmserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlprmserror(network,xy,npoints, _state); } /************************************************************************* RMS error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprmserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPRMSErrorSparse: sparse matrix XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRMSErrorSparse: sparse matrix XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRMSErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.rmserror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlprmserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlprmserrorsparse(network,xy,npoints, _state); } /************************************************************************* Average absolute error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPAvgError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgError: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgerror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgerror(network,xy,npoints, _state); } /************************************************************************* Average absolute error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPAvgErrorSparse: XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgErrorSparse: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgErrorSparse: XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgErrorSparse: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgerror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgerrorsparse(network,xy,npoints, _state); } /************************************************************************* Average relative error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(xy->rows>=npoints, "MLPAvgRelError: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgRelError: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelError: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgrelerror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgrelerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgrelerror(network,xy,npoints, _state); } /************************************************************************* Average relative error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double result; ae_assert(sparseiscrs(xy, _state), "MLPAvgRelErrorSparse: XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgRelErrorSparse: XY has less than NPoints rows", _state); if( npoints>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgRelErrorSparse: XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelErrorSparse: XY has less than NIn+NOut columns", _state); } } mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); result = network->err.avgrelerror; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlpavgrelerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { return mlpavgrelerrorsparse(network,xy,npoints, _state); } /************************************************************************* Gradient calculation INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgrad(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* desiredy, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_int_t i; ae_int_t nout; ae_int_t ntotal; *e = 0; /* * Alloc */ rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); /* * Prepare dError/dOut, internal structures */ mlpprocess(network, x, &network->y, _state); nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; *e = (double)(0); for(i=0; i<=ntotal-1; i++) { network->derror.ptr.p_double[i] = (double)(0); } for(i=0; i<=nout-1; i++) { network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/2; } /* * gradient */ mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_false, _state); } /************************************************************************* Gradient calculation (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradn(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* desiredy, double* e, /* Real */ ae_vector* grad, ae_state *_state) { double s; ae_int_t i; ae_int_t nout; ae_int_t ntotal; *e = 0; /* * Alloc */ rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); /* * Prepare dError/dOut, internal structures */ mlpprocess(network, x, &network->y, _state); nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; for(i=0; i<=ntotal-1; i++) { network->derror.ptr.p_double[i] = (double)(0); } *e = (double)(0); if( network->structinfo.ptr.p_int[6]==0 ) { /* * Regression network, least squares */ for(i=0; i<=nout-1; i++) { network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/2; } } else { /* * Classification network, cross-entropy */ s = (double)(0); for(i=0; i<=nout-1; i++) { s = s+desiredy->ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { network->derror.ptr.p_double[ntotal-nout+i] = s*network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; *e = *e+mlpbase_safecrossentropy(desiredy->ptr.p_double[i], network->y.ptr.p_double[i], _state); } } /* * gradient */ mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_true, _state); } /************************************************************************* Batch gradient calculation for a set of inputs/outputs FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t subset0; ae_int_t subset1; ae_int_t subsettype; smlpgrad *sgrad; ae_smart_ptr _sgrad; ae_frame_make(_state, &_frame_block); *e = 0; ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state); ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); subset0 = 0; subset1 = ssize; subsettype = 0; mlpproperties(network, &nin, &nout, &wcount, _state); rvectorsetlengthatleast(grad, wcount, _state); ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { sgrad->f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad->g.ptr.p_double[i] = 0.0; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } mlpgradbatchx(network, xy, &network->dummysxy, ssize, 0, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); *e = 0.0; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = 0.0; } ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { *e = *e+sgrad->f; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpgradbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { mlpgradbatch(network,xy,ssize,e,grad, _state); } /************************************************************************* Batch gradient calculation for a set of inputs/outputs given by sparse matrices FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs. * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t subset0; ae_int_t subset1; ae_int_t subsettype; smlpgrad *sgrad; ae_smart_ptr _sgrad; ae_frame_make(_state, &_frame_block); *e = 0; ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state); ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparse: sparse matrix XY must be in CRS format.", _state); subset0 = 0; subset1 = ssize; subsettype = 0; mlpproperties(network, &nin, &nout, &wcount, _state); rvectorsetlengthatleast(grad, wcount, _state); ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { sgrad->f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad->g.ptr.p_double[i] = 0.0; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } mlpgradbatchx(network, &network->dummydxy, xy, ssize, 1, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); *e = 0.0; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = 0.0; } ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { *e = *e+sgrad->f; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpgradbatchsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { mlpgradbatchsparse(network,xy,ssize,e,grad, _state); } /************************************************************************* Batch gradient calculation for a subset of dataset FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t npoints; ae_int_t subset0; ae_int_t subset1; ae_int_t subsettype; smlpgrad *sgrad; ae_smart_ptr _sgrad; ae_frame_make(_state, &_frame_block); *e = 0; ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state); ae_assert(setsize>=0, "MLPGradBatchSubset: SetSize<0", _state); ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSubset: SubsetSize>Length(Idx)", _state); npoints = setsize; if( subsetsize<0 ) { subset0 = 0; subset1 = setsize; subsettype = 0; } else { subset0 = 0; subset1 = subsetsize; subsettype = 1; for(i=0; i<=subsetsize-1; i++) { ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]<0)", _state); ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); } } mlpproperties(network, &nin, &nout, &wcount, _state); rvectorsetlengthatleast(grad, wcount, _state); ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { sgrad->f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad->g.ptr.p_double[i] = 0.0; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } mlpgradbatchx(network, xy, &network->dummysxy, setsize, 0, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); *e = 0.0; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = 0.0; } ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { *e = *e+sgrad->f; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpgradbatchsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { mlpgradbatchsubset(network,xy,setsize,idx,subsetsize,e,grad, _state); } /************************************************************************* Batch gradient calculation for a set of inputs/outputs for a subset of dataset given by set of indexes. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse function. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t npoints; ae_int_t subset0; ae_int_t subset1; ae_int_t subsettype; smlpgrad *sgrad; ae_smart_ptr _sgrad; ae_frame_make(_state, &_frame_block); *e = 0; ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state); ae_assert(setsize>=0, "MLPGradBatchSparseSubset: SetSize<0", _state); ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSparseSubset: SubsetSize>Length(Idx)", _state); ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparseSubset: sparse matrix XY must be in CRS format.", _state); npoints = setsize; if( subsetsize<0 ) { subset0 = 0; subset1 = setsize; subsettype = 0; } else { subset0 = 0; subset1 = subsetsize; subsettype = 1; for(i=0; i<=subsetsize-1; i++) { ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); } } mlpproperties(network, &nin, &nout, &wcount, _state); rvectorsetlengthatleast(grad, wcount, _state); ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { sgrad->f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad->g.ptr.p_double[i] = 0.0; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } mlpgradbatchx(network, &network->dummydxy, xy, setsize, 1, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); *e = 0.0; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = 0.0; } ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); while(sgrad!=NULL) { *e = *e+sgrad->f; for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; } ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpgradbatchsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { mlpgradbatchsparsesubset(network,xy,setsize,idx,subsetsize,e,grad, _state); } /************************************************************************* Internal function which actually calculates batch gradient for a subset or full dataset, which can be represented in different formats. THIS FUNCTION IS NOT INTENDED TO BE USED BY ALGLIB USERS! -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchx(multilayerperceptron* network, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, ae_shared_pool* gradbuf, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t rowsize; ae_int_t srcidx; ae_int_t cstart; ae_int_t csize; ae_int_t j; double problemcost; mlpbuffers *buf2; ae_smart_ptr _buf2; ae_int_t len0; ae_int_t len1; mlpbuffers *pbuf; ae_smart_ptr _pbuf; smlpgrad *sgrad; ae_smart_ptr _sgrad; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_buf2, (void**)&buf2, _state); ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state); ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state); ae_assert(datasetsize>=0, "MLPGradBatchX: SetSize<0", _state); ae_assert(datasettype==0||datasettype==1, "MLPGradBatchX: DatasetType is incorrect", _state); ae_assert(subsettype==0||subsettype==1, "MLPGradBatchX: SubsetType is incorrect", _state); /* * Determine network and dataset properties */ mlpproperties(network, &nin, &nout, &wcount, _state); if( mlpissoftmax(network, _state) ) { rowsize = nin+1; } else { rowsize = nin+nout; } /* * Split problem. * * Splitting problem allows us to reduce effect of single-precision * arithmetics (SSE-optimized version of MLPChunkedGradient uses single * precision internally, but converts them to double precision after * results are exported from HPC buffer to network). Small batches are * calculated in single precision, results are aggregated in double * precision, and it allows us to avoid accumulation of errors when * we process very large batches (tens of thousands of items). * * NOTE: it is important to use real arithmetics for ProblemCost * because ProblemCost may be larger than MAXINT. */ problemcost = (double)(subset1-subset0); problemcost = problemcost*wcount; if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(problemcost,(double)(mlpbase_gradbasecasecost)) ) { splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, gradbuf, _state); mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, gradbuf, _state); ae_frame_leave(_state); return; } /* * Chunked processing */ ae_shared_pool_retrieve(gradbuf, &_sgrad, _state); ae_shared_pool_retrieve(buf, &_pbuf, _state); hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); cstart = subset0; while(cstartchunksize, _state)-cstart; for(j=0; j<=csize-1; j++) { srcidx = -1; if( subsettype==0 ) { srcidx = cstart+j; } if( subsettype==1 ) { srcidx = idx->ptr.p_int[cstart+j]; } ae_assert(srcidx>=0, "MLPGradBatchX: internal error", _state); if( datasettype==0 ) { ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); } if( datasettype==1 ) { sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); } } /* * Process chunk and advance line pointer */ mlpbase_mlpchunkedgradient(network, &pbuf->xy, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, &sgrad->f, ae_false, _state); cstart = cstart+pbuf->chunksize; } hpcfinalizechunkedgradient(pbuf, &sgrad->g, _state); ae_shared_pool_recycle(buf, &_pbuf, _state); ae_shared_pool_recycle(gradbuf, &_sgrad, _state); ae_frame_leave(_state); } /************************************************************************* Batch gradient calculation for a set of inputs/outputs (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - set of inputs/outputs; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradnbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t nin; ae_int_t nout; ae_int_t wcount; mlpbuffers *pbuf; ae_smart_ptr _pbuf; ae_frame_make(_state, &_frame_block); *e = 0; ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state); /* * Alloc */ mlpproperties(network, &nin, &nout, &wcount, _state); ae_shared_pool_retrieve(&network->buf, &_pbuf, _state); hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); rvectorsetlengthatleast(grad, wcount, _state); for(i=0; i<=wcount-1; i++) { grad->ptr.p_double[i] = (double)(0); } *e = (double)(0); i = 0; while(i<=ssize-1) { mlpbase_mlpchunkedgradient(network, xy, i, ae_minint(ssize, i+pbuf->chunksize, _state)-i, &pbuf->batch4buf, &pbuf->hpcbuf, e, ae_true, _state); i = i+pbuf->chunksize; } hpcfinalizechunkedgradient(pbuf, grad, _state); ae_shared_pool_recycle(&network->buf, &_pbuf, _state); ae_frame_leave(_state); } /************************************************************************* Batch Hessian calculation (natural error function) using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessiannbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state) { *e = 0; mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_true, e, grad, h, _state); } /************************************************************************* Batch Hessian calculation using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessianbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state) { *e = 0; mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_false, e, grad, h, _state); } /************************************************************************* Internal subroutine, shouldn't be called by user. *************************************************************************/ void mlpinternalprocessvector(/* Integer */ ae_vector* structinfo, /* Real */ ae_vector* weights, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_vector* neurons, /* Real */ ae_vector* dfdnet, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t n1; ae_int_t n2; ae_int_t w1; ae_int_t w2; ae_int_t ntotal; ae_int_t nin; ae_int_t nout; ae_int_t istart; ae_int_t offs; double net; double f; double df; double d2f; double mx; ae_bool perr; /* * Read network geometry */ nin = structinfo->ptr.p_int[1]; nout = structinfo->ptr.p_int[2]; ntotal = structinfo->ptr.p_int[3]; istart = structinfo->ptr.p_int[5]; /* * Inputs standartisation and putting in the network */ for(i=0; i<=nin-1; i++) { if( ae_fp_neq(columnsigmas->ptr.p_double[i],(double)(0)) ) { neurons->ptr.p_double[i] = (x->ptr.p_double[i]-columnmeans->ptr.p_double[i])/columnsigmas->ptr.p_double[i]; } else { neurons->ptr.p_double[i] = x->ptr.p_double[i]-columnmeans->ptr.p_double[i]; } } /* * Process network */ for(i=0; i<=ntotal-1; i++) { offs = istart+i*mlpbase_nfieldwidth; if( structinfo->ptr.p_int[offs+0]>0||structinfo->ptr.p_int[offs+0]==-5 ) { /* * Activation function */ mlpactivationfunction(neurons->ptr.p_double[structinfo->ptr.p_int[offs+2]], structinfo->ptr.p_int[offs+0], &f, &df, &d2f, _state); neurons->ptr.p_double[i] = f; dfdnet->ptr.p_double[i] = df; continue; } if( structinfo->ptr.p_int[offs+0]==0 ) { /* * Adaptive summator */ n1 = structinfo->ptr.p_int[offs+2]; n2 = n1+structinfo->ptr.p_int[offs+1]-1; w1 = structinfo->ptr.p_int[offs+3]; w2 = w1+structinfo->ptr.p_int[offs+1]-1; net = ae_v_dotproduct(&weights->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2)); neurons->ptr.p_double[i] = net; dfdnet->ptr.p_double[i] = 1.0; touchint(&n2, _state); continue; } if( structinfo->ptr.p_int[offs+0]<0 ) { perr = ae_true; if( structinfo->ptr.p_int[offs+0]==-2 ) { /* * input neuron, left unchanged */ perr = ae_false; } if( structinfo->ptr.p_int[offs+0]==-3 ) { /* * "-1" neuron */ neurons->ptr.p_double[i] = (double)(-1); perr = ae_false; } if( structinfo->ptr.p_int[offs+0]==-4 ) { /* * "0" neuron */ neurons->ptr.p_double[i] = (double)(0); perr = ae_false; } ae_assert(!perr, "MLPInternalProcessVector: internal error - unknown neuron type!", _state); continue; } } /* * Extract result */ ae_v_move(&y->ptr.p_double[0], 1, &neurons->ptr.p_double[ntotal-nout], 1, ae_v_len(0,nout-1)); /* * Softmax post-processing or standardisation if needed */ ae_assert(structinfo->ptr.p_int[6]==0||structinfo->ptr.p_int[6]==1, "MLPInternalProcessVector: unknown normalization type!", _state); if( structinfo->ptr.p_int[6]==1 ) { /* * Softmax */ mx = y->ptr.p_double[0]; for(i=1; i<=nout-1; i++) { mx = ae_maxreal(mx, y->ptr.p_double[i], _state); } net = (double)(0); for(i=0; i<=nout-1; i++) { y->ptr.p_double[i] = ae_exp(y->ptr.p_double[i]-mx, _state); net = net+y->ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y->ptr.p_double[i] = y->ptr.p_double[i]/net; } } else { /* * Standardisation */ for(i=0; i<=nout-1; i++) { y->ptr.p_double[i] = y->ptr.p_double[i]*columnsigmas->ptr.p_double[nin+i]+columnmeans->ptr.p_double[nin+i]; } } } /************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpalloc(ae_serializer* s, multilayerperceptron* network, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t fkind; double threshold; double v0; double v1; ae_int_t nin; ae_int_t nout; nin = network->hllayersizes.ptr.p_int[0]; nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); allocintegerarray(s, &network->hllayersizes, -1, _state); for(i=1; i<=network->hllayersizes.cnt-1; i++) { for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) { mlpgetneuroninfo(network, i, j, &fkind, &threshold, _state); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) { ae_serializer_alloc_entry(s); } } } for(j=0; j<=nin-1; j++) { mlpgetinputscaling(network, j, &v0, &v1, _state); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); } for(j=0; j<=nout-1; j++) { mlpgetoutputscaling(network, j, &v0, &v1, _state); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); } } /************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpserialize(ae_serializer* s, multilayerperceptron* network, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t fkind; double threshold; double v0; double v1; ae_int_t nin; ae_int_t nout; nin = network->hllayersizes.ptr.p_int[0]; nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; ae_serializer_serialize_int(s, getmlpserializationcode(_state), _state); ae_serializer_serialize_int(s, mlpbase_mlpfirstversion, _state); ae_serializer_serialize_bool(s, mlpissoftmax(network, _state), _state); serializeintegerarray(s, &network->hllayersizes, -1, _state); for(i=1; i<=network->hllayersizes.cnt-1; i++) { for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) { mlpgetneuroninfo(network, i, j, &fkind, &threshold, _state); ae_serializer_serialize_int(s, fkind, _state); ae_serializer_serialize_double(s, threshold, _state); for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) { ae_serializer_serialize_double(s, mlpgetweight(network, i-1, k, i, j, _state), _state); } } } for(j=0; j<=nin-1; j++) { mlpgetinputscaling(network, j, &v0, &v1, _state); ae_serializer_serialize_double(s, v0, _state); ae_serializer_serialize_double(s, v1, _state); } for(j=0; j<=nout-1; j++) { mlpgetoutputscaling(network, j, &v0, &v1, _state); ae_serializer_serialize_double(s, v0, _state); ae_serializer_serialize_double(s, v1, _state); } } /************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpunserialize(ae_serializer* s, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_int_t i0; ae_int_t i1; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t fkind; double threshold; double v0; double v1; ae_int_t nin; ae_int_t nout; ae_bool issoftmax; ae_vector layersizes; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&layersizes, 0, DT_INT, _state); /* * check correctness of header */ ae_serializer_unserialize_int(s, &i0, _state); ae_assert(i0==getmlpserializationcode(_state), "MLPUnserialize: stream header corrupted", _state); ae_serializer_unserialize_int(s, &i1, _state); ae_assert(i1==mlpbase_mlpfirstversion, "MLPUnserialize: stream header corrupted", _state); /* * Create network */ ae_serializer_unserialize_bool(s, &issoftmax, _state); unserializeintegerarray(s, &layersizes, _state); ae_assert((layersizes.cnt==2||layersizes.cnt==3)||layersizes.cnt==4, "MLPUnserialize: too many hidden layers!", _state); nin = layersizes.ptr.p_int[0]; nout = layersizes.ptr.p_int[layersizes.cnt-1]; if( layersizes.cnt==2 ) { if( issoftmax ) { mlpcreatec0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); } else { mlpcreate0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); } } if( layersizes.cnt==3 ) { if( issoftmax ) { mlpcreatec1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); } else { mlpcreate1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); } } if( layersizes.cnt==4 ) { if( issoftmax ) { mlpcreatec2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); } else { mlpcreate2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); } } /* * Load neurons and weights */ for(i=1; i<=layersizes.cnt-1; i++) { for(j=0; j<=layersizes.ptr.p_int[i]-1; j++) { ae_serializer_unserialize_int(s, &fkind, _state); ae_serializer_unserialize_double(s, &threshold, _state); mlpsetneuroninfo(network, i, j, fkind, threshold, _state); for(k=0; k<=layersizes.ptr.p_int[i-1]-1; k++) { ae_serializer_unserialize_double(s, &v0, _state); mlpsetweight(network, i-1, k, i, j, v0, _state); } } } /* * Load standartizator */ for(j=0; j<=nin-1; j++) { ae_serializer_unserialize_double(s, &v0, _state); ae_serializer_unserialize_double(s, &v1, _state); mlpsetinputscaling(network, j, v0, v1, _state); } for(j=0; j<=nout-1; j++) { ae_serializer_unserialize_double(s, &v0, _state); ae_serializer_unserialize_double(s, &v1, _state); mlpsetoutputscaling(network, j, v0, v1, _state); } ae_frame_leave(_state); } /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state) { ae_int_t idx0; ae_int_t idx1; ae_int_t idxtype; _modelerrors_clear(rep); ae_assert(xy->rows>=setsize, "MLPAllErrorsSubset: XY has less than SetSize rows", _state); if( setsize>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSubset: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSubset: XY has less than NIn+NOut columns", _state); } } if( subsetsize>=0 ) { idx0 = 0; idx1 = subsetsize; idxtype = 1; } else { idx0 = 0; idx1 = setsize; idxtype = 0; } mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, rep, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpallerrorssubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state) { mlpallerrorssubset(network,xy,setsize,subset,subsetsize,rep, _state); } /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset given by sparse matrix; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state) { ae_int_t idx0; ae_int_t idx1; ae_int_t idxtype; _modelerrors_clear(rep); ae_assert(sparseiscrs(xy, _state), "MLPAllErrorsSparseSubset: XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPAllErrorsSparseSubset: XY has less than SetSize rows", _state); if( setsize>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSparseSubset: XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSparseSubset: XY has less than NIn+NOut columns", _state); } } if( subsetsize>=0 ) { idx0 = 0; idx1 = subsetsize; idxtype = 1; } else { idx0 = 0; idx1 = setsize; idxtype = 0; } mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, rep, _state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpallerrorssparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state) { mlpallerrorssparsesubset(network,xy,setsize,subset,subsetsize,rep, _state); } /************************************************************************* Error of the neural network on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state) { ae_int_t idx0; ae_int_t idx1; ae_int_t idxtype; double result; ae_assert(xy->rows>=setsize, "MLPErrorSubset: XY has less than SetSize rows", _state); if( setsize>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPErrorSubset: XY has less than NIn+1 columns", _state); } else { ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSubset: XY has less than NIn+NOut columns", _state); } } if( subsetsize>=0 ) { idx0 = 0; idx1 = subsetsize; idxtype = 1; } else { idx0 = 0; idx1 = setsize; idxtype = 0; } mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); result = ae_sqr(network->err.rmserror, _state)*(idx1-idx0)*mlpgetoutputscount(network, _state)/2; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlperrorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state) { return mlperrorsubset(network,xy,setsize,subset,subsetsize, _state); } /************************************************************************* Error of the neural network on subset of sparse dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. SetSize - real size of XY, SetSize>=0; it is used when SubsetSize<0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state) { ae_int_t idx0; ae_int_t idx1; ae_int_t idxtype; double result; ae_assert(sparseiscrs(xy, _state), "MLPErrorSparseSubset: XY is not in CRS format.", _state); ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPErrorSparseSubset: XY has less than SetSize rows", _state); if( setsize>0 ) { if( mlpissoftmax(network, _state) ) { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparseSubset: XY has less than NIn+1 columns", _state); } else { ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparseSubset: XY has less than NIn+NOut columns", _state); } } if( subsetsize>=0 ) { idx0 = 0; idx1 = subsetsize; idxtype = 1; } else { idx0 = 0; idx1 = setsize; idxtype = 0; } mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); result = ae_sqr(network->err.rmserror, _state)*(idx1-idx0)*mlpgetoutputscount(network, _state)/2; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ double _pexec_mlperrorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state) { return mlperrorsparsesubset(network,xy,setsize,subset,subsetsize, _state); } /************************************************************************* Calculation of all types of errors at once for a subset or full dataset, which can be represented in different formats. THIS INTERNAL FUNCTION IS NOT INTENDED TO BE USED BY ALGLIB USERS! -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorsx(multilayerperceptron* network, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, modelerrors* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t rowsize; ae_bool iscls; ae_int_t srcidx; ae_int_t cstart; ae_int_t csize; ae_int_t j; mlpbuffers *pbuf; ae_smart_ptr _pbuf; ae_int_t len0; ae_int_t len1; modelerrors rep0; modelerrors rep1; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state); _modelerrors_init(&rep0, _state); _modelerrors_init(&rep1, _state); ae_assert(datasetsize>=0, "MLPAllErrorsX: SetSize<0", _state); ae_assert(datasettype==0||datasettype==1, "MLPAllErrorsX: DatasetType is incorrect", _state); ae_assert(subsettype==0||subsettype==1, "MLPAllErrorsX: SubsetType is incorrect", _state); /* * Determine network properties */ mlpproperties(network, &nin, &nout, &wcount, _state); iscls = mlpissoftmax(network, _state); /* * Split problem. * * Splitting problem allows us to reduce effect of single-precision * arithmetics (SSE-optimized version of MLPChunkedProcess uses single * precision internally, but converts them to double precision after * results are exported from HPC buffer to network). Small batches are * calculated in single precision, results are aggregated in double * precision, and it allows us to avoid accumulation of errors when * we process very large batches (tens of thousands of items). * * NOTE: it is important to use real arithmetics for ProblemCost * because ProblemCost may be larger than MAXINT. */ if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(inttoreal(subset1-subset0, _state)*inttoreal(wcount, _state),(double)(mlpbase_gradbasecasecost)) ) { splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, &rep0, _state); mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, &rep1, _state); rep->relclserror = (len0*rep0.relclserror+len1*rep1.relclserror)/(len0+len1); rep->avgce = (len0*rep0.avgce+len1*rep1.avgce)/(len0+len1); rep->rmserror = ae_sqrt((len0*ae_sqr(rep0.rmserror, _state)+len1*ae_sqr(rep1.rmserror, _state))/(len0+len1), _state); rep->avgerror = (len0*rep0.avgerror+len1*rep1.avgerror)/(len0+len1); rep->avgrelerror = (len0*rep0.avgrelerror+len1*rep1.avgrelerror)/(len0+len1); ae_frame_leave(_state); return; } /* * Retrieve and prepare */ ae_shared_pool_retrieve(buf, &_pbuf, _state); if( iscls ) { rowsize = nin+1; dserrallocate(nout, &pbuf->tmp0, _state); } else { rowsize = nin+nout; dserrallocate(-nout, &pbuf->tmp0, _state); } /* * Processing */ hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); cstart = subset0; while(cstartchunksize, _state)-cstart; for(j=0; j<=csize-1; j++) { srcidx = -1; if( subsettype==0 ) { srcidx = cstart+j; } if( subsettype==1 ) { srcidx = idx->ptr.p_int[cstart+j]; } ae_assert(srcidx>=0, "MLPAllErrorsX: internal error", _state); if( datasettype==0 ) { ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); } if( datasettype==1 ) { sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); } } /* * Unpack XY and process (temporary code, to be replaced by chunked processing) */ for(j=0; j<=csize-1; j++) { ae_v_move(&pbuf->xy2.ptr.pp_double[j][0], 1, &pbuf->xy.ptr.pp_double[j][0], 1, ae_v_len(0,rowsize-1)); } mlpbase_mlpchunkedprocess(network, &pbuf->xy2, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, _state); for(j=0; j<=csize-1; j++) { ae_v_move(&pbuf->x.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][0], 1, ae_v_len(0,nin-1)); ae_v_move(&pbuf->y.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); if( iscls ) { pbuf->desiredy.ptr.p_double[0] = pbuf->xy.ptr.pp_double[j][nin]; } else { ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &pbuf->xy.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); } dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); } /* * Process chunk and advance line pointer */ cstart = cstart+pbuf->chunksize; } dserrfinish(&pbuf->tmp0, _state); rep->relclserror = pbuf->tmp0.ptr.p_double[0]; rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log((double)(2), _state); rep->rmserror = pbuf->tmp0.ptr.p_double[2]; rep->avgerror = pbuf->tmp0.ptr.p_double[3]; rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; /* * Recycle */ ae_shared_pool_recycle(buf, &_pbuf, _state); ae_frame_leave(_state); } /************************************************************************* Internal subroutine: adding new input layer to network *************************************************************************/ static void mlpbase_addinputlayer(ae_int_t ncount, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state) { lsizes->ptr.p_int[0] = ncount; ltypes->ptr.p_int[0] = -2; lconnfirst->ptr.p_int[0] = 0; lconnlast->ptr.p_int[0] = 0; *lastproc = 0; } /************************************************************************* Internal subroutine: adding new summator layer to network *************************************************************************/ static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state) { lsizes->ptr.p_int[*lastproc+1] = 1; ltypes->ptr.p_int[*lastproc+1] = -3; lconnfirst->ptr.p_int[*lastproc+1] = 0; lconnlast->ptr.p_int[*lastproc+1] = 0; lsizes->ptr.p_int[*lastproc+2] = ncount; ltypes->ptr.p_int[*lastproc+2] = 0; lconnfirst->ptr.p_int[*lastproc+2] = *lastproc; lconnlast->ptr.p_int[*lastproc+2] = *lastproc+1; *lastproc = *lastproc+2; } /************************************************************************* Internal subroutine: adding new summator layer to network *************************************************************************/ static void mlpbase_addactivationlayer(ae_int_t functype, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state) { ae_assert(functype>0||functype==-5, "AddActivationLayer: incorrect function type", _state); lsizes->ptr.p_int[*lastproc+1] = lsizes->ptr.p_int[*lastproc]; ltypes->ptr.p_int[*lastproc+1] = functype; lconnfirst->ptr.p_int[*lastproc+1] = *lastproc; lconnlast->ptr.p_int[*lastproc+1] = *lastproc; *lastproc = *lastproc+1; } /************************************************************************* Internal subroutine: adding new zero layer to network *************************************************************************/ static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t* lastproc, ae_state *_state) { lsizes->ptr.p_int[*lastproc+1] = 1; ltypes->ptr.p_int[*lastproc+1] = -4; lconnfirst->ptr.p_int[*lastproc+1] = 0; lconnlast->ptr.p_int[*lastproc+1] = 0; *lastproc = *lastproc+1; } /************************************************************************* This routine adds input layer to the high-level description of the network. It modifies Network.HLConnections and Network.HLNeurons and assumes that these arrays have enough place to store data. It accepts following parameters: Network - network ConnIdx - index of the first free entry in the HLConnections NeuroIdx - index of the first free entry in the HLNeurons StructInfoIdx- index of the first entry in the low level description of the current layer (in the StructInfo array) NIn - number of inputs It modified Network and indices. *************************************************************************/ static void mlpbase_hladdinputlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t nin, ae_state *_state) { ae_int_t i; ae_int_t offs; offs = mlpbase_hlnfieldwidth*(*neuroidx); for(i=0; i<=nin-1; i++) { network->hlneurons.ptr.p_int[offs+0] = 0; network->hlneurons.ptr.p_int[offs+1] = i; network->hlneurons.ptr.p_int[offs+2] = -1; network->hlneurons.ptr.p_int[offs+3] = -1; offs = offs+mlpbase_hlnfieldwidth; } *neuroidx = *neuroidx+nin; *structinfoidx = *structinfoidx+nin; } /************************************************************************* This routine adds output layer to the high-level description of the network. It modifies Network.HLConnections and Network.HLNeurons and assumes that these arrays have enough place to store data. It accepts following parameters: Network - network ConnIdx - index of the first free entry in the HLConnections NeuroIdx - index of the first free entry in the HLNeurons StructInfoIdx- index of the first entry in the low level description of the current layer (in the StructInfo array) WeightsIdx - index of the first entry in the Weights array which corresponds to the current layer K - current layer index NPrev - number of neurons in the previous layer NOut - number of outputs IsCls - is it classifier network? IsLinear - is it network with linear output? It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. *************************************************************************/ static void mlpbase_hladdoutputlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t* weightsidx, ae_int_t k, ae_int_t nprev, ae_int_t nout, ae_bool iscls, ae_bool islinearout, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t neurooffs; ae_int_t connoffs; ae_assert((iscls&&islinearout)||!iscls, "HLAddOutputLayer: internal error", _state); neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); connoffs = mlpbase_hlconnfieldwidth*(*connidx); if( !iscls ) { /* * Regression network */ for(i=0; i<=nout-1; i++) { network->hlneurons.ptr.p_int[neurooffs+0] = k; network->hlneurons.ptr.p_int[neurooffs+1] = i; network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+nout+i; network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; neurooffs = neurooffs+mlpbase_hlnfieldwidth; } for(i=0; i<=nprev-1; i++) { for(j=0; j<=nout-1; j++) { network->hlconnections.ptr.p_int[connoffs+0] = k-1; network->hlconnections.ptr.p_int[connoffs+1] = i; network->hlconnections.ptr.p_int[connoffs+2] = k; network->hlconnections.ptr.p_int[connoffs+3] = j; network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); connoffs = connoffs+mlpbase_hlconnfieldwidth; } } *connidx = *connidx+nprev*nout; *neuroidx = *neuroidx+nout; *structinfoidx = *structinfoidx+2*nout+1; *weightsidx = *weightsidx+nout*(nprev+1); } else { /* * Classification network */ for(i=0; i<=nout-2; i++) { network->hlneurons.ptr.p_int[neurooffs+0] = k; network->hlneurons.ptr.p_int[neurooffs+1] = i; network->hlneurons.ptr.p_int[neurooffs+2] = -1; network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; neurooffs = neurooffs+mlpbase_hlnfieldwidth; } network->hlneurons.ptr.p_int[neurooffs+0] = k; network->hlneurons.ptr.p_int[neurooffs+1] = i; network->hlneurons.ptr.p_int[neurooffs+2] = -1; network->hlneurons.ptr.p_int[neurooffs+3] = -1; for(i=0; i<=nprev-1; i++) { for(j=0; j<=nout-2; j++) { network->hlconnections.ptr.p_int[connoffs+0] = k-1; network->hlconnections.ptr.p_int[connoffs+1] = i; network->hlconnections.ptr.p_int[connoffs+2] = k; network->hlconnections.ptr.p_int[connoffs+3] = j; network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); connoffs = connoffs+mlpbase_hlconnfieldwidth; } } *connidx = *connidx+nprev*(nout-1); *neuroidx = *neuroidx+nout; *structinfoidx = *structinfoidx+nout+2; *weightsidx = *weightsidx+(nout-1)*(nprev+1); } } /************************************************************************* This routine adds hidden layer to the high-level description of the network. It modifies Network.HLConnections and Network.HLNeurons and assumes that these arrays have enough place to store data. It accepts following parameters: Network - network ConnIdx - index of the first free entry in the HLConnections NeuroIdx - index of the first free entry in the HLNeurons StructInfoIdx- index of the first entry in the low level description of the current layer (in the StructInfo array) WeightsIdx - index of the first entry in the Weights array which corresponds to the current layer K - current layer index NPrev - number of neurons in the previous layer NCur - number of neurons in the current layer It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. *************************************************************************/ static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, ae_int_t* connidx, ae_int_t* neuroidx, ae_int_t* structinfoidx, ae_int_t* weightsidx, ae_int_t k, ae_int_t nprev, ae_int_t ncur, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t neurooffs; ae_int_t connoffs; neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); connoffs = mlpbase_hlconnfieldwidth*(*connidx); for(i=0; i<=ncur-1; i++) { network->hlneurons.ptr.p_int[neurooffs+0] = k; network->hlneurons.ptr.p_int[neurooffs+1] = i; network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+ncur+i; network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; neurooffs = neurooffs+mlpbase_hlnfieldwidth; } for(i=0; i<=nprev-1; i++) { for(j=0; j<=ncur-1; j++) { network->hlconnections.ptr.p_int[connoffs+0] = k-1; network->hlconnections.ptr.p_int[connoffs+1] = i; network->hlconnections.ptr.p_int[connoffs+2] = k; network->hlconnections.ptr.p_int[connoffs+3] = j; network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); connoffs = connoffs+mlpbase_hlconnfieldwidth; } } *connidx = *connidx+nprev*ncur; *neuroidx = *neuroidx+ncur; *structinfoidx = *structinfoidx+2*ncur+1; *weightsidx = *weightsidx+ncur*(nprev+1); } /************************************************************************* This function fills high level information about network created using internal MLPCreate() function. This function does NOT examine StructInfo for low level information, it just expects that network has following structure: input neuron \ ... | input layer input neuron / "-1" neuron \ biased summator | ... | biased summator | hidden layer(s), if there are exists any activation function | ... | activation function / "-1" neuron \ biased summator | output layer: ... | biased summator | * we have NOut summators/activators for regression networks activation function | * we have only NOut-1 summators and no activators for classifiers ... | * we have "0" neuron only when we have classifier activation function | "0" neuron / -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_bool iscls, ae_bool islinearout, ae_state *_state) { ae_int_t idxweights; ae_int_t idxstruct; ae_int_t idxneuro; ae_int_t idxconn; ae_assert((iscls&&islinearout)||!iscls, "FillHighLevelInformation: internal error", _state); /* * Preparations common to all types of networks */ idxweights = 0; idxneuro = 0; idxstruct = 0; idxconn = 0; network->hlnetworktype = 0; /* * network without hidden layers */ if( nhid1==0 ) { ae_vector_set_length(&network->hllayersizes, 2, _state); network->hllayersizes.ptr.p_int[0] = nin; network->hllayersizes.ptr.p_int[1] = nout; if( !iscls ) { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*nout, _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); network->hlnormtype = 0; } else { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*(nout-1), _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); network->hlnormtype = 1; } mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nout, iscls, islinearout, _state); return; } /* * network with one hidden layers */ if( nhid2==0 ) { ae_vector_set_length(&network->hllayersizes, 3, _state); network->hllayersizes.ptr.p_int[0] = nin; network->hllayersizes.ptr.p_int[1] = nhid1; network->hllayersizes.ptr.p_int[2] = nout; if( !iscls ) { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nout), _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); network->hlnormtype = 0; } else { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*(nout-1)), _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); network->hlnormtype = 1; } mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nout, iscls, islinearout, _state); return; } /* * Two hidden layers */ ae_vector_set_length(&network->hllayersizes, 4, _state); network->hllayersizes.ptr.p_int[0] = nin; network->hllayersizes.ptr.p_int[1] = nhid1; network->hllayersizes.ptr.p_int[2] = nhid2; network->hllayersizes.ptr.p_int[3] = nout; if( !iscls ) { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*nout), _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); network->hlnormtype = 0; } else { ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*(nout-1)), _state); ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); network->hlnormtype = 1; } mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nhid2, _state); mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 3, nhid2, nout, iscls, islinearout, _state); } /************************************************************************* Internal subroutine. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ static void mlpbase_mlpcreate(ae_int_t nin, ae_int_t nout, /* Integer */ ae_vector* lsizes, /* Integer */ ae_vector* ltypes, /* Integer */ ae_vector* lconnfirst, /* Integer */ ae_vector* lconnlast, ae_int_t layerscount, ae_bool isclsnet, multilayerperceptron* network, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t ssize; ae_int_t ntotal; ae_int_t wcount; ae_int_t offs; ae_int_t nprocessed; ae_int_t wallocated; ae_vector localtemp; ae_vector lnfirst; ae_vector lnsyn; mlpbuffers buf; smlpgrad sgrad; ae_frame_make(_state, &_frame_block); _multilayerperceptron_clear(network); ae_vector_init(&localtemp, 0, DT_INT, _state); ae_vector_init(&lnfirst, 0, DT_INT, _state); ae_vector_init(&lnsyn, 0, DT_INT, _state); _mlpbuffers_init(&buf, _state); _smlpgrad_init(&sgrad, _state); /* * Check */ ae_assert(layerscount>0, "MLPCreate: wrong parameters!", _state); ae_assert(ltypes->ptr.p_int[0]==-2, "MLPCreate: wrong LTypes[0] (must be -2)!", _state); for(i=0; i<=layerscount-1; i++) { ae_assert(lsizes->ptr.p_int[i]>0, "MLPCreate: wrong LSizes!", _state); ae_assert(lconnfirst->ptr.p_int[i]>=0&&(lconnfirst->ptr.p_int[i]ptr.p_int[i]>=lconnfirst->ptr.p_int[i]&&(lconnlast->ptr.p_int[i]ptr.p_int[i]>=0||ltypes->ptr.p_int[i]==-5 ) { lnsyn.ptr.p_int[i] = 0; for(j=lconnfirst->ptr.p_int[i]; j<=lconnlast->ptr.p_int[i]; j++) { lnsyn.ptr.p_int[i] = lnsyn.ptr.p_int[i]+lsizes->ptr.p_int[j]; } } else { if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) { lnsyn.ptr.p_int[i] = 0; } } ae_assert(lnsyn.ptr.p_int[i]>=0, "MLPCreate: internal error #0!", _state); /* * Other info */ lnfirst.ptr.p_int[i] = ntotal; ntotal = ntotal+lsizes->ptr.p_int[i]; if( ltypes->ptr.p_int[i]==0 ) { wcount = wcount+lnsyn.ptr.p_int[i]*lsizes->ptr.p_int[i]; } } ssize = 7+ntotal*mlpbase_nfieldwidth; /* * Allocate */ ae_vector_set_length(&network->structinfo, ssize-1+1, _state); ae_vector_set_length(&network->weights, wcount-1+1, _state); if( isclsnet ) { ae_vector_set_length(&network->columnmeans, nin-1+1, _state); ae_vector_set_length(&network->columnsigmas, nin-1+1, _state); } else { ae_vector_set_length(&network->columnmeans, nin+nout-1+1, _state); ae_vector_set_length(&network->columnsigmas, nin+nout-1+1, _state); } ae_vector_set_length(&network->neurons, ntotal-1+1, _state); ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); ae_vector_set_length(&network->integerbuf, 3+1, _state); ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); ae_vector_set_length(&network->x, nin-1+1, _state); ae_vector_set_length(&network->y, nout-1+1, _state); ae_vector_set_length(&network->derror, ntotal-1+1, _state); /* * Fill structure: global info */ network->structinfo.ptr.p_int[0] = ssize; network->structinfo.ptr.p_int[1] = nin; network->structinfo.ptr.p_int[2] = nout; network->structinfo.ptr.p_int[3] = ntotal; network->structinfo.ptr.p_int[4] = wcount; network->structinfo.ptr.p_int[5] = 7; if( isclsnet ) { network->structinfo.ptr.p_int[6] = 1; } else { network->structinfo.ptr.p_int[6] = 0; } /* * Fill structure: neuron connections */ nprocessed = 0; wallocated = 0; for(i=0; i<=layerscount-1; i++) { for(j=0; j<=lsizes->ptr.p_int[i]-1; j++) { offs = network->structinfo.ptr.p_int[5]+nprocessed*mlpbase_nfieldwidth; network->structinfo.ptr.p_int[offs+0] = ltypes->ptr.p_int[i]; if( ltypes->ptr.p_int[i]==0 ) { /* * Adaptive summator: * * connections with weights to previous neurons */ network->structinfo.ptr.p_int[offs+1] = lnsyn.ptr.p_int[i]; network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]; network->structinfo.ptr.p_int[offs+3] = wallocated; wallocated = wallocated+lnsyn.ptr.p_int[i]; nprocessed = nprocessed+1; } if( ltypes->ptr.p_int[i]>0||ltypes->ptr.p_int[i]==-5 ) { /* * Activation layer: * * each neuron connected to one (only one) of previous neurons. * * no weights */ network->structinfo.ptr.p_int[offs+1] = 1; network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]+j; network->structinfo.ptr.p_int[offs+3] = -1; nprocessed = nprocessed+1; } if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) { nprocessed = nprocessed+1; } } } ae_assert(wallocated==wcount, "MLPCreate: internal error #1!", _state); ae_assert(nprocessed==ntotal, "MLPCreate: internal error #2!", _state); /* * Fill weights by small random values * Initialize means and sigmas */ for(i=0; i<=nin-1; i++) { network->columnmeans.ptr.p_double[i] = (double)(0); network->columnsigmas.ptr.p_double[i] = (double)(1); } if( !isclsnet ) { for(i=0; i<=nout-1; i++) { network->columnmeans.ptr.p_double[nin+i] = (double)(0); network->columnsigmas.ptr.p_double[nin+i] = (double)(1); } } mlprandomize(network, _state); /* * Seed buffers */ ae_shared_pool_set_seed(&network->buf, &buf, sizeof(buf), _mlpbuffers_init, _mlpbuffers_init_copy, _mlpbuffers_destroy, _state); ae_vector_set_length(&sgrad.g, wcount, _state); sgrad.f = 0.0; for(i=0; i<=wcount-1; i++) { sgrad.g.ptr.p_double[i] = 0.0; } ae_shared_pool_set_seed(&network->gradbuf, &sgrad, sizeof(sgrad), _smlpgrad_init, _smlpgrad_init_copy, _smlpgrad_destroy, _state); ae_frame_leave(_state); } /************************************************************************* Internal subroutine for Hessian calculation. WARNING! Unspeakable math far beyong human capabilities :) *************************************************************************/ static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_bool naturalerr, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntotal; ae_int_t istart; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t kl; ae_int_t offs; ae_int_t n1; ae_int_t n2; ae_int_t w1; ae_int_t w2; double s; double t; double v; double et; ae_bool bflag; double f; double df; double d2f; double deidyj; double mx; double q; double z; double s2; double expi; double expj; ae_vector x; ae_vector desiredy; ae_vector gt; ae_vector zeros; ae_matrix rx; ae_matrix ry; ae_matrix rdx; ae_matrix rdy; ae_frame_make(_state, &_frame_block); *e = 0; ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&desiredy, 0, DT_REAL, _state); ae_vector_init(>, 0, DT_REAL, _state); ae_vector_init(&zeros, 0, DT_REAL, _state); ae_matrix_init(&rx, 0, 0, DT_REAL, _state); ae_matrix_init(&ry, 0, 0, DT_REAL, _state); ae_matrix_init(&rdx, 0, 0, DT_REAL, _state); ae_matrix_init(&rdy, 0, 0, DT_REAL, _state); mlpproperties(network, &nin, &nout, &wcount, _state); ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Prepare */ ae_vector_set_length(&x, nin-1+1, _state); ae_vector_set_length(&desiredy, nout-1+1, _state); ae_vector_set_length(&zeros, wcount-1+1, _state); ae_vector_set_length(>, wcount-1+1, _state); ae_matrix_set_length(&rx, ntotal+nout-1+1, wcount-1+1, _state); ae_matrix_set_length(&ry, ntotal+nout-1+1, wcount-1+1, _state); ae_matrix_set_length(&rdx, ntotal+nout-1+1, wcount-1+1, _state); ae_matrix_set_length(&rdy, ntotal+nout-1+1, wcount-1+1, _state); *e = (double)(0); for(i=0; i<=wcount-1; i++) { zeros.ptr.p_double[i] = (double)(0); } ae_v_move(&grad->ptr.p_double[0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); for(i=0; i<=wcount-1; i++) { ae_v_move(&h->ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } /* * Process */ for(k=0; k<=ssize-1; k++) { /* * Process vector with MLPGradN. * Now Neurons, DFDNET and DError contains results of the last run. */ ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(network, _state) ) { /* * class labels outputs */ kl = ae_round(xy->ptr.pp_double[k][nin], _state); for(i=0; i<=nout-1; i++) { if( i==kl ) { desiredy.ptr.p_double[i] = (double)(1); } else { desiredy.ptr.p_double[i] = (double)(0); } } } else { /* * real outputs */ ae_v_move(&desiredy.ptr.p_double[0], 1, &xy->ptr.pp_double[k][nin], 1, ae_v_len(0,nout-1)); } if( naturalerr ) { mlpgradn(network, &x, &desiredy, &et, >, _state); } else { mlpgrad(network, &x, &desiredy, &et, >, _state); } /* * grad, error */ *e = *e+et; ae_v_add(&grad->ptr.p_double[0], 1, >.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); /* * Hessian. * Forward pass of the R-algorithm */ for(i=0; i<=ntotal-1; i++) { offs = istart+i*mlpbase_nfieldwidth; ae_v_move(&rx.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ae_v_move(&ry.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) { /* * Activation function */ n1 = network->structinfo.ptr.p_int[offs+2]; ae_v_move(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); v = network->dfdnet.ptr.p_double[i]; ae_v_moved(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); continue; } if( network->structinfo.ptr.p_int[offs+0]==0 ) { /* * Adaptive summator */ n1 = network->structinfo.ptr.p_int[offs+2]; n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; w1 = network->structinfo.ptr.p_int[offs+3]; w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; for(j=n1; j<=n2; j++) { v = network->weights.ptr.p_double[w1+j-n1]; ae_v_addd(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[j][0], 1, ae_v_len(0,wcount-1), v); rx.ptr.pp_double[i][w1+j-n1] = rx.ptr.pp_double[i][w1+j-n1]+network->neurons.ptr.p_double[j]; } ae_v_move(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); continue; } if( network->structinfo.ptr.p_int[offs+0]<0 ) { bflag = ae_true; if( network->structinfo.ptr.p_int[offs+0]==-2 ) { /* * input neuron, left unchanged */ bflag = ae_false; } if( network->structinfo.ptr.p_int[offs+0]==-3 ) { /* * "-1" neuron, left unchanged */ bflag = ae_false; } if( network->structinfo.ptr.p_int[offs+0]==-4 ) { /* * "0" neuron, left unchanged */ bflag = ae_false; } ae_assert(!bflag, "MLPHessianNBatch: internal error - unknown neuron type!", _state); continue; } } /* * Hessian. Backward pass of the R-algorithm. * * Stage 1. Initialize RDY */ for(i=0; i<=ntotal+nout-1; i++) { ae_v_move(&rdy.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } if( network->structinfo.ptr.p_int[6]==0 ) { /* * Standardisation. * * In context of the Hessian calculation standardisation * is considered as additional layer with weightless * activation function: * * F(NET) := Sigma*NET * * So we add one more layer to forward pass, and * make forward/backward pass through this layer. */ for(i=0; i<=nout-1; i++) { n1 = ntotal-nout+i; n2 = ntotal+i; /* * Forward pass from N1 to N2 */ ae_v_move(&rx.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); v = network->columnsigmas.ptr.p_double[nin+i]; ae_v_moved(&ry.ptr.pp_double[n2][0], 1, &rx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), v); /* * Initialization of RDY */ ae_v_move(&rdy.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); /* * Backward pass from N2 to N1: * 1. Calculate R(dE/dX). * 2. No R(dE/dWij) is needed since weight of activation neuron * is fixed to 1. So we can update R(dE/dY) for * the connected neuron (note that Vij=0, Wij=1) */ df = network->columnsigmas.ptr.p_double[nin+i]; ae_v_moved(&rdx.ptr.pp_double[n2][0], 1, &rdy.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), df); ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); } } else { /* * Softmax. * * Initialize RDY using generalized expression for ei'(yi) * (see expression (9) from p. 5 of "Fast Exact Multiplication by the Hessian"). * * When we are working with softmax network, generalized * expression for ei'(yi) is used because softmax * normalization leads to ei, which depends on all y's */ if( naturalerr ) { /* * softmax + cross-entropy. * We have: * * S = sum(exp(yk)), * ei = sum(trn)*exp(yi)/S-trn_i * * j=i: d(ei)/d(yj) = T*exp(yi)*(S-exp(yi))/S^2 * j<>i: d(ei)/d(yj) = -T*exp(yi)*exp(yj)/S^2 */ t = (double)(0); for(i=0; i<=nout-1; i++) { t = t+desiredy.ptr.p_double[i]; } mx = network->neurons.ptr.p_double[ntotal-nout]; for(i=0; i<=nout-1; i++) { mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); } s = (double)(0); for(i=0; i<=nout-1; i++) { network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); s = s+network->nwbuf.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { for(j=0; j<=nout-1; j++) { if( j==i ) { deidyj = t*network->nwbuf.ptr.p_double[i]*(s-network->nwbuf.ptr.p_double[i])/ae_sqr(s, _state); ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+i][0], 1, ae_v_len(0,wcount-1), deidyj); } else { deidyj = -t*network->nwbuf.ptr.p_double[i]*network->nwbuf.ptr.p_double[j]/ae_sqr(s, _state); ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); } } } } else { /* * For a softmax + squared error we have expression * far beyond human imagination so we don't even try * to comment on it. Just enjoy the code... * * P.S. That's why "natural error" is called "natural" - * compact beatiful expressions, fast code.... */ mx = network->neurons.ptr.p_double[ntotal-nout]; for(i=0; i<=nout-1; i++) { mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); } s = (double)(0); s2 = (double)(0); for(i=0; i<=nout-1; i++) { network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); s = s+network->nwbuf.ptr.p_double[i]; s2 = s2+ae_sqr(network->nwbuf.ptr.p_double[i], _state); } q = (double)(0); for(i=0; i<=nout-1; i++) { q = q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*network->nwbuf.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { z = -q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*s; expi = network->nwbuf.ptr.p_double[i]; for(j=0; j<=nout-1; j++) { expj = network->nwbuf.ptr.p_double[j]; if( j==i ) { deidyj = expi/ae_sqr(s, _state)*((z+expi)*(s-2*expi)/s+expi*s2/ae_sqr(s, _state)); } else { deidyj = expi*expj/ae_sqr(s, _state)*(s2/ae_sqr(s, _state)-2*z/s-(expi+expj)/s+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])-(network->y.ptr.p_double[j]-desiredy.ptr.p_double[j])); } ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); } } } } /* * Hessian. Backward pass of the R-algorithm * * Stage 2. Process. */ for(i=ntotal-1; i>=0; i--) { /* * Possible variants: * 1. Activation function * 2. Adaptive summator * 3. Special neuron */ offs = istart+i*mlpbase_nfieldwidth; if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) { n1 = network->structinfo.ptr.p_int[offs+2]; /* * First, calculate R(dE/dX). */ mlpactivationfunction(network->neurons.ptr.p_double[n1], network->structinfo.ptr.p_int[offs+0], &f, &df, &d2f, _state); v = d2f*network->derror.ptr.p_double[i]; ae_v_moved(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), df); ae_v_addd(&rdx.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); /* * No R(dE/dWij) is needed since weight of activation neuron * is fixed to 1. * * So we can update R(dE/dY) for the connected neuron. * (note that Vij=0, Wij=1) */ ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); continue; } if( network->structinfo.ptr.p_int[offs+0]==0 ) { /* * Adaptive summator */ n1 = network->structinfo.ptr.p_int[offs+2]; n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; w1 = network->structinfo.ptr.p_int[offs+3]; w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; /* * First, calculate R(dE/dX). */ ae_v_move(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); /* * Then, calculate R(dE/dWij) */ for(j=w1; j<=w2; j++) { v = network->neurons.ptr.p_double[n1+j-w1]; ae_v_addd(&h->ptr.pp_double[j][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); v = network->derror.ptr.p_double[i]; ae_v_addd(&h->ptr.pp_double[j][0], 1, &ry.ptr.pp_double[n1+j-w1][0], 1, ae_v_len(0,wcount-1), v); } /* * And finally, update R(dE/dY) for connected neurons. */ for(j=w1; j<=w2; j++) { v = network->weights.ptr.p_double[j]; ae_v_addd(&rdy.ptr.pp_double[n1+j-w1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); rdy.ptr.pp_double[n1+j-w1][j] = rdy.ptr.pp_double[n1+j-w1][j]+network->derror.ptr.p_double[i]; } continue; } if( network->structinfo.ptr.p_int[offs+0]<0 ) { bflag = ae_false; if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) { /* * Special neuron type, no back-propagation required */ bflag = ae_true; } ae_assert(bflag, "MLPHessianNBatch: unknown neuron type!", _state); continue; } } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine Network must be processed by MLPProcess on X *************************************************************************/ static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, /* Real */ ae_vector* neurons, /* Real */ ae_vector* weights, /* Real */ ae_vector* derror, /* Real */ ae_vector* grad, ae_bool naturalerrorfunc, ae_state *_state) { ae_int_t i; ae_int_t n1; ae_int_t n2; ae_int_t w1; ae_int_t w2; ae_int_t ntotal; ae_int_t istart; ae_int_t nin; ae_int_t nout; ae_int_t offs; double dedf; double dfdnet; double v; double fown; double deown; double net; double mx; ae_bool bflag; /* * Read network geometry */ nin = network->structinfo.ptr.p_int[1]; nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; /* * Pre-processing of dError/dOut: * from dError/dOut(normalized) to dError/dOut(non-normalized) */ ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPInternalCalculateGradient: unknown normalization type!", _state); if( network->structinfo.ptr.p_int[6]==1 ) { /* * Softmax */ if( !naturalerrorfunc ) { mx = network->neurons.ptr.p_double[ntotal-nout]; for(i=0; i<=nout-1; i++) { mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); } net = (double)(0); for(i=0; i<=nout-1; i++) { network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); net = net+network->nwbuf.ptr.p_double[i]; } v = ae_v_dotproduct(&network->derror.ptr.p_double[ntotal-nout], 1, &network->nwbuf.ptr.p_double[0], 1, ae_v_len(ntotal-nout,ntotal-1)); for(i=0; i<=nout-1; i++) { fown = network->nwbuf.ptr.p_double[i]; deown = network->derror.ptr.p_double[ntotal-nout+i]; network->nwbuf.ptr.p_double[nout+i] = (-v+deown*fown+deown*(net-fown))*fown/ae_sqr(net, _state); } for(i=0; i<=nout-1; i++) { network->derror.ptr.p_double[ntotal-nout+i] = network->nwbuf.ptr.p_double[nout+i]; } } } else { /* * Un-standardisation */ for(i=0; i<=nout-1; i++) { network->derror.ptr.p_double[ntotal-nout+i] = network->derror.ptr.p_double[ntotal-nout+i]*network->columnsigmas.ptr.p_double[nin+i]; } } /* * Backpropagation */ for(i=ntotal-1; i>=0; i--) { /* * Extract info */ offs = istart+i*mlpbase_nfieldwidth; if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) { /* * Activation function */ dedf = network->derror.ptr.p_double[i]; dfdnet = network->dfdnet.ptr.p_double[i]; derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]] = derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]]+dedf*dfdnet; continue; } if( network->structinfo.ptr.p_int[offs+0]==0 ) { /* * Adaptive summator */ n1 = network->structinfo.ptr.p_int[offs+2]; n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; w1 = network->structinfo.ptr.p_int[offs+3]; w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; dedf = network->derror.ptr.p_double[i]; dfdnet = 1.0; v = dedf*dfdnet; ae_v_moved(&grad->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2), v); ae_v_addd(&derror->ptr.p_double[n1], 1, &weights->ptr.p_double[w1], 1, ae_v_len(n1,n2), v); continue; } if( network->structinfo.ptr.p_int[offs+0]<0 ) { bflag = ae_false; if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) { /* * Special neuron type, no back-propagation required */ bflag = ae_true; } ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); continue; } } } static void mlpbase_mlpchunkedgradient(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, double* e, ae_bool naturalerrorfunc, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t kl; ae_int_t ntotal; ae_int_t nin; ae_int_t nout; ae_int_t offs; double f; double df; double d2f; double v; double vv; double s; double fown; double deown; ae_bool bflag; ae_int_t istart; ae_int_t entrysize; ae_int_t dfoffs; ae_int_t derroroffs; ae_int_t entryoffs; ae_int_t neuronidx; ae_int_t srcentryoffs; ae_int_t srcneuronidx; ae_int_t srcweightidx; ae_int_t neurontype; ae_int_t nweights; ae_int_t offs0; ae_int_t offs1; ae_int_t offs2; double v0; double v1; double v2; double v3; double s0; double s1; double s2; double s3; ae_int_t chunksize; chunksize = 4; ae_assert(csize<=chunksize, "MLPChunkedGradient: internal error (CSize>ChunkSize)", _state); /* * Try to use HPC core, if possible */ if( hpcchunkedgradient(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc, _state) ) { return; } /* * Read network geometry, prepare data */ nin = network->structinfo.ptr.p_int[1]; nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; entrysize = 12; dfoffs = 4; derroroffs = 8; /* * Fill Batch4Buf by zeros. * * THIS STAGE IS VERY IMPORTANT! * * We fill all components of entry - neuron values, dF/dNET, dError/dF. * It allows us to easily handle situations when CSizeptr.p_double[i] = (double)(0); } /* * Forward pass: * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],(double)(0)) ) { batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; } else { batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; } } } for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) { entryoffs = entrysize*neuronidx; offs = istart+neuronidx*mlpbase_nfieldwidth; neurontype = network->structinfo.ptr.p_int[offs+0]; if( neurontype>0||neurontype==-5 ) { /* * "activation function" neuron, which takes value of neuron SrcNeuronIdx * and applies activation function to it. * * This neuron has no weights and no tunable parameters. */ srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+0] = f; batch4buf->ptr.p_double[entryoffs+0+dfoffs] = df; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+1] = f; batch4buf->ptr.p_double[entryoffs+1+dfoffs] = df; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+2] = f; batch4buf->ptr.p_double[entryoffs+2+dfoffs] = df; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+3] = f; batch4buf->ptr.p_double[entryoffs+3+dfoffs] = df; continue; } if( neurontype==0 ) { /* * "adaptive summator" neuron, whose output is a weighted sum of inputs. * It has weights, but has no activation function. */ nweights = network->structinfo.ptr.p_int[offs+1]; srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; srcweightidx = network->structinfo.ptr.p_int[offs+3]; v0 = (double)(0); v1 = (double)(0); v2 = (double)(0); v3 = (double)(0); for(j=0; j<=nweights-1; j++) { v = network->weights.ptr.p_double[srcweightidx]; srcweightidx = srcweightidx+1; v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; srcentryoffs = srcentryoffs+entrysize; } batch4buf->ptr.p_double[entryoffs+0] = v0; batch4buf->ptr.p_double[entryoffs+1] = v1; batch4buf->ptr.p_double[entryoffs+2] = v2; batch4buf->ptr.p_double[entryoffs+3] = v3; batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(1); batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(1); batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(1); batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(1); continue; } if( neurontype<0 ) { bflag = ae_false; if( neurontype==-2 ) { /* * Input neuron, left unchanged */ bflag = ae_true; } if( neurontype==-3 ) { /* * "-1" neuron */ batch4buf->ptr.p_double[entryoffs+0] = (double)(-1); batch4buf->ptr.p_double[entryoffs+1] = (double)(-1); batch4buf->ptr.p_double[entryoffs+2] = (double)(-1); batch4buf->ptr.p_double[entryoffs+3] = (double)(-1); batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(0); bflag = ae_true; } if( neurontype==-4 ) { /* * "0" neuron */ batch4buf->ptr.p_double[entryoffs+0] = (double)(0); batch4buf->ptr.p_double[entryoffs+1] = (double)(0); batch4buf->ptr.p_double[entryoffs+2] = (double)(0); batch4buf->ptr.p_double[entryoffs+3] = (double)(0); batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(0); batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(0); bflag = ae_true; } ae_assert(bflag, "MLPChunkedGradient: internal error - unknown neuron type!", _state); continue; } } /* * Intermediate phase between forward and backward passes. * * For regression networks: * * forward pass is completely done (no additional post-processing is * needed). * * before starting backward pass, we have to calculate dError/dOut * for output neurons. We also update error at this phase. * * For classification networks: * * in addition to forward pass we apply SOFTMAX normalization to * output neurons. * * after applying normalization, we have to calculate dError/dOut, * which is calculated in two steps: * * first, we calculate derivative of error with respect to SOFTMAX * normalized outputs (normalized dError) * * then, we calculate derivative of error with respect to values * of outputs BEFORE normalization was applied to them */ ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedGradient: unknown normalization type!", _state); if( network->structinfo.ptr.p_int[6]==1 ) { /* * SOFTMAX-normalized network. * * First, calculate (V0,V1,V2,V3) - component-wise maximum * of output neurons. This vector of maximum values will be * used for normalization of outputs prior to calculating * exponentials. * * NOTE: the only purpose of this stage is to prevent overflow * during calculation of exponentials. With this stage * we make sure that all exponentials are calculated * with non-positive argument. If you load (0,0,0,0) to * (V0,V1,V2,V3), your program will continue working - * although with less robustness. */ entryoffs = entrysize*(ntotal-nout); v0 = batch4buf->ptr.p_double[entryoffs+0]; v1 = batch4buf->ptr.p_double[entryoffs+1]; v2 = batch4buf->ptr.p_double[entryoffs+2]; v3 = batch4buf->ptr.p_double[entryoffs+3]; entryoffs = entryoffs+entrysize; for(i=1; i<=nout-1; i++) { v = batch4buf->ptr.p_double[entryoffs+0]; if( v>v0 ) { v0 = v; } v = batch4buf->ptr.p_double[entryoffs+1]; if( v>v1 ) { v1 = v; } v = batch4buf->ptr.p_double[entryoffs+2]; if( v>v2 ) { v2 = v; } v = batch4buf->ptr.p_double[entryoffs+3]; if( v>v3 ) { v3 = v; } entryoffs = entryoffs+entrysize; } /* * Then, calculate exponentials and place them to part of the * array which is located past the last entry. We also * calculate sum of exponentials which will be stored past the * exponentials. */ entryoffs = entrysize*(ntotal-nout); offs0 = entrysize*ntotal; s0 = (double)(0); s1 = (double)(0); s2 = (double)(0); s3 = (double)(0); for(i=0; i<=nout-1; i++) { v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); s0 = s0+v; batch4buf->ptr.p_double[offs0+0] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); s1 = s1+v; batch4buf->ptr.p_double[offs0+1] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); s2 = s2+v; batch4buf->ptr.p_double[offs0+2] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); s3 = s3+v; batch4buf->ptr.p_double[offs0+3] = v; entryoffs = entryoffs+entrysize; offs0 = offs0+chunksize; } offs0 = entrysize*ntotal+2*nout*chunksize; batch4buf->ptr.p_double[offs0+0] = s0; batch4buf->ptr.p_double[offs0+1] = s1; batch4buf->ptr.p_double[offs0+2] = s2; batch4buf->ptr.p_double[offs0+3] = s3; /* * Now we have: * * Batch4Buf[0...EntrySize*NTotal-1] stores: * * NTotal*ChunkSize neuron output values (SOFTMAX normalization * was not applied to these values), * * NTotal*ChunkSize values of dF/dNET (derivative of neuron * output with respect to its input) * * NTotal*ChunkSize zeros in the elements which correspond to * dError/dOut (derivative of error with respect to neuron output). * * Batch4Buf[EntrySize*NTotal...EntrySize*NTotal+ChunkSize*NOut-1] - * stores exponentials of last NOut neurons. * * Batch4Buf[EntrySize*NTotal+ChunkSize*NOut-1...EntrySize*NTotal+ChunkSize*2*NOut-1] * - can be used for temporary calculations * * Batch4Buf[EntrySize*NTotal+ChunkSize*2*NOut...EntrySize*NTotal+ChunkSize*2*NOut+ChunkSize-1] * - stores sum-of-exponentials * * Block below calculates derivatives of error function with respect * to non-SOFTMAX-normalized output values of last NOut neurons. * * It is quite complicated; we do not describe algebra behind it, * but if you want you may check it yourself :) */ if( naturalerrorfunc ) { /* * Calculate derivative of error with respect to values of * output neurons PRIOR TO SOFTMAX NORMALIZATION. Because we * use natural error function (cross-entropy), we can do so * very easy. */ offs0 = entrysize*ntotal+2*nout*chunksize; for(k=0; k<=csize-1; k++) { s = batch4buf->ptr.p_double[offs0+k]; kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); offs1 = (ntotal-nout)*entrysize+derroroffs+k; offs2 = entrysize*ntotal+k; for(i=0; i<=nout-1; i++) { if( i==kl ) { v = (double)(1); } else { v = (double)(0); } vv = batch4buf->ptr.p_double[offs2]; batch4buf->ptr.p_double[offs1] = vv/s-v; *e = *e+mlpbase_safecrossentropy(v, vv/s, _state); offs1 = offs1+entrysize; offs2 = offs2+chunksize; } } } else { /* * SOFTMAX normalization makes things very difficult. * Sorry, we do not dare to describe this esoteric math * in details. */ offs0 = entrysize*ntotal+chunksize*2*nout; for(k=0; k<=csize-1; k++) { s = batch4buf->ptr.p_double[offs0+k]; kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); vv = (double)(0); offs1 = entrysize*ntotal+k; offs2 = entrysize*ntotal+nout*chunksize+k; for(i=0; i<=nout-1; i++) { fown = batch4buf->ptr.p_double[offs1]; if( i==kl ) { deown = fown/s-1; } else { deown = fown/s; } batch4buf->ptr.p_double[offs2] = deown; vv = vv+deown*fown; *e = *e+deown*deown/2; offs1 = offs1+chunksize; offs2 = offs2+chunksize; } offs1 = entrysize*ntotal+k; offs2 = entrysize*ntotal+nout*chunksize+k; for(i=0; i<=nout-1; i++) { fown = batch4buf->ptr.p_double[offs1]; deown = batch4buf->ptr.p_double[offs2]; batch4buf->ptr.p_double[(ntotal-nout+i)*entrysize+derroroffs+k] = (-vv+deown*fown+deown*(s-fown))*fown/ae_sqr(s, _state); offs1 = offs1+chunksize; offs2 = offs2+chunksize; } } } } else { /* * Regression network with sum-of-squares function. * * For each NOut of last neurons: * * calculate difference between actual and desired output * * calculate dError/dOut for this neuron (proportional to difference) * * store in in last 4 components of entry (these values are used * to start backpropagation) * * update error */ for(i=0; i<=nout-1; i++) { v0 = network->columnsigmas.ptr.p_double[nin+i]; v1 = network->columnmeans.ptr.p_double[nin+i]; entryoffs = entrysize*(ntotal-nout+i); offs0 = entryoffs; offs1 = entryoffs+derroroffs; for(j=0; j<=csize-1; j++) { v = batch4buf->ptr.p_double[offs0+j]*v0+v1-xy->ptr.pp_double[cstart+j][nin+i]; batch4buf->ptr.p_double[offs1+j] = v*v0; *e = *e+v*v/2; } } } /* * Backpropagation */ for(neuronidx=ntotal-1; neuronidx>=0; neuronidx--) { entryoffs = entrysize*neuronidx; offs = istart+neuronidx*mlpbase_nfieldwidth; neurontype = network->structinfo.ptr.p_int[offs+0]; if( neurontype>0||neurontype==-5 ) { /* * Activation function */ srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; offs0 = srcentryoffs+derroroffs; offs1 = entryoffs+derroroffs; offs2 = entryoffs+dfoffs; batch4buf->ptr.p_double[offs0+0] = batch4buf->ptr.p_double[offs0+0]+batch4buf->ptr.p_double[offs1+0]*batch4buf->ptr.p_double[offs2+0]; batch4buf->ptr.p_double[offs0+1] = batch4buf->ptr.p_double[offs0+1]+batch4buf->ptr.p_double[offs1+1]*batch4buf->ptr.p_double[offs2+1]; batch4buf->ptr.p_double[offs0+2] = batch4buf->ptr.p_double[offs0+2]+batch4buf->ptr.p_double[offs1+2]*batch4buf->ptr.p_double[offs2+2]; batch4buf->ptr.p_double[offs0+3] = batch4buf->ptr.p_double[offs0+3]+batch4buf->ptr.p_double[offs1+3]*batch4buf->ptr.p_double[offs2+3]; continue; } if( neurontype==0 ) { /* * Adaptive summator */ nweights = network->structinfo.ptr.p_int[offs+1]; srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; srcweightidx = network->structinfo.ptr.p_int[offs+3]; v0 = batch4buf->ptr.p_double[entryoffs+derroroffs+0]; v1 = batch4buf->ptr.p_double[entryoffs+derroroffs+1]; v2 = batch4buf->ptr.p_double[entryoffs+derroroffs+2]; v3 = batch4buf->ptr.p_double[entryoffs+derroroffs+3]; for(j=0; j<=nweights-1; j++) { offs0 = srcentryoffs; offs1 = srcentryoffs+derroroffs; v = network->weights.ptr.p_double[srcweightidx]; hpcbuf->ptr.p_double[srcweightidx] = hpcbuf->ptr.p_double[srcweightidx]+batch4buf->ptr.p_double[offs0+0]*v0+batch4buf->ptr.p_double[offs0+1]*v1+batch4buf->ptr.p_double[offs0+2]*v2+batch4buf->ptr.p_double[offs0+3]*v3; batch4buf->ptr.p_double[offs1+0] = batch4buf->ptr.p_double[offs1+0]+v*v0; batch4buf->ptr.p_double[offs1+1] = batch4buf->ptr.p_double[offs1+1]+v*v1; batch4buf->ptr.p_double[offs1+2] = batch4buf->ptr.p_double[offs1+2]+v*v2; batch4buf->ptr.p_double[offs1+3] = batch4buf->ptr.p_double[offs1+3]+v*v3; srcentryoffs = srcentryoffs+entrysize; srcweightidx = srcweightidx+1; } continue; } if( neurontype<0 ) { bflag = ae_false; if( (neurontype==-2||neurontype==-3)||neurontype==-4 ) { /* * Special neuron type, no back-propagation required */ bflag = ae_true; } ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); continue; } } } static void mlpbase_mlpchunkedprocess(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t cstart, ae_int_t csize, /* Real */ ae_vector* batch4buf, /* Real */ ae_vector* hpcbuf, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t ntotal; ae_int_t nin; ae_int_t nout; ae_int_t offs; double f; double df; double d2f; double v; ae_bool bflag; ae_int_t istart; ae_int_t entrysize; ae_int_t entryoffs; ae_int_t neuronidx; ae_int_t srcentryoffs; ae_int_t srcneuronidx; ae_int_t srcweightidx; ae_int_t neurontype; ae_int_t nweights; ae_int_t offs0; double v0; double v1; double v2; double v3; double s0; double s1; double s2; double s3; ae_int_t chunksize; chunksize = 4; ae_assert(csize<=chunksize, "MLPChunkedProcess: internal error (CSize>ChunkSize)", _state); /* * Try to use HPC core, if possible */ if( hpcchunkedprocess(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, _state) ) { return; } /* * Read network geometry, prepare data */ nin = network->structinfo.ptr.p_int[1]; nout = network->structinfo.ptr.p_int[2]; ntotal = network->structinfo.ptr.p_int[3]; istart = network->structinfo.ptr.p_int[5]; entrysize = 4; /* * Fill Batch4Buf by zeros. * * THIS STAGE IS VERY IMPORTANT! * * We fill all components of entry - neuron values, dF/dNET, dError/dF. * It allows us to easily handle situations when CSizeptr.p_double[i] = (double)(0); } /* * Forward pass: * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],(double)(0)) ) { batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; } else { batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; } } } for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) { entryoffs = entrysize*neuronidx; offs = istart+neuronidx*mlpbase_nfieldwidth; neurontype = network->structinfo.ptr.p_int[offs+0]; if( neurontype>0||neurontype==-5 ) { /* * "activation function" neuron, which takes value of neuron SrcNeuronIdx * and applies activation function to it. * * This neuron has no weights and no tunable parameters. */ srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+0] = f; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+1] = f; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+2] = f; mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); batch4buf->ptr.p_double[entryoffs+3] = f; continue; } if( neurontype==0 ) { /* * "adaptive summator" neuron, whose output is a weighted sum of inputs. * It has weights, but has no activation function. */ nweights = network->structinfo.ptr.p_int[offs+1]; srcneuronidx = network->structinfo.ptr.p_int[offs+2]; srcentryoffs = entrysize*srcneuronidx; srcweightidx = network->structinfo.ptr.p_int[offs+3]; v0 = (double)(0); v1 = (double)(0); v2 = (double)(0); v3 = (double)(0); for(j=0; j<=nweights-1; j++) { v = network->weights.ptr.p_double[srcweightidx]; srcweightidx = srcweightidx+1; v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; srcentryoffs = srcentryoffs+entrysize; } batch4buf->ptr.p_double[entryoffs+0] = v0; batch4buf->ptr.p_double[entryoffs+1] = v1; batch4buf->ptr.p_double[entryoffs+2] = v2; batch4buf->ptr.p_double[entryoffs+3] = v3; continue; } if( neurontype<0 ) { bflag = ae_false; if( neurontype==-2 ) { /* * Input neuron, left unchanged */ bflag = ae_true; } if( neurontype==-3 ) { /* * "-1" neuron */ batch4buf->ptr.p_double[entryoffs+0] = (double)(-1); batch4buf->ptr.p_double[entryoffs+1] = (double)(-1); batch4buf->ptr.p_double[entryoffs+2] = (double)(-1); batch4buf->ptr.p_double[entryoffs+3] = (double)(-1); bflag = ae_true; } if( neurontype==-4 ) { /* * "0" neuron */ batch4buf->ptr.p_double[entryoffs+0] = (double)(0); batch4buf->ptr.p_double[entryoffs+1] = (double)(0); batch4buf->ptr.p_double[entryoffs+2] = (double)(0); batch4buf->ptr.p_double[entryoffs+3] = (double)(0); bflag = ae_true; } ae_assert(bflag, "MLPChunkedProcess: internal error - unknown neuron type!", _state); continue; } } /* * SOFTMAX normalization or scaling. */ ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedProcess: unknown normalization type!", _state); if( network->structinfo.ptr.p_int[6]==1 ) { /* * SOFTMAX-normalized network. * * First, calculate (V0,V1,V2,V3) - component-wise maximum * of output neurons. This vector of maximum values will be * used for normalization of outputs prior to calculating * exponentials. * * NOTE: the only purpose of this stage is to prevent overflow * during calculation of exponentials. With this stage * we make sure that all exponentials are calculated * with non-positive argument. If you load (0,0,0,0) to * (V0,V1,V2,V3), your program will continue working - * although with less robustness. */ entryoffs = entrysize*(ntotal-nout); v0 = batch4buf->ptr.p_double[entryoffs+0]; v1 = batch4buf->ptr.p_double[entryoffs+1]; v2 = batch4buf->ptr.p_double[entryoffs+2]; v3 = batch4buf->ptr.p_double[entryoffs+3]; entryoffs = entryoffs+entrysize; for(i=1; i<=nout-1; i++) { v = batch4buf->ptr.p_double[entryoffs+0]; if( v>v0 ) { v0 = v; } v = batch4buf->ptr.p_double[entryoffs+1]; if( v>v1 ) { v1 = v; } v = batch4buf->ptr.p_double[entryoffs+2]; if( v>v2 ) { v2 = v; } v = batch4buf->ptr.p_double[entryoffs+3]; if( v>v3 ) { v3 = v; } entryoffs = entryoffs+entrysize; } /* * Then, calculate exponentials and place them to part of the * array which is located past the last entry. We also * calculate sum of exponentials. */ entryoffs = entrysize*(ntotal-nout); offs0 = entrysize*ntotal; s0 = (double)(0); s1 = (double)(0); s2 = (double)(0); s3 = (double)(0); for(i=0; i<=nout-1; i++) { v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); s0 = s0+v; batch4buf->ptr.p_double[offs0+0] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); s1 = s1+v; batch4buf->ptr.p_double[offs0+1] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); s2 = s2+v; batch4buf->ptr.p_double[offs0+2] = v; v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); s3 = s3+v; batch4buf->ptr.p_double[offs0+3] = v; entryoffs = entryoffs+entrysize; offs0 = offs0+chunksize; } /* * Write SOFTMAX-normalized values to the output array. */ offs0 = entrysize*ntotal; for(i=0; i<=nout-1; i++) { if( csize>0 ) { xy->ptr.pp_double[cstart+0][nin+i] = batch4buf->ptr.p_double[offs0+0]/s0; } if( csize>1 ) { xy->ptr.pp_double[cstart+1][nin+i] = batch4buf->ptr.p_double[offs0+1]/s1; } if( csize>2 ) { xy->ptr.pp_double[cstart+2][nin+i] = batch4buf->ptr.p_double[offs0+2]/s2; } if( csize>3 ) { xy->ptr.pp_double[cstart+3][nin+i] = batch4buf->ptr.p_double[offs0+3]/s3; } offs0 = offs0+chunksize; } } else { /* * Regression network with sum-of-squares function. * * For each NOut of last neurons: * * calculate difference between actual and desired output * * calculate dError/dOut for this neuron (proportional to difference) * * store in in last 4 components of entry (these values are used * to start backpropagation) * * update error */ for(i=0; i<=nout-1; i++) { v0 = network->columnsigmas.ptr.p_double[nin+i]; v1 = network->columnmeans.ptr.p_double[nin+i]; entryoffs = entrysize*(ntotal-nout+i); for(j=0; j<=csize-1; j++) { xy->ptr.pp_double[cstart+j][nin+i] = batch4buf->ptr.p_double[entryoffs+j]*v0+v1; } } } } /************************************************************************* Returns T*Ln(T/Z), guarded against overflow/underflow. Internal subroutine. *************************************************************************/ static double mlpbase_safecrossentropy(double t, double z, ae_state *_state) { double r; double result; if( ae_fp_eq(t,(double)(0)) ) { result = (double)(0); } else { if( ae_fp_greater(ae_fabs(z, _state),(double)(1)) ) { /* * Shouldn't be the case with softmax, * but we just want to be sure. */ if( ae_fp_eq(t/z,(double)(0)) ) { r = ae_minrealnumber; } else { r = t/z; } } else { /* * Normal case */ if( ae_fp_eq(z,(double)(0))||ae_fp_greater_eq(ae_fabs(t, _state),ae_maxrealnumber*ae_fabs(z, _state)) ) { r = ae_maxrealnumber; } else { r = t/z; } } result = t*ae_log(r, _state); } return result; } /************************************************************************* This function performs backward pass of neural network randimization: * it assumes that Network.Weights stores standard deviation of weights (weights are not generated yet, only their deviations are present) * it sets deviations of weights which feed NeuronIdx-th neuron to specified value * it recursively passes to deeper neuron and modifies their weights * it stops after encountering nonlinear neurons, linear activation function, input neurons, "0" and "-1" neurons -- ALGLIB -- Copyright 27.06.2013 by Bochkanov Sergey *************************************************************************/ static void mlpbase_randomizebackwardpass(multilayerperceptron* network, ae_int_t neuronidx, double v, ae_state *_state) { ae_int_t istart; ae_int_t neurontype; ae_int_t n1; ae_int_t n2; ae_int_t w1; ae_int_t w2; ae_int_t offs; ae_int_t i; istart = network->structinfo.ptr.p_int[5]; neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; if( neurontype==-2 ) { /* * Input neuron - stop */ return; } if( neurontype==-3 ) { /* * "-1" neuron: stop */ return; } if( neurontype==-4 ) { /* * "0" neuron: stop */ return; } if( neurontype==0 ) { /* * Adaptive summator neuron: * * modify deviations of its weights * * recursively call this function for its inputs */ offs = istart+neuronidx*mlpbase_nfieldwidth; n1 = network->structinfo.ptr.p_int[offs+2]; n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; w1 = network->structinfo.ptr.p_int[offs+3]; w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; for(i=w1; i<=w2; i++) { network->weights.ptr.p_double[i] = v; } for(i=n1; i<=n2; i++) { mlpbase_randomizebackwardpass(network, i, v, _state); } return; } if( neurontype==-5 ) { /* * Linear activation function: stop */ return; } if( neurontype>0 ) { /* * Nonlinear activation function: stop */ return; } ae_assert(ae_false, "RandomizeBackwardPass: unexpected neuron type", _state); } void _modelerrors_init(void* _p, ae_state *_state) { modelerrors *p = (modelerrors*)_p; ae_touch_ptr((void*)p); } void _modelerrors_init_copy(void* _dst, void* _src, ae_state *_state) { modelerrors *dst = (modelerrors*)_dst; modelerrors *src = (modelerrors*)_src; dst->relclserror = src->relclserror; dst->avgce = src->avgce; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; } void _modelerrors_clear(void* _p) { modelerrors *p = (modelerrors*)_p; ae_touch_ptr((void*)p); } void _modelerrors_destroy(void* _p) { modelerrors *p = (modelerrors*)_p; ae_touch_ptr((void*)p); } void _smlpgrad_init(void* _p, ae_state *_state) { smlpgrad *p = (smlpgrad*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->g, 0, DT_REAL, _state); } void _smlpgrad_init_copy(void* _dst, void* _src, ae_state *_state) { smlpgrad *dst = (smlpgrad*)_dst; smlpgrad *src = (smlpgrad*)_src; dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); } void _smlpgrad_clear(void* _p) { smlpgrad *p = (smlpgrad*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->g); } void _smlpgrad_destroy(void* _p) { smlpgrad *p = (smlpgrad*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->g); } void _multilayerperceptron_init(void* _p, ae_state *_state) { multilayerperceptron *p = (multilayerperceptron*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->hllayersizes, 0, DT_INT, _state); ae_vector_init(&p->hlconnections, 0, DT_INT, _state); ae_vector_init(&p->hlneurons, 0, DT_INT, _state); ae_vector_init(&p->structinfo, 0, DT_INT, _state); ae_vector_init(&p->weights, 0, DT_REAL, _state); ae_vector_init(&p->columnmeans, 0, DT_REAL, _state); ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state); ae_vector_init(&p->neurons, 0, DT_REAL, _state); ae_vector_init(&p->dfdnet, 0, DT_REAL, _state); ae_vector_init(&p->derror, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state); ae_vector_init(&p->xyrow, 0, DT_REAL, _state); ae_vector_init(&p->nwbuf, 0, DT_REAL, _state); ae_vector_init(&p->integerbuf, 0, DT_INT, _state); _modelerrors_init(&p->err, _state); ae_vector_init(&p->rndbuf, 0, DT_REAL, _state); ae_shared_pool_init(&p->buf, _state); ae_shared_pool_init(&p->gradbuf, _state); ae_matrix_init(&p->dummydxy, 0, 0, DT_REAL, _state); _sparsematrix_init(&p->dummysxy, _state); ae_vector_init(&p->dummyidx, 0, DT_INT, _state); ae_shared_pool_init(&p->dummypool, _state); } void _multilayerperceptron_init_copy(void* _dst, void* _src, ae_state *_state) { multilayerperceptron *dst = (multilayerperceptron*)_dst; multilayerperceptron *src = (multilayerperceptron*)_src; dst->hlnetworktype = src->hlnetworktype; dst->hlnormtype = src->hlnormtype; ae_vector_init_copy(&dst->hllayersizes, &src->hllayersizes, _state); ae_vector_init_copy(&dst->hlconnections, &src->hlconnections, _state); ae_vector_init_copy(&dst->hlneurons, &src->hlneurons, _state); ae_vector_init_copy(&dst->structinfo, &src->structinfo, _state); ae_vector_init_copy(&dst->weights, &src->weights, _state); ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state); ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state); ae_vector_init_copy(&dst->neurons, &src->neurons, _state); ae_vector_init_copy(&dst->dfdnet, &src->dfdnet, _state); ae_vector_init_copy(&dst->derror, &src->derror, _state); ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->y, &src->y, _state); ae_matrix_init_copy(&dst->xy, &src->xy, _state); ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state); ae_vector_init_copy(&dst->nwbuf, &src->nwbuf, _state); ae_vector_init_copy(&dst->integerbuf, &src->integerbuf, _state); _modelerrors_init_copy(&dst->err, &src->err, _state); ae_vector_init_copy(&dst->rndbuf, &src->rndbuf, _state); ae_shared_pool_init_copy(&dst->buf, &src->buf, _state); ae_shared_pool_init_copy(&dst->gradbuf, &src->gradbuf, _state); ae_matrix_init_copy(&dst->dummydxy, &src->dummydxy, _state); _sparsematrix_init_copy(&dst->dummysxy, &src->dummysxy, _state); ae_vector_init_copy(&dst->dummyidx, &src->dummyidx, _state); ae_shared_pool_init_copy(&dst->dummypool, &src->dummypool, _state); } void _multilayerperceptron_clear(void* _p) { multilayerperceptron *p = (multilayerperceptron*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->hllayersizes); ae_vector_clear(&p->hlconnections); ae_vector_clear(&p->hlneurons); ae_vector_clear(&p->structinfo); ae_vector_clear(&p->weights); ae_vector_clear(&p->columnmeans); ae_vector_clear(&p->columnsigmas); ae_vector_clear(&p->neurons); ae_vector_clear(&p->dfdnet); ae_vector_clear(&p->derror); ae_vector_clear(&p->x); ae_vector_clear(&p->y); ae_matrix_clear(&p->xy); ae_vector_clear(&p->xyrow); ae_vector_clear(&p->nwbuf); ae_vector_clear(&p->integerbuf); _modelerrors_clear(&p->err); ae_vector_clear(&p->rndbuf); ae_shared_pool_clear(&p->buf); ae_shared_pool_clear(&p->gradbuf); ae_matrix_clear(&p->dummydxy); _sparsematrix_clear(&p->dummysxy); ae_vector_clear(&p->dummyidx); ae_shared_pool_clear(&p->dummypool); } void _multilayerperceptron_destroy(void* _p) { multilayerperceptron *p = (multilayerperceptron*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->hllayersizes); ae_vector_destroy(&p->hlconnections); ae_vector_destroy(&p->hlneurons); ae_vector_destroy(&p->structinfo); ae_vector_destroy(&p->weights); ae_vector_destroy(&p->columnmeans); ae_vector_destroy(&p->columnsigmas); ae_vector_destroy(&p->neurons); ae_vector_destroy(&p->dfdnet); ae_vector_destroy(&p->derror); ae_vector_destroy(&p->x); ae_vector_destroy(&p->y); ae_matrix_destroy(&p->xy); ae_vector_destroy(&p->xyrow); ae_vector_destroy(&p->nwbuf); ae_vector_destroy(&p->integerbuf); _modelerrors_destroy(&p->err); ae_vector_destroy(&p->rndbuf); ae_shared_pool_destroy(&p->buf); ae_shared_pool_destroy(&p->gradbuf); ae_matrix_destroy(&p->dummydxy); _sparsematrix_destroy(&p->dummysxy); ae_vector_destroy(&p->dummyidx); ae_shared_pool_destroy(&p->dummypool); } /************************************************************************* This subroutine trains logit model. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars] First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPointsptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) { *info = -2; ae_frame_leave(_state); return; } } *info = 1; /* * Initialize data */ rep->ngrad = 0; rep->nhess = 0; /* * Allocate array */ offs = 5; ssize = 5+(nvars+1)*(nclasses-1)+nclasses; ae_vector_set_length(&lm->w, ssize-1+1, _state); lm->w.ptr.p_double[0] = (double)(ssize); lm->w.ptr.p_double[1] = (double)(logit_logitvnum); lm->w.ptr.p_double[2] = (double)(nvars); lm->w.ptr.p_double[3] = (double)(nclasses); lm->w.ptr.p_double[4] = (double)(offs); /* * Degenerate case: all outputs are equal */ allsame = ae_true; for(i=1; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nvars], _state)!=ae_round(xy->ptr.pp_double[i-1][nvars], _state) ) { allsame = ae_false; } } if( allsame ) { for(i=0; i<=(nvars+1)*(nclasses-1)-1; i++) { lm->w.ptr.p_double[offs+i] = (double)(0); } v = -2*ae_log(ae_minrealnumber, _state); k = ae_round(xy->ptr.pp_double[0][nvars], _state); if( k==nclasses-1 ) { for(i=0; i<=nclasses-2; i++) { lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = -v; } } else { for(i=0; i<=nclasses-2; i++) { if( i==k ) { lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = v; } else { lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = (double)(0); } } } ae_frame_leave(_state); return; } /* * General case. * Prepare task and network. Allocate space. */ mlpcreatec0(nvars, nclasses, &network, _state); mlpinitpreprocessor(&network, xy, npoints, _state); mlpproperties(&network, &nin, &nout, &wcount, _state); for(i=0; i<=wcount-1; i++) { network.weights.ptr.p_double[i] = (2*ae_randomreal(_state)-1)/nvars; } ae_vector_set_length(&g, wcount-1+1, _state); ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); ae_vector_set_length(&wbase, wcount-1+1, _state); ae_vector_set_length(&wdir, wcount-1+1, _state); ae_vector_set_length(&work, wcount-1+1, _state); /* * First stage: optimize in gradient direction. */ for(k=0; k<=wcount/3+10; k++) { /* * Calculate gradient in starting point */ mlpgradnbatch(&network, xy, npoints, &e, &g, _state); v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); rep->ngrad = rep->ngrad+1; /* * Setup optimization scheme */ ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); wstep = ae_sqrt(v, _state); v = 1/ae_sqrt(v, _state); ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); mcstage = 0; logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); while(mcstage!=0) { mlpgradnbatch(&network, xy, npoints, &e, &g, _state); v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); rep->ngrad = rep->ngrad+1; logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); } } /* * Second stage: use Hessian when we are close to the minimum */ for(;;) { /* * Calculate and update E/G/H */ mlphessiannbatch(&network, xy, npoints, &e, &g, &h, _state); v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); for(k=0; k<=wcount-1; k++) { h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; } rep->nhess = rep->nhess+1; /* * Select step direction * NOTE: it is important to use lower-triangle Cholesky * factorization since it is much faster than higher-triangle version. */ spd = spdmatrixcholesky(&h, wcount, ae_false, _state); spdmatrixcholeskysolve(&h, wcount, ae_false, &g, &solverinfo, &solverrep, &wdir, _state); spd = solverinfo>0; if( spd ) { /* * H is positive definite. * Step in Newton direction. */ ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1); spd = ae_true; } else { /* * H is indefinite. * Step in gradient direction. */ ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); spd = ae_false; } /* * Optimize in WDir direction */ v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); wstep = ae_sqrt(v, _state); v = 1/ae_sqrt(v, _state); ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); mcstage = 0; logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); while(mcstage!=0) { mlpgradnbatch(&network, xy, npoints, &e, &g, _state); v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); rep->ngrad = rep->ngrad+1; logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); } if( spd&&((mcinfo==2||mcinfo==4)||mcinfo==6) ) { break; } } /* * Convert from NN format to MNL format */ ae_v_move(&lm->w.ptr.p_double[offs], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); for(k=0; k<=nvars-1; k++) { for(i=0; i<=nclasses-2; i++) { s = network.columnsigmas.ptr.p_double[k]; if( ae_fp_eq(s,(double)(0)) ) { s = (double)(1); } j = offs+(nvars+1)*i; v = lm->w.ptr.p_double[j+k]; lm->w.ptr.p_double[j+k] = v/s; lm->w.ptr.p_double[j+nvars] = lm->w.ptr.p_double[j+nvars]+v*network.columnmeans.ptr.p_double[k]/s; } } for(k=0; k<=nclasses-2; k++) { lm->w.ptr.p_double[offs+(nvars+1)*k+nvars] = -lm->w.ptr.p_double[offs+(nvars+1)*k+nvars]; } ae_frame_leave(_state); } /************************************************************************* Procesing INPUT PARAMETERS: LM - logit model, passed by non-constant reference (some fields of structure are used as temporaries when calculating model output). X - input vector, array[0..NVars-1]. Y - (possibly) preallocated buffer; if size of Y is less than NClasses, it will be reallocated.If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result, array[0..NClasses-1] Vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlprocess(logitmodel* lm, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t nvars; ae_int_t nclasses; ae_int_t offs; ae_int_t i; ae_int_t i1; double s; ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLProcess: unexpected model version", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); nclasses = ae_round(lm->w.ptr.p_double[3], _state); offs = ae_round(lm->w.ptr.p_double[4], _state); logit_mnliexp(&lm->w, x, _state); s = (double)(0); i1 = offs+(nvars+1)*(nclasses-1); for(i=i1; i<=i1+nclasses-1; i++) { s = s+lm->w.ptr.p_double[i]; } if( y->cntptr.p_double[i] = lm->w.ptr.p_double[i1+i]/s; } } /************************************************************************* 'interactive' variant of MNLProcess for languages like Python which support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlprocessi(logitmodel* lm, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_vector_clear(y); mnlprocess(lm, x, y, _state); } /************************************************************************* Unpacks coefficients of logit model. Logit model have form: P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when iw.ptr.p_double[1],(double)(logit_logitvnum)), "MNLUnpack: unexpected model version", _state); *nvars = ae_round(lm->w.ptr.p_double[2], _state); *nclasses = ae_round(lm->w.ptr.p_double[3], _state); offs = ae_round(lm->w.ptr.p_double[4], _state); ae_matrix_set_length(a, *nclasses-2+1, *nvars+1, _state); for(i=0; i<=*nclasses-2; i++) { ae_v_move(&a->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs+i*(*nvars+1)], 1, ae_v_len(0,*nvars)); } } /************************************************************************* "Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack reversed). INPUT PARAMETERS: A - model (see MNLUnpack) NVars - number of independent variables NClasses - number of classes OUTPUT PARAMETERS: LM - logit model. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ void mnlpack(/* Real */ ae_matrix* a, ae_int_t nvars, ae_int_t nclasses, logitmodel* lm, ae_state *_state) { ae_int_t offs; ae_int_t i; ae_int_t ssize; _logitmodel_clear(lm); offs = 5; ssize = 5+(nvars+1)*(nclasses-1)+nclasses; ae_vector_set_length(&lm->w, ssize-1+1, _state); lm->w.ptr.p_double[0] = (double)(ssize); lm->w.ptr.p_double[1] = (double)(logit_logitvnum); lm->w.ptr.p_double[2] = (double)(nvars); lm->w.ptr.p_double[3] = (double)(nclasses); lm->w.ptr.p_double[4] = (double)(offs); for(i=0; i<=nclasses-2; i++) { ae_v_move(&lm->w.ptr.p_double[offs+i*(nvars+1)], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars)); } } /************************************************************************* Copying of LogitModel strucure INPUT PARAMETERS: LM1 - original OUTPUT PARAMETERS: LM2 - copy -- ALGLIB -- Copyright 15.03.2009 by Bochkanov Sergey *************************************************************************/ void mnlcopy(logitmodel* lm1, logitmodel* lm2, ae_state *_state) { ae_int_t k; _logitmodel_clear(lm2); k = ae_round(lm1->w.ptr.p_double[0], _state); ae_vector_set_length(&lm2->w, k-1+1, _state); ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*ln(2)). -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgce(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_int_t nvars; ae_int_t nclasses; ae_int_t i; ae_vector workx; ae_vector worky; double result; ae_frame_make(_state, &_frame_block); ae_vector_init(&workx, 0, DT_REAL, _state); ae_vector_init(&worky, 0, DT_REAL, _state); ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLClsError: unexpected model version", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); nclasses = ae_round(lm->w.ptr.p_double[3], _state); ae_vector_set_length(&workx, nvars-1+1, _state); ae_vector_set_length(&worky, nclasses-1+1, _state); result = (double)(0); for(i=0; i<=npoints-1; i++) { ae_assert(ae_round(xy->ptr.pp_double[i][nvars], _state)>=0&&ae_round(xy->ptr.pp_double[i][nvars], _state)ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); mnlprocess(lm, &workx, &worky, _state); if( ae_fp_greater(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)],(double)(0)) ) { result = result-ae_log(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)], _state); } else { result = result-ae_log(ae_minrealnumber, _state); } } result = result/(npoints*ae_log((double)(2), _state)); ae_frame_leave(_state); return result; } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ double mnlrelclserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double result; result = (double)mnlclserror(lm, xy, npoints, _state)/(double)npoints; return result; } /************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: root mean square error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlrmserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double relcls; double avgce; double rms; double avg; double avgrel; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); result = rms; return result; } /************************************************************************* Average error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgerror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { double relcls; double avgce; double rms; double avg; double avgrel; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); result = avg; return result; } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average relative error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ double mnlavgrelerror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state) { double relcls; double avgce; double rms; double avg; double avgrel; double result; ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); logit_mnlallerrors(lm, xy, ssize, &relcls, &avgce, &rms, &avg, &avgrel, _state); result = avgrel; return result; } /************************************************************************* Classification error on test set = MNLRelClsError*NPoints -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/ ae_int_t mnlclserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; ae_int_t nvars; ae_int_t nclasses; ae_int_t i; ae_int_t j; ae_vector workx; ae_vector worky; ae_int_t nmax; ae_int_t result; ae_frame_make(_state, &_frame_block); ae_vector_init(&workx, 0, DT_REAL, _state); ae_vector_init(&worky, 0, DT_REAL, _state); ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLClsError: unexpected model version", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); nclasses = ae_round(lm->w.ptr.p_double[3], _state); ae_vector_set_length(&workx, nvars-1+1, _state); ae_vector_set_length(&worky, nclasses-1+1, _state); result = 0; for(i=0; i<=npoints-1; i++) { /* * Process */ ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); mnlprocess(lm, &workx, &worky, _state); /* * Logit version of the answer */ nmax = 0; for(j=0; j<=nclasses-1; j++) { if( ae_fp_greater(worky.ptr.p_double[j],worky.ptr.p_double[nmax]) ) { nmax = j; } } /* * compare */ if( nmax!=ae_round(xy->ptr.pp_double[i][nvars], _state) ) { result = result+1; } } ae_frame_leave(_state); return result; } /************************************************************************* Internal subroutine. Places exponents of the anti-overflow shifted internal linear outputs into the service part of the W array. *************************************************************************/ static void logit_mnliexp(/* Real */ ae_vector* w, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t nvars; ae_int_t nclasses; ae_int_t offs; ae_int_t i; ae_int_t i1; double v; double mx; ae_assert(ae_fp_eq(w->ptr.p_double[1],(double)(logit_logitvnum)), "LOGIT: unexpected model version", _state); nvars = ae_round(w->ptr.p_double[2], _state); nclasses = ae_round(w->ptr.p_double[3], _state); offs = ae_round(w->ptr.p_double[4], _state); i1 = offs+(nvars+1)*(nclasses-1); for(i=0; i<=nclasses-2; i++) { v = ae_v_dotproduct(&w->ptr.p_double[offs+i*(nvars+1)], 1, &x->ptr.p_double[0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars-1)); w->ptr.p_double[i1+i] = v+w->ptr.p_double[offs+i*(nvars+1)+nvars]; } w->ptr.p_double[i1+nclasses-1] = (double)(0); mx = (double)(0); for(i=i1; i<=i1+nclasses-1; i++) { mx = ae_maxreal(mx, w->ptr.p_double[i], _state); } for(i=i1; i<=i1+nclasses-1; i++) { w->ptr.p_double[i] = ae_exp(w->ptr.p_double[i]-mx, _state); } } /************************************************************************* Calculation of all types of errors -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/ static void logit_mnlallerrors(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, double* relcls, double* avgce, double* rms, double* avg, double* avgrel, ae_state *_state) { ae_frame _frame_block; ae_int_t nvars; ae_int_t nclasses; ae_int_t i; ae_vector buf; ae_vector workx; ae_vector y; ae_vector dy; ae_frame_make(_state, &_frame_block); *relcls = 0; *avgce = 0; *rms = 0; *avg = 0; *avgrel = 0; ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&workx, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&dy, 0, DT_REAL, _state); ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNL unit: Incorrect MNL version!", _state); nvars = ae_round(lm->w.ptr.p_double[2], _state); nclasses = ae_round(lm->w.ptr.p_double[3], _state); ae_vector_set_length(&workx, nvars-1+1, _state); ae_vector_set_length(&y, nclasses-1+1, _state); ae_vector_set_length(&dy, 0+1, _state); dserrallocate(nclasses, &buf, _state); for(i=0; i<=npoints-1; i++) { ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); mnlprocess(lm, &workx, &y, _state); dy.ptr.p_double[0] = xy->ptr.pp_double[i][nvars]; dserraccumulate(&buf, &y, &dy, _state); } dserrfinish(&buf, _state); *relcls = buf.ptr.p_double[0]; *avgce = buf.ptr.p_double[1]; *rms = buf.ptr.p_double[2]; *avg = buf.ptr.p_double[3]; *avgrel = buf.ptr.p_double[4]; ae_frame_leave(_state); } /************************************************************************* THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT DECREASE CONDITION AND A CURVATURE CONDITION. AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT DECREASE CONDITION F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), AND THE CURVATURE CONDITION ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. PARAMETERS DESCRIPRION N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES. X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S. F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT IT CONTAINS THE VALUE OF F AT X + STP*S. G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X. ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S. S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION. STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE. FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE SATISFIED. XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND UPPER BOUNDS FOR THE STEP. MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION. INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS: INFO = 0 IMPROPER INPUT PARAMETERS. INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION HOLD. INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV. INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN. INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX. INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS. THERE MAY NOT BE A STEP WHICH SATISFIES THE SUFFICIENT DECREASE AND CURVATURE CONDITIONS. TOLERANCES MAY BE TOO SMALL. NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN. WA IS A WORK ARRAY OF LENGTH N. ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983 JORGE J. MORE', DAVID J. THUENTE *************************************************************************/ static void logit_mnlmcsrch(ae_int_t n, /* Real */ ae_vector* x, double* f, /* Real */ ae_vector* g, /* Real */ ae_vector* s, double* stp, ae_int_t* info, ae_int_t* nfev, /* Real */ ae_vector* wa, logitmcstate* state, ae_int_t* stage, ae_state *_state) { double v; double p5; double p66; double zero; /* * init */ p5 = 0.5; p66 = 0.66; state->xtrapf = 4.0; zero = (double)(0); /* * Main cycle */ for(;;) { if( *stage==0 ) { /* * NEXT */ *stage = 2; continue; } if( *stage==2 ) { state->infoc = 1; *info = 0; /* * CHECK THE INPUT PARAMETERS FOR ERRORS. */ if( ((((((n<=0||ae_fp_less_eq(*stp,(double)(0)))||ae_fp_less(logit_ftol,(double)(0)))||ae_fp_less(logit_gtol,zero))||ae_fp_less(logit_xtol,zero))||ae_fp_less(logit_stpmin,zero))||ae_fp_less(logit_stpmax,logit_stpmin))||logit_maxfev<=0 ) { *stage = 0; return; } /* * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION * AND CHECK THAT S IS A DESCENT DIRECTION. */ v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->dginit = v; if( ae_fp_greater_eq(state->dginit,(double)(0)) ) { *stage = 0; return; } /* * INITIALIZE LOCAL VARIABLES. */ state->brackt = ae_false; state->stage1 = ae_true; *nfev = 0; state->finit = *f; state->dgtest = logit_ftol*state->dginit; state->width = logit_stpmax-logit_stpmin; state->width1 = state->width/p5; ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF * THE INTERVAL OF UNCERTAINTY. * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. */ state->stx = (double)(0); state->fx = state->finit; state->dgx = state->dginit; state->sty = (double)(0); state->fy = state->finit; state->dgy = state->dginit; /* * NEXT */ *stage = 3; continue; } if( *stage==3 ) { /* * START OF ITERATION. * * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND * TO THE PRESENT INTERVAL OF UNCERTAINTY. */ if( state->brackt ) { if( ae_fp_less(state->stx,state->sty) ) { state->stmin = state->stx; state->stmax = state->sty; } else { state->stmin = state->sty; state->stmax = state->stx; } } else { state->stmin = state->stx; state->stmax = *stp+state->xtrapf*(*stp-state->stx); } /* * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. */ if( ae_fp_greater(*stp,logit_stpmax) ) { *stp = logit_stpmax; } if( ae_fp_less(*stp,logit_stpmin) ) { *stp = logit_stpmin; } /* * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET * STP BE THE LOWEST POINT OBTAINED SO FAR. */ if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=logit_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax)) ) { *stp = state->stx; } /* * EVALUATE THE FUNCTION AND GRADIENT AT STP * AND COMPUTE THE DIRECTIONAL DERIVATIVE. */ ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); /* * NEXT */ *stage = 4; return; } if( *stage==4 ) { *info = 0; *nfev = *nfev+1; v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->dg = v; state->ftest1 = state->finit+*stp*state->dgtest; /* * TEST FOR CONVERGENCE. */ if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) { *info = 6; } if( (ae_fp_eq(*stp,logit_stpmax)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) { *info = 5; } if( ae_fp_eq(*stp,logit_stpmin)&&(ae_fp_greater(*f,state->ftest1)||ae_fp_greater_eq(state->dg,state->dgtest)) ) { *info = 4; } if( *nfev>=logit_maxfev ) { *info = 3; } if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax) ) { *info = 2; } if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-logit_gtol*state->dginit) ) { *info = 1; } /* * CHECK FOR TERMINATION. */ if( *info!=0 ) { *stage = 0; return; } /* * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. */ if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(logit_ftol, logit_gtol, _state)*state->dginit) ) { state->stage1 = ae_false; } /* * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. */ if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) { /* * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. */ state->fm = *f-*stp*state->dgtest; state->fxm = state->fx-state->stx*state->dgtest; state->fym = state->fy-state->sty*state->dgtest; state->dgm = state->dg-state->dgtest; state->dgxm = state->dgx-state->dgtest; state->dgym = state->dgy-state->dgtest; /* * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY * AND TO COMPUTE THE NEW STEP. */ logit_mnlmcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); /* * RESET THE FUNCTION AND GRADIENT VALUES FOR F. */ state->fx = state->fxm+state->stx*state->dgtest; state->fy = state->fym+state->sty*state->dgtest; state->dgx = state->dgxm+state->dgtest; state->dgy = state->dgym+state->dgtest; } else { /* * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY * AND TO COMPUTE THE NEW STEP. */ logit_mnlmcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); } /* * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE * INTERVAL OF UNCERTAINTY. */ if( state->brackt ) { if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) { *stp = state->stx+p5*(state->sty-state->stx); } state->width1 = state->width; state->width = ae_fabs(state->sty-state->stx, _state); } /* * NEXT. */ *stage = 3; continue; } } } static void logit_mnlmcstep(double* stx, double* fx, double* dx, double* sty, double* fy, double* dy, double* stp, double fp, double dp, ae_bool* brackt, double stmin, double stmax, ae_int_t* info, ae_state *_state) { ae_bool bound; double gamma; double p; double q; double r; double s; double sgnd; double stpc; double stpf; double stpq; double theta; *info = 0; /* * CHECK THE INPUT PARAMETERS FOR ERRORS. */ if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),(double)(0)))||ae_fp_less(stmax,stmin) ) { return; } /* * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. */ sgnd = dp*(*dx/ae_fabs(*dx, _state)); /* * FIRST CASE. A HIGHER FUNCTION VALUE. * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. */ if( ae_fp_greater(fp,*fx) ) { *info = 1; bound = ae_true; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); if( ae_fp_less(*stp,*stx) ) { gamma = -gamma; } p = gamma-(*dx)+theta; q = gamma-(*dx)+gamma+dp; r = p/q; stpc = *stx+r*(*stp-(*stx)); stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/2*(*stp-(*stx)); if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) { stpf = stpc; } else { stpf = stpc+(stpq-stpc)/2; } *brackt = ae_true; } else { if( ae_fp_less(sgnd,(double)(0)) ) { /* * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. */ *info = 2; bound = ae_false; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); if( ae_fp_greater(*stp,*stx) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma-dp+gamma+(*dx); r = p/q; stpc = *stp+r*(*stx-(*stp)); stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) { stpf = stpc; } else { stpf = stpq; } *brackt = ae_true; } else { if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) { /* * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. */ *info = 3; bound = ae_true; theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); /* * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND * TO INFINITY IN THE DIRECTION OF THE STEP. */ gamma = s*ae_sqrt(ae_maxreal((double)(0), ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); if( ae_fp_greater(*stp,*stx) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma+(*dx-dp)+gamma; r = p/q; if( ae_fp_less(r,(double)(0))&&ae_fp_neq(gamma,(double)(0)) ) { stpc = *stp+r*(*stx-(*stp)); } else { if( ae_fp_greater(*stp,*stx) ) { stpc = stmax; } else { stpc = stmin; } } stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); if( *brackt ) { if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) { stpf = stpc; } else { stpf = stpq; } } else { if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) { stpf = stpc; } else { stpf = stpq; } } } else { /* * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. */ *info = 4; bound = ae_false; if( *brackt ) { theta = 3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); if( ae_fp_greater(*stp,*sty) ) { gamma = -gamma; } p = gamma-dp+theta; q = gamma-dp+gamma+(*dy); r = p/q; stpc = *stp+r*(*sty-(*stp)); stpf = stpc; } else { if( ae_fp_greater(*stp,*stx) ) { stpf = stmax; } else { stpf = stmin; } } } } } /* * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. */ if( ae_fp_greater(fp,*fx) ) { *sty = *stp; *fy = fp; *dy = dp; } else { if( ae_fp_less(sgnd,0.0) ) { *sty = *stx; *fy = *fx; *dy = *dx; } *stx = *stp; *fx = fp; *dx = dp; } /* * COMPUTE THE NEW STEP AND SAFEGUARD IT. */ stpf = ae_minreal(stmax, stpf, _state); stpf = ae_maxreal(stmin, stpf, _state); *stp = stpf; if( *brackt&&bound ) { if( ae_fp_greater(*sty,*stx) ) { *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); } else { *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); } } } void _logitmodel_init(void* _p, ae_state *_state) { logitmodel *p = (logitmodel*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->w, 0, DT_REAL, _state); } void _logitmodel_init_copy(void* _dst, void* _src, ae_state *_state) { logitmodel *dst = (logitmodel*)_dst; logitmodel *src = (logitmodel*)_src; ae_vector_init_copy(&dst->w, &src->w, _state); } void _logitmodel_clear(void* _p) { logitmodel *p = (logitmodel*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->w); } void _logitmodel_destroy(void* _p) { logitmodel *p = (logitmodel*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->w); } void _logitmcstate_init(void* _p, ae_state *_state) { logitmcstate *p = (logitmcstate*)_p; ae_touch_ptr((void*)p); } void _logitmcstate_init_copy(void* _dst, void* _src, ae_state *_state) { logitmcstate *dst = (logitmcstate*)_dst; logitmcstate *src = (logitmcstate*)_src; dst->brackt = src->brackt; dst->stage1 = src->stage1; dst->infoc = src->infoc; dst->dg = src->dg; dst->dgm = src->dgm; dst->dginit = src->dginit; dst->dgtest = src->dgtest; dst->dgx = src->dgx; dst->dgxm = src->dgxm; dst->dgy = src->dgy; dst->dgym = src->dgym; dst->finit = src->finit; dst->ftest1 = src->ftest1; dst->fm = src->fm; dst->fx = src->fx; dst->fxm = src->fxm; dst->fy = src->fy; dst->fym = src->fym; dst->stx = src->stx; dst->sty = src->sty; dst->stmin = src->stmin; dst->stmax = src->stmax; dst->width = src->width; dst->width1 = src->width1; dst->xtrapf = src->xtrapf; } void _logitmcstate_clear(void* _p) { logitmcstate *p = (logitmcstate*)_p; ae_touch_ptr((void*)p); } void _logitmcstate_destroy(void* _p) { logitmcstate *p = (logitmcstate*)_p; ae_touch_ptr((void*)p); } void _mnlreport_init(void* _p, ae_state *_state) { mnlreport *p = (mnlreport*)_p; ae_touch_ptr((void*)p); } void _mnlreport_init_copy(void* _dst, void* _src, ae_state *_state) { mnlreport *dst = (mnlreport*)_dst; mnlreport *src = (mnlreport*)_src; dst->ngrad = src->ngrad; dst->nhess = src->nhess; } void _mnlreport_clear(void* _p) { mnlreport *p = (mnlreport*)_p; ae_touch_ptr((void*)p); } void _mnlreport_destroy(void* _p) { mnlreport *p = (mnlreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* DESCRIPTION: This function creates MCPD (Markov Chains for Population Data) solver. This solver can be used to find transition matrix P for N-dimensional prediction problem where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional population vectors (components of each X are non-negative), and P is a N*N transition matrix (elements of P are non-negative, each column sums to 1.0). Such models arise when when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is constant, i.e. there is no new individuals and no one leaves population * you want to model transitions of individuals from one state into another USAGE: Here we give very brief outline of the MCPD. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on data analysis which is available at http://www.alglib.net/dataanalysis/ 1. User initializes algorithm state with MCPDCreate() call 2. User adds one or more tracks - sequences of states which describe evolution of a system being modelled from different starting conditions 3. User may add optional boundary, equality and/or linear constraints on the coefficients of P by calling one of the following functions: * MCPDSetEC() to set equality constraints * MCPDSetBC() to set bound constraints * MCPDSetLC() to set linear constraints 4. Optionally, user may set custom weights for prediction errors (by default, algorithm assigns non-equal, automatically chosen weights for errors in the prediction of different components of X). It can be done with a call of MCPDSetPredictionWeights() function. 5. User calls MCPDSolve() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 6. User calls MCPDResults() to get solution INPUT PARAMETERS: N - problem dimension, N>=1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state) { _mcpdstate_clear(s); ae_assert(n>=1, "MCPDCreate: N<1", _state); mcpd_mcpdinit(n, -1, -1, s, _state); } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state Such conditions basically mean that row of P which corresponds to "entry" state is zero. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn, but still no one leaves population * you want to model transitions of individuals from one state into another * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentry(ae_int_t n, ae_int_t entrystate, mcpdstate* s, ae_state *_state) { _mcpdstate_clear(s); ae_assert(n>=2, "MCPDCreateEntry: N<2", _state); ae_assert(entrystate>=0, "MCPDCreateEntry: EntryState<0", _state); ae_assert(entrystate=N", _state); mcpd_mcpdinit(n, entrystate, -1, s, _state); } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "exit" state and is treated in a special way: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that column of P which corresponds to "exit" state is zero. Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - individuals can move into "exit" state and leave population at the next turn, but there are no new individuals * amount of individuals which leave population can be predicted * you want to model transitions of individuals from one state into another (including transitions into the "exit" state) This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateexit(ae_int_t n, ae_int_t exitstate, mcpdstate* s, ae_state *_state) { _mcpdstate_clear(s); ae_assert(n>=2, "MCPDCreateExit: N<2", _state); ae_assert(exitstate>=0, "MCPDCreateExit: ExitState<0", _state); ae_assert(exitstate=N", _state); mcpd_mcpdinit(n, -1, exitstate, s, _state); } /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-Exit-states" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state and another one component of X[] is called "exit" state and is treated in a special way too: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that: row of P which corresponds to "entry" state is zero column of P which corresponds to "exit" state is zero Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant * at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn * some individuals can move (predictably) into "exit" state and leave population at the next turn * you want to model transitions of individuals from one state into another, including transitions from the "entry" state and into the "exit" state. * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentryexit(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state) { _mcpdstate_clear(s); ae_assert(n>=2, "MCPDCreateEntryExit: N<2", _state); ae_assert(entrystate>=0, "MCPDCreateEntryExit: EntryState<0", _state); ae_assert(entrystate=N", _state); ae_assert(exitstate>=0, "MCPDCreateEntryExit: ExitState<0", _state); ae_assert(exitstate=N", _state); ae_assert(entrystate!=exitstate, "MCPDCreateEntryExit: EntryState=ExitState", _state); mcpd_mcpdinit(n, entrystate, exitstate, s, _state); } /************************************************************************* This function is used to add a track - sequence of system states at the different moments of its evolution. You may add one or several tracks to the MCPD solver. In case you have several tracks, they won't overwrite each other. For example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont try to model transition from t=A+3 to t=B+1. INPUT PARAMETERS: S - solver XY - track, array[K,N]: * I-th row is a state at t=I * elements of XY must be non-negative (exception will be thrown on negative elements) K - number of points in a track * if given, only leading K rows of XY are used * if not given, automatically determined from size of XY NOTES: 1. Track may contain either proportional or population data: * with proportional data all rows of XY must sum to 1.0, i.e. we have proportions instead of absolute population values * with population data rows of XY contain population counts and generally do not sum to 1.0 (although they still must be non-negative) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddtrack(mcpdstate* s, /* Real */ ae_matrix* xy, ae_int_t k, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; double s0; double s1; n = s->n; ae_assert(k>=0, "MCPDAddTrack: K<0", _state); ae_assert(xy->cols>=n, "MCPDAddTrack: Cols(XY)rows>=k, "MCPDAddTrack: Rows(XY)ptr.pp_double[i][j],(double)(0)), "MCPDAddTrack: XY contains negative elements", _state); } } if( k<2 ) { return; } if( s->data.rowsnpairs+k-1 ) { rmatrixresize(&s->data, ae_maxint(2*s->data.rows, s->npairs+k-1, _state), 2*n, _state); } for(i=0; i<=k-2; i++) { s0 = (double)(0); s1 = (double)(0); for(j=0; j<=n-1; j++) { if( s->states.ptr.p_int[j]>=0 ) { s0 = s0+xy->ptr.pp_double[i][j]; } if( s->states.ptr.p_int[j]<=0 ) { s1 = s1+xy->ptr.pp_double[i+1][j]; } } if( ae_fp_greater(s0,(double)(0))&&ae_fp_greater(s1,(double)(0)) ) { for(j=0; j<=n-1; j++) { if( s->states.ptr.p_int[j]>=0 ) { s->data.ptr.pp_double[s->npairs][j] = xy->ptr.pp_double[i][j]/s0; } else { s->data.ptr.pp_double[s->npairs][j] = 0.0; } if( s->states.ptr.p_int[j]<=0 ) { s->data.ptr.pp_double[s->npairs][n+j] = xy->ptr.pp_double[i+1][j]/s1; } else { s->data.ptr.pp_double[s->npairs][n+j] = 0.0; } } s->npairs = s->npairs+1; } } } /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place equality constraints on arbitrary subset of elements of P. Set of constraints is specified by EC, which may contain either NAN's or finite numbers from [0,1]. NAN denotes absence of constraint, finite number denotes equality constraint on specific element of P. You can also use MCPDAddEC() function which allows to ADD equality constraint for one element of P without changing constraints for other elements. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver EC - equality constraints, array[N,N]. Elements of EC can be either NAN's or finite numbers from [0,1]. NAN denotes absence of constraints, while finite value denotes equality constraint on the corresponding element of P. NOTES: 1. infinite values of EC will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetec(mcpdstate* s, /* Real */ ae_matrix* ec, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; n = s->n; ae_assert(ec->cols>=n, "MCPDSetEC: Cols(EC)rows>=n, "MCPDSetEC: Rows(EC)ptr.pp_double[i][j], _state)||ae_isnan(ec->ptr.pp_double[i][j], _state), "MCPDSetEC: EC containts infinite elements", _state); s->ec.ptr.pp_double[i][j] = ec->ptr.pp_double[i][j]; } } } /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD equality constraint for one element of P without changing constraints for other elements. You can also use MCPDSetEC() function which allows you to specify arbitrary set of equality constraints in one call. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver I - row index of element being constrained J - column index of element being constrained C - value (constraint for P[I,J]). Can be either NAN (no constraint) or finite value from [0,1]. NOTES: 1. infinite values of C will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddec(mcpdstate* s, ae_int_t i, ae_int_t j, double c, ae_state *_state) { ae_assert(i>=0, "MCPDAddEC: I<0", _state); ae_assert(in, "MCPDAddEC: I>=N", _state); ae_assert(j>=0, "MCPDAddEC: J<0", _state); ae_assert(jn, "MCPDAddEC: J>=N", _state); ae_assert(ae_isnan(c, _state)||ae_isfinite(c, _state), "MCPDAddEC: C is not finite number or NAN", _state); s->ec.ptr.pp_double[i][j] = c; } /************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INFn; ae_assert(bndl->cols>=n, "MCPDSetBC: Cols(BndL)rows>=n, "MCPDSetBC: Rows(BndL)cols>=n, "MCPDSetBC: Cols(BndU)rows>=n, "MCPDSetBC: Rows(BndU)ptr.pp_double[i][j], _state)||ae_isneginf(bndl->ptr.pp_double[i][j], _state), "MCPDSetBC: BndL containts NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.pp_double[i][j], _state)||ae_isposinf(bndu->ptr.pp_double[i][j], _state), "MCPDSetBC: BndU containts NAN or -INF", _state); s->bndl.ptr.pp_double[i][j] = bndl->ptr.pp_double[i][j]; s->bndu.ptr.pp_double[i][j] = bndu->ptr.pp_double[i][j]; } } } /************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD bound constraint for one element of P without changing constraints for other elements. You can also use MCPDSetBC() function which allows to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF=0, "MCPDAddBC: I<0", _state); ae_assert(in, "MCPDAddBC: I>=N", _state); ae_assert(j>=0, "MCPDAddBC: J<0", _state); ae_assert(jn, "MCPDAddBC: J>=N", _state); ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MCPDAddBC: BndL is NAN or +INF", _state); ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MCPDAddBC: BndU is NAN or -INF", _state); s->bndl.ptr.pp_double[i][j] = bndl; s->bndu.ptr.pp_double[i][j] = bndu; } /************************************************************************* This function is used to set linear equality/inequality constraints on the elements of the transition matrix P. This function can be used to set one or several general linear constraints on the elements of P. Two types of constraints are supported: * equality constraints * inequality constraints (both less-or-equal and greater-or-equal) Coefficients of constraints are specified by matrix C (one of the parameters). One row of C corresponds to one constraint. Because transition matrix P has N*N elements, we need N*N columns to store all coefficients (they are stored row by row), and one more column to store right part - hence C has N*N+1 columns. Constraint kind is stored in the CT array. Thus, I-th linear constraint is P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). Your constraint may involve only some subset of P (less than N*N elements). For example it can be something like P[0,0] + P[0,1] = 0.5 In this case you still should pass matrix with N*N+1 columns, but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. INPUT PARAMETERS: S - solver C - array[K,N*N+1] - coefficients of constraints (see above for complete description) CT - array[K] - constraint types (see above for complete description) K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetlc(mcpdstate* s, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; n = s->n; ae_assert(c->cols>=n*n+1, "MCPDSetLC: Cols(C)rows>=k, "MCPDSetLC: Rows(C)cnt>=k, "MCPDSetLC: Len(CT)c, k, n*n+1, _state); ivectorsetlengthatleast(&s->ct, k, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n*n; j++) { s->c.ptr.pp_double[i][j] = c->ptr.pp_double[i][j]; } s->ct.ptr.p_int[i] = ct->ptr.p_int[i]; } s->ccnt = k; } /************************************************************************* This function allows to tune amount of Tikhonov regularization being applied to your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change coefficient r. You can also change prior values with MCPDSetPrior() function. INPUT PARAMETERS: S - solver V - regularization coefficient, finite non-negative value. It is not recommended to specify zero value unless you are pretty sure that you want it. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state) { ae_assert(ae_isfinite(v, _state), "MCPDSetTikhonovRegularizer: V is infinite or NAN", _state); ae_assert(ae_fp_greater_eq(v,0.0), "MCPDSetTikhonovRegularizer: V is less than zero", _state); s->regterm = v; } /************************************************************************* This function allows to set prior values used for regularization of your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change prior values prior_P. You can also change r with MCPDSetTikhonovRegularizer() function. INPUT PARAMETERS: S - solver PP - array[N,N], matrix of prior values: 1. elements must be real numbers from [0,1] 2. columns must sum to 1.0. First property is checked (exception is thrown otherwise), while second one is not checked/enforced. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetprior(mcpdstate* s, /* Real */ ae_matrix* pp, ae_state *_state) { ae_frame _frame_block; ae_matrix _pp; ae_int_t i; ae_int_t j; ae_int_t n; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_pp, pp, _state); pp = &_pp; n = s->n; ae_assert(pp->cols>=n, "MCPDSetPrior: Cols(PP)rows>=n, "MCPDSetPrior: Rows(PP)ptr.pp_double[i][j], _state), "MCPDSetPrior: PP containts infinite elements", _state); ae_assert(ae_fp_greater_eq(pp->ptr.pp_double[i][j],0.0)&&ae_fp_less_eq(pp->ptr.pp_double[i][j],1.0), "MCPDSetPrior: PP[i,j] is less than 0.0 or greater than 1.0", _state); s->priorp.ptr.pp_double[i][j] = pp->ptr.pp_double[i][j]; } } ae_frame_leave(_state); } /************************************************************************* This function is used to change prediction weights MCPD solver scales prediction errors as follows Error(P) = ||W*(y-P*x)||^2 where x is a system state at time t y is a system state at time t+1 P is a transition matrix W is a diagonal scaling matrix By default, weights are chosen in order to minimize relative prediction error instead of absolute one. For example, if one component of state is about 0.5 in magnitude and another one is about 0.05, then algorithm will make corresponding weights equal to 2.0 and 20.0. INPUT PARAMETERS: S - solver PW - array[N], weights: * must be non-negative values (exception will be thrown otherwise) * zero values will be replaced by automatically chosen values -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetpredictionweights(mcpdstate* s, /* Real */ ae_vector* pw, ae_state *_state) { ae_int_t i; ae_int_t n; n = s->n; ae_assert(pw->cnt>=n, "MCPDSetPredictionWeights: Length(PW)ptr.p_double[i], _state), "MCPDSetPredictionWeights: PW containts infinite or NAN elements", _state); ae_assert(ae_fp_greater_eq(pw->ptr.p_double[i],(double)(0)), "MCPDSetPredictionWeights: PW containts negative elements", _state); s->pw.ptr.p_double[i] = pw->ptr.p_double[i]; } } /************************************************************************* This function is used to start solution of the MCPD problem. After return from this function, you can use MCPDResults() to get solution and completion code. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsolve(mcpdstate* s, ae_state *_state) { ae_int_t n; ae_int_t npairs; ae_int_t ccnt; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t k2; double v; double vv; n = s->n; npairs = s->npairs; /* * init fields of S */ s->repterminationtype = 0; s->repinneriterationscount = 0; s->repouteriterationscount = 0; s->repnfev = 0; for(k=0; k<=n-1; k++) { for(k2=0; k2<=n-1; k2++) { s->p.ptr.pp_double[k][k2] = _state->v_nan; } } /* * Generate "effective" weights for prediction and calculate preconditioner */ for(i=0; i<=n-1; i++) { if( ae_fp_eq(s->pw.ptr.p_double[i],(double)(0)) ) { v = (double)(0); k = 0; for(j=0; j<=npairs-1; j++) { if( ae_fp_neq(s->data.ptr.pp_double[j][n+i],(double)(0)) ) { v = v+s->data.ptr.pp_double[j][n+i]; k = k+1; } } if( k!=0 ) { s->effectivew.ptr.p_double[i] = k/v; } else { s->effectivew.ptr.p_double[i] = 1.0; } } else { s->effectivew.ptr.p_double[i] = s->pw.ptr.p_double[i]; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->h.ptr.p_double[i*n+j] = 2*s->regterm; } } for(k=0; k<=npairs-1; k++) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->h.ptr.p_double[i*n+j] = s->h.ptr.p_double[i*n+j]+2*ae_sqr(s->effectivew.ptr.p_double[i], _state)*ae_sqr(s->data.ptr.pp_double[k][j], _state); } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_eq(s->h.ptr.p_double[i*n+j],(double)(0)) ) { s->h.ptr.p_double[i*n+j] = (double)(1); } } } /* * Generate "effective" BndL/BndU */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * Set default boundary constraints. * Lower bound is always zero, upper bound is calculated * with respect to entry/exit states. */ s->effectivebndl.ptr.p_double[i*n+j] = 0.0; if( s->states.ptr.p_int[i]>0||s->states.ptr.p_int[j]<0 ) { s->effectivebndu.ptr.p_double[i*n+j] = 0.0; } else { s->effectivebndu.ptr.p_double[i*n+j] = 1.0; } /* * Calculate intersection of the default and user-specified bound constraints. * This code checks consistency of such combination. */ if( ae_isfinite(s->bndl.ptr.pp_double[i][j], _state)&&ae_fp_greater(s->bndl.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j]) ) { s->effectivebndl.ptr.p_double[i*n+j] = s->bndl.ptr.pp_double[i][j]; } if( ae_isfinite(s->bndu.ptr.pp_double[i][j], _state)&&ae_fp_less(s->bndu.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) { s->effectivebndu.ptr.p_double[i*n+j] = s->bndu.ptr.pp_double[i][j]; } if( ae_fp_greater(s->effectivebndl.ptr.p_double[i*n+j],s->effectivebndu.ptr.p_double[i*n+j]) ) { s->repterminationtype = -3; return; } /* * Calculate intersection of the effective bound constraints * and user-specified equality constraints. * This code checks consistency of such combination. */ if( ae_isfinite(s->ec.ptr.pp_double[i][j], _state) ) { if( ae_fp_less(s->ec.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j])||ae_fp_greater(s->ec.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) { s->repterminationtype = -3; return; } s->effectivebndl.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; s->effectivebndu.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; } } } /* * Generate linear constraints: * * "default" sums-to-one constraints (not generated for "exit" states) */ rmatrixsetlengthatleast(&s->effectivec, s->ccnt+n, n*n+1, _state); ivectorsetlengthatleast(&s->effectivect, s->ccnt+n, _state); ccnt = s->ccnt; for(i=0; i<=s->ccnt-1; i++) { for(j=0; j<=n*n; j++) { s->effectivec.ptr.pp_double[i][j] = s->c.ptr.pp_double[i][j]; } s->effectivect.ptr.p_int[i] = s->ct.ptr.p_int[i]; } for(i=0; i<=n-1; i++) { if( s->states.ptr.p_int[i]>=0 ) { for(k=0; k<=n*n-1; k++) { s->effectivec.ptr.pp_double[ccnt][k] = (double)(0); } for(k=0; k<=n-1; k++) { s->effectivec.ptr.pp_double[ccnt][k*n+i] = (double)(1); } s->effectivec.ptr.pp_double[ccnt][n*n] = 1.0; s->effectivect.ptr.p_int[ccnt] = 0; ccnt = ccnt+1; } } /* * create optimizer */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->tmpp.ptr.p_double[i*n+j] = (double)1/(double)n; } } minbleicrestartfrom(&s->bs, &s->tmpp, _state); minbleicsetbc(&s->bs, &s->effectivebndl, &s->effectivebndu, _state); minbleicsetlc(&s->bs, &s->effectivec, &s->effectivect, ccnt, _state); minbleicsetcond(&s->bs, 0.0, 0.0, mcpd_xtol, 0, _state); minbleicsetprecdiag(&s->bs, &s->h, _state); /* * solve problem */ while(minbleiciteration(&s->bs, _state)) { ae_assert(s->bs.needfg, "MCPDSolve: internal error", _state); if( s->bs.needfg ) { /* * Calculate regularization term */ s->bs.f = 0.0; vv = s->regterm; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->bs.f = s->bs.f+vv*ae_sqr(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j], _state); s->bs.g.ptr.p_double[i*n+j] = 2*vv*(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j]); } } /* * calculate prediction error/gradient for K-th pair */ for(k=0; k<=npairs-1; k++) { for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&s->bs.x.ptr.p_double[i*n], 1, &s->data.ptr.pp_double[k][0], 1, ae_v_len(i*n,i*n+n-1)); vv = s->effectivew.ptr.p_double[i]; s->bs.f = s->bs.f+ae_sqr(vv*(v-s->data.ptr.pp_double[k][n+i]), _state); for(j=0; j<=n-1; j++) { s->bs.g.ptr.p_double[i*n+j] = s->bs.g.ptr.p_double[i*n+j]+2*vv*vv*(v-s->data.ptr.pp_double[k][n+i])*s->data.ptr.pp_double[k][j]; } } } /* * continue */ continue; } } minbleicresultsbuf(&s->bs, &s->tmpp, &s->br, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->p.ptr.pp_double[i][j] = s->tmpp.ptr.p_double[i*n+j]; } } s->repterminationtype = s->br.terminationtype; s->repinneriterationscount = s->br.inneriterationscount; s->repouteriterationscount = s->br.outeriterationscount; s->repnfev = s->br.nfev; } /************************************************************************* MCPD results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: P - array[N,N], transition matrix Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one. Speaking short, positive values denote success, negative ones are failures. More information about fields of this structure can be found in the comments on MCPDReport datatype. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdresults(mcpdstate* s, /* Real */ ae_matrix* p, mcpdreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(p); _mcpdreport_clear(rep); ae_matrix_set_length(p, s->n, s->n, _state); for(i=0; i<=s->n-1; i++) { for(j=0; j<=s->n-1; j++) { p->ptr.pp_double[i][j] = s->p.ptr.pp_double[i][j]; } } rep->terminationtype = s->repterminationtype; rep->inneriterationscount = s->repinneriterationscount; rep->outeriterationscount = s->repouteriterationscount; rep->nfev = s->repnfev; } /************************************************************************* Internal initialization function -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ static void mcpd_mcpdinit(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state) { ae_int_t i; ae_int_t j; ae_assert(n>=1, "MCPDCreate: N<1", _state); s->n = n; ae_vector_set_length(&s->states, n, _state); for(i=0; i<=n-1; i++) { s->states.ptr.p_int[i] = 0; } if( entrystate>=0 ) { s->states.ptr.p_int[entrystate] = 1; } if( exitstate>=0 ) { s->states.ptr.p_int[exitstate] = -1; } s->npairs = 0; s->regterm = 1.0E-8; s->ccnt = 0; ae_matrix_set_length(&s->p, n, n, _state); ae_matrix_set_length(&s->ec, n, n, _state); ae_matrix_set_length(&s->bndl, n, n, _state); ae_matrix_set_length(&s->bndu, n, n, _state); ae_vector_set_length(&s->pw, n, _state); ae_matrix_set_length(&s->priorp, n, n, _state); ae_vector_set_length(&s->tmpp, n*n, _state); ae_vector_set_length(&s->effectivew, n, _state); ae_vector_set_length(&s->effectivebndl, n*n, _state); ae_vector_set_length(&s->effectivebndu, n*n, _state); ae_vector_set_length(&s->h, n*n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->p.ptr.pp_double[i][j] = 0.0; s->priorp.ptr.pp_double[i][j] = 0.0; s->bndl.ptr.pp_double[i][j] = _state->v_neginf; s->bndu.ptr.pp_double[i][j] = _state->v_posinf; s->ec.ptr.pp_double[i][j] = _state->v_nan; } s->pw.ptr.p_double[i] = 0.0; s->priorp.ptr.pp_double[i][i] = 1.0; } ae_matrix_set_length(&s->data, 1, 2*n, _state); for(i=0; i<=2*n-1; i++) { s->data.ptr.pp_double[0][i] = 0.0; } for(i=0; i<=n*n-1; i++) { s->tmpp.ptr.p_double[i] = 0.0; } minbleiccreate(n*n, &s->tmpp, &s->bs, _state); } void _mcpdstate_init(void* _p, ae_state *_state) { mcpdstate *p = (mcpdstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->states, 0, DT_INT, _state); ae_matrix_init(&p->data, 0, 0, DT_REAL, _state); ae_matrix_init(&p->ec, 0, 0, DT_REAL, _state); ae_matrix_init(&p->bndl, 0, 0, DT_REAL, _state); ae_matrix_init(&p->bndu, 0, 0, DT_REAL, _state); ae_matrix_init(&p->c, 0, 0, DT_REAL, _state); ae_vector_init(&p->ct, 0, DT_INT, _state); ae_vector_init(&p->pw, 0, DT_REAL, _state); ae_matrix_init(&p->priorp, 0, 0, DT_REAL, _state); _minbleicstate_init(&p->bs, _state); _minbleicreport_init(&p->br, _state); ae_vector_init(&p->tmpp, 0, DT_REAL, _state); ae_vector_init(&p->effectivew, 0, DT_REAL, _state); ae_vector_init(&p->effectivebndl, 0, DT_REAL, _state); ae_vector_init(&p->effectivebndu, 0, DT_REAL, _state); ae_matrix_init(&p->effectivec, 0, 0, DT_REAL, _state); ae_vector_init(&p->effectivect, 0, DT_INT, _state); ae_vector_init(&p->h, 0, DT_REAL, _state); ae_matrix_init(&p->p, 0, 0, DT_REAL, _state); } void _mcpdstate_init_copy(void* _dst, void* _src, ae_state *_state) { mcpdstate *dst = (mcpdstate*)_dst; mcpdstate *src = (mcpdstate*)_src; dst->n = src->n; ae_vector_init_copy(&dst->states, &src->states, _state); dst->npairs = src->npairs; ae_matrix_init_copy(&dst->data, &src->data, _state); ae_matrix_init_copy(&dst->ec, &src->ec, _state); ae_matrix_init_copy(&dst->bndl, &src->bndl, _state); ae_matrix_init_copy(&dst->bndu, &src->bndu, _state); ae_matrix_init_copy(&dst->c, &src->c, _state); ae_vector_init_copy(&dst->ct, &src->ct, _state); dst->ccnt = src->ccnt; ae_vector_init_copy(&dst->pw, &src->pw, _state); ae_matrix_init_copy(&dst->priorp, &src->priorp, _state); dst->regterm = src->regterm; _minbleicstate_init_copy(&dst->bs, &src->bs, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repnfev = src->repnfev; dst->repterminationtype = src->repterminationtype; _minbleicreport_init_copy(&dst->br, &src->br, _state); ae_vector_init_copy(&dst->tmpp, &src->tmpp, _state); ae_vector_init_copy(&dst->effectivew, &src->effectivew, _state); ae_vector_init_copy(&dst->effectivebndl, &src->effectivebndl, _state); ae_vector_init_copy(&dst->effectivebndu, &src->effectivebndu, _state); ae_matrix_init_copy(&dst->effectivec, &src->effectivec, _state); ae_vector_init_copy(&dst->effectivect, &src->effectivect, _state); ae_vector_init_copy(&dst->h, &src->h, _state); ae_matrix_init_copy(&dst->p, &src->p, _state); } void _mcpdstate_clear(void* _p) { mcpdstate *p = (mcpdstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->states); ae_matrix_clear(&p->data); ae_matrix_clear(&p->ec); ae_matrix_clear(&p->bndl); ae_matrix_clear(&p->bndu); ae_matrix_clear(&p->c); ae_vector_clear(&p->ct); ae_vector_clear(&p->pw); ae_matrix_clear(&p->priorp); _minbleicstate_clear(&p->bs); _minbleicreport_clear(&p->br); ae_vector_clear(&p->tmpp); ae_vector_clear(&p->effectivew); ae_vector_clear(&p->effectivebndl); ae_vector_clear(&p->effectivebndu); ae_matrix_clear(&p->effectivec); ae_vector_clear(&p->effectivect); ae_vector_clear(&p->h); ae_matrix_clear(&p->p); } void _mcpdstate_destroy(void* _p) { mcpdstate *p = (mcpdstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->states); ae_matrix_destroy(&p->data); ae_matrix_destroy(&p->ec); ae_matrix_destroy(&p->bndl); ae_matrix_destroy(&p->bndu); ae_matrix_destroy(&p->c); ae_vector_destroy(&p->ct); ae_vector_destroy(&p->pw); ae_matrix_destroy(&p->priorp); _minbleicstate_destroy(&p->bs); _minbleicreport_destroy(&p->br); ae_vector_destroy(&p->tmpp); ae_vector_destroy(&p->effectivew); ae_vector_destroy(&p->effectivebndl); ae_vector_destroy(&p->effectivebndu); ae_matrix_destroy(&p->effectivec); ae_vector_destroy(&p->effectivect); ae_vector_destroy(&p->h); ae_matrix_destroy(&p->p); } void _mcpdreport_init(void* _p, ae_state *_state) { mcpdreport *p = (mcpdreport*)_p; ae_touch_ptr((void*)p); } void _mcpdreport_init_copy(void* _dst, void* _src, ae_state *_state) { mcpdreport *dst = (mcpdreport*)_dst; mcpdreport *src = (mcpdreport*)_src; dst->inneriterationscount = src->inneriterationscount; dst->outeriterationscount = src->outeriterationscount; dst->nfev = src->nfev; dst->terminationtype = src->terminationtype; } void _mcpdreport_clear(void* _p) { mcpdreport *p = (mcpdreport*)_p; ae_touch_ptr((void*)p); } void _mcpdreport_destroy(void* _p) { mcpdreport *p = (mcpdreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* Like MLPCreate0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate0(ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreate0(nin, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreate1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreate1(nin, nhid, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreate2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreate2(nin, nhid1, nhid2, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateB0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb0(ae_int_t nin, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreateb0(nin, nout, b, d, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateB1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreateb1(nin, nhid, nout, b, d, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateB2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreateb2(nin, nhid1, nhid2, nout, b, d, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateR0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater0(ae_int_t nin, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreater0(nin, nout, a, b, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateR1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreater1(nin, nhid, nout, a, b, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateR2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreater2(nin, nhid1, nhid2, nout, a, b, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateC0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec0(ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreatec0(nin, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateC1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreatec1(nin, nhid, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Like MLPCreateC2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_frame_make(_state, &_frame_block); _mlpensemble_clear(ensemble); _multilayerperceptron_init(&net, _state); mlpcreatec2(nin, nhid1, nhid2, nout, &net, _state); mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); ae_frame_leave(_state); } /************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatefromnetwork(multilayerperceptron* network, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state) { ae_int_t i; ae_int_t ccount; ae_int_t wcount; _mlpensemble_clear(ensemble); ae_assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!", _state); /* * Copy network */ mlpcopy(network, &ensemble->network, _state); /* * network properties */ if( mlpissoftmax(network, _state) ) { ccount = mlpgetinputscount(&ensemble->network, _state); } else { ccount = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); } wcount = mlpgetweightscount(&ensemble->network, _state); ensemble->ensemblesize = ensemblesize; /* * weights, means, sigmas */ ae_vector_set_length(&ensemble->weights, ensemblesize*wcount, _state); ae_vector_set_length(&ensemble->columnmeans, ensemblesize*ccount, _state); ae_vector_set_length(&ensemble->columnsigmas, ensemblesize*ccount, _state); for(i=0; i<=ensemblesize*wcount-1; i++) { ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; } for(i=0; i<=ensemblesize-1; i++) { ae_v_move(&ensemble->columnmeans.ptr.p_double[i*ccount], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); ae_v_move(&ensemble->columnsigmas.ptr.p_double[i*ccount], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); } /* * temporaries, internal buffers */ ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); } /************************************************************************* Copying of MLPEnsemble strucure INPUT PARAMETERS: Ensemble1 - original OUTPUT PARAMETERS: Ensemble2 - copy -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecopy(mlpensemble* ensemble1, mlpensemble* ensemble2, ae_state *_state) { ae_int_t ccount; ae_int_t wcount; _mlpensemble_clear(ensemble2); /* * Unload info */ if( mlpissoftmax(&ensemble1->network, _state) ) { ccount = mlpgetinputscount(&ensemble1->network, _state); } else { ccount = mlpgetinputscount(&ensemble1->network, _state)+mlpgetoutputscount(&ensemble1->network, _state); } wcount = mlpgetweightscount(&ensemble1->network, _state); /* * Allocate space */ ae_vector_set_length(&ensemble2->weights, ensemble1->ensemblesize*wcount, _state); ae_vector_set_length(&ensemble2->columnmeans, ensemble1->ensemblesize*ccount, _state); ae_vector_set_length(&ensemble2->columnsigmas, ensemble1->ensemblesize*ccount, _state); ae_vector_set_length(&ensemble2->y, mlpgetoutputscount(&ensemble1->network, _state), _state); /* * Copy */ ensemble2->ensemblesize = ensemble1->ensemblesize; ae_v_move(&ensemble2->weights.ptr.p_double[0], 1, &ensemble1->weights.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*wcount-1)); ae_v_move(&ensemble2->columnmeans.ptr.p_double[0], 1, &ensemble1->columnmeans.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); ae_v_move(&ensemble2->columnsigmas.ptr.p_double[0], 1, &ensemble1->columnsigmas.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); mlpcopy(&ensemble1->network, &ensemble2->network, _state); } /************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlperandomize(mlpensemble* ensemble, ae_state *_state) { ae_int_t i; ae_int_t wcount; wcount = mlpgetweightscount(&ensemble->network, _state); for(i=0; i<=ensemble->ensemblesize*wcount-1; i++) { ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; } } /************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeproperties(mlpensemble* ensemble, ae_int_t* nin, ae_int_t* nout, ae_state *_state) { *nin = 0; *nout = 0; *nin = mlpgetinputscount(&ensemble->network, _state); *nout = mlpgetoutputscount(&ensemble->network, _state); } /************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ ae_bool mlpeissoftmax(mlpensemble* ensemble, ae_state *_state) { ae_bool result; result = mlpissoftmax(&ensemble->network, _state); return result; } /************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocess(mlpensemble* ensemble, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t i; ae_int_t es; ae_int_t wc; ae_int_t cc; double v; ae_int_t nout; if( y->cntnetwork, _state) ) { ae_vector_set_length(y, mlpgetoutputscount(&ensemble->network, _state), _state); } es = ensemble->ensemblesize; wc = mlpgetweightscount(&ensemble->network, _state); if( mlpissoftmax(&ensemble->network, _state) ) { cc = mlpgetinputscount(&ensemble->network, _state); } else { cc = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); } v = (double)1/(double)es; nout = mlpgetoutputscount(&ensemble->network, _state); for(i=0; i<=nout-1; i++) { y->ptr.p_double[i] = (double)(0); } for(i=0; i<=es-1; i++) { ae_v_move(&ensemble->network.weights.ptr.p_double[0], 1, &ensemble->weights.ptr.p_double[i*wc], 1, ae_v_len(0,wc-1)); ae_v_move(&ensemble->network.columnmeans.ptr.p_double[0], 1, &ensemble->columnmeans.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); ae_v_move(&ensemble->network.columnsigmas.ptr.p_double[0], 1, &ensemble->columnsigmas.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); mlpprocess(&ensemble->network, x, &ensemble->y, _state); ae_v_addd(&y->ptr.p_double[0], 1, &ensemble->y.ptr.p_double[0], 1, ae_v_len(0,nout-1), v); } } /************************************************************************* 'interactive' variant of MLPEProcess for languages like Python which support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocessi(mlpensemble* ensemble, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_vector_clear(y); mlpeprocess(ensemble, x, y, _state); } /************************************************************************* Calculation of all types of errors -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeallerrorsx(mlpensemble* ensemble, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, modelerrors* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t nin; ae_int_t nout; ae_bool iscls; ae_int_t srcidx; mlpbuffers *pbuf; ae_smart_ptr _pbuf; modelerrors rep0; modelerrors rep1; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state); _modelerrors_init(&rep0, _state); _modelerrors_init(&rep1, _state); /* * Get network information */ nin = mlpgetinputscount(&ensemble->network, _state); nout = mlpgetoutputscount(&ensemble->network, _state); iscls = mlpissoftmax(&ensemble->network, _state); /* * Retrieve buffer, prepare, process data, recycle buffer */ ae_shared_pool_retrieve(buf, &_pbuf, _state); if( iscls ) { dserrallocate(nout, &pbuf->tmp0, _state); } else { dserrallocate(-nout, &pbuf->tmp0, _state); } rvectorsetlengthatleast(&pbuf->x, nin, _state); rvectorsetlengthatleast(&pbuf->y, nout, _state); rvectorsetlengthatleast(&pbuf->desiredy, nout, _state); for(i=subset0; i<=subset1-1; i++) { srcidx = -1; if( subsettype==0 ) { srcidx = i; } if( subsettype==1 ) { srcidx = idx->ptr.p_int[i]; } ae_assert(srcidx>=0, "MLPEAllErrorsX: internal error", _state); if( datasettype==0 ) { ae_v_move(&pbuf->x.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,nin-1)); } if( datasettype==1 ) { sparsegetrow(sparsexy, srcidx, &pbuf->x, _state); } mlpeprocess(ensemble, &pbuf->x, &pbuf->y, _state); if( mlpissoftmax(&ensemble->network, _state) ) { if( datasettype==0 ) { pbuf->desiredy.ptr.p_double[0] = densexy->ptr.pp_double[srcidx][nin]; } if( datasettype==1 ) { pbuf->desiredy.ptr.p_double[0] = sparseget(sparsexy, srcidx, nin, _state); } } else { if( datasettype==0 ) { ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][nin], 1, ae_v_len(0,nout-1)); } if( datasettype==1 ) { for(j=0; j<=nout-1; j++) { pbuf->desiredy.ptr.p_double[j] = sparseget(sparsexy, srcidx, nin+j, _state); } } } dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); } dserrfinish(&pbuf->tmp0, _state); rep->relclserror = pbuf->tmp0.ptr.p_double[0]; rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log((double)(2), _state); rep->rmserror = pbuf->tmp0.ptr.p_double[2]; rep->avgerror = pbuf->tmp0.ptr.p_double[3]; rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; ae_shared_pool_recycle(buf, &_pbuf, _state); ae_frame_leave(_state); } /************************************************************************* Calculation of all types of errors on dataset given by sparse matrix -- ALGLIB -- Copyright 10.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpeallerrorssparse(mlpensemble* ensemble, sparsematrix* xy, ae_int_t npoints, double* relcls, double* avgce, double* rms, double* avg, double* avgrel, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector buf; ae_vector workx; ae_vector y; ae_vector dy; ae_int_t nin; ae_int_t nout; ae_frame_make(_state, &_frame_block); *relcls = 0; *avgce = 0; *rms = 0; *avg = 0; *avgrel = 0; ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&workx, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&dy, 0, DT_REAL, _state); nin = mlpgetinputscount(&ensemble->network, _state); nout = mlpgetoutputscount(&ensemble->network, _state); if( mlpissoftmax(&ensemble->network, _state) ) { ae_vector_set_length(&dy, 1, _state); dserrallocate(nout, &buf, _state); } else { ae_vector_set_length(&dy, nout, _state); dserrallocate(-nout, &buf, _state); } for(i=0; i<=npoints-1; i++) { sparsegetrow(xy, i, &workx, _state); mlpeprocess(ensemble, &workx, &y, _state); if( mlpissoftmax(&ensemble->network, _state) ) { dy.ptr.p_double[0] = workx.ptr.p_double[nin]; } else { ae_v_move(&dy.ptr.p_double[0], 1, &workx.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); } dserraccumulate(&buf, &y, &dy, _state); } dserrfinish(&buf, _state); *relcls = buf.ptr.p_double[0]; *avgce = buf.ptr.p_double[1]; *rms = buf.ptr.p_double[2]; *avg = buf.ptr.p_double[3]; *avgrel = buf.ptr.p_double[4]; ae_frame_leave(_state); } /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Works both for classifier betwork and for regression networks which are used as classifiers. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlperelclserror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; modelerrors rep; double result; ae_frame_make(_state, &_frame_block); _modelerrors_init(&rep, _state); mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); result = rep.relclserror; ae_frame_leave(_state); return result; } /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if ensemble solves regression task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgce(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; modelerrors rep; double result; ae_frame_make(_state, &_frame_block); _modelerrors_init(&rep, _state); mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); result = rep.avgce; ae_frame_leave(_state); return result; } /************************************************************************* RMS error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpermserror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; modelerrors rep; double result; ae_frame_make(_state, &_frame_block); _modelerrors_init(&rep, _state); mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); result = rep.rmserror; ae_frame_leave(_state); return result; } /************************************************************************* Average error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgerror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; modelerrors rep; double result; ae_frame_make(_state, &_frame_block); _modelerrors_init(&rep, _state); mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); result = rep.avgerror; ae_frame_leave(_state); return result; } /************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgrelerror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_frame _frame_block; modelerrors rep; double result; ae_frame_make(_state, &_frame_block); _modelerrors_init(&rep, _state); mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); result = rep.avgrelerror; ae_frame_leave(_state); return result; } /************************************************************************* Serializer: allocation -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ void mlpealloc(ae_serializer* s, mlpensemble* ensemble, ae_state *_state) { ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); ae_serializer_alloc_entry(s); allocrealarray(s, &ensemble->weights, -1, _state); allocrealarray(s, &ensemble->columnmeans, -1, _state); allocrealarray(s, &ensemble->columnsigmas, -1, _state); mlpalloc(s, &ensemble->network, _state); } /************************************************************************* Serializer: serialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpeserialize(ae_serializer* s, mlpensemble* ensemble, ae_state *_state) { ae_serializer_serialize_int(s, getmlpeserializationcode(_state), _state); ae_serializer_serialize_int(s, mlpe_mlpefirstversion, _state); ae_serializer_serialize_int(s, ensemble->ensemblesize, _state); serializerealarray(s, &ensemble->weights, -1, _state); serializerealarray(s, &ensemble->columnmeans, -1, _state); serializerealarray(s, &ensemble->columnsigmas, -1, _state); mlpserialize(s, &ensemble->network, _state); } /************************************************************************* Serializer: unserialization -- ALGLIB -- Copyright 14.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpeunserialize(ae_serializer* s, mlpensemble* ensemble, ae_state *_state) { ae_int_t i0; ae_int_t i1; _mlpensemble_clear(ensemble); /* * check correctness of header */ ae_serializer_unserialize_int(s, &i0, _state); ae_assert(i0==getmlpeserializationcode(_state), "MLPEUnserialize: stream header corrupted", _state); ae_serializer_unserialize_int(s, &i1, _state); ae_assert(i1==mlpe_mlpefirstversion, "MLPEUnserialize: stream header corrupted", _state); /* * Create network */ ae_serializer_unserialize_int(s, &ensemble->ensemblesize, _state); unserializerealarray(s, &ensemble->weights, _state); unserializerealarray(s, &ensemble->columnmeans, _state); unserializerealarray(s, &ensemble->columnsigmas, _state); mlpunserialize(s, &ensemble->network, _state); /* * Allocate termoraries */ ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); } void _mlpensemble_init(void* _p, ae_state *_state) { mlpensemble *p = (mlpensemble*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->weights, 0, DT_REAL, _state); ae_vector_init(&p->columnmeans, 0, DT_REAL, _state); ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state); _multilayerperceptron_init(&p->network, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); } void _mlpensemble_init_copy(void* _dst, void* _src, ae_state *_state) { mlpensemble *dst = (mlpensemble*)_dst; mlpensemble *src = (mlpensemble*)_src; dst->ensemblesize = src->ensemblesize; ae_vector_init_copy(&dst->weights, &src->weights, _state); ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state); ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state); _multilayerperceptron_init_copy(&dst->network, &src->network, _state); ae_vector_init_copy(&dst->y, &src->y, _state); } void _mlpensemble_clear(void* _p) { mlpensemble *p = (mlpensemble*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->weights); ae_vector_clear(&p->columnmeans); ae_vector_clear(&p->columnsigmas); _multilayerperceptron_clear(&p->network); ae_vector_clear(&p->y); } void _mlpensemble_destroy(void* _p) { mlpensemble *p = (mlpensemble*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->weights); ae_vector_destroy(&p->columnmeans); ae_vector_destroy(&p->columnsigmas); _multilayerperceptron_destroy(&p->network); ae_vector_destroy(&p->y); } /************************************************************************* Neural network training using modified Levenberg-Marquardt with exact Hessian calculation and regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for small and medium scale problems (hundreds of weights). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -9, if internal matrix inverse subroutine failed * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptrainlm(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; double lmsteptol; ae_int_t i; ae_int_t k; double v; double e; double enew; double xnorm2; double stepnorm; ae_vector g; ae_vector d; ae_matrix h; ae_matrix hmod; ae_matrix z; ae_bool spd; double nu; double lambdav; double lambdaup; double lambdadown; minlbfgsreport internalrep; minlbfgsstate state; ae_vector x; ae_vector y; ae_vector wbase; ae_vector wdir; ae_vector wt; ae_vector wx; ae_int_t pass; ae_vector wbest; double ebest; ae_int_t invinfo; matinvreport invrep; ae_int_t solverinfo; densesolverreport solverrep; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_matrix_init(&h, 0, 0, DT_REAL, _state); ae_matrix_init(&hmod, 0, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); _minlbfgsreport_init(&internalrep, _state); _minlbfgsstate_init(&state, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&wbase, 0, DT_REAL, _state); ae_vector_init(&wdir, 0, DT_REAL, _state); ae_vector_init(&wt, 0, DT_REAL, _state); ae_vector_init(&wx, 0, DT_REAL, _state); ae_vector_init(&wbest, 0, DT_REAL, _state); _matinvreport_init(&invrep, _state); _densesolverreport_init(&solverrep, _state); mlpproperties(network, &nin, &nout, &wcount, _state); lambdaup = (double)(10); lambdadown = 0.3; lmsteptol = 0.001; /* * Test for inputs */ if( npoints<=0||restarts<1 ) { *info = -1; ae_frame_leave(_state); return; } if( mlpissoftmax(network, _state) ) { for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } } decay = ae_maxreal(decay, mlptrain_mindecay, _state); *info = 2; /* * Initialize data */ rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; /* * General case. * Prepare task and network. Allocate space. */ mlpinitpreprocessor(network, xy, npoints, _state); ae_vector_set_length(&g, wcount-1+1, _state); ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); ae_matrix_set_length(&hmod, wcount-1+1, wcount-1+1, _state); ae_vector_set_length(&wbase, wcount-1+1, _state); ae_vector_set_length(&wdir, wcount-1+1, _state); ae_vector_set_length(&wbest, wcount-1+1, _state); ae_vector_set_length(&wt, wcount-1+1, _state); ae_vector_set_length(&wx, wcount-1+1, _state); ebest = ae_maxrealnumber; /* * Multiple passes */ for(pass=1; pass<=restarts; pass++) { /* * Initialize weights */ mlprandomize(network, _state); /* * First stage of the hybrid algorithm: LBFGS */ ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); minlbfgscreate(wcount, ae_minint(wcount, 5, _state), &wbase, &state, _state); minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), ae_maxint(25, wcount, _state), _state); while(minlbfgsiteration(&state, _state)) { /* * gradient */ ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); mlpgradbatch(network, xy, npoints, &state.f, &state.g, _state); /* * weight decay */ v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); state.f = state.f+0.5*decay*v; ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); /* * next iteration */ rep->ngrad = rep->ngrad+1; } minlbfgsresults(&state, &wbase, &internalrep, _state); ae_v_move(&network->weights.ptr.p_double[0], 1, &wbase.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); /* * Second stage of the hybrid algorithm: LM * * Initialize H with identity matrix, * G with gradient, * E with regularized error. */ mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); for(k=0; k<=wcount-1; k++) { h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; } rep->nhess = rep->nhess+1; lambdav = 0.001; nu = (double)(2); for(;;) { /* * 1. HMod = H+lambda*I * 2. Try to solve (H+Lambda*I)*dx = -g. * Increase lambda if left part is not positive definite. */ for(i=0; i<=wcount-1; i++) { ae_v_move(&hmod.ptr.pp_double[i][0], 1, &h.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); hmod.ptr.pp_double[i][i] = hmod.ptr.pp_double[i][i]+lambdav; } spd = spdmatrixcholesky(&hmod, wcount, ae_true, _state); rep->ncholesky = rep->ncholesky+1; if( !spd ) { lambdav = lambdav*lambdaup*nu; nu = nu*2; continue; } spdmatrixcholeskysolve(&hmod, wcount, ae_true, &g, &solverinfo, &solverrep, &wdir, _state); if( solverinfo<0 ) { lambdav = lambdav*lambdaup*nu; nu = nu*2; continue; } ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1); /* * Lambda found. * 1. Save old w in WBase * 1. Test some stopping criterions * 2. If error(w+wdir)>error(w), increase lambda */ ae_v_add(&network->weights.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); xnorm2 = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); stepnorm = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); stepnorm = ae_sqrt(stepnorm, _state); enew = mlperror(network, xy, npoints, _state)+0.5*decay*xnorm2; if( ae_fp_less(stepnorm,lmsteptol*(1+ae_sqrt(xnorm2, _state))) ) { break; } if( ae_fp_greater(enew,e) ) { lambdav = lambdav*lambdaup*nu; nu = nu*2; continue; } /* * Optimize using inv(cholesky(H)) as preconditioner */ rmatrixtrinverse(&hmod, wcount, ae_true, ae_false, &invinfo, &invrep, _state); if( invinfo<=0 ) { /* * if matrix can't be inverted then exit with errors * TODO: make WCount steps in direction suggested by HMod */ *info = -9; ae_frame_leave(_state); return; } ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); for(i=0; i<=wcount-1; i++) { wt.ptr.p_double[i] = (double)(0); } minlbfgscreatex(wcount, wcount, &wt, 1, 0.0, &state, _state); minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 5, _state); while(minlbfgsiteration(&state, _state)) { /* * gradient */ for(i=0; i<=wcount-1; i++) { v = ae_v_dotproduct(&state.x.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; } mlpgradbatch(network, xy, npoints, &state.f, &g, _state); for(i=0; i<=wcount-1; i++) { state.g.ptr.p_double[i] = (double)(0); } for(i=0; i<=wcount-1; i++) { v = g.ptr.p_double[i]; ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); } /* * weight decay * grad(x'*x) = A'*(x0+A*t) */ v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); state.f = state.f+0.5*decay*v; for(i=0; i<=wcount-1; i++) { v = decay*network->weights.ptr.p_double[i]; ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); } /* * next iteration */ rep->ngrad = rep->ngrad+1; } minlbfgsresults(&state, &wt, &internalrep, _state); /* * Accept new position. * Calculate Hessian */ for(i=0; i<=wcount-1; i++) { v = ae_v_dotproduct(&wt.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; } mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = e+0.5*decay*v; ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); for(k=0; k<=wcount-1; k++) { h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; } rep->nhess = rep->nhess+1; /* * Update lambda */ lambdav = lambdav*lambdadown; nu = (double)(2); } /* * update WBest */ v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = 0.5*decay*v+mlperror(network, xy, npoints, _state); if( ae_fp_less(e,ebest) ) { ebest = e; ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } } /* * copy WBest to output */ ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ae_frame_leave(_state); } /************************************************************************* Neural network training using L-BFGS algorithm with regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for problems of any dimensionality (memory requirements and step complexity are linear by weights number). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. MaxIts - stopping criterion. Algorithm stops after MaxIts iterations (NOT gradient calculations). Zero MaxIts means stopping when step is sufficiently small. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlptrainlbfgs(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t pass; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_vector w; ae_vector wbest; double e; double v; double ebest; minlbfgsreport internalrep; minlbfgsstate state; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&wbest, 0, DT_REAL, _state); _minlbfgsreport_init(&internalrep, _state); _minlbfgsstate_init(&state, _state); /* * Test inputs, parse flags, read network geometry */ if( ae_fp_eq(wstep,(double)(0))&&maxits==0 ) { *info = -8; ae_frame_leave(_state); return; } if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,(double)(0)))||maxits<0 ) { *info = -1; ae_frame_leave(_state); return; } mlpproperties(network, &nin, &nout, &wcount, _state); if( mlpissoftmax(network, _state) ) { for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } } decay = ae_maxreal(decay, mlptrain_mindecay, _state); *info = 2; /* * Prepare */ mlpinitpreprocessor(network, xy, npoints, _state); ae_vector_set_length(&w, wcount-1+1, _state); ae_vector_set_length(&wbest, wcount-1+1, _state); ebest = ae_maxrealnumber; /* * Multiple starts */ rep->ncholesky = 0; rep->nhess = 0; rep->ngrad = 0; for(pass=1; pass<=restarts; pass++) { /* * Process */ mlprandomize(network, _state); ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); minlbfgssetcond(&state, 0.0, 0.0, wstep, maxits, _state); while(minlbfgsiteration(&state, _state)) { ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); mlpgradnbatch(network, xy, npoints, &state.f, &state.g, _state); v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); state.f = state.f+0.5*decay*v; ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); rep->ngrad = rep->ngrad+1; } minlbfgsresults(&state, &w, &internalrep, _state); ae_v_move(&network->weights.ptr.p_double[0], 1, &w.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); /* * Compare with best */ v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = mlperrorn(network, xy, npoints, _state)+0.5*decay*v; if( ae_fp_less(e,ebest) ) { ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ebest = e; } } /* * The best network */ ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ae_frame_leave(_state); } /************************************************************************* Neural network training using early stopping (base algorithm - L-BFGS with regularization). INPUT PARAMETERS: Network - neural network with initialized geometry TrnXY - training set TrnSize - training set size, TrnSize>0 ValXY - validation set ValSize - validation set size, ValSize>0 Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts, either: * strictly positive number - algorithm make specified number of restarts from random position. * -1, in which case algorithm makes exactly one run from the initial state of the network (no randomization). If you don't know what Restarts to choose, choose one one the following: * -1 (deterministic start) * +1 (one random restart) * +5 (moderate amount of random restarts) OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1, ...). * 2, task has been solved, stopping criterion met - sufficiently small step size. Not expected (we use EARLY stopping) but possible and not an error. * 6, task has been solved, stopping criterion met - increasing of validation set error. Rep - training report NOTE: Algorithm stops if validation set error increases for a long enough or step size is small enought (there are task where validation set may decrease for eternity). In any case solution returned corresponds to the minimum of validation set error. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptraines(multilayerperceptron* network, /* Real */ ae_matrix* trnxy, ae_int_t trnsize, /* Real */ ae_matrix* valxy, ae_int_t valsize, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t pass; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_vector w; ae_vector wbest; double e; double v; double ebest; ae_vector wfinal; double efinal; ae_int_t itcnt; ae_int_t itbest; minlbfgsreport internalrep; minlbfgsstate state; double wstep; ae_bool needrandomization; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&wbest, 0, DT_REAL, _state); ae_vector_init(&wfinal, 0, DT_REAL, _state); _minlbfgsreport_init(&internalrep, _state); _minlbfgsstate_init(&state, _state); wstep = 0.001; /* * Test inputs, parse flags, read network geometry */ if( ((trnsize<=0||valsize<=0)||(restarts<1&&restarts!=-1))||ae_fp_less(decay,(double)(0)) ) { *info = -1; ae_frame_leave(_state); return; } if( restarts==-1 ) { needrandomization = ae_false; restarts = 1; } else { needrandomization = ae_true; } mlpproperties(network, &nin, &nout, &wcount, _state); if( mlpissoftmax(network, _state) ) { for(i=0; i<=trnsize-1; i++) { if( ae_round(trnxy->ptr.pp_double[i][nin], _state)<0||ae_round(trnxy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } for(i=0; i<=valsize-1; i++) { if( ae_round(valxy->ptr.pp_double[i][nin], _state)<0||ae_round(valxy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } } *info = 2; /* * Prepare */ mlpinitpreprocessor(network, trnxy, trnsize, _state); ae_vector_set_length(&w, wcount-1+1, _state); ae_vector_set_length(&wbest, wcount-1+1, _state); ae_vector_set_length(&wfinal, wcount-1+1, _state); efinal = ae_maxrealnumber; for(i=0; i<=wcount-1; i++) { wfinal.ptr.p_double[i] = (double)(0); } /* * Multiple starts */ rep->ncholesky = 0; rep->nhess = 0; rep->ngrad = 0; for(pass=1; pass<=restarts; pass++) { /* * Process */ if( needrandomization ) { mlprandomize(network, _state); } ebest = mlperror(network, valxy, valsize, _state); ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); itbest = 0; itcnt = 0; ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); minlbfgssetcond(&state, 0.0, 0.0, wstep, 0, _state); minlbfgssetxrep(&state, ae_true, _state); while(minlbfgsiteration(&state, _state)) { /* * Calculate gradient */ if( state.needfg ) { ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); mlpgradnbatch(network, trnxy, trnsize, &state.f, &state.g, _state); v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); state.f = state.f+0.5*decay*v; ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); rep->ngrad = rep->ngrad+1; } /* * Validation set */ if( state.xupdated ) { ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = mlperror(network, valxy, valsize, _state); if( ae_fp_less(e,ebest) ) { ebest = e; ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); itbest = itcnt; } if( itcnt>30&&ae_fp_greater((double)(itcnt),1.5*itbest) ) { *info = 6; break; } itcnt = itcnt+1; } } minlbfgsresults(&state, &w, &internalrep, _state); /* * Compare with final answer */ if( ae_fp_less(ebest,efinal) ) { ae_v_move(&wfinal.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); efinal = ebest; } } /* * The best network */ ae_v_move(&network->weights.ptr.p_double[0], 1, &wfinal.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ae_frame_leave(_state); } /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - L-BFGS. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlbfgs(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t foldscount, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state) { *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(cvrep); mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_false, wstep, maxits, info, rep, cvrep, _state); } /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - Levenberg-Marquardt. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlm(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t foldscount, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state) { *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(cvrep); mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_true, 0.0, 0, info, rep, cvrep, _state); } /************************************************************************* This function estimates generalization error using cross-validation on the current dataset with current training settings. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * FoldsCount cross-validation rounds (always) ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. Network is not changed during cross- validation and is not trained - it is used only as representative of its architecture. I.e., we estimate generalization properties of ARCHITECTURE, not some specific network. NRestarts - number of restarts, >=0: * NRestarts>0 means that for each cross-validation round specified number of random restarts is performed, with best network being chosen after training. * NRestarts=0 is same as NRestarts=1 FoldsCount - number of folds in k-fold cross-validation: * 2<=FoldsCount<=size of dataset * recommended value: 10. * values larger than dataset size will be silently truncated down to dataset size OUTPUT PARAMETERS: Rep - structure which contains cross-validation estimates: * Rep.RelCLSError - fraction of misclassified cases. * Rep.AvgCE - acerage cross-entropy * Rep.RMSError - root-mean-square error * Rep.AvgError - average error * Rep.AvgRelError - average relative error NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or subset with only one point was given, zeros are returned as estimates. NOTE: this method performs FoldsCount cross-validation rounds, each one with NRestarts random starts. Thus, FoldsCount*NRestarts networks are trained in total. NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError contain errors in prediction of posterior probabilities. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcv(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_shared_pool pooldatacv; mlpparallelizationcv datacv; mlpparallelizationcv *sdatacv; ae_smart_ptr _sdatacv; ae_matrix cvy; ae_vector folds; ae_vector buf; ae_vector dy; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t rowsize; ae_int_t ntype; ae_int_t ttype; ae_int_t i; ae_int_t j; ae_int_t k; hqrndstate rs; ae_frame_make(_state, &_frame_block); _mlpreport_clear(rep); ae_shared_pool_init(&pooldatacv, _state); _mlpparallelizationcv_init(&datacv, _state); ae_smart_ptr_init(&_sdatacv, (void**)&sdatacv, _state); ae_matrix_init(&cvy, 0, 0, DT_REAL, _state); ae_vector_init(&folds, 0, DT_INT, _state); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&dy, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); if( !mlpissoftmax(network, _state) ) { ntype = 0; } else { ntype = 1; } if( s->rcpar ) { ttype = 0; } else { ttype = 1; } ae_assert(ntype==ttype, "MLPKFoldCV: type of input network is not similar to network type in trainer object", _state); ae_assert(s->npoints>=0, "MLPKFoldCV: possible trainer S is not initialized(S.NPoints<0)", _state); mlpproperties(network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPKFoldCV: number of inputs in trainer is not equal to number of inputs in network", _state); ae_assert(s->nout==nout, "MLPKFoldCV: number of outputs in trainer is not equal to number of outputs in network", _state); ae_assert(nrestarts>=0, "MLPKFoldCV: NRestarts<0", _state); ae_assert(foldscount>=2, "MLPKFoldCV: FoldsCount<2", _state); if( foldscount>s->npoints ) { foldscount = s->npoints; } rep->relclserror = (double)(0); rep->avgce = (double)(0); rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); hqrndrandomize(&rs, _state); rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; if( s->npoints==0||s->npoints==1 ) { ae_frame_leave(_state); return; } /* * Read network geometry, test parameters */ if( s->rcpar ) { rowsize = nin+nout; ae_vector_set_length(&dy, nout, _state); dserrallocate(-nout, &buf, _state); } else { rowsize = nin+1; ae_vector_set_length(&dy, 1, _state); dserrallocate(nout, &buf, _state); } /* * Folds */ ae_vector_set_length(&folds, s->npoints, _state); for(i=0; i<=s->npoints-1; i++) { folds.ptr.p_int[i] = i*foldscount/s->npoints; } for(i=0; i<=s->npoints-2; i++) { j = i+hqrnduniformi(&rs, s->npoints-i, _state); if( j!=i ) { k = folds.ptr.p_int[i]; folds.ptr.p_int[i] = folds.ptr.p_int[j]; folds.ptr.p_int[j] = k; } } ae_matrix_set_length(&cvy, s->npoints, nout, _state); /* * Initialize SEED-value for shared pool */ datacv.ngrad = 0; mlpcopy(network, &datacv.network, _state); ae_vector_set_length(&datacv.subset, s->npoints, _state); ae_vector_set_length(&datacv.xyrow, rowsize, _state); ae_vector_set_length(&datacv.y, nout, _state); /* * Create shared pool */ ae_shared_pool_set_seed(&pooldatacv, &datacv, sizeof(datacv), _mlpparallelizationcv_init, _mlpparallelizationcv_init_copy, _mlpparallelizationcv_destroy, _state); /* * Parallelization */ mlptrain_mthreadcv(s, rowsize, nrestarts, &folds, 0, foldscount, &cvy, &pooldatacv, _state); /* * Calculate value for NGrad */ ae_shared_pool_first_recycled(&pooldatacv, &_sdatacv, _state); while(sdatacv!=NULL) { rep->ngrad = rep->ngrad+sdatacv->ngrad; ae_shared_pool_next_recycled(&pooldatacv, &_sdatacv, _state); } /* * Connect of results and calculate cross-validation error */ for(i=0; i<=s->npoints-1; i++) { if( s->datatype==0 ) { ae_v_move(&datacv.xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); } if( s->datatype==1 ) { sparsegetrow(&s->sparsexy, i, &datacv.xyrow, _state); } ae_v_move(&datacv.y.ptr.p_double[0], 1, &cvy.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1)); if( s->rcpar ) { ae_v_move(&dy.ptr.p_double[0], 1, &datacv.xyrow.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); } else { dy.ptr.p_double[0] = datacv.xyrow.ptr.p_double[nin]; } dserraccumulate(&buf, &datacv.y, &dy, _state); } dserrfinish(&buf, _state); rep->relclserror = buf.ptr.p_double[0]; rep->avgce = buf.ptr.p_double[1]; rep->rmserror = buf.ptr.p_double[2]; rep->avgerror = buf.ptr.p_double[3]; rep->avgrelerror = buf.ptr.p_double[4]; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlpkfoldcv(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport* rep, ae_state *_state) { mlpkfoldcv(s,network,nrestarts,foldscount,rep, _state); } /************************************************************************* Creation of the network trainer object for regression networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NOut - number of outputs, NOut>=1 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any regression network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainer(ae_int_t nin, ae_int_t nout, mlptrainer* s, ae_state *_state) { _mlptrainer_clear(s); ae_assert(nin>=1, "MLPCreateTrainer: NIn<1.", _state); ae_assert(nout>=1, "MLPCreateTrainer: NOut<1.", _state); s->nin = nin; s->nout = nout; s->rcpar = ae_true; s->lbfgsfactor = mlptrain_defaultlbfgsfactor; s->decay = 1.0E-6; mlpsetcond(s, (double)(0), 0, _state); s->datatype = 0; s->npoints = 0; mlpsetalgobatch(s, _state); } /************************************************************************* Creation of the network trainer object for classification networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any classification network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainercls(ae_int_t nin, ae_int_t nclasses, mlptrainer* s, ae_state *_state) { _mlptrainer_clear(s); ae_assert(nin>=1, "MLPCreateTrainerCls: NIn<1.", _state); ae_assert(nclasses>=2, "MLPCreateTrainerCls: NClasses<2.", _state); s->nin = nin; s->nout = nclasses; s->rcpar = ae_false; s->lbfgsfactor = mlptrain_defaultlbfgsfactor; s->decay = 1.0E-6; mlpsetcond(s, (double)(0), 0, _state); s->datatype = 0; s->npoints = 0; mlpsetalgobatch(s, _state); } /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user. INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. NPoints - points count, >=0. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdataset(mlptrainer* s, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state) { ae_int_t ndim; ae_int_t i; ae_int_t j; ae_assert(s->nin>=1, "MLPSetDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); ae_assert(npoints>=0, "MLPSetDataset: NPoint<0", _state); ae_assert(npoints<=xy->rows, "MLPSetDataset: invalid size of matrix XY(NPoint more then rows of matrix XY)", _state); s->datatype = 0; s->npoints = npoints; if( npoints==0 ) { return; } if( s->rcpar ) { ae_assert(s->nout>=1, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); ndim = s->nin+s->nout; ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); } else { ae_assert(s->nout>=2, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); ndim = s->nin+1; ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); for(i=0; i<=npoints-1; i++) { ae_assert(ae_round(xy->ptr.pp_double[i][s->nin], _state)>=0&&ae_round(xy->ptr.pp_double[i][s->nin], _state)nout, "MLPSetDataset: invalid parameter XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); } } rmatrixsetlengthatleast(&s->densexy, npoints, ndim, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=ndim-1; j++) { s->densexy.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; } } } /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user (sparse matrix is used to store dataset). INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Any sparse storage format can be used: Hash-table, CRS... NPoints - points count, >=0 DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetsparsedataset(mlptrainer* s, sparsematrix* xy, ae_int_t npoints, ae_state *_state) { double v; ae_int_t t0; ae_int_t t1; ae_int_t i; ae_int_t j; /* * Check correctness of the data */ ae_assert(s->nin>0, "MLPSetSparseDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); ae_assert(npoints>=0, "MLPSetSparseDataset: NPoint<0", _state); ae_assert(npoints<=sparsegetnrows(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(NPoint more then rows of matrix XY)", _state); if( npoints>0 ) { t0 = 0; t1 = 0; if( s->rcpar ) { ae_assert(s->nout>=1, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); ae_assert(s->nin+s->nout<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) { if( inin+s->nout ) { ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); } } } else { ae_assert(s->nout>=2, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); ae_assert(s->nin+1<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) { if( inin ) { if( j!=s->nin ) { ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); } else { ae_assert((ae_isfinite(v, _state)&&ae_round(v, _state)>=0)&&ae_round(v, _state)nout, "MLPSetSparseDataset: invalid sparse matrix XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); } } } } } /* * Set dataset */ s->datatype = 1; s->npoints = npoints; sparsecopytocrs(xy, &s->sparsexy, _state); } /************************************************************************* This function sets weight decay coefficient which is used for training. INPUT PARAMETERS: S - trainer object Decay - weight decay coefficient, >=0. Weight decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 1.0E-3. Weight decay can be set to zero, in this case network is trained without weight decay. NOTE: by default network uses some small nonzero value for weight decay. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state) { ae_assert(ae_isfinite(decay, _state), "MLPSetDecay: parameter Decay contains Infinite or NaN.", _state); ae_assert(ae_fp_greater_eq(decay,(double)(0)), "MLPSetDecay: Decay<0.", _state); s->decay = decay; } /************************************************************************* This function sets stopping criteria for the optimizer. INPUT PARAMETERS: S - trainer object WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. WStep>=0. MaxIts - stopping criterion. Algorithm stops after MaxIts epochs (full passes over entire dataset). Zero MaxIts means stopping when step is sufficiently small. MaxIts>=0. NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also used when MLPSetCond() is called with WStep=0 and MaxIts=0. NOTE: these stopping criteria are used for all kinds of neural training - from "conventional" networks to early stopping ensembles. When used for "conventional" networks, they are used as the only stopping criteria. When combined with early stopping, they used as ADDITIONAL stopping criteria which can terminate early stopping algorithm. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetcond(mlptrainer* s, double wstep, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(wstep, _state), "MLPSetCond: parameter WStep contains Infinite or NaN.", _state); ae_assert(ae_fp_greater_eq(wstep,(double)(0)), "MLPSetCond: WStep<0.", _state); ae_assert(maxits>=0, "MLPSetCond: MaxIts<0.", _state); if( ae_fp_neq(wstep,(double)(0))||maxits!=0 ) { s->wstep = wstep; s->maxits = maxits; } else { s->wstep = 0.005; s->maxits = 0; } } /************************************************************************* This function sets training algorithm: batch training using L-BFGS will be used. This algorithm: * the most robust for small-scale problems, but may be too slow for large scale ones. * perfoms full pass through the dataset before performing step * uses conditions specified by MLPSetCond() for stopping * is default one used by trainer object INPUT PARAMETERS: S - trainer object -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetalgobatch(mlptrainer* s, ae_state *_state) { s->algokind = 0; } /************************************************************************* This function trains neural network passed to this function, using current dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) and current training settings. Training from NRestarts random starting positions is performed, best network is chosen. Training is performed using current training algorithm. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed, best network is chosen after training * NRestarts=0 means that current state of the network is used for training. OUTPUT PARAMETERS: Network - trained network NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), network is filled by zero values. Same behavior for functions MLPStartTraining and MLPContinueTraining. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainnetwork(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntype; ae_int_t ttype; ae_shared_pool trnpool; ae_frame_make(_state, &_frame_block); _mlpreport_clear(rep); ae_shared_pool_init(&trnpool, _state); ae_assert(s->npoints>=0, "MLPTrainNetwork: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); if( !mlpissoftmax(network, _state) ) { ntype = 0; } else { ntype = 1; } if( s->rcpar ) { ttype = 0; } else { ttype = 1; } ae_assert(ntype==ttype, "MLPTrainNetwork: type of input network is not similar to network type in trainer object", _state); mlpproperties(network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPTrainNetwork: number of inputs in trainer is not equal to number of inputs in network", _state); ae_assert(s->nout==nout, "MLPTrainNetwork: number of outputs in trainer is not equal to number of outputs in network", _state); ae_assert(nrestarts>=0, "MLPTrainNetwork: NRestarts<0.", _state); /* * Train */ mlptrain_mlptrainnetworkx(s, nrestarts, -1, &s->subset, -1, &s->subset, 0, network, rep, ae_true, &trnpool, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlptrainnetwork(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, mlpreport* rep, ae_state *_state) { mlptrainnetwork(s,network,nrestarts,rep, _state); } /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. After call to this function trainer object remembers network and is ready to train it. However, no training is performed until first call to MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() will advance training progress one iteration further. EXAMPLE: > > ...initialize network and trainer object.... > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > ...visualize training progress... > INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. RandomStart - randomize network before training or not: * True means that network is randomized and its initial state (one which was passed to the trainer object) is lost. * False means that training is started from the current state of the network OUTPUT PARAMETERS: Network - neural network which is ready to training (weights are initialized, preprocessor is initialized using current training set) NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpstarttraining(mlptrainer* s, multilayerperceptron* network, ae_bool randomstart, ae_state *_state) { ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntype; ae_int_t ttype; ae_assert(s->npoints>=0, "MLPStartTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); if( !mlpissoftmax(network, _state) ) { ntype = 0; } else { ntype = 1; } if( s->rcpar ) { ttype = 0; } else { ttype = 1; } ae_assert(ntype==ttype, "MLPStartTraining: type of input network is not similar to network type in trainer object", _state); mlpproperties(network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPStartTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); ae_assert(s->nout==nout, "MLPStartTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); /* * Initialize temporaries */ mlptrain_initmlptrnsession(network, randomstart, s, &s->session, _state); /* * Train network */ mlptrain_mlpstarttrainingx(s, randomstart, -1, &s->subset, -1, &s->session, _state); /* * Update network */ mlpcopytunableparameters(&s->session.network, network, _state); } /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. This function performs one more iteration of the training and returns either True (training continues) or False (training stopped). In case True was returned, Network weights are updated according to the current state of the optimization progress. In case False was returned, no additional updates is performed (previous update of the network weights moved us to the final point, and no additional updates is needed). EXAMPLE: > > [initialize network and trainer object] > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > [visualize training progress] > INPUT PARAMETERS: S - trainer object Network - neural network structure, which is used to store current state of the training process. OUTPUT PARAMETERS: Network - weights of the neural network are rewritten by the current approximation. NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. NOTE: It is expected that Network is the same one which was passed to MLPStartTraining() function. However, THIS function checks only following: * that number of network inputs is consistent with trainer object settings * that number of network outputs/classes is consistent with trainer object settings * that number of network weights is the same as number of weights in the network passed to MLPStartTraining() function Exception is thrown when these conditions are violated. It is also expected that you do not change state of the network on your own - the only party who has right to change network during its training is a trainer object. Any attempt to interfere with trainer may lead to unpredictable results. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ ae_bool mlpcontinuetraining(mlptrainer* s, multilayerperceptron* network, ae_state *_state) { ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntype; ae_int_t ttype; ae_bool result; ae_assert(s->npoints>=0, "MLPContinueTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); if( s->rcpar ) { ttype = 0; } else { ttype = 1; } if( !mlpissoftmax(network, _state) ) { ntype = 0; } else { ntype = 1; } ae_assert(ntype==ttype, "MLPContinueTraining: type of input network is not similar to network type in trainer object.", _state); mlpproperties(network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPContinueTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); ae_assert(s->nout==nout, "MLPContinueTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); result = mlptrain_mlpcontinuetrainingx(s, &s->subset, -1, &s->ngradbatch, &s->session, _state); if( result ) { ae_v_move(&network->weights.ptr.p_double[0], 1, &s->session.network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_mlpcontinuetraining(mlptrainer* s, multilayerperceptron* network, ae_state *_state) { return mlpcontinuetraining(s,network, _state); } /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). Modified Levenberg-Marquardt algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglm(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state) { *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(ooberrors); mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, 0.0, 0, ae_true, info, rep, ooberrors, _state); } /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). L-BFGS algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglbfgs(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state) { *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(ooberrors); mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, wstep, maxits, ae_false, info, rep, ooberrors, _state); } /************************************************************************* Training neural networks ensemble using early stopping. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 6, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlpetraines(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t k; ae_int_t ccount; ae_int_t pcount; ae_matrix trnxy; ae_matrix valxy; ae_int_t trnsize; ae_int_t valsize; ae_int_t tmpinfo; mlpreport tmprep; modelerrors moderr; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); ae_matrix_init(&trnxy, 0, 0, DT_REAL, _state); ae_matrix_init(&valxy, 0, 0, DT_REAL, _state); _mlpreport_init(&tmprep, _state); _modelerrors_init(&moderr, _state); nin = mlpgetinputscount(&ensemble->network, _state); nout = mlpgetoutputscount(&ensemble->network, _state); wcount = mlpgetweightscount(&ensemble->network, _state); if( (npoints<2||restarts<1)||ae_fp_less(decay,(double)(0)) ) { *info = -1; ae_frame_leave(_state); return; } if( mlpissoftmax(&ensemble->network, _state) ) { for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } } *info = 6; /* * allocate */ if( mlpissoftmax(&ensemble->network, _state) ) { ccount = nin+1; pcount = nin; } else { ccount = nin+nout; pcount = nin+nout; } ae_matrix_set_length(&trnxy, npoints, ccount, _state); ae_matrix_set_length(&valxy, npoints, ccount, _state); rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; /* * train networks */ for(k=0; k<=ensemble->ensemblesize-1; k++) { /* * Split set */ do { trnsize = 0; valsize = 0; for(i=0; i<=npoints-1; i++) { if( ae_fp_less(ae_randomreal(_state),0.66) ) { /* * Assign sample to training set */ ae_v_move(&trnxy.ptr.pp_double[trnsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); trnsize = trnsize+1; } else { /* * Assign sample to validation set */ ae_v_move(&valxy.ptr.pp_double[valsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); valsize = valsize+1; } } } while(!(trnsize!=0&&valsize!=0)); /* * Train */ mlptraines(&ensemble->network, &trnxy, trnsize, &valxy, valsize, decay, restarts, &tmpinfo, &tmprep, _state); if( tmpinfo<0 ) { *info = tmpinfo; ae_frame_leave(_state); return; } /* * save results */ ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); rep->ngrad = rep->ngrad+tmprep.ngrad; rep->nhess = rep->nhess+tmprep.nhess; rep->ncholesky = rep->ncholesky+tmprep.ncholesky; } mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &moderr, _state); rep->relclserror = moderr.relclserror; rep->avgce = moderr.avgce; rep->rmserror = moderr.rmserror; rep->avgerror = moderr.avgerror; rep->avgrelerror = moderr.avgrelerror; ae_frame_leave(_state); } /************************************************************************* This function trains neural network ensemble passed to this function using current dataset and early stopping training algorithm. Each early stopping round performs NRestarts random restarts (thus, EnsembleSize*NRestarts training rounds is performed in total). FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * EnsembleSize training sessions performed for each of ensemble ! members (always parallelized) ! * NRestarts training sessions performed within each of training ! sessions (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object; Ensemble - neural network ensemble. It must have same number of inputs and outputs/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed during each ES round; * NRestarts=0 is silently replaced by 1. OUTPUT PARAMETERS: Ensemble - trained ensemble; Rep - it contains all type of errors. NOTE: this training method uses BOTH early stopping and weight decay! So, you should select weight decay before starting training just as you select it before training "conventional" networks. NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or single-point dataset was passed, ensemble is filled by zero values. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 22.08.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainensemblees(mlptrainer* s, mlpensemble* ensemble, ae_int_t nrestarts, mlpreport* rep, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t ntype; ae_int_t ttype; ae_shared_pool esessions; sinteger sgrad; modelerrors tmprep; ae_frame_make(_state, &_frame_block); _mlpreport_clear(rep); ae_shared_pool_init(&esessions, _state); _sinteger_init(&sgrad, _state); _modelerrors_init(&tmprep, _state); ae_assert(s->npoints>=0, "MLPTrainEnsembleES: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); if( !mlpeissoftmax(ensemble, _state) ) { ntype = 0; } else { ntype = 1; } if( s->rcpar ) { ttype = 0; } else { ttype = 1; } ae_assert(ntype==ttype, "MLPTrainEnsembleES: internal error - type of input network is not similar to network type in trainer object", _state); nin = mlpgetinputscount(&ensemble->network, _state); ae_assert(s->nin==nin, "MLPTrainEnsembleES: number of inputs in trainer is not equal to number of inputs in ensemble network", _state); nout = mlpgetoutputscount(&ensemble->network, _state); ae_assert(s->nout==nout, "MLPTrainEnsembleES: number of outputs in trainer is not equal to number of outputs in ensemble network", _state); ae_assert(nrestarts>=0, "MLPTrainEnsembleES: NRestarts<0.", _state); /* * Initialize parameter Rep */ rep->relclserror = (double)(0); rep->avgce = (double)(0); rep->rmserror = (double)(0); rep->avgerror = (double)(0); rep->avgrelerror = (double)(0); rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; /* * Allocate */ ivectorsetlengthatleast(&s->subset, s->npoints, _state); ivectorsetlengthatleast(&s->valsubset, s->npoints, _state); /* * Start training * * NOTE: ESessions is not initialized because MLPTrainEnsembleX * needs uninitialized pool. */ sgrad.val = 0; mlptrain_mlptrainensemblex(s, ensemble, 0, ensemble->ensemblesize, nrestarts, 0, &sgrad, ae_true, &esessions, _state); rep->ngrad = sgrad.val; /* * Calculate errors. */ if( s->datatype==0 ) { mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 0, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); } if( s->datatype==1 ) { mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 1, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); } rep->relclserror = tmprep.relclserror; rep->avgce = tmprep.avgce; rep->rmserror = tmprep.rmserror; rep->avgerror = tmprep.avgerror; rep->avgrelerror = tmprep.avgrelerror; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_mlptrainensemblees(mlptrainer* s, mlpensemble* ensemble, ae_int_t nrestarts, mlpreport* rep, ae_state *_state) { mlptrainensemblees(s,ensemble,nrestarts,rep, _state); } /************************************************************************* Internal cross-validation subroutine *************************************************************************/ static void mlptrain_mlpkfoldcvgeneral(multilayerperceptron* n, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t foldscount, ae_bool lmalgorithm, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t fold; ae_int_t j; ae_int_t k; multilayerperceptron network; ae_int_t nin; ae_int_t nout; ae_int_t rowlen; ae_int_t wcount; ae_int_t nclasses; ae_int_t tssize; ae_int_t cvssize; ae_matrix cvset; ae_matrix testset; ae_vector folds; ae_int_t relcnt; mlpreport internalrep; ae_vector x; ae_vector y; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(cvrep); _multilayerperceptron_init(&network, _state); ae_matrix_init(&cvset, 0, 0, DT_REAL, _state); ae_matrix_init(&testset, 0, 0, DT_REAL, _state); ae_vector_init(&folds, 0, DT_INT, _state); _mlpreport_init(&internalrep, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); /* * Read network geometry, test parameters */ mlpproperties(n, &nin, &nout, &wcount, _state); if( mlpissoftmax(n, _state) ) { nclasses = nout; rowlen = nin+1; } else { nclasses = -nout; rowlen = nin+nout; } if( (npoints<=0||foldscount<2)||foldscount>npoints ) { *info = -1; ae_frame_leave(_state); return; } mlpcopy(n, &network, _state); /* * K-fold out cross-validation. * First, estimate generalization error */ ae_matrix_set_length(&testset, npoints-1+1, rowlen-1+1, _state); ae_matrix_set_length(&cvset, npoints-1+1, rowlen-1+1, _state); ae_vector_set_length(&x, nin-1+1, _state); ae_vector_set_length(&y, nout-1+1, _state); mlptrain_mlpkfoldsplit(xy, npoints, nclasses, foldscount, ae_false, &folds, _state); cvrep->relclserror = (double)(0); cvrep->avgce = (double)(0); cvrep->rmserror = (double)(0); cvrep->avgerror = (double)(0); cvrep->avgrelerror = (double)(0); rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; relcnt = 0; for(fold=0; fold<=foldscount-1; fold++) { /* * Separate set */ tssize = 0; cvssize = 0; for(i=0; i<=npoints-1; i++) { if( folds.ptr.p_int[i]==fold ) { ae_v_move(&testset.ptr.pp_double[tssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); tssize = tssize+1; } else { ae_v_move(&cvset.ptr.pp_double[cvssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); cvssize = cvssize+1; } } /* * Train on CV training set */ if( lmalgorithm ) { mlptrainlm(&network, &cvset, cvssize, decay, restarts, info, &internalrep, _state); } else { mlptrainlbfgs(&network, &cvset, cvssize, decay, restarts, wstep, maxits, info, &internalrep, _state); } if( *info<0 ) { cvrep->relclserror = (double)(0); cvrep->avgce = (double)(0); cvrep->rmserror = (double)(0); cvrep->avgerror = (double)(0); cvrep->avgrelerror = (double)(0); ae_frame_leave(_state); return; } rep->ngrad = rep->ngrad+internalrep.ngrad; rep->nhess = rep->nhess+internalrep.nhess; rep->ncholesky = rep->ncholesky+internalrep.ncholesky; /* * Estimate error using CV test set */ if( mlpissoftmax(&network, _state) ) { /* * classification-only code */ cvrep->relclserror = cvrep->relclserror+mlpclserror(&network, &testset, tssize, _state); cvrep->avgce = cvrep->avgce+mlperrorn(&network, &testset, tssize, _state); } for(i=0; i<=tssize-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &testset.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); mlpprocess(&network, &x, &y, _state); if( mlpissoftmax(&network, _state) ) { /* * Classification-specific code */ k = ae_round(testset.ptr.pp_double[i][nin], _state); for(j=0; j<=nout-1; j++) { if( j==k ) { cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-1, _state); cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-1, _state); cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs(y.ptr.p_double[j]-1, _state); relcnt = relcnt+1; } else { cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j], _state); cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j], _state); } } } else { /* * Regression-specific code */ for(j=0; j<=nout-1; j++) { cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); if( ae_fp_neq(testset.ptr.pp_double[i][nin+j],(double)(0)) ) { cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs((y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j])/testset.ptr.pp_double[i][nin+j], _state); relcnt = relcnt+1; } } } } } if( mlpissoftmax(&network, _state) ) { cvrep->relclserror = cvrep->relclserror/npoints; cvrep->avgce = cvrep->avgce/(ae_log((double)(2), _state)*npoints); } cvrep->rmserror = ae_sqrt(cvrep->rmserror/(npoints*nout), _state); cvrep->avgerror = cvrep->avgerror/(npoints*nout); if( relcnt>0 ) { cvrep->avgrelerror = cvrep->avgrelerror/relcnt; } *info = 1; ae_frame_leave(_state); } /************************************************************************* Subroutine prepares K-fold split of the training set. NOTES: "NClasses>0" means that we have classification task. "NClasses<0" means regression task with -NClasses real outputs. *************************************************************************/ static void mlptrain_mlpkfoldsplit(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nclasses, ae_int_t foldscount, ae_bool stratifiedsplits, /* Integer */ ae_vector* folds, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_vector_clear(folds); _hqrndstate_init(&rs, _state); /* * test parameters */ ae_assert(npoints>0, "MLPKFoldSplit: wrong NPoints!", _state); ae_assert(nclasses>1||nclasses<0, "MLPKFoldSplit: wrong NClasses!", _state); ae_assert(foldscount>=2&&foldscount<=npoints, "MLPKFoldSplit: wrong FoldsCount!", _state); ae_assert(!stratifiedsplits, "MLPKFoldSplit: stratified splits are not supported!", _state); /* * Folds */ hqrndrandomize(&rs, _state); ae_vector_set_length(folds, npoints-1+1, _state); for(i=0; i<=npoints-1; i++) { folds->ptr.p_int[i] = i*foldscount/npoints; } for(i=0; i<=npoints-2; i++) { j = i+hqrnduniformi(&rs, npoints-i, _state); if( j!=i ) { k = folds->ptr.p_int[i]; folds->ptr.p_int[i] = folds->ptr.p_int[j]; folds->ptr.p_int[j] = k; } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine for parallelization function MLPFoldCV. INPUT PARAMETERS: S - trainer object; RowSize - row size(eitherNIn+NOut or NIn+1); NRestarts - number of restarts(>=0); Folds - cross-validation set; Fold - the number of first cross-validation(>=0); DFold - the number of second cross-validation(>=Fold+1); CVY - parameter which stores the result is returned by network, training on I-th cross-validation set. It has to be preallocated. PoolDataCV- parameter for parallelization. NOTE: There are no checks on the parameters correctness. -- ALGLIB -- Copyright 25.09.2012 by Bochkanov Sergey *************************************************************************/ static void mlptrain_mthreadcv(mlptrainer* s, ae_int_t rowsize, ae_int_t nrestarts, /* Integer */ ae_vector* folds, ae_int_t fold, ae_int_t dfold, /* Real */ ae_matrix* cvy, ae_shared_pool* pooldatacv, ae_state *_state) { ae_frame _frame_block; mlpparallelizationcv *datacv; ae_smart_ptr _datacv; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_datacv, (void**)&datacv, _state); if( fold==dfold-1 ) { /* * Separate set */ ae_shared_pool_retrieve(pooldatacv, &_datacv, _state); datacv->subsetsize = 0; for(i=0; i<=s->npoints-1; i++) { if( folds->ptr.p_int[i]!=fold ) { datacv->subset.ptr.p_int[datacv->subsetsize] = i; datacv->subsetsize = datacv->subsetsize+1; } } /* * Train on CV training set */ mlptrain_mlptrainnetworkx(s, nrestarts, -1, &datacv->subset, datacv->subsetsize, &datacv->subset, 0, &datacv->network, &datacv->rep, ae_true, &datacv->trnpool, _state); datacv->ngrad = datacv->ngrad+datacv->rep.ngrad; /* * Estimate error using CV test set */ for(i=0; i<=s->npoints-1; i++) { if( folds->ptr.p_int[i]==fold ) { if( s->datatype==0 ) { ae_v_move(&datacv->xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); } if( s->datatype==1 ) { sparsegetrow(&s->sparsexy, i, &datacv->xyrow, _state); } mlpprocess(&datacv->network, &datacv->xyrow, &datacv->y, _state); ae_v_move(&cvy->ptr.pp_double[i][0], 1, &datacv->y.ptr.p_double[0], 1, ae_v_len(0,s->nout-1)); } } ae_shared_pool_recycle(pooldatacv, &_datacv, _state); } else { ae_assert(foldDFold-1).", _state); mlptrain_mthreadcv(s, rowsize, nrestarts, folds, fold, (fold+dfold)/2, cvy, pooldatacv, _state); mlptrain_mthreadcv(s, rowsize, nrestarts, folds, (fold+dfold)/2, dfold, cvy, pooldatacv, _state); } ae_frame_leave(_state); } /************************************************************************* This function trains neural network passed to this function, using current dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) and current training settings. Training from NRestarts random starting positions is performed, best network is chosen. This function is inteded to be used internally. It may be used in several settings: * training with ValSubsetSize=0, corresponds to "normal" training with termination criteria based on S.MaxIts (steps count) and S.WStep (step size). Training sample is given by TrnSubset/TrnSubsetSize. * training with ValSubsetSize>0, corresponds to early stopping training with additional MaxIts/WStep stopping criteria. Training sample is given by TrnSubset/TrnSubsetSize, validation sample is given by ValSubset/ ValSubsetSize. -- ALGLIB -- Copyright 13.08.2012 by Bochkanov Sergey *************************************************************************/ static void mlptrain_mlptrainnetworkx(mlptrainer* s, ae_int_t nrestarts, ae_int_t algokind, /* Integer */ ae_vector* trnsubset, ae_int_t trnsubsetsize, /* Integer */ ae_vector* valsubset, ae_int_t valsubsetsize, multilayerperceptron* network, mlpreport* rep, ae_bool isrootcall, ae_shared_pool* sessions, ae_state *_state) { ae_frame _frame_block; modelerrors modrep; double eval; double ebest; ae_int_t ngradbatch; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t pcount; ae_int_t itbest; ae_int_t itcnt; ae_int_t ntype; ae_int_t ttype; ae_bool rndstart; ae_int_t i; ae_int_t nr0; ae_int_t nr1; mlpreport rep0; mlpreport rep1; ae_bool randomizenetwork; double bestrmserror; smlptrnsession *psession; ae_smart_ptr _psession; ae_frame_make(_state, &_frame_block); _modelerrors_init(&modrep, _state); _mlpreport_init(&rep0, _state); _mlpreport_init(&rep1, _state); ae_smart_ptr_init(&_psession, (void**)&psession, _state); mlpproperties(network, &nin, &nout, &wcount, _state); /* * Process root call */ if( isrootcall ) { /* * Check correctness of parameters */ ae_assert(algokind==0||algokind==-1, "MLPTrainNetworkX: unexpected AlgoKind", _state); ae_assert(s->npoints>=0, "MLPTrainNetworkX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); if( s->rcpar ) { ttype = 0; } else { ttype = 1; } if( !mlpissoftmax(network, _state) ) { ntype = 0; } else { ntype = 1; } ae_assert(ntype==ttype, "MLPTrainNetworkX: internal error - type of the training network is not similar to network type in trainer object", _state); ae_assert(s->nin==nin, "MLPTrainNetworkX: internal error - number of inputs in trainer is not equal to number of inputs in the training network.", _state); ae_assert(s->nout==nout, "MLPTrainNetworkX: internal error - number of outputs in trainer is not equal to number of outputs in the training network.", _state); ae_assert(nrestarts>=0, "MLPTrainNetworkX: internal error - NRestarts<0.", _state); ae_assert(trnsubset->cnt>=trnsubsetsize, "MLPTrainNetworkX: internal error - parameter TrnSubsetSize more than input subset size(Length(TrnSubset)ptr.p_int[i]>=0&&trnsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter TrnSubset contains incorrect index(TrnSubset[I]<0 or TrnSubset[I]>S.NPoints-1)", _state); } ae_assert(valsubset->cnt>=valsubsetsize, "MLPTrainNetworkX: internal error - parameter ValSubsetSize more than input subset size(Length(ValSubset)ptr.p_int[i]>=0&&valsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter ValSubset contains incorrect index(ValSubset[I]<0 or ValSubset[I]>S.NPoints-1)", _state); } /* * Train */ randomizenetwork = nrestarts>0; mlptrain_initmlptrnsessions(network, randomizenetwork, s, sessions, _state); mlptrain_mlptrainnetworkx(s, nrestarts, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, rep, ae_false, sessions, _state); /* * Choose best network */ bestrmserror = ae_maxrealnumber; ae_shared_pool_first_recycled(sessions, &_psession, _state); while(psession!=NULL) { if( ae_fp_less(psession->bestrmserror,bestrmserror) ) { mlpimporttunableparameters(network, &psession->bestparameters, _state); bestrmserror = psession->bestrmserror; } ae_shared_pool_next_recycled(sessions, &_psession, _state); } /* * Calculate errors */ if( s->datatype==0 ) { mlpallerrorssubset(network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); } if( s->datatype==1 ) { mlpallerrorssparsesubset(network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); } rep->relclserror = modrep.relclserror; rep->avgce = modrep.avgce; rep->rmserror = modrep.rmserror; rep->avgerror = modrep.avgerror; rep->avgrelerror = modrep.avgrelerror; /* * Done */ ae_frame_leave(_state); return; } /* * Split problem, if we have more than 1 restart */ if( nrestarts>=2 ) { /* * Divide problem with NRestarts into two: NR0 and NR1. */ nr0 = nrestarts/2; nr1 = nrestarts-nr0; mlptrain_mlptrainnetworkx(s, nr0, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep0, ae_false, sessions, _state); mlptrain_mlptrainnetworkx(s, nr1, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep1, ae_false, sessions, _state); /* * Aggregate results */ rep->ngrad = rep0.ngrad+rep1.ngrad; rep->nhess = rep0.nhess+rep1.nhess; rep->ncholesky = rep0.ncholesky+rep1.ncholesky; /* * Done :) */ ae_frame_leave(_state); return; } /* * Execution with NRestarts=1 or NRestarts=0: * * NRestarts=1 means that network is restarted from random position * * NRestarts=0 means that network is not randomized */ ae_assert(nrestarts==0||nrestarts==1, "MLPTrainNetworkX: internal error", _state); rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; ae_shared_pool_retrieve(sessions, &_psession, _state); if( ((s->datatype==0||s->datatype==1)&&s->npoints>0)&&trnsubsetsize!=0 ) { /* * Train network using combination of early stopping and step-size * and step-count based criteria. Network state with best value of * validation set error is stored in WBuf0. When validation set is * zero, most recent state of network is stored. */ rndstart = nrestarts!=0; ngradbatch = 0; eval = (double)(0); ebest = (double)(0); itbest = 0; itcnt = 0; mlptrain_mlpstarttrainingx(s, rndstart, algokind, trnsubset, trnsubsetsize, psession, _state); if( s->datatype==0 ) { ebest = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); } if( s->datatype==1 ) { ebest = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); } ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); while(mlptrain_mlpcontinuetrainingx(s, trnsubset, trnsubsetsize, &ngradbatch, psession, _state)) { if( s->datatype==0 ) { eval = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); } if( s->datatype==1 ) { eval = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); } if( ae_fp_less_eq(eval,ebest)||valsubsetsize==0 ) { ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ebest = eval; itbest = itcnt; } if( itcnt>30&&ae_fp_greater((double)(itcnt),1.5*itbest) ) { break; } itcnt = itcnt+1; } ae_v_move(&psession->network.weights.ptr.p_double[0], 1, &psession->wbuf0.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); rep->ngrad = ngradbatch; } else { for(i=0; i<=wcount-1; i++) { psession->network.weights.ptr.p_double[i] = (double)(0); } } /* * Evaluate network performance and update PSession.BestParameters/BestRMSError * (if needed). */ if( s->datatype==0 ) { mlpallerrorssubset(&psession->network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); } if( s->datatype==1 ) { mlpallerrorssparsesubset(&psession->network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); } if( ae_fp_less(modrep.rmserror,psession->bestrmserror) ) { mlpexporttunableparameters(&psession->network, &psession->bestparameters, &pcount, _state); psession->bestrmserror = modrep.rmserror; } /* * Move session back to pool */ ae_shared_pool_recycle(sessions, &_psession, _state); ae_frame_leave(_state); } /************************************************************************* This function trains neural network ensemble passed to this function using current dataset and early stopping training algorithm. Each early stopping round performs NRestarts random restarts (thus, EnsembleSize*NRestarts training rounds is performed in total). -- ALGLIB -- Copyright 22.08.2012 by Bochkanov Sergey *************************************************************************/ static void mlptrain_mlptrainensemblex(mlptrainer* s, mlpensemble* ensemble, ae_int_t idx0, ae_int_t idx1, ae_int_t nrestarts, ae_int_t trainingmethod, sinteger* ngrad, ae_bool isrootcall, ae_shared_pool* esessions, ae_state *_state) { ae_frame _frame_block; ae_int_t pcount; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t trnsubsetsize; ae_int_t valsubsetsize; ae_int_t k0; sinteger ngrad0; sinteger ngrad1; mlpetrnsession *psession; ae_smart_ptr _psession; hqrndstate rs; ae_frame_make(_state, &_frame_block); _sinteger_init(&ngrad0, _state); _sinteger_init(&ngrad1, _state); ae_smart_ptr_init(&_psession, (void**)&psession, _state); _hqrndstate_init(&rs, _state); nin = mlpgetinputscount(&ensemble->network, _state); nout = mlpgetoutputscount(&ensemble->network, _state); wcount = mlpgetweightscount(&ensemble->network, _state); if( mlpissoftmax(&ensemble->network, _state) ) { pcount = nin; } else { pcount = nin+nout; } if( nrestarts<=0 ) { nrestarts = 1; } /* * Handle degenerate case */ if( s->npoints<2 ) { for(i=idx0; i<=idx1-1; i++) { for(j=0; j<=wcount-1; j++) { ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; } for(j=0; j<=pcount-1; j++) { ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 1.0; } } ae_frame_leave(_state); return; } /* * Process root call */ if( isrootcall ) { /* * Prepare: * * prepare MLPETrnSessions * * fill ensemble by zeros (helps to detect errors) */ mlptrain_initmlpetrnsessions(&ensemble->network, s, esessions, _state); for(i=idx0; i<=idx1-1; i++) { for(j=0; j<=wcount-1; j++) { ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; } for(j=0; j<=pcount-1; j++) { ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 0.0; } } /* * Train in non-root mode and exit */ mlptrain_mlptrainensemblex(s, ensemble, idx0, idx1, nrestarts, trainingmethod, ngrad, ae_false, esessions, _state); ae_frame_leave(_state); return; } /* * Split problem */ if( idx1-idx0>=2 ) { k0 = (idx1-idx0)/2; ngrad0.val = 0; ngrad1.val = 0; mlptrain_mlptrainensemblex(s, ensemble, idx0, idx0+k0, nrestarts, trainingmethod, &ngrad0, ae_false, esessions, _state); mlptrain_mlptrainensemblex(s, ensemble, idx0+k0, idx1, nrestarts, trainingmethod, &ngrad1, ae_false, esessions, _state); ngrad->val = ngrad0.val+ngrad1.val; ae_frame_leave(_state); return; } /* * Retrieve and prepare session */ ae_shared_pool_retrieve(esessions, &_psession, _state); /* * Train */ hqrndrandomize(&rs, _state); for(k=idx0; k<=idx1-1; k++) { /* * Split set */ trnsubsetsize = 0; valsubsetsize = 0; if( trainingmethod==0 ) { do { trnsubsetsize = 0; valsubsetsize = 0; for(i=0; i<=s->npoints-1; i++) { if( ae_fp_less(ae_randomreal(_state),0.66) ) { /* * Assign sample to training set */ psession->trnsubset.ptr.p_int[trnsubsetsize] = i; trnsubsetsize = trnsubsetsize+1; } else { /* * Assign sample to validation set */ psession->valsubset.ptr.p_int[valsubsetsize] = i; valsubsetsize = valsubsetsize+1; } } } while(!(trnsubsetsize!=0&&valsubsetsize!=0)); } if( trainingmethod==1 ) { valsubsetsize = 0; trnsubsetsize = s->npoints; for(i=0; i<=s->npoints-1; i++) { psession->trnsubset.ptr.p_int[i] = hqrnduniformi(&rs, s->npoints, _state); } } /* * Train */ mlptrain_mlptrainnetworkx(s, nrestarts, -1, &psession->trnsubset, trnsubsetsize, &psession->valsubset, valsubsetsize, &psession->network, &psession->mlprep, ae_true, &psession->mlpsessions, _state); ngrad->val = ngrad->val+psession->mlprep.ngrad; /* * Save results */ ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &psession->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &psession->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); } /* * Recycle session */ ae_shared_pool_recycle(esessions, &_psession, _state); ae_frame_leave(_state); } /************************************************************************* This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTrainingX call, and then user subsequently calls MLPContinueTrainingX to perform one more iteration of the training. After call to this function trainer object remembers network and is ready to train it. However, no training is performed until first call to MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() will advance traing progress one iteration further. -- ALGLIB -- Copyright 13.08.2012 by Bochkanov Sergey *************************************************************************/ static void mlptrain_mlpstarttrainingx(mlptrainer* s, ae_bool randomstart, ae_int_t algokind, /* Integer */ ae_vector* subset, ae_int_t subsetsize, smlptrnsession* session, ae_state *_state) { ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t ntype; ae_int_t ttype; ae_int_t i; /* * Check parameters */ ae_assert(s->npoints>=0, "MLPStartTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); ae_assert(algokind==0||algokind==-1, "MLPStartTrainingX: unexpected AlgoKind", _state); if( s->rcpar ) { ttype = 0; } else { ttype = 1; } if( !mlpissoftmax(&session->network, _state) ) { ntype = 0; } else { ntype = 1; } ae_assert(ntype==ttype, "MLPStartTrainingX: internal error - type of the resulting network is not similar to network type in trainer object", _state); mlpproperties(&session->network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPStartTrainingX: number of inputs in trainer is not equal to number of inputs in the network.", _state); ae_assert(s->nout==nout, "MLPStartTrainingX: number of outputs in trainer is not equal to number of outputs in the network.", _state); ae_assert(subset->cnt>=subsetsize, "MLPStartTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPStartTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1)", _state); } /* * Prepare session */ minlbfgssetcond(&session->optimizer, 0.0, 0.0, s->wstep, s->maxits, _state); if( s->npoints>0&&subsetsize!=0 ) { if( randomstart ) { mlprandomize(&session->network, _state); } minlbfgsrestartfrom(&session->optimizer, &session->network.weights, _state); } else { for(i=0; i<=wcount-1; i++) { session->network.weights.ptr.p_double[i] = (double)(0); } } if( algokind==-1 ) { session->algoused = s->algokind; if( s->algokind==1 ) { session->minibatchsize = s->minibatchsize; } } else { session->algoused = 0; } hqrndrandomize(&session->generator, _state); ae_vector_set_length(&session->rstate.ia, 15+1, _state); ae_vector_set_length(&session->rstate.ra, 1+1, _state); session->rstate.stage = -1; } /************************************************************************* This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTrainingX call, and then user subsequently calls MLPContinueTrainingX to perform one more iteration of the training. This function performs one more iteration of the training and returns either True (training continues) or False (training stopped). In case True was returned, Network weights are updated according to the current state of the optimization progress. In case False was returned, no additional updates is performed (previous update of the network weights moved us to the final point, and no additional updates is needed). EXAMPLE: > > [initialize network and trainer object] > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > [visualize training progress] > -- ALGLIB -- Copyright 13.08.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool mlptrain_mlpcontinuetrainingx(mlptrainer* s, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_int_t* ngradbatch, smlptrnsession* session, ae_state *_state) { ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t twcount; ae_int_t ntype; ae_int_t ttype; double decay; double v; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t trnsetsize; ae_int_t epoch; ae_int_t minibatchcount; ae_int_t minibatchidx; ae_int_t cursize; ae_int_t idx0; ae_int_t idx1; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( session->rstate.stage>=0 ) { nin = session->rstate.ia.ptr.p_int[0]; nout = session->rstate.ia.ptr.p_int[1]; wcount = session->rstate.ia.ptr.p_int[2]; twcount = session->rstate.ia.ptr.p_int[3]; ntype = session->rstate.ia.ptr.p_int[4]; ttype = session->rstate.ia.ptr.p_int[5]; i = session->rstate.ia.ptr.p_int[6]; j = session->rstate.ia.ptr.p_int[7]; k = session->rstate.ia.ptr.p_int[8]; trnsetsize = session->rstate.ia.ptr.p_int[9]; epoch = session->rstate.ia.ptr.p_int[10]; minibatchcount = session->rstate.ia.ptr.p_int[11]; minibatchidx = session->rstate.ia.ptr.p_int[12]; cursize = session->rstate.ia.ptr.p_int[13]; idx0 = session->rstate.ia.ptr.p_int[14]; idx1 = session->rstate.ia.ptr.p_int[15]; decay = session->rstate.ra.ptr.p_double[0]; v = session->rstate.ra.ptr.p_double[1]; } else { nin = -983; nout = -989; wcount = -834; twcount = 900; ntype = -287; ttype = 364; i = 214; j = -338; k = -686; trnsetsize = 912; epoch = 585; minibatchcount = 497; minibatchidx = -271; cursize = -581; idx0 = 745; idx1 = -533; decay = -77; v = 678; } if( session->rstate.stage==0 ) { goto lbl_0; } /* * Routine body */ /* * Check correctness of inputs */ ae_assert(s->npoints>=0, "MLPContinueTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0).", _state); if( s->rcpar ) { ttype = 0; } else { ttype = 1; } if( !mlpissoftmax(&session->network, _state) ) { ntype = 0; } else { ntype = 1; } ae_assert(ntype==ttype, "MLPContinueTrainingX: internal error - type of the resulting network is not similar to network type in trainer object.", _state); mlpproperties(&session->network, &nin, &nout, &wcount, _state); ae_assert(s->nin==nin, "MLPContinueTrainingX: internal error - number of inputs in trainer is not equal to number of inputs in the network.", _state); ae_assert(s->nout==nout, "MLPContinueTrainingX: internal error - number of outputs in trainer is not equal to number of outputs in the network.", _state); ae_assert(subset->cnt>=subsetsize, "MLPContinueTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPContinueTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1).", _state); } /* * Quick exit on empty training set */ if( s->npoints==0||subsetsize==0 ) { result = ae_false; return result; } /* * Minibatch training */ if( session->algoused==1 ) { ae_assert(ae_false, "MINIBATCH TRAINING IS NOT IMPLEMENTED YET", _state); } /* * Last option: full batch training */ decay = s->decay; lbl_1: if( !minlbfgsiteration(&session->optimizer, _state) ) { goto lbl_2; } if( !session->optimizer.xupdated ) { goto lbl_3; } ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); session->rstate.stage = 0; goto lbl_rcomm; lbl_0: lbl_3: ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); if( s->datatype==0 ) { mlpgradbatchsubset(&session->network, &s->densexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); } if( s->datatype==1 ) { mlpgradbatchsparsesubset(&session->network, &s->sparsexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); } /* * Increment number of operations performed on batch gradient */ *ngradbatch = *ngradbatch+1; v = ae_v_dotproduct(&session->network.weights.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); session->optimizer.f = session->optimizer.f+0.5*decay*v; ae_v_addd(&session->optimizer.g.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); goto lbl_1; lbl_2: minlbfgsresultsbuf(&session->optimizer, &session->network.weights, &session->optimizerrep, _state); result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; session->rstate.ia.ptr.p_int[0] = nin; session->rstate.ia.ptr.p_int[1] = nout; session->rstate.ia.ptr.p_int[2] = wcount; session->rstate.ia.ptr.p_int[3] = twcount; session->rstate.ia.ptr.p_int[4] = ntype; session->rstate.ia.ptr.p_int[5] = ttype; session->rstate.ia.ptr.p_int[6] = i; session->rstate.ia.ptr.p_int[7] = j; session->rstate.ia.ptr.p_int[8] = k; session->rstate.ia.ptr.p_int[9] = trnsetsize; session->rstate.ia.ptr.p_int[10] = epoch; session->rstate.ia.ptr.p_int[11] = minibatchcount; session->rstate.ia.ptr.p_int[12] = minibatchidx; session->rstate.ia.ptr.p_int[13] = cursize; session->rstate.ia.ptr.p_int[14] = idx0; session->rstate.ia.ptr.p_int[15] = idx1; session->rstate.ra.ptr.p_double[0] = decay; session->rstate.ra.ptr.p_double[1] = v; return result; } /************************************************************************* Internal bagging subroutine. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_bool lmalgorithm, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state) { ae_frame _frame_block; ae_matrix xys; ae_vector s; ae_matrix oobbuf; ae_vector oobcntbuf; ae_vector x; ae_vector y; ae_vector dy; ae_vector dsbuf; ae_int_t ccnt; ae_int_t pcnt; ae_int_t i; ae_int_t j; ae_int_t k; double v; mlpreport tmprep; ae_int_t nin; ae_int_t nout; ae_int_t wcount; hqrndstate rs; ae_frame_make(_state, &_frame_block); *info = 0; _mlpreport_clear(rep); _mlpcvreport_clear(ooberrors); ae_matrix_init(&xys, 0, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_BOOL, _state); ae_matrix_init(&oobbuf, 0, 0, DT_REAL, _state); ae_vector_init(&oobcntbuf, 0, DT_INT, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&dy, 0, DT_REAL, _state); ae_vector_init(&dsbuf, 0, DT_REAL, _state); _mlpreport_init(&tmprep, _state); _hqrndstate_init(&rs, _state); nin = mlpgetinputscount(&ensemble->network, _state); nout = mlpgetoutputscount(&ensemble->network, _state); wcount = mlpgetweightscount(&ensemble->network, _state); /* * Test for inputs */ if( (!lmalgorithm&&ae_fp_eq(wstep,(double)(0)))&&maxits==0 ) { *info = -8; ae_frame_leave(_state); return; } if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,(double)(0)))||maxits<0 ) { *info = -1; ae_frame_leave(_state); return; } if( mlpissoftmax(&ensemble->network, _state) ) { for(i=0; i<=npoints-1; i++) { if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) { *info = -2; ae_frame_leave(_state); return; } } } /* * allocate temporaries */ *info = 2; rep->ngrad = 0; rep->nhess = 0; rep->ncholesky = 0; ooberrors->relclserror = (double)(0); ooberrors->avgce = (double)(0); ooberrors->rmserror = (double)(0); ooberrors->avgerror = (double)(0); ooberrors->avgrelerror = (double)(0); if( mlpissoftmax(&ensemble->network, _state) ) { ccnt = nin+1; pcnt = nin; } else { ccnt = nin+nout; pcnt = nin+nout; } ae_matrix_set_length(&xys, npoints, ccnt, _state); ae_vector_set_length(&s, npoints, _state); ae_matrix_set_length(&oobbuf, npoints, nout, _state); ae_vector_set_length(&oobcntbuf, npoints, _state); ae_vector_set_length(&x, nin, _state); ae_vector_set_length(&y, nout, _state); if( mlpissoftmax(&ensemble->network, _state) ) { ae_vector_set_length(&dy, 1, _state); } else { ae_vector_set_length(&dy, nout, _state); } for(i=0; i<=npoints-1; i++) { for(j=0; j<=nout-1; j++) { oobbuf.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=npoints-1; i++) { oobcntbuf.ptr.p_int[i] = 0; } /* * main bagging cycle */ hqrndrandomize(&rs, _state); for(k=0; k<=ensemble->ensemblesize-1; k++) { /* * prepare dataset */ for(i=0; i<=npoints-1; i++) { s.ptr.p_bool[i] = ae_false; } for(i=0; i<=npoints-1; i++) { j = hqrnduniformi(&rs, npoints, _state); s.ptr.p_bool[j] = ae_true; ae_v_move(&xys.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,ccnt-1)); } /* * train */ if( lmalgorithm ) { mlptrainlm(&ensemble->network, &xys, npoints, decay, restarts, info, &tmprep, _state); } else { mlptrainlbfgs(&ensemble->network, &xys, npoints, decay, restarts, wstep, maxits, info, &tmprep, _state); } if( *info<0 ) { ae_frame_leave(_state); return; } /* * save results */ rep->ngrad = rep->ngrad+tmprep.ngrad; rep->nhess = rep->nhess+tmprep.nhess; rep->ncholesky = rep->ncholesky+tmprep.ncholesky; ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcnt], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcnt], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); /* * OOB estimates */ for(i=0; i<=npoints-1; i++) { if( !s.ptr.p_bool[i] ) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); mlpprocess(&ensemble->network, &x, &y, _state); ae_v_add(&oobbuf.ptr.pp_double[i][0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); oobcntbuf.ptr.p_int[i] = oobcntbuf.ptr.p_int[i]+1; } } } /* * OOB estimates */ if( mlpissoftmax(&ensemble->network, _state) ) { dserrallocate(nout, &dsbuf, _state); } else { dserrallocate(-nout, &dsbuf, _state); } for(i=0; i<=npoints-1; i++) { if( oobcntbuf.ptr.p_int[i]!=0 ) { v = (double)1/(double)oobcntbuf.ptr.p_int[i]; ae_v_moved(&y.ptr.p_double[0], 1, &oobbuf.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1), v); if( mlpissoftmax(&ensemble->network, _state) ) { dy.ptr.p_double[0] = xy->ptr.pp_double[i][nin]; } else { ae_v_moved(&dy.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1), v); } dserraccumulate(&dsbuf, &y, &dy, _state); } } dserrfinish(&dsbuf, _state); ooberrors->relclserror = dsbuf.ptr.p_double[0]; ooberrors->avgce = dsbuf.ptr.p_double[1]; ooberrors->rmserror = dsbuf.ptr.p_double[2]; ooberrors->avgerror = dsbuf.ptr.p_double[3]; ooberrors->avgrelerror = dsbuf.ptr.p_double[4]; ae_frame_leave(_state); } /************************************************************************* This function initializes temporaries needed for training session. -- ALGLIB -- Copyright 01.07.2013 by Bochkanov Sergey *************************************************************************/ static void mlptrain_initmlptrnsession(multilayerperceptron* networktrained, ae_bool randomizenetwork, mlptrainer* trainer, smlptrnsession* session, ae_state *_state) { ae_frame _frame_block; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t pcount; ae_vector dummysubset; ae_frame_make(_state, &_frame_block); ae_vector_init(&dummysubset, 0, DT_INT, _state); /* * Prepare network: * * copy input network to Session.Network * * re-initialize preprocessor and weights if RandomizeNetwork=True */ mlpcopy(networktrained, &session->network, _state); if( randomizenetwork ) { ae_assert(trainer->datatype==0||trainer->datatype==1, "InitTemporaries: unexpected Trainer.DataType", _state); if( trainer->datatype==0 ) { mlpinitpreprocessorsubset(&session->network, &trainer->densexy, trainer->npoints, &dummysubset, -1, _state); } if( trainer->datatype==1 ) { mlpinitpreprocessorsparsesubset(&session->network, &trainer->sparsexy, trainer->npoints, &dummysubset, -1, _state); } mlprandomize(&session->network, _state); session->randomizenetwork = ae_true; } else { session->randomizenetwork = ae_false; } /* * Determine network geometry and initialize optimizer */ mlpproperties(&session->network, &nin, &nout, &wcount, _state); minlbfgscreate(wcount, ae_minint(wcount, trainer->lbfgsfactor, _state), &session->network.weights, &session->optimizer, _state); minlbfgssetxrep(&session->optimizer, ae_true, _state); /* * Create buffers */ ae_vector_set_length(&session->wbuf0, wcount, _state); ae_vector_set_length(&session->wbuf1, wcount, _state); /* * Initialize session result */ mlpexporttunableparameters(&session->network, &session->bestparameters, &pcount, _state); session->bestrmserror = ae_maxrealnumber; ae_frame_leave(_state); } /************************************************************************* This function initializes temporaries needed for training session. *************************************************************************/ static void mlptrain_initmlptrnsessions(multilayerperceptron* networktrained, ae_bool randomizenetwork, mlptrainer* trainer, ae_shared_pool* sessions, ae_state *_state) { ae_frame _frame_block; ae_vector dummysubset; smlptrnsession t; smlptrnsession *p; ae_smart_ptr _p; ae_frame_make(_state, &_frame_block); ae_vector_init(&dummysubset, 0, DT_INT, _state); _smlptrnsession_init(&t, _state); ae_smart_ptr_init(&_p, (void**)&p, _state); if( ae_shared_pool_is_initialized(sessions) ) { /* * Pool was already initialized. * Clear sessions stored in the pool. */ ae_shared_pool_first_recycled(sessions, &_p, _state); while(p!=NULL) { ae_assert(mlpsamearchitecture(&p->network, networktrained, _state), "InitMLPTrnSessions: internal consistency error", _state); p->bestrmserror = ae_maxrealnumber; ae_shared_pool_next_recycled(sessions, &_p, _state); } } else { /* * Prepare session and seed pool */ mlptrain_initmlptrnsession(networktrained, randomizenetwork, trainer, &t, _state); ae_shared_pool_set_seed(sessions, &t, sizeof(t), _smlptrnsession_init, _smlptrnsession_init_copy, _smlptrnsession_destroy, _state); } ae_frame_leave(_state); } /************************************************************************* This function initializes temporaries needed for ensemble training. *************************************************************************/ static void mlptrain_initmlpetrnsession(multilayerperceptron* individualnetwork, mlptrainer* trainer, mlpetrnsession* session, ae_state *_state) { ae_frame _frame_block; ae_vector dummysubset; ae_frame_make(_state, &_frame_block); ae_vector_init(&dummysubset, 0, DT_INT, _state); /* * Prepare network: * * copy input network to Session.Network * * re-initialize preprocessor and weights if RandomizeNetwork=True */ mlpcopy(individualnetwork, &session->network, _state); mlptrain_initmlptrnsessions(individualnetwork, ae_true, trainer, &session->mlpsessions, _state); ivectorsetlengthatleast(&session->trnsubset, trainer->npoints, _state); ivectorsetlengthatleast(&session->valsubset, trainer->npoints, _state); ae_frame_leave(_state); } /************************************************************************* This function initializes temporaries needed for training session. *************************************************************************/ static void mlptrain_initmlpetrnsessions(multilayerperceptron* individualnetwork, mlptrainer* trainer, ae_shared_pool* sessions, ae_state *_state) { ae_frame _frame_block; mlpetrnsession t; ae_frame_make(_state, &_frame_block); _mlpetrnsession_init(&t, _state); if( !ae_shared_pool_is_initialized(sessions) ) { mlptrain_initmlpetrnsession(individualnetwork, trainer, &t, _state); ae_shared_pool_set_seed(sessions, &t, sizeof(t), _mlpetrnsession_init, _mlpetrnsession_init_copy, _mlpetrnsession_destroy, _state); } ae_frame_leave(_state); } void _mlpreport_init(void* _p, ae_state *_state) { mlpreport *p = (mlpreport*)_p; ae_touch_ptr((void*)p); } void _mlpreport_init_copy(void* _dst, void* _src, ae_state *_state) { mlpreport *dst = (mlpreport*)_dst; mlpreport *src = (mlpreport*)_src; dst->relclserror = src->relclserror; dst->avgce = src->avgce; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; dst->ngrad = src->ngrad; dst->nhess = src->nhess; dst->ncholesky = src->ncholesky; } void _mlpreport_clear(void* _p) { mlpreport *p = (mlpreport*)_p; ae_touch_ptr((void*)p); } void _mlpreport_destroy(void* _p) { mlpreport *p = (mlpreport*)_p; ae_touch_ptr((void*)p); } void _mlpcvreport_init(void* _p, ae_state *_state) { mlpcvreport *p = (mlpcvreport*)_p; ae_touch_ptr((void*)p); } void _mlpcvreport_init_copy(void* _dst, void* _src, ae_state *_state) { mlpcvreport *dst = (mlpcvreport*)_dst; mlpcvreport *src = (mlpcvreport*)_src; dst->relclserror = src->relclserror; dst->avgce = src->avgce; dst->rmserror = src->rmserror; dst->avgerror = src->avgerror; dst->avgrelerror = src->avgrelerror; } void _mlpcvreport_clear(void* _p) { mlpcvreport *p = (mlpcvreport*)_p; ae_touch_ptr((void*)p); } void _mlpcvreport_destroy(void* _p) { mlpcvreport *p = (mlpcvreport*)_p; ae_touch_ptr((void*)p); } void _smlptrnsession_init(void* _p, ae_state *_state) { smlptrnsession *p = (smlptrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->bestparameters, 0, DT_REAL, _state); _multilayerperceptron_init(&p->network, _state); _minlbfgsstate_init(&p->optimizer, _state); _minlbfgsreport_init(&p->optimizerrep, _state); ae_vector_init(&p->wbuf0, 0, DT_REAL, _state); ae_vector_init(&p->wbuf1, 0, DT_REAL, _state); ae_vector_init(&p->allminibatches, 0, DT_INT, _state); ae_vector_init(&p->currentminibatch, 0, DT_INT, _state); _rcommstate_init(&p->rstate, _state); _hqrndstate_init(&p->generator, _state); } void _smlptrnsession_init_copy(void* _dst, void* _src, ae_state *_state) { smlptrnsession *dst = (smlptrnsession*)_dst; smlptrnsession *src = (smlptrnsession*)_src; ae_vector_init_copy(&dst->bestparameters, &src->bestparameters, _state); dst->bestrmserror = src->bestrmserror; dst->randomizenetwork = src->randomizenetwork; _multilayerperceptron_init_copy(&dst->network, &src->network, _state); _minlbfgsstate_init_copy(&dst->optimizer, &src->optimizer, _state); _minlbfgsreport_init_copy(&dst->optimizerrep, &src->optimizerrep, _state); ae_vector_init_copy(&dst->wbuf0, &src->wbuf0, _state); ae_vector_init_copy(&dst->wbuf1, &src->wbuf1, _state); ae_vector_init_copy(&dst->allminibatches, &src->allminibatches, _state); ae_vector_init_copy(&dst->currentminibatch, &src->currentminibatch, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->algoused = src->algoused; dst->minibatchsize = src->minibatchsize; _hqrndstate_init_copy(&dst->generator, &src->generator, _state); } void _smlptrnsession_clear(void* _p) { smlptrnsession *p = (smlptrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->bestparameters); _multilayerperceptron_clear(&p->network); _minlbfgsstate_clear(&p->optimizer); _minlbfgsreport_clear(&p->optimizerrep); ae_vector_clear(&p->wbuf0); ae_vector_clear(&p->wbuf1); ae_vector_clear(&p->allminibatches); ae_vector_clear(&p->currentminibatch); _rcommstate_clear(&p->rstate); _hqrndstate_clear(&p->generator); } void _smlptrnsession_destroy(void* _p) { smlptrnsession *p = (smlptrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->bestparameters); _multilayerperceptron_destroy(&p->network); _minlbfgsstate_destroy(&p->optimizer); _minlbfgsreport_destroy(&p->optimizerrep); ae_vector_destroy(&p->wbuf0); ae_vector_destroy(&p->wbuf1); ae_vector_destroy(&p->allminibatches); ae_vector_destroy(&p->currentminibatch); _rcommstate_destroy(&p->rstate); _hqrndstate_destroy(&p->generator); } void _mlpetrnsession_init(void* _p, ae_state *_state) { mlpetrnsession *p = (mlpetrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->trnsubset, 0, DT_INT, _state); ae_vector_init(&p->valsubset, 0, DT_INT, _state); ae_shared_pool_init(&p->mlpsessions, _state); _mlpreport_init(&p->mlprep, _state); _multilayerperceptron_init(&p->network, _state); } void _mlpetrnsession_init_copy(void* _dst, void* _src, ae_state *_state) { mlpetrnsession *dst = (mlpetrnsession*)_dst; mlpetrnsession *src = (mlpetrnsession*)_src; ae_vector_init_copy(&dst->trnsubset, &src->trnsubset, _state); ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state); ae_shared_pool_init_copy(&dst->mlpsessions, &src->mlpsessions, _state); _mlpreport_init_copy(&dst->mlprep, &src->mlprep, _state); _multilayerperceptron_init_copy(&dst->network, &src->network, _state); } void _mlpetrnsession_clear(void* _p) { mlpetrnsession *p = (mlpetrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->trnsubset); ae_vector_clear(&p->valsubset); ae_shared_pool_clear(&p->mlpsessions); _mlpreport_clear(&p->mlprep); _multilayerperceptron_clear(&p->network); } void _mlpetrnsession_destroy(void* _p) { mlpetrnsession *p = (mlpetrnsession*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->trnsubset); ae_vector_destroy(&p->valsubset); ae_shared_pool_destroy(&p->mlpsessions); _mlpreport_destroy(&p->mlprep); _multilayerperceptron_destroy(&p->network); } void _mlptrainer_init(void* _p, ae_state *_state) { mlptrainer *p = (mlptrainer*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->densexy, 0, 0, DT_REAL, _state); _sparsematrix_init(&p->sparsexy, _state); _smlptrnsession_init(&p->session, _state); ae_vector_init(&p->subset, 0, DT_INT, _state); ae_vector_init(&p->valsubset, 0, DT_INT, _state); } void _mlptrainer_init_copy(void* _dst, void* _src, ae_state *_state) { mlptrainer *dst = (mlptrainer*)_dst; mlptrainer *src = (mlptrainer*)_src; dst->nin = src->nin; dst->nout = src->nout; dst->rcpar = src->rcpar; dst->lbfgsfactor = src->lbfgsfactor; dst->decay = src->decay; dst->wstep = src->wstep; dst->maxits = src->maxits; dst->datatype = src->datatype; dst->npoints = src->npoints; ae_matrix_init_copy(&dst->densexy, &src->densexy, _state); _sparsematrix_init_copy(&dst->sparsexy, &src->sparsexy, _state); _smlptrnsession_init_copy(&dst->session, &src->session, _state); dst->ngradbatch = src->ngradbatch; ae_vector_init_copy(&dst->subset, &src->subset, _state); dst->subsetsize = src->subsetsize; ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state); dst->valsubsetsize = src->valsubsetsize; dst->algokind = src->algokind; dst->minibatchsize = src->minibatchsize; } void _mlptrainer_clear(void* _p) { mlptrainer *p = (mlptrainer*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->densexy); _sparsematrix_clear(&p->sparsexy); _smlptrnsession_clear(&p->session); ae_vector_clear(&p->subset); ae_vector_clear(&p->valsubset); } void _mlptrainer_destroy(void* _p) { mlptrainer *p = (mlptrainer*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->densexy); _sparsematrix_destroy(&p->sparsexy); _smlptrnsession_destroy(&p->session); ae_vector_destroy(&p->subset); ae_vector_destroy(&p->valsubset); } void _mlpparallelizationcv_init(void* _p, ae_state *_state) { mlpparallelizationcv *p = (mlpparallelizationcv*)_p; ae_touch_ptr((void*)p); _multilayerperceptron_init(&p->network, _state); _mlpreport_init(&p->rep, _state); ae_vector_init(&p->subset, 0, DT_INT, _state); ae_vector_init(&p->xyrow, 0, DT_REAL, _state); ae_vector_init(&p->y, 0, DT_REAL, _state); ae_shared_pool_init(&p->trnpool, _state); } void _mlpparallelizationcv_init_copy(void* _dst, void* _src, ae_state *_state) { mlpparallelizationcv *dst = (mlpparallelizationcv*)_dst; mlpparallelizationcv *src = (mlpparallelizationcv*)_src; _multilayerperceptron_init_copy(&dst->network, &src->network, _state); _mlpreport_init_copy(&dst->rep, &src->rep, _state); ae_vector_init_copy(&dst->subset, &src->subset, _state); dst->subsetsize = src->subsetsize; ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state); ae_vector_init_copy(&dst->y, &src->y, _state); dst->ngrad = src->ngrad; ae_shared_pool_init_copy(&dst->trnpool, &src->trnpool, _state); } void _mlpparallelizationcv_clear(void* _p) { mlpparallelizationcv *p = (mlpparallelizationcv*)_p; ae_touch_ptr((void*)p); _multilayerperceptron_clear(&p->network); _mlpreport_clear(&p->rep); ae_vector_clear(&p->subset); ae_vector_clear(&p->xyrow); ae_vector_clear(&p->y); ae_shared_pool_clear(&p->trnpool); } void _mlpparallelizationcv_destroy(void* _p) { mlpparallelizationcv *p = (mlpparallelizationcv*)_p; ae_touch_ptr((void*)p); _multilayerperceptron_destroy(&p->network); _mlpreport_destroy(&p->rep); ae_vector_destroy(&p->subset); ae_vector_destroy(&p->xyrow); ae_vector_destroy(&p->y); ae_shared_pool_destroy(&p->trnpool); } /************************************************************************* Principal components analysis Subroutine builds orthogonal basis where first axis corresponds to direction with maximum variance, second axis maximizes variance in subspace orthogonal to first axis and so on. It should be noted that, unlike LDA, PCA does not use class labels. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - dataset, array[0..NPoints-1,0..NVars-1]. matrix contains ONLY INDEPENDENT VARIABLES. NPoints - dataset size, NPoints>=0 NVars - number of independent variables, NVars>=1 OUTPUT PARAMETERS: Info - return code: * -4, if SVD subroutine haven't converged * -1, if wrong parameters has been passed (NPoints<0, NVars<1) * 1, if task is solved S2 - array[0..NVars-1]. variance values corresponding to basis vectors. V - array[0..NVars-1,0..NVars-1] matrix, whose columns store basis vectors. -- ALGLIB -- Copyright 25.08.2008 by Bochkanov Sergey *************************************************************************/ void pcabuildbasis(/* Real */ ae_matrix* x, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* s2, /* Real */ ae_matrix* v, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix u; ae_matrix vt; ae_vector m; ae_vector t; ae_int_t i; ae_int_t j; double mean; double variance; double skewness; double kurtosis; ae_frame_make(_state, &_frame_block); *info = 0; ae_vector_clear(s2); ae_matrix_clear(v); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_vector_init(&m, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); /* * Check input data */ if( npoints<0||nvars<1 ) { *info = -1; ae_frame_leave(_state); return; } *info = 1; /* * Special case: NPoints=0 */ if( npoints==0 ) { ae_vector_set_length(s2, nvars, _state); ae_matrix_set_length(v, nvars, nvars, _state); for(i=0; i<=nvars-1; i++) { s2->ptr.p_double[i] = (double)(0); } for(i=0; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { if( i==j ) { v->ptr.pp_double[i][j] = (double)(1); } else { v->ptr.pp_double[i][j] = (double)(0); } } } ae_frame_leave(_state); return; } /* * Calculate means */ ae_vector_set_length(&m, nvars, _state); ae_vector_set_length(&t, npoints, _state); for(j=0; j<=nvars-1; j++) { ae_v_move(&t.ptr.p_double[0], 1, &x->ptr.pp_double[0][j], x->stride, ae_v_len(0,npoints-1)); samplemoments(&t, npoints, &mean, &variance, &skewness, &kurtosis, _state); m.ptr.p_double[j] = mean; } /* * Center, apply SVD, prepare output */ ae_matrix_set_length(&a, ae_maxint(npoints, nvars, _state), nvars, _state); for(i=0; i<=npoints-1; i++) { ae_v_move(&a.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&a.ptr.pp_double[i][0], 1, &m.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); } for(i=npoints; i<=nvars-1; i++) { for(j=0; j<=nvars-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } if( !rmatrixsvd(&a, ae_maxint(npoints, nvars, _state), nvars, 0, 1, 2, s2, &u, &vt, _state) ) { *info = -4; ae_frame_leave(_state); return; } if( npoints!=1 ) { for(i=0; i<=nvars-1; i++) { s2->ptr.p_double[i] = ae_sqr(s2->ptr.p_double[i], _state)/(npoints-1); } } ae_matrix_set_length(v, nvars, nvars, _state); copyandtranspose(&vt, 0, nvars-1, 0, nvars-1, v, 0, nvars-1, 0, nvars-1, _state); ae_frame_leave(_state); } } qmapshack-1.10.0/3rdparty/alglib/src/dataanalysis.h000755 001750 000144 00001130005 13015033052 023334 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _dataanalysis_pkg_h #define _dataanalysis_pkg_h #include "ap.h" #include "alglibinternal.h" #include "linalg.h" #include "statistics.h" #include "alglibmisc.h" #include "specialfunctions.h" #include "solvers.h" #include "optimization.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; } cvreport; typedef struct { ae_matrix ct; ae_matrix ctbest; ae_vector xycbest; ae_vector xycprev; ae_vector d2; ae_vector csizes; apbuffers initbuf; ae_shared_pool updatepool; } kmeansbuffers; typedef struct { ae_int_t npoints; ae_int_t nfeatures; ae_int_t disttype; ae_matrix xy; ae_matrix d; ae_int_t ahcalgo; ae_int_t kmeansrestarts; ae_int_t kmeansmaxits; ae_int_t kmeansinitalgo; ae_bool kmeansdbgnoits; ae_matrix tmpd; apbuffers distbuf; kmeansbuffers kmeanstmp; } clusterizerstate; typedef struct { ae_int_t terminationtype; ae_int_t npoints; ae_vector p; ae_matrix z; ae_matrix pz; ae_matrix pm; ae_vector mergedist; } ahcreport; typedef struct { ae_int_t npoints; ae_int_t nfeatures; ae_int_t terminationtype; ae_int_t iterationscount; double energy; ae_int_t k; ae_matrix c; ae_vector cidx; } kmeansreport; typedef struct { ae_int_t nvars; ae_int_t nclasses; ae_int_t ntrees; ae_int_t bufsize; ae_vector trees; } decisionforest; typedef struct { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; double oobrelclserror; double oobavgce; double oobrmserror; double oobavgerror; double oobavgrelerror; } dfreport; typedef struct { ae_vector treebuf; ae_vector idxbuf; ae_vector tmpbufr; ae_vector tmpbufr2; ae_vector tmpbufi; ae_vector classibuf; ae_vector sortrbuf; ae_vector sortrbuf2; ae_vector sortibuf; ae_vector varpool; ae_vector evsbin; ae_vector evssplits; } dfinternalbuffers; typedef struct { ae_vector w; } linearmodel; typedef struct { ae_matrix c; double rmserror; double avgerror; double avgrelerror; double cvrmserror; double cvavgerror; double cvavgrelerror; ae_int_t ncvdefects; ae_vector cvdefects; } lrreport; typedef struct { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; } modelerrors; typedef struct { double f; ae_vector g; } smlpgrad; typedef struct { ae_int_t hlnetworktype; ae_int_t hlnormtype; ae_vector hllayersizes; ae_vector hlconnections; ae_vector hlneurons; ae_vector structinfo; ae_vector weights; ae_vector columnmeans; ae_vector columnsigmas; ae_vector neurons; ae_vector dfdnet; ae_vector derror; ae_vector x; ae_vector y; ae_matrix xy; ae_vector xyrow; ae_vector nwbuf; ae_vector integerbuf; modelerrors err; ae_vector rndbuf; ae_shared_pool buf; ae_shared_pool gradbuf; ae_matrix dummydxy; sparsematrix dummysxy; ae_vector dummyidx; ae_shared_pool dummypool; } multilayerperceptron; typedef struct { ae_vector w; } logitmodel; typedef struct { ae_bool brackt; ae_bool stage1; ae_int_t infoc; double dg; double dgm; double dginit; double dgtest; double dgx; double dgxm; double dgy; double dgym; double finit; double ftest1; double fm; double fx; double fxm; double fy; double fym; double stx; double sty; double stmin; double stmax; double width; double width1; double xtrapf; } logitmcstate; typedef struct { ae_int_t ngrad; ae_int_t nhess; } mnlreport; typedef struct { ae_int_t n; ae_vector states; ae_int_t npairs; ae_matrix data; ae_matrix ec; ae_matrix bndl; ae_matrix bndu; ae_matrix c; ae_vector ct; ae_int_t ccnt; ae_vector pw; ae_matrix priorp; double regterm; minbleicstate bs; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repnfev; ae_int_t repterminationtype; minbleicreport br; ae_vector tmpp; ae_vector effectivew; ae_vector effectivebndl; ae_vector effectivebndu; ae_matrix effectivec; ae_vector effectivect; ae_vector h; ae_matrix p; } mcpdstate; typedef struct { ae_int_t inneriterationscount; ae_int_t outeriterationscount; ae_int_t nfev; ae_int_t terminationtype; } mcpdreport; typedef struct { ae_int_t ensemblesize; ae_vector weights; ae_vector columnmeans; ae_vector columnsigmas; multilayerperceptron network; ae_vector y; } mlpensemble; typedef struct { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; ae_int_t ngrad; ae_int_t nhess; ae_int_t ncholesky; } mlpreport; typedef struct { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; } mlpcvreport; typedef struct { ae_vector bestparameters; double bestrmserror; ae_bool randomizenetwork; multilayerperceptron network; minlbfgsstate optimizer; minlbfgsreport optimizerrep; ae_vector wbuf0; ae_vector wbuf1; ae_vector allminibatches; ae_vector currentminibatch; rcommstate rstate; ae_int_t algoused; ae_int_t minibatchsize; hqrndstate generator; } smlptrnsession; typedef struct { ae_vector trnsubset; ae_vector valsubset; ae_shared_pool mlpsessions; mlpreport mlprep; multilayerperceptron network; } mlpetrnsession; typedef struct { ae_int_t nin; ae_int_t nout; ae_bool rcpar; ae_int_t lbfgsfactor; double decay; double wstep; ae_int_t maxits; ae_int_t datatype; ae_int_t npoints; ae_matrix densexy; sparsematrix sparsexy; smlptrnsession session; ae_int_t ngradbatch; ae_vector subset; ae_int_t subsetsize; ae_vector valsubset; ae_int_t valsubsetsize; ae_int_t algokind; ae_int_t minibatchsize; } mlptrainer; typedef struct { multilayerperceptron network; mlpreport rep; ae_vector subset; ae_int_t subsetsize; ae_vector xyrow; ae_vector y; ae_int_t ngrad; ae_shared_pool trnpool; } mlpparallelizationcv; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* This structure is a clusterization engine. You should not try to access its fields directly. Use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ class _clusterizerstate_owner { public: _clusterizerstate_owner(); _clusterizerstate_owner(const _clusterizerstate_owner &rhs); _clusterizerstate_owner& operator=(const _clusterizerstate_owner &rhs); virtual ~_clusterizerstate_owner(); alglib_impl::clusterizerstate* c_ptr(); alglib_impl::clusterizerstate* c_ptr() const; protected: alglib_impl::clusterizerstate *p_struct; }; class clusterizerstate : public _clusterizerstate_owner { public: clusterizerstate(); clusterizerstate(const clusterizerstate &rhs); clusterizerstate& operator=(const clusterizerstate &rhs); virtual ~clusterizerstate(); }; /************************************************************************* This structure is used to store results of the agglomerative hierarchical clustering (AHC). Following information is returned: * TerminationType - completion code: * 1 for successful completion of algorithm * -5 inappropriate combination of clustering algorithm and distance function was used. As for now, it is possible only when Ward's method is called for dataset with non-Euclidean distance function. In case negative completion code is returned, other fields of report structure are invalid and should not be used. * NPoints contains number of points in the original dataset * Z contains information about merges performed (see below). Z contains indexes from the original (unsorted) dataset and it can be used when you need to know what points were merged. However, it is not convenient when you want to build a dendrograd (see below). * if you want to build dendrogram, you can use Z, but it is not good option, because Z contains indexes from unsorted dataset. Dendrogram built from such dataset is likely to have intersections. So, you have to reorder you points before building dendrogram. Permutation which reorders point is returned in P. Another representation of merges, which is more convenient for dendorgram construction, is returned in PM. * more information on format of Z, P and PM can be found below and in the examples from ALGLIB Reference Manual. FORMAL DESCRIPTION OF FIELDS: NPoints number of points Z array[NPoints-1,2], contains indexes of clusters linked in pairs to form clustering tree. I-th row corresponds to I-th merge: * Z[I,0] - index of the first cluster to merge * Z[I,1] - index of the second cluster to merge * Z[I,0]=0 NFeatures number of variables, >=1 TerminationType completion code: * -5 if distance type is anything different from Euclidean metric * -3 for degenerate dataset: a) less than K distinct points, b) K=0 for non-empty dataset. * +1 for successful completion K number of clusters C array[K,NFeatures], rows of the array store centers CIdx array[NPoints], which contains cluster indexes IterationsCount actual number of iterations performed by clusterizer. If algorithm performed more than one random restart, total number of iterations is returned. Energy merit function, "energy", sum of squared deviations from cluster centers -- ALGLIB -- Copyright 27.11.2012 by Bochkanov Sergey *************************************************************************/ class _kmeansreport_owner { public: _kmeansreport_owner(); _kmeansreport_owner(const _kmeansreport_owner &rhs); _kmeansreport_owner& operator=(const _kmeansreport_owner &rhs); virtual ~_kmeansreport_owner(); alglib_impl::kmeansreport* c_ptr(); alglib_impl::kmeansreport* c_ptr() const; protected: alglib_impl::kmeansreport *p_struct; }; class kmeansreport : public _kmeansreport_owner { public: kmeansreport(); kmeansreport(const kmeansreport &rhs); kmeansreport& operator=(const kmeansreport &rhs); virtual ~kmeansreport(); ae_int_t &npoints; ae_int_t &nfeatures; ae_int_t &terminationtype; ae_int_t &iterationscount; double &energy; ae_int_t &k; real_2d_array c; integer_1d_array cidx; }; /************************************************************************* *************************************************************************/ class _decisionforest_owner { public: _decisionforest_owner(); _decisionforest_owner(const _decisionforest_owner &rhs); _decisionforest_owner& operator=(const _decisionforest_owner &rhs); virtual ~_decisionforest_owner(); alglib_impl::decisionforest* c_ptr(); alglib_impl::decisionforest* c_ptr() const; protected: alglib_impl::decisionforest *p_struct; }; class decisionforest : public _decisionforest_owner { public: decisionforest(); decisionforest(const decisionforest &rhs); decisionforest& operator=(const decisionforest &rhs); virtual ~decisionforest(); }; /************************************************************************* *************************************************************************/ class _dfreport_owner { public: _dfreport_owner(); _dfreport_owner(const _dfreport_owner &rhs); _dfreport_owner& operator=(const _dfreport_owner &rhs); virtual ~_dfreport_owner(); alglib_impl::dfreport* c_ptr(); alglib_impl::dfreport* c_ptr() const; protected: alglib_impl::dfreport *p_struct; }; class dfreport : public _dfreport_owner { public: dfreport(); dfreport(const dfreport &rhs); dfreport& operator=(const dfreport &rhs); virtual ~dfreport(); double &relclserror; double &avgce; double &rmserror; double &avgerror; double &avgrelerror; double &oobrelclserror; double &oobavgce; double &oobrmserror; double &oobavgerror; double &oobavgrelerror; }; /************************************************************************* *************************************************************************/ class _linearmodel_owner { public: _linearmodel_owner(); _linearmodel_owner(const _linearmodel_owner &rhs); _linearmodel_owner& operator=(const _linearmodel_owner &rhs); virtual ~_linearmodel_owner(); alglib_impl::linearmodel* c_ptr(); alglib_impl::linearmodel* c_ptr() const; protected: alglib_impl::linearmodel *p_struct; }; class linearmodel : public _linearmodel_owner { public: linearmodel(); linearmodel(const linearmodel &rhs); linearmodel& operator=(const linearmodel &rhs); virtual ~linearmodel(); }; /************************************************************************* LRReport structure contains additional information about linear model: * C - covariation matrix, array[0..NVars,0..NVars]. C[i,j] = Cov(A[i],A[j]) * RMSError - root mean square error on a training set * AvgError - average error on a training set * AvgRelError - average relative error on a training set (excluding observations with zero function value). * CVRMSError - leave-one-out cross-validation estimate of generalization error. Calculated using fast algorithm with O(NVars*NPoints) complexity. * CVAvgError - cross-validation estimate of average error * CVAvgRelError - cross-validation estimate of average relative error All other fields of the structure are intended for internal use and should not be used outside ALGLIB. *************************************************************************/ class _lrreport_owner { public: _lrreport_owner(); _lrreport_owner(const _lrreport_owner &rhs); _lrreport_owner& operator=(const _lrreport_owner &rhs); virtual ~_lrreport_owner(); alglib_impl::lrreport* c_ptr(); alglib_impl::lrreport* c_ptr() const; protected: alglib_impl::lrreport *p_struct; }; class lrreport : public _lrreport_owner { public: lrreport(); lrreport(const lrreport &rhs); lrreport& operator=(const lrreport &rhs); virtual ~lrreport(); real_2d_array c; double &rmserror; double &avgerror; double &avgrelerror; double &cvrmserror; double &cvavgerror; double &cvavgrelerror; ae_int_t &ncvdefects; integer_1d_array cvdefects; }; /************************************************************************* Model's errors: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/ class _modelerrors_owner { public: _modelerrors_owner(); _modelerrors_owner(const _modelerrors_owner &rhs); _modelerrors_owner& operator=(const _modelerrors_owner &rhs); virtual ~_modelerrors_owner(); alglib_impl::modelerrors* c_ptr(); alglib_impl::modelerrors* c_ptr() const; protected: alglib_impl::modelerrors *p_struct; }; class modelerrors : public _modelerrors_owner { public: modelerrors(); modelerrors(const modelerrors &rhs); modelerrors& operator=(const modelerrors &rhs); virtual ~modelerrors(); double &relclserror; double &avgce; double &rmserror; double &avgerror; double &avgrelerror; }; /************************************************************************* *************************************************************************/ class _multilayerperceptron_owner { public: _multilayerperceptron_owner(); _multilayerperceptron_owner(const _multilayerperceptron_owner &rhs); _multilayerperceptron_owner& operator=(const _multilayerperceptron_owner &rhs); virtual ~_multilayerperceptron_owner(); alglib_impl::multilayerperceptron* c_ptr(); alglib_impl::multilayerperceptron* c_ptr() const; protected: alglib_impl::multilayerperceptron *p_struct; }; class multilayerperceptron : public _multilayerperceptron_owner { public: multilayerperceptron(); multilayerperceptron(const multilayerperceptron &rhs); multilayerperceptron& operator=(const multilayerperceptron &rhs); virtual ~multilayerperceptron(); }; /************************************************************************* *************************************************************************/ class _logitmodel_owner { public: _logitmodel_owner(); _logitmodel_owner(const _logitmodel_owner &rhs); _logitmodel_owner& operator=(const _logitmodel_owner &rhs); virtual ~_logitmodel_owner(); alglib_impl::logitmodel* c_ptr(); alglib_impl::logitmodel* c_ptr() const; protected: alglib_impl::logitmodel *p_struct; }; class logitmodel : public _logitmodel_owner { public: logitmodel(); logitmodel(const logitmodel &rhs); logitmodel& operator=(const logitmodel &rhs); virtual ~logitmodel(); }; /************************************************************************* MNLReport structure contains information about training process: * NGrad - number of gradient calculations * NHess - number of Hessian calculations *************************************************************************/ class _mnlreport_owner { public: _mnlreport_owner(); _mnlreport_owner(const _mnlreport_owner &rhs); _mnlreport_owner& operator=(const _mnlreport_owner &rhs); virtual ~_mnlreport_owner(); alglib_impl::mnlreport* c_ptr(); alglib_impl::mnlreport* c_ptr() const; protected: alglib_impl::mnlreport *p_struct; }; class mnlreport : public _mnlreport_owner { public: mnlreport(); mnlreport(const mnlreport &rhs); mnlreport& operator=(const mnlreport &rhs); virtual ~mnlreport(); ae_int_t &ngrad; ae_int_t &nhess; }; /************************************************************************* This structure is a MCPD (Markov Chains for Population Data) solver. You should use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ class _mcpdstate_owner { public: _mcpdstate_owner(); _mcpdstate_owner(const _mcpdstate_owner &rhs); _mcpdstate_owner& operator=(const _mcpdstate_owner &rhs); virtual ~_mcpdstate_owner(); alglib_impl::mcpdstate* c_ptr(); alglib_impl::mcpdstate* c_ptr() const; protected: alglib_impl::mcpdstate *p_struct; }; class mcpdstate : public _mcpdstate_owner { public: mcpdstate(); mcpdstate(const mcpdstate &rhs); mcpdstate& operator=(const mcpdstate &rhs); virtual ~mcpdstate(); }; /************************************************************************* This structure is a MCPD training report: InnerIterationsCount - number of inner iterations of the underlying optimization algorithm OuterIterationsCount - number of outer iterations of the underlying optimization algorithm NFEV - number of merit function evaluations TerminationType - termination type (same as for MinBLEIC optimizer, positive values denote success, negative ones - failure) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ class _mcpdreport_owner { public: _mcpdreport_owner(); _mcpdreport_owner(const _mcpdreport_owner &rhs); _mcpdreport_owner& operator=(const _mcpdreport_owner &rhs); virtual ~_mcpdreport_owner(); alglib_impl::mcpdreport* c_ptr(); alglib_impl::mcpdreport* c_ptr() const; protected: alglib_impl::mcpdreport *p_struct; }; class mcpdreport : public _mcpdreport_owner { public: mcpdreport(); mcpdreport(const mcpdreport &rhs); mcpdreport& operator=(const mcpdreport &rhs); virtual ~mcpdreport(); ae_int_t &inneriterationscount; ae_int_t &outeriterationscount; ae_int_t &nfev; ae_int_t &terminationtype; }; /************************************************************************* Neural networks ensemble *************************************************************************/ class _mlpensemble_owner { public: _mlpensemble_owner(); _mlpensemble_owner(const _mlpensemble_owner &rhs); _mlpensemble_owner& operator=(const _mlpensemble_owner &rhs); virtual ~_mlpensemble_owner(); alglib_impl::mlpensemble* c_ptr(); alglib_impl::mlpensemble* c_ptr() const; protected: alglib_impl::mlpensemble *p_struct; }; class mlpensemble : public _mlpensemble_owner { public: mlpensemble(); mlpensemble(const mlpensemble &rhs); mlpensemble& operator=(const mlpensemble &rhs); virtual ~mlpensemble(); }; /************************************************************************* Training report: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error * NGrad - number of gradient calculations * NHess - number of Hessian calculations * NCholesky - number of Cholesky decompositions NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/ class _mlpreport_owner { public: _mlpreport_owner(); _mlpreport_owner(const _mlpreport_owner &rhs); _mlpreport_owner& operator=(const _mlpreport_owner &rhs); virtual ~_mlpreport_owner(); alglib_impl::mlpreport* c_ptr(); alglib_impl::mlpreport* c_ptr() const; protected: alglib_impl::mlpreport *p_struct; }; class mlpreport : public _mlpreport_owner { public: mlpreport(); mlpreport(const mlpreport &rhs); mlpreport& operator=(const mlpreport &rhs); virtual ~mlpreport(); double &relclserror; double &avgce; double &rmserror; double &avgerror; double &avgrelerror; ae_int_t &ngrad; ae_int_t &nhess; ae_int_t &ncholesky; }; /************************************************************************* Cross-validation estimates of generalization error *************************************************************************/ class _mlpcvreport_owner { public: _mlpcvreport_owner(); _mlpcvreport_owner(const _mlpcvreport_owner &rhs); _mlpcvreport_owner& operator=(const _mlpcvreport_owner &rhs); virtual ~_mlpcvreport_owner(); alglib_impl::mlpcvreport* c_ptr(); alglib_impl::mlpcvreport* c_ptr() const; protected: alglib_impl::mlpcvreport *p_struct; }; class mlpcvreport : public _mlpcvreport_owner { public: mlpcvreport(); mlpcvreport(const mlpcvreport &rhs); mlpcvreport& operator=(const mlpcvreport &rhs); virtual ~mlpcvreport(); double &relclserror; double &avgce; double &rmserror; double &avgerror; double &avgrelerror; }; /************************************************************************* Trainer object for neural network. You should not try to access fields of this object directly - use ALGLIB functions to work with this object. *************************************************************************/ class _mlptrainer_owner { public: _mlptrainer_owner(); _mlptrainer_owner(const _mlptrainer_owner &rhs); _mlptrainer_owner& operator=(const _mlptrainer_owner &rhs); virtual ~_mlptrainer_owner(); alglib_impl::mlptrainer* c_ptr(); alglib_impl::mlptrainer* c_ptr() const; protected: alglib_impl::mlptrainer *p_struct; }; class mlptrainer : public _mlptrainer_owner { public: mlptrainer(); mlptrainer(const mlptrainer &rhs); mlptrainer& operator=(const mlptrainer &rhs); virtual ~mlptrainer(); }; /************************************************************************* Optimal binary classification Algorithms finds optimal (=with minimal cross-entropy) binary partition. Internal subroutine. INPUT PARAMETERS: A - array[0..N-1], variable C - array[0..N-1], class numbers (0 or 1). N - array size OUTPUT PARAMETERS: Info - completetion code: * -3, all values of A[] are same (partition is impossible) * -2, one of C[] is incorrect (<0, >1) * -1, incorrect pararemets were passed (N<=0). * 1, OK Threshold- partiton boundary. Left part contains values which are strictly less than Threshold. Right part contains values which are greater than or equal to Threshold. PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) CVE - cross-validation estimate of cross-entropy -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve); /************************************************************************* Optimal partition, internal subroutine. Fast version. Accepts: A array[0..N-1] array of attributes array[0..N-1] C array[0..N-1] array of class labels TiesBuf array[0..N] temporaries (ties) CntBuf array[0..2*NC-1] temporaries (counts) Alpha centering factor (0<=alpha<=1, recommended value - 0.05) BufR array[0..N-1] temporaries BufI array[0..N-1] temporaries Output: Info error code (">0"=OK, "<0"=bad) RMS training set RMS error CVRMS leave-one-out RMS error Note: content of all arrays is changed by subroutine; it doesn't allocate temporaries. -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/ void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms); /************************************************************************* This function initializes clusterizer object. Newly initialized object is empty, i.e. it does not contain dataset. You should use it as follows: 1. creation 2. dataset is added with ClusterizerSetPoints() 3. additional parameters are set 3. clusterization is performed with one of the clustering functions -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizercreate(clusterizerstate &s); /************************************************************************* This function adds dataset to the clusterizer structure. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm), non-squared * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| NOTE 1: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. NOTE 2: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric * k-means++ clustering algorithm may be used only with Euclidean distance function Thus, list of specific clustering algorithms you may use depends on distance function you specify when you set your dataset. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype); void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype); /************************************************************************* This function adds dataset given by distance matrix to the clusterizer structure. It is important that dataset is not given explicitly - only distance matrix is given. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - array[NPoints,NPoints], distance matrix given by its upper or lower triangle (main diagonal is ignored because its entries are expected to be zero). NPoints - number of points IsUpper - whether upper or lower triangle of D is given. NOTE 1: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric, including one which is given by distance matrix * k-means++ clustering algorithm may be used only with Euclidean distance function and explicitly given points - it can not be used with dataset given by distance matrix Thus, if you call this function, you will be unable to use k-means clustering algorithm to process your problem. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper); void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const bool isupper); /************************************************************************* This function sets agglomerative hierarchical clustering algorithm INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Algo - algorithm type: * 0 complete linkage (default algorithm) * 1 single linkage * 2 unweighted average linkage * 3 weighted average linkage * 4 Ward's method NOTE: Ward's method works correctly only with Euclidean distance, that's why algorithm will return negative termination code (failure) for any other distance type. It is possible, however, to use this method with user-supplied distance matrix. It is your responsibility to pass one which was calculated with Euclidean distance function. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetahcalgo(const clusterizerstate &s, const ae_int_t algo); /************************************************************************* This function sets k-means properties: number of restarts and maximum number of iterations per one run. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Restarts- restarts count, >=1. k-means++ algorithm performs several restarts and chooses best set of centers (one with minimum squared distance). MaxIts - maximum number of k-means iterations performed during one run. >=0, zero value means that algorithm performs unlimited number of iterations. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeanslimits(const clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits); /************************************************************************* This function sets k-means initialization algorithm. Several different algorithms can be chosen, including k-means++. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() InitAlgo- initialization algorithm: * 0 automatic selection ( different versions of ALGLIB may select different algorithms) * 1 random initialization * 2 k-means++ initialization (best quality of initial centers, but long non-parallelizable initialization phase with bad cache locality) * 3 "fast-greedy" algorithm with efficient, easy to parallelize initialization. Quality of initial centers is somewhat worse than that of k-means++. This algorithm is a default one in the current version of ALGLIB. *-1 "debug" algorithm which always selects first K rows of dataset; this algorithm is used for debug purposes only. Do not use it in the industrial code! -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ void clusterizersetkmeansinit(const clusterizerstate &s, const ae_int_t initalgo); /************************************************************************* This function performs agglomerative hierarchical clustering COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() OUTPUT PARAMETERS: Rep - clustering results; see description of AHCReport structure for more information. NOTE 1: hierarchical clustering algorithms require large amounts of memory. In particular, this implementation needs sizeof(double)*NPoints^2 bytes, which are used to store distance matrix. In case we work with user-supplied matrix, this amount is multiplied by 2 (we have to store original matrix and to work with its copy). For example, problem with 10000 points would require 800M of RAM, even when working in a 1-dimensional space. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunahc(const clusterizerstate &s, ahcreport &rep); void smp_clusterizerrunahc(const clusterizerstate &s, ahcreport &rep); /************************************************************************* This function performs clustering by k-means++ algorithm. You may change algorithm properties by calling: * ClusterizerSetKMeansLimits() to change number of restarts or iterations * ClusterizerSetKMeansInit() to change initialization algorithm By default, one restart and unlimited number of iterations are used. Initialization algorithm is chosen automatically. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (can be used from C# and C++) ! * access to high-performance C++ core (actual for C# users) ! ! K-means clustering algorithm has two phases: selection of initial ! centers and clustering itself. ALGLIB parallelizes both phases. ! Parallel version is optimized for the following scenario: medium or ! high-dimensional problem (20 or more dimensions) with large number of ! points and clusters. However, some speed-up can be obtained even when ! assumptions above are violated. ! ! As for native-vs-managed comparison, working with native core brings ! 30-40% improvement in speed over pure C# version of ALGLIB. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() K - number of clusters, K>=0. K can be zero only when algorithm is called for empty dataset, in this case completion code is set to success (+1). If K=0 and dataset size is non-zero, we can not meaningfully assign points to some center (there are no centers because K=0) and return -3 as completion code (failure). OUTPUT PARAMETERS: Rep - clustering results; see description of KMeansReport structure for more information. NOTE 1: k-means clustering can be performed only for datasets with Euclidean distance function. Algorithm will return negative completion code in Rep.TerminationType in case dataset was added to clusterizer with DistType other than Euclidean (or dataset was specified by distance matrix instead of explicitly given points). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep); void smp_clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep); /************************************************************************* This function returns distance matrix for dataset COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm, non-squared) * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| OUTPUT PARAMETERS: D - array[NPoints,NPoints], distance matrix (full matrix is returned, with lower and upper triangles) NOTE: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/ void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d); void smp_clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d); /************************************************************************* This function takes as input clusterization report Rep, desired clusters count K, and builds top K clusters from hierarchical clusterization tree. It returns assignment of points to clusters (array of cluster indexes). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY K - desired number of clusters, 1<=K<=NPoints. K can be zero only when NPoints=0. OUTPUT PARAMETERS: CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]=0 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep); /************************************************************************* This subroutine builds random decision forest. This function gives ability to tune number of variables used when choosing best split. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. NRndVars - number of variables used when choosing best split R - percent of a training set used to build individual trees. 01). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/ void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep); /************************************************************************* Procesing INPUT PARAMETERS: DF - decision forest model X - input vector, array[0..NVars-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also DFProcessI. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y); /************************************************************************* 'interactive' variant of DFProcess for languages like Python which support constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/ void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y); /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* RMS error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average relative error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/ double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Linear regression Subroutine builds model: Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) and model found in ALGLIB format, covariation matrix, training set errors (rms, average, average relative) and leave-one-out cross-validation estimate of the generalization error. CV estimate calculated using fast algorithm with O(NPoints*NVars) complexity. When covariation matrix is calculated standard deviations of function values are assumed to be equal to RMS error on the training set. INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints0. NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k); void filtersma(real_1d_array &x, const ae_int_t k); /************************************************************************* Filters: exponential moving averages. This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is defined as filter which replaces X[] by S[]: S[0] = X[0] S[t] = alpha*X[t] + (1-alpha)*S[t-1] INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 alpha - 0=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/ void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k); void filterlrma(real_1d_array &x, const ae_int_t k); /************************************************************************* Multiclass Fisher LDA Subroutine finds coefficients of linear combination which optimally separates training set on classes. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - linear combination coefficients, array[0..NVars-1] -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_1d_array &w); /************************************************************************* N-dimensional multiclass Fisher LDA Subroutine finds coefficients of linear combinations which optimally separates training set on classes. It returns N-dimensional basis whose vector are sorted by quality of training set separation (in descending order). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - basis, array[0..NVars-1,0..NVars-1] columns of matrix stores basis vectors, sorted by quality of training set separation (in descending order) -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/ void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w); void smp_fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w); /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void mlpserialize(multilayerperceptron &obj, std::string &s_out); /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void mlpunserialize(std::string &s_in, multilayerperceptron &obj); /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers, with linear output layer. Network weights are filled with small random values. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Same as MLPCreate0, but with one hidden layer (NHid neurons) with non-linear activation function. Output layer is linear. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) with non-linear activation function. Output layer is linear. $ALL -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values: (B, +INF), if D>=0 or (-INF, B), if D<0. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); /************************************************************************* Same as MLPCreateB0 but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); /************************************************************************* Same as MLPCreateB0 but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); /************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values [A,B]. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); /************************************************************************* Same as MLPCreateR0, but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); /************************************************************************* Same as MLPCreateR0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); /************************************************************************* Creates classifier network with NIn inputs and NOut possible classes. Network contains no hidden layers and linear output layer with SOFTMAX- normalization (so outputs sums up to 1.0 and converge to posterior probabilities). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Same as MLPCreateC0, but with one non-linear hidden layer. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Same as MLPCreateC0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network); /************************************************************************* Copying of neural network INPUT PARAMETERS: Network1 - original OUTPUT PARAMETERS: Network2 - copy -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpcopy(const multilayerperceptron &network1, multilayerperceptron &network2); /************************************************************************* This function copies tunable parameters (weights/means/sigmas) from one network to another with same architecture. It performs some rudimentary checks that architectures are same, and throws exception if check fails. It is intended for fast copying of states between two network which are known to have same geometry. INPUT PARAMETERS: Network1 - source, must be correctly initialized Network2 - target, must have same architecture OUTPUT PARAMETERS: Network2 - network state is copied from source to target -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/ void mlpcopytunableparameters(const multilayerperceptron &network1, const multilayerperceptron &network2); /************************************************************************* Randomization of neural network weights -- ALGLIB -- Copyright 06.11.2007 by Bochkanov Sergey *************************************************************************/ void mlprandomize(const multilayerperceptron &network); /************************************************************************* Randomization of neural network weights and standartisator -- ALGLIB -- Copyright 10.03.2008 by Bochkanov Sergey *************************************************************************/ void mlprandomizefull(const multilayerperceptron &network); /************************************************************************* Internal subroutine. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/ void mlpinitpreprocessor(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize); /************************************************************************* Returns information about initialized network: number of inputs, outputs, weights. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount); /************************************************************************* Returns number of inputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetinputscount(const multilayerperceptron &network); /************************************************************************* Returns number of outputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetoutputscount(const multilayerperceptron &network); /************************************************************************* Returns number of weights. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetweightscount(const multilayerperceptron &network); /************************************************************************* Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ bool mlpissoftmax(const multilayerperceptron &network); /************************************************************************* This function returns total number of layers (including input, hidden and output layers). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayerscount(const multilayerperceptron &network); /************************************************************************* This function returns size of K-th layer. K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. Size of the output layer is always equal to the number of outputs, although when we have softmax-normalized network, last neuron doesn't have any connections - it is just zero. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k); /************************************************************************* This function returns offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma); /************************************************************************* This function returns offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. In case we have SOFTMAX-normalized network, we return (Mean,Sigma)=(0.0,1.0). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma); /************************************************************************* This function returns information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) OUTPUT PARAMETERS: FKind - activation function type (used by MLPActivationFunction()) this value is zero for input or linear neurons Threshold - also called offset, bias zero for input neurons NOTE: this function throws exception if layer or neuron with given index do not exists. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpgetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold); /************************************************************************* This function returns information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) RESULT: connection weight (zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. returns zero if neurons exist, but there is no connection between them -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ double mlpgetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1); /************************************************************************* This function sets offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) NTE: I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network. This function sets Mean and Sigma. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetinputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma); /************************************************************************* This function sets offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) OUTPUT PARAMETERS: NOTE: I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. This function sets Sigma/Mean. In case we have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything other than(0.0,1.0) - this function will throw exception. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetoutputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma); /************************************************************************* This function modifies information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) FKind - activation function type (used by MLPActivationFunction()) this value must be zero for input neurons (you can not set activation function for input neurons) Threshold - also called offset, bias this value must be zero for input neurons (you can not set threshold for input neurons) NOTES: 1. this function throws exception if layer or neuron with given index do not exists. 2. this function also throws exception when you try to set non-linear activation function for input neurons (any kind of network) or for output neurons of classifier network. 3. this function throws exception when you try to set non-zero threshold for input neurons (any kind of network). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold); /************************************************************************* This function modifies information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) W - connection weight (must be zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. throws exception if you try to set non-zero weight for non-existent connection -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/ void mlpsetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w); /************************************************************************* Neural network activation function INPUT PARAMETERS: NET - neuron input K - function index (zero for linear function) OUTPUT PARAMETERS: F - function DF - its derivative D2F - its second derivative -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f); /************************************************************************* Procesing INPUT PARAMETERS: Network - neural network X - input vector, array[0..NIn-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also MLPProcessI -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpprocess(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y); /************************************************************************* 'interactive' variant of MLPProcess for languages like Python which support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 21.09.2010 by Bochkanov Sergey *************************************************************************/ void mlpprocessi(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y); /************************************************************************* Error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Error of the neural network on dataset given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0 RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* Natural error function for neural network, internal subroutine. NOTE: this function is single-threaded. Unlike other error function, it receives no speed-up from being executed in SMP mode. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlperrorn(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize); /************************************************************************* Classification error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: classification error (number of misclassified cases) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ ae_int_t mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); ae_int_t smp_mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Relative classification error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 25.12.2008 by Bochkanov Sergey *************************************************************************/ double mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Relative classification error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* Average cross-entropy (in bits per element) on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 08.01.2009 by Bochkanov Sergey *************************************************************************/ double mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average cross-entropy (in bits per element) on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 9.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* RMS error on the test set given. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ double mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* RMS error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* Average absolute error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average absolute error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* Average relative error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); double smp_mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average relative error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/ double mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); double smp_mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* Gradient calculation INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgrad(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad); /************************************************************************* Gradient calculation (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradn(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad); /************************************************************************* Batch gradient calculation for a set of inputs/outputs FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); void smp_mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); /************************************************************************* Batch gradient calculation for a set of inputs/outputs given by sparse matrices FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs. * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad); void smp_mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad); /************************************************************************* Batch gradient calculation for a subset of dataset FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); void smp_mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); /************************************************************************* Batch gradient calculation for a set of inputs/outputs for a subset of dataset given by set of indexes. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse function. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); void smp_mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); /************************************************************************* Batch gradient calculation for a set of inputs/outputs (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - set of inputs/outputs; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/ void mlpgradnbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); /************************************************************************* Batch Hessian calculation (natural error function) using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessiannbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h); /************************************************************************* Batch Hessian calculation using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/ void mlphessianbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h); /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); void smp_mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); /************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset given by sparse matrix; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ void mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); void smp_mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); /************************************************************************* Error of the neural network on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); double smp_mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); /************************************************************************* Error of the neural network on subset of sparse dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. SetSize - real size of XY, SetSize>=0; it is used when SubsetSize<0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/ double mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); double smp_mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); /************************************************************************* This subroutine trains logit model. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars] First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints=1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreate(const ae_int_t n, mcpdstate &s); /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state Such conditions basically mean that row of P which corresponds to "entry" state is zero. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn, but still no one leaves population * you want to model transitions of individuals from one state into another * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s); /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "exit" state and is treated in a special way: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that column of P which corresponds to "exit" state is zero. Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - individuals can move into "exit" state and leave population at the next turn, but there are no new individuals * amount of individuals which leave population can be predicted * you want to model transitions of individuals from one state into another (including transitions into the "exit" state) This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s); /************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-Exit-states" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state and another one component of X[] is called "exit" state and is treated in a special way too: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that: row of P which corresponds to "entry" state is zero column of P which corresponds to "exit" state is zero Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant * at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn * some individuals can move (predictably) into "exit" state and leave population at the next turn * you want to model transitions of individuals from one state into another, including transitions from the "entry" state and into the "exit" state. * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s); /************************************************************************* This function is used to add a track - sequence of system states at the different moments of its evolution. You may add one or several tracks to the MCPD solver. In case you have several tracks, they won't overwrite each other. For example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont try to model transition from t=A+3 to t=B+1. INPUT PARAMETERS: S - solver XY - track, array[K,N]: * I-th row is a state at t=I * elements of XY must be non-negative (exception will be thrown on negative elements) K - number of points in a track * if given, only leading K rows of XY are used * if not given, automatically determined from size of XY NOTES: 1. Track may contain either proportional or population data: * with proportional data all rows of XY must sum to 1.0, i.e. we have proportions instead of absolute population values * with population data rows of XY contain population counts and generally do not sum to 1.0 (although they still must be non-negative) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy, const ae_int_t k); void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy); /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place equality constraints on arbitrary subset of elements of P. Set of constraints is specified by EC, which may contain either NAN's or finite numbers from [0,1]. NAN denotes absence of constraint, finite number denotes equality constraint on specific element of P. You can also use MCPDAddEC() function which allows to ADD equality constraint for one element of P without changing constraints for other elements. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver EC - equality constraints, array[N,N]. Elements of EC can be either NAN's or finite numbers from [0,1]. NAN denotes absence of constraints, while finite value denotes equality constraint on the corresponding element of P. NOTES: 1. infinite values of EC will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetec(const mcpdstate &s, const real_2d_array &ec); /************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD equality constraint for one element of P without changing constraints for other elements. You can also use MCPDSetEC() function which allows you to specify arbitrary set of equality constraints in one call. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver I - row index of element being constrained J - column index of element being constrained C - value (constraint for P[I,J]). Can be either NAN (no constraint) or finite value from [0,1]. NOTES: 1. infinite values of C will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdaddec(const mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c); /************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD bound constraint for one element of P without changing constraints for other elements. You can also use MCPDSetBC() function which allows to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF=" (CT[i]>0). Your constraint may involve only some subset of P (less than N*N elements). For example it can be something like P[0,0] + P[0,1] = 0.5 In this case you still should pass matrix with N*N+1 columns, but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. INPUT PARAMETERS: S - solver C - array[K,N*N+1] - coefficients of constraints (see above for complete description) CT - array[K] - constraint types (see above for complete description) K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct); /************************************************************************* This function allows to tune amount of Tikhonov regularization being applied to your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change coefficient r. You can also change prior values with MCPDSetPrior() function. INPUT PARAMETERS: S - solver V - regularization coefficient, finite non-negative value. It is not recommended to specify zero value unless you are pretty sure that you want it. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsettikhonovregularizer(const mcpdstate &s, const double v); /************************************************************************* This function allows to set prior values used for regularization of your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change prior values prior_P. You can also change r with MCPDSetTikhonovRegularizer() function. INPUT PARAMETERS: S - solver PP - array[N,N], matrix of prior values: 1. elements must be real numbers from [0,1] 2. columns must sum to 1.0. First property is checked (exception is thrown otherwise), while second one is not checked/enforced. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetprior(const mcpdstate &s, const real_2d_array &pp); /************************************************************************* This function is used to change prediction weights MCPD solver scales prediction errors as follows Error(P) = ||W*(y-P*x)||^2 where x is a system state at time t y is a system state at time t+1 P is a transition matrix W is a diagonal scaling matrix By default, weights are chosen in order to minimize relative prediction error instead of absolute one. For example, if one component of state is about 0.5 in magnitude and another one is about 0.05, then algorithm will make corresponding weights equal to 2.0 and 20.0. INPUT PARAMETERS: S - solver PW - array[N], weights: * must be non-negative values (exception will be thrown otherwise) * zero values will be replaced by automatically chosen values -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsetpredictionweights(const mcpdstate &s, const real_1d_array &pw); /************************************************************************* This function is used to start solution of the MCPD problem. After return from this function, you can use MCPDResults() to get solution and completion code. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdsolve(const mcpdstate &s); /************************************************************************* MCPD results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: P - array[N,N], transition matrix Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one. Speaking short, positive values denote success, negative ones are failures. More information about fields of this structure can be found in the comments on MCPDReport datatype. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/ void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep); /************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/ void mlpeserialize(mlpensemble &obj, std::string &s_out); /************************************************************************* This function unserializes data structure from string. *************************************************************************/ void mlpeunserialize(std::string &s_in, mlpensemble &obj); /************************************************************************* Like MLPCreate0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreate1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreate2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateB0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateB1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateB2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateR0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateR1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateR2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateC0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateC1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Like MLPCreateC2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble); /************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlperandomize(const mlpensemble &ensemble); /************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout); /************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ bool mlpeissoftmax(const mlpensemble &ensemble); /************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocess(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y); /************************************************************************* 'interactive' variant of MLPEProcess for languages like Python which support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpeprocessi(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y); /************************************************************************* Relative classification error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Works both for classifier betwork and for regression networks which are used as classifiers. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlperelclserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if ensemble solves regression task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgce(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* RMS error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpermserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ double mlpeavgrelerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* Neural network training using modified Levenberg-Marquardt with exact Hessian calculation and regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for small and medium scale problems (hundreds of weights). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -9, if internal matrix inverse subroutine failed * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptrainlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); /************************************************************************* Neural network training using L-BFGS algorithm with regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for problems of any dimensionality (memory requirements and step complexity are linear by weights number). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. MaxIts - stopping criterion. Algorithm stops after MaxIts iterations (NOT gradient calculations). Zero MaxIts means stopping when step is sufficiently small. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlptrainlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep); /************************************************************************* Neural network training using early stopping (base algorithm - L-BFGS with regularization). INPUT PARAMETERS: Network - neural network with initialized geometry TrnXY - training set TrnSize - training set size, TrnSize>0 ValXY - validation set ValSize - validation set size, ValSize>0 Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts, either: * strictly positive number - algorithm make specified number of restarts from random position. * -1, in which case algorithm makes exactly one run from the initial state of the network (no randomization). If you don't know what Restarts to choose, choose one one the following: * -1 (deterministic start) * +1 (one random restart) * +5 (moderate amount of random restarts) OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1, ...). * 2, task has been solved, stopping criterion met - sufficiently small step size. Not expected (we use EARLY stopping) but possible and not an error. * 6, task has been solved, stopping criterion met - increasing of validation set error. Rep - training report NOTE: Algorithm stops if validation set error increases for a long enough or step size is small enought (there are task where validation set may decrease for eternity). In any case solution returned corresponds to the minimum of validation set error. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlptraines(const multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - L-BFGS. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep); /************************************************************************* Cross-validation estimate of generalization error. Base algorithm - Levenberg-Marquardt. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep); /************************************************************************* This function estimates generalization error using cross-validation on the current dataset with current training settings. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * FoldsCount cross-validation rounds (always) ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. Network is not changed during cross- validation and is not trained - it is used only as representative of its architecture. I.e., we estimate generalization properties of ARCHITECTURE, not some specific network. NRestarts - number of restarts, >=0: * NRestarts>0 means that for each cross-validation round specified number of random restarts is performed, with best network being chosen after training. * NRestarts=0 is same as NRestarts=1 FoldsCount - number of folds in k-fold cross-validation: * 2<=FoldsCount<=size of dataset * recommended value: 10. * values larger than dataset size will be silently truncated down to dataset size OUTPUT PARAMETERS: Rep - structure which contains cross-validation estimates: * Rep.RelCLSError - fraction of misclassified cases. * Rep.AvgCE - acerage cross-entropy * Rep.RMSError - root-mean-square error * Rep.AvgError - average error * Rep.AvgRelError - average relative error NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or subset with only one point was given, zeros are returned as estimates. NOTE: this method performs FoldsCount cross-validation rounds, each one with NRestarts random starts. Thus, FoldsCount*NRestarts networks are trained in total. NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError contain errors in prediction of posterior probabilities. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep); void smp_mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep); /************************************************************************* Creation of the network trainer object for regression networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NOut - number of outputs, NOut>=1 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any regression network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s); /************************************************************************* Creation of the network trainer object for classification networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any classification network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s); /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user. INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. NPoints - points count, >=0. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdataset(const mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints); /************************************************************************* This function sets "current dataset" of the trainer object to one passed by user (sparse matrix is used to store dataset). INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Any sparse storage format can be used: Hash-table, CRS... NPoints - points count, >=0 DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetsparsedataset(const mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints); /************************************************************************* This function sets weight decay coefficient which is used for training. INPUT PARAMETERS: S - trainer object Decay - weight decay coefficient, >=0. Weight decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 1.0E-3. Weight decay can be set to zero, in this case network is trained without weight decay. NOTE: by default network uses some small nonzero value for weight decay. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetdecay(const mlptrainer &s, const double decay); /************************************************************************* This function sets stopping criteria for the optimizer. INPUT PARAMETERS: S - trainer object WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. WStep>=0. MaxIts - stopping criterion. Algorithm stops after MaxIts epochs (full passes over entire dataset). Zero MaxIts means stopping when step is sufficiently small. MaxIts>=0. NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also used when MLPSetCond() is called with WStep=0 and MaxIts=0. NOTE: these stopping criteria are used for all kinds of neural training - from "conventional" networks to early stopping ensembles. When used for "conventional" networks, they are used as the only stopping criteria. When combined with early stopping, they used as ADDITIONAL stopping criteria which can terminate early stopping algorithm. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetcond(const mlptrainer &s, const double wstep, const ae_int_t maxits); /************************************************************************* This function sets training algorithm: batch training using L-BFGS will be used. This algorithm: * the most robust for small-scale problems, but may be too slow for large scale ones. * perfoms full pass through the dataset before performing step * uses conditions specified by MLPSetCond() for stopping * is default one used by trainer object INPUT PARAMETERS: S - trainer object -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpsetalgobatch(const mlptrainer &s); /************************************************************************* This function trains neural network passed to this function, using current dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) and current training settings. Training from NRestarts random starting positions is performed, best network is chosen. Training is performed using current training algorithm. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed, best network is chosen after training * NRestarts=0 means that current state of the network is used for training. OUTPUT PARAMETERS: Network - trained network NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), network is filled by zero values. Same behavior for functions MLPStartTraining and MLPContinueTraining. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep); void smp_mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep); /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. After call to this function trainer object remembers network and is ready to train it. However, no training is performed until first call to MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() will advance training progress one iteration further. EXAMPLE: > > ...initialize network and trainer object.... > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > ...visualize training progress... > INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. RandomStart - randomize network before training or not: * True means that network is randomized and its initial state (one which was passed to the trainer object) is lost. * False means that training is started from the current state of the network OUTPUT PARAMETERS: Network - neural network which is ready to training (weights are initialized, preprocessor is initialized using current training set) NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ void mlpstarttraining(const mlptrainer &s, const multilayerperceptron &network, const bool randomstart); /************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. This function performs one more iteration of the training and returns either True (training continues) or False (training stopped). In case True was returned, Network weights are updated according to the current state of the optimization progress. In case False was returned, no additional updates is performed (previous update of the network weights moved us to the final point, and no additional updates is needed). EXAMPLE: > > [initialize network and trainer object] > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > [visualize training progress] > INPUT PARAMETERS: S - trainer object Network - neural network structure, which is used to store current state of the training process. OUTPUT PARAMETERS: Network - weights of the neural network are rewritten by the current approximation. NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. NOTE: It is expected that Network is the same one which was passed to MLPStartTraining() function. However, THIS function checks only following: * that number of network inputs is consistent with trainer object settings * that number of network outputs/classes is consistent with trainer object settings * that number of network weights is the same as number of weights in the network passed to MLPStartTraining() function Exception is thrown when these conditions are violated. It is also expected that you do not change state of the network on your own - the only party who has right to change network during its training is a trainer object. Any attempt to interfere with trainer may lead to unpredictable results. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ bool mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network); bool smp_mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network); /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). Modified Levenberg-Marquardt algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglm(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors); /************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). L-BFGS algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/ void mlpebagginglbfgs(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors); /************************************************************************* Training neural networks ensemble using early stopping. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 6, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void mlpetraines(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); /************************************************************************* This function trains neural network ensemble passed to this function using current dataset and early stopping training algorithm. Each early stopping round performs NRestarts random restarts (thus, EnsembleSize*NRestarts training rounds is performed in total). FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * EnsembleSize training sessions performed for each of ensemble ! members (always parallelized) ! * NRestarts training sessions performed within each of training ! sessions (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object; Ensemble - neural network ensemble. It must have same number of inputs and outputs/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed during each ES round; * NRestarts=0 is silently replaced by 1. OUTPUT PARAMETERS: Ensemble - trained ensemble; Rep - it contains all type of errors. NOTE: this training method uses BOTH early stopping and weight decay! So, you should select weight decay before starting training just as you select it before training "conventional" networks. NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or single-point dataset was passed, ensemble is filled by zero values. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 22.08.2012 by Bochkanov Sergey *************************************************************************/ void mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep); void smp_mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep); /************************************************************************* Principal components analysis Subroutine builds orthogonal basis where first axis corresponds to direction with maximum variance, second axis maximizes variance in subspace orthogonal to first axis and so on. It should be noted that, unlike LDA, PCA does not use class labels. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - dataset, array[0..NPoints-1,0..NVars-1]. matrix contains ONLY INDEPENDENT VARIABLES. NPoints - dataset size, NPoints>=0 NVars - number of independent variables, NVars>=1 OUTPUT PARAMETERS: Info - return code: * -4, if SVD subroutine haven't converged * -1, if wrong parameters has been passed (NPoints<0, NVars<1) * 1, if task is solved S2 - array[0..NVars-1]. variance values corresponding to basis vectors. V - array[0..NVars-1,0..NVars-1] matrix, whose columns store basis vectors. -- ALGLIB -- Copyright 25.08.2008 by Bochkanov Sergey *************************************************************************/ void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, real_1d_array &s2, real_2d_array &v); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void dserrallocate(ae_int_t nclasses, /* Real */ ae_vector* buf, ae_state *_state); void dserraccumulate(/* Real */ ae_vector* buf, /* Real */ ae_vector* y, /* Real */ ae_vector* desiredy, ae_state *_state); void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state); void dsnormalize(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* means, /* Real */ ae_vector* sigmas, ae_state *_state); void dsnormalizec(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* means, /* Real */ ae_vector* sigmas, ae_state *_state); double dsgetmeanmindistance(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_state *_state); void dstie(/* Real */ ae_vector* a, ae_int_t n, /* Integer */ ae_vector* ties, ae_int_t* tiecount, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, ae_state *_state); void dstiefasti(/* Real */ ae_vector* a, /* Integer */ ae_vector* b, ae_int_t n, /* Integer */ ae_vector* ties, ae_int_t* tiecount, /* Real */ ae_vector* bufr, /* Integer */ ae_vector* bufi, ae_state *_state); void dsoptimalsplit2(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t* info, double* threshold, double* pal, double* pbl, double* par, double* pbr, double* cve, ae_state *_state); void dsoptimalsplit2fast(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, /* Integer */ ae_vector* tiesbuf, /* Integer */ ae_vector* cntbuf, /* Real */ ae_vector* bufr, /* Integer */ ae_vector* bufi, ae_int_t n, ae_int_t nc, double alpha, ae_int_t* info, double* threshold, double* rms, double* cvrms, ae_state *_state); void dssplitk(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t nc, ae_int_t kmax, ae_int_t* info, /* Real */ ae_vector* thresholds, ae_int_t* ni, double* cve, ae_state *_state); void dsoptimalsplitk(/* Real */ ae_vector* a, /* Integer */ ae_vector* c, ae_int_t n, ae_int_t nc, ae_int_t kmax, ae_int_t* info, /* Real */ ae_vector* thresholds, ae_int_t* ni, double* cve, ae_state *_state); void _cvreport_init(void* _p, ae_state *_state); void _cvreport_init_copy(void* _dst, void* _src, ae_state *_state); void _cvreport_clear(void* _p); void _cvreport_destroy(void* _p); void clusterizercreate(clusterizerstate* s, ae_state *_state); void clusterizersetpoints(clusterizerstate* s, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, ae_state *_state); void clusterizersetdistances(clusterizerstate* s, /* Real */ ae_matrix* d, ae_int_t npoints, ae_bool isupper, ae_state *_state); void clusterizersetahcalgo(clusterizerstate* s, ae_int_t algo, ae_state *_state); void clusterizersetkmeanslimits(clusterizerstate* s, ae_int_t restarts, ae_int_t maxits, ae_state *_state); void clusterizersetkmeansinit(clusterizerstate* s, ae_int_t initalgo, ae_state *_state); void clusterizerrunahc(clusterizerstate* s, ahcreport* rep, ae_state *_state); void _pexec_clusterizerrunahc(clusterizerstate* s, ahcreport* rep, ae_state *_state); void clusterizerrunkmeans(clusterizerstate* s, ae_int_t k, kmeansreport* rep, ae_state *_state); void _pexec_clusterizerrunkmeans(clusterizerstate* s, ae_int_t k, kmeansreport* rep, ae_state *_state); void clusterizergetdistances(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_state *_state); void _pexec_clusterizergetdistances(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_state *_state); void clusterizergetdistancesbuf(apbuffers* buf, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, /* Real */ ae_matrix* d, ae_state *_state); void clusterizergetkclusters(ahcreport* rep, ae_int_t k, /* Integer */ ae_vector* cidx, /* Integer */ ae_vector* cz, ae_state *_state); void clusterizerseparatedbydist(ahcreport* rep, double r, ae_int_t* k, /* Integer */ ae_vector* cidx, /* Integer */ ae_vector* cz, ae_state *_state); void clusterizerseparatedbycorr(ahcreport* rep, double r, ae_int_t* k, /* Integer */ ae_vector* cidx, /* Integer */ ae_vector* cz, ae_state *_state); void kmeansinitbuf(kmeansbuffers* buf, ae_state *_state); void kmeansgenerateinternal(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t k, ae_int_t initalgo, ae_int_t maxits, ae_int_t restarts, ae_bool kmeansdbgnoits, ae_int_t* info, ae_int_t* iterationscount, /* Real */ ae_matrix* ccol, ae_bool needccol, /* Real */ ae_matrix* crow, ae_bool needcrow, /* Integer */ ae_vector* xyc, double* energy, kmeansbuffers* buf, ae_state *_state); void kmeansupdatedistances(/* Real */ ae_matrix* xy, ae_int_t idx0, ae_int_t idx1, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t cidx0, ae_int_t cidx1, /* Integer */ ae_vector* xyc, /* Real */ ae_vector* xydist2, ae_shared_pool* bufferpool, ae_state *_state); void _kmeansbuffers_init(void* _p, ae_state *_state); void _kmeansbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _kmeansbuffers_clear(void* _p); void _kmeansbuffers_destroy(void* _p); void _clusterizerstate_init(void* _p, ae_state *_state); void _clusterizerstate_init_copy(void* _dst, void* _src, ae_state *_state); void _clusterizerstate_clear(void* _p); void _clusterizerstate_destroy(void* _p); void _ahcreport_init(void* _p, ae_state *_state); void _ahcreport_init_copy(void* _dst, void* _src, ae_state *_state); void _ahcreport_clear(void* _p); void _ahcreport_destroy(void* _p); void _kmeansreport_init(void* _p, ae_state *_state); void _kmeansreport_init_copy(void* _dst, void* _src, ae_state *_state); void _kmeansreport_clear(void* _p); void _kmeansreport_destroy(void* _p); void kmeansgenerate(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t k, ae_int_t restarts, ae_int_t* info, /* Real */ ae_matrix* c, /* Integer */ ae_vector* xyc, ae_state *_state); void dfbuildrandomdecisionforest(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, double r, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state); void dfbuildrandomdecisionforestx1(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, ae_int_t nrndvars, double r, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state); void dfbuildinternal(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, ae_int_t samplesize, ae_int_t nfeatures, ae_int_t flags, ae_int_t* info, decisionforest* df, dfreport* rep, ae_state *_state); void dfprocess(decisionforest* df, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void dfprocessi(decisionforest* df, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); double dfrelclserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double dfavgce(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double dfrmserror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double dfavgerror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double dfavgrelerror(decisionforest* df, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); void dfcopy(decisionforest* df1, decisionforest* df2, ae_state *_state); void dfalloc(ae_serializer* s, decisionforest* forest, ae_state *_state); void dfserialize(ae_serializer* s, decisionforest* forest, ae_state *_state); void dfunserialize(ae_serializer* s, decisionforest* forest, ae_state *_state); void _decisionforest_init(void* _p, ae_state *_state); void _decisionforest_init_copy(void* _dst, void* _src, ae_state *_state); void _decisionforest_clear(void* _p); void _decisionforest_destroy(void* _p); void _dfreport_init(void* _p, ae_state *_state); void _dfreport_init_copy(void* _dst, void* _src, ae_state *_state); void _dfreport_clear(void* _p); void _dfreport_destroy(void* _p); void _dfinternalbuffers_init(void* _p, ae_state *_state); void _dfinternalbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _dfinternalbuffers_clear(void* _p); void _dfinternalbuffers_destroy(void* _p); void lrbuild(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state); void lrbuilds(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state); void lrbuildzs(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state); void lrbuildz(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, linearmodel* lm, lrreport* ar, ae_state *_state); void lrunpack(linearmodel* lm, /* Real */ ae_vector* v, ae_int_t* nvars, ae_state *_state); void lrpack(/* Real */ ae_vector* v, ae_int_t nvars, linearmodel* lm, ae_state *_state); double lrprocess(linearmodel* lm, /* Real */ ae_vector* x, ae_state *_state); double lrrmserror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double lravgerror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double lravgrelerror(linearmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); void lrcopy(linearmodel* lm1, linearmodel* lm2, ae_state *_state); void lrlines(/* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_int_t n, ae_int_t* info, double* a, double* b, double* vara, double* varb, double* covab, double* corrab, double* p, ae_state *_state); void lrline(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t* info, double* a, double* b, ae_state *_state); void _linearmodel_init(void* _p, ae_state *_state); void _linearmodel_init_copy(void* _dst, void* _src, ae_state *_state); void _linearmodel_clear(void* _p); void _linearmodel_destroy(void* _p); void _lrreport_init(void* _p, ae_state *_state); void _lrreport_init_copy(void* _dst, void* _src, ae_state *_state); void _lrreport_clear(void* _p); void _lrreport_destroy(void* _p); void filtersma(/* Real */ ae_vector* x, ae_int_t n, ae_int_t k, ae_state *_state); void filterema(/* Real */ ae_vector* x, ae_int_t n, double alpha, ae_state *_state); void filterlrma(/* Real */ ae_vector* x, ae_int_t n, ae_int_t k, ae_state *_state); void fisherlda(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_vector* w, ae_state *_state); void fisherldan(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_matrix* w, ae_state *_state); void _pexec_fisherldan(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, /* Real */ ae_matrix* w, ae_state *_state); ae_int_t mlpgradsplitcost(ae_state *_state); ae_int_t mlpgradsplitsize(ae_state *_state); void mlpcreate0(ae_int_t nin, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcreate1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcreate2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcreateb0(ae_int_t nin, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state); void mlpcreateb1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state); void mlpcreateb2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, multilayerperceptron* network, ae_state *_state); void mlpcreater0(ae_int_t nin, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state); void mlpcreater1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state); void mlpcreater2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, multilayerperceptron* network, ae_state *_state); void mlpcreatec0(ae_int_t nin, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcreatec1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcreatec2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron* network, ae_state *_state); void mlpcopy(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state); void mlpcopyshared(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state); ae_bool mlpsamearchitecture(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state); void mlpcopytunableparameters(multilayerperceptron* network1, multilayerperceptron* network2, ae_state *_state); void mlpexporttunableparameters(multilayerperceptron* network, /* Real */ ae_vector* p, ae_int_t* pcount, ae_state *_state); void mlpimporttunableparameters(multilayerperceptron* network, /* Real */ ae_vector* p, ae_state *_state); void mlpserializeold(multilayerperceptron* network, /* Real */ ae_vector* ra, ae_int_t* rlen, ae_state *_state); void mlpunserializeold(/* Real */ ae_vector* ra, multilayerperceptron* network, ae_state *_state); void mlprandomize(multilayerperceptron* network, ae_state *_state); void mlprandomizefull(multilayerperceptron* network, ae_state *_state); void mlpinitpreprocessor(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state); void mlpinitpreprocessorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, ae_state *_state); void mlpinitpreprocessorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, ae_state *_state); void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, ae_state *_state); void mlpproperties(multilayerperceptron* network, ae_int_t* nin, ae_int_t* nout, ae_int_t* wcount, ae_state *_state); ae_int_t mlpntotal(multilayerperceptron* network, ae_state *_state); ae_int_t mlpgetinputscount(multilayerperceptron* network, ae_state *_state); ae_int_t mlpgetoutputscount(multilayerperceptron* network, ae_state *_state); ae_int_t mlpgetweightscount(multilayerperceptron* network, ae_state *_state); ae_bool mlpissoftmax(multilayerperceptron* network, ae_state *_state); ae_int_t mlpgetlayerscount(multilayerperceptron* network, ae_state *_state); ae_int_t mlpgetlayersize(multilayerperceptron* network, ae_int_t k, ae_state *_state); void mlpgetinputscaling(multilayerperceptron* network, ae_int_t i, double* mean, double* sigma, ae_state *_state); void mlpgetoutputscaling(multilayerperceptron* network, ae_int_t i, double* mean, double* sigma, ae_state *_state); void mlpgetneuroninfo(multilayerperceptron* network, ae_int_t k, ae_int_t i, ae_int_t* fkind, double* threshold, ae_state *_state); double mlpgetweight(multilayerperceptron* network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1, ae_state *_state); void mlpsetinputscaling(multilayerperceptron* network, ae_int_t i, double mean, double sigma, ae_state *_state); void mlpsetoutputscaling(multilayerperceptron* network, ae_int_t i, double mean, double sigma, ae_state *_state); void mlpsetneuroninfo(multilayerperceptron* network, ae_int_t k, ae_int_t i, ae_int_t fkind, double threshold, ae_state *_state); void mlpsetweight(multilayerperceptron* network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1, double w, ae_state *_state); void mlpactivationfunction(double net, ae_int_t k, double* f, double* df, double* d2f, ae_state *_state); void mlpprocess(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mlpprocessi(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); double mlperror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlperror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlperrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlperrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double mlperrorn(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state); ae_int_t mlpclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); ae_int_t _pexec_mlpclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlprelclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlprelclserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlprelclserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlprelclserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgce(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgce(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgcesparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgcesparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double mlprmserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlprmserror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlprmserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlprmserrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgrelerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgrelerror(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpavgrelerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); double _pexec_mlpavgrelerrorsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t npoints, ae_state *_state); void mlpgrad(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* desiredy, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradn(multilayerperceptron* network, /* Real */ ae_vector* x, /* Real */ ae_vector* desiredy, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void _pexec_mlpgradbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradbatchsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void _pexec_mlpgradbatchsparse(multilayerperceptron* network, sparsematrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradbatchsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void _pexec_mlpgradbatchsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradbatchsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void _pexec_mlpgradbatchsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* idx, ae_int_t subsetsize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlpgradbatchx(multilayerperceptron* network, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, ae_shared_pool* gradbuf, ae_state *_state); void mlpgradnbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, ae_state *_state); void mlphessiannbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state); void mlphessianbatch(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t ssize, double* e, /* Real */ ae_vector* grad, /* Real */ ae_matrix* h, ae_state *_state); void mlpinternalprocessvector(/* Integer */ ae_vector* structinfo, /* Real */ ae_vector* weights, /* Real */ ae_vector* columnmeans, /* Real */ ae_vector* columnsigmas, /* Real */ ae_vector* neurons, /* Real */ ae_vector* dfdnet, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mlpalloc(ae_serializer* s, multilayerperceptron* network, ae_state *_state); void mlpserialize(ae_serializer* s, multilayerperceptron* network, ae_state *_state); void mlpunserialize(ae_serializer* s, multilayerperceptron* network, ae_state *_state); void mlpallerrorssubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state); void _pexec_mlpallerrorssubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state); void mlpallerrorssparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state); void _pexec_mlpallerrorssparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, modelerrors* rep, ae_state *_state); double mlperrorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state); double _pexec_mlperrorsubset(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state); double mlperrorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state); double _pexec_mlperrorsparsesubset(multilayerperceptron* network, sparsematrix* xy, ae_int_t setsize, /* Integer */ ae_vector* subset, ae_int_t subsetsize, ae_state *_state); void mlpallerrorsx(multilayerperceptron* network, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, modelerrors* rep, ae_state *_state); void _modelerrors_init(void* _p, ae_state *_state); void _modelerrors_init_copy(void* _dst, void* _src, ae_state *_state); void _modelerrors_clear(void* _p); void _modelerrors_destroy(void* _p); void _smlpgrad_init(void* _p, ae_state *_state); void _smlpgrad_init_copy(void* _dst, void* _src, ae_state *_state); void _smlpgrad_clear(void* _p); void _smlpgrad_destroy(void* _p); void _multilayerperceptron_init(void* _p, ae_state *_state); void _multilayerperceptron_init_copy(void* _dst, void* _src, ae_state *_state); void _multilayerperceptron_clear(void* _p); void _multilayerperceptron_destroy(void* _p); void mnltrainh(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t* info, logitmodel* lm, mnlreport* rep, ae_state *_state); void mnlprocess(logitmodel* lm, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mnlprocessi(logitmodel* lm, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mnlunpack(logitmodel* lm, /* Real */ ae_matrix* a, ae_int_t* nvars, ae_int_t* nclasses, ae_state *_state); void mnlpack(/* Real */ ae_matrix* a, ae_int_t nvars, ae_int_t nclasses, logitmodel* lm, ae_state *_state); void mnlcopy(logitmodel* lm1, logitmodel* lm2, ae_state *_state); double mnlavgce(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mnlrelclserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mnlrmserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mnlavgerror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mnlavgrelerror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t ssize, ae_state *_state); ae_int_t mnlclserror(logitmodel* lm, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); void _logitmodel_init(void* _p, ae_state *_state); void _logitmodel_init_copy(void* _dst, void* _src, ae_state *_state); void _logitmodel_clear(void* _p); void _logitmodel_destroy(void* _p); void _logitmcstate_init(void* _p, ae_state *_state); void _logitmcstate_init_copy(void* _dst, void* _src, ae_state *_state); void _logitmcstate_clear(void* _p); void _logitmcstate_destroy(void* _p); void _mnlreport_init(void* _p, ae_state *_state); void _mnlreport_init_copy(void* _dst, void* _src, ae_state *_state); void _mnlreport_clear(void* _p); void _mnlreport_destroy(void* _p); void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state); void mcpdcreateentry(ae_int_t n, ae_int_t entrystate, mcpdstate* s, ae_state *_state); void mcpdcreateexit(ae_int_t n, ae_int_t exitstate, mcpdstate* s, ae_state *_state); void mcpdcreateentryexit(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state); void mcpdaddtrack(mcpdstate* s, /* Real */ ae_matrix* xy, ae_int_t k, ae_state *_state); void mcpdsetec(mcpdstate* s, /* Real */ ae_matrix* ec, ae_state *_state); void mcpdaddec(mcpdstate* s, ae_int_t i, ae_int_t j, double c, ae_state *_state); void mcpdsetbc(mcpdstate* s, /* Real */ ae_matrix* bndl, /* Real */ ae_matrix* bndu, ae_state *_state); void mcpdaddbc(mcpdstate* s, ae_int_t i, ae_int_t j, double bndl, double bndu, ae_state *_state); void mcpdsetlc(mcpdstate* s, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state); void mcpdsetprior(mcpdstate* s, /* Real */ ae_matrix* pp, ae_state *_state); void mcpdsetpredictionweights(mcpdstate* s, /* Real */ ae_vector* pw, ae_state *_state); void mcpdsolve(mcpdstate* s, ae_state *_state); void mcpdresults(mcpdstate* s, /* Real */ ae_matrix* p, mcpdreport* rep, ae_state *_state); void _mcpdstate_init(void* _p, ae_state *_state); void _mcpdstate_init_copy(void* _dst, void* _src, ae_state *_state); void _mcpdstate_clear(void* _p); void _mcpdstate_destroy(void* _p); void _mcpdreport_init(void* _p, ae_state *_state); void _mcpdreport_init_copy(void* _dst, void* _src, ae_state *_state); void _mcpdreport_clear(void* _p); void _mcpdreport_destroy(void* _p); void mlpecreate0(ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreate1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreate2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreateb0(ae_int_t nin, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreateb1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreateb2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreater0(ae_int_t nin, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreater1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreater2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreatec0(ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreatec1(ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreatec2(ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecreatefromnetwork(multilayerperceptron* network, ae_int_t ensemblesize, mlpensemble* ensemble, ae_state *_state); void mlpecopy(mlpensemble* ensemble1, mlpensemble* ensemble2, ae_state *_state); void mlperandomize(mlpensemble* ensemble, ae_state *_state); void mlpeproperties(mlpensemble* ensemble, ae_int_t* nin, ae_int_t* nout, ae_state *_state); ae_bool mlpeissoftmax(mlpensemble* ensemble, ae_state *_state); void mlpeprocess(mlpensemble* ensemble, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mlpeprocessi(mlpensemble* ensemble, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); void mlpeallerrorsx(mlpensemble* ensemble, /* Real */ ae_matrix* densexy, sparsematrix* sparsexy, ae_int_t datasetsize, ae_int_t datasettype, /* Integer */ ae_vector* idx, ae_int_t subset0, ae_int_t subset1, ae_int_t subsettype, ae_shared_pool* buf, modelerrors* rep, ae_state *_state); void mlpeallerrorssparse(mlpensemble* ensemble, sparsematrix* xy, ae_int_t npoints, double* relcls, double* avgce, double* rms, double* avg, double* avgrel, ae_state *_state); double mlperelclserror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpeavgce(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpermserror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpeavgerror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); double mlpeavgrelerror(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); void mlpealloc(ae_serializer* s, mlpensemble* ensemble, ae_state *_state); void mlpeserialize(ae_serializer* s, mlpensemble* ensemble, ae_state *_state); void mlpeunserialize(ae_serializer* s, mlpensemble* ensemble, ae_state *_state); void _mlpensemble_init(void* _p, ae_state *_state); void _mlpensemble_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpensemble_clear(void* _p); void _mlpensemble_destroy(void* _p); void mlptrainlm(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state); void mlptrainlbfgs(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, ae_state *_state); void mlptraines(multilayerperceptron* network, /* Real */ ae_matrix* trnxy, ae_int_t trnsize, /* Real */ ae_matrix* valxy, ae_int_t valsize, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state); void mlpkfoldcvlbfgs(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t foldscount, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state); void mlpkfoldcvlm(multilayerperceptron* network, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t foldscount, ae_int_t* info, mlpreport* rep, mlpcvreport* cvrep, ae_state *_state); void mlpkfoldcv(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport* rep, ae_state *_state); void _pexec_mlpkfoldcv(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport* rep, ae_state *_state); void mlpcreatetrainer(ae_int_t nin, ae_int_t nout, mlptrainer* s, ae_state *_state); void mlpcreatetrainercls(ae_int_t nin, ae_int_t nclasses, mlptrainer* s, ae_state *_state); void mlpsetdataset(mlptrainer* s, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_state *_state); void mlpsetsparsedataset(mlptrainer* s, sparsematrix* xy, ae_int_t npoints, ae_state *_state); void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state); void mlpsetcond(mlptrainer* s, double wstep, ae_int_t maxits, ae_state *_state); void mlpsetalgobatch(mlptrainer* s, ae_state *_state); void mlptrainnetwork(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, mlpreport* rep, ae_state *_state); void _pexec_mlptrainnetwork(mlptrainer* s, multilayerperceptron* network, ae_int_t nrestarts, mlpreport* rep, ae_state *_state); void mlpstarttraining(mlptrainer* s, multilayerperceptron* network, ae_bool randomstart, ae_state *_state); ae_bool mlpcontinuetraining(mlptrainer* s, multilayerperceptron* network, ae_state *_state); ae_bool _pexec_mlpcontinuetraining(mlptrainer* s, multilayerperceptron* network, ae_state *_state); void mlpebagginglm(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state); void mlpebagginglbfgs(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t* info, mlpreport* rep, mlpcvreport* ooberrors, ae_state *_state); void mlpetraines(mlpensemble* ensemble, /* Real */ ae_matrix* xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t* info, mlpreport* rep, ae_state *_state); void mlptrainensemblees(mlptrainer* s, mlpensemble* ensemble, ae_int_t nrestarts, mlpreport* rep, ae_state *_state); void _pexec_mlptrainensemblees(mlptrainer* s, mlpensemble* ensemble, ae_int_t nrestarts, mlpreport* rep, ae_state *_state); void _mlpreport_init(void* _p, ae_state *_state); void _mlpreport_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpreport_clear(void* _p); void _mlpreport_destroy(void* _p); void _mlpcvreport_init(void* _p, ae_state *_state); void _mlpcvreport_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpcvreport_clear(void* _p); void _mlpcvreport_destroy(void* _p); void _smlptrnsession_init(void* _p, ae_state *_state); void _smlptrnsession_init_copy(void* _dst, void* _src, ae_state *_state); void _smlptrnsession_clear(void* _p); void _smlptrnsession_destroy(void* _p); void _mlpetrnsession_init(void* _p, ae_state *_state); void _mlpetrnsession_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpetrnsession_clear(void* _p); void _mlpetrnsession_destroy(void* _p); void _mlptrainer_init(void* _p, ae_state *_state); void _mlptrainer_init_copy(void* _dst, void* _src, ae_state *_state); void _mlptrainer_clear(void* _p); void _mlptrainer_destroy(void* _p); void _mlpparallelizationcv_init(void* _p, ae_state *_state); void _mlpparallelizationcv_init_copy(void* _dst, void* _src, ae_state *_state); void _mlpparallelizationcv_clear(void* _p); void _mlpparallelizationcv_destroy(void* _p); void pcabuildbasis(/* Real */ ae_matrix* x, ae_int_t npoints, ae_int_t nvars, ae_int_t* info, /* Real */ ae_vector* s2, /* Real */ ae_matrix* v, ae_state *_state); } #endif qmapshack-1.10.0/3rdparty/alglib/src/solvers.cpp000755 001750 000144 00001721524 13015033052 022723 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "solvers.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* *************************************************************************/ _densesolverreport_owner::_densesolverreport_owner() { p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_densesolverreport_init(p_struct, NULL); } _densesolverreport_owner::_densesolverreport_owner(const _densesolverreport_owner &rhs) { p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _densesolverreport_owner& _densesolverreport_owner::operator=(const _densesolverreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_densesolverreport_clear(p_struct); alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _densesolverreport_owner::~_densesolverreport_owner() { alglib_impl::_densesolverreport_clear(p_struct); ae_free(p_struct); } alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() { return p_struct; } alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() const { return const_cast(p_struct); } densesolverreport::densesolverreport() : _densesolverreport_owner() ,r1(p_struct->r1),rinf(p_struct->rinf) { } densesolverreport::densesolverreport(const densesolverreport &rhs):_densesolverreport_owner(rhs) ,r1(p_struct->r1),rinf(p_struct->rinf) { } densesolverreport& densesolverreport::operator=(const densesolverreport &rhs) { if( this==&rhs ) return *this; _densesolverreport_owner::operator=(rhs); return *this; } densesolverreport::~densesolverreport() { } /************************************************************************* *************************************************************************/ _densesolverlsreport_owner::_densesolverlsreport_owner() { p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_densesolverlsreport_init(p_struct, NULL); } _densesolverlsreport_owner::_densesolverlsreport_owner(const _densesolverlsreport_owner &rhs) { p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _densesolverlsreport_owner& _densesolverlsreport_owner::operator=(const _densesolverlsreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_densesolverlsreport_clear(p_struct); alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _densesolverlsreport_owner::~_densesolverlsreport_owner() { alglib_impl::_densesolverlsreport_clear(p_struct); ae_free(p_struct); } alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() { return p_struct; } alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() const { return const_cast(p_struct); } densesolverlsreport::densesolverlsreport() : _densesolverlsreport_owner() ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) { } densesolverlsreport::densesolverlsreport(const densesolverlsreport &rhs):_densesolverlsreport_owner(rhs) ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) { } densesolverlsreport& densesolverlsreport::operator=(const densesolverlsreport &rhs) { if( this==&rhs ) return *this; _densesolverlsreport_owner::operator=(rhs); return *this; } densesolverlsreport::~densesolverlsreport() { } /************************************************************************* Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and b. This is "slow-but-feature rich" version of the linear solver. Faster version is RMatrixSolveFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix, x and b are vectors. This is a "fast" version of linear solver which does NOT provide any additional functions like condition number estimation or iterative refinement. Algorithm features: * efficient algorithm O(N^3) complexity * no performance overhead from additional functionality If you need condition number estimation or iterative refinement, use more feature-rich version - RMatrixSolve(). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsolvefast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsolvefast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "slow-but-robust" version of linear solver with additional functionality like condition number estimation. There also exists faster version - RMatrixSolveMFast(). Algorithm features: * automatic detection of degenerate cases * condition number estimation * optional iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 A is ill conditioned or singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "fast" version of linear solver which does NOT offer additional functions like condition number estimation or iterative refinement. Algorithm features: * O(N^3+M*N^2) complexity * no additional functionality, highest performance COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsolvemfast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsolvemfast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "slow-but-robust" version of the linear LU-based solver. Faster version is RMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlusolve(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "fast-without-any-checks" version of the linear LU-based solver. Slower but more robust version is RMatrixLUSolve() function. Algorithm features: * O(N^2) complexity * fast algorithm without ANY additional checks, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlusolvefast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "robust-but-slow" version of LU-based solver which performs additional checks for non-degeneracy of inputs (condition number estimation). If you need best performance, use "fast-without-any-checks" version, RMatrixLUSolveMFast(). Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts, where b and x are NxM matrices. This is "fast-without-any-checks" version of LU-based solver. It does not estimate condition number of a system, so it is extremely fast. If you need better detection of near-degenerate cases, use RMatrixLUSolveM() function. Algorithm features: * O(M*N^2) complexity * fast algorithm without ANY additional checks, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixlusolvemfast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixlusolvemfast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have both A and its LU decomposition. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixmixedsolve(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Similar to RMatrixMixedSolve() but solves task with multiple right parts (where b and x are NxM matrices). Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixmixedsolvem(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Slow-but-feature-rich" version which provides additional functions, at the cost of slower performance. Faster version may be invoked with CMatrixSolveMFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Fast-but-lightweight" version which provides just triangular solver - and no additional functions like iterative refinement or condition number estimation. Algorithm features: * O(N^3+M*N^2) complexity * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixsolvemfast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixsolvemfast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * no additional time consuming features, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixsolvefast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixsolvefast(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * no additional time-consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlusolvemfast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_cmatrixlusolvemfast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense linear solver for A*x=b with complex N*N A given by its LU decomposition and N*1 vectors x and b. This is "slow-but-robust" version of the complex linear solver with additional features which add significant performance overhead. Faster version is CMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlusolve(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Complex dense linear solver for A*x=b with N*N complex A given by its LU decomposition and N*1 vectors x and b. This is fast lightweight version of solver, which is significantly faster than CMatrixLUSolve(), but does not provide additional information (like condition numbers). Algorithm features: * O(N^2) complexity * no additional time-consuming features, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros NOTE: unlike CMatrixLUSolve(), this function does NOT check for near-degeneracy of input matrix. It checks for EXACT degeneracy, because this check is easy to do. However, very badly conditioned matrices may went unnoticed. -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixlusolvefast(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixmixedsolvem(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::cmatrixmixedsolve(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular * -1 N<=0 was passed * 1 task was solved B - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixsolvemfast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixsolvemfast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or non-SPD * -1 N<=0 was passed * 1 task was solved B - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixsolvefast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixsolvefast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- lightweight" version of the solver which just solves linear system, without any additional functions. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional functionality INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskysolvemfast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_spdmatrixcholeskysolvemfast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- but-feature-rich" version of the solver which, in addition to the solution, performs condition number estimation. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskysolve(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvefast(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::spdmatrixcholeskysolvefast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems (N<100). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - same as in RMatrixSolve. Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or is not positive definite. B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[0..N-1]: * overwritten by solution * zeros, if problem was not solved -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixsolvemfast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixsolvemfast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, HPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - same as in RMatrixSolve Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver without additional functions. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or not positive definite X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[0..N-1]: * overwritten by solution * zeros, if A is exactly singular (diagonal of its LU decomposition has exact zeros). -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixsolvefast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixsolvefast(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "slow-but-feature-rich" version of the solver which, in addition to the solution, estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large Cholesky decomposition. However, if you call ! this function many times for the same left side, this ! overhead BECOMES significant. It also becomes significant ! for small-scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskysolvemfast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_hpdmatrixcholeskysolvemfast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "slow-but-feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskysolve(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::hpdmatrixcholeskysolvefast(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Dense solver. This subroutine finds solution of the linear system A*X=B with non-square, possibly degenerate A. System is solved in the least squares sense, and general least squares solution X = X0 + CX*y which minimizes |A*X-B| is returned. If A is non-degenerate, solution in the usual sense is returned. Algorithm features: * automatic detection (and correct handling!) of degenerate cases * iterative refinement * O(N^3) complexity COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..NRows-1,0..NCols-1], system matrix NRows - vertical size of A NCols - horizontal size of A B - array[0..NCols-1], right part Threshold- a number in [0,1]. Singular values beyond Threshold are considered zero. Set it to 0.0, if you don't understand what it means, so the solver will choose good value on its own. OUTPUT PARAMETERS Info - return code: * -4 SVD subroutine failed * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed * 1 if task is solved Rep - solver report, see below for more info X - array[0..N-1,0..M-1], it contains: * solution of A*X=B (even for singular A) * zeros, if SVD subroutine failed SOLVER REPORT Subroutine sets following fields of the Rep structure: * R2 reciprocal of condition number: 1/cond(A), 2-norm. * N = NCols * K dim(Null(A)) * CX array[0..N-1,0..K-1], kernel of A. Columns of CX store such vectors that A*CX[i]=0. -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::rmatrixsolvels(const_cast(a.c_ptr()), nrows, ncols, const_cast(b.c_ptr()), threshold, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void smp_rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::_pexec_rmatrixsolvels(const_cast(a.c_ptr()), nrows, ncols, const_cast(b.c_ptr()), threshold, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores state of the LinLSQR method. You should use ALGLIB functions to work with this object. *************************************************************************/ _linlsqrstate_owner::_linlsqrstate_owner() { p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linlsqrstate_init(p_struct, NULL); } _linlsqrstate_owner::_linlsqrstate_owner(const _linlsqrstate_owner &rhs) { p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _linlsqrstate_owner& _linlsqrstate_owner::operator=(const _linlsqrstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_linlsqrstate_clear(p_struct); alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _linlsqrstate_owner::~_linlsqrstate_owner() { alglib_impl::_linlsqrstate_clear(p_struct); ae_free(p_struct); } alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() { return p_struct; } alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() const { return const_cast(p_struct); } linlsqrstate::linlsqrstate() : _linlsqrstate_owner() { } linlsqrstate::linlsqrstate(const linlsqrstate &rhs):_linlsqrstate_owner(rhs) { } linlsqrstate& linlsqrstate::operator=(const linlsqrstate &rhs) { if( this==&rhs ) return *this; _linlsqrstate_owner::operator=(rhs); return *this; } linlsqrstate::~linlsqrstate() { } /************************************************************************* *************************************************************************/ _linlsqrreport_owner::_linlsqrreport_owner() { p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linlsqrreport_init(p_struct, NULL); } _linlsqrreport_owner::_linlsqrreport_owner(const _linlsqrreport_owner &rhs) { p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _linlsqrreport_owner& _linlsqrreport_owner::operator=(const _linlsqrreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_linlsqrreport_clear(p_struct); alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _linlsqrreport_owner::~_linlsqrreport_owner() { alglib_impl::_linlsqrreport_clear(p_struct); ae_free(p_struct); } alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() { return p_struct; } alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() const { return const_cast(p_struct); } linlsqrreport::linlsqrreport() : _linlsqrreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) { } linlsqrreport::linlsqrreport(const linlsqrreport &rhs):_linlsqrreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) { } linlsqrreport& linlsqrreport::operator=(const linlsqrreport &rhs) { if( this==&rhs ) return *this; _linlsqrreport_owner::operator=(rhs); return *this; } linlsqrreport::~linlsqrreport() { } /************************************************************************* This function initializes linear LSQR Solver. This solver is used to solve non-symmetric (and, possibly, non-square) problems. Least squares solution is returned for non-compatible systems. USAGE: 1. User initializes algorithm state with LinLSQRCreate() call 2. User tunes solver parameters with LinLSQRSetCond() and other functions 3. User calls LinLSQRSolveSparse() function which takes algorithm state and SparseMatrix object. 4. User calls LinLSQRResults() to get solution 5. Optionally, user may call LinLSQRSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinLSQRState structure. INPUT PARAMETERS: M - number of rows in A N - number of variables, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrcreate(m, n, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function changes preconditioning settings of LinLSQQSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecunit(const linlsqrstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsetprecunit(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecdiag(const linlsqrstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsetprecdiag(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets optional Tikhonov regularization coefficient. It is zero by default. INPUT PARAMETERS: LambdaI - regularization factor, LambdaI>=0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetlambdai(const linlsqrstate &state, const double lambdai) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsetlambdai(const_cast(state.c_ptr()), lambdai, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse M*N matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function BEFORE you pass it to this function). B - right part, array[M] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinLSQRSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsolvesparse(const linlsqrstate &state, const sparsematrix &a, const real_1d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsolvesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| MaxIts - algorithm will be stopped if number of iterations more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will be setted as default values. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetcond(const linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsetcond(const_cast(state.c_ptr()), epsa, epsb, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LSQR solver: results. This function must be called after LinLSQRSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * 1 ||Rk||<=EpsB*||B|| * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, X contains best point found so far. (sometimes returned on singular systems) * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetxrep(const linlsqrstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::linlsqrsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores state of the linear CG method. You should use ALGLIB functions to work with this object. Never try to access its fields directly! *************************************************************************/ _lincgstate_owner::_lincgstate_owner() { p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lincgstate_init(p_struct, NULL); } _lincgstate_owner::_lincgstate_owner(const _lincgstate_owner &rhs) { p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _lincgstate_owner& _lincgstate_owner::operator=(const _lincgstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_lincgstate_clear(p_struct); alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _lincgstate_owner::~_lincgstate_owner() { alglib_impl::_lincgstate_clear(p_struct); ae_free(p_struct); } alglib_impl::lincgstate* _lincgstate_owner::c_ptr() { return p_struct; } alglib_impl::lincgstate* _lincgstate_owner::c_ptr() const { return const_cast(p_struct); } lincgstate::lincgstate() : _lincgstate_owner() { } lincgstate::lincgstate(const lincgstate &rhs):_lincgstate_owner(rhs) { } lincgstate& lincgstate::operator=(const lincgstate &rhs) { if( this==&rhs ) return *this; _lincgstate_owner::operator=(rhs); return *this; } lincgstate::~lincgstate() { } /************************************************************************* *************************************************************************/ _lincgreport_owner::_lincgreport_owner() { p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lincgreport_init(p_struct, NULL); } _lincgreport_owner::_lincgreport_owner(const _lincgreport_owner &rhs) { p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _lincgreport_owner& _lincgreport_owner::operator=(const _lincgreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_lincgreport_clear(p_struct); alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _lincgreport_owner::~_lincgreport_owner() { alglib_impl::_lincgreport_clear(p_struct); ae_free(p_struct); } alglib_impl::lincgreport* _lincgreport_owner::c_ptr() { return p_struct; } alglib_impl::lincgreport* _lincgreport_owner::c_ptr() const { return const_cast(p_struct); } lincgreport::lincgreport() : _lincgreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) { } lincgreport::lincgreport(const lincgreport &rhs):_lincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) { } lincgreport& lincgreport::operator=(const lincgreport &rhs) { if( this==&rhs ) return *this; _lincgreport_owner::operator=(rhs); return *this; } lincgreport::~lincgreport() { } /************************************************************************* This function initializes linear CG Solver. This solver is used to solve symmetric positive definite problems. If you want to solve nonsymmetric (or non-positive definite) problem you may use LinLSQR solver provided by ALGLIB. USAGE: 1. User initializes algorithm state with LinCGCreate() call 2. User tunes solver parameters with LinCGSetCond() and other functions 3. Optionally, user sets starting point with LinCGSetStartingPoint() 4. User calls LinCGSolveSparse() function which takes algorithm state and SparseMatrix object. 5. User calls LinCGResults() to get solution 6. Optionally, user may call LinCGSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinCGState structure. INPUT PARAMETERS: N - problem dimension, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgcreate(const ae_int_t n, lincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgcreate(n, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets starting point. By default, zero starting point is used. INPUT PARAMETERS: X - starting point, array[N] OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetstartingpoint(const lincgstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetstartingpoint(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecunit(const lincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetprecunit(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecdiag(const lincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetprecdiag(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsF - algorithm will be stopped if norm of residual is less than EpsF*||b||. MaxIts - algorithm will be stopped if number of iterations is more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: If both EpsF and MaxIts are zero then small EpsF will be set to small value. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetcond(const lincgstate &state, const double epsf, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetcond(const_cast(state.c_ptr()), epsf, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function). IsUpper - whether upper or lower triangle of A is used: * IsUpper=True => only upper triangle is used and lower triangle is not referenced at all * IsUpper=False => only lower triangle is used and upper triangle is not referenced at all B - right part, array[N] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinCGSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsolvesparse(const lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsolvesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* CG-solver: results. This function must be called after LinCGSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * -5 input matrix is either not positive definite, too large or too small * -4 overflow/underflow during solution (ill conditioned problem) * 1 ||residual||<=EpsF*||b|| * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, best point found is returned * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets restart frequency. By default, algorithm is restarted after N subsequent iterations. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrestartfreq(const lincgstate &state, const ae_int_t srf) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetrestartfreq(const_cast(state.c_ptr()), srf, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets frequency of residual recalculations. Algorithm updates residual r_k using iterative formula, but recalculates it from scratch after each 10 iterations. It is done to avoid accumulation of numerical errors and to stop algorithm when r_k starts to grow. Such low update frequence (1/10) gives very little overhead, but makes algorithm a bit more robust against numerical errors. However, you may change it INPUT PARAMETERS: Freq - desired update frequency, Freq>=0. Zero value means that no updates will be done. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrupdatefreq(const lincgstate &state, const ae_int_t freq) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetrupdatefreq(const_cast(state.c_ptr()), freq, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetxrep(const lincgstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::lincgsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _nleqstate_owner::_nleqstate_owner() { p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_nleqstate_init(p_struct, NULL); } _nleqstate_owner::_nleqstate_owner(const _nleqstate_owner &rhs) { p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _nleqstate_owner& _nleqstate_owner::operator=(const _nleqstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_nleqstate_clear(p_struct); alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _nleqstate_owner::~_nleqstate_owner() { alglib_impl::_nleqstate_clear(p_struct); ae_free(p_struct); } alglib_impl::nleqstate* _nleqstate_owner::c_ptr() { return p_struct; } alglib_impl::nleqstate* _nleqstate_owner::c_ptr() const { return const_cast(p_struct); } nleqstate::nleqstate() : _nleqstate_owner() ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } nleqstate::nleqstate(const nleqstate &rhs):_nleqstate_owner(rhs) ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } nleqstate& nleqstate::operator=(const nleqstate &rhs) { if( this==&rhs ) return *this; _nleqstate_owner::operator=(rhs); return *this; } nleqstate::~nleqstate() { } /************************************************************************* *************************************************************************/ _nleqreport_owner::_nleqreport_owner() { p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_nleqreport_init(p_struct, NULL); } _nleqreport_owner::_nleqreport_owner(const _nleqreport_owner &rhs) { p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _nleqreport_owner& _nleqreport_owner::operator=(const _nleqreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_nleqreport_clear(p_struct); alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _nleqreport_owner::~_nleqreport_owner() { alglib_impl::_nleqreport_clear(p_struct); ae_free(p_struct); } alglib_impl::nleqreport* _nleqreport_owner::c_ptr() { return p_struct; } alglib_impl::nleqreport* _nleqreport_owner::c_ptr() const { return const_cast(p_struct); } nleqreport::nleqreport() : _nleqreport_owner() ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) { } nleqreport::nleqreport(const nleqreport &rhs):_nleqreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) { } nleqreport& nleqreport::operator=(const nleqreport &rhs) { if( this==&rhs ) return *this; _nleqreport_owner::operator=(rhs); return *this; } nleqreport::~nleqreport() { } /************************************************************************* LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER DESCRIPTION: This algorithm solves system of nonlinear equations F[0](x[0], ..., x[n-1]) = 0 F[1](x[0], ..., x[n-1]) = 0 ... F[M-1](x[0], ..., x[n-1]) = 0 with M/N do not necessarily coincide. Algorithm converges quadratically under following conditions: * the solution set XS is nonempty * for some xs in XS there exist such neighbourhood N(xs) that: * vector function F(x) and its Jacobian J(x) are continuously differentiable on N * ||F(x)|| provides local error bound on N, i.e. there exists such c1, that ||F(x)||>c1*distance(x,XS) Note that these conditions are much more weaker than usual non-singularity conditions. For example, algorithm will converge for any affine function F (whether its Jacobian singular or not). REQUIREMENTS: Algorithm will request following information during its operation: * function vector F[] and Jacobian matrix at given point X * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X USAGE: 1. User initializes algorithm state with NLEQCreateLM() call 2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and other functions 3. User calls NLEQSolve() function which takes algorithm state and pointers (delegates, etc.) to callback functions which calculate merit function value and Jacobian. 4. User calls NLEQResults() to get solution 5. Optionally, user may call NLEQRestartFrom() to solve another problem with same parameters (N/M) but another starting point and/or another function vector. NLEQRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - space dimension, N>1: * if provided, only leading N elements of X are used * if not provided, determined automatically from size of X M - system size X - starting point OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with NLEQSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use NLEQSetStpMax() function to bound algorithm's steps. 3. this algorithm is a slightly modified implementation of the method described in 'Levenberg-Marquardt method for constrained nonlinear equations with strong local convergence properties' by Christian Kanzow Nobuo Yamashita and Masao Fukushima and further developed in 'On the convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang Yuan. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqcreatelm(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER DESCRIPTION: This algorithm solves system of nonlinear equations F[0](x[0], ..., x[n-1]) = 0 F[1](x[0], ..., x[n-1]) = 0 ... F[M-1](x[0], ..., x[n-1]) = 0 with M/N do not necessarily coincide. Algorithm converges quadratically under following conditions: * the solution set XS is nonempty * for some xs in XS there exist such neighbourhood N(xs) that: * vector function F(x) and its Jacobian J(x) are continuously differentiable on N * ||F(x)|| provides local error bound on N, i.e. there exists such c1, that ||F(x)||>c1*distance(x,XS) Note that these conditions are much more weaker than usual non-singularity conditions. For example, algorithm will converge for any affine function F (whether its Jacobian singular or not). REQUIREMENTS: Algorithm will request following information during its operation: * function vector F[] and Jacobian matrix at given point X * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X USAGE: 1. User initializes algorithm state with NLEQCreateLM() call 2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and other functions 3. User calls NLEQSolve() function which takes algorithm state and pointers (delegates, etc.) to callback functions which calculate merit function value and Jacobian. 4. User calls NLEQResults() to get solution 5. Optionally, user may call NLEQRestartFrom() to solve another problem with same parameters (N/M) but another starting point and/or another function vector. NLEQRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - space dimension, N>1: * if provided, only leading N elements of X are used * if not provided, determined automatically from size of X M - system size X - starting point OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with NLEQSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use NLEQSetStpMax() function to bound algorithm's steps. 3. this algorithm is a slightly modified implementation of the method described in 'Levenberg-Marquardt method for constrained nonlinear equations with strong local convergence properties' by Christian Kanzow Nobuo Yamashita and Masao Fukushima and further developed in 'On the convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang Yuan. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqcreatelm(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for the nonlinear solver INPUT PARAMETERS: State - structure which stores algorithm state EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition ||F||<=EpsF is satisfied MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic stopping criterion selection (small EpsF). NOTES: -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetcond(const nleqstate &state, const double epsf, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqsetcond(const_cast(state.c_ptr()), epsf, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to NLEQSolve(). -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetxrep(const nleqstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when target function contains exp() or other fast growing functions, and algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetstpmax(const nleqstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool nleqiteration(const nleqstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::nleqiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void nleqsolve(nleqstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'nleqsolve()' (func is NULL)"); if( jac==NULL ) throw ap_error("ALGLIB: error in 'nleqsolve()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::nleqiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'nleqsolve' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NLEQ solver results INPUT PARAMETERS: State - algorithm state. OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -4 ERROR: algorithm has converged to the stationary point Xf which is local minimum of f=F[0]^2+...+F[m-1]^2, but is not solution of nonlinear system. * 1 sqrt(f)<=EpsF. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations * ActiveConstraints contains number of active constraints -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NLEQ solver results Buffered implementation of NLEQResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinCGCreate call. X - new starting point. BndL - new lower bounds BndU - new upper bounds -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void nleqrestartfrom(const nleqstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::nleqrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _polynomialsolverreport_owner::_polynomialsolverreport_owner() { p_struct = (alglib_impl::polynomialsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialsolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_polynomialsolverreport_init(p_struct, NULL); } _polynomialsolverreport_owner::_polynomialsolverreport_owner(const _polynomialsolverreport_owner &rhs) { p_struct = (alglib_impl::polynomialsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialsolverreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_polynomialsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _polynomialsolverreport_owner& _polynomialsolverreport_owner::operator=(const _polynomialsolverreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_polynomialsolverreport_clear(p_struct); alglib_impl::_polynomialsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _polynomialsolverreport_owner::~_polynomialsolverreport_owner() { alglib_impl::_polynomialsolverreport_clear(p_struct); ae_free(p_struct); } alglib_impl::polynomialsolverreport* _polynomialsolverreport_owner::c_ptr() { return p_struct; } alglib_impl::polynomialsolverreport* _polynomialsolverreport_owner::c_ptr() const { return const_cast(p_struct); } polynomialsolverreport::polynomialsolverreport() : _polynomialsolverreport_owner() ,maxerr(p_struct->maxerr) { } polynomialsolverreport::polynomialsolverreport(const polynomialsolverreport &rhs):_polynomialsolverreport_owner(rhs) ,maxerr(p_struct->maxerr) { } polynomialsolverreport& polynomialsolverreport::operator=(const polynomialsolverreport &rhs) { if( this==&rhs ) return *this; _polynomialsolverreport_owner::operator=(rhs); return *this; } polynomialsolverreport::~polynomialsolverreport() { } /************************************************************************* Polynomial root finding. This function returns all roots of the polynomial P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n Both real and complex roots are returned (see below). INPUT PARAMETERS: A - array[N+1], polynomial coefficients: * A[0] is constant term * A[N] is a coefficient of X^N N - polynomial degree OUTPUT PARAMETERS: X - array of complex roots: * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 * complex roots are always returned in pairs - roots occupy positions I and I+1, with: * X[I+1]=Conj(X[I]) * IMAGE(X[I]) > 0 * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 * multiple real roots may have non-zero imaginary part due to roundoff errors. There is no reliable way to distinguish real root of multiplicity 2 from two complex roots in the presence of roundoff errors. Rep - report, additional information, following fields are set: * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field allows to quickly estimate "quality" of the roots being returned. NOTE: this function uses companion matrix method to find roots. In case internal EVD solver fails do find eigenvalues, exception is generated. NOTE: roots are not "polished" and no matrix balancing is performed for them. -- ALGLIB -- Copyright 24.02.2014 by Bochkanov Sergey *************************************************************************/ void polynomialsolve(const real_1d_array &a, const ae_int_t n, complex_1d_array &x, polynomialsolverreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::polynomialsolve(const_cast(a.c_ptr()), n, const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* a, ae_bool havea, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* a, ae_bool havea, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state); static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* a, ae_bool havea, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* a, ae_bool havea, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state); static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, double r1, double rinf, ae_state *_state); static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, double r2, ae_state *_state); static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* xb, ae_state *_state); static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* xb, ae_state *_state); static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* xb, ae_state *_state); static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* xb, ae_state *_state); static double linlsqr_atol = 1.0E-6; static double linlsqr_btol = 1.0E-6; static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state); static double lincg_defaultprecision = 1.0E-6; static void lincg_clearrfields(lincgstate* state, ae_state *_state); static void lincg_updateitersdata(lincgstate* state, ae_state *_state); static void nleq_clearrequestfields(nleqstate* state, ae_state *_state); static ae_bool nleq_increaselambda(double* lambdav, double* nu, double lambdaup, ae_state *_state); static void nleq_decreaselambda(double* lambdav, double* nu, double lambdadown, ae_state *_state); /************************************************************************* Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and b. This is "slow-but-feature rich" version of the linear solver. Faster version is RMatrixSolveFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_REAL, _state); ae_matrix_init(&xm, 0, 0, DT_REAL, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); rmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { rmatrixsolve(a,n,b,info,rep,x, _state); } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix, x and b are vectors. This is a "fast" version of linear solver which does NOT provide any additional functions like condition number estimation or iterative refinement. Algorithm features: * efficient algorithm O(N^3) complexity * no performance overhead from additional functionality If you need condition number estimation or iterative refinement, use more feature-rich version - RMatrixSolve(). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; ae_vector_init(&p, 0, DT_INT, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } rmatrixlu(a, n, n, &p, _state); for(i=0; i<=n-1; i++) { if( ae_fp_eq(a->ptr.pp_double[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { b->ptr.p_double[j] = 0.0; } *info = -3; ae_frame_leave(_state); return; } } densesolver_rbasiclusolve(a, &p, n, b, _state); *info = 1; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { rmatrixsolvefast(a,n,b,info, _state); } /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "slow-but-robust" version of linear solver with additional functionality like condition number estimation. There also exists faster version - RMatrixSolveMFast(). Algorithm features: * automatic detection of degenerate cases * condition number estimation * optional iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 A is ill conditioned or singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix da; ae_matrix emptya; ae_vector p; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&da, 0, 0, DT_REAL, _state); ae_matrix_init(&emptya, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&da, n, n, _state); /* * 1. factorize matrix * 3. solve */ for(i=0; i<=n-1; i++) { ae_v_move(&da.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } rmatrixlu(&da, n, n, &p, _state); if( rfs ) { densesolver_rmatrixlusolveinternal(&da, &p, n, a, ae_true, b, m, info, rep, x, _state); } else { densesolver_rmatrixlusolveinternal(&da, &p, n, &emptya, ae_false, b, m, info, rep, x, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { rmatrixsolvem(a,n,b,m,rfs,info,rep,x, _state); } /************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "fast" version of linear solver which does NOT offer additional functions like condition number estimation or iterative refinement. Algorithm features: * O(N^3+M*N^2) complexity * no additional functionality, highest performance COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; double v; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; ae_vector_init(&p, 0, DT_INT, _state); /* * Check for exact degeneracy */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } rmatrixlu(a, n, n, &p, _state); for(i=0; i<=n-1; i++) { if( ae_fp_eq(a->ptr.pp_double[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { for(k=0; k<=m-1; k++) { b->ptr.pp_double[j][k] = 0.0; } } *info = -3; ae_frame_leave(_state); return; } } /* * Solve with TRSM() */ for(i=0; i<=n-1; i++) { if( p.ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = b->ptr.pp_double[i][j]; b->ptr.pp_double[i][j] = b->ptr.pp_double[p.ptr.p_int[i]][j]; b->ptr.pp_double[p.ptr.p_int[i]][j] = v; } } } rmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); rmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); *info = 1; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { rmatrixsolvemfast(a,n,b,m,info, _state); } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "slow-but-robust" version of the linear LU-based solver. Faster version is RMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolve(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_REAL, _state); ae_matrix_init(&xm, 0, 0, DT_REAL, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); rmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "fast-without-any-checks" version of the linear LU-based solver. Slower but more robust version is RMatrixLUSolve() function. Algorithm features: * O(N^2) complexity * fast algorithm without ANY additional checks, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvefast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t j; *info = 0; if( n<=0 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( ae_fp_eq(lua->ptr.pp_double[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { b->ptr.p_double[j] = 0.0; } *info = -3; return; } } densesolver_rbasiclusolve(lua, p, n, b, _state); *info = 1; } /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "robust-but-slow" version of LU-based solver which performs additional checks for non-degeneracy of inputs (condition number estimation). If you need best performance, use "fast-without-any-checks" version, RMatrixLUSolveMFast(). Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvem(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix emptya; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&emptya, 0, 0, DT_REAL, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } /* * solve */ densesolver_rmatrixlusolveinternal(lua, p, n, &emptya, ae_false, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlusolvem(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { rmatrixlusolvem(lua,p,n,b,m,info,rep,x, _state); } /************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts, where b and x are NxM matrices. This is "fast-without-any-checks" version of LU-based solver. It does not estimate condition number of a system, so it is extremely fast. If you need better detection of near-degenerate cases, use RMatrixLUSolveM() function. Algorithm features: * O(M*N^2) complexity * fast algorithm without ANY additional checks, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void rmatrixlusolvemfast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { double v; ae_int_t i; ae_int_t j; ae_int_t k; *info = 0; /* * Check for exact degeneracy */ if( n<=0||m<=0 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( ae_fp_eq(lua->ptr.pp_double[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { for(k=0; k<=m-1; k++) { b->ptr.pp_double[j][k] = 0.0; } } *info = -3; return; } } /* * Solve with TRSM() */ for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = b->ptr.pp_double[i][j]; b->ptr.pp_double[i][j] = b->ptr.pp_double[p->ptr.p_int[i]][j]; b->ptr.pp_double[p->ptr.p_int[i]][j] = v; } } } rmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); rmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); *info = 1; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixlusolvemfast(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { rmatrixlusolvemfast(lua,p,n,b,m,info, _state); } /************************************************************************* Dense solver. This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have both A and its LU decomposition. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolve(/* Real */ ae_matrix* a, /* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_REAL, _state); ae_matrix_init(&xm, 0, 0, DT_REAL, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); rmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Dense solver. Similar to RMatrixMixedSolve() but solves task with multiple right parts (where b and x are NxM matrices). Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void rmatrixmixedsolvem(/* Real */ ae_matrix* a, /* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; return; } /* * solve */ densesolver_rmatrixlusolveinternal(lua, p, n, a, ae_true, b, m, info, rep, x, _state); } /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Slow-but-feature-rich" version which provides additional functions, at the cost of slower performance. Faster version may be invoked with CMatrixSolveMFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix da; ae_matrix emptya; ae_vector p; ae_int_t i; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&da, n, n, _state); /* * factorize, solve */ for(i=0; i<=n-1; i++) { ae_v_cmove(&da.ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); } cmatrixlu(&da, n, n, &p, _state); if( rfs ) { densesolver_cmatrixlusolveinternal(&da, &p, n, a, ae_true, b, m, info, rep, x, _state); } else { densesolver_cmatrixlusolveinternal(&da, &p, n, &emptya, ae_false, b, m, info, rep, x, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_bool rfs, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { cmatrixsolvem(a,n,b,m,rfs,info,rep,x, _state); } /************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Fast-but-lightweight" version which provides just triangular solver - and no additional functions like iterative refinement or condition number estimation. Algorithm features: * O(N^3+M*N^2) complexity * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_complex v; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; ae_vector_init(&p, 0, DT_INT, _state); /* * Check for exact degeneracy */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } cmatrixlu(a, n, n, &p, _state); for(i=0; i<=n-1; i++) { if( ae_c_eq_d(a->ptr.pp_complex[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { for(k=0; k<=m-1; k++) { b->ptr.pp_complex[j][k] = ae_complex_from_d(0.0); } } *info = -3; ae_frame_leave(_state); return; } } /* * Solve with TRSM() */ for(i=0; i<=n-1; i++) { if( p.ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = b->ptr.pp_complex[i][j]; b->ptr.pp_complex[i][j] = b->ptr.pp_complex[p.ptr.p_int[i]][j]; b->ptr.pp_complex[p.ptr.p_int[i]][j] = v; } } } cmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); cmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); *info = 1; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { cmatrixsolvemfast(a,n,b,m,info, _state); } /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); cmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { cmatrixsolve(a,n,b,info,rep,x, _state); } /************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * no additional time consuming features, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; ae_vector_init(&p, 0, DT_INT, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } cmatrixlu(a, n, n, &p, _state); for(i=0; i<=n-1; i++) { if( ae_c_eq_d(a->ptr.pp_complex[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { b->ptr.p_complex[j] = ae_complex_from_d(0.0); } *info = -3; ae_frame_leave(_state); return; } } densesolver_cbasiclusolve(a, &p, n, b, _state); *info = 1; ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { cmatrixsolvefast(a,n,b,info, _state); } /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvem(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix emptya; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } /* * solve */ densesolver_cmatrixlusolveinternal(lua, p, n, &emptya, ae_false, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlusolvem(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { cmatrixlusolvem(lua,p,n,b,m,info,rep,x, _state); } /************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * no additional time-consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvemfast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_complex v; ae_int_t i; ae_int_t j; ae_int_t k; *info = 0; /* * Check for exact degeneracy */ if( n<=0||m<=0 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( ae_c_eq_d(lua->ptr.pp_complex[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { for(k=0; k<=m-1; k++) { b->ptr.pp_complex[j][k] = ae_complex_from_d(0.0); } } *info = -3; return; } } /* * Solve with TRSM() */ for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = b->ptr.pp_complex[i][j]; b->ptr.pp_complex[i][j] = b->ptr.pp_complex[p->ptr.p_int[i]][j]; b->ptr.pp_complex[p->ptr.p_int[i]][j] = v; } } } cmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); cmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); *info = 1; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_cmatrixlusolvemfast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { cmatrixlusolvemfast(lua,p,n,b,m,info, _state); } /************************************************************************* Complex dense linear solver for A*x=b with complex N*N A given by its LU decomposition and N*1 vectors x and b. This is "slow-but-robust" version of the complex linear solver with additional features which add significant performance overhead. Faster version is CMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolve(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); cmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Complex dense linear solver for A*x=b with N*N complex A given by its LU decomposition and N*1 vectors x and b. This is fast lightweight version of solver, which is significantly faster than CMatrixLUSolve(), but does not provide additional information (like condition numbers). Algorithm features: * O(N^2) complexity * no additional time-consuming features, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros NOTE: unlike CMatrixLUSolve(), this function does NOT check for near-degeneracy of input matrix. It checks for EXACT degeneracy, because this check is easy to do. However, very badly conditioned matrices may went unnoticed. -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixlusolvefast(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t j; *info = 0; if( n<=0 ) { *info = -1; return; } for(i=0; i<=n-1; i++) { if( ae_c_eq_d(lua->ptr.pp_complex[i][i],(double)(0)) ) { for(j=0; j<=n-1; j++) { b->ptr.p_complex[j] = ae_complex_from_d(0.0); } *info = -3; return; } } densesolver_cbasiclusolve(lua, p, n, b, _state); *info = 1; } /************************************************************************* Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; return; } /* * solve */ densesolver_cmatrixlusolveinternal(lua, p, n, a, ae_true, b, m, info, rep, x, _state); } /************************************************************************* Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void cmatrixmixedsolve(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); cmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix da; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&da, 0, 0, DT_REAL, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&da, n, n, _state); /* * factorize * solve */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } ae_v_move(&da.ptr.pp_double[i][j1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(j1,j2)); } if( !spdmatrixcholesky(&da, n, isupper, _state) ) { ae_matrix_set_length(x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_double[i][j] = (double)(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } *info = 1; densesolver_spdmatrixcholeskysolveinternal(&da, n, isupper, a, ae_true, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixsolvem(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { spdmatrixsolvem(a,n,isupper,b,m,info,rep,x, _state); } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular * -1 N<=0 was passed * 1 task was solved B - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; *info = 1; if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } if( !spdmatrixcholesky(a, n, isupper, _state) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { b->ptr.pp_double[i][j] = 0.0; } } *info = -3; ae_frame_leave(_state); return; } if( isupper ) { rmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 1, b, 0, 0, _state); rmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); } else { rmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); rmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_false, 1, b, 0, 0, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixsolvemfast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { spdmatrixsolvemfast(a,n,isupper,b,m,info, _state); } /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_REAL, _state); ae_matrix_init(&xm, 0, 0, DT_REAL, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); spdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixsolve(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { spdmatrixsolve(a,n,isupper,b,info,rep,x, _state); } /************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or non-SPD * -1 N<=0 was passed * 1 task was solved B - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; *info = 1; if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } if( !spdmatrixcholesky(a, n, isupper, _state) ) { for(i=0; i<=n-1; i++) { b->ptr.p_double[i] = 0.0; } *info = -3; ae_frame_leave(_state); return; } densesolver_spdbasiccholeskysolve(a, n, isupper, b, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixsolvefast(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { spdmatrixsolvefast(a,n,isupper,b,info, _state); } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix emptya; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&emptya, 0, 0, DT_REAL, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } /* * solve */ densesolver_spdmatrixcholeskysolveinternal(cha, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { spdmatrixcholeskysolvem(cha,n,isupper,b,m,info,rep,x, _state); } /************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- lightweight" version of the solver which just solves linear system, without any additional functions. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional functionality INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvemfast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; *info = 0; *info = 1; if( n<=0 ) { *info = -1; return; } for(k=0; k<=n-1; k++) { if( ae_fp_eq(cha->ptr.pp_double[k][k],0.0) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { b->ptr.pp_double[i][j] = 0.0; } } *info = -3; return; } } if( isupper ) { rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 1, b, 0, 0, _state); rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); } else { rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 1, b, 0, 0, _state); } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_spdmatrixcholeskysolvemfast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { spdmatrixcholeskysolvemfast(cha,n,isupper,b,m,info, _state); } /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- but-feature-rich" version of the solver which, in addition to the solution, performs condition number estimation. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_REAL, _state); ae_matrix_init(&xm, 0, 0, DT_REAL, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); spdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void spdmatrixcholeskysolvefast(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t k; *info = 0; *info = 1; if( n<=0 ) { *info = -1; return; } for(k=0; k<=n-1; k++) { if( ae_fp_eq(cha->ptr.pp_double[k][k],0.0) ) { for(i=0; i<=n-1; i++) { b->ptr.p_double[i] = 0.0; } *info = -3; return; } } densesolver_spdbasiccholeskysolve(cha, n, isupper, b, _state); } /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems (N<100). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - same as in RMatrixSolve. Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix da; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&da, n, n, _state); /* * factorize matrix, solve */ for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } ae_v_cmove(&da.ptr.pp_complex[i][j1], 1, &a->ptr.pp_complex[i][j1], 1, "N", ae_v_len(j1,j2)); } if( !hpdmatrixcholesky(&da, n, isupper, _state) ) { ae_matrix_set_length(x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } *info = 1; densesolver_hpdmatrixcholeskysolveinternal(&da, n, isupper, a, ae_true, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixsolvem(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { hpdmatrixsolvem(a,n,isupper,b,m,info,rep,x, _state); } /************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or is not positive definite. B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[0..N-1]: * overwritten by solution * zeros, if problem was not solved -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; *info = 1; if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } if( !hpdmatrixcholesky(a, n, isupper, _state) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { b->ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } *info = -3; ae_frame_leave(_state); return; } if( isupper ) { cmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 2, b, 0, 0, _state); cmatrixlefttrsm(n, m, a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); } else { cmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); cmatrixlefttrsm(n, m, a, 0, 0, ae_false, ae_false, 2, b, 0, 0, _state); } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixsolvemfast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { hpdmatrixsolvemfast(a,n,isupper,b,m,info, _state); } /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, HPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - same as in RMatrixSolve Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); hpdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixsolve(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { hpdmatrixsolve(a,n,isupper,b,info,rep,x, _state); } /************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver without additional functions. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or not positive definite X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[0..N-1]: * overwritten by solution * zeros, if A is exactly singular (diagonal of its LU decomposition has exact zeros). -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; *info = 0; *info = 1; if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } if( !hpdmatrixcholesky(a, n, isupper, _state) ) { for(i=0; i<=n-1; i++) { b->ptr.p_complex[i] = ae_complex_from_d(0.0); } *info = -3; ae_frame_leave(_state); return; } densesolver_hpdbasiccholeskysolve(a, n, isupper, b, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixsolvefast(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { hpdmatrixsolvefast(a,n,isupper,b,info, _state); } /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "slow-but-feature-rich" version of the solver which, in addition to the solution, estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large Cholesky decomposition. However, if you call ! this function many times for the same left side, this ! overhead BECOMES significant. It also becomes significant ! for small-scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_matrix emptya; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } /* * 1. scale matrix, max(|U[i,j]|) * 2. factorize scaled matrix * 3. solve */ densesolver_hpdmatrixcholeskysolveinternal(cha, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { hpdmatrixcholeskysolvem(cha,n,isupper,b,m,info,rep,x, _state); } /************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvemfast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; *info = 0; *info = 1; if( n<=0 ) { *info = -1; return; } for(k=0; k<=n-1; k++) { if( ae_fp_eq(cha->ptr.pp_complex[k][k].x,0.0)&&ae_fp_eq(cha->ptr.pp_complex[k][k].y,0.0) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { b->ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } *info = -3; return; } } if( isupper ) { cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 2, b, 0, 0, _state); cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); } else { cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 2, b, 0, 0, _state); } } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_hpdmatrixcholeskysolvemfast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, ae_state *_state) { hpdmatrixcholeskysolvemfast(cha,n,isupper,b,m,info, _state); } /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "slow-but-feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_matrix bm; ae_matrix xm; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_vector_clear(x); ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state); if( n<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(&bm, n, 1, _state); ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); hpdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); ae_vector_set_length(x, n, _state); ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); ae_frame_leave(_state); } /************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/ void hpdmatrixcholeskysolvefast(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* b, ae_int_t* info, ae_state *_state) { ae_int_t i; ae_int_t k; *info = 0; *info = 1; if( n<=0 ) { *info = -1; return; } for(k=0; k<=n-1; k++) { if( ae_fp_eq(cha->ptr.pp_complex[k][k].x,0.0)&&ae_fp_eq(cha->ptr.pp_complex[k][k].y,0.0) ) { for(i=0; i<=n-1; i++) { b->ptr.p_complex[i] = ae_complex_from_d(0.0); } *info = -3; return; } } densesolver_hpdbasiccholeskysolve(cha, n, isupper, b, _state); } /************************************************************************* Dense solver. This subroutine finds solution of the linear system A*X=B with non-square, possibly degenerate A. System is solved in the least squares sense, and general least squares solution X = X0 + CX*y which minimizes |A*X-B| is returned. If A is non-degenerate, solution in the usual sense is returned. Algorithm features: * automatic detection (and correct handling!) of degenerate cases * iterative refinement * O(N^3) complexity COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..NRows-1,0..NCols-1], system matrix NRows - vertical size of A NCols - horizontal size of A B - array[0..NCols-1], right part Threshold- a number in [0,1]. Singular values beyond Threshold are considered zero. Set it to 0.0, if you don't understand what it means, so the solver will choose good value on its own. OUTPUT PARAMETERS Info - return code: * -4 SVD subroutine failed * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed * 1 if task is solved Rep - solver report, see below for more info X - array[0..N-1,0..M-1], it contains: * solution of A*X=B (even for singular A) * zeros, if SVD subroutine failed SOLVER REPORT Subroutine sets following fields of the Rep structure: * R2 reciprocal of condition number: 1/cond(A), 2-norm. * N = NCols * K dim(Null(A)) * CX array[0..N-1,0..K-1], kernel of A. Columns of CX store such vectors that A*CX[i]=0. -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/ void rmatrixsolvels(/* Real */ ae_matrix* a, ae_int_t nrows, ae_int_t ncols, /* Real */ ae_vector* b, double threshold, ae_int_t* info, densesolverlsreport* rep, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_vector sv; ae_matrix u; ae_matrix vt; ae_vector rp; ae_vector utb; ae_vector sutb; ae_vector tmp; ae_vector ta; ae_vector tx; ae_vector buf; ae_vector w; ae_int_t i; ae_int_t j; ae_int_t nsv; ae_int_t kernelidx; double v; double verr; ae_bool svdfailed; ae_bool zeroa; ae_int_t rfs; ae_int_t nrfs; ae_bool terminatenexttime; ae_bool smallerr; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverlsreport_clear(rep); ae_vector_clear(x); ae_vector_init(&sv, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_vector_init(&rp, 0, DT_REAL, _state); ae_vector_init(&utb, 0, DT_REAL, _state); ae_vector_init(&sutb, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&ta, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); ae_vector_init(&buf, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); if( (nrows<=0||ncols<=0)||ae_fp_less(threshold,(double)(0)) ) { *info = -1; ae_frame_leave(_state); return; } if( ae_fp_eq(threshold,(double)(0)) ) { threshold = 1000*ae_machineepsilon; } /* * Factorize A first */ svdfailed = !rmatrixsvd(a, nrows, ncols, 1, 2, 2, &sv, &u, &vt, _state); zeroa = ae_fp_eq(sv.ptr.p_double[0],(double)(0)); if( svdfailed||zeroa ) { if( svdfailed ) { *info = -4; } else { *info = 1; } ae_vector_set_length(x, ncols, _state); for(i=0; i<=ncols-1; i++) { x->ptr.p_double[i] = (double)(0); } rep->n = ncols; rep->k = ncols; ae_matrix_set_length(&rep->cx, ncols, ncols, _state); for(i=0; i<=ncols-1; i++) { for(j=0; j<=ncols-1; j++) { if( i==j ) { rep->cx.ptr.pp_double[i][j] = (double)(1); } else { rep->cx.ptr.pp_double[i][j] = (double)(0); } } } rep->r2 = (double)(0); ae_frame_leave(_state); return; } nsv = ae_minint(ncols, nrows, _state); if( nsv==ncols ) { rep->r2 = sv.ptr.p_double[nsv-1]/sv.ptr.p_double[0]; } else { rep->r2 = (double)(0); } rep->n = ncols; *info = 1; /* * Iterative refinement of xc combined with solution: * 1. xc = 0 * 2. calculate r = bc-A*xc using extra-precise dot product * 3. solve A*y = r * 4. update x:=x+r * 5. goto 2 * * This cycle is executed until one of two things happens: * 1. maximum number of iterations reached * 2. last iteration decreased error to the lower limit */ ae_vector_set_length(&utb, nsv, _state); ae_vector_set_length(&sutb, nsv, _state); ae_vector_set_length(x, ncols, _state); ae_vector_set_length(&tmp, ncols, _state); ae_vector_set_length(&ta, ncols+1, _state); ae_vector_set_length(&tx, ncols+1, _state); ae_vector_set_length(&buf, ncols+1, _state); for(i=0; i<=ncols-1; i++) { x->ptr.p_double[i] = (double)(0); } kernelidx = nsv; for(i=0; i<=nsv-1; i++) { if( ae_fp_less_eq(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) { kernelidx = i; break; } } rep->k = ncols-kernelidx; nrfs = densesolver_densesolverrfsmaxv2(ncols, rep->r2, _state); terminatenexttime = ae_false; ae_vector_set_length(&rp, nrows, _state); for(rfs=0; rfs<=nrfs; rfs++) { if( terminatenexttime ) { break; } /* * calculate right part */ if( rfs==0 ) { ae_v_move(&rp.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nrows-1)); } else { smallerr = ae_true; for(i=0; i<=nrows-1; i++) { ae_v_move(&ta.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,ncols-1)); ta.ptr.p_double[ncols] = (double)(-1); ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,ncols-1)); tx.ptr.p_double[ncols] = b->ptr.p_double[i]; xdot(&ta, &tx, ncols+1, &buf, &v, &verr, _state); rp.ptr.p_double[i] = -v; smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); } if( smallerr ) { terminatenexttime = ae_true; } } /* * solve A*dx = rp */ for(i=0; i<=ncols-1; i++) { tmp.ptr.p_double[i] = (double)(0); } for(i=0; i<=nsv-1; i++) { utb.ptr.p_double[i] = (double)(0); } for(i=0; i<=nrows-1; i++) { v = rp.ptr.p_double[i]; ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nsv-1), v); } for(i=0; i<=nsv-1; i++) { if( iptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,ncols-1)); } /* * fill CX */ if( rep->k>0 ) { ae_matrix_set_length(&rep->cx, ncols, rep->k, _state); for(i=0; i<=rep->k-1; i++) { ae_v_move(&rep->cx.ptr.pp_double[0][i], rep->cx.stride, &vt.ptr.pp_double[kernelidx+i][0], 1, ae_v_len(0,ncols-1)); } } ae_frame_leave(_state); } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ void _pexec_rmatrixsolvels(/* Real */ ae_matrix* a, ae_int_t nrows, ae_int_t ncols, /* Real */ ae_vector* b, double threshold, ae_int_t* info, densesolverlsreport* rep, /* Real */ ae_vector* x, ae_state *_state) { rmatrixsolvels(a,nrows,ncols,b,threshold,info,rep,x, _state); } /************************************************************************* Internal LU solver -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_matrix* a, ae_bool havea, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t rfs; ae_int_t nrfs; ae_vector xc; ae_vector y; ae_vector bc; ae_vector xa; ae_vector xb; ae_vector tx; double v; double verr; double mxb; ae_bool smallerr; ae_bool terminatenexttime; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&bc, 0, DT_REAL, _state); ae_vector_init(&xa, 0, DT_REAL, _state); ae_vector_init(&xb, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]r1 = rmatrixlurcond1(lua, n, _state); rep->rinf = rmatrixlurcondinf(lua, n, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_double[i][j] = (double)(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } *info = 1; /* * First stage of solution: rough solution with TRSM() */ mxb = 0.0; for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = b->ptr.pp_double[i][j]; mxb = ae_maxreal(mxb, ae_fabs(v, _state), _state); x->ptr.pp_double[i][j] = v; } } for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = x->ptr.pp_double[i][j]; x->ptr.pp_double[i][j] = x->ptr.pp_double[p->ptr.p_int[i]][j]; x->ptr.pp_double[p->ptr.p_int[i]][j] = v; } } } rmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, x, 0, 0, _state); rmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); /* * Second stage: iterative refinement */ if( havea ) { for(k=0; k<=m-1; k++) { nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); terminatenexttime = ae_false; for(rfs=0; rfs<=nrfs-1; rfs++) { if( terminatenexttime ) { break; } /* * generate right part */ smallerr = ae_true; ae_v_move(&xb.ptr.p_double[0], 1, &x->ptr.pp_double[0][k], x->stride, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_move(&xa.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); xa.ptr.p_double[n] = (double)(-1); xb.ptr.p_double[n] = b->ptr.pp_double[i][k]; xdot(&xa, &xb, n+1, &tx, &v, &verr, _state); y.ptr.p_double[i] = -v; smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); } if( smallerr ) { terminatenexttime = ae_true; } /* * solve and update */ densesolver_rbasiclusolve(lua, p, n, &y, _state); ae_v_add(&x->ptr.pp_double[0][k], x->stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } } ae_frame_leave(_state); } /************************************************************************* Internal Cholesky solver -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* a, ae_bool havea, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Real */ ae_matrix* x, ae_state *_state) { ae_int_t i; ae_int_t j; *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; return; } ae_matrix_set_length(x, n, m, _state); /* * estimate condition number, test for near singularity */ rep->r1 = spdmatrixcholeskyrcond(cha, n, isupper, _state); rep->rinf = rep->r1; if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_double[i][j] = (double)(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; return; } *info = 1; /* * Solve with TRSM() */ for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]; } } if( isupper ) { rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 1, x, 0, 0, _state); rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); } else { rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, x, 0, 0, _state); rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 1, x, 0, 0, _state); } } /************************************************************************* Internal LU solver -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_matrix* a, ae_bool havea, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t rfs; ae_int_t nrfs; ae_vector xc; ae_vector y; ae_vector bc; ae_vector xa; ae_vector xb; ae_vector tx; ae_vector tmpbuf; ae_complex v; double verr; ae_bool smallerr; ae_bool terminatenexttime; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_vector_init(&xc, 0, DT_COMPLEX, _state); ae_vector_init(&y, 0, DT_COMPLEX, _state); ae_vector_init(&bc, 0, DT_COMPLEX, _state); ae_vector_init(&xa, 0, DT_COMPLEX, _state); ae_vector_init(&xb, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_COMPLEX, _state); ae_vector_init(&tmpbuf, 0, DT_REAL, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]r1 = cmatrixlurcond1(lua, n, _state); rep->rinf = cmatrixlurcondinf(lua, n, _state); if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } *info = 1; /* * First phase: solve with TRSM() */ for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_complex[i][j] = b->ptr.pp_complex[i][j]; } } for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { for(j=0; j<=m-1; j++) { v = x->ptr.pp_complex[i][j]; x->ptr.pp_complex[i][j] = x->ptr.pp_complex[p->ptr.p_int[i]][j]; x->ptr.pp_complex[p->ptr.p_int[i]][j] = v; } } } cmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, x, 0, 0, _state); cmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); /* * solve */ for(k=0; k<=m-1; k++) { ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); ae_v_cmove(&xc.ptr.p_complex[0], 1, &x->ptr.pp_complex[0][k], x->stride, "N", ae_v_len(0,n-1)); /* * Iterative refinement of xc: * * calculate r = bc-A*xc using extra-precise dot product * * solve A*y = r * * update x:=x+r * * This cycle is executed until one of two things happens: * 1. maximum number of iterations reached * 2. last iteration decreased error to the lower limit */ if( havea ) { nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); terminatenexttime = ae_false; for(rfs=0; rfs<=nrfs-1; rfs++) { if( terminatenexttime ) { break; } /* * generate right part */ smallerr = ae_true; ae_v_cmove(&xb.ptr.p_complex[0], 1, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_cmove(&xa.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); xa.ptr.p_complex[n] = ae_complex_from_i(-1); xb.ptr.p_complex[n] = bc.ptr.p_complex[i]; xcdot(&xa, &xb, n+1, &tmpbuf, &v, &verr, _state); y.ptr.p_complex[i] = ae_c_neg(v); smallerr = smallerr&&ae_fp_less(ae_c_abs(v, _state),4*verr); } if( smallerr ) { terminatenexttime = ae_true; } /* * solve and update */ densesolver_cbasiclusolve(lua, p, n, &y, _state); ae_v_cadd(&xc.ptr.p_complex[0], 1, &y.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); } } /* * Store xc. * Post-scale result. */ ae_v_cmove(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); } ae_frame_leave(_state); } /************************************************************************* Internal Cholesky solver -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_matrix* a, ae_bool havea, /* Complex */ ae_matrix* b, ae_int_t m, ae_int_t* info, densesolverreport* rep, /* Complex */ ae_matrix* x, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector xc; ae_vector y; ae_vector bc; ae_vector xa; ae_vector xb; ae_vector tx; ae_frame_make(_state, &_frame_block); *info = 0; _densesolverreport_clear(rep); ae_matrix_clear(x); ae_vector_init(&xc, 0, DT_COMPLEX, _state); ae_vector_init(&y, 0, DT_COMPLEX, _state); ae_vector_init(&bc, 0, DT_COMPLEX, _state); ae_vector_init(&xa, 0, DT_COMPLEX, _state); ae_vector_init(&xb, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_COMPLEX, _state); /* * prepare: check inputs, allocate space... */ if( n<=0||m<=0 ) { *info = -1; ae_frame_leave(_state); return; } ae_matrix_set_length(x, n, m, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&bc, n, _state); ae_vector_set_length(&tx, n+1, _state); ae_vector_set_length(&xa, n+1, _state); ae_vector_set_length(&xb, n+1, _state); /* * estimate condition number, test for near singularity */ rep->r1 = hpdmatrixcholeskyrcond(cha, n, isupper, _state); rep->rinf = rep->r1; if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } rep->r1 = (double)(0); rep->rinf = (double)(0); *info = -3; ae_frame_leave(_state); return; } *info = 1; /* * solve */ for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x->ptr.pp_complex[i][j] = b->ptr.pp_complex[i][j]; } } if( isupper ) { cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 2, x, 0, 0, _state); cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); } else { cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, x, 0, 0, _state); cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 2, x, 0, 0, _state); } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Returns maximum count of RFS iterations as function of: 1. machine epsilon 2. task size. 3. condition number -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, double r1, double rinf, ae_state *_state) { ae_int_t result; result = 5; return result; } /************************************************************************* Internal subroutine. Returns maximum count of RFS iterations as function of: 1. machine epsilon 2. task size. 3. norm-2 condition number -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, double r2, ae_state *_state) { ae_int_t result; result = densesolver_densesolverrfsmax(n, (double)(0), (double)(0), _state); return result; } /************************************************************************* Basic LU solver for PLU*x = y. This subroutine assumes that: * A=PLU is well-conditioned, so no zero divisions or overflow may occur -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Real */ ae_vector* xb, ae_state *_state) { ae_int_t i; double v; for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { v = xb->ptr.p_double[i]; xb->ptr.p_double[i] = xb->ptr.p_double[p->ptr.p_int[i]]; xb->ptr.p_double[p->ptr.p_int[i]] = v; } } for(i=1; i<=n-1; i++) { v = ae_v_dotproduct(&lua->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; } xb->ptr.p_double[n-1] = xb->ptr.p_double[n-1]/lua->ptr.pp_double[n-1][n-1]; for(i=n-2; i>=0; i--) { v = ae_v_dotproduct(&lua->ptr.pp_double[i][i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); xb->ptr.p_double[i] = (xb->ptr.p_double[i]-v)/lua->ptr.pp_double[i][i]; } } /************************************************************************* Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. This subroutine assumes that: * A*ScaleA is well scaled * A is well-conditioned, so no zero divisions or overflow may occur -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Real */ ae_vector* xb, ae_state *_state) { ae_int_t i; double v; /* * A = L*L' or A=U'*U */ if( isupper ) { /* * Solve U'*y=b first. */ for(i=0; i<=n-1; i++) { xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; if( iptr.p_double[i]; ae_v_subd(&xb->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), v); } } /* * Solve U*x=y then. */ for(i=n-1; i>=0; i--) { if( iptr.pp_double[i][i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; } xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; } } else { /* * Solve L*y=b first */ for(i=0; i<=n-1; i++) { if( i>0 ) { v = ae_v_dotproduct(&cha->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; } xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; } /* * Solve L'*x=y then. */ for(i=n-1; i>=0; i--) { xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; if( i>0 ) { v = xb->ptr.p_double[i]; ae_v_subd(&xb->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v); } } } } /************************************************************************* Basic LU solver for ScaleA*PLU*x = y. This subroutine assumes that: * L is well-scaled, and it is U which needs scaling by ScaleA. * A=PLU is well-conditioned, so no zero divisions or overflow may occur -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, /* Integer */ ae_vector* p, ae_int_t n, /* Complex */ ae_vector* xb, ae_state *_state) { ae_int_t i; ae_complex v; for(i=0; i<=n-1; i++) { if( p->ptr.p_int[i]!=i ) { v = xb->ptr.p_complex[i]; xb->ptr.p_complex[i] = xb->ptr.p_complex[p->ptr.p_int[i]]; xb->ptr.p_complex[p->ptr.p_int[i]] = v; } } for(i=1; i<=n-1; i++) { v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); } xb->ptr.p_complex[n-1] = ae_c_div(xb->ptr.p_complex[n-1],lua->ptr.pp_complex[n-1][n-1]); for(i=n-2; i>=0; i--) { v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); xb->ptr.p_complex[i] = ae_c_div(ae_c_sub(xb->ptr.p_complex[i],v),lua->ptr.pp_complex[i][i]); } } /************************************************************************* Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. This subroutine assumes that: * A*ScaleA is well scaled * A is well-conditioned, so no zero divisions or overflow may occur -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, ae_int_t n, ae_bool isupper, /* Complex */ ae_vector* xb, ae_state *_state) { ae_int_t i; ae_complex v; /* * A = L*L' or A=U'*U */ if( isupper ) { /* * Solve U'*y=b first. */ for(i=0; i<=n-1; i++) { xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_conj(cha->ptr.pp_complex[i][i], _state)); if( iptr.p_complex[i]; ae_v_csubc(&xb->ptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), v); } } /* * Solve U*x=y then. */ for(i=n-1; i>=0; i--) { if( iptr.pp_complex[i][i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); } xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],cha->ptr.pp_complex[i][i]); } } else { /* * Solve L*y=b first */ for(i=0; i<=n-1; i++) { if( i>0 ) { v = ae_v_cdotproduct(&cha->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); } xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],cha->ptr.pp_complex[i][i]); } /* * Solve L'*x=y then. */ for(i=n-1; i>=0; i--) { xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_conj(cha->ptr.pp_complex[i][i], _state)); if( i>0 ) { v = xb->ptr.p_complex[i]; ae_v_csubc(&xb->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), v); } } } } void _densesolverreport_init(void* _p, ae_state *_state) { densesolverreport *p = (densesolverreport*)_p; ae_touch_ptr((void*)p); } void _densesolverreport_init_copy(void* _dst, void* _src, ae_state *_state) { densesolverreport *dst = (densesolverreport*)_dst; densesolverreport *src = (densesolverreport*)_src; dst->r1 = src->r1; dst->rinf = src->rinf; } void _densesolverreport_clear(void* _p) { densesolverreport *p = (densesolverreport*)_p; ae_touch_ptr((void*)p); } void _densesolverreport_destroy(void* _p) { densesolverreport *p = (densesolverreport*)_p; ae_touch_ptr((void*)p); } void _densesolverlsreport_init(void* _p, ae_state *_state) { densesolverlsreport *p = (densesolverlsreport*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->cx, 0, 0, DT_REAL, _state); } void _densesolverlsreport_init_copy(void* _dst, void* _src, ae_state *_state) { densesolverlsreport *dst = (densesolverlsreport*)_dst; densesolverlsreport *src = (densesolverlsreport*)_src; dst->r2 = src->r2; ae_matrix_init_copy(&dst->cx, &src->cx, _state); dst->n = src->n; dst->k = src->k; } void _densesolverlsreport_clear(void* _p) { densesolverlsreport *p = (densesolverlsreport*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->cx); } void _densesolverlsreport_destroy(void* _p) { densesolverlsreport *p = (densesolverlsreport*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->cx); } /************************************************************************* This function initializes linear LSQR Solver. This solver is used to solve non-symmetric (and, possibly, non-square) problems. Least squares solution is returned for non-compatible systems. USAGE: 1. User initializes algorithm state with LinLSQRCreate() call 2. User tunes solver parameters with LinLSQRSetCond() and other functions 3. User calls LinLSQRSolveSparse() function which takes algorithm state and SparseMatrix object. 4. User calls LinLSQRResults() to get solution 5. Optionally, user may call LinLSQRSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinLSQRState structure. INPUT PARAMETERS: M - number of rows in A N - number of variables, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrcreate(ae_int_t m, ae_int_t n, linlsqrstate* state, ae_state *_state) { ae_int_t i; _linlsqrstate_clear(state); ae_assert(m>0, "LinLSQRCreate: M<=0", _state); ae_assert(n>0, "LinLSQRCreate: N<=0", _state); state->m = m; state->n = n; state->prectype = 0; state->epsa = linlsqr_atol; state->epsb = linlsqr_btol; state->epsc = 1/ae_sqrt(ae_machineepsilon, _state); state->maxits = 0; state->lambdai = (double)(0); state->xrep = ae_false; state->running = ae_false; /* * * allocate arrays * * set RX to NAN (just for the case user calls Results() without * calling SolveSparse() * * set B to zero */ normestimatorcreate(m, n, 2, 2, &state->nes, _state); ae_vector_set_length(&state->rx, state->n, _state); ae_vector_set_length(&state->ui, state->m+state->n, _state); ae_vector_set_length(&state->uip1, state->m+state->n, _state); ae_vector_set_length(&state->vip1, state->n, _state); ae_vector_set_length(&state->vi, state->n, _state); ae_vector_set_length(&state->omegai, state->n, _state); ae_vector_set_length(&state->omegaip1, state->n, _state); ae_vector_set_length(&state->d, state->n, _state); ae_vector_set_length(&state->x, state->m+state->n, _state); ae_vector_set_length(&state->mv, state->m+state->n, _state); ae_vector_set_length(&state->mtv, state->n, _state); ae_vector_set_length(&state->b, state->m, _state); for(i=0; i<=n-1; i++) { state->rx.ptr.p_double[i] = _state->v_nan; } for(i=0; i<=m-1; i++) { state->b.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&state->rstate.ia, 1+1, _state); ae_vector_set_length(&state->rstate.ra, 0+1, _state); state->rstate.stage = -1; } /************************************************************************* This function sets right part. By default, right part is zero. INPUT PARAMETERS: B - right part, array[N]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetb(linlsqrstate* state, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t i; ae_assert(!state->running, "LinLSQRSetB: you can not change B when LinLSQRIteration is running", _state); ae_assert(state->m<=b->cnt, "LinLSQRSetB: Length(B)m, _state), "LinLSQRSetB: B contains infinite or NaN values", _state); state->bnorm2 = (double)(0); for(i=0; i<=state->m-1; i++) { state->b.ptr.p_double[i] = b->ptr.p_double[i]; state->bnorm2 = state->bnorm2+b->ptr.p_double[i]*b->ptr.p_double[i]; } } /************************************************************************* This function changes preconditioning settings of LinLSQQSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state) { ae_assert(!state->running, "LinLSQRSetPrecUnit: you can not change preconditioner, because function LinLSQRIteration is running!", _state); state->prectype = -1; } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state) { ae_assert(!state->running, "LinLSQRSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); state->prectype = 0; } /************************************************************************* This function sets optional Tikhonov regularization coefficient. It is zero by default. INPUT PARAMETERS: LambdaI - regularization factor, LambdaI>=0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetlambdai(linlsqrstate* state, double lambdai, ae_state *_state) { ae_assert(!state->running, "LinLSQRSetLambdaI: you can not set LambdaI, because function LinLSQRIteration is running", _state); ae_assert(ae_isfinite(lambdai, _state)&&ae_fp_greater_eq(lambdai,(double)(0)), "LinLSQRSetLambdaI: LambdaI is infinite or NaN", _state); state->lambdai = lambdai; } /************************************************************************* -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state) { ae_int_t summn; double bnorm; ae_int_t i; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { summn = state->rstate.ia.ptr.p_int[0]; i = state->rstate.ia.ptr.p_int[1]; bnorm = state->rstate.ra.ptr.p_double[0]; } else { summn = -983; i = -989; bnorm = -834; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } /* * Routine body */ ae_assert(state->b.cnt>0, "LinLSQRIteration: using non-allocated array B", _state); bnorm = ae_sqrt(state->bnorm2, _state); state->running = ae_true; state->repnmv = 0; linlsqr_clearrfields(state, _state); state->repiterationscount = 0; summn = state->m+state->n; state->r2 = state->bnorm2; /* *estimate for ANorm */ normestimatorrestart(&state->nes, _state); lbl_7: if( !normestimatoriteration(&state->nes, _state) ) { goto lbl_8; } if( !state->nes.needmv ) { goto lbl_9; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; linlsqr_clearrfields(state, _state); state->needmv = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needmv = ae_false; ae_v_move(&state->nes.mv.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); goto lbl_7; lbl_9: if( !state->nes.needmtv ) { goto lbl_11; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); /* *matrix-vector multiplication */ state->repnmv = state->repnmv+1; linlsqr_clearrfields(state, _state); state->needmtv = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->needmtv = ae_false; ae_v_move(&state->nes.mtv.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); goto lbl_7; lbl_11: goto lbl_7; lbl_8: normestimatorresults(&state->nes, &state->anorm, _state); /* *initialize .RX by zeros */ for(i=0; i<=state->n-1; i++) { state->rx.ptr.p_double[i] = (double)(0); } /* *output first report */ if( !state->xrep ) { goto lbl_13; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); linlsqr_clearrfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->xupdated = ae_false; lbl_13: /* * LSQR, Step 0. * * Algorithm outline corresponds to one which was described at p.50 of * "LSQR - an algorithm for sparse linear equations and sparse least * squares" by C.Paige and M.Saunders with one small addition - we * explicitly extend system matrix by additional N lines in order * to handle non-zero lambda, i.e. original A is replaced by * [ A ] * A_mod = [ ] * [ lambda*I ]. * * Step 0: * x[0] = 0 * beta[1]*u[1] = b * alpha[1]*v[1] = A_mod'*u[1] * w[1] = v[1] * phiBar[1] = beta[1] * rhoBar[1] = alpha[1] * d[0] = 0 * * NOTE: * There are three criteria for stopping: * (S0) maximum number of iterations * (S1) ||Rk||<=EpsB*||B||; * (S2) ||A^T*Rk||/(||A||*||Rk||)<=EpsA. * It is very important that S2 always checked AFTER S1. It is necessary * to avoid division by zero when Rk=0. */ state->betai = bnorm; if( ae_fp_eq(state->betai,(double)(0)) ) { /* * Zero right part */ state->running = ae_false; state->repterminationtype = 1; result = ae_false; return result; } for(i=0; i<=summn-1; i++) { if( im ) { state->ui.ptr.p_double[i] = state->b.ptr.p_double[i]/state->betai; } else { state->ui.ptr.p_double[i] = (double)(0); } state->x.ptr.p_double[i] = state->ui.ptr.p_double[i]; } state->repnmv = state->repnmv+1; linlsqr_clearrfields(state, _state); state->needmtv = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needmtv = ae_false; for(i=0; i<=state->n-1; i++) { state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->ui.ptr.p_double[state->m+i]; } state->alphai = (double)(0); for(i=0; i<=state->n-1; i++) { state->alphai = state->alphai+state->mtv.ptr.p_double[i]*state->mtv.ptr.p_double[i]; } state->alphai = ae_sqrt(state->alphai, _state); if( ae_fp_eq(state->alphai,(double)(0)) ) { /* * Orthogonality stopping criterion is met */ state->running = ae_false; state->repterminationtype = 4; result = ae_false; return result; } for(i=0; i<=state->n-1; i++) { state->vi.ptr.p_double[i] = state->mtv.ptr.p_double[i]/state->alphai; state->omegai.ptr.p_double[i] = state->vi.ptr.p_double[i]; } state->phibari = state->betai; state->rhobari = state->alphai; for(i=0; i<=state->n-1; i++) { state->d.ptr.p_double[i] = (double)(0); } state->dnorm = (double)(0); /* * Steps I=1, 2, ... */ lbl_15: if( ae_false ) { goto lbl_16; } /* * At I-th step State.RepIterationsCount=I. */ state->repiterationscount = state->repiterationscount+1; /* * Bidiagonalization part: * beta[i+1]*u[i+1] = A_mod*v[i]-alpha[i]*u[i] * alpha[i+1]*v[i+1] = A_mod'*u[i+1] - beta[i+1]*v[i] * * NOTE: beta[i+1]=0 or alpha[i+1]=0 will lead to successful termination * in the end of the current iteration. In this case u/v are zero. * NOTE2: algorithm won't fail on zero alpha or beta (there will be no * division by zero because it will be stopped BEFORE division * occurs). However, near-zero alpha and beta won't stop algorithm * and, although no division by zero will happen, orthogonality * in U and V will be lost. */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->vi.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; linlsqr_clearrfields(state, _state); state->needmv = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->needmv = ae_false; for(i=0; i<=state->n-1; i++) { state->mv.ptr.p_double[state->m+i] = state->lambdai*state->vi.ptr.p_double[i]; } state->betaip1 = (double)(0); for(i=0; i<=summn-1; i++) { state->uip1.ptr.p_double[i] = state->mv.ptr.p_double[i]-state->alphai*state->ui.ptr.p_double[i]; state->betaip1 = state->betaip1+state->uip1.ptr.p_double[i]*state->uip1.ptr.p_double[i]; } if( ae_fp_neq(state->betaip1,(double)(0)) ) { state->betaip1 = ae_sqrt(state->betaip1, _state); for(i=0; i<=summn-1; i++) { state->uip1.ptr.p_double[i] = state->uip1.ptr.p_double[i]/state->betaip1; } } ae_v_move(&state->x.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); state->repnmv = state->repnmv+1; linlsqr_clearrfields(state, _state); state->needmtv = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->needmtv = ae_false; for(i=0; i<=state->n-1; i++) { state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->uip1.ptr.p_double[state->m+i]; } state->alphaip1 = (double)(0); for(i=0; i<=state->n-1; i++) { state->vip1.ptr.p_double[i] = state->mtv.ptr.p_double[i]-state->betaip1*state->vi.ptr.p_double[i]; state->alphaip1 = state->alphaip1+state->vip1.ptr.p_double[i]*state->vip1.ptr.p_double[i]; } if( ae_fp_neq(state->alphaip1,(double)(0)) ) { state->alphaip1 = ae_sqrt(state->alphaip1, _state); for(i=0; i<=state->n-1; i++) { state->vip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]/state->alphaip1; } } /* * Build next orthogonal transformation */ state->rhoi = safepythag2(state->rhobari, state->betaip1, _state); state->ci = state->rhobari/state->rhoi; state->si = state->betaip1/state->rhoi; state->theta = state->si*state->alphaip1; state->rhobarip1 = -state->ci*state->alphaip1; state->phii = state->ci*state->phibari; state->phibarip1 = state->si*state->phibari; /* * Update .RNorm * * This tricky formula is necessary because simply writing * State.R2:=State.PhiBarIP1*State.PhiBarIP1 does NOT guarantees * monotonic decrease of R2. Roundoff error combined with 80-bit * precision used internally by Intel chips allows R2 to increase * slightly in some rare, but possible cases. This property is * undesirable, so we prefer to guard against R increase. */ state->r2 = ae_minreal(state->r2, state->phibarip1*state->phibarip1, _state); /* * Update d and DNorm, check condition-related stopping criteria */ for(i=0; i<=state->n-1; i++) { state->d.ptr.p_double[i] = 1/state->rhoi*(state->vi.ptr.p_double[i]-state->theta*state->d.ptr.p_double[i]); state->dnorm = state->dnorm+state->d.ptr.p_double[i]*state->d.ptr.p_double[i]; } if( ae_fp_greater_eq(ae_sqrt(state->dnorm, _state)*state->anorm,state->epsc) ) { state->running = ae_false; state->repterminationtype = 7; result = ae_false; return result; } /* * Update x, output report */ for(i=0; i<=state->n-1; i++) { state->rx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->phii/state->rhoi*state->omegai.ptr.p_double[i]; } if( !state->xrep ) { goto lbl_17; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); linlsqr_clearrfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->xupdated = ae_false; lbl_17: /* * Check stopping criteria * 1. achieved required number of iterations; * 2. ||Rk||<=EpsB*||B||; * 3. ||A^T*Rk||/(||A||*||Rk||)<=EpsA; */ if( state->maxits>0&&state->repiterationscount>=state->maxits ) { /* * Achieved required number of iterations */ state->running = ae_false; state->repterminationtype = 5; result = ae_false; return result; } if( ae_fp_less_eq(state->phibarip1,state->epsb*bnorm) ) { /* * ||Rk||<=EpsB*||B||, here ||Rk||=PhiBar */ state->running = ae_false; state->repterminationtype = 1; result = ae_false; return result; } if( ae_fp_less_eq(state->alphaip1*ae_fabs(state->ci, _state)/state->anorm,state->epsa) ) { /* * ||A^T*Rk||/(||A||*||Rk||)<=EpsA, here ||A^T*Rk||=PhiBar*Alpha[i+1]*|.C| */ state->running = ae_false; state->repterminationtype = 4; result = ae_false; return result; } /* * Update omega */ for(i=0; i<=state->n-1; i++) { state->omegaip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]-state->theta/state->rhoi*state->omegai.ptr.p_double[i]; } /* * Prepare for the next iteration - rename variables: * u[i] := u[i+1] * v[i] := v[i+1] * rho[i] := rho[i+1] * ... */ ae_v_move(&state->ui.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,summn-1)); ae_v_move(&state->vi.ptr.p_double[0], 1, &state->vip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_v_move(&state->omegai.ptr.p_double[0], 1, &state->omegaip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->alphai = state->alphaip1; state->betai = state->betaip1; state->phibari = state->phibarip1; state->rhobari = state->rhobarip1; goto lbl_15; lbl_16: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = summn; state->rstate.ia.ptr.p_int[1] = i; state->rstate.ra.ptr.p_double[0] = bnorm; return result; } /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse M*N matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function BEFORE you pass it to this function). B - right part, array[M] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinLSQRSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsolvesparse(linlsqrstate* state, sparsematrix* a, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t t0; ae_int_t t1; double v; n = state->n; ae_assert(!state->running, "LinLSQRSolveSparse: you can not call this function when LinLSQRIteration is running", _state); ae_assert(b->cnt>=state->m, "LinLSQRSolveSparse: Length(B)m, _state), "LinLSQRSolveSparse: B contains infinite or NaN values", _state); /* * Allocate temporaries */ rvectorsetlengthatleast(&state->tmpd, n, _state); rvectorsetlengthatleast(&state->tmpx, n, _state); /* * Compute diagonal scaling matrix D */ if( state->prectype==0 ) { /* * Default preconditioner - inverse of column norms */ for(i=0; i<=n-1; i++) { state->tmpd.ptr.p_double[i] = (double)(0); } t0 = 0; t1 = 0; while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) { state->tmpd.ptr.p_double[j] = state->tmpd.ptr.p_double[j]+ae_sqr(v, _state); } for(i=0; i<=n-1; i++) { if( ae_fp_greater(state->tmpd.ptr.p_double[i],(double)(0)) ) { state->tmpd.ptr.p_double[i] = 1/ae_sqrt(state->tmpd.ptr.p_double[i], _state); } else { state->tmpd.ptr.p_double[i] = (double)(1); } } } else { /* * No diagonal scaling */ for(i=0; i<=n-1; i++) { state->tmpd.ptr.p_double[i] = (double)(1); } } /* * Solve. * * Instead of solving A*x=b we solve preconditioned system (A*D)*(inv(D)*x)=b. * Transformed A is not calculated explicitly, we just modify multiplication * by A or A'. After solution we modify State.RX so it will store untransformed * variables */ linlsqrsetb(state, b, _state); linlsqrrestart(state, _state); while(linlsqriteration(state, _state)) { if( state->needmv ) { for(i=0; i<=n-1; i++) { state->tmpx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->x.ptr.p_double[i]; } sparsemv(a, &state->tmpx, &state->mv, _state); } if( state->needmtv ) { sparsemtv(a, &state->x, &state->mtv, _state); for(i=0; i<=n-1; i++) { state->mtv.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->mtv.ptr.p_double[i]; } } } for(i=0; i<=n-1; i++) { state->rx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->rx.ptr.p_double[i]; } } /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| MaxIts - algorithm will be stopped if number of iterations more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will be setted as default values. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetcond(linlsqrstate* state, double epsa, double epsb, ae_int_t maxits, ae_state *_state) { ae_assert(!state->running, "LinLSQRSetCond: you can not call this function when LinLSQRIteration is running", _state); ae_assert(ae_isfinite(epsa, _state)&&ae_fp_greater_eq(epsa,(double)(0)), "LinLSQRSetCond: EpsA is negative, INF or NAN", _state); ae_assert(ae_isfinite(epsb, _state)&&ae_fp_greater_eq(epsb,(double)(0)), "LinLSQRSetCond: EpsB is negative, INF or NAN", _state); ae_assert(maxits>=0, "LinLSQRSetCond: MaxIts is negative", _state); if( (ae_fp_eq(epsa,(double)(0))&&ae_fp_eq(epsb,(double)(0)))&&maxits==0 ) { state->epsa = linlsqr_atol; state->epsb = linlsqr_btol; state->maxits = state->n; } else { state->epsa = epsa; state->epsb = epsb; state->maxits = maxits; } } /************************************************************************* LSQR solver: results. This function must be called after LinLSQRSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * 1 ||Rk||<=EpsB*||B|| * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, X contains best point found so far. (sometimes returned on singular systems) * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrresults(linlsqrstate* state, /* Real */ ae_vector* x, linlsqrreport* rep, ae_state *_state) { ae_vector_clear(x); _linlsqrreport_clear(rep); ae_assert(!state->running, "LinLSQRResult: you can not call this function when LinLSQRIteration is running", _state); if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nmv = state->repnmv; rep->terminationtype = state->repterminationtype; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrsetxrep(linlsqrstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function restarts LinLSQRIteration -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ void linlsqrrestart(linlsqrstate* state, ae_state *_state) { ae_vector_set_length(&state->rstate.ia, 1+1, _state); ae_vector_set_length(&state->rstate.ra, 0+1, _state); state->rstate.stage = -1; linlsqr_clearrfields(state, _state); } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state) { state->xupdated = ae_false; state->needmv = ae_false; state->needmtv = ae_false; state->needmv2 = ae_false; state->needvmv = ae_false; state->needprec = ae_false; } void _linlsqrstate_init(void* _p, ae_state *_state) { linlsqrstate *p = (linlsqrstate*)_p; ae_touch_ptr((void*)p); _normestimatorstate_init(&p->nes, _state); ae_vector_init(&p->rx, 0, DT_REAL, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->ui, 0, DT_REAL, _state); ae_vector_init(&p->uip1, 0, DT_REAL, _state); ae_vector_init(&p->vi, 0, DT_REAL, _state); ae_vector_init(&p->vip1, 0, DT_REAL, _state); ae_vector_init(&p->omegai, 0, DT_REAL, _state); ae_vector_init(&p->omegaip1, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->mv, 0, DT_REAL, _state); ae_vector_init(&p->mtv, 0, DT_REAL, _state); ae_vector_init(&p->tmpd, 0, DT_REAL, _state); ae_vector_init(&p->tmpx, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _linlsqrstate_init_copy(void* _dst, void* _src, ae_state *_state) { linlsqrstate *dst = (linlsqrstate*)_dst; linlsqrstate *src = (linlsqrstate*)_src; _normestimatorstate_init_copy(&dst->nes, &src->nes, _state); ae_vector_init_copy(&dst->rx, &src->rx, _state); ae_vector_init_copy(&dst->b, &src->b, _state); dst->n = src->n; dst->m = src->m; dst->prectype = src->prectype; ae_vector_init_copy(&dst->ui, &src->ui, _state); ae_vector_init_copy(&dst->uip1, &src->uip1, _state); ae_vector_init_copy(&dst->vi, &src->vi, _state); ae_vector_init_copy(&dst->vip1, &src->vip1, _state); ae_vector_init_copy(&dst->omegai, &src->omegai, _state); ae_vector_init_copy(&dst->omegaip1, &src->omegaip1, _state); dst->alphai = src->alphai; dst->alphaip1 = src->alphaip1; dst->betai = src->betai; dst->betaip1 = src->betaip1; dst->phibari = src->phibari; dst->phibarip1 = src->phibarip1; dst->phii = src->phii; dst->rhobari = src->rhobari; dst->rhobarip1 = src->rhobarip1; dst->rhoi = src->rhoi; dst->ci = src->ci; dst->si = src->si; dst->theta = src->theta; dst->lambdai = src->lambdai; ae_vector_init_copy(&dst->d, &src->d, _state); dst->anorm = src->anorm; dst->bnorm2 = src->bnorm2; dst->dnorm = src->dnorm; dst->r2 = src->r2; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->mv, &src->mv, _state); ae_vector_init_copy(&dst->mtv, &src->mtv, _state); dst->epsa = src->epsa; dst->epsb = src->epsb; dst->epsc = src->epsc; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->xupdated = src->xupdated; dst->needmv = src->needmv; dst->needmtv = src->needmtv; dst->needmv2 = src->needmv2; dst->needvmv = src->needvmv; dst->needprec = src->needprec; dst->repiterationscount = src->repiterationscount; dst->repnmv = src->repnmv; dst->repterminationtype = src->repterminationtype; dst->running = src->running; ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state); ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _linlsqrstate_clear(void* _p) { linlsqrstate *p = (linlsqrstate*)_p; ae_touch_ptr((void*)p); _normestimatorstate_clear(&p->nes); ae_vector_clear(&p->rx); ae_vector_clear(&p->b); ae_vector_clear(&p->ui); ae_vector_clear(&p->uip1); ae_vector_clear(&p->vi); ae_vector_clear(&p->vip1); ae_vector_clear(&p->omegai); ae_vector_clear(&p->omegaip1); ae_vector_clear(&p->d); ae_vector_clear(&p->x); ae_vector_clear(&p->mv); ae_vector_clear(&p->mtv); ae_vector_clear(&p->tmpd); ae_vector_clear(&p->tmpx); _rcommstate_clear(&p->rstate); } void _linlsqrstate_destroy(void* _p) { linlsqrstate *p = (linlsqrstate*)_p; ae_touch_ptr((void*)p); _normestimatorstate_destroy(&p->nes); ae_vector_destroy(&p->rx); ae_vector_destroy(&p->b); ae_vector_destroy(&p->ui); ae_vector_destroy(&p->uip1); ae_vector_destroy(&p->vi); ae_vector_destroy(&p->vip1); ae_vector_destroy(&p->omegai); ae_vector_destroy(&p->omegaip1); ae_vector_destroy(&p->d); ae_vector_destroy(&p->x); ae_vector_destroy(&p->mv); ae_vector_destroy(&p->mtv); ae_vector_destroy(&p->tmpd); ae_vector_destroy(&p->tmpx); _rcommstate_destroy(&p->rstate); } void _linlsqrreport_init(void* _p, ae_state *_state) { linlsqrreport *p = (linlsqrreport*)_p; ae_touch_ptr((void*)p); } void _linlsqrreport_init_copy(void* _dst, void* _src, ae_state *_state) { linlsqrreport *dst = (linlsqrreport*)_dst; linlsqrreport *src = (linlsqrreport*)_src; dst->iterationscount = src->iterationscount; dst->nmv = src->nmv; dst->terminationtype = src->terminationtype; } void _linlsqrreport_clear(void* _p) { linlsqrreport *p = (linlsqrreport*)_p; ae_touch_ptr((void*)p); } void _linlsqrreport_destroy(void* _p) { linlsqrreport *p = (linlsqrreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* This function initializes linear CG Solver. This solver is used to solve symmetric positive definite problems. If you want to solve nonsymmetric (or non-positive definite) problem you may use LinLSQR solver provided by ALGLIB. USAGE: 1. User initializes algorithm state with LinCGCreate() call 2. User tunes solver parameters with LinCGSetCond() and other functions 3. Optionally, user sets starting point with LinCGSetStartingPoint() 4. User calls LinCGSolveSparse() function which takes algorithm state and SparseMatrix object. 5. User calls LinCGResults() to get solution 6. Optionally, user may call LinCGSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinCGState structure. INPUT PARAMETERS: N - problem dimension, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state) { ae_int_t i; _lincgstate_clear(state); ae_assert(n>0, "LinCGCreate: N<=0", _state); state->n = n; state->prectype = 0; state->itsbeforerestart = n; state->itsbeforerupdate = 10; state->epsf = lincg_defaultprecision; state->maxits = 0; state->xrep = ae_false; state->running = ae_false; /* * * allocate arrays * * set RX to NAN (just for the case user calls Results() without * calling SolveSparse() * * set starting point to zero * * we do NOT initialize B here because we assume that user should * initializate it using LinCGSetB() function. In case he forgets * to do so, exception will be thrown in the LinCGIteration(). */ ae_vector_set_length(&state->rx, state->n, _state); ae_vector_set_length(&state->startx, state->n, _state); ae_vector_set_length(&state->b, state->n, _state); for(i=0; i<=state->n-1; i++) { state->rx.ptr.p_double[i] = _state->v_nan; state->startx.ptr.p_double[i] = 0.0; state->b.ptr.p_double[i] = (double)(0); } ae_vector_set_length(&state->cx, state->n, _state); ae_vector_set_length(&state->p, state->n, _state); ae_vector_set_length(&state->r, state->n, _state); ae_vector_set_length(&state->cr, state->n, _state); ae_vector_set_length(&state->z, state->n, _state); ae_vector_set_length(&state->cz, state->n, _state); ae_vector_set_length(&state->x, state->n, _state); ae_vector_set_length(&state->mv, state->n, _state); ae_vector_set_length(&state->pv, state->n, _state); lincg_updateitersdata(state, _state); ae_vector_set_length(&state->rstate.ia, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; } /************************************************************************* This function sets starting point. By default, zero starting point is used. INPUT PARAMETERS: X - starting point, array[N] OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetstartingpoint(lincgstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_assert(!state->running, "LinCGSetStartingPoint: you can not change starting point because LinCGIteration() function is running", _state); ae_assert(state->n<=x->cnt, "LinCGSetStartingPoint: Length(X)n, _state), "LinCGSetStartingPoint: X contains infinite or NaN values!", _state); ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } /************************************************************************* This function sets right part. By default, right part is zero. INPUT PARAMETERS: B - right part, array[N]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetb(lincgstate* state, /* Real */ ae_vector* b, ae_state *_state) { ae_assert(!state->running, "LinCGSetB: you can not set B, because function LinCGIteration is running!", _state); ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecunit(lincgstate* state, ae_state *_state) { ae_assert(!state->running, "LinCGSetPrecUnit: you can not change preconditioner, because function LinCGIteration is running!", _state); state->prectype = -1; } /************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/ void lincgsetprecdiag(lincgstate* state, ae_state *_state) { ae_assert(!state->running, "LinCGSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); state->prectype = 0; } /************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsF - algorithm will be stopped if norm of residual is less than EpsF*||b||. MaxIts - algorithm will be stopped if number of iterations is more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: If both EpsF and MaxIts are zero then small EpsF will be set to small value. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetcond(lincgstate* state, double epsf, ae_int_t maxits, ae_state *_state) { ae_assert(!state->running, "LinCGSetCond: you can not change stopping criteria when LinCGIteration() is running", _state); ae_assert(ae_isfinite(epsf, _state)&&ae_fp_greater_eq(epsf,(double)(0)), "LinCGSetCond: EpsF is negative or contains infinite or NaN values", _state); ae_assert(maxits>=0, "LinCGSetCond: MaxIts is negative", _state); if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) { state->epsf = lincg_defaultprecision; state->maxits = maxits; } else { state->epsf = epsf; state->maxits = maxits; } } /************************************************************************* Reverse communication version of linear CG. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ ae_bool lincgiteration(lincgstate* state, ae_state *_state) { ae_int_t i; double uvar; double bnorm; double v; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { i = state->rstate.ia.ptr.p_int[0]; uvar = state->rstate.ra.ptr.p_double[0]; bnorm = state->rstate.ra.ptr.p_double[1]; v = state->rstate.ra.ptr.p_double[2]; } else { i = -983; uvar = -989; bnorm = -834; v = 900; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } /* * Routine body */ ae_assert(state->b.cnt>0, "LinCGIteration: B is not initialized (you must initialize B by LinCGSetB() call", _state); state->running = ae_true; state->repnmv = 0; lincg_clearrfields(state, _state); lincg_updateitersdata(state, _state); /* * Start 0-th iteration */ ae_v_move(&state->rx.ptr.p_double[0], 1, &state->startx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; lincg_clearrfields(state, _state); state->needvmv = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needvmv = ae_false; bnorm = (double)(0); state->r2 = (double)(0); state->meritfunction = (double)(0); for(i=0; i<=state->n-1; i++) { state->r.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; state->r2 = state->r2+state->r.ptr.p_double[i]*state->r.ptr.p_double[i]; state->meritfunction = state->meritfunction+state->mv.ptr.p_double[i]*state->rx.ptr.p_double[i]-2*state->b.ptr.p_double[i]*state->rx.ptr.p_double[i]; bnorm = bnorm+state->b.ptr.p_double[i]*state->b.ptr.p_double[i]; } bnorm = ae_sqrt(bnorm, _state); /* * Output first report */ if( !state->xrep ) { goto lbl_8; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); lincg_clearrfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->xupdated = ae_false; lbl_8: /* * Is x0 a solution? */ if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) { state->running = ae_false; if( ae_isfinite(state->r2, _state) ) { state->repterminationtype = 1; } else { state->repterminationtype = -4; } result = ae_false; return result; } /* * Calculate Z and P */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->r.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; lincg_clearrfields(state, _state); state->needprec = ae_true; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->needprec = ae_false; for(i=0; i<=state->n-1; i++) { state->z.ptr.p_double[i] = state->pv.ptr.p_double[i]; state->p.ptr.p_double[i] = state->z.ptr.p_double[i]; } /* * Other iterations(1..N) */ state->repiterationscount = 0; lbl_10: if( ae_false ) { goto lbl_11; } state->repiterationscount = state->repiterationscount+1; /* * Calculate Alpha */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->p.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; lincg_clearrfields(state, _state); state->needvmv = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needvmv = ae_false; if( !ae_isfinite(state->vmv, _state)||ae_fp_less_eq(state->vmv,(double)(0)) ) { /* * a) Overflow when calculating VMV * b) non-positive VMV (non-SPD matrix) */ state->running = ae_false; if( ae_isfinite(state->vmv, _state) ) { state->repterminationtype = -5; } else { state->repterminationtype = -4; } result = ae_false; return result; } state->alpha = (double)(0); for(i=0; i<=state->n-1; i++) { state->alpha = state->alpha+state->r.ptr.p_double[i]*state->z.ptr.p_double[i]; } state->alpha = state->alpha/state->vmv; if( !ae_isfinite(state->alpha, _state) ) { /* * Overflow when calculating Alpha */ state->running = ae_false; state->repterminationtype = -4; result = ae_false; return result; } /* * Next step toward solution */ for(i=0; i<=state->n-1; i++) { state->cx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->alpha*state->p.ptr.p_double[i]; } /* * Calculate R: * * use recurrent relation to update R * * at every ItsBeforeRUpdate-th iteration recalculate it from scratch, using matrix-vector product * in case R grows instead of decreasing, algorithm is terminated with positive completion code */ if( !(state->itsbeforerupdate==0||state->repiterationscount%state->itsbeforerupdate!=0) ) { goto lbl_12; } /* * Calculate R using recurrent formula */ for(i=0; i<=state->n-1; i++) { state->cr.ptr.p_double[i] = state->r.ptr.p_double[i]-state->alpha*state->mv.ptr.p_double[i]; state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; } goto lbl_13; lbl_12: /* * Calculate R using matrix-vector multiplication */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->repnmv = state->repnmv+1; lincg_clearrfields(state, _state); state->needmv = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->needmv = ae_false; for(i=0; i<=state->n-1; i++) { state->cr.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; } /* * Calculating merit function * Check emergency stopping criterion */ v = (double)(0); for(i=0; i<=state->n-1; i++) { v = v+state->mv.ptr.p_double[i]*state->cx.ptr.p_double[i]-2*state->b.ptr.p_double[i]*state->cx.ptr.p_double[i]; } if( ae_fp_less(v,state->meritfunction) ) { goto lbl_14; } for(i=0; i<=state->n-1; i++) { if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) { state->running = ae_false; state->repterminationtype = -4; result = ae_false; return result; } } /* *output last report */ if( !state->xrep ) { goto lbl_16; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); lincg_clearrfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->xupdated = ae_false; lbl_16: state->running = ae_false; state->repterminationtype = 7; result = ae_false; return result; lbl_14: state->meritfunction = v; lbl_13: ae_v_move(&state->rx.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); /* * calculating RNorm * * NOTE: monotonic decrease of R2 is not guaranteed by algorithm. */ state->r2 = (double)(0); for(i=0; i<=state->n-1; i++) { state->r2 = state->r2+state->cr.ptr.p_double[i]*state->cr.ptr.p_double[i]; } /* *output report */ if( !state->xrep ) { goto lbl_18; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); lincg_clearrfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->xupdated = ae_false; lbl_18: /* *stopping criterion *achieved the required precision */ if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) { state->running = ae_false; if( ae_isfinite(state->r2, _state) ) { state->repterminationtype = 1; } else { state->repterminationtype = -4; } result = ae_false; return result; } if( state->repiterationscount>=state->maxits&&state->maxits>0 ) { for(i=0; i<=state->n-1; i++) { if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) { state->running = ae_false; state->repterminationtype = -4; result = ae_false; return result; } } /* *if X is finite number */ state->running = ae_false; state->repterminationtype = 5; result = ae_false; return result; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->cr.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); /* *prepere of parameters for next iteration */ state->repnmv = state->repnmv+1; lincg_clearrfields(state, _state); state->needprec = ae_true; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->needprec = ae_false; ae_v_move(&state->cz.ptr.p_double[0], 1, &state->pv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); if( state->repiterationscount%state->itsbeforerestart!=0 ) { state->beta = (double)(0); uvar = (double)(0); for(i=0; i<=state->n-1; i++) { state->beta = state->beta+state->cz.ptr.p_double[i]*state->cr.ptr.p_double[i]; uvar = uvar+state->z.ptr.p_double[i]*state->r.ptr.p_double[i]; } /* *check that UVar is't INF or is't zero */ if( !ae_isfinite(uvar, _state)||ae_fp_eq(uvar,(double)(0)) ) { state->running = ae_false; state->repterminationtype = -4; result = ae_false; return result; } /* *calculate .BETA */ state->beta = state->beta/uvar; /* *check that .BETA neither INF nor NaN */ if( !ae_isfinite(state->beta, _state) ) { state->running = ae_false; state->repterminationtype = -1; result = ae_false; return result; } for(i=0; i<=state->n-1; i++) { state->p.ptr.p_double[i] = state->cz.ptr.p_double[i]+state->beta*state->p.ptr.p_double[i]; } } else { ae_v_move(&state->p.ptr.p_double[0], 1, &state->cz.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } /* *prepere data for next iteration */ for(i=0; i<=state->n-1; i++) { /* *write (k+1)th iteration to (k )th iteration */ state->r.ptr.p_double[i] = state->cr.ptr.p_double[i]; state->z.ptr.p_double[i] = state->cz.ptr.p_double[i]; } goto lbl_10; lbl_11: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = i; state->rstate.ra.ptr.p_double[0] = uvar; state->rstate.ra.ptr.p_double[1] = bnorm; state->rstate.ra.ptr.p_double[2] = v; return result; } /************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function). IsUpper - whether upper or lower triangle of A is used: * IsUpper=True => only upper triangle is used and lower triangle is not referenced at all * IsUpper=False => only lower triangle is used and upper triangle is not referenced at all B - right part, array[N] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinCGSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsolvesparse(lincgstate* state, sparsematrix* a, ae_bool isupper, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t n; ae_int_t i; double v; double vmv; n = state->n; ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); /* * Allocate temporaries */ rvectorsetlengthatleast(&state->tmpd, n, _state); /* * Compute diagonal scaling matrix D */ if( state->prectype==0 ) { /* * Default preconditioner - inverse of matrix diagonal */ for(i=0; i<=n-1; i++) { v = sparsegetdiagonal(a, i, _state); if( ae_fp_greater(v,(double)(0)) ) { state->tmpd.ptr.p_double[i] = 1/ae_sqrt(v, _state); } else { state->tmpd.ptr.p_double[i] = (double)(1); } } } else { /* * No diagonal scaling */ for(i=0; i<=n-1; i++) { state->tmpd.ptr.p_double[i] = (double)(1); } } /* * Solve */ lincgrestart(state, _state); lincgsetb(state, b, _state); while(lincgiteration(state, _state)) { /* * Process different requests from optimizer */ if( state->needmv ) { sparsesmv(a, isupper, &state->x, &state->mv, _state); } if( state->needvmv ) { sparsesmv(a, isupper, &state->x, &state->mv, _state); vmv = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->vmv = vmv; } if( state->needprec ) { for(i=0; i<=n-1; i++) { state->pv.ptr.p_double[i] = state->x.ptr.p_double[i]*ae_sqr(state->tmpd.ptr.p_double[i], _state); } } } } /************************************************************************* CG-solver: results. This function must be called after LinCGSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * -5 input matrix is either not positive definite, too large or too small * -4 overflow/underflow during solution (ill conditioned problem) * 1 ||residual||<=EpsF*||b|| * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, best point found is returned * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgresults(lincgstate* state, /* Real */ ae_vector* x, lincgreport* rep, ae_state *_state) { ae_vector_clear(x); _lincgreport_clear(rep); ae_assert(!state->running, "LinCGResult: you can not get result, because function LinCGIteration has been launched!", _state); if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nmv = state->repnmv; rep->terminationtype = state->repterminationtype; rep->r2 = state->r2; } /************************************************************************* This function sets restart frequency. By default, algorithm is restarted after N subsequent iterations. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrestartfreq(lincgstate* state, ae_int_t srf, ae_state *_state) { ae_assert(!state->running, "LinCGSetRestartFreq: you can not change restart frequency when LinCGIteration() is running", _state); ae_assert(srf>0, "LinCGSetRestartFreq: non-positive SRF", _state); state->itsbeforerestart = srf; } /************************************************************************* This function sets frequency of residual recalculations. Algorithm updates residual r_k using iterative formula, but recalculates it from scratch after each 10 iterations. It is done to avoid accumulation of numerical errors and to stop algorithm when r_k starts to grow. Such low update frequence (1/10) gives very little overhead, but makes algorithm a bit more robust against numerical errors. However, you may change it INPUT PARAMETERS: Freq - desired update frequency, Freq>=0. Zero value means that no updates will be done. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetrupdatefreq(lincgstate* state, ae_int_t freq, ae_state *_state) { ae_assert(!state->running, "LinCGSetRUpdateFreq: you can not change update frequency when LinCGIteration() is running", _state); ae_assert(freq>=0, "LinCGSetRUpdateFreq: non-positive Freq", _state); state->itsbeforerupdate = freq; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* Procedure for restart function LinCGIteration -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ void lincgrestart(lincgstate* state, ae_state *_state) { ae_vector_set_length(&state->rstate.ia, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; lincg_clearrfields(state, _state); } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void lincg_clearrfields(lincgstate* state, ae_state *_state) { state->xupdated = ae_false; state->needmv = ae_false; state->needmtv = ae_false; state->needmv2 = ae_false; state->needvmv = ae_false; state->needprec = ae_false; } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void lincg_updateitersdata(lincgstate* state, ae_state *_state) { state->repiterationscount = 0; state->repnmv = 0; state->repterminationtype = 0; } void _lincgstate_init(void* _p, ae_state *_state) { lincgstate *p = (lincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->rx, 0, DT_REAL, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->cx, 0, DT_REAL, _state); ae_vector_init(&p->cr, 0, DT_REAL, _state); ae_vector_init(&p->cz, 0, DT_REAL, _state); ae_vector_init(&p->p, 0, DT_REAL, _state); ae_vector_init(&p->r, 0, DT_REAL, _state); ae_vector_init(&p->z, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->mv, 0, DT_REAL, _state); ae_vector_init(&p->pv, 0, DT_REAL, _state); ae_vector_init(&p->startx, 0, DT_REAL, _state); ae_vector_init(&p->tmpd, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); } void _lincgstate_init_copy(void* _dst, void* _src, ae_state *_state) { lincgstate *dst = (lincgstate*)_dst; lincgstate *src = (lincgstate*)_src; ae_vector_init_copy(&dst->rx, &src->rx, _state); ae_vector_init_copy(&dst->b, &src->b, _state); dst->n = src->n; dst->prectype = src->prectype; ae_vector_init_copy(&dst->cx, &src->cx, _state); ae_vector_init_copy(&dst->cr, &src->cr, _state); ae_vector_init_copy(&dst->cz, &src->cz, _state); ae_vector_init_copy(&dst->p, &src->p, _state); ae_vector_init_copy(&dst->r, &src->r, _state); ae_vector_init_copy(&dst->z, &src->z, _state); dst->alpha = src->alpha; dst->beta = src->beta; dst->r2 = src->r2; dst->meritfunction = src->meritfunction; ae_vector_init_copy(&dst->x, &src->x, _state); ae_vector_init_copy(&dst->mv, &src->mv, _state); ae_vector_init_copy(&dst->pv, &src->pv, _state); dst->vmv = src->vmv; ae_vector_init_copy(&dst->startx, &src->startx, _state); dst->epsf = src->epsf; dst->maxits = src->maxits; dst->itsbeforerestart = src->itsbeforerestart; dst->itsbeforerupdate = src->itsbeforerupdate; dst->xrep = src->xrep; dst->xupdated = src->xupdated; dst->needmv = src->needmv; dst->needmtv = src->needmtv; dst->needmv2 = src->needmv2; dst->needvmv = src->needvmv; dst->needprec = src->needprec; dst->repiterationscount = src->repiterationscount; dst->repnmv = src->repnmv; dst->repterminationtype = src->repterminationtype; dst->running = src->running; ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state); _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); } void _lincgstate_clear(void* _p) { lincgstate *p = (lincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->rx); ae_vector_clear(&p->b); ae_vector_clear(&p->cx); ae_vector_clear(&p->cr); ae_vector_clear(&p->cz); ae_vector_clear(&p->p); ae_vector_clear(&p->r); ae_vector_clear(&p->z); ae_vector_clear(&p->x); ae_vector_clear(&p->mv); ae_vector_clear(&p->pv); ae_vector_clear(&p->startx); ae_vector_clear(&p->tmpd); _rcommstate_clear(&p->rstate); } void _lincgstate_destroy(void* _p) { lincgstate *p = (lincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->rx); ae_vector_destroy(&p->b); ae_vector_destroy(&p->cx); ae_vector_destroy(&p->cr); ae_vector_destroy(&p->cz); ae_vector_destroy(&p->p); ae_vector_destroy(&p->r); ae_vector_destroy(&p->z); ae_vector_destroy(&p->x); ae_vector_destroy(&p->mv); ae_vector_destroy(&p->pv); ae_vector_destroy(&p->startx); ae_vector_destroy(&p->tmpd); _rcommstate_destroy(&p->rstate); } void _lincgreport_init(void* _p, ae_state *_state) { lincgreport *p = (lincgreport*)_p; ae_touch_ptr((void*)p); } void _lincgreport_init_copy(void* _dst, void* _src, ae_state *_state) { lincgreport *dst = (lincgreport*)_dst; lincgreport *src = (lincgreport*)_src; dst->iterationscount = src->iterationscount; dst->nmv = src->nmv; dst->terminationtype = src->terminationtype; dst->r2 = src->r2; } void _lincgreport_clear(void* _p) { lincgreport *p = (lincgreport*)_p; ae_touch_ptr((void*)p); } void _lincgreport_destroy(void* _p) { lincgreport *p = (lincgreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER DESCRIPTION: This algorithm solves system of nonlinear equations F[0](x[0], ..., x[n-1]) = 0 F[1](x[0], ..., x[n-1]) = 0 ... F[M-1](x[0], ..., x[n-1]) = 0 with M/N do not necessarily coincide. Algorithm converges quadratically under following conditions: * the solution set XS is nonempty * for some xs in XS there exist such neighbourhood N(xs) that: * vector function F(x) and its Jacobian J(x) are continuously differentiable on N * ||F(x)|| provides local error bound on N, i.e. there exists such c1, that ||F(x)||>c1*distance(x,XS) Note that these conditions are much more weaker than usual non-singularity conditions. For example, algorithm will converge for any affine function F (whether its Jacobian singular or not). REQUIREMENTS: Algorithm will request following information during its operation: * function vector F[] and Jacobian matrix at given point X * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X USAGE: 1. User initializes algorithm state with NLEQCreateLM() call 2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and other functions 3. User calls NLEQSolve() function which takes algorithm state and pointers (delegates, etc.) to callback functions which calculate merit function value and Jacobian. 4. User calls NLEQResults() to get solution 5. Optionally, user may call NLEQRestartFrom() to solve another problem with same parameters (N/M) but another starting point and/or another function vector. NLEQRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - space dimension, N>1: * if provided, only leading N elements of X are used * if not provided, determined automatically from size of X M - system size X - starting point OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with NLEQSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use NLEQSetStpMax() function to bound algorithm's steps. 3. this algorithm is a slightly modified implementation of the method described in 'Levenberg-Marquardt method for constrained nonlinear equations with strong local convergence properties' by Christian Kanzow Nobuo Yamashita and Masao Fukushima and further developed in 'On the convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang Yuan. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqcreatelm(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, nleqstate* state, ae_state *_state) { _nleqstate_clear(state); ae_assert(n>=1, "NLEQCreateLM: N<1!", _state); ae_assert(m>=1, "NLEQCreateLM: M<1!", _state); ae_assert(x->cnt>=n, "NLEQCreateLM: Length(X)n = n; state->m = m; nleqsetcond(state, (double)(0), 0, _state); nleqsetxrep(state, ae_false, _state); nleqsetstpmax(state, (double)(0), _state); ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->xbase, n, _state); ae_matrix_set_length(&state->j, m, n, _state); ae_vector_set_length(&state->fi, m, _state); ae_vector_set_length(&state->rightpart, n, _state); ae_vector_set_length(&state->candstep, n, _state); nleqrestartfrom(state, x, _state); } /************************************************************************* This function sets stopping conditions for the nonlinear solver INPUT PARAMETERS: State - structure which stores algorithm state EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition ||F||<=EpsF is satisfied MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic stopping criterion selection (small EpsF). NOTES: -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetcond(nleqstate* state, double epsf, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsf, _state), "NLEQSetCond: EpsF is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "NLEQSetCond: negative EpsF!", _state); ae_assert(maxits>=0, "NLEQSetCond: negative MaxIts!", _state); if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) { epsf = 1.0E-6; } state->epsf = epsf; state->maxits = maxits; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to NLEQSolve(). -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when target function contains exp() or other fast growing functions, and algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "NLEQSetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "NLEQSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ ae_bool nleqiteration(nleqstate* state, ae_state *_state) { ae_int_t n; ae_int_t m; ae_int_t i; double lambdaup; double lambdadown; double lambdav; double rho; double mu; double stepnorm; ae_bool b; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; i = state->rstate.ia.ptr.p_int[2]; b = state->rstate.ba.ptr.p_bool[0]; lambdaup = state->rstate.ra.ptr.p_double[0]; lambdadown = state->rstate.ra.ptr.p_double[1]; lambdav = state->rstate.ra.ptr.p_double[2]; rho = state->rstate.ra.ptr.p_double[3]; mu = state->rstate.ra.ptr.p_double[4]; stepnorm = state->rstate.ra.ptr.p_double[5]; } else { n = -983; m = -989; i = -834; b = ae_false; lambdaup = -287; lambdadown = 364; lambdav = 214; rho = -338; mu = -686; stepnorm = 912; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } /* * Routine body */ /* * Prepare */ n = state->n; m = state->m; state->repterminationtype = 0; state->repiterationscount = 0; state->repnfunc = 0; state->repnjac = 0; /* * Calculate F/G, initialize algorithm */ nleq_clearrequestfields(state, _state); state->needf = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needf = ae_false; state->repnfunc = state->repnfunc+1; ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->fbase = state->f; state->fprev = ae_maxrealnumber; if( !state->xrep ) { goto lbl_5; } /* * progress report */ nleq_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->xupdated = ae_false; lbl_5: if( ae_fp_less_eq(state->f,ae_sqr(state->epsf, _state)) ) { state->repterminationtype = 1; result = ae_false; return result; } /* * Main cycle */ lambdaup = (double)(10); lambdadown = 0.3; lambdav = 0.001; rho = (double)(1); lbl_7: if( ae_false ) { goto lbl_8; } /* * Get Jacobian; * before we get to this point we already have State.XBase filled * with current point and State.FBase filled with function value * at XBase */ nleq_clearrequestfields(state, _state); state->needfij = ae_true; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->needfij = ae_false; state->repnfunc = state->repnfunc+1; state->repnjac = state->repnjac+1; rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->rightpart, 0, _state); ae_v_muld(&state->rightpart.ptr.p_double[0], 1, ae_v_len(0,n-1), -1); /* * Inner cycle: find good lambda */ lbl_9: if( ae_false ) { goto lbl_10; } /* * Solve (J^T*J + (Lambda+Mu)*I)*y = J^T*F * to get step d=-y where: * * Mu=||F|| - is damping parameter for nonlinear system * * Lambda - is additional Levenberg-Marquardt parameter * for better convergence when far away from minimum */ for(i=0; i<=n-1; i++) { state->candstep.ptr.p_double[i] = (double)(0); } fblssolvecgx(&state->j, m, n, lambdav, &state->rightpart, &state->candstep, &state->cgbuf, _state); /* * Normalize step (it must be no more than StpMax) */ stepnorm = (double)(0); for(i=0; i<=n-1; i++) { if( ae_fp_neq(state->candstep.ptr.p_double[i],(double)(0)) ) { stepnorm = (double)(1); break; } } linminnormalized(&state->candstep, &stepnorm, n, _state); if( ae_fp_neq(state->stpmax,(double)(0)) ) { stepnorm = ae_minreal(stepnorm, state->stpmax, _state); } /* * Test new step - is it good enough? * * if not, Lambda is increased and we try again. * * if step is good, we decrease Lambda and move on. * * We can break this cycle on two occasions: * * step is so small that x+step==x (in floating point arithmetics) * * lambda is so large */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); b = ae_true; for(i=0; i<=n-1; i++) { if( ae_fp_neq(state->x.ptr.p_double[i],state->xbase.ptr.p_double[i]) ) { b = ae_false; break; } } if( b ) { /* * Step is too small, force zero step and break */ stepnorm = (double)(0); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; goto lbl_10; } nleq_clearrequestfields(state, _state); state->needf = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needf = ae_false; state->repnfunc = state->repnfunc+1; if( ae_fp_less(state->f,state->fbase) ) { /* * function value decreased, move on */ nleq_decreaselambda(&lambdav, &rho, lambdadown, _state); goto lbl_10; } if( !nleq_increaselambda(&lambdav, &rho, lambdaup, _state) ) { /* * Lambda is too large (near overflow), force zero step and break */ stepnorm = (double)(0); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; goto lbl_10; } goto lbl_9; lbl_10: /* * Accept step: * * new position * * new function value */ state->fbase = state->f; ae_v_addd(&state->xbase.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); state->repiterationscount = state->repiterationscount+1; /* * Report new iteration */ if( !state->xrep ) { goto lbl_11; } nleq_clearrequestfields(state, _state); state->xupdated = ae_true; state->f = state->fbase; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->xupdated = ae_false; lbl_11: /* * Test stopping conditions on F, step (zero/non-zero) and MaxIts; * If one of the conditions is met, RepTerminationType is changed. */ if( ae_fp_less_eq(ae_sqrt(state->f, _state),state->epsf) ) { state->repterminationtype = 1; } if( ae_fp_eq(stepnorm,(double)(0))&&state->repterminationtype==0 ) { state->repterminationtype = -4; } if( state->repiterationscount>=state->maxits&&state->maxits>0 ) { state->repterminationtype = 5; } if( state->repterminationtype!=0 ) { goto lbl_8; } /* * Now, iteration is finally over */ goto lbl_7; lbl_8: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = i; state->rstate.ba.ptr.p_bool[0] = b; state->rstate.ra.ptr.p_double[0] = lambdaup; state->rstate.ra.ptr.p_double[1] = lambdadown; state->rstate.ra.ptr.p_double[2] = lambdav; state->rstate.ra.ptr.p_double[3] = rho; state->rstate.ra.ptr.p_double[4] = mu; state->rstate.ra.ptr.p_double[5] = stepnorm; return result; } /************************************************************************* NLEQ solver results INPUT PARAMETERS: State - algorithm state. OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -4 ERROR: algorithm has converged to the stationary point Xf which is local minimum of f=F[0]^2+...+F[m-1]^2, but is not solution of nonlinear system. * 1 sqrt(f)<=EpsF. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations * ActiveConstraints contains number of active constraints -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresults(nleqstate* state, /* Real */ ae_vector* x, nleqreport* rep, ae_state *_state) { ae_vector_clear(x); _nleqreport_clear(rep); nleqresultsbuf(state, x, rep, _state); } /************************************************************************* NLEQ solver results Buffered implementation of NLEQResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/ void nleqresultsbuf(nleqstate* state, /* Real */ ae_vector* x, nleqreport* rep, ae_state *_state) { if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nfunc = state->repnfunc; rep->njac = state->repnjac; rep->terminationtype = state->repterminationtype; } /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinCGCreate call. X - new starting point. BndL - new lower bounds BndU - new upper bounds -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void nleqrestartfrom(nleqstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_assert(x->cnt>=state->n, "NLEQRestartFrom: Length(X)n, _state), "NLEQRestartFrom: X contains infinite or NaN values!", _state); ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_vector_set_length(&state->rstate.ia, 2+1, _state); ae_vector_set_length(&state->rstate.ba, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 5+1, _state); state->rstate.stage = -1; nleq_clearrequestfields(state, _state); } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void nleq_clearrequestfields(nleqstate* state, ae_state *_state) { state->needf = ae_false; state->needfij = ae_false; state->xupdated = ae_false; } /************************************************************************* Increases lambda, returns False when there is a danger of overflow *************************************************************************/ static ae_bool nleq_increaselambda(double* lambdav, double* nu, double lambdaup, ae_state *_state) { double lnlambda; double lnnu; double lnlambdaup; double lnmax; ae_bool result; result = ae_false; lnlambda = ae_log(*lambdav, _state); lnlambdaup = ae_log(lambdaup, _state); lnnu = ae_log(*nu, _state); lnmax = 0.5*ae_log(ae_maxrealnumber, _state); if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,lnmax) ) { return result; } if( ae_fp_greater(lnnu+ae_log((double)(2), _state),lnmax) ) { return result; } *lambdav = *lambdav*lambdaup*(*nu); *nu = *nu*2; result = ae_true; return result; } /************************************************************************* Decreases lambda, but leaves it unchanged when there is danger of underflow. *************************************************************************/ static void nleq_decreaselambda(double* lambdav, double* nu, double lambdadown, ae_state *_state) { *nu = (double)(1); if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) { *lambdav = ae_minrealnumber; } else { *lambdav = *lambdav*lambdadown; } } void _nleqstate_init(void* _p, ae_state *_state) { nleqstate *p = (nleqstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->fi, 0, DT_REAL, _state); ae_matrix_init(&p->j, 0, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); ae_vector_init(&p->xbase, 0, DT_REAL, _state); ae_vector_init(&p->candstep, 0, DT_REAL, _state); ae_vector_init(&p->rightpart, 0, DT_REAL, _state); ae_vector_init(&p->cgbuf, 0, DT_REAL, _state); } void _nleqstate_init_copy(void* _dst, void* _src, ae_state *_state) { nleqstate *dst = (nleqstate*)_dst; nleqstate *src = (nleqstate*)_src; dst->n = src->n; dst->m = src->m; dst->epsf = src->epsf; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->stpmax = src->stpmax; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->fi, &src->fi, _state); ae_matrix_init_copy(&dst->j, &src->j, _state); dst->needf = src->needf; dst->needfij = src->needfij; dst->xupdated = src->xupdated; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->repiterationscount = src->repiterationscount; dst->repnfunc = src->repnfunc; dst->repnjac = src->repnjac; dst->repterminationtype = src->repterminationtype; ae_vector_init_copy(&dst->xbase, &src->xbase, _state); dst->fbase = src->fbase; dst->fprev = src->fprev; ae_vector_init_copy(&dst->candstep, &src->candstep, _state); ae_vector_init_copy(&dst->rightpart, &src->rightpart, _state); ae_vector_init_copy(&dst->cgbuf, &src->cgbuf, _state); } void _nleqstate_clear(void* _p) { nleqstate *p = (nleqstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->fi); ae_matrix_clear(&p->j); _rcommstate_clear(&p->rstate); ae_vector_clear(&p->xbase); ae_vector_clear(&p->candstep); ae_vector_clear(&p->rightpart); ae_vector_clear(&p->cgbuf); } void _nleqstate_destroy(void* _p) { nleqstate *p = (nleqstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->fi); ae_matrix_destroy(&p->j); _rcommstate_destroy(&p->rstate); ae_vector_destroy(&p->xbase); ae_vector_destroy(&p->candstep); ae_vector_destroy(&p->rightpart); ae_vector_destroy(&p->cgbuf); } void _nleqreport_init(void* _p, ae_state *_state) { nleqreport *p = (nleqreport*)_p; ae_touch_ptr((void*)p); } void _nleqreport_init_copy(void* _dst, void* _src, ae_state *_state) { nleqreport *dst = (nleqreport*)_dst; nleqreport *src = (nleqreport*)_src; dst->iterationscount = src->iterationscount; dst->nfunc = src->nfunc; dst->njac = src->njac; dst->terminationtype = src->terminationtype; } void _nleqreport_clear(void* _p) { nleqreport *p = (nleqreport*)_p; ae_touch_ptr((void*)p); } void _nleqreport_destroy(void* _p) { nleqreport *p = (nleqreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* Polynomial root finding. This function returns all roots of the polynomial P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n Both real and complex roots are returned (see below). INPUT PARAMETERS: A - array[N+1], polynomial coefficients: * A[0] is constant term * A[N] is a coefficient of X^N N - polynomial degree OUTPUT PARAMETERS: X - array of complex roots: * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 * complex roots are always returned in pairs - roots occupy positions I and I+1, with: * X[I+1]=Conj(X[I]) * IMAGE(X[I]) > 0 * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 * multiple real roots may have non-zero imaginary part due to roundoff errors. There is no reliable way to distinguish real root of multiplicity 2 from two complex roots in the presence of roundoff errors. Rep - report, additional information, following fields are set: * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field allows to quickly estimate "quality" of the roots being returned. NOTE: this function uses companion matrix method to find roots. In case internal EVD solver fails do find eigenvalues, exception is generated. NOTE: roots are not "polished" and no matrix balancing is performed for them. -- ALGLIB -- Copyright 24.02.2014 by Bochkanov Sergey *************************************************************************/ void polynomialsolve(/* Real */ ae_vector* a, ae_int_t n, /* Complex */ ae_vector* x, polynomialsolverreport* rep, ae_state *_state) { ae_frame _frame_block; ae_vector _a; ae_matrix c; ae_matrix vl; ae_matrix vr; ae_vector wr; ae_vector wi; ae_int_t i; ae_int_t j; ae_bool status; ae_int_t nz; ae_int_t ne; ae_complex v; ae_complex vv; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_a, a, _state); a = &_a; ae_vector_clear(x); _polynomialsolverreport_clear(rep); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&vl, 0, 0, DT_REAL, _state); ae_matrix_init(&vr, 0, 0, DT_REAL, _state); ae_vector_init(&wr, 0, DT_REAL, _state); ae_vector_init(&wi, 0, DT_REAL, _state); ae_assert(n>0, "PolynomialSolve: N<=0", _state); ae_assert(a->cnt>=n+1, "PolynomialSolve: Length(A)ptr.p_double[n],(double)(0)), "PolynomialSolve: A[N]=0", _state); /* * Prepare */ ae_vector_set_length(x, n, _state); /* * Normalize A: * * analytically determine NZ zero roots * * quick exit for NZ=N * * make residual NE-th degree polynomial monic * (here NE=N-NZ) */ nz = 0; while(nzptr.p_double[nz],(double)(0))) { nz = nz+1; } ne = n-nz; for(i=nz; i<=n; i++) { a->ptr.p_double[i-nz] = a->ptr.p_double[i]/a->ptr.p_double[n]; } /* * For NZ0 ) { ae_matrix_set_length(&c, ne, ne, _state); for(i=0; i<=ne-1; i++) { for(j=0; j<=ne-1; j++) { c.ptr.pp_double[i][j] = (double)(0); } } c.ptr.pp_double[0][ne-1] = -a->ptr.p_double[0]; for(i=1; i<=ne-1; i++) { c.ptr.pp_double[i][i-1] = (double)(1); c.ptr.pp_double[i][ne-1] = -a->ptr.p_double[i]; } status = rmatrixevd(&c, ne, 0, &wr, &wi, &vl, &vr, _state); ae_assert(status, "PolynomialSolve: inernal error - EVD solver failed", _state); for(i=0; i<=ne-1; i++) { x->ptr.p_complex[i].x = wr.ptr.p_double[i]; x->ptr.p_complex[i].y = wi.ptr.p_double[i]; } } /* * Remaining NZ zero roots */ for(i=ne; i<=n-1; i++) { x->ptr.p_complex[i] = ae_complex_from_i(0); } /* * Rep */ rep->maxerr = (double)(0); for(i=0; i<=ne-1; i++) { v = ae_complex_from_i(0); vv = ae_complex_from_i(1); for(j=0; j<=ne; j++) { v = ae_c_add(v,ae_c_mul_d(vv,a->ptr.p_double[j])); vv = ae_c_mul(vv,x->ptr.p_complex[i]); } rep->maxerr = ae_maxreal(rep->maxerr, ae_c_abs(v, _state), _state); } ae_frame_leave(_state); } void _polynomialsolverreport_init(void* _p, ae_state *_state) { polynomialsolverreport *p = (polynomialsolverreport*)_p; ae_touch_ptr((void*)p); } void _polynomialsolverreport_init_copy(void* _dst, void* _src, ae_state *_state) { polynomialsolverreport *dst = (polynomialsolverreport*)_dst; polynomialsolverreport *src = (polynomialsolverreport*)_src; dst->maxerr = src->maxerr; } void _polynomialsolverreport_clear(void* _p) { polynomialsolverreport *p = (polynomialsolverreport*)_p; ae_touch_ptr((void*)p); } void _polynomialsolverreport_destroy(void* _p) { polynomialsolverreport *p = (polynomialsolverreport*)_p; ae_touch_ptr((void*)p); } } qmapshack-1.10.0/3rdparty/alglib/src/optimization.h000755 001750 000144 00001036654 13015033052 023424 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #ifndef _optimization_pkg_h #define _optimization_pkg_h #include "ap.h" #include "alglibinternal.h" #include "alglibmisc.h" #include "linalg.h" #include "solvers.h" ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { typedef struct { ae_vector norms; ae_vector alpha; ae_vector rho; ae_matrix yk; ae_vector idx; ae_vector bufa; ae_vector bufb; } precbuflbfgs; typedef struct { ae_int_t n; ae_int_t k; ae_vector d; ae_matrix v; ae_vector bufc; ae_matrix bufz; ae_matrix bufw; ae_vector tmp; } precbuflowrank; typedef struct { ae_int_t n; ae_int_t k; double alpha; double tau; double theta; ae_matrix a; ae_matrix q; ae_vector b; ae_vector r; ae_vector xc; ae_vector d; ae_vector activeset; ae_matrix tq2dense; ae_matrix tk2; ae_vector tq2diag; ae_vector tq1; ae_vector tk1; double tq0; double tk0; ae_vector txc; ae_vector tb; ae_int_t nfree; ae_int_t ecakind; ae_matrix ecadense; ae_matrix eq; ae_matrix eccm; ae_vector ecadiag; ae_vector eb; double ec; ae_vector tmp0; ae_vector tmp1; ae_vector tmpg; ae_matrix tmp2; ae_bool ismaintermchanged; ae_bool issecondarytermchanged; ae_bool islineartermchanged; ae_bool isactivesetchanged; } convexquadraticmodel; typedef struct { ae_int_t ns; ae_int_t nd; ae_int_t nr; ae_matrix densea; ae_vector b; ae_vector nnc; double debugflops; ae_int_t debugmaxinnerits; ae_vector xn; ae_vector xp; ae_matrix tmpz; ae_matrix tmpca; ae_matrix tmplq; ae_matrix trda; ae_vector trdd; ae_vector crb; ae_vector g; ae_vector d; ae_vector dx; ae_vector diagaa; ae_vector cb; ae_vector cx; ae_vector cborg; ae_vector tmpcholesky; ae_vector r; ae_vector regdiag; ae_vector tmp0; ae_vector tmp1; ae_vector tmp2; ae_vector rdtmprowmap; } snnlssolver; typedef struct { ae_int_t n; ae_int_t algostate; ae_vector xc; ae_bool hasxc; ae_vector s; ae_vector h; ae_vector activeset; ae_bool basisisready; ae_matrix sbasis; ae_matrix pbasis; ae_matrix ibasis; ae_int_t basissize; ae_bool constraintschanged; ae_vector hasbndl; ae_vector hasbndu; ae_vector bndl; ae_vector bndu; ae_matrix cleic; ae_int_t nec; ae_int_t nic; ae_vector mtx; ae_vector mtas; ae_vector cdtmp; ae_vector corrtmp; ae_vector unitdiagonal; snnlssolver solver; ae_vector scntmp; ae_vector tmp0; ae_vector tmpfeas; ae_matrix tmpm0; ae_vector rctmps; ae_vector rctmpg; ae_vector rctmprightpart; ae_matrix rctmpdense0; ae_matrix rctmpdense1; ae_vector rctmpisequality; ae_vector rctmpconstraintidx; ae_vector rctmplambdas; ae_matrix tmpbasis; } sactiveset; typedef struct { ae_int_t n; double epsg; double epsf; double epsx; ae_int_t maxits; double stpmax; double suggestedstep; ae_bool xrep; ae_bool drep; ae_int_t cgtype; ae_int_t prectype; ae_vector diagh; ae_vector diaghl2; ae_matrix vcorr; ae_int_t vcnt; ae_vector s; double diffstep; ae_int_t nfev; ae_int_t mcstage; ae_int_t k; ae_vector xk; ae_vector dk; ae_vector xn; ae_vector dn; ae_vector d; double fold; double stp; double curstpmax; ae_vector yk; double lastgoodstep; double lastscaledstep; ae_int_t mcinfo; ae_bool innerresetneeded; ae_bool terminationneeded; double trimthreshold; ae_int_t rstimer; ae_vector x; double f; ae_vector g; ae_bool needf; ae_bool needfg; ae_bool xupdated; ae_bool algpowerup; ae_bool lsstart; ae_bool lsend; ae_bool userterminationneeded; double teststep; rcommstate rstate; ae_int_t repiterationscount; ae_int_t repnfev; ae_int_t repvaridx; ae_int_t repterminationtype; ae_int_t debugrestartscount; linminstate lstate; double fbase; double fm2; double fm1; double fp1; double fp2; double betahs; double betady; ae_vector work0; ae_vector work1; } mincgstate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; } mincgreport; typedef struct { ae_int_t nmain; ae_int_t nslack; double epsg; double epsf; double epsx; ae_int_t maxits; ae_bool xrep; ae_bool drep; double stpmax; double diffstep; sactiveset sas; ae_vector s; ae_int_t prectype; ae_vector diagh; ae_vector x; double f; ae_vector g; ae_bool needf; ae_bool needfg; ae_bool xupdated; ae_bool lsstart; ae_bool steepestdescentstep; ae_bool boundedstep; ae_bool userterminationneeded; double teststep; rcommstate rstate; ae_vector ugc; ae_vector cgc; ae_vector xn; ae_vector ugn; ae_vector cgn; ae_vector xp; double fc; double fn; double fp; ae_vector d; ae_matrix cleic; ae_int_t nec; ae_int_t nic; double lastgoodstep; double lastscaledgoodstep; double maxscaledgrad; ae_vector hasbndl; ae_vector hasbndu; ae_vector bndl; ae_vector bndu; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repnfev; ae_int_t repvaridx; ae_int_t repterminationtype; double repdebugeqerr; double repdebugfs; double repdebugff; double repdebugdx; ae_int_t repdebugfeasqpits; ae_int_t repdebugfeasgpaits; ae_vector xstart; snnlssolver solver; double fbase; double fm2; double fm1; double fp1; double fp2; double xm1; double xp1; double gm1; double gp1; ae_int_t cidx; double cval; ae_vector tmpprec; ae_vector tmp0; ae_int_t nfev; ae_int_t mcstage; double stp; double curstpmax; double activationstep; ae_vector work; linminstate lstate; double trimthreshold; ae_int_t nonmonotoniccnt; ae_matrix bufyk; ae_matrix bufsk; ae_vector bufrho; ae_vector buftheta; ae_int_t bufsize; } minbleicstate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; double debugeqerr; double debugfs; double debugff; double debugdx; ae_int_t debugfeasqpits; ae_int_t debugfeasgpaits; ae_int_t inneriterationscount; ae_int_t outeriterationscount; } minbleicreport; typedef struct { ae_int_t n; ae_int_t m; double epsg; double epsf; double epsx; ae_int_t maxits; ae_bool xrep; double stpmax; ae_vector s; double diffstep; ae_int_t nfev; ae_int_t mcstage; ae_int_t k; ae_int_t q; ae_int_t p; ae_vector rho; ae_matrix yk; ae_matrix sk; ae_vector xp; ae_vector theta; ae_vector d; double stp; ae_vector work; double fold; double trimthreshold; ae_int_t prectype; double gammak; ae_matrix denseh; ae_vector diagh; ae_vector precc; ae_vector precd; ae_matrix precw; ae_int_t preck; precbuflbfgs precbuf; precbuflowrank lowrankbuf; double fbase; double fm2; double fm1; double fp1; double fp2; ae_vector autobuf; ae_vector x; double f; ae_vector g; ae_bool needf; ae_bool needfg; ae_bool xupdated; ae_bool userterminationneeded; double teststep; rcommstate rstate; ae_int_t repiterationscount; ae_int_t repnfev; ae_int_t repvaridx; ae_int_t repterminationtype; linminstate lstate; } minlbfgsstate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; } minlbfgsreport; typedef struct { double epsg; double epsf; double epsx; ae_int_t maxouterits; ae_bool cgphase; ae_bool cnphase; ae_int_t cgminits; ae_int_t cgmaxits; ae_int_t cnmaxupdates; ae_int_t sparsesolver; } qqpsettings; typedef struct { ae_int_t n; ae_int_t nmain; ae_int_t nslack; ae_int_t nec; ae_int_t nic; ae_int_t akind; ae_matrix densea; sparsematrix sparsea; ae_bool sparseupper; double absamax; double absasum; double absasum2; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector havebndl; ae_vector havebndu; ae_matrix cleic; ae_vector xs; ae_vector gc; ae_vector xp; ae_vector dc; ae_vector dp; ae_vector cgc; ae_vector cgp; sactiveset sas; ae_vector activated; ae_int_t nfree; ae_int_t cnmodelage; ae_matrix densez; sparsematrix sparsecca; ae_vector yidx; ae_vector regdiag; ae_vector regx0; ae_vector tmpcn; ae_vector tmpcni; ae_vector tmpcnb; ae_vector tmp0; ae_vector stpbuf; sparsebuffers sbuf; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repncholesky; ae_int_t repncupdates; } qqpbuffers; typedef struct { double epsg; double epsf; double epsx; ae_int_t maxits; } qpbleicsettings; typedef struct { minbleicstate solver; minbleicreport solverrep; ae_vector tmp0; ae_vector tmp1; ae_vector tmpi; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; } qpbleicbuffers; typedef struct { double epsg; double epsf; double epsx; ae_int_t maxits; } qpcholeskysettings; typedef struct { sactiveset sas; ae_vector pg; ae_vector gc; ae_vector xs; ae_vector xn; ae_vector workbndl; ae_vector workbndu; ae_vector havebndl; ae_vector havebndu; ae_matrix workcleic; ae_vector rctmpg; ae_vector tmp0; ae_vector tmp1; ae_vector tmpb; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repncholesky; } qpcholeskybuffers; typedef struct { ae_int_t n; qqpsettings qqpsettingsuser; qqpsettings qqpsettingscurrent; qpbleicsettings qpbleicsettingsuser; qpbleicsettings qpbleicsettingscurrent; ae_int_t algokind; ae_int_t akind; convexquadraticmodel a; sparsematrix sparsea; ae_bool sparseaupper; double absamax; double absasum; double absasum2; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector s; ae_vector havebndl; ae_vector havebndu; ae_vector xorigin; ae_vector startx; ae_bool havex; ae_matrix cleic; ae_int_t nec; ae_int_t nic; ae_vector xs; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repncholesky; ae_int_t repnmv; ae_int_t repterminationtype; ae_vector tmp0; ae_bool qpbleicfirstcall; qpbleicbuffers qpbleicbuf; qqpbuffers qqpbuf; qpcholeskybuffers qpcholeskybuf; normestimatorstate estimator; } minqpstate; typedef struct { ae_int_t inneriterationscount; ae_int_t outeriterationscount; ae_int_t nmv; ae_int_t ncholesky; ae_int_t terminationtype; } minqpreport; typedef struct { ae_int_t n; ae_int_t m; double diffstep; double epsg; double epsf; double epsx; ae_int_t maxits; ae_bool xrep; double stpmax; ae_int_t maxmodelage; ae_bool makeadditers; ae_vector x; double f; ae_vector fi; ae_matrix j; ae_matrix h; ae_vector g; ae_bool needf; ae_bool needfg; ae_bool needfgh; ae_bool needfij; ae_bool needfi; ae_bool xupdated; ae_bool userterminationneeded; ae_int_t algomode; ae_bool hasf; ae_bool hasfi; ae_bool hasg; ae_vector xbase; double fbase; ae_vector fibase; ae_vector gbase; ae_matrix quadraticmodel; ae_vector bndl; ae_vector bndu; ae_vector havebndl; ae_vector havebndu; ae_vector s; double lambdav; double nu; ae_int_t modelage; ae_vector xdir; ae_vector deltax; ae_vector deltaf; ae_bool deltaxready; ae_bool deltafready; double teststep; ae_int_t repiterationscount; ae_int_t repterminationtype; ae_int_t repfuncidx; ae_int_t repvaridx; ae_int_t repnfunc; ae_int_t repnjac; ae_int_t repngrad; ae_int_t repnhess; ae_int_t repncholesky; rcommstate rstate; ae_vector choleskybuf; ae_vector tmp0; double actualdecrease; double predicteddecrease; double xm1; double xp1; ae_vector fm1; ae_vector fp1; ae_vector fc1; ae_vector gm1; ae_vector gp1; ae_vector gc1; minlbfgsstate internalstate; minlbfgsreport internalrep; minqpstate qpstate; minqpreport qprep; } minlmstate; typedef struct { ae_int_t iterationscount; ae_int_t terminationtype; ae_int_t funcidx; ae_int_t varidx; ae_int_t nfunc; ae_int_t njac; ae_int_t ngrad; ae_int_t nhess; ae_int_t ncholesky; } minlmreport; typedef struct { ae_int_t n; double epsg; double epsf; double epsx; ae_int_t maxits; ae_bool xrep; double stpmax; ae_int_t cgtype; ae_int_t k; ae_int_t nfev; ae_int_t mcstage; ae_vector bndl; ae_vector bndu; ae_int_t curalgo; ae_int_t acount; double mu; double finit; double dginit; ae_vector ak; ae_vector xk; ae_vector dk; ae_vector an; ae_vector xn; ae_vector dn; ae_vector d; double fold; double stp; ae_vector work; ae_vector yk; ae_vector gc; double laststep; ae_vector x; double f; ae_vector g; ae_bool needfg; ae_bool xupdated; rcommstate rstate; ae_int_t repiterationscount; ae_int_t repnfev; ae_int_t repterminationtype; ae_int_t debugrestartscount; linminstate lstate; double betahs; double betady; } minasastate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; ae_int_t terminationtype; ae_int_t activeconstraints; } minasareport; typedef struct { double stabilizingpoint; double initialinequalitymultiplier; ae_int_t solvertype; ae_int_t prectype; ae_int_t updatefreq; double rho; ae_int_t n; double epsg; double epsf; double epsx; ae_int_t maxits; ae_int_t aulitscnt; ae_bool xrep; double diffstep; double teststep; ae_vector s; ae_vector bndl; ae_vector bndu; ae_vector hasbndl; ae_vector hasbndu; ae_int_t nec; ae_int_t nic; ae_matrix cleic; ae_int_t ng; ae_int_t nh; ae_vector x; double f; ae_vector fi; ae_matrix j; ae_bool needfij; ae_bool needfi; ae_bool xupdated; rcommstate rstate; rcommstate rstateaul; ae_vector scaledbndl; ae_vector scaledbndu; ae_matrix scaledcleic; ae_vector xc; ae_vector xstart; ae_vector xbase; ae_vector fbase; ae_vector dfbase; ae_vector fm2; ae_vector fm1; ae_vector fp1; ae_vector fp2; ae_vector dfm1; ae_vector dfp1; ae_vector bufd; ae_vector bufc; ae_matrix bufw; ae_vector xk; ae_vector xk1; ae_vector gk; ae_vector gk1; double gammak; ae_bool xkpresent; minlbfgsstate auloptimizer; minlbfgsreport aulreport; ae_vector nubc; ae_vector nulc; ae_vector nunlc; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repnfev; ae_int_t repvaridx; ae_int_t repfuncidx; ae_int_t repterminationtype; ae_int_t repdbgphase0its; } minnlcstate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t funcidx; ae_int_t terminationtype; ae_int_t dbgphase0its; } minnlcreport; typedef struct { double fc; double fn; ae_vector xc; ae_vector xn; ae_vector x0; ae_vector gc; ae_vector d; ae_matrix uh; ae_matrix ch; ae_matrix rk; ae_vector invutc; ae_vector tmp0; ae_vector tmpidx; ae_vector tmpd; ae_vector tmpc; ae_vector tmplambdas; ae_matrix tmpc2; ae_vector tmpb; snnlssolver nnls; } minnsqp; typedef struct { ae_int_t solvertype; ae_int_t n; double epsx; ae_int_t maxits; ae_bool xrep; double diffstep; ae_vector s; ae_vector bndl; ae_vector bndu; ae_vector hasbndl; ae_vector hasbndu; ae_int_t nec; ae_int_t nic; ae_matrix cleic; ae_int_t ng; ae_int_t nh; ae_vector x; double f; ae_vector fi; ae_matrix j; ae_bool needfij; ae_bool needfi; ae_bool xupdated; rcommstate rstate; rcommstate rstateags; hqrndstate agsrs; double agsradius; ae_int_t agssamplesize; double agsraddecay; double agsalphadecay; double agsdecrease; double agsinitstp; double agsstattold; double agsshortstpabs; double agsshortstprel; double agsshortf; ae_int_t agsshortlimit; double agsrhononlinear; ae_int_t agsminupdate; ae_int_t agsmaxraddecays; ae_int_t agsmaxbacktrack; ae_int_t agsmaxbacktracknonfull; double agspenaltylevel; double agspenaltyincrease; ae_vector xstart; ae_vector xc; ae_vector xn; ae_vector grs; ae_vector d; ae_vector colmax; ae_vector diagh; ae_vector signmin; ae_vector signmax; ae_bool userterminationneeded; ae_vector scaledbndl; ae_vector scaledbndu; ae_matrix scaledcleic; ae_vector rholinear; ae_matrix samplex; ae_matrix samplegm; ae_matrix samplegmbc; ae_vector samplef; ae_vector samplef0; minnsqp nsqp; ae_vector tmp0; ae_vector tmp1; ae_matrix tmp2; ae_vector tmp3; ae_vector xbase; ae_vector fp; ae_vector fm; ae_int_t repinneriterationscount; ae_int_t repouteriterationscount; ae_int_t repnfev; ae_int_t repvaridx; ae_int_t repfuncidx; ae_int_t repterminationtype; double replcerr; double repnlcerr; ae_int_t dbgncholesky; } minnsstate; typedef struct { ae_int_t iterationscount; ae_int_t nfev; double cerr; double lcerr; double nlcerr; ae_int_t terminationtype; ae_int_t varidx; ae_int_t funcidx; } minnsreport; } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* This object stores state of the nonlinear CG optimizer. You should use ALGLIB functions to work with this object. *************************************************************************/ class _mincgstate_owner { public: _mincgstate_owner(); _mincgstate_owner(const _mincgstate_owner &rhs); _mincgstate_owner& operator=(const _mincgstate_owner &rhs); virtual ~_mincgstate_owner(); alglib_impl::mincgstate* c_ptr(); alglib_impl::mincgstate* c_ptr() const; protected: alglib_impl::mincgstate *p_struct; }; class mincgstate : public _mincgstate_owner { public: mincgstate(); mincgstate(const mincgstate &rhs); mincgstate& operator=(const mincgstate &rhs); virtual ~mincgstate(); ae_bool &needf; ae_bool &needfg; ae_bool &xupdated; double &f; real_1d_array g; real_1d_array x; }; /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinCGSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called mincgrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/ class _mincgreport_owner { public: _mincgreport_owner(); _mincgreport_owner(const _mincgreport_owner &rhs); _mincgreport_owner& operator=(const _mincgreport_owner &rhs); virtual ~_mincgreport_owner(); alglib_impl::mincgreport* c_ptr(); alglib_impl::mincgreport* c_ptr() const; protected: alglib_impl::mincgreport *p_struct; }; class mincgreport : public _mincgreport_owner { public: mincgreport(); mincgreport(const mincgreport &rhs); mincgreport& operator=(const mincgreport &rhs); virtual ~mincgreport(); ae_int_t &iterationscount; ae_int_t &nfev; ae_int_t &varidx; ae_int_t &terminationtype; }; /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinBLEIC subpackage to work with this object *************************************************************************/ class _minbleicstate_owner { public: _minbleicstate_owner(); _minbleicstate_owner(const _minbleicstate_owner &rhs); _minbleicstate_owner& operator=(const _minbleicstate_owner &rhs); virtual ~_minbleicstate_owner(); alglib_impl::minbleicstate* c_ptr(); alglib_impl::minbleicstate* c_ptr() const; protected: alglib_impl::minbleicstate *p_struct; }; class minbleicstate : public _minbleicstate_owner { public: minbleicstate(); minbleicstate(const minbleicstate &rhs); minbleicstate& operator=(const minbleicstate &rhs); virtual ~minbleicstate(); ae_bool &needf; ae_bool &needfg; ae_bool &xupdated; double &f; real_1d_array g; real_1d_array x; }; /************************************************************************* This structure stores optimization report: * IterationsCount number of iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. ADDITIONAL FIELDS There are additional fields which can be used for debugging: * DebugEqErr error in the equality constraints (2-norm) * DebugFS f, calculated at projection of initial point to the feasible set * DebugFF f, calculated at the final point * DebugDX |X_start-X_final| *************************************************************************/ class _minbleicreport_owner { public: _minbleicreport_owner(); _minbleicreport_owner(const _minbleicreport_owner &rhs); _minbleicreport_owner& operator=(const _minbleicreport_owner &rhs); virtual ~_minbleicreport_owner(); alglib_impl::minbleicreport* c_ptr(); alglib_impl::minbleicreport* c_ptr() const; protected: alglib_impl::minbleicreport *p_struct; }; class minbleicreport : public _minbleicreport_owner { public: minbleicreport(); minbleicreport(const minbleicreport &rhs); minbleicreport& operator=(const minbleicreport &rhs); virtual ~minbleicreport(); ae_int_t &iterationscount; ae_int_t &nfev; ae_int_t &varidx; ae_int_t &terminationtype; double &debugeqerr; double &debugfs; double &debugff; double &debugdx; ae_int_t &debugfeasqpits; ae_int_t &debugfeasgpaits; ae_int_t &inneriterationscount; ae_int_t &outeriterationscount; }; /************************************************************************* *************************************************************************/ class _minlbfgsstate_owner { public: _minlbfgsstate_owner(); _minlbfgsstate_owner(const _minlbfgsstate_owner &rhs); _minlbfgsstate_owner& operator=(const _minlbfgsstate_owner &rhs); virtual ~_minlbfgsstate_owner(); alglib_impl::minlbfgsstate* c_ptr(); alglib_impl::minlbfgsstate* c_ptr() const; protected: alglib_impl::minlbfgsstate *p_struct; }; class minlbfgsstate : public _minlbfgsstate_owner { public: minlbfgsstate(); minlbfgsstate(const minlbfgsstate &rhs); minlbfgsstate& operator=(const minlbfgsstate &rhs); virtual ~minlbfgsstate(); ae_bool &needf; ae_bool &needfg; ae_bool &xupdated; double &f; real_1d_array g; real_1d_array x; }; /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/ class _minlbfgsreport_owner { public: _minlbfgsreport_owner(); _minlbfgsreport_owner(const _minlbfgsreport_owner &rhs); _minlbfgsreport_owner& operator=(const _minlbfgsreport_owner &rhs); virtual ~_minlbfgsreport_owner(); alglib_impl::minlbfgsreport* c_ptr(); alglib_impl::minlbfgsreport* c_ptr() const; protected: alglib_impl::minlbfgsreport *p_struct; }; class minlbfgsreport : public _minlbfgsreport_owner { public: minlbfgsreport(); minlbfgsreport(const minlbfgsreport &rhs); minlbfgsreport& operator=(const minlbfgsreport &rhs); virtual ~minlbfgsreport(); ae_int_t &iterationscount; ae_int_t &nfev; ae_int_t &varidx; ae_int_t &terminationtype; }; /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinQP subpackage to work with this object *************************************************************************/ class _minqpstate_owner { public: _minqpstate_owner(); _minqpstate_owner(const _minqpstate_owner &rhs); _minqpstate_owner& operator=(const _minqpstate_owner &rhs); virtual ~_minqpstate_owner(); alglib_impl::minqpstate* c_ptr(); alglib_impl::minqpstate* c_ptr() const; protected: alglib_impl::minqpstate *p_struct; }; class minqpstate : public _minqpstate_owner { public: minqpstate(); minqpstate(const minqpstate &rhs); minqpstate& operator=(const minqpstate &rhs); virtual ~minqpstate(); }; /************************************************************************* This structure stores optimization report: * InnerIterationsCount number of inner iterations * OuterIterationsCount number of outer iterations * NCholesky number of Cholesky decomposition * NMV number of matrix-vector products (only products calculated as part of iterative process are counted) * TerminationType completion code (see below) Completion codes: * -5 inappropriate solver was used: * QuickQP solver for problem with general linear constraints * Cholesky solver for semidefinite or indefinite problems * Cholesky solver for problems with non-boundary constraints * -4 BLEIC-QP or QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or, maybe, feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. * -1 solver error * 1..4 successful completion * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. *************************************************************************/ class _minqpreport_owner { public: _minqpreport_owner(); _minqpreport_owner(const _minqpreport_owner &rhs); _minqpreport_owner& operator=(const _minqpreport_owner &rhs); virtual ~_minqpreport_owner(); alglib_impl::minqpreport* c_ptr(); alglib_impl::minqpreport* c_ptr() const; protected: alglib_impl::minqpreport *p_struct; }; class minqpreport : public _minqpreport_owner { public: minqpreport(); minqpreport(const minqpreport &rhs); minqpreport& operator=(const minqpreport &rhs); virtual ~minqpreport(); ae_int_t &inneriterationscount; ae_int_t &outeriterationscount; ae_int_t &nmv; ae_int_t &ncholesky; ae_int_t &terminationtype; }; /************************************************************************* Levenberg-Marquardt optimizer. This structure should be created using one of the MinLMCreate???() functions. You should not access its fields directly; use ALGLIB functions to work with it. *************************************************************************/ class _minlmstate_owner { public: _minlmstate_owner(); _minlmstate_owner(const _minlmstate_owner &rhs); _minlmstate_owner& operator=(const _minlmstate_owner &rhs); virtual ~_minlmstate_owner(); alglib_impl::minlmstate* c_ptr(); alglib_impl::minlmstate* c_ptr() const; protected: alglib_impl::minlmstate *p_struct; }; class minlmstate : public _minlmstate_owner { public: minlmstate(); minlmstate(const minlmstate &rhs); minlmstate& operator=(const minlmstate &rhs); virtual ~minlmstate(); ae_bool &needf; ae_bool &needfg; ae_bool &needfgh; ae_bool &needfi; ae_bool &needfij; ae_bool &xupdated; double &f; real_1d_array fi; real_1d_array g; real_2d_array h; real_2d_array j; real_1d_array x; }; /************************************************************************* Optimization report, filled by MinLMResults() function FIELDS: * TerminationType, completetion code: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called MinLMRequestTermination(). X contains point which was "current accepted" when termination request was submitted. * IterationsCount, contains iterations count * NFunc, number of function calculations * NJac, number of Jacobi matrix calculations * NGrad, number of gradient calculations * NHess, number of Hessian calculations * NCholesky, number of Cholesky decomposition calculations *************************************************************************/ class _minlmreport_owner { public: _minlmreport_owner(); _minlmreport_owner(const _minlmreport_owner &rhs); _minlmreport_owner& operator=(const _minlmreport_owner &rhs); virtual ~_minlmreport_owner(); alglib_impl::minlmreport* c_ptr(); alglib_impl::minlmreport* c_ptr() const; protected: alglib_impl::minlmreport *p_struct; }; class minlmreport : public _minlmreport_owner { public: minlmreport(); minlmreport(const minlmreport &rhs); minlmreport& operator=(const minlmreport &rhs); virtual ~minlmreport(); ae_int_t &iterationscount; ae_int_t &terminationtype; ae_int_t &funcidx; ae_int_t &varidx; ae_int_t &nfunc; ae_int_t &njac; ae_int_t &ngrad; ae_int_t &nhess; ae_int_t &ncholesky; }; /************************************************************************* *************************************************************************/ class _minasastate_owner { public: _minasastate_owner(); _minasastate_owner(const _minasastate_owner &rhs); _minasastate_owner& operator=(const _minasastate_owner &rhs); virtual ~_minasastate_owner(); alglib_impl::minasastate* c_ptr(); alglib_impl::minasastate* c_ptr() const; protected: alglib_impl::minasastate *p_struct; }; class minasastate : public _minasastate_owner { public: minasastate(); minasastate(const minasastate &rhs); minasastate& operator=(const minasastate &rhs); virtual ~minasastate(); ae_bool &needfg; ae_bool &xupdated; double &f; real_1d_array g; real_1d_array x; }; /************************************************************************* *************************************************************************/ class _minasareport_owner { public: _minasareport_owner(); _minasareport_owner(const _minasareport_owner &rhs); _minasareport_owner& operator=(const _minasareport_owner &rhs); virtual ~_minasareport_owner(); alglib_impl::minasareport* c_ptr(); alglib_impl::minasareport* c_ptr() const; protected: alglib_impl::minasareport *p_struct; }; class minasareport : public _minasareport_owner { public: minasareport(); minasareport(const minasareport &rhs); minasareport& operator=(const minasareport &rhs); virtual ~minasareport(); ae_int_t &iterationscount; ae_int_t &nfev; ae_int_t &terminationtype; ae_int_t &activeconstraints; }; /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNLC subpackage to work with this object *************************************************************************/ class _minnlcstate_owner { public: _minnlcstate_owner(); _minnlcstate_owner(const _minnlcstate_owner &rhs); _minnlcstate_owner& operator=(const _minnlcstate_owner &rhs); virtual ~_minnlcstate_owner(); alglib_impl::minnlcstate* c_ptr(); alglib_impl::minnlcstate* c_ptr() const; protected: alglib_impl::minnlcstate *p_struct; }; class minnlcstate : public _minnlcstate_owner { public: minnlcstate(); minnlcstate(const minnlcstate &rhs); minnlcstate& operator=(const minnlcstate &rhs); virtual ~minnlcstate(); ae_bool &needfi; ae_bool &needfij; ae_bool &xupdated; double &f; real_1d_array fi; real_2d_array j; real_1d_array x; }; /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. Other fields of this structure are not documented and should not be used! *************************************************************************/ class _minnlcreport_owner { public: _minnlcreport_owner(); _minnlcreport_owner(const _minnlcreport_owner &rhs); _minnlcreport_owner& operator=(const _minnlcreport_owner &rhs); virtual ~_minnlcreport_owner(); alglib_impl::minnlcreport* c_ptr(); alglib_impl::minnlcreport* c_ptr() const; protected: alglib_impl::minnlcreport *p_struct; }; class minnlcreport : public _minnlcreport_owner { public: minnlcreport(); minnlcreport(const minnlcreport &rhs); minnlcreport& operator=(const minnlcreport &rhs); virtual ~minnlcreport(); ae_int_t &iterationscount; ae_int_t &nfev; ae_int_t &varidx; ae_int_t &funcidx; ae_int_t &terminationtype; ae_int_t &dbgphase0its; }; /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNS subpackage to work with this object *************************************************************************/ class _minnsstate_owner { public: _minnsstate_owner(); _minnsstate_owner(const _minnsstate_owner &rhs); _minnsstate_owner& operator=(const _minnsstate_owner &rhs); virtual ~_minnsstate_owner(); alglib_impl::minnsstate* c_ptr(); alglib_impl::minnsstate* c_ptr() const; protected: alglib_impl::minnsstate *p_struct; }; class minnsstate : public _minnsstate_owner { public: minnsstate(); minnsstate(const minnsstate &rhs); minnsstate& operator=(const minnsstate &rhs); virtual ~minnsstate(); ae_bool &needfi; ae_bool &needfij; ae_bool &xupdated; double &f; real_1d_array fi; real_2d_array j; real_1d_array x; }; /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) * CErr maximum violation of all types of constraints * LCErr maximum violation of linear constraints * NLCErr maximum violation of nonlinear constraints TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -3 box constraints are inconsistent -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() 2 sampling radius decreased below epsx 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 User requested termination via MinNSRequestTermination() Other fields of this structure are not documented and should not be used! *************************************************************************/ class _minnsreport_owner { public: _minnsreport_owner(); _minnsreport_owner(const _minnsreport_owner &rhs); _minnsreport_owner& operator=(const _minnsreport_owner &rhs); virtual ~_minnsreport_owner(); alglib_impl::minnsreport* c_ptr(); alglib_impl::minnsreport* c_ptr() const; protected: alglib_impl::minnsreport *p_struct; }; class minnsreport : public _minnsreport_owner { public: minnsreport(); minnsreport(const minnsreport &rhs); minnsreport& operator=(const minnsreport &rhs); virtual ~minnsreport(); ae_int_t &iterationscount; ae_int_t &nfev; double &cerr; double &lcerr; double &nlcerr; ae_int_t &terminationtype; ae_int_t &varidx; ae_int_t &funcidx; }; /************************************************************************* NONLINEAR CONJUGATE GRADIENT METHOD DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using one of the nonlinear conjugate gradient methods. These CG methods are globally convergent (even on non-convex functions) as long as grad(f) is Lipschitz continuous in a some neighborhood of the L = { x : f(x)<=f(x0) }. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinCGCreate() call 2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and other functions 3. User calls MinCGOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinCGResults() to get solution 5. Optionally, user may call MinCGRestartFrom() to solve another problem with same N but another starting point and/or another function. MinCGRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state); void mincgcreate(const real_1d_array &x, mincgstate &state); /************************************************************************* The subroutine is finite difference variant of MinCGCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinCGCreate() in order to get more information about creation of CG optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinCGSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. L-BFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state); void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state); /************************************************************************* This function sets stopping conditions for CG optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinCGSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function sets scaling coefficients for CG optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of CG optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the CG too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinCGSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void mincgsetscale(const mincgstate &state, const real_1d_array &s); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetxrep(const mincgstate &state, const bool needxrep); /************************************************************************* This function sets CG algorithm. INPUT PARAMETERS: State - structure which stores algorithm state CGType - algorithm type: * -1 automatic selection of the best algorithm * 0 DY (Dai and Yuan) algorithm * 1 Hybrid DY-HS algorithm -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype); /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetstpmax(const mincgstate &state, const double stpmax); /************************************************************************* This function allows to suggest initial step length to the CG algorithm. Suggested step length is used as starting point for the line search. It can be useful when you have badly scaled problem, i.e. when ||grad|| (which is used as initial estimate for the first step) is many orders of magnitude different from the desired step. Line search may fail on such problems without good estimate of initial step length. Imagine, for example, problem with ||grad||=10^50 and desired step equal to 0.1 Line search function will use 10^50 as initial step, then it will decrease step length by 2 (up to 20 attempts) and will get 10^44, which is still too large. This function allows us to tell than line search should be started from some moderate step length, like 1.0, so algorithm will be able to detect desired step length in a several searches. Default behavior (when no step is suggested) is to use preconditioner, if it is available, to generate initial estimate of step length. This function influences only first iteration of algorithm. It should be called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. Suggested step is ignored if you have preconditioner. INPUT PARAMETERS: State - structure used to store algorithm state. Stp - initial estimate of the step length. Can be zero (no estimate). -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgsuggeststep(const mincgstate &state, const double stp); /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdefault(const mincgstate &state); /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdiag(const mincgstate &state, const real_1d_array &d); /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinCGSetScale() call (before or after MinCGSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecscale(const mincgstate &state); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool mincgiteration(const mincgstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinCGCreate() for analytical gradient or MinCGCreateF() for numerical differentiation) you should choose appropriate variant of MinCGOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinCGOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinCGOptimize() and specific function used to create optimizer. | USER PASSED TO MinCGOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinCGCreateF() | work FAIL MinCGCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinCGOptimize() version. Attemps to use such combination (for example, to create optimizer with MinCGCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgoptimize(mincgstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void mincgoptimize(mincgstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* Conjugate gradient results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinCGSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, we return best X found so far * 8 terminated by user * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep); /************************************************************************* Conjugate gradient results Buffered implementation of MinCGResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep); /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgrestartfrom(const mincgstate &state, const real_1d_array &x); /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void mincgrequesttermination(const mincgstate &state); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinCGOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinCGSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 31.05.2012 by Bochkanov Sergey *************************************************************************/ void mincgsetgradientcheck(const mincgstate &state, const double teststep); /************************************************************************* BOUND CONSTRAINED OPTIMIZATION WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints REQUIREMENTS: * user must provide function value and gradient * starting point X0 must be feasible or not too far away from the feasible set * grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) } * function must be defined everywhere on the feasible set F USAGE: Constrained optimization if far more complex than the unconstrained one. Here we give very brief outline of the BLEIC optimizer. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinBLEICCreate() call 2. USer adds boundary and/or linear constraints by calling MinBLEICSetBC() and MinBLEICSetLC() functions. 3. User sets stopping conditions with MinBLEICSetCond(). 4. User calls MinBLEICOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 5. User calls MinBLEICResults() to get solution 6. Optionally user may call MinBLEICRestartFrom() to solve another problem with same N but another starting point. MinBLEICRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state); void minbleiccreate(const real_1d_array &x, minbleicstate &state); /************************************************************************* The subroutine is finite difference variant of MinBLEICCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinBLEICCreate() in order to get more information about creation of BLEIC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinBLEICSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. CG needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state); void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state); /************************************************************************* This function sets boundary constraints for BLEIC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function sets linear constraints for BLEIC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct); /************************************************************************* This function sets stopping conditions for the optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinBLEICSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform slightly more than MaxIts iterations. I.e., MaxIts sets non-strict limit on iterations count. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetcond(const minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function sets scaling coefficients for BLEIC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the BLEIC too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinBLEICSetPrec...() functions. There is a special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minbleicsetscale(const minbleicstate &state, const real_1d_array &s); /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdefault(const minbleicstate &state); /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE 1: D[i] should be positive. Exception will be thrown otherwise. NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &d); /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecscale(const minbleicstate &state); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinBLEICOptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetxrep(const minbleicstate &state, const bool needxrep); /************************************************************************* This function sets maximum step length IMPORTANT: this feature is hard to combine with preconditioning. You can't set upper limit on step length, when you solve optimization problem with linear (non-boundary) constraints AND preconditioner turned on. When non-boundary constraints are present, you have to either a) use preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! In this case algorithm will terminate with appropriate error code. INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetstpmax(const minbleicstate &state, const double stpmax); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minbleiciteration(const minbleicstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() for numerical differentiation) you should choose appropriate variant of MinBLEICOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinBLEICOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinBLEICOptimize() and specific function used to create optimizer. | USER PASSED TO MinBLEICOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinBLEICCreateF() | work FAIL MinBLEICCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinBLEICOptimize() version. Attemps to use such combination (for example, to create optimizer with MinBLEICCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicoptimize(minbleicstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minbleicoptimize(minbleicstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* BLEIC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. * -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken * 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. More information about fields of this structure can be found in the comments on MinBLEICReport datatype. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep); /************************************************************************* BLEIC results Buffered implementation of MinBLEICResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep); /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x); /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minbleicrequesttermination(const minbleicstate &state); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinBLEICOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinBLEICSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minbleicsetgradientcheck(const minbleicstate &state, const double teststep); /************************************************************************* LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using a quasi- Newton method (LBFGS scheme) which is optimized to use a minimum amount of memory. The subroutine generates the approximation of an inverse Hessian matrix by using information about the last M steps of the algorithm (instead of N). It lessens a required amount of memory from a value of order N^2 to a value of order 2*N*M. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinLBFGSCreate() call 2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() and other functions 3. User calls MinLBFGSOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinLBFGSResults() to get solution 5. Optionally user may call MinLBFGSRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLBFGSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension. N>0 M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - initial solution approximation, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLBFGSSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLBFGSSetStpMax() function to bound algorithm's steps. However, L-BFGS rarely needs such a tuning. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state); void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state); /************************************************************************* The subroutine is finite difference variant of MinLBFGSCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinLBFGSCreate() in order to get more information about creation of LBFGS optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinLBFGSSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. LBFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state); void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state); /************************************************************************* This function sets stopping conditions for L-BFGS optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLBFGSSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLBFGSOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep); /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax); /************************************************************************* This function sets scaling coefficients for LBFGS optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the LBFGS too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinLBFGSSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s); /************************************************************************* Modification of the preconditioner: default preconditioner (simple scaling, same for all elements of X) is used. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdefault(const minlbfgsstate &state); /************************************************************************* Modification of the preconditioner: Cholesky factorization of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state P - triangular preconditioner, Cholesky factorization of the approximate Hessian. array[0..N-1,0..N-1], (if larger, only leading N elements are used). IsUpper - whether upper or lower triangle of P is given (other triangle is not referenced) After call to this function preconditioner is changed to P (P is copied into the internal buffer). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: P should be nonsingular. Exception will be thrown otherwise. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper); /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &d); /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecscale(const minlbfgsstate &state); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minlbfgsiteration(const minlbfgsstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() for numerical differentiation) you should choose appropriate variant of MinLBFGSOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinLBFGSOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinLBFGSOptimize() and specific function used to create optimizer. | USER PASSED TO MinLBFGSOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinLBFGSCreateF() | work FAIL MinLBFGSCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinLBFGSOptimize() version. Attemps to use such combination (for example, to create optimizer with MinLBFGSCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minlbfgsoptimize(minlbfgsstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlbfgsoptimize(minlbfgsstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* L-BFGS algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. * -2 rounding errors prevent further improvement. X contains best point found. * -1 incorrect parameters were specified * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep); /************************************************************************* L-BFGS algorithm results Buffered implementation of MinLBFGSResults which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep); /************************************************************************* This subroutine restarts LBFGS algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x); /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlbfgsrequesttermination(const minlbfgsstate &state); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLBFGSOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLBFGSSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 24.05.2012 by Bochkanov Sergey *************************************************************************/ void minlbfgssetgradientcheck(const minlbfgsstate &state, const double teststep); /************************************************************************* CONSTRAINED QUADRATIC PROGRAMMING The subroutine creates QP optimizer. After initial creation, it contains default optimization problem with zero quadratic and linear terms and no constraints. You should set quadratic/linear terms with calls to functions provided by MinQP subpackage. You should also choose appropriate QP solver and set it and its stopping criteria by means of MinQPSetAlgo??????() function. Then, you should start solution process by means of MinQPOptimize() call. Solution itself can be obtained with MinQPResults() function. INPUT PARAMETERS: N - problem size OUTPUT PARAMETERS: State - optimizer with zero quadratic/linear terms and no constraints -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpcreate(const ae_int_t n, minqpstate &state); /************************************************************************* This function sets linear term for QP solver. By default, linear term is zero. INPUT PARAMETERS: State - structure which stores algorithm state B - linear term, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b); /************************************************************************* This function sets dense quadratic term for QP solver. By default, quadratic term is zero. SUPPORT BY ALGLIB QP ALGORITHMS: Dense quadratic term can be handled by any of the QP algorithms supported by ALGLIB QP Solver. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper); void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a); /************************************************************************* This function sets sparse quadratic term for QP solver. By default, quadratic term is zero. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadratictermsparse(const minqpstate &state, const sparsematrix &a, const bool isupper); /************************************************************************* This function sets starting point for QP solver. It is useful to have good initial approximation to the solution, because it will increase speed of convergence and identification of active constraints. INPUT PARAMETERS: State - structure which stores algorithm state X - starting point, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x); /************************************************************************* This function sets origin for QP solver. By default, following QP program is solved: min(0.5*x'*A*x+b'*x) This function allows to solve different problem: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) INPUT PARAMETERS: State - structure which stores algorithm state XOrigin - origin, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin); /************************************************************************* This function sets scaling coefficients. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function BLEIC-based QP solver uses scale for two purposes: * to evaluate stopping conditions * for preconditioning of the underlying BLEIC solver INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetscale(const minqpstate &state, const real_1d_array &s); /************************************************************************* This function tells solver to use Cholesky-based algorithm. This algorithm was deprecated in ALGLIB 3.9.0 because its performance is inferior to that of BLEIC-QP or QuickQP on high-dimensional problems. Furthermore, it supports only dense convex QP problems. This solver is no longer active by default. We recommend you to switch to BLEIC-QP or QuickQP solver. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgocholesky(const minqpstate &state); /************************************************************************* This function tells solver to use BLEIC-based algorithm and sets stopping criteria for the algorithm. ALGORITHM FEATURES: * supports dense and sparse QP problems * supports boundary and general linear equality/inequality constraints * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". Of course, global minimum is found only for positive definite and semidefinite problems. As for indefinite ones - only local minimum is found. ALGORITHM OUTLINE: * BLEIC-QP solver is just a driver function for MinBLEIC solver; it solves quadratic programming problem as general linearly constrained optimization problem, which is solved by means of BLEIC solver (part of ALGLIB, active set method). ALGORITHM LIMITATIONS: * unlike QuickQP solver, this algorithm does not perform Newton steps and does not use Level 3 BLAS. Being general-purpose active set method, it can activate constraints only one-by-one. Thus, its performance is lower than that of QuickQP. * its precision is also a bit inferior to that of QuickQP. BLEIC-QP performs only LBFGS steps (no Newton steps), which are good at detecting neighborhood of the solution, buy need many iterations to find solution with more than 6 digits of precision. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. NOTE: this algorithm uses LBFGS iterations, which are relatively cheap, but improve function value only a bit. So you will need many iterations to converge - from 0.1*N to 10*N, depending on problem's condition number. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgobleic(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function tells solver to use QuickQP algorithm: special extra-fast algorithm for problems with boundary-only constrants. It may solve non-convex problems as long as they are bounded from below under constraints. ALGORITHM FEATURES: * many times (from 5x to 50x!) faster than BLEIC-based QP solver; utilizes accelerated methods for activation of constraints. * supports dense and sparse QP problems * supports ONLY boundary constraints; general linear constraints are NOT supported by this solver * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". In convex/semidefinite case global minimum is returned, in nonconvex case - algorithm returns one of the local minimums. ALGORITHM OUTLINE: * algorithm performs two kinds of iterations: constrained CG iterations and constrained Newton iterations * initially it performs small number of constrained CG iterations, which can efficiently activate/deactivate multiple constraints * after CG phase algorithm tries to calculate Cholesky decomposition and to perform several constrained Newton steps. If Cholesky decomposition failed (matrix is indefinite even under constraints), we perform more CG iterations until we converge to such set of constraints that system matrix becomes positive definite. Constrained Newton steps greatly increase convergence speed and precision. * algorithm interleaves CG and Newton iterations which allows to handle indefinite matrices (CG phase) and quickly converge after final set of constraints is found (Newton phase). Combination of CG and Newton phases is called "outer iteration". * it is possible to turn off Newton phase (beneficial for semidefinite problems - Cholesky decomposition will fail too often) ALGORITHM LIMITATIONS: * algorithm does not support general linear constraints; only boundary ones are supported * Cholesky decomposition for sparse problems is performed with Skyline Cholesky solver, which is intended for low-profile matrices. No profile- reducing reordering of variables is performed in this version of ALGLIB. * problems with near-zero negative eigenvalues (or exacty zero ones) may experience about 2-3x performance penalty. The reason is that Cholesky decomposition can not be performed until we identify directions of zero and negative curvature and activate corresponding boundary constraints - but we need a lot of trial and errors because these directions are hard to notice in the matrix spectrum. In this case you may turn off Newton phase of algorithm. Large negative eigenvalues are not an issue, so highly non-convex problems can be solved very efficiently. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxOuterIts-maximum number of OUTER iterations. One outer iteration includes some amount of CG iterations (from 5 to ~N) and one or several (usually small amount) Newton steps. Thus, one outer iteration has high cost, but can greatly reduce funcation value. UseNewton- use Newton phase or not: * Newton phase improves performance of positive definite dense problems (about 2 times improvement can be observed) * can result in some performance penalty on semidefinite or slightly negative definite problems - each Newton phase will bring no improvement (Cholesky failure), but still will require computational time. * if you doubt, you can turn off this phase - optimizer will retain its most of its high speed. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 22.05.2014 by Bochkanov Sergey *************************************************************************/ void minqpsetalgoquickqp(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxouterits, const bool usenewton); /************************************************************************* This function sets boundary constraints for QP solver Boundary constraints are inactive by default (after initial creation). After being set, they are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function sets linear constraints for QP optimizer. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - structure previously allocated with MinQPCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately - there always exists some minor violation (about 10^-10...10^-13) due to numerical errors. -- ALGLIB -- Copyright 19.06.2012 by Bochkanov Sergey *************************************************************************/ void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct); /************************************************************************* This function solves quadratic programming problem. Prior to calling this function you should choose solver by means of one of the following functions: * MinQPSetAlgoQuickQP() - for QuickQP solver * MinQPSetAlgoBLEIC() - for BLEIC-QP solver These functions also allow you to control stopping criteria of the solver. If you did not set solver, MinQP subpackage will automatically select solver for your problem and will run it with default stopping criteria. However, it is better to set explicitly solver and its stopping criteria. INPUT PARAMETERS: State - algorithm state You should use MinQPResults() function to access results after calls to this function. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey. Special thanks to Elvira Illarionova for important suggestions on the linearly constrained QP algorithm. *************************************************************************/ void minqpoptimize(const minqpstate &state); /************************************************************************* QP solver results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution. This array is allocated and initialized only when Rep.TerminationType parameter is positive (success). Rep - optimization report. You should check Rep.TerminationType, which contains completion code, and you may check another fields which contain another information about algorithm functioning. Failure codes returned by algorithm are: * -5 inappropriate solver was used: * Cholesky solver for (semi)indefinite problems * Cholesky solver for problems with sparse matrix * QuickQP solver for problem with general linear constraints * -4 BLEIC-QP/QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or maybe feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. Completion codes specific for Cholesky algorithm: * 4 successful completion Completion codes specific for BLEIC/QuickQP algorithms: * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep); /************************************************************************* QP results Buffered implementation of MinQPResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep); /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] and Jacobian of f[]. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X * function vector f[] and Jacobian of f[] (simultaneously) at given point There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() and jac() callbacks. First one is used to calculate f[] at given point, second one calculates f[] and Jacobian df[i]/dx[j]. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not provide Jacobian), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateVJ() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state); /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] only. Finite differences are used to calculate Jacobian. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() callback. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not accept function vector), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateV() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state See also MinLMIteration, MinLMResults. NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state); void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state); /************************************************************************* LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION DESCRIPTION: This function is used to find minimum of general form (not "sum-of- -squares") function F = F(x[0], ..., x[n-1]) using its gradient and Hessian. Levenberg-Marquardt modification with L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step is used. REQUIREMENTS: This algorithm will request following information during its operation: * function value F at given point X * F and gradient G (simultaneously) at given point X * F, G and Hessian H (simultaneously) at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts func(), grad() and hess() function pointers. First pointer is used to calculate F at given point, second one calculates F(x) and grad F(x), third one calculates F(x), grad F(x), hess F(x). You can try to initialize MinLMState structure with FGH-function and then use incorrect version of MinLMOptimize() (for example, version which does not provide Hessian matrix), but it will lead to exception being thrown after first attempt to calculate Hessian. USAGE: 1. User initializes algorithm state with MinLMCreateFGH() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and pointers (delegates, etc.) to callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state); void minlmcreatefgh(const real_1d_array &x, minlmstate &state); /************************************************************************* This function sets stopping conditions for Levenberg-Marquardt optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLMSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS iterations are reported. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetxrep(const minlmstate &state, const bool needxrep); /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetstpmax(const minlmstate &state, const double stpmax); /************************************************************************* This function sets scaling coefficients for LM optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetscale(const minlmstate &state, const real_1d_array &s); /************************************************************************* This function sets boundary constraints for LM optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints or at its boundary -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function is used to change acceleration settings You can choose between three acceleration strategies: * AccType=0, no acceleration. * AccType=1, secant updates are used to update quadratic model after each iteration. After fixed number of iterations (or after model breakdown) we recalculate quadratic model using analytic Jacobian or finite differences. Number of secant-based iterations depends on optimization settings: about 3 iterations - when we have analytic Jacobian, up to 2*N iterations - when we use finite differences to calculate Jacobian. AccType=1 is recommended when Jacobian calculation cost is prohibitive high (several Mx1 function vector calculations followed by several NxN Cholesky factorizations are faster than calculation of one M*N Jacobian). It should also be used when we have no Jacobian, because finite difference approximation takes too much time to compute. Table below list optimization protocols (XYZ protocol corresponds to MinLMCreateXYZ) and acceleration types they support (and use by default). ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: protocol 0 1 comment V + + VJ + + FGH + DAFAULT VALUES: protocol 0 1 comment V x without acceleration it is so slooooooooow VJ x FGH x NOTE: this function should be called before optimization. Attempt to call it during algorithm iterations may result in unexpected behavior. NOTE: attempt to call this function with unsupported protocol/acceleration combination will result in exception being thrown. -- ALGLIB -- Copyright 14.10.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetacctype(const minlmstate &state, const ae_int_t acctype); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minlmiteration(const minlmstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x hess - callback which calculates function (or merit function) value func, gradient grad and Hessian hess at given point x fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. Depending on function used to create state structure, this algorithm may accept Jacobian and/or Hessian and/or gradient. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with MinLMCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* Levenberg-Marquardt algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report; includes termination codes and additional information. Termination codes are listed below, see comments for this structure for more info. Termination code is stored in rep.terminationtype field: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlmrequesttermination(). X contains point which was "current accepted" when termination request was submitted. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep); /************************************************************************* Levenberg-Marquardt algorithm results Buffered implementation of MinLMResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep); /************************************************************************* This subroutine restarts LM algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinLMCreateXXX call. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlmrestartfrom(const minlmstate &state, const real_1d_array &x); /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlmrequesttermination(const minlmstate &state); /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state); /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state); /************************************************************************* This function is considered obsolete since ALGLIB 3.1.0 and is present for backward compatibility only. We recommend to use MinLMCreateVJ, which provides similar, but more consistent and feature-rich interface. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLMOptimize() is called * prior to actual optimization, for each function Fi and each component of parameters being optimized X[j] algorithm performs following steps: * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], where X[j] is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on X[] * Fi(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) Jacobian evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLMSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minlmsetgradientcheck(const minlmstate &state, const double teststep); /************************************************************************* Obsolete function, use MinLBFGSSetPrecDefault() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state); /************************************************************************* Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper); /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierwidth(const minbleicstate &state, const double mu); /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state); void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetxrep(const minasastate &state, const bool needxrep); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetalgorithm(const minasastate &state, const ae_int_t algotype); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetstpmax(const minasastate &state, const double stpmax); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minasaiteration(const minasastate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaoptimize(minasastate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep); /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* NONLINEARLY CONSTRAINED OPTIMIZATION WITH PRECONDITIONED AUGMENTED LAGRANGIAN ALGORITHM DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 REQUIREMENTS: * user must provide function value and gradient for F(), H(), G() * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are twice continuously differentiable on the feasible set and its neighborhood * nonlinear constraints G() and H() must have non-zero gradient at G(x)=0 and at H(x)=0. Say, constraint like x^2>=1 is supported, but x^2>=0 is NOT supported. USAGE: Constrained optimization if far more complex than the unconstrained one. Nonlinearly constrained optimization is one of the most esoteric numerical procedures. Here we give very brief outline of the MinNLC optimizer. We strongly recommend you to study examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinNLCCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AUL solver (activated with MinNLCSetAlgoAUL() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNLCSetBC() for boundary constraints b) MinNLCSetLC() for linear constraints c) MinNLCSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNLCSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNLCSetCond(). If NLC solver uses inner/outer iteration layout, this function sets stopping conditions for INNER iterations. 5. User chooses one of the preconditioning methods. Preconditioning is very important for efficient handling of boundary/linear/nonlinear constraints. Without preconditioning algorithm would require thousands of iterations even for simple problems. Two preconditioners can be used: * approximate LBFGS-based preconditioner which should be used for problems with almost orthogonal constraints (activated by calling MinNLCSetPrecInexact) * exact low-rank preconditiner (activated by MinNLCSetPrecExactLowRank) which should be used for problems with moderate number of constraints which do not have to be orthogonal. 6. Finally, user calls MinNLCOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G/H. 7. User calls MinNLCResults() to get solution 8. Optionally user may call MinNLCRestartFrom() to solve another problem with same N but another starting point. MinNLCRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreate(const ae_int_t n, const real_1d_array &x, minnlcstate &state); void minnlccreate(const real_1d_array &x, minnlcstate &state); /************************************************************************* This subroutine is a finite difference variant of MinNLCCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinNLCCreate() in order to get more information about creation of NLC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinNLCSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large TRUNCATION errors, while too small step will result in too large NUMERICAL errors. 1.0E-4 can be good value to start from. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state); void minnlccreatef(const real_1d_array &x, const double diffstep, minnlcstate &state); /************************************************************************* This function sets boundary constraints for NLC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine boundary constraints with general linear ones - and with nonlinear ones! Boundary constraints are handled more efficiently than other types. Thus, if your problem has mixed constraints, you may explicitly specify some of them as boundary and save some time/space. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: when you solve your problem with augmented Lagrangian solver, boundary constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetbc(const minnlcstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function sets linear constraints for MinNLC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine linear constraints with boundary ones - and with nonlinear ones! If your problem has mixed constraints, you may explicitly specify some of them as linear. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: when you solve your problem with augmented Lagrangian solver, linear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetlc(const minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); void minnlcsetlc(const minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct); /************************************************************************* This function sets nonlinear constraints for MinNLC optimizer. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to MinNLCOptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] corresponds to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: when you solve your problem with augmented Lagrangian solver, nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! NOTE 2: algorithm scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetnlc(const minnlcstate &state, const ae_int_t nlec, const ae_int_t nlic); /************************************************************************* This function sets stopping conditions for inner iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinNLCSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetcond(const minnlcstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetscale(const minnlcstate &state, const real_1d_array &s); /************************************************************************* This function sets preconditioner to "inexact LBFGS-based" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss LBFGS-based preconditioner. Inexact LBFGS-based preconditioner uses L-BFGS formula combined with orthogonality assumption to perform very fast updates. For a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K) cost per iteration. This preconditioner has best quality (less iterations) when general linear and nonlinear constraints are orthogonal to each other (orthogonality with respect to boundary constraints is not required). Number of iterations increases when constraints are non-orthogonal, because algorithm assumes orthogonality, but still it is better than no preconditioner at all. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecinexact(const minnlcstate &state); /************************************************************************* This function sets preconditioner to "exact low rank" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss low rank preconditioner. Exact low-rank preconditioner uses Woodbury matrix identity to build quadratic model of the penalized function. It has no special assumptions about orthogonality, so it is quite general. However, for a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K^2) cost per iteration (for comparison: inexact LBFGS-based preconditioner has O(N*K) cost). INPUT PARAMETERS: State - structure stores algorithm state UpdateFreq- update frequency. Preconditioner is rebuilt after every UpdateFreq iterations. Recommended value: 10 or higher. Zero value means that good default value will be used. -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecexactlowrank(const minnlcstate &state, const ae_int_t updatefreq); /************************************************************************* This function sets preconditioner to "turned off" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. This function activates this test mode. Do not use it in production code to solve real-life problems. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecnone(const minnlcstate &state); /************************************************************************* This function tells MinNLC unit to use Augmented Lagrangian algorithm for nonlinearly constrained optimization. This algorithm is a slight modification of one described in "A Modified Barrier-Augmented Lagrangian Method for Constrained Minimization (1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH. Augmented Lagrangian algorithm works by converting problem of minimizing F(x) subject to equality/inequality constraints to unconstrained problem of the form min[ f(x) + + Rho*PENALTY_EQ(x) + SHIFT_EQ(x,Nu1) + + Rho*PENALTY_INEQ(x) + SHIFT_INEQ(x,Nu2) ] where: * Rho is a fixed penalization coefficient * PENALTY_EQ(x) is a penalty term, which is used to APPROXIMATELY enforce equality constraints * SHIFT_EQ(x) is a special "shift" term which is used to "fine-tune" equality constraints, greatly increasing precision * PENALTY_INEQ(x) is a penalty term which is used to approximately enforce inequality constraints * SHIFT_INEQ(x) is a special "shift" term which is used to "fine-tune" inequality constraints, greatly increasing precision * Nu1/Nu2 are vectors of Lagrange coefficients which are fine-tuned during outer iterations of algorithm This version of AUL algorithm uses preconditioner, which greatly accelerates convergence. Because this algorithm is similar to penalty methods, it may perform steps into infeasible area. All kinds of constraints (boundary, linear and nonlinear ones) may be violated in intermediate points - and in the solution. However, properly configured AUL method is significantly better at handling constraints than barrier and/or penalty methods. The very basic outline of algorithm is given below: 1) first outer iteration is performed with "default" values of Lagrange multipliers Nu1/Nu2. Solution quality is low (candidate point can be too far away from true solution; large violation of constraints is possible) and is comparable with that of penalty methods. 2) subsequent outer iterations refine Lagrange multipliers and improve quality of the solution. INPUT PARAMETERS: State - structure which stores algorithm state Rho - penalty coefficient, Rho>0: * large enough that algorithm converges with desired precision. Minimum value is 10*max(S'*diag(H)*S), where S is a scale matrix (set by MinNLCSetScale) and H is a Hessian of the function being minimized. If you can not easily estimate Hessian norm, see our recommendations below. * not TOO large to prevent ill-conditioning * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * it is important to note that Rho is internally multiplied by scaling matrix, i.e. optimum value of Rho depends on scale of variables specified by MinNLCSetScale(). ItsCnt - number of outer iterations: * ItsCnt=0 means that small number of outer iterations is automatically chosen (10 iterations in current version). * ItsCnt=1 means that AUL algorithm performs just as usual barrier method. * ItsCnt>1 means that AUL algorithm performs specified number of outer iterations HOW TO CHOOSE PARAMETERS Nonlinear optimization is a tricky area and Augmented Lagrangian algorithm is sometimes hard to tune. Good values of Rho and ItsCnt are problem- specific. In order to help you we prepared following set of recommendations: * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * start from some small value of Rho and solve problem with just one outer iteration (ItcCnt=1). In this case algorithm behaves like penalty method. Increase Rho in 2x or 10x steps until you see that one outer iteration returns point which is "rough approximation to solution". It is very important to have Rho so large that penalty term becomes constraining i.e. modified function becomes highly convex in constrained directions. From the other side, too large Rho may prevent you from converging to the solution. You can diagnose it by studying number of inner iterations performed by algorithm: too few (5-10 on 1000-dimensional problem) or too many (orders of magnitude more than dimensionality) usually means that Rho is too large. * with just one outer iteration you usually have low-quality solution. Some constraints can be violated with very large margin, while other ones (which are NOT violated in the true solution) can push final point too far in the inner area of the feasible set. For example, if you have constraint x0>=0 and true solution x0=1, then merely a presence of "x0>=0" will introduce a bias towards larger values of x0. Say, algorithm may stop at x0=1.5 instead of 1.0. * after you found good Rho, you may increase number of outer iterations. ItsCnt=10 is a good value. Subsequent outer iteration will refine values of Lagrange multipliers. Constraints which were violated will be enforced, inactive constraints will be dropped (corresponding multipliers will be decreased). Ideally, you should see 10-1000x improvement in constraint handling (constraint violation is reduced). * if you see that algorithm converges to vicinity of solution, but additional outer iterations do not refine solution, it may mean that algorithm is unstable - it wanders around true solution, but can not approach it. Sometimes algorithm may be stabilized by increasing Rho one more time, making it 5x or 10x larger. SCALING OF CONSTRAINTS [IMPORTANT] AUL optimizer scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, because function being optimized is a mix of original function and constraint-dependent penalty functions, it is important to rescale both variables AND constraints. Say, if you minimize f(x)=x^2 subject to 1000000*x>=0, then you have constraint whose scale is different from that of target function (another example is 0.000001*x>=0). It is also possible to have constraints whose scales are misaligned: 1000000*x0>=0, 0.000001*x1<=0. Inappropriate scaling may ruin convergence because minimizing x^2 subject to x>=0 is NOT same as minimizing it subject to 1000000*x>=0. Because we know coefficients of boundary/linear constraints, we can automatically rescale and normalize them. However, there is no way to automatically rescale nonlinear constraints Gi(x) and Hi(x) - they are black boxes. It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to rescale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). WHAT IF IT DOES NOT CONVERGE? It is possible that AUL algorithm fails to converge to precise values of Lagrange multipliers. It stops somewhere around true solution, but candidate point is still too far from solution, and some constraints are violated. Such kind of failure is specific for Lagrangian algorithms - technically, they stop at some point, but this point is not constrained solution. There are exist several reasons why algorithm may fail to converge: a) too loose stopping criteria for inner iteration b) degenerate, redundant constraints c) target function has unconstrained extremum exactly at the boundary of some constraint d) numerical noise in the target function In all these cases algorithm is unstable - each outer iteration results in large and almost random step which improves handling of some constraints, but violates other ones (ideally outer iterations should form a sequence of progressively decreasing steps towards solution). First reason possible is that too loose stopping criteria for inner iteration were specified. Augmented Lagrangian algorithm solves a sequence of intermediate problems, and requries each of them to be solved with high precision. Insufficient precision results in incorrect update of Lagrange multipliers. Another reason is that you may have specified degenerate constraints: say, some constraint was repeated twice. In most cases AUL algorithm gracefully handles such situations, but sometimes it may spend too much time figuring out subtle degeneracies in constraint matrix. Third reason is tricky and hard to diagnose. Consider situation when you minimize f=x^2 subject to constraint x>=0. Unconstrained extremum is located exactly at the boundary of constrained area. In this case algorithm will tend to oscillate between negative and positive x. Each time it stops at x<0 it "reinforces" constraint x>=0, and each time it is bounced to x>0 it "relaxes" constraint (and is attracted to x<0). Such situation sometimes happens in problems with hidden symetries. Algorithm is got caught in a loop with Lagrange multipliers being continuously increased/decreased. Luckily, such loop forms after at least three iterations, so this problem can be solved by DECREASING number of outer iterations down to 1-2 and increasing penalty coefficient Rho as much as possible. Final reason is numerical noise. AUL algorithm is robust against moderate noise (more robust than, say, active set methods), but large noise may destabilize algorithm. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetalgoaul(const minnlcstate &state, const double rho, const ae_int_t itscnt); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinNLCOptimize(). NOTE: algorithm passes two parameters to rep() callback - current point and penalized function value at current point. Important - function value which is returned is NOT function being minimized. It is sum of the value of the function being minimized - and penalty term. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcsetxrep(const minnlcstate &state, const bool needxrep); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minnlciteration(const minnlcstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of MinNLCOptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of MinNLCOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinNLCOptimize() and specific function used to create optimizer. | USER PASSED TO MinNLCOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinNLCCreateF() | works FAILS MinNLCCreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and MinNLCOptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcoptimize(minnlcstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minnlcoptimize(minnlcstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* MinNLC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken More information about fields of this structure can be found in the comments on MinNLCReport datatype. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcresults(const minnlcstate &state, real_1d_array &x, minnlcreport &rep); /************************************************************************* NLC results Buffered implementation of MinNLCResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcresultsbuf(const minnlcstate &state, real_1d_array &x, minnlcreport &rep); /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcrestartfrom(const minnlcstate &state, const real_1d_array &x); /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinNLCOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, and Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinNLCSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetgradientcheck(const minnlcstate &state, const double teststep); /************************************************************************* NONSMOOTH NONCONVEX OPTIMIZATION SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 IMPORTANT: see MinNSSetAlgoAGS for important information on performance restrictions of AGS solver. REQUIREMENTS: * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are continuous, locally Lipschitz and continuously (but not necessarily twice) differentiable in an open dense subset of R^N. Functions F(), G() and H() may be nonsmooth and non-convex. Informally speaking, it means that functions are composed of large differentiable "patches" with nonsmoothness having place only at the boundaries between these "patches". Most real-life nonsmooth functions satisfy these requirements. Say, anything which involves finite number of abs(), min() and max() is very likely to pass the test. Say, it is possible to optimize anything of the following: * f=abs(x0)+2*abs(x1) * f=max(x0,x1) * f=sin(max(x0,x1)+abs(x2)) * for nonlinearly constrained problems: F() must be bounded from below without nonlinear constraints (this requirement is due to the fact that, contrary to box and linear constraints, nonlinear ones require special handling). * user must provide function value and gradient for F(), H(), G() at all points where function/gradient can be calculated. If optimizer requires value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), where gradient is not defined, user may resolve tie arbitrarily (in our case - return +1 or -1 at its discretion). * NS solver supports numerical differentiation, i.e. it may differentiate your function for you, but it results in 2N increase of function evaluations. Not recommended unless you solve really small problems. See minnscreatef() for more information on this functionality. USAGE: 1. User initializes algorithm state with MinNSCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AGS solver (activated with MinNSSetAlgoAGS() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNSSetBC() for boundary constraints b) MinNSSetLC() for linear constraints c) MinNSSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNSSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNSSetCond(). 5. Finally, user calls MinNSOptimize() function which takes algorithm state and pointer (delegate, etc) to callback function which calculates F/G/H. 7. User calls MinNSResults() to get solution 8. Optionally user may call MinNSRestartFrom() to solve another problem with same N but another starting point. MinNSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state NOTE: minnscreatef() function may be used if you do not have analytic gradient. This function creates solver which uses numerical differentiation with user-specified step. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreate(const ae_int_t n, const real_1d_array &x, minnsstate &state); void minnscreate(const real_1d_array &x, minnsstate &state); /************************************************************************* Version of minnscreatef() which uses numerical differentiation. I.e., you do not have to calculate derivatives yourself. However, this version needs 2N times more function evaluations. 2-point differentiation formula is used, because more precise 4-point formula is unstable when used on non-smooth functions. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, DiffStep>0. Algorithm performs numerical differentiation with step for I-th variable being equal to DiffStep*S[I] (here S[] is a scale vector, set by minnssetscale() function). Do not use too small steps, because it may lead to catastrophic cancellation during intermediate calculations. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnsstate &state); void minnscreatef(const real_1d_array &x, const double diffstep, minnsstate &state); /************************************************************************* This function sets boundary constraints. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: AGS solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetbc(const minnsstate &state, const real_1d_array &bndl, const real_1d_array &bndu); /************************************************************************* This function sets linear constraints. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about current sampling radius in magnitude during optimization, about EpsX in the solution) due to use of penalty method to handle constraints. * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetlc(const minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); void minnssetlc(const minnsstate &state, const real_2d_array &c, const integer_1d_array &ct); /************************************************************************* This function sets nonlinear constraints. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to minnsoptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] correspond to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of the feasible area! NOTE 2: algorithm scales variables according to scale specified by minnssetscale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by minnssetscale() function). NOTE 3: nonlinear constraints are always hard to handle, no matter what algorithm you try to use. Even basic box/linear constraints modify function curvature by adding valleys and ridges. However, nonlinear constraints add valleys which are very hard to follow due to their "curved" nature. It means that optimization with single nonlinear constraint may be significantly slower than optimization with multiple linear ones. It is normal situation, and we recommend you to carefully choose Rho parameter of minnssetalgoags(), because too large value may slow down convergence. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetnlc(const minnsstate &state, const ae_int_t nlec, const ae_int_t nlic); /************************************************************************* This function sets stopping conditions for iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsX - >=0 The AGS solver finishes its work if on k+1-th iteration sampling radius decreases below EpsX. MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. We do not recommend you to rely on default choice in production code. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetcond(const minnsstate &state, const double epsx, const ae_int_t maxits); /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetscale(const minnsstate &state, const real_1d_array &s); /************************************************************************* This function tells MinNS unit to use AGS (adaptive gradient sampling) algorithm for nonsmooth constrained optimization. This algorithm is a slight modification of one described in "An Adaptive Gradient Sampling Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. This optimizer has following benefits and drawbacks: + robustness; it can be used with nonsmooth and nonconvex functions. + relatively easy tuning; most of the metaparameters are easy to select. - it has convergence of steepest descent, slower than CG/LBFGS. - each iteration involves evaluation of ~2N gradient values and solution of 2Nx2N quadratic programming problem, which limits applicability of algorithm by small-scale problems (up to 50-100). IMPORTANT: this algorithm has convergence guarantees, i.e. it will steadily move towards some stationary point of the function. However, "stationary point" does not always mean "solution". Nonsmooth problems often have "flat spots", i.e. areas where function do not change at all. Such "flat spots" are stationary points by definition, and algorithm may be caught here. Nonsmooth CONVEX tasks are not prone to this problem. Say, if your function has form f()=MAX(f0,f1,...), and f_i are convex, then f() is convex too and you have guaranteed convergence to solution. INPUT PARAMETERS: State - structure which stores algorithm state Radius - initial sampling radius, >=0. Internally multiplied by vector of per-variable scales specified by minnssetscale()). You should select relatively large sampling radius, roughly proportional to scaled length of the first steps of the algorithm. Something close to 0.1 in magnitude should be good for most problems. AGS solver can automatically decrease radius, so too large radius is not a problem (assuming that you won't choose so large radius that algorithm will sample function in too far away points, where gradient value is irrelevant). Too small radius won't cause algorithm to fail, but it may slow down algorithm (it may have to perform too short steps). Penalty - penalty coefficient for nonlinear constraints: * for problem with nonlinear constraints should be some problem-specific positive value, large enough that penalty term changes shape of the function. Starting from some problem-specific value penalty coefficient becomes large enough to exactly enforce nonlinear constraints; larger values do not improve precision. Increasing it too much may slow down convergence, so you should choose it carefully. * can be zero for problems WITHOUT nonlinear constraints (i.e. for unconstrained ones or ones with just box or linear constraints) * if you specify zero value for problem with at least one nonlinear constraint, algorithm will terminate with error code -1. ALGORITHM OUTLINE The very basic outline of unconstrained AGS algorithm is given below: 0. If sampling radius is below EpsX or we performed more then MaxIts iterations - STOP. 1. sample O(N) gradient values at random locations around current point; informally speaking, this sample is an implicit piecewise linear model of the function, although algorithm formulation does not mention that explicitly 2. solve quadratic programming problem in order to find descent direction 3. if QP solver tells us that we are near solution, decrease sampling radius and move to (0) 4. perform backtracking line search 5. after moving to new point, goto (0) As for the constraints: * box constraints are handled exactly by modification of the function being minimized * linear/nonlinear constraints are handled by adding L1 penalty. Because our solver can handle nonsmoothness, we can use L1 penalty function, which is an exact one (i.e. exact solution is returned under such penalty). * penalty coefficient for linear constraints is chosen automatically; however, penalty coefficient for nonlinear constraints must be specified by user. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetalgoags(const minnsstate &state, const double radius, const double penalty); /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to minnsoptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnssetxrep(const minnsstate &state, const bool needxrep); /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrequesttermination(const minnsstate &state); /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minnsiteration(const minnsstate &state); /************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of minnsoptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of minnsoptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to minnsoptimize() and specific function used to create optimizer. | USER PASSED TO minnsoptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ minnscreatef() | works FAILS minnscreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and minnsoptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsoptimize(minnsstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minnsoptimize(minnsstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); /************************************************************************* MinNS results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -3 box constraints are inconsistent * -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() * 2 sampling radius decreased below epsx * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. * 8 User requested termination via minnsrequesttermination() -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresults(const minnsstate &state, real_1d_array &x, minnsreport &rep); /************************************************************************* Buffered implementation of minnsresults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresultsbuf(const minnsstate &state, real_1d_array &x, minnsreport &rep); /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. X - new starting point. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrestartfrom(const minnsstate &state, const real_1d_array &x); } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { void trimprepare(double f, double* threshold, ae_state *_state); void trimfunction(double* f, /* Real */ ae_vector* g, ae_int_t n, double threshold, ae_state *_state); ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, /* Real */ ae_vector* bl, /* Boolean */ ae_vector* havebl, /* Real */ ae_vector* bu, /* Boolean */ ae_vector* havebu, ae_int_t nmain, ae_int_t nslack, ae_state *_state); void projectgradientintobc(/* Real */ ae_vector* x, /* Real */ ae_vector* g, /* Real */ ae_vector* bl, /* Boolean */ ae_vector* havebl, /* Real */ ae_vector* bu, /* Boolean */ ae_vector* havebu, ae_int_t nmain, ae_int_t nslack, ae_state *_state); void calculatestepbound(/* Real */ ae_vector* x, /* Real */ ae_vector* d, double alpha, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_int_t* variabletofreeze, double* valuetofreeze, double* maxsteplen, ae_state *_state); ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, /* Real */ ae_vector* xprev, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_int_t variabletofreeze, double valuetofreeze, double steptaken, double maxsteplen, ae_state *_state); void filterdirection(/* Real */ ae_vector* d, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, /* Real */ ae_vector* s, ae_int_t nmain, ae_int_t nslack, double droptol, ae_state *_state); ae_int_t numberofchangedconstraints(/* Real */ ae_vector* x, /* Real */ ae_vector* xprev, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_state *_state); ae_bool findfeasiblepoint(/* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, /* Real */ ae_matrix* ce, ae_int_t k, double epsi, ae_int_t* qpits, ae_int_t* gpaits, ae_state *_state); ae_bool derivativecheck(double f0, double df0, double f1, double df1, double f, double df, double width, ae_state *_state); void estimateparabolicmodel(double absasum, double absasum2, double mx, double mb, double md, double d1, double d2, ae_int_t* d1est, ae_int_t* d2est, ae_state *_state); void inexactlbfgspreconditioner(/* Real */ ae_vector* s, ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t k, precbuflbfgs* buf, ae_state *_state); void preparelowrankpreconditioner(/* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t n, ae_int_t k, precbuflowrank* buf, ae_state *_state); void applylowrankpreconditioner(/* Real */ ae_vector* s, precbuflowrank* buf, ae_state *_state); void _precbuflbfgs_init(void* _p, ae_state *_state); void _precbuflbfgs_init_copy(void* _dst, void* _src, ae_state *_state); void _precbuflbfgs_clear(void* _p); void _precbuflbfgs_destroy(void* _p); void _precbuflowrank_init(void* _p, ae_state *_state); void _precbuflowrank_init_copy(void* _dst, void* _src, ae_state *_state); void _precbuflowrank_clear(void* _p); void _precbuflowrank_destroy(void* _p); void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state); void cqmseta(convexquadraticmodel* s, /* Real */ ae_matrix* a, ae_bool isupper, double alpha, ae_state *_state); void cqmgeta(convexquadraticmodel* s, /* Real */ ae_matrix* a, ae_state *_state); void cqmrewritedensediagonal(convexquadraticmodel* s, /* Real */ ae_vector* z, ae_state *_state); void cqmsetd(convexquadraticmodel* s, /* Real */ ae_vector* d, double tau, ae_state *_state); void cqmdropa(convexquadraticmodel* s, ae_state *_state); void cqmsetb(convexquadraticmodel* s, /* Real */ ae_vector* b, ae_state *_state); void cqmsetq(convexquadraticmodel* s, /* Real */ ae_matrix* q, /* Real */ ae_vector* r, ae_int_t k, double theta, ae_state *_state); void cqmsetactiveset(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Boolean */ ae_vector* activeset, ae_state *_state); double cqmeval(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); void cqmevalx(convexquadraticmodel* s, /* Real */ ae_vector* x, double* r, double* noise, ae_state *_state); void cqmgradunconstrained(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state); double cqmxtadx2(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); void cqmadx(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state); ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); void cqmscalevector(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); double cqmdebugconstrainedevalt(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); double cqmdebugconstrainedevale(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state); void _convexquadraticmodel_init(void* _p, ae_state *_state); void _convexquadraticmodel_init_copy(void* _dst, void* _src, ae_state *_state); void _convexquadraticmodel_clear(void* _p); void _convexquadraticmodel_destroy(void* _p); void snnlsinit(ae_int_t nsmax, ae_int_t ndmax, ae_int_t nrmax, snnlssolver* s, ae_state *_state); void snnlssetproblem(snnlssolver* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t ns, ae_int_t nd, ae_int_t nr, ae_state *_state); void snnlsdropnnc(snnlssolver* s, ae_int_t idx, ae_state *_state); void snnlssolve(snnlssolver* s, /* Real */ ae_vector* x, ae_state *_state); void _snnlssolver_init(void* _p, ae_state *_state); void _snnlssolver_init_copy(void* _dst, void* _src, ae_state *_state); void _snnlssolver_clear(void* _p); void _snnlssolver_destroy(void* _p); void sasinit(ae_int_t n, sactiveset* s, ae_state *_state); void sassetscale(sactiveset* state, /* Real */ ae_vector* s, ae_state *_state); void sassetprecdiag(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state); void sassetbc(sactiveset* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void sassetlc(sactiveset* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void sassetlcx(sactiveset* state, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, ae_state *_state); ae_bool sasstartoptimization(sactiveset* state, /* Real */ ae_vector* x, ae_state *_state); void sasexploredirection(sactiveset* state, /* Real */ ae_vector* d, double* stpmax, ae_int_t* cidx, double* vval, ae_state *_state); ae_int_t sasmoveto(sactiveset* state, /* Real */ ae_vector* xn, ae_bool needact, ae_int_t cidx, double cval, ae_state *_state); void sasimmediateactivation(sactiveset* state, ae_int_t cidx, double cval, ae_state *_state); void sasconstraineddescent(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* d, ae_state *_state); void sasconstraineddescentprec(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* d, ae_state *_state); void sasconstraineddirection(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state); void sasconstraineddirectionprec(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state); void sascorrection(sactiveset* state, /* Real */ ae_vector* x, double* penalty, ae_state *_state); double sasactivelcpenalty1(sactiveset* state, /* Real */ ae_vector* x, ae_state *_state); double sasscaledconstrainednorm(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state); void sasstopoptimization(sactiveset* state, ae_state *_state); void sasreactivateconstraints(sactiveset* state, /* Real */ ae_vector* gc, ae_state *_state); void sasreactivateconstraintsprec(sactiveset* state, /* Real */ ae_vector* gc, ae_state *_state); void sasrebuildbasis(sactiveset* state, ae_state *_state); void _sactiveset_init(void* _p, ae_state *_state); void _sactiveset_init_copy(void* _dst, void* _src, ae_state *_state); void _sactiveset_clear(void* _p); void _sactiveset_destroy(void* _p); void mincgcreate(ae_int_t n, /* Real */ ae_vector* x, mincgstate* state, ae_state *_state); void mincgcreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, mincgstate* state, ae_state *_state); void mincgsetcond(mincgstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void mincgsetscale(mincgstate* state, /* Real */ ae_vector* s, ae_state *_state); void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state); void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state); void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state); void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state); void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state); double mincglastgoodstep(mincgstate* state, ae_state *_state); void mincgsetprecdefault(mincgstate* state, ae_state *_state); void mincgsetprecdiag(mincgstate* state, /* Real */ ae_vector* d, ae_state *_state); void mincgsetprecscale(mincgstate* state, ae_state *_state); ae_bool mincgiteration(mincgstate* state, ae_state *_state); void mincgresults(mincgstate* state, /* Real */ ae_vector* x, mincgreport* rep, ae_state *_state); void mincgresultsbuf(mincgstate* state, /* Real */ ae_vector* x, mincgreport* rep, ae_state *_state); void mincgrestartfrom(mincgstate* state, /* Real */ ae_vector* x, ae_state *_state); void mincgrequesttermination(mincgstate* state, ae_state *_state); void mincgsetprecdiagfast(mincgstate* state, /* Real */ ae_vector* d, ae_state *_state); void mincgsetpreclowrankfast(mincgstate* state, /* Real */ ae_vector* d1, /* Real */ ae_vector* c, /* Real */ ae_matrix* v, ae_int_t vcnt, ae_state *_state); void mincgsetprecvarpart(mincgstate* state, /* Real */ ae_vector* d2, ae_state *_state); void mincgsetgradientcheck(mincgstate* state, double teststep, ae_state *_state); void _mincgstate_init(void* _p, ae_state *_state); void _mincgstate_init_copy(void* _dst, void* _src, ae_state *_state); void _mincgstate_clear(void* _p); void _mincgstate_destroy(void* _p); void _mincgreport_init(void* _p, ae_state *_state); void _mincgreport_init_copy(void* _dst, void* _src, ae_state *_state); void _mincgreport_clear(void* _p); void _mincgreport_destroy(void* _p); void minbleiccreate(ae_int_t n, /* Real */ ae_vector* x, minbleicstate* state, ae_state *_state); void minbleiccreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minbleicstate* state, ae_state *_state); void minbleicsetbc(minbleicstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void minbleicsetlc(minbleicstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void minbleicsetcond(minbleicstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minbleicsetscale(minbleicstate* state, /* Real */ ae_vector* s, ae_state *_state); void minbleicsetprecdefault(minbleicstate* state, ae_state *_state); void minbleicsetprecdiag(minbleicstate* state, /* Real */ ae_vector* d, ae_state *_state); void minbleicsetprecscale(minbleicstate* state, ae_state *_state); void minbleicsetxrep(minbleicstate* state, ae_bool needxrep, ae_state *_state); void minbleicsetdrep(minbleicstate* state, ae_bool needdrep, ae_state *_state); void minbleicsetstpmax(minbleicstate* state, double stpmax, ae_state *_state); ae_bool minbleiciteration(minbleicstate* state, ae_state *_state); void minbleicresults(minbleicstate* state, /* Real */ ae_vector* x, minbleicreport* rep, ae_state *_state); void minbleicresultsbuf(minbleicstate* state, /* Real */ ae_vector* x, minbleicreport* rep, ae_state *_state); void minbleicrestartfrom(minbleicstate* state, /* Real */ ae_vector* x, ae_state *_state); void minbleicrequesttermination(minbleicstate* state, ae_state *_state); void minbleicemergencytermination(minbleicstate* state, ae_state *_state); void minbleicsetgradientcheck(minbleicstate* state, double teststep, ae_state *_state); void _minbleicstate_init(void* _p, ae_state *_state); void _minbleicstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minbleicstate_clear(void* _p); void _minbleicstate_destroy(void* _p); void _minbleicreport_init(void* _p, ae_state *_state); void _minbleicreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minbleicreport_clear(void* _p); void _minbleicreport_destroy(void* _p); void minlbfgscreate(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlbfgsstate* state, ae_state *_state); void minlbfgscreatef(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, double diffstep, minlbfgsstate* state, ae_state *_state); void minlbfgssetcond(minlbfgsstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minlbfgssetxrep(minlbfgsstate* state, ae_bool needxrep, ae_state *_state); void minlbfgssetstpmax(minlbfgsstate* state, double stpmax, ae_state *_state); void minlbfgssetscale(minlbfgsstate* state, /* Real */ ae_vector* s, ae_state *_state); void minlbfgscreatex(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, ae_int_t flags, double diffstep, minlbfgsstate* state, ae_state *_state); void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state); void minlbfgssetpreccholesky(minlbfgsstate* state, /* Real */ ae_matrix* p, ae_bool isupper, ae_state *_state); void minlbfgssetprecdiag(minlbfgsstate* state, /* Real */ ae_vector* d, ae_state *_state); void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state); void minlbfgssetprecrankklbfgsfast(minlbfgsstate* state, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t cnt, ae_state *_state); void minlbfgssetpreclowrankexact(minlbfgsstate* state, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t cnt, ae_state *_state); ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state); void minlbfgsresults(minlbfgsstate* state, /* Real */ ae_vector* x, minlbfgsreport* rep, ae_state *_state); void minlbfgsresultsbuf(minlbfgsstate* state, /* Real */ ae_vector* x, minlbfgsreport* rep, ae_state *_state); void minlbfgsrestartfrom(minlbfgsstate* state, /* Real */ ae_vector* x, ae_state *_state); void minlbfgsrequesttermination(minlbfgsstate* state, ae_state *_state); void minlbfgssetgradientcheck(minlbfgsstate* state, double teststep, ae_state *_state); void _minlbfgsstate_init(void* _p, ae_state *_state); void _minlbfgsstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minlbfgsstate_clear(void* _p); void _minlbfgsstate_destroy(void* _p); void _minlbfgsreport_init(void* _p, ae_state *_state); void _minlbfgsreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minlbfgsreport_clear(void* _p); void _minlbfgsreport_destroy(void* _p); void qqploaddefaults(ae_int_t nmain, qqpsettings* s, ae_state *_state); void qqpcopysettings(qqpsettings* src, qqpsettings* dst, ae_state *_state); void qqpoptimize(convexquadraticmodel* ac, sparsematrix* sparseac, ae_int_t akind, ae_bool sparseupper, /* Real */ ae_vector* bc, /* Real */ ae_vector* bndlc, /* Real */ ae_vector* bnduc, /* Real */ ae_vector* sc, /* Real */ ae_vector* xoriginc, ae_int_t nc, /* Real */ ae_matrix* cleicc, ae_int_t nec, ae_int_t nic, qqpsettings* settings, qqpbuffers* sstate, /* Real */ ae_vector* xs, ae_int_t* terminationtype, ae_state *_state); void _qqpsettings_init(void* _p, ae_state *_state); void _qqpsettings_init_copy(void* _dst, void* _src, ae_state *_state); void _qqpsettings_clear(void* _p); void _qqpsettings_destroy(void* _p); void _qqpbuffers_init(void* _p, ae_state *_state); void _qqpbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _qqpbuffers_clear(void* _p); void _qqpbuffers_destroy(void* _p); void qpbleicloaddefaults(ae_int_t nmain, qpbleicsettings* s, ae_state *_state); void qpbleiccopysettings(qpbleicsettings* src, qpbleicsettings* dst, ae_state *_state); void qpbleicoptimize(convexquadraticmodel* a, sparsematrix* sparsea, ae_int_t akind, ae_bool sparseaupper, double absasum, double absasum2, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, /* Real */ ae_vector* s, /* Real */ ae_vector* xorigin, ae_int_t n, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, qpbleicsettings* settings, qpbleicbuffers* sstate, ae_bool* firstcall, /* Real */ ae_vector* xs, ae_int_t* terminationtype, ae_state *_state); void _qpbleicsettings_init(void* _p, ae_state *_state); void _qpbleicsettings_init_copy(void* _dst, void* _src, ae_state *_state); void _qpbleicsettings_clear(void* _p); void _qpbleicsettings_destroy(void* _p); void _qpbleicbuffers_init(void* _p, ae_state *_state); void _qpbleicbuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _qpbleicbuffers_clear(void* _p); void _qpbleicbuffers_destroy(void* _p); void qpcholeskyloaddefaults(ae_int_t nmain, qpcholeskysettings* s, ae_state *_state); void qpcholeskycopysettings(qpcholeskysettings* src, qpcholeskysettings* dst, ae_state *_state); void qpcholeskyoptimize(convexquadraticmodel* a, double anorm, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, /* Real */ ae_vector* s, /* Real */ ae_vector* xorigin, ae_int_t n, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, qpcholeskybuffers* sstate, /* Real */ ae_vector* xsc, ae_int_t* terminationtype, ae_state *_state); void _qpcholeskysettings_init(void* _p, ae_state *_state); void _qpcholeskysettings_init_copy(void* _dst, void* _src, ae_state *_state); void _qpcholeskysettings_clear(void* _p); void _qpcholeskysettings_destroy(void* _p); void _qpcholeskybuffers_init(void* _p, ae_state *_state); void _qpcholeskybuffers_init_copy(void* _dst, void* _src, ae_state *_state); void _qpcholeskybuffers_clear(void* _p); void _qpcholeskybuffers_destroy(void* _p); void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state); void minqpsetlinearterm(minqpstate* state, /* Real */ ae_vector* b, ae_state *_state); void minqpsetquadraticterm(minqpstate* state, /* Real */ ae_matrix* a, ae_bool isupper, ae_state *_state); void minqpsetquadratictermsparse(minqpstate* state, sparsematrix* a, ae_bool isupper, ae_state *_state); void minqpsetstartingpoint(minqpstate* state, /* Real */ ae_vector* x, ae_state *_state); void minqpsetorigin(minqpstate* state, /* Real */ ae_vector* xorigin, ae_state *_state); void minqpsetscale(minqpstate* state, /* Real */ ae_vector* s, ae_state *_state); void minqpsetalgocholesky(minqpstate* state, ae_state *_state); void minqpsetalgobleic(minqpstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minqpsetalgoquickqp(minqpstate* state, double epsg, double epsf, double epsx, ae_int_t maxouterits, ae_bool usenewton, ae_state *_state); void minqpsetbc(minqpstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void minqpsetlc(minqpstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void minqpoptimize(minqpstate* state, ae_state *_state); void minqpresults(minqpstate* state, /* Real */ ae_vector* x, minqpreport* rep, ae_state *_state); void minqpresultsbuf(minqpstate* state, /* Real */ ae_vector* x, minqpreport* rep, ae_state *_state); void minqpsetlineartermfast(minqpstate* state, /* Real */ ae_vector* b, ae_state *_state); void minqpsetquadratictermfast(minqpstate* state, /* Real */ ae_matrix* a, ae_bool isupper, double s, ae_state *_state); void minqprewritediagonal(minqpstate* state, /* Real */ ae_vector* s, ae_state *_state); void minqpsetstartingpointfast(minqpstate* state, /* Real */ ae_vector* x, ae_state *_state); void minqpsetoriginfast(minqpstate* state, /* Real */ ae_vector* xorigin, ae_state *_state); void _minqpstate_init(void* _p, ae_state *_state); void _minqpstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minqpstate_clear(void* _p); void _minqpstate_destroy(void* _p); void _minqpreport_init(void* _p, ae_state *_state); void _minqpreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minqpreport_clear(void* _p); void _minqpreport_destroy(void* _p); void minlmcreatevj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state); void minlmcreatev(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, double diffstep, minlmstate* state, ae_state *_state); void minlmcreatefgh(ae_int_t n, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state); void minlmsetcond(minlmstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state); void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state); void minlmsetscale(minlmstate* state, /* Real */ ae_vector* s, ae_state *_state); void minlmsetbc(minlmstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void minlmsetacctype(minlmstate* state, ae_int_t acctype, ae_state *_state); ae_bool minlmiteration(minlmstate* state, ae_state *_state); void minlmresults(minlmstate* state, /* Real */ ae_vector* x, minlmreport* rep, ae_state *_state); void minlmresultsbuf(minlmstate* state, /* Real */ ae_vector* x, minlmreport* rep, ae_state *_state); void minlmrestartfrom(minlmstate* state, /* Real */ ae_vector* x, ae_state *_state); void minlmrequesttermination(minlmstate* state, ae_state *_state); void minlmcreatevgj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state); void minlmcreatefgj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state); void minlmcreatefj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state); void minlmsetgradientcheck(minlmstate* state, double teststep, ae_state *_state); void _minlmstate_init(void* _p, ae_state *_state); void _minlmstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minlmstate_clear(void* _p); void _minlmstate_destroy(void* _p); void _minlmreport_init(void* _p, ae_state *_state); void _minlmreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minlmreport_clear(void* _p); void _minlmreport_destroy(void* _p); void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, ae_state *_state); void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, /* Real */ ae_matrix* p, ae_bool isupper, ae_state *_state); void minbleicsetbarrierwidth(minbleicstate* state, double mu, ae_state *_state); void minbleicsetbarrierdecay(minbleicstate* state, double mudecay, ae_state *_state); void minasacreate(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, minasastate* state, ae_state *_state); void minasasetcond(minasastate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state); void minasasetalgorithm(minasastate* state, ae_int_t algotype, ae_state *_state); void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state); ae_bool minasaiteration(minasastate* state, ae_state *_state); void minasaresults(minasastate* state, /* Real */ ae_vector* x, minasareport* rep, ae_state *_state); void minasaresultsbuf(minasastate* state, /* Real */ ae_vector* x, minasareport* rep, ae_state *_state); void minasarestartfrom(minasastate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void _minasastate_init(void* _p, ae_state *_state); void _minasastate_init_copy(void* _dst, void* _src, ae_state *_state); void _minasastate_clear(void* _p); void _minasastate_destroy(void* _p); void _minasareport_init(void* _p, ae_state *_state); void _minasareport_init_copy(void* _dst, void* _src, ae_state *_state); void _minasareport_clear(void* _p); void _minasareport_destroy(void* _p); void minnlccreate(ae_int_t n, /* Real */ ae_vector* x, minnlcstate* state, ae_state *_state); void minnlccreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnlcstate* state, ae_state *_state); void minnlcsetbc(minnlcstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void minnlcsetlc(minnlcstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void minnlcsetnlc(minnlcstate* state, ae_int_t nlec, ae_int_t nlic, ae_state *_state); void minnlcsetcond(minnlcstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state); void minnlcsetscale(minnlcstate* state, /* Real */ ae_vector* s, ae_state *_state); void minnlcsetprecinexact(minnlcstate* state, ae_state *_state); void minnlcsetprecexactlowrank(minnlcstate* state, ae_int_t updatefreq, ae_state *_state); void minnlcsetprecnone(minnlcstate* state, ae_state *_state); void minnlcsetalgoaul(minnlcstate* state, double rho, ae_int_t itscnt, ae_state *_state); void minnlcsetxrep(minnlcstate* state, ae_bool needxrep, ae_state *_state); ae_bool minnlciteration(minnlcstate* state, ae_state *_state); void minnlcresults(minnlcstate* state, /* Real */ ae_vector* x, minnlcreport* rep, ae_state *_state); void minnlcresultsbuf(minnlcstate* state, /* Real */ ae_vector* x, minnlcreport* rep, ae_state *_state); void minnlcrestartfrom(minnlcstate* state, /* Real */ ae_vector* x, ae_state *_state); void minnlcsetgradientcheck(minnlcstate* state, double teststep, ae_state *_state); void minnlcequalitypenaltyfunction(double alpha, double* f, double* df, double* d2f, ae_state *_state); void minnlcinequalitypenaltyfunction(double alpha, double stabilizingpoint, double* f, double* df, double* d2f, ae_state *_state); void minnlcinequalityshiftfunction(double alpha, double* f, double* df, double* d2f, ae_state *_state); void _minnlcstate_init(void* _p, ae_state *_state); void _minnlcstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minnlcstate_clear(void* _p); void _minnlcstate_destroy(void* _p); void _minnlcreport_init(void* _p, ae_state *_state); void _minnlcreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minnlcreport_clear(void* _p); void _minnlcreport_destroy(void* _p); void minnscreate(ae_int_t n, /* Real */ ae_vector* x, minnsstate* state, ae_state *_state); void minnscreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnsstate* state, ae_state *_state); void minnssetbc(minnsstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); void minnssetlc(minnsstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state); void minnssetnlc(minnsstate* state, ae_int_t nlec, ae_int_t nlic, ae_state *_state); void minnssetcond(minnsstate* state, double epsx, ae_int_t maxits, ae_state *_state); void minnssetscale(minnsstate* state, /* Real */ ae_vector* s, ae_state *_state); void minnssetalgoags(minnsstate* state, double radius, double penalty, ae_state *_state); void minnssetxrep(minnsstate* state, ae_bool needxrep, ae_state *_state); void minnsrequesttermination(minnsstate* state, ae_state *_state); ae_bool minnsiteration(minnsstate* state, ae_state *_state); void minnsresults(minnsstate* state, /* Real */ ae_vector* x, minnsreport* rep, ae_state *_state); void minnsresultsbuf(minnsstate* state, /* Real */ ae_vector* x, minnsreport* rep, ae_state *_state); void minnsrestartfrom(minnsstate* state, /* Real */ ae_vector* x, ae_state *_state); void _minnsqp_init(void* _p, ae_state *_state); void _minnsqp_init_copy(void* _dst, void* _src, ae_state *_state); void _minnsqp_clear(void* _p); void _minnsqp_destroy(void* _p); void _minnsstate_init(void* _p, ae_state *_state); void _minnsstate_init_copy(void* _dst, void* _src, ae_state *_state); void _minnsstate_clear(void* _p); void _minnsstate_destroy(void* _p); void _minnsreport_init(void* _p, ae_state *_state); void _minnsreport_init_copy(void* _dst, void* _src, ae_state *_state); void _minnsreport_clear(void* _p); void _minnsreport_destroy(void* _p); } #endif qmapshack-1.10.0/3rdparty/alglib/src/optimization.cpp000755 001750 000144 00005204367 13024173403 023766 0ustar00oeichlerxusers000000 000000 /************************************************************************* ALGLIB 3.10.0 (source code generated 2015-08-19) Copyright (c) Sergey Bochkanov (ALGLIB project). >>> SOURCE LICENSE >>> 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 (www.fsf.org); either version 2 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. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses >>> END OF LICENSE >>> *************************************************************************/ #include "stdafx.h" #include "optimization.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif using namespace std; ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE // ///////////////////////////////////////////////////////////////////////// namespace alglib { /************************************************************************* This object stores state of the nonlinear CG optimizer. You should use ALGLIB functions to work with this object. *************************************************************************/ _mincgstate_owner::_mincgstate_owner() { p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mincgstate_init(p_struct, NULL); } _mincgstate_owner::_mincgstate_owner(const _mincgstate_owner &rhs) { p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mincgstate_owner& _mincgstate_owner::operator=(const _mincgstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mincgstate_clear(p_struct); alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mincgstate_owner::~_mincgstate_owner() { alglib_impl::_mincgstate_clear(p_struct); ae_free(p_struct); } alglib_impl::mincgstate* _mincgstate_owner::c_ptr() { return p_struct; } alglib_impl::mincgstate* _mincgstate_owner::c_ptr() const { return const_cast(p_struct); } mincgstate::mincgstate() : _mincgstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } mincgstate::mincgstate(const mincgstate &rhs):_mincgstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } mincgstate& mincgstate::operator=(const mincgstate &rhs) { if( this==&rhs ) return *this; _mincgstate_owner::operator=(rhs); return *this; } mincgstate::~mincgstate() { } /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinCGSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called mincgrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/ _mincgreport_owner::_mincgreport_owner() { p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mincgreport_init(p_struct, NULL); } _mincgreport_owner::_mincgreport_owner(const _mincgreport_owner &rhs) { p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _mincgreport_owner& _mincgreport_owner::operator=(const _mincgreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_mincgreport_clear(p_struct); alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _mincgreport_owner::~_mincgreport_owner() { alglib_impl::_mincgreport_clear(p_struct); ae_free(p_struct); } alglib_impl::mincgreport* _mincgreport_owner::c_ptr() { return p_struct; } alglib_impl::mincgreport* _mincgreport_owner::c_ptr() const { return const_cast(p_struct); } mincgreport::mincgreport() : _mincgreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) { } mincgreport::mincgreport(const mincgreport &rhs):_mincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) { } mincgreport& mincgreport::operator=(const mincgreport &rhs) { if( this==&rhs ) return *this; _mincgreport_owner::operator=(rhs); return *this; } mincgreport::~mincgreport() { } /************************************************************************* NONLINEAR CONJUGATE GRADIENT METHOD DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using one of the nonlinear conjugate gradient methods. These CG methods are globally convergent (even on non-convex functions) as long as grad(f) is Lipschitz continuous in a some neighborhood of the L = { x : f(x)<=f(x0) }. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinCGCreate() call 2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and other functions 3. User calls MinCGOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinCGResults() to get solution 5. Optionally, user may call MinCGRestartFrom() to solve another problem with same N but another starting point and/or another function. MinCGRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgcreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NONLINEAR CONJUGATE GRADIENT METHOD DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using one of the nonlinear conjugate gradient methods. These CG methods are globally convergent (even on non-convex functions) as long as grad(f) is Lipschitz continuous in a some neighborhood of the L = { x : f(x)<=f(x0) }. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinCGCreate() call 2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and other functions 3. User calls MinCGOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinCGResults() to get solution 5. Optionally, user may call MinCGRestartFrom() to solve another problem with same N but another starting point and/or another function. MinCGRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void mincgcreate(const real_1d_array &x, mincgstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgcreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinCGCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinCGCreate() in order to get more information about creation of CG optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinCGSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. L-BFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgcreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinCGCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinCGCreate() in order to get more information about creation of CG optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinCGSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. L-BFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgcreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for CG optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinCGSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for CG optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of CG optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the CG too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinCGSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void mincgsetscale(const mincgstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetxrep(const mincgstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets CG algorithm. INPUT PARAMETERS: State - structure which stores algorithm state CGType - algorithm type: * -1 automatic selection of the best algorithm * 0 DY (Dai and Yuan) algorithm * 1 Hybrid DY-HS algorithm -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetcgtype(const_cast(state.c_ptr()), cgtype, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetstpmax(const mincgstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function allows to suggest initial step length to the CG algorithm. Suggested step length is used as starting point for the line search. It can be useful when you have badly scaled problem, i.e. when ||grad|| (which is used as initial estimate for the first step) is many orders of magnitude different from the desired step. Line search may fail on such problems without good estimate of initial step length. Imagine, for example, problem with ||grad||=10^50 and desired step equal to 0.1 Line search function will use 10^50 as initial step, then it will decrease step length by 2 (up to 20 attempts) and will get 10^44, which is still too large. This function allows us to tell than line search should be started from some moderate step length, like 1.0, so algorithm will be able to detect desired step length in a several searches. Default behavior (when no step is suggested) is to use preconditioner, if it is available, to generate initial estimate of step length. This function influences only first iteration of algorithm. It should be called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. Suggested step is ignored if you have preconditioner. INPUT PARAMETERS: State - structure used to store algorithm state. Stp - initial estimate of the step length. Can be zero (no estimate). -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgsuggeststep(const mincgstate &state, const double stp) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsuggeststep(const_cast(state.c_ptr()), stp, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdefault(const mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdiag(const mincgstate &state, const real_1d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinCGSetScale() call (before or after MinCGSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecscale(const mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool mincgiteration(const mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::mincgiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void mincgoptimize(mincgstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'mincgoptimize()' (func is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void mincgoptimize(mincgstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( grad==NULL ) throw ap_error("ALGLIB: error in 'mincgoptimize()' (grad is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conjugate gradient results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinCGSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, we return best X found so far * 8 terminated by user * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Conjugate gradient results Buffered implementation of MinCGResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgrestartfrom(const mincgstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void mincgrequesttermination(const mincgstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgrequesttermination(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinCGOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinCGSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 31.05.2012 by Bochkanov Sergey *************************************************************************/ void mincgsetgradientcheck(const mincgstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::mincgsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinBLEIC subpackage to work with this object *************************************************************************/ _minbleicstate_owner::_minbleicstate_owner() { p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minbleicstate_init(p_struct, NULL); } _minbleicstate_owner::_minbleicstate_owner(const _minbleicstate_owner &rhs) { p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minbleicstate_owner& _minbleicstate_owner::operator=(const _minbleicstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minbleicstate_clear(p_struct); alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minbleicstate_owner::~_minbleicstate_owner() { alglib_impl::_minbleicstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() { return p_struct; } alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() const { return const_cast(p_struct); } minbleicstate::minbleicstate() : _minbleicstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minbleicstate::minbleicstate(const minbleicstate &rhs):_minbleicstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minbleicstate& minbleicstate::operator=(const minbleicstate &rhs) { if( this==&rhs ) return *this; _minbleicstate_owner::operator=(rhs); return *this; } minbleicstate::~minbleicstate() { } /************************************************************************* This structure stores optimization report: * IterationsCount number of iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. ADDITIONAL FIELDS There are additional fields which can be used for debugging: * DebugEqErr error in the equality constraints (2-norm) * DebugFS f, calculated at projection of initial point to the feasible set * DebugFF f, calculated at the final point * DebugDX |X_start-X_final| *************************************************************************/ _minbleicreport_owner::_minbleicreport_owner() { p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minbleicreport_init(p_struct, NULL); } _minbleicreport_owner::_minbleicreport_owner(const _minbleicreport_owner &rhs) { p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minbleicreport_owner& _minbleicreport_owner::operator=(const _minbleicreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minbleicreport_clear(p_struct); alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minbleicreport_owner::~_minbleicreport_owner() { alglib_impl::_minbleicreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() { return p_struct; } alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() const { return const_cast(p_struct); } minbleicreport::minbleicreport() : _minbleicreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) { } minbleicreport::minbleicreport(const minbleicreport &rhs):_minbleicreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) { } minbleicreport& minbleicreport::operator=(const minbleicreport &rhs) { if( this==&rhs ) return *this; _minbleicreport_owner::operator=(rhs); return *this; } minbleicreport::~minbleicreport() { } /************************************************************************* BOUND CONSTRAINED OPTIMIZATION WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints REQUIREMENTS: * user must provide function value and gradient * starting point X0 must be feasible or not too far away from the feasible set * grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) } * function must be defined everywhere on the feasible set F USAGE: Constrained optimization if far more complex than the unconstrained one. Here we give very brief outline of the BLEIC optimizer. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinBLEICCreate() call 2. USer adds boundary and/or linear constraints by calling MinBLEICSetBC() and MinBLEICSetLC() functions. 3. User sets stopping conditions with MinBLEICSetCond(). 4. User calls MinBLEICOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 5. User calls MinBLEICResults() to get solution 6. Optionally user may call MinBLEICRestartFrom() to solve another problem with same N but another starting point. MinBLEICRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleiccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* BOUND CONSTRAINED OPTIMIZATION WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints REQUIREMENTS: * user must provide function value and gradient * starting point X0 must be feasible or not too far away from the feasible set * grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) } * function must be defined everywhere on the feasible set F USAGE: Constrained optimization if far more complex than the unconstrained one. Here we give very brief outline of the BLEIC optimizer. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinBLEICCreate() call 2. USer adds boundary and/or linear constraints by calling MinBLEICSetBC() and MinBLEICSetLC() functions. 3. User sets stopping conditions with MinBLEICSetCond(). 4. User calls MinBLEICOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 5. User calls MinBLEICResults() to get solution 6. Optionally user may call MinBLEICRestartFrom() to solve another problem with same N but another starting point. MinBLEICRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleiccreate(const real_1d_array &x, minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleiccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinBLEICCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinBLEICCreate() in order to get more information about creation of BLEIC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinBLEICSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. CG needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleiccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinBLEICCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinBLEICCreate() in order to get more information about creation of BLEIC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinBLEICSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. CG needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleiccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints for BLEIC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for BLEIC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for BLEIC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; if( (c.rows()!=ct.length())) throw ap_error("Error while calling 'minbleicsetlc': looks like one of arguments has wrong size"); k = c.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for the optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinBLEICSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform slightly more than MaxIts iterations. I.e., MaxIts sets non-strict limit on iterations count. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetcond(const minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for BLEIC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the BLEIC too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinBLEICSetPrec...() functions. There is a special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minbleicsetscale(const minbleicstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdefault(const minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE 1: D[i] should be positive. Exception will be thrown otherwise. NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecscale(const minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinBLEICOptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetxrep(const minbleicstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length IMPORTANT: this feature is hard to combine with preconditioning. You can't set upper limit on step length, when you solve optimization problem with linear (non-boundary) constraints AND preconditioner turned on. When non-boundary constraints are present, you have to either a) use preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! In this case algorithm will terminate with appropriate error code. INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetstpmax(const minbleicstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minbleiciteration(const minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minbleiciteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minbleicoptimize(minbleicstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'minbleicoptimize()' (func is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minbleicoptimize(minbleicstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( grad==NULL ) throw ap_error("ALGLIB: error in 'minbleicoptimize()' (grad is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* BLEIC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. * -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken * 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. More information about fields of this structure can be found in the comments on MinBLEICReport datatype. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* BLEIC results Buffered implementation of MinBLEICResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minbleicrequesttermination(const minbleicstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicrequesttermination(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinBLEICOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinBLEICSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minbleicsetgradientcheck(const minbleicstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _minlbfgsstate_owner::_minlbfgsstate_owner() { p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlbfgsstate_init(p_struct, NULL); } _minlbfgsstate_owner::_minlbfgsstate_owner(const _minlbfgsstate_owner &rhs) { p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minlbfgsstate_owner& _minlbfgsstate_owner::operator=(const _minlbfgsstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minlbfgsstate_clear(p_struct); alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minlbfgsstate_owner::~_minlbfgsstate_owner() { alglib_impl::_minlbfgsstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() { return p_struct; } alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() const { return const_cast(p_struct); } minlbfgsstate::minlbfgsstate() : _minlbfgsstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minlbfgsstate::minlbfgsstate(const minlbfgsstate &rhs):_minlbfgsstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minlbfgsstate& minlbfgsstate::operator=(const minlbfgsstate &rhs) { if( this==&rhs ) return *this; _minlbfgsstate_owner::operator=(rhs); return *this; } minlbfgsstate::~minlbfgsstate() { } /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/ _minlbfgsreport_owner::_minlbfgsreport_owner() { p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlbfgsreport_init(p_struct, NULL); } _minlbfgsreport_owner::_minlbfgsreport_owner(const _minlbfgsreport_owner &rhs) { p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minlbfgsreport_owner& _minlbfgsreport_owner::operator=(const _minlbfgsreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minlbfgsreport_clear(p_struct); alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minlbfgsreport_owner::~_minlbfgsreport_owner() { alglib_impl::_minlbfgsreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() { return p_struct; } alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() const { return const_cast(p_struct); } minlbfgsreport::minlbfgsreport() : _minlbfgsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) { } minlbfgsreport::minlbfgsreport(const minlbfgsreport &rhs):_minlbfgsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) { } minlbfgsreport& minlbfgsreport::operator=(const minlbfgsreport &rhs) { if( this==&rhs ) return *this; _minlbfgsreport_owner::operator=(rhs); return *this; } minlbfgsreport::~minlbfgsreport() { } /************************************************************************* LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using a quasi- Newton method (LBFGS scheme) which is optimized to use a minimum amount of memory. The subroutine generates the approximation of an inverse Hessian matrix by using information about the last M steps of the algorithm (instead of N). It lessens a required amount of memory from a value of order N^2 to a value of order 2*N*M. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinLBFGSCreate() call 2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() and other functions 3. User calls MinLBFGSOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinLBFGSResults() to get solution 5. Optionally user may call MinLBFGSRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLBFGSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension. N>0 M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - initial solution approximation, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLBFGSSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLBFGSSetStpMax() function to bound algorithm's steps. However, L-BFGS rarely needs such a tuning. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgscreate(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using a quasi- Newton method (LBFGS scheme) which is optimized to use a minimum amount of memory. The subroutine generates the approximation of an inverse Hessian matrix by using information about the last M steps of the algorithm (instead of N). It lessens a required amount of memory from a value of order N^2 to a value of order 2*N*M. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinLBFGSCreate() call 2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() and other functions 3. User calls MinLBFGSOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinLBFGSResults() to get solution 5. Optionally user may call MinLBFGSRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLBFGSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension. N>0 M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - initial solution approximation, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLBFGSSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLBFGSSetStpMax() function to bound algorithm's steps. However, L-BFGS rarely needs such a tuning. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgscreate(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinLBFGSCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinLBFGSCreate() in order to get more information about creation of LBFGS optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinLBFGSSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. LBFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgscreatef(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* The subroutine is finite difference variant of MinLBFGSCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinLBFGSCreate() in order to get more information about creation of LBFGS optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinLBFGSSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. LBFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgscreatef(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for L-BFGS optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLBFGSSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLBFGSOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for LBFGS optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the LBFGS too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinLBFGSSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: default preconditioner (simple scaling, same for all elements of X) is used. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdefault(const minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: Cholesky factorization of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state P - triangular preconditioner, Cholesky factorization of the approximate Hessian. array[0..N-1,0..N-1], (if larger, only leading N elements are used). IsUpper - whether upper or lower triangle of P is given (other triangle is not referenced) After call to this function preconditioner is changed to P (P is copied into the internal buffer). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: P should be nonsingular. Exception will be thrown otherwise. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetpreccholesky(const_cast(state.c_ptr()), const_cast(p.c_ptr()), isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &d) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecscale(const minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minlbfgsiteration(const minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minlbfgsiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlbfgsoptimize(minlbfgsstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (func is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlbfgsoptimize(minlbfgsstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( grad==NULL ) throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (grad is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* L-BFGS algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. * -2 rounding errors prevent further improvement. X contains best point found. * -1 incorrect parameters were specified * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgsresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* L-BFGS algorithm results Buffered implementation of MinLBFGSResults which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgsresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts LBFGS algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgsrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlbfgsrequesttermination(const minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgsrequesttermination(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLBFGSOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLBFGSSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 24.05.2012 by Bochkanov Sergey *************************************************************************/ void minlbfgssetgradientcheck(const minlbfgsstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinQP subpackage to work with this object *************************************************************************/ _minqpstate_owner::_minqpstate_owner() { p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minqpstate_init(p_struct, NULL); } _minqpstate_owner::_minqpstate_owner(const _minqpstate_owner &rhs) { p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minqpstate_owner& _minqpstate_owner::operator=(const _minqpstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minqpstate_clear(p_struct); alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minqpstate_owner::~_minqpstate_owner() { alglib_impl::_minqpstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minqpstate* _minqpstate_owner::c_ptr() { return p_struct; } alglib_impl::minqpstate* _minqpstate_owner::c_ptr() const { return const_cast(p_struct); } minqpstate::minqpstate() : _minqpstate_owner() { } minqpstate::minqpstate(const minqpstate &rhs):_minqpstate_owner(rhs) { } minqpstate& minqpstate::operator=(const minqpstate &rhs) { if( this==&rhs ) return *this; _minqpstate_owner::operator=(rhs); return *this; } minqpstate::~minqpstate() { } /************************************************************************* This structure stores optimization report: * InnerIterationsCount number of inner iterations * OuterIterationsCount number of outer iterations * NCholesky number of Cholesky decomposition * NMV number of matrix-vector products (only products calculated as part of iterative process are counted) * TerminationType completion code (see below) Completion codes: * -5 inappropriate solver was used: * QuickQP solver for problem with general linear constraints * Cholesky solver for semidefinite or indefinite problems * Cholesky solver for problems with non-boundary constraints * -4 BLEIC-QP or QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or, maybe, feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. * -1 solver error * 1..4 successful completion * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. *************************************************************************/ _minqpreport_owner::_minqpreport_owner() { p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minqpreport_init(p_struct, NULL); } _minqpreport_owner::_minqpreport_owner(const _minqpreport_owner &rhs) { p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minqpreport_owner& _minqpreport_owner::operator=(const _minqpreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minqpreport_clear(p_struct); alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minqpreport_owner::~_minqpreport_owner() { alglib_impl::_minqpreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minqpreport* _minqpreport_owner::c_ptr() { return p_struct; } alglib_impl::minqpreport* _minqpreport_owner::c_ptr() const { return const_cast(p_struct); } minqpreport::minqpreport() : _minqpreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype) { } minqpreport::minqpreport(const minqpreport &rhs):_minqpreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype) { } minqpreport& minqpreport::operator=(const minqpreport &rhs) { if( this==&rhs ) return *this; _minqpreport_owner::operator=(rhs); return *this; } minqpreport::~minqpreport() { } /************************************************************************* CONSTRAINED QUADRATIC PROGRAMMING The subroutine creates QP optimizer. After initial creation, it contains default optimization problem with zero quadratic and linear terms and no constraints. You should set quadratic/linear terms with calls to functions provided by MinQP subpackage. You should also choose appropriate QP solver and set it and its stopping criteria by means of MinQPSetAlgo??????() function. Then, you should start solution process by means of MinQPOptimize() call. Solution itself can be obtained with MinQPResults() function. INPUT PARAMETERS: N - problem size OUTPUT PARAMETERS: State - optimizer with zero quadratic/linear terms and no constraints -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpcreate(const ae_int_t n, minqpstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpcreate(n, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear term for QP solver. By default, linear term is zero. INPUT PARAMETERS: State - structure which stores algorithm state B - linear term, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetlinearterm(const_cast(state.c_ptr()), const_cast(b.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets dense quadratic term for QP solver. By default, quadratic term is zero. SUPPORT BY ALGLIB QP ALGORITHMS: Dense quadratic term can be handled by any of the QP algorithms supported by ALGLIB QP Solver. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetquadraticterm(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets dense quadratic term for QP solver. By default, quadratic term is zero. SUPPORT BY ALGLIB QP ALGORITHMS: Dense quadratic term can be handled by any of the QP algorithms supported by ALGLIB QP Solver. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a) { alglib_impl::ae_state _alglib_env_state; bool isupper; if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) throw ap_error("'a' parameter is not symmetric matrix"); isupper = false; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetquadraticterm(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets sparse quadratic term for QP solver. By default, quadratic term is zero. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadratictermsparse(const minqpstate &state, const sparsematrix &a, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetquadratictermsparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets starting point for QP solver. It is useful to have good initial approximation to the solution, because it will increase speed of convergence and identification of active constraints. INPUT PARAMETERS: State - structure which stores algorithm state X - starting point, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetstartingpoint(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets origin for QP solver. By default, following QP program is solved: min(0.5*x'*A*x+b'*x) This function allows to solve different problem: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) INPUT PARAMETERS: State - structure which stores algorithm state XOrigin - origin, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetorigin(const_cast(state.c_ptr()), const_cast(xorigin.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function BLEIC-based QP solver uses scale for two purposes: * to evaluate stopping conditions * for preconditioning of the underlying BLEIC solver INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetscale(const minqpstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function tells solver to use Cholesky-based algorithm. This algorithm was deprecated in ALGLIB 3.9.0 because its performance is inferior to that of BLEIC-QP or QuickQP on high-dimensional problems. Furthermore, it supports only dense convex QP problems. This solver is no longer active by default. We recommend you to switch to BLEIC-QP or QuickQP solver. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgocholesky(const minqpstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetalgocholesky(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function tells solver to use BLEIC-based algorithm and sets stopping criteria for the algorithm. ALGORITHM FEATURES: * supports dense and sparse QP problems * supports boundary and general linear equality/inequality constraints * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". Of course, global minimum is found only for positive definite and semidefinite problems. As for indefinite ones - only local minimum is found. ALGORITHM OUTLINE: * BLEIC-QP solver is just a driver function for MinBLEIC solver; it solves quadratic programming problem as general linearly constrained optimization problem, which is solved by means of BLEIC solver (part of ALGLIB, active set method). ALGORITHM LIMITATIONS: * unlike QuickQP solver, this algorithm does not perform Newton steps and does not use Level 3 BLAS. Being general-purpose active set method, it can activate constraints only one-by-one. Thus, its performance is lower than that of QuickQP. * its precision is also a bit inferior to that of QuickQP. BLEIC-QP performs only LBFGS steps (no Newton steps), which are good at detecting neighborhood of the solution, buy need many iterations to find solution with more than 6 digits of precision. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. NOTE: this algorithm uses LBFGS iterations, which are relatively cheap, but improve function value only a bit. So you will need many iterations to converge - from 0.1*N to 10*N, depending on problem's condition number. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgobleic(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetalgobleic(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function tells solver to use QuickQP algorithm: special extra-fast algorithm for problems with boundary-only constrants. It may solve non-convex problems as long as they are bounded from below under constraints. ALGORITHM FEATURES: * many times (from 5x to 50x!) faster than BLEIC-based QP solver; utilizes accelerated methods for activation of constraints. * supports dense and sparse QP problems * supports ONLY boundary constraints; general linear constraints are NOT supported by this solver * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". In convex/semidefinite case global minimum is returned, in nonconvex case - algorithm returns one of the local minimums. ALGORITHM OUTLINE: * algorithm performs two kinds of iterations: constrained CG iterations and constrained Newton iterations * initially it performs small number of constrained CG iterations, which can efficiently activate/deactivate multiple constraints * after CG phase algorithm tries to calculate Cholesky decomposition and to perform several constrained Newton steps. If Cholesky decomposition failed (matrix is indefinite even under constraints), we perform more CG iterations until we converge to such set of constraints that system matrix becomes positive definite. Constrained Newton steps greatly increase convergence speed and precision. * algorithm interleaves CG and Newton iterations which allows to handle indefinite matrices (CG phase) and quickly converge after final set of constraints is found (Newton phase). Combination of CG and Newton phases is called "outer iteration". * it is possible to turn off Newton phase (beneficial for semidefinite problems - Cholesky decomposition will fail too often) ALGORITHM LIMITATIONS: * algorithm does not support general linear constraints; only boundary ones are supported * Cholesky decomposition for sparse problems is performed with Skyline Cholesky solver, which is intended for low-profile matrices. No profile- reducing reordering of variables is performed in this version of ALGLIB. * problems with near-zero negative eigenvalues (or exacty zero ones) may experience about 2-3x performance penalty. The reason is that Cholesky decomposition can not be performed until we identify directions of zero and negative curvature and activate corresponding boundary constraints - but we need a lot of trial and errors because these directions are hard to notice in the matrix spectrum. In this case you may turn off Newton phase of algorithm. Large negative eigenvalues are not an issue, so highly non-convex problems can be solved very efficiently. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxOuterIts-maximum number of OUTER iterations. One outer iteration includes some amount of CG iterations (from 5 to ~N) and one or several (usually small amount) Newton steps. Thus, one outer iteration has high cost, but can greatly reduce funcation value. UseNewton- use Newton phase or not: * Newton phase improves performance of positive definite dense problems (about 2 times improvement can be observed) * can result in some performance penalty on semidefinite or slightly negative definite problems - each Newton phase will bring no improvement (Cholesky failure), but still will require computational time. * if you doubt, you can turn off this phase - optimizer will retain its most of its high speed. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 22.05.2014 by Bochkanov Sergey *************************************************************************/ void minqpsetalgoquickqp(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxouterits, const bool usenewton) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetalgoquickqp(const_cast(state.c_ptr()), epsg, epsf, epsx, maxouterits, usenewton, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints for QP solver Boundary constraints are inactive by default (after initial creation). After being set, they are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for QP optimizer. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - structure previously allocated with MinQPCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately - there always exists some minor violation (about 10^-10...10^-13) due to numerical errors. -- ALGLIB -- Copyright 19.06.2012 by Bochkanov Sergey *************************************************************************/ void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for QP optimizer. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - structure previously allocated with MinQPCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately - there always exists some minor violation (about 10^-10...10^-13) due to numerical errors. -- ALGLIB -- Copyright 19.06.2012 by Bochkanov Sergey *************************************************************************/ void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; if( (c.rows()!=ct.length())) throw ap_error("Error while calling 'minqpsetlc': looks like one of arguments has wrong size"); k = c.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function solves quadratic programming problem. Prior to calling this function you should choose solver by means of one of the following functions: * MinQPSetAlgoQuickQP() - for QuickQP solver * MinQPSetAlgoBLEIC() - for BLEIC-QP solver These functions also allow you to control stopping criteria of the solver. If you did not set solver, MinQP subpackage will automatically select solver for your problem and will run it with default stopping criteria. However, it is better to set explicitly solver and its stopping criteria. INPUT PARAMETERS: State - algorithm state You should use MinQPResults() function to access results after calls to this function. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey. Special thanks to Elvira Illarionova for important suggestions on the linearly constrained QP algorithm. *************************************************************************/ void minqpoptimize(const minqpstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpoptimize(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* QP solver results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution. This array is allocated and initialized only when Rep.TerminationType parameter is positive (success). Rep - optimization report. You should check Rep.TerminationType, which contains completion code, and you may check another fields which contain another information about algorithm functioning. Failure codes returned by algorithm are: * -5 inappropriate solver was used: * Cholesky solver for (semi)indefinite problems * Cholesky solver for problems with sparse matrix * QuickQP solver for problem with general linear constraints * -4 BLEIC-QP/QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or maybe feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. Completion codes specific for Cholesky algorithm: * 4 successful completion Completion codes specific for BLEIC/QuickQP algorithms: * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* QP results Buffered implementation of MinQPResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minqpresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Levenberg-Marquardt optimizer. This structure should be created using one of the MinLMCreate???() functions. You should not access its fields directly; use ALGLIB functions to work with it. *************************************************************************/ _minlmstate_owner::_minlmstate_owner() { p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlmstate_init(p_struct, NULL); } _minlmstate_owner::_minlmstate_owner(const _minlmstate_owner &rhs) { p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minlmstate_owner& _minlmstate_owner::operator=(const _minlmstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minlmstate_clear(p_struct); alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minlmstate_owner::~_minlmstate_owner() { alglib_impl::_minlmstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minlmstate* _minlmstate_owner::c_ptr() { return p_struct; } alglib_impl::minlmstate* _minlmstate_owner::c_ptr() const { return const_cast(p_struct); } minlmstate::minlmstate() : _minlmstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x) { } minlmstate::minlmstate(const minlmstate &rhs):_minlmstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x) { } minlmstate& minlmstate::operator=(const minlmstate &rhs) { if( this==&rhs ) return *this; _minlmstate_owner::operator=(rhs); return *this; } minlmstate::~minlmstate() { } /************************************************************************* Optimization report, filled by MinLMResults() function FIELDS: * TerminationType, completetion code: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called MinLMRequestTermination(). X contains point which was "current accepted" when termination request was submitted. * IterationsCount, contains iterations count * NFunc, number of function calculations * NJac, number of Jacobi matrix calculations * NGrad, number of gradient calculations * NHess, number of Hessian calculations * NCholesky, number of Cholesky decomposition calculations *************************************************************************/ _minlmreport_owner::_minlmreport_owner() { p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlmreport_init(p_struct, NULL); } _minlmreport_owner::_minlmreport_owner(const _minlmreport_owner &rhs) { p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minlmreport_owner& _minlmreport_owner::operator=(const _minlmreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minlmreport_clear(p_struct); alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minlmreport_owner::~_minlmreport_owner() { alglib_impl::_minlmreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minlmreport* _minlmreport_owner::c_ptr() { return p_struct; } alglib_impl::minlmreport* _minlmreport_owner::c_ptr() const { return const_cast(p_struct); } minlmreport::minlmreport() : _minlmreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),funcidx(p_struct->funcidx),varidx(p_struct->varidx),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) { } minlmreport::minlmreport(const minlmreport &rhs):_minlmreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),funcidx(p_struct->funcidx),varidx(p_struct->varidx),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) { } minlmreport& minlmreport::operator=(const minlmreport &rhs) { if( this==&rhs ) return *this; _minlmreport_owner::operator=(rhs); return *this; } minlmreport::~minlmreport() { } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] and Jacobian of f[]. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X * function vector f[] and Jacobian of f[] (simultaneously) at given point There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() and jac() callbacks. First one is used to calculate f[] at given point, second one calculates f[] and Jacobian df[i]/dx[j]. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not provide Jacobian), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateVJ() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatevj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] and Jacobian of f[]. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X * function vector f[] and Jacobian of f[] (simultaneously) at given point There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() and jac() callbacks. First one is used to calculate f[] at given point, second one calculates f[] and Jacobian df[i]/dx[j]. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not provide Jacobian), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateVJ() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatevj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] only. Finite differences are used to calculate Jacobian. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() callback. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not accept function vector), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateV() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state See also MinLMIteration, MinLMResults. NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatev(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] only. Finite differences are used to calculate Jacobian. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() callback. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not accept function vector), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateV() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state See also MinLMIteration, MinLMResults. NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatev(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION DESCRIPTION: This function is used to find minimum of general form (not "sum-of- -squares") function F = F(x[0], ..., x[n-1]) using its gradient and Hessian. Levenberg-Marquardt modification with L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step is used. REQUIREMENTS: This algorithm will request following information during its operation: * function value F at given point X * F and gradient G (simultaneously) at given point X * F, G and Hessian H (simultaneously) at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts func(), grad() and hess() function pointers. First pointer is used to calculate F at given point, second one calculates F(x) and grad F(x), third one calculates F(x), grad F(x), hess F(x). You can try to initialize MinLMState structure with FGH-function and then use incorrect version of MinLMOptimize() (for example, version which does not provide Hessian matrix), but it will lead to exception being thrown after first attempt to calculate Hessian. USAGE: 1. User initializes algorithm state with MinLMCreateFGH() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and pointers (delegates, etc.) to callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefgh(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION DESCRIPTION: This function is used to find minimum of general form (not "sum-of- -squares") function F = F(x[0], ..., x[n-1]) using its gradient and Hessian. Levenberg-Marquardt modification with L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step is used. REQUIREMENTS: This algorithm will request following information during its operation: * function value F at given point X * F and gradient G (simultaneously) at given point X * F, G and Hessian H (simultaneously) at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts func(), grad() and hess() function pointers. First pointer is used to calculate F at given point, second one calculates F(x) and grad F(x), third one calculates F(x), grad F(x), hess F(x). You can try to initialize MinLMState structure with FGH-function and then use incorrect version of MinLMOptimize() (for example, version which does not provide Hessian matrix), but it will lead to exception being thrown after first attempt to calculate Hessian. USAGE: 1. User initializes algorithm state with MinLMCreateFGH() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and pointers (delegates, etc.) to callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgh(const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefgh(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for Levenberg-Marquardt optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLMSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS iterations are reported. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetxrep(const minlmstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetstpmax(const minlmstate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for LM optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetscale(const minlmstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints for LM optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints or at its boundary -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is used to change acceleration settings You can choose between three acceleration strategies: * AccType=0, no acceleration. * AccType=1, secant updates are used to update quadratic model after each iteration. After fixed number of iterations (or after model breakdown) we recalculate quadratic model using analytic Jacobian or finite differences. Number of secant-based iterations depends on optimization settings: about 3 iterations - when we have analytic Jacobian, up to 2*N iterations - when we use finite differences to calculate Jacobian. AccType=1 is recommended when Jacobian calculation cost is prohibitive high (several Mx1 function vector calculations followed by several NxN Cholesky factorizations are faster than calculation of one M*N Jacobian). It should also be used when we have no Jacobian, because finite difference approximation takes too much time to compute. Table below list optimization protocols (XYZ protocol corresponds to MinLMCreateXYZ) and acceleration types they support (and use by default). ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: protocol 0 1 comment V + + VJ + + FGH + DAFAULT VALUES: protocol 0 1 comment V x without acceleration it is so slooooooooow VJ x FGH x NOTE: this function should be called before optimization. Attempt to call it during algorithm iterations may result in unexpected behavior. NOTE: attempt to call this function with unsupported protocol/acceleration combination will result in exception being thrown. -- ALGLIB -- Copyright 14.10.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetacctype(const minlmstate &state, const ae_int_t acctype) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetacctype(const_cast(state.c_ptr()), acctype, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minlmiteration(const minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minlmiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( fvec==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfi ) { fvec(state.x, state.fi, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( fvec==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)"); if( jac==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfi ) { fvec(state.x, state.fi, ptr); continue; } if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); if( grad==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)"); if( hess==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (hess is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.needfgh ) { hess(state.x, state.f, state.g, state.h, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); if( jac==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( func==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); if( grad==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)"); if( jac==NULL ) throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needf ) { func(state.x, state.f, ptr); continue; } if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Levenberg-Marquardt algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report; includes termination codes and additional information. Termination codes are listed below, see comments for this structure for more info. Termination code is stored in rep.terminationtype field: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlmrequesttermination(). X contains point which was "current accepted" when termination request was submitted. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Levenberg-Marquardt algorithm results Buffered implementation of MinLMResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts LM algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinLMCreateXXX call. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlmrestartfrom(const minlmstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlmrequesttermination(const minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmrequesttermination(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatevgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatevgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is considered obsolete since ALGLIB 3.1.0 and is present for backward compatibility only. We recommend to use MinLMCreateVJ, which provides similar, but more consistent and feature-rich interface. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function is considered obsolete since ALGLIB 3.1.0 and is present for backward compatibility only. We recommend to use MinLMCreateVJ, which provides similar, but more consistent and feature-rich interface. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmcreatefj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLMOptimize() is called * prior to actual optimization, for each function Fi and each component of parameters being optimized X[j] algorithm performs following steps: * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], where X[j] is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on X[] * Fi(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) Jacobian evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLMSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minlmsetgradientcheck(const minlmstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlmsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* *************************************************************************/ _minasastate_owner::_minasastate_owner() { p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minasastate_init(p_struct, NULL); } _minasastate_owner::_minasastate_owner(const _minasastate_owner &rhs) { p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minasastate_owner& _minasastate_owner::operator=(const _minasastate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minasastate_clear(p_struct); alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minasastate_owner::~_minasastate_owner() { alglib_impl::_minasastate_clear(p_struct); ae_free(p_struct); } alglib_impl::minasastate* _minasastate_owner::c_ptr() { return p_struct; } alglib_impl::minasastate* _minasastate_owner::c_ptr() const { return const_cast(p_struct); } minasastate::minasastate() : _minasastate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minasastate::minasastate(const minasastate &rhs):_minasastate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) { } minasastate& minasastate::operator=(const minasastate &rhs) { if( this==&rhs ) return *this; _minasastate_owner::operator=(rhs); return *this; } minasastate::~minasastate() { } /************************************************************************* *************************************************************************/ _minasareport_owner::_minasareport_owner() { p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minasareport_init(p_struct, NULL); } _minasareport_owner::_minasareport_owner(const _minasareport_owner &rhs) { p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minasareport_owner& _minasareport_owner::operator=(const _minasareport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minasareport_clear(p_struct); alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minasareport_owner::~_minasareport_owner() { alglib_impl::_minasareport_clear(p_struct); ae_free(p_struct); } alglib_impl::minasareport* _minasareport_owner::c_ptr() { return p_struct; } alglib_impl::minasareport* _minasareport_owner::c_ptr() const { return const_cast(p_struct); } minasareport::minasareport() : _minasareport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) { } minasareport::minasareport(const minasareport &rhs):_minasareport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) { } minasareport& minasareport::operator=(const minasareport &rhs) { if( this==&rhs ) return *this; _minasareport_owner::operator=(rhs); return *this; } minasareport::~minasareport() { } /************************************************************************* Obsolete function, use MinLBFGSSetPrecDefault() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetdefaultpreconditioner(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minlbfgssetcholeskypreconditioner(const_cast(state.c_ptr()), const_cast(p.c_ptr()), isupper, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierwidth(const minbleicstate &state, const double mu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetbarrierwidth(const_cast(state.c_ptr()), mu, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minbleicsetbarrierdecay(const_cast(state.c_ptr()), mudecay, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasacreate(n, const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; if( (x.length()!=bndl.length()) || (x.length()!=bndu.length())) throw ap_error("Error while calling 'minasacreate': looks like one of arguments has wrong size"); n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasacreate(n, const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasasetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetxrep(const minasastate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasasetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetalgorithm(const minasastate &state, const ae_int_t algotype) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasasetalgorithm(const_cast(state.c_ptr()), algotype, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetstpmax(const minasastate &state, const double stpmax) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasasetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minasaiteration(const minasastate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minasaiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minasaoptimize(minasastate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( grad==NULL ) throw ap_error("ALGLIB: error in 'minasaoptimize()' (grad is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfg ) { grad(state.x, state.f, state.g, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasaresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasaresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minasarestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNLC subpackage to work with this object *************************************************************************/ _minnlcstate_owner::_minnlcstate_owner() { p_struct = (alglib_impl::minnlcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnlcstate_init(p_struct, NULL); } _minnlcstate_owner::_minnlcstate_owner(const _minnlcstate_owner &rhs) { p_struct = (alglib_impl::minnlcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnlcstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minnlcstate_owner& _minnlcstate_owner::operator=(const _minnlcstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minnlcstate_clear(p_struct); alglib_impl::_minnlcstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minnlcstate_owner::~_minnlcstate_owner() { alglib_impl::_minnlcstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minnlcstate* _minnlcstate_owner::c_ptr() { return p_struct; } alglib_impl::minnlcstate* _minnlcstate_owner::c_ptr() const { return const_cast(p_struct); } minnlcstate::minnlcstate() : _minnlcstate_owner() ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } minnlcstate::minnlcstate(const minnlcstate &rhs):_minnlcstate_owner(rhs) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } minnlcstate& minnlcstate::operator=(const minnlcstate &rhs) { if( this==&rhs ) return *this; _minnlcstate_owner::operator=(rhs); return *this; } minnlcstate::~minnlcstate() { } /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. Other fields of this structure are not documented and should not be used! *************************************************************************/ _minnlcreport_owner::_minnlcreport_owner() { p_struct = (alglib_impl::minnlcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnlcreport_init(p_struct, NULL); } _minnlcreport_owner::_minnlcreport_owner(const _minnlcreport_owner &rhs) { p_struct = (alglib_impl::minnlcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnlcreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minnlcreport_owner& _minnlcreport_owner::operator=(const _minnlcreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minnlcreport_clear(p_struct); alglib_impl::_minnlcreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minnlcreport_owner::~_minnlcreport_owner() { alglib_impl::_minnlcreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minnlcreport* _minnlcreport_owner::c_ptr() { return p_struct; } alglib_impl::minnlcreport* _minnlcreport_owner::c_ptr() const { return const_cast(p_struct); } minnlcreport::minnlcreport() : _minnlcreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),funcidx(p_struct->funcidx),terminationtype(p_struct->terminationtype),dbgphase0its(p_struct->dbgphase0its) { } minnlcreport::minnlcreport(const minnlcreport &rhs):_minnlcreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),funcidx(p_struct->funcidx),terminationtype(p_struct->terminationtype),dbgphase0its(p_struct->dbgphase0its) { } minnlcreport& minnlcreport::operator=(const minnlcreport &rhs) { if( this==&rhs ) return *this; _minnlcreport_owner::operator=(rhs); return *this; } minnlcreport::~minnlcreport() { } /************************************************************************* NONLINEARLY CONSTRAINED OPTIMIZATION WITH PRECONDITIONED AUGMENTED LAGRANGIAN ALGORITHM DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 REQUIREMENTS: * user must provide function value and gradient for F(), H(), G() * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are twice continuously differentiable on the feasible set and its neighborhood * nonlinear constraints G() and H() must have non-zero gradient at G(x)=0 and at H(x)=0. Say, constraint like x^2>=1 is supported, but x^2>=0 is NOT supported. USAGE: Constrained optimization if far more complex than the unconstrained one. Nonlinearly constrained optimization is one of the most esoteric numerical procedures. Here we give very brief outline of the MinNLC optimizer. We strongly recommend you to study examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinNLCCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AUL solver (activated with MinNLCSetAlgoAUL() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNLCSetBC() for boundary constraints b) MinNLCSetLC() for linear constraints c) MinNLCSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNLCSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNLCSetCond(). If NLC solver uses inner/outer iteration layout, this function sets stopping conditions for INNER iterations. 5. User chooses one of the preconditioning methods. Preconditioning is very important for efficient handling of boundary/linear/nonlinear constraints. Without preconditioning algorithm would require thousands of iterations even for simple problems. Two preconditioners can be used: * approximate LBFGS-based preconditioner which should be used for problems with almost orthogonal constraints (activated by calling MinNLCSetPrecInexact) * exact low-rank preconditiner (activated by MinNLCSetPrecExactLowRank) which should be used for problems with moderate number of constraints which do not have to be orthogonal. 6. Finally, user calls MinNLCOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G/H. 7. User calls MinNLCResults() to get solution 8. Optionally user may call MinNLCRestartFrom() to solve another problem with same N but another starting point. MinNLCRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreate(const ae_int_t n, const real_1d_array &x, minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NONLINEARLY CONSTRAINED OPTIMIZATION WITH PRECONDITIONED AUGMENTED LAGRANGIAN ALGORITHM DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 REQUIREMENTS: * user must provide function value and gradient for F(), H(), G() * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are twice continuously differentiable on the feasible set and its neighborhood * nonlinear constraints G() and H() must have non-zero gradient at G(x)=0 and at H(x)=0. Say, constraint like x^2>=1 is supported, but x^2>=0 is NOT supported. USAGE: Constrained optimization if far more complex than the unconstrained one. Nonlinearly constrained optimization is one of the most esoteric numerical procedures. Here we give very brief outline of the MinNLC optimizer. We strongly recommend you to study examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinNLCCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AUL solver (activated with MinNLCSetAlgoAUL() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNLCSetBC() for boundary constraints b) MinNLCSetLC() for linear constraints c) MinNLCSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNLCSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNLCSetCond(). If NLC solver uses inner/outer iteration layout, this function sets stopping conditions for INNER iterations. 5. User chooses one of the preconditioning methods. Preconditioning is very important for efficient handling of boundary/linear/nonlinear constraints. Without preconditioning algorithm would require thousands of iterations even for simple problems. Two preconditioners can be used: * approximate LBFGS-based preconditioner which should be used for problems with almost orthogonal constraints (activated by calling MinNLCSetPrecInexact) * exact low-rank preconditiner (activated by MinNLCSetPrecExactLowRank) which should be used for problems with moderate number of constraints which do not have to be orthogonal. 6. Finally, user calls MinNLCOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G/H. 7. User calls MinNLCResults() to get solution 8. Optionally user may call MinNLCRestartFrom() to solve another problem with same N but another starting point. MinNLCRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreate(const real_1d_array &x, minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine is a finite difference variant of MinNLCCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinNLCCreate() in order to get more information about creation of NLC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinNLCSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large TRUNCATION errors, while too small step will result in too large NUMERICAL errors. 1.0E-4 can be good value to start from. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine is a finite difference variant of MinNLCCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinNLCCreate() in order to get more information about creation of NLC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinNLCSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large TRUNCATION errors, while too small step will result in too large NUMERICAL errors. 1.0E-4 can be good value to start from. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreatef(const real_1d_array &x, const double diffstep, minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints for NLC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine boundary constraints with general linear ones - and with nonlinear ones! Boundary constraints are handled more efficiently than other types. Thus, if your problem has mixed constraints, you may explicitly specify some of them as boundary and save some time/space. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: when you solve your problem with augmented Lagrangian solver, boundary constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetbc(const minnlcstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for MinNLC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine linear constraints with boundary ones - and with nonlinear ones! If your problem has mixed constraints, you may explicitly specify some of them as linear. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: when you solve your problem with augmented Lagrangian solver, linear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetlc(const minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints for MinNLC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine linear constraints with boundary ones - and with nonlinear ones! If your problem has mixed constraints, you may explicitly specify some of them as linear. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: when you solve your problem with augmented Lagrangian solver, linear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetlc(const minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; if( (c.rows()!=ct.length())) throw ap_error("Error while calling 'minnlcsetlc': looks like one of arguments has wrong size"); k = c.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets nonlinear constraints for MinNLC optimizer. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to MinNLCOptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] corresponds to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: when you solve your problem with augmented Lagrangian solver, nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! NOTE 2: algorithm scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetnlc(const minnlcstate &state, const ae_int_t nlec, const ae_int_t nlic) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetnlc(const_cast(state.c_ptr()), nlec, nlic, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for inner iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinNLCSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetcond(const minnlcstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetscale(const minnlcstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets preconditioner to "inexact LBFGS-based" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss LBFGS-based preconditioner. Inexact LBFGS-based preconditioner uses L-BFGS formula combined with orthogonality assumption to perform very fast updates. For a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K) cost per iteration. This preconditioner has best quality (less iterations) when general linear and nonlinear constraints are orthogonal to each other (orthogonality with respect to boundary constraints is not required). Number of iterations increases when constraints are non-orthogonal, because algorithm assumes orthogonality, but still it is better than no preconditioner at all. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecinexact(const minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetprecinexact(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets preconditioner to "exact low rank" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss low rank preconditioner. Exact low-rank preconditioner uses Woodbury matrix identity to build quadratic model of the penalized function. It has no special assumptions about orthogonality, so it is quite general. However, for a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K^2) cost per iteration (for comparison: inexact LBFGS-based preconditioner has O(N*K) cost). INPUT PARAMETERS: State - structure stores algorithm state UpdateFreq- update frequency. Preconditioner is rebuilt after every UpdateFreq iterations. Recommended value: 10 or higher. Zero value means that good default value will be used. -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecexactlowrank(const minnlcstate &state, const ae_int_t updatefreq) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetprecexactlowrank(const_cast(state.c_ptr()), updatefreq, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets preconditioner to "turned off" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. This function activates this test mode. Do not use it in production code to solve real-life problems. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecnone(const minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetprecnone(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function tells MinNLC unit to use Augmented Lagrangian algorithm for nonlinearly constrained optimization. This algorithm is a slight modification of one described in "A Modified Barrier-Augmented Lagrangian Method for Constrained Minimization (1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH. Augmented Lagrangian algorithm works by converting problem of minimizing F(x) subject to equality/inequality constraints to unconstrained problem of the form min[ f(x) + + Rho*PENALTY_EQ(x) + SHIFT_EQ(x,Nu1) + + Rho*PENALTY_INEQ(x) + SHIFT_INEQ(x,Nu2) ] where: * Rho is a fixed penalization coefficient * PENALTY_EQ(x) is a penalty term, which is used to APPROXIMATELY enforce equality constraints * SHIFT_EQ(x) is a special "shift" term which is used to "fine-tune" equality constraints, greatly increasing precision * PENALTY_INEQ(x) is a penalty term which is used to approximately enforce inequality constraints * SHIFT_INEQ(x) is a special "shift" term which is used to "fine-tune" inequality constraints, greatly increasing precision * Nu1/Nu2 are vectors of Lagrange coefficients which are fine-tuned during outer iterations of algorithm This version of AUL algorithm uses preconditioner, which greatly accelerates convergence. Because this algorithm is similar to penalty methods, it may perform steps into infeasible area. All kinds of constraints (boundary, linear and nonlinear ones) may be violated in intermediate points - and in the solution. However, properly configured AUL method is significantly better at handling constraints than barrier and/or penalty methods. The very basic outline of algorithm is given below: 1) first outer iteration is performed with "default" values of Lagrange multipliers Nu1/Nu2. Solution quality is low (candidate point can be too far away from true solution; large violation of constraints is possible) and is comparable with that of penalty methods. 2) subsequent outer iterations refine Lagrange multipliers and improve quality of the solution. INPUT PARAMETERS: State - structure which stores algorithm state Rho - penalty coefficient, Rho>0: * large enough that algorithm converges with desired precision. Minimum value is 10*max(S'*diag(H)*S), where S is a scale matrix (set by MinNLCSetScale) and H is a Hessian of the function being minimized. If you can not easily estimate Hessian norm, see our recommendations below. * not TOO large to prevent ill-conditioning * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * it is important to note that Rho is internally multiplied by scaling matrix, i.e. optimum value of Rho depends on scale of variables specified by MinNLCSetScale(). ItsCnt - number of outer iterations: * ItsCnt=0 means that small number of outer iterations is automatically chosen (10 iterations in current version). * ItsCnt=1 means that AUL algorithm performs just as usual barrier method. * ItsCnt>1 means that AUL algorithm performs specified number of outer iterations HOW TO CHOOSE PARAMETERS Nonlinear optimization is a tricky area and Augmented Lagrangian algorithm is sometimes hard to tune. Good values of Rho and ItsCnt are problem- specific. In order to help you we prepared following set of recommendations: * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * start from some small value of Rho and solve problem with just one outer iteration (ItcCnt=1). In this case algorithm behaves like penalty method. Increase Rho in 2x or 10x steps until you see that one outer iteration returns point which is "rough approximation to solution". It is very important to have Rho so large that penalty term becomes constraining i.e. modified function becomes highly convex in constrained directions. From the other side, too large Rho may prevent you from converging to the solution. You can diagnose it by studying number of inner iterations performed by algorithm: too few (5-10 on 1000-dimensional problem) or too many (orders of magnitude more than dimensionality) usually means that Rho is too large. * with just one outer iteration you usually have low-quality solution. Some constraints can be violated with very large margin, while other ones (which are NOT violated in the true solution) can push final point too far in the inner area of the feasible set. For example, if you have constraint x0>=0 and true solution x0=1, then merely a presence of "x0>=0" will introduce a bias towards larger values of x0. Say, algorithm may stop at x0=1.5 instead of 1.0. * after you found good Rho, you may increase number of outer iterations. ItsCnt=10 is a good value. Subsequent outer iteration will refine values of Lagrange multipliers. Constraints which were violated will be enforced, inactive constraints will be dropped (corresponding multipliers will be decreased). Ideally, you should see 10-1000x improvement in constraint handling (constraint violation is reduced). * if you see that algorithm converges to vicinity of solution, but additional outer iterations do not refine solution, it may mean that algorithm is unstable - it wanders around true solution, but can not approach it. Sometimes algorithm may be stabilized by increasing Rho one more time, making it 5x or 10x larger. SCALING OF CONSTRAINTS [IMPORTANT] AUL optimizer scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, because function being optimized is a mix of original function and constraint-dependent penalty functions, it is important to rescale both variables AND constraints. Say, if you minimize f(x)=x^2 subject to 1000000*x>=0, then you have constraint whose scale is different from that of target function (another example is 0.000001*x>=0). It is also possible to have constraints whose scales are misaligned: 1000000*x0>=0, 0.000001*x1<=0. Inappropriate scaling may ruin convergence because minimizing x^2 subject to x>=0 is NOT same as minimizing it subject to 1000000*x>=0. Because we know coefficients of boundary/linear constraints, we can automatically rescale and normalize them. However, there is no way to automatically rescale nonlinear constraints Gi(x) and Hi(x) - they are black boxes. It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to rescale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). WHAT IF IT DOES NOT CONVERGE? It is possible that AUL algorithm fails to converge to precise values of Lagrange multipliers. It stops somewhere around true solution, but candidate point is still too far from solution, and some constraints are violated. Such kind of failure is specific for Lagrangian algorithms - technically, they stop at some point, but this point is not constrained solution. There are exist several reasons why algorithm may fail to converge: a) too loose stopping criteria for inner iteration b) degenerate, redundant constraints c) target function has unconstrained extremum exactly at the boundary of some constraint d) numerical noise in the target function In all these cases algorithm is unstable - each outer iteration results in large and almost random step which improves handling of some constraints, but violates other ones (ideally outer iterations should form a sequence of progressively decreasing steps towards solution). First reason possible is that too loose stopping criteria for inner iteration were specified. Augmented Lagrangian algorithm solves a sequence of intermediate problems, and requries each of them to be solved with high precision. Insufficient precision results in incorrect update of Lagrange multipliers. Another reason is that you may have specified degenerate constraints: say, some constraint was repeated twice. In most cases AUL algorithm gracefully handles such situations, but sometimes it may spend too much time figuring out subtle degeneracies in constraint matrix. Third reason is tricky and hard to diagnose. Consider situation when you minimize f=x^2 subject to constraint x>=0. Unconstrained extremum is located exactly at the boundary of constrained area. In this case algorithm will tend to oscillate between negative and positive x. Each time it stops at x<0 it "reinforces" constraint x>=0, and each time it is bounced to x>0 it "relaxes" constraint (and is attracted to x<0). Such situation sometimes happens in problems with hidden symetries. Algorithm is got caught in a loop with Lagrange multipliers being continuously increased/decreased. Luckily, such loop forms after at least three iterations, so this problem can be solved by DECREASING number of outer iterations down to 1-2 and increasing penalty coefficient Rho as much as possible. Final reason is numerical noise. AUL algorithm is robust against moderate noise (more robust than, say, active set methods), but large noise may destabilize algorithm. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetalgoaul(const minnlcstate &state, const double rho, const ae_int_t itscnt) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetalgoaul(const_cast(state.c_ptr()), rho, itscnt, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinNLCOptimize(). NOTE: algorithm passes two parameters to rep() callback - current point and penalized function value at current point. Important - function value which is returned is NOT function being minimized. It is sum of the value of the function being minimized - and penalty term. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcsetxrep(const minnlcstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minnlciteration(const minnlcstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minnlciteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minnlcoptimize(minnlcstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( fvec==NULL ) throw ap_error("ALGLIB: error in 'minnlcoptimize()' (fvec is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfi ) { fvec(state.x, state.fi, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minnlcoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minnlcoptimize(minnlcstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( jac==NULL ) throw ap_error("ALGLIB: error in 'minnlcoptimize()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minnlcoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* MinNLC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken More information about fields of this structure can be found in the comments on MinNLCReport datatype. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcresults(const minnlcstate &state, real_1d_array &x, minnlcreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NLC results Buffered implementation of MinNLCResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcresultsbuf(const minnlcstate &state, real_1d_array &x, minnlcreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcrestartfrom(const minnlcstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinNLCOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, and Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinNLCSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetgradientcheck(const minnlcstate &state, const double teststep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnlcsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNS subpackage to work with this object *************************************************************************/ _minnsstate_owner::_minnsstate_owner() { p_struct = (alglib_impl::minnsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnsstate_init(p_struct, NULL); } _minnsstate_owner::_minnsstate_owner(const _minnsstate_owner &rhs) { p_struct = (alglib_impl::minnsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsstate), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minnsstate_owner& _minnsstate_owner::operator=(const _minnsstate_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minnsstate_clear(p_struct); alglib_impl::_minnsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minnsstate_owner::~_minnsstate_owner() { alglib_impl::_minnsstate_clear(p_struct); ae_free(p_struct); } alglib_impl::minnsstate* _minnsstate_owner::c_ptr() { return p_struct; } alglib_impl::minnsstate* _minnsstate_owner::c_ptr() const { return const_cast(p_struct); } minnsstate::minnsstate() : _minnsstate_owner() ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } minnsstate::minnsstate(const minnsstate &rhs):_minnsstate_owner(rhs) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) { } minnsstate& minnsstate::operator=(const minnsstate &rhs) { if( this==&rhs ) return *this; _minnsstate_owner::operator=(rhs); return *this; } minnsstate::~minnsstate() { } /************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) * CErr maximum violation of all types of constraints * LCErr maximum violation of linear constraints * NLCErr maximum violation of nonlinear constraints TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -3 box constraints are inconsistent -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() 2 sampling radius decreased below epsx 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 User requested termination via MinNSRequestTermination() Other fields of this structure are not documented and should not be used! *************************************************************************/ _minnsreport_owner::_minnsreport_owner() { p_struct = (alglib_impl::minnsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnsreport_init(p_struct, NULL); } _minnsreport_owner::_minnsreport_owner(const _minnsreport_owner &rhs) { p_struct = (alglib_impl::minnsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsreport), NULL); if( p_struct==NULL ) throw ap_error("ALGLIB: malloc error"); alglib_impl::_minnsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); } _minnsreport_owner& _minnsreport_owner::operator=(const _minnsreport_owner &rhs) { if( this==&rhs ) return *this; alglib_impl::_minnsreport_clear(p_struct); alglib_impl::_minnsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL); return *this; } _minnsreport_owner::~_minnsreport_owner() { alglib_impl::_minnsreport_clear(p_struct); ae_free(p_struct); } alglib_impl::minnsreport* _minnsreport_owner::c_ptr() { return p_struct; } alglib_impl::minnsreport* _minnsreport_owner::c_ptr() const { return const_cast(p_struct); } minnsreport::minnsreport() : _minnsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),cerr(p_struct->cerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),varidx(p_struct->varidx),funcidx(p_struct->funcidx) { } minnsreport::minnsreport(const minnsreport &rhs):_minnsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),cerr(p_struct->cerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),varidx(p_struct->varidx),funcidx(p_struct->funcidx) { } minnsreport& minnsreport::operator=(const minnsreport &rhs) { if( this==&rhs ) return *this; _minnsreport_owner::operator=(rhs); return *this; } minnsreport::~minnsreport() { } /************************************************************************* NONSMOOTH NONCONVEX OPTIMIZATION SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 IMPORTANT: see MinNSSetAlgoAGS for important information on performance restrictions of AGS solver. REQUIREMENTS: * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are continuous, locally Lipschitz and continuously (but not necessarily twice) differentiable in an open dense subset of R^N. Functions F(), G() and H() may be nonsmooth and non-convex. Informally speaking, it means that functions are composed of large differentiable "patches" with nonsmoothness having place only at the boundaries between these "patches". Most real-life nonsmooth functions satisfy these requirements. Say, anything which involves finite number of abs(), min() and max() is very likely to pass the test. Say, it is possible to optimize anything of the following: * f=abs(x0)+2*abs(x1) * f=max(x0,x1) * f=sin(max(x0,x1)+abs(x2)) * for nonlinearly constrained problems: F() must be bounded from below without nonlinear constraints (this requirement is due to the fact that, contrary to box and linear constraints, nonlinear ones require special handling). * user must provide function value and gradient for F(), H(), G() at all points where function/gradient can be calculated. If optimizer requires value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), where gradient is not defined, user may resolve tie arbitrarily (in our case - return +1 or -1 at its discretion). * NS solver supports numerical differentiation, i.e. it may differentiate your function for you, but it results in 2N increase of function evaluations. Not recommended unless you solve really small problems. See minnscreatef() for more information on this functionality. USAGE: 1. User initializes algorithm state with MinNSCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AGS solver (activated with MinNSSetAlgoAGS() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNSSetBC() for boundary constraints b) MinNSSetLC() for linear constraints c) MinNSSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNSSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNSSetCond(). 5. Finally, user calls MinNSOptimize() function which takes algorithm state and pointer (delegate, etc) to callback function which calculates F/G/H. 7. User calls MinNSResults() to get solution 8. Optionally user may call MinNSRestartFrom() to solve another problem with same N but another starting point. MinNSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state NOTE: minnscreatef() function may be used if you do not have analytic gradient. This function creates solver which uses numerical differentiation with user-specified step. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreate(const ae_int_t n, const real_1d_array &x, minnsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnscreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* NONSMOOTH NONCONVEX OPTIMIZATION SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 IMPORTANT: see MinNSSetAlgoAGS for important information on performance restrictions of AGS solver. REQUIREMENTS: * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are continuous, locally Lipschitz and continuously (but not necessarily twice) differentiable in an open dense subset of R^N. Functions F(), G() and H() may be nonsmooth and non-convex. Informally speaking, it means that functions are composed of large differentiable "patches" with nonsmoothness having place only at the boundaries between these "patches". Most real-life nonsmooth functions satisfy these requirements. Say, anything which involves finite number of abs(), min() and max() is very likely to pass the test. Say, it is possible to optimize anything of the following: * f=abs(x0)+2*abs(x1) * f=max(x0,x1) * f=sin(max(x0,x1)+abs(x2)) * for nonlinearly constrained problems: F() must be bounded from below without nonlinear constraints (this requirement is due to the fact that, contrary to box and linear constraints, nonlinear ones require special handling). * user must provide function value and gradient for F(), H(), G() at all points where function/gradient can be calculated. If optimizer requires value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), where gradient is not defined, user may resolve tie arbitrarily (in our case - return +1 or -1 at its discretion). * NS solver supports numerical differentiation, i.e. it may differentiate your function for you, but it results in 2N increase of function evaluations. Not recommended unless you solve really small problems. See minnscreatef() for more information on this functionality. USAGE: 1. User initializes algorithm state with MinNSCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AGS solver (activated with MinNSSetAlgoAGS() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNSSetBC() for boundary constraints b) MinNSSetLC() for linear constraints c) MinNSSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNSSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNSSetCond(). 5. Finally, user calls MinNSOptimize() function which takes algorithm state and pointer (delegate, etc) to callback function which calculates F/G/H. 7. User calls MinNSResults() to get solution 8. Optionally user may call MinNSRestartFrom() to solve another problem with same N but another starting point. MinNSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state NOTE: minnscreatef() function may be used if you do not have analytic gradient. This function creates solver which uses numerical differentiation with user-specified step. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreate(const real_1d_array &x, minnsstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnscreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Version of minnscreatef() which uses numerical differentiation. I.e., you do not have to calculate derivatives yourself. However, this version needs 2N times more function evaluations. 2-point differentiation formula is used, because more precise 4-point formula is unstable when used on non-smooth functions. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, DiffStep>0. Algorithm performs numerical differentiation with step for I-th variable being equal to DiffStep*S[I] (here S[] is a scale vector, set by minnssetscale() function). Do not use too small steps, because it may lead to catastrophic cancellation during intermediate calculations. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnscreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Version of minnscreatef() which uses numerical differentiation. I.e., you do not have to calculate derivatives yourself. However, this version needs 2N times more function evaluations. 2-point differentiation formula is used, because more precise 4-point formula is unstable when used on non-smooth functions. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, DiffStep>0. Algorithm performs numerical differentiation with step for I-th variable being equal to DiffStep*S[I] (here S[] is a scale vector, set by minnssetscale() function). Do not use too small steps, because it may lead to catastrophic cancellation during intermediate calculations. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreatef(const real_1d_array &x, const double diffstep, minnsstate &state) { alglib_impl::ae_state _alglib_env_state; ae_int_t n; n = x.length(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnscreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets boundary constraints. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: AGS solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetbc(const minnsstate &state, const real_1d_array &bndl, const real_1d_array &bndu) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about current sampling radius in magnitude during optimization, about EpsX in the solution) due to use of penalty method to handle constraints. * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetlc(const minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets linear constraints. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about current sampling radius in magnitude during optimization, about EpsX in the solution) due to use of penalty method to handle constraints. * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetlc(const minnsstate &state, const real_2d_array &c, const integer_1d_array &ct) { alglib_impl::ae_state _alglib_env_state; ae_int_t k; if( (c.rows()!=ct.length())) throw ap_error("Error while calling 'minnssetlc': looks like one of arguments has wrong size"); k = c.rows(); alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets nonlinear constraints. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to minnsoptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] correspond to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of the feasible area! NOTE 2: algorithm scales variables according to scale specified by minnssetscale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by minnssetscale() function). NOTE 3: nonlinear constraints are always hard to handle, no matter what algorithm you try to use. Even basic box/linear constraints modify function curvature by adding valleys and ridges. However, nonlinear constraints add valleys which are very hard to follow due to their "curved" nature. It means that optimization with single nonlinear constraint may be significantly slower than optimization with multiple linear ones. It is normal situation, and we recommend you to carefully choose Rho parameter of minnssetalgoags(), because too large value may slow down convergence. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetnlc(const minnsstate &state, const ae_int_t nlec, const ae_int_t nlic) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetnlc(const_cast(state.c_ptr()), nlec, nlic, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets stopping conditions for iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsX - >=0 The AGS solver finishes its work if on k+1-th iteration sampling radius decreases below EpsX. MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. We do not recommend you to rely on default choice in production code. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetcond(const minnsstate &state, const double epsx, const ae_int_t maxits) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetcond(const_cast(state.c_ptr()), epsx, maxits, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetscale(const minnsstate &state, const real_1d_array &s) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function tells MinNS unit to use AGS (adaptive gradient sampling) algorithm for nonsmooth constrained optimization. This algorithm is a slight modification of one described in "An Adaptive Gradient Sampling Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. This optimizer has following benefits and drawbacks: + robustness; it can be used with nonsmooth and nonconvex functions. + relatively easy tuning; most of the metaparameters are easy to select. - it has convergence of steepest descent, slower than CG/LBFGS. - each iteration involves evaluation of ~2N gradient values and solution of 2Nx2N quadratic programming problem, which limits applicability of algorithm by small-scale problems (up to 50-100). IMPORTANT: this algorithm has convergence guarantees, i.e. it will steadily move towards some stationary point of the function. However, "stationary point" does not always mean "solution". Nonsmooth problems often have "flat spots", i.e. areas where function do not change at all. Such "flat spots" are stationary points by definition, and algorithm may be caught here. Nonsmooth CONVEX tasks are not prone to this problem. Say, if your function has form f()=MAX(f0,f1,...), and f_i are convex, then f() is convex too and you have guaranteed convergence to solution. INPUT PARAMETERS: State - structure which stores algorithm state Radius - initial sampling radius, >=0. Internally multiplied by vector of per-variable scales specified by minnssetscale()). You should select relatively large sampling radius, roughly proportional to scaled length of the first steps of the algorithm. Something close to 0.1 in magnitude should be good for most problems. AGS solver can automatically decrease radius, so too large radius is not a problem (assuming that you won't choose so large radius that algorithm will sample function in too far away points, where gradient value is irrelevant). Too small radius won't cause algorithm to fail, but it may slow down algorithm (it may have to perform too short steps). Penalty - penalty coefficient for nonlinear constraints: * for problem with nonlinear constraints should be some problem-specific positive value, large enough that penalty term changes shape of the function. Starting from some problem-specific value penalty coefficient becomes large enough to exactly enforce nonlinear constraints; larger values do not improve precision. Increasing it too much may slow down convergence, so you should choose it carefully. * can be zero for problems WITHOUT nonlinear constraints (i.e. for unconstrained ones or ones with just box or linear constraints) * if you specify zero value for problem with at least one nonlinear constraint, algorithm will terminate with error code -1. ALGORITHM OUTLINE The very basic outline of unconstrained AGS algorithm is given below: 0. If sampling radius is below EpsX or we performed more then MaxIts iterations - STOP. 1. sample O(N) gradient values at random locations around current point; informally speaking, this sample is an implicit piecewise linear model of the function, although algorithm formulation does not mention that explicitly 2. solve quadratic programming problem in order to find descent direction 3. if QP solver tells us that we are near solution, decrease sampling radius and move to (0) 4. perform backtracking line search 5. after moving to new point, goto (0) As for the constraints: * box constraints are handled exactly by modification of the function being minimized * linear/nonlinear constraints are handled by adding L1 penalty. Because our solver can handle nonsmoothness, we can use L1 penalty function, which is an exact one (i.e. exact solution is returned under such penalty). * penalty coefficient for linear constraints is chosen automatically; however, penalty coefficient for nonlinear constraints must be specified by user. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetalgoags(const minnsstate &state, const double radius, const double penalty) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetalgoags(const_cast(state.c_ptr()), radius, penalty, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to minnsoptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnssetxrep(const minnsstate &state, const bool needxrep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnssetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrequesttermination(const minnsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnsrequesttermination(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ bool minnsiteration(const minnsstate &state) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { ae_bool result = alglib_impl::minnsiteration(const_cast(state.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return *(reinterpret_cast(&result)); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minnsoptimize(minnsstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( fvec==NULL ) throw ap_error("ALGLIB: error in 'minnsoptimize()' (fvec is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minnsiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfi ) { fvec(state.x, state.fi, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minnsoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } void minnsoptimize(minnsstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr), void *ptr) { alglib_impl::ae_state _alglib_env_state; if( jac==NULL ) throw ap_error("ALGLIB: error in 'minnsoptimize()' (jac is NULL)"); alglib_impl::ae_state_init(&_alglib_env_state); try { while( alglib_impl::minnsiteration(state.c_ptr(), &_alglib_env_state) ) { if( state.needfij ) { jac(state.x, state.fi, state.j, ptr); continue; } if( state.xupdated ) { if( rep!=NULL ) rep(state.x, state.f, ptr); continue; } throw ap_error("ALGLIB: error in 'minnsoptimize' (some derivatives were not provided?)"); } alglib_impl::ae_state_clear(&_alglib_env_state); } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* MinNS results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -3 box constraints are inconsistent * -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() * 2 sampling radius decreased below epsx * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. * 8 User requested termination via minnsrequesttermination() -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresults(const minnsstate &state, real_1d_array &x, minnsreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnsresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* Buffered implementation of minnsresults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresultsbuf(const minnsstate &state, real_1d_array &x, minnsreport &rep) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnsresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. X - new starting point. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrestartfrom(const minnsstate &state, const real_1d_array &x) { alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_state_init(&_alglib_env_state); try { alglib_impl::minnsrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); return; } catch(alglib_impl::ae_error_type) { throw ap_error(_alglib_env_state.error_msg); } } } ///////////////////////////////////////////////////////////////////////// // // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE // ///////////////////////////////////////////////////////////////////////// namespace alglib_impl { static ae_int_t cqmodels_newtonrefinementits = 3; static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, ae_state *_state); static void cqmodels_cqmsolveea(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* tmp, ae_state *_state); static void snnls_funcgradu(snnlssolver* s, /* Real */ ae_vector* x, /* Real */ ae_vector* r, /* Real */ ae_vector* g, double* f, ae_state *_state); static void snnls_func(snnlssolver* s, /* Real */ ae_vector* x, double* f, ae_state *_state); static void snnls_trdprepare(snnlssolver* s, /* Real */ ae_vector* x, /* Real */ ae_vector* diag, double lambdav, /* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, /* Real */ ae_vector* tmp0, /* Real */ ae_vector* tmp1, /* Real */ ae_vector* tmp2, /* Real */ ae_matrix* tmplq, ae_state *_state); static void snnls_trdsolve(/* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, ae_int_t ns, ae_int_t nd, /* Real */ ae_vector* d, ae_state *_state); static void snnls_trdfixvariable(/* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, ae_int_t ns, ae_int_t nd, ae_int_t idx, /* Real */ ae_vector* tmp, ae_state *_state); static void sactivesets_constraineddescent(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* h, /* Real */ ae_matrix* ha, ae_bool normalize, /* Real */ ae_vector* d, ae_state *_state); static void sactivesets_reactivateconstraints(sactiveset* state, /* Real */ ae_vector* gc, /* Real */ ae_vector* h, ae_state *_state); static ae_int_t mincg_rscountdownlen = 10; static double mincg_gtol = 0.3; static void mincg_clearrequestfields(mincgstate* state, ae_state *_state); static void mincg_preconditionedmultiply(mincgstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* work0, /* Real */ ae_vector* work1, ae_state *_state); static double mincg_preconditionedmultiply2(mincgstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* work0, /* Real */ ae_vector* work1, ae_state *_state); static void mincg_mincginitinternal(ae_int_t n, double diffstep, mincgstate* state, ae_state *_state); static double minbleic_gtol = 0.4; static double minbleic_maxnonmonotoniclen = 1.0E-5; static double minbleic_initialdecay = 0.5; static double minbleic_mindecay = 0.1; static double minbleic_decaycorrection = 0.8; static double minbleic_penaltyfactor = 100; static void minbleic_clearrequestfields(minbleicstate* state, ae_state *_state); static void minbleic_minbleicinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minbleicstate* state, ae_state *_state); static void minbleic_updateestimateofgoodstep(double* estimate, double newstep, ae_state *_state); static double minlbfgs_gtol = 0.4; static void minlbfgs_clearrequestfields(minlbfgsstate* state, ae_state *_state); static ae_int_t qqpsolver_quickqprestartcg = 50; static double qqpsolver_penaltyfactor = 50.0; static double qqpsolver_regz = 1.0E-9; static double qqpsolver_projectedtargetfunction(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* d, double stp, /* Real */ ae_vector* tmp0, ae_state *_state); static void qqpsolver_targetgradient(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state); static void qqpsolver_quadraticmodel(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* d, /* Real */ ae_vector* g, double* d1, ae_int_t* d1est, double* d2, ae_int_t* d2est, ae_state *_state); static void qqpsolver_findbeststepandmove(qqpbuffers* sstate, sactiveset* sas, /* Real */ ae_vector* d, double stp, ae_bool needact, ae_int_t cidx, double cval, /* Real */ ae_vector* addsteps, ae_int_t addstepscnt, /* Boolean */ ae_vector* activated, /* Real */ ae_vector* tmp0, ae_state *_state); static ae_bool qqpsolver_cnewtonbuild(qqpbuffers* sstate, ae_int_t sparsesolver, ae_int_t* ncholesky, ae_state *_state); static ae_bool qqpsolver_cnewtonupdate(qqpbuffers* sstate, qqpsettings* settings, ae_int_t* ncupdates, ae_state *_state); static ae_bool qqpsolver_cnewtonstep(qqpbuffers* sstate, qqpsettings* settings, /* Real */ ae_vector* gc, ae_state *_state); static ae_int_t qpcholeskysolver_maxlagrangeits = 10; static ae_int_t qpcholeskysolver_maxbadnewtonits = 7; static double qpcholeskysolver_penaltyfactor = 100.0; static double qpcholeskysolver_modelvalue(convexquadraticmodel* a, /* Real */ ae_vector* b, /* Real */ ae_vector* xc, ae_int_t n, /* Real */ ae_vector* tmp, ae_state *_state); static ae_int_t qpcholeskysolver_boundedstepandactivation(sactiveset* sas, /* Real */ ae_vector* xn, ae_int_t n, /* Real */ ae_vector* buf, ae_state *_state); static ae_bool qpcholeskysolver_constrainedoptimum(sactiveset* sas, convexquadraticmodel* a, double anorm, /* Real */ ae_vector* b, /* Real */ ae_vector* xn, ae_int_t n, /* Real */ ae_vector* tmp, /* Boolean */ ae_vector* tmpb, /* Real */ ae_vector* lagrangec, ae_state *_state); static double minlm_lambdaup = 2.0; static double minlm_lambdadown = 0.33; static double minlm_suspiciousnu = 16; static ae_int_t minlm_smallmodelage = 3; static ae_int_t minlm_additers = 5; static void minlm_lmprepare(ae_int_t n, ae_int_t m, ae_bool havegrad, minlmstate* state, ae_state *_state); static void minlm_clearrequestfields(minlmstate* state, ae_state *_state); static ae_bool minlm_increaselambda(double* lambdav, double* nu, ae_state *_state); static void minlm_decreaselambda(double* lambdav, double* nu, ae_state *_state); static double minlm_boundedscaledantigradnorm(minlmstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state); static ae_int_t mincomp_n1 = 2; static ae_int_t mincomp_n2 = 2; static double mincomp_stpmin = 1.0E-300; static double mincomp_gtol = 0.3; static double mincomp_gpaftol = 0.0001; static double mincomp_gpadecay = 0.5; static double mincomp_asarho = 0.5; static double mincomp_asaboundedantigradnorm(minasastate* state, ae_state *_state); static double mincomp_asaginorm(minasastate* state, ae_state *_state); static double mincomp_asad1norm(minasastate* state, ae_state *_state); static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state); static void mincomp_clearrequestfields(minasastate* state, ae_state *_state); static double minnlc_aulmaxgrowth = 10.0; static ae_int_t minnlc_lbfgsfactor = 10; static double minnlc_hessesttol = 1.0E-6; static void minnlc_clearrequestfields(minnlcstate* state, ae_state *_state); static void minnlc_minnlcinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnlcstate* state, ae_state *_state); static void minnlc_clearpreconditioner(minlbfgsstate* auloptimizer, ae_state *_state); static void minnlc_updatepreconditioner(ae_int_t prectype, ae_int_t updatefreq, ae_int_t* preccounter, minlbfgsstate* auloptimizer, /* Real */ ae_vector* x, double rho, double gammak, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* hasbndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* hasbndu, /* Real */ ae_vector* nubc, /* Real */ ae_matrix* cleic, /* Real */ ae_vector* nulc, /* Real */ ae_vector* fi, /* Real */ ae_matrix* jac, /* Real */ ae_vector* nunlc, /* Real */ ae_vector* bufd, /* Real */ ae_vector* bufc, /* Real */ ae_matrix* bufw, ae_int_t n, ae_int_t nec, ae_int_t nic, ae_int_t ng, ae_int_t nh, ae_state *_state); static void minnlc_penaltybc(/* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* hasbndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* hasbndu, /* Real */ ae_vector* nubc, ae_int_t n, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state); static void minnlc_penaltylc(/* Real */ ae_vector* x, /* Real */ ae_matrix* cleic, /* Real */ ae_vector* nulc, ae_int_t n, ae_int_t nec, ae_int_t nic, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state); static void minnlc_penaltynlc(/* Real */ ae_vector* fi, /* Real */ ae_matrix* j, /* Real */ ae_vector* nunlc, ae_int_t n, ae_int_t ng, ae_int_t nh, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state); static ae_bool minnlc_auliteration(minnlcstate* state, ae_state *_state); static void minns_clearrequestfields(minnsstate* state, ae_state *_state); static void minns_minnsinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnsstate* state, ae_state *_state); static ae_bool minns_agsiteration(minnsstate* state, ae_state *_state); static void minns_generatemeritfunction(minnsstate* state, ae_int_t sampleidx, ae_state *_state); static void minns_unscalepointbc(minnsstate* state, /* Real */ ae_vector* x, ae_state *_state); static void minns_solveqp(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, ae_int_t* dbgncholesky, minnsqp* state, ae_state *_state); static void minns_qpcalculategradfunc(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, /* Real */ ae_vector* g, double* f, /* Real */ ae_vector* tmp, ae_state *_state); static void minns_qpcalculatefunc(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, double* f, /* Real */ ae_vector* tmp, ae_state *_state); static void minns_qpsolveu(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); static void minns_qpsolveut(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); /************************************************************************* This subroutine is used to prepare threshold value which will be used for trimming of the target function (see comments on TrimFunction() for more information). This function accepts only one parameter: function value at the starting point. It returns threshold which will be used for trimming. -- ALGLIB -- Copyright 10.05.2011 by Bochkanov Sergey *************************************************************************/ void trimprepare(double f, double* threshold, ae_state *_state) { *threshold = 0; *threshold = 10*(ae_fabs(f, _state)+1); } /************************************************************************* This subroutine is used to "trim" target function, i.e. to do following transformation: { {F,G} if F=Threshold Such transformation allows us to solve problems with singularities by redefining function in such way that it becomes bounded from above. -- ALGLIB -- Copyright 10.05.2011 by Bochkanov Sergey *************************************************************************/ void trimfunction(double* f, /* Real */ ae_vector* g, ae_int_t n, double threshold, ae_state *_state) { ae_int_t i; if( ae_fp_greater_eq(*f,threshold) ) { *f = threshold; for(i=0; i<=n-1; i++) { g->ptr.p_double[i] = 0.0; } } } /************************************************************************* This function enforces boundary constraints in the X. This function correctly (although a bit inefficient) handles BL[i] which are -INF and BU[i] which are +INF. We have NMain+NSlack dimensional X, with first NMain components bounded by BL/BU, and next NSlack ones bounded by non-negativity constraints. INPUT PARAMETERS X - array[NMain+NSlack], point BL - array[NMain], lower bounds (may contain -INF, when bound is not present) HaveBL - array[NMain], if HaveBL[i] is False, then i-th bound is not present BU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBU - array[NMain], if HaveBU[i] is False, then i-th bound is not present OUTPUT PARAMETERS X - X with all constraints being enforced It returns True when constraints are consistent, False - when constraints are inconsistent. -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, /* Real */ ae_vector* bl, /* Boolean */ ae_vector* havebl, /* Real */ ae_vector* bu, /* Boolean */ ae_vector* havebu, ae_int_t nmain, ae_int_t nslack, ae_state *_state) { ae_int_t i; ae_bool result; result = ae_false; for(i=0; i<=nmain-1; i++) { if( (havebl->ptr.p_bool[i]&&havebu->ptr.p_bool[i])&&ae_fp_greater(bl->ptr.p_double[i],bu->ptr.p_double[i]) ) { return result; } if( havebl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bl->ptr.p_double[i]) ) { x->ptr.p_double[i] = bl->ptr.p_double[i]; } if( havebu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bu->ptr.p_double[i]) ) { x->ptr.p_double[i] = bu->ptr.p_double[i]; } } for(i=0; i<=nslack-1; i++) { if( ae_fp_less(x->ptr.p_double[nmain+i],(double)(0)) ) { x->ptr.p_double[nmain+i] = (double)(0); } } result = ae_true; return result; } /************************************************************************* This function projects gradient into feasible area of boundary constrained optimization problem. X can be infeasible with respect to boundary constraints. We have NMain+NSlack dimensional X, with first NMain components bounded by BL/BU, and next NSlack ones bounded by non-negativity constraints. INPUT PARAMETERS X - array[NMain+NSlack], point G - array[NMain+NSlack], gradient BL - lower bounds (may contain -INF, when bound is not present) HaveBL - if HaveBL[i] is False, then i-th bound is not present BU - upper bounds (may contain +INF, when bound is not present) HaveBU - if HaveBU[i] is False, then i-th bound is not present OUTPUT PARAMETERS G - projection of G. Components of G which satisfy one of the following (1) (X[I]<=BndL[I]) and (G[I]>0), OR (2) (X[I]>=BndU[I]) and (G[I]<0) are replaced by zeros. NOTE 1: this function assumes that constraints are feasible. It throws exception otherwise. NOTE 2: in fact, projection of ANTI-gradient is calculated, because this function trims components of -G which points outside of the feasible area. However, working with -G is considered confusing, because all optimization source work with G. -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ void projectgradientintobc(/* Real */ ae_vector* x, /* Real */ ae_vector* g, /* Real */ ae_vector* bl, /* Boolean */ ae_vector* havebl, /* Real */ ae_vector* bu, /* Boolean */ ae_vector* havebu, ae_int_t nmain, ae_int_t nslack, ae_state *_state) { ae_int_t i; for(i=0; i<=nmain-1; i++) { ae_assert((!havebl->ptr.p_bool[i]||!havebu->ptr.p_bool[i])||ae_fp_less_eq(bl->ptr.p_double[i],bu->ptr.p_double[i]), "ProjectGradientIntoBC: internal error (infeasible constraints)", _state); if( (havebl->ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],bl->ptr.p_double[i]))&&ae_fp_greater(g->ptr.p_double[i],(double)(0)) ) { g->ptr.p_double[i] = (double)(0); } if( (havebu->ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],bu->ptr.p_double[i]))&&ae_fp_less(g->ptr.p_double[i],(double)(0)) ) { g->ptr.p_double[i] = (double)(0); } } for(i=0; i<=nslack-1; i++) { if( ae_fp_less_eq(x->ptr.p_double[nmain+i],(double)(0))&&ae_fp_greater(g->ptr.p_double[nmain+i],(double)(0)) ) { g->ptr.p_double[nmain+i] = (double)(0); } } } /************************************************************************* Given a) initial point X0[NMain+NSlack] (feasible with respect to bound constraints) b) step vector alpha*D[NMain+NSlack] c) boundary constraints BndL[NMain], BndU[NMain] d) implicit non-negativity constraints for slack variables this function calculates bound on the step length subject to boundary constraints. It returns: * MaxStepLen - such step length that X0+MaxStepLen*alpha*D is exactly at the boundary given by constraints * VariableToFreeze - index of the constraint to be activated, 0 <= VariableToFreeze < NMain+NSlack * ValueToFreeze - value of the corresponding constraint. Notes: * it is possible that several constraints can be activated by the step at once. In such cases only one constraint is returned. It is caller responsibility to check other constraints. This function makes sure that we activate at least one constraint, and everything else is the responsibility of the caller. * steps smaller than MaxStepLen still can activate constraints due to numerical errors. Thus purpose of this function is not to guard against accidental activation of the constraints - quite the reverse, its purpose is to activate at least constraint upon performing step which is too long. * in case there is no constraints to activate, we return negative VariableToFreeze and zero MaxStepLen and ValueToFreeze. * this function assumes that constraints are consistent; it throws exception otherwise. INPUT PARAMETERS X - array[NMain+NSlack], point. Must be feasible with respect to bound constraints (exception will be thrown otherwise) D - array[NMain+NSlack], step direction alpha - scalar multiplier before D, alpha<>0 BndL - lower bounds, array[NMain] (may contain -INF, when bound is not present) HaveBndL - array[NMain], if HaveBndL[i] is False, then i-th bound is not present BndU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBndU - array[NMain], if HaveBndU[i] is False, then i-th bound is not present NMain - number of main variables NSlack - number of slack variables OUTPUT PARAMETERS VariableToFreeze: * negative value = step is unbounded, ValueToFreeze=0, MaxStepLen=0. * non-negative value = at least one constraint, given by this parameter, will be activated upon performing maximum step. ValueToFreeze- value of the variable which will be constrained MaxStepLen - maximum length of the step. Can be zero when step vector looks outside of the feasible area. -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ void calculatestepbound(/* Real */ ae_vector* x, /* Real */ ae_vector* d, double alpha, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_int_t* variabletofreeze, double* valuetofreeze, double* maxsteplen, ae_state *_state) { ae_int_t i; double prevmax; double initval; *variabletofreeze = 0; *valuetofreeze = 0; *maxsteplen = 0; ae_assert(ae_fp_neq(alpha,(double)(0)), "CalculateStepBound: zero alpha", _state); *variabletofreeze = -1; initval = ae_maxrealnumber; *maxsteplen = initval; for(i=0; i<=nmain-1; i++) { if( havebndl->ptr.p_bool[i]&&ae_fp_less(alpha*d->ptr.p_double[i],(double)(0)) ) { ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); prevmax = *maxsteplen; *maxsteplen = safeminposrv(x->ptr.p_double[i]-bndl->ptr.p_double[i], -alpha*d->ptr.p_double[i], *maxsteplen, _state); if( ae_fp_less(*maxsteplen,prevmax) ) { *variabletofreeze = i; *valuetofreeze = bndl->ptr.p_double[i]; } } if( havebndu->ptr.p_bool[i]&&ae_fp_greater(alpha*d->ptr.p_double[i],(double)(0)) ) { ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); prevmax = *maxsteplen; *maxsteplen = safeminposrv(bndu->ptr.p_double[i]-x->ptr.p_double[i], alpha*d->ptr.p_double[i], *maxsteplen, _state); if( ae_fp_less(*maxsteplen,prevmax) ) { *variabletofreeze = i; *valuetofreeze = bndu->ptr.p_double[i]; } } } for(i=0; i<=nslack-1; i++) { if( ae_fp_less(alpha*d->ptr.p_double[nmain+i],(double)(0)) ) { ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],(double)(0)), "CalculateStepBound: infeasible X", _state); prevmax = *maxsteplen; *maxsteplen = safeminposrv(x->ptr.p_double[nmain+i], -alpha*d->ptr.p_double[nmain+i], *maxsteplen, _state); if( ae_fp_less(*maxsteplen,prevmax) ) { *variabletofreeze = nmain+i; *valuetofreeze = (double)(0); } } } if( ae_fp_eq(*maxsteplen,initval) ) { *valuetofreeze = (double)(0); *maxsteplen = (double)(0); } } /************************************************************************* This function postprocesses bounded step by: * analysing step length (whether it is equal to MaxStepLen) and activating constraint given by VariableToFreeze if needed * checking for additional bound constraints to activate This function uses final point of the step, quantities calculated by the CalculateStepBound() function. As result, it returns point which is exactly feasible with respect to boundary constraints. NOTE 1: this function does NOT handle and check linear equality constraints NOTE 2: when StepTaken=MaxStepLen we always activate at least one constraint INPUT PARAMETERS X - array[NMain+NSlack], final point to postprocess XPrev - array[NMain+NSlack], initial point BndL - lower bounds, array[NMain] (may contain -INF, when bound is not present) HaveBndL - array[NMain], if HaveBndL[i] is False, then i-th bound is not present BndU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBndU - array[NMain], if HaveBndU[i] is False, then i-th bound is not present NMain - number of main variables NSlack - number of slack variables VariableToFreeze-result of CalculateStepBound() ValueToFreeze- result of CalculateStepBound() StepTaken - actual step length (actual step is equal to the possibly non-unit step direction vector times this parameter). StepTaken<=MaxStepLen. MaxStepLen - result of CalculateStepBound() OUTPUT PARAMETERS X - point bounded with respect to constraints. components corresponding to active constraints are exactly equal to the boundary values. RESULT: number of constraints activated in addition to previously active ones. Constraints which were DEACTIVATED are ignored (do not influence function value). -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, /* Real */ ae_vector* xprev, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_int_t variabletofreeze, double valuetofreeze, double steptaken, double maxsteplen, ae_state *_state) { ae_int_t i; ae_bool wasactivated; ae_int_t result; ae_assert(variabletofreeze<0||ae_fp_less_eq(steptaken,maxsteplen), "Assertion failed", _state); /* * Activate constraints */ if( variabletofreeze>=0&&ae_fp_eq(steptaken,maxsteplen) ) { x->ptr.p_double[variabletofreeze] = valuetofreeze; } for(i=0; i<=nmain-1; i++) { if( havebndl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) { x->ptr.p_double[i] = bndl->ptr.p_double[i]; } if( havebndu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) { x->ptr.p_double[i] = bndu->ptr.p_double[i]; } } for(i=0; i<=nslack-1; i++) { if( ae_fp_less_eq(x->ptr.p_double[nmain+i],(double)(0)) ) { x->ptr.p_double[nmain+i] = (double)(0); } } /* * Calculate number of constraints being activated */ result = 0; for(i=0; i<=nmain-1; i++) { wasactivated = ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i])&&((havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]))); wasactivated = wasactivated||variabletofreeze==i; if( wasactivated ) { result = result+1; } } for(i=0; i<=nslack-1; i++) { wasactivated = ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&ae_fp_eq(x->ptr.p_double[nmain+i],0.0); wasactivated = wasactivated||variabletofreeze==nmain+i; if( wasactivated ) { result = result+1; } } return result; } /************************************************************************* The purpose of this function is to prevent algorithm from "unsticking" from the active bound constraints because of numerical noise in the gradient or Hessian. It is done by zeroing some components of the search direction D. D[i] is zeroed when both (a) and (b) are true: a) corresponding X[i] is exactly at the boundary b) |D[i]*S[i]| <= DropTol*Sqrt(SUM(D[i]^2*S[I]^2)) D can be step direction , antigradient, gradient, or anything similar. Sign of D does not matter, nor matters step length. NOTE 1: boundary constraints are expected to be consistent, as well as X is expected to be feasible. Exception will be thrown otherwise. INPUT PARAMETERS D - array[NMain+NSlack], direction X - array[NMain+NSlack], current point BndL - lower bounds, array[NMain] (may contain -INF, when bound is not present) HaveBndL - array[NMain], if HaveBndL[i] is False, then i-th bound is not present BndU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBndU - array[NMain], if HaveBndU[i] is False, then i-th bound is not present S - array[NMain+NSlack], scaling of the variables NMain - number of main variables NSlack - number of slack variables DropTol - drop tolerance, >=0 OUTPUT PARAMETERS X - point bounded with respect to constraints. components corresponding to active constraints are exactly equal to the boundary values. -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ void filterdirection(/* Real */ ae_vector* d, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, /* Real */ ae_vector* s, ae_int_t nmain, ae_int_t nslack, double droptol, ae_state *_state) { ae_int_t i; double scalednorm; ae_bool isactive; scalednorm = 0.0; for(i=0; i<=nmain+nslack-1; i++) { scalednorm = scalednorm+ae_sqr(d->ptr.p_double[i]*s->ptr.p_double[i], _state); } scalednorm = ae_sqrt(scalednorm, _state); for(i=0; i<=nmain-1; i++) { ae_assert(!havebndl->ptr.p_bool[i]||ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "FilterDirection: infeasible point", _state); ae_assert(!havebndu->ptr.p_bool[i]||ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "FilterDirection: infeasible point", _state); isactive = (havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])); if( isactive&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[i]*s->ptr.p_double[i], _state),droptol*scalednorm) ) { d->ptr.p_double[i] = 0.0; } } for(i=0; i<=nslack-1; i++) { ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],(double)(0)), "FilterDirection: infeasible point", _state); if( ae_fp_eq(x->ptr.p_double[nmain+i],(double)(0))&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[nmain+i]*s->ptr.p_double[nmain+i], _state),droptol*scalednorm) ) { d->ptr.p_double[nmain+i] = 0.0; } } } /************************************************************************* This function returns number of bound constraints whose state was changed (either activated or deactivated) when making step from XPrev to X. Constraints are considered: * active - when we are exactly at the boundary * inactive - when we are not at the boundary You should note that antigradient direction is NOT taken into account when we make decions on the constraint status. INPUT PARAMETERS X - array[NMain+NSlack], final point. Must be feasible with respect to bound constraints. XPrev - array[NMain+NSlack], initial point. Must be feasible with respect to bound constraints. BndL - lower bounds, array[NMain] (may contain -INF, when bound is not present) HaveBndL - array[NMain], if HaveBndL[i] is False, then i-th bound is not present BndU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBndU - array[NMain], if HaveBndU[i] is False, then i-th bound is not present NMain - number of main variables NSlack - number of slack variables RESULT: number of constraints whose state was changed. -- ALGLIB -- Copyright 10.01.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t numberofchangedconstraints(/* Real */ ae_vector* x, /* Real */ ae_vector* xprev, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, ae_state *_state) { ae_int_t i; ae_bool statuschanged; ae_int_t result; result = 0; for(i=0; i<=nmain-1; i++) { if( ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i]) ) { statuschanged = ae_false; if( havebndl->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndl->ptr.p_double[i])) ) { statuschanged = ae_true; } if( havebndu->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndu->ptr.p_double[i])) ) { statuschanged = ae_true; } if( statuschanged ) { result = result+1; } } } for(i=0; i<=nslack-1; i++) { if( ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&(ae_fp_eq(x->ptr.p_double[nmain+i],(double)(0))||ae_fp_eq(xprev->ptr.p_double[nmain+i],(double)(0))) ) { result = result+1; } } return result; } /************************************************************************* This function finds feasible point of (NMain+NSlack)-dimensional problem subject to NMain explicit boundary constraints (some constraints can be omitted), NSlack implicit non-negativity constraints, K linear equality constraints. INPUT PARAMETERS X - array[NMain+NSlack], initial point. BndL - lower bounds, array[NMain] (may contain -INF, when bound is not present) HaveBndL - array[NMain], if HaveBndL[i] is False, then i-th bound is not present BndU - array[NMain], upper bounds (may contain +INF, when bound is not present) HaveBndU - array[NMain], if HaveBndU[i] is False, then i-th bound is not present NMain - number of main variables NSlack - number of slack variables CE - array[K,NMain+NSlack+1], equality constraints CE*x=b. Rows contain constraints, first NMain+NSlack columns contain coefficients before X[], last column contain right part. K - number of linear constraints EpsI - infeasibility (error in the right part) allowed in the solution OUTPUT PARAMETERS: X - feasible point or best infeasible point found before algorithm termination QPIts - number of QP iterations (for debug purposes) GPAIts - number of GPA iterations (for debug purposes) RESULT: True in case X is feasible, False - if it is infeasible. -- ALGLIB -- Copyright 20.01.2012 by Bochkanov Sergey *************************************************************************/ ae_bool findfeasiblepoint(/* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* havebndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* havebndu, ae_int_t nmain, ae_int_t nslack, /* Real */ ae_matrix* ce, ae_int_t k, double epsi, ae_int_t* qpits, ae_int_t* gpaits, ae_state *_state) { ae_frame _frame_block; ae_matrix _ce; ae_int_t i; ae_int_t j; ae_int_t idx0; ae_int_t idx1; ae_vector permx; ae_vector xn; ae_vector xa; ae_vector newtonstep; ae_vector g; ae_vector pg; ae_matrix a; double armijostep; double armijobeststep; double armijobestfeas; double v; double mx; double feaserr; double feaserr0; double feaserr1; double feasold; double feasnew; double pgnorm; double vn; double vd; double stp; ae_int_t vartofreeze; double valtofreeze; double maxsteplen; ae_bool werechangesinconstraints; ae_bool stage1isover; ae_bool converged; ae_vector activeconstraints; ae_vector tmpk; ae_vector colnorms; ae_int_t nactive; ae_int_t nfree; ae_int_t nsvd; ae_vector p1; ae_vector p2; apbuffers buf; ae_vector w; ae_vector s; ae_matrix u; ae_matrix vt; ae_int_t itscount; ae_int_t itswithintolerance; ae_int_t maxitswithintolerance; ae_int_t badits; ae_int_t maxbadits; ae_int_t gparuns; ae_int_t maxarmijoruns; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_ce, ce, _state); ce = &_ce; *qpits = 0; *gpaits = 0; ae_vector_init(&permx, 0, DT_REAL, _state); ae_vector_init(&xn, 0, DT_REAL, _state); ae_vector_init(&xa, 0, DT_REAL, _state); ae_vector_init(&newtonstep, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&pg, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&activeconstraints, 0, DT_REAL, _state); ae_vector_init(&tmpk, 0, DT_REAL, _state); ae_vector_init(&colnorms, 0, DT_REAL, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); _apbuffers_init(&buf, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); maxitswithintolerance = 3; maxbadits = 3; maxarmijoruns = 5; *qpits = 0; *gpaits = 0; /* * Initial enforcement of the feasibility with respect to boundary constraints * NOTE: after this block we assume that boundary constraints are consistent. */ if( !enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } if( k==0 ) { /* * No linear constraints, we can exit right now */ result = ae_true; ae_frame_leave(_state); return result; } /* * Scale rows of CE in such way that max(CE[i,0..nmain+nslack-1])=1 for any i=0..k-1 */ for(i=0; i<=k-1; i++) { v = 0.0; for(j=0; j<=nmain+nslack-1; j++) { v = ae_maxreal(v, ae_fabs(ce->ptr.pp_double[i][j], _state), _state); } if( ae_fp_neq(v,(double)(0)) ) { v = 1/v; ae_v_muld(&ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack), v); } } /* * Allocate temporaries */ ae_vector_set_length(&xn, nmain+nslack, _state); ae_vector_set_length(&xa, nmain+nslack, _state); ae_vector_set_length(&permx, nmain+nslack, _state); ae_vector_set_length(&g, nmain+nslack, _state); ae_vector_set_length(&pg, nmain+nslack, _state); ae_vector_set_length(&tmpk, k, _state); ae_matrix_set_length(&a, k, nmain+nslack, _state); ae_vector_set_length(&activeconstraints, nmain+nslack, _state); ae_vector_set_length(&newtonstep, nmain+nslack, _state); ae_vector_set_length(&s, nmain+nslack, _state); ae_vector_set_length(&colnorms, nmain+nslack, _state); for(i=0; i<=nmain+nslack-1; i++) { s.ptr.p_double[i] = 1.0; colnorms.ptr.p_double[i] = 0.0; for(j=0; j<=k-1; j++) { colnorms.ptr.p_double[i] = colnorms.ptr.p_double[i]+ae_sqr(ce->ptr.pp_double[j][i], _state); } } /* * K>0, we have linear equality constraints combined with bound constraints. * * Try to find feasible point as minimizer of the quadratic function * F(x) = 0.5*||CE*x-b||^2 = 0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b * subject to boundary constraints given by BL, BU and non-negativity of * the slack variables. BTW, we drop constant term because it does not * actually influences on the solution. * * Below we will assume that K>0. */ itswithintolerance = 0; badits = 0; itscount = 0; for(;;) { /* * Stage 0: check for exact convergence */ converged = ae_true; feaserr = (double)(0); for(i=0; i<=k-1; i++) { /* * Calculate: * * V - error in the right part * * MX - maximum term in the left part * * Terminate if error in the right part is not greater than 100*Eps*MX. * * IMPORTANT: we must perform check for non-strict inequality, i.e. to use <= instead of <. * it will allow us to easily handle situations with zero rows of CE. */ mx = (double)(0); v = -ce->ptr.pp_double[i][nmain+nslack]; for(j=0; j<=nmain+nslack-1; j++) { mx = ae_maxreal(mx, ae_fabs(ce->ptr.pp_double[i][j]*x->ptr.p_double[j], _state), _state); v = v+ce->ptr.pp_double[i][j]*x->ptr.p_double[j]; } feaserr = feaserr+ae_sqr(v, _state); converged = converged&&ae_fp_less_eq(ae_fabs(v, _state),100*ae_machineepsilon*mx); } feaserr = ae_sqrt(feaserr, _state); feaserr0 = feaserr; if( converged ) { result = ae_fp_less_eq(feaserr,epsi); ae_frame_leave(_state); return result; } /* * Stage 1: equality constrained quadratic programming * * * treat active bound constraints as equality ones (constraint is considered * active when we are at the boundary, independently of the antigradient direction) * * calculate unrestricted Newton step to point XM (which may be infeasible) * calculate MaxStepLen = largest step in direction of XM which retains feasibility. * * perform bounded step from X to XN: * a) XN=XM (if XM is feasible) * b) XN=X-MaxStepLen*(XM-X) (otherwise) * * X := XN * * if XM (Newton step subject to currently active constraints) was feasible, goto Stage 2 * * repeat Stage 1 * * NOTE 1: in order to solve constrained qudratic subproblem we will have to reorder * variables in such way that ones corresponding to inactive constraints will * be first, and active ones will be last in the list. CE and X are now * [ xi ] * separated into two parts: CE = [CEi CEa], x = [ ], where CEi/Xi correspond * [ xa ] * to INACTIVE constraints, and CEa/Xa correspond to the ACTIVE ones. * * Now, instead of F=0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b, we have * F(xi) = 0.5*(CEi*xi,CEi*xi) + (CEa*xa-b,CEi*xi) + (0.5*CEa*xa-b,CEa*xa). * Here xa is considered constant, i.e. we optimize with respect to xi, leaving xa fixed. * * We can solve it by performing SVD of CEi and calculating pseudoinverse of the * Hessian matrix. Of course, we do NOT calculate pseudoinverse explicitly - we * just use singular vectors to perform implicit multiplication by it. * */ for(;;) { /* * Calculate G - gradient subject to equality constraints, * multiply it by inverse of the Hessian diagonal to obtain initial * step vector. * * Bound step subject to constraints which can be activated, * run Armijo search with increasing step size. * Search is terminated when feasibility error stops to decrease. * * NOTE: it is important to test for "stops to decrease" instead * of "starts to increase" in order to correctly handle cases with * zero CE. */ armijobeststep = 0.0; armijobestfeas = 0.0; for(i=0; i<=nmain+nslack-1; i++) { g.ptr.p_double[i] = (double)(0); } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; armijobestfeas = armijobestfeas+ae_sqr(v, _state); ae_v_addd(&g.ptr.p_double[0], 1, &ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v); } armijobestfeas = ae_sqrt(armijobestfeas, _state); for(i=0; i<=nmain-1; i++) { if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) { g.ptr.p_double[i] = 0.0; } if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) { g.ptr.p_double[i] = 0.0; } } for(i=0; i<=nslack-1; i++) { if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) { g.ptr.p_double[nmain+i] = 0.0; } } v = 0.0; for(i=0; i<=nmain+nslack-1; i++) { if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),(double)(0)) ) { newtonstep.ptr.p_double[i] = -g.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); } else { newtonstep.ptr.p_double[i] = 0.0; } v = v+ae_sqr(newtonstep.ptr.p_double[i], _state); } if( ae_fp_eq(v,(double)(0)) ) { /* * Constrained gradient is zero, QP iterations are over */ break; } calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) { /* * Can not perform step, QP iterations are over */ break; } if( vartofreeze>=0 ) { armijostep = ae_minreal(1.0, maxsteplen, _state); } else { armijostep = (double)(1); } for(;;) { ae_v_move(&xa.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); feaserr = 0.0; for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; feaserr = feaserr+ae_sqr(v, _state); } feaserr = ae_sqrt(feaserr, _state); if( ae_fp_greater_eq(feaserr,armijobestfeas) ) { break; } armijobestfeas = feaserr; armijobeststep = armijostep; armijostep = 2.0*armijostep; } ae_v_addd(&x->ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); /* * Determine number of active and free constraints */ nactive = 0; for(i=0; i<=nmain-1; i++) { activeconstraints.ptr.p_double[i] = (double)(0); if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) { activeconstraints.ptr.p_double[i] = (double)(1); } if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) { activeconstraints.ptr.p_double[i] = (double)(1); } if( ae_fp_greater(activeconstraints.ptr.p_double[i],(double)(0)) ) { nactive = nactive+1; } } for(i=0; i<=nslack-1; i++) { activeconstraints.ptr.p_double[nmain+i] = (double)(0); if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) { activeconstraints.ptr.p_double[nmain+i] = (double)(1); } if( ae_fp_greater(activeconstraints.ptr.p_double[nmain+i],(double)(0)) ) { nactive = nactive+1; } } nfree = nmain+nslack-nactive; if( nfree==0 ) { break; } *qpits = *qpits+1; /* * Reorder variables */ tagsortbuf(&activeconstraints, nmain+nslack, &p1, &p2, &buf, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=nmain+nslack-1; j++) { a.ptr.pp_double[i][j] = ce->ptr.pp_double[i][j]; } } for(j=0; j<=nmain+nslack-1; j++) { permx.ptr.p_double[j] = x->ptr.p_double[j]; } for(j=0; j<=nmain+nslack-1; j++) { if( p2.ptr.p_int[j]!=j ) { idx0 = p2.ptr.p_int[j]; idx1 = j; for(i=0; i<=k-1; i++) { v = a.ptr.pp_double[i][idx0]; a.ptr.pp_double[i][idx0] = a.ptr.pp_double[i][idx1]; a.ptr.pp_double[i][idx1] = v; } v = permx.ptr.p_double[idx0]; permx.ptr.p_double[idx0] = permx.ptr.p_double[idx1]; permx.ptr.p_double[idx1] = v; } } /* * Calculate (unprojected) gradient: * G(xi) = CEi'*(CEi*xi + CEa*xa - b) */ for(i=0; i<=nfree-1; i++) { g.ptr.p_double[i] = (double)(0); } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &permx.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); tmpk.ptr.p_double[i] = v-ce->ptr.pp_double[i][nmain+nslack]; } for(i=0; i<=k-1; i++) { v = tmpk.ptr.p_double[i]; ae_v_addd(&g.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); } /* * Calculate Newton step using SVD of CEi: * F(xi) = 0.5*xi'*H*xi + g'*xi (Taylor decomposition) * XN = -H^(-1)*g (new point, solution of the QP subproblem) * H = CEi'*CEi * CEi = U*W*V' (SVD of CEi) * H = V*W^2*V' * H^(-1) = V*W^(-2)*V' * step = -V*W^(-2)*V'*g (it is better to perform multiplication from right to left) * * NOTE 1: we do NOT need left singular vectors to perform Newton step. */ nsvd = ae_minint(k, nfree, _state); if( !rmatrixsvd(&a, k, nfree, 0, 1, 2, &w, &u, &vt, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } for(i=0; i<=nsvd-1; i++) { v = ae_v_dotproduct(&vt.ptr.pp_double[i][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); tmpk.ptr.p_double[i] = v; } for(i=0; i<=nsvd-1; i++) { /* * It is important to have strict ">" in order to correctly * handle zero singular values. */ if( ae_fp_greater(ae_sqr(w.ptr.p_double[i], _state),ae_sqr(w.ptr.p_double[0], _state)*(nmain+nslack)*ae_machineepsilon) ) { tmpk.ptr.p_double[i] = tmpk.ptr.p_double[i]/ae_sqr(w.ptr.p_double[i], _state); } else { tmpk.ptr.p_double[i] = (double)(0); } } for(i=0; i<=nmain+nslack-1; i++) { newtonstep.ptr.p_double[i] = (double)(0); } for(i=0; i<=nsvd-1; i++) { v = tmpk.ptr.p_double[i]; ae_v_subd(&newtonstep.ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); } for(j=nmain+nslack-1; j>=0; j--) { if( p2.ptr.p_int[j]!=j ) { idx0 = p2.ptr.p_int[j]; idx1 = j; v = newtonstep.ptr.p_double[idx0]; newtonstep.ptr.p_double[idx0] = newtonstep.ptr.p_double[idx1]; newtonstep.ptr.p_double[idx1] = v; } } /* * NewtonStep contains Newton step subject to active bound constraints. * * Such step leads us to the minimizer of the equality constrained F, * but such minimizer may be infeasible because some constraints which * are inactive at the initial point can be violated at the solution. * * Thus, we perform optimization in two stages: * a) perform bounded Newton step, i.e. step in the Newton direction * until activation of the first constraint * b) in case (MaxStepLen>0)and(MaxStepLen<1), perform additional iteration * of the Armijo line search in the rest of the Newton direction. */ calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) { /* * Activation of the constraints prevent us from performing step, * QP iterations are over */ break; } if( vartofreeze>=0 ) { v = ae_minreal(1.0, maxsteplen, _state); } else { v = 1.0; } ae_v_moved(&xn.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); ae_v_add(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); if( ae_fp_greater(maxsteplen,(double)(0))&&ae_fp_less(maxsteplen,(double)(1)) ) { /* * Newton step was restricted by activation of the constraints, * perform Armijo iteration. * * Initial estimate for best step is zero step. We try different * step sizes, from the 1-MaxStepLen (residual of the full Newton * step) to progressively smaller and smaller steps. */ armijobeststep = 0.0; armijobestfeas = 0.0; for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; armijobestfeas = armijobestfeas+ae_sqr(v, _state); } armijobestfeas = ae_sqrt(armijobestfeas, _state); armijostep = 1-maxsteplen; for(j=0; j<=maxarmijoruns-1; j++) { ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); feaserr = 0.0; for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; feaserr = feaserr+ae_sqr(v, _state); } feaserr = ae_sqrt(feaserr, _state); if( ae_fp_less(feaserr,armijobestfeas) ) { armijobestfeas = feaserr; armijobeststep = armijostep; } armijostep = 0.5*armijostep; } ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); } else { /* * Armijo iteration is not performed */ ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); } stage1isover = ae_fp_greater_eq(maxsteplen,(double)(1))||ae_fp_eq(maxsteplen,(double)(0)); /* * Calculate feasibility errors for old and new X. * These quantinies are used for debugging purposes only. * However, we can leave them in release code because performance impact is insignificant. * * Update X. Exit if needed. */ feasold = (double)(0); feasnew = (double)(0); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); feasold = feasold+ae_sqr(v-ce->ptr.pp_double[i][nmain+nslack], _state); v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); feasnew = feasnew+ae_sqr(v-ce->ptr.pp_double[i][nmain+nslack], _state); } feasold = ae_sqrt(feasold, _state); feasnew = ae_sqrt(feasnew, _state); if( ae_fp_greater_eq(feasnew,feasold) ) { break; } ae_v_move(&x->ptr.p_double[0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); if( stage1isover ) { break; } } /* * Stage 2: gradient projection algorithm (GPA) * * * calculate feasibility error (with respect to linear equality constraints) * * calculate gradient G of F, project it into feasible area (G => PG) * * exit if norm(PG) is exactly zero or feasibility error is smaller than EpsC * * let XM be exact minimum of F along -PG (XM may be infeasible). * calculate MaxStepLen = largest step in direction of -PG which retains feasibility. * * perform bounded step from X to XN: * a) XN=XM (if XM is feasible) * b) XN=X-MaxStepLen*PG (otherwise) * * X := XN * * stop after specified number of iterations or when no new constraints was activated * * NOTES: * * grad(F) = (CE'*CE)*x - (b'*CE)^T * * CE[i] denotes I-th row of CE * * XM = X+stp*(-PG) where stp=(grad(F(X)),PG)/(CE*PG,CE*PG). * Here PG is a projected gradient, but in fact it can be arbitrary non-zero * direction vector - formula for minimum of F along PG still will be correct. */ werechangesinconstraints = ae_false; for(gparuns=1; gparuns<=k; gparuns++) { /* * calculate feasibility error and G */ feaserr = (double)(0); for(i=0; i<=nmain+nslack-1; i++) { g.ptr.p_double[i] = (double)(0); } for(i=0; i<=k-1; i++) { /* * G += CE[i]^T * (CE[i]*x-b[i]) */ v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; feaserr = feaserr+ae_sqr(v, _state); ae_v_addd(&g.ptr.p_double[0], 1, &ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v); } /* * project G, filter it (strip numerical noise) */ ae_v_move(&pg.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); projectgradientintobc(x, &pg, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); filterdirection(&pg, x, bndl, havebndl, bndu, havebndu, &s, nmain, nslack, 1.0E-9, _state); for(i=0; i<=nmain+nslack-1; i++) { if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),(double)(0)) ) { pg.ptr.p_double[i] = pg.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); } else { pg.ptr.p_double[i] = 0.0; } } /* * Check GNorm and feasibility. * Exit when GNorm is exactly zero. */ pgnorm = ae_v_dotproduct(&pg.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); feaserr = ae_sqrt(feaserr, _state); pgnorm = ae_sqrt(pgnorm, _state); if( ae_fp_eq(pgnorm,(double)(0)) ) { result = ae_fp_less_eq(feaserr,epsi); ae_frame_leave(_state); return result; } /* * calculate planned step length */ vn = ae_v_dotproduct(&g.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); vd = (double)(0); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); vd = vd+ae_sqr(v, _state); } stp = vn/vd; /* * Calculate step bound. * Perform bounded step and post-process it */ calculatestepbound(x, &pg, -1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } if( vartofreeze>=0 ) { v = ae_minreal(stp, maxsteplen, _state); } else { v = stp; } ae_v_move(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); ae_v_subd(&xn.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); /* * update X * check stopping criteria */ werechangesinconstraints = werechangesinconstraints||numberofchangedconstraints(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state)>0; ae_v_move(&x->ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); *gpaits = *gpaits+1; if( !werechangesinconstraints ) { break; } } /* * Stage 3: decide to stop algorithm or not to stop * * 1. we can stop when last GPA run did NOT changed constraints status. * It means that we've found final set of the active constraints even * before GPA made its run. And it means that Newton step moved us to * the minimum subject to the present constraints. * Depending on feasibility error, True or False is returned. */ feaserr = (double)(0); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); v = v-ce->ptr.pp_double[i][nmain+nslack]; feaserr = feaserr+ae_sqr(v, _state); } feaserr = ae_sqrt(feaserr, _state); feaserr1 = feaserr; if( ae_fp_greater_eq(feaserr1,feaserr0*(1-1000*ae_machineepsilon)) ) { inc(&badits, _state); } else { badits = 0; } if( ae_fp_less_eq(feaserr,epsi) ) { inc(&itswithintolerance, _state); } else { itswithintolerance = 0; } if( (!werechangesinconstraints||itswithintolerance>=maxitswithintolerance)||badits>=maxbadits ) { result = ae_fp_less_eq(feaserr,epsi); ae_frame_leave(_state); return result; } itscount = itscount+1; } ae_frame_leave(_state); return result; } /************************************************************************* This function checks that input derivatives are right. First it scales parameters DF0 and DF1 from segment [A;B] to [0;1]. Then it builds Hermite spline and derivative of it in 0.5. Search scale as Max(DF0,DF1, |F0-F1|). Right derivative has to satisfy condition: |H-F|/S<=0,01, |H'-F'|/S<=0,01. INPUT PARAMETERS: F0 - function's value in X-TestStep point; DF0 - derivative's value in X-TestStep point; F1 - function's value in X+TestStep point; DF1 - derivative's value in X+TestStep point; F - testing function's value; DF - testing derivative's value; Width- width of verification segment. RESULT: If input derivatives is right then function returns true, else function returns false. -- ALGLIB -- Copyright 29.05.2012 by Bochkanov Sergey *************************************************************************/ ae_bool derivativecheck(double f0, double df0, double f1, double df1, double f, double df, double width, ae_state *_state) { double s; double h; double dh; ae_bool result; df = width*df; df0 = width*df0; df1 = width*df1; s = ae_maxreal(ae_maxreal(ae_fabs(df0, _state), ae_fabs(df1, _state), _state), ae_fabs(f1-f0, _state), _state); h = 0.5*f0+0.125*df0+0.5*f1-0.125*df1; dh = -1.5*f0-0.25*df0+1.5*f1-0.25*df1; if( ae_fp_neq(s,(double)(0)) ) { if( ae_fp_greater(ae_fabs(h-f, _state)/s,0.001)||ae_fp_greater(ae_fabs(dh-df, _state)/s,0.001) ) { result = ae_false; return result; } } else { if( ae_fp_neq(h-f,0.0)||ae_fp_neq(dh-df,0.0) ) { result = ae_false; return result; } } result = ae_true; return result; } /************************************************************************* Having quadratic target function f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) and its parabolic model along direction D F(x0+alpha*D) = D2*alpha^2 + D1*alpha this function estimates numerical errors in the coefficients of the model. It is important that this function does NOT calculate D1/D2 - it only estimates numerical errors introduced during evaluation and compares their magnitudes against magnitudes of numerical errors. As result, one of three outcomes is returned for each coefficient: * "true" coefficient is almost surely positive * "true" coefficient is almost surely negative * numerical errors in coefficient are so large that it can not be reliably distinguished from zero INPUT PARAMETERS: AbsASum - SUM(|A[i,j]|) AbsASum2- SUM(A[i,j]^2) MB - max(|B|) MX - max(|X|) MD - max(|D|) D1 - linear coefficient D2 - quadratic coefficient OUTPUT PARAMETERS: D1Est - estimate of D1 sign, accounting for possible numerical errors: * >0 means "almost surely positive" (D1>0 and large) * <0 means "almost surely negative" (D1<0 and large) * =0 means "pessimistic estimate of numerical errors in D1 is larger than magnitude of D1 itself; it is impossible to reliably distinguish D1 from zero". D2Est - estimate of D2 sign, accounting for possible numerical errors: * >0 means "almost surely positive" (D2>0 and large) * <0 means "almost surely negative" (D2<0 and large) * =0 means "pessimistic estimate of numerical errors in D2 is larger than magnitude of D2 itself; it is impossible to reliably distinguish D2 from zero". -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ void estimateparabolicmodel(double absasum, double absasum2, double mx, double mb, double md, double d1, double d2, ae_int_t* d1est, ae_int_t* d2est, ae_state *_state) { double d1esterror; double d2esterror; double eps; double e1; double e2; *d1est = 0; *d2est = 0; /* * Error estimates: * * * error in D1=d'*(A*x+b) is estimated as * ED1 = eps*MAX_ABS(D)*(MAX_ABS(X)*ENORM(A)+MAX_ABS(B)) * * error in D2=0.5*d'*A*d is estimated as * ED2 = eps*MAX_ABS(D)^2*ENORM(A) * * Here ENORM(A) is some pseudo-norm which reflects the way numerical * error accumulates during addition. Two ways of accumulation are * possible - worst case (errors always increase) and mean-case (errors * may cancel each other). We calculate geometrical average of both: * * ENORM_WORST(A) = SUM(|A[i,j]|) error in N-term sum grows as O(N) * * ENORM_MEAN(A) = SQRT(SUM(A[i,j]^2)) error in N-term sum grows as O(sqrt(N)) * * ENORM(A) = SQRT(ENORM_WORST(A),ENORM_MEAN(A)) */ eps = 4*ae_machineepsilon; e1 = eps*md*(mx*absasum+mb); e2 = eps*md*(mx*ae_sqrt(absasum2, _state)+mb); d1esterror = ae_sqrt(e1*e2, _state); if( ae_fp_less_eq(ae_fabs(d1, _state),d1esterror) ) { *d1est = 0; } else { *d1est = ae_sign(d1, _state); } e1 = eps*md*md*absasum; e2 = eps*md*md*ae_sqrt(absasum2, _state); d2esterror = ae_sqrt(e1*e2, _state); if( ae_fp_less_eq(ae_fabs(d2, _state),d2esterror) ) { *d2est = 0; } else { *d2est = ae_sign(d2, _state); } } /************************************************************************* This function calculates inexact rank-K preconditioner for Hessian matrix H=D+W'*C*W, where: * H is a Hessian matrix, which is approximated by D/W/C * D is a diagonal matrix with positive entries * W is a rank-K correction * C is a diagonal factor of rank-K correction This preconditioner is inexact but fast - it requires O(N*K) time to be applied. Its main purpose - to be used in barrier/penalty/AUL methods, where ill-conditioning is created by combination of two factors: * simple bounds on variables => ill-conditioned D * general barrier/penalty => correction W with large coefficient C (makes problem ill-conditioned) but W itself is well conditioned. Preconditioner P is calculated by artificially constructing a set of BFGS updates which tries to reproduce behavior of H: * Sk = Wk (k-th row of W) * Yk = (D+Wk'*Ck*Wk)*Sk * Yk/Sk are reordered by ascending of C[k]*norm(Wk)^2 Here we assume that rows of Wk are orthogonal or nearly orthogonal, which allows us to have O(N*K+K^2) update instead of O(N*K^2) one. Reordering of updates is essential for having good performance on non-orthogonal problems (updates which do not add much of curvature are added first, and updates which add very large eigenvalues are added last and override effect of the first updates). On input this function takes direction S and components of H. On output it returns inv(H)*S -- ALGLIB -- Copyright 30.06.2014 by Bochkanov Sergey *************************************************************************/ void inexactlbfgspreconditioner(/* Real */ ae_vector* s, ae_int_t n, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t k, precbuflbfgs* buf, ae_state *_state) { ae_int_t idx; ae_int_t i; ae_int_t j; double v; double v0; double v1; double vx; double vy; rvectorsetlengthatleast(&buf->norms, k, _state); rvectorsetlengthatleast(&buf->alpha, k, _state); rvectorsetlengthatleast(&buf->rho, k, _state); rmatrixsetlengthatleast(&buf->yk, k, n, _state); ivectorsetlengthatleast(&buf->idx, k, _state); /* * Check inputs */ for(i=0; i<=n-1; i++) { ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "InexactLBFGSPreconditioner: D[]<=0", _state); } for(i=0; i<=k-1; i++) { ae_assert(ae_fp_greater_eq(c->ptr.p_double[i],(double)(0)), "InexactLBFGSPreconditioner: C[]<0", _state); } /* * Reorder linear terms according to increase of second derivative. * Fill Norms[] array. */ for(idx=0; idx<=k-1; idx++) { v = ae_v_dotproduct(&w->ptr.pp_double[idx][0], 1, &w->ptr.pp_double[idx][0], 1, ae_v_len(0,n-1)); buf->norms.ptr.p_double[idx] = v*c->ptr.p_double[idx]; buf->idx.ptr.p_int[idx] = idx; } tagsortfasti(&buf->norms, &buf->idx, &buf->bufa, &buf->bufb, k, _state); /* * Apply updates */ for(idx=0; idx<=k-1; idx++) { /* * Select update to perform (ordered by ascending of second derivative) */ i = buf->idx.ptr.p_int[idx]; /* * Calculate YK and Rho */ v = ae_v_dotproduct(&w->ptr.pp_double[i][0], 1, &w->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = v*c->ptr.p_double[i]; for(j=0; j<=n-1; j++) { buf->yk.ptr.pp_double[i][j] = (d->ptr.p_double[j]+v)*w->ptr.pp_double[i][j]; } v = 0.0; v0 = 0.0; v1 = 0.0; for(j=0; j<=n-1; j++) { vx = w->ptr.pp_double[i][j]; vy = buf->yk.ptr.pp_double[i][j]; v = v+vx*vy; v0 = v0+vx*vx; v1 = v1+vy*vy; } if( (ae_fp_greater(v,(double)(0))&&ae_fp_greater(v0*v1,(double)(0)))&&ae_fp_greater(v/ae_sqrt(v0*v1, _state),n*10*ae_machineepsilon) ) { buf->rho.ptr.p_double[i] = 1/v; } else { buf->rho.ptr.p_double[i] = 0.0; } } for(idx=k-1; idx>=0; idx--) { /* * Select update to perform (ordered by ascending of second derivative) */ i = buf->idx.ptr.p_int[idx]; /* * Calculate Alpha[] according to L-BFGS algorithm * and update S[] */ v = ae_v_dotproduct(&w->ptr.pp_double[i][0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = buf->rho.ptr.p_double[i]*v; buf->alpha.ptr.p_double[i] = v; ae_v_subd(&s->ptr.p_double[0], 1, &buf->yk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } for(j=0; j<=n-1; j++) { s->ptr.p_double[j] = s->ptr.p_double[j]/d->ptr.p_double[j]; } for(idx=0; idx<=k-1; idx++) { /* * Select update to perform (ordered by ascending of second derivative) */ i = buf->idx.ptr.p_int[idx]; /* * Calculate Beta according to L-BFGS algorithm * and update S[] */ v = ae_v_dotproduct(&buf->yk.ptr.pp_double[i][0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = buf->alpha.ptr.p_double[i]-buf->rho.ptr.p_double[i]*v; ae_v_addd(&s->ptr.p_double[0], 1, &w->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } } /************************************************************************* This function prepares exact low-rank preconditioner for Hessian matrix H=D+W'*C*W, where: * H is a Hessian matrix, which is approximated by D/W/C * D is a diagonal matrix with positive entries * W is a rank-K correction * C is a diagonal factor of rank-K correction, positive semidefinite This preconditioner is exact but relatively slow - it requires O(N*K^2) time to be prepared and O(N*K) time to be applied. It is calculated with the help of Woodbury matrix identity. It should be used as follows: * PrepareLowRankPreconditioner() call PREPARES data structure * subsequent calls to ApplyLowRankPreconditioner() APPLY preconditioner to user-specified search direction. -- ALGLIB -- Copyright 30.06.2014 by Bochkanov Sergey *************************************************************************/ void preparelowrankpreconditioner(/* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t n, ae_int_t k, precbuflowrank* buf, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_bool b; /* * Check inputs */ ae_assert(n>0, "PrepareLowRankPreconditioner: N<=0", _state); ae_assert(k>=0, "PrepareLowRankPreconditioner: N<=0", _state); for(i=0; i<=n-1; i++) { ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "PrepareLowRankPreconditioner: D[]<=0", _state); } for(i=0; i<=k-1; i++) { ae_assert(ae_fp_greater_eq(c->ptr.p_double[i],(double)(0)), "PrepareLowRankPreconditioner: C[]<0", _state); } /* * Prepare buffer structure; skip zero entries of update. */ rvectorsetlengthatleast(&buf->d, n, _state); rmatrixsetlengthatleast(&buf->v, k, n, _state); rvectorsetlengthatleast(&buf->bufc, k, _state); rmatrixsetlengthatleast(&buf->bufw, k+1, n, _state); buf->n = n; buf->k = 0; for(i=0; i<=k-1; i++) { /* * Estimate magnitude of update row; skip zero rows (either W or C are zero) */ v = 0.0; for(j=0; j<=n-1; j++) { v = v+w->ptr.pp_double[i][j]*w->ptr.pp_double[i][j]; } v = v*c->ptr.p_double[i]; if( ae_fp_eq(v,(double)(0)) ) { continue; } ae_assert(ae_fp_greater(v,(double)(0)), "PrepareLowRankPreconditioner: internal error", _state); /* * Copy non-zero update to buffer */ buf->bufc.ptr.p_double[buf->k] = c->ptr.p_double[i]; for(j=0; j<=n-1; j++) { buf->v.ptr.pp_double[buf->k][j] = w->ptr.pp_double[i][j]; buf->bufw.ptr.pp_double[buf->k][j] = w->ptr.pp_double[i][j]; } inc(&buf->k, _state); } /* * Reset K (for convenience) */ k = buf->k; /* * Prepare diagonal factor; quick exit for K=0 */ for(i=0; i<=n-1; i++) { buf->d.ptr.p_double[i] = 1/d->ptr.p_double[i]; } if( k==0 ) { return; } /* * Use Woodbury matrix identity */ rmatrixsetlengthatleast(&buf->bufz, k, k, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { buf->bufz.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=k-1; i++) { buf->bufz.ptr.pp_double[i][i] = 1/buf->bufc.ptr.p_double[i]; } for(j=0; j<=n-1; j++) { buf->bufw.ptr.pp_double[k][j] = 1/ae_sqrt(d->ptr.p_double[j], _state); } for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { buf->bufw.ptr.pp_double[i][j] = buf->bufw.ptr.pp_double[i][j]*buf->bufw.ptr.pp_double[k][j]; } } rmatrixgemm(k, k, n, 1.0, &buf->bufw, 0, 0, 0, &buf->bufw, 0, 0, 1, 1.0, &buf->bufz, 0, 0, _state); b = spdmatrixcholeskyrec(&buf->bufz, 0, k, ae_true, &buf->tmp, _state); ae_assert(b, "PrepareLowRankPreconditioner: internal error (Cholesky failure)", _state); rmatrixlefttrsm(k, n, &buf->bufz, 0, 0, ae_true, ae_false, 1, &buf->v, 0, 0, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { buf->v.ptr.pp_double[i][j] = buf->v.ptr.pp_double[i][j]*buf->d.ptr.p_double[j]; } } } /************************************************************************* This function apply exact low-rank preconditioner prepared by PrepareLowRankPreconditioner function (see its comments for more information). -- ALGLIB -- Copyright 30.06.2014 by Bochkanov Sergey *************************************************************************/ void applylowrankpreconditioner(/* Real */ ae_vector* s, precbuflowrank* buf, ae_state *_state) { ae_int_t n; ae_int_t k; ae_int_t i; ae_int_t j; double v; n = buf->n; k = buf->k; rvectorsetlengthatleast(&buf->tmp, n, _state); for(j=0; j<=n-1; j++) { buf->tmp.ptr.p_double[j] = buf->d.ptr.p_double[j]*s->ptr.p_double[j]; } for(i=0; i<=k-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+buf->v.ptr.pp_double[i][j]*s->ptr.p_double[j]; } for(j=0; j<=n-1; j++) { buf->tmp.ptr.p_double[j] = buf->tmp.ptr.p_double[j]-v*buf->v.ptr.pp_double[i][j]; } } for(i=0; i<=n-1; i++) { s->ptr.p_double[i] = buf->tmp.ptr.p_double[i]; } } void _precbuflbfgs_init(void* _p, ae_state *_state) { precbuflbfgs *p = (precbuflbfgs*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->norms, 0, DT_REAL, _state); ae_vector_init(&p->alpha, 0, DT_REAL, _state); ae_vector_init(&p->rho, 0, DT_REAL, _state); ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state); ae_vector_init(&p->idx, 0, DT_INT, _state); ae_vector_init(&p->bufa, 0, DT_REAL, _state); ae_vector_init(&p->bufb, 0, DT_INT, _state); } void _precbuflbfgs_init_copy(void* _dst, void* _src, ae_state *_state) { precbuflbfgs *dst = (precbuflbfgs*)_dst; precbuflbfgs *src = (precbuflbfgs*)_src; ae_vector_init_copy(&dst->norms, &src->norms, _state); ae_vector_init_copy(&dst->alpha, &src->alpha, _state); ae_vector_init_copy(&dst->rho, &src->rho, _state); ae_matrix_init_copy(&dst->yk, &src->yk, _state); ae_vector_init_copy(&dst->idx, &src->idx, _state); ae_vector_init_copy(&dst->bufa, &src->bufa, _state); ae_vector_init_copy(&dst->bufb, &src->bufb, _state); } void _precbuflbfgs_clear(void* _p) { precbuflbfgs *p = (precbuflbfgs*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->norms); ae_vector_clear(&p->alpha); ae_vector_clear(&p->rho); ae_matrix_clear(&p->yk); ae_vector_clear(&p->idx); ae_vector_clear(&p->bufa); ae_vector_clear(&p->bufb); } void _precbuflbfgs_destroy(void* _p) { precbuflbfgs *p = (precbuflbfgs*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->norms); ae_vector_destroy(&p->alpha); ae_vector_destroy(&p->rho); ae_matrix_destroy(&p->yk); ae_vector_destroy(&p->idx); ae_vector_destroy(&p->bufa); ae_vector_destroy(&p->bufb); } void _precbuflowrank_init(void* _p, ae_state *_state) { precbuflowrank *p = (precbuflowrank*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_matrix_init(&p->v, 0, 0, DT_REAL, _state); ae_vector_init(&p->bufc, 0, DT_REAL, _state); ae_matrix_init(&p->bufz, 0, 0, DT_REAL, _state); ae_matrix_init(&p->bufw, 0, 0, DT_REAL, _state); ae_vector_init(&p->tmp, 0, DT_REAL, _state); } void _precbuflowrank_init_copy(void* _dst, void* _src, ae_state *_state) { precbuflowrank *dst = (precbuflowrank*)_dst; precbuflowrank *src = (precbuflowrank*)_src; dst->n = src->n; dst->k = src->k; ae_vector_init_copy(&dst->d, &src->d, _state); ae_matrix_init_copy(&dst->v, &src->v, _state); ae_vector_init_copy(&dst->bufc, &src->bufc, _state); ae_matrix_init_copy(&dst->bufz, &src->bufz, _state); ae_matrix_init_copy(&dst->bufw, &src->bufw, _state); ae_vector_init_copy(&dst->tmp, &src->tmp, _state); } void _precbuflowrank_clear(void* _p) { precbuflowrank *p = (precbuflowrank*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->d); ae_matrix_clear(&p->v); ae_vector_clear(&p->bufc); ae_matrix_clear(&p->bufz); ae_matrix_clear(&p->bufw); ae_vector_clear(&p->tmp); } void _precbuflowrank_destroy(void* _p) { precbuflowrank *p = (precbuflowrank*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->d); ae_matrix_destroy(&p->v); ae_vector_destroy(&p->bufc); ae_matrix_destroy(&p->bufz); ae_matrix_destroy(&p->bufw); ae_vector_destroy(&p->tmp); } /************************************************************************* This subroutine is used to initialize CQM. By default, empty NxN model is generated, with Alpha=Lambda=Theta=0.0 and zero b. Previously allocated buffer variables are reused as much as possible. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state) { ae_int_t i; s->n = n; s->k = 0; s->nfree = n; s->ecakind = -1; s->alpha = 0.0; s->tau = 0.0; s->theta = 0.0; s->ismaintermchanged = ae_true; s->issecondarytermchanged = ae_true; s->islineartermchanged = ae_true; s->isactivesetchanged = ae_true; bvectorsetlengthatleast(&s->activeset, n, _state); rvectorsetlengthatleast(&s->xc, n, _state); rvectorsetlengthatleast(&s->eb, n, _state); rvectorsetlengthatleast(&s->tq1, n, _state); rvectorsetlengthatleast(&s->txc, n, _state); rvectorsetlengthatleast(&s->tb, n, _state); rvectorsetlengthatleast(&s->b, s->n, _state); rvectorsetlengthatleast(&s->tk1, s->n, _state); for(i=0; i<=n-1; i++) { s->activeset.ptr.p_bool[i] = ae_false; s->xc.ptr.p_double[i] = 0.0; s->b.ptr.p_double[i] = 0.0; } } /************************************************************************* This subroutine changes main quadratic term of the model. INPUT PARAMETERS: S - model A - NxN matrix, only upper or lower triangle is referenced IsUpper - True, when matrix is stored in upper triangle Alpha - multiplier; when Alpha=0, A is not referenced at all -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmseta(convexquadraticmodel* s, /* Real */ ae_matrix* a, ae_bool isupper, double alpha, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_assert(ae_isfinite(alpha, _state)&&ae_fp_greater_eq(alpha,(double)(0)), "CQMSetA: Alpha<0 or is not finite number", _state); ae_assert(ae_fp_eq(alpha,(double)(0))||isfinitertrmatrix(a, s->n, isupper, _state), "CQMSetA: A is not finite NxN matrix", _state); s->alpha = alpha; if( ae_fp_greater(alpha,(double)(0)) ) { rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); for(i=0; i<=s->n-1; i++) { for(j=i; j<=s->n-1; j++) { if( isupper ) { v = a->ptr.pp_double[i][j]; } else { v = a->ptr.pp_double[j][i]; } s->a.ptr.pp_double[i][j] = v; s->a.ptr.pp_double[j][i] = v; } } } s->ismaintermchanged = ae_true; } /************************************************************************* This subroutine changes main quadratic term of the model. INPUT PARAMETERS: S - model A - possibly preallocated buffer OUTPUT PARAMETERS: A - NxN matrix, full matrix is returned. Zero matrix is returned if model is empty. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmgeta(convexquadraticmodel* s, /* Real */ ae_matrix* a, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_int_t n; n = s->n; rmatrixsetlengthatleast(a, n, n, _state); if( ae_fp_greater(s->alpha,(double)(0)) ) { v = s->alpha; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = v*s->a.ptr.pp_double[i][j]; } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a->ptr.pp_double[i][j] = 0.0; } } } } /************************************************************************* This subroutine rewrites diagonal of the main quadratic term of the model (dense A) by vector Z/Alpha (current value of the Alpha coefficient is used). IMPORTANT: in case model has no dense quadratic term, this function allocates N*N dense matrix of zeros, and fills its diagonal by non-zero values. INPUT PARAMETERS: S - model Z - new diagonal, array[N] -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmrewritedensediagonal(convexquadraticmodel* s, /* Real */ ae_vector* z, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; n = s->n; if( ae_fp_eq(s->alpha,(double)(0)) ) { rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { s->a.ptr.pp_double[i][j] = 0.0; } } s->alpha = 1.0; } for(i=0; i<=s->n-1; i++) { s->a.ptr.pp_double[i][i] = z->ptr.p_double[i]/s->alpha; } s->ismaintermchanged = ae_true; } /************************************************************************* This subroutine changes diagonal quadratic term of the model. INPUT PARAMETERS: S - model D - array[N], semidefinite diagonal matrix Tau - multiplier; when Tau=0, D is not referenced at all -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmsetd(convexquadraticmodel* s, /* Real */ ae_vector* d, double tau, ae_state *_state) { ae_int_t i; ae_assert(ae_isfinite(tau, _state)&&ae_fp_greater_eq(tau,(double)(0)), "CQMSetD: Tau<0 or is not finite number", _state); ae_assert(ae_fp_eq(tau,(double)(0))||isfinitevector(d, s->n, _state), "CQMSetD: D is not finite Nx1 vector", _state); s->tau = tau; if( ae_fp_greater(tau,(double)(0)) ) { rvectorsetlengthatleast(&s->d, s->n, _state); rvectorsetlengthatleast(&s->ecadiag, s->n, _state); rvectorsetlengthatleast(&s->tq2diag, s->n, _state); for(i=0; i<=s->n-1; i++) { ae_assert(ae_fp_greater_eq(d->ptr.p_double[i],(double)(0)), "CQMSetD: D[i]<0", _state); s->d.ptr.p_double[i] = d->ptr.p_double[i]; } } s->ismaintermchanged = ae_true; } /************************************************************************* This subroutine drops main quadratic term A from the model. It is same as call to CQMSetA() with zero A, but gives better performance because algorithm knows that matrix is zero and can optimize subsequent calculations. INPUT PARAMETERS: S - model -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmdropa(convexquadraticmodel* s, ae_state *_state) { s->alpha = 0.0; s->ismaintermchanged = ae_true; } /************************************************************************* This subroutine changes linear term of the model -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmsetb(convexquadraticmodel* s, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t i; ae_assert(isfinitevector(b, s->n, _state), "CQMSetB: B is not finite vector", _state); rvectorsetlengthatleast(&s->b, s->n, _state); for(i=0; i<=s->n-1; i++) { s->b.ptr.p_double[i] = b->ptr.p_double[i]; } s->islineartermchanged = ae_true; } /************************************************************************* This subroutine changes linear term of the model -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmsetq(convexquadraticmodel* s, /* Real */ ae_matrix* q, /* Real */ ae_vector* r, ae_int_t k, double theta, ae_state *_state) { ae_int_t i; ae_int_t j; ae_assert(k>=0, "CQMSetQ: K<0", _state); ae_assert((k==0||ae_fp_eq(theta,(double)(0)))||apservisfinitematrix(q, k, s->n, _state), "CQMSetQ: Q is not finite matrix", _state); ae_assert((k==0||ae_fp_eq(theta,(double)(0)))||isfinitevector(r, k, _state), "CQMSetQ: R is not finite vector", _state); ae_assert(ae_isfinite(theta, _state)&&ae_fp_greater_eq(theta,(double)(0)), "CQMSetQ: Theta<0 or is not finite number", _state); /* * degenerate case: K=0 or Theta=0 */ if( k==0||ae_fp_eq(theta,(double)(0)) ) { s->k = 0; s->theta = (double)(0); s->issecondarytermchanged = ae_true; return; } /* * General case: both Theta>0 and K>0 */ s->k = k; s->theta = theta; rmatrixsetlengthatleast(&s->q, s->k, s->n, _state); rvectorsetlengthatleast(&s->r, s->k, _state); rmatrixsetlengthatleast(&s->eq, s->k, s->n, _state); rmatrixsetlengthatleast(&s->eccm, s->k, s->k, _state); rmatrixsetlengthatleast(&s->tk2, s->k, s->n, _state); for(i=0; i<=s->k-1; i++) { for(j=0; j<=s->n-1; j++) { s->q.ptr.pp_double[i][j] = q->ptr.pp_double[i][j]; } s->r.ptr.p_double[i] = r->ptr.p_double[i]; } s->issecondarytermchanged = ae_true; } /************************************************************************* This subroutine changes active set INPUT PARAMETERS S - model X - array[N], constraint values ActiveSet- array[N], active set. If ActiveSet[I]=True, then I-th variables is constrained to X[I]. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmsetactiveset(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Boolean */ ae_vector* activeset, ae_state *_state) { ae_int_t i; ae_assert(x->cnt>=s->n, "CQMSetActiveSet: Length(X)cnt>=s->n, "CQMSetActiveSet: Length(ActiveSet)n-1; i++) { s->isactivesetchanged = s->isactivesetchanged||(s->activeset.ptr.p_bool[i]&&!activeset->ptr.p_bool[i]); s->isactivesetchanged = s->isactivesetchanged||(activeset->ptr.p_bool[i]&&!s->activeset.ptr.p_bool[i]); s->activeset.ptr.p_bool[i] = activeset->ptr.p_bool[i]; if( activeset->ptr.p_bool[i] ) { ae_assert(ae_isfinite(x->ptr.p_double[i], _state), "CQMSetActiveSet: X[] contains infinite constraints", _state); s->isactivesetchanged = s->isactivesetchanged||ae_fp_neq(s->xc.ptr.p_double[i],x->ptr.p_double[i]); s->xc.ptr.p_double[i] = x->ptr.p_double[i]; } } } /************************************************************************* This subroutine evaluates model at X. Active constraints are ignored. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ double cqmeval(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double v; double result; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); result = 0.0; /* * main quadratic term */ if( ae_fp_greater(s->alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result+s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; } } } if( ae_fp_greater(s->tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; } } /* * secondary quadratic term */ if( ae_fp_greater(s->theta,(double)(0)) ) { for(i=0; i<=s->k-1; i++) { v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = result+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); } } /* * linear term */ for(i=0; i<=s->n-1; i++) { result = result+x->ptr.p_double[i]*s->b.ptr.p_double[i]; } return result; } /************************************************************************* This subroutine evaluates model at X. Active constraints are ignored. It returns: R - model value Noise- estimate of the numerical noise in data -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmevalx(convexquadraticmodel* s, /* Real */ ae_vector* x, double* r, double* noise, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double v; double v2; double mxq; double eps; *r = 0; *noise = 0; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); *r = 0.0; *noise = 0.0; eps = 2*ae_machineepsilon; mxq = 0.0; /* * Main quadratic term. * * Noise from the main quadratic term is equal to the * maximum summand in the term. */ if( ae_fp_greater(s->alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; *r = *r+v; *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); } } } if( ae_fp_greater(s->tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = 0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; *r = *r+v; *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); } } /* * secondary quadratic term * * Noise from the secondary quadratic term is estimated as follows: * * noise in qi*x-r[i] is estimated as * Eps*MXQ = Eps*max(|r[i]|, |q[i,j]*x[j]|) * * noise in (qi*x-r[i])^2 is estimated as * NOISE = (|qi*x-r[i]|+Eps*MXQ)^2-(|qi*x-r[i]|)^2 * = Eps*MXQ*(2*|qi*x-r[i]|+Eps*MXQ) */ if( ae_fp_greater(s->theta,(double)(0)) ) { for(i=0; i<=s->k-1; i++) { v = 0.0; mxq = ae_fabs(s->r.ptr.p_double[i], _state); for(j=0; j<=n-1; j++) { v2 = s->q.ptr.pp_double[i][j]*x->ptr.p_double[j]; v = v+v2; mxq = ae_maxreal(mxq, ae_fabs(v2, _state), _state); } *r = *r+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); *noise = ae_maxreal(*noise, eps*mxq*(2*ae_fabs(v-s->r.ptr.p_double[i], _state)+eps*mxq), _state); } } /* * linear term */ for(i=0; i<=s->n-1; i++) { *r = *r+x->ptr.p_double[i]*s->b.ptr.p_double[i]; *noise = ae_maxreal(*noise, eps*ae_fabs(x->ptr.p_double[i]*s->b.ptr.p_double[i], _state), _state); } /* * Final update of the noise */ *noise = n*(*noise); } /************************************************************************* This subroutine evaluates gradient of the model; active constraints are ignored. INPUT PARAMETERS: S - convex model X - point, array[N] G - possibly preallocated buffer; resized, if too small -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmgradunconstrained(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double v; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMEvalGradUnconstrained: X is not finite vector", _state); rvectorsetlengthatleast(g, n, _state); for(i=0; i<=n-1; i++) { g->ptr.p_double[i] = (double)(0); } /* * main quadratic term */ if( ae_fp_greater(s->alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+s->alpha*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; } g->ptr.p_double[i] = g->ptr.p_double[i]+v; } } if( ae_fp_greater(s->tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { g->ptr.p_double[i] = g->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; } } /* * secondary quadratic term */ if( ae_fp_greater(s->theta,(double)(0)) ) { for(i=0; i<=s->k-1; i++) { v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = s->theta*(v-s->r.ptr.p_double[i]); ae_v_addd(&g->ptr.p_double[0], 1, &s->q.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } } /* * linear term */ for(i=0; i<=n-1; i++) { g->ptr.p_double[i] = g->ptr.p_double[i]+s->b.ptr.p_double[i]; } } /************************************************************************* This subroutine evaluates x'*(0.5*alpha*A+tau*D)*x -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ double cqmxtadx2(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double result; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); result = 0.0; /* * main quadratic term */ if( ae_fp_greater(s->alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result+s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; } } } if( ae_fp_greater(s->tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; } } return result; } /************************************************************************* This subroutine evaluates (0.5*alpha*A+tau*D)*x Y is automatically resized if needed -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmadx(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_state *_state) { ae_int_t n; ae_int_t i; double v; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); rvectorsetlengthatleast(y, n, _state); /* * main quadratic term */ for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = (double)(0); } if( ae_fp_greater(s->alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&s->a.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); y->ptr.p_double[i] = y->ptr.p_double[i]+s->alpha*v; } } if( ae_fp_greater(s->tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { y->ptr.p_double[i] = y->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; } } } /************************************************************************* This subroutine finds optimum of the model. It returns False on failure (indefinite/semidefinite matrix). Optimum is found subject to active constraints. INPUT PARAMETERS S - model X - possibly preallocated buffer; automatically resized, if too small enough. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t nfree; ae_int_t k; ae_int_t i; double v; ae_int_t cidx0; ae_int_t itidx; ae_bool result; /* * Rebuild internal structures */ if( !cqmodels_cqmrebuild(s, _state) ) { result = ae_false; return result; } n = s->n; k = s->k; nfree = s->nfree; result = ae_true; /* * Calculate initial point for the iterative refinement: * * free components are set to zero * * constrained components are set to their constrained values */ rvectorsetlengthatleast(x, n, _state); for(i=0; i<=n-1; i++) { if( s->activeset.ptr.p_bool[i] ) { x->ptr.p_double[i] = s->xc.ptr.p_double[i]; } else { x->ptr.p_double[i] = (double)(0); } } /* * Iterative refinement. * * In an ideal world without numerical errors it would be enough * to make just one Newton step from initial point: * x_new = -H^(-1)*grad(x=0) * However, roundoff errors can significantly deteriorate quality * of the solution. So we have to recalculate gradient and to * perform Newton steps several times. * * Below we perform fixed number of Newton iterations. */ for(itidx=0; itidx<=cqmodels_newtonrefinementits-1; itidx++) { /* * Calculate gradient at the current point. * Move free components of the gradient in the beginning. */ cqmgradunconstrained(s, x, &s->tmpg, _state); cidx0 = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { s->tmpg.ptr.p_double[cidx0] = s->tmpg.ptr.p_double[i]; cidx0 = cidx0+1; } } /* * Free components of the extrema are calculated in the first NFree elements of TXC. * * First, we have to calculate original Newton step, without rank-K perturbations */ ae_v_moveneg(&s->txc.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); cqmodels_cqmsolveea(s, &s->txc, &s->tmp0, _state); /* * Then, we account for rank-K correction. * Woodbury matrix identity is used. */ if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) { rvectorsetlengthatleast(&s->tmp0, ae_maxint(nfree, k, _state), _state); rvectorsetlengthatleast(&s->tmp1, ae_maxint(nfree, k, _state), _state); ae_v_moveneg(&s->tmp1.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&s->eq.ptr.pp_double[i][0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); s->tmp0.ptr.p_double[i] = v; } fblscholeskysolve(&s->eccm, 1.0, k, ae_true, &s->tmp0, &s->tmp1, _state); for(i=0; i<=nfree-1; i++) { s->tmp1.ptr.p_double[i] = 0.0; } for(i=0; i<=k-1; i++) { v = s->tmp0.ptr.p_double[i]; ae_v_addd(&s->tmp1.ptr.p_double[0], 1, &s->eq.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); } cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); ae_v_sub(&s->txc.ptr.p_double[0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); } /* * Unpack components from TXC into X. We pass through all * free components of X and add our step. */ cidx0 = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { x->ptr.p_double[i] = x->ptr.p_double[i]+s->txc.ptr.p_double[cidx0]; cidx0 = cidx0+1; } } } return result; } /************************************************************************* This function scales vector by multiplying it by inverse of the diagonal of the Hessian matrix. It should be used to accelerate steepest descent phase of the QP solver. Although it is called "scale-grad", it can be called for any vector, whether it is gradient, anti-gradient, or just some vector. This function does NOT takes into account current set of constraints, it just performs matrix-vector multiplication without taking into account constraints. INPUT PARAMETERS: S - model X - vector to scale OUTPUT PARAMETERS: X - scaled vector NOTE: when called for non-SPD matrices, it silently skips components of X which correspond to zero or negative diagonal elements. NOTE: this function uses diagonals of A and D; it ignores Q - rank-K term of the quadratic model. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ void cqmscalevector(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t i; double v; n = s->n; for(i=0; i<=n-1; i++) { v = 0.0; if( ae_fp_greater(s->alpha,(double)(0)) ) { v = v+s->a.ptr.pp_double[i][i]; } if( ae_fp_greater(s->tau,(double)(0)) ) { v = v+s->d.ptr.p_double[i]; } if( ae_fp_greater(v,(double)(0)) ) { x->ptr.p_double[i] = x->ptr.p_double[i]/v; } } } /************************************************************************* This subroutine calls CQMRebuild() and evaluates model at X subject to active constraints. It is intended for debug purposes only, because it evaluates model by means of temporaries, which were calculated by CQMRebuild(). The only purpose of this function is to check correctness of CQMRebuild() by comparing results of this function with ones obtained by CQMEval(), which is used as reference point. The idea is that significant deviation in results of these two functions is evidence of some error in the CQMRebuild(). NOTE: suffix T denotes that temporaries marked by T-prefix are used. There is one more variant of this function, which uses "effective" model built by CQMRebuild(). NOTE2: in case CQMRebuild() fails (due to model non-convexity), this function returns NAN. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ double cqmdebugconstrainedevalt(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t nfree; ae_int_t i; ae_int_t j; double v; double result; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalT: X is not finite vector", _state); if( !cqmodels_cqmrebuild(s, _state) ) { result = _state->v_nan; return result; } result = 0.0; nfree = s->nfree; /* * Reorder variables */ j = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; j = j+1; } } /* * TQ2, TQ1, TQ0 * */ if( ae_fp_greater(s->alpha,(double)(0)) ) { /* * Dense TQ2 */ for(i=0; i<=nfree-1; i++) { for(j=0; j<=nfree-1; j++) { result = result+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; } } } else { /* * Diagonal TQ2 */ for(i=0; i<=nfree-1; i++) { result = result+0.5*s->tq2diag.ptr.p_double[i]*ae_sqr(s->txc.ptr.p_double[i], _state); } } for(i=0; i<=nfree-1; i++) { result = result+s->tq1.ptr.p_double[i]*s->txc.ptr.p_double[i]; } result = result+s->tq0; /* * TK2, TK1, TK0 */ if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) { for(i=0; i<=s->k-1; i++) { v = (double)(0); for(j=0; j<=nfree-1; j++) { v = v+s->tk2.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; } result = result+0.5*ae_sqr(v, _state); } for(i=0; i<=nfree-1; i++) { result = result+s->tk1.ptr.p_double[i]*s->txc.ptr.p_double[i]; } result = result+s->tk0; } /* * TB (Bf and Bc parts) */ for(i=0; i<=n-1; i++) { result = result+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; } return result; } /************************************************************************* This subroutine calls CQMRebuild() and evaluates model at X subject to active constraints. It is intended for debug purposes only, because it evaluates model by means of "effective" matrices built by CQMRebuild(). The only purpose of this function is to check correctness of CQMRebuild() by comparing results of this function with ones obtained by CQMEval(), which is used as reference point. The idea is that significant deviation in results of these two functions is evidence of some error in the CQMRebuild(). NOTE: suffix E denotes that effective matrices. There is one more variant of this function, which uses temporary matrices built by CQMRebuild(). NOTE2: in case CQMRebuild() fails (due to model non-convexity), this function returns NAN. -- ALGLIB -- Copyright 12.06.2012 by Bochkanov Sergey *************************************************************************/ double cqmdebugconstrainedevale(convexquadraticmodel* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t nfree; ae_int_t i; ae_int_t j; double v; double result; n = s->n; ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalE: X is not finite vector", _state); if( !cqmodels_cqmrebuild(s, _state) ) { result = _state->v_nan; return result; } result = 0.0; nfree = s->nfree; /* * Reorder variables */ j = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; j = j+1; } } /* * ECA */ ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&nfree==0), "CQMDebugConstrainedEvalE: unexpected ECAKind", _state); if( s->ecakind==0 ) { /* * Dense ECA */ for(i=0; i<=nfree-1; i++) { v = 0.0; for(j=i; j<=nfree-1; j++) { v = v+s->ecadense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; } result = result+0.5*ae_sqr(v, _state); } } if( s->ecakind==1 ) { /* * Diagonal ECA */ for(i=0; i<=nfree-1; i++) { result = result+0.5*ae_sqr(s->ecadiag.ptr.p_double[i]*s->txc.ptr.p_double[i], _state); } } /* * EQ */ for(i=0; i<=s->k-1; i++) { v = 0.0; for(j=0; j<=nfree-1; j++) { v = v+s->eq.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; } result = result+0.5*ae_sqr(v, _state); } /* * EB */ for(i=0; i<=nfree-1; i++) { result = result+s->eb.ptr.p_double[i]*s->txc.ptr.p_double[i]; } /* * EC */ result = result+s->ec; return result; } /************************************************************************* Internal function, rebuilds "effective" model subject to constraints. Returns False on failure (non-SPD main quadratic term) -- ALGLIB -- Copyright 10.05.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, ae_state *_state) { ae_int_t n; ae_int_t nfree; ae_int_t k; ae_int_t i; ae_int_t j; ae_int_t ridx0; ae_int_t ridx1; ae_int_t cidx0; ae_int_t cidx1; double v; ae_bool result; if( ae_fp_eq(s->alpha,(double)(0))&&ae_fp_eq(s->tau,(double)(0)) ) { /* * Non-SPD model, quick exit */ result = ae_false; return result; } result = ae_true; n = s->n; k = s->k; /* * Determine number of free variables. * Fill TXC - array whose last N-NFree elements store constraints. */ if( s->isactivesetchanged ) { s->nfree = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { s->nfree = s->nfree+1; } } j = s->nfree; for(i=0; i<=n-1; i++) { if( s->activeset.ptr.p_bool[i] ) { s->txc.ptr.p_double[j] = s->xc.ptr.p_double[i]; j = j+1; } } } nfree = s->nfree; /* * Re-evaluate TQ2/TQ1/TQ0, if needed */ if( s->isactivesetchanged||s->ismaintermchanged ) { /* * Handle cases Alpha>0 and Alpha=0 separately: * * in the first case we have dense matrix * * in the second one we have diagonal matrix, which can be * handled more efficiently */ if( ae_fp_greater(s->alpha,(double)(0)) ) { /* * Alpha>0, dense QP * * Split variables into two groups - free (F) and constrained (C). Reorder * variables in such way that free vars come first, constrained are last: * x = [xf, xc]. * * Main quadratic term x'*(alpha*A+tau*D)*x now splits into quadratic part, * linear part and constant part: * ( alpha*Aff+tau*Df alpha*Afc ) ( xf ) * 0.5*( xf' xc' )*( )*( ) = * ( alpha*Acf alpha*Acc+tau*Dc ) ( xc ) * * = 0.5*xf'*(alpha*Aff+tau*Df)*xf + (alpha*Afc*xc)'*xf + 0.5*xc'(alpha*Acc+tau*Dc)*xc * * We store these parts into temporary variables: * * alpha*Aff+tau*Df, alpha*Afc, alpha*Acc+tau*Dc are stored into upper * triangle of TQ2 * * alpha*Afc*xc is stored into TQ1 * * 0.5*xc'(alpha*Acc+tau*Dc)*xc is stored into TQ0 * * Below comes first part of the work - generation of TQ2: * * we pass through rows of A and copy I-th row into upper block (Aff/Afc) or * lower one (Acf/Acc) of TQ2, depending on presence of X[i] in the active set. * RIdx0 variable contains current position for insertion into upper block, * RIdx1 contains current position for insertion into lower one. * * within each row, we copy J-th element into left half (Aff/Acf) or right * one (Afc/Acc), depending on presence of X[j] in the active set. CIdx0 * contains current position for insertion into left block, CIdx1 contains * position for insertion into right one. * * during copying, we multiply elements by alpha and add diagonal matrix D. */ ridx0 = 0; ridx1 = s->nfree; for(i=0; i<=n-1; i++) { cidx0 = 0; cidx1 = s->nfree; for(j=0; j<=n-1; j++) { if( !s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) { /* * Element belongs to Aff */ v = s->alpha*s->a.ptr.pp_double[i][j]; if( i==j&&ae_fp_greater(s->tau,(double)(0)) ) { v = v+s->tau*s->d.ptr.p_double[i]; } s->tq2dense.ptr.pp_double[ridx0][cidx0] = v; } if( !s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) { /* * Element belongs to Afc */ s->tq2dense.ptr.pp_double[ridx0][cidx1] = s->alpha*s->a.ptr.pp_double[i][j]; } if( s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) { /* * Element belongs to Acf */ s->tq2dense.ptr.pp_double[ridx1][cidx0] = s->alpha*s->a.ptr.pp_double[i][j]; } if( s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) { /* * Element belongs to Acc */ v = s->alpha*s->a.ptr.pp_double[i][j]; if( i==j&&ae_fp_greater(s->tau,(double)(0)) ) { v = v+s->tau*s->d.ptr.p_double[i]; } s->tq2dense.ptr.pp_double[ridx1][cidx1] = v; } if( s->activeset.ptr.p_bool[j] ) { cidx1 = cidx1+1; } else { cidx0 = cidx0+1; } } if( s->activeset.ptr.p_bool[i] ) { ridx1 = ridx1+1; } else { ridx0 = ridx0+1; } } /* * Now we have TQ2, and we can evaluate TQ1. * In the special case when we have Alpha=0, NFree=0 or NFree=N, * TQ1 is filled by zeros. */ for(i=0; i<=n-1; i++) { s->tq1.ptr.p_double[i] = 0.0; } if( s->nfree>0&&s->nfreenfree, n-s->nfree, &s->tq2dense, 0, s->nfree, 0, &s->txc, s->nfree, &s->tq1, 0, _state); } /* * And finally, we evaluate TQ0. */ v = 0.0; for(i=s->nfree; i<=n-1; i++) { for(j=s->nfree; j<=n-1; j++) { v = v+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; } } s->tq0 = v; } else { /* * Alpha=0, diagonal QP * * Split variables into two groups - free (F) and constrained (C). Reorder * variables in such way that free vars come first, constrained are last: * x = [xf, xc]. * * Main quadratic term x'*(tau*D)*x now splits into quadratic and constant * parts: * ( tau*Df ) ( xf ) * 0.5*( xf' xc' )*( )*( ) = * ( tau*Dc ) ( xc ) * * = 0.5*xf'*(tau*Df)*xf + 0.5*xc'(tau*Dc)*xc * * We store these parts into temporary variables: * * tau*Df is stored in TQ2Diag * * 0.5*xc'(tau*Dc)*xc is stored into TQ0 */ s->tq0 = 0.0; ridx0 = 0; for(i=0; i<=n-1; i++) { if( !s->activeset.ptr.p_bool[i] ) { s->tq2diag.ptr.p_double[ridx0] = s->tau*s->d.ptr.p_double[i]; ridx0 = ridx0+1; } else { s->tq0 = s->tq0+0.5*s->tau*s->d.ptr.p_double[i]*ae_sqr(s->xc.ptr.p_double[i], _state); } } for(i=0; i<=n-1; i++) { s->tq1.ptr.p_double[i] = 0.0; } } } /* * Re-evaluate TK2/TK1/TK0, if needed */ if( s->isactivesetchanged||s->issecondarytermchanged ) { /* * Split variables into two groups - free (F) and constrained (C). Reorder * variables in such way that free vars come first, constrained are last: * x = [xf, xc]. * * Secondary term theta*(Q*x-r)'*(Q*x-r) now splits into quadratic part, * linear part and constant part: * ( ( xf ) )' ( ( xf ) ) * 0.5*theta*( (Qf Qc)'*( ) - r ) * ( (Qf Qc)'*( ) - r ) = * ( ( xc ) ) ( ( xc ) ) * * = 0.5*theta*xf'*(Qf'*Qf)*xf + theta*((Qc*xc-r)'*Qf)*xf + * + theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) * * We store these parts into temporary variables: * * sqrt(theta)*Qf is stored into TK2 * * theta*((Qc*xc-r)'*Qf) is stored into TK1 * * theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) is stored into TK0 * * We use several other temporaries to store intermediate results: * * Tmp0 - to store Qc*xc-r * * Tmp1 - to store Qc*xc * * Generation of TK2/TK1/TK0 is performed as follows: * * we fill TK2/TK1/TK0 (to handle K=0 or Theta=0) * * other steps are performed only for K>0 and Theta>0 * * we pass through columns of Q and copy I-th column into left block (Qf) or * right one (Qc) of TK2, depending on presence of X[i] in the active set. * CIdx0 variable contains current position for insertion into upper block, * CIdx1 contains current position for insertion into lower one. * * we calculate Qc*xc-r and store it into Tmp0 * * we calculate TK0 and TK1 * * we multiply leading part of TK2 which stores Qf by sqrt(theta) * it is important to perform this step AFTER calculation of TK0 and TK1, * because we need original (non-modified) Qf to calculate TK0 and TK1. */ for(j=0; j<=n-1; j++) { for(i=0; i<=k-1; i++) { s->tk2.ptr.pp_double[i][j] = 0.0; } s->tk1.ptr.p_double[j] = 0.0; } s->tk0 = 0.0; if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) { /* * Split Q into Qf and Qc * Calculate Qc*xc-r, store in Tmp0 */ rvectorsetlengthatleast(&s->tmp0, k, _state); rvectorsetlengthatleast(&s->tmp1, k, _state); cidx0 = 0; cidx1 = nfree; for(i=0; i<=k-1; i++) { s->tmp1.ptr.p_double[i] = 0.0; } for(j=0; j<=n-1; j++) { if( s->activeset.ptr.p_bool[j] ) { for(i=0; i<=k-1; i++) { s->tk2.ptr.pp_double[i][cidx1] = s->q.ptr.pp_double[i][j]; s->tmp1.ptr.p_double[i] = s->tmp1.ptr.p_double[i]+s->q.ptr.pp_double[i][j]*s->txc.ptr.p_double[cidx1]; } cidx1 = cidx1+1; } else { for(i=0; i<=k-1; i++) { s->tk2.ptr.pp_double[i][cidx0] = s->q.ptr.pp_double[i][j]; } cidx0 = cidx0+1; } } for(i=0; i<=k-1; i++) { s->tmp0.ptr.p_double[i] = s->tmp1.ptr.p_double[i]-s->r.ptr.p_double[i]; } /* * Calculate TK0 */ v = 0.0; for(i=0; i<=k-1; i++) { v = v+s->theta*(0.5*ae_sqr(s->tmp1.ptr.p_double[i], _state)-s->r.ptr.p_double[i]*s->tmp0.ptr.p_double[i]-0.5*ae_sqr(s->r.ptr.p_double[i], _state)); } s->tk0 = v; /* * Calculate TK1 */ if( nfree>0 ) { for(i=0; i<=k-1; i++) { v = s->theta*s->tmp0.ptr.p_double[i]; ae_v_addd(&s->tk1.ptr.p_double[0], 1, &s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); } } /* * Calculate TK2 */ if( nfree>0 ) { v = ae_sqrt(s->theta, _state); for(i=0; i<=k-1; i++) { ae_v_muld(&s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); } } } } /* * Re-evaluate TB */ if( s->isactivesetchanged||s->islineartermchanged ) { ridx0 = 0; ridx1 = nfree; for(i=0; i<=n-1; i++) { if( s->activeset.ptr.p_bool[i] ) { s->tb.ptr.p_double[ridx1] = s->b.ptr.p_double[i]; ridx1 = ridx1+1; } else { s->tb.ptr.p_double[ridx0] = s->b.ptr.p_double[i]; ridx0 = ridx0+1; } } } /* * Compose ECA: either dense ECA or diagonal ECA */ if( (s->isactivesetchanged||s->ismaintermchanged)&&nfree>0 ) { if( ae_fp_greater(s->alpha,(double)(0)) ) { /* * Dense ECA */ s->ecakind = 0; for(i=0; i<=nfree-1; i++) { for(j=i; j<=nfree-1; j++) { s->ecadense.ptr.pp_double[i][j] = s->tq2dense.ptr.pp_double[i][j]; } } if( !spdmatrixcholeskyrec(&s->ecadense, 0, nfree, ae_true, &s->tmp0, _state) ) { result = ae_false; return result; } } else { /* * Diagonal ECA */ s->ecakind = 1; for(i=0; i<=nfree-1; i++) { if( ae_fp_less(s->tq2diag.ptr.p_double[i],(double)(0)) ) { result = ae_false; return result; } s->ecadiag.ptr.p_double[i] = ae_sqrt(s->tq2diag.ptr.p_double[i], _state); } } } /* * Compose EQ */ if( s->isactivesetchanged||s->issecondarytermchanged ) { for(i=0; i<=k-1; i++) { for(j=0; j<=nfree-1; j++) { s->eq.ptr.pp_double[i][j] = s->tk2.ptr.pp_double[i][j]; } } } /* * Calculate ECCM */ if( ((((s->isactivesetchanged||s->ismaintermchanged)||s->issecondarytermchanged)&&s->k>0)&&ae_fp_greater(s->theta,(double)(0)))&&nfree>0 ) { /* * Calculate ECCM - Cholesky factor of the "effective" capacitance * matrix CM = I + EQ*inv(EffectiveA)*EQ'. * * We calculate CM as follows: * CM = I + EQ*inv(EffectiveA)*EQ' * = I + EQ*ECA^(-1)*ECA^(-T)*EQ' * = I + (EQ*ECA^(-1))*(EQ*ECA^(-1))' * * Then we perform Cholesky decomposition of CM. */ rmatrixsetlengthatleast(&s->tmp2, k, n, _state); rmatrixcopy(k, nfree, &s->eq, 0, 0, &s->tmp2, 0, 0, _state); ae_assert(s->ecakind==0||s->ecakind==1, "CQMRebuild: unexpected ECAKind", _state); if( s->ecakind==0 ) { rmatrixrighttrsm(k, nfree, &s->ecadense, 0, 0, ae_true, ae_false, 0, &s->tmp2, 0, 0, _state); } if( s->ecakind==1 ) { for(i=0; i<=k-1; i++) { for(j=0; j<=nfree-1; j++) { s->tmp2.ptr.pp_double[i][j] = s->tmp2.ptr.pp_double[i][j]/s->ecadiag.ptr.p_double[j]; } } } for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { s->eccm.ptr.pp_double[i][j] = 0.0; } s->eccm.ptr.pp_double[i][i] = 1.0; } rmatrixsyrk(k, nfree, 1.0, &s->tmp2, 0, 0, 0, 1.0, &s->eccm, 0, 0, ae_true, _state); if( !spdmatrixcholeskyrec(&s->eccm, 0, k, ae_true, &s->tmp0, _state) ) { result = ae_false; return result; } } /* * Compose EB and EC * * NOTE: because these quantities are cheap to compute, we do not * use caching here. */ for(i=0; i<=nfree-1; i++) { s->eb.ptr.p_double[i] = s->tq1.ptr.p_double[i]+s->tk1.ptr.p_double[i]+s->tb.ptr.p_double[i]; } s->ec = s->tq0+s->tk0; for(i=nfree; i<=n-1; i++) { s->ec = s->ec+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; } /* * Change cache status - everything is cached */ s->ismaintermchanged = ae_false; s->issecondarytermchanged = ae_false; s->islineartermchanged = ae_false; s->isactivesetchanged = ae_false; return result; } /************************************************************************* Internal function, solves system Effective_A*x = b. It should be called after successful completion of CQMRebuild(). INPUT PARAMETERS: S - quadratic model, after call to CQMRebuild() X - right part B, array[S.NFree] Tmp - temporary array, automatically reallocated if needed OUTPUT PARAMETERS: X - solution, array[S.NFree] NOTE: when called with zero S.NFree, returns silently NOTE: this function assumes that EA is non-degenerate -- ALGLIB -- Copyright 10.05.2011 by Bochkanov Sergey *************************************************************************/ static void cqmodels_cqmsolveea(convexquadraticmodel* s, /* Real */ ae_vector* x, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&s->nfree==0), "CQMSolveEA: unexpected ECAKind", _state); if( s->ecakind==0 ) { /* * Dense ECA, use FBLSCholeskySolve() dense solver. */ fblscholeskysolve(&s->ecadense, 1.0, s->nfree, ae_true, x, tmp, _state); } if( s->ecakind==1 ) { /* * Diagonal ECA */ for(i=0; i<=s->nfree-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]/ae_sqr(s->ecadiag.ptr.p_double[i], _state); } } } void _convexquadraticmodel_init(void* _p, ae_state *_state) { convexquadraticmodel *p = (convexquadraticmodel*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->a, 0, 0, DT_REAL, _state); ae_matrix_init(&p->q, 0, 0, DT_REAL, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->r, 0, DT_REAL, _state); ae_vector_init(&p->xc, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->activeset, 0, DT_BOOL, _state); ae_matrix_init(&p->tq2dense, 0, 0, DT_REAL, _state); ae_matrix_init(&p->tk2, 0, 0, DT_REAL, _state); ae_vector_init(&p->tq2diag, 0, DT_REAL, _state); ae_vector_init(&p->tq1, 0, DT_REAL, _state); ae_vector_init(&p->tk1, 0, DT_REAL, _state); ae_vector_init(&p->txc, 0, DT_REAL, _state); ae_vector_init(&p->tb, 0, DT_REAL, _state); ae_matrix_init(&p->ecadense, 0, 0, DT_REAL, _state); ae_matrix_init(&p->eq, 0, 0, DT_REAL, _state); ae_matrix_init(&p->eccm, 0, 0, DT_REAL, _state); ae_vector_init(&p->ecadiag, 0, DT_REAL, _state); ae_vector_init(&p->eb, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmp1, 0, DT_REAL, _state); ae_vector_init(&p->tmpg, 0, DT_REAL, _state); ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state); } void _convexquadraticmodel_init_copy(void* _dst, void* _src, ae_state *_state) { convexquadraticmodel *dst = (convexquadraticmodel*)_dst; convexquadraticmodel *src = (convexquadraticmodel*)_src; dst->n = src->n; dst->k = src->k; dst->alpha = src->alpha; dst->tau = src->tau; dst->theta = src->theta; ae_matrix_init_copy(&dst->a, &src->a, _state); ae_matrix_init_copy(&dst->q, &src->q, _state); ae_vector_init_copy(&dst->b, &src->b, _state); ae_vector_init_copy(&dst->r, &src->r, _state); ae_vector_init_copy(&dst->xc, &src->xc, _state); ae_vector_init_copy(&dst->d, &src->d, _state); ae_vector_init_copy(&dst->activeset, &src->activeset, _state); ae_matrix_init_copy(&dst->tq2dense, &src->tq2dense, _state); ae_matrix_init_copy(&dst->tk2, &src->tk2, _state); ae_vector_init_copy(&dst->tq2diag, &src->tq2diag, _state); ae_vector_init_copy(&dst->tq1, &src->tq1, _state); ae_vector_init_copy(&dst->tk1, &src->tk1, _state); dst->tq0 = src->tq0; dst->tk0 = src->tk0; ae_vector_init_copy(&dst->txc, &src->txc, _state); ae_vector_init_copy(&dst->tb, &src->tb, _state); dst->nfree = src->nfree; dst->ecakind = src->ecakind; ae_matrix_init_copy(&dst->ecadense, &src->ecadense, _state); ae_matrix_init_copy(&dst->eq, &src->eq, _state); ae_matrix_init_copy(&dst->eccm, &src->eccm, _state); ae_vector_init_copy(&dst->ecadiag, &src->ecadiag, _state); ae_vector_init_copy(&dst->eb, &src->eb, _state); dst->ec = src->ec; ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state); ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state); ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state); dst->ismaintermchanged = src->ismaintermchanged; dst->issecondarytermchanged = src->issecondarytermchanged; dst->islineartermchanged = src->islineartermchanged; dst->isactivesetchanged = src->isactivesetchanged; } void _convexquadraticmodel_clear(void* _p) { convexquadraticmodel *p = (convexquadraticmodel*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->a); ae_matrix_clear(&p->q); ae_vector_clear(&p->b); ae_vector_clear(&p->r); ae_vector_clear(&p->xc); ae_vector_clear(&p->d); ae_vector_clear(&p->activeset); ae_matrix_clear(&p->tq2dense); ae_matrix_clear(&p->tk2); ae_vector_clear(&p->tq2diag); ae_vector_clear(&p->tq1); ae_vector_clear(&p->tk1); ae_vector_clear(&p->txc); ae_vector_clear(&p->tb); ae_matrix_clear(&p->ecadense); ae_matrix_clear(&p->eq); ae_matrix_clear(&p->eccm); ae_vector_clear(&p->ecadiag); ae_vector_clear(&p->eb); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmp1); ae_vector_clear(&p->tmpg); ae_matrix_clear(&p->tmp2); } void _convexquadraticmodel_destroy(void* _p) { convexquadraticmodel *p = (convexquadraticmodel*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->a); ae_matrix_destroy(&p->q); ae_vector_destroy(&p->b); ae_vector_destroy(&p->r); ae_vector_destroy(&p->xc); ae_vector_destroy(&p->d); ae_vector_destroy(&p->activeset); ae_matrix_destroy(&p->tq2dense); ae_matrix_destroy(&p->tk2); ae_vector_destroy(&p->tq2diag); ae_vector_destroy(&p->tq1); ae_vector_destroy(&p->tk1); ae_vector_destroy(&p->txc); ae_vector_destroy(&p->tb); ae_matrix_destroy(&p->ecadense); ae_matrix_destroy(&p->eq); ae_matrix_destroy(&p->eccm); ae_vector_destroy(&p->ecadiag); ae_vector_destroy(&p->eb); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmp1); ae_vector_destroy(&p->tmpg); ae_matrix_destroy(&p->tmp2); } /************************************************************************* This subroutine is used to initialize SNNLS solver. By default, empty NNLS problem is produced, but we allocated enough space to store problems with NSMax+NDMax columns and NRMax rows. It is good place to provide algorithm with initial estimate of the space requirements, although you may underestimate problem size or even pass zero estimates - in this case buffer variables will be resized automatically when you set NNLS problem. Previously allocated buffer variables are reused as much as possible. This function does not clear structure completely, it tries to preserve as much dynamically allocated memory as possible. -- ALGLIB -- Copyright 10.10.2012 by Bochkanov Sergey *************************************************************************/ void snnlsinit(ae_int_t nsmax, ae_int_t ndmax, ae_int_t nrmax, snnlssolver* s, ae_state *_state) { s->ns = 0; s->nd = 0; s->nr = 0; rmatrixsetlengthatleast(&s->densea, nrmax, ndmax, _state); rmatrixsetlengthatleast(&s->tmpca, nrmax, ndmax, _state); rmatrixsetlengthatleast(&s->tmpz, ndmax, ndmax, _state); rvectorsetlengthatleast(&s->b, nrmax, _state); bvectorsetlengthatleast(&s->nnc, nsmax+ndmax, _state); s->debugflops = 0.0; s->debugmaxinnerits = 0; } /************************************************************************* This subroutine is used to set NNLS problem: ( [ 1 | ] [ ] [ ] )^2 ( [ 1 | ] [ ] [ ] ) min ( [ 1 | Ad ] * [ x ] - [ b ] ) s.t. x>=0 ( [ | ] [ ] [ ] ) ( [ | ] [ ] [ ] ) where: * identity matrix has NS*NS size (NS<=NR, NS can be zero) * dense matrix Ad has NR*ND size * b is NR*1 vector * x is (NS+ND)*1 vector * all elements of x are non-negative (this constraint can be removed later by calling SNNLSDropNNC() function) Previously allocated buffer variables are reused as much as possible. After you set problem, you can solve it with SNNLSSolve(). INPUT PARAMETERS: S - SNNLS solver, must be initialized with SNNLSInit() call A - array[NR,ND], dense part of the system B - array[NR], right part NS - size of the sparse part of the system, 0<=NS<=NR ND - size of the dense part of the system, ND>=0 NR - rows count, NR>0 NOTE: 1. You can have NS+ND=0, solver will correctly accept such combination and return empty array as problem solution. -- ALGLIB -- Copyright 10.10.2012 by Bochkanov Sergey *************************************************************************/ void snnlssetproblem(snnlssolver* s, /* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t ns, ae_int_t nd, ae_int_t nr, ae_state *_state) { ae_int_t i; ae_assert(nd>=0, "SNNLSSetProblem: ND<0", _state); ae_assert(ns>=0, "SNNLSSetProblem: NS<0", _state); ae_assert(nr>0, "SNNLSSetProblem: NR<=0", _state); ae_assert(ns<=nr, "SNNLSSetProblem: NS>NR", _state); ae_assert(a->rows>=nr||nd==0, "SNNLSSetProblem: rows(A)cols>=nd, "SNNLSSetProblem: cols(A)cnt>=nr, "SNNLSSetProblem: length(B)ns = ns; s->nd = nd; s->nr = nr; if( nd>0 ) { rmatrixsetlengthatleast(&s->densea, nr, nd, _state); for(i=0; i<=nr-1; i++) { ae_v_move(&s->densea.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,nd-1)); } } rvectorsetlengthatleast(&s->b, nr, _state); ae_v_move(&s->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nr-1)); bvectorsetlengthatleast(&s->nnc, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { s->nnc.ptr.p_bool[i] = ae_true; } } /************************************************************************* This subroutine drops non-negativity constraint from the problem set by SNNLSSetProblem() call. This function must be called AFTER problem is set, because each SetProblem() call resets constraints to their default state (all constraints are present). INPUT PARAMETERS: S - SNNLS solver, must be initialized with SNNLSInit() call, problem must be set with SNNLSSetProblem() call. Idx - constraint index, 0<=IDX=0, "SNNLSDropNNC: Idx<0", _state); ae_assert(idxns+s->nd, "SNNLSDropNNC: Idx>=NS+ND", _state); s->nnc.ptr.p_bool[idx] = ae_false; } /************************************************************************* This subroutine is used to solve NNLS problem. INPUT PARAMETERS: S - SNNLS solver, must be initialized with SNNLSInit() call and problem must be set up with SNNLSSetProblem() call. X - possibly preallocated buffer, automatically resized if needed OUTPUT PARAMETERS: X - array[NS+ND], solution NOTE: 1. You can have NS+ND=0, solver will correctly accept such combination and return empty array as problem solution. 2. Internal field S.DebugFLOPS contains rough estimate of FLOPs used to solve problem. It can be used for debugging purposes. This field is real-valued. -- ALGLIB -- Copyright 10.10.2012 by Bochkanov Sergey *************************************************************************/ void snnlssolve(snnlssolver* s, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; ae_int_t ns; ae_int_t nd; ae_int_t nr; ae_bool wasactivation; double lambdav; double v0; double v1; double v; ae_int_t outerits; ae_int_t innerits; ae_int_t maxouterits; double xtol; double kicklength; ae_bool kickneeded; double f0; double f1; double dnrm; ae_int_t actidx; double stp; double stpmax; /* * Prepare */ ns = s->ns; nd = s->nd; nr = s->nr; s->debugflops = 0.0; /* * Handle special cases: * * NS+ND=0 * * ND=0 */ if( ns+nd==0 ) { return; } if( nd==0 ) { rvectorsetlengthatleast(x, ns, _state); for(i=0; i<=ns-1; i++) { x->ptr.p_double[i] = s->b.ptr.p_double[i]; if( s->nnc.ptr.p_bool[i] ) { x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], 0.0, _state); } } return; } /* * Main cycle of BLEIC-SNNLS algorithm. * Below we assume that ND>0. */ rvectorsetlengthatleast(x, ns+nd, _state); rvectorsetlengthatleast(&s->xn, ns+nd, _state); rvectorsetlengthatleast(&s->xp, ns+nd, _state); rvectorsetlengthatleast(&s->g, ns+nd, _state); rvectorsetlengthatleast(&s->d, ns+nd, _state); rvectorsetlengthatleast(&s->r, nr, _state); rvectorsetlengthatleast(&s->diagaa, nd, _state); rvectorsetlengthatleast(&s->regdiag, ns+nd, _state); rvectorsetlengthatleast(&s->dx, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { x->ptr.p_double[i] = 0.0; s->regdiag.ptr.p_double[i] = 1.0; } lambdav = 1.0E6*ae_machineepsilon; maxouterits = 10; outerits = 0; innerits = 0; xtol = 1.0E3*ae_machineepsilon; kicklength = ae_sqrt(ae_minrealnumber, _state); for(;;) { /* * Initial check for correctness of X */ for(i=0; i<=ns+nd-1; i++) { ae_assert(!s->nnc.ptr.p_bool[i]||ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)), "SNNLS: integrity check failed", _state); } /* * Calculate gradient G and constrained descent direction D */ snnls_funcgradu(s, x, &s->r, &s->g, &f0, _state); for(i=0; i<=ns+nd-1; i++) { if( (s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],(double)(0)))&&ae_fp_greater(s->g.ptr.p_double[i],(double)(0)) ) { s->d.ptr.p_double[i] = 0.0; } else { s->d.ptr.p_double[i] = -s->g.ptr.p_double[i]; } } /* * Decide whether we need "kick" stage: special stage * that moves us away from boundary constraints which are * not strictly active (i.e. such constraints that x[i]=0.0 and d[i]>0). * * If we need kick stage, we make a kick - and restart iteration. * If not, after this block we can rely on the fact that * for all x[i]=0.0 we have d[i]=0.0 * * NOTE: we do not increase outer iterations counter here */ kickneeded = ae_false; for(i=0; i<=ns+nd-1; i++) { if( (s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0))&&ae_fp_greater(s->d.ptr.p_double[i],0.0) ) { kickneeded = ae_true; } } if( kickneeded ) { /* * Perform kick. * Restart. * Do not increase iterations counter. */ for(i=0; i<=ns+nd-1; i++) { if( ae_fp_eq(x->ptr.p_double[i],0.0)&&ae_fp_greater(s->d.ptr.p_double[i],0.0) ) { x->ptr.p_double[i] = x->ptr.p_double[i]+kicklength; } } continue; } /* * Newton phase * Reduce problem to constrained triangular form and perform Newton * steps with quick activation of constrants (triangular form is * updated in order to handle changed constraints). */ for(i=0; i<=ns+nd-1; i++) { s->xp.ptr.p_double[i] = x->ptr.p_double[i]; } snnls_trdprepare(s, x, &s->regdiag, lambdav, &s->trdd, &s->trda, &s->tmp0, &s->tmp1, &s->tmp2, &s->tmplq, _state); for(;;) { /* * Skip if debug limit on inner iterations count is turned on. */ if( s->debugmaxinnerits>0&&innerits>=s->debugmaxinnerits ) { break; } /* * Prepare step vector. */ snnls_funcgradu(s, x, &s->r, &s->g, &f0, _state); for(i=0; i<=ns+nd-1; i++) { s->d.ptr.p_double[i] = -s->g.ptr.p_double[i]; if( s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0) ) { s->d.ptr.p_double[i] = 0.0; } } snnls_trdsolve(&s->trdd, &s->trda, ns, nd, &s->d, _state); /* * Perform unconstrained trial step and compare function values. */ for(i=0; i<=ns+nd-1; i++) { s->xn.ptr.p_double[i] = x->ptr.p_double[i]+s->d.ptr.p_double[i]; } snnls_func(s, &s->xn, &f1, _state); if( ae_fp_greater_eq(f1,f0) ) { break; } /* * Calculate length of D, maximum step and component which is * activated by this step. Break if D is exactly zero. */ dnrm = 0.0; for(i=0; i<=ns+nd-1; i++) { dnrm = dnrm+ae_sqr(s->d.ptr.p_double[i], _state); } dnrm = ae_sqrt(dnrm, _state); actidx = -1; stpmax = 1.0E50; for(i=0; i<=ns+nd-1; i++) { if( s->nnc.ptr.p_bool[i]&&ae_fp_less(s->d.ptr.p_double[i],0.0) ) { v = stpmax; stpmax = safeminposrv(x->ptr.p_double[i], -s->d.ptr.p_double[i], stpmax, _state); if( ae_fp_less(stpmax,v) ) { actidx = i; } } } if( ae_fp_eq(dnrm,0.0) ) { break; } /* * Perform constrained step and update X * and triangular model. */ stp = ae_minreal(1.0, stpmax, _state); for(i=0; i<=ns+nd-1; i++) { v = x->ptr.p_double[i]+stp*s->d.ptr.p_double[i]; if( s->nnc.ptr.p_bool[i] ) { v = ae_maxreal(v, 0.0, _state); } s->xn.ptr.p_double[i] = v; } if( ae_fp_eq(stp,stpmax)&&actidx>=0 ) { s->xn.ptr.p_double[actidx] = 0.0; } wasactivation = ae_false; for(i=0; i<=ns+nd-1; i++) { if( ae_fp_eq(s->xn.ptr.p_double[i],0.0)&&ae_fp_neq(x->ptr.p_double[i],0.0) ) { wasactivation = ae_true; snnls_trdfixvariable(&s->trdd, &s->trda, ns, nd, i, &s->tmpcholesky, _state); } } for(i=0; i<=ns+nd-1; i++) { x->ptr.p_double[i] = s->xn.ptr.p_double[i]; } /* * Increment iterations counter. * Terminate if no constraint was activated. */ inc(&innerits, _state); if( !wasactivation ) { break; } } /* * Update outer iterations counter. * * Break if necessary: * * maximum number of outer iterations performed * * relative change in X is small enough */ inc(&outerits, _state); if( outerits>=maxouterits ) { break; } v = (double)(0); for(i=0; i<=ns+nd-1; i++) { v0 = ae_fabs(s->xp.ptr.p_double[i], _state); v1 = ae_fabs(x->ptr.p_double[i], _state); if( ae_fp_neq(v0,(double)(0))||ae_fp_neq(v1,(double)(0)) ) { v = ae_maxreal(v, ae_fabs(x->ptr.p_double[i]-s->xp.ptr.p_double[i], _state)/ae_maxreal(v0, v1, _state), _state); } } if( ae_fp_less_eq(v,xtol) ) { break; } } } /************************************************************************* This function calculates: * residual vector R = A*x-b * unconstrained gradient vector G * function value F = 0.5*|R|^2 R and G must have at least N elements. -- ALGLIB -- Copyright 15.07.2015 by Bochkanov Sergey *************************************************************************/ static void snnls_funcgradu(snnlssolver* s, /* Real */ ae_vector* x, /* Real */ ae_vector* r, /* Real */ ae_vector* g, double* f, ae_state *_state) { ae_int_t i; ae_int_t nr; ae_int_t nd; ae_int_t ns; double v; *f = 0; nr = s->nr; nd = s->nd; ns = s->ns; *f = 0.0; for(i=0; i<=nr-1; i++) { v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); if( iptr.p_double[i]; } v = v-s->b.ptr.p_double[i]; r->ptr.p_double[i] = v; *f = *f+0.5*v*v; } for(i=0; i<=ns-1; i++) { g->ptr.p_double[i] = r->ptr.p_double[i]; } for(i=ns; i<=ns+nd-1; i++) { g->ptr.p_double[i] = 0.0; } for(i=0; i<=nr-1; i++) { v = r->ptr.p_double[i]; ae_v_addd(&g->ptr.p_double[ns], 1, &s->densea.ptr.pp_double[i][0], 1, ae_v_len(ns,ns+nd-1), v); } } /************************************************************************* This function calculates function value F = 0.5*|R|^2 at X. -- ALGLIB -- Copyright 15.07.2015 by Bochkanov Sergey *************************************************************************/ static void snnls_func(snnlssolver* s, /* Real */ ae_vector* x, double* f, ae_state *_state) { ae_int_t i; ae_int_t nr; ae_int_t nd; ae_int_t ns; double v; *f = 0; nr = s->nr; nd = s->nd; ns = s->ns; *f = 0.0; for(i=0; i<=nr-1; i++) { v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); if( iptr.p_double[i]; } v = v-s->b.ptr.p_double[i]; *f = *f+0.5*v*v; } } static void snnls_trdprepare(snnlssolver* s, /* Real */ ae_vector* x, /* Real */ ae_vector* diag, double lambdav, /* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, /* Real */ ae_vector* tmp0, /* Real */ ae_vector* tmp1, /* Real */ ae_vector* tmp2, /* Real */ ae_matrix* tmplq, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t ns; ae_int_t nd; ae_int_t nr; double v; double cs; double sn; double r; /* * Prepare */ ns = s->ns; nd = s->nd; nr = s->nr; /* * Triangular reduction */ rvectorsetlengthatleast(trdd, ns, _state); rmatrixsetlengthatleast(trda, ns+nd, nd, _state); rmatrixsetlengthatleast(tmplq, nd, nr+nd, _state); for(i=0; i<=ns-1; i++) { /* * Apply rotation to I-th row and corresponding row of * regularizer. Here V is diagonal element of I-th row, * which is set to 1.0 or 0.0 depending on variable * status (constrained or not). */ v = 1.0; if( s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0) ) { v = 0.0; } generaterotation(v, lambdav, &cs, &sn, &r, _state); trdd->ptr.p_double[i] = cs*v+sn*lambdav; for(j=0; j<=nd-1; j++) { v = s->densea.ptr.pp_double[i][j]; trda->ptr.pp_double[i][j] = cs*v; tmplq->ptr.pp_double[j][i] = -sn*v; } } for(j=0; j<=nd-1; j++) { for(i=ns; i<=nr-1; i++) { tmplq->ptr.pp_double[j][i] = s->densea.ptr.pp_double[i][j]; } } for(j=0; j<=nd-1; j++) { if( s->nnc.ptr.p_bool[ns+j]&&ae_fp_eq(x->ptr.p_double[ns+j],0.0) ) { /* * Variable is constrained, entire row is set to zero. */ for(i=0; i<=nr-1; i++) { tmplq->ptr.pp_double[j][i] = 0.0; } for(i=0; i<=ns-1; i++) { trda->ptr.pp_double[i][j] = 0.0; } } } for(i=0; i<=nd-1; i++) { for(j=0; j<=nd-1; j++) { tmplq->ptr.pp_double[j][nr+i] = 0.0; } tmplq->ptr.pp_double[i][nr+i] = lambdav*diag->ptr.p_double[i]; } rvectorsetlengthatleast(tmp0, nr+nd+1, _state); rvectorsetlengthatleast(tmp1, nr+nd+1, _state); rvectorsetlengthatleast(tmp2, nr+nd+1, _state); rmatrixlqbasecase(tmplq, nd, nr+nd, tmp0, tmp1, tmp2, _state); for(i=0; i<=nd-1; i++) { if( ae_fp_less(tmplq->ptr.pp_double[i][i],0.0) ) { for(j=i; j<=nd-1; j++) { tmplq->ptr.pp_double[j][i] = -tmplq->ptr.pp_double[j][i]; } } } for(i=0; i<=nd-1; i++) { for(j=0; j<=i; j++) { trda->ptr.pp_double[ns+j][i] = tmplq->ptr.pp_double[i][j]; } } } static void snnls_trdsolve(/* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, ae_int_t ns, ae_int_t nd, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_int_t j; double v; /* * Solve U'*y=d first. * * This section includes two parts: * * solve diagonal part of U' * * solve dense part of U' */ for(i=0; i<=ns-1; i++) { d->ptr.p_double[i] = d->ptr.p_double[i]/trdd->ptr.p_double[i]; v = d->ptr.p_double[i]; for(j=0; j<=nd-1; j++) { d->ptr.p_double[ns+j] = d->ptr.p_double[ns+j]-v*trda->ptr.pp_double[i][j]; } } for(i=0; i<=nd-1; i++) { d->ptr.p_double[ns+i] = d->ptr.p_double[ns+i]/trda->ptr.pp_double[ns+i][i]; v = d->ptr.p_double[ns+i]; for(j=i+1; j<=nd-1; j++) { d->ptr.p_double[ns+j] = d->ptr.p_double[ns+j]-v*trda->ptr.pp_double[ns+i][j]; } } /* * Solve U*x=y then. * * This section includes two parts: * * solve trailing triangular part of U * * solve combination of diagonal and dense parts of U */ for(i=nd-1; i>=0; i--) { v = 0.0; for(j=i+1; j<=nd-1; j++) { v = v+trda->ptr.pp_double[ns+i][j]*d->ptr.p_double[ns+j]; } d->ptr.p_double[ns+i] = (d->ptr.p_double[ns+i]-v)/trda->ptr.pp_double[ns+i][i]; } for(i=ns-1; i>=0; i--) { v = 0.0; for(j=0; j<=nd-1; j++) { v = v+trda->ptr.pp_double[i][j]*d->ptr.p_double[ns+j]; } d->ptr.p_double[i] = (d->ptr.p_double[i]-v)/trdd->ptr.p_double[i]; } } static void snnls_trdfixvariable(/* Real */ ae_vector* trdd, /* Real */ ae_matrix* trda, ae_int_t ns, ae_int_t nd, ae_int_t idx, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double cs; double sn; double r; double v; double vv; ae_assert(ns>=0, "TRDFixVariable: integrity error", _state); ae_assert(nd>=0, "TRDFixVariable: integrity error", _state); ae_assert(ns+nd>0, "TRDFixVariable: integrity error", _state); ae_assert(idx>=0, "TRDFixVariable: integrity error", _state); ae_assert(idxptr.p_double[idx] = 1.0; return; } for(j=0; j<=nd-1; j++) { /* * Apply first rotation */ tmp->ptr.p_double[j] = trda->ptr.pp_double[idx][j]; trda->ptr.pp_double[idx][j] = 0.0; } trdd->ptr.p_double[idx] = 1.0; for(i=0; i<=nd-1; i++) { if( ae_fp_neq(tmp->ptr.p_double[i],(double)(0)) ) { /* * Apply subsequent rotations with bottom triangular part of A */ generaterotation(trda->ptr.pp_double[ns+i][i], tmp->ptr.p_double[i], &cs, &sn, &r, _state); for(j=i; j<=nd-1; j++) { v = trda->ptr.pp_double[ns+i][j]; vv = tmp->ptr.p_double[j]; trda->ptr.pp_double[ns+i][j] = v*cs+vv*sn; tmp->ptr.p_double[j] = vv*cs-v*sn; } } } } else { /* * We fix variable in the dense part of the model. It means * that prior to fixing we have: * * ( | ) * ( D | ) * ( | ) * (-----| A ) * ( |0 ) * ( |00 ) * ( |000 ) * ( |0000 ) * ( |00000) * * then we replace idx-th column by zeros: * * ( | 0 ) * ( D | 0 ) * ( | 0 ) * (-----|A 0 A) * ( | 0 ) * ( | 0 ) * ( | 0 ) * * and append row with unit element to bottom, in order to * regularize problem * * ( | 0 ) * ( D | 0 ) * ( | 0 ) * (-----|A 0 A) * ( | 0 ) * ( | 0 ) * ( | 0 ) * (00000|00100) <- appended * * and then we nullify this row by applying rotations: * * (D 0 | ) * ( 0 | ) * ( 0 D| ) * (-----| A ) * ( | ) * ( | ) <- first rotation is applied here * ( | ) <- subsequent rotations are applied to rows below * ( 0 | 0 ) <- as result, row becomes zero * * and triangular structure is preserved. */ k = idx-ns; for(i=0; i<=ns+nd-1; i++) { trda->ptr.pp_double[i][k] = 0.0; } for(j=k+1; j<=nd-1; j++) { /* * Apply first rotation */ tmp->ptr.p_double[j] = trda->ptr.pp_double[idx][j]; trda->ptr.pp_double[idx][j] = 0.0; } trda->ptr.pp_double[idx][k] = 1.0; for(i=k+1; i<=nd-1; i++) { if( ae_fp_neq(tmp->ptr.p_double[i],(double)(0)) ) { /* * Apply subsequent rotations with bottom triangular part of A */ generaterotation(trda->ptr.pp_double[ns+i][i], tmp->ptr.p_double[i], &cs, &sn, &r, _state); for(j=i; j<=nd-1; j++) { v = trda->ptr.pp_double[ns+i][j]; vv = tmp->ptr.p_double[j]; trda->ptr.pp_double[ns+i][j] = v*cs+vv*sn; tmp->ptr.p_double[j] = vv*cs-v*sn; } } } } } void _snnlssolver_init(void* _p, ae_state *_state) { snnlssolver *p = (snnlssolver*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->nnc, 0, DT_BOOL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->xp, 0, DT_REAL, _state); ae_matrix_init(&p->tmpz, 0, 0, DT_REAL, _state); ae_matrix_init(&p->tmpca, 0, 0, DT_REAL, _state); ae_matrix_init(&p->tmplq, 0, 0, DT_REAL, _state); ae_matrix_init(&p->trda, 0, 0, DT_REAL, _state); ae_vector_init(&p->trdd, 0, DT_REAL, _state); ae_vector_init(&p->crb, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->dx, 0, DT_REAL, _state); ae_vector_init(&p->diagaa, 0, DT_REAL, _state); ae_vector_init(&p->cb, 0, DT_REAL, _state); ae_vector_init(&p->cx, 0, DT_REAL, _state); ae_vector_init(&p->cborg, 0, DT_REAL, _state); ae_vector_init(&p->tmpcholesky, 0, DT_REAL, _state); ae_vector_init(&p->r, 0, DT_REAL, _state); ae_vector_init(&p->regdiag, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmp1, 0, DT_REAL, _state); ae_vector_init(&p->tmp2, 0, DT_REAL, _state); ae_vector_init(&p->rdtmprowmap, 0, DT_INT, _state); } void _snnlssolver_init_copy(void* _dst, void* _src, ae_state *_state) { snnlssolver *dst = (snnlssolver*)_dst; snnlssolver *src = (snnlssolver*)_src; dst->ns = src->ns; dst->nd = src->nd; dst->nr = src->nr; ae_matrix_init_copy(&dst->densea, &src->densea, _state); ae_vector_init_copy(&dst->b, &src->b, _state); ae_vector_init_copy(&dst->nnc, &src->nnc, _state); dst->debugflops = src->debugflops; dst->debugmaxinnerits = src->debugmaxinnerits; ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->xp, &src->xp, _state); ae_matrix_init_copy(&dst->tmpz, &src->tmpz, _state); ae_matrix_init_copy(&dst->tmpca, &src->tmpca, _state); ae_matrix_init_copy(&dst->tmplq, &src->tmplq, _state); ae_matrix_init_copy(&dst->trda, &src->trda, _state); ae_vector_init_copy(&dst->trdd, &src->trdd, _state); ae_vector_init_copy(&dst->crb, &src->crb, _state); ae_vector_init_copy(&dst->g, &src->g, _state); ae_vector_init_copy(&dst->d, &src->d, _state); ae_vector_init_copy(&dst->dx, &src->dx, _state); ae_vector_init_copy(&dst->diagaa, &src->diagaa, _state); ae_vector_init_copy(&dst->cb, &src->cb, _state); ae_vector_init_copy(&dst->cx, &src->cx, _state); ae_vector_init_copy(&dst->cborg, &src->cborg, _state); ae_vector_init_copy(&dst->tmpcholesky, &src->tmpcholesky, _state); ae_vector_init_copy(&dst->r, &src->r, _state); ae_vector_init_copy(&dst->regdiag, &src->regdiag, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state); ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state); ae_vector_init_copy(&dst->rdtmprowmap, &src->rdtmprowmap, _state); } void _snnlssolver_clear(void* _p) { snnlssolver *p = (snnlssolver*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->densea); ae_vector_clear(&p->b); ae_vector_clear(&p->nnc); ae_vector_clear(&p->xn); ae_vector_clear(&p->xp); ae_matrix_clear(&p->tmpz); ae_matrix_clear(&p->tmpca); ae_matrix_clear(&p->tmplq); ae_matrix_clear(&p->trda); ae_vector_clear(&p->trdd); ae_vector_clear(&p->crb); ae_vector_clear(&p->g); ae_vector_clear(&p->d); ae_vector_clear(&p->dx); ae_vector_clear(&p->diagaa); ae_vector_clear(&p->cb); ae_vector_clear(&p->cx); ae_vector_clear(&p->cborg); ae_vector_clear(&p->tmpcholesky); ae_vector_clear(&p->r); ae_vector_clear(&p->regdiag); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmp1); ae_vector_clear(&p->tmp2); ae_vector_clear(&p->rdtmprowmap); } void _snnlssolver_destroy(void* _p) { snnlssolver *p = (snnlssolver*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->densea); ae_vector_destroy(&p->b); ae_vector_destroy(&p->nnc); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->xp); ae_matrix_destroy(&p->tmpz); ae_matrix_destroy(&p->tmpca); ae_matrix_destroy(&p->tmplq); ae_matrix_destroy(&p->trda); ae_vector_destroy(&p->trdd); ae_vector_destroy(&p->crb); ae_vector_destroy(&p->g); ae_vector_destroy(&p->d); ae_vector_destroy(&p->dx); ae_vector_destroy(&p->diagaa); ae_vector_destroy(&p->cb); ae_vector_destroy(&p->cx); ae_vector_destroy(&p->cborg); ae_vector_destroy(&p->tmpcholesky); ae_vector_destroy(&p->r); ae_vector_destroy(&p->regdiag); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmp1); ae_vector_destroy(&p->tmp2); ae_vector_destroy(&p->rdtmprowmap); } /************************************************************************* This subroutine is used to initialize active set. By default, empty N-variable model with no constraints is generated. Previously allocated buffer variables are reused as much as possible. Two use cases for this object are described below. CASE 1 - STEEPEST DESCENT: SASInit() repeat: SASReactivateConstraints() SASDescentDirection() SASExploreDirection() SASMoveTo() until convergence CASE 1 - PRECONDITIONED STEEPEST DESCENT: SASInit() repeat: SASReactivateConstraintsPrec() SASDescentDirectionPrec() SASExploreDirection() SASMoveTo() until convergence -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasinit(ae_int_t n, sactiveset* s, ae_state *_state) { ae_int_t i; s->n = n; s->algostate = 0; /* * Constraints */ s->constraintschanged = ae_true; s->nec = 0; s->nic = 0; rvectorsetlengthatleast(&s->bndl, n, _state); bvectorsetlengthatleast(&s->hasbndl, n, _state); rvectorsetlengthatleast(&s->bndu, n, _state); bvectorsetlengthatleast(&s->hasbndu, n, _state); for(i=0; i<=n-1; i++) { s->bndl.ptr.p_double[i] = _state->v_neginf; s->bndu.ptr.p_double[i] = _state->v_posinf; s->hasbndl.ptr.p_bool[i] = ae_false; s->hasbndu.ptr.p_bool[i] = ae_false; } /* * current point, scale */ s->hasxc = ae_false; rvectorsetlengthatleast(&s->xc, n, _state); rvectorsetlengthatleast(&s->s, n, _state); rvectorsetlengthatleast(&s->h, n, _state); for(i=0; i<=n-1; i++) { s->xc.ptr.p_double[i] = 0.0; s->s.ptr.p_double[i] = 1.0; s->h.ptr.p_double[i] = 1.0; } /* * Other */ rvectorsetlengthatleast(&s->unitdiagonal, n, _state); for(i=0; i<=n-1; i++) { s->unitdiagonal.ptr.p_double[i] = 1.0; } } /************************************************************************* This function sets scaling coefficients for SAS object. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function During orthogonalization phase, scale is used to calculate drop tolerances (whether vector is significantly non-zero or not). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sassetscale(sactiveset* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(state->algostate==0, "SASSetScale: you may change scale only in modification mode", _state); ae_assert(s->cnt>=state->n, "SASSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "SASSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "SASSetScale: S contains zero elements", _state); } for(i=0; i<=state->n-1; i++) { state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE 1: D[i] should be positive. Exception will be thrown otherwise. NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sassetprecdiag(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(state->algostate==0, "SASSetPrecDiag: you may change preconditioner only in modification mode", _state); ae_assert(d->cnt>=state->n, "SASSetPrecDiag: D is too short", _state); for(i=0; i<=state->n-1; i++) { ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "SASSetPrecDiag: D contains infinite or NAN elements", _state); ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "SASSetPrecDiag: D contains non-positive elements", _state); } for(i=0; i<=state->n-1; i++) { state->h.ptr.p_double[i] = d->ptr.p_double[i]; } } /************************************************************************* This function sets/changes boundary constraints. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sassetbc(sactiveset* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_int_t i; ae_int_t n; ae_assert(state->algostate==0, "SASSetBC: you may change constraints only in modification mode", _state); n = state->n; ae_assert(bndl->cnt>=n, "SASSetBC: Length(BndL)cnt>=n, "SASSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } state->constraintschanged = ae_true; } /************************************************************************* This function sets linear constraints for SAS object. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - SAS structure C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0 NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void sassetlc(sactiveset* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t n; ae_int_t i; ae_assert(state->algostate==0, "SASSetLC: you may change constraints only in modification mode", _state); n = state->n; /* * First, check for errors in the inputs */ ae_assert(k>=0, "SASSetLC: K<0", _state); ae_assert(c->cols>=n+1||k==0, "SASSetLC: Cols(C)rows>=k, "SASSetLC: Rows(C)cnt>=k, "SASSetLC: Length(CT)nec = 0; state->nic = 0; state->constraintschanged = ae_true; return; } /* * Equality constraints are stored first, in the upper * NEC rows of State.CLEIC matrix. Inequality constraints * are stored in the next NIC rows. * * NOTE: we convert inequality constraints to the form * A*x<=b before copying them. */ rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); state->nec = 0; state->nic = 0; for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]==0 ) { ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); state->nec = state->nec+1; } } for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]!=0 ) { if( ct->ptr.p_int[i]>0 ) { ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } else { ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } state->nic = state->nic+1; } } /* * Mark state as changed */ state->constraintschanged = ae_true; } /************************************************************************* Another variation of SASSetLC(), which accepts linear constraints using another representation. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - SAS structure CLEIC - linear constraints, array[NEC+NIC,N+1]. Each row of C represents one constraint: * first N elements correspond to coefficients, * last element corresponds to the right part. First NEC rows store equality constraints, next NIC - are inequality ones. All elements of C (including right part) must be finite. NEC - number of equality constraints, NEC>=0 NIC - number of inequality constraints, NIC>=0 NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void sassetlcx(sactiveset* state, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_assert(state->algostate==0, "SASSetLCX: you may change constraints only in modification mode", _state); n = state->n; /* * First, check for errors in the inputs */ ae_assert(nec>=0, "SASSetLCX: NEC<0", _state); ae_assert(nic>=0, "SASSetLCX: NIC<0", _state); ae_assert(cleic->cols>=n+1||nec+nic==0, "SASSetLCX: Cols(CLEIC)rows>=nec+nic, "SASSetLCX: Rows(CLEIC)cleic, nec+nic, n+1, _state); state->nec = nec; state->nic = nic; for(i=0; i<=nec+nic-1; i++) { for(j=0; j<=n; j++) { state->cleic.ptr.pp_double[i][j] = cleic->ptr.pp_double[i][j]; } } /* * Mark state as changed */ state->constraintschanged = ae_true; } /************************************************************************* This subroutine turns on optimization mode: 1. feasibility in X is enforced (in case X=S.XC and constraints have not changed, algorithm just uses X without any modifications at all) 2. constraints are marked as "candidate" or "inactive" INPUT PARAMETERS: S - active set object X - initial point (candidate), array[N]. It is expected that X contains only finite values (we do not check it). OUTPUT PARAMETERS: S - state is changed X - initial point can be changed to enforce feasibility RESULT: True in case feasible point was found (mode was changed to "optimization") False in case no feasible point was found (mode was not changed) -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ ae_bool sasstartoptimization(sactiveset* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t i; ae_int_t j; double v; ae_bool result; ae_assert(state->algostate==0, "SASStartOptimization: already in optimization mode", _state); result = ae_false; n = state->n; nec = state->nec; nic = state->nic; /* * Enforce feasibility and calculate set of "candidate"/"active" constraints. * Always active equality constraints are marked as "active", all other constraints * are marked as "candidate". */ ivectorsetlengthatleast(&state->activeset, n+nec+nic, _state); for(i=0; i<=n-1; i++) { if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) { if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { return result; } } } ae_v_move(&state->xc.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); if( state->nec+state->nic>0 ) { /* * General linear constraints are present; general code is used. */ rvectorsetlengthatleast(&state->tmp0, n, _state); rvectorsetlengthatleast(&state->tmpfeas, n+state->nic, _state); rmatrixsetlengthatleast(&state->tmpm0, state->nec+state->nic, n+state->nic+1, _state); for(i=0; i<=state->nec+state->nic-1; i++) { ae_v_move(&state->tmpm0.ptr.pp_double[i][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); for(j=n; j<=n+state->nic-1; j++) { state->tmpm0.ptr.pp_double[i][j] = (double)(0); } if( i>=state->nec ) { state->tmpm0.ptr.pp_double[i][n+i-state->nec] = 1.0; } state->tmpm0.ptr.pp_double[i][n+state->nic] = state->cleic.ptr.pp_double[i][n]; } ae_v_move(&state->tmpfeas.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=state->nic-1; i++) { v = ae_v_dotproduct(&state->cleic.ptr.pp_double[i+state->nec][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->tmpfeas.ptr.p_double[i+n] = ae_maxreal(state->cleic.ptr.pp_double[i+state->nec][n]-v, 0.0, _state); } if( !findfeasiblepoint(&state->tmpfeas, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, state->nic, &state->tmpm0, state->nec+state->nic, 1.0E-6, &i, &j, _state) ) { return result; } ae_v_move(&state->xc.ptr.p_double[0], 1, &state->tmpfeas.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->activeset.ptr.p_int[i] = 1; continue; } if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))||(state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i])) ) { state->activeset.ptr.p_int[i] = 0; continue; } state->activeset.ptr.p_int[i] = -1; } for(i=0; i<=state->nec-1; i++) { state->activeset.ptr.p_int[n+i] = 1; } for(i=0; i<=state->nic-1; i++) { if( ae_fp_eq(state->tmpfeas.ptr.p_double[n+i],(double)(0)) ) { state->activeset.ptr.p_int[n+state->nec+i] = 0; } else { state->activeset.ptr.p_int[n+state->nec+i] = -1; } } } else { /* * Only bound constraints are present, quick code can be used */ for(i=0; i<=n-1; i++) { state->activeset.ptr.p_int[i] = -1; if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->activeset.ptr.p_int[i] = 1; state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; continue; } if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; state->activeset.ptr.p_int[i] = 0; continue; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; state->activeset.ptr.p_int[i] = 0; continue; } } } /* * Change state, allocate temporaries */ result = ae_true; state->algostate = 1; state->basisisready = ae_false; state->hasxc = ae_true; rmatrixsetlengthatleast(&state->pbasis, ae_minint(nec+nic, n, _state), n+1, _state); rmatrixsetlengthatleast(&state->ibasis, ae_minint(nec+nic, n, _state), n+1, _state); rmatrixsetlengthatleast(&state->sbasis, ae_minint(nec+nic, n, _state), n+1, _state); return result; } /************************************************************************* This function explores search direction and calculates bound for step as well as information for activation of constraints. INPUT PARAMETERS: State - SAS structure which stores current point and all other active set related information D - descent direction to explore OUTPUT PARAMETERS: StpMax - upper limit on step length imposed by yet inactive constraints. Can be zero in case some constraints can be activated by zero step. Equal to some large value in case step is unlimited. CIdx - -1 for unlimited step, in [0,N+NEC+NIC) in case of limited step. VVal - value which is assigned to X[CIdx] during activation. For CIdx<0 or CIdx>=N some dummy value is assigned to this parameter. *************************************************************************/ void sasexploredirection(sactiveset* state, /* Real */ ae_vector* d, double* stpmax, ae_int_t* cidx, double* vval, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t i; double prevmax; double vc; double vd; *stpmax = 0; *cidx = 0; *vval = 0; ae_assert(state->algostate==1, "SASExploreDirection: is not in optimization mode", _state); n = state->n; nec = state->nec; nic = state->nic; *cidx = -1; *vval = (double)(0); *stpmax = 1.0E50; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]<=0 ) { ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(d->ptr.p_double[i],(double)(0)) ) { prevmax = *stpmax; *stpmax = safeminposrv(state->xc.ptr.p_double[i]-state->bndl.ptr.p_double[i], -d->ptr.p_double[i], *stpmax, _state); if( ae_fp_less(*stpmax,prevmax) ) { *cidx = i; *vval = state->bndl.ptr.p_double[i]; } } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(d->ptr.p_double[i],(double)(0)) ) { prevmax = *stpmax; *stpmax = safeminposrv(state->bndu.ptr.p_double[i]-state->xc.ptr.p_double[i], d->ptr.p_double[i], *stpmax, _state); if( ae_fp_less(*stpmax,prevmax) ) { *cidx = i; *vval = state->bndu.ptr.p_double[i]; } } } } for(i=nec; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]<=0 ) { vc = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); vc = vc-state->cleic.ptr.pp_double[i][n]; vd = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_less_eq(vd,(double)(0)) ) { continue; } if( ae_fp_less(vc,(double)(0)) ) { /* * XC is strictly feasible with respect to I-th constraint, * we can perform non-zero step because there is non-zero distance * between XC and bound. */ prevmax = *stpmax; *stpmax = safeminposrv(-vc, vd, *stpmax, _state); if( ae_fp_less(*stpmax,prevmax) ) { *cidx = n+i; } } else { /* * XC is at the boundary (or slightly beyond it), and step vector * points beyond the boundary. * * The only thing we can do is to perform zero step and activate * I-th constraint. */ *stpmax = (double)(0); *cidx = n+i; } } } } /************************************************************************* This subroutine moves current point to XN, which can be: a) point in the direction previously explored with SASExploreDirection() function (in this case NeedAct/CIdx/CVal are used) b) point in arbitrary direction, not necessarily previously checked with SASExploreDirection() function. Step may activate one constraint. It is assumed than XN is approximately feasible (small error as large as several ulps is possible). Strict feasibility with respect to bound constraints is enforced during activation, feasibility with respect to general linear constraints is not enforced. This function activates boundary constraints, such that both is True: 1) XC[I] is not at the boundary 2) XN[I] is at the boundary or beyond it INPUT PARAMETERS: S - active set object XN - new point. NeedAct - True in case one constraint needs activation CIdx - index of constraint, in [0,N+NEC+NIC). Ignored if NeedAct is false. This value is calculated by SASExploreDirection(). CVal - for CIdx in [0,N) this field stores value which is assigned to XC[CIdx] during activation. CVal is ignored in other cases. This value is calculated by SASExploreDirection(). OUTPUT PARAMETERS: S - current point and list of active constraints are changed. RESULT: >0, in case at least one inactive non-candidate constraint was activated =0, in case only "candidate" constraints were activated <0, in case no constraints were activated by the step NOTE: in general case State.XC<>XN because activation of constraints may slightly change current point (to enforce feasibility). -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ ae_int_t sasmoveto(sactiveset* state, /* Real */ ae_vector* xn, ae_bool needact, ae_int_t cidx, double cval, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t i; ae_bool wasactivation; ae_int_t result; ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); n = state->n; nec = state->nec; nic = state->nic; /* * Save previous state, update current point */ rvectorsetlengthatleast(&state->mtx, n, _state); ivectorsetlengthatleast(&state->mtas, n+nec+nic, _state); for(i=0; i<=n-1; i++) { state->mtx.ptr.p_double[i] = state->xc.ptr.p_double[i]; state->xc.ptr.p_double[i] = xn->ptr.p_double[i]; } for(i=0; i<=n+nec+nic-1; i++) { state->mtas.ptr.p_int[i] = state->activeset.ptr.p_int[i]; } /* * Activate constraints */ wasactivation = ae_false; if( needact ) { /* * Activation */ ae_assert(cidx>=0&&cidxxc.ptr.p_double[cidx] = cval; } state->activeset.ptr.p_int[cidx] = 1; wasactivation = ae_true; } for(i=0; i<=n-1; i++) { /* * Post-check (some constraints may be activated because of numerical errors) */ if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; state->activeset.ptr.p_int[i] = 1; wasactivation = ae_true; } if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; state->activeset.ptr.p_int[i] = 1; wasactivation = ae_true; } } /* * Determine return status: * * -1 in case no constraints were activated * * 0 in case only "candidate" constraints were activated * * +1 in case at least one "non-candidate" constraint was activated */ if( wasactivation ) { /* * Step activated one/several constraints, but sometimes it is spurious * activation - RecalculateConstraints() tells us that constraint is * inactive (negative Largrange multiplier), but step activates it * because of numerical noise. * * This block of code checks whether step activated truly new constraints * (ones which were not in the active set at the solution): * * * for non-boundary constraint it is enough to check that previous value * of ActiveSet[i] is negative (=far from boundary), and new one is * positive (=we are at the boundary, constraint is activated). * * * for boundary constraints previous criterion won't work. Each variable * has two constraints, and simply checking their status is not enough - * we have to correctly identify cases when we leave one boundary * (PrevActiveSet[i]=0) and move to another boundary (ActiveSet[i]>0). * Such cases can be identified if we compare previous X with new X. * * In case only "candidate" constraints were activated, result variable * is set to 0. In case at least one new constraint was activated, result * is set to 1. */ result = 0; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>0&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) { result = 1; } } for(i=n; i<=n+state->nec+state->nic-1; i++) { if( state->mtas.ptr.p_int[i]<0&&state->activeset.ptr.p_int[i]>0 ) { result = 1; } } } else { /* * No activation, return -1 */ result = -1; } /* * Invalidate basis */ state->basisisready = ae_false; return result; } /************************************************************************* This subroutine performs immediate activation of one constraint: * "immediate" means that we do not have to move to activate it * in case boundary constraint is activated, we enforce current point to be exactly at the boundary INPUT PARAMETERS: S - active set object CIdx - index of constraint, in [0,N+NEC+NIC). This value is calculated by SASExploreDirection(). CVal - for CIdx in [0,N) this field stores value which is assigned to XC[CIdx] during activation. CVal is ignored in other cases. This value is calculated by SASExploreDirection(). -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasimmediateactivation(sactiveset* state, ae_int_t cidx, double cval, ae_state *_state) { ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); if( cidxn ) { state->xc.ptr.p_double[cidx] = cval; } state->activeset.ptr.p_int[cidx] = 1; state->basisisready = ae_false; } /************************************************************************* This subroutine calculates descent direction subject to current active set. INPUT PARAMETERS: S - active set object G - array[N], gradient D - possibly prealocated buffer; automatically resized if needed. OUTPUT PARAMETERS: D - descent direction projected onto current active set. Components of D which correspond to active boundary constraints are forced to be exactly zero. In case D is non-zero, it is normalized to have unit norm. NOTE: in case active set has N active constraints (or more), descent direction is forced to be exactly zero. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasconstraineddescent(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* d, ae_state *_state) { ae_assert(state->algostate==1, "SASConstrainedDescent: is not in optimization mode", _state); sasrebuildbasis(state, _state); sactivesets_constraineddescent(state, g, &state->unitdiagonal, &state->ibasis, ae_true, d, _state); } /************************************************************************* This subroutine calculates preconditioned descent direction subject to current active set. INPUT PARAMETERS: S - active set object G - array[N], gradient D - possibly prealocated buffer; automatically resized if needed. OUTPUT PARAMETERS: D - descent direction projected onto current active set. Components of D which correspond to active boundary constraints are forced to be exactly zero. In case D is non-zero, it is normalized to have unit norm. NOTE: in case active set has N active constraints (or more), descent direction is forced to be exactly zero. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasconstraineddescentprec(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* d, ae_state *_state) { ae_assert(state->algostate==1, "SASConstrainedDescentPrec: is not in optimization mode", _state); sasrebuildbasis(state, _state); sactivesets_constraineddescent(state, g, &state->h, &state->pbasis, ae_true, d, _state); } /************************************************************************* This subroutine calculates projection of direction vector to current active set. INPUT PARAMETERS: S - active set object D - array[N], direction OUTPUT PARAMETERS: D - direction projected onto current active set. Components of D which correspond to active boundary constraints are forced to be exactly zero. NOTE: in case active set has N active constraints (or more), descent direction is forced to be exactly zero. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasconstraineddirection(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); sasrebuildbasis(state, _state); sactivesets_constraineddescent(state, d, &state->unitdiagonal, &state->ibasis, ae_false, &state->cdtmp, _state); for(i=0; i<=state->n-1; i++) { d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; } } /************************************************************************* This subroutine calculates product of direction vector and preconditioner multiplied subject to current active set. INPUT PARAMETERS: S - active set object D - array[N], direction OUTPUT PARAMETERS: D - preconditioned direction projected onto current active set. Components of D which correspond to active boundary constraints are forced to be exactly zero. NOTE: in case active set has N active constraints (or more), descent direction is forced to be exactly zero. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasconstraineddirectionprec(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); sasrebuildbasis(state, _state); sactivesets_constraineddescent(state, d, &state->h, &state->pbasis, ae_false, &state->cdtmp, _state); for(i=0; i<=state->n-1; i++) { d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; } } /************************************************************************* This subroutine performs correction of some (possibly infeasible) point with respect to a) current active set, b) all boundary constraints, both active and inactive: 0) we calculate L1 penalty term for violation of active linear constraints (one which is returned by SASActiveLCPenalty1() function). 1) first, it performs projection (orthogonal with respect to scale matrix S) of X into current active set: X -> X1. 2) next, we perform projection with respect to ALL boundary constraints which are violated at X1: X1 -> X2. 3) X is replaced by X2. The idea is that this function can preserve and enforce feasibility during optimization, and additional penalty parameter can be used to prevent algo from leaving feasible set because of rounding errors. INPUT PARAMETERS: S - active set object X - array[N], candidate point OUTPUT PARAMETERS: X - "improved" candidate point: a) feasible with respect to all boundary constraints b) feasibility with respect to active set is retained at good level. Penalty - penalty term, which can be added to function value if user wants to penalize violation of constraints (recommended). NOTE: this function is not intended to find exact projection (i.e. best approximation) of X into feasible set. It just improves situation a bit. Regular use of this function will help you to retain feasibility - if you already have something to start with and constrain your steps is such way that the only source of infeasibility are roundoff errors. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sascorrection(sactiveset* state, /* Real */ ae_vector* x, double* penalty, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; double v; *penalty = 0; ae_assert(state->algostate==1, "SASCorrection: is not in optimization mode", _state); sasrebuildbasis(state, _state); n = state->n; rvectorsetlengthatleast(&state->corrtmp, n, _state); /* * Calculate penalty term. */ *penalty = sasactivelcpenalty1(state, x, _state); /* * Perform projection 1. * * This projecton is given by: * * x_proj = x - S*S*As'*(As*x-b) * * where x is original x before projection, S is a scale matrix, * As is a matrix of equality constraints (active set) which were * orthogonalized with respect to inner product given by S (i.e. we * have As*S*S'*As'=I), b is a right part of the orthogonalized * constraints. * * NOTE: you can verify that x_proj is strictly feasible w.r.t. * active set by multiplying it by As - you will get * As*x_proj = As*x - As*x + b = b. * * This formula for projection can be obtained by solving * following minimization problem. * * min ||inv(S)*(x_proj-x)||^2 s.t. As*x_proj=b * */ ae_v_move(&state->corrtmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=state->basissize-1; i++) { v = -state->sbasis.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = v+state->sbasis.ptr.pp_double[i][j]*state->corrtmp.ptr.p_double[j]; } for(j=0; j<=n-1; j++) { state->corrtmp.ptr.p_double[j] = state->corrtmp.ptr.p_double[j]-v*state->sbasis.ptr.pp_double[i][j]*ae_sqr(state->s.ptr.p_double[j], _state); } } for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>0 ) { state->corrtmp.ptr.p_double[i] = state->xc.ptr.p_double[i]; } } /* * Perform projection 2 */ for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = state->corrtmp.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; } } } /************************************************************************* This subroutine returns L1 penalty for violation of active general linear constraints (violation of boundary or inactive linear constraints is not added to penalty). Penalty term is equal to: Penalty = SUM( Abs((C_i*x-R_i)/Alpha_i) ) Here: * summation is performed for I=0...NEC+NIC-1, ActiveSet[N+I]>0 (only for rows of CLEIC which are in active set) * C_i is I-th row of CLEIC * R_i is corresponding right part * S is a scale matrix * Alpha_i = ||S*C_i|| - is a scaling coefficient which "normalizes" I-th summation term according to its scale. INPUT PARAMETERS: S - active set object X - array[N], candidate point -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ double sasactivelcpenalty1(sactiveset* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t nec; ae_int_t nic; double v; double alpha; double p; double result; ae_assert(state->algostate==1, "SASActiveLCPenalty1: is not in optimization mode", _state); sasrebuildbasis(state, _state); n = state->n; nec = state->nec; nic = state->nic; /* * Calculate penalty term. */ result = (double)(0); for(i=0; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]>0 ) { alpha = (double)(0); p = -state->cleic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = state->cleic.ptr.pp_double[i][j]; p = p+v*x->ptr.p_double[j]; alpha = alpha+ae_sqr(v*state->s.ptr.p_double[j], _state); } alpha = ae_sqrt(alpha, _state); if( ae_fp_neq(alpha,(double)(0)) ) { result = result+ae_fabs(p/alpha, _state); } } } return result; } /************************************************************************* This subroutine calculates scaled norm of vector after projection onto subspace of active constraints. Most often this function is used to test stopping conditions. INPUT PARAMETERS: S - active set object D - vector whose norm is calculated RESULT: Vector norm (after projection and scaling) NOTE: projection is performed first, scaling is performed after projection NOTE: if we have N active constraints, zero value (exact zero) is returned -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ double sasscaledconstrainednorm(sactiveset* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_int_t n; double v; ae_int_t nactive; double result; ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); n = state->n; rvectorsetlengthatleast(&state->scntmp, n, _state); /* * Prepare basis (if needed) */ sasrebuildbasis(state, _state); /* * Calculate descent direction */ nactive = 0; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>0 ) { state->scntmp.ptr.p_double[i] = (double)(0); nactive = nactive+1; } else { state->scntmp.ptr.p_double[i] = d->ptr.p_double[i]; } } if( nactive+state->basissize>=n ) { /* * Quick exit if number of active constraints is N or larger */ result = 0.0; return result; } for(i=0; i<=state->basissize-1; i++) { v = ae_v_dotproduct(&state->ibasis.ptr.pp_double[i][0], 1, &state->scntmp.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_subd(&state->scntmp.ptr.p_double[0], 1, &state->ibasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->s.ptr.p_double[i]*state->scntmp.ptr.p_double[i], _state); } result = ae_sqrt(v, _state); return result; } /************************************************************************* This subroutine turns off optimization mode. INPUT PARAMETERS: S - active set object OUTPUT PARAMETERS: S - state is changed NOTE: this function can be called many times for optimizer which was already stopped. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ void sasstopoptimization(sactiveset* state, ae_state *_state) { state->algostate = 0; } /************************************************************************* This function recalculates constraints - activates and deactivates them according to gradient value at current point. Algorithm assumes that we want to make steepest descent step from current point; constraints are activated and deactivated in such way that we won't violate any constraint by steepest descent step. After call to this function active set is ready to try steepest descent step (SASDescentDirection-SASExploreDirection-SASMoveTo). Only already "active" and "candidate" elements of ActiveSet are examined; constraints which are not active are not examined. INPUT PARAMETERS: State - active set object GC - array[N], gradient at XC OUTPUT PARAMETERS: State - active set object, with new set of constraint -- ALGLIB -- Copyright 26.09.2012 by Bochkanov Sergey *************************************************************************/ void sasreactivateconstraints(sactiveset* state, /* Real */ ae_vector* gc, ae_state *_state) { ae_assert(state->algostate==1, "SASReactivateConstraints: must be in optimization mode", _state); sactivesets_reactivateconstraints(state, gc, &state->unitdiagonal, _state); } /************************************************************************* This function recalculates constraints - activates and deactivates them according to gradient value at current point. Algorithm assumes that we want to make Quasi-Newton step from current point with diagonal Quasi-Newton matrix H. Constraints are activated and deactivated in such way that we won't violate any constraint by step. After call to this function active set is ready to try preconditioned steepest descent step (SASDescentDirection-SASExploreDirection-SASMoveTo). Only already "active" and "candidate" elements of ActiveSet are examined; constraints which are not active are not examined. INPUT PARAMETERS: State - active set object GC - array[N], gradient at XC OUTPUT PARAMETERS: State - active set object, with new set of constraint -- ALGLIB -- Copyright 26.09.2012 by Bochkanov Sergey *************************************************************************/ void sasreactivateconstraintsprec(sactiveset* state, /* Real */ ae_vector* gc, ae_state *_state) { ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); sactivesets_reactivateconstraints(state, gc, &state->h, _state); } /************************************************************************* This function builds three orthonormal basises for current active set: * P-orthogonal one, which is orthogonalized with inner product (x,y) = x'*P*y, where P=inv(H) is current preconditioner * S-orthogonal one, which is orthogonalized with inner product (x,y) = x'*S'*S*y, where S is diagonal scaling matrix * I-orthogonal one, which is orthogonalized with standard dot product NOTE: all sets of orthogonal vectors are guaranteed to have same size. P-orthogonal basis is built first, I/S-orthogonal basises are forced to have same number of vectors as P-orthogonal one (padded by zero vectors if needed). NOTE: this function tracks changes in active set; first call will result in reorthogonalization INPUT PARAMETERS: State - active set object H - diagonal preconditioner, H[i]>0 OUTPUT PARAMETERS: State - active set object with new basis -- ALGLIB -- Copyright 20.06.2012 by Bochkanov Sergey *************************************************************************/ void sasrebuildbasis(sactiveset* state, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t i; ae_int_t j; ae_int_t t; ae_int_t nactivelin; ae_int_t nactivebnd; double v; double vmax; ae_int_t kmax; if( state->basisisready ) { return; } n = state->n; nec = state->nec; nic = state->nic; rmatrixsetlengthatleast(&state->tmpbasis, nec+nic, n+1, _state); state->basissize = 0; state->basisisready = ae_true; /* * Determine number of active boundary and non-boundary * constraints, move them to TmpBasis. Quick exit if no * non-boundary constraints were detected. */ nactivelin = 0; nactivebnd = 0; for(i=0; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]>0 ) { nactivelin = nactivelin+1; } } for(j=0; j<=n-1; j++) { if( state->activeset.ptr.p_int[j]>0 ) { nactivebnd = nactivebnd+1; } } if( nactivelin==0 ) { return; } /* * Orthogonalize linear constraints (inner product is given by preconditioner) * with respect to each other and boundary ones: * * normalize all constraints * * orthogonalize with respect to boundary ones * * repeat: * * if basisSize+nactivebnd=n - TERMINATE * * choose largest row from TmpBasis * * if row norm is too small - TERMINATE * * add row to basis, normalize * * remove from TmpBasis, orthogonalize other constraints with respect to this one */ nactivelin = 0; for(i=0; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]>0 ) { ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); nactivelin = nactivelin+1; } } for(i=0; i<=nactivelin-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state)/state->h.ptr.p_double[j]; } if( ae_fp_greater(v,(double)(0)) ) { v = 1/ae_sqrt(v, _state); for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; } } } for(j=0; j<=n-1; j++) { if( state->activeset.ptr.p_int[j]>0 ) { for(i=0; i<=nactivelin-1; i++) { state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; state->tmpbasis.ptr.pp_double[i][j] = 0.0; } } } while(state->basissize+nactivebndtmpbasis.ptr.pp_double[i][j], _state)/state->h.ptr.p_double[j]; } v = ae_sqrt(v, _state); if( ae_fp_greater(v,vmax) ) { vmax = v; kmax = i; } } if( ae_fp_less(vmax,1.0E4*ae_machineepsilon) ) { break; } v = 1/vmax; ae_v_moved(&state->pbasis.ptr.pp_double[state->basissize][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); state->basissize = state->basissize+1; /* * Reorthogonalize other vectors with respect to chosen one. * Remove it from the array. */ for(i=0; i<=nactivelin-1; i++) { if( i!=kmax ) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+state->pbasis.ptr.pp_double[state->basissize-1][j]*state->tmpbasis.ptr.pp_double[i][j]/state->h.ptr.p_double[j]; } ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->pbasis.ptr.pp_double[state->basissize-1][0], 1, ae_v_len(0,n), v); } } for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[kmax][j] = (double)(0); } } /* * Orthogonalize linear constraints using traditional dot product * with respect to each other and boundary ones. * * NOTE: we force basis size to be equal to one which was computed * at the previous step, with preconditioner-based inner product. */ nactivelin = 0; for(i=0; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]>0 ) { ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); nactivelin = nactivelin+1; } } for(i=0; i<=nactivelin-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state); } if( ae_fp_greater(v,(double)(0)) ) { v = 1/ae_sqrt(v, _state); for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; } } } for(j=0; j<=n-1; j++) { if( state->activeset.ptr.p_int[j]>0 ) { for(i=0; i<=nactivelin-1; i++) { state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; state->tmpbasis.ptr.pp_double[i][j] = 0.0; } } } for(t=0; t<=state->basissize-1; t++) { /* * Find largest vector, add to basis. */ vmax = (double)(-1); kmax = -1; for(i=0; i<=nactivelin-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state); } v = ae_sqrt(v, _state); if( ae_fp_greater(v,vmax) ) { vmax = v; kmax = i; } } if( ae_fp_eq(vmax,(double)(0)) ) { for(j=0; j<=n; j++) { state->ibasis.ptr.pp_double[t][j] = 0.0; } continue; } v = 1/vmax; ae_v_moved(&state->ibasis.ptr.pp_double[t][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); /* * Reorthogonalize other vectors with respect to chosen one. * Remove it from the array. */ for(i=0; i<=nactivelin-1; i++) { if( i!=kmax ) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+state->ibasis.ptr.pp_double[t][j]*state->tmpbasis.ptr.pp_double[i][j]; } ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->ibasis.ptr.pp_double[t][0], 1, ae_v_len(0,n), v); } } for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[kmax][j] = (double)(0); } } /* * Orthogonalize linear constraints using inner product given by * scale matrix. * * NOTE: we force basis size to be equal to one which was computed * with preconditioner-based inner product. */ nactivelin = 0; for(i=0; i<=nec+nic-1; i++) { if( state->activeset.ptr.p_int[n+i]>0 ) { ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); nactivelin = nactivelin+1; } } for(i=0; i<=nactivelin-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state); } if( ae_fp_greater(v,(double)(0)) ) { v = 1/ae_sqrt(v, _state); for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; } } } for(j=0; j<=n-1; j++) { if( state->activeset.ptr.p_int[j]>0 ) { for(i=0; i<=nactivelin-1; i++) { state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; state->tmpbasis.ptr.pp_double[i][j] = 0.0; } } } for(t=0; t<=state->basissize-1; t++) { /* * Find largest vector, add to basis. */ vmax = (double)(-1); kmax = -1; for(i=0; i<=nactivelin-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state); } v = ae_sqrt(v, _state); if( ae_fp_greater(v,vmax) ) { vmax = v; kmax = i; } } if( ae_fp_eq(vmax,(double)(0)) ) { for(j=0; j<=n; j++) { state->sbasis.ptr.pp_double[t][j] = 0.0; } continue; } v = 1/vmax; ae_v_moved(&state->sbasis.ptr.pp_double[t][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); /* * Reorthogonalize other vectors with respect to chosen one. * Remove it from the array. */ for(i=0; i<=nactivelin-1; i++) { if( i!=kmax ) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+state->sbasis.ptr.pp_double[t][j]*state->tmpbasis.ptr.pp_double[i][j]*ae_sqr(state->s.ptr.p_double[j], _state); } ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->sbasis.ptr.pp_double[t][0], 1, ae_v_len(0,n), v); } } for(j=0; j<=n; j++) { state->tmpbasis.ptr.pp_double[kmax][j] = (double)(0); } } } /************************************************************************* This subroutine calculates preconditioned descent direction subject to current active set. INPUT PARAMETERS: State - active set object G - array[N], gradient H - array[N], Hessian matrix HA - active constraints orthogonalized in such way that HA*inv(H)*HA'= I. Normalize- whether we need normalized descent or not D - possibly preallocated buffer; automatically resized. OUTPUT PARAMETERS: D - descent direction projected onto current active set. Components of D which correspond to active boundary constraints are forced to be exactly zero. In case D is non-zero and Normalize is True, it is normalized to have unit norm. NOTE: if we have N active constraints, D is explicitly set to zero. -- ALGLIB -- Copyright 21.12.2012 by Bochkanov Sergey *************************************************************************/ static void sactivesets_constraineddescent(sactiveset* state, /* Real */ ae_vector* g, /* Real */ ae_vector* h, /* Real */ ae_matrix* ha, ae_bool normalize, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; double v; ae_int_t nactive; ae_assert(state->algostate==1, "SAS: internal error in ConstrainedDescent() - not in optimization mode", _state); ae_assert(state->basisisready, "SAS: internal error in ConstrainedDescent() - no basis", _state); n = state->n; rvectorsetlengthatleast(d, n, _state); /* * Calculate preconditioned constrained descent direction: * * d := -inv(H)*( g - HA'*(HA*inv(H)*g) ) * * Formula above always gives direction which is orthogonal to rows of HA. * You can verify it by multiplication of both sides by HA[i] (I-th row), * taking into account that HA*inv(H)*HA'= I (by definition of HA - it is * orthogonal basis with inner product given by inv(H)). */ nactive = 0; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>0 ) { d->ptr.p_double[i] = (double)(0); nactive = nactive+1; } else { d->ptr.p_double[i] = g->ptr.p_double[i]; } } for(i=0; i<=state->basissize-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+ha->ptr.pp_double[i][j]*d->ptr.p_double[j]/h->ptr.p_double[j]; } ae_v_subd(&d->ptr.p_double[0], 1, &ha->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); nactive = nactive+1; } v = 0.0; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>0 ) { d->ptr.p_double[i] = (double)(0); } else { d->ptr.p_double[i] = -d->ptr.p_double[i]/h->ptr.p_double[i]; v = v+ae_sqr(d->ptr.p_double[i], _state); } } v = ae_sqrt(v, _state); if( nactive>=n ) { v = (double)(0); for(i=0; i<=n-1; i++) { d->ptr.p_double[i] = (double)(0); } } if( normalize&&ae_fp_greater(v,(double)(0)) ) { for(i=0; i<=n-1; i++) { d->ptr.p_double[i] = d->ptr.p_double[i]/v; } } } /************************************************************************* This function recalculates constraints - activates and deactivates them according to gradient value at current point. Algorithm assumes that we want to make Quasi-Newton step from current point with diagonal Quasi-Newton matrix H. Constraints are activated and deactivated in such way that we won't violate any constraint by step. Only already "active" and "candidate" elements of ActiveSet are examined; constraints which are not active are not examined. INPUT PARAMETERS: State - active set object GC - array[N], gradient at XC H - array[N], Hessian matrix OUTPUT PARAMETERS: State - active set object, with new set of constraint -- ALGLIB -- Copyright 26.09.2012 by Bochkanov Sergey *************************************************************************/ static void sactivesets_reactivateconstraints(sactiveset* state, /* Real */ ae_vector* gc, /* Real */ ae_vector* h, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t i; ae_int_t j; ae_int_t idx0; ae_int_t idx1; double v; ae_int_t nactivebnd; ae_int_t nactivelin; ae_int_t nactiveconstraints; double rowscale; ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); /* * Prepare */ n = state->n; nec = state->nec; nic = state->nic; state->basisisready = ae_false; /* * Handle important special case - no linear constraints, * only boundary constraints are present */ if( nec+nic==0 ) { for(i=0; i<=n-1; i++) { if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->activeset.ptr.p_int[i] = 1; continue; } if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],(double)(0)) ) { state->activeset.ptr.p_int[i] = 1; continue; } if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],(double)(0)) ) { state->activeset.ptr.p_int[i] = 1; continue; } state->activeset.ptr.p_int[i] = -1; } return; } /* * General case. * Allocate temporaries. */ rvectorsetlengthatleast(&state->rctmpg, n, _state); rvectorsetlengthatleast(&state->rctmprightpart, n, _state); rvectorsetlengthatleast(&state->rctmps, n, _state); rmatrixsetlengthatleast(&state->rctmpdense0, n, nec+nic, _state); rmatrixsetlengthatleast(&state->rctmpdense1, n, nec+nic, _state); bvectorsetlengthatleast(&state->rctmpisequality, n+nec+nic, _state); ivectorsetlengthatleast(&state->rctmpconstraintidx, n+nec+nic, _state); /* * Calculate descent direction */ ae_v_moveneg(&state->rctmpg.ptr.p_double[0], 1, &gc->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Determine candidates to the active set. * * After this block constraints become either "inactive" (ActiveSet[i]<0) * or "candidates" (ActiveSet[i]=0). Previously active constraints always * become "candidates". */ for(i=0; i<=n+nec+nic-1; i++) { if( state->activeset.ptr.p_int[i]>0 ) { state->activeset.ptr.p_int[i] = 0; } else { state->activeset.ptr.p_int[i] = -1; } } nactiveconstraints = 0; nactivebnd = 0; nactivelin = 0; for(i=0; i<=n-1; i++) { /* * Activate boundary constraints: * * copy constraint index to RCTmpConstraintIdx * * set corresponding element of ActiveSet[] to "candidate" * * fill RCTmpS by either +1 (lower bound) or -1 (upper bound) * * set RCTmpIsEquality to False (BndLhasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { /* * Equality constraint is activated */ state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; state->activeset.ptr.p_int[i] = 0; state->rctmps.ptr.p_double[i] = 1.0; state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_true; nactiveconstraints = nactiveconstraints+1; nactivebnd = nactivebnd+1; continue; } if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { /* * Lower bound is activated */ state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; state->activeset.ptr.p_int[i] = 0; state->rctmps.ptr.p_double[i] = -1.0; state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; nactiveconstraints = nactiveconstraints+1; nactivebnd = nactivebnd+1; continue; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { /* * Upper bound is activated */ state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; state->activeset.ptr.p_int[i] = 0; state->rctmps.ptr.p_double[i] = 1.0; state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; nactiveconstraints = nactiveconstraints+1; nactivebnd = nactivebnd+1; continue; } } for(i=0; i<=nec+nic-1; i++) { if( i>=nec&&state->activeset.ptr.p_int[n+i]<0 ) { /* * Inequality constraints are skipped if both (a) constraint was * not active, and (b) we are too far away from the boundary. */ rowscale = 0.0; v = -state->cleic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = v+state->cleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; rowscale = ae_maxreal(rowscale, ae_fabs(state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state), _state); } if( ae_fp_less_eq(v,-1.0E5*ae_machineepsilon*rowscale) ) { /* * NOTE: it is important to check for non-strict inequality * because we have to correctly handle zero constraint * 0*x<=0 */ continue; } } ae_v_move(&state->rctmpdense0.ptr.pp_double[0][nactivelin], state->rctmpdense0.stride, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = n+i; state->activeset.ptr.p_int[n+i] = 0; state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ihasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->activeset.ptr.p_int[i] = 1; continue; } if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],(double)(0)) ) { state->activeset.ptr.p_int[i] = 1; continue; } if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],(double)(0)) ) { state->activeset.ptr.p_int[i] = 1; continue; } } return; } /* * General case. * * APPROACH TO CONSTRAINTS ACTIVATION/DEACTIVATION * * We have NActiveConstraints "candidates": NActiveBnd boundary candidates, * NActiveLin linear candidates. Indexes of boundary constraints are stored * in RCTmpConstraintIdx[0:NActiveBnd-1], indexes of linear ones are stored * in RCTmpConstraintIdx[NActiveBnd:NActiveBnd+NActiveLin-1]. Some of the * constraints are equality ones, some are inequality - as specified by * RCTmpIsEquality[i]. * * Now we have to determine active subset of "candidates" set. In order to * do so we solve following constrained minimization problem: * ( )^2 * min ( SUM(lambda[i]*A[i]) + G ) * ( ) * Here: * * G is a gradient (column vector) * * A[i] is a column vector, linear (left) part of I-th constraint. * I=0..NActiveConstraints-1, first NActiveBnd elements of A are just * subset of identity matrix (boundary constraints), next NActiveLin * elements are subset of rows of the matrix of general linear constraints. * * lambda[i] is a Lagrange multiplier corresponding to I-th constraint * * NOTE: for preconditioned setting A is replaced by A*H^(-0.5), G is * replaced by G*H^(-0.5). We apply this scaling at the last stage, * before passing data to NNLS solver. * * Minimization is performed subject to non-negativity constraints on * lambda[i] corresponding to inequality constraints. Inequality constraints * which correspond to non-zero lambda are activated, equality constraints * are always considered active. * * Informally speaking, we "decompose" descent direction -G and represent * it as sum of constraint vectors and "residual" part (which is equal to * the actual descent direction subject to constraints). * * SOLUTION OF THE NNLS PROBLEM * * We solve this optimization problem with Non-Negative Least Squares solver, * which can efficiently solve least squares problems of the form * * ( [ I | AU ] )^2 * min ( [ | ]*x-b ) s.t. non-negativity constraints on some x[i] * ( [ 0 | AL ] ) * * In order to use this solver we have to rearrange rows of A[] and G in * such way that first NActiveBnd columns of A store identity matrix (before * sorting non-zero elements are randomly distributed in the first NActiveBnd * columns of A, during sorting we move them to first NActiveBnd rows). * * Then we create instance of NNLS solver (we reuse instance left from the * previous run of the optimization problem) and solve NNLS problem. */ idx0 = 0; idx1 = nactivebnd; for(i=0; i<=n-1; i++) { if( state->activeset.ptr.p_int[i]>=0 ) { v = 1/ae_sqrt(h->ptr.p_double[i], _state); for(j=0; j<=nactivelin-1; j++) { state->rctmpdense1.ptr.pp_double[idx0][j] = state->rctmpdense0.ptr.pp_double[i][j]/state->rctmps.ptr.p_double[i]*v; } state->rctmprightpart.ptr.p_double[idx0] = state->rctmpg.ptr.p_double[i]/state->rctmps.ptr.p_double[i]*v; idx0 = idx0+1; } else { v = 1/ae_sqrt(h->ptr.p_double[i], _state); for(j=0; j<=nactivelin-1; j++) { state->rctmpdense1.ptr.pp_double[idx1][j] = state->rctmpdense0.ptr.pp_double[i][j]*v; } state->rctmprightpart.ptr.p_double[idx1] = state->rctmpg.ptr.p_double[i]*v; idx1 = idx1+1; } } snnlsinit(n, nec+nic, n, &state->solver, _state); snnlssetproblem(&state->solver, &state->rctmpdense1, &state->rctmprightpart, nactivebnd, nactiveconstraints-nactivebnd, n, _state); for(i=0; i<=nactiveconstraints-1; i++) { if( state->rctmpisequality.ptr.p_bool[i] ) { snnlsdropnnc(&state->solver, i, _state); } } snnlssolve(&state->solver, &state->rctmplambdas, _state); /* * After solution of the problem we activate equality constraints (always active) * and inequality constraints with non-zero Lagrange multipliers. Then we reorthogonalize * active constraints. */ for(i=0; i<=n+nec+nic-1; i++) { state->activeset.ptr.p_int[i] = -1; } for(i=0; i<=nactiveconstraints-1; i++) { if( state->rctmpisequality.ptr.p_bool[i]||ae_fp_greater(state->rctmplambdas.ptr.p_double[i],(double)(0)) ) { state->activeset.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 1; } else { state->activeset.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 0; } } sasrebuildbasis(state, _state); } void _sactiveset_init(void* _p, ae_state *_state) { sactiveset *p = (sactiveset*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->xc, 0, DT_REAL, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->h, 0, DT_REAL, _state); ae_vector_init(&p->activeset, 0, DT_INT, _state); ae_matrix_init(&p->sbasis, 0, 0, DT_REAL, _state); ae_matrix_init(&p->pbasis, 0, 0, DT_REAL, _state); ae_matrix_init(&p->ibasis, 0, 0, DT_REAL, _state); ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state); ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->mtx, 0, DT_REAL, _state); ae_vector_init(&p->mtas, 0, DT_INT, _state); ae_vector_init(&p->cdtmp, 0, DT_REAL, _state); ae_vector_init(&p->corrtmp, 0, DT_REAL, _state); ae_vector_init(&p->unitdiagonal, 0, DT_REAL, _state); _snnlssolver_init(&p->solver, _state); ae_vector_init(&p->scntmp, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmpfeas, 0, DT_REAL, _state); ae_matrix_init(&p->tmpm0, 0, 0, DT_REAL, _state); ae_vector_init(&p->rctmps, 0, DT_REAL, _state); ae_vector_init(&p->rctmpg, 0, DT_REAL, _state); ae_vector_init(&p->rctmprightpart, 0, DT_REAL, _state); ae_matrix_init(&p->rctmpdense0, 0, 0, DT_REAL, _state); ae_matrix_init(&p->rctmpdense1, 0, 0, DT_REAL, _state); ae_vector_init(&p->rctmpisequality, 0, DT_BOOL, _state); ae_vector_init(&p->rctmpconstraintidx, 0, DT_INT, _state); ae_vector_init(&p->rctmplambdas, 0, DT_REAL, _state); ae_matrix_init(&p->tmpbasis, 0, 0, DT_REAL, _state); } void _sactiveset_init_copy(void* _dst, void* _src, ae_state *_state) { sactiveset *dst = (sactiveset*)_dst; sactiveset *src = (sactiveset*)_src; dst->n = src->n; dst->algostate = src->algostate; ae_vector_init_copy(&dst->xc, &src->xc, _state); dst->hasxc = src->hasxc; ae_vector_init_copy(&dst->s, &src->s, _state); ae_vector_init_copy(&dst->h, &src->h, _state); ae_vector_init_copy(&dst->activeset, &src->activeset, _state); dst->basisisready = src->basisisready; ae_matrix_init_copy(&dst->sbasis, &src->sbasis, _state); ae_matrix_init_copy(&dst->pbasis, &src->pbasis, _state); ae_matrix_init_copy(&dst->ibasis, &src->ibasis, _state); dst->basissize = src->basissize; dst->constraintschanged = src->constraintschanged; ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state); ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); dst->nec = src->nec; dst->nic = src->nic; ae_vector_init_copy(&dst->mtx, &src->mtx, _state); ae_vector_init_copy(&dst->mtas, &src->mtas, _state); ae_vector_init_copy(&dst->cdtmp, &src->cdtmp, _state); ae_vector_init_copy(&dst->corrtmp, &src->corrtmp, _state); ae_vector_init_copy(&dst->unitdiagonal, &src->unitdiagonal, _state); _snnlssolver_init_copy(&dst->solver, &src->solver, _state); ae_vector_init_copy(&dst->scntmp, &src->scntmp, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmpfeas, &src->tmpfeas, _state); ae_matrix_init_copy(&dst->tmpm0, &src->tmpm0, _state); ae_vector_init_copy(&dst->rctmps, &src->rctmps, _state); ae_vector_init_copy(&dst->rctmpg, &src->rctmpg, _state); ae_vector_init_copy(&dst->rctmprightpart, &src->rctmprightpart, _state); ae_matrix_init_copy(&dst->rctmpdense0, &src->rctmpdense0, _state); ae_matrix_init_copy(&dst->rctmpdense1, &src->rctmpdense1, _state); ae_vector_init_copy(&dst->rctmpisequality, &src->rctmpisequality, _state); ae_vector_init_copy(&dst->rctmpconstraintidx, &src->rctmpconstraintidx, _state); ae_vector_init_copy(&dst->rctmplambdas, &src->rctmplambdas, _state); ae_matrix_init_copy(&dst->tmpbasis, &src->tmpbasis, _state); } void _sactiveset_clear(void* _p) { sactiveset *p = (sactiveset*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->xc); ae_vector_clear(&p->s); ae_vector_clear(&p->h); ae_vector_clear(&p->activeset); ae_matrix_clear(&p->sbasis); ae_matrix_clear(&p->pbasis); ae_matrix_clear(&p->ibasis); ae_vector_clear(&p->hasbndl); ae_vector_clear(&p->hasbndu); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->mtx); ae_vector_clear(&p->mtas); ae_vector_clear(&p->cdtmp); ae_vector_clear(&p->corrtmp); ae_vector_clear(&p->unitdiagonal); _snnlssolver_clear(&p->solver); ae_vector_clear(&p->scntmp); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmpfeas); ae_matrix_clear(&p->tmpm0); ae_vector_clear(&p->rctmps); ae_vector_clear(&p->rctmpg); ae_vector_clear(&p->rctmprightpart); ae_matrix_clear(&p->rctmpdense0); ae_matrix_clear(&p->rctmpdense1); ae_vector_clear(&p->rctmpisequality); ae_vector_clear(&p->rctmpconstraintidx); ae_vector_clear(&p->rctmplambdas); ae_matrix_clear(&p->tmpbasis); } void _sactiveset_destroy(void* _p) { sactiveset *p = (sactiveset*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->xc); ae_vector_destroy(&p->s); ae_vector_destroy(&p->h); ae_vector_destroy(&p->activeset); ae_matrix_destroy(&p->sbasis); ae_matrix_destroy(&p->pbasis); ae_matrix_destroy(&p->ibasis); ae_vector_destroy(&p->hasbndl); ae_vector_destroy(&p->hasbndu); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->mtx); ae_vector_destroy(&p->mtas); ae_vector_destroy(&p->cdtmp); ae_vector_destroy(&p->corrtmp); ae_vector_destroy(&p->unitdiagonal); _snnlssolver_destroy(&p->solver); ae_vector_destroy(&p->scntmp); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmpfeas); ae_matrix_destroy(&p->tmpm0); ae_vector_destroy(&p->rctmps); ae_vector_destroy(&p->rctmpg); ae_vector_destroy(&p->rctmprightpart); ae_matrix_destroy(&p->rctmpdense0); ae_matrix_destroy(&p->rctmpdense1); ae_vector_destroy(&p->rctmpisequality); ae_vector_destroy(&p->rctmpconstraintidx); ae_vector_destroy(&p->rctmplambdas); ae_matrix_destroy(&p->tmpbasis); } /************************************************************************* NONLINEAR CONJUGATE GRADIENT METHOD DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using one of the nonlinear conjugate gradient methods. These CG methods are globally convergent (even on non-convex functions) as long as grad(f) is Lipschitz continuous in a some neighborhood of the L = { x : f(x)<=f(x0) }. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinCGCreate() call 2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and other functions 3. User calls MinCGOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinCGResults() to get solution 5. Optionally, user may call MinCGRestartFrom() to solve another problem with same N but another starting point and/or another function. MinCGRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void mincgcreate(ae_int_t n, /* Real */ ae_vector* x, mincgstate* state, ae_state *_state) { _mincgstate_clear(state); ae_assert(n>=1, "MinCGCreate: N too small!", _state); ae_assert(x->cnt>=n, "MinCGCreate: Length(X)0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinCGSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. L-BFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void mincgcreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, mincgstate* state, ae_state *_state) { _mincgstate_clear(state); ae_assert(n>=1, "MinCGCreateF: N too small!", _state); ae_assert(x->cnt>=n, "MinCGCreateF: Length(X)=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinCGSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcond(mincgstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinCGSetCond: EpsG is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinCGSetCond: negative EpsG!", _state); ae_assert(ae_isfinite(epsf, _state), "MinCGSetCond: EpsF is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinCGSetCond: negative EpsF!", _state); ae_assert(ae_isfinite(epsx, _state), "MinCGSetCond: EpsX is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinCGSetCond: negative EpsX!", _state); ae_assert(maxits>=0, "MinCGSetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function sets scaling coefficients for CG optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of CG optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the CG too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinCGSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void mincgsetscale(mincgstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->n, "MinCGSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinCGSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinCGSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function turns on/off line search reports. These reports are described in more details in developer-only comments on MinCGState object. INPUT PARAMETERS: State - structure which stores algorithm state NeedDRep- whether line search reports are needed or not This function is intended for private use only. Turning it on artificially may cause program failure. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state) { state->drep = needdrep; } /************************************************************************* This function sets CG algorithm. INPUT PARAMETERS: State - structure which stores algorithm state CGType - algorithm type: * -1 automatic selection of the best algorithm * 0 DY (Dai and Yuan) algorithm * 1 Hybrid DY-HS algorithm -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state) { ae_assert(cgtype>=-1&&cgtype<=1, "MinCGSetCGType: incorrect CGType!", _state); if( cgtype==-1 ) { cgtype = 1; } state->cgtype = cgtype; } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "MinCGSetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinCGSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* This function allows to suggest initial step length to the CG algorithm. Suggested step length is used as starting point for the line search. It can be useful when you have badly scaled problem, i.e. when ||grad|| (which is used as initial estimate for the first step) is many orders of magnitude different from the desired step. Line search may fail on such problems without good estimate of initial step length. Imagine, for example, problem with ||grad||=10^50 and desired step equal to 0.1 Line search function will use 10^50 as initial step, then it will decrease step length by 2 (up to 20 attempts) and will get 10^44, which is still too large. This function allows us to tell than line search should be started from some moderate step length, like 1.0, so algorithm will be able to detect desired step length in a several searches. Default behavior (when no step is suggested) is to use preconditioner, if it is available, to generate initial estimate of step length. This function influences only first iteration of algorithm. It should be called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. Suggested step is ignored if you have preconditioner. INPUT PARAMETERS: State - structure used to store algorithm state. Stp - initial estimate of the step length. Can be zero (no estimate). -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state) { ae_assert(ae_isfinite(stp, _state), "MinCGSuggestStep: Stp is infinite or NAN", _state); ae_assert(ae_fp_greater_eq(stp,(double)(0)), "MinCGSuggestStep: Stp<0", _state); state->suggestedstep = stp; } /************************************************************************* This developer-only function allows to retrieve unscaled (!) length of last good step (i.e. step which resulted in sufficient decrease of target function). It can be used in for solution of sequential optimization subproblems, where MinCGSuggestStep() is called with length of previous step as parameter. INPUT PARAMETERS: State - structure used to store algorithm state. RESULT: length of last good step being accepted NOTE: result of this function is undefined if you called it before -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ double mincglastgoodstep(mincgstate* state, ae_state *_state) { double result; result = state->lastgoodstep; return result; } /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdefault(mincgstate* state, ae_state *_state) { state->prectype = 0; state->innerresetneeded = ae_true; } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdiag(mincgstate* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(d->cnt>=state->n, "MinCGSetPrecDiag: D is too short", _state); for(i=0; i<=state->n-1; i++) { ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinCGSetPrecDiag: D contains infinite or NAN elements", _state); ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinCGSetPrecDiag: D contains non-positive elements", _state); } mincgsetprecdiagfast(state, d, _state); } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinCGSetScale() call (before or after MinCGSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecscale(mincgstate* state, ae_state *_state) { state->prectype = 3; state->innerresetneeded = ae_true; } /************************************************************************* NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinCGCreate() for analytical gradient or MinCGCreateF() for numerical differentiation) you should choose appropriate variant of MinCGOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinCGOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinCGOptimize() and specific function used to create optimizer. | USER PASSED TO MinCGOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinCGCreateF() | work FAIL MinCGCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinCGOptimize() version. Attemps to use such combination (for example, to create optimizer with MinCGCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ ae_bool mincgiteration(mincgstate* state, ae_state *_state) { ae_int_t n; ae_int_t i; double betak; double v; double vv; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; i = state->rstate.ia.ptr.p_int[1]; betak = state->rstate.ra.ptr.p_double[0]; v = state->rstate.ra.ptr.p_double[1]; vv = state->rstate.ra.ptr.p_double[2]; } else { n = -983; i = -989; betak = -834; v = 900; vv = -287; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } if( state->rstate.stage==14 ) { goto lbl_14; } if( state->rstate.stage==15 ) { goto lbl_15; } if( state->rstate.stage==16 ) { goto lbl_16; } if( state->rstate.stage==17 ) { goto lbl_17; } if( state->rstate.stage==18 ) { goto lbl_18; } if( state->rstate.stage==19 ) { goto lbl_19; } /* * Routine body */ /* * Prepare */ n = state->n; state->terminationneeded = ae_false; state->userterminationneeded = ae_false; state->repterminationtype = 0; state->repiterationscount = 0; state->repvaridx = -1; state->repnfev = 0; state->debugrestartscount = 0; /* * Check, that transferred derivative value is right */ mincg_clearrequestfields(state, _state); if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) { goto lbl_20; } state->needfg = ae_true; i = 0; lbl_22: if( i>n-1 ) { goto lbl_24; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->fm1 = state->f; state->fp1 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->fm2 = state->f; state->fp2 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = v; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: /* * 2*State.TestStep - scale parameter * width of segment [Xi-TestStep;Xi+TestStep] */ if( !derivativecheck(state->fm1, state->fp1, state->fm2, state->fp2, state->f, state->g.ptr.p_double[i], 2*state->teststep, _state) ) { state->repvaridx = i; state->repterminationtype = -7; result = ae_false; return result; } i = i+1; goto lbl_22; lbl_24: state->needfg = ae_false; lbl_20: /* * Preparations continue: * * set XK * * calculate F/G * * set DK to -G * * powerup algo (it may change preconditioner) * * apply preconditioner to DK * * report update of X * * check stopping conditions for G */ ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); mincg_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_25; } state->needfg = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needfg = ae_false; goto lbl_26; lbl_25: state->needf = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->fbase = state->f; i = 0; lbl_27: if( i>n-1 ) { goto lbl_29; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->fp2 = state->f; state->x.ptr.p_double[i] = v; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); i = i+1; goto lbl_27; lbl_29: state->f = state->fbase; state->needf = ae_false; lbl_26: if( !state->drep ) { goto lbl_30; } /* * Report algorithm powerup (if needed) */ mincg_clearrequestfields(state, _state); state->algpowerup = ae_true; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->algpowerup = ae_false; lbl_30: trimprepare(state->f, &state->trimthreshold, _state); ae_v_moveneg(&state->dk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); mincg_preconditionedmultiply(state, &state->dk, &state->work0, &state->work1, _state); if( !state->xrep ) { goto lbl_32; } mincg_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->xupdated = ae_false; lbl_32: if( state->terminationneeded||state->userterminationneeded ) { /* * Combined termination point for "internal" termination by TerminationNeeded flag * and for "user" termination by MinCGRequestTermination() (UserTerminationNeeded flag). * In this location rules for both of methods are same, thus only one exit point is needed. */ ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) { ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 4; result = ae_false; return result; } state->repnfev = 1; state->k = 0; state->fold = state->f; /* * Choose initial step. * Apply preconditioner, if we have something other than default. */ if( state->prectype==2||state->prectype==3 ) { /* * because we use preconditioner, step length must be equal * to the norm of DK */ v = ae_v_dotproduct(&state->dk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->lastgoodstep = ae_sqrt(v, _state); } else { /* * No preconditioner is used, we try to use suggested step */ if( ae_fp_greater(state->suggestedstep,(double)(0)) ) { state->lastgoodstep = state->suggestedstep; } else { state->lastgoodstep = 1.0; } } /* * Main cycle */ state->rstimer = mincg_rscountdownlen; lbl_34: if( ae_false ) { goto lbl_35; } /* * * clear reset flag * * clear termination flag * * store G[k] for later calculation of Y[k] * * prepare starting point and direction and step length for line search */ state->innerresetneeded = ae_false; state->terminationneeded = ae_false; ae_v_moveneg(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->mcstage = 0; state->stp = 1.0; linminnormalized(&state->d, &state->stp, n, _state); if( ae_fp_neq(state->lastgoodstep,(double)(0)) ) { state->stp = state->lastgoodstep; } state->curstpmax = state->stpmax; /* * Report beginning of line search (if needed) * Terminate algorithm, if user request was detected */ if( !state->drep ) { goto lbl_36; } mincg_clearrequestfields(state, _state); state->lsstart = ae_true; state->rstate.stage = 11; goto lbl_rcomm; lbl_11: state->lsstart = ae_false; lbl_36: if( state->terminationneeded ) { ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } /* * Minimization along D */ mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); lbl_38: if( state->mcstage==0 ) { goto lbl_39; } /* * Calculate function/gradient using either * analytical gradient supplied by user * or finite difference approximation. * * "Trim" function in order to handle near-singularity points. */ mincg_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_40; } state->needfg = ae_true; state->rstate.stage = 12; goto lbl_rcomm; lbl_12: state->needfg = ae_false; goto lbl_41; lbl_40: state->needf = ae_true; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->fbase = state->f; i = 0; lbl_42: if( i>n-1 ) { goto lbl_44; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 14; goto lbl_rcomm; lbl_14: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 15; goto lbl_rcomm; lbl_15: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 16; goto lbl_rcomm; lbl_16: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 17; goto lbl_rcomm; lbl_17: state->fp2 = state->f; state->x.ptr.p_double[i] = v; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); i = i+1; goto lbl_42; lbl_44: state->f = state->fbase; state->needf = ae_false; lbl_41: trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); /* * Call MCSRCH again */ mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); goto lbl_38; lbl_39: /* * * terminate algorithm if "user" request for detected * * report end of line search * * store current point to XN * * report iteration * * terminate algorithm if "internal" request was detected */ if( state->userterminationneeded ) { ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } if( !state->drep ) { goto lbl_45; } /* * Report end of line search (if needed) */ mincg_clearrequestfields(state, _state); state->lsend = ae_true; state->rstate.stage = 18; goto lbl_rcomm; lbl_18: state->lsend = ae_false; lbl_45: ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( !state->xrep ) { goto lbl_47; } mincg_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 19; goto lbl_rcomm; lbl_19: state->xupdated = ae_false; lbl_47: if( state->terminationneeded ) { ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } /* * Line search is finished. * * calculate BetaK * * calculate DN * * update timers * * calculate step length: * * LastScaledStep is ALWAYS calculated because it is used in the stopping criteria * * LastGoodStep is updated only when MCINFO is equal to 1 (Wolfe conditions hold). * See below for more explanation. */ if( state->mcinfo==1&&!state->innerresetneeded ) { /* * Standard Wolfe conditions hold * Calculate Y[K] and D[K]'*Y[K] */ ae_v_add(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Calculate BetaK according to DY formula */ v = mincg_preconditionedmultiply2(state, &state->g, &state->g, &state->work0, &state->work1, _state); state->betady = v/vv; /* * Calculate BetaK according to HS formula */ v = mincg_preconditionedmultiply2(state, &state->g, &state->yk, &state->work0, &state->work1, _state); state->betahs = v/vv; /* * Choose BetaK */ if( state->cgtype==0 ) { betak = state->betady; } if( state->cgtype==1 ) { betak = ae_maxreal((double)(0), ae_minreal(state->betady, state->betahs, _state), _state); } } else { /* * Something is wrong (may be function is too wild or too flat) * or we just have to restart algo. * * We'll set BetaK=0, which will restart CG algorithm. * We can stop later (during normal checks) if stopping conditions are met. */ betak = (double)(0); state->debugrestartscount = state->debugrestartscount+1; } if( state->repiterationscount>0&&state->repiterationscount%(3+n)==0 ) { /* * clear Beta every N iterations */ betak = (double)(0); } if( state->mcinfo==1||state->mcinfo==5 ) { state->rstimer = mincg_rscountdownlen; } else { state->rstimer = state->rstimer-1; } ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); mincg_preconditionedmultiply(state, &state->dn, &state->work0, &state->work1, _state); ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); state->lastscaledstep = 0.0; for(i=0; i<=n-1; i++) { state->lastscaledstep = state->lastscaledstep+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); } state->lastscaledstep = state->stp*ae_sqrt(state->lastscaledstep, _state); if( state->mcinfo==1 ) { /* * Step is good (Wolfe conditions hold), update LastGoodStep. * * This check for MCINFO=1 is essential because sometimes in the * constrained optimization setting we may take very short steps * (like 1E-15) because we were very close to boundary of the * feasible area. Such short step does not mean that we've converged * to the solution - it was so short because we were close to the * boundary and there was a limit on step length. * * So having such short step is quite normal situation. However, we * should NOT start next iteration from step whose initial length is * estimated as 1E-15 because it may lead to the failure of the * linear minimizer (step is too short, function does not changes, * line search stagnates). */ state->lastgoodstep = (double)(0); for(i=0; i<=n-1; i++) { state->lastgoodstep = state->lastgoodstep+ae_sqr(state->d.ptr.p_double[i], _state); } state->lastgoodstep = state->stp*ae_sqrt(state->lastgoodstep, _state); } /* * Update information. * Check stopping conditions. */ v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } if( !ae_isfinite(v, _state)||!ae_isfinite(state->f, _state) ) { /* * Abnormal termination - infinities in function/gradient */ state->repterminationtype = -8; result = ae_false; return result; } state->repnfev = state->repnfev+state->nfev; state->repiterationscount = state->repiterationscount+1; if( state->repiterationscount>=state->maxits&&state->maxits>0 ) { /* * Too many iterations */ state->repterminationtype = 5; result = ae_false; return result; } if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) { /* * Gradient is small enough */ state->repterminationtype = 4; result = ae_false; return result; } if( !state->innerresetneeded ) { /* * These conditions are checked only when no inner reset was requested by user */ if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) { /* * F(k+1)-F(k) is small enough */ state->repterminationtype = 1; result = ae_false; return result; } if( ae_fp_less_eq(state->lastscaledstep,state->epsx) ) { /* * X(k+1)-X(k) is small enough */ state->repterminationtype = 2; result = ae_false; return result; } } if( state->rstimer<=0 ) { /* * Too many subsequent restarts */ state->repterminationtype = 7; result = ae_false; return result; } /* * Shift Xk/Dk, update other information */ ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->fold = state->f; state->k = state->k+1; goto lbl_34; lbl_35: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = i; state->rstate.ra.ptr.p_double[0] = betak; state->rstate.ra.ptr.p_double[1] = v; state->rstate.ra.ptr.p_double[2] = vv; return result; } /************************************************************************* Conjugate gradient results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinCGSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, we return best X found so far * 8 terminated by user * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresults(mincgstate* state, /* Real */ ae_vector* x, mincgreport* rep, ae_state *_state) { ae_vector_clear(x); _mincgreport_clear(rep); mincgresultsbuf(state, x, rep, _state); } /************************************************************************* Conjugate gradient results Buffered implementation of MinCGResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/ void mincgresultsbuf(mincgstate* state, /* Real */ ae_vector* x, mincgreport* rep, ae_state *_state) { if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nfev = state->repnfev; rep->varidx = state->repvaridx; rep->terminationtype = state->repterminationtype; } /************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void mincgrestartfrom(mincgstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_assert(x->cnt>=state->n, "MinCGRestartFrom: Length(X)n, _state), "MinCGCreate: X contains infinite or NaN values!", _state); ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); mincgsuggeststep(state, 0.0, _state); ae_vector_set_length(&state->rstate.ia, 1+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; mincg_clearrequestfields(state, _state); } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void mincgrequesttermination(mincgstate* state, ae_state *_state) { state->userterminationneeded = ae_true; } /************************************************************************* Faster version of MinCGSetPrecDiag(), for time-critical parts of code, without safety checks. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecdiagfast(mincgstate* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; rvectorsetlengthatleast(&state->diagh, state->n, _state); rvectorsetlengthatleast(&state->diaghl2, state->n, _state); state->prectype = 2; state->vcnt = 0; state->innerresetneeded = ae_true; for(i=0; i<=state->n-1; i++) { state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; state->diaghl2.ptr.p_double[i] = 0.0; } } /************************************************************************* This function sets low-rank preconditioner for Hessian matrix H=D+V'*C*V, where: * H is a Hessian matrix, which is approximated by D/V/C * D=D1+D2 is a diagonal matrix, which includes two positive definite terms: * constant term D1 (is not updated or infrequently updated) * variable term D2 (can be cheaply updated from iteration to iteration) * V is a low-rank correction * C is a diagonal factor of low-rank correction Preconditioner P is calculated using approximate Woodburry formula: P = D^(-1) - D^(-1)*V'*(C^(-1)+V*D1^(-1)*V')^(-1)*V*D^(-1) = D^(-1) - D^(-1)*VC'*VC*D^(-1), where VC = sqrt(B)*V B = (C^(-1)+V*D1^(-1)*V')^(-1) Note that B is calculated using constant term (D1) only, which allows us to update D2 without recalculation of B or VC. Such preconditioner is exact when D2 is zero. When D2 is non-zero, it is only approximation, but very good and cheap one. This function accepts D1, V, C. D2 is set to zero by default. Cost of this update is O(N*VCnt*VCnt), but D2 can be updated in just O(N) by MinCGSetPrecVarPart. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetpreclowrankfast(mincgstate* state, /* Real */ ae_vector* d1, /* Real */ ae_vector* c, /* Real */ ae_matrix* v, ae_int_t vcnt, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; double t; ae_matrix b; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_REAL, _state); if( vcnt==0 ) { mincgsetprecdiagfast(state, d1, _state); ae_frame_leave(_state); return; } n = state->n; ae_matrix_set_length(&b, vcnt, vcnt, _state); rvectorsetlengthatleast(&state->diagh, n, _state); rvectorsetlengthatleast(&state->diaghl2, n, _state); rmatrixsetlengthatleast(&state->vcorr, vcnt, n, _state); state->prectype = 2; state->vcnt = vcnt; state->innerresetneeded = ae_true; for(i=0; i<=n-1; i++) { state->diagh.ptr.p_double[i] = d1->ptr.p_double[i]; state->diaghl2.ptr.p_double[i] = 0.0; } for(i=0; i<=vcnt-1; i++) { for(j=i; j<=vcnt-1; j++) { t = (double)(0); for(k=0; k<=n-1; k++) { t = t+v->ptr.pp_double[i][k]*v->ptr.pp_double[j][k]/d1->ptr.p_double[k]; } b.ptr.pp_double[i][j] = t; } b.ptr.pp_double[i][i] = b.ptr.pp_double[i][i]+1.0/c->ptr.p_double[i]; } if( !spdmatrixcholeskyrec(&b, 0, vcnt, ae_true, &state->work0, _state) ) { state->vcnt = 0; ae_frame_leave(_state); return; } for(i=0; i<=vcnt-1; i++) { ae_v_move(&state->vcorr.ptr.pp_double[i][0], 1, &v->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); for(j=0; j<=i-1; j++) { t = b.ptr.pp_double[j][i]; ae_v_subd(&state->vcorr.ptr.pp_double[i][0], 1, &state->vcorr.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), t); } t = 1/b.ptr.pp_double[i][i]; ae_v_muld(&state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), t); } ae_frame_leave(_state); } /************************************************************************* This function updates variable part (diagonal matrix D2) of low-rank preconditioner. This update is very cheap and takes just O(N) time. It has no effect with default preconditioner. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void mincgsetprecvarpart(mincgstate* state, /* Real */ ae_vector* d2, ae_state *_state) { ae_int_t i; ae_int_t n; n = state->n; for(i=0; i<=n-1; i++) { state->diaghl2.ptr.p_double[i] = d2->ptr.p_double[i]; } } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinCGOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinCGSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 31.05.2012 by Bochkanov Sergey *************************************************************************/ void mincgsetgradientcheck(mincgstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "MinCGSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinCGSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void mincg_clearrequestfields(mincgstate* state, ae_state *_state) { state->needf = ae_false; state->needfg = ae_false; state->xupdated = ae_false; state->lsstart = ae_false; state->lsend = ae_false; state->algpowerup = ae_false; } /************************************************************************* This function calculates preconditioned product H^(-1)*x and stores result back into X. Work0[] and Work1[] are used as temporaries (size must be at least N; this function doesn't allocate arrays). -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ static void mincg_preconditionedmultiply(mincgstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* work0, /* Real */ ae_vector* work1, ae_state *_state) { ae_int_t i; ae_int_t n; ae_int_t vcnt; double v; n = state->n; vcnt = state->vcnt; if( state->prectype==0 ) { return; } if( state->prectype==3 ) { for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; } return; } ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); /* * handle part common for VCnt=0 and VCnt<>0 */ for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); } /* * if VCnt>0 */ if( vcnt>0 ) { for(i=0; i<=vcnt-1; i++) { v = ae_v_dotproduct(&state->vcorr.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); work0->ptr.p_double[i] = v; } for(i=0; i<=n-1; i++) { work1->ptr.p_double[i] = (double)(0); } for(i=0; i<=vcnt-1; i++) { v = work0->ptr.p_double[i]; ae_v_addd(&state->work1.ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]-state->work1.ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); } } } /************************************************************************* This function calculates preconditioned product x'*H^(-1)*y. Work0[] and Work1[] are used as temporaries (size must be at least N; this function doesn't allocate arrays). -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ static double mincg_preconditionedmultiply2(mincgstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* work0, /* Real */ ae_vector* work1, ae_state *_state) { ae_int_t i; ae_int_t n; ae_int_t vcnt; double v0; double v1; double result; n = state->n; vcnt = state->vcnt; /* * no preconditioning */ if( state->prectype==0 ) { v0 = ae_v_dotproduct(&x->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = v0; return result; } if( state->prectype==3 ) { result = (double)(0); for(i=0; i<=n-1; i++) { result = result+x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]*y->ptr.p_double[i]; } return result; } ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); /* * low rank preconditioning */ result = 0.0; for(i=0; i<=n-1; i++) { result = result+x->ptr.p_double[i]*y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); } if( vcnt>0 ) { for(i=0; i<=n-1; i++) { work0->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); work1->ptr.p_double[i] = y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); } for(i=0; i<=vcnt-1; i++) { v0 = ae_v_dotproduct(&work0->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v1 = ae_v_dotproduct(&work1->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); result = result-v0*v1; } } return result; } /************************************************************************* Internal initialization subroutine -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ static void mincg_mincginitinternal(ae_int_t n, double diffstep, mincgstate* state, ae_state *_state) { ae_int_t i; /* * Initialize */ state->teststep = (double)(0); state->n = n; state->diffstep = diffstep; state->lastgoodstep = (double)(0); mincgsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); mincgsetxrep(state, ae_false, _state); mincgsetdrep(state, ae_false, _state); mincgsetstpmax(state, (double)(0), _state); mincgsetcgtype(state, -1, _state); mincgsetprecdefault(state, _state); ae_vector_set_length(&state->xk, n, _state); ae_vector_set_length(&state->dk, n, _state); ae_vector_set_length(&state->xn, n, _state); ae_vector_set_length(&state->dn, n, _state); ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->d, n, _state); ae_vector_set_length(&state->g, n, _state); ae_vector_set_length(&state->work0, n, _state); ae_vector_set_length(&state->work1, n, _state); ae_vector_set_length(&state->yk, n, _state); ae_vector_set_length(&state->s, n, _state); for(i=0; i<=n-1; i++) { state->s.ptr.p_double[i] = 1.0; } } void _mincgstate_init(void* _p, ae_state *_state) { mincgstate *p = (mincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->diagh, 0, DT_REAL, _state); ae_vector_init(&p->diaghl2, 0, DT_REAL, _state); ae_matrix_init(&p->vcorr, 0, 0, DT_REAL, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->xk, 0, DT_REAL, _state); ae_vector_init(&p->dk, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->dn, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->yk, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); _linminstate_init(&p->lstate, _state); ae_vector_init(&p->work0, 0, DT_REAL, _state); ae_vector_init(&p->work1, 0, DT_REAL, _state); } void _mincgstate_init_copy(void* _dst, void* _src, ae_state *_state) { mincgstate *dst = (mincgstate*)_dst; mincgstate *src = (mincgstate*)_src; dst->n = src->n; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->stpmax = src->stpmax; dst->suggestedstep = src->suggestedstep; dst->xrep = src->xrep; dst->drep = src->drep; dst->cgtype = src->cgtype; dst->prectype = src->prectype; ae_vector_init_copy(&dst->diagh, &src->diagh, _state); ae_vector_init_copy(&dst->diaghl2, &src->diaghl2, _state); ae_matrix_init_copy(&dst->vcorr, &src->vcorr, _state); dst->vcnt = src->vcnt; ae_vector_init_copy(&dst->s, &src->s, _state); dst->diffstep = src->diffstep; dst->nfev = src->nfev; dst->mcstage = src->mcstage; dst->k = src->k; ae_vector_init_copy(&dst->xk, &src->xk, _state); ae_vector_init_copy(&dst->dk, &src->dk, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->dn, &src->dn, _state); ae_vector_init_copy(&dst->d, &src->d, _state); dst->fold = src->fold; dst->stp = src->stp; dst->curstpmax = src->curstpmax; ae_vector_init_copy(&dst->yk, &src->yk, _state); dst->lastgoodstep = src->lastgoodstep; dst->lastscaledstep = src->lastscaledstep; dst->mcinfo = src->mcinfo; dst->innerresetneeded = src->innerresetneeded; dst->terminationneeded = src->terminationneeded; dst->trimthreshold = src->trimthreshold; dst->rstimer = src->rstimer; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); dst->needf = src->needf; dst->needfg = src->needfg; dst->xupdated = src->xupdated; dst->algpowerup = src->algpowerup; dst->lsstart = src->lsstart; dst->lsend = src->lsend; dst->userterminationneeded = src->userterminationneeded; dst->teststep = src->teststep; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->repiterationscount = src->repiterationscount; dst->repnfev = src->repnfev; dst->repvaridx = src->repvaridx; dst->repterminationtype = src->repterminationtype; dst->debugrestartscount = src->debugrestartscount; _linminstate_init_copy(&dst->lstate, &src->lstate, _state); dst->fbase = src->fbase; dst->fm2 = src->fm2; dst->fm1 = src->fm1; dst->fp1 = src->fp1; dst->fp2 = src->fp2; dst->betahs = src->betahs; dst->betady = src->betady; ae_vector_init_copy(&dst->work0, &src->work0, _state); ae_vector_init_copy(&dst->work1, &src->work1, _state); } void _mincgstate_clear(void* _p) { mincgstate *p = (mincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->diagh); ae_vector_clear(&p->diaghl2); ae_matrix_clear(&p->vcorr); ae_vector_clear(&p->s); ae_vector_clear(&p->xk); ae_vector_clear(&p->dk); ae_vector_clear(&p->xn); ae_vector_clear(&p->dn); ae_vector_clear(&p->d); ae_vector_clear(&p->yk); ae_vector_clear(&p->x); ae_vector_clear(&p->g); _rcommstate_clear(&p->rstate); _linminstate_clear(&p->lstate); ae_vector_clear(&p->work0); ae_vector_clear(&p->work1); } void _mincgstate_destroy(void* _p) { mincgstate *p = (mincgstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->diagh); ae_vector_destroy(&p->diaghl2); ae_matrix_destroy(&p->vcorr); ae_vector_destroy(&p->s); ae_vector_destroy(&p->xk); ae_vector_destroy(&p->dk); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->dn); ae_vector_destroy(&p->d); ae_vector_destroy(&p->yk); ae_vector_destroy(&p->x); ae_vector_destroy(&p->g); _rcommstate_destroy(&p->rstate); _linminstate_destroy(&p->lstate); ae_vector_destroy(&p->work0); ae_vector_destroy(&p->work1); } void _mincgreport_init(void* _p, ae_state *_state) { mincgreport *p = (mincgreport*)_p; ae_touch_ptr((void*)p); } void _mincgreport_init_copy(void* _dst, void* _src, ae_state *_state) { mincgreport *dst = (mincgreport*)_dst; mincgreport *src = (mincgreport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->varidx = src->varidx; dst->terminationtype = src->terminationtype; } void _mincgreport_clear(void* _p) { mincgreport *p = (mincgreport*)_p; ae_touch_ptr((void*)p); } void _mincgreport_destroy(void* _p) { mincgreport *p = (mincgreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* BOUND CONSTRAINED OPTIMIZATION WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints REQUIREMENTS: * user must provide function value and gradient * starting point X0 must be feasible or not too far away from the feasible set * grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) } * function must be defined everywhere on the feasible set F USAGE: Constrained optimization if far more complex than the unconstrained one. Here we give very brief outline of the BLEIC optimizer. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinBLEICCreate() call 2. USer adds boundary and/or linear constraints by calling MinBLEICSetBC() and MinBLEICSetLC() functions. 3. User sets stopping conditions with MinBLEICSetCond(). 4. User calls MinBLEICOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 5. User calls MinBLEICResults() to get solution 6. Optionally user may call MinBLEICRestartFrom() to solve another problem with same N but another starting point. MinBLEICRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleiccreate(ae_int_t n, /* Real */ ae_vector* x, minbleicstate* state, ae_state *_state) { ae_frame _frame_block; ae_matrix c; ae_vector ct; ae_frame_make(_state, &_frame_block); _minbleicstate_clear(state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_assert(n>=1, "MinBLEICCreate: N<1", _state); ae_assert(x->cnt>=n, "MinBLEICCreate: Length(X)0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinBLEICSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. CG needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minbleiccreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minbleicstate* state, ae_state *_state) { ae_frame _frame_block; ae_matrix c; ae_vector ct; ae_frame_make(_state, &_frame_block); _minbleicstate_clear(state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_assert(n>=1, "MinBLEICCreateF: N<1", _state); ae_assert(x->cnt>=n, "MinBLEICCreateF: Length(X)nmain; ae_assert(bndl->cnt>=n, "MinBLEICSetBC: Length(BndL)cnt>=n, "MinBLEICSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } sassetbc(&state->sas, bndl, bndu, _state); } /************************************************************************* This function sets linear constraints for BLEIC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetlc(minbleicstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double v; n = state->nmain; /* * First, check for errors in the inputs */ ae_assert(k>=0, "MinBLEICSetLC: K<0", _state); ae_assert(c->cols>=n+1||k==0, "MinBLEICSetLC: Cols(C)rows>=k, "MinBLEICSetLC: Rows(C)cnt>=k, "MinBLEICSetLC: Length(CT)nec = 0; state->nic = 0; return; } /* * Equality constraints are stored first, in the upper * NEC rows of State.CLEIC matrix. Inequality constraints * are stored in the next NIC rows. * * NOTE: we convert inequality constraints to the form * A*x<=b before copying them. */ rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); state->nec = 0; state->nic = 0; for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]==0 ) { ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); state->nec = state->nec+1; } } for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]!=0 ) { if( ct->ptr.p_int[i]>0 ) { ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } else { ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } state->nic = state->nic+1; } } /* * Normalize rows of State.CLEIC: each row must have unit norm. * Norm is calculated using first N elements (i.e. right part is * not counted when we calculate norm). */ for(i=0; i<=k-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->cleic.ptr.pp_double[i][j], _state); } if( ae_fp_eq(v,(double)(0)) ) { continue; } v = 1/ae_sqrt(v, _state); ae_v_muld(&state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n), v); } sassetlc(&state->sas, c, ct, k, _state); } /************************************************************************* This function sets stopping conditions for the optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinBLEICSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform slightly more than MaxIts iterations. I.e., MaxIts sets non-strict limit on iterations count. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetcond(minbleicstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinBLEICSetCond: EpsG is not finite number", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinBLEICSetCond: negative EpsG", _state); ae_assert(ae_isfinite(epsf, _state), "MinBLEICSetCond: EpsF is not finite number", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinBLEICSetCond: negative EpsF", _state); ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetCond: EpsX is not finite number", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinBLEICSetCond: negative EpsX", _state); ae_assert(maxits>=0, "MinBLEICSetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function sets scaling coefficients for BLEIC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the BLEIC too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinBLEICSetPrec...() functions. There is a special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minbleicsetscale(minbleicstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->nmain, "MinBLEICSetScale: Length(S)nmain-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinBLEICSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinBLEICSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } sassetscale(&state->sas, s, _state); } /************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdefault(minbleicstate* state, ae_state *_state) { state->prectype = 0; } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE 1: D[i] should be positive. Exception will be thrown otherwise. NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecdiag(minbleicstate* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(d->cnt>=state->nmain, "MinBLEICSetPrecDiag: D is too short", _state); for(i=0; i<=state->nmain-1; i++) { ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinBLEICSetPrecDiag: D contains infinite or NAN elements", _state); ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinBLEICSetPrecDiag: D contains non-positive elements", _state); } rvectorsetlengthatleast(&state->diagh, state->nmain, _state); state->prectype = 2; for(i=0; i<=state->nmain-1; i++) { state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; } } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetprecscale(minbleicstate* state, ae_state *_state) { state->prectype = 3; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinBLEICOptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetxrep(minbleicstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function turns on/off line search reports. These reports are described in more details in developer-only comments on MinBLEICState object. INPUT PARAMETERS: State - structure which stores algorithm state NeedDRep- whether line search reports are needed or not This function is intended for private use only. Turning it on artificially may cause program failure. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetdrep(minbleicstate* state, ae_bool needdrep, ae_state *_state) { state->drep = needdrep; } /************************************************************************* This function sets maximum step length IMPORTANT: this feature is hard to combine with preconditioning. You can't set upper limit on step length, when you solve optimization problem with linear (non-boundary) constraints AND preconditioner turned on. When non-boundary constraints are present, you have to either a) use preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! In this case algorithm will terminate with appropriate error code. INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetstpmax(minbleicstate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "MinBLEICSetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinBLEICSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() for numerical differentiation) you should choose appropriate variant of MinBLEICOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinBLEICOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinBLEICOptimize() and specific function used to create optimizer. | USER PASSED TO MinBLEICOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinBLEICCreateF() | work FAIL MinBLEICCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinBLEICOptimize() version. Attemps to use such combination (for example, to create optimizer with MinBLEICCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ ae_bool minbleiciteration(minbleicstate* state, ae_state *_state) { ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; double v; double vv; double v0; ae_bool b; ae_int_t mcinfo; ae_int_t actstatus; ae_int_t itidx; double penalty; double ginit; double gdecay; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; i = state->rstate.ia.ptr.p_int[2]; j = state->rstate.ia.ptr.p_int[3]; mcinfo = state->rstate.ia.ptr.p_int[4]; actstatus = state->rstate.ia.ptr.p_int[5]; itidx = state->rstate.ia.ptr.p_int[6]; b = state->rstate.ba.ptr.p_bool[0]; v = state->rstate.ra.ptr.p_double[0]; vv = state->rstate.ra.ptr.p_double[1]; v0 = state->rstate.ra.ptr.p_double[2]; penalty = state->rstate.ra.ptr.p_double[3]; ginit = state->rstate.ra.ptr.p_double[4]; gdecay = state->rstate.ra.ptr.p_double[5]; } else { n = -983; m = -989; i = -834; j = 900; mcinfo = -287; actstatus = 364; itidx = 214; b = ae_false; v = -686; vv = 912; v0 = 585; penalty = 497; ginit = -271; gdecay = -581; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } if( state->rstate.stage==14 ) { goto lbl_14; } if( state->rstate.stage==15 ) { goto lbl_15; } if( state->rstate.stage==16 ) { goto lbl_16; } if( state->rstate.stage==17 ) { goto lbl_17; } if( state->rstate.stage==18 ) { goto lbl_18; } if( state->rstate.stage==19 ) { goto lbl_19; } if( state->rstate.stage==20 ) { goto lbl_20; } if( state->rstate.stage==21 ) { goto lbl_21; } if( state->rstate.stage==22 ) { goto lbl_22; } if( state->rstate.stage==23 ) { goto lbl_23; } /* * Routine body */ /* * Algorithm parameters: * * M number of L-BFGS corrections. * This coefficient remains fixed during iterations. * * GDecay desired decrease of constrained gradient during L-BFGS iterations. * This coefficient is decreased after each L-BFGS round until * it reaches minimum decay. */ m = ae_minint(5, state->nmain, _state); gdecay = minbleic_initialdecay; /* * Init */ n = state->nmain; state->steepestdescentstep = ae_false; state->userterminationneeded = ae_false; state->repterminationtype = 0; state->repinneriterationscount = 0; state->repouteriterationscount = 0; state->repnfev = 0; state->repvaridx = -1; state->repdebugeqerr = 0.0; state->repdebugfs = _state->v_nan; state->repdebugff = _state->v_nan; state->repdebugdx = _state->v_nan; if( ae_fp_neq(state->stpmax,(double)(0))&&state->prectype!=0 ) { state->repterminationtype = -10; result = ae_false; return result; } rmatrixsetlengthatleast(&state->bufyk, m+1, n, _state); rmatrixsetlengthatleast(&state->bufsk, m+1, n, _state); rvectorsetlengthatleast(&state->bufrho, m, _state); rvectorsetlengthatleast(&state->buftheta, m, _state); rvectorsetlengthatleast(&state->tmp0, n, _state); /* * Fill TmpPrec with current preconditioner */ rvectorsetlengthatleast(&state->tmpprec, n, _state); for(i=0; i<=n-1; i++) { if( state->prectype==2 ) { state->tmpprec.ptr.p_double[i] = state->diagh.ptr.p_double[i]; continue; } if( state->prectype==3 ) { state->tmpprec.ptr.p_double[i] = 1/ae_sqr(state->s.ptr.p_double[i], _state); continue; } state->tmpprec.ptr.p_double[i] = (double)(1); } sassetprecdiag(&state->sas, &state->tmpprec, _state); /* * Start optimization */ if( !sasstartoptimization(&state->sas, &state->xstart, _state) ) { state->repterminationtype = -3; result = ae_false; return result; } /* * Check correctness of user-supplied gradient */ if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) { goto lbl_24; } minbleic_clearrequestfields(state, _state); ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->needfg = ae_true; i = 0; lbl_26: if( i>n-1 ) { goto lbl_28; } ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->sas.xc.ptr.p_double[i],state->bndl.ptr.p_double[i]), "MinBLEICIteration: internal error(State.X is out of bounds)", _state); ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->sas.xc.ptr.p_double[i],state->bndu.ptr.p_double[i]), "MinBLEICIteration: internal error(State.X is out of bounds)", _state); v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } state->xm1 = state->x.ptr.p_double[i]; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->fm1 = state->f; state->gm1 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; if( state->hasbndu.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } state->xp1 = state->x.ptr.p_double[i]; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->fp1 = state->f; state->gp1 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = (state->xm1+state->xp1)/2; if( state->hasbndl.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } if( state->hasbndu.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->x.ptr.p_double[i] = v; if( !derivativecheck(state->fm1, state->gm1, state->fp1, state->gp1, state->f, state->g.ptr.p_double[i], state->xp1-state->xm1, _state) ) { state->repvaridx = i; state->repterminationtype = -7; sasstopoptimization(&state->sas, _state); result = ae_false; return result; } i = i+1; goto lbl_26; lbl_28: state->needfg = ae_false; lbl_24: /* * Main cycle of BLEIC-PG algorithm */ state->repterminationtype = 0; state->lastgoodstep = (double)(0); state->lastscaledgoodstep = (double)(0); state->maxscaledgrad = (double)(0); state->nonmonotoniccnt = ae_round(1.5*(n+state->nic), _state)+5; ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); minbleic_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_29; } state->needfg = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needfg = ae_false; goto lbl_30; lbl_29: state->needf = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->needf = ae_false; lbl_30: state->fc = state->f; trimprepare(state->f, &state->trimthreshold, _state); state->repnfev = state->repnfev+1; if( !state->xrep ) { goto lbl_31; } /* * Report current point */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fc; state->xupdated = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->xupdated = ae_false; lbl_31: if( state->userterminationneeded ) { /* * User requested termination */ sasstopoptimization(&state->sas, _state); state->repterminationtype = 8; result = ae_false; return result; } lbl_33: if( ae_false ) { goto lbl_34; } /* * Preparations * * (a) calculate unconstrained gradient * (b) determine initial active set * (c) update MaxScaledGrad * (d) check F/G for NAN/INF, abnormally terminate algorithm if needed */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); minbleic_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_35; } /* * Analytic gradient */ state->needfg = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->needfg = ae_false; goto lbl_36; lbl_35: /* * Numerical differentiation */ state->needf = ae_true; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->fbase = state->f; i = 0; lbl_37: if( i>n-1 ) { goto lbl_39; } v = state->x.ptr.p_double[i]; b = ae_false; if( state->hasbndl.ptr.p_bool[i] ) { b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); } if( state->hasbndu.ptr.p_bool[i] ) { b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); } if( b ) { goto lbl_40; } state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 11; goto lbl_rcomm; lbl_11: state->fp2 = state->f; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); goto lbl_41; lbl_40: state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) { state->xm1 = state->bndl.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) { state->xp1 = state->bndu.ptr.p_double[i]; } state->x.ptr.p_double[i] = state->xm1; state->rstate.stage = 12; goto lbl_rcomm; lbl_12: state->fm1 = state->f; state->x.ptr.p_double[i] = state->xp1; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->fp1 = state->f; if( ae_fp_neq(state->xm1,state->xp1) ) { state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); } else { state->g.ptr.p_double[i] = (double)(0); } lbl_41: state->x.ptr.p_double[i] = v; i = i+1; goto lbl_37; lbl_39: state->f = state->fbase; state->needf = ae_false; lbl_36: state->fc = state->f; ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); sasreactivateconstraintsprec(&state->sas, &state->ugc, _state); sasconstraineddirection(&state->sas, &state->cgc, _state); ginit = 0.0; for(i=0; i<=n-1; i++) { ginit = ginit+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } ginit = ae_sqrt(ginit, _state); state->maxscaledgrad = ae_maxreal(state->maxscaledgrad, ginit, _state); if( !ae_isfinite(ginit, _state)||!ae_isfinite(state->fc, _state) ) { /* * Abnormal termination - infinities in function/gradient */ sasstopoptimization(&state->sas, _state); state->repterminationtype = -8; result = ae_false; return result; } if( state->userterminationneeded ) { /* * User requested termination */ sasstopoptimization(&state->sas, _state); state->repterminationtype = 8; result = ae_false; return result; } /* * LBFGS stage: * * during LBFGS iterations we activate new constraints, but never * deactivate already active ones. * * we perform at most N iterations of LBFGS before re-evaluating * active set and restarting LBFGS. * * first iteration of LBFGS is a special - it is performed with * minimum set of active constraints, algorithm termination can * be performed only at this state. We call this iteration * "steepest descent step". * * About termination: * * LBFGS iterations can be terminated because of two reasons: * * "termination" - non-zero termination code in RepTerminationType, * which means that optimization is done * * "restart" - zero RepTerminationType, which means that we * have to re-evaluate active set and resume LBFGS stage. * * one more option is "refresh" - to continue LBFGS iterations, * but with all BFGS updates (Sk/Yk pairs) being dropped; * it happens after changes in active set */ state->bufsize = 0; state->steepestdescentstep = ae_true; itidx = 0; lbl_42: if( itidx>n-1 ) { goto lbl_44; } /* * At the beginning of each iteration: * * SAS.XC stores current point * * FC stores current function value * * UGC stores current unconstrained gradient * * CGC stores current constrained gradient * * D stores constrained step direction (calculated at this block) * * * Check gradient-based stopping criteria * * This stopping condition is tested only for step which is the * first step of LBFGS (subsequent steps may accumulate active * constraints thus they should NOT be used for stopping - gradient * may be small when constrained, but these constraints may be * deactivated by the subsequent steps) */ if( state->steepestdescentstep&&ae_fp_less_eq(sasscaledconstrainednorm(&state->sas, &state->ugc, _state),state->epsg) ) { /* * Gradient is small enough. * Optimization is terminated */ state->repterminationtype = 4; goto lbl_44; } /* * 1. Calculate search direction D according to L-BFGS algorithm * using constrained preconditioner to perform inner multiplication. * 2. Evaluate scaled length of direction D; restart LBFGS if D is zero * (it may be possible that we found minimum, but it is also possible * that some constraints need deactivation) * 3. If D is non-zero, try to use previous scaled step length as initial estimate for new step. */ ae_v_move(&state->work.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=state->bufsize-1; i>=0; i--) { v = ae_v_dotproduct(&state->bufsk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->buftheta.ptr.p_double[i] = v; vv = v*state->bufrho.ptr.p_double[i]; ae_v_subd(&state->work.ptr.p_double[0], 1, &state->bufyk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } sasconstraineddirectionprec(&state->sas, &state->work, _state); for(i=0; i<=state->bufsize-1; i++) { v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = state->bufrho.ptr.p_double[i]*(-v+state->buftheta.ptr.p_double[i]); ae_v_addd(&state->work.ptr.p_double[0], 1, &state->bufsk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); if( ae_fp_eq(v,(double)(0)) ) { /* * Search direction is zero. * If we perform "steepest descent step", algorithm is terminated. * Otherwise we just restart LBFGS. */ if( state->steepestdescentstep ) { state->repterminationtype = 4; } goto lbl_44; } ae_assert(ae_fp_greater(v,(double)(0)), "MinBLEIC: internal error", _state); if( ae_fp_greater(state->lastscaledgoodstep,(double)(0))&&ae_fp_greater(v,(double)(0)) ) { state->stp = state->lastscaledgoodstep/v; } else { state->stp = 1.0/v; } /* * Calculate bound on step length. * Step direction is stored */ sasexploredirection(&state->sas, &state->d, &state->curstpmax, &state->cidx, &state->cval, _state); state->activationstep = state->curstpmax; if( state->cidx>=0&&ae_fp_eq(state->activationstep,(double)(0)) ) { /* * We are exactly at the boundary, immediate activation * of constraint is required. LBFGS stage is continued * with "refreshed" model. * * ! IMPORTANT: we do not clear SteepestDescent flag here, * ! it is very important for correct stopping * ! of algorithm. */ sasimmediateactivation(&state->sas, state->cidx, state->cval, _state); state->bufsize = 0; goto lbl_43; } if( ae_fp_greater(state->stpmax,(double)(0)) ) { v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_sqrt(v, _state); if( ae_fp_greater(v,(double)(0)) ) { state->curstpmax = ae_minreal(state->curstpmax, state->stpmax/v, _state); } } /* * Report beginning of line search (if requested by caller). * See description of the MinBLEICState for more information * about fields accessible to caller. * * Caller may do following: * * change State.Stp and load better initial estimate of * the step length. * Caller may not terminate algorithm. */ if( !state->drep ) { goto lbl_45; } minbleic_clearrequestfields(state, _state); state->lsstart = ae_true; state->boundedstep = state->cidx>=0; ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 14; goto lbl_rcomm; lbl_14: state->lsstart = ae_false; lbl_45: /* * Minimize F(x+alpha*d) */ ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->ugc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->fn = state->fc; state->mcstage = 0; mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); lbl_47: if( state->mcstage==0 ) { goto lbl_48; } /* * Perform correction (constraints are enforced) * Copy XN to X */ sascorrection(&state->sas, &state->xn, &penalty, _state); for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; } /* * Gradient, either user-provided or numerical differentiation */ minbleic_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_49; } /* * Analytic gradient */ state->needfg = ae_true; state->rstate.stage = 15; goto lbl_rcomm; lbl_15: state->needfg = ae_false; state->repnfev = state->repnfev+1; goto lbl_50; lbl_49: /* * Numerical differentiation */ state->needf = ae_true; state->rstate.stage = 16; goto lbl_rcomm; lbl_16: state->fbase = state->f; i = 0; lbl_51: if( i>n-1 ) { goto lbl_53; } v = state->x.ptr.p_double[i]; b = ae_false; if( state->hasbndl.ptr.p_bool[i] ) { b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); } if( state->hasbndu.ptr.p_bool[i] ) { b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); } if( b ) { goto lbl_54; } state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 17; goto lbl_rcomm; lbl_17: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 18; goto lbl_rcomm; lbl_18: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 19; goto lbl_rcomm; lbl_19: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 20; goto lbl_rcomm; lbl_20: state->fp2 = state->f; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); state->repnfev = state->repnfev+4; goto lbl_55; lbl_54: state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) { state->xm1 = state->bndl.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) { state->xp1 = state->bndu.ptr.p_double[i]; } state->x.ptr.p_double[i] = state->xm1; state->rstate.stage = 21; goto lbl_rcomm; lbl_21: state->fm1 = state->f; state->x.ptr.p_double[i] = state->xp1; state->rstate.stage = 22; goto lbl_rcomm; lbl_22: state->fp1 = state->f; if( ae_fp_neq(state->xm1,state->xp1) ) { state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); } else { state->g.ptr.p_double[i] = (double)(0); } state->repnfev = state->repnfev+2; lbl_55: state->x.ptr.p_double[i] = v; i = i+1; goto lbl_51; lbl_53: state->f = state->fbase; state->needf = ae_false; lbl_50: /* * Back to MCSRCH * * NOTE: penalty term from correction is added to FN in order * to penalize increase in infeasibility. */ state->fn = state->f+minbleic_penaltyfactor*state->maxscaledgrad*penalty; ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); sasconstraineddirection(&state->sas, &state->cgn, _state); trimfunction(&state->fn, &state->cgn, n, state->trimthreshold, _state); mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); goto lbl_47; lbl_48: ae_v_moveneg(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_moveneg(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Check for presence of NAN/INF in function/gradient */ v = state->fn; for(i=0; i<=n-1; i++) { v = 0.1*v+state->ugn.ptr.p_double[i]; } if( !ae_isfinite(v, _state) ) { /* * Abnormal termination - infinities in function/gradient */ state->repterminationtype = -8; goto lbl_44; } /* * Handle possible failure of the line search or request for termination */ if( mcinfo!=1&&mcinfo!=5 ) { /* * We can not find step which decreases function value. We have * two possibilities: * (a) numerical properties of the function do not allow us to * find good step. * (b) we are close to activation of some constraint, and it is * so close that step which activates it leads to change in * target function which is smaller than numerical noise. * * Optimization algorithm must be able to handle case (b), because * inability to handle it will cause failure when algorithm * started very close to boundary of the feasible area. * * In order to correctly handle such cases we allow limited amount * of small steps which increase function value. */ v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->d.ptr.p_double[i]*state->curstpmax/state->s.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); if( (state->cidx>=0&&ae_fp_less_eq(v,minbleic_maxnonmonotoniclen))&&state->nonmonotoniccnt>0 ) { /* * We enforce non-monotonic step: * * Stp := CurStpMax * * MCINFO := 5 * * XN := XC+CurStpMax*D * * non-monotonic counter is decreased * * NOTE: UGN/CGN are not updated because step is so short that we assume that * GN is approximately equal to GC. */ state->stp = state->curstpmax; mcinfo = 5; v = state->curstpmax; ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); state->nonmonotoniccnt = state->nonmonotoniccnt-1; } else { /* * Numerical properties of the function does not allow * us to solve problem. Here we have two possibilities: * * if it is "steepest descent" step, we can terminate * algorithm because we are close to minimum * * if it is NOT "steepest descent" step, we should restart * LBFGS iterations. */ if( state->steepestdescentstep ) { /* * Algorithm is terminated */ state->repterminationtype = 7; goto lbl_44; } else { /* * Re-evaluate active set and restart LBFGS */ goto lbl_44; } } } if( state->userterminationneeded ) { goto lbl_44; } /* * Current point is updated: * * move XC/FC/GC to XP/FP/GP * * change current point remembered by SAS structure * * move XN/FN/GN to XC/FC/GC * * report current point and update iterations counter * * if MCINFO=1, push new pair SK/YK to LBFGS buffer */ state->fp = state->fc; ae_v_move(&state->xp.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->fc = state->fn; ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->ugn.ptr.p_double[0], 1, ae_v_len(0,n-1)); actstatus = sasmoveto(&state->sas, &state->xn, state->cidx>=0&&ae_fp_greater_eq(state->stp,state->activationstep), state->cidx, state->cval, _state); if( !state->xrep ) { goto lbl_56; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); minbleic_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 23; goto lbl_rcomm; lbl_23: state->xupdated = ae_false; lbl_56: state->repinneriterationscount = state->repinneriterationscount+1; if( mcinfo==1 ) { /* * Accept new LBFGS update given by Sk,Yk */ if( state->bufsize==m ) { /* * Buffer is full, shift contents by one row */ for(i=0; i<=state->bufsize-1; i++) { ae_v_move(&state->bufsk.ptr.pp_double[i][0], 1, &state->bufsk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); ae_v_move(&state->bufyk.ptr.pp_double[i][0], 1, &state->bufyk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); } for(i=0; i<=state->bufsize-2; i++) { state->bufrho.ptr.p_double[i] = state->bufrho.ptr.p_double[i+1]; state->buftheta.ptr.p_double[i] = state->buftheta.ptr.p_double[i+1]; } } else { /* * Buffer is not full, increase buffer size by 1 */ state->bufsize = state->bufsize+1; } v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufsk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); vv = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); if( ae_fp_eq(v,(double)(0))||ae_fp_eq(vv,(double)(0)) ) { /* * Strange internal error in LBFGS - either YK=0 * (which should not have been) or (SK,YK)=0 (again, * unexpected). It should not take place because * MCINFO=1, which signals "good" step. But just * to be sure we have special branch of code which * restarts LBFGS */ goto lbl_44; } state->bufrho.ptr.p_double[state->bufsize-1] = 1/v; ae_assert(state->bufsize<=m, "MinBLEIC: internal error", _state); /* * Update length of the good step */ v = (double)(0); vv = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); vv = vv+ae_sqr(state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i], _state); } state->lastgoodstep = ae_sqrt(vv, _state); minbleic_updateestimateofgoodstep(&state->lastscaledgoodstep, ae_sqrt(v, _state), _state); } /* * Check stopping criteria * * Step size and function-based stopping criteria are tested only * for step which satisfies Wolfe conditions and is the first step of * LBFGS (subsequent steps may accumulate active constraints thus * they should NOT be used for stopping; step size or function change * may be small when constrained, but these constraints may be * deactivated by the subsequent steps). * * MaxIts-based stopping condition is checked for all kinds of steps. */ if( mcinfo==1&&state->steepestdescentstep ) { /* * Step is small enough */ v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); if( ae_fp_less_eq(v,state->epsx) ) { state->repterminationtype = 2; goto lbl_44; } /* * Function change is small enough */ if( ae_fp_less_eq(ae_fabs(state->fp-state->fc, _state),state->epsf*ae_maxreal(ae_fabs(state->fc, _state), ae_maxreal(ae_fabs(state->fp, _state), 1.0, _state), _state)) ) { state->repterminationtype = 1; goto lbl_44; } } if( state->maxits>0&&state->repinneriterationscount>=state->maxits ) { state->repterminationtype = 5; goto lbl_44; } /* * Clear "steepest descent" flag. */ state->steepestdescentstep = ae_false; /* * Smooth reset (LBFGS memory model is refreshed) or hard restart: * * LBFGS model is refreshed, if line search was performed with activation of constraints * * algorithm is restarted if scaled gradient decreased below GDecay */ if( actstatus>=0 ) { state->bufsize = 0; goto lbl_43; } v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } if( ae_fp_less(ae_sqrt(v, _state),gdecay*ginit) ) { goto lbl_44; } lbl_43: itidx = itidx+1; goto lbl_42; lbl_44: if( state->userterminationneeded ) { /* * User requested termination */ state->repterminationtype = 8; goto lbl_34; } if( state->repterminationtype!=0 ) { /* * Algorithm terminated */ goto lbl_34; } /* * Decrease decay coefficient. Subsequent L-BFGS stages will * have more stringent stopping criteria. */ gdecay = ae_maxreal(gdecay*minbleic_decaycorrection, minbleic_mindecay, _state); goto lbl_33; lbl_34: sasstopoptimization(&state->sas, _state); state->repouteriterationscount = 1; result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = i; state->rstate.ia.ptr.p_int[3] = j; state->rstate.ia.ptr.p_int[4] = mcinfo; state->rstate.ia.ptr.p_int[5] = actstatus; state->rstate.ia.ptr.p_int[6] = itidx; state->rstate.ba.ptr.p_bool[0] = b; state->rstate.ra.ptr.p_double[0] = v; state->rstate.ra.ptr.p_double[1] = vv; state->rstate.ra.ptr.p_double[2] = v0; state->rstate.ra.ptr.p_double[3] = penalty; state->rstate.ra.ptr.p_double[4] = ginit; state->rstate.ra.ptr.p_double[5] = gdecay; return result; } /************************************************************************* BLEIC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. * -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken * 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. More information about fields of this structure can be found in the comments on MinBLEICReport datatype. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresults(minbleicstate* state, /* Real */ ae_vector* x, minbleicreport* rep, ae_state *_state) { ae_vector_clear(x); _minbleicreport_clear(rep); minbleicresultsbuf(state, x, rep, _state); } /************************************************************************* BLEIC results Buffered implementation of MinBLEICResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicresultsbuf(minbleicstate* state, /* Real */ ae_vector* x, minbleicreport* rep, ae_state *_state) { ae_int_t i; if( x->cntnmain ) { ae_vector_set_length(x, state->nmain, _state); } rep->iterationscount = state->repinneriterationscount; rep->inneriterationscount = state->repinneriterationscount; rep->outeriterationscount = state->repouteriterationscount; rep->nfev = state->repnfev; rep->varidx = state->repvaridx; rep->terminationtype = state->repterminationtype; if( state->repterminationtype>0 ) { ae_v_move(&x->ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,state->nmain-1)); } else { for(i=0; i<=state->nmain-1; i++) { x->ptr.p_double[i] = _state->v_nan; } } rep->debugeqerr = state->repdebugeqerr; rep->debugfs = state->repdebugfs; rep->debugff = state->repdebugff; rep->debugdx = state->repdebugdx; rep->debugfeasqpits = state->repdebugfeasqpits; rep->debugfeasgpaits = state->repdebugfeasgpaits; } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicrestartfrom(minbleicstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; n = state->nmain; /* * First, check for errors in the inputs */ ae_assert(x->cnt>=n, "MinBLEICRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * prepare RComm facilities */ ae_vector_set_length(&state->rstate.ia, 6+1, _state); ae_vector_set_length(&state->rstate.ba, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 5+1, _state); state->rstate.stage = -1; minbleic_clearrequestfields(state, _state); sasstopoptimization(&state->sas, _state); } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minbleicrequesttermination(minbleicstate* state, ae_state *_state) { state->userterminationneeded = ae_true; } /************************************************************************* This subroutine finalizes internal structures after emergency termination from State.LSStart report (see comments on MinBLEICState for more information). INPUT PARAMETERS: State - structure after exit from LSStart report -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicemergencytermination(minbleicstate* state, ae_state *_state) { sasstopoptimization(&state->sas, _state); } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinBLEICOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinBLEICSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minbleicsetgradientcheck(minbleicstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "MinBLEICSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinBLEICSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Clears request fileds (to be sure that we don't forget to clear something) *************************************************************************/ static void minbleic_clearrequestfields(minbleicstate* state, ae_state *_state) { state->needf = ae_false; state->needfg = ae_false; state->xupdated = ae_false; state->lsstart = ae_false; } /************************************************************************* Internal initialization subroutine *************************************************************************/ static void minbleic_minbleicinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minbleicstate* state, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_matrix c; ae_vector ct; ae_frame_make(_state, &_frame_block); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); /* * Initialize */ state->teststep = (double)(0); state->nmain = n; state->diffstep = diffstep; sasinit(n, &state->sas, _state); ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->hasbndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->hasbndu, n, _state); ae_vector_set_length(&state->xstart, n, _state); ae_vector_set_length(&state->cgc, n, _state); ae_vector_set_length(&state->ugc, n, _state); ae_vector_set_length(&state->xn, n, _state); ae_vector_set_length(&state->cgn, n, _state); ae_vector_set_length(&state->ugn, n, _state); ae_vector_set_length(&state->xp, n, _state); ae_vector_set_length(&state->d, n, _state); ae_vector_set_length(&state->s, n, _state); ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->g, n, _state); ae_vector_set_length(&state->work, n, _state); for(i=0; i<=n-1; i++) { state->bndl.ptr.p_double[i] = _state->v_neginf; state->hasbndl.ptr.p_bool[i] = ae_false; state->bndu.ptr.p_double[i] = _state->v_posinf; state->hasbndu.ptr.p_bool[i] = ae_false; state->s.ptr.p_double[i] = 1.0; } minbleicsetlc(state, &c, &ct, 0, _state); minbleicsetcond(state, 0.0, 0.0, 0.0, 0, _state); minbleicsetxrep(state, ae_false, _state); minbleicsetdrep(state, ae_false, _state); minbleicsetstpmax(state, 0.0, _state); minbleicsetprecdefault(state, _state); minbleicrestartfrom(state, x, _state); ae_frame_leave(_state); } /************************************************************************* This subroutine updates estimate of the good step length given: 1) previous estimate 2) new length of the good step It makes sure that estimate does not change too rapidly - ratio of new and old estimates will be at least 0.01, at most 100.0 In case previous estimate of good step is zero (no estimate), new estimate is used unconditionally. -- ALGLIB -- Copyright 16.01.2013 by Bochkanov Sergey *************************************************************************/ static void minbleic_updateestimateofgoodstep(double* estimate, double newstep, ae_state *_state) { if( ae_fp_eq(*estimate,(double)(0)) ) { *estimate = newstep; return; } if( ae_fp_less(newstep,*estimate*0.01) ) { *estimate = *estimate*0.01; return; } if( ae_fp_greater(newstep,*estimate*100) ) { *estimate = *estimate*100; return; } *estimate = newstep; } void _minbleicstate_init(void* _p, ae_state *_state) { minbleicstate *p = (minbleicstate*)_p; ae_touch_ptr((void*)p); _sactiveset_init(&p->sas, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->diagh, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); ae_vector_init(&p->ugc, 0, DT_REAL, _state); ae_vector_init(&p->cgc, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->ugn, 0, DT_REAL, _state); ae_vector_init(&p->cgn, 0, DT_REAL, _state); ae_vector_init(&p->xp, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state); ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->xstart, 0, DT_REAL, _state); _snnlssolver_init(&p->solver, _state); ae_vector_init(&p->tmpprec, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->work, 0, DT_REAL, _state); _linminstate_init(&p->lstate, _state); ae_matrix_init(&p->bufyk, 0, 0, DT_REAL, _state); ae_matrix_init(&p->bufsk, 0, 0, DT_REAL, _state); ae_vector_init(&p->bufrho, 0, DT_REAL, _state); ae_vector_init(&p->buftheta, 0, DT_REAL, _state); } void _minbleicstate_init_copy(void* _dst, void* _src, ae_state *_state) { minbleicstate *dst = (minbleicstate*)_dst; minbleicstate *src = (minbleicstate*)_src; dst->nmain = src->nmain; dst->nslack = src->nslack; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->drep = src->drep; dst->stpmax = src->stpmax; dst->diffstep = src->diffstep; _sactiveset_init_copy(&dst->sas, &src->sas, _state); ae_vector_init_copy(&dst->s, &src->s, _state); dst->prectype = src->prectype; ae_vector_init_copy(&dst->diagh, &src->diagh, _state); ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); dst->needf = src->needf; dst->needfg = src->needfg; dst->xupdated = src->xupdated; dst->lsstart = src->lsstart; dst->steepestdescentstep = src->steepestdescentstep; dst->boundedstep = src->boundedstep; dst->userterminationneeded = src->userterminationneeded; dst->teststep = src->teststep; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); ae_vector_init_copy(&dst->ugc, &src->ugc, _state); ae_vector_init_copy(&dst->cgc, &src->cgc, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->ugn, &src->ugn, _state); ae_vector_init_copy(&dst->cgn, &src->cgn, _state); ae_vector_init_copy(&dst->xp, &src->xp, _state); dst->fc = src->fc; dst->fn = src->fn; dst->fp = src->fp; ae_vector_init_copy(&dst->d, &src->d, _state); ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); dst->nec = src->nec; dst->nic = src->nic; dst->lastgoodstep = src->lastgoodstep; dst->lastscaledgoodstep = src->lastscaledgoodstep; dst->maxscaledgrad = src->maxscaledgrad; ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state); ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repnfev = src->repnfev; dst->repvaridx = src->repvaridx; dst->repterminationtype = src->repterminationtype; dst->repdebugeqerr = src->repdebugeqerr; dst->repdebugfs = src->repdebugfs; dst->repdebugff = src->repdebugff; dst->repdebugdx = src->repdebugdx; dst->repdebugfeasqpits = src->repdebugfeasqpits; dst->repdebugfeasgpaits = src->repdebugfeasgpaits; ae_vector_init_copy(&dst->xstart, &src->xstart, _state); _snnlssolver_init_copy(&dst->solver, &src->solver, _state); dst->fbase = src->fbase; dst->fm2 = src->fm2; dst->fm1 = src->fm1; dst->fp1 = src->fp1; dst->fp2 = src->fp2; dst->xm1 = src->xm1; dst->xp1 = src->xp1; dst->gm1 = src->gm1; dst->gp1 = src->gp1; dst->cidx = src->cidx; dst->cval = src->cval; ae_vector_init_copy(&dst->tmpprec, &src->tmpprec, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); dst->nfev = src->nfev; dst->mcstage = src->mcstage; dst->stp = src->stp; dst->curstpmax = src->curstpmax; dst->activationstep = src->activationstep; ae_vector_init_copy(&dst->work, &src->work, _state); _linminstate_init_copy(&dst->lstate, &src->lstate, _state); dst->trimthreshold = src->trimthreshold; dst->nonmonotoniccnt = src->nonmonotoniccnt; ae_matrix_init_copy(&dst->bufyk, &src->bufyk, _state); ae_matrix_init_copy(&dst->bufsk, &src->bufsk, _state); ae_vector_init_copy(&dst->bufrho, &src->bufrho, _state); ae_vector_init_copy(&dst->buftheta, &src->buftheta, _state); dst->bufsize = src->bufsize; } void _minbleicstate_clear(void* _p) { minbleicstate *p = (minbleicstate*)_p; ae_touch_ptr((void*)p); _sactiveset_clear(&p->sas); ae_vector_clear(&p->s); ae_vector_clear(&p->diagh); ae_vector_clear(&p->x); ae_vector_clear(&p->g); _rcommstate_clear(&p->rstate); ae_vector_clear(&p->ugc); ae_vector_clear(&p->cgc); ae_vector_clear(&p->xn); ae_vector_clear(&p->ugn); ae_vector_clear(&p->cgn); ae_vector_clear(&p->xp); ae_vector_clear(&p->d); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->hasbndl); ae_vector_clear(&p->hasbndu); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->xstart); _snnlssolver_clear(&p->solver); ae_vector_clear(&p->tmpprec); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->work); _linminstate_clear(&p->lstate); ae_matrix_clear(&p->bufyk); ae_matrix_clear(&p->bufsk); ae_vector_clear(&p->bufrho); ae_vector_clear(&p->buftheta); } void _minbleicstate_destroy(void* _p) { minbleicstate *p = (minbleicstate*)_p; ae_touch_ptr((void*)p); _sactiveset_destroy(&p->sas); ae_vector_destroy(&p->s); ae_vector_destroy(&p->diagh); ae_vector_destroy(&p->x); ae_vector_destroy(&p->g); _rcommstate_destroy(&p->rstate); ae_vector_destroy(&p->ugc); ae_vector_destroy(&p->cgc); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->ugn); ae_vector_destroy(&p->cgn); ae_vector_destroy(&p->xp); ae_vector_destroy(&p->d); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->hasbndl); ae_vector_destroy(&p->hasbndu); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->xstart); _snnlssolver_destroy(&p->solver); ae_vector_destroy(&p->tmpprec); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->work); _linminstate_destroy(&p->lstate); ae_matrix_destroy(&p->bufyk); ae_matrix_destroy(&p->bufsk); ae_vector_destroy(&p->bufrho); ae_vector_destroy(&p->buftheta); } void _minbleicreport_init(void* _p, ae_state *_state) { minbleicreport *p = (minbleicreport*)_p; ae_touch_ptr((void*)p); } void _minbleicreport_init_copy(void* _dst, void* _src, ae_state *_state) { minbleicreport *dst = (minbleicreport*)_dst; minbleicreport *src = (minbleicreport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->varidx = src->varidx; dst->terminationtype = src->terminationtype; dst->debugeqerr = src->debugeqerr; dst->debugfs = src->debugfs; dst->debugff = src->debugff; dst->debugdx = src->debugdx; dst->debugfeasqpits = src->debugfeasqpits; dst->debugfeasgpaits = src->debugfeasgpaits; dst->inneriterationscount = src->inneriterationscount; dst->outeriterationscount = src->outeriterationscount; } void _minbleicreport_clear(void* _p) { minbleicreport *p = (minbleicreport*)_p; ae_touch_ptr((void*)p); } void _minbleicreport_destroy(void* _p) { minbleicreport *p = (minbleicreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using a quasi- Newton method (LBFGS scheme) which is optimized to use a minimum amount of memory. The subroutine generates the approximation of an inverse Hessian matrix by using information about the last M steps of the algorithm (instead of N). It lessens a required amount of memory from a value of order N^2 to a value of order 2*N*M. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinLBFGSCreate() call 2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() and other functions 3. User calls MinLBFGSOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinLBFGSResults() to get solution 5. Optionally user may call MinLBFGSRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLBFGSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension. N>0 M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - initial solution approximation, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLBFGSSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLBFGSSetStpMax() function to bound algorithm's steps. However, L-BFGS rarely needs such a tuning. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgscreate(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlbfgsstate* state, ae_state *_state) { _minlbfgsstate_clear(state); ae_assert(n>=1, "MinLBFGSCreate: N<1!", _state); ae_assert(m>=1, "MinLBFGSCreate: M<1", _state); ae_assert(m<=n, "MinLBFGSCreate: M>N", _state); ae_assert(x->cnt>=n, "MinLBFGSCreate: Length(X)0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinLBFGSSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. LBFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgscreatef(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, double diffstep, minlbfgsstate* state, ae_state *_state) { _minlbfgsstate_clear(state); ae_assert(n>=1, "MinLBFGSCreateF: N too small!", _state); ae_assert(m>=1, "MinLBFGSCreateF: M<1", _state); ae_assert(m<=n, "MinLBFGSCreateF: M>N", _state); ae_assert(x->cnt>=n, "MinLBFGSCreateF: Length(X)=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLBFGSSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcond(minlbfgsstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinLBFGSSetCond: EpsG is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinLBFGSSetCond: negative EpsG!", _state); ae_assert(ae_isfinite(epsf, _state), "MinLBFGSSetCond: EpsF is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinLBFGSSetCond: negative EpsF!", _state); ae_assert(ae_isfinite(epsx, _state), "MinLBFGSSetCond: EpsX is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinLBFGSSetCond: negative EpsX!", _state); ae_assert(maxits>=0, "MinLBFGSSetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLBFGSOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetxrep(minlbfgsstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetstpmax(minlbfgsstate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "MinLBFGSSetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinLBFGSSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* This function sets scaling coefficients for LBFGS optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the LBFGS too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinLBFGSSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlbfgssetscale(minlbfgsstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->n, "MinLBFGSSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLBFGSSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinLBFGSSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* Extended subroutine for internal use only. Accepts additional parameters: Flags - additional settings: * Flags = 0 means no additional settings * Flags = 1 "do not allocate memory". used when solving a many subsequent tasks with same N/M values. First call MUST be without this flag bit set, subsequent calls of MinLBFGS with same MinLBFGSState structure can set Flags to 1. DiffStep - numerical differentiation step -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgscreatex(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, ae_int_t flags, double diffstep, minlbfgsstate* state, ae_state *_state) { ae_bool allocatemem; ae_int_t i; ae_assert(n>=1, "MinLBFGS: N too small!", _state); ae_assert(m>=1, "MinLBFGS: M too small!", _state); ae_assert(m<=n, "MinLBFGS: M too large!", _state); /* * Initialize */ state->teststep = (double)(0); state->diffstep = diffstep; state->n = n; state->m = m; allocatemem = flags%2==0; flags = flags/2; if( allocatemem ) { ae_vector_set_length(&state->rho, m, _state); ae_vector_set_length(&state->theta, m, _state); ae_matrix_set_length(&state->yk, m, n, _state); ae_matrix_set_length(&state->sk, m, n, _state); ae_vector_set_length(&state->d, n, _state); ae_vector_set_length(&state->xp, n, _state); ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->s, n, _state); ae_vector_set_length(&state->g, n, _state); ae_vector_set_length(&state->work, n, _state); } minlbfgssetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minlbfgssetxrep(state, ae_false, _state); minlbfgssetstpmax(state, (double)(0), _state); minlbfgsrestartfrom(state, x, _state); for(i=0; i<=n-1; i++) { state->s.ptr.p_double[i] = 1.0; } state->prectype = 0; } /************************************************************************* Modification of the preconditioner: default preconditioner (simple scaling, same for all elements of X) is used. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state) { state->prectype = 0; } /************************************************************************* Modification of the preconditioner: Cholesky factorization of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state P - triangular preconditioner, Cholesky factorization of the approximate Hessian. array[0..N-1,0..N-1], (if larger, only leading N elements are used). IsUpper - whether upper or lower triangle of P is given (other triangle is not referenced) After call to this function preconditioner is changed to P (P is copied into the internal buffer). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: P should be nonsingular. Exception will be thrown otherwise. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetpreccholesky(minlbfgsstate* state, /* Real */ ae_matrix* p, ae_bool isupper, ae_state *_state) { ae_int_t i; double mx; ae_assert(isfinitertrmatrix(p, state->n, isupper, _state), "MinLBFGSSetPrecCholesky: P contains infinite or NAN values!", _state); mx = (double)(0); for(i=0; i<=state->n-1; i++) { mx = ae_maxreal(mx, ae_fabs(p->ptr.pp_double[i][i], _state), _state); } ae_assert(ae_fp_greater(mx,(double)(0)), "MinLBFGSSetPrecCholesky: P is strictly singular!", _state); if( state->denseh.rowsn||state->denseh.colsn ) { ae_matrix_set_length(&state->denseh, state->n, state->n, _state); } state->prectype = 1; if( isupper ) { rmatrixcopy(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); } else { rmatrixtranspose(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); } } /************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecdiag(minlbfgsstate* state, /* Real */ ae_vector* d, ae_state *_state) { ae_int_t i; ae_assert(d->cnt>=state->n, "MinLBFGSSetPrecDiag: D is too short", _state); for(i=0; i<=state->n-1; i++) { ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinLBFGSSetPrecDiag: D contains infinite or NAN elements", _state); ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinLBFGSSetPrecDiag: D contains non-positive elements", _state); } rvectorsetlengthatleast(&state->diagh, state->n, _state); state->prectype = 2; for(i=0; i<=state->n-1; i++) { state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; } } /************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state) { state->prectype = 3; } /************************************************************************* This function sets low-rank preconditioner for Hessian matrix H=D+W'*C*W, where: * H is a Hessian matrix, which is approximated by D/W/C * D is a NxN diagonal positive definite matrix * W is a KxN low-rank correction * C is a KxK positive definite diagonal factor of low-rank correction This preconditioner is inexact but fast - it requires O(N*K) time to be applied. Preconditioner P is calculated by artificially constructing a set of BFGS updates which tries to reproduce behavior of H: * Sk = Wk (k-th row of W) * Yk = (D+Wk'*Ck*Wk)*Sk * Yk/Sk are reordered by ascending of C[k]*norm(Wk)^2 Here we assume that rows of Wk are orthogonal or nearly orthogonal, which allows us to have O(N*K+K^2) update instead of O(N*K^2) one. Reordering of updates is essential for having good performance on non-orthogonal problems (updates which do not add much of curvature are added first, and updates which add very large eigenvalues are added last and override effect of the first updates). In practice, this preconditioner is perfect when ortogonal correction is applied; on non-orthogonal problems sometimes it allows to achieve 5x speedup (when compared to non-preconditioned solver). -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetprecrankklbfgsfast(minlbfgsstate* state, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t cnt, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; n = state->n; state->prectype = 4; state->preck = cnt; rvectorsetlengthatleast(&state->precc, cnt, _state); rvectorsetlengthatleast(&state->precd, n, _state); rmatrixsetlengthatleast(&state->precw, cnt, n, _state); for(i=0; i<=n-1; i++) { state->precd.ptr.p_double[i] = d->ptr.p_double[i]; } for(i=0; i<=cnt-1; i++) { state->precc.ptr.p_double[i] = c->ptr.p_double[i]; for(j=0; j<=n-1; j++) { state->precw.ptr.pp_double[i][j] = w->ptr.pp_double[i][j]; } } } /************************************************************************* This function sets exact low-rank preconditioner for Hessian matrix H=D+W'*C*W, where: * H is a Hessian matrix, which is approximated by D/W/C * D is a NxN diagonal positive definite matrix * W is a KxN low-rank correction * C is a KxK semidefinite diagonal factor of low-rank correction This preconditioner is exact but slow - it requires O(N*K^2) time to be built and O(N*K) time to be applied. Woodbury matrix identity is used to build inverse matrix. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetpreclowrankexact(minlbfgsstate* state, /* Real */ ae_vector* d, /* Real */ ae_vector* c, /* Real */ ae_matrix* w, ae_int_t cnt, ae_state *_state) { state->prectype = 5; preparelowrankpreconditioner(d, c, w, state->n, cnt, &state->lowrankbuf, _state); } /************************************************************************* NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() for numerical differentiation) you should choose appropriate variant of MinLBFGSOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinLBFGSOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinLBFGSOptimize() and specific function used to create optimizer. | USER PASSED TO MinLBFGSOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinLBFGSCreateF() | work FAIL MinLBFGSCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinLBFGSOptimize() version. Attemps to use such combination (for example, to create optimizer with MinLBFGSCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state) { ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; ae_int_t ic; ae_int_t mcinfo; double v; double vv; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; i = state->rstate.ia.ptr.p_int[2]; j = state->rstate.ia.ptr.p_int[3]; ic = state->rstate.ia.ptr.p_int[4]; mcinfo = state->rstate.ia.ptr.p_int[5]; v = state->rstate.ra.ptr.p_double[0]; vv = state->rstate.ra.ptr.p_double[1]; } else { n = -983; m = -989; i = -834; j = 900; ic = -287; mcinfo = 364; v = 214; vv = -338; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } if( state->rstate.stage==14 ) { goto lbl_14; } if( state->rstate.stage==15 ) { goto lbl_15; } if( state->rstate.stage==16 ) { goto lbl_16; } /* * Routine body */ /* * Unload frequently used variables from State structure * (just for typing convinience) */ n = state->n; m = state->m; state->userterminationneeded = ae_false; state->repterminationtype = 0; state->repiterationscount = 0; state->repvaridx = -1; state->repnfev = 0; /* * Check, that transferred derivative value is right */ minlbfgs_clearrequestfields(state, _state); if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) { goto lbl_17; } state->needfg = ae_true; i = 0; lbl_19: if( i>n-1 ) { goto lbl_21; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->fm1 = state->f; state->fp1 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->fm2 = state->f; state->fp2 = state->g.ptr.p_double[i]; state->x.ptr.p_double[i] = v; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: /* * 2*State.TestStep - scale parameter * width of segment [Xi-TestStep;Xi+TestStep] */ if( !derivativecheck(state->fm1, state->fp1, state->fm2, state->fp2, state->f, state->g.ptr.p_double[i], 2*state->teststep, _state) ) { state->repvaridx = i; state->repterminationtype = -7; result = ae_false; return result; } i = i+1; goto lbl_19; lbl_21: state->needfg = ae_false; lbl_17: /* * Calculate F/G at the initial point */ minlbfgs_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_22; } state->needfg = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needfg = ae_false; goto lbl_23; lbl_22: state->needf = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->fbase = state->f; i = 0; lbl_24: if( i>n-1 ) { goto lbl_26; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->fp2 = state->f; state->x.ptr.p_double[i] = v; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); i = i+1; goto lbl_24; lbl_26: state->f = state->fbase; state->needf = ae_false; lbl_23: trimprepare(state->f, &state->trimthreshold, _state); if( !state->xrep ) { goto lbl_27; } minlbfgs_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->xupdated = ae_false; lbl_27: if( state->userterminationneeded ) { /* * User requested termination */ state->repterminationtype = 8; result = ae_false; return result; } state->repnfev = 1; state->fold = state->f; v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) { state->repterminationtype = 4; result = ae_false; return result; } /* * Choose initial step and direction. * Apply preconditioner, if we have something other than default. */ ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( state->prectype==0 ) { /* * Default preconditioner is used, but we can't use it before iterations will start */ v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_sqrt(v, _state); if( ae_fp_eq(state->stpmax,(double)(0)) ) { state->stp = ae_minreal(1.0/v, (double)(1), _state); } else { state->stp = ae_minreal(1.0/v, state->stpmax, _state); } } if( state->prectype==1 ) { /* * Cholesky preconditioner is used */ fblscholeskysolve(&state->denseh, 1.0, n, ae_true, &state->d, &state->autobuf, _state); state->stp = (double)(1); } if( state->prectype==2 ) { /* * diagonal approximation is used */ for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = state->d.ptr.p_double[i]/state->diagh.ptr.p_double[i]; } state->stp = (double)(1); } if( state->prectype==3 ) { /* * scale-based preconditioner is used */ for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = state->d.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; } state->stp = (double)(1); } if( state->prectype==4 ) { /* * rank-k BFGS-based preconditioner is used */ inexactlbfgspreconditioner(&state->d, n, &state->precd, &state->precc, &state->precw, state->preck, &state->precbuf, _state); state->stp = (double)(1); } if( state->prectype==5 ) { /* * exact low-rank preconditioner is used */ applylowrankpreconditioner(&state->d, &state->lowrankbuf, _state); state->stp = (double)(1); } /* * Main cycle */ state->k = 0; lbl_29: if( ae_false ) { goto lbl_30; } /* * Main cycle: prepare to 1-D line search */ state->p = state->k%m; state->q = ae_minint(state->k, m-1, _state); /* * Store X[k], G[k] */ ae_v_move(&state->xp.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_moveneg(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_moveneg(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Minimize F(x+alpha*d) * Calculate S[k], Y[k] */ state->mcstage = 0; if( state->k!=0 ) { state->stp = 1.0; } linminnormalized(&state->d, &state->stp, n, _state); mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); lbl_31: if( state->mcstage==0 ) { goto lbl_32; } minlbfgs_clearrequestfields(state, _state); if( ae_fp_neq(state->diffstep,(double)(0)) ) { goto lbl_33; } state->needfg = ae_true; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->needfg = ae_false; goto lbl_34; lbl_33: state->needf = ae_true; state->rstate.stage = 11; goto lbl_rcomm; lbl_11: state->fbase = state->f; i = 0; lbl_35: if( i>n-1 ) { goto lbl_37; } v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 12; goto lbl_rcomm; lbl_12: state->fm2 = state->f; state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->fm1 = state->f; state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 14; goto lbl_rcomm; lbl_14: state->fp1 = state->f; state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; state->rstate.stage = 15; goto lbl_rcomm; lbl_15: state->fp2 = state->f; state->x.ptr.p_double[i] = v; state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); i = i+1; goto lbl_35; lbl_37: state->f = state->fbase; state->needf = ae_false; lbl_34: trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); goto lbl_31; lbl_32: if( state->userterminationneeded ) { /* * User requested termination. * Restore previous point and return. */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xp.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } if( !state->xrep ) { goto lbl_38; } /* * report */ minlbfgs_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 16; goto lbl_rcomm; lbl_16: state->xupdated = ae_false; lbl_38: state->repnfev = state->repnfev+state->nfev; state->repiterationscount = state->repiterationscount+1; ae_v_add(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Stopping conditions */ v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); } if( !ae_isfinite(v, _state)||!ae_isfinite(state->f, _state) ) { /* * Abnormal termination - infinities in function/gradient */ state->repterminationtype = -8; result = ae_false; return result; } if( state->repiterationscount>=state->maxits&&state->maxits>0 ) { /* * Too many iterations */ state->repterminationtype = 5; result = ae_false; return result; } if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) { /* * Gradient is small enough */ state->repterminationtype = 4; result = ae_false; return result; } if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) { /* * F(k+1)-F(k) is small enough */ state->repterminationtype = 1; result = ae_false; return result; } v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->sk.ptr.pp_double[state->p][i]/state->s.ptr.p_double[i], _state); } if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsx) ) { /* * X(k+1)-X(k) is small enough */ state->repterminationtype = 2; result = ae_false; return result; } /* * If Wolfe conditions are satisfied, we can update * limited memory model. * * However, if conditions are not satisfied (NFEV limit is met, * function is too wild, ...), we'll skip L-BFGS update */ if( mcinfo!=1 ) { /* * Skip update. * * In such cases we'll initialize search direction by * antigradient vector, because it leads to more * transparent code with less number of special cases */ state->fold = state->f; ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); } else { /* * Calculate Rho[k], GammaK */ v = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->sk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); vv = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->yk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); if( ae_fp_eq(v,(double)(0))||ae_fp_eq(vv,(double)(0)) ) { /* * Rounding errors make further iterations impossible. */ state->repterminationtype = -2; result = ae_false; return result; } state->rho.ptr.p_double[state->p] = 1/v; state->gammak = v/vv; /* * Calculate d(k+1) = -H(k+1)*g(k+1) * * for I:=K downto K-Q do * V = s(i)^T * work(iteration:I) * theta(i) = V * work(iteration:I+1) = work(iteration:I) - V*Rho(i)*y(i) * work(last iteration) = H0*work(last iteration) - preconditioner * for I:=K-Q to K do * V = y(i)^T*work(iteration:I) * work(iteration:I+1) = work(iteration:I) +(-V+theta(i))*Rho(i)*s(i) * * NOW WORK CONTAINS d(k+1) */ ae_v_move(&state->work.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=state->k; i>=state->k-state->q; i--) { ic = i%m; v = ae_v_dotproduct(&state->sk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->theta.ptr.p_double[ic] = v; vv = v*state->rho.ptr.p_double[ic]; ae_v_subd(&state->work.ptr.p_double[0], 1, &state->yk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); } if( state->prectype==0 ) { /* * Simple preconditioner is used */ v = state->gammak; ae_v_muld(&state->work.ptr.p_double[0], 1, ae_v_len(0,n-1), v); } if( state->prectype==1 ) { /* * Cholesky preconditioner is used */ fblscholeskysolve(&state->denseh, (double)(1), n, ae_true, &state->work, &state->autobuf, _state); } if( state->prectype==2 ) { /* * diagonal approximation is used */ for(i=0; i<=n-1; i++) { state->work.ptr.p_double[i] = state->work.ptr.p_double[i]/state->diagh.ptr.p_double[i]; } } if( state->prectype==3 ) { /* * scale-based preconditioner is used */ for(i=0; i<=n-1; i++) { state->work.ptr.p_double[i] = state->work.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; } } if( state->prectype==4 ) { /* * Rank-K BFGS-based preconditioner is used */ inexactlbfgspreconditioner(&state->work, n, &state->precd, &state->precc, &state->precw, state->preck, &state->precbuf, _state); } if( state->prectype==5 ) { /* * Exact low-rank preconditioner is used */ applylowrankpreconditioner(&state->work, &state->lowrankbuf, _state); } for(i=state->k-state->q; i<=state->k; i++) { ic = i%m; v = ae_v_dotproduct(&state->yk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]); ae_v_addd(&state->work.ptr.p_double[0], 1, &state->sk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); } ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Next step */ state->fold = state->f; state->k = state->k+1; } goto lbl_29; lbl_30: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = i; state->rstate.ia.ptr.p_int[3] = j; state->rstate.ia.ptr.p_int[4] = ic; state->rstate.ia.ptr.p_int[5] = mcinfo; state->rstate.ra.ptr.p_double[0] = v; state->rstate.ra.ptr.p_double[1] = vv; return result; } /************************************************************************* L-BFGS algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. * -2 rounding errors prevent further improvement. X contains best point found. * -1 incorrect parameters were specified * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresults(minlbfgsstate* state, /* Real */ ae_vector* x, minlbfgsreport* rep, ae_state *_state) { ae_vector_clear(x); _minlbfgsreport_clear(rep); minlbfgsresultsbuf(state, x, rep, _state); } /************************************************************************* L-BFGS algorithm results Buffered implementation of MinLBFGSResults which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsresultsbuf(minlbfgsstate* state, /* Real */ ae_vector* x, minlbfgsreport* rep, ae_state *_state) { if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nfev = state->repnfev; rep->varidx = state->repvaridx; rep->terminationtype = state->repterminationtype; } /************************************************************************* This subroutine restarts LBFGS algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgsrestartfrom(minlbfgsstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_assert(x->cnt>=state->n, "MinLBFGSRestartFrom: Length(X)n, _state), "MinLBFGSRestartFrom: X contains infinite or NaN values!", _state); ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_vector_set_length(&state->rstate.ia, 5+1, _state); ae_vector_set_length(&state->rstate.ra, 1+1, _state); state->rstate.stage = -1; minlbfgs_clearrequestfields(state, _state); } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlbfgsrequesttermination(minlbfgsstate* state, ae_state *_state) { state->userterminationneeded = ae_true; } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLBFGSOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLBFGSSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 24.05.2012 by Bochkanov Sergey *************************************************************************/ void minlbfgssetgradientcheck(minlbfgsstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "MinLBFGSSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinLBFGSSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void minlbfgs_clearrequestfields(minlbfgsstate* state, ae_state *_state) { state->needf = ae_false; state->needfg = ae_false; state->xupdated = ae_false; } void _minlbfgsstate_init(void* _p, ae_state *_state) { minlbfgsstate *p = (minlbfgsstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->rho, 0, DT_REAL, _state); ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state); ae_matrix_init(&p->sk, 0, 0, DT_REAL, _state); ae_vector_init(&p->xp, 0, DT_REAL, _state); ae_vector_init(&p->theta, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->work, 0, DT_REAL, _state); ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state); ae_vector_init(&p->diagh, 0, DT_REAL, _state); ae_vector_init(&p->precc, 0, DT_REAL, _state); ae_vector_init(&p->precd, 0, DT_REAL, _state); ae_matrix_init(&p->precw, 0, 0, DT_REAL, _state); _precbuflbfgs_init(&p->precbuf, _state); _precbuflowrank_init(&p->lowrankbuf, _state); ae_vector_init(&p->autobuf, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); _linminstate_init(&p->lstate, _state); } void _minlbfgsstate_init_copy(void* _dst, void* _src, ae_state *_state) { minlbfgsstate *dst = (minlbfgsstate*)_dst; minlbfgsstate *src = (minlbfgsstate*)_src; dst->n = src->n; dst->m = src->m; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->stpmax = src->stpmax; ae_vector_init_copy(&dst->s, &src->s, _state); dst->diffstep = src->diffstep; dst->nfev = src->nfev; dst->mcstage = src->mcstage; dst->k = src->k; dst->q = src->q; dst->p = src->p; ae_vector_init_copy(&dst->rho, &src->rho, _state); ae_matrix_init_copy(&dst->yk, &src->yk, _state); ae_matrix_init_copy(&dst->sk, &src->sk, _state); ae_vector_init_copy(&dst->xp, &src->xp, _state); ae_vector_init_copy(&dst->theta, &src->theta, _state); ae_vector_init_copy(&dst->d, &src->d, _state); dst->stp = src->stp; ae_vector_init_copy(&dst->work, &src->work, _state); dst->fold = src->fold; dst->trimthreshold = src->trimthreshold; dst->prectype = src->prectype; dst->gammak = src->gammak; ae_matrix_init_copy(&dst->denseh, &src->denseh, _state); ae_vector_init_copy(&dst->diagh, &src->diagh, _state); ae_vector_init_copy(&dst->precc, &src->precc, _state); ae_vector_init_copy(&dst->precd, &src->precd, _state); ae_matrix_init_copy(&dst->precw, &src->precw, _state); dst->preck = src->preck; _precbuflbfgs_init_copy(&dst->precbuf, &src->precbuf, _state); _precbuflowrank_init_copy(&dst->lowrankbuf, &src->lowrankbuf, _state); dst->fbase = src->fbase; dst->fm2 = src->fm2; dst->fm1 = src->fm1; dst->fp1 = src->fp1; dst->fp2 = src->fp2; ae_vector_init_copy(&dst->autobuf, &src->autobuf, _state); ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); dst->needf = src->needf; dst->needfg = src->needfg; dst->xupdated = src->xupdated; dst->userterminationneeded = src->userterminationneeded; dst->teststep = src->teststep; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->repiterationscount = src->repiterationscount; dst->repnfev = src->repnfev; dst->repvaridx = src->repvaridx; dst->repterminationtype = src->repterminationtype; _linminstate_init_copy(&dst->lstate, &src->lstate, _state); } void _minlbfgsstate_clear(void* _p) { minlbfgsstate *p = (minlbfgsstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->s); ae_vector_clear(&p->rho); ae_matrix_clear(&p->yk); ae_matrix_clear(&p->sk); ae_vector_clear(&p->xp); ae_vector_clear(&p->theta); ae_vector_clear(&p->d); ae_vector_clear(&p->work); ae_matrix_clear(&p->denseh); ae_vector_clear(&p->diagh); ae_vector_clear(&p->precc); ae_vector_clear(&p->precd); ae_matrix_clear(&p->precw); _precbuflbfgs_clear(&p->precbuf); _precbuflowrank_clear(&p->lowrankbuf); ae_vector_clear(&p->autobuf); ae_vector_clear(&p->x); ae_vector_clear(&p->g); _rcommstate_clear(&p->rstate); _linminstate_clear(&p->lstate); } void _minlbfgsstate_destroy(void* _p) { minlbfgsstate *p = (minlbfgsstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->s); ae_vector_destroy(&p->rho); ae_matrix_destroy(&p->yk); ae_matrix_destroy(&p->sk); ae_vector_destroy(&p->xp); ae_vector_destroy(&p->theta); ae_vector_destroy(&p->d); ae_vector_destroy(&p->work); ae_matrix_destroy(&p->denseh); ae_vector_destroy(&p->diagh); ae_vector_destroy(&p->precc); ae_vector_destroy(&p->precd); ae_matrix_destroy(&p->precw); _precbuflbfgs_destroy(&p->precbuf); _precbuflowrank_destroy(&p->lowrankbuf); ae_vector_destroy(&p->autobuf); ae_vector_destroy(&p->x); ae_vector_destroy(&p->g); _rcommstate_destroy(&p->rstate); _linminstate_destroy(&p->lstate); } void _minlbfgsreport_init(void* _p, ae_state *_state) { minlbfgsreport *p = (minlbfgsreport*)_p; ae_touch_ptr((void*)p); } void _minlbfgsreport_init_copy(void* _dst, void* _src, ae_state *_state) { minlbfgsreport *dst = (minlbfgsreport*)_dst; minlbfgsreport *src = (minlbfgsreport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->varidx = src->varidx; dst->terminationtype = src->terminationtype; } void _minlbfgsreport_clear(void* _p) { minlbfgsreport *p = (minlbfgsreport*)_p; ae_touch_ptr((void*)p); } void _minlbfgsreport_destroy(void* _p) { minlbfgsreport *p = (minlbfgsreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* This function initializes QQPSettings structure with default settings. Newly created structure MUST be initialized by default settings - or by copy of the already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qqploaddefaults(ae_int_t nmain, qqpsettings* s, ae_state *_state) { s->epsg = 0.0; s->epsf = 0.0; s->epsx = 1.0E-6; s->maxouterits = 0; s->cgphase = ae_true; s->cnphase = ae_true; s->cgminits = 5; s->cgmaxits = ae_maxint(s->cgminits, ae_round(1+0.33*nmain, _state), _state); s->sparsesolver = 0; s->cnmaxupdates = ae_round(1+0.1*nmain, _state); } /************************************************************************* This function initializes QQPSettings structure with copy of another, already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qqpcopysettings(qqpsettings* src, qqpsettings* dst, ae_state *_state) { dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxouterits = src->maxouterits; dst->cgphase = src->cgphase; dst->cnphase = src->cnphase; dst->cgminits = src->cgminits; dst->cgmaxits = src->cgmaxits; dst->sparsesolver = src->sparsesolver; dst->cnmaxupdates = src->cnmaxupdates; } /************************************************************************* This function runs QQP solver; it returns after optimization process was completed. Following QP problem is solved: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) subject to boundary constraints. IMPORTANT: UNLIKE MANY OTHER SOLVERS, THIS FUNCTION DOES NOT REQUIRE YOU TO INITIALIZE STATE OBJECT. IT CAN BE AUTOMATICALLY INITIALIZED DURING SOLUTION PROCESS. INPUT PARAMETERS: AC - for dense problems (AKind=0) A-term of CQM object contains system matrix. Other terms are unspecified and should not be referenced. SparseAC - for sparse problems (AKind=1 AKind - sparse matrix format: * 0 for dense matrix * 1 for sparse matrix SparseUpper - which triangle of SparseAC stores matrix - upper or lower one (for dense matrices this parameter is not actual). BC - linear term, array[NC] BndLC - lower bound, array[NC] BndUC - upper bound, array[NC] SC - scale vector, array[NC]: * I-th element contains scale of I-th variable, * SC[I]>0 XOriginC - origin term, array[NC]. Can be zero. NC - number of variables in the original formulation (no slack variables). CLEICC - linear equality/inequality constraints. Present version of this function does NOT provide publicly available support for linear constraints. This feature will be introduced in the future versions of the function. NEC, NIC - number of equality/inequality constraints. MUST BE ZERO IN THE CURRENT VERSION!!! Settings - QQPSettings object initialized by one of the initialization functions. SState - object which stores temporaries: * uninitialized object is automatically initialized * previously allocated memory is reused as much as possible XS - initial point, array[NC] OUTPUT PARAMETERS: XS - last point TerminationType-termination type: * * * -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qqpoptimize(convexquadraticmodel* ac, sparsematrix* sparseac, ae_int_t akind, ae_bool sparseupper, /* Real */ ae_vector* bc, /* Real */ ae_vector* bndlc, /* Real */ ae_vector* bnduc, /* Real */ ae_vector* sc, /* Real */ ae_vector* xoriginc, ae_int_t nc, /* Real */ ae_matrix* cleicc, ae_int_t nec, ae_int_t nic, qqpsettings* settings, qqpbuffers* sstate, /* Real */ ae_vector* xs, ae_int_t* terminationtype, ae_state *_state) { ae_int_t n; ae_int_t nmain; ae_int_t i; ae_int_t j; ae_int_t k; double v; double vv; double d2; double d1; ae_int_t d1est; ae_int_t d2est; ae_bool needact; double reststp; double fullstp; double stpmax; double stp; ae_int_t stpcnt; ae_int_t cidx; double cval; ae_int_t cgcnt; ae_int_t cgmax; ae_int_t newtcnt; ae_int_t sparsesolver; double beta; ae_bool b; double fprev; double fcur; *terminationtype = 0; /* * Primary checks */ ae_assert(akind==0||akind==1, "QQPOptimize: incorrect AKind", _state); sstate->nmain = nc; sstate->nslack = nic; sstate->n = nc+nic; sstate->nec = nec; sstate->nic = nic; sstate->akind = akind; n = sstate->n; nmain = sstate->nmain; *terminationtype = 0; sstate->repinneriterationscount = 0; sstate->repouteriterationscount = 0; sstate->repncholesky = 0; sstate->repncupdates = 0; /* * Several checks * * matrix size * * scale vector * * consistency of bound constraints * * consistency of settings */ if( akind==1 ) { ae_assert(sparsegetnrows(sparseac, _state)==nmain, "QQPOptimize: rows(SparseAC)<>NMain", _state); ae_assert(sparsegetncols(sparseac, _state)==nmain, "QQPOptimize: cols(SparseAC)<>NMain", _state); } for(i=0; i<=nmain-1; i++) { ae_assert(ae_isfinite(sc->ptr.p_double[i], _state)&&ae_fp_greater(sc->ptr.p_double[i],(double)(0)), "QQPOptimize: incorrect scale", _state); } for(i=0; i<=nmain-1; i++) { if( ae_isfinite(bndlc->ptr.p_double[i], _state)&&ae_isfinite(bnduc->ptr.p_double[i], _state) ) { if( ae_fp_greater(bndlc->ptr.p_double[i],bnduc->ptr.p_double[i]) ) { *terminationtype = -3; return; } } } ae_assert(settings->cgphase||settings->cnphase, "QQPOptimize: both phases (CG and Newton) are inactive", _state); /* * Allocate data structures */ rvectorsetlengthatleast(&sstate->bndl, n, _state); rvectorsetlengthatleast(&sstate->bndu, n, _state); bvectorsetlengthatleast(&sstate->havebndl, n, _state); bvectorsetlengthatleast(&sstate->havebndu, n, _state); rvectorsetlengthatleast(&sstate->xs, n, _state); rvectorsetlengthatleast(&sstate->xp, n, _state); rvectorsetlengthatleast(&sstate->gc, n, _state); rvectorsetlengthatleast(&sstate->cgc, n, _state); rvectorsetlengthatleast(&sstate->cgp, n, _state); rvectorsetlengthatleast(&sstate->dc, n, _state); rvectorsetlengthatleast(&sstate->dp, n, _state); rvectorsetlengthatleast(&sstate->tmp0, n, _state); rvectorsetlengthatleast(&sstate->stpbuf, 15, _state); sasinit(n, &sstate->sas, _state); /* * Scale/shift problem coefficients: * * min { 0.5*(x-x0)'*A*(x-x0) + b'*(x-x0) } * * becomes (after transformation "x = S*y+x0") * * min { 0.5*y'*(S*A*S)*y + (S*b)'*y * * Modified A_mod=S*A*S and b_mod=S*(b+A*x0) are * stored into SState.DenseA and SState.B. * * NOTE: DenseA/DenseB are arrays whose lengths are * NMain, not N=NMain+NSlack! We store reduced * matrix and vector because extend parts (last * NSlack rows/columns) are exactly zero. * */ rvectorsetlengthatleast(&sstate->b, nmain, _state); for(i=0; i<=nmain-1; i++) { sstate->b.ptr.p_double[i] = sc->ptr.p_double[i]*bc->ptr.p_double[i]; } if( akind==0 ) { /* * Dense QP problem - just copy and scale. */ rmatrixsetlengthatleast(&sstate->densea, nmain, nmain, _state); cqmgeta(ac, &sstate->densea, _state); sstate->absamax = (double)(0); sstate->absasum = (double)(0); sstate->absasum2 = (double)(0); for(i=0; i<=nmain-1; i++) { for(j=0; j<=nmain-1; j++) { v = sc->ptr.p_double[i]*sstate->densea.ptr.pp_double[i][j]*sc->ptr.p_double[j]; sstate->densea.ptr.pp_double[i][j] = v; sstate->absamax = ae_maxreal(sstate->absamax, v, _state); sstate->absasum = sstate->absasum+v; sstate->absasum2 = sstate->absasum2+v*v; } } } else { /* * Sparse QP problem - a bit tricky. Depending on format of the * input we use different strategies for copying matrix: * * SKS matrices are copied to SKS format * * anything else is copied to CRS format */ ae_assert(akind==1, "QQPOptimize: unexpected AKind (internal error)", _state); sparsecopytosksbuf(sparseac, &sstate->sparsea, _state); if( sparseupper ) { sparsetransposesks(&sstate->sparsea, _state); } sstate->sparseupper = ae_false; sstate->absamax = (double)(0); sstate->absasum = (double)(0); sstate->absasum2 = (double)(0); for(i=0; i<=n-1; i++) { k = sstate->sparsea.ridx.ptr.p_int[i]; for(j=i-sstate->sparsea.didx.ptr.p_int[i]; j<=i; j++) { v = sc->ptr.p_double[i]*sstate->sparsea.vals.ptr.p_double[k]*sc->ptr.p_double[j]; sstate->sparsea.vals.ptr.p_double[k] = v; if( i==j ) { /* * Diagonal terms are counted only once */ sstate->absamax = ae_maxreal(sstate->absamax, v, _state); sstate->absasum = sstate->absasum+v; sstate->absasum2 = sstate->absasum2+v*v; } else { /* * Offdiagonal terms are counted twice */ sstate->absamax = ae_maxreal(sstate->absamax, v, _state); sstate->absasum = sstate->absasum+2*v; sstate->absasum2 = sstate->absasum2+2*v*v; } k = k+1; } } } /* * Load box constraints into State structure. * * We apply transformation to variables: y=(x-x_origin)/s, * each of the constraints is appropriately shifted/scaled. */ for(i=0; i<=nmain-1; i++) { sstate->havebndl.ptr.p_bool[i] = ae_isfinite(bndlc->ptr.p_double[i], _state); if( sstate->havebndl.ptr.p_bool[i] ) { sstate->bndl.ptr.p_double[i] = (bndlc->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; } else { ae_assert(ae_isneginf(bndlc->ptr.p_double[i], _state), "QQPOptimize: incorrect lower bound", _state); sstate->bndl.ptr.p_double[i] = _state->v_neginf; } sstate->havebndu.ptr.p_bool[i] = ae_isfinite(bnduc->ptr.p_double[i], _state); if( sstate->havebndu.ptr.p_bool[i] ) { sstate->bndu.ptr.p_double[i] = (bnduc->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; } else { ae_assert(ae_isposinf(bnduc->ptr.p_double[i], _state), "QQPOptimize: incorrect upper bound", _state); sstate->bndu.ptr.p_double[i] = _state->v_posinf; } } for(i=nmain; i<=n-1; i++) { sstate->havebndl.ptr.p_bool[i] = ae_true; sstate->bndl.ptr.p_double[i] = 0.0; sstate->havebndu.ptr.p_bool[i] = ae_false; sstate->bndu.ptr.p_double[i] = _state->v_posinf; } /* * Shift/scale linear constraints with transformation y=(x-x_origin)/s: * * constraint "c[i]'*x = b[i]" becomes "(s[i]*c[i])'*x = b[i]-c[i]'*x_origin". * * after constraint is loaded into SState.CLEIC, it is additionally normalized */ rmatrixsetlengthatleast(&sstate->cleic, nec+nic, n+1, _state); for(i=0; i<=nec+nic-1; i++) { v = (double)(0); vv = (double)(0); for(j=0; j<=nmain-1; j++) { sstate->cleic.ptr.pp_double[i][j] = cleicc->ptr.pp_double[i][j]*sc->ptr.p_double[j]; vv = vv+ae_sqr(sstate->cleic.ptr.pp_double[i][j], _state); v = v+cleicc->ptr.pp_double[i][j]*xoriginc->ptr.p_double[j]; } vv = ae_sqrt(vv, _state); for(j=nmain; j<=n-1; j++) { sstate->cleic.ptr.pp_double[i][j] = 0.0; } sstate->cleic.ptr.pp_double[i][n] = cleicc->ptr.pp_double[i][nmain]-v; if( i>=nec ) { sstate->cleic.ptr.pp_double[i][nmain+i-nec] = 1.0; } if( ae_fp_greater(vv,(double)(0)) ) { for(j=0; j<=n; j++) { sstate->cleic.ptr.pp_double[i][j] = sstate->cleic.ptr.pp_double[i][j]/vv; } } } /* * Process initial point: * * first NMain components are equal to XS-XOriginC * * last NIC components are deduced from linear constraints * * make sure that boundary constraints are preserved by transformation */ for(i=0; i<=nmain-1; i++) { sstate->xs.ptr.p_double[i] = (xs->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(sstate->xs.ptr.p_double[i],sstate->bndl.ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->bndl.ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(sstate->xs.ptr.p_double[i],sstate->bndu.ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->bndu.ptr.p_double[i]; } if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(xs->ptr.p_double[i],bndlc->ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->bndl.ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(xs->ptr.p_double[i],bnduc->ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->bndu.ptr.p_double[i]; } } for(i=0; i<=nic-1; i++) { v = ae_v_dotproduct(&sstate->xs.ptr.p_double[0], 1, &sstate->cleic.ptr.pp_double[nec+i][0], 1, ae_v_len(0,nmain-1)); sstate->xs.ptr.p_double[nmain+i] = ae_maxreal(sstate->cleic.ptr.pp_double[nec+i][n]-v, 0.0, _state); } /* * Prepare "active set" structure */ sassetbc(&sstate->sas, &sstate->bndl, &sstate->bndu, _state); sassetlcx(&sstate->sas, &sstate->cleic, 0, 0, _state); if( !sasstartoptimization(&sstate->sas, &sstate->xs, _state) ) { *terminationtype = -3; return; } /* * Select sparse direct solver */ if( akind==1 ) { sparsesolver = settings->sparsesolver; if( sparsesolver==0 ) { sparsesolver = 1; } if( sparseissks(&sstate->sparsea, _state) ) { sparsesolver = 2; } sparsesolver = 2; ae_assert(sparsesolver==1||sparsesolver==2, "QQPOptimize: incorrect SparseSolver", _state); } else { sparsesolver = 0; } /* * Main loop. * * Following variables are used: * * GC stores current gradient (unconstrained) * * CGC stores current gradient (constrained) * * DC stores current search direction * * CGP stores constrained gradient at previous point * (zero on initial entry) * * DP stores previous search direction * (zero on initial entry) */ cgmax = settings->cgminits; sstate->repinneriterationscount = 0; sstate->repouteriterationscount = 0; for(;;) { if( settings->maxouterits>0&&sstate->repouteriterationscount>=settings->maxouterits ) { *terminationtype = 5; break; } if( sstate->repouteriterationscount>0 ) { /* * Check EpsF- and EpsX-based stopping criteria. * Because problem was already scaled, we do not scale step before checking its length. * NOTE: these checks are performed only after at least one outer iteration was made. */ if( ae_fp_greater(settings->epsf,(double)(0)) ) { /* * NOTE 1: here we rely on the fact that ProjectedTargetFunction() ignore D when Stp=0 * NOTE 2: code below handles situation when update increases function value instead * of decreasing it. */ fprev = qqpsolver_projectedtargetfunction(sstate, &sstate->xp, &sstate->dc, 0.0, &sstate->tmp0, _state); fcur = qqpsolver_projectedtargetfunction(sstate, &sstate->sas.xc, &sstate->dc, 0.0, &sstate->tmp0, _state); if( ae_fp_less_eq(fprev-fcur,settings->epsf*ae_maxreal(ae_fabs(fprev, _state), ae_maxreal(ae_fabs(fcur, _state), 1.0, _state), _state)) ) { *terminationtype = 1; break; } } if( ae_fp_greater(settings->epsx,(double)(0)) ) { v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(sstate->xp.ptr.p_double[i]-sstate->sas.xc.ptr.p_double[i], _state); } if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsx) ) { *terminationtype = 2; break; } } } inc(&sstate->repouteriterationscount, _state); ae_v_move(&sstate->xp.ptr.p_double[0], 1, &sstate->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( !settings->cgphase ) { cgmax = 0; } for(i=0; i<=n-1; i++) { sstate->cgp.ptr.p_double[i] = 0.0; sstate->dp.ptr.p_double[i] = 0.0; } for(cgcnt=0; cgcnt<=cgmax-1; cgcnt++) { /* * Calculate unconstrained gradient GC for "extended" QP problem * Determine active set, current constrained gradient CGC. * Check gradient-based stopping condition. * * NOTE: because problem was scaled, we do not have to apply scaling * to gradient before checking stopping condition. */ qqpsolver_targetgradient(sstate, &sstate->sas.xc, &sstate->gc, _state); sasreactivateconstraints(&sstate->sas, &sstate->gc, _state); ae_v_move(&sstate->cgc.ptr.p_double[0], 1, &sstate->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); sasconstraineddirection(&sstate->sas, &sstate->cgc, _state); v = ae_v_dotproduct(&sstate->cgc.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsg) ) { *terminationtype = 4; break; } /* * Prepare search direction DC and explore it. * * We try to use CGP/DP to prepare conjugate gradient step, * but we resort to steepest descent step (Beta=0) in case * we are at I-th boundary, but DP[I]<>0. * * Such approach allows us to ALWAYS have feasible DC, with * guaranteed compatibility with both feasible area and current * active set. * * Automatic CG reset performed every time DP is incompatible * with current active set and/or feasible area. We also * perform reset every QuickQPRestartCG iterations. */ ae_v_moveneg(&sstate->dc.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = 0.0; vv = 0.0; b = ae_false; for(i=0; i<=n-1; i++) { v = v+sstate->cgc.ptr.p_double[i]*sstate->cgc.ptr.p_double[i]; vv = vv+sstate->cgp.ptr.p_double[i]*sstate->cgp.ptr.p_double[i]; b = b||((sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]))&&ae_fp_neq(sstate->dp.ptr.p_double[i],(double)(0))); b = b||((sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]))&&ae_fp_neq(sstate->dp.ptr.p_double[i],(double)(0))); } b = b||ae_fp_eq(vv,(double)(0)); b = b||cgcnt%qqpsolver_quickqprestartcg==0; if( !b ) { beta = v/vv; } else { beta = 0.0; } ae_v_addd(&sstate->dc.ptr.p_double[0], 1, &sstate->dp.ptr.p_double[0], 1, ae_v_len(0,n-1), beta); sasconstraineddirection(&sstate->sas, &sstate->dc, _state); sasexploredirection(&sstate->sas, &sstate->dc, &stpmax, &cidx, &cval, _state); /* * Build quadratic model of F along descent direction: * * F(xc+alpha*D) = D2*alpha^2 + D1*alpha * * Terminate algorithm if needed. * * NOTE: we do not maintain constant term D0 */ qqpsolver_quadraticmodel(sstate, &sstate->sas.xc, &sstate->dc, &sstate->gc, &d1, &d1est, &d2, &d2est, _state); if( ae_fp_eq(d1,(double)(0))&&ae_fp_eq(d2,(double)(0)) ) { /* * D1 and D2 are exactly zero, success. * After this if-then we assume that D is non-zero. */ *terminationtype = 4; break; } if( d1est>=0 ) { /* * Numerical noise is too large, it means that we are close * to minimum - and that further improvement is impossible. * * After this if-then we assume that D1 is definitely negative * (even under presence of numerical errors). */ *terminationtype = 7; break; } if( d2est<=0&&cidx<0 ) { /* * Function is unbounded from below: * * D1<0 (verified by previous block) * * D2Est<=0, which means that either D2<0 - or it can not * be reliably distinguished from zero. * * step is unconstrained * * If these conditions are true, we abnormally terminate QP * algorithm with return code -4 */ *terminationtype = -4; break; } /* * Perform step along DC. * * In this block of code we maintain two step length: * * RestStp - restricted step, maximum step length along DC which does * not violate constraints * * FullStp - step length along DC which minimizes quadratic function * without taking constraints into account. If problem is * unbounded from below without constraints, FullStp is * forced to be RestStp. * * So, if function is convex (D2>0): * * FullStp = -D1/(2*D2) * * RestStp = restricted FullStp * * 0<=RestStp<=FullStp * * If function is non-convex, but bounded from below under constraints: * * RestStp = step length subject to constraints * * FullStp = RestStp * * After RestStp and FullStp are initialized, we generate several trial * steps which are different multiples of RestStp and FullStp. */ if( d2est>0 ) { ae_assert(ae_fp_less(d1,(double)(0)), "QQPOptimize: internal error", _state); fullstp = -d1/(2*d2); needact = ae_fp_greater_eq(fullstp,stpmax); if( needact ) { ae_assert(sstate->stpbuf.cnt>=3, "QQPOptimize: StpBuf overflow", _state); reststp = stpmax; stp = reststp; sstate->stpbuf.ptr.p_double[0] = reststp*4; sstate->stpbuf.ptr.p_double[1] = fullstp; sstate->stpbuf.ptr.p_double[2] = fullstp/4; stpcnt = 3; } else { reststp = fullstp; stp = fullstp; stpcnt = 0; } } else { ae_assert(cidx>=0, "QQPOptimize: internal error", _state); ae_assert(sstate->stpbuf.cnt>=2, "QQPOptimize: StpBuf overflow", _state); reststp = stpmax; fullstp = stpmax; stp = reststp; needact = ae_true; sstate->stpbuf.ptr.p_double[0] = 4*reststp; stpcnt = 1; } qqpsolver_findbeststepandmove(sstate, &sstate->sas, &sstate->dc, stp, needact, cidx, cval, &sstate->stpbuf, stpcnt, &sstate->activated, &sstate->tmp0, _state); /* * Update CG information. */ ae_v_move(&sstate->dp.ptr.p_double[0], 1, &sstate->dc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&sstate->cgp.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Update iterations counter */ sstate->repinneriterationscount = sstate->repinneriterationscount+1; } if( *terminationtype!=0 ) { break; } cgmax = settings->cgmaxits; /* * Generate YIdx - reordering of variables for constrained Newton phase. * Free variables come first, fixed are last ones. */ newtcnt = 0; for(;;) { /* * Skip iteration if constrained Newton is turned off. */ if( !settings->cnphase ) { break; } /* * At the first iteration - build Cholesky decomposition of Hessian. * At subsequent iterations - refine Hessian by adding new constraints. * * Loop is terminated in following cases: * * Hessian is not positive definite subject to current constraints * (termination during initial decomposition) * * there were no new constraints being activated * (termination during update) * * all constraints were activated during last step * (termination during update) * * CNMaxUpdates were performed on matrix * (termination during update) */ if( newtcnt==0 ) { /* * Perform initial Newton step. If Cholesky decomposition fails, * increase number of CG iterations to CGMaxIts - it should help * us to find set of constraints which will make matrix positive * definite. */ b = qqpsolver_cnewtonbuild(sstate, sparsesolver, &sstate->repncholesky, _state); if( b ) { cgmax = settings->cgminits; } } else { b = qqpsolver_cnewtonupdate(sstate, settings, &sstate->repncupdates, _state); } if( !b ) { break; } inc(&newtcnt, _state); /* * Calculate gradient GC. */ qqpsolver_targetgradient(sstate, &sstate->sas.xc, &sstate->gc, _state); /* * Bound-constrained Newton step */ for(i=0; i<=n-1; i++) { sstate->dc.ptr.p_double[i] = sstate->gc.ptr.p_double[i]; } if( !qqpsolver_cnewtonstep(sstate, settings, &sstate->dc, _state) ) { break; } qqpsolver_quadraticmodel(sstate, &sstate->sas.xc, &sstate->dc, &sstate->gc, &d1, &d1est, &d2, &d2est, _state); if( d1est>=0||d2est<=0 ) { break; } ae_assert(ae_fp_less(d1,(double)(0)), "QQPOptimize: internal error", _state); fullstp = -d1/(2*d2); sasexploredirection(&sstate->sas, &sstate->dc, &stpmax, &cidx, &cval, _state); needact = ae_fp_greater_eq(fullstp,stpmax); if( needact ) { ae_assert(sstate->stpbuf.cnt>=3, "QQPOptimize: StpBuf overflow", _state); reststp = stpmax; stp = reststp; sstate->stpbuf.ptr.p_double[0] = reststp*4; sstate->stpbuf.ptr.p_double[1] = fullstp; sstate->stpbuf.ptr.p_double[2] = fullstp/4; stpcnt = 3; } else { reststp = fullstp; stp = fullstp; stpcnt = 0; } qqpsolver_findbeststepandmove(sstate, &sstate->sas, &sstate->dc, stp, needact, cidx, cval, &sstate->stpbuf, stpcnt, &sstate->activated, &sstate->tmp0, _state); } if( *terminationtype!=0 ) { break; } } /* * Stop optimization and unpack results. * * Add XOriginC to XS and make sure that boundary constraints are * both (a) satisfied, (b) preserved. Former means that "shifted" * point is feasible, while latter means that point which was exactly * at the boundary before shift will be exactly at the boundary * after shift. */ sasstopoptimization(&sstate->sas, _state); for(i=0; i<=nmain-1; i++) { xs->ptr.p_double[i] = sc->ptr.p_double[i]*sstate->sas.xc.ptr.p_double[i]+xoriginc->ptr.p_double[i]; if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(xs->ptr.p_double[i],bndlc->ptr.p_double[i]) ) { xs->ptr.p_double[i] = bndlc->ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(xs->ptr.p_double[i],bnduc->ptr.p_double[i]) ) { xs->ptr.p_double[i] = bnduc->ptr.p_double[i]; } if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]) ) { xs->ptr.p_double[i] = bndlc->ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]) ) { xs->ptr.p_double[i] = bnduc->ptr.p_double[i]; } } } /************************************************************************* Target function at point PROJ(X+Stp*D), where PROJ(.) is a projection into feasible set. NOTE: if Stp=0, D is not referenced at all. Thus, there is no need to fill it by some meaningful values for Stp=0. This subroutine uses temporary buffer Tmp, which is automatically resized if needed. -- ALGLIB -- Copyright 21.12.2013 by Bochkanov Sergey *************************************************************************/ static double qqpsolver_projectedtargetfunction(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* d, double stp, /* Real */ ae_vector* tmp0, ae_state *_state) { ae_int_t nec; ae_int_t nic; ae_int_t n; ae_int_t nmain; ae_int_t i; ae_int_t j; double v; double vv; double result; n = sstate->n; nmain = sstate->nmain; nec = sstate->nec; nic = sstate->nic; rvectorsetlengthatleast(tmp0, n, _state); /* * Calculate projected point */ for(i=0; i<=n-1; i++) { if( ae_fp_neq(stp,(double)(0)) ) { v = x->ptr.p_double[i]+stp*d->ptr.p_double[i]; } else { v = x->ptr.p_double[i]; } if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) { v = sstate->bndl.ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) { v = sstate->bndu.ptr.p_double[i]; } tmp0->ptr.p_double[i] = v; } /* * Function value at the Tmp0: * * f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) */ result = 0.0; for(i=0; i<=nmain-1; i++) { result = result+sstate->b.ptr.p_double[i]*tmp0->ptr.p_double[i]; } if( sstate->akind==0 ) { /* * Dense matrix A */ for(i=0; i<=nmain-1; i++) { v = tmp0->ptr.p_double[i]; result = result+0.5*v*v*sstate->densea.ptr.pp_double[i][i]; vv = 0.0; for(j=i+1; j<=nmain-1; j++) { vv = vv+sstate->densea.ptr.pp_double[i][j]*tmp0->ptr.p_double[j]; } result = result+v*vv; } } else { /* * sparse matrix A */ ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in ProjectedTargetFunction", _state); result = result+0.5*sparsevsmv(&sstate->sparsea, sstate->sparseupper, tmp0, _state); } for(i=0; i<=nec+nic-1; i++) { v = ae_v_dotproduct(&sstate->cleic.ptr.pp_double[i][0], 1, &tmp0->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = result+0.5*qqpsolver_penaltyfactor*ae_sqr(v-sstate->cleic.ptr.pp_double[i][n], _state); } return result; } /************************************************************************* Gradient of "extended" (N>=NMain variables, original + slack ones) target function: f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) which is equal to grad = A*x + b + penaltyfactor*C'*(C*x-b) Here: * x is array[N] (that's why problem is called extended - N>=NMain) * A is array[NMain,NMain] * b is array[NMain] * C is array[NEC+NIC,N] INPUT PARAMETERS: SState - structure which stores function terms (not modified) X - location G - possibly preallocated buffer OUTPUT PARAMETERS: G - array[N], gradient -- ALGLIB -- Copyright 21.12.2013 by Bochkanov Sergey *************************************************************************/ static void qqpsolver_targetgradient(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t nec; ae_int_t nic; ae_int_t n; ae_int_t nmain; ae_int_t i; double v; n = sstate->n; nmain = sstate->nmain; nec = sstate->nec; nic = sstate->nic; rvectorsetlengthatleast(g, n, _state); if( sstate->akind==0 ) { /* * Dense matrix A */ rmatrixmv(nmain, nmain, &sstate->densea, 0, 0, 0, x, 0, g, 0, _state); } else { /* * Sparse matrix A */ ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in TargetGradient", _state); sparsesmv(&sstate->sparsea, sstate->sparseupper, x, g, _state); } ae_v_add(&g->ptr.p_double[0], 1, &sstate->b.ptr.p_double[0], 1, ae_v_len(0,nmain-1)); for(i=nmain; i<=n-1; i++) { g->ptr.p_double[i] = 0.0; } for(i=0; i<=nec+nic-1; i++) { v = ae_v_dotproduct(&sstate->cleic.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-sstate->cleic.ptr.pp_double[i][n]; v = v*qqpsolver_penaltyfactor; ae_v_addd(&g->ptr.p_double[0], 1, &sstate->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } } /************************************************************************* First and second derivatives of the "extended" target function along specified direction. Target function is called "extended" because of additional slack variables and has form: f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) with gradient grad = A*x + b + penaltyfactor*C'*(C*x-b) Quadratic model has form F(x0+alpha*D) = D2*alpha^2 + D1*alpha INPUT PARAMETERS: SState - structure which is used to obtain quadratic term of the model X - current point, array[N] D - direction across which derivatives are calculated, array[N] G - gradient at current point (pre-calculated by caller), array[N] OUTPUT PARAMETERS: D1 - linear coefficient D1Est - estimate of D1 sign, accounting for possible numerical errors: * >0 means "almost surely positive" * <0 means "almost surely negative" * =0 means "pessimistic estimate of numerical errors in D1 is larger than magnitude of D1 itself; it is impossible to reliably distinguish D1 from zero". D2 - quadratic coefficient D2Est - estimate of D2 sign, accounting for possible numerical errors: * >0 means "almost surely positive" * <0 means "almost surely negative" * =0 means "pessimistic estimate of numerical errors in D2 is larger than magnitude of D2 itself; it is impossible to reliably distinguish D2 from zero". -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ static void qqpsolver_quadraticmodel(qqpbuffers* sstate, /* Real */ ae_vector* x, /* Real */ ae_vector* d, /* Real */ ae_vector* g, double* d1, ae_int_t* d1est, double* d2, ae_int_t* d2est, ae_state *_state) { ae_int_t nec; ae_int_t nic; ae_int_t n; ae_int_t nmain; ae_int_t i; ae_int_t j; double v; double vv; double mx; double mb; double md; *d1 = 0; *d1est = 0; *d2 = 0; *d2est = 0; n = sstate->n; nmain = sstate->nmain; nec = sstate->nec; nic = sstate->nic; /* * Maximums */ mx = 0.0; md = 0.0; mb = 0.0; for(i=0; i<=n-1; i++) { mx = ae_maxreal(mx, ae_fabs(x->ptr.p_double[i], _state), _state); md = ae_maxreal(md, ae_fabs(d->ptr.p_double[i], _state), _state); } for(i=0; i<=nmain-1; i++) { mb = ae_maxreal(mb, ae_fabs(sstate->b.ptr.p_double[i], _state), _state); } /* * D2 */ if( sstate->akind==0 ) { /* * Dense matrix A */ *d2 = 0.0; for(i=0; i<=nmain-1; i++) { v = d->ptr.p_double[i]; vv = 0.0; *d2 = *d2+0.5*v*v*sstate->densea.ptr.pp_double[i][i]; for(j=i+1; j<=nmain-1; j++) { vv = vv+sstate->densea.ptr.pp_double[i][j]*d->ptr.p_double[j]; } *d2 = *d2+v*vv; } } else { /* * Sparse matrix A */ ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in TargetGradient", _state); *d2 = 0.5*sparsevsmv(&sstate->sparsea, sstate->sparseupper, d, _state); } for(i=0; i<=nec+nic-1; i++) { /* * NOTE: there is no "V:=V-CLEIC[I,N]" line, and it is not an error! * We estimate curvature information here, which is not dependent * on right part. */ v = ae_v_dotproduct(&sstate->cleic.ptr.pp_double[i][0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); *d2 = *d2+v*v*qqpsolver_penaltyfactor*0.5; } v = ae_v_dotproduct(&d->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,n-1)); *d1 = v; /* * Error estimates */ estimateparabolicmodel(sstate->absasum, sstate->absasum2, mx, mb, md, *d1, *d2, d1est, d2est, _state); } /************************************************************************* This function accepts quadratic model of the form f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) and list of possible steps along direction D. It chooses best step (one which achieves minimum value of the target function) and moves current point (given by SAS object) to the new location. Step is bounded subject to boundary constraints. Candidate steps are divided into two groups: * "default" step, which is always performed when no candidate steps LONGER THAN THE DEFAULT ONE is given. This candidate MUST reduce target function value; it is responsibility of caller to provide default candidate which reduces target function. * "additional candidates", which may be shorter or longer than the default step. Candidates which are shorter that the default step are ignored; candidates which are longer than the "default" step are tested. The idea is that we ALWAYS try "default" step, and it is responsibility of the caller to provide us with something which is worth trying. This step may activate some constraint - that's why we stopped at "default" step size. However, we may also try longer steps which may activate additional constraints and further reduce function value. INPUT PARAMETERS: SState - structure which stores model SAS - active set structure which stores current point in SAS.XC D - direction for step Stp - step length for "default" candidate NeedAct - whether default candidate activates some constraint; if NeedAct is True, constraint given by CIdc/CVal is GUARANTEED to be activated in the final point. CIdx - if NeedAct is True, stores index of the constraint to activate CVal - if NeedAct is True, stores constrained value; SAS.XC[CIdx] is forced to be equal to CVal. AddSteps- array[AddStepsCnt] of additional steps: * AddSteps[]<=Stp are ignored * AddSteps[]>Stp are tried Activated- possibly preallocated buffer; previously allocated memory will be reused. Tmp0 - possibly preallocated buffer; previously allocated memory will be reused. OUTPUT PARAMETERS: SAS - SAS.XC is set to new point; if there was a constraint specified by NeedAct/CIdx/CVal, it will be activated (other constraints may be activated too, but this one is guaranteed to be active in the final point). Activated- elements of this array are set to True, if I-th constraint as inactive at previous point, but become active in the new one. Situations when we deactivate xi>=0 and activate xi<=1 are considered as activation of previously inactive constraint -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ static void qqpsolver_findbeststepandmove(qqpbuffers* sstate, sactiveset* sas, /* Real */ ae_vector* d, double stp, ae_bool needact, ae_int_t cidx, double cval, /* Real */ ae_vector* addsteps, ae_int_t addstepscnt, /* Boolean */ ae_vector* activated, /* Real */ ae_vector* tmp0, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t k; double v; double stpbest; double fbest; double fcand; n = sstate->n; rvectorsetlengthatleast(tmp0, n, _state); bvectorsetlengthatleast(activated, n, _state); /* * Calculate initial step, store to Tmp0 * * NOTE: Tmp0 is guaranteed to be feasible w.r.t. boundary constraints */ for(i=0; i<=n-1; i++) { v = sas->xc.ptr.p_double[i]+stp*d->ptr.p_double[i]; if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) { v = sstate->bndl.ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) { v = sstate->bndu.ptr.p_double[i]; } tmp0->ptr.p_double[i] = v; } if( needact ) { tmp0->ptr.p_double[cidx] = cval; } /* * Try additional steps, if AddStepsCnt>0 */ if( addstepscnt>0 ) { /* * Find best step */ stpbest = stp; fbest = qqpsolver_projectedtargetfunction(sstate, &sas->xc, d, stpbest, tmp0, _state); for(k=0; k<=addstepscnt-1; k++) { if( ae_fp_greater(addsteps->ptr.p_double[k],stp) ) { fcand = qqpsolver_projectedtargetfunction(sstate, &sas->xc, d, addsteps->ptr.p_double[k], tmp0, _state); if( ae_fp_less(fcand,fbest) ) { fbest = fcand; stpbest = addsteps->ptr.p_double[k]; } } } /* * Prepare best step * * NOTE: because only AddSteps[]>Stp were checked, * this step will activate constraint CIdx. */ for(i=0; i<=n-1; i++) { v = sas->xc.ptr.p_double[i]+stpbest*d->ptr.p_double[i]; if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) { v = sstate->bndl.ptr.p_double[i]; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) { v = sstate->bndu.ptr.p_double[i]; } tmp0->ptr.p_double[i] = v; } if( needact ) { tmp0->ptr.p_double[cidx] = cval; } } /* * Fill Activated array by information about activated constraints. * Perform step */ for(i=0; i<=n-1; i++) { activated->ptr.p_bool[i] = ae_false; v = tmp0->ptr.p_double[i]; if( ae_fp_eq(v,sas->xc.ptr.p_double[i]) ) { continue; } if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(v,sstate->bndl.ptr.p_double[i]) ) { activated->ptr.p_bool[i] = ae_true; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(v,sstate->bndu.ptr.p_double[i]) ) { activated->ptr.p_bool[i] = ae_true; } } sasmoveto(sas, tmp0, needact, cidx, cval, _state); } /************************************************************************* This function prepares data for constrained Newton step for penalized quadratic model of the form f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) where A can be dense or sparse, and model is considered subject to equality constraints specified by SState.SAS.XC object. Constraint is considered active if XC[i] is exactly BndL[i] or BndU[i], i.e. we ignore internal list of constraints monitored by SAS object. Our own set of constraints includes all constraints stored by SAS, but also may include some constraints which are inactive in SAS. "Preparation" means that Cholesky decomposition of the effective system matrix is performed, and we can perform constrained Newton step. This function works as black box. It uses fields of SState which are marked as "Variables for constrained Newton phase", and only this function and its friends know about these variables. Everyone else should use: * CNewtonBuild() to prepare initial Cholesky decomposition for step * CNewtonStep() to perform constrained Newton step * CNewtonUpdate() to update Cholesky matrix after point was moved and constraints were updated. In some cases it is possible to efficiently re-calculate Cholesky decomposition if you know which constraints were activated. If efficient re-calculation is impossible, this function returns False. INPUT PARAMETERS: SState - structure which stores model and temporaries for CN phase; in particular, SAS.XC stores current point. SparseSolver-which sparse solver to use for sparse model; ignored for dense QP. Can be: * 2 - SKS-based Cholesky NCholesky- counter which is incremented after Cholesky (successful or failed one) OUTPUT PARAMETERS: NCholesky- possibly updated counter RESULT: True, if Cholesky decomposition was successfully performed. False, if a) matrix was semi-definite or indefinite, or b) particular combination of matrix type (sparse) and constraints (general linear) is not supported. NOTE: this function may routinely return False, for indefinite matrices or for sparse problems with general linear constraints. You should be able to handle such situations. -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ static ae_bool qqpsolver_cnewtonbuild(qqpbuffers* sstate, ae_int_t sparsesolver, ae_int_t* ncholesky, ae_state *_state) { ae_int_t nec; ae_int_t nic; ae_int_t n; ae_int_t nmain; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_bool b; ae_int_t ridx0; ae_int_t ridx1; ae_int_t nfree; ae_bool result; result = ae_false; /* * Fetch often used fields */ n = sstate->n; nmain = sstate->nmain; nec = sstate->nec; nic = sstate->nic; /* * Check problem properties. * Sparse problems with general linear constraints are not supported yet. */ if( sstate->akind==1&&nec+nic>0 ) { return result; } /* * 1. Set CNModelAge to zero * 2. Generate YIdx - reordering of variables such that free variables * come first and are ordered by ascending, fixed are last ones and * have no particular ordering. * * This step is same for dense and sparse problems. */ sstate->cnmodelage = 0; ivectorsetlengthatleast(&sstate->yidx, n, _state); ridx0 = 0; ridx1 = n-1; for(i=0; i<=n-1; i++) { sstate->yidx.ptr.p_int[i] = -1; } for(i=0; i<=n-1; i++) { ae_assert(!sstate->havebndl.ptr.p_bool[i]||ae_fp_greater_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]), "CNewtonBuild: internal error", _state); ae_assert(!sstate->havebndu.ptr.p_bool[i]||ae_fp_less_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]), "CNewtonBuild: internal error", _state); b = ae_false; b = b||(sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i])); b = b||(sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i])); if( b ) { sstate->yidx.ptr.p_int[ridx1] = i; ridx1 = ridx1-1; } else { sstate->yidx.ptr.p_int[ridx0] = i; ridx0 = ridx0+1; } } ae_assert(ridx0==ridx1+1, "CNewtonBuild: internal error", _state); nfree = ridx0; sstate->nfree = nfree; if( nfree==0 ) { return result; } /* * Constrained Newton matrix: dense version */ if( sstate->akind==0 ) { rmatrixsetlengthatleast(&sstate->densez, n, n, _state); rvectorsetlengthatleast(&sstate->tmpcn, n, _state); if( nec+nic>0 ) { /* * Initialize Z with C'*C, add A */ rmatrixsyrk(n, nec+nic, qqpsolver_penaltyfactor, &sstate->cleic, 0, 0, 2, 0.0, &sstate->densez, 0, 0, ae_true, _state); for(i=0; i<=nmain-1; i++) { for(j=i; j<=nmain-1; j++) { sstate->densez.ptr.pp_double[i][j] = sstate->densez.ptr.pp_double[i][j]+sstate->densea.ptr.pp_double[i][j]; } } } else { /* * No linear constraints, just set Z to A */ ae_assert(n==nmain, "CNewtonBuild: integrity check failed", _state); for(i=0; i<=nmain-1; i++) { for(j=i; j<=nmain-1; j++) { sstate->densez.ptr.pp_double[i][j] = sstate->densea.ptr.pp_double[i][j]; } } } for(i=1; i<=nfree-1; i++) { ae_assert(sstate->yidx.ptr.p_int[i]>sstate->yidx.ptr.p_int[i-1], "CNewtonBuild: integrity check failed", _state); } for(i=0; i<=nfree-1; i++) { k = sstate->yidx.ptr.p_int[i]; for(j=i; j<=nfree-1; j++) { sstate->densez.ptr.pp_double[i][j] = sstate->densez.ptr.pp_double[k][sstate->yidx.ptr.p_int[j]]; } } rvectorsetlengthatleast(&sstate->regdiag, n, _state); for(i=0; i<=nfree-1; i++) { v = 0.0; for(j=0; j<=i-1; j++) { v = v+ae_fabs(sstate->densez.ptr.pp_double[j][i], _state); } for(j=i; j<=nfree-1; j++) { v = v+ae_fabs(sstate->densez.ptr.pp_double[i][j], _state); } if( ae_fp_eq(v,(double)(0)) ) { v = 1.0; } sstate->regdiag.ptr.p_double[i] = qqpsolver_regz*v; } for(i=0; i<=nfree-1; i++) { sstate->densez.ptr.pp_double[i][i] = sstate->densez.ptr.pp_double[i][i]+sstate->regdiag.ptr.p_double[i]; } inc(ncholesky, _state); if( !spdmatrixcholeskyrec(&sstate->densez, 0, nfree, ae_true, &sstate->tmpcn, _state) ) { return result; } for(i=nfree-1; i>=0; i--) { ae_v_move(&sstate->tmpcn.ptr.p_double[i], 1, &sstate->densez.ptr.pp_double[i][i], 1, ae_v_len(i,nfree-1)); k = sstate->yidx.ptr.p_int[i]; for(j=k; j<=n-1; j++) { sstate->densez.ptr.pp_double[k][j] = (double)(0); } for(j=i; j<=nfree-1; j++) { sstate->densez.ptr.pp_double[k][sstate->yidx.ptr.p_int[j]] = sstate->tmpcn.ptr.p_double[j]; } } for(i=nfree; i<=n-1; i++) { k = sstate->yidx.ptr.p_int[i]; sstate->densez.ptr.pp_double[k][k] = 1.0; for(j=k+1; j<=n-1; j++) { sstate->densez.ptr.pp_double[k][j] = (double)(0); } } result = ae_true; return result; } /* * Constrained Newton matrix: sparse version */ if( sstate->akind==1 ) { ae_assert(nec+nic==0, "CNewtonBuild: internal error", _state); ae_assert(sparsesolver==2, "CNewtonBuild: internal error", _state); /* * Copy sparse A to Z and fill rows/columns corresponding to active * constraints by zeros. Diagonal elements corresponding to active * constraints are filled by unit values. */ sparsecopytosksbuf(&sstate->sparsea, &sstate->sparsecca, _state); rvectorsetlengthatleast(&sstate->tmpcn, n, _state); for(i=0; i<=n-1; i++) { sstate->tmpcn.ptr.p_double[i] = (double)(0); } for(i=nfree; i<=n-1; i++) { sstate->tmpcn.ptr.p_double[sstate->yidx.ptr.p_int[i]] = (double)(1); } for(i=0; i<=n-1; i++) { k = sstate->sparsecca.ridx.ptr.p_int[i]; for(j=i-sstate->sparsecca.didx.ptr.p_int[i]; j<=i; j++) { if( ae_fp_neq(sstate->tmpcn.ptr.p_double[i],(double)(0))||ae_fp_neq(sstate->tmpcn.ptr.p_double[j],(double)(0)) ) { /* * I-th or J-th variable is in active set (constrained) */ if( i==j ) { sstate->sparsecca.vals.ptr.p_double[k] = 1.0; } else { sstate->sparsecca.vals.ptr.p_double[k] = 0.0; } } k = k+1; } } /* * Perform sparse Cholesky */ inc(ncholesky, _state); if( !sparsecholeskyskyline(&sstate->sparsecca, nmain, sstate->sparseupper, _state) ) { return result; } result = ae_true; return result; } /* * Unexpected :) */ ae_assert(ae_false, "CNewtonBuild: internal error", _state); return result; } /************************************************************************* This function updates equality-constrained Cholesky matrix after activation of the new equality constraints. Matrix being updated is quadratic term of the function below f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) where A can be dense or sparse. This function uses YIdx[] array (set by CNewtonBuild() function) to distinguish between active and inactive constraints. This function works as black box. It uses fields of SState which are marked as "Variables for constrained Newton phase", and only this function and its friends know about these variables. Everyone else should use: * CNewtonBuild() to prepare initial Cholesky decomposition for step * CNewtonStep() to perform constrained Newton step * CNewtonUpdate() to update Cholesky matrix after point was moved and constraints were updated. In some cases it is possible to efficiently re-calculate Cholesky decomposition if you know which constraints were activated. If efficient re-calculation is impossible, this function returns False. INPUT PARAMETERS: SState - structure which stores model and temporaries for CN phase; in particular, SAS.XC stores current point. Settings - QQPSettings object which was initialized by appropriate construction function. NCUpdates- counter which is incremented after each update (one update means one variable being fixed) OUTPUT PARAMETERS: NCUpdates- possibly updated counter RESULT: True, if Cholesky decomposition was successfully performed. False, if a) model age was too high, or b) particular combination of matrix type (sparse) and constraints (general linear) is not supported NOTE: this function may routinely return False. You should be able to handle such situations. -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ static ae_bool qqpsolver_cnewtonupdate(qqpbuffers* sstate, qqpsettings* settings, ae_int_t* ncupdates, ae_state *_state) { ae_int_t n; ae_int_t nfree; ae_int_t ntofix; ae_bool b; ae_int_t ridx0; ae_int_t ridx1; ae_int_t i; ae_int_t k; ae_bool result; result = ae_false; /* * Cholesky updates for sparse problems are not supported */ if( sstate->akind==1 ) { return result; } /* * Fetch often used fields */ n = sstate->n; nfree = sstate->nfree; /* * Determine variables to fix and move them to YIdx[NFree-NToFix:NFree-1] * Exit if CNModelAge increased too much. */ ivectorsetlengthatleast(&sstate->tmpcni, n, _state); ridx0 = 0; ridx1 = nfree-1; for(i=0; i<=nfree-1; i++) { sstate->tmpcni.ptr.p_int[i] = -1; } for(k=0; k<=nfree-1; k++) { i = sstate->yidx.ptr.p_int[k]; ae_assert(!sstate->havebndl.ptr.p_bool[i]||ae_fp_greater_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]), "CNewtonUpdate: internal error", _state); ae_assert(!sstate->havebndu.ptr.p_bool[i]||ae_fp_less_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]), "CNewtonUpdate: internal error", _state); b = ae_false; b = b||(sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i])); b = b||(sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i])); if( b ) { sstate->tmpcni.ptr.p_int[ridx1] = i; ridx1 = ridx1-1; } else { sstate->tmpcni.ptr.p_int[ridx0] = i; ridx0 = ridx0+1; } } ae_assert(ridx0==ridx1+1, "CNewtonUpdate: internal error", _state); ntofix = nfree-ridx0; if( ntofix==0||ntofix==nfree ) { return result; } if( sstate->cnmodelage+ntofix>settings->cnmaxupdates ) { return result; } for(i=0; i<=nfree-1; i++) { sstate->yidx.ptr.p_int[i] = sstate->tmpcni.ptr.p_int[i]; } /* * Constrained Newton matrix: dense version. */ if( sstate->akind==0 ) { /* * Update Cholesky matrix with SPDMatrixCholeskyUpdateFixBuf() */ bvectorsetlengthatleast(&sstate->tmpcnb, n, _state); for(i=0; i<=n-1; i++) { sstate->tmpcnb.ptr.p_bool[i] = ae_false; } for(i=nfree-ntofix; i<=nfree-1; i++) { sstate->tmpcnb.ptr.p_bool[sstate->yidx.ptr.p_int[i]] = ae_true; } spdmatrixcholeskyupdatefixbuf(&sstate->densez, n, ae_true, &sstate->tmpcnb, &sstate->tmpcn, _state); /* * Update information stored in State and exit */ sstate->nfree = nfree-ntofix; sstate->cnmodelage = sstate->cnmodelage+ntofix; *ncupdates = *ncupdates+ntofix; result = ae_true; return result; } /* * Unexpected :) */ ae_assert(ae_false, "CNewtonUpdate: internal error", _state); return result; } /************************************************************************* This function prepares equality-constrained Newton step using previously calculated constrained Cholesky matrix of the problem f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) where A can be dense or sparse. As input, this function accepts gradient at the current location. As output, it returns step vector (replaces gradient). This function works as black box. It uses fields of SState which are marked as "Variables for constrained Newton phase", and only this function and its friends know about these variables. Everyone else should use: * CNewtonBuild() to prepare initial Cholesky decomposition for step * CNewtonStep() to perform constrained Newton step * CNewtonUpdate() to update Cholesky matrix after point was moved and constraints were updated. In some cases it is possible to efficiently re-calculate Cholesky decomposition if you know which constraints were activated. If efficient re-calculation is impossible, this function returns False. INPUT PARAMETERS: SState - structure which stores model and temporaries for CN phase; in particular, SAS.XC stores current point. Settings - QQPSettings object which was initialized by appropriate construction function. GC - array[NMain+NSlack], gradient of the target function OUTPUT PARAMETERS: GC - array[NMain+NSlack], step vector (on success) RESULT: True, if step was successfully calculated. False, if step calculation failed: a) gradient was exactly zero, b) gradient norm was smaller than EpsG (stopping condition) c) all variables were equality-constrained NOTE: this function may routinely return False. You should be able to handle such situations. -- ALGLIB -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/ static ae_bool qqpsolver_cnewtonstep(qqpbuffers* sstate, qqpsettings* settings, /* Real */ ae_vector* gc, ae_state *_state) { ae_int_t i; ae_int_t n; ae_int_t nfree; double v; ae_bool result; result = ae_false; n = sstate->n; nfree = sstate->nfree; for(i=nfree; i<=n-1; i++) { gc->ptr.p_double[sstate->yidx.ptr.p_int[i]] = 0.0; } v = ae_v_dotproduct(&gc->ptr.p_double[0], 1, &gc->ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsg) ) { return result; } for(i=0; i<=n-1; i++) { gc->ptr.p_double[i] = -gc->ptr.p_double[i]; } if( sstate->akind==0 ) { /* * Dense Newton step. * Use straightforward Cholesky solver. */ fblscholeskysolve(&sstate->densez, 1.0, n, ae_true, gc, &sstate->tmpcn, _state); result = ae_true; return result; } if( sstate->akind==1 ) { /* * Sparse Newton step. * * We have T*T' = L*L' = U'*U (depending on specific triangle stored in SparseCCA). */ if( sstate->sparseupper ) { sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 1, gc, _state); sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 0, gc, _state); } else { sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 0, gc, _state); sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 1, gc, _state); } result = ae_true; return result; } ae_assert(ae_false, "CNewtonStep: internal error", _state); return result; } void _qqpsettings_init(void* _p, ae_state *_state) { qqpsettings *p = (qqpsettings*)_p; ae_touch_ptr((void*)p); } void _qqpsettings_init_copy(void* _dst, void* _src, ae_state *_state) { qqpsettings *dst = (qqpsettings*)_dst; qqpsettings *src = (qqpsettings*)_src; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxouterits = src->maxouterits; dst->cgphase = src->cgphase; dst->cnphase = src->cnphase; dst->cgminits = src->cgminits; dst->cgmaxits = src->cgmaxits; dst->cnmaxupdates = src->cnmaxupdates; dst->sparsesolver = src->sparsesolver; } void _qqpsettings_clear(void* _p) { qqpsettings *p = (qqpsettings*)_p; ae_touch_ptr((void*)p); } void _qqpsettings_destroy(void* _p) { qqpsettings *p = (qqpsettings*)_p; ae_touch_ptr((void*)p); } void _qqpbuffers_init(void* _p, ae_state *_state) { qqpbuffers *p = (qqpbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state); _sparsematrix_init(&p->sparsea, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->havebndl, 0, DT_BOOL, _state); ae_vector_init(&p->havebndu, 0, DT_BOOL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->xs, 0, DT_REAL, _state); ae_vector_init(&p->gc, 0, DT_REAL, _state); ae_vector_init(&p->xp, 0, DT_REAL, _state); ae_vector_init(&p->dc, 0, DT_REAL, _state); ae_vector_init(&p->dp, 0, DT_REAL, _state); ae_vector_init(&p->cgc, 0, DT_REAL, _state); ae_vector_init(&p->cgp, 0, DT_REAL, _state); _sactiveset_init(&p->sas, _state); ae_vector_init(&p->activated, 0, DT_BOOL, _state); ae_matrix_init(&p->densez, 0, 0, DT_REAL, _state); _sparsematrix_init(&p->sparsecca, _state); ae_vector_init(&p->yidx, 0, DT_INT, _state); ae_vector_init(&p->regdiag, 0, DT_REAL, _state); ae_vector_init(&p->regx0, 0, DT_REAL, _state); ae_vector_init(&p->tmpcn, 0, DT_REAL, _state); ae_vector_init(&p->tmpcni, 0, DT_INT, _state); ae_vector_init(&p->tmpcnb, 0, DT_BOOL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->stpbuf, 0, DT_REAL, _state); _sparsebuffers_init(&p->sbuf, _state); } void _qqpbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { qqpbuffers *dst = (qqpbuffers*)_dst; qqpbuffers *src = (qqpbuffers*)_src; dst->n = src->n; dst->nmain = src->nmain; dst->nslack = src->nslack; dst->nec = src->nec; dst->nic = src->nic; dst->akind = src->akind; ae_matrix_init_copy(&dst->densea, &src->densea, _state); _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state); dst->sparseupper = src->sparseupper; dst->absamax = src->absamax; dst->absasum = src->absasum; dst->absasum2 = src->absasum2; ae_vector_init_copy(&dst->b, &src->b, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state); ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state); ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); ae_vector_init_copy(&dst->xs, &src->xs, _state); ae_vector_init_copy(&dst->gc, &src->gc, _state); ae_vector_init_copy(&dst->xp, &src->xp, _state); ae_vector_init_copy(&dst->dc, &src->dc, _state); ae_vector_init_copy(&dst->dp, &src->dp, _state); ae_vector_init_copy(&dst->cgc, &src->cgc, _state); ae_vector_init_copy(&dst->cgp, &src->cgp, _state); _sactiveset_init_copy(&dst->sas, &src->sas, _state); ae_vector_init_copy(&dst->activated, &src->activated, _state); dst->nfree = src->nfree; dst->cnmodelage = src->cnmodelage; ae_matrix_init_copy(&dst->densez, &src->densez, _state); _sparsematrix_init_copy(&dst->sparsecca, &src->sparsecca, _state); ae_vector_init_copy(&dst->yidx, &src->yidx, _state); ae_vector_init_copy(&dst->regdiag, &src->regdiag, _state); ae_vector_init_copy(&dst->regx0, &src->regx0, _state); ae_vector_init_copy(&dst->tmpcn, &src->tmpcn, _state); ae_vector_init_copy(&dst->tmpcni, &src->tmpcni, _state); ae_vector_init_copy(&dst->tmpcnb, &src->tmpcnb, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->stpbuf, &src->stpbuf, _state); _sparsebuffers_init_copy(&dst->sbuf, &src->sbuf, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repncholesky = src->repncholesky; dst->repncupdates = src->repncupdates; } void _qqpbuffers_clear(void* _p) { qqpbuffers *p = (qqpbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->densea); _sparsematrix_clear(&p->sparsea); ae_vector_clear(&p->b); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->havebndl); ae_vector_clear(&p->havebndu); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->xs); ae_vector_clear(&p->gc); ae_vector_clear(&p->xp); ae_vector_clear(&p->dc); ae_vector_clear(&p->dp); ae_vector_clear(&p->cgc); ae_vector_clear(&p->cgp); _sactiveset_clear(&p->sas); ae_vector_clear(&p->activated); ae_matrix_clear(&p->densez); _sparsematrix_clear(&p->sparsecca); ae_vector_clear(&p->yidx); ae_vector_clear(&p->regdiag); ae_vector_clear(&p->regx0); ae_vector_clear(&p->tmpcn); ae_vector_clear(&p->tmpcni); ae_vector_clear(&p->tmpcnb); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->stpbuf); _sparsebuffers_clear(&p->sbuf); } void _qqpbuffers_destroy(void* _p) { qqpbuffers *p = (qqpbuffers*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->densea); _sparsematrix_destroy(&p->sparsea); ae_vector_destroy(&p->b); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->havebndl); ae_vector_destroy(&p->havebndu); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->xs); ae_vector_destroy(&p->gc); ae_vector_destroy(&p->xp); ae_vector_destroy(&p->dc); ae_vector_destroy(&p->dp); ae_vector_destroy(&p->cgc); ae_vector_destroy(&p->cgp); _sactiveset_destroy(&p->sas); ae_vector_destroy(&p->activated); ae_matrix_destroy(&p->densez); _sparsematrix_destroy(&p->sparsecca); ae_vector_destroy(&p->yidx); ae_vector_destroy(&p->regdiag); ae_vector_destroy(&p->regx0); ae_vector_destroy(&p->tmpcn); ae_vector_destroy(&p->tmpcni); ae_vector_destroy(&p->tmpcnb); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->stpbuf); _sparsebuffers_destroy(&p->sbuf); } /************************************************************************* This function initializes QPBLEICSettings structure with default settings. Newly created structure MUST be initialized by default settings - or by copy of the already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpbleicloaddefaults(ae_int_t nmain, qpbleicsettings* s, ae_state *_state) { s->epsg = 0.0; s->epsf = 0.0; s->epsx = 1.0E-6; s->maxits = 0; } /************************************************************************* This function initializes QPBLEICSettings structure with copy of another, already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpbleiccopysettings(qpbleicsettings* src, qpbleicsettings* dst, ae_state *_state) { dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; } /************************************************************************* This function runs QPBLEIC solver; it returns after optimization process was completed. Following QP problem is solved: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) subject to boundary constraints. INPUT PARAMETERS: AC - for dense problems (AKind=0), A-term of CQM object contains system matrix. Other terms are unspecified and should not be referenced. SparseAC - for sparse problems (AKind=1 AKind - sparse matrix format: * 0 for dense matrix * 1 for sparse matrix SparseUpper - which triangle of SparseAC stores matrix - upper or lower one (for dense matrices this parameter is not actual). AbsASum - SUM(|A[i,j]|) AbsASum2 - SUM(A[i,j]^2) BC - linear term, array[NC] BndLC - lower bound, array[NC] BndUC - upper bound, array[NC] SC - scale vector, array[NC]: * I-th element contains scale of I-th variable, * SC[I]>0 XOriginC - origin term, array[NC]. Can be zero. NC - number of variables in the original formulation (no slack variables). CLEICC - linear equality/inequality constraints. Present version of this function does NOT provide publicly available support for linear constraints. This feature will be introduced in the future versions of the function. NEC, NIC - number of equality/inequality constraints. MUST BE ZERO IN THE CURRENT VERSION!!! Settings - QPBLEICSettings object initialized by one of the initialization functions. SState - object which stores temporaries: * if uninitialized object was passed, FirstCall parameter MUST be set to True; object will be automatically initialized by the function, and FirstCall will be set to False. * if FirstCall=False, it is assumed that this parameter was already initialized by previous call to this function with same problem dimensions (variable count N). FirstCall - whether it is first call of this function for this specific instance of SState, with this number of variables N specified. XS - initial point, array[NC] OUTPUT PARAMETERS: XS - last point FirstCall - uncondtionally set to False TerminationType-termination type: * * * -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpbleicoptimize(convexquadraticmodel* a, sparsematrix* sparsea, ae_int_t akind, ae_bool sparseaupper, double absasum, double absasum2, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, /* Real */ ae_vector* s, /* Real */ ae_vector* xorigin, ae_int_t n, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, qpbleicsettings* settings, qpbleicbuffers* sstate, ae_bool* firstcall, /* Real */ ae_vector* xs, ae_int_t* terminationtype, ae_state *_state) { ae_int_t i; double d2; double d1; double d0; double v; double v0; double v1; double md; double mx; double mb; ae_int_t d1est; ae_int_t d2est; *terminationtype = 0; ae_assert(akind==0||akind==1, "QPBLEICOptimize: unexpected AKind", _state); sstate->repinneriterationscount = 0; sstate->repouteriterationscount = 0; *terminationtype = 0; /* * Prepare solver object, if needed */ if( *firstcall ) { minbleiccreate(n, xs, &sstate->solver, _state); *firstcall = ae_false; } /* * Prepare max(|B|) */ mb = 0.0; for(i=0; i<=n-1; i++) { mb = ae_maxreal(mb, ae_fabs(b->ptr.p_double[i], _state), _state); } /* * Temporaries */ ivectorsetlengthatleast(&sstate->tmpi, nec+nic, _state); rvectorsetlengthatleast(&sstate->tmp0, n, _state); rvectorsetlengthatleast(&sstate->tmp1, n, _state); for(i=0; i<=nec-1; i++) { sstate->tmpi.ptr.p_int[i] = 0; } for(i=0; i<=nic-1; i++) { sstate->tmpi.ptr.p_int[nec+i] = -1; } minbleicsetlc(&sstate->solver, cleic, &sstate->tmpi, nec+nic, _state); minbleicsetbc(&sstate->solver, bndl, bndu, _state); minbleicsetdrep(&sstate->solver, ae_true, _state); minbleicsetcond(&sstate->solver, ae_minrealnumber, 0.0, 0.0, settings->maxits, _state); minbleicsetscale(&sstate->solver, s, _state); minbleicsetprecscale(&sstate->solver, _state); minbleicrestartfrom(&sstate->solver, xs, _state); while(minbleiciteration(&sstate->solver, _state)) { /* * Line search started */ if( sstate->solver.lsstart ) { /* * Iteration counters: * * inner iterations count is increased on every line search * * outer iterations count is increased only at steepest descent line search */ inc(&sstate->repinneriterationscount, _state); if( sstate->solver.steepestdescentstep ) { inc(&sstate->repouteriterationscount, _state); } /* * Build quadratic model of F along descent direction: * * F(x+alpha*d) = D2*alpha^2 + D1*alpha + D0 * * Calculate estimates of linear and quadratic term * (term magnitude is compared with magnitude of numerical errors) */ d0 = sstate->solver.f; d1 = ae_v_dotproduct(&sstate->solver.d.ptr.p_double[0], 1, &sstate->solver.g.ptr.p_double[0], 1, ae_v_len(0,n-1)); d2 = (double)(0); if( akind==0 ) { d2 = cqmxtadx2(a, &sstate->solver.d, _state); } if( akind==1 ) { sparsesmv(sparsea, sparseaupper, &sstate->solver.d, &sstate->tmp0, _state); d2 = 0.0; for(i=0; i<=n-1; i++) { d2 = d2+sstate->solver.d.ptr.p_double[i]*sstate->tmp0.ptr.p_double[i]; } d2 = 0.5*d2; } mx = 0.0; md = 0.0; for(i=0; i<=n-1; i++) { mx = ae_maxreal(mx, ae_fabs(sstate->solver.x.ptr.p_double[i], _state), _state); md = ae_maxreal(md, ae_fabs(sstate->solver.d.ptr.p_double[i], _state), _state); } estimateparabolicmodel(absasum, absasum2, mx, mb, md, d1, d2, &d1est, &d2est, _state); /* * Tests for "normal" convergence. * * This line search may be started from steepest descent * stage (stage 2) or from L-BFGS stage (stage 3) of the * BLEIC algorithm. Depending on stage type, different * checks are performed. * * Say, L-BFGS stage is an equality-constrained refinement * stage of BLEIC. This stage refines current iterate * under "frozen" equality constraints. We can terminate * iterations at this stage only when we encounter * unconstrained direction of negative curvature. In all * other cases (say, when constrained gradient is zero) * we should not terminate algorithm because everything may * change after de-activating presently active constraints. * * Tests for convergence are performed only at "steepest descent" stage * of the BLEIC algorithm, and only when function is non-concave * (D2 is positive or approximately zero) along direction D. * * NOTE: we do not test iteration count (MaxIts) here, because * this stopping condition is tested by BLEIC itself. */ if( sstate->solver.steepestdescentstep&&d2est>=0 ) { if( d1est>=0 ) { /* * "Emergency" stopping condition: D is non-descent direction. * Sometimes it is possible because of numerical noise in the * target function. */ *terminationtype = 4; for(i=0; i<=n-1; i++) { xs->ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]; } break; } if( d2est>0 ) { /* * Stopping condition #4 - gradient norm is small: * * 1. rescale State.Solver.D and State.Solver.G according to * current scaling, store results to Tmp0 and Tmp1. * 2. Normalize Tmp0 (scaled direction vector). * 3. compute directional derivative (in scaled variables), * which is equal to DOTPRODUCT(Tmp0,Tmp1). */ v = (double)(0); for(i=0; i<=n-1; i++) { sstate->tmp0.ptr.p_double[i] = sstate->solver.d.ptr.p_double[i]/s->ptr.p_double[i]; sstate->tmp1.ptr.p_double[i] = sstate->solver.g.ptr.p_double[i]*s->ptr.p_double[i]; v = v+ae_sqr(sstate->tmp0.ptr.p_double[i], _state); } ae_assert(ae_fp_greater(v,(double)(0)), "QPBLEICOptimize: internal error (scaled direction is zero)", _state); v = 1/ae_sqrt(v, _state); ae_v_muld(&sstate->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1), v); v = ae_v_dotproduct(&sstate->tmp0.ptr.p_double[0], 1, &sstate->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_less_eq(ae_fabs(v, _state),settings->epsg) ) { *terminationtype = 4; for(i=0; i<=n-1; i++) { xs->ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]; } break; } /* * Stopping condition #1 - relative function improvement is small: * * 1. calculate steepest descent step: V = -D1/(2*D2) * 2. calculate function change: V1= D2*V^2 + D1*V * 3. stop if function change is small enough */ v = -d1/(2*d2); v1 = d2*v*v+d1*v; if( ae_fp_less_eq(ae_fabs(v1, _state),settings->epsf*ae_maxreal(d0, 1.0, _state)) ) { *terminationtype = 1; for(i=0; i<=n-1; i++) { xs->ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]; } break; } /* * Stopping condition #2 - scaled step is small: * * 1. calculate step multiplier V0 (step itself is D*V0) * 2. calculate scaled step length V * 3. stop if step is small enough */ v0 = -d1/(2*d2); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(v0*sstate->solver.d.ptr.p_double[i]/s->ptr.p_double[i], _state); } if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsx) ) { *terminationtype = 2; for(i=0; i<=n-1; i++) { xs->ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]; } break; } } } /* * Test for unconstrained direction of negative curvature */ if( (d2est<0||(d2est==0&&d1est<0))&&!sstate->solver.boundedstep ) { /* * Function is unbounded from below: * * function will decrease along D, i.e. either: * * D2<0 * * D2=0 and D1<0 * * step is unconstrained * * If these conditions are true, we abnormally terminate QP * algorithm with return code -4 (we can do so at any stage * of BLEIC - whether it is L-BFGS or steepest descent one). */ *terminationtype = -4; for(i=0; i<=n-1; i++) { xs->ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]; } break; } /* * Suggest new step (only if D1 is negative far away from zero, * D2 is positive far away from zero). */ if( d1est<0&&d2est>0 ) { sstate->solver.stp = safeminposrv(-d1, 2*d2, sstate->solver.curstpmax, _state); } } /* * Gradient evaluation */ if( sstate->solver.needfg ) { for(i=0; i<=n-1; i++) { sstate->tmp0.ptr.p_double[i] = sstate->solver.x.ptr.p_double[i]-xorigin->ptr.p_double[i]; } if( akind==0 ) { cqmadx(a, &sstate->tmp0, &sstate->tmp1, _state); } if( akind==1 ) { sparsesmv(sparsea, sparseaupper, &sstate->tmp0, &sstate->tmp1, _state); } v0 = ae_v_dotproduct(&sstate->tmp0.ptr.p_double[0], 1, &sstate->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); v1 = ae_v_dotproduct(&sstate->tmp0.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); sstate->solver.f = 0.5*v0+v1; ae_v_move(&sstate->solver.g.ptr.p_double[0], 1, &sstate->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&sstate->solver.g.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); } } if( *terminationtype==0 ) { /* * BLEIC optimizer was terminated by one of its inner stopping * conditions. Usually it is iteration counter (if such * stopping condition was specified by user). */ minbleicresultsbuf(&sstate->solver, xs, &sstate->solverrep, _state); *terminationtype = sstate->solverrep.terminationtype; } else { /* * BLEIC optimizer was terminated in "emergency" mode by QP * solver. * * NOTE: such termination is "emergency" only when viewed from * BLEIC's position. QP solver sees such termination as * routine one, triggered by QP's stopping criteria. */ minbleicemergencytermination(&sstate->solver, _state); } } void _qpbleicsettings_init(void* _p, ae_state *_state) { qpbleicsettings *p = (qpbleicsettings*)_p; ae_touch_ptr((void*)p); } void _qpbleicsettings_init_copy(void* _dst, void* _src, ae_state *_state) { qpbleicsettings *dst = (qpbleicsettings*)_dst; qpbleicsettings *src = (qpbleicsettings*)_src; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; } void _qpbleicsettings_clear(void* _p) { qpbleicsettings *p = (qpbleicsettings*)_p; ae_touch_ptr((void*)p); } void _qpbleicsettings_destroy(void* _p) { qpbleicsettings *p = (qpbleicsettings*)_p; ae_touch_ptr((void*)p); } void _qpbleicbuffers_init(void* _p, ae_state *_state) { qpbleicbuffers *p = (qpbleicbuffers*)_p; ae_touch_ptr((void*)p); _minbleicstate_init(&p->solver, _state); _minbleicreport_init(&p->solverrep, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmp1, 0, DT_REAL, _state); ae_vector_init(&p->tmpi, 0, DT_INT, _state); } void _qpbleicbuffers_init_copy(void* _dst, void* _src, ae_state *_state) { qpbleicbuffers *dst = (qpbleicbuffers*)_dst; qpbleicbuffers *src = (qpbleicbuffers*)_src; _minbleicstate_init_copy(&dst->solver, &src->solver, _state); _minbleicreport_init_copy(&dst->solverrep, &src->solverrep, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state); ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; } void _qpbleicbuffers_clear(void* _p) { qpbleicbuffers *p = (qpbleicbuffers*)_p; ae_touch_ptr((void*)p); _minbleicstate_clear(&p->solver); _minbleicreport_clear(&p->solverrep); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmp1); ae_vector_clear(&p->tmpi); } void _qpbleicbuffers_destroy(void* _p) { qpbleicbuffers *p = (qpbleicbuffers*)_p; ae_touch_ptr((void*)p); _minbleicstate_destroy(&p->solver); _minbleicreport_destroy(&p->solverrep); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmp1); ae_vector_destroy(&p->tmpi); } /************************************************************************* This function initializes QPCholeskySettings structure with default settings. Newly created structure MUST be initialized by default settings - or by copy of the already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpcholeskyloaddefaults(ae_int_t nmain, qpcholeskysettings* s, ae_state *_state) { s->epsg = 0.0; s->epsf = 0.0; s->epsx = 1.0E-6; s->maxits = 0; } /************************************************************************* This function initializes QPCholeskySettings structure with copy of another, already initialized structure. -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpcholeskycopysettings(qpcholeskysettings* src, qpcholeskysettings* dst, ae_state *_state) { dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; } /************************************************************************* This function runs QPCholesky solver; it returns after optimization process was completed. Following QP problem is solved: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) subject to boundary constraints. INPUT PARAMETERS: AC - for dense problems (AKind=0) contains system matrix in the A-term of CQM object. OTHER TERMS ARE ACTIVELY USED AND MODIFIED BY THE SOLVER! SparseAC - for sparse problems (AKind=1 AKind - sparse matrix format: * 0 for dense matrix * 1 for sparse matrix SparseUpper - which triangle of SparseAC stores matrix - upper or lower one (for dense matrices this parameter is not actual). BC - linear term, array[NC] BndLC - lower bound, array[NC] BndUC - upper bound, array[NC] SC - scale vector, array[NC]: * I-th element contains scale of I-th variable, * SC[I]>0 XOriginC - origin term, array[NC]. Can be zero. NC - number of variables in the original formulation (no slack variables). CLEICC - linear equality/inequality constraints. Present version of this function does NOT provide publicly available support for linear constraints. This feature will be introduced in the future versions of the function. NEC, NIC - number of equality/inequality constraints. MUST BE ZERO IN THE CURRENT VERSION!!! Settings - QPCholeskySettings object initialized by one of the initialization functions. SState - object which stores temporaries: * if uninitialized object was passed, FirstCall parameter MUST be set to True; object will be automatically initialized by the function, and FirstCall will be set to False. * if FirstCall=False, it is assumed that this parameter was already initialized by previous call to this function with same problem dimensions (variable count N). XS - initial point, array[NC] OUTPUT PARAMETERS: XS - last point TerminationType-termination type: * * * -- ALGLIB -- Copyright 14.05.2011 by Bochkanov Sergey *************************************************************************/ void qpcholeskyoptimize(convexquadraticmodel* a, double anorm, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, /* Real */ ae_vector* s, /* Real */ ae_vector* xorigin, ae_int_t n, /* Real */ ae_matrix* cleic, ae_int_t nec, ae_int_t nic, qpcholeskybuffers* sstate, /* Real */ ae_vector* xsc, ae_int_t* terminationtype, ae_state *_state) { ae_int_t i; double noisetolerance; ae_bool havebc; double v; ae_int_t badnewtonits; double maxscaledgrad; double v0; double v1; ae_int_t nextaction; double fprev; double fcur; double fcand; double noiselevel; double d0; double d1; double d2; ae_int_t actstatus; *terminationtype = 0; /* * Allocate storage and prepare fields */ rvectorsetlengthatleast(&sstate->rctmpg, n, _state); rvectorsetlengthatleast(&sstate->tmp0, n, _state); rvectorsetlengthatleast(&sstate->tmp1, n, _state); rvectorsetlengthatleast(&sstate->gc, n, _state); rvectorsetlengthatleast(&sstate->pg, n, _state); rvectorsetlengthatleast(&sstate->xs, n, _state); rvectorsetlengthatleast(&sstate->xn, n, _state); rvectorsetlengthatleast(&sstate->workbndl, n, _state); rvectorsetlengthatleast(&sstate->workbndu, n, _state); bvectorsetlengthatleast(&sstate->havebndl, n, _state); bvectorsetlengthatleast(&sstate->havebndu, n, _state); sstate->repinneriterationscount = 0; sstate->repouteriterationscount = 0; sstate->repncholesky = 0; noisetolerance = (double)(10); /* * Our formulation of quadratic problem includes origin point, * i.e. we have F(x-x_origin) which is minimized subject to * constraints on x, instead of having simply F(x). * * Here we make transition from non-zero origin to zero one. * In order to make such transition we have to: * 1. subtract x_origin from x_start * 2. modify constraints * 3. solve problem * 4. add x_origin to solution * * There is alternate solution - to modify quadratic function * by expansion of multipliers containing (x-x_origin), but * we prefer to modify constraints, because it is a) more precise * and b) easier to to. * * Parts (1)-(2) are done here. After this block is over, * we have: * * XS, which stores shifted XStart (if we don't have XStart, * value of XS will be ignored later) * * WorkBndL, WorkBndU, which store modified boundary constraints. */ havebc = ae_false; for(i=0; i<=n-1; i++) { sstate->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); sstate->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); havebc = (havebc||sstate->havebndl.ptr.p_bool[i])||sstate->havebndu.ptr.p_bool[i]; if( sstate->havebndl.ptr.p_bool[i] ) { sstate->workbndl.ptr.p_double[i] = bndl->ptr.p_double[i]-xorigin->ptr.p_double[i]; } else { sstate->workbndl.ptr.p_double[i] = _state->v_neginf; } if( sstate->havebndu.ptr.p_bool[i] ) { sstate->workbndu.ptr.p_double[i] = bndu->ptr.p_double[i]-xorigin->ptr.p_double[i]; } else { sstate->workbndu.ptr.p_double[i] = _state->v_posinf; } } rmatrixsetlengthatleast(&sstate->workcleic, nec+nic, n+1, _state); for(i=0; i<=nec+nic-1; i++) { v = ae_v_dotproduct(&cleic->ptr.pp_double[i][0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&sstate->workcleic.ptr.pp_double[i][0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); sstate->workcleic.ptr.pp_double[i][n] = cleic->ptr.pp_double[i][n]-v; } /* * We have starting point in StartX, so we just have to shift and bound it */ for(i=0; i<=n-1; i++) { sstate->xs.ptr.p_double[i] = xsc->ptr.p_double[i]-xorigin->ptr.p_double[i]; if( sstate->havebndl.ptr.p_bool[i] ) { if( ae_fp_less(sstate->xs.ptr.p_double[i],sstate->workbndl.ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->workbndl.ptr.p_double[i]; } } if( sstate->havebndu.ptr.p_bool[i] ) { if( ae_fp_greater(sstate->xs.ptr.p_double[i],sstate->workbndu.ptr.p_double[i]) ) { sstate->xs.ptr.p_double[i] = sstate->workbndu.ptr.p_double[i]; } } } /* * Handle special case - no constraints */ if( !havebc&&nec+nic==0 ) { /* * "Simple" unconstrained Cholesky */ bvectorsetlengthatleast(&sstate->tmpb, n, _state); for(i=0; i<=n-1; i++) { sstate->tmpb.ptr.p_bool[i] = ae_false; } sstate->repncholesky = sstate->repncholesky+1; cqmsetb(a, b, _state); cqmsetactiveset(a, &sstate->xs, &sstate->tmpb, _state); if( !cqmconstrainedoptimum(a, &sstate->xn, _state) ) { *terminationtype = -5; return; } ae_v_move(&xsc->ptr.p_double[0], 1, &sstate->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&xsc->ptr.p_double[0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1)); sstate->repinneriterationscount = 1; sstate->repouteriterationscount = 1; *terminationtype = 4; return; } /* * Prepare "active set" structure */ sasinit(n, &sstate->sas, _state); sassetbc(&sstate->sas, &sstate->workbndl, &sstate->workbndu, _state); sassetlcx(&sstate->sas, &sstate->workcleic, nec, nic, _state); sassetscale(&sstate->sas, s, _state); if( !sasstartoptimization(&sstate->sas, &sstate->xs, _state) ) { *terminationtype = -3; return; } /* * Main cycle of CQP algorithm */ *terminationtype = 4; badnewtonits = 0; maxscaledgrad = 0.0; for(;;) { /* * Update iterations count */ inc(&sstate->repouteriterationscount, _state); inc(&sstate->repinneriterationscount, _state); /* * Phase 1. * * Determine active set. * Update MaxScaledGrad. */ cqmadx(a, &sstate->sas.xc, &sstate->rctmpg, _state); ae_v_add(&sstate->rctmpg.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); sasreactivateconstraints(&sstate->sas, &sstate->rctmpg, _state); v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(sstate->rctmpg.ptr.p_double[i]*s->ptr.p_double[i], _state); } maxscaledgrad = ae_maxreal(maxscaledgrad, ae_sqrt(v, _state), _state); /* * Phase 2: perform penalized steepest descent step. * * NextAction control variable is set on exit from this loop: * * NextAction>0 in case we have to proceed to Phase 3 (Newton step) * * NextAction<0 in case we have to proceed to Phase 1 (recalculate active set) * * NextAction=0 in case we found solution (step along projected gradient is small enough) */ for(;;) { /* * Calculate constrained descent direction, store to PG. * Successful termination if PG is zero. */ cqmadx(a, &sstate->sas.xc, &sstate->gc, _state); ae_v_add(&sstate->gc.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); sasconstraineddescent(&sstate->sas, &sstate->gc, &sstate->pg, _state); v0 = ae_v_dotproduct(&sstate->pg.ptr.p_double[0], 1, &sstate->pg.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_eq(v0,(double)(0)) ) { /* * Constrained derivative is zero. * Solution found. */ nextaction = 0; break; } /* * Build quadratic model of F along descent direction: * F(xc+alpha*pg) = D2*alpha^2 + D1*alpha + D0 * Store noise level in the XC (noise level is used to classify * step as singificant or insignificant). * * In case function curvature is negative or product of descent * direction and gradient is non-negative, iterations are terminated. * * NOTE: D0 is not actually used, but we prefer to maintain it. */ fprev = qpcholeskysolver_modelvalue(a, b, &sstate->sas.xc, n, &sstate->tmp0, _state); fprev = fprev+qpcholeskysolver_penaltyfactor*maxscaledgrad*sasactivelcpenalty1(&sstate->sas, &sstate->sas.xc, _state); cqmevalx(a, &sstate->sas.xc, &v, &noiselevel, _state); v0 = cqmxtadx2(a, &sstate->pg, _state); d2 = v0; v1 = ae_v_dotproduct(&sstate->pg.ptr.p_double[0], 1, &sstate->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); d1 = v1; d0 = fprev; if( ae_fp_less_eq(d2,(double)(0)) ) { /* * Second derivative is non-positive, function is non-convex. */ *terminationtype = -5; nextaction = 0; break; } if( ae_fp_greater_eq(d1,(double)(0)) ) { /* * Second derivative is positive, first derivative is non-negative. * Solution found. */ nextaction = 0; break; } /* * Modify quadratic model - add penalty for violation of the active * constraints. * * Boundary constraints are always satisfied exactly, so we do not * add penalty term for them. General equality constraint of the * form a'*(xc+alpha*d)=b adds penalty term: * P(alpha) = (a'*(xc+alpha*d)-b)^2 * = (alpha*(a'*d) + (a'*xc-b))^2 * = alpha^2*(a'*d)^2 + alpha*2*(a'*d)*(a'*xc-b) + (a'*xc-b)^2 * Each penalty term is multiplied by 100*Anorm before adding it to * the 1-dimensional quadratic model. * * Penalization of the quadratic model improves behavior of the * algorithm in the presense of the multiple degenerate constraints. * In particular, it prevents algorithm from making large steps in * directions which violate equality constraints. */ for(i=0; i<=nec+nic-1; i++) { if( sstate->sas.activeset.ptr.p_int[n+i]>0 ) { v0 = ae_v_dotproduct(&sstate->workcleic.ptr.pp_double[i][0], 1, &sstate->pg.ptr.p_double[0], 1, ae_v_len(0,n-1)); v1 = ae_v_dotproduct(&sstate->workcleic.ptr.pp_double[i][0], 1, &sstate->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); v1 = v1-sstate->workcleic.ptr.pp_double[i][n]; v = 100*anorm; d2 = d2+v*ae_sqr(v0, _state); d1 = d1+v*2*v0*v1; d0 = d0+v*ae_sqr(v1, _state); } } /* * Try unbounded step. * In case function change is dominated by noise or function actually increased * instead of decreasing, we terminate iterations. */ v = -d1/(2*d2); ae_v_move(&sstate->xn.ptr.p_double[0], 1, &sstate->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&sstate->xn.ptr.p_double[0], 1, &sstate->pg.ptr.p_double[0], 1, ae_v_len(0,n-1), v); fcand = qpcholeskysolver_modelvalue(a, b, &sstate->xn, n, &sstate->tmp0, _state); fcand = fcand+qpcholeskysolver_penaltyfactor*maxscaledgrad*sasactivelcpenalty1(&sstate->sas, &sstate->xn, _state); if( ae_fp_greater_eq(fcand,fprev-noiselevel*noisetolerance) ) { nextaction = 0; break; } /* * Save active set * Perform bounded step with (possible) activation */ actstatus = qpcholeskysolver_boundedstepandactivation(&sstate->sas, &sstate->xn, n, &sstate->tmp0, _state); fcur = qpcholeskysolver_modelvalue(a, b, &sstate->sas.xc, n, &sstate->tmp0, _state); /* * Depending on results, decide what to do: * 1. In case step was performed without activation of constraints, * we proceed to Newton method * 2. In case there was activated at least one constraint with ActiveSet[I]<0, * we proceed to Phase 1 and re-evaluate active set. * 3. Otherwise (activation of the constraints with ActiveSet[I]=0) * we try Phase 2 one more time. */ if( actstatus<0 ) { /* * Step without activation, proceed to Newton */ nextaction = 1; break; } if( actstatus==0 ) { /* * No new constraints added during last activation - only * ones which were at the boundary (ActiveSet[I]=0), but * inactive due to numerical noise. * * Now, these constraints are added to the active set, and * we try to perform steepest descent (Phase 2) one more time. */ continue; } else { /* * Last step activated at least one significantly new * constraint (ActiveSet[I]<0), we have to re-evaluate * active set (Phase 1). */ nextaction = -1; break; } } if( nextaction<0 ) { continue; } if( nextaction==0 ) { break; } /* * Phase 3: fast equality-constrained solver * * NOTE: this solver uses Augmented Lagrangian algorithm to solve * equality-constrained subproblems. This algorithm may * perform steps which increase function values instead of * decreasing it (in hard cases, like overconstrained problems). * * Such non-monononic steps may create a loop, when Augmented * Lagrangian algorithm performs uphill step, and steepest * descent algorithm (Phase 2) performs downhill step in the * opposite direction. * * In order to prevent iterations to continue forever we * count iterations when AL algorithm increased function * value instead of decreasing it. When number of such "bad" * iterations will increase beyong MaxBadNewtonIts, we will * terminate algorithm. */ fprev = qpcholeskysolver_modelvalue(a, b, &sstate->sas.xc, n, &sstate->tmp0, _state); for(;;) { /* * Calculate optimum subject to presently active constraints */ sstate->repncholesky = sstate->repncholesky+1; if( !qpcholeskysolver_constrainedoptimum(&sstate->sas, a, anorm, b, &sstate->xn, n, &sstate->tmp0, &sstate->tmpb, &sstate->tmp1, _state) ) { *terminationtype = -5; sasstopoptimization(&sstate->sas, _state); return; } /* * Add constraints. * If no constraints was added, accept candidate point XN and move to next phase. */ if( qpcholeskysolver_boundedstepandactivation(&sstate->sas, &sstate->xn, n, &sstate->tmp0, _state)<0 ) { break; } } fcur = qpcholeskysolver_modelvalue(a, b, &sstate->sas.xc, n, &sstate->tmp0, _state); if( ae_fp_greater_eq(fcur,fprev) ) { badnewtonits = badnewtonits+1; } if( badnewtonits>=qpcholeskysolver_maxbadnewtonits ) { /* * Algorithm found solution, but keeps iterating because Newton * algorithm performs uphill steps (noise in the Augmented Lagrangian * algorithm). We terminate algorithm; it is considered normal * termination. */ break; } } sasstopoptimization(&sstate->sas, _state); /* * Post-process: add XOrigin to XC */ for(i=0; i<=n-1; i++) { if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->workbndl.ptr.p_double[i]) ) { xsc->ptr.p_double[i] = bndl->ptr.p_double[i]; continue; } if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->workbndu.ptr.p_double[i]) ) { xsc->ptr.p_double[i] = bndu->ptr.p_double[i]; continue; } xsc->ptr.p_double[i] = boundval(sstate->sas.xc.ptr.p_double[i]+xorigin->ptr.p_double[i], bndl->ptr.p_double[i], bndu->ptr.p_double[i], _state); } } /************************************************************************* Model value: f = 0.5*x'*A*x + b'*x INPUT PARAMETERS: A - convex quadratic model; only main quadratic term is used, other parts of the model (D/Q/linear term) are ignored. This function does not modify model state. B - right part XC - evaluation point Tmp - temporary buffer, automatically resized if needed -- ALGLIB -- Copyright 20.06.2012 by Bochkanov Sergey *************************************************************************/ static double qpcholeskysolver_modelvalue(convexquadraticmodel* a, /* Real */ ae_vector* b, /* Real */ ae_vector* xc, ae_int_t n, /* Real */ ae_vector* tmp, ae_state *_state) { double v0; double v1; double result; rvectorsetlengthatleast(tmp, n, _state); cqmadx(a, xc, tmp, _state); v0 = ae_v_dotproduct(&xc->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,n-1)); v1 = ae_v_dotproduct(&xc->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = 0.5*v0+v1; return result; } /************************************************************************* Having feasible current point XC and possibly infeasible candidate point XN, this function performs longest step from XC to XN which retains feasibility. In case XN is found to be infeasible, at least one constraint is activated. For example, if we have: XC=0.5 XN=1.2 x>=0, x<=1 then this function will move us to X=1.0 and activate constraint "x<=1". INPUT PARAMETERS: State - MinQP state. XC - current point, must be feasible with respect to all constraints XN - candidate point, can be infeasible with respect to some constraints. Must be located in the subspace of current active set, i.e. it is feasible with respect to already active constraints. Buf - temporary buffer, automatically resized if needed OUTPUT PARAMETERS: State - this function changes following fields of State: * State.ActiveSet * State.ActiveC - active linear constraints XC - new position RESULT: >0, in case at least one inactive non-candidate constraint was activated =0, in case only "candidate" constraints were activated <0, in case no constraints were activated by the step -- ALGLIB -- Copyright 29.02.2012 by Bochkanov Sergey *************************************************************************/ static ae_int_t qpcholeskysolver_boundedstepandactivation(sactiveset* sas, /* Real */ ae_vector* xn, ae_int_t n, /* Real */ ae_vector* buf, ae_state *_state) { double stpmax; ae_int_t cidx; double cval; ae_bool needact; double v; ae_int_t result; rvectorsetlengthatleast(buf, n, _state); ae_v_move(&buf->ptr.p_double[0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_sub(&buf->ptr.p_double[0], 1, &sas->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); sasexploredirection(sas, buf, &stpmax, &cidx, &cval, _state); needact = ae_fp_less_eq(stpmax,(double)(1)); v = ae_minreal(stpmax, 1.0, _state); ae_v_muld(&buf->ptr.p_double[0], 1, ae_v_len(0,n-1), v); ae_v_add(&buf->ptr.p_double[0], 1, &sas->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); result = sasmoveto(sas, buf, needact, cidx, cval, _state); return result; } /************************************************************************* Optimum of A subject to: a) active boundary constraints (given by ActiveSet[] and corresponding elements of XC) b) active linear constraints (given by C, R, LagrangeC) INPUT PARAMETERS: A - main quadratic term of the model; although structure may store linear and rank-K terms, these terms are ignored and rewritten by this function. ANorm - estimate of ||A|| (2-norm is used) B - array[N], linear term of the model XN - possibly preallocated buffer Tmp - temporary buffer (automatically resized) Tmp1 - temporary buffer (automatically resized) OUTPUT PARAMETERS: A - modified quadratic model (this function changes rank-K term and linear term of the model) LagrangeC- current estimate of the Lagrange coefficients XN - solution RESULT: True on success, False on failure (non-SPD model) -- ALGLIB -- Copyright 20.06.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool qpcholeskysolver_constrainedoptimum(sactiveset* sas, convexquadraticmodel* a, double anorm, /* Real */ ae_vector* b, /* Real */ ae_vector* xn, ae_int_t n, /* Real */ ae_vector* tmp, /* Boolean */ ae_vector* tmpb, /* Real */ ae_vector* lagrangec, ae_state *_state) { ae_int_t itidx; ae_int_t i; double v; double feaserrold; double feaserrnew; double theta; ae_bool result; /* * Rebuild basis accroding to current active set. * We call SASRebuildBasis() to make sure that fields of SAS * store up to date values. */ sasrebuildbasis(sas, _state); /* * Allocate temporaries. */ rvectorsetlengthatleast(tmp, ae_maxint(n, sas->basissize, _state), _state); bvectorsetlengthatleast(tmpb, n, _state); rvectorsetlengthatleast(lagrangec, sas->basissize, _state); /* * Prepare model */ for(i=0; i<=sas->basissize-1; i++) { tmp->ptr.p_double[i] = sas->pbasis.ptr.pp_double[i][n]; } theta = 100.0*anorm; for(i=0; i<=n-1; i++) { if( sas->activeset.ptr.p_int[i]>0 ) { tmpb->ptr.p_bool[i] = ae_true; } else { tmpb->ptr.p_bool[i] = ae_false; } } cqmsetactiveset(a, &sas->xc, tmpb, _state); cqmsetq(a, &sas->pbasis, tmp, sas->basissize, theta, _state); /* * Iterate until optimal values of Lagrange multipliers are found */ for(i=0; i<=sas->basissize-1; i++) { lagrangec->ptr.p_double[i] = (double)(0); } feaserrnew = ae_maxrealnumber; result = ae_true; for(itidx=1; itidx<=qpcholeskysolver_maxlagrangeits; itidx++) { /* * Generate right part B using linear term and current * estimate of the Lagrange multipliers. */ ae_v_move(&tmp->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=sas->basissize-1; i++) { v = lagrangec->ptr.p_double[i]; ae_v_subd(&tmp->ptr.p_double[0], 1, &sas->pbasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } cqmsetb(a, tmp, _state); /* * Solve */ result = cqmconstrainedoptimum(a, xn, _state); if( !result ) { return result; } /* * Compare feasibility errors. * Terminate if error decreased too slowly. */ feaserrold = feaserrnew; feaserrnew = (double)(0); for(i=0; i<=sas->basissize-1; i++) { v = ae_v_dotproduct(&sas->pbasis.ptr.pp_double[i][0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); feaserrnew = feaserrnew+ae_sqr(v-sas->pbasis.ptr.pp_double[i][n], _state); } feaserrnew = ae_sqrt(feaserrnew, _state); if( ae_fp_greater_eq(feaserrnew,0.2*feaserrold) ) { break; } /* * Update Lagrange multipliers */ for(i=0; i<=sas->basissize-1; i++) { v = ae_v_dotproduct(&sas->pbasis.ptr.pp_double[i][0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); lagrangec->ptr.p_double[i] = lagrangec->ptr.p_double[i]-theta*(v-sas->pbasis.ptr.pp_double[i][n]); } } return result; } void _qpcholeskysettings_init(void* _p, ae_state *_state) { qpcholeskysettings *p = (qpcholeskysettings*)_p; ae_touch_ptr((void*)p); } void _qpcholeskysettings_init_copy(void* _dst, void* _src, ae_state *_state) { qpcholeskysettings *dst = (qpcholeskysettings*)_dst; qpcholeskysettings *src = (qpcholeskysettings*)_src; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; } void _qpcholeskysettings_clear(void* _p) { qpcholeskysettings *p = (qpcholeskysettings*)_p; ae_touch_ptr((void*)p); } void _qpcholeskysettings_destroy(void* _p) { qpcholeskysettings *p = (qpcholeskysettings*)_p; ae_touch_ptr((void*)p); } void _qpcholeskybuffers_init(void* _p, ae_state *_state) { qpcholeskybuffers *p = (qpcholeskybuffers*)_p; ae_touch_ptr((void*)p); _sactiveset_init(&p->sas, _state); ae_vector_init(&p->pg, 0, DT_REAL, _state); ae_vector_init(&p->gc, 0, DT_REAL, _state); ae_vector_init(&p->xs, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->workbndl, 0, DT_REAL, _state); ae_vector_init(&p->workbndu, 0, DT_REAL, _state); ae_vector_init(&p->havebndl, 0, DT_BOOL, _state); ae_vector_init(&p->havebndu, 0, DT_BOOL, _state); ae_matrix_init(&p->workcleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->rctmpg, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmp1, 0, DT_REAL, _state); ae_vector_init(&p->tmpb, 0, DT_BOOL, _state); } void _qpcholeskybuffers_init_copy(void* _dst, void* _src, ae_state *_state) { qpcholeskybuffers *dst = (qpcholeskybuffers*)_dst; qpcholeskybuffers *src = (qpcholeskybuffers*)_src; _sactiveset_init_copy(&dst->sas, &src->sas, _state); ae_vector_init_copy(&dst->pg, &src->pg, _state); ae_vector_init_copy(&dst->gc, &src->gc, _state); ae_vector_init_copy(&dst->xs, &src->xs, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->workbndl, &src->workbndl, _state); ae_vector_init_copy(&dst->workbndu, &src->workbndu, _state); ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state); ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state); ae_matrix_init_copy(&dst->workcleic, &src->workcleic, _state); ae_vector_init_copy(&dst->rctmpg, &src->rctmpg, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state); ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repncholesky = src->repncholesky; } void _qpcholeskybuffers_clear(void* _p) { qpcholeskybuffers *p = (qpcholeskybuffers*)_p; ae_touch_ptr((void*)p); _sactiveset_clear(&p->sas); ae_vector_clear(&p->pg); ae_vector_clear(&p->gc); ae_vector_clear(&p->xs); ae_vector_clear(&p->xn); ae_vector_clear(&p->workbndl); ae_vector_clear(&p->workbndu); ae_vector_clear(&p->havebndl); ae_vector_clear(&p->havebndu); ae_matrix_clear(&p->workcleic); ae_vector_clear(&p->rctmpg); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmp1); ae_vector_clear(&p->tmpb); } void _qpcholeskybuffers_destroy(void* _p) { qpcholeskybuffers *p = (qpcholeskybuffers*)_p; ae_touch_ptr((void*)p); _sactiveset_destroy(&p->sas); ae_vector_destroy(&p->pg); ae_vector_destroy(&p->gc); ae_vector_destroy(&p->xs); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->workbndl); ae_vector_destroy(&p->workbndu); ae_vector_destroy(&p->havebndl); ae_vector_destroy(&p->havebndu); ae_matrix_destroy(&p->workcleic); ae_vector_destroy(&p->rctmpg); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmp1); ae_vector_destroy(&p->tmpb); } /************************************************************************* CONSTRAINED QUADRATIC PROGRAMMING The subroutine creates QP optimizer. After initial creation, it contains default optimization problem with zero quadratic and linear terms and no constraints. You should set quadratic/linear terms with calls to functions provided by MinQP subpackage. You should also choose appropriate QP solver and set it and its stopping criteria by means of MinQPSetAlgo??????() function. Then, you should start solution process by means of MinQPOptimize() call. Solution itself can be obtained with MinQPResults() function. INPUT PARAMETERS: N - problem size OUTPUT PARAMETERS: State - optimizer with zero quadratic/linear terms and no constraints -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state) { ae_int_t i; _minqpstate_clear(state); ae_assert(n>=1, "MinQPCreate: N<1", _state); /* * initialize QP solver */ state->n = n; state->nec = 0; state->nic = 0; state->repterminationtype = 0; state->absamax = (double)(1); state->absasum = (double)(1); state->absasum2 = (double)(1); state->akind = 0; state->sparseaupper = ae_false; cqminit(n, &state->a, _state); ae_vector_set_length(&state->b, n, _state); ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->havebndl, n, _state); ae_vector_set_length(&state->havebndu, n, _state); ae_vector_set_length(&state->s, n, _state); ae_vector_set_length(&state->startx, n, _state); ae_vector_set_length(&state->xorigin, n, _state); ae_vector_set_length(&state->xs, n, _state); for(i=0; i<=n-1; i++) { state->bndl.ptr.p_double[i] = _state->v_neginf; state->bndu.ptr.p_double[i] = _state->v_posinf; state->havebndl.ptr.p_bool[i] = ae_false; state->havebndu.ptr.p_bool[i] = ae_false; state->b.ptr.p_double[i] = 0.0; state->startx.ptr.p_double[i] = 0.0; state->xorigin.ptr.p_double[i] = 0.0; state->s.ptr.p_double[i] = 1.0; } state->havex = ae_false; minqpsetalgocholesky(state, _state); normestimatorcreate(n, n, 5, 5, &state->estimator, _state); qqploaddefaults(n, &state->qqpsettingsuser, _state); qpbleicloaddefaults(n, &state->qpbleicsettingsuser, _state); state->qpbleicfirstcall = ae_true; } /************************************************************************* This function sets linear term for QP solver. By default, linear term is zero. INPUT PARAMETERS: State - structure which stores algorithm state B - linear term, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetlinearterm(minqpstate* state, /* Real */ ae_vector* b, ae_state *_state) { ae_int_t n; n = state->n; ae_assert(b->cnt>=n, "MinQPSetLinearTerm: Length(B)n; ae_assert(a->rows>=n, "MinQPSetQuadraticTerm: Rows(A)cols>=n, "MinQPSetQuadraticTerm: Cols(A)n; ae_assert(sparsegetnrows(a, _state)==n, "MinQPSetQuadraticTermSparse: Rows(A)<>N", _state); ae_assert(sparsegetncols(a, _state)==n, "MinQPSetQuadraticTermSparse: Cols(A)<>N", _state); sparsecopytocrsbuf(a, &state->sparsea, _state); state->sparseaupper = isupper; state->akind = 1; /* * Estimate norm of A * (it will be used later in the quadratic penalty function) */ state->absamax = (double)(0); state->absasum = (double)(0); state->absasum2 = (double)(0); t0 = 0; t1 = 0; while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) { if( i==j ) { /* * Diagonal terms are counted only once */ state->absamax = ae_maxreal(state->absamax, v, _state); state->absasum = state->absasum+v; state->absasum2 = state->absasum2+v*v; } if( (j>i&&isupper)||(jabsamax = ae_maxreal(state->absamax, v, _state); state->absasum = state->absasum+2*v; state->absasum2 = state->absasum2+2*v*v; } } } /************************************************************************* This function sets starting point for QP solver. It is useful to have good initial approximation to the solution, because it will increase speed of convergence and identification of active constraints. INPUT PARAMETERS: State - structure which stores algorithm state X - starting point, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetstartingpoint(minqpstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; n = state->n; ae_assert(x->cnt>=n, "MinQPSetStartingPoint: Length(B)n; ae_assert(xorigin->cnt>=n, "MinQPSetOrigin: Length(B)cnt>=state->n, "MinQPSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinQPSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinQPSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function tells solver to use Cholesky-based algorithm. This algorithm was deprecated in ALGLIB 3.9.0 because its performance is inferior to that of BLEIC-QP or QuickQP on high-dimensional problems. Furthermore, it supports only dense convex QP problems. This solver is no longer active by default. We recommend you to switch to BLEIC-QP or QuickQP solver. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgocholesky(minqpstate* state, ae_state *_state) { state->algokind = 1; } /************************************************************************* This function tells solver to use BLEIC-based algorithm and sets stopping criteria for the algorithm. ALGORITHM FEATURES: * supports dense and sparse QP problems * supports boundary and general linear equality/inequality constraints * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". Of course, global minimum is found only for positive definite and semidefinite problems. As for indefinite ones - only local minimum is found. ALGORITHM OUTLINE: * BLEIC-QP solver is just a driver function for MinBLEIC solver; it solves quadratic programming problem as general linearly constrained optimization problem, which is solved by means of BLEIC solver (part of ALGLIB, active set method). ALGORITHM LIMITATIONS: * unlike QuickQP solver, this algorithm does not perform Newton steps and does not use Level 3 BLAS. Being general-purpose active set method, it can activate constraints only one-by-one. Thus, its performance is lower than that of QuickQP. * its precision is also a bit inferior to that of QuickQP. BLEIC-QP performs only LBFGS steps (no Newton steps), which are good at detecting neighborhood of the solution, buy need many iterations to find solution with more than 6 digits of precision. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. NOTE: this algorithm uses LBFGS iterations, which are relatively cheap, but improve function value only a bit. So you will need many iterations to converge - from 0.1*N to 10*N, depending on problem's condition number. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetalgobleic(minqpstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinQPSetAlgoBLEIC: EpsG is not finite number", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinQPSetAlgoBLEIC: negative EpsG", _state); ae_assert(ae_isfinite(epsf, _state), "MinQPSetAlgoBLEIC: EpsF is not finite number", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinQPSetAlgoBLEIC: negative EpsF", _state); ae_assert(ae_isfinite(epsx, _state), "MinQPSetAlgoBLEIC: EpsX is not finite number", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinQPSetAlgoBLEIC: negative EpsX", _state); ae_assert(maxits>=0, "MinQPSetAlgoBLEIC: negative MaxIts!", _state); state->algokind = 2; if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->qpbleicsettingsuser.epsg = epsg; state->qpbleicsettingsuser.epsf = epsf; state->qpbleicsettingsuser.epsx = epsx; state->qpbleicsettingsuser.maxits = maxits; } /************************************************************************* This function tells solver to use QuickQP algorithm: special extra-fast algorithm for problems with boundary-only constrants. It may solve non-convex problems as long as they are bounded from below under constraints. ALGORITHM FEATURES: * many times (from 5x to 50x!) faster than BLEIC-based QP solver; utilizes accelerated methods for activation of constraints. * supports dense and sparse QP problems * supports ONLY boundary constraints; general linear constraints are NOT supported by this solver * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". In convex/semidefinite case global minimum is returned, in nonconvex case - algorithm returns one of the local minimums. ALGORITHM OUTLINE: * algorithm performs two kinds of iterations: constrained CG iterations and constrained Newton iterations * initially it performs small number of constrained CG iterations, which can efficiently activate/deactivate multiple constraints * after CG phase algorithm tries to calculate Cholesky decomposition and to perform several constrained Newton steps. If Cholesky decomposition failed (matrix is indefinite even under constraints), we perform more CG iterations until we converge to such set of constraints that system matrix becomes positive definite. Constrained Newton steps greatly increase convergence speed and precision. * algorithm interleaves CG and Newton iterations which allows to handle indefinite matrices (CG phase) and quickly converge after final set of constraints is found (Newton phase). Combination of CG and Newton phases is called "outer iteration". * it is possible to turn off Newton phase (beneficial for semidefinite problems - Cholesky decomposition will fail too often) ALGORITHM LIMITATIONS: * algorithm does not support general linear constraints; only boundary ones are supported * Cholesky decomposition for sparse problems is performed with Skyline Cholesky solver, which is intended for low-profile matrices. No profile- reducing reordering of variables is performed in this version of ALGLIB. * problems with near-zero negative eigenvalues (or exacty zero ones) may experience about 2-3x performance penalty. The reason is that Cholesky decomposition can not be performed until we identify directions of zero and negative curvature and activate corresponding boundary constraints - but we need a lot of trial and errors because these directions are hard to notice in the matrix spectrum. In this case you may turn off Newton phase of algorithm. Large negative eigenvalues are not an issue, so highly non-convex problems can be solved very efficiently. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxOuterIts-maximum number of OUTER iterations. One outer iteration includes some amount of CG iterations (from 5 to ~N) and one or several (usually small amount) Newton steps. Thus, one outer iteration has high cost, but can greatly reduce funcation value. UseNewton- use Newton phase or not: * Newton phase improves performance of positive definite dense problems (about 2 times improvement can be observed) * can result in some performance penalty on semidefinite or slightly negative definite problems - each Newton phase will bring no improvement (Cholesky failure), but still will require computational time. * if you doubt, you can turn off this phase - optimizer will retain its most of its high speed. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 22.05.2014 by Bochkanov Sergey *************************************************************************/ void minqpsetalgoquickqp(minqpstate* state, double epsg, double epsf, double epsx, ae_int_t maxouterits, ae_bool usenewton, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinQPSetAlgoQuickQP: EpsG is not finite number", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsG", _state); ae_assert(ae_isfinite(epsf, _state), "MinQPSetAlgoQuickQP: EpsF is not finite number", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsF", _state); ae_assert(ae_isfinite(epsx, _state), "MinQPSetAlgoQuickQP: EpsX is not finite number", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsX", _state); ae_assert(maxouterits>=0, "MinQPSetAlgoQuickQP: negative MaxOuterIts!", _state); state->algokind = 3; if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxouterits==0 ) { epsx = 1.0E-6; } state->qqpsettingsuser.maxouterits = maxouterits; state->qqpsettingsuser.epsg = epsg; state->qqpsettingsuser.epsf = epsf; state->qqpsettingsuser.epsx = epsx; state->qqpsettingsuser.cnphase = usenewton; } /************************************************************************* This function sets boundary constraints for QP solver Boundary constraints are inactive by default (after initial creation). After being set, they are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetbc(minqpstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_int_t i; ae_int_t n; n = state->n; ae_assert(bndl->cnt>=n, "MinQPSetBC: Length(BndL)cnt>=n, "MinQPSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinQPSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinQPSetBC: BndU contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } } /************************************************************************* This function sets linear constraints for QP optimizer. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - structure previously allocated with MinQPCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately - there always exists some minor violation (about 10^-10...10^-13) due to numerical errors. -- ALGLIB -- Copyright 19.06.2012 by Bochkanov Sergey *************************************************************************/ void minqpsetlc(minqpstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; double v; n = state->n; /* * First, check for errors in the inputs */ ae_assert(k>=0, "MinQPSetLC: K<0", _state); ae_assert(c->cols>=n+1||k==0, "MinQPSetLC: Cols(C)rows>=k, "MinQPSetLC: Rows(C)cnt>=k, "MinQPSetLC: Length(CT)nec = 0; state->nic = 0; return; } /* * Equality constraints are stored first, in the upper * NEC rows of State.CLEIC matrix. Inequality constraints * are stored in the next NIC rows. * * NOTE: we convert inequality constraints to the form * A*x<=b before copying them. */ rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); state->nec = 0; state->nic = 0; for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]==0 ) { ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); state->nec = state->nec+1; } } for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]!=0 ) { if( ct->ptr.p_int[i]>0 ) { ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } else { ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } state->nic = state->nic+1; } } /* * Normalize rows of State.CLEIC: each row must have unit norm. * Norm is calculated using first N elements (i.e. right part is * not counted when we calculate norm). */ for(i=0; i<=k-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+ae_sqr(state->cleic.ptr.pp_double[i][j], _state); } if( ae_fp_eq(v,(double)(0)) ) { continue; } v = 1/ae_sqrt(v, _state); ae_v_muld(&state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n), v); } } /************************************************************************* This function solves quadratic programming problem. Prior to calling this function you should choose solver by means of one of the following functions: * MinQPSetAlgoQuickQP() - for QuickQP solver * MinQPSetAlgoBLEIC() - for BLEIC-QP solver These functions also allow you to control stopping criteria of the solver. If you did not set solver, MinQP subpackage will automatically select solver for your problem and will run it with default stopping criteria. However, it is better to set explicitly solver and its stopping criteria. INPUT PARAMETERS: State - algorithm state You should use MinQPResults() function to access results after calls to this function. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey. Special thanks to Elvira Illarionova for important suggestions on the linearly constrained QP algorithm. *************************************************************************/ void minqpoptimize(minqpstate* state, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t nbc; ae_int_t currentsolver; n = state->n; state->repterminationtype = -5; state->repinneriterationscount = 0; state->repouteriterationscount = 0; state->repncholesky = 0; state->repnmv = 0; /* * check correctness of constraints */ for(i=0; i<=n-1; i++) { if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) { if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->repterminationtype = -3; return; } } } /* * count number of bound and linear constraints */ nbc = 0; for(i=0; i<=n-1; i++) { if( state->havebndl.ptr.p_bool[i] ) { nbc = nbc+1; } if( state->havebndu.ptr.p_bool[i] ) { nbc = nbc+1; } } /* * Initial point: * * if we have starting point in StartX, we just have to bound it * * if we do not have StartX, deduce initial point from boundary constraints */ if( state->havex ) { for(i=0; i<=n-1; i++) { state->xs.ptr.p_double[i] = state->startx.ptr.p_double[i]; if( state->havebndl.ptr.p_bool[i]&&ae_fp_less(state->xs.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; } if( state->havebndu.ptr.p_bool[i]&&ae_fp_greater(state->xs.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; } } } else { for(i=0; i<=n-1; i++) { if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) { state->xs.ptr.p_double[i] = 0.5*(state->bndl.ptr.p_double[i]+state->bndu.ptr.p_double[i]); continue; } if( state->havebndl.ptr.p_bool[i] ) { state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; continue; } if( state->havebndu.ptr.p_bool[i] ) { state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; continue; } state->xs.ptr.p_double[i] = (double)(0); } } /* * Choose solver - user-specified or default one. */ currentsolver = state->algokind; if( currentsolver==0 ) { /* * Choose solver automatically */ if( state->nec+state->nic==0 ) { /* * QQP solver is used for problems without linear constraints */ currentsolver = 3; qqploaddefaults(n, &state->qqpsettingscurrent, _state); } else { /* * QP-BLEIC solver is used for problems without linear constraints */ currentsolver = 2; qpbleicloaddefaults(n, &state->qpbleicsettingscurrent, _state); } } else { ae_assert((currentsolver==1||currentsolver==2)||currentsolver==3, "MinQPOptimize: internal error", _state); if( currentsolver==1 ) { } if( currentsolver==2 ) { /* * QP-BLEIC solver is chosen by user */ qpbleiccopysettings(&state->qpbleicsettingsuser, &state->qpbleicsettingscurrent, _state); } if( currentsolver==3 ) { /* * QQP solver is chosen by user */ qqpcopysettings(&state->qqpsettingsuser, &state->qqpsettingscurrent, _state); } } /* * QP-BLEIC solver */ if( currentsolver==2 ) { qpbleicoptimize(&state->a, &state->sparsea, state->akind, state->sparseaupper, state->absasum, state->absasum2, &state->b, &state->bndl, &state->bndu, &state->s, &state->xorigin, n, &state->cleic, state->nec, state->nic, &state->qpbleicsettingscurrent, &state->qpbleicbuf, &state->qpbleicfirstcall, &state->xs, &state->repterminationtype, _state); state->repinneriterationscount = state->qpbleicbuf.repinneriterationscount; state->repouteriterationscount = state->qpbleicbuf.repouteriterationscount; return; } /* * QuickQP solver */ if( currentsolver==3 ) { if( state->nec+state->nic>0 ) { state->repterminationtype = -5; return; } qqpoptimize(&state->a, &state->sparsea, state->akind, state->sparseaupper, &state->b, &state->bndl, &state->bndu, &state->s, &state->xorigin, n, &state->cleic, state->nec, state->nic, &state->qqpsettingscurrent, &state->qqpbuf, &state->xs, &state->repterminationtype, _state); state->repinneriterationscount = state->qqpbuf.repinneriterationscount; state->repouteriterationscount = state->qqpbuf.repouteriterationscount; state->repncholesky = state->qqpbuf.repncholesky; return; } /* * Cholesky solver. */ if( currentsolver==1 ) { /* * Check matrix type. * Cholesky solver supports only dense matrices. */ if( state->akind!=0 ) { state->repterminationtype = -5; return; } qpcholeskyoptimize(&state->a, state->absamax*n, &state->b, &state->bndl, &state->bndu, &state->s, &state->xorigin, n, &state->cleic, state->nec, state->nic, &state->qpcholeskybuf, &state->xs, &state->repterminationtype, _state); state->repinneriterationscount = state->qqpbuf.repinneriterationscount; state->repouteriterationscount = state->qqpbuf.repouteriterationscount; state->repncholesky = state->qqpbuf.repncholesky; return; } } /************************************************************************* QP solver results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution. This array is allocated and initialized only when Rep.TerminationType parameter is positive (success). Rep - optimization report. You should check Rep.TerminationType, which contains completion code, and you may check another fields which contain another information about algorithm functioning. Failure codes returned by algorithm are: * -5 inappropriate solver was used: * Cholesky solver for (semi)indefinite problems * Cholesky solver for problems with sparse matrix * QuickQP solver for problem with general linear constraints * -4 BLEIC-QP/QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or maybe feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. Completion codes specific for Cholesky algorithm: * 4 successful completion Completion codes specific for BLEIC/QuickQP algorithms: * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresults(minqpstate* state, /* Real */ ae_vector* x, minqpreport* rep, ae_state *_state) { ae_vector_clear(x); _minqpreport_clear(rep); minqpresultsbuf(state, x, rep, _state); } /************************************************************************* QP results Buffered implementation of MinQPResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpresultsbuf(minqpstate* state, /* Real */ ae_vector* x, minqpreport* rep, ae_state *_state) { if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->xs.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->inneriterationscount = state->repinneriterationscount; rep->outeriterationscount = state->repouteriterationscount; rep->nmv = state->repnmv; rep->ncholesky = state->repncholesky; rep->terminationtype = state->repterminationtype; } /************************************************************************* Fast version of MinQPSetLinearTerm(), which doesn't check its arguments. For internal use only. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetlineartermfast(minqpstate* state, /* Real */ ae_vector* b, ae_state *_state) { ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } /************************************************************************* Fast version of MinQPSetQuadraticTerm(), which doesn't check its arguments. It accepts additional parameter - shift S, which allows to "shift" matrix A by adding s*I to A. S must be positive (although it is not checked). For internal use only. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetquadratictermfast(minqpstate* state, /* Real */ ae_matrix* a, ae_bool isupper, double s, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t n; double v; ae_int_t j0; ae_int_t j1; n = state->n; state->akind = 0; cqmseta(&state->a, a, isupper, 1.0, _state); if( ae_fp_greater(s,(double)(0)) ) { rvectorsetlengthatleast(&state->tmp0, n, _state); for(i=0; i<=n-1; i++) { state->tmp0.ptr.p_double[i] = a->ptr.pp_double[i][i]+s; } cqmrewritedensediagonal(&state->a, &state->tmp0, _state); } /* * Estimate norm of A * (it will be used later in the quadratic penalty function) */ state->absamax = (double)(0); state->absasum = (double)(0); state->absasum2 = (double)(0); for(i=0; i<=n-1; i++) { if( isupper ) { j0 = i; j1 = n-1; } else { j0 = 0; j1 = i; } for(j=j0; j<=j1; j++) { v = ae_fabs(a->ptr.pp_double[i][j], _state); state->absamax = ae_maxreal(state->absamax, v, _state); state->absasum = state->absasum+v; state->absasum2 = state->absasum2+v*v; } } } /************************************************************************* Internal function which allows to rewrite diagonal of quadratic term. For internal use only. This function can be used only when you have dense A and already made MinQPSetQuadraticTerm(Fast) call. -- ALGLIB -- Copyright 16.01.2011 by Bochkanov Sergey *************************************************************************/ void minqprewritediagonal(minqpstate* state, /* Real */ ae_vector* s, ae_state *_state) { cqmrewritedensediagonal(&state->a, s, _state); } /************************************************************************* Fast version of MinQPSetStartingPoint(), which doesn't check its arguments. For internal use only. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetstartingpointfast(minqpstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; n = state->n; ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); state->havex = ae_true; } /************************************************************************* Fast version of MinQPSetOrigin(), which doesn't check its arguments. For internal use only. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/ void minqpsetoriginfast(minqpstate* state, /* Real */ ae_vector* xorigin, ae_state *_state) { ae_int_t n; n = state->n; ae_v_move(&state->xorigin.ptr.p_double[0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1)); } void _minqpstate_init(void* _p, ae_state *_state) { minqpstate *p = (minqpstate*)_p; ae_touch_ptr((void*)p); _qqpsettings_init(&p->qqpsettingsuser, _state); _qqpsettings_init(&p->qqpsettingscurrent, _state); _qpbleicsettings_init(&p->qpbleicsettingsuser, _state); _qpbleicsettings_init(&p->qpbleicsettingscurrent, _state); _convexquadraticmodel_init(&p->a, _state); _sparsematrix_init(&p->sparsea, _state); ae_vector_init(&p->b, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->havebndl, 0, DT_BOOL, _state); ae_vector_init(&p->havebndu, 0, DT_BOOL, _state); ae_vector_init(&p->xorigin, 0, DT_REAL, _state); ae_vector_init(&p->startx, 0, DT_REAL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->xs, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); _qpbleicbuffers_init(&p->qpbleicbuf, _state); _qqpbuffers_init(&p->qqpbuf, _state); _qpcholeskybuffers_init(&p->qpcholeskybuf, _state); _normestimatorstate_init(&p->estimator, _state); } void _minqpstate_init_copy(void* _dst, void* _src, ae_state *_state) { minqpstate *dst = (minqpstate*)_dst; minqpstate *src = (minqpstate*)_src; dst->n = src->n; _qqpsettings_init_copy(&dst->qqpsettingsuser, &src->qqpsettingsuser, _state); _qqpsettings_init_copy(&dst->qqpsettingscurrent, &src->qqpsettingscurrent, _state); _qpbleicsettings_init_copy(&dst->qpbleicsettingsuser, &src->qpbleicsettingsuser, _state); _qpbleicsettings_init_copy(&dst->qpbleicsettingscurrent, &src->qpbleicsettingscurrent, _state); dst->algokind = src->algokind; dst->akind = src->akind; _convexquadraticmodel_init_copy(&dst->a, &src->a, _state); _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state); dst->sparseaupper = src->sparseaupper; dst->absamax = src->absamax; dst->absasum = src->absasum; dst->absasum2 = src->absasum2; ae_vector_init_copy(&dst->b, &src->b, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_vector_init_copy(&dst->s, &src->s, _state); ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state); ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state); ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state); ae_vector_init_copy(&dst->startx, &src->startx, _state); dst->havex = src->havex; ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); dst->nec = src->nec; dst->nic = src->nic; ae_vector_init_copy(&dst->xs, &src->xs, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repncholesky = src->repncholesky; dst->repnmv = src->repnmv; dst->repterminationtype = src->repterminationtype; ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); dst->qpbleicfirstcall = src->qpbleicfirstcall; _qpbleicbuffers_init_copy(&dst->qpbleicbuf, &src->qpbleicbuf, _state); _qqpbuffers_init_copy(&dst->qqpbuf, &src->qqpbuf, _state); _qpcholeskybuffers_init_copy(&dst->qpcholeskybuf, &src->qpcholeskybuf, _state); _normestimatorstate_init_copy(&dst->estimator, &src->estimator, _state); } void _minqpstate_clear(void* _p) { minqpstate *p = (minqpstate*)_p; ae_touch_ptr((void*)p); _qqpsettings_clear(&p->qqpsettingsuser); _qqpsettings_clear(&p->qqpsettingscurrent); _qpbleicsettings_clear(&p->qpbleicsettingsuser); _qpbleicsettings_clear(&p->qpbleicsettingscurrent); _convexquadraticmodel_clear(&p->a); _sparsematrix_clear(&p->sparsea); ae_vector_clear(&p->b); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->s); ae_vector_clear(&p->havebndl); ae_vector_clear(&p->havebndu); ae_vector_clear(&p->xorigin); ae_vector_clear(&p->startx); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->xs); ae_vector_clear(&p->tmp0); _qpbleicbuffers_clear(&p->qpbleicbuf); _qqpbuffers_clear(&p->qqpbuf); _qpcholeskybuffers_clear(&p->qpcholeskybuf); _normestimatorstate_clear(&p->estimator); } void _minqpstate_destroy(void* _p) { minqpstate *p = (minqpstate*)_p; ae_touch_ptr((void*)p); _qqpsettings_destroy(&p->qqpsettingsuser); _qqpsettings_destroy(&p->qqpsettingscurrent); _qpbleicsettings_destroy(&p->qpbleicsettingsuser); _qpbleicsettings_destroy(&p->qpbleicsettingscurrent); _convexquadraticmodel_destroy(&p->a); _sparsematrix_destroy(&p->sparsea); ae_vector_destroy(&p->b); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->s); ae_vector_destroy(&p->havebndl); ae_vector_destroy(&p->havebndu); ae_vector_destroy(&p->xorigin); ae_vector_destroy(&p->startx); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->xs); ae_vector_destroy(&p->tmp0); _qpbleicbuffers_destroy(&p->qpbleicbuf); _qqpbuffers_destroy(&p->qqpbuf); _qpcholeskybuffers_destroy(&p->qpcholeskybuf); _normestimatorstate_destroy(&p->estimator); } void _minqpreport_init(void* _p, ae_state *_state) { minqpreport *p = (minqpreport*)_p; ae_touch_ptr((void*)p); } void _minqpreport_init_copy(void* _dst, void* _src, ae_state *_state) { minqpreport *dst = (minqpreport*)_dst; minqpreport *src = (minqpreport*)_src; dst->inneriterationscount = src->inneriterationscount; dst->outeriterationscount = src->outeriterationscount; dst->nmv = src->nmv; dst->ncholesky = src->ncholesky; dst->terminationtype = src->terminationtype; } void _minqpreport_clear(void* _p) { minqpreport *p = (minqpreport*)_p; ae_touch_ptr((void*)p); } void _minqpreport_destroy(void* _p) { minqpreport *p = (minqpreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] and Jacobian of f[]. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X * function vector f[] and Jacobian of f[] (simultaneously) at given point There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() and jac() callbacks. First one is used to calculate f[] at given point, second one calculates f[] and Jacobian df[i]/dx[j]. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not provide Jacobian), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateVJ() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); ae_assert(n>=1, "MinLMCreateVJ: N<1!", _state); ae_assert(m>=1, "MinLMCreateVJ: M<1!", _state); ae_assert(x->cnt>=n, "MinLMCreateVJ: Length(X)teststep = (double)(0); state->n = n; state->m = m; state->algomode = 1; state->hasf = ae_false; state->hasfi = ae_true; state->hasg = ae_false; /* * second stage of initialization */ minlm_lmprepare(n, m, ae_false, state, _state); minlmsetacctype(state, 0, _state); minlmsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minlmsetxrep(state, ae_false, _state); minlmsetstpmax(state, (double)(0), _state); minlmrestartfrom(state, x, _state); } /************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] only. Finite differences are used to calculate Jacobian. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() callback. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not accept function vector), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateV() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state See also MinLMIteration, MinLMResults. NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatev(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, double diffstep, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); ae_assert(ae_isfinite(diffstep, _state), "MinLMCreateV: DiffStep is not finite!", _state); ae_assert(ae_fp_greater(diffstep,(double)(0)), "MinLMCreateV: DiffStep<=0!", _state); ae_assert(n>=1, "MinLMCreateV: N<1!", _state); ae_assert(m>=1, "MinLMCreateV: M<1!", _state); ae_assert(x->cnt>=n, "MinLMCreateV: Length(X)teststep = (double)(0); state->n = n; state->m = m; state->algomode = 0; state->hasf = ae_false; state->hasfi = ae_true; state->hasg = ae_false; state->diffstep = diffstep; /* * Second stage of initialization */ minlm_lmprepare(n, m, ae_false, state, _state); minlmsetacctype(state, 1, _state); minlmsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minlmsetxrep(state, ae_false, _state); minlmsetstpmax(state, (double)(0), _state); minlmrestartfrom(state, x, _state); } /************************************************************************* LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION DESCRIPTION: This function is used to find minimum of general form (not "sum-of- -squares") function F = F(x[0], ..., x[n-1]) using its gradient and Hessian. Levenberg-Marquardt modification with L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step is used. REQUIREMENTS: This algorithm will request following information during its operation: * function value F at given point X * F and gradient G (simultaneously) at given point X * F, G and Hessian H (simultaneously) at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts func(), grad() and hess() function pointers. First pointer is used to calculate F at given point, second one calculates F(x) and grad F(x), third one calculates F(x), grad F(x), hess F(x). You can try to initialize MinLMState structure with FGH-function and then use incorrect version of MinLMOptimize() (for example, version which does not provide Hessian matrix), but it will lead to exception being thrown after first attempt to calculate Hessian. USAGE: 1. User initializes algorithm state with MinLMCreateFGH() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and pointers (delegates, etc.) to callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgh(ae_int_t n, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); ae_assert(n>=1, "MinLMCreateFGH: N<1!", _state); ae_assert(x->cnt>=n, "MinLMCreateFGH: Length(X)teststep = (double)(0); state->n = n; state->m = 0; state->algomode = 2; state->hasf = ae_true; state->hasfi = ae_false; state->hasg = ae_true; /* * init2 */ minlm_lmprepare(n, 0, ae_true, state, _state); minlmsetacctype(state, 2, _state); minlmsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minlmsetxrep(state, ae_false, _state); minlmsetstpmax(state, (double)(0), _state); minlmrestartfrom(state, x, _state); } /************************************************************************* This function sets stopping conditions for Levenberg-Marquardt optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLMSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetcond(minlmstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinLMSetCond: EpsG is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinLMSetCond: negative EpsG!", _state); ae_assert(ae_isfinite(epsf, _state), "MinLMSetCond: EpsF is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinLMSetCond: negative EpsF!", _state); ae_assert(ae_isfinite(epsx, _state), "MinLMSetCond: EpsX is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinLMSetCond: negative EpsX!", _state); ae_assert(maxits>=0, "MinLMSetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS iterations are reported. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "MinLMSetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinLMSetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* This function sets scaling coefficients for LM optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetscale(minlmstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->n, "MinLMSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLMSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinLMSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function sets boundary constraints for LM optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints or at its boundary -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ void minlmsetbc(minlmstate* state, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_int_t i; ae_int_t n; n = state->n; ae_assert(bndl->cnt>=n, "MinLMSetBC: Length(BndL)cnt>=n, "MinLMSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLMSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLMSetBC: BndU contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } } /************************************************************************* This function is used to change acceleration settings You can choose between three acceleration strategies: * AccType=0, no acceleration. * AccType=1, secant updates are used to update quadratic model after each iteration. After fixed number of iterations (or after model breakdown) we recalculate quadratic model using analytic Jacobian or finite differences. Number of secant-based iterations depends on optimization settings: about 3 iterations - when we have analytic Jacobian, up to 2*N iterations - when we use finite differences to calculate Jacobian. AccType=1 is recommended when Jacobian calculation cost is prohibitive high (several Mx1 function vector calculations followed by several NxN Cholesky factorizations are faster than calculation of one M*N Jacobian). It should also be used when we have no Jacobian, because finite difference approximation takes too much time to compute. Table below list optimization protocols (XYZ protocol corresponds to MinLMCreateXYZ) and acceleration types they support (and use by default). ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: protocol 0 1 comment V + + VJ + + FGH + DAFAULT VALUES: protocol 0 1 comment V x without acceleration it is so slooooooooow VJ x FGH x NOTE: this function should be called before optimization. Attempt to call it during algorithm iterations may result in unexpected behavior. NOTE: attempt to call this function with unsupported protocol/acceleration combination will result in exception being thrown. -- ALGLIB -- Copyright 14.10.2010 by Bochkanov Sergey *************************************************************************/ void minlmsetacctype(minlmstate* state, ae_int_t acctype, ae_state *_state) { ae_assert((acctype==0||acctype==1)||acctype==2, "MinLMSetAccType: incorrect AccType!", _state); if( acctype==2 ) { acctype = 0; } if( acctype==0 ) { state->maxmodelage = 0; state->makeadditers = ae_false; return; } if( acctype==1 ) { ae_assert(state->hasfi, "MinLMSetAccType: AccType=1 is incompatible with current protocol!", _state); if( state->algomode==0 ) { state->maxmodelage = 2*state->n; } else { state->maxmodelage = minlm_smallmodelage; } state->makeadditers = ae_false; return; } } /************************************************************************* NOTES: 1. Depending on function used to create state structure, this algorithm may accept Jacobian and/or Hessian and/or gradient. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with MinLMCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ ae_bool minlmiteration(minlmstate* state, ae_state *_state) { ae_int_t n; ae_int_t m; ae_bool bflag; ae_int_t iflag; double v; double s; double t; ae_int_t i; ae_int_t k; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; m = state->rstate.ia.ptr.p_int[1]; iflag = state->rstate.ia.ptr.p_int[2]; i = state->rstate.ia.ptr.p_int[3]; k = state->rstate.ia.ptr.p_int[4]; bflag = state->rstate.ba.ptr.p_bool[0]; v = state->rstate.ra.ptr.p_double[0]; s = state->rstate.ra.ptr.p_double[1]; t = state->rstate.ra.ptr.p_double[2]; } else { n = -983; m = -989; iflag = -834; i = 900; k = -287; bflag = ae_false; v = 214; s = -338; t = -686; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } if( state->rstate.stage==14 ) { goto lbl_14; } if( state->rstate.stage==15 ) { goto lbl_15; } if( state->rstate.stage==16 ) { goto lbl_16; } if( state->rstate.stage==17 ) { goto lbl_17; } if( state->rstate.stage==18 ) { goto lbl_18; } /* * Routine body */ /* * prepare */ n = state->n; m = state->m; state->repiterationscount = 0; state->repterminationtype = 0; state->repfuncidx = -1; state->repvaridx = -1; state->repnfunc = 0; state->repnjac = 0; state->repngrad = 0; state->repnhess = 0; state->repncholesky = 0; state->userterminationneeded = ae_false; /* * check consistency of constraints, * enforce feasibility of the solution * set constraints */ if( !enforceboundaryconstraints(&state->xbase, &state->bndl, &state->havebndl, &state->bndu, &state->havebndu, n, 0, _state) ) { state->repterminationtype = -3; result = ae_false; return result; } minqpsetbc(&state->qpstate, &state->bndl, &state->bndu, _state); /* * Check, that transferred derivative value is right */ minlm_clearrequestfields(state, _state); if( !(state->algomode==1&&ae_fp_greater(state->teststep,(double)(0))) ) { goto lbl_19; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->needfij = ae_true; i = 0; lbl_21: if( i>n-1 ) { goto lbl_23; } ae_assert((state->havebndl.ptr.p_bool[i]&&ae_fp_less_eq(state->bndl.ptr.p_double[i],state->x.ptr.p_double[i]))||!state->havebndl.ptr.p_bool[i], "MinLM: internal error(State.X is out of bounds)", _state); ae_assert((state->havebndu.ptr.p_bool[i]&&ae_fp_less_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]))||!state->havebndu.ptr.p_bool[i], "MinLMIteration: internal error(State.X is out of bounds)", _state); v = state->x.ptr.p_double[i]; state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; if( state->havebndl.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } state->xm1 = state->x.ptr.p_double[i]; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_move(&state->gm1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; if( state->havebndu.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } state->xp1 = state->x.ptr.p_double[i]; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_move(&state->gp1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); state->x.ptr.p_double[i] = (state->xm1+state->xp1)/2; if( state->havebndl.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); } if( state->havebndu.ptr.p_bool[i] ) { state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } state->rstate.stage = 2; goto lbl_rcomm; lbl_2: ae_v_move(&state->fc1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_move(&state->gc1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); state->x.ptr.p_double[i] = v; for(k=0; k<=m-1; k++) { if( !derivativecheck(state->fm1.ptr.p_double[k], state->gm1.ptr.p_double[k], state->fp1.ptr.p_double[k], state->gp1.ptr.p_double[k], state->fc1.ptr.p_double[k], state->gc1.ptr.p_double[k], state->xp1-state->xm1, _state) ) { state->repfuncidx = k; state->repvaridx = i; state->repterminationtype = -7; result = ae_false; return result; } } i = i+1; goto lbl_21; lbl_23: state->needfij = ae_false; lbl_19: /* * Initial report of current point * * Note 1: we rewrite State.X twice because * user may accidentally change it after first call. * * Note 2: we set NeedF or NeedFI depending on what * information about function we have. */ if( !state->xrep ) { goto lbl_24; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); if( !state->hasf ) { goto lbl_26; } state->needf = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needf = ae_false; goto lbl_27; lbl_26: ae_assert(state->hasfi, "MinLM: internal error 2!", _state); state->needfi = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->needfi = ae_false; v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->f = v; lbl_27: state->repnfunc = state->repnfunc+1; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->xupdated = ae_false; lbl_24: if( state->userterminationneeded ) { /* * User requested termination */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } /* * Prepare control variables */ state->nu = (double)(1); state->lambdav = -ae_maxrealnumber; state->modelage = state->maxmodelage+1; state->deltaxready = ae_false; state->deltafready = ae_false; /* * Main cycle. * * We move through it until either: * * one of the stopping conditions is met * * we decide that stopping conditions are too stringent * and break from cycle * */ lbl_28: if( ae_false ) { goto lbl_29; } /* * First, we have to prepare quadratic model for our function. * We use BFlag to ensure that model is prepared; * if it is false at the end of this block, something went wrong. * * We may either calculate brand new model or update old one. * * Before this block we have: * * State.XBase - current position. * * State.DeltaX - if DeltaXReady is True * * State.DeltaF - if DeltaFReady is True * * After this block is over, we will have: * * State.XBase - base point (unchanged) * * State.FBase - F(XBase) * * State.GBase - linear term * * State.QuadraticModel - quadratic term * * State.LambdaV - current estimate for lambda * * We also clear DeltaXReady/DeltaFReady flags * after initialization is done. */ bflag = ae_false; if( !(state->algomode==0||state->algomode==1) ) { goto lbl_30; } /* * Calculate f[] and Jacobian */ if( !(state->modelage>state->maxmodelage||!(state->deltaxready&&state->deltafready)) ) { goto lbl_32; } /* * Refresh model (using either finite differences or analytic Jacobian) */ if( state->algomode!=0 ) { goto lbl_34; } /* * Optimization using F values only. * Use finite differences to estimate Jacobian. */ ae_assert(state->hasfi, "MinLMIteration: internal error when estimating Jacobian (no f[])", _state); k = 0; lbl_36: if( k>n-1 ) { goto lbl_38; } /* * We guard X[k] from leaving [BndL,BndU]. * In case BndL=BndU, we assume that derivative in this direction is zero. */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; if( state->havebndl.ptr.p_bool[k] ) { state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); } if( state->havebndu.ptr.p_bool[k] ) { state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); } state->xm1 = state->x.ptr.p_double[k]; minlm_clearrequestfields(state, _state); state->needfi = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->repnfunc = state->repnfunc+1; ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; if( state->havebndl.ptr.p_bool[k] ) { state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); } if( state->havebndu.ptr.p_bool[k] ) { state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); } state->xp1 = state->x.ptr.p_double[k]; minlm_clearrequestfields(state, _state); state->needfi = ae_true; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->repnfunc = state->repnfunc+1; ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); v = state->xp1-state->xm1; if( ae_fp_neq(v,(double)(0)) ) { v = 1/v; ae_v_moved(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); ae_v_subd(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); } else { for(i=0; i<=m-1; i++) { state->j.ptr.pp_double[i][k] = (double)(0); } } k = k+1; goto lbl_36; lbl_38: /* * Calculate F(XBase) */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->needfi = ae_true; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->needfi = ae_false; state->repnfunc = state->repnfunc+1; state->repnjac = state->repnjac+1; /* * New model */ state->modelage = 0; goto lbl_35; lbl_34: /* * Obtain f[] and Jacobian */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->needfij = ae_true; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->needfij = ae_false; state->repnfunc = state->repnfunc+1; state->repnjac = state->repnjac+1; /* * New model */ state->modelage = 0; lbl_35: goto lbl_33; lbl_32: /* * State.J contains Jacobian or its current approximation; * refresh it using secant updates: * * f(x0+dx) = f(x0) + J*dx, * J_new = J_old + u*h' * h = x_new-x_old * u = (f_new - f_old - J_old*h)/(h'h) * * We can explicitly generate h and u, but it is * preferential to do in-place calculations. Only * I-th row of J_old is needed to calculate u[I], * so we can update J row by row in one pass. * * NOTE: we expect that State.XBase contains new point, * State.FBase contains old point, State.DeltaX and * State.DeltaY contain updates from last step. */ ae_assert(state->deltaxready&&state->deltafready, "MinLMIteration: uninitialized DeltaX/DeltaF", _state); t = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_assert(ae_fp_neq(t,(double)(0)), "MinLM: internal error (T=0)", _state); for(i=0; i<=m-1; i++) { v = ae_v_dotproduct(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = (state->deltaf.ptr.p_double[i]-v)/t; ae_v_addd(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1), v); } ae_v_move(&state->fi.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_add(&state->fi.ptr.p_double[0], 1, &state->deltaf.ptr.p_double[0], 1, ae_v_len(0,m-1)); /* * Increase model age */ state->modelage = state->modelage+1; lbl_33: /* * Generate quadratic model: * f(xbase+dx) = * = (f0 + J*dx)'(f0 + J*dx) * = f0^2 + dx'J'f0 + f0*J*dx + dx'J'J*dx * = f0^2 + 2*f0*J*dx + dx'J'J*dx * * Note that we calculate 2*(J'J) instead of J'J because * our quadratic model is based on Tailor decomposition, * i.e. it has 0.5 before quadratic term. */ rmatrixgemm(n, n, m, 2.0, &state->j, 0, 0, 1, &state->j, 0, 0, 0, 0.0, &state->quadraticmodel, 0, 0, _state); rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->gbase, 0, _state); ae_v_muld(&state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1), 2); v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->fbase = v; ae_v_move(&state->fibase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); /* * set control variables */ bflag = ae_true; lbl_30: if( state->algomode!=2 ) { goto lbl_39; } ae_assert(!state->hasfi, "MinLMIteration: internal error (HasFI is True in Hessian-based mode)", _state); /* * Obtain F, G, H */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->needfgh = ae_true; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->needfgh = ae_false; state->repnfunc = state->repnfunc+1; state->repngrad = state->repngrad+1; state->repnhess = state->repnhess+1; rmatrixcopy(n, n, &state->h, 0, 0, &state->quadraticmodel, 0, 0, _state); ae_v_move(&state->gbase.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->fbase = state->f; /* * set control variables */ bflag = ae_true; state->modelage = 0; lbl_39: ae_assert(bflag, "MinLM: internal integrity check failed!", _state); state->deltaxready = ae_false; state->deltafready = ae_false; /* * If Lambda is not initialized, initialize it using quadratic model */ if( ae_fp_less(state->lambdav,(double)(0)) ) { state->lambdav = (double)(0); for(i=0; i<=n-1; i++) { state->lambdav = ae_maxreal(state->lambdav, ae_fabs(state->quadraticmodel.ptr.pp_double[i][i], _state)*ae_sqr(state->s.ptr.p_double[i], _state), _state); } state->lambdav = 0.001*state->lambdav; if( ae_fp_eq(state->lambdav,(double)(0)) ) { state->lambdav = (double)(1); } } /* * Test stopping conditions for function gradient */ if( ae_fp_greater(minlm_boundedscaledantigradnorm(state, &state->xbase, &state->gbase, _state),state->epsg) ) { goto lbl_41; } if( state->modelage!=0 ) { goto lbl_43; } /* * Model is fresh, we can rely on it and terminate algorithm */ state->repterminationtype = 4; if( !state->xrep ) { goto lbl_45; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 11; goto lbl_rcomm; lbl_11: state->xupdated = ae_false; lbl_45: result = ae_false; return result; goto lbl_44; lbl_43: /* * Model is not fresh, we should refresh it and test * conditions once more */ state->modelage = state->maxmodelage+1; goto lbl_28; lbl_44: lbl_41: /* * Find value of Levenberg-Marquardt damping parameter which: * * leads to positive definite damped model * * within bounds specified by StpMax * * generates step which decreases function value * * After this block IFlag is set to: * * -3, if constraints are infeasible * * -2, if model update is needed (either Lambda growth is too large * or step is too short, but we can't rely on model and stop iterations) * * -1, if model is fresh, Lambda have grown too large, termination is needed * * 0, if everything is OK, continue iterations * * State.Nu can have any value on enter, but after exit it is set to 1.0 */ iflag = -99; lbl_47: if( ae_false ) { goto lbl_48; } /* * Do we need model update? */ if( state->modelage>0&&ae_fp_greater_eq(state->nu,minlm_suspiciousnu) ) { iflag = -2; goto lbl_48; } /* * Setup quadratic solver and solve quadratic programming problem. * After problem is solved we'll try to bound step by StpMax * (Lambda will be increased if step size is too large). * * We use BFlag variable to indicate that we have to increase Lambda. * If it is False, we will try to increase Lambda and move to new iteration. */ bflag = ae_true; minqpsetstartingpointfast(&state->qpstate, &state->xbase, _state); minqpsetoriginfast(&state->qpstate, &state->xbase, _state); minqpsetlineartermfast(&state->qpstate, &state->gbase, _state); minqpsetquadratictermfast(&state->qpstate, &state->quadraticmodel, ae_true, 0.0, _state); for(i=0; i<=n-1; i++) { state->tmp0.ptr.p_double[i] = state->quadraticmodel.ptr.pp_double[i][i]+state->lambdav/ae_sqr(state->s.ptr.p_double[i], _state); } minqprewritediagonal(&state->qpstate, &state->tmp0, _state); minqpoptimize(&state->qpstate, _state); minqpresultsbuf(&state->qpstate, &state->xdir, &state->qprep, _state); if( state->qprep.terminationtype>0 ) { /* * successful solution of QP problem */ ae_v_sub(&state->xdir.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&state->xdir.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_isfinite(v, _state) ) { v = ae_sqrt(v, _state); if( ae_fp_greater(state->stpmax,(double)(0))&&ae_fp_greater(v,state->stpmax) ) { bflag = ae_false; } } else { bflag = ae_false; } } else { /* * Either problem is non-convex (increase LambdaV) or constraints are inconsistent */ ae_assert(state->qprep.terminationtype==-3||state->qprep.terminationtype==-5, "MinLM: unexpected completion code from QP solver", _state); if( state->qprep.terminationtype==-3 ) { iflag = -3; goto lbl_48; } bflag = ae_false; } if( !bflag ) { /* * Solution failed: * try to increase lambda to make matrix positive definite and continue. */ if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) ) { iflag = -1; goto lbl_48; } goto lbl_47; } /* * Step in State.XDir and it is bounded by StpMax. * * We should check stopping conditions on step size here. * DeltaX, which is used for secant updates, is initialized here. * * This code is a bit tricky because sometimes XDir<>0, but * it is so small that XDir+XBase==XBase (in finite precision * arithmetics). So we set DeltaX to XBase, then * add XDir, and then subtract XBase to get exact value of * DeltaX. * * Step length is estimated using DeltaX. * * NOTE: stopping conditions are tested * for fresh models only (ModelAge=0) */ ae_v_move(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&state->deltax.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_sub(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->deltaxready = ae_true; v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->deltax.ptr.p_double[i]/state->s.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); if( ae_fp_greater(v,state->epsx) ) { goto lbl_49; } if( state->modelage!=0 ) { goto lbl_51; } /* * Step is too short, model is fresh and we can rely on it. * Terminating. */ state->repterminationtype = 2; if( !state->xrep ) { goto lbl_53; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 12; goto lbl_rcomm; lbl_12: state->xupdated = ae_false; lbl_53: result = ae_false; return result; goto lbl_52; lbl_51: /* * Step is suspiciously short, but model is not fresh * and we can't rely on it. */ iflag = -2; goto lbl_48; lbl_52: lbl_49: /* * Let's evaluate new step: * a) if we have Fi vector, we evaluate it using rcomm, and * then we manually calculate State.F as sum of squares of Fi[] * b) if we have F value, we just evaluate it through rcomm interface * * We prefer (a) because we may need Fi vector for additional * iterations */ ae_assert(state->hasfi||state->hasf, "MinLM: internal error 2!", _state); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&state->x.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); if( !state->hasfi ) { goto lbl_55; } state->needfi = ae_true; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->needfi = ae_false; v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->f = v; ae_v_move(&state->deltaf.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_sub(&state->deltaf.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->deltafready = ae_true; goto lbl_56; lbl_55: state->needf = ae_true; state->rstate.stage = 14; goto lbl_rcomm; lbl_14: state->needf = ae_false; lbl_56: state->repnfunc = state->repnfunc+1; if( ae_fp_greater_eq(state->f,state->fbase) ) { /* * Increase lambda and continue */ if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) ) { iflag = -1; goto lbl_48; } goto lbl_47; } /* * We've found our step! */ iflag = 0; goto lbl_48; goto lbl_47; lbl_48: if( state->userterminationneeded ) { /* * User requested termination */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repterminationtype = 8; result = ae_false; return result; } state->nu = (double)(1); ae_assert(iflag>=-3&&iflag<=0, "MinLM: internal integrity check failed!", _state); if( iflag==-3 ) { state->repterminationtype = -3; result = ae_false; return result; } if( iflag==-2 ) { state->modelage = state->maxmodelage+1; goto lbl_28; } if( iflag==-1 ) { goto lbl_29; } /* * Levenberg-Marquardt step is ready. * Compare predicted vs. actual decrease and decide what to do with lambda. * * NOTE: we expect that State.DeltaX contains direction of step, * State.F contains function value at new point. */ ae_assert(state->deltaxready, "MinLM: deltaX is not ready", _state); t = (double)(0); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&state->quadraticmodel.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); t = t+state->deltax.ptr.p_double[i]*state->gbase.ptr.p_double[i]+0.5*state->deltax.ptr.p_double[i]*v; } state->predicteddecrease = -t; state->actualdecrease = -(state->f-state->fbase); if( ae_fp_less_eq(state->predicteddecrease,(double)(0)) ) { goto lbl_29; } v = state->actualdecrease/state->predicteddecrease; if( ae_fp_greater_eq(v,0.1) ) { goto lbl_57; } if( minlm_increaselambda(&state->lambdav, &state->nu, _state) ) { goto lbl_59; } /* * Lambda is too large, we have to break iterations. */ state->repterminationtype = 7; if( !state->xrep ) { goto lbl_61; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 15; goto lbl_rcomm; lbl_15: state->xupdated = ae_false; lbl_61: result = ae_false; return result; lbl_59: lbl_57: if( ae_fp_greater(v,0.5) ) { minlm_decreaselambda(&state->lambdav, &state->nu, _state); } /* * Accept step, report it and * test stopping conditions on iterations count and function decrease. * * NOTE: we expect that State.DeltaX contains direction of step, * State.F contains function value at new point. * * NOTE2: we should update XBase ONLY. In the beginning of the next * iteration we expect that State.FIBase is NOT updated and * contains old value of a function vector. */ ae_v_add(&state->xbase.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( !state->xrep ) { goto lbl_63; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 16; goto lbl_rcomm; lbl_16: state->xupdated = ae_false; lbl_63: state->repiterationscount = state->repiterationscount+1; if( state->repiterationscount>=state->maxits&&state->maxits>0 ) { state->repterminationtype = 5; } if( state->modelage==0 ) { if( ae_fp_less_eq(ae_fabs(state->f-state->fbase, _state),state->epsf*ae_maxreal((double)(1), ae_maxreal(ae_fabs(state->f, _state), ae_fabs(state->fbase, _state), _state), _state)) ) { state->repterminationtype = 1; } } if( state->repterminationtype<=0 ) { goto lbl_65; } if( !state->xrep ) { goto lbl_67; } /* * Report: XBase contains new point, F contains function value at new point */ ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 17; goto lbl_rcomm; lbl_17: state->xupdated = ae_false; lbl_67: result = ae_false; return result; lbl_65: state->modelage = state->modelage+1; goto lbl_28; lbl_29: /* * Lambda is too large, we have to break iterations. */ state->repterminationtype = 7; if( !state->xrep ) { goto lbl_69; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->fbase; minlm_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 18; goto lbl_rcomm; lbl_18: state->xupdated = ae_false; lbl_69: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = m; state->rstate.ia.ptr.p_int[2] = iflag; state->rstate.ia.ptr.p_int[3] = i; state->rstate.ia.ptr.p_int[4] = k; state->rstate.ba.ptr.p_bool[0] = bflag; state->rstate.ra.ptr.p_double[0] = v; state->rstate.ra.ptr.p_double[1] = s; state->rstate.ra.ptr.p_double[2] = t; return result; } /************************************************************************* Levenberg-Marquardt algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report; includes termination codes and additional information. Termination codes are listed below, see comments for this structure for more info. Termination code is stored in rep.terminationtype field: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlmrequesttermination(). X contains point which was "current accepted" when termination request was submitted. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresults(minlmstate* state, /* Real */ ae_vector* x, minlmreport* rep, ae_state *_state) { ae_vector_clear(x); _minlmreport_clear(rep); minlmresultsbuf(state, x, rep, _state); } /************************************************************************* Levenberg-Marquardt algorithm results Buffered implementation of MinLMResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmresultsbuf(minlmstate* state, /* Real */ ae_vector* x, minlmreport* rep, ae_state *_state) { if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->terminationtype = state->repterminationtype; rep->funcidx = state->repfuncidx; rep->varidx = state->repvaridx; rep->nfunc = state->repnfunc; rep->njac = state->repnjac; rep->ngrad = state->repngrad; rep->nhess = state->repnhess; rep->ncholesky = state->repncholesky; } /************************************************************************* This subroutine restarts LM algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinLMCreateXXX call. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minlmrestartfrom(minlmstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_assert(x->cnt>=state->n, "MinLMRestartFrom: Length(X)n, _state), "MinLMRestartFrom: X contains infinite or NaN values!", _state); ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_vector_set_length(&state->rstate.ia, 4+1, _state); ae_vector_set_length(&state->rstate.ba, 0+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; minlm_clearrequestfields(state, _state); } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/ void minlmrequesttermination(minlmstate* state, ae_state *_state) { state->userterminationneeded = ae_true; } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatevgj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); minlmcreatevj(n, m, x, state, _state); } /************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefgj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); minlmcreatefj(n, m, x, state, _state); } /************************************************************************* This function is considered obsolete since ALGLIB 3.1.0 and is present for backward compatibility only. We recommend to use MinLMCreateVJ, which provides similar, but more consistent and feature-rich interface. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/ void minlmcreatefj(ae_int_t n, ae_int_t m, /* Real */ ae_vector* x, minlmstate* state, ae_state *_state) { _minlmstate_clear(state); ae_assert(n>=1, "MinLMCreateFJ: N<1!", _state); ae_assert(m>=1, "MinLMCreateFJ: M<1!", _state); ae_assert(x->cnt>=n, "MinLMCreateFJ: Length(X)teststep = (double)(0); state->n = n; state->m = m; state->algomode = 1; state->hasf = ae_true; state->hasfi = ae_false; state->hasg = ae_false; /* * init 2 */ minlm_lmprepare(n, m, ae_true, state, _state); minlmsetacctype(state, 0, _state); minlmsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minlmsetxrep(state, ae_false, _state); minlmsetstpmax(state, (double)(0), _state); minlmrestartfrom(state, x, _state); } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLMOptimize() is called * prior to actual optimization, for each function Fi and each component of parameters being optimized X[j] algorithm performs following steps: * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], where X[j] is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on X[] * Fi(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) Jacobian evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLMSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ void minlmsetgradientcheck(minlmstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "MinLMSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinLMSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Prepare internal structures (except for RComm). Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode. *************************************************************************/ static void minlm_lmprepare(ae_int_t n, ae_int_t m, ae_bool havegrad, minlmstate* state, ae_state *_state) { ae_int_t i; if( n<=0||m<0 ) { return; } if( havegrad ) { ae_vector_set_length(&state->g, n, _state); } if( m!=0 ) { ae_matrix_set_length(&state->j, m, n, _state); ae_vector_set_length(&state->fi, m, _state); ae_vector_set_length(&state->fibase, m, _state); ae_vector_set_length(&state->deltaf, m, _state); ae_vector_set_length(&state->fm1, m, _state); ae_vector_set_length(&state->fp1, m, _state); ae_vector_set_length(&state->fc1, m, _state); ae_vector_set_length(&state->gm1, m, _state); ae_vector_set_length(&state->gp1, m, _state); ae_vector_set_length(&state->gc1, m, _state); } else { ae_matrix_set_length(&state->h, n, n, _state); } ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->deltax, n, _state); ae_matrix_set_length(&state->quadraticmodel, n, n, _state); ae_vector_set_length(&state->xbase, n, _state); ae_vector_set_length(&state->gbase, n, _state); ae_vector_set_length(&state->xdir, n, _state); ae_vector_set_length(&state->tmp0, n, _state); /* * prepare internal L-BFGS */ for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = (double)(0); } minlbfgscreate(n, ae_minint(minlm_additers, n, _state), &state->x, &state->internalstate, _state); minlbfgssetcond(&state->internalstate, 0.0, 0.0, 0.0, ae_minint(minlm_additers, n, _state), _state); /* * Prepare internal QP solver */ minqpcreate(n, &state->qpstate, _state); minqpsetalgocholesky(&state->qpstate, _state); /* * Prepare boundary constraints */ ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->havebndl, n, _state); ae_vector_set_length(&state->havebndu, n, _state); for(i=0; i<=n-1; i++) { state->bndl.ptr.p_double[i] = _state->v_neginf; state->havebndl.ptr.p_bool[i] = ae_false; state->bndu.ptr.p_double[i] = _state->v_posinf; state->havebndu.ptr.p_bool[i] = ae_false; } /* * Prepare scaling matrix */ ae_vector_set_length(&state->s, n, _state); for(i=0; i<=n-1; i++) { state->s.ptr.p_double[i] = 1.0; } } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void minlm_clearrequestfields(minlmstate* state, ae_state *_state) { state->needf = ae_false; state->needfg = ae_false; state->needfgh = ae_false; state->needfij = ae_false; state->needfi = ae_false; state->xupdated = ae_false; } /************************************************************************* Increases lambda, returns False when there is a danger of overflow *************************************************************************/ static ae_bool minlm_increaselambda(double* lambdav, double* nu, ae_state *_state) { double lnlambda; double lnnu; double lnlambdaup; double lnmax; ae_bool result; result = ae_false; lnlambda = ae_log(*lambdav, _state); lnlambdaup = ae_log(minlm_lambdaup, _state); lnnu = ae_log(*nu, _state); lnmax = ae_log(ae_maxrealnumber, _state); if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,0.25*lnmax) ) { return result; } if( ae_fp_greater(lnnu+ae_log((double)(2), _state),lnmax) ) { return result; } *lambdav = *lambdav*minlm_lambdaup*(*nu); *nu = *nu*2; result = ae_true; return result; } /************************************************************************* Decreases lambda, but leaves it unchanged when there is danger of underflow. *************************************************************************/ static void minlm_decreaselambda(double* lambdav, double* nu, ae_state *_state) { *nu = (double)(1); if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(minlm_lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) { *lambdav = ae_minrealnumber; } else { *lambdav = *lambdav*minlm_lambdadown; } } /************************************************************************* Returns norm of bounded scaled anti-gradient. Bounded antigradient is a vector obtained from anti-gradient by zeroing components which point outwards: result = norm(v) v[i]=0 if ((-g[i]<0)and(x[i]=bndl[i])) or ((-g[i]>0)and(x[i]=bndu[i])) v[i]=-g[i]*s[i] otherwise, where s[i] is a scale for I-th variable This function may be used to check a stopping criterion. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ static double minlm_boundedscaledantigradnorm(minlmstate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t n; ae_int_t i; double v; double result; result = (double)(0); n = state->n; for(i=0; i<=n-1; i++) { v = -g->ptr.p_double[i]*state->s.ptr.p_double[i]; if( state->havebndl.ptr.p_bool[i] ) { if( ae_fp_less_eq(x->ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-g->ptr.p_double[i],(double)(0)) ) { v = (double)(0); } } if( state->havebndu.ptr.p_bool[i] ) { if( ae_fp_greater_eq(x->ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-g->ptr.p_double[i],(double)(0)) ) { v = (double)(0); } } result = result+ae_sqr(v, _state); } result = ae_sqrt(result, _state); return result; } void _minlmstate_init(void* _p, ae_state *_state) { minlmstate *p = (minlmstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->fi, 0, DT_REAL, _state); ae_matrix_init(&p->j, 0, 0, DT_REAL, _state); ae_matrix_init(&p->h, 0, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); ae_vector_init(&p->xbase, 0, DT_REAL, _state); ae_vector_init(&p->fibase, 0, DT_REAL, _state); ae_vector_init(&p->gbase, 0, DT_REAL, _state); ae_matrix_init(&p->quadraticmodel, 0, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->havebndl, 0, DT_BOOL, _state); ae_vector_init(&p->havebndu, 0, DT_BOOL, _state); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->xdir, 0, DT_REAL, _state); ae_vector_init(&p->deltax, 0, DT_REAL, _state); ae_vector_init(&p->deltaf, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->fm1, 0, DT_REAL, _state); ae_vector_init(&p->fp1, 0, DT_REAL, _state); ae_vector_init(&p->fc1, 0, DT_REAL, _state); ae_vector_init(&p->gm1, 0, DT_REAL, _state); ae_vector_init(&p->gp1, 0, DT_REAL, _state); ae_vector_init(&p->gc1, 0, DT_REAL, _state); _minlbfgsstate_init(&p->internalstate, _state); _minlbfgsreport_init(&p->internalrep, _state); _minqpstate_init(&p->qpstate, _state); _minqpreport_init(&p->qprep, _state); } void _minlmstate_init_copy(void* _dst, void* _src, ae_state *_state) { minlmstate *dst = (minlmstate*)_dst; minlmstate *src = (minlmstate*)_src; dst->n = src->n; dst->m = src->m; dst->diffstep = src->diffstep; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->stpmax = src->stpmax; dst->maxmodelage = src->maxmodelage; dst->makeadditers = src->makeadditers; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->fi, &src->fi, _state); ae_matrix_init_copy(&dst->j, &src->j, _state); ae_matrix_init_copy(&dst->h, &src->h, _state); ae_vector_init_copy(&dst->g, &src->g, _state); dst->needf = src->needf; dst->needfg = src->needfg; dst->needfgh = src->needfgh; dst->needfij = src->needfij; dst->needfi = src->needfi; dst->xupdated = src->xupdated; dst->userterminationneeded = src->userterminationneeded; dst->algomode = src->algomode; dst->hasf = src->hasf; dst->hasfi = src->hasfi; dst->hasg = src->hasg; ae_vector_init_copy(&dst->xbase, &src->xbase, _state); dst->fbase = src->fbase; ae_vector_init_copy(&dst->fibase, &src->fibase, _state); ae_vector_init_copy(&dst->gbase, &src->gbase, _state); ae_matrix_init_copy(&dst->quadraticmodel, &src->quadraticmodel, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state); ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state); ae_vector_init_copy(&dst->s, &src->s, _state); dst->lambdav = src->lambdav; dst->nu = src->nu; dst->modelage = src->modelage; ae_vector_init_copy(&dst->xdir, &src->xdir, _state); ae_vector_init_copy(&dst->deltax, &src->deltax, _state); ae_vector_init_copy(&dst->deltaf, &src->deltaf, _state); dst->deltaxready = src->deltaxready; dst->deltafready = src->deltafready; dst->teststep = src->teststep; dst->repiterationscount = src->repiterationscount; dst->repterminationtype = src->repterminationtype; dst->repfuncidx = src->repfuncidx; dst->repvaridx = src->repvaridx; dst->repnfunc = src->repnfunc; dst->repnjac = src->repnjac; dst->repngrad = src->repngrad; dst->repnhess = src->repnhess; dst->repncholesky = src->repncholesky; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); dst->actualdecrease = src->actualdecrease; dst->predicteddecrease = src->predicteddecrease; dst->xm1 = src->xm1; dst->xp1 = src->xp1; ae_vector_init_copy(&dst->fm1, &src->fm1, _state); ae_vector_init_copy(&dst->fp1, &src->fp1, _state); ae_vector_init_copy(&dst->fc1, &src->fc1, _state); ae_vector_init_copy(&dst->gm1, &src->gm1, _state); ae_vector_init_copy(&dst->gp1, &src->gp1, _state); ae_vector_init_copy(&dst->gc1, &src->gc1, _state); _minlbfgsstate_init_copy(&dst->internalstate, &src->internalstate, _state); _minlbfgsreport_init_copy(&dst->internalrep, &src->internalrep, _state); _minqpstate_init_copy(&dst->qpstate, &src->qpstate, _state); _minqpreport_init_copy(&dst->qprep, &src->qprep, _state); } void _minlmstate_clear(void* _p) { minlmstate *p = (minlmstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->x); ae_vector_clear(&p->fi); ae_matrix_clear(&p->j); ae_matrix_clear(&p->h); ae_vector_clear(&p->g); ae_vector_clear(&p->xbase); ae_vector_clear(&p->fibase); ae_vector_clear(&p->gbase); ae_matrix_clear(&p->quadraticmodel); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->havebndl); ae_vector_clear(&p->havebndu); ae_vector_clear(&p->s); ae_vector_clear(&p->xdir); ae_vector_clear(&p->deltax); ae_vector_clear(&p->deltaf); _rcommstate_clear(&p->rstate); ae_vector_clear(&p->choleskybuf); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->fm1); ae_vector_clear(&p->fp1); ae_vector_clear(&p->fc1); ae_vector_clear(&p->gm1); ae_vector_clear(&p->gp1); ae_vector_clear(&p->gc1); _minlbfgsstate_clear(&p->internalstate); _minlbfgsreport_clear(&p->internalrep); _minqpstate_clear(&p->qpstate); _minqpreport_clear(&p->qprep); } void _minlmstate_destroy(void* _p) { minlmstate *p = (minlmstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->x); ae_vector_destroy(&p->fi); ae_matrix_destroy(&p->j); ae_matrix_destroy(&p->h); ae_vector_destroy(&p->g); ae_vector_destroy(&p->xbase); ae_vector_destroy(&p->fibase); ae_vector_destroy(&p->gbase); ae_matrix_destroy(&p->quadraticmodel); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->havebndl); ae_vector_destroy(&p->havebndu); ae_vector_destroy(&p->s); ae_vector_destroy(&p->xdir); ae_vector_destroy(&p->deltax); ae_vector_destroy(&p->deltaf); _rcommstate_destroy(&p->rstate); ae_vector_destroy(&p->choleskybuf); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->fm1); ae_vector_destroy(&p->fp1); ae_vector_destroy(&p->fc1); ae_vector_destroy(&p->gm1); ae_vector_destroy(&p->gp1); ae_vector_destroy(&p->gc1); _minlbfgsstate_destroy(&p->internalstate); _minlbfgsreport_destroy(&p->internalrep); _minqpstate_destroy(&p->qpstate); _minqpreport_destroy(&p->qprep); } void _minlmreport_init(void* _p, ae_state *_state) { minlmreport *p = (minlmreport*)_p; ae_touch_ptr((void*)p); } void _minlmreport_init_copy(void* _dst, void* _src, ae_state *_state) { minlmreport *dst = (minlmreport*)_dst; minlmreport *src = (minlmreport*)_src; dst->iterationscount = src->iterationscount; dst->terminationtype = src->terminationtype; dst->funcidx = src->funcidx; dst->varidx = src->varidx; dst->nfunc = src->nfunc; dst->njac = src->njac; dst->ngrad = src->ngrad; dst->nhess = src->nhess; dst->ncholesky = src->ncholesky; } void _minlmreport_clear(void* _p) { minlmreport *p = (minlmreport*)_p; ae_touch_ptr((void*)p); } void _minlmreport_destroy(void* _p) { minlmreport *p = (minlmreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* Obsolete function, use MinLBFGSSetPrecDefault() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, ae_state *_state) { minlbfgssetprecdefault(state, _state); } /************************************************************************* Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/ void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, /* Real */ ae_matrix* p, ae_bool isupper, ae_state *_state) { minlbfgssetpreccholesky(state, p, isupper, _state); } /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierwidth(minbleicstate* state, double mu, ae_state *_state) { } /************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minbleicsetbarrierdecay(minbleicstate* state, double mudecay, ae_state *_state) { } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/ void minasacreate(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, minasastate* state, ae_state *_state) { ae_int_t i; _minasastate_clear(state); ae_assert(n>=1, "MinASA: N too small!", _state); ae_assert(x->cnt>=n, "MinCGCreate: Length(X)cnt>=n, "MinCGCreate: Length(BndL)cnt>=n, "MinCGCreate: Length(BndU)ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: inconsistent bounds!", _state); ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],x->ptr.p_double[i]), "MinASA: infeasible X!", _state); ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: infeasible X!", _state); } /* * Initialize */ state->n = n; minasasetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); minasasetxrep(state, ae_false, _state); minasasetstpmax(state, (double)(0), _state); minasasetalgorithm(state, -1, _state); ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->ak, n, _state); ae_vector_set_length(&state->xk, n, _state); ae_vector_set_length(&state->dk, n, _state); ae_vector_set_length(&state->an, n, _state); ae_vector_set_length(&state->xn, n, _state); ae_vector_set_length(&state->dn, n, _state); ae_vector_set_length(&state->x, n, _state); ae_vector_set_length(&state->d, n, _state); ae_vector_set_length(&state->g, n, _state); ae_vector_set_length(&state->gc, n, _state); ae_vector_set_length(&state->work, n, _state); ae_vector_set_length(&state->yk, n, _state); minasarestartfrom(state, x, bndl, bndu, _state); } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetcond(minasastate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinASASetCond: EpsG is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinASASetCond: negative EpsG!", _state); ae_assert(ae_isfinite(epsf, _state), "MinASASetCond: EpsF is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinASASetCond: negative EpsF!", _state); ae_assert(ae_isfinite(epsx, _state), "MinASASetCond: EpsX is not finite number!", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinASASetCond: negative EpsX!", _state); ae_assert(maxits>=0, "MinASASetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetalgorithm(minasastate* state, ae_int_t algotype, ae_state *_state) { ae_assert(algotype>=-1&&algotype<=1, "MinASASetAlgorithm: incorrect AlgoType!", _state); if( algotype==-1 ) { algotype = 1; } state->cgtype = algotype; } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state) { ae_assert(ae_isfinite(stpmax, _state), "MinASASetStpMax: StpMax is not finite!", _state); ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinASASetStpMax: StpMax<0!", _state); state->stpmax = stpmax; } /************************************************************************* -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ ae_bool minasaiteration(minasastate* state, ae_state *_state) { ae_int_t n; ae_int_t i; double betak; double v; double vv; ae_int_t mcinfo; ae_bool b; ae_bool stepfound; ae_int_t diffcnt; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { n = state->rstate.ia.ptr.p_int[0]; i = state->rstate.ia.ptr.p_int[1]; mcinfo = state->rstate.ia.ptr.p_int[2]; diffcnt = state->rstate.ia.ptr.p_int[3]; b = state->rstate.ba.ptr.p_bool[0]; stepfound = state->rstate.ba.ptr.p_bool[1]; betak = state->rstate.ra.ptr.p_double[0]; v = state->rstate.ra.ptr.p_double[1]; vv = state->rstate.ra.ptr.p_double[2]; } else { n = -983; i = -989; mcinfo = -834; diffcnt = 900; b = ae_true; stepfound = ae_false; betak = 214; v = -338; vv = -686; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } if( state->rstate.stage==9 ) { goto lbl_9; } if( state->rstate.stage==10 ) { goto lbl_10; } if( state->rstate.stage==11 ) { goto lbl_11; } if( state->rstate.stage==12 ) { goto lbl_12; } if( state->rstate.stage==13 ) { goto lbl_13; } if( state->rstate.stage==14 ) { goto lbl_14; } /* * Routine body */ /* * Prepare */ n = state->n; state->repterminationtype = 0; state->repiterationscount = 0; state->repnfev = 0; state->debugrestartscount = 0; state->cgtype = 1; ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xk.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xk.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->ak.ptr.p_double[i] = (double)(0); } else { state->ak.ptr.p_double[i] = (double)(1); } } state->mu = 0.1; state->curalgo = 0; /* * Calculate F/G, initialize algorithm */ mincomp_clearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: state->needfg = ae_false; if( !state->xrep ) { goto lbl_15; } /* * progress report */ mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: state->xupdated = ae_false; lbl_15: if( ae_fp_less_eq(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) { state->repterminationtype = 4; result = ae_false; return result; } state->repnfev = state->repnfev+1; /* * Main cycle * * At the beginning of new iteration: * * CurAlgo stores current algorithm selector * * State.XK, State.F and State.G store current X/F/G * * State.AK stores current set of active constraints */ lbl_17: if( ae_false ) { goto lbl_18; } /* * GPA algorithm */ if( state->curalgo!=0 ) { goto lbl_19; } state->k = 0; state->acount = 0; lbl_21: if( ae_false ) { goto lbl_22; } /* * Determine Dk = proj(xk - gk)-xk */ for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->xk.ptr.p_double[i]; } /* * Armijo line search. * * exact search with alpha=1 is tried first, * 'exact' means that we evaluate f() EXACTLY at * bound(x-g,bndl,bndu), without intermediate floating * point operations. * * alpha<1 are tried if explicit search wasn't successful * Result is placed into XN. * * Two types of search are needed because we can't * just use second type with alpha=1 because in finite * precision arithmetics (x1-x0)+x0 may differ from x1. * So while x1 is correctly bounded (it lie EXACTLY on * boundary, if it is active), (x1-x0)+x0 may be * not bounded. */ v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->dginit = v; state->finit = state->f; if( !(ae_fp_less_eq(mincomp_asad1norm(state, _state),state->stpmax)||ae_fp_eq(state->stpmax,(double)(0))) ) { goto lbl_23; } /* * Try alpha=1 step first */ for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } mincomp_clearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: state->needfg = ae_false; state->repnfev = state->repnfev+1; stepfound = ae_fp_less_eq(state->f,state->finit+mincomp_gpaftol*state->dginit); goto lbl_24; lbl_23: stepfound = ae_false; lbl_24: if( !stepfound ) { goto lbl_25; } /* * we are at the boundary(ies) */ ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->stp = (double)(1); goto lbl_26; lbl_25: /* * alpha=1 is too large, try smaller values */ state->stp = (double)(1); linminnormalized(&state->d, &state->stp, n, _state); state->dginit = state->dginit/state->stp; state->stp = mincomp_gpadecay*state->stp; if( ae_fp_greater(state->stpmax,(double)(0)) ) { state->stp = ae_minreal(state->stp, state->stpmax, _state); } lbl_27: if( ae_false ) { goto lbl_28; } v = state->stp; ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->x.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); mincomp_clearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: state->needfg = ae_false; state->repnfev = state->repnfev+1; if( ae_fp_less_eq(state->stp,mincomp_stpmin) ) { goto lbl_28; } if( ae_fp_less_eq(state->f,state->finit+state->stp*mincomp_gpaftol*state->dginit) ) { goto lbl_28; } state->stp = state->stp*mincomp_gpadecay; goto lbl_27; lbl_28: ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); lbl_26: state->repiterationscount = state->repiterationscount+1; if( !state->xrep ) { goto lbl_29; } /* * progress report */ mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: state->xupdated = ae_false; lbl_29: /* * Calculate new set of active constraints. * Reset counter if active set was changed. * Prepare for the new iteration */ for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->an.ptr.p_double[i] = (double)(0); } else { state->an.ptr.p_double[i] = (double)(1); } } for(i=0; i<=n-1; i++) { if( ae_fp_neq(state->ak.ptr.p_double[i],state->an.ptr.p_double[i]) ) { state->acount = -1; break; } } state->acount = state->acount+1; ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->ak.ptr.p_double[0], 1, &state->an.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Stopping conditions */ if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) { goto lbl_31; } /* * Too many iterations */ state->repterminationtype = 5; if( !state->xrep ) { goto lbl_33; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: state->xupdated = ae_false; lbl_33: result = ae_false; return result; lbl_31: if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) { goto lbl_35; } /* * Gradient is small enough */ state->repterminationtype = 4; if( !state->xrep ) { goto lbl_37; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: state->xupdated = ae_false; lbl_37: result = ae_false; return result; lbl_35: v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( ae_fp_greater(ae_sqrt(v, _state)*state->stp,state->epsx) ) { goto lbl_39; } /* * Step size is too small, no further improvement is * possible */ state->repterminationtype = 2; if( !state->xrep ) { goto lbl_41; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 7; goto lbl_rcomm; lbl_7: state->xupdated = ae_false; lbl_41: result = ae_false; return result; lbl_39: if( ae_fp_greater(state->finit-state->f,state->epsf*ae_maxreal(ae_fabs(state->finit, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) { goto lbl_43; } /* * F(k+1)-F(k) is small enough */ state->repterminationtype = 1; if( !state->xrep ) { goto lbl_45; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 8; goto lbl_rcomm; lbl_8: state->xupdated = ae_false; lbl_45: result = ae_false; return result; lbl_43: /* * Decide - should we switch algorithm or not */ if( mincomp_asauisempty(state, _state) ) { if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) { state->curalgo = 1; goto lbl_22; } else { state->mu = state->mu*mincomp_asarho; } } else { if( state->acount==mincomp_n1 ) { if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) { state->curalgo = 1; goto lbl_22; } } } /* * Next iteration */ state->k = state->k+1; goto lbl_21; lbl_22: lbl_19: /* * CG algorithm */ if( state->curalgo!=1 ) { goto lbl_47; } /* * first, check that there are non-active constraints. * move to GPA algorithm, if all constraints are active */ b = ae_true; for(i=0; i<=n-1; i++) { if( ae_fp_neq(state->ak.ptr.p_double[i],(double)(0)) ) { b = ae_false; break; } } if( b ) { state->curalgo = 0; goto lbl_17; } /* * CG iterations */ state->fold = state->f; ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { state->dk.ptr.p_double[i] = -state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; } lbl_49: if( ae_false ) { goto lbl_50; } /* * Store G[k] for later calculation of Y[k] */ for(i=0; i<=n-1; i++) { state->yk.ptr.p_double[i] = -state->gc.ptr.p_double[i]; } /* * Make a CG step in direction given by DK[]: * * calculate step. Step projection into feasible set * is used. It has several benefits: a) step may be * found with usual line search, b) multiple constraints * may be activated with one step, c) activated constraints * are detected in a natural way - just compare x[i] with * bounds * * update active set, set B to True, if there * were changes in the set. */ ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->mcstage = 0; state->stp = (double)(1); linminnormalized(&state->d, &state->stp, n, _state); if( ae_fp_neq(state->laststep,(double)(0)) ) { state->stp = state->laststep; } mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); lbl_51: if( state->mcstage==0 ) { goto lbl_52; } /* * preprocess data: bound State.XN so it belongs to the * feasible set and store it in the State.X */ for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); } /* * RComm */ mincomp_clearrequestfields(state, _state); state->needfg = ae_true; state->rstate.stage = 9; goto lbl_rcomm; lbl_9: state->needfg = ae_false; /* * postprocess data: zero components of G corresponding to * the active constraints */ for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->gc.ptr.p_double[i] = (double)(0); } else { state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]; } } mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); goto lbl_51; lbl_52: diffcnt = 0; for(i=0; i<=n-1; i++) { /* * XN contains unprojected result, project it, * save copy to X (will be used for progress reporting) */ state->xn.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); /* * update active set */ if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->an.ptr.p_double[i] = (double)(0); } else { state->an.ptr.p_double[i] = (double)(1); } if( ae_fp_neq(state->an.ptr.p_double[i],state->ak.ptr.p_double[i]) ) { diffcnt = diffcnt+1; } state->ak.ptr.p_double[i] = state->an.ptr.p_double[i]; } ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->repnfev = state->repnfev+state->nfev; state->repiterationscount = state->repiterationscount+1; if( !state->xrep ) { goto lbl_53; } /* * progress report */ mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 10; goto lbl_rcomm; lbl_10: state->xupdated = ae_false; lbl_53: /* * Update info about step length */ v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->laststep = ae_sqrt(v, _state)*state->stp; /* * Check stopping conditions. */ if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) { goto lbl_55; } /* * Gradient is small enough */ state->repterminationtype = 4; if( !state->xrep ) { goto lbl_57; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 11; goto lbl_rcomm; lbl_11: state->xupdated = ae_false; lbl_57: result = ae_false; return result; lbl_55: if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) { goto lbl_59; } /* * Too many iterations */ state->repterminationtype = 5; if( !state->xrep ) { goto lbl_61; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 12; goto lbl_rcomm; lbl_12: state->xupdated = ae_false; lbl_61: result = ae_false; return result; lbl_59: if( !(ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state))&&diffcnt==0) ) { goto lbl_63; } /* * These conditions (EpsF/EpsX) are explicitly or implicitly * related to the current step size and influenced * by changes in the active constraints. * * For these reasons they are checked only when we don't * want to 'unstick' at the end of the iteration and there * were no changes in the active set. * * NOTE: consition |G|>=Mu*|D1| must be exactly opposite * to the condition used to switch back to GPA. At least * one inequality must be strict, otherwise infinite cycle * may occur when |G|=Mu*|D1| (we DON'T test stopping * conditions and we DON'T switch to GPA, so we cycle * indefinitely). */ if( ae_fp_greater(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) { goto lbl_65; } /* * F(k+1)-F(k) is small enough */ state->repterminationtype = 1; if( !state->xrep ) { goto lbl_67; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 13; goto lbl_rcomm; lbl_13: state->xupdated = ae_false; lbl_67: result = ae_false; return result; lbl_65: if( ae_fp_greater(state->laststep,state->epsx) ) { goto lbl_69; } /* * X(k+1)-X(k) is small enough */ state->repterminationtype = 2; if( !state->xrep ) { goto lbl_71; } mincomp_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstate.stage = 14; goto lbl_rcomm; lbl_14: state->xupdated = ae_false; lbl_71: result = ae_false; return result; lbl_69: lbl_63: /* * Check conditions for switching */ if( ae_fp_less(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) { state->curalgo = 0; goto lbl_50; } if( diffcnt>0 ) { if( mincomp_asauisempty(state, _state)||diffcnt>=mincomp_n2 ) { state->curalgo = 1; } else { state->curalgo = 0; } goto lbl_50; } /* * Calculate D(k+1) * * Line search may result in: * * maximum feasible step being taken (already processed) * * point satisfying Wolfe conditions * * some kind of error (CG is restarted by assigning 0.0 to Beta) */ if( mcinfo==1 ) { /* * Standard Wolfe conditions are satisfied: * * calculate Y[K] and BetaK */ ae_v_add(&state->yk.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->betady = v/vv; v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->betahs = v/vv; if( state->cgtype==0 ) { betak = state->betady; } if( state->cgtype==1 ) { betak = ae_maxreal((double)(0), ae_minreal(state->betady, state->betahs, _state), _state); } } else { /* * Something is wrong (may be function is too wild or too flat). * * We'll set BetaK=0, which will restart CG algorithm. * We can stop later (during normal checks) if stopping conditions are met. */ betak = (double)(0); state->debugrestartscount = state->debugrestartscount+1; } ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * update other information */ state->fold = state->f; state->k = state->k+1; goto lbl_49; lbl_50: lbl_47: goto lbl_17; lbl_18: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = n; state->rstate.ia.ptr.p_int[1] = i; state->rstate.ia.ptr.p_int[2] = mcinfo; state->rstate.ia.ptr.p_int[3] = diffcnt; state->rstate.ba.ptr.p_bool[0] = b; state->rstate.ba.ptr.p_bool[1] = stepfound; state->rstate.ra.ptr.p_double[0] = betak; state->rstate.ra.ptr.p_double[1] = v; state->rstate.ra.ptr.p_double[2] = vv; return result; } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresults(minasastate* state, /* Real */ ae_vector* x, minasareport* rep, ae_state *_state) { ae_vector_clear(x); _minasareport_clear(rep); minasaresultsbuf(state, x, rep, _state); } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ void minasaresultsbuf(minasastate* state, /* Real */ ae_vector* x, minasareport* rep, ae_state *_state) { ae_int_t i; if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); rep->iterationscount = state->repiterationscount; rep->nfev = state->repnfev; rep->terminationtype = state->repterminationtype; rep->activeconstraints = 0; for(i=0; i<=state->n-1; i++) { if( ae_fp_eq(state->ak.ptr.p_double[i],(double)(0)) ) { rep->activeconstraints = rep->activeconstraints+1; } } } /************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/ void minasarestartfrom(minasastate* state, /* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_assert(x->cnt>=state->n, "MinASARestartFrom: Length(X)n, _state), "MinASARestartFrom: X contains infinite or NaN values!", _state); ae_assert(bndl->cnt>=state->n, "MinASARestartFrom: Length(BndL)n, _state), "MinASARestartFrom: BndL contains infinite or NaN values!", _state); ae_assert(bndu->cnt>=state->n, "MinASARestartFrom: Length(BndU)n, _state), "MinASARestartFrom: BndU contains infinite or NaN values!", _state); ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_v_move(&state->bndl.ptr.p_double[0], 1, &bndl->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); ae_v_move(&state->bndu.ptr.p_double[0], 1, &bndu->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); state->laststep = (double)(0); ae_vector_set_length(&state->rstate.ia, 3+1, _state); ae_vector_set_length(&state->rstate.ba, 1+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; mincomp_clearrequestfields(state, _state); } /************************************************************************* Returns norm of bounded anti-gradient. Bounded antigradient is a vector obtained from anti-gradient by zeroing components which point outwards: result = norm(v) v[i]=0 if ((-g[i]<0)and(x[i]=bndl[i])) or ((-g[i]>0)and(x[i]=bndu[i])) v[i]=-g[i] otherwise This function may be used to check a stopping criterion. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ static double mincomp_asaboundedantigradnorm(minasastate* state, ae_state *_state) { ae_int_t i; double v; double result; result = (double)(0); for(i=0; i<=state->n-1; i++) { v = -state->g.ptr.p_double[i]; if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-state->g.ptr.p_double[i],(double)(0)) ) { v = (double)(0); } if( ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-state->g.ptr.p_double[i],(double)(0)) ) { v = (double)(0); } result = result+ae_sqr(v, _state); } result = ae_sqrt(result, _state); return result; } /************************************************************************* Returns norm of GI(x). GI(x) is a gradient vector whose components associated with active constraints are zeroed. It differs from bounded anti-gradient because components of GI(x) are zeroed independently of sign(g[i]), and anti-gradient's components are zeroed with respect to both constraint and sign. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ static double mincomp_asaginorm(minasastate* state, ae_state *_state) { ae_int_t i; double result; result = (double)(0); for(i=0; i<=state->n-1; i++) { if( ae_fp_neq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_neq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { result = result+ae_sqr(state->g.ptr.p_double[i], _state); } } result = ae_sqrt(result, _state); return result; } /************************************************************************* Returns norm(D1(State.X)) For a meaning of D1 see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ static double mincomp_asad1norm(minasastate* state, ae_state *_state) { ae_int_t i; double result; result = (double)(0); for(i=0; i<=state->n-1; i++) { result = result+ae_sqr(boundval(state->x.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->x.ptr.p_double[i], _state); } result = ae_sqrt(result, _state); return result; } /************************************************************************* Returns True, if U set is empty. * State.X is used as point, * State.G - as gradient, * D is calculated within function (because State.D may have different meaning depending on current optimization algorithm) For a meaning of U see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/ static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state) { ae_int_t i; double d; double d2; double d32; ae_bool result; d = mincomp_asad1norm(state, _state); d2 = ae_sqrt(d, _state); d32 = d*d2; result = ae_true; for(i=0; i<=state->n-1; i++) { if( ae_fp_greater_eq(ae_fabs(state->g.ptr.p_double[i], _state),d2)&&ae_fp_greater_eq(ae_minreal(state->x.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i]-state->x.ptr.p_double[i], _state),d32) ) { result = ae_false; return result; } } return result; } /************************************************************************* Clears request fileds (to be sure that we don't forgot to clear something) *************************************************************************/ static void mincomp_clearrequestfields(minasastate* state, ae_state *_state) { state->needfg = ae_false; state->xupdated = ae_false; } void _minasastate_init(void* _p, ae_state *_state) { minasastate *p = (minasastate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->ak, 0, DT_REAL, _state); ae_vector_init(&p->xk, 0, DT_REAL, _state); ae_vector_init(&p->dk, 0, DT_REAL, _state); ae_vector_init(&p->an, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->dn, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->work, 0, DT_REAL, _state); ae_vector_init(&p->yk, 0, DT_REAL, _state); ae_vector_init(&p->gc, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->g, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); _linminstate_init(&p->lstate, _state); } void _minasastate_init_copy(void* _dst, void* _src, ae_state *_state) { minasastate *dst = (minasastate*)_dst; minasastate *src = (minasastate*)_src; dst->n = src->n; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->stpmax = src->stpmax; dst->cgtype = src->cgtype; dst->k = src->k; dst->nfev = src->nfev; dst->mcstage = src->mcstage; ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); dst->curalgo = src->curalgo; dst->acount = src->acount; dst->mu = src->mu; dst->finit = src->finit; dst->dginit = src->dginit; ae_vector_init_copy(&dst->ak, &src->ak, _state); ae_vector_init_copy(&dst->xk, &src->xk, _state); ae_vector_init_copy(&dst->dk, &src->dk, _state); ae_vector_init_copy(&dst->an, &src->an, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->dn, &src->dn, _state); ae_vector_init_copy(&dst->d, &src->d, _state); dst->fold = src->fold; dst->stp = src->stp; ae_vector_init_copy(&dst->work, &src->work, _state); ae_vector_init_copy(&dst->yk, &src->yk, _state); ae_vector_init_copy(&dst->gc, &src->gc, _state); dst->laststep = src->laststep; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->g, &src->g, _state); dst->needfg = src->needfg; dst->xupdated = src->xupdated; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); dst->repiterationscount = src->repiterationscount; dst->repnfev = src->repnfev; dst->repterminationtype = src->repterminationtype; dst->debugrestartscount = src->debugrestartscount; _linminstate_init_copy(&dst->lstate, &src->lstate, _state); dst->betahs = src->betahs; dst->betady = src->betady; } void _minasastate_clear(void* _p) { minasastate *p = (minasastate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->ak); ae_vector_clear(&p->xk); ae_vector_clear(&p->dk); ae_vector_clear(&p->an); ae_vector_clear(&p->xn); ae_vector_clear(&p->dn); ae_vector_clear(&p->d); ae_vector_clear(&p->work); ae_vector_clear(&p->yk); ae_vector_clear(&p->gc); ae_vector_clear(&p->x); ae_vector_clear(&p->g); _rcommstate_clear(&p->rstate); _linminstate_clear(&p->lstate); } void _minasastate_destroy(void* _p) { minasastate *p = (minasastate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->ak); ae_vector_destroy(&p->xk); ae_vector_destroy(&p->dk); ae_vector_destroy(&p->an); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->dn); ae_vector_destroy(&p->d); ae_vector_destroy(&p->work); ae_vector_destroy(&p->yk); ae_vector_destroy(&p->gc); ae_vector_destroy(&p->x); ae_vector_destroy(&p->g); _rcommstate_destroy(&p->rstate); _linminstate_destroy(&p->lstate); } void _minasareport_init(void* _p, ae_state *_state) { minasareport *p = (minasareport*)_p; ae_touch_ptr((void*)p); } void _minasareport_init_copy(void* _dst, void* _src, ae_state *_state) { minasareport *dst = (minasareport*)_dst; minasareport *src = (minasareport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->terminationtype = src->terminationtype; dst->activeconstraints = src->activeconstraints; } void _minasareport_clear(void* _p) { minasareport *p = (minasareport*)_p; ae_touch_ptr((void*)p); } void _minasareport_destroy(void* _p) { minasareport *p = (minasareport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* NONLINEARLY CONSTRAINED OPTIMIZATION WITH PRECONDITIONED AUGMENTED LAGRANGIAN ALGORITHM DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 REQUIREMENTS: * user must provide function value and gradient for F(), H(), G() * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are twice continuously differentiable on the feasible set and its neighborhood * nonlinear constraints G() and H() must have non-zero gradient at G(x)=0 and at H(x)=0. Say, constraint like x^2>=1 is supported, but x^2>=0 is NOT supported. USAGE: Constrained optimization if far more complex than the unconstrained one. Nonlinearly constrained optimization is one of the most esoteric numerical procedures. Here we give very brief outline of the MinNLC optimizer. We strongly recommend you to study examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinNLCCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AUL solver (activated with MinNLCSetAlgoAUL() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNLCSetBC() for boundary constraints b) MinNLCSetLC() for linear constraints c) MinNLCSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNLCSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNLCSetCond(). If NLC solver uses inner/outer iteration layout, this function sets stopping conditions for INNER iterations. 5. User chooses one of the preconditioning methods. Preconditioning is very important for efficient handling of boundary/linear/nonlinear constraints. Without preconditioning algorithm would require thousands of iterations even for simple problems. Two preconditioners can be used: * approximate LBFGS-based preconditioner which should be used for problems with almost orthogonal constraints (activated by calling MinNLCSetPrecInexact) * exact low-rank preconditiner (activated by MinNLCSetPrecExactLowRank) which should be used for problems with moderate number of constraints which do not have to be orthogonal. 6. Finally, user calls MinNLCOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G/H. 7. User calls MinNLCResults() to get solution 8. Optionally user may call MinNLCRestartFrom() to solve another problem with same N but another starting point. MinNLCRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreate(ae_int_t n, /* Real */ ae_vector* x, minnlcstate* state, ae_state *_state) { _minnlcstate_clear(state); ae_assert(n>=1, "MinNLCCreate: N<1", _state); ae_assert(x->cnt>=n, "MinNLCCreate: Length(X)0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinNLCSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large TRUNCATION errors, while too small step will result in too large NUMERICAL errors. 1.0E-4 can be good value to start from. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlccreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnlcstate* state, ae_state *_state) { _minnlcstate_clear(state); ae_assert(n>=1, "MinNLCCreateF: N<1", _state); ae_assert(x->cnt>=n, "MinNLCCreateF: Length(X)n; ae_assert(bndl->cnt>=n, "MinNLCSetBC: Length(BndL)cnt>=n, "MinNLCSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinNLCSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinNLCSetBC: BndL contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } } /************************************************************************* This function sets linear constraints for MinNLC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine linear constraints with boundary ones - and with nonlinear ones! If your problem has mixed constraints, you may explicitly specify some of them as linear. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: when you solve your problem with augmented Lagrangian solver, linear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetlc(minnlcstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t n; ae_int_t i; n = state->n; /* * First, check for errors in the inputs */ ae_assert(k>=0, "MinNLCSetLC: K<0", _state); ae_assert(c->cols>=n+1||k==0, "MinNLCSetLC: Cols(C)rows>=k, "MinNLCSetLC: Rows(C)cnt>=k, "MinNLCSetLC: Length(CT)nec = 0; state->nic = 0; return; } /* * Equality constraints are stored first, in the upper * NEC rows of State.CLEIC matrix. Inequality constraints * are stored in the next NIC rows. * * NOTE: we convert inequality constraints to the form * A*x<=b before copying them. */ rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); state->nec = 0; state->nic = 0; for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]==0 ) { ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); state->nec = state->nec+1; } } for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]!=0 ) { if( ct->ptr.p_int[i]>0 ) { ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } else { ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } state->nic = state->nic+1; } } } /************************************************************************* This function sets nonlinear constraints for MinNLC optimizer. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to MinNLCOptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] corresponds to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: when you solve your problem with augmented Lagrangian solver, nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! NOTE 2: algorithm scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetnlc(minnlcstate* state, ae_int_t nlec, ae_int_t nlic, ae_state *_state) { ae_assert(nlec>=0, "MinNLCSetNLC: NLEC<0", _state); ae_assert(nlic>=0, "MinNLCSetNLC: NLIC<0", _state); state->ng = nlec; state->nh = nlic; ae_vector_set_length(&state->fi, 1+state->ng+state->nh, _state); ae_matrix_set_length(&state->j, 1+state->ng+state->nh, state->n, _state); } /************************************************************************* This function sets stopping conditions for inner iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinNLCSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetcond(minnlcstate* state, double epsg, double epsf, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsg, _state), "MinNLCSetCond: EpsG is not finite number", _state); ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinNLCSetCond: negative EpsG", _state); ae_assert(ae_isfinite(epsf, _state), "MinNLCSetCond: EpsF is not finite number", _state); ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinNLCSetCond: negative EpsF", _state); ae_assert(ae_isfinite(epsx, _state), "MinNLCSetCond: EpsX is not finite number", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinNLCSetCond: negative EpsX", _state); ae_assert(maxits>=0, "MinNLCSetCond: negative MaxIts!", _state); if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) { epsx = 1.0E-6; } state->epsg = epsg; state->epsf = epsf; state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetscale(minnlcstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->n, "MinNLCSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinNLCSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinNLCSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function sets preconditioner to "inexact LBFGS-based" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss LBFGS-based preconditioner. Inexact LBFGS-based preconditioner uses L-BFGS formula combined with orthogonality assumption to perform very fast updates. For a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K) cost per iteration. This preconditioner has best quality (less iterations) when general linear and nonlinear constraints are orthogonal to each other (orthogonality with respect to boundary constraints is not required). Number of iterations increases when constraints are non-orthogonal, because algorithm assumes orthogonality, but still it is better than no preconditioner at all. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecinexact(minnlcstate* state, ae_state *_state) { state->updatefreq = 0; state->prectype = 1; } /************************************************************************* This function sets preconditioner to "exact low rank" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss low rank preconditioner. Exact low-rank preconditioner uses Woodbury matrix identity to build quadratic model of the penalized function. It has no special assumptions about orthogonality, so it is quite general. However, for a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K^2) cost per iteration (for comparison: inexact LBFGS-based preconditioner has O(N*K) cost). INPUT PARAMETERS: State - structure stores algorithm state UpdateFreq- update frequency. Preconditioner is rebuilt after every UpdateFreq iterations. Recommended value: 10 or higher. Zero value means that good default value will be used. -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecexactlowrank(minnlcstate* state, ae_int_t updatefreq, ae_state *_state) { ae_assert(updatefreq>=0, "MinNLCSetPrecExactLowRank: UpdateFreq<0", _state); if( updatefreq==0 ) { updatefreq = 10; } state->prectype = 2; state->updatefreq = updatefreq; } /************************************************************************* This function sets preconditioner to "turned off" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. This function activates this test mode. Do not use it in production code to solve real-life problems. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetprecnone(minnlcstate* state, ae_state *_state) { state->updatefreq = 0; state->prectype = 0; } /************************************************************************* This function tells MinNLC unit to use Augmented Lagrangian algorithm for nonlinearly constrained optimization. This algorithm is a slight modification of one described in "A Modified Barrier-Augmented Lagrangian Method for Constrained Minimization (1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH. Augmented Lagrangian algorithm works by converting problem of minimizing F(x) subject to equality/inequality constraints to unconstrained problem of the form min[ f(x) + + Rho*PENALTY_EQ(x) + SHIFT_EQ(x,Nu1) + + Rho*PENALTY_INEQ(x) + SHIFT_INEQ(x,Nu2) ] where: * Rho is a fixed penalization coefficient * PENALTY_EQ(x) is a penalty term, which is used to APPROXIMATELY enforce equality constraints * SHIFT_EQ(x) is a special "shift" term which is used to "fine-tune" equality constraints, greatly increasing precision * PENALTY_INEQ(x) is a penalty term which is used to approximately enforce inequality constraints * SHIFT_INEQ(x) is a special "shift" term which is used to "fine-tune" inequality constraints, greatly increasing precision * Nu1/Nu2 are vectors of Lagrange coefficients which are fine-tuned during outer iterations of algorithm This version of AUL algorithm uses preconditioner, which greatly accelerates convergence. Because this algorithm is similar to penalty methods, it may perform steps into infeasible area. All kinds of constraints (boundary, linear and nonlinear ones) may be violated in intermediate points - and in the solution. However, properly configured AUL method is significantly better at handling constraints than barrier and/or penalty methods. The very basic outline of algorithm is given below: 1) first outer iteration is performed with "default" values of Lagrange multipliers Nu1/Nu2. Solution quality is low (candidate point can be too far away from true solution; large violation of constraints is possible) and is comparable with that of penalty methods. 2) subsequent outer iterations refine Lagrange multipliers and improve quality of the solution. INPUT PARAMETERS: State - structure which stores algorithm state Rho - penalty coefficient, Rho>0: * large enough that algorithm converges with desired precision. Minimum value is 10*max(S'*diag(H)*S), where S is a scale matrix (set by MinNLCSetScale) and H is a Hessian of the function being minimized. If you can not easily estimate Hessian norm, see our recommendations below. * not TOO large to prevent ill-conditioning * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * it is important to note that Rho is internally multiplied by scaling matrix, i.e. optimum value of Rho depends on scale of variables specified by MinNLCSetScale(). ItsCnt - number of outer iterations: * ItsCnt=0 means that small number of outer iterations is automatically chosen (10 iterations in current version). * ItsCnt=1 means that AUL algorithm performs just as usual barrier method. * ItsCnt>1 means that AUL algorithm performs specified number of outer iterations HOW TO CHOOSE PARAMETERS Nonlinear optimization is a tricky area and Augmented Lagrangian algorithm is sometimes hard to tune. Good values of Rho and ItsCnt are problem- specific. In order to help you we prepared following set of recommendations: * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * start from some small value of Rho and solve problem with just one outer iteration (ItcCnt=1). In this case algorithm behaves like penalty method. Increase Rho in 2x or 10x steps until you see that one outer iteration returns point which is "rough approximation to solution". It is very important to have Rho so large that penalty term becomes constraining i.e. modified function becomes highly convex in constrained directions. From the other side, too large Rho may prevent you from converging to the solution. You can diagnose it by studying number of inner iterations performed by algorithm: too few (5-10 on 1000-dimensional problem) or too many (orders of magnitude more than dimensionality) usually means that Rho is too large. * with just one outer iteration you usually have low-quality solution. Some constraints can be violated with very large margin, while other ones (which are NOT violated in the true solution) can push final point too far in the inner area of the feasible set. For example, if you have constraint x0>=0 and true solution x0=1, then merely a presence of "x0>=0" will introduce a bias towards larger values of x0. Say, algorithm may stop at x0=1.5 instead of 1.0. * after you found good Rho, you may increase number of outer iterations. ItsCnt=10 is a good value. Subsequent outer iteration will refine values of Lagrange multipliers. Constraints which were violated will be enforced, inactive constraints will be dropped (corresponding multipliers will be decreased). Ideally, you should see 10-1000x improvement in constraint handling (constraint violation is reduced). * if you see that algorithm converges to vicinity of solution, but additional outer iterations do not refine solution, it may mean that algorithm is unstable - it wanders around true solution, but can not approach it. Sometimes algorithm may be stabilized by increasing Rho one more time, making it 5x or 10x larger. SCALING OF CONSTRAINTS [IMPORTANT] AUL optimizer scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, because function being optimized is a mix of original function and constraint-dependent penalty functions, it is important to rescale both variables AND constraints. Say, if you minimize f(x)=x^2 subject to 1000000*x>=0, then you have constraint whose scale is different from that of target function (another example is 0.000001*x>=0). It is also possible to have constraints whose scales are misaligned: 1000000*x0>=0, 0.000001*x1<=0. Inappropriate scaling may ruin convergence because minimizing x^2 subject to x>=0 is NOT same as minimizing it subject to 1000000*x>=0. Because we know coefficients of boundary/linear constraints, we can automatically rescale and normalize them. However, there is no way to automatically rescale nonlinear constraints Gi(x) and Hi(x) - they are black boxes. It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to rescale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). WHAT IF IT DOES NOT CONVERGE? It is possible that AUL algorithm fails to converge to precise values of Lagrange multipliers. It stops somewhere around true solution, but candidate point is still too far from solution, and some constraints are violated. Such kind of failure is specific for Lagrangian algorithms - technically, they stop at some point, but this point is not constrained solution. There are exist several reasons why algorithm may fail to converge: a) too loose stopping criteria for inner iteration b) degenerate, redundant constraints c) target function has unconstrained extremum exactly at the boundary of some constraint d) numerical noise in the target function In all these cases algorithm is unstable - each outer iteration results in large and almost random step which improves handling of some constraints, but violates other ones (ideally outer iterations should form a sequence of progressively decreasing steps towards solution). First reason possible is that too loose stopping criteria for inner iteration were specified. Augmented Lagrangian algorithm solves a sequence of intermediate problems, and requries each of them to be solved with high precision. Insufficient precision results in incorrect update of Lagrange multipliers. Another reason is that you may have specified degenerate constraints: say, some constraint was repeated twice. In most cases AUL algorithm gracefully handles such situations, but sometimes it may spend too much time figuring out subtle degeneracies in constraint matrix. Third reason is tricky and hard to diagnose. Consider situation when you minimize f=x^2 subject to constraint x>=0. Unconstrained extremum is located exactly at the boundary of constrained area. In this case algorithm will tend to oscillate between negative and positive x. Each time it stops at x<0 it "reinforces" constraint x>=0, and each time it is bounced to x>0 it "relaxes" constraint (and is attracted to x<0). Such situation sometimes happens in problems with hidden symetries. Algorithm is got caught in a loop with Lagrange multipliers being continuously increased/decreased. Luckily, such loop forms after at least three iterations, so this problem can be solved by DECREASING number of outer iterations down to 1-2 and increasing penalty coefficient Rho as much as possible. Final reason is numerical noise. AUL algorithm is robust against moderate noise (more robust than, say, active set methods), but large noise may destabilize algorithm. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetalgoaul(minnlcstate* state, double rho, ae_int_t itscnt, ae_state *_state) { ae_assert(itscnt>=0, "MinNLCSetAlgoAUL: negative ItsCnt", _state); ae_assert(ae_isfinite(rho, _state), "MinNLCSetAlgoAUL: Rho is not finite", _state); ae_assert(ae_fp_greater(rho,(double)(0)), "MinNLCSetAlgoAUL: Rho<=0", _state); if( itscnt==0 ) { itscnt = 10; } state->aulitscnt = itscnt; state->rho = rho; state->solvertype = 0; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinNLCOptimize(). NOTE: algorithm passes two parameters to rep() callback - current point and penalized function value at current point. Important - function value which is returned is NOT function being minimized. It is sum of the value of the function being minimized - and penalty term. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcsetxrep(minnlcstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of MinNLCOptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of MinNLCOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinNLCOptimize() and specific function used to create optimizer. | USER PASSED TO MinNLCOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinNLCCreateF() | works FAILS MinNLCCreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and MinNLCOptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ ae_bool minnlciteration(minnlcstate* state, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t n; ae_int_t ng; ae_int_t nh; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { i = state->rstate.ia.ptr.p_int[0]; k = state->rstate.ia.ptr.p_int[1]; n = state->rstate.ia.ptr.p_int[2]; ng = state->rstate.ia.ptr.p_int[3]; nh = state->rstate.ia.ptr.p_int[4]; } else { i = -983; k = -989; n = -834; ng = 900; nh = -287; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } if( state->rstate.stage==4 ) { goto lbl_4; } if( state->rstate.stage==5 ) { goto lbl_5; } if( state->rstate.stage==6 ) { goto lbl_6; } if( state->rstate.stage==7 ) { goto lbl_7; } if( state->rstate.stage==8 ) { goto lbl_8; } /* * Routine body */ /* * Init */ state->repterminationtype = 0; state->repinneriterationscount = 0; state->repouteriterationscount = 0; state->repnfev = 0; state->repvaridx = 0; state->repfuncidx = 0; state->repdbgphase0its = 0; n = state->n; ng = state->ng; nh = state->nh; minnlc_clearrequestfields(state, _state); /* * Test gradient */ if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) { goto lbl_9; } rvectorsetlengthatleast(&state->xbase, n, _state); rvectorsetlengthatleast(&state->fbase, 1+ng+nh, _state); rvectorsetlengthatleast(&state->dfbase, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fm1, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fp1, 1+ng+nh, _state); rvectorsetlengthatleast(&state->dfm1, 1+ng+nh, _state); rvectorsetlengthatleast(&state->dfp1, 1+ng+nh, _state); state->needfij = ae_true; ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->xstart.ptr.p_double[0], 1, ae_v_len(0,n-1)); k = 0; lbl_11: if( k>n-1 ) { goto lbl_13; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 0; goto lbl_rcomm; lbl_0: ae_v_move(&state->fbase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->dfbase.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][k], state->j.stride, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->teststep; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->dfm1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][k], state->j.stride, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->teststep; state->rstate.stage = 2; goto lbl_rcomm; lbl_2: ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->dfp1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][k], state->j.stride, ae_v_len(0,ng+nh)); for(i=0; i<=ng+nh; i++) { if( !derivativecheck(state->fm1.ptr.p_double[i], state->dfm1.ptr.p_double[i], state->fp1.ptr.p_double[i], state->dfp1.ptr.p_double[i], state->fbase.ptr.p_double[i], state->dfbase.ptr.p_double[i], 2*state->s.ptr.p_double[k]*state->teststep, _state) ) { state->repfuncidx = i; state->repvaridx = k; state->repterminationtype = -7; result = ae_false; return result; } } k = k+1; goto lbl_11; lbl_13: state->needfij = ae_false; lbl_9: /* * AUL solver */ if( state->solvertype!=0 ) { goto lbl_14; } if( ae_fp_neq(state->diffstep,(double)(0)) ) { rvectorsetlengthatleast(&state->xbase, n, _state); rvectorsetlengthatleast(&state->fbase, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fm2, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fm1, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fp1, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fp2, 1+ng+nh, _state); } ae_vector_set_length(&state->rstateaul.ia, 8+1, _state); ae_vector_set_length(&state->rstateaul.ra, 7+1, _state); state->rstateaul.stage = -1; lbl_16: if( !minnlc_auliteration(state, _state) ) { goto lbl_17; } /* * Numerical differentiation (if needed) - intercept NeedFiJ * request and replace it by sequence of NeedFi requests */ if( !(ae_fp_neq(state->diffstep,(double)(0))&&state->needfij) ) { goto lbl_18; } state->needfij = ae_false; state->needfi = ae_true; ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); k = 0; lbl_20: if( k>n-1 ) { goto lbl_22; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; state->rstate.stage = 3; goto lbl_rcomm; lbl_3: ae_v_move(&state->fm2.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-0.5*state->s.ptr.p_double[k]*state->diffstep; state->rstate.stage = 4; goto lbl_rcomm; lbl_4: ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+0.5*state->s.ptr.p_double[k]*state->diffstep; state->rstate.stage = 5; goto lbl_rcomm; lbl_5: ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; state->rstate.stage = 6; goto lbl_rcomm; lbl_6: ae_v_move(&state->fp2.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); for(i=0; i<=ng+nh; i++) { state->j.ptr.pp_double[i][k] = (8*(state->fp1.ptr.p_double[i]-state->fm1.ptr.p_double[i])-(state->fp2.ptr.p_double[i]-state->fm2.ptr.p_double[i]))/(6*state->diffstep*state->s.ptr.p_double[i]); } k = k+1; goto lbl_20; lbl_22: ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 7; goto lbl_rcomm; lbl_7: /* * Restore previous values of fields and continue */ state->needfi = ae_false; state->needfij = ae_true; goto lbl_16; lbl_18: /* * Forward request to caller */ state->rstate.stage = 8; goto lbl_rcomm; lbl_8: goto lbl_16; lbl_17: result = ae_false; return result; lbl_14: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = i; state->rstate.ia.ptr.p_int[1] = k; state->rstate.ia.ptr.p_int[2] = n; state->rstate.ia.ptr.p_int[3] = ng; state->rstate.ia.ptr.p_int[4] = nh; return result; } /************************************************************************* MinNLC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken More information about fields of this structure can be found in the comments on MinNLCReport datatype. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcresults(minnlcstate* state, /* Real */ ae_vector* x, minnlcreport* rep, ae_state *_state) { ae_vector_clear(x); _minnlcreport_clear(rep); minnlcresultsbuf(state, x, rep, _state); } /************************************************************************* NLC results Buffered implementation of MinNLCResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcresultsbuf(minnlcstate* state, /* Real */ ae_vector* x, minnlcreport* rep, ae_state *_state) { ae_int_t i; if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } rep->iterationscount = state->repinneriterationscount; rep->nfev = state->repnfev; rep->varidx = state->repvaridx; rep->funcidx = state->repfuncidx; rep->terminationtype = state->repterminationtype; rep->dbgphase0its = state->repdbgphase0its; if( state->repterminationtype>0 ) { ae_v_move(&x->ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } else { for(i=0; i<=state->n-1; i++) { x->ptr.p_double[i] = _state->v_nan; } } } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnlcrestartfrom(minnlcstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; n = state->n; /* * First, check for errors in the inputs */ ae_assert(x->cnt>=n, "MinNLCRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * prepare RComm facilities */ ae_vector_set_length(&state->rstate.ia, 4+1, _state); state->rstate.stage = -1; minnlc_clearrequestfields(state, _state); } /************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinNLCOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, and Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinNLCSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcsetgradientcheck(minnlcstate* state, double teststep, ae_state *_state) { ae_assert(ae_isfinite(teststep, _state), "MinNLCSetGradientCheck: TestStep contains NaN or Infinite", _state); ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinNLCSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); state->teststep = teststep; } /************************************************************************* Penalty function for equality constraints. INPUT PARAMETERS: Alpha - function argument. Penalty function becomes large when Alpha approaches -1 or +1. It is defined for Alpha<=-1 or Alpha>=+1 - in this case infinite value is returned. OUTPUT PARAMETERS: F - depending on Alpha: * for Alpha in (-1+eps,+1-eps), F=F(Alpha) * for Alpha outside of interval, F is some very large number DF - depending on Alpha: * for Alpha in (-1+eps,+1-eps), DF=dF(Alpha)/dAlpha, exact numerical derivative. * otherwise, it is zero D2F - second derivative -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcequalitypenaltyfunction(double alpha, double* f, double* df, double* d2f, ae_state *_state) { *f = 0; *df = 0; *d2f = 0; *f = 0.5*alpha*alpha; *df = alpha; *d2f = 1.0; } /************************************************************************* "Penalty" function for inequality constraints, which is multiplied by penalty coefficient Rho. "Penalty" function plays only supplementary role - it helps to stabilize algorithm when solving non-convex problems. Because it is multiplied by fixed and large Rho - not Lagrange multiplier Nu which may become arbitrarily small! - it enforces convexity of the problem behind the boundary of the feasible area. This function is zero at the feasible area and in the close neighborhood, it becomes non-zero only at some distance (scaling is essential!) and grows quadratically. Penalty function must enter augmented Lagrangian as Rho*PENALTY(x-lowerbound) with corresponding changes being made for upper bound or other kinds of constraints. INPUT PARAMETERS: Alpha - function argument. Typically, if we have active constraint with precise Lagrange multiplier, we have Alpha around 1. Large positive Alpha's correspond to inner area of the feasible set. Alpha<1 corresponds to outer area of the feasible set. StabilizingPoint- point where F becomes non-zero. Must be negative value, at least -1, large values (hundreds) are possible. OUTPUT PARAMETERS: F - F(Alpha) DF - DF=dF(Alpha)/dAlpha, exact derivative D2F - second derivative NOTE: it is improtant to have significantly non-zero StabilizingPoint, because when it is large, shift term does not interfere with Lagrange multipliers converging to their final values. Thus, convergence of such modified AUL algorithm is still guaranteed by same set of theorems. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcinequalitypenaltyfunction(double alpha, double stabilizingpoint, double* f, double* df, double* d2f, ae_state *_state) { *f = 0; *df = 0; *d2f = 0; if( ae_fp_greater_eq(alpha,stabilizingpoint) ) { *f = 0.0; *df = 0.0; *d2f = 0.0; } else { alpha = alpha-stabilizingpoint; *f = 0.5*alpha*alpha; *df = alpha; *d2f = 1.0; } } /************************************************************************* "Shift" function for inequality constraints, which is multiplied by corresponding Lagrange multiplier. "Shift" function is a main factor which enforces inequality constraints. Inequality penalty function plays only supplementary role - it prevents accidental step deep into infeasible area when working with non-convex problems (read comments on corresponding function for more information). Shift function must enter augmented Lagrangian as Nu/Rho*SHIFT((x-lowerbound)*Rho+1) with corresponding changes being made for upper bound or other kinds of constraints. INPUT PARAMETERS: Alpha - function argument. Typically, if we have active constraint with precise Lagrange multiplier, we have Alpha around 1. Large positive Alpha's correspond to inner area of the feasible set. Alpha<1 corresponds to outer area of the feasible set. OUTPUT PARAMETERS: F - F(Alpha) DF - DF=dF(Alpha)/dAlpha, exact derivative D2F - second derivative -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ void minnlcinequalityshiftfunction(double alpha, double* f, double* df, double* d2f, ae_state *_state) { *f = 0; *df = 0; *d2f = 0; if( ae_fp_greater_eq(alpha,0.5) ) { *f = -ae_log(alpha, _state); *df = -1/alpha; *d2f = 1/(alpha*alpha); } else { *f = 2*alpha*alpha-4*alpha+(ae_log((double)(2), _state)+1.5); *df = 4*alpha-4; *d2f = (double)(4); } } /************************************************************************* Clears request fileds (to be sure that we don't forget to clear something) *************************************************************************/ static void minnlc_clearrequestfields(minnlcstate* state, ae_state *_state) { state->needfi = ae_false; state->needfij = ae_false; state->xupdated = ae_false; } /************************************************************************* Internal initialization subroutine. Sets default NLC solver with default criteria. *************************************************************************/ static void minnlc_minnlcinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnlcstate* state, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_matrix c; ae_vector ct; ae_frame_make(_state, &_frame_block); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); /* * Default params */ state->stabilizingpoint = -100.0; state->initialinequalitymultiplier = 1.0; /* * Initialize other params */ state->teststep = (double)(0); state->n = n; state->diffstep = diffstep; ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->hasbndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->hasbndu, n, _state); ae_vector_set_length(&state->s, n, _state); ae_vector_set_length(&state->xstart, n, _state); ae_vector_set_length(&state->xc, n, _state); ae_vector_set_length(&state->x, n, _state); for(i=0; i<=n-1; i++) { state->bndl.ptr.p_double[i] = _state->v_neginf; state->hasbndl.ptr.p_bool[i] = ae_false; state->bndu.ptr.p_double[i] = _state->v_posinf; state->hasbndu.ptr.p_bool[i] = ae_false; state->s.ptr.p_double[i] = 1.0; state->xstart.ptr.p_double[i] = x->ptr.p_double[i]; state->xc.ptr.p_double[i] = x->ptr.p_double[i]; } minnlcsetlc(state, &c, &ct, 0, _state); minnlcsetnlc(state, 0, 0, _state); minnlcsetcond(state, 0.0, 0.0, 0.0, 0, _state); minnlcsetxrep(state, ae_false, _state); minnlcsetalgoaul(state, 1.0E-3, 0, _state); minnlcsetprecinexact(state, _state); minlbfgscreate(n, ae_minint(minnlc_lbfgsfactor, n, _state), x, &state->auloptimizer, _state); minnlcrestartfrom(state, x, _state); ae_frame_leave(_state); } /************************************************************************* This function clears preconditioner for L-BFGS optimizer (sets it do default state); Parameters: AULOptimizer - optimizer to tune -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static void minnlc_clearpreconditioner(minlbfgsstate* auloptimizer, ae_state *_state) { minlbfgssetprecdefault(auloptimizer, _state); } /************************************************************************* This function updates preconditioner for L-BFGS optimizer. Parameters: PrecType - preconditioner type: * 0 for unpreconditioned iterations * 1 for inexact LBFGS * 2 for exact preconditioner update after each UpdateFreq its UpdateFreq - update frequency PrecCounter - iterations counter, must be zero on the first call, automatically increased by this function. This counter is used to implement "update-once-in-X-iterations" scheme. AULOptimizer - optimizer to tune X - current point Rho - penalty term GammaK - current estimate of Hessian norm (used for initialization of preconditioner). Can be zero, in which case Hessian is assumed to be unit. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static void minnlc_updatepreconditioner(ae_int_t prectype, ae_int_t updatefreq, ae_int_t* preccounter, minlbfgsstate* auloptimizer, /* Real */ ae_vector* x, double rho, double gammak, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* hasbndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* hasbndu, /* Real */ ae_vector* nubc, /* Real */ ae_matrix* cleic, /* Real */ ae_vector* nulc, /* Real */ ae_vector* fi, /* Real */ ae_matrix* jac, /* Real */ ae_vector* nunlc, /* Real */ ae_vector* bufd, /* Real */ ae_vector* bufc, /* Real */ ae_matrix* bufw, ae_int_t n, ae_int_t nec, ae_int_t nic, ae_int_t ng, ae_int_t nh, ae_state *_state) { ae_int_t i; double v; double p; double dp; double d2p; ae_assert(ae_fp_greater(rho,(double)(0)), "MinNLC: integrity check failed", _state); rvectorsetlengthatleast(bufd, n, _state); rvectorsetlengthatleast(bufc, nec+nic+ng+nh, _state); rmatrixsetlengthatleast(bufw, nec+nic+ng+nh, n, _state); /* * Preconditioner before update from barrier/penalty functions */ if( ae_fp_eq(gammak,(double)(0)) ) { gammak = (double)(1); } for(i=0; i<=n-1; i++) { bufd->ptr.p_double[i] = gammak; } /* * Update diagonal Hessian using nonlinearity from boundary constraints: * * penalty term from equality constraints * * shift term from inequality constraints * * NOTE: penalty term for inequality constraints is ignored because it * is large only in exceptional cases. */ for(i=0; i<=n-1; i++) { if( (hasbndl->ptr.p_bool[i]&&hasbndu->ptr.p_bool[i])&&ae_fp_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) { minnlcequalitypenaltyfunction((x->ptr.p_double[i]-bndl->ptr.p_double[i])*rho, &p, &dp, &d2p, _state); bufd->ptr.p_double[i] = bufd->ptr.p_double[i]+d2p*rho; continue; } if( hasbndl->ptr.p_bool[i] ) { minnlcinequalityshiftfunction((x->ptr.p_double[i]-bndl->ptr.p_double[i])*rho+1, &p, &dp, &d2p, _state); bufd->ptr.p_double[i] = bufd->ptr.p_double[i]+nubc->ptr.p_double[2*i+0]*d2p*rho; } if( hasbndu->ptr.p_bool[i] ) { minnlcinequalityshiftfunction((bndu->ptr.p_double[i]-x->ptr.p_double[i])*rho+1, &p, &dp, &d2p, _state); bufd->ptr.p_double[i] = bufd->ptr.p_double[i]+nubc->ptr.p_double[2*i+1]*d2p*rho; } } /* * Process linear constraints */ for(i=0; i<=nec+nic-1; i++) { ae_v_move(&bufw->ptr.pp_double[i][0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&cleic->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-cleic->ptr.pp_double[i][n]; if( iptr.p_double[i] = d2p*rho; } else { /* * Inequality constraint */ minnlcinequalityshiftfunction(-v*rho+1, &p, &dp, &d2p, _state); bufc->ptr.p_double[i] = nulc->ptr.p_double[i]*d2p*rho; } } /* * Process nonlinear constraints */ for(i=0; i<=ng+nh-1; i++) { ae_v_move(&bufw->ptr.pp_double[nec+nic+i][0], 1, &jac->ptr.pp_double[1+i][0], 1, ae_v_len(0,n-1)); v = fi->ptr.p_double[1+i]; if( iptr.p_double[nec+nic+i] = d2p*rho; } else { /* * Inequality constraint */ minnlcinequalityshiftfunction(-v*rho+1, &p, &dp, &d2p, _state); bufc->ptr.p_double[nec+nic+i] = nunlc->ptr.p_double[i]*d2p*rho; } } if( prectype==1 ) { minlbfgssetprecrankklbfgsfast(auloptimizer, bufd, bufc, bufw, nec+nic+ng+nh, _state); } if( prectype==2&&*preccounter%updatefreq==0 ) { minlbfgssetpreclowrankexact(auloptimizer, bufd, bufc, bufw, nec+nic+ng+nh, _state); } inc(preccounter, _state); } /************************************************************************* This subroutine adds penalty from boundary constraints to target function and its gradient. Penalty function is one which is used for main AUL cycle - with Lagrange multipliers and infinite at the barrier and beyond. Parameters: X[] - current point BndL[], BndU[] - boundary constraints HasBndL[], HasBndU[] - I-th element is True if corresponding constraint is present NuBC[] - Lagrange multipliers corresponding to constraints Rho - penalty term StabilizingPoint - branch point for inequality stabilizing term F - function value to modify G - gradient to modify -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static void minnlc_penaltybc(/* Real */ ae_vector* x, /* Real */ ae_vector* bndl, /* Boolean */ ae_vector* hasbndl, /* Real */ ae_vector* bndu, /* Boolean */ ae_vector* hasbndu, /* Real */ ae_vector* nubc, ae_int_t n, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t i; double p; double dp; double d2p; for(i=0; i<=n-1; i++) { if( (hasbndl->ptr.p_bool[i]&&hasbndu->ptr.p_bool[i])&&ae_fp_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) { /* * I-th boundary constraint is of equality-type */ minnlcequalitypenaltyfunction((x->ptr.p_double[i]-bndl->ptr.p_double[i])*rho, &p, &dp, &d2p, _state); *f = *f+p/rho-nubc->ptr.p_double[2*i+0]*(x->ptr.p_double[i]-bndl->ptr.p_double[i]); g->ptr.p_double[i] = g->ptr.p_double[i]+dp-nubc->ptr.p_double[2*i+0]; continue; } if( hasbndl->ptr.p_bool[i] ) { /* * Handle lower bound */ minnlcinequalitypenaltyfunction(x->ptr.p_double[i]-bndl->ptr.p_double[i], stabilizingpoint, &p, &dp, &d2p, _state); *f = *f+rho*p; g->ptr.p_double[i] = g->ptr.p_double[i]+rho*dp; minnlcinequalityshiftfunction((x->ptr.p_double[i]-bndl->ptr.p_double[i])*rho+1, &p, &dp, &d2p, _state); *f = *f+p/rho*nubc->ptr.p_double[2*i+0]; g->ptr.p_double[i] = g->ptr.p_double[i]+dp*nubc->ptr.p_double[2*i+0]; } if( hasbndu->ptr.p_bool[i] ) { /* * Handle upper bound */ minnlcinequalitypenaltyfunction(bndu->ptr.p_double[i]-x->ptr.p_double[i], stabilizingpoint, &p, &dp, &d2p, _state); *f = *f+rho*p; g->ptr.p_double[i] = g->ptr.p_double[i]-rho*dp; minnlcinequalityshiftfunction((bndu->ptr.p_double[i]-x->ptr.p_double[i])*rho+1, &p, &dp, &d2p, _state); *f = *f+p/rho*nubc->ptr.p_double[2*i+1]; g->ptr.p_double[i] = g->ptr.p_double[i]-dp*nubc->ptr.p_double[2*i+1]; } } } /************************************************************************* This subroutine adds penalty from linear constraints to target function and its gradient. Penalty function is one which is used for main AUL cycle - with Lagrange multipliers and infinite at the barrier and beyond. Parameters: X[] - current point CLEIC[] - constraints matrix, first NEC rows are equality ones, next NIC rows are inequality ones. array[NEC+NIC,N+1] NuLC[] - Lagrange multipliers corresponding to constraints, array[NEC+NIC] N - dimensionalty NEC - number of equality constraints NIC - number of inequality constraints. Rho - penalty term StabilizingPoint - branch point for inequality stabilizing term F - function value to modify G - gradient to modify -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static void minnlc_penaltylc(/* Real */ ae_vector* x, /* Real */ ae_matrix* cleic, /* Real */ ae_vector* nulc, ae_int_t n, ae_int_t nec, ae_int_t nic, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t i; double v; double vv; double p; double dp; double d2p; for(i=0; i<=nec+nic-1; i++) { v = ae_v_dotproduct(&cleic->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-cleic->ptr.pp_double[i][n]; if( iptr.p_double[0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); *f = *f-nulc->ptr.p_double[i]*v; vv = nulc->ptr.p_double[i]; ae_v_subd(&g->ptr.p_double[0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } else { /* * Inequality constraint */ minnlcinequalitypenaltyfunction(-v, stabilizingpoint, &p, &dp, &d2p, _state); *f = *f+p*rho; vv = dp*rho; ae_v_subd(&g->ptr.p_double[0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); minnlcinequalityshiftfunction(-v*rho+1, &p, &dp, &d2p, _state); *f = *f+p/rho*nulc->ptr.p_double[i]; vv = dp*nulc->ptr.p_double[i]; ae_v_subd(&g->ptr.p_double[0], 1, &cleic->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } } } /************************************************************************* This subroutine adds penalty from nonlinear constraints to target function and its gradient. Penalty function is one which is used for main AUL cycle - with Lagrange multipliers and infinite at the barrier and beyond. Parameters: Fi[] - function vector: * 1 component for function being minimized * NG components for equality constraints G_i(x)=0 * NH components for inequality constraints H_i(x)<=0 J[] - Jacobian matrix, array[1+NG+NH,N] NuNLC[] - Lagrange multipliers corresponding to constraints, array[NG+NH] N - number of dimensions NG - number of equality constraints NH - number of inequality constraints Rho - penalty term StabilizingPoint - branch point for inequality stabilizing term F - function value to modify G - gradient to modify -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static void minnlc_penaltynlc(/* Real */ ae_vector* fi, /* Real */ ae_matrix* j, /* Real */ ae_vector* nunlc, ae_int_t n, ae_int_t ng, ae_int_t nh, double rho, double stabilizingpoint, double* f, /* Real */ ae_vector* g, ae_state *_state) { ae_int_t i; double v; double vv; double p; double dp; double d2p; /* * IMPORTANT: loop starts from 1, not zero! */ for(i=1; i<=ng+nh; i++) { v = fi->ptr.p_double[i]; if( i<=ng ) { /* * Equality constraint */ minnlcequalitypenaltyfunction(v*rho, &p, &dp, &d2p, _state); *f = *f+p/rho; vv = dp; ae_v_addd(&g->ptr.p_double[0], 1, &j->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); *f = *f-nunlc->ptr.p_double[i-1]*v; vv = nunlc->ptr.p_double[i-1]; ae_v_subd(&g->ptr.p_double[0], 1, &j->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } else { /* * Inequality constraint */ minnlcinequalitypenaltyfunction(-v, stabilizingpoint, &p, &dp, &d2p, _state); *f = *f+p*rho; vv = dp*rho; ae_v_subd(&g->ptr.p_double[0], 1, &j->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); minnlcinequalityshiftfunction(-v*rho+1, &p, &dp, &d2p, _state); *f = *f+p/rho*nunlc->ptr.p_double[i-1]; vv = dp*nunlc->ptr.p_double[i-1]; ae_v_subd(&g->ptr.p_double[0], 1, &j->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); } } } /************************************************************************* This function performs actual processing for AUL algorith. It expects that caller redirects its reverse communication requests NeedFiJ/XUpdated to external user who will provide analytic derivative (or handle reports about progress). In case external user does not have analytic derivative, it is responsibility of caller to intercept NeedFiJ request and replace it with appropriate numerical differentiation scheme. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/ static ae_bool minnlc_auliteration(minnlcstate* state, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t ng; ae_int_t nh; ae_int_t i; ae_int_t j; ae_int_t outerit; ae_int_t preccounter; double v; double vv; double p; double dp; double d2p; double v0; double v1; double v2; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstateaul.stage>=0 ) { n = state->rstateaul.ia.ptr.p_int[0]; nec = state->rstateaul.ia.ptr.p_int[1]; nic = state->rstateaul.ia.ptr.p_int[2]; ng = state->rstateaul.ia.ptr.p_int[3]; nh = state->rstateaul.ia.ptr.p_int[4]; i = state->rstateaul.ia.ptr.p_int[5]; j = state->rstateaul.ia.ptr.p_int[6]; outerit = state->rstateaul.ia.ptr.p_int[7]; preccounter = state->rstateaul.ia.ptr.p_int[8]; v = state->rstateaul.ra.ptr.p_double[0]; vv = state->rstateaul.ra.ptr.p_double[1]; p = state->rstateaul.ra.ptr.p_double[2]; dp = state->rstateaul.ra.ptr.p_double[3]; d2p = state->rstateaul.ra.ptr.p_double[4]; v0 = state->rstateaul.ra.ptr.p_double[5]; v1 = state->rstateaul.ra.ptr.p_double[6]; v2 = state->rstateaul.ra.ptr.p_double[7]; } else { n = 364; nec = 214; nic = -338; ng = -686; nh = 912; i = 585; j = 497; outerit = -271; preccounter = -581; v = 745; vv = -533; p = -77; dp = 678; d2p = -293; v0 = 316; v1 = 647; v2 = -756; } if( state->rstateaul.stage==0 ) { goto lbl_0; } if( state->rstateaul.stage==1 ) { goto lbl_1; } if( state->rstateaul.stage==2 ) { goto lbl_2; } /* * Routine body */ ae_assert(state->solvertype==0, "MinNLC: internal error", _state); n = state->n; nec = state->nec; nic = state->nic; ng = state->ng; nh = state->nh; /* * Prepare scaled problem */ rvectorsetlengthatleast(&state->scaledbndl, n, _state); rvectorsetlengthatleast(&state->scaledbndu, n, _state); rmatrixsetlengthatleast(&state->scaledcleic, nec+nic, n+1, _state); for(i=0; i<=n-1; i++) { if( state->hasbndl.ptr.p_bool[i] ) { state->scaledbndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]/state->s.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i] ) { state->scaledbndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]/state->s.ptr.p_double[i]; } state->xc.ptr.p_double[i] = state->xstart.ptr.p_double[i]/state->s.ptr.p_double[i]; } for(i=0; i<=nec+nic-1; i++) { /* * Scale and normalize linear constraints */ vv = 0.0; for(j=0; j<=n-1; j++) { v = state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; state->scaledcleic.ptr.pp_double[i][j] = v; vv = vv+v*v; } vv = ae_sqrt(vv, _state); state->scaledcleic.ptr.pp_double[i][n] = state->cleic.ptr.pp_double[i][n]; if( ae_fp_greater(vv,(double)(0)) ) { for(j=0; j<=n; j++) { state->scaledcleic.ptr.pp_double[i][j] = state->scaledcleic.ptr.pp_double[i][j]/vv; } } } /* * Prepare stopping criteria */ minlbfgssetcond(&state->auloptimizer, state->epsg, state->epsf, state->epsx, state->maxits, _state); /* * Main AUL cycle: * * prepare Lagrange multipliers NuNB/NuLC * * set GammaK (current estimate of Hessian norm) to 0.0 and XKPresent to False */ rvectorsetlengthatleast(&state->nubc, 2*n, _state); rvectorsetlengthatleast(&state->nulc, nec+nic, _state); rvectorsetlengthatleast(&state->nunlc, ng+nh, _state); rvectorsetlengthatleast(&state->xk, n, _state); rvectorsetlengthatleast(&state->gk, n, _state); rvectorsetlengthatleast(&state->xk1, n, _state); rvectorsetlengthatleast(&state->gk1, n, _state); for(i=0; i<=n-1; i++) { state->nubc.ptr.p_double[2*i+0] = 0.0; state->nubc.ptr.p_double[2*i+1] = 0.0; if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { continue; } if( state->hasbndl.ptr.p_bool[i] ) { state->nubc.ptr.p_double[2*i+0] = state->initialinequalitymultiplier; } if( state->hasbndu.ptr.p_bool[i] ) { state->nubc.ptr.p_double[2*i+1] = state->initialinequalitymultiplier; } } for(i=0; i<=nec-1; i++) { state->nulc.ptr.p_double[i] = 0.0; } for(i=0; i<=nic-1; i++) { state->nulc.ptr.p_double[nec+i] = state->initialinequalitymultiplier; } for(i=0; i<=ng-1; i++) { state->nunlc.ptr.p_double[i] = 0.0; } for(i=0; i<=nh-1; i++) { state->nunlc.ptr.p_double[ng+i] = state->initialinequalitymultiplier; } state->gammak = 0.0; state->xkpresent = ae_false; ae_assert(state->aulitscnt>0, "MinNLC: integrity check failed", _state); minnlc_clearpreconditioner(&state->auloptimizer, _state); outerit = 0; lbl_3: if( outerit>state->aulitscnt-1 ) { goto lbl_5; } /* * Optimize with current Lagrange multipliers * * NOTE: this code expects and checks that line search ends in the * point which is used as beginning for the next search. Such * guarantee is given by MCSRCH function. L-BFGS optimizer * does not formally guarantee it, but it follows same rule. * Below we a) rely on such property of the optimizer, and b) * assert that it is true, in order to fail loudly if it is * not true. * * NOTE: security check for NAN/INF in F/G is responsibility of * LBFGS optimizer. AUL optimizer checks for NAN/INF only * when we update Lagrange multipliers. */ preccounter = 0; minlbfgssetxrep(&state->auloptimizer, ae_true, _state); minlbfgsrestartfrom(&state->auloptimizer, &state->xc, _state); lbl_6: if( !minlbfgsiteration(&state->auloptimizer, _state) ) { goto lbl_7; } if( !state->auloptimizer.needfg ) { goto lbl_8; } /* * Un-scale X, evaluate F/G/H, re-scale Jacobian */ for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = state->auloptimizer.x.ptr.p_double[i]*state->s.ptr.p_double[i]; } state->needfij = ae_true; state->rstateaul.stage = 0; goto lbl_rcomm; lbl_0: state->needfij = ae_false; for(i=0; i<=ng+nh; i++) { for(j=0; j<=n-1; j++) { state->j.ptr.pp_double[i][j] = state->j.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; } } /* * Store data for estimation of Hessian norm: * * current point (re-scaled) * * gradient of the target function (re-scaled, unmodified) */ ae_v_move(&state->xk1.ptr.p_double[0], 1, &state->auloptimizer.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->gk1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); /* * Function being optimized */ state->auloptimizer.f = state->fi.ptr.p_double[0]; for(i=0; i<=n-1; i++) { state->auloptimizer.g.ptr.p_double[i] = state->j.ptr.pp_double[0][i]; } /* * Penalty for violation of boundary/linear/nonlinear constraints */ minnlc_penaltybc(&state->auloptimizer.x, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, &state->nubc, n, state->rho, state->stabilizingpoint, &state->auloptimizer.f, &state->auloptimizer.g, _state); minnlc_penaltylc(&state->auloptimizer.x, &state->scaledcleic, &state->nulc, n, nec, nic, state->rho, state->stabilizingpoint, &state->auloptimizer.f, &state->auloptimizer.g, _state); minnlc_penaltynlc(&state->fi, &state->j, &state->nunlc, n, ng, nh, state->rho, state->stabilizingpoint, &state->auloptimizer.f, &state->auloptimizer.g, _state); /* * To optimizer */ goto lbl_6; lbl_8: if( !state->auloptimizer.xupdated ) { goto lbl_10; } /* * Report current point (if needed) */ if( !state->xrep ) { goto lbl_12; } for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = state->auloptimizer.x.ptr.p_double[i]*state->s.ptr.p_double[i]; } state->f = state->auloptimizer.f; state->xupdated = ae_true; state->rstateaul.stage = 1; goto lbl_rcomm; lbl_1: state->xupdated = ae_false; lbl_12: /* * Update GammaK */ if( state->xkpresent ) { /* * XK/GK store beginning of current line search, and XK1/GK1 * store data for the end of the line search: * * first, we Assert() that XK1 (last point where function * was evaluated) is same as AULOptimizer.X (what is * reported by RComm interface * * calculate step length V2. * * If V2>HessEstTol, then: * * calculate V0 - directional derivative at XK, * and V1 - directional derivative at XK1 * * set GammaK to Max(GammaK, |V1-V0|/V2) */ for(i=0; i<=n-1; i++) { ae_assert(ae_fp_less_eq(ae_fabs(state->auloptimizer.x.ptr.p_double[i]-state->xk1.ptr.p_double[i], _state),100*ae_machineepsilon), "MinNLC: integrity check failed, unexpected behavior of LBFGS optimizer", _state); } v2 = 0.0; for(i=0; i<=n-1; i++) { v2 = v2+ae_sqr(state->xk.ptr.p_double[i]-state->xk1.ptr.p_double[i], _state); } v2 = ae_sqrt(v2, _state); if( ae_fp_greater(v2,minnlc_hessesttol) ) { v0 = 0.0; v1 = 0.0; for(i=0; i<=n-1; i++) { v = (state->xk.ptr.p_double[i]-state->xk1.ptr.p_double[i])/v2; v0 = v0+state->gk.ptr.p_double[i]*v; v1 = v1+state->gk1.ptr.p_double[i]*v; } state->gammak = ae_maxreal(state->gammak, ae_fabs(v1-v0, _state)/v2, _state); } } else { /* * Beginning of the first line search, XK is not yet initialized. */ ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->gk.ptr.p_double[0], 1, &state->gk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->xkpresent = ae_true; } /* * Update preconsitioner using current GammaK */ minnlc_updatepreconditioner(state->prectype, state->updatefreq, &preccounter, &state->auloptimizer, &state->auloptimizer.x, state->rho, state->gammak, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, &state->nubc, &state->scaledcleic, &state->nulc, &state->fi, &state->j, &state->nunlc, &state->bufd, &state->bufc, &state->bufw, n, nec, nic, ng, nh, _state); goto lbl_6; lbl_10: ae_assert(ae_false, "MinNLC: integrity check failed", _state); goto lbl_6; lbl_7: minlbfgsresultsbuf(&state->auloptimizer, &state->xc, &state->aulreport, _state); state->repinneriterationscount = state->repinneriterationscount+state->aulreport.iterationscount; state->repnfev = state->repnfev+state->aulreport.nfev; state->repterminationtype = state->aulreport.terminationtype; inc(&state->repouteriterationscount, _state); if( state->repterminationtype<=0 ) { goto lbl_5; } /* * 1. Evaluate F/J * 2. Check for NAN/INF in F/J: we just calculate sum of their * components, it should be enough to reduce vector/matrix to * just one value which either "normal" (all summands were "normal") * or NAN/INF (at least one summand was NAN/INF). * 3. Update Lagrange multipliers */ for(i=0; i<=n-1; i++) { state->x.ptr.p_double[i] = state->xc.ptr.p_double[i]*state->s.ptr.p_double[i]; } state->needfij = ae_true; state->rstateaul.stage = 2; goto lbl_rcomm; lbl_2: state->needfij = ae_false; v = 0.0; for(i=0; i<=ng+nh; i++) { v = 0.1*v+state->fi.ptr.p_double[i]; for(j=0; j<=n-1; j++) { v = 0.1*v+state->j.ptr.pp_double[i][j]; } } if( !ae_isfinite(v, _state) ) { /* * Abnormal termination - infinities in function/gradient */ state->repterminationtype = -8; result = ae_false; return result; } for(i=0; i<=ng+nh; i++) { for(j=0; j<=n-1; j++) { state->j.ptr.pp_double[i][j] = state->j.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; } } for(i=0; i<=n-1; i++) { /* * Process coefficients corresponding to equality-type * constraints. */ if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { minnlcequalitypenaltyfunction((state->xc.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*state->rho, &p, &dp, &d2p, _state); state->nubc.ptr.p_double[2*i+0] = state->nubc.ptr.p_double[2*i+0]-dp; continue; } /* * Process coefficients corresponding to inequality-type * constraints. These coefficients have limited growth/decay * per iteration which helps to stabilize algorithm. */ ae_assert(ae_fp_greater(minnlc_aulmaxgrowth,1.0), "MinNLC: integrity error", _state); if( state->hasbndl.ptr.p_bool[i] ) { minnlcinequalityshiftfunction((state->xc.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*state->rho+1, &p, &dp, &d2p, _state); v = ae_fabs(dp, _state); v = ae_minreal(v, minnlc_aulmaxgrowth, _state); v = ae_maxreal(v, 1/minnlc_aulmaxgrowth, _state); state->nubc.ptr.p_double[2*i+0] = state->nubc.ptr.p_double[2*i+0]*v; } if( state->hasbndu.ptr.p_bool[i] ) { minnlcinequalityshiftfunction((state->scaledbndu.ptr.p_double[i]-state->xc.ptr.p_double[i])*state->rho+1, &p, &dp, &d2p, _state); v = ae_fabs(dp, _state); v = ae_minreal(v, minnlc_aulmaxgrowth, _state); v = ae_maxreal(v, 1/minnlc_aulmaxgrowth, _state); state->nubc.ptr.p_double[2*i+1] = state->nubc.ptr.p_double[2*i+1]*v; } } for(i=0; i<=nec+nic-1; i++) { v = ae_v_dotproduct(&state->scaledcleic.ptr.pp_double[i][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-state->scaledcleic.ptr.pp_double[i][n]; if( irho, &p, &dp, &d2p, _state); state->nulc.ptr.p_double[i] = state->nulc.ptr.p_double[i]-dp; } else { minnlcinequalityshiftfunction(-v*state->rho+1, &p, &dp, &d2p, _state); v = ae_fabs(dp, _state); v = ae_minreal(v, minnlc_aulmaxgrowth, _state); v = ae_maxreal(v, 1/minnlc_aulmaxgrowth, _state); state->nulc.ptr.p_double[i] = state->nulc.ptr.p_double[i]*v; } } for(i=1; i<=ng+nh; i++) { /* * NOTE: loop index must start from 1, not zero! */ v = state->fi.ptr.p_double[i]; if( i<=ng ) { minnlcequalitypenaltyfunction(v*state->rho, &p, &dp, &d2p, _state); state->nunlc.ptr.p_double[i-1] = state->nunlc.ptr.p_double[i-1]-dp; } else { minnlcinequalityshiftfunction(-v*state->rho+1, &p, &dp, &d2p, _state); v = ae_fabs(dp, _state); v = ae_minreal(v, minnlc_aulmaxgrowth, _state); v = ae_maxreal(v, 1/minnlc_aulmaxgrowth, _state); state->nunlc.ptr.p_double[i-1] = state->nunlc.ptr.p_double[i-1]*v; } } outerit = outerit+1; goto lbl_3; lbl_5: for(i=0; i<=n-1; i++) { state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]*state->s.ptr.p_double[i]; } result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstateaul.ia.ptr.p_int[0] = n; state->rstateaul.ia.ptr.p_int[1] = nec; state->rstateaul.ia.ptr.p_int[2] = nic; state->rstateaul.ia.ptr.p_int[3] = ng; state->rstateaul.ia.ptr.p_int[4] = nh; state->rstateaul.ia.ptr.p_int[5] = i; state->rstateaul.ia.ptr.p_int[6] = j; state->rstateaul.ia.ptr.p_int[7] = outerit; state->rstateaul.ia.ptr.p_int[8] = preccounter; state->rstateaul.ra.ptr.p_double[0] = v; state->rstateaul.ra.ptr.p_double[1] = vv; state->rstateaul.ra.ptr.p_double[2] = p; state->rstateaul.ra.ptr.p_double[3] = dp; state->rstateaul.ra.ptr.p_double[4] = d2p; state->rstateaul.ra.ptr.p_double[5] = v0; state->rstateaul.ra.ptr.p_double[6] = v1; state->rstateaul.ra.ptr.p_double[7] = v2; return result; } void _minnlcstate_init(void* _p, ae_state *_state) { minnlcstate *p = (minnlcstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state); ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->fi, 0, DT_REAL, _state); ae_matrix_init(&p->j, 0, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); _rcommstate_init(&p->rstateaul, _state); ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state); ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state); ae_matrix_init(&p->scaledcleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->xc, 0, DT_REAL, _state); ae_vector_init(&p->xstart, 0, DT_REAL, _state); ae_vector_init(&p->xbase, 0, DT_REAL, _state); ae_vector_init(&p->fbase, 0, DT_REAL, _state); ae_vector_init(&p->dfbase, 0, DT_REAL, _state); ae_vector_init(&p->fm2, 0, DT_REAL, _state); ae_vector_init(&p->fm1, 0, DT_REAL, _state); ae_vector_init(&p->fp1, 0, DT_REAL, _state); ae_vector_init(&p->fp2, 0, DT_REAL, _state); ae_vector_init(&p->dfm1, 0, DT_REAL, _state); ae_vector_init(&p->dfp1, 0, DT_REAL, _state); ae_vector_init(&p->bufd, 0, DT_REAL, _state); ae_vector_init(&p->bufc, 0, DT_REAL, _state); ae_matrix_init(&p->bufw, 0, 0, DT_REAL, _state); ae_vector_init(&p->xk, 0, DT_REAL, _state); ae_vector_init(&p->xk1, 0, DT_REAL, _state); ae_vector_init(&p->gk, 0, DT_REAL, _state); ae_vector_init(&p->gk1, 0, DT_REAL, _state); _minlbfgsstate_init(&p->auloptimizer, _state); _minlbfgsreport_init(&p->aulreport, _state); ae_vector_init(&p->nubc, 0, DT_REAL, _state); ae_vector_init(&p->nulc, 0, DT_REAL, _state); ae_vector_init(&p->nunlc, 0, DT_REAL, _state); } void _minnlcstate_init_copy(void* _dst, void* _src, ae_state *_state) { minnlcstate *dst = (minnlcstate*)_dst; minnlcstate *src = (minnlcstate*)_src; dst->stabilizingpoint = src->stabilizingpoint; dst->initialinequalitymultiplier = src->initialinequalitymultiplier; dst->solvertype = src->solvertype; dst->prectype = src->prectype; dst->updatefreq = src->updatefreq; dst->rho = src->rho; dst->n = src->n; dst->epsg = src->epsg; dst->epsf = src->epsf; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->aulitscnt = src->aulitscnt; dst->xrep = src->xrep; dst->diffstep = src->diffstep; dst->teststep = src->teststep; ae_vector_init_copy(&dst->s, &src->s, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state); ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state); dst->nec = src->nec; dst->nic = src->nic; ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); dst->ng = src->ng; dst->nh = src->nh; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->fi, &src->fi, _state); ae_matrix_init_copy(&dst->j, &src->j, _state); dst->needfij = src->needfij; dst->needfi = src->needfi; dst->xupdated = src->xupdated; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); _rcommstate_init_copy(&dst->rstateaul, &src->rstateaul, _state); ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state); ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state); ae_matrix_init_copy(&dst->scaledcleic, &src->scaledcleic, _state); ae_vector_init_copy(&dst->xc, &src->xc, _state); ae_vector_init_copy(&dst->xstart, &src->xstart, _state); ae_vector_init_copy(&dst->xbase, &src->xbase, _state); ae_vector_init_copy(&dst->fbase, &src->fbase, _state); ae_vector_init_copy(&dst->dfbase, &src->dfbase, _state); ae_vector_init_copy(&dst->fm2, &src->fm2, _state); ae_vector_init_copy(&dst->fm1, &src->fm1, _state); ae_vector_init_copy(&dst->fp1, &src->fp1, _state); ae_vector_init_copy(&dst->fp2, &src->fp2, _state); ae_vector_init_copy(&dst->dfm1, &src->dfm1, _state); ae_vector_init_copy(&dst->dfp1, &src->dfp1, _state); ae_vector_init_copy(&dst->bufd, &src->bufd, _state); ae_vector_init_copy(&dst->bufc, &src->bufc, _state); ae_matrix_init_copy(&dst->bufw, &src->bufw, _state); ae_vector_init_copy(&dst->xk, &src->xk, _state); ae_vector_init_copy(&dst->xk1, &src->xk1, _state); ae_vector_init_copy(&dst->gk, &src->gk, _state); ae_vector_init_copy(&dst->gk1, &src->gk1, _state); dst->gammak = src->gammak; dst->xkpresent = src->xkpresent; _minlbfgsstate_init_copy(&dst->auloptimizer, &src->auloptimizer, _state); _minlbfgsreport_init_copy(&dst->aulreport, &src->aulreport, _state); ae_vector_init_copy(&dst->nubc, &src->nubc, _state); ae_vector_init_copy(&dst->nulc, &src->nulc, _state); ae_vector_init_copy(&dst->nunlc, &src->nunlc, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repnfev = src->repnfev; dst->repvaridx = src->repvaridx; dst->repfuncidx = src->repfuncidx; dst->repterminationtype = src->repterminationtype; dst->repdbgphase0its = src->repdbgphase0its; } void _minnlcstate_clear(void* _p) { minnlcstate *p = (minnlcstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->s); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->hasbndl); ae_vector_clear(&p->hasbndu); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->x); ae_vector_clear(&p->fi); ae_matrix_clear(&p->j); _rcommstate_clear(&p->rstate); _rcommstate_clear(&p->rstateaul); ae_vector_clear(&p->scaledbndl); ae_vector_clear(&p->scaledbndu); ae_matrix_clear(&p->scaledcleic); ae_vector_clear(&p->xc); ae_vector_clear(&p->xstart); ae_vector_clear(&p->xbase); ae_vector_clear(&p->fbase); ae_vector_clear(&p->dfbase); ae_vector_clear(&p->fm2); ae_vector_clear(&p->fm1); ae_vector_clear(&p->fp1); ae_vector_clear(&p->fp2); ae_vector_clear(&p->dfm1); ae_vector_clear(&p->dfp1); ae_vector_clear(&p->bufd); ae_vector_clear(&p->bufc); ae_matrix_clear(&p->bufw); ae_vector_clear(&p->xk); ae_vector_clear(&p->xk1); ae_vector_clear(&p->gk); ae_vector_clear(&p->gk1); _minlbfgsstate_clear(&p->auloptimizer); _minlbfgsreport_clear(&p->aulreport); ae_vector_clear(&p->nubc); ae_vector_clear(&p->nulc); ae_vector_clear(&p->nunlc); } void _minnlcstate_destroy(void* _p) { minnlcstate *p = (minnlcstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->s); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->hasbndl); ae_vector_destroy(&p->hasbndu); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->x); ae_vector_destroy(&p->fi); ae_matrix_destroy(&p->j); _rcommstate_destroy(&p->rstate); _rcommstate_destroy(&p->rstateaul); ae_vector_destroy(&p->scaledbndl); ae_vector_destroy(&p->scaledbndu); ae_matrix_destroy(&p->scaledcleic); ae_vector_destroy(&p->xc); ae_vector_destroy(&p->xstart); ae_vector_destroy(&p->xbase); ae_vector_destroy(&p->fbase); ae_vector_destroy(&p->dfbase); ae_vector_destroy(&p->fm2); ae_vector_destroy(&p->fm1); ae_vector_destroy(&p->fp1); ae_vector_destroy(&p->fp2); ae_vector_destroy(&p->dfm1); ae_vector_destroy(&p->dfp1); ae_vector_destroy(&p->bufd); ae_vector_destroy(&p->bufc); ae_matrix_destroy(&p->bufw); ae_vector_destroy(&p->xk); ae_vector_destroy(&p->xk1); ae_vector_destroy(&p->gk); ae_vector_destroy(&p->gk1); _minlbfgsstate_destroy(&p->auloptimizer); _minlbfgsreport_destroy(&p->aulreport); ae_vector_destroy(&p->nubc); ae_vector_destroy(&p->nulc); ae_vector_destroy(&p->nunlc); } void _minnlcreport_init(void* _p, ae_state *_state) { minnlcreport *p = (minnlcreport*)_p; ae_touch_ptr((void*)p); } void _minnlcreport_init_copy(void* _dst, void* _src, ae_state *_state) { minnlcreport *dst = (minnlcreport*)_dst; minnlcreport *src = (minnlcreport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->varidx = src->varidx; dst->funcidx = src->funcidx; dst->terminationtype = src->terminationtype; dst->dbgphase0its = src->dbgphase0its; } void _minnlcreport_clear(void* _p) { minnlcreport *p = (minnlcreport*)_p; ae_touch_ptr((void*)p); } void _minnlcreport_destroy(void* _p) { minnlcreport *p = (minnlcreport*)_p; ae_touch_ptr((void*)p); } /************************************************************************* NONSMOOTH NONCONVEX OPTIMIZATION SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 IMPORTANT: see MinNSSetAlgoAGS for important information on performance restrictions of AGS solver. REQUIREMENTS: * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are continuous, locally Lipschitz and continuously (but not necessarily twice) differentiable in an open dense subset of R^N. Functions F(), G() and H() may be nonsmooth and non-convex. Informally speaking, it means that functions are composed of large differentiable "patches" with nonsmoothness having place only at the boundaries between these "patches". Most real-life nonsmooth functions satisfy these requirements. Say, anything which involves finite number of abs(), min() and max() is very likely to pass the test. Say, it is possible to optimize anything of the following: * f=abs(x0)+2*abs(x1) * f=max(x0,x1) * f=sin(max(x0,x1)+abs(x2)) * for nonlinearly constrained problems: F() must be bounded from below without nonlinear constraints (this requirement is due to the fact that, contrary to box and linear constraints, nonlinear ones require special handling). * user must provide function value and gradient for F(), H(), G() at all points where function/gradient can be calculated. If optimizer requires value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), where gradient is not defined, user may resolve tie arbitrarily (in our case - return +1 or -1 at its discretion). * NS solver supports numerical differentiation, i.e. it may differentiate your function for you, but it results in 2N increase of function evaluations. Not recommended unless you solve really small problems. See minnscreatef() for more information on this functionality. USAGE: 1. User initializes algorithm state with MinNSCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AGS solver (activated with MinNSSetAlgoAGS() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNSSetBC() for boundary constraints b) MinNSSetLC() for linear constraints c) MinNSSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNSSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNSSetCond(). 5. Finally, user calls MinNSOptimize() function which takes algorithm state and pointer (delegate, etc) to callback function which calculates F/G/H. 7. User calls MinNSResults() to get solution 8. Optionally user may call MinNSRestartFrom() to solve another problem with same N but another starting point. MinNSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state NOTE: minnscreatef() function may be used if you do not have analytic gradient. This function creates solver which uses numerical differentiation with user-specified step. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreate(ae_int_t n, /* Real */ ae_vector* x, minnsstate* state, ae_state *_state) { _minnsstate_clear(state); ae_assert(n>=1, "MinNSCreate: N<1", _state); ae_assert(x->cnt>=n, "MinNSCreate: Length(X)0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, DiffStep>0. Algorithm performs numerical differentiation with step for I-th variable being equal to DiffStep*S[I] (here S[] is a scale vector, set by minnssetscale() function). Do not use too small steps, because it may lead to catastrophic cancellation during intermediate calculations. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnscreatef(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnsstate* state, ae_state *_state) { _minnsstate_clear(state); ae_assert(n>=1, "MinNSCreateF: N<1", _state); ae_assert(x->cnt>=n, "MinNSCreateF: Length(X)n; ae_assert(bndl->cnt>=n, "MinNSSetBC: Length(BndL)cnt>=n, "MinNSSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinNSSetBC: BndL contains NAN or +INF", _state); ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinNSSetBC: BndL contains NAN or -INF", _state); state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); } } /************************************************************************* This function sets linear constraints. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about current sampling radius in magnitude during optimization, about EpsX in the solution) due to use of penalty method to handle constraints. * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetlc(minnsstate* state, /* Real */ ae_matrix* c, /* Integer */ ae_vector* ct, ae_int_t k, ae_state *_state) { ae_int_t n; ae_int_t i; n = state->n; /* * First, check for errors in the inputs */ ae_assert(k>=0, "MinNSSetLC: K<0", _state); ae_assert(c->cols>=n+1||k==0, "MinNSSetLC: Cols(C)rows>=k, "MinNSSetLC: Rows(C)cnt>=k, "MinNSSetLC: Length(CT)nec = 0; state->nic = 0; return; } /* * Equality constraints are stored first, in the upper * NEC rows of State.CLEIC matrix. Inequality constraints * are stored in the next NIC rows. * * NOTE: we convert inequality constraints to the form * A*x<=b before copying them. */ rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); state->nec = 0; state->nic = 0; for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]==0 ) { ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); state->nec = state->nec+1; } } for(i=0; i<=k-1; i++) { if( ct->ptr.p_int[i]!=0 ) { if( ct->ptr.p_int[i]>0 ) { ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } else { ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); } state->nic = state->nic+1; } } } /************************************************************************* This function sets nonlinear constraints. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to minnsoptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] correspond to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of the feasible area! NOTE 2: algorithm scales variables according to scale specified by minnssetscale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by minnssetscale() function). NOTE 3: nonlinear constraints are always hard to handle, no matter what algorithm you try to use. Even basic box/linear constraints modify function curvature by adding valleys and ridges. However, nonlinear constraints add valleys which are very hard to follow due to their "curved" nature. It means that optimization with single nonlinear constraint may be significantly slower than optimization with multiple linear ones. It is normal situation, and we recommend you to carefully choose Rho parameter of minnssetalgoags(), because too large value may slow down convergence. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetnlc(minnsstate* state, ae_int_t nlec, ae_int_t nlic, ae_state *_state) { ae_assert(nlec>=0, "MinNSSetNLC: NLEC<0", _state); ae_assert(nlic>=0, "MinNSSetNLC: NLIC<0", _state); state->ng = nlec; state->nh = nlic; ae_vector_set_length(&state->fi, 1+state->ng+state->nh, _state); ae_matrix_set_length(&state->j, 1+state->ng+state->nh, state->n, _state); } /************************************************************************* This function sets stopping conditions for iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsX - >=0 The AGS solver finishes its work if on k+1-th iteration sampling radius decreases below EpsX. MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. We do not recommend you to rely on default choice in production code. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetcond(minnsstate* state, double epsx, ae_int_t maxits, ae_state *_state) { ae_assert(ae_isfinite(epsx, _state), "MinNSSetCond: EpsX is not finite number", _state); ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinNSSetCond: negative EpsX", _state); ae_assert(maxits>=0, "MinNSSetCond: negative MaxIts!", _state); if( ae_fp_eq(epsx,(double)(0))&&maxits==0 ) { epsx = 1.0E-6; } state->epsx = epsx; state->maxits = maxits; } /************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetscale(minnsstate* state, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_assert(s->cnt>=state->n, "MinNSSetScale: Length(S)n-1; i++) { ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinNSSetScale: S contains infinite or NAN elements", _state); ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinNSSetScale: S contains zero elements", _state); state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); } } /************************************************************************* This function tells MinNS unit to use AGS (adaptive gradient sampling) algorithm for nonsmooth constrained optimization. This algorithm is a slight modification of one described in "An Adaptive Gradient Sampling Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. This optimizer has following benefits and drawbacks: + robustness; it can be used with nonsmooth and nonconvex functions. + relatively easy tuning; most of the metaparameters are easy to select. - it has convergence of steepest descent, slower than CG/LBFGS. - each iteration involves evaluation of ~2N gradient values and solution of 2Nx2N quadratic programming problem, which limits applicability of algorithm by small-scale problems (up to 50-100). IMPORTANT: this algorithm has convergence guarantees, i.e. it will steadily move towards some stationary point of the function. However, "stationary point" does not always mean "solution". Nonsmooth problems often have "flat spots", i.e. areas where function do not change at all. Such "flat spots" are stationary points by definition, and algorithm may be caught here. Nonsmooth CONVEX tasks are not prone to this problem. Say, if your function has form f()=MAX(f0,f1,...), and f_i are convex, then f() is convex too and you have guaranteed convergence to solution. INPUT PARAMETERS: State - structure which stores algorithm state Radius - initial sampling radius, >=0. Internally multiplied by vector of per-variable scales specified by minnssetscale()). You should select relatively large sampling radius, roughly proportional to scaled length of the first steps of the algorithm. Something close to 0.1 in magnitude should be good for most problems. AGS solver can automatically decrease radius, so too large radius is not a problem (assuming that you won't choose so large radius that algorithm will sample function in too far away points, where gradient value is irrelevant). Too small radius won't cause algorithm to fail, but it may slow down algorithm (it may have to perform too short steps). Penalty - penalty coefficient for nonlinear constraints: * for problem with nonlinear constraints should be some problem-specific positive value, large enough that penalty term changes shape of the function. Starting from some problem-specific value penalty coefficient becomes large enough to exactly enforce nonlinear constraints; larger values do not improve precision. Increasing it too much may slow down convergence, so you should choose it carefully. * can be zero for problems WITHOUT nonlinear constraints (i.e. for unconstrained ones or ones with just box or linear constraints) * if you specify zero value for problem with at least one nonlinear constraint, algorithm will terminate with error code -1. ALGORITHM OUTLINE The very basic outline of unconstrained AGS algorithm is given below: 0. If sampling radius is below EpsX or we performed more then MaxIts iterations - STOP. 1. sample O(N) gradient values at random locations around current point; informally speaking, this sample is an implicit piecewise linear model of the function, although algorithm formulation does not mention that explicitly 2. solve quadratic programming problem in order to find descent direction 3. if QP solver tells us that we are near solution, decrease sampling radius and move to (0) 4. perform backtracking line search 5. after moving to new point, goto (0) As for the constraints: * box constraints are handled exactly by modification of the function being minimized * linear/nonlinear constraints are handled by adding L1 penalty. Because our solver can handle nonsmoothness, we can use L1 penalty function, which is an exact one (i.e. exact solution is returned under such penalty). * penalty coefficient for linear constraints is chosen automatically; however, penalty coefficient for nonlinear constraints must be specified by user. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnssetalgoags(minnsstate* state, double radius, double penalty, ae_state *_state) { ae_assert(ae_isfinite(radius, _state), "MinNSSetAlgoAGS: Radius is not finite", _state); ae_assert(ae_fp_greater(radius,(double)(0)), "MinNSSetAlgoAGS: Radius<=0", _state); ae_assert(ae_isfinite(penalty, _state), "MinNSSetAlgoAGS: Penalty is not finite", _state); ae_assert(ae_fp_greater_eq(penalty,0.0), "MinNSSetAlgoAGS: Penalty<0", _state); state->agsrhononlinear = penalty; state->agsradius = radius; state->solvertype = 0; } /************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to minnsoptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/ void minnssetxrep(minnsstate* state, ae_bool needxrep, ae_state *_state) { state->xrep = needxrep; } /************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrequesttermination(minnsstate* state, ae_state *_state) { state->userterminationneeded = ae_true; } /************************************************************************* NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of minnsoptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of minnsoptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to minnsoptimize() and specific function used to create optimizer. | USER PASSED TO minnsoptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ minnscreatef() | works FAILS minnscreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and minnsoptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ ae_bool minnsiteration(minnsstate* state, ae_state *_state) { ae_int_t i; ae_int_t k; ae_int_t n; ae_int_t ng; ae_int_t nh; double v; double xp; double xm; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstate.stage>=0 ) { i = state->rstate.ia.ptr.p_int[0]; k = state->rstate.ia.ptr.p_int[1]; n = state->rstate.ia.ptr.p_int[2]; ng = state->rstate.ia.ptr.p_int[3]; nh = state->rstate.ia.ptr.p_int[4]; v = state->rstate.ra.ptr.p_double[0]; xp = state->rstate.ra.ptr.p_double[1]; xm = state->rstate.ra.ptr.p_double[2]; } else { i = -983; k = -989; n = -834; ng = 900; nh = -287; v = 364; xp = 214; xm = -338; } if( state->rstate.stage==0 ) { goto lbl_0; } if( state->rstate.stage==1 ) { goto lbl_1; } if( state->rstate.stage==2 ) { goto lbl_2; } if( state->rstate.stage==3 ) { goto lbl_3; } /* * Routine body */ /* * Init */ state->replcerr = 0.0; state->repnlcerr = 0.0; state->repterminationtype = 0; state->repinneriterationscount = 0; state->repouteriterationscount = 0; state->repnfev = 0; state->repvaridx = 0; state->repfuncidx = 0; state->userterminationneeded = ae_false; state->dbgncholesky = 0; n = state->n; ng = state->ng; nh = state->nh; minns_clearrequestfields(state, _state); /* * AGS solver */ if( state->solvertype!=0 ) { goto lbl_4; } if( ae_fp_neq(state->diffstep,(double)(0)) ) { rvectorsetlengthatleast(&state->xbase, n, _state); rvectorsetlengthatleast(&state->fm, 1+ng+nh, _state); rvectorsetlengthatleast(&state->fp, 1+ng+nh, _state); } ae_vector_set_length(&state->rstateags.ia, 13+1, _state); ae_vector_set_length(&state->rstateags.ba, 3+1, _state); ae_vector_set_length(&state->rstateags.ra, 9+1, _state); state->rstateags.stage = -1; lbl_6: if( !minns_agsiteration(state, _state) ) { goto lbl_7; } /* * Numerical differentiation (if needed) - intercept NeedFiJ * request and replace it by sequence of NeedFi requests */ if( !(ae_fp_neq(state->diffstep,(double)(0))&&state->needfij) ) { goto lbl_8; } state->needfij = ae_false; state->needfi = ae_true; ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); k = 0; lbl_10: if( k>n-1 ) { goto lbl_12; } v = state->xbase.ptr.p_double[k]; xm = v-state->diffstep*state->s.ptr.p_double[k]; xp = v+state->diffstep*state->s.ptr.p_double[k]; if( state->hasbndl.ptr.p_bool[k]&&ae_fp_less(xm,state->bndl.ptr.p_double[k]) ) { xm = state->bndl.ptr.p_double[k]; } if( state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(xp,state->bndu.ptr.p_double[k]) ) { xp = state->bndu.ptr.p_double[k]; } ae_assert(ae_fp_less_eq(xm,xp), "MinNS: integrity check failed", _state); if( ae_fp_eq(xm,xp) ) { goto lbl_13; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = xm; state->rstate.stage = 0; goto lbl_rcomm; lbl_0: ae_v_move(&state->fm.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->x.ptr.p_double[k] = xp; state->rstate.stage = 1; goto lbl_rcomm; lbl_1: ae_v_move(&state->fp.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_move(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); ae_v_sub(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); v = 1/(xp-xm); ae_v_muld(&state->j.ptr.pp_double[0][k], state->j.stride, ae_v_len(0,ng+nh), v); state->repnfev = state->repnfev+2; goto lbl_14; lbl_13: for(i=0; i<=ng+nh; i++) { state->j.ptr.pp_double[i][k] = 0.0; } lbl_14: k = k+1; goto lbl_10; lbl_12: ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->rstate.stage = 2; goto lbl_rcomm; lbl_2: /* * Restore previous values of fields and continue */ state->needfi = ae_false; state->needfij = ae_true; goto lbl_6; lbl_8: /* * Forward request to caller */ state->rstate.stage = 3; goto lbl_rcomm; lbl_3: inc(&state->repnfev, _state); goto lbl_6; lbl_7: result = ae_false; return result; lbl_4: result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstate.ia.ptr.p_int[0] = i; state->rstate.ia.ptr.p_int[1] = k; state->rstate.ia.ptr.p_int[2] = n; state->rstate.ia.ptr.p_int[3] = ng; state->rstate.ia.ptr.p_int[4] = nh; state->rstate.ra.ptr.p_double[0] = v; state->rstate.ra.ptr.p_double[1] = xp; state->rstate.ra.ptr.p_double[2] = xm; return result; } /************************************************************************* MinNS results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -3 box constraints are inconsistent * -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() * 2 sampling radius decreased below epsx * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. * 8 User requested termination via minnsrequesttermination() -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresults(minnsstate* state, /* Real */ ae_vector* x, minnsreport* rep, ae_state *_state) { ae_vector_clear(x); _minnsreport_clear(rep); minnsresultsbuf(state, x, rep, _state); } /************************************************************************* Buffered implementation of minnsresults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsresultsbuf(minnsstate* state, /* Real */ ae_vector* x, minnsreport* rep, ae_state *_state) { ae_int_t i; if( x->cntn ) { ae_vector_set_length(x, state->n, _state); } rep->iterationscount = state->repinneriterationscount; rep->nfev = state->repnfev; rep->varidx = state->repvaridx; rep->funcidx = state->repfuncidx; rep->terminationtype = state->repterminationtype; rep->cerr = ae_maxreal(state->replcerr, state->repnlcerr, _state); rep->lcerr = state->replcerr; rep->nlcerr = state->repnlcerr; if( state->repterminationtype>0 ) { ae_v_move(&x->ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); } else { for(i=0; i<=state->n-1; i++) { x->ptr.p_double[i] = _state->v_nan; } } } /************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. X - new starting point. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/ void minnsrestartfrom(minnsstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t n; n = state->n; /* * First, check for errors in the inputs */ ae_assert(x->cnt>=n, "MinNSRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * prepare RComm facilities */ ae_vector_set_length(&state->rstate.ia, 4+1, _state); ae_vector_set_length(&state->rstate.ra, 2+1, _state); state->rstate.stage = -1; minns_clearrequestfields(state, _state); } /************************************************************************* Clears request fileds (to be sure that we don't forget to clear something) *************************************************************************/ static void minns_clearrequestfields(minnsstate* state, ae_state *_state) { state->needfi = ae_false; state->needfij = ae_false; state->xupdated = ae_false; } /************************************************************************* Internal initialization subroutine. Sets default NLC solver with default criteria. *************************************************************************/ static void minns_minnsinitinternal(ae_int_t n, /* Real */ ae_vector* x, double diffstep, minnsstate* state, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_matrix c; ae_vector ct; ae_frame_make(_state, &_frame_block); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); state->agsinitstp = 0.2; state->agsstattold = 1.0E-10; state->agsshortstpabs = 1.0E-10; state->agsshortstprel = 0.75; state->agsshortf = 10*ae_machineepsilon; state->agsrhononlinear = 0.0; state->agsraddecay = 0.2; state->agsalphadecay = 0.5; state->agsdecrease = 0.1; state->agsmaxraddecays = 50; state->agsmaxbacktrack = 20; state->agsmaxbacktracknonfull = 8; state->agspenaltylevel = 10.0; state->agspenaltyincrease = 20.0; state->agsminupdate = ae_maxint(5, n/2, _state); state->agssamplesize = ae_maxint(2*n+1, state->agsminupdate+1, _state); state->agsshortlimit = 4+state->agssamplesize/state->agsminupdate; /* * Initialize other params */ state->n = n; state->diffstep = diffstep; ae_vector_set_length(&state->bndl, n, _state); ae_vector_set_length(&state->hasbndl, n, _state); ae_vector_set_length(&state->bndu, n, _state); ae_vector_set_length(&state->hasbndu, n, _state); ae_vector_set_length(&state->s, n, _state); ae_vector_set_length(&state->xstart, n, _state); ae_vector_set_length(&state->xc, n, _state); ae_vector_set_length(&state->xn, n, _state); ae_vector_set_length(&state->d, n, _state); ae_vector_set_length(&state->x, n, _state); for(i=0; i<=n-1; i++) { state->bndl.ptr.p_double[i] = _state->v_neginf; state->hasbndl.ptr.p_bool[i] = ae_false; state->bndu.ptr.p_double[i] = _state->v_posinf; state->hasbndu.ptr.p_bool[i] = ae_false; state->s.ptr.p_double[i] = 1.0; state->xstart.ptr.p_double[i] = x->ptr.p_double[i]; state->xc.ptr.p_double[i] = x->ptr.p_double[i]; } minnssetlc(state, &c, &ct, 0, _state); minnssetnlc(state, 0, 0, _state); minnssetcond(state, 0.0, 0, _state); minnssetxrep(state, ae_false, _state); minnssetalgoags(state, 0.1, 1000.0, _state); minnsrestartfrom(state, x, _state); ae_frame_leave(_state); } /************************************************************************* This function performs actual processing for AUL algorith. It expects that caller redirects its reverse communication requests NeedFiJ/XUpdated to external user who will provide analytic derivative (or handle reports about progress). In case external user does not have analytic derivative, it is responsibility of caller to intercept NeedFiJ request and replace it with appropriate numerical differentiation scheme. -- ALGLIB -- Copyright 06.06.2015 by Bochkanov Sergey *************************************************************************/ static ae_bool minns_agsiteration(minnsstate* state, ae_state *_state) { ae_int_t n; ae_int_t nec; ae_int_t nic; ae_int_t ng; ae_int_t nh; ae_int_t i; ae_int_t j; ae_int_t k; double radius0; double radius; ae_int_t radiusdecays; double alpha; double recommendedstep; double dnrm; double dg; double v; double vv; ae_int_t maxsamplesize; ae_int_t cursamplesize; double v0; double v1; ae_bool restartneeded; ae_bool b; ae_bool alphadecreased; ae_int_t shortstepscnt; ae_int_t backtrackits; ae_int_t maxbacktrackits; ae_bool fullsample; ae_bool result; /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( state->rstateags.stage>=0 ) { n = state->rstateags.ia.ptr.p_int[0]; nec = state->rstateags.ia.ptr.p_int[1]; nic = state->rstateags.ia.ptr.p_int[2]; ng = state->rstateags.ia.ptr.p_int[3]; nh = state->rstateags.ia.ptr.p_int[4]; i = state->rstateags.ia.ptr.p_int[5]; j = state->rstateags.ia.ptr.p_int[6]; k = state->rstateags.ia.ptr.p_int[7]; radiusdecays = state->rstateags.ia.ptr.p_int[8]; maxsamplesize = state->rstateags.ia.ptr.p_int[9]; cursamplesize = state->rstateags.ia.ptr.p_int[10]; shortstepscnt = state->rstateags.ia.ptr.p_int[11]; backtrackits = state->rstateags.ia.ptr.p_int[12]; maxbacktrackits = state->rstateags.ia.ptr.p_int[13]; restartneeded = state->rstateags.ba.ptr.p_bool[0]; b = state->rstateags.ba.ptr.p_bool[1]; alphadecreased = state->rstateags.ba.ptr.p_bool[2]; fullsample = state->rstateags.ba.ptr.p_bool[3]; radius0 = state->rstateags.ra.ptr.p_double[0]; radius = state->rstateags.ra.ptr.p_double[1]; alpha = state->rstateags.ra.ptr.p_double[2]; recommendedstep = state->rstateags.ra.ptr.p_double[3]; dnrm = state->rstateags.ra.ptr.p_double[4]; dg = state->rstateags.ra.ptr.p_double[5]; v = state->rstateags.ra.ptr.p_double[6]; vv = state->rstateags.ra.ptr.p_double[7]; v0 = state->rstateags.ra.ptr.p_double[8]; v1 = state->rstateags.ra.ptr.p_double[9]; } else { n = -686; nec = 912; nic = 585; ng = 497; nh = -271; i = -581; j = 745; k = -533; radiusdecays = -77; maxsamplesize = 678; cursamplesize = -293; shortstepscnt = 316; backtrackits = 647; maxbacktrackits = -756; restartneeded = ae_false; b = ae_true; alphadecreased = ae_false; fullsample = ae_false; radius0 = 13; radius = -740; alpha = 262; recommendedstep = 439; dnrm = 327; dg = 222; v = -589; vv = 274; v0 = 845; v1 = 456; } if( state->rstateags.stage==0 ) { goto lbl_0; } if( state->rstateags.stage==1 ) { goto lbl_1; } if( state->rstateags.stage==2 ) { goto lbl_2; } if( state->rstateags.stage==3 ) { goto lbl_3; } /* * Routine body */ ae_assert(state->solvertype==0, "MinNS: internal error", _state); n = state->n; nec = state->nec; nic = state->nic; ng = state->ng; nh = state->nh; /* * Check consistency of parameters */ if( ng+nh>0&&ae_fp_eq(state->agsrhononlinear,(double)(0)) ) { state->repterminationtype = -1; result = ae_false; return result; } /* * Allocate arrays. */ rvectorsetlengthatleast(&state->colmax, n, _state); rvectorsetlengthatleast(&state->diagh, n, _state); rvectorsetlengthatleast(&state->signmin, n, _state); rvectorsetlengthatleast(&state->signmax, n, _state); maxsamplesize = state->agssamplesize; rmatrixsetlengthatleast(&state->samplex, maxsamplesize+1, n, _state); rmatrixsetlengthatleast(&state->samplegm, maxsamplesize+1, n, _state); rmatrixsetlengthatleast(&state->samplegmbc, maxsamplesize+1, n, _state); rvectorsetlengthatleast(&state->samplef, maxsamplesize+1, _state); rvectorsetlengthatleast(&state->samplef0, maxsamplesize+1, _state); rvectorsetlengthatleast(&state->grs, n, _state); /* * Prepare optimizer */ rvectorsetlengthatleast(&state->tmp0, maxsamplesize, _state); rvectorsetlengthatleast(&state->tmp1, maxsamplesize, _state); ivectorsetlengthatleast(&state->tmp3, 1, _state); rmatrixsetlengthatleast(&state->tmp2, 1, maxsamplesize+1, _state); for(i=0; i<=maxsamplesize-1; i++) { state->tmp0.ptr.p_double[i] = 0.0; state->tmp1.ptr.p_double[i] = _state->v_posinf; } /* * Prepare RNG, seed it with fixed values so * that each run on same problem yeilds same results */ hqrndseed(7235, 98532, &state->agsrs, _state); /* * Prepare initial point subject to current bound constraints and * perform scaling of bound constraints, linear constraints, point itself */ rvectorsetlengthatleast(&state->scaledbndl, n, _state); rvectorsetlengthatleast(&state->scaledbndu, n, _state); for(i=0; i<=n-1; i++) { /* * Check and scale constraints */ if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_less(state->bndu.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { state->repterminationtype = -3; result = ae_false; return result; } if( state->hasbndl.ptr.p_bool[i] ) { state->scaledbndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]/state->s.ptr.p_double[i]; } else { state->scaledbndl.ptr.p_double[i] = _state->v_neginf; } if( state->hasbndu.ptr.p_bool[i] ) { state->scaledbndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]/state->s.ptr.p_double[i]; } else { state->scaledbndu.ptr.p_double[i] = _state->v_posinf; } if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) { ae_assert(ae_fp_less_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity check failed", _state); } if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { ae_assert(ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity check failed", _state); } /* * Scale and constrain point */ state->xc.ptr.p_double[i] = state->xstart.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; continue; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; continue; } state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]/state->s.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) { state->xc.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; } } rmatrixsetlengthatleast(&state->scaledcleic, nec+nic, n+1, _state); rvectorsetlengthatleast(&state->rholinear, nec+nic, _state); for(i=0; i<=nec+nic-1; i++) { /* * Initial value of penalty coefficient is zero */ state->rholinear.ptr.p_double[i] = 0.0; /* * Scale and normalize linear constraints */ vv = 0.0; for(j=0; j<=n-1; j++) { v = state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; state->scaledcleic.ptr.pp_double[i][j] = v; vv = vv+v*v; } vv = ae_sqrt(vv, _state); state->scaledcleic.ptr.pp_double[i][n] = state->cleic.ptr.pp_double[i][n]; if( ae_fp_greater(vv,(double)(0)) ) { for(j=0; j<=n; j++) { state->scaledcleic.ptr.pp_double[i][j] = state->scaledcleic.ptr.pp_double[i][j]/vv; } } } /* * Main cycle * * We maintain several variables during iteration: * * RecommendedStep- current estimate of recommended step length; * must be Radius0 on first entry * * Radius - current sampling radius * * CurSampleSize - current sample size (may change in future versions) * * FullSample - whether we have full sample, or only partial one * * RadiusDecays - total number of decreases performed for sampling radius */ radius = state->agsradius; radius0 = radius; recommendedstep = ae_minreal(radius0, state->agsinitstp, _state); cursamplesize = 1; radiusdecays = 0; shortstepscnt = 0; fullsample = ae_false; lbl_4: if( ae_false ) { goto lbl_5; } /* * First phase of iteration - central point: * * 1. evaluate function at central point - first entry in sample. * Its status is ignored, it is always recalculated. * 2. report point and check gradient/function value for NAN/INF * 3. check penalty coefficients for linear terms; increase them * if directional derivative of function being optimized (not * merit function!) is larger than derivative of penalty. * 4. update report on constraint violation */ cursamplesize = ae_maxint(cursamplesize, 1, _state); ae_v_move(&state->samplex.ptr.pp_double[0][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); minns_unscalepointbc(state, &state->x, _state); minns_clearrequestfields(state, _state); state->needfij = ae_true; state->rstateags.stage = 0; goto lbl_rcomm; lbl_0: state->needfij = ae_false; state->replcerr = 0.0; for(i=0; i<=nec+nic-1; i++) { v = -state->scaledcleic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = v+state->scaledcleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; } if( i>=nec&&ae_fp_less_eq(v,(double)(0)) ) { continue; } state->replcerr = ae_maxreal(state->replcerr, ae_fabs(v, _state), _state); } state->repnlcerr = 0.0; for(i=1; i<=ng+nh; i++) { v = state->fi.ptr.p_double[i]; if( i>ng&&ae_fp_less_eq(v,(double)(0)) ) { continue; } state->repnlcerr = ae_maxreal(state->repnlcerr, ae_fabs(v, _state), _state); } for(j=0; j<=n-1; j++) { state->grs.ptr.p_double[j] = state->j.ptr.pp_double[0][j]*state->s.ptr.p_double[j]; } minns_generatemeritfunction(state, 0, _state); if( !state->xrep ) { goto lbl_6; } ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); state->f = state->samplef0.ptr.p_double[0]; minns_unscalepointbc(state, &state->x, _state); minns_clearrequestfields(state, _state); state->xupdated = ae_true; state->rstateags.stage = 1; goto lbl_rcomm; lbl_1: state->xupdated = ae_false; lbl_6: if( state->userterminationneeded ) { /* * User requested termination */ state->repterminationtype = 8; goto lbl_5; } v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(state->samplegm.ptr.pp_double[0][i], _state); } if( !ae_isfinite(v, _state)||!ae_isfinite(state->samplef.ptr.p_double[0], _state) ) { /* * Abnormal termination - infinities in function/gradient */ state->repterminationtype = -8; goto lbl_5; } restartneeded = ae_false; for(i=0; i<=nec+nic-1; i++) { /* * Evaluate penalty function. * * Skip update if penalty is satisfied exactly (this check * also covers situations when I-th row is exactly zero). */ v = -state->scaledcleic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = v+state->scaledcleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; } if( i=nec&&ae_fp_less_eq(v,(double)(0)) ) { continue; } /* * Calculate directional derivative, compare it with threshold. * * NOTE: we rely on the fact that ScaledCLEIC is normalized */ ae_assert(ae_fp_greater(state->agspenaltylevel,1.0), "MinNS: integrity error", _state); ae_assert(ae_fp_greater(state->agspenaltyincrease,state->agspenaltylevel), "MinNS: integrity error", _state); v = 0.0; for(j=0; j<=n-1; j++) { v = v+state->grs.ptr.p_double[j]*state->scaledcleic.ptr.pp_double[i][j]; } v = ae_fabs(v, _state); if( ae_fp_greater(v*state->agspenaltylevel,state->rholinear.ptr.p_double[i]) ) { state->rholinear.ptr.p_double[i] = v*state->agspenaltyincrease; restartneeded = ae_true; } } if( restartneeded ) { cursamplesize = 0; goto lbl_4; } /* * Check stopping conditions. */ if( radiusdecays>=state->agsmaxraddecays ) { /* * Too many attempts to decrease radius */ state->repterminationtype = 7; goto lbl_5; } if( state->repinneriterationscount>=state->maxits&&state->maxits>0 ) { /* * Too many iterations */ state->repterminationtype = 5; goto lbl_5; } if( ae_fp_less_eq(radius,state->epsx*state->agsraddecay) ) { /* * Radius is smaller than required step tolerance multiplied by radius decay. * * Additional decay is required in order to make sure that optimization session * with radius equal to EpsX was successfully done. */ state->repterminationtype = 2; goto lbl_5; } /* * Update sample: * * 1. invalidate entries which are too far away from XC * and move all valid entries to beginning of the sample. * 2. add new entries until we have AGSSampleSize * items in our sample. We remove oldest entries from * sample until we have enough place to add at least * AGSMinUpdate items. * 3. prepare "modified" gradient sample with respect to * boundary constraints. */ ae_assert(cursamplesize>=1, "MinNS: integrity check failed", _state); k = 1; for(i=1; i<=cursamplesize-1; i++) { /* * If entry is outside of Radius-ball around XC, discard it. */ v = 0.0; for(j=0; j<=n-1; j++) { v = ae_maxreal(v, ae_fabs(state->samplex.ptr.pp_double[i][j]-state->xc.ptr.p_double[j], _state), _state); } if( ae_fp_greater(v,radius) ) { continue; } /* * If central point is exactly at boundary, and corresponding * component of entry is OUT of boundary, entry is discarded. */ b = ae_false; for(j=0; j<=n-1; j++) { b = b||((state->hasbndl.ptr.p_bool[j]&&ae_fp_eq(state->xc.ptr.p_double[j],state->scaledbndl.ptr.p_double[j]))&&ae_fp_neq(state->samplex.ptr.pp_double[i][j],state->scaledbndl.ptr.p_double[j])); b = b||((state->hasbndu.ptr.p_bool[j]&&ae_fp_eq(state->xc.ptr.p_double[j],state->scaledbndu.ptr.p_double[j]))&&ae_fp_neq(state->samplex.ptr.pp_double[i][j],state->scaledbndu.ptr.p_double[j])); } if( b ) { continue; } /* * Move to the beginning */ ae_v_move(&state->samplex.ptr.pp_double[k][0], 1, &state->samplex.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); ae_v_move(&state->samplegm.ptr.pp_double[k][0], 1, &state->samplegm.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); state->samplef.ptr.p_double[k] = state->samplef.ptr.p_double[i]; state->samplef0.ptr.p_double[k] = state->samplef0.ptr.p_double[i]; k = k+1; } cursamplesize = k; if( state->agssamplesize-cursamplesizeagsminupdate ) { /* * Remove oldest entries */ k = state->agsminupdate-(state->agssamplesize-cursamplesize); ae_assert(k<=cursamplesize-1, "MinNS: integrity check failed", _state); for(i=1; i<=cursamplesize-k-1; i++) { ae_v_move(&state->samplex.ptr.pp_double[i][0], 1, &state->samplex.ptr.pp_double[i+k][0], 1, ae_v_len(0,n-1)); ae_v_move(&state->samplegm.ptr.pp_double[i][0], 1, &state->samplegm.ptr.pp_double[i+k][0], 1, ae_v_len(0,n-1)); state->samplef.ptr.p_double[i] = state->samplef.ptr.p_double[i+k]; state->samplef0.ptr.p_double[i] = state->samplef0.ptr.p_double[i+k]; } cursamplesize = cursamplesize-k; } k = 0; i = cursamplesize; lbl_8: if( i>ae_minint(cursamplesize+state->agsminupdate, state->agssamplesize, _state)-1 ) { goto lbl_10; } for(j=0; j<=n-1; j++) { /* * Undistorted position */ state->samplex.ptr.pp_double[i][j] = state->xc.ptr.p_double[j]; /* * Do not apply distortion, if we are exactly at boundary constraint. */ if( (state->hasbndl.ptr.p_bool[j]&&state->hasbndu.ptr.p_bool[j])&&ae_fp_eq(state->scaledbndl.ptr.p_double[j],state->scaledbndu.ptr.p_double[j]) ) { continue; } if( state->hasbndl.ptr.p_bool[j]&&ae_fp_eq(state->samplex.ptr.pp_double[i][j],state->scaledbndl.ptr.p_double[j]) ) { continue; } if( state->hasbndu.ptr.p_bool[j]&&ae_fp_eq(state->samplex.ptr.pp_double[i][j],state->scaledbndu.ptr.p_double[j]) ) { continue; } /* * Apply distortion */ if( ae_fp_greater_eq(hqrnduniformr(&state->agsrs, _state),0.5) ) { /* * Sample at the left side with 50% probability */ v0 = state->samplex.ptr.pp_double[i][j]-radius; v1 = state->samplex.ptr.pp_double[i][j]; if( state->hasbndl.ptr.p_bool[j] ) { v0 = ae_maxreal(state->scaledbndl.ptr.p_double[j], v0, _state); } } else { /* * Sample at the right side with 50% probability */ v0 = state->samplex.ptr.pp_double[i][j]; v1 = state->samplex.ptr.pp_double[i][j]+radius; if( state->hasbndu.ptr.p_bool[j] ) { v1 = ae_minreal(state->scaledbndu.ptr.p_double[j], v1, _state); } } ae_assert(ae_fp_greater_eq(v1,v0), "MinNS: integrity check failed", _state); state->samplex.ptr.pp_double[i][j] = boundval(v0+(v1-v0)*hqrnduniformr(&state->agsrs, _state), v0, v1, _state); } ae_v_move(&state->x.ptr.p_double[0], 1, &state->samplex.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); minns_unscalepointbc(state, &state->x, _state); minns_clearrequestfields(state, _state); state->needfij = ae_true; state->rstateags.stage = 2; goto lbl_rcomm; lbl_2: state->needfij = ae_false; minns_generatemeritfunction(state, i, _state); k = k+1; i = i+1; goto lbl_8; lbl_10: cursamplesize = cursamplesize+k; fullsample = cursamplesize==state->agssamplesize; for(j=0; j<=cursamplesize-1; j++) { /* * For J-th element in gradient sample, process all of its components * and modify them according to status of box constraints */ for(i=0; i<=n-1; i++) { ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]), "MinNS: integrity error", _state); ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity error", _state); state->samplegmbc.ptr.pp_double[j][i] = state->samplegm.ptr.pp_double[j][i]; if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) { /* * I-th box constraint is of equality type (lower bound matches upper one). * Simplest case, always active. */ state->samplegmbc.ptr.pp_double[j][i] = 0.0; continue; } if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) { /* * We are at lower bound. * * A bit more complex: * * first, we have to activate/deactivate constraint depending on gradient at XC * * second, in any case, I-th column of gradient sample must be non-positive */ if( ae_fp_greater_eq(state->samplegm.ptr.pp_double[0][i],0.0) ) { state->samplegmbc.ptr.pp_double[j][i] = 0.0; } state->samplegmbc.ptr.pp_double[j][i] = ae_minreal(state->samplegmbc.ptr.pp_double[j][i], 0.0, _state); continue; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) { /* * We are at upper bound. * * A bit more complex: * * first, we have to activate/deactivate constraint depending on gradient at XC * * second, in any case, I-th column of gradient sample must be non-negative */ if( ae_fp_less_eq(state->samplegm.ptr.pp_double[0][i],0.0) ) { state->samplegmbc.ptr.pp_double[j][i] = 0.0; } state->samplegmbc.ptr.pp_double[j][i] = ae_maxreal(state->samplegmbc.ptr.pp_double[j][i], 0.0, _state); continue; } } } /* * Calculate diagonal Hessian. * * This Hessian serves two purposes: * * first, it improves performance of gradient descent step * * second, it improves condition number of QP subproblem * solved to determine step * * The idea is that for each variable we check whether sample * includes entries with alternating sign of gradient: * * if gradients with different signs are present, Hessian * component is set to M/R, where M is a maximum magnitude * of corresponding gradient component, R is a sampling radius. * Note that sign=0 and sign=1 are treated as different ones * * if all gradients have same sign, Hessian component is * set to M/R0, where R0 is initial sampling radius. */ for(j=0; j<=n-1; j++) { state->colmax.ptr.p_double[j] = 0.0; state->signmin.ptr.p_double[j] = (double)(1); state->signmax.ptr.p_double[j] = (double)(-1); } for(i=0; i<=cursamplesize-1; i++) { for(j=0; j<=n-1; j++) { v = state->samplegmbc.ptr.pp_double[i][j]; state->colmax.ptr.p_double[j] = ae_maxreal(state->colmax.ptr.p_double[j], ae_fabs(v, _state), _state); state->signmin.ptr.p_double[j] = ae_minreal(state->signmin.ptr.p_double[j], (double)(ae_sign(v, _state)), _state); state->signmax.ptr.p_double[j] = ae_maxreal(state->signmax.ptr.p_double[j], (double)(ae_sign(v, _state)), _state); } } for(j=0; j<=n-1; j++) { if( ae_fp_neq(state->signmin.ptr.p_double[j],state->signmax.ptr.p_double[j]) ) { /* * Alternating signs of gradient - step is proportional to current sampling radius */ ae_assert(ae_fp_neq(state->colmax.ptr.p_double[j],(double)(0)), "MinNS: integrity check failed", _state); ae_assert(ae_fp_neq(radius,(double)(0)), "MinNS: integrity check failed", _state); state->diagh.ptr.p_double[j] = state->colmax.ptr.p_double[j]/radius; continue; } if( ae_fp_neq(state->colmax.ptr.p_double[j],(double)(0)) ) { /* * Non-alternating sign of gradient, but non-zero. * Step is proportional to initial sampling radius */ ae_assert(ae_fp_neq(radius0,(double)(0)), "MinNS: integrity check failed", _state); state->diagh.ptr.p_double[j] = state->colmax.ptr.p_double[j]/radius0; continue; } state->diagh.ptr.p_double[j] = (double)(1); } /* * PROJECTION PHASE * * We project zero vector on convex hull of gradient sample. * If projection is small enough, we decrease radius and restart. * Otherwise, this phase returns search direction in State.D. * * NOTE: because we use iterative solver, it may have trouble * dealing with ill-conditioned problems. So we also employ * second, backup test for stationarity - when too many * subsequent backtracking searches resulted in short steps. */ minns_solveqp(&state->samplegmbc, &state->diagh, cursamplesize, n, &state->tmp0, &state->dbgncholesky, &state->nsqp, _state); for(j=0; j<=n-1; j++) { state->d.ptr.p_double[j] = 0.0; } for(i=0; i<=cursamplesize-1; i++) { v = state->tmp0.ptr.p_double[i]; ae_v_addd(&state->d.ptr.p_double[0], 1, &state->samplegmbc.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } v = 0.0; for(j=0; j<=n-1; j++) { v = ae_maxreal(v, ae_fabs(state->d.ptr.p_double[j]/coalesce(state->colmax.ptr.p_double[j], 1.0, _state), _state), _state); } if( ae_fp_less_eq(v,state->agsstattold) ) { /* * Stationarity test succeded. * Decrease radius and restart. * * NOTE: we also clear ShortStepsCnt on restart */ radius = radius*state->agsraddecay; shortstepscnt = 0; inc(&radiusdecays, _state); inc(&state->repinneriterationscount, _state); goto lbl_4; } for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = -state->d.ptr.p_double[i]/state->diagh.ptr.p_double[i]; } /* * Perform backtracking line search. * Update initial step length depending on search results. * Here we assume that D is non-zero. * * NOTE: if AGSShortLimit subsequent line searches resulted * in steps shorter than AGSStatTolStp, we decrease radius. */ dnrm = 0.0; dg = 0.0; for(i=0; i<=n-1; i++) { dnrm = dnrm+ae_sqr(state->d.ptr.p_double[i], _state); dg = dg+state->d.ptr.p_double[i]*state->samplegmbc.ptr.pp_double[0][i]; } dnrm = ae_sqrt(dnrm, _state); ae_assert(ae_fp_greater(dnrm,(double)(0)), "MinNS: integrity error", _state); alpha = recommendedstep/dnrm; alphadecreased = ae_false; backtrackits = 0; if( fullsample ) { maxbacktrackits = state->agsmaxbacktrack; } else { maxbacktrackits = state->agsmaxbacktracknonfull; } lbl_11: if( ae_false ) { goto lbl_12; } /* * Prepare XN and evaluate merit function at XN */ ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); enforceboundaryconstraints(&state->xn, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); ae_v_move(&state->samplex.ptr.pp_double[maxsamplesize][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&state->x.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); minns_unscalepointbc(state, &state->x, _state); minns_clearrequestfields(state, _state); state->needfij = ae_true; state->rstateags.stage = 3; goto lbl_rcomm; lbl_3: state->needfij = ae_false; minns_generatemeritfunction(state, maxsamplesize, _state); /* * Check sufficient decrease condition */ ae_assert(ae_fp_greater(dnrm,(double)(0)), "MinNS: integrity error", _state); if( ae_fp_less_eq(state->samplef.ptr.p_double[maxsamplesize],state->samplef.ptr.p_double[0]+alpha*state->agsdecrease*dg) ) { goto lbl_12; } /* * Decrease Alpha */ alpha = alpha*state->agsalphadecay; alphadecreased = ae_true; /* * Update and check iterations counter. */ inc(&backtrackits, _state); if( backtrackits>=maxbacktrackits ) { /* * Too many backtracking searches performed without success. * Terminate iterations. */ alpha = 0.0; alphadecreased = ae_true; ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); goto lbl_12; } goto lbl_11; lbl_12: if( (ae_fp_less_eq(alpha*dnrm,state->agsshortstpabs)||ae_fp_less_eq(alpha*dnrm,state->agsshortstprel*radius))||ae_fp_less_eq(ae_fabs(state->samplef.ptr.p_double[0]-state->samplef.ptr.p_double[maxsamplesize], _state),state->agsshortf) ) { inc(&shortstepscnt, _state); } else { shortstepscnt = 0; } if( shortstepscnt>=state->agsshortlimit ) { /* * Too many subsequent short steps. * * It may be possible that optimizer is unable to find out * that we have to decrease radius because of ill-conditioned * gradients. * * Decrease radius and restart. */ radius = radius*state->agsraddecay; shortstepscnt = 0; inc(&radiusdecays, _state); inc(&state->repinneriterationscount, _state); goto lbl_4; } if( !alphadecreased ) { recommendedstep = recommendedstep*2.0; } if( alphadecreased&&fullsample ) { recommendedstep = recommendedstep*0.5; } /* * Next iteration */ ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); inc(&state->repinneriterationscount, _state); goto lbl_4; lbl_5: /* * Convert back from scaled to unscaled representation */ minns_unscalepointbc(state, &state->xc, _state); result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; state->rstateags.ia.ptr.p_int[0] = n; state->rstateags.ia.ptr.p_int[1] = nec; state->rstateags.ia.ptr.p_int[2] = nic; state->rstateags.ia.ptr.p_int[3] = ng; state->rstateags.ia.ptr.p_int[4] = nh; state->rstateags.ia.ptr.p_int[5] = i; state->rstateags.ia.ptr.p_int[6] = j; state->rstateags.ia.ptr.p_int[7] = k; state->rstateags.ia.ptr.p_int[8] = radiusdecays; state->rstateags.ia.ptr.p_int[9] = maxsamplesize; state->rstateags.ia.ptr.p_int[10] = cursamplesize; state->rstateags.ia.ptr.p_int[11] = shortstepscnt; state->rstateags.ia.ptr.p_int[12] = backtrackits; state->rstateags.ia.ptr.p_int[13] = maxbacktrackits; state->rstateags.ba.ptr.p_bool[0] = restartneeded; state->rstateags.ba.ptr.p_bool[1] = b; state->rstateags.ba.ptr.p_bool[2] = alphadecreased; state->rstateags.ba.ptr.p_bool[3] = fullsample; state->rstateags.ra.ptr.p_double[0] = radius0; state->rstateags.ra.ptr.p_double[1] = radius; state->rstateags.ra.ptr.p_double[2] = alpha; state->rstateags.ra.ptr.p_double[3] = recommendedstep; state->rstateags.ra.ptr.p_double[4] = dnrm; state->rstateags.ra.ptr.p_double[5] = dg; state->rstateags.ra.ptr.p_double[6] = v; state->rstateags.ra.ptr.p_double[7] = vv; state->rstateags.ra.ptr.p_double[8] = v0; state->rstateags.ra.ptr.p_double[9] = v1; return result; } /************************************************************************* This function calculates merit function (target function + penalties for violation of non-box constraints), using State.X (unscaled), State.Fi, State.J (unscaled) and State.SampleX (scaled) as inputs. Results are loaded: * target function value - to State.SampleF0[SampleIdx] * merit function value - to State.SampleF[SampleIdx] * gradient of merit function - to State.SampleGM[SampleIdx] -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_generatemeritfunction(minnsstate* state, ae_int_t sampleidx, ae_state *_state) { ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t nec; ae_int_t nic; ae_int_t ng; ae_int_t nh; double v; double s; n = state->n; nec = state->nec; nic = state->nic; ng = state->ng; nh = state->nh; /* * Integrity check */ for(i=0; i<=n-1; i++) { ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i]), "MinNS: integrity error", _state); ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]), "MinNS: integrity error", _state); } /* * Prepare "raw" function */ state->samplef.ptr.p_double[sampleidx] = state->fi.ptr.p_double[0]; state->samplef0.ptr.p_double[sampleidx] = state->fi.ptr.p_double[0]; for(j=0; j<=n-1; j++) { state->samplegm.ptr.pp_double[sampleidx][j] = state->j.ptr.pp_double[0][j]*state->s.ptr.p_double[j]; } /* * Modify merit function with linear constraints */ for(i=0; i<=nec+nic-1; i++) { v = -state->scaledcleic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { v = v+state->scaledcleic.ptr.pp_double[i][j]*state->samplex.ptr.pp_double[sampleidx][j]; } if( i>=nec&&ae_fp_less(v,(double)(0)) ) { continue; } state->samplef.ptr.p_double[sampleidx] = state->samplef.ptr.p_double[sampleidx]+state->rholinear.ptr.p_double[i]*ae_fabs(v, _state); s = (double)(ae_sign(v, _state)); for(j=0; j<=n-1; j++) { state->samplegm.ptr.pp_double[sampleidx][j] = state->samplegm.ptr.pp_double[sampleidx][j]+state->rholinear.ptr.p_double[i]*s*state->scaledcleic.ptr.pp_double[i][j]; } } /* * Modify merit function with nonlinear constraints */ for(i=1; i<=ng+nh; i++) { v = state->fi.ptr.p_double[i]; if( i<=ng&&ae_fp_eq(v,(double)(0)) ) { continue; } if( i>ng&&ae_fp_less_eq(v,(double)(0)) ) { continue; } state->samplef.ptr.p_double[sampleidx] = state->samplef.ptr.p_double[sampleidx]+state->agsrhononlinear*ae_fabs(v, _state); s = (double)(ae_sign(v, _state)); for(j=0; j<=n-1; j++) { state->samplegm.ptr.pp_double[sampleidx][j] = state->samplegm.ptr.pp_double[sampleidx][j]+state->agsrhononlinear*s*state->j.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; } } } /************************************************************************* This function performs transformation of X from scaled coordinates to unscaled ones, paying special attention to box constraints: * points which were exactly at the boundary before scaling will be mapped to corresponding boundary after scaling * in any case, unscaled box constraints will be satisfied -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_unscalepointbc(minnsstate* state, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; for(i=0; i<=state->n-1; i++) { if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; continue; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; continue; } x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]; if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; } if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) { x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; } } } /************************************************************************* This function solves QP problem of the form [ ] min [ 0.5*c'*(G*inv(H)*G')*c ] s.t. c[i]>=0, SUM(c[i])=1.0 [ ] where G is stored in SampleG[] array, diagonal H is stored in DiagH[]. DbgNCholesky is incremented every time we perform Cholesky decomposition. -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_solveqp(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, ae_int_t* dbgncholesky, minnsqp* state, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double v; double vv; ae_int_t n; ae_int_t nr; ae_int_t idx0; ae_int_t idx1; ae_int_t ncandbnd; ae_int_t innerits; ae_int_t outerits; double dnrm; double stp; double stpmax; ae_int_t actidx; double dtol; ae_bool kickneeded; ae_bool terminationneeded; double kicklength; double lambdav; double maxdiag; ae_bool wasactivation; ae_bool werechanges; ae_int_t termcnt; n = nsample; nr = nvars; /* * Allocate arrays, prepare data */ rvectorsetlengthatleast(coeffs, n, _state); rvectorsetlengthatleast(&state->xc, n, _state); rvectorsetlengthatleast(&state->xn, n, _state); rvectorsetlengthatleast(&state->x0, n, _state); rvectorsetlengthatleast(&state->gc, n, _state); rvectorsetlengthatleast(&state->d, n, _state); rmatrixsetlengthatleast(&state->uh, n, n, _state); rmatrixsetlengthatleast(&state->ch, n, n, _state); rmatrixsetlengthatleast(&state->rk, nsample, nvars, _state); rvectorsetlengthatleast(&state->invutc, n, _state); rvectorsetlengthatleast(&state->tmp0, n, _state); bvectorsetlengthatleast(&state->tmpb, n, _state); for(i=0; i<=n-1; i++) { state->xc.ptr.p_double[i] = 1.0/n; coeffs->ptr.p_double[i] = 1.0/n; } for(i=0; i<=nsample-1; i++) { for(j=0; j<=nvars-1; j++) { state->rk.ptr.pp_double[i][j] = sampleg->ptr.pp_double[i][j]/ae_sqrt(diagh->ptr.p_double[j], _state); } } rmatrixsyrk(nsample, nvars, 1.0, &state->rk, 0, 0, 0, 0.0, &state->uh, 0, 0, ae_true, _state); maxdiag = 0.0; for(i=0; i<=nsample-1; i++) { maxdiag = ae_maxreal(maxdiag, state->uh.ptr.pp_double[i][i], _state); } maxdiag = coalesce(maxdiag, 1.0, _state); /* * Main cycle: */ innerits = 0; outerits = 0; dtol = 1.0E5*ae_machineepsilon; kicklength = ae_machineepsilon; lambdav = 1.0E5*ae_machineepsilon; terminationneeded = ae_false; termcnt = 0; for(;;) { /* * Save current point to X0 */ ae_v_move(&state->x0.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Calculate gradient at initial point, solve NNLS problem * to determine descent direction D subject to constraints. * * In order to do so we solve following constrained * minimization problem: * ( )^2 * min ( SUM(lambda[i]*A[i]) + G ) * ( ) * Here: * * G is a gradient (column vector) * * A[i] is a column vector of I-th constraint * * lambda[i] is a Lagrange multiplier corresponding to I-th constraint * * NOTE: all A[i] except for last one have only one element being set, * so we rely on sparse capabilities of NNLS solver. However, * in order to use these capabilities we have to reorder variables * in such way that sparse ones come first. * * After finding lambda[] coefficients, we can find constrained descent * direction by subtracting lambda[i]*A[i] from D=-G. We make use of the * fact that first NCandBnd columns are just columns of identity matrix, * so we can perform exact projection by explicitly setting elements of D * to zeros. */ minns_qpcalculategradfunc(sampleg, diagh, nsample, nvars, &state->xc, &state->gc, &state->fc, &state->tmp0, _state); ivectorsetlengthatleast(&state->tmpidx, n, _state); rvectorsetlengthatleast(&state->tmpd, n, _state); rmatrixsetlengthatleast(&state->tmpc2, n, 1, _state); idx0 = 0; ncandbnd = 0; for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xc.ptr.p_double[i],0.0) ) { ncandbnd = ncandbnd+1; } } idx1 = ncandbnd; for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xc.ptr.p_double[i],0.0) ) { /* * Candidate for activation of boundary constraint, * comes first. * * NOTE: multiplication by -1 is due to the fact that * it is lower bound, and has specific direction * of constraint gradient. */ state->tmpidx.ptr.p_int[idx0] = i; state->tmpd.ptr.p_double[idx0] = (-state->gc.ptr.p_double[i])*(-1); state->tmpc2.ptr.pp_double[idx0][0] = 1.0*(-1); idx0 = idx0+1; } else { /* * We are far away from boundary. */ state->tmpidx.ptr.p_int[idx1] = i; state->tmpd.ptr.p_double[idx1] = -state->gc.ptr.p_double[i]; state->tmpc2.ptr.pp_double[idx1][0] = 1.0; idx1 = idx1+1; } } ae_assert(idx0==ncandbnd, "MinNSQP: integrity check failed", _state); ae_assert(idx1==n, "MinNSQP: integrity check failed", _state); snnlsinit(n, 1, n, &state->nnls, _state); snnlssetproblem(&state->nnls, &state->tmpc2, &state->tmpd, ncandbnd, 1, n, _state); snnlsdropnnc(&state->nnls, ncandbnd, _state); snnlssolve(&state->nnls, &state->tmplambdas, _state); for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = -state->gc.ptr.p_double[i]-state->tmplambdas.ptr.p_double[ncandbnd]; } for(i=0; i<=ncandbnd-1; i++) { if( ae_fp_greater(state->tmplambdas.ptr.p_double[i],(double)(0)) ) { state->d.ptr.p_double[state->tmpidx.ptr.p_int[i]] = 0.0; } } /* * Additional stage to "polish" D (improve situation * with sum-to-one constraint and boundary constraints) * and to perform additional integrity check. * * After this stage we are pretty sure that: * * if x[i]=0.0, then d[i]>=0.0 * * if d[i]<0.0, then x[i]>0.0 */ v = 0.0; vv = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_less(state->d.ptr.p_double[i],0.0) ) { state->d.ptr.p_double[i] = 0.0; } v = v+state->d.ptr.p_double[i]; vv = ae_maxreal(vv, ae_fabs(state->gc.ptr.p_double[i], _state), _state); } ae_assert(ae_fp_less(ae_fabs(v, _state),1.0E5*ae_sqrt((double)(n), _state)*ae_machineepsilon*ae_maxreal(vv, 1.0, _state)), "MinNSQP: integrity check failed", _state); /* * Decide whether we need "kick" stage: special stage * that moves us away from boundary constraints which are * not strictly active (i.e. such constraints that x[i]=0.0 and d[i]>0). * * If we need kick stage, we make a kick - and restart iteration. * If not, after this block we can rely on the fact that * for all x[i]=0.0 we have d[i]=0.0 */ kickneeded = ae_false; for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->d.ptr.p_double[i],0.0) ) { kickneeded = ae_true; } } if( kickneeded ) { /* * Perform kick. * Restart. * Do not increase outer iterations counter. */ v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->d.ptr.p_double[i],0.0) ) { state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]+kicklength; } v = v+state->xc.ptr.p_double[i]; } ae_assert(ae_fp_greater(v,0.0), "MinNSQP: integrity check failed", _state); for(i=0; i<=n-1; i++) { state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]/v; } inc(&innerits, _state); continue; } /* * Calculate Cholesky decomposition of constrained Hessian * for Newton phase. */ for(;;) { for(i=0; i<=n-1; i++) { /* * Diagonal element */ if( ae_fp_greater(state->xc.ptr.p_double[i],0.0) ) { state->ch.ptr.pp_double[i][i] = state->uh.ptr.pp_double[i][i]+lambdav*maxdiag; } else { state->ch.ptr.pp_double[i][i] = 1.0; } /* * Offdiagonal elements */ for(j=i+1; j<=n-1; j++) { if( ae_fp_greater(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->xc.ptr.p_double[j],0.0) ) { state->ch.ptr.pp_double[i][j] = state->uh.ptr.pp_double[i][j]; } else { state->ch.ptr.pp_double[i][j] = 0.0; } } } inc(dbgncholesky, _state); if( !spdmatrixcholeskyrec(&state->ch, 0, n, ae_true, &state->tmp0, _state) ) { /* * Cholesky decomposition failed. * Increase LambdaV and repeat iteration. * Do not increase outer iterations counter. */ lambdav = lambdav*10; continue; } break; } /* * Newton phase */ for(;;) { /* * Calculate constrained (equality and sum-to-one) descent direction D. * * Here we use Sherman-Morrison update to calculate direction subject to * sum-to-one constraint. */ minns_qpcalculategradfunc(sampleg, diagh, nsample, nvars, &state->xc, &state->gc, &state->fc, &state->tmp0, _state); for(i=0; i<=n-1; i++) { if( ae_fp_greater(state->xc.ptr.p_double[i],0.0) ) { state->invutc.ptr.p_double[i] = 1.0; state->d.ptr.p_double[i] = -state->gc.ptr.p_double[i]; } else { state->invutc.ptr.p_double[i] = 0.0; state->d.ptr.p_double[i] = 0.0; } } minns_qpsolveut(&state->ch, n, &state->invutc, _state); minns_qpsolveut(&state->ch, n, &state->d, _state); v = 0.0; vv = 0.0; for(i=0; i<=n-1; i++) { vv = vv+ae_sqr(state->invutc.ptr.p_double[i], _state); v = v+state->invutc.ptr.p_double[i]*state->d.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { state->d.ptr.p_double[i] = state->d.ptr.p_double[i]-v/vv*state->invutc.ptr.p_double[i]; } minns_qpsolveu(&state->ch, n, &state->d, _state); v = 0.0; k = 0; for(i=0; i<=n-1; i++) { v = v+state->d.ptr.p_double[i]; if( ae_fp_neq(state->d.ptr.p_double[i],0.0) ) { k = k+1; } } if( k>0&&ae_fp_greater(v,0.0) ) { vv = v/k; for(i=0; i<=n-1; i++) { if( ae_fp_neq(state->d.ptr.p_double[i],0.0) ) { state->d.ptr.p_double[i] = state->d.ptr.p_double[i]-vv; } } } /* * Calculate length of D, maximum step and component which is * activated by this step. * * Break if D is exactly zero. We do not break here if DNrm is * small - this check is performed later. It is important to * perform last step with nearly-zero D, it allows us to have * extra-precision in solution which is often needed for convergence * of AGS algorithm. */ dnrm = 0.0; for(i=0; i<=n-1; i++) { dnrm = dnrm+ae_sqr(state->d.ptr.p_double[i], _state); } dnrm = ae_sqrt(dnrm, _state); actidx = -1; stpmax = 1.0E50; for(i=0; i<=n-1; i++) { if( ae_fp_less(state->d.ptr.p_double[i],0.0) ) { v = stpmax; stpmax = safeminposrv(state->xc.ptr.p_double[i], -state->d.ptr.p_double[i], stpmax, _state); if( ae_fp_less(stpmax,v) ) { actidx = i; } } } if( ae_fp_eq(dnrm,0.0) ) { break; } /* * Calculate trial function value at unconstrained full step. * If trial value is greater or equal to FC, terminate iterations. */ for(i=0; i<=n-1; i++) { state->xn.ptr.p_double[i] = state->xc.ptr.p_double[i]+1.0*state->d.ptr.p_double[i]; } minns_qpcalculatefunc(sampleg, diagh, nsample, nvars, &state->xn, &state->fn, &state->tmp0, _state); if( ae_fp_greater_eq(state->fn,state->fc) ) { break; } /* * Perform step * Update Hessian * Update XC * * Break if: * a) no constraint was activated * b) norm of D is small enough */ stp = ae_minreal(1.0, stpmax, _state); for(i=0; i<=n-1; i++) { state->xn.ptr.p_double[i] = ae_maxreal(state->xc.ptr.p_double[i]+stp*state->d.ptr.p_double[i], 0.0, _state); } if( ae_fp_eq(stp,stpmax)&&actidx>=0 ) { state->xn.ptr.p_double[actidx] = 0.0; } wasactivation = ae_false; for(i=0; i<=n-1; i++) { state->tmpb.ptr.p_bool[i] = ae_fp_eq(state->xn.ptr.p_double[i],0.0)&&ae_fp_neq(state->xc.ptr.p_double[i],0.0); wasactivation = wasactivation||state->tmpb.ptr.p_bool[i]; } ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( !wasactivation ) { break; } if( ae_fp_less_eq(dnrm,dtol) ) { break; } spdmatrixcholeskyupdatefixbuf(&state->ch, n, ae_true, &state->tmpb, &state->tmp0, _state); } /* * Compare status of boundary constraints - if nothing changed during * last outer iteration, TermCnt is increased. Otherwise it is reset * to zero. * * When TermCnt is large enough, we terminate algorithm. */ werechanges = ae_false; for(i=0; i<=n-1; i++) { werechanges = werechanges||ae_sign(state->x0.ptr.p_double[i], _state)!=ae_sign(state->xc.ptr.p_double[i], _state); } if( !werechanges ) { inc(&termcnt, _state); } else { termcnt = 0; } if( termcnt>=2 ) { break; } /* * Increase number of outer iterations. * Break if we performed too many. */ inc(&outerits, _state); if( outerits==10 ) { break; } } /* * Store result */ for(i=0; i<=n-1; i++) { coeffs->ptr.p_double[i] = state->xc.ptr.p_double[i]; } } /************************************************************************* Function/gradient calculation for QP solver. -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_qpcalculategradfunc(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, /* Real */ ae_vector* g, double* f, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; double v; *f = 0; rvectorsetlengthatleast(g, nsample, _state); rvectorsetlengthatleast(tmp, nvars, _state); /* * Calculate GS*p */ for(j=0; j<=nvars-1; j++) { tmp->ptr.p_double[j] = 0.0; } for(i=0; i<=nsample-1; i++) { v = coeffs->ptr.p_double[i]; ae_v_addd(&tmp->ptr.p_double[0], 1, &sampleg->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); } /* * Calculate F */ *f = 0.0; for(i=0; i<=nvars-1; i++) { *f = *f+0.5*ae_sqr(tmp->ptr.p_double[i], _state)/diagh->ptr.p_double[i]; } /* * Multiply by inverse Hessian */ for(i=0; i<=nvars-1; i++) { tmp->ptr.p_double[i] = tmp->ptr.p_double[i]/diagh->ptr.p_double[i]; } /* * Function gradient */ for(i=0; i<=nsample-1; i++) { v = ae_v_dotproduct(&sampleg->ptr.pp_double[i][0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,nvars-1)); g->ptr.p_double[i] = v; } } /************************************************************************* Function calculation for QP solver. -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_qpcalculatefunc(/* Real */ ae_matrix* sampleg, /* Real */ ae_vector* diagh, ae_int_t nsample, ae_int_t nvars, /* Real */ ae_vector* coeffs, double* f, /* Real */ ae_vector* tmp, ae_state *_state) { ae_int_t i; ae_int_t j; double v; *f = 0; rvectorsetlengthatleast(tmp, nvars, _state); /* * Calculate GS*p */ for(j=0; j<=nvars-1; j++) { tmp->ptr.p_double[j] = 0.0; } for(i=0; i<=nsample-1; i++) { v = coeffs->ptr.p_double[i]; ae_v_addd(&tmp->ptr.p_double[0], 1, &sampleg->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); } /* * Calculate F */ *f = 0.0; for(i=0; i<=nvars-1; i++) { *f = *f+0.5*ae_sqr(tmp->ptr.p_double[i], _state)/diagh->ptr.p_double[i]; } } /************************************************************************* Triangular solver for QP solver. -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_qpsolveu(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; ae_int_t j; double v; /* * A^(-1)*X */ for(i=n-1; i>=0; i--) { v = x->ptr.p_double[i]; for(j=i+1; j<=n-1; j++) { v = v-a->ptr.pp_double[i][j]*x->ptr.p_double[j]; } x->ptr.p_double[i] = v/a->ptr.pp_double[i][i]; } } /************************************************************************* Triangular solver for QP solver. -- ALGLIB -- Copyright 02.06.2015 by Bochkanov Sergey *************************************************************************/ static void minns_qpsolveut(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) { ae_int_t i; ae_int_t j; double v; /* * A^(-T)*X */ for(i=0; i<=n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]/a->ptr.pp_double[i][i]; v = x->ptr.p_double[i]; for(j=i+1; j<=n-1; j++) { x->ptr.p_double[j] = x->ptr.p_double[j]-a->ptr.pp_double[i][j]*v; } } } void _minnsqp_init(void* _p, ae_state *_state) { minnsqp *p = (minnsqp*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->xc, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->x0, 0, DT_REAL, _state); ae_vector_init(&p->gc, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_matrix_init(&p->uh, 0, 0, DT_REAL, _state); ae_matrix_init(&p->ch, 0, 0, DT_REAL, _state); ae_matrix_init(&p->rk, 0, 0, DT_REAL, _state); ae_vector_init(&p->invutc, 0, DT_REAL, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmpidx, 0, DT_INT, _state); ae_vector_init(&p->tmpd, 0, DT_REAL, _state); ae_vector_init(&p->tmpc, 0, DT_REAL, _state); ae_vector_init(&p->tmplambdas, 0, DT_REAL, _state); ae_matrix_init(&p->tmpc2, 0, 0, DT_REAL, _state); ae_vector_init(&p->tmpb, 0, DT_BOOL, _state); _snnlssolver_init(&p->nnls, _state); } void _minnsqp_init_copy(void* _dst, void* _src, ae_state *_state) { minnsqp *dst = (minnsqp*)_dst; minnsqp *src = (minnsqp*)_src; dst->fc = src->fc; dst->fn = src->fn; ae_vector_init_copy(&dst->xc, &src->xc, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->x0, &src->x0, _state); ae_vector_init_copy(&dst->gc, &src->gc, _state); ae_vector_init_copy(&dst->d, &src->d, _state); ae_matrix_init_copy(&dst->uh, &src->uh, _state); ae_matrix_init_copy(&dst->ch, &src->ch, _state); ae_matrix_init_copy(&dst->rk, &src->rk, _state); ae_vector_init_copy(&dst->invutc, &src->invutc, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmpidx, &src->tmpidx, _state); ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state); ae_vector_init_copy(&dst->tmpc, &src->tmpc, _state); ae_vector_init_copy(&dst->tmplambdas, &src->tmplambdas, _state); ae_matrix_init_copy(&dst->tmpc2, &src->tmpc2, _state); ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state); _snnlssolver_init_copy(&dst->nnls, &src->nnls, _state); } void _minnsqp_clear(void* _p) { minnsqp *p = (minnsqp*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->xc); ae_vector_clear(&p->xn); ae_vector_clear(&p->x0); ae_vector_clear(&p->gc); ae_vector_clear(&p->d); ae_matrix_clear(&p->uh); ae_matrix_clear(&p->ch); ae_matrix_clear(&p->rk); ae_vector_clear(&p->invutc); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmpidx); ae_vector_clear(&p->tmpd); ae_vector_clear(&p->tmpc); ae_vector_clear(&p->tmplambdas); ae_matrix_clear(&p->tmpc2); ae_vector_clear(&p->tmpb); _snnlssolver_clear(&p->nnls); } void _minnsqp_destroy(void* _p) { minnsqp *p = (minnsqp*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->xc); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->x0); ae_vector_destroy(&p->gc); ae_vector_destroy(&p->d); ae_matrix_destroy(&p->uh); ae_matrix_destroy(&p->ch); ae_matrix_destroy(&p->rk); ae_vector_destroy(&p->invutc); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmpidx); ae_vector_destroy(&p->tmpd); ae_vector_destroy(&p->tmpc); ae_vector_destroy(&p->tmplambdas); ae_matrix_destroy(&p->tmpc2); ae_vector_destroy(&p->tmpb); _snnlssolver_destroy(&p->nnls); } void _minnsstate_init(void* _p, ae_state *_state) { minnsstate *p = (minnsstate*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->s, 0, DT_REAL, _state); ae_vector_init(&p->bndl, 0, DT_REAL, _state); ae_vector_init(&p->bndu, 0, DT_REAL, _state); ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state); ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state); ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->x, 0, DT_REAL, _state); ae_vector_init(&p->fi, 0, DT_REAL, _state); ae_matrix_init(&p->j, 0, 0, DT_REAL, _state); _rcommstate_init(&p->rstate, _state); _rcommstate_init(&p->rstateags, _state); _hqrndstate_init(&p->agsrs, _state); ae_vector_init(&p->xstart, 0, DT_REAL, _state); ae_vector_init(&p->xc, 0, DT_REAL, _state); ae_vector_init(&p->xn, 0, DT_REAL, _state); ae_vector_init(&p->grs, 0, DT_REAL, _state); ae_vector_init(&p->d, 0, DT_REAL, _state); ae_vector_init(&p->colmax, 0, DT_REAL, _state); ae_vector_init(&p->diagh, 0, DT_REAL, _state); ae_vector_init(&p->signmin, 0, DT_REAL, _state); ae_vector_init(&p->signmax, 0, DT_REAL, _state); ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state); ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state); ae_matrix_init(&p->scaledcleic, 0, 0, DT_REAL, _state); ae_vector_init(&p->rholinear, 0, DT_REAL, _state); ae_matrix_init(&p->samplex, 0, 0, DT_REAL, _state); ae_matrix_init(&p->samplegm, 0, 0, DT_REAL, _state); ae_matrix_init(&p->samplegmbc, 0, 0, DT_REAL, _state); ae_vector_init(&p->samplef, 0, DT_REAL, _state); ae_vector_init(&p->samplef0, 0, DT_REAL, _state); _minnsqp_init(&p->nsqp, _state); ae_vector_init(&p->tmp0, 0, DT_REAL, _state); ae_vector_init(&p->tmp1, 0, DT_REAL, _state); ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state); ae_vector_init(&p->tmp3, 0, DT_INT, _state); ae_vector_init(&p->xbase, 0, DT_REAL, _state); ae_vector_init(&p->fp, 0, DT_REAL, _state); ae_vector_init(&p->fm, 0, DT_REAL, _state); } void _minnsstate_init_copy(void* _dst, void* _src, ae_state *_state) { minnsstate *dst = (minnsstate*)_dst; minnsstate *src = (minnsstate*)_src; dst->solvertype = src->solvertype; dst->n = src->n; dst->epsx = src->epsx; dst->maxits = src->maxits; dst->xrep = src->xrep; dst->diffstep = src->diffstep; ae_vector_init_copy(&dst->s, &src->s, _state); ae_vector_init_copy(&dst->bndl, &src->bndl, _state); ae_vector_init_copy(&dst->bndu, &src->bndu, _state); ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state); ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state); dst->nec = src->nec; dst->nic = src->nic; ae_matrix_init_copy(&dst->cleic, &src->cleic, _state); dst->ng = src->ng; dst->nh = src->nh; ae_vector_init_copy(&dst->x, &src->x, _state); dst->f = src->f; ae_vector_init_copy(&dst->fi, &src->fi, _state); ae_matrix_init_copy(&dst->j, &src->j, _state); dst->needfij = src->needfij; dst->needfi = src->needfi; dst->xupdated = src->xupdated; _rcommstate_init_copy(&dst->rstate, &src->rstate, _state); _rcommstate_init_copy(&dst->rstateags, &src->rstateags, _state); _hqrndstate_init_copy(&dst->agsrs, &src->agsrs, _state); dst->agsradius = src->agsradius; dst->agssamplesize = src->agssamplesize; dst->agsraddecay = src->agsraddecay; dst->agsalphadecay = src->agsalphadecay; dst->agsdecrease = src->agsdecrease; dst->agsinitstp = src->agsinitstp; dst->agsstattold = src->agsstattold; dst->agsshortstpabs = src->agsshortstpabs; dst->agsshortstprel = src->agsshortstprel; dst->agsshortf = src->agsshortf; dst->agsshortlimit = src->agsshortlimit; dst->agsrhononlinear = src->agsrhononlinear; dst->agsminupdate = src->agsminupdate; dst->agsmaxraddecays = src->agsmaxraddecays; dst->agsmaxbacktrack = src->agsmaxbacktrack; dst->agsmaxbacktracknonfull = src->agsmaxbacktracknonfull; dst->agspenaltylevel = src->agspenaltylevel; dst->agspenaltyincrease = src->agspenaltyincrease; ae_vector_init_copy(&dst->xstart, &src->xstart, _state); ae_vector_init_copy(&dst->xc, &src->xc, _state); ae_vector_init_copy(&dst->xn, &src->xn, _state); ae_vector_init_copy(&dst->grs, &src->grs, _state); ae_vector_init_copy(&dst->d, &src->d, _state); ae_vector_init_copy(&dst->colmax, &src->colmax, _state); ae_vector_init_copy(&dst->diagh, &src->diagh, _state); ae_vector_init_copy(&dst->signmin, &src->signmin, _state); ae_vector_init_copy(&dst->signmax, &src->signmax, _state); dst->userterminationneeded = src->userterminationneeded; ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state); ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state); ae_matrix_init_copy(&dst->scaledcleic, &src->scaledcleic, _state); ae_vector_init_copy(&dst->rholinear, &src->rholinear, _state); ae_matrix_init_copy(&dst->samplex, &src->samplex, _state); ae_matrix_init_copy(&dst->samplegm, &src->samplegm, _state); ae_matrix_init_copy(&dst->samplegmbc, &src->samplegmbc, _state); ae_vector_init_copy(&dst->samplef, &src->samplef, _state); ae_vector_init_copy(&dst->samplef0, &src->samplef0, _state); _minnsqp_init_copy(&dst->nsqp, &src->nsqp, _state); ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state); ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state); ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state); ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state); ae_vector_init_copy(&dst->xbase, &src->xbase, _state); ae_vector_init_copy(&dst->fp, &src->fp, _state); ae_vector_init_copy(&dst->fm, &src->fm, _state); dst->repinneriterationscount = src->repinneriterationscount; dst->repouteriterationscount = src->repouteriterationscount; dst->repnfev = src->repnfev; dst->repvaridx = src->repvaridx; dst->repfuncidx = src->repfuncidx; dst->repterminationtype = src->repterminationtype; dst->replcerr = src->replcerr; dst->repnlcerr = src->repnlcerr; dst->dbgncholesky = src->dbgncholesky; } void _minnsstate_clear(void* _p) { minnsstate *p = (minnsstate*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->s); ae_vector_clear(&p->bndl); ae_vector_clear(&p->bndu); ae_vector_clear(&p->hasbndl); ae_vector_clear(&p->hasbndu); ae_matrix_clear(&p->cleic); ae_vector_clear(&p->x); ae_vector_clear(&p->fi); ae_matrix_clear(&p->j); _rcommstate_clear(&p->rstate); _rcommstate_clear(&p->rstateags); _hqrndstate_clear(&p->agsrs); ae_vector_clear(&p->xstart); ae_vector_clear(&p->xc); ae_vector_clear(&p->xn); ae_vector_clear(&p->grs); ae_vector_clear(&p->d); ae_vector_clear(&p->colmax); ae_vector_clear(&p->diagh); ae_vector_clear(&p->signmin); ae_vector_clear(&p->signmax); ae_vector_clear(&p->scaledbndl); ae_vector_clear(&p->scaledbndu); ae_matrix_clear(&p->scaledcleic); ae_vector_clear(&p->rholinear); ae_matrix_clear(&p->samplex); ae_matrix_clear(&p->samplegm); ae_matrix_clear(&p->samplegmbc); ae_vector_clear(&p->samplef); ae_vector_clear(&p->samplef0); _minnsqp_clear(&p->nsqp); ae_vector_clear(&p->tmp0); ae_vector_clear(&p->tmp1); ae_matrix_clear(&p->tmp2); ae_vector_clear(&p->tmp3); ae_vector_clear(&p->xbase); ae_vector_clear(&p->fp); ae_vector_clear(&p->fm); } void _minnsstate_destroy(void* _p) { minnsstate *p = (minnsstate*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->s); ae_vector_destroy(&p->bndl); ae_vector_destroy(&p->bndu); ae_vector_destroy(&p->hasbndl); ae_vector_destroy(&p->hasbndu); ae_matrix_destroy(&p->cleic); ae_vector_destroy(&p->x); ae_vector_destroy(&p->fi); ae_matrix_destroy(&p->j); _rcommstate_destroy(&p->rstate); _rcommstate_destroy(&p->rstateags); _hqrndstate_destroy(&p->agsrs); ae_vector_destroy(&p->xstart); ae_vector_destroy(&p->xc); ae_vector_destroy(&p->xn); ae_vector_destroy(&p->grs); ae_vector_destroy(&p->d); ae_vector_destroy(&p->colmax); ae_vector_destroy(&p->diagh); ae_vector_destroy(&p->signmin); ae_vector_destroy(&p->signmax); ae_vector_destroy(&p->scaledbndl); ae_vector_destroy(&p->scaledbndu); ae_matrix_destroy(&p->scaledcleic); ae_vector_destroy(&p->rholinear); ae_matrix_destroy(&p->samplex); ae_matrix_destroy(&p->samplegm); ae_matrix_destroy(&p->samplegmbc); ae_vector_destroy(&p->samplef); ae_vector_destroy(&p->samplef0); _minnsqp_destroy(&p->nsqp); ae_vector_destroy(&p->tmp0); ae_vector_destroy(&p->tmp1); ae_matrix_destroy(&p->tmp2); ae_vector_destroy(&p->tmp3); ae_vector_destroy(&p->xbase); ae_vector_destroy(&p->fp); ae_vector_destroy(&p->fm); } void _minnsreport_init(void* _p, ae_state *_state) { minnsreport *p = (minnsreport*)_p; ae_touch_ptr((void*)p); } void _minnsreport_init_copy(void* _dst, void* _src, ae_state *_state) { minnsreport *dst = (minnsreport*)_dst; minnsreport *src = (minnsreport*)_src; dst->iterationscount = src->iterationscount; dst->nfev = src->nfev; dst->cerr = src->cerr; dst->lcerr = src->lcerr; dst->nlcerr = src->nlcerr; dst->terminationtype = src->terminationtype; dst->varidx = src->varidx; dst->funcidx = src->funcidx; } void _minnsreport_clear(void* _p) { minnsreport *p = (minnsreport*)_p; ae_touch_ptr((void*)p); } void _minnsreport_destroy(void* _p) { minnsreport *p = (minnsreport*)_p; ae_touch_ptr((void*)p); } } qmapshack-1.10.0/3rdparty/alglib/tests/000755 001750 000144 00000000000 13216664442 021076 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/3rdparty/alglib/tests/test_x.cpp000755 001750 000144 00000171772 13015033052 023112 0ustar00oeichlerxusers000000 000000 #include "stdafx.h" #include #include "alglibmisc.h" #include "alglibinternal.h" #include "linalg.h" #include "statistics.h" #include "dataanalysis.h" #include "specialfunctions.h" #include "solvers.h" #include "optimization.h" #include "diffequations.h" #include "fasttransforms.h" #include "integration.h" #include "interpolation.h" using namespace alglib; const char *fmt_str = "%-29s %s\n"; // // Flag variables // bool issue505_passed = true; bool issue478_passed = true; bool issue528_passed = true; bool issue591_passed = true; bool issue594_passed = true; // // Service datatypes // typedef struct { alglib_impl::ae_complex cval; double rval; alglib_impl::ae_int_t ival; ae_bool bval; alglib_impl::ae_vector i1val; } innerrec; typedef struct { ae_bool bval; innerrec recval; alglib_impl::ae_shared_pool pool; } seedrec; void _innerrec_init(void* _p, alglib_impl::ae_state *_state) { innerrec *p = (innerrec*)_p; alglib_impl::ae_touch_ptr((void*)p); alglib_impl::ae_vector_init(&p->i1val, 0, alglib_impl::DT_INT, _state); } void _innerrec_init_copy(void* _dst, void* _src, alglib_impl::ae_state *_state) { innerrec *dst = (innerrec*)_dst; innerrec *src = (innerrec*)_src; dst->cval = src->cval; dst->rval = src->rval; dst->ival = src->ival; dst->bval = src->bval; alglib_impl::ae_vector_init_copy(&dst->i1val, &src->i1val, _state); } void _innerrec_clear(void* _p) { innerrec *p = (innerrec*)_p; alglib_impl::ae_touch_ptr((void*)p); alglib_impl::ae_vector_clear(&p->i1val); } void _innerrec_destroy(void* _p) { innerrec *p = (innerrec*)_p; alglib_impl::ae_touch_ptr((void*)p); alglib_impl::ae_vector_destroy(&p->i1val); } void _seedrec_init(void* _p, alglib_impl::ae_state *_state) { seedrec *p = (seedrec*)_p; alglib_impl::ae_touch_ptr((void*)p); _innerrec_init(&p->recval, _state); alglib_impl::ae_shared_pool_init(&p->pool, _state); } void _seedrec_init_copy(void* _dst, void* _src, alglib_impl::ae_state *_state) { seedrec *dst = (seedrec*)_dst; seedrec *src = (seedrec*)_src; dst->bval = src->bval; _innerrec_init_copy(&dst->recval, &src->recval, _state); alglib_impl::ae_shared_pool_init_copy(&dst->pool, &src->pool, _state); } void _seedrec_clear(void* _p) { seedrec *p = (seedrec*)_p; alglib_impl::ae_touch_ptr((void*)p); _innerrec_clear(&p->recval); alglib_impl::ae_shared_pool_clear(&p->pool); } void _seedrec_destroy(void* _p) { seedrec *p = (seedrec*)_p; alglib_impl::ae_touch_ptr((void*)p); _innerrec_destroy(&p->recval); alglib_impl::ae_shared_pool_destroy(&p->pool); } void func505_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { double x0 = *((double*)ptr); // // This block assigns zero vector to gradient. Because gradient is a proxy vector // (vector which uses another object as storage), sizes of gradient and vector being // assigned must be equal. In this case data are copied in the memory linked with // proxy. // // Early versions of ALGLIB failed to handle such assignment (it discrupted link // between proxy vector and actual gradient stored in the internals of ALGLIB). // real_1d_array z = "[0]"; grad = "[0]"; grad = z; // // This block tries to perform operations which are forbidden for proxy vector: // * assign vector of non-matching size // * change length of the vector // Correct implementation must throw an exception without breaking a link between // proxy object and actual vector. // z = "[0,1]"; try { grad = "[0,1]"; issue505_passed = false; } catch(...) {} try { grad = z; issue505_passed = false; } catch(...) {} try { grad.setlength(10); issue505_passed = false; } catch(...) {} try { grad.setlength(1); issue505_passed = false; } catch(...) {} // // This block actually calculates function/gradient // func = pow(x[0]-x0,4); grad[0] = 4*pow(x[0]-x0,3); } void func505_vec(const real_1d_array &x, real_1d_array &fi, void *ptr) { double x0 = *((double*)ptr); fi[0] = x[0]-x0; fi[1] = pow(x[0]-x0,2); } void func505_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { double x0 = *((double*)ptr); // // This block assigns zero matrix to Jacobian. Because Jacobian is a proxy matrix // (matrix which uses another object as storage), sizes of Jacobian and matrix being // assigned must be equal. In this case data are copied in the memory linked with // proxy. // // Early versions of ALGLIB failed to handle such assignment (it discrupted link // between proxy and actual matrix stored in the internals of ALGLIB). // real_2d_array z = "[[0],[0]]"; jac = "[[0],[0]]"; jac = z; // // This block tries to perform operations which are forbidden for proxy vector: // * assign vector of non-matching size // * change length of the vector // Correct implementation must throw an exception without breaking a link between // proxy object and actual vector. // try { jac = "[[0]]"; issue505_passed = false; } catch(...) {} try { jac = "[[0,0],[1,1]]"; issue505_passed = false; } catch(...) {} try { z = "[[0,1]]"; jac = z; issue505_passed = false; } catch(...) {} try { jac.setlength(10,6); issue505_passed = false; } catch(...) {} try { jac.setlength(2,1); issue505_passed = false; } catch(...) {} // // This block actually calculates function/gradient // fi[0] = x[0]-x0; fi[1] = pow(x[0]-x0,2); jac[0][0] = 1.0; jac[1][0] = 2*(x[0]-x0); } void file_put_contents(const char *filename, const char *contents) { FILE *f = fopen(filename, "wb"); if( f==NULL ) throw alglib::ap_error("file_put_contents: failed opening file"); if( fwrite((void*)contents, 1, strlen(contents), f)!=strlen(contents) ) throw alglib::ap_error("file_put_contents: failed writing to file"); fclose(f); } int main() { // // Report system properties // printf("System:\n"); #ifdef AE_HPC printf("* cores count %3ld\n", (long)alglib_impl::ae_cores_count()); #else printf("* cores count %3ld\n", (long)1); #endif // // Testing basic functionality // printf("Basic functions:\n"); { // // Testing 1D array functionality // bool passed = true; try { // // 1D boolean // // Default constructor, string constructor, copy constructor, assignment constructors: // * test that array sizes as reported by length match to what was specified // * test item-by-item access // * test to_string() // * test that modification of the copied array does not change original // * test that setlength() changes length // * test setcontent/getcontent // * test getcontent(), operator() and operator[] on constant arrays // (in this case distinct implementation is used which must be tested separately) // alglib::boolean_1d_array arr_0, arr_1("[]"), arr_2("[true,false,true]"), arr_3(arr_2), arr_4, arr_5; arr_4 = arr_2; arr_5 = "[true,true,false]"; passed = passed && (arr_0.length()==0); passed = passed && (arr_1.length()==0); passed = passed && (arr_2.length()==3); passed = passed && (arr_3.length()==3); passed = passed && (arr_2[0]==arr_2(0)) && (arr_2[1]==arr_2(1)) && (arr_2[2]==arr_2(2)); passed = passed && arr_2[0] && !arr_2[1] && arr_2[2]; passed = passed && arr_3[0] && !arr_3[1] && arr_3[2]; passed = passed && arr_4[0] && !arr_4[1] && arr_4[2]; passed = passed && arr_5[0] && arr_5[1] && !arr_5[2]; passed = passed && (arr_2.tostring()=="[true,false,true]"); passed = passed && (arr_3.tostring()=="[true,false,true]"); passed = passed && (arr_4.tostring()=="[true,false,true]"); passed = passed && (arr_5.tostring()=="[true,true,false]"); arr_2[0] = false; passed = passed && !arr_2[0] && arr_3[0] && arr_4[0]; arr_5.setlength(99); passed = passed && (arr_5.length()==99); // setcontent/getcontent bool a0[] = {true, false, true, false, false}; bool a0_mod = false; bool a0_orig = true; bool *p6; alglib::boolean_1d_array arr_6; arr_6.setcontent(5, a0); passed = passed && (arr_6[0]==a0[0]) && (arr_6[1]==a0[1]) && (arr_6[2]==a0[2]) && (arr_6[3]==a0[3]) && (arr_6[4]==a0[4]); p6 = arr_6.getcontent(); passed = passed && (p6!=a0); passed = passed && (p6[0]==a0[0]) && (p6[1]==a0[1]) && (p6[2]==a0[2]) && (p6[3]==a0[3]) && (p6[4]==a0[4]); a0[0] = a0_mod; passed = passed && (arr_6[0]!=a0[0]); a0[0] = a0_orig; // operations on constant arrays { const alglib::boolean_1d_array &ac = arr_6; passed = passed && (ac[0]==a0[0]) && (ac[1]==a0[1]) && (ac[2]==a0[2]) && (ac[3]==a0[3]) && (ac[4]==a0[4]); passed = passed && (ac(0)==a0[0]) && (ac(1)==a0[1]) && (ac(2)==a0[2]) && (ac(3)==a0[3]) && (ac(4)==a0[4]); const bool *p = ac.getcontent(); passed = passed && (p[0]==a0[0]) && (p[1]==a0[1]) && (p[2]==a0[2]) && (p[3]==a0[3]) && (p[4]==a0[4]); } // // Operations with proxy arrays: // * changes in target are propagated to proxy and vice versa // * assignments where proxy is source create new independent copy // * assignments to proxy are checked (their size must match to that of the target) // * incorrect assignments or attempts to change length must generate exception // * attempts to call setlength() must fail even when new size match original size // of the array // alglib::boolean_1d_array proxy, targt, acopy; targt = "[true,false,false,true]"; proxy.attach_to(targt.c_ptr()); acopy = proxy; passed = passed && targt[0] && !targt[1] && !targt[2] && targt[3]; passed = passed && proxy[0] && !proxy[1] && !proxy[2] && proxy[3]; passed = passed && acopy[0] && !acopy[1] && !acopy[2] && acopy[3]; targt[0] = false; passed = passed && !targt[0] && !proxy[0] && acopy[0]; proxy[0] = true; passed = passed && targt[0] && proxy[0] && acopy[0]; acopy = "[false,true,true,true]"; proxy = acopy; passed = passed && !targt[0] && targt[1] && targt[2] && targt[3]; passed = passed && !proxy[0] && proxy[1] && proxy[2] && proxy[3]; proxy = "[true,false,true,true]"; passed = passed && targt[0] && !targt[1] && targt[2] && targt[3]; passed = passed && proxy[0] && !proxy[1] && proxy[2] && proxy[3]; try { acopy = "[false,true,true]"; proxy = acopy; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy = "[true,true,true]"; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(100); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(proxy.length()); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } } catch(...) { passed = false; } try { // // 1D integer // // Default constructor, string constructor, copy constructor, assignment constructors: // * test that array sizes as reported by length match to what was specified // * test item-by-item access // * test to_string() // * test that modification of the copied array does not change original // * test that setlength() changes length // const char *s1 = "[2,3,-1]"; const char *s2 = "[5,4,3]"; const char *s3 = "[6,7,3,-4]"; const char *s4 = "[9,5,-12,-0]"; const char *s5 = "[1,7,2,1]"; const char *s6 = "[7,7,7]"; int v10 = 2, v11 = 3, v12 = -1, v10_mod = 9; int v20 = 5, v21 = 4, v22 = 3; int v30 = 6, v31 = 7, v32 = 3, v33 = -4, v30_mod = -6; int v40 = 9, v41 = 5, v42 =-12, v43 = 0; int v50 = 1, v51 = 7, v52 = 2, v53 = 1; alglib::integer_1d_array arr_0, arr_1("[]"), arr_2(s1), arr_3(arr_2), arr_4, arr_5; arr_4 = arr_2; arr_5 = s2; passed = passed && (arr_0.length()==0); passed = passed && (arr_1.length()==0); passed = passed && (arr_2.length()==3); passed = passed && (arr_3.length()==3); passed = passed && (arr_2[0]==arr_2(0)) && (arr_2[1]==arr_2(1)) && (arr_2[2]==arr_2(2)); passed = passed && (arr_2[0]==v10) && (arr_2[1]==v11) && (arr_2[2]==v12); passed = passed && (arr_3[0]==v10) && (arr_3[1]==v11) && (arr_3[2]==v12); passed = passed && (arr_4[0]==v10) && (arr_4[1]==v11) && (arr_4[2]==v12); passed = passed && (arr_5[0]==v20) && (arr_5[1]==v21) && (arr_5[2]==v22); passed = passed && (arr_2.tostring()==s1); passed = passed && (arr_3.tostring()==s1); passed = passed && (arr_4.tostring()==s1); passed = passed && (arr_5.tostring()==s2); arr_2[0] = v10_mod; passed = passed && (arr_2[0]==v10_mod) && (arr_3[0]==v10) && (arr_4[0]==v10); arr_5.setlength(99); passed = passed && (arr_5.length()==99); // setcontent/getcontent alglib::ae_int_t a0[] = {2, 3, 1, 9, 2}; alglib::ae_int_t a0_mod = 7; alglib::ae_int_t a0_orig = 2; alglib::ae_int_t *p6; alglib::integer_1d_array arr_6; arr_6.setcontent(5, a0); passed = passed && (arr_6[0]==a0[0]) && (arr_6[1]==a0[1]) && (arr_6[2]==a0[2]) && (arr_6[3]==a0[3]) && (arr_6[4]==a0[4]); p6 = arr_6.getcontent(); passed = passed && (p6!=a0); passed = passed && (p6[0]==a0[0]) && (p6[1]==a0[1]) && (p6[2]==a0[2]) && (p6[3]==a0[3]) && (p6[4]==a0[4]); a0[0] = a0_mod; passed = passed && (arr_6[0]!=a0[0]); a0[0] = a0_orig; // operations on constant arrays { const alglib::integer_1d_array &ac = arr_6; passed = passed && (ac[0]==a0[0]) && (ac[1]==a0[1]) && (ac[2]==a0[2]) && (ac[3]==a0[3]) && (ac[4]==a0[4]); passed = passed && (ac(0)==a0[0]) && (ac(1)==a0[1]) && (ac(2)==a0[2]) && (ac(3)==a0[3]) && (ac(4)==a0[4]); const alglib::ae_int_t *p = ac.getcontent(); passed = passed && (p[0]==a0[0]) && (p[1]==a0[1]) && (p[2]==a0[2]) && (p[3]==a0[3]) && (p[4]==a0[4]); } // // Operations with proxy arrays: // * changes in target are propagated to proxy and vice versa // * assignments where proxy is source create new independent copy // * assignments to proxy are checked (their size must match to that of the target) // * incorrect assignments or attempts to change length must generate exception // * attempts to call setlength() must fail even when new size match original size // of the array // alglib::integer_1d_array proxy, targt, acopy; targt = s3; proxy.attach_to(targt.c_ptr()); acopy = proxy; passed = passed && (targt[0]==v30) && (targt[1]==v31) && (targt[2]==v32) && (targt[3]==v33); passed = passed && (proxy[0]==v30) && (proxy[1]==v31) && (proxy[2]==v32) && (proxy[3]==v33); passed = passed && (acopy[0]==v30) && (acopy[1]==v31) && (acopy[2]==v32) && (acopy[3]==v33); targt[0] = v30_mod; passed = passed && (targt[0]==v30_mod) && (proxy[0]==v30_mod) && (acopy[0]==v30); proxy[0] = v30; passed = passed && (targt[0]==v30) && (proxy[0]==v30) && (acopy[0]==v30); acopy = s4; proxy = acopy; passed = passed && (targt[0]==v40) && (targt[1]==v41) && (targt[2]==v42) && (targt[3]==v43); passed = passed && (proxy[0]==v40) && (proxy[1]==v41) && (proxy[2]==v42) && (proxy[3]==v43); proxy = s5; passed = passed && (targt[0]==v50) && (targt[1]==v51) && (targt[2]==v52) && (targt[3]==v53); passed = passed && (proxy[0]==v50) && (proxy[1]==v51) && (proxy[2]==v52) && (proxy[3]==v53); try { acopy = s6; proxy = acopy; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy = s6; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(100); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(proxy.length()); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } } catch(...) { passed = false; } try { // // 1D real // // Default constructor, string constructor, copy constructor, assignment constructors: // * test that array sizes as reported by length match to what was specified // * test item-by-item access // * test to_string() // * test that modification of the copied array does not change original // * test that setlength() changes length // const char *s1 = "[2,3.5,-2.5E-1]"; const char *s1_fmt = "[2.00,3.50,-0.25]"; const char *s2 = "[5,4,3.126]"; const char *s2_fmt = "[5.00,4.00,3.13]"; const char *s3 = "[6,7,3,-4E2]"; const char *s4 = "[9,5,-12,-0.01]"; const char *s5 = "[1,7,2,1]"; const char *s6 = "[7,7,7]"; const int dps = 2; double v10 = 2, v11 = 3.5, v12 = -0.25, v10_mod = 9; double v20 = 5, v21 = 4, v22 = 3.126; double v30 = 6, v31 = 7, v32 = 3, v33 = -400, v30_mod = -6; double v40 = 9, v41 = 5, v42 =-12, v43 = -0.01; double v50 = 1, v51 = 7, v52 = 2, v53 = 1; alglib::real_1d_array arr_0, arr_1("[]"), arr_2(s1), arr_3(arr_2), arr_4, arr_5; arr_4 = arr_2; arr_5 = s2; passed = passed && (arr_0.length()==0); passed = passed && (arr_1.length()==0); passed = passed && (arr_2.length()==3); passed = passed && (arr_3.length()==3); passed = passed && (arr_2[0]==arr_2(0)) && (arr_2[1]==arr_2(1)) && (arr_2[2]==arr_2(2)); passed = passed && (arr_2[0]==v10) && (arr_2[1]==v11) && (arr_2[2]==v12); passed = passed && (arr_3[0]==v10) && (arr_3[1]==v11) && (arr_3[2]==v12); passed = passed && (arr_4[0]==v10) && (arr_4[1]==v11) && (arr_4[2]==v12); passed = passed && (arr_5[0]==v20) && (arr_5[1]==v21) && (arr_5[2]==v22); passed = passed && (arr_2.tostring(dps)==s1_fmt); passed = passed && (arr_3.tostring(dps)==s1_fmt); passed = passed && (arr_4.tostring(dps)==s1_fmt); passed = passed && (arr_5.tostring(dps)==s2_fmt); arr_2[0] = v10_mod; passed = passed && (arr_2[0]==v10_mod) && (arr_3[0]==v10) && (arr_4[0]==v10); arr_5.setlength(99); passed = passed && (arr_5.length()==99); // setcontent/getcontent double a0[] = {2, 3.5, 1, 9.125, 2}; double a0_mod = 7; double a0_orig = 2; double *p6; alglib::real_1d_array arr_6; arr_6.setcontent(5, a0); passed = passed && (arr_6[0]==a0[0]) && (arr_6[1]==a0[1]) && (arr_6[2]==a0[2]) && (arr_6[3]==a0[3]) && (arr_6[4]==a0[4]); p6 = arr_6.getcontent(); passed = passed && (p6!=a0); passed = passed && (p6[0]==a0[0]) && (p6[1]==a0[1]) && (p6[2]==a0[2]) && (p6[3]==a0[3]) && (p6[4]==a0[4]); a0[0] = a0_mod; passed = passed && (arr_6[0]!=a0[0]); a0[0] = a0_orig; // operations on constant arrays { const alglib::real_1d_array &ac = arr_6; passed = passed && (ac[0]==a0[0]) && (ac[1]==a0[1]) && (ac[2]==a0[2]) && (ac[3]==a0[3]) && (ac[4]==a0[4]); passed = passed && (ac(0)==a0[0]) && (ac(1)==a0[1]) && (ac(2)==a0[2]) && (ac(3)==a0[3]) && (ac(4)==a0[4]); const double *p = ac.getcontent(); passed = passed && (p[0]==a0[0]) && (p[1]==a0[1]) && (p[2]==a0[2]) && (p[3]==a0[3]) && (p[4]==a0[4]); } // // Operations with proxy arrays: // * changes in target are propagated to proxy and vice versa // * assignments where proxy is source create new independent copy // * assignments to proxy are checked (their size must match to that of the target) // * incorrect assignments or attempts to change length must generate exception // * attempts to call setlength() must fail even when new size match original size // of the array // alglib::real_1d_array proxy, targt, acopy; targt = s3; proxy.attach_to(targt.c_ptr()); acopy = proxy; passed = passed && (targt[0]==v30) && (targt[1]==v31) && (targt[2]==v32) && (targt[3]==v33); passed = passed && (proxy[0]==v30) && (proxy[1]==v31) && (proxy[2]==v32) && (proxy[3]==v33); passed = passed && (acopy[0]==v30) && (acopy[1]==v31) && (acopy[2]==v32) && (acopy[3]==v33); targt[0] = v30_mod; passed = passed && (targt[0]==v30_mod) && (proxy[0]==v30_mod) && (acopy[0]==v30); proxy[0] = v30; passed = passed && (targt[0]==v30) && (proxy[0]==v30) && (acopy[0]==v30); acopy = s4; proxy = acopy; passed = passed && (targt[0]==v40) && (targt[1]==v41) && (targt[2]==v42) && (targt[3]==v43); passed = passed && (proxy[0]==v40) && (proxy[1]==v41) && (proxy[2]==v42) && (proxy[3]==v43); proxy = s5; passed = passed && (targt[0]==v50) && (targt[1]==v51) && (targt[2]==v52) && (targt[3]==v53); passed = passed && (proxy[0]==v50) && (proxy[1]==v51) && (proxy[2]==v52) && (proxy[3]==v53); try { acopy = s6; proxy = acopy; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy = s6; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(100); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(proxy.length()); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } } catch(...) { passed = false; } try { // // 1D complex // // Default constructor, string constructor, copy constructor, assignment constructors: // * test that array sizes as reported by length match to what was specified // * test item-by-item access // * test to_string() // * test that modification of the copied array does not change original // * test that setlength() changes length // const char *s1 = "[2,3.5i,1-2.5E-1i]"; const char *s1_fmt = "[2.00,3.50i,1.00-0.25i]"; const char *s2 = "[5,-4+1i,3.126]"; const char *s2_fmt = "[5.00,-4.00+1.00i,3.13]"; const char *s3 = "[6,7,3,-4E2]"; const char *s4 = "[9,5,-12,-0.01]"; const char *s5 = "[1,7,2,1]"; const char *s6 = "[7,7,7]"; const int dps = 2; alglib::complex v10 = 2, v11 = alglib::complex(0,3.5), v12 = alglib::complex(1,-0.25), v10_mod = 9; alglib::complex v20 = 5, v21 = alglib::complex(-4,1), v22 = 3.126; alglib::complex v30 = 6, v31 = 7, v32 = 3, v33 = -400, v30_mod = -6; alglib::complex v40 = 9, v41 = 5, v42 =-12, v43 = -0.01; alglib::complex v50 = 1, v51 = 7, v52 = 2, v53 = 1; alglib::complex_1d_array arr_0, arr_1("[]"), arr_2(s1), arr_3(arr_2), arr_4, arr_5; arr_4 = arr_2; arr_5 = s2; passed = passed && (arr_0.length()==0); passed = passed && (arr_1.length()==0); passed = passed && (arr_2.length()==3); passed = passed && (arr_3.length()==3); passed = passed && (arr_2[0]==arr_2(0)) && (arr_2[1]==arr_2(1)) && (arr_2[2]==arr_2(2)); passed = passed && (arr_2[0]==v10) && (arr_2[1]==v11) && (arr_2[2]==v12); passed = passed && (arr_3[0]==v10) && (arr_3[1]==v11) && (arr_3[2]==v12); passed = passed && (arr_4[0]==v10) && (arr_4[1]==v11) && (arr_4[2]==v12); passed = passed && (arr_5[0]==v20) && (arr_5[1]==v21) && (arr_5[2]==v22); passed = passed && (arr_2.tostring(dps)==s1_fmt); passed = passed && (arr_3.tostring(dps)==s1_fmt); passed = passed && (arr_4.tostring(dps)==s1_fmt); passed = passed && (arr_5.tostring(dps)==s2_fmt); arr_2[0] = v10_mod; passed = passed && (arr_2[0]==v10_mod) && (arr_3[0]==v10) && (arr_4[0]==v10); arr_5.setlength(99); passed = passed && (arr_5.length()==99); // setcontent/getcontent alglib::complex a0[] = {2, 3.5, 1, 9.125, 2}; alglib::complex a0_mod = 7; alglib::complex a0_orig = 2; alglib::complex *p6; alglib::complex_1d_array arr_6; arr_6.setcontent(5, a0); passed = passed && (arr_6[0]==a0[0]) && (arr_6[1]==a0[1]) && (arr_6[2]==a0[2]) && (arr_6[3]==a0[3]) && (arr_6[4]==a0[4]); p6 = arr_6.getcontent(); passed = passed && (p6!=a0); passed = passed && (p6[0]==a0[0]) && (p6[1]==a0[1]) && (p6[2]==a0[2]) && (p6[3]==a0[3]) && (p6[4]==a0[4]); a0[0] = a0_mod; passed = passed && (arr_6[0]!=a0[0]); a0[0] = a0_orig; // operations on constant arrays { const alglib::complex_1d_array &ac = arr_6; passed = passed && (ac[0]==a0[0]) && (ac[1]==a0[1]) && (ac[2]==a0[2]) && (ac[3]==a0[3]) && (ac[4]==a0[4]); passed = passed && (ac(0)==a0[0]) && (ac(1)==a0[1]) && (ac(2)==a0[2]) && (ac(3)==a0[3]) && (ac(4)==a0[4]); const alglib::complex *p = ac.getcontent(); passed = passed && (p[0]==a0[0]) && (p[1]==a0[1]) && (p[2]==a0[2]) && (p[3]==a0[3]) && (p[4]==a0[4]); } // // Operations with proxy arrays: // * changes in target are propagated to proxy and vice versa // * assignments where proxy is source create new independent copy // * assignments to proxy are checked (their size must match to that of the target) // * incorrect assignments or attempts to change length must generate exception // * attempts to call setlength() must fail even when new size match original size // of the array // alglib::complex_1d_array proxy, targt, acopy; targt = s3; proxy.attach_to(targt.c_ptr()); acopy = proxy; passed = passed && (targt[0]==v30) && (targt[1]==v31) && (targt[2]==v32) && (targt[3]==v33); passed = passed && (proxy[0]==v30) && (proxy[1]==v31) && (proxy[2]==v32) && (proxy[3]==v33); passed = passed && (acopy[0]==v30) && (acopy[1]==v31) && (acopy[2]==v32) && (acopy[3]==v33); targt[0] = v30_mod; passed = passed && (targt[0]==v30_mod) && (proxy[0]==v30_mod) && (acopy[0]==v30); proxy[0] = v30; passed = passed && (targt[0]==v30) && (proxy[0]==v30) && (acopy[0]==v30); acopy = s4; proxy = acopy; passed = passed && (targt[0]==v40) && (targt[1]==v41) && (targt[2]==v42) && (targt[3]==v43); passed = passed && (proxy[0]==v40) && (proxy[1]==v41) && (proxy[2]==v42) && (proxy[3]==v43); proxy = s5; passed = passed && (targt[0]==v50) && (targt[1]==v51) && (targt[2]==v52) && (targt[3]==v53); passed = passed && (proxy[0]==v50) && (proxy[1]==v51) && (proxy[2]==v52) && (proxy[3]==v53); try { acopy = s6; proxy = acopy; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy = s6; passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(100); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } try { proxy.setlength(proxy.length()); passed = false; } catch(alglib::ap_error e) { } catch(...) { passed = false; } } catch(...) { passed = false; } // // Report // printf(fmt_str, "* 1D arrays", passed ? "OK" : "FAILED"); fflush(stdout); if( !passed ) return 1; } { // // Testing 2D array functionality // bool passed = true; try { // // 2D real // // Default constructor, string constructor, copy constructor, assignment constructors: // * test that array sizes as reported by length match to what was specified // * test item-by-item access // * test to_string() // * test that modification of the copied array does not change original // * test that setlength() changes length // const char *s1 = "[[2,3.5,-2.5E-1],[1,2,3]]"; const char *s1_fmt = "[[2.00,3.50,-0.25],[1.00,2.00,3.00]]"; const char *s2 = "[[5],[4],[3.126]]"; const char *s2_fmt = "[[5.00],[4.00],[3.13]]"; const char *s3 = "[[6,7],[3,-4E2],[-3,-1]]"; const char *s4 = "[[9,5],[-12,-0.01],[-1,-2]]"; const char *s5 = "[[1,7],[2,1],[0,4]]"; const char *s60 = "[[7,7],[7,7]]"; const char *s61 = "[[7],[7],[7]]"; const int dps = 2; double v10 = 2, v11 = 3.5, v12 = -0.25, v13=1, v14 = 2, v15 = 3, v10_mod = 9; double v20 = 5, v21 = 4, v22 = 3.126; /*double v30 = 6, v31 = 7, v32 = 3, v33 = -400, v30_mod = -6; double v40 = 9, v41 = 5, v42 =-12, v43 = -0.01; double v50 = 1, v51 = 7, v52 = 2, v53 = 1;*/ double r; alglib::real_2d_array arr_0, arr_1("[[]]"), arr_2(s1), arr_3(arr_2), arr_4, arr_5; arr_4 = arr_2; arr_5 = s2; passed = passed && (arr_0.rows()==0) && (arr_0.cols()==0) && (arr_0.getstride()==0); passed = passed && (arr_1.rows()==0) && (arr_1.cols()==0) && (arr_1.getstride()==0); passed = passed && (arr_2.rows()==2) && (arr_2.cols()==3) && (arr_2.getstride()>=arr_2.cols()); passed = passed && (arr_3.rows()==2) && (arr_3.cols()==3) && (arr_3.getstride()>=arr_3.cols()); passed = passed && (arr_4.rows()==2) && (arr_4.cols()==3) && (arr_4.getstride()>=arr_4.cols()); passed = passed && (arr_5.rows()==3) && (arr_5.cols()==1) && (arr_5.getstride()>=arr_5.cols()); passed = passed && (arr_2[0][0]==arr_2(0,0)) && (arr_2[0][1]==arr_2(0,1)) && (arr_2[0][2]==arr_2(0,2)); passed = passed && (arr_2[1][0]==arr_2(1,0)) && (arr_2[1][1]==arr_2(1,1)) && (arr_2[1][2]==arr_2(1,2)); passed = passed && (arr_2[0][0]==v10) && (arr_2[0][1]==v11) && (arr_2[0][2]==v12); passed = passed && (arr_2[1][0]==v13) && (arr_2[1][1]==v14) && (arr_2[1][2]==v15); passed = passed && (arr_3[0][0]==v10) && (arr_3[0][1]==v11) && (arr_3[0][2]==v12); passed = passed && (arr_3[1][0]==v13) && (arr_3[1][1]==v14) && (arr_3[1][2]==v15); passed = passed && (arr_4[0][0]==v10) && (arr_4[0][1]==v11) && (arr_4[0][2]==v12); passed = passed && (arr_4[1][0]==v13) && (arr_4[1][1]==v14) && (arr_4[1][2]==v15); passed = passed && (arr_5[0][0]==v20) && (arr_5[1][0]==v21) && (arr_5[2][0]==v22); passed = passed && (arr_2.tostring(dps)==s1_fmt); passed = passed && (arr_3.tostring(dps)==s1_fmt); passed = passed && (arr_4.tostring(dps)==s1_fmt); passed = passed && (arr_5.tostring(dps)==s2_fmt); arr_2[0][0] = v10_mod; passed = passed && (arr_2[0][0]==v10_mod) && (arr_3[0][0]==v10) && (arr_4[0][0]==v10); arr_5.setlength(99,97); passed = passed && (arr_5.rows()==99) && (arr_5.cols()==97); // // setcontent/elementwise access/constant arrays // ae_int_t n, m, i, j; for(n=1; n<=10; n++) for(m=1; m<=10; m++) { alglib::real_2d_array arr_6; double a0[100]; // fill array by random values, test setcontent(0 for(i=0; i4 ) { // // 64-bit mode, perform test: // * use large NMax>2^31 // * generate 1.000.000 random numbers // * use two bins - one for numbers less then NMax/2, // another one for the rest of them // * bin sizes are equal to n0, n1 // * both bins should be approximately equal, we use // ad hoc threshold 0.45 < n0,n1 < 0.55. // try { alglib::hqrndstate rs; alglib::ae_int_t nmax[3]; alglib::ae_int_t ncnt = 3, nidx; double n0, n1; alglib::hqrndrandomize(rs); // // nmax: // * first nmax is just large value to test basic uniformity of generator // nmax[0] = 1000000; nmax[0] = nmax[0]*nmax[0]; nmax[1] = 2147483562; nmax[1] *= 1.5; nmax[2] = 2147483562; nmax[2] *= 3; for(nidx=0; nidx=0) && (v0.45); issue478_passed = issue478_passed && (n0/(n0+n1)<0.55); issue478_passed = issue478_passed && (n1/(n0+n1)>0.45); issue478_passed = issue478_passed && (n1/(n0+n1)<0.55); } } catch(...) { issue478_passed = false; } printf(fmt_str, "* issue 478", issue478_passed ? "OK" : "FAILED"); fflush(stdout); if( !issue478_passed ) return 1; } else { // // 32-bit mode, skip test // printf(fmt_str, "* issue 478", "OK (skipped in 32-bit mode)"); fflush(stdout); } // // Testing issue #528 (http://bugs.alglib.net/view.php?id=528) // in shared pool and smart pointer which leak memory. // // In order to test it we create pool, seed it with specially // created structure, perform several operations, then clear it. // We test allocation counter before and after this operation. // #ifndef AE_USE_ALLOC_COUNTER #error AE_USE_ALLOC_COUNTER must be defined #endif try { int alloc_cnt; alglib_impl::ae_state _alglib_env_state; alglib_impl::ae_frame _frame_block; alglib_impl::ae_shared_pool pool; alglib_impl::ae_smart_ptr ptr0, ptr1; void *p0, *p1; seedrec seed; // case #0: just seeding the pool alloc_cnt = alglib_impl::_alloc_counter; alglib_impl::ae_state_init(&_alglib_env_state); alglib_impl::ae_frame_make(&_alglib_env_state, &_frame_block); alglib_impl::ae_shared_pool_init(&pool, &_alglib_env_state); _seedrec_init(&seed, &_alglib_env_state); alglib_impl::ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _seedrec_init, _seedrec_init_copy, _seedrec_destroy, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); issue528_passed = issue528_passed && (alloc_cnt==alglib_impl::_alloc_counter); // case #1: seeding and retrieving, not recycling alloc_cnt = alglib_impl::_alloc_counter; alglib_impl::ae_state_init(&_alglib_env_state); alglib_impl::ae_frame_make(&_alglib_env_state, &_frame_block); alglib_impl::ae_smart_ptr_init(&ptr0, (void**)&p0, &_alglib_env_state); alglib_impl::ae_shared_pool_init(&pool, &_alglib_env_state); _seedrec_init(&seed, &_alglib_env_state); alglib_impl::ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _seedrec_init, _seedrec_init_copy, _seedrec_destroy, &_alglib_env_state); alglib_impl::ae_shared_pool_retrieve(&pool, &ptr0, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); issue528_passed = issue528_passed && (alloc_cnt==alglib_impl::_alloc_counter); // case #2: seeding and retrieving twice, recycling both alloc_cnt = alglib_impl::_alloc_counter; alglib_impl::ae_state_init(&_alglib_env_state); alglib_impl::ae_frame_make(&_alglib_env_state, &_frame_block); alglib_impl::ae_smart_ptr_init(&ptr0, (void**)&p0, &_alglib_env_state); alglib_impl::ae_smart_ptr_init(&ptr1, (void**)&p1, &_alglib_env_state); alglib_impl::ae_shared_pool_init(&pool, &_alglib_env_state); _seedrec_init(&seed, &_alglib_env_state); alglib_impl::ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _seedrec_init, _seedrec_init_copy, _seedrec_destroy, &_alglib_env_state); alglib_impl::ae_shared_pool_retrieve(&pool, &ptr0, &_alglib_env_state); alglib_impl::ae_shared_pool_retrieve(&pool, &ptr1, &_alglib_env_state); alglib_impl::ae_shared_pool_recycle(&pool, &ptr0, &_alglib_env_state); alglib_impl::ae_shared_pool_recycle(&pool, &ptr1, &_alglib_env_state); alglib_impl::ae_state_clear(&_alglib_env_state); issue528_passed = issue528_passed && (alloc_cnt==alglib_impl::_alloc_counter); } catch(...) { issue528_passed = false; } printf(fmt_str, "* issue 528", issue528_passed ? "OK" : "FAILED"); fflush(stdout); if( !issue528_passed ) return 1; // // Testing issue #591 (http://bugs.alglib.net/view.php?id=591) // in copying of object containing shared pool as one of its // fields. // // Unfixed ALGLIB crashes because of unneeded assertion in the // ae_shared_pool_init_copy() function. // try { alglib::multilayerperceptron net0, net1; alglib::real_1d_array x("[1,2]"), y0("[0,0]"), y1("[0,0]"), y2("[0,0]"); alglib::mlpcreate0(2, 2, net0); alglib::mlpprocess(net0, x, y0); // // Test assignment constructor // net1 = net0; alglib::mlpprocess(net1, x, y1); issue591_passed = issue591_passed && (fabs(y0[0]-y1[0])<1.0E-9) && (fabs(y0[1]-y1[1])<1.0E-9); // // Test copy constructor // alglib::multilayerperceptron net2(net0); alglib::mlpprocess(net2, x, y2); issue591_passed = issue591_passed && (fabs(y0[0]-y2[0])<1.0E-9) && (fabs(y0[1]-y2[1])<1.0E-9); } catch(...) { issue591_passed = false; } printf(fmt_str, "* issue 591", issue591_passed ? "OK" : "FAILED"); fflush(stdout); if( !issue591_passed ) return 1; // // Task #594 (http://bugs.alglib.net/view.php?id=594) - additional // test for correctness of copying of objects. When we copy ALGLIB // object, indenendent new copy is created. // // This test checks both copying with copy constructor and assignment // constructor // try { alglib::multilayerperceptron net0, net1; alglib::real_1d_array x("[1,2]"), y0("[0,0]"), y1("[0,0]"), y2("[0,0]"); alglib::mlpcreate0(2, 2, net0); alglib::mlpprocess(net0, x, y0); // // Test assignment and copy constructors: // * copy object with one of the constructors // * process vector with original network // * randomize original network // * process vector with copied networks and compare // net1 = net0; alglib::multilayerperceptron net2(net0); alglib::mlprandomize(net0); alglib::mlpprocess(net1, x, y1); alglib::mlpprocess(net2, x, y2); issue594_passed = issue594_passed && (fabs(y0[0]-y1[0])<1.0E-9) && (fabs(y0[1]-y1[1])<1.0E-9); issue594_passed = issue594_passed && (fabs(y0[0]-y2[0])<1.0E-9) && (fabs(y0[1]-y2[1])<1.0E-9); } catch(...) { issue594_passed = false; } printf(fmt_str, "* issue 594", issue594_passed ? "OK" : "FAILED"); fflush(stdout); if( !issue594_passed ) return 1; } // // Performance testing // printf("Performance:\n"); { { int _n[] = { 16, 32, 64, 1024, 0}; int i, j, k, t, nidx; double desiredflops = 1.0E10; for(nidx=0; _n[nidx]!=0; nidx++) { // // Settings: // * n - matrix size // * nrepeat - number of repeated multiplications, always divisible by 4 // int n = _n[nidx]; int nrepeat = (int)(desiredflops/(2*pow((double)n,3.0))); nrepeat = 4*(nrepeat/4+1); // // Actual processing // alglib::real_2d_array a, b, c; double perf0, perf1, perf2; a.setlength(n, n); b.setlength(n, n); c.setlength(n, n); for(i=0; i #include "alglibinternal.h" #include "alglibmisc.h" #include "linalg.h" #include "statistics.h" #include "dataanalysis.h" #include "specialfunctions.h" #include "solvers.h" #include "optimization.h" #include "diffequations.h" #include "fasttransforms.h" #include "integration.h" #include "interpolation.h" using namespace alglib; bool doc_test_bool(bool v, bool t) { return (v && t) || (!v && !t); } bool doc_test_int(ae_int_t v, ae_int_t t) { return v==t; } bool doc_test_real(double v, double t, double _threshold) { double s = _threshold>=0 ? 1.0 : fabs(t); double threshold = fabs(_threshold); return fabs(v-t)/s<=threshold; } bool doc_test_complex(alglib::complex v, alglib::complex t, double _threshold) { double s = _threshold>=0 ? 1.0 : alglib::abscomplex(t); double threshold = fabs(_threshold); return abscomplex(v-t)/s<=threshold; } bool doc_test_bool_vector(const boolean_1d_array &v, const boolean_1d_array &t) { ae_int_t i; if( v.length()!=t.length() ) return false; for(i=0; i=0 ? 1.0 : fabs(t(i)); double threshold = fabs(_threshold); if( fabs(v(i)-t(i))/s>threshold ) return false; } return true; } bool doc_test_real_matrix(const real_2d_array &v, const real_2d_array &t, double _threshold) { ae_int_t i, j; if( v.rows()!=t.rows() ) return false; if( v.cols()!=t.cols() ) return false; for(i=0; i=0 ? 1.0 : fabs(t(i,j)); double threshold = fabs(_threshold); if( fabs(v(i,j)-t(i,j))/s>threshold ) return false; } return true; } bool doc_test_complex_vector(const complex_1d_array &v, const complex_1d_array &t, double _threshold) { ae_int_t i; if( v.length()!=t.length() ) return false; for(i=0; i=0 ? 1.0 : alglib::abscomplex(t(i)); double threshold = fabs(_threshold); if( abscomplex(v(i)-t(i))/s>threshold ) return false; } return true; } bool doc_test_complex_matrix(const complex_2d_array &v, const complex_2d_array &t, double _threshold) { ae_int_t i, j; if( v.rows()!=t.rows() ) return false; if( v.cols()!=t.cols() ) return false; for(i=0; i=0 ? 1.0 : alglib::abscomplex(t(i,j)); double threshold = fabs(_threshold); if( abscomplex(v(i,j)-t(i,j))/s>threshold ) return false; } return true; } template void spoil_vector_by_adding_element(T &x) { ae_int_t i; T y = x; x.setlength(y.length()+1); for(i=0; i void spoil_vector_by_deleting_element(T &x) { ae_int_t i; T y = x; x.setlength(y.length()-1); for(i=0; i void spoil_matrix_by_adding_row(T &x) { ae_int_t i, j; T y = x; x.setlength(y.rows()+1, y.cols()); for(i=0; i void spoil_matrix_by_deleting_row(T &x) { ae_int_t i, j; T y = x; x.setlength(y.rows()-1, y.cols()); for(i=0; i void spoil_matrix_by_adding_col(T &x) { ae_int_t i, j; T y = x; x.setlength(y.rows(), y.cols()+1); for(i=0; i void spoil_matrix_by_deleting_col(T &x) { ae_int_t i, j; T y = x; x.setlength(y.rows(), y.cols()-1); for(i=0; i void spoil_vector_by_nan(T &x) { if( x.length()!=0 ) x(randominteger(x.length())) = fp_nan; } template void spoil_vector_by_posinf(T &x) { if( x.length()!=0 ) x(randominteger(x.length())) = fp_posinf; } template void spoil_vector_by_neginf(T &x) { if( x.length()!=0 ) x(randominteger(x.length())) = fp_neginf; } template void spoil_matrix_by_nan(T &x) { if( x.rows()!=0 && x.cols()!=0 ) x(randominteger(x.rows()),randominteger(x.cols())) = fp_nan; } template void spoil_matrix_by_posinf(T &x) { if( x.rows()!=0 && x.cols()!=0 ) x(randominteger(x.rows()),randominteger(x.cols())) = fp_posinf; } template void spoil_matrix_by_neginf(T &x) { if( x.rows()!=0 && x.cols()!=0 ) x(randominteger(x.rows()),randominteger(x.cols())) = fp_neginf; } void function1_func(const real_1d_array &x, double &func, void *ptr) { // // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4 // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); } void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { // // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4 // and its derivatives df/d0 and df/dx1 // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); grad[0] = 400*pow(x[0]+3,3); grad[1] = 4*pow(x[1]-3,3); } void function1_hess(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr) { // // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4 // its derivatives df/d0 and df/dx1 // and its Hessian. // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); grad[0] = 400*pow(x[0]+3,3); grad[1] = 4*pow(x[1]-3,3); hess[0][0] = 1200*pow(x[0]+3,2); hess[0][1] = 0; hess[1][0] = 0; hess[1][1] = 12*pow(x[1]-3,2); } void function1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr) { // // this callback calculates // f0(x0,x1) = 100*(x0+3)^4, // f1(x0,x1) = (x1-3)^4 // fi[0] = 10*pow(x[0]+3,2); fi[1] = pow(x[1]-3,2); } void function1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates // f0(x0,x1) = 100*(x0+3)^4, // f1(x0,x1) = (x1-3)^4 // and Jacobian matrix J = [dfi/dxj] // fi[0] = 10*pow(x[0]+3,2); fi[1] = pow(x[1]-3,2); jac[0][0] = 20*(x[0]+3); jac[0][1] = 0; jac[1][0] = 0; jac[1][1] = 2*(x[1]-3); } void function2_func(const real_1d_array &x, double &func, void *ptr) { // // this callback calculates f(x0,x1) = (x0^2+1)^2 + (x1-1)^2 // func = pow(x[0]*x[0]+1,2) + pow(x[1]-1,2); } void function2_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { // // this callback calculates f(x0,x1) = (x0^2+1)^2 + (x1-1)^2 // and its derivatives df/d0 and df/dx1 // func = pow(x[0]*x[0]+1,2) + pow(x[1]-1,2); grad[0] = 4*(x[0]*x[0]+1)*x[0]; grad[1] = 2*(x[1]-1); } void function2_hess(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr) { // // this callback calculates f(x0,x1) = (x0^2+1)^2 + (x1-1)^2 // its gradient and Hessian // func = pow(x[0]*x[0]+1,2) + pow(x[1]-1,2); grad[0] = 4*(x[0]*x[0]+1)*x[0]; grad[1] = 2*(x[1]-1); hess[0][0] = 12*x[0]*x[0]+4; hess[0][1] = 0; hess[1][0] = 0; hess[1][1] = 2; } void function2_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr) { // // this callback calculates // f0(x0,x1) = x0^2+1 // f1(x0,x1) = x1-1 // fi[0] = x[0]*x[0]+1; fi[1] = x[1]-1; } void function2_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates // f0(x0,x1) = x0^2+1 // f1(x0,x1) = x1-1 // and Jacobian matrix J = [dfi/dxj] // fi[0] = x[0]*x[0]+1; fi[1] = x[1]-1; jac[0][0] = 2*x[0]; jac[0][1] = 0; jac[1][0] = 0; jac[1][1] = 1; } void nlcfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates // // f0(x0,x1) = -x0+x1 // f1(x0,x1) = x0^2+x1^2-1 // // and Jacobian matrix J = [dfi/dxj] // fi[0] = -x[0]+x[1]; fi[1] = x[0]*x[0] + x[1]*x[1] - 1.0; jac[0][0] = -1.0; jac[0][1] = +1.0; jac[1][0] = 2*x[0]; jac[1][1] = 2*x[1]; } void nlcfunc2_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates // // f0(x0,x1,x2) = x0+x1 // f1(x0,x1,x2) = x2-exp(x0) // f2(x0,x1,x2) = x0^2+x1^2-1 // // and Jacobian matrix J = [dfi/dxj] // fi[0] = x[0]+x[1]; fi[1] = x[2]-exp(x[0]); fi[2] = x[0]*x[0] + x[1]*x[1] - 1.0; jac[0][0] = 1.0; jac[0][1] = 1.0; jac[0][2] = 0.0; jac[1][0] = -exp(x[0]); jac[1][1] = 0.0; jac[1][2] = 1.0; jac[2][0] = 2*x[0]; jac[2][1] = 2*x[1]; jac[2][2] = 0.0; } void nsfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates // // f0(x0,x1) = 2*|x0|+x1 // // and Jacobian matrix J = [df0/dx0 df0/dx1] // fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1])); jac[0][0] = 2*alglib::sign(x[0]); jac[0][1] = alglib::sign(x[1]); } void nsfunc1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr) { // // this callback calculates // // f0(x0,x1) = 2*|x0|+x1 // fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1])); } void nsfunc2_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates function vector // // f0(x0,x1) = 2*|x0|+x1 // f1(x0,x1) = x0-1 // f2(x0,x1) = -x1-1 // // and Jacobian matrix J // // [ df0/dx0 df0/dx1 ] // J = [ df1/dx0 df1/dx1 ] // [ df2/dx0 df2/dx1 ] // fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1])); jac[0][0] = 2*alglib::sign(x[0]); jac[0][1] = alglib::sign(x[1]); fi[1] = x[0]-1; jac[1][0] = 1; jac[1][1] = 0; fi[2] = -x[1]-1; jac[2][0] = 0; jac[2][1] = -1; } void bad_func(const real_1d_array &x, double &func, void *ptr) { // // this callback calculates 'bad' function, // i.e. function with incorrectly calculated derivatives // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); } void bad_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { // // this callback calculates 'bad' function, // i.e. function with incorrectly calculated derivatives // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); grad[0] = 40*pow(x[0]+3,3); grad[1] = 40*pow(x[1]-3,3); } void bad_hess(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr) { // // this callback calculates 'bad' function, // i.e. function with incorrectly calculated derivatives // func = 100*pow(x[0]+3,4) + pow(x[1]-3,4); grad[0] = 40*pow(x[0]+3,3); grad[1] = 40*pow(x[1]-3,3); hess[0][0] = 120*pow(x[0]+3,2); hess[0][1] = 0; hess[1][0] = 0; hess[1][1] = 120*pow(x[1]-3,2); } void bad_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr) { // // this callback calculates 'bad' function, // i.e. function with incorrectly calculated derivatives // fi[0] = 10*pow(x[0]+3,2); fi[1] = pow(x[1]-3,2); } void bad_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr) { // // this callback calculates 'bad' function, // i.e. function with incorrectly calculated derivatives // fi[0] = 10*pow(x[0]+3,2); fi[1] = pow(x[1]-3,2); jac[0][0] = 2*(x[0]+3); jac[0][1] = 1; jac[1][0] = 0; jac[1][1] = 20*(x[1]-3); } void function_cx_1_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) { // this callback calculates f(c,x)=exp(-c0*sqr(x0)) // where x is a position on X-axis and c is adjustable parameter func = exp(-c[0]*pow(x[0],2)); } void function_cx_1_grad(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { // this callback calculates f(c,x)=exp(-c0*sqr(x0)) and gradient G={df/dc[i]} // where x is a position on X-axis and c is adjustable parameter. // IMPORTANT: gradient is calculated with respect to C, not to X func = exp(-c[0]*pow(x[0],2)); grad[0] = -pow(x[0],2)*func; } void function_cx_1_hess(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr) { // this callback calculates f(c,x)=exp(-c0*sqr(x0)), gradient G={df/dc[i]} and Hessian H={d2f/(dc[i]*dc[j])} // where x is a position on X-axis and c is adjustable parameter. // IMPORTANT: gradient/Hessian are calculated with respect to C, not to X func = exp(-c[0]*pow(x[0],2)); grad[0] = -pow(x[0],2)*func; hess[0][0] = pow(x[0],4)*func; } void ode_function_1_diff(const real_1d_array &y, double x, real_1d_array &dy, void *ptr) { // this callback calculates f(y[],x)=-y[0] dy[0] = -y[0]; } void int_function_1_func(double x, double xminusa, double bminusx, double &y, void *ptr) { // this callback calculates f(x)=exp(x) y = exp(x); } void function_debt_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) { // // this callback calculates f(c,x)=c[0]*(1+c[1]*(pow(x[0]-1999,c[2])-1)) // func = c[0]*(1+c[1]*(pow(x[0]-1999,c[2])-1)); } void s1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) { // // this callback calculates f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x and its gradient. // // function is trimmed when we calculate it near the singular points or outside of the [-1,+1]. // Note that we do NOT calculate gradient in this case. // if( (x[0]<=-0.999999999999) || (x[0]>=+0.999999999999) ) { func = 1.0E+300; return; } func = pow(1+x[0],-0.2) + pow(1-x[0],-0.3) + 1000*x[0]; grad[0] = -0.2*pow(1+x[0],-1.2) +0.3*pow(1-x[0],-1.3) + 1000; } int main() { bool _TotalResult = true; bool _TestResult; int _spoil_scenario; printf("C++ tests. Please wait...\n"); #ifdef AE_USE_ALLOC_COUNTER printf("Allocation counter activated...\n"); alglib_impl::_use_alloc_counter = ae_true; if( alglib_impl::_alloc_counter!=0 ) { _TotalResult = false; printf("FAILURE: alloc_counter is non-zero on start!\n"); } #endif try { // // TEST nneighbor_d_1 // Nearest neighbor search, KNN queries // printf("0/145\n"); _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { real_2d_array a = "[[0,0],[0,1],[1,0],[1,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); ae_int_t nx = 2; ae_int_t ny = 0; ae_int_t normtype = 2; kdtree kdt; real_1d_array x; real_2d_array r = "[[]]"; ae_int_t k; kdtreebuild(a, nx, ny, normtype, kdt); x = "[-1,0]"; k = kdtreequeryknn(kdt, x, 1); _TestResult = _TestResult && doc_test_int(k, 1); kdtreequeryresultsx(kdt, r); _TestResult = _TestResult && doc_test_real_matrix(r, "[[0,0]]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nneighbor_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nneighbor_t_2 // Subsequent queries; buffered functions must use previously allocated storage (if large enough), so buffer may contain some info from previous call // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { real_2d_array a = "[[0,0],[0,1],[1,0],[1,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); ae_int_t nx = 2; ae_int_t ny = 0; ae_int_t normtype = 2; kdtree kdt; real_1d_array x; real_2d_array rx = "[[]]"; ae_int_t k; kdtreebuild(a, nx, ny, normtype, kdt); x = "[+2,0]"; k = kdtreequeryknn(kdt, x, 2, true); _TestResult = _TestResult && doc_test_int(k, 2); kdtreequeryresultsx(kdt, rx); _TestResult = _TestResult && doc_test_real_matrix(rx, "[[1,0],[1,1]]", 0.05); x = "[-2,0]"; k = kdtreequeryknn(kdt, x, 1, true); _TestResult = _TestResult && doc_test_int(k, 1); kdtreequeryresultsx(kdt, rx); _TestResult = _TestResult && doc_test_real_matrix(rx, "[[0,0],[1,1]]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nneighbor_t_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nneighbor_d_2 // Serialization of KD-trees // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { real_2d_array a = "[[0,0],[0,1],[1,0],[1,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); ae_int_t nx = 2; ae_int_t ny = 0; ae_int_t normtype = 2; kdtree kdt0; kdtree kdt1; std::string s; real_1d_array x; real_2d_array r0 = "[[]]"; real_2d_array r1 = "[[]]"; // // Build tree and serialize it // kdtreebuild(a, nx, ny, normtype, kdt0); alglib::kdtreeserialize(kdt0, s); alglib::kdtreeunserialize(s, kdt1); // // Compare results from KNN queries // x = "[-1,0]"; kdtreequeryknn(kdt0, x, 1); kdtreequeryresultsx(kdt0, r0); kdtreequeryknn(kdt1, x, 1); kdtreequeryresultsx(kdt1, r1); _TestResult = _TestResult && doc_test_real_matrix(r0, "[[0,0]]", 0.05); _TestResult = _TestResult && doc_test_real_matrix(r1, "[[0,0]]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nneighbor_d_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_d_gemm // Matrix multiplication (single-threaded) // _TestResult = true; try { real_2d_array a = "[[2,1],[1,3]]"; real_2d_array b = "[[2,1],[0,1]]"; real_2d_array c = "[[0,0],[0,0]]"; // // rmatrixgemm() function allows us to calculate matrix product C:=A*B or // to perform more general operation, C:=alpha*op1(A)*op2(B)+beta*C, // where A, B, C are rectangular matrices, op(X) can be X or X^T, // alpha and beta are scalars. // // This function: // * can apply transposition and/or multiplication by scalar to operands // * can use arbitrary part of matrices A/B (given by submatrix offset) // * can store result into arbitrary part of C // * for performance reasons requires C to be preallocated // // Parameters of this function are: // * M, N, K - sizes of op1(A) (which is MxK), op2(B) (which // is KxN) and C (which is MxN) // * Alpha - coefficient before A*B // * A, IA, JA - matrix A and offset of the submatrix // * OpTypeA - transformation type: // 0 - no transformation // 1 - transposition // * B, IB, JB - matrix B and offset of the submatrix // * OpTypeB - transformation type: // 0 - no transformation // 1 - transposition // * Beta - coefficient before C // * C, IC, JC - preallocated matrix C and offset of the submatrix // // Below we perform simple product C:=A*B (alpha=1, beta=0) // // IMPORTANT: this function works with preallocated C, which must be large // enough to store multiplication result. // ae_int_t m = 2; ae_int_t n = 2; ae_int_t k = 2; double alpha = 1.0; ae_int_t ia = 0; ae_int_t ja = 0; ae_int_t optypea = 0; ae_int_t ib = 0; ae_int_t jb = 0; ae_int_t optypeb = 0; double beta = 0.0; ae_int_t ic = 0; ae_int_t jc = 0; rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); _TestResult = _TestResult && doc_test_real_matrix(c, "[[4,3],[2,4]]", 0.0001); // // Now we try to apply some simple transformation to operands: C:=A*B^T // optypeb = 1; rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); _TestResult = _TestResult && doc_test_real_matrix(c, "[[5,1],[5,3]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_d_gemm"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_d_syrk // Symmetric rank-K update (single-threaded) // _TestResult = true; try { // // rmatrixsyrk() function allows us to calculate symmetric rank-K update // C := beta*C + alpha*A'*A, where C is square N*N matrix, A is square K*N // matrix, alpha and beta are scalars. It is also possible to update by // adding A*A' instead of A'*A. // // Parameters of this function are: // * N, K - matrix size // * Alpha - coefficient before A // * A, IA, JA - matrix and submatrix offsets // * OpTypeA - multiplication type: // * 0 - A*A^T is calculated // * 2 - A^T*A is calculated // * Beta - coefficient before C // * C, IC, JC - preallocated input/output matrix and submatrix offsets // * IsUpper - whether upper or lower triangle of C is updated; // this function updates only one half of C, leaving // other half unchanged (not referenced at all). // // Below we will show how to calculate simple product C:=A'*A // // NOTE: beta=0 and we do not use previous value of C, but still it // MUST be preallocated. // ae_int_t n = 2; ae_int_t k = 1; double alpha = 1.0; ae_int_t ia = 0; ae_int_t ja = 0; ae_int_t optypea = 2; double beta = 0.0; ae_int_t ic = 0; ae_int_t jc = 0; bool isupper = true; real_2d_array a = "[[1,2]]"; // preallocate space to store result real_2d_array c = "[[0,0],[0,0]]"; // calculate product, store result into upper part of c rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); // output result. // IMPORTANT: lower triangle of C was NOT updated! _TestResult = _TestResult && doc_test_real_matrix(c, "[[1,2],[0,4]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_d_syrk"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_smp_gemm // Matrix multiplication (multithreaded) // _TestResult = true; try { // // In this example we assume that you already know how to work with // rmatrixgemm() function. Below we concentrate on its multithreading // capabilities. // // SMP edition of ALGLIB includes smp_rmatrixgemm() - multithreaded // version of rmatrixgemm() function. In the basic edition of ALGLIB // (GPL edition or commercial version without SMP support) this function // just calls single-threaded stub. So, you may call this function from // ANY edition of ALGLIB, but only in SMP edition it will work in really // multithreaded mode. // // In order to use multithreading, you have to: // 1) Install SMP edition of ALGLIB. // 2) This step is specific for C++ users: you should activate OS-specific // capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems) // or AE_OS=AE_WINDOWS (for Windows systems). // C# users do not have to perform this step because C# programs are // portable across different systems without OS-specific tuning. // 3) Allow ALGLIB to know about number of worker threads to use: // a) autodetection (C++, C#): // ALGLIB will automatically determine number of CPU cores and // (by default) will use all cores except for one. Say, on 4-core // system it will use three cores - unless you manually told it // to use more or less. It will keep your system responsive during // lengthy computations. // Such behavior may be changed with setnworkers() call: // * alglib::setnworkers(0) = use all cores // * alglib::setnworkers(-1) = leave one core unused // * alglib::setnworkers(-2) = leave two cores unused // * alglib::setnworkers(+2) = use 2 cores (even if you have more) // b) manual specification (C++, C#): // You may want to specify maximum number of worker threads during // compile time by means of preprocessor definition AE_NWORKERS. // For C++ it will be "AE_NWORKERS=X" where X can be any positive number. // For C# it is "AE_NWORKERSX", where X should be replaced by number of // workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...). // You can add this definition to compiler command line or change // corresponding project settings in your IDE. // // After you installed and configured SMP edition of ALGLIB, you may choose // between serial and multithreaded versions of SMP-capable functions: // * serial version works as usual, in the context of the calling thread // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker // threads, inserts task in the worker queue, and waits for completion of // the task. All processing is done in context of worker thread(s). // // NOTE: because starting/stopping worker threads costs thousands of CPU cycles, // you should not use multithreading for lightweight computational problems. // // NOTE: some old POSIX-compatible operating systems do not support // sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order // to automatically determine number of active cores. On these systems // you should specify number of cores manually at compile time. // Without it ALGLIB will run in single-threaded mode. // // Now, back to our example. In this example we will show you: // * how to call SMP version of rmatrixgemm(). Because we work with tiny 2x2 // matrices, we won't expect to see ANY speedup from using multithreading. // The only purpose of this demo is to show how to call SMP functions. // * how to modify number of worker threads used by ALGLIB // real_2d_array a = "[[2,1],[1,3]]"; real_2d_array b = "[[2,1],[0,1]]"; real_2d_array c = "[[0,0],[0,0]]"; ae_int_t m = 2; ae_int_t n = 2; ae_int_t k = 2; double alpha = 1.0; ae_int_t ia = 0; ae_int_t ja = 0; ae_int_t optypea = 0; ae_int_t ib = 0; ae_int_t jb = 0; ae_int_t optypeb = 0; double beta = 0.0; ae_int_t ic = 0; ae_int_t jc = 0; // serial code c = "[[0,0],[0,0]]"; rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); // SMP code with default number of worker threads c = "[[0,0],[0,0]]"; smp_rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); _TestResult = _TestResult && doc_test_real_matrix(c, "[[4,3],[2,4]]", 0.0001); // override number of worker threads - use two cores alglib::setnworkers(+2); c = "[[0,0],[0,0]]"; smp_rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); _TestResult = _TestResult && doc_test_real_matrix(c, "[[4,3],[2,4]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_smp_gemm"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_smp_syrk // Symmetric rank-K update (multithreaded) // _TestResult = true; try { // // In this example we assume that you already know how to work with // rmatrixsyrk() function. Below we concentrate on its multithreading // capabilities. // // SMP edition of ALGLIB includes smp_rmatrixsyrk() - multithreaded // version of rmatrixsyrk() function. In the basic edition of ALGLIB // (GPL edition or commercial version without SMP support) this function // just calls single-threaded stub. So, you may call this function from // ANY edition of ALGLIB, but only in SMP edition it will work in really // multithreaded mode. // // In order to use multithreading, you have to: // 1) Install SMP edition of ALGLIB. // 2) This step is specific for C++ users: you should activate OS-specific // capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems) // or AE_OS=AE_WINDOWS (for Windows systems). // C# users do not have to perform this step because C# programs are // portable across different systems without OS-specific tuning. // 3) Allow ALGLIB to know about number of worker threads to use: // a) autodetection (C++, C#): // ALGLIB will automatically determine number of CPU cores and // (by default) will use all cores except for one. Say, on 4-core // system it will use three cores - unless you manually told it // to use more or less. It will keep your system responsive during // lengthy computations. // Such behavior may be changed with setnworkers() call: // * alglib::setnworkers(0) = use all cores // * alglib::setnworkers(-1) = leave one core unused // * alglib::setnworkers(-2) = leave two cores unused // * alglib::setnworkers(+2) = use 2 cores (even if you have more) // b) manual specification (C++, C#): // You may want to specify maximum number of worker threads during // compile time by means of preprocessor definition AE_NWORKERS. // For C++ it will be "AE_NWORKERS=X" where X can be any positive number. // For C# it is "AE_NWORKERSX", where X should be replaced by number of // workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...). // You can add this definition to compiler command line or change // corresponding project settings in your IDE. // // After you installed and configured SMP edition of ALGLIB, you may choose // between serial and multithreaded versions of SMP-capable functions: // * serial version works as usual, in the context of the calling thread // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker // threads, inserts task in the worker queue, and waits for completion of // the task. All processing is done in context of worker thread(s). // // NOTE: because starting/stopping worker threads costs thousands of CPU cycles, // you should not use multithreading for lightweight computational problems. // // NOTE: some old POSIX-compatible operating systems do not support // sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order // to automatically determine number of active cores. On these systems // you should specify number of cores manually at compile time. // Without it ALGLIB will run in single-threaded mode. // // Now, back to our example. In this example we will show you: // * how to call SMP version of rmatrixsyrk(). Because we work with tiny 2x2 // matrices, we won't expect to see ANY speedup from using multithreading. // The only purpose of this demo is to show how to call SMP functions. // * how to modify number of worker threads used by ALGLIB // ae_int_t n = 2; ae_int_t k = 1; double alpha = 1.0; ae_int_t ia = 0; ae_int_t ja = 0; ae_int_t optypea = 2; double beta = 0.0; ae_int_t ic = 0; ae_int_t jc = 0; bool isupper = true; real_2d_array a = "[[1,2]]"; real_2d_array c = "[[]]"; // // Default number of worker threads. // Preallocate space to store result, call multithreaded version, test. // // NOTE: this function updates only one triangular part of C. In our // example we choose to update upper triangle. // c = "[[0,0],[0,0]]"; smp_rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); _TestResult = _TestResult && doc_test_real_matrix(c, "[[1,2],[0,4]]", 0.0001); // // Override default number of worker threads (set to 2). // Preallocate space to store result, call multithreaded version, test. // // NOTE: this function updates only one triangular part of C. In our // example we choose to update upper triangle. // alglib::setnworkers(+2); c = "[[0,0],[0,0]]"; smp_rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); _TestResult = _TestResult && doc_test_real_matrix(c, "[[1,2],[0,4]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_smp_syrk"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_t_real // Basis test for real matrix functions (correctness and presence of SMP support) // _TestResult = true; try { real_2d_array a; real_2d_array b; real_2d_array c; // test rmatrixgemm() a = "[[2,1],[1,3]]"; b = "[[2,1],[0,1]]"; c = "[[0,0],[0,0]]"; rmatrixgemm(2, 2, 2, 1.0, a, 0, 0, 0, b, 0, 0, 0, 0.0, c, 0, 0); _TestResult = _TestResult && doc_test_real_matrix(c, "[[4,3],[2,4]]", 0.0001); smp_rmatrixgemm(2, 2, 2, 1.0, a, 0, 0, 0, b, 0, 0, 0, 1.0, c, 0, 0); _TestResult = _TestResult && doc_test_real_matrix(c, "[[8,6],[4,8]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_t_real"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST ablas_t_complex // Basis test for complex matrix functions (correctness and presence of SMP support) // _TestResult = true; try { complex_2d_array a; complex_2d_array b; complex_2d_array c; // test cmatrixgemm() a = "[[2i,1i],[1,3]]"; b = "[[2,1],[0,1]]"; c = "[[0,0],[0,0]]"; cmatrixgemm(2, 2, 2, 1.0, a, 0, 0, 0, b, 0, 0, 0, 0.0, c, 0, 0); _TestResult = _TestResult && doc_test_complex_matrix(c, "[[4i,3i],[2,4]]", 0.0001); smp_cmatrixgemm(2, 2, 2, 1.0, a, 0, 0, 0, b, 0, 0, 0, 1.0, c, 0, 0); _TestResult = _TestResult && doc_test_complex_matrix(c, "[[8i,6i],[4,8]]", 0.0001); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "ablas_t_complex"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_d_base // Basic functionality (moments, adev, median, percentile) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double mean; double variance; double skewness; double kurtosis; double adev; double p; double v; // // Here we demonstrate calculation of sample moments // (mean, variance, skewness, kurtosis) // samplemoments(x, mean, variance, skewness, kurtosis); _TestResult = _TestResult && doc_test_real(mean, 28.5, 0.01); _TestResult = _TestResult && doc_test_real(variance, 801.1667, 0.01); _TestResult = _TestResult && doc_test_real(skewness, 0.5751, 0.01); _TestResult = _TestResult && doc_test_real(kurtosis, -1.2666, 0.01); // // Average deviation // sampleadev(x, adev); _TestResult = _TestResult && doc_test_real(adev, 23.2, 0.01); // // Median and percentile // samplemedian(x, v); _TestResult = _TestResult && doc_test_real(v, 20.5, 0.01); p = 0.5; if( _spoil_scenario==3 ) p = fp_nan; if( _spoil_scenario==4 ) p = fp_posinf; if( _spoil_scenario==5 ) p = fp_neginf; samplepercentile(x, p, v); _TestResult = _TestResult && doc_test_real(v, 20.5, 0.01); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_d_base"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_d_c2 // Correlation (covariance) between two random variables // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { // // We have two samples - x and y, and want to measure dependency between them // real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); double v; // // Three dependency measures are calculated: // * covariation // * Pearson correlation // * Spearman rank correlation // v = cov2(x, y); _TestResult = _TestResult && doc_test_real(v, 82.5, 0.001); v = pearsoncorr2(x, y); _TestResult = _TestResult && doc_test_real(v, 0.9627, 0.001); v = spearmancorr2(x, y); _TestResult = _TestResult && doc_test_real(v, 1.000, 0.001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_d_c2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_d_cm // Correlation (covariance) between components of random vector // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // X is a sample matrix: // * I-th row corresponds to I-th observation // * J-th column corresponds to J-th variable // real_2d_array x = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); real_2d_array c; // // Three dependency measures are calculated: // * covariation // * Pearson correlation // * Spearman rank correlation // // Result is stored into C, with C[i,j] equal to correlation // (covariance) between I-th and J-th variables of X. // covm(x, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[1.80,0.60,-1.40],[0.60,0.70,-0.80],[-1.40,-0.80,14.70]]", 0.01); pearsoncorrm(x, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[1.000,0.535,-0.272],[0.535,1.000,-0.249],[-0.272,-0.249,1.000]]", 0.01); spearmancorrm(x, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[1.000,0.556,-0.306],[0.556,1.000,-0.750],[-0.306,-0.750,1.000]]", 0.01); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_d_cm"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_d_cm2 // Correlation (covariance) between two random vectors // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // X and Y are sample matrices: // * I-th row corresponds to I-th observation // * J-th column corresponds to J-th variable // real_2d_array x = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); real_2d_array y = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==3 ) spoil_matrix_by_nan(y); if( _spoil_scenario==4 ) spoil_matrix_by_posinf(y); if( _spoil_scenario==5 ) spoil_matrix_by_neginf(y); real_2d_array c; // // Three dependency measures are calculated: // * covariation // * Pearson correlation // * Spearman rank correlation // // Result is stored into C, with C[i,j] equal to correlation // (covariance) between I-th variable of X and J-th variable of Y. // covm2(x, y, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[4.100,-3.250],[2.450,-1.500],[13.450,-5.750]]", 0.01); pearsoncorrm2(x, y, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0.519,-0.699],[0.497,-0.518],[0.596,-0.433]]", 0.01); spearmancorrm2(x, y, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0.541,-0.649],[0.216,-0.433],[0.433,-0.135]]", 0.01); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_d_cm2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_t_base // Tests ability to detect errors in inputs // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<34; _spoil_scenario++) { try { double mean; double variance; double skewness; double kurtosis; double adev; double p; double v; // // first, we test short form of functions // real_1d_array x1 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x1); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x1); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x1); samplemoments(x1, mean, variance, skewness, kurtosis); real_1d_array x2 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(x2); if( _spoil_scenario==4 ) spoil_vector_by_posinf(x2); if( _spoil_scenario==5 ) spoil_vector_by_neginf(x2); sampleadev(x2, adev); real_1d_array x3 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==6 ) spoil_vector_by_nan(x3); if( _spoil_scenario==7 ) spoil_vector_by_posinf(x3); if( _spoil_scenario==8 ) spoil_vector_by_neginf(x3); samplemedian(x3, v); real_1d_array x4 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(x4); if( _spoil_scenario==10 ) spoil_vector_by_posinf(x4); if( _spoil_scenario==11 ) spoil_vector_by_neginf(x4); p = 0.5; if( _spoil_scenario==12 ) p = fp_nan; if( _spoil_scenario==13 ) p = fp_posinf; if( _spoil_scenario==14 ) p = fp_neginf; samplepercentile(x4, p, v); // // and then we test full form // real_1d_array x5 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(x5); if( _spoil_scenario==16 ) spoil_vector_by_posinf(x5); if( _spoil_scenario==17 ) spoil_vector_by_neginf(x5); if( _spoil_scenario==18 ) spoil_vector_by_deleting_element(x5); samplemoments(x5, 10, mean, variance, skewness, kurtosis); real_1d_array x6 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(x6); if( _spoil_scenario==20 ) spoil_vector_by_posinf(x6); if( _spoil_scenario==21 ) spoil_vector_by_neginf(x6); if( _spoil_scenario==22 ) spoil_vector_by_deleting_element(x6); sampleadev(x6, 10, adev); real_1d_array x7 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==23 ) spoil_vector_by_nan(x7); if( _spoil_scenario==24 ) spoil_vector_by_posinf(x7); if( _spoil_scenario==25 ) spoil_vector_by_neginf(x7); if( _spoil_scenario==26 ) spoil_vector_by_deleting_element(x7); samplemedian(x7, 10, v); real_1d_array x8 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==27 ) spoil_vector_by_nan(x8); if( _spoil_scenario==28 ) spoil_vector_by_posinf(x8); if( _spoil_scenario==29 ) spoil_vector_by_neginf(x8); if( _spoil_scenario==30 ) spoil_vector_by_deleting_element(x8); p = 0.5; if( _spoil_scenario==31 ) p = fp_nan; if( _spoil_scenario==32 ) p = fp_posinf; if( _spoil_scenario==33 ) p = fp_neginf; samplepercentile(x8, 10, p, v); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_t_base"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST basestat_t_covcorr // Tests ability to detect errors in inputs // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<126; _spoil_scenario++) { try { double v; real_2d_array c; // // 2-sample short-form cov/corr are tested // real_1d_array x1 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x1); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x1); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x1); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x1); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x1); real_1d_array y1 = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y1); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y1); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y1); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y1); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y1); v = cov2(x1, y1); real_1d_array x2 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(x2); if( _spoil_scenario==11 ) spoil_vector_by_posinf(x2); if( _spoil_scenario==12 ) spoil_vector_by_neginf(x2); if( _spoil_scenario==13 ) spoil_vector_by_adding_element(x2); if( _spoil_scenario==14 ) spoil_vector_by_deleting_element(x2); real_1d_array y2 = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(y2); if( _spoil_scenario==16 ) spoil_vector_by_posinf(y2); if( _spoil_scenario==17 ) spoil_vector_by_neginf(y2); if( _spoil_scenario==18 ) spoil_vector_by_adding_element(y2); if( _spoil_scenario==19 ) spoil_vector_by_deleting_element(y2); v = pearsoncorr2(x2, y2); real_1d_array x3 = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==20 ) spoil_vector_by_nan(x3); if( _spoil_scenario==21 ) spoil_vector_by_posinf(x3); if( _spoil_scenario==22 ) spoil_vector_by_neginf(x3); if( _spoil_scenario==23 ) spoil_vector_by_adding_element(x3); if( _spoil_scenario==24 ) spoil_vector_by_deleting_element(x3); real_1d_array y3 = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==25 ) spoil_vector_by_nan(y3); if( _spoil_scenario==26 ) spoil_vector_by_posinf(y3); if( _spoil_scenario==27 ) spoil_vector_by_neginf(y3); if( _spoil_scenario==28 ) spoil_vector_by_adding_element(y3); if( _spoil_scenario==29 ) spoil_vector_by_deleting_element(y3); v = spearmancorr2(x3, y3); // // 2-sample full-form cov/corr are tested // real_1d_array x1a = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==30 ) spoil_vector_by_nan(x1a); if( _spoil_scenario==31 ) spoil_vector_by_posinf(x1a); if( _spoil_scenario==32 ) spoil_vector_by_neginf(x1a); if( _spoil_scenario==33 ) spoil_vector_by_deleting_element(x1a); real_1d_array y1a = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==34 ) spoil_vector_by_nan(y1a); if( _spoil_scenario==35 ) spoil_vector_by_posinf(y1a); if( _spoil_scenario==36 ) spoil_vector_by_neginf(y1a); if( _spoil_scenario==37 ) spoil_vector_by_deleting_element(y1a); v = cov2(x1a, y1a, 10); real_1d_array x2a = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==38 ) spoil_vector_by_nan(x2a); if( _spoil_scenario==39 ) spoil_vector_by_posinf(x2a); if( _spoil_scenario==40 ) spoil_vector_by_neginf(x2a); if( _spoil_scenario==41 ) spoil_vector_by_deleting_element(x2a); real_1d_array y2a = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==42 ) spoil_vector_by_nan(y2a); if( _spoil_scenario==43 ) spoil_vector_by_posinf(y2a); if( _spoil_scenario==44 ) spoil_vector_by_neginf(y2a); if( _spoil_scenario==45 ) spoil_vector_by_deleting_element(y2a); v = pearsoncorr2(x2a, y2a, 10); real_1d_array x3a = "[0,1,4,9,16,25,36,49,64,81]"; if( _spoil_scenario==46 ) spoil_vector_by_nan(x3a); if( _spoil_scenario==47 ) spoil_vector_by_posinf(x3a); if( _spoil_scenario==48 ) spoil_vector_by_neginf(x3a); if( _spoil_scenario==49 ) spoil_vector_by_deleting_element(x3a); real_1d_array y3a = "[0,1,2,3,4,5,6,7,8,9]"; if( _spoil_scenario==50 ) spoil_vector_by_nan(y3a); if( _spoil_scenario==51 ) spoil_vector_by_posinf(y3a); if( _spoil_scenario==52 ) spoil_vector_by_neginf(y3a); if( _spoil_scenario==53 ) spoil_vector_by_deleting_element(y3a); v = spearmancorr2(x3a, y3a, 10); // // vector short-form cov/corr are tested. // real_2d_array x4 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==54 ) spoil_matrix_by_nan(x4); if( _spoil_scenario==55 ) spoil_matrix_by_posinf(x4); if( _spoil_scenario==56 ) spoil_matrix_by_neginf(x4); covm(x4, c); real_2d_array x5 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==57 ) spoil_matrix_by_nan(x5); if( _spoil_scenario==58 ) spoil_matrix_by_posinf(x5); if( _spoil_scenario==59 ) spoil_matrix_by_neginf(x5); pearsoncorrm(x5, c); real_2d_array x6 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==60 ) spoil_matrix_by_nan(x6); if( _spoil_scenario==61 ) spoil_matrix_by_posinf(x6); if( _spoil_scenario==62 ) spoil_matrix_by_neginf(x6); spearmancorrm(x6, c); // // vector full-form cov/corr are tested. // real_2d_array x7 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==63 ) spoil_matrix_by_nan(x7); if( _spoil_scenario==64 ) spoil_matrix_by_posinf(x7); if( _spoil_scenario==65 ) spoil_matrix_by_neginf(x7); if( _spoil_scenario==66 ) spoil_matrix_by_deleting_row(x7); if( _spoil_scenario==67 ) spoil_matrix_by_deleting_col(x7); covm(x7, 5, 3, c); real_2d_array x8 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==68 ) spoil_matrix_by_nan(x8); if( _spoil_scenario==69 ) spoil_matrix_by_posinf(x8); if( _spoil_scenario==70 ) spoil_matrix_by_neginf(x8); if( _spoil_scenario==71 ) spoil_matrix_by_deleting_row(x8); if( _spoil_scenario==72 ) spoil_matrix_by_deleting_col(x8); pearsoncorrm(x8, 5, 3, c); real_2d_array x9 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==73 ) spoil_matrix_by_nan(x9); if( _spoil_scenario==74 ) spoil_matrix_by_posinf(x9); if( _spoil_scenario==75 ) spoil_matrix_by_neginf(x9); if( _spoil_scenario==76 ) spoil_matrix_by_deleting_row(x9); if( _spoil_scenario==77 ) spoil_matrix_by_deleting_col(x9); spearmancorrm(x9, 5, 3, c); // // cross-vector short-form cov/corr are tested. // real_2d_array x10 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==78 ) spoil_matrix_by_nan(x10); if( _spoil_scenario==79 ) spoil_matrix_by_posinf(x10); if( _spoil_scenario==80 ) spoil_matrix_by_neginf(x10); real_2d_array y10 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==81 ) spoil_matrix_by_nan(y10); if( _spoil_scenario==82 ) spoil_matrix_by_posinf(y10); if( _spoil_scenario==83 ) spoil_matrix_by_neginf(y10); covm2(x10, y10, c); real_2d_array x11 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==84 ) spoil_matrix_by_nan(x11); if( _spoil_scenario==85 ) spoil_matrix_by_posinf(x11); if( _spoil_scenario==86 ) spoil_matrix_by_neginf(x11); real_2d_array y11 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==87 ) spoil_matrix_by_nan(y11); if( _spoil_scenario==88 ) spoil_matrix_by_posinf(y11); if( _spoil_scenario==89 ) spoil_matrix_by_neginf(y11); pearsoncorrm2(x11, y11, c); real_2d_array x12 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==90 ) spoil_matrix_by_nan(x12); if( _spoil_scenario==91 ) spoil_matrix_by_posinf(x12); if( _spoil_scenario==92 ) spoil_matrix_by_neginf(x12); real_2d_array y12 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==93 ) spoil_matrix_by_nan(y12); if( _spoil_scenario==94 ) spoil_matrix_by_posinf(y12); if( _spoil_scenario==95 ) spoil_matrix_by_neginf(y12); spearmancorrm2(x12, y12, c); // // cross-vector full-form cov/corr are tested. // real_2d_array x13 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==96 ) spoil_matrix_by_nan(x13); if( _spoil_scenario==97 ) spoil_matrix_by_posinf(x13); if( _spoil_scenario==98 ) spoil_matrix_by_neginf(x13); if( _spoil_scenario==99 ) spoil_matrix_by_deleting_row(x13); if( _spoil_scenario==100 ) spoil_matrix_by_deleting_col(x13); real_2d_array y13 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==101 ) spoil_matrix_by_nan(y13); if( _spoil_scenario==102 ) spoil_matrix_by_posinf(y13); if( _spoil_scenario==103 ) spoil_matrix_by_neginf(y13); if( _spoil_scenario==104 ) spoil_matrix_by_deleting_row(y13); if( _spoil_scenario==105 ) spoil_matrix_by_deleting_col(y13); covm2(x13, y13, 5, 3, 2, c); real_2d_array x14 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==106 ) spoil_matrix_by_nan(x14); if( _spoil_scenario==107 ) spoil_matrix_by_posinf(x14); if( _spoil_scenario==108 ) spoil_matrix_by_neginf(x14); if( _spoil_scenario==109 ) spoil_matrix_by_deleting_row(x14); if( _spoil_scenario==110 ) spoil_matrix_by_deleting_col(x14); real_2d_array y14 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==111 ) spoil_matrix_by_nan(y14); if( _spoil_scenario==112 ) spoil_matrix_by_posinf(y14); if( _spoil_scenario==113 ) spoil_matrix_by_neginf(y14); if( _spoil_scenario==114 ) spoil_matrix_by_deleting_row(y14); if( _spoil_scenario==115 ) spoil_matrix_by_deleting_col(y14); pearsoncorrm2(x14, y14, 5, 3, 2, c); real_2d_array x15 = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]"; if( _spoil_scenario==116 ) spoil_matrix_by_nan(x15); if( _spoil_scenario==117 ) spoil_matrix_by_posinf(x15); if( _spoil_scenario==118 ) spoil_matrix_by_neginf(x15); if( _spoil_scenario==119 ) spoil_matrix_by_deleting_row(x15); if( _spoil_scenario==120 ) spoil_matrix_by_deleting_col(x15); real_2d_array y15 = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]"; if( _spoil_scenario==121 ) spoil_matrix_by_nan(y15); if( _spoil_scenario==122 ) spoil_matrix_by_posinf(y15); if( _spoil_scenario==123 ) spoil_matrix_by_neginf(y15); if( _spoil_scenario==124 ) spoil_matrix_by_deleting_row(y15); if( _spoil_scenario==125 ) spoil_matrix_by_deleting_col(y15); spearmancorrm2(x15, y15, 5, 3, 2, c); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "basestat_t_covcorr"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST clst_ahc // Simple hierarchical clusterization with Euclidean distance function // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // The very simple clusterization example // // We have a set of points in 2D space: // (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5)) // // | // | P3 // | // | P1 // | P4 // | P0 P2 // |------------------------- // // We want to perform Agglomerative Hierarchic Clusterization (AHC), // using complete linkage (default algorithm) and Euclidean distance // (default metric). // // In order to do that, we: // * create clusterizer with clusterizercreate() // * set points XY and metric (2=Euclidean) with clusterizersetpoints() // * run AHC algorithm with clusterizerrunahc // // You may see that clusterization itself is a minor part of the example, // most of which is dominated by comments :) // clusterizerstate s; ahcreport rep; real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); clusterizercreate(s); clusterizersetpoints(s, xy, 2); clusterizerrunahc(s, rep); // // Now we've built our clusterization tree. Rep.z contains information which // is required to build dendrogram. I-th row of rep.z represents one merge // operation, with first cluster to merge having index rep.z[I,0] and second // one having index rep.z[I,1]. Merge result has index NPoints+I. // // Clusters with indexes less than NPoints are single-point initial clusters, // while ones with indexes from NPoints to 2*NPoints-2 are multi-point // clusters created during merges. // // In our example, Z=[[2,4], [0,1], [3,6], [5,7]] // // It means that: // * first, we merge C2=(P2) and C4=(P4), and create C5=(P2,P4) // * then, we merge C2=(P0) and C1=(P1), and create C6=(P0,P1) // * then, we merge C3=(P3) and C6=(P0,P1), and create C7=(P0,P1,P3) // * finally, we merge C5 and C7 and create C8=(P0,P1,P2,P3,P4) // // Thus, we have following dendrogram: // // ------8----- // | | // | ----7---- // | | | // ---5--- | ---6--- // | | | | | // P2 P4 P3 P0 P1 // _TestResult = _TestResult && doc_test_int_matrix(rep.z, "[[2,4],[0,1],[3,6],[5,7]]"); // // We've built dendrogram above by reordering our dataset. // // Without such reordering it would be impossible to build dendrogram without // intersections. Luckily, ahcreport structure contains two additional fields // which help to build dendrogram from your data: // * rep.p, which contains permutation applied to dataset // * rep.pm, which contains another representation of merges // // In our example we have: // * P=[3,4,0,2,1] // * PZ=[[0,0,1,1,0,0],[3,3,4,4,0,0],[2,2,3,4,0,1],[0,1,2,4,1,2]] // // Permutation array P tells us that P0 should be moved to position 3, // P1 moved to position 4, P2 moved to position 0 and so on: // // (P0 P1 P2 P3 P4) => (P2 P4 P3 P0 P1) // // Merges array PZ tells us how to perform merges on the sorted dataset. // One row of PZ corresponds to one merge operations, with first pair of // elements denoting first of the clusters to merge (start index, end // index) and next pair of elements denoting second of the clusters to // merge. Clusters being merged are always adjacent, with first one on // the left and second one on the right. // // For example, first row of PZ tells us that clusters [0,0] and [1,1] are // merged (single-point clusters, with first one containing P2 and second // one containing P4). Third row of PZ tells us that we merge one single- // point cluster [2,2] with one two-point cluster [3,4]. // // There are two more elements in each row of PZ. These are the helper // elements, which denote HEIGHT (not size) of left and right subdendrograms. // For example, according to PZ, first two merges are performed on clusterization // trees of height 0, while next two merges are performed on 0-1 and 1-2 // pairs of trees correspondingly. // _TestResult = _TestResult && doc_test_int_vector(rep.p, "[3,4,0,2,1]"); _TestResult = _TestResult && doc_test_int_matrix(rep.pm, "[[0,0,1,1,0,0],[3,3,4,4,0,0],[2,2,3,4,0,1],[0,1,2,4,1,2]]"); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "clst_ahc"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST clst_kmeans // Simple k-means clusterization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // The very simple clusterization example // // We have a set of points in 2D space: // (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5)) // // | // | P3 // | // | P1 // | P4 // | P0 P2 // |------------------------- // // We want to perform k-means++ clustering with K=2. // // In order to do that, we: // * create clusterizer with clusterizercreate() // * set points XY and metric (must be Euclidean, distype=2) with clusterizersetpoints() // * (optional) set number of restarts from random positions to 5 // * run k-means algorithm with clusterizerrunkmeans() // // You may see that clusterization itself is a minor part of the example, // most of which is dominated by comments :) // clusterizerstate s; kmeansreport rep; real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); clusterizercreate(s); clusterizersetpoints(s, xy, 2); clusterizersetkmeanslimits(s, 5, 0); clusterizerrunkmeans(s, 2, rep); // // We've performed clusterization, and it succeeded (completion code is +1). // // Now first center is stored in the first row of rep.c, second one is stored // in the second row. rep.cidx can be used to determine which center is // closest to some specific point of the dataset. // _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); // We called clusterizersetpoints() with disttype=2 because k-means++ // algorithm does NOT support metrics other than Euclidean. But what if we // try to use some other metric? // // We change metric type by calling clusterizersetpoints() one more time, // and try to run k-means algo again. It fails. // clusterizersetpoints(s, xy, 0); clusterizerrunkmeans(s, 2, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, -5); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "clst_kmeans"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST clst_linkage // Clusterization with different linkage types // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // We have a set of points in 1D space: // (P0,P1,P2,P3,P4) = (1, 3, 10, 16, 20) // // We want to perform Agglomerative Hierarchic Clusterization (AHC), // using either complete or single linkage and Euclidean distance // (default metric). // // First two steps merge P0/P1 and P3/P4 independently of the linkage type. // However, third step depends on linkage type being used: // * in case of complete linkage P2=10 is merged with [P0,P1] // * in case of single linkage P2=10 is merged with [P3,P4] // clusterizerstate s; ahcreport rep; real_2d_array xy = "[[1],[3],[10],[16],[20]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); integer_1d_array cidx; integer_1d_array cz; clusterizercreate(s); clusterizersetpoints(s, xy, 2); // use complete linkage, reduce set down to 2 clusters. // print clusterization with clusterizergetkclusters(2). // P2 must belong to [P0,P1] clusterizersetahcalgo(s, 0); clusterizerrunahc(s, rep); clusterizergetkclusters(rep, 2, cidx, cz); _TestResult = _TestResult && doc_test_int_vector(cidx, "[1,1,1,0,0]"); // use single linkage, reduce set down to 2 clusters. // print clusterization with clusterizergetkclusters(2). // P2 must belong to [P2,P3] clusterizersetahcalgo(s, 1); clusterizerrunahc(s, rep); clusterizergetkclusters(rep, 2, cidx, cz); _TestResult = _TestResult && doc_test_int_vector(cidx, "[0,0,1,1,1]"); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "clst_linkage"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST clst_distance // Clusterization with different metric types // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // We have three points in 4D space: // (P0,P1,P2) = ((1, 2, 1, 2), (6, 7, 6, 7), (7, 6, 7, 6)) // // We want to try clustering them with different distance functions. // Distance function is chosen when we add dataset to the clusterizer. // We can choose several distance types - Euclidean, city block, Chebyshev, // several correlation measures or user-supplied distance matrix. // // Here we'll try three distances: Euclidean, Pearson correlation, // user-supplied distance matrix. Different distance functions lead // to different choices being made by algorithm during clustering. // clusterizerstate s; ahcreport rep; ae_int_t disttype; real_2d_array xy = "[[1, 2, 1, 2], [6, 7, 6, 7], [7, 6, 7, 6]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); clusterizercreate(s); // With Euclidean distance function (disttype=2) two closest points // are P1 and P2, thus: // * first, we merge P1 and P2 to form C3=[P1,P2] // * second, we merge P0 and C3 to form C4=[P0,P1,P2] disttype = 2; clusterizersetpoints(s, xy, disttype); clusterizerrunahc(s, rep); _TestResult = _TestResult && doc_test_int_matrix(rep.z, "[[1,2],[0,3]]"); // With Pearson correlation distance function (disttype=10) situation // is different - distance between P0 and P1 is zero, thus: // * first, we merge P0 and P1 to form C3=[P0,P1] // * second, we merge P2 and C3 to form C4=[P0,P1,P2] disttype = 10; clusterizersetpoints(s, xy, disttype); clusterizerrunahc(s, rep); _TestResult = _TestResult && doc_test_int_matrix(rep.z, "[[0,1],[2,3]]"); // Finally, we try clustering with user-supplied distance matrix: // [ 0 3 1 ] // P = [ 3 0 3 ], where P[i,j] = dist(Pi,Pj) // [ 1 3 0 ] // // * first, we merge P0 and P2 to form C3=[P0,P2] // * second, we merge P1 and C3 to form C4=[P0,P1,P2] real_2d_array d = "[[0,3,1],[3,0,3],[1,3,0]]"; clusterizersetdistances(s, d, true); clusterizerrunahc(s, rep); _TestResult = _TestResult && doc_test_int_matrix(rep.z, "[[0,2],[1,3]]"); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "clst_distance"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST clst_kclusters // Obtaining K top clusters from clusterization tree // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // We have a set of points in 2D space: // (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5)) // // | // | P3 // | // | P1 // | P4 // | P0 P2 // |------------------------- // // We perform Agglomerative Hierarchic Clusterization (AHC) and we want // to get top K clusters from clusterization tree for different K. // clusterizerstate s; ahcreport rep; real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); integer_1d_array cidx; integer_1d_array cz; clusterizercreate(s); clusterizersetpoints(s, xy, 2); clusterizerrunahc(s, rep); // with K=5, every points is assigned to its own cluster: // C0=P0, C1=P1 and so on... clusterizergetkclusters(rep, 5, cidx, cz); _TestResult = _TestResult && doc_test_int_vector(cidx, "[0,1,2,3,4]"); // with K=1 we have one large cluster C0=[P0,P1,P2,P3,P4,P5] clusterizergetkclusters(rep, 1, cidx, cz); _TestResult = _TestResult && doc_test_int_vector(cidx, "[0,0,0,0,0]"); // with K=3 we have three clusters C0=[P3], C1=[P2,P4], C2=[P0,P1] clusterizergetkclusters(rep, 3, cidx, cz); _TestResult = _TestResult && doc_test_int_vector(cidx, "[2,2,1,0,1]"); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "clst_kclusters"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST linreg_d_basic // Linear regression used to build the very basic model and unpack coefficients // _TestResult = true; try { // // In this example we demonstrate linear fitting by f(x|a) = a*exp(0.5*x). // // We have: // * xy - matrix of basic function values (exp(0.5*x)) and expected values // real_2d_array xy = "[[0.606531,1.133719],[0.670320,1.306522],[0.740818,1.504604],[0.818731,1.554663],[0.904837,1.884638],[1.000000,2.072436],[1.105171,2.257285],[1.221403,2.534068],[1.349859,2.622017],[1.491825,2.897713],[1.648721,3.219371]]"; ae_int_t info; ae_int_t nvars; linearmodel model; lrreport rep; real_1d_array c; lrbuildz(xy, 11, 1, info, model, rep); _TestResult = _TestResult && doc_test_int(info, 1); lrunpack(model, c, nvars); _TestResult = _TestResult && doc_test_real_vector(c, "[1.98650,0.00000]", 0.00005); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "linreg_d_basic"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST filters_d_sma // SMA(k) filter // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Here we demonstrate SMA(k) filtering for time series. // real_1d_array x = "[5,6,7,8]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); // // Apply filter. // We should get [5, 5.5, 6.5, 7.5] as result // filtersma(x, 2); _TestResult = _TestResult && doc_test_real_vector(x, "[5,5.5,6.5,7.5]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "filters_d_sma"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST filters_d_ema // EMA(alpha) filter // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Here we demonstrate EMA(0.5) filtering for time series. // real_1d_array x = "[5,6,7,8]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); // // Apply filter. // We should get [5, 5.5, 6.25, 7.125] as result // filterema(x, 0.5); _TestResult = _TestResult && doc_test_real_vector(x, "[5,5.5,6.25,7.125]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "filters_d_ema"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST filters_d_lrma // LRMA(k) filter // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Here we demonstrate LRMA(3) filtering for time series. // real_1d_array x = "[7,8,8,9,12,12]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); // // Apply filter. // We should get [7.0000, 8.0000, 8.1667, 8.8333, 11.6667, 12.5000] as result // filterlrma(x, 3); _TestResult = _TestResult && doc_test_real_vector(x, "[7.0000,8.0000,8.1667,8.8333,11.6667,12.5000]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "filters_d_lrma"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST sparse_d_1 // Basic operations with sparse matrices // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<1; _spoil_scenario++) { try { // // This example demonstrates creation/initialization of the sparse matrix // and matrix-vector multiplication. // // First, we have to create matrix and initialize it. Matrix is initially created // in the Hash-Table format, which allows convenient initialization. We can modify // Hash-Table matrix with sparseset() and sparseadd() functions. // // NOTE: Unlike CRS format, Hash-Table representation allows you to initialize // elements in the arbitrary order. You may see that we initialize a[0][0] first, // then move to the second row, and then move back to the first row. // sparsematrix s; sparsecreate(2, 2, s); sparseset(s, 0, 0, 2.0); sparseset(s, 1, 1, 1.0); sparseset(s, 0, 1, 1.0); sparseadd(s, 1, 1, 4.0); // // Now S is equal to // [ 2 1 ] // [ 5 ] // Lets check it by reading matrix contents with sparseget(). // You may see that with sparseget() you may read both non-zero // and zero elements. // double v; v = sparseget(s, 0, 0); _TestResult = _TestResult && doc_test_real(v, 2.0000, 0.005); v = sparseget(s, 0, 1); _TestResult = _TestResult && doc_test_real(v, 1.0000, 0.005); v = sparseget(s, 1, 0); _TestResult = _TestResult && doc_test_real(v, 0.0000, 0.005); v = sparseget(s, 1, 1); _TestResult = _TestResult && doc_test_real(v, 5.0000, 0.005); // // After successful creation we can use our matrix for linear operations. // // However, there is one more thing we MUST do before using S in linear // operations: we have to convert it from HashTable representation (used for // initialization and dynamic operations) to CRS format with sparseconverttocrs() // call. If you omit this call, ALGLIB will generate exception on the first // attempt to use S in linear operations. // sparseconverttocrs(s); // // Now S is in the CRS format and we are ready to do linear operations. // Lets calculate A*x for some x. // real_1d_array x = "[1,-1]"; if( _spoil_scenario==0 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[]"; sparsemv(s, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[1.000,-5.000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "sparse_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST sparse_d_crs // Advanced topic: creation in the CRS format. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<2; _spoil_scenario++) { try { // // This example demonstrates creation/initialization of the sparse matrix in the // CRS format. // // Hash-Table format used by default is very convenient (it allows easy // insertion of elements, automatic memory reallocation), but has // significant memory and performance overhead. Insertion of one element // costs hundreds of CPU cycles, and memory consumption is several times // higher than that of CRS. // // When you work with really large matrices and when you can tell in // advance how many elements EXACTLY you need, it can be beneficial to // create matrix in the CRS format from the very beginning. // // If you want to create matrix in the CRS format, you should: // * use sparsecreatecrs() function // * know row sizes in advance (number of non-zero entries in the each row) // * initialize matrix with sparseset() - another function, sparseadd(), is not allowed // * initialize elements from left to right, from top to bottom, each // element is initialized only once. // sparsematrix s; integer_1d_array row_sizes = "[2,2,2,1]"; if( _spoil_scenario==0 ) spoil_vector_by_deleting_element(row_sizes); sparsecreatecrs(4, 4, row_sizes, s); sparseset(s, 0, 0, 2.0); sparseset(s, 0, 1, 1.0); sparseset(s, 1, 1, 4.0); sparseset(s, 1, 2, 2.0); sparseset(s, 2, 2, 3.0); sparseset(s, 2, 3, 1.0); sparseset(s, 3, 3, 9.0); // // Now S is equal to // [ 2 1 ] // [ 4 2 ] // [ 3 1 ] // [ 9 ] // // We should point that we have initialized S elements from left to right, // from top to bottom. CRS representation does NOT allow you to do so in // the different order. Try to change order of the sparseset() calls above, // and you will see that your program generates exception. // // We can check it by reading matrix contents with sparseget(). // However, you should remember that sparseget() is inefficient on // CRS matrices (it may have to pass through all elements of the row // until it finds element you need). // double v; v = sparseget(s, 0, 0); _TestResult = _TestResult && doc_test_real(v, 2.0000, 0.005); v = sparseget(s, 2, 3); _TestResult = _TestResult && doc_test_real(v, 1.0000, 0.005); // you may see that you can read zero elements (which are not stored) with sparseget() v = sparseget(s, 3, 2); _TestResult = _TestResult && doc_test_real(v, 0.0000, 0.005); // // After successful creation we can use our matrix for linear operations. // Lets calculate A*x for some x. // real_1d_array x = "[1,-1,1,-1]"; if( _spoil_scenario==1 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[]"; sparsemv(s, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[1.000,-2.000,2.000,-9]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "sparse_d_crs"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_d_r1 // Real matrix inverse // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { real_2d_array a = "[[1,-1],[1,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(a); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(a); ae_int_t info; matinvreport rep; rmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_matrix(a, "[[0.5,0.5],[-0.5,0.5]]", 0.00005); _TestResult = _TestResult && doc_test_real(rep.r1, 0.5, 0.00005); _TestResult = _TestResult && doc_test_real(rep.rinf, 0.5, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_d_r1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_d_c1 // Complex matrix inverse // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { complex_2d_array a = "[[1i,-1],[1i,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(a); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(a); ae_int_t info; matinvreport rep; cmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_complex_matrix(a, "[[-0.5i,-0.5i],[-0.5,0.5]]", 0.00005); _TestResult = _TestResult && doc_test_real(rep.r1, 0.5, 0.00005); _TestResult = _TestResult && doc_test_real(rep.rinf, 0.5, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_d_c1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_d_spd1 // SPD matrix inverse // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { real_2d_array a = "[[2,1],[1,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(a); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(a); ae_int_t info; matinvreport rep; spdmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_matrix(a, "[[0.666666,-0.333333],[-0.333333,0.666666]]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_d_spd1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_d_hpd1 // HPD matrix inverse // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { complex_2d_array a = "[[2,1],[1,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(a); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(a); ae_int_t info; matinvreport rep; hpdmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_complex_matrix(a, "[[0.666666,-0.333333],[-0.333333,0.666666]]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_d_hpd1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_t_r1 // Real matrix inverse: singular matrix // _TestResult = true; try { real_2d_array a = "[[1,-1],[-2,2]]"; ae_int_t info; matinvreport rep; rmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, -3); _TestResult = _TestResult && doc_test_real(rep.r1, 0.0, 0.00005); _TestResult = _TestResult && doc_test_real(rep.rinf, 0.0, 0.00005); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_t_r1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_t_c1 // Complex matrix inverse: singular matrix // _TestResult = true; try { complex_2d_array a = "[[1i,-1i],[-2,2]]"; ae_int_t info; matinvreport rep; cmatrixinverse(a, info, rep); _TestResult = _TestResult && doc_test_int(info, -3); _TestResult = _TestResult && doc_test_real(rep.r1, 0.0, 0.00005); _TestResult = _TestResult && doc_test_real(rep.rinf, 0.0, 0.00005); } catch(ap_error) { _TestResult = false; } if( !_TestResult) { printf("%-32s FAILED\n", "matinv_t_c1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_e_spd1 // Attempt to use SPD function on nonsymmetrix matrix // _TestResult = true; try { real_2d_array a = "[[1,0],[1,1]]"; ae_int_t info; matinvreport rep; spdmatrixinverse(a, info, rep); _TestResult = false; } catch(ap_error) {} if( !_TestResult) { printf("%-32s FAILED\n", "matinv_e_spd1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matinv_e_hpd1 // Attempt to use SPD function on nonsymmetrix matrix // _TestResult = true; try { complex_2d_array a = "[[1,0],[1,1]]"; ae_int_t info; matinvreport rep; hpdmatrixinverse(a, info, rep); _TestResult = false; } catch(ap_error) {} if( !_TestResult) { printf("%-32s FAILED\n", "matinv_e_hpd1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mincg_d_1 // Nonlinear optimization by CG // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // with nonlinear conjugate gradient method. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; mincgstate state; mincgreport rep; mincgcreate(x, state); mincgsetcond(state, epsg, epsf, epsx, maxits); alglib::mincgoptimize(state, function1_grad); mincgresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mincg_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mincg_d_2 // Nonlinear optimization with additional settings and restarts // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // with nonlinear conjugate gradient method. // // Several advanced techniques are demonstrated: // * upper limit on step size // * restart from new point // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; double stpmax = 0.1; if( _spoil_scenario==12 ) stpmax = fp_nan; if( _spoil_scenario==13 ) stpmax = fp_posinf; if( _spoil_scenario==14 ) stpmax = fp_neginf; ae_int_t maxits = 0; mincgstate state; mincgreport rep; // first run mincgcreate(x, state); mincgsetcond(state, epsg, epsf, epsx, maxits); mincgsetstpmax(state, stpmax); alglib::mincgoptimize(state, function1_grad); mincgresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); // second run - algorithm is restarted with mincgrestartfrom() x = "[10,10]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(x); if( _spoil_scenario==16 ) spoil_vector_by_posinf(x); if( _spoil_scenario==17 ) spoil_vector_by_neginf(x); mincgrestartfrom(state, x); alglib::mincgoptimize(state, function1_grad); mincgresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mincg_d_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mincg_numdiff // Nonlinear optimization by CG with numerical differentiation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<15; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // using numerical differentiation to calculate gradient. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; double diffstep = 1.0e-6; if( _spoil_scenario==12 ) diffstep = fp_nan; if( _spoil_scenario==13 ) diffstep = fp_posinf; if( _spoil_scenario==14 ) diffstep = fp_neginf; ae_int_t maxits = 0; mincgstate state; mincgreport rep; mincgcreatef(x, diffstep, state); mincgsetcond(state, epsg, epsf, epsx, maxits); alglib::mincgoptimize(state, function1_func); mincgresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mincg_numdiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mincg_ftrim // Nonlinear optimization by CG, function with singularities // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x. // This function has singularities at the boundary of the [-1,+1], but technique called // "function trimming" allows us to solve this optimization problem. // // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information // on this subject. // real_1d_array x = "[0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 1.0e-6; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; mincgstate state; mincgreport rep; mincgcreate(x, state); mincgsetcond(state, epsg, epsf, epsx, maxits); alglib::mincgoptimize(state, s1_grad); mincgresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-0.99917305]", 0.000005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mincg_ftrim"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minbleic_d_1 // Nonlinear optimization with bound constraints // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // subject to bound constraints -1<=x<=+1, -1<=y<=+1, using BLEIC optimizer. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); real_1d_array bndl = "[-1,-1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[+1,+1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==6 ) spoil_vector_by_deleting_element(bndu); minbleicstate state; minbleicreport rep; // // These variables define stopping conditions for the optimizer. // // We use very simple condition - |g|<=epsg // double epsg = 0.000001; if( _spoil_scenario==7 ) epsg = fp_nan; if( _spoil_scenario==8 ) epsg = fp_posinf; if( _spoil_scenario==9 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==10 ) epsf = fp_nan; if( _spoil_scenario==11 ) epsf = fp_posinf; if( _spoil_scenario==12 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==13 ) epsx = fp_nan; if( _spoil_scenario==14 ) epsx = fp_posinf; if( _spoil_scenario==15 ) epsx = fp_neginf; ae_int_t maxits = 0; // // Now we are ready to actually optimize something: // * first we create optimizer // * we add boundary constraints // * we tune stopping conditions // * and, finally, optimize and obtain results... // minbleiccreate(x, state); minbleicsetbc(state, bndl, bndu); minbleicsetcond(state, epsg, epsf, epsx, maxits); alglib::minbleicoptimize(state, function1_grad); minbleicresults(state, x, rep); // // ...and evaluate these results // _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-1,1]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minbleic_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minbleic_d_2 // Nonlinear optimization with linear inequality constraints // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // subject to inequality constraints: // * x>=2 (posed as general linear constraint), // * x+y>=6 // using BLEIC optimizer. // real_1d_array x = "[5,5]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); real_2d_array c = "[[1,0,2],[1,1,6]]"; if( _spoil_scenario==3 ) spoil_matrix_by_nan(c); if( _spoil_scenario==4 ) spoil_matrix_by_posinf(c); if( _spoil_scenario==5 ) spoil_matrix_by_neginf(c); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_row(c); if( _spoil_scenario==7 ) spoil_matrix_by_deleting_col(c); integer_1d_array ct = "[1,1]"; if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(ct); minbleicstate state; minbleicreport rep; // // These variables define stopping conditions for the optimizer. // // We use very simple condition - |g|<=epsg // double epsg = 0.000001; if( _spoil_scenario==9 ) epsg = fp_nan; if( _spoil_scenario==10 ) epsg = fp_posinf; if( _spoil_scenario==11 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==12 ) epsf = fp_nan; if( _spoil_scenario==13 ) epsf = fp_posinf; if( _spoil_scenario==14 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==15 ) epsx = fp_nan; if( _spoil_scenario==16 ) epsx = fp_posinf; if( _spoil_scenario==17 ) epsx = fp_neginf; ae_int_t maxits = 0; // // Now we are ready to actually optimize something: // * first we create optimizer // * we add linear constraints // * we tune stopping conditions // * and, finally, optimize and obtain results... // minbleiccreate(x, state); minbleicsetlc(state, c, ct); minbleicsetcond(state, epsg, epsf, epsx, maxits); alglib::minbleicoptimize(state, function1_grad); minbleicresults(state, x, rep); // // ...and evaluate these results // _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[2,4]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minbleic_d_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minbleic_numdiff // Nonlinear optimization with bound constraints and numerical differentiation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<19; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // subject to bound constraints -1<=x<=+1, -1<=y<=+1, using BLEIC optimizer. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); real_1d_array bndl = "[-1,-1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[+1,+1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==6 ) spoil_vector_by_deleting_element(bndu); minbleicstate state; minbleicreport rep; // // These variables define stopping conditions for the optimizer. // // We use very simple condition - |g|<=epsg // double epsg = 0.000001; if( _spoil_scenario==7 ) epsg = fp_nan; if( _spoil_scenario==8 ) epsg = fp_posinf; if( _spoil_scenario==9 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==10 ) epsf = fp_nan; if( _spoil_scenario==11 ) epsf = fp_posinf; if( _spoil_scenario==12 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==13 ) epsx = fp_nan; if( _spoil_scenario==14 ) epsx = fp_posinf; if( _spoil_scenario==15 ) epsx = fp_neginf; ae_int_t maxits = 0; // // This variable contains differentiation step // double diffstep = 1.0e-6; if( _spoil_scenario==16 ) diffstep = fp_nan; if( _spoil_scenario==17 ) diffstep = fp_posinf; if( _spoil_scenario==18 ) diffstep = fp_neginf; // // Now we are ready to actually optimize something: // * first we create optimizer // * we add boundary constraints // * we tune stopping conditions // * and, finally, optimize and obtain results... // minbleiccreatef(x, diffstep, state); minbleicsetbc(state, bndl, bndu); minbleicsetcond(state, epsg, epsf, epsx, maxits); alglib::minbleicoptimize(state, function1_func); minbleicresults(state, x, rep); // // ...and evaluate these results // _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-1,1]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minbleic_numdiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minbleic_ftrim // Nonlinear optimization by BLEIC, function with singularities // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x. // // This function is undefined outside of (-1,+1) and has singularities at x=-1 and x=+1. // Special technique called "function trimming" allows us to solve this optimization problem // - without using boundary constraints! // // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information // on this subject. // real_1d_array x = "[0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 1.0e-6; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minbleicstate state; minbleicreport rep; minbleiccreate(x, state); minbleicsetcond(state, epsg, epsf, epsx, maxits); alglib::minbleicoptimize(state, s1_grad); minbleicresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-0.99917305]", 0.000005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minbleic_ftrim"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mcpd_simple1 // Simple unconstrained MCPD model (no entry/exit states) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // The very simple MCPD example // // We have a loan portfolio. Our loans can be in one of two states: // * normal loans ("good" ones) // * past due loans ("bad" ones) // // We assume that: // * loans can transition from any state to any other state. In // particular, past due loan can become "good" one at any moment // with same (fixed) probability. Not realistic, but it is toy example :) // * portfolio size does not change over time // // Thus, we have following model // state_new = P*state_old // where // ( p00 p01 ) // P = ( ) // ( p10 p11 ) // // We want to model transitions between these two states using MCPD // approach (Markov Chains for Proportional/Population Data), i.e. // to restore hidden transition matrix P using actual portfolio data. // We have: // * poportional data, i.e. proportion of loans in the normal and past // due states (not portfolio size measured in some currency, although // it is possible to work with population data too) // * two tracks, i.e. two sequences which describe portfolio // evolution from two different starting states: [1,0] (all loans // are "good") and [0.8,0.2] (only 80% of portfolio is in the "good" // state) // mcpdstate s; mcpdreport rep; real_2d_array p; real_2d_array track0 = "[[1.00000,0.00000],[0.95000,0.05000],[0.92750,0.07250],[0.91738,0.08263],[0.91282,0.08718]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(track0); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(track0); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(track0); real_2d_array track1 = "[[0.80000,0.20000],[0.86000,0.14000],[0.88700,0.11300],[0.89915,0.10085]]"; if( _spoil_scenario==3 ) spoil_matrix_by_nan(track1); if( _spoil_scenario==4 ) spoil_matrix_by_posinf(track1); if( _spoil_scenario==5 ) spoil_matrix_by_neginf(track1); mcpdcreate(2, s); mcpdaddtrack(s, track0); mcpdaddtrack(s, track1); mcpdsolve(s); mcpdresults(s, p, rep); // // Hidden matrix P is equal to // ( 0.95 0.50 ) // ( ) // ( 0.05 0.50 ) // which means that "good" loans can become "bad" with 5% probability, // while "bad" loans will return to good state with 50% probability. // _TestResult = _TestResult && doc_test_real_matrix(p, "[[0.95,0.50],[0.05,0.50]]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mcpd_simple1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST mcpd_simple2 // Simple MCPD model (no entry/exit states) with equality constraints // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // Simple MCPD example // // We have a loan portfolio. Our loans can be in one of three states: // * normal loans // * past due loans // * charged off loans // // We assume that: // * normal loan can stay normal or become past due (but not charged off) // * past due loan can stay past due, become normal or charged off // * charged off loan will stay charged off for the rest of eternity // * portfolio size does not change over time // Not realistic, but it is toy example :) // // Thus, we have following model // state_new = P*state_old // where // ( p00 p01 ) // P = ( p10 p11 ) // ( p21 1 ) // i.e. four elements of P are known a priori. // // Although it is possible (given enough data) to In order to enforce // this property we set equality constraints on these elements. // // We want to model transitions between these two states using MCPD // approach (Markov Chains for Proportional/Population Data), i.e. // to restore hidden transition matrix P using actual portfolio data. // We have: // * poportional data, i.e. proportion of loans in the current and past // due states (not portfolio size measured in some currency, although // it is possible to work with population data too) // * two tracks, i.e. two sequences which describe portfolio // evolution from two different starting states: [1,0,0] (all loans // are "good") and [0.8,0.2,0.0] (only 80% of portfolio is in the "good" // state) // mcpdstate s; mcpdreport rep; real_2d_array p; real_2d_array track0 = "[[1.000000,0.000000,0.000000],[0.950000,0.050000,0.000000],[0.927500,0.060000,0.012500],[0.911125,0.061375,0.027500],[0.896256,0.060900,0.042844]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(track0); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(track0); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(track0); real_2d_array track1 = "[[0.800000,0.200000,0.000000],[0.860000,0.090000,0.050000],[0.862000,0.065500,0.072500],[0.851650,0.059475,0.088875],[0.838805,0.057451,0.103744]]"; if( _spoil_scenario==3 ) spoil_matrix_by_nan(track1); if( _spoil_scenario==4 ) spoil_matrix_by_posinf(track1); if( _spoil_scenario==5 ) spoil_matrix_by_neginf(track1); mcpdcreate(3, s); mcpdaddtrack(s, track0); mcpdaddtrack(s, track1); mcpdaddec(s, 0, 2, 0.0); mcpdaddec(s, 1, 2, 0.0); mcpdaddec(s, 2, 2, 1.0); mcpdaddec(s, 2, 0, 0.0); mcpdsolve(s); mcpdresults(s, p, rep); // // Hidden matrix P is equal to // ( 0.95 0.50 ) // ( 0.05 0.25 ) // ( 0.25 1.00 ) // which means that "good" loans can become past due with 5% probability, // while past due loans will become charged off with 25% probability or // return back to normal state with 50% probability. // _TestResult = _TestResult && doc_test_real_matrix(p, "[[0.95,0.50,0.00],[0.05,0.25,0.00],[0.00,0.25,1.00]]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "mcpd_simple2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlbfgs_d_1 // Nonlinear optimization by L-BFGS // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // using LBFGS method. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlbfgsstate state; minlbfgsreport rep; minlbfgscreate(1, x, state); minlbfgssetcond(state, epsg, epsf, epsx, maxits); alglib::minlbfgsoptimize(state, function1_grad); minlbfgsresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlbfgs_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlbfgs_d_2 // Nonlinear optimization with additional settings and restarts // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // using LBFGS method. // // Several advanced techniques are demonstrated: // * upper limit on step size // * restart from new point // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; double stpmax = 0.1; if( _spoil_scenario==12 ) stpmax = fp_nan; if( _spoil_scenario==13 ) stpmax = fp_posinf; if( _spoil_scenario==14 ) stpmax = fp_neginf; ae_int_t maxits = 0; minlbfgsstate state; minlbfgsreport rep; // first run minlbfgscreate(1, x, state); minlbfgssetcond(state, epsg, epsf, epsx, maxits); minlbfgssetstpmax(state, stpmax); alglib::minlbfgsoptimize(state, function1_grad); minlbfgsresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); // second run - algorithm is restarted x = "[10,10]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(x); if( _spoil_scenario==16 ) spoil_vector_by_posinf(x); if( _spoil_scenario==17 ) spoil_vector_by_neginf(x); minlbfgsrestartfrom(state, x); alglib::minlbfgsoptimize(state, function1_grad); minlbfgsresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlbfgs_d_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlbfgs_numdiff // Nonlinear optimization by L-BFGS with numerical differentiation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<15; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4 // using numerical differentiation to calculate gradient. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; double diffstep = 1.0e-6; if( _spoil_scenario==12 ) diffstep = fp_nan; if( _spoil_scenario==13 ) diffstep = fp_posinf; if( _spoil_scenario==14 ) diffstep = fp_neginf; ae_int_t maxits = 0; minlbfgsstate state; minlbfgsreport rep; minlbfgscreatef(1, x, diffstep, state); minlbfgssetcond(state, epsg, epsf, epsx, maxits); alglib::minlbfgsoptimize(state, function1_func); minlbfgsresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlbfgs_numdiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlbfgs_ftrim // Nonlinear optimization by LBFGS, function with singularities // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x. // This function has singularities at the boundary of the [-1,+1], but technique called // "function trimming" allows us to solve this optimization problem. // // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information // on this subject. // real_1d_array x = "[0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 1.0e-6; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlbfgsstate state; minlbfgsreport rep; minlbfgscreate(1, x, state); minlbfgssetcond(state, epsg, epsf, epsx, maxits); alglib::minlbfgsoptimize(state, s1_grad); minlbfgsresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-0.99917305]", 0.000005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlbfgs_ftrim"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_regr // Regression problem with one output (2=>1) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // The very simple example on neural network: network is trained to reproduce // small 2x2 multiplication table. // // NOTE: we use network with excessive amount of neurons, which guarantees // almost exact reproduction of the training set. Generalization ability // of such network is rather low, but we are not concerned with such // questions in this basic demo. // mlptrainer trn; multilayerperceptron network; mlpreport rep; // // Training set: // * one row corresponds to one record A*B=C in the multiplication table // * first two columns store A and B, last column stores C // // [1 * 1 = 1] // [1 * 2 = 2] // [2 * 1 = 2] // [2 * 2 = 4] // real_2d_array xy = "[[1,1,1],[1,2,2],[2,1,2],[2,2,4]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // Network is created. // Trainer object is created. // Dataset is attached to trainer object. // mlpcreatetrainer(2, 1, trn); mlpcreate1(2, 5, 1, network); mlpsetdataset(trn, xy, 4); // // Network is trained with 5 restarts from random positions // mlptrainnetwork(trn, network, 5, rep); // // 2*2=? // real_1d_array x = "[2,2]"; real_1d_array y = "[0]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[4.000]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_regr"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_regr_n // Regression problem with multiple outputs (2=>2) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Network with 2 inputs and 2 outputs is trained to reproduce vector function: // (x0,x1) => (x0+x1, x0*x1) // // Informally speaking, we want neural network to simultaneously calculate // both sum of two numbers and their product. // // NOTE: we use network with excessive amount of neurons, which guarantees // almost exact reproduction of the training set. Generalization ability // of such network is rather low, but we are not concerned with such // questions in this basic demo. // mlptrainer trn; multilayerperceptron network; mlpreport rep; // // Training set. One row corresponds to one record [A,B,A+B,A*B]. // // [ 1 1 1+1 1*1 ] // [ 1 2 1+2 1*2 ] // [ 2 1 2+1 2*1 ] // [ 2 2 2+2 2*2 ] // real_2d_array xy = "[[1,1,2,1],[1,2,3,2],[2,1,3,2],[2,2,4,4]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // Network is created. // Trainer object is created. // Dataset is attached to trainer object. // mlpcreatetrainer(2, 2, trn); mlpcreate1(2, 5, 2, network); mlpsetdataset(trn, xy, 4); // // Network is trained with 5 restarts from random positions // mlptrainnetwork(trn, network, 5, rep); // // 2+1=? // 2*1=? // real_1d_array x = "[2,1]"; real_1d_array y = "[0,0]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[3.000,2.000]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_regr_n"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_cls2 // Binary classification problem // printf("50/145\n"); _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Suppose that we want to classify numbers as positive (class 0) and negative // (class 1). We have training set which includes several strictly positive // or negative numbers - and zero. // // The problem is that we are not sure how to classify zero, so from time to // time we mark it as positive or negative (with equal probability). Other // numbers are marked in pure deterministic setting. How will neural network // cope with such classification task? // // NOTE: we use network with excessive amount of neurons, which guarantees // almost exact reproduction of the training set. Generalization ability // of such network is rather low, but we are not concerned with such // questions in this basic demo. // mlptrainer trn; multilayerperceptron network; mlpreport rep; real_1d_array x = "[0]"; real_1d_array y = "[0,0]"; // // Training set. One row corresponds to one record [A => class(A)]. // // Classes are denoted by numbers from 0 to 1, where 0 corresponds to positive // numbers and 1 to negative numbers. // // [ +1 0] // [ +2 0] // [ -1 1] // [ -2 1] // [ 0 0] !! sometimes we classify 0 as positive, sometimes as negative // [ 0 1] !! // real_2d_array xy = "[[+1,0],[+2,0],[-1,1],[-2,1],[0,0],[0,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // // When we solve classification problems, everything is slightly different from // the regression ones: // // 1. Network is created. Because we solve classification problem, we use // mlpcreatec1() function instead of mlpcreate1(). This function creates // classifier network with SOFTMAX-normalized outputs. This network returns // vector of class membership probabilities which are normalized to be // non-negative and sum to 1.0 // // 2. We use mlpcreatetrainercls() function instead of mlpcreatetrainer() to // create trainer object. Trainer object process dataset and neural network // slightly differently to account for specifics of the classification // problems. // // 3. Dataset is attached to trainer object. Note that dataset format is slightly // different from one used for regression. // mlpcreatetrainercls(1, 2, trn); mlpcreatec1(1, 5, 2, network); mlpsetdataset(trn, xy, 6); // // Network is trained with 5 restarts from random positions // mlptrainnetwork(trn, network, 5, rep); // // Test our neural network on strictly positive and strictly negative numbers. // // IMPORTANT! Classifier network returns class membership probabilities instead // of class indexes. Network returns two values (probabilities) instead of one // (class index). // // Thus, for +1 we expect to get [P0,P1] = [1,0], where P0 is probability that // number is positive (belongs to class 0), and P1 is probability that number // is negative (belongs to class 1). // // For -1 we expect to get [P0,P1] = [0,1] // // Following properties are guaranteed by network architecture: // * P0>=0, P1>=0 non-negativity // * P0+P1=1 normalization // x = "[1]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[1.000,0.000]", 0.05); x = "[-1]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,1.000]", 0.05); // // But what our network will return for 0, which is between classes 0 and 1? // // In our dataset it has two different marks assigned (class 0 AND class 1). // So network will return something average between class 0 and class 1: // 0 => [0.5, 0.5] // x = "[0]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.500,0.500]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_cls2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_cls3 // Multiclass classification problem // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // Suppose that we want to classify numbers as positive (class 0) and negative // (class 1). We also have one more class for zero (class 2). // // NOTE: we use network with excessive amount of neurons, which guarantees // almost exact reproduction of the training set. Generalization ability // of such network is rather low, but we are not concerned with such // questions in this basic demo. // mlptrainer trn; multilayerperceptron network; mlpreport rep; real_1d_array x = "[0]"; real_1d_array y = "[0,0,0]"; // // Training set. One row corresponds to one record [A => class(A)]. // // Classes are denoted by numbers from 0 to 2, where 0 corresponds to positive // numbers, 1 to negative numbers, 2 to zero // // [ +1 0] // [ +2 0] // [ -1 1] // [ -2 1] // [ 0 2] // real_2d_array xy = "[[+1,0],[+2,0],[-1,1],[-2,1],[0,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // // When we solve classification problems, everything is slightly different from // the regression ones: // // 1. Network is created. Because we solve classification problem, we use // mlpcreatec1() function instead of mlpcreate1(). This function creates // classifier network with SOFTMAX-normalized outputs. This network returns // vector of class membership probabilities which are normalized to be // non-negative and sum to 1.0 // // 2. We use mlpcreatetrainercls() function instead of mlpcreatetrainer() to // create trainer object. Trainer object process dataset and neural network // slightly differently to account for specifics of the classification // problems. // // 3. Dataset is attached to trainer object. Note that dataset format is slightly // different from one used for regression. // mlpcreatetrainercls(1, 3, trn); mlpcreatec1(1, 5, 3, network); mlpsetdataset(trn, xy, 5); // // Network is trained with 5 restarts from random positions // mlptrainnetwork(trn, network, 5, rep); // // Test our neural network on strictly positive and strictly negative numbers. // // IMPORTANT! Classifier network returns class membership probabilities instead // of class indexes. Network returns three values (probabilities) instead of one // (class index). // // Thus, for +1 we expect to get [P0,P1,P2] = [1,0,0], // for -1 we expect to get [P0,P1,P2] = [0,1,0], // and for 0 we will get [P0,P1,P2] = [0,0,1]. // // Following properties are guaranteed by network architecture: // * P0>=0, P1>=0, P2>=0 non-negativity // * P0+P1+P2=1 normalization // x = "[1]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[1.000,0.000,0.000]", 0.05); x = "[-1]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,1.000,0.000]", 0.05); x = "[0]"; mlpprocess(network, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,0.000,1.000]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_cls3"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_trainerobject // Advanced example on trainer object // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // Trainer object is used to train network. It stores dataset, training settings, // and other information which is NOT part of neural network. You should use // trainer object as follows: // (1) you create trainer object and specify task type (classification/regression) // and number of inputs/outputs // (2) you add dataset to the trainer object // (3) you may change training settings (stopping criteria or weight decay) // (4) finally, you may train one or more networks // // You may interleave stages 2...4 and repeat them many times. Trainer object // remembers its internal state and can be used several times after its creation // and initialization. // mlptrainer trn; // // Stage 1: object creation. // // We have to specify number of inputs and outputs. Trainer object can be used // only for problems with same number of inputs/outputs as was specified during // its creation. // // In case you want to train SOFTMAX-normalized network which solves classification // problems, you must use another function to create trainer object: // mlpcreatetrainercls(). // // Below we create trainer object which can be used to train regression networks // with 2 inputs and 1 output. // mlpcreatetrainer(2, 1, trn); // // Stage 2: specification of the training set // // By default trainer object stores empty dataset. So to solve your non-empty problem // you have to set dataset by passing to trainer dense or sparse matrix. // // One row of the matrix corresponds to one record A*B=C in the multiplication table. // First two columns store A and B, last column stores C // // [1 * 1 = 1] [ 1 1 1 ] // [1 * 2 = 2] [ 1 2 2 ] // [2 * 1 = 2] = [ 2 1 2 ] // [2 * 2 = 4] [ 2 2 4 ] // real_2d_array xy = "[[1,1,1],[1,2,2],[2,1,2],[2,2,4]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); mlpsetdataset(trn, xy, 4); // // Stage 3: modification of the training parameters. // // You may modify parameters like weights decay or stopping criteria: // * we set moderate weight decay // * we choose iterations limit as stopping condition (another condition - step size - // is zero, which means than this condition is not active) // double wstep = 0.000; if( _spoil_scenario==3 ) wstep = fp_nan; if( _spoil_scenario==4 ) wstep = fp_posinf; if( _spoil_scenario==5 ) wstep = fp_neginf; ae_int_t maxits = 100; mlpsetdecay(trn, 0.01); mlpsetcond(trn, wstep, maxits); // // Stage 4: training. // // We will train several networks with different architecture using same trainer object. // We may change training parameters or even dataset, so different networks are trained // differently. But in this simple example we will train all networks with same settings. // // We create and train three networks: // * network 1 has 2x1 architecture (2 inputs, no hidden neurons, 1 output) // * network 2 has 2x5x1 architecture (2 inputs, 5 hidden neurons, 1 output) // * network 3 has 2x5x5x1 architecture (2 inputs, two hidden layers, 1 output) // // NOTE: these networks solve regression problems. For classification problems you // should use mlpcreatec0/c1/c2 to create neural networks which have SOFTMAX- // normalized outputs. // multilayerperceptron net1; multilayerperceptron net2; multilayerperceptron net3; mlpreport rep; mlpcreate0(2, 1, net1); mlpcreate1(2, 5, 1, net2); mlpcreate2(2, 5, 5, 1, net3); mlptrainnetwork(trn, net1, 5, rep); mlptrainnetwork(trn, net2, 5, rep); mlptrainnetwork(trn, net3, 5, rep); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_trainerobject"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_crossvalidation // Cross-validation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example shows how to perform cross-validation with ALGLIB // mlptrainer trn; multilayerperceptron network; mlpreport rep; // // Training set: f(x)=1/(x^2+1) // One row corresponds to one record [x,f(x)] // real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // Trainer object is created. // Dataset is attached to trainer object. // // NOTE: it is not good idea to perform cross-validation on sample // as small as ours (13 examples). It is done for demonstration // purposes only. Generalization error estimates won't be // precise enough for practical purposes. // mlpcreatetrainer(1, 1, trn); mlpsetdataset(trn, xy, 13); // // The key property of the cross-validation is that it estimates // generalization properties of neural ARCHITECTURE. It does NOT // estimates generalization error of some specific network which // is passed to the k-fold CV routine. // // In our example we create 1x4x1 neural network and pass it to // CV routine without training it. Original state of the network // is not used for cross-validation - each round is restarted from // random initial state. Only geometry of network matters. // // We perform 5 restarts from different random positions for each // of the 10 cross-validation rounds. // mlpcreate1(1, 4, 1, network); mlpkfoldcv(trn, network, 5, 10, rep); // // Cross-validation routine stores estimates of the generalization // error to MLP report structure. You may examine its fields and // see estimates of different errors (RMS, CE, Avg). // // Because cross-validation is non-deterministic, in our manual we // can not say what values will be stored to rep after call to // mlpkfoldcv(). Every CV round will return slightly different // estimates. // _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_crossvalidation"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_ensembles_es // Early stopping ensembles // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example shows how to train early stopping ensebles. // mlptrainer trn; mlpensemble ensemble; mlpreport rep; // // Training set: f(x)=1/(x^2+1) // One row corresponds to one record [x,f(x)] // real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); // // Trainer object is created. // Dataset is attached to trainer object. // // NOTE: it is not good idea to use early stopping ensemble on sample // as small as ours (13 examples). It is done for demonstration // purposes only. Ensemble training algorithm won't find good // solution on such small sample. // mlpcreatetrainer(1, 1, trn); mlpsetdataset(trn, xy, 13); // // Ensemble is created and trained. Each of 50 network is trained // with 5 restarts. // mlpecreate1(1, 4, 1, 50, ensemble); mlptrainensemblees(trn, ensemble, 5, rep); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_ensembles_es"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST nn_parallel // Parallel training // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example shows how to use parallel functionality of ALGLIB. // We generate simple 1-dimensional regression problem and show how // to use parallel training, parallel cross-validation, parallel // training of neural ensembles. // // We assume that you already know how to use ALGLIB in serial mode // and concentrate on its parallel capabilities. // // NOTE: it is not good idea to use parallel features on sample as small // as ours (13 examples). It is done only for demonstration purposes. // mlptrainer trn; multilayerperceptron network; mlpensemble ensemble; mlpreport rep; real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); mlpcreatetrainer(1, 1, trn); mlpsetdataset(trn, xy, 13); mlpcreate1(1, 4, 1, network); mlpecreate1(1, 4, 1, 50, ensemble); // // Below we demonstrate how to perform: // * parallel training of individual networks // * parallel cross-validation // * parallel training of neural ensembles // // In order to use multithreading, you have to: // 1) Install SMP edition of ALGLIB. // 2) This step is specific for C++ users: you should activate OS-specific // capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems) // or AE_OS=AE_WINDOWS (for Windows systems). // C# users do not have to perform this step because C# programs are // portable across different systems without OS-specific tuning. // 3) Allow ALGLIB to know about number of worker threads to use: // a) autodetection (C++, C#): // ALGLIB will automatically determine number of CPU cores and // (by default) will use all cores except for one. Say, on 4-core // system it will use three cores - unless you manually told it // to use more or less. It will keep your system responsive during // lengthy computations. // Such behavior may be changed with setnworkers() call: // * alglib::setnworkers(0) = use all cores // * alglib::setnworkers(-1) = leave one core unused // * alglib::setnworkers(-2) = leave two cores unused // * alglib::setnworkers(+2) = use 2 cores (even if you have more) // b) manual specification (C++, C#): // You may want to specify maximum number of worker threads during // compile time by means of preprocessor definition AE_NWORKERS. // For C++ it will be "AE_NWORKERS=X" where X can be any positive number. // For C# it is "AE_NWORKERSX", where X should be replaced by number of // workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...). // You can add this definition to compiler command line or change // corresponding project settings in your IDE. // // After you installed and configured SMP edition of ALGLIB, you may choose // between serial and multithreaded versions of SMP-capable functions: // * serial version works as usual, in the context of the calling thread // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker // threads, inserts task in the worker queue, and waits for completion of // the task. All processing is done in context of worker thread(s). // // NOTE: because starting/stopping worker threads costs thousands of CPU cycles, // you should not use multithreading for lightweight computational problems. // // NOTE: some old POSIX-compatible operating systems do not support // sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order // to automatically determine number of active cores. On these systems // you should specify number of cores manually at compile time. // Without it ALGLIB will run in single-threaded mode. // // // First, we perform parallel training of individual network with 5 // restarts from random positions. These 5 rounds of training are // executed in parallel manner, with best network chosen after // training. // // ALGLIB can use additional way to speed up computations - divide // dataset into smaller subsets and process these subsets // simultaneously. It allows us to efficiently parallelize even // single training round. This operation is performed automatically // for large datasets, but our toy dataset is too small. // smp_mlptrainnetwork(trn, network, 5, rep); // // Then, we perform parallel 10-fold cross-validation, with 5 random // restarts per each CV round. I.e., 5*10=50 networks are trained // in total. All these operations can be parallelized. // // NOTE: again, ALGLIB can parallelize calculation of gradient // over entire dataset - but our dataset is too small. // smp_mlpkfoldcv(trn, network, 5, 10, rep); // // Finally, we train early stopping ensemble of 50 neural networks, // each of them is trained with 5 random restarts. I.e., 5*50=250 // networks aretrained in total. // smp_mlptrainensemblees(trn, ensemble, 5, rep); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "nn_parallel"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST odesolver_d1 // Solving y'=-y with ODE solver // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<13; _spoil_scenario++) { try { real_1d_array y = "[1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); real_1d_array x = "[0, 1, 2, 3]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(x); if( _spoil_scenario==5 ) spoil_vector_by_posinf(x); if( _spoil_scenario==6 ) spoil_vector_by_neginf(x); double eps = 0.00001; if( _spoil_scenario==7 ) eps = fp_nan; if( _spoil_scenario==8 ) eps = fp_posinf; if( _spoil_scenario==9 ) eps = fp_neginf; double h = 0; if( _spoil_scenario==10 ) h = fp_nan; if( _spoil_scenario==11 ) h = fp_posinf; if( _spoil_scenario==12 ) h = fp_neginf; odesolverstate s; ae_int_t m; real_1d_array xtbl; real_2d_array ytbl; odesolverreport rep; odesolverrkck(y, x, eps, h, s); alglib::odesolversolve(s, ode_function_1_diff); odesolverresults(s, m, xtbl, ytbl, rep); _TestResult = _TestResult && doc_test_int(m, 4); _TestResult = _TestResult && doc_test_real_vector(xtbl, "[0, 1, 2, 3]", 0.005); _TestResult = _TestResult && doc_test_real_matrix(ytbl, "[[1], [0.367], [0.135], [0.050]]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "odesolver_d1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST fft_complex_d1 // Complex FFT: simple example // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // first we demonstrate forward FFT: // [1i,1i,1i,1i] is converted to [4i, 0, 0, 0] // complex_1d_array z = "[1i,1i,1i,1i]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(z); if( _spoil_scenario==1 ) spoil_vector_by_posinf(z); if( _spoil_scenario==2 ) spoil_vector_by_neginf(z); fftc1d(z); _TestResult = _TestResult && doc_test_complex_vector(z, "[4i,0,0,0]", 0.0001); // // now we convert [4i, 0, 0, 0] back to [1i,1i,1i,1i] // with backward FFT // fftc1dinv(z); _TestResult = _TestResult && doc_test_complex_vector(z, "[1i,1i,1i,1i]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "fft_complex_d1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST fft_complex_d2 // Complex FFT: advanced example // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // first we demonstrate forward FFT: // [0,1,0,1i] is converted to [1+1i, -1-1i, -1-1i, 1+1i] // complex_1d_array z = "[0,1,0,1i]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(z); if( _spoil_scenario==1 ) spoil_vector_by_posinf(z); if( _spoil_scenario==2 ) spoil_vector_by_neginf(z); fftc1d(z); _TestResult = _TestResult && doc_test_complex_vector(z, "[1+1i, -1-1i, -1-1i, 1+1i]", 0.0001); // // now we convert result back with backward FFT // fftc1dinv(z); _TestResult = _TestResult && doc_test_complex_vector(z, "[0,1,0,1i]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "fft_complex_d2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST fft_real_d1 // Real FFT: simple example // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // first we demonstrate forward FFT: // [1,1,1,1] is converted to [4, 0, 0, 0] // real_1d_array x = "[1,1,1,1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); complex_1d_array f; real_1d_array x2; fftr1d(x, f); _TestResult = _TestResult && doc_test_complex_vector(f, "[4,0,0,0]", 0.0001); // // now we convert [4, 0, 0, 0] back to [1,1,1,1] // with backward FFT // fftr1dinv(f, x2); _TestResult = _TestResult && doc_test_real_vector(x2, "[1,1,1,1]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "fft_real_d1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST fft_real_d2 // Real FFT: advanced example // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // first we demonstrate forward FFT: // [1,2,3,4] is converted to [10, -2+2i, -2, -2-2i] // // note that output array is self-adjoint: // * f[0] = conj(f[0]) // * f[1] = conj(f[3]) // * f[2] = conj(f[2]) // real_1d_array x = "[1,2,3,4]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); complex_1d_array f; real_1d_array x2; fftr1d(x, f); _TestResult = _TestResult && doc_test_complex_vector(f, "[10, -2+2i, -2, -2-2i]", 0.0001); // // now we convert [10, -2+2i, -2, -2-2i] back to [1,2,3,4] // fftr1dinv(f, x2); _TestResult = _TestResult && doc_test_real_vector(x2, "[1,2,3,4]", 0.0001); // // remember that F is self-adjoint? It means that we can pass just half // (slightly larger than half) of F to inverse real FFT and still get our result. // // I.e. instead [10, -2+2i, -2, -2-2i] we pass just [10, -2+2i, -2] and everything works! // // NOTE: in this case we should explicitly pass array length (which is 4) to ALGLIB; // if not, it will automatically use array length to determine FFT size and // will erroneously make half-length FFT. // f = "[10, -2+2i, -2]"; fftr1dinv(f, 4, x2); _TestResult = _TestResult && doc_test_real_vector(x2, "[1,2,3,4]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "fft_real_d2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST fft_complex_e1 // error detection in backward FFT // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { complex_1d_array z = "[0,2,0,-2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(z); if( _spoil_scenario==1 ) spoil_vector_by_posinf(z); if( _spoil_scenario==2 ) spoil_vector_by_neginf(z); fftc1dinv(z); _TestResult = _TestResult && doc_test_complex_vector(z, "[0,1i,0,-1i]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "fft_complex_e1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST autogk_d1 // Integrating f=exp(x) by adaptive integrator // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // This example demonstrates integration of f=exp(x) on [0,1]: // * first, autogkstate is initialized // * then we call integration function // * and finally we obtain results with autogkresults() call // double a = 0; if( _spoil_scenario==0 ) a = fp_nan; if( _spoil_scenario==1 ) a = fp_posinf; if( _spoil_scenario==2 ) a = fp_neginf; double b = 1; if( _spoil_scenario==3 ) b = fp_nan; if( _spoil_scenario==4 ) b = fp_posinf; if( _spoil_scenario==5 ) b = fp_neginf; autogkstate s; double v; autogkreport rep; autogksmooth(a, b, s); alglib::autogkintegrate(s, int_function_1_func); autogkresults(s, v, rep); _TestResult = _TestResult && doc_test_real(v, 1.7182, 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "autogk_d1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_d_calcdiff // Interpolation and differentiation using barycentric representation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // Here we demonstrate polynomial interpolation and differentiation // of y=x^2-x sampled at [0,1,2]. Barycentric representation of polynomial is used. // real_1d_array x = "[0,1,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0,0,2]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==10 ) t = fp_posinf; if( _spoil_scenario==11 ) t = fp_neginf; double v; double dv; double d2v; barycentricinterpolant p; // barycentric model is created polynomialbuild(x, y, p); // barycentric interpolation is demonstrated v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); // barycentric differentation is demonstrated barycentricdiff1(p, t, v, dv); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && doc_test_real(dv, -3.0, 0.00005); // second derivatives with barycentric representation barycentricdiff1(p, t, v, dv); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && doc_test_real(dv, -3.0, 0.00005); barycentricdiff2(p, t, v, dv, d2v); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && doc_test_real(dv, -3.0, 0.00005); _TestResult = _TestResult && doc_test_real(d2v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_d_calcdiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_d_conv // Conversion between power basis and barycentric representation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { // // Here we demonstrate conversion of y=x^2-x // between power basis and barycentric representation. // real_1d_array a = "[0,-1,+1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(a); if( _spoil_scenario==1 ) spoil_vector_by_posinf(a); if( _spoil_scenario==2 ) spoil_vector_by_neginf(a); double t = 2; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; real_1d_array a2; double v; barycentricinterpolant p; // // a=[0,-1,+1] is decomposition of y=x^2-x in the power basis: // // y = 0 - 1*x + 1*x^2 // // We convert it to the barycentric form. // polynomialpow2bar(a, p); // now we have barycentric interpolation; we can use it for interpolation v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.005); // we can also convert back from barycentric representation to power basis polynomialbar2pow(p, a2); _TestResult = _TestResult && doc_test_real_vector(a2, "[0,-1,+1]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_d_conv"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_d_spec // Polynomial interpolation on special grids (equidistant, Chebyshev I/II) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { // // Temporaries: // * values of y=x^2-x sampled at three special grids: // * equdistant grid spanning [0,2], x[i] = 2*i/(N-1), i=0..N-1 // * Chebyshev-I grid spanning [-1,+1], x[i] = 1 + Cos(PI*(2*i+1)/(2*n)), i=0..N-1 // * Chebyshev-II grid spanning [-1,+1], x[i] = 1 + Cos(PI*i/(n-1)), i=0..N-1 // * barycentric interpolants for these three grids // * vectors to store coefficients of quadratic representation // real_1d_array y_eqdist = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y_eqdist); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y_eqdist); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y_eqdist); real_1d_array y_cheb1 = "[-0.116025,0.000000,1.616025]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(y_cheb1); if( _spoil_scenario==4 ) spoil_vector_by_posinf(y_cheb1); if( _spoil_scenario==5 ) spoil_vector_by_neginf(y_cheb1); real_1d_array y_cheb2 = "[0,0,2]"; if( _spoil_scenario==6 ) spoil_vector_by_nan(y_cheb2); if( _spoil_scenario==7 ) spoil_vector_by_posinf(y_cheb2); if( _spoil_scenario==8 ) spoil_vector_by_neginf(y_cheb2); barycentricinterpolant p_eqdist; barycentricinterpolant p_cheb1; barycentricinterpolant p_cheb2; real_1d_array a_eqdist; real_1d_array a_cheb1; real_1d_array a_cheb2; // // First, we demonstrate construction of barycentric interpolants on // special grids. We unpack power representation to ensure that // interpolant was built correctly. // // In all three cases we should get same quadratic function. // polynomialbuildeqdist(0.0, 2.0, y_eqdist, p_eqdist); polynomialbar2pow(p_eqdist, a_eqdist); _TestResult = _TestResult && doc_test_real_vector(a_eqdist, "[0,-1,+1]", 0.00005); polynomialbuildcheb1(-1, +1, y_cheb1, p_cheb1); polynomialbar2pow(p_cheb1, a_cheb1); _TestResult = _TestResult && doc_test_real_vector(a_cheb1, "[0,-1,+1]", 0.00005); polynomialbuildcheb2(-1, +1, y_cheb2, p_cheb2); polynomialbar2pow(p_cheb2, a_cheb2); _TestResult = _TestResult && doc_test_real_vector(a_cheb2, "[0,-1,+1]", 0.00005); // // Now we demonstrate polynomial interpolation without construction // of the barycentricinterpolant structure. // // We calculate interpolant value at x=-2. // In all three cases we should get same f=6 // double t = -2; if( _spoil_scenario==9 ) t = fp_posinf; if( _spoil_scenario==10 ) t = fp_neginf; double v; v = polynomialcalceqdist(0.0, 2.0, y_eqdist, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); v = polynomialcalccheb1(-1, +1, y_cheb1, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); v = polynomialcalccheb2(-1, +1, y_cheb2, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_d_spec"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_1 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { real_1d_array x = "[0,1,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0,0,2]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==8 ) t = fp_posinf; if( _spoil_scenario==9 ) t = fp_neginf; barycentricinterpolant p; double v; polynomialbuild(x, y, 3, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_2 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; barycentricinterpolant p; double v; polynomialbuildeqdist(0.0, 2.0, y, 3, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_3 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { real_1d_array y = "[-0.116025,0.000000,1.616025]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; barycentricinterpolant p; double v; polynomialbuildcheb1(-1.0, +1.0, y, 3, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_3"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_4 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -2; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; double a = -1; if( _spoil_scenario==6 ) a = fp_nan; if( _spoil_scenario==7 ) a = fp_posinf; if( _spoil_scenario==8 ) a = fp_neginf; double b = +1; if( _spoil_scenario==9 ) b = fp_nan; if( _spoil_scenario==10 ) b = fp_posinf; if( _spoil_scenario==11 ) b = fp_neginf; barycentricinterpolant p; double v; polynomialbuildcheb2(a, b, y, 3, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_4"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_5 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; double v; v = polynomialcalceqdist(0.0, 2.0, y, 3, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_5"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_6 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { real_1d_array y = "[-0.116025,0.000000,1.616025]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -1; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; double a = -1; if( _spoil_scenario==6 ) a = fp_nan; if( _spoil_scenario==7 ) a = fp_posinf; if( _spoil_scenario==8 ) a = fp_neginf; double b = +1; if( _spoil_scenario==9 ) b = fp_nan; if( _spoil_scenario==10 ) b = fp_posinf; if( _spoil_scenario==11 ) b = fp_neginf; double v; v = polynomialcalccheb1(a, b, y, 3, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_6"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_7 // Polynomial interpolation, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(y); double t = -2; if( _spoil_scenario==4 ) t = fp_posinf; if( _spoil_scenario==5 ) t = fp_neginf; double a = -1; if( _spoil_scenario==6 ) a = fp_nan; if( _spoil_scenario==7 ) a = fp_posinf; if( _spoil_scenario==8 ) a = fp_neginf; double b = +1; if( _spoil_scenario==9 ) b = fp_nan; if( _spoil_scenario==10 ) b = fp_posinf; if( _spoil_scenario==11 ) b = fp_neginf; double v; v = polynomialcalccheb2(a, b, y, 3, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_7"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_8 // Polynomial interpolation: y=x^2-x, equidistant grid, barycentric form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -1; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; barycentricinterpolant p; double v; polynomialbuildeqdist(0.0, 2.0, y, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_8"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_9 // Polynomial interpolation: y=x^2-x, Chebyshev grid (first kind), barycentric form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { real_1d_array y = "[-0.116025,0.000000,1.616025]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -1; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; double a = -1; if( _spoil_scenario==5 ) a = fp_nan; if( _spoil_scenario==6 ) a = fp_posinf; if( _spoil_scenario==7 ) a = fp_neginf; double b = +1; if( _spoil_scenario==8 ) b = fp_nan; if( _spoil_scenario==9 ) b = fp_posinf; if( _spoil_scenario==10 ) b = fp_neginf; barycentricinterpolant p; double v; polynomialbuildcheb1(a, b, y, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_9"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_10 // Polynomial interpolation: y=x^2-x, Chebyshev grid (second kind), barycentric form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -2; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; double a = -1; if( _spoil_scenario==5 ) a = fp_nan; if( _spoil_scenario==6 ) a = fp_posinf; if( _spoil_scenario==7 ) a = fp_neginf; double b = +1; if( _spoil_scenario==8 ) b = fp_nan; if( _spoil_scenario==9 ) b = fp_posinf; if( _spoil_scenario==10 ) b = fp_neginf; barycentricinterpolant p; double v; polynomialbuildcheb2(a, b, y, p); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_10"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_11 // Polynomial interpolation: y=x^2-x, equidistant grid // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -1; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; double v; v = polynomialcalceqdist(0.0, 2.0, y, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_11"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_12 // Polynomial interpolation: y=x^2-x, Chebyshev grid (first kind) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { real_1d_array y = "[-0.116025,0.000000,1.616025]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -1; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; double a = -1; if( _spoil_scenario==5 ) a = fp_nan; if( _spoil_scenario==6 ) a = fp_posinf; if( _spoil_scenario==7 ) a = fp_neginf; double b = +1; if( _spoil_scenario==8 ) b = fp_nan; if( _spoil_scenario==9 ) b = fp_posinf; if( _spoil_scenario==10 ) b = fp_neginf; double v; v = polynomialcalccheb1(a, b, y, t); _TestResult = _TestResult && doc_test_real(v, 2.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_12"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST polint_t_13 // Polynomial interpolation: y=x^2-x, Chebyshev grid (second kind) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { real_1d_array y = "[0,0,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); double t = -2; if( _spoil_scenario==3 ) t = fp_posinf; if( _spoil_scenario==4 ) t = fp_neginf; double a = -1; if( _spoil_scenario==5 ) a = fp_nan; if( _spoil_scenario==6 ) a = fp_posinf; if( _spoil_scenario==7 ) a = fp_neginf; double b = +1; if( _spoil_scenario==8 ) b = fp_nan; if( _spoil_scenario==9 ) b = fp_posinf; if( _spoil_scenario==10 ) b = fp_neginf; double v; v = polynomialcalccheb2(a, b, y, t); _TestResult = _TestResult && doc_test_real(v, 6.0, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "polint_t_13"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline1d_d_linear // Piecewise linear spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // We use piecewise linear spline to interpolate f(x)=x^2 sampled // at 5 equidistant nodes on [-1,+1]. // real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); double t = 0.25; if( _spoil_scenario==10 ) t = fp_posinf; if( _spoil_scenario==11 ) t = fp_neginf; double v; spline1dinterpolant s; // build spline spline1dbuildlinear(x, y, s); // calculate S(0.25) - it is quite different from 0.25^2=0.0625 v = spline1dcalc(s, t); _TestResult = _TestResult && doc_test_real(v, 0.125, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline1d_d_linear"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline1d_d_cubic // Cubic spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { // // We use cubic spline to interpolate f(x)=x^2 sampled // at 5 equidistant nodes on [-1,+1]. // // First, we use default boundary conditions ("parabolically terminated // spline") because cubic spline built with such boundary conditions // will exactly reproduce any quadratic f(x). // // Then we try to use natural boundary conditions // d2S(-1)/dx^2 = 0.0 // d2S(+1)/dx^2 = 0.0 // and see that such spline interpolated f(x) with small error. // real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); double t = 0.25; if( _spoil_scenario==8 ) t = fp_posinf; if( _spoil_scenario==9 ) t = fp_neginf; double v; spline1dinterpolant s; ae_int_t natural_bound_type = 2; // // Test exact boundary conditions: build S(x), calculare S(0.25) // (almost same as original function) // spline1dbuildcubic(x, y, s); v = spline1dcalc(s, t); _TestResult = _TestResult && doc_test_real(v, 0.0625, 0.00001); // // Test natural boundary conditions: build S(x), calculare S(0.25) // (small interpolation error) // spline1dbuildcubic(x, y, 5, natural_bound_type, 0.0, natural_bound_type, 0.0, s); v = spline1dcalc(s, t); _TestResult = _TestResult && doc_test_real(v, 0.0580, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline1d_d_cubic"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline1d_d_monotone // Monotone interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { // // Spline built witn spline1dbuildcubic() can be non-monotone even when // Y-values form monotone sequence. Say, for x=[0,1,2] and y=[0,1,1] // cubic spline will monotonically grow until x=1.5 and then start // decreasing. // // That's why ALGLIB provides special spline construction function // which builds spline which preserves monotonicity of the original // dataset. // // NOTE: in case original dataset is non-monotonic, ALGLIB splits it // into monotone subsequences and builds piecewise monotonic spline. // real_1d_array x = "[0,1,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0,1,1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); spline1dinterpolant s; // build spline spline1dbuildmonotone(x, y, s); // calculate S at x = [-0.5, 0.0, 0.5, 1.0, 1.5, 2.0] // you may see that spline is really monotonic double v; v = spline1dcalc(s, -0.5); _TestResult = _TestResult && doc_test_real(v, 0.0000, 0.00005); v = spline1dcalc(s, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.0000, 0.00005); v = spline1dcalc(s, +0.5); _TestResult = _TestResult && doc_test_real(v, 0.5000, 0.00005); v = spline1dcalc(s, 1.0); _TestResult = _TestResult && doc_test_real(v, 1.0000, 0.00005); v = spline1dcalc(s, 1.5); _TestResult = _TestResult && doc_test_real(v, 1.0000, 0.00005); v = spline1dcalc(s, 2.0); _TestResult = _TestResult && doc_test_real(v, 1.0000, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline1d_d_monotone"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline1d_d_griddiff // Differentiation on the grid using cubic splines // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { // // We use cubic spline to do grid differentiation, i.e. having // values of f(x)=x^2 sampled at 5 equidistant nodes on [-1,+1] // we calculate derivatives of cubic spline at nodes WITHOUT // CONSTRUCTION OF SPLINE OBJECT. // // There are efficient functions spline1dgriddiffcubic() and // spline1dgriddiff2cubic() for such calculations. // // We use default boundary conditions ("parabolically terminated // spline") because cubic spline built with such boundary conditions // will exactly reproduce any quadratic f(x). // // Actually, we could use natural conditions, but we feel that // spline which exactly reproduces f() will show us more // understandable results. // real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array d1; real_1d_array d2; // // We calculate first derivatives: they must be equal to 2*x // spline1dgriddiffcubic(x, y, d1); _TestResult = _TestResult && doc_test_real_vector(d1, "[-2.0, -1.0, 0.0, +1.0, +2.0]", 0.0001); // // Now test griddiff2, which returns first AND second derivatives. // First derivative is 2*x, second is equal to 2.0 // spline1dgriddiff2cubic(x, y, d1, d2); _TestResult = _TestResult && doc_test_real_vector(d1, "[-2.0, -1.0, 0.0, +1.0, +2.0]", 0.0001); _TestResult = _TestResult && doc_test_real_vector(d2, "[ 2.0, 2.0, 2.0, 2.0, 2.0]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline1d_d_griddiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline1d_d_convdiff // Resampling using cubic splines // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<11; _spoil_scenario++) { try { // // We use cubic spline to do resampling, i.e. having // values of f(x)=x^2 sampled at 5 equidistant nodes on [-1,+1] // we calculate values/derivatives of cubic spline on // another grid (equidistant with 9 nodes on [-1,+1]) // WITHOUT CONSTRUCTION OF SPLINE OBJECT. // // There are efficient functions spline1dconvcubic(), // spline1dconvdiffcubic() and spline1dconvdiff2cubic() // for such calculations. // // We use default boundary conditions ("parabolically terminated // spline") because cubic spline built with such boundary conditions // will exactly reproduce any quadratic f(x). // // Actually, we could use natural conditions, but we feel that // spline which exactly reproduces f() will show us more // understandable results. // real_1d_array x_old = "[-1.0,-0.5,0.0,+0.5,+1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x_old); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x_old); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x_old); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x_old); real_1d_array y_old = "[+1.0,0.25,0.0,0.25,+1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y_old); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y_old); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y_old); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y_old); real_1d_array x_new = "[-1.00,-0.75,-0.50,-0.25,0.00,+0.25,+0.50,+0.75,+1.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(x_new); if( _spoil_scenario==9 ) spoil_vector_by_posinf(x_new); if( _spoil_scenario==10 ) spoil_vector_by_neginf(x_new); real_1d_array y_new; real_1d_array d1_new; real_1d_array d2_new; // // First, conversion without differentiation. // // spline1dconvcubic(x_old, y_old, x_new, y_new); _TestResult = _TestResult && doc_test_real_vector(y_new, "[1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]", 0.0001); // // Then, conversion with differentiation (first derivatives only) // // spline1dconvdiffcubic(x_old, y_old, x_new, y_new, d1_new); _TestResult = _TestResult && doc_test_real_vector(y_new, "[1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]", 0.0001); _TestResult = _TestResult && doc_test_real_vector(d1_new, "[-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]", 0.0001); // // Finally, conversion with first and second derivatives // // spline1dconvdiff2cubic(x_old, y_old, x_new, y_new, d1_new, d2_new); _TestResult = _TestResult && doc_test_real_vector(y_new, "[1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]", 0.0001); _TestResult = _TestResult && doc_test_real_vector(d1_new, "[-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]", 0.0001); _TestResult = _TestResult && doc_test_real_vector(d2_new, "[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]", 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline1d_d_convdiff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minqp_d_u1 // Unconstrained dense quadratic programming // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<17; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1 // // Exact solution is [x0,x1] = [3,2] // // We provide algorithm with starting point, although in this case // (dense matrix, no constraints) it can work without such information. // // IMPORTANT: this solver minimizes following function: // f(x) = 0.5*x'*A*x + b'*x. // Note that quadratic term has 0.5 before it. So if you want to minimize // quadratic function, you should rewrite it in such way that quadratic term // is multiplied by 0.5 too. // // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as // f(x) = 0.5*(2*x0^2+2*x1^2) + .... // and pass diag(2,2) as quadratic term - NOT diag(1,1)! // real_2d_array a = "[[2,0],[0,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(a); real_1d_array b = "[-6,-4]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(b); if( _spoil_scenario==6 ) spoil_vector_by_posinf(b); if( _spoil_scenario==7 ) spoil_vector_by_neginf(b); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(b); real_1d_array x0 = "[0,1]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(x0); if( _spoil_scenario==10 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==11 ) spoil_vector_by_neginf(x0); if( _spoil_scenario==12 ) spoil_vector_by_deleting_element(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==13 ) spoil_vector_by_nan(s); if( _spoil_scenario==14 ) spoil_vector_by_posinf(s); if( _spoil_scenario==15 ) spoil_vector_by_neginf(s); if( _spoil_scenario==16 ) spoil_vector_by_deleting_element(s); real_1d_array x; minqpstate state; minqpreport rep; // create solver, set quadratic/linear terms minqpcreate(2, state); minqpsetquadraticterm(state, a); minqpsetlinearterm(state, b); minqpsetstartingpoint(state, x0); // Set scale of the parameters. // It is strongly recommended that you set scale of your variables. // Knowing their scales is essential for evaluation of stopping criteria // and for preconditioning of the algorithm steps. // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php minqpsetscale(state, s); // solve problem with QuickQP solver, default stopping criteria are used, Newton phase is active minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[3,2]", 0.005); // solve problem with BLEIC-based QP solver. // default stopping criteria are used. minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[3,2]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minqp_d_u1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minqp_d_bc1 // Bound constrained dense quadratic programming // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<21; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1 // subject to bound constraints 0<=x0<=2.5, 0<=x1<=2.5 // // Exact solution is [x0,x1] = [2.5,2] // // We provide algorithm with starting point. With such small problem good starting // point is not really necessary, but with high-dimensional problem it can save us // a lot of time. // // IMPORTANT: this solver minimizes following function: // f(x) = 0.5*x'*A*x + b'*x. // Note that quadratic term has 0.5 before it. So if you want to minimize // quadratic function, you should rewrite it in such way that quadratic term // is multiplied by 0.5 too. // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as // f(x) = 0.5*(2*x0^2+2*x1^2) + .... // and pass diag(2,2) as quadratic term - NOT diag(1,1)! // real_2d_array a = "[[2,0],[0,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(a); real_1d_array b = "[-6,-4]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(b); if( _spoil_scenario==6 ) spoil_vector_by_posinf(b); if( _spoil_scenario==7 ) spoil_vector_by_neginf(b); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(b); real_1d_array x0 = "[0,1]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(x0); if( _spoil_scenario==10 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==11 ) spoil_vector_by_neginf(x0); if( _spoil_scenario==12 ) spoil_vector_by_deleting_element(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==13 ) spoil_vector_by_nan(s); if( _spoil_scenario==14 ) spoil_vector_by_posinf(s); if( _spoil_scenario==15 ) spoil_vector_by_neginf(s); if( _spoil_scenario==16 ) spoil_vector_by_deleting_element(s); real_1d_array bndl = "[0.0,0.0]"; if( _spoil_scenario==17 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==18 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[2.5,2.5]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==20 ) spoil_vector_by_deleting_element(bndu); real_1d_array x; minqpstate state; minqpreport rep; // create solver, set quadratic/linear terms minqpcreate(2, state); minqpsetquadraticterm(state, a); minqpsetlinearterm(state, b); minqpsetstartingpoint(state, x0); minqpsetbc(state, bndl, bndu); // Set scale of the parameters. // It is strongly recommended that you set scale of your variables. // Knowing their scales is essential for evaluation of stopping criteria // and for preconditioning of the algorithm steps. // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php minqpsetscale(state, s); // solve problem with QuickQP solver, default stopping criteria are used minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[2.5,2]", 0.005); // solve problem with BLEIC-based QP solver // default stopping criteria are used. minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[2.5,2]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minqp_d_bc1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minqp_d_lc1 // Linearly constrained dense quadratic programming // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1 // subject to linear constraint x0+x1<=2 // // Exact solution is [x0,x1] = [1.5,0.5] // // IMPORTANT: this solver minimizes following function: // f(x) = 0.5*x'*A*x + b'*x. // Note that quadratic term has 0.5 before it. So if you want to minimize // quadratic function, you should rewrite it in such way that quadratic term // is multiplied by 0.5 too. // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as // f(x) = 0.5*(2*x0^2+2*x1^2) + .... // and pass diag(2,2) as quadratic term - NOT diag(1,1)! // real_2d_array a = "[[2,0],[0,2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(a); real_1d_array b = "[-6,-4]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(b); if( _spoil_scenario==6 ) spoil_vector_by_posinf(b); if( _spoil_scenario==7 ) spoil_vector_by_neginf(b); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(b); real_1d_array s = "[1,1]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(s); if( _spoil_scenario==10 ) spoil_vector_by_posinf(s); if( _spoil_scenario==11 ) spoil_vector_by_neginf(s); if( _spoil_scenario==12 ) spoil_vector_by_deleting_element(s); real_2d_array c = "[[1.0,1.0,2.0]]"; if( _spoil_scenario==13 ) spoil_matrix_by_nan(c); if( _spoil_scenario==14 ) spoil_matrix_by_posinf(c); if( _spoil_scenario==15 ) spoil_matrix_by_neginf(c); integer_1d_array ct = "[-1]"; real_1d_array x; minqpstate state; minqpreport rep; // create solver, set quadratic/linear terms minqpcreate(2, state); minqpsetquadraticterm(state, a); minqpsetlinearterm(state, b); minqpsetlc(state, c, ct); // Set scale of the parameters. // It is strongly recommended that you set scale of your variables. // Knowing their scales is essential for evaluation of stopping criteria // and for preconditioning of the algorithm steps. // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php minqpsetscale(state, s); // solve problem with BLEIC-based QP solver // default stopping criteria are used. minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[1.500,0.500]", 0.05); // solve problem with QuickQP solver, default stopping criteria are used // Oops! It does not support general linear constraints, -5 returned as completion code! minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, -5); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minqp_d_lc1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minqp_d_u2 // Unconstrained sparse quadratic programming // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1, // with quadratic term given by sparse matrix structure. // // Exact solution is [x0,x1] = [3,2] // // We provide algorithm with starting point, although in this case // (dense matrix, no constraints) it can work without such information. // // IMPORTANT: this solver minimizes following function: // f(x) = 0.5*x'*A*x + b'*x. // Note that quadratic term has 0.5 before it. So if you want to minimize // quadratic function, you should rewrite it in such way that quadratic term // is multiplied by 0.5 too. // // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as // f(x) = 0.5*(2*x0^2+2*x1^2) + .... // and pass diag(2,2) as quadratic term - NOT diag(1,1)! // sparsematrix a; real_1d_array b = "[-6,-4]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(b); if( _spoil_scenario==1 ) spoil_vector_by_posinf(b); if( _spoil_scenario==2 ) spoil_vector_by_neginf(b); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(b); real_1d_array x0 = "[0,1]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(x0); if( _spoil_scenario==5 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==6 ) spoil_vector_by_neginf(x0); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(s); if( _spoil_scenario==9 ) spoil_vector_by_posinf(s); if( _spoil_scenario==10 ) spoil_vector_by_neginf(s); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(s); real_1d_array x; minqpstate state; minqpreport rep; // initialize sparsematrix structure sparsecreate(2, 2, 0, a); sparseset(a, 0, 0, 2.0); sparseset(a, 1, 1, 2.0); // create solver, set quadratic/linear terms minqpcreate(2, state); minqpsetquadratictermsparse(state, a, true); minqpsetlinearterm(state, b); minqpsetstartingpoint(state, x0); // Set scale of the parameters. // It is strongly recommended that you set scale of your variables. // Knowing their scales is essential for evaluation of stopping criteria // and for preconditioning of the algorithm steps. // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php minqpsetscale(state, s); // solve problem with BLEIC-based QP solver. // default stopping criteria are used. minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[3,2]", 0.005); // try to solve problem with Cholesky-based QP solver... // Oops! It does not support sparse matrices, -5 returned as completion code! minqpsetalgocholesky(state); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, -5); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minqp_d_u2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minqp_d_nonconvex // Nonconvex quadratic programming // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<21; _spoil_scenario++) { try { // // This example demonstrates minimization of nonconvex function // F(x0,x1) = -(x0^2+x1^2) // subject to constraints x0,x1 in [1.0,2.0] // Exact solution is [x0,x1] = [2,2]. // // IMPORTANT: this solver minimizes following function: // f(x) = 0.5*x'*A*x + b'*x. // Note that quadratic term has 0.5 before it. So if you want to minimize // quadratic function, you should rewrite it in such way that quadratic term // is multiplied by 0.5 too. // // For example, our function is f(x)=-(x0^2+x1^2), but we rewrite it as // f(x) = 0.5*(-2*x0^2-2*x1^2) // and pass diag(-2,-2) as quadratic term - NOT diag(-1,-1)! // real_2d_array a = "[[-2,0],[0,-2]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(a); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(a); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(a); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(a); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(a); real_1d_array x0 = "[1,1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(x0); if( _spoil_scenario==6 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==7 ) spoil_vector_by_neginf(x0); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(s); if( _spoil_scenario==10 ) spoil_vector_by_posinf(s); if( _spoil_scenario==11 ) spoil_vector_by_neginf(s); if( _spoil_scenario==12 ) spoil_vector_by_deleting_element(s); real_1d_array bndl = "[1.0,1.0]"; if( _spoil_scenario==13 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==14 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[2.0,2.0]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==16 ) spoil_vector_by_deleting_element(bndu); real_1d_array x; minqpstate state; minqpreport rep; // create solver, set quadratic/linear terms, constraints minqpcreate(2, state); minqpsetquadraticterm(state, a); minqpsetstartingpoint(state, x0); minqpsetbc(state, bndl, bndu); // Set scale of the parameters. // It is strongly recommended that you set scale of your variables. // Knowing their scales is essential for evaluation of stopping criteria // and for preconditioning of the algorithm steps. // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php minqpsetscale(state, s); // solve problem with BLEIC-QP solver. // default stopping criteria are used. minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[2,2]", 0.005); // Hmm... this problem is bounded from below (has solution) only under constraints. // What it we remove them? // // You may see that algorithm detects unboundedness of the problem, // -4 is returned as completion code. real_1d_array nobndl = "[-inf,-inf]"; if( _spoil_scenario==17 ) spoil_vector_by_nan(nobndl); if( _spoil_scenario==18 ) spoil_vector_by_deleting_element(nobndl); real_1d_array nobndu = "[+inf,+inf]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(nobndu); if( _spoil_scenario==20 ) spoil_vector_by_deleting_element(nobndu); minqpsetbc(state, nobndl, nobndu); minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0); minqpoptimize(state); minqpresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, -4); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minqp_d_nonconvex"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_d_v // Nonlinear least squares optimization using function vector only // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where // // f0(x0,x1) = 10*(x0+3)^2 // f1(x0,x1) = (x1-3)^2 // // using "V" mode of the Levenberg-Marquardt optimizer. // // Optimization algorithm uses: // * function vector f[] = {f1,f2} // // No other information (Jacobian, gradient, etc.) is needed. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatev(2, x, 0.0001, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_fvec); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_d_v"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_d_vj // Nonlinear least squares optimization using function vector and Jacobian // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where // // f0(x0,x1) = 10*(x0+3)^2 // f1(x0,x1) = (x1-3)^2 // // using "VJ" mode of the Levenberg-Marquardt optimizer. // // Optimization algorithm uses: // * function vector f[] = {f1,f2} // * Jacobian matrix J = {dfi/dxj}. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatevj(2, x, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_fvec, function1_jac); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_d_vj"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_d_fgh // Nonlinear Hessian-based optimization for general functions // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = 100*(x0+3)^4+(x1-3)^4 // using "FGH" mode of the Levenberg-Marquardt optimizer. // // F is treated like a monolitic function without internal structure, // i.e. we do NOT represent it as a sum of squares. // // Optimization algorithm uses: // * function value F(x0,x1) // * gradient G={dF/dxi} // * Hessian H={d2F/(dxi*dxj)} // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatefgh(x, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_func, function1_grad, function1_hess); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_d_fgh"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_d_vb // Bound constrained nonlinear least squares optimization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where // // f0(x0,x1) = 10*(x0+3)^2 // f1(x0,x1) = (x1-3)^2 // // with boundary constraints // // -1 <= x0 <= +1 // -1 <= x1 <= +1 // // using "V" mode of the Levenberg-Marquardt optimizer. // // Optimization algorithm uses: // * function vector f[] = {f1,f2} // // No other information (Jacobian, gradient, etc.) is needed. // real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); real_1d_array bndl = "[-1,-1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[+1,+1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==6 ) spoil_vector_by_deleting_element(bndu); double epsg = 0.0000000001; if( _spoil_scenario==7 ) epsg = fp_nan; if( _spoil_scenario==8 ) epsg = fp_posinf; if( _spoil_scenario==9 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==10 ) epsf = fp_nan; if( _spoil_scenario==11 ) epsf = fp_posinf; if( _spoil_scenario==12 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==13 ) epsx = fp_nan; if( _spoil_scenario==14 ) epsx = fp_posinf; if( _spoil_scenario==15 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatev(2, x, 0.0001, state); minlmsetbc(state, bndl, bndu); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_fvec); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-1,+1]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_d_vb"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_d_restarts // Efficient restarts of LM optimizer // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<15; _spoil_scenario++) { try { // // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where // // f0(x0,x1) = 10*(x0+3)^2 // f1(x0,x1) = (x1-3)^2 // // using several starting points and efficient restarts. // real_1d_array x; double epsg = 0.0000000001; if( _spoil_scenario==0 ) epsg = fp_nan; if( _spoil_scenario==1 ) epsg = fp_posinf; if( _spoil_scenario==2 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==3 ) epsf = fp_nan; if( _spoil_scenario==4 ) epsf = fp_posinf; if( _spoil_scenario==5 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==6 ) epsx = fp_nan; if( _spoil_scenario==7 ) epsx = fp_posinf; if( _spoil_scenario==8 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; // // create optimizer using minlmcreatev() // x = "[10,10]"; if( _spoil_scenario==9 ) spoil_vector_by_nan(x); if( _spoil_scenario==10 ) spoil_vector_by_posinf(x); if( _spoil_scenario==11 ) spoil_vector_by_neginf(x); minlmcreatev(2, x, 0.0001, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_fvec); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); // // restart optimizer using minlmrestartfrom() // // we can use different starting point, different function, // different stopping conditions, but problem size // must remain unchanged. // x = "[4,4]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(x); if( _spoil_scenario==13 ) spoil_vector_by_posinf(x); if( _spoil_scenario==14 ) spoil_vector_by_neginf(x); minlmrestartfrom(state, x); alglib::minlmoptimize(state, function2_fvec); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_real_vector(x, "[0,1]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_d_restarts"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_t_1 // Nonlinear least squares optimization, FJ scheme (obsolete, but supported) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatefj(2, x, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_func, function1_jac); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_t_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minlm_t_2 // Nonlinear least squares optimization, FGJ scheme (obsolete, but supported) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { real_1d_array x = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); double epsg = 0.0000000001; if( _spoil_scenario==3 ) epsg = fp_nan; if( _spoil_scenario==4 ) epsg = fp_posinf; if( _spoil_scenario==5 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==6 ) epsf = fp_nan; if( _spoil_scenario==7 ) epsf = fp_posinf; if( _spoil_scenario==8 ) epsf = fp_neginf; double epsx = 0; if( _spoil_scenario==9 ) epsx = fp_nan; if( _spoil_scenario==10 ) epsx = fp_posinf; if( _spoil_scenario==11 ) epsx = fp_neginf; ae_int_t maxits = 0; minlmstate state; minlmreport rep; minlmcreatefgj(2, x, state); minlmsetcond(state, epsg, epsf, epsx, maxits); alglib::minlmoptimize(state, function1_func, function1_grad, function1_jac); minlmresults(state, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[-3,+3]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minlm_t_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_nlf // Nonlinear fitting using function value only // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<27; _spoil_scenario++) { try { // // In this example we demonstrate exponential fitting // by f(x) = exp(-c*x^2) // using function value only. // // Gradient is estimated using combination of numerical differences // and secant updates. diffstep variable stores differentiation step // (we have to tell algorithm what step to use). // real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array c = "[0.3]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(c); if( _spoil_scenario==11 ) spoil_vector_by_posinf(c); if( _spoil_scenario==12 ) spoil_vector_by_neginf(c); double epsf = 0; if( _spoil_scenario==13 ) epsf = fp_nan; if( _spoil_scenario==14 ) epsf = fp_posinf; if( _spoil_scenario==15 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==16 ) epsx = fp_nan; if( _spoil_scenario==17 ) epsx = fp_posinf; if( _spoil_scenario==18 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t info; lsfitstate state; lsfitreport rep; double diffstep = 0.0001; if( _spoil_scenario==19 ) diffstep = fp_nan; if( _spoil_scenario==20 ) diffstep = fp_posinf; if( _spoil_scenario==21 ) diffstep = fp_neginf; // // Fitting without weights // lsfitcreatef(x, y, c, diffstep, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); // // Fitting with weights // (you can change weights and see how it changes result) // real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]"; if( _spoil_scenario==22 ) spoil_vector_by_nan(w); if( _spoil_scenario==23 ) spoil_vector_by_posinf(w); if( _spoil_scenario==24 ) spoil_vector_by_neginf(w); if( _spoil_scenario==25 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==26 ) spoil_vector_by_deleting_element(w); lsfitcreatewf(x, y, w, c, diffstep, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_nlf"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_nlfg // Nonlinear fitting using gradient // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<24; _spoil_scenario++) { try { // // In this example we demonstrate exponential fitting // by f(x) = exp(-c*x^2) // using function value and gradient (with respect to c). // real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array c = "[0.3]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(c); if( _spoil_scenario==11 ) spoil_vector_by_posinf(c); if( _spoil_scenario==12 ) spoil_vector_by_neginf(c); double epsf = 0; if( _spoil_scenario==13 ) epsf = fp_nan; if( _spoil_scenario==14 ) epsf = fp_posinf; if( _spoil_scenario==15 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==16 ) epsx = fp_nan; if( _spoil_scenario==17 ) epsx = fp_posinf; if( _spoil_scenario==18 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t info; lsfitstate state; lsfitreport rep; // // Fitting without weights // lsfitcreatefg(x, y, c, true, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); // // Fitting with weights // (you can change weights and see how it changes result) // real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(w); if( _spoil_scenario==20 ) spoil_vector_by_posinf(w); if( _spoil_scenario==21 ) spoil_vector_by_neginf(w); if( _spoil_scenario==22 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==23 ) spoil_vector_by_deleting_element(w); lsfitcreatewfg(x, y, w, c, true, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_nlfg"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_nlfgh // Nonlinear fitting using gradient and Hessian // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<24; _spoil_scenario++) { try { // // In this example we demonstrate exponential fitting // by f(x) = exp(-c*x^2) // using function value, gradient and Hessian (with respect to c) // real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array c = "[0.3]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(c); if( _spoil_scenario==11 ) spoil_vector_by_posinf(c); if( _spoil_scenario==12 ) spoil_vector_by_neginf(c); double epsf = 0; if( _spoil_scenario==13 ) epsf = fp_nan; if( _spoil_scenario==14 ) epsf = fp_posinf; if( _spoil_scenario==15 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==16 ) epsx = fp_nan; if( _spoil_scenario==17 ) epsx = fp_posinf; if( _spoil_scenario==18 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t info; lsfitstate state; lsfitreport rep; // // Fitting without weights // lsfitcreatefgh(x, y, c, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad, function_cx_1_hess); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); // // Fitting with weights // (you can change weights and see how it changes result) // real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(w); if( _spoil_scenario==20 ) spoil_vector_by_posinf(w); if( _spoil_scenario==21 ) spoil_vector_by_neginf(w); if( _spoil_scenario==22 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==23 ) spoil_vector_by_deleting_element(w); lsfitcreatewfgh(x, y, w, c, state); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad, function_cx_1_hess); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[1.5]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_nlfgh"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_nlfb // Bound contstrained nonlinear fitting using function value only // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<26; _spoil_scenario++) { try { // // In this example we demonstrate exponential fitting by // f(x) = exp(-c*x^2) // subject to bound constraints // 0.0 <= c <= 1.0 // using function value only. // // Gradient is estimated using combination of numerical differences // and secant updates. diffstep variable stores differentiation step // (we have to tell algorithm what step to use). // // Unconstrained solution is c=1.5, but because of constraints we should // get c=1.0 (at the boundary). // real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array c = "[0.3]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(c); if( _spoil_scenario==11 ) spoil_vector_by_posinf(c); if( _spoil_scenario==12 ) spoil_vector_by_neginf(c); real_1d_array bndl = "[0.0]"; if( _spoil_scenario==13 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==14 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[1.0]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==16 ) spoil_vector_by_deleting_element(bndu); double epsf = 0; if( _spoil_scenario==17 ) epsf = fp_nan; if( _spoil_scenario==18 ) epsf = fp_posinf; if( _spoil_scenario==19 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==20 ) epsx = fp_nan; if( _spoil_scenario==21 ) epsx = fp_posinf; if( _spoil_scenario==22 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t info; lsfitstate state; lsfitreport rep; double diffstep = 0.0001; if( _spoil_scenario==23 ) diffstep = fp_nan; if( _spoil_scenario==24 ) diffstep = fp_posinf; if( _spoil_scenario==25 ) diffstep = fp_neginf; lsfitcreatef(x, y, c, diffstep, state); lsfitsetbc(state, bndl, bndu); lsfitsetcond(state, epsf, epsx, maxits); alglib::lsfitfit(state, function_cx_1_func); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_real_vector(c, "[1.0]", 0.05); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_nlfb"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_nlscale // Nonlinear fitting with custom scaling and bound constraints // printf("100/145\n"); _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<30; _spoil_scenario++) { try { // // In this example we demonstrate fitting by // f(x) = c[0]*(1+c[1]*((x-1999)^c[2]-1)) // subject to bound constraints // -INF < c[0] < +INF // -10 <= c[1] <= +10 // 0.1 <= c[2] <= 2.0 // Data we want to fit are time series of Japan national debt // collected from 2000 to 2008 measured in USD (dollars, not // millions of dollars). // // Our variables are: // c[0] - debt value at initial moment (2000), // c[1] - direction coefficient (growth or decrease), // c[2] - curvature coefficient. // You may see that our variables are badly scaled - first one // is order of 10^12, and next two are somewhere about 1 in // magnitude. Such problem is difficult to solve without some // kind of scaling. // That is exactly where lsfitsetscale() function can be used. // We set scale of our variables to [1.0E12, 1, 1], which allows // us to easily solve this problem. // // You can try commenting out lsfitsetscale() call - and you will // see that algorithm will fail to converge. // real_2d_array x = "[[2000],[2001],[2002],[2003],[2004],[2005],[2006],[2007],[2008]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); real_1d_array y = "[4323239600000.0, 4560913100000.0, 5564091500000.0, 6743189300000.0, 7284064600000.0, 7050129600000.0, 7092221500000.0, 8483907600000.0, 8625804400000.0]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array c = "[1.0e+13, 1, 1]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(c); if( _spoil_scenario==11 ) spoil_vector_by_posinf(c); if( _spoil_scenario==12 ) spoil_vector_by_neginf(c); double epsf = 0; if( _spoil_scenario==13 ) epsf = fp_nan; if( _spoil_scenario==14 ) epsf = fp_posinf; if( _spoil_scenario==15 ) epsf = fp_neginf; double epsx = 1.0e-5; if( _spoil_scenario==16 ) epsx = fp_nan; if( _spoil_scenario==17 ) epsx = fp_posinf; if( _spoil_scenario==18 ) epsx = fp_neginf; real_1d_array bndl = "[-inf, -10, 0.1]"; if( _spoil_scenario==19 ) spoil_vector_by_nan(bndl); if( _spoil_scenario==20 ) spoil_vector_by_deleting_element(bndl); real_1d_array bndu = "[+inf, +10, 2.0]"; if( _spoil_scenario==21 ) spoil_vector_by_nan(bndu); if( _spoil_scenario==22 ) spoil_vector_by_deleting_element(bndu); real_1d_array s = "[1.0e+12, 1, 1]"; if( _spoil_scenario==23 ) spoil_vector_by_nan(s); if( _spoil_scenario==24 ) spoil_vector_by_posinf(s); if( _spoil_scenario==25 ) spoil_vector_by_neginf(s); if( _spoil_scenario==26 ) spoil_vector_by_deleting_element(s); ae_int_t maxits = 0; ae_int_t info; lsfitstate state; lsfitreport rep; double diffstep = 1.0e-5; if( _spoil_scenario==27 ) diffstep = fp_nan; if( _spoil_scenario==28 ) diffstep = fp_posinf; if( _spoil_scenario==29 ) diffstep = fp_neginf; lsfitcreatef(x, y, c, diffstep, state); lsfitsetcond(state, epsf, epsx, maxits); lsfitsetbc(state, bndl, bndu); lsfitsetscale(state, s); alglib::lsfitfit(state, function_debt_func); lsfitresults(state, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 2); _TestResult = _TestResult && doc_test_real_vector(c, "[4.142560e+12, 0.434240, 0.565376]", -0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_nlscale"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_lin // Unconstrained (general) linear least squares fitting with and without weights // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<13; _spoil_scenario++) { try { // // In this example we demonstrate linear fitting by f(x|a) = a*exp(0.5*x). // // We have: // * y - vector of experimental data // * fmatrix - matrix of basis functions calculated at sample points // Actually, we have only one basis function F0 = exp(0.5*x). // real_2d_array fmatrix = "[[0.606531],[0.670320],[0.740818],[0.818731],[0.904837],[1.000000],[1.105171],[1.221403],[1.349859],[1.491825],[1.648721]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(fmatrix); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(fmatrix); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(fmatrix); real_1d_array y = "[1.133719, 1.306522, 1.504604, 1.554663, 1.884638, 2.072436, 2.257285, 2.534068, 2.622017, 2.897713, 3.219371]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(y); if( _spoil_scenario==4 ) spoil_vector_by_posinf(y); if( _spoil_scenario==5 ) spoil_vector_by_neginf(y); if( _spoil_scenario==6 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); ae_int_t info; real_1d_array c; lsfitreport rep; // // Linear fitting without weights // lsfitlinear(y, fmatrix, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_vector(c, "[1.98650]", 0.00005); // // Linear fitting with individual weights. // Slightly different result is returned. // real_1d_array w = "[1.414213, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(w); if( _spoil_scenario==9 ) spoil_vector_by_posinf(w); if( _spoil_scenario==10 ) spoil_vector_by_neginf(w); if( _spoil_scenario==11 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==12 ) spoil_vector_by_deleting_element(w); lsfitlinearw(y, w, fmatrix, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_vector(c, "[1.983354]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_lin"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_linc // Constrained (general) linear least squares fitting with and without weights // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<20; _spoil_scenario++) { try { // // In this example we demonstrate linear fitting by f(x|a,b) = a*x+b // with simple constraint f(0)=0. // // We have: // * y - vector of experimental data // * fmatrix - matrix of basis functions sampled at [0,1] with step 0.2: // [ 1.0 0.0 ] // [ 1.0 0.2 ] // [ 1.0 0.4 ] // [ 1.0 0.6 ] // [ 1.0 0.8 ] // [ 1.0 1.0 ] // first column contains value of first basis function (constant term) // second column contains second basis function (linear term) // * cmatrix - matrix of linear constraints: // [ 1.0 0.0 0.0 ] // first two columns contain coefficients before basis functions, // last column contains desired value of their sum. // So [1,0,0] means "1*constant_term + 0*linear_term = 0" // real_1d_array y = "[0.072436,0.246944,0.491263,0.522300,0.714064,0.921929]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(y); if( _spoil_scenario==1 ) spoil_vector_by_posinf(y); if( _spoil_scenario==2 ) spoil_vector_by_neginf(y); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(y); real_2d_array fmatrix = "[[1,0.0],[1,0.2],[1,0.4],[1,0.6],[1,0.8],[1,1.0]]"; if( _spoil_scenario==5 ) spoil_matrix_by_nan(fmatrix); if( _spoil_scenario==6 ) spoil_matrix_by_posinf(fmatrix); if( _spoil_scenario==7 ) spoil_matrix_by_neginf(fmatrix); if( _spoil_scenario==8 ) spoil_matrix_by_adding_row(fmatrix); if( _spoil_scenario==9 ) spoil_matrix_by_adding_col(fmatrix); if( _spoil_scenario==10 ) spoil_matrix_by_deleting_row(fmatrix); if( _spoil_scenario==11 ) spoil_matrix_by_deleting_col(fmatrix); real_2d_array cmatrix = "[[1,0,0]]"; if( _spoil_scenario==12 ) spoil_matrix_by_nan(cmatrix); if( _spoil_scenario==13 ) spoil_matrix_by_posinf(cmatrix); if( _spoil_scenario==14 ) spoil_matrix_by_neginf(cmatrix); ae_int_t info; real_1d_array c; lsfitreport rep; // // Constrained fitting without weights // lsfitlinearc(y, fmatrix, cmatrix, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_vector(c, "[0,0.932933]", 0.0005); // // Constrained fitting with individual weights // real_1d_array w = "[1, 1.414213, 1, 1, 1, 1]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(w); if( _spoil_scenario==16 ) spoil_vector_by_posinf(w); if( _spoil_scenario==17 ) spoil_vector_by_neginf(w); if( _spoil_scenario==18 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==19 ) spoil_vector_by_deleting_element(w); lsfitlinearwc(y, w, fmatrix, cmatrix, info, c, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && doc_test_real_vector(c, "[0,0.938322]", 0.0005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_linc"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_pol // Unconstrained polynomial fitting // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<20; _spoil_scenario++) { try { // // This example demonstrates polynomial fitting. // // Fitting is done by two (M=2) functions from polynomial basis: // f0 = 1 // f1 = x // Basically, it just a linear fit; more complex polynomials may be used // (e.g. parabolas with M=3, cubic with M=4), but even such simple fit allows // us to demonstrate polynomialfit() function in action. // // We have: // * x set of abscissas // * y experimental data // // Additionally we demonstrate weighted fitting, where second point has // more weight than other ones. // real_1d_array x = "[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.00,0.05,0.26,0.32,0.33,0.43,0.60,0.60,0.77,0.98,1.02]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); ae_int_t m = 2; double t = 2; if( _spoil_scenario==10 ) t = fp_posinf; if( _spoil_scenario==11 ) t = fp_neginf; ae_int_t info; barycentricinterpolant p; polynomialfitreport rep; double v; // // Fitting without individual weights // // NOTE: result is returned as barycentricinterpolant structure. // if you want to get representation in the power basis, // you can use barycentricbar2pow() function to convert // from barycentric to power representation (see docs for // POLINT subpackage for more info). // polynomialfit(x, y, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.011, 0.002); // // Fitting with individual weights // // NOTE: slightly different result is returned // real_1d_array w = "[1,1.414213562,1,1,1,1,1,1,1,1,1]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(w); if( _spoil_scenario==13 ) spoil_vector_by_posinf(w); if( _spoil_scenario==14 ) spoil_vector_by_neginf(w); if( _spoil_scenario==15 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==16 ) spoil_vector_by_deleting_element(w); real_1d_array xc = "[]"; if( _spoil_scenario==17 ) spoil_vector_by_adding_element(xc); real_1d_array yc = "[]"; if( _spoil_scenario==18 ) spoil_vector_by_adding_element(yc); integer_1d_array dc = "[]"; if( _spoil_scenario==19 ) spoil_vector_by_adding_element(dc); polynomialfitwc(x, y, w, xc, yc, dc, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.023, 0.002); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_pol"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_polc // Constrained polynomial fitting // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<29; _spoil_scenario++) { try { // // This example demonstrates polynomial fitting. // // Fitting is done by two (M=2) functions from polynomial basis: // f0 = 1 // f1 = x // with simple constraint on function value // f(0) = 0 // Basically, it just a linear fit; more complex polynomials may be used // (e.g. parabolas with M=3, cubic with M=4), but even such simple fit allows // us to demonstrate polynomialfit() function in action. // // We have: // * x set of abscissas // * y experimental data // * xc points where constraints are placed // * yc constraints on derivatives // * dc derivative indices // (0 means function itself, 1 means first derivative) // real_1d_array x = "[1.0,1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.9,1.1]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); real_1d_array w = "[1,1]"; if( _spoil_scenario==10 ) spoil_vector_by_nan(w); if( _spoil_scenario==11 ) spoil_vector_by_posinf(w); if( _spoil_scenario==12 ) spoil_vector_by_neginf(w); if( _spoil_scenario==13 ) spoil_vector_by_adding_element(w); if( _spoil_scenario==14 ) spoil_vector_by_deleting_element(w); real_1d_array xc = "[0]"; if( _spoil_scenario==15 ) spoil_vector_by_nan(xc); if( _spoil_scenario==16 ) spoil_vector_by_posinf(xc); if( _spoil_scenario==17 ) spoil_vector_by_neginf(xc); if( _spoil_scenario==18 ) spoil_vector_by_adding_element(xc); if( _spoil_scenario==19 ) spoil_vector_by_deleting_element(xc); real_1d_array yc = "[0]"; if( _spoil_scenario==20 ) spoil_vector_by_nan(yc); if( _spoil_scenario==21 ) spoil_vector_by_posinf(yc); if( _spoil_scenario==22 ) spoil_vector_by_neginf(yc); if( _spoil_scenario==23 ) spoil_vector_by_adding_element(yc); if( _spoil_scenario==24 ) spoil_vector_by_deleting_element(yc); integer_1d_array dc = "[0]"; if( _spoil_scenario==25 ) spoil_vector_by_adding_element(dc); if( _spoil_scenario==26 ) spoil_vector_by_deleting_element(dc); double t = 2; if( _spoil_scenario==27 ) t = fp_posinf; if( _spoil_scenario==28 ) t = fp_neginf; ae_int_t m = 2; ae_int_t info; barycentricinterpolant p; polynomialfitreport rep; double v; polynomialfitwc(x, y, w, xc, yc, dc, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.000, 0.001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_polc"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_d_spline // Unconstrained fitting by penalized regression spline // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<19; _spoil_scenario++) { try { // // In this example we demonstrate penalized spline fitting of noisy data // // We have: // * x - abscissas // * y - vector of experimental data, straight line with small noise // real_1d_array x = "[0.00,0.10,0.20,0.30,0.40,0.50,0.60,0.70,0.80,0.90]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_adding_element(x); if( _spoil_scenario==4 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.10,0.00,0.30,0.40,0.30,0.40,0.62,0.68,0.75,0.95]"; if( _spoil_scenario==5 ) spoil_vector_by_nan(y); if( _spoil_scenario==6 ) spoil_vector_by_posinf(y); if( _spoil_scenario==7 ) spoil_vector_by_neginf(y); if( _spoil_scenario==8 ) spoil_vector_by_adding_element(y); if( _spoil_scenario==9 ) spoil_vector_by_deleting_element(y); ae_int_t info; double v; spline1dinterpolant s; spline1dfitreport rep; double rho; // // Fit with VERY small amount of smoothing (rho = -5.0) // and large number of basis functions (M=50). // // With such small regularization penalized spline almost fully reproduces function values // rho = -5.0; if( _spoil_scenario==10 ) rho = fp_nan; if( _spoil_scenario==11 ) rho = fp_posinf; if( _spoil_scenario==12 ) rho = fp_neginf; spline1dfitpenalized(x, y, 50, rho, info, s, rep); _TestResult = _TestResult && doc_test_int(info, 1); v = spline1dcalc(s, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.10, 0.01); // // Fit with VERY large amount of smoothing (rho = 10.0) // and large number of basis functions (M=50). // // With such regularization our spline should become close to the straight line fit. // We will compare its value in x=1.0 with results obtained from such fit. // rho = +10.0; if( _spoil_scenario==13 ) rho = fp_nan; if( _spoil_scenario==14 ) rho = fp_posinf; if( _spoil_scenario==15 ) rho = fp_neginf; spline1dfitpenalized(x, y, 50, rho, info, s, rep); _TestResult = _TestResult && doc_test_int(info, 1); v = spline1dcalc(s, 1.0); _TestResult = _TestResult && doc_test_real(v, 0.969, 0.001); // // In real life applications you may need some moderate degree of fitting, // so we try to fit once more with rho=3.0. // rho = +3.0; if( _spoil_scenario==16 ) rho = fp_nan; if( _spoil_scenario==17 ) rho = fp_posinf; if( _spoil_scenario==18 ) rho = fp_neginf; spline1dfitpenalized(x, y, 50, rho, info, s, rep); _TestResult = _TestResult && doc_test_int(info, 1); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_d_spline"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_t_polfit_1 // Polynomial fitting, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<10; _spoil_scenario++) { try { real_1d_array x = "[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.00,0.05,0.26,0.32,0.33,0.43,0.60,0.60,0.77,0.98,1.02]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); ae_int_t m = 2; double t = 2; if( _spoil_scenario==8 ) t = fp_posinf; if( _spoil_scenario==9 ) t = fp_neginf; ae_int_t info; barycentricinterpolant p; polynomialfitreport rep; double v; polynomialfit(x, y, 11, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.011, 0.002); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_t_polfit_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_t_polfit_2 // Polynomial fitting, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<14; _spoil_scenario++) { try { real_1d_array x = "[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.00,0.05,0.26,0.32,0.33,0.43,0.60,0.60,0.77,0.98,1.02]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array w = "[1,1.414213562,1,1,1,1,1,1,1,1,1]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(w); if( _spoil_scenario==9 ) spoil_vector_by_posinf(w); if( _spoil_scenario==10 ) spoil_vector_by_neginf(w); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(w); real_1d_array xc = "[]"; real_1d_array yc = "[]"; integer_1d_array dc = "[]"; ae_int_t m = 2; double t = 2; if( _spoil_scenario==12 ) t = fp_posinf; if( _spoil_scenario==13 ) t = fp_neginf; ae_int_t info; barycentricinterpolant p; polynomialfitreport rep; double v; polynomialfitwc(x, y, w, 11, xc, yc, dc, 0, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.023, 0.002); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_t_polfit_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_t_polfit_3 // Polynomial fitting, full list of parameters. // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<23; _spoil_scenario++) { try { real_1d_array x = "[1.0,1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.9,1.1]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array w = "[1,1]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(w); if( _spoil_scenario==9 ) spoil_vector_by_posinf(w); if( _spoil_scenario==10 ) spoil_vector_by_neginf(w); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(w); real_1d_array xc = "[0]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(xc); if( _spoil_scenario==13 ) spoil_vector_by_posinf(xc); if( _spoil_scenario==14 ) spoil_vector_by_neginf(xc); if( _spoil_scenario==15 ) spoil_vector_by_deleting_element(xc); real_1d_array yc = "[0]"; if( _spoil_scenario==16 ) spoil_vector_by_nan(yc); if( _spoil_scenario==17 ) spoil_vector_by_posinf(yc); if( _spoil_scenario==18 ) spoil_vector_by_neginf(yc); if( _spoil_scenario==19 ) spoil_vector_by_deleting_element(yc); integer_1d_array dc = "[0]"; if( _spoil_scenario==20 ) spoil_vector_by_deleting_element(dc); ae_int_t m = 2; double t = 2; if( _spoil_scenario==21 ) t = fp_posinf; if( _spoil_scenario==22 ) t = fp_neginf; ae_int_t info; barycentricinterpolant p; polynomialfitreport rep; double v; polynomialfitwc(x, y, w, 2, xc, yc, dc, 1, m, info, p, rep); v = barycentriccalc(p, t); _TestResult = _TestResult && doc_test_real(v, 2.000, 0.001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_t_polfit_3"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_t_4pl // 4-parameter logistic fitting // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<8; _spoil_scenario++) { try { real_1d_array x = "[1,2,3,4,5,6,7,8]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.06313223,0.44552624,0.61838364,0.71385108,0.77345838,0.81383140,0.84280033,0.86449822]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); ae_int_t n = 8; double a; double b; double c; double d; lsfitreport rep; // // Test logisticfit4() on carefully designed data with a priori known answer. // logisticfit4(x, y, n, a, b, c, d, rep); _TestResult = _TestResult && doc_test_real(a, -1.000, 0.01); _TestResult = _TestResult && doc_test_real(b, 1.200, 0.01); _TestResult = _TestResult && doc_test_real(c, 0.900, 0.01); _TestResult = _TestResult && doc_test_real(d, 1.000, 0.01); // // Evaluate model at point x=0.5 // double v; v = logisticcalc4(0.5, a, b, c, d); _TestResult = _TestResult && doc_test_real(v, -0.33874308, 0.001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_t_4pl"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lsfit_t_5pl // 5-parameter logistic fitting // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<8; _spoil_scenario++) { try { real_1d_array x = "[1,2,3,4,5,6,7,8]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.1949776139,0.5710060208,0.726002637,0.8060434158,0.8534547965,0.8842071579,0.9054773317,0.9209088299]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); ae_int_t n = 8; double a; double b; double c; double d; double g; lsfitreport rep; // // Test logisticfit5() on carefully designed data with a priori known answer. // logisticfit5(x, y, n, a, b, c, d, g, rep); _TestResult = _TestResult && doc_test_real(a, -1.000, 0.01); _TestResult = _TestResult && doc_test_real(b, 1.200, 0.01); _TestResult = _TestResult && doc_test_real(c, 0.900, 0.01); _TestResult = _TestResult && doc_test_real(d, 1.000, 0.01); _TestResult = _TestResult && doc_test_real(g, 1.200, 0.01); // // Evaluate model at point x=0.5 // double v; v = logisticcalc5(0.5, a, b, c, d, g); _TestResult = _TestResult && doc_test_real(v, -0.2354656824, 0.001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lsfit_t_5pl"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST parametric_rdp // Parametric Ramer-Douglas-Peucker approximation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { // // We use RDP algorithm to approximate parametric 2D curve given by // locations in t=0,1,2,3 (see below), which form piecewise linear // trajectory through D-dimensional space (2-dimensional in our example). // // | // | // - * * X2................X3 // | . // | . // - * * . * * * * // | . // | . // - * X1 * * * * // | ..... // | .... // X0----|-----|-----|-----|-----|-----|--- // ae_int_t npoints = 4; ae_int_t ndimensions = 2; real_2d_array x = "[[0,0],[2,1],[3,3],[6,3]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(x); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(x); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(x); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(x); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(x); // // Approximation of parametric curve is performed by another parametric curve // with lesser amount of points. It allows to work with "compressed" // representation, which needs smaller amount of memory. Say, in our example // (we allow points with error smaller than 0.8) approximation will have // just two sequential sections connecting X0 with X2, and X2 with X3. // // | // | // - * * X2................X3 // | . // | . // - * . * * * * // | . // | . // - . X1 * * * * // | . // | . // X0----|-----|-----|-----|-----|-----|--- // // real_2d_array y; integer_1d_array idxy; ae_int_t nsections; ae_int_t limitcnt = 0; double limiteps = 0.8; if( _spoil_scenario==5 ) limiteps = fp_posinf; if( _spoil_scenario==6 ) limiteps = fp_neginf; parametricrdpfixed(x, npoints, ndimensions, limitcnt, limiteps, y, idxy, nsections); _TestResult = _TestResult && doc_test_int(nsections, 2); _TestResult = _TestResult && doc_test_int_vector(idxy, "[0,2,3]"); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "parametric_rdp"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST linlsqr_d_1 // Solution of sparse linear systems with CG // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<4; _spoil_scenario++) { try { // // This example illustrates solution of sparse linear least squares problem // with LSQR algorithm. // // Suppose that we have least squares problem min|A*x-b| with sparse A // represented by sparsematrix object // [ 1 1 ] // [ 1 1 ] // A = [ 2 1 ] // [ 1 ] // [ 1 ] // and right part b // [ 4 ] // [ 2 ] // b = [ 4 ] // [ 1 ] // [ 2 ] // and we want to solve this system in the least squares sense using // LSQR algorithm. In order to do so, we have to create left part // (sparsematrix object) and right part (dense array). // // Initially, sparse matrix is created in the Hash-Table format, // which allows easy initialization, but do not allow matrix to be // used in the linear solvers. So after construction you should convert // sparse matrix to CRS format (one suited for linear operations). // sparsematrix a; sparsecreate(5, 2, a); sparseset(a, 0, 0, 1.0); sparseset(a, 0, 1, 1.0); sparseset(a, 1, 0, 1.0); sparseset(a, 1, 1, 1.0); sparseset(a, 2, 0, 2.0); sparseset(a, 2, 1, 1.0); sparseset(a, 3, 0, 1.0); sparseset(a, 4, 1, 1.0); // // Now our matrix is fully initialized, but we have to do one more // step - convert it from Hash-Table format to CRS format (see // documentation on sparse matrices for more information about these // formats). // // If you omit this call, ALGLIB will generate exception on the first // attempt to use A in linear operations. // sparseconverttocrs(a); // // Initialization of the right part // real_1d_array b = "[4,2,4,1,2]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(b); if( _spoil_scenario==1 ) spoil_vector_by_posinf(b); if( _spoil_scenario==2 ) spoil_vector_by_neginf(b); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(b); // // Now we have to create linear solver object and to use it for the // solution of the linear system. // linlsqrstate s; linlsqrreport rep; real_1d_array x; linlsqrcreate(5, 2, s); linlsqrsolvesparse(s, a, b); linlsqrresults(s, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 4); _TestResult = _TestResult && doc_test_real_vector(x, "[1.000,2.000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "linlsqr_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_qnn // Simple model built with RBF-QNN algorithm // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example illustrates basic concepts of the RBF models: creation, modification, // evaluation. // // Suppose that we have set of 2-dimensional points with associated // scalar function values, and we want to build a RBF model using // our data. // // NOTE: we can work with 3D models too :) // // Typical sequence of steps is given below: // 1. we create RBF model object // 2. we attach our dataset to the RBF model and tune algorithm settings // 3. we rebuild RBF model using QNN algorithm on new data // 4. we use RBF model (evaluate, serialize, etc.) // double v; // // Step 1: RBF model creation. // // We have to specify dimensionality of the space (2 or 3) and // dimensionality of the function (scalar or vector). // rbfmodel model; rbfcreate(2, 1, model); // New model is empty - it can be evaluated, // but we just get zero value at any point. v = rbfcalc2(model, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.000, 0.005); // // Step 2: we add dataset. // // XY arrays containt two points - x0=(-1,0) and x1=(+1,0) - // and two function values f(x0)=2, f(x1)=3. // real_2d_array xy = "[[-1,0,2],[+1,0,3]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); rbfsetpoints(model, xy); // We added points, but model was not rebuild yet. // If we call rbfcalc2(), we still will get 0.0 as result. v = rbfcalc2(model, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.000, 0.005); // // Step 3: rebuild model // // After we've configured model, we should rebuild it - // it will change coefficients stored internally in the // rbfmodel structure. // // By default, RBF uses QNN algorithm, which works well with // relatively uniform datasets (all points are well separated, // average distance is approximately same for all points). // This default algorithm is perfectly suited for our simple // made up data. // // NOTE: we recommend you to take a look at example of RBF-ML, // multilayer RBF algorithm, which sometimes is a better // option than QNN. // rbfreport rep; rbfsetalgoqnn(model); rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); // // Step 4: model was built // // After call of rbfbuildmodel(), rbfcalc2() will return // value of the new model. // v = rbfcalc2(model, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_qnn"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_vector // Working with vector functions // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { // // Suppose that we have set of 2-dimensional points with associated VECTOR // function values, and we want to build a RBF model using our data. // // Typical sequence of steps is given below: // 1. we create RBF model object // 2. we attach our dataset to the RBF model and tune algorithm settings // 3. we rebuild RBF model using new data // 4. we use RBF model (evaluate, serialize, etc.) // real_1d_array x; real_1d_array y; // // Step 1: RBF model creation. // // We have to specify dimensionality of the space (equal to 2) and // dimensionality of the function (2-dimensional vector function). // rbfmodel model; rbfcreate(2, 2, model); // New model is empty - it can be evaluated, // but we just get zero value at any point. x = "[+1,+1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); rbfcalc(model, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,0.000]", 0.005); // // Step 2: we add dataset. // // XY arrays containt four points: // * (x0,y0) = (+1,+1), f(x0,y0)=(0,-1) // * (x1,y1) = (+1,-1), f(x1,y1)=(-1,0) // * (x2,y2) = (-1,-1), f(x2,y2)=(0,+1) // * (x3,y3) = (-1,+1), f(x3,y3)=(+1,0) // // By default, RBF uses QNN algorithm, which works well with // relatively uniform datasets (all points are well separated, // average distance is approximately same for all points). // // This default algorithm is perfectly suited for our simple // made up data. // real_2d_array xy = "[[+1,+1,0,-1],[+1,-1,-1,0],[-1,-1,0,+1],[-1,+1,+1,0]]"; if( _spoil_scenario==3 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==4 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==5 ) spoil_matrix_by_neginf(xy); rbfsetpoints(model, xy); // We added points, but model was not rebuild yet. // If we call rbfcalc(), we still will get 0.0 as result. rbfcalc(model, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,0.000]", 0.005); // // Step 3: rebuild model // // After we've configured model, we should rebuild it - // it will change coefficients stored internally in the // rbfmodel structure. // rbfreport rep; rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); // // Step 4: model was built // // After call of rbfbuildmodel(), rbfcalc() will return // value of the new model. // rbfcalc(model, x, y); _TestResult = _TestResult && doc_test_real_vector(y, "[0.000,-1.000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_vector"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_polterm // RBF models - working with polynomial term // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example show how to work with polynomial term // // Suppose that we have set of 2-dimensional points with associated // scalar function values, and we want to build a RBF model using // our data. // double v; rbfmodel model; real_2d_array xy = "[[-1,0,2],[+1,0,3]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); rbfreport rep; rbfcreate(2, 1, model); rbfsetpoints(model, xy); rbfsetalgoqnn(model); // // By default, RBF model uses linear term. It means that model // looks like // f(x,y) = SUM(RBF[i]) + a*x + b*y + c // where RBF[i] is I-th radial basis function and a*x+by+c is a // linear term. Having linear terms in a model gives us: // (1) improved extrapolation properties // (2) linearity of the model when data can be perfectly fitted // by the linear function // (3) linear asymptotic behavior // // Our simple dataset can be modelled by the linear function // f(x,y) = 0.5*x + 2.5 // and rbfbuildmodel() with default settings should preserve this // linearity. // ae_int_t nx; ae_int_t ny; ae_int_t nc; real_2d_array xwr; real_2d_array c; rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); rbfunpack(model, nx, ny, xwr, nc, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0.500,0.000,2.500]]", 0.005); // asymptotic behavior of our function is linear v = rbfcalc2(model, 1000.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 502.50, 0.05); // // Instead of linear term we can use constant term. In this case // we will get model which has form // f(x,y) = SUM(RBF[i]) + c // where RBF[i] is I-th radial basis function and c is a constant, // which is equal to the average function value on the dataset. // // Because we've already attached dataset to the model the only // thing we have to do is to call rbfsetconstterm() and then // rebuild model with rbfbuildmodel(). // rbfsetconstterm(model); rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); rbfunpack(model, nx, ny, xwr, nc, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0.000,0.000,2.500]]", 0.005); // asymptotic behavior of our function is constant v = rbfcalc2(model, 1000.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.005); // // Finally, we can use zero term. Just plain RBF without polynomial // part: // f(x,y) = SUM(RBF[i]) // where RBF[i] is I-th radial basis function. // rbfsetzeroterm(model); rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); rbfunpack(model, nx, ny, xwr, nc, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0.000,0.000,0.000]]", 0.005); // asymptotic behavior of our function is just zero constant v = rbfcalc2(model, 1000.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.000, 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_polterm"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_serialize // Serialization/unserialization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example show how to serialize and unserialize RBF model // // Suppose that we have set of 2-dimensional points with associated // scalar function values, and we want to build a RBF model using // our data. Then we want to serialize it to string and to unserialize // from string, loading to another instance of RBF model. // // Here we assume that you already know how to create RBF models. // std::string s; double v; rbfmodel model0; rbfmodel model1; real_2d_array xy = "[[-1,0,2],[+1,0,3]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy); rbfreport rep; // model initialization rbfcreate(2, 1, model0); rbfsetpoints(model0, xy); rbfsetalgoqnn(model0); rbfbuildmodel(model0, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); // // Serialization - it looks easy, // but you should carefully read next section. // alglib::rbfserialize(model0, s); alglib::rbfunserialize(s, model1); // both models return same value v = rbfcalc2(model0, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.005); v = rbfcalc2(model1, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.005); // // Previous section shows that model state is saved/restored during // serialization. However, some properties are NOT serialized. // // Serialization saves/restores RBF model, but it does NOT saves/restores // settings which were used to build current model. In particular, dataset // which were used to build model, is not preserved. // // What does it mean in for us? // // Do you remember this sequence: rbfcreate-rbfsetpoints-rbfbuildmodel? // First step creates model, second step adds dataset and tunes model // settings, third step builds model using current dataset and model // construction settings. // // If you call rbfbuildmodel() without calling rbfsetpoints() first, you // will get empty (zero) RBF model. In our example, model0 contains // dataset which was added by rbfsetpoints() call. However, model1 does // NOT contain dataset - because dataset is NOT serialized. // // This, if we call rbfbuildmodel(model0,rep), we will get same model, // which returns 2.5 at (x,y)=(0,0). However, after same call model1 will // return zero - because it contains RBF model (coefficients), but does NOT // contain dataset which was used to build this model. // // Basically, it means that: // * serialization of the RBF model preserves anything related to the model // EVALUATION // * but it does NOT creates perfect copy of the original object. // rbfbuildmodel(model0, rep); v = rbfcalc2(model0, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.005); rbfbuildmodel(model1, rep); v = rbfcalc2(model1, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.000, 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_serialize"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_ml_simple // Simple model built with RBF-ML algorithm // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example shows how to build models with RBF-ML algorithm. Below // we assume that you already know basic concepts shown in the example // on RBF-QNN algorithm. // // RBF-ML is a multilayer RBF algorithm, which fits a sequence of models // with decreasing radii. Each model is fitted with fixed number of // iterations of linear solver. First layers give only inexact approximation // of the target function, because RBF problems with large radii are // ill-conditioned. However, as we add more and more layers with smaller // and smaller radii, we get better conditioned systems - and more precise models. // rbfmodel model; rbfreport rep; double v; // // We have 2-dimensional space and very simple interpolation problem - all // points are distinct and located at straight line. We want to solve it // with RBF-ML algorithm. This problem is very simple, and RBF-QNN will // solve it too, but we want to evaluate RBF-ML and to start from the simple // problem. // X Y // -2 1 // -1 0 // 0 1 // +1 -1 // +2 1 // rbfcreate(2, 1, model); real_2d_array xy0 = "[[-2,0,1],[-1,0,0],[0,0,1],[+1,0,-1],[+2,0,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy0); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy0); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy0); rbfsetpoints(model, xy0); // First, we try to use R=5.0 with single layer (NLayers=1) and moderate amount // of regularization.... but results are disappointing: Model(x=0,y=0)=-0.02, // and we need 1.0 at (x,y)=(0,0). Why? // // Because first layer gives very smooth and imprecise approximation of the // function. Average distance between points is 1.0, and R=5.0 is too large // to give us flexible model. It can give smoothness, but can't give precision. // So we need more layers with smaller radii. rbfsetalgomultilayer(model, 5.0, 1, 1.0e-3); rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); v = rbfcalc2(model, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, -0.021690, 0.002); // Now we know that single layer is not enough. We still want to start with // R=5.0 because it has good smoothness properties, but we will add more layers, // each with R[i+1]=R[i]/2. We think that 4 layers is enough, because last layer // will have R = 5.0/2^3 = 5/8 ~ 0.63, which is smaller than the average distance // between points. And it works! rbfsetalgomultilayer(model, 5.0, 4, 1.0e-3); rbfbuildmodel(model, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); v = rbfcalc2(model, 0.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.000000, 0.002); // BTW, if you look at v, you will see that it is equal to 0.9999999997, not to 1. // This small error can be fixed by adding one more layer. _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_ml_simple"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST rbf_d_ml_ls // Least squares problem solved with RBF-ML algorithm // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<3; _spoil_scenario++) { try { // // This example shows how to solve least squares problems with RBF-ML algorithm. // Below we assume that you already know basic concepts shown in the RBF_D_QNN and // RBF_D_ML_SIMPLE examples. // rbfmodel model; rbfreport rep; double v; // // We have 2-dimensional space and very simple fitting problem - all points // except for two are well separated and located at straight line. Two // "exceptional" points are very close, with distance between them as small // as 0.01. RBF-QNN algorithm will have many difficulties with such distribution // of points: // X Y // -2 1 // -1 0 // -0.005 1 // +0.005 2 // +1 -1 // +2 1 // How will RBF-ML handle such problem? // rbfcreate(2, 1, model); real_2d_array xy0 = "[[-2,0,1],[-1,0,0],[-0.005,0,1],[+0.005,0,2],[+1,0,-1],[+2,0,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(xy0); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(xy0); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(xy0); rbfsetpoints(model, xy0); // First, we try to use R=5.0 with single layer (NLayers=1) and moderate amount // of regularization. Well, we already expected that results will be bad: // Model(x=-2,y=0)=0.8407 (instead of 1.0) // Model(x=0.005,y=0)=0.6584 (instead of 2.0) // We need more layers to show better results. rbfsetalgomultilayer(model, 5.0, 1, 1.0e-3); rbfbuildmodel(model, rep); v = rbfcalc2(model, -2.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.8407981659, 0.002); v = rbfcalc2(model, 0.005, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.6584267649, 0.002); // With 4 layers we got better result at x=-2 (point which is well separated // from its neighbors). Model is now many times closer to the original data // Model(x=-2,y=0)=0.9992 (instead of 1.0) // Model(x=0.005,y=0)=1.5534 (instead of 2.0) // We may see that at x=0.005 result is a bit closer to 2.0, but does not // reproduce function value precisely because of close neighbor located at // at x=-0.005. Let's add two layers... rbfsetalgomultilayer(model, 5.0, 4, 1.0e-3); rbfbuildmodel(model, rep); v = rbfcalc2(model, -2.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 0.9992673278, 0.002); v = rbfcalc2(model, 0.005, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.5534666012, 0.002); // With 6 layers we got almost perfect fit: // Model(x=-2,y=0)=1.000 (perfect fit) // Model(x=0.005,y=0)=1.996 (instead of 2.0) // Of course, we can reduce error at x=0.005 down to zero by adding more // layers. But do we really need it? rbfsetalgomultilayer(model, 5.0, 6, 1.0e-3); rbfbuildmodel(model, rep); v = rbfcalc2(model, -2.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.0000000000, 0.002); v = rbfcalc2(model, 0.005, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.9965775952, 0.002); // Do we really need zero error? We have f(+0.005)=2 and f(-0.005)=1. // Two points are very close, and in real life situations it often means // that difference in function values can be explained by noise in the // data. Thus, true value of the underlying function should be close to // 1.5 (halfway between 1.0 and 2.0). // // How can we get such result with RBF-ML? Well, we can: // a) reduce number of layers (make model less flexible) // b) increase regularization coefficient (another way of reducing flexibility) // // Having NLayers=5 and LambdaV=0.1 gives us good least squares fit to the data: // Model(x=-2,y=0)=1.000 // Model(x=-0.005,y=0)=1.504 // Model(x=+0.005,y=0)=1.496 rbfsetalgomultilayer(model, 5.0, 5, 1.0e-1); rbfbuildmodel(model, rep); v = rbfcalc2(model, -2.0, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.0000001620, 0.002); v = rbfcalc2(model, -0.005, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.5042954378, 0.002); v = rbfcalc2(model, 0.005, 0.0); _TestResult = _TestResult && doc_test_real(v, 1.4957042013, 0.002); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "rbf_d_ml_ls"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline2d_bilinear // Bilinear spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // We use bilinear spline to interpolate f(x,y)=x^2+2*y^2 sampled // at (x,y) from [0.0, 0.5, 1.0] X [0.0, 1.0]. // real_1d_array x = "[0.0, 0.5, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array f = "[0.00,0.25,1.00,2.00,2.25,3.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(f); if( _spoil_scenario==9 ) spoil_vector_by_posinf(f); if( _spoil_scenario==10 ) spoil_vector_by_neginf(f); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(f); double vx = 0.25; if( _spoil_scenario==12 ) vx = fp_posinf; if( _spoil_scenario==13 ) vx = fp_neginf; double vy = 0.50; if( _spoil_scenario==14 ) vy = fp_posinf; if( _spoil_scenario==15 ) vy = fp_neginf; double v; spline2dinterpolant s; // build spline spline2dbuildbilinearv(x, 3, y, 2, f, 1, s); // calculate S(0.25,0.50) v = spline2dcalc(s, vx, vy); _TestResult = _TestResult && doc_test_real(v, 1.1250, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline2d_bilinear"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline2d_bicubic // Bilinear spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // We use bilinear spline to interpolate f(x,y)=x^2+2*y^2 sampled // at (x,y) from [0.0, 0.5, 1.0] X [0.0, 1.0]. // real_1d_array x = "[0.0, 0.5, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array f = "[0.00,0.25,1.00,2.00,2.25,3.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(f); if( _spoil_scenario==9 ) spoil_vector_by_posinf(f); if( _spoil_scenario==10 ) spoil_vector_by_neginf(f); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(f); double vx = 0.25; if( _spoil_scenario==12 ) vx = fp_posinf; if( _spoil_scenario==13 ) vx = fp_neginf; double vy = 0.50; if( _spoil_scenario==14 ) vy = fp_posinf; if( _spoil_scenario==15 ) vy = fp_neginf; double v; double dx; double dy; double dxy; spline2dinterpolant s; // build spline spline2dbuildbicubicv(x, 3, y, 2, f, 1, s); // calculate S(0.25,0.50) v = spline2dcalc(s, vx, vy); _TestResult = _TestResult && doc_test_real(v, 1.0625, 0.00005); // calculate derivatives spline2ddiff(s, vx, vy, v, dx, dy, dxy); _TestResult = _TestResult && doc_test_real(v, 1.0625, 0.00005); _TestResult = _TestResult && doc_test_real(dx, 0.5000, 0.00005); _TestResult = _TestResult && doc_test_real(dy, 2.0000, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline2d_bicubic"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline2d_unpack // Unpacking bilinear spline // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // We build bilinear spline for f(x,y)=x+2*y+3*xy for (x,y) in [0,1]. // Then we demonstrate how to unpack it. // real_1d_array x = "[0.0, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array f = "[0.00,1.00,2.00,6.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(f); if( _spoil_scenario==9 ) spoil_vector_by_posinf(f); if( _spoil_scenario==10 ) spoil_vector_by_neginf(f); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(f); real_2d_array c; ae_int_t m; ae_int_t n; ae_int_t d; spline2dinterpolant s; // build spline spline2dbuildbilinearv(x, 2, y, 2, f, 1, s); // unpack and test spline2dunpackv(s, m, n, d, c); _TestResult = _TestResult && doc_test_real_matrix(c, "[[0, 1, 0, 1, 0,2,0,0, 1,3,0,0, 0,0,0,0, 0,0,0,0 ]]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline2d_unpack"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline2d_copytrans // Copy and transform // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<16; _spoil_scenario++) { try { // // We build bilinear spline for f(x,y)=x+2*y for (x,y) in [0,1]. // Then we apply several transformations to this spline. // real_1d_array x = "[0.0, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array f = "[0.00,1.00,2.00,3.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(f); if( _spoil_scenario==9 ) spoil_vector_by_posinf(f); if( _spoil_scenario==10 ) spoil_vector_by_neginf(f); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(f); spline2dinterpolant s; spline2dinterpolant snew; double v; spline2dbuildbilinearv(x, 2, y, 2, f, 1, s); // copy spline, apply transformation x:=2*xnew, y:=4*ynew // evaluate at (xnew,ynew) = (0.25,0.25) - should be same as (x,y)=(0.5,1.0) spline2dcopy(s, snew); spline2dlintransxy(snew, 2.0, 0.0, 4.0, 0.0); v = spline2dcalc(snew, 0.25, 0.25); _TestResult = _TestResult && doc_test_real(v, 2.500, 0.00005); // copy spline, apply transformation SNew:=2*S+3 spline2dcopy(s, snew); spline2dlintransf(snew, 2.0, 3.0); v = spline2dcalc(snew, 0.5, 1.0); _TestResult = _TestResult && doc_test_real(v, 8.000, 0.00005); // // Same example, but for vector spline (f0,f1) = {x+2*y, 2*x+y} // real_1d_array f2 = "[0.00,0.00, 1.00,2.00, 2.00,1.00, 3.00,3.00]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(f2); if( _spoil_scenario==13 ) spoil_vector_by_posinf(f2); if( _spoil_scenario==14 ) spoil_vector_by_neginf(f2); if( _spoil_scenario==15 ) spoil_vector_by_deleting_element(f2); real_1d_array vr; spline2dbuildbilinearv(x, 2, y, 2, f2, 2, s); // copy spline, apply transformation x:=2*xnew, y:=4*ynew spline2dcopy(s, snew); spline2dlintransxy(snew, 2.0, 0.0, 4.0, 0.0); spline2dcalcv(snew, 0.25, 0.25, vr); _TestResult = _TestResult && doc_test_real_vector(vr, "[2.500,2.000]", 0.00005); // copy spline, apply transformation SNew:=2*S+3 spline2dcopy(s, snew); spline2dlintransf(snew, 2.0, 3.0); spline2dcalcv(snew, 0.5, 1.0, vr); _TestResult = _TestResult && doc_test_real_vector(vr, "[8.000,7.000]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline2d_copytrans"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline2d_vector // Copy and transform // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<12; _spoil_scenario++) { try { // // We build bilinear vector-valued spline (f0,f1) = {x+2*y, 2*x+y} // Spline is built using function values at 2x2 grid: (x,y)=[0,1]*[0,1] // Then we perform evaluation at (x,y)=(0.1,0.3) // real_1d_array x = "[0.0, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array f = "[0.00,0.00, 1.00,2.00, 2.00,1.00, 3.00,3.00]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(f); if( _spoil_scenario==9 ) spoil_vector_by_posinf(f); if( _spoil_scenario==10 ) spoil_vector_by_neginf(f); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(f); spline2dinterpolant s; real_1d_array vr; spline2dbuildbilinearv(x, 2, y, 2, f, 2, s); spline2dcalcv(s, 0.1, 0.3, vr); _TestResult = _TestResult && doc_test_real_vector(vr, "[0.700,0.500]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline2d_vector"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline3d_trilinear // Trilinear spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<22; _spoil_scenario++) { try { // // We use trilinear spline to interpolate f(x,y,z)=x+xy+z sampled // at (x,y,z) from [0.0, 1.0] X [0.0, 1.0] X [0.0, 1.0]. // // We store x, y and z-values at local arrays with same names. // Function values are stored in the array F as follows: // f[0] (x,y,z) = (0,0,0) // f[1] (x,y,z) = (1,0,0) // f[2] (x,y,z) = (0,1,0) // f[3] (x,y,z) = (1,1,0) // f[4] (x,y,z) = (0,0,1) // f[5] (x,y,z) = (1,0,1) // f[6] (x,y,z) = (0,1,1) // f[7] (x,y,z) = (1,1,1) // real_1d_array x = "[0.0, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array z = "[0.0, 1.0]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(z); if( _spoil_scenario==9 ) spoil_vector_by_posinf(z); if( _spoil_scenario==10 ) spoil_vector_by_neginf(z); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(z); real_1d_array f = "[0,1,0,2,1,2,1,3]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(f); if( _spoil_scenario==13 ) spoil_vector_by_posinf(f); if( _spoil_scenario==14 ) spoil_vector_by_neginf(f); if( _spoil_scenario==15 ) spoil_vector_by_deleting_element(f); double vx = 0.50; if( _spoil_scenario==16 ) vx = fp_posinf; if( _spoil_scenario==17 ) vx = fp_neginf; double vy = 0.50; if( _spoil_scenario==18 ) vy = fp_posinf; if( _spoil_scenario==19 ) vy = fp_neginf; double vz = 0.50; if( _spoil_scenario==20 ) vz = fp_posinf; if( _spoil_scenario==21 ) vz = fp_neginf; double v; spline3dinterpolant s; // build spline spline3dbuildtrilinearv(x, 2, y, 2, z, 2, f, 1, s); // calculate S(0.5,0.5,0.5) v = spline3dcalc(s, vx, vy, vz); _TestResult = _TestResult && doc_test_real(v, 1.2500, 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline3d_trilinear"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST spline3d_vector // Vector-valued trilinear spline interpolation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<22; _spoil_scenario++) { try { // // We use trilinear vector-valued spline to interpolate {f0,f1}={x+xy+z,x+xy+yz+z} // sampled at (x,y,z) from [0.0, 1.0] X [0.0, 1.0] X [0.0, 1.0]. // // We store x, y and z-values at local arrays with same names. // Function values are stored in the array F as follows: // f[0] f0, (x,y,z) = (0,0,0) // f[1] f1, (x,y,z) = (0,0,0) // f[2] f0, (x,y,z) = (1,0,0) // f[3] f1, (x,y,z) = (1,0,0) // f[4] f0, (x,y,z) = (0,1,0) // f[5] f1, (x,y,z) = (0,1,0) // f[6] f0, (x,y,z) = (1,1,0) // f[7] f1, (x,y,z) = (1,1,0) // f[8] f0, (x,y,z) = (0,0,1) // f[9] f1, (x,y,z) = (0,0,1) // f[10] f0, (x,y,z) = (1,0,1) // f[11] f1, (x,y,z) = (1,0,1) // f[12] f0, (x,y,z) = (0,1,1) // f[13] f1, (x,y,z) = (0,1,1) // f[14] f0, (x,y,z) = (1,1,1) // f[15] f1, (x,y,z) = (1,1,1) // real_1d_array x = "[0.0, 1.0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(x); real_1d_array y = "[0.0, 1.0]"; if( _spoil_scenario==4 ) spoil_vector_by_nan(y); if( _spoil_scenario==5 ) spoil_vector_by_posinf(y); if( _spoil_scenario==6 ) spoil_vector_by_neginf(y); if( _spoil_scenario==7 ) spoil_vector_by_deleting_element(y); real_1d_array z = "[0.0, 1.0]"; if( _spoil_scenario==8 ) spoil_vector_by_nan(z); if( _spoil_scenario==9 ) spoil_vector_by_posinf(z); if( _spoil_scenario==10 ) spoil_vector_by_neginf(z); if( _spoil_scenario==11 ) spoil_vector_by_deleting_element(z); real_1d_array f = "[0,0, 1,1, 0,0, 2,2, 1,1, 2,2, 1,2, 3,4]"; if( _spoil_scenario==12 ) spoil_vector_by_nan(f); if( _spoil_scenario==13 ) spoil_vector_by_posinf(f); if( _spoil_scenario==14 ) spoil_vector_by_neginf(f); if( _spoil_scenario==15 ) spoil_vector_by_deleting_element(f); double vx = 0.50; if( _spoil_scenario==16 ) vx = fp_posinf; if( _spoil_scenario==17 ) vx = fp_neginf; double vy = 0.50; if( _spoil_scenario==18 ) vy = fp_posinf; if( _spoil_scenario==19 ) vy = fp_neginf; double vz = 0.50; if( _spoil_scenario==20 ) vz = fp_posinf; if( _spoil_scenario==21 ) vz = fp_neginf; spline3dinterpolant s; // build spline spline3dbuildtrilinearv(x, 2, y, 2, z, 2, f, 2, s); // calculate S(0.5,0.5,0.5) - we have vector of values instead of single value real_1d_array v; spline3dcalcv(s, vx, vy, vz, v); _TestResult = _TestResult && doc_test_real_vector(v, "[1.2500,1.5000]", 0.00005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "spline3d_vector"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_d_1 // Determinant calculation, real matrix, short form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { real_2d_array b = "[[1,2],[2,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(b); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(b); double a; a = rmatrixdet(b); _TestResult = _TestResult && doc_test_real(a, -3, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_d_2 // Determinant calculation, real matrix, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { real_2d_array b = "[[5,4],[4,5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); double a; a = rmatrixdet(b, 2); _TestResult = _TestResult && doc_test_real(a, 9, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_d_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_d_3 // Determinant calculation, complex matrix, short form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { complex_2d_array b = "[[1+1i,2],[2,1-1i]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(b); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(b); alglib::complex a; a = cmatrixdet(b); _TestResult = _TestResult && doc_test_complex(a, -2, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_d_3"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_d_4 // Determinant calculation, complex matrix, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { alglib::complex a; complex_2d_array b = "[[5i,4],[4i,5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); a = cmatrixdet(b, 2); _TestResult = _TestResult && doc_test_complex(a, alglib::complex(0,9), 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_d_4"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_d_5 // Determinant calculation, complex matrix with zero imaginary part, short form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<7; _spoil_scenario++) { try { alglib::complex a; complex_2d_array b = "[[9,1],[2,1]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(b); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(b); a = cmatrixdet(b); _TestResult = _TestResult && doc_test_complex(a, 7, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_d_5"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_0 // Determinant calculation, real matrix, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { double a; real_2d_array b = "[[3,4],[-4,3]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); a = rmatrixdet(b, 2); _TestResult = _TestResult && doc_test_real(a, 25, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_0"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_1 // Determinant calculation, real matrix, LU, short form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<9; _spoil_scenario++) { try { double a; real_2d_array b = "[[1,2],[2,5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(b); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(b); integer_1d_array p = "[1,1]"; if( _spoil_scenario==7 ) spoil_vector_by_adding_element(p); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(p); a = rmatrixludet(b, p); _TestResult = _TestResult && doc_test_real(a, -5, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_2 // Determinant calculation, real matrix, LU, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { double a; real_2d_array b = "[[5,4],[4,5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); integer_1d_array p = "[0,1]"; if( _spoil_scenario==5 ) spoil_vector_by_deleting_element(p); a = rmatrixludet(b, p, 2); _TestResult = _TestResult && doc_test_real(a, 25, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_2"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_3 // Determinant calculation, complex matrix, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<5; _spoil_scenario++) { try { alglib::complex a; complex_2d_array b = "[[5i,4],[-4,5i]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); a = cmatrixdet(b, 2); _TestResult = _TestResult && doc_test_complex(a, -9, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_3"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_4 // Determinant calculation, complex matrix, LU, short form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<9; _spoil_scenario++) { try { alglib::complex a; complex_2d_array b = "[[1,2],[2,5i]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_adding_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_adding_col(b); if( _spoil_scenario==5 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==6 ) spoil_matrix_by_deleting_col(b); integer_1d_array p = "[1,1]"; if( _spoil_scenario==7 ) spoil_vector_by_adding_element(p); if( _spoil_scenario==8 ) spoil_vector_by_deleting_element(p); a = cmatrixludet(b, p); _TestResult = _TestResult && doc_test_complex(a, alglib::complex(0,-5), 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_4"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST matdet_t_5 // Determinant calculation, complex matrix, LU, full form // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<6; _spoil_scenario++) { try { alglib::complex a; complex_2d_array b = "[[5,4i],[4,5]]"; if( _spoil_scenario==0 ) spoil_matrix_by_nan(b); if( _spoil_scenario==1 ) spoil_matrix_by_posinf(b); if( _spoil_scenario==2 ) spoil_matrix_by_neginf(b); if( _spoil_scenario==3 ) spoil_matrix_by_deleting_row(b); if( _spoil_scenario==4 ) spoil_matrix_by_deleting_col(b); integer_1d_array p = "[0,1]"; if( _spoil_scenario==5 ) spoil_vector_by_deleting_element(p); a = cmatrixludet(b, p, 2); _TestResult = _TestResult && doc_test_complex(a, 25, 0.0001); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "matdet_t_5"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minnlc_d_inequality // Nonlinearly constrained optimization (inequality constraints) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = -x0+x1 // // subject to boundary constraints // // x0>=0, x1>=0 // // and nonlinear inequality constraint // // x0^2 + x1^2 - 1 <= 0 // real_1d_array x0 = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsg = 0; if( _spoil_scenario==6 ) epsg = fp_nan; if( _spoil_scenario==7 ) epsg = fp_posinf; if( _spoil_scenario==8 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==9 ) epsf = fp_nan; if( _spoil_scenario==10 ) epsf = fp_posinf; if( _spoil_scenario==11 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==12 ) epsx = fp_nan; if( _spoil_scenario==13 ) epsx = fp_posinf; if( _spoil_scenario==14 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t outerits = 5; ae_int_t updatefreq = 10; double rho = 1000; if( _spoil_scenario==15 ) rho = fp_nan; if( _spoil_scenario==16 ) rho = fp_posinf; if( _spoil_scenario==17 ) rho = fp_neginf; real_1d_array bndl = "[0,0]"; real_1d_array bndu = "[+inf,+inf]"; minnlcstate state; minnlcreport rep; real_1d_array x1; // // Create optimizer object, choose AUL algorithm and tune its settings: // * rho=1000 penalty coefficient // * outerits=5 number of outer iterations to tune Lagrange coefficients // * epsx=0.000001 stopping condition for inner iterations // * s=[1,1] all variables have unit scale // * exact low-rank preconditioner is used, updated after each 10 iterations // minnlccreate(2, x0, state); minnlcsetalgoaul(state, rho, outerits); minnlcsetcond(state, epsg, epsf, epsx, maxits); minnlcsetscale(state, s); minnlcsetprecexactlowrank(state, updatefreq); // // Set constraints: // // 1. boundary constraints are passed with minnlcsetbc() call // // 2. nonlinear constraints are more tricky - you can not "pack" general // nonlinear function into double precision array. That's why // minnlcsetnlc() does not accept constraints itself - only constraint // counts are passed: first parameter is number of equality constraints, // second one is number of inequality constraints. // // As for constraining functions - these functions are passed as part // of problem Jacobian (see below). // // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general // linear and general nonlinear constraints. This example does not // show how to work with general linear constraints, but you can // easily find it in documentation on minnlcsetlc() function. // minnlcsetbc(state, bndl, bndu); minnlcsetnlc(state, 0, 1); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints. // // So, our vector function has form // // {f0,f1} = { -x0+x1 , x0^2+x1^2-1 } // // with Jacobian // // [ -1 +1 ] // J = [ ] // [ 2*x0 2*x1 ] // // with f0 being target function, f1 being constraining function. Number // of equality/inequality constraints is specified by minnlcsetnlc(), // with equality ones always being first, inequality ones being last. // alglib::minnlcoptimize(state, nlcfunc1_jac); minnlcresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[1.0000,0.0000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minnlc_d_inequality"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minnlc_d_equality // Nonlinearly constrained optimization (equality constraints) // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = -x0+x1 // // subject to nonlinear equality constraint // // x0^2 + x1^2 - 1 = 0 // real_1d_array x0 = "[0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsg = 0; if( _spoil_scenario==6 ) epsg = fp_nan; if( _spoil_scenario==7 ) epsg = fp_posinf; if( _spoil_scenario==8 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==9 ) epsf = fp_nan; if( _spoil_scenario==10 ) epsf = fp_posinf; if( _spoil_scenario==11 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==12 ) epsx = fp_nan; if( _spoil_scenario==13 ) epsx = fp_posinf; if( _spoil_scenario==14 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t outerits = 5; ae_int_t updatefreq = 10; double rho = 1000; if( _spoil_scenario==15 ) rho = fp_nan; if( _spoil_scenario==16 ) rho = fp_posinf; if( _spoil_scenario==17 ) rho = fp_neginf; minnlcstate state; minnlcreport rep; real_1d_array x1; // // Create optimizer object, choose AUL algorithm and tune its settings: // * rho=1000 penalty coefficient // * outerits=5 number of outer iterations to tune Lagrange coefficients // * epsx=0.000001 stopping condition for inner iterations // * s=[1,1] all variables have unit scale // * exact low-rank preconditioner is used, updated after each 10 iterations // minnlccreate(2, x0, state); minnlcsetalgoaul(state, rho, outerits); minnlcsetcond(state, epsg, epsf, epsx, maxits); minnlcsetscale(state, s); minnlcsetprecexactlowrank(state, updatefreq); // // Set constraints: // // Nonlinear constraints are tricky - you can not "pack" general // nonlinear function into double precision array. That's why // minnlcsetnlc() does not accept constraints itself - only constraint // counts are passed: first parameter is number of equality constraints, // second one is number of inequality constraints. // // As for constraining functions - these functions are passed as part // of problem Jacobian (see below). // // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general // linear and general nonlinear constraints. This example does not // show how to work with general linear constraints, but you can // easily find it in documentation on minnlcsetbc() and // minnlcsetlc() functions. // minnlcsetnlc(state, 1, 0); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints. // // So, our vector function has form // // {f0,f1} = { -x0+x1 , x0^2+x1^2-1 } // // with Jacobian // // [ -1 +1 ] // J = [ ] // [ 2*x0 2*x1 ] // // with f0 being target function, f1 being constraining function. Number // of equality/inequality constraints is specified by minnlcsetnlc(), // with equality ones always being first, inequality ones being last. // alglib::minnlcoptimize(state, nlcfunc1_jac); minnlcresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[0.70710,-0.70710]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minnlc_d_equality"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minnlc_d_mixed // Nonlinearly constrained optimization with mixed equality/inequality constraints // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = x0+x1 // // subject to nonlinear inequality constraint // // x0^2 + x1^2 - 1 <= 0 // // and nonlinear equality constraint // // x2-exp(x0) = 0 // real_1d_array x0 = "[0,0,0]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsg = 0; if( _spoil_scenario==6 ) epsg = fp_nan; if( _spoil_scenario==7 ) epsg = fp_posinf; if( _spoil_scenario==8 ) epsg = fp_neginf; double epsf = 0; if( _spoil_scenario==9 ) epsf = fp_nan; if( _spoil_scenario==10 ) epsf = fp_posinf; if( _spoil_scenario==11 ) epsf = fp_neginf; double epsx = 0.000001; if( _spoil_scenario==12 ) epsx = fp_nan; if( _spoil_scenario==13 ) epsx = fp_posinf; if( _spoil_scenario==14 ) epsx = fp_neginf; ae_int_t maxits = 0; ae_int_t outerits = 5; ae_int_t updatefreq = 10; double rho = 1000; if( _spoil_scenario==15 ) rho = fp_nan; if( _spoil_scenario==16 ) rho = fp_posinf; if( _spoil_scenario==17 ) rho = fp_neginf; minnlcstate state; minnlcreport rep; real_1d_array x1; // // Create optimizer object, choose AUL algorithm and tune its settings: // * rho=1000 penalty coefficient // * outerits=5 number of outer iterations to tune Lagrange coefficients // * epsx=0.000001 stopping condition for inner iterations // * s=[1,1] all variables have unit scale // * exact low-rank preconditioner is used, updated after each 10 iterations // minnlccreate(3, x0, state); minnlcsetalgoaul(state, rho, outerits); minnlcsetcond(state, epsg, epsf, epsx, maxits); minnlcsetscale(state, s); minnlcsetprecexactlowrank(state, updatefreq); // // Set constraints: // // Nonlinear constraints are tricky - you can not "pack" general // nonlinear function into double precision array. That's why // minnlcsetnlc() does not accept constraints itself - only constraint // counts are passed: first parameter is number of equality constraints, // second one is number of inequality constraints. // // As for constraining functions - these functions are passed as part // of problem Jacobian (see below). // // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general // linear and general nonlinear constraints. This example does not // show how to work with boundary or general linear constraints, but you // can easily find it in documentation on minnlcsetbc() and // minnlcsetlc() functions. // minnlcsetnlc(state, 1, 1); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints. // // So, our vector function has form // // {f0,f1,f2} = { x0+x1 , x2-exp(x0) , x0^2+x1^2-1 } // // with Jacobian // // [ +1 +1 0 ] // J = [-exp(x0) 0 1 ] // [ 2*x0 2*x1 0 ] // // with f0 being target function, f1 being equality constraint "f1=0", // f2 being inequality constraint "f2<=0". Number of equality/inequality // constraints is specified by minnlcsetnlc(), with equality ones always // being first, inequality ones being last. // alglib::minnlcoptimize(state, nlcfunc2_jac); minnlcresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[-0.70710,-0.70710,0.49306]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minnlc_d_mixed"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minns_d_unconstrained // Nonsmooth unconstrained optimization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<15; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = 2*|x0|+|x1| // // using nonsmooth nonlinear optimizer. // real_1d_array x0 = "[1,1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsx = 0.00001; if( _spoil_scenario==6 ) epsx = fp_nan; if( _spoil_scenario==7 ) epsx = fp_posinf; if( _spoil_scenario==8 ) epsx = fp_neginf; double radius = 0.1; if( _spoil_scenario==9 ) radius = fp_nan; if( _spoil_scenario==10 ) radius = fp_posinf; if( _spoil_scenario==11 ) radius = fp_neginf; double rho = 0.0; if( _spoil_scenario==12 ) rho = fp_nan; if( _spoil_scenario==13 ) rho = fp_posinf; if( _spoil_scenario==14 ) rho = fp_neginf; ae_int_t maxits = 0; minnsstate state; minnsreport rep; real_1d_array x1; // // Create optimizer object, choose AGS algorithm and tune its settings: // * radius=0.1 good initial value; will be automatically decreased later. // * rho=0.0 penalty coefficient for nonlinear constraints; can be zero // because we do not have such constraints // * epsx=0.000001 stopping conditions // * s=[1,1] all variables have unit scale // minnscreate(2, x0, state); minnssetalgoags(state, radius, rho); minnssetcond(state, epsx, maxits); minnssetscale(state, s); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints // (box/linear ones are passed separately by means of minnssetbc() and // minnssetlc() calls). // // If you do not have nonlinear constraints (exactly our situation), then // you will have one-component function vector and 1xN Jacobian matrix. // // So, our vector function has form // // {f0} = { 2*|x0|+|x1| } // // with Jacobian // // [ ] // J = [ 2*sign(x0) sign(x1) ] // [ ] // // NOTE: nonsmooth optimizer requires considerably more function // evaluations than smooth solver - about 2N times more. Using // numerical differentiation introduces additional (multiplicative) // 2N speedup. // // It means that if smooth optimizer WITH user-supplied gradient // needs 100 function evaluations to solve 50-dimensional problem, // then AGS solver with user-supplied gradient will need about 10.000 // function evaluations, and with numerical gradient about 1.000.000 // function evaluations will be performed. // // NOTE: AGS solver used by us can handle nonsmooth and nonconvex // optimization problems. It has convergence guarantees, i.e. it will // converge to stationary point of the function after running for some // time. // // However, it is important to remember that "stationary point" is not // equal to "solution". If your problem is convex, everything is OK. // But nonconvex optimization problems may have "flat spots" - large // areas where gradient is exactly zero, but function value is far away // from optimal. Such areas are stationary points too, and optimizer // may be trapped here. // // "Flat spots" are nonsmooth equivalent of the saddle points, but with // orders of magnitude worse properties - they may be quite large and // hard to avoid. All nonsmooth optimizers are prone to this kind of the // problem, because it is impossible to automatically distinguish "flat // spot" from true solution. // // This note is here to warn you that you should be very careful when // you solve nonsmooth optimization problems. Visual inspection of // results is essential. // alglib::minnsoptimize(state, nsfunc1_jac); minnsresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[0.0000,0.0000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minns_d_unconstrained"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minns_d_diff // Nonsmooth unconstrained optimization with numerical differentiation // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<18; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = 2*|x0|+|x1| // // using nonsmooth nonlinear optimizer with numerical // differentiation provided by ALGLIB. // // NOTE: nonsmooth optimizer requires considerably more function // evaluations than smooth solver - about 2N times more. Using // numerical differentiation introduces additional (multiplicative) // 2N speedup. // // It means that if smooth optimizer WITH user-supplied gradient // needs 100 function evaluations to solve 50-dimensional problem, // then AGS solver with user-supplied gradient will need about 10.000 // function evaluations, and with numerical gradient about 1.000.000 // function evaluations will be performed. // real_1d_array x0 = "[1,1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsx = 0.00001; if( _spoil_scenario==6 ) epsx = fp_nan; if( _spoil_scenario==7 ) epsx = fp_posinf; if( _spoil_scenario==8 ) epsx = fp_neginf; double diffstep = 0.000001; if( _spoil_scenario==9 ) diffstep = fp_nan; if( _spoil_scenario==10 ) diffstep = fp_posinf; if( _spoil_scenario==11 ) diffstep = fp_neginf; double radius = 0.1; if( _spoil_scenario==12 ) radius = fp_nan; if( _spoil_scenario==13 ) radius = fp_posinf; if( _spoil_scenario==14 ) radius = fp_neginf; double rho = 0.0; if( _spoil_scenario==15 ) rho = fp_nan; if( _spoil_scenario==16 ) rho = fp_posinf; if( _spoil_scenario==17 ) rho = fp_neginf; ae_int_t maxits = 0; minnsstate state; minnsreport rep; real_1d_array x1; // // Create optimizer object, choose AGS algorithm and tune its settings: // * radius=0.1 good initial value; will be automatically decreased later. // * rho=0.0 penalty coefficient for nonlinear constraints; can be zero // because we do not have such constraints // * epsx=0.000001 stopping conditions // * s=[1,1] all variables have unit scale // minnscreatef(2, x0, diffstep, state); minnssetalgoags(state, radius, rho); minnssetcond(state, epsx, maxits); minnssetscale(state, s); // // Optimize and test results. // // Optimizer object accepts vector function, with first component // being target function, and next components being nonlinear equality // and inequality constraints (box/linear ones are passed separately // by means of minnssetbc() and minnssetlc() calls). // // If you do not have nonlinear constraints (exactly our situation), then // you will have one-component function vector. // // So, our vector function has form // // {f0} = { 2*|x0|+|x1| } // alglib::minnsoptimize(state, nsfunc1_fvec); minnsresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[0.0000,0.0000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minns_d_diff"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minns_d_bc // Nonsmooth box constrained optimization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<17; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = 2*|x0|+|x1| // // subject to box constraints // // 1 <= x0 < +INF // -INF <= x1 < +INF // // using nonsmooth nonlinear optimizer. // real_1d_array x0 = "[1,1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); real_1d_array bndl = "[1,-inf]"; if( _spoil_scenario==6 ) spoil_vector_by_nan(bndl); real_1d_array bndu = "[+inf,+inf]"; if( _spoil_scenario==7 ) spoil_vector_by_nan(bndu); double epsx = 0.00001; if( _spoil_scenario==8 ) epsx = fp_nan; if( _spoil_scenario==9 ) epsx = fp_posinf; if( _spoil_scenario==10 ) epsx = fp_neginf; double radius = 0.1; if( _spoil_scenario==11 ) radius = fp_nan; if( _spoil_scenario==12 ) radius = fp_posinf; if( _spoil_scenario==13 ) radius = fp_neginf; double rho = 0.0; if( _spoil_scenario==14 ) rho = fp_nan; if( _spoil_scenario==15 ) rho = fp_posinf; if( _spoil_scenario==16 ) rho = fp_neginf; ae_int_t maxits = 0; minnsstate state; minnsreport rep; real_1d_array x1; // // Create optimizer object, choose AGS algorithm and tune its settings: // * radius=0.1 good initial value; will be automatically decreased later. // * rho=0.0 penalty coefficient for nonlinear constraints; can be zero // because we do not have such constraints // * epsx=0.000001 stopping conditions // * s=[1,1] all variables have unit scale // minnscreate(2, x0, state); minnssetalgoags(state, radius, rho); minnssetcond(state, epsx, maxits); minnssetscale(state, s); // // Set box constraints. // // General linear constraints are set in similar way (see comments on // minnssetlc() function for more information). // // You may combine box, linear and nonlinear constraints in one optimization // problem. // minnssetbc(state, bndl, bndu); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints // (box/linear ones are passed separately by means of minnssetbc() and // minnssetlc() calls). // // If you do not have nonlinear constraints (exactly our situation), then // you will have one-component function vector and 1xN Jacobian matrix. // // So, our vector function has form // // {f0} = { 2*|x0|+|x1| } // // with Jacobian // // [ ] // J = [ 2*sign(x0) sign(x1) ] // [ ] // // NOTE: nonsmooth optimizer requires considerably more function // evaluations than smooth solver - about 2N times more. Using // numerical differentiation introduces additional (multiplicative) // 2N speedup. // // It means that if smooth optimizer WITH user-supplied gradient // needs 100 function evaluations to solve 50-dimensional problem, // then AGS solver with user-supplied gradient will need about 10.000 // function evaluations, and with numerical gradient about 1.000.000 // function evaluations will be performed. // // NOTE: AGS solver used by us can handle nonsmooth and nonconvex // optimization problems. It has convergence guarantees, i.e. it will // converge to stationary point of the function after running for some // time. // // However, it is important to remember that "stationary point" is not // equal to "solution". If your problem is convex, everything is OK. // But nonconvex optimization problems may have "flat spots" - large // areas where gradient is exactly zero, but function value is far away // from optimal. Such areas are stationary points too, and optimizer // may be trapped here. // // "Flat spots" are nonsmooth equivalent of the saddle points, but with // orders of magnitude worse properties - they may be quite large and // hard to avoid. All nonsmooth optimizers are prone to this kind of the // problem, because it is impossible to automatically distinguish "flat // spot" from true solution. // // This note is here to warn you that you should be very careful when // you solve nonsmooth optimization problems. Visual inspection of // results is essential. // // alglib::minnsoptimize(state, nsfunc1_jac); minnsresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[1.0000,0.0000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minns_d_bc"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST minns_d_nlc // Nonsmooth nonlinearly constrained optimization // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<15; _spoil_scenario++) { try { // // This example demonstrates minimization of // // f(x0,x1) = 2*|x0|+|x1| // // subject to combination of equality and inequality constraints // // x0 = 1 // x1 >= -1 // // using nonsmooth nonlinear optimizer. Although these constraints // are linear, we treat them as general nonlinear ones in order to // demonstrate nonlinearly constrained optimization setup. // real_1d_array x0 = "[1,1]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(x0); if( _spoil_scenario==1 ) spoil_vector_by_posinf(x0); if( _spoil_scenario==2 ) spoil_vector_by_neginf(x0); real_1d_array s = "[1,1]"; if( _spoil_scenario==3 ) spoil_vector_by_nan(s); if( _spoil_scenario==4 ) spoil_vector_by_posinf(s); if( _spoil_scenario==5 ) spoil_vector_by_neginf(s); double epsx = 0.00001; if( _spoil_scenario==6 ) epsx = fp_nan; if( _spoil_scenario==7 ) epsx = fp_posinf; if( _spoil_scenario==8 ) epsx = fp_neginf; double radius = 0.1; if( _spoil_scenario==9 ) radius = fp_nan; if( _spoil_scenario==10 ) radius = fp_posinf; if( _spoil_scenario==11 ) radius = fp_neginf; double rho = 50.0; if( _spoil_scenario==12 ) rho = fp_nan; if( _spoil_scenario==13 ) rho = fp_posinf; if( _spoil_scenario==14 ) rho = fp_neginf; ae_int_t maxits = 0; minnsstate state; minnsreport rep; real_1d_array x1; // // Create optimizer object, choose AGS algorithm and tune its settings: // * radius=0.1 good initial value; will be automatically decreased later. // * rho=50.0 penalty coefficient for nonlinear constraints. It is your // responsibility to choose good one - large enough that it // enforces constraints, but small enough in order to avoid // extreme slowdown due to ill-conditioning. // * epsx=0.000001 stopping conditions // * s=[1,1] all variables have unit scale // minnscreate(2, x0, state); minnssetalgoags(state, radius, rho); minnssetcond(state, epsx, maxits); minnssetscale(state, s); // // Set general nonlinear constraints. // // This part is more tricky than working with box/linear constraints - you // can not "pack" general nonlinear function into double precision array. // That's why minnssetnlc() does not accept constraints itself - only // constraint COUNTS are passed: first parameter is number of equality // constraints, second one is number of inequality constraints. // // As for constraining functions - these functions are passed as part // of problem Jacobian (see below). // // NOTE: MinNS optimizer supports arbitrary combination of boundary, general // linear and general nonlinear constraints. This example does not // show how to work with general linear constraints, but you can // easily find it in documentation on minnlcsetlc() function. // minnssetnlc(state, 1, 1); // // Optimize and test results. // // Optimizer object accepts vector function and its Jacobian, with first // component (Jacobian row) being target function, and next components // (Jacobian rows) being nonlinear equality and inequality constraints // (box/linear ones are passed separately by means of minnssetbc() and // minnssetlc() calls). // // Nonlinear equality constraints have form Gi(x)=0, inequality ones // have form Hi(x)<=0, so we may have to "normalize" constraints prior // to passing them to optimizer (right side is zero, constraints are // sorted, multiplied by -1 when needed). // // So, our vector function has form // // {f0,f1,f2} = { 2*|x0|+|x1|, x0-1, -x1-1 } // // with Jacobian // // [ 2*sign(x0) sign(x1) ] // J = [ 1 0 ] // [ 0 -1 ] // // which means that we have optimization problem // // min{f0} subject to f1=0, f2<=0 // // which is essentially same as // // min { 2*|x0|+|x1| } subject to x0=1, x1>=-1 // // NOTE: AGS solver used by us can handle nonsmooth and nonconvex // optimization problems. It has convergence guarantees, i.e. it will // converge to stationary point of the function after running for some // time. // // However, it is important to remember that "stationary point" is not // equal to "solution". If your problem is convex, everything is OK. // But nonconvex optimization problems may have "flat spots" - large // areas where gradient is exactly zero, but function value is far away // from optimal. Such areas are stationary points too, and optimizer // may be trapped here. // // "Flat spots" are nonsmooth equivalent of the saddle points, but with // orders of magnitude worse properties - they may be quite large and // hard to avoid. All nonsmooth optimizers are prone to this kind of the // problem, because it is impossible to automatically distinguish "flat // spot" from true solution. // // This note is here to warn you that you should be very careful when // you solve nonsmooth optimization problems. Visual inspection of // results is essential. // alglib::minnsoptimize(state, nsfunc2_jac); minnsresults(state, x1, rep); _TestResult = _TestResult && doc_test_real_vector(x1, "[1.0000,0.0000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "minns_d_nlc"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; // // TEST lincg_d_1 // Solution of sparse linear systems with CG // _TestResult = true; for(_spoil_scenario=-1; _spoil_scenario<4; _spoil_scenario++) { try { // // This example illustrates solution of sparse linear systems with // conjugate gradient method. // // Suppose that we have linear system A*x=b with sparse symmetric // positive definite A (represented by sparsematrix object) // [ 5 1 ] // [ 1 7 2 ] // A = [ 2 8 1 ] // [ 1 4 1 ] // [ 1 4 ] // and right part b // [ 7 ] // [ 17 ] // b = [ 14 ] // [ 10 ] // [ 6 ] // and we want to solve this system using sparse linear CG. In order // to do so, we have to create left part (sparsematrix object) and // right part (dense array). // // Initially, sparse matrix is created in the Hash-Table format, // which allows easy initialization, but do not allow matrix to be // used in the linear solvers. So after construction you should convert // sparse matrix to CRS format (one suited for linear operations). // // It is important to note that in our example we initialize full // matrix A, both lower and upper triangles. However, it is symmetric // and sparse solver needs just one half of the matrix. So you may // save about half of the space by filling only one of the triangles. // sparsematrix a; sparsecreate(5, 5, a); sparseset(a, 0, 0, 5.0); sparseset(a, 0, 1, 1.0); sparseset(a, 1, 0, 1.0); sparseset(a, 1, 1, 7.0); sparseset(a, 1, 2, 2.0); sparseset(a, 2, 1, 2.0); sparseset(a, 2, 2, 8.0); sparseset(a, 2, 3, 1.0); sparseset(a, 3, 2, 1.0); sparseset(a, 3, 3, 4.0); sparseset(a, 3, 4, 1.0); sparseset(a, 4, 3, 1.0); sparseset(a, 4, 4, 4.0); // // Now our matrix is fully initialized, but we have to do one more // step - convert it from Hash-Table format to CRS format (see // documentation on sparse matrices for more information about these // formats). // // If you omit this call, ALGLIB will generate exception on the first // attempt to use A in linear operations. // sparseconverttocrs(a); // // Initialization of the right part // real_1d_array b = "[7,17,14,10,6]"; if( _spoil_scenario==0 ) spoil_vector_by_nan(b); if( _spoil_scenario==1 ) spoil_vector_by_posinf(b); if( _spoil_scenario==2 ) spoil_vector_by_neginf(b); if( _spoil_scenario==3 ) spoil_vector_by_deleting_element(b); // // Now we have to create linear solver object and to use it for the // solution of the linear system. // // NOTE: lincgsolvesparse() accepts additional parameter which tells // what triangle of the symmetric matrix should be used - upper // or lower. Because we've filled both parts of the matrix, we // can use any part - upper or lower. // lincgstate s; lincgreport rep; real_1d_array x; lincgcreate(5, s); lincgsolvesparse(s, a, true, b); lincgresults(s, x, rep); _TestResult = _TestResult && doc_test_int(rep.terminationtype, 1); _TestResult = _TestResult && doc_test_real_vector(x, "[1.000,2.000,1.000,2.000,1.000]", 0.005); _TestResult = _TestResult && (_spoil_scenario==-1); } catch(ap_error) { _TestResult = _TestResult && (_spoil_scenario!=-1); } } if( !_TestResult) { printf("%-32s FAILED\n", "lincg_d_1"); fflush(stdout); } _TotalResult = _TotalResult && _TestResult; printf("145/145\n"); } catch(...) { printf("Unhandled exception was raised!\n"); return 1; } #ifdef AE_USE_ALLOC_COUNTER printf("Allocation counter checked... "); if( alglib_impl::_alloc_counter!=0 ) { _TotalResult = false; printf("FAILURE: alloc_counter is non-zero on end!\n"); } else printf("OK\n"); #endif return _TotalResult ? 0 : 1; } qmapshack-1.10.0/3rdparty/alglib/tests/test_c.cpp000755 001750 000144 00014435145 13015033052 023067 0ustar00oeichlerxusers000000 000000 #include #include #include "ap.h" // disable some irrelevant warnings #if (AE_COMPILER==AE_MSVC) #pragma warning(disable:4100) #pragma warning(disable:4127) #pragma warning(disable:4702) #pragma warning(disable:4996) #endif #include "alglibinternal.h" #include "alglibmisc.h" #include "linalg.h" #include "statistics.h" #include "dataanalysis.h" #include "specialfunctions.h" #include "solvers.h" #include "optimization.h" #include "diffequations.h" #include "fasttransforms.h" #include "integration.h" #include "interpolation.h" using namespace alglib_impl; ae_bool testhqrnd(ae_bool silent, ae_state *_state); ae_bool _pexec_testhqrnd(ae_bool silent, ae_state *_state); /************************************************************************* Function for test HQRNDContinuous function *************************************************************************/ ae_bool hqrndcontinuoustest(ae_bool silent, ae_state *_state); /************************************************************************* Function for test HQRNDContinuous function *************************************************************************/ ae_bool hqrnddiscretetest(ae_bool silent, ae_state *_state); /************************************************************************* Testing tag sort *************************************************************************/ ae_bool testtsort(ae_bool silent, ae_state *_state); ae_bool _pexec_testtsort(ae_bool silent, ae_state *_state); /************************************************************************* Testing Nearest Neighbor Search *************************************************************************/ ae_bool testnearestneighbor(ae_bool silent, ae_state *_state); ae_bool _pexec_testnearestneighbor(ae_bool silent, ae_state *_state); ae_bool testablas(ae_bool silent, ae_state *_state); ae_bool _pexec_testablas(ae_bool silent, ae_state *_state); ae_bool testbasestat(ae_bool silent, ae_state *_state); ae_bool _pexec_testbasestat(ae_bool silent, ae_state *_state); /************************************************************************* Testing BDSS operations *************************************************************************/ ae_bool testbdss(ae_bool silent, ae_state *_state); ae_bool _pexec_testbdss(ae_bool silent, ae_state *_state); ae_bool testblas(ae_bool silent, ae_state *_state); ae_bool _pexec_testblas(ae_bool silent, ae_state *_state); /************************************************************************* Testing clustering *************************************************************************/ ae_bool testclustering(ae_bool silent, ae_state *_state); ae_bool _pexec_testclustering(ae_bool silent, ae_state *_state); ae_bool testdforest(ae_bool silent, ae_state *_state); ae_bool _pexec_testdforest(ae_bool silent, ae_state *_state); ae_bool testgammafunc(ae_bool silent, ae_state *_state); ae_bool _pexec_testgammafunc(ae_bool silent, ae_state *_state); ae_bool testhblas(ae_bool silent, ae_state *_state); ae_bool _pexec_testhblas(ae_bool silent, ae_state *_state); ae_bool testreflections(ae_bool silent, ae_state *_state); ae_bool _pexec_testreflections(ae_bool silent, ae_state *_state); ae_bool testcreflections(ae_bool silent, ae_state *_state); ae_bool _pexec_testcreflections(ae_bool silent, ae_state *_state); ae_bool testsblas(ae_bool silent, ae_state *_state); ae_bool _pexec_testsblas(ae_bool silent, ae_state *_state); /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testortfac(ae_bool silent, ae_state *_state); ae_bool _pexec_testortfac(ae_bool silent, ae_state *_state); /************************************************************************* Testing bidiagonal SVD decomposition subroutine *************************************************************************/ ae_bool testbdsvd(ae_bool silent, ae_state *_state); ae_bool _pexec_testbdsvd(ae_bool silent, ae_state *_state); /************************************************************************* Testing SVD decomposition subroutine *************************************************************************/ ae_bool testsvd(ae_bool silent, ae_state *_state); ae_bool _pexec_testsvd(ae_bool silent, ae_state *_state); ae_bool testlinreg(ae_bool silent, ae_state *_state); ae_bool _pexec_testlinreg(ae_bool silent, ae_state *_state); ae_bool testfilters(ae_bool silent, ae_state *_state); ae_bool _pexec_testfilters(ae_bool silent, ae_state *_state); /************************************************************************* This function tests SMA(k) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testsma(ae_bool issilent, ae_state *_state); /************************************************************************* This function tests EMA(alpha) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testema(ae_bool issilent, ae_state *_state); /************************************************************************* This function tests LRMA(k) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testlrma(ae_bool issilent, ae_state *_state); /************************************************************************* Testing symmetric EVD subroutine *************************************************************************/ ae_bool testevd(ae_bool silent, ae_state *_state); ae_bool _pexec_testevd(ae_bool silent, ae_state *_state); ae_bool testmatgen(ae_bool silent, ae_state *_state); ae_bool _pexec_testmatgen(ae_bool silent, ae_state *_state); typedef struct { ae_int_t n; ae_int_t m; ae_int_t matkind; ae_int_t triangle; ae_matrix bufa; hqrndstate rs; rcommstate rcs; } sparsegenerator; ae_bool testsparse(ae_bool silent, ae_state *_state); ae_bool _pexec_testsparse(ae_bool silent, ae_state *_state); /************************************************************************* Function for testing basic SKS functional. Returns True on errors, False on success. -- ALGLIB PROJECT -- Copyright 16.01.1014 by Bochkanov Sergey *************************************************************************/ ae_bool skstest(ae_state *_state); /************************************************************************* Function for testing basic functional -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool basicfunctest(ae_state *_state); /************************************************************************* Function for testing Level 2 unsymmetric linear algebra functions. Additionally it tests SparseGet() for several matrix formats. Returns True on failure. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ ae_bool testlevel2unsymmetric(ae_state *_state); /************************************************************************* Function for testing Level 3 unsymmetric linear algebra functions. Additionally it tests SparseGet() for several matrix formats. Returns True on failure. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ ae_bool testlevel3unsymmetric(ae_state *_state); /************************************************************************* Function for testing Level 2 symmetric linear algebra functions. Additionally it tests SparseGet() for several matrix formats. Returns True on failure. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ ae_bool testlevel2symmetric(ae_state *_state); /************************************************************************* Function for testing Level 2 symmetric linear algebra functions. Additionally it tests SparseGet() for several matrix formats. Returns True on failure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool testlevel3symmetric(ae_state *_state); /************************************************************************* Function for testing Level 2 triangular linear algebra functions. Returns True on failure. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/ ae_bool testlevel2triangular(ae_state *_state); /************************************************************************* Function for testing basic functional -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool basicfuncrandomtest(ae_state *_state); /************************************************************************* Function for testing multyplication matrix with vector -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool linearfunctionstest(ae_state *_state); /************************************************************************* Function for testing multyplication for simmetric matrix with vector -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool linearfunctionsstest(ae_state *_state); /************************************************************************* Function for testing multyplication sparse matrix with nerrow dense matrix -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool linearfunctionsmmtest(ae_state *_state); /************************************************************************* Function for testing multyplication for simmetric sparse matrix with narrow dense matrix -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool linearfunctionssmmtest(ae_state *_state); /************************************************************************* Function for basic test SparseCopy -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool basiccopyfunctest(ae_bool silent, ae_state *_state); /************************************************************************* Function for testing SparseCopy -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool copyfunctest(ae_bool silent, ae_state *_state); void _sparsegenerator_init(void* _p, ae_state *_state); void _sparsegenerator_init_copy(void* _dst, void* _src, ae_state *_state); void _sparsegenerator_clear(void* _p); void _sparsegenerator_destroy(void* _p); ae_bool testtrfac(ae_bool silent, ae_state *_state); ae_bool _pexec_testtrfac(ae_bool silent, ae_state *_state); /************************************************************************* Function for testing sparse real Cholesky. Returns True on errors, False on success. -- ALGLIB PROJECT -- Copyright 16.01.1014 by Bochkanov Sergey *************************************************************************/ ae_bool sparserealcholeskytest(ae_state *_state); /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testtrlinsolve(ae_bool silent, ae_state *_state); ae_bool _pexec_testtrlinsolve(ae_bool silent, ae_state *_state); /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testsafesolve(ae_bool silent, ae_state *_state); ae_bool _pexec_testsafesolve(ae_bool silent, ae_state *_state); ae_bool testrcond(ae_bool silent, ae_state *_state); ae_bool _pexec_testrcond(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testmatinv(ae_bool silent, ae_state *_state); ae_bool _pexec_testmatinv(ae_bool silent, ae_state *_state); ae_bool testlda(ae_bool silent, ae_state *_state); ae_bool _pexec_testlda(ae_bool silent, ae_state *_state); ae_bool testmlpbase(ae_bool silent, ae_state *_state); ae_bool _pexec_testmlpbase(ae_bool silent, ae_state *_state); ae_bool testxblas(ae_bool silent, ae_state *_state); ae_bool _pexec_testxblas(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testdensesolver(ae_bool silent, ae_state *_state); ae_bool _pexec_testdensesolver(ae_bool silent, ae_state *_state); ae_bool testoptserv(ae_bool silent, ae_state *_state); ae_bool _pexec_testoptserv(ae_bool silent, ae_state *_state); /************************************************************************* Testing *************************************************************************/ ae_bool testfbls(ae_bool silent, ae_state *_state); ae_bool _pexec_testfbls(ae_bool silent, ae_state *_state); ae_bool testcqmodels(ae_bool silent, ae_state *_state); ae_bool _pexec_testcqmodels(ae_bool silent, ae_state *_state); ae_bool testsnnls(ae_bool silent, ae_state *_state); ae_bool _pexec_testsnnls(ae_bool silent, ae_state *_state); ae_bool testsactivesets(ae_bool silent, ae_state *_state); ae_bool _pexec_testsactivesets(ae_bool silent, ae_state *_state); ae_bool testlinmin(ae_bool silent, ae_state *_state); ae_bool _pexec_testlinmin(ae_bool silent, ae_state *_state); ae_bool testmincg(ae_bool silent, ae_state *_state); ae_bool _pexec_testmincg(ae_bool silent, ae_state *_state); /************************************************************************* Other properties *************************************************************************/ void testother(ae_bool* err, ae_state *_state); ae_bool testminbleic(ae_bool silent, ae_state *_state); ae_bool _pexec_testminbleic(ae_bool silent, ae_state *_state); ae_bool testmcpd(ae_bool silent, ae_state *_state); ae_bool _pexec_testmcpd(ae_bool silent, ae_state *_state); ae_bool testmlpe(ae_bool silent, ae_state *_state); ae_bool _pexec_testmlpe(ae_bool silent, ae_state *_state); ae_bool testminlbfgs(ae_bool silent, ae_state *_state); ae_bool _pexec_testminlbfgs(ae_bool silent, ae_state *_state); ae_bool testmlptrain(ae_bool silent, ae_state *_state); ae_bool _pexec_testmlptrain(ae_bool silent, ae_state *_state); ae_bool testpca(ae_bool silent, ae_state *_state); ae_bool _pexec_testpca(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testodesolver(ae_bool silent, ae_state *_state); ae_bool _pexec_testodesolver(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testfft(ae_bool silent, ae_state *_state); ae_bool _pexec_testfft(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testconv(ae_bool silent, ae_state *_state); ae_bool _pexec_testconv(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testcorr(ae_bool silent, ae_state *_state); ae_bool _pexec_testcorr(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testfht(ae_bool silent, ae_state *_state); ae_bool _pexec_testfht(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testgq(ae_bool silent, ae_state *_state); ae_bool _pexec_testgq(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testgkq(ae_bool silent, ae_state *_state); ae_bool _pexec_testgkq(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testautogk(ae_bool silent, ae_state *_state); ae_bool _pexec_testautogk(ae_bool silent, ae_state *_state); /************************************************************************* Testing IDW interpolation *************************************************************************/ ae_bool testidwint(ae_bool silent, ae_state *_state); ae_bool _pexec_testidwint(ae_bool silent, ae_state *_state); ae_bool testratint(ae_bool silent, ae_state *_state); ae_bool _pexec_testratint(ae_bool silent, ae_state *_state); /************************************************************************* Unit test *************************************************************************/ ae_bool testpolint(ae_bool silent, ae_state *_state); ae_bool _pexec_testpolint(ae_bool silent, ae_state *_state); ae_bool testspline1d(ae_bool silent, ae_state *_state); ae_bool _pexec_testspline1d(ae_bool silent, ae_state *_state); ae_bool testnormestimator(ae_bool silent, ae_state *_state); ae_bool _pexec_testnormestimator(ae_bool silent, ae_state *_state); ae_bool testminqp(ae_bool silent, ae_state *_state); ae_bool _pexec_testminqp(ae_bool silent, ae_state *_state); /************************************************************************* Function to test: 'MinQPCreate', 'MinQPSetQuadraticTerm', 'MinQPSetBC', 'MinQPSetOrigin', 'MinQPSetStartingPoint', 'MinQPOptimize', 'MinQPResults'. Test problem: A = diag(aii), aii>0 (random) b = 0 random bounds (either no bounds, one bound, two bounds a 0 without bounds random start point dimension - from 1 to 5. *************************************************************************/ ae_bool functest1(ae_state *_state); /************************************************************************* Function to test: 'MinQPCreate', 'MinQPSetLinearTerm', 'MinQPSetQuadraticTerm', 'MinQPSetBC', 'MinQPSetOrigin', 'MinQPSetStartingPoint', 'MinQPOptimize', 'MinQPResults'. Test problem: A = positive-definite matrix, obtained by 'SPDMatrixRndCond' function b <> 0 boundary constraints random start point dimension - from 1 to 5. *************************************************************************/ ae_bool functest2(ae_state *_state); /************************************************************************* ConsoleTest. *************************************************************************/ ae_bool consoletest(ae_state *_state); /************************************************************************* This function performs tests specific for Cholesky solver Returns True on success, False on failure. *************************************************************************/ ae_bool choleskytests(ae_state *_state); /************************************************************************* This function performs tests specific for QuickQP solver Returns True on failure. *************************************************************************/ ae_bool quickqptests(ae_state *_state); /************************************************************************* This function performs tests specific for BLEIC solver Returns True on error, False on success. *************************************************************************/ ae_bool bleictests(ae_state *_state); ae_bool testminlm(ae_bool silent, ae_state *_state); ae_bool _pexec_testminlm(ae_bool silent, ae_state *_state); ae_bool testlsfit(ae_bool silent, ae_state *_state); ae_bool _pexec_testlsfit(ae_bool silent, ae_state *_state); ae_bool testparametric(ae_bool silent, ae_state *_state); ae_bool _pexec_testparametric(ae_bool silent, ae_state *_state); ae_bool testlinlsqr(ae_bool silent, ae_state *_state); ae_bool _pexec_testlinlsqr(ae_bool silent, ae_state *_state); ae_bool testrbf(ae_bool silent, ae_state *_state); ae_bool _pexec_testrbf(ae_bool silent, ae_state *_state); /************************************************************************* The test has to check, that algorithm can solve problems of matrix are degenerate. * used model with linear term; * points locate in a subspace of dimension less than an original space. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ ae_bool sqrdegmatrixrbftest(ae_bool silent, ae_state *_state); /************************************************************************* Function for testing basic functionality of RBF module on regular grids with multi-layer algorithm in 1D. -- ALGLIB -- Copyright 2.03.2012 by Bochkanov Sergey *************************************************************************/ ae_bool basicmultilayerrbf1dtest(ae_state *_state); ae_bool testspline2d(ae_bool silent, ae_state *_state); ae_bool _pexec_testspline2d(ae_bool silent, ae_state *_state); ae_bool testspline3d(ae_bool silence, ae_state *_state); ae_bool _pexec_testspline3d(ae_bool silence, ae_state *_state); /************************************************************************* Testing bidiagonal SVD decomposition subroutine *************************************************************************/ ae_bool testspdgevd(ae_bool silent, ae_state *_state); ae_bool _pexec_testspdgevd(ae_bool silent, ae_state *_state); ae_bool testinverseupdate(ae_bool silent, ae_state *_state); ae_bool _pexec_testinverseupdate(ae_bool silent, ae_state *_state); /************************************************************************* Testing Schur decomposition subroutine *************************************************************************/ ae_bool testschur(ae_bool silent, ae_state *_state); ae_bool _pexec_testschur(ae_bool silent, ae_state *_state); ae_bool testminnlc(ae_bool silent, ae_state *_state); ae_bool _pexec_testminnlc(ae_bool silent, ae_state *_state); ae_bool testminns(ae_bool silent, ae_state *_state); ae_bool _pexec_testminns(ae_bool silent, ae_state *_state); ae_bool testlincg(ae_bool silent, ae_state *_state); ae_bool _pexec_testlincg(ae_bool silent, ae_state *_state); ae_bool testnleq(ae_bool silent, ae_state *_state); ae_bool _pexec_testnleq(ae_bool silent, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testpolynomialsolver(ae_bool silent, ae_state *_state); ae_bool _pexec_testpolynomialsolver(ae_bool silent, ae_state *_state); ae_bool testchebyshev(ae_bool silent, ae_state *_state); ae_bool _pexec_testchebyshev(ae_bool silent, ae_state *_state); ae_bool testhermite(ae_bool silent, ae_state *_state); ae_bool _pexec_testhermite(ae_bool silent, ae_state *_state); ae_bool testlaguerre(ae_bool silent, ae_state *_state); ae_bool _pexec_testlaguerre(ae_bool silent, ae_state *_state); ae_bool testlegendre(ae_bool silent, ae_state *_state); ae_bool _pexec_testlegendre(ae_bool silent, ae_state *_state); ae_bool teststest(ae_bool silent, ae_state *_state); ae_bool _pexec_teststest(ae_bool silent, ae_state *_state); ae_bool teststudentttests(ae_bool silent, ae_state *_state); ae_bool _pexec_teststudentttests(ae_bool silent, ae_state *_state); typedef struct { ae_bool bfield; double rfield; ae_int_t ifield; ae_complex cfield; ae_vector b1field; ae_vector r1field; ae_vector i1field; ae_vector c1field; ae_matrix b2field; ae_matrix r2field; ae_matrix i2field; ae_matrix c2field; } rec1; typedef struct { ae_vector b; ae_vector i; ae_vector r; } rec4serialization; typedef struct { ae_complex cval; double rval; ae_int_t ival; ae_bool bval; ae_vector i1val; } poolrec1; typedef struct { ae_bool bval; poolrec1 recval; ae_shared_pool pool; } poolrec2; typedef struct { ae_int_t val; } poolsummand; void rec4serializationalloc(ae_serializer* s, rec4serialization* v, ae_state *_state); void rec4serializationserialize(ae_serializer* s, rec4serialization* v, ae_state *_state); void rec4serializationunserialize(ae_serializer* s, rec4serialization* v, ae_state *_state); ae_bool testalglibbasics(ae_bool silent, ae_state *_state); ae_bool _pexec_testalglibbasics(ae_bool silent, ae_state *_state); void _rec1_init(void* _p, ae_state *_state); void _rec1_init_copy(void* _dst, void* _src, ae_state *_state); void _rec1_clear(void* _p); void _rec1_destroy(void* _p); void _rec4serialization_init(void* _p, ae_state *_state); void _rec4serialization_init_copy(void* _dst, void* _src, ae_state *_state); void _rec4serialization_clear(void* _p); void _rec4serialization_destroy(void* _p); void _poolrec1_init(void* _p, ae_state *_state); void _poolrec1_init_copy(void* _dst, void* _src, ae_state *_state); void _poolrec1_clear(void* _p); void _poolrec1_destroy(void* _p); void _poolrec2_init(void* _p, ae_state *_state); void _poolrec2_init_copy(void* _dst, void* _src, ae_state *_state); void _poolrec2_clear(void* _p); void _poolrec2_destroy(void* _p); void _poolsummand_init(void* _p, ae_state *_state); void _poolsummand_init_copy(void* _dst, void* _src, ae_state *_state); void _poolsummand_clear(void* _p); void _poolsummand_destroy(void* _p); static void testhqrndunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state); static void testhqrndunit_unsetstate(hqrndstate* state, ae_state *_state); ae_bool testhqrnd(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_int_t samplesize; double sigmathreshold; ae_int_t passcount; ae_int_t n; ae_int_t i; ae_int_t k; ae_int_t pass; ae_int_t s1; ae_int_t s2; ae_int_t i1; ae_int_t i2; double r1; double r2; ae_vector x; ae_vector bins; double mean; double means; double stddev; double stddevs; double lambdav; ae_bool seederrors; ae_bool urerrors; double ursigmaerr; ae_bool uierrors; double uisigmaerr; ae_bool normerrors; double normsigmaerr; ae_bool unit2errors; ae_bool experrors; double expsigmaerr; ae_bool discreteerr; ae_bool continuouserr; hqrndstate state; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&bins, 0, DT_INT, _state); _hqrndstate_init(&state, _state); waserrors = ae_false; sigmathreshold = (double)(7); samplesize = 100000; passcount = 50; seederrors = ae_false; urerrors = ae_false; uierrors = ae_false; normerrors = ae_false; experrors = ae_false; unit2errors = ae_false; ae_vector_set_length(&x, samplesize-1+1, _state); /* * Test seed errors */ for(pass=1; pass<=passcount; pass++) { s1 = 1+ae_randominteger(32000, _state); s2 = 1+ae_randominteger(32000, _state); testhqrndunit_unsetstate(&state, _state); hqrndseed(s1, s2, &state, _state); i1 = hqrnduniformi(&state, 100, _state); testhqrndunit_unsetstate(&state, _state); hqrndseed(s1, s2, &state, _state); i2 = hqrnduniformi(&state, 100, _state); seederrors = seederrors||i1!=i2; testhqrndunit_unsetstate(&state, _state); hqrndseed(s1, s2, &state, _state); r1 = hqrnduniformr(&state, _state); testhqrndunit_unsetstate(&state, _state); hqrndseed(s1, s2, &state, _state); r2 = hqrnduniformr(&state, _state); seederrors = seederrors||ae_fp_neq(r1,r2); } /* * Test HQRNDRandomize() and real uniform generator */ testhqrndunit_unsetstate(&state, _state); hqrndrandomize(&state, _state); ursigmaerr = (double)(0); for(i=0; i<=samplesize-1; i++) { x.ptr.p_double[i] = hqrnduniformr(&state, _state); } for(i=0; i<=samplesize-1; i++) { urerrors = (urerrors||ae_fp_less_eq(x.ptr.p_double[i],(double)(0)))||ae_fp_greater_eq(x.ptr.p_double[i],(double)(1)); } testhqrndunit_calculatemv(&x, samplesize, &mean, &means, &stddev, &stddevs, _state); if( ae_fp_neq(means,(double)(0)) ) { ursigmaerr = ae_maxreal(ursigmaerr, ae_fabs((mean-0.5)/means, _state), _state); } else { urerrors = ae_true; } if( ae_fp_neq(stddevs,(double)(0)) ) { ursigmaerr = ae_maxreal(ursigmaerr, ae_fabs((stddev-ae_sqrt((double)1/(double)12, _state))/stddevs, _state), _state); } else { urerrors = ae_true; } urerrors = urerrors||ae_fp_greater(ursigmaerr,sigmathreshold); /* * Test HQRNDRandomize() and integer uniform */ testhqrndunit_unsetstate(&state, _state); hqrndrandomize(&state, _state); uisigmaerr = (double)(0); for(n=2; n<=10; n++) { for(i=0; i<=samplesize-1; i++) { x.ptr.p_double[i] = (double)(hqrnduniformi(&state, n, _state)); } for(i=0; i<=samplesize-1; i++) { uierrors = (uierrors||ae_fp_less(x.ptr.p_double[i],(double)(0)))||ae_fp_greater_eq(x.ptr.p_double[i],(double)(n)); } testhqrndunit_calculatemv(&x, samplesize, &mean, &means, &stddev, &stddevs, _state); if( ae_fp_neq(means,(double)(0)) ) { uisigmaerr = ae_maxreal(uisigmaerr, ae_fabs((mean-0.5*(n-1))/means, _state), _state); } else { uierrors = ae_true; } if( ae_fp_neq(stddevs,(double)(0)) ) { uisigmaerr = ae_maxreal(uisigmaerr, ae_fabs((stddev-ae_sqrt((ae_sqr((double)(n), _state)-1)/12, _state))/stddevs, _state), _state); } else { uierrors = ae_true; } } uierrors = uierrors||ae_fp_greater(uisigmaerr,sigmathreshold); /* * Special 'close-to-limit' test on uniformity of integers * (straightforward implementation like 'RND mod N' will return * non-uniform numbers for N=2/3*LIMIT) */ testhqrndunit_unsetstate(&state, _state); hqrndrandomize(&state, _state); uisigmaerr = (double)(0); n = 1431655708; for(i=0; i<=samplesize-1; i++) { x.ptr.p_double[i] = (double)(hqrnduniformi(&state, n, _state)); } for(i=0; i<=samplesize-1; i++) { uierrors = (uierrors||ae_fp_less(x.ptr.p_double[i],(double)(0)))||ae_fp_greater_eq(x.ptr.p_double[i],(double)(n)); } testhqrndunit_calculatemv(&x, samplesize, &mean, &means, &stddev, &stddevs, _state); if( ae_fp_neq(means,(double)(0)) ) { uisigmaerr = ae_maxreal(uisigmaerr, ae_fabs((mean-0.5*(n-1))/means, _state), _state); } else { uierrors = ae_true; } if( ae_fp_neq(stddevs,(double)(0)) ) { uisigmaerr = ae_maxreal(uisigmaerr, ae_fabs((stddev-ae_sqrt((ae_sqr((double)(n), _state)-1)/12, _state))/stddevs, _state), _state); } else { uierrors = ae_true; } uierrors = uierrors||ae_fp_greater(uisigmaerr,sigmathreshold); /* * Test normal */ testhqrndunit_unsetstate(&state, _state); hqrndrandomize(&state, _state); normsigmaerr = (double)(0); i = 0; while(i=bins.cnt ) { k = bins.cnt-1; } bins.ptr.p_int[k] = bins.ptr.p_int[k]+1; } for(i=0; i<=bins.cnt-1; i++) { seterrorflag(&unit2errors, ae_fp_less((double)(bins.ptr.p_int[i]),0.9*n/bins.cnt)||ae_fp_greater((double)(bins.ptr.p_int[i]),1.1*n/bins.cnt), _state); } /* * Test exponential */ testhqrndunit_unsetstate(&state, _state); hqrndrandomize(&state, _state); expsigmaerr = (double)(0); lambdav = 2+5*ae_randomreal(_state); for(i=0; i<=samplesize-1; i++) { x.ptr.p_double[i] = hqrndexponential(&state, lambdav, _state); } for(i=0; i<=samplesize-1; i++) { uierrors = uierrors||ae_fp_less(x.ptr.p_double[i],(double)(0)); } testhqrndunit_calculatemv(&x, samplesize, &mean, &means, &stddev, &stddevs, _state); if( ae_fp_neq(means,(double)(0)) ) { expsigmaerr = ae_maxreal(expsigmaerr, ae_fabs((mean-1.0/lambdav)/means, _state), _state); } else { experrors = ae_true; } if( ae_fp_neq(stddevs,(double)(0)) ) { expsigmaerr = ae_maxreal(expsigmaerr, ae_fabs((stddev-1.0/lambdav)/stddevs, _state), _state); } else { experrors = ae_true; } experrors = experrors||ae_fp_greater(expsigmaerr,sigmathreshold); /* *Discrete/Continuous tests */ discreteerr = hqrnddiscretetest(ae_true, _state); continuouserr = hqrndcontinuoustest(ae_true, _state); /* * Final report */ waserrors = ((((((seederrors||urerrors)||uierrors)||normerrors)||unit2errors)||experrors)||discreteerr)||continuouserr; if( !silent ) { printf("RNG TEST\n"); printf("SEED TEST: "); if( !seederrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("UNIFORM CONTINUOUS: "); if( !urerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("UNIFORM INTEGER: "); if( !uierrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("NORMAL: "); if( !normerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("UNIT2: "); if( !unit2errors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("EXPONENTIAL: "); if( !experrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("DISCRETE: "); if( !discreteerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("CONTINUOUS: "); if( !continuouserr ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testhqrnd(ae_bool silent, ae_state *_state) { return testhqrnd(silent, _state); } /************************************************************************* Function for test HQRNDContinuous function *************************************************************************/ ae_bool hqrndcontinuoustest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_vector sample; ae_vector bins; ae_vector binbounds; ae_int_t nb; ae_int_t samplesize; hqrndstate state; ae_int_t xp; ae_int_t i; ae_int_t j; double v; double sigma; double sigmamax; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&sample, 0, DT_REAL, _state); ae_vector_init(&bins, 0, DT_INT, _state); ae_vector_init(&binbounds, 0, DT_REAL, _state); _hqrndstate_init(&state, _state); result = ae_false; /* * Test for sample size equal to 1 */ ae_vector_set_length(&sample, 1, _state); sample.ptr.p_double[0] = ae_randomreal(_state); hqrndrandomize(&state, _state); result = result||ae_fp_neq(hqrndcontinuous(&state, &sample, 1, _state),sample.ptr.p_double[0]); /* * Test for larger samples */ xp = 100000; sigmamax = 10.0; for(samplesize=2; samplesize<=5; samplesize++) { /* * 1. Generate random sample with SampleSize points * 2. Generate NB=3*(SampleSize-1) bins, with bounds as prescribed by (BinBounds[I],BinBounds[I+1]). * Bin bounds are generated in such a way that value can fall into any bin with same probability * 3. Generate many random values * 4. Calculate number of values which fall into each bin * 5. Bins[I] should have binomial distribution with mean XP/NB and * variance XP*(1/NB)*(1-1/NB) */ nb = 3*(samplesize-1); sigma = ae_sqrt(xp*((double)1/(double)nb)*(1-(double)1/(double)nb), _state); ae_vector_set_length(&sample, samplesize, _state); sample.ptr.p_double[0] = 2*ae_randomreal(_state)-1; for(i=0; i<=samplesize-2; i++) { sample.ptr.p_double[i+1] = sample.ptr.p_double[i]+0.1+ae_randomreal(_state); } ae_vector_set_length(&bins, nb, _state); ae_vector_set_length(&binbounds, nb+1, _state); for(i=0; i<=samplesize-2; i++) { bins.ptr.p_int[3*i+0] = 0; bins.ptr.p_int[3*i+1] = 0; bins.ptr.p_int[3*i+2] = 0; binbounds.ptr.p_double[3*i+0] = sample.ptr.p_double[i]; binbounds.ptr.p_double[3*i+1] = sample.ptr.p_double[i]+(sample.ptr.p_double[i+1]-sample.ptr.p_double[i])/3; binbounds.ptr.p_double[3*i+2] = sample.ptr.p_double[i]+(sample.ptr.p_double[i+1]-sample.ptr.p_double[i])*2/3; } binbounds.ptr.p_double[nb] = sample.ptr.p_double[samplesize-1]; hqrndrandomize(&state, _state); for(i=0; i<=xp-1; i++) { v = hqrndcontinuous(&state, &sample, samplesize, _state); for(j=0; j<=nb-1; j++) { if( ae_fp_greater(v,binbounds.ptr.p_double[j])&&ae_fp_less(v,binbounds.ptr.p_double[j+1]) ) { bins.ptr.p_int[j] = bins.ptr.p_int[j]+1; break; } } } for(i=0; i<=nb-1; i++) { result = result||ae_fp_greater(ae_fabs(bins.ptr.p_int[i]-(double)xp/(double)nb, _state),sigma*sigmamax); } } ae_frame_leave(_state); return result; } /************************************************************************* Function for test HQRNDContinuous function *************************************************************************/ ae_bool hqrnddiscretetest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_vector sample; double sigma; double sigmathreshold; double tsample; double max; double min; ae_int_t i; ae_int_t j; ae_int_t s1; ae_int_t s2; ae_int_t binscount; ae_int_t xp; ae_vector nn; hqrndstate state; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&sample, 0, DT_REAL, _state); ae_vector_init(&nn, 0, DT_INT, _state); _hqrndstate_init(&state, _state); /* * We test that all values from discrete sample are generated with same probability. * To do this, we generate random values many times, then we calculate actual probabilities * and compare them with theoretical ones. */ max = (double)(100); min = (double)(-100); xp = 100000; sigmathreshold = 10.0; for(binscount=1; binscount<=5; binscount++) { sigma = ae_sqrt(xp*((double)1/(double)binscount)*(1-(double)1/(double)binscount), _state); ae_vector_set_length(&nn, binscount, _state); for(i=0; i<=binscount-1; i++) { nn.ptr.p_int[i] = 0; } ae_vector_set_length(&sample, binscount, _state); sample.ptr.p_double[0] = (max-min)*ae_randomreal(_state)+min; for(i=1; i<=binscount-1; i++) { sample.ptr.p_double[i] = sample.ptr.p_double[i-1]+max*ae_randomreal(_state)+0.001; } s1 = 1+ae_randominteger(32000, _state); s2 = 1+ae_randominteger(32000, _state); hqrndseed(s1, s2, &state, _state); for(i=0; i<=xp-1; i++) { tsample = hqrnddiscrete(&state, &sample, binscount, _state); for(j=0; j<=binscount-1; j++) { if( ae_fp_eq(tsample,sample.ptr.p_double[j]) ) { nn.ptr.p_int[j] = nn.ptr.p_int[j]+1; break; } } } for(i=0; i<=binscount-1; i++) { if( ae_fp_less((double)(nn.ptr.p_int[i]),(double)xp/(double)binscount-sigmathreshold*sigma)||ae_fp_greater((double)(nn.ptr.p_int[i]),(double)xp/(double)binscount+sigmathreshold*sigma) ) { if( !silent ) { printf("HQRNDDiscreteTest::ErrorReport::\n"); printf("nn[%0d]=%0d;\n xp/BinsCount=%0.5f;\n C*sigma=%0.5f\n", (int)(i), (int)(nn.ptr.p_int[i]), (double)((double)xp/(double)binscount), (double)(sigmathreshold*sigma)); printf("HQRNDDiscreteTest: test is FAILED!\n"); } result = ae_true; ae_frame_leave(_state); return result; } } if( !silent ) { printf("HQRNDDiscreteTest: test is OK.\n"); } } result = ae_false; ae_frame_leave(_state); return result; } static void testhqrndunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state) { ae_int_t i; double v1; double v2; double variance; *mean = 0; *means = 0; *stddev = 0; *stddevs = 0; *mean = (double)(0); *means = (double)(1); *stddev = (double)(0); *stddevs = (double)(1); variance = (double)(0); if( n<=1 ) { return; } /* * Mean */ for(i=0; i<=n-1; i++) { *mean = *mean+x->ptr.p_double[i]; } *mean = *mean/n; /* * Variance (using corrected two-pass algorithm) */ if( n!=1 ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-(*mean)); } v2 = ae_sqr(v2, _state)/n; variance = (v1-v2)/(n-1); if( ae_fp_less(variance,(double)(0)) ) { variance = (double)(0); } *stddev = ae_sqrt(variance, _state); } /* * Errors */ *means = *stddev/ae_sqrt((double)(n), _state); *stddevs = *stddev*ae_sqrt((double)(2), _state)/ae_sqrt((double)(n-1), _state); } /************************************************************************* Unsets HQRNDState structure *************************************************************************/ static void testhqrndunit_unsetstate(hqrndstate* state, ae_state *_state) { state->s1 = 0; state->s2 = 0; state->magicv = 0; } static void testtsortunit_unset1di(/* Integer */ ae_vector* a, ae_state *_state); static void testtsortunit_testsortresults(/* Real */ ae_vector* asorted, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, /* Real */ ae_vector* aoriginal, ae_int_t n, ae_bool* waserrors, ae_state *_state); /************************************************************************* Testing tag sort *************************************************************************/ ae_bool testtsort(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_int_t n; ae_int_t i; ae_int_t m; ae_int_t offs; ae_int_t pass; ae_int_t passcount; ae_int_t maxn; ae_vector a; ae_vector a0; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector i1; ae_vector i2; ae_vector i3; ae_vector a4; ae_vector pa4; ae_vector ar; ae_vector ar2; ae_vector ai; ae_vector p1; ae_vector p2; ae_vector bufr1; ae_vector bufr2; ae_vector bufi1; ae_bool distinctvals; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&a0, 0, DT_REAL, _state); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&a3, 0, DT_REAL, _state); ae_vector_init(&i1, 0, DT_INT, _state); ae_vector_init(&i2, 0, DT_INT, _state); ae_vector_init(&i3, 0, DT_INT, _state); ae_vector_init(&a4, 0, DT_INT, _state); ae_vector_init(&pa4, 0, DT_INT, _state); ae_vector_init(&ar, 0, DT_REAL, _state); ae_vector_init(&ar2, 0, DT_REAL, _state); ae_vector_init(&ai, 0, DT_INT, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); ae_vector_init(&bufr1, 0, DT_REAL, _state); ae_vector_init(&bufr2, 0, DT_REAL, _state); ae_vector_init(&bufi1, 0, DT_INT, _state); waserrors = ae_false; maxn = 100; passcount = 10; /* * Test tagsort */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { /* * Pprobably distinct sort: * * generate array of integer random numbers. * Because of birthday paradox, random numbers have to be VERY large * in order to avoid situation when we have distinct values. * * sort A0 using TagSort and test sort results * * now we can use A0 as reference point and test other functions */ testtsortunit_unset1di(&p1, _state); testtsortunit_unset1di(&p2, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&a0, n, _state); ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); ae_vector_set_length(&a3, n, _state); ae_vector_set_length(&a4, n, _state); ae_vector_set_length(&ar, n, _state); ae_vector_set_length(&ar2, n, _state); ae_vector_set_length(&ai, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(ae_randominteger(100000000, _state)); a0.ptr.p_double[i] = a.ptr.p_double[i]; a1.ptr.p_double[i] = a.ptr.p_double[i]; a2.ptr.p_double[i] = a.ptr.p_double[i]; a3.ptr.p_double[i] = a.ptr.p_double[i]; a4.ptr.p_int[i] = ae_round(a.ptr.p_double[i], _state); ar.ptr.p_double[i] = (double)(i); ar2.ptr.p_double[i] = (double)(i); ai.ptr.p_int[i] = i; } tagsort(&a0, n, &p1, &p2, _state); testtsortunit_testsortresults(&a0, &p1, &p2, &a, n, &waserrors, _state); distinctvals = ae_true; for(i=1; i<=n-1; i++) { distinctvals = distinctvals&&ae_fp_neq(a0.ptr.p_double[i],a0.ptr.p_double[i-1]); } if( distinctvals ) { tagsortfasti(&a1, &ai, &bufr1, &bufi1, n, _state); for(i=0; i<=n-1; i++) { waserrors = (waserrors||ae_fp_neq(a1.ptr.p_double[i],a0.ptr.p_double[i]))||ai.ptr.p_int[i]!=p1.ptr.p_int[i]; } tagsortfastr(&a2, &ar, &bufr1, &bufr2, n, _state); for(i=0; i<=n-1; i++) { waserrors = (waserrors||ae_fp_neq(a2.ptr.p_double[i],a0.ptr.p_double[i]))||ae_fp_neq(ar.ptr.p_double[i],(double)(p1.ptr.p_int[i])); } tagsortfast(&a3, &bufr1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a3.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortmiddleir(&a4, &ar2, 0, n, _state); for(i=0; i<=n-1; i++) { waserrors = (waserrors||ae_fp_neq((double)(a4.ptr.p_int[i]),a0.ptr.p_double[i]))||ae_fp_neq(ar2.ptr.p_double[i],(double)(p1.ptr.p_int[i])); } } /* * Non-distinct sort. * We test that keys are correctly reordered, but do NOT test order of values. */ testtsortunit_unset1di(&p1, _state); testtsortunit_unset1di(&p2, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&a0, n, _state); ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); ae_vector_set_length(&a3, n, _state); ae_vector_set_length(&a4, n, _state); ae_vector_set_length(&ar, n, _state); ae_vector_set_length(&ar2, n, _state); ae_vector_set_length(&ai, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)((n-i)/2); a0.ptr.p_double[i] = a.ptr.p_double[i]; a1.ptr.p_double[i] = a.ptr.p_double[i]; a2.ptr.p_double[i] = a.ptr.p_double[i]; a3.ptr.p_double[i] = a.ptr.p_double[i]; a4.ptr.p_int[i] = ae_round(a.ptr.p_double[i], _state); ar.ptr.p_double[i] = (double)(i); ar2.ptr.p_double[i] = (double)(i); ai.ptr.p_int[i] = i; } tagsort(&a0, n, &p1, &p2, _state); testtsortunit_testsortresults(&a0, &p1, &p2, &a, n, &waserrors, _state); tagsortfasti(&a1, &ai, &bufr1, &bufi1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a1.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfastr(&a2, &ar, &bufr1, &bufr2, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a2.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfast(&a3, &bufr1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a3.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortmiddleir(&a4, &ar2, 0, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq((double)(a4.ptr.p_int[i]),a0.ptr.p_double[i]); } /* * 'All same' sort * We test that keys are correctly reordered, but do NOT test order of values. */ testtsortunit_unset1di(&p1, _state); testtsortunit_unset1di(&p2, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&a0, n, _state); ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); ae_vector_set_length(&a3, n, _state); ae_vector_set_length(&a4, n, _state); ae_vector_set_length(&ar, n, _state); ae_vector_set_length(&ar2, n, _state); ae_vector_set_length(&ai, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(0); a0.ptr.p_double[i] = a.ptr.p_double[i]; a1.ptr.p_double[i] = a.ptr.p_double[i]; a2.ptr.p_double[i] = a.ptr.p_double[i]; a3.ptr.p_double[i] = a.ptr.p_double[i]; a4.ptr.p_int[i] = ae_round(a.ptr.p_double[i], _state); ar.ptr.p_double[i] = (double)(i); ar2.ptr.p_double[i] = (double)(i); ai.ptr.p_int[i] = i; } tagsort(&a0, n, &p1, &p2, _state); testtsortunit_testsortresults(&a0, &p1, &p2, &a, n, &waserrors, _state); tagsortfasti(&a1, &ai, &bufr1, &bufi1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a1.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfastr(&a2, &ar, &bufr1, &bufr2, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a2.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfast(&a3, &bufr1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a3.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortmiddleir(&a4, &ar2, 0, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq((double)(a4.ptr.p_int[i]),a0.ptr.p_double[i]); } /* * 0-1 sort * We test that keys are correctly reordered, but do NOT test order of values. */ testtsortunit_unset1di(&p1, _state); testtsortunit_unset1di(&p2, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&a0, n, _state); ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); ae_vector_set_length(&a3, n, _state); ae_vector_set_length(&a4, n, _state); ae_vector_set_length(&ar, n, _state); ae_vector_set_length(&ar2, n, _state); ae_vector_set_length(&ai, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(ae_randominteger(2, _state)); a0.ptr.p_double[i] = a.ptr.p_double[i]; a1.ptr.p_double[i] = a.ptr.p_double[i]; a2.ptr.p_double[i] = a.ptr.p_double[i]; a3.ptr.p_double[i] = a.ptr.p_double[i]; a4.ptr.p_int[i] = ae_round(a.ptr.p_double[i], _state); ar.ptr.p_double[i] = (double)(i); ar2.ptr.p_double[i] = (double)(i); ai.ptr.p_int[i] = i; } tagsort(&a0, n, &p1, &p2, _state); testtsortunit_testsortresults(&a0, &p1, &p2, &a, n, &waserrors, _state); tagsortfasti(&a1, &ai, &bufr1, &bufi1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a1.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfastr(&a2, &ar, &bufr1, &bufr2, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a2.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortfast(&a3, &bufr1, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq(a3.ptr.p_double[i],a0.ptr.p_double[i]); } tagsortmiddleir(&a4, &ar2, 0, n, _state); for(i=0; i<=n-1; i++) { waserrors = waserrors||ae_fp_neq((double)(a4.ptr.p_int[i]),a0.ptr.p_double[i]); } /* * Special test for TagSortMiddleIR: sorting in the middle gives same results * as sorting in the beginning of the array */ m = 3*n; offs = ae_randominteger(n, _state); ae_vector_set_length(&i1, m, _state); ae_vector_set_length(&i2, m, _state); ae_vector_set_length(&i3, m, _state); ae_vector_set_length(&ar, m, _state); ae_vector_set_length(&ar2, m, _state); for(i=0; i<=m-1; i++) { i1.ptr.p_int[i] = ae_randominteger(100000000, _state); i2.ptr.p_int[i] = i1.ptr.p_int[i]; i3.ptr.p_int[i] = i1.ptr.p_int[i]; ar.ptr.p_double[i] = (double)(i); ar2.ptr.p_double[i] = (double)(i); } for(i=0; i<=n-1; i++) { i1.ptr.p_int[i] = i1.ptr.p_int[offs+i]; ar.ptr.p_double[i] = ar.ptr.p_double[offs+i]; } tagsortmiddleir(&i1, &ar, 0, n, _state); for(i=1; i<=n-1; i++) { distinctvals = distinctvals&&i1.ptr.p_int[i]!=i1.ptr.p_int[i-1]; } if( distinctvals ) { tagsortmiddleir(&i2, &ar2, offs, n, _state); for(i=0; i<=n-1; i++) { waserrors = (waserrors||i2.ptr.p_int[offs+i]!=i1.ptr.p_int[i])||ae_fp_neq(ar2.ptr.p_double[offs+i],ar.ptr.p_double[i]); } } } } /* * report */ if( !silent ) { printf("TESTING TAGSORT\n"); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testtsort(ae_bool silent, ae_state *_state) { return testtsort(silent, _state); } /************************************************************************* Unsets 1D array. *************************************************************************/ static void testtsortunit_unset1di(/* Integer */ ae_vector* a, ae_state *_state) { ae_vector_set_length(a, 0+1, _state); a->ptr.p_int[0] = ae_randominteger(3, _state)-1; } static void testtsortunit_testsortresults(/* Real */ ae_vector* asorted, /* Integer */ ae_vector* p1, /* Integer */ ae_vector* p2, /* Real */ ae_vector* aoriginal, ae_int_t n, ae_bool* waserrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_vector a2; double t; ae_vector f; ae_frame_make(_state, &_frame_block); ae_vector_init(&a2, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_INT, _state); ae_vector_set_length(&a2, n-1+1, _state); ae_vector_set_length(&f, n-1+1, _state); /* * is set ordered? */ for(i=0; i<=n-2; i++) { *waserrors = *waserrors||ae_fp_greater(asorted->ptr.p_double[i],asorted->ptr.p_double[i+1]); } /* * P1 correctness */ for(i=0; i<=n-1; i++) { *waserrors = *waserrors||ae_fp_neq(asorted->ptr.p_double[i],aoriginal->ptr.p_double[p1->ptr.p_int[i]]); } for(i=0; i<=n-1; i++) { f.ptr.p_int[i] = 0; } for(i=0; i<=n-1; i++) { f.ptr.p_int[p1->ptr.p_int[i]] = f.ptr.p_int[p1->ptr.p_int[i]]+1; } for(i=0; i<=n-1; i++) { *waserrors = *waserrors||f.ptr.p_int[i]!=1; } /* * P2 correctness */ for(i=0; i<=n-1; i++) { a2.ptr.p_double[i] = aoriginal->ptr.p_double[i]; } for(i=0; i<=n-1; i++) { if( p2->ptr.p_int[i]!=i ) { t = a2.ptr.p_double[i]; a2.ptr.p_double[i] = a2.ptr.p_double[p2->ptr.p_int[i]]; a2.ptr.p_double[p2->ptr.p_int[i]] = t; } } for(i=0; i<=n-1; i++) { *waserrors = *waserrors||ae_fp_neq(asorted->ptr.p_double[i],a2.ptr.p_double[i]); } ae_frame_leave(_state); } static ae_bool testnearestneighborunit_kdtresultsdifferent(/* Real */ ae_matrix* refxy, ae_int_t ntotal, /* Real */ ae_matrix* qx, /* Real */ ae_matrix* qxy, /* Integer */ ae_vector* qt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state); static double testnearestneighborunit_vnorm(/* Real */ ae_vector* x, ae_int_t n, ae_int_t normtype, ae_state *_state); static void testnearestneighborunit_testkdtuniform(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, ae_bool* kdterrors, ae_state *_state); static void testnearestneighborunit_testkdtreeserialization(ae_bool* err, ae_state *_state); static ae_bool testnearestneighborunit_testspecialcases(ae_state *_state); /************************************************************************* Testing Nearest Neighbor Search *************************************************************************/ ae_bool testnearestneighbor(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_int_t i; ae_int_t j; double v; ae_int_t normtype; ae_int_t nx; ae_int_t ny; ae_int_t n; ae_int_t smalln; ae_int_t largen; ae_int_t passcount; ae_int_t pass; ae_bool waserrors; ae_bool kdterrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); kdterrors = ae_false; passcount = 2; smalln = 256; largen = 2048; ny = 3; /* * */ testnearestneighborunit_testkdtreeserialization(&kdterrors, _state); for(pass=1; pass<=passcount; pass++) { for(normtype=0; normtype<=2; normtype++) { for(nx=1; nx<=3; nx++) { /* * Test in hypercube */ ae_matrix_set_length(&xy, largen, nx+ny, _state); for(i=0; i<=largen-1; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[i][j] = 10*ae_randomreal(_state)-5; } } for(n=1; n<=10; n++) { testnearestneighborunit_testkdtuniform(&xy, n, nx, ae_randominteger(ny+1, _state), normtype, &kdterrors, _state); } testnearestneighborunit_testkdtuniform(&xy, largen, nx, ae_randominteger(ny+1, _state), normtype, &kdterrors, _state); /* * Test clustered (2*N points, pairs of equal points) */ ae_matrix_set_length(&xy, 2*smalln, nx+ny, _state); for(i=0; i<=smalln-1; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[2*i+0][j] = 10*ae_randomreal(_state)-5; xy.ptr.pp_double[2*i+1][j] = xy.ptr.pp_double[2*i+0][j]; } } testnearestneighborunit_testkdtuniform(&xy, 2*smalln, nx, ae_randominteger(ny+1, _state), normtype, &kdterrors, _state); /* * Test degenerate case: all points are same except for one */ ae_matrix_set_length(&xy, smalln, nx+ny, _state); v = ae_randomreal(_state); for(i=0; i<=smalln-2; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[i][j] = v; } } for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[smalln-1][j] = 10*ae_randomreal(_state)-5; } testnearestneighborunit_testkdtuniform(&xy, smalln, nx, ae_randominteger(ny+1, _state), normtype, &kdterrors, _state); } } } kdterrors = kdterrors||testnearestneighborunit_testspecialcases(_state); /* * report */ waserrors = kdterrors; if( !silent ) { printf("TESTING NEAREST NEIGHBOR SEARCH\n"); printf("* KD TREES: "); if( !kdterrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testnearestneighbor(ae_bool silent, ae_state *_state) { return testnearestneighbor(silent, _state); } /************************************************************************* Compare results from different queries: * X just X-values * XY X-values and Y-values * XT X-values and tag values *************************************************************************/ static ae_bool testnearestneighborunit_kdtresultsdifferent(/* Real */ ae_matrix* refxy, ae_int_t ntotal, /* Real */ ae_matrix* qx, /* Real */ ae_matrix* qxy, /* Integer */ ae_vector* qt, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_false; for(i=0; i<=n-1; i++) { if( qt->ptr.p_int[i]<0||qt->ptr.p_int[i]>=ntotal ) { result = ae_true; return result; } for(j=0; j<=nx-1; j++) { result = result||ae_fp_neq(qx->ptr.pp_double[i][j],refxy->ptr.pp_double[qt->ptr.p_int[i]][j]); result = result||ae_fp_neq(qxy->ptr.pp_double[i][j],refxy->ptr.pp_double[qt->ptr.p_int[i]][j]); } for(j=0; j<=ny-1; j++) { result = result||ae_fp_neq(qxy->ptr.pp_double[i][nx+j],refxy->ptr.pp_double[qt->ptr.p_int[i]][nx+j]); } } return result; } /************************************************************************* Returns norm *************************************************************************/ static double testnearestneighborunit_vnorm(/* Real */ ae_vector* x, ae_int_t n, ae_int_t normtype, ae_state *_state) { ae_int_t i; double result; result = ae_randomreal(_state); if( normtype==0 ) { result = (double)(0); for(i=0; i<=n-1; i++) { result = ae_maxreal(result, ae_fabs(x->ptr.p_double[i], _state), _state); } return result; } if( normtype==1 ) { result = (double)(0); for(i=0; i<=n-1; i++) { result = result+ae_fabs(x->ptr.p_double[i], _state); } return result; } if( normtype==2 ) { result = (double)(0); for(i=0; i<=n-1; i++) { result = result+ae_sqr(x->ptr.p_double[i], _state); } result = ae_sqrt(result, _state); return result; } return result; } /************************************************************************* Testing Nearest Neighbor Search on uniformly distributed hypercube NormType: 0, 1, 2 D: space dimension N: points count *************************************************************************/ static void testnearestneighborunit_testkdtuniform(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, ae_bool* kdterrors, ae_state *_state) { ae_frame _frame_block; double errtol; ae_vector tags; ae_vector ptx; ae_vector tmpx; ae_vector tmpb; kdtree treex; kdtree treexy; kdtree treext; ae_matrix qx; ae_matrix qxy; ae_vector qtags; ae_vector qr; ae_int_t kx; ae_int_t kxy; ae_int_t kt; double eps; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t task; ae_bool isequal; double r; ae_int_t q; ae_int_t qcount; ae_frame_make(_state, &_frame_block); ae_vector_init(&tags, 0, DT_INT, _state); ae_vector_init(&ptx, 0, DT_REAL, _state); ae_vector_init(&tmpx, 0, DT_REAL, _state); ae_vector_init(&tmpb, 0, DT_BOOL, _state); _kdtree_init(&treex, _state); _kdtree_init(&treexy, _state); _kdtree_init(&treext, _state); ae_matrix_init(&qx, 0, 0, DT_REAL, _state); ae_matrix_init(&qxy, 0, 0, DT_REAL, _state); ae_vector_init(&qtags, 0, DT_INT, _state); ae_vector_init(&qr, 0, DT_REAL, _state); qcount = 10; /* * Tol - roundoff error tolerance (for '>=' comparisons) */ errtol = 100000*ae_machineepsilon; /* * fill tags */ ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { tags.ptr.p_int[i] = i; } /* * build trees */ kdtreebuild(xy, n, nx, 0, normtype, &treex, _state); kdtreebuild(xy, n, nx, ny, normtype, &treexy, _state); kdtreebuildtagged(xy, &tags, n, nx, 0, normtype, &treext, _state); /* * allocate arrays */ ae_vector_set_length(&tmpx, nx, _state); ae_vector_set_length(&tmpb, n, _state); ae_matrix_set_length(&qx, n, nx, _state); ae_matrix_set_length(&qxy, n, nx+ny, _state); ae_vector_set_length(&qtags, n, _state); ae_vector_set_length(&qr, n, _state); ae_vector_set_length(&ptx, nx, _state); /* * test general K-NN queries (with self-matches): * * compare results from different trees (must be equal) and * check that correct (value,tag) pairs are returned * * test results from XT tree - let R be radius of query result. * then all points not in result must be not closer than R. */ for(q=1; q<=qcount; q++) { /* * Select K: 1..N */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { k = 1+ae_randominteger(n, _state); } else { k = 1; } /* * Select point (either one of the points, or random) */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { i = ae_randominteger(n, _state); ae_v_move(&ptx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); } else { for(i=0; i<=nx-1; i++) { ptx.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } /* * Test: * * consistency of results from different queries * * points in query are IN the R-sphere (or at the boundary), * and points not in query are outside of the R-sphere (or at the boundary) * * distances are correct and are ordered */ kx = kdtreequeryknn(&treex, &ptx, k, ae_true, _state); kxy = kdtreequeryknn(&treexy, &ptx, k, ae_true, _state); kt = kdtreequeryknn(&treext, &ptx, k, ae_true, _state); if( (kx!=k||kxy!=k)||kt!=k ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } kdtreequeryresultsxi(&treex, &qx, _state); kdtreequeryresultsxyi(&treexy, &qxy, _state); kdtreequeryresultstagsi(&treext, &qtags, _state); kdtreequeryresultsdistancesi(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); kdtreequeryresultsx(&treex, &qx, _state); kdtreequeryresultsxy(&treexy, &qxy, _state); kdtreequeryresultstags(&treext, &qtags, _state); kdtreequeryresultsdistances(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); for(i=0; i<=n-1; i++) { tmpb.ptr.p_bool[i] = ae_true; } r = (double)(0); for(i=0; i<=k-1; i++) { tmpb.ptr.p_bool[qtags.ptr.p_int[i]] = ae_false; ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &qx.ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); r = ae_maxreal(r, testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state), _state); } for(i=0; i<=n-1; i++) { if( tmpb.ptr.p_bool[i] ) { ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); *kdterrors = *kdterrors||ae_fp_less(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state),r*(1-errtol)); } } for(i=0; i<=k-2; i++) { *kdterrors = *kdterrors||ae_fp_greater(qr.ptr.p_double[i],qr.ptr.p_double[i+1]); } for(i=0; i<=k-1; i++) { ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[qtags.ptr.p_int[i]][0], 1, ae_v_len(0,nx-1)); *kdterrors = *kdterrors||ae_fp_greater(ae_fabs(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state)-qr.ptr.p_double[i], _state),errtol); } /* * Test reallocation properties: buffered functions must automatically * resize array which is too small, but leave unchanged array which is * too large. */ if( n>=2 ) { /* * First step: array is too small, two elements are required */ k = 2; kx = kdtreequeryknn(&treex, &ptx, k, ae_true, _state); kxy = kdtreequeryknn(&treexy, &ptx, k, ae_true, _state); kt = kdtreequeryknn(&treext, &ptx, k, ae_true, _state); if( (kx!=k||kxy!=k)||kt!=k ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } ae_matrix_set_length(&qx, 1, 1, _state); ae_matrix_set_length(&qxy, 1, 1, _state); ae_vector_set_length(&qtags, 1, _state); ae_vector_set_length(&qr, 1, _state); kdtreequeryresultsx(&treex, &qx, _state); kdtreequeryresultsxy(&treexy, &qxy, _state); kdtreequeryresultstags(&treext, &qtags, _state); kdtreequeryresultsdistances(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); /* * Second step: array is one row larger than needed, so only first * row is overwritten. Test it. */ k = 1; kx = kdtreequeryknn(&treex, &ptx, k, ae_true, _state); kxy = kdtreequeryknn(&treexy, &ptx, k, ae_true, _state); kt = kdtreequeryknn(&treext, &ptx, k, ae_true, _state); if( (kx!=k||kxy!=k)||kt!=k ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } for(i=0; i<=nx-1; i++) { qx.ptr.pp_double[1][i] = _state->v_nan; } for(i=0; i<=nx+ny-1; i++) { qxy.ptr.pp_double[1][i] = _state->v_nan; } qtags.ptr.p_int[1] = 999; qr.ptr.p_double[1] = _state->v_nan; kdtreequeryresultsx(&treex, &qx, _state); kdtreequeryresultsxy(&treexy, &qxy, _state); kdtreequeryresultstags(&treext, &qtags, _state); kdtreequeryresultsdistances(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); for(i=0; i<=nx-1; i++) { *kdterrors = *kdterrors||!ae_isnan(qx.ptr.pp_double[1][i], _state); } for(i=0; i<=nx+ny-1; i++) { *kdterrors = *kdterrors||!ae_isnan(qxy.ptr.pp_double[1][i], _state); } *kdterrors = *kdterrors||!(qtags.ptr.p_int[1]==999); *kdterrors = *kdterrors||!ae_isnan(qr.ptr.p_double[1], _state); } /* * Test reallocation properties: 'interactive' functions must allocate * new array on each call. */ if( n>=2 ) { /* * On input array is either too small or too large */ for(k=1; k<=2; k++) { ae_assert(k==1||k==2, "KNN: internal error (unexpected K)!", _state); kx = kdtreequeryknn(&treex, &ptx, k, ae_true, _state); kxy = kdtreequeryknn(&treexy, &ptx, k, ae_true, _state); kt = kdtreequeryknn(&treext, &ptx, k, ae_true, _state); if( (kx!=k||kxy!=k)||kt!=k ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } ae_matrix_set_length(&qx, 3-k, 3-k, _state); ae_matrix_set_length(&qxy, 3-k, 3-k, _state); ae_vector_set_length(&qtags, 3-k, _state); ae_vector_set_length(&qr, 3-k, _state); kdtreequeryresultsxi(&treex, &qx, _state); kdtreequeryresultsxyi(&treexy, &qxy, _state); kdtreequeryresultstagsi(&treext, &qtags, _state); kdtreequeryresultsdistancesi(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); *kdterrors = (*kdterrors||qx.rows!=k)||qx.cols!=nx; *kdterrors = (*kdterrors||qxy.rows!=k)||qxy.cols!=nx+ny; *kdterrors = *kdterrors||qtags.cnt!=k; *kdterrors = *kdterrors||qr.cnt!=k; } } } /* * test general approximate K-NN queries (with self-matches): * * compare results from different trees (must be equal) and * check that correct (value,tag) pairs are returned * * test results from XT tree - let R be radius of query result. * then all points not in result must be not closer than R/(1+Eps). */ for(q=1; q<=qcount; q++) { /* * Select K: 1..N */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { k = 1+ae_randominteger(n, _state); } else { k = 1; } /* * Select Eps */ eps = 0.5+ae_randomreal(_state); /* * Select point (either one of the points, or random) */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { i = ae_randominteger(n, _state); ae_v_move(&ptx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); } else { for(i=0; i<=nx-1; i++) { ptx.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } /* * Test: * * consistency of results from different queries * * points in query are IN the R-sphere (or at the boundary), * and points not in query are outside of the R-sphere (or at the boundary) * * distances are correct and are ordered */ kx = kdtreequeryaknn(&treex, &ptx, k, ae_true, eps, _state); kxy = kdtreequeryaknn(&treexy, &ptx, k, ae_true, eps, _state); kt = kdtreequeryaknn(&treext, &ptx, k, ae_true, eps, _state); if( (kx!=k||kxy!=k)||kt!=k ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } kdtreequeryresultsxi(&treex, &qx, _state); kdtreequeryresultsxyi(&treexy, &qxy, _state); kdtreequeryresultstagsi(&treext, &qtags, _state); kdtreequeryresultsdistancesi(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); kdtreequeryresultsx(&treex, &qx, _state); kdtreequeryresultsxy(&treexy, &qxy, _state); kdtreequeryresultstags(&treext, &qtags, _state); kdtreequeryresultsdistances(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, k, nx, ny, _state); for(i=0; i<=n-1; i++) { tmpb.ptr.p_bool[i] = ae_true; } r = (double)(0); for(i=0; i<=k-1; i++) { tmpb.ptr.p_bool[qtags.ptr.p_int[i]] = ae_false; ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &qx.ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); r = ae_maxreal(r, testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state), _state); } for(i=0; i<=n-1; i++) { if( tmpb.ptr.p_bool[i] ) { ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); *kdterrors = *kdterrors||ae_fp_less(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state),r*(1-errtol)/(1+eps)); } } for(i=0; i<=k-2; i++) { *kdterrors = *kdterrors||ae_fp_greater(qr.ptr.p_double[i],qr.ptr.p_double[i+1]); } for(i=0; i<=k-1; i++) { ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[qtags.ptr.p_int[i]][0], 1, ae_v_len(0,nx-1)); *kdterrors = *kdterrors||ae_fp_greater(ae_fabs(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state)-qr.ptr.p_double[i], _state),errtol); } } /* * test general R-NN queries (with self-matches): * * compare results from different trees (must be equal) and * check that correct (value,tag) pairs are returned * * test results from XT tree - let R be radius of query result. * then all points not in result must be not closer than R. */ for(q=1; q<=qcount; q++) { /* * Select R */ if( ae_fp_greater(ae_randomreal(_state),0.3) ) { r = ae_maxreal(ae_randomreal(_state), ae_machineepsilon, _state); } else { r = ae_machineepsilon; } /* * Select point (either one of the points, or random) */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { i = ae_randominteger(n, _state); ae_v_move(&ptx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); } else { for(i=0; i<=nx-1; i++) { ptx.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } /* * Test: * * consistency of results from different queries * * points in query are IN the R-sphere (or at the boundary), * and points not in query are outside of the R-sphere (or at the boundary) * * distances are correct and are ordered */ kx = kdtreequeryrnn(&treex, &ptx, r, ae_true, _state); kxy = kdtreequeryrnn(&treexy, &ptx, r, ae_true, _state); kt = kdtreequeryrnn(&treext, &ptx, r, ae_true, _state); if( kxy!=kx||kt!=kx ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } kdtreequeryresultsxi(&treex, &qx, _state); kdtreequeryresultsxyi(&treexy, &qxy, _state); kdtreequeryresultstagsi(&treext, &qtags, _state); kdtreequeryresultsdistancesi(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, kx, nx, ny, _state); kdtreequeryresultsx(&treex, &qx, _state); kdtreequeryresultsxy(&treexy, &qxy, _state); kdtreequeryresultstags(&treext, &qtags, _state); kdtreequeryresultsdistances(&treext, &qr, _state); *kdterrors = *kdterrors||testnearestneighborunit_kdtresultsdifferent(xy, n, &qx, &qxy, &qtags, kx, nx, ny, _state); for(i=0; i<=n-1; i++) { tmpb.ptr.p_bool[i] = ae_true; } for(i=0; i<=kx-1; i++) { tmpb.ptr.p_bool[qtags.ptr.p_int[i]] = ae_false; } for(i=0; i<=n-1; i++) { ae_v_move(&tmpx.ptr.p_double[0], 1, &ptx.ptr.p_double[0], 1, ae_v_len(0,nx-1)); ae_v_sub(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); if( tmpb.ptr.p_bool[i] ) { *kdterrors = *kdterrors||ae_fp_less(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state),r*(1-errtol)); } else { *kdterrors = *kdterrors||ae_fp_greater(testnearestneighborunit_vnorm(&tmpx, nx, normtype, _state),r*(1+errtol)); } } for(i=0; i<=kx-2; i++) { *kdterrors = *kdterrors||ae_fp_greater(qr.ptr.p_double[i],qr.ptr.p_double[i+1]); } } /* * Test self-matching: * * self-match - nearest neighbor of each point in XY is the point itself * * no self-match - nearest neighbor is NOT the point itself */ if( n>1 ) { /* * test for N=1 have non-general form, but it is not really needed */ for(task=0; task<=1; task++) { for(i=0; i<=n-1; i++) { ae_v_move(&ptx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); kx = kdtreequeryknn(&treex, &ptx, 1, task==0, _state); kdtreequeryresultsxi(&treex, &qx, _state); if( kx!=1 ) { *kdterrors = ae_true; ae_frame_leave(_state); return; } isequal = ae_true; for(j=0; j<=nx-1; j++) { isequal = isequal&&ae_fp_eq(qx.ptr.pp_double[0][j],ptx.ptr.p_double[j]); } if( task==0 ) { *kdterrors = *kdterrors||!isequal; } else { *kdterrors = *kdterrors||isequal; } } } } ae_frame_leave(_state); } /************************************************************************* Testing serialization of KD trees This function sets Err to True on errors, but leaves it unchanged on success *************************************************************************/ static void testnearestneighborunit_testkdtreeserialization(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t nx; ae_int_t ny; ae_int_t normtype; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t q; ae_matrix xy; ae_vector x; ae_vector tags; ae_vector qsizes; double threshold; kdtree tree0; kdtree tree1; ae_int_t k0; ae_int_t k1; ae_matrix xy0; ae_matrix xy1; ae_vector tags0; ae_vector tags1; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&tags, 0, DT_INT, _state); ae_vector_init(&qsizes, 0, DT_INT, _state); _kdtree_init(&tree0, _state); _kdtree_init(&tree1, _state); ae_matrix_init(&xy0, 0, 0, DT_REAL, _state); ae_matrix_init(&xy1, 0, 0, DT_REAL, _state); ae_vector_init(&tags0, 0, DT_INT, _state); ae_vector_init(&tags1, 0, DT_INT, _state); threshold = 100*ae_machineepsilon; /* * different N, NX, NY, NormType */ n = 1; while(n<=51) { /* * prepare array with query sizes */ ae_vector_set_length(&qsizes, 4, _state); qsizes.ptr.p_int[0] = 1; qsizes.ptr.p_int[1] = ae_minint(2, n, _state); qsizes.ptr.p_int[2] = ae_minint(4, n, _state); qsizes.ptr.p_int[3] = n; /* * different NX/NY/NormType */ for(nx=1; nx<=2; nx++) { for(ny=0; ny<=2; ny++) { for(normtype=0; normtype<=2; normtype++) { /* * Prepare data */ ae_matrix_set_length(&xy, n, nx+ny, _state); ae_vector_set_length(&tags, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } tags.ptr.p_int[i] = ae_randominteger(100, _state); } /* * Build tree, pass it through serializer */ kdtreebuildtagged(&xy, &tags, n, nx, ny, normtype, &tree0, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); kdtreealloc(&_local_serializer, &tree0, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); kdtreeserialize(&_local_serializer, &tree0, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); kdtreeunserialize(&_local_serializer, &tree1, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } /* * For each point of XY we make queries with different sizes */ ae_vector_set_length(&x, nx, _state); for(k=0; k<=n-1; k++) { for(q=0; q<=qsizes.cnt-1; q++) { ae_v_move(&x.ptr.p_double[0], 1, &xy.ptr.pp_double[k][0], 1, ae_v_len(0,nx-1)); k0 = kdtreequeryknn(&tree0, &x, qsizes.ptr.p_int[q], ae_true, _state); k1 = kdtreequeryknn(&tree1, &x, qsizes.ptr.p_int[q], ae_true, _state); if( k0!=k1 ) { *err = ae_true; ae_frame_leave(_state); return; } kdtreequeryresultsxy(&tree0, &xy0, _state); kdtreequeryresultsxy(&tree1, &xy1, _state); for(i=0; i<=k0-1; i++) { for(j=0; j<=nx+ny-1; j++) { if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[i][j]-xy1.ptr.pp_double[i][j], _state),threshold) ) { *err = ae_true; ae_frame_leave(_state); return; } } } kdtreequeryresultstags(&tree0, &tags0, _state); kdtreequeryresultstags(&tree1, &tags1, _state); for(i=0; i<=k0-1; i++) { if( tags0.ptr.p_int[i]!=tags1.ptr.p_int[i] ) { *err = ae_true; ae_frame_leave(_state); return; } } } } } } } /* * Next N */ n = n+25; } ae_frame_leave(_state); } /************************************************************************* This function tests different special cases: * Kd-tree for a zero number of points * Kd-tree for array with a lot of duplicates (early versions of ALGLIB raised stack overflow on such datasets) It returns True on errors, False on success. *************************************************************************/ static ae_bool testnearestneighborunit_testspecialcases(ae_state *_state) { ae_frame _frame_block; kdtree kdt; ae_matrix xy; ae_vector tags; ae_vector x; ae_int_t n; ae_int_t nk; ae_int_t nx; ae_int_t ny; ae_int_t normtype; ae_int_t i; ae_int_t j; double v; ae_bool result; ae_frame_make(_state, &_frame_block); _kdtree_init(&kdt, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&tags, 0, DT_INT, _state); ae_vector_init(&x, 0, DT_REAL, _state); result = ae_false; for(nx=1; nx<=3; nx++) { for(ny=0; ny<=3; ny++) { for(normtype=0; normtype<=2; normtype++) { /* * Build tree */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { kdtreebuildtagged(&xy, &tags, 0, nx, ny, normtype, &kdt, _state); } else { kdtreebuild(&xy, 0, nx, ny, normtype, &kdt, _state); } /* * Test different queries */ ae_vector_set_length(&x, nx, _state); for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state); } result = result||kdtreequeryknn(&kdt, &x, 1, ae_true, _state)>0; result = result||kdtreequeryrnn(&kdt, &x, 1.0E6, ae_true, _state)>0; result = result||kdtreequeryaknn(&kdt, &x, 1, ae_true, 2.0, _state)>0; } } } /* * Ability to handle array with a lot of duplicates without causing * stack overflow. * * Two situations are handled: * * array where ALL N elements are duplicates * * array where there are NK distinct elements and N-NK duplicates */ nx = 2; ny = 1; n = 100000; nk = 100; v = ae_randomreal(_state); ae_matrix_set_length(&xy, n, nx+ny, _state); ae_vector_set_length(&x, nx, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[i][j] = v; } } kdtreebuild(&xy, n, nx, ny, 2, &kdt, _state); for(j=0; j<=nx-1; j++) { x.ptr.p_double[j] = v; } result = result||kdtreequeryrnn(&kdt, &x, 0.0001, ae_true, _state)!=n; for(i=0; i<=nk-1; i++) { for(j=0; j<=nx+ny-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } kdtreebuild(&xy, n, nx, ny, 2, &kdt, _state); result = result||kdtreequeryrnn(&kdt, &x, 0.0001, ae_true, _state)=aoffsi&&i=aoffsj)&&j=xoffsi&&j>=xoffsj ) { cxr1.ptr.pp_complex[i][j] = refcxr.ptr.pp_complex[i][j]; cxr2.ptr.pp_complex[i][j] = refcxr.ptr.pp_complex[i][j]; rxr1.ptr.pp_double[i][j] = refrxr.ptr.pp_double[i][j]; rxr2.ptr.pp_double[i][j] = refrxr.ptr.pp_double[i][j]; } else { cxr1.ptr.pp_complex[i][j] = ae_complex_from_d(ae_randomreal(_state)); cxr2.ptr.pp_complex[i][j] = cxr1.ptr.pp_complex[i][j]; rxr1.ptr.pp_double[i][j] = ae_randomreal(_state); rxr2.ptr.pp_double[i][j] = rxr1.ptr.pp_double[i][j]; } } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( i>=xoffsi&&j>=xoffsj ) { cxl1.ptr.pp_complex[i][j] = refcxl.ptr.pp_complex[i][j]; cxl2.ptr.pp_complex[i][j] = refcxl.ptr.pp_complex[i][j]; rxl1.ptr.pp_double[i][j] = refrxl.ptr.pp_double[i][j]; rxl2.ptr.pp_double[i][j] = refrxl.ptr.pp_double[i][j]; } else { cxl1.ptr.pp_complex[i][j] = ae_complex_from_d(ae_randomreal(_state)); cxl2.ptr.pp_complex[i][j] = cxl1.ptr.pp_complex[i][j]; rxl1.ptr.pp_double[i][j] = ae_randomreal(_state); rxl2.ptr.pp_double[i][j] = rxl1.ptr.pp_double[i][j]; } } } /* * Test CXR */ cmatrixrighttrsm(n-xoffsi, m-xoffsj, &ca, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &cxr1, xoffsi, xoffsj, _state); testablasunit_refcmatrixrighttrsm(n-xoffsi, m-xoffsj, &ca, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &cxr2, xoffsi, xoffsj, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(cxr1.ptr.pp_complex[i][j],cxr2.ptr.pp_complex[i][j]), _state),threshold); } } /* * Test CXL */ cmatrixlefttrsm(m-xoffsi, n-xoffsj, &ca, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &cxl1, xoffsi, xoffsj, _state); testablasunit_refcmatrixlefttrsm(m-xoffsi, n-xoffsj, &ca, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &cxl2, xoffsi, xoffsj, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(cxl1.ptr.pp_complex[i][j],cxl2.ptr.pp_complex[i][j]), _state),threshold); } } if( optype<2 ) { /* * Test RXR */ rmatrixrighttrsm(n-xoffsi, m-xoffsj, &ra, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &rxr1, xoffsi, xoffsj, _state); testablasunit_refrmatrixrighttrsm(n-xoffsi, m-xoffsj, &ra, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &rxr2, xoffsi, xoffsj, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result||ae_fp_greater(ae_fabs(rxr1.ptr.pp_double[i][j]-rxr2.ptr.pp_double[i][j], _state),threshold); } } /* * Test RXL */ rmatrixlefttrsm(m-xoffsi, n-xoffsj, &ra, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &rxl1, xoffsi, xoffsj, _state); testablasunit_refrmatrixlefttrsm(m-xoffsi, n-xoffsj, &ra, aoffsi, aoffsj, uppertype==0, unittype==0, optype, &rxl2, xoffsi, xoffsj, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { result = result||ae_fp_greater(ae_fabs(rxl1.ptr.pp_double[i][j]-rxl2.ptr.pp_double[i][j], _state),threshold); } } } } ae_frame_leave(_state); return result; } /************************************************************************* SYRK tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testsyrk(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t k; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t uppertype; ae_int_t xoffsi; ae_int_t xoffsj; ae_int_t aoffsitype; ae_int_t aoffsjtype; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t alphatype; ae_int_t betatype; ae_matrix refra; ae_matrix refrc; ae_matrix refca; ae_matrix refcc; double alpha; double beta; ae_matrix ra1; ae_matrix ra2; ae_matrix ca1; ae_matrix ca2; ae_matrix rc; ae_matrix rct; ae_matrix cc; ae_matrix cct; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&refra, 0, 0, DT_REAL, _state); ae_matrix_init(&refrc, 0, 0, DT_REAL, _state); ae_matrix_init(&refca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&refcc, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ra1, 0, 0, DT_REAL, _state); ae_matrix_init(&ra2, 0, 0, DT_REAL, _state); ae_matrix_init(&ca1, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ca2, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&rc, 0, 0, DT_REAL, _state); ae_matrix_init(&rct, 0, 0, DT_REAL, _state); ae_matrix_init(&cc, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cct, 0, 0, DT_COMPLEX, _state); threshold = maxn*100*ae_machineepsilon; result = ae_false; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N in [1,MX] such that max(M,N)=MX */ k = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { k = mx; } else { n = mx; } /* * Initialize RefRA/RefCA by random Hermitian matrices, * RefRC/RefCC by random matrices * * RA/CA size is 2Nx2N (four copies of same NxN matrix * to test different offsets) */ ae_matrix_set_length(&refra, 2*n, 2*n, _state); ae_matrix_set_length(&refca, 2*n, 2*n, _state); for(i=0; i<=n-1; i++) { refra.ptr.pp_double[i][i] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][i] = ae_complex_from_d(2*ae_randomreal(_state)-1); for(j=i+1; j<=n-1; j++) { refra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; refra.ptr.pp_double[j][i] = refra.ptr.pp_double[i][j]; refca.ptr.pp_complex[j][i] = ae_c_conj(refca.ptr.pp_complex[i][j], _state); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { refra.ptr.pp_double[i+n][j] = refra.ptr.pp_double[i][j]; refra.ptr.pp_double[i][j+n] = refra.ptr.pp_double[i][j]; refra.ptr.pp_double[i+n][j+n] = refra.ptr.pp_double[i][j]; refca.ptr.pp_complex[i+n][j] = refca.ptr.pp_complex[i][j]; refca.ptr.pp_complex[i][j+n] = refca.ptr.pp_complex[i][j]; refca.ptr.pp_complex[i+n][j+n] = refca.ptr.pp_complex[i][j]; } } ae_matrix_set_length(&refrc, n, k, _state); ae_matrix_set_length(&refcc, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { refrc.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refcc.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refcc.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } /* * test different types of operations, offsets, and so on... * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ ae_matrix_set_length(&ra1, 2*n, 2*n, _state); ae_matrix_set_length(&ra2, 2*n, 2*n, _state); ae_matrix_set_length(&ca1, 2*n, 2*n, _state); ae_matrix_set_length(&ca2, 2*n, 2*n, _state); ae_matrix_set_length(&rc, n, k, _state); ae_matrix_set_length(&rct, k, n, _state); ae_matrix_set_length(&cc, n, k, _state); ae_matrix_set_length(&cct, k, n, _state); uppertype = ae_randominteger(2, _state); xoffsi = ae_randominteger(2, _state); xoffsj = ae_randominteger(2, _state); aoffsitype = ae_randominteger(2, _state); aoffsjtype = ae_randominteger(2, _state); alphatype = ae_randominteger(2, _state); betatype = ae_randominteger(2, _state); aoffsi = n*aoffsitype; aoffsj = n*aoffsjtype; alpha = alphatype*(2*ae_randomreal(_state)-1); beta = betatype*(2*ae_randomreal(_state)-1); /* * copy A, C (fill unused parts with random garbage) */ for(i=0; i<=2*n-1; i++) { for(j=0; j<=2*n-1; j++) { if( ((i>=aoffsi&&i=aoffsj)&&j=xoffsi&&j>=xoffsj ) { rc.ptr.pp_double[i][j] = refrc.ptr.pp_double[i][j]; rct.ptr.pp_double[j][i] = refrc.ptr.pp_double[i][j]; cc.ptr.pp_complex[i][j] = refcc.ptr.pp_complex[i][j]; cct.ptr.pp_complex[j][i] = refcc.ptr.pp_complex[i][j]; } else { rc.ptr.pp_double[i][j] = ae_randomreal(_state); rct.ptr.pp_double[j][i] = rc.ptr.pp_double[i][j]; cc.ptr.pp_complex[i][j] = ae_complex_from_d(ae_randomreal(_state)); cct.ptr.pp_complex[j][i] = cct.ptr.pp_complex[j][i]; } } } /* * Test complex * Only one of transform types is selected and tested */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { cmatrixherk(n-xoffsi, k-xoffsj, alpha, &cc, xoffsi, xoffsj, 0, beta, &ca1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refcmatrixherk(n-xoffsi, k-xoffsj, alpha, &cc, xoffsi, xoffsj, 0, beta, &ca2, aoffsi, aoffsj, uppertype==0, _state); } else { cmatrixherk(n-xoffsi, k-xoffsj, alpha, &cct, xoffsj, xoffsi, 2, beta, &ca1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refcmatrixherk(n-xoffsi, k-xoffsj, alpha, &cct, xoffsj, xoffsi, 2, beta, &ca2, aoffsi, aoffsj, uppertype==0, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(ca1.ptr.pp_complex[i][j],ca2.ptr.pp_complex[i][j]), _state),threshold); } } /* * Test old version of HERK (named SYRK) * Only one of transform types is selected and tested */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { cmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &cc, xoffsi, xoffsj, 0, beta, &ca1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refcmatrixherk(n-xoffsi, k-xoffsj, alpha, &cc, xoffsi, xoffsj, 0, beta, &ca2, aoffsi, aoffsj, uppertype==0, _state); } else { cmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &cct, xoffsj, xoffsi, 2, beta, &ca1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refcmatrixherk(n-xoffsi, k-xoffsj, alpha, &cct, xoffsj, xoffsi, 2, beta, &ca2, aoffsi, aoffsj, uppertype==0, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(ca1.ptr.pp_complex[i][j],ca2.ptr.pp_complex[i][j]), _state),threshold); } } /* * Test real * Only one of transform types is selected and tested */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { rmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &rc, xoffsi, xoffsj, 0, beta, &ra1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refrmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &rc, xoffsi, xoffsj, 0, beta, &ra2, aoffsi, aoffsj, uppertype==0, _state); } else { rmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &rct, xoffsj, xoffsi, 1, beta, &ra1, aoffsi, aoffsj, uppertype==0, _state); testablasunit_refrmatrixsyrk(n-xoffsi, k-xoffsj, alpha, &rct, xoffsj, xoffsi, 1, beta, &ra2, aoffsi, aoffsj, uppertype==0, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result||ae_fp_greater(ae_fabs(ra1.ptr.pp_double[i][j]-ra2.ptr.pp_double[i][j], _state),threshold); } } } ae_frame_leave(_state); return result; } /************************************************************************* GEMM tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testgemm(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t k; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t aoptype; ae_int_t aoptyper; ae_int_t boffsi; ae_int_t boffsj; ae_int_t boptype; ae_int_t boptyper; ae_int_t coffsi; ae_int_t coffsj; ae_matrix refra; ae_matrix refrb; ae_matrix refrc; ae_matrix refca; ae_matrix refcb; ae_matrix refcc; double alphar; double betar; ae_complex alphac; ae_complex betac; ae_matrix rc1; ae_matrix rc2; ae_matrix cc1; ae_matrix cc2; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&refra, 0, 0, DT_REAL, _state); ae_matrix_init(&refrb, 0, 0, DT_REAL, _state); ae_matrix_init(&refrc, 0, 0, DT_REAL, _state); ae_matrix_init(&refca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&refcb, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&refcc, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&rc1, 0, 0, DT_REAL, _state); ae_matrix_init(&rc2, 0, 0, DT_REAL, _state); ae_matrix_init(&cc1, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cc2, 0, 0, DT_COMPLEX, _state); threshold = maxn*100*ae_machineepsilon; result = ae_false; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N/K in [1,MX] such that max(M,N,K)=MX */ m = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); k = 1+ae_randominteger(mx, _state); i = ae_randominteger(3, _state); if( i==0 ) { m = mx; } if( i==1 ) { n = mx; } if( i==2 ) { k = mx; } /* * Initialize A/B/C by random matrices with size (MaxN+1)*(MaxN+1) */ ae_matrix_set_length(&refra, maxn+1, maxn+1, _state); ae_matrix_set_length(&refrb, maxn+1, maxn+1, _state); ae_matrix_set_length(&refrc, maxn+1, maxn+1, _state); ae_matrix_set_length(&refca, maxn+1, maxn+1, _state); ae_matrix_set_length(&refcb, maxn+1, maxn+1, _state); ae_matrix_set_length(&refcc, maxn+1, maxn+1, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { refra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refrb.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refrc.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; refcb.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refcb.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; refcc.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refcc.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } /* * test different types of operations, offsets, and so on... * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ ae_matrix_set_length(&rc1, maxn+1, maxn+1, _state); ae_matrix_set_length(&rc2, maxn+1, maxn+1, _state); ae_matrix_set_length(&cc1, maxn+1, maxn+1, _state); ae_matrix_set_length(&cc2, maxn+1, maxn+1, _state); aoffsi = ae_randominteger(2, _state); aoffsj = ae_randominteger(2, _state); aoptype = ae_randominteger(3, _state); aoptyper = ae_randominteger(2, _state); boffsi = ae_randominteger(2, _state); boffsj = ae_randominteger(2, _state); boptype = ae_randominteger(3, _state); boptyper = ae_randominteger(2, _state); coffsi = ae_randominteger(2, _state); coffsj = ae_randominteger(2, _state); alphar = ae_randominteger(2, _state)*(2*ae_randomreal(_state)-1); betar = ae_randominteger(2, _state)*(2*ae_randomreal(_state)-1); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { alphac.x = 2*ae_randomreal(_state)-1; alphac.y = 2*ae_randomreal(_state)-1; } else { alphac = ae_complex_from_i(0); } if( ae_fp_greater(ae_randomreal(_state),0.5) ) { betac.x = 2*ae_randomreal(_state)-1; betac.y = 2*ae_randomreal(_state)-1; } else { betac = ae_complex_from_i(0); } /* * copy C */ for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { rc1.ptr.pp_double[i][j] = refrc.ptr.pp_double[i][j]; rc2.ptr.pp_double[i][j] = refrc.ptr.pp_double[i][j]; cc1.ptr.pp_complex[i][j] = refcc.ptr.pp_complex[i][j]; cc2.ptr.pp_complex[i][j] = refcc.ptr.pp_complex[i][j]; } } /* * Test complex */ cmatrixgemm(m, n, k, alphac, &refca, aoffsi, aoffsj, aoptype, &refcb, boffsi, boffsj, boptype, betac, &cc1, coffsi, coffsj, _state); testablasunit_refcmatrixgemm(m, n, k, alphac, &refca, aoffsi, aoffsj, aoptype, &refcb, boffsi, boffsj, boptype, betac, &cc2, coffsi, coffsj, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(cc1.ptr.pp_complex[i][j],cc2.ptr.pp_complex[i][j]), _state),threshold); } } /* * Test real */ rmatrixgemm(m, n, k, alphar, &refra, aoffsi, aoffsj, aoptyper, &refrb, boffsi, boffsj, boptyper, betar, &rc1, coffsi, coffsj, _state); testablasunit_refrmatrixgemm(m, n, k, alphar, &refra, aoffsi, aoffsj, aoptyper, &refrb, boffsi, boffsj, boptyper, betar, &rc2, coffsi, coffsj, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { result = result||ae_fp_greater(ae_fabs(rc1.ptr.pp_double[i][j]-rc2.ptr.pp_double[i][j], _state),threshold); } } } ae_frame_leave(_state); return result; } /************************************************************************* transpose tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testtrans(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t boffsi; ae_int_t boffsj; double v1; double v2; double threshold; ae_matrix refra; ae_matrix refrb; ae_matrix refca; ae_matrix refcb; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&refra, 0, 0, DT_REAL, _state); ae_matrix_init(&refrb, 0, 0, DT_REAL, _state); ae_matrix_init(&refca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&refcb, 0, 0, DT_COMPLEX, _state); result = ae_false; threshold = 1000*ae_machineepsilon; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N in [1,MX] such that max(M,N)=MX * Generate random V1 and V2 which are used to fill * RefRB/RefCB with control values. */ m = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); if( ae_randominteger(2, _state)==0 ) { m = mx; } else { n = mx; } v1 = ae_randomreal(_state); v2 = ae_randomreal(_state); /* * Initialize A by random matrix with size (MaxN+1)*(MaxN+1) * Fill B with control values */ ae_matrix_set_length(&refra, maxn+1, maxn+1, _state); ae_matrix_set_length(&refrb, maxn+1, maxn+1, _state); ae_matrix_set_length(&refca, maxn+1, maxn+1, _state); ae_matrix_set_length(&refcb, maxn+1, maxn+1, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { refra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; refrb.ptr.pp_double[i][j] = i*v1+j*v2; refcb.ptr.pp_complex[i][j] = ae_complex_from_d(i*v1+j*v2); } } /* * test different offsets (zero or one) * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ aoffsi = ae_randominteger(2, _state); aoffsj = ae_randominteger(2, _state); boffsi = ae_randominteger(2, _state); boffsj = ae_randominteger(2, _state); rmatrixtranspose(m, n, &refra, aoffsi, aoffsj, &refrb, boffsi, boffsj, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { if( ((i=boffsi+n)||j=boffsj+m ) { result = result||ae_fp_greater(ae_fabs(refrb.ptr.pp_double[i][j]-(v1*i+v2*j), _state),threshold); } else { result = result||ae_fp_greater(ae_fabs(refrb.ptr.pp_double[i][j]-refra.ptr.pp_double[aoffsi+j-boffsj][aoffsj+i-boffsi], _state),threshold); } } } cmatrixtranspose(m, n, &refca, aoffsi, aoffsj, &refcb, boffsi, boffsj, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { if( ((i=boffsi+n)||j=boffsj+m ) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub_d(refcb.ptr.pp_complex[i][j],v1*i+v2*j), _state),threshold); } else { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(refcb.ptr.pp_complex[i][j],refca.ptr.pp_complex[aoffsi+j-boffsj][aoffsj+i-boffsi]), _state),threshold); } } } } ae_frame_leave(_state); return result; } /************************************************************************* rank-1tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testrank1(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t uoffs; ae_int_t voffs; double threshold; ae_matrix refra; ae_matrix refrb; ae_matrix refca; ae_matrix refcb; ae_vector ru; ae_vector rv; ae_vector cu; ae_vector cv; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&refra, 0, 0, DT_REAL, _state); ae_matrix_init(&refrb, 0, 0, DT_REAL, _state); ae_matrix_init(&refca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&refcb, 0, 0, DT_COMPLEX, _state); ae_vector_init(&ru, 0, DT_REAL, _state); ae_vector_init(&rv, 0, DT_REAL, _state); ae_vector_init(&cu, 0, DT_COMPLEX, _state); ae_vector_init(&cv, 0, DT_COMPLEX, _state); result = ae_false; threshold = 1000*ae_machineepsilon; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N in [1,MX] such that max(M,N)=MX */ m = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); if( ae_randominteger(2, _state)==0 ) { m = mx; } else { n = mx; } /* * Initialize A by random matrix with size (MaxN+1)*(MaxN+1) * Fill B with control values */ ae_matrix_set_length(&refra, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&refrb, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&refca, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&refcb, maxn+maxn, maxn+maxn, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { refra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; refrb.ptr.pp_double[i][j] = refra.ptr.pp_double[i][j]; refcb.ptr.pp_complex[i][j] = refca.ptr.pp_complex[i][j]; } } ae_vector_set_length(&ru, 2*m, _state); ae_vector_set_length(&cu, 2*m, _state); for(i=0; i<=2*m-1; i++) { ru.ptr.p_double[i] = 2*ae_randomreal(_state)-1; cu.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cu.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rv, 2*n, _state); ae_vector_set_length(&cv, 2*n, _state); for(i=0; i<=2*n-1; i++) { rv.ptr.p_double[i] = 2*ae_randomreal(_state)-1; cv.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cv.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } /* * test different offsets (zero or one) * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ aoffsi = ae_randominteger(maxn, _state); aoffsj = ae_randominteger(maxn, _state); uoffs = ae_randominteger(m, _state); voffs = ae_randominteger(n, _state); cmatrixrank1(m, n, &refca, aoffsi, aoffsj, &cu, uoffs, &cv, voffs, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { if( ((i=aoffsi+m)||j=aoffsj+n ) { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(refca.ptr.pp_complex[i][j],refcb.ptr.pp_complex[i][j]), _state),threshold); } else { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(refca.ptr.pp_complex[i][j],ae_c_add(refcb.ptr.pp_complex[i][j],ae_c_mul(cu.ptr.p_complex[i-aoffsi+uoffs],cv.ptr.p_complex[j-aoffsj+voffs]))), _state),threshold); } } } rmatrixrank1(m, n, &refra, aoffsi, aoffsj, &ru, uoffs, &rv, voffs, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { if( ((i=aoffsi+m)||j=aoffsj+n ) { result = result||ae_fp_greater(ae_fabs(refra.ptr.pp_double[i][j]-refrb.ptr.pp_double[i][j], _state),threshold); } else { result = result||ae_fp_greater(ae_fabs(refra.ptr.pp_double[i][j]-(refrb.ptr.pp_double[i][j]+ru.ptr.p_double[i-aoffsi+uoffs]*rv.ptr.p_double[j-aoffsj+voffs]), _state),threshold); } } } } ae_frame_leave(_state); return result; } /************************************************************************* MV tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testmv(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t xoffs; ae_int_t yoffs; ae_int_t opca; ae_int_t opra; double threshold; double rv1; double rv2; ae_complex cv1; ae_complex cv2; ae_matrix refra; ae_matrix refca; ae_vector rx; ae_vector ry; ae_vector cx; ae_vector cy; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&refra, 0, 0, DT_REAL, _state); ae_matrix_init(&refca, 0, 0, DT_COMPLEX, _state); ae_vector_init(&rx, 0, DT_REAL, _state); ae_vector_init(&ry, 0, DT_REAL, _state); ae_vector_init(&cx, 0, DT_COMPLEX, _state); ae_vector_init(&cy, 0, DT_COMPLEX, _state); result = ae_false; threshold = 1000*ae_machineepsilon; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N in [1,MX] such that max(M,N)=MX */ m = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); if( ae_randominteger(2, _state)==0 ) { m = mx; } else { n = mx; } /* * Initialize A by random matrix with size (MaxN+MaxN)*(MaxN+MaxN) * Initialize X by random vector with size (MaxN+MaxN) * Fill Y by control values */ ae_matrix_set_length(&refra, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&refca, maxn+maxn, maxn+maxn, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { refra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; refca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } ae_vector_set_length(&rx, 2*maxn, _state); ae_vector_set_length(&cx, 2*maxn, _state); ae_vector_set_length(&ry, 2*maxn, _state); ae_vector_set_length(&cy, 2*maxn, _state); for(i=0; i<=2*maxn-1; i++) { rx.ptr.p_double[i] = 2*ae_randomreal(_state)-1; cx.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cx.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; ry.ptr.p_double[i] = (double)(i); cy.ptr.p_complex[i] = ae_complex_from_i(i); } /* * test different offsets (zero or one) * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ aoffsi = ae_randominteger(maxn, _state); aoffsj = ae_randominteger(maxn, _state); xoffs = ae_randominteger(maxn, _state); yoffs = ae_randominteger(maxn, _state); opca = ae_randominteger(3, _state); opra = ae_randominteger(2, _state); cmatrixmv(m, n, &refca, aoffsi, aoffsj, opca, &cx, xoffs, &cy, yoffs, _state); for(i=0; i<=2*maxn-1; i++) { if( i=yoffs+m ) { result = result||ae_c_neq_d(cy.ptr.p_complex[i],(double)(i)); } else { cv1 = cy.ptr.p_complex[i]; cv2 = ae_complex_from_d(0.0); if( opca==0 ) { cv2 = ae_v_cdotproduct(&refca.ptr.pp_complex[aoffsi+i-yoffs][aoffsj], 1, "N", &cx.ptr.p_complex[xoffs], 1, "N", ae_v_len(aoffsj,aoffsj+n-1)); } if( opca==1 ) { cv2 = ae_v_cdotproduct(&refca.ptr.pp_complex[aoffsi][aoffsj+i-yoffs], refca.stride, "N", &cx.ptr.p_complex[xoffs], 1, "N", ae_v_len(aoffsi,aoffsi+n-1)); } if( opca==2 ) { cv2 = ae_v_cdotproduct(&refca.ptr.pp_complex[aoffsi][aoffsj+i-yoffs], refca.stride, "Conj", &cx.ptr.p_complex[xoffs], 1, "N", ae_v_len(aoffsi,aoffsi+n-1)); } result = result||ae_fp_greater(ae_c_abs(ae_c_sub(cv1,cv2), _state),threshold); } } rmatrixmv(m, n, &refra, aoffsi, aoffsj, opra, &rx, xoffs, &ry, yoffs, _state); for(i=0; i<=2*maxn-1; i++) { if( i=yoffs+m ) { result = result||ae_fp_neq(ry.ptr.p_double[i],(double)(i)); } else { rv1 = ry.ptr.p_double[i]; rv2 = (double)(0); if( opra==0 ) { rv2 = ae_v_dotproduct(&refra.ptr.pp_double[aoffsi+i-yoffs][aoffsj], 1, &rx.ptr.p_double[xoffs], 1, ae_v_len(aoffsj,aoffsj+n-1)); } if( opra==1 ) { rv2 = ae_v_dotproduct(&refra.ptr.pp_double[aoffsi][aoffsj+i-yoffs], refra.stride, &rx.ptr.p_double[xoffs], 1, ae_v_len(aoffsi,aoffsi+n-1)); } result = result||ae_fp_greater(ae_fabs(rv1-rv2, _state),threshold); } } } ae_frame_leave(_state); return result; } /************************************************************************* COPY tests Returns False for passed test, True - for failed *************************************************************************/ static ae_bool testablasunit_testcopy(ae_int_t minn, ae_int_t maxn, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t mx; ae_int_t i; ae_int_t j; ae_int_t aoffsi; ae_int_t aoffsj; ae_int_t boffsi; ae_int_t boffsj; double threshold; ae_matrix ra; ae_matrix rb; ae_matrix ca; ae_matrix cb; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); ae_matrix_init(&rb, 0, 0, DT_REAL, _state); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cb, 0, 0, DT_COMPLEX, _state); result = ae_false; threshold = 1000*ae_machineepsilon; for(mx=minn; mx<=maxn; mx++) { /* * Select random M/N in [1,MX] such that max(M,N)=MX */ m = 1+ae_randominteger(mx, _state); n = 1+ae_randominteger(mx, _state); if( ae_randominteger(2, _state)==0 ) { m = mx; } else { n = mx; } /* * Initialize A by random matrix with size (MaxN+MaxN)*(MaxN+MaxN) * Initialize X by random vector with size (MaxN+MaxN) * Fill Y by control values */ ae_matrix_set_length(&ra, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&ca, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&rb, maxn+maxn, maxn+maxn, _state); ae_matrix_set_length(&cb, maxn+maxn, maxn+maxn, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; rb.ptr.pp_double[i][j] = (double)(1+2*i+3*j); cb.ptr.pp_complex[i][j] = ae_complex_from_i(1+2*i+3*j); } } /* * test different offsets (zero or one) * * to avoid unnecessary slowdown we don't test ALL possible * combinations of operation types. We just generate one random * set of parameters and test it. */ aoffsi = ae_randominteger(maxn, _state); aoffsj = ae_randominteger(maxn, _state); boffsi = ae_randominteger(maxn, _state); boffsj = ae_randominteger(maxn, _state); cmatrixcopy(m, n, &ca, aoffsi, aoffsj, &cb, boffsi, boffsj, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { if( ((i=boffsi+m)||j=boffsj+n ) { result = result||ae_c_neq_d(cb.ptr.pp_complex[i][j],(double)(1+2*i+3*j)); } else { result = result||ae_fp_greater(ae_c_abs(ae_c_sub(ca.ptr.pp_complex[aoffsi+i-boffsi][aoffsj+j-boffsj],cb.ptr.pp_complex[i][j]), _state),threshold); } } } rmatrixcopy(m, n, &ra, aoffsi, aoffsj, &rb, boffsi, boffsj, _state); for(i=0; i<=2*maxn-1; i++) { for(j=0; j<=2*maxn-1; j++) { if( ((i=boffsi+m)||j=boffsj+n ) { result = result||ae_fp_neq(rb.ptr.pp_double[i][j],(double)(1+2*i+3*j)); } else { result = result||ae_fp_greater(ae_fabs(ra.ptr.pp_double[aoffsi+i-boffsi][aoffsj+j-boffsj]-rb.ptr.pp_double[i][j], _state),threshold); } } } } ae_frame_leave(_state); return result; } /************************************************************************* Reference implementation -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refcmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_frame _frame_block; ae_matrix a1; ae_matrix a2; ae_vector tx; ae_int_t i; ae_int_t j; ae_complex vc; ae_bool rupper; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a1, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&a2, 0, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_COMPLEX, _state); if( n*m==0 ) { ae_frame_leave(_state); return; } ae_matrix_set_length(&a1, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a1.ptr.pp_complex[i][j] = a->ptr.pp_complex[i1+i][j1+j]; } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { a1.ptr.pp_complex[i][j] = a->ptr.pp_complex[i1+i][j1+j]; } } } rupper = isupper; if( isunit ) { for(i=0; i<=n-1; i++) { a1.ptr.pp_complex[i][i] = ae_complex_from_i(1); } } ae_matrix_set_length(&a2, n, n, _state); if( optype==0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a2.ptr.pp_complex[i][j] = a1.ptr.pp_complex[i][j]; } } } if( optype==1 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a2.ptr.pp_complex[i][j] = a1.ptr.pp_complex[j][i]; } } rupper = !rupper; } if( optype==2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a2.ptr.pp_complex[i][j] = ae_c_conj(a1.ptr.pp_complex[j][i], _state); } } rupper = !rupper; } testablasunit_internalcmatrixtrinverse(&a2, n, rupper, ae_false, _state); ae_vector_set_length(&tx, n, _state); for(i=0; i<=m-1; i++) { ae_v_cmove(&tx.ptr.p_complex[0], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(0,n-1)); for(j=0; j<=n-1; j++) { vc = ae_v_cdotproduct(&tx.ptr.p_complex[0], 1, "N", &a2.ptr.pp_complex[0][j], a2.stride, "N", ae_v_len(0,n-1)); x->ptr.pp_complex[i2+i][j2+j] = vc; } } ae_frame_leave(_state); } /************************************************************************* Reference implementation -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refcmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Complex */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_frame _frame_block; ae_matrix a1; ae_matrix a2; ae_vector tx; ae_int_t i; ae_int_t j; ae_complex vc; ae_bool rupper; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a1, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&a2, 0, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_COMPLEX, _state); if( n*m==0 ) { ae_frame_leave(_state); return; } ae_matrix_set_length(&a1, m, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a1.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } if( isupper ) { for(i=0; i<=m-1; i++) { for(j=i; j<=m-1; j++) { a1.ptr.pp_complex[i][j] = a->ptr.pp_complex[i1+i][j1+j]; } } } else { for(i=0; i<=m-1; i++) { for(j=0; j<=i; j++) { a1.ptr.pp_complex[i][j] = a->ptr.pp_complex[i1+i][j1+j]; } } } rupper = isupper; if( isunit ) { for(i=0; i<=m-1; i++) { a1.ptr.pp_complex[i][i] = ae_complex_from_i(1); } } ae_matrix_set_length(&a2, m, m, _state); if( optype==0 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_complex[i][j] = a1.ptr.pp_complex[i][j]; } } } if( optype==1 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_complex[i][j] = a1.ptr.pp_complex[j][i]; } } rupper = !rupper; } if( optype==2 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_complex[i][j] = ae_c_conj(a1.ptr.pp_complex[j][i], _state); } } rupper = !rupper; } testablasunit_internalcmatrixtrinverse(&a2, m, rupper, ae_false, _state); ae_vector_set_length(&tx, m, _state); for(j=0; j<=n-1; j++) { ae_v_cmove(&tx.ptr.p_complex[0], 1, &x->ptr.pp_complex[i2][j2+j], x->stride, "N", ae_v_len(0,m-1)); for(i=0; i<=m-1; i++) { vc = ae_v_cdotproduct(&a2.ptr.pp_complex[i][0], 1, "N", &tx.ptr.p_complex[0], 1, "N", ae_v_len(0,m-1)); x->ptr.pp_complex[i2+i][j2+j] = vc; } } ae_frame_leave(_state); } /************************************************************************* Reference implementation -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refrmatrixrighttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_frame _frame_block; ae_matrix a1; ae_matrix a2; ae_vector tx; ae_int_t i; ae_int_t j; double vr; ae_bool rupper; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); if( n*m==0 ) { ae_frame_leave(_state); return; } ae_matrix_set_length(&a1, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = (double)(0); } } if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a1.ptr.pp_double[i][j] = a->ptr.pp_double[i1+i][j1+j]; } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { a1.ptr.pp_double[i][j] = a->ptr.pp_double[i1+i][j1+j]; } } } rupper = isupper; if( isunit ) { for(i=0; i<=n-1; i++) { a1.ptr.pp_double[i][i] = (double)(1); } } ae_matrix_set_length(&a2, n, n, _state); if( optype==0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a2.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]; } } } if( optype==1 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a2.ptr.pp_double[i][j] = a1.ptr.pp_double[j][i]; } } rupper = !rupper; } testablasunit_internalrmatrixtrinverse(&a2, n, rupper, ae_false, _state); ae_vector_set_length(&tx, n, _state); for(i=0; i<=m-1; i++) { ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(0,n-1)); for(j=0; j<=n-1; j++) { vr = ae_v_dotproduct(&tx.ptr.p_double[0], 1, &a2.ptr.pp_double[0][j], a2.stride, ae_v_len(0,n-1)); x->ptr.pp_double[i2+i][j2+j] = vr; } } ae_frame_leave(_state); } /************************************************************************* Reference implementation -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refrmatrixlefttrsm(ae_int_t m, ae_int_t n, /* Real */ ae_matrix* a, ae_int_t i1, ae_int_t j1, ae_bool isupper, ae_bool isunit, ae_int_t optype, /* Real */ ae_matrix* x, ae_int_t i2, ae_int_t j2, ae_state *_state) { ae_frame _frame_block; ae_matrix a1; ae_matrix a2; ae_vector tx; ae_int_t i; ae_int_t j; double vr; ae_bool rupper; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); if( n*m==0 ) { ae_frame_leave(_state); return; } ae_matrix_set_length(&a1, m, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a1.ptr.pp_double[i][j] = (double)(0); } } if( isupper ) { for(i=0; i<=m-1; i++) { for(j=i; j<=m-1; j++) { a1.ptr.pp_double[i][j] = a->ptr.pp_double[i1+i][j1+j]; } } } else { for(i=0; i<=m-1; i++) { for(j=0; j<=i; j++) { a1.ptr.pp_double[i][j] = a->ptr.pp_double[i1+i][j1+j]; } } } rupper = isupper; if( isunit ) { for(i=0; i<=m-1; i++) { a1.ptr.pp_double[i][i] = (double)(1); } } ae_matrix_set_length(&a2, m, m, _state); if( optype==0 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]; } } } if( optype==1 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_double[i][j] = a1.ptr.pp_double[j][i]; } } rupper = !rupper; } testablasunit_internalrmatrixtrinverse(&a2, m, rupper, ae_false, _state); ae_vector_set_length(&tx, m, _state); for(j=0; j<=n-1; j++) { ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.pp_double[i2][j2+j], x->stride, ae_v_len(0,m-1)); for(i=0; i<=m-1; i++) { vr = ae_v_dotproduct(&a2.ptr.pp_double[i][0], 1, &tx.ptr.p_double[0], 1, ae_v_len(0,m-1)); x->ptr.pp_double[i2+i][j2+j] = vr; } } ae_frame_leave(_state); } /************************************************************************* Internal subroutine. Triangular matrix inversion -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static ae_bool testablasunit_internalcmatrixtrinverse(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state) { ae_frame _frame_block; ae_bool nounit; ae_int_t i; ae_int_t j; ae_complex v; ae_complex ajj; ae_vector t; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&t, 0, DT_COMPLEX, _state); result = ae_true; ae_vector_set_length(&t, n-1+1, _state); /* * Test the input parameters. */ nounit = !isunittriangular; if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( nounit ) { if( ae_c_eq_d(a->ptr.pp_complex[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_complex[j][j] = ae_c_d_div(1,a->ptr.pp_complex[j][j]); ajj = ae_c_neg(a->ptr.pp_complex[j][j]); } else { ajj = ae_complex_from_i(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_cmove(&t.ptr.p_complex[0], 1, &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( i+1ptr.pp_complex[i][i+1], 1, "N", &t.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,j-1)); } else { v = ae_complex_from_i(0); } if( nounit ) { a->ptr.pp_complex[i][j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[i][i],t.ptr.p_complex[i])); } else { a->ptr.pp_complex[i][j] = ae_c_add(v,t.ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[0][j], a->stride, ae_v_len(0,j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( nounit ) { if( ae_c_eq_d(a->ptr.pp_complex[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_complex[j][j] = ae_c_d_div(1,a->ptr.pp_complex[j][j]); ajj = ae_c_neg(a->ptr.pp_complex[j][j]); } else { ajj = ae_complex_from_i(-1); } if( j+1ptr.pp_complex[j+1][j], a->stride, "N", ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[i][j+1], 1, "N", &t.ptr.p_complex[j+1], 1, "N", ae_v_len(j+1,i-1)); } else { v = ae_complex_from_i(0); } if( nounit ) { a->ptr.pp_complex[i][j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[i][i],t.ptr.p_complex[i])); } else { a->ptr.pp_complex[i][j] = ae_c_add(v,t.ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[j+1][j], a->stride, ae_v_len(j+1,n-1), ajj); } } } ae_frame_leave(_state); return result; } /************************************************************************* Internal subroutine. Triangular matrix inversion -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University February 29, 1992 *************************************************************************/ static ae_bool testablasunit_internalrmatrixtrinverse(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state) { ae_frame _frame_block; ae_bool nounit; ae_int_t i; ae_int_t j; double v; double ajj; ae_vector t; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&t, 0, DT_REAL, _state); result = ae_true; ae_vector_set_length(&t, n-1+1, _state); /* * Test the input parameters. */ nounit = !isunittriangular; if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_move(&t.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_double[i][i+1], 1, &t.ptr.p_double[i+1], 1, ae_v_len(i+1,j-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } if( jptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_dotproduct(&a->ptr.pp_double[i][j+1], 1, &t.ptr.p_double[j+1], 1, ae_v_len(j+1,i-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1), ajj); } } } ae_frame_leave(_state); return result; } /************************************************************************* Reference SYRK subroutine. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refcmatrixherk(ae_int_t n, ae_int_t k, double alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix ae; ae_int_t i; ae_int_t j; ae_complex vc; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ae, 0, 0, DT_COMPLEX, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (isupper&&j>=i)||(!isupper&&j<=i) ) { if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_complex[i+ic][j+jc] = ae_complex_from_i(0); } else { c->ptr.pp_complex[i+ic][j+jc] = ae_c_mul_d(c->ptr.pp_complex[i+ic][j+jc],beta); } } } } if( ae_fp_eq(alpha,(double)(0)) ) { ae_frame_leave(_state); return; } if( n*k>0 ) { ae_matrix_set_length(&ae, n, k, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { if( optypea==0 ) { ae.ptr.pp_complex[i][j] = a->ptr.pp_complex[ia+i][ja+j]; } if( optypea==2 ) { ae.ptr.pp_complex[i][j] = ae_c_conj(a->ptr.pp_complex[ia+j][ja+i], _state); } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vc = ae_complex_from_i(0); if( k>0 ) { vc = ae_v_cdotproduct(&ae.ptr.pp_complex[i][0], 1, "N", &ae.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,k-1)); } vc = ae_c_mul_d(vc,alpha); if( isupper&&j>=i ) { c->ptr.pp_complex[ic+i][jc+j] = ae_c_add(vc,c->ptr.pp_complex[ic+i][jc+j]); } if( !isupper&&j<=i ) { c->ptr.pp_complex[ic+i][jc+j] = ae_c_add(vc,c->ptr.pp_complex[ic+i][jc+j]); } } } ae_frame_leave(_state); } /************************************************************************* Reference SYRK subroutine. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/ static void testablasunit_refrmatrixsyrk(ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix ae; ae_int_t i; ae_int_t j; double vr; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ae, 0, 0, DT_REAL, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (isupper&&j>=i)||(!isupper&&j<=i) ) { if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[i+ic][j+jc] = (double)(0); } else { c->ptr.pp_double[i+ic][j+jc] = c->ptr.pp_double[i+ic][j+jc]*beta; } } } } if( ae_fp_eq(alpha,(double)(0)) ) { ae_frame_leave(_state); return; } if( n*k>0 ) { ae_matrix_set_length(&ae, n, k, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { if( optypea==0 ) { ae.ptr.pp_double[i][j] = a->ptr.pp_double[ia+i][ja+j]; } if( optypea==1 ) { ae.ptr.pp_double[i][j] = a->ptr.pp_double[ia+j][ja+i]; } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { vr = (double)(0); if( k>0 ) { vr = ae_v_dotproduct(&ae.ptr.pp_double[i][0], 1, &ae.ptr.pp_double[j][0], 1, ae_v_len(0,k-1)); } vr = alpha*vr; if( isupper&&j>=i ) { c->ptr.pp_double[ic+i][jc+j] = vr+c->ptr.pp_double[ic+i][jc+j]; } if( !isupper&&j<=i ) { c->ptr.pp_double[ic+i][jc+j] = vr+c->ptr.pp_double[ic+i][jc+j]; } } } ae_frame_leave(_state); } /************************************************************************* Reference GEMM, ALGLIB subroutine *************************************************************************/ static void testablasunit_refcmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, ae_complex alpha, /* Complex */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Complex */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, ae_complex beta, /* Complex */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_frame _frame_block; ae_matrix ae; ae_matrix be; ae_int_t i; ae_int_t j; ae_complex vc; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ae, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&be, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&ae, m, k, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { if( optypea==0 ) { ae.ptr.pp_complex[i][j] = a->ptr.pp_complex[ia+i][ja+j]; } if( optypea==1 ) { ae.ptr.pp_complex[i][j] = a->ptr.pp_complex[ia+j][ja+i]; } if( optypea==2 ) { ae.ptr.pp_complex[i][j] = ae_c_conj(a->ptr.pp_complex[ia+j][ja+i], _state); } } } ae_matrix_set_length(&be, k, n, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { if( optypeb==0 ) { be.ptr.pp_complex[i][j] = b->ptr.pp_complex[ib+i][jb+j]; } if( optypeb==1 ) { be.ptr.pp_complex[i][j] = b->ptr.pp_complex[ib+j][jb+i]; } if( optypeb==2 ) { be.ptr.pp_complex[i][j] = ae_c_conj(b->ptr.pp_complex[ib+j][jb+i], _state); } } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { vc = ae_v_cdotproduct(&ae.ptr.pp_complex[i][0], 1, "N", &be.ptr.pp_complex[0][j], be.stride, "N", ae_v_len(0,k-1)); vc = ae_c_mul(alpha,vc); if( ae_c_neq_d(beta,(double)(0)) ) { vc = ae_c_add(vc,ae_c_mul(beta,c->ptr.pp_complex[ic+i][jc+j])); } c->ptr.pp_complex[ic+i][jc+j] = vc; } } ae_frame_leave(_state); } /************************************************************************* Reference GEMM, ALGLIB subroutine *************************************************************************/ static void testablasunit_refrmatrixgemm(ae_int_t m, ae_int_t n, ae_int_t k, double alpha, /* Real */ ae_matrix* a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, /* Real */ ae_matrix* b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, /* Real */ ae_matrix* c, ae_int_t ic, ae_int_t jc, ae_state *_state) { ae_frame _frame_block; ae_matrix ae; ae_matrix be; ae_int_t i; ae_int_t j; double vc; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ae, 0, 0, DT_REAL, _state); ae_matrix_init(&be, 0, 0, DT_REAL, _state); ae_matrix_set_length(&ae, m, k, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { if( optypea==0 ) { ae.ptr.pp_double[i][j] = a->ptr.pp_double[ia+i][ja+j]; } if( optypea==1 ) { ae.ptr.pp_double[i][j] = a->ptr.pp_double[ia+j][ja+i]; } } } ae_matrix_set_length(&be, k, n, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { if( optypeb==0 ) { be.ptr.pp_double[i][j] = b->ptr.pp_double[ib+i][jb+j]; } if( optypeb==1 ) { be.ptr.pp_double[i][j] = b->ptr.pp_double[ib+j][jb+i]; } } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { vc = ae_v_dotproduct(&ae.ptr.pp_double[i][0], 1, &be.ptr.pp_double[0][j], be.stride, ae_v_len(0,k-1)); vc = alpha*vc; if( ae_fp_neq(beta,(double)(0)) ) { vc = vc+beta*c->ptr.pp_double[ic+i][jc+j]; } c->ptr.pp_double[ic+i][jc+j] = vc; } } ae_frame_leave(_state); } static void testbasestatunit_testranking(ae_bool* err, ae_state *_state); ae_bool testbasestat(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool s1errors; ae_bool covcorrerrors; ae_bool rankerrors; double threshold; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t kx; ae_int_t ky; ae_int_t ctype; ae_int_t cidxx; ae_int_t cidxy; ae_vector x; ae_vector y; ae_matrix mx; ae_matrix my; ae_matrix cc; ae_matrix cp; ae_matrix cs; double mean; double variance; double skewness; double kurtosis; double adev; double median; double pv; double v; double tmean; double tvariance; double tskewness; double tkurtosis; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&mx, 0, 0, DT_REAL, _state); ae_matrix_init(&my, 0, 0, DT_REAL, _state); ae_matrix_init(&cc, 0, 0, DT_REAL, _state); ae_matrix_init(&cp, 0, 0, DT_REAL, _state); ae_matrix_init(&cs, 0, 0, DT_REAL, _state); /* * Primary settings */ waserrors = ae_false; s1errors = ae_false; covcorrerrors = ae_false; rankerrors = ae_false; threshold = 1000*ae_machineepsilon; /* * Ranking */ testbasestatunit_testranking(&rankerrors, _state); /* * * prepare X and Y - two test samples * * test 1-sample coefficients * * test for SampleMean, SampleVariance, * SampleSkewness, SampleKurtosis. */ n = 10; ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_sqr((double)(i), _state); } samplemoments(&x, n, &mean, &variance, &skewness, &kurtosis, _state); s1errors = s1errors||ae_fp_greater(ae_fabs(mean-28.5, _state),0.001); s1errors = s1errors||ae_fp_greater(ae_fabs(variance-801.1667, _state),0.001); s1errors = s1errors||ae_fp_greater(ae_fabs(skewness-0.5751, _state),0.001); s1errors = s1errors||ae_fp_greater(ae_fabs(kurtosis+1.2666, _state),0.001); tmean = samplemean(&x, n, _state); tvariance = samplevariance(&x, n, _state); tskewness = sampleskewness(&x, n, _state); tkurtosis = samplekurtosis(&x, n, _state); s1errors = s1errors||ae_fp_neq(mean-tmean,(double)(0)); s1errors = s1errors||ae_fp_neq(variance-tvariance,(double)(0)); s1errors = s1errors||ae_fp_neq(skewness-tskewness,(double)(0)); s1errors = s1errors||ae_fp_neq(kurtosis-tkurtosis,(double)(0)); sampleadev(&x, n, &adev, _state); s1errors = s1errors||ae_fp_greater(ae_fabs(adev-23.2000, _state),0.001); samplemedian(&x, n, &median, _state); s1errors = s1errors||ae_fp_greater(ae_fabs(median-0.5*(16+25), _state),0.001); for(i=0; i<=n-1; i++) { samplepercentile(&x, n, (double)i/(double)(n-1), &pv, _state); s1errors = s1errors||ae_fp_greater(ae_fabs(pv-x.ptr.p_double[i], _state),0.001); } samplepercentile(&x, n, 0.5, &pv, _state); s1errors = s1errors||ae_fp_greater(ae_fabs(pv-0.5*(16+25), _state),0.001); /* * test covariance/correlation: * * 2-sample coefficients * * We generate random matrices MX and MY */ n = 10; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_sqr((double)(i), _state); y.ptr.p_double[i] = (double)(i); } covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(pearsoncorr2(&x, &y, n, _state)-0.9627, _state),0.0001); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(spearmancorr2(&x, &y, n, _state)-1.0000, _state),0.0001); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(cov2(&x, &y, n, _state)-82.5000, _state),0.0001); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_sqr(i-0.5*n, _state); y.ptr.p_double[i] = (double)(i); } covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(pearsoncorr2(&x, &y, n, _state)+0.3676, _state),0.0001); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(spearmancorr2(&x, &y, n, _state)+0.2761, _state),0.0001); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(cov2(&x, &y, n, _state)+9.1667, _state),0.0001); /* * test covariance/correlation: * * matrix covariance/correlation * * matrix cross-covariance/cross-correlation * * We generate random matrices MX and MY which contain KX (KY) * columns, all except one are random, one of them is constant. * We test that function (a) do not crash on constant column, * and (b) return variances/correlations that are exactly zero * for this column. * * CType control variable controls type of constant: 0 - no constant * column, 1 - zero column, 2 - nonzero column with value whose * binary representation contains many non-zero bits. Using such * type of constant column we are able to ensure than even in the * presense of roundoff error functions correctly detect constant * columns. */ for(n=0; n<=10; n++) { if( n>0 ) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); } for(ctype=0; ctype<=2; ctype++) { for(kx=1; kx<=10; kx++) { for(ky=1; ky<=10; ky++) { /* * Fill matrices, add constant column (when CType=1 or =2) */ cidxx = -1; cidxy = -1; if( n>0 ) { ae_matrix_set_length(&mx, n, kx, _state); ae_matrix_set_length(&my, n, ky, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=kx-1; j++) { mx.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } for(j=0; j<=ky-1; j++) { my.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } if( ctype==1 ) { cidxx = ae_randominteger(kx, _state); cidxy = ae_randominteger(ky, _state); for(i=0; i<=n-1; i++) { mx.ptr.pp_double[i][cidxx] = 0.0; my.ptr.pp_double[i][cidxy] = 0.0; } } if( ctype==2 ) { cidxx = ae_randominteger(kx, _state); cidxy = ae_randominteger(ky, _state); v = ae_sqrt((double)(ae_randominteger(kx, _state)+1)/(double)kx, _state); for(i=0; i<=n-1; i++) { mx.ptr.pp_double[i][cidxx] = v; my.ptr.pp_double[i][cidxy] = v; } } } /* * test covariance/correlation matrix using * 2-sample functions as reference point. * * We also test that coefficients for constant variables * are exactly zero. */ covm(&mx, n, kx, &cc, _state); pearsoncorrm(&mx, n, kx, &cp, _state); spearmancorrm(&mx, n, kx, &cs, _state); for(i=0; i<=kx-1; i++) { for(j=0; j<=kx-1; j++) { if( n>0 ) { ae_v_move(&x.ptr.p_double[0], 1, &mx.ptr.pp_double[0][i], mx.stride, ae_v_len(0,n-1)); ae_v_move(&y.ptr.p_double[0], 1, &mx.ptr.pp_double[0][j], mx.stride, ae_v_len(0,n-1)); } covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(cov2(&x, &y, n, _state)-cc.ptr.pp_double[i][j], _state),threshold); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(pearsoncorr2(&x, &y, n, _state)-cp.ptr.pp_double[i][j], _state),threshold); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(spearmancorr2(&x, &y, n, _state)-cs.ptr.pp_double[i][j], _state),threshold); } } if( ctype!=0&&n>0 ) { for(i=0; i<=kx-1; i++) { covcorrerrors = covcorrerrors||ae_fp_neq(cc.ptr.pp_double[i][cidxx],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cc.ptr.pp_double[cidxx][i],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cp.ptr.pp_double[i][cidxx],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cp.ptr.pp_double[cidxx][i],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cs.ptr.pp_double[i][cidxx],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cs.ptr.pp_double[cidxx][i],(double)(0)); } } /* * test cross-covariance/cross-correlation matrix using * 2-sample functions as reference point. * * We also test that coefficients for constant variables * are exactly zero. */ covm2(&mx, &my, n, kx, ky, &cc, _state); pearsoncorrm2(&mx, &my, n, kx, ky, &cp, _state); spearmancorrm2(&mx, &my, n, kx, ky, &cs, _state); for(i=0; i<=kx-1; i++) { for(j=0; j<=ky-1; j++) { if( n>0 ) { ae_v_move(&x.ptr.p_double[0], 1, &mx.ptr.pp_double[0][i], mx.stride, ae_v_len(0,n-1)); ae_v_move(&y.ptr.p_double[0], 1, &my.ptr.pp_double[0][j], my.stride, ae_v_len(0,n-1)); } covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(cov2(&x, &y, n, _state)-cc.ptr.pp_double[i][j], _state),threshold); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(pearsoncorr2(&x, &y, n, _state)-cp.ptr.pp_double[i][j], _state),threshold); covcorrerrors = covcorrerrors||ae_fp_greater(ae_fabs(spearmancorr2(&x, &y, n, _state)-cs.ptr.pp_double[i][j], _state),threshold); } } if( ctype!=0&&n>0 ) { for(i=0; i<=kx-1; i++) { covcorrerrors = covcorrerrors||ae_fp_neq(cc.ptr.pp_double[i][cidxy],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cp.ptr.pp_double[i][cidxy],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cs.ptr.pp_double[i][cidxy],(double)(0)); } for(j=0; j<=ky-1; j++) { covcorrerrors = covcorrerrors||ae_fp_neq(cc.ptr.pp_double[cidxx][j],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cp.ptr.pp_double[cidxx][j],(double)(0)); covcorrerrors = covcorrerrors||ae_fp_neq(cs.ptr.pp_double[cidxx][j],(double)(0)); } } } } } } /* * Final report */ waserrors = (s1errors||covcorrerrors)||rankerrors; if( !silent ) { printf("DESC.STAT TEST\n"); printf("TOTAL RESULTS: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* 1-SAMPLE FUNCTIONALITY: "); if( !s1errors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* CORRELATION/COVARIATION: "); if( !covcorrerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* RANKING: "); if( !rankerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testbasestat(ae_bool silent, ae_state *_state) { return testbasestat(silent, _state); } /************************************************************************* This function tests ranking functionality. In case of failure it sets Err parameter to True; this parameter is left unchanged otherwise. *************************************************************************/ static void testbasestatunit_testranking(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t testk; ae_int_t npoints; ae_int_t nfeatures; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix xy0; ae_matrix xy1; ae_matrix xy2; double v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy0, 0, 0, DT_REAL, _state); ae_matrix_init(&xy1, 0, 0, DT_REAL, _state); ae_matrix_init(&xy2, 0, 0, DT_REAL, _state); /* * Test 1 - large array, unique ranks, each row is obtained as follows: * * we generate X[i=0..N-1] = I * * we add random noise: X[i] := X[i] + 0.2*randomreal()-0.1 * * we perform random permutation * * Such dataset has following properties: * * all data are unique within their rows * * rank(X[i]) = round(X[i]) * * We perform several tests with different NPoints/NFeatures. */ for(testk=0; testk<=1; testk++) { /* * Select problem size */ if( testk==0 ) { npoints = 200; nfeatures = 1000; } else { npoints = 1000; nfeatures = 200; } /* * Generate XY0, XY1, XY2 */ ae_matrix_set_length(&xy0, npoints, nfeatures, _state); ae_matrix_set_length(&xy1, npoints, nfeatures, _state); ae_matrix_set_length(&xy2, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { xy0.ptr.pp_double[i][j] = j+0.2*ae_randomreal(_state)-0.1; } for(j=0; j<=nfeatures-2; j++) { k = ae_randominteger(nfeatures-j, _state); if( k!=0 ) { v = xy0.ptr.pp_double[i][j]; xy0.ptr.pp_double[i][j] = xy0.ptr.pp_double[i][j+k]; xy0.ptr.pp_double[i][j+k] = v; } } for(j=0; j<=nfeatures-1; j++) { xy1.ptr.pp_double[i][j] = xy0.ptr.pp_double[i][j]; xy2.ptr.pp_double[i][j] = xy0.ptr.pp_double[i][j]; } } /* * Test uncentered ranks */ rankdata(&xy0, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { if( ae_fp_neq(xy0.ptr.pp_double[i][j],(double)(ae_round(xy2.ptr.pp_double[i][j], _state))) ) { *err = ae_true; } } } /* * Test centered ranks: * they must be equal to uncentered ranks minus (NFeatures-1)/2 */ rankdatacentered(&xy1, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { if( ae_fp_neq(xy1.ptr.pp_double[i][j],ae_round(xy2.ptr.pp_double[i][j], _state)-(double)(nfeatures-1)/(double)2) ) { *err = ae_true; } } } } /* * Test correct handling of tied ranks */ npoints = 3; nfeatures = 4; ae_matrix_set_length(&xy0, npoints, nfeatures, _state); ae_matrix_set_length(&xy1, npoints, nfeatures, _state); xy0.ptr.pp_double[0][0] = 2.25; xy0.ptr.pp_double[0][1] = 3.75; xy0.ptr.pp_double[0][2] = 3.25; xy0.ptr.pp_double[0][3] = 2.25; xy0.ptr.pp_double[1][0] = (double)(2); xy0.ptr.pp_double[1][1] = (double)(2); xy0.ptr.pp_double[1][2] = (double)(2); xy0.ptr.pp_double[1][3] = (double)(7); xy0.ptr.pp_double[2][0] = (double)(9); xy0.ptr.pp_double[2][1] = (double)(9); xy0.ptr.pp_double[2][2] = (double)(9); xy0.ptr.pp_double[2][3] = (double)(9); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { xy1.ptr.pp_double[i][j] = xy0.ptr.pp_double[i][j]; } } rankdata(&xy0, npoints, nfeatures, _state); if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[0][0]-0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[0][1]-3.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[0][2]-2.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[0][3]-0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[1][0]-1.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[1][1]-1.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[1][2]-1.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[1][3]-3.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[2][0]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[2][1]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[2][2]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy0.ptr.pp_double[2][3]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } rankdatacentered(&xy1, npoints, nfeatures, _state); if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[0][0]+1.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[0][1]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[0][2]-0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[0][3]+1.0, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[1][0]+0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[1][1]+0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[1][2]+0.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_greater(ae_fabs(xy1.ptr.pp_double[1][3]-1.5, _state),10*ae_machineepsilon) ) { *err = ae_true; } if( ae_fp_neq(xy1.ptr.pp_double[2][0],(double)(0)) ) { *err = ae_true; } if( ae_fp_neq(xy1.ptr.pp_double[2][1],(double)(0)) ) { *err = ae_true; } if( ae_fp_neq(xy1.ptr.pp_double[2][2],(double)(0)) ) { *err = ae_true; } if( ae_fp_neq(xy1.ptr.pp_double[2][3],(double)(0)) ) { *err = ae_true; } ae_frame_leave(_state); } static void testbdssunit_unset1di(/* Integer */ ae_vector* a, ae_state *_state); /************************************************************************* Testing BDSS operations *************************************************************************/ ae_bool testbdss(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t passcount; ae_int_t maxn; ae_int_t maxnq; ae_vector a; ae_vector a0; ae_vector at; ae_matrix p; ae_vector thresholds; ae_int_t ni; ae_vector c; ae_vector p1; ae_vector p2; ae_vector ties; ae_vector pt1; ae_vector pt2; ae_int_t tiecount; ae_int_t c1; ae_int_t c0; ae_int_t nc; ae_vector tmp; ae_vector sortrbuf; ae_vector sortrbuf2; ae_vector sortibuf; double pal; double pbl; double par; double pbr; double cve; double cvr; ae_int_t info; double threshold; ae_vector tiebuf; ae_vector cntbuf; double rms; double cvrms; ae_bool waserrors; ae_bool tieserrors; ae_bool split2errors; ae_bool optimalsplitkerrors; ae_bool splitkerrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&a0, 0, DT_REAL, _state); ae_vector_init(&at, 0, DT_REAL, _state); ae_matrix_init(&p, 0, 0, DT_REAL, _state); ae_vector_init(&thresholds, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_INT, _state); ae_vector_init(&p1, 0, DT_INT, _state); ae_vector_init(&p2, 0, DT_INT, _state); ae_vector_init(&ties, 0, DT_INT, _state); ae_vector_init(&pt1, 0, DT_INT, _state); ae_vector_init(&pt2, 0, DT_INT, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&sortrbuf, 0, DT_REAL, _state); ae_vector_init(&sortrbuf2, 0, DT_REAL, _state); ae_vector_init(&sortibuf, 0, DT_INT, _state); ae_vector_init(&tiebuf, 0, DT_INT, _state); ae_vector_init(&cntbuf, 0, DT_INT, _state); waserrors = ae_false; tieserrors = ae_false; split2errors = ae_false; splitkerrors = ae_false; optimalsplitkerrors = ae_false; maxn = 100; maxnq = 49; passcount = 10; /* * Test ties */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { /* * untied data, test DSTie */ testbdssunit_unset1di(&p1, _state); testbdssunit_unset1di(&p2, _state); testbdssunit_unset1di(&pt1, _state); testbdssunit_unset1di(&pt2, _state); ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&a0, n-1+1, _state); ae_vector_set_length(&at, n-1+1, _state); ae_vector_set_length(&tmp, n-1+1, _state); a.ptr.p_double[0] = 2*ae_randomreal(_state)-1; tmp.ptr.p_double[0] = ae_randomreal(_state); for(i=1; i<=n-1; i++) { /* * A is randomly permuted */ a.ptr.p_double[i] = a.ptr.p_double[i-1]+0.1*ae_randomreal(_state)+0.1; tmp.ptr.p_double[i] = ae_randomreal(_state); } tagsortfastr(&tmp, &a, &sortrbuf, &sortrbuf2, n, _state); for(i=0; i<=n-1; i++) { a0.ptr.p_double[i] = a.ptr.p_double[i]; at.ptr.p_double[i] = a.ptr.p_double[i]; } dstie(&a0, n, &ties, &tiecount, &p1, &p2, _state); tagsort(&at, n, &pt1, &pt2, _state); for(i=0; i<=n-1; i++) { tieserrors = tieserrors||p1.ptr.p_int[i]!=pt1.ptr.p_int[i]; tieserrors = tieserrors||p2.ptr.p_int[i]!=pt2.ptr.p_int[i]; } tieserrors = tieserrors||tiecount!=n; if( tiecount==n ) { for(i=0; i<=n; i++) { tieserrors = tieserrors||ties.ptr.p_int[i]!=i; } } /* * tied data, test DSTie */ testbdssunit_unset1di(&p1, _state); testbdssunit_unset1di(&p2, _state); testbdssunit_unset1di(&pt1, _state); testbdssunit_unset1di(&pt2, _state); ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&a0, n-1+1, _state); ae_vector_set_length(&at, n-1+1, _state); c1 = 0; c0 = 0; for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(ae_randominteger(2, _state)); if( ae_fp_eq(a.ptr.p_double[i],(double)(0)) ) { c0 = c0+1; } else { c1 = c1+1; } a0.ptr.p_double[i] = a.ptr.p_double[i]; at.ptr.p_double[i] = a.ptr.p_double[i]; } dstie(&a0, n, &ties, &tiecount, &p1, &p2, _state); tagsort(&at, n, &pt1, &pt2, _state); for(i=0; i<=n-1; i++) { tieserrors = tieserrors||p1.ptr.p_int[i]!=pt1.ptr.p_int[i]; tieserrors = tieserrors||p2.ptr.p_int[i]!=pt2.ptr.p_int[i]; } if( c0==0||c1==0 ) { tieserrors = tieserrors||tiecount!=1; if( tiecount==1 ) { tieserrors = tieserrors||ties.ptr.p_int[0]!=0; tieserrors = tieserrors||ties.ptr.p_int[1]!=n; } } else { tieserrors = tieserrors||tiecount!=2; if( tiecount==2 ) { tieserrors = tieserrors||ties.ptr.p_int[0]!=0; tieserrors = tieserrors||ties.ptr.p_int[1]!=c0; tieserrors = tieserrors||ties.ptr.p_int[2]!=n; } } } } /* * split-2 */ /* * General tests for different N's */ for(n=1; n<=maxn; n++) { ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); /* * one-tie test */ if( n%2==0 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(n); c.ptr.p_int[i] = i%2; } dsoptimalsplit2(&a, &c, n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, _state); if( info!=-3 ) { split2errors = ae_true; continue; } } /* * two-tie test */ /* * test #1 */ if( n>1 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(i/((n+1)/2)); c.ptr.p_int[i] = i/((n+1)/2); } dsoptimalsplit2(&a, &c, n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, _state); if( info!=1 ) { split2errors = ae_true; continue; } split2errors = split2errors||ae_fp_greater(ae_fabs(threshold-0.5, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(pal-1, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(pbl-0, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(par-0, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(pbr-1, _state),100*ae_machineepsilon); } } /* * Special "CREDIT"-test (transparency coefficient) */ n = 110; ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); a.ptr.p_double[0] = 0.000; c.ptr.p_int[0] = 0; a.ptr.p_double[1] = 0.000; c.ptr.p_int[1] = 0; a.ptr.p_double[2] = 0.000; c.ptr.p_int[2] = 0; a.ptr.p_double[3] = 0.000; c.ptr.p_int[3] = 0; a.ptr.p_double[4] = 0.000; c.ptr.p_int[4] = 0; a.ptr.p_double[5] = 0.000; c.ptr.p_int[5] = 0; a.ptr.p_double[6] = 0.000; c.ptr.p_int[6] = 0; a.ptr.p_double[7] = 0.000; c.ptr.p_int[7] = 1; a.ptr.p_double[8] = 0.000; c.ptr.p_int[8] = 0; a.ptr.p_double[9] = 0.000; c.ptr.p_int[9] = 1; a.ptr.p_double[10] = 0.000; c.ptr.p_int[10] = 0; a.ptr.p_double[11] = 0.000; c.ptr.p_int[11] = 0; a.ptr.p_double[12] = 0.000; c.ptr.p_int[12] = 0; a.ptr.p_double[13] = 0.000; c.ptr.p_int[13] = 0; a.ptr.p_double[14] = 0.000; c.ptr.p_int[14] = 0; a.ptr.p_double[15] = 0.000; c.ptr.p_int[15] = 0; a.ptr.p_double[16] = 0.000; c.ptr.p_int[16] = 0; a.ptr.p_double[17] = 0.000; c.ptr.p_int[17] = 0; a.ptr.p_double[18] = 0.000; c.ptr.p_int[18] = 0; a.ptr.p_double[19] = 0.000; c.ptr.p_int[19] = 0; a.ptr.p_double[20] = 0.000; c.ptr.p_int[20] = 0; a.ptr.p_double[21] = 0.000; c.ptr.p_int[21] = 0; a.ptr.p_double[22] = 0.000; c.ptr.p_int[22] = 1; a.ptr.p_double[23] = 0.000; c.ptr.p_int[23] = 0; a.ptr.p_double[24] = 0.000; c.ptr.p_int[24] = 0; a.ptr.p_double[25] = 0.000; c.ptr.p_int[25] = 0; a.ptr.p_double[26] = 0.000; c.ptr.p_int[26] = 0; a.ptr.p_double[27] = 0.000; c.ptr.p_int[27] = 1; a.ptr.p_double[28] = 0.000; c.ptr.p_int[28] = 0; a.ptr.p_double[29] = 0.000; c.ptr.p_int[29] = 1; a.ptr.p_double[30] = 0.000; c.ptr.p_int[30] = 0; a.ptr.p_double[31] = 0.000; c.ptr.p_int[31] = 1; a.ptr.p_double[32] = 0.000; c.ptr.p_int[32] = 0; a.ptr.p_double[33] = 0.000; c.ptr.p_int[33] = 1; a.ptr.p_double[34] = 0.000; c.ptr.p_int[34] = 0; a.ptr.p_double[35] = 0.030; c.ptr.p_int[35] = 0; a.ptr.p_double[36] = 0.030; c.ptr.p_int[36] = 0; a.ptr.p_double[37] = 0.050; c.ptr.p_int[37] = 0; a.ptr.p_double[38] = 0.070; c.ptr.p_int[38] = 1; a.ptr.p_double[39] = 0.110; c.ptr.p_int[39] = 0; a.ptr.p_double[40] = 0.110; c.ptr.p_int[40] = 1; a.ptr.p_double[41] = 0.120; c.ptr.p_int[41] = 0; a.ptr.p_double[42] = 0.130; c.ptr.p_int[42] = 0; a.ptr.p_double[43] = 0.140; c.ptr.p_int[43] = 0; a.ptr.p_double[44] = 0.140; c.ptr.p_int[44] = 0; a.ptr.p_double[45] = 0.140; c.ptr.p_int[45] = 0; a.ptr.p_double[46] = 0.150; c.ptr.p_int[46] = 0; a.ptr.p_double[47] = 0.150; c.ptr.p_int[47] = 0; a.ptr.p_double[48] = 0.170; c.ptr.p_int[48] = 0; a.ptr.p_double[49] = 0.190; c.ptr.p_int[49] = 1; a.ptr.p_double[50] = 0.200; c.ptr.p_int[50] = 0; a.ptr.p_double[51] = 0.200; c.ptr.p_int[51] = 0; a.ptr.p_double[52] = 0.250; c.ptr.p_int[52] = 0; a.ptr.p_double[53] = 0.250; c.ptr.p_int[53] = 0; a.ptr.p_double[54] = 0.260; c.ptr.p_int[54] = 0; a.ptr.p_double[55] = 0.270; c.ptr.p_int[55] = 0; a.ptr.p_double[56] = 0.280; c.ptr.p_int[56] = 0; a.ptr.p_double[57] = 0.310; c.ptr.p_int[57] = 0; a.ptr.p_double[58] = 0.310; c.ptr.p_int[58] = 0; a.ptr.p_double[59] = 0.330; c.ptr.p_int[59] = 0; a.ptr.p_double[60] = 0.330; c.ptr.p_int[60] = 0; a.ptr.p_double[61] = 0.340; c.ptr.p_int[61] = 0; a.ptr.p_double[62] = 0.340; c.ptr.p_int[62] = 0; a.ptr.p_double[63] = 0.370; c.ptr.p_int[63] = 0; a.ptr.p_double[64] = 0.380; c.ptr.p_int[64] = 1; a.ptr.p_double[65] = 0.380; c.ptr.p_int[65] = 0; a.ptr.p_double[66] = 0.410; c.ptr.p_int[66] = 0; a.ptr.p_double[67] = 0.460; c.ptr.p_int[67] = 0; a.ptr.p_double[68] = 0.520; c.ptr.p_int[68] = 0; a.ptr.p_double[69] = 0.530; c.ptr.p_int[69] = 0; a.ptr.p_double[70] = 0.540; c.ptr.p_int[70] = 0; a.ptr.p_double[71] = 0.560; c.ptr.p_int[71] = 0; a.ptr.p_double[72] = 0.560; c.ptr.p_int[72] = 0; a.ptr.p_double[73] = 0.570; c.ptr.p_int[73] = 0; a.ptr.p_double[74] = 0.600; c.ptr.p_int[74] = 0; a.ptr.p_double[75] = 0.600; c.ptr.p_int[75] = 0; a.ptr.p_double[76] = 0.620; c.ptr.p_int[76] = 0; a.ptr.p_double[77] = 0.650; c.ptr.p_int[77] = 0; a.ptr.p_double[78] = 0.660; c.ptr.p_int[78] = 0; a.ptr.p_double[79] = 0.680; c.ptr.p_int[79] = 0; a.ptr.p_double[80] = 0.700; c.ptr.p_int[80] = 0; a.ptr.p_double[81] = 0.750; c.ptr.p_int[81] = 0; a.ptr.p_double[82] = 0.770; c.ptr.p_int[82] = 0; a.ptr.p_double[83] = 0.770; c.ptr.p_int[83] = 0; a.ptr.p_double[84] = 0.770; c.ptr.p_int[84] = 0; a.ptr.p_double[85] = 0.790; c.ptr.p_int[85] = 0; a.ptr.p_double[86] = 0.810; c.ptr.p_int[86] = 0; a.ptr.p_double[87] = 0.840; c.ptr.p_int[87] = 0; a.ptr.p_double[88] = 0.860; c.ptr.p_int[88] = 0; a.ptr.p_double[89] = 0.870; c.ptr.p_int[89] = 0; a.ptr.p_double[90] = 0.890; c.ptr.p_int[90] = 0; a.ptr.p_double[91] = 0.900; c.ptr.p_int[91] = 1; a.ptr.p_double[92] = 0.900; c.ptr.p_int[92] = 0; a.ptr.p_double[93] = 0.910; c.ptr.p_int[93] = 0; a.ptr.p_double[94] = 0.940; c.ptr.p_int[94] = 0; a.ptr.p_double[95] = 0.950; c.ptr.p_int[95] = 0; a.ptr.p_double[96] = 0.952; c.ptr.p_int[96] = 0; a.ptr.p_double[97] = 0.970; c.ptr.p_int[97] = 0; a.ptr.p_double[98] = 0.970; c.ptr.p_int[98] = 0; a.ptr.p_double[99] = 0.980; c.ptr.p_int[99] = 0; a.ptr.p_double[100] = 1.000; c.ptr.p_int[100] = 0; a.ptr.p_double[101] = 1.000; c.ptr.p_int[101] = 0; a.ptr.p_double[102] = 1.000; c.ptr.p_int[102] = 0; a.ptr.p_double[103] = 1.000; c.ptr.p_int[103] = 0; a.ptr.p_double[104] = 1.000; c.ptr.p_int[104] = 0; a.ptr.p_double[105] = 1.020; c.ptr.p_int[105] = 0; a.ptr.p_double[106] = 1.090; c.ptr.p_int[106] = 0; a.ptr.p_double[107] = 1.130; c.ptr.p_int[107] = 0; a.ptr.p_double[108] = 1.840; c.ptr.p_int[108] = 0; a.ptr.p_double[109] = 2.470; c.ptr.p_int[109] = 0; dsoptimalsplit2(&a, &c, n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, _state); if( info!=1 ) { split2errors = ae_true; } else { split2errors = split2errors||ae_fp_greater(ae_fabs(threshold-0.195, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(pal-0.80, _state),0.02); split2errors = split2errors||ae_fp_greater(ae_fabs(pbl-0.20, _state),0.02); split2errors = split2errors||ae_fp_greater(ae_fabs(par-0.97, _state),0.02); split2errors = split2errors||ae_fp_greater(ae_fabs(pbr-0.03, _state),0.02); } /* * split-2 fast */ /* * General tests for different N's */ for(n=1; n<=maxn; n++) { ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); ae_vector_set_length(&tiebuf, n+1, _state); ae_vector_set_length(&cntbuf, 3+1, _state); /* * one-tie test */ if( n%2==0 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(n); c.ptr.p_int[i] = i%2; } dsoptimalsplit2fast(&a, &c, &tiebuf, &cntbuf, &sortrbuf, &sortibuf, n, 2, 0.00, &info, &threshold, &rms, &cvrms, _state); if( info!=-3 ) { split2errors = ae_true; continue; } } /* * two-tie test */ /* * test #1 */ if( n>1 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(i/((n+1)/2)); c.ptr.p_int[i] = i/((n+1)/2); } dsoptimalsplit2fast(&a, &c, &tiebuf, &cntbuf, &sortrbuf, &sortibuf, n, 2, 0.00, &info, &threshold, &rms, &cvrms, _state); if( info!=1 ) { split2errors = ae_true; continue; } split2errors = split2errors||ae_fp_greater(ae_fabs(threshold-0.5, _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(rms-0, _state),100*ae_machineepsilon); if( n==2 ) { split2errors = split2errors||ae_fp_greater(ae_fabs(cvrms-0.5, _state),100*ae_machineepsilon); } else { if( n==3 ) { split2errors = split2errors||ae_fp_greater(ae_fabs(cvrms-ae_sqrt((2*0+2*0+2*0.25)/6, _state), _state),100*ae_machineepsilon); } else { split2errors = split2errors||ae_fp_greater(ae_fabs(cvrms, _state),100*ae_machineepsilon); } } } } /* * special tests */ n = 10; ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); ae_vector_set_length(&tiebuf, n+1, _state); ae_vector_set_length(&cntbuf, 2*3-1+1, _state); for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(i); if( i<=n-3 ) { c.ptr.p_int[i] = 0; } else { c.ptr.p_int[i] = i-(n-3); } } dsoptimalsplit2fast(&a, &c, &tiebuf, &cntbuf, &sortrbuf, &sortibuf, n, 3, 0.00, &info, &threshold, &rms, &cvrms, _state); if( info!=1 ) { split2errors = ae_true; } else { split2errors = split2errors||ae_fp_greater(ae_fabs(threshold-(n-2.5), _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(rms-ae_sqrt((0.25+0.25+0.25+0.25)/(3*n), _state), _state),100*ae_machineepsilon); split2errors = split2errors||ae_fp_greater(ae_fabs(cvrms-ae_sqrt((double)(1+1+1+1)/(double)(3*n), _state), _state),100*ae_machineepsilon); } /* * Optimal split-K */ /* * General tests for different N's */ for(n=1; n<=maxnq; n++) { ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); /* * one-tie test */ if( n%2==0 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(n); c.ptr.p_int[i] = i%2; } dsoptimalsplitk(&a, &c, n, 2, 2+ae_randominteger(5, _state), &info, &thresholds, &ni, &cve, _state); if( info!=-3 ) { optimalsplitkerrors = ae_true; continue; } } /* * two-tie test */ /* * test #1 */ if( n>1 ) { c0 = 0; c1 = 0; for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(i/((n+1)/2)); c.ptr.p_int[i] = i/((n+1)/2); if( c.ptr.p_int[i]==0 ) { c0 = c0+1; } if( c.ptr.p_int[i]==1 ) { c1 = c1+1; } } dsoptimalsplitk(&a, &c, n, 2, 2+ae_randominteger(5, _state), &info, &thresholds, &ni, &cve, _state); if( info!=1 ) { optimalsplitkerrors = ae_true; continue; } optimalsplitkerrors = optimalsplitkerrors||ni!=2; optimalsplitkerrors = optimalsplitkerrors||ae_fp_greater(ae_fabs(thresholds.ptr.p_double[0]-0.5, _state),100*ae_machineepsilon); optimalsplitkerrors = optimalsplitkerrors||ae_fp_greater(ae_fabs(cve-(-c0*ae_log((double)c0/(double)(c0+1), _state)-c1*ae_log((double)c1/(double)(c1+1), _state)), _state),100*ae_machineepsilon); } /* * test #2 */ if( n>2 ) { c0 = 1+ae_randominteger(n-1, _state); c1 = n-c0; for(i=0; i<=n-1; i++) { if( i=16 ) { /* * Multi-tie test. * * First NC-1 ties have C0 entries, remaining NC-th tie * have C1 entries. */ nc = ae_round(ae_sqrt((double)(n), _state), _state); c0 = n/nc; c1 = n-c0*(nc-1); for(i=0; i<=nc-2; i++) { for(j=c0*i; j<=c0*(i+1)-1; j++) { a.ptr.p_double[j] = (double)(j); c.ptr.p_int[j] = i; } } for(j=c0*(nc-1); j<=n-1; j++) { a.ptr.p_double[j] = (double)(j); c.ptr.p_int[j] = nc-1; } dsoptimalsplitk(&a, &c, n, nc, nc+ae_randominteger(nc, _state), &info, &thresholds, &ni, &cve, _state); if( info!=1 ) { optimalsplitkerrors = ae_true; continue; } optimalsplitkerrors = optimalsplitkerrors||ni!=nc; if( ni==nc ) { for(i=0; i<=nc-2; i++) { optimalsplitkerrors = optimalsplitkerrors||ae_fp_greater(ae_fabs(thresholds.ptr.p_double[i]-(c0*(i+1)-1+0.5), _state),100*ae_machineepsilon); } cvr = -((nc-1)*c0*ae_log((double)c0/(double)(c0+nc-1), _state)+c1*ae_log((double)c1/(double)(c1+nc-1), _state)); optimalsplitkerrors = optimalsplitkerrors||ae_fp_greater(ae_fabs(cve-cvr, _state),100*ae_machineepsilon); } } } /* * Non-optimal split-K */ /* * General tests for different N's */ for(n=1; n<=maxnq; n++) { ae_vector_set_length(&a, n-1+1, _state); ae_vector_set_length(&c, n-1+1, _state); /* * one-tie test */ if( n%2==0 ) { for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(99); c.ptr.p_int[i] = i%2; } dssplitk(&a, &c, n, 2, 2+ae_randominteger(5, _state), &info, &thresholds, &ni, &cve, _state); if( info!=-3 ) { splitkerrors = ae_true; continue; } } /* * two-tie test */ /* * test #1 */ if( n>1 ) { c0 = 0; c1 = 0; for(i=0; i<=n-1; i++) { a.ptr.p_double[i] = (double)(i/((n+1)/2)); c.ptr.p_int[i] = i/((n+1)/2); if( c.ptr.p_int[i]==0 ) { c0 = c0+1; } if( c.ptr.p_int[i]==1 ) { c1 = c1+1; } } dssplitk(&a, &c, n, 2, 2+ae_randominteger(5, _state), &info, &thresholds, &ni, &cve, _state); if( info!=1 ) { splitkerrors = ae_true; continue; } splitkerrors = splitkerrors||ni!=2; if( ni==2 ) { splitkerrors = splitkerrors||ae_fp_greater(ae_fabs(thresholds.ptr.p_double[0]-0.5, _state),100*ae_machineepsilon); splitkerrors = splitkerrors||ae_fp_greater(ae_fabs(cve-(-c0*ae_log((double)c0/(double)(c0+1), _state)-c1*ae_log((double)c1/(double)(c1+1), _state)), _state),100*ae_machineepsilon); } } /* * test #2 */ if( n>2 ) { c0 = 1+ae_randominteger(n-1, _state); c1 = n-c0; for(i=0; i<=n-1; i++) { if( i1 ) { nc = n/c0; for(i=0; i<=nc-1; i++) { for(j=c0*i; j<=c0*(i+1)-1; j++) { a.ptr.p_double[j] = (double)(j); c.ptr.p_int[j] = i; } } dssplitk(&a, &c, n, nc, nc+ae_randominteger(nc, _state), &info, &thresholds, &ni, &cve, _state); if( info!=1 ) { splitkerrors = ae_true; continue; } splitkerrors = splitkerrors||ni!=nc; if( ni==nc ) { for(i=0; i<=nc-2; i++) { splitkerrors = splitkerrors||ae_fp_greater(ae_fabs(thresholds.ptr.p_double[i]-(c0*(i+1)-1+0.5), _state),100*ae_machineepsilon); } cvr = -nc*c0*ae_log((double)c0/(double)(c0+nc-1), _state); splitkerrors = splitkerrors||ae_fp_greater(ae_fabs(cve-cvr, _state),100*ae_machineepsilon); } } } } /* * report */ waserrors = ((tieserrors||split2errors)||optimalsplitkerrors)||splitkerrors; if( !silent ) { printf("TESTING BASIC DATASET SUBROUTINES\n"); printf("TIES: "); if( !tieserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SPLIT-2: "); if( !split2errors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("OPTIMAL SPLIT-K: "); if( !optimalsplitkerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SPLIT-K: "); if( !splitkerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testbdss(ae_bool silent, ae_state *_state) { return testbdss(silent, _state); } /************************************************************************* Unsets 1D array. *************************************************************************/ static void testbdssunit_unset1di(/* Integer */ ae_vector* a, ae_state *_state) { ae_vector_set_length(a, 0+1, _state); a->ptr.p_int[0] = ae_randominteger(3, _state)-1; } static void testblasunit_naivematrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, double alpha, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, double beta, ae_state *_state); ae_bool testblas(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t passcount; ae_int_t n; ae_int_t i; ae_int_t i1; ae_int_t i2; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_int_t l; ae_int_t k; ae_int_t r; ae_int_t i3; ae_int_t j3; ae_int_t col1; ae_int_t col2; ae_int_t row1; ae_int_t row2; ae_vector x1; ae_vector x2; ae_matrix a; ae_matrix b; ae_matrix c1; ae_matrix c2; double err; double e1; double e2; double e3; double v; double scl1; double scl2; double scl3; ae_bool was1; ae_bool was2; ae_bool trans1; ae_bool trans2; double threshold; ae_bool n2errors; ae_bool hsnerrors; ae_bool amaxerrors; ae_bool mverrors; ae_bool iterrors; ae_bool cterrors; ae_bool mmerrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_init(&c1, 0, 0, DT_REAL, _state); ae_matrix_init(&c2, 0, 0, DT_REAL, _state); n2errors = ae_false; amaxerrors = ae_false; hsnerrors = ae_false; mverrors = ae_false; iterrors = ae_false; cterrors = ae_false; mmerrors = ae_false; waserrors = ae_false; threshold = 10000*ae_machineepsilon; /* * Test Norm2 */ passcount = 1000; e1 = (double)(0); e2 = (double)(0); e3 = (double)(0); scl2 = 0.5*ae_maxrealnumber; scl3 = 2*ae_minrealnumber; for(pass=1; pass<=passcount; pass++) { n = 1+ae_randominteger(1000, _state); i1 = ae_randominteger(10, _state); i2 = n+i1-1; ae_vector_set_length(&x1, i2+1, _state); ae_vector_set_length(&x2, i2+1, _state); for(i=i1; i<=i2; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } v = (double)(0); for(i=i1; i<=i2; i++) { v = v+ae_sqr(x1.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); e1 = ae_maxreal(e1, ae_fabs(v-vectornorm2(&x1, i1, i2, _state), _state), _state); for(i=i1; i<=i2; i++) { x2.ptr.p_double[i] = scl2*x1.ptr.p_double[i]; } e2 = ae_maxreal(e2, ae_fabs(v*scl2-vectornorm2(&x2, i1, i2, _state), _state), _state); for(i=i1; i<=i2; i++) { x2.ptr.p_double[i] = scl3*x1.ptr.p_double[i]; } e3 = ae_maxreal(e3, ae_fabs(v*scl3-vectornorm2(&x2, i1, i2, _state), _state), _state); } e2 = e2/scl2; e3 = e3/scl3; n2errors = (ae_fp_greater_eq(e1,threshold)||ae_fp_greater_eq(e2,threshold))||ae_fp_greater_eq(e3,threshold); /* * Testing VectorAbsMax, Column/Row AbsMax */ ae_vector_set_length(&x1, 5+1, _state); x1.ptr.p_double[1] = 2.0; x1.ptr.p_double[2] = 0.2; x1.ptr.p_double[3] = -1.3; x1.ptr.p_double[4] = 0.7; x1.ptr.p_double[5] = -3.0; amaxerrors = (vectoridxabsmax(&x1, 1, 5, _state)!=5||vectoridxabsmax(&x1, 1, 4, _state)!=1)||vectoridxabsmax(&x1, 2, 4, _state)!=3; n = 30; ae_vector_set_length(&x1, n+1, _state); ae_matrix_set_length(&a, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } was1 = ae_false; was2 = ae_false; for(pass=1; pass<=1000; pass++) { j = 1+ae_randominteger(n, _state); i1 = 1+ae_randominteger(n, _state); i2 = i1+ae_randominteger(n+1-i1, _state); ae_v_move(&x1.ptr.p_double[i1], 1, &a.ptr.pp_double[i1][j], a.stride, ae_v_len(i1,i2)); if( vectoridxabsmax(&x1, i1, i2, _state)!=columnidxabsmax(&a, i1, i2, j, _state) ) { was1 = ae_true; } i = 1+ae_randominteger(n, _state); j1 = 1+ae_randominteger(n, _state); j2 = j1+ae_randominteger(n+1-j1, _state); ae_v_move(&x1.ptr.p_double[j1], 1, &a.ptr.pp_double[i][j1], 1, ae_v_len(j1,j2)); if( vectoridxabsmax(&x1, j1, j2, _state)!=rowidxabsmax(&a, j1, j2, i, _state) ) { was2 = ae_true; } } amaxerrors = (amaxerrors||was1)||was2; /* * Testing upper Hessenberg 1-norm */ ae_matrix_set_length(&a, 3+1, 3+1, _state); ae_vector_set_length(&x1, 3+1, _state); a.ptr.pp_double[1][1] = (double)(2); a.ptr.pp_double[1][2] = (double)(3); a.ptr.pp_double[1][3] = (double)(1); a.ptr.pp_double[2][1] = (double)(4); a.ptr.pp_double[2][2] = (double)(-5); a.ptr.pp_double[2][3] = (double)(8); a.ptr.pp_double[3][1] = (double)(99); a.ptr.pp_double[3][2] = (double)(3); a.ptr.pp_double[3][3] = (double)(1); hsnerrors = ae_fp_greater(ae_fabs(upperhessenberg1norm(&a, 1, 3, 1, 3, &x1, _state)-11, _state),threshold); /* * Testing MatrixVectorMultiply */ ae_matrix_set_length(&a, 3+1, 5+1, _state); ae_vector_set_length(&x1, 3+1, _state); ae_vector_set_length(&x2, 2+1, _state); a.ptr.pp_double[2][3] = (double)(2); a.ptr.pp_double[2][4] = (double)(-1); a.ptr.pp_double[2][5] = (double)(-1); a.ptr.pp_double[3][3] = (double)(1); a.ptr.pp_double[3][4] = (double)(-2); a.ptr.pp_double[3][5] = (double)(2); x1.ptr.p_double[1] = (double)(1); x1.ptr.p_double[2] = (double)(2); x1.ptr.p_double[3] = (double)(1); x2.ptr.p_double[1] = (double)(-1); x2.ptr.p_double[2] = (double)(-1); matrixvectormultiply(&a, 2, 3, 3, 5, ae_false, &x1, 1, 3, 1.0, &x2, 1, 2, 1.0, _state); matrixvectormultiply(&a, 2, 3, 3, 5, ae_true, &x2, 1, 2, 1.0, &x1, 1, 3, 1.0, _state); e1 = ae_fabs(x1.ptr.p_double[1]+5, _state)+ae_fabs(x1.ptr.p_double[2]-8, _state)+ae_fabs(x1.ptr.p_double[3]+1, _state)+ae_fabs(x2.ptr.p_double[1]+2, _state)+ae_fabs(x2.ptr.p_double[2]+2, _state); x1.ptr.p_double[1] = (double)(1); x1.ptr.p_double[2] = (double)(2); x1.ptr.p_double[3] = (double)(1); x2.ptr.p_double[1] = (double)(-1); x2.ptr.p_double[2] = (double)(-1); matrixvectormultiply(&a, 2, 3, 3, 5, ae_false, &x1, 1, 3, 1.0, &x2, 1, 2, 0.0, _state); matrixvectormultiply(&a, 2, 3, 3, 5, ae_true, &x2, 1, 2, 1.0, &x1, 1, 3, 0.0, _state); e2 = ae_fabs(x1.ptr.p_double[1]+3, _state)+ae_fabs(x1.ptr.p_double[2]-3, _state)+ae_fabs(x1.ptr.p_double[3]+1, _state)+ae_fabs(x2.ptr.p_double[1]+1, _state)+ae_fabs(x2.ptr.p_double[2]+1, _state); mverrors = ae_fp_greater_eq(e1+e2,threshold); /* * testing inplace transpose */ n = 10; ae_matrix_set_length(&a, n+1, n+1, _state); ae_matrix_set_length(&b, n+1, n+1, _state); ae_vector_set_length(&x1, n-1+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { a.ptr.pp_double[i][j] = ae_randomreal(_state); } } passcount = 10000; was1 = ae_false; for(pass=1; pass<=passcount; pass++) { i1 = 1+ae_randominteger(n, _state); i2 = i1+ae_randominteger(n-i1+1, _state); j1 = 1+ae_randominteger(n-(i2-i1), _state); j2 = j1+(i2-i1); copymatrix(&a, i1, i2, j1, j2, &b, i1, i2, j1, j2, _state); inplacetranspose(&b, i1, i2, j1, j2, &x1, _state); for(i=i1; i<=i2; i++) { for(j=j1; j<=j2; j++) { if( ae_fp_neq(a.ptr.pp_double[i][j],b.ptr.pp_double[i1+(j-j1)][j1+(i-i1)]) ) { was1 = ae_true; } } } } iterrors = was1; /* * testing copy and transpose */ n = 10; ae_matrix_set_length(&a, n+1, n+1, _state); ae_matrix_set_length(&b, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { a.ptr.pp_double[i][j] = ae_randomreal(_state); } } passcount = 10000; was1 = ae_false; for(pass=1; pass<=passcount; pass++) { i1 = 1+ae_randominteger(n, _state); i2 = i1+ae_randominteger(n-i1+1, _state); j1 = 1+ae_randominteger(n, _state); j2 = j1+ae_randominteger(n-j1+1, _state); copyandtranspose(&a, i1, i2, j1, j2, &b, j1, j2, i1, i2, _state); for(i=i1; i<=i2; i++) { for(j=j1; j<=j2; j++) { if( ae_fp_neq(a.ptr.pp_double[i][j],b.ptr.pp_double[j][i]) ) { was1 = ae_true; } } } } cterrors = was1; /* * Testing MatrixMatrixMultiply */ n = 10; ae_matrix_set_length(&a, 2*n+1, 2*n+1, _state); ae_matrix_set_length(&b, 2*n+1, 2*n+1, _state); ae_matrix_set_length(&c1, 2*n+1, 2*n+1, _state); ae_matrix_set_length(&c2, 2*n+1, 2*n+1, _state); ae_vector_set_length(&x1, n+1, _state); ae_vector_set_length(&x2, n+1, _state); for(i=1; i<=2*n; i++) { for(j=1; j<=2*n; j++) { a.ptr.pp_double[i][j] = ae_randomreal(_state); b.ptr.pp_double[i][j] = ae_randomreal(_state); } } passcount = 1000; was1 = ae_false; for(pass=1; pass<=passcount; pass++) { for(i=1; i<=2*n; i++) { for(j=1; j<=2*n; j++) { c1.ptr.pp_double[i][j] = 2.1*i+3.1*j; c2.ptr.pp_double[i][j] = c1.ptr.pp_double[i][j]; } } l = 1+ae_randominteger(n, _state); k = 1+ae_randominteger(n, _state); r = 1+ae_randominteger(n, _state); i1 = 1+ae_randominteger(n, _state); j1 = 1+ae_randominteger(n, _state); i2 = 1+ae_randominteger(n, _state); j2 = 1+ae_randominteger(n, _state); i3 = 1+ae_randominteger(n, _state); j3 = 1+ae_randominteger(n, _state); trans1 = ae_fp_greater(ae_randomreal(_state),0.5); trans2 = ae_fp_greater(ae_randomreal(_state),0.5); if( trans1 ) { col1 = l; row1 = k; } else { col1 = k; row1 = l; } if( trans2 ) { col2 = k; row2 = r; } else { col2 = r; row2 = k; } scl1 = ae_randomreal(_state); scl2 = ae_randomreal(_state); matrixmatrixmultiply(&a, i1, i1+row1-1, j1, j1+col1-1, trans1, &b, i2, i2+row2-1, j2, j2+col2-1, trans2, scl1, &c1, i3, i3+l-1, j3, j3+r-1, scl2, &x1, _state); testblasunit_naivematrixmatrixmultiply(&a, i1, i1+row1-1, j1, j1+col1-1, trans1, &b, i2, i2+row2-1, j2, j2+col2-1, trans2, scl1, &c2, i3, i3+l-1, j3, j3+r-1, scl2, _state); err = (double)(0); for(i=1; i<=l; i++) { for(j=1; j<=r; j++) { err = ae_maxreal(err, ae_fabs(c1.ptr.pp_double[i3+i-1][j3+j-1]-c2.ptr.pp_double[i3+i-1][j3+j-1], _state), _state); } } if( ae_fp_greater(err,threshold) ) { was1 = ae_true; break; } } mmerrors = was1; /* * report */ waserrors = (((((n2errors||amaxerrors)||hsnerrors)||mverrors)||iterrors)||cterrors)||mmerrors; if( !silent ) { printf("TESTING BLAS\n"); printf("VectorNorm2: "); if( n2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("AbsMax (vector/row/column): "); if( amaxerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("UpperHessenberg1Norm: "); if( hsnerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MatrixVectorMultiply: "); if( mverrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("InplaceTranspose: "); if( iterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CopyAndTranspose: "); if( cterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MatrixMatrixMultiply: "); if( mmerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testblas(ae_bool silent, ae_state *_state) { return testblas(silent, _state); } static void testblasunit_naivematrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, double alpha, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, double beta, ae_state *_state) { ae_frame _frame_block; ae_int_t arows; ae_int_t acols; ae_int_t brows; ae_int_t bcols; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_int_t r; double v; ae_vector x1; ae_vector x2; ae_frame_make(_state, &_frame_block); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); /* * Setup */ if( !transa ) { arows = ai2-ai1+1; acols = aj2-aj1+1; } else { arows = aj2-aj1+1; acols = ai2-ai1+1; } if( !transb ) { brows = bi2-bi1+1; bcols = bj2-bj1+1; } else { brows = bj2-bj1+1; bcols = bi2-bi1+1; } ae_assert(acols==brows, "NaiveMatrixMatrixMultiply: incorrect matrix sizes!", _state); if( ((arows<=0||acols<=0)||brows<=0)||bcols<=0 ) { ae_frame_leave(_state); return; } l = arows; r = bcols; k = acols; ae_vector_set_length(&x1, k+1, _state); ae_vector_set_length(&x2, k+1, _state); for(i=1; i<=l; i++) { for(j=1; j<=r; j++) { if( !transa ) { if( !transb ) { v = ae_v_dotproduct(&b->ptr.pp_double[bi1][bj1+j-1], b->stride, &a->ptr.pp_double[ai1+i-1][aj1], 1, ae_v_len(bi1,bi2)); } else { v = ae_v_dotproduct(&b->ptr.pp_double[bi1+j-1][bj1], 1, &a->ptr.pp_double[ai1+i-1][aj1], 1, ae_v_len(bj1,bj2)); } } else { if( !transb ) { v = ae_v_dotproduct(&b->ptr.pp_double[bi1][bj1+j-1], b->stride, &a->ptr.pp_double[ai1][aj1+i-1], a->stride, ae_v_len(bi1,bi2)); } else { v = ae_v_dotproduct(&b->ptr.pp_double[bi1+j-1][bj1], 1, &a->ptr.pp_double[ai1][aj1+i-1], a->stride, ae_v_len(bj1,bj2)); } } if( ae_fp_eq(beta,(double)(0)) ) { c->ptr.pp_double[ci1+i-1][cj1+j-1] = alpha*v; } else { c->ptr.pp_double[ci1+i-1][cj1+j-1] = beta*c->ptr.pp_double[ci1+i-1][cj1+j-1]+alpha*v; } } } ae_frame_leave(_state); } static ae_bool testclusteringunit_basicahctests(ae_state *_state); static ae_bool testclusteringunit_advancedahctests(ae_state *_state); static void testclusteringunit_kmeanssimpletest1(ae_int_t nvars, ae_int_t nc, ae_int_t passcount, ae_bool* converrors, ae_bool* othererrors, ae_bool* simpleerrors, ae_state *_state); static void testclusteringunit_kmeansspecialtests(ae_bool* othererrors, ae_state *_state); static void testclusteringunit_kmeansinfinitelooptest(ae_bool* othererrors, ae_state *_state); static void testclusteringunit_kmeansrestartstest(ae_bool* converrors, ae_bool* restartserrors, ae_state *_state); static double testclusteringunit_rnormal(ae_state *_state); static void testclusteringunit_rsphere(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t i, ae_state *_state); static double testclusteringunit_distfunc(/* Real */ ae_vector* x0, /* Real */ ae_vector* x1, ae_int_t d, ae_int_t disttype, ae_state *_state); static ae_bool testclusteringunit_errorsinmerges(/* Real */ ae_matrix* d, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nf, ahcreport* rep, ae_int_t ahcalgo, ae_state *_state); static void testclusteringunit_kmeansreferenceupdatedistances(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t k, /* Integer */ ae_vector* xyc, /* Real */ ae_vector* xydist2, ae_state *_state); /************************************************************************* Testing clustering *************************************************************************/ ae_bool testclustering(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool basicahcerrors; ae_bool ahcerrors; ae_bool kmeansconverrors; ae_bool kmeanssimpleerrors; ae_bool kmeansothererrors; ae_bool kmeansrestartserrors; ae_int_t passcount; ae_int_t nf; ae_int_t nc; ae_bool result; /* * AHC tests */ basicahcerrors = testclusteringunit_basicahctests(_state); ahcerrors = testclusteringunit_advancedahctests(_state); /* * k-means tests */ passcount = 10; kmeansconverrors = ae_false; kmeansothererrors = ae_false; kmeanssimpleerrors = ae_false; kmeansrestartserrors = ae_false; testclusteringunit_kmeansspecialtests(&kmeansothererrors, _state); testclusteringunit_kmeansinfinitelooptest(&kmeansothererrors, _state); testclusteringunit_kmeansrestartstest(&kmeansconverrors, &kmeansrestartserrors, _state); for(nf=1; nf<=5; nf++) { for(nc=1; nc<=5; nc++) { testclusteringunit_kmeanssimpletest1(nf, nc, passcount, &kmeansconverrors, &kmeansothererrors, &kmeanssimpleerrors, _state); } } /* * Results */ waserrors = ae_false; waserrors = waserrors||(basicahcerrors||ahcerrors); waserrors = waserrors||(((kmeansconverrors||kmeansothererrors)||kmeanssimpleerrors)||kmeansrestartserrors); if( !silent ) { printf("TESTING CLUSTERING\n"); printf("AHC: \n"); printf("* BASIC TESTS "); if( !basicahcerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* GENERAL TESTS "); if( !ahcerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("K-MEANS: \n"); printf("* CONVERGENCE "); if( !kmeansconverrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* SIMPLE TASKS "); if( !kmeanssimpleerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* OTHER PROPERTIES "); if( !kmeansothererrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* RESTARTS PROPERTIES "); if( !kmeansrestartserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testclustering(ae_bool silent, ae_state *_state) { return testclustering(silent, _state); } /************************************************************************* Basic agglomerative hierarchical clustering tests: returns True on failure, False on success. Basic tests study algorithm behavior on simple, hand-made datasets with small number of points (1..10). *************************************************************************/ static ae_bool testclusteringunit_basicahctests(ae_state *_state) { ae_frame _frame_block; clusterizerstate s; ahcreport rep; ae_matrix xy; ae_matrix d; ae_matrix c; ae_bool berr; ae_int_t ahcalgo; ae_int_t i; ae_int_t j; ae_int_t npoints; ae_int_t k; ae_vector cidx; ae_vector cz; ae_vector cidx2; ae_vector cz2; ae_bool result; ae_frame_make(_state, &_frame_block); _clusterizerstate_init(&s, _state); _ahcreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&d, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&cidx, 0, DT_INT, _state); ae_vector_init(&cz, 0, DT_INT, _state); ae_vector_init(&cidx2, 0, DT_INT, _state); ae_vector_init(&cz2, 0, DT_INT, _state); result = ae_true; /* * Test on empty problem */ clusterizercreate(&s, _state); clusterizerrunahc(&s, &rep, _state); if( rep.npoints!=0 ) { ae_frame_leave(_state); return result; } /* * Test on problem with one point */ ae_matrix_set_length(&xy, 1, 2, _state); xy.ptr.pp_double[0][0] = ae_randomreal(_state); xy.ptr.pp_double[0][1] = ae_randomreal(_state); clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 1, 2, 0, _state); clusterizerrunahc(&s, &rep, _state); if( rep.npoints!=1 ) { ae_frame_leave(_state); return result; } /* * Test on problem with two points */ ae_matrix_set_length(&xy, 2, 2, _state); xy.ptr.pp_double[0][0] = ae_randomreal(_state); xy.ptr.pp_double[0][1] = ae_randomreal(_state); xy.ptr.pp_double[1][0] = ae_randomreal(_state); xy.ptr.pp_double[1][1] = ae_randomreal(_state); clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 2, 2, 0, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=2||rep.z.rows!=1)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[0][0]!=0||rep.z.ptr.pp_int[0][1]!=1 ) { ae_frame_leave(_state); return result; } /* * Test on specially designed problem which should have * following dendrogram: * * ------ * | | * ---- ---- * | | | | * 0 1 2 3 * * ...with first merge performed on 0 and 1, second merge * performed on 2 and 3. Complete linkage is used. * * Additionally we test ClusterizerSeparatedByDist() on this * problem for different distances. Test is performed by * comparing function result with ClusterizerGetKClusters() * for known K. */ ae_matrix_set_length(&xy, 4, 1, _state); xy.ptr.pp_double[0][0] = 0.0; xy.ptr.pp_double[1][0] = 1.0; xy.ptr.pp_double[2][0] = 3.0; xy.ptr.pp_double[3][0] = 4.1; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 4, 1, 0, _state); clusterizersetahcalgo(&s, 0, _state); clusterizerrunahc(&s, &rep, _state); if( (((rep.npoints!=4||rep.z.rows!=3)||rep.z.cols!=2)||rep.pz.rows!=3)||rep.pz.cols!=2 ) { ae_frame_leave(_state); return result; } berr = ae_false; berr = (berr||rep.z.ptr.pp_int[0][0]!=0)||rep.z.ptr.pp_int[0][1]!=1; berr = (berr||rep.z.ptr.pp_int[1][0]!=2)||rep.z.ptr.pp_int[1][1]!=3; berr = (berr||rep.z.ptr.pp_int[2][0]!=4)||rep.z.ptr.pp_int[2][1]!=5; berr = (((berr||rep.p.ptr.p_int[0]!=0)||rep.p.ptr.p_int[1]!=1)||rep.p.ptr.p_int[2]!=2)||rep.p.ptr.p_int[3]!=3; berr = (berr||rep.pz.ptr.pp_int[0][0]!=0)||rep.pz.ptr.pp_int[0][1]!=1; berr = (berr||rep.pz.ptr.pp_int[1][0]!=2)||rep.pz.ptr.pp_int[1][1]!=3; berr = (berr||rep.pz.ptr.pp_int[2][0]!=4)||rep.pz.ptr.pp_int[2][1]!=5; berr = (((berr||rep.pm.ptr.pp_int[0][0]!=0)||rep.pm.ptr.pp_int[0][1]!=0)||rep.pm.ptr.pp_int[0][2]!=1)||rep.pm.ptr.pp_int[0][3]!=1; berr = (((berr||rep.pm.ptr.pp_int[1][0]!=2)||rep.pm.ptr.pp_int[1][1]!=2)||rep.pm.ptr.pp_int[1][2]!=3)||rep.pm.ptr.pp_int[1][3]!=3; berr = (((berr||rep.pm.ptr.pp_int[2][0]!=0)||rep.pm.ptr.pp_int[2][1]!=1)||rep.pm.ptr.pp_int[2][2]!=2)||rep.pm.ptr.pp_int[2][3]!=3; if( berr ) { ae_frame_leave(_state); return result; } clusterizerseparatedbydist(&rep, 0.5, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 4, &cidx2, &cz2, _state); if( k!=4 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( ((cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1])||cz.ptr.p_int[2]!=cz2.ptr.p_int[2])||cz.ptr.p_int[3]!=cz2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } clusterizerseparatedbydist(&rep, 1.05, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 3, &cidx2, &cz2, _state); if( k!=3 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( (cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1])||cz.ptr.p_int[2]!=cz2.ptr.p_int[2] ) { ae_frame_leave(_state); return result; } clusterizerseparatedbydist(&rep, 1.15, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 2, &cidx2, &cz2, _state); if( k!=2 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1] ) { ae_frame_leave(_state); return result; } /* * Test on specially designed problem with Pearson distance * which should have following dendrogram: * * ------ * | | * ---- ---- * | | | | * 0 1 2 3 * * This problem is used to test ClusterizerSeparatedByDist(). * The test is performed by comparing function result with * ClusterizerGetKClusters() for known K. * * NOTE: * * corr(a0,a1) = 0.866 * * corr(a2,a3) = 0.990 * * corr(a0/a1, a2/a3)<=0.5 */ ae_matrix_set_length(&xy, 4, 3, _state); xy.ptr.pp_double[0][0] = 0.3; xy.ptr.pp_double[0][1] = 0.5; xy.ptr.pp_double[0][2] = 0.3; xy.ptr.pp_double[1][0] = 0.3; xy.ptr.pp_double[1][1] = 0.5; xy.ptr.pp_double[1][2] = 0.4; xy.ptr.pp_double[2][0] = 0.1; xy.ptr.pp_double[2][1] = 0.5; xy.ptr.pp_double[2][2] = 0.9; xy.ptr.pp_double[3][0] = 0.1; xy.ptr.pp_double[3][1] = 0.4; xy.ptr.pp_double[3][2] = 0.9; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 4, 3, 10, _state); clusterizersetahcalgo(&s, 1, _state); clusterizerrunahc(&s, &rep, _state); clusterizerseparatedbycorr(&rep, 0.999, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 4, &cidx2, &cz2, _state); if( k!=4 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( ((cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1])||cz.ptr.p_int[2]!=cz2.ptr.p_int[2])||cz.ptr.p_int[3]!=cz2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } clusterizerseparatedbycorr(&rep, 0.900, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 3, &cidx2, &cz2, _state); if( k!=3 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( (cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1])||cz.ptr.p_int[2]!=cz2.ptr.p_int[2] ) { ae_frame_leave(_state); return result; } clusterizerseparatedbycorr(&rep, 0.600, &k, &cidx, &cz, _state); clusterizergetkclusters(&rep, 2, &cidx2, &cz2, _state); if( k!=2 ) { ae_frame_leave(_state); return result; } if( ((cidx.ptr.p_int[0]!=cidx2.ptr.p_int[0]||cidx.ptr.p_int[1]!=cidx2.ptr.p_int[1])||cidx.ptr.p_int[2]!=cidx2.ptr.p_int[2])||cidx.ptr.p_int[3]!=cidx2.ptr.p_int[3] ) { ae_frame_leave(_state); return result; } if( cz.ptr.p_int[0]!=cz2.ptr.p_int[0]||cz.ptr.p_int[1]!=cz2.ptr.p_int[1] ) { ae_frame_leave(_state); return result; } /* * Single linkage vs. complete linkage */ ae_matrix_set_length(&xy, 6, 1, _state); xy.ptr.pp_double[0][0] = 0.0; xy.ptr.pp_double[1][0] = 1.0; xy.ptr.pp_double[2][0] = 2.1; xy.ptr.pp_double[3][0] = 3.3; xy.ptr.pp_double[4][0] = 6.0; xy.ptr.pp_double[5][0] = 4.6; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 6, 1, 0, _state); clusterizersetahcalgo(&s, 0, _state); clusterizerrunahc(&s, &rep, _state); if( rep.npoints!=6||rep.p.cnt!=6 ) { ae_frame_leave(_state); return result; } if( ((rep.z.rows!=5||rep.z.cols!=2)||rep.pz.rows!=5)||rep.pz.cols!=2 ) { ae_frame_leave(_state); return result; } berr = ae_false; berr = berr||rep.p.ptr.p_int[0]!=2; berr = berr||rep.p.ptr.p_int[1]!=3; berr = berr||rep.p.ptr.p_int[2]!=4; berr = berr||rep.p.ptr.p_int[3]!=5; berr = berr||rep.p.ptr.p_int[4]!=0; berr = berr||rep.p.ptr.p_int[5]!=1; berr = (berr||rep.z.ptr.pp_int[0][0]!=0)||rep.z.ptr.pp_int[0][1]!=1; berr = (berr||rep.z.ptr.pp_int[1][0]!=2)||rep.z.ptr.pp_int[1][1]!=3; berr = (berr||rep.z.ptr.pp_int[2][0]!=4)||rep.z.ptr.pp_int[2][1]!=5; berr = (berr||rep.z.ptr.pp_int[3][0]!=6)||rep.z.ptr.pp_int[3][1]!=7; berr = (berr||rep.z.ptr.pp_int[4][0]!=8)||rep.z.ptr.pp_int[4][1]!=9; berr = (berr||rep.pz.ptr.pp_int[0][0]!=2)||rep.pz.ptr.pp_int[0][1]!=3; berr = (berr||rep.pz.ptr.pp_int[1][0]!=4)||rep.pz.ptr.pp_int[1][1]!=5; berr = (berr||rep.pz.ptr.pp_int[2][0]!=0)||rep.pz.ptr.pp_int[2][1]!=1; berr = (berr||rep.pz.ptr.pp_int[3][0]!=6)||rep.pz.ptr.pp_int[3][1]!=7; berr = (berr||rep.pz.ptr.pp_int[4][0]!=8)||rep.pz.ptr.pp_int[4][1]!=9; if( berr ) { ae_frame_leave(_state); return result; } clusterizersetahcalgo(&s, 1, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=6||rep.z.rows!=5)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } berr = ae_false; berr = (berr||rep.z.ptr.pp_int[0][0]!=0)||rep.z.ptr.pp_int[0][1]!=1; berr = (berr||rep.z.ptr.pp_int[1][0]!=2)||rep.z.ptr.pp_int[1][1]!=6; berr = (berr||rep.z.ptr.pp_int[2][0]!=3)||rep.z.ptr.pp_int[2][1]!=7; berr = (berr||rep.z.ptr.pp_int[3][0]!=5)||rep.z.ptr.pp_int[3][1]!=8; berr = (berr||rep.z.ptr.pp_int[4][0]!=4)||rep.z.ptr.pp_int[4][1]!=9; if( berr ) { ae_frame_leave(_state); return result; } /* * Test which differentiates complete linkage and average linkage from * single linkage: * * we have cluster C0={(-0.5), (0)}, * cluster C1={(19.0), (20.0), (21.0), (22.0), (23.0)}, * and point P between them - (10.0) * * we try three different strategies - single linkage, complete * linkage, average linkage. * * any strategy will merge C0 first, then merge points of C1, * and then merge P with C0 or C1 (depending on linkage type) * * we test that: * a) C0 is merged first * b) after 5 merges (including merge of C0), P is merged with C0 or C1 * c) P is merged with C1 when we have single linkage, with C0 otherwise */ ae_matrix_set_length(&xy, 8, 1, _state); xy.ptr.pp_double[0][0] = -0.5; xy.ptr.pp_double[1][0] = 0.0; xy.ptr.pp_double[2][0] = 10.0; xy.ptr.pp_double[3][0] = 19.0; xy.ptr.pp_double[4][0] = 20.0; xy.ptr.pp_double[5][0] = 21.0; xy.ptr.pp_double[6][0] = 22.0; xy.ptr.pp_double[7][0] = 23.0; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 8, 1, 0, _state); for(ahcalgo=0; ahcalgo<=2; ahcalgo++) { clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=8||rep.z.rows!=7)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[0][0]!=0||rep.z.ptr.pp_int[0][1]!=1 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[5][0]!=2&&rep.z.ptr.pp_int[5][1]!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[5][0]!=2&&rep.z.ptr.pp_int[5][1]!=2 ) { ae_frame_leave(_state); return result; } if( (ahcalgo==0||ahcalgo==2)&&(rep.z.ptr.pp_int[5][0]!=8&&rep.z.ptr.pp_int[5][1]!=8) ) { ae_frame_leave(_state); return result; } if( ahcalgo==1&&(rep.z.ptr.pp_int[5][0]==8||rep.z.ptr.pp_int[5][1]==8) ) { ae_frame_leave(_state); return result; } } /* * Test which differentiates single linkage and average linkage from * complete linkage: * * we have cluster C0={(-2.5), (-2.0)}, * cluster C1={(19.0), (20.0), (21.0), (22.0), (23.0)}, * and point P between them - (10.0) * * we try three different strategies - single linkage, complete * linkage, average linkage. * * any strategy will merge C0 first, then merge points of C1, * and then merge P with C0 or C1 (depending on linkage type) * * we test that: * a) C0 is merged first * b) after 5 merges (including merge of C0), P is merged with C0 or C1 * c) P is merged with C0 when we have complete linkage, with C1 otherwise */ ae_matrix_set_length(&xy, 8, 1, _state); xy.ptr.pp_double[0][0] = -2.5; xy.ptr.pp_double[1][0] = -2.0; xy.ptr.pp_double[2][0] = 10.0; xy.ptr.pp_double[3][0] = 19.0; xy.ptr.pp_double[4][0] = 20.0; xy.ptr.pp_double[5][0] = 21.0; xy.ptr.pp_double[6][0] = 22.0; xy.ptr.pp_double[7][0] = 23.0; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 8, 1, 0, _state); for(ahcalgo=0; ahcalgo<=2; ahcalgo++) { clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=8||rep.z.rows!=7)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[0][0]!=0||rep.z.ptr.pp_int[0][1]!=1 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[5][0]!=2&&rep.z.ptr.pp_int[5][1]!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[5][0]!=2&&rep.z.ptr.pp_int[5][1]!=2 ) { ae_frame_leave(_state); return result; } if( ahcalgo==0&&(rep.z.ptr.pp_int[5][0]!=8&&rep.z.ptr.pp_int[5][1]!=8) ) { ae_frame_leave(_state); return result; } if( (ahcalgo==1||ahcalgo==2)&&(rep.z.ptr.pp_int[5][0]==8||rep.z.ptr.pp_int[5][1]==8) ) { ae_frame_leave(_state); return result; } } /* * Test which differentiates weighred average linkage from unweighted average linkage: * * we have cluster C0={(0.0), (1.5), (2.5)}, * cluster C1={(7.5), (7.99)}, * and point P between them - (4.5) * * we try two different strategies - weighted average linkage and unweighted average linkage * * any strategy will merge C1 first, then merge points of C0, * and then merge P with C0 or C1 (depending on linkage type) * * we test that: * a) C1 is merged first, C0 is merged after that * b) after first 3 merges P is merged with C0 or C1 * c) P is merged with C1 when we have weighted average linkage, with C0 otherwise */ ae_matrix_set_length(&xy, 6, 1, _state); xy.ptr.pp_double[0][0] = 0.0; xy.ptr.pp_double[1][0] = 1.5; xy.ptr.pp_double[2][0] = 2.5; xy.ptr.pp_double[3][0] = 4.5; xy.ptr.pp_double[4][0] = 7.5; xy.ptr.pp_double[5][0] = 7.99; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 6, 1, 0, _state); for(ahcalgo=2; ahcalgo<=3; ahcalgo++) { clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=6||rep.z.rows!=5)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[0][0]!=4||rep.z.ptr.pp_int[0][1]!=5 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[1][0]!=1||rep.z.ptr.pp_int[1][1]!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[2][0]!=0||rep.z.ptr.pp_int[2][1]!=7 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[3][0]!=3 ) { ae_frame_leave(_state); return result; } if( ahcalgo==2&&rep.z.ptr.pp_int[3][1]!=8 ) { ae_frame_leave(_state); return result; } if( ahcalgo==3&&rep.z.ptr.pp_int[3][1]!=6 ) { ae_frame_leave(_state); return result; } } /* * Test which checks correctness of Ward's method on very basic problem */ ae_matrix_set_length(&xy, 4, 1, _state); xy.ptr.pp_double[0][0] = 0.0; xy.ptr.pp_double[1][0] = 1.0; xy.ptr.pp_double[2][0] = 3.1; xy.ptr.pp_double[3][0] = 4.0; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, xy.rows, xy.cols, 2, _state); clusterizergetdistances(&xy, xy.rows, xy.cols, 2, &d, _state); clusterizersetahcalgo(&s, 4, _state); clusterizerrunahc(&s, &rep, _state); if( testclusteringunit_errorsinmerges(&d, &xy, xy.rows, xy.cols, &rep, 4, _state) ) { ae_frame_leave(_state); return result; } /* * One more Ward's test */ ae_matrix_set_length(&xy, 8, 2, _state); xy.ptr.pp_double[0][0] = 0.4700566262; xy.ptr.pp_double[0][1] = 0.4565938448; xy.ptr.pp_double[1][0] = 0.2394499506; xy.ptr.pp_double[1][1] = 0.1750209592; xy.ptr.pp_double[2][0] = 0.6518417019; xy.ptr.pp_double[2][1] = 0.6151370746; xy.ptr.pp_double[3][0] = 0.9863942841; xy.ptr.pp_double[3][1] = 0.7855012189; xy.ptr.pp_double[4][0] = 0.1517812919; xy.ptr.pp_double[4][1] = 0.2600174758; xy.ptr.pp_double[5][0] = 0.7840203638; xy.ptr.pp_double[5][1] = 0.9023597604; xy.ptr.pp_double[6][0] = 0.2604194835; xy.ptr.pp_double[6][1] = 0.9792704661; xy.ptr.pp_double[7][0] = 0.6353096042; xy.ptr.pp_double[7][1] = 0.8252606906; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, xy.rows, xy.cols, 2, _state); clusterizergetdistances(&xy, xy.rows, xy.cols, 2, &d, _state); clusterizersetahcalgo(&s, 4, _state); clusterizerrunahc(&s, &rep, _state); if( rep.z.ptr.pp_int[0][0]!=1||rep.z.ptr.pp_int[0][1]!=4 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[1][0]!=5||rep.z.ptr.pp_int[1][1]!=7 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[2][0]!=0||rep.z.ptr.pp_int[2][1]!=2 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[3][0]!=3||rep.z.ptr.pp_int[3][1]!=9 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[4][0]!=10||rep.z.ptr.pp_int[4][1]!=11 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[5][0]!=6||rep.z.ptr.pp_int[5][1]!=12 ) { ae_frame_leave(_state); return result; } if( rep.z.ptr.pp_int[6][0]!=8||rep.z.ptr.pp_int[6][1]!=13 ) { ae_frame_leave(_state); return result; } if( testclusteringunit_errorsinmerges(&d, &xy, xy.rows, xy.cols, &rep, 4, _state) ) { ae_frame_leave(_state); return result; } /* * Ability to solve problems with zero distance matrix */ npoints = 20; ae_matrix_set_length(&d, npoints, npoints, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=npoints-1; j++) { d.ptr.pp_double[i][j] = 0.0; } } for(ahcalgo=0; ahcalgo<=4; ahcalgo++) { clusterizercreate(&s, _state); clusterizersetdistances(&s, &d, npoints, ae_true, _state); clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); if( (rep.npoints!=npoints||rep.z.rows!=npoints-1)||rep.z.cols!=2 ) { ae_frame_leave(_state); return result; } } /* * Test GetKClusters() */ ae_matrix_set_length(&xy, 8, 1, _state); xy.ptr.pp_double[0][0] = -2.5; xy.ptr.pp_double[1][0] = -2.0; xy.ptr.pp_double[2][0] = 10.0; xy.ptr.pp_double[3][0] = 19.0; xy.ptr.pp_double[4][0] = 20.0; xy.ptr.pp_double[5][0] = 21.0; xy.ptr.pp_double[6][0] = 22.0; xy.ptr.pp_double[7][0] = 23.0; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, 8, 1, 0, _state); clusterizersetahcalgo(&s, 0, _state); clusterizerrunahc(&s, &rep, _state); clusterizergetkclusters(&rep, 3, &cidx, &cz, _state); if( ((((((cidx.ptr.p_int[0]!=1||cidx.ptr.p_int[1]!=1)||cidx.ptr.p_int[2]!=0)||cidx.ptr.p_int[3]!=2)||cidx.ptr.p_int[4]!=2)||cidx.ptr.p_int[5]!=2)||cidx.ptr.p_int[6]!=2)||cidx.ptr.p_int[7]!=2 ) { ae_frame_leave(_state); return result; } if( (cz.ptr.p_int[0]!=2||cz.ptr.p_int[1]!=8)||cz.ptr.p_int[2]!=12 ) { ae_frame_leave(_state); return result; } /* * Test is done */ result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Advanced agglomerative hierarchical clustering tests : returns True on failure, False on success. Advanced testing subroutine perform several automatically generated tests. *************************************************************************/ static ae_bool testclusteringunit_advancedahctests(ae_state *_state) { ae_frame _frame_block; clusterizerstate s; ahcreport rep; ae_matrix xy; ae_matrix dm; ae_matrix dm2; ae_vector idx; ae_vector disttypes; ae_vector x0; ae_vector x1; ae_int_t d; ae_int_t n; ae_int_t npoints; ae_int_t ahcalgo; ae_int_t disttype; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_int_t t; ae_int_t euclidean; ae_bool result; ae_frame_make(_state, &_frame_block); _clusterizerstate_init(&s, _state); _ahcreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&dm, 0, 0, DT_REAL, _state); ae_matrix_init(&dm2, 0, 0, DT_REAL, _state); ae_vector_init(&idx, 0, DT_INT, _state); ae_vector_init(&disttypes, 0, DT_INT, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); result = ae_false; euclidean = 2; /* * Test on D-dimensional problem: * * D = 2...5 * * D clusters, each has N points; * centers are located at x=(0 ... 1 ... 0); * cluster radii are approximately 0.1 * * single/complete/unweighted_average/weighted_average linkage/Ward's method are tested * * Euclidean distance is used, either: * a) one given by distance matrix (ClusterizerSetDistances) * b) one calculated from dataset (ClusterizerSetPoints) * * we have N*D points, and N*D-1 merges in total * * points are randomly rearranged after generation * * For all kinds of linkage we perform following test: * * for each point we remember index of its cluster * (one which is determined during dataset generation) * * we clusterize points with ALGLIB capabilities * * we scan Rep.Z and perform first D*(N-1) merges * * for each merge we check that it merges points * from same cluster; * * Additonally, we call ErrorsInMerges(). See function comments * for more information about specific tests performed. This function * allows us to check that clusters are built exactly as specified by * definition of the clustering algorithm. */ for(d=2; d<=5; d++) { for(ahcalgo=0; ahcalgo<=4; ahcalgo++) { n = ae_round(ae_pow((double)(3), (double)(ae_randominteger(3, _state)), _state), _state); npoints = d*n; /* * 1. generate dataset. * 2. fill Idx (array of cluster indexes): * * first N*D elements store cluster indexes * * next D*(N-1) elements are filled during merges * 3. build distance matrix DM */ ae_matrix_set_length(&xy, n*d, d, _state); ae_vector_set_length(&idx, n*d+d*(n-1), _state); for(i=0; i<=n*d-1; i++) { for(j=0; j<=d-1; j++) { xy.ptr.pp_double[i][j] = 0.2*ae_randomreal(_state)-0.1; } xy.ptr.pp_double[i][i%d] = xy.ptr.pp_double[i][i%d]+1.0; idx.ptr.p_int[i] = i%d; } for(i=0; i<=n*d-1; i++) { k = ae_randominteger(n*d, _state); if( k!=i ) { for(j=0; j<=d-1; j++) { v = xy.ptr.pp_double[i][j]; xy.ptr.pp_double[i][j] = xy.ptr.pp_double[k][j]; xy.ptr.pp_double[k][j] = v; } t = idx.ptr.p_int[k]; idx.ptr.p_int[k] = idx.ptr.p_int[i]; idx.ptr.p_int[i] = t; } } ae_matrix_set_length(&dm, npoints, npoints, _state); ae_vector_set_length(&x0, d, _state); ae_vector_set_length(&x1, d, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=npoints-1; j++) { ae_v_move(&x0.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,d-1)); ae_v_move(&x1.ptr.p_double[0], 1, &xy.ptr.pp_double[j][0], 1, ae_v_len(0,d-1)); dm.ptr.pp_double[i][j] = testclusteringunit_distfunc(&x0, &x1, d, euclidean, _state); } } /* * Clusterize with SetPoints() */ clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, n*d, d, euclidean, _state); clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); /* * Tests: * * replay first D*(N-1) merges; these merges should take place * within clusters, intercluster merges will be performed at the * last stages of the processing. * * test with ErrorsInMerges() */ if( rep.npoints!=npoints ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=d*(n-1)-1; i++) { /* * Check correctness of I-th row of Z */ if( (rep.z.ptr.pp_int[i][0]<0||rep.z.ptr.pp_int[i][0]>=rep.z.ptr.pp_int[i][1])||rep.z.ptr.pp_int[i][1]>=d*n+i ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Check that merge is performed within cluster */ if( idx.ptr.p_int[rep.z.ptr.pp_int[i][0]]!=idx.ptr.p_int[rep.z.ptr.pp_int[i][1]] ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Write new entry of Idx. * Both points from the same cluster, so result of the merge * belongs to the same cluster */ idx.ptr.p_int[n*d+i] = idx.ptr.p_int[rep.z.ptr.pp_int[i][1]]; } if( ((ahcalgo==0||ahcalgo==1)||ahcalgo==2)||ahcalgo==4 ) { if( testclusteringunit_errorsinmerges(&dm, &xy, d*n, d, &rep, ahcalgo, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Clusterize one more time, now with distance matrix */ clusterizercreate(&s, _state); clusterizersetdistances(&s, &dm, n*d, ae_fp_greater(ae_randomreal(_state),0.5), _state); clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); /* * Tests: * * replay first D*(N-1) merges; these merges should take place * within clusters, intercluster merges will be performed at the * last stages of the processing. * * test with ErrorsInMerges() */ if( rep.npoints!=npoints ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=d*(n-1)-1; i++) { /* * Check correctness of I-th row of Z */ if( (rep.z.ptr.pp_int[i][0]<0||rep.z.ptr.pp_int[i][0]>=rep.z.ptr.pp_int[i][1])||rep.z.ptr.pp_int[i][1]>=d*n+i ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Check that merge is performed within cluster */ if( idx.ptr.p_int[rep.z.ptr.pp_int[i][0]]!=idx.ptr.p_int[rep.z.ptr.pp_int[i][1]] ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Write new entry of Idx. * Both points from the same cluster, so result of the merge * belongs to the same cluster */ idx.ptr.p_int[n*d+i] = idx.ptr.p_int[rep.z.ptr.pp_int[i][1]]; } if( ((ahcalgo==0||ahcalgo==1)||ahcalgo==2)||ahcalgo==4 ) { if( testclusteringunit_errorsinmerges(&dm, &xy, d*n, d, &rep, ahcalgo, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } /* * Test on random D-dimensional problem: * * D = 2...5 * * N=1..16 random points from unit hypercube * * single/complete/unweighted_average linkage/Ward's method are tested * * different distance functions are tested * * we call ErrorsInMerges() and we check distance matrix * calculated by unit test against one returned by GetDistances() */ ae_vector_set_length(&disttypes, 9, _state); disttypes.ptr.p_int[0] = 0; disttypes.ptr.p_int[1] = 1; disttypes.ptr.p_int[2] = 2; disttypes.ptr.p_int[3] = 10; disttypes.ptr.p_int[4] = 11; disttypes.ptr.p_int[5] = 12; disttypes.ptr.p_int[6] = 13; disttypes.ptr.p_int[7] = 20; disttypes.ptr.p_int[8] = 21; for(disttype=0; disttype<=disttypes.cnt-1; disttype++) { for(ahcalgo=0; ahcalgo<=4; ahcalgo++) { if( ahcalgo==3 ) { continue; } if( ahcalgo==4&&disttype!=2 ) { continue; } npoints = ae_round(ae_pow((double)(2), (double)(ae_randominteger(5, _state)), _state), _state); d = 2+ae_randominteger(4, _state); /* * Generate dataset and distance matrix */ ae_matrix_set_length(&xy, npoints, d, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=d-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } ae_matrix_set_length(&dm, npoints, npoints, _state); ae_vector_set_length(&x0, d, _state); ae_vector_set_length(&x1, d, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=npoints-1; j++) { ae_v_move(&x0.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,d-1)); ae_v_move(&x1.ptr.p_double[0], 1, &xy.ptr.pp_double[j][0], 1, ae_v_len(0,d-1)); dm.ptr.pp_double[i][j] = testclusteringunit_distfunc(&x0, &x1, d, disttypes.ptr.p_int[disttype], _state); } } /* * Clusterize */ clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, npoints, d, disttypes.ptr.p_int[disttype], _state); clusterizersetahcalgo(&s, ahcalgo, _state); clusterizerrunahc(&s, &rep, _state); /* * Test with ErrorsInMerges() */ if( testclusteringunit_errorsinmerges(&dm, &xy, npoints, d, &rep, ahcalgo, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Test distance matrix */ clusterizergetdistances(&xy, npoints, d, disttypes.ptr.p_int[disttype], &dm2, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=npoints-1; j++) { if( !ae_isfinite(dm2.ptr.pp_double[i][j], _state)||ae_fp_greater(ae_fabs(dm.ptr.pp_double[i][j]-dm2.ptr.pp_double[i][j], _state),1.0E5*ae_machineepsilon) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } ae_frame_leave(_state); return result; } /************************************************************************* Simple test 1: ellipsoid in NF-dimensional space. compare k-means centers with random centers *************************************************************************/ static void testclusteringunit_kmeanssimpletest1(ae_int_t nvars, ae_int_t nc, ae_int_t passcount, ae_bool* converrors, ae_bool* othererrors, ae_bool* simpleerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t npoints; ae_int_t majoraxis; ae_matrix xy; ae_vector tmp; double v; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t restarts; double ekmeans; double erandom; double dclosest; ae_int_t cclosest; clusterizerstate s; kmeansreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); _clusterizerstate_init(&s, _state); _kmeansreport_init(&rep, _state); npoints = nc*100; restarts = 5; passcount = 10; ae_vector_set_length(&tmp, nvars-1+1, _state); for(pass=1; pass<=passcount; pass++) { /* * Fill */ ae_matrix_set_length(&xy, npoints-1+1, nvars-1+1, _state); majoraxis = ae_randominteger(nvars, _state); for(i=0; i<=npoints-1; i++) { testclusteringunit_rsphere(&xy, nvars, i, _state); xy.ptr.pp_double[i][majoraxis] = nc*xy.ptr.pp_double[i][majoraxis]; } /* * Test */ clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, npoints, nvars, 2, _state); clusterizersetkmeanslimits(&s, restarts, 0, _state); clusterizerrunkmeans(&s, nc, &rep, _state); if( rep.terminationtype<=0 ) { *converrors = ae_true; ae_frame_leave(_state); return; } /* * Test that XYC is correct mapping to cluster centers */ for(i=0; i<=npoints-1; i++) { cclosest = -1; dclosest = ae_maxrealnumber; for(j=0; j<=nc-1; j++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &rep.c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); if( ae_fp_less(v,dclosest) ) { cclosest = j; dclosest = v; } } if( cclosest!=rep.cidx.ptr.p_int[i] ) { *othererrors = ae_true; ae_frame_leave(_state); return; } } /* * Use first NC rows of XY as random centers * (XY is totally random, so it is as good as any other choice). * * Compare potential functions. */ ekmeans = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &rep.c.ptr.pp_double[rep.cidx.ptr.p_int[i]][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); ekmeans = ekmeans+v; } erandom = (double)(0); for(i=0; i<=npoints-1; i++) { dclosest = ae_maxrealnumber; v = (double)(0); for(j=0; j<=nc-1; j++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); if( ae_fp_less(v,dclosest) ) { dclosest = v; } } erandom = erandom+v; } if( ae_fp_less(erandom,ekmeans) ) { *simpleerrors = ae_true; ae_frame_leave(_state); return; } } ae_frame_leave(_state); } /************************************************************************* This test perform several checks for special properties On failure sets error flag, on success leaves it unchanged. *************************************************************************/ static void testclusteringunit_kmeansspecialtests(ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t npoints; ae_int_t nfeatures; ae_int_t nclusters; ae_int_t initalgo; ae_matrix xy; ae_matrix c; ae_int_t idx0; ae_int_t idx1; ae_int_t idx2; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t passcount; ae_int_t separation; ae_vector xyc; ae_vector xycref; ae_vector xydist2; ae_vector xydist2ref; ae_vector energies; hqrndstate rs; clusterizerstate s; kmeansreport rep; ae_shared_pool bufferpool; apbuffers bufferseed; ae_vector pointslist; ae_vector featureslist; ae_vector clusterslist; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&xyc, 0, DT_INT, _state); ae_vector_init(&xycref, 0, DT_INT, _state); ae_vector_init(&xydist2, 0, DT_REAL, _state); ae_vector_init(&xydist2ref, 0, DT_REAL, _state); ae_vector_init(&energies, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); _clusterizerstate_init(&s, _state); _kmeansreport_init(&rep, _state); ae_shared_pool_init(&bufferpool, _state); _apbuffers_init(&bufferseed, _state); ae_vector_init(&pointslist, 0, DT_INT, _state); ae_vector_init(&featureslist, 0, DT_INT, _state); ae_vector_init(&clusterslist, 0, DT_INT, _state); hqrndrandomize(&rs, _state); /* * Compare different initialization algorithms: * * dataset is K balls, chosen at random gaussian points, with * radius equal to 2^(-Separation). * * we generate random sample, run k-means initialization algorithm * and calculate mean energy for each initialization algorithm. * In order to suppress Lloyd's iteration we use KmeansDbgNoIts * debug flag. * * then, we compare mean energies; kmeans++ must be best one, * random initialization must be worst one. */ ae_vector_set_length(&energies, 4, _state); passcount = 1000; npoints = 100; nfeatures = 3; nclusters = 6; ae_matrix_set_length(&xy, npoints, nfeatures, _state); ae_matrix_set_length(&c, nclusters, nfeatures, _state); clusterizercreate(&s, _state); s.kmeansdbgnoits = ae_true; for(separation=2; separation<=5; separation++) { /* * Try different init algorithms */ for(initalgo=1; initalgo<=3; initalgo++) { energies.ptr.p_double[initalgo] = 0.0; clusterizersetkmeansinit(&s, initalgo, _state); for(pass=1; pass<=passcount; pass++) { /* * Generate centers of balls */ for(i=0; i<=nclusters-1; i++) { for(j=0; j<=nfeatures-1; j++) { c.ptr.pp_double[i][j] = hqrndnormal(&rs, _state); } } /* * Generate points */ for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = hqrndnormal(&rs, _state)*ae_pow((double)(2), (double)(-separation), _state)+c.ptr.pp_double[i%nclusters][j]; } } /* * Run clusterization */ clusterizersetpoints(&s, &xy, npoints, nfeatures, 2, _state); clusterizerrunkmeans(&s, nclusters, &rep, _state); seterrorflag(othererrors, rep.terminationtype<=0, _state); energies.ptr.p_double[initalgo] = energies.ptr.p_double[initalgo]+rep.energy/passcount; } } /* * Compare */ seterrorflag(othererrors, !ae_fp_less(energies.ptr.p_double[2],energies.ptr.p_double[1]), _state); seterrorflag(othererrors, !ae_fp_less(energies.ptr.p_double[3],energies.ptr.p_double[1]), _state); } /* * Test distance calculation algorithm */ ae_vector_set_length(&pointslist, 6, _state); pointslist.ptr.p_int[0] = 1; pointslist.ptr.p_int[1] = 10; pointslist.ptr.p_int[2] = 32; pointslist.ptr.p_int[3] = 100; pointslist.ptr.p_int[4] = 512; pointslist.ptr.p_int[5] = 8000; ae_vector_set_length(&featureslist, 5, _state); featureslist.ptr.p_int[0] = 1; featureslist.ptr.p_int[1] = 5; featureslist.ptr.p_int[2] = 32; featureslist.ptr.p_int[3] = 50; featureslist.ptr.p_int[4] = 96; ae_vector_set_length(&clusterslist, 5, _state); clusterslist.ptr.p_int[0] = 1; clusterslist.ptr.p_int[1] = 5; clusterslist.ptr.p_int[2] = 32; clusterslist.ptr.p_int[3] = 50; clusterslist.ptr.p_int[4] = 96; ae_shared_pool_set_seed(&bufferpool, &bufferseed, sizeof(bufferseed), _apbuffers_init, _apbuffers_init_copy, _apbuffers_destroy, _state); for(idx0=0; idx0<=pointslist.cnt-1; idx0++) { for(idx1=0; idx1<=featureslist.cnt-1; idx1++) { for(idx2=0; idx2<=clusterslist.cnt-1; idx2++) { npoints = pointslist.ptr.p_int[idx0]; nfeatures = featureslist.ptr.p_int[idx1]; nclusters = clusterslist.ptr.p_int[idx2]; ae_matrix_set_length(&xy, npoints, nfeatures, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = hqrndnormal(&rs, _state); } } ae_matrix_set_length(&c, nclusters, nfeatures, _state); for(i=0; i<=nclusters-1; i++) { for(j=0; j<=nfeatures-1; j++) { c.ptr.pp_double[i][j] = hqrndnormal(&rs, _state); } } ae_vector_set_length(&xyc, npoints, _state); ae_vector_set_length(&xycref, npoints, _state); ae_vector_set_length(&xydist2, npoints, _state); ae_vector_set_length(&xydist2ref, npoints, _state); /* * Test */ kmeansupdatedistances(&xy, 0, npoints, nfeatures, &c, 0, nclusters, &xyc, &xydist2, &bufferpool, _state); testclusteringunit_kmeansreferenceupdatedistances(&xy, npoints, nfeatures, &c, nclusters, &xycref, &xydist2ref, _state); for(i=0; i<=npoints-1; i++) { seterrorflag(othererrors, xyc.ptr.p_int[i]!=xycref.ptr.p_int[i], _state); seterrorflag(othererrors, ae_fp_greater(ae_fabs(xydist2.ptr.p_double[i]-xydist2ref.ptr.p_double[i], _state),1.0E-6), _state); } } } } /* * Test degenerate dataset (less than NClusters distinct points) */ for(nclusters=2; nclusters<=10; nclusters++) { for(initalgo=0; initalgo<=3; initalgo++) { for(pass=1; pass<=10; pass++) { /* * Initialize points. Two algorithms are used: * * initialization by small integers (no rounding problems) * * initialization by "long" fraction */ npoints = 100; nfeatures = 10; ae_matrix_set_length(&xy, npoints, nfeatures, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { for(i=0; i<=nclusters-2; i++) { for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = ae_sin(hqrndnormal(&rs, _state), _state); } } } else { for(i=0; i<=nclusters-2; i++) { for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = (double)(hqrnduniformi(&rs, 50, _state)); } } } for(i=nclusters-1; i<=npoints-1; i++) { idx0 = hqrnduniformi(&rs, nclusters-1, _state); for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = xy.ptr.pp_double[idx0][j]; } } /* * Clusterize with unlimited number of iterations. * Correct error code must be returned. */ clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, npoints, nfeatures, 2, _state); clusterizersetkmeanslimits(&s, 1, 0, _state); clusterizersetkmeansinit(&s, initalgo, _state); clusterizerrunkmeans(&s, nclusters, &rep, _state); seterrorflag(othererrors, rep.terminationtype!=-3, _state); } } } ae_frame_leave(_state); } /************************************************************************* This test checks algorithm ability to handle degenerate problems without causing infinite loop. *************************************************************************/ static void testclusteringunit_kmeansinfinitelooptest(ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t npoints; ae_int_t nfeatures; ae_int_t nclusters; ae_int_t restarts; ae_matrix xy; ae_int_t i; ae_int_t j; clusterizerstate s; kmeansreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _clusterizerstate_init(&s, _state); _kmeansreport_init(&rep, _state); /* * Problem 1: all points are same. * * For NClusters=1 we must get correct solution, for NClusters>1 we must get failure. */ npoints = 100; nfeatures = 1; restarts = 5; ae_matrix_set_length(&xy, npoints, nfeatures, _state); for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[0][j] = ae_randomreal(_state); } for(i=1; i<=npoints-1; i++) { for(j=0; j<=nfeatures-1; j++) { xy.ptr.pp_double[i][j] = xy.ptr.pp_double[0][j]; } } nclusters = 1; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, npoints, nfeatures, 2, _state); clusterizersetkmeanslimits(&s, restarts, 0, _state); clusterizerrunkmeans(&s, nclusters, &rep, _state); *othererrors = *othererrors||rep.terminationtype<=0; for(i=0; i<=nfeatures-1; i++) { *othererrors = *othererrors||ae_fp_greater(ae_fabs(rep.c.ptr.pp_double[0][i]-xy.ptr.pp_double[0][i], _state),1000*ae_machineepsilon); } for(i=0; i<=npoints-1; i++) { *othererrors = *othererrors||rep.cidx.ptr.p_int[i]!=0; } nclusters = 5; clusterizerrunkmeans(&s, nclusters, &rep, _state); *othererrors = *othererrors||rep.terminationtype>0; /* * Problem 2: degenerate dataset (report by Andreas). */ npoints = 57; nfeatures = 1; restarts = 1; nclusters = 4; ae_matrix_set_length(&xy, npoints, nfeatures, _state); xy.ptr.pp_double[0][0] = 12.244689632138986; xy.ptr.pp_double[1][0] = 12.244689632138982; xy.ptr.pp_double[2][0] = 12.244689632138986; xy.ptr.pp_double[3][0] = 12.244689632138982; xy.ptr.pp_double[4][0] = 12.244689632138986; xy.ptr.pp_double[5][0] = 12.244689632138986; xy.ptr.pp_double[6][0] = 12.244689632138986; xy.ptr.pp_double[7][0] = 12.244689632138986; xy.ptr.pp_double[8][0] = 12.244689632138986; xy.ptr.pp_double[9][0] = 12.244689632138986; xy.ptr.pp_double[10][0] = 12.244689632138989; xy.ptr.pp_double[11][0] = 12.244689632138984; xy.ptr.pp_double[12][0] = 12.244689632138986; xy.ptr.pp_double[13][0] = 12.244689632138986; xy.ptr.pp_double[14][0] = 12.244689632138989; xy.ptr.pp_double[15][0] = 12.244689632138986; xy.ptr.pp_double[16][0] = 12.244689632138986; xy.ptr.pp_double[17][0] = 12.244689632138986; xy.ptr.pp_double[18][0] = 12.244689632138986; xy.ptr.pp_double[19][0] = 12.244689632138989; xy.ptr.pp_double[20][0] = 12.244689632138972; xy.ptr.pp_double[21][0] = 12.244689632138986; xy.ptr.pp_double[22][0] = 12.244689632138986; xy.ptr.pp_double[23][0] = 12.244689632138986; xy.ptr.pp_double[24][0] = 12.244689632138984; xy.ptr.pp_double[25][0] = 12.244689632138982; xy.ptr.pp_double[26][0] = 12.244689632138986; xy.ptr.pp_double[27][0] = 12.244689632138986; xy.ptr.pp_double[28][0] = 12.244689632138986; xy.ptr.pp_double[29][0] = 12.244689632138986; xy.ptr.pp_double[30][0] = 12.244689632138986; xy.ptr.pp_double[31][0] = 12.244689632138986; xy.ptr.pp_double[32][0] = 12.244689632138986; xy.ptr.pp_double[33][0] = 12.244689632138986; xy.ptr.pp_double[34][0] = 12.244689632138986; xy.ptr.pp_double[35][0] = 12.244689632138982; xy.ptr.pp_double[36][0] = 12.244689632138989; xy.ptr.pp_double[37][0] = 12.244689632138986; xy.ptr.pp_double[38][0] = 12.244689632138986; xy.ptr.pp_double[39][0] = 12.244689632138986; xy.ptr.pp_double[40][0] = 12.244689632138986; xy.ptr.pp_double[41][0] = 12.244689632138986; xy.ptr.pp_double[42][0] = 12.244689632138986; xy.ptr.pp_double[43][0] = 12.244689632138986; xy.ptr.pp_double[44][0] = 12.244689632138986; xy.ptr.pp_double[45][0] = 12.244689632138986; xy.ptr.pp_double[46][0] = 12.244689632138986; xy.ptr.pp_double[47][0] = 12.244689632138986; xy.ptr.pp_double[48][0] = 12.244689632138986; xy.ptr.pp_double[49][0] = 12.244689632138986; xy.ptr.pp_double[50][0] = 12.244689632138984; xy.ptr.pp_double[51][0] = 12.244689632138986; xy.ptr.pp_double[52][0] = 12.244689632138986; xy.ptr.pp_double[53][0] = 12.244689632138986; xy.ptr.pp_double[54][0] = 12.244689632138986; xy.ptr.pp_double[55][0] = 12.244689632138986; xy.ptr.pp_double[56][0] = 12.244689632138986; clusterizercreate(&s, _state); clusterizersetpoints(&s, &xy, npoints, nfeatures, 2, _state); clusterizersetkmeanslimits(&s, restarts, 0, _state); clusterizerrunkmeans(&s, nclusters, &rep, _state); *othererrors = *othererrors||rep.terminationtype<=0; ae_frame_leave(_state); } /************************************************************************* This non-deterministic test checks that Restarts>1 significantly improves quality of results. Subroutine generates random task 3 unit balls in 2D, each with 20 points, separated by 5 units wide gaps, and solves it with Restarts=1 and with Restarts=5. Potential functions are compared, outcome of the trial is either 0 or 1 (depending on what is better). Sequence of 1000 such tasks is solved. If Restarts>1 actually improve quality of solution, sum of outcome will be non-binomial. If it doesn't matter, it will be binomially distributed. P.S. This test was added after report from Gianluca Borello who noticed error in the handling of multiple restarts. *************************************************************************/ static void testclusteringunit_kmeansrestartstest(ae_bool* converrors, ae_bool* restartserrors, ae_state *_state) { ae_frame _frame_block; ae_int_t npoints; ae_int_t nvars; ae_int_t nclusters; ae_int_t clustersize; ae_int_t restarts; ae_int_t passcount; double sigmathreshold; double p; double s; ae_matrix xy; ae_vector tmp; ae_int_t i; ae_int_t j; ae_int_t pass; double ea; double eb; double v; clusterizerstate state; kmeansreport rep1; kmeansreport rep2; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); _clusterizerstate_init(&state, _state); _kmeansreport_init(&rep1, _state); _kmeansreport_init(&rep2, _state); restarts = 5; passcount = 1000; clustersize = 20; nclusters = 3; nvars = 2; npoints = nclusters*clustersize; sigmathreshold = (double)(5); ae_matrix_set_length(&xy, npoints, nvars, _state); ae_vector_set_length(&tmp, nvars, _state); p = (double)(0); for(pass=1; pass<=passcount; pass++) { /* * Fill */ for(i=0; i<=npoints-1; i++) { testclusteringunit_rsphere(&xy, nvars, i, _state); for(j=0; j<=nvars-1; j++) { xy.ptr.pp_double[i][j] = xy.ptr.pp_double[i][j]+(double)i/(double)clustersize*5; } } clusterizercreate(&state, _state); clusterizersetpoints(&state, &xy, npoints, nvars, 2, _state); /* * Test: Restarts=1 */ clusterizersetkmeanslimits(&state, 1, 0, _state); clusterizerrunkmeans(&state, nclusters, &rep1, _state); if( rep1.terminationtype<=0 ) { *converrors = ae_true; ae_frame_leave(_state); return; } ea = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &rep1.c.ptr.pp_double[rep1.cidx.ptr.p_int[i]][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); ea = ea+v; } /* * Test: Restarts>1 */ clusterizersetkmeanslimits(&state, restarts, 0, _state); clusterizerrunkmeans(&state, nclusters, &rep2, _state); if( rep2.terminationtype<=0 ) { *converrors = ae_true; ae_frame_leave(_state); return; } eb = (double)(0); for(i=0; i<=npoints-1; i++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &rep2.c.ptr.pp_double[rep2.cidx.ptr.p_int[i]][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); eb = eb+v; } /* * Calculate statistic. */ if( ae_fp_less(ea,eb) ) { p = p+1; } if( ae_fp_eq(ea,eb) ) { p = p+0.5; } } /* * If Restarts doesn't influence quality of centers found, P must be * binomially distributed random value with mean 0.5*PassCount and * standard deviation Sqrt(PassCount/4). * * If Restarts do influence quality of solution, P must be significantly * lower than 0.5*PassCount. */ s = (p-0.5*passcount)/ae_sqrt((double)passcount/(double)4, _state); *restartserrors = *restartserrors||ae_fp_greater(s,-sigmathreshold); ae_frame_leave(_state); } /************************************************************************* Random normal number *************************************************************************/ static double testclusteringunit_rnormal(ae_state *_state) { double u; double v; double s; double x1; double x2; double result; for(;;) { u = 2*ae_randomreal(_state)-1; v = 2*ae_randomreal(_state)-1; s = ae_sqr(u, _state)+ae_sqr(v, _state); if( ae_fp_greater(s,(double)(0))&&ae_fp_less(s,(double)(1)) ) { s = ae_sqrt(-2*ae_log(s, _state)/s, _state); x1 = u*s; x2 = v*s; break; } } result = x1; return result; } /************************************************************************* Random point from sphere *************************************************************************/ static void testclusteringunit_rsphere(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t i, ae_state *_state) { ae_int_t j; double v; for(j=0; j<=n-1; j++) { xy->ptr.pp_double[i][j] = testclusteringunit_rnormal(_state); } v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = ae_randomreal(_state)/ae_sqrt(v, _state); ae_v_muld(&xy->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } /************************************************************************* Distance function: distance between X0 and X1 X0, X1 - array[D], points DistType - distance type *************************************************************************/ static double testclusteringunit_distfunc(/* Real */ ae_vector* x0, /* Real */ ae_vector* x1, ae_int_t d, ae_int_t disttype, ae_state *_state) { ae_int_t i; double s0; double s1; double result; ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "Assertion failed", _state); if( disttype==0 ) { result = 0.0; for(i=0; i<=d-1; i++) { result = ae_maxreal(result, ae_fabs(x0->ptr.p_double[i]-x1->ptr.p_double[i], _state), _state); } return result; } if( disttype==1 ) { result = 0.0; for(i=0; i<=d-1; i++) { result = result+ae_fabs(x0->ptr.p_double[i]-x1->ptr.p_double[i], _state); } return result; } if( disttype==2 ) { result = 0.0; for(i=0; i<=d-1; i++) { result = result+ae_sqr(x0->ptr.p_double[i]-x1->ptr.p_double[i], _state); } result = ae_sqrt(result, _state); return result; } if( disttype==10 ) { result = ae_maxreal(1-pearsoncorr2(x0, x1, d, _state), 0.0, _state); return result; } if( disttype==11 ) { result = ae_maxreal(1-ae_fabs(pearsoncorr2(x0, x1, d, _state), _state), 0.0, _state); return result; } if( disttype==12||disttype==13 ) { s0 = 0.0; s1 = 0.0; for(i=0; i<=d-1; i++) { s0 = s0+ae_sqr(x0->ptr.p_double[i], _state)/d; s1 = s1+ae_sqr(x1->ptr.p_double[i], _state)/d; } s0 = ae_sqrt(s0, _state); s1 = ae_sqrt(s1, _state); result = (double)(0); for(i=0; i<=d-1; i++) { result = result+x0->ptr.p_double[i]/s0*(x1->ptr.p_double[i]/s1)/d; } if( disttype==12 ) { result = ae_maxreal(1-result, 0.0, _state); } else { result = ae_maxreal(1-ae_fabs(result, _state), 0.0, _state); } return result; } if( disttype==20 ) { result = ae_maxreal(1-spearmancorr2(x0, x1, d, _state), 0.0, _state); return result; } if( disttype==21 ) { result = ae_maxreal(1-ae_fabs(spearmancorr2(x0, x1, d, _state), _state), 0.0, _state); return result; } result = (double)(0); return result; } /************************************************************************* This function replays merges and checks that: * Rep.NPoints, Rep.Z, Rep.PZ and Rep.PM are consistent and correct * Rep.MergeDist is consistent with distance between clusters being merged * clusters with minimal distance are merged at each step * GetKClusters() correctly unpacks clusters for each K NOTE: this algorithm correctly handle ties, i.e. situations where several pairs of clusters have same intercluster distance, and we can't unambiguously choose clusters to merge. INPUT PARAMETERS D - distance matrix, array[NPoints,NPoints], full matrix is given (including both triangles and zeros on the main diagonal) XY - dataset matrix, array[NPoints,NF] NPoints - dataset size NF - number of features Rep - clusterizer report AHCAlgo - AHC algorithm: * 0 - complete linkage * 1 - single linkage * 2 - unweighted average linkage This function returns True on failure, False on success. *************************************************************************/ static ae_bool testclusteringunit_errorsinmerges(/* Real */ ae_matrix* d, /* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nf, ahcreport* rep, ae_int_t ahcalgo, ae_state *_state) { ae_frame _frame_block; ae_matrix dm; ae_matrix cm; ae_vector clustersizes; ae_vector clusterheights; ae_vector b; ae_vector x0; ae_vector x1; ae_bool bflag; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t i0; ae_int_t i1; ae_int_t c0; ae_int_t c1; ae_int_t s0; ae_int_t s1; double v; ae_int_t t; ae_int_t mergeidx; ae_vector kidx; ae_vector kidxz; ae_int_t currentelement; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&dm, 0, 0, DT_REAL, _state); ae_matrix_init(&cm, 0, 0, DT_INT, _state); ae_vector_init(&clustersizes, 0, DT_INT, _state); ae_vector_init(&clusterheights, 0, DT_INT, _state); ae_vector_init(&b, 0, DT_BOOL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&kidx, 0, DT_INT, _state); ae_vector_init(&kidxz, 0, DT_INT, _state); ae_assert(ahcalgo!=3, "integrity error", _state); result = ae_false; ae_vector_set_length(&x0, nf, _state); ae_vector_set_length(&x1, nf, _state); /* * Basic checks: * * positive completion code * * sizes of arrays * * Rep.P is correct permutation * * Rep.Z contains correct cluster indexes * * Rep.PZ is consistent with Rep.P/Rep.Z * * Rep.PM contains consistent indexes * * GetKClusters() for K=NPoints */ bflag = ae_false; bflag = bflag||rep->terminationtype<=0; if( bflag ) { result = ae_true; ae_frame_leave(_state); return result; } bflag = bflag||rep->npoints!=npoints; bflag = (bflag||rep->z.rows!=npoints-1)||(npoints>1&&rep->z.cols!=2); bflag = (bflag||rep->pz.rows!=npoints-1)||(npoints>1&&rep->pz.cols!=2); bflag = (bflag||rep->pm.rows!=npoints-1)||(npoints>1&&rep->pm.cols!=6); bflag = bflag||rep->mergedist.cnt!=npoints-1; bflag = bflag||rep->p.cnt!=npoints; if( bflag ) { result = ae_true; ae_frame_leave(_state); return result; } ae_vector_set_length(&b, npoints, _state); for(i=0; i<=npoints-1; i++) { b.ptr.p_bool[i] = ae_false; } for(i=0; i<=npoints-1; i++) { if( (rep->p.ptr.p_int[i]<0||rep->p.ptr.p_int[i]>=npoints)||b.ptr.p_bool[rep->p.ptr.p_int[i]] ) { result = ae_true; ae_frame_leave(_state); return result; } b.ptr.p_bool[rep->p.ptr.p_int[i]] = ae_true; } for(i=0; i<=npoints-2; i++) { if( (rep->z.ptr.pp_int[i][0]<0||rep->z.ptr.pp_int[i][0]>=rep->z.ptr.pp_int[i][1])||rep->z.ptr.pp_int[i][1]>=npoints+i ) { result = ae_true; ae_frame_leave(_state); return result; } if( (rep->pz.ptr.pp_int[i][0]<0||rep->pz.ptr.pp_int[i][0]>=rep->pz.ptr.pp_int[i][1])||rep->pz.ptr.pp_int[i][1]>=npoints+i ) { result = ae_true; ae_frame_leave(_state); return result; } } for(i=0; i<=npoints-2; i++) { c0 = rep->z.ptr.pp_int[i][0]; c1 = rep->z.ptr.pp_int[i][1]; s0 = rep->pz.ptr.pp_int[i][0]; s1 = rep->pz.ptr.pp_int[i][1]; if( c0p.ptr.p_int[c0]; } if( c1p.ptr.p_int[c1]; } if( c0!=s0||c1!=s1 ) { result = ae_true; ae_frame_leave(_state); return result; } } clusterizergetkclusters(rep, npoints, &kidx, &kidxz, _state); if( kidx.cnt!=npoints||kidxz.cnt!=npoints ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=npoints-1; i++) { if( kidxz.ptr.p_int[i]!=i||kidx.ptr.p_int[i]!=i ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Test description: * * we generate (2*NPoints-1)x(2*NPoints-1) matrix of distances DM and * (2*NPoints-1)xNPoints matrix of clusters CM (I-th row contains indexes * of elements which belong to I-th cluster, negative indexes denote * empty cells). Leading N*N square of DM is just a distance matrix, * other elements are filled by some large number M (used to mark empty * elements). * * we replay all merges * * every time we merge clusters I and J into K, we: * * check that distance between I and J is equal to the smallest * element of DM (note: we account for rounding errors when we * decide on that) * * check that distance is consistent with Rep.MergeDist * * then, we enumerate all elements in clusters being merged, * and check that after permutation their indexes fall into range * prescribed by Rep.PM * * fill K-th column/row of D by distances to cluster K * * merge I-th and J-th rows of CM and store result into K-th row * * clear DM and CM: fill I-th and J-th column/row of DM by large * number M, fill I-th and J-th row of CM by -1. * * NOTE: DM is initialized by distance metric specific to AHC algorithm * being used. CLINK, SLINK and average linkage use user-provided * distance measure, say Euclidean one, without any modifications. * Ward's method uses (and reports) squared and scaled Euclidean * distances. */ ae_matrix_set_length(&dm, 2*npoints-1, 2*npoints-1, _state); ae_matrix_set_length(&cm, 2*npoints-1, npoints, _state); ae_vector_set_length(&clustersizes, 2*npoints-1, _state); for(i=0; i<=2*npoints-2; i++) { for(j=0; j<=2*npoints-2; j++) { if( iptr.pp_double[i][j]; if( ahcalgo==4 ) { dm.ptr.pp_double[i][j] = 0.5*ae_sqr(dm.ptr.pp_double[i][j], _state); } } else { dm.ptr.pp_double[i][j] = ae_maxrealnumber; } } } for(i=0; i<=2*npoints-2; i++) { for(j=0; j<=npoints-1; j++) { cm.ptr.pp_int[i][j] = -1; } } for(i=0; i<=npoints-1; i++) { cm.ptr.pp_int[i][0] = i; clustersizes.ptr.p_int[i] = 1; } for(i=npoints; i<=2*npoints-2; i++) { clustersizes.ptr.p_int[i] = 0; } ae_vector_set_length(&clusterheights, 2*npoints-1, _state); for(i=0; i<=npoints-1; i++) { clusterheights.ptr.p_int[i] = 0; } for(mergeidx=0; mergeidx<=npoints-2; mergeidx++) { /* * Check that clusters with minimum distance are merged, * and that MergeDist is consistent with results. * * NOTE: we do not check for specific cluster indexes, * because it is possible to have a tie. We just * check that distance between clusters is a true * minimum over all possible clusters. */ v = ae_maxrealnumber; for(i=0; i<=2*npoints-2; i++) { for(j=0; j<=2*npoints-2; j++) { if( i!=j ) { v = ae_minreal(v, dm.ptr.pp_double[i][j], _state); } } } c0 = rep->z.ptr.pp_int[mergeidx][0]; c1 = rep->z.ptr.pp_int[mergeidx][1]; if( ae_fp_greater(dm.ptr.pp_double[c0][c1],v+10000*ae_machineepsilon) ) { result = ae_true; ae_frame_leave(_state); return result; } if( ae_fp_greater(rep->mergedist.ptr.p_double[mergeidx],v+10000*ae_machineepsilon) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Check that indexes of elements fall into range prescribed by Rep.PM, * and Rep.PM correctly described merge operation */ s0 = clustersizes.ptr.p_int[c0]; s1 = clustersizes.ptr.p_int[c1]; for(j=0; j<=clustersizes.ptr.p_int[c0]-1; j++) { if( rep->p.ptr.p_int[cm.ptr.pp_int[c0][j]]pm.ptr.pp_int[mergeidx][0]||rep->p.ptr.p_int[cm.ptr.pp_int[c0][j]]>rep->pm.ptr.pp_int[mergeidx][1] ) { /* * Element falls outside of range described by PM */ result = ae_true; ae_frame_leave(_state); return result; } } for(j=0; j<=clustersizes.ptr.p_int[c1]-1; j++) { if( rep->p.ptr.p_int[cm.ptr.pp_int[c1][j]]pm.ptr.pp_int[mergeidx][2]||rep->p.ptr.p_int[cm.ptr.pp_int[c1][j]]>rep->pm.ptr.pp_int[mergeidx][3] ) { /* * Element falls outside of range described by PM */ result = ae_true; ae_frame_leave(_state); return result; } } if( (rep->pm.ptr.pp_int[mergeidx][1]-rep->pm.ptr.pp_int[mergeidx][0]!=s0-1||rep->pm.ptr.pp_int[mergeidx][3]-rep->pm.ptr.pp_int[mergeidx][2]!=s1-1)||rep->pm.ptr.pp_int[mergeidx][2]!=rep->pm.ptr.pp_int[mergeidx][1]+1 ) { /* * Cluster size (as given by PM) is inconsistent with its actual size. */ result = ae_true; ae_frame_leave(_state); return result; } if( rep->pm.ptr.pp_int[mergeidx][4]!=clusterheights.ptr.p_int[rep->z.ptr.pp_int[mergeidx][0]]||rep->pm.ptr.pp_int[mergeidx][5]!=clusterheights.ptr.p_int[rep->z.ptr.pp_int[mergeidx][1]] ) { /* * Heights of subdendrograms as returned by PM are inconsistent with heights * calculated by us. */ result = ae_true; ae_frame_leave(_state); return result; } /* * Update cluster heights */ clusterheights.ptr.p_int[mergeidx+npoints] = ae_maxint(clusterheights.ptr.p_int[rep->z.ptr.pp_int[mergeidx][0]], clusterheights.ptr.p_int[rep->z.ptr.pp_int[mergeidx][1]], _state)+1; /* * Update CM */ t = 0; for(j=0; j<=clustersizes.ptr.p_int[rep->z.ptr.pp_int[mergeidx][0]]-1; j++) { cm.ptr.pp_int[npoints+mergeidx][t] = cm.ptr.pp_int[rep->z.ptr.pp_int[mergeidx][0]][j]; t = t+1; } for(j=0; j<=clustersizes.ptr.p_int[rep->z.ptr.pp_int[mergeidx][1]]-1; j++) { cm.ptr.pp_int[npoints+mergeidx][t] = cm.ptr.pp_int[rep->z.ptr.pp_int[mergeidx][1]][j]; t = t+1; } clustersizes.ptr.p_int[npoints+mergeidx] = t; clustersizes.ptr.p_int[rep->z.ptr.pp_int[mergeidx][0]] = 0; clustersizes.ptr.p_int[rep->z.ptr.pp_int[mergeidx][1]] = 0; /* * Update distance matrix D */ for(i=0; i<=2*npoints-2; i++) { /* * "Remove" columns/rows corresponding to clusters being merged */ dm.ptr.pp_double[i][rep->z.ptr.pp_int[mergeidx][0]] = ae_maxrealnumber; dm.ptr.pp_double[i][rep->z.ptr.pp_int[mergeidx][1]] = ae_maxrealnumber; dm.ptr.pp_double[rep->z.ptr.pp_int[mergeidx][0]][i] = ae_maxrealnumber; dm.ptr.pp_double[rep->z.ptr.pp_int[mergeidx][1]][i] = ae_maxrealnumber; } for(i=0; i<=npoints+mergeidx-1; i++) { if( clustersizes.ptr.p_int[i]>0 ) { /* * Calculate column/row corresponding to new cluster */ if( ahcalgo==0 ) { /* * Calculate distance between clusters I and NPoints+MergeIdx for CLINK */ v = 0.0; for(i0=0; i0<=clustersizes.ptr.p_int[i]-1; i0++) { for(i1=0; i1<=clustersizes.ptr.p_int[npoints+mergeidx]-1; i1++) { v = ae_maxreal(v, d->ptr.pp_double[cm.ptr.pp_int[i][i0]][cm.ptr.pp_int[npoints+mergeidx][i1]], _state); } } } if( ahcalgo==1 ) { /* * Calculate distance between clusters I and NPoints+MergeIdx for SLINK */ v = ae_maxrealnumber; for(i0=0; i0<=clustersizes.ptr.p_int[i]-1; i0++) { for(i1=0; i1<=clustersizes.ptr.p_int[npoints+mergeidx]-1; i1++) { v = ae_minreal(v, d->ptr.pp_double[cm.ptr.pp_int[i][i0]][cm.ptr.pp_int[npoints+mergeidx][i1]], _state); } } } if( ahcalgo==2 ) { /* * Calculate distance between clusters I and NPoints+MergeIdx for unweighted average */ v = 0.0; t = 0; for(i0=0; i0<=clustersizes.ptr.p_int[i]-1; i0++) { for(i1=0; i1<=clustersizes.ptr.p_int[npoints+mergeidx]-1; i1++) { v = v+d->ptr.pp_double[cm.ptr.pp_int[i][i0]][cm.ptr.pp_int[npoints+mergeidx][i1]]; t = t+1; } } v = v/t; } if( ahcalgo==3 ) { ae_assert(ae_false, "Assertion failed", _state); } if( ahcalgo==4 ) { /* * Calculate distance between clusters I and NPoints+MergeIdx for Ward's method: * * X0 = center of mass for cluster I * * X1 = center of mass for cluster NPoints+MergeIdx * * S0 = size of cluster I * * S1 = size of cluster NPoints+MergeIdx * * distance between clusters is S0*S1/(S0+S1)*|X0-X1|^2 * */ for(j=0; j<=nf-1; j++) { x0.ptr.p_double[j] = 0.0; x1.ptr.p_double[j] = 0.0; } for(i0=0; i0<=clustersizes.ptr.p_int[i]-1; i0++) { for(j=0; j<=nf-1; j++) { x0.ptr.p_double[j] = x0.ptr.p_double[j]+xy->ptr.pp_double[cm.ptr.pp_int[i][i0]][j]/clustersizes.ptr.p_int[i]; } } for(i1=0; i1<=clustersizes.ptr.p_int[npoints+mergeidx]-1; i1++) { for(j=0; j<=nf-1; j++) { x1.ptr.p_double[j] = x1.ptr.p_double[j]+xy->ptr.pp_double[cm.ptr.pp_int[npoints+mergeidx][i1]][j]/clustersizes.ptr.p_int[npoints+mergeidx]; } } v = 0.0; for(j=0; j<=nf-1; j++) { v = v+ae_sqr(x0.ptr.p_double[j]-x1.ptr.p_double[j], _state); } v = v*clustersizes.ptr.p_int[i]*clustersizes.ptr.p_int[npoints+mergeidx]/(clustersizes.ptr.p_int[i]+clustersizes.ptr.p_int[npoints+mergeidx]); } dm.ptr.pp_double[i][npoints+mergeidx] = v; dm.ptr.pp_double[npoints+mergeidx][i] = v; } } /* * Check that GetKClusters() correctly unpacks clusters for K=NPoints-(MergeIdx+1): * * check lengths of arays * * check consistency of CIdx/CZ parameters * * scan clusters (CZ parameter), for each cluster scan CM matrix which stores * cluster elements (according to our replay of merges), for each element of * the current cluster check that CIdx array correctly reflects its status. */ k = npoints-(mergeidx+1); clusterizergetkclusters(rep, k, &kidx, &kidxz, _state); if( kidx.cnt!=npoints||kidxz.cnt!=k ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=k-2; i++) { if( (kidxz.ptr.p_int[i]<0||kidxz.ptr.p_int[i]>=kidxz.ptr.p_int[i+1])||kidxz.ptr.p_int[i+1]>2*npoints-2 ) { /* * CZ is inconsistent */ result = ae_true; ae_frame_leave(_state); return result; } } for(i=0; i<=npoints-1; i++) { if( kidx.ptr.p_int[i]<0||kidx.ptr.p_int[i]>=k ) { /* * CIdx is inconsistent */ result = ae_true; ae_frame_leave(_state); return result; } } for(i=0; i<=k-1; i++) { for(j=0; j<=clustersizes.ptr.p_int[kidxz.ptr.p_int[i]]-1; j++) { currentelement = cm.ptr.pp_int[kidxz.ptr.p_int[i]][j]; if( kidx.ptr.p_int[currentelement]!=i ) { /* * We've found element which belongs to I-th cluster (according to CM * matrix, which reflects current status of agglomerative clustering), * but this element does not belongs to I-th cluster according to * results of ClusterizerGetKClusters() */ result = ae_true; ae_frame_leave(_state); return result; } } } } ae_frame_leave(_state); return result; } /************************************************************************* This procedure is a reference version of KMeansUpdateDistances(). INPUT PARAMETERS: XY - dataset, array [0..NPoints-1,0..NVars-1]. NPoints - dataset size, NPoints>=K NVars - number of variables, NVars>=1 CT - matrix of centers, centers are stored in rows K - number of centers, K>=1 XYC - preallocated output buffer XYDist2 - preallocated output buffer OUTPUT PARAMETERS: XYC - new assignment of points to centers XYDist2 - squared distances -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/ static void testclusteringunit_kmeansreferenceupdatedistances(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nvars, /* Real */ ae_matrix* ct, ae_int_t k, /* Integer */ ae_vector* xyc, /* Real */ ae_vector* xydist2, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t cclosest; double dclosest; double v; ae_vector tmp; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_set_length(&tmp, nvars, _state); for(i=0; i<=npoints-1; i++) { cclosest = -1; dclosest = ae_maxrealnumber; for(j=0; j<=k-1; j++) { ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); ae_v_sub(&tmp.ptr.p_double[0], 1, &ct->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); if( ae_fp_less(v,dclosest) ) { cclosest = j; dclosest = v; } } ae_assert(cclosest>=0, "KMeansUpdateDistances: internal error", _state); xyc->ptr.p_int[i] = cclosest; xydist2->ptr.p_double[i] = dclosest; } ae_frame_leave(_state); } static void testdforestunit_testprocessing(ae_bool* err, ae_state *_state); static void testdforestunit_basictest1(ae_int_t nvars, ae_int_t nclasses, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testdforestunit_basictest2(ae_bool* err, ae_state *_state); static void testdforestunit_basictest3(ae_bool* err, ae_state *_state); static void testdforestunit_basictest4(ae_bool* err, ae_state *_state); static void testdforestunit_basictest5(ae_bool* err, ae_state *_state); static void testdforestunit_unsetdf(decisionforest* df, ae_state *_state); ae_bool testdforest(ae_bool silent, ae_state *_state) { ae_int_t ncmax; ae_int_t nvmax; ae_int_t passcount; ae_int_t nvars; ae_int_t nclasses; ae_bool waserrors; ae_bool basicerrors; ae_bool procerrors; ae_bool result; /* * Primary settings */ nvmax = 4; ncmax = 3; passcount = 10; basicerrors = ae_false; procerrors = ae_false; waserrors = ae_false; /* * Tests */ testdforestunit_testprocessing(&procerrors, _state); for(nvars=1; nvars<=nvmax; nvars++) { for(nclasses=1; nclasses<=ncmax; nclasses++) { testdforestunit_basictest1(nvars, nclasses, passcount, &basicerrors, _state); } } testdforestunit_basictest2(&basicerrors, _state); testdforestunit_basictest3(&basicerrors, _state); testdforestunit_basictest4(&basicerrors, _state); testdforestunit_basictest5(&basicerrors, _state); /* * Final report */ waserrors = basicerrors||procerrors; if( !silent ) { printf("RANDOM FOREST TEST\n"); printf("TOTAL RESULTS: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* PROCESSING FUNCTIONS: "); if( !procerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* BASIC TESTS: "); if( !basicerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testdforest(ae_bool silent, ae_state *_state) { return testdforest(silent, _state); } /************************************************************************* Processing functions test *************************************************************************/ static void testdforestunit_testprocessing(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t nvars; ae_int_t nclasses; ae_int_t nsample; ae_int_t ntrees; ae_int_t nfeatures; ae_int_t flags; decisionforest df1; decisionforest df2; ae_int_t npoints; ae_matrix xy; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_bool allsame; ae_int_t info; dfreport rep; ae_vector x1; ae_vector x2; ae_vector y1; ae_vector y2; double v; ae_frame_make(_state, &_frame_block); _decisionforest_init(&df1, _state); _decisionforest_init(&df2, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _dfreport_init(&rep, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); passcount = 100; /* * Main cycle */ for(pass=1; pass<=passcount; pass++) { /* * initialize parameters */ nvars = 1+ae_randominteger(5, _state); nclasses = 1+ae_randominteger(3, _state); ntrees = 1+ae_randominteger(4, _state); nfeatures = 1+ae_randominteger(nvars, _state); flags = 0; if( ae_fp_greater(ae_randomreal(_state),0.5) ) { flags = flags+2; } /* * Initialize arrays and data */ npoints = 10+ae_randominteger(50, _state); nsample = ae_maxint(10, ae_randominteger(npoints, _state), _state); ae_vector_set_length(&x1, nvars-1+1, _state); ae_vector_set_length(&x2, nvars-1+1, _state); ae_vector_set_length(&y1, nclasses-1+1, _state); ae_vector_set_length(&y2, nclasses-1+1, _state); ae_matrix_set_length(&xy, npoints-1+1, nvars+1, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nvars-1; j++) { if( j%2==0 ) { xy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { xy.ptr.pp_double[i][j] = (double)(ae_randominteger(2, _state)); } } if( nclasses==1 ) { xy.ptr.pp_double[i][nvars] = 2*ae_randomreal(_state)-1; } else { xy.ptr.pp_double[i][nvars] = (double)(ae_randominteger(nclasses, _state)); } } /* * create forest */ dfbuildinternal(&xy, npoints, nvars, nclasses, ntrees, nsample, nfeatures, flags, &info, &df1, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } /* * Same inputs leads to same outputs */ for(i=0; i<=nvars-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nclasses-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } dfprocess(&df1, &x1, &y1, _state); dfprocess(&df1, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nclasses-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Same inputs on original forest leads to same outputs * on copy created using DFCopy */ testdforestunit_unsetdf(&df2, _state); dfcopy(&df1, &df2, _state); for(i=0; i<=nvars-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nclasses-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } dfprocess(&df1, &x1, &y1, _state); dfprocess(&df2, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nclasses-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Same inputs on original forest leads to same outputs * on copy created using DFSerialize */ testdforestunit_unsetdf(&df2, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); dfalloc(&_local_serializer, &df1, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); dfserialize(&_local_serializer, &df1, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); dfunserialize(&_local_serializer, &df2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } for(i=0; i<=nvars-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nclasses-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } dfprocess(&df1, &x1, &y1, _state); dfprocess(&df2, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nclasses-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Normalization properties */ if( nclasses>1 ) { for(i=0; i<=nvars-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } dfprocess(&df1, &x1, &y1, _state); v = (double)(0); for(i=0; i<=nclasses-1; i++) { v = v+y1.ptr.p_double[i]; *err = *err||ae_fp_less(y1.ptr.p_double[i],(double)(0)); } *err = *err||ae_fp_greater(ae_fabs(v-1, _state),1000*ae_machineepsilon); } } ae_frame_leave(_state); } /************************************************************************* Basic test: one-tree forest built using full sample must remember all the training cases *************************************************************************/ static void testdforestunit_basictest1(ae_int_t nvars, ae_int_t nclasses, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_matrix xy; ae_int_t npoints; ae_int_t i; ae_int_t j; ae_int_t k; double s; ae_int_t info; decisionforest df; ae_vector x; ae_vector y; dfreport rep; ae_bool hassame; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _decisionforest_init(&df, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _dfreport_init(&rep, _state); if( nclasses==1 ) { /* * only classification tasks */ ae_frame_leave(_state); return; } for(pass=1; pass<=passcount; pass++) { /* * select number of points */ if( pass<=3&&passcount>3 ) { npoints = pass; } else { npoints = 100+ae_randominteger(100, _state); } /* * Prepare task */ ae_matrix_set_length(&xy, npoints-1+1, nvars+1, _state); ae_vector_set_length(&x, nvars-1+1, _state); ae_vector_set_length(&y, nclasses-1+1, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nvars-1; j++) { xy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } xy.ptr.pp_double[i][nvars] = (double)(ae_randominteger(nclasses, _state)); } /* * Test */ dfbuildinternal(&xy, npoints, nvars, nclasses, 1, npoints, 1, 1, &info, &df, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); dfprocess(&df, &x, &y, _state); s = (double)(0); for(j=0; j<=nclasses-1; j++) { if( ae_fp_less(y.ptr.p_double[j],(double)(0)) ) { *err = ae_true; ae_frame_leave(_state); return; } s = s+y.ptr.p_double[j]; } if( ae_fp_greater(ae_fabs(s-1, _state),1000*ae_machineepsilon) ) { *err = ae_true; ae_frame_leave(_state); return; } if( ae_fp_greater(ae_fabs(y.ptr.p_double[ae_round(xy.ptr.pp_double[i][nvars], _state)]-1, _state),1000*ae_machineepsilon) ) { /* * not an error if there exists such K,J that XY[K,J]=XY[I,J] * (may be we just can't distinguish two tied values). * * definitely error otherwise. */ hassame = ae_false; for(k=0; k<=npoints-1; k++) { if( k!=i ) { for(j=0; j<=nvars-1; j++) { if( ae_fp_eq(xy.ptr.pp_double[k][j],xy.ptr.pp_double[i][j]) ) { hassame = ae_true; } } } } if( !hassame ) { *err = ae_true; ae_frame_leave(_state); return; } } } } ae_frame_leave(_state); } /************************************************************************* Basic test: tests generalization ability on a simple noisy classification task: * 00.25 - P(class=0)=0 *************************************************************************/ static void testdforestunit_basictest3(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t passcount; ae_matrix xy; ae_int_t npoints; ae_int_t ntrees; ae_int_t i; ae_int_t j; ae_int_t k; double s; ae_int_t info; decisionforest df; ae_vector x; ae_vector y; dfreport rep; ae_int_t testgridsize; double r; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _decisionforest_init(&df, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _dfreport_init(&rep, _state); passcount = 1; testgridsize = 50; for(pass=1; pass<=passcount; pass++) { /* * select npoints and ntrees */ npoints = 2000; ntrees = 100; /* * Prepare task */ ae_matrix_set_length(&xy, npoints-1+1, 2+1, _state); ae_vector_set_length(&x, 1+1, _state); ae_vector_set_length(&y, 1+1, _state); for(i=0; i<=npoints-1; i++) { xy.ptr.pp_double[i][0] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[i][1] = 2*ae_randomreal(_state)-1; if( ae_fp_less_eq(ae_sqr(xy.ptr.pp_double[i][0], _state)+ae_sqr(xy.ptr.pp_double[i][1], _state),0.25) ) { xy.ptr.pp_double[i][2] = (double)(0); } else { xy.ptr.pp_double[i][2] = (double)(1); } } /* * Test */ dfbuildinternal(&xy, npoints, 2, 2, ntrees, ae_round(0.1*npoints, _state), 1, 0, &info, &df, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } for(i=-testgridsize/2; i<=testgridsize/2; i++) { for(j=-testgridsize/2; j<=testgridsize/2; j++) { x.ptr.p_double[0] = (double)i/(double)(testgridsize/2); x.ptr.p_double[1] = (double)j/(double)(testgridsize/2); dfprocess(&df, &x, &y, _state); /* * Test for basic properties */ s = (double)(0); for(k=0; k<=1; k++) { if( ae_fp_less(y.ptr.p_double[k],(double)(0)) ) { *err = ae_true; ae_frame_leave(_state); return; } s = s+y.ptr.p_double[k]; } if( ae_fp_greater(ae_fabs(s-1, _state),1000*ae_machineepsilon) ) { *err = ae_true; ae_frame_leave(_state); return; } /* * test for good correlation with results */ r = ae_sqrt(ae_sqr(x.ptr.p_double[0], _state)+ae_sqr(x.ptr.p_double[1], _state), _state); if( ae_fp_less(r,0.5*0.5) ) { *err = *err||ae_fp_less(y.ptr.p_double[0],0.6); } if( ae_fp_greater(r,0.5*1.5) ) { *err = *err||ae_fp_less(y.ptr.p_double[1],0.6); } } } } ae_frame_leave(_state); } /************************************************************************* Basic test: simple regression task without noise: * |x|<1, |y|<1 * F(x,y) = x^2+y *************************************************************************/ static void testdforestunit_basictest4(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t passcount; ae_matrix xy; ae_int_t npoints; ae_int_t ntrees; ae_int_t ns; ae_int_t strongc; ae_int_t i; ae_int_t j; ae_int_t info; decisionforest df; decisionforest df2; ae_vector x; ae_vector y; dfreport rep; dfreport rep2; ae_int_t testgridsize; double maxerr; double maxerr2; double avgerr; double avgerr2; ae_int_t cnt; double ey; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _decisionforest_init(&df, _state); _decisionforest_init(&df2, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _dfreport_init(&rep, _state); _dfreport_init(&rep2, _state); passcount = 1; testgridsize = 50; for(pass=1; pass<=passcount; pass++) { /* * select npoints and ntrees */ npoints = 5000; ntrees = 100; ns = ae_round(0.1*npoints, _state); strongc = 1; /* * Prepare task */ ae_matrix_set_length(&xy, npoints-1+1, 2+1, _state); ae_vector_set_length(&x, 1+1, _state); ae_vector_set_length(&y, 0+1, _state); for(i=0; i<=npoints-1; i++) { xy.ptr.pp_double[i][0] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[i][1] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[i][2] = ae_sqr(xy.ptr.pp_double[i][0], _state)+xy.ptr.pp_double[i][1]; } /* * Test */ dfbuildinternal(&xy, npoints, 2, 1, ntrees, ns, 1, 0, &info, &df, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } dfbuildinternal(&xy, npoints, 2, 1, ntrees, ns, 1, strongc, &info, &df2, &rep2, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } maxerr = (double)(0); maxerr2 = (double)(0); avgerr = (double)(0); avgerr2 = (double)(0); cnt = 0; for(i=ae_round(-0.7*testgridsize/2, _state); i<=ae_round(0.7*testgridsize/2, _state); i++) { for(j=ae_round(-0.7*testgridsize/2, _state); j<=ae_round(0.7*testgridsize/2, _state); j++) { x.ptr.p_double[0] = (double)i/(double)(testgridsize/2); x.ptr.p_double[1] = (double)j/(double)(testgridsize/2); ey = ae_sqr(x.ptr.p_double[0], _state)+x.ptr.p_double[1]; dfprocess(&df, &x, &y, _state); maxerr = ae_maxreal(maxerr, ae_fabs(y.ptr.p_double[0]-ey, _state), _state); avgerr = avgerr+ae_fabs(y.ptr.p_double[0]-ey, _state); dfprocess(&df2, &x, &y, _state); maxerr2 = ae_maxreal(maxerr2, ae_fabs(y.ptr.p_double[0]-ey, _state), _state); avgerr2 = avgerr2+ae_fabs(y.ptr.p_double[0]-ey, _state); cnt = cnt+1; } } avgerr = avgerr/cnt; avgerr2 = avgerr2/cnt; *err = *err||ae_fp_greater(maxerr,0.2); *err = *err||ae_fp_greater(maxerr2,0.2); *err = *err||ae_fp_greater(avgerr,0.1); *err = *err||ae_fp_greater(avgerr2,0.1); } ae_frame_leave(_state); } /************************************************************************* Basic test: extended variable selection leads to better results. Next task CAN be solved without EVS but it is very unlikely. With EVS it can be easily and exactly solved. Task matrix: 1 0 0 0 ... 0 0 0 1 0 0 ... 0 1 0 0 1 0 ... 0 2 0 0 0 1 ... 0 3 0 0 0 0 ... 1 N-1 *************************************************************************/ static void testdforestunit_basictest5(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_int_t nvars; ae_int_t npoints; ae_int_t nfeatures; ae_int_t nsample; ae_int_t ntrees; ae_int_t evs; ae_int_t i; ae_int_t j; ae_bool eflag; ae_int_t info; decisionforest df; ae_vector x; ae_vector y; dfreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _decisionforest_init(&df, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _dfreport_init(&rep, _state); /* * select npoints and ntrees */ npoints = 50; nvars = npoints; ntrees = 1; nsample = npoints; evs = 2; nfeatures = 1; /* * Prepare task */ ae_matrix_set_length(&xy, npoints-1+1, nvars+1, _state); ae_vector_set_length(&x, nvars-1+1, _state); ae_vector_set_length(&y, 0+1, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nvars-1; j++) { xy.ptr.pp_double[i][j] = (double)(0); } xy.ptr.pp_double[i][i] = (double)(1); xy.ptr.pp_double[i][nvars] = (double)(i); } /* * Without EVS */ dfbuildinternal(&xy, npoints, nvars, 1, ntrees, nsample, nfeatures, 0, &info, &df, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } eflag = ae_false; for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); dfprocess(&df, &x, &y, _state); if( ae_fp_greater(ae_fabs(y.ptr.p_double[0]-xy.ptr.pp_double[i][nvars], _state),1000*ae_machineepsilon) ) { eflag = ae_true; } } if( !eflag ) { *err = ae_true; ae_frame_leave(_state); return; } /* * With EVS */ dfbuildinternal(&xy, npoints, nvars, 1, ntrees, nsample, nfeatures, evs, &info, &df, &rep, _state); if( info<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } eflag = ae_false; for(i=0; i<=npoints-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); dfprocess(&df, &x, &y, _state); if( ae_fp_greater(ae_fabs(y.ptr.p_double[0]-xy.ptr.pp_double[i][nvars], _state),1000*ae_machineepsilon) ) { eflag = ae_true; } } if( eflag ) { *err = ae_true; ae_frame_leave(_state); return; } ae_frame_leave(_state); } /************************************************************************* Unsets DF *************************************************************************/ static void testdforestunit_unsetdf(decisionforest* df, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_int_t info; dfreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _dfreport_init(&rep, _state); ae_matrix_set_length(&xy, 0+1, 1+1, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(0); dfbuildinternal(&xy, 1, 1, 1, 1, 1, 1, 0, &info, df, &rep, _state); ae_frame_leave(_state); } ae_bool testgammafunc(ae_bool silent, ae_state *_state) { double threshold; double v; double s; ae_bool waserrors; ae_bool gammaerrors; ae_bool lngammaerrors; ae_bool result; gammaerrors = ae_false; lngammaerrors = ae_false; waserrors = ae_false; threshold = 100*ae_machineepsilon; /* * */ gammaerrors = gammaerrors||ae_fp_greater(ae_fabs(gammafunction(0.5, _state)-ae_sqrt(ae_pi, _state), _state),threshold); gammaerrors = gammaerrors||ae_fp_greater(ae_fabs(gammafunction(1.5, _state)-0.5*ae_sqrt(ae_pi, _state), _state),threshold); v = lngamma(0.5, &s, _state); lngammaerrors = (lngammaerrors||ae_fp_greater(ae_fabs(v-ae_log(ae_sqrt(ae_pi, _state), _state), _state),threshold))||ae_fp_neq(s,(double)(1)); v = lngamma(1.5, &s, _state); lngammaerrors = (lngammaerrors||ae_fp_greater(ae_fabs(v-ae_log(0.5*ae_sqrt(ae_pi, _state), _state), _state),threshold))||ae_fp_neq(s,(double)(1)); /* * report */ waserrors = gammaerrors||lngammaerrors; if( !silent ) { printf("TESTING GAMMA FUNCTION\n"); printf("GAMMA: "); if( gammaerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LN GAMMA: "); if( lngammaerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testgammafunc(ae_bool silent, ae_state *_state) { return testgammafunc(silent, _state); } ae_bool testhblas(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix ua; ae_matrix la; ae_vector x; ae_vector y1; ae_vector y2; ae_vector y3; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t j; ae_int_t i1; ae_int_t i2; ae_bool waserrors; double mverr; double threshold; ae_complex alpha; ae_complex v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ua, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&la, 0, 0, DT_COMPLEX, _state); ae_vector_init(&x, 0, DT_COMPLEX, _state); ae_vector_init(&y1, 0, DT_COMPLEX, _state); ae_vector_init(&y2, 0, DT_COMPLEX, _state); ae_vector_init(&y3, 0, DT_COMPLEX, _state); mverr = (double)(0); waserrors = ae_false; maxn = 10; threshold = 1000*ae_machineepsilon; /* * Test MV */ for(n=2; n<=maxn; n++) { ae_matrix_set_length(&a, n+1, n+1, _state); ae_matrix_set_length(&ua, n+1, n+1, _state); ae_matrix_set_length(&la, n+1, n+1, _state); ae_vector_set_length(&x, n+1, _state); ae_vector_set_length(&y1, n+1, _state); ae_vector_set_length(&y2, n+1, _state); ae_vector_set_length(&y3, n+1, _state); /* * fill A, UA, LA */ for(i=1; i<=n; i++) { a.ptr.pp_complex[i][i].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][i].y = (double)(0); for(j=i+1; j<=n; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[j][i] = ae_c_conj(a.ptr.pp_complex[i][j], _state); } } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { ua.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=1; i<=n; i++) { for(j=i; j<=n; j++) { ua.ptr.pp_complex[i][j] = a.ptr.pp_complex[i][j]; } } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { la.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=1; i<=n; i++) { for(j=1; j<=i; j++) { la.ptr.pp_complex[i][j] = a.ptr.pp_complex[i][j]; } } /* * test on different I1, I2 */ for(i1=1; i1<=n; i1++) { for(i2=i1; i2<=n; i2++) { /* * Fill X, choose Alpha */ for(i=1; i<=i2-i1+1; i++) { x.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; x.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } alpha.x = 2*ae_randomreal(_state)-1; alpha.y = 2*ae_randomreal(_state)-1; /* * calculate A*x, UA*x, LA*x */ for(i=i1; i<=i2; i++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][i1], 1, "N", &x.ptr.p_complex[1], 1, "N", ae_v_len(i1,i2)); y1.ptr.p_complex[i-i1+1] = ae_c_mul(alpha,v); } hermitianmatrixvectormultiply(&ua, ae_true, i1, i2, &x, alpha, &y2, _state); hermitianmatrixvectormultiply(&la, ae_false, i1, i2, &x, alpha, &y3, _state); /* * Calculate error */ ae_v_csub(&y2.ptr.p_complex[1], 1, &y1.ptr.p_complex[1], 1, "N", ae_v_len(1,i2-i1+1)); v = ae_v_cdotproduct(&y2.ptr.p_complex[1], 1, "N", &y2.ptr.p_complex[1], 1, "Conj", ae_v_len(1,i2-i1+1)); mverr = ae_maxreal(mverr, ae_sqrt(ae_c_abs(v, _state), _state), _state); ae_v_csub(&y3.ptr.p_complex[1], 1, &y1.ptr.p_complex[1], 1, "N", ae_v_len(1,i2-i1+1)); v = ae_v_cdotproduct(&y3.ptr.p_complex[1], 1, "N", &y3.ptr.p_complex[1], 1, "Conj", ae_v_len(1,i2-i1+1)); mverr = ae_maxreal(mverr, ae_sqrt(ae_c_abs(v, _state), _state), _state); } } } /* * report */ waserrors = ae_fp_greater(mverr,threshold); if( !silent ) { printf("TESTING HERMITIAN BLAS\n"); printf("MV error: %5.3e\n", (double)(mverr)); printf("Threshold: %5.3e\n", (double)(threshold)); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testhblas(ae_bool silent, ae_state *_state) { return testhblas(silent, _state); } ae_bool testreflections(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t m; ae_int_t maxmn; ae_vector x; ae_vector v; ae_vector work; ae_matrix h; ae_matrix a; ae_matrix b; ae_matrix c; double tmp; double beta; double tau; double err; double mer; double mel; double meg; ae_int_t pass; ae_int_t passcount; double threshold; ae_int_t tasktype; double xscale; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); ae_matrix_init(&h, 0, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); passcount = 10; threshold = 100*ae_machineepsilon; mer = (double)(0); mel = (double)(0); meg = (double)(0); for(pass=1; pass<=passcount; pass++) { for(n=1; n<=10; n++) { for(m=1; m<=10; m++) { /* * Task */ n = 1+ae_randominteger(10, _state); m = 1+ae_randominteger(10, _state); maxmn = ae_maxint(m, n, _state); /* * Initialize */ ae_vector_set_length(&x, maxmn+1, _state); ae_vector_set_length(&v, maxmn+1, _state); ae_vector_set_length(&work, maxmn+1, _state); ae_matrix_set_length(&h, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&a, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&b, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&c, maxmn+1, maxmn+1, _state); /* * GenerateReflection, three tasks are possible: * * random X * * zero X * * non-zero X[1], all other are zeros * * random X, near underflow scale * * random X, near overflow scale */ for(tasktype=0; tasktype<=4; tasktype++) { xscale = (double)(1); if( tasktype==0 ) { for(i=1; i<=n; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } if( tasktype==1 ) { for(i=1; i<=n; i++) { x.ptr.p_double[i] = (double)(0); } } if( tasktype==2 ) { x.ptr.p_double[1] = 2*ae_randomreal(_state)-1; for(i=2; i<=n; i++) { x.ptr.p_double[i] = (double)(0); } } if( tasktype==3 ) { for(i=1; i<=n; i++) { x.ptr.p_double[i] = (ae_randominteger(21, _state)-10)*ae_minrealnumber; } xscale = 10*ae_minrealnumber; } if( tasktype==4 ) { for(i=1; i<=n; i++) { x.ptr.p_double[i] = (2*ae_randomreal(_state)-1)*ae_maxrealnumber; } xscale = ae_maxrealnumber; } ae_v_move(&v.ptr.p_double[1], 1, &x.ptr.p_double[1], 1, ae_v_len(1,n)); generatereflection(&v, n, &tau, _state); beta = v.ptr.p_double[1]; v.ptr.p_double[1] = (double)(1); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { h.ptr.pp_double[i][j] = 1-tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } else { h.ptr.pp_double[i][j] = -tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } } } err = (double)(0); for(i=1; i<=n; i++) { tmp = ae_v_dotproduct(&h.ptr.pp_double[i][1], 1, &x.ptr.p_double[1], 1, ae_v_len(1,n)); if( i==1 ) { err = ae_maxreal(err, ae_fabs(tmp-beta, _state), _state); } else { err = ae_maxreal(err, ae_fabs(tmp, _state), _state); } } meg = ae_maxreal(meg, err/xscale, _state); } /* * ApplyReflectionFromTheLeft */ for(i=1; i<=m; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; v.ptr.p_double[i] = x.ptr.p_double[i]; } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; b.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } } generatereflection(&v, m, &tau, _state); beta = v.ptr.p_double[1]; v.ptr.p_double[1] = (double)(1); applyreflectionfromtheleft(&b, tau, &v, 1, m, 1, n, &work, _state); for(i=1; i<=m; i++) { for(j=1; j<=m; j++) { if( i==j ) { h.ptr.pp_double[i][j] = 1-tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } else { h.ptr.pp_double[i][j] = -tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } } } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { tmp = ae_v_dotproduct(&h.ptr.pp_double[i][1], 1, &a.ptr.pp_double[1][j], a.stride, ae_v_len(1,m)); c.ptr.pp_double[i][j] = tmp; } } err = (double)(0); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { err = ae_maxreal(err, ae_fabs(b.ptr.pp_double[i][j]-c.ptr.pp_double[i][j], _state), _state); } } mel = ae_maxreal(mel, err, _state); /* * ApplyReflectionFromTheRight */ for(i=1; i<=n; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; v.ptr.p_double[i] = x.ptr.p_double[i]; } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; b.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } } generatereflection(&v, n, &tau, _state); beta = v.ptr.p_double[1]; v.ptr.p_double[1] = (double)(1); applyreflectionfromtheright(&b, tau, &v, 1, m, 1, n, &work, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { h.ptr.pp_double[i][j] = 1-tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } else { h.ptr.pp_double[i][j] = -tau*v.ptr.p_double[i]*v.ptr.p_double[j]; } } } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { tmp = ae_v_dotproduct(&a.ptr.pp_double[i][1], 1, &h.ptr.pp_double[1][j], h.stride, ae_v_len(1,n)); c.ptr.pp_double[i][j] = tmp; } } err = (double)(0); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { err = ae_maxreal(err, ae_fabs(b.ptr.pp_double[i][j]-c.ptr.pp_double[i][j], _state), _state); } } mer = ae_maxreal(mer, err, _state); } } } /* * Overflow crash test */ ae_vector_set_length(&x, 10+1, _state); ae_vector_set_length(&v, 10+1, _state); for(i=1; i<=10; i++) { v.ptr.p_double[i] = ae_maxrealnumber*0.01*(2*ae_randomreal(_state)-1); } generatereflection(&v, 10, &tau, _state); result = (ae_fp_less_eq(meg,threshold)&&ae_fp_less_eq(mel,threshold))&&ae_fp_less_eq(mer,threshold); if( !silent ) { printf("TESTING REFLECTIONS\n"); printf("Pass count is %0d\n", (int)(passcount)); printf("Generate absolute error is %5.3e\n", (double)(meg)); printf("Apply(Left) absolute error is %5.3e\n", (double)(mel)); printf("Apply(Right) absolute error is %5.3e\n", (double)(mer)); printf("Overflow crash test passed\n"); if( result ) { printf("TEST PASSED\n"); } else { printf("TEST FAILED\n"); } } ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testreflections(ae_bool silent, ae_state *_state) { return testreflections(silent, _state); } ae_bool testcreflections(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t m; ae_int_t maxmn; ae_vector x; ae_vector v; ae_vector work; ae_matrix h; ae_matrix a; ae_matrix b; ae_matrix c; ae_complex tmp; ae_complex beta; ae_complex tau; double err; double mer; double mel; double meg; ae_int_t pass; ae_int_t passcount; ae_bool waserrors; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_COMPLEX, _state); ae_vector_init(&v, 0, DT_COMPLEX, _state); ae_vector_init(&work, 0, DT_COMPLEX, _state); ae_matrix_init(&h, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&c, 0, 0, DT_COMPLEX, _state); threshold = 1000*ae_machineepsilon; passcount = 1000; mer = (double)(0); mel = (double)(0); meg = (double)(0); for(pass=1; pass<=passcount; pass++) { /* * Task */ n = 1+ae_randominteger(10, _state); m = 1+ae_randominteger(10, _state); maxmn = ae_maxint(m, n, _state); /* * Initialize */ ae_vector_set_length(&x, maxmn+1, _state); ae_vector_set_length(&v, maxmn+1, _state); ae_vector_set_length(&work, maxmn+1, _state); ae_matrix_set_length(&h, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&a, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&b, maxmn+1, maxmn+1, _state); ae_matrix_set_length(&c, maxmn+1, maxmn+1, _state); /* * GenerateReflection */ for(i=1; i<=n; i++) { x.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; x.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; v.ptr.p_complex[i] = x.ptr.p_complex[i]; } complexgeneratereflection(&v, n, &tau, _state); beta = v.ptr.p_complex[1]; v.ptr.p_complex[1] = ae_complex_from_i(1); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { h.ptr.pp_complex[i][j] = ae_c_d_sub(1,ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } else { h.ptr.pp_complex[i][j] = ae_c_neg(ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } } } err = (double)(0); for(i=1; i<=n; i++) { tmp = ae_v_cdotproduct(&h.ptr.pp_complex[1][i], h.stride, "Conj", &x.ptr.p_complex[1], 1, "N", ae_v_len(1,n)); if( i==1 ) { err = ae_maxreal(err, ae_c_abs(ae_c_sub(tmp,beta), _state), _state); } else { err = ae_maxreal(err, ae_c_abs(tmp, _state), _state); } } err = ae_maxreal(err, ae_fabs(beta.y, _state), _state); meg = ae_maxreal(meg, err, _state); /* * ApplyReflectionFromTheLeft */ for(i=1; i<=m; i++) { x.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; x.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; v.ptr.p_complex[i] = x.ptr.p_complex[i]; } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; b.ptr.pp_complex[i][j] = a.ptr.pp_complex[i][j]; } } complexgeneratereflection(&v, m, &tau, _state); beta = v.ptr.p_complex[1]; v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheleft(&b, tau, &v, 1, m, 1, n, &work, _state); for(i=1; i<=m; i++) { for(j=1; j<=m; j++) { if( i==j ) { h.ptr.pp_complex[i][j] = ae_c_d_sub(1,ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } else { h.ptr.pp_complex[i][j] = ae_c_neg(ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } } } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { tmp = ae_v_cdotproduct(&h.ptr.pp_complex[i][1], 1, "N", &a.ptr.pp_complex[1][j], a.stride, "N", ae_v_len(1,m)); c.ptr.pp_complex[i][j] = tmp; } } err = (double)(0); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { err = ae_maxreal(err, ae_c_abs(ae_c_sub(b.ptr.pp_complex[i][j],c.ptr.pp_complex[i][j]), _state), _state); } } mel = ae_maxreal(mel, err, _state); /* * ApplyReflectionFromTheRight */ for(i=1; i<=n; i++) { x.ptr.p_complex[i] = ae_complex_from_d(2*ae_randomreal(_state)-1); v.ptr.p_complex[i] = x.ptr.p_complex[i]; } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); b.ptr.pp_complex[i][j] = a.ptr.pp_complex[i][j]; } } complexgeneratereflection(&v, n, &tau, _state); beta = v.ptr.p_complex[1]; v.ptr.p_complex[1] = ae_complex_from_i(1); complexapplyreflectionfromtheright(&b, tau, &v, 1, m, 1, n, &work, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { h.ptr.pp_complex[i][j] = ae_c_d_sub(1,ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } else { h.ptr.pp_complex[i][j] = ae_c_neg(ae_c_mul(ae_c_mul(tau,v.ptr.p_complex[i]),ae_c_conj(v.ptr.p_complex[j], _state))); } } } for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { tmp = ae_v_cdotproduct(&a.ptr.pp_complex[i][1], 1, "N", &h.ptr.pp_complex[1][j], h.stride, "N", ae_v_len(1,n)); c.ptr.pp_complex[i][j] = tmp; } } err = (double)(0); for(i=1; i<=m; i++) { for(j=1; j<=n; j++) { err = ae_maxreal(err, ae_c_abs(ae_c_sub(b.ptr.pp_complex[i][j],c.ptr.pp_complex[i][j]), _state), _state); } } mer = ae_maxreal(mer, err, _state); } /* * Overflow crash test */ ae_vector_set_length(&x, 10+1, _state); ae_vector_set_length(&v, 10+1, _state); for(i=1; i<=10; i++) { v.ptr.p_complex[i] = ae_complex_from_d(ae_maxrealnumber*0.01*(2*ae_randomreal(_state)-1)); } complexgeneratereflection(&v, 10, &tau, _state); /* * report */ waserrors = (ae_fp_greater(meg,threshold)||ae_fp_greater(mel,threshold))||ae_fp_greater(mer,threshold); if( !silent ) { printf("TESTING COMPLEX REFLECTIONS\n"); printf("Generate error: %5.3e\n", (double)(meg)); printf("Apply(L) error: %5.3e\n", (double)(mel)); printf("Apply(R) error: %5.3e\n", (double)(mer)); printf("Threshold: %5.3e\n", (double)(threshold)); printf("Overflow crash test: PASSED\n"); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testcreflections(ae_bool silent, ae_state *_state) { return testcreflections(silent, _state); } ae_bool testsblas(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix ua; ae_matrix la; ae_vector x; ae_vector y1; ae_vector y2; ae_vector y3; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t j; ae_int_t i1; ae_int_t i2; ae_bool waserrors; double mverr; double threshold; double alpha; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&ua, 0, 0, DT_REAL, _state); ae_matrix_init(&la, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&y3, 0, DT_REAL, _state); mverr = (double)(0); waserrors = ae_false; maxn = 10; threshold = 1000*ae_machineepsilon; /* * Test MV */ for(n=2; n<=maxn; n++) { ae_matrix_set_length(&a, n+1, n+1, _state); ae_matrix_set_length(&ua, n+1, n+1, _state); ae_matrix_set_length(&la, n+1, n+1, _state); ae_vector_set_length(&x, n+1, _state); ae_vector_set_length(&y1, n+1, _state); ae_vector_set_length(&y2, n+1, _state); ae_vector_set_length(&y3, n+1, _state); /* * fill A, UA, LA */ for(i=1; i<=n; i++) { a.ptr.pp_double[i][i] = 2*ae_randomreal(_state)-1; for(j=i+1; j<=n; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { ua.ptr.pp_double[i][j] = (double)(0); } } for(i=1; i<=n; i++) { for(j=i; j<=n; j++) { ua.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { la.ptr.pp_double[i][j] = (double)(0); } } for(i=1; i<=n; i++) { for(j=1; j<=i; j++) { la.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } } /* * test on different I1, I2 */ for(i1=1; i1<=n; i1++) { for(i2=i1; i2<=n; i2++) { /* * Fill X, choose Alpha */ for(i=1; i<=i2-i1+1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } alpha = 2*ae_randomreal(_state)-1; /* * calculate A*x, UA*x, LA*x */ for(i=i1; i<=i2; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][i1], 1, &x.ptr.p_double[1], 1, ae_v_len(i1,i2)); y1.ptr.p_double[i-i1+1] = alpha*v; } symmetricmatrixvectormultiply(&ua, ae_true, i1, i2, &x, alpha, &y2, _state); symmetricmatrixvectormultiply(&la, ae_false, i1, i2, &x, alpha, &y3, _state); /* * Calculate error */ ae_v_sub(&y2.ptr.p_double[1], 1, &y1.ptr.p_double[1], 1, ae_v_len(1,i2-i1+1)); v = ae_v_dotproduct(&y2.ptr.p_double[1], 1, &y2.ptr.p_double[1], 1, ae_v_len(1,i2-i1+1)); mverr = ae_maxreal(mverr, ae_sqrt(v, _state), _state); ae_v_sub(&y3.ptr.p_double[1], 1, &y1.ptr.p_double[1], 1, ae_v_len(1,i2-i1+1)); v = ae_v_dotproduct(&y3.ptr.p_double[1], 1, &y3.ptr.p_double[1], 1, ae_v_len(1,i2-i1+1)); mverr = ae_maxreal(mverr, ae_sqrt(v, _state), _state); } } } /* * report */ waserrors = ae_fp_greater(mverr,threshold); if( !silent ) { printf("TESTING SYMMETRIC BLAS\n"); printf("MV error: %5.3e\n", (double)(mverr)); printf("Threshold: %5.3e\n", (double)(threshold)); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsblas(ae_bool silent, ae_state *_state) { return testsblas(silent, _state); } static double testortfacunit_rmatrixdiff(/* Real */ ae_matrix* a, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t n, ae_state *_state); static void testortfacunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state); static void testortfacunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state); static void testortfacunit_rmatrixfillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state); static void testortfacunit_cmatrixfillsparsea(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state); static void testortfacunit_internalmatrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, ae_state *_state); static void testortfacunit_testrqrproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* qrerrors, ae_state *_state); static void testortfacunit_testcqrproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* qrerrors, ae_state *_state); static void testortfacunit_testrlqproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* lqerrors, ae_state *_state); static void testortfacunit_testclqproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* lqerrors, ae_state *_state); static void testortfacunit_testrbdproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* bderrors, ae_state *_state); static void testortfacunit_testrhessproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* hesserrors, ae_state *_state); static void testortfacunit_testrtdproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* tderrors, ae_state *_state); static void testortfacunit_testctdproblem(/* Complex */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* tderrors, ae_state *_state); /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testortfac(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t maxmn; double threshold; ae_int_t passcount; ae_int_t mx; ae_matrix ra; ae_matrix ca; ae_int_t m; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_bool rqrerrors; ae_bool rlqerrors; ae_bool cqrerrors; ae_bool clqerrors; ae_bool rbderrors; ae_bool rhesserrors; ae_bool rtderrors; ae_bool ctderrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); waserrors = ae_false; rqrerrors = ae_false; rlqerrors = ae_false; cqrerrors = ae_false; clqerrors = ae_false; rbderrors = ae_false; rhesserrors = ae_false; rtderrors = ae_false; ctderrors = ae_false; maxmn = 3*ablasblocksize(&ra, _state)+1; passcount = 1; threshold = 5*1000*ae_machineepsilon; /* * Different problems */ for(mx=1; mx<=maxmn; mx++) { for(pass=1; pass<=passcount; pass++) { /* * Rectangular factorizations: QR, LQ, bidiagonal * Matrix types: zero, dense, sparse */ n = 1+ae_randominteger(mx, _state); m = 1+ae_randominteger(mx, _state); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { n = mx; } else { m = mx; } ae_matrix_set_length(&ra, m, n, _state); ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testortfacunit_testrqrproblem(&ra, m, n, threshold, &rqrerrors, _state); testortfacunit_testrlqproblem(&ra, m, n, threshold, &rlqerrors, _state); testortfacunit_testcqrproblem(&ca, m, n, threshold, &cqrerrors, _state); testortfacunit_testclqproblem(&ca, m, n, threshold, &clqerrors, _state); testortfacunit_testrbdproblem(&ra, m, n, threshold, &rbderrors, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } testortfacunit_testrqrproblem(&ra, m, n, threshold, &rqrerrors, _state); testortfacunit_testrlqproblem(&ra, m, n, threshold, &rlqerrors, _state); testortfacunit_testcqrproblem(&ca, m, n, threshold, &cqrerrors, _state); testortfacunit_testclqproblem(&ca, m, n, threshold, &clqerrors, _state); testortfacunit_testrbdproblem(&ra, m, n, threshold, &rbderrors, _state); testortfacunit_rmatrixfillsparsea(&ra, m, n, 0.95, _state); testortfacunit_cmatrixfillsparsea(&ca, m, n, 0.95, _state); testortfacunit_testrqrproblem(&ra, m, n, threshold, &rqrerrors, _state); testortfacunit_testrlqproblem(&ra, m, n, threshold, &rlqerrors, _state); testortfacunit_testcqrproblem(&ca, m, n, threshold, &cqrerrors, _state); testortfacunit_testclqproblem(&ca, m, n, threshold, &clqerrors, _state); testortfacunit_testrbdproblem(&ra, m, n, threshold, &rbderrors, _state); /* * Square factorizations: Hessenberg, tridiagonal * Matrix types: zero, dense, sparse */ ae_matrix_set_length(&ra, mx, mx, _state); ae_matrix_set_length(&ca, mx, mx, _state); for(i=0; i<=mx-1; i++) { for(j=0; j<=mx-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testortfacunit_testrhessproblem(&ra, mx, threshold, &rhesserrors, _state); for(i=0; i<=mx-1; i++) { for(j=0; j<=mx-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } testortfacunit_testrhessproblem(&ra, mx, threshold, &rhesserrors, _state); testortfacunit_rmatrixfillsparsea(&ra, mx, mx, 0.95, _state); testortfacunit_cmatrixfillsparsea(&ca, mx, mx, 0.95, _state); testortfacunit_testrhessproblem(&ra, mx, threshold, &rhesserrors, _state); /* * Symetric factorizations: tridiagonal * Matrix types: zero, dense, sparse */ ae_matrix_set_length(&ra, mx, mx, _state); ae_matrix_set_length(&ca, mx, mx, _state); for(i=0; i<=mx-1; i++) { for(j=0; j<=mx-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testortfacunit_testrtdproblem(&ra, mx, threshold, &rtderrors, _state); testortfacunit_testctdproblem(&ca, mx, threshold, &ctderrors, _state); for(i=0; i<=mx-1; i++) { for(j=i; j<=mx-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; ra.ptr.pp_double[j][i] = ra.ptr.pp_double[i][j]; ca.ptr.pp_complex[j][i] = ae_c_conj(ca.ptr.pp_complex[i][j], _state); } } for(i=0; i<=mx-1; i++) { ca.ptr.pp_complex[i][i] = ae_complex_from_d(2*ae_randomreal(_state)-1); } testortfacunit_testrtdproblem(&ra, mx, threshold, &rtderrors, _state); testortfacunit_testctdproblem(&ca, mx, threshold, &ctderrors, _state); testortfacunit_rmatrixfillsparsea(&ra, mx, mx, 0.95, _state); testortfacunit_cmatrixfillsparsea(&ca, mx, mx, 0.95, _state); for(i=0; i<=mx-1; i++) { for(j=i; j<=mx-1; j++) { ra.ptr.pp_double[j][i] = ra.ptr.pp_double[i][j]; ca.ptr.pp_complex[j][i] = ae_c_conj(ca.ptr.pp_complex[i][j], _state); } } for(i=0; i<=mx-1; i++) { ca.ptr.pp_complex[i][i] = ae_complex_from_d(2*ae_randomreal(_state)-1); } testortfacunit_testrtdproblem(&ra, mx, threshold, &rtderrors, _state); testortfacunit_testctdproblem(&ca, mx, threshold, &ctderrors, _state); } } /* * report */ waserrors = ((((((rqrerrors||rlqerrors)||cqrerrors)||clqerrors)||rbderrors)||rhesserrors)||rtderrors)||ctderrors; if( !silent ) { printf("TESTING ORTFAC UNIT\n"); printf("RQR ERRORS: "); if( !rqrerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("RLQ ERRORS: "); if( !rlqerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("CQR ERRORS: "); if( !cqrerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("CLQ ERRORS: "); if( !clqerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("RBD ERRORS: "); if( !rbderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("RHESS ERRORS: "); if( !rhesserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("RTD ERRORS: "); if( !rtderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("CTD ERRORS: "); if( !ctderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testortfac(ae_bool silent, ae_state *_state) { return testortfac(silent, _state); } /************************************************************************* Diff *************************************************************************/ static double testortfacunit_rmatrixdiff(/* Real */ ae_matrix* a, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; double result; result = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { result = ae_maxreal(result, ae_fabs(b->ptr.pp_double[i][j]-a->ptr.pp_double[i][j], _state), _state); } } return result; } /************************************************************************* Copy *************************************************************************/ static void testortfacunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* Copy *************************************************************************/ static void testortfacunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } } /************************************************************************* Sparse fill *************************************************************************/ static void testortfacunit_rmatrixfillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_double[i][j] = (double)(0); } } } } /************************************************************************* Sparse fill *************************************************************************/ static void testortfacunit_cmatrixfillsparsea(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a->ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } } /************************************************************************* Matrix multiplication *************************************************************************/ static void testortfacunit_internalmatrixmatrixmultiply(/* Real */ ae_matrix* a, ae_int_t ai1, ae_int_t ai2, ae_int_t aj1, ae_int_t aj2, ae_bool transa, /* Real */ ae_matrix* b, ae_int_t bi1, ae_int_t bi2, ae_int_t bj1, ae_int_t bj2, ae_bool transb, /* Real */ ae_matrix* c, ae_int_t ci1, ae_int_t ci2, ae_int_t cj1, ae_int_t cj2, ae_state *_state) { ae_frame _frame_block; ae_int_t arows; ae_int_t acols; ae_int_t brows; ae_int_t bcols; ae_int_t crows; ae_int_t ccols; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_int_t r; double v; ae_vector work; double beta; double alpha; ae_frame_make(_state, &_frame_block); ae_vector_init(&work, 0, DT_REAL, _state); /* * Pre-setup */ k = ae_maxint(ai2-ai1+1, aj2-aj1+1, _state); k = ae_maxint(k, bi2-bi1+1, _state); k = ae_maxint(k, bj2-bj1+1, _state); ae_vector_set_length(&work, k+1, _state); beta = (double)(0); alpha = (double)(1); /* * Setup */ if( !transa ) { arows = ai2-ai1+1; acols = aj2-aj1+1; } else { arows = aj2-aj1+1; acols = ai2-ai1+1; } if( !transb ) { brows = bi2-bi1+1; bcols = bj2-bj1+1; } else { brows = bj2-bj1+1; bcols = bi2-bi1+1; } ae_assert(acols==brows, "MatrixMatrixMultiply: incorrect matrix sizes!", _state); if( ((arows<=0||acols<=0)||brows<=0)||bcols<=0 ) { ae_frame_leave(_state); return; } crows = arows; ccols = bcols; /* * Test WORK */ i = ae_maxint(arows, acols, _state); i = ae_maxint(brows, i, _state); i = ae_maxint(i, bcols, _state); work.ptr.p_double[1] = (double)(0); work.ptr.p_double[i] = (double)(0); /* * Prepare C */ if( ae_fp_eq(beta,(double)(0)) ) { for(i=ci1; i<=ci2; i++) { for(j=cj1; j<=cj2; j++) { c->ptr.pp_double[i][j] = (double)(0); } } } else { for(i=ci1; i<=ci2; i++) { ae_v_muld(&c->ptr.pp_double[i][cj1], 1, ae_v_len(cj1,cj2), beta); } } /* * A*B */ if( !transa&&!transb ) { for(l=ai1; l<=ai2; l++) { for(r=bi1; r<=bi2; r++) { v = alpha*a->ptr.pp_double[l][aj1+r-bi1]; k = ci1+l-ai1; ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); } } ae_frame_leave(_state); return; } /* * A*B' */ if( !transa&&transb ) { if( arows*acolsptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; } } ae_frame_leave(_state); return; } else { for(l=ai1; l<=ai2; l++) { for(r=bi1; r<=bi2; r++) { v = ae_v_dotproduct(&a->ptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; } } ae_frame_leave(_state); return; } } /* * A'*B */ if( transa&&!transb ) { for(l=aj1; l<=aj2; l++) { for(r=bi1; r<=bi2; r++) { v = alpha*a->ptr.pp_double[ai1+r-bi1][l]; k = ci1+l-aj1; ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); } } ae_frame_leave(_state); return; } /* * A'*B' */ if( transa&&transb ) { if( arows*acolsptr.pp_double[r][bj1+l-ai1]; k = cj1+r-bi1; ae_v_addd(&work.ptr.p_double[1], 1, &a->ptr.pp_double[l][aj1], 1, ae_v_len(1,crows), v); } ae_v_add(&c->ptr.pp_double[ci1][k], c->stride, &work.ptr.p_double[1], 1, ae_v_len(ci1,ci2)); } ae_frame_leave(_state); return; } else { for(l=aj1; l<=aj2; l++) { k = ai2-ai1+1; ae_v_move(&work.ptr.p_double[1], 1, &a->ptr.pp_double[ai1][l], a->stride, ae_v_len(1,k)); for(r=bi1; r<=bi2; r++) { v = ae_v_dotproduct(&work.ptr.p_double[1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(1,k)); c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1]+alpha*v; } } ae_frame_leave(_state); return; } } ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testrqrproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* qrerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix b; ae_vector taub; ae_matrix q; ae_matrix r; ae_matrix q2; double v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_vector_init(&taub, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&r, 0, 0, DT_REAL, _state); ae_matrix_init(&q2, 0, 0, DT_REAL, _state); /* * Test decompose-and-unpack error */ testortfacunit_rmatrixmakeacopy(a, m, n, &b, _state); rmatrixqr(&b, m, n, &taub, _state); rmatrixqrunpackq(&b, m, n, &taub, m, &q, _state); rmatrixqrunpackr(&b, m, n, &r, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &r.ptr.pp_double[0][j], r.stride, ae_v_len(0,m-1)); *qrerrors = *qrerrors||ae_fp_greater(ae_fabs(v-a->ptr.pp_double[i][j], _state),threshold); } } for(i=0; i<=m-1; i++) { for(j=0; j<=ae_minint(i, n-1, _state)-1; j++) { *qrerrors = *qrerrors||ae_fp_neq(r.ptr.pp_double[i][j],(double)(0)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &q.ptr.pp_double[j][0], 1, ae_v_len(0,m-1)); if( i==j ) { v = v-1; } *qrerrors = *qrerrors||ae_fp_greater_eq(ae_fabs(v, _state),threshold); } } /* * Test for other errors */ k = 1+ae_randominteger(m, _state); rmatrixqrunpackq(&b, m, n, &taub, k, &q2, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { *qrerrors = *qrerrors||ae_fp_greater(ae_fabs(q2.ptr.pp_double[i][j]-q.ptr.pp_double[i][j], _state),10*ae_machineepsilon); } } ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testcqrproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* qrerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix b; ae_vector taub; ae_matrix q; ae_matrix r; ae_matrix q2; ae_complex v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_vector_init(&taub, 0, DT_COMPLEX, _state); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&r, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&q2, 0, 0, DT_COMPLEX, _state); /* * Test decompose-and-unpack error */ testortfacunit_cmatrixmakeacopy(a, m, n, &b, _state); cmatrixqr(&b, m, n, &taub, _state); cmatrixqrunpackq(&b, m, n, &taub, m, &q, _state); cmatrixqrunpackr(&b, m, n, &r, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[i][0], 1, "N", &r.ptr.pp_complex[0][j], r.stride, "N", ae_v_len(0,m-1)); *qrerrors = *qrerrors||ae_fp_greater(ae_c_abs(ae_c_sub(v,a->ptr.pp_complex[i][j]), _state),threshold); } } for(i=0; i<=m-1; i++) { for(j=0; j<=ae_minint(i, n-1, _state)-1; j++) { *qrerrors = *qrerrors||ae_c_neq_d(r.ptr.pp_complex[i][j],(double)(0)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,m-1)); if( i==j ) { v = ae_c_sub_d(v,1); } *qrerrors = *qrerrors||ae_fp_greater_eq(ae_c_abs(v, _state),threshold); } } /* * Test for other errors */ k = 1+ae_randominteger(m, _state); cmatrixqrunpackq(&b, m, n, &taub, k, &q2, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { *qrerrors = *qrerrors||ae_fp_greater(ae_c_abs(ae_c_sub(q2.ptr.pp_complex[i][j],q.ptr.pp_complex[i][j]), _state),10*ae_machineepsilon); } } ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testrlqproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* lqerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix b; ae_vector taub; ae_matrix q; ae_matrix l; ae_matrix q2; double v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_vector_init(&taub, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&l, 0, 0, DT_REAL, _state); ae_matrix_init(&q2, 0, 0, DT_REAL, _state); /* * Test decompose-and-unpack error */ testortfacunit_rmatrixmakeacopy(a, m, n, &b, _state); rmatrixlq(&b, m, n, &taub, _state); rmatrixlqunpackq(&b, m, n, &taub, n, &q, _state); rmatrixlqunpackl(&b, m, n, &l, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&l.ptr.pp_double[i][0], 1, &q.ptr.pp_double[0][j], q.stride, ae_v_len(0,n-1)); *lqerrors = *lqerrors||ae_fp_greater_eq(ae_fabs(v-a->ptr.pp_double[i][j], _state),threshold); } } for(i=0; i<=m-1; i++) { for(j=ae_minint(i, n-1, _state)+1; j<=n-1; j++) { *lqerrors = *lqerrors||ae_fp_neq(l.ptr.pp_double[i][j],(double)(0)); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &q.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } *lqerrors = *lqerrors||ae_fp_greater_eq(ae_fabs(v, _state),threshold); } } /* * Test for other errors */ k = 1+ae_randominteger(n, _state); rmatrixlqunpackq(&b, m, n, &taub, k, &q2, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { *lqerrors = *lqerrors||ae_fp_greater(ae_fabs(q2.ptr.pp_double[i][j]-q.ptr.pp_double[i][j], _state),10*ae_machineepsilon); } } ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testclqproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* lqerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix b; ae_vector taub; ae_matrix q; ae_matrix l; ae_matrix q2; ae_complex v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_vector_init(&taub, 0, DT_COMPLEX, _state); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&l, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&q2, 0, 0, DT_COMPLEX, _state); /* * Test decompose-and-unpack error */ testortfacunit_cmatrixmakeacopy(a, m, n, &b, _state); cmatrixlq(&b, m, n, &taub, _state); cmatrixlqunpackq(&b, m, n, &taub, n, &q, _state); cmatrixlqunpackl(&b, m, n, &l, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&l.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[0][j], q.stride, "N", ae_v_len(0,n-1)); *lqerrors = *lqerrors||ae_fp_greater_eq(ae_c_abs(ae_c_sub(v,a->ptr.pp_complex[i][j]), _state),threshold); } } for(i=0; i<=m-1; i++) { for(j=ae_minint(i, n-1, _state)+1; j<=n-1; j++) { *lqerrors = *lqerrors||ae_c_neq_d(l.ptr.pp_complex[i][j],(double)(0)); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } *lqerrors = *lqerrors||ae_fp_greater_eq(ae_c_abs(v, _state),threshold); } } /* * Test for other errors */ k = 1+ae_randominteger(n, _state); cmatrixlqunpackq(&b, m, n, &taub, k, &q2, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { *lqerrors = *lqerrors||ae_fp_greater(ae_c_abs(ae_c_sub(q2.ptr.pp_complex[i][j],q.ptr.pp_complex[i][j]), _state),10*ae_machineepsilon); } } ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testrbdproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* bderrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix t; ae_matrix pt; ae_matrix q; ae_matrix r; ae_matrix bd; ae_matrix x; ae_matrix r1; ae_matrix r2; ae_vector taup; ae_vector tauq; ae_vector d; ae_vector e; ae_bool up; double v; ae_int_t mtsize; ae_frame_make(_state, &_frame_block); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_matrix_init(&pt, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&r, 0, 0, DT_REAL, _state); ae_matrix_init(&bd, 0, 0, DT_REAL, _state); ae_matrix_init(&x, 0, 0, DT_REAL, _state); ae_matrix_init(&r1, 0, 0, DT_REAL, _state); ae_matrix_init(&r2, 0, 0, DT_REAL, _state); ae_vector_init(&taup, 0, DT_REAL, _state); ae_vector_init(&tauq, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); /* * Bidiagonal decomposition error */ testortfacunit_rmatrixmakeacopy(a, m, n, &t, _state); rmatrixbd(&t, m, n, &tauq, &taup, _state); rmatrixbdunpackq(&t, m, n, &tauq, m, &q, _state); rmatrixbdunpackpt(&t, m, n, &taup, n, &pt, _state); rmatrixbdunpackdiagonals(&t, m, n, &up, &d, &e, _state); ae_matrix_set_length(&bd, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { bd.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=ae_minint(m, n, _state)-1; i++) { bd.ptr.pp_double[i][i] = d.ptr.p_double[i]; } if( up ) { for(i=0; i<=ae_minint(m, n, _state)-2; i++) { bd.ptr.pp_double[i][i+1] = e.ptr.p_double[i]; } } else { for(i=0; i<=ae_minint(m, n, _state)-2; i++) { bd.ptr.pp_double[i+1][i] = e.ptr.p_double[i]; } } ae_matrix_set_length(&r, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &bd.ptr.pp_double[0][j], bd.stride, ae_v_len(0,m-1)); r.ptr.pp_double[i][j] = v; } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&r.ptr.pp_double[i][0], 1, &pt.ptr.pp_double[0][j], pt.stride, ae_v_len(0,n-1)); *bderrors = *bderrors||ae_fp_greater(ae_fabs(v-a->ptr.pp_double[i][j], _state),threshold); } } /* * Orthogonality test for Q/PT */ for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[0][i], q.stride, &q.ptr.pp_double[0][j], q.stride, ae_v_len(0,m-1)); if( i==j ) { *bderrors = *bderrors||ae_fp_greater(ae_fabs(v-1, _state),threshold); } else { *bderrors = *bderrors||ae_fp_greater(ae_fabs(v, _state),threshold); } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&pt.ptr.pp_double[i][0], 1, &pt.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { *bderrors = *bderrors||ae_fp_greater(ae_fabs(v-1, _state),threshold); } else { *bderrors = *bderrors||ae_fp_greater(ae_fabs(v, _state),threshold); } } } /* * Partial unpacking test */ k = 1+ae_randominteger(m, _state); rmatrixbdunpackq(&t, m, n, &tauq, k, &r, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=k-1; j++) { *bderrors = *bderrors||ae_fp_greater(ae_fabs(r.ptr.pp_double[i][j]-q.ptr.pp_double[i][j], _state),10*ae_machineepsilon); } } k = 1+ae_randominteger(n, _state); rmatrixbdunpackpt(&t, m, n, &taup, k, &r, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { *bderrors = *bderrors||ae_fp_neq(r.ptr.pp_double[i][j]-pt.ptr.pp_double[i][j],(double)(0)); } } /* * Multiplication test */ ae_matrix_set_length(&x, ae_maxint(m, n, _state)-1+1, ae_maxint(m, n, _state)-1+1, _state); ae_matrix_set_length(&r, ae_maxint(m, n, _state)-1+1, ae_maxint(m, n, _state)-1+1, _state); ae_matrix_set_length(&r1, ae_maxint(m, n, _state)-1+1, ae_maxint(m, n, _state)-1+1, _state); ae_matrix_set_length(&r2, ae_maxint(m, n, _state)-1+1, ae_maxint(m, n, _state)-1+1, _state); for(i=0; i<=ae_maxint(m, n, _state)-1; i++) { for(j=0; j<=ae_maxint(m, n, _state)-1; j++) { x.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } mtsize = 1+ae_randominteger(ae_maxint(m, n, _state), _state); testortfacunit_rmatrixmakeacopy(&x, mtsize, m, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&r, 0, mtsize-1, 0, m-1, ae_false, &q, 0, m-1, 0, m-1, ae_false, &r1, 0, mtsize-1, 0, m-1, _state); testortfacunit_rmatrixmakeacopy(&x, mtsize, m, &r2, _state); rmatrixbdmultiplybyq(&t, m, n, &tauq, &r2, mtsize, m, ae_true, ae_false, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, mtsize, m, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, mtsize, m, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&r, 0, mtsize-1, 0, m-1, ae_false, &q, 0, m-1, 0, m-1, ae_true, &r1, 0, mtsize-1, 0, m-1, _state); testortfacunit_rmatrixmakeacopy(&x, mtsize, m, &r2, _state); rmatrixbdmultiplybyq(&t, m, n, &tauq, &r2, mtsize, m, ae_true, ae_true, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, mtsize, m, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, m, mtsize, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&q, 0, m-1, 0, m-1, ae_false, &r, 0, m-1, 0, mtsize-1, ae_false, &r1, 0, m-1, 0, mtsize-1, _state); testortfacunit_rmatrixmakeacopy(&x, m, mtsize, &r2, _state); rmatrixbdmultiplybyq(&t, m, n, &tauq, &r2, m, mtsize, ae_false, ae_false, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, m, mtsize, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, m, mtsize, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&q, 0, m-1, 0, m-1, ae_true, &r, 0, m-1, 0, mtsize-1, ae_false, &r1, 0, m-1, 0, mtsize-1, _state); testortfacunit_rmatrixmakeacopy(&x, m, mtsize, &r2, _state); rmatrixbdmultiplybyq(&t, m, n, &tauq, &r2, m, mtsize, ae_false, ae_true, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, m, mtsize, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, mtsize, n, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&r, 0, mtsize-1, 0, n-1, ae_false, &pt, 0, n-1, 0, n-1, ae_true, &r1, 0, mtsize-1, 0, n-1, _state); testortfacunit_rmatrixmakeacopy(&x, mtsize, n, &r2, _state); rmatrixbdmultiplybyp(&t, m, n, &taup, &r2, mtsize, n, ae_true, ae_false, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, mtsize, n, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, mtsize, n, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&r, 0, mtsize-1, 0, n-1, ae_false, &pt, 0, n-1, 0, n-1, ae_false, &r1, 0, mtsize-1, 0, n-1, _state); testortfacunit_rmatrixmakeacopy(&x, mtsize, n, &r2, _state); rmatrixbdmultiplybyp(&t, m, n, &taup, &r2, mtsize, n, ae_true, ae_true, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, mtsize, n, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, n, mtsize, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&pt, 0, n-1, 0, n-1, ae_true, &r, 0, n-1, 0, mtsize-1, ae_false, &r1, 0, n-1, 0, mtsize-1, _state); testortfacunit_rmatrixmakeacopy(&x, n, mtsize, &r2, _state); rmatrixbdmultiplybyp(&t, m, n, &taup, &r2, n, mtsize, ae_false, ae_false, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, n, mtsize, _state),threshold); testortfacunit_rmatrixmakeacopy(&x, n, mtsize, &r, _state); testortfacunit_internalmatrixmatrixmultiply(&pt, 0, n-1, 0, n-1, ae_false, &r, 0, n-1, 0, mtsize-1, ae_false, &r1, 0, n-1, 0, mtsize-1, _state); testortfacunit_rmatrixmakeacopy(&x, n, mtsize, &r2, _state); rmatrixbdmultiplybyp(&t, m, n, &taup, &r2, n, mtsize, ae_false, ae_true, _state); *bderrors = *bderrors||ae_fp_greater(testortfacunit_rmatrixdiff(&r1, &r2, n, mtsize, _state),threshold); ae_frame_leave(_state); } /************************************************************************* Problem testing *************************************************************************/ static void testortfacunit_testrhessproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* hesserrors, ae_state *_state) { ae_frame _frame_block; ae_matrix b; ae_matrix h; ae_matrix q; ae_matrix t1; ae_matrix t2; ae_vector tau; ae_int_t i; ae_int_t j; double v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_init(&h, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&t1, 0, 0, DT_REAL, _state); ae_matrix_init(&t2, 0, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_REAL, _state); testortfacunit_rmatrixmakeacopy(a, n, n, &b, _state); /* * Decomposition */ rmatrixhessenberg(&b, n, &tau, _state); rmatrixhessenbergunpackq(&b, n, &tau, &q, _state); rmatrixhessenbergunpackh(&b, n, &h, _state); /* * Matrix properties */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[0][i], q.stride, &q.ptr.pp_double[0][j], q.stride, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } *hesserrors = *hesserrors||ae_fp_greater(ae_fabs(v, _state),threshold); } } for(i=0; i<=n-1; i++) { for(j=0; j<=i-2; j++) { *hesserrors = *hesserrors||ae_fp_neq(h.ptr.pp_double[i][j],(double)(0)); } } /* * Decomposition error */ ae_matrix_set_length(&t1, n, n, _state); ae_matrix_set_length(&t2, n, n, _state); testortfacunit_internalmatrixmatrixmultiply(&q, 0, n-1, 0, n-1, ae_false, &h, 0, n-1, 0, n-1, ae_false, &t1, 0, n-1, 0, n-1, _state); testortfacunit_internalmatrixmatrixmultiply(&t1, 0, n-1, 0, n-1, ae_false, &q, 0, n-1, 0, n-1, ae_true, &t2, 0, n-1, 0, n-1, _state); *hesserrors = *hesserrors||ae_fp_greater(testortfacunit_rmatrixdiff(&t2, a, n, n, _state),threshold); ae_frame_leave(_state); } /************************************************************************* Tridiagonal tester *************************************************************************/ static void testortfacunit_testrtdproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* tderrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix ua; ae_matrix la; ae_matrix t; ae_matrix q; ae_matrix t2; ae_matrix t3; ae_vector tau; ae_vector d; ae_vector e; double v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ua, 0, 0, DT_REAL, _state); ae_matrix_init(&la, 0, 0, DT_REAL, _state); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&t2, 0, 0, DT_REAL, _state); ae_matrix_init(&t3, 0, 0, DT_REAL, _state); ae_vector_init(&tau, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_set_length(&ua, n-1+1, n-1+1, _state); ae_matrix_set_length(&la, n-1+1, n-1+1, _state); ae_matrix_set_length(&t, n-1+1, n-1+1, _state); ae_matrix_set_length(&q, n-1+1, n-1+1, _state); ae_matrix_set_length(&t2, n-1+1, n-1+1, _state); ae_matrix_set_length(&t3, n-1+1, n-1+1, _state); /* * fill */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ua.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { ua.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { la.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { la.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } /* * Test 2tridiagonal: upper */ smatrixtd(&ua, n, ae_true, &tau, &d, &e, _state); smatrixtdunpackq(&ua, n, ae_true, &tau, &q, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { t.ptr.pp_double[i][i] = d.ptr.p_double[i]; } for(i=0; i<=n-2; i++) { t.ptr.pp_double[i][i+1] = e.ptr.p_double[i]; t.ptr.pp_double[i+1][i] = e.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[0][i], q.stride, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); t2.ptr.pp_double[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&t2.ptr.pp_double[i][0], 1, &q.ptr.pp_double[0][j], q.stride, ae_v_len(0,n-1)); t3.ptr.pp_double[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *tderrors = *tderrors||ae_fp_greater(ae_fabs(t3.ptr.pp_double[i][j]-t.ptr.pp_double[i][j], _state),threshold); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &q.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } *tderrors = *tderrors||ae_fp_greater(ae_fabs(v, _state),threshold); } } /* * Test 2tridiagonal: lower */ smatrixtd(&la, n, ae_false, &tau, &d, &e, _state); smatrixtdunpackq(&la, n, ae_false, &tau, &q, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { t.ptr.pp_double[i][i] = d.ptr.p_double[i]; } for(i=0; i<=n-2; i++) { t.ptr.pp_double[i][i+1] = e.ptr.p_double[i]; t.ptr.pp_double[i+1][i] = e.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[0][i], q.stride, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); t2.ptr.pp_double[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&t2.ptr.pp_double[i][0], 1, &q.ptr.pp_double[0][j], q.stride, ae_v_len(0,n-1)); t3.ptr.pp_double[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *tderrors = *tderrors||ae_fp_greater(ae_fabs(t3.ptr.pp_double[i][j]-t.ptr.pp_double[i][j], _state),threshold); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &q.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } *tderrors = *tderrors||ae_fp_greater(ae_fabs(v, _state),threshold); } } ae_frame_leave(_state); } /************************************************************************* Hermitian problem tester *************************************************************************/ static void testortfacunit_testctdproblem(/* Complex */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* tderrors, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_matrix ua; ae_matrix la; ae_matrix t; ae_matrix q; ae_matrix t2; ae_matrix t3; ae_vector tau; ae_vector d; ae_vector e; ae_complex v; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ua, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&la, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&t, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&t2, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&t3, 0, 0, DT_COMPLEX, _state); ae_vector_init(&tau, 0, DT_COMPLEX, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_set_length(&ua, n-1+1, n-1+1, _state); ae_matrix_set_length(&la, n-1+1, n-1+1, _state); ae_matrix_set_length(&t, n-1+1, n-1+1, _state); ae_matrix_set_length(&q, n-1+1, n-1+1, _state); ae_matrix_set_length(&t2, n-1+1, n-1+1, _state); ae_matrix_set_length(&t3, n-1+1, n-1+1, _state); /* * fill */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ua.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { ua.ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { la.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { la.ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } /* * Test 2tridiagonal: upper */ hmatrixtd(&ua, n, ae_true, &tau, &d, &e, _state); hmatrixtdunpackq(&ua, n, ae_true, &tau, &q, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=n-1; i++) { t.ptr.pp_complex[i][i] = ae_complex_from_d(d.ptr.p_double[i]); } for(i=0; i<=n-2; i++) { t.ptr.pp_complex[i][i+1] = ae_complex_from_d(e.ptr.p_double[i]); t.ptr.pp_complex[i+1][i] = ae_complex_from_d(e.ptr.p_double[i]); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[0][i], q.stride, "Conj", &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,n-1)); t2.ptr.pp_complex[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&t2.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[0][j], q.stride, "N", ae_v_len(0,n-1)); t3.ptr.pp_complex[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *tderrors = *tderrors||ae_fp_greater(ae_c_abs(ae_c_sub(t3.ptr.pp_complex[i][j],t.ptr.pp_complex[i][j]), _state),threshold); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } *tderrors = *tderrors||ae_fp_greater(ae_c_abs(v, _state),threshold); } } /* * Test 2tridiagonal: lower */ hmatrixtd(&la, n, ae_false, &tau, &d, &e, _state); hmatrixtdunpackq(&la, n, ae_false, &tau, &q, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=n-1; i++) { t.ptr.pp_complex[i][i] = ae_complex_from_d(d.ptr.p_double[i]); } for(i=0; i<=n-2; i++) { t.ptr.pp_complex[i][i+1] = ae_complex_from_d(e.ptr.p_double[i]); t.ptr.pp_complex[i+1][i] = ae_complex_from_d(e.ptr.p_double[i]); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[0][i], q.stride, "Conj", &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,n-1)); t2.ptr.pp_complex[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&t2.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[0][j], q.stride, "N", ae_v_len(0,n-1)); t3.ptr.pp_complex[i][j] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *tderrors = *tderrors||ae_fp_greater(ae_c_abs(ae_c_sub(t3.ptr.pp_complex[i][j],t.ptr.pp_complex[i][j]), _state),threshold); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&q.ptr.pp_complex[i][0], 1, "N", &q.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } *tderrors = *tderrors||ae_fp_greater(ae_c_abs(v, _state),threshold); } } ae_frame_leave(_state); } static void testbdsvdunit_fillidentity(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); static void testbdsvdunit_fillsparsede(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, double sparcity, ae_state *_state); static void testbdsvdunit_getbdsvderror(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, /* Real */ ae_matrix* c, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* materr, double* orterr, ae_bool* wsorted, ae_state *_state); static void testbdsvdunit_checksvdmultiplication(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, /* Real */ ae_matrix* c, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* err, ae_state *_state); static void testbdsvdunit_testbdsvdproblem(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, double* materr, double* orterr, ae_bool* wsorted, ae_bool* wfailed, ae_int_t* failcount, ae_int_t* succcount, ae_state *_state); /************************************************************************* Testing bidiagonal SVD decomposition subroutine *************************************************************************/ ae_bool testbdsvd(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_vector d; ae_vector e; ae_matrix mempty; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t pass; ae_bool waserrors; ae_bool wsorted; ae_bool wfailed; double materr; double orterr; double threshold; double failr; ae_int_t failcount; ae_int_t succcount; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_matrix_init(&mempty, 0, 0, DT_REAL, _state); failcount = 0; succcount = 0; materr = (double)(0); orterr = (double)(0); wsorted = ae_true; wfailed = ae_false; waserrors = ae_false; maxn = 15; threshold = 5*100*ae_machineepsilon; ae_vector_set_length(&d, maxn-1+1, _state); ae_vector_set_length(&e, maxn-2+1, _state); /* * special case: zero divide matrix * unfixed LAPACK routine should fail on this problem */ n = 7; d.ptr.p_double[0] = -6.96462904751731892700e-01; d.ptr.p_double[1] = 0.00000000000000000000e+00; d.ptr.p_double[2] = -5.73827770385971991400e-01; d.ptr.p_double[3] = -6.62562624399371191700e-01; d.ptr.p_double[4] = 5.82737148001782223600e-01; d.ptr.p_double[5] = 3.84825263580925003300e-01; d.ptr.p_double[6] = 9.84087420830525472200e-01; e.ptr.p_double[0] = -7.30307931760612871800e-02; e.ptr.p_double[1] = -2.30079042939542843800e-01; e.ptr.p_double[2] = -6.87824621739351216300e-01; e.ptr.p_double[3] = -1.77306437707837570600e-02; e.ptr.p_double[4] = 1.78285126526551632000e-15; e.ptr.p_double[5] = -4.89434737751289969400e-02; rmatrixbdsvd(&d, &e, n, ae_true, ae_false, &mempty, 0, &mempty, 0, &mempty, 0, _state); /* * zero matrix, several cases */ for(i=0; i<=maxn-1; i++) { d.ptr.p_double[i] = (double)(0); } for(i=0; i<=maxn-2; i++) { e.ptr.p_double[i] = (double)(0); } for(n=1; n<=maxn; n++) { testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); } /* * Dense matrix */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=10; pass++) { for(i=0; i<=maxn-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=maxn-2; i++) { e.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); } } /* * Sparse matrices, very sparse matrices, incredible sparse matrices */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=10; pass++) { testbdsvdunit_fillsparsede(&d, &e, n, 0.5, _state); testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); testbdsvdunit_fillsparsede(&d, &e, n, 0.8, _state); testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); testbdsvdunit_fillsparsede(&d, &e, n, 0.9, _state); testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); testbdsvdunit_fillsparsede(&d, &e, n, 0.95, _state); testbdsvdunit_testbdsvdproblem(&d, &e, n, &materr, &orterr, &wsorted, &wfailed, &failcount, &succcount, _state); } } /* * report */ failr = (double)failcount/(double)(succcount+failcount); waserrors = ((wfailed||ae_fp_greater(materr,threshold))||ae_fp_greater(orterr,threshold))||!wsorted; if( !silent ) { printf("TESTING BIDIAGONAL SVD DECOMPOSITION\n"); printf("SVD decomposition error: %5.3e\n", (double)(materr)); printf("SVD orthogonality error: %5.3e\n", (double)(orterr)); printf("Singular values order: "); if( wsorted ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("Always converged: "); if( !wfailed ) { printf("YES\n"); } else { printf("NO\n"); printf("Fail ratio: %5.3f\n", (double)(failr)); } printf("Threshold: %5.3e\n", (double)(threshold)); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testbdsvd(ae_bool silent, ae_state *_state) { return testbdsvd(silent, _state); } static void testbdsvdunit_fillidentity(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_set_length(a, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a->ptr.pp_double[i][j] = (double)(1); } else { a->ptr.pp_double[i][j] = (double)(0); } } } } static void testbdsvdunit_fillsparsede(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_vector_set_length(d, n-1+1, _state); ae_vector_set_length(e, ae_maxint(0, n-2, _state)+1, _state); for(i=0; i<=n-1; i++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { d->ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { d->ptr.p_double[i] = (double)(0); } } for(i=0; i<=n-2; i++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { e->ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { e->ptr.p_double[i] = (double)(0); } } } static void testbdsvdunit_getbdsvderror(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, /* Real */ ae_matrix* c, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* materr, double* orterr, ae_bool* wsorted, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double locerr; double sm; /* * decomposition error */ locerr = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { sm = (double)(0); for(k=0; k<=n-1; k++) { sm = sm+w->ptr.p_double[k]*u->ptr.pp_double[i][k]*vt->ptr.pp_double[k][j]; } if( isupper ) { if( i==j ) { locerr = ae_maxreal(locerr, ae_fabs(d->ptr.p_double[i]-sm, _state), _state); } else { if( i==j-1 ) { locerr = ae_maxreal(locerr, ae_fabs(e->ptr.p_double[i]-sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } } } else { if( i==j ) { locerr = ae_maxreal(locerr, ae_fabs(d->ptr.p_double[i]-sm, _state), _state); } else { if( i-1==j ) { locerr = ae_maxreal(locerr, ae_fabs(e->ptr.p_double[j]-sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } } } } } *materr = ae_maxreal(*materr, locerr, _state); /* * check for C = U' * we consider it as decomposition error */ locerr = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { locerr = ae_maxreal(locerr, ae_fabs(u->ptr.pp_double[i][j]-c->ptr.pp_double[j][i], _state), _state); } } *materr = ae_maxreal(*materr, locerr, _state); /* * orthogonality error */ locerr = (double)(0); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { sm = ae_v_dotproduct(&u->ptr.pp_double[0][i], u->stride, &u->ptr.pp_double[0][j], u->stride, ae_v_len(0,n-1)); if( i!=j ) { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm-1, _state), _state); } sm = ae_v_dotproduct(&vt->ptr.pp_double[i][0], 1, &vt->ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i!=j ) { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm-1, _state), _state); } } } *orterr = ae_maxreal(*orterr, locerr, _state); /* * values order error */ for(i=1; i<=n-1; i++) { if( ae_fp_greater(w->ptr.p_double[i],w->ptr.p_double[i-1]) ) { *wsorted = ae_false; } } } static void testbdsvdunit_checksvdmultiplication(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool isupper, /* Real */ ae_matrix* u, /* Real */ ae_matrix* c, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* err, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_vector wt; ae_matrix u2; ae_matrix c2; ae_matrix vt2; ae_matrix u1; ae_matrix c1; ae_matrix vt1; ae_int_t nru; ae_int_t ncc; ae_int_t ncvt; ae_int_t pass; hqrndstate rs; double v; ae_frame_make(_state, &_frame_block); ae_vector_init(&wt, 0, DT_REAL, _state); ae_matrix_init(&u2, 0, 0, DT_REAL, _state); ae_matrix_init(&c2, 0, 0, DT_REAL, _state); ae_matrix_init(&vt2, 0, 0, DT_REAL, _state); ae_matrix_init(&u1, 0, 0, DT_REAL, _state); ae_matrix_init(&c1, 0, 0, DT_REAL, _state); ae_matrix_init(&vt1, 0, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); ae_vector_set_length(&wt, n, _state); /* * Perform nonsquare SVD */ for(pass=1; pass<=20; pass++) { /* * Problem size */ nru = hqrnduniformi(&rs, 2*n, _state); ncc = hqrnduniformi(&rs, 2*n, _state); ncvt = hqrnduniformi(&rs, 2*n, _state); /* * Reference matrices (copy 1) and working matrices (copy 2) */ for(i=0; i<=n-1; i++) { wt.ptr.p_double[i] = d->ptr.p_double[i]; } if( nru>0 ) { /* * init U1/U2 */ ae_matrix_set_length(&u1, nru, n, _state); ae_matrix_set_length(&u2, nru, n, _state); for(i=0; i<=u1.rows-1; i++) { for(j=0; j<=u1.cols-1; j++) { u1.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; u2.ptr.pp_double[i][j] = u1.ptr.pp_double[i][j]; } } } else { /* * Set U1/U2 to 1x1 matrices; working with 1x1 matrices allows * to test correctness of code which passes them to MKL. */ ae_matrix_set_length(&u1, 1, 1, _state); ae_matrix_set_length(&u2, 1, 1, _state); } if( ncc>0 ) { ae_matrix_set_length(&c1, n, ncc, _state); ae_matrix_set_length(&c2, n, ncc, _state); for(i=0; i<=c1.rows-1; i++) { for(j=0; j<=c1.cols-1; j++) { c1.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; c2.ptr.pp_double[i][j] = c1.ptr.pp_double[i][j]; } } } else { /* * Set C1/C1 to 1x1 matrices; working with 1x1 matrices allows * to test correctness of code which passes them to MKL. */ ae_matrix_set_length(&c1, 1, 1, _state); ae_matrix_set_length(&c2, 1, 1, _state); } if( ncvt>0 ) { ae_matrix_set_length(&vt1, n, ncvt, _state); ae_matrix_set_length(&vt2, n, ncvt, _state); for(i=0; i<=vt1.rows-1; i++) { for(j=0; j<=vt1.cols-1; j++) { vt1.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; vt2.ptr.pp_double[i][j] = vt1.ptr.pp_double[i][j]; } } } else { /* * Set VT1/VT1 to 1x1 matrices; working with 1x1 matrices allows * to test correctness of code which passes them to MKL. */ ae_matrix_set_length(&vt1, 1, 1, _state); ae_matrix_set_length(&vt2, 1, 1, _state); } /* * SVD with non-square U/C/VT */ if( !rmatrixbdsvd(&wt, e, n, isupper, ae_fp_greater(hqrnduniformr(&rs, _state),(double)(0)), &u2, nru, &c2, ncc, &vt2, ncvt, _state) ) { *err = 1.0; ae_frame_leave(_state); return; } for(i=0; i<=nru-1; i++) { for(j=0; j<=u2.cols-1; j++) { v = ae_v_dotproduct(&u1.ptr.pp_double[i][0], 1, &u->ptr.pp_double[0][j], u->stride, ae_v_len(0,n-1)); *err = ae_maxreal(*err, ae_fabs(v-u2.ptr.pp_double[i][j], _state), _state); } } for(i=0; i<=c2.rows-1; i++) { for(j=0; j<=ncc-1; j++) { v = ae_v_dotproduct(&c->ptr.pp_double[i][0], 1, &c1.ptr.pp_double[0][j], c1.stride, ae_v_len(0,n-1)); *err = ae_maxreal(*err, ae_fabs(v-c2.ptr.pp_double[i][j], _state), _state); } } for(i=0; i<=vt2.rows-1; i++) { for(j=0; j<=ncvt-1; j++) { v = ae_v_dotproduct(&vt->ptr.pp_double[i][0], 1, &vt1.ptr.pp_double[0][j], vt1.stride, ae_v_len(0,n-1)); *err = ae_maxreal(*err, ae_fabs(v-vt2.ptr.pp_double[i][j], _state), _state); } } } ae_frame_leave(_state); } static void testbdsvdunit_testbdsvdproblem(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, double* materr, double* orterr, ae_bool* wsorted, ae_bool* wfailed, ae_int_t* failcount, ae_int_t* succcount, ae_state *_state) { ae_frame _frame_block; ae_matrix u; ae_matrix vt; ae_matrix c; ae_vector w; ae_int_t i; double mx; ae_frame_make(_state, &_frame_block); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); mx = (double)(0); for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(d->ptr.p_double[i], _state),mx) ) { mx = ae_fabs(d->ptr.p_double[i], _state); } } for(i=0; i<=n-2; i++) { if( ae_fp_greater(ae_fabs(e->ptr.p_double[i], _state),mx) ) { mx = ae_fabs(e->ptr.p_double[i], _state); } } if( ae_fp_eq(mx,(double)(0)) ) { mx = (double)(1); } /* * Upper BDSVD tests */ ae_vector_set_length(&w, n-1+1, _state); testbdsvdunit_fillidentity(&u, n, _state); testbdsvdunit_fillidentity(&vt, n, _state); testbdsvdunit_fillidentity(&c, n, _state); for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = d->ptr.p_double[i]; } if( !rmatrixbdsvd(&w, e, n, ae_true, ae_false, &u, n, &c, n, &vt, n, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } testbdsvdunit_getbdsvderror(d, e, n, ae_true, &u, &c, &w, &vt, materr, orterr, wsorted, _state); testbdsvdunit_checksvdmultiplication(d, e, n, ae_true, &u, &c, &w, &vt, materr, _state); testbdsvdunit_fillidentity(&u, n, _state); testbdsvdunit_fillidentity(&vt, n, _state); testbdsvdunit_fillidentity(&c, n, _state); for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = d->ptr.p_double[i]; } if( !rmatrixbdsvd(&w, e, n, ae_true, ae_true, &u, n, &c, n, &vt, n, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } testbdsvdunit_getbdsvderror(d, e, n, ae_true, &u, &c, &w, &vt, materr, orterr, wsorted, _state); testbdsvdunit_checksvdmultiplication(d, e, n, ae_true, &u, &c, &w, &vt, materr, _state); /* * Lower BDSVD tests */ ae_vector_set_length(&w, n-1+1, _state); testbdsvdunit_fillidentity(&u, n, _state); testbdsvdunit_fillidentity(&vt, n, _state); testbdsvdunit_fillidentity(&c, n, _state); for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = d->ptr.p_double[i]; } if( !rmatrixbdsvd(&w, e, n, ae_false, ae_false, &u, n, &c, n, &vt, n, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } testbdsvdunit_getbdsvderror(d, e, n, ae_false, &u, &c, &w, &vt, materr, orterr, wsorted, _state); testbdsvdunit_checksvdmultiplication(d, e, n, ae_false, &u, &c, &w, &vt, materr, _state); testbdsvdunit_fillidentity(&u, n, _state); testbdsvdunit_fillidentity(&vt, n, _state); testbdsvdunit_fillidentity(&c, n, _state); for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = d->ptr.p_double[i]; } if( !rmatrixbdsvd(&w, e, n, ae_false, ae_true, &u, n, &c, n, &vt, n, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } testbdsvdunit_getbdsvderror(d, e, n, ae_false, &u, &c, &w, &vt, materr, orterr, wsorted, _state); testbdsvdunit_checksvdmultiplication(d, e, n, ae_false, &u, &c, &w, &vt, materr, _state); /* * update counter */ *succcount = *succcount+1; ae_frame_leave(_state); } static void testsvdunit_fillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state); static void testsvdunit_getsvderror(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* u, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* materr, double* orterr, ae_bool* wsorted, ae_state *_state); static void testsvdunit_testsvdproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double* materr, double* orterr, double* othererr, ae_bool* wsorted, ae_bool* wfailed, ae_int_t* failcount, ae_int_t* succcount, ae_state *_state); /************************************************************************* Testing SVD decomposition subroutine *************************************************************************/ ae_bool testsvd(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_int_t m; ae_int_t n; ae_int_t maxmn; ae_int_t i; ae_int_t j; ae_int_t gpass; ae_int_t pass; ae_bool waserrors; ae_bool wsorted; ae_bool wfailed; double materr; double orterr; double othererr; double threshold; double failr; ae_int_t failcount; ae_int_t succcount; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); failcount = 0; succcount = 0; materr = (double)(0); orterr = (double)(0); othererr = (double)(0); wsorted = ae_true; wfailed = ae_false; waserrors = ae_false; maxmn = 30; threshold = 5*100*ae_machineepsilon; ae_matrix_set_length(&a, maxmn-1+1, maxmn-1+1, _state); /* * TODO: div by zero fail, convergence fail */ for(gpass=1; gpass<=1; gpass++) { /* * zero matrix, several cases */ for(i=0; i<=maxmn-1; i++) { for(j=0; j<=maxmn-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=1; i<=ae_minint(5, maxmn, _state); i++) { for(j=1; j<=ae_minint(5, maxmn, _state); j++) { testsvdunit_testsvdproblem(&a, i, j, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); } } /* * Long dense matrix */ for(i=0; i<=maxmn-1; i++) { for(j=0; j<=ae_minint(5, maxmn, _state)-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } for(i=1; i<=maxmn; i++) { for(j=1; j<=ae_minint(5, maxmn, _state); j++) { testsvdunit_testsvdproblem(&a, i, j, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); } } for(i=0; i<=ae_minint(5, maxmn, _state)-1; i++) { for(j=0; j<=maxmn-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } for(i=1; i<=ae_minint(5, maxmn, _state); i++) { for(j=1; j<=maxmn; j++) { testsvdunit_testsvdproblem(&a, i, j, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); } } /* * Dense matrices */ for(m=1; m<=ae_minint(10, maxmn, _state); m++) { for(n=1; n<=ae_minint(10, maxmn, _state); n++) { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } testsvdunit_testsvdproblem(&a, m, n, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); } } /* * Sparse matrices, very sparse matrices, incredible sparse matrices */ for(m=1; m<=10; m++) { for(n=1; n<=10; n++) { for(pass=1; pass<=2; pass++) { testsvdunit_fillsparsea(&a, m, n, 0.8, _state); testsvdunit_testsvdproblem(&a, m, n, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); testsvdunit_fillsparsea(&a, m, n, 0.9, _state); testsvdunit_testsvdproblem(&a, m, n, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); testsvdunit_fillsparsea(&a, m, n, 0.95, _state); testsvdunit_testsvdproblem(&a, m, n, &materr, &orterr, &othererr, &wsorted, &wfailed, &failcount, &succcount, _state); } } } } /* * report */ failr = (double)failcount/(double)(succcount+failcount); waserrors = (((wfailed||ae_fp_greater(materr,threshold))||ae_fp_greater(orterr,threshold))||ae_fp_greater(othererr,threshold))||!wsorted; if( !silent ) { printf("TESTING SVD DECOMPOSITION\n"); printf("SVD decomposition error: %5.3e\n", (double)(materr)); printf("SVD orthogonality error: %5.3e\n", (double)(orterr)); printf("SVD with different parameters error: %5.3e\n", (double)(othererr)); printf("Singular values order: "); if( wsorted ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("Always converged: "); if( !wfailed ) { printf("YES\n"); } else { printf("NO\n"); printf("Fail ratio: %5.3f\n", (double)(failr)); } printf("Threshold: %5.3e\n", (double)(threshold)); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsvd(ae_bool silent, ae_state *_state) { return testsvd(silent, _state); } static void testsvdunit_fillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_double[i][j] = (double)(0); } } } } static void testsvdunit_getsvderror(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* u, /* Real */ ae_vector* w, /* Real */ ae_matrix* vt, double* materr, double* orterr, ae_bool* wsorted, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t minmn; double locerr; double sm; minmn = ae_minint(m, n, _state); /* * decomposition error */ locerr = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { sm = (double)(0); for(k=0; k<=minmn-1; k++) { sm = sm+w->ptr.p_double[k]*u->ptr.pp_double[i][k]*vt->ptr.pp_double[k][j]; } locerr = ae_maxreal(locerr, ae_fabs(a->ptr.pp_double[i][j]-sm, _state), _state); } } *materr = ae_maxreal(*materr, locerr, _state); /* * orthogonality error */ locerr = (double)(0); for(i=0; i<=minmn-1; i++) { for(j=i; j<=minmn-1; j++) { sm = ae_v_dotproduct(&u->ptr.pp_double[0][i], u->stride, &u->ptr.pp_double[0][j], u->stride, ae_v_len(0,m-1)); if( i!=j ) { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm-1, _state), _state); } sm = ae_v_dotproduct(&vt->ptr.pp_double[i][0], 1, &vt->ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i!=j ) { locerr = ae_maxreal(locerr, ae_fabs(sm, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(sm-1, _state), _state); } } } *orterr = ae_maxreal(*orterr, locerr, _state); /* * values order error */ for(i=1; i<=minmn-1; i++) { if( ae_fp_greater(w->ptr.p_double[i],w->ptr.p_double[i-1]) ) { *wsorted = ae_false; } } } static void testsvdunit_testsvdproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double* materr, double* orterr, double* othererr, ae_bool* wsorted, ae_bool* wfailed, ae_int_t* failcount, ae_int_t* succcount, ae_state *_state) { ae_frame _frame_block; ae_matrix u; ae_matrix vt; ae_matrix u2; ae_matrix vt2; ae_vector w; ae_vector w2; ae_int_t i; ae_int_t j; ae_int_t ujob; ae_int_t vtjob; ae_int_t memjob; ae_int_t ucheck; ae_int_t vtcheck; ae_frame_make(_state, &_frame_block); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_matrix_init(&u2, 0, 0, DT_REAL, _state); ae_matrix_init(&vt2, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); /* * Main SVD test */ if( !rmatrixsvd(a, m, n, 2, 2, 2, &w, &u, &vt, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } testsvdunit_getsvderror(a, m, n, &u, &w, &vt, materr, orterr, wsorted, _state); /* * Additional SVD tests */ for(ujob=0; ujob<=2; ujob++) { for(vtjob=0; vtjob<=2; vtjob++) { for(memjob=0; memjob<=2; memjob++) { if( !rmatrixsvd(a, m, n, ujob, vtjob, memjob, &w2, &u2, &vt2, _state) ) { *failcount = *failcount+1; *wfailed = ae_true; ae_frame_leave(_state); return; } ucheck = 0; if( ujob==1 ) { ucheck = ae_minint(m, n, _state); } if( ujob==2 ) { ucheck = m; } vtcheck = 0; if( vtjob==1 ) { vtcheck = ae_minint(m, n, _state); } if( vtjob==2 ) { vtcheck = n; } for(i=0; i<=m-1; i++) { for(j=0; j<=ucheck-1; j++) { *othererr = ae_maxreal(*othererr, ae_fabs(u.ptr.pp_double[i][j]-u2.ptr.pp_double[i][j], _state), _state); } } for(i=0; i<=vtcheck-1; i++) { for(j=0; j<=n-1; j++) { *othererr = ae_maxreal(*othererr, ae_fabs(vt.ptr.pp_double[i][j]-vt2.ptr.pp_double[i][j], _state), _state); } } for(i=0; i<=ae_minint(m, n, _state)-1; i++) { *othererr = ae_maxreal(*othererr, ae_fabs(w.ptr.p_double[i]-w2.ptr.p_double[i], _state), _state); } } } } /* * update counter */ *succcount = *succcount+1; ae_frame_leave(_state); } static void testlinregunit_generaterandomtask(double xl, double xr, ae_bool randomx, double ymin, double ymax, double smin, double smax, ae_int_t n, /* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_state *_state); static void testlinregunit_generatetask(double a, double b, double xl, double xr, ae_bool randomx, double smin, double smax, ae_int_t n, /* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_state *_state); static void testlinregunit_filltaskwithy(double a, double b, ae_int_t n, /* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_state *_state); static double testlinregunit_generatenormal(double mean, double sigma, ae_state *_state); static void testlinregunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state); static void testlinregunit_unsetlr(linearmodel* lr, ae_state *_state); ae_bool testlinreg(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double sigmathreshold; ae_int_t maxn; ae_int_t maxm; ae_int_t passcount; ae_int_t estpasscount; double threshold; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t tmpi; ae_int_t pass; ae_int_t epass; ae_int_t m; ae_int_t tasktype; ae_int_t modeltype; ae_int_t m1; ae_int_t m2; ae_int_t n1; ae_int_t n2; ae_int_t info; ae_int_t info2; ae_matrix xy; ae_matrix xy2; ae_vector s; ae_vector s2; ae_vector w2; ae_vector x; ae_vector ta; ae_vector tb; ae_vector tc; ae_vector xy0; ae_vector tmpweights; linearmodel w; linearmodel wt; linearmodel wt2; ae_vector x1; ae_vector x2; double y1; double y2; ae_bool allsame; double ea; double eb; double varatested; double varbtested; double a; double b; double vara; double varb; double a2; double b2; double covab; double corrab; double p; ae_int_t qcnt; ae_vector qtbl; ae_vector qvals; ae_vector qsigma; lrreport ar; lrreport ar2; double f; double fp; double fm; double v; double vv; double cvrmserror; double cvavgerror; double cvavgrelerror; double rmserror; double avgerror; double avgrelerror; ae_bool nondefect; double sinshift; double tasklevel; double noiselevel; double hstep; double sigma; double mean; double means; double stddev; double stddevs; ae_bool slcerrors; ae_bool slerrors; ae_bool grcoverrors; ae_bool gropterrors; ae_bool gresterrors; ae_bool grothererrors; ae_bool grconverrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&xy2, 0, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&s2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&ta, 0, DT_REAL, _state); ae_vector_init(&tb, 0, DT_REAL, _state); ae_vector_init(&tc, 0, DT_REAL, _state); ae_vector_init(&xy0, 0, DT_REAL, _state); ae_vector_init(&tmpweights, 0, DT_REAL, _state); _linearmodel_init(&w, _state); _linearmodel_init(&wt, _state); _linearmodel_init(&wt2, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&qtbl, 0, DT_REAL, _state); ae_vector_init(&qvals, 0, DT_REAL, _state); ae_vector_init(&qsigma, 0, DT_REAL, _state); _lrreport_init(&ar, _state); _lrreport_init(&ar2, _state); /* * Primary settings */ maxn = 40; maxm = 5; passcount = 3; estpasscount = 1000; sigmathreshold = (double)(7); threshold = 1000000*ae_machineepsilon; slerrors = ae_false; slcerrors = ae_false; grcoverrors = ae_false; gropterrors = ae_false; gresterrors = ae_false; grothererrors = ae_false; grconverrors = ae_false; waserrors = ae_false; /* * Quantiles table setup */ qcnt = 5; ae_vector_set_length(&qtbl, qcnt-1+1, _state); ae_vector_set_length(&qvals, qcnt-1+1, _state); ae_vector_set_length(&qsigma, qcnt-1+1, _state); qtbl.ptr.p_double[0] = 0.5; qtbl.ptr.p_double[1] = 0.25; qtbl.ptr.p_double[2] = 0.10; qtbl.ptr.p_double[3] = 0.05; qtbl.ptr.p_double[4] = 0.025; for(i=0; i<=qcnt-1; i++) { qsigma.ptr.p_double[i] = ae_sqrt(qtbl.ptr.p_double[i]*(1-qtbl.ptr.p_double[i])/estpasscount, _state); } /* * Other setup */ ae_vector_set_length(&ta, estpasscount-1+1, _state); ae_vector_set_length(&tb, estpasscount-1+1, _state); /* * Test straight line regression */ for(n=2; n<=maxn; n++) { /* * Fail/pass test */ testlinregunit_generaterandomtask((double)(-1), (double)(1), ae_false, (double)(-1), (double)(1), (double)(1), (double)(2), n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); slcerrors = slcerrors||info!=1; testlinregunit_generaterandomtask((double)(1), (double)(1), ae_false, (double)(-1), (double)(1), (double)(1), (double)(2), n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); slcerrors = slcerrors||info!=-3; testlinregunit_generaterandomtask((double)(-1), (double)(1), ae_false, (double)(-1), (double)(1), (double)(-1), (double)(-1), n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); slcerrors = slcerrors||info!=-2; testlinregunit_generaterandomtask((double)(-1), (double)(1), ae_false, (double)(-1), (double)(1), (double)(2), (double)(1), 2, &xy, &s, _state); lrlines(&xy, &s, 1, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); slcerrors = slcerrors||info!=-1; /* * Multipass tests */ for(pass=1; pass<=passcount; pass++) { /* * Test S variant against non-S variant */ ea = 2*ae_randomreal(_state)-1; eb = 2*ae_randomreal(_state)-1; testlinregunit_generatetask(ea, eb, -5*ae_randomreal(_state), 5*ae_randomreal(_state), ae_fp_greater(ae_randomreal(_state),0.5), (double)(1), (double)(1), n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); lrline(&xy, n, &info2, &a2, &b2, _state); if( info!=1||info2!=1 ) { slcerrors = ae_true; } else { slerrors = (slerrors||ae_fp_greater(ae_fabs(a-a2, _state),threshold))||ae_fp_greater(ae_fabs(b-b2, _state),threshold); } /* * Test for A/B * * Generate task with exact, non-perturbed y[i], * then make non-zero s[i] */ ea = 2*ae_randomreal(_state)-1; eb = 2*ae_randomreal(_state)-1; testlinregunit_generatetask(ea, eb, -5*ae_randomreal(_state), 5*ae_randomreal(_state), n>4, 0.0, 0.0, n, &xy, &s, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = 1+ae_randomreal(_state); } lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1 ) { slcerrors = ae_true; } else { slerrors = (slerrors||ae_fp_greater(ae_fabs(a-ea, _state),0.001))||ae_fp_greater(ae_fabs(b-eb, _state),0.001); } /* * Test for VarA, VarB, P (P is being tested only for N>2) */ for(i=0; i<=qcnt-1; i++) { qvals.ptr.p_double[i] = (double)(0); } ea = 2*ae_randomreal(_state)-1; eb = 2*ae_randomreal(_state)-1; testlinregunit_generatetask(ea, eb, -5*ae_randomreal(_state), 5*ae_randomreal(_state), n>4, 1.0, 2.0, n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1 ) { slcerrors = ae_true; continue; } varatested = vara; varbtested = varb; for(epass=0; epass<=estpasscount-1; epass++) { /* * Generate */ testlinregunit_filltaskwithy(ea, eb, n, &xy, &s, _state); lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1 ) { slcerrors = ae_true; continue; } /* * A, B, P * (P is being tested for uniformity, additional p-tests are below) */ ta.ptr.p_double[epass] = a; tb.ptr.p_double[epass] = b; for(i=0; i<=qcnt-1; i++) { if( ae_fp_less_eq(p,qtbl.ptr.p_double[i]) ) { qvals.ptr.p_double[i] = qvals.ptr.p_double[i]+(double)1/(double)estpasscount; } } } testlinregunit_calculatemv(&ta, estpasscount, &mean, &means, &stddev, &stddevs, _state); slerrors = slerrors||ae_fp_greater_eq(ae_fabs(mean-ea, _state)/means,sigmathreshold); slerrors = slerrors||ae_fp_greater_eq(ae_fabs(stddev-ae_sqrt(varatested, _state), _state)/stddevs,sigmathreshold); testlinregunit_calculatemv(&tb, estpasscount, &mean, &means, &stddev, &stddevs, _state); slerrors = slerrors||ae_fp_greater_eq(ae_fabs(mean-eb, _state)/means,sigmathreshold); slerrors = slerrors||ae_fp_greater_eq(ae_fabs(stddev-ae_sqrt(varbtested, _state), _state)/stddevs,sigmathreshold); if( n>2 ) { for(i=0; i<=qcnt-1; i++) { if( ae_fp_greater(ae_fabs(qtbl.ptr.p_double[i]-qvals.ptr.p_double[i], _state)/qsigma.ptr.p_double[i],sigmathreshold) ) { slerrors = ae_true; } } } /* * Additional tests for P: correlation with fit quality */ if( n>2 ) { testlinregunit_generatetask(ea, eb, -5*ae_randomreal(_state), 5*ae_randomreal(_state), ae_false, 0.0, 0.0, n, &xy, &s, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = 1+ae_randomreal(_state); } lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1 ) { slcerrors = ae_true; continue; } slerrors = slerrors||ae_fp_less(p,0.999); testlinregunit_generatetask((double)(0), (double)(0), -5*ae_randomreal(_state), 5*ae_randomreal(_state), ae_false, 1.0, 1.0, n, &xy, &s, _state); for(i=0; i<=n-1; i++) { if( i%2==0 ) { xy.ptr.pp_double[i][1] = 5.0; } else { xy.ptr.pp_double[i][1] = -5.0; } } if( n%2!=0 ) { xy.ptr.pp_double[n-1][1] = (double)(0); } lrlines(&xy, &s, n, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1 ) { slcerrors = ae_true; continue; } slerrors = slerrors||ae_fp_greater(p,0.001); } } } /* * General regression tests: */ /* * Simple linear tests (small sample, optimum point, covariance) */ for(n=3; n<=maxn; n++) { ae_vector_set_length(&s, n-1+1, _state); /* * Linear tests: * a. random points, sigmas * b. no sigmas */ ae_matrix_set_length(&xy, n-1+1, 1+1, _state); for(i=0; i<=n-1; i++) { xy.ptr.pp_double[i][0] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[i][1] = 2*ae_randomreal(_state)-1; s.ptr.p_double[i] = 1+ae_randomreal(_state); } lrbuilds(&xy, &s, n, 1, &info, &wt, &ar, _state); if( info!=1 ) { grconverrors = ae_true; continue; } lrunpack(&wt, &tmpweights, &tmpi, _state); lrlines(&xy, &s, n, &info2, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); gropterrors = gropterrors||ae_fp_greater(ae_fabs(a-tmpweights.ptr.p_double[1], _state),threshold); gropterrors = gropterrors||ae_fp_greater(ae_fabs(b-tmpweights.ptr.p_double[0], _state),threshold); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(vara-ar.c.ptr.pp_double[1][1], _state),threshold); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(varb-ar.c.ptr.pp_double[0][0], _state),threshold); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(covab-ar.c.ptr.pp_double[1][0], _state),threshold); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(covab-ar.c.ptr.pp_double[0][1], _state),threshold); lrbuild(&xy, n, 1, &info, &wt, &ar, _state); if( info!=1 ) { grconverrors = ae_true; continue; } lrunpack(&wt, &tmpweights, &tmpi, _state); lrline(&xy, n, &info2, &a, &b, _state); gropterrors = gropterrors||ae_fp_greater(ae_fabs(a-tmpweights.ptr.p_double[1], _state),threshold); gropterrors = gropterrors||ae_fp_greater(ae_fabs(b-tmpweights.ptr.p_double[0], _state),threshold); } /* * S covariance versus S-less covariance. * Slightly skewed task, large sample size. * Will S-less subroutine estimate covariance matrix good enough? */ n = 1000+ae_randominteger(3000, _state); sigma = 0.1+ae_randomreal(_state)*1.9; ae_matrix_set_length(&xy, n-1+1, 1+1, _state); ae_vector_set_length(&s, n-1+1, _state); for(i=0; i<=n-1; i++) { xy.ptr.pp_double[i][0] = 1.5*ae_randomreal(_state)-0.5; xy.ptr.pp_double[i][1] = 1.2*xy.ptr.pp_double[i][0]-0.3+testlinregunit_generatenormal((double)(0), sigma, _state); s.ptr.p_double[i] = sigma; } lrbuild(&xy, n, 1, &info, &wt, &ar, _state); lrlines(&xy, &s, n, &info2, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); if( info!=1||info2!=1 ) { grconverrors = ae_true; } else { grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(ae_log(ar.c.ptr.pp_double[0][0]/varb, _state), _state),ae_log(1.2, _state)); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(ae_log(ar.c.ptr.pp_double[1][1]/vara, _state), _state),ae_log(1.2, _state)); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(ae_log(ar.c.ptr.pp_double[0][1]/covab, _state), _state),ae_log(1.2, _state)); grcoverrors = grcoverrors||ae_fp_greater(ae_fabs(ae_log(ar.c.ptr.pp_double[1][0]/covab, _state), _state),ae_log(1.2, _state)); } /* * General tests: * * basis functions - up to cubic * * task types: * * data set is noisy sine half-period with random shift * * tests: * unpacking/packing * optimality * error estimates * * tasks: * 0 = noised sine * 1 = degenerate task with 1-of-n encoded categorical variables * 2 = random task with large variation (for 1-type models) * 3 = random task with small variation (for 1-type models) * * Additional tasks TODO * specially designed task with defective vectors which leads to * the failure of the fast CV formula. * */ m1 = 0; m2 = -1; n1 = 0; n2 = -1; for(modeltype=0; modeltype<=1; modeltype++) { for(tasktype=0; tasktype<=3; tasktype++) { if( tasktype==0 ) { m1 = 1; m2 = 3; } if( tasktype==1 ) { m1 = 9; m2 = 9; } if( tasktype==2||tasktype==3 ) { m1 = 9; m2 = 9; } for(m=m1; m<=m2; m++) { if( tasktype==0 ) { n1 = m+3; n2 = m+20; } if( tasktype==1 ) { n1 = 70+ae_randominteger(70, _state); n2 = n1; } if( tasktype==2||tasktype==3 ) { n1 = 100; n2 = n1; } for(n=n1; n<=n2; n++) { ae_matrix_set_length(&xy, n-1+1, m+1, _state); ae_vector_set_length(&xy0, n-1+1, _state); ae_vector_set_length(&s, n-1+1, _state); hstep = 0.001; noiselevel = 0.2; /* * Prepare task */ if( tasktype==0 ) { for(i=0; i<=n-1; i++) { xy.ptr.pp_double[i][0] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { for(j=1; j<=m-1; j++) { xy.ptr.pp_double[i][j] = xy.ptr.pp_double[i][0]*xy.ptr.pp_double[i][j-1]; } } sinshift = ae_randomreal(_state)*ae_pi; for(i=0; i<=n-1; i++) { xy0.ptr.p_double[i] = ae_sin(sinshift+ae_pi*0.5*(xy.ptr.pp_double[i][0]+1), _state); xy.ptr.pp_double[i][m] = xy0.ptr.p_double[i]+noiselevel*testlinregunit_generatenormal((double)(0), (double)(1), _state); } } if( tasktype==1 ) { ae_assert(m==9, "Assertion failed", _state); ae_vector_set_length(&ta, 8+1, _state); ta.ptr.p_double[0] = (double)(1); ta.ptr.p_double[1] = (double)(2); ta.ptr.p_double[2] = (double)(3); ta.ptr.p_double[3] = 0.25; ta.ptr.p_double[4] = 0.5; ta.ptr.p_double[5] = 0.75; ta.ptr.p_double[6] = 0.06; ta.ptr.p_double[7] = 0.12; ta.ptr.p_double[8] = 0.18; for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xy.ptr.pp_double[i][j] = (double)(0); } xy.ptr.pp_double[i][0+i%3] = (double)(1); xy.ptr.pp_double[i][3+i/3%3] = (double)(1); xy.ptr.pp_double[i][6+i/9%3] = (double)(1); v = ae_v_dotproduct(&xy.ptr.pp_double[i][0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,8)); xy0.ptr.p_double[i] = v; xy.ptr.pp_double[i][m] = v+noiselevel*testlinregunit_generatenormal((double)(0), (double)(1), _state); } } if( tasktype==2||tasktype==3 ) { ae_assert(m==9, "Assertion failed", _state); ae_vector_set_length(&ta, 8+1, _state); ta.ptr.p_double[0] = (double)(1); ta.ptr.p_double[1] = (double)(-2); ta.ptr.p_double[2] = (double)(3); ta.ptr.p_double[3] = 0.25; ta.ptr.p_double[4] = -0.5; ta.ptr.p_double[5] = 0.75; ta.ptr.p_double[6] = -0.06; ta.ptr.p_double[7] = 0.12; ta.ptr.p_double[8] = -0.18; for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { if( tasktype==2 ) { xy.ptr.pp_double[i][j] = 1+testlinregunit_generatenormal((double)(0), (double)(3), _state); } else { xy.ptr.pp_double[i][j] = 1+testlinregunit_generatenormal((double)(0), 0.05, _state); } } v = ae_v_dotproduct(&xy.ptr.pp_double[i][0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,8)); xy0.ptr.p_double[i] = v; xy.ptr.pp_double[i][m] = v+noiselevel*testlinregunit_generatenormal((double)(0), (double)(1), _state); } } for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = 1+ae_randomreal(_state); } /* * Solve (using S-variant, non-S-variant is not tested) */ if( modeltype==0 ) { lrbuilds(&xy, &s, n, m, &info, &wt, &ar, _state); } else { lrbuildzs(&xy, &s, n, m, &info, &wt, &ar, _state); } if( info!=1 ) { grconverrors = ae_true; continue; } lrunpack(&wt, &tmpweights, &tmpi, _state); /* * LRProcess test */ ae_vector_set_length(&x, m-1+1, _state); v = tmpweights.ptr.p_double[m]; for(i=0; i<=m-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; v = v+tmpweights.ptr.p_double[i]*x.ptr.p_double[i]; } grothererrors = grothererrors||ae_fp_greater(ae_fabs(v-lrprocess(&wt, &x, _state), _state)/ae_maxreal(ae_fabs(v, _state), (double)(1), _state),threshold); /* * LRPack test */ lrpack(&tmpweights, m, &wt2, _state); ae_vector_set_length(&x, m-1+1, _state); for(i=0; i<=m-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } v = lrprocess(&wt, &x, _state); grothererrors = grothererrors||ae_fp_greater(ae_fabs(v-lrprocess(&wt2, &x, _state), _state)/ae_fabs(v, _state),threshold); /* * Optimality test */ for(k=0; k<=m; k++) { if( modeltype==1&&k==m ) { /* * 0-type models (with non-zero constant term) * are tested for optimality of all coefficients. * * 1-type models (with zero constant term) * are tested for optimality of non-constant terms only. */ continue; } f = (double)(0); fp = (double)(0); fm = (double)(0); for(i=0; i<=n-1; i++) { v = tmpweights.ptr.p_double[m]; for(j=0; j<=m-1; j++) { v = v+xy.ptr.pp_double[i][j]*tmpweights.ptr.p_double[j]; } f = f+ae_sqr((v-xy.ptr.pp_double[i][m])/s.ptr.p_double[i], _state); if( kptr.pp_double[i][0] = xl+(xr-xl)*ae_randomreal(_state); } else { xy->ptr.pp_double[i][0] = xl+(xr-xl)*i/(n-1); } xy->ptr.pp_double[i][1] = ymin+(ymax-ymin)*ae_randomreal(_state); s->ptr.p_double[i] = smin+(smax-smin)*ae_randomreal(_state); } } /************************************************************************* Task generation. *************************************************************************/ static void testlinregunit_generatetask(double a, double b, double xl, double xr, ae_bool randomx, double smin, double smax, ae_int_t n, /* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; ae_matrix_set_length(xy, n-1+1, 1+1, _state); ae_vector_set_length(s, n-1+1, _state); for(i=0; i<=n-1; i++) { if( randomx ) { xy->ptr.pp_double[i][0] = xl+(xr-xl)*ae_randomreal(_state); } else { xy->ptr.pp_double[i][0] = xl+(xr-xl)*i/(n-1); } s->ptr.p_double[i] = smin+(smax-smin)*ae_randomreal(_state); xy->ptr.pp_double[i][1] = a+b*xy->ptr.pp_double[i][0]+testlinregunit_generatenormal((double)(0), s->ptr.p_double[i], _state); } } /************************************************************************* Task generation. y[i] are filled based on A, B, X[I], S[I] *************************************************************************/ static void testlinregunit_filltaskwithy(double a, double b, ae_int_t n, /* Real */ ae_matrix* xy, /* Real */ ae_vector* s, ae_state *_state) { ae_int_t i; for(i=0; i<=n-1; i++) { xy->ptr.pp_double[i][1] = a+b*xy->ptr.pp_double[i][0]+testlinregunit_generatenormal((double)(0), s->ptr.p_double[i], _state); } } /************************************************************************* Normal random numbers *************************************************************************/ static double testlinregunit_generatenormal(double mean, double sigma, ae_state *_state) { double u; double v; double sum; double result; result = mean; for(;;) { u = (2*ae_randominteger(2, _state)-1)*ae_randomreal(_state); v = (2*ae_randominteger(2, _state)-1)*ae_randomreal(_state); sum = u*u+v*v; if( ae_fp_less(sum,(double)(1))&&ae_fp_greater(sum,(double)(0)) ) { sum = ae_sqrt(-2*ae_log(sum, _state)/sum, _state); result = sigma*u*sum+mean; return result; } } return result; } /************************************************************************* Moments estimates and their errors *************************************************************************/ static void testlinregunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state) { ae_int_t i; double v1; double v2; double variance; *mean = 0; *means = 0; *stddev = 0; *stddevs = 0; *mean = (double)(0); *means = (double)(1); *stddev = (double)(0); *stddevs = (double)(1); variance = (double)(0); if( n<=1 ) { return; } /* * Mean */ for(i=0; i<=n-1; i++) { *mean = *mean+x->ptr.p_double[i]; } *mean = *mean/n; /* * Variance (using corrected two-pass algorithm) */ if( n!=1 ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-(*mean)); } v2 = ae_sqr(v2, _state)/n; variance = (v1-v2)/(n-1); if( ae_fp_less(variance,(double)(0)) ) { variance = (double)(0); } *stddev = ae_sqrt(variance, _state); } /* * Errors */ *means = *stddev/ae_sqrt((double)(n), _state); *stddevs = *stddev*ae_sqrt((double)(2), _state)/ae_sqrt((double)(n-1), _state); } /************************************************************************* Unsets LR *************************************************************************/ static void testlinregunit_unsetlr(linearmodel* lr, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_int_t info; lrreport rep; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _lrreport_init(&rep, _state); ae_matrix_set_length(&xy, 5+1, 1+1, _state); for(i=0; i<=5; i++) { xy.ptr.pp_double[i][0] = (double)(0); xy.ptr.pp_double[i][1] = (double)(0); } lrbuild(&xy, 6, 1, &info, lr, &rep, _state); ae_assert(info>0, "Assertion failed", _state); ae_frame_leave(_state); } ae_bool testfilters(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool smaerrors; ae_bool emaerrors; ae_bool lrmaerrors; ae_bool result; smaerrors = testsma(ae_true, _state); emaerrors = testema(ae_true, _state); lrmaerrors = testlrma(ae_true, _state); /* * Final report */ waserrors = (smaerrors||emaerrors)||lrmaerrors; if( !silent ) { printf("FILTERS TEST\n"); printf("* SMA: "); if( !smaerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* EMA: "); if( !emaerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LRMA: "); if( !lrmaerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testfilters(ae_bool silent, ae_state *_state) { return testfilters(silent, _state); } /************************************************************************* This function tests SMA(k) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testsma(ae_bool issilent, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_bool precomputederrors; ae_bool zerohandlingerrors; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); threshold = 1000*ae_machineepsilon; if( !issilent ) { printf("SMA(K) TEST\n"); } /* * Test several pre-computed problems. * * NOTE: tests below rely on the fact that floating point * additions and subtractions are exact when dealing * with integer values. */ precomputederrors = ae_false; ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = (double)(7); filtersma(&x, 1, 1, _state); precomputederrors = precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)); ae_vector_set_length(&x, 3, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(9); filtersma(&x, 3, 1, _state); precomputederrors = ((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],(double)(8)))||ae_fp_neq(x.ptr.p_double[2],(double)(9)); filtersma(&x, 3, 2, _state); precomputederrors = ((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],7.5))||ae_fp_neq(x.ptr.p_double[2],8.5); ae_vector_set_length(&x, 3, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(9); filtersma(&x, 3, 4, _state); precomputederrors = ((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],7.5))||ae_fp_neq(x.ptr.p_double[2],(double)(8)); /* * Test zero-handling: * a) when we have non-zero sequence (N1 elements) followed by zero sequence * (N2 elements), then first N1+K-1 elements of the processed sequence are * non-zero, but elements since (N1+K)th must be exactly zero. * b) similar property holds for zero sequence followed by non-zero one * * Naive implementation of SMA does not have such property. * * NOTE: it is important to initialize X with non-integer elements with long * binary mantissas, because this test tries to test behaviour in the presence * of roundoff errors, and it will be useless when used with integer inputs. */ zerohandlingerrors = ae_false; ae_vector_set_length(&x, 10, _state); x.ptr.p_double[0] = ae_sqrt((double)(2), _state); x.ptr.p_double[1] = ae_sqrt((double)(3), _state); x.ptr.p_double[2] = ae_sqrt((double)(5), _state); x.ptr.p_double[3] = ae_sqrt((double)(6), _state); x.ptr.p_double[4] = ae_sqrt((double)(7), _state); x.ptr.p_double[5] = (double)(0); x.ptr.p_double[6] = (double)(0); x.ptr.p_double[7] = (double)(0); x.ptr.p_double[8] = (double)(0); x.ptr.p_double[9] = (double)(0); filtersma(&x, 10, 3, _state); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_sqrt((double)(2), _state), _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[1]-(ae_sqrt((double)(2), _state)+ae_sqrt((double)(3), _state))/2, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-(ae_sqrt((double)(2), _state)+ae_sqrt((double)(3), _state)+ae_sqrt((double)(5), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[3]-(ae_sqrt((double)(3), _state)+ae_sqrt((double)(5), _state)+ae_sqrt((double)(6), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[4]-(ae_sqrt((double)(5), _state)+ae_sqrt((double)(6), _state)+ae_sqrt((double)(7), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[5]-(ae_sqrt((double)(6), _state)+ae_sqrt((double)(7), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[6]-ae_sqrt((double)(7), _state)/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[7],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[8],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[9],(double)(0)); x.ptr.p_double[0] = (double)(0); x.ptr.p_double[1] = (double)(0); x.ptr.p_double[2] = (double)(0); x.ptr.p_double[3] = (double)(0); x.ptr.p_double[4] = (double)(0); x.ptr.p_double[5] = ae_sqrt((double)(2), _state); x.ptr.p_double[6] = ae_sqrt((double)(3), _state); x.ptr.p_double[7] = ae_sqrt((double)(5), _state); x.ptr.p_double[8] = ae_sqrt((double)(6), _state); x.ptr.p_double[9] = ae_sqrt((double)(7), _state); filtersma(&x, 10, 3, _state); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[0],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[1],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[2],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[3],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_neq(x.ptr.p_double[4],(double)(0)); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[5]-ae_sqrt((double)(2), _state)/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[6]-(ae_sqrt((double)(2), _state)+ae_sqrt((double)(3), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[7]-(ae_sqrt((double)(2), _state)+ae_sqrt((double)(3), _state)+ae_sqrt((double)(5), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[8]-(ae_sqrt((double)(3), _state)+ae_sqrt((double)(5), _state)+ae_sqrt((double)(6), _state))/3, _state),threshold); zerohandlingerrors = zerohandlingerrors||ae_fp_greater(ae_fabs(x.ptr.p_double[9]-(ae_sqrt((double)(5), _state)+ae_sqrt((double)(6), _state)+ae_sqrt((double)(7), _state))/3, _state),threshold); /* * Final result */ result = precomputederrors||zerohandlingerrors; ae_frame_leave(_state); return result; } /************************************************************************* This function tests EMA(alpha) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testema(ae_bool issilent, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_bool precomputederrors; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); threshold = 1000*ae_machineepsilon; if( !issilent ) { printf("EMA(alpha) TEST\n"); } /* * Test several pre-computed problems. * * NOTE: tests below rely on the fact that floating point * additions and subtractions are exact when dealing * with integer values. */ precomputederrors = ae_false; ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = (double)(7); filterema(&x, 1, 1.0, _state); precomputederrors = precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)); filterema(&x, 1, 0.5, _state); precomputederrors = precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)); ae_vector_set_length(&x, 3, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(9); filterema(&x, 3, 1.0, _state); precomputederrors = ((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],(double)(8)))||ae_fp_neq(x.ptr.p_double[2],(double)(9)); filterema(&x, 3, 0.5, _state); precomputederrors = ((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],7.5))||ae_fp_neq(x.ptr.p_double[2],8.25); /* * Final result */ result = precomputederrors; ae_frame_leave(_state); return result; } /************************************************************************* This function tests LRMA(k) filter. It returns True on error. Additional IsSilent parameter controls detailed error reporting. *************************************************************************/ ae_bool testlrma(ae_bool issilent, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_bool precomputederrors; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); threshold = 1000*ae_machineepsilon; if( !issilent ) { printf("LRMA(K) TEST\n"); } precomputederrors = ae_false; /* * First, check that filter does not changes points for K=1 or K=2 */ ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = (double)(7); filterlrma(&x, 1, 1, _state); precomputederrors = precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)); ae_vector_set_length(&x, 6, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(9); x.ptr.p_double[3] = (double)(10); x.ptr.p_double[4] = (double)(11); x.ptr.p_double[5] = (double)(12); filterlrma(&x, 6, 1, _state); precomputederrors = (((((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],(double)(8)))||ae_fp_neq(x.ptr.p_double[2],(double)(9)))||ae_fp_neq(x.ptr.p_double[3],(double)(10)))||ae_fp_neq(x.ptr.p_double[4],(double)(11)))||ae_fp_neq(x.ptr.p_double[5],(double)(12)); filterlrma(&x, 6, 2, _state); precomputederrors = (((((precomputederrors||ae_fp_neq(x.ptr.p_double[0],(double)(7)))||ae_fp_neq(x.ptr.p_double[1],(double)(8)))||ae_fp_neq(x.ptr.p_double[2],(double)(9)))||ae_fp_neq(x.ptr.p_double[3],(double)(10)))||ae_fp_neq(x.ptr.p_double[4],(double)(11)))||ae_fp_neq(x.ptr.p_double[5],(double)(12)); /* * Check several precomputed problems */ ae_vector_set_length(&x, 6, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(9); x.ptr.p_double[3] = (double)(10); x.ptr.p_double[4] = (double)(11); x.ptr.p_double[5] = (double)(12); filterlrma(&x, 6, 3, _state); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-7, _state),threshold); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[1]-8, _state),threshold); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-9, _state),threshold); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[3]-10, _state),threshold); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[4]-11, _state),threshold); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[5]-12, _state),threshold); ae_vector_set_length(&x, 6, _state); x.ptr.p_double[0] = (double)(7); x.ptr.p_double[1] = (double)(8); x.ptr.p_double[2] = (double)(8); x.ptr.p_double[3] = (double)(9); x.ptr.p_double[4] = (double)(12); x.ptr.p_double[5] = (double)(12); filterlrma(&x, 6, 3, _state); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-7.0000000000, _state),1.0E-5); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[1]-8.0000000000, _state),1.0E-5); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-8.1666666667, _state),1.0E-5); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[3]-8.8333333333, _state),1.0E-5); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[4]-11.6666666667, _state),1.0E-5); precomputederrors = precomputederrors||ae_fp_greater(ae_fabs(x.ptr.p_double[5]-12.5000000000, _state),1.0E-5); /* * Final result */ result = precomputederrors; ae_frame_leave(_state); return result; } static void testevdunit_rmatrixfillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state); static void testevdunit_cmatrixfillsparsea(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state); static void testevdunit_rmatrixsymmetricsplit(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_state *_state); static void testevdunit_cmatrixhermitiansplit(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* al, /* Complex */ ae_matrix* au, ae_state *_state); static void testevdunit_unset2d(/* Real */ ae_matrix* a, ae_state *_state); static void testevdunit_cunset2d(/* Complex */ ae_matrix* a, ae_state *_state); static void testevdunit_unset1d(/* Real */ ae_vector* a, ae_state *_state); static double testevdunit_tdtestproduct(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, /* Real */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state); static double testevdunit_testproduct(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state); static double testevdunit_testort(/* Real */ ae_matrix* z, ae_int_t n, ae_state *_state); static double testevdunit_testcproduct(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state); static double testevdunit_testcort(/* Complex */ ae_matrix* z, ae_int_t n, ae_state *_state); static void testevdunit_testsevdproblem(/* Real */ ae_matrix* a, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_int_t n, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state); static void testevdunit_testhevdproblem(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* al, /* Complex */ ae_matrix* au, ae_int_t n, double threshold, ae_bool* herrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state); static void testevdunit_testsevdbiproblem(/* Real */ ae_matrix* afull, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_int_t n, ae_bool distvals, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state); static void testevdunit_testhevdbiproblem(/* Complex */ ae_matrix* afull, /* Complex */ ae_matrix* al, /* Complex */ ae_matrix* au, ae_int_t n, ae_bool distvals, double threshold, ae_bool* herrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state); static void testevdunit_testtdevdproblem(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, double threshold, ae_bool* tderrors, ae_state *_state); static void testevdunit_testtdevdbiproblem(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool distvals, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state); static void testevdunit_testnsevdproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* nserrors, ae_state *_state); static void testevdunit_testevdset(ae_int_t n, double threshold, double bithreshold, ae_int_t* failc, ae_int_t* runs, ae_bool* nserrors, ae_bool* serrors, ae_bool* herrors, ae_bool* tderrors, ae_bool* sbierrors, ae_bool* hbierrors, ae_bool* tdbierrors, ae_state *_state); /************************************************************************* Testing symmetric EVD subroutine *************************************************************************/ ae_bool testevd(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix ra; ae_int_t n; ae_int_t j; ae_int_t failc; ae_int_t runs; double failthreshold; double threshold; double bithreshold; ae_bool waserrors; ae_bool nserrors; ae_bool serrors; ae_bool herrors; ae_bool tderrors; ae_bool sbierrors; ae_bool hbierrors; ae_bool tdbierrors; ae_bool wfailed; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); failthreshold = 0.005; threshold = 1.0E-8; bithreshold = 1.0E-6; nserrors = ae_false; serrors = ae_false; herrors = ae_false; tderrors = ae_false; sbierrors = ae_false; hbierrors = ae_false; tdbierrors = ae_false; failc = 0; runs = 0; /* * Test problems */ for(n=1; n<=ablasblocksize(&ra, _state); n++) { testevdunit_testevdset(n, threshold, bithreshold, &failc, &runs, &nserrors, &serrors, &herrors, &tderrors, &sbierrors, &hbierrors, &tdbierrors, _state); } for(j=2; j<=3; j++) { for(n=j*ablasblocksize(&ra, _state)-1; n<=j*ablasblocksize(&ra, _state)+1; n++) { testevdunit_testevdset(n, threshold, bithreshold, &failc, &runs, &nserrors, &serrors, &herrors, &tderrors, &sbierrors, &hbierrors, &tdbierrors, _state); } } /* * report */ wfailed = ae_fp_greater((double)failc/(double)runs,failthreshold); waserrors = ((((((nserrors||serrors)||herrors)||tderrors)||sbierrors)||hbierrors)||tdbierrors)||wfailed; if( !silent ) { printf("TESTING EVD UNIT\n"); printf("NS ERRORS: "); if( !nserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("S ERRORS: "); if( !serrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("H ERRORS: "); if( !herrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("TD ERRORS: "); if( !tderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SBI ERRORS: "); if( !sbierrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("HBI ERRORS: "); if( !hbierrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("TDBI ERRORS: "); if( !tdbierrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("FAILURE THRESHOLD: "); if( !wfailed ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testevd(ae_bool silent, ae_state *_state) { return testevd(silent, _state); } /************************************************************************* Sparse fill *************************************************************************/ static void testevdunit_rmatrixfillsparsea(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_double[i][j] = (double)(0); } } } } /************************************************************************* Sparse fill *************************************************************************/ static void testevdunit_cmatrixfillsparsea(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a->ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } } /************************************************************************* Copies A to AL (lower half) and AU (upper half), filling unused parts by random garbage. *************************************************************************/ static void testevdunit_rmatrixsymmetricsplit(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { al->ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; al->ptr.pp_double[j][i] = a->ptr.pp_double[i][j]; au->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; au->ptr.pp_double[j][i] = 2*ae_randomreal(_state)-1; } al->ptr.pp_double[i][i] = a->ptr.pp_double[i][i]; au->ptr.pp_double[i][i] = a->ptr.pp_double[i][i]; } } /************************************************************************* Copies A to AL (lower half) and AU (upper half), filling unused parts by random garbage. *************************************************************************/ static void testevdunit_cmatrixhermitiansplit(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* al, /* Complex */ ae_matrix* au, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { al->ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); al->ptr.pp_complex[j][i] = ae_c_conj(a->ptr.pp_complex[i][j], _state); au->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; au->ptr.pp_complex[j][i] = ae_complex_from_d(2*ae_randomreal(_state)-1); } al->ptr.pp_complex[i][i] = a->ptr.pp_complex[i][i]; au->ptr.pp_complex[i][i] = a->ptr.pp_complex[i][i]; } } /************************************************************************* Unsets 2D array. *************************************************************************/ static void testevdunit_unset2d(/* Real */ ae_matrix* a, ae_state *_state) { ae_matrix_clear(a); if( a->rows*a->cols>0 ) { ae_matrix_set_length(a, 1, 1, _state); } } /************************************************************************* Unsets 2D array. *************************************************************************/ static void testevdunit_cunset2d(/* Complex */ ae_matrix* a, ae_state *_state) { ae_matrix_set_length(a, 0+1, 0+1, _state); a->ptr.pp_complex[0][0] = ae_complex_from_d(2*ae_randomreal(_state)-1); } /************************************************************************* Unsets 1D array. *************************************************************************/ static void testevdunit_unset1d(/* Real */ ae_vector* a, ae_state *_state) { ae_vector_clear(a); if( a->cnt>0 ) { ae_vector_set_length(a, 1, _state); } } /************************************************************************* Tests Z*Lambda*Z' against tridiag(D,E). Returns relative error. *************************************************************************/ static double testevdunit_tdtestproduct(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, /* Real */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double v; double mx; double result; result = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * Calculate V = A[i,j], A = Z*Lambda*Z' */ v = (double)(0); for(k=0; k<=n-1; k++) { v = v+z->ptr.pp_double[i][k]*lambdav->ptr.p_double[k]*z->ptr.pp_double[j][k]; } /* * Compare */ if( ae_iabs(i-j, _state)==0 ) { result = ae_maxreal(result, ae_fabs(v-d->ptr.p_double[i], _state), _state); } if( ae_iabs(i-j, _state)==1 ) { result = ae_maxreal(result, ae_fabs(v-e->ptr.p_double[ae_minint(i, j, _state)], _state), _state); } if( ae_iabs(i-j, _state)>1 ) { result = ae_maxreal(result, ae_fabs(v, _state), _state); } } } mx = (double)(0); for(i=0; i<=n-1; i++) { mx = ae_maxreal(mx, ae_fabs(d->ptr.p_double[i], _state), _state); } for(i=0; i<=n-2; i++) { mx = ae_maxreal(mx, ae_fabs(e->ptr.p_double[i], _state), _state); } if( ae_fp_eq(mx,(double)(0)) ) { mx = (double)(1); } result = result/mx; return result; } /************************************************************************* Tests Z*Lambda*Z' against A Returns relative error. *************************************************************************/ static double testevdunit_testproduct(/* Real */ ae_matrix* a, ae_int_t n, /* Real */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double v; double mx; double result; result = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * Calculate V = A[i,j], A = Z*Lambda*Z' */ v = (double)(0); for(k=0; k<=n-1; k++) { v = v+z->ptr.pp_double[i][k]*lambdav->ptr.p_double[k]*z->ptr.pp_double[j][k]; } /* * Compare */ result = ae_maxreal(result, ae_fabs(v-a->ptr.pp_double[i][j], _state), _state); } } mx = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); } } if( ae_fp_eq(mx,(double)(0)) ) { mx = (double)(1); } result = result/mx; return result; } /************************************************************************* Tests Z*Z' against diag(1...1) Returns absolute error. *************************************************************************/ static double testevdunit_testort(/* Real */ ae_matrix* z, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; double v; double result; result = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&z->ptr.pp_double[0][i], z->stride, &z->ptr.pp_double[0][j], z->stride, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } result = ae_maxreal(result, ae_fabs(v, _state), _state); } } return result; } /************************************************************************* Tests Z*Lambda*Z' against A Returns relative error. *************************************************************************/ static double testevdunit_testcproduct(/* Complex */ ae_matrix* a, ae_int_t n, /* Complex */ ae_matrix* z, /* Real */ ae_vector* lambdav, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; ae_complex v; double mx; double result; result = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * Calculate V = A[i,j], A = Z*Lambda*Z' */ v = ae_complex_from_i(0); for(k=0; k<=n-1; k++) { v = ae_c_add(v,ae_c_mul(ae_c_mul_d(z->ptr.pp_complex[i][k],lambdav->ptr.p_double[k]),ae_c_conj(z->ptr.pp_complex[j][k], _state))); } /* * Compare */ result = ae_maxreal(result, ae_c_abs(ae_c_sub(v,a->ptr.pp_complex[i][j]), _state), _state); } } mx = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); } } if( ae_fp_eq(mx,(double)(0)) ) { mx = (double)(1); } result = result/mx; return result; } /************************************************************************* Tests Z*Z' against diag(1...1) Returns absolute error. *************************************************************************/ static double testevdunit_testcort(/* Complex */ ae_matrix* z, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex v; double result; result = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&z->ptr.pp_complex[0][i], z->stride, "N", &z->ptr.pp_complex[0][j], z->stride, "Conj", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } result = ae_maxreal(result, ae_c_abs(v, _state), _state); } } return result; } /************************************************************************* Tests SEVD problem *************************************************************************/ static void testevdunit_testsevdproblem(/* Real */ ae_matrix* a, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_int_t n, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state) { ae_frame _frame_block; ae_vector lambdav; ae_vector lambdaref; ae_matrix z; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&lambdav, 0, DT_REAL, _state); ae_vector_init(&lambdaref, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); /* * Test simple EVD: values and full vectors, lower A */ testevdunit_unset1d(&lambdaref, _state); testevdunit_unset2d(&z, _state); *runs = *runs+1; if( !smatrixevd(al, n, 1, ae_false, &lambdaref, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } *serrors = *serrors||ae_fp_greater(testevdunit_testproduct(a, n, &z, &lambdaref, _state),threshold); *serrors = *serrors||ae_fp_greater(testevdunit_testort(&z, n, _state),threshold); for(i=0; i<=n-2; i++) { if( ae_fp_less(lambdaref.ptr.p_double[i+1],lambdaref.ptr.p_double[i]) ) { *serrors = ae_true; ae_frame_leave(_state); return; } } /* * Test simple EVD: values and full vectors, upper A */ testevdunit_unset1d(&lambdav, _state); testevdunit_unset2d(&z, _state); *runs = *runs+1; if( !smatrixevd(au, n, 1, ae_true, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } *serrors = *serrors||ae_fp_greater(testevdunit_testproduct(a, n, &z, &lambdav, _state),threshold); *serrors = *serrors||ae_fp_greater(testevdunit_testort(&z, n, _state),threshold); for(i=0; i<=n-2; i++) { if( ae_fp_less(lambdav.ptr.p_double[i+1],lambdav.ptr.p_double[i]) ) { *serrors = ae_true; ae_frame_leave(_state); return; } } /* * Test simple EVD: values only, lower A */ testevdunit_unset1d(&lambdav, _state); testevdunit_unset2d(&z, _state); *runs = *runs+1; if( !smatrixevd(al, n, 0, ae_false, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[i]-lambdaref.ptr.p_double[i], _state),threshold); } /* * Test simple EVD: values only, upper A */ testevdunit_unset1d(&lambdav, _state); testevdunit_unset2d(&z, _state); *runs = *runs+1; if( !smatrixevd(au, n, 0, ae_true, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[i]-lambdaref.ptr.p_double[i], _state),threshold); } ae_frame_leave(_state); } /************************************************************************* Tests SEVD problem *************************************************************************/ static void testevdunit_testhevdproblem(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* al, /* Complex */ ae_matrix* au, ae_int_t n, double threshold, ae_bool* herrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state) { ae_frame _frame_block; ae_vector lambdav; ae_vector lambdaref; ae_matrix z; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&lambdav, 0, DT_REAL, _state); ae_vector_init(&lambdaref, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_COMPLEX, _state); /* * Test simple EVD: values and full vectors, lower A */ testevdunit_unset1d(&lambdaref, _state); testevdunit_cunset2d(&z, _state); *runs = *runs+1; if( !hmatrixevd(al, n, 1, ae_false, &lambdaref, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } *herrors = *herrors||ae_fp_greater(testevdunit_testcproduct(a, n, &z, &lambdaref, _state),threshold); *herrors = *herrors||ae_fp_greater(testevdunit_testcort(&z, n, _state),threshold); for(i=0; i<=n-2; i++) { if( ae_fp_less(lambdaref.ptr.p_double[i+1],lambdaref.ptr.p_double[i]) ) { *herrors = ae_true; ae_frame_leave(_state); return; } } /* * Test simple EVD: values and full vectors, upper A */ testevdunit_unset1d(&lambdav, _state); testevdunit_cunset2d(&z, _state); *runs = *runs+1; if( !hmatrixevd(au, n, 1, ae_true, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } *herrors = *herrors||ae_fp_greater(testevdunit_testcproduct(a, n, &z, &lambdav, _state),threshold); *herrors = *herrors||ae_fp_greater(testevdunit_testcort(&z, n, _state),threshold); for(i=0; i<=n-2; i++) { if( ae_fp_less(lambdav.ptr.p_double[i+1],lambdav.ptr.p_double[i]) ) { *herrors = ae_true; ae_frame_leave(_state); return; } } /* * Test simple EVD: values only, lower A */ testevdunit_unset1d(&lambdav, _state); testevdunit_cunset2d(&z, _state); *runs = *runs+1; if( !hmatrixevd(al, n, 0, ae_false, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { *herrors = *herrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[i]-lambdaref.ptr.p_double[i], _state),threshold); } /* * Test simple EVD: values only, upper A */ testevdunit_unset1d(&lambdav, _state); testevdunit_cunset2d(&z, _state); *runs = *runs+1; if( !hmatrixevd(au, n, 0, ae_true, &lambdav, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { *herrors = *herrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[i]-lambdaref.ptr.p_double[i], _state),threshold); } ae_frame_leave(_state); } /************************************************************************* Tests EVD problem DistVals - is True, when eigenvalues are distinct. Is False, when we are solving sparse task with lots of zero eigenvalues. In such cases some tests related to the eigenvectors are not performed. *************************************************************************/ static void testevdunit_testsevdbiproblem(/* Real */ ae_matrix* afull, /* Real */ ae_matrix* al, /* Real */ ae_matrix* au, ae_int_t n, ae_bool distvals, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state) { ae_frame _frame_block; ae_vector lambdav; ae_vector lambdaref; ae_matrix z; ae_matrix zref; ae_matrix a1; ae_matrix a2; ae_matrix ar; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t m; ae_int_t i1; ae_int_t i2; double v; double a; double b; ae_frame_make(_state, &_frame_block); ae_vector_init(&lambdav, 0, DT_REAL, _state); ae_vector_init(&lambdaref, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); ae_matrix_init(&zref, 0, 0, DT_REAL, _state); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_matrix_init(&ar, 0, 0, DT_REAL, _state); ae_vector_set_length(&lambdaref, n-1+1, _state); ae_matrix_set_length(&zref, n-1+1, n-1+1, _state); ae_matrix_set_length(&a1, n-1+1, n-1+1, _state); ae_matrix_set_length(&a2, n-1+1, n-1+1, _state); /* * Reference EVD */ *runs = *runs+1; if( !smatrixevd(afull, n, 1, ae_true, &lambdaref, &zref, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } /* * Select random interval boundaries. * If there are non-distinct eigenvalues at the boundaries, * we move indexes further until values splits. It is done to * avoid situations where we can't get definite answer. */ i1 = ae_randominteger(n, _state); i2 = i1+ae_randominteger(n-i1, _state); while(i1>0) { if( ae_fp_greater(ae_fabs(lambdaref.ptr.p_double[i1-1]-lambdaref.ptr.p_double[i1], _state),10*threshold) ) { break; } i1 = i1-1; } while(i20 ) { a = 0.5*(lambdaref.ptr.p_double[i1]+lambdaref.ptr.p_double[i1-1]); } else { a = lambdaref.ptr.p_double[0]-1; } if( i20) { if( ae_fp_greater(ae_fabs(lambdaref.ptr.p_double[i1-1]-lambdaref.ptr.p_double[i1], _state),10*threshold) ) { break; } i1 = i1-1; } while(i20 ) { a = 0.5*(lambdaref.ptr.p_double[i1]+lambdaref.ptr.p_double[i1-1]); } else { a = lambdaref.ptr.p_double[0]-1; } if( i21 ) { ae_vector_set_length(&ee, n-2+1, _state); } /* * Test simple EVD: values and full vectors */ for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { ee.ptr.p_double[i] = e->ptr.p_double[i]; } testevdunit_unset2d(&z, _state); wsucc = smatrixtdevd(&lambdav, &ee, n, 2, &z, _state); if( !wsucc ) { seterrorflag(tderrors, ae_true, _state); ae_frame_leave(_state); return; } seterrorflag(tderrors, ae_fp_greater(testevdunit_tdtestproduct(d, e, n, &z, &lambdav, _state),threshold), _state); seterrorflag(tderrors, ae_fp_greater(testevdunit_testort(&z, n, _state),threshold), _state); for(i=0; i<=n-2; i++) { if( ae_fp_less(lambdav.ptr.p_double[i+1],lambdav.ptr.p_double[i]) ) { seterrorflag(tderrors, ae_true, _state); ae_frame_leave(_state); return; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { zref.ptr.pp_double[i][j] = z.ptr.pp_double[i][j]; } } /* * Test values only variant */ for(i=0; i<=n-1; i++) { lambda2.ptr.p_double[i] = d->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { ee.ptr.p_double[i] = e->ptr.p_double[i]; } testevdunit_unset2d(&z, _state); wsucc = smatrixtdevd(&lambda2, &ee, n, 0, &z, _state); if( !wsucc ) { seterrorflag(tderrors, ae_true, _state); ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(tderrors, ae_fp_greater(ae_fabs(lambda2.ptr.p_double[i]-lambdav.ptr.p_double[i], _state),threshold), _state); } /* * Test multiplication variant */ for(i=0; i<=n-1; i++) { lambda2.ptr.p_double[i] = d->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { ee.ptr.p_double[i] = e->ptr.p_double[i]; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a2.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]; } } wsucc = smatrixtdevd(&lambda2, &ee, n, 1, &a1, _state); if( !wsucc ) { seterrorflag(tderrors, ae_true, _state); ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(tderrors, ae_fp_greater(ae_fabs(lambda2.ptr.p_double[i]-lambdav.ptr.p_double[i], _state),threshold), _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&a2.ptr.pp_double[i][0], 1, &zref.ptr.pp_double[0][j], zref.stride, ae_v_len(0,n-1)); /* * next line is a bit complicated because * depending on algorithm used we can get either * z or -z as eigenvector. so we compare result * with both A*ZRef and -A*ZRef */ seterrorflag(tderrors, ae_fp_greater(ae_fabs(v-a1.ptr.pp_double[i][j], _state),threshold)&&ae_fp_greater(ae_fabs(v+a1.ptr.pp_double[i][j], _state),threshold), _state); } } /* * Test first row variant. * * NOTE: this test is special because ZNeeded=3 is ALGLIB-specific feature * which is NOT supported by Intel MKL. Thus, MKL-capable version of * ALGLIB will use different algorithms for ZNeeded=3 and for ZNeeded<3. * * In most cases it is OK, but when problem happened to be degenerate * (two close eigenvalues), Z computed by ALGLIB may be different from * Z computed by MKL (up to arbitrary rotation), which will lead to * failure of the test, because ZNeeded=2 is used as reference value * for ZNeeded=3. * * That's why this test is performed only for well-separated matrices, * and with custom threshold. */ requiredseparation = 1.0E-6; specialthreshold = 1.0E-6; worstseparation = ae_maxrealnumber; for(i=0; i<=n-2; i++) { worstseparation = ae_minreal(worstseparation, ae_fabs(lambdav.ptr.p_double[i+1]-lambdav.ptr.p_double[i], _state), _state); } if( ae_fp_greater(worstseparation,requiredseparation) ) { for(i=0; i<=n-1; i++) { lambda2.ptr.p_double[i] = d->ptr.p_double[i]; } for(i=0; i<=n-2; i++) { ee.ptr.p_double[i] = e->ptr.p_double[i]; } testevdunit_unset2d(&z, _state); wsucc = smatrixtdevd(&lambda2, &ee, n, 3, &z, _state); if( !wsucc ) { seterrorflag(tderrors, ae_true, _state); ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(tderrors, ae_fp_greater(ae_fabs(lambda2.ptr.p_double[i]-lambdav.ptr.p_double[i], _state),threshold), _state); /* * next line is a bit complicated because * depending on algorithm used we can get either * z or -z as eigenvector. so we compare result * with both z and -z */ seterrorflag(tderrors, ae_fp_greater(ae_fabs(z.ptr.pp_double[0][i]-zref.ptr.pp_double[0][i], _state),specialthreshold)&&ae_fp_greater(ae_fabs(z.ptr.pp_double[0][i]+zref.ptr.pp_double[0][i], _state),specialthreshold), _state); } } ae_frame_leave(_state); } /************************************************************************* Tests EVD problem DistVals - is True, when eigenvalues are distinct. Is False, when we are solving sparse task with lots of zero eigenvalues. In such cases some tests related to the eigenvectors are not performed. *************************************************************************/ static void testevdunit_testtdevdbiproblem(/* Real */ ae_vector* d, /* Real */ ae_vector* e, ae_int_t n, ae_bool distvals, double threshold, ae_bool* serrors, ae_int_t* failc, ae_int_t* runs, ae_state *_state) { ae_frame _frame_block; ae_vector lambdav; ae_vector lambdaref; ae_matrix z; ae_matrix zref; ae_matrix a1; ae_matrix a2; ae_matrix ar; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t m; ae_int_t i1; ae_int_t i2; double v; double a; double b; ae_frame_make(_state, &_frame_block); ae_vector_init(&lambdav, 0, DT_REAL, _state); ae_vector_init(&lambdaref, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); ae_matrix_init(&zref, 0, 0, DT_REAL, _state); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_matrix_init(&ar, 0, 0, DT_REAL, _state); ae_vector_set_length(&lambdaref, n-1+1, _state); ae_matrix_set_length(&zref, n-1+1, n-1+1, _state); ae_matrix_set_length(&a1, n-1+1, n-1+1, _state); ae_matrix_set_length(&a2, n-1+1, n-1+1, _state); /* * Reference EVD */ ae_vector_set_length(&lambdaref, n, _state); ae_v_move(&lambdaref.ptr.p_double[0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); *runs = *runs+1; if( !smatrixtdevd(&lambdaref, e, n, 2, &zref, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } /* * Select random interval boundaries. * If there are non-distinct eigenvalues at the boundaries, * we move indexes further until values splits. It is done to * avoid situations where we can't get definite answer. */ i1 = ae_randominteger(n, _state); i2 = i1+ae_randominteger(n-i1, _state); while(i1>0) { if( ae_fp_greater(ae_fabs(lambdaref.ptr.p_double[i1-1]-lambdaref.ptr.p_double[i1], _state),10*threshold) ) { break; } i1 = i1-1; } while(i20 ) { a = 0.5*(lambdaref.ptr.p_double[i1]+lambdaref.ptr.p_double[i1-1]); } else { a = lambdaref.ptr.p_double[0]-1; } if( i2ptr.p_double[i]; } *runs = *runs+1; if( !smatrixtdevdr(&lambdav, e, n, 0, a, b, &m, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } if( m!=i2-i1+1 ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } /* * Test indexes, no vectors */ ae_vector_set_length(&lambdav, n-1+1, _state); for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } *runs = *runs+1; if( !smatrixtdevdi(&lambdav, e, n, 0, i1, i2, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } m = i2-i1+1; for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } /* * Test interval, transform vectors */ ae_vector_set_length(&lambdav, n-1+1, _state); for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } ae_matrix_set_length(&a1, n-1+1, n-1+1, _state); ae_matrix_set_length(&a2, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a2.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]; } } *runs = *runs+1; if( !smatrixtdevdr(&lambdav, e, n, 1, a, b, &m, &a1, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } if( m!=i2-i1+1 ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } if( distvals ) { ae_matrix_set_length(&ar, n-1+1, m-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a2.ptr.pp_double[i][0], 1, &zref.ptr.pp_double[0][i1+j], zref.stride, ae_v_len(0,n-1)); ar.ptr.pp_double[i][j] = v; } } for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a1.ptr.pp_double[0][j], a1.stride, &ar.ptr.pp_double[0][j], ar.stride, ae_v_len(0,n-1)); if( ae_fp_less(v,(double)(0)) ) { ae_v_muld(&ar.ptr.pp_double[0][j], ar.stride, ae_v_len(0,n-1), -1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { *serrors = *serrors||ae_fp_greater(ae_fabs(a1.ptr.pp_double[i][j]-ar.ptr.pp_double[i][j], _state),threshold); } } } /* * Test indexes, transform vectors */ ae_vector_set_length(&lambdav, n-1+1, _state); for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } ae_matrix_set_length(&a1, n-1+1, n-1+1, _state); ae_matrix_set_length(&a2, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a2.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]; } } *runs = *runs+1; if( !smatrixtdevdi(&lambdav, e, n, 1, i1, i2, &a1, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } m = i2-i1+1; for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } if( distvals ) { ae_matrix_set_length(&ar, n-1+1, m-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a2.ptr.pp_double[i][0], 1, &zref.ptr.pp_double[0][i1+j], zref.stride, ae_v_len(0,n-1)); ar.ptr.pp_double[i][j] = v; } } for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a1.ptr.pp_double[0][j], a1.stride, &ar.ptr.pp_double[0][j], ar.stride, ae_v_len(0,n-1)); if( ae_fp_less(v,(double)(0)) ) { ae_v_muld(&ar.ptr.pp_double[0][j], ar.stride, ae_v_len(0,n-1), -1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { *serrors = *serrors||ae_fp_greater(ae_fabs(a1.ptr.pp_double[i][j]-ar.ptr.pp_double[i][j], _state),threshold); } } } /* * Test interval, do not transform vectors */ ae_vector_set_length(&lambdav, n-1+1, _state); for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } ae_matrix_set_length(&z, 0+1, 0+1, _state); *runs = *runs+1; if( !smatrixtdevdr(&lambdav, e, n, 2, a, b, &m, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } if( m!=i2-i1+1 ) { *failc = *failc+1; ae_frame_leave(_state); return; } for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } if( distvals ) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&z.ptr.pp_double[0][j], z.stride, &zref.ptr.pp_double[0][i1+j], zref.stride, ae_v_len(0,n-1)); if( ae_fp_less(v,(double)(0)) ) { ae_v_muld(&z.ptr.pp_double[0][j], z.stride, ae_v_len(0,n-1), -1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { *serrors = *serrors||ae_fp_greater(ae_fabs(z.ptr.pp_double[i][j]-zref.ptr.pp_double[i][i1+j], _state),threshold); } } } /* * Test indexes, do not transform vectors */ ae_vector_set_length(&lambdav, n-1+1, _state); for(i=0; i<=n-1; i++) { lambdav.ptr.p_double[i] = d->ptr.p_double[i]; } ae_matrix_set_length(&z, 0+1, 0+1, _state); *runs = *runs+1; if( !smatrixtdevdi(&lambdav, e, n, 2, i1, i2, &z, _state) ) { *failc = *failc+1; ae_frame_leave(_state); return; } m = i2-i1+1; for(k=0; k<=m-1; k++) { *serrors = *serrors||ae_fp_greater(ae_fabs(lambdav.ptr.p_double[k]-lambdaref.ptr.p_double[i1+k], _state),threshold); } if( distvals ) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&z.ptr.pp_double[0][j], z.stride, &zref.ptr.pp_double[0][i1+j], zref.stride, ae_v_len(0,n-1)); if( ae_fp_less(v,(double)(0)) ) { ae_v_muld(&z.ptr.pp_double[0][j], z.stride, ae_v_len(0,n-1), -1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { *serrors = *serrors||ae_fp_greater(ae_fabs(z.ptr.pp_double[i][j]-zref.ptr.pp_double[i][i1+j], _state),threshold); } } } ae_frame_leave(_state); } /************************************************************************* Non-symmetric problem *************************************************************************/ static void testevdunit_testnsevdproblem(/* Real */ ae_matrix* a, ae_int_t n, double threshold, ae_bool* nserrors, ae_state *_state) { ae_frame _frame_block; double mx; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t vjob; ae_bool needl; ae_bool needr; ae_vector wr0; ae_vector wi0; ae_vector wr1; ae_vector wi1; ae_vector wr0s; ae_vector wi0s; ae_vector wr1s; ae_vector wi1s; ae_matrix vl; ae_matrix vr; ae_vector vec1r; ae_vector vec1i; ae_vector vec2r; ae_vector vec2i; ae_vector vec3r; ae_vector vec3i; double curwr; double curwi; double vt; double tmp; double vnorm; ae_frame_make(_state, &_frame_block); ae_vector_init(&wr0, 0, DT_REAL, _state); ae_vector_init(&wi0, 0, DT_REAL, _state); ae_vector_init(&wr1, 0, DT_REAL, _state); ae_vector_init(&wi1, 0, DT_REAL, _state); ae_vector_init(&wr0s, 0, DT_REAL, _state); ae_vector_init(&wi0s, 0, DT_REAL, _state); ae_vector_init(&wr1s, 0, DT_REAL, _state); ae_vector_init(&wi1s, 0, DT_REAL, _state); ae_matrix_init(&vl, 0, 0, DT_REAL, _state); ae_matrix_init(&vr, 0, 0, DT_REAL, _state); ae_vector_init(&vec1r, 0, DT_REAL, _state); ae_vector_init(&vec1i, 0, DT_REAL, _state); ae_vector_init(&vec2r, 0, DT_REAL, _state); ae_vector_init(&vec2i, 0, DT_REAL, _state); ae_vector_init(&vec3r, 0, DT_REAL, _state); ae_vector_init(&vec3i, 0, DT_REAL, _state); ae_vector_set_length(&vec1r, n-1+1, _state); ae_vector_set_length(&vec2r, n-1+1, _state); ae_vector_set_length(&vec3r, n-1+1, _state); ae_vector_set_length(&vec1i, n-1+1, _state); ae_vector_set_length(&vec2i, n-1+1, _state); ae_vector_set_length(&vec3i, n-1+1, _state); ae_vector_set_length(&wr0s, n-1+1, _state); ae_vector_set_length(&wr1s, n-1+1, _state); ae_vector_set_length(&wi0s, n-1+1, _state); ae_vector_set_length(&wi1s, n-1+1, _state); mx = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(a->ptr.pp_double[i][j], _state),mx) ) { mx = ae_fabs(a->ptr.pp_double[i][j], _state); } } } if( ae_fp_eq(mx,(double)(0)) ) { mx = (double)(1); } /* * Load values-only */ if( !rmatrixevd(a, n, 0, &wr0, &wi0, &vl, &vr, _state) ) { seterrorflag(nserrors, ae_true, _state); ae_frame_leave(_state); return; } /* * Test different jobs */ for(vjob=1; vjob<=3; vjob++) { needr = vjob==1||vjob==3; needl = vjob==2||vjob==3; if( !rmatrixevd(a, n, vjob, &wr1, &wi1, &vl, &vr, _state) ) { seterrorflag(nserrors, ae_true, _state); ae_frame_leave(_state); return; } /* * Test values: * 1. sort by real part * 2. test */ ae_v_move(&wr0s.ptr.p_double[0], 1, &wr0.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&wi0s.ptr.p_double[0], 1, &wi0.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater(wr0s.ptr.p_double[j],wr0s.ptr.p_double[j+1]) ) { tmp = wr0s.ptr.p_double[j]; wr0s.ptr.p_double[j] = wr0s.ptr.p_double[j+1]; wr0s.ptr.p_double[j+1] = tmp; tmp = wi0s.ptr.p_double[j]; wi0s.ptr.p_double[j] = wi0s.ptr.p_double[j+1]; wi0s.ptr.p_double[j+1] = tmp; } } } ae_v_move(&wr1s.ptr.p_double[0], 1, &wr1.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&wi1s.ptr.p_double[0], 1, &wi1.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater(wr1s.ptr.p_double[j],wr1s.ptr.p_double[j+1]) ) { tmp = wr1s.ptr.p_double[j]; wr1s.ptr.p_double[j] = wr1s.ptr.p_double[j+1]; wr1s.ptr.p_double[j+1] = tmp; tmp = wi1s.ptr.p_double[j]; wi1s.ptr.p_double[j] = wi1s.ptr.p_double[j+1]; wi1s.ptr.p_double[j+1] = tmp; } } } for(i=0; i<=n-1; i++) { seterrorflag(nserrors, ae_fp_greater(ae_fabs(wr0s.ptr.p_double[i]-wr1s.ptr.p_double[i], _state),threshold), _state); seterrorflag(nserrors, ae_fp_greater(ae_fabs(wi0s.ptr.p_double[i]-wi1s.ptr.p_double[i], _state),threshold), _state); } /* * Test right vectors */ if( needr ) { k = 0; while(k<=n-1) { curwr = (double)(0); curwi = (double)(0); if( ae_fp_eq(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vr.ptr.pp_double[0][k], vr.stride, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { vec1i.ptr.p_double[i] = (double)(0); } curwr = wr1.ptr.p_double[k]; curwi = (double)(0); } if( ae_fp_greater(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vr.ptr.pp_double[0][k], vr.stride, ae_v_len(0,n-1)); ae_v_move(&vec1i.ptr.p_double[0], 1, &vr.ptr.pp_double[0][k+1], vr.stride, ae_v_len(0,n-1)); curwr = wr1.ptr.p_double[k]; curwi = wi1.ptr.p_double[k]; } if( ae_fp_less(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vr.ptr.pp_double[0][k-1], vr.stride, ae_v_len(0,n-1)); ae_v_moveneg(&vec1i.ptr.p_double[0], 1, &vr.ptr.pp_double[0][k], vr.stride, ae_v_len(0,n-1)); curwr = wr1.ptr.p_double[k]; curwi = wi1.ptr.p_double[k]; } vnorm = 0.0; for(i=0; i<=n-1; i++) { vt = ae_v_dotproduct(&a->ptr.pp_double[i][0], 1, &vec1r.ptr.p_double[0], 1, ae_v_len(0,n-1)); vec2r.ptr.p_double[i] = vt; vt = ae_v_dotproduct(&a->ptr.pp_double[i][0], 1, &vec1i.ptr.p_double[0], 1, ae_v_len(0,n-1)); vec2i.ptr.p_double[i] = vt; vnorm = vnorm+ae_sqr(vec1r.ptr.p_double[i], _state)+ae_sqr(vec1i.ptr.p_double[i], _state); } vnorm = ae_sqrt(vnorm, _state); ae_v_moved(&vec3r.ptr.p_double[0], 1, &vec1r.ptr.p_double[0], 1, ae_v_len(0,n-1), curwr); ae_v_subd(&vec3r.ptr.p_double[0], 1, &vec1i.ptr.p_double[0], 1, ae_v_len(0,n-1), curwi); ae_v_moved(&vec3i.ptr.p_double[0], 1, &vec1r.ptr.p_double[0], 1, ae_v_len(0,n-1), curwi); ae_v_addd(&vec3i.ptr.p_double[0], 1, &vec1i.ptr.p_double[0], 1, ae_v_len(0,n-1), curwr); seterrorflag(nserrors, ae_fp_less(vnorm,1.0E-3)||!ae_isfinite(vnorm, _state), _state); for(i=0; i<=n-1; i++) { seterrorflag(nserrors, ae_fp_greater(ae_fabs(vec2r.ptr.p_double[i]-vec3r.ptr.p_double[i], _state),threshold), _state); seterrorflag(nserrors, ae_fp_greater(ae_fabs(vec2i.ptr.p_double[i]-vec3i.ptr.p_double[i], _state),threshold), _state); } k = k+1; } } /* * Test left vectors */ curwr = (double)(0); curwi = (double)(0); if( needl ) { k = 0; while(k<=n-1) { if( ae_fp_eq(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vl.ptr.pp_double[0][k], vl.stride, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { vec1i.ptr.p_double[i] = (double)(0); } curwr = wr1.ptr.p_double[k]; curwi = (double)(0); } if( ae_fp_greater(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vl.ptr.pp_double[0][k], vl.stride, ae_v_len(0,n-1)); ae_v_move(&vec1i.ptr.p_double[0], 1, &vl.ptr.pp_double[0][k+1], vl.stride, ae_v_len(0,n-1)); curwr = wr1.ptr.p_double[k]; curwi = wi1.ptr.p_double[k]; } if( ae_fp_less(wi1.ptr.p_double[k],(double)(0)) ) { ae_v_move(&vec1r.ptr.p_double[0], 1, &vl.ptr.pp_double[0][k-1], vl.stride, ae_v_len(0,n-1)); ae_v_moveneg(&vec1i.ptr.p_double[0], 1, &vl.ptr.pp_double[0][k], vl.stride, ae_v_len(0,n-1)); curwr = wr1.ptr.p_double[k]; curwi = wi1.ptr.p_double[k]; } vnorm = 0.0; for(j=0; j<=n-1; j++) { vt = ae_v_dotproduct(&vec1r.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); vec2r.ptr.p_double[j] = vt; vt = ae_v_dotproduct(&vec1i.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); vec2i.ptr.p_double[j] = -vt; vnorm = vnorm+ae_sqr(vec1r.ptr.p_double[j], _state)+ae_sqr(vec1i.ptr.p_double[j], _state); } vnorm = ae_sqrt(vnorm, _state); ae_v_moved(&vec3r.ptr.p_double[0], 1, &vec1r.ptr.p_double[0], 1, ae_v_len(0,n-1), curwr); ae_v_addd(&vec3r.ptr.p_double[0], 1, &vec1i.ptr.p_double[0], 1, ae_v_len(0,n-1), curwi); ae_v_moved(&vec3i.ptr.p_double[0], 1, &vec1r.ptr.p_double[0], 1, ae_v_len(0,n-1), curwi); ae_v_addd(&vec3i.ptr.p_double[0], 1, &vec1i.ptr.p_double[0], 1, ae_v_len(0,n-1), -curwr); seterrorflag(nserrors, ae_fp_less(vnorm,1.0E-3)||!ae_isfinite(vnorm, _state), _state); for(i=0; i<=n-1; i++) { seterrorflag(nserrors, ae_fp_greater(ae_fabs(vec2r.ptr.p_double[i]-vec3r.ptr.p_double[i], _state),threshold), _state); seterrorflag(nserrors, ae_fp_greater(ae_fabs(vec2i.ptr.p_double[i]-vec3i.ptr.p_double[i], _state),threshold), _state); } k = k+1; } } } ae_frame_leave(_state); } /************************************************************************* Testing EVD subroutines for one N NOTES: * BIThreshold is a threshold for bisection-and-inverse-iteration subroutines. special threshold is needed because these subroutines may have much more larger error than QR-based algorithms. *************************************************************************/ static void testevdunit_testevdset(ae_int_t n, double threshold, double bithreshold, ae_int_t* failc, ae_int_t* runs, ae_bool* nserrors, ae_bool* serrors, ae_bool* herrors, ae_bool* tderrors, ae_bool* sbierrors, ae_bool* hbierrors, ae_bool* tdbierrors, ae_state *_state) { ae_frame _frame_block; ae_matrix ra; ae_matrix ral; ae_matrix rau; ae_matrix ca; ae_matrix cal; ae_matrix cau; ae_vector d; ae_vector e; ae_int_t i; ae_int_t j; ae_int_t mkind; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); ae_matrix_init(&ral, 0, 0, DT_REAL, _state); ae_matrix_init(&rau, 0, 0, DT_REAL, _state); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cal, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cau, 0, 0, DT_COMPLEX, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); /* * Test symmetric problems */ ae_matrix_set_length(&ra, n, n, _state); ae_matrix_set_length(&ral, n, n, _state); ae_matrix_set_length(&rau, n, n, _state); ae_matrix_set_length(&ca, n, n, _state); ae_matrix_set_length(&cal, n, n, _state); ae_matrix_set_length(&cau, n, n, _state); /* * Zero matrices */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testevdunit_rmatrixsymmetricsplit(&ra, n, &ral, &rau, _state); testevdunit_cmatrixhermitiansplit(&ca, n, &cal, &cau, _state); testevdunit_testsevdproblem(&ra, &ral, &rau, n, threshold, serrors, failc, runs, _state); testevdunit_testhevdproblem(&ca, &cal, &cau, n, threshold, herrors, failc, runs, _state); testevdunit_testsevdbiproblem(&ra, &ral, &rau, n, ae_false, bithreshold, sbierrors, failc, runs, _state); testevdunit_testhevdbiproblem(&ca, &cal, &cau, n, ae_false, bithreshold, hbierrors, failc, runs, _state); /* * Random matrix */ for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; ra.ptr.pp_double[j][i] = ra.ptr.pp_double[i][j]; ca.ptr.pp_complex[j][i] = ae_c_conj(ca.ptr.pp_complex[i][j], _state); } ra.ptr.pp_double[i][i] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][i] = ae_complex_from_d(2*ae_randomreal(_state)-1); } testevdunit_rmatrixsymmetricsplit(&ra, n, &ral, &rau, _state); testevdunit_cmatrixhermitiansplit(&ca, n, &cal, &cau, _state); testevdunit_testsevdproblem(&ra, &ral, &rau, n, threshold, serrors, failc, runs, _state); testevdunit_testhevdproblem(&ca, &cal, &cau, n, threshold, herrors, failc, runs, _state); /* * Random diagonally dominant matrix with distinct eigenvalues */ for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { ra.ptr.pp_double[i][j] = 0.1*(2*ae_randomreal(_state)-1)/n; ca.ptr.pp_complex[i][j].x = 0.1*(2*ae_randomreal(_state)-1)/n; ca.ptr.pp_complex[i][j].y = 0.1*(2*ae_randomreal(_state)-1)/n; ra.ptr.pp_double[j][i] = ra.ptr.pp_double[i][j]; ca.ptr.pp_complex[j][i] = ae_c_conj(ca.ptr.pp_complex[i][j], _state); } ra.ptr.pp_double[i][i] = 0.1*(2*ae_randomreal(_state)-1)+i; ca.ptr.pp_complex[i][i] = ae_complex_from_d(0.1*(2*ae_randomreal(_state)-1)+i); } testevdunit_rmatrixsymmetricsplit(&ra, n, &ral, &rau, _state); testevdunit_cmatrixhermitiansplit(&ca, n, &cal, &cau, _state); testevdunit_testsevdproblem(&ra, &ral, &rau, n, threshold, serrors, failc, runs, _state); testevdunit_testhevdproblem(&ca, &cal, &cau, n, threshold, herrors, failc, runs, _state); testevdunit_testsevdbiproblem(&ra, &ral, &rau, n, ae_true, bithreshold, sbierrors, failc, runs, _state); testevdunit_testhevdbiproblem(&ca, &cal, &cau, n, ae_true, bithreshold, hbierrors, failc, runs, _state); /* * Sparse matrices */ testevdunit_rmatrixfillsparsea(&ra, n, n, 0.995, _state); testevdunit_cmatrixfillsparsea(&ca, n, n, 0.995, _state); for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { ra.ptr.pp_double[j][i] = ra.ptr.pp_double[i][j]; ca.ptr.pp_complex[j][i] = ae_c_conj(ca.ptr.pp_complex[i][j], _state); } ca.ptr.pp_complex[i][i].y = (double)(0); } testevdunit_rmatrixsymmetricsplit(&ra, n, &ral, &rau, _state); testevdunit_cmatrixhermitiansplit(&ca, n, &cal, &cau, _state); testevdunit_testsevdproblem(&ra, &ral, &rau, n, threshold, serrors, failc, runs, _state); testevdunit_testhevdproblem(&ca, &cal, &cau, n, threshold, herrors, failc, runs, _state); testevdunit_testsevdbiproblem(&ra, &ral, &rau, n, ae_false, bithreshold, sbierrors, failc, runs, _state); testevdunit_testhevdbiproblem(&ca, &cal, &cau, n, ae_false, bithreshold, hbierrors, failc, runs, _state); /* * testing tridiagonal problems */ for(mkind=0; mkind<=7; mkind++) { ae_vector_set_length(&d, n, _state); if( n>1 ) { ae_vector_set_length(&e, n-1, _state); } if( mkind==0 ) { /* * Zero matrix */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = (double)(0); } } if( mkind==1 ) { /* * Diagonal matrix */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = (double)(0); } } if( mkind==2 ) { /* * Off-diagonal matrix */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } if( mkind==3 ) { /* * Dense matrix with blocks */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } j = 1; i = 2; while(j<=n-2) { e.ptr.p_double[j] = (double)(0); j = j+i; i = i+1; } } if( mkind==4 ) { /* * dense matrix */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } if( mkind==5 ) { /* * Diagonal matrix with distinct eigenvalues */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 0.1*(2*ae_randomreal(_state)-1)+i; } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = (double)(0); } } if( mkind==6 ) { /* * Off-diagonal matrix with distinct eigenvalues */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = 0.1*(2*ae_randomreal(_state)-1)+i+1; } } if( mkind==7 ) { /* * dense matrix with distinct eigenvalues */ for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 0.1*(2*ae_randomreal(_state)-1)+i+1; } for(i=0; i<=n-2; i++) { e.ptr.p_double[i] = 0.1*(2*ae_randomreal(_state)-1); } } testevdunit_testtdevdproblem(&d, &e, n, threshold, tderrors, _state); testevdunit_testtdevdbiproblem(&d, &e, n, (mkind==5||mkind==6)||mkind==7, bithreshold, tdbierrors, failc, runs, _state); } /* * Test non-symmetric problems */ /* * Test non-symmetric problems: zero, random, sparse matrices. */ ae_matrix_set_length(&ra, n, n, _state); ae_matrix_set_length(&ca, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testevdunit_testnsevdproblem(&ra, n, threshold, nserrors, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; ca.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } testevdunit_testnsevdproblem(&ra, n, threshold, nserrors, _state); testevdunit_rmatrixfillsparsea(&ra, n, n, 0.995, _state); testevdunit_cmatrixfillsparsea(&ca, n, n, 0.995, _state); testevdunit_testnsevdproblem(&ra, n, threshold, nserrors, _state); ae_frame_leave(_state); } static ae_int_t testmatgenunit_maxsvditerations = 60; static void testmatgenunit_unset2d(/* Real */ ae_matrix* a, ae_state *_state); static void testmatgenunit_unset2dc(/* Complex */ ae_matrix* a, ae_state *_state); static ae_bool testmatgenunit_isspd(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state); static ae_bool testmatgenunit_ishpd(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); static ae_bool testmatgenunit_testeult(ae_state *_state); static double testmatgenunit_svdcond(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); static ae_bool testmatgenunit_obsoletesvddecomposition(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* w, /* Real */ ae_matrix* v, ae_state *_state); static double testmatgenunit_extsign(double a, double b, ae_state *_state); static double testmatgenunit_mymax(double a, double b, ae_state *_state); static double testmatgenunit_pythag(double a, double b, ae_state *_state); ae_bool testmatgen(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix b; ae_matrix u; ae_matrix v; ae_matrix ca; ae_matrix cb; ae_matrix r1; ae_matrix r2; ae_matrix c1; ae_matrix c2; ae_vector w; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t passcount; ae_bool waserrors; double cond; double threshold; double vt; ae_complex ct; double minw; double maxw; ae_bool serr; ae_bool herr; ae_bool spderr; ae_bool hpderr; ae_bool rerr; ae_bool cerr; ae_bool eulerr; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cb, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&r1, 0, 0, DT_REAL, _state); ae_matrix_init(&r2, 0, 0, DT_REAL, _state); ae_matrix_init(&c1, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&c2, 0, 0, DT_COMPLEX, _state); ae_vector_init(&w, 0, DT_REAL, _state); rerr = ae_false; cerr = ae_false; serr = ae_false; herr = ae_false; spderr = ae_false; hpderr = ae_false; eulerr = ae_false; waserrors = ae_false; maxn = 20; passcount = 15; threshold = 1000*ae_machineepsilon; /* * Testing orthogonal */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { ae_matrix_set_length(&r1, n-1+1, 2*n-1+1, _state); ae_matrix_set_length(&r2, 2*n-1+1, n-1+1, _state); ae_matrix_set_length(&c1, n-1+1, 2*n-1+1, _state); ae_matrix_set_length(&c2, 2*n-1+1, n-1+1, _state); /* * Random orthogonal, real */ testmatgenunit_unset2d(&a, _state); testmatgenunit_unset2d(&b, _state); rmatrixrndorthogonal(n, &a, _state); rmatrixrndorthogonal(n, &b, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ vt = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &a.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } vt = ae_v_dotproduct(&b.ptr.pp_double[i][0], 1, &b.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } /* * test for difference in A and B */ if( n>=2 ) { rerr = rerr||ae_fp_eq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } /* * Random orthogonal, complex */ testmatgenunit_unset2dc(&ca, _state); testmatgenunit_unset2dc(&cb, _state); cmatrixrndorthogonal(n, &ca, _state); cmatrixrndorthogonal(n, &cb, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ ct = ae_v_cdotproduct(&ca.ptr.pp_complex[i][0], 1, "N", &ca.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } ct = ae_v_cdotproduct(&cb.ptr.pp_complex[i][0], 1, "N", &cb.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } /* * test for difference in A and B */ if( n>=2 ) { cerr = cerr||ae_c_eq(ca.ptr.pp_complex[i][j],cb.ptr.pp_complex[i][j]); } } } /* * From the right real tests: * 1. E*Q is orthogonal * 2. Q1<>Q2 (routine result is changing) * 3. (E E)'*Q = (Q' Q')' (correct handling of non-square matrices) */ testmatgenunit_unset2d(&a, _state); testmatgenunit_unset2d(&b, _state); ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_matrix_set_length(&b, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); b.ptr.pp_double[i][j] = (double)(0); } a.ptr.pp_double[i][i] = (double)(1); b.ptr.pp_double[i][i] = (double)(1); } rmatrixrndorthogonalfromtheright(&a, n, n, _state); rmatrixrndorthogonalfromtheright(&b, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ vt = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &a.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } vt = ae_v_dotproduct(&b.ptr.pp_double[i][0], 1, &b.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } /* * test for difference in A and B */ if( n>=2 ) { rerr = rerr||ae_fp_eq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { r2.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; r2.ptr.pp_double[i+n][j] = r2.ptr.pp_double[i][j]; } } rmatrixrndorthogonalfromtheright(&r2, 2*n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { rerr = rerr||ae_fp_greater(ae_fabs(r2.ptr.pp_double[i+n][j]-r2.ptr.pp_double[i][j], _state),threshold); } } /* * From the left real tests: * 1. Q*E is orthogonal * 2. Q1<>Q2 (routine result is changing) * 3. Q*(E E) = (Q Q) (correct handling of non-square matrices) */ testmatgenunit_unset2d(&a, _state); testmatgenunit_unset2d(&b, _state); ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_matrix_set_length(&b, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); b.ptr.pp_double[i][j] = (double)(0); } a.ptr.pp_double[i][i] = (double)(1); b.ptr.pp_double[i][i] = (double)(1); } rmatrixrndorthogonalfromtheleft(&a, n, n, _state); rmatrixrndorthogonalfromtheleft(&b, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ vt = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &a.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } vt = ae_v_dotproduct(&b.ptr.pp_double[i][0], 1, &b.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); if( i==j ) { rerr = rerr||ae_fp_greater(ae_fabs(vt-1, _state),threshold); } else { rerr = rerr||ae_fp_greater(ae_fabs(vt, _state),threshold); } /* * test for difference in A and B */ if( n>=2 ) { rerr = rerr||ae_fp_eq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { r1.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; r1.ptr.pp_double[i][j+n] = r1.ptr.pp_double[i][j]; } } rmatrixrndorthogonalfromtheleft(&r1, n, 2*n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { rerr = rerr||ae_fp_greater(ae_fabs(r1.ptr.pp_double[i][j]-r1.ptr.pp_double[i][j+n], _state),threshold); } } /* * From the right complex tests: * 1. E*Q is orthogonal * 2. Q1<>Q2 (routine result is changing) * 3. (E E)'*Q = (Q' Q')' (correct handling of non-square matrices) */ testmatgenunit_unset2dc(&ca, _state); testmatgenunit_unset2dc(&cb, _state); ae_matrix_set_length(&ca, n-1+1, n-1+1, _state); ae_matrix_set_length(&cb, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); cb.ptr.pp_complex[i][j] = ae_complex_from_i(0); } ca.ptr.pp_complex[i][i] = ae_complex_from_i(1); cb.ptr.pp_complex[i][i] = ae_complex_from_i(1); } cmatrixrndorthogonalfromtheright(&ca, n, n, _state); cmatrixrndorthogonalfromtheright(&cb, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ ct = ae_v_cdotproduct(&ca.ptr.pp_complex[i][0], 1, "N", &ca.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } ct = ae_v_cdotproduct(&cb.ptr.pp_complex[i][0], 1, "N", &cb.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } /* * test for difference in A and B */ cerr = cerr||ae_c_eq(ca.ptr.pp_complex[i][j],cb.ptr.pp_complex[i][j]); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { c2.ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); c2.ptr.pp_complex[i+n][j] = c2.ptr.pp_complex[i][j]; } } cmatrixrndorthogonalfromtheright(&c2, 2*n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub(c2.ptr.pp_complex[i+n][j],c2.ptr.pp_complex[i][j]), _state),threshold); } } /* * From the left complex tests: * 1. Q*E is orthogonal * 2. Q1<>Q2 (routine result is changing) * 3. Q*(E E) = (Q Q) (correct handling of non-square matrices) */ testmatgenunit_unset2dc(&ca, _state); testmatgenunit_unset2dc(&cb, _state); ae_matrix_set_length(&ca, n-1+1, n-1+1, _state); ae_matrix_set_length(&cb, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); cb.ptr.pp_complex[i][j] = ae_complex_from_i(0); } ca.ptr.pp_complex[i][i] = ae_complex_from_i(1); cb.ptr.pp_complex[i][i] = ae_complex_from_i(1); } cmatrixrndorthogonalfromtheleft(&ca, n, n, _state); cmatrixrndorthogonalfromtheleft(&cb, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { /* * orthogonality test */ ct = ae_v_cdotproduct(&ca.ptr.pp_complex[i][0], 1, "N", &ca.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } ct = ae_v_cdotproduct(&cb.ptr.pp_complex[i][0], 1, "N", &cb.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,n-1)); if( i==j ) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub_d(ct,1), _state),threshold); } else { cerr = cerr||ae_fp_greater(ae_c_abs(ct, _state),threshold); } /* * test for difference in A and B */ cerr = cerr||ae_c_eq(ca.ptr.pp_complex[i][j],cb.ptr.pp_complex[i][j]); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { c1.ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); c1.ptr.pp_complex[i][j+n] = c1.ptr.pp_complex[i][j]; } } cmatrixrndorthogonalfromtheleft(&c1, n, 2*n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { cerr = cerr||ae_fp_greater(ae_c_abs(ae_c_sub(c1.ptr.pp_complex[i][j],c1.ptr.pp_complex[i][j+n]), _state),threshold); } } } } /* * Testing GCond */ for(n=2; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { /* * real test */ testmatgenunit_unset2d(&a, _state); cond = ae_exp(ae_log((double)(1000), _state)*ae_randomreal(_state), _state); rmatrixrndcond(n, cond, &a, _state); ae_matrix_set_length(&b, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { b.ptr.pp_double[i][j] = a.ptr.pp_double[i-1][j-1]; } } if( testmatgenunit_obsoletesvddecomposition(&b, n, n, &w, &v, _state) ) { maxw = w.ptr.p_double[1]; minw = w.ptr.p_double[1]; for(i=2; i<=n; i++) { if( ae_fp_greater(w.ptr.p_double[i],maxw) ) { maxw = w.ptr.p_double[i]; } if( ae_fp_less(w.ptr.p_double[i],minw) ) { minw = w.ptr.p_double[i]; } } vt = maxw/minw/cond; if( ae_fp_greater(ae_fabs(ae_log(vt, _state), _state),ae_log(1+threshold, _state)) ) { rerr = ae_true; } } } } /* * Symmetric/SPD * N = 2 .. 30 */ for(n=2; n<=maxn; n++) { /* * SPD matrices */ for(pass=1; pass<=passcount; pass++) { /* * Generate A */ testmatgenunit_unset2d(&a, _state); cond = ae_exp(ae_log((double)(1000), _state)*ae_randomreal(_state), _state); spdmatrixrndcond(n, cond, &a, _state); /* * test condition number */ spderr = spderr||ae_fp_greater(testmatgenunit_svdcond(&a, n, _state)/cond-1,threshold); /* * test SPD */ spderr = spderr||!testmatgenunit_isspd(&a, n, ae_true, _state); /* * test that A is symmetic */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { spderr = spderr||ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-a.ptr.pp_double[j][i], _state),threshold); } } /* * test for difference between A and B (subsequent matrix) */ testmatgenunit_unset2d(&b, _state); spdmatrixrndcond(n, cond, &b, _state); if( n>=2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { spderr = spderr||ae_fp_eq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } } /* * HPD matrices */ for(pass=1; pass<=passcount; pass++) { /* * Generate A */ testmatgenunit_unset2dc(&ca, _state); cond = ae_exp(ae_log((double)(1000), _state)*ae_randomreal(_state), _state); hpdmatrixrndcond(n, cond, &ca, _state); /* * test HPD */ hpderr = hpderr||!testmatgenunit_ishpd(&ca, n, _state); /* * test that A is Hermitian */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { hpderr = hpderr||ae_fp_greater(ae_c_abs(ae_c_sub(ca.ptr.pp_complex[i][j],ae_c_conj(ca.ptr.pp_complex[j][i], _state)), _state),threshold); } } /* * test for difference between A and B (subsequent matrix) */ testmatgenunit_unset2dc(&cb, _state); hpdmatrixrndcond(n, cond, &cb, _state); if( n>=2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { hpderr = hpderr||ae_c_eq(ca.ptr.pp_complex[i][j],cb.ptr.pp_complex[i][j]); } } } } /* * Symmetric matrices */ for(pass=1; pass<=passcount; pass++) { /* * test condition number */ testmatgenunit_unset2d(&a, _state); cond = ae_exp(ae_log((double)(1000), _state)*ae_randomreal(_state), _state); smatrixrndcond(n, cond, &a, _state); serr = serr||ae_fp_greater(testmatgenunit_svdcond(&a, n, _state)/cond-1,threshold); /* * test for difference between A and B */ testmatgenunit_unset2d(&b, _state); smatrixrndcond(n, cond, &b, _state); if( n>=2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { serr = serr||ae_fp_eq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } } /* * Hermitian matrices */ for(pass=1; pass<=passcount; pass++) { /* * Generate A */ testmatgenunit_unset2dc(&ca, _state); cond = ae_exp(ae_log((double)(1000), _state)*ae_randomreal(_state), _state); hmatrixrndcond(n, cond, &ca, _state); /* * test that A is Hermitian */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { herr = herr||ae_fp_greater(ae_c_abs(ae_c_sub(ca.ptr.pp_complex[i][j],ae_c_conj(ca.ptr.pp_complex[j][i], _state)), _state),threshold); } } /* * test for difference between A and B (subsequent matrix) */ testmatgenunit_unset2dc(&cb, _state); hmatrixrndcond(n, cond, &cb, _state); if( n>=2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { herr = herr||ae_c_eq(ca.ptr.pp_complex[i][j],cb.ptr.pp_complex[i][j]); } } } } } /* * Test for symmetric matrices */ eulerr = testmatgenunit_testeult(_state); /* * report */ waserrors = (((((rerr||cerr)||serr)||spderr)||herr)||hpderr)||eulerr; if( !silent ) { printf("TESTING MATRIX GENERATOR\n"); printf("REAL TEST: "); if( !rerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("COMPLEX TEST: "); if( !cerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SYMMETRIC TEST: "); if( !serr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("HERMITIAN TEST: "); if( !herr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SPD TEST: "); if( !spderr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("HPD TEST: "); if( !hpderr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("TEST FOR SYMMETRIC MATRICES: "); if( !eulerr ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmatgen(ae_bool silent, ae_state *_state) { return testmatgen(silent, _state); } /************************************************************************* Unsets 2D array. *************************************************************************/ static void testmatgenunit_unset2d(/* Real */ ae_matrix* a, ae_state *_state) { ae_matrix_set_length(a, 0+1, 0+1, _state); a->ptr.pp_double[0][0] = 2*ae_randomreal(_state)-1; } /************************************************************************* Unsets 2D array. *************************************************************************/ static void testmatgenunit_unset2dc(/* Complex */ ae_matrix* a, ae_state *_state) { ae_matrix_set_length(a, 0+1, 0+1, _state); a->ptr.pp_complex[0][0] = ae_complex_from_d(2*ae_randomreal(_state)-1); } /************************************************************************* Test whether matrix is SPD *************************************************************************/ static ae_bool testmatgenunit_isspd(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t i; ae_int_t j; double ajj; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; /* * Test the input parameters. */ ae_assert(n>=0, "Error in SMatrixCholesky: incorrect function arguments", _state); /* * Quick return if possible */ result = ae_true; if( n<=0 ) { ae_frame_leave(_state); return result; } if( isupper ) { /* * Compute the Cholesky factorization A = U'*U. */ for(j=0; j<=n-1; j++) { /* * Compute U(J,J) and test for non-positive-definiteness. */ v = ae_v_dotproduct(&a->ptr.pp_double[0][j], a->stride, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1)); ajj = a->ptr.pp_double[j][j]-v; if( ae_fp_less_eq(ajj,(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } ajj = ae_sqrt(ajj, _state); a->ptr.pp_double[j][j] = ajj; /* * Compute elements J+1:N of row J. */ if( jptr.pp_double[0][i], a->stride, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1)); a->ptr.pp_double[j][i] = a->ptr.pp_double[j][i]-v; } v = 1/ajj; ae_v_muld(&a->ptr.pp_double[j][j+1], 1, ae_v_len(j+1,n-1), v); } } } else { /* * Compute the Cholesky factorization A = L*L'. */ for(j=0; j<=n-1; j++) { /* * Compute L(J,J) and test for non-positive-definiteness. */ v = ae_v_dotproduct(&a->ptr.pp_double[j][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,j-1)); ajj = a->ptr.pp_double[j][j]-v; if( ae_fp_less_eq(ajj,(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } ajj = ae_sqrt(ajj, _state); a->ptr.pp_double[j][j] = ajj; /* * Compute elements J+1:N of column J. */ if( jptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,j-1)); a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]-v; } v = 1/ajj; ae_v_muld(&a->ptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1), v); } } } ae_frame_leave(_state); return result; } /************************************************************************* Tests whether A is HPD *************************************************************************/ static ae_bool testmatgenunit_ishpd(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_int_t j; double ajj; ae_complex v; double r; ae_vector t; ae_vector t2; ae_vector t3; ae_int_t i; ae_matrix a1; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_vector_init(&t, 0, DT_COMPLEX, _state); ae_vector_init(&t2, 0, DT_COMPLEX, _state); ae_vector_init(&t3, 0, DT_COMPLEX, _state); ae_matrix_init(&a1, 0, 0, DT_COMPLEX, _state); ae_vector_set_length(&t, n-1+1, _state); ae_vector_set_length(&t2, n-1+1, _state); ae_vector_set_length(&t3, n-1+1, _state); result = ae_true; /* * Compute the Cholesky factorization A = U'*U. */ for(j=0; j<=n-1; j++) { /* * Compute U(J,J) and test for non-positive-definiteness. */ v = ae_v_cdotproduct(&a->ptr.pp_complex[0][j], a->stride, "Conj", &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,j-1)); ajj = ae_c_sub(a->ptr.pp_complex[j][j],v).x; if( ae_fp_less_eq(ajj,(double)(0)) ) { a->ptr.pp_complex[j][j] = ae_complex_from_d(ajj); result = ae_false; ae_frame_leave(_state); return result; } ajj = ae_sqrt(ajj, _state); a->ptr.pp_complex[j][j] = ae_complex_from_d(ajj); /* * Compute elements J+1:N-1 of row J. */ if( jptr.pp_complex[0][j], a->stride, "Conj", ae_v_len(0,j-1)); ae_v_cmove(&t3.ptr.p_complex[j+1], 1, &a->ptr.pp_complex[j][j+1], 1, "N", ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { v = ae_v_cdotproduct(&a->ptr.pp_complex[0][i], a->stride, "N", &t2.ptr.p_complex[0], 1, "N", ae_v_len(0,j-1)); t3.ptr.p_complex[i] = ae_c_sub(t3.ptr.p_complex[i],v); } ae_v_cmove(&a->ptr.pp_complex[j][j+1], 1, &t3.ptr.p_complex[j+1], 1, "N", ae_v_len(j+1,n-1)); r = 1/ajj; ae_v_cmuld(&a->ptr.pp_complex[j][j+1], 1, ae_v_len(j+1,n-1), r); } } ae_frame_leave(_state); return result; } /************************************************************************* The function check, that upper triangle from symmetric matrix is equal to lower triangle. *************************************************************************/ static ae_bool testmatgenunit_testeult(ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix b; double c; double range; double eps; ae_int_t n; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); eps = 2*ae_machineepsilon; range = 100*(2*ae_randomreal(_state)-1); for(n=1; n<=15; n++) { c = 900*ae_randomreal(_state)+100; /* * Generate symmetric matrix and check it */ smatrixrndcond(n, c, &a, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-a.ptr.pp_double[j][i], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } spdmatrixrndcond(n, c, &a, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-a.ptr.pp_double[j][i], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } hmatrixrndcond(n, c, &b, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].x-b.ptr.pp_complex[j][i].x, _state),eps)||ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].y+b.ptr.pp_complex[j][i].y, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } hpdmatrixrndcond(n, c, &b, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].x-b.ptr.pp_complex[j][i].x, _state),eps)||ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].y+b.ptr.pp_complex[j][i].y, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * Prepare symmetric matrix with real values */ for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_double[i][j] = range*(2*ae_randomreal(_state)-1); } } for(i=0; i<=n-2; i++) { for(j=i+1; j<=n-1; j++) { a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } smatrixrndmultiply(&a, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-a.ptr.pp_double[j][i], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * Prepare symmetric matrix with complex values */ for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { b.ptr.pp_complex[i][j].x = range*(2*ae_randomreal(_state)-1); if( i!=j ) { b.ptr.pp_complex[i][j].y = range*(2*ae_randomreal(_state)-1); } else { b.ptr.pp_complex[i][j].y = (double)(0); } } } for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { b.ptr.pp_complex[i][j].x = b.ptr.pp_complex[j][i].x; b.ptr.pp_complex[i][j].y = -b.ptr.pp_complex[j][i].y; } } hmatrixrndmultiply(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.pp_complex[i][i].y = (double)(0); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].x-b.ptr.pp_complex[j][i].x, _state),eps)||ae_fp_greater(ae_fabs(b.ptr.pp_complex[i][j].y+b.ptr.pp_complex[j][i].y, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* SVD condition number *************************************************************************/ static double testmatgenunit_svdcond(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_matrix a1; ae_matrix v; ae_vector w; ae_int_t i; ae_int_t j; double minw; double maxw; double result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_matrix_set_length(&a1, n+1, n+1, _state); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { a1.ptr.pp_double[i][j] = a->ptr.pp_double[i-1][j-1]; } } if( !testmatgenunit_obsoletesvddecomposition(&a1, n, n, &w, &v, _state) ) { result = (double)(0); ae_frame_leave(_state); return result; } minw = w.ptr.p_double[1]; maxw = w.ptr.p_double[1]; for(i=2; i<=n; i++) { if( ae_fp_less(w.ptr.p_double[i],minw) ) { minw = w.ptr.p_double[i]; } if( ae_fp_greater(w.ptr.p_double[i],maxw) ) { maxw = w.ptr.p_double[i]; } } result = maxw/minw; ae_frame_leave(_state); return result; } static ae_bool testmatgenunit_obsoletesvddecomposition(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_vector* w, /* Real */ ae_matrix* v, ae_state *_state) { ae_frame _frame_block; ae_int_t nm; ae_int_t minmn; ae_int_t l; ae_int_t k; ae_int_t j; ae_int_t jj; ae_int_t its; ae_int_t i; double z; double y; double x; double vscale; double s; double h; double g; double f; double c; double anorm; ae_vector rv1; ae_bool flag; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_clear(w); ae_matrix_clear(v); ae_vector_init(&rv1, 0, DT_REAL, _state); ae_vector_set_length(&rv1, n+1, _state); ae_vector_set_length(w, n+1, _state); ae_matrix_set_length(v, n+1, n+1, _state); result = ae_true; if( mptr.pp_double[k][i], _state); } if( ae_fp_neq(vscale,0.0) ) { for(k=i; k<=m; k++) { a->ptr.pp_double[k][i] = a->ptr.pp_double[k][i]/vscale; s = s+a->ptr.pp_double[k][i]*a->ptr.pp_double[k][i]; } f = a->ptr.pp_double[i][i]; g = -testmatgenunit_extsign(ae_sqrt(s, _state), f, _state); h = f*g-s; a->ptr.pp_double[i][i] = f-g; if( i!=n ) { for(j=l; j<=n; j++) { s = 0.0; for(k=i; k<=m; k++) { s = s+a->ptr.pp_double[k][i]*a->ptr.pp_double[k][j]; } f = s/h; for(k=i; k<=m; k++) { a->ptr.pp_double[k][j] = a->ptr.pp_double[k][j]+f*a->ptr.pp_double[k][i]; } } } for(k=i; k<=m; k++) { a->ptr.pp_double[k][i] = vscale*a->ptr.pp_double[k][i]; } } } w->ptr.p_double[i] = vscale*g; g = 0.0; s = 0.0; vscale = 0.0; if( i<=m&&i!=n ) { for(k=l; k<=n; k++) { vscale = vscale+ae_fabs(a->ptr.pp_double[i][k], _state); } if( ae_fp_neq(vscale,0.0) ) { for(k=l; k<=n; k++) { a->ptr.pp_double[i][k] = a->ptr.pp_double[i][k]/vscale; s = s+a->ptr.pp_double[i][k]*a->ptr.pp_double[i][k]; } f = a->ptr.pp_double[i][l]; g = -testmatgenunit_extsign(ae_sqrt(s, _state), f, _state); h = f*g-s; a->ptr.pp_double[i][l] = f-g; for(k=l; k<=n; k++) { rv1.ptr.p_double[k] = a->ptr.pp_double[i][k]/h; } if( i!=m ) { for(j=l; j<=m; j++) { s = 0.0; for(k=l; k<=n; k++) { s = s+a->ptr.pp_double[j][k]*a->ptr.pp_double[i][k]; } for(k=l; k<=n; k++) { a->ptr.pp_double[j][k] = a->ptr.pp_double[j][k]+s*rv1.ptr.p_double[k]; } } } for(k=l; k<=n; k++) { a->ptr.pp_double[i][k] = vscale*a->ptr.pp_double[i][k]; } } } anorm = testmatgenunit_mymax(anorm, ae_fabs(w->ptr.p_double[i], _state)+ae_fabs(rv1.ptr.p_double[i], _state), _state); } for(i=n; i>=1; i--) { if( iptr.pp_double[j][i] = a->ptr.pp_double[i][j]/a->ptr.pp_double[i][l]/g; } for(j=l; j<=n; j++) { s = 0.0; for(k=l; k<=n; k++) { s = s+a->ptr.pp_double[i][k]*v->ptr.pp_double[k][j]; } for(k=l; k<=n; k++) { v->ptr.pp_double[k][j] = v->ptr.pp_double[k][j]+s*v->ptr.pp_double[k][i]; } } } for(j=l; j<=n; j++) { v->ptr.pp_double[i][j] = 0.0; v->ptr.pp_double[j][i] = 0.0; } } v->ptr.pp_double[i][i] = 1.0; g = rv1.ptr.p_double[i]; l = i; } for(i=minmn; i>=1; i--) { l = i+1; g = w->ptr.p_double[i]; if( iptr.pp_double[i][j] = 0.0; } } if( ae_fp_neq(g,0.0) ) { g = 1.0/g; if( i!=n ) { for(j=l; j<=n; j++) { s = 0.0; for(k=l; k<=m; k++) { s = s+a->ptr.pp_double[k][i]*a->ptr.pp_double[k][j]; } f = s/a->ptr.pp_double[i][i]*g; for(k=i; k<=m; k++) { a->ptr.pp_double[k][j] = a->ptr.pp_double[k][j]+f*a->ptr.pp_double[k][i]; } } } for(j=i; j<=m; j++) { a->ptr.pp_double[j][i] = a->ptr.pp_double[j][i]*g; } } else { for(j=i; j<=m; j++) { a->ptr.pp_double[j][i] = 0.0; } } a->ptr.pp_double[i][i] = a->ptr.pp_double[i][i]+1.0; } nm = 0; for(k=n; k>=1; k--) { for(its=1; its<=testmatgenunit_maxsvditerations; its++) { flag = ae_true; for(l=k; l>=1; l--) { nm = l-1; if( ae_fp_eq(ae_fabs(rv1.ptr.p_double[l], _state)+anorm,anorm) ) { flag = ae_false; break; } if( ae_fp_eq(ae_fabs(w->ptr.p_double[nm], _state)+anorm,anorm) ) { break; } } if( flag ) { c = 0.0; s = 1.0; for(i=l; i<=k; i++) { f = s*rv1.ptr.p_double[i]; if( ae_fp_neq(ae_fabs(f, _state)+anorm,anorm) ) { g = w->ptr.p_double[i]; h = testmatgenunit_pythag(f, g, _state); w->ptr.p_double[i] = h; h = 1.0/h; c = g*h; s = -f*h; for(j=1; j<=m; j++) { y = a->ptr.pp_double[j][nm]; z = a->ptr.pp_double[j][i]; a->ptr.pp_double[j][nm] = y*c+z*s; a->ptr.pp_double[j][i] = -y*s+z*c; } } } } z = w->ptr.p_double[k]; if( l==k ) { if( ae_fp_less(z,0.0) ) { w->ptr.p_double[k] = -z; for(j=1; j<=n; j++) { v->ptr.pp_double[j][k] = -v->ptr.pp_double[j][k]; } } break; } if( its==testmatgenunit_maxsvditerations ) { result = ae_false; ae_frame_leave(_state); return result; } x = w->ptr.p_double[l]; nm = k-1; y = w->ptr.p_double[nm]; g = rv1.ptr.p_double[nm]; h = rv1.ptr.p_double[k]; f = ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g = testmatgenunit_pythag(f, (double)(1), _state); f = ((x-z)*(x+z)+h*(y/(f+testmatgenunit_extsign(g, f, _state))-h))/x; c = 1.0; s = 1.0; for(j=l; j<=nm; j++) { i = j+1; g = rv1.ptr.p_double[i]; y = w->ptr.p_double[i]; h = s*g; g = c*g; z = testmatgenunit_pythag(f, h, _state); rv1.ptr.p_double[j] = z; c = f/z; s = h/z; f = x*c+g*s; g = -x*s+g*c; h = y*s; y = y*c; for(jj=1; jj<=n; jj++) { x = v->ptr.pp_double[jj][j]; z = v->ptr.pp_double[jj][i]; v->ptr.pp_double[jj][j] = x*c+z*s; v->ptr.pp_double[jj][i] = -x*s+z*c; } z = testmatgenunit_pythag(f, h, _state); w->ptr.p_double[j] = z; if( ae_fp_neq(z,0.0) ) { z = 1.0/z; c = f*z; s = h*z; } f = c*g+s*y; x = -s*g+c*y; for(jj=1; jj<=m; jj++) { y = a->ptr.pp_double[jj][j]; z = a->ptr.pp_double[jj][i]; a->ptr.pp_double[jj][j] = y*c+z*s; a->ptr.pp_double[jj][i] = -y*s+z*c; } } rv1.ptr.p_double[l] = 0.0; rv1.ptr.p_double[k] = f; w->ptr.p_double[k] = x; } } ae_frame_leave(_state); return result; } static double testmatgenunit_extsign(double a, double b, ae_state *_state) { double result; if( ae_fp_greater_eq(b,(double)(0)) ) { result = ae_fabs(a, _state); } else { result = -ae_fabs(a, _state); } return result; } static double testmatgenunit_mymax(double a, double b, ae_state *_state) { double result; if( ae_fp_greater(a,b) ) { result = a; } else { result = b; } return result; } static double testmatgenunit_pythag(double a, double b, ae_state *_state) { double result; if( ae_fp_less(ae_fabs(a, _state),ae_fabs(b, _state)) ) { result = ae_fabs(b, _state)*ae_sqrt(1+ae_sqr(a/b, _state), _state); } else { result = ae_fabs(a, _state)*ae_sqrt(1+ae_sqr(b/a, _state), _state); } return result; } static void testsparseunit_initgenerator(ae_int_t m, ae_int_t n, ae_int_t matkind, ae_int_t triangle, sparsegenerator* g, ae_state *_state); static ae_bool testsparseunit_generatenext(sparsegenerator* g, /* Real */ ae_matrix* da, sparsematrix* sa, ae_state *_state); static void testsparseunit_createrandom(ae_int_t m, ae_int_t n, ae_int_t pkind, ae_int_t ckind, ae_int_t p0, ae_int_t p1, /* Real */ ae_matrix* da, sparsematrix* sa, ae_state *_state); static ae_bool testsparseunit_enumeratetest(ae_state *_state); static ae_bool testsparseunit_rewriteexistingtest(ae_state *_state); static void testsparseunit_testgetrow(ae_bool* err, ae_state *_state); static ae_bool testsparseunit_testconvertsm(ae_state *_state); static ae_bool testsparseunit_testgcmatrixtype(ae_state *_state); ae_bool testsparse(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool basicerrors; ae_bool linearerrors; ae_bool basicrnderrors; ae_bool level2unsymmetricerrors; ae_bool level2symmetricerrors; ae_bool level2triangularerrors; ae_bool level3unsymmetricerrors; ae_bool level3symmetricerrors; ae_bool linearserrors; ae_bool linearmmerrors; ae_bool linearsmmerrors; ae_bool getrowerrors; ae_bool copyerrors; ae_bool basiccopyerrors; ae_bool enumerateerrors; ae_bool rewriteexistingerr; ae_bool skserrors; ae_bool result; getrowerrors = ae_false; skserrors = skstest(_state); basicerrors = basicfunctest(_state)||testsparseunit_testgcmatrixtype(_state); basicrnderrors = basicfuncrandomtest(_state); linearerrors = linearfunctionstest(_state); level2unsymmetricerrors = testlevel2unsymmetric(_state); level2symmetricerrors = testlevel2symmetric(_state); level2triangularerrors = testlevel2triangular(_state); level3unsymmetricerrors = testlevel3unsymmetric(_state); level3symmetricerrors = testlevel3symmetric(_state); linearserrors = linearfunctionsstest(_state); linearmmerrors = linearfunctionsmmtest(_state); linearsmmerrors = linearfunctionssmmtest(_state); copyerrors = copyfunctest(ae_true, _state)||testsparseunit_testconvertsm(_state); basiccopyerrors = basiccopyfunctest(ae_true, _state); enumerateerrors = testsparseunit_enumeratetest(_state); rewriteexistingerr = testsparseunit_rewriteexistingtest(_state); testsparseunit_testgetrow(&getrowerrors, _state); /* * report */ waserrors = (((((((((((((((skserrors||getrowerrors)||basicerrors)||linearerrors)||basicrnderrors)||level2unsymmetricerrors)||level2symmetricerrors)||level2triangularerrors)||level3unsymmetricerrors)||level3symmetricerrors)||linearserrors)||linearmmerrors)||linearsmmerrors)||copyerrors)||basiccopyerrors)||enumerateerrors)||rewriteexistingerr; if( !silent ) { printf("TESTING SPARSE\n"); printf("STORAGE FORMATS:\n"); printf("* SKS: "); if( !skserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("OPERATIONS:\n"); printf("* GETROW: "); if( !getrowerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BLAS:\n"); printf("* LEVEL 2 GENERAL: "); if( !level2unsymmetricerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LEVEL 2 SYMMETRIC: "); if( !level2symmetricerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LEVEL 2 TRIANGULAR: "); if( !level2triangularerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LEVEL 3 GENERAL: "); if( !level3unsymmetricerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LEVEL 3 SYMMETRIC: "); if( !level3symmetricerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BASIC TEST: "); if( !basicerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("COPY TEST: "); if( !copyerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BASIC_COPY TEST: "); if( !basiccopyerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BASIC_RND TEST: "); if( !basicrnderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("LINEAR TEST: "); if( !linearerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("LINEAR TEST FOR SYMMETRIC MATRICES: "); if( !linearserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("LINEAR MxM TEST: "); if( !linearmmerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("LINEAR MxM TEST FOR SYMMETRIC MATRICES: "); if( !linearsmmerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("ENUMERATE TEST: "); if( !enumerateerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("REWRITE EXISTING TEST: "); if( !rewriteexistingerr ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsparse(ae_bool silent, ae_state *_state) { return testsparse(silent, _state); } /************************************************************************* Function for testing basic SKS functional. Returns True on errors, False on success. -- ALGLIB PROJECT -- Copyright 16.01.1014 by Bochkanov Sergey *************************************************************************/ ae_bool skstest(ae_state *_state) { ae_frame _frame_block; sparsematrix s0; sparsematrix s1; sparsematrix s2; sparsematrix s3; sparsematrix s4; sparsematrix s5; sparsematrix s6; ae_int_t n; ae_int_t nz; double pnz; ae_int_t i; ae_int_t j; ae_int_t t0; ae_int_t t1; ae_matrix a; ae_matrix wasenumerated; ae_vector d; ae_vector u; hqrndstate rs; double v0; double v1; ae_int_t uppercnt; ae_int_t lowercnt; ae_bool result; ae_frame_make(_state, &_frame_block); _sparsematrix_init(&s0, _state); _sparsematrix_init(&s1, _state); _sparsematrix_init(&s2, _state); _sparsematrix_init(&s3, _state); _sparsematrix_init(&s4, _state); _sparsematrix_init(&s5, _state); _sparsematrix_init(&s6, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&wasenumerated, 0, 0, DT_BOOL, _state); ae_vector_init(&d, 0, DT_INT, _state); ae_vector_init(&u, 0, DT_INT, _state); _hqrndstate_init(&rs, _state); result = ae_false; hqrndrandomize(&rs, _state); for(n=1; n<=20; n++) { nz = n*n-n; for(;;) { /* * Generate N*N matrix where probability of non-diagonal element * being non-zero is PNZ. We also generate D and U - subdiagonal * and superdiagonal profile sizes. */ if( n>1 ) { pnz = (double)nz/(double)(n*n-n); } else { pnz = 1.0; } ae_vector_set_length(&d, n, _state); ae_vector_set_length(&u, n, _state); for(i=0; i<=n-1; i++) { d.ptr.p_int[i] = 0; u.ptr.p_int[i] = 0; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j||ae_fp_less_eq(hqrnduniformr(&rs, _state),pnz) ) { a.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; if( ji1 ) { inc(&uppercnt, _state); } if( j1N * * with 50% probability to CRS or SKS, if M=N */ if( m!=n||ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); } else { sparsecopytosks(&sa, &s0, _state); } /* * Test SparseGet() for SA and S0 against matrix returned in A */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&sa, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&s0, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); } } /* * Test SparseMV */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x1, n, _state); for(j=0; j<=n-1; j++) { x0.ptr.p_double[j] = hqrnduniformr(&rs, _state)-0.5; x1.ptr.p_double[j] = x0.ptr.p_double[j]; } sparsemv(&s0, &x0, &y0, _state); seterrorflag(&result, y0.cntN * * with 50% probability to CRS or SKS, if M=N */ if( m!=n||ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); } else { sparsecopytosks(&sa, &s0, _state); } /* * Test SparseGet() for SA and S0 against matrix returned in A */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(&result, ae_fp_neq(sparseget(&sa, i, j, _state),a.ptr.pp_double[i][j]), _state); seterrorflag(&result, ae_fp_neq(sparseget(&s0, i, j, _state),a.ptr.pp_double[i][j]), _state); } } /* * Test SparseMV */ ae_matrix_set_length(&x0, n, k, _state); ae_matrix_set_length(&x1, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { x0.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; x1.ptr.pp_double[i][j] = x0.ptr.pp_double[i][j]; } } sparsemm(&s0, &x0, k, &y0, _state); seterrorflag(&result, y0.rows0 ) { isupper = ae_true; } testsparseunit_initgenerator(n, n, 0, triangletype, &g, _state); while(testsparseunit_generatenext(&g, &a, &sa, _state)) { /* * Convert SA to desired storage format: * * S0 stores unmodified copy * * S1 stores copy with unmodified triangle corresponding * to IsUpper and another triangle being spoiled by random * trash */ sparsecopytohash(&sa, &s1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { sparseset(&s1, i, j, hqrnduniformr(&rs, _state), _state); } } } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); sparseconverttocrs(&s1, _state); } else { sparsecopytosks(&sa, &s0, _state); sparseconverttosks(&s1, _state); } /* * Test SparseGet() for SA and S0 against matrix returned in A */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&sa, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&s0, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); seterrorflag(&result, (ji&&triangletype==-1)&&ae_fp_neq(sparseget(&s0, i, j, _state),(double)(0)), _state); } } /* * Before we proceed with testing, update empty triangle of A * with its copy from another part of the matrix. */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a.ptr.pp_double[i][j] = a.ptr.pp_double[j][i]; } } } /* * Test SparseSMV */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x1, n, _state); for(j=0; j<=n-1; j++) { x0.ptr.p_double[j] = hqrnduniformr(&rs, _state)-0.5; x1.ptr.p_double[j] = x0.ptr.p_double[j]; } sparsesmv(&s0, isupper, &x0, &y0, _state); seterrorflag(&result, y0.cnt0 ) { isupper = ae_true; } testsparseunit_initgenerator(n, n, 0, triangletype, &g, _state); while(testsparseunit_generatenext(&g, &a, &sa, _state)) { /* * Choose matrix width K */ k = 1+hqrnduniformi(&rs, 20, _state); /* * Convert SA to desired storage format: * * S0 stores unmodified copy * * S1 stores copy with unmodified triangle corresponding * to IsUpper and another triangle being spoiled by random * trash */ sparsecopytohash(&sa, &s1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { sparseset(&s1, i, j, hqrnduniformr(&rs, _state), _state); } } } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); sparseconverttocrs(&s1, _state); } else { sparsecopytosks(&sa, &s0, _state); sparseconverttosks(&s1, _state); } /* * Test SparseGet() for SA and S0 against matrix returned in A */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&sa, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&s0, i, j, _state)-a.ptr.pp_double[i][j], _state),eps), _state); seterrorflag(&result, (ji&&triangletype==-1)&&ae_fp_neq(sparseget(&s0, i, j, _state),(double)(0)), _state); } } /* * Before we proceed with testing, update empty triangle of A * with its copy from another part of the matrix. */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a.ptr.pp_double[i][j] = a.ptr.pp_double[j][i]; } } } /* * Test SparseSMM */ ae_matrix_set_length(&x0, n, k, _state); ae_matrix_set_length(&x1, n, k, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=k-1; j++) { x0.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; x1.ptr.pp_double[i][j] = x0.ptr.pp_double[i][j]; } } sparsesmm(&s0, isupper, &x0, k, &y0, _state); seterrorflag(&result, y0.rows0 ) { isupper = ae_true; } testsparseunit_initgenerator(n, n, 0, triangletype, &g, _state); while(testsparseunit_generatenext(&g, &a, &sa, _state)) { /* * Settings (IsUpper was already set, handle the rest) */ isunit = ae_fp_less(hqrnduniformr(&rs, _state),0.5); optype = hqrnduniformi(&rs, 2, _state); /* * Convert SA to desired storage format: * * S0 stores unmodified copy * * S1 stores copy with unmodified triangle corresponding * to IsUpper and another triangle being spoiled by random * trash */ sparsecopytohash(&sa, &s1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { sparseset(&s1, i, j, hqrnduniformr(&rs, _state), _state); } } } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); sparseconverttocrs(&s1, _state); } else { sparsecopytosks(&sa, &s0, _state); sparseconverttosks(&s1, _state); } /* * Generate "effective A" */ ae_matrix_set_length(&ea, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ea.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { i1 = i; j1 = j; if( optype==1 ) { swapi(&i1, &j1, _state); } ea.ptr.pp_double[i1][j1] = a.ptr.pp_double[i][j]; if( isunit&&i1==j1 ) { ea.ptr.pp_double[i1][j1] = 1.0; } } } } /* * Test SparseTRMV */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x1, n, _state); for(j=0; j<=n-1; j++) { x0.ptr.p_double[j] = hqrnduniformr(&rs, _state)-0.5; x1.ptr.p_double[j] = x0.ptr.p_double[j]; } sparsetrmv(&s0, isupper, isunit, optype, &x0, &y0, _state); seterrorflag(&result, y0.cnti&&!isupper) ) { sparseset(&s1, i, j, hqrnduniformr(&rs, _state), _state); } } } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { sparsecopytocrs(&sa, &s0, _state); sparseconverttocrs(&s1, _state); } else { sparsecopytosks(&sa, &s0, _state); sparseconverttosks(&s1, _state); } /* * Generate "effective A" and EY = inv(EA)*x0 */ ae_matrix_set_length(&ea, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ea.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { i1 = i; j1 = j; if( optype==1 ) { swapi(&i1, &j1, _state); } ea.ptr.pp_double[i1][j1] = a.ptr.pp_double[i][j]; if( isunit&&i1==j1 ) { ea.ptr.pp_double[i1][j1] = 1.0; } } } } ae_vector_set_length(&ey, n, _state); for(i=0; i<=n-1; i++) { ey.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; } ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x1, n, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&ea.ptr.pp_double[i][0], 1, &ey.ptr.p_double[0], 1, ae_v_len(0,n-1)); x0.ptr.p_double[i] = v; x1.ptr.p_double[i] = v; } /* * Test SparseTRSV */ sparsetrsv(&s0, isupper, isunit, optype, &x0, _state); seterrorflag(&result, x0.cnti1&&j1<=i1+2 ) { a.ptr.pp_double[i1][j1] = (double)(i1+j1+1); sparseset(&s, i1, j1, a.ptr.pp_double[i1][j1], _state); sparseadd(&s, i1, j1, (double)(0), _state); sparseset(&sss, i1, j1, a.ptr.pp_double[i1][j1], _state); } else { a.ptr.pp_double[i1][j1] = (double)(0); sparseset(&s, i1, j1, a.ptr.pp_double[i1][j1], _state); sparseadd(&s, i1, j1, (double)(0), _state); } /* * Check for SparseCreate */ sparsecopy(&s, &ss, _state); a0 = sparseget(&s, i1, j1, _state); a1 = sparseget(&ss, i1, j1, _state); if( ae_fp_neq(a0,a1) ) { if( !silent ) { printf("BasicCopyFuncTest::Report::SparseGet\n"); printf("S::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a0)); printf("SS::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a1)); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } /* * Check for SparseCreateCRS */ for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { sparsecopy(&sss, &ss, _state); a0 = sparseget(&sss, i1, j1, _state); a1 = sparseget(&ss, i1, j1, _state); if( ae_fp_neq(a0,a1) ) { if( !silent ) { printf("BasicCopyFuncTest::Report::SparseGet\n"); printf("S::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a0)); printf("SS::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a1)); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } /* * Check for Matrix with CRS type */ sparseconverttocrs(&s, _state); sparsecopy(&s, &ss, _state); for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { a0 = sparseget(&s, i1, j1, _state); a1 = sparseget(&ss, i1, j1, _state); if( ae_fp_neq(a0,a1) ) { if( !silent ) { printf("BasicCopyFuncTest::Report::SparseGet\n"); printf("S::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a0)); printf("SS::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a1)); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } } } if( !silent ) { printf(" TEST IS PASSED.\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing SparseCopy -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/ ae_bool copyfunctest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; sparsematrix s; sparsematrix ss; ae_int_t n; ae_int_t m; ae_int_t mtype; ae_int_t i; ae_int_t j; ae_int_t i1; ae_int_t j1; double lb; double rb; ae_matrix a; ae_vector x0; ae_vector x1; ae_vector ty; ae_vector tyt; ae_vector y; ae_vector yt; ae_vector y0; ae_vector yt0; ae_vector cpy; ae_vector cpyt; ae_vector cpy0; ae_vector cpyt0; double eps; double a0; double a1; ae_bool result; ae_frame_make(_state, &_frame_block); _sparsematrix_init(&s, _state); _sparsematrix_init(&ss, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&ty, 0, DT_REAL, _state); ae_vector_init(&tyt, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&yt, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&yt0, 0, DT_REAL, _state); ae_vector_init(&cpy, 0, DT_REAL, _state); ae_vector_init(&cpyt, 0, DT_REAL, _state); ae_vector_init(&cpy0, 0, DT_REAL, _state); ae_vector_init(&cpyt0, 0, DT_REAL, _state); /* * Accuracy */ eps = 1000*ae_machineepsilon; /* * Size of the matrix (m*n) */ n = 30; m = 30; /* * Left and right borders, limiting matrix values */ lb = (double)(-10); rb = (double)(10); /* * Test linear algebra functions for: * a) sparse matrix converted to CRS from Hash-Table * b) sparse matrix initially created as CRS */ for(i=1; i<=m-1; i++) { for(j=1; j<=n-1; j++) { for(mtype=0; mtype<=1; mtype++) { /* * Prepare test problem */ testsparseunit_createrandom(i, j, -1, mtype, -1, -1, &a, &s, _state); sparsecopy(&s, &ss, _state); /* * Initialize temporaries */ ae_vector_set_length(&ty, i, _state); ae_vector_set_length(&tyt, j, _state); for(i1=0; i1<=i-1; i1++) { ty.ptr.p_double[i1] = (double)(0); } for(i1=0; i1<=j-1; i1++) { tyt.ptr.p_double[i1] = (double)(0); } ae_vector_set_length(&x0, j, _state); ae_vector_set_length(&x1, i, _state); for(i1=0; i1<=j-1; i1++) { x0.ptr.p_double[i1] = (rb-lb)*ae_randomreal(_state)+lb; } for(i1=0; i1<=i-1; i1++) { x1.ptr.p_double[i1] = (rb-lb)*ae_randomreal(_state)+lb; } /* * Consider two cases: square matrix, and non-square matrix */ if( i!=j ) { /* * Searching true result */ for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { ty.ptr.p_double[i1] = ty.ptr.p_double[i1]+a.ptr.pp_double[i1][j1]*x0.ptr.p_double[j1]; tyt.ptr.p_double[j1] = tyt.ptr.p_double[j1]+a.ptr.pp_double[i1][j1]*x1.ptr.p_double[i1]; } } /* * Multiplication */ sparsemv(&s, &x0, &y, _state); sparsemtv(&s, &x1, &yt, _state); sparsemv(&ss, &x0, &cpy, _state); sparsemtv(&ss, &x1, &cpyt, _state); /* * Check for MV-result */ for(i1=0; i1<=i-1; i1++) { if( (ae_fp_greater_eq(ae_fabs(y.ptr.p_double[i1]-ty.ptr.p_double[i1], _state),eps)||ae_fp_greater_eq(ae_fabs(cpy.ptr.p_double[i1]-ty.ptr.p_double[i1], _state),eps))||ae_fp_neq(cpy.ptr.p_double[i1]-y.ptr.p_double[i1],(double)(0)) ) { if( !silent ) { printf("CopyFuncTest::Report::RES_MV\n"); printf("Y[%0d]=%0.5f; tY[%0d]=%0.5f\n", (int)(i1), (double)(y.ptr.p_double[i1]), (int)(i1), (double)(ty.ptr.p_double[i1])); printf("cpY[%0d]=%0.5f;\n", (int)(i1), (double)(cpy.ptr.p_double[i1])); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } /* * Check for MTV-result */ for(i1=0; i1<=j-1; i1++) { if( (ae_fp_greater_eq(ae_fabs(yt.ptr.p_double[i1]-tyt.ptr.p_double[i1], _state),eps)||ae_fp_greater_eq(ae_fabs(cpyt.ptr.p_double[i1]-tyt.ptr.p_double[i1], _state),eps))||ae_fp_neq(cpyt.ptr.p_double[i1]-yt.ptr.p_double[i1],(double)(0)) ) { if( !silent ) { printf("CopyFuncTest::Report::RES_MTV\n"); printf("Yt[%0d]=%0.5f; tYt[%0d]=%0.5f\n", (int)(i1), (double)(yt.ptr.p_double[i1]), (int)(i1), (double)(tyt.ptr.p_double[i1])); printf("cpYt[%0d]=%0.5f;\n", (int)(i1), (double)(cpyt.ptr.p_double[i1])); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } sparsecopy(&s, &ss, _state); for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { a0 = sparseget(&s, i1, j1, _state); a1 = sparseget(&ss, i1, j1, _state); if( ae_fp_neq(a0,a1) ) { if( !silent ) { printf("CopyFuncTest::Report::SparseGet\n"); printf("S::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a0)); printf("SS::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a1)); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } } else { /* * Searching true result */ for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { ty.ptr.p_double[i1] = ty.ptr.p_double[i1]+a.ptr.pp_double[i1][j1]*x0.ptr.p_double[j1]; tyt.ptr.p_double[j1] = tyt.ptr.p_double[j1]+a.ptr.pp_double[i1][j1]*x0.ptr.p_double[i1]; } } /* * Multiplication */ sparsemv(&s, &x0, &y, _state); sparsemtv(&s, &x0, &yt, _state); sparsemv2(&s, &x0, &y0, &yt0, _state); sparsemv(&ss, &x0, &cpy, _state); sparsemtv(&ss, &x0, &cpyt, _state); sparsemv2(&ss, &x0, &cpy0, &cpyt0, _state); /* * Check for MV2-result */ for(i1=0; i1<=i-1; i1++) { if( ((((ae_fp_greater_eq(ae_fabs(y0.ptr.p_double[i1]-ty.ptr.p_double[i1], _state),eps)||ae_fp_greater_eq(ae_fabs(yt0.ptr.p_double[i1]-tyt.ptr.p_double[i1], _state),eps))||ae_fp_greater_eq(ae_fabs(cpy0.ptr.p_double[i1]-ty.ptr.p_double[i1], _state),eps))||ae_fp_greater_eq(ae_fabs(cpyt0.ptr.p_double[i1]-tyt.ptr.p_double[i1], _state),eps))||ae_fp_neq(cpy0.ptr.p_double[i1]-y0.ptr.p_double[i1],(double)(0)))||ae_fp_neq(cpyt0.ptr.p_double[i1]-yt0.ptr.p_double[i1],(double)(0)) ) { if( !silent ) { printf("CopyFuncTest::Report::RES_MV2\n"); printf("Y0[%0d]=%0.5f; tY[%0d]=%0.5f\n", (int)(i1), (double)(y0.ptr.p_double[i1]), (int)(i1), (double)(ty.ptr.p_double[i1])); printf("Yt0[%0d]=%0.5f; tYt[%0d]=%0.5f\n", (int)(i1), (double)(yt0.ptr.p_double[i1]), (int)(i1), (double)(tyt.ptr.p_double[i1])); printf("cpY0[%0d]=%0.5f;\n", (int)(i1), (double)(cpy0.ptr.p_double[i1])); printf("cpYt0[%0d]=%0.5f;\n", (int)(i1), (double)(cpyt0.ptr.p_double[i1])); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } /* * Check for MV- and MTV-result by help MV2 */ for(i1=0; i1<=i-1; i1++) { if( ((ae_fp_greater(ae_fabs(y0.ptr.p_double[i1]-y.ptr.p_double[i1], _state),eps)||ae_fp_greater(ae_fabs(yt0.ptr.p_double[i1]-yt.ptr.p_double[i1], _state),eps))||ae_fp_greater(ae_fabs(cpy0.ptr.p_double[i1]-cpy.ptr.p_double[i1], _state),eps))||ae_fp_greater(ae_fabs(cpyt0.ptr.p_double[i1]-cpyt.ptr.p_double[i1], _state),eps) ) { if( !silent ) { printf("CopyFuncTest::Report::RES_MV_MVT\n"); printf("Y0[%0d]=%0.5f; Y[%0d]=%0.5f\n", (int)(i1), (double)(y0.ptr.p_double[i1]), (int)(i1), (double)(y.ptr.p_double[i1])); printf("Yt0[%0d]=%0.5f; Yt[%0d]=%0.5f\n", (int)(i1), (double)(yt0.ptr.p_double[i1]), (int)(i1), (double)(yt.ptr.p_double[i1])); printf("cpY0[%0d]=%0.5f; cpY[%0d]=%0.5f\n", (int)(i1), (double)(cpy0.ptr.p_double[i1]), (int)(i1), (double)(cpy.ptr.p_double[i1])); printf("cpYt0[%0d]=%0.5f; cpYt[%0d]=%0.5f\n", (int)(i1), (double)(cpyt0.ptr.p_double[i1]), (int)(i1), (double)(cpyt.ptr.p_double[i1])); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } sparsecopy(&s, &ss, _state); for(i1=0; i1<=i-1; i1++) { for(j1=0; j1<=j-1; j1++) { a0 = sparseget(&s, i1, j1, _state); a1 = sparseget(&ss, i1, j1, _state); if( ae_fp_neq(a0,a1) ) { if( !silent ) { printf("CopyFuncTest::Report::SparseGet\n"); printf("S::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a0)); printf("SS::[%0d,%0d]=%0.5f\n", (int)(i1), (int)(j1), (double)(a1)); printf(" TEST FAILED.\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } } } } } if( !silent ) { printf(" TEST IS PASSED.\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function initializes sparse matrix generator, which is used to generate a set of matrices with sequentially increasing sparsity. PARAMETERS: M, N - matrix size. If M=0, then matrix is square N*N. N and M must be small enough to store N*M dense matrix. MatKind - matrix properties: * 0 - general sparse (no structure) * 1 - general sparse, but diagonal is always present and non-zero * 2 - diagonally dominant, SPD Triangle - triangle being returned: * +1 - upper triangle * -1 - lower triangle * 0 - full matrix is returned OUTPUT PARAMETERS: G - generator A - matrix A in dense format SA - matrix A in sparse format (hash-table storage) *************************************************************************/ static void testsparseunit_initgenerator(ae_int_t m, ae_int_t n, ae_int_t matkind, ae_int_t triangle, sparsegenerator* g, ae_state *_state) { _sparsegenerator_clear(g); g->n = n; g->m = m; g->matkind = matkind; g->triangle = triangle; hqrndrandomize(&g->rs, _state); ae_vector_set_length(&g->rcs.ia, 5+1, _state); ae_vector_set_length(&g->rcs.ra, 1+1, _state); g->rcs.stage = -1; } static ae_bool testsparseunit_generatenext(sparsegenerator* g, /* Real */ ae_matrix* da, sparsematrix* sa, ae_state *_state) { ae_int_t n; ae_int_t m; ae_int_t nz; ae_int_t nzd; double pnz; ae_int_t i; ae_int_t j; double v; ae_bool result; ae_matrix_clear(da); _sparsematrix_clear(sa); /* * Reverse communication preparations * I know it looks ugly, but it works the same way * anywhere from C++ to Python. * * This code initializes locals by: * * random values determined during code * generation - on first subroutine call * * values from previous call - on subsequent calls */ if( g->rcs.stage>=0 ) { n = g->rcs.ia.ptr.p_int[0]; m = g->rcs.ia.ptr.p_int[1]; nz = g->rcs.ia.ptr.p_int[2]; nzd = g->rcs.ia.ptr.p_int[3]; i = g->rcs.ia.ptr.p_int[4]; j = g->rcs.ia.ptr.p_int[5]; pnz = g->rcs.ra.ptr.p_double[0]; v = g->rcs.ra.ptr.p_double[1]; } else { n = -983; m = -989; nz = -834; nzd = 900; i = -287; j = 364; pnz = 214; v = -338; } if( g->rcs.stage==0 ) { goto lbl_0; } if( g->rcs.stage==1 ) { goto lbl_1; } /* * Routine body */ n = g->n; if( g->m==0 ) { m = n; } else { m = g->m; } ae_assert(m>0&&n>0, "GenerateNext: incorrect N/M", _state); /* * Generate general sparse matrix */ if( g->matkind!=0 ) { goto lbl_2; } nz = n*m; lbl_4: if( ae_false ) { goto lbl_5; } /* * Generate dense N*N matrix where probability of element * being non-zero is PNZ. */ pnz = (double)nz/(double)(n*m); ae_matrix_set_length(&g->bufa, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_less_eq(hqrnduniformr(&g->rs, _state),pnz) ) { g->bufa.ptr.pp_double[i][j] = hqrnduniformr(&g->rs, _state)-0.5; } else { g->bufa.ptr.pp_double[i][j] = 0.0; } } } /* * Output matrix and RComm */ ae_matrix_set_length(da, m, n, _state); sparsecreate(m, n, ae_round(pnz*m*n, _state), sa, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&g->triangle<=0)||(j>=i&&g->triangle>=0) ) { da->ptr.pp_double[i][j] = g->bufa.ptr.pp_double[i][j]; sparseset(sa, i, j, g->bufa.ptr.pp_double[i][j], _state); } else { da->ptr.pp_double[i][j] = 0.0; } } } g->rcs.stage = 0; goto lbl_rcomm; lbl_0: /* * Increase problem sparcity and try one more time. * Stop after testing NZ=0. */ if( nz==0 ) { goto lbl_5; } nz = nz/2; goto lbl_4; lbl_5: result = ae_false; return result; lbl_2: /* * Generate general sparse matrix with non-zero diagonal */ if( g->matkind!=1 ) { goto lbl_6; } ae_assert(n==m, "GenerateNext: non-square matrix for MatKind=1", _state); nz = n*n-n; lbl_8: if( ae_false ) { goto lbl_9; } /* * Generate dense N*N matrix where probability of non-diagonal element * being non-zero is PNZ. */ if( n>1 ) { pnz = (double)nz/(double)(n*n-n); } else { pnz = (double)(1); } ae_matrix_set_length(&g->bufa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { do { g->bufa.ptr.pp_double[i][i] = hqrnduniformr(&g->rs, _state)-0.5; } while(ae_fp_eq(g->bufa.ptr.pp_double[i][i],(double)(0))); g->bufa.ptr.pp_double[i][i] = g->bufa.ptr.pp_double[i][i]+1.5*ae_sign(g->bufa.ptr.pp_double[i][i], _state); continue; } if( ae_fp_less_eq(hqrnduniformr(&g->rs, _state),pnz) ) { g->bufa.ptr.pp_double[i][j] = hqrnduniformr(&g->rs, _state)-0.5; } else { g->bufa.ptr.pp_double[i][j] = 0.0; } } } /* * Output matrix and RComm */ ae_matrix_set_length(da, n, n, _state); sparsecreate(n, n, ae_round(pnz*(n*n-n)+n, _state), sa, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&g->triangle<=0)||(j>=i&&g->triangle>=0) ) { da->ptr.pp_double[i][j] = g->bufa.ptr.pp_double[i][j]; sparseset(sa, i, j, g->bufa.ptr.pp_double[i][j], _state); } else { da->ptr.pp_double[i][j] = 0.0; } } } g->rcs.stage = 1; goto lbl_rcomm; lbl_1: /* * Increase problem sparcity and try one more time. * Stop after testing NZ=0. */ if( nz==0 ) { goto lbl_9; } nz = nz/2; goto lbl_8; lbl_9: result = ae_false; return result; lbl_6: ae_assert(ae_false, "Assertion failed", _state); result = ae_false; return result; /* * Saving state */ lbl_rcomm: result = ae_true; g->rcs.ia.ptr.p_int[0] = n; g->rcs.ia.ptr.p_int[1] = m; g->rcs.ia.ptr.p_int[2] = nz; g->rcs.ia.ptr.p_int[3] = nzd; g->rcs.ia.ptr.p_int[4] = i; g->rcs.ia.ptr.p_int[5] = j; g->rcs.ra.ptr.p_double[0] = pnz; g->rcs.ra.ptr.p_double[1] = v; return result; } /************************************************************************* This function creates random sparse matrix with some prescribed pattern. INPUT PARAMETERS: M - number of rows N - number of columns PKind - sparsity pattern: *-1 = pattern is chosen at random as well as P0/P1 * 0 = matrix with up to P0 non-zero elements at random locations (however, actual number of non-zero elements can be less than P0, and in fact can be zero) * 1 = band matrix with P0 non-zero elements below diagonal and P1 non-zero element above diagonal * 2 = matrix with random number of contiguous non-zero elements in the each row CKind - creation type: *-1 = CKind is chosen at random * 0 = matrix is created in Hash-Table format and converted to CRS representation * 1 = matrix is created in CRS format OUTPUT PARAMETERS: DA - dense representation of A, array[M,N] SA - sparse representation of A, in CRS format -- ALGLIB PROJECT -- Copyright 31.10.2011 by Bochkanov Sergey *************************************************************************/ static void testsparseunit_createrandom(ae_int_t m, ae_int_t n, ae_int_t pkind, ae_int_t ckind, ae_int_t p0, ae_int_t p1, /* Real */ ae_matrix* da, sparsematrix* sa, ae_state *_state) { ae_frame _frame_block; ae_int_t maxpkind; ae_int_t maxckind; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_vector c0; ae_vector c1; ae_vector rowsizes; ae_frame_make(_state, &_frame_block); ae_matrix_clear(da); _sparsematrix_clear(sa); ae_vector_init(&c0, 0, DT_INT, _state); ae_vector_init(&c1, 0, DT_INT, _state); ae_vector_init(&rowsizes, 0, DT_INT, _state); maxpkind = 2; maxckind = 1; ae_assert(m>=1, "CreateRandom: incorrect parameters", _state); ae_assert(n>=1, "CreateRandom: incorrect parameters", _state); ae_assert(pkind>=-1&&pkind<=maxpkind, "CreateRandom: incorrect parameters", _state); ae_assert(ckind>=-1&&ckind<=maxckind, "CreateRandom: incorrect parameters", _state); if( pkind==-1 ) { pkind = ae_randominteger(maxpkind+1, _state); if( pkind==0 ) { p0 = ae_randominteger(m*n, _state); } if( pkind==1 ) { p0 = ae_randominteger(ae_minint(m, n, _state), _state); p1 = ae_randominteger(ae_minint(m, n, _state), _state); } } if( ckind==-1 ) { ckind = ae_randominteger(maxckind+1, _state); } if( pkind==0 ) { /* * Matrix with elements at random locations */ ae_matrix_set_length(da, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { da->ptr.pp_double[i][j] = (double)(0); } } if( ckind==0 ) { /* * Create matrix in Hash format, convert to CRS */ sparsecreate(m, n, 1, sa, _state); for(k=0; k<=p0-1; k++) { i = ae_randominteger(m, _state); j = ae_randominteger(n, _state); v = (double)(ae_randominteger(17, _state)-8)/(double)8; if( ae_fp_greater(ae_randomreal(_state),0.5) ) { da->ptr.pp_double[i][j] = v; sparseset(sa, i, j, v, _state); } else { da->ptr.pp_double[i][j] = da->ptr.pp_double[i][j]+v; sparseadd(sa, i, j, v, _state); } } sparseconverttocrs(sa, _state); ae_frame_leave(_state); return; } if( ckind==1 ) { /* * Create matrix in CRS format */ for(k=0; k<=p0-1; k++) { i = ae_randominteger(m, _state); j = ae_randominteger(n, _state); v = (double)(ae_randominteger(17, _state)-8)/(double)8; da->ptr.pp_double[i][j] = v; } ae_vector_set_length(&rowsizes, m, _state); for(i=0; i<=m-1; i++) { rowsizes.ptr.p_int[i] = 0; for(j=0; j<=n-1; j++) { if( ae_fp_neq(da->ptr.pp_double[i][j],(double)(0)) ) { rowsizes.ptr.p_int[i] = rowsizes.ptr.p_int[i]+1; } } } sparsecreatecrs(m, n, &rowsizes, sa, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_neq(da->ptr.pp_double[i][j],(double)(0)) ) { sparseset(sa, i, j, da->ptr.pp_double[i][j], _state); } } } ae_frame_leave(_state); return; } ae_assert(ae_false, "CreateRandom: internal error", _state); } if( pkind==1 ) { /* * Band matrix */ ae_matrix_set_length(da, m, n, _state); ae_vector_set_length(&rowsizes, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { da->ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=m-1; i++) { for(j=ae_maxint(i-p0, 0, _state); j<=ae_minint(i+p1, n-1, _state); j++) { do { da->ptr.pp_double[i][j] = (double)(ae_randominteger(17, _state)-8)/(double)8; } while(ae_fp_eq(da->ptr.pp_double[i][j],(double)(0))); } rowsizes.ptr.p_int[i] = ae_maxint(ae_minint(i+p1, n-1, _state)-ae_maxint(i-p0, 0, _state)+1, 0, _state); } if( ckind==0 ) { sparsecreate(m, n, 1, sa, _state); } if( ckind==1 ) { sparsecreatecrs(m, n, &rowsizes, sa, _state); } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_neq(da->ptr.pp_double[i][j],(double)(0)) ) { sparseset(sa, i, j, da->ptr.pp_double[i][j], _state); } } } sparseconverttocrs(sa, _state); ae_frame_leave(_state); return; } if( pkind==2 ) { /* * Matrix with one contiguous sequence of non-zero elements per row */ ae_matrix_set_length(da, m, n, _state); ae_vector_set_length(&rowsizes, m, _state); ae_vector_set_length(&c0, m, _state); ae_vector_set_length(&c1, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { da->ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=m-1; i++) { c0.ptr.p_int[i] = ae_randominteger(n, _state); c1.ptr.p_int[i] = c0.ptr.p_int[i]+ae_randominteger(n-c0.ptr.p_int[i]+1, _state); rowsizes.ptr.p_int[i] = c1.ptr.p_int[i]-c0.ptr.p_int[i]; } for(i=0; i<=m-1; i++) { for(j=c0.ptr.p_int[i]; j<=c1.ptr.p_int[i]-1; j++) { do { da->ptr.pp_double[i][j] = (double)(ae_randominteger(17, _state)-8)/(double)8; } while(ae_fp_eq(da->ptr.pp_double[i][j],(double)(0))); } } if( ckind==0 ) { sparsecreate(m, n, 1, sa, _state); } if( ckind==1 ) { sparsecreatecrs(m, n, &rowsizes, sa, _state); } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_neq(da->ptr.pp_double[i][j],(double)(0)) ) { sparseset(sa, i, j, da->ptr.pp_double[i][j], _state); } } } sparseconverttocrs(sa, _state); ae_frame_leave(_state); return; } ae_frame_leave(_state); } /************************************************************************* This function does test for SparseEnumerate function. -- ALGLIB PROJECT -- Copyright 14.03.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool testsparseunit_enumeratetest(ae_state *_state) { ae_frame _frame_block; sparsematrix spa; ae_matrix a; ae_matrix ta; ae_int_t m; ae_int_t n; double r; double v; ae_int_t ne; ae_int_t t0; ae_int_t t1; ae_int_t counter; ae_int_t c; ae_int_t hashcrs; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _sparsematrix_init(&spa, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&ta, 0, 0, DT_BOOL, _state); r = 10.5; for(m=1; m<=30; m++) { for(n=1; n<=30; n++) { ne = 0; /* * Create matrix with non-zero elements inside the region: * 0<=In ) { seterrorflag(err, ae_true, _state); ae_frame_leave(_state); return; } for(j=0; j<=n-1; j++) { wasreturned.ptr.p_bool[j] = ae_false; } for(j=0; j<=nz-1; j++) { if( colidx.ptr.p_int[j]<0||colidx.ptr.p_int[j]>n ) { seterrorflag(err, ae_true, _state); ae_frame_leave(_state); return; } seterrorflag(err, j>0&&colidx.ptr.p_int[j]<=colidx.ptr.p_int[j-1], _state); seterrorflag(err, ae_fp_neq(vals.ptr.p_double[j],a.ptr.pp_double[i][colidx.ptr.p_int[j]])||ae_fp_neq(vals.ptr.p_double[j],sparseget(&s, i, colidx.ptr.p_int[j], _state)), _state); wasreturned.ptr.p_bool[colidx.ptr.p_int[j]] = ae_true; } for(j=0; j<=n-1; j++) { seterrorflag(err, ae_fp_neq(a.ptr.pp_double[i][j],(double)(0))&&!wasreturned.ptr.p_bool[j], _state); } } } } } ae_frame_leave(_state); } /************************************************************************* Test for SparseConvert functions(isn't tested ConvertToCRS function). The function create random dense and sparse matrices in CRS format. Then convert sparse matrix to some format by CONVERT_TO/COPY_TO functions, then it does some modification in matrices and compares that marices are identical. NOTE: Result of the function assigned to variable CopyErrors in unit test. -- ALGLIB PROJECT -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool testsparseunit_testconvertsm(ae_state *_state) { ae_frame _frame_block; sparsematrix s; sparsematrix cs; ae_matrix a; ae_int_t m; ae_int_t n; ae_int_t msize; ae_int_t nsize; ae_vector ner; double tmp; ae_int_t i; ae_int_t j; ae_int_t vartf; ae_bool result; ae_frame_make(_state, &_frame_block); _sparsematrix_init(&s, _state); _sparsematrix_init(&cs, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&ner, 0, DT_INT, _state); msize = 15; nsize = 15; for(m=1; m<=msize; m++) { for(n=1; n<=nsize; n++) { for(vartf=0; vartf<=2; vartf++) { ae_matrix_set_length(&a, m, n, _state); ae_vector_set_length(&ner, m, _state); for(i=0; i<=m-1; i++) { ner.ptr.p_int[i] = 0; for(j=0; j<=n-1; j++) { if( ae_randominteger(5, _state)==3 ) { ner.ptr.p_int[i] = ner.ptr.p_int[i]+1; a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { a.ptr.pp_double[i][j] = (double)(0); } } } /* * Create sparse matrix */ sparsecreatecrs(m, n, &ner, &s, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_neq(a.ptr.pp_double[i][j],(double)(0)) ) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; sparseset(&s, i, j, a.ptr.pp_double[i][j], _state); } } } /* * Set matrix type(we have to be sure that all formats * converted correctly) */ i = ae_randominteger(2, _state); if( i==0 ) { sparseconverttohash(&s, _state); } if( i==1 ) { sparseconverttocrs(&s, _state); } /* * Start test */ if( vartf==0 ) { sparseconverttohash(&s, _state); sparsecopy(&s, &cs, _state); } if( vartf==1 ) { sparsecopytohash(&s, &cs, _state); } if( vartf==2 ) { sparsecopytocrs(&s, &cs, _state); } /* * Change some elements in row */ if( vartf!=2 ) { for(i=0; i<=m-1; i++) { tmp = 2*ae_randomreal(_state)-1; j = ae_randominteger(n, _state); a.ptr.pp_double[i][j] = tmp; sparseset(&cs, i, j, tmp, _state); tmp = 2*ae_randomreal(_state)-1; j = ae_randominteger(n, _state); a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+tmp; sparseadd(&cs, i, j, tmp, _state); } } /* * Check that A is identical to S */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_neq(a.ptr.pp_double[i][j],sparseget(&cs, i, j, _state)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Test for check/get type functions. The function create sparse matrix, converts it to desired type then check this type. NOTE: Result of the function assigned to variable BasicErrors in unit test. -- ALGLIB PROJECT -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool testsparseunit_testgcmatrixtype(ae_state *_state) { ae_frame _frame_block; sparsematrix s; sparsematrix cs; ae_int_t m; ae_int_t n; ae_int_t msize; ae_int_t nsize; ae_bool result; ae_frame_make(_state, &_frame_block); _sparsematrix_init(&s, _state); _sparsematrix_init(&cs, _state); msize = 5; nsize = 5; for(m=1; m<=msize; m++) { for(n=1; n<=nsize; n++) { sparsecreate(m, n, 1, &s, _state); sparseconverttocrs(&s, _state); if( (sparseishash(&s, _state)||!sparseiscrs(&s, _state))||sparsegetmatrixtype(&s, _state)!=1 ) { result = ae_true; ae_frame_leave(_state); return result; } sparseconverttohash(&s, _state); if( (!sparseishash(&s, _state)||sparseiscrs(&s, _state))||sparsegetmatrixtype(&s, _state)!=0 ) { result = ae_true; ae_frame_leave(_state); return result; } sparsecopytocrs(&s, &cs, _state); if( (sparseishash(&cs, _state)||!sparseiscrs(&cs, _state))||sparsegetmatrixtype(&cs, _state)!=1 ) { result = ae_true; ae_frame_leave(_state); return result; } sparsecopytohash(&cs, &s, _state); if( (!sparseishash(&s, _state)||sparseiscrs(&s, _state))||sparsegetmatrixtype(&s, _state)!=0 ) { result = ae_true; ae_frame_leave(_state); return result; } } } result = ae_false; ae_frame_leave(_state); return result; } void _sparsegenerator_init(void* _p, ae_state *_state) { sparsegenerator *p = (sparsegenerator*)_p; ae_touch_ptr((void*)p); ae_matrix_init(&p->bufa, 0, 0, DT_REAL, _state); _hqrndstate_init(&p->rs, _state); _rcommstate_init(&p->rcs, _state); } void _sparsegenerator_init_copy(void* _dst, void* _src, ae_state *_state) { sparsegenerator *dst = (sparsegenerator*)_dst; sparsegenerator *src = (sparsegenerator*)_src; dst->n = src->n; dst->m = src->m; dst->matkind = src->matkind; dst->triangle = src->triangle; ae_matrix_init_copy(&dst->bufa, &src->bufa, _state); _hqrndstate_init_copy(&dst->rs, &src->rs, _state); _rcommstate_init_copy(&dst->rcs, &src->rcs, _state); } void _sparsegenerator_clear(void* _p) { sparsegenerator *p = (sparsegenerator*)_p; ae_touch_ptr((void*)p); ae_matrix_clear(&p->bufa); _hqrndstate_clear(&p->rs); _rcommstate_clear(&p->rcs); } void _sparsegenerator_destroy(void* _p) { sparsegenerator *p = (sparsegenerator*)_p; ae_touch_ptr((void*)p); ae_matrix_destroy(&p->bufa); _hqrndstate_destroy(&p->rs); _rcommstate_destroy(&p->rcs); } static void testtrfacunit_testcluproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* err, ae_bool* properr, ae_state *_state); static void testtrfacunit_testrluproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* err, ae_bool* properr, ae_state *_state); static void testtrfacunit_testdensecholeskyupdates(ae_bool* spdupderrorflag, ae_state *_state); ae_bool testtrfac(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix ra; ae_matrix ral; ae_matrix rau; ae_matrix ca; ae_matrix cal; ae_matrix cau; ae_int_t m; ae_int_t n; ae_int_t mx; ae_int_t maxmn; ae_int_t largemn; ae_int_t i; ae_int_t j; ae_complex vc; double vr; ae_bool waserrors; ae_bool dspderr; ae_bool sspderr; ae_bool hpderr; ae_bool rerr; ae_bool cerr; ae_bool properr; ae_bool dspdupderr; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); ae_matrix_init(&ral, 0, 0, DT_REAL, _state); ae_matrix_init(&rau, 0, 0, DT_REAL, _state); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cal, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cau, 0, 0, DT_COMPLEX, _state); rerr = ae_false; dspderr = ae_false; sspderr = ae_false; cerr = ae_false; hpderr = ae_false; properr = ae_false; dspdupderr = ae_false; waserrors = ae_false; maxmn = 4*ablasblocksize(&ra, _state)+1; largemn = 256; threshold = 1000*ae_machineepsilon*maxmn; /* * Sparse Cholesky */ sspderr = sparserealcholeskytest(_state); /* * Cholesky updates */ testtrfacunit_testdensecholeskyupdates(&dspdupderr, _state); /* * test LU: * * first, test on small-scale matrices * * then, perform several large-scale tests */ for(mx=1; mx<=maxmn; mx++) { /* * Initialize N/M, both are <=MX, * at least one of them is exactly equal to MX */ n = 1+ae_randominteger(mx, _state); m = 1+ae_randominteger(mx, _state); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { n = mx; } else { m = mx; } /* * First, test on zero matrix */ ae_matrix_set_length(&ra, m, n, _state); ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } testtrfacunit_testcluproblem(&ca, m, n, threshold, &cerr, &properr, _state); testtrfacunit_testrluproblem(&ra, m, n, threshold, &rerr, &properr, _state); /* * Second, random matrix with moderate condition number */ ae_matrix_set_length(&ra, m, n, _state); ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=ae_minint(m, n, _state)-1; i++) { ra.ptr.pp_double[i][i] = 1+10*ae_randomreal(_state); ca.ptr.pp_complex[i][i] = ae_complex_from_d(1+10*ae_randomreal(_state)); } cmatrixrndorthogonalfromtheleft(&ca, m, n, _state); cmatrixrndorthogonalfromtheright(&ca, m, n, _state); rmatrixrndorthogonalfromtheleft(&ra, m, n, _state); rmatrixrndorthogonalfromtheright(&ra, m, n, _state); testtrfacunit_testcluproblem(&ca, m, n, threshold, &cerr, &properr, _state); testtrfacunit_testrluproblem(&ra, m, n, threshold, &rerr, &properr, _state); } for(m=largemn-1; m<=largemn+1; m++) { for(n=largemn-1; n<=largemn+1; n++) { /* * Random matrix with moderate condition number */ ae_matrix_set_length(&ra, m, n, _state); ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ra.ptr.pp_double[i][j] = (double)(0); ca.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } for(i=0; i<=ae_minint(m, n, _state)-1; i++) { ra.ptr.pp_double[i][i] = 1+10*ae_randomreal(_state); ca.ptr.pp_complex[i][i] = ae_complex_from_d(1+10*ae_randomreal(_state)); } cmatrixrndorthogonalfromtheleft(&ca, m, n, _state); cmatrixrndorthogonalfromtheright(&ca, m, n, _state); rmatrixrndorthogonalfromtheleft(&ra, m, n, _state); rmatrixrndorthogonalfromtheright(&ra, m, n, _state); testtrfacunit_testcluproblem(&ca, m, n, threshold, &cerr, &properr, _state); testtrfacunit_testrluproblem(&ra, m, n, threshold, &rerr, &properr, _state); } } /* * Test Cholesky */ for(n=1; n<=maxmn; n++) { /* * Load CA (HPD matrix with low condition number), * CAL and CAU - its lower and upper triangles */ hpdmatrixrndcond(n, 1+50*ae_randomreal(_state), &ca, _state); ae_matrix_set_length(&cal, n, n, _state); ae_matrix_set_length(&cau, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { cal.ptr.pp_complex[i][j] = ae_complex_from_i(i); cau.ptr.pp_complex[i][j] = ae_complex_from_i(j); } } for(i=0; i<=n-1; i++) { ae_v_cmove(&cal.ptr.pp_complex[i][0], 1, &ca.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i)); ae_v_cmove(&cau.ptr.pp_complex[i][i], 1, &ca.ptr.pp_complex[i][i], 1, "N", ae_v_len(i,n-1)); } /* * Test HPDMatrixCholesky: * 1. it must leave upper (lower) part unchanged * 2. max(A-L*L^H) must be small */ if( hpdmatrixcholesky(&cal, n, ae_false, _state) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( j>i ) { hpderr = hpderr||ae_c_neq_d(cal.ptr.pp_complex[i][j],(double)(i)); } else { vc = ae_v_cdotproduct(&cal.ptr.pp_complex[i][0], 1, "N", &cal.ptr.pp_complex[j][0], 1, "Conj", ae_v_len(0,j)); hpderr = hpderr||ae_fp_greater(ae_c_abs(ae_c_sub(ca.ptr.pp_complex[i][j],vc), _state),threshold); } } } } else { hpderr = ae_true; } if( hpdmatrixcholesky(&cau, n, ae_true, _state) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ji ) { dspderr = dspderr||ae_fp_neq(ral.ptr.pp_double[i][j],(double)(i)); } else { vr = ae_v_dotproduct(&ral.ptr.pp_double[i][0], 1, &ral.ptr.pp_double[j][0], 1, ae_v_len(0,j)); dspderr = dspderr||ae_fp_greater(ae_fabs(ra.ptr.pp_double[i][j]-vr, _state),threshold); } } } } else { dspderr = ae_true; } if( spdmatrixcholesky(&rau, n, ae_true, _state) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( j1 ) { pnz = (double)nz/(double)(n*n-n); } else { pnz = 1.0; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { if( i==j ) { a.ptr.pp_double[i][i] = 1+hqrnduniformr(&rs, _state); continue; } if( ae_fp_less_eq(hqrnduniformr(&rs, _state),pnz) ) { a.ptr.pp_double[i][j] = offscale*(hqrnduniformr(&rs, _state)-0.5); a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } else { a.ptr.pp_double[i][j] = 0.0; a.ptr.pp_double[j][i] = 0.0; } } } /* * Problem statement */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); cfmt = ae_randominteger(maxfmt+1, _state); cord = ae_randominteger(maxord+1-minord, _state)+minord; /* * Create matrix is hash-based storage format, convert it to random storage format. */ sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&!isupper)||(j>=i&&isupper) ) { sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } } } sparseconvertto(&sa, hqrnduniformi(&rs, maxfmt+1, _state), _state); /* * Perform sparse Cholesky and make several tests: * * correctness of P0 and P1 (they are correct permutations and one is inverse of another) * * format of SC matches CFmt * * SC has correct size (exactly N*N) * * check that correct triangle is returned */ if( !sparsecholeskyx(&sa, n, isupper, &p0, &p1, cord, ae_randominteger(3, _state), cfmt, &sbuf, &sc, _state) ) { seterrorflag(&result, ae_true, _state); ae_frame_leave(_state); return result; } seterrorflag(&result, p0.cnt=n, _state); seterrorflag(&result, p1.ptr.p_int[i]>=n, _state); if( result ) { ae_frame_leave(_state); return result; } seterrorflag(&result, b1.ptr.p_bool[p0.ptr.p_int[i]], _state); b1.ptr.p_bool[p0.ptr.p_int[i]] = ae_true; seterrorflag(&result, p1.ptr.p_int[p0.ptr.p_int[i]]!=i, _state); } seterrorflag(&result, sparsegetmatrixtype(&sc, _state)!=cfmt, _state); seterrorflag(&result, sparsegetncols(&sc, _state)!=n, _state); seterrorflag(&result, sparsegetnrows(&sc, _state)!=n, _state); t0 = 0; t1 = 0; while(sparseenumerate(&sc, &t0, &t1, &i, &j, &v, _state)) { seterrorflag(&result, ji&&!isupper, _state); } /* * Now, test correctness of Cholesky decomposition itself. * We calculate U'*U (or L*L') and check at against permutation * of A given by P0. * * NOTE: we expect that only one triangle of SC is filled, * and another one is exactly zero. */ if( isupper ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = 0.0; for(k=0; k<=n-1; k++) { v = v+sparseget(&sc, k, j, _state)*sparseget(&sc, k, i, _state); } seterrorflag(&result, ae_fp_greater(ae_fabs(a.ptr.pp_double[p0.ptr.p_int[i]][p0.ptr.p_int[j]]-v, _state),tol), _state); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = 0.0; for(k=0; k<=n-1; k++) { v = v+sparseget(&sc, j, k, _state)*sparseget(&sc, i, k, _state); } seterrorflag(&result, ae_fp_greater(ae_fabs(a.ptr.pp_double[p0.ptr.p_int[i]][p0.ptr.p_int[j]]-v, _state),tol), _state); } } } /* * Increase problem sparcity and try one more time. * Stop after testing NZ=0. */ if( nz==0 ) { break; } nz = nz/2; } } /* * SparseCholeskySkyline test: performed for matrices * of all sizes in 1..20 and all sparcity percentages. */ for(n=1; n<=20; n++) { nz = n*n-n; for(;;) { /* * Choose IsUpper - main triangle to work with. * * Generate A - symmetric N*N matrix where probability of non-diagonal * element being non-zero is PNZ. Off-diagonal elements are set to * very small values, so positive definiteness is guaranteed. Full matrix * is generated. * * Additionally, we create A1 - same as A, but one of the triangles is * asymmetrically spoiled. If IsUpper is True, we spoil lower one, or vice versa. */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); if( n>1 ) { pnz = (double)nz/(double)(n*n-n); } else { pnz = 1.0; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { if( i==j ) { a.ptr.pp_double[i][i] = 1+hqrnduniformr(&rs, _state); continue; } if( ae_fp_less_eq(hqrnduniformr(&rs, _state),pnz) ) { a.ptr.pp_double[i][j] = offscale*(hqrnduniformr(&rs, _state)-0.5); a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } else { a.ptr.pp_double[i][j] = 0.0; a.ptr.pp_double[j][i] = 0.0; } } } ae_matrix_set_length(&a1, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&!isupper)||(j>=i&&isupper) ) { /* * Copy one triangle */ a1.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } else { /* * Form another sparse pattern in different triangle. */ if( ae_fp_less_eq(hqrnduniformr(&rs, _state),pnz) ) { a1.ptr.pp_double[i][j] = offscale*(hqrnduniformr(&rs, _state)-0.5); } else { a1.ptr.pp_double[i][j] = 0.0; } } } } /* * Create copies of A and A1 in hash-based storage format. * Only one triangle of A is copied, but A1 is copied fully. * Convert them to SKS */ sparsecreate(n, n, 0, &sa, _state); sparsecreate(n, n, 0, &sa1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&!isupper)||(j>=i&&isupper) ) { sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } sparseset(&sa1, i, j, a1.ptr.pp_double[i][j], _state); } } sparseconverttosks(&sa, _state); sparseconverttosks(&sa1, _state); /* * Call SparseCholeskySkyline() for SA and make several tests: * * check that it is still SKS * * check that it has correct size (exactly N*N) * * check that correct triangle is returned (and another one is unchanged - zero) * * check that it is correct Cholesky decomposition. * We calculate U'*U (or L*L') and check at against A. We expect * that only one triangle of SA is filled, and another one is * exactly zero. */ if( !sparsecholeskyskyline(&sa, n, isupper, _state) ) { seterrorflag(&result, ae_true, _state); ae_frame_leave(_state); return result; } seterrorflag(&result, !sparseissks(&sa, _state), _state); seterrorflag(&result, sparsegetncols(&sa, _state)!=n, _state); seterrorflag(&result, sparsegetnrows(&sa, _state)!=n, _state); t0 = 0; t1 = 0; while(sparseenumerate(&sa, &t0, &t1, &i, &j, &v, _state)) { seterrorflag(&result, ji&&!isupper, _state); } if( isupper ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = 0.0; for(k=0; k<=n-1; k++) { v = v+sparseget(&sa, k, j, _state)*sparseget(&sa, k, i, _state); } seterrorflag(&result, ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-v, _state),tol), _state); } } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = 0.0; for(k=0; k<=n-1; k++) { v = v+sparseget(&sa, j, k, _state)*sparseget(&sa, i, k, _state); } seterrorflag(&result, ae_fp_greater(ae_fabs(a.ptr.pp_double[i][j]-v, _state),tol), _state); } } } /* * Call SparseCholeskySkyline() for SA1 and make several tests: * * check that it is still SKS * * check that it has correct size (exactly N*N) * * check that factorized triangle matches contents of SA, * and another triangle was unchanged (matches contents of A1). */ if( !sparsecholeskyskyline(&sa1, n, isupper, _state) ) { seterrorflag(&result, ae_true, _state); ae_frame_leave(_state); return result; } seterrorflag(&result, !sparseissks(&sa1, _state), _state); seterrorflag(&result, sparsegetncols(&sa1, _state)!=n, _state); seterrorflag(&result, sparsegetnrows(&sa1, _state)!=n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j<=i&&!isupper)||(j>=i&&isupper) ) { seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&sa1, i, j, _state)-sparseget(&sa, i, j, _state), _state),10*ae_machineepsilon), _state); } else { seterrorflag(&result, ae_fp_greater(ae_fabs(sparseget(&sa1, i, j, _state)-a1.ptr.pp_double[i][j], _state),10*ae_machineepsilon), _state); } } } /* * Increase problem sparcity and try one more time. * Stop after testing NZ=0. */ if( nz==0 ) { break; } nz = nz/2; } } ae_frame_leave(_state); return result; } static void testtrfacunit_testcluproblem(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* err, ae_bool* properr, ae_state *_state) { ae_frame _frame_block; ae_matrix ca; ae_matrix cl; ae_matrix cu; ae_matrix ca2; ae_vector ct; ae_int_t i; ae_int_t j; ae_int_t minmn; ae_complex v; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cl, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cu, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ca2, 0, 0, DT_COMPLEX, _state); ae_vector_init(&ct, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); minmn = ae_minint(m, n, _state); /* * PLU test */ ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { ae_v_cmove(&ca.ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); } cmatrixplu(&ca, m, n, &p, _state); for(i=0; i<=minmn-1; i++) { if( p.ptr.p_int[i]=m ) { *properr = ae_true; ae_frame_leave(_state); return; } } ae_matrix_set_length(&cl, m, minmn, _state); for(j=0; j<=minmn-1; j++) { for(i=0; i<=j-1; i++) { cl.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } cl.ptr.pp_complex[j][j] = ae_complex_from_d(1.0); for(i=j+1; i<=m-1; i++) { cl.ptr.pp_complex[i][j] = ca.ptr.pp_complex[i][j]; } } ae_matrix_set_length(&cu, minmn, n, _state); for(i=0; i<=minmn-1; i++) { for(j=0; j<=i-1; j++) { cu.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } for(j=i; j<=n-1; j++) { cu.ptr.pp_complex[i][j] = ca.ptr.pp_complex[i][j]; } } ae_matrix_set_length(&ca2, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&cl.ptr.pp_complex[i][0], 1, "N", &cu.ptr.pp_complex[0][j], cu.stride, "N", ae_v_len(0,minmn-1)); ca2.ptr.pp_complex[i][j] = v; } } ae_vector_set_length(&ct, n, _state); for(i=minmn-1; i>=0; i--) { if( i!=p.ptr.p_int[i] ) { ae_v_cmove(&ct.ptr.p_complex[0], 1, &ca2.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); ae_v_cmove(&ca2.ptr.pp_complex[i][0], 1, &ca2.ptr.pp_complex[p.ptr.p_int[i]][0], 1, "N", ae_v_len(0,n-1)); ae_v_cmove(&ca2.ptr.pp_complex[p.ptr.p_int[i]][0], 1, &ct.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_c_abs(ae_c_sub(a->ptr.pp_complex[i][j],ca2.ptr.pp_complex[i][j]), _state),threshold); } } /* * LUP test */ ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { ae_v_cmove(&ca.ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); } cmatrixlup(&ca, m, n, &p, _state); for(i=0; i<=minmn-1; i++) { if( p.ptr.p_int[i]=n ) { *properr = ae_true; ae_frame_leave(_state); return; } } ae_matrix_set_length(&cl, m, minmn, _state); for(j=0; j<=minmn-1; j++) { for(i=0; i<=j-1; i++) { cl.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } for(i=j; i<=m-1; i++) { cl.ptr.pp_complex[i][j] = ca.ptr.pp_complex[i][j]; } } ae_matrix_set_length(&cu, minmn, n, _state); for(i=0; i<=minmn-1; i++) { for(j=0; j<=i-1; j++) { cu.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } cu.ptr.pp_complex[i][i] = ae_complex_from_d(1.0); for(j=i+1; j<=n-1; j++) { cu.ptr.pp_complex[i][j] = ca.ptr.pp_complex[i][j]; } } ae_matrix_set_length(&ca2, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&cl.ptr.pp_complex[i][0], 1, "N", &cu.ptr.pp_complex[0][j], cu.stride, "N", ae_v_len(0,minmn-1)); ca2.ptr.pp_complex[i][j] = v; } } ae_vector_set_length(&ct, m, _state); for(i=minmn-1; i>=0; i--) { if( i!=p.ptr.p_int[i] ) { ae_v_cmove(&ct.ptr.p_complex[0], 1, &ca2.ptr.pp_complex[0][i], ca2.stride, "N", ae_v_len(0,m-1)); ae_v_cmove(&ca2.ptr.pp_complex[0][i], ca2.stride, &ca2.ptr.pp_complex[0][p.ptr.p_int[i]], ca2.stride, "N", ae_v_len(0,m-1)); ae_v_cmove(&ca2.ptr.pp_complex[0][p.ptr.p_int[i]], ca2.stride, &ct.ptr.p_complex[0], 1, "N", ae_v_len(0,m-1)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_c_abs(ae_c_sub(a->ptr.pp_complex[i][j],ca2.ptr.pp_complex[i][j]), _state),threshold); } } ae_frame_leave(_state); } static void testtrfacunit_testrluproblem(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, double threshold, ae_bool* err, ae_bool* properr, ae_state *_state) { ae_frame _frame_block; ae_matrix ca; ae_matrix cl; ae_matrix cu; ae_matrix ca2; ae_vector ct; ae_int_t i; ae_int_t j; ae_int_t minmn; double v; ae_vector p; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ca, 0, 0, DT_REAL, _state); ae_matrix_init(&cl, 0, 0, DT_REAL, _state); ae_matrix_init(&cu, 0, 0, DT_REAL, _state); ae_matrix_init(&ca2, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); minmn = ae_minint(m, n, _state); /* * PLU test */ ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { ae_v_move(&ca.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } rmatrixplu(&ca, m, n, &p, _state); for(i=0; i<=minmn-1; i++) { if( p.ptr.p_int[i]=m ) { *properr = ae_true; ae_frame_leave(_state); return; } } ae_matrix_set_length(&cl, m, minmn, _state); for(j=0; j<=minmn-1; j++) { for(i=0; i<=j-1; i++) { cl.ptr.pp_double[i][j] = 0.0; } cl.ptr.pp_double[j][j] = 1.0; for(i=j+1; i<=m-1; i++) { cl.ptr.pp_double[i][j] = ca.ptr.pp_double[i][j]; } } ae_matrix_set_length(&cu, minmn, n, _state); for(i=0; i<=minmn-1; i++) { for(j=0; j<=i-1; j++) { cu.ptr.pp_double[i][j] = 0.0; } for(j=i; j<=n-1; j++) { cu.ptr.pp_double[i][j] = ca.ptr.pp_double[i][j]; } } ae_matrix_set_length(&ca2, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&cl.ptr.pp_double[i][0], 1, &cu.ptr.pp_double[0][j], cu.stride, ae_v_len(0,minmn-1)); ca2.ptr.pp_double[i][j] = v; } } ae_vector_set_length(&ct, n, _state); for(i=minmn-1; i>=0; i--) { if( i!=p.ptr.p_int[i] ) { ae_v_move(&ct.ptr.p_double[0], 1, &ca2.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); ae_v_move(&ca2.ptr.pp_double[i][0], 1, &ca2.ptr.pp_double[p.ptr.p_int[i]][0], 1, ae_v_len(0,n-1)); ae_v_move(&ca2.ptr.pp_double[p.ptr.p_int[i]][0], 1, &ct.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(a->ptr.pp_double[i][j]-ca2.ptr.pp_double[i][j], _state),threshold); } } /* * LUP test */ ae_matrix_set_length(&ca, m, n, _state); for(i=0; i<=m-1; i++) { ae_v_move(&ca.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } rmatrixlup(&ca, m, n, &p, _state); for(i=0; i<=minmn-1; i++) { if( p.ptr.p_int[i]=n ) { *properr = ae_true; ae_frame_leave(_state); return; } } ae_matrix_set_length(&cl, m, minmn, _state); for(j=0; j<=minmn-1; j++) { for(i=0; i<=j-1; i++) { cl.ptr.pp_double[i][j] = 0.0; } for(i=j; i<=m-1; i++) { cl.ptr.pp_double[i][j] = ca.ptr.pp_double[i][j]; } } ae_matrix_set_length(&cu, minmn, n, _state); for(i=0; i<=minmn-1; i++) { for(j=0; j<=i-1; j++) { cu.ptr.pp_double[i][j] = 0.0; } cu.ptr.pp_double[i][i] = 1.0; for(j=i+1; j<=n-1; j++) { cu.ptr.pp_double[i][j] = ca.ptr.pp_double[i][j]; } } ae_matrix_set_length(&ca2, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&cl.ptr.pp_double[i][0], 1, &cu.ptr.pp_double[0][j], cu.stride, ae_v_len(0,minmn-1)); ca2.ptr.pp_double[i][j] = v; } } ae_vector_set_length(&ct, m, _state); for(i=minmn-1; i>=0; i--) { if( i!=p.ptr.p_int[i] ) { ae_v_move(&ct.ptr.p_double[0], 1, &ca2.ptr.pp_double[0][i], ca2.stride, ae_v_len(0,m-1)); ae_v_move(&ca2.ptr.pp_double[0][i], ca2.stride, &ca2.ptr.pp_double[0][p.ptr.p_int[i]], ca2.stride, ae_v_len(0,m-1)); ae_v_move(&ca2.ptr.pp_double[0][p.ptr.p_int[i]], ca2.stride, &ct.ptr.p_double[0], 1, ae_v_len(0,m-1)); } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(a->ptr.pp_double[i][j]-ca2.ptr.pp_double[i][j], _state),threshold); } } ae_frame_leave(_state); } /************************************************************************* Function for testing dense Cholesky updates Sets error flag to True on errors, does not change it on success. -- ALGLIB PROJECT -- Copyright 16.01.1014 by Bochkanov Sergey *************************************************************************/ static void testtrfacunit_testdensecholeskyupdates(ae_bool* spdupderrorflag, ae_state *_state) { ae_frame _frame_block; ae_int_t n; double pfix; ae_matrix a0; ae_matrix a1; ae_vector u; ae_vector fix; ae_int_t i; ae_int_t j; ae_bool isupper; double tol; ae_vector bufr; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a0, 0, 0, DT_REAL, _state); ae_matrix_init(&a1, 0, 0, DT_REAL, _state); ae_vector_init(&u, 0, DT_REAL, _state); ae_vector_init(&fix, 0, DT_BOOL, _state); ae_vector_init(&bufr, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Settings */ tol = 1.0E-8; /* * Test rank-1 updates * * For each matrix size in 1..30 select sparse update vector with probability of element * being non-zero equal to 1/2. */ for(n=1; n<=30; n++) { /* * Generate two matrices A0=A1, fill one triangle with SPD matrix, * another one with trash. Prepare vector U. */ isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); spdmatrixrndcond(n, 1.0E4, &a0, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a0.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } ae_matrix_set_length(&a1, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = a0.ptr.pp_double[i][j]; } } ae_vector_set_length(&u, n, _state); for(i=0; i<=n-1; i++) { if( ae_fp_less_eq(hqrnduniformr(&rs, _state),0.5) ) { u.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; } else { u.ptr.p_double[i] = (double)(0); } } /* * Factorize and compare: * * A0 is factorized as follows: first with full Cholesky, then * we call SPDMatrixCholeskyUpdateAdd1 * * A1 is transformed explicitly before factorization with full Cholesky * * We randomly test either SPDMatrixCholeskyUpdateFix() or its * buffered version, SPDMatrixCholeskyUpdateFixBuf() */ seterrorflag(spdupderrorflag, !spdmatrixcholesky(&a0, n, isupper, _state), _state); if( *spdupderrorflag ) { ae_frame_leave(_state); return; } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { spdmatrixcholeskyupdateadd1(&a0, n, isupper, &u, _state); } else { spdmatrixcholeskyupdateadd1buf(&a0, n, isupper, &u, &bufr, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { a1.ptr.pp_double[i][j] = a1.ptr.pp_double[i][j]+u.ptr.p_double[i]*u.ptr.p_double[j]; } } } seterrorflag(spdupderrorflag, !spdmatrixcholesky(&a1, n, isupper, _state), _state); if( *spdupderrorflag ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(spdupderrorflag, ae_fp_greater(ae_fabs(a0.ptr.pp_double[i][j]-a1.ptr.pp_double[i][j], _state),tol), _state); } } } /* * Test variable fixing functions. * * For each matrix size in 1..30 select PFix - probability of each variable being fixed, * and perform test. */ for(n=1; n<=30; n++) { /* * Generate two matrices A0=A1, fill one triangle with SPD matrix, * another one with trash. Prepare vector Fix. */ pfix = (double)hqrnduniformi(&rs, n+1, _state)/(double)n; isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); spdmatrixrndcond(n, 1.0E4, &a0, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a0.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } ae_matrix_set_length(&a1, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a1.ptr.pp_double[i][j] = a0.ptr.pp_double[i][j]; } } ae_vector_set_length(&fix, n, _state); for(i=0; i<=n-1; i++) { fix.ptr.p_bool[i] = ae_fp_less_eq(hqrnduniformr(&rs, _state),pfix); } /* * Factorize and compare: * * A0 is factorized as follows: first with full Cholesky, then * variables are fixed with SPDMatrixCholeskyUpdateFix * * A1 is fixed explicitly before factorization with full Cholesky * * We randomly test either SPDMatrixCholeskyUpdateFix() or its * buffered version, SPDMatrixCholeskyUpdateFixBuf() */ seterrorflag(spdupderrorflag, !spdmatrixcholesky(&a0, n, isupper, _state), _state); if( *spdupderrorflag ) { ae_frame_leave(_state); return; } if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { spdmatrixcholeskyupdatefixbuf(&a0, n, isupper, &fix, &bufr, _state); } else { spdmatrixcholeskyupdatefix(&a0, n, isupper, &fix, _state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { if( fix.ptr.p_bool[i]||fix.ptr.p_bool[j] ) { if( i==j ) { a1.ptr.pp_double[i][j] = (double)(1); } else { a1.ptr.pp_double[i][j] = (double)(0); } } } } } seterrorflag(spdupderrorflag, !spdmatrixcholesky(&a1, n, isupper, _state), _state); if( *spdupderrorflag ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { seterrorflag(spdupderrorflag, ae_fp_greater(ae_fabs(a0.ptr.pp_double[i][j]-a1.ptr.pp_double[i][j], _state),tol), _state); } } } ae_frame_leave(_state); } /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testtrlinsolve(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t maxmn; ae_int_t passcount; double threshold; ae_matrix aeffective; ae_matrix aparam; ae_vector xe; ae_vector b; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t cnts; ae_int_t cntu; ae_int_t cntt; ae_int_t cntm; ae_bool waserrors; ae_bool isupper; ae_bool istrans; ae_bool isunit; double v; double s; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&aeffective, 0, 0, DT_REAL, _state); ae_matrix_init(&aparam, 0, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); waserrors = ae_false; maxmn = 15; passcount = 15; threshold = 1000*ae_machineepsilon; /* * Different problems */ for(n=1; n<=maxmn; n++) { ae_matrix_set_length(&aeffective, n-1+1, n-1+1, _state); ae_matrix_set_length(&aparam, n-1+1, n-1+1, _state); ae_vector_set_length(&xe, n-1+1, _state); ae_vector_set_length(&b, n-1+1, _state); for(pass=1; pass<=passcount; pass++) { for(cnts=0; cnts<=1; cnts++) { for(cntu=0; cntu<=1; cntu++) { for(cntt=0; cntt<=1; cntt++) { for(cntm=0; cntm<=2; cntm++) { isupper = cnts==0; isunit = cntu==0; istrans = cntt==0; /* * Skip meaningless combinations of parameters: * (matrix is singular) AND (matrix is unit diagonal) */ if( cntm==2&&isunit ) { continue; } /* * Clear matrices */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { aeffective.ptr.pp_double[i][j] = (double)(0); aparam.ptr.pp_double[i][j] = (double)(0); } } /* * Prepare matrices */ if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { aeffective.ptr.pp_double[i][j] = 0.9*(2*ae_randomreal(_state)-1); aparam.ptr.pp_double[i][j] = aeffective.ptr.pp_double[i][j]; } aeffective.ptr.pp_double[i][i] = (2*ae_randominteger(2, _state)-1)*(0.8+ae_randomreal(_state)); aparam.ptr.pp_double[i][i] = aeffective.ptr.pp_double[i][i]; } } else { for(i=0; i<=n-1; i++) { for(j=0; j<=i; j++) { aeffective.ptr.pp_double[i][j] = 0.9*(2*ae_randomreal(_state)-1); aparam.ptr.pp_double[i][j] = aeffective.ptr.pp_double[i][j]; } aeffective.ptr.pp_double[i][i] = (2*ae_randominteger(2, _state)-1)*(0.8+ae_randomreal(_state)); aparam.ptr.pp_double[i][i] = aeffective.ptr.pp_double[i][i]; } } if( isunit ) { for(i=0; i<=n-1; i++) { aeffective.ptr.pp_double[i][i] = (double)(1); aparam.ptr.pp_double[i][i] = (double)(0); } } if( istrans ) { if( isupper ) { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { aeffective.ptr.pp_double[j][i] = aeffective.ptr.pp_double[i][j]; aeffective.ptr.pp_double[i][j] = (double)(0); } } } else { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { aeffective.ptr.pp_double[i][j] = aeffective.ptr.pp_double[j][i]; aeffective.ptr.pp_double[j][i] = (double)(0); } } } } /* * Prepare task, solve, compare */ for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&aeffective.ptr.pp_double[i][0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = v; } rmatrixtrsafesolve(&aparam, n, &b, &s, isupper, istrans, isunit, _state); ae_v_muld(&xe.ptr.p_double[0], 1, ae_v_len(0,n-1), s); ae_v_sub(&xe.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&xe.ptr.p_double[0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_sqrt(v, _state); waserrors = waserrors||ae_fp_greater(v,threshold); } } } } } } /* * report */ if( !silent ) { printf("TESTING RMatrixTRSafeSolve\n"); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testtrlinsolve(ae_bool silent, ae_state *_state) { return testtrlinsolve(silent, _state); } static void testsafesolveunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state); static void testsafesolveunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state); /************************************************************************* Main unittest subroutine *************************************************************************/ ae_bool testsafesolve(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t maxmn; double threshold; ae_bool rerrors; ae_bool cerrors; ae_bool waserrors; ae_bool isupper; ae_int_t trans; ae_bool isunit; double scalea; double growth; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t j1; ae_int_t j2; ae_complex cv; ae_matrix ca; ae_matrix cea; ae_matrix ctmpa; ae_vector cxs; ae_vector cxe; double rv; ae_matrix ra; ae_matrix rea; ae_matrix rtmpa; ae_vector rxs; ae_vector rxe; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ca, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cea, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ctmpa, 0, 0, DT_COMPLEX, _state); ae_vector_init(&cxs, 0, DT_COMPLEX, _state); ae_vector_init(&cxe, 0, DT_COMPLEX, _state); ae_matrix_init(&ra, 0, 0, DT_REAL, _state); ae_matrix_init(&rea, 0, 0, DT_REAL, _state); ae_matrix_init(&rtmpa, 0, 0, DT_REAL, _state); ae_vector_init(&rxs, 0, DT_REAL, _state); ae_vector_init(&rxe, 0, DT_REAL, _state); maxmn = 30; threshold = 100000*ae_machineepsilon; rerrors = ae_false; cerrors = ae_false; waserrors = ae_false; /* * Different problems: general tests */ for(n=1; n<=maxmn; n++) { /* * test complex solver with well-conditioned matrix: * 1. generate A: fill off-diagonal elements with small values, * diagonal elements are filled with larger values * 2. generate 'effective' A * 3. prepare task (exact X is stored in CXE, right part - in CXS), * solve and compare CXS and CXE */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); trans = ae_randominteger(3, _state); isunit = ae_fp_greater(ae_randomreal(_state),0.5); scalea = ae_randomreal(_state)+0.5; ae_matrix_set_length(&ca, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { ca.ptr.pp_complex[i][j].x = (2*ae_randominteger(2, _state)-1)*(5+ae_randomreal(_state)); ca.ptr.pp_complex[i][j].y = (2*ae_randominteger(2, _state)-1)*(5+ae_randomreal(_state)); } else { ca.ptr.pp_complex[i][j].x = 0.2*ae_randomreal(_state)-0.1; ca.ptr.pp_complex[i][j].y = 0.2*ae_randomreal(_state)-0.1; } } } testsafesolveunit_cmatrixmakeacopy(&ca, n, n, &ctmpa, _state); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = 0; j2 = i-1; } else { j1 = i+1; j2 = n-1; } for(j=j1; j<=j2; j++) { ctmpa.ptr.pp_complex[i][j] = ae_complex_from_i(0); } if( isunit ) { ctmpa.ptr.pp_complex[i][i] = ae_complex_from_i(1); } } ae_matrix_set_length(&cea, n, n, _state); for(i=0; i<=n-1; i++) { if( trans==0 ) { ae_v_cmoved(&cea.ptr.pp_complex[i][0], 1, &ctmpa.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1), scalea); } if( trans==1 ) { ae_v_cmoved(&cea.ptr.pp_complex[0][i], cea.stride, &ctmpa.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1), scalea); } if( trans==2 ) { ae_v_cmoved(&cea.ptr.pp_complex[0][i], cea.stride, &ctmpa.ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,n-1), scalea); } } ae_vector_set_length(&cxe, n, _state); for(i=0; i<=n-1; i++) { cxe.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cxe.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&cxs, n, _state); for(i=0; i<=n-1; i++) { cv = ae_v_cdotproduct(&cea.ptr.pp_complex[i][0], 1, "N", &cxe.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); cxs.ptr.p_complex[i] = cv; } if( cmatrixscaledtrsafesolve(&ca, scalea, n, &cxs, isupper, trans, isunit, ae_sqrt(ae_maxrealnumber, _state), _state) ) { for(i=0; i<=n-1; i++) { cerrors = cerrors||ae_fp_greater(ae_c_abs(ae_c_sub(cxs.ptr.p_complex[i],cxe.ptr.p_complex[i]), _state),threshold); } } else { cerrors = ae_true; } /* * same with real */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); trans = ae_randominteger(2, _state); isunit = ae_fp_greater(ae_randomreal(_state),0.5); scalea = ae_randomreal(_state)+0.5; ae_matrix_set_length(&ra, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { ra.ptr.pp_double[i][j] = (2*ae_randominteger(2, _state)-1)*(5+ae_randomreal(_state)); } else { ra.ptr.pp_double[i][j] = 0.2*ae_randomreal(_state)-0.1; } } } testsafesolveunit_rmatrixmakeacopy(&ra, n, n, &rtmpa, _state); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = 0; j2 = i-1; } else { j1 = i+1; j2 = n-1; } for(j=j1; j<=j2; j++) { rtmpa.ptr.pp_double[i][j] = (double)(0); } if( isunit ) { rtmpa.ptr.pp_double[i][i] = (double)(1); } } ae_matrix_set_length(&rea, n, n, _state); for(i=0; i<=n-1; i++) { if( trans==0 ) { ae_v_moved(&rea.ptr.pp_double[i][0], 1, &rtmpa.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), scalea); } if( trans==1 ) { ae_v_moved(&rea.ptr.pp_double[0][i], rea.stride, &rtmpa.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), scalea); } } ae_vector_set_length(&rxe, n, _state); for(i=0; i<=n-1; i++) { rxe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rxs, n, _state); for(i=0; i<=n-1; i++) { rv = ae_v_dotproduct(&rea.ptr.pp_double[i][0], 1, &rxe.ptr.p_double[0], 1, ae_v_len(0,n-1)); rxs.ptr.p_double[i] = rv; } if( rmatrixscaledtrsafesolve(&ra, scalea, n, &rxs, isupper, trans, isunit, ae_sqrt(ae_maxrealnumber, _state), _state) ) { for(i=0; i<=n-1; i++) { rerrors = rerrors||ae_fp_greater(ae_fabs(rxs.ptr.p_double[i]-rxe.ptr.p_double[i], _state),threshold); } } else { rerrors = ae_true; } } /* * Special test with diagonal ill-conditioned matrix: * * ability to solve it when resulting growth is less than threshold * * ability to stop solve when resulting growth is greater than threshold * * A = diag(1, 1/growth) * b = (1, 0.5) */ n = 2; growth = (double)(10); ae_matrix_set_length(&ca, n, n, _state); ca.ptr.pp_complex[0][0] = ae_complex_from_i(1); ca.ptr.pp_complex[0][1] = ae_complex_from_i(0); ca.ptr.pp_complex[1][0] = ae_complex_from_i(0); ca.ptr.pp_complex[1][1] = ae_complex_from_d(1/growth); ae_vector_set_length(&cxs, n, _state); cxs.ptr.p_complex[0] = ae_complex_from_d(1.0); cxs.ptr.p_complex[1] = ae_complex_from_d(0.5); cerrors = cerrors||!cmatrixscaledtrsafesolve(&ca, 1.0, n, &cxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(3, _state), ae_false, 1.05*ae_maxreal(ae_c_abs(cxs.ptr.p_complex[1], _state)*growth, 1.0, _state), _state); cerrors = cerrors||!cmatrixscaledtrsafesolve(&ca, 1.0, n, &cxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(3, _state), ae_false, 0.95*ae_maxreal(ae_c_abs(cxs.ptr.p_complex[1], _state)*growth, 1.0, _state), _state); ae_matrix_set_length(&ra, n, n, _state); ra.ptr.pp_double[0][0] = (double)(1); ra.ptr.pp_double[0][1] = (double)(0); ra.ptr.pp_double[1][0] = (double)(0); ra.ptr.pp_double[1][1] = 1/growth; ae_vector_set_length(&rxs, n, _state); rxs.ptr.p_double[0] = 1.0; rxs.ptr.p_double[1] = 0.5; rerrors = rerrors||!rmatrixscaledtrsafesolve(&ra, 1.0, n, &rxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(2, _state), ae_false, 1.05*ae_maxreal(ae_fabs(rxs.ptr.p_double[1], _state)*growth, 1.0, _state), _state); rerrors = rerrors||!rmatrixscaledtrsafesolve(&ra, 1.0, n, &rxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(2, _state), ae_false, 0.95*ae_maxreal(ae_fabs(rxs.ptr.p_double[1], _state)*growth, 1.0, _state), _state); /* * Special test with diagonal degenerate matrix: * * ability to solve it when resulting growth is less than threshold * * ability to stop solve when resulting growth is greater than threshold * * A = diag(1, 0) * b = (1, 0.5) */ n = 2; ae_matrix_set_length(&ca, n, n, _state); ca.ptr.pp_complex[0][0] = ae_complex_from_i(1); ca.ptr.pp_complex[0][1] = ae_complex_from_i(0); ca.ptr.pp_complex[1][0] = ae_complex_from_i(0); ca.ptr.pp_complex[1][1] = ae_complex_from_i(0); ae_vector_set_length(&cxs, n, _state); cxs.ptr.p_complex[0] = ae_complex_from_d(1.0); cxs.ptr.p_complex[1] = ae_complex_from_d(0.5); cerrors = cerrors||cmatrixscaledtrsafesolve(&ca, 1.0, n, &cxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(3, _state), ae_false, ae_sqrt(ae_maxrealnumber, _state), _state); ae_matrix_set_length(&ra, n, n, _state); ra.ptr.pp_double[0][0] = (double)(1); ra.ptr.pp_double[0][1] = (double)(0); ra.ptr.pp_double[1][0] = (double)(0); ra.ptr.pp_double[1][1] = (double)(0); ae_vector_set_length(&rxs, n, _state); rxs.ptr.p_double[0] = 1.0; rxs.ptr.p_double[1] = 0.5; rerrors = rerrors||rmatrixscaledtrsafesolve(&ra, 1.0, n, &rxs, ae_fp_greater(ae_randomreal(_state),0.5), ae_randominteger(2, _state), ae_false, ae_sqrt(ae_maxrealnumber, _state), _state); /* * report */ waserrors = rerrors||cerrors; if( !silent ) { printf("TESTING SAFE TR SOLVER\n"); printf("REAL: "); if( !rerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("COMPLEX: "); if( !cerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsafesolve(ae_bool silent, ae_state *_state) { return testsafesolve(silent, _state); } /************************************************************************* Copy *************************************************************************/ static void testsafesolveunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* Copy *************************************************************************/ static void testsafesolveunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } } static double testrcondunit_threshold50 = 0.25; static double testrcondunit_threshold90 = 0.10; static void testrcondunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state); static void testrcondunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testrcondunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testrcondunit_rmatrixgenzero(/* Real */ ae_matrix* a0, ae_int_t n, ae_state *_state); static ae_bool testrcondunit_rmatrixinvmattr(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state); static ae_bool testrcondunit_rmatrixinvmatlu(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state); static ae_bool testrcondunit_rmatrixinvmat(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state); static void testrcondunit_rmatrixrefrcond(/* Real */ ae_matrix* a, ae_int_t n, double* rc1, double* rcinf, ae_state *_state); static void testrcondunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state); static void testrcondunit_cmatrixgenzero(/* Complex */ ae_matrix* a0, ae_int_t n, ae_state *_state); static ae_bool testrcondunit_cmatrixinvmattr(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state); static ae_bool testrcondunit_cmatrixinvmatlu(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state); static ae_bool testrcondunit_cmatrixinvmat(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state); static void testrcondunit_cmatrixrefrcond(/* Complex */ ae_matrix* a, ae_int_t n, double* rc1, double* rcinf, ae_state *_state); static ae_bool testrcondunit_testrmatrixtrrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); static ae_bool testrcondunit_testcmatrixtrrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); static ae_bool testrcondunit_testrmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); static ae_bool testrcondunit_testspdmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); static ae_bool testrcondunit_testcmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); static ae_bool testrcondunit_testhpdmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state); ae_bool testrcond(ae_bool silent, ae_state *_state) { ae_int_t maxn; ae_int_t passcount; ae_bool waserrors; ae_bool rtrerr; ae_bool ctrerr; ae_bool rerr; ae_bool cerr; ae_bool spderr; ae_bool hpderr; ae_bool result; maxn = 10; passcount = 100; /* * report */ rtrerr = !testrcondunit_testrmatrixtrrcond(maxn, passcount, _state); ctrerr = !testrcondunit_testcmatrixtrrcond(maxn, passcount, _state); rerr = !testrcondunit_testrmatrixrcond(maxn, passcount, _state); cerr = !testrcondunit_testcmatrixrcond(maxn, passcount, _state); spderr = !testrcondunit_testspdmatrixrcond(maxn, passcount, _state); hpderr = !testrcondunit_testhpdmatrixrcond(maxn, passcount, _state); waserrors = ((((rtrerr||ctrerr)||rerr)||cerr)||spderr)||hpderr; if( !silent ) { printf("TESTING RCOND\n"); printf("REAL TRIANGULAR: "); if( !rtrerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("COMPLEX TRIANGULAR: "); if( !ctrerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("REAL: "); if( !rerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("SPD: "); if( !spderr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("HPD: "); if( !hpderr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("COMPLEX: "); if( !cerr ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testrcond(ae_bool silent, ae_state *_state) { return testrcond(silent, _state); } /************************************************************************* Copy *************************************************************************/ static void testrcondunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testrcondunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_double[i][j] = (double)(1+2*i+3*j); } } } } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testrcondunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_complex[i][j] = ae_complex_from_i(1+2*i+3*j); } } } } /************************************************************************* Generate matrix with given condition number C (2-norm) *************************************************************************/ static void testrcondunit_rmatrixgenzero(/* Real */ ae_matrix* a0, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_set_length(a0, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a0->ptr.pp_double[i][j] = (double)(0); } } } /************************************************************************* triangular inverse *************************************************************************/ static ae_bool testrcondunit_rmatrixinvmattr(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state) { ae_frame _frame_block; ae_bool nounit; ae_int_t i; ae_int_t j; double v; double ajj; ae_vector t; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&t, 0, DT_REAL, _state); result = ae_true; ae_vector_set_length(&t, n-1+1, _state); /* * Test the input parameters. */ nounit = !isunittriangular; if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_move(&t.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_double[i][i+1], 1, &t.ptr.p_double[i+1], 1, ae_v_len(i+1,j-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } if( jptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_dotproduct(&a->ptr.pp_double[i][j+1], 1, &t.ptr.p_double[j+1], 1, ae_v_len(j+1,i-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1), ajj); } } } ae_frame_leave(_state); return result; } /************************************************************************* LU inverse *************************************************************************/ static ae_bool testrcondunit_rmatrixinvmatlu(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_int_t i; ae_int_t j; ae_int_t jp; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&work, 0, DT_REAL, _state); result = ae_true; /* * Quick return if possible */ if( n==0 ) { ae_frame_leave(_state); return result; } ae_vector_set_length(&work, n-1+1, _state); /* * Form inv(U) */ if( !testrcondunit_rmatrixinvmattr(a, n, ae_true, ae_false, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Solve the equation inv(A)*L = inv(U) for inv(A). */ for(j=n-1; j>=0; j--) { /* * Copy current column of L to WORK and replace with zeros. */ for(i=j+1; i<=n-1; i++) { work.ptr.p_double[i] = a->ptr.pp_double[i][j]; a->ptr.pp_double[i][j] = (double)(0); } /* * Compute current column of inv(A). */ if( jptr.pp_double[i][j+1], 1, &work.ptr.p_double[j+1], 1, ae_v_len(j+1,n-1)); a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]-v; } } } /* * Apply column interchanges. */ for(j=n-2; j>=0; j--) { jp = pivots->ptr.p_int[j]; if( jp!=j ) { ae_v_move(&work.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[0][j], a->stride, &a->ptr.pp_double[0][jp], a->stride, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[0][jp], a->stride, &work.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } ae_frame_leave(_state); return result; } /************************************************************************* Matrix inverse *************************************************************************/ static ae_bool testrcondunit_rmatrixinvmat(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); rmatrixlu(a, n, n, &pivots, _state); result = testrcondunit_rmatrixinvmatlu(a, &pivots, n, _state); ae_frame_leave(_state); return result; } /************************************************************************* reference RCond *************************************************************************/ static void testrcondunit_rmatrixrefrcond(/* Real */ ae_matrix* a, ae_int_t n, double* rc1, double* rcinf, ae_state *_state) { ae_frame _frame_block; ae_matrix inva; double nrm1a; double nrminfa; double nrm1inva; double nrminfinva; double v; ae_int_t k; ae_int_t i; ae_frame_make(_state, &_frame_block); *rc1 = 0; *rcinf = 0; ae_matrix_init(&inva, 0, 0, DT_REAL, _state); /* * inv A */ testrcondunit_rmatrixmakeacopy(a, n, n, &inva, _state); if( !testrcondunit_rmatrixinvmat(&inva, n, _state) ) { *rc1 = (double)(0); *rcinf = (double)(0); ae_frame_leave(_state); return; } /* * norm A */ nrm1a = (double)(0); nrminfa = (double)(0); for(k=0; k<=n-1; k++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_fabs(a->ptr.pp_double[i][k], _state); } nrm1a = ae_maxreal(nrm1a, v, _state); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_fabs(a->ptr.pp_double[k][i], _state); } nrminfa = ae_maxreal(nrminfa, v, _state); } /* * norm inv A */ nrm1inva = (double)(0); nrminfinva = (double)(0); for(k=0; k<=n-1; k++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_fabs(inva.ptr.pp_double[i][k], _state); } nrm1inva = ae_maxreal(nrm1inva, v, _state); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_fabs(inva.ptr.pp_double[k][i], _state); } nrminfinva = ae_maxreal(nrminfinva, v, _state); } /* * result */ *rc1 = nrm1inva*nrm1a; *rcinf = nrminfinva*nrminfa; ae_frame_leave(_state); } /************************************************************************* Copy *************************************************************************/ static void testrcondunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } } /************************************************************************* Generate matrix with given condition number C (2-norm) *************************************************************************/ static void testrcondunit_cmatrixgenzero(/* Complex */ ae_matrix* a0, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_set_length(a0, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a0->ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } /************************************************************************* triangular inverse *************************************************************************/ static ae_bool testrcondunit_cmatrixinvmattr(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state) { ae_frame _frame_block; ae_bool nounit; ae_int_t i; ae_int_t j; ae_complex v; ae_complex ajj; ae_vector t; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&t, 0, DT_COMPLEX, _state); result = ae_true; ae_vector_set_length(&t, n-1+1, _state); /* * Test the input parameters. */ nounit = !isunittriangular; if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( nounit ) { if( ae_c_eq_d(a->ptr.pp_complex[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_complex[j][j] = ae_c_d_div(1,a->ptr.pp_complex[j][j]); ajj = ae_c_neg(a->ptr.pp_complex[j][j]); } else { ajj = ae_complex_from_i(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_cmove(&t.ptr.p_complex[0], 1, &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_complex[i][i+1], 1, "N", &t.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,j-1)); } else { v = ae_complex_from_i(0); } if( nounit ) { a->ptr.pp_complex[i][j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[i][i],t.ptr.p_complex[i])); } else { a->ptr.pp_complex[i][j] = ae_c_add(v,t.ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[0][j], a->stride, ae_v_len(0,j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( nounit ) { if( ae_c_eq_d(a->ptr.pp_complex[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_complex[j][j] = ae_c_d_div(1,a->ptr.pp_complex[j][j]); ajj = ae_c_neg(a->ptr.pp_complex[j][j]); } else { ajj = ae_complex_from_i(-1); } if( jptr.pp_complex[j+1][j], a->stride, "N", ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_cdotproduct(&a->ptr.pp_complex[i][j+1], 1, "N", &t.ptr.p_complex[j+1], 1, "N", ae_v_len(j+1,i-1)); } else { v = ae_complex_from_i(0); } if( nounit ) { a->ptr.pp_complex[i][j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[i][i],t.ptr.p_complex[i])); } else { a->ptr.pp_complex[i][j] = ae_c_add(v,t.ptr.p_complex[i]); } } ae_v_cmulc(&a->ptr.pp_complex[j+1][j], a->stride, ae_v_len(j+1,n-1), ajj); } } } ae_frame_leave(_state); return result; } /************************************************************************* LU inverse *************************************************************************/ static ae_bool testrcondunit_cmatrixinvmatlu(/* Complex */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_int_t i; ae_int_t j; ae_int_t jp; ae_complex v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&work, 0, DT_COMPLEX, _state); result = ae_true; /* * Quick return if possible */ if( n==0 ) { ae_frame_leave(_state); return result; } ae_vector_set_length(&work, n-1+1, _state); /* * Form inv(U) */ if( !testrcondunit_cmatrixinvmattr(a, n, ae_true, ae_false, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Solve the equation inv(A)*L = inv(U) for inv(A). */ for(j=n-1; j>=0; j--) { /* * Copy current column of L to WORK and replace with zeros. */ for(i=j+1; i<=n-1; i++) { work.ptr.p_complex[i] = a->ptr.pp_complex[i][j]; a->ptr.pp_complex[i][j] = ae_complex_from_i(0); } /* * Compute current column of inv(A). */ if( jptr.pp_complex[i][j+1], 1, "N", &work.ptr.p_complex[j+1], 1, "N", ae_v_len(j+1,n-1)); a->ptr.pp_complex[i][j] = ae_c_sub(a->ptr.pp_complex[i][j],v); } } } /* * Apply column interchanges. */ for(j=n-2; j>=0; j--) { jp = pivots->ptr.p_int[j]; if( jp!=j ) { ae_v_cmove(&work.ptr.p_complex[0], 1, &a->ptr.pp_complex[0][j], a->stride, "N", ae_v_len(0,n-1)); ae_v_cmove(&a->ptr.pp_complex[0][j], a->stride, &a->ptr.pp_complex[0][jp], a->stride, "N", ae_v_len(0,n-1)); ae_v_cmove(&a->ptr.pp_complex[0][jp], a->stride, &work.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); } } ae_frame_leave(_state); return result; } /************************************************************************* Matrix inverse *************************************************************************/ static ae_bool testrcondunit_cmatrixinvmat(/* Complex */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); cmatrixlu(a, n, n, &pivots, _state); result = testrcondunit_cmatrixinvmatlu(a, &pivots, n, _state); ae_frame_leave(_state); return result; } /************************************************************************* reference RCond *************************************************************************/ static void testrcondunit_cmatrixrefrcond(/* Complex */ ae_matrix* a, ae_int_t n, double* rc1, double* rcinf, ae_state *_state) { ae_frame _frame_block; ae_matrix inva; double nrm1a; double nrminfa; double nrm1inva; double nrminfinva; double v; ae_int_t k; ae_int_t i; ae_frame_make(_state, &_frame_block); *rc1 = 0; *rcinf = 0; ae_matrix_init(&inva, 0, 0, DT_COMPLEX, _state); /* * inv A */ testrcondunit_cmatrixmakeacopy(a, n, n, &inva, _state); if( !testrcondunit_cmatrixinvmat(&inva, n, _state) ) { *rc1 = (double)(0); *rcinf = (double)(0); ae_frame_leave(_state); return; } /* * norm A */ nrm1a = (double)(0); nrminfa = (double)(0); for(k=0; k<=n-1; k++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_c_abs(a->ptr.pp_complex[i][k], _state); } nrm1a = ae_maxreal(nrm1a, v, _state); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_c_abs(a->ptr.pp_complex[k][i], _state); } nrminfa = ae_maxreal(nrminfa, v, _state); } /* * norm inv A */ nrm1inva = (double)(0); nrminfinva = (double)(0); for(k=0; k<=n-1; k++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_c_abs(inva.ptr.pp_complex[i][k], _state); } nrm1inva = ae_maxreal(nrm1inva, v, _state); v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_c_abs(inva.ptr.pp_complex[k][i], _state); } nrminfinva = ae_maxreal(nrminfinva, v, _state); } /* * result */ *rc1 = nrm1inva*nrm1a; *rcinf = nrminfinva*nrminfa; ae_frame_leave(_state); } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testrmatrixtrrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix ea; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errspec; ae_bool errless; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool isupper; ae_bool isunit; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&ea, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; ae_vector_set_length(&q50, 2, _state); ae_vector_set_length(&q90, 2, _state); for(n=1; n<=maxn; n++) { /* * special test for zero matrix */ testrcondunit_rmatrixgenzero(&a, n, _state); errspec = errspec||ae_fp_neq(rmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); /* * general test */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=1; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); isunit = ae_fp_greater(ae_randomreal(_state),0.5); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = ae_randomreal(_state)-0.5; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 1+ae_randomreal(_state); } testrcondunit_rmatrixmakeacopy(&a, n, n, &ea, _state); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = 0; j2 = i-1; } else { j1 = i+1; j2 = n-1; } for(j=j1; j<=j2; j++) { ea.ptr.pp_double[i][j] = (double)(0); } if( isunit ) { ea.ptr.pp_double[i][i] = (double)(1); } } testrcondunit_rmatrixrefrcond(&ea, n, &erc1, &ercinf, _state); /* * 1-norm */ v = 1/rmatrixtrrcond1(&a, n, isupper, isunit, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Inf-norm */ v = 1/rmatrixtrrcondinf(&a, n, isupper, isunit, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); } for(i=0; i<=1; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } a.ptr.pp_double[0][0] = (double)(1); a.ptr.pp_double[n-1][n-1] = (double)(1); errspec = errspec||ae_fp_neq(rmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = (double)(1); } i = ae_randominteger(n, _state); a.ptr.pp_double[i][i] = 0.1*ae_maxrealnumber; errspec = errspec||ae_fp_neq(rmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testcmatrixtrrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix ea; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t j1; ae_int_t j2; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errspec; ae_bool errless; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool isupper; ae_bool isunit; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&ea, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; ae_vector_set_length(&q50, 2, _state); ae_vector_set_length(&q90, 2, _state); for(n=1; n<=maxn; n++) { /* * special test for zero matrix */ testrcondunit_cmatrixgenzero(&a, n, _state); errspec = errspec||ae_fp_neq(cmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); /* * general test */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=1; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); isunit = ae_fp_greater(ae_randomreal(_state),0.5); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = ae_randomreal(_state)-0.5; a.ptr.pp_complex[i][j].y = ae_randomreal(_state)-0.5; } } for(i=0; i<=n-1; i++) { a.ptr.pp_complex[i][i].x = 1+ae_randomreal(_state); a.ptr.pp_complex[i][i].y = 1+ae_randomreal(_state); } testrcondunit_cmatrixmakeacopy(&a, n, n, &ea, _state); for(i=0; i<=n-1; i++) { if( isupper ) { j1 = 0; j2 = i-1; } else { j1 = i+1; j2 = n-1; } for(j=j1; j<=j2; j++) { ea.ptr.pp_complex[i][j] = ae_complex_from_i(0); } if( isunit ) { ea.ptr.pp_complex[i][i] = ae_complex_from_i(1); } } testrcondunit_cmatrixrefrcond(&ea, n, &erc1, &ercinf, _state); /* * 1-norm */ v = 1/cmatrixtrrcond1(&a, n, isupper, isunit, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Inf-norm */ v = 1/cmatrixtrrcondinf(&a, n, isupper, isunit, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); } for(i=0; i<=1; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } a.ptr.pp_complex[0][0] = ae_complex_from_i(1); a.ptr.pp_complex[n-1][n-1] = ae_complex_from_i(1); errspec = errspec||ae_fp_neq(cmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } for(i=0; i<=n-1; i++) { a.ptr.pp_complex[i][i] = ae_complex_from_i(1); } i = ae_randominteger(n, _state); a.ptr.pp_complex[i][i] = ae_complex_from_d(0.1*ae_maxrealnumber); errspec = errspec||ae_fp_neq(cmatrixtrrcond1(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixtrrcondinf(&a, n, ae_fp_greater(ae_randomreal(_state),0.5), ae_false, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testrmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errspec; ae_bool errless; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&lua, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; ae_vector_set_length(&q50, 3+1, _state); ae_vector_set_length(&q90, 3+1, _state); for(n=1; n<=maxn; n++) { /* * special test for zero matrix */ testrcondunit_rmatrixgenzero(&a, n, _state); testrcondunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); errspec = errspec||ae_fp_neq(rmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcond1(&lua, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcondinf(&lua, n, _state),(double)(0)); /* * general test */ ae_matrix_set_length(&a, n-1+1, n-1+1, _state); for(i=0; i<=3; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { rmatrixrndcond(n, ae_exp(ae_randomreal(_state)*ae_log((double)(1000), _state), _state), &a, _state); testrcondunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); testrcondunit_rmatrixrefrcond(&a, n, &erc1, &ercinf, _state); /* * 1-norm, normal */ v = 1/rmatrixrcond1(&a, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * 1-norm, LU */ v = 1/rmatrixlurcond1(&lua, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Inf-norm, normal */ v = 1/rmatrixrcondinf(&a, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[2] = q50.ptr.p_double[2]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[2] = q90.ptr.p_double[2]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); /* * Inf-norm, LU */ v = 1/rmatrixlurcondinf(&lua, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[3] = q50.ptr.p_double[3]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[3] = q90.ptr.p_double[3]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); } for(i=0; i<=3; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } a.ptr.pp_double[0][0] = (double)(1); a.ptr.pp_double[n-1][n-1] = (double)(1); errspec = errspec||ae_fp_neq(rmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcondinf(&a, n, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = (double)(1); } i = ae_randominteger(n, _state); a.ptr.pp_double[i][i] = 0.1*ae_maxrealnumber; errspec = errspec||ae_fp_neq(rmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(rmatrixlurcondinf(&a, n, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testspdmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errspec; ae_bool errless; ae_bool isupper; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&cha, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; ae_vector_set_length(&q50, 2, _state); ae_vector_set_length(&q90, 2, _state); for(n=1; n<=maxn; n++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); /* * general test */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=1; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { spdmatrixrndcond(n, ae_exp(ae_randomreal(_state)*ae_log((double)(1000), _state), _state), &a, _state); testrcondunit_rmatrixrefrcond(&a, n, &erc1, &ercinf, _state); testrcondunit_rmatrixdrophalf(&a, n, isupper, _state); testrcondunit_rmatrixmakeacopy(&a, n, n, &cha, _state); spdmatrixcholesky(&cha, n, isupper, _state); /* * normal */ v = 1/spdmatrixrcond(&a, n, isupper, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Cholesky */ v = 1/spdmatrixcholeskyrcond(&cha, n, isupper, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); } for(i=0; i<=1; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } a.ptr.pp_double[0][0] = (double)(1); a.ptr.pp_double[n-1][n-1] = (double)(1); errspec = errspec||ae_fp_neq(spdmatrixrcond(&a, n, isupper, _state),(double)(-1)); errspec = errspec||ae_fp_neq(spdmatrixcholeskyrcond(&a, n, isupper, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = (double)(1); } i = ae_randominteger(n, _state); a.ptr.pp_double[i][i] = 0.1*ae_maxrealnumber; errspec = errspec||ae_fp_neq(spdmatrixrcond(&a, n, isupper, _state),(double)(0)); errspec = errspec||ae_fp_neq(spdmatrixcholeskyrcond(&a, n, isupper, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testcmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errless; ae_bool errspec; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&lua, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); ae_vector_set_length(&q50, 3+1, _state); ae_vector_set_length(&q90, 3+1, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; /* * process */ for(n=1; n<=maxn; n++) { /* * special test for zero matrix */ testrcondunit_cmatrixgenzero(&a, n, _state); testrcondunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); errspec = errspec||ae_fp_neq(cmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcond1(&lua, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcondinf(&lua, n, _state),(double)(0)); /* * general test */ ae_matrix_set_length(&a, n-1+1, n-1+1, _state); for(i=0; i<=3; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { cmatrixrndcond(n, ae_exp(ae_randomreal(_state)*ae_log((double)(1000), _state), _state), &a, _state); testrcondunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); testrcondunit_cmatrixrefrcond(&a, n, &erc1, &ercinf, _state); /* * 1-norm, normal */ v = 1/cmatrixrcond1(&a, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * 1-norm, LU */ v = 1/cmatrixlurcond1(&lua, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Inf-norm, normal */ v = 1/cmatrixrcondinf(&a, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[2] = q50.ptr.p_double[2]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[2] = q90.ptr.p_double[2]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); /* * Inf-norm, LU */ v = 1/cmatrixlurcondinf(&lua, n, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*ercinf) ) { q50.ptr.p_double[3] = q50.ptr.p_double[3]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*ercinf) ) { q90.ptr.p_double[3] = q90.ptr.p_double[3]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,ercinf*1.001); } for(i=0; i<=3; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } a.ptr.pp_complex[0][0] = ae_complex_from_i(1); a.ptr.pp_complex[n-1][n-1] = ae_complex_from_i(1); errspec = errspec||ae_fp_neq(cmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcondinf(&a, n, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } for(i=0; i<=n-1; i++) { a.ptr.pp_complex[i][i] = ae_complex_from_i(1); } i = ae_randominteger(n, _state); a.ptr.pp_complex[i][i] = ae_complex_from_d(0.1*ae_maxrealnumber); errspec = errspec||ae_fp_neq(cmatrixrcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixrcondinf(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcond1(&a, n, _state),(double)(0)); errspec = errspec||ae_fp_neq(cmatrixlurcondinf(&a, n, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } /************************************************************************* Returns True for successful test, False - for failed test *************************************************************************/ static ae_bool testrcondunit_testhpdmatrixrcond(ae_int_t maxn, ae_int_t passcount, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_vector p; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t pass; ae_bool err50; ae_bool err90; ae_bool errspec; ae_bool errless; ae_bool isupper; double erc1; double ercinf; ae_vector q50; ae_vector q90; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cha, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_vector_init(&q50, 0, DT_REAL, _state); ae_vector_init(&q90, 0, DT_REAL, _state); err50 = ae_false; err90 = ae_false; errless = ae_false; errspec = ae_false; ae_vector_set_length(&q50, 2, _state); ae_vector_set_length(&q90, 2, _state); for(n=1; n<=maxn; n++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); /* * general test */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=1; i++) { q50.ptr.p_double[i] = (double)(0); q90.ptr.p_double[i] = (double)(0); } for(pass=1; pass<=passcount; pass++) { hpdmatrixrndcond(n, ae_exp(ae_randomreal(_state)*ae_log((double)(1000), _state), _state), &a, _state); testrcondunit_cmatrixrefrcond(&a, n, &erc1, &ercinf, _state); testrcondunit_cmatrixdrophalf(&a, n, isupper, _state); testrcondunit_cmatrixmakeacopy(&a, n, n, &cha, _state); hpdmatrixcholesky(&cha, n, isupper, _state); /* * normal */ v = 1/hpdmatrixrcond(&a, n, isupper, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[0] = q50.ptr.p_double[0]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[0] = q90.ptr.p_double[0]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); /* * Cholesky */ v = 1/hpdmatrixcholeskyrcond(&cha, n, isupper, _state); if( ae_fp_greater_eq(v,testrcondunit_threshold50*erc1) ) { q50.ptr.p_double[1] = q50.ptr.p_double[1]+(double)1/(double)passcount; } if( ae_fp_greater_eq(v,testrcondunit_threshold90*erc1) ) { q90.ptr.p_double[1] = q90.ptr.p_double[1]+(double)1/(double)passcount; } errless = errless||ae_fp_greater(v,erc1*1.001); } for(i=0; i<=1; i++) { err50 = err50||ae_fp_less(q50.ptr.p_double[i],0.50); err90 = err90||ae_fp_less(q90.ptr.p_double[i],0.90); } /* * degenerate matrix test */ if( n>=3 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } a.ptr.pp_complex[0][0] = ae_complex_from_i(1); a.ptr.pp_complex[n-1][n-1] = ae_complex_from_i(1); errspec = errspec||ae_fp_neq(hpdmatrixrcond(&a, n, isupper, _state),(double)(-1)); errspec = errspec||ae_fp_neq(hpdmatrixcholeskyrcond(&a, n, isupper, _state),(double)(0)); } /* * near-degenerate matrix test */ if( n>=2 ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_d(0.0); } } for(i=0; i<=n-1; i++) { a.ptr.pp_complex[i][i] = ae_complex_from_i(1); } i = ae_randominteger(n, _state); a.ptr.pp_complex[i][i] = ae_complex_from_d(0.1*ae_maxrealnumber); errspec = errspec||ae_fp_neq(hpdmatrixrcond(&a, n, isupper, _state),(double)(0)); errspec = errspec||ae_fp_neq(hpdmatrixcholeskyrcond(&a, n, isupper, _state),(double)(0)); } } /* * report */ result = !(((err50||err90)||errless)||errspec); ae_frame_leave(_state); return result; } static void testmatinvunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state); static void testmatinvunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state); static ae_bool testmatinvunit_rmatrixcheckinverse(/* Real */ ae_matrix* a, /* Real */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static ae_bool testmatinvunit_spdmatrixcheckinverse(/* Real */ ae_matrix* a, /* Real */ ae_matrix* inva, ae_bool isupper, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static ae_bool testmatinvunit_hpdmatrixcheckinverse(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* inva, ae_bool isupper, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static ae_bool testmatinvunit_rmatrixcheckinversesingular(/* Real */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static ae_bool testmatinvunit_cmatrixcheckinverse(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static ae_bool testmatinvunit_cmatrixcheckinversesingular(/* Complex */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state); static void testmatinvunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testmatinvunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testmatinvunit_testrtrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* rtrerrors, ae_state *_state); static void testmatinvunit_testctrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* ctrerrors, ae_state *_state); static void testmatinvunit_testrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* rerrors, ae_state *_state); static void testmatinvunit_testcinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* cerrors, ae_state *_state); static void testmatinvunit_testspdinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* spderrors, ae_state *_state); static void testmatinvunit_testhpdinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* hpderrors, ae_state *_state); static void testmatinvunit_unset2d(/* Real */ ae_matrix* x, ae_state *_state); static void testmatinvunit_cunset2d(/* Complex */ ae_matrix* x, ae_state *_state); static void testmatinvunit_unsetrep(matinvreport* r, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testmatinv(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t maxrn; ae_int_t maxcn; ae_int_t largen; ae_int_t passcount; double threshold; double rcondtol; ae_bool rtrerrors; ae_bool ctrerrors; ae_bool rerrors; ae_bool cerrors; ae_bool spderrors; ae_bool hpderrors; ae_bool waserrors; ae_matrix emptyra; ae_matrix emptyca; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&emptyra, 0, 0, DT_REAL, _state); ae_matrix_init(&emptyca, 0, 0, DT_REAL, _state); maxrn = 3*ablasblocksize(&emptyra, _state)+1; maxcn = 3*ablasblocksize(&emptyca, _state)+1; largen = 256; passcount = 1; threshold = 10000*ae_machineepsilon; rcondtol = 0.01; rtrerrors = ae_false; ctrerrors = ae_false; rerrors = ae_false; cerrors = ae_false; spderrors = ae_false; hpderrors = ae_false; testmatinvunit_testrtrinv(1, maxrn, passcount, threshold, &rtrerrors, _state); testmatinvunit_testctrinv(1, maxcn, passcount, threshold, &ctrerrors, _state); testmatinvunit_testrinv(1, maxrn, passcount, threshold, &rerrors, _state); testmatinvunit_testspdinv(1, maxrn, passcount, threshold, &spderrors, _state); testmatinvunit_testcinv(1, maxcn, passcount, threshold, &cerrors, _state); testmatinvunit_testhpdinv(1, maxcn, passcount, threshold, &hpderrors, _state); testmatinvunit_testrtrinv(largen, largen, passcount, threshold, &rtrerrors, _state); testmatinvunit_testctrinv(largen, largen, passcount, threshold, &ctrerrors, _state); testmatinvunit_testrinv(largen, largen, passcount, threshold, &rerrors, _state); testmatinvunit_testspdinv(largen, largen, passcount, threshold, &spderrors, _state); testmatinvunit_testcinv(largen, largen, passcount, threshold, &cerrors, _state); testmatinvunit_testhpdinv(largen, largen, passcount, threshold, &hpderrors, _state); waserrors = ((((rtrerrors||ctrerrors)||rerrors)||cerrors)||spderrors)||hpderrors; if( !silent ) { printf("TESTING MATINV\n"); printf("* REAL TRIANGULAR: "); if( rtrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* COMPLEX TRIANGULAR: "); if( ctrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* REAL: "); if( rerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* COMPLEX: "); if( cerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* SPD: "); if( spderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* HPD: "); if( hpderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmatinv(ae_bool silent, ae_state *_state) { return testmatinv(silent, _state); } /************************************************************************* Copy *************************************************************************/ static void testmatinvunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* Copy *************************************************************************/ static void testmatinvunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } } /************************************************************************* Checks whether inverse is correct Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_rmatrixcheckinverse(/* Real */ ae_matrix* a, /* Real */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&a->ptr.pp_double[i][0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } result = result&&ae_fp_less_eq(ae_fabs(v, _state),threshold); } } } return result; } /************************************************************************* Checks whether inverse is correct Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_spdmatrixcheckinverse(/* Real */ ae_matrix* a, /* Real */ ae_matrix* inva, ae_bool isupper, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_matrix _inva; ae_int_t i; ae_int_t j; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_matrix_init_copy(&_inva, inva, _state); inva = &_inva; for(i=0; i<=n-2; i++) { if( isupper ) { ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &a->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1)); ae_v_move(&inva->ptr.pp_double[i+1][i], inva->stride, &inva->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1)); } else { ae_v_move(&a->ptr.pp_double[i][i+1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i+1,n-1)); ae_v_move(&inva->ptr.pp_double[i][i+1], 1, &inva->ptr.pp_double[i+1][i], inva->stride, ae_v_len(i+1,n-1)); } } result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&a->ptr.pp_double[i][0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); if( i==j ) { v = v-1; } result = result&&ae_fp_less_eq(ae_fabs(v, _state),threshold); } } } ae_frame_leave(_state); return result; } /************************************************************************* Checks whether inverse is correct Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_hpdmatrixcheckinverse(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* inva, ae_bool isupper, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_frame _frame_block; ae_matrix _a; ae_matrix _inva; ae_int_t i; ae_int_t j; ae_complex v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_a, a, _state); a = &_a; ae_matrix_init_copy(&_inva, inva, _state); inva = &_inva; for(i=0; i<=n-2; i++) { if( isupper ) { ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &a->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1)); ae_v_cmove(&inva->ptr.pp_complex[i+1][i], inva->stride, &inva->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1)); } else { ae_v_cmove(&a->ptr.pp_complex[i][i+1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "Conj", ae_v_len(i+1,n-1)); ae_v_cmove(&inva->ptr.pp_complex[i][i+1], 1, &inva->ptr.pp_complex[i+1][i], inva->stride, "Conj", ae_v_len(i+1,n-1)); } } result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&a->ptr.pp_complex[i][0], 1, "N", &inva->ptr.pp_complex[0][j], inva->stride, "N", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } result = result&&ae_fp_less_eq(ae_c_abs(v, _state),threshold); } } } ae_frame_leave(_state); return result; } /************************************************************************* Checks whether inversion result indicate singular matrix Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_rmatrixcheckinversesingular(/* Real */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3&&info!=1 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,(double)(0))||ae_fp_greater(rep->r1,1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,(double)(0))||ae_fp_greater(rep->rinf,1000*ae_machineepsilon)); if( info==-3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result&&ae_fp_eq(inva->ptr.pp_double[i][j],(double)(0)); } } } } return result; } /************************************************************************* Checks whether inverse is correct Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_cmatrixcheckinverse(/* Complex */ ae_matrix* a, /* Complex */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex v; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&a->ptr.pp_complex[i][0], 1, "N", &inva->ptr.pp_complex[0][j], inva->stride, "N", ae_v_len(0,n-1)); if( i==j ) { v = ae_c_sub_d(v,1); } result = result&&ae_fp_less_eq(ae_c_abs(v, _state),threshold); } } } return result; } /************************************************************************* Checks whether inversion result indicate singular matrix Returns True on success. *************************************************************************/ static ae_bool testmatinvunit_cmatrixcheckinversesingular(/* Complex */ ae_matrix* inva, ae_int_t n, double threshold, ae_int_t info, matinvreport* rep, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3&&info!=1 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,(double)(0))||ae_fp_greater(rep->r1,1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,(double)(0))||ae_fp_greater(rep->rinf,1000*ae_machineepsilon)); if( info==-3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { result = result&&ae_c_eq_d(inva->ptr.pp_complex[i][j],(double)(0)); } } } } return result; } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testmatinvunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_double[i][j] = (double)(1+2*i+3*j); } } } } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testmatinvunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_complex[i][j] = ae_complex_from_i(1+2*i+3*j); } } } } /************************************************************************* Real TR inverse *************************************************************************/ static void testmatinvunit_testrtrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* rtrerrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix b; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t task; ae_bool isupper; ae_bool isunit; double v; ae_bool waserrors; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); _matinvreport_init(&rep, _state); waserrors = ae_false; /* * Test */ for(n=minn; n<=maxn; n++) { ae_matrix_set_length(&a, n, n, _state); ae_matrix_set_length(&b, n, n, _state); for(task=0; task<=3; task++) { for(pass=1; pass<=passcount; pass++) { /* * Determine task */ isupper = task%2==0; isunit = task/2%2==0; /* * Generate matrix */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_double[i][i] = 1+ae_randomreal(_state); } else { a.ptr.pp_double[i][j] = 0.2*ae_randomreal(_state)-0.1; } b.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; } } /* * Inverse */ rmatrixtrinverse(&b, n, isupper, isunit, &info, &rep, _state); if( info<=0 ) { *rtrerrors = ae_true; ae_frame_leave(_state); return; } /* * Structural test */ if( isunit ) { for(i=0; i<=n-1; i++) { *rtrerrors = *rtrerrors||ae_fp_neq(a.ptr.pp_double[i][i],b.ptr.pp_double[i][i]); } } if( isupper ) { for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { *rtrerrors = *rtrerrors||ae_fp_neq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } else { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { *rtrerrors = *rtrerrors||ae_fp_neq(a.ptr.pp_double[i][j],b.ptr.pp_double[i][j]); } } } /* * Inverse test */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a.ptr.pp_double[i][j] = (double)(0); b.ptr.pp_double[i][j] = (double)(0); } } } if( isunit ) { for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = (double)(1); b.ptr.pp_double[i][i] = (double)(1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &b.ptr.pp_double[0][j], b.stride, ae_v_len(0,n-1)); if( j!=i ) { *rtrerrors = *rtrerrors||ae_fp_greater(ae_fabs(v, _state),threshold); } else { *rtrerrors = *rtrerrors||ae_fp_greater(ae_fabs(v-1, _state),threshold); } } } } } } ae_frame_leave(_state); } /************************************************************************* Complex TR inverse *************************************************************************/ static void testmatinvunit_testctrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* ctrerrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix b; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t task; ae_bool isupper; ae_bool isunit; ae_complex v; ae_bool waserrors; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); _matinvreport_init(&rep, _state); waserrors = ae_false; /* * Test */ for(n=minn; n<=maxn; n++) { ae_matrix_set_length(&a, n, n, _state); ae_matrix_set_length(&b, n, n, _state); for(task=0; task<=3; task++) { for(pass=1; pass<=passcount; pass++) { /* * Determine task */ isupper = task%2==0; isunit = task/2%2==0; /* * Generate matrix */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_complex[i][i].x = 1+ae_randomreal(_state); a.ptr.pp_complex[i][i].y = 1+ae_randomreal(_state); } else { a.ptr.pp_complex[i][j].x = 0.2*ae_randomreal(_state)-0.1; a.ptr.pp_complex[i][j].y = 0.2*ae_randomreal(_state)-0.1; } b.ptr.pp_complex[i][j] = a.ptr.pp_complex[i][j]; } } /* * Inverse */ cmatrixtrinverse(&b, n, isupper, isunit, &info, &rep, _state); if( info<=0 ) { *ctrerrors = ae_true; ae_frame_leave(_state); return; } /* * Structural test */ if( isunit ) { for(i=0; i<=n-1; i++) { *ctrerrors = *ctrerrors||ae_c_neq(a.ptr.pp_complex[i][i],b.ptr.pp_complex[i][i]); } } if( isupper ) { for(i=0; i<=n-1; i++) { for(j=0; j<=i-1; j++) { *ctrerrors = *ctrerrors||ae_c_neq(a.ptr.pp_complex[i][j],b.ptr.pp_complex[i][j]); } } } else { for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { *ctrerrors = *ctrerrors||ae_c_neq(a.ptr.pp_complex[i][j],b.ptr.pp_complex[i][j]); } } } /* * Inverse test */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (ji&&!isupper) ) { a.ptr.pp_complex[i][j] = ae_complex_from_i(0); b.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( isunit ) { for(i=0; i<=n-1; i++) { a.ptr.pp_complex[i][i] = ae_complex_from_i(1); b.ptr.pp_complex[i][i] = ae_complex_from_i(1); } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][0], 1, "N", &b.ptr.pp_complex[0][j], b.stride, "N", ae_v_len(0,n-1)); if( j!=i ) { *ctrerrors = *ctrerrors||ae_fp_greater(ae_c_abs(v, _state),threshold); } else { *ctrerrors = *ctrerrors||ae_fp_greater(ae_c_abs(ae_c_sub_d(v,1), _state),threshold); } } } } } } ae_frame_leave(_state); } /************************************************************************* Real test *************************************************************************/ static void testmatinvunit_testrinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* rerrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_matrix inva; ae_matrix invlua; ae_vector p; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t pass; ae_int_t taskkind; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&lua, 0, 0, DT_REAL, _state); ae_matrix_init(&inva, 0, 0, DT_REAL, _state); ae_matrix_init(&invlua, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); _matinvreport_init(&rep, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=minn; n<=maxn; n++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ rmatrixrndcond(n, (double)(1000), &a, _state); testmatinvunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); testmatinvunit_rmatrixmakeacopy(&a, n, n, &inva, _state); testmatinvunit_rmatrixmakeacopy(&lua, n, n, &invlua, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); rmatrixinverse(&inva, n, &info, &rep, _state); *rerrors = *rerrors||!testmatinvunit_rmatrixcheckinverse(&a, &inva, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); rmatrixluinverse(&invlua, &p, n, &info, &rep, _state); *rerrors = *rerrors||!testmatinvunit_rmatrixcheckinverse(&a, &invlua, n, threshold, info, &rep, _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * * with equal rows/columns * 2. test different methods */ for(taskkind=0; taskkind<=4; taskkind++) { testmatinvunit_unset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_move(&a.ptr.pp_double[0][0], a.stride, &a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1)); } if( taskkind==4 ) { /* * equal rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_move(&a.ptr.pp_double[0][0], 1, &a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1)); } testmatinvunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); rmatrixinverse(&a, n, &info, &rep, _state); *rerrors = *rerrors||!testmatinvunit_rmatrixcheckinversesingular(&a, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); rmatrixluinverse(&lua, &p, n, &info, &rep, _state); *rerrors = *rerrors||!testmatinvunit_rmatrixcheckinversesingular(&lua, n, threshold, info, &rep, _state); } } } ae_frame_leave(_state); } /************************************************************************* Complex test *************************************************************************/ static void testmatinvunit_testcinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* cerrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_matrix inva; ae_matrix invlua; ae_vector p; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t pass; ae_int_t taskkind; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&lua, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&inva, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&invlua, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); _matinvreport_init(&rep, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=minn; n<=maxn; n++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ cmatrixrndcond(n, (double)(1000), &a, _state); testmatinvunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); testmatinvunit_cmatrixmakeacopy(&a, n, n, &inva, _state); testmatinvunit_cmatrixmakeacopy(&lua, n, n, &invlua, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); cmatrixinverse(&inva, n, &info, &rep, _state); *cerrors = *cerrors||!testmatinvunit_cmatrixcheckinverse(&a, &inva, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); cmatrixluinverse(&invlua, &p, n, &info, &rep, _state); *cerrors = *cerrors||!testmatinvunit_cmatrixcheckinverse(&a, &invlua, n, threshold, info, &rep, _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * * with equal rows/columns * 2. test different methods */ for(taskkind=0; taskkind<=4; taskkind++) { testmatinvunit_cunset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_cmove(&a.ptr.pp_complex[0][0], a.stride, &a.ptr.pp_complex[0][k], a.stride, "N", ae_v_len(0,n-1)); } if( taskkind==4 ) { /* * equal rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_cmove(&a.ptr.pp_complex[0][0], 1, &a.ptr.pp_complex[k][0], 1, "N", ae_v_len(0,n-1)); } testmatinvunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); cmatrixinverse(&a, n, &info, &rep, _state); *cerrors = *cerrors||!testmatinvunit_cmatrixcheckinversesingular(&a, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); cmatrixluinverse(&lua, &p, n, &info, &rep, _state); *cerrors = *cerrors||!testmatinvunit_cmatrixcheckinversesingular(&lua, n, threshold, info, &rep, _state); } } } ae_frame_leave(_state); } /************************************************************************* SPD test *************************************************************************/ static void testmatinvunit_testspdinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* spderrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_matrix inva; ae_matrix invcha; ae_bool isupper; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t pass; ae_int_t taskkind; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&cha, 0, 0, DT_REAL, _state); ae_matrix_init(&inva, 0, 0, DT_REAL, _state); ae_matrix_init(&invcha, 0, 0, DT_REAL, _state); _matinvreport_init(&rep, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=minn; n<=maxn; n++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ spdmatrixrndcond(n, (double)(1000), &a, _state); testmatinvunit_rmatrixdrophalf(&a, n, isupper, _state); testmatinvunit_rmatrixmakeacopy(&a, n, n, &cha, _state); if( !spdmatrixcholesky(&cha, n, isupper, _state) ) { continue; } testmatinvunit_rmatrixmakeacopy(&a, n, n, &inva, _state); testmatinvunit_rmatrixmakeacopy(&cha, n, n, &invcha, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); spdmatrixinverse(&inva, n, isupper, &info, &rep, _state); *spderrors = *spderrors||!testmatinvunit_spdmatrixcheckinverse(&a, &inva, isupper, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); spdmatrixcholeskyinverse(&invcha, n, isupper, &info, &rep, _state); *spderrors = *spderrors||!testmatinvunit_spdmatrixcheckinverse(&a, &invcha, isupper, n, threshold, info, &rep, _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * 2. test different methods */ for(taskkind=0; taskkind<=2; taskkind++) { testmatinvunit_unset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), 0); } info = 0; testmatinvunit_unsetrep(&rep, _state); spdmatrixcholeskyinverse(&a, n, isupper, &info, &rep, _state); if( info!=-3&&info!=1 ) { *spderrors = ae_true; } else { *spderrors = (*spderrors||ae_fp_less(rep.r1,(double)(0)))||ae_fp_greater(rep.r1,1000*ae_machineepsilon); *spderrors = (*spderrors||ae_fp_less(rep.rinf,(double)(0)))||ae_fp_greater(rep.rinf,1000*ae_machineepsilon); } } } } ae_frame_leave(_state); } /************************************************************************* HPD test *************************************************************************/ static void testmatinvunit_testhpdinv(ae_int_t minn, ae_int_t maxn, ae_int_t passcount, double threshold, ae_bool* hpderrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_matrix inva; ae_matrix invcha; ae_bool isupper; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t pass; ae_int_t taskkind; ae_int_t info; matinvreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cha, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&inva, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&invcha, 0, 0, DT_COMPLEX, _state); _matinvreport_init(&rep, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=minn; n<=maxn; n++) { isupper = ae_fp_greater(ae_randomreal(_state),0.5); /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ hpdmatrixrndcond(n, (double)(1000), &a, _state); testmatinvunit_cmatrixdrophalf(&a, n, isupper, _state); testmatinvunit_cmatrixmakeacopy(&a, n, n, &cha, _state); if( !hpdmatrixcholesky(&cha, n, isupper, _state) ) { continue; } testmatinvunit_cmatrixmakeacopy(&a, n, n, &inva, _state); testmatinvunit_cmatrixmakeacopy(&cha, n, n, &invcha, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); hpdmatrixinverse(&inva, n, isupper, &info, &rep, _state); *hpderrors = *hpderrors||!testmatinvunit_hpdmatrixcheckinverse(&a, &inva, isupper, n, threshold, info, &rep, _state); info = 0; testmatinvunit_unsetrep(&rep, _state); hpdmatrixcholeskyinverse(&invcha, n, isupper, &info, &rep, _state); *hpderrors = *hpderrors||!testmatinvunit_hpdmatrixcheckinverse(&a, &invcha, isupper, n, threshold, info, &rep, _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * 2. test different methods */ for(taskkind=0; taskkind<=2; taskkind++) { testmatinvunit_cunset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); } info = 0; testmatinvunit_unsetrep(&rep, _state); hpdmatrixcholeskyinverse(&a, n, isupper, &info, &rep, _state); if( info!=-3&&info!=1 ) { *hpderrors = ae_true; } else { *hpderrors = (*hpderrors||ae_fp_less(rep.r1,(double)(0)))||ae_fp_greater(rep.r1,1000*ae_machineepsilon); *hpderrors = (*hpderrors||ae_fp_less(rep.rinf,(double)(0)))||ae_fp_greater(rep.rinf,1000*ae_machineepsilon); } } } } ae_frame_leave(_state); } /************************************************************************* Unsets real matrix *************************************************************************/ static void testmatinvunit_unset2d(/* Real */ ae_matrix* x, ae_state *_state) { ae_matrix_set_length(x, 1, 1, _state); x->ptr.pp_double[0][0] = 2*ae_randomreal(_state)-1; } /************************************************************************* Unsets real matrix *************************************************************************/ static void testmatinvunit_cunset2d(/* Complex */ ae_matrix* x, ae_state *_state) { ae_matrix_set_length(x, 1, 1, _state); x->ptr.pp_complex[0][0] = ae_complex_from_d(2*ae_randomreal(_state)-1); } /************************************************************************* Unsets report *************************************************************************/ static void testmatinvunit_unsetrep(matinvreport* r, ae_state *_state) { r->r1 = (double)(-1); r->rinf = (double)(-1); } static void testldaunit_gensimpleset(ae_int_t nfeatures, ae_int_t nclasses, ae_int_t nsamples, ae_int_t axis, /* Real */ ae_matrix* xy, ae_state *_state); static void testldaunit_gendeg1set(ae_int_t nfeatures, ae_int_t nclasses, ae_int_t nsamples, ae_int_t axis, /* Real */ ae_matrix* xy, ae_state *_state); static double testldaunit_generatenormal(double mean, double sigma, ae_state *_state); static ae_bool testldaunit_testwn(/* Real */ ae_matrix* xy, /* Real */ ae_matrix* wn, ae_int_t ns, ae_int_t nf, ae_int_t nc, ae_int_t ndeg, ae_state *_state); static double testldaunit_calcj(ae_int_t nf, /* Real */ ae_matrix* st, /* Real */ ae_matrix* sw, /* Real */ ae_vector* w, double* p, double* q, ae_state *_state); static void testldaunit_fishers(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t nclasses, /* Real */ ae_matrix* st, /* Real */ ae_matrix* sw, ae_state *_state); ae_bool testlda(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t maxnf; ae_int_t maxns; ae_int_t maxnc; ae_int_t passcount; ae_bool ldanerrors; ae_bool lda1errors; ae_bool waserrors; ae_int_t nf; ae_int_t nc; ae_int_t ns; ae_int_t i; ae_int_t info; ae_int_t pass; ae_int_t axis; ae_matrix xy; ae_matrix wn; ae_vector w1; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&wn, 0, 0, DT_REAL, _state); ae_vector_init(&w1, 0, DT_REAL, _state); /* * Primary settings */ maxnf = 10; maxns = 1000; maxnc = 5; passcount = 1; waserrors = ae_false; ldanerrors = ae_false; lda1errors = ae_false; /* * General tests */ for(nf=1; nf<=maxnf; nf++) { for(nc=2; nc<=maxnc; nc++) { for(pass=1; pass<=passcount; pass++) { /* * Simple test for LDA-N/LDA-1 */ axis = ae_randominteger(nf, _state); ns = maxns/2+ae_randominteger(maxns/2, _state); testldaunit_gensimpleset(nf, nc, ns, axis, &xy, _state); fisherldan(&xy, ns, nf, nc, &info, &wn, _state); if( info!=1 ) { ldanerrors = ae_true; continue; } ldanerrors = ldanerrors||!testldaunit_testwn(&xy, &wn, ns, nf, nc, 0, _state); ldanerrors = ldanerrors||ae_fp_less_eq(ae_fabs(wn.ptr.pp_double[axis][0], _state),0.75); fisherlda(&xy, ns, nf, nc, &info, &w1, _state); for(i=0; i<=nf-1; i++) { lda1errors = lda1errors||ae_fp_neq(w1.ptr.p_double[i],wn.ptr.pp_double[i][0]); } /* * Degenerate test for LDA-N */ if( nf>=3 ) { ns = maxns/2+ae_randominteger(maxns/2, _state); /* * there are two duplicate features, * axis is oriented along non-duplicate feature */ axis = ae_randominteger(nf-2, _state); testldaunit_gendeg1set(nf, nc, ns, axis, &xy, _state); fisherldan(&xy, ns, nf, nc, &info, &wn, _state); if( info!=2 ) { ldanerrors = ae_true; continue; } ldanerrors = ldanerrors||ae_fp_less_eq(wn.ptr.pp_double[axis][0],0.75); fisherlda(&xy, ns, nf, nc, &info, &w1, _state); for(i=0; i<=nf-1; i++) { lda1errors = lda1errors||ae_fp_neq(w1.ptr.p_double[i],wn.ptr.pp_double[i][0]); } } } } } /* * Final report */ waserrors = ldanerrors||lda1errors; if( !silent ) { printf("LDA TEST\n"); printf("FISHER LDA-N: "); if( !ldanerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("FISHER LDA-1: "); if( !lda1errors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlda(ae_bool silent, ae_state *_state) { return testlda(silent, _state); } /************************************************************************* Generates 'simple' set - a sequence of unit 'balls' at (0,0), (1,0), (2,0) and so on. *************************************************************************/ static void testldaunit_gensimpleset(ae_int_t nfeatures, ae_int_t nclasses, ae_int_t nsamples, ae_int_t axis, /* Real */ ae_matrix* xy, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t c; ae_matrix_clear(xy); ae_assert(axis>=0&&axisptr.pp_double[i][j] = testldaunit_generatenormal(0.0, 1.0, _state); } c = i%nclasses; xy->ptr.pp_double[i][axis] = xy->ptr.pp_double[i][axis]+c; xy->ptr.pp_double[i][nfeatures] = (double)(c); } } /************************************************************************* Generates 'degenerate' set #1. NFeatures>=3. *************************************************************************/ static void testldaunit_gendeg1set(ae_int_t nfeatures, ae_int_t nclasses, ae_int_t nsamples, ae_int_t axis, /* Real */ ae_matrix* xy, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t c; ae_matrix_clear(xy); ae_assert(axis>=0&&axis=3, "GenDeg1Set: wrong NFeatures!", _state); ae_matrix_set_length(xy, nsamples-1+1, nfeatures+1, _state); if( axis>=nfeatures-2 ) { axis = nfeatures-3; } for(i=0; i<=nsamples-1; i++) { for(j=0; j<=nfeatures-2; j++) { xy->ptr.pp_double[i][j] = testldaunit_generatenormal(0.0, 1.0, _state); } xy->ptr.pp_double[i][nfeatures-1] = xy->ptr.pp_double[i][nfeatures-2]; c = i%nclasses; xy->ptr.pp_double[i][axis] = xy->ptr.pp_double[i][axis]+c; xy->ptr.pp_double[i][nfeatures] = (double)(c); } } /************************************************************************* Normal random number *************************************************************************/ static double testldaunit_generatenormal(double mean, double sigma, ae_state *_state) { double u; double v; double sum; double result; result = mean; for(;;) { u = (2*ae_randominteger(2, _state)-1)*ae_randomreal(_state); v = (2*ae_randominteger(2, _state)-1)*ae_randomreal(_state); sum = u*u+v*v; if( ae_fp_less(sum,(double)(1))&&ae_fp_greater(sum,(double)(0)) ) { sum = ae_sqrt(-2*ae_log(sum, _state)/sum, _state); result = sigma*u*sum+mean; return result; } } return result; } /************************************************************************* Tests WN for correctness *************************************************************************/ static ae_bool testldaunit_testwn(/* Real */ ae_matrix* xy, /* Real */ ae_matrix* wn, ae_int_t ns, ae_int_t nf, ae_int_t nc, ae_int_t ndeg, ae_state *_state) { ae_frame _frame_block; ae_matrix st; ae_matrix sw; ae_matrix a; ae_matrix z; ae_vector tx; ae_vector jp; ae_vector jq; ae_vector work; ae_int_t i; ae_int_t j; double v; double wprev; double tol; double p; double q; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&st, 0, 0, DT_REAL, _state); ae_matrix_init(&sw, 0, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); ae_vector_init(&jp, 0, DT_REAL, _state); ae_vector_init(&jq, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); tol = (double)(10000); result = ae_true; testldaunit_fishers(xy, ns, nf, nc, &st, &sw, _state); /* * Test for decreasing of J */ ae_vector_set_length(&tx, nf-1+1, _state); ae_vector_set_length(&jp, nf-1+1, _state); ae_vector_set_length(&jq, nf-1+1, _state); for(j=0; j<=nf-1; j++) { ae_v_move(&tx.ptr.p_double[0], 1, &wn->ptr.pp_double[0][j], wn->stride, ae_v_len(0,nf-1)); v = testldaunit_calcj(nf, &st, &sw, &tx, &p, &q, _state); jp.ptr.p_double[j] = p; jq.ptr.p_double[j] = q; } for(i=1; i<=nf-1-ndeg; i++) { result = result&&ae_fp_greater_eq(jp.ptr.p_double[i-1]/jq.ptr.p_double[i-1],(1-tol*ae_machineepsilon)*jp.ptr.p_double[i]/jq.ptr.p_double[i]); } for(i=nf-1-ndeg+1; i<=nf-1; i++) { result = result&&ae_fp_less_eq(jp.ptr.p_double[i],tol*ae_machineepsilon*jp.ptr.p_double[0]); } /* * Test for J optimality */ ae_v_move(&tx.ptr.p_double[0], 1, &wn->ptr.pp_double[0][0], wn->stride, ae_v_len(0,nf-1)); v = testldaunit_calcj(nf, &st, &sw, &tx, &p, &q, _state); for(i=0; i<=nf-1; i++) { wprev = tx.ptr.p_double[i]; tx.ptr.p_double[i] = wprev+0.01; result = result&&ae_fp_greater_eq(v,(1-tol*ae_machineepsilon)*testldaunit_calcj(nf, &st, &sw, &tx, &p, &q, _state)); tx.ptr.p_double[i] = wprev-0.01; result = result&&ae_fp_greater_eq(v,(1-tol*ae_machineepsilon)*testldaunit_calcj(nf, &st, &sw, &tx, &p, &q, _state)); tx.ptr.p_double[i] = wprev; } /* * Test for linear independence of W */ ae_vector_set_length(&work, nf+1, _state); ae_matrix_set_length(&a, nf-1+1, nf-1+1, _state); matrixmatrixmultiply(wn, 0, nf-1, 0, nf-1, ae_false, wn, 0, nf-1, 0, nf-1, ae_true, 1.0, &a, 0, nf-1, 0, nf-1, 0.0, &work, _state); if( smatrixevd(&a, nf, 1, ae_true, &tx, &z, _state) ) { result = result&&ae_fp_greater(tx.ptr.p_double[0],tx.ptr.p_double[nf-1]*1000*ae_machineepsilon); } /* * Test for other properties */ for(j=0; j<=nf-1; j++) { v = ae_v_dotproduct(&wn->ptr.pp_double[0][j], wn->stride, &wn->ptr.pp_double[0][j], wn->stride, ae_v_len(0,nf-1)); v = ae_sqrt(v, _state); result = result&&ae_fp_less_eq(ae_fabs(v-1, _state),1000*ae_machineepsilon); v = (double)(0); for(i=0; i<=nf-1; i++) { v = v+wn->ptr.pp_double[i][j]; } result = result&&ae_fp_greater_eq(v,(double)(0)); } ae_frame_leave(_state); return result; } /************************************************************************* Calculates J *************************************************************************/ static double testldaunit_calcj(ae_int_t nf, /* Real */ ae_matrix* st, /* Real */ ae_matrix* sw, /* Real */ ae_vector* w, double* p, double* q, ae_state *_state) { ae_frame _frame_block; ae_vector tx; ae_int_t i; double v; double result; ae_frame_make(_state, &_frame_block); *p = 0; *q = 0; ae_vector_init(&tx, 0, DT_REAL, _state); ae_vector_set_length(&tx, nf-1+1, _state); for(i=0; i<=nf-1; i++) { v = ae_v_dotproduct(&st->ptr.pp_double[i][0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,nf-1)); tx.ptr.p_double[i] = v; } v = ae_v_dotproduct(&w->ptr.p_double[0], 1, &tx.ptr.p_double[0], 1, ae_v_len(0,nf-1)); *p = v; for(i=0; i<=nf-1; i++) { v = ae_v_dotproduct(&sw->ptr.pp_double[i][0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,nf-1)); tx.ptr.p_double[i] = v; } v = ae_v_dotproduct(&w->ptr.p_double[0], 1, &tx.ptr.p_double[0], 1, ae_v_len(0,nf-1)); *q = v; result = *p/(*q); ae_frame_leave(_state); return result; } /************************************************************************* Calculates ST/SW *************************************************************************/ static void testldaunit_fishers(/* Real */ ae_matrix* xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t nclasses, /* Real */ ae_matrix* st, /* Real */ ae_matrix* sw, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_vector c; ae_vector mu; ae_matrix muc; ae_vector nc; ae_vector tf; ae_vector work; ae_frame_make(_state, &_frame_block); ae_matrix_clear(st); ae_matrix_clear(sw); ae_vector_init(&c, 0, DT_INT, _state); ae_vector_init(&mu, 0, DT_REAL, _state); ae_matrix_init(&muc, 0, 0, DT_REAL, _state); ae_vector_init(&nc, 0, DT_INT, _state); ae_vector_init(&tf, 0, DT_REAL, _state); ae_vector_init(&work, 0, DT_REAL, _state); /* * Prepare temporaries */ ae_vector_set_length(&tf, nfeatures-1+1, _state); ae_vector_set_length(&work, nfeatures+1, _state); /* * Convert class labels from reals to integers (just for convenience) */ ae_vector_set_length(&c, npoints-1+1, _state); for(i=0; i<=npoints-1; i++) { c.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nfeatures], _state); } /* * Calculate class sizes and means */ ae_vector_set_length(&mu, nfeatures-1+1, _state); ae_matrix_set_length(&muc, nclasses-1+1, nfeatures-1+1, _state); ae_vector_set_length(&nc, nclasses-1+1, _state); for(j=0; j<=nfeatures-1; j++) { mu.ptr.p_double[j] = (double)(0); } for(i=0; i<=nclasses-1; i++) { nc.ptr.p_int[i] = 0; for(j=0; j<=nfeatures-1; j++) { muc.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=npoints-1; i++) { ae_v_add(&mu.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); ae_v_add(&muc.ptr.pp_double[c.ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); nc.ptr.p_int[c.ptr.p_int[i]] = nc.ptr.p_int[c.ptr.p_int[i]]+1; } for(i=0; i<=nclasses-1; i++) { v = (double)1/(double)nc.ptr.p_int[i]; ae_v_muld(&muc.ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1), v); } v = (double)1/(double)npoints; ae_v_muld(&mu.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1), v); /* * Create ST matrix */ ae_matrix_set_length(st, nfeatures-1+1, nfeatures-1+1, _state); for(i=0; i<=nfeatures-1; i++) { for(j=0; j<=nfeatures-1; j++) { st->ptr.pp_double[i][j] = (double)(0); } } for(k=0; k<=npoints-1; k++) { ae_v_move(&tf.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nfeatures-1)); ae_v_sub(&tf.ptr.p_double[0], 1, &mu.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); for(i=0; i<=nfeatures-1; i++) { v = tf.ptr.p_double[i]; ae_v_addd(&st->ptr.pp_double[i][0], 1, &tf.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1), v); } } /* * Create SW matrix */ ae_matrix_set_length(sw, nfeatures-1+1, nfeatures-1+1, _state); for(i=0; i<=nfeatures-1; i++) { for(j=0; j<=nfeatures-1; j++) { sw->ptr.pp_double[i][j] = (double)(0); } } for(k=0; k<=npoints-1; k++) { ae_v_move(&tf.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nfeatures-1)); ae_v_sub(&tf.ptr.p_double[0], 1, &muc.ptr.pp_double[c.ptr.p_int[k]][0], 1, ae_v_len(0,nfeatures-1)); for(i=0; i<=nfeatures-1; i++) { v = tf.ptr.p_double[i]; ae_v_addd(&sw->ptr.pp_double[i][0], 1, &tf.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1), v); } } ae_frame_leave(_state); } static double testmlpbaseunit_vectordiff(/* Real */ ae_vector* g0, /* Real */ ae_vector* g1, ae_int_t n, double s, ae_state *_state); static void testmlpbaseunit_createnetwork(multilayerperceptron* network, ae_int_t nkind, double a1, double a2, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_state *_state); static void testmlpbaseunit_unsetnetwork(multilayerperceptron* network, ae_state *_state); static void testmlpbaseunit_testinformational(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testmlpbaseunit_testprocessing(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testmlpbaseunit_testgradient(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state); static void testmlpbaseunit_testhessian(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testmlpbaseunit_testerr(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state); static void testmlpbaseunit_spectests(ae_bool* inferrors, ae_bool* procerrors, ae_bool* graderrors, ae_bool* hesserrors, ae_bool* errerrors, ae_state *_state); static ae_bool testmlpbaseunit_testmlpgbsubset(ae_state *_state); ae_bool testmlpbase(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_int_t passcount; ae_int_t maxn; ae_int_t maxhid; ae_int_t sizemin; ae_int_t sizemax; ae_int_t nf; ae_int_t nl; ae_int_t nhid1; ae_int_t nhid2; ae_int_t nkind; multilayerperceptron network; multilayerperceptron network2; ae_matrix xy; ae_matrix valxy; ae_bool inferrors; ae_bool procerrors; ae_bool graderrors; ae_bool hesserrors; ae_bool errerrors; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); _multilayerperceptron_init(&network2, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&valxy, 0, 0, DT_REAL, _state); waserrors = ae_false; inferrors = ae_false; procerrors = ae_false; graderrors = ae_false; hesserrors = ae_false; errerrors = ae_false; passcount = 5; maxn = 3; maxhid = 3; /* * Special tests */ testmlpbaseunit_spectests(&inferrors, &procerrors, &graderrors, &hesserrors, &errerrors, _state); /* * General multilayer network tests. * These tests are performed with small dataset, whose size is in [0,10]. * We test correctness of functions on small sets, but do not test code * which splits large dataset into smaller chunks. */ sizemin = 0; sizemax = 10; for(nf=1; nf<=maxn; nf++) { for(nl=1; nl<=maxn; nl++) { for(nhid1=0; nhid1<=maxhid; nhid1++) { for(nhid2=0; nhid2<=maxhid; nhid2++) { for(nkind=0; nkind<=3; nkind++) { /* * Skip meaningless parameters combinations */ if( nkind==1&&nl<2 ) { continue; } if( nhid1==0&&nhid2!=0 ) { continue; } /* * Tests */ testmlpbaseunit_testinformational(nkind, nf, nhid1, nhid2, nl, passcount, &inferrors, _state); testmlpbaseunit_testprocessing(nkind, nf, nhid1, nhid2, nl, passcount, &procerrors, _state); testmlpbaseunit_testgradient(nkind, nf, nhid1, nhid2, nl, passcount, sizemin, sizemax, &graderrors, _state); testmlpbaseunit_testhessian(nkind, nf, nhid1, nhid2, nl, passcount, &hesserrors, _state); testmlpbaseunit_testerr(nkind, nf, nhid1, nhid2, nl, passcount, sizemin, sizemax, &errerrors, _state); } } } } } /* * Special tests on large datasets: test ability to correctly split * work into smaller chunks. */ nf = 2; nhid1 = 30; nhid2 = 30; nl = 2; sizemin = 1000; sizemax = 1000; testmlpbaseunit_testerr(0, nf, nhid1, nhid2, nl, 1, sizemin, sizemax, &errerrors, _state); testmlpbaseunit_testgradient(0, nf, nhid1, nhid2, nl, 1, sizemin, sizemax, &graderrors, _state); /* * Test for MLPGradBatch____Subset() */ graderrors = graderrors||testmlpbaseunit_testmlpgbsubset(_state); /* * Final report */ waserrors = (((inferrors||procerrors)||graderrors)||hesserrors)||errerrors; if( !silent ) { printf("MLP TEST\n"); printf("INFORMATIONAL FUNCTIONS: "); if( !inferrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BASIC PROCESSING: "); if( !procerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("GRADIENT CALCULATION: "); if( !graderrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("HESSIAN CALCULATION: "); if( !hesserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("ERROR FUNCTIONS: "); if( !errerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmlpbase(ae_bool silent, ae_state *_state) { return testmlpbase(silent, _state); } /************************************************************************* This function compares vectors G0 and G1 and returns ||G0-G1||/max(||G0||,||G1||,S) For zero G0, G1 and S (all three quantities are zero) it returns zero. *************************************************************************/ static double testmlpbaseunit_vectordiff(/* Real */ ae_vector* g0, /* Real */ ae_vector* g1, ae_int_t n, double s, ae_state *_state) { ae_int_t i; double norm0; double norm1; double diff; double result; norm0 = (double)(0); norm1 = (double)(0); diff = (double)(0); for(i=0; i<=n-1; i++) { norm0 = norm0+ae_sqr(g0->ptr.p_double[i], _state); norm1 = norm1+ae_sqr(g1->ptr.p_double[i], _state); diff = diff+ae_sqr(g0->ptr.p_double[i]-g1->ptr.p_double[i], _state); } norm0 = ae_sqrt(norm0, _state); norm1 = ae_sqrt(norm1, _state); diff = ae_sqrt(diff, _state); if( (ae_fp_neq(norm0,(double)(0))||ae_fp_neq(norm1,(double)(0)))||ae_fp_neq(s,(double)(0)) ) { diff = diff/ae_maxreal(ae_maxreal(norm0, norm1, _state), s, _state); } else { diff = (double)(0); } result = diff; return result; } /************************************************************************* Network creation This function creates network with desired structure. Network is created using one of the three methods: a) straightforward creation using MLPCreate???() b) MLPCreate???() for proxy object, which is copied with PassThroughSerializer() c) MLPCreate???() for proxy object, which is copied with MLPCopy() One of these methods is chosen at random. *************************************************************************/ static void testmlpbaseunit_createnetwork(multilayerperceptron* network, ae_int_t nkind, double a1, double a2, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_state *_state) { ae_frame _frame_block; ae_int_t mkind; multilayerperceptron tmp; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&tmp, _state); ae_assert(((nin>0&&nhid1>=0)&&nhid2>=0)&&nout>0, "CreateNetwork error", _state); ae_assert(nhid1!=0||nhid2==0, "CreateNetwork error", _state); ae_assert(nkind!=1||nout>=2, "CreateNetwork error", _state); mkind = ae_randominteger(3, _state); if( nhid1==0 ) { /* * No hidden layers */ if( nkind==0 ) { if( mkind==0 ) { mlpcreate0(nin, nout, network, _state); } if( mkind==1 ) { mlpcreate0(nin, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreate0(nin, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==1 ) { if( mkind==0 ) { mlpcreatec0(nin, nout, network, _state); } if( mkind==1 ) { mlpcreatec0(nin, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreatec0(nin, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==2 ) { if( mkind==0 ) { mlpcreateb0(nin, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreateb0(nin, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreateb0(nin, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==3 ) { if( mkind==0 ) { mlpcreater0(nin, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreater0(nin, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreater0(nin, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } } } } mlprandomizefull(network, _state); ae_frame_leave(_state); return; } if( nhid2==0 ) { /* * One hidden layer */ if( nkind==0 ) { if( mkind==0 ) { mlpcreate1(nin, nhid1, nout, network, _state); } if( mkind==1 ) { mlpcreate1(nin, nhid1, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreate1(nin, nhid1, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==1 ) { if( mkind==0 ) { mlpcreatec1(nin, nhid1, nout, network, _state); } if( mkind==1 ) { mlpcreatec1(nin, nhid1, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreatec1(nin, nhid1, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==2 ) { if( mkind==0 ) { mlpcreateb1(nin, nhid1, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreateb1(nin, nhid1, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreateb1(nin, nhid1, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==3 ) { if( mkind==0 ) { mlpcreater1(nin, nhid1, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreater1(nin, nhid1, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreater1(nin, nhid1, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } } } } mlprandomizefull(network, _state); ae_frame_leave(_state); return; } /* * Two hidden layers */ if( nkind==0 ) { if( mkind==0 ) { mlpcreate2(nin, nhid1, nhid2, nout, network, _state); } if( mkind==1 ) { mlpcreate2(nin, nhid1, nhid2, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreate2(nin, nhid1, nhid2, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==1 ) { if( mkind==0 ) { mlpcreatec2(nin, nhid1, nhid2, nout, network, _state); } if( mkind==1 ) { mlpcreatec2(nin, nhid1, nhid2, nout, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreatec2(nin, nhid1, nhid2, nout, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==2 ) { if( mkind==0 ) { mlpcreateb2(nin, nhid1, nhid2, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreateb2(nin, nhid1, nhid2, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreateb2(nin, nhid1, nhid2, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } else { if( nkind==3 ) { if( mkind==0 ) { mlpcreater2(nin, nhid1, nhid2, nout, a1, a2, network, _state); } if( mkind==1 ) { mlpcreater2(nin, nhid1, nhid2, nout, a1, a2, &tmp, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &tmp, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &tmp, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } } if( mkind==2 ) { mlpcreater2(nin, nhid1, nhid2, nout, a1, a2, &tmp, _state); mlpcopy(&tmp, network, _state); } } } } } mlprandomizefull(network, _state); ae_frame_leave(_state); } /************************************************************************* Unsets network (initialize it to smallest network possible *************************************************************************/ static void testmlpbaseunit_unsetnetwork(multilayerperceptron* network, ae_state *_state) { mlpcreate0(1, 1, network, _state); } /************************************************************************* Informational functions test *************************************************************************/ static void testmlpbaseunit_testinformational(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; multilayerperceptron network; ae_int_t n1; ae_int_t n2; ae_int_t wcount; ae_int_t i; ae_int_t j; ae_int_t k; double threshold; ae_int_t nlayers; ae_int_t nmax; ae_bool issoftmax; ae_matrix neurons; ae_vector x; ae_vector y; double mean; double sigma; ae_int_t fkind; double c; double f; double df; double d2f; double s; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); ae_matrix_init(&neurons, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); threshold = 100000*ae_machineepsilon; testmlpbaseunit_createnetwork(&network, nkind, 0.0, 0.0, nin, nhid1, nhid2, nout, _state); /* * test MLPProperties() */ mlpproperties(&network, &n1, &n2, &wcount, _state); *err = ((*err||n1!=nin)||n2!=nout)||wcount<=0; *err = ((*err||mlpgetinputscount(&network, _state)!=nin)||mlpgetoutputscount(&network, _state)!=nout)||mlpgetweightscount(&network, _state)!=wcount; /* * Test network geometry functions * * In order to do this we calculate neural network output using * informational functions only, and compare results with ones * obtained with MLPProcess(): * 1. we allocate 2-dimensional array of neurons and fill it by zeros * 2. we full first layer of neurons by input values * 3. we move through array, calculating values of subsequent layers * 4. if we have classification network, we SOFTMAX-normalize output layer * 5. we apply scaling to the outputs * 6. we compare results with ones obtained by MLPProcess() * * NOTE: it is important to do (4) before (5), because on SOFTMAX network * MLPGetOutputScaling() must return Mean=0 and Sigma=1. In order * to test it implicitly, we apply it to the classifier results * (already normalized). If one of the coefficients deviates from * expected values, we will get error during (6). */ nlayers = 2; nmax = ae_maxint(nin, nout, _state); issoftmax = nkind==1; if( nhid1!=0 ) { nlayers = 3; nmax = ae_maxint(nmax, nhid1, _state); } if( nhid2!=0 ) { nlayers = 4; nmax = ae_maxint(nmax, nhid2, _state); } ae_matrix_set_length(&neurons, nlayers, nmax, _state); for(i=0; i<=nlayers-1; i++) { for(j=0; j<=nmax-1; j++) { neurons.ptr.pp_double[i][j] = (double)(0); } } ae_vector_set_length(&x, nin, _state); for(i=0; i<=nin-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&y, nout, _state); for(i=0; i<=nout-1; i++) { y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(j=0; j<=nin-1; j++) { mlpgetinputscaling(&network, j, &mean, &sigma, _state); neurons.ptr.pp_double[0][j] = (x.ptr.p_double[j]-mean)/sigma; } for(i=1; i<=nlayers-1; i++) { for(j=0; j<=mlpgetlayersize(&network, i, _state)-1; j++) { for(k=0; k<=mlpgetlayersize(&network, i-1, _state)-1; k++) { neurons.ptr.pp_double[i][j] = neurons.ptr.pp_double[i][j]+mlpgetweight(&network, i-1, k, i, j, _state)*neurons.ptr.pp_double[i-1][k]; } mlpgetneuroninfo(&network, i, j, &fkind, &c, _state); mlpactivationfunction(neurons.ptr.pp_double[i][j]-c, fkind, &f, &df, &d2f, _state); neurons.ptr.pp_double[i][j] = f; } } if( nkind==1 ) { s = (double)(0); for(j=0; j<=nout-1; j++) { s = s+ae_exp(neurons.ptr.pp_double[nlayers-1][j], _state); } for(j=0; j<=nout-1; j++) { neurons.ptr.pp_double[nlayers-1][j] = ae_exp(neurons.ptr.pp_double[nlayers-1][j], _state)/s; } } for(j=0; j<=nout-1; j++) { mlpgetoutputscaling(&network, j, &mean, &sigma, _state); neurons.ptr.pp_double[nlayers-1][j] = neurons.ptr.pp_double[nlayers-1][j]*sigma+mean; } mlpprocess(&network, &x, &y, _state); for(j=0; j<=nout-1; j++) { *err = *err||ae_fp_greater(ae_fabs(neurons.ptr.pp_double[nlayers-1][j]-y.ptr.p_double[j], _state),threshold); } ae_frame_leave(_state); } /************************************************************************* Processing functions test *************************************************************************/ static void testmlpbaseunit_testprocessing(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; multilayerperceptron network; multilayerperceptron network2; sparsematrix sparsexy; ae_matrix densexy; ae_int_t npoints; ae_int_t subnp; ae_bool iscls; ae_int_t n1; ae_int_t n2; ae_int_t wcount; ae_bool zeronet; double a1; double a2; ae_int_t pass; ae_int_t i; ae_int_t j; ae_bool allsame; ae_vector x1; ae_vector x2; ae_vector y1; ae_vector y2; ae_vector p0; ae_vector p1; ae_int_t pcount; double v; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); _multilayerperceptron_init(&network2, _state); _sparsematrix_init(&sparsexy, _state); ae_matrix_init(&densexy, 0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&p0, 0, DT_REAL, _state); ae_vector_init(&p1, 0, DT_REAL, _state); ae_assert(passcount>=2, "PassCount<2!", _state); /* * Prepare network */ a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } testmlpbaseunit_createnetwork(&network, nkind, a1, a2, nin, nhid1, nhid2, nout, _state); mlpproperties(&network, &n1, &n2, &wcount, _state); iscls = mlpissoftmax(&network, _state); /* * Initialize arrays */ ae_vector_set_length(&x1, nin, _state); ae_vector_set_length(&x2, nin, _state); ae_vector_set_length(&y1, nout, _state); ae_vector_set_length(&y2, nout, _state); /* * Initialize sets */ npoints = ae_randominteger(11, _state)+10; if( iscls ) { ae_matrix_set_length(&densexy, npoints, nin+1, _state); sparsecreate(npoints, nin+1, npoints, &sparsexy, _state); } else { ae_matrix_set_length(&densexy, npoints, nin+nout, _state); sparsecreate(npoints, nin+nout, npoints, &sparsexy, _state); } sparseconverttocrs(&sparsexy, _state); /* * Main cycle */ for(pass=1; pass<=passcount; pass++) { /* * Last run is made on zero network */ mlprandomizefull(&network, _state); zeronet = ae_false; if( pass==passcount ) { ae_v_muld(&network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), 0); zeronet = ae_true; } /* * Same inputs leads to same outputs */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network, &x2, &y2, _state); seterrorflag(err, ae_fp_neq(testmlpbaseunit_vectordiff(&y1, &y2, nout, 1.0, _state),0.0), _state); /* * Same inputs on original network leads to same outputs * on copy created: * * using MLPCopy * * using MLPCopyShared */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } testmlpbaseunit_unsetnetwork(&network2, _state); mlpcopy(&network, &network2, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x2, &y2, _state); seterrorflag(err, ae_fp_neq(testmlpbaseunit_vectordiff(&y1, &y2, nout, 1.0, _state),0.0), _state); for(i=0; i<=nout-1; i++) { y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } testmlpbaseunit_unsetnetwork(&network2, _state); mlpcopyshared(&network, &network2, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x2, &y2, _state); seterrorflag(err, ae_fp_neq(testmlpbaseunit_vectordiff(&y1, &y2, nout, 1.0, _state),0.0), _state); /* * Additionally we tests functions for copying of tunable * parameters by: * * copying network using MLPCopy * * randomizing tunable parameters with MLPRandomizeFull() * * copying tunable parameters with: * a) MLPCopyTunableParameters * b) combination of MLPExportTunableParameters and * MLPImportTunableParameters - we export parameters * to P1, copy PCount elements to P2, then test import. */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } testmlpbaseunit_unsetnetwork(&network2, _state); mlpcopy(&network, &network2, _state); mlprandomizefull(&network2, _state); mlpcopytunableparameters(&network, &network2, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x2, &y2, _state); seterrorflag(err, ae_fp_neq(testmlpbaseunit_vectordiff(&y1, &y2, nout, 1.0, _state),0.0), _state); for(i=0; i<=nout-1; i++) { y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } testmlpbaseunit_unsetnetwork(&network2, _state); mlpcopy(&network, &network2, _state); mlprandomizefull(&network2, _state); mlpexporttunableparameters(&network, &p0, &pcount, _state); ae_vector_set_length(&p1, pcount, _state); for(i=0; i<=pcount-1; i++) { p1.ptr.p_double[i] = p0.ptr.p_double[i]; } mlpimporttunableparameters(&network2, &p1, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x2, &y2, _state); seterrorflag(err, ae_fp_neq(testmlpbaseunit_vectordiff(&y1, &y2, nout, 1.0, _state),0.0), _state); /* * Same inputs on original network leads to same outputs * on copy created using MLPSerialize */ testmlpbaseunit_unsetnetwork(&network2, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpalloc(&_local_serializer, &network, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpserialize(&_local_serializer, &network, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpunserialize(&_local_serializer, &network2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Different inputs leads to different outputs (non-zero network) */ if( !zeronet ) { for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = y1.ptr.p_double[i]; } mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||allsame; } /* * Randomization changes outputs (when inputs are unchanged, non-zero network) */ if( !zeronet ) { for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = y1.ptr.p_double[i]; } mlpcopy(&network, &network2, _state); mlprandomize(&network2, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x1, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||allsame; } /* * Full randomization changes outputs (when inputs are unchanged, non-zero network) */ if( !zeronet ) { for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = y1.ptr.p_double[i]; } mlpcopy(&network, &network2, _state); mlprandomizefull(&network2, _state); mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x1, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||allsame; } /* * Normalization properties */ if( nkind==1 ) { /* * Classifier network outputs are normalized */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); v = (double)(0); for(i=0; i<=nout-1; i++) { v = v+y1.ptr.p_double[i]; *err = *err||ae_fp_less(y1.ptr.p_double[i],(double)(0)); } *err = *err||ae_fp_greater(ae_fabs(v-1, _state),1000*ae_machineepsilon); } if( nkind==2 ) { /* * B-type network outputs are bounded from above/below */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); for(i=0; i<=nout-1; i++) { if( ae_fp_greater_eq(a2,(double)(0)) ) { *err = *err||ae_fp_less(y1.ptr.p_double[i],a1); } else { *err = *err||ae_fp_greater(y1.ptr.p_double[i],a1); } } } if( nkind==3 ) { /* * R-type network outputs are within [A1,A2] (or [A2,A1]) */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); for(i=0; i<=nout-1; i++) { *err = (*err||ae_fp_less(y1.ptr.p_double[i],ae_minreal(a1, a2, _state)))||ae_fp_greater(y1.ptr.p_double[i],ae_maxreal(a1, a2, _state)); } } /* * Comperison MLPInitPreprocessor results with * MLPInitPreprocessorSparse results */ sparseconverttohash(&sparsexy, _state); if( iscls ) { for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin-1; j++) { densexy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; sparseset(&sparsexy, i, j, densexy.ptr.pp_double[i][j], _state); } densexy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, i, j, densexy.ptr.pp_double[i][nin], _state); } } else { for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin+nout-1; j++) { densexy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; sparseset(&sparsexy, i, j, densexy.ptr.pp_double[i][j], _state); } } } sparseconverttocrs(&sparsexy, _state); mlpcopy(&network, &network2, _state); mlpinitpreprocessor(&network, &densexy, npoints, _state); mlpinitpreprocessorsparse(&network2, &sparsexy, npoints, _state); subnp = ae_randominteger(npoints, _state); for(i=0; i<=subnp-1; i++) { for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 2*ae_randomreal(_state)-1; } mlpprocess(&network, &x1, &y1, _state); mlpprocess(&network2, &x1, &y2, _state); for(j=0; j<=nout-1; j++) { *err = *err||ae_fp_greater(ae_fabs(y1.ptr.p_double[j]-y2.ptr.p_double[j], _state),1.0E-6); } } } ae_frame_leave(_state); } /************************************************************************* Gradient functions test *************************************************************************/ static void testmlpbaseunit_testgradient(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state) { ae_frame _frame_block; multilayerperceptron network; sparsematrix sparsexy; sparsematrix sparsexy2; ae_int_t n1; ae_int_t n2; ae_int_t wcount; double h; double etol; double escale; double gscale; double nonstricttolerance; double a1; double a2; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t ssize; ae_int_t subsetsize; ae_int_t rowsize; ae_matrix xy; ae_matrix xy2; ae_vector grad1; ae_vector grad2; ae_vector gradsp; ae_vector x; ae_vector y; ae_vector x1; ae_vector x2; ae_vector y1; ae_vector y2; ae_vector idx; double v; double e; double e1; double e2; double esp; double v1; double v2; double v3; double v4; double wprev; double referencee; ae_vector referenceg; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); _sparsematrix_init(&sparsexy, _state); _sparsematrix_init(&sparsexy2, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&xy2, 0, 0, DT_REAL, _state); ae_vector_init(&grad1, 0, DT_REAL, _state); ae_vector_init(&grad2, 0, DT_REAL, _state); ae_vector_init(&gradsp, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&idx, 0, DT_INT, _state); ae_vector_init(&referenceg, 0, DT_REAL, _state); a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } testmlpbaseunit_createnetwork(&network, nkind, a1, a2, nin, nhid1, nhid2, nout, _state); mlpproperties(&network, &n1, &n2, &wcount, _state); h = 0.0001; etol = 1.0E-2; escale = 1.0E-2; gscale = 1.0E-2; nonstricttolerance = 0.01; /* * Initialize */ ae_vector_set_length(&x, nin, _state); ae_vector_set_length(&x1, nin, _state); ae_vector_set_length(&x2, nin, _state); ae_vector_set_length(&y, nout, _state); ae_vector_set_length(&y1, nout, _state); ae_vector_set_length(&y2, nout, _state); ae_vector_set_length(&referenceg, wcount, _state); ae_vector_set_length(&grad1, wcount, _state); ae_vector_set_length(&grad2, wcount, _state); /* * Process */ for(pass=1; pass<=passcount; pass++) { /* * Randomize network, then re-randomaze weights manually. * * NOTE: weights magnitude is chosen to be small, about 0.1, * which allows us to avoid oversaturated network. * In 10% of cases we use zero weights. */ mlprandomizefull(&network, _state); if( ae_fp_less_eq(ae_randomreal(_state),0.1) ) { for(i=0; i<=wcount-1; i++) { network.weights.ptr.p_double[i] = 0.0; } } else { for(i=0; i<=wcount-1; i++) { network.weights.ptr.p_double[i] = 0.2*ae_randomreal(_state)-0.1; } } /* * Test MLPError(), MLPErrorSparse(), MLPGrad() for single-element dataset: * * generate input X, output Y, combine them in dataset XY * * calculate "reference" error on dataset manually (call MLPProcess and evaluate sum-of-squared errors) * * calculate "reference" gradient by performing numerical differentiation of "reference" error * using 4-point differentiation formula * * test error/gradient returned by MLPGrad(), MLPError(), MLPErrorSparse() */ ae_matrix_set_length(&xy, 1, nin+nout, _state); sparsecreate(1, nin+nout, nin+nout, &sparsexy, _state); for(i=0; i<=nin-1; i++) { x.ptr.p_double[i] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[0][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,nin-1)); for(i=0; i<=nin-1; i++) { sparseset(&sparsexy, 0, i, x.ptr.p_double[i], _state); } if( mlpissoftmax(&network, _state) ) { for(i=0; i<=nout-1; i++) { y.ptr.p_double[i] = (double)(0); } xy.ptr.pp_double[0][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, 0, nin, xy.ptr.pp_double[0][nin], _state); y.ptr.p_double[ae_round(xy.ptr.pp_double[0][nin], _state)] = (double)(1); } else { for(i=0; i<=nout-1; i++) { y.ptr.p_double[i] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, 0, nin+i, y.ptr.p_double[i], _state); } ae_v_move(&xy.ptr.pp_double[0][nin], 1, &y.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } sparseconverttocrs(&sparsexy, _state); mlpprocess(&network, &x, &y2, _state); ae_v_sub(&y2.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); referencee = ae_v_dotproduct(&y2.ptr.p_double[0], 1, &y2.ptr.p_double[0], 1, ae_v_len(0,nout-1)); referencee = referencee/2; for(i=0; i<=wcount-1; i++) { wprev = network.weights.ptr.p_double[i]; network.weights.ptr.p_double[i] = wprev-2*h; mlpprocess(&network, &x, &y1, _state); ae_v_sub(&y1.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v1 = ae_v_dotproduct(&y1.ptr.p_double[0], 1, &y1.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v1 = v1/2; network.weights.ptr.p_double[i] = wprev-h; mlpprocess(&network, &x, &y1, _state); ae_v_sub(&y1.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v2 = ae_v_dotproduct(&y1.ptr.p_double[0], 1, &y1.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v2 = v2/2; network.weights.ptr.p_double[i] = wprev+h; mlpprocess(&network, &x, &y1, _state); ae_v_sub(&y1.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v3 = ae_v_dotproduct(&y1.ptr.p_double[0], 1, &y1.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v3 = v3/2; network.weights.ptr.p_double[i] = wprev+2*h; mlpprocess(&network, &x, &y1, _state); ae_v_sub(&y1.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v4 = ae_v_dotproduct(&y1.ptr.p_double[0], 1, &y1.ptr.p_double[0], 1, ae_v_len(0,nout-1)); v4 = v4/2; network.weights.ptr.p_double[i] = wprev; referenceg.ptr.p_double[i] = (v1-8*v2+8*v3-v4)/(12*h); } mlpgrad(&network, &x, &y, &e, &grad2, _state); seterrorflagdiff(err, e, referencee, etol, escale, _state); seterrorflagdiff(err, mlperror(&network, &xy, 1, _state), referencee, etol, escale, _state); seterrorflagdiff(err, mlperrorsparse(&network, &sparsexy, 1, _state), referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); /* * Test MLPErrorN(), MLPGradN() for single-element dataset: * * generate input X, output Y, combine them in dataset XY * * calculate "reference" error on dataset manually (call MLPProcess and evaluate sum-of-squared errors) * * calculate "reference" gradient by performing numerical differentiation of "reference" error * * test error/gradient returned by MLPGradN(), MLPErrorN() * * NOTE: because we use inexact 2-point formula, we perform gradient test with NonStrictTolerance */ ae_matrix_set_length(&xy, 1, nin+nout, _state); for(i=0; i<=nin-1; i++) { x.ptr.p_double[i] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[0][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(i=0; i<=nout-1; i++) { y.ptr.p_double[i] = (double)(0); } xy.ptr.pp_double[0][nin] = (double)(ae_randominteger(nout, _state)); y.ptr.p_double[ae_round(xy.ptr.pp_double[0][nin], _state)] = (double)(1); } else { for(i=0; i<=nout-1; i++) { y.ptr.p_double[i] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[0][nin], 1, &y.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } mlpprocess(&network, &x, &y2, _state); referencee = (double)(0); if( nkind!=1 ) { for(i=0; i<=nout-1; i++) { referencee = referencee+0.5*ae_sqr(y2.ptr.p_double[i]-y.ptr.p_double[i], _state); } } else { for(i=0; i<=nout-1; i++) { if( ae_fp_neq(y.ptr.p_double[i],(double)(0)) ) { if( ae_fp_eq(y2.ptr.p_double[i],(double)(0)) ) { referencee = referencee+y.ptr.p_double[i]*ae_log(ae_maxrealnumber, _state); } else { referencee = referencee+y.ptr.p_double[i]*ae_log(y.ptr.p_double[i]/y2.ptr.p_double[i], _state); } } } } for(i=0; i<=wcount-1; i++) { wprev = network.weights.ptr.p_double[i]; network.weights.ptr.p_double[i] = wprev+h; mlpprocess(&network, &x, &y2, _state); network.weights.ptr.p_double[i] = wprev-h; mlpprocess(&network, &x, &y1, _state); network.weights.ptr.p_double[i] = wprev; v = (double)(0); if( nkind!=1 ) { for(j=0; j<=nout-1; j++) { v = v+0.5*(ae_sqr(y2.ptr.p_double[j]-y.ptr.p_double[j], _state)-ae_sqr(y1.ptr.p_double[j]-y.ptr.p_double[j], _state))/(2*h); } } else { for(j=0; j<=nout-1; j++) { if( ae_fp_neq(y.ptr.p_double[j],(double)(0)) ) { if( ae_fp_eq(y2.ptr.p_double[j],(double)(0)) ) { v = v+y.ptr.p_double[j]*ae_log(ae_maxrealnumber, _state); } else { v = v+y.ptr.p_double[j]*ae_log(y.ptr.p_double[j]/y2.ptr.p_double[j], _state); } if( ae_fp_eq(y1.ptr.p_double[j],(double)(0)) ) { v = v-y.ptr.p_double[j]*ae_log(ae_maxrealnumber, _state); } else { v = v-y.ptr.p_double[j]*ae_log(y.ptr.p_double[j]/y1.ptr.p_double[j], _state); } } } v = v/(2*h); } referenceg.ptr.p_double[i] = v; } mlpgradn(&network, &x, &y, &e, &grad2, _state); seterrorflagdiff(err, e, referencee, etol, escale, _state); seterrorflagdiff(err, mlperrorn(&network, &xy, 1, _state), referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),nonstricttolerance), _state); /* * Test that gradient calculation functions automatically allocate * space for gradient, if needed. * * NOTE: we perform test with empty dataset. */ sparsecreate(1, nin+nout, 0, &sparsexy, _state); sparseconverttocrs(&sparsexy, _state); ae_vector_set_length(&grad1, 1, _state); mlpgradbatch(&network, &xy, 0, &e1, &grad1, _state); seterrorflag(err, grad1.cnt!=wcount, _state); ae_vector_set_length(&grad1, 1, _state); mlpgradbatchsparse(&network, &sparsexy, 0, &e1, &grad1, _state); seterrorflag(err, grad1.cnt!=wcount, _state); ae_vector_set_length(&grad1, 1, _state); mlpgradbatchsubset(&network, &xy, 0, &idx, 0, &e1, &grad1, _state); seterrorflag(err, grad1.cnt!=wcount, _state); ae_vector_set_length(&grad1, 1, _state); mlpgradbatchsparsesubset(&network, &sparsexy, 0, &idx, 0, &e1, &grad1, _state); seterrorflag(err, grad1.cnt!=wcount, _state); /* * Test MLPError(), MLPErrorSparse(), MLPGradBatch(), MLPGradBatchSparse() for many-element dataset: * * generate random dataset XY * * calculate "reference" error/gradient using MLPGrad(), which was tested in previous * section and is assumed to work correctly * * test results returned by MLPGradBatch/MLPGradBatchSparse against reference ones * * NOTE: about 10% of tests are performed with zero SSize */ ssize = sizemin+ae_randominteger(sizemax-sizemin+1, _state); ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+nout, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+nout, ssize*(nin+nout), &sparsexy, _state); for(i=0; i<=wcount-1; i++) { referenceg.ptr.p_double[i] = (double)(0); } referencee = (double)(0); for(i=0; i<=ssize-1; i++) { for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, j, x1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, i, nin, xy.ptr.pp_double[i][nin], _state); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, nin+j, y1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } mlpgrad(&network, &x1, &y1, &v, &grad2, _state); referencee = referencee+v; ae_v_add(&referenceg.ptr.p_double[0], 1, &grad2.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } sparseconverttocrs(&sparsexy, _state); e2 = mlperror(&network, &xy, ssize, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); e2 = mlperrorsparse(&network, &sparsexy, ssize, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); mlpgradbatch(&network, &xy, ssize, &e2, &grad2, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); mlpgradbatchsparse(&network, &sparsexy, ssize, &esp, &gradsp, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &gradsp, wcount, gscale, _state),etol), _state); /* * Test MLPErrorSubset(), MLPGradBatchSubset(), MLPErrorSparseSubset(), MLPGradBatchSparseSubset() * for many-element dataset with different types of subsets: * * generate random dataset XY * * "reference" error/gradient are calculated with MLPGradBatch(), * which was tested in previous section and is assumed to work correctly * * we perform tests for different subsets: * * SubsetSize<0 - subset is a full dataset * * SubsetSize=0 - subset is empty * * SubsetSize>0 - random subset */ ssize = sizemin+ae_randominteger(sizemax-sizemin+1, _state); ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+nout, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+nout, ssize*(nin+nout), &sparsexy, _state); for(i=0; i<=ssize-1; i++) { for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, j, x1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, i, nin, xy.ptr.pp_double[i][nin], _state); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, nin+j, y1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } } sparseconverttocrs(&sparsexy, _state); if( ssize>0 ) { subsetsize = 1+ae_randominteger(10, _state); ae_matrix_set_length(&xy2, subsetsize, nin+nout, _state); ae_vector_set_length(&idx, subsetsize, _state); sparsecreate(subsetsize, nin+nout, subsetsize*(nin+nout), &sparsexy2, _state); if( mlpissoftmax(&network, _state) ) { rowsize = nin+1; } else { rowsize = nin+nout; } for(i=0; i<=subsetsize-1; i++) { k = ae_randominteger(ssize, _state); idx.ptr.p_int[i] = k; for(j=0; j<=rowsize-1; j++) { xy2.ptr.pp_double[i][j] = xy.ptr.pp_double[k][j]; sparseset(&sparsexy2, i, j, sparseget(&sparsexy, k, j, _state), _state); } } sparseconverttocrs(&sparsexy2, _state); } else { subsetsize = 0; ae_matrix_set_length(&xy2, 0, 0, _state); ae_vector_set_length(&idx, 0, _state); sparsecreate(1, nin+nout, 0, &sparsexy2, _state); sparseconverttocrs(&sparsexy2, _state); } mlpgradbatch(&network, &xy, ssize, &referencee, &referenceg, _state); e2 = mlperrorsubset(&network, &xy, ssize, &idx, -1, _state); esp = mlperrorsparsesubset(&network, &sparsexy, ssize, &idx, -1, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); mlpgradbatchsubset(&network, &xy, ssize, &idx, -1, &e2, &grad2, _state); mlpgradbatchsparsesubset(&network, &sparsexy, ssize, &idx, -1, &esp, &gradsp, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &gradsp, wcount, gscale, _state),etol), _state); mlpgradbatch(&network, &xy, 0, &referencee, &referenceg, _state); e2 = mlperrorsubset(&network, &xy, ssize, &idx, 0, _state); esp = mlperrorsparsesubset(&network, &sparsexy, ssize, &idx, 0, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); mlpgradbatchsubset(&network, &xy, ssize, &idx, 0, &e2, &grad2, _state); mlpgradbatchsparsesubset(&network, &sparsexy, ssize, &idx, 0, &esp, &gradsp, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &gradsp, wcount, gscale, _state),etol), _state); mlpgradbatch(&network, &xy2, subsetsize, &referencee, &referenceg, _state); e2 = mlperrorsubset(&network, &xy, ssize, &idx, subsetsize, _state); esp = mlperrorsparsesubset(&network, &sparsexy, ssize, &idx, subsetsize, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); mlpgradbatchsubset(&network, &xy, ssize, &idx, subsetsize, &e2, &grad2, _state); mlpgradbatchsparsesubset(&network, &sparsexy, ssize, &idx, subsetsize, &esp, &gradsp, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflagdiff(err, esp, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &gradsp, wcount, gscale, _state),etol), _state); /* * Test MLPGradNBatch() for many-element dataset: * * generate random dataset XY * * calculate "reference" error/gradient using MLPGrad(), which was tested in previous * section and is assumed to work correctly * * test results returned by MLPGradNBatch against reference ones */ ssize = sizemin+ae_randominteger(sizemax-sizemin+1, _state); ae_matrix_set_length(&xy, ssize, nin+nout, _state); for(i=0; i<=wcount-1; i++) { referenceg.ptr.p_double[i] = (double)(0); } referencee = (double)(0); for(i=0; i<=ssize-1; i++) { for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } mlpgradn(&network, &x1, &y1, &v, &grad2, _state); referencee = referencee+v; ae_v_add(&referenceg.ptr.p_double[0], 1, &grad2.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } mlpgradnbatch(&network, &xy, ssize, &e2, &grad2, _state); seterrorflagdiff(err, e2, referencee, etol, escale, _state); seterrorflag(err, ae_fp_greater(testmlpbaseunit_vectordiff(&referenceg, &grad2, wcount, gscale, _state),etol), _state); } ae_frame_leave(_state); } /************************************************************************* Hessian functions test *************************************************************************/ static void testmlpbaseunit_testhessian(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; multilayerperceptron network; ae_int_t hkind; ae_int_t n1; ae_int_t n2; ae_int_t wcount; double h; double etol; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t ssize; double a1; double a2; ae_matrix xy; ae_matrix h1; ae_matrix h2; ae_vector grad1; ae_vector grad2; ae_vector grad3; ae_vector x; ae_vector y; ae_vector x1; ae_vector x2; ae_vector y1; ae_vector y2; double v; double e1; double e2; double wprev; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&h1, 0, 0, DT_REAL, _state); ae_matrix_init(&h2, 0, 0, DT_REAL, _state); ae_vector_init(&grad1, 0, DT_REAL, _state); ae_vector_init(&grad2, 0, DT_REAL, _state); ae_vector_init(&grad3, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_assert(passcount>=2, "PassCount<2!", _state); a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } testmlpbaseunit_createnetwork(&network, nkind, a1, a2, nin, nhid1, nhid2, nout, _state); mlpproperties(&network, &n1, &n2, &wcount, _state); h = 0.0001; etol = 0.05; /* * Initialize */ ae_vector_set_length(&x, nin-1+1, _state); ae_vector_set_length(&x1, nin-1+1, _state); ae_vector_set_length(&x2, nin-1+1, _state); ae_vector_set_length(&y, nout-1+1, _state); ae_vector_set_length(&y1, nout-1+1, _state); ae_vector_set_length(&y2, nout-1+1, _state); ae_vector_set_length(&grad1, wcount-1+1, _state); ae_vector_set_length(&grad2, wcount-1+1, _state); ae_vector_set_length(&grad3, wcount-1+1, _state); ae_matrix_set_length(&h1, wcount-1+1, wcount-1+1, _state); ae_matrix_set_length(&h2, wcount-1+1, wcount-1+1, _state); /* * Process */ for(pass=1; pass<=passcount; pass++) { mlprandomizefull(&network, _state); /* * Test hessian calculation . * E1 contains total error (calculated using MLPGrad/MLPGradN) * Grad1 contains total gradient (calculated using MLPGrad/MLPGradN) * H1 contains Hessian calculated using differences of gradients * * E2, Grad2 and H2 contains corresponing values calculated using MLPHessianBatch/MLPHessianNBatch */ for(hkind=0; hkind<=1; hkind++) { ssize = 1+ae_randominteger(10, _state); ae_matrix_set_length(&xy, ssize-1+1, nin+nout-1+1, _state); for(i=0; i<=wcount-1; i++) { grad1.ptr.p_double[i] = (double)(0); } for(i=0; i<=wcount-1; i++) { for(j=0; j<=wcount-1; j++) { h1.ptr.pp_double[i][j] = (double)(0); } } e1 = (double)(0); for(i=0; i<=ssize-1; i++) { /* * X, Y */ for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } /* * E1, Grad1 */ if( hkind==0 ) { mlpgrad(&network, &x1, &y1, &v, &grad2, _state); } else { mlpgradn(&network, &x1, &y1, &v, &grad2, _state); } e1 = e1+v; ae_v_add(&grad1.ptr.p_double[0], 1, &grad2.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); /* * H1 */ for(j=0; j<=wcount-1; j++) { wprev = network.weights.ptr.p_double[j]; network.weights.ptr.p_double[j] = wprev-2*h; if( hkind==0 ) { mlpgrad(&network, &x1, &y1, &v, &grad2, _state); } else { mlpgradn(&network, &x1, &y1, &v, &grad2, _state); } network.weights.ptr.p_double[j] = wprev-h; if( hkind==0 ) { mlpgrad(&network, &x1, &y1, &v, &grad3, _state); } else { mlpgradn(&network, &x1, &y1, &v, &grad3, _state); } ae_v_subd(&grad2.ptr.p_double[0], 1, &grad3.ptr.p_double[0], 1, ae_v_len(0,wcount-1), 8); network.weights.ptr.p_double[j] = wprev+h; if( hkind==0 ) { mlpgrad(&network, &x1, &y1, &v, &grad3, _state); } else { mlpgradn(&network, &x1, &y1, &v, &grad3, _state); } ae_v_addd(&grad2.ptr.p_double[0], 1, &grad3.ptr.p_double[0], 1, ae_v_len(0,wcount-1), 8); network.weights.ptr.p_double[j] = wprev+2*h; if( hkind==0 ) { mlpgrad(&network, &x1, &y1, &v, &grad3, _state); } else { mlpgradn(&network, &x1, &y1, &v, &grad3, _state); } ae_v_sub(&grad2.ptr.p_double[0], 1, &grad3.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); v = 1/(12*h); ae_v_addd(&h1.ptr.pp_double[j][0], 1, &grad2.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); network.weights.ptr.p_double[j] = wprev; } } if( hkind==0 ) { mlphessianbatch(&network, &xy, ssize, &e2, &grad2, &h2, _state); } else { mlphessiannbatch(&network, &xy, ssize, &e2, &grad2, &h2, _state); } *err = *err||ae_fp_greater(ae_fabs(e1-e2, _state)/e1,etol); for(i=0; i<=wcount-1; i++) { if( ae_fp_greater(ae_fabs(grad1.ptr.p_double[i], _state),1.0E-2) ) { *err = *err||ae_fp_greater(ae_fabs((grad2.ptr.p_double[i]-grad1.ptr.p_double[i])/grad1.ptr.p_double[i], _state),etol); } else { *err = *err||ae_fp_greater(ae_fabs(grad2.ptr.p_double[i]-grad1.ptr.p_double[i], _state),etol); } } for(i=0; i<=wcount-1; i++) { for(j=0; j<=wcount-1; j++) { if( ae_fp_greater(ae_fabs(h1.ptr.pp_double[i][j], _state),5.0E-2) ) { *err = *err||ae_fp_greater(ae_fabs((h1.ptr.pp_double[i][j]-h2.ptr.pp_double[i][j])/h1.ptr.pp_double[i][j], _state),etol); } else { *err = *err||ae_fp_greater(ae_fabs(h2.ptr.pp_double[i][j]-h1.ptr.pp_double[i][j], _state),etol); } } } } } ae_frame_leave(_state); } /************************************************************************* Error functions (other than MLPError and MLPErrorN) test. Network of type NKind is created, with NIn inputs, NHid1*NHid2 hidden layers (one layer if NHid2=0), NOut outputs. PassCount random passes is performed. Dataset has random size in [SizeMin,SizeMax]. *************************************************************************/ static void testmlpbaseunit_testerr(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state) { ae_frame _frame_block; multilayerperceptron network; sparsematrix sparsexy; ae_int_t n1; ae_int_t n2; ae_int_t wcount; double etol; double escale; double a1; double a2; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t ssize; ae_int_t subsetsize; ae_matrix xy; ae_vector y; ae_vector x1; ae_vector y1; ae_vector idx; ae_vector dummy; double refrmserror; double refclserror; double refrelclserror; double refavgce; double refavgerror; double refavgrelerror; ae_int_t avgrelcnt; modelerrors allerrors; ae_int_t nnmax; ae_int_t dsmax; double relclstolerance; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); _sparsematrix_init(&sparsexy, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&idx, 0, DT_INT, _state); ae_vector_init(&dummy, 0, DT_INT, _state); _modelerrors_init(&allerrors, _state); a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } testmlpbaseunit_createnetwork(&network, nkind, a1, a2, nin, nhid1, nhid2, nout, _state); mlpproperties(&network, &n1, &n2, &wcount, _state); etol = 1.0E-4; escale = 1.0E-2; /* * Initialize */ ae_vector_set_length(&x1, nin, _state); ae_vector_set_length(&y, nout, _state); ae_vector_set_length(&y1, nout, _state); /* * Process */ for(pass=1; pass<=passcount; pass++) { /* * Randomize network, then re-randomaze weights manually. * * NOTE: weights magnitude is chosen to be small, about 0.1, * which allows us to avoid oversaturated network. * In 10% of cases we use zero weights. */ mlprandomizefull(&network, _state); if( ae_fp_less_eq(ae_randomreal(_state),0.1) ) { for(i=0; i<=wcount-1; i++) { network.weights.ptr.p_double[i] = 0.0; } } else { for(i=0; i<=wcount-1; i++) { network.weights.ptr.p_double[i] = 0.2*ae_randomreal(_state)-0.1; } } /* * Generate random dataset. * Calculate reference errors. * * NOTE: about 10% of tests are performed with zero SSize */ ssize = sizemin+ae_randominteger(sizemax-sizemin+1, _state); if( mlpissoftmax(&network, _state) ) { ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+1, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+1, 0, &sparsexy, _state); } else { ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+nout, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+nout, 0, &sparsexy, _state); } refrmserror = 0.0; refclserror = 0.0; refavgce = 0.0; refavgerror = 0.0; refavgrelerror = 0.0; avgrelcnt = 0; for(i=0; i<=ssize-1; i++) { /* * Fill I-th row */ for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, j, x1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, i, nin, xy.ptr.pp_double[i][nin], _state); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, nin+j, y1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } /* * Process */ mlpprocess(&network, &x1, &y, _state); /* * Update reference errors */ nnmax = 0; if( mlpissoftmax(&network, _state) ) { if( ae_fp_greater(y.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)],(double)(0)) ) { refavgce = refavgce+ae_log(1/y.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)], _state); } else { refavgce = refavgce+ae_log(ae_maxrealnumber, _state); } } if( mlpissoftmax(&network, _state) ) { dsmax = ae_round(xy.ptr.pp_double[i][nin], _state); } else { dsmax = 0; } for(j=0; j<=nout-1; j++) { refrmserror = refrmserror+ae_sqr(y.ptr.p_double[j]-y1.ptr.p_double[j], _state); refavgerror = refavgerror+ae_fabs(y.ptr.p_double[j]-y1.ptr.p_double[j], _state); if( ae_fp_neq(y1.ptr.p_double[j],(double)(0)) ) { refavgrelerror = refavgrelerror+ae_fabs(y.ptr.p_double[j]-y1.ptr.p_double[j], _state)/ae_fabs(y1.ptr.p_double[j], _state); avgrelcnt = avgrelcnt+1; } if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[nnmax]) ) { nnmax = j; } if( !mlpissoftmax(&network, _state)&&ae_fp_greater(y1.ptr.p_double[j],y1.ptr.p_double[dsmax]) ) { dsmax = j; } } if( nnmax!=dsmax ) { refclserror = refclserror+1; } } sparseconverttocrs(&sparsexy, _state); if( ssize>0 ) { refrmserror = ae_sqrt(refrmserror/(ssize*nout), _state); refavgerror = refavgerror/(ssize*nout); refrelclserror = refclserror/ssize; refavgce = refavgce/(ssize*ae_log((double)(2), _state)); } else { refrelclserror = 0.0; } if( avgrelcnt>0 ) { refavgrelerror = refavgrelerror/avgrelcnt; } /* * Test "continuous" errors on full dataset */ seterrorflagdiff(err, mlprmserror(&network, &xy, ssize, _state), refrmserror, etol, escale, _state); seterrorflagdiff(err, mlpavgce(&network, &xy, ssize, _state), refavgce, etol, escale, _state); seterrorflagdiff(err, mlpavgerror(&network, &xy, ssize, _state), refavgerror, etol, escale, _state); seterrorflagdiff(err, mlpavgrelerror(&network, &xy, ssize, _state), refavgrelerror, etol, escale, _state); seterrorflagdiff(err, mlprmserrorsparse(&network, &sparsexy, ssize, _state), refrmserror, etol, escale, _state); seterrorflagdiff(err, mlpavgcesparse(&network, &sparsexy, ssize, _state), refavgce, etol, escale, _state); seterrorflagdiff(err, mlpavgerrorsparse(&network, &sparsexy, ssize, _state), refavgerror, etol, escale, _state); seterrorflagdiff(err, mlpavgrelerrorsparse(&network, &sparsexy, ssize, _state), refavgrelerror, etol, escale, _state); mlpallerrorssubset(&network, &xy, ssize, &dummy, -1, &allerrors, _state); seterrorflagdiff(err, allerrors.avgce, refavgce, etol, escale, _state); seterrorflagdiff(err, allerrors.rmserror, refrmserror, etol, escale, _state); seterrorflagdiff(err, allerrors.avgerror, refavgerror, etol, escale, _state); seterrorflagdiff(err, allerrors.avgrelerror, refavgrelerror, etol, escale, _state); mlpallerrorssparsesubset(&network, &sparsexy, ssize, &dummy, -1, &allerrors, _state); seterrorflagdiff(err, allerrors.avgce, refavgce, etol, escale, _state); seterrorflagdiff(err, allerrors.rmserror, refrmserror, etol, escale, _state); seterrorflagdiff(err, allerrors.avgerror, refavgerror, etol, escale, _state); seterrorflagdiff(err, allerrors.avgrelerror, refavgrelerror, etol, escale, _state); /* * Test errors on dataset given by subset. * We perform only limited test for RMS error, assuming that either all errors * are calculated correctly (subject to subset given by Idx) - or none of them. */ if( ssize>0 ) { subsetsize = ae_randominteger(10, _state); } else { subsetsize = 0; } ae_vector_set_length(&idx, subsetsize, _state); refrmserror = 0.0; for(i=0; i<=subsetsize-1; i++) { k = ae_randominteger(ssize, _state); idx.ptr.p_int[i] = k; ae_v_move(&x1.ptr.p_double[0], 1, &xy.ptr.pp_double[k][0], 1, ae_v_len(0,nin-1)); if( mlpissoftmax(&network, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } y1.ptr.p_double[ae_round(xy.ptr.pp_double[k][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = xy.ptr.pp_double[k][nin+j]; } } mlpprocess(&network, &x1, &y, _state); for(j=0; j<=nout-1; j++) { refrmserror = refrmserror+ae_sqr(y.ptr.p_double[j]-y1.ptr.p_double[j], _state); } } if( subsetsize>0 ) { refrmserror = ae_sqrt(refrmserror/(subsetsize*nout), _state); } mlpallerrorssubset(&network, &xy, ssize, &idx, subsetsize, &allerrors, _state); seterrorflagdiff(err, allerrors.rmserror, refrmserror, etol, escale, _state); mlpallerrorssparsesubset(&network, &sparsexy, ssize, &idx, subsetsize, &allerrors, _state); seterrorflagdiff(err, allerrors.rmserror, refrmserror, etol, escale, _state); /* * Test "discontinuous" error function. * Even slight changes in the network output may force these functions * to change by 1. So, we test them with relaxed criteria, corresponding to * difference in classification of two samples. */ if( ssize>0 ) { relclstolerance = 2.5/ssize; seterrorflag(err, ae_fp_greater(ae_fabs(mlpclserror(&network, &xy, ssize, _state)-refclserror, _state),ssize*relclstolerance), _state); seterrorflag(err, ae_fp_greater(ae_fabs(mlprelclserror(&network, &xy, ssize, _state)-refrelclserror, _state),relclstolerance), _state); seterrorflag(err, ae_fp_greater(ae_fabs(mlprelclserrorsparse(&network, &sparsexy, ssize, _state)-refrelclserror, _state),relclstolerance), _state); } } ae_frame_leave(_state); } /************************************************************************* Special tests *************************************************************************/ static void testmlpbaseunit_spectests(ae_bool* inferrors, ae_bool* procerrors, ae_bool* graderrors, ae_bool* hesserrors, ae_bool* errerrors, ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_matrix xy; double f; ae_vector g; ae_int_t i; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); /* * Special test for overflow in TanH: * * create 1x1x1 linear network * * create dataset with 1 item: [x, y] = [0, 1] * * set network weights to [10000000, 10000000, 10000000, 10000000] * * check that error function is finite * * check that gradient is finite */ mlpcreate1(1, 1, 1, &net, _state); ae_matrix_set_length(&xy, 1, 2, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = 1.0; for(i=0; i<=mlpgetweightscount(&net, _state)-1; i++) { net.weights.ptr.p_double[i] = 10000000.0; } mlpgradbatch(&net, &xy, 1, &f, &g, _state); seterrorflag(graderrors, !ae_isfinite(f, _state), _state); seterrorflag(graderrors, !ae_isfinite(mlperror(&net, &xy, 1, _state), _state), _state); for(i=0; i<=mlpgetweightscount(&net, _state)-1; i++) { seterrorflag(graderrors, !ae_isfinite(g.ptr.p_double[i], _state), _state); } /* * Special test for overflow in SOFTMAX layer: * * create 1x1x2 classifier network * * create dataset with 1 item: [x, y] = [0, 1] * * set network weights to [10000000, 10000000, 10000000, 10000000] * * check that error function is finite * * check that gradient is finite */ mlpcreatec1(1, 1, 2, &net, _state); ae_matrix_set_length(&xy, 1, 2, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(1); for(i=0; i<=mlpgetweightscount(&net, _state)-1; i++) { net.weights.ptr.p_double[i] = 10000000.0; } mlpgradbatch(&net, &xy, 1, &f, &g, _state); seterrorflag(graderrors, !ae_isfinite(f, _state), _state); seterrorflag(graderrors, !ae_isfinite(mlperror(&net, &xy, 1, _state), _state), _state); for(i=0; i<=mlpgetweightscount(&net, _state)-1; i++) { seterrorflag(graderrors, !ae_isfinite(g.ptr.p_double[i], _state), _state); } ae_frame_leave(_state); } /************************************************************************* The function test functions MLPGradBatchMasked and MLPGradBatchSparseMasked. *************************************************************************/ static ae_bool testmlpbaseunit_testmlpgbsubset(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; ae_matrix a; ae_matrix parta; sparsematrix sa; sparsematrix partsa; ae_vector idx; double e1; double e2; ae_vector grad1; ae_vector grad2; ae_int_t nin; ae_int_t nout; ae_int_t w; ae_int_t wcount; ae_int_t nhid1; ae_int_t nhid2; ae_int_t nkind; double a1; double a2; ae_int_t n1; ae_int_t n2; ae_int_t ssize; ae_int_t maxssize; ae_int_t sbsize; ae_int_t nvar; ae_int_t variant; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&parta, 0, 0, DT_REAL, _state); _sparsematrix_init(&sa, _state); _sparsematrix_init(&partsa, _state); ae_vector_init(&idx, 0, DT_INT, _state); ae_vector_init(&grad1, 0, DT_REAL, _state); ae_vector_init(&grad2, 0, DT_REAL, _state); /* * Variant: * * 1 - there are all rows; * * 2 - there are no one rows; * * 3 - there are some random rows. */ nvar = 3; maxssize = 96; for(ssize=0; ssize<=maxssize; ssize++) { ae_vector_set_length(&idx, ssize, _state); nkind = ae_randominteger(4, _state); a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } nin = ae_randominteger(20, _state)+1; nhid1 = ae_randominteger(5, _state); if( nhid1==0 ) { nhid2 = 0; } else { nhid2 = ae_randominteger(5, _state); } nout = ae_randominteger(20, _state)+2; testmlpbaseunit_createnetwork(&net, nkind, a1, a2, nin, nhid1, nhid2, nout, _state); mlpproperties(&net, &n1, &n2, &wcount, _state); if( mlpissoftmax(&net, _state) ) { w = nin+1; if( ssize>0 ) { ae_matrix_set_length(&a, ssize, w, _state); sparsecreate(ssize, w, ssize*w, &sa, _state); } else { ae_matrix_set_length(&a, 0, 0, _state); sparsecreate(1, 1, 0, &sa, _state); } for(i=0; i<=ssize-1; i++) { for(j=0; j<=w-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } } for(i=0; i<=ssize-1; i++) { a.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sa, i, nin, a.ptr.pp_double[i][nin], _state); } } else { w = nin+nout; if( ssize>0 ) { ae_matrix_set_length(&a, ssize, w, _state); sparsecreate(ssize, w, ssize*w, &sa, _state); } else { ae_matrix_set_length(&a, 0, 0, _state); sparsecreate(1, 1, 0, &sa, _state); } for(i=0; i<=ssize-1; i++) { for(j=0; j<=w-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } } } sparseconverttocrs(&sa, _state); for(variant=1; variant<=nvar; variant++) { sbsize = -1; if( variant==1 ) { sbsize = ssize; for(i=0; i<=sbsize-1; i++) { idx.ptr.p_int[i] = i; } } if( variant==2 ) { sbsize = 0; } if( variant==3 ) { if( ssize==0 ) { sbsize = 0; } else { sbsize = ae_randominteger(ssize, _state); } for(i=0; i<=sbsize-1; i++) { idx.ptr.p_int[i] = ae_randominteger(ssize, _state); } } ae_assert(sbsize>=0, "mlpbase test: integrity check failed", _state); if( sbsize!=0 ) { ae_matrix_set_length(&parta, sbsize, w, _state); sparsecreate(sbsize, w, sbsize*w, &partsa, _state); } else { ae_matrix_set_length(&parta, 0, 0, _state); sparsecreate(1, 1, 0, &partsa, _state); } for(i=0; i<=sbsize-1; i++) { ae_v_move(&parta.ptr.pp_double[i][0], 1, &a.ptr.pp_double[idx.ptr.p_int[i]][0], 1, ae_v_len(0,w-1)); for(j=0; j<=w-1; j++) { sparseset(&partsa, i, j, parta.ptr.pp_double[i][j], _state); } } sparseconverttocrs(&partsa, _state); mlpgradbatch(&net, &parta, sbsize, &e1, &grad1, _state); mlpgradbatchsubset(&net, &a, ssize, &idx, sbsize, &e2, &grad2, _state); /* * Test for dense matrix */ if( ae_fp_greater(ae_fabs(e1-e2, _state),1.0E-6) ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=wcount-1; i++) { if( ae_fp_greater(ae_fabs(grad1.ptr.p_double[i]-grad2.ptr.p_double[i], _state),1.0E-6) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Test for sparse matrix */ mlpgradbatchsparse(&net, &partsa, sbsize, &e1, &grad1, _state); mlpgradbatchsparsesubset(&net, &sa, ssize, &idx, sbsize, &e2, &grad2, _state); if( ae_fp_greater(ae_fabs(e1-e2, _state),1.0E-6) ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=wcount-1; i++) { if( ae_fp_greater(ae_fabs(grad1.ptr.p_double[i]-grad2.ptr.p_double[i], _state),1.0E-6) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } ae_bool testxblas(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool approxerrors; ae_bool exactnesserrors; ae_bool waserrors; double approxthreshold; ae_int_t maxn; ae_int_t passcount; ae_int_t n; ae_int_t i; ae_int_t pass; double rv1; double rv2; double rv2err; ae_complex cv1; ae_complex cv2; double cv2err; ae_vector rx; ae_vector ry; ae_vector cx; ae_vector cy; ae_vector temp; double s; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&rx, 0, DT_REAL, _state); ae_vector_init(&ry, 0, DT_REAL, _state); ae_vector_init(&cx, 0, DT_COMPLEX, _state); ae_vector_init(&cy, 0, DT_COMPLEX, _state); ae_vector_init(&temp, 0, DT_REAL, _state); approxerrors = ae_false; exactnesserrors = ae_false; waserrors = ae_false; approxthreshold = 1000*ae_machineepsilon; maxn = 1000; passcount = 10; /* * tests: * 1. ability to calculate dot product * 2. higher precision */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { /* * ability to approximately calculate real dot product */ ae_vector_set_length(&rx, n, _state); ae_vector_set_length(&ry, n, _state); ae_vector_set_length(&temp, n, _state); for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_randomreal(_state),0.2) ) { rx.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { rx.ptr.p_double[i] = (double)(0); } if( ae_fp_greater(ae_randomreal(_state),0.2) ) { ry.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { ry.ptr.p_double[i] = (double)(0); } } rv1 = ae_v_dotproduct(&rx.ptr.p_double[0], 1, &ry.ptr.p_double[0], 1, ae_v_len(0,n-1)); xdot(&rx, &ry, n, &temp, &rv2, &rv2err, _state); approxerrors = approxerrors||ae_fp_greater(ae_fabs(rv1-rv2, _state),approxthreshold); /* * ability to approximately calculate complex dot product */ ae_vector_set_length(&cx, n, _state); ae_vector_set_length(&cy, n, _state); ae_vector_set_length(&temp, 2*n, _state); for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_randomreal(_state),0.2) ) { cx.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cx.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } else { cx.ptr.p_complex[i] = ae_complex_from_i(0); } if( ae_fp_greater(ae_randomreal(_state),0.2) ) { cy.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cy.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } else { cy.ptr.p_complex[i] = ae_complex_from_i(0); } } cv1 = ae_v_cdotproduct(&cx.ptr.p_complex[0], 1, "N", &cy.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); xcdot(&cx, &cy, n, &temp, &cv2, &cv2err, _state); approxerrors = approxerrors||ae_fp_greater(ae_c_abs(ae_c_sub(cv1,cv2), _state),approxthreshold); } } /* * test of precision: real */ n = 50000; ae_vector_set_length(&rx, n, _state); ae_vector_set_length(&ry, n, _state); ae_vector_set_length(&temp, n, _state); for(pass=0; pass<=passcount-1; pass++) { ae_assert(n%2==0, "Assertion failed", _state); /* * First test: X + X + ... + X - X - X - ... - X = 1*X */ s = ae_exp((double)(ae_maxint(pass, 50, _state)), _state); if( pass==passcount-1&&pass>1 ) { s = ae_maxrealnumber; } ry.ptr.p_double[0] = (2*ae_randomreal(_state)-1)*s*ae_sqrt(2*ae_randomreal(_state), _state); for(i=1; i<=n-1; i++) { ry.ptr.p_double[i] = ry.ptr.p_double[0]; } for(i=0; i<=n/2-1; i++) { rx.ptr.p_double[i] = (double)(1); } for(i=n/2; i<=n-2; i++) { rx.ptr.p_double[i] = (double)(-1); } rx.ptr.p_double[n-1] = (double)(0); xdot(&rx, &ry, n, &temp, &rv2, &rv2err, _state); exactnesserrors = exactnesserrors||ae_fp_less(rv2err,(double)(0)); exactnesserrors = exactnesserrors||ae_fp_greater(rv2err,4*ae_machineepsilon*ae_fabs(ry.ptr.p_double[0], _state)); exactnesserrors = exactnesserrors||ae_fp_greater(ae_fabs(rv2-ry.ptr.p_double[0], _state),rv2err); /* * First test: X + X + ... + X = N*X */ s = ae_exp((double)(ae_maxint(pass, 50, _state)), _state); if( pass==passcount-1&&pass>1 ) { s = ae_maxrealnumber; } ry.ptr.p_double[0] = (2*ae_randomreal(_state)-1)*s*ae_sqrt(2*ae_randomreal(_state), _state); for(i=1; i<=n-1; i++) { ry.ptr.p_double[i] = ry.ptr.p_double[0]; } for(i=0; i<=n-1; i++) { rx.ptr.p_double[i] = (double)(1); } xdot(&rx, &ry, n, &temp, &rv2, &rv2err, _state); exactnesserrors = exactnesserrors||ae_fp_less(rv2err,(double)(0)); exactnesserrors = exactnesserrors||ae_fp_greater(rv2err,4*ae_machineepsilon*ae_fabs(ry.ptr.p_double[0], _state)*n); exactnesserrors = exactnesserrors||ae_fp_greater(ae_fabs(rv2-n*ry.ptr.p_double[0], _state),rv2err); } /* * test of precision: complex */ n = 50000; ae_vector_set_length(&cx, n, _state); ae_vector_set_length(&cy, n, _state); ae_vector_set_length(&temp, 2*n, _state); for(pass=0; pass<=passcount-1; pass++) { ae_assert(n%2==0, "Assertion failed", _state); /* * First test: X + X + ... + X - X - X - ... - X = 1*X */ s = ae_exp((double)(ae_maxint(pass, 50, _state)), _state); if( pass==passcount-1&&pass>1 ) { s = ae_maxrealnumber; } cy.ptr.p_complex[0].x = (2*ae_randomreal(_state)-1)*s*ae_sqrt(2*ae_randomreal(_state), _state); cy.ptr.p_complex[0].y = (2*ae_randomreal(_state)-1)*s*ae_sqrt(2*ae_randomreal(_state), _state); for(i=1; i<=n-1; i++) { cy.ptr.p_complex[i] = cy.ptr.p_complex[0]; } for(i=0; i<=n/2-1; i++) { cx.ptr.p_complex[i] = ae_complex_from_i(1); } for(i=n/2; i<=n-2; i++) { cx.ptr.p_complex[i] = ae_complex_from_i(-1); } cx.ptr.p_complex[n-1] = ae_complex_from_i(0); xcdot(&cx, &cy, n, &temp, &cv2, &cv2err, _state); exactnesserrors = exactnesserrors||ae_fp_less(cv2err,(double)(0)); exactnesserrors = exactnesserrors||ae_fp_greater(cv2err,4*ae_machineepsilon*ae_c_abs(cy.ptr.p_complex[0], _state)); exactnesserrors = exactnesserrors||ae_fp_greater(ae_c_abs(ae_c_sub(cv2,cy.ptr.p_complex[0]), _state),cv2err); /* * First test: X + X + ... + X = N*X */ s = ae_exp((double)(ae_maxint(pass, 50, _state)), _state); if( pass==passcount-1&&pass>1 ) { s = ae_maxrealnumber; } cy.ptr.p_complex[0] = ae_complex_from_d((2*ae_randomreal(_state)-1)*s*ae_sqrt(2*ae_randomreal(_state), _state)); for(i=1; i<=n-1; i++) { cy.ptr.p_complex[i] = cy.ptr.p_complex[0]; } for(i=0; i<=n-1; i++) { cx.ptr.p_complex[i] = ae_complex_from_i(1); } xcdot(&cx, &cy, n, &temp, &cv2, &cv2err, _state); exactnesserrors = exactnesserrors||ae_fp_less(cv2err,(double)(0)); exactnesserrors = exactnesserrors||ae_fp_greater(cv2err,4*ae_machineepsilon*ae_c_abs(cy.ptr.p_complex[0], _state)*n); exactnesserrors = exactnesserrors||ae_fp_greater(ae_c_abs(ae_c_sub(cv2,ae_c_mul_d(cy.ptr.p_complex[0],1.0*n)), _state),cv2err); } /* * report */ waserrors = approxerrors||exactnesserrors; if( !silent ) { printf("TESTING XBLAS\n"); printf("APPROX.TESTS: "); if( approxerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("EXACT TESTS: "); if( exactnesserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testxblas(ae_bool silent, ae_state *_state) { return testxblas(silent, _state); } static ae_bool testdensesolverunit_rmatrixchecksolutionm(/* Real */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, densesolverreport* rep, /* Real */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksolutionmfast(/* Real */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, /* Real */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksolution(/* Real */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, densesolverreport* rep, /* Real */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksolutionfast(/* Real */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, /* Real */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksingularm(ae_int_t n, ae_int_t m, ae_int_t info, densesolverreport* rep, /* Real */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksingularmfast(ae_int_t n, ae_int_t m, ae_int_t info, /* Real */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksingular(ae_int_t n, ae_int_t info, densesolverreport* rep, /* Real */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_rmatrixchecksingularfast(ae_int_t n, ae_int_t info, /* Real */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksolutionm(/* Complex */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, densesolverreport* rep, /* Complex */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksolutionmfast(/* Complex */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, /* Complex */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksolution(/* Complex */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, densesolverreport* rep, /* Complex */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksolutionfast(/* Complex */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, /* Complex */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksingularm(ae_int_t n, ae_int_t m, ae_int_t info, densesolverreport* rep, /* Complex */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksingularmfast(ae_int_t n, ae_int_t m, ae_int_t info, /* Complex */ ae_matrix* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksingular(ae_int_t n, ae_int_t info, densesolverreport* rep, /* Complex */ ae_vector* xs, ae_state *_state); static ae_bool testdensesolverunit_cmatrixchecksingularfast(ae_int_t n, ae_int_t info, /* Complex */ ae_vector* xs, ae_state *_state); static void testdensesolverunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state); static void testdensesolverunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state); static void testdensesolverunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testdensesolverunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state); static void testdensesolverunit_testrsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* rerrors, ae_bool* rfserrors, ae_state *_state); static void testdensesolverunit_testspdsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* spderrors, ae_bool* rfserrors, ae_state *_state); static void testdensesolverunit_testcsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* cerrors, ae_bool* rfserrors, ae_state *_state); static void testdensesolverunit_testhpdsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* hpderrors, ae_bool* rfserrors, ae_state *_state); static void testdensesolverunit_unset2d(/* Real */ ae_matrix* x, ae_state *_state); static void testdensesolverunit_unset1d(/* Real */ ae_vector* x, ae_state *_state); static void testdensesolverunit_cunset2d(/* Complex */ ae_matrix* x, ae_state *_state); static void testdensesolverunit_cunset1d(/* Complex */ ae_vector* x, ae_state *_state); static void testdensesolverunit_unsetrep(densesolverreport* r, ae_state *_state); static void testdensesolverunit_unsetlsrep(densesolverlsreport* r, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testdensesolver(ae_bool silent, ae_state *_state) { ae_int_t maxn; ae_int_t maxm; ae_int_t passcount; double threshold; ae_bool rerrors; ae_bool cerrors; ae_bool spderrors; ae_bool hpderrors; ae_bool rfserrors; ae_bool waserrors; ae_bool result; maxn = 10; maxm = 5; passcount = 5; threshold = 10000*ae_machineepsilon; rfserrors = ae_false; rerrors = ae_false; cerrors = ae_false; spderrors = ae_false; hpderrors = ae_false; testdensesolverunit_testrsolver(maxn, maxm, passcount, threshold, &rerrors, &rfserrors, _state); testdensesolverunit_testspdsolver(maxn, maxm, passcount, threshold, &spderrors, &rfserrors, _state); testdensesolverunit_testcsolver(maxn, maxm, passcount, threshold, &cerrors, &rfserrors, _state); testdensesolverunit_testhpdsolver(maxn, maxm, passcount, threshold, &hpderrors, &rfserrors, _state); waserrors = (((rerrors||cerrors)||spderrors)||hpderrors)||rfserrors; if( !silent ) { printf("TESTING DENSE SOLVER\n"); printf("* REAL: "); if( rerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* COMPLEX: "); if( cerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* SPD: "); if( spderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* HPD: "); if( hpderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* ITERATIVE IMPROVEMENT: "); if( rfserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testdensesolver(ae_bool silent, ae_state *_state) { return testdensesolver(silent, _state); } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksolutionm(/* Real */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, densesolverreport* rep, /* Real */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_less_eq(ae_fabs(xe->ptr.pp_double[i][j]-xs->ptr.pp_double[i][j], _state),threshold); } } } return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksolutionmfast(/* Real */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, /* Real */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_less_eq(ae_fabs(xe->ptr.pp_double[i][j]-xs->ptr.pp_double[i][j], _state),threshold); } } } return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksolution(/* Real */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, densesolverreport* rep, /* Real */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_REAL, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_move(&xsm.ptr.pp_double[0][0], xsm.stride, &xs->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = testdensesolverunit_rmatrixchecksolutionm(xe, n, 1, threshold, info, rep, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksolutionfast(/* Real */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, /* Real */ ae_vector* xs, ae_state *_state) { ae_int_t i; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { for(i=0; i<=n-1; i++) { result = result&&ae_fp_less_eq(ae_fabs(xe->ptr.pp_double[i][0]-xs->ptr.p_double[i], _state),threshold); } } return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksingularm(ae_int_t n, ae_int_t m, ae_int_t info, densesolverreport* rep, /* Real */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3&&info!=1 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,(double)(0))||ae_fp_greater(rep->r1,1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,(double)(0))||ae_fp_greater(rep->rinf,1000*ae_machineepsilon)); if( info==-3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_eq(xs->ptr.pp_double[i][j],(double)(0)); } } } } return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksingularmfast(ae_int_t n, ae_int_t m, ae_int_t info, /* Real */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3 ) { result = ae_false; } else { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_eq(xs->ptr.pp_double[i][j],(double)(0)); } } } return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksingular(ae_int_t n, ae_int_t info, densesolverreport* rep, /* Real */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_REAL, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_move(&xsm.ptr.pp_double[0][0], xsm.stride, &xs->ptr.p_double[0], 1, ae_v_len(0,n-1)); result = testdensesolverunit_rmatrixchecksingularm(n, 1, info, rep, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_rmatrixchecksingularfast(ae_int_t n, ae_int_t info, /* Real */ ae_vector* xs, ae_state *_state) { ae_int_t i; ae_bool result; result = ae_true; if( info!=-3 ) { result = ae_false; } else { for(i=0; i<=n-1; i++) { result = result&&ae_fp_eq(xs->ptr.p_double[i],(double)(0)); } } return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksolutionm(/* Complex */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, densesolverreport* rep, /* Complex */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; } else { result = result&&!(ae_fp_less(rep->r1,100*ae_machineepsilon)||ae_fp_greater(rep->r1,1+1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,100*ae_machineepsilon)||ae_fp_greater(rep->rinf,1+1000*ae_machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_less_eq(ae_c_abs(ae_c_sub(xe->ptr.pp_complex[i][j],xs->ptr.pp_complex[i][j]), _state),threshold); } } } return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksolutionmfast(/* Complex */ ae_matrix* xe, ae_int_t n, ae_int_t m, double threshold, ae_int_t info, /* Complex */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info<=0 ) { result = ae_false; return result; } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_fp_less_eq(ae_c_abs(ae_c_sub(xe->ptr.pp_complex[i][j],xs->ptr.pp_complex[i][j]), _state),threshold); } } return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksolution(/* Complex */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, densesolverreport* rep, /* Complex */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_cmove(&xsm.ptr.pp_complex[0][0], xsm.stride, &xs->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); result = testdensesolverunit_cmatrixchecksolutionm(xe, n, 1, threshold, info, rep, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Checks whether solver results are correct solution. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksolutionfast(/* Complex */ ae_matrix* xe, ae_int_t n, double threshold, ae_int_t info, /* Complex */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_cmove(&xsm.ptr.pp_complex[0][0], xsm.stride, &xs->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); result = testdensesolverunit_cmatrixchecksolutionmfast(xe, n, 1, threshold, info, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksingularm(ae_int_t n, ae_int_t m, ae_int_t info, densesolverreport* rep, /* Complex */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3&&info!=1 ) { result = ae_false; return result; } result = result&&!(ae_fp_less(rep->r1,(double)(0))||ae_fp_greater(rep->r1,1000*ae_machineepsilon)); result = result&&!(ae_fp_less(rep->rinf,(double)(0))||ae_fp_greater(rep->rinf,1000*ae_machineepsilon)); if( info==-3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_c_eq_d(xs->ptr.pp_complex[i][j],(double)(0)); } } } return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksingularmfast(ae_int_t n, ae_int_t m, ae_int_t info, /* Complex */ ae_matrix* xs, ae_state *_state) { ae_int_t i; ae_int_t j; ae_bool result; result = ae_true; if( info!=-3 ) { result = ae_false; return result; } if( info==-3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { result = result&&ae_c_eq_d(xs->ptr.pp_complex[i][j],(double)(0)); } } } return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksingular(ae_int_t n, ae_int_t info, densesolverreport* rep, /* Complex */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_cmove(&xsm.ptr.pp_complex[0][0], xsm.stride, &xs->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); result = testdensesolverunit_cmatrixchecksingularm(n, 1, info, rep, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Checks whether solver results indicate singular matrix. Returns True on success. *************************************************************************/ static ae_bool testdensesolverunit_cmatrixchecksingularfast(ae_int_t n, ae_int_t info, /* Complex */ ae_vector* xs, ae_state *_state) { ae_frame _frame_block; ae_matrix xsm; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xsm, 0, 0, DT_COMPLEX, _state); ae_matrix_set_length(&xsm, n, 1, _state); ae_v_cmove(&xsm.ptr.pp_complex[0][0], xsm.stride, &xs->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); result = testdensesolverunit_cmatrixchecksingularmfast(n, 1, info, &xsm, _state); ae_frame_leave(_state); return result; } /************************************************************************* Copy *************************************************************************/ static void testdensesolverunit_rmatrixmakeacopy(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Real */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* Copy *************************************************************************/ static void testdensesolverunit_cmatrixmakeacopy(/* Complex */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Complex */ ae_matrix* b, ae_state *_state) { ae_int_t i; ae_int_t j; ae_matrix_clear(b); ae_matrix_set_length(b, m-1+1, n-1+1, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { b->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; } } } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testdensesolverunit_rmatrixdrophalf(/* Real */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_double[i][j] = (double)(1+2*i+3*j); } } } } /************************************************************************* Drops upper or lower half of the matrix - fills it by special pattern which may be used later to ensure that this part wasn't changed *************************************************************************/ static void testdensesolverunit_cmatrixdrophalf(/* Complex */ ae_matrix* a, ae_int_t n, ae_bool droplower, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (droplower&&i>j)||(!droplower&&iptr.pp_complex[i][j] = ae_complex_from_i(1+2*i+3*j); } } } } /************************************************************************* Real test *************************************************************************/ static void testdensesolverunit_testrsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* rerrors, ae_bool* rfserrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_matrix atmp; ae_vector p; ae_matrix xe; ae_matrix b; ae_vector bv; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t m; ae_int_t pass; ae_int_t taskkind; double v; double verr; ae_int_t info; densesolverreport rep; densesolverlsreport repls; ae_matrix x; ae_vector xv; ae_vector y; ae_vector tx; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&lua, 0, 0, DT_REAL, _state); ae_matrix_init(&atmp, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_matrix_init(&xe, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_vector_init(&bv, 0, DT_REAL, _state); _densesolverreport_init(&rep, _state); _densesolverlsreport_init(&repls, _state); ae_matrix_init(&x, 0, 0, DT_REAL, _state); ae_vector_init(&xv, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ rmatrixrndcond(n, (double)(1000), &a, _state); testdensesolverunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.pp_double[0][j], xe.stride, ae_v_len(0,n-1)); b.ptr.pp_double[i][j] = v; } } /* * Test solvers */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixsolvem(&a, n, &b, m, ae_fp_greater(ae_randomreal(_state),0.5), &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } rmatrixsolvemfast(&a, n, &x, m, &info, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixsolvefast(&a, n, &bv, &info, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixlusolvem(&lua, &p, n, &b, m, &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } rmatrixlusolvemfast(&lua, &p, n, &x, m, &info, _state); seterrorflag(rerrors, !testdensesolverunit_rmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixlusolve(&lua, &p, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&xv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixlusolvefast(&lua, &p, n, &xv, &info, _state); seterrorflag(rerrors, !testdensesolverunit_rmatrixchecksolutionfast(&xe, n, threshold, info, &xv, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixmixedsolvem(&a, &lua, &p, n, &b, m, &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixmixedsolve(&a, &lua, &p, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); /* * Test DenseSolverRLS(): * * test on original system A*x = b * * test on overdetermined system with the same solution: (A' A')'*x = (b' b')' * * test on underdetermined system with the same solution: (A 0 0 0 ) * z = b */ info = 0; testdensesolverunit_unsetlsrep(&repls, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixsolvels(&a, n, n, &bv, 0.0, &info, &repls, &xv, _state); if( info<=0 ) { *rerrors = ae_true; } else { *rerrors = (*rerrors||ae_fp_less(repls.r2,100*ae_machineepsilon))||ae_fp_greater(repls.r2,1+1000*ae_machineepsilon); *rerrors = (*rerrors||repls.n!=n)||repls.k!=0; for(i=0; i<=n-1; i++) { *rerrors = *rerrors||ae_fp_greater(ae_fabs(xe.ptr.pp_double[i][0]-xv.ptr.p_double[i], _state),threshold); } } info = 0; testdensesolverunit_unsetlsrep(&repls, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, 2*n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); ae_v_move(&bv.ptr.p_double[n], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(n,2*n-1)); ae_matrix_set_length(&atmp, 2*n, n, _state); copymatrix(&a, 0, n-1, 0, n-1, &atmp, 0, n-1, 0, n-1, _state); copymatrix(&a, 0, n-1, 0, n-1, &atmp, n, 2*n-1, 0, n-1, _state); rmatrixsolvels(&atmp, 2*n, n, &bv, 0.0, &info, &repls, &xv, _state); if( info<=0 ) { *rerrors = ae_true; } else { *rerrors = (*rerrors||ae_fp_less(repls.r2,100*ae_machineepsilon))||ae_fp_greater(repls.r2,1+1000*ae_machineepsilon); *rerrors = (*rerrors||repls.n!=n)||repls.k!=0; for(i=0; i<=n-1; i++) { *rerrors = *rerrors||ae_fp_greater(ae_fabs(xe.ptr.pp_double[i][0]-xv.ptr.p_double[i], _state),threshold); } } info = 0; testdensesolverunit_unsetlsrep(&repls, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); ae_matrix_set_length(&atmp, n, 2*n, _state); copymatrix(&a, 0, n-1, 0, n-1, &atmp, 0, n-1, 0, n-1, _state); for(i=0; i<=n-1; i++) { for(j=n; j<=2*n-1; j++) { atmp.ptr.pp_double[i][j] = (double)(0); } } rmatrixsolvels(&atmp, n, 2*n, &bv, 0.0, &info, &repls, &xv, _state); if( info<=0 ) { *rerrors = ae_true; } else { *rerrors = *rerrors||ae_fp_neq(repls.r2,(double)(0)); *rerrors = (*rerrors||repls.n!=2*n)||repls.k!=n; for(i=0; i<=n-1; i++) { *rerrors = *rerrors||ae_fp_greater(ae_fabs(xe.ptr.pp_double[i][0]-xv.ptr.p_double[i], _state),threshold); } for(i=n; i<=2*n-1; i++) { *rerrors = *rerrors||ae_fp_greater(ae_fabs(xv.ptr.p_double[i], _state),threshold); } } /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero (TaskKind=0) * * with zero columns (TaskKind=1) * * with zero rows (TaskKind=2) * * with equal rows/columns (TaskKind=2 or 3) * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods */ for(taskkind=0; taskkind<=4; taskkind++) { testdensesolverunit_unset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_move(&a.ptr.pp_double[0][0], a.stride, &a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1)); } if( taskkind==4 ) { /* * equal rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_move(&a.ptr.pp_double[0][0], 1, &a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1)); } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.pp_double[0][j], xe.stride, ae_v_len(0,n-1)); b.ptr.pp_double[i][j] = v; } } testdensesolverunit_rmatrixmakeacopy(&a, n, n, &lua, _state); rmatrixlu(&lua, n, n, &p, _state); /* * Test RMatrixSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixsolvem(&a, n, &b, m, ae_fp_greater(ae_randomreal(_state),0.5), &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test RMatrixSolveMFast(); performed only for matrices * with zero rows or columns */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } rmatrixsolvemfast(&a, n, &x, m, &info, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingularmfast(n, m, info, &x, _state); } /* * Test RMatrixSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingular(n, info, &rep, &xv, _state); /* * Test RMatrixSolveFast(); performed only for matrices * with zero rows or columns */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixsolvefast(&a, n, &bv, &info, _state); seterrorflag(rerrors, !testdensesolverunit_rmatrixchecksingularfast(n, info, &bv, _state), _state); } /* * Test RMatrixLUSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixlusolvem(&lua, &p, n, &b, m, &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test RMatrixLUSolveMFast(); performed only for matrices * with zero rows or columns */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } rmatrixlusolvemfast(&lua, &p, n, &x, m, &info, _state); seterrorflag(rerrors, !testdensesolverunit_rmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test RMatrixLUSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixlusolve(&lua, &p, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingular(n, info, &rep, &xv, _state); /* * Test RMatrixLUSolveFast(); performed only for matrices * with zero rows or columns */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixlusolvefast(&lua, &p, n, &bv, &info, _state); seterrorflag(rerrors, !testdensesolverunit_rmatrixchecksingularfast(n, info, &bv, _state), _state); } /* * Test RMatrixMixedSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); rmatrixmixedsolvem(&a, &lua, &p, n, &b, m, &info, &rep, &x, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test RMatrixMixedSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); rmatrixmixedsolve(&a, &lua, &p, n, &bv, &info, &rep, &xv, _state); *rerrors = *rerrors||!testdensesolverunit_rmatrixchecksingular(n, info, &rep, &xv, _state); } } } } /* * test iterative improvement */ for(pass=1; pass<=passcount; pass++) { /* * Test iterative improvement matrices * * A matrix/right part are constructed such that both matrix * and solution components are within (-1,+1). Such matrix/right part * have nice properties - system can be solved using iterative * improvement with |A*x-b| about several ulps of max(1,|b|). */ n = 100; ae_matrix_set_length(&a, n, n, _state); ae_matrix_set_length(&b, n, 1, _state); ae_vector_set_length(&bv, n, _state); ae_vector_set_length(&tx, n, _state); ae_vector_set_length(&xv, n, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { xv.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } ae_v_move(&y.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); xdot(&y, &xv, n, &tx, &v, &verr, _state); bv.ptr.p_double[i] = v; } ae_v_move(&b.ptr.pp_double[0][0], b.stride, &bv.ptr.p_double[0], 1, ae_v_len(0,n-1)); /* * Test RMatrixSolveM() */ testdensesolverunit_unset2d(&x, _state); rmatrixsolvem(&a, n, &b, 1, ae_true, &info, &rep, &x, _state); if( info<=0 ) { *rfserrors = ae_true; } else { ae_vector_set_length(&xv, n, _state); ae_v_move(&xv.ptr.p_double[0], 1, &x.ptr.pp_double[0][0], x.stride, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_move(&y.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); xdot(&y, &xv, n, &tx, &v, &verr, _state); *rfserrors = *rfserrors||ae_fp_greater(ae_fabs(v-b.ptr.pp_double[i][0], _state),8*ae_machineepsilon*ae_maxreal((double)(1), ae_fabs(b.ptr.pp_double[i][0], _state), _state)); } } /* * Test RMatrixSolve() */ testdensesolverunit_unset1d(&xv, _state); rmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); if( info<=0 ) { *rfserrors = ae_true; } else { for(i=0; i<=n-1; i++) { ae_v_move(&y.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); xdot(&y, &xv, n, &tx, &v, &verr, _state); *rfserrors = *rfserrors||ae_fp_greater(ae_fabs(v-bv.ptr.p_double[i], _state),8*ae_machineepsilon*ae_maxreal((double)(1), ae_fabs(bv.ptr.p_double[i], _state), _state)); } } /* * Test LS-solver on the same matrix */ rmatrixsolvels(&a, n, n, &bv, 0.0, &info, &repls, &xv, _state); if( info<=0 ) { *rfserrors = ae_true; } else { for(i=0; i<=n-1; i++) { ae_v_move(&y.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); xdot(&y, &xv, n, &tx, &v, &verr, _state); *rfserrors = *rfserrors||ae_fp_greater(ae_fabs(v-bv.ptr.p_double[i], _state),8*ae_machineepsilon*ae_maxreal((double)(1), ae_fabs(bv.ptr.p_double[i], _state), _state)); } } } ae_frame_leave(_state); } /************************************************************************* SPD test *************************************************************************/ static void testdensesolverunit_testspdsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* spderrors, ae_bool* rfserrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_matrix atmp; ae_vector p; ae_matrix xe; ae_matrix b; ae_vector bv; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t m; ae_int_t pass; ae_int_t taskkind; double v; ae_bool isupper; ae_int_t info; densesolverreport rep; densesolverlsreport repls; ae_matrix x; ae_vector xv; ae_vector y; ae_vector tx; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&cha, 0, 0, DT_REAL, _state); ae_matrix_init(&atmp, 0, 0, DT_REAL, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_matrix_init(&xe, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_vector_init(&bv, 0, DT_REAL, _state); _densesolverreport_init(&rep, _state); _densesolverlsreport_init(&repls, _state); ae_matrix_init(&x, 0, 0, DT_REAL, _state); ae_vector_init(&xv, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); spdmatrixrndcond(n, (double)(1000), &a, _state); testdensesolverunit_rmatrixmakeacopy(&a, n, n, &cha, _state); if( !spdmatrixcholesky(&cha, n, isupper, _state) ) { *spderrors = ae_true; ae_frame_leave(_state); return; } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.pp_double[0][j], xe.stride, ae_v_len(0,n-1)); b.ptr.pp_double[i][j] = v; } } testdensesolverunit_rmatrixdrophalf(&a, n, isupper, _state); testdensesolverunit_rmatrixdrophalf(&cha, n, isupper, _state); /* * Test solvers */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); spdmatrixsolvem(&a, n, isupper, &b, m, &info, &rep, &x, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } spdmatrixsolvemfast(&a, n, isupper, &x, m, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixsolve(&a, n, isupper, &bv, &info, &rep, &xv, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixsolvefast(&a, n, isupper, &bv, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); spdmatrixcholeskysolvem(&cha, n, isupper, &b, m, &info, &rep, &x, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } spdmatrixcholeskysolvemfast(&cha, n, isupper, &x, m, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixcholeskysolve(&cha, n, isupper, &bv, &info, &rep, &xv, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixcholeskysolvefast(&cha, n, isupper, &bv, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state), _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * * with equal rows/columns * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods */ for(taskkind=0; taskkind<=3; taskkind++) { testdensesolverunit_unset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1), 0); ae_v_muld(&a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } k = ae_randominteger(n, _state); ae_v_muld(&a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), 0); ae_v_muld(&a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns/rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } k = 1+ae_randominteger(n-1, _state); ae_v_move(&a.ptr.pp_double[0][0], a.stride, &a.ptr.pp_double[0][k], a.stride, ae_v_len(0,n-1)); ae_v_move(&a.ptr.pp_double[0][0], 1, &a.ptr.pp_double[k][0], 1, ae_v_len(0,n-1)); } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.pp_double[0][j], xe.stride, ae_v_len(0,n-1)); b.ptr.pp_double[i][j] = v; } } testdensesolverunit_rmatrixmakeacopy(&a, n, n, &cha, _state); testdensesolverunit_rmatrixdrophalf(&a, n, isupper, _state); testdensesolverunit_rmatrixdrophalf(&cha, n, isupper, _state); /* * Test SPDMatrixSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); spdmatrixsolvem(&a, n, isupper, &b, m, &info, &rep, &x, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test SPDMatrixSolveMFast() */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } spdmatrixsolvemfast(&a, n, isupper, &x, m, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test SPDMatrixSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixsolve(&a, n, isupper, &bv, &info, &rep, &xv, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksingular(n, info, &rep, &xv, _state); /* * Test SPDMatrixSolveFast() */ info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixsolvefast(&a, n, isupper, &bv, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksingular(n, info, &rep, &bv, _state), _state); /* * 'equal columns/rows' are degenerate, but * Cholesky matrix with equal columns/rows IS NOT degenerate, * so it is not used for testing purposes. */ if( taskkind!=3 ) { /* * Test SPDMatrixLUSolveM() (and fast version) */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); spdmatrixcholeskysolvem(&cha, n, isupper, &b, m, &info, &rep, &x, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksingularm(n, m, info, &rep, &x, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = b.ptr.pp_double[i][j]; } } spdmatrixcholeskysolvemfast(&a, n, isupper, &x, m, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test SPDMatrixLUSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_unset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixcholeskysolve(&cha, n, isupper, &bv, &info, &rep, &xv, _state); *spderrors = *spderrors||!testdensesolverunit_rmatrixchecksingular(n, info, &rep, &xv, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_move(&bv.ptr.p_double[0], 1, &b.ptr.pp_double[0][0], b.stride, ae_v_len(0,n-1)); spdmatrixcholeskysolvefast(&a, n, isupper, &bv, &info, _state); seterrorflag(spderrors, !testdensesolverunit_rmatrixchecksingularfast(n, info, &bv, _state), _state); } } } } } } ae_frame_leave(_state); } /************************************************************************* Real test *************************************************************************/ static void testdensesolverunit_testcsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* cerrors, ae_bool* rfserrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix lua; ae_matrix atmp; ae_vector p; ae_matrix xe; ae_matrix b; ae_vector bv; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t m; ae_int_t pass; ae_int_t taskkind; double verr; ae_complex v; ae_int_t info; densesolverreport rep; densesolverlsreport repls; ae_matrix x; ae_vector xv; ae_vector y; ae_vector tx; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&lua, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&atmp, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_matrix_init(&xe, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_vector_init(&bv, 0, DT_COMPLEX, _state); _densesolverreport_init(&rep, _state); _densesolverlsreport_init(&repls, _state); ae_matrix_init(&x, 0, 0, DT_COMPLEX, _state); ae_vector_init(&xv, 0, DT_COMPLEX, _state); ae_vector_init(&y, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_REAL, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ cmatrixrndcond(n, (double)(1000), &a, _state); testdensesolverunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; xe.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][0], 1, "N", &xe.ptr.pp_complex[0][j], xe.stride, "N", ae_v_len(0,n-1)); b.ptr.pp_complex[i][j] = v; } } /* * Test solvers */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixsolvem(&a, n, &b, m, ae_fp_greater(ae_randomreal(_state),0.5), &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } cmatrixsolvemfast(&a, n, &x, m, &info, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixsolvefast(&a, n, &bv, &info, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixlusolvem(&lua, &p, n, &b, m, &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } cmatrixlusolvemfast(&lua, &p, n, &x, m, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixlusolve(&lua, &p, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixlusolvefast(&lua, &p, n, &bv, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixmixedsolvem(&a, &lua, &p, n, &b, m, &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixmixedsolve(&a, &lua, &p, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * * with equal rows/columns * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods */ for(taskkind=0; taskkind<=4; taskkind++) { testdensesolverunit_cunset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_cmove(&a.ptr.pp_complex[0][0], a.stride, &a.ptr.pp_complex[0][k], a.stride, "N", ae_v_len(0,n-1)); } if( taskkind==4 ) { /* * equal rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } k = 1+ae_randominteger(n-1, _state); ae_v_cmove(&a.ptr.pp_complex[0][0], 1, &a.ptr.pp_complex[k][0], 1, "N", ae_v_len(0,n-1)); } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][0], 1, "N", &xe.ptr.pp_complex[0][j], xe.stride, "N", ae_v_len(0,n-1)); b.ptr.pp_complex[i][j] = v; } } testdensesolverunit_cmatrixmakeacopy(&a, n, n, &lua, _state); cmatrixlu(&lua, n, n, &p, _state); /* * Test CMatrixSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixsolvem(&a, n, &b, m, ae_fp_greater(ae_randomreal(_state),0.5), &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test CMatrixSolveMFast(); performed only for matrices * with zero rows or columns */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } cmatrixsolvemfast(&a, n, &x, m, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test CMatrixSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingular(n, info, &rep, &xv, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixsolvefast(&a, n, &bv, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksingularfast(n, info, &bv, _state), _state); } /* * Test CMatrixLUSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixlusolvem(&lua, &p, n, &b, m, &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test CMatrixLUSolveMFast() */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } cmatrixlusolvemfast(&lua, &p, n, &x, m, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test CMatrixLUSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixlusolve(&lua, &p, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingular(n, info, &rep, &xv, _state); /* * Test CMatrixLUSolveFast() */ if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixlusolvefast(&lua, &p, n, &bv, &info, _state); seterrorflag(cerrors, !testdensesolverunit_cmatrixchecksingularfast(n, info, &bv, _state), _state); } /* * Test CMatrixMixedSolveM() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); cmatrixmixedsolvem(&a, &lua, &p, n, &b, m, &info, &rep, &x, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingularm(n, m, info, &rep, &x, _state); /* * Test CMatrixMixedSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); cmatrixmixedsolve(&a, &lua, &p, n, &bv, &info, &rep, &xv, _state); *cerrors = *cerrors||!testdensesolverunit_cmatrixchecksingular(n, info, &rep, &xv, _state); } } } } /* * test iterative improvement */ for(pass=1; pass<=passcount; pass++) { /* * Test iterative improvement matrices * * A matrix/right part are constructed such that both matrix * and solution components magnitudes are within (-1,+1). * Such matrix/right part have nice properties - system can * be solved using iterative improvement with |A*x-b| about * several ulps of max(1,|b|). */ n = 100; ae_matrix_set_length(&a, n, n, _state); ae_matrix_set_length(&b, n, 1, _state); ae_vector_set_length(&bv, n, _state); ae_vector_set_length(&tx, 2*n, _state); ae_vector_set_length(&xv, n, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { xv.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; xv.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } ae_v_cmove(&y.ptr.p_complex[0], 1, &a.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); xcdot(&y, &xv, n, &tx, &v, &verr, _state); bv.ptr.p_complex[i] = v; } ae_v_cmove(&b.ptr.pp_complex[0][0], b.stride, &bv.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); /* * Test CMatrixSolveM() */ testdensesolverunit_cunset2d(&x, _state); cmatrixsolvem(&a, n, &b, 1, ae_true, &info, &rep, &x, _state); if( info<=0 ) { *rfserrors = ae_true; } else { ae_vector_set_length(&xv, n, _state); ae_v_cmove(&xv.ptr.p_complex[0], 1, &x.ptr.pp_complex[0][0], x.stride, "N", ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { ae_v_cmove(&y.ptr.p_complex[0], 1, &a.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); xcdot(&y, &xv, n, &tx, &v, &verr, _state); *rfserrors = *rfserrors||ae_fp_greater(ae_c_abs(ae_c_sub(v,b.ptr.pp_complex[i][0]), _state),8*ae_machineepsilon*ae_maxreal((double)(1), ae_c_abs(b.ptr.pp_complex[i][0], _state), _state)); } } /* * Test CMatrixSolve() */ testdensesolverunit_cunset1d(&xv, _state); cmatrixsolve(&a, n, &bv, &info, &rep, &xv, _state); if( info<=0 ) { *rfserrors = ae_true; } else { for(i=0; i<=n-1; i++) { ae_v_cmove(&y.ptr.p_complex[0], 1, &a.ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); xcdot(&y, &xv, n, &tx, &v, &verr, _state); *rfserrors = *rfserrors||ae_fp_greater(ae_c_abs(ae_c_sub(v,bv.ptr.p_complex[i]), _state),8*ae_machineepsilon*ae_maxreal((double)(1), ae_c_abs(bv.ptr.p_complex[i], _state), _state)); } } /* * TODO: Test LS-solver on the same matrix */ } ae_frame_leave(_state); } /************************************************************************* HPD test *************************************************************************/ static void testdensesolverunit_testhpdsolver(ae_int_t maxn, ae_int_t maxm, ae_int_t passcount, double threshold, ae_bool* hpderrors, ae_bool* rfserrors, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix cha; ae_matrix atmp; ae_vector p; ae_matrix xe; ae_matrix b; ae_vector bv; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t m; ae_int_t pass; ae_int_t taskkind; ae_complex v; ae_bool isupper; ae_int_t info; densesolverreport rep; densesolverlsreport repls; ae_matrix x; ae_vector xv; ae_vector y; ae_vector tx; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&cha, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&atmp, 0, 0, DT_COMPLEX, _state); ae_vector_init(&p, 0, DT_INT, _state); ae_matrix_init(&xe, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state); ae_vector_init(&bv, 0, DT_COMPLEX, _state); _densesolverreport_init(&rep, _state); _densesolverlsreport_init(&repls, _state); ae_matrix_init(&x, 0, 0, DT_COMPLEX, _state); ae_vector_init(&xv, 0, DT_COMPLEX, _state); ae_vector_init(&y, 0, DT_COMPLEX, _state); ae_vector_init(&tx, 0, DT_COMPLEX, _state); /* * General square matrices: * * test general solvers * * test least squares solver */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { /* * ******************************************************** * WELL CONDITIONED TASKS * ability to find correct solution is tested * ******************************************************** * * 1. generate random well conditioned matrix A. * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods on original A */ isupper = ae_fp_greater(ae_randomreal(_state),0.5); hpdmatrixrndcond(n, (double)(1000), &a, _state); testdensesolverunit_cmatrixmakeacopy(&a, n, n, &cha, _state); if( !hpdmatrixcholesky(&cha, n, isupper, _state) ) { *hpderrors = ae_true; ae_frame_leave(_state); return; } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; xe.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][0], 1, "N", &xe.ptr.pp_complex[0][j], xe.stride, "N", ae_v_len(0,n-1)); b.ptr.pp_complex[i][j] = v; } } testdensesolverunit_cmatrixdrophalf(&a, n, isupper, _state); testdensesolverunit_cmatrixdrophalf(&cha, n, isupper, _state); /* * Test solvers */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); hpdmatrixsolvem(&a, n, isupper, &b, m, &info, &rep, &x, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } hpdmatrixsolvemfast(&a, n, isupper, &x, m, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixsolve(&a, n, isupper, &bv, &info, &rep, &xv, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixsolvefast(&a, n, isupper, &bv, &info, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &bv, _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); hpdmatrixcholeskysolvem(&cha, n, isupper, &b, m, &info, &rep, &x, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksolutionm(&xe, n, m, threshold, info, &rep, &x, _state); info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } hpdmatrixcholeskysolvemfast(&cha, n, isupper, &x, m, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksolutionmfast(&xe, n, m, threshold, info, &x, _state), _state); info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset1d(&xv, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixcholeskysolve(&cha, n, isupper, &bv, &info, &rep, &xv, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksolution(&xe, n, threshold, info, &rep, &xv, _state); info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixcholeskysolvefast(&cha, n, isupper, &bv, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksolutionfast(&xe, n, threshold, info, &bv, _state), _state); /* * ******************************************************** * EXACTLY SINGULAR MATRICES * ability to detect singularity is tested * ******************************************************** * * 1. generate different types of singular matrices: * * zero * * with zero columns * * with zero rows * * with equal rows/columns * 2. generate random solution vector xe * 3. generate right part b=A*xe * 4. test different methods */ for(taskkind=0; taskkind<=3; taskkind++) { testdensesolverunit_cunset2d(&a, _state); if( taskkind==0 ) { /* * all zeros */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_complex[i][j] = ae_complex_from_i(0); } } } if( taskkind==1 ) { /* * there is zero column */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; if( i==j ) { a.ptr.pp_complex[i][j].y = (double)(0); } a.ptr.pp_complex[j][i] = a.ptr.pp_complex[i][j]; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); } if( taskkind==2 ) { /* * there is zero row */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; if( i==j ) { a.ptr.pp_complex[i][j].y = (double)(0); } a.ptr.pp_complex[j][i] = a.ptr.pp_complex[i][j]; } } k = ae_randominteger(n, _state); ae_v_cmuld(&a.ptr.pp_complex[k][0], 1, ae_v_len(0,n-1), 0); ae_v_cmuld(&a.ptr.pp_complex[0][k], a.stride, ae_v_len(0,n-1), 0); } if( taskkind==3 ) { /* * equal columns/rows */ if( n<2 ) { continue; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=i; j<=n-1; j++) { a.ptr.pp_complex[i][j].x = 2*ae_randomreal(_state)-1; a.ptr.pp_complex[i][j].y = 2*ae_randomreal(_state)-1; if( i==j ) { a.ptr.pp_complex[i][j].y = (double)(0); } a.ptr.pp_complex[j][i] = a.ptr.pp_complex[i][j]; } } k = 1+ae_randominteger(n-1, _state); ae_v_cmove(&a.ptr.pp_complex[0][0], a.stride, &a.ptr.pp_complex[0][k], a.stride, "N", ae_v_len(0,n-1)); ae_v_cmove(&a.ptr.pp_complex[0][0], 1, &a.ptr.pp_complex[k][0], 1, "N", ae_v_len(0,n-1)); } ae_matrix_set_length(&xe, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { xe.ptr.pp_complex[i][j] = ae_complex_from_d(2*ae_randomreal(_state)-1); } } ae_matrix_set_length(&b, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { v = ae_v_cdotproduct(&a.ptr.pp_complex[i][0], 1, "N", &xe.ptr.pp_complex[0][j], xe.stride, "N", ae_v_len(0,n-1)); b.ptr.pp_complex[i][j] = v; } } testdensesolverunit_cmatrixmakeacopy(&a, n, n, &cha, _state); testdensesolverunit_cmatrixdrophalf(&a, n, isupper, _state); testdensesolverunit_cmatrixdrophalf(&cha, n, isupper, _state); /* * Test SPDMatrixSolveM() (and fast version) */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); hpdmatrixsolvem(&a, n, isupper, &b, m, &info, &rep, &x, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksingularm(n, m, info, &rep, &x, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } hpdmatrixsolvemfast(&a, n, isupper, &x, m, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test SPDMatrixSolve() */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixsolve(&a, n, isupper, &bv, &info, &rep, &xv, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksingular(n, info, &rep, &xv, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixsolvefast(&a, n, isupper, &bv, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksingularfast(n, info, &bv, _state), _state); } /* * 'equal columns/rows' are degenerate, but * Cholesky matrix with equal columns/rows IS NOT degenerate, * so it is not used for testing purposes. */ if( taskkind!=3 ) { /* * Test SPDMatrixCholeskySolveM()/fast */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); hpdmatrixcholeskysolvem(&cha, n, isupper, &b, m, &info, &rep, &x, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksingularm(n, m, info, &rep, &x, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { info = 0; ae_matrix_set_length(&x, n, m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_complex[i][j] = b.ptr.pp_complex[i][j]; } } hpdmatrixcholeskysolvemfast(&cha, n, isupper, &x, m, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksingularmfast(n, m, info, &x, _state), _state); } /* * Test HPDMatrixCholeskySolve() (fast) */ info = 0; testdensesolverunit_unsetrep(&rep, _state); testdensesolverunit_cunset2d(&x, _state); ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixcholeskysolve(&cha, n, isupper, &bv, &info, &rep, &xv, _state); *hpderrors = *hpderrors||!testdensesolverunit_cmatrixchecksingular(n, info, &rep, &xv, _state); if( (taskkind==0||taskkind==1)||taskkind==2 ) { ae_vector_set_length(&bv, n, _state); ae_v_cmove(&bv.ptr.p_complex[0], 1, &b.ptr.pp_complex[0][0], b.stride, "N", ae_v_len(0,n-1)); hpdmatrixcholeskysolvefast(&cha, n, isupper, &bv, &info, _state); seterrorflag(hpderrors, !testdensesolverunit_cmatrixchecksingularfast(n, info, &bv, _state), _state); } } } } } } ae_frame_leave(_state); } /************************************************************************* Unsets real matrix *************************************************************************/ static void testdensesolverunit_unset2d(/* Real */ ae_matrix* x, ae_state *_state) { ae_matrix_set_length(x, 1, 1, _state); x->ptr.pp_double[0][0] = 2*ae_randomreal(_state)-1; } /************************************************************************* Unsets real vector *************************************************************************/ static void testdensesolverunit_unset1d(/* Real */ ae_vector* x, ae_state *_state) { ae_vector_set_length(x, 1, _state); x->ptr.p_double[0] = 2*ae_randomreal(_state)-1; } /************************************************************************* Unsets real matrix *************************************************************************/ static void testdensesolverunit_cunset2d(/* Complex */ ae_matrix* x, ae_state *_state) { ae_matrix_set_length(x, 1, 1, _state); x->ptr.pp_complex[0][0] = ae_complex_from_d(2*ae_randomreal(_state)-1); } /************************************************************************* Unsets real vector *************************************************************************/ static void testdensesolverunit_cunset1d(/* Complex */ ae_vector* x, ae_state *_state) { ae_vector_set_length(x, 1, _state); x->ptr.p_complex[0] = ae_complex_from_d(2*ae_randomreal(_state)-1); } /************************************************************************* Unsets report *************************************************************************/ static void testdensesolverunit_unsetrep(densesolverreport* r, ae_state *_state) { r->r1 = (double)(-1); r->rinf = (double)(-1); } /************************************************************************* Unsets report *************************************************************************/ static void testdensesolverunit_unsetlsrep(densesolverlsreport* r, ae_state *_state) { r->r2 = (double)(-1); r->n = -1; r->k = -1; testdensesolverunit_unset2d(&r->cx, _state); } static void testoptservunit_testprec(ae_bool* wereerrors, ae_state *_state); ae_bool testoptserv(ae_bool silent, ae_state *_state) { ae_bool precerrors; ae_bool wereerrors; ae_bool result; precerrors = ae_false; testoptservunit_testprec(&precerrors, _state); /* * report */ wereerrors = precerrors; if( !silent ) { printf("TESTING OPTSERV\n"); printf("TESTS: \n"); printf("* PRECONDITIONERS "); if( precerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( wereerrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !wereerrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testoptserv(ae_bool silent, ae_state *_state) { return testoptserv(silent, _state); } /************************************************************************* This function checks preconditioning functions On failure sets error flag. *************************************************************************/ static void testoptservunit_testprec(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t k; ae_int_t i; ae_int_t j; ae_int_t i0; ae_int_t j0; ae_int_t j1; double v; double rho; double theta; double tolg; ae_matrix va; ae_vector vc; ae_vector vd; ae_vector vb; ae_vector s0; ae_vector s1; ae_vector s2; ae_vector g; precbuflbfgs buf; precbuflowrank lowrankbuf; ae_vector norms; ae_matrix sk; ae_matrix yk; ae_matrix bk; ae_vector bksk; ae_vector tmp; matinvreport rep; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_matrix_init(&va, 0, 0, DT_REAL, _state); ae_vector_init(&vc, 0, DT_REAL, _state); ae_vector_init(&vd, 0, DT_REAL, _state); ae_vector_init(&vb, 0, DT_REAL, _state); ae_vector_init(&s0, 0, DT_REAL, _state); ae_vector_init(&s1, 0, DT_REAL, _state); ae_vector_init(&s2, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); _precbuflbfgs_init(&buf, _state); _precbuflowrank_init(&lowrankbuf, _state); ae_vector_init(&norms, 0, DT_REAL, _state); ae_matrix_init(&sk, 0, 0, DT_REAL, _state); ae_matrix_init(&yk, 0, 0, DT_REAL, _state); ae_matrix_init(&bk, 0, 0, DT_REAL, _state); ae_vector_init(&bksk, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); _matinvreport_init(&rep, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Test for inexact L-BFGS preconditioner. * * We generate QP problem 0.5*x'*H*x, with random H=D+V'*C*V. * Different K's, from 0 to N, are tried. We test preconditioner * code which uses compact L-BFGS update against reference implementation * which uses non-compact BFGS scheme. * * For each K we perform two tests: first for KxN non-zero matrix V, * second one for NxN matrix V with last N-K rows set to zero. Last test * checks algorithm's ability to handle zero updates. */ tolg = 1.0E-9; for(n=1; n<=10; n++) { for(k=0; k<=n; k++) { /* * Prepare problem: * * VD, VC, VA, with VC/VA reordered by ascending of VC[i]*norm(VA[i,...])^2 * * trial vector S (copies are stored to S0,S1,S2) */ ae_vector_set_length(&vd, n, _state); ae_vector_set_length(&s0, n, _state); ae_vector_set_length(&s1, n, _state); ae_vector_set_length(&s2, n, _state); for(i=0; i<=n-1; i++) { vd.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); s0.ptr.p_double[i] = hqrndnormal(&rs, _state); s1.ptr.p_double[i] = s0.ptr.p_double[i]; s2.ptr.p_double[i] = s0.ptr.p_double[i]; } rmatrixrndcond(n, 1.0E2, &va, _state); rvectorsetlengthatleast(&vc, n, _state); for(i=0; i<=k-1; i++) { vc.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); } for(i=k; i<=n-1; i++) { vc.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { va.ptr.pp_double[i][j] = 0.0; } } ae_vector_set_length(&norms, k, _state); for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&va.ptr.pp_double[i][0], 1, &va.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); norms.ptr.p_double[i] = v*vc.ptr.p_double[i]; } for(i=0; i<=k-1; i++) { for(j=0; j<=k-2; j++) { if( ae_fp_greater(norms.ptr.p_double[j],norms.ptr.p_double[j+1]) ) { /* * Swap elements J and J+1 */ v = norms.ptr.p_double[j]; norms.ptr.p_double[j] = norms.ptr.p_double[j+1]; norms.ptr.p_double[j+1] = v; v = vc.ptr.p_double[j]; vc.ptr.p_double[j] = vc.ptr.p_double[j+1]; vc.ptr.p_double[j+1] = v; for(j0=0; j0<=n-1; j0++) { v = va.ptr.pp_double[j][j0]; va.ptr.pp_double[j][j0] = va.ptr.pp_double[j+1][j0]; va.ptr.pp_double[j+1][j0] = v; } } } } /* * Generate reference model and apply it to S2: * * generate approximate Hessian Bk * * calculate inv(Bk) * * calculate inv(Bk)*S2, store to S2 */ rmatrixsetlengthatleast(&sk, k, n, _state); rmatrixsetlengthatleast(&yk, k, n, _state); ae_matrix_set_length(&bk, n, n, _state); ae_vector_set_length(&bksk, n, _state); ae_vector_set_length(&tmp, n, _state); for(i=0; i<=k-1; i++) { ae_v_move(&sk.ptr.pp_double[i][0], 1, &va.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&va.ptr.pp_double[i][0], 1, &sk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = v*vc.ptr.p_double[i]; for(j=0; j<=n-1; j++) { yk.ptr.pp_double[i][j] = vd.ptr.p_double[j]*sk.ptr.pp_double[i][j]+va.ptr.pp_double[i][j]*v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { bk.ptr.pp_double[i][i] = vd.ptr.p_double[i]; } else { bk.ptr.pp_double[i][j] = 0.0; } } } for(i=0; i<=k-1; i++) { theta = 0.0; for(j0=0; j0<=n-1; j0++) { bksk.ptr.p_double[j0] = (double)(0); for(j1=0; j1<=n-1; j1++) { theta = theta+sk.ptr.pp_double[i][j0]*bk.ptr.pp_double[j0][j1]*sk.ptr.pp_double[i][j1]; bksk.ptr.p_double[j0] = bksk.ptr.p_double[j0]+bk.ptr.pp_double[j0][j1]*sk.ptr.pp_double[i][j1]; } } theta = 1/theta; rho = ae_v_dotproduct(&sk.ptr.pp_double[i][0], 1, &yk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); rho = 1/rho; for(j0=0; j0<=n-1; j0++) { for(j1=0; j1<=n-1; j1++) { bk.ptr.pp_double[j0][j1] = bk.ptr.pp_double[j0][j1]+rho*yk.ptr.pp_double[i][j0]*yk.ptr.pp_double[i][j1]; } } for(j0=0; j0<=n-1; j0++) { for(j1=0; j1<=n-1; j1++) { bk.ptr.pp_double[j0][j1] = bk.ptr.pp_double[j0][j1]-theta*bksk.ptr.p_double[j0]*bksk.ptr.p_double[j1]; } } } rmatrixinverse(&bk, n, &j0, &rep, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&bk.ptr.pp_double[i][0], 1, &s2.ptr.p_double[0], 1, ae_v_len(0,n-1)); tmp.ptr.p_double[i] = v; } for(i=0; i<=n-1; i++) { s2.ptr.p_double[i] = tmp.ptr.p_double[i]; } /* * First test for non-zero V: * * apply preconditioner to X0 * * compare reference model against implementation being tested */ inexactlbfgspreconditioner(&s0, n, &vd, &vc, &va, k, &buf, _state); for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(s2.ptr.p_double[i]-s0.ptr.p_double[i], _state),tolg), _state); } /* * Second test - N-K zero rows appended to V and rows are * randomly reordered. Doing so should not change result, * algorithm must be able to order rows according to second derivative * and skip zero updates. */ for(i=0; i<=n-1; i++) { i0 = i+hqrnduniformi(&rs, n-i, _state); v = vc.ptr.p_double[i]; vc.ptr.p_double[i] = vc.ptr.p_double[i0]; vc.ptr.p_double[i0] = v; for(j=0; j<=n-1; j++) { v = va.ptr.pp_double[i][j]; va.ptr.pp_double[i][j] = va.ptr.pp_double[i0][j]; va.ptr.pp_double[i0][j] = v; } } inexactlbfgspreconditioner(&s1, n, &vd, &vc, &va, n, &buf, _state); for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(s2.ptr.p_double[i]-s1.ptr.p_double[i], _state),tolg), _state); } } } /* * Test for exact low-rank preconditioner. * * We generate QP problem 0.5*x'*H*x, with random H=D+V'*C*V. * Different K's, from 0 to N, are tried. We test preconditioner * code which uses Woodbury update against reference implementation * which performs straightforward matrix inversion. * * For each K we perform two tests: first for KxN non-zero matrix V, * second one for NxN matrix V with randomly appended N-K zero rows. * Last test checks algorithm's ability to handle zero updates. */ tolg = 1.0E-9; for(n=1; n<=10; n++) { for(k=0; k<=n; k++) { /* * Prepare problem: * * VD, VC, VA * * trial vector S (copies are stored to S0,S1,S2) */ ae_vector_set_length(&vd, n, _state); ae_vector_set_length(&s0, n, _state); ae_vector_set_length(&s1, n, _state); ae_vector_set_length(&s2, n, _state); for(i=0; i<=n-1; i++) { vd.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); s0.ptr.p_double[i] = hqrndnormal(&rs, _state); s1.ptr.p_double[i] = s0.ptr.p_double[i]; s2.ptr.p_double[i] = s0.ptr.p_double[i]; } rmatrixrndcond(n, 1.0E2, &va, _state); rvectorsetlengthatleast(&vc, n, _state); for(i=0; i<=k-1; i++) { vc.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); } for(i=k; i<=n-1; i++) { vc.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { va.ptr.pp_double[i][j] = 0.0; } } /* * Generate reference model and apply it to S2 */ ae_matrix_set_length(&bk, n, n, _state); ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { v = vd.ptr.p_double[i]; } else { v = 0.0; } for(j1=0; j1<=k-1; j1++) { v = v+va.ptr.pp_double[j1][i]*vc.ptr.p_double[j1]*va.ptr.pp_double[j1][j]; } bk.ptr.pp_double[i][j] = v; } } rmatrixinverse(&bk, n, &j, &rep, _state); ae_assert(j>0, "Assertion failed", _state); for(i=0; i<=n-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+bk.ptr.pp_double[i][j]*s2.ptr.p_double[j]; } tmp.ptr.p_double[i] = v; } for(i=0; i<=n-1; i++) { s2.ptr.p_double[i] = tmp.ptr.p_double[i]; } /* * First test for non-zero V: * * apply preconditioner to X0 * * compare reference model against implementation being tested */ preparelowrankpreconditioner(&vd, &vc, &va, n, k, &lowrankbuf, _state); applylowrankpreconditioner(&s0, &lowrankbuf, _state); for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(s2.ptr.p_double[i]-s0.ptr.p_double[i], _state),tolg), _state); } /* * Second test - N-K zero rows appended to V and rows are * randomly reordered. Doing so should not change result, * algorithm must be able to order rows according to second derivative * and skip zero updates. */ for(i=0; i<=n-1; i++) { i0 = i+hqrnduniformi(&rs, n-i, _state); v = vc.ptr.p_double[i]; vc.ptr.p_double[i] = vc.ptr.p_double[i0]; vc.ptr.p_double[i0] = v; for(j=0; j<=n-1; j++) { v = va.ptr.pp_double[i][j]; va.ptr.pp_double[i][j] = va.ptr.pp_double[i0][j]; va.ptr.pp_double[i0][j] = v; } } preparelowrankpreconditioner(&vd, &vc, &va, n, n, &lowrankbuf, _state); applylowrankpreconditioner(&s1, &lowrankbuf, _state); for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(s2.ptr.p_double[i]-s1.ptr.p_double[i], _state),tolg), _state); } } } ae_frame_leave(_state); } /************************************************************************* Testing *************************************************************************/ ae_bool testfbls(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t m; ae_int_t mx; ae_int_t i; ae_int_t j; ae_bool waserrors; ae_bool cgerrors; ae_bool lserrors; double eps; double v; double v1; double v2; ae_vector tmp0; ae_vector tmp1; ae_vector tmp2; ae_matrix a; ae_vector b; ae_vector x; ae_vector xe; ae_vector buf; double alpha; double e1; double e2; fblslincgstate cgstate; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_vector_init(&tmp1, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&buf, 0, DT_REAL, _state); _fblslincgstate_init(&cgstate, _state); mx = 10; waserrors = ae_false; cgerrors = ae_false; lserrors = ae_false; /* * Test CG solver: * * generate problem (A, B, Alpha, XE - exact solution) and initial approximation X * * E1 = ||A'A*x-b|| * * solve * * E2 = ||A'A*x-b|| * * test that E2<0.001*E1 */ for(n=1; n<=mx; n++) { for(m=1; m<=mx; m++) { ae_matrix_set_length(&a, m, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xe, n, _state); ae_vector_set_length(&tmp1, m, _state); ae_vector_set_length(&tmp2, n, _state); /* * init A, alpha, B, X (initial approximation), XE (exact solution) * X is initialized in such way that is has no chances to be equal to XE. */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } alpha = ae_randomreal(_state)+0.1; for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x.ptr.p_double[i] = (2*ae_randominteger(2, _state)-1)*(2+ae_randomreal(_state)); } /* * Test dense CG (which solves A'A*x=b and accepts dense A) */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (2*ae_randominteger(2, _state)-1)*(2+ae_randomreal(_state)); } rmatrixmv(m, n, &a, 0, 0, 0, &x, 0, &tmp1, 0, _state); rmatrixmv(n, m, &a, 0, 0, 1, &tmp1, 0, &tmp2, 0, _state); ae_v_addd(&tmp2.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); ae_v_sub(&tmp2.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1)); e1 = ae_sqrt(v, _state); fblssolvecgx(&a, m, n, alpha, &b, &x, &buf, _state); rmatrixmv(m, n, &a, 0, 0, 0, &x, 0, &tmp1, 0, _state); rmatrixmv(n, m, &a, 0, 0, 1, &tmp1, 0, &tmp2, 0, _state); ae_v_addd(&tmp2.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); ae_v_sub(&tmp2.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1)); e2 = ae_sqrt(v, _state); cgerrors = cgerrors||ae_fp_greater(e2,0.001*e1); /* * Test sparse CG (which relies on reverse communication) */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (2*ae_randominteger(2, _state)-1)*(2+ae_randomreal(_state)); } rmatrixmv(m, n, &a, 0, 0, 0, &x, 0, &tmp1, 0, _state); rmatrixmv(n, m, &a, 0, 0, 1, &tmp1, 0, &tmp2, 0, _state); ae_v_addd(&tmp2.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); ae_v_sub(&tmp2.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1)); e1 = ae_sqrt(v, _state); fblscgcreate(&x, &b, n, &cgstate, _state); while(fblscgiteration(&cgstate, _state)) { rmatrixmv(m, n, &a, 0, 0, 0, &cgstate.x, 0, &tmp1, 0, _state); rmatrixmv(n, m, &a, 0, 0, 1, &tmp1, 0, &cgstate.ax, 0, _state); ae_v_addd(&cgstate.ax.ptr.p_double[0], 1, &cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); v1 = ae_v_dotproduct(&tmp1.ptr.p_double[0], 1, &tmp1.ptr.p_double[0], 1, ae_v_len(0,m-1)); v2 = ae_v_dotproduct(&cgstate.x.ptr.p_double[0], 1, &cgstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); cgstate.xax = v1+alpha*v2; } rmatrixmv(m, n, &a, 0, 0, 0, &cgstate.xk, 0, &tmp1, 0, _state); rmatrixmv(n, m, &a, 0, 0, 1, &tmp1, 0, &tmp2, 0, _state); ae_v_addd(&tmp2.ptr.p_double[0], 1, &cgstate.xk.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); ae_v_sub(&tmp2.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1)); e2 = ae_sqrt(v, _state); cgerrors = cgerrors||ae_fp_greater(ae_fabs(e1-cgstate.e1, _state),100*ae_machineepsilon*e1); cgerrors = cgerrors||ae_fp_greater(ae_fabs(e2-cgstate.e2, _state),100*ae_machineepsilon*e1); cgerrors = cgerrors||ae_fp_greater(e2,0.001*e1); } } /* * Test linear least squares: * * try N=1..5, M=N..2*N * [ B ] * * generate MxN matrix A = [ ], where (M-N)xN submatrix B contains * [ C ] * random values from [-1,+1], and NxN submatrix C is diagonally dominant * (diagonal of C is equal to 1.0, and magnitude of off-diagonal elements * is smaller than 0.01). Such matrix is guaranteed to be non-degenerate. * * generate random known solution xe, set right part b=A*xe * * check that results of FBLSSolveLS agree with xe */ eps = 1.0E-6; for(n=1; n<=5; n++) { for(m=n; m<=2*n; m++) { ae_matrix_set_length(&a, m, n, _state); for(i=0; i<=m-n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } for(i=m-n; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.01*(2*ae_randomreal(_state)-1); } a.ptr.pp_double[i][i-(m-n)] = 1.0; } ae_vector_set_length(&xe, n, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&b, m, _state); for(i=0; i<=m-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = v; } fblssolvels(&a, &b, m, n, &tmp0, &tmp1, &tmp2, _state); for(i=0; i<=n-1; i++) { lserrors = lserrors||ae_fp_greater(ae_fabs(b.ptr.p_double[i]-xe.ptr.p_double[i], _state),eps); } } } /* * report */ waserrors = cgerrors||lserrors; if( !silent ) { printf("TESTING FBLS\n"); printf("CG ERRORS: "); if( cgerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LS ERRORS: "); if( lserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testfbls(ae_bool silent, ae_state *_state) { return testfbls(silent, _state); } ae_bool testcqmodels(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool eval0errors; ae_bool eval1errors; ae_bool eval2errors; ae_bool newton0errors; ae_bool newton1errors; ae_bool newton2errors; ae_bool waserrors; convexquadraticmodel s; ae_int_t nkind; ae_int_t kmax; ae_int_t n; ae_int_t k; ae_int_t i; ae_int_t pass; ae_int_t j; double alpha; double theta; double tau; double v; double v2; double h; double f0; double mkind; double xtadx2; double noise; ae_matrix a; ae_matrix q; ae_vector b; ae_vector r; ae_vector x; ae_vector x0; ae_vector xc; ae_vector d; ae_vector ge; ae_vector gt; ae_vector tmp0; ae_vector adx; ae_vector adxe; ae_vector activeset; ae_bool result; ae_frame_make(_state, &_frame_block); _convexquadraticmodel_init(&s, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&r, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&ge, 0, DT_REAL, _state); ae_vector_init(>, 0, DT_REAL, _state); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_vector_init(&adx, 0, DT_REAL, _state); ae_vector_init(&adxe, 0, DT_REAL, _state); ae_vector_init(&activeset, 0, DT_BOOL, _state); waserrors = ae_false; /* * Eval0 test: unconstrained model evaluation */ eval0errors = ae_false; for(n=1; n<=5; n++) { for(k=0; k<=2*n; k++) { /* * Allocate place */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&ge, n, _state); ae_vector_set_length(>, n, _state); if( k>0 ) { ae_matrix_set_length(&q, k, n, _state); ae_vector_set_length(&r, k, _state); } /* * Generate problem */ alpha = ae_randomreal(_state)+1.0; theta = ae_randomreal(_state)+1.0; tau = ae_randomreal(_state)*ae_randominteger(2, _state); for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 10*(1+ae_randomreal(_state)); b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_randomreal(_state)+1; for(j=i+1; j<=n-1; j++) { v = 0.1*ae_randomreal(_state)-0.05; a.ptr.pp_double[i][j] = v; a.ptr.pp_double[j][i] = v; } for(j=0; j<=k-1; j++) { q.ptr.pp_double[j][i] = 2*ae_randomreal(_state)-1; } } for(i=0; i<=k-1; i++) { r.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } /* * Build model */ cqminit(n, &s, _state); cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); cqmsetb(&s, &b, _state); cqmsetq(&s, &q, &r, k, theta, _state); cqmsetd(&s, &d, tau, _state); /* * Evaluate and compare: * * X - random point * * GE - "exact" gradient * * XTADX2 - x'*(alpha*A+tau*D)*x/2 * * ADXE - (alpha*A+tau*D)*x * * V - model value at X */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; ge.ptr.p_double[i] = 0.0; } v = 0.0; xtadx2 = 0.0; ae_vector_set_length(&adxe, n, _state); for(i=0; i<=n-1; i++) { adxe.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { v = v+x.ptr.p_double[i]*b.ptr.p_double[i]; ge.ptr.p_double[i] = ge.ptr.p_double[i]+b.ptr.p_double[i]; v = v+0.5*ae_sqr(x.ptr.p_double[i], _state)*tau*d.ptr.p_double[i]; ge.ptr.p_double[i] = ge.ptr.p_double[i]+x.ptr.p_double[i]*tau*d.ptr.p_double[i]; adxe.ptr.p_double[i] = adxe.ptr.p_double[i]+x.ptr.p_double[i]*tau*d.ptr.p_double[i]; xtadx2 = xtadx2+0.5*ae_sqr(x.ptr.p_double[i], _state)*tau*d.ptr.p_double[i]; for(j=0; j<=n-1; j++) { v = v+0.5*alpha*x.ptr.p_double[i]*a.ptr.pp_double[i][j]*x.ptr.p_double[j]; ge.ptr.p_double[i] = ge.ptr.p_double[i]+alpha*a.ptr.pp_double[i][j]*x.ptr.p_double[j]; adxe.ptr.p_double[i] = adxe.ptr.p_double[i]+alpha*a.ptr.pp_double[i][j]*x.ptr.p_double[j]; xtadx2 = xtadx2+0.5*alpha*x.ptr.p_double[i]*a.ptr.pp_double[i][j]*x.ptr.p_double[j]; } } for(i=0; i<=k-1; i++) { v2 = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+0.5*theta*ae_sqr(v2-r.ptr.p_double[i], _state); for(j=0; j<=n-1; j++) { ge.ptr.p_double[j] = ge.ptr.p_double[j]+theta*(v2-r.ptr.p_double[i])*q.ptr.pp_double[i][j]; } } v2 = cqmeval(&s, &x, _state); eval0errors = eval0errors||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); cqmevalx(&s, &x, &v2, &noise, _state); eval0errors = eval0errors||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); eval0errors = (eval0errors||ae_fp_less(noise,(double)(0)))||ae_fp_greater(noise,10000*ae_machineepsilon); v2 = cqmxtadx2(&s, &x, _state); eval0errors = eval0errors||ae_fp_greater(ae_fabs(xtadx2-v2, _state),10000*ae_machineepsilon); cqmgradunconstrained(&s, &x, >, _state); for(i=0; i<=n-1; i++) { eval0errors = eval0errors||ae_fp_greater(ae_fabs(ge.ptr.p_double[i]-gt.ptr.p_double[i], _state),10000*ae_machineepsilon); } cqmadx(&s, &x, &adx, _state); for(i=0; i<=n-1; i++) { eval0errors = eval0errors||ae_fp_greater(ae_fabs(adx.ptr.p_double[i]-adxe.ptr.p_double[i], _state),10000*ae_machineepsilon); } } } waserrors = waserrors||eval0errors; /* * Eval1 test: constrained model evaluation */ eval1errors = ae_false; for(n=1; n<=5; n++) { for(k=0; k<=2*n; k++) { /* * Allocate place */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&activeset, n, _state); if( k>0 ) { ae_matrix_set_length(&q, k, n, _state); ae_vector_set_length(&r, k, _state); } /* * Generate problem */ alpha = ae_randomreal(_state)+1.0; theta = ae_randomreal(_state)+1.0; for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 10*(1+ae_randomreal(_state)); b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; activeset.ptr.p_bool[i] = ae_fp_greater(ae_randomreal(_state),0.5); for(j=i+1; j<=n-1; j++) { v = 0.1*ae_randomreal(_state)-0.05; a.ptr.pp_double[i][j] = v; a.ptr.pp_double[j][i] = v; } for(j=0; j<=k-1; j++) { q.ptr.pp_double[j][i] = 2*ae_randomreal(_state)-1; } } for(i=0; i<=k-1; i++) { r.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } /* * Build model, evaluate at random point X, compare */ cqminit(n, &s, _state); cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); cqmsetb(&s, &b, _state); cqmsetq(&s, &q, &r, k, theta, _state); cqmsetactiveset(&s, &xc, &activeset, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; if( !activeset.ptr.p_bool[i] ) { xc.ptr.p_double[i] = x.ptr.p_double[i]; } } v = 0.0; for(i=0; i<=n-1; i++) { v = v+xc.ptr.p_double[i]*b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { v = v+0.5*alpha*xc.ptr.p_double[i]*a.ptr.pp_double[i][j]*xc.ptr.p_double[j]; } } for(i=0; i<=k-1; i++) { v2 = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+0.5*theta*ae_sqr(v2-r.ptr.p_double[i], _state); } eval1errors = eval1errors||ae_fp_greater(ae_fabs(v-cqmeval(&s, &xc, _state), _state),10000*ae_machineepsilon); eval1errors = eval1errors||ae_fp_greater(ae_fabs(v-cqmdebugconstrainedevalt(&s, &x, _state), _state),10000*ae_machineepsilon); eval1errors = eval1errors||ae_fp_greater(ae_fabs(v-cqmdebugconstrainedevale(&s, &x, _state), _state),10000*ae_machineepsilon); } } waserrors = waserrors||eval1errors; /* * Eval2 test: we generate empty problem and apply sequence of random transformations, * re-evaluating and re-checking model after each modification. * * The purpose of such test is to ensure that our caching strategy works correctly. */ eval2errors = ae_false; for(n=1; n<=5; n++) { kmax = 2*n; ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xc, n, _state); ae_matrix_set_length(&q, kmax, n, _state); ae_vector_set_length(&r, kmax, _state); ae_vector_set_length(&activeset, n, _state); ae_vector_set_length(&tmp0, n, _state); alpha = 0.0; theta = 0.0; k = 0; tau = 1.0+ae_randomreal(_state); for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 1.0; b.ptr.p_double[i] = 0.0; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } cqminit(n, &s, _state); cqmsetd(&s, &d, tau, _state); for(pass=1; pass<=100; pass++) { /* * Select random modification type, apply modification. * * MKind is a random integer in [0,7] - number of specific * modification to apply. */ mkind = (double)(ae_randominteger(8, _state)); if( ae_fp_eq(mkind,(double)(0)) ) { /* * Set non-zero D */ tau = 1.0+ae_randomreal(_state); for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)+1; } cqmsetd(&s, &d, tau, _state); } else { if( ae_fp_eq(mkind,(double)(1)) ) { /* * Set zero D. * In case Alpha=0, set non-zero A. */ if( ae_fp_eq(alpha,(double)(0)) ) { alpha = 1.0+ae_randomreal(_state); for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.2*ae_randomreal(_state)-0.1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 4+2*ae_randomreal(_state); } cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); } tau = 0.0; for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = (double)(0); } cqmsetd(&s, &d, 0.0, _state); } else { if( ae_fp_eq(mkind,(double)(2)) ) { /* * Set non-zero A */ alpha = 1.0+ae_randomreal(_state); for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.2*ae_randomreal(_state)-0.1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 4+2*ae_randomreal(_state); } cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); } else { if( ae_fp_eq(mkind,(double)(3)) ) { /* * Set zero A. * In case Tau=0, set non-zero D. */ if( ae_fp_eq(tau,(double)(0)) ) { tau = 1.0+ae_randomreal(_state); for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = 2*ae_randomreal(_state)+1; } cqmsetd(&s, &d, tau, _state); } alpha = 0.0; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); } else { if( ae_fp_eq(mkind,(double)(4)) ) { /* * Set B. */ for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } cqmsetb(&s, &b, _state); } else { if( ae_fp_eq(mkind,(double)(5)) ) { /* * Set Q. */ k = ae_randominteger(kmax+1, _state); theta = 1.0+ae_randomreal(_state); for(i=0; i<=k-1; i++) { r.ptr.p_double[i] = 2*ae_randomreal(_state)-1; for(j=0; j<=n-1; j++) { q.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } cqmsetq(&s, &q, &r, k, theta, _state); } else { if( ae_fp_eq(mkind,(double)(6)) ) { /* * Set active set */ for(i=0; i<=n-1; i++) { activeset.ptr.p_bool[i] = ae_fp_greater(ae_randomreal(_state),0.5); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } cqmsetactiveset(&s, &xc, &activeset, _state); } else { if( ae_fp_eq(mkind,(double)(7)) ) { /* * Rewrite main diagonal */ if( ae_fp_eq(alpha,(double)(0)) ) { alpha = 1.0; } for(i=0; i<=n-1; i++) { tmp0.ptr.p_double[i] = 1+ae_randomreal(_state); a.ptr.pp_double[i][i] = tmp0.ptr.p_double[i]/alpha; } cqmrewritedensediagonal(&s, &tmp0, _state); } } } } } } } } /* * generate random point with respect to constraints, * test model at this point */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; if( activeset.ptr.p_bool[i] ) { x.ptr.p_double[i] = xc.ptr.p_double[i]; } } v = 0.0; for(i=0; i<=n-1; i++) { v = v+x.ptr.p_double[i]*b.ptr.p_double[i]; } if( ae_fp_greater(tau,(double)(0)) ) { for(i=0; i<=n-1; i++) { v = v+0.5*tau*d.ptr.p_double[i]*ae_sqr(x.ptr.p_double[i], _state); } } if( ae_fp_greater(alpha,(double)(0)) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = v+0.5*alpha*x.ptr.p_double[i]*a.ptr.pp_double[i][j]*x.ptr.p_double[j]; } } } if( ae_fp_greater(theta,(double)(0)) ) { for(i=0; i<=k-1; i++) { v2 = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+0.5*theta*ae_sqr(v2-r.ptr.p_double[i], _state); } } v2 = cqmeval(&s, &x, _state); eval2errors = eval2errors||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); v2 = cqmdebugconstrainedevalt(&s, &x, _state); eval2errors = eval2errors||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); v2 = cqmdebugconstrainedevale(&s, &x, _state); eval2errors = eval2errors||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); } } waserrors = waserrors||eval2errors; /* * Newton0 test: unconstrained optimization */ newton0errors = ae_false; for(n=1; n<=5; n++) { for(k=0; k<=2*n; k++) { /* * Allocate place */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); if( k>0 ) { ae_matrix_set_length(&q, k, n, _state); ae_vector_set_length(&r, k, _state); } /* * Generate problem with known solution x0: * min f(x), * f(x) = 0.5*(x-x0)'*A*(x-x0) * = 0.5*x'*A*x + (-x0'*A)*x + 0.5*x0'*A*x0' */ alpha = ae_randomreal(_state)+1.0; for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[i][i] = 10*(1+ae_randomreal(_state)); for(j=i+1; j<=n-1; j++) { v = 0.1*ae_randomreal(_state)-0.05; a.ptr.pp_double[i][j] = v; a.ptr.pp_double[j][i] = v; } } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = -alpha*v; } theta = ae_randomreal(_state)+1.0; for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { q.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } v = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); r.ptr.p_double[i] = v; } /* * Build model, evaluate at random point X, compare */ cqminit(n, &s, _state); cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); cqmsetb(&s, &b, _state); cqmsetq(&s, &q, &r, k, theta, _state); cqmconstrainedoptimum(&s, &x, _state); for(i=0; i<=n-1; i++) { newton0errors = newton0errors||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-x0.ptr.p_double[i], _state),1.0E6*ae_machineepsilon); } } } waserrors = waserrors||newton0errors; /* * Newton1 test: constrained optimization */ newton1errors = ae_false; h = 1.0E-3; for(n=1; n<=5; n++) { for(k=0; k<=2*n; k++) { /* * Allocate place */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&activeset, n, _state); if( k>0 ) { ae_matrix_set_length(&q, k, n, _state); ae_vector_set_length(&r, k, _state); } /* * Generate test problem with unknown solution. */ alpha = ae_randomreal(_state)+1.0; for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 10*(1+ae_randomreal(_state)); b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; activeset.ptr.p_bool[i] = ae_fp_greater(ae_randomreal(_state),0.5); for(j=i+1; j<=n-1; j++) { v = 0.1*ae_randomreal(_state)-0.05; a.ptr.pp_double[i][j] = v; a.ptr.pp_double[j][i] = v; } } theta = ae_randomreal(_state)+1.0; for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { q.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } r.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } /* * Build model, find solution */ cqminit(n, &s, _state); cqmseta(&s, &a, ae_fp_greater(ae_randomreal(_state),0.5), alpha, _state); cqmsetb(&s, &b, _state); cqmsetq(&s, &q, &r, k, theta, _state); cqmsetactiveset(&s, &xc, &activeset, _state); if( cqmconstrainedoptimum(&s, &x, _state) ) { /* * Check that constraints are satisfied, * and that solution is true optimum */ f0 = cqmeval(&s, &x, _state); for(i=0; i<=n-1; i++) { newton1errors = newton1errors||(activeset.ptr.p_bool[i]&&ae_fp_neq(x.ptr.p_double[i],xc.ptr.p_double[i])); if( !activeset.ptr.p_bool[i] ) { v = x.ptr.p_double[i]; x.ptr.p_double[i] = v+h; v2 = cqmeval(&s, &x, _state); newton1errors = newton1errors||ae_fp_less(v2,f0); x.ptr.p_double[i] = v-h; v2 = cqmeval(&s, &x, _state); newton1errors = newton1errors||ae_fp_less(v2,f0); x.ptr.p_double[i] = v; } } } else { newton1errors = ae_true; } } } waserrors = waserrors||newton1errors; /* * Newton2 test: we test ability to work with diagonal matrices, including * very large ones (up to 100.000 elements). This test checks that: * a) we can work with Alpha=0, i.e. when we have strictly diagonal A * b) diagonal problems are handled efficiently, i.e. algorithm will * successfully solve problem with N=100.000 * * Test problem: * * diagonal term D and rank-K term Q * * known solution X0, * * about 50% of constraints are active and equal to components of X0 */ newton2errors = ae_false; for(nkind=0; nkind<=5; nkind++) { for(k=0; k<=5; k++) { n = ae_round(ae_pow((double)(n), (double)(nkind), _state), _state); /* * generate problem */ ae_vector_set_length(&d, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&activeset, n, _state); if( k>0 ) { ae_matrix_set_length(&q, k, n, _state); ae_vector_set_length(&r, k, _state); } tau = 1+ae_randomreal(_state); theta = 1+ae_randomreal(_state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = 1+ae_randomreal(_state); b.ptr.p_double[i] = -x0.ptr.p_double[i]*tau*d.ptr.p_double[i]; activeset.ptr.p_bool[i] = ae_fp_greater(ae_randomreal(_state),0.5); } for(i=0; i<=k-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { q.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; v = v+q.ptr.pp_double[i][j]*x0.ptr.p_double[j]; } r.ptr.p_double[i] = v; } /* * Solve, test */ cqminit(n, &s, _state); cqmsetb(&s, &b, _state); cqmsetd(&s, &d, tau, _state); cqmsetq(&s, &q, &r, k, theta, _state); cqmsetactiveset(&s, &x0, &activeset, _state); if( cqmconstrainedoptimum(&s, &x, _state) ) { /* * Check that constraints are satisfied, * and that solution is true optimum */ f0 = cqmeval(&s, &x, _state); for(i=0; i<=n-1; i++) { newton2errors = newton2errors||(activeset.ptr.p_bool[i]&&ae_fp_neq(x.ptr.p_double[i],x0.ptr.p_double[i])); newton2errors = newton2errors||(!activeset.ptr.p_bool[i]&&ae_fp_greater(ae_fabs(x.ptr.p_double[i]-x0.ptr.p_double[i], _state),1000*ae_machineepsilon)); } /* * Check that constrained evaluation at some point gives correct results */ for(i=0; i<=n-1; i++) { if( activeset.ptr.p_bool[i] ) { x.ptr.p_double[i] = x0.ptr.p_double[i]; } else { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } } v = 0.0; for(i=0; i<=n-1; i++) { v = v+0.5*tau*d.ptr.p_double[i]*ae_sqr(x.ptr.p_double[i], _state)+x.ptr.p_double[i]*b.ptr.p_double[i]; } for(i=0; i<=k-1; i++) { v2 = ae_v_dotproduct(&q.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+0.5*theta*ae_sqr(v2-r.ptr.p_double[i], _state); } v2 = cqmeval(&s, &x, _state); newton2errors = (newton2errors||!ae_isfinite(v2, _state))||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); v2 = cqmdebugconstrainedevalt(&s, &x, _state); newton2errors = (newton2errors||!ae_isfinite(v2, _state))||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); v2 = cqmdebugconstrainedevale(&s, &x, _state); newton2errors = (newton2errors||!ae_isfinite(v2, _state))||ae_fp_greater(ae_fabs(v-v2, _state),10000*ae_machineepsilon); } else { newton2errors = ae_true; } } } waserrors = waserrors||newton2errors; /* * report */ if( !silent ) { printf("TESTING CONVEX QUADRATIC MODELS\n"); printf("Eval0 test: "); if( eval0errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Eval1 test: "); if( eval1errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Eval2 test: "); if( eval2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Newton0 test: "); if( newton0errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Newton1 test: "); if( newton1errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Newton2 test: "); if( newton2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testcqmodels(ae_bool silent, ae_state *_state) { return testcqmodels(silent, _state); } ae_bool testsnnls(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool test0errors; ae_bool test1errors; ae_bool test2errors; ae_bool testnewtonerrors; ae_bool waserrors; double eps; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_int_t ns; ae_int_t nd; ae_int_t nr; ae_matrix densea; ae_matrix effectivea; ae_vector isconstrained; ae_vector g; ae_vector b; ae_vector x; ae_vector xs; snnlssolver s; hqrndstate rs; double rho; double xtol; ae_int_t nmax; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&densea, 0, 0, DT_REAL, _state); ae_matrix_init(&effectivea, 0, 0, DT_REAL, _state); ae_vector_init(&isconstrained, 0, DT_BOOL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xs, 0, DT_REAL, _state); _snnlssolver_init(&s, _state); _hqrndstate_init(&rs, _state); test0errors = ae_false; test1errors = ae_false; test2errors = ae_false; testnewtonerrors = ae_false; waserrors = ae_false; hqrndrandomize(&rs, _state); nmax = 10; /* * Test 2 (comes first because it is very basic): * * NS=0 * * ND in [1,NMAX] * * NR=ND * * DenseA is diagonal with positive entries * * B is random * * random constraints * Exact solution is known and can be tested */ eps = 1.0E-12; for(nd=1; nd<=nmax; nd++) { /* * Generate problem */ ns = 0; nr = nd; ae_matrix_set_length(&densea, nd, nd, _state); ae_vector_set_length(&b, nd, _state); ae_vector_set_length(&isconstrained, nd, _state); for(i=0; i<=nd-1; i++) { for(j=0; j<=nd-1; j++) { densea.ptr.pp_double[i][j] = (double)(0); } densea.ptr.pp_double[i][i] = (double)(1+hqrnduniformi(&rs, 2, _state)); b.ptr.p_double[i] = (double)((1+hqrnduniformi(&rs, 2, _state))*(2*hqrnduniformi(&rs, 2, _state)-1)); isconstrained.ptr.p_bool[i] = ae_fp_greater(hqrnduniformr(&rs, _state),0.5); } /* * Solve with SNNLS solver */ snnlsinit(0, 0, 0, &s, _state); snnlssetproblem(&s, &densea, &b, 0, nd, nd, _state); for(i=0; i<=nd-1; i++) { if( !isconstrained.ptr.p_bool[i] ) { snnlsdropnnc(&s, i, _state); } } snnlssolve(&s, &x, _state); /* * Check */ for(i=0; i<=nd-1; i++) { if( isconstrained.ptr.p_bool[i] ) { seterrorflag(&test2errors, ae_fp_greater(ae_fabs(x.ptr.p_double[i]-ae_maxreal(b.ptr.p_double[i]/densea.ptr.pp_double[i][i], 0.0, _state), _state),eps), _state); seterrorflag(&test2errors, ae_fp_less(x.ptr.p_double[i],0.0), _state); } else { seterrorflag(&test2errors, ae_fp_greater(ae_fabs(x.ptr.p_double[i]-b.ptr.p_double[i]/densea.ptr.pp_double[i][i], _state),eps), _state); } } } /* * Test 0: * * NS in [0,NMAX] * * ND in [0,NMAX] * * NR in [NS,NS+ND+NMAX] * * NS+ND>0, NR>0 * * about 50% of variables are constrained * * we check that constrained gradient is small at the solution */ eps = 1.0E-5; for(ns=0; ns<=nmax; ns++) { for(nd=0; nd<=nmax; nd++) { for(nr=ns; nr<=ns+nd+nmax; nr++) { /* * Skip NS+ND=0, NR=0 */ if( ns+nd==0 ) { continue; } if( nr==0 ) { continue; } /* * Generate problem: * * DenseA, array[NR,ND] * * EffectiveA, array[NR,NS+ND] * * B, array[NR] * * IsConstrained, array[NS+ND] */ if( nd>0 ) { ae_matrix_set_length(&densea, nr, nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { densea.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } } ae_matrix_set_length(&effectivea, nr, ns+nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=ns+nd-1; j++) { effectivea.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=ns-1; i++) { effectivea.ptr.pp_double[i][i] = 1.0; } for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { effectivea.ptr.pp_double[i][ns+j] = densea.ptr.pp_double[i][j]; } } ae_vector_set_length(&b, nr, _state); for(i=0; i<=nr-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&isconstrained, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { isconstrained.ptr.p_bool[i] = ae_fp_greater(ae_randomreal(_state),0.5); } /* * Solve with SNNLS solver */ snnlsinit(0, 0, 0, &s, _state); snnlssetproblem(&s, &densea, &b, ns, nd, nr, _state); for(i=0; i<=ns+nd-1; i++) { if( !isconstrained.ptr.p_bool[i] ) { snnlsdropnnc(&s, i, _state); } } snnlssolve(&s, &x, _state); /* * Check non-negativity */ for(i=0; i<=ns+nd-1; i++) { seterrorflag(&test0errors, isconstrained.ptr.p_bool[i]&&ae_fp_less(x.ptr.p_double[i],(double)(0)), _state); } /* * Calculate gradient A'*A*x-b'*A. * Check projected gradient (each component must be less than Eps). */ ae_vector_set_length(&g, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { v = ae_v_dotproduct(&b.ptr.p_double[0], 1, &effectivea.ptr.pp_double[0][i], effectivea.stride, ae_v_len(0,nr-1)); g.ptr.p_double[i] = -v; } for(i=0; i<=nr-1; i++) { v = ae_v_dotproduct(&effectivea.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,ns+nd-1)); ae_v_addd(&g.ptr.p_double[0], 1, &effectivea.ptr.pp_double[i][0], 1, ae_v_len(0,ns+nd-1), v); } for(i=0; i<=ns+nd-1; i++) { if( !isconstrained.ptr.p_bool[i]||ae_fp_greater(x.ptr.p_double[i],(double)(0)) ) { seterrorflag(&test0errors, ae_fp_greater(ae_fabs(g.ptr.p_double[i], _state),eps), _state); } else { seterrorflag(&test0errors, ae_fp_less(g.ptr.p_double[i],-eps), _state); } } } } } /* * Test 1: ability of the solver to take very short steps. * * We solve problem similar to one solver in test 0, but with * progressively decreased magnitude of variables. We generate * problem with already-known solution and compare results against it. */ xtol = 1.0E6*ae_machineepsilon; for(ns=0; ns<=nmax; ns++) { for(nd=0; nd<=nmax; nd++) { for(nr=ns; nr<=ns+nd+nmax; nr++) { for(k=0; k<=20; k++) { /* * Skip NS+ND=0, NR=0 * * Skip degenerate problems (NR0 ) { ae_matrix_set_length(&densea, nr, nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { densea.ptr.pp_double[i][j] = 2*hqrnduniformr(&rs, _state)-1; } } } ae_matrix_set_length(&effectivea, nr, ns+nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=ns+nd-1; j++) { effectivea.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=ns-1; i++) { effectivea.ptr.pp_double[i][i] = 1.0; } for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { effectivea.ptr.pp_double[i][ns+j] = densea.ptr.pp_double[i][j]; } } ae_vector_set_length(&xs, ns+nd, _state); ae_vector_set_length(&isconstrained, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { xs.ptr.p_double[i] = rho*(hqrnduniformr(&rs, _state)-0.5); isconstrained.ptr.p_bool[i] = ae_fp_greater(xs.ptr.p_double[i],0.0); } ae_vector_set_length(&b, nr, _state); for(i=0; i<=nr-1; i++) { v = 0.0; for(j=0; j<=ns+nd-1; j++) { v = v+effectivea.ptr.pp_double[i][j]*xs.ptr.p_double[j]; } b.ptr.p_double[i] = v; } /* * Solve with SNNLS solver */ snnlsinit(0, 0, 0, &s, _state); snnlssetproblem(&s, &densea, &b, ns, nd, nr, _state); for(i=0; i<=ns+nd-1; i++) { if( !isconstrained.ptr.p_bool[i] ) { snnlsdropnnc(&s, i, _state); } } snnlssolve(&s, &x, _state); /* * Check non-negativity */ for(i=0; i<=ns+nd-1; i++) { seterrorflag(&test1errors, isconstrained.ptr.p_bool[i]&&ae_fp_less(x.ptr.p_double[i],(double)(0)), _state); } /* * Compare with true solution */ for(i=0; i<=ns+nd-1; i++) { seterrorflag(&test1errors, ae_fp_greater(ae_fabs(xs.ptr.p_double[i]-x.ptr.p_double[i], _state),rho*xtol), _state); } } } } } /* * Test for Newton phase: * * NS in [0,NMAX] * * ND in [0,NMAX] * * NR in [NS,NS+ND+NMAX] * * NS+ND>0, NR>0 * * all variables are unconstrained * * S.DebugMaxNewton is set to 1, S.RefinementIts is set to 1, * i.e. algorithm is terminated after one Newton iteration, and no * iterative refinement is used. * * we test that gradient is small at solution, i.e. one Newton iteration * on unconstrained problem is enough to find solution. In case of buggy * Newton solver one iteration won't move us to the solution - it may * decrease function value, but won't find exact solution. * * This test is intended to catch subtle bugs in the Newton solver which * do NOT prevent algorithm from converging to the solution, but slow it * down (convergence becomes linear or even slower). */ eps = 1.0E-4; for(ns=0; ns<=nmax; ns++) { for(nd=0; nd<=nmax; nd++) { for(nr=ns; nr<=ns+nd+nmax; nr++) { /* * Skip NS+ND=0, NR=0 */ if( ns+nd==0 ) { continue; } if( nr==0 ) { continue; } /* * Generate problem: * * DenseA, array[NR,ND] * * EffectiveA, array[NR,NS+ND] * * B, array[NR] * * IsConstrained, array[NS+ND] */ if( nd>0 ) { ae_matrix_set_length(&densea, nr, nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { densea.ptr.pp_double[i][j] = hqrndnormal(&rs, _state); } } } ae_matrix_set_length(&effectivea, nr, ns+nd, _state); for(i=0; i<=nr-1; i++) { for(j=0; j<=ns+nd-1; j++) { effectivea.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=ns-1; i++) { effectivea.ptr.pp_double[i][i] = 1.0; } for(i=0; i<=nr-1; i++) { for(j=0; j<=nd-1; j++) { effectivea.ptr.pp_double[i][ns+j] = densea.ptr.pp_double[i][j]; } } ae_vector_set_length(&b, nr, _state); for(i=0; i<=nr-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); } /* * Solve with SNNLS solver */ snnlsinit(0, 0, 0, &s, _state); snnlssetproblem(&s, &densea, &b, ns, nd, nr, _state); for(i=0; i<=ns+nd-1; i++) { snnlsdropnnc(&s, i, _state); } s.debugmaxinnerits = 1; snnlssolve(&s, &x, _state); /* * Calculate gradient A'*A*x-b'*A. * Check projected gradient (each component must be less than Eps). */ ae_vector_set_length(&g, ns+nd, _state); for(i=0; i<=ns+nd-1; i++) { v = ae_v_dotproduct(&b.ptr.p_double[0], 1, &effectivea.ptr.pp_double[0][i], effectivea.stride, ae_v_len(0,nr-1)); g.ptr.p_double[i] = -v; } for(i=0; i<=nr-1; i++) { v = ae_v_dotproduct(&effectivea.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,ns+nd-1)); ae_v_addd(&g.ptr.p_double[0], 1, &effectivea.ptr.pp_double[i][0], 1, ae_v_len(0,ns+nd-1), v); } for(i=0; i<=ns+nd-1; i++) { seterrorflag(&testnewtonerrors, ae_fp_greater(ae_fabs(g.ptr.p_double[i], _state),eps), _state); } } } } /* * report */ waserrors = ((test0errors||test1errors)||test2errors)||testnewtonerrors; if( !silent ) { printf("TESTING SPECIAL NNLS SOLVER\n"); printf("TEST 0: "); if( test0errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST 1: "); if( test1errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST 2: "); if( test2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("NEWTON PHASE: "); if( testnewtonerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsnnls(ae_bool silent, ae_state *_state) { return testsnnls(silent, _state); } ae_bool testsactivesets(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool result; waserrors = ae_false; /* * report */ waserrors = waserrors; if( !silent ) { printf("TESTING ACTIVE SETS\n"); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testsactivesets(ae_bool silent, ae_state *_state) { return testsactivesets(silent, _state); } ae_bool testlinmin(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool result; waserrors = ae_false; if( !silent ) { printf("TESTING LINMIN\n"); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlinmin(ae_bool silent, ae_state *_state) { return testlinmin(silent, _state); } static void testmincgunit_testfunc2(mincgstate* state, ae_state *_state); static void testmincgunit_testfunc3(mincgstate* state, ae_state *_state); static void testmincgunit_calciip2(mincgstate* state, ae_int_t n, ae_state *_state); static void testmincgunit_calclowrank(mincgstate* state, ae_int_t n, ae_int_t vcnt, /* Real */ ae_vector* d, /* Real */ ae_matrix* v, /* Real */ ae_vector* vd, /* Real */ ae_vector* x0, ae_state *_state); static void testmincgunit_testpreconditioning(ae_bool* err, ae_state *_state); static ae_bool testmincgunit_gradientchecktest(ae_state *_state); static void testmincgunit_funcderiv(double a, double b, double c, double d, double x0, double x1, double x2, /* Real */ ae_vector* x, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state); ae_bool testmincg(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool referror; ae_bool eqerror; ae_bool linerror1; ae_bool linerror2; ae_bool restartserror; ae_bool precerror; ae_bool converror; ae_bool othererrors; ae_bool graderrors; ae_int_t n; ae_vector x; ae_vector xe; ae_vector b; ae_vector xlast; ae_int_t i; ae_int_t j; double v; ae_matrix a; ae_vector diagh; mincgstate state; mincgreport rep; ae_int_t cgtype; ae_int_t difftype; double diffstep; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&diagh, 0, DT_REAL, _state); _mincgstate_init(&state, _state); _mincgreport_init(&rep, _state); waserrors = ae_false; referror = ae_false; linerror1 = ae_false; linerror2 = ae_false; eqerror = ae_false; converror = ae_false; restartserror = ae_false; othererrors = ae_false; precerror = ae_false; testmincgunit_testpreconditioning(&precerror, _state); testother(&othererrors, _state); for(difftype=0; difftype<=1; difftype++) { for(cgtype=-1; cgtype<=1; cgtype++) { /* * Reference problem */ ae_vector_set_length(&x, 2+1, _state); n = 3; diffstep = 1.0E-6; x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; x.ptr.p_double[1] = 100*ae_randomreal(_state)-50; x.ptr.p_double[2] = 100*ae_randomreal(_state)-50; if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); } if( state.needfg ) { state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]-2)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } } mincgresults(&state, &x, &rep, _state); referror = (((referror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-2, _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-2, _state),0.001); /* * F2 problem with restarts: * * make several iterations and restart BEFORE termination * * iterate and restart AFTER termination * * NOTE: step is bounded from above to avoid premature convergence */ ae_vector_set_length(&x, 3, _state); n = 3; diffstep = 1.0E-6; x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcgtype(&state, cgtype, _state); mincgsetstpmax(&state, 0.1, _state); mincgsetcond(&state, 0.0000001, 0.0, 0.0, 0, _state); for(i=0; i<=10; i++) { if( !mincgiteration(&state, _state) ) { break; } testmincgunit_testfunc2(&state, _state); } x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc2(&state, _state); } mincgresults(&state, &x, &rep, _state); restartserror = (((restartserror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.01); x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc2(&state, _state); } mincgresults(&state, &x, &rep, _state); restartserror = (((restartserror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.01); /* * 1D problem #1 */ ae_vector_set_length(&x, 0+1, _state); n = 1; diffstep = 1.0E-6; x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = -ae_cos(state.x.ptr.p_double[0], _state); } if( state.needfg ) { state.g.ptr.p_double[0] = ae_sin(state.x.ptr.p_double[0], _state); } } mincgresults(&state, &x, &rep, _state); linerror1 = (linerror1||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]/ae_pi-ae_round(x.ptr.p_double[0]/ae_pi, _state), _state),0.001); /* * 1D problem #2 */ ae_vector_set_length(&x, 0+1, _state); n = 1; diffstep = 1.0E-6; x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0], _state)/(1+ae_sqr(state.x.ptr.p_double[0], _state)); } if( state.needfg ) { state.g.ptr.p_double[0] = (2*state.x.ptr.p_double[0]*(1+ae_sqr(state.x.ptr.p_double[0], _state))-ae_sqr(state.x.ptr.p_double[0], _state)*2*state.x.ptr.p_double[0])/ae_sqr(1+ae_sqr(state.x.ptr.p_double[0], _state), _state); } } mincgresults(&state, &x, &rep, _state); linerror2 = (linerror2||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0], _state),0.001); /* * Linear equations */ diffstep = 1.0E-6; for(n=1; n<=10; n++) { /* * Prepare task */ ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&xe, n-1+1, _state); ae_vector_set_length(&b, n-1+1, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } a.ptr.pp_double[i][i] = a.ptr.pp_double[i][i]+3*ae_sign(a.ptr.pp_double[i][i], _state); } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = v; } /* * Solve task */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } if( state.needfg ) { for(i=0; i<=n-1; i++) { state.g.ptr.p_double[i] = (double)(0); } } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( state.needf||state.needfg ) { state.f = state.f+ae_sqr(v-b.ptr.p_double[i], _state); } if( state.needfg ) { for(j=0; j<=n-1; j++) { state.g.ptr.p_double[j] = state.g.ptr.p_double[j]+2*(v-b.ptr.p_double[i])*a.ptr.pp_double[i][j]; } } } } mincgresults(&state, &x, &rep, _state); eqerror = eqerror||rep.terminationtype<=0; for(i=0; i<=n-1; i++) { eqerror = eqerror||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-xe.ptr.p_double[i], _state),0.001); } } /* * Testing convergence properties */ diffstep = 1.0E-6; n = 3; ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcond(&state, 0.001, 0.0, 0.0, 0, _state); mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc3(&state, _state); } mincgresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=4; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcond(&state, 0.0, 0.001, 0.0, 0, _state); mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc3(&state, _state); } mincgresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcond(&state, 0.0, 0.0, 0.001, 0, _state); mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc3(&state, _state); } mincgresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=2; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( difftype==0 ) { mincgcreate(n, &x, &state, _state); } if( difftype==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcond(&state, 0.0, 0.0, 0.0, 10, _state); mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { testmincgunit_testfunc3(&state, _state); } mincgresults(&state, &x, &rep, _state); converror = converror||!((rep.terminationtype==5&&rep.iterationscount==10)||rep.terminationtype==7); } } /* * Test for MinCGGradientCheck */ graderrors = testmincgunit_gradientchecktest(_state); /* * end */ waserrors = (((((((referror||eqerror)||linerror1)||linerror2)||converror)||othererrors)||restartserror)||precerror)||graderrors; if( !silent ) { printf("TESTING CG OPTIMIZATION\n"); printf("REFERENCE PROBLEM: "); if( referror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LIN-1 PROBLEM: "); if( linerror1 ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LIN-2 PROBLEM: "); if( linerror2 ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LINEAR EQUATIONS: "); if( eqerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RESTARTS: "); if( restartserror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("PRECONDITIONING: "); if( precerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CONVERGENCE PROPERTIES: "); if( converror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("OTHER PROPERTIES: "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST FOR VERIFICATION OF THE GRADIENT: "); if( graderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmincg(ae_bool silent, ae_state *_state) { return testmincg(silent, _state); } /************************************************************************* Other properties *************************************************************************/ void testother(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_vector x; ae_vector s; ae_vector a; ae_vector b; ae_vector h; ae_vector x0; ae_vector x1; ae_vector xlast; ae_matrix fulla; double fprev; double xprev; double stpmax; ae_int_t i; ae_int_t j; ae_int_t k; mincgstate state; mincgreport rep; ae_int_t cgtype; double tmpeps; double epsg; double v; double r; ae_bool hasxlast; double lastscaledstep; ae_int_t pkind; ae_int_t ckind; ae_int_t mkind; ae_int_t dkind; double diffstep; double vc; double vm; ae_bool wasf; ae_bool wasfg; hqrndstate rs; ae_int_t spoiliteration; ae_int_t stopiteration; ae_int_t spoilvar; double spoilval; ae_int_t pass; double ss; ae_int_t callidx; ae_int_t stopcallidx; ae_int_t maxits; ae_bool terminationrequested; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&h, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); _mincgstate_init(&state, _state); _mincgreport_init(&rep, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); for(cgtype=-1; cgtype<=1; cgtype++) { /* * Test reports (F should form monotone sequence) */ n = 50; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(1); } mincgcreate(n, &x, &state, _state); mincgsetcond(&state, (double)(0), (double)(0), (double)(0), 100, _state); mincgsetxrep(&state, ae_true, _state); fprev = ae_maxrealnumber; while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_sqr((1+i)*state.x.ptr.p_double[i], _state); state.g.ptr.p_double[i] = 2*(1+i)*state.x.ptr.p_double[i]; } } if( state.xupdated ) { *err = *err||ae_fp_greater(state.f,fprev); if( ae_fp_eq(fprev,ae_maxrealnumber) ) { for(i=0; i<=n-1; i++) { *err = *err||ae_fp_neq(state.x.ptr.p_double[i],x.ptr.p_double[i]); } } fprev = state.f; ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } mincgresults(&state, &x, &rep, _state); for(i=0; i<=n-1; i++) { *err = *err||ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]); } /* * Test differentiation vs. analytic gradient * (first one issues NeedF requests, second one issues NeedFG requests) */ n = 50; diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(1); } if( dkind==0 ) { mincgcreate(n, &x, &state, _state); } if( dkind==1 ) { mincgcreatef(n, &x, diffstep, &state, _state); } mincgsetcond(&state, (double)(0), (double)(0), (double)(0), n/2, _state); wasf = ae_false; wasfg = ae_false; while(mincgiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_sqr((1+i)*state.x.ptr.p_double[i], _state); } if( state.needfg ) { state.g.ptr.p_double[i] = 2*(1+i)*state.x.ptr.p_double[i]; } } wasf = wasf||state.needf; wasfg = wasfg||state.needfg; } mincgresults(&state, &x, &rep, _state); if( dkind==0 ) { *err = (*err||wasf)||!wasfg; } if( dkind==1 ) { *err = (*err||!wasf)||wasfg; } } /* * Test that numerical differentiation uses scaling. * * In order to test that we solve simple optimization * problem: min(x^2) with initial x equal to 0.0. * * We choose random DiffStep and S, then we check that * optimizer evaluates function at +-DiffStep*S only. */ ae_vector_set_length(&x, 1, _state); ae_vector_set_length(&s, 1, _state); diffstep = ae_randomreal(_state)*1.0E-6; s.ptr.p_double[0] = ae_exp(ae_randomreal(_state)*4-2, _state); x.ptr.p_double[0] = (double)(0); mincgcreatef(1, &x, diffstep, &state, _state); mincgsetcond(&state, 1.0E-6, (double)(0), (double)(0), 0, _state); mincgsetscale(&state, &s, _state); v = (double)(0); while(mincgiteration(&state, _state)) { state.f = ae_sqr(state.x.ptr.p_double[0], _state); v = ae_maxreal(v, ae_fabs(state.x.ptr.p_double[0], _state), _state); } mincgresults(&state, &x, &rep, _state); r = v/(s.ptr.p_double[0]*diffstep); *err = *err||ae_fp_greater(ae_fabs(ae_log(r, _state), _state),ae_log(1+1000*ae_machineepsilon, _state)); /* * Test maximum step */ n = 1; ae_vector_set_length(&x, n, _state); x.ptr.p_double[0] = (double)(100); stpmax = 0.05+0.05*ae_randomreal(_state); mincgcreate(n, &x, &state, _state); mincgsetcond(&state, 1.0E-9, (double)(0), (double)(0), 0, _state); mincgsetstpmax(&state, stpmax, _state); mincgsetxrep(&state, ae_true, _state); xprev = x.ptr.p_double[0]; while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = ae_exp(state.x.ptr.p_double[0], _state)+ae_exp(-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = ae_exp(state.x.ptr.p_double[0], _state)-ae_exp(-state.x.ptr.p_double[0], _state); *err = *err||ae_fp_greater(ae_fabs(state.x.ptr.p_double[0]-xprev, _state),(1+ae_sqrt(ae_machineepsilon, _state))*stpmax); } if( state.xupdated ) { *err = *err||ae_fp_greater(ae_fabs(state.x.ptr.p_double[0]-xprev, _state),(1+ae_sqrt(ae_machineepsilon, _state))*stpmax); xprev = state.x.ptr.p_double[0]; } } /* * Test correctness of the scaling: * * initial point is random point from [+1,+2]^N * * f(x) = SUM(A[i]*x[i]^4), C[i] is random from [0.01,100] * * we use random scaling matrix * * we test different variants of the preconditioning: * 0) unit preconditioner * 1) random diagonal from [0.01,100] * 2) scale preconditioner * * we set stringent stopping conditions (we try EpsG and EpsX) * * and we test that in the extremum stopping conditions are * satisfied subject to the current scaling coefficients. */ tmpeps = 1.0E-10; for(n=1; n<=10; n++) { for(pkind=0; pkind<=2; pkind++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&h, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)+1; a.ptr.p_double[i] = ae_exp(ae_log((double)(100), _state)*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_exp(ae_log((double)(100), _state)*(2*ae_randomreal(_state)-1), _state); h.ptr.p_double[i] = ae_exp(ae_log((double)(100), _state)*(2*ae_randomreal(_state)-1), _state); } mincgcreate(n, &x, &state, _state); mincgsetscale(&state, &s, _state); mincgsetxrep(&state, ae_true, _state); if( pkind==1 ) { mincgsetprecdiag(&state, &h, _state); } if( pkind==2 ) { mincgsetprecscale(&state, _state); } /* * Test gradient-based stopping condition */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)+1; } mincgsetcond(&state, tmpeps, (double)(0), (double)(0), 0, _state); mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+a.ptr.p_double[i]*ae_pow(state.x.ptr.p_double[i], (double)(4), _state); state.g.ptr.p_double[i] = 4*a.ptr.p_double[i]*ae_pow(state.x.ptr.p_double[i], (double)(3), _state); } } } mincgresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(s.ptr.p_double[i]*4*a.ptr.p_double[i]*ae_pow(x.ptr.p_double[i], (double)(3), _state), _state); } v = ae_sqrt(v, _state); *err = *err||ae_fp_greater(v,tmpeps); /* * Test step-based stopping condition */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)+1; } hasxlast = ae_false; mincgsetcond(&state, (double)(0), (double)(0), tmpeps, 0, _state); mincgrestartfrom(&state, &x, _state); lastscaledstep = (double)(0); while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+a.ptr.p_double[i]*ae_pow(state.x.ptr.p_double[i], (double)(4), _state); state.g.ptr.p_double[i] = 4*a.ptr.p_double[i]*ae_pow(state.x.ptr.p_double[i], (double)(3), _state); } } if( state.xupdated ) { if( hasxlast ) { lastscaledstep = (double)(0); for(i=0; i<=n-1; i++) { lastscaledstep = lastscaledstep+ae_sqr(state.x.ptr.p_double[i]-xlast.ptr.p_double[i], _state)/ae_sqr(s.ptr.p_double[i], _state); } lastscaledstep = ae_sqrt(lastscaledstep, _state); } else { lastscaledstep = (double)(0); } ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); hasxlast = ae_true; } } mincgresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } *err = *err||ae_fp_greater(lastscaledstep,tmpeps); } } /* * Check correctness of the "trimming". * * Trimming is a technique which is used to help algorithm * cope with unbounded functions. In order to check this * technique we will try to solve following optimization * problem: * * min f(x) subject to no constraints on X * { 1/(1-x) + 1/(1+x) + c*x, if -0.999999=0.999999 * * where c is either 1.0 or 1.0E+6, M is either 1.0E8, 1.0E20 or +INF * (we try different combinations) */ for(ckind=0; ckind<=1; ckind++) { for(mkind=0; mkind<=2; mkind++) { /* * Choose c and M */ vc = 1.0; vm = 1.0E+8; if( ckind==1 ) { vc = 1.0E+6; } if( mkind==1 ) { vm = 1.0E+20; } if( mkind==2 ) { vm = _state->v_posinf; } /* * Create optimizer, solve optimization problem */ epsg = 1.0E-6*vc; ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = 0.0; mincgcreate(1, &x, &state, _state); mincgsetcond(&state, epsg, (double)(0), (double)(0), 0, _state); mincgsetcgtype(&state, cgtype, _state); while(mincgiteration(&state, _state)) { if( state.needfg ) { if( ae_fp_less(-0.999999,state.x.ptr.p_double[0])&&ae_fp_less(state.x.ptr.p_double[0],0.999999) ) { state.f = 1/(1-state.x.ptr.p_double[0])+1/(1+state.x.ptr.p_double[0])+vc*state.x.ptr.p_double[0]; state.g.ptr.p_double[0] = 1/ae_sqr(1-state.x.ptr.p_double[0], _state)-1/ae_sqr(1+state.x.ptr.p_double[0], _state)+vc; } else { state.f = vm; } } } mincgresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } *err = *err||ae_fp_greater(ae_fabs(1/ae_sqr(1-x.ptr.p_double[0], _state)-1/ae_sqr(1+x.ptr.p_double[0], _state)+vc, _state),epsg); } } } /* * Test integrity checks for NAN/INF: * * algorithm solves optimization problem, which is normal for some time (quadratic) * * after 5-th step we choose random component of gradient and consistently spoil * it by NAN or INF. * * we check that correct termination code is returned (-8) */ n = 100; for(pass=1; pass<=10; pass++) { spoiliteration = 5; stopiteration = 8; if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { /* * Gradient can be spoiled by +INF, -INF, NAN */ spoilvar = hqrnduniformi(&rs, n, _state); i = hqrnduniformi(&rs, 3, _state); spoilval = _state->v_nan; if( i==0 ) { spoilval = _state->v_neginf; } if( i==1 ) { spoilval = _state->v_posinf; } } else { /* * Function value can be spoiled only by NAN * (+INF can be recognized as legitimate value during optimization) */ spoilvar = -1; spoilval = _state->v_nan; } spdmatrixrndcond(n, 1.0E5, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } mincgcreate(n, &x0, &state, _state); mincgsetcond(&state, 0.0, 0.0, 0.0, stopiteration, _state); mincgsetxrep(&state, ae_true, _state); k = -1; while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.f = state.f+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.g.ptr.p_double[i] = state.g.ptr.p_double[i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } if( k>=spoiliteration ) { if( spoilvar<0 ) { state.f = spoilval; } else { state.g.ptr.p_double[spoilvar] = spoilval; } } continue; } if( state.xupdated ) { inc(&k, _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } mincgresults(&state, &x1, &rep, _state); seterrorflag(err, rep.terminationtype!=-8, _state); } /* * Check algorithm ability to handle request for termination: * * to terminate with correct return code = 8 * * to return point which was "current" at the moment of termination */ for(pass=1; pass<=50; pass++) { n = 3; ss = (double)(100); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6+ae_randomreal(_state); } stopcallidx = ae_randominteger(20, _state); maxits = 25; mincgcreate(n, &x, &state, _state); mincgsetcond(&state, (double)(0), (double)(0), (double)(0), maxits, _state); mincgsetxrep(&state, ae_true, _state); callidx = 0; terminationrequested = ae_false; ae_v_move(&xlast.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); while(mincgiteration(&state, _state)) { if( state.needfg ) { state.f = ss*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = 2*ss*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0])*(-1); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); if( callidx==stopcallidx ) { mincgrequesttermination(&state, _state); terminationrequested = ae_true; } inc(&callidx, _state); continue; } if( state.xupdated ) { if( !terminationrequested ) { ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } continue; } ae_assert(ae_false, "Assertion failed", _state); } mincgresults(&state, &x, &rep, _state); seterrorflag(err, rep.terminationtype!=8, _state); for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]), _state); } } ae_frame_leave(_state); } /************************************************************************* Calculate test function #2 Simple variation of #1, much more nonlinear, which makes unlikely premature convergence of algorithm . *************************************************************************/ static void testmincgunit_testfunc2(mincgstate* state, ae_state *_state) { if( ae_fp_less(state->x.ptr.p_double[0],(double)(100)) ) { if( state->needf||state->needfg ) { state->f = ae_sqr(ae_exp(state->x.ptr.p_double[0], _state)-2, _state)+ae_sqr(ae_sqr(state->x.ptr.p_double[1], _state), _state)+ae_sqr(state->x.ptr.p_double[2]-state->x.ptr.p_double[0], _state); } if( state->needfg ) { state->g.ptr.p_double[0] = 2*(ae_exp(state->x.ptr.p_double[0], _state)-2)*ae_exp(state->x.ptr.p_double[0], _state)+2*(state->x.ptr.p_double[0]-state->x.ptr.p_double[2]); state->g.ptr.p_double[1] = 4*state->x.ptr.p_double[1]*ae_sqr(state->x.ptr.p_double[1], _state); state->g.ptr.p_double[2] = 2*(state->x.ptr.p_double[2]-state->x.ptr.p_double[0]); } } else { if( state->needf||state->needfg ) { state->f = ae_sqrt(ae_maxrealnumber, _state); } if( state->needfg ) { state->g.ptr.p_double[0] = ae_sqrt(ae_maxrealnumber, _state); state->g.ptr.p_double[1] = (double)(0); state->g.ptr.p_double[2] = (double)(0); } } } /************************************************************************* Calculate test function #3 Simple variation of #1, much more nonlinear, with non-zero value at minimum. It achieve two goals: * makes unlikely premature convergence of algorithm . * solves some issues with EpsF stopping condition which arise when F(minimum) is zero *************************************************************************/ static void testmincgunit_testfunc3(mincgstate* state, ae_state *_state) { double s; s = 0.001; if( ae_fp_less(state->x.ptr.p_double[0],(double)(100)) ) { if( state->needf||state->needfg ) { state->f = ae_sqr(ae_exp(state->x.ptr.p_double[0], _state)-2, _state)+ae_sqr(ae_sqr(state->x.ptr.p_double[1], _state)+s, _state)+ae_sqr(state->x.ptr.p_double[2]-state->x.ptr.p_double[0], _state); } if( state->needfg ) { state->g.ptr.p_double[0] = 2*(ae_exp(state->x.ptr.p_double[0], _state)-2)*ae_exp(state->x.ptr.p_double[0], _state)+2*(state->x.ptr.p_double[0]-state->x.ptr.p_double[2]); state->g.ptr.p_double[1] = 2*(ae_sqr(state->x.ptr.p_double[1], _state)+s)*2*state->x.ptr.p_double[1]; state->g.ptr.p_double[2] = 2*(state->x.ptr.p_double[2]-state->x.ptr.p_double[0]); } } else { if( state->needf||state->needfg ) { state->f = ae_sqrt(ae_maxrealnumber, _state); } if( state->needfg ) { state->g.ptr.p_double[0] = ae_sqrt(ae_maxrealnumber, _state); state->g.ptr.p_double[1] = (double)(0); state->g.ptr.p_double[2] = (double)(0); } } } /************************************************************************* Calculate test function IIP2 f(x) = sum( ((i*i+1)*x[i])^2, i=0..N-1) It has high condition number which makes fast convergence unlikely without good preconditioner. *************************************************************************/ static void testmincgunit_calciip2(mincgstate* state, ae_int_t n, ae_state *_state) { ae_int_t i; if( state->needf||state->needfg ) { state->f = (double)(0); } for(i=0; i<=n-1; i++) { if( state->needf||state->needfg ) { state->f = state->f+ae_sqr((double)(i*i+1), _state)*ae_sqr(state->x.ptr.p_double[i], _state); } if( state->needfg ) { state->g.ptr.p_double[i] = ae_sqr((double)(i*i+1), _state)*2*state->x.ptr.p_double[i]; } } } /************************************************************************* Calculate test function f(x) = 0.5*(x-x0)'*A*(x-x0), A = D+V'*Vd*V *************************************************************************/ static void testmincgunit_calclowrank(mincgstate* state, ae_int_t n, ae_int_t vcnt, /* Real */ ae_vector* d, /* Real */ ae_matrix* v, /* Real */ ae_vector* vd, /* Real */ ae_vector* x0, ae_state *_state) { ae_int_t i; ae_int_t j; double dx; double t; double t2; state->f = (double)(0); for(i=0; i<=n-1; i++) { state->g.ptr.p_double[i] = (double)(0); } for(i=0; i<=n-1; i++) { dx = state->x.ptr.p_double[i]-x0->ptr.p_double[i]; state->f = state->f+0.5*dx*d->ptr.p_double[i]*dx; state->g.ptr.p_double[i] = state->g.ptr.p_double[i]+d->ptr.p_double[i]*dx; } for(i=0; i<=vcnt-1; i++) { t = (double)(0); for(j=0; j<=n-1; j++) { t = t+v->ptr.pp_double[i][j]*(state->x.ptr.p_double[j]-x0->ptr.p_double[j]); } state->f = state->f+0.5*t*vd->ptr.p_double[i]*t; t2 = t*vd->ptr.p_double[i]; ae_v_addd(&state->g.ptr.p_double[0], 1, &v->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), t2); } } /************************************************************************* This function tests preconditioning On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmincgunit_testpreconditioning(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t n; ae_vector x; ae_vector x0; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t vs; ae_matrix v; ae_vector vd; ae_vector d; ae_vector s; ae_int_t cntb1; ae_int_t cntg1; ae_int_t cntb2; ae_int_t cntg2; double epsg; ae_vector diagh; mincgstate state; mincgreport rep; ae_int_t cgtype; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_vector_init(&vd, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&diagh, 0, DT_REAL, _state); _mincgstate_init(&state, _state); _mincgreport_init(&rep, _state); k = 50; epsg = 1.0E-10; for(cgtype=-1; cgtype<=1; cgtype++) { /* * Preconditioner test 1. * * If * * B1 is default preconditioner * * G1 is diagonal precomditioner based on approximate diagonal of Hessian matrix * then "bad" preconditioner is worse than "good" one. * "Worse" means more iterations to converge. * * * We test it using f(x) = sum( ((i*i+1)*x[i])^2, i=0..N-1). * * N - problem size * K - number of repeated passes (should be large enough to average out random factors) */ for(n=10; n<=15; n++) { ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(0); } mincgcreate(n, &x, &state, _state); mincgsetcgtype(&state, cgtype, _state); /* * Test it with default preconditioner */ mincgsetprecdefault(&state, _state); cntb1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_calciip2(&state, n, _state); } mincgresults(&state, &x, &rep, _state); cntb1 = cntb1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Test it with perturbed diagonal preconditioner */ ae_vector_set_length(&diagh, n, _state); for(i=0; i<=n-1; i++) { diagh.ptr.p_double[i] = 2*ae_sqr((double)(i*i+1), _state)*(0.8+0.4*ae_randomreal(_state)); } mincgsetprecdiag(&state, &diagh, _state); cntg1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_calciip2(&state, n, _state); } mincgresults(&state, &x, &rep, _state); cntg1 = cntg1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Compare */ *err = *err||cntb10 ) { ae_matrix_set_length(&v, vs, n, _state); ae_vector_set_length(&vd, vs, _state); for(i=0; i<=vs-1; i++) { for(j=0; j<=n-1; j++) { v.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } vd.ptr.p_double[i] = ae_exp(2*ae_randomreal(_state), _state); } } mincgcreate(n, &x, &state, _state); mincgsetcgtype(&state, cgtype, _state); /* * Test it with default preconditioner */ mincgsetprecdefault(&state, _state); cntb1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_calclowrank(&state, n, vs, &d, &v, &vd, &x0, _state); } mincgresults(&state, &x, &rep, _state); cntb1 = cntb1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Test it with low rank preconditioner */ mincgsetpreclowrankfast(&state, &d, &vd, &v, vs, _state); cntg1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mincgrestartfrom(&state, &x, _state); while(mincgiteration(&state, _state)) { testmincgunit_calclowrank(&state, n, vs, &d, &v, &vd, &x0, _state); } mincgresults(&state, &x, &rep, _state); cntg1 = cntg1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Compare */ *err = *err||cntb1=1&&functype<=3, "FuncDeriv: incorrect funcType(funcType<1 or funcType>3).", _state); if( functype==1 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2, _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x2); return; } if( functype==2 ) { *f = a*ae_sqr(ae_sin(x->ptr.p_double[0]-x0, _state), _state)+b*ae_sqr(ae_sin(x->ptr.p_double[1]-x1, _state), _state)+c*ae_sqr(ae_sin(x->ptr.p_double[2]-x2, _state), _state)+d; g->ptr.p_double[0] = 2*a*ae_sin(x->ptr.p_double[0]-x0, _state)*ae_cos(x->ptr.p_double[0]-x0, _state); g->ptr.p_double[1] = 2*b*ae_sin(x->ptr.p_double[1]-x1, _state)*ae_cos(x->ptr.p_double[1]-x1, _state); g->ptr.p_double[2] = 2*c*ae_sin(x->ptr.p_double[2]-x2, _state)*ae_cos(x->ptr.p_double[2]-x2, _state); return; } if( functype==3 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2-(x->ptr.p_double[0]-x0), _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0)+2*c*(x->ptr.p_double[0]-x->ptr.p_double[2]-x0+x2); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x->ptr.p_double[0]-x2+x0); return; } } static void testminbleicunit_calciip2(minbleicstate* state, ae_int_t n, ae_int_t fk, ae_state *_state); static void testminbleicunit_testfeasibility(ae_bool* feaserr, ae_bool* converr, ae_bool* interr, ae_state *_state); static void testminbleicunit_testother(ae_bool* err, ae_state *_state); static void testminbleicunit_testconv(ae_bool* err, ae_state *_state); static void testminbleicunit_testpreconditioning(ae_bool* err, ae_state *_state); static void testminbleicunit_setrandompreconditioner(minbleicstate* state, ae_int_t n, ae_int_t preckind, ae_state *_state); static void testminbleicunit_testgradientcheck(ae_bool* testg, ae_state *_state); static void testminbleicunit_testbugs(ae_bool* err, ae_state *_state); static void testminbleicunit_funcderiv(double a, double b, double c, double d, double x0, double x1, double x2, /* Real */ ae_vector* x, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state); ae_bool testminbleic(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool feasibilityerrors; ae_bool othererrors; ae_bool precerrors; ae_bool interrors; ae_bool converrors; ae_bool graderrors; ae_bool bugs; ae_bool result; waserrors = ae_false; feasibilityerrors = ae_false; othererrors = ae_false; precerrors = ae_false; interrors = ae_false; converrors = ae_false; graderrors = ae_false; bugs = ae_false; testminbleicunit_testfeasibility(&feasibilityerrors, &converrors, &interrors, _state); testminbleicunit_testother(&othererrors, _state); testminbleicunit_testconv(&converrors, _state); testminbleicunit_testbugs(&bugs, _state); testminbleicunit_testpreconditioning(&precerrors, _state); testminbleicunit_testgradientcheck(&graderrors, _state); /* * end */ waserrors = (((((feasibilityerrors||othererrors)||converrors)||interrors)||precerrors)||graderrors)||bugs; if( !silent ) { printf("TESTING BLEIC OPTIMIZATION\n"); printf("FEASIBILITY PROPERTIES: "); if( feasibilityerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("PRECONDITIONING: "); if( precerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("OTHER PROPERTIES: "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CONVERGENCE PROPERTIES: "); if( converrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("INTERNAL ERRORS: "); if( interrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST FOR VERIFICATION OF THE GRADIENT: "); if( graderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("FIXED BUGS: "); if( bugs ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminbleic(ae_bool silent, ae_state *_state) { return testminbleic(silent, _state); } /************************************************************************* Calculate test function IIP2 f(x) = sum( ((i*i+1)^FK*x[i])^2, i=0..N-1) It has high condition number which makes fast convergence unlikely without good preconditioner. *************************************************************************/ static void testminbleicunit_calciip2(minbleicstate* state, ae_int_t n, ae_int_t fk, ae_state *_state) { ae_int_t i; if( state->needfg ) { state->f = (double)(0); } for(i=0; i<=n-1; i++) { if( state->needfg ) { state->f = state->f+ae_pow((double)(i*i+1), (double)(2*fk), _state)*ae_sqr(state->x.ptr.p_double[i], _state); state->g.ptr.p_double[i] = ae_pow((double)(i*i+1), (double)(2*fk), _state)*2*state->x.ptr.p_double[i]; } } } /************************************************************************* This function test feasibility properties. It launches a sequence of problems and examines their solutions. Most of the attention is directed towards feasibility properties, although we make some quick checks to ensure that actual solution is found. On failure sets FeasErr (or ConvErr, depending on failure type) to True, or leaves it unchanged otherwise. IntErr is set to True on internal errors (errors in the control flow). *************************************************************************/ static void testminbleicunit_testfeasibility(ae_bool* feaserr, ae_bool* converr, ae_bool* interr, ae_state *_state) { ae_frame _frame_block; ae_int_t pkind; ae_int_t preckind; ae_int_t passcount; ae_int_t pass; ae_int_t n; ae_int_t nmax; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t p; double v; double v2; double v3; double vv; ae_vector bl; ae_vector bu; ae_vector x; ae_vector g; ae_vector x0; ae_vector xc; ae_vector xs; ae_vector svdw; ae_matrix c; ae_matrix svdu; ae_matrix svdvt; ae_vector ct; minbleicstate state; double epsx; double epsg; double epsfeas; double weakepsg; minbleicreport rep; ae_int_t dkind; double diffstep; ae_frame_make(_state, &_frame_block); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&xs, 0, DT_REAL, _state); ae_vector_init(&svdw, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&svdu, 0, 0, DT_REAL, _state); ae_matrix_init(&svdvt, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minbleicstate_init(&state, _state); _minbleicreport_init(&rep, _state); nmax = 5; epsg = 1.0E-8; weakepsg = 1.0E-4; epsx = 1.0E-4; epsfeas = 1.0E-6; passcount = 10; for(pass=1; pass<=passcount; pass++) { /* * Test problem 1: * * no boundary and inequality constraints * * randomly generated plane as equality constraint * * random point (not necessarily on the plane) * * f = |x|^P, P = {2, 4} is used as target function * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * either analytic gradient or numerical differentiation are used * * we check that after work is over we are on the plane and * that we are in the stationary point of constrained F */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { /* * Generate X, BL, BU, CT and left part of C. * * Right part of C is generated using somewhat complex algo: * * we generate random vector and multiply it by C. * * result is used as the right part. * * calculations are done on the fly, vector itself is not stored * We use such algo to be sure that our system is consistent. */ p = 2*pkind; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&g, n, _state); ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); c.ptr.pp_double[0][n] = (double)(0); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; c.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; v = 2*ae_randomreal(_state)-1; c.ptr.pp_double[0][n] = c.ptr.pp_double[0][n]+c.ptr.pp_double[0][i]*v; } ct.ptr.p_int[0] = 0; /* * Create and optimize */ if( dkind==0 ) { minbleiccreate(n, &x, &state, _state); } if( dkind==1 ) { minbleiccreatef(n, &x, diffstep, &state, _state); } minbleicsetlc(&state, &c, &ct, 1, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_pow(state.x.ptr.p_double[i], (double)(p), _state); } if( state.needfg ) { state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i], (double)(p-1), _state); } } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * Test feasibility of solution */ v = ae_v_dotproduct(&c.ptr.pp_double[0][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); *feaserr = *feaserr||ae_fp_greater(ae_fabs(v-c.ptr.pp_double[0][n], _state),epsfeas); /* * if C is nonzero, test that result is * a stationary point of constrained F. * * NOTE: this check is done only if C is nonzero */ vv = ae_v_dotproduct(&c.ptr.pp_double[0][0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); if( ae_fp_neq(vv,(double)(0)) ) { /* * Calculate gradient at the result * Project gradient into C * Check projected norm */ for(i=0; i<=n-1; i++) { g.ptr.p_double[i] = p*ae_pow(x.ptr.p_double[i], (double)(p-1), _state); } v2 = ae_v_dotproduct(&c.ptr.pp_double[0][0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&c.ptr.pp_double[0][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = v/v2; ae_v_subd(&g.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1), vv); v3 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); *converr = *converr||ae_fp_greater(ae_sqrt(v3, _state),weakepsg); } } } } } /* * Test problem 2 (multiple equality constraints): * * 1<=N<=NMax, 1<=K<=N * * no boundary constraints * * N-dimensional space * * randomly generated point xs * * K randomly generated hyperplanes which all pass through xs * define K equality constraints: (a[k],x)=b[k] * * equality constraints are checked for being well conditioned * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * f(x) = |x-x0|^2, x0 = xs+a[0] * * either analytic gradient or numerical differentiation are used * * extremum of f(x) is exactly xs because: * * xs is the closest point in the plane defined by (a[0],x)=b[0] * * xs is feasible by definition */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { for(preckind=0; preckind<=2; preckind++) { for(n=2; n<=nmax; n++) { for(k=1; k<=n; k++) { /* * Generate X, X0, XS, BL, BU, CT and left part of C. * * Right part of C is generated using somewhat complex algo: * * we generate random vector and multiply it by C. * * result is used as the right part. * * calculations are done on the fly, vector itself is not stored * We use such algo to be sure that our system is consistent. */ ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xs, n, _state); ae_vector_set_length(&g, n, _state); ae_matrix_set_length(&c, k, n+1, _state); ae_vector_set_length(&ct, k, _state); c.ptr.pp_double[0][n] = (double)(0); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xs.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } do { for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &xs.ptr.p_double[0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[i][n] = v; ct.ptr.p_int[i] = 0; } seterrorflag(feaserr, !rmatrixsvd(&c, k, n, 0, 0, 0, &svdw, &svdu, &svdvt, _state), _state); } while(!(ae_fp_greater(svdw.ptr.p_double[0],(double)(0))&&ae_fp_greater(svdw.ptr.p_double[k-1],0.001*svdw.ptr.p_double[0]))); ae_v_move(&x0.ptr.p_double[0], 1, &xs.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_add(&x0.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); /* * Create and optimize */ if( dkind==0 ) { minbleiccreate(n, &x, &state, _state); } if( dkind==1 ) { minbleiccreatef(n, &x, diffstep, &state, _state); } minbleicsetlc(&state, &c, &ct, k, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_sqr(state.x.ptr.p_double[i]-x0.ptr.p_double[i], _state); } if( state.needfg ) { state.g.ptr.p_double[i] = 2*(state.x.ptr.p_double[i]-x0.ptr.p_double[i]); } } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * check feasiblity properties */ for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); *feaserr = *feaserr||ae_fp_greater(ae_fabs(v-c.ptr.pp_double[i][n], _state),epsx); } /* * Compare with XS */ v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(x.ptr.p_double[i]-xs.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); *converr = *converr||ae_fp_greater(ae_fabs(v, _state),0.001); } } } } /* * Another simple problem: * * bound constraints 0 <= x[i] <= 1 * * no linear constraints * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * with such simple boundaries and function it is easy to find * analytic form of solution: S[i] = bound(x0[i], 0, 1) * * we also check that both final solution and subsequent iterates * are strictly feasible */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = (double)(0); bu.ptr.p_double[i] = (double)(1); x.ptr.p_double[i] = ae_randomreal(_state); x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; } /* * Create and optimize */ if( dkind==0 ) { minbleiccreate(n, &x, &state, _state); } if( dkind==1 ) { minbleiccreatef(n, &x, diffstep, &state, _state); } minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p), _state); } if( state.needfg ) { state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state); } *feaserr = *feaserr||ae_fp_less(state.x.ptr.p_double[i],0.0); *feaserr = *feaserr||ae_fp_greater(state.x.ptr.p_double[i],1.0); } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * * compare solution with analytic one * * check feasibility */ v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_greater(x.ptr.p_double[i],(double)(0))&&ae_fp_less(x.ptr.p_double[i],(double)(1)) ) { v = v+ae_sqr(p*ae_pow(x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state), _state); } *feaserr = *feaserr||ae_fp_less(x.ptr.p_double[i],0.0); *feaserr = *feaserr||ae_fp_greater(x.ptr.p_double[i],1.0); } *converr = *converr||ae_fp_greater(ae_sqrt(v, _state),weakepsg); } } } } /* * Same as previous problem, but with minor modifications: * * some bound constraints are 0<=x[i]<=1, some are Ci=x[i]=Ci * * no linear constraints * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * with such simple boundaries and function it is easy to find * analytic form of solution: S[i] = bound(x0[i], 0, 1) * * we also check that both final solution and subsequent iterates * are strictly feasible */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_randomreal(_state),0.5) ) { bl.ptr.p_double[i] = (double)(0); bu.ptr.p_double[i] = (double)(1); } else { bl.ptr.p_double[i] = ae_randomreal(_state); bu.ptr.p_double[i] = bl.ptr.p_double[i]; } x.ptr.p_double[i] = ae_randomreal(_state); x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; } /* * Create and optimize */ if( dkind==0 ) { minbleiccreate(n, &x, &state, _state); } if( dkind==1 ) { minbleiccreatef(n, &x, diffstep, &state, _state); } minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p), _state); } if( state.needfg ) { state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state); } *feaserr = *feaserr||ae_fp_less(state.x.ptr.p_double[i],bl.ptr.p_double[i]); *feaserr = *feaserr||ae_fp_greater(state.x.ptr.p_double[i],bu.ptr.p_double[i]); } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * * compare solution with analytic one * * check feasibility */ v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_greater(x.ptr.p_double[i],bl.ptr.p_double[i])&&ae_fp_less(x.ptr.p_double[i],bu.ptr.p_double[i]) ) { v = v+ae_sqr(p*ae_pow(x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state), _state); } *feaserr = *feaserr||ae_fp_less(x.ptr.p_double[i],bl.ptr.p_double[i]); *feaserr = *feaserr||ae_fp_greater(x.ptr.p_double[i],bu.ptr.p_double[i]); } *converr = *converr||ae_fp_greater(ae_sqrt(v, _state),weakepsg); } } } } /* * Same as previous one, but with bound constraints posed * as general linear ones: * * no bound constraints * * 2*N linear constraints 0 <= x[i] <= 1 * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * with such simple constraints and function it is easy to find * analytic form of solution: S[i] = bound(x0[i], 0, 1). * * however, we can't guarantee that solution is strictly feasible * with respect to nonlinearity constraint, so we check * for approximate feasibility. */ for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state); x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; for(j=0; j<=n; j++) { c.ptr.pp_double[2*i+0][j] = (double)(0); c.ptr.pp_double[2*i+1][j] = (double)(0); } c.ptr.pp_double[2*i+0][i] = (double)(1); c.ptr.pp_double[2*i+0][n] = (double)(0); ct.ptr.p_int[2*i+0] = 1; c.ptr.pp_double[2*i+1][i] = (double)(1); c.ptr.pp_double[2*i+1][n] = (double)(1); ct.ptr.p_int[2*i+1] = -1; } /* * Create and optimize */ minbleiccreate(n, &x, &state, _state); minbleicsetlc(&state, &c, &ct, 2*n, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p), _state); state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state); } continue; } /* * Unknown protocol specified */ *interr = ae_true; ae_frame_leave(_state); return; } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * * compare solution with analytic one * * check feasibility */ v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_greater(x.ptr.p_double[i],0.02)&&ae_fp_less(x.ptr.p_double[i],0.98) ) { v = v+ae_sqr(p*ae_pow(x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state), _state); } *feaserr = *feaserr||ae_fp_less(x.ptr.p_double[i],0.0-epsfeas); *feaserr = *feaserr||ae_fp_greater(x.ptr.p_double[i],1.0+epsfeas); } *converr = *converr||ae_fp_greater(ae_sqrt(v, _state),weakepsg); } } } /* * Feasibility problem: * * bound constraints 0<=x[i]<=1 * * starting point xs with xs[i] in [-1,+2] * * random point xc from [0,1] is used to generate K<=N * random linear equality/inequality constraints of the form * (c,x-xc)=0.0 (or, alternatively, >= or <=), where * c is a random vector. * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * we do not know analytic form of the solution, and, if fact, we do not * check for solution correctness. We just check that algorithm converges * to the feasible points. */ for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { for(k=1; k<=n; k++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&xs, n, _state); ae_matrix_set_length(&c, k, n+1, _state); ae_vector_set_length(&ct, k, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; xs.ptr.p_double[i] = 3*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 0.1+0.8*ae_randomreal(_state); bl.ptr.p_double[i] = (double)(0); bu.ptr.p_double[i] = (double)(1); } for(i=0; i<=k-1; i++) { c.ptr.pp_double[i][n] = (double)(0); for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; c.ptr.pp_double[i][n] = c.ptr.pp_double[i][n]+c.ptr.pp_double[i][j]*xc.ptr.p_double[j]; } ct.ptr.p_int[i] = ae_randominteger(3, _state)-1; } /* * Create and optimize */ minbleiccreate(n, &xs, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, k, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p), _state); state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state); } continue; } /* * Unknown protocol specified */ *interr = ae_true; ae_frame_leave(_state); return; } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *converr = ae_true; ae_frame_leave(_state); return; } /* * Check feasibility */ for(i=0; i<=n-1; i++) { *feaserr = *feaserr||ae_fp_less(x.ptr.p_double[i],0.0); *feaserr = *feaserr||ae_fp_greater(x.ptr.p_double[i],1.0); } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-c.ptr.pp_double[i][n]; if( ct.ptr.p_int[i]==0 ) { *feaserr = *feaserr||ae_fp_greater(ae_fabs(v, _state),epsfeas); } if( ct.ptr.p_int[i]<0 ) { *feaserr = *feaserr||ae_fp_greater(v,epsfeas); } if( ct.ptr.p_int[i]>0 ) { *feaserr = *feaserr||ae_fp_less(v,-epsfeas); } } } } } } /* * Infeasible problem: * * all bound constraints are 0 <= x[i] <= 1 except for one * * that one is 0 >= x[i] >= 1 * * no linear constraints * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from detecting * infeasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * algorithm must return correct error code on such problem */ for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = (double)(0); bu.ptr.p_double[i] = (double)(1); x.ptr.p_double[i] = ae_randomreal(_state); x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; } i = ae_randominteger(n, _state); bl.ptr.p_double[i] = (double)(1); bu.ptr.p_double[i] = (double)(0); /* * Create and optimize */ minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p), _state); state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i]-x0.ptr.p_double[i], (double)(p-1), _state); } continue; } /* * Unknown protocol specified */ *interr = ae_true; ae_frame_leave(_state); return; } minbleicresults(&state, &x, &rep, _state); *feaserr = *feaserr||rep.terminationtype!=-3; } } } /* * Infeasible problem (2): * * no bound and inequality constraints * * 1<=K<=N arbitrary equality constraints * * (K+1)th constraint which is equal to the first constraint a*x=c, * but with c:=c+1. I.e. we have both a*x=c and a*x=c+1, which can't * be true (other constraints may be inconsistent too, but we don't * have to check it). * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from detecting * infeasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x|^P, where P={2,4} * * algorithm must return correct error code on such problem */ for(preckind=0; preckind<=2; preckind++) { for(pkind=1; pkind<=2; pkind++) { for(n=1; n<=nmax; n++) { for(k=1; k<=n; k++) { /* * Generate X, BL, BU. */ p = 2*pkind; ae_vector_set_length(&x, n, _state); ae_matrix_set_length(&c, k+1, n+1, _state); ae_vector_set_length(&ct, k+1, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state); } for(i=0; i<=k-1; i++) { for(j=0; j<=n; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } ct.ptr.p_int[i] = 0; } ct.ptr.p_int[k] = 0; ae_v_move(&c.ptr.pp_double[k][0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[k][n] = c.ptr.pp_double[0][n]+1; /* * Create and optimize */ minbleiccreate(n, &x, &state, _state); minbleicsetlc(&state, &c, &ct, k+1, _state); minbleicsetcond(&state, weakepsg, 0.0, 0.0, 0, _state); testminbleicunit_setrandompreconditioner(&state, n, preckind, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_pow(state.x.ptr.p_double[i], (double)(p), _state); state.g.ptr.p_double[i] = p*ae_pow(state.x.ptr.p_double[i], (double)(p-1), _state); } continue; } /* * Unknown protocol specified */ *interr = ae_true; ae_frame_leave(_state); return; } minbleicresults(&state, &x, &rep, _state); *feaserr = *feaserr||rep.terminationtype!=-3; } } } } } ae_frame_leave(_state); } /************************************************************************* This function additional properties. On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testminbleicunit_testother(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t passcount; ae_int_t pass; ae_int_t n; ae_int_t nmax; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector bl; ae_vector bu; ae_vector x; ae_vector xf; ae_vector x0; ae_vector x1; ae_vector b; ae_vector xlast; ae_vector a; ae_vector s; ae_vector h; ae_matrix c; ae_matrix fulla; ae_vector ct; double fprev; double xprev; double stpmax; double v; ae_int_t pkind; ae_int_t ckind; ae_int_t mkind; double vc; double vm; minbleicstate state; double epsx; double epsg; double eps; double tmpeps; minbleicreport rep; double diffstep; ae_int_t dkind; ae_bool wasf; ae_bool wasfg; double r; hqrndstate rs; ae_int_t spoiliteration; ae_int_t stopiteration; ae_int_t spoilvar; double spoilval; double ss; ae_int_t stopcallidx; ae_int_t callidx; ae_int_t maxits; ae_bool terminationrequested; ae_frame_make(_state, &_frame_block); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xf, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&h, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minbleicstate_init(&state, _state); _minbleicreport_init(&rep, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); nmax = 5; epsx = 1.0E-4; epsg = 1.0E-8; passcount = 10; /* * Try to reproduce bug 570 (optimizer hangs on problems where it is required * to perform very small step - less than 1E-50 - in order to activate constraints). * * The problem being solved is: * * min x[0]+x[1]+...+x[n-1] * * subject to * * x[i]>=0, for i=0..n-1 * * with initial point * * x[0] = 1.0E-100, x[1]=x[2]=...=0.5 * * We try to reproduce this problem in different settings: * * boundary-only constraints - we test that completion code is positive, * and all x[] are EXACTLY zero * * boundary constraints posed as general linear ones - we test that * completion code is positive, and all x[] are APPROXIMATELY zero. */ n = 10; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_matrix_set_length(&c, n, n+1, _state); ae_vector_set_length(&ct, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 0.5; bl.ptr.p_double[i] = 0.0; bu.ptr.p_double[i] = _state->v_posinf; ct.ptr.p_int[i] = 1; for(j=0; j<=n; j++) { c.ptr.pp_double[i][j] = 0.0; } c.ptr.pp_double[i][i] = 1.0; } x.ptr.p_double[0] = 1.0E-100; minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, (double)(0), (double)(0), (double)(0), 2*n, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = 1.0; } } } minbleicresults(&state, &xf, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_neq(xf.ptr.p_double[i],(double)(0)), _state); } } minbleiccreate(n, &x, &state, _state); minbleicsetlc(&state, &c, &ct, n, _state); minbleicsetcond(&state, 1.0E-64, (double)(0), (double)(0), 10, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = 1.0; } } } minbleicresults(&state, &xf, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(xf.ptr.p_double[i], _state),1.0E-10), _state); } } /* * Test reports: * * first value must be starting point * * last value must be last point */ for(pass=1; pass<=passcount; pass++) { n = 50; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(10); bl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bu.ptr.p_double[i] = _state->v_posinf; } minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, 1.0E-64, (double)(0), (double)(0), 10, _state); minbleicsetxrep(&state, ae_true, _state); fprev = ae_maxrealnumber; while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_sqr((1+i)*state.x.ptr.p_double[i], _state); state.g.ptr.p_double[i] = 2*(1+i)*state.x.ptr.p_double[i]; } } if( state.xupdated ) { if( ae_fp_eq(fprev,ae_maxrealnumber) ) { for(i=0; i<=n-1; i++) { *err = *err||ae_fp_neq(state.x.ptr.p_double[i],x.ptr.p_double[i]); } } fprev = state.f; ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } minbleicresults(&state, &x, &rep, _state); for(i=0; i<=n-1; i++) { *err = *err||ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]); } } /* * Test differentiation vs. analytic gradient * (first one issues NeedF requests, second one issues NeedFG requests) */ for(pass=1; pass<=passcount; pass++) { n = 10; diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(1); } if( dkind==0 ) { minbleiccreate(n, &x, &state, _state); } if( dkind==1 ) { minbleiccreatef(n, &x, diffstep, &state, _state); } minbleicsetcond(&state, 1.0E-6, (double)(0), epsx, 0, _state); wasf = ae_false; wasfg = ae_false; while(minbleiciteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } for(i=0; i<=n-1; i++) { if( state.needf||state.needfg ) { state.f = state.f+ae_sqr((1+i)*state.x.ptr.p_double[i], _state); } if( state.needfg ) { state.g.ptr.p_double[i] = 2*(1+i)*state.x.ptr.p_double[i]; } } wasf = wasf||state.needf; wasfg = wasfg||state.needfg; } minbleicresults(&state, &x, &rep, _state); if( dkind==0 ) { *err = (*err||wasf)||!wasfg; } if( dkind==1 ) { *err = (*err||!wasf)||wasfg; } } } /* * Test that numerical differentiation uses scaling. * * In order to test that we solve simple optimization * problem: min(x^2) with initial x equal to 0.0. * * We choose random DiffStep and S, then we check that * optimizer evaluates function at +-DiffStep*S only. */ for(pass=1; pass<=passcount; pass++) { ae_vector_set_length(&x, 1, _state); ae_vector_set_length(&s, 1, _state); diffstep = ae_randomreal(_state)*1.0E-6; s.ptr.p_double[0] = ae_exp(ae_randomreal(_state)*4-2, _state); x.ptr.p_double[0] = (double)(0); minbleiccreatef(1, &x, diffstep, &state, _state); minbleicsetcond(&state, 1.0E-6, (double)(0), epsx, 0, _state); minbleicsetscale(&state, &s, _state); v = (double)(0); while(minbleiciteration(&state, _state)) { state.f = ae_sqr(state.x.ptr.p_double[0], _state); v = ae_maxreal(v, ae_fabs(state.x.ptr.p_double[0], _state), _state); } minbleicresults(&state, &x, &rep, _state); r = v/(s.ptr.p_double[0]*diffstep); *err = *err||ae_fp_greater(ae_fabs(ae_log(r, _state), _state),ae_log(1+1000*ae_machineepsilon, _state)); } /* * Test stpmax */ for(pass=1; pass<=passcount; pass++) { n = 1; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); x.ptr.p_double[0] = (double)(100); bl.ptr.p_double[0] = 2*ae_randomreal(_state)-1; bu.ptr.p_double[0] = _state->v_posinf; stpmax = 0.05+0.05*ae_randomreal(_state); minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, epsg, (double)(0), epsx, 0, _state); minbleicsetxrep(&state, ae_true, _state); minbleicsetstpmax(&state, stpmax, _state); xprev = x.ptr.p_double[0]; while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ae_exp(state.x.ptr.p_double[0], _state)+ae_exp(-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = ae_exp(state.x.ptr.p_double[0], _state)-ae_exp(-state.x.ptr.p_double[0], _state); *err = *err||ae_fp_greater(ae_fabs(state.x.ptr.p_double[0]-xprev, _state),(1+ae_sqrt(ae_machineepsilon, _state))*stpmax); } if( state.xupdated ) { *err = *err||ae_fp_greater(ae_fabs(state.x.ptr.p_double[0]-xprev, _state),(1+ae_sqrt(ae_machineepsilon, _state))*stpmax); xprev = state.x.ptr.p_double[0]; } } } /* * Ability to solve problems with function which is unbounded from below */ for(pass=1; pass<=passcount; pass++) { n = 1; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); bl.ptr.p_double[0] = 4*ae_randomreal(_state)+1; bu.ptr.p_double[0] = bl.ptr.p_double[0]+1; x.ptr.p_double[0] = 0.5*(bl.ptr.p_double[0]+bu.ptr.p_double[0]); minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetcond(&state, epsg, (double)(0), epsx, 0, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = -1.0E8*ae_sqr(state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = -2.0E8*state.x.ptr.p_double[0]; } } minbleicresults(&state, &x, &rep, _state); *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-bu.ptr.p_double[0], _state),epsx); } /* * Test correctness of the scaling: * * initial point is random point from [+1,+2]^N * * f(x) = SUM(A[i]*x[i]^4), C[i] is random from [0.01,100] * * function is EFFECTIVELY unconstrained; it has formal constraints, * but they are inactive at the solution; we try different variants * in order to explore different control paths of the optimizer: * 0) absense of constraints * 1) bound constraints -100000<=x[i]<=100000 * 2) one linear constraint 0*x=0 * 3) combination of (1) and (2) * * we use random scaling matrix * * we test different variants of the preconditioning: * 0) unit preconditioner * 1) random diagonal from [0.01,100] * 2) scale preconditioner * * we set very stringent stopping conditions * * and we test that in the extremum stopping conditions are * satisfied subject to the current scaling coefficients. */ for(pass=1; pass<=passcount; pass++) { tmpeps = 1.0E-5; for(n=1; n<=10; n++) { for(ckind=0; ckind<=3; ckind++) { for(pkind=0; pkind<=2; pkind++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&h, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); ct.ptr.p_int[0] = 0; c.ptr.pp_double[0][n] = (double)(0); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)+1; bl.ptr.p_double[i] = (double)(-100000); bu.ptr.p_double[i] = (double)(100000); c.ptr.pp_double[0][i] = (double)(0); a.ptr.p_double[i] = ae_exp(ae_log((double)(10), _state)*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_exp(ae_log((double)(10), _state)*(2*ae_randomreal(_state)-1), _state); h.ptr.p_double[i] = ae_exp(ae_log((double)(10), _state)*(2*ae_randomreal(_state)-1), _state); } minbleiccreate(n, &x, &state, _state); if( ckind==1||ckind==3 ) { minbleicsetbc(&state, &bl, &bu, _state); } if( ckind==2||ckind==3 ) { minbleicsetlc(&state, &c, &ct, 1, _state); } if( pkind==1 ) { minbleicsetprecdiag(&state, &h, _state); } if( pkind==2 ) { minbleicsetprecscale(&state, _state); } minbleicsetcond(&state, tmpeps, (double)(0), (double)(0), 0, _state); minbleicsetscale(&state, &s, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+a.ptr.p_double[i]*ae_sqr(state.x.ptr.p_double[i], _state); state.g.ptr.p_double[i] = 2*a.ptr.p_double[i]*state.x.ptr.p_double[i]; } } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } v = (double)(0); for(i=0; i<=n-1; i++) { v = v+ae_sqr(s.ptr.p_double[i]*2*a.ptr.p_double[i]*x.ptr.p_double[i], _state); } v = ae_sqrt(v, _state); seterrorflag(err, ae_fp_greater(v,tmpeps), _state); } } } } /* * Check correctness of the "trimming". * * Trimming is a technique which is used to help algorithm * cope with unbounded functions. In order to check this * technique we will try to solve following optimization * problem: * * min f(x) subject to no constraints on X * { 1/(1-x) + 1/(1+x) + c*x, if -0.999999=0.999999 * * where c is either 1.0 or 1.0E+4, M is either 1.0E8, 1.0E20 or +INF * (we try different combinations) */ for(pass=1; pass<=passcount; pass++) { for(ckind=0; ckind<=1; ckind++) { for(mkind=0; mkind<=2; mkind++) { /* * Choose c and M */ vc = (double)(1); vm = (double)(1); if( ckind==0 ) { vc = 1.0; } if( ckind==1 ) { vc = 1.0E+4; } if( mkind==0 ) { vm = 1.0E+8; } if( mkind==1 ) { vm = 1.0E+20; } if( mkind==2 ) { vm = _state->v_posinf; } /* * Create optimizer, solve optimization problem */ epsg = 1.0E-6*vc; ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = 0.0; minbleiccreate(1, &x, &state, _state); minbleicsetcond(&state, epsg, (double)(0), (double)(0), 0, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { if( ae_fp_less(-0.999999,state.x.ptr.p_double[0])&&ae_fp_less(state.x.ptr.p_double[0],0.999999) ) { state.f = 1/(1-state.x.ptr.p_double[0])+1/(1+state.x.ptr.p_double[0])+vc*state.x.ptr.p_double[0]; state.g.ptr.p_double[0] = 1/ae_sqr(1-state.x.ptr.p_double[0], _state)-1/ae_sqr(1+state.x.ptr.p_double[0], _state)+vc; } else { state.f = vm; state.g.ptr.p_double[0] = (double)(0); } } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } *err = *err||ae_fp_greater(ae_fabs(1/ae_sqr(1-x.ptr.p_double[0], _state)-1/ae_sqr(1+x.ptr.p_double[0], _state)+vc, _state),epsg); } } } /* * Test behaviour on noisy functions. * * Consider following problem: * * f(x,y) = (x+1)^2 + (y+1)^2 + 10000*MachineEpsilon*RandomReal() * * boundary constraints x>=0, y>=0 * * starting point (x0,y0)=(10*MachineEpsilon,1.0) * * Such problem contains small numerical noise. Without noise its * solution is (xs,ys)=(0,0), which is easy to find. However, presence * of the noise makes it hard to solve: * * noisy f(x,y) is monotonically decreasing only when we perform * steps orders of magnitude larger than 10000*MachineEpsilon * * at small scales f(x,y) is non-monotonic and non-convex * * however, our first step must be done towards * (x1,y1) = (0,1-some_small_value), and length of such step is * many times SMALLER than 10000*MachineEpsilon * * second step, from (x1,y1) to (xs,ys), will be large enough to * ignore numerical noise, so the only problem is to perform * first step * * Naive implementation of BLEIC should fail sometimes (sometimes - * due to non-deterministic nature of noise) on such problem. However, * our improved implementation should solve it correctly. We test * several variations of inner stopping criteria. */ for(pass=1; pass<=passcount; pass++) { eps = 1.0E-9; ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&bl, 2, _state); ae_vector_set_length(&bu, 2, _state); x.ptr.p_double[0] = 10*ae_machineepsilon; x.ptr.p_double[1] = 1.0; bl.ptr.p_double[0] = 0.0; bu.ptr.p_double[0] = _state->v_posinf; bl.ptr.p_double[1] = 0.0; bu.ptr.p_double[1] = _state->v_posinf; for(ckind=0; ckind<=2; ckind++) { minbleiccreate(2, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); if( ckind==0 ) { minbleicsetcond(&state, eps, (double)(0), (double)(0), 0, _state); } if( ckind==1 ) { minbleicsetcond(&state, (double)(0), eps, (double)(0), 0, _state); } if( ckind==2 ) { minbleicsetcond(&state, (double)(0), (double)(0), eps, 0, _state); } while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]+1, _state)+ae_sqr(state.x.ptr.p_double[1]+1, _state)+10000*ae_machineepsilon*ae_randomreal(_state); state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]+1); state.g.ptr.p_double[1] = 2*(state.x.ptr.p_double[1]+1); } } minbleicresults(&state, &xf, &rep, _state); if( (rep.terminationtype<=0||ae_fp_neq(xf.ptr.p_double[0],(double)(0)))||ae_fp_neq(xf.ptr.p_double[1],(double)(0)) ) { *err = ae_true; ae_frame_leave(_state); return; } } } /* * Deterministic variation of the previous problem. * * Consider following problem: * * boundary constraints x>=0, y>=0 * * starting point (x0,y0)=(10*MachineEpsilon,1.0) * / (x+1)^2 + (y+1)^2, for (x,y)<>(x0,y0) * * f(x,y) = | * \ (x+1)^2 + (y+1)^2 - 0.1, for (x,y)=(x0,y0) * * Such problem contains deterministic numerical noise (-0.1 at * starting point). Without noise its solution is easy to find. * However, presence of the noise makes it hard to solve: * * our first step must be done towards (x1,y1) = (0,1-some_small_value), * but such step will increase function valye by approximately 0.1 - * instead of decreasing it. * * Naive implementation of BLEIC should fail on such problem. However, * our improved implementation should solve it correctly. We test * several variations of inner stopping criteria. */ for(pass=1; pass<=passcount; pass++) { eps = 1.0E-9; ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&bl, 2, _state); ae_vector_set_length(&bu, 2, _state); x.ptr.p_double[0] = 10*ae_machineepsilon; x.ptr.p_double[1] = 1.0; bl.ptr.p_double[0] = 0.0; bu.ptr.p_double[0] = _state->v_posinf; bl.ptr.p_double[1] = 0.0; bu.ptr.p_double[1] = _state->v_posinf; for(ckind=0; ckind<=2; ckind++) { minbleiccreate(2, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); if( ckind==0 ) { minbleicsetcond(&state, eps, (double)(0), (double)(0), 0, _state); } if( ckind==1 ) { minbleicsetcond(&state, (double)(0), eps, (double)(0), 0, _state); } if( ckind==2 ) { minbleicsetcond(&state, (double)(0), (double)(0), eps, 0, _state); } while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]+1, _state)+ae_sqr(state.x.ptr.p_double[1]+1, _state); if( ae_fp_eq(state.x.ptr.p_double[0],x.ptr.p_double[0])&&ae_fp_eq(state.x.ptr.p_double[1],x.ptr.p_double[1]) ) { state.f = state.f-0.1; } state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]+1); state.g.ptr.p_double[1] = 2*(state.x.ptr.p_double[1]+1); } } minbleicresults(&state, &xf, &rep, _state); if( (rep.terminationtype<=0||ae_fp_neq(xf.ptr.p_double[0],(double)(0)))||ae_fp_neq(xf.ptr.p_double[1],(double)(0)) ) { *err = ae_true; ae_frame_leave(_state); return; } } } /* * Test integrity checks for NAN/INF: * * algorithm solves optimization problem, which is normal for some time (quadratic) * * after 5-th step we choose random component of gradient and consistently spoil * it by NAN or INF. * * we check that correct termination code is returned (-8) */ n = 100; for(pass=1; pass<=10; pass++) { spoiliteration = 5; stopiteration = 8; if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { /* * Gradient can be spoiled by +INF, -INF, NAN */ spoilvar = hqrnduniformi(&rs, n, _state); i = hqrnduniformi(&rs, 3, _state); spoilval = _state->v_nan; if( i==0 ) { spoilval = _state->v_neginf; } if( i==1 ) { spoilval = _state->v_posinf; } } else { /* * Function value can be spoiled only by NAN * (+INF can be recognized as legitimate value during optimization) */ spoilvar = -1; spoilval = _state->v_nan; } spdmatrixrndcond(n, 1.0E5, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } minbleiccreate(n, &x0, &state, _state); minbleicsetcond(&state, 0.0, 0.0, 0.0, stopiteration, _state); minbleicsetxrep(&state, ae_true, _state); k = -1; while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.f = state.f+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.g.ptr.p_double[i] = state.g.ptr.p_double[i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } if( k>=spoiliteration ) { if( spoilvar<0 ) { state.f = spoilval; } else { state.g.ptr.p_double[spoilvar] = spoilval; } } continue; } if( state.xupdated ) { inc(&k, _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minbleicresults(&state, &x1, &rep, _state); seterrorflag(err, rep.terminationtype!=-8, _state); } /* * Check algorithm ability to handle request for termination: * * to terminate with correct return code = 8 * * to return point which was "current" at the moment of termination * * NOTE: we solve problem with "corrupted" preconditioner which makes it hard * to converge in less than StopCallIdx iterations */ for(pass=1; pass<=50; pass++) { n = 3; ss = (double)(100); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6+ae_randomreal(_state); } ae_vector_set_length(&s, 3, _state); s.ptr.p_double[0] = 0.00001; s.ptr.p_double[1] = 0.00001; s.ptr.p_double[2] = 10000.0; stopcallidx = ae_randominteger(20, _state); maxits = 25; minbleiccreate(n, &x, &state, _state); minbleicsetcond(&state, (double)(0), (double)(0), (double)(0), maxits, _state); minbleicsetxrep(&state, ae_true, _state); minbleicsetprecdiag(&state, &s, _state); callidx = 0; terminationrequested = ae_false; ae_v_move(&xlast.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ss*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = 2*ss*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0])*(-1); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); if( callidx==stopcallidx ) { minbleicrequesttermination(&state, _state); terminationrequested = ae_true; } inc(&callidx, _state); continue; } if( state.xupdated ) { if( !terminationrequested ) { ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minbleicresults(&state, &x, &rep, _state); seterrorflag(err, rep.terminationtype!=8, _state); for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]), _state); } } ae_frame_leave(_state); } /************************************************************************* This function tests convergence properties. We solve several simple problems with different combinations of constraints On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testminbleicunit_testconv(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t passcount; ae_int_t pass; ae_vector bl; ae_vector bu; ae_vector x; ae_vector b; ae_vector tmp; ae_vector g; ae_vector xf; ae_vector xs0; ae_vector xs1; ae_matrix a; ae_matrix c; ae_matrix ce; ae_vector ct; ae_vector nonnegative; minbleicstate state; double epsg; double epsfeas; double tol; minbleicreport rep; snnlssolver nnls; ae_int_t m; ae_int_t n; ae_int_t k; ae_int_t i; ae_int_t j; double v; double vv; ae_int_t preckind; ae_int_t akind; ae_int_t shiftkind; ae_int_t bscale; double tolconstr; double f0; double f1; ae_int_t ccnt; hqrndstate rs; ae_frame_make(_state, &_frame_block); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&xf, 0, DT_REAL, _state); ae_vector_init(&xs0, 0, DT_REAL, _state); ae_vector_init(&xs1, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&ce, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&nonnegative, 0, DT_BOOL, _state); _minbleicstate_init(&state, _state); _minbleicreport_init(&rep, _state); _snnlssolver_init(&nnls, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); epsg = 1.0E-8; epsfeas = 1.0E-8; tol = 0.001; passcount = 10; /* * Three closely connected problems: * * 2-dimensional space * * octagonal area bounded by: * * -1<=x<=+1 * * -1<=y<=+1 * * x+y<=1.5 * * x-y<=1.5 * * -x+y<=1.5 * * -x-y<=1.5 * * several target functions: * * f0=x+0.001*y, minimum at x=-1, y=-0.5 * * f1=(x+10)^2+y^2, minimum at x=-1, y=0 * * f2=(x+10)^2+(y-0.6)^2, minimum at x=-1, y=0.5 */ ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&bl, 2, _state); ae_vector_set_length(&bu, 2, _state); ae_matrix_set_length(&c, 4, 3, _state); ae_vector_set_length(&ct, 4, _state); bl.ptr.p_double[0] = (double)(-1); bl.ptr.p_double[1] = (double)(-1); bu.ptr.p_double[0] = (double)(1); bu.ptr.p_double[1] = (double)(1); c.ptr.pp_double[0][0] = (double)(1); c.ptr.pp_double[0][1] = (double)(1); c.ptr.pp_double[0][2] = 1.5; ct.ptr.p_int[0] = -1; c.ptr.pp_double[1][0] = (double)(1); c.ptr.pp_double[1][1] = (double)(-1); c.ptr.pp_double[1][2] = 1.5; ct.ptr.p_int[1] = -1; c.ptr.pp_double[2][0] = (double)(-1); c.ptr.pp_double[2][1] = (double)(1); c.ptr.pp_double[2][2] = 1.5; ct.ptr.p_int[2] = -1; c.ptr.pp_double[3][0] = (double)(-1); c.ptr.pp_double[3][1] = (double)(-1); c.ptr.pp_double[3][2] = 1.5; ct.ptr.p_int[3] = -1; for(pass=1; pass<=passcount; pass++) { /* * f0 */ x.ptr.p_double[0] = 0.2*ae_randomreal(_state)-0.1; x.ptr.p_double[1] = 0.2*ae_randomreal(_state)-0.1; minbleiccreate(2, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, 4, _state); minbleicsetcond(&state, epsg, 0.0, 0.0, 0, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = state.x.ptr.p_double[0]+0.001*state.x.ptr.p_double[1]; state.g.ptr.p_double[0] = (double)(1); state.g.ptr.p_double[1] = 0.001; } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[0]+1, _state),tol); *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[1]+0.5, _state),tol); } else { *err = ae_true; } /* * f1 */ x.ptr.p_double[0] = 0.2*ae_randomreal(_state)-0.1; x.ptr.p_double[1] = 0.2*ae_randomreal(_state)-0.1; minbleiccreate(2, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, 4, _state); minbleicsetcond(&state, epsg, 0.0, 0.0, 0, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]+10, _state)+ae_sqr(state.x.ptr.p_double[1], _state); state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]+10); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[0]+1, _state),tol); *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),tol); } else { *err = ae_true; } /* * f2 */ x.ptr.p_double[0] = 0.2*ae_randomreal(_state)-0.1; x.ptr.p_double[1] = 0.2*ae_randomreal(_state)-0.1; minbleiccreate(2, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, 4, _state); minbleicsetcond(&state, epsg, 0.0, 0.0, 0, _state); while(minbleiciteration(&state, _state)) { if( state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]+10, _state)+ae_sqr(state.x.ptr.p_double[1]-0.6, _state); state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]+10); state.g.ptr.p_double[1] = 2*(state.x.ptr.p_double[1]-0.6); } } minbleicresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[0]+1, _state),tol); *err = *err||ae_fp_greater(ae_fabs(x.ptr.p_double[1]-0.5, _state),tol); } else { *err = ae_true; } } /* * Degenerate optimization problem with excessive constraints. * * * N=3..10, M=N div 3, K = 2*N * * f(x) = 0.5*|A*x-b|^2, where A is MxN random matrix, b is Mx1 random vector * * bound constraint: * a) Ci=x[i]=Ci for i=0..M-1 * b) 0<=x[i]<=1 for i=M..N-1 * * linear constraints (for fixed feasible xf and random ai): * a) ai*x = ai*xf for i=0..M-1 * b) ai*x <= ai*xf+random(0.1,1.0) for i=M..K-1 * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from detecting * infeasible point): * a) unit preconditioner * b) random diagonal-based preconditioner * c) random scale-based preconditioner * * we choose two random initial points from interior of the area * given by bound constraints. * * We do not know analytic solution of this problem, and we do not need * to solve it :) we just perform two restarts from two different initial * points and check that both solutions give approximately same function * value. */ for(preckind=0; preckind<=2; preckind++) { for(n=3; n<=10; n++) { /* * Generate problem */ m = n/3; k = 2*n; ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xs0, n, _state); ae_vector_set_length(&xs1, n, _state); ae_vector_set_length(&xf, n, _state); for(i=0; i<=n-1; i++) { if( i=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } if( akind==2 ) { /* * Dense well conditioned indefinite */ smatrixrndcond(n, 50.0, &a, _state); } if( akind==3 ) { /* * Low rank */ ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(k=1; k<=ae_minint(3, n-1, _state); k++) { for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = hqrndnormal(&rs, _state); } v = hqrndnormal(&rs, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+v*tmp.ptr.p_double[i]*tmp.ptr.p_double[j]; } } } } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_round(ae_pow((double)(2), (double)(n), _state), _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = -1; k = i; c.ptr.pp_double[i][n] = ae_sign((double)(shiftkind), _state)*ae_pow((double)(10), ae_fabs((double)(shiftkind), _state), _state)*ae_machineepsilon; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = (double)(2*(k%2)-1); c.ptr.pp_double[i][n] = c.ptr.pp_double[i][n]+c.ptr.pp_double[i][j]*c.ptr.pp_double[i][j]; k = k/2; } } /* * Create and optimize */ minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, ccnt, _state); minbleicsetcond(&state, 1.0E-9, 0.0, 0.0, 0, _state); while(minbleiciteration(&state, _state)) { ae_assert(state.needfg, "Assertion failed", _state); state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.x.ptr.p_double[i]*b.ptr.p_double[i]; state.g.ptr.p_double[i] = b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.f = state.f+0.5*state.x.ptr.p_double[i]*v; state.g.ptr.p_double[i] = state.g.ptr.p_double[i]+v; } } minbleicresults(&state, &xs0, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( *err ) { ae_frame_leave(_state); return; } /* * Evaluate gradient at solution and test */ vv = 0.0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+b.ptr.p_double[i]; if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr)&&ae_fp_greater(v,(double)(0)) ) { v = 0.0; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr)&&ae_fp_less(v,(double)(0)) ) { v = 0.0; } vv = vv+ae_sqr(v, _state); } vv = ae_sqrt(vv, _state); seterrorflag(err, ae_fp_greater(vv,1.0E-5), _state); } } } } /* * Convex/nonconvex optimization problem with combination of * box and linear constraints: * * * N=2..8 * * f = 0.5*x'*A*x+b'*x * * b has normally distributed entries with scale 10^BScale * * several kinds of A are tried: zero, well conditioned SPD, * well conditioned indefinite, low rank * * box constraints: x[i] in [-1,+1] * * initial point x0 = [0 0 ... 0 0] * * CCnt=min(3,N-1) general linear constraints of form (c,x)=0. * random mix of equality/inequality constraints is tried. * x0 is guaranteed to be feasible. * * We check that constrained gradient is close to zero at solution. * Inequality constraint is considered active if distance to boundary * is less than TolConstr. We use nonnegative least squares solver * in order to compute constrained gradient. */ tolconstr = 1.0E-8; for(n=2; n<=8; n++) { for(akind=0; akind<=3; akind++) { for(bscale=0; bscale>=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = 0.0; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } if( akind==2 ) { /* * Dense well conditioned indefinite */ smatrixrndcond(n, 50.0, &a, _state); } if( akind==3 ) { /* * Low rank */ ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(k=1; k<=ae_minint(3, n-1, _state); k++) { for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = hqrndnormal(&rs, _state); } v = hqrndnormal(&rs, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+v*tmp.ptr.p_double[i]*tmp.ptr.p_double[j]; } } } } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_minint(3, n-1, _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = hqrnduniformi(&rs, 3, _state)-1; c.ptr.pp_double[i][n] = 0.0; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } /* * Create and optimize */ minbleiccreate(n, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, ccnt, _state); minbleicsetcond(&state, 1.0E-9, 0.0, 0.0, 0, _state); while(minbleiciteration(&state, _state)) { ae_assert(state.needfg, "Assertion failed", _state); state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.x.ptr.p_double[i]*b.ptr.p_double[i]; state.g.ptr.p_double[i] = b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.f = state.f+0.5*state.x.ptr.p_double[i]*v; state.g.ptr.p_double[i] = state.g.ptr.p_double[i]+v; } } minbleicresults(&state, &xs0, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( *err ) { ae_frame_leave(_state); return; } /* * 1. evaluate unconstrained gradient at solution * * 2. calculate constrained gradient (NNLS solver is used * to evaluate gradient subject to active constraints). * In order to do this we form CE matrix, matrix of active * constraints (columns store constraint vectors). Then * we try to approximate gradient vector by columns of CE, * subject to non-negativity restriction placed on variables * corresponding to inequality constraints. * * Residual from such regression is a constrained gradient vector. */ ae_vector_set_length(&g, n, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); g.ptr.p_double[i] = v+b.ptr.p_double[i]; } ae_matrix_set_length(&ce, n, n+ccnt, _state); ae_vector_set_length(&nonnegative, n+ccnt, _state); k = 0; for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_less(xs0.ptr.p_double[i],bl.ptr.p_double[i]), _state); seterrorflag(err, ae_fp_greater(xs0.ptr.p_double[i],bu.ptr.p_double[i]), _state); if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = 1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = -1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } for(i=0; i<=ccnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-c.ptr.pp_double[i][n]; seterrorflag(err, ct.ptr.p_int[i]==0&&ae_fp_greater(ae_fabs(v, _state),tolconstr), _state); seterrorflag(err, ct.ptr.p_int[i]>0&&ae_fp_less(v,-tolconstr), _state); seterrorflag(err, ct.ptr.p_int[i]<0&&ae_fp_greater(v,tolconstr), _state); if( ct.ptr.p_int[i]==0 ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_false; inc(&k, _state); continue; } if( (ct.ptr.p_int[i]>0&&ae_fp_less_eq(v,tolconstr))||(ct.ptr.p_int[i]<0&&ae_fp_greater_eq(v,-tolconstr)) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = ae_sign((double)(ct.ptr.p_int[i]), _state)*c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } snnlsinit(0, 0, 0, &nnls, _state); snnlssetproblem(&nnls, &ce, &g, 0, k, n, _state); for(i=0; i<=k-1; i++) { if( !nonnegative.ptr.p_bool[i] ) { snnlsdropnnc(&nnls, i, _state); } } snnlssolve(&nnls, &tmp, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { g.ptr.p_double[j] = g.ptr.p_double[j]-tmp.ptr.p_double[i]*ce.ptr.pp_double[j][i]; } } vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = ae_sqrt(vv, _state); seterrorflag(err, ae_fp_greater(vv,1.0E-5), _state); } } } ae_frame_leave(_state); } /************************************************************************* This function tests preconditioning On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testminbleicunit_testpreconditioning(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t n; ae_vector x; ae_vector x0; ae_int_t i; ae_int_t k; ae_matrix v; ae_matrix c; ae_vector ct; ae_vector bl; ae_vector bu; ae_vector vd; ae_vector d; ae_vector units; ae_vector s; ae_int_t cntb1; ae_int_t cntb2; ae_int_t cntg1; ae_int_t cntg2; double epsg; ae_vector diagh; minbleicstate state; minbleicreport rep; ae_int_t ckind; ae_int_t fk; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&vd, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&units, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&diagh, 0, DT_REAL, _state); _minbleicstate_init(&state, _state); _minbleicreport_init(&rep, _state); /* * Preconditioner test 1. * * If * * B1 is default preconditioner with unit scale * * G1 is diagonal preconditioner based on approximate diagonal of Hessian matrix * * B2 is default preconditioner with non-unit scale S[i]=1/sqrt(h[i]) * * G2 is scale-based preconditioner with non-unit scale S[i]=1/sqrt(h[i]) * then B1 is worse than G1, B2 is worse than G2. * "Worse" means more iterations to converge. * * Test problem setup: * * f(x) = sum( ((i*i+1)*x[i])^2, i=0..N-1) * * constraints: * 0) absent * 1) boundary only * 2) linear equality only * 3) combination of boundary and linear equality constraints * * N - problem size * K - number of repeated passes (should be large enough to average out random factors) */ k = 100; epsg = 1.0E-8; for(n=10; n<=10; n++) { for(ckind=0; ckind<=3; ckind++) { fk = 1; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&units, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(0); units.ptr.p_double[i] = (double)(1); } minbleiccreate(n, &x, &state, _state); minbleicsetcond(&state, epsg, 0.0, 0.0, 0, _state); if( ckind==1||ckind==3 ) { ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = (double)(-1); bu.ptr.p_double[i] = (double)(1); } minbleicsetbc(&state, &bl, &bu, _state); } if( ckind==2||ckind==3 ) { ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); ct.ptr.p_int[0] = ae_randominteger(3, _state)-1; for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; } c.ptr.pp_double[0][n] = (double)(0); minbleicsetlc(&state, &c, &ct, 1, _state); } /* * Test it with default preconditioner VS. perturbed diagonal preconditioner */ minbleicsetprecdefault(&state, _state); minbleicsetscale(&state, &units, _state); cntb1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minbleicrestartfrom(&state, &x, _state); while(minbleiciteration(&state, _state)) { testminbleicunit_calciip2(&state, n, fk, _state); } minbleicresults(&state, &x, &rep, _state); cntb1 = cntb1+rep.inneriterationscount; *err = *err||rep.terminationtype<=0; } ae_vector_set_length(&diagh, n, _state); for(i=0; i<=n-1; i++) { diagh.ptr.p_double[i] = 2*ae_pow((double)(i*i+1), (double)(2*fk), _state)*(0.8+0.4*ae_randomreal(_state)); } minbleicsetprecdiag(&state, &diagh, _state); minbleicsetscale(&state, &units, _state); cntg1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minbleicrestartfrom(&state, &x, _state); while(minbleiciteration(&state, _state)) { testminbleicunit_calciip2(&state, n, fk, _state); } minbleicresults(&state, &x, &rep, _state); cntg1 = cntg1+rep.inneriterationscount; *err = *err||rep.terminationtype<=0; } *err = *err||cntb1v_neginf; } infcomp = ae_randominteger(n+1, _state); if( infcompv_posinf; } minbleiccreate(n, &x, &state, _state); minbleicsetgradientcheck(&state, teststep, _state); minbleicsetbc(&state, &bl, &bu, _state); /* * Check that the criterion passes a derivative if it is correct */ while(minbleiciteration(&state, _state)) { if( state.needfg ) { /* * Check that .X within the boundaries */ for(i=0; i<=n-1; i++) { if( (ae_isfinite(bl.ptr.p_double[i], _state)&&ae_fp_less(state.x.ptr.p_double[i],bl.ptr.p_double[i]))||(ae_isfinite(bu.ptr.p_double[i], _state)&&ae_fp_greater(state.x.ptr.p_double[i],bu.ptr.p_double[i])) ) { *testg = ae_true; ae_frame_leave(_state); return; } } testminbleicunit_funcderiv(a, b, c, d, x0, x1, x2, &state.x, func, &state.f, &state.g, _state); } } minbleicresults(&state, &x, &rep, _state); /* * Check that error code does not equal to -7 and parameter .VarIdx * equal to -1. */ if( rep.terminationtype==-7||rep.varidx!=-1 ) { *testg = ae_true; ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 5*randomnormal(_state); } minbleicrestartfrom(&state, &x, _state); /* * Check that the criterion does not miss a derivative if * it is incorrect */ while(minbleiciteration(&state, _state)) { if( state.needfg ) { for(i=0; i<=n-1; i++) { if( (ae_isfinite(bl.ptr.p_double[i], _state)&&ae_fp_less(state.x.ptr.p_double[i],bl.ptr.p_double[i]))||(ae_isfinite(bu.ptr.p_double[i], _state)&&ae_fp_greater(state.x.ptr.p_double[i],bu.ptr.p_double[i])) ) { *testg = ae_true; ae_frame_leave(_state); return; } } testminbleicunit_funcderiv(a, b, c, d, x0, x1, x2, &state.x, func, &state.f, &state.g, _state); state.g.ptr.p_double[nbrcomp] = state.g.ptr.p_double[nbrcomp]+noise; } } minbleicresults(&state, &x, &rep, _state); /* * Check that error code equal to -7 and parameter .VarIdx * equal to number of incorrect component. */ if( rep.terminationtype!=-7||rep.varidx!=nbrcomp ) { *testg = ae_true; ae_frame_leave(_state); return; } } *testg = ae_false; ae_frame_leave(_state); } /************************************************************************* This function tests problems which caused bugs in the past. On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testminbleicunit_testbugs(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t k; double v; ae_vector bl; ae_vector bu; ae_vector x; ae_vector x1; ae_vector h; ae_vector prior; ae_vector w; ae_matrix a; ae_matrix c; ae_matrix xy; ae_vector ct; minbleicstate state; minbleicreport rep; hqrndstate rs; ae_int_t pass; double tolx; double regterm; ae_int_t n; ae_int_t ckind; ae_frame_make(_state, &_frame_block); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&h, 0, DT_REAL, _state); ae_vector_init(&prior, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minbleicstate_init(&state, _state); _minbleicreport_init(&rep, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Reproduce situation: optimizer sometimes hangs when starts with * gradient orthogonal to the only linear constraint. In most cases * it is solved successfully, but sometimes leads to infinite loop * in one of the early optimizer versions. * * The problem is: * * f(x)= x'*x + c'*x * * linear constraint c'*x=0 * * initial point is x=0 * * there are two ways to choose coefficient vector c: * * its components can be long binary fractions * * or they can be either 0 or 1 * both ways test different scenarios for accumulation of rounding errors * * If test fails, it usually hangs */ tolx = 1.0E-10; for(pass=1; pass<=10; pass++) { for(ckind=0; ckind<=1; ckind++) { for(n=2; n<=10; n++) { ae_vector_set_length(&x, n, _state); ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 0.0; if( ckind==0 ) { c.ptr.pp_double[0][i] = ae_sqrt(hqrnduniformr(&rs, _state), _state); } else { c.ptr.pp_double[0][i] = (double)(hqrnduniformi(&rs, 2, _state)); } } c.ptr.pp_double[0][n] = 0.0; ct.ptr.p_int[0] = 0; minbleiccreate(n, &x, &state, _state); minbleicsetlc(&state, &c, &ct, 1, _state); minbleicsetcond(&state, 0.0, 0.0, 0.0, 99, _state); while(minbleiciteration(&state, _state)) { ae_assert(state.needfg, "Assertion failed", _state); if( state.needfg ) { state.f = 0.0; for(i=0; i<=n-1; i++) { state.f = state.f+ae_sqr(state.x.ptr.p_double[i], _state)+state.x.ptr.p_double[i]*c.ptr.pp_double[0][i]; state.g.ptr.p_double[i] = 2*state.x.ptr.p_double[i]+c.ptr.pp_double[0][i]; } } } minbleicresultsbuf(&state, &x1, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(x1.ptr.p_double[i], _state),tolx), _state); } } } } /* * Reproduce optimization problem which caused bugs (optimizer hangs) * when BLEIC was used from MCPD unit. We perform test on specific * 9-dimensional problem, no need to try general-case methods. * * This test hangs if bug is present. Thus, we do not test completion * code returned by optimizer - we just test that it was returned :) */ tolx = 1.0E-8; regterm = 1.0E-8; for(pass=1; pass<=1000; pass++) { /* * Prepare constraints: * * [0,1] box constraints on all variables * * 5 linear constraints, first one is random equality; * second one is random inequality; other ones are "sum-to-one" constraints * for x0-x2, x3-x5, x6-x8. */ ae_vector_set_length(&bl, 9, _state); ae_vector_set_length(&bu, 9, _state); for(i=0; i<=9-1; i++) { bl.ptr.p_double[i] = 0.0; bu.ptr.p_double[i] = 1.0; } ae_matrix_set_length(&c, 5, 10, _state); ae_vector_set_length(&ct, 5, _state); for(i=0; i<=1; i++) { c.ptr.pp_double[i][9] = (double)(0); for(j=0; j<=9-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; c.ptr.pp_double[i][9] = c.ptr.pp_double[i][9]+c.ptr.pp_double[i][j]*((double)1/(double)9); } } ct.ptr.p_int[0] = 0; ct.ptr.p_int[1] = 1; c.ptr.pp_double[1][9] = c.ptr.pp_double[1][9]-0.1; for(i=0; i<=3-1; i++) { for(k=0; k<=9-1; k++) { c.ptr.pp_double[2+i][k] = (double)(0); } for(k=0; k<=3-1; k++) { c.ptr.pp_double[2+i][k*3+i] = (double)(1); } c.ptr.pp_double[2+i][9] = 1.0; ct.ptr.p_int[2+i] = 0; } /* * Prepare weights */ ae_vector_set_length(&w, 3, _state); for(i=0; i<=w.cnt-1; i++) { w.ptr.p_double[i] = 1.0; } /* * Prepare preconditioner H */ ae_vector_set_length(&h, 9, _state); for(i=0; i<=h.cnt-1; i++) { h.ptr.p_double[i] = 1.0; } /* * Prepare prior value for regularization */ ae_vector_set_length(&prior, 9, _state); for(i=0; i<=prior.cnt-1; i++) { prior.ptr.p_double[i] = (double)(0); } prior.ptr.p_double[0] = 1.0; prior.ptr.p_double[4] = 1.0; prior.ptr.p_double[8] = 1.0; /* * Prepare dataset XY */ ae_matrix_set_length(&xy, 6, 3, _state); for(i=0; i<=xy.rows-1; i++) { for(j=0; j<=xy.cols-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } /* * Optimize */ ae_vector_set_length(&x, 9, _state); for(i=0; i<=9-1; i++) { x.ptr.p_double[i] = (double)1/(double)9; } minbleiccreate(9, &x, &state, _state); minbleicsetbc(&state, &bl, &bu, _state); minbleicsetlc(&state, &c, &ct, 5, _state); minbleicsetcond(&state, 0.0, 0.0, tolx, 0, _state); minbleicsetprecdiag(&state, &h, _state); while(minbleiciteration(&state, _state)) { ae_assert(state.needfg, "Assertion failed", _state); if( state.needfg ) { /* * Calculate regularization term */ state.f = 0.0; for(i=0; i<=9-1; i++) { state.f = state.f+regterm*ae_sqr(state.x.ptr.p_double[i]-prior.ptr.p_double[i], _state); state.g.ptr.p_double[i] = 2*regterm*(state.x.ptr.p_double[i]-prior.ptr.p_double[i]); } /* * calculate prediction error/gradient for K-th pair */ for(k=0; k<=xy.rows-2; k++) { for(i=0; i<=3-1; i++) { v = ae_v_dotproduct(&state.x.ptr.p_double[i*3], 1, &xy.ptr.pp_double[k][0], 1, ae_v_len(i*3,i*3+3-1)); state.f = state.f+ae_sqr(w.ptr.p_double[i]*(v-xy.ptr.pp_double[k+1][i]), _state); for(j=0; j<=3-1; j++) { state.g.ptr.p_double[i*3+j] = state.g.ptr.p_double[i*3+j]+2*w.ptr.p_double[i]*w.ptr.p_double[i]*(v-xy.ptr.pp_double[k+1][i])*xy.ptr.pp_double[k][j]; } } } } } minbleicresultsbuf(&state, &x, &rep, _state); } ae_frame_leave(_state); } /************************************************************************* This function return function value and it derivatives. Function dimension is 3. Function's list: * funcType=1: F(X)=A*(X-X0)^2+B*(Y-Y0)^2+C*(Z-Z0)^2+D; * funcType=2: F(X)=A*sin(X-X0)^2+B*sin(Y-Y0)^2+C*sin(Z-Z0)^2+D; * funcType=3: F(X)=A*(X-X0)^2+B*(Y-Y0)^2+C*((Z-Z0)-(X-X0))^2+D. *************************************************************************/ static void testminbleicunit_funcderiv(double a, double b, double c, double d, double x0, double x1, double x2, /* Real */ ae_vector* x, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state) { ae_assert(((ae_isfinite(a, _state)&&ae_isfinite(b, _state))&&ae_isfinite(c, _state))&&ae_isfinite(d, _state), "FuncDeriv: A, B, C or D contains NaN or Infinite.", _state); ae_assert((ae_isfinite(x0, _state)&&ae_isfinite(x1, _state))&&ae_isfinite(x2, _state), "FuncDeriv: X0, X1 or X2 contains NaN or Infinite.", _state); ae_assert(functype>=1&&functype<=3, "FuncDeriv: incorrect funcType(funcType<1 or funcType>3).", _state); if( functype==1 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2, _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x2); return; } if( functype==2 ) { *f = a*ae_sqr(ae_sin(x->ptr.p_double[0]-x0, _state), _state)+b*ae_sqr(ae_sin(x->ptr.p_double[1]-x1, _state), _state)+c*ae_sqr(ae_sin(x->ptr.p_double[2]-x2, _state), _state)+d; g->ptr.p_double[0] = 2*a*ae_sin(x->ptr.p_double[0]-x0, _state)*ae_cos(x->ptr.p_double[0]-x0, _state); g->ptr.p_double[1] = 2*b*ae_sin(x->ptr.p_double[1]-x1, _state)*ae_cos(x->ptr.p_double[1]-x1, _state); g->ptr.p_double[2] = 2*c*ae_sin(x->ptr.p_double[2]-x2, _state)*ae_cos(x->ptr.p_double[2]-x2, _state); return; } if( functype==3 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2-(x->ptr.p_double[0]-x0), _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0)+2*c*(x->ptr.p_double[0]-x->ptr.p_double[2]-x0+x2); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x->ptr.p_double[0]-x2+x0); return; } } static void testmcpdunit_testsimple(ae_bool* err, ae_state *_state); static void testmcpdunit_testentryexit(ae_bool* err, ae_state *_state); static void testmcpdunit_testec(ae_bool* err, ae_state *_state); static void testmcpdunit_testbc(ae_bool* err, ae_state *_state); static void testmcpdunit_testlc(ae_bool* err, ae_state *_state); static void testmcpdunit_createee(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state); ae_bool testmcpd(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool simpleerrors; ae_bool entryexiterrors; ae_bool ecerrors; ae_bool bcerrors; ae_bool lcerrors; ae_bool othererrors; ae_bool result; /* * Init */ waserrors = ae_false; othererrors = ae_false; simpleerrors = ae_false; entryexiterrors = ae_false; ecerrors = ae_false; bcerrors = ae_false; lcerrors = ae_false; /* * Test */ testmcpdunit_testsimple(&simpleerrors, _state); testmcpdunit_testentryexit(&entryexiterrors, _state); testmcpdunit_testec(&ecerrors, _state); testmcpdunit_testbc(&bcerrors, _state); testmcpdunit_testlc(&lcerrors, _state); /* * Final report */ waserrors = ((((othererrors||simpleerrors)||entryexiterrors)||ecerrors)||bcerrors)||lcerrors; if( !silent ) { printf("MCPD TEST\n"); printf("TOTAL RESULTS: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* SIMPLE: "); if( !simpleerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* ENTRY/EXIT: "); if( !entryexiterrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* EQUALITY CONSTRAINTS: "); if( !ecerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* BOUND CONSTRAINTS: "); if( !bcerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* LINEAR CONSTRAINTS: "); if( !lcerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* OTHER PROPERTIES: "); if( !othererrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmcpd(ae_bool silent, ae_state *_state) { return testmcpd(silent, _state); } /************************************************************************* Simple test with no "entry"/"exit" states On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmcpdunit_testsimple(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_matrix pexact; ae_matrix xy; double threshold; ae_int_t i; ae_int_t j; double v; double v0; ae_matrix p; mcpdstate s; mcpdreport rep; double offdiagonal; ae_frame_make(_state, &_frame_block); ae_matrix_init(&pexact, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&p, 0, 0, DT_REAL, _state); _mcpdstate_init(&s, _state); _mcpdreport_init(&rep, _state); threshold = 1.0E-2; /* * First test: * * N-dimensional problem * * proportional data * * no "entry"/"exit" states * * N tracks, each includes only two states * * first record in I-th track is [0 ... 1 ... 0] with 1 is in I-th position * * all tracks are modelled using randomly generated transition matrix P */ for(n=1; n<=5; n++) { /* * Initialize "exact" P: * * fill by random values * * make sure that each column sums to non-zero value * * normalize */ ae_matrix_set_length(&pexact, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { pexact.ptr.pp_double[i][j] = ae_randomreal(_state); } } for(j=0; j<=n-1; j++) { i = ae_randominteger(n, _state); pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]+0.1; } for(j=0; j<=n-1; j++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+pexact.ptr.pp_double[i][j]; } for(i=0; i<=n-1; i++) { pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]/v; } } /* * Initialize solver: * * create object * * add tracks */ mcpdcreate(n, &s, _state); for(i=0; i<=n-1; i++) { ae_matrix_set_length(&xy, 2, n, _state); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[0][j] = (double)(0); } xy.ptr.pp_double[0][i] = (double)(1); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[1][j] = pexact.ptr.pp_double[j][i]; } mcpdaddtrack(&s, &xy, 2, _state); } /* * Solve and test */ mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(p.ptr.pp_double[i][j]-pexact.ptr.pp_double[i][j], _state),threshold); } } } else { *err = ae_true; } } /* * Second test: * * N-dimensional problem * * proportional data * * no "entry"/"exit" states * * N tracks, each includes only two states * * first record in I-th track is [0 ...0.1 0.8 0.1 ... 0] with 0.8 is in I-th position * * all tracks are modelled using randomly generated transition matrix P */ offdiagonal = 0.1; for(n=1; n<=5; n++) { /* * Initialize "exact" P: * * fill by random values * * make sure that each column sums to non-zero value * * normalize */ ae_matrix_set_length(&pexact, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { pexact.ptr.pp_double[i][j] = ae_randomreal(_state); } } for(j=0; j<=n-1; j++) { i = ae_randominteger(n, _state); pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]+0.1; } for(j=0; j<=n-1; j++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+pexact.ptr.pp_double[i][j]; } for(i=0; i<=n-1; i++) { pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]/v; } } /* * Initialize solver: * * create object * * add tracks */ mcpdcreate(n, &s, _state); for(i=0; i<=n-1; i++) { ae_matrix_set_length(&xy, 2, n, _state); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[0][j] = (double)(0); } /* * "main" element */ xy.ptr.pp_double[0][i] = 1.0-2*offdiagonal; for(j=0; j<=n-1; j++) { xy.ptr.pp_double[1][j] = (1.0-2*offdiagonal)*pexact.ptr.pp_double[j][i]; } /* * off-diagonal ones */ if( i>0 ) { xy.ptr.pp_double[0][i-1] = offdiagonal; for(j=0; j<=n-1; j++) { xy.ptr.pp_double[1][j] = xy.ptr.pp_double[1][j]+offdiagonal*pexact.ptr.pp_double[j][i-1]; } } if( i0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(p.ptr.pp_double[i][j]-pexact.ptr.pp_double[i][j], _state),threshold); } } } else { *err = ae_true; } } /* * Third test: * * N-dimensional problem * * population data * * no "entry"/"exit" states * * N tracks, each includes only two states * * first record in I-th track is V*[0 ...0.1 0.8 0.1 ... 0] with 0.8 is in I-th position, V in [1,10] * * all tracks are modelled using randomly generated transition matrix P */ offdiagonal = 0.1; for(n=1; n<=5; n++) { /* * Initialize "exact" P: * * fill by random values * * make sure that each column sums to non-zero value * * normalize */ ae_matrix_set_length(&pexact, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { pexact.ptr.pp_double[i][j] = ae_randomreal(_state); } } for(j=0; j<=n-1; j++) { i = ae_randominteger(n, _state); pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]+0.1; } for(j=0; j<=n-1; j++) { v = (double)(0); for(i=0; i<=n-1; i++) { v = v+pexact.ptr.pp_double[i][j]; } for(i=0; i<=n-1; i++) { pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]/v; } } /* * Initialize solver: * * create object * * add tracks */ mcpdcreate(n, &s, _state); for(i=0; i<=n-1; i++) { ae_matrix_set_length(&xy, 2, n, _state); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[0][j] = (double)(0); } /* * "main" element */ v0 = 9*ae_randomreal(_state)+1; xy.ptr.pp_double[0][i] = v0*(1.0-2*offdiagonal); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[1][j] = v0*(1.0-2*offdiagonal)*pexact.ptr.pp_double[j][i]; } /* * off-diagonal ones */ if( i>0 ) { xy.ptr.pp_double[0][i-1] = v0*offdiagonal; for(j=0; j<=n-1; j++) { xy.ptr.pp_double[1][j] = xy.ptr.pp_double[1][j]+v0*offdiagonal*pexact.ptr.pp_double[j][i-1]; } } if( i0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(p.ptr.pp_double[i][j]-pexact.ptr.pp_double[i][j], _state),threshold); } } } else { *err = ae_true; } } ae_frame_leave(_state); } /************************************************************************* Test for different combinations of "entry"/"exit" models On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmcpdunit_testentryexit(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_matrix p; ae_matrix pexact; ae_matrix xy; double threshold; ae_int_t entrystate; ae_int_t exitstate; ae_int_t entrykind; ae_int_t exitkind; ae_int_t popkind; ae_int_t i; ae_int_t j; ae_int_t k; double v; mcpdstate s; mcpdreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&p, 0, 0, DT_REAL, _state); ae_matrix_init(&pexact, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _mcpdstate_init(&s, _state); _mcpdreport_init(&rep, _state); threshold = 1.0E-3; /* * */ for(n=2; n<=5; n++) { for(entrykind=0; entrykind<=1; entrykind++) { for(exitkind=0; exitkind<=1; exitkind++) { for(popkind=0; popkind<=1; popkind++) { /* * Generate EntryState/ExitState such that one of the following is True: * * EntryState<>ExitState * * EntryState=-1 or ExitState=-1 */ do { if( entrykind==0 ) { entrystate = -1; } else { entrystate = ae_randominteger(n, _state); } if( exitkind==0 ) { exitstate = -1; } else { exitstate = ae_randominteger(n, _state); } } while(!((entrystate==-1||exitstate==-1)||entrystate!=exitstate)); /* * Generate transition matrix P such that: * * columns corresponding to non-exit states sums to 1.0 * * columns corresponding to exit states sums to 0.0 * * rows corresponding to entry states are zero */ ae_matrix_set_length(&pexact, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { pexact.ptr.pp_double[i][j] = (double)(1+ae_randominteger(5, _state)); if( i==entrystate ) { pexact.ptr.pp_double[i][j] = 0.0; } if( j==exitstate ) { pexact.ptr.pp_double[i][j] = 0.0; } } } for(j=0; j<=n-1; j++) { v = 0.0; for(i=0; i<=n-1; i++) { v = v+pexact.ptr.pp_double[i][j]; } if( ae_fp_neq(v,(double)(0)) ) { for(i=0; i<=n-1; i++) { pexact.ptr.pp_double[i][j] = pexact.ptr.pp_double[i][j]/v; } } } /* * Create MCPD solver */ if( entrystate<0&&exitstate<0 ) { mcpdcreate(n, &s, _state); } if( entrystate>=0&&exitstate<0 ) { mcpdcreateentry(n, entrystate, &s, _state); } if( entrystate<0&&exitstate>=0 ) { mcpdcreateexit(n, exitstate, &s, _state); } if( entrystate>=0&&exitstate>=0 ) { mcpdcreateentryexit(n, entrystate, exitstate, &s, _state); } /* * Add N tracks. * * K-th track starts from vector with large value of * K-th component and small random noise in other components. * * Track contains from 2 to 4 elements. * * Tracks contain proportional (normalized) or * population data, depending on PopKind variable. */ for(k=0; k<=n-1; k++) { /* * Generate track whose length is in 2..4 */ ae_matrix_set_length(&xy, 2+ae_randominteger(3, _state), n, _state); for(j=0; j<=n-1; j++) { xy.ptr.pp_double[0][j] = 0.05*ae_randomreal(_state); } xy.ptr.pp_double[0][k] = 1+ae_randomreal(_state); for(i=1; i<=xy.rows-1; i++) { for(j=0; j<=n-1; j++) { if( j!=entrystate ) { v = ae_v_dotproduct(&pexact.ptr.pp_double[j][0], 1, &xy.ptr.pp_double[i-1][0], 1, ae_v_len(0,n-1)); xy.ptr.pp_double[i][j] = v; } else { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } } /* * Normalize, if needed */ if( popkind==1 ) { for(i=0; i<=xy.rows-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { v = v+xy.ptr.pp_double[i][j]; } if( ae_fp_greater(v,(double)(0)) ) { for(j=0; j<=n-1; j++) { xy.ptr.pp_double[i][j] = xy.ptr.pp_double[i][j]/v; } } } } /* * Add track */ mcpdaddtrack(&s, &xy, xy.rows, _state); } /* * Solve and test */ mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_greater(ae_fabs(p.ptr.pp_double[i][j]-pexact.ptr.pp_double[i][j], _state),threshold); } } } else { *err = ae_true; } } } } } ae_frame_leave(_state); } /************************************************************************* Test equality constraints. On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmcpdunit_testec(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_matrix p; ae_matrix ec; ae_matrix xy; ae_int_t entrystate; ae_int_t exitstate; ae_int_t entrykind; ae_int_t exitkind; ae_int_t i; ae_int_t j; ae_int_t ic; ae_int_t jc; double vc; mcpdstate s; mcpdreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&p, 0, 0, DT_REAL, _state); ae_matrix_init(&ec, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _mcpdstate_init(&s, _state); _mcpdreport_init(&rep, _state); /* * We try different problems with following properties: * * N is large enough - we won't have problems with inconsistent constraints * * first state is either "entry" or "normal" * * last state is either "exit" or "normal" * * we have one long random track * * We test several properties which are described in comments below */ for(n=4; n<=6; n++) { for(entrykind=0; entrykind<=1; entrykind++) { for(exitkind=0; exitkind<=1; exitkind++) { /* * Prepare problem */ if( entrykind==0 ) { entrystate = -1; } else { entrystate = 0; } if( exitkind==0 ) { exitstate = -1; } else { exitstate = n-1; } ae_matrix_set_length(&xy, 2*n, n, _state); for(i=0; i<=xy.rows-1; i++) { for(j=0; j<=xy.cols-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } /* * Test that single equality constraint on non-entry * non-exit elements of P is satisfied. * * NOTE: this test needs N>=4 because smaller values * can give us inconsistent constraints */ ae_assert(n>=4, "TestEC: expectation failed", _state); ic = 1+ae_randominteger(n-2, _state); jc = 1+ae_randominteger(n-2, _state); vc = ae_randomreal(_state); testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddec(&s, ic, jc, vc, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { *err = *err||ae_fp_neq(p.ptr.pp_double[ic][jc],vc); } else { *err = ae_true; } /* * Test interaction with default "sum-to-one" constraint * on columns of P. * * We set N-1 equality constraints on random non-exit column * of P, which are inconsistent with this default constraint * (sum will be greater that 1.0). * * Algorithm must detect inconsistency. * * NOTE: * 1. we do not set constraints for the first element of * the column, because this element may be constrained by * "exit state" constraint. * 2. this test needs N>=3 */ ae_assert(n>=3, "TestEC: expectation failed", _state); jc = ae_randominteger(n-1, _state); vc = 0.95; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); for(i=1; i<=n-1; i++) { mcpdaddec(&s, i, jc, vc, _state); } mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; /* * Test interaction with constrains on entry states. * * When model has entry state, corresponding row of P * must be zero. We try to set two kinds of constraints * on random element of this row: * * zero equality constraint, which must be consistent * * non-zero equality constraint, which must be inconsistent */ if( entrystate>=0 ) { jc = ae_randominteger(n, _state); testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddec(&s, entrystate, jc, 0.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddec(&s, entrystate, jc, 0.5, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } /* * Test interaction with constrains on exit states. * * When model has exit state, corresponding column of P * must be zero. We try to set two kinds of constraints * on random element of this column: * * zero equality constraint, which must be consistent * * non-zero equality constraint, which must be inconsistent */ if( exitstate>=0 ) { ic = ae_randominteger(n, _state); testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddec(&s, ic, exitstate, 0.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddec(&s, ic, exitstate, 0.5, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } /* * Test SetEC() call - we constrain subset of non-entry * non-exit elements and test it. */ ae_assert(n>=4, "TestEC: expectation failed", _state); ae_matrix_set_length(&ec, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ec.ptr.pp_double[i][j] = _state->v_nan; } } for(j=1; j<=n-2; j++) { ec.ptr.pp_double[1+ae_randominteger(n-2, _state)][j] = 0.1+0.1*ae_randomreal(_state); } testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetec(&s, &ec, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_isfinite(ec.ptr.pp_double[i][j], _state) ) { *err = *err||ae_fp_neq(p.ptr.pp_double[i][j],ec.ptr.pp_double[i][j]); } } } } else { *err = ae_true; } } } } ae_frame_leave(_state); } /************************************************************************* Test bound constraints. On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmcpdunit_testbc(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_matrix p; ae_matrix bndl; ae_matrix bndu; ae_matrix xy; ae_int_t entrystate; ae_int_t exitstate; ae_int_t entrykind; ae_int_t exitkind; ae_int_t i; ae_int_t j; ae_int_t ic; ae_int_t jc; double vl; double vu; mcpdstate s; mcpdreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&p, 0, 0, DT_REAL, _state); ae_matrix_init(&bndl, 0, 0, DT_REAL, _state); ae_matrix_init(&bndu, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _mcpdstate_init(&s, _state); _mcpdreport_init(&rep, _state); /* * We try different problems with following properties: * * N is large enough - we won't have problems with inconsistent constraints * * first state is either "entry" or "normal" * * last state is either "exit" or "normal" * * we have one long random track * * We test several properties which are described in comments below */ for(n=4; n<=6; n++) { for(entrykind=0; entrykind<=1; entrykind++) { for(exitkind=0; exitkind<=1; exitkind++) { /* * Prepare problem */ if( entrykind==0 ) { entrystate = -1; } else { entrystate = 0; } if( exitkind==0 ) { exitstate = -1; } else { exitstate = n-1; } ae_matrix_set_length(&xy, 2*n, n, _state); for(i=0; i<=xy.rows-1; i++) { for(j=0; j<=xy.cols-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } /* * Test that single bound constraint on non-entry * non-exit elements of P is satisfied. * * NOTE 1: this test needs N>=4 because smaller values * can give us inconsistent constraints */ ae_assert(n>=4, "TestBC: expectation failed", _state); ic = 1+ae_randominteger(n-2, _state); jc = 1+ae_randominteger(n-2, _state); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { vl = 0.3*ae_randomreal(_state); } else { vl = _state->v_neginf; } if( ae_fp_greater(ae_randomreal(_state),0.5) ) { vu = 0.5+0.3*ae_randomreal(_state); } else { vu = _state->v_posinf; } testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddbc(&s, ic, jc, vl, vu, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { *err = *err||ae_fp_less(p.ptr.pp_double[ic][jc],vl); *err = *err||ae_fp_greater(p.ptr.pp_double[ic][jc],vu); } else { *err = ae_true; } /* * Test interaction with default "sum-to-one" constraint * on columns of P. * * We set N-1 bound constraints on random non-exit column * of P, which are inconsistent with this default constraint * (sum will be greater that 1.0). * * Algorithm must detect inconsistency. * * NOTE: * 1. we do not set constraints for the first element of * the column, because this element may be constrained by * "exit state" constraint. * 2. this test needs N>=3 */ ae_assert(n>=3, "TestEC: expectation failed", _state); jc = ae_randominteger(n-1, _state); vl = 0.85; vu = 0.95; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); for(i=1; i<=n-1; i++) { mcpdaddbc(&s, i, jc, vl, vu, _state); } mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; /* * Test interaction with constrains on entry states. * * When model has entry state, corresponding row of P * must be zero. We try to set two kinds of constraints * on random element of this row: * * bound constraint with zero lower bound, which must be consistent * * bound constraint with non-zero lower bound, which must be inconsistent */ if( entrystate>=0 ) { jc = ae_randominteger(n, _state); testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddbc(&s, entrystate, jc, 0.0, 1.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddbc(&s, entrystate, jc, 0.5, 1.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } /* * Test interaction with constrains on exit states. * * When model has exit state, corresponding column of P * must be zero. We try to set two kinds of constraints * on random element of this column: * * bound constraint with zero lower bound, which must be consistent * * bound constraint with non-zero lower bound, which must be inconsistent */ if( exitstate>=0 ) { ic = ae_randominteger(n, _state); testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddbc(&s, ic, exitstate, 0.0, 1.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdaddbc(&s, ic, exitstate, 0.5, 1.0, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } /* * Test SetBC() call - we constrain subset of non-entry * non-exit elements and test it. */ ae_assert(n>=4, "TestBC: expectation failed", _state); ae_matrix_set_length(&bndl, n, n, _state); ae_matrix_set_length(&bndu, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { bndl.ptr.pp_double[i][j] = _state->v_neginf; bndu.ptr.pp_double[i][j] = _state->v_posinf; } } for(j=1; j<=n-2; j++) { i = 1+ae_randominteger(n-2, _state); bndl.ptr.pp_double[i][j] = 0.5-0.1*ae_randomreal(_state); bndu.ptr.pp_double[i][j] = 0.5+0.1*ae_randomreal(_state); } testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetbc(&s, &bndl, &bndu, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { *err = *err||ae_fp_less(p.ptr.pp_double[i][j],bndl.ptr.pp_double[i][j]); *err = *err||ae_fp_greater(p.ptr.pp_double[i][j],bndu.ptr.pp_double[i][j]); } } } else { *err = ae_true; } } } } ae_frame_leave(_state); } /************************************************************************* Test bound constraints. On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testmcpdunit_testlc(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_matrix p; ae_matrix c; ae_matrix xy; ae_vector ct; ae_int_t entrystate; ae_int_t exitstate; ae_int_t entrykind; ae_int_t exitkind; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t t; ae_int_t jc; double v; double threshold; mcpdstate s; mcpdreport rep; ae_frame_make(_state, &_frame_block); ae_matrix_init(&p, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _mcpdstate_init(&s, _state); _mcpdreport_init(&rep, _state); threshold = 1.0E5*ae_machineepsilon; /* * We try different problems with following properties: * * N is large enough - we won't have problems with inconsistent constraints * * first state is either "entry" or "normal" * * last state is either "exit" or "normal" * * we have one long random track * * We test several properties which are described in comments below */ for(n=4; n<=6; n++) { for(entrykind=0; entrykind<=1; entrykind++) { for(exitkind=0; exitkind<=1; exitkind++) { /* * Prepare problem */ if( entrykind==0 ) { entrystate = -1; } else { entrystate = 0; } if( exitkind==0 ) { exitstate = -1; } else { exitstate = n-1; } ae_matrix_set_length(&xy, 2*n, n, _state); for(i=0; i<=xy.rows-1; i++) { for(j=0; j<=xy.cols-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } /* * Test that single linear equality/inequality constraint * on non-entry non-exit elements of P is satisfied. * * NOTE 1: this test needs N>=4 because smaller values * can give us inconsistent constraints * NOTE 2: Constraints are generated is such a way that P=(1/N ... 1/N) * is always feasible. It guarantees that there always exists * at least one feasible point * NOTE 3: If we have inequality constraint, we "shift" right part * in order to make feasible some neighborhood of P=(1/N ... 1/N). */ ae_assert(n>=4, "TestLC: expectation failed", _state); ae_matrix_set_length(&c, 1, n*n+1, _state); ae_vector_set_length(&ct, 1, _state); v = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ((i==0||i==n-1)||j==0)||j==n-1 ) { c.ptr.pp_double[0][i*n+j] = (double)(0); } else { c.ptr.pp_double[0][i*n+j] = ae_randomreal(_state); v = v+c.ptr.pp_double[0][i*n+j]*((double)1/(double)n); } } } c.ptr.pp_double[0][n*n] = v; ct.ptr.p_int[0] = ae_randominteger(3, _state)-1; if( ct.ptr.p_int[0]<0 ) { c.ptr.pp_double[0][n*n] = c.ptr.pp_double[0][n*n]+0.1; } if( ct.ptr.p_int[0]>0 ) { c.ptr.pp_double[0][n*n] = c.ptr.pp_double[0][n*n]-0.1; } testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { v = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = v+p.ptr.pp_double[i][j]*c.ptr.pp_double[0][i*n+j]; } } if( ct.ptr.p_int[0]<0 ) { *err = *err||ae_fp_greater_eq(v,c.ptr.pp_double[0][n*n]+threshold); } if( ct.ptr.p_int[0]==0 ) { *err = *err||ae_fp_greater_eq(ae_fabs(v-c.ptr.pp_double[0][n*n], _state),threshold); } if( ct.ptr.p_int[0]>0 ) { *err = *err||ae_fp_less_eq(v,c.ptr.pp_double[0][n*n]-threshold); } } else { *err = ae_true; } /* * Test interaction with default "sum-to-one" constraint * on columns of P. * * We set linear constraint which has for "sum-to-X" on * on random non-exit column of P. This constraint can be * either consistent (X=1.0) or inconsistent (X<>1.0) with * this default constraint. * * Algorithm must detect inconsistency. * * NOTE: * 1. this test needs N>=2 */ ae_assert(n>=2, "TestLC: expectation failed", _state); jc = ae_randominteger(n-1, _state); ae_matrix_set_length(&c, 1, n*n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n*n-1; i++) { c.ptr.pp_double[0][i] = 0.0; } for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][n*i+jc] = 1.0; } c.ptr.pp_double[0][n*n] = 1.0; ct.ptr.p_int[0] = 0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; c.ptr.pp_double[0][n*n] = 2.0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; /* * Test interaction with constrains on entry states. * * When model has entry state, corresponding row of P * must be zero. We try to set two kinds of constraints * on elements of this row: * * sums-to-zero constraint, which must be consistent * * sums-to-one constraint, which must be inconsistent */ if( entrystate>=0 ) { ae_matrix_set_length(&c, 1, n*n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n*n-1; i++) { c.ptr.pp_double[0][i] = 0.0; } for(j=0; j<=n-1; j++) { c.ptr.pp_double[0][n*entrystate+j] = 1.0; } ct.ptr.p_int[0] = 0; c.ptr.pp_double[0][n*n] = 0.0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; c.ptr.pp_double[0][n*n] = 1.0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } /* * Test interaction with constrains on exit states. * * When model has exit state, corresponding column of P * must be zero. We try to set two kinds of constraints * on elements of this column: * * sums-to-zero constraint, which must be consistent * * sums-to-one constraint, which must be inconsistent */ if( exitstate>=0 ) { ae_matrix_set_length(&c, 1, n*n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n*n-1; i++) { c.ptr.pp_double[0][i] = 0.0; } for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][n*i+exitstate] = 1.0; } ct.ptr.p_int[0] = 0; c.ptr.pp_double[0][n*n] = 0.0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype<=0; c.ptr.pp_double[0][n*n] = 1.0; testmcpdunit_createee(n, entrystate, exitstate, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, 1, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); *err = *err||rep.terminationtype!=-3; } } } } /* * Final test - we generate several random constraints and * test SetLC() function. * * NOTES: * * 1. Constraints are generated is such a way that P=(1/N ... 1/N) * is always feasible. It guarantees that there always exists * at least one feasible point * 2. For simplicity of the test we do not use entry/exit states * in our model */ for(n=1; n<=4; n++) { for(k=1; k<=2*n; k++) { /* * Generate track */ ae_matrix_set_length(&xy, 2*n, n, _state); for(i=0; i<=xy.rows-1; i++) { for(j=0; j<=xy.cols-1; j++) { xy.ptr.pp_double[i][j] = ae_randomreal(_state); } } /* * Generate random constraints */ ae_matrix_set_length(&c, k, n*n+1, _state); ae_vector_set_length(&ct, k, _state); for(i=0; i<=k-1; i++) { /* * Generate constraint and its right part */ c.ptr.pp_double[i][n*n] = (double)(0); for(j=0; j<=n*n-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; c.ptr.pp_double[i][n*n] = c.ptr.pp_double[i][n*n]+c.ptr.pp_double[i][j]*((double)1/(double)n); } ct.ptr.p_int[i] = ae_randominteger(3, _state)-1; /* * If we have inequality constraint, we "shift" right part * in order to make feasible some neighborhood of P=(1/N ... 1/N). */ if( ct.ptr.p_int[i]<0 ) { c.ptr.pp_double[i][n*n] = c.ptr.pp_double[i][n*n]+0.1; } if( ct.ptr.p_int[i]>0 ) { c.ptr.pp_double[i][n*n] = c.ptr.pp_double[i][n*n]-0.1; } } /* * Test */ testmcpdunit_createee(n, -1, -1, &s, _state); mcpdaddtrack(&s, &xy, xy.rows, _state); mcpdsetlc(&s, &c, &ct, k, _state); mcpdsolve(&s, _state); mcpdresults(&s, &p, &rep, _state); if( rep.terminationtype>0 ) { for(t=0; t<=k-1; t++) { v = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = v+p.ptr.pp_double[i][j]*c.ptr.pp_double[t][i*n+j]; } } if( ct.ptr.p_int[t]<0 ) { *err = *err||ae_fp_greater_eq(v,c.ptr.pp_double[t][n*n]+threshold); } if( ct.ptr.p_int[t]==0 ) { *err = *err||ae_fp_greater_eq(ae_fabs(v-c.ptr.pp_double[t][n*n], _state),threshold); } if( ct.ptr.p_int[t]>0 ) { *err = *err||ae_fp_less_eq(v,c.ptr.pp_double[t][n*n]-threshold); } } } else { *err = ae_true; } } } ae_frame_leave(_state); } /************************************************************************* This function is used to create MCPD object with arbitrary combination of entry and exit states *************************************************************************/ static void testmcpdunit_createee(ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate* s, ae_state *_state) { _mcpdstate_clear(s); if( entrystate<0&&exitstate<0 ) { mcpdcreate(n, s, _state); } if( entrystate>=0&&exitstate<0 ) { mcpdcreateentry(n, entrystate, s, _state); } if( entrystate<0&&exitstate>=0 ) { mcpdcreateexit(n, exitstate, s, _state); } if( entrystate>=0&&exitstate>=0 ) { mcpdcreateentryexit(n, entrystate, exitstate, s, _state); } } static void testmlpeunit_createensemble(mlpensemble* ensemble, ae_int_t nkind, double a1, double a2, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_state *_state); static void testmlpeunit_unsetensemble(mlpensemble* ensemble, ae_state *_state); static void testmlpeunit_testinformational(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testmlpeunit_testprocessing(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_bool* err, ae_state *_state); static void testmlpeunit_testerr(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state); ae_bool testmlpe(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool inferrors; ae_bool procerrors; ae_bool errerrors; ae_int_t passcount; ae_int_t maxn; ae_int_t maxhid; ae_int_t nf; ae_int_t nl; ae_int_t nhid1; ae_int_t nhid2; ae_int_t ec; ae_int_t nkind; ae_int_t sizemin; ae_int_t sizemax; ae_bool result; waserrors = ae_false; inferrors = ae_false; procerrors = ae_false; errerrors = ae_false; passcount = 5; maxn = 3; maxhid = 3; /* * General MLP ensembles tests * These tests are performed with small dataset, whose size is in [0,10]. * We test correctness of functions on small sets, but do not test code * which splits large dataset into smaller chunks. */ sizemin = 0; sizemax = 10; for(nf=1; nf<=maxn; nf++) { for(nl=1; nl<=maxn; nl++) { for(nhid1=0; nhid1<=maxhid; nhid1++) { for(nhid2=0; nhid2<=maxhid; nhid2++) { for(nkind=0; nkind<=3; nkind++) { for(ec=1; ec<=3; ec++) { /* * Skip meaningless parameters combinations */ if( nkind==1&&nl<2 ) { continue; } if( nhid1==0&&nhid2!=0 ) { continue; } /* * Tests */ testmlpeunit_testinformational(nkind, nf, nhid1, nhid2, nl, ec, passcount, &inferrors, _state); testmlpeunit_testprocessing(nkind, nf, nhid1, nhid2, nl, ec, passcount, &procerrors, _state); testmlpeunit_testerr(nkind, nf, nhid1, nhid2, nl, ec, passcount, sizemin, sizemax, &errerrors, _state); } } } } } } /* * Special tests on large datasets: test ability to correctly split * work into smaller chunks. */ nf = 2; nhid1 = 10; nhid2 = 10; nl = 2; ec = 10; sizemin = 1000; sizemax = 1000; testmlpeunit_testerr(0, nf, nhid1, nhid2, nl, ec, 1, sizemin, sizemax, &errerrors, _state); /* * Final report */ waserrors = (inferrors||procerrors)||errerrors; if( !silent ) { printf("MLP ENSEMBLE TEST\n"); printf("INFORMATIONAL FUNCTIONS: "); if( !inferrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("BASIC PROCESSING: "); if( !procerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("ERROR FUNCTIONS: "); if( !errerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmlpe(ae_bool silent, ae_state *_state) { return testmlpe(silent, _state); } /************************************************************************* Network creation *************************************************************************/ static void testmlpeunit_createensemble(mlpensemble* ensemble, ae_int_t nkind, double a1, double a2, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_state *_state) { ae_assert(((nin>0&&nhid1>=0)&&nhid2>=0)&&nout>0, "CreateNetwork error", _state); ae_assert(nhid1!=0||nhid2==0, "CreateNetwork error", _state); ae_assert(nkind!=1||nout>=2, "CreateNetwork error", _state); if( nhid1==0 ) { /* * No hidden layers */ if( nkind==0 ) { mlpecreate0(nin, nout, ec, ensemble, _state); } else { if( nkind==1 ) { mlpecreatec0(nin, nout, ec, ensemble, _state); } else { if( nkind==2 ) { mlpecreateb0(nin, nout, a1, a2, ec, ensemble, _state); } else { if( nkind==3 ) { mlpecreater0(nin, nout, a1, a2, ec, ensemble, _state); } } } } return; } if( nhid2==0 ) { /* * One hidden layer */ if( nkind==0 ) { mlpecreate1(nin, nhid1, nout, ec, ensemble, _state); } else { if( nkind==1 ) { mlpecreatec1(nin, nhid1, nout, ec, ensemble, _state); } else { if( nkind==2 ) { mlpecreateb1(nin, nhid1, nout, a1, a2, ec, ensemble, _state); } else { if( nkind==3 ) { mlpecreater1(nin, nhid1, nout, a1, a2, ec, ensemble, _state); } } } } return; } /* * Two hidden layers */ if( nkind==0 ) { mlpecreate2(nin, nhid1, nhid2, nout, ec, ensemble, _state); } else { if( nkind==1 ) { mlpecreatec2(nin, nhid1, nhid2, nout, ec, ensemble, _state); } else { if( nkind==2 ) { mlpecreateb2(nin, nhid1, nhid2, nout, a1, a2, ec, ensemble, _state); } else { if( nkind==3 ) { mlpecreater2(nin, nhid1, nhid2, nout, a1, a2, ec, ensemble, _state); } } } } } /************************************************************************* Unsets network (initialize it to smallest network possible *************************************************************************/ static void testmlpeunit_unsetensemble(mlpensemble* ensemble, ae_state *_state) { mlpecreate0(1, 1, 1, ensemble, _state); } /************************************************************************* Iformational functions test *************************************************************************/ static void testmlpeunit_testinformational(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; mlpensemble ensemble; ae_int_t n1; ae_int_t n2; ae_frame_make(_state, &_frame_block); _mlpensemble_init(&ensemble, _state); testmlpeunit_createensemble(&ensemble, nkind, -1.0, 1.0, nin, nhid1, nhid2, nout, ec, _state); mlpeproperties(&ensemble, &n1, &n2, _state); *err = (*err||n1!=nin)||n2!=nout; ae_frame_leave(_state); } /************************************************************************* Processing functions test *************************************************************************/ static void testmlpeunit_testprocessing(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_bool* err, ae_state *_state) { ae_frame _frame_block; mlpensemble ensemble; mlpensemble ensemble2; double a1; double a2; ae_int_t pass; ae_int_t rkind; ae_int_t i; ae_bool allsame; ae_vector x1; ae_vector x2; ae_vector y1; ae_vector y2; ae_vector ra; ae_vector ra2; double v; ae_frame_make(_state, &_frame_block); _mlpensemble_init(&ensemble, _state); _mlpensemble_init(&ensemble2, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&ra, 0, DT_REAL, _state); ae_vector_init(&ra2, 0, DT_REAL, _state); /* * Prepare network */ a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } /* * Initialize arrays */ ae_vector_set_length(&x1, nin-1+1, _state); ae_vector_set_length(&x2, nin-1+1, _state); ae_vector_set_length(&y1, nout-1+1, _state); ae_vector_set_length(&y2, nout-1+1, _state); /* * Main cycle: * * Pass is a number of repeated test * * RKind is a "replication kind": * * RKind=0 means that we work with original ensemble * * RKind=1 means that we work with replica created with MLPECopy() * * RKind=2 means that we work with replica created with serialization/unserialization */ for(pass=1; pass<=passcount; pass++) { for(rkind=0; rkind<=2; rkind++) { /* * Create network, pass through replication in order to test that replicated network works correctly. */ testmlpeunit_createensemble(&ensemble, nkind, a1, a2, nin, nhid1, nhid2, nout, ec, _state); if( rkind==1 ) { mlpecopy(&ensemble, &ensemble2, _state); testmlpeunit_unsetensemble(&ensemble, _state); mlpecopy(&ensemble2, &ensemble, _state); testmlpeunit_unsetensemble(&ensemble2, _state); } if( rkind==2 ) { { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpealloc(&_local_serializer, &ensemble, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeserialize(&_local_serializer, &ensemble, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeunserialize(&_local_serializer, &ensemble2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } testmlpeunit_unsetensemble(&ensemble, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpealloc(&_local_serializer, &ensemble2, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeserialize(&_local_serializer, &ensemble2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeunserialize(&_local_serializer, &ensemble, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } testmlpeunit_unsetensemble(&ensemble2, _state); } /* * Same inputs leads to same outputs */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); mlpeprocess(&ensemble, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Same inputs on original network leads to same outputs * on copy created using MLPCopy */ testmlpeunit_unsetensemble(&ensemble2, _state); mlpecopy(&ensemble, &ensemble2, _state); for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); mlpeprocess(&ensemble2, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Same inputs on original network leads to same outputs * on copy created using MLPSerialize */ { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); mlpealloc(&_local_serializer, &ensemble, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeserialize(&_local_serializer, &ensemble, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); mlpeunserialize(&_local_serializer, &ensemble2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = x1.ptr.p_double[i]; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); mlpeprocess(&ensemble2, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||!allsame; /* * Different inputs leads to different outputs (non-zero network) */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = y1.ptr.p_double[i]; } mlpeprocess(&ensemble, &x1, &y1, _state); mlpeprocess(&ensemble, &x2, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||allsame; /* * Randomization changes outputs (when inputs are unchanged, non-zero network) */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nout-1; i++) { y1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y2.ptr.p_double[i] = y1.ptr.p_double[i]; } mlpecopy(&ensemble, &ensemble2, _state); mlperandomize(&ensemble2, _state); mlpeprocess(&ensemble, &x1, &y1, _state); mlpeprocess(&ensemble2, &x1, &y2, _state); allsame = ae_true; for(i=0; i<=nout-1; i++) { allsame = allsame&&ae_fp_eq(y1.ptr.p_double[i],y2.ptr.p_double[i]); } *err = *err||allsame; /* * Normalization properties */ if( nkind==1 ) { /* * Classifier network outputs are normalized */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); v = (double)(0); for(i=0; i<=nout-1; i++) { v = v+y1.ptr.p_double[i]; *err = *err||ae_fp_less(y1.ptr.p_double[i],(double)(0)); } *err = *err||ae_fp_greater(ae_fabs(v-1, _state),1000*ae_machineepsilon); } if( nkind==2 ) { /* * B-type network outputs are bounded from above/below */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); for(i=0; i<=nout-1; i++) { if( ae_fp_greater_eq(a2,(double)(0)) ) { *err = *err||ae_fp_less(y1.ptr.p_double[i],a1); } else { *err = *err||ae_fp_greater(y1.ptr.p_double[i],a1); } } } if( nkind==3 ) { /* * R-type network outputs are within [A1,A2] (or [A2,A1]) */ for(i=0; i<=nin-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } mlpeprocess(&ensemble, &x1, &y1, _state); for(i=0; i<=nout-1; i++) { *err = (*err||ae_fp_less(y1.ptr.p_double[i],ae_minreal(a1, a2, _state)))||ae_fp_greater(y1.ptr.p_double[i],ae_maxreal(a1, a2, _state)); } } } } ae_frame_leave(_state); } /************************************************************************* Error functions Ensemble of type NKind is created, with NIn inputs, NHid1*NHid2 hidden layers (one layer if NHid2=0), NOut outputs. PassCount random passes is performed. Dataset has random size in [SizeMin,SizeMax]. *************************************************************************/ static void testmlpeunit_testerr(ae_int_t nkind, ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ec, ae_int_t passcount, ae_int_t sizemin, ae_int_t sizemax, ae_bool* err, ae_state *_state) { ae_frame _frame_block; mlpensemble ensemble; sparsematrix sparsexy; sparsematrix sparsexy2; ae_int_t n1; ae_int_t n2; ae_int_t wcount; double etol; double escale; double a1; double a2; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t ssize; ae_matrix xy; ae_matrix xy2; ae_vector y; ae_vector x1; ae_vector y1; ae_vector idx; ae_vector dummy; double refrmserror; double refclserror; double refrelclserror; double refavgce; double refavgerror; double refavgrelerror; ae_int_t avgrelcnt; modelerrors allerrors; ae_int_t nnmax; ae_int_t dsmax; ae_frame_make(_state, &_frame_block); _mlpensemble_init(&ensemble, _state); _sparsematrix_init(&sparsexy, _state); _sparsematrix_init(&sparsexy2, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&xy2, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); ae_vector_init(&idx, 0, DT_INT, _state); ae_vector_init(&dummy, 0, DT_INT, _state); _modelerrors_init(&allerrors, _state); a1 = (double)(0); a2 = (double)(0); if( nkind==2 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = 2*ae_randomreal(_state)-1; } if( nkind==3 ) { a1 = 1000*ae_randomreal(_state)-500; a2 = a1+(2*ae_randominteger(2, _state)-1)*(0.1+0.9*ae_randomreal(_state)); } testmlpeunit_createensemble(&ensemble, nkind, a1, a2, nin, nhid1, nhid2, nout, ec, _state); mlpproperties(&ensemble.network, &n1, &n2, &wcount, _state); etol = 1.0E-4; escale = 1.0E-2; /* * Initialize */ ae_vector_set_length(&x1, nin, _state); ae_vector_set_length(&y, nout, _state); ae_vector_set_length(&y1, nout, _state); /* * Process */ for(pass=1; pass<=passcount; pass++) { /* * Randomize Ensemble, then re-randomaze weights manually. * * NOTE: weights magnitude is chosen to be small, about 0.1, * which allows us to avoid oversaturated Ensemble. * In 10% of cases we use zero weights. */ mlperandomize(&ensemble, _state); if( ae_fp_less_eq(ae_randomreal(_state),0.1) ) { for(i=0; i<=wcount*ec-1; i++) { ensemble.weights.ptr.p_double[i] = 0.0; } } else { for(i=0; i<=wcount*ec-1; i++) { ensemble.weights.ptr.p_double[i] = 0.2*ae_randomreal(_state)-0.1; } } /* * Generate random dataset. * Calculate reference errors. * * NOTE: about 10% of tests are performed with zero SSize */ ssize = sizemin+ae_randominteger(sizemax-sizemin+1, _state); if( mlpeissoftmax(&ensemble, _state) ) { ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+1, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+1, 0, &sparsexy, _state); } else { ae_matrix_set_length(&xy, ae_maxint(ssize, 1, _state), nin+nout, _state); sparsecreate(ae_maxint(ssize, 1, _state), nin+nout, 0, &sparsexy, _state); } refrmserror = 0.0; refclserror = 0.0; refavgce = 0.0; refavgerror = 0.0; refavgrelerror = 0.0; avgrelcnt = 0; for(i=0; i<=ssize-1; i++) { /* * Fill I-th row */ for(j=0; j<=nin-1; j++) { x1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, j, x1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,nin-1)); if( mlpeissoftmax(&ensemble, _state) ) { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = (double)(0); } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nout, _state)); sparseset(&sparsexy, i, nin, xy.ptr.pp_double[i][nin], _state); y1.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)] = (double)(1); } else { for(j=0; j<=nout-1; j++) { y1.ptr.p_double[j] = 4*ae_randomreal(_state)-2; sparseset(&sparsexy, i, nin+j, y1.ptr.p_double[j], _state); } ae_v_move(&xy.ptr.pp_double[i][nin], 1, &y1.ptr.p_double[0], 1, ae_v_len(nin,nin+nout-1)); } /* * Process */ mlpeprocess(&ensemble, &x1, &y, _state); /* * Update reference errors */ nnmax = 0; if( mlpeissoftmax(&ensemble, _state) ) { if( ae_fp_greater(y.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)],(double)(0)) ) { refavgce = refavgce+ae_log(1/y.ptr.p_double[ae_round(xy.ptr.pp_double[i][nin], _state)], _state); } else { refavgce = refavgce+ae_log(ae_maxrealnumber, _state); } } if( mlpeissoftmax(&ensemble, _state) ) { dsmax = ae_round(xy.ptr.pp_double[i][nin], _state); } else { dsmax = 0; } for(j=0; j<=nout-1; j++) { refrmserror = refrmserror+ae_sqr(y.ptr.p_double[j]-y1.ptr.p_double[j], _state); refavgerror = refavgerror+ae_fabs(y.ptr.p_double[j]-y1.ptr.p_double[j], _state); if( ae_fp_neq(y1.ptr.p_double[j],(double)(0)) ) { refavgrelerror = refavgrelerror+ae_fabs(y.ptr.p_double[j]-y1.ptr.p_double[j], _state)/ae_fabs(y1.ptr.p_double[j], _state); avgrelcnt = avgrelcnt+1; } if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[nnmax]) ) { nnmax = j; } if( !mlpeissoftmax(&ensemble, _state)&&ae_fp_greater(y1.ptr.p_double[j],y1.ptr.p_double[dsmax]) ) { dsmax = j; } } if( nnmax!=dsmax ) { refclserror = refclserror+1; } } sparseconverttocrs(&sparsexy, _state); if( ssize>0 ) { refrmserror = ae_sqrt(refrmserror/(ssize*nout), _state); refavgerror = refavgerror/(ssize*nout); refrelclserror = refclserror/ssize; refavgce = refavgce/(ssize*ae_log((double)(2), _state)); } else { refrelclserror = 0.0; } if( avgrelcnt>0 ) { refavgrelerror = refavgrelerror/avgrelcnt; } /* * Test "continuous" errors on full dataset */ seterrorflagdiff(err, mlpermserror(&ensemble, &xy, ssize, _state), refrmserror, etol, escale, _state); seterrorflagdiff(err, mlpeavgce(&ensemble, &xy, ssize, _state), refavgce, etol, escale, _state); seterrorflagdiff(err, mlpeavgerror(&ensemble, &xy, ssize, _state), refavgerror, etol, escale, _state); seterrorflagdiff(err, mlpeavgrelerror(&ensemble, &xy, ssize, _state), refavgrelerror, etol, escale, _state); } ae_frame_leave(_state); } static void testminlbfgsunit_testfunc2(minlbfgsstate* state, ae_state *_state); static void testminlbfgsunit_testfunc3(minlbfgsstate* state, ae_state *_state); static void testminlbfgsunit_calciip2(minlbfgsstate* state, ae_int_t n, ae_state *_state); static void testminlbfgsunit_testpreconditioning(ae_bool* err, ae_state *_state); static void testminlbfgsunit_testother(ae_bool* err, ae_state *_state); static ae_bool testminlbfgsunit_gradientchecktest(ae_state *_state); static void testminlbfgsunit_funcderiv(double a, double b, double c, double d, double x0, double x1, double x2, /* Real */ ae_vector* x, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state); ae_bool testminlbfgs(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool referror; ae_bool nonconverror; ae_bool eqerror; ae_bool converror; ae_bool crashtest; ae_bool othererrors; ae_bool restartserror; ae_bool precerror; ae_bool graderrors; ae_int_t n; ae_int_t m; ae_vector x; ae_vector xe; ae_vector b; ae_vector xlast; ae_int_t i; ae_int_t j; double v; ae_matrix a; ae_vector diagh; ae_int_t maxits; minlbfgsstate state; minlbfgsreport rep; double diffstep; ae_int_t dkind; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&diagh, 0, DT_REAL, _state); _minlbfgsstate_init(&state, _state); _minlbfgsreport_init(&rep, _state); waserrors = ae_false; referror = ae_false; precerror = ae_false; nonconverror = ae_false; restartserror = ae_false; eqerror = ae_false; converror = ae_false; crashtest = ae_false; othererrors = ae_false; testminlbfgsunit_testpreconditioning(&precerror, _state); testminlbfgsunit_testother(&othererrors, _state); /* * Reference problem */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, 3, _state); n = 3; m = 2; x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; x.ptr.p_double[1] = 100*ae_randomreal(_state)-50; x.ptr.p_double[2] = 100*ae_randomreal(_state)-50; if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0]-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); } if( state.needfg ) { state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]-2)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } } minlbfgsresults(&state, &x, &rep, _state); referror = (((referror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-2, _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-2, _state),0.001); } /* * nonconvex problems with complex surface: we start from point with very small * gradient, but we need ever smaller gradient in the next step due to * Wolfe conditions. */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, 1, _state); n = 1; m = 1; v = (double)(-100); while(ae_fp_less(v,0.1)) { x.ptr.p_double[0] = v; if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, 1.0E-9, (double)(0), (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = ae_sqr(state.x.ptr.p_double[0], _state)/(1+ae_sqr(state.x.ptr.p_double[0], _state)); } if( state.needfg ) { state.g.ptr.p_double[0] = (2*state.x.ptr.p_double[0]*(1+ae_sqr(state.x.ptr.p_double[0], _state))-ae_sqr(state.x.ptr.p_double[0], _state)*2*state.x.ptr.p_double[0])/ae_sqr(1+ae_sqr(state.x.ptr.p_double[0], _state), _state); } } minlbfgsresults(&state, &x, &rep, _state); nonconverror = (nonconverror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0], _state),0.001); v = v+0.1; } } /* * F2 problem with restarts: * * make several iterations and restart BEFORE termination * * iterate and restart AFTER termination * * NOTE: step is bounded from above to avoid premature convergence */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, 3, _state); n = 3; m = 2; x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetstpmax(&state, 0.1, _state); minlbfgssetcond(&state, 0.0000001, 0.0, 0.0, 0, _state); for(i=0; i<=10; i++) { if( !minlbfgsiteration(&state, _state) ) { break; } testminlbfgsunit_testfunc2(&state, _state); } x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc2(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); restartserror = (((restartserror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.01); x.ptr.p_double[0] = 10+10*ae_randomreal(_state); x.ptr.p_double[1] = 10+10*ae_randomreal(_state); x.ptr.p_double[2] = 10+10*ae_randomreal(_state); minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc2(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); restartserror = (((restartserror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.01))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.01); } /* * Linear equations */ diffstep = 1.0E-6; for(n=1; n<=10; n++) { /* * Prepare task */ ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&xe, n-1+1, _state); ae_vector_set_length(&b, n-1+1, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } a.ptr.pp_double[i][i] = a.ptr.pp_double[i][i]+3*ae_sign(a.ptr.pp_double[i][i], _state); } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = v; } /* * Test different M/DKind */ for(m=1; m<=n; m++) { for(dkind=0; dkind<=1; dkind++) { /* * Solve task */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { if( state.needf||state.needfg ) { state.f = (double)(0); } if( state.needfg ) { for(i=0; i<=n-1; i++) { state.g.ptr.p_double[i] = (double)(0); } } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( state.needf||state.needfg ) { state.f = state.f+ae_sqr(v-b.ptr.p_double[i], _state); } if( state.needfg ) { for(j=0; j<=n-1; j++) { state.g.ptr.p_double[j] = state.g.ptr.p_double[j]+2*(v-b.ptr.p_double[i])*a.ptr.pp_double[i][j]; } } } } minlbfgsresults(&state, &x, &rep, _state); eqerror = eqerror||rep.terminationtype<=0; for(i=0; i<=n-1; i++) { eqerror = eqerror||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-xe.ptr.p_double[i], _state),0.001); } } } } /* * Testing convergence properties */ diffstep = 1.0E-6; for(dkind=0; dkind<=1; dkind++) { ae_vector_set_length(&x, 3, _state); n = 3; m = 2; for(i=0; i<=2; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, 0.001, (double)(0), (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc3(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=4; for(i=0; i<=2; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, (double)(0), 0.001, (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc3(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=1; for(i=0; i<=2; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, (double)(0), (double)(0), 0.001, 0, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc3(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); converror = converror||rep.terminationtype!=2; for(i=0; i<=2; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( dkind==0 ) { minlbfgscreate(n, m, &x, &state, _state); } if( dkind==1 ) { minlbfgscreatef(n, m, &x, diffstep, &state, _state); } minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 10, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_testfunc3(&state, _state); } minlbfgsresults(&state, &x, &rep, _state); converror = (converror||rep.terminationtype!=5)||rep.iterationscount!=10; } /* * Crash test: too many iterations on a simple tasks * May fail when encounter zero step, underflow or something like that */ ae_vector_set_length(&x, 2+1, _state); n = 3; m = 2; maxits = 10000; for(i=0; i<=2; i++) { x.ptr.p_double[i] = 6*ae_randomreal(_state)-3; } minlbfgscreate(n, m, &x, &state, _state); minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), maxits, _state); while(minlbfgsiteration(&state, _state)) { state.f = ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = 2*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } minlbfgsresults(&state, &x, &rep, _state); crashtest = crashtest||rep.terminationtype<=0; /* * Test for MinLBFGSGradientCheck */ graderrors = testminlbfgsunit_gradientchecktest(_state); /* * end */ waserrors = (((((((referror||nonconverror)||eqerror)||converror)||crashtest)||othererrors)||restartserror)||precerror)||graderrors; if( !silent ) { printf("TESTING L-BFGS OPTIMIZATION\n"); printf("REFERENCE PROBLEM: "); if( referror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("NON-CONVEX PROBLEM: "); if( nonconverror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LINEAR EQUATIONS: "); if( eqerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RESTARTS: "); if( restartserror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("PRECONDITIONER: "); if( precerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CONVERGENCE PROPERTIES: "); if( converror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CRASH TEST: "); if( crashtest ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("OTHER PROPERTIES: "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST FOR VERIFICATION OF THE GRADIENT: "); if( graderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminlbfgs(ae_bool silent, ae_state *_state) { return testminlbfgs(silent, _state); } /************************************************************************* Calculate test function #2 Simple variation of #1, much more nonlinear, which makes unlikely premature convergence of algorithm . *************************************************************************/ static void testminlbfgsunit_testfunc2(minlbfgsstate* state, ae_state *_state) { if( ae_fp_less(state->x.ptr.p_double[0],(double)(100)) ) { if( state->needf||state->needfg ) { state->f = ae_sqr(ae_exp(state->x.ptr.p_double[0], _state)-2, _state)+ae_sqr(ae_sqr(state->x.ptr.p_double[1], _state), _state)+ae_sqr(state->x.ptr.p_double[2]-state->x.ptr.p_double[0], _state); } if( state->needfg ) { state->g.ptr.p_double[0] = 2*(ae_exp(state->x.ptr.p_double[0], _state)-2)*ae_exp(state->x.ptr.p_double[0], _state)+2*(state->x.ptr.p_double[0]-state->x.ptr.p_double[2]); state->g.ptr.p_double[1] = 4*state->x.ptr.p_double[1]*ae_sqr(state->x.ptr.p_double[1], _state); state->g.ptr.p_double[2] = 2*(state->x.ptr.p_double[2]-state->x.ptr.p_double[0]); } } else { if( state->needf||state->needfg ) { state->f = ae_sqrt(ae_maxrealnumber, _state); } if( state->needfg ) { state->g.ptr.p_double[0] = ae_sqrt(ae_maxrealnumber, _state); state->g.ptr.p_double[1] = (double)(0); state->g.ptr.p_double[2] = (double)(0); } } } /************************************************************************* Calculate test function #3 Simple variation of #1, much more nonlinear, with non-zero value at minimum. It achieve two goals: * makes unlikely premature convergence of algorithm . * solves some issues with EpsF stopping condition which arise when F(minimum) is zero *************************************************************************/ static void testminlbfgsunit_testfunc3(minlbfgsstate* state, ae_state *_state) { double s; s = 0.001; if( ae_fp_less(state->x.ptr.p_double[0],(double)(100)) ) { if( state->needf||state->needfg ) { state->f = ae_sqr(ae_exp(state->x.ptr.p_double[0], _state)-2, _state)+ae_sqr(ae_sqr(state->x.ptr.p_double[1], _state)+s, _state)+ae_sqr(state->x.ptr.p_double[2]-state->x.ptr.p_double[0], _state); } if( state->needfg ) { state->g.ptr.p_double[0] = 2*(ae_exp(state->x.ptr.p_double[0], _state)-2)*ae_exp(state->x.ptr.p_double[0], _state)+2*(state->x.ptr.p_double[0]-state->x.ptr.p_double[2]); state->g.ptr.p_double[1] = 2*(ae_sqr(state->x.ptr.p_double[1], _state)+s)*2*state->x.ptr.p_double[1]; state->g.ptr.p_double[2] = 2*(state->x.ptr.p_double[2]-state->x.ptr.p_double[0]); } } else { if( state->needf||state->needfg ) { state->f = ae_sqrt(ae_maxrealnumber, _state); } if( state->needfg ) { state->g.ptr.p_double[0] = ae_sqrt(ae_maxrealnumber, _state); state->g.ptr.p_double[1] = (double)(0); state->g.ptr.p_double[2] = (double)(0); } } } /************************************************************************* Calculate test function IIP2 f(x) = sum( ((i*i+1)*x[i])^2, i=0..N-1) It has high condition number which makes fast convergence unlikely without good preconditioner. *************************************************************************/ static void testminlbfgsunit_calciip2(minlbfgsstate* state, ae_int_t n, ae_state *_state) { ae_int_t i; if( state->needf||state->needfg ) { state->f = (double)(0); } for(i=0; i<=n-1; i++) { if( state->needf||state->needfg ) { state->f = state->f+ae_sqr((double)(i*i+1), _state)*ae_sqr(state->x.ptr.p_double[i], _state); } if( state->needfg ) { state->g.ptr.p_double[i] = ae_sqr((double)(i*i+1), _state)*2*state->x.ptr.p_double[i]; } } } /************************************************************************* This function tests preconditioning On failure sets Err to True (leaves it unchanged otherwise) *************************************************************************/ static void testminlbfgsunit_testpreconditioning(ae_bool* err, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t cntb1; ae_int_t cntb2; ae_int_t cntg1; ae_int_t cntg2; double epsg; ae_int_t pkind; minlbfgsstate state; minlbfgsreport rep; ae_vector x; ae_vector s; ae_matrix a; ae_vector diagh; ae_frame_make(_state, &_frame_block); _minlbfgsstate_init(&state, _state); _minlbfgsreport_init(&rep, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&diagh, 0, DT_REAL, _state); m = 1; k = 50; epsg = 1.0E-10; /* * Preconditioner test1. * * If * * B1 is default preconditioner * * B2 is Cholesky preconditioner with unit diagonal * * G1 is Cholesky preconditioner based on exact Hessian with perturbations * * G2 is diagonal precomditioner based on approximate diagonal of Hessian matrix * then "bad" preconditioners (B1/B2/..) are worse than "good" ones (G1/G2/..). * "Worse" means more iterations to converge. * * We test it using f(x) = sum( ((i*i+1)*x[i])^2, i=0..N-1) and L-BFGS * optimizer with deliberately small M=1. * * N - problem size * PKind - zero for upper triangular preconditioner, one for lower triangular. * K - number of repeated passes (should be large enough to average out random factors) */ for(n=10; n<=15; n++) { pkind = ae_randominteger(2, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(0); } minlbfgscreate(n, m, &x, &state, _state); /* * Test it with default preconditioner */ minlbfgssetprecdefault(&state, _state); cntb1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_calciip2(&state, n, _state); } minlbfgsresults(&state, &x, &rep, _state); cntb1 = cntb1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Test it with unit preconditioner */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_double[i][i] = (double)(1); } else { a.ptr.pp_double[i][j] = (double)(0); } } } minlbfgssetpreccholesky(&state, &a, pkind==0, _state); cntb2 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_calciip2(&state, n, _state); } minlbfgsresults(&state, &x, &rep, _state); cntb2 = cntb2+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Test it with perturbed Hessian preconditioner */ ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_double[i][i] = (i*i+1)*(0.8+0.4*ae_randomreal(_state)); } else { if( (pkind==0&&j>i)||(pkind==1&&jv_nan; } } } } minlbfgssetpreccholesky(&state, &a, pkind==0, _state); cntg1 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_calciip2(&state, n, _state); } minlbfgsresults(&state, &x, &rep, _state); cntg1 = cntg1+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Test it with perturbed diagonal preconditioner */ ae_vector_set_length(&diagh, n, _state); for(i=0; i<=n-1; i++) { diagh.ptr.p_double[i] = 2*ae_sqr((double)(i*i+1), _state)*(0.8+0.4*ae_randomreal(_state)); } minlbfgssetprecdiag(&state, &diagh, _state); cntg2 = 0; for(pass=0; pass<=k-1; pass++) { for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minlbfgsrestartfrom(&state, &x, _state); while(minlbfgsiteration(&state, _state)) { testminlbfgsunit_calciip2(&state, n, _state); } minlbfgsresults(&state, &x, &rep, _state); cntg2 = cntg2+rep.iterationscount; *err = *err||rep.terminationtype<=0; } /* * Compare */ *err = *err||cntb1=0.999999 * * where c is either 1.0 or 1.0E+6, M is either 1.0E8, 1.0E20 or +INF * (we try different combinations) */ for(ckind=0; ckind<=1; ckind++) { for(mkind=0; mkind<=2; mkind++) { /* * Choose c and M */ vc = (double)(1); vm = (double)(1); if( ckind==0 ) { vc = 1.0; } if( ckind==1 ) { vc = 1.0E+6; } if( mkind==0 ) { vm = 1.0E+8; } if( mkind==1 ) { vm = 1.0E+20; } if( mkind==2 ) { vm = _state->v_posinf; } /* * Create optimizer, solve optimization problem */ epsg = 1.0E-6*vc; ae_vector_set_length(&x, 1, _state); x.ptr.p_double[0] = 0.0; minlbfgscreate(1, 1, &x, &state, _state); minlbfgssetcond(&state, epsg, (double)(0), (double)(0), 0, _state); while(minlbfgsiteration(&state, _state)) { if( state.needfg ) { if( ae_fp_less(-0.999999,state.x.ptr.p_double[0])&&ae_fp_less(state.x.ptr.p_double[0],0.999999) ) { state.f = 1/(1-state.x.ptr.p_double[0])+1/(1+state.x.ptr.p_double[0])+vc*state.x.ptr.p_double[0]; state.g.ptr.p_double[0] = 1/ae_sqr(1-state.x.ptr.p_double[0], _state)-1/ae_sqr(1+state.x.ptr.p_double[0], _state)+vc; } else { state.f = vm; } } } minlbfgsresults(&state, &x, &rep, _state); if( rep.terminationtype<=0 ) { *err = ae_true; ae_frame_leave(_state); return; } *err = *err||ae_fp_greater(ae_fabs(1/ae_sqr(1-x.ptr.p_double[0], _state)-1/ae_sqr(1+x.ptr.p_double[0], _state)+vc, _state),epsg); } } /* * Test integrity checks for NAN/INF: * * algorithm solves optimization problem, which is normal for some time (quadratic) * * after 5-th step we choose random component of gradient and consistently spoil * it by NAN or INF. * * we check that correct termination code is returned (-8) */ n = 100; for(pass=1; pass<=10; pass++) { spoiliteration = 5; stopiteration = 8; if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { /* * Gradient can be spoiled by +INF, -INF, NAN */ spoilvar = hqrnduniformi(&rs, n, _state); i = hqrnduniformi(&rs, 3, _state); spoilval = _state->v_nan; if( i==0 ) { spoilval = _state->v_neginf; } if( i==1 ) { spoilval = _state->v_posinf; } } else { /* * Function value can be spoiled only by NAN * (+INF can be recognized as legitimate value during optimization) */ spoilvar = -1; spoilval = _state->v_nan; } spdmatrixrndcond(n, 1.0E5, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } minlbfgscreate(n, 1, &x0, &state, _state); minlbfgssetcond(&state, 0.0, 0.0, 0.0, stopiteration, _state); minlbfgssetxrep(&state, ae_true, _state); k = -1; while(minlbfgsiteration(&state, _state)) { if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.f = state.f+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.g.ptr.p_double[i] = state.g.ptr.p_double[i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } if( k>=spoiliteration ) { if( spoilvar<0 ) { state.f = spoilval; } else { state.g.ptr.p_double[spoilvar] = spoilval; } } continue; } if( state.xupdated ) { inc(&k, _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minlbfgsresults(&state, &x1, &rep, _state); seterrorflag(err, rep.terminationtype!=-8, _state); } /* * Check algorithm ability to handle request for termination: * * to terminate with correct return code = 8 * * to return point which was "current" at the moment of termination */ for(pass=1; pass<=50; pass++) { n = 3; ss = (double)(100); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6+ae_randomreal(_state); } stopcallidx = ae_randominteger(20, _state); maxits = 25; minlbfgscreate(n, 1, &x, &state, _state); minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), maxits, _state); minlbfgssetxrep(&state, ae_true, _state); callidx = 0; terminationrequested = ae_false; ae_v_move(&xlast.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); while(minlbfgsiteration(&state, _state)) { if( state.needfg ) { state.f = ss*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); state.g.ptr.p_double[0] = 2*ss*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0])*(-1); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); if( callidx==stopcallidx ) { minlbfgsrequesttermination(&state, _state); terminationrequested = ae_true; } inc(&callidx, _state); continue; } if( state.xupdated ) { if( !terminationrequested ) { ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minlbfgsresults(&state, &x, &rep, _state); seterrorflag(err, rep.terminationtype!=8, _state); for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]), _state); } } ae_frame_leave(_state); } /************************************************************************* This function tests, that gradient verified correctly. *************************************************************************/ static ae_bool testminlbfgsunit_gradientchecktest(ae_state *_state) { ae_frame _frame_block; minlbfgsstate state; minlbfgsreport rep; ae_int_t m; ae_int_t n; double a; double b; double c; double d; double x0; double x1; double x2; ae_vector x; double teststep; double noise; ae_int_t nbrcomp; ae_int_t func; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_bool result; ae_frame_make(_state, &_frame_block); _minlbfgsstate_init(&state, _state); _minlbfgsreport_init(&rep, _state); ae_vector_init(&x, 0, DT_REAL, _state); passcount = 35; teststep = 0.01; n = 3; m = 2; ae_vector_set_length(&x, n, _state); for(pass=1; pass<=passcount; pass++) { /* * Prepare test's parameters */ func = ae_randominteger(3, _state)+1; nbrcomp = ae_randominteger(n, _state); noise = (double)(10*(2*ae_randominteger(2, _state)-1)); /* * Prepare function's parameters */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 5*randomnormal(_state); } a = 5*ae_randomreal(_state)+1; b = 5*ae_randomreal(_state)+1; c = 5*ae_randomreal(_state)+1; d = 5*ae_randomreal(_state)+1; x0 = 5*(2*ae_randomreal(_state)-1); x1 = 5*(2*ae_randomreal(_state)-1); x2 = 5*(2*ae_randomreal(_state)-1); minlbfgscreate(n, m, &x, &state, _state); minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 0, _state); minlbfgssetgradientcheck(&state, teststep, _state); /* * Check that the criterion passes a derivative if it is correct */ while(minlbfgsiteration(&state, _state)) { if( state.needfg ) { testminlbfgsunit_funcderiv(a, b, c, d, x0, x1, x2, &state.x, func, &state.f, &state.g, _state); } } minlbfgsresults(&state, &x, &rep, _state); /* * Check that error code does not equal to -7 and parameter .VarIdx * equal to -1. */ if( rep.terminationtype==-7||rep.varidx!=-1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 5*randomnormal(_state); } minlbfgsrestartfrom(&state, &x, _state); /* * Check that the criterion does not miss a derivative if * it is incorrect */ while(minlbfgsiteration(&state, _state)) { if( state.needfg ) { testminlbfgsunit_funcderiv(a, b, c, d, x0, x1, x2, &state.x, func, &state.f, &state.g, _state); state.g.ptr.p_double[nbrcomp] = state.g.ptr.p_double[nbrcomp]+noise; } } minlbfgsresults(&state, &x, &rep, _state); /* * Check that error code equal to -7 and parameter .VarIdx * equal to number of incorrect component. */ if( rep.terminationtype!=-7||rep.varidx!=nbrcomp ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function return function value and it derivatives. Function dimension is 3. Function's list: * funcType=1: F(X)=A*(X-X0)^2+B*(Y-Y0)^2+C*(Z-Z0)^2+D; * funcType=2: F(X)=A*sin(X-X0)^2+B*sin(Y-Y0)^2+C*sin(Z-Z0)^2+D; * funcType=3: F(X)=A*(X-X0)^2+B*(Y-Y0)^2+C*((Z-Z0)-(X-X0))^2+D. *************************************************************************/ static void testminlbfgsunit_funcderiv(double a, double b, double c, double d, double x0, double x1, double x2, /* Real */ ae_vector* x, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state) { ae_assert(((ae_isfinite(a, _state)&&ae_isfinite(b, _state))&&ae_isfinite(c, _state))&&ae_isfinite(d, _state), "FuncDeriv: A, B, C or D contains NaN or Infinite.", _state); ae_assert((ae_isfinite(x0, _state)&&ae_isfinite(x1, _state))&&ae_isfinite(x2, _state), "FuncDeriv: X0, X1 or X2 contains NaN or Infinite.", _state); ae_assert(functype>=1&&functype<=3, "FuncDeriv: incorrect funcType(funcType<1 or funcType>3).", _state); if( functype==1 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2, _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x2); return; } if( functype==2 ) { *f = a*ae_sqr(ae_sin(x->ptr.p_double[0]-x0, _state), _state)+b*ae_sqr(ae_sin(x->ptr.p_double[1]-x1, _state), _state)+c*ae_sqr(ae_sin(x->ptr.p_double[2]-x2, _state), _state)+d; g->ptr.p_double[0] = 2*a*ae_sin(x->ptr.p_double[0]-x0, _state)*ae_cos(x->ptr.p_double[0]-x0, _state); g->ptr.p_double[1] = 2*b*ae_sin(x->ptr.p_double[1]-x1, _state)*ae_cos(x->ptr.p_double[1]-x1, _state); g->ptr.p_double[2] = 2*c*ae_sin(x->ptr.p_double[2]-x2, _state)*ae_cos(x->ptr.p_double[2]-x2, _state); return; } if( functype==3 ) { *f = a*ae_sqr(x->ptr.p_double[0]-x0, _state)+b*ae_sqr(x->ptr.p_double[1]-x1, _state)+c*ae_sqr(x->ptr.p_double[2]-x2-(x->ptr.p_double[0]-x0), _state)+d; g->ptr.p_double[0] = 2*a*(x->ptr.p_double[0]-x0)+2*c*(x->ptr.p_double[0]-x->ptr.p_double[2]-x0+x2); g->ptr.p_double[1] = 2*b*(x->ptr.p_double[1]-x1); g->ptr.p_double[2] = 2*c*(x->ptr.p_double[2]-x->ptr.p_double[0]-x2+x0); return; } } static ae_bool testmlptrainunit_testmlptraines(ae_state *_state); static ae_bool testmlptrainunit_testmlptrainregr(ae_state *_state); static ae_bool testmlptrainunit_testmlpxorregr(ae_state *_state); static ae_bool testmlptrainunit_testmlptrainclass(ae_state *_state); static ae_bool testmlptrainunit_testmlpxorcls(ae_state *_state); static ae_bool testmlptrainunit_testmlpzeroweights(ae_state *_state); static ae_bool testmlptrainunit_testmlprestarts(ae_state *_state); static ae_bool testmlptrainunit_testmlpcverror(ae_state *_state); static ae_bool testmlptrainunit_testmlptrainens(ae_state *_state); static ae_bool testmlptrainunit_testmlptrainensregr(ae_state *_state); static ae_bool testmlptrainunit_testmlptrainenscls(ae_state *_state); ae_bool testmlptrain(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_int_t maxn; ae_int_t maxhid; ae_int_t info; multilayerperceptron network; multilayerperceptron network2; mlpreport rep; mlpcvreport cvrep; ae_matrix xy; ae_matrix valxy; ae_bool trnerrors; ae_bool mlpcverrorerr; ae_bool mlptrainregrerr; ae_bool mlptrainclasserr; ae_bool mlprestartserr; ae_bool mlpxorregrerr; ae_bool mlpxorclserr; ae_bool mlptrainenserrors; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); _multilayerperceptron_init(&network2, _state); _mlpreport_init(&rep, _state); _mlpcvreport_init(&cvrep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&valxy, 0, 0, DT_REAL, _state); waserrors = ae_false; trnerrors = ae_false; mlpcverrorerr = ae_false; mlptrainregrerr = ae_false; mlptrainclasserr = ae_false; mlprestartserr = ae_false; mlpxorregrerr = ae_false; mlpxorclserr = ae_false; mlptrainenserrors = ae_false; maxn = 4; maxhid = 4; /* * Test network training on simple XOR problem */ ae_matrix_set_length(&xy, 3+1, 2+1, _state); xy.ptr.pp_double[0][0] = (double)(-1); xy.ptr.pp_double[0][1] = (double)(-1); xy.ptr.pp_double[0][2] = (double)(-1); xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(-1); xy.ptr.pp_double[1][2] = (double)(1); xy.ptr.pp_double[2][0] = (double)(-1); xy.ptr.pp_double[2][1] = (double)(1); xy.ptr.pp_double[2][2] = (double)(1); xy.ptr.pp_double[3][0] = (double)(1); xy.ptr.pp_double[3][1] = (double)(1); xy.ptr.pp_double[3][2] = (double)(-1); mlpcreate1(2, 2, 1, &network, _state); mlptrainlm(&network, &xy, 4, 0.001, 10, &info, &rep, _state); trnerrors = trnerrors||ae_fp_greater(mlprmserror(&network, &xy, 4, _state),0.1); /* * Test early stopping */ trnerrors = trnerrors||testmlptrainunit_testmlptraines(_state); /* * Test for function MLPFoldCV() */ mlpcverrorerr = testmlptrainunit_testmlpcverror(_state); /* * Test for training functions */ mlptrainregrerr = testmlptrainunit_testmlptrainregr(_state)||testmlptrainunit_testmlpzeroweights(_state); mlptrainclasserr = testmlptrainunit_testmlptrainclass(_state); mlprestartserr = testmlptrainunit_testmlprestarts(_state); mlpxorregrerr = testmlptrainunit_testmlpxorregr(_state); mlpxorclserr = testmlptrainunit_testmlpxorcls(_state); /* * Training for ensembles */ mlptrainenserrors = (testmlptrainunit_testmlptrainens(_state)||testmlptrainunit_testmlptrainensregr(_state))||testmlptrainunit_testmlptrainenscls(_state); /* * Final report */ waserrors = ((((((trnerrors||mlptrainregrerr)||mlptrainclasserr)||mlprestartserr)||mlpxorregrerr)||mlpxorclserr)||mlpcverrorerr)||mlptrainenserrors; if( !silent ) { printf("MLP TEST\n"); printf("CROSS-VALIDATION ERRORS: "); if( !mlpcverrorerr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("TRAINING: "); if( !trnerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("TRAIN -LM -LBFGS FOR REGRESSION: "); if( mlptrainregrerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TRAIN -LM -LBFGS FOR CLASSIFIER: "); if( mlptrainclasserr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("PARAMETER RESTARTS IN TRAIN -LBFGS: "); if( mlprestartserr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TRAINIG WITH TRAINER FOR REGRESSION: "); if( mlpxorregrerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TRAINIG WITH TRAINER FOR CLASSIFIER: "); if( mlpxorclserr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TRAINING ENSEMBLES: "); if( mlptrainenserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testmlptrain(ae_bool silent, ae_state *_state) { return testmlptrain(silent, _state); } /************************************************************************* This function tests MLPTrainES(). It returns True in case of errors, False when no errors were detected *************************************************************************/ static ae_bool testmlptrainunit_testmlptraines(ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t passcount; multilayerperceptron network; ae_matrix trnxy; ae_matrix valxy; ae_vector x; ae_vector y; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t nrestarts; ae_int_t info; mlpreport rep; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&network, _state); ae_matrix_init(&trnxy, 0, 0, DT_REAL, _state); ae_matrix_init(&valxy, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _mlpreport_init(&rep, _state); result = ae_false; /* * First test checks that MLPTrainES() - when training set is equal to the validation * set, MLPTrainES() behaves just like a "normal" training algorithm. * * Test sequence: * * generate training set - 100 random points from 2D square [-1,+1]*[-1,+1] * * generate network with 2 inputs, no hidden layers, nonlinear output layer, * use its outputs as target values for the test set * * randomize network * * train with MLPTrainES(), using original set as both training and validation set * * trained network must reproduce training set with good precision * * NOTE: it is important to test algorithm on nonlinear network because linear * problems converge too fast. Slow convergence is important to detect * some kinds of bugs. * * NOTE: it is important to have NRestarts at least equal to 5, because with just * one restart algorithm fails test about once in several thousands of passes. */ passcount = 10; nrestarts = 5; for(pass=1; pass<=passcount; pass++) { /* * Create network, generate training/validation sets */ mlpcreater0(2, 1, -2.0, 2.0, &network, _state); mlprandomize(&network, _state); n = 100; ae_matrix_set_length(&trnxy, n, 3, _state); ae_matrix_set_length(&valxy, n, 3, _state); ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&y, 1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=1; j++) { trnxy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; valxy.ptr.pp_double[i][j] = trnxy.ptr.pp_double[i][j]; x.ptr.p_double[j] = trnxy.ptr.pp_double[i][j]; } mlpprocess(&network, &x, &y, _state); trnxy.ptr.pp_double[i][2] = y.ptr.p_double[0]; valxy.ptr.pp_double[i][2] = y.ptr.p_double[0]; } mlprandomize(&network, _state); mlptraines(&network, &trnxy, n, &valxy, n, 0.0001, nrestarts, &info, &rep, _state); if( info<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } if( ae_fp_greater(ae_sqrt(mlperror(&network, &valxy, n, _state)/n, _state),0.01) ) { result = ae_true; ae_frame_leave(_state); return result; } } ae_frame_leave(_state); return result; } /************************************************************************* This function tests MLPTrainLM, MLPTrainLBFGS and MLPTrainNetwork functions for regression. It check that train functions work correctly. Test use Create1 with 10 neurons. Test function is f(x,y)=X^2+cos(3*Pi*y). *************************************************************************/ static ae_bool testmlptrainunit_testmlptrainregr(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; mlptrainer trainer; mlpreport rep; ae_int_t info; ae_matrix xy; sparsematrix sm; ae_vector x; ae_vector y; ae_int_t n; ae_int_t sn; ae_int_t nneurons; double vdecay; double averr; double st; double eps; double traineps; ae_int_t nneedrest; ae_int_t trainits; ae_int_t shift; ae_int_t i; ae_int_t j; ae_int_t vtrain; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); _mlptrainer_init(&trainer, _state); _mlpreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _sparsematrix_init(&sm, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); eps = 0.01; vdecay = 0.001; nneurons = 10; nneedrest = 5; traineps = 1.0E-3; trainits = 0; sn = 5; n = sn*sn; st = (double)2/(double)(sn-1); sparsecreate(n, 3, n*3, &sm, _state); ae_matrix_set_length(&xy, n, 3, _state); ae_vector_set_length(&x, 2, _state); for(vtrain=0; vtrain<=3; vtrain++) { averr = (double)(0); /* * Create a train set(uniformly distributed set of points). */ for(i=0; i<=sn-1; i++) { for(j=0; j<=sn-1; j++) { shift = i*sn+j; xy.ptr.pp_double[shift][0] = i*st-1.0; xy.ptr.pp_double[shift][1] = j*st-1.0; xy.ptr.pp_double[shift][2] = xy.ptr.pp_double[shift][0]*xy.ptr.pp_double[shift][0]+ae_cos(3*ae_pi*xy.ptr.pp_double[shift][1], _state); } } /* * Create and train a neural network */ mlpcreate1(2, nneurons, 1, &net, _state); if( vtrain==0 ) { mlptrainlm(&net, &xy, n, vdecay, nneedrest, &info, &rep, _state); } if( vtrain==1 ) { mlptrainlbfgs(&net, &xy, n, vdecay, nneedrest, traineps, trainits, &info, &rep, _state); } /* * Train with trainer, using: * * dense matrix; */ if( vtrain==2 ) { mlpcreatetrainer(2, 1, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } /* * * sparse matrix. */ if( vtrain==3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=2; j++) { sparseset(&sm, i, j, xy.ptr.pp_double[i][j], _state); } } mlpcreatetrainer(2, 1, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } /* * Check that network is trained correctly */ for(i=0; i<=n-1; i++) { x.ptr.p_double[0] = xy.ptr.pp_double[i][0]; x.ptr.p_double[1] = xy.ptr.pp_double[i][1]; mlpprocess(&net, &x, &y, _state); /* * Calculate average error */ averr = averr+ae_fabs(y.ptr.p_double[0]-xy.ptr.pp_double[i][2], _state); } if( ae_fp_greater(averr/n,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests MLPTrainNetwork/MLPStartTraining/MLPContinueTraining functions for regression. It check that train functions work correctly. Test use Create1 with 2 neurons. Test function is XOR(x,y). *************************************************************************/ static ae_bool testmlptrainunit_testmlpxorregr(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; mlptrainer trainer; mlpreport rep; ae_matrix xy; sparsematrix sm; ae_vector x; ae_vector y; ae_int_t n; ae_int_t sn; ae_int_t nneurons; double vdecay; double averr; double eps; ae_int_t numxp; double traineps; ae_int_t nneedrest; ae_int_t trainits; ae_int_t shift; ae_int_t i; ae_int_t j; ae_int_t vtrain; ae_int_t xp; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); _mlptrainer_init(&trainer, _state); _mlpreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _sparsematrix_init(&sm, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); eps = 0.01; numxp = 15; vdecay = 0.001; nneurons = 3; nneedrest = 1; traineps = 1.0E-4; trainits = 0; sn = 2; n = sn*sn; sparsecreate(n, 3, n*3, &sm, _state); ae_matrix_set_length(&xy, n, 3, _state); ae_vector_set_length(&x, 2, _state); for(xp=1; xp<=numxp; xp++) { for(vtrain=0; vtrain<=3; vtrain++) { averr = (double)(0); /* * Create a train set(uniformly distributed set of points). */ for(i=0; i<=sn-1; i++) { for(j=0; j<=sn-1; j++) { shift = i*sn+j; xy.ptr.pp_double[shift][0] = (double)(i); xy.ptr.pp_double[shift][1] = (double)(j); if( ae_fp_eq(xy.ptr.pp_double[shift][0],xy.ptr.pp_double[shift][1]) ) { xy.ptr.pp_double[shift][2] = (double)(0); } else { xy.ptr.pp_double[shift][2] = (double)(1); } } } /* * Create and train a neural network */ mlpcreate1(2, nneurons, 1, &net, _state); /* * Train with trainer, using: * * dense matrix; */ if( vtrain==0 ) { mlpcreatetrainer(2, 1, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } if( vtrain==1 ) { mlpcreatetrainer(2, 1, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlpstarttraining(&trainer, &net, ae_true, _state); while(mlpcontinuetraining(&trainer, &net, _state)) { } } /* * * sparse matrix. */ if( vtrain==2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=2; j++) { sparseset(&sm, i, j, xy.ptr.pp_double[i][j], _state); } } mlpcreatetrainer(2, 1, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } if( vtrain==3 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=2; j++) { sparseset(&sm, i, j, xy.ptr.pp_double[i][j], _state); } } mlpcreatetrainer(2, 1, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlpstarttraining(&trainer, &net, ae_true, _state); while(mlpcontinuetraining(&trainer, &net, _state)) { } } /* * Check that network is trained correctly */ for(i=0; i<=n-1; i++) { x.ptr.p_double[0] = xy.ptr.pp_double[i][0]; x.ptr.p_double[1] = xy.ptr.pp_double[i][1]; mlpprocess(&net, &x, &y, _state); /* * Calculate average error */ averr = averr+ae_fabs(y.ptr.p_double[0]-xy.ptr.pp_double[i][2], _state); } if( ae_fp_greater(averr/n,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests MLPTrainLM, MLPTrainLBFGS and MLPTrainNetwork functions for classification problems. It check that train functions work correctly when is used CreateC1 function. Here the network tries to distinguish positive from negative numbers. *************************************************************************/ static ae_bool testmlptrainunit_testmlptrainclass(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; mlptrainer trainer; mlpreport rep; ae_int_t info; ae_matrix xy; sparsematrix sm; ae_vector x; ae_vector y; ae_int_t n; double vdecay; double traineps; ae_int_t nneedrest; ae_int_t trainits; double tmp; double mnc; double mxc; ae_int_t nxp; ae_int_t i; ae_int_t rndind; ae_int_t vtrain; ae_int_t xp; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); _mlptrainer_init(&trainer, _state); _mlpreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _sparsematrix_init(&sm, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); mnc = (double)(10); mxc = (double)(11); nxp = 15; vdecay = 0.001; nneedrest = 10; traineps = 1.0E-4; trainits = 0; n = 100; sparsecreate(n, 2, n*2, &sm, _state); ae_vector_set_length(&x, 1, _state); ae_matrix_set_length(&xy, n, 2, _state); for(xp=1; xp<=nxp; xp++) { for(vtrain=0; vtrain<=3; vtrain++) { /* * Initialization: * * create negative part of the set; */ for(i=0; i<=n/2-1; i++) { xy.ptr.pp_double[i][0] = -1*((mxc-mnc)*ae_randomreal(_state)+mnc); xy.ptr.pp_double[i][1] = (double)(0); } /* * * create positive part of the set; */ for(i=n/2; i<=n-1; i++) { xy.ptr.pp_double[i][0] = (mxc-mnc)*ae_randomreal(_state)+mnc; xy.ptr.pp_double[i][1] = (double)(1); } /* * * mix two parts. */ for(i=0; i<=n-1; i++) { do { rndind = ae_randominteger(n, _state); } while(rndind==i); tmp = xy.ptr.pp_double[i][0]; xy.ptr.pp_double[i][0] = xy.ptr.pp_double[rndind][0]; xy.ptr.pp_double[rndind][0] = tmp; tmp = xy.ptr.pp_double[i][1]; xy.ptr.pp_double[i][1] = xy.ptr.pp_double[rndind][1]; xy.ptr.pp_double[rndind][1] = tmp; } /* * Create and train a neural network */ mlpcreatec0(1, 2, &net, _state); if( vtrain==0 ) { mlptrainlm(&net, &xy, n, vdecay, nneedrest, &info, &rep, _state); } if( vtrain==1 ) { mlptrainlbfgs(&net, &xy, n, vdecay, nneedrest, traineps, trainits, &info, &rep, _state); } /* * Train with trainer, using: * * dense matrix; */ if( vtrain==2 ) { mlpcreatetrainercls(1, 2, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } /* * * sparse matrix. */ if( vtrain==3 ) { for(i=0; i<=n-1; i++) { sparseset(&sm, i, 0, xy.ptr.pp_double[i][0], _state); sparseset(&sm, i, 1, xy.ptr.pp_double[i][1], _state); } mlpcreatetrainercls(1, 2, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } /* * Test on training set */ for(i=0; i<=n-1; i++) { x.ptr.p_double[0] = xy.ptr.pp_double[i][0]; mlpprocess(&net, &x, &y, _state); /* * Negative number has to be negative and * positive number has to be positive. */ if( ((ae_fp_less(x.ptr.p_double[0],(double)(0))&&ae_fp_less(y.ptr.p_double[0],0.95))&&ae_fp_greater(y.ptr.p_double[1],0.05))||((ae_fp_greater_eq(x.ptr.p_double[0],(double)(0))&&ae_fp_greater(y.ptr.p_double[0],0.05))&&ae_fp_less(y.ptr.p_double[1],0.95)) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Test on random set */ for(i=0; i<=n-1; i++) { x.ptr.p_double[0] = ae_pow((double)(-1), (double)(ae_randominteger(2, _state)), _state)*((mxc-mnc)*ae_randomreal(_state)+mnc); mlpprocess(&net, &x, &y, _state); if( ((ae_fp_less(x.ptr.p_double[0],(double)(0))&&ae_fp_less(y.ptr.p_double[0],0.95))&&ae_fp_greater(y.ptr.p_double[1],0.05))||((ae_fp_greater_eq(x.ptr.p_double[0],(double)(0))&&ae_fp_greater(y.ptr.p_double[0],0.05))&&ae_fp_less(y.ptr.p_double[1],0.95)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests MLPTrainNetwork/MLPStartTraining/MLPContinueTraining functions for classification problems. It check that train functions work correctly when is used CreateC1 function. Here the network tries to distinguish positive from negative numbers. *************************************************************************/ static ae_bool testmlptrainunit_testmlpxorcls(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; mlptrainer trainer; mlpreport rep; ae_matrix xy; sparsematrix sm; ae_vector x; ae_vector y; ae_int_t n; ae_int_t nin; ae_int_t nout; ae_int_t wcount; double e; double ebest; double v; ae_vector wbest; double vdecay; double traineps; ae_int_t nneurons; ae_int_t nneedrest; ae_int_t trainits; ae_int_t nxp; ae_int_t i; ae_int_t vtrain; ae_int_t xp; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); _mlptrainer_init(&trainer, _state); _mlpreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _sparsematrix_init(&sm, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&wbest, 0, DT_REAL, _state); nxp = 15; nneurons = 3; vdecay = 0.001; nneedrest = 3; traineps = 1.0E-4; trainits = 0; n = 4; sparsecreate(n, 3, n*3, &sm, _state); ae_vector_set_length(&x, 2, _state); ae_matrix_set_length(&xy, n, 3, _state); /* * Initialization: */ xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(0); xy.ptr.pp_double[0][2] = (double)(0); xy.ptr.pp_double[1][0] = (double)(0); xy.ptr.pp_double[1][1] = (double)(1); xy.ptr.pp_double[1][2] = (double)(1); xy.ptr.pp_double[2][0] = (double)(1); xy.ptr.pp_double[2][1] = (double)(0); xy.ptr.pp_double[2][2] = (double)(1); xy.ptr.pp_double[3][0] = (double)(1); xy.ptr.pp_double[3][1] = (double)(1); xy.ptr.pp_double[3][2] = (double)(0); /* * Create a neural network */ mlpcreatec1(2, nneurons, 2, &net, _state); mlpproperties(&net, &nin, &nout, &wcount, _state); ae_vector_set_length(&wbest, wcount, _state); /* * Test */ for(xp=1; xp<=nxp; xp++) { for(vtrain=0; vtrain<=3; vtrain++) { /* * Train with trainer, using: * * dense matrix; */ if( vtrain==0 ) { mlpcreatetrainercls(2, 2, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } if( vtrain==1 ) { mlpcreatetrainercls(2, 2, &trainer, _state); mlpsetdataset(&trainer, &xy, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); ebest = ae_maxrealnumber; for(i=1; i<=nneedrest; i++) { mlpstarttraining(&trainer, &net, ae_true, _state); while(mlpcontinuetraining(&trainer, &net, _state)) { } v = ae_v_dotproduct(&net.weights.ptr.p_double[0], 1, &net.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = mlperror(&net, &xy, n, _state)+0.5*vdecay*v; /* * Compare with the best answer. */ if( ae_fp_less(e,ebest) ) { ae_v_move(&wbest.ptr.p_double[0], 1, &net.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ebest = e; } } /* * The best result */ ae_v_move(&net.weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } /* * * sparse matrix. */ if( vtrain==2 ) { for(i=0; i<=n-1; i++) { sparseset(&sm, i, 0, xy.ptr.pp_double[i][0], _state); sparseset(&sm, i, 1, xy.ptr.pp_double[i][1], _state); sparseset(&sm, i, 2, xy.ptr.pp_double[i][2], _state); } mlpcreatetrainercls(2, 2, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } if( vtrain==3 ) { for(i=0; i<=n-1; i++) { sparseset(&sm, i, 0, xy.ptr.pp_double[i][0], _state); sparseset(&sm, i, 1, xy.ptr.pp_double[i][1], _state); sparseset(&sm, i, 2, xy.ptr.pp_double[i][2], _state); } mlpcreatetrainercls(2, 2, &trainer, _state); mlpsetsparsedataset(&trainer, &sm, n, _state); mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); ebest = ae_maxrealnumber; for(i=1; i<=nneedrest; i++) { mlpstarttraining(&trainer, &net, ae_true, _state); while(mlpcontinuetraining(&trainer, &net, _state)) { } v = ae_v_dotproduct(&net.weights.ptr.p_double[0], 1, &net.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); e = mlperror(&net, &xy, n, _state)+0.5*vdecay*v; /* * Compare with the best answer. */ if( ae_fp_less(e,ebest) ) { ae_v_move(&wbest.ptr.p_double[0], 1, &net.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); ebest = e; } } /* * The best result */ ae_v_move(&net.weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); } /* * Test on training set */ for(i=0; i<=n-1; i++) { x.ptr.p_double[0] = xy.ptr.pp_double[i][0]; x.ptr.p_double[1] = xy.ptr.pp_double[i][1]; mlpprocess(&net, &x, &y, _state); if( ((ae_fp_eq(x.ptr.p_double[0],x.ptr.p_double[1])&&ae_fp_less(y.ptr.p_double[0],0.95))&&ae_fp_greater(y.ptr.p_double[1],0.05))||((ae_fp_neq(x.ptr.p_double[0],x.ptr.p_double[1])&&ae_fp_greater(y.ptr.p_double[0],0.05))&&ae_fp_less(y.ptr.p_double[1],0.95)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The test check, that all weights are zero after training with trainer using empty dataset(either zero size or is't used MLPSetDataSet function). Test on regression and classification problems given by dense or sparse matrix. NOTE: Result of the function is written in MLPTrainRegrErr variable in unit test. *************************************************************************/ static ae_bool testmlptrainunit_testmlpzeroweights(ae_state *_state) { ae_frame _frame_block; mlptrainer trainer; multilayerperceptron net; mlpreport rep; ae_int_t nin; ae_int_t nout; ae_int_t wcount; ae_int_t mxnin; ae_int_t mxnout; double vdecay; double traineps; ae_int_t trainits; ae_int_t nneedrest; ae_matrix dds; sparsematrix sds; ae_bool iscls; ae_bool issparse; ae_int_t c; ae_int_t n; ae_int_t mnn; ae_int_t mxn; ae_int_t xp; ae_int_t nxp; ae_bool result; ae_frame_make(_state, &_frame_block); _mlptrainer_init(&trainer, _state); _multilayerperceptron_init(&net, _state); _mlpreport_init(&rep, _state); ae_matrix_init(&dds, 0, 0, DT_REAL, _state); _sparsematrix_init(&sds, _state); mxn = 20; mnn = 10; mxnin = 10; mxnout = 10; vdecay = 1.0E-3; nneedrest = 1; traineps = 1.0E-3; trainits = 0; sparsecreate(1, 1, 0, &sds, _state); sparseconverttocrs(&sds, _state); nxp = 10; for(xp=1; xp<=nxp; xp++) { c = ae_randominteger(2, _state); iscls = c==1; c = ae_randominteger(2, _state); issparse = c==1; /* * Create trainer and network */ if( !iscls ) { /* * Regression */ nin = ae_randominteger(mxnin, _state)+1; nout = ae_randominteger(mxnout, _state)+1; mlpcreatetrainer(nin, nout, &trainer, _state); mlpcreate0(nin, nout, &net, _state); } else { /* * Classification */ nin = ae_randominteger(mxnin, _state)+1; nout = ae_randominteger(mxnout, _state)+2; mlpcreatetrainercls(nin, nout, &trainer, _state); mlpcreatec0(nin, nout, &net, _state); } n = ae_randominteger(2, _state)-1; if( n==0 ) { if( !issparse ) { mlpsetdataset(&trainer, &dds, n, _state); } else { mlpsetsparsedataset(&trainer, &sds, n, _state); } } mlpsetdecay(&trainer, vdecay, _state); mlpsetcond(&trainer, traineps, trainits, _state); c = ae_randominteger(2, _state); if( c==0 ) { mlpstarttraining(&trainer, &net, ae_true, _state); while(mlpcontinuetraining(&trainer, &net, _state)) { } } if( c==1 ) { mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); } /* * Check weights */ mlpproperties(&net, &nin, &nout, &wcount, _state); for(c=0; c<=wcount-1; c++) { if( ae_fp_neq(net.weights.ptr.p_double[c],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests that increasing numbers of restarts lead to statistical improvement quality of solution. Neural network created by Create1(10 neurons) and trained by MLPTrainLBFGS. TEST's DISCRIPTION: Net0 - network trained with one restart (denoted as R1) Net1 - network trained with more than one restart (denoted as Rn) We must refuse hypothesis that R1 equivalent to Rn. Here Mean = N/2, Sigma = Sqrt(N)/2. _ | 0 - R1 worse than Rn; ri = | |_1 - Rn same or worse then R1. If Sum(ri)1 restarts. */ mlpproperties(&net1, &nin, &nout, &wcount1, _state); e1 = ae_v_dotproduct(&net1.weights.ptr.p_double[0], 1, &net1.weights.ptr.p_double[0], 1, ae_v_len(0,wcount1-1)); e1 = mlperrorn(&net1, &xy, n, _state)+0.5*vdecay*e1; if( ae_fp_less_eq(e0,e1) ) { avval = avval+1; } } if( ae_fp_less(mean-numsigma,avval) ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The function test function MLPKFoldCV. *************************************************************************/ static ae_bool testmlptrainunit_testmlpcverror(ae_state *_state) { ae_frame _frame_block; multilayerperceptron net; mlptrainer trainer; mlpreport rep; mlpreport cvrep; ae_int_t nin; ae_int_t nout; ae_int_t nneurons; ae_int_t rowsz; double decay; double wstep; ae_int_t maxits; ae_int_t foldscount; ae_int_t nneedrest; sparsematrix sptrainingset; ae_matrix trainingset; ae_matrix testset; ae_int_t npoints; ae_int_t ntstpoints; double mean; double numsigma; double diffms; double tstrelclserror; double tstavgce; double tstrmserror; double tstavgerror; double tstavgrelerror; ae_int_t r0; ae_int_t r1; ae_int_t r2; ae_int_t r3; ae_int_t r4; ae_int_t ntest; ae_int_t xp; ae_int_t nxp; ae_bool isregr; ae_int_t issparse; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _multilayerperceptron_init(&net, _state); _mlptrainer_init(&trainer, _state); _mlpreport_init(&rep, _state); _mlpreport_init(&cvrep, _state); _sparsematrix_init(&sptrainingset, _state); ae_matrix_init(&trainingset, 0, 0, DT_REAL, _state); ae_matrix_init(&testset, 0, 0, DT_REAL, _state); decay = 1.0E-6; wstep = 0.0; foldscount = 5; nneedrest = 1; ntest = ae_randominteger(4, _state); nxp = 1000; maxits = 50; nin = 1; nout = 1; npoints = 5; ntstpoints = 100; isregr = ae_true; nneurons = 3; if( ntest==1 ) { nxp = 1000; maxits = 50; nin = 1; nout = 10; npoints = 5; ntstpoints = 100; isregr = ae_true; } if( ntest==2 ) { nxp = 1000; maxits = 50; nin = 10; nout = 1; npoints = 20; ntstpoints = 100; isregr = ae_true; } if( ntest==3 ) { nxp = 2000; maxits = 10; nin = 1; nneurons = 3; nout = 3; npoints = 10; ntstpoints = 100; isregr = ae_false; } mean = nxp/2.0; numsigma = 5.0*ae_sqrt((double)(nxp), _state)/2.0; diffms = mean-numsigma; issparse = ae_randominteger(2, _state); if( isregr ) { mlpcreate0(nin, nout, &net, _state); mlpcreatetrainer(nin, nout, &trainer, _state); } else { mlpcreatec1(nin, nneurons, nout, &net, _state); mlpcreatetrainercls(nin, nout, &trainer, _state); } mlpsetcond(&trainer, wstep, maxits, _state); mlpsetdecay(&trainer, decay, _state); if( isregr ) { rowsz = nin+nout; } else { rowsz = nin+1; } r0 = 0; r1 = 0; r2 = 0; r3 = 0; r4 = 0; for(xp=1; xp<=nxp; xp++) { /* * Dense matrix */ if( issparse==0 ) { rmatrixsetlengthatleast(&trainingset, npoints, rowsz, _state); /* * Create training set */ for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin-1; j++) { trainingset.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } if( isregr ) { for(i=0; i<=npoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { trainingset.ptr.pp_double[i][j] = 2*ae_randomreal(_state)+1; } } } else { for(i=0; i<=npoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { trainingset.ptr.pp_double[i][j] = (double)(ae_randominteger(nout, _state)); } } } mlpsetdataset(&trainer, &trainingset, npoints, _state); } /* * Sparse matrix */ if( issparse==1 ) { sparsecreate(npoints, rowsz, npoints*rowsz, &sptrainingset, _state); /* * Create training set */ for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin-1; j++) { sparseset(&sptrainingset, i, j, 2*ae_randomreal(_state)-1, _state); } } if( isregr ) { for(i=0; i<=npoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { sparseset(&sptrainingset, i, j, 2*ae_randomreal(_state)+1, _state); } } } else { for(i=0; i<=npoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { sparseset(&sptrainingset, i, j, (double)(ae_randominteger(nout, _state)), _state); } } } sparseconverttocrs(&sptrainingset, _state); mlpsetsparsedataset(&trainer, &sptrainingset, npoints, _state); } rmatrixsetlengthatleast(&testset, ntstpoints, rowsz, _state); /* * Create test set */ for(i=0; i<=ntstpoints-1; i++) { for(j=0; j<=nin-1; j++) { testset.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } if( isregr ) { for(i=0; i<=ntstpoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { testset.ptr.pp_double[i][j] = 2*ae_randomreal(_state)+1; } } } else { for(i=0; i<=ntstpoints-1; i++) { for(j=nin; j<=rowsz-1; j++) { testset.ptr.pp_double[i][j] = (double)(ae_randominteger(nout, _state)); } } } mlptrainnetwork(&trainer, &net, nneedrest, &rep, _state); tstrelclserror = (double)(0); tstavgce = (double)(0); tstrmserror = (double)(0); tstavgerror = (double)(0); tstavgrelerror = (double)(0); if( !isregr ) { tstrelclserror = mlprelclserror(&net, &testset, ntstpoints, _state); tstavgce = mlpavgce(&net, &testset, ntstpoints, _state); } tstrmserror = mlprmserror(&net, &testset, ntstpoints, _state); tstavgerror = mlpavgerror(&net, &testset, ntstpoints, _state); tstavgrelerror = mlpavgrelerror(&net, &testset, ntstpoints, _state); /* * Cross-validation */ mlpkfoldcv(&trainer, &net, nneedrest, foldscount, &cvrep, _state); if( !isregr ) { if( ae_fp_less(ae_fabs(tstrelclserror-rep.relclserror, _state),ae_fabs(tstrelclserror-cvrep.relclserror, _state)) ) { r0 = r0+1; } if( ae_fp_less(ae_fabs(tstavgce-rep.avgce, _state),ae_fabs(tstavgce-cvrep.avgce, _state)) ) { r1 = r1+1; } } if( ae_fp_less(ae_fabs(tstrmserror-rep.rmserror, _state),ae_fabs(tstrmserror-cvrep.rmserror, _state)) ) { r2 = r2+1; } if( ae_fp_less(ae_fabs(tstavgerror-rep.avgerror, _state),ae_fabs(tstavgerror-cvrep.avgerror, _state)) ) { r3 = r3+1; } if( ae_fp_less(ae_fabs(tstavgrelerror-rep.avgrelerror, _state),ae_fabs(tstavgrelerror-cvrep.avgrelerror, _state)) ) { r4 = r4+1; } } if( !isregr ) { if( ae_fp_less_eq(diffms,(double)(r0))||ae_fp_less_eq(diffms,(double)(r1)) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( (ae_fp_less_eq(diffms,(double)(r2))||ae_fp_less_eq(diffms,(double)(r3)))||ae_fp_less_eq(diffms,(double)(r4)) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Test FoldCV when no dataset was specified with * MLPSetDataset/SetSparseDataset(), or subset with * only one point was given. * * NPoints values: * * -1 - don't set dataset with using MLPSetDataset..; * * 0 - zero dataset; * * 1 - dataset with one point. */ for(npoints=-1; npoints<=1; npoints++) { if( isregr ) { mlpcreatetrainer(nin, nout, &trainer, _state); } else { mlpcreatetrainercls(nin, nout, &trainer, _state); } if( npoints>-1 ) { if( issparse==0 ) { mlpsetdataset(&trainer, &trainingset, npoints, _state); } if( issparse==1 ) { mlpsetsparsedataset(&trainer, &sptrainingset, npoints, _state); } } mlpkfoldcv(&trainer, &net, nneedrest, foldscount, &cvrep, _state); if( ((((((ae_fp_neq(cvrep.relclserror,(double)(0))||ae_fp_neq(cvrep.avgce,(double)(0)))||ae_fp_neq(cvrep.rmserror,(double)(0)))||ae_fp_neq(cvrep.avgerror,(double)(0)))||ae_fp_neq(cvrep.avgrelerror,(double)(0)))||cvrep.ngrad!=0)||cvrep.nhess!=0)||cvrep.ncholesky!=0 ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The function tests functions for training ensembles: MLPEBaggingLM, MLPEBaggingLBFGS. *************************************************************************/ static ae_bool testmlptrainunit_testmlptrainens(ae_state *_state) { ae_frame _frame_block; mlpensemble ensemble; mlpreport rep; mlpcvreport oobrep; ae_int_t info; ae_matrix xy; ae_int_t nin; ae_int_t nout; ae_int_t npoints; ae_int_t nhid; ae_int_t algtype; ae_int_t tasktype; ae_int_t pass; double e; ae_int_t nless; ae_int_t nall; ae_int_t nclasses; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _mlpensemble_init(&ensemble, _state); _mlpreport_init(&rep, _state); _mlpcvreport_init(&oobrep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); result = ae_false; /* * network training must reduce error * test on random regression task */ nin = 3; nout = 2; nhid = 5; npoints = 100; nless = 0; nall = 0; for(pass=1; pass<=10; pass++) { for(algtype=0; algtype<=1; algtype++) { for(tasktype=0; tasktype<=1; tasktype++) { if( tasktype==0 ) { ae_matrix_set_length(&xy, npoints, nin+nout, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin+nout-1; j++) { xy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } mlpecreate1(nin, nhid, nout, 1+ae_randominteger(3, _state), &ensemble, _state); } else { ae_matrix_set_length(&xy, npoints, nin+1, _state); nclasses = 2+ae_randominteger(2, _state); for(i=0; i<=npoints-1; i++) { for(j=0; j<=nin-1; j++) { xy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } xy.ptr.pp_double[i][nin] = (double)(ae_randominteger(nclasses, _state)); } mlpecreatec1(nin, nhid, nclasses, 1+ae_randominteger(3, _state), &ensemble, _state); } e = mlpermserror(&ensemble, &xy, npoints, _state); if( algtype==0 ) { mlpebagginglm(&ensemble, &xy, npoints, 0.001, 1, &info, &rep, &oobrep, _state); } else { mlpebagginglbfgs(&ensemble, &xy, npoints, 0.001, 1, 0.01, 0, &info, &rep, &oobrep, _state); } if( info<0 ) { result = ae_true; } else { if( ae_fp_less(mlpermserror(&ensemble, &xy, npoints, _state),e) ) { nless = nless+1; } } nall = nall+1; } } } result = result||ae_fp_greater((double)(nall-nless),0.3*nall); ae_frame_leave(_state); return result; } /************************************************************************* Testing for functions MLPETrainES and MLPTrainEnsembleES on regression problems. Returns TRUE for errors, FALSE for success. *************************************************************************/ static ae_bool testmlptrainunit_testmlptrainensregr(ae_state *_state) { ae_frame _frame_block; mlptrainer trainer; mlpensemble netens; mlpreport rep; modelerrors repx; ae_int_t info; sparsematrix xytrainsp; ae_matrix xytrain; ae_matrix xytest; ae_int_t nin; ae_int_t nout; ae_int_t nneurons; ae_vector x; ae_vector y; double decay; double wstep; ae_int_t maxits; ae_int_t nneedrest; ae_int_t enssize; double mnval; double mxval; ae_int_t ntrain; ae_int_t ntest; double avgerr; ae_int_t issparse; ae_int_t withtrainer; double eps; ae_int_t xp; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _mlptrainer_init(&trainer, _state); _mlpensemble_init(&netens, _state); _mlpreport_init(&rep, _state); _modelerrors_init(&repx, _state); _sparsematrix_init(&xytrainsp, _state); ae_matrix_init(&xytrain, 0, 0, DT_REAL, _state); ae_matrix_init(&xytest, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); result = ae_false; /* * This test checks ability to train ensemble on simple regression * problem "f(x0,x1,x2,...) = x0 + x1 + x2 + ...". */ eps = 5.0E-2; mnval = (double)(-1); mxval = (double)(1); ntrain = 40; ntest = 20; decay = 1.0E-3; wstep = 1.0E-3; maxits = 20; nneedrest = 1; nneurons = 20; nout = 1; enssize = 100; for(xp=1; xp<=2; xp++) { nin = ae_randominteger(3, _state)+1; rvectorsetlengthatleast(&x, nin, _state); mlpcreatetrainer(nin, nout, &trainer, _state); mlpsetdecay(&trainer, decay, _state); mlpsetcond(&trainer, wstep, maxits, _state); rmatrixsetlengthatleast(&xytrain, ntrain, nin+nout, _state); rmatrixsetlengthatleast(&xytest, ntest, nin+nout, _state); withtrainer = ae_randominteger(2, _state); issparse = 0; if( withtrainer==0 ) { issparse = 0; } if( withtrainer==1 ) { issparse = ae_randominteger(2, _state); } /* * Training set */ for(i=0; i<=ntrain-1; i++) { for(j=0; j<=nin-1; j++) { xytrain.ptr.pp_double[i][j] = (mxval-mnval)*ae_randomreal(_state)+mnval; } xytrain.ptr.pp_double[i][nin] = (double)(0); for(j=0; j<=nin-1; j++) { xytrain.ptr.pp_double[i][nin] = xytrain.ptr.pp_double[i][nin]+xytrain.ptr.pp_double[i][j]; } } if( withtrainer==1 ) { /* * Dense matrix */ if( issparse==0 ) { mlpsetdataset(&trainer, &xytrain, ntrain, _state); } /* * Sparse matrix */ if( issparse==1 ) { sparsecreate(ntrain, nin+nout, ntrain*(nin+nout), &xytrainsp, _state); /* * Just copy dense matrix to sparse matrix(using SparseGet() is too expensive). */ for(i=0; i<=ntrain-1; i++) { for(j=0; j<=nin+nout-1; j++) { sparseset(&xytrainsp, i, j, xytrain.ptr.pp_double[i][j], _state); } } sparseconverttocrs(&xytrainsp, _state); mlpsetsparsedataset(&trainer, &xytrainsp, ntrain, _state); } } /* * Test set */ for(i=0; i<=ntest-1; i++) { for(j=0; j<=nin-1; j++) { xytest.ptr.pp_double[i][j] = (mxval-mnval)*ae_randomreal(_state)+mnval; } xytest.ptr.pp_double[i][nin] = (double)(0); for(j=0; j<=nin-1; j++) { xytest.ptr.pp_double[i][nin] = xytest.ptr.pp_double[i][nin]+xytest.ptr.pp_double[i][j]; } } /* * Create ensemble */ mlpecreate1(nin, nneurons, nout, enssize, &netens, _state); /* * Train ensembles: * * without trainer; */ if( withtrainer==0 ) { mlpetraines(&netens, &xytrain, ntrain, decay, nneedrest, &info, &rep, _state); } /* * * with trainer. */ if( withtrainer==1 ) { mlptrainensemblees(&trainer, &netens, nneedrest, &rep, _state); } /* * Test that Rep contains correct error values */ mlpeallerrorsx(&netens, &xytrain, &xytrainsp, ntrain, 0, &netens.network.dummyidx, 0, ntrain, 0, &netens.network.buf, &repx, _state); seterrorflagdiff(&result, rep.relclserror, repx.relclserror, 1.0E-4, 1.0E-2, _state); seterrorflagdiff(&result, rep.avgce, repx.avgce, 1.0E-4, 1.0E-2, _state); seterrorflagdiff(&result, rep.rmserror, repx.rmserror, 1.0E-4, 1.0E-2, _state); seterrorflagdiff(&result, rep.avgerror, repx.avgerror, 1.0E-4, 1.0E-2, _state); seterrorflagdiff(&result, rep.avgrelerror, repx.avgrelerror, 1.0E-4, 1.0E-2, _state); /* * Test that network fits data well. Calculate average error: * * on training dataset; * * on test dataset. (here we reduce the accuracy * requirements - average error is compared with 2*Eps). */ avgerr = (double)(0); for(i=0; i<=ntrain-1; i++) { if( issparse==0 ) { ae_v_move(&x.ptr.p_double[0], 1, &xytrain.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); } if( issparse==1 ) { sparsegetrow(&xytrainsp, i, &x, _state); } mlpeprocess(&netens, &x, &y, _state); avgerr = avgerr+ae_fabs(y.ptr.p_double[0]-xytrain.ptr.pp_double[i][nin], _state); } avgerr = avgerr/ntrain; seterrorflag(&result, ae_fp_greater(avgerr,eps), _state); avgerr = (double)(0); for(i=0; i<=ntest-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xytest.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); mlpeprocess(&netens, &x, &y, _state); avgerr = avgerr+ae_fabs(y.ptr.p_double[0]-xytest.ptr.pp_double[i][nin], _state); } avgerr = avgerr/ntest; seterrorflag(&result, ae_fp_greater(avgerr,2*eps), _state); } /* * Catch bug in implementation of MLPTrainEnsembleX: * test ensemble training on empty dataset. * * Unfixed version should crash with violation of array * bounds (at least in C#). */ nin = 2; nout = 2; nneurons = 3; enssize = 3; nneedrest = 2; wstep = 0.001; maxits = 2; mlpcreatetrainer(nin, nout, &trainer, _state); mlpsetcond(&trainer, wstep, maxits, _state); mlpecreate1(nin, nneurons, nout, enssize, &netens, _state); mlptrainensemblees(&trainer, &netens, nneedrest, &rep, _state); ae_frame_leave(_state); return result; } /************************************************************************* Testing for functions MLPETrainES and MLPTrainEnsembleES on classification problems. *************************************************************************/ static ae_bool testmlptrainunit_testmlptrainenscls(ae_state *_state) { ae_frame _frame_block; mlptrainer trainer; mlpensemble netens; mlpreport rep; ae_int_t info; sparsematrix xytrainsp; ae_matrix xytrain; ae_matrix xytest; ae_int_t nin; ae_int_t nout; ae_vector x; ae_vector y; double decay; double wstep; ae_int_t maxits; ae_int_t nneedrest; ae_int_t enssize; ae_int_t val; ae_int_t ntrain; ae_int_t ntest; double avgerr; double eps; double delta; ae_int_t issparse; ae_int_t withtrainer; ae_int_t xp; ae_int_t nxp; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _mlptrainer_init(&trainer, _state); _mlpensemble_init(&netens, _state); _mlpreport_init(&rep, _state); _sparsematrix_init(&xytrainsp, _state); ae_matrix_init(&xytrain, 0, 0, DT_REAL, _state); ae_matrix_init(&xytest, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); eps = 5.0E-2; delta = 0.1; ntrain = 90; ntest = 90; nin = 3; nout = 3; rvectorsetlengthatleast(&x, nin, _state); rmatrixsetlengthatleast(&xytrain, ntrain, nin+1, _state); rmatrixsetlengthatleast(&xytest, ntest, nin+1, _state); decay = 1.0E-3; wstep = 1.0E-3; maxits = 100; nneedrest = 1; mlpcreatetrainercls(nin, nout, &trainer, _state); mlpsetdecay(&trainer, decay, _state); mlpsetcond(&trainer, wstep, maxits, _state); nxp = 5; for(xp=1; xp<=nxp; xp++) { enssize = ae_round(ae_pow((double)(10), (double)(ae_randominteger(2, _state)+1), _state), _state); withtrainer = ae_randominteger(2, _state); issparse = 0; if( withtrainer==0 ) { issparse = 0; } if( withtrainer==1 ) { issparse = ae_randominteger(2, _state); } for(i=0; i<=ntrain-1; i++) { val = i%nin; for(j=0; j<=nin-1; j++) { xytrain.ptr.pp_double[i][j] = delta*(ae_randomreal(_state)-1); } xytrain.ptr.pp_double[i][val] = xytrain.ptr.pp_double[i][val]+1; xytrain.ptr.pp_double[i][nin] = (double)(val); } /* * Set dense dataset in trainer */ if( issparse==0 ) { mlpsetdataset(&trainer, &xytrain, ntrain, _state); } /* * * Sparse dataset(create it with using dense dataset). */ if( issparse==1 ) { sparsecreate(ntrain, nin+1, ntrain*(nin+1), &xytrainsp, _state); for(i=0; i<=ntrain-1; i++) { for(j=0; j<=nin-1; j++) { sparseset(&xytrainsp, i, j, xytrain.ptr.pp_double[i][j], _state); } sparseset(&xytrainsp, i, nin, xytrain.ptr.pp_double[i][nin], _state); } sparseconverttocrs(&xytrainsp, _state); /* * Set sparse dataset in trainer */ mlpsetsparsedataset(&trainer, &xytrainsp, ntrain, _state); } /* * Create test set */ for(i=0; i<=ntest-1; i++) { val = ae_randominteger(nin, _state); for(j=0; j<=nin-1; j++) { xytest.ptr.pp_double[i][j] = delta*(ae_randomreal(_state)-1); } xytest.ptr.pp_double[i][val] = xytest.ptr.pp_double[i][val]+1; xytest.ptr.pp_double[i][nin] = (double)(val); } /* * Create ensemble */ mlpecreatec0(nin, nout, enssize, &netens, _state); /* * Train ensembles: * * without trainer; */ if( withtrainer==0 ) { mlpetraines(&netens, &xytrain, ntrain, decay, nneedrest, &info, &rep, _state); } /* * * with trainer. */ if( withtrainer==1 ) { mlptrainensemblees(&trainer, &netens, nneedrest, &rep, _state); } /* * Calculate average error: * * on training dataset; */ avgerr = (double)(0); for(i=0; i<=ntrain-1; i++) { if( issparse==0 ) { ae_v_move(&x.ptr.p_double[0], 1, &xytrain.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); } if( issparse==1 ) { sparsegetrow(&xytrainsp, i, &x, _state); } mlpeprocess(&netens, &x, &y, _state); for(j=0; j<=nout-1; j++) { if( ae_fp_neq((double)(j),xytrain.ptr.pp_double[i][nin]) ) { avgerr = avgerr+y.ptr.p_double[j]; } else { avgerr = avgerr+(1-y.ptr.p_double[j]); } } } avgerr = avgerr/(ntrain*nout); if( ae_fp_greater(avgerr,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * * on test dataset. */ avgerr = (double)(0); for(i=0; i<=ntest-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xytest.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); mlpeprocess(&netens, &x, &y, _state); for(j=0; j<=nout-1; j++) { if( ae_fp_neq((double)(j),xytest.ptr.pp_double[i][nin]) ) { avgerr = avgerr+y.ptr.p_double[j]; } else { avgerr = avgerr+(1-y.ptr.p_double[j]); } } } avgerr = avgerr/(ntest*nout); if( ae_fp_greater(avgerr,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } static void testpcaunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state); ae_bool testpca(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t passcount; ae_int_t maxn; ae_int_t maxm; double threshold; ae_int_t m; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t info; ae_vector means; ae_vector s; ae_vector t2; ae_vector t3; ae_matrix v; ae_matrix x; double t; double h; double tmean; double tmeans; double tstddev; double tstddevs; double tmean2; double tmeans2; double tstddev2; double tstddevs2; ae_bool pcaconverrors; ae_bool pcaorterrors; ae_bool pcavarerrors; ae_bool pcaopterrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&means, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_init(&t3, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_matrix_init(&x, 0, 0, DT_REAL, _state); /* * Primary settings */ maxm = 10; maxn = 100; passcount = 1; threshold = 1000*ae_machineepsilon; waserrors = ae_false; pcaconverrors = ae_false; pcaorterrors = ae_false; pcavarerrors = ae_false; pcaopterrors = ae_false; /* * Test 1: N random points in M-dimensional space */ for(m=1; m<=maxm; m++) { for(n=1; n<=maxn; n++) { /* * Generate task */ ae_matrix_set_length(&x, n-1+1, m-1+1, _state); ae_vector_set_length(&means, m-1+1, _state); for(j=0; j<=m-1; j++) { means.ptr.p_double[j] = 1.5*ae_randomreal(_state)-0.75; } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = means.ptr.p_double[j]+(2*ae_randomreal(_state)-1); } } /* * Solve */ pcabuildbasis(&x, n, m, &info, &s, &v, _state); if( info!=1 ) { pcaconverrors = ae_true; continue; } /* * Orthogonality test */ for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { t = ae_v_dotproduct(&v.ptr.pp_double[0][i], v.stride, &v.ptr.pp_double[0][j], v.stride, ae_v_len(0,m-1)); if( i==j ) { t = t-1; } pcaorterrors = pcaorterrors||ae_fp_greater(ae_fabs(t, _state),threshold); } } /* * Variance test */ ae_vector_set_length(&t2, n-1+1, _state); for(k=0; k<=m-1; k++) { for(i=0; i<=n-1; i++) { t = ae_v_dotproduct(&x.ptr.pp_double[i][0], 1, &v.ptr.pp_double[0][k], v.stride, ae_v_len(0,m-1)); t2.ptr.p_double[i] = t; } testpcaunit_calculatemv(&t2, n, &tmean, &tmeans, &tstddev, &tstddevs, _state); if( n!=1 ) { t = ae_sqr(tstddev, _state)*n/(n-1); } else { t = (double)(0); } pcavarerrors = pcavarerrors||ae_fp_greater(ae_fabs(t-s.ptr.p_double[k], _state),threshold); } for(k=0; k<=m-2; k++) { pcavarerrors = pcavarerrors||ae_fp_less(s.ptr.p_double[k],s.ptr.p_double[k+1]); } /* * Optimality: different perturbations in V[..,0] can't * increase variance of projection - can only decrease. */ ae_vector_set_length(&t2, n-1+1, _state); ae_vector_set_length(&t3, n-1+1, _state); for(i=0; i<=n-1; i++) { t = ae_v_dotproduct(&x.ptr.pp_double[i][0], 1, &v.ptr.pp_double[0][0], v.stride, ae_v_len(0,m-1)); t2.ptr.p_double[i] = t; } testpcaunit_calculatemv(&t2, n, &tmean, &tmeans, &tstddev, &tstddevs, _state); for(k=0; k<=2*m-1; k++) { h = 0.001; if( k%2!=0 ) { h = -h; } ae_v_move(&t3.ptr.p_double[0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_addd(&t3.ptr.p_double[0], 1, &x.ptr.pp_double[0][k/2], x.stride, ae_v_len(0,n-1), h); t = (double)(0); for(j=0; j<=m-1; j++) { if( j!=k/2 ) { t = t+ae_sqr(v.ptr.pp_double[j][0], _state); } else { t = t+ae_sqr(v.ptr.pp_double[j][0]+h, _state); } } t = 1/ae_sqrt(t, _state); ae_v_muld(&t3.ptr.p_double[0], 1, ae_v_len(0,n-1), t); testpcaunit_calculatemv(&t3, n, &tmean2, &tmeans2, &tstddev2, &tstddevs2, _state); pcaopterrors = pcaopterrors||ae_fp_greater(tstddev2,tstddev+threshold); } } } /* * Special test for N=0 */ for(m=1; m<=maxm; m++) { /* * Solve */ pcabuildbasis(&x, 0, m, &info, &s, &v, _state); if( info!=1 ) { pcaconverrors = ae_true; continue; } /* * Orthogonality test */ for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { t = ae_v_dotproduct(&v.ptr.pp_double[0][i], v.stride, &v.ptr.pp_double[0][j], v.stride, ae_v_len(0,m-1)); if( i==j ) { t = t-1; } pcaorterrors = pcaorterrors||ae_fp_greater(ae_fabs(t, _state),threshold); } } } /* * Final report */ waserrors = ((pcaconverrors||pcaorterrors)||pcavarerrors)||pcaopterrors; if( !silent ) { printf("PCA TEST\n"); printf("TOTAL RESULTS: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* CONVERGENCE "); if( !pcaconverrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* ORTOGONALITY "); if( !pcaorterrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* VARIANCE REPORT "); if( !pcavarerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* OPTIMALITY "); if( !pcaopterrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testpca(ae_bool silent, ae_state *_state) { return testpca(silent, _state); } /************************************************************************* Moments estimates and their errors *************************************************************************/ static void testpcaunit_calculatemv(/* Real */ ae_vector* x, ae_int_t n, double* mean, double* means, double* stddev, double* stddevs, ae_state *_state) { ae_int_t i; double v1; double v2; double variance; *mean = 0; *means = 0; *stddev = 0; *stddevs = 0; *mean = (double)(0); *means = (double)(1); *stddev = (double)(0); *stddevs = (double)(1); variance = (double)(0); if( n<=1 ) { return; } /* * Mean */ for(i=0; i<=n-1; i++) { *mean = *mean+x->ptr.p_double[i]; } *mean = *mean/n; /* * Variance (using corrected two-pass algorithm) */ if( n!=1 ) { v1 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); } v2 = (double)(0); for(i=0; i<=n-1; i++) { v2 = v2+(x->ptr.p_double[i]-(*mean)); } v2 = ae_sqr(v2, _state)/n; variance = (v1-v2)/n; if( ae_fp_less(variance,(double)(0)) ) { variance = (double)(0); } *stddev = ae_sqrt(variance, _state); } /* * Errors */ *means = *stddev/ae_sqrt((double)(n), _state); *stddevs = *stddev*ae_sqrt((double)(2), _state)/ae_sqrt((double)(n-1), _state); } /************************************************************************* Test *************************************************************************/ ae_bool testodesolver(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t passcount; ae_bool curerrors; ae_bool rkckerrors; ae_bool waserrors; ae_vector xtbl; ae_matrix ytbl; odesolverreport rep; ae_vector xg; ae_vector y; double h; double eps; ae_int_t solver; ae_int_t pass; ae_int_t mynfev; double v; ae_int_t m; ae_int_t m2; ae_int_t i; double err; odesolverstate state; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&xtbl, 0, DT_REAL, _state); ae_matrix_init(&ytbl, 0, 0, DT_REAL, _state); _odesolverreport_init(&rep, _state); ae_vector_init(&xg, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _odesolverstate_init(&state, _state); rkckerrors = ae_false; waserrors = ae_false; passcount = 10; /* * simple test: just A*sin(x)+B*cos(x) */ ae_assert(passcount>=2, "Assertion failed", _state); for(pass=0; pass<=passcount-1; pass++) { for(solver=0; solver<=0; solver++) { /* * prepare */ h = 1.0E-2; eps = 1.0E-5; if( pass%2==0 ) { eps = -eps; } ae_vector_set_length(&y, 2, _state); for(i=0; i<=1; i++) { y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } m = 2+ae_randominteger(10, _state); ae_vector_set_length(&xg, m, _state); xg.ptr.p_double[0] = (m-1)*ae_randomreal(_state); for(i=1; i<=m-1; i++) { xg.ptr.p_double[i] = xg.ptr.p_double[i-1]+ae_randomreal(_state); } v = 2*ae_pi/(xg.ptr.p_double[m-1]-xg.ptr.p_double[0]); ae_v_muld(&xg.ptr.p_double[0], 1, ae_v_len(0,m-1), v); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { ae_v_muld(&xg.ptr.p_double[0], 1, ae_v_len(0,m-1), -1); } mynfev = 0; /* * choose solver */ if( solver==0 ) { odesolverrkck(&y, 2, &xg, m, eps, h, &state, _state); } /* * solve */ while(odesolveriteration(&state, _state)) { state.dy.ptr.p_double[0] = state.y.ptr.p_double[1]; state.dy.ptr.p_double[1] = -state.y.ptr.p_double[0]; mynfev = mynfev+1; } odesolverresults(&state, &m2, &xtbl, &ytbl, &rep, _state); /* * check results */ curerrors = ae_false; if( rep.terminationtype<=0 ) { curerrors = ae_true; } else { curerrors = curerrors||m2!=m; err = (double)(0); for(i=0; i<=m-1; i++) { err = ae_maxreal(err, ae_fabs(ytbl.ptr.pp_double[i][0]-(y.ptr.p_double[0]*ae_cos(xtbl.ptr.p_double[i]-xtbl.ptr.p_double[0], _state)+y.ptr.p_double[1]*ae_sin(xtbl.ptr.p_double[i]-xtbl.ptr.p_double[0], _state)), _state), _state); err = ae_maxreal(err, ae_fabs(ytbl.ptr.pp_double[i][1]-(-y.ptr.p_double[0]*ae_sin(xtbl.ptr.p_double[i]-xtbl.ptr.p_double[0], _state)+y.ptr.p_double[1]*ae_cos(xtbl.ptr.p_double[i]-xtbl.ptr.p_double[0], _state)), _state), _state); } curerrors = curerrors||ae_fp_greater(err,10*ae_fabs(eps, _state)); curerrors = curerrors||mynfev!=rep.nfev; } if( solver==0 ) { rkckerrors = rkckerrors||curerrors; } } } /* * another test: * * y(0) = 0 * dy/dx = f(x,y) * f(x,y) = 0, x<1 * x-1, x>=1 * * with BOTH absolute and fractional tolerances. * Starting from zero will be real challenge for * fractional tolerance. */ ae_assert(passcount>=2, "Assertion failed", _state); for(pass=0; pass<=passcount-1; pass++) { h = 1.0E-4; eps = 1.0E-4; if( pass%2==0 ) { eps = -eps; } ae_vector_set_length(&y, 1, _state); y.ptr.p_double[0] = (double)(0); m = 21; ae_vector_set_length(&xg, m, _state); for(i=0; i<=m-1; i++) { xg.ptr.p_double[i] = (double)(2*i)/(double)(m-1); } mynfev = 0; odesolverrkck(&y, 1, &xg, m, eps, h, &state, _state); while(odesolveriteration(&state, _state)) { state.dy.ptr.p_double[0] = ae_maxreal(state.x-1, (double)(0), _state); mynfev = mynfev+1; } odesolverresults(&state, &m2, &xtbl, &ytbl, &rep, _state); if( rep.terminationtype<=0 ) { rkckerrors = ae_true; } else { rkckerrors = rkckerrors||m2!=m; err = (double)(0); for(i=0; i<=m-1; i++) { err = ae_maxreal(err, ae_fabs(ytbl.ptr.pp_double[i][0]-ae_sqr(ae_maxreal(xg.ptr.p_double[i]-1, (double)(0), _state), _state)/2, _state), _state); } rkckerrors = rkckerrors||ae_fp_greater(err,ae_fabs(eps, _state)); rkckerrors = rkckerrors||mynfev!=rep.nfev; } } /* * end */ waserrors = rkckerrors; if( !silent ) { printf("TESTING ODE SOLVER\n"); printf("* RK CASH-KARP: "); if( rkckerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testodesolver(ae_bool silent, ae_state *_state) { return testodesolver(silent, _state); } static void testfftunit_reffftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); static void testfftunit_reffftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); static void testfftunit_refinternalcfft(/* Real */ ae_vector* a, ae_int_t nn, ae_bool inversefft, ae_state *_state); static void testfftunit_refinternalrfft(/* Real */ ae_vector* a, ae_int_t nn, /* Complex */ ae_vector* f, ae_state *_state); static void testfftunit_quicktest(ae_int_t n, double* referr, double* refrerr, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testfft(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t k; ae_vector a1; ae_vector a2; ae_vector a3; ae_vector r1; ae_vector r2; ae_vector buf; fasttransformplan plan; ae_int_t maxsmalln; double bidierr; double bidirerr; double referr; double refrerr; double reinterr; double errtol; ae_bool referrors; ae_bool bidierrors; ae_bool refrerrors; ae_bool bidirerrors; ae_bool reinterrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a1, 0, DT_COMPLEX, _state); ae_vector_init(&a2, 0, DT_COMPLEX, _state); ae_vector_init(&a3, 0, DT_COMPLEX, _state); ae_vector_init(&r1, 0, DT_REAL, _state); ae_vector_init(&r2, 0, DT_REAL, _state); ae_vector_init(&buf, 0, DT_REAL, _state); _fasttransformplan_init(&plan, _state); maxsmalln = 128; errtol = 100000*ae_pow((double)(maxsmalln), (double)3/(double)2, _state)*ae_machineepsilon; bidierrors = ae_false; referrors = ae_false; bidirerrors = ae_false; refrerrors = ae_false; reinterrors = ae_false; waserrors = ae_false; /* * Test bi-directional error: norm(x-invFFT(FFT(x))) */ bidierr = (double)(0); bidirerr = (double)(0); for(n=1; n<=maxsmalln; n++) { /* * Complex FFT/invFFT */ ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); ae_vector_set_length(&a3, n, _state); for(i=0; i<=n-1; i++) { a1.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; a1.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; a2.ptr.p_complex[i] = a1.ptr.p_complex[i]; a3.ptr.p_complex[i] = a1.ptr.p_complex[i]; } fftc1d(&a2, n, _state); fftc1dinv(&a2, n, _state); fftc1dinv(&a3, n, _state); fftc1d(&a3, n, _state); for(i=0; i<=n-1; i++) { bidierr = ae_maxreal(bidierr, ae_c_abs(ae_c_sub(a1.ptr.p_complex[i],a2.ptr.p_complex[i]), _state), _state); bidierr = ae_maxreal(bidierr, ae_c_abs(ae_c_sub(a1.ptr.p_complex[i],a3.ptr.p_complex[i]), _state), _state); } /* * Real */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; } fftr1d(&r2, n, &a1, _state); ae_v_muld(&r2.ptr.p_double[0], 1, ae_v_len(0,n-1), 0); fftr1dinv(&a1, n, &r2, _state); for(i=0; i<=n-1; i++) { bidirerr = ae_maxreal(bidirerr, ae_c_abs(ae_complex_from_d(r1.ptr.p_double[i]-r2.ptr.p_double[i]), _state), _state); } } bidierrors = bidierrors||ae_fp_greater(bidierr,errtol); bidirerrors = bidirerrors||ae_fp_greater(bidirerr,errtol); /* * Test against reference O(N^2) implementation for small N's * (we do not test large N's because reference implementation will be too slow). */ referr = (double)(0); refrerr = (double)(0); for(n=1; n<=maxsmalln; n++) { /* * Complex FFT */ ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); for(i=0; i<=n-1; i++) { a1.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; a1.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; a2.ptr.p_complex[i] = a1.ptr.p_complex[i]; } fftc1d(&a1, n, _state); testfftunit_reffftc1d(&a2, n, _state); for(i=0; i<=n-1; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(a1.ptr.p_complex[i],a2.ptr.p_complex[i]), _state), _state); } /* * Complex inverse FFT */ ae_vector_set_length(&a1, n, _state); ae_vector_set_length(&a2, n, _state); for(i=0; i<=n-1; i++) { a1.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; a1.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; a2.ptr.p_complex[i] = a1.ptr.p_complex[i]; } fftc1dinv(&a1, n, _state); testfftunit_reffftc1dinv(&a2, n, _state); for(i=0; i<=n-1; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(a1.ptr.p_complex[i],a2.ptr.p_complex[i]), _state), _state); } /* * Real forward/inverse FFT: * * calculate and check forward FFT * * use precalculated FFT to check backward FFT * fill unused parts of frequencies array with random numbers * to ensure that they are not really used */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; } fftr1d(&r1, n, &a1, _state); testfftunit_refinternalrfft(&r2, n, &a2, _state); for(i=0; i<=n-1; i++) { refrerr = ae_maxreal(refrerr, ae_c_abs(ae_c_sub(a1.ptr.p_complex[i],a2.ptr.p_complex[i]), _state), _state); } ae_vector_set_length(&a3, ae_ifloor((double)n/(double)2, _state)+1, _state); for(i=0; i<=ae_ifloor((double)n/(double)2, _state); i++) { a3.ptr.p_complex[i] = a2.ptr.p_complex[i]; } a3.ptr.p_complex[0].y = 2*ae_randomreal(_state)-1; if( n%2==0 ) { a3.ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = (double)(0); } fftr1dinv(&a3, n, &r1, _state); for(i=0; i<=n-1; i++) { refrerr = ae_maxreal(refrerr, ae_fabs(r2.ptr.p_double[i]-r1.ptr.p_double[i], _state), _state); } } referrors = referrors||ae_fp_greater(referr,errtol); refrerrors = refrerrors||ae_fp_greater(refrerr,errtol); /* * Test for large N's: * * we perform FFT * * we selectively calculate K (small number) of DFT components (using reference formula) * and compare them with ones calculated by fast implementation * * K components to test are chosen at random (random sampling with possible repetitions) * * overall complexity of the test is O(N*logN+K*N) * Several N's are tested, with different kinds of factorizations */ referr = (double)(0); refrerr = (double)(0); testfftunit_quicktest(1000, &referr, &refrerr, _state); testfftunit_quicktest(1024, &referr, &refrerr, _state); testfftunit_quicktest(1025, &referr, &refrerr, _state); testfftunit_quicktest(2000, &referr, &refrerr, _state); testfftunit_quicktest(2048, &referr, &refrerr, _state); testfftunit_quicktest(6535, &referr, &refrerr, _state); testfftunit_quicktest(65536, &referr, &refrerr, _state); testfftunit_quicktest(104729, &referr, &refrerr, _state); testfftunit_quicktest(139129, &referr, &refrerr, _state); testfftunit_quicktest(141740, &referr, &refrerr, _state); referrors = referrors||ae_fp_greater(referr,errtol); refrerrors = refrerrors||ae_fp_greater(refrerr,errtol); /* * test internal real even FFT */ reinterr = (double)(0); for(k=1; k<=maxsmalln/2; k++) { n = 2*k; /* * Real forward FFT */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; } ftcomplexfftplan(n/2, 1, &plan, _state); ae_vector_set_length(&buf, n, _state); fftr1dinternaleven(&r1, n, &buf, &plan, _state); testfftunit_refinternalrfft(&r2, n, &a2, _state); reinterr = ae_maxreal(reinterr, ae_fabs(r1.ptr.p_double[0]-a2.ptr.p_complex[0].x, _state), _state); reinterr = ae_maxreal(reinterr, ae_fabs(r1.ptr.p_double[1]-a2.ptr.p_complex[n/2].x, _state), _state); for(i=1; i<=n/2-1; i++) { reinterr = ae_maxreal(reinterr, ae_fabs(r1.ptr.p_double[2*i+0]-a2.ptr.p_complex[i].x, _state), _state); reinterr = ae_maxreal(reinterr, ae_fabs(r1.ptr.p_double[2*i+1]-a2.ptr.p_complex[i].y, _state), _state); } /* * Real backward FFT */ ae_vector_set_length(&r1, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&a2, ae_ifloor((double)n/(double)2, _state)+1, _state); a2.ptr.p_complex[0] = ae_complex_from_d(r1.ptr.p_double[0]); for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) { a2.ptr.p_complex[i].x = r1.ptr.p_double[2*i+0]; a2.ptr.p_complex[i].y = r1.ptr.p_double[2*i+1]; } a2.ptr.p_complex[ae_ifloor((double)n/(double)2, _state)] = ae_complex_from_d(r1.ptr.p_double[1]); ftcomplexfftplan(n/2, 1, &plan, _state); ae_vector_set_length(&buf, n, _state); fftr1dinvinternaleven(&r1, n, &buf, &plan, _state); fftr1dinv(&a2, n, &r2, _state); for(i=0; i<=n-1; i++) { reinterr = ae_maxreal(reinterr, ae_fabs(r1.ptr.p_double[i]-r2.ptr.p_double[i], _state), _state); } } reinterrors = reinterrors||ae_fp_greater(reinterr,errtol); /* * end */ waserrors = (((bidierrors||bidirerrors)||referrors)||refrerrors)||reinterrors; if( !silent ) { printf("TESTING FFT\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BI-DIRECTIONAL COMPLEX TEST: "); if( bidierrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE COMPLEX FFT: "); if( referrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BI-DIRECTIONAL REAL TEST: "); if( bidirerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE REAL FFT: "); if( refrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* INTERNAL EVEN FFT: "); if( reinterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testfft(ae_bool silent, ae_state *_state) { return testfft(silent, _state); } /************************************************************************* Reference FFT *************************************************************************/ static void testfftunit_reffftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector buf; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&buf, 0, DT_REAL, _state); ae_assert(n>0, "FFTC1D: incorrect N!", _state); ae_vector_set_length(&buf, 2*n, _state); for(i=0; i<=n-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } testfftunit_refinternalcfft(&buf, n, ae_false, _state); for(i=0; i<=n-1; i++) { a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0]; a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* Reference inverse FFT *************************************************************************/ static void testfftunit_reffftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector buf; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_init(&buf, 0, DT_REAL, _state); ae_assert(n>0, "FFTC1DInv: incorrect N!", _state); ae_vector_set_length(&buf, 2*n, _state); for(i=0; i<=n-1; i++) { buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; } testfftunit_refinternalcfft(&buf, n, ae_true, _state); for(i=0; i<=n-1; i++) { a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0]; a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* Internal complex FFT stub. Uses straightforward formula with O(N^2) complexity. *************************************************************************/ static void testfftunit_refinternalcfft(/* Real */ ae_vector* a, ae_int_t nn, ae_bool inversefft, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_int_t k; double hre; double him; double c; double s; double re; double im; ae_frame_make(_state, &_frame_block); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_set_length(&tmp, 2*nn-1+1, _state); if( !inversefft ) { for(i=0; i<=nn-1; i++) { hre = (double)(0); him = (double)(0); for(k=0; k<=nn-1; k++) { re = a->ptr.p_double[2*k]; im = a->ptr.p_double[2*k+1]; c = ae_cos(-2*ae_pi*k*i/nn, _state); s = ae_sin(-2*ae_pi*k*i/nn, _state); hre = hre+c*re-s*im; him = him+c*im+s*re; } tmp.ptr.p_double[2*i] = hre; tmp.ptr.p_double[2*i+1] = him; } for(i=0; i<=2*nn-1; i++) { a->ptr.p_double[i] = tmp.ptr.p_double[i]; } } else { for(k=0; k<=nn-1; k++) { hre = (double)(0); him = (double)(0); for(i=0; i<=nn-1; i++) { re = a->ptr.p_double[2*i]; im = a->ptr.p_double[2*i+1]; c = ae_cos(2*ae_pi*k*i/nn, _state); s = ae_sin(2*ae_pi*k*i/nn, _state); hre = hre+c*re-s*im; him = him+c*im+s*re; } tmp.ptr.p_double[2*k] = hre/nn; tmp.ptr.p_double[2*k+1] = him/nn; } for(i=0; i<=2*nn-1; i++) { a->ptr.p_double[i] = tmp.ptr.p_double[i]; } } ae_frame_leave(_state); } /************************************************************************* Internal real FFT stub. Uses straightforward formula with O(N^2) complexity. *************************************************************************/ static void testfftunit_refinternalrfft(/* Real */ ae_vector* a, ae_int_t nn, /* Complex */ ae_vector* f, ae_state *_state) { ae_frame _frame_block; ae_vector tmp; ae_int_t i; ae_frame_make(_state, &_frame_block); ae_vector_clear(f); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_set_length(&tmp, 2*nn-1+1, _state); for(i=0; i<=nn-1; i++) { tmp.ptr.p_double[2*i] = a->ptr.p_double[i]; tmp.ptr.p_double[2*i+1] = (double)(0); } testfftunit_refinternalcfft(&tmp, nn, ae_false, _state); ae_vector_set_length(f, nn, _state); for(i=0; i<=nn-1; i++) { f->ptr.p_complex[i].x = tmp.ptr.p_double[2*i+0]; f->ptr.p_complex[i].y = tmp.ptr.p_double[2*i+1]; } ae_frame_leave(_state); } /************************************************************************* This function performs real/complex FFT of given length on random data, selects K random components and compares them with values calculated by DFT definition. It updates RefErr and RefRErr as follows: RefErr:= max(RefErr, error_of_complex_FFT) RefRErr:= max(RefRErr,error_of_real_FFT) *************************************************************************/ static void testfftunit_quicktest(ae_int_t n, double* referr, double* refrerr, ae_state *_state) { ae_frame _frame_block; ae_vector a0; ae_vector a1; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t idx; ae_complex v; double c; double s; double re; double im; ae_frame_make(_state, &_frame_block); ae_vector_init(&a0, 0, DT_COMPLEX, _state); ae_vector_init(&a1, 0, DT_COMPLEX, _state); k = 10; /* * Complex FFT - forward and inverse */ ae_vector_set_length(&a0, n, _state); ae_vector_set_length(&a1, n, _state); for(i=0; i<=n-1; i++) { a0.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; a0.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; a1.ptr.p_complex[i] = a0.ptr.p_complex[i]; } fftc1d(&a0, n, _state); for(i=0; i<=k-1; i++) { idx = ae_randominteger(n, _state); v = ae_complex_from_i(0); for(j=0; j<=n-1; j++) { re = a1.ptr.p_complex[j].x; im = a1.ptr.p_complex[j].y; c = ae_cos(-2*ae_pi*j*idx/n, _state); s = ae_sin(-2*ae_pi*j*idx/n, _state); v.x = v.x+c*re-s*im; v.y = v.y+c*im+s*re; } *referr = ae_maxreal(*referr, ae_c_abs(ae_c_sub(v,a0.ptr.p_complex[idx]), _state), _state); } fftc1dinv(&a0, n, _state); for(i=0; i<=n-1; i++) { *referr = ae_maxreal(*referr, ae_c_abs(ae_c_sub(a0.ptr.p_complex[i],a1.ptr.p_complex[i]), _state), _state); } ae_frame_leave(_state); } static void testconvunit_refconvc1d(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state); static void testconvunit_refconvc1dcircular(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state); static void testconvunit_refconvr1d(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state); static void testconvunit_refconvr1dcircular(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testconv(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t i; ae_int_t rkind; ae_int_t circkind; ae_vector ra; ae_vector rb; ae_vector rr1; ae_vector rr2; ae_vector ca; ae_vector cb; ae_vector cr1; ae_vector cr2; ae_int_t maxn; double referr; double refrerr; double inverr; double invrerr; double errtol; ae_bool referrors; ae_bool refrerrors; ae_bool inverrors; ae_bool invrerrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&ra, 0, DT_REAL, _state); ae_vector_init(&rb, 0, DT_REAL, _state); ae_vector_init(&rr1, 0, DT_REAL, _state); ae_vector_init(&rr2, 0, DT_REAL, _state); ae_vector_init(&ca, 0, DT_COMPLEX, _state); ae_vector_init(&cb, 0, DT_COMPLEX, _state); ae_vector_init(&cr1, 0, DT_COMPLEX, _state); ae_vector_init(&cr2, 0, DT_COMPLEX, _state); maxn = 32; errtol = 100000*ae_pow((double)(maxn), (double)3/(double)2, _state)*ae_machineepsilon; referrors = ae_false; refrerrors = ae_false; inverrors = ae_false; invrerrors = ae_false; waserrors = ae_false; /* * Test against reference O(N^2) implementation. * * Automatic ConvC1D() and different algorithms of ConvC1DX() are tested. */ referr = (double)(0); refrerr = (double)(0); for(m=1; m<=maxn; m++) { for(n=1; n<=maxn; n++) { for(circkind=0; circkind<=1; circkind++) { for(rkind=-3; rkind<=1; rkind++) { /* * skip impossible combinations of parameters: * * circular convolution, M-3 - internal subroutine does not support M=n ) { /* * test internal subroutine: * * circular/non-circular mode */ convc1dx(&ca, m, &cb, n, circkind!=0, rkind, 0, &cr1, _state); } else { /* * test internal subroutine - circular mode only */ ae_assert(circkind==0, "Convolution test: internal error!", _state); convc1dx(&cb, n, &ca, m, ae_false, rkind, 0, &cr1, _state); } } if( circkind==0 ) { testconvunit_refconvc1d(&ca, m, &cb, n, &cr2, _state); } else { testconvunit_refconvc1dcircular(&ca, m, &cb, n, &cr2, _state); } if( circkind==0 ) { for(i=0; i<=m+n-2; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],cr2.ptr.p_complex[i]), _state), _state); } } else { for(i=0; i<=m-1; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],cr2.ptr.p_complex[i]), _state), _state); } } /* * Real convolution */ ae_vector_set_length(&ra, m, _state); for(i=0; i<=m-1; i++) { ra.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rb, n, _state); for(i=0; i<=n-1; i++) { rb.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rr1, 1, _state); if( rkind==-3 ) { /* * test wrapper subroutine: * * circular/non-circular */ if( circkind==0 ) { convr1d(&ra, m, &rb, n, &rr1, _state); } else { convr1dcircular(&ra, m, &rb, n, &rr1, _state); } } else { if( m>=n ) { /* * test internal subroutine: * * circular/non-circular mode */ convr1dx(&ra, m, &rb, n, circkind!=0, rkind, 0, &rr1, _state); } else { /* * test internal subroutine - non-circular mode only */ convr1dx(&rb, n, &ra, m, circkind!=0, rkind, 0, &rr1, _state); } } if( circkind==0 ) { testconvunit_refconvr1d(&ra, m, &rb, n, &rr2, _state); } else { testconvunit_refconvr1dcircular(&ra, m, &rb, n, &rr2, _state); } if( circkind==0 ) { for(i=0; i<=m+n-2; i++) { refrerr = ae_maxreal(refrerr, ae_fabs(rr1.ptr.p_double[i]-rr2.ptr.p_double[i], _state), _state); } } else { for(i=0; i<=m-1; i++) { refrerr = ae_maxreal(refrerr, ae_fabs(rr1.ptr.p_double[i]-rr2.ptr.p_double[i], _state), _state); } } } } } } referrors = referrors||ae_fp_greater(referr,errtol); refrerrors = refrerrors||ae_fp_greater(refrerr,errtol); /* * Test inverse convolution */ inverr = (double)(0); invrerr = (double)(0); for(m=1; m<=maxn; m++) { for(n=1; n<=maxn; n++) { /* * Complex circilar and non-circular */ ae_vector_set_length(&ca, m, _state); for(i=0; i<=m-1; i++) { ca.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; ca.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&cb, n, _state); for(i=0; i<=n-1; i++) { cb.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cb.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&cr1, 1, _state); ae_vector_set_length(&cr2, 1, _state); convc1d(&ca, m, &cb, n, &cr2, _state); convc1dinv(&cr2, m+n-1, &cb, n, &cr1, _state); for(i=0; i<=m-1; i++) { inverr = ae_maxreal(inverr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],ca.ptr.p_complex[i]), _state), _state); } ae_vector_set_length(&cr1, 1, _state); ae_vector_set_length(&cr2, 1, _state); convc1dcircular(&ca, m, &cb, n, &cr2, _state); convc1dcircularinv(&cr2, m, &cb, n, &cr1, _state); for(i=0; i<=m-1; i++) { inverr = ae_maxreal(inverr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],ca.ptr.p_complex[i]), _state), _state); } /* * Real circilar and non-circular */ ae_vector_set_length(&ra, m, _state); for(i=0; i<=m-1; i++) { ra.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rb, n, _state); for(i=0; i<=n-1; i++) { rb.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rr1, 1, _state); ae_vector_set_length(&rr2, 1, _state); convr1d(&ra, m, &rb, n, &rr2, _state); convr1dinv(&rr2, m+n-1, &rb, n, &rr1, _state); for(i=0; i<=m-1; i++) { invrerr = ae_maxreal(invrerr, ae_fabs(rr1.ptr.p_double[i]-ra.ptr.p_double[i], _state), _state); } ae_vector_set_length(&rr1, 1, _state); ae_vector_set_length(&rr2, 1, _state); convr1dcircular(&ra, m, &rb, n, &rr2, _state); convr1dcircularinv(&rr2, m, &rb, n, &rr1, _state); for(i=0; i<=m-1; i++) { invrerr = ae_maxreal(invrerr, ae_fabs(rr1.ptr.p_double[i]-ra.ptr.p_double[i], _state), _state); } } } inverrors = inverrors||ae_fp_greater(inverr,errtol); invrerrors = invrerrors||ae_fp_greater(invrerr,errtol); /* * end */ waserrors = ((referrors||refrerrors)||inverrors)||invrerrors; if( !silent ) { printf("TESTING CONVOLUTION\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE COMPLEX CONV: "); if( referrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE REAL CONV: "); if( refrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* COMPLEX INVERSE: "); if( inverrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* REAL INVERSE: "); if( invrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testconv(ae_bool silent, ae_state *_state) { return testconv(silent, _state); } /************************************************************************* Reference implementation *************************************************************************/ static void testconvunit_refconvc1d(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state) { ae_int_t i; ae_complex v; ae_vector_clear(r); ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_complex[i] = ae_complex_from_i(0); } for(i=0; i<=m-1; i++) { v = a->ptr.p_complex[i]; ae_v_caddc(&r->ptr.p_complex[i], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(i,i+n-1), v); } } /************************************************************************* Reference implementation *************************************************************************/ static void testconvunit_refconvc1dcircular(/* Complex */ ae_vector* a, ae_int_t m, /* Complex */ ae_vector* b, ae_int_t n, /* Complex */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_vector buf; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&buf, 0, DT_COMPLEX, _state); testconvunit_refconvc1d(a, m, b, n, &buf, _state); ae_vector_set_length(r, m, _state); ae_v_cmove(&r->ptr.p_complex[0], 1, &buf.ptr.p_complex[0], 1, "N", ae_v_len(0,m-1)); i1 = m; while(i1<=m+n-2) { i2 = ae_minint(i1+m-1, m+n-2, _state); j2 = i2-i1; ae_v_cadd(&r->ptr.p_complex[0], 1, &buf.ptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); i1 = i1+m; } ae_frame_leave(_state); } /************************************************************************* Reference FFT *************************************************************************/ static void testconvunit_refconvr1d(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state) { ae_int_t i; double v; ae_vector_clear(r); ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=m+n-2; i++) { r->ptr.p_double[i] = (double)(0); } for(i=0; i<=m-1; i++) { v = a->ptr.p_double[i]; ae_v_addd(&r->ptr.p_double[i], 1, &b->ptr.p_double[0], 1, ae_v_len(i,i+n-1), v); } } /************************************************************************* Reference implementation *************************************************************************/ static void testconvunit_refconvr1dcircular(/* Real */ ae_vector* a, ae_int_t m, /* Real */ ae_vector* b, ae_int_t n, /* Real */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i1; ae_int_t i2; ae_int_t j2; ae_vector buf; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&buf, 0, DT_REAL, _state); testconvunit_refconvr1d(a, m, b, n, &buf, _state); ae_vector_set_length(r, m, _state); ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); i1 = m; while(i1<=m+n-2) { i2 = ae_minint(i1+m-1, m+n-2, _state); j2 = i2-i1; ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[i1], 1, ae_v_len(0,j2)); i1 = i1+m; } ae_frame_leave(_state); } static void testcorrunit_refcorrc1d(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state); static void testcorrunit_refcorrc1dcircular(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state); static void testcorrunit_refcorrr1d(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state); static void testcorrunit_refcorrr1dcircular(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testcorr(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t m; ae_int_t n; ae_int_t i; ae_vector ra; ae_vector rb; ae_vector rr1; ae_vector rr2; ae_vector ca; ae_vector cb; ae_vector cr1; ae_vector cr2; ae_int_t maxn; double referr; double refrerr; double errtol; ae_bool referrors; ae_bool refrerrors; ae_bool inverrors; ae_bool invrerrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&ra, 0, DT_REAL, _state); ae_vector_init(&rb, 0, DT_REAL, _state); ae_vector_init(&rr1, 0, DT_REAL, _state); ae_vector_init(&rr2, 0, DT_REAL, _state); ae_vector_init(&ca, 0, DT_COMPLEX, _state); ae_vector_init(&cb, 0, DT_COMPLEX, _state); ae_vector_init(&cr1, 0, DT_COMPLEX, _state); ae_vector_init(&cr2, 0, DT_COMPLEX, _state); maxn = 32; errtol = 100000*ae_pow((double)(maxn), (double)3/(double)2, _state)*ae_machineepsilon; referrors = ae_false; refrerrors = ae_false; inverrors = ae_false; invrerrors = ae_false; waserrors = ae_false; /* * Test against reference O(N^2) implementation. */ referr = (double)(0); refrerr = (double)(0); for(m=1; m<=maxn; m++) { for(n=1; n<=maxn; n++) { /* * Complex correlation */ ae_vector_set_length(&ca, m, _state); for(i=0; i<=m-1; i++) { ca.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; ca.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&cb, n, _state); for(i=0; i<=n-1; i++) { cb.ptr.p_complex[i].x = 2*ae_randomreal(_state)-1; cb.ptr.p_complex[i].y = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&cr1, 1, _state); corrc1d(&ca, m, &cb, n, &cr1, _state); testcorrunit_refcorrc1d(&ca, m, &cb, n, &cr2, _state); for(i=0; i<=m+n-2; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],cr2.ptr.p_complex[i]), _state), _state); } ae_vector_set_length(&cr1, 1, _state); corrc1dcircular(&ca, m, &cb, n, &cr1, _state); testcorrunit_refcorrc1dcircular(&ca, m, &cb, n, &cr2, _state); for(i=0; i<=m-1; i++) { referr = ae_maxreal(referr, ae_c_abs(ae_c_sub(cr1.ptr.p_complex[i],cr2.ptr.p_complex[i]), _state), _state); } /* * Real correlation */ ae_vector_set_length(&ra, m, _state); for(i=0; i<=m-1; i++) { ra.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rb, n, _state); for(i=0; i<=n-1; i++) { rb.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&rr1, 1, _state); corrr1d(&ra, m, &rb, n, &rr1, _state); testcorrunit_refcorrr1d(&ra, m, &rb, n, &rr2, _state); for(i=0; i<=m+n-2; i++) { refrerr = ae_maxreal(refrerr, ae_fabs(rr1.ptr.p_double[i]-rr2.ptr.p_double[i], _state), _state); } ae_vector_set_length(&rr1, 1, _state); corrr1dcircular(&ra, m, &rb, n, &rr1, _state); testcorrunit_refcorrr1dcircular(&ra, m, &rb, n, &rr2, _state); for(i=0; i<=m-1; i++) { refrerr = ae_maxreal(refrerr, ae_fabs(rr1.ptr.p_double[i]-rr2.ptr.p_double[i], _state), _state); } } } referrors = referrors||ae_fp_greater(referr,errtol); refrerrors = refrerrors||ae_fp_greater(refrerr,errtol); /* * end */ waserrors = referrors||refrerrors; if( !silent ) { printf("TESTING CORRELATION\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE COMPLEX CORR: "); if( referrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE REAL CORR: "); if( refrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testcorr(ae_bool silent, ae_state *_state) { return testcorr(silent, _state); } /************************************************************************* Reference implementation *************************************************************************/ static void testcorrunit_refcorrc1d(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_complex v; ae_vector s; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&s, 0, DT_COMPLEX, _state); ae_vector_set_length(&s, m+n-1, _state); ae_v_cmove(&s.ptr.p_complex[0], 1, &signal->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); for(i=n; i<=m+n-2; i++) { s.ptr.p_complex[i] = ae_complex_from_i(0); } ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=n-1; i++) { v = ae_complex_from_i(0); for(j=0; j<=m-1; j++) { if( i+j>=n ) { break; } v = ae_c_add(v,ae_c_mul(ae_c_conj(pattern->ptr.p_complex[j], _state),s.ptr.p_complex[i+j])); } r->ptr.p_complex[i] = v; } for(i=1; i<=m-1; i++) { v = ae_complex_from_i(0); for(j=i; j<=m-1; j++) { v = ae_c_add(v,ae_c_mul(ae_c_conj(pattern->ptr.p_complex[j], _state),s.ptr.p_complex[j-i])); } r->ptr.p_complex[m+n-1-i] = v; } ae_frame_leave(_state); } /************************************************************************* Reference implementation *************************************************************************/ static void testcorrunit_refcorrc1dcircular(/* Complex */ ae_vector* signal, ae_int_t n, /* Complex */ ae_vector* pattern, ae_int_t m, /* Complex */ ae_vector* r, ae_state *_state) { ae_int_t i; ae_int_t j; ae_complex v; ae_vector_clear(r); ae_vector_set_length(r, n, _state); for(i=0; i<=n-1; i++) { v = ae_complex_from_i(0); for(j=0; j<=m-1; j++) { v = ae_c_add(v,ae_c_mul(ae_c_conj(pattern->ptr.p_complex[j], _state),signal->ptr.p_complex[(i+j)%n])); } r->ptr.p_complex[i] = v; } } /************************************************************************* Reference implementation *************************************************************************/ static void testcorrunit_refcorrr1d(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; double v; ae_vector s; ae_frame_make(_state, &_frame_block); ae_vector_clear(r); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_set_length(&s, m+n-1, _state); ae_v_move(&s.ptr.p_double[0], 1, &signal->ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=n; i<=m+n-2; i++) { s.ptr.p_double[i] = (double)(0); } ae_vector_set_length(r, m+n-1, _state); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=m-1; j++) { if( i+j>=n ) { break; } v = v+pattern->ptr.p_double[j]*s.ptr.p_double[i+j]; } r->ptr.p_double[i] = v; } for(i=1; i<=m-1; i++) { v = (double)(0); for(j=i; j<=m-1; j++) { v = v+pattern->ptr.p_double[j]*s.ptr.p_double[-i+j]; } r->ptr.p_double[m+n-1-i] = v; } ae_frame_leave(_state); } /************************************************************************* Reference implementation *************************************************************************/ static void testcorrunit_refcorrr1dcircular(/* Real */ ae_vector* signal, ae_int_t n, /* Real */ ae_vector* pattern, ae_int_t m, /* Real */ ae_vector* r, ae_state *_state) { ae_int_t i; ae_int_t j; double v; ae_vector_clear(r); ae_vector_set_length(r, n, _state); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=m-1; j++) { v = v+pattern->ptr.p_double[j]*signal->ptr.p_double[(i+j)%n]; } r->ptr.p_double[i] = v; } } static void testfhtunit_reffhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); static void testfhtunit_reffhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testfht(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_vector r1; ae_vector r2; ae_vector r3; ae_int_t maxn; double bidierr; double referr; double errtol; ae_bool referrors; ae_bool bidierrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&r1, 0, DT_REAL, _state); ae_vector_init(&r2, 0, DT_REAL, _state); ae_vector_init(&r3, 0, DT_REAL, _state); maxn = 128; errtol = 100000*ae_pow((double)(maxn), (double)3/(double)2, _state)*ae_machineepsilon; bidierrors = ae_false; referrors = ae_false; waserrors = ae_false; /* * Test bi-directional error: norm(x-invFHT(FHT(x))) */ bidierr = (double)(0); for(n=1; n<=maxn; n++) { /* * FHT/invFHT */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); ae_vector_set_length(&r3, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; r3.ptr.p_double[i] = r1.ptr.p_double[i]; } fhtr1d(&r2, n, _state); fhtr1dinv(&r2, n, _state); fhtr1dinv(&r3, n, _state); fhtr1d(&r3, n, _state); for(i=0; i<=n-1; i++) { bidierr = ae_maxreal(bidierr, ae_fabs(r1.ptr.p_double[i]-r2.ptr.p_double[i], _state), _state); bidierr = ae_maxreal(bidierr, ae_fabs(r1.ptr.p_double[i]-r3.ptr.p_double[i], _state), _state); } } bidierrors = bidierrors||ae_fp_greater(bidierr,errtol); /* * Test against reference O(N^2) implementation */ referr = (double)(0); for(n=1; n<=maxn; n++) { /* * FHT */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; } fhtr1d(&r1, n, _state); testfhtunit_reffhtr1d(&r2, n, _state); for(i=0; i<=n-1; i++) { referr = ae_maxreal(referr, ae_fabs(r1.ptr.p_double[i]-r2.ptr.p_double[i], _state), _state); } /* * inverse FHT */ ae_vector_set_length(&r1, n, _state); ae_vector_set_length(&r2, n, _state); for(i=0; i<=n-1; i++) { r1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; r2.ptr.p_double[i] = r1.ptr.p_double[i]; } fhtr1dinv(&r1, n, _state); testfhtunit_reffhtr1dinv(&r2, n, _state); for(i=0; i<=n-1; i++) { referr = ae_maxreal(referr, ae_fabs(r1.ptr.p_double[i]-r2.ptr.p_double[i], _state), _state); } } referrors = referrors||ae_fp_greater(referr,errtol); /* * end */ waserrors = bidierrors||referrors; if( !silent ) { printf("TESTING FHT\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BI-DIRECTIONAL TEST: "); if( bidierrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE FHT: "); if( referrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testfht(ae_bool silent, ae_state *_state) { return testfht(silent, _state); } /************************************************************************* Reference FHT *************************************************************************/ static void testfhtunit_reffhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector buf; ae_int_t i; ae_int_t j; double v; ae_frame_make(_state, &_frame_block); ae_vector_init(&buf, 0, DT_REAL, _state); ae_assert(n>0, "RefFHTR1D: incorrect N!", _state); ae_vector_set_length(&buf, n, _state); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+a->ptr.p_double[j]*(ae_cos(2*ae_pi*i*j/n, _state)+ae_sin(2*ae_pi*i*j/n, _state)); } buf.ptr.p_double[i] = v; } for(i=0; i<=n-1; i++) { a->ptr.p_double[i] = buf.ptr.p_double[i]; } ae_frame_leave(_state); } /************************************************************************* Reference inverse FHT *************************************************************************/ static void testfhtunit_reffhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) { ae_int_t i; ae_assert(n>0, "RefFHTR1DInv: incorrect N!", _state); testfhtunit_reffhtr1d(a, n, _state); for(i=0; i<=n-1; i++) { a->ptr.p_double[i] = a->ptr.p_double[i]/n; } } static double testgqunit_mapkind(ae_int_t k, ae_state *_state); static void testgqunit_buildgausslegendrequadrature(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); static void testgqunit_buildgaussjacobiquadrature(ae_int_t n, double alpha, double beta, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); static void testgqunit_buildgausslaguerrequadrature(ae_int_t n, double alpha, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); static void testgqunit_buildgausshermitequadrature(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testgq(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_vector alpha; ae_vector beta; ae_vector x; ae_vector w; ae_vector x2; ae_vector w2; double err; ae_int_t n; ae_int_t i; ae_int_t info; ae_int_t akind; ae_int_t bkind; double alphac; double betac; double errtol; double nonstricterrtol; double stricterrtol; ae_bool recerrors; ae_bool specerrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&alpha, 0, DT_REAL, _state); ae_vector_init(&beta, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); recerrors = ae_false; specerrors = ae_false; waserrors = ae_false; errtol = 1.0E-12; nonstricterrtol = 1.0E-6; stricterrtol = 1000*ae_machineepsilon; /* * Three tests for rec-based Gauss quadratures with known weights/nodes: * 1. Gauss-Legendre with N=2 * 2. Gauss-Legendre with N=5 * 3. Gauss-Chebyshev with N=1, 2, 4, 8, ..., 512 */ err = (double)(0); ae_vector_set_length(&alpha, 2, _state); ae_vector_set_length(&beta, 2, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); beta.ptr.p_double[1] = (double)1/(double)(4*1*1-1); gqgeneraterec(&alpha, &beta, 2.0, 2, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+ae_sqrt((double)(3), _state)/3, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]-ae_sqrt((double)(3), _state)/3, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-1, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-1, _state), _state); for(i=0; i<=0; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } ae_vector_set_length(&alpha, 5, _state); ae_vector_set_length(&beta, 5, _state); alpha.ptr.p_double[0] = (double)(0); for(i=1; i<=4; i++) { alpha.ptr.p_double[i] = (double)(0); beta.ptr.p_double[i] = ae_sqr((double)(i), _state)/(4*ae_sqr((double)(i), _state)-1); } gqgeneraterec(&alpha, &beta, 2.0, 5, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+ae_sqrt(245+14*ae_sqrt((double)(70), _state), _state)/21, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+x.ptr.p_double[4], _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]+ae_sqrt(245-14*ae_sqrt((double)(70), _state), _state)/21, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]+x.ptr.p_double[3], _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(322-13*ae_sqrt((double)(70), _state))/900, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-w.ptr.p_double[4], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(322+13*ae_sqrt((double)(70), _state))/900, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-w.ptr.p_double[3], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(double)128/(double)225, _state), _state); for(i=0; i<=3; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } n = 1; while(n<=512) { ae_vector_set_length(&alpha, n, _state); ae_vector_set_length(&beta, n, _state); for(i=0; i<=n-1; i++) { alpha.ptr.p_double[i] = (double)(0); if( i==0 ) { beta.ptr.p_double[i] = (double)(0); } if( i==1 ) { beta.ptr.p_double[i] = (double)1/(double)2; } if( i>1 ) { beta.ptr.p_double[i] = (double)1/(double)4; } } gqgeneraterec(&alpha, &beta, ae_pi, n, &info, &x, &w, _state); if( info>0 ) { for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]-ae_cos(ae_pi*(n-i-0.5)/n, _state), _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-ae_pi/n, _state), _state); } for(i=0; i<=n-2; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } n = n*2; } recerrors = recerrors||ae_fp_greater(err,errtol); /* * Three tests for rec-based Gauss-Lobatto quadratures with known weights/nodes: * 1. Gauss-Lobatto with N=3 * 2. Gauss-Lobatto with N=4 * 3. Gauss-Lobatto with N=6 */ err = (double)(0); ae_vector_set_length(&alpha, 2, _state); ae_vector_set_length(&beta, 2, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); beta.ptr.p_double[0] = (double)(0); beta.ptr.p_double[1] = (double)(1*1)/(double)(4*1*1-1); gqgenerategausslobattorec(&alpha, &beta, 2.0, (double)(-1), (double)(1), 3, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1], _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2]-1, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(double)1/(double)3, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(double)4/(double)3, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(double)1/(double)3, _state), _state); for(i=0; i<=1; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } ae_vector_set_length(&alpha, 3, _state); ae_vector_set_length(&beta, 3, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); alpha.ptr.p_double[2] = (double)(0); beta.ptr.p_double[0] = (double)(0); beta.ptr.p_double[1] = (double)(1*1)/(double)(4*1*1-1); beta.ptr.p_double[2] = (double)(2*2)/(double)(4*2*2-1); gqgenerategausslobattorec(&alpha, &beta, 2.0, (double)(-1), (double)(1), 4, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]+ae_sqrt((double)(5), _state)/5, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2]-ae_sqrt((double)(5), _state)/5, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[3]-1, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(double)1/(double)6, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(double)5/(double)6, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(double)5/(double)6, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[3]-(double)1/(double)6, _state), _state); for(i=0; i<=2; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } ae_vector_set_length(&alpha, 5, _state); ae_vector_set_length(&beta, 5, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); alpha.ptr.p_double[2] = (double)(0); alpha.ptr.p_double[3] = (double)(0); alpha.ptr.p_double[4] = (double)(0); beta.ptr.p_double[0] = (double)(0); beta.ptr.p_double[1] = (double)(1*1)/(double)(4*1*1-1); beta.ptr.p_double[2] = (double)(2*2)/(double)(4*2*2-1); beta.ptr.p_double[3] = (double)(3*3)/(double)(4*3*3-1); beta.ptr.p_double[4] = (double)(4*4)/(double)(4*4*4-1); gqgenerategausslobattorec(&alpha, &beta, 2.0, (double)(-1), (double)(1), 6, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]+ae_sqrt((7+2*ae_sqrt((double)(7), _state))/21, _state), _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2]+ae_sqrt((7-2*ae_sqrt((double)(7), _state))/21, _state), _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[3]-ae_sqrt((7-2*ae_sqrt((double)(7), _state))/21, _state), _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[4]-ae_sqrt((7+2*ae_sqrt((double)(7), _state))/21, _state), _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[5]-1, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(double)1/(double)15, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(14-ae_sqrt((double)(7), _state))/30, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(14+ae_sqrt((double)(7), _state))/30, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[3]-(14+ae_sqrt((double)(7), _state))/30, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[4]-(14-ae_sqrt((double)(7), _state))/30, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[5]-(double)1/(double)15, _state), _state); for(i=0; i<=4; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } recerrors = recerrors||ae_fp_greater(err,errtol); /* * Three tests for rec-based Gauss-Radau quadratures with known weights/nodes: * 1. Gauss-Radau with N=2 * 2. Gauss-Radau with N=3 * 3. Gauss-Radau with N=3 (another case) */ err = (double)(0); ae_vector_set_length(&alpha, 1, _state); ae_vector_set_length(&beta, 2, _state); alpha.ptr.p_double[0] = (double)(0); beta.ptr.p_double[0] = (double)(0); beta.ptr.p_double[1] = (double)(1*1)/(double)(4*1*1-1); gqgenerategaussradaurec(&alpha, &beta, 2.0, (double)(-1), 2, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]-(double)1/(double)3, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-0.5, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-1.5, _state), _state); for(i=0; i<=0; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } ae_vector_set_length(&alpha, 2, _state); ae_vector_set_length(&beta, 3, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); for(i=0; i<=2; i++) { beta.ptr.p_double[i] = ae_sqr((double)(i), _state)/(4*ae_sqr((double)(i), _state)-1); } gqgenerategaussradaurec(&alpha, &beta, 2.0, (double)(-1), 3, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]-(1-ae_sqrt((double)(6), _state))/5, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2]-(1+ae_sqrt((double)(6), _state))/5, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(double)2/(double)9, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(16+ae_sqrt((double)(6), _state))/18, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(16-ae_sqrt((double)(6), _state))/18, _state), _state); for(i=0; i<=1; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } ae_vector_set_length(&alpha, 2, _state); ae_vector_set_length(&beta, 3, _state); alpha.ptr.p_double[0] = (double)(0); alpha.ptr.p_double[1] = (double)(0); for(i=0; i<=2; i++) { beta.ptr.p_double[i] = ae_sqr((double)(i), _state)/(4*ae_sqr((double)(i), _state)-1); } gqgenerategaussradaurec(&alpha, &beta, 2.0, (double)(1), 3, &info, &x, &w, _state); if( info>0 ) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[2]-1, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[1]+(1-ae_sqrt((double)(6), _state))/5, _state), _state); err = ae_maxreal(err, ae_fabs(x.ptr.p_double[0]+(1+ae_sqrt((double)(6), _state))/5, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[2]-(double)2/(double)9, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[1]-(16+ae_sqrt((double)(6), _state))/18, _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[0]-(16-ae_sqrt((double)(6), _state))/18, _state), _state); for(i=0; i<=1; i++) { recerrors = recerrors||ae_fp_greater_eq(x.ptr.p_double[i],x.ptr.p_double[i+1]); } } else { recerrors = ae_true; } recerrors = recerrors||ae_fp_greater(err,errtol); /* * test recurrence-based special cases (Legendre, Jacobi, Hermite, ...) * against another implementation (polynomial root-finder) */ for(n=1; n<=20; n++) { /* * test gauss-legendre */ err = (double)(0); gqgenerategausslegendre(n, &info, &x, &w, _state); if( info>0 ) { testgqunit_buildgausslegendrequadrature(n, &x2, &w2, _state); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-w2.ptr.p_double[i], _state), _state); } } else { specerrors = ae_true; } specerrors = specerrors||ae_fp_greater(err,errtol); /* * Test Gauss-Jacobi. * Since task is much more difficult we will use less strict * threshold. */ err = (double)(0); for(akind=0; akind<=9; akind++) { for(bkind=0; bkind<=9; bkind++) { alphac = testgqunit_mapkind(akind, _state); betac = testgqunit_mapkind(bkind, _state); gqgenerategaussjacobi(n, alphac, betac, &info, &x, &w, _state); if( info>0 ) { testgqunit_buildgaussjacobiquadrature(n, alphac, betac, &x2, &w2, _state); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-w2.ptr.p_double[i], _state), _state); } } else { specerrors = ae_true; } } } specerrors = specerrors||ae_fp_greater(err,nonstricterrtol); /* * special test for Gauss-Jacobi (Chebyshev weight * function with analytically known nodes/weights) */ err = (double)(0); gqgenerategaussjacobi(n, -0.5, -0.5, &info, &x, &w, _state); if( info>0 ) { for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]+ae_cos(ae_pi*(i+0.5)/n, _state), _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-ae_pi/n, _state), _state); } } else { specerrors = ae_true; } specerrors = specerrors||ae_fp_greater(err,stricterrtol); /* * Test Gauss-Laguerre */ err = (double)(0); for(akind=0; akind<=9; akind++) { alphac = testgqunit_mapkind(akind, _state); gqgenerategausslaguerre(n, alphac, &info, &x, &w, _state); if( info>0 ) { testgqunit_buildgausslaguerrequadrature(n, alphac, &x2, &w2, _state); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-w2.ptr.p_double[i], _state), _state); } } else { specerrors = ae_true; } } specerrors = specerrors||ae_fp_greater(err,nonstricterrtol); /* * Test Gauss-Hermite */ err = (double)(0); gqgenerategausshermite(n, &info, &x, &w, _state); if( info>0 ) { testgqunit_buildgausshermitequadrature(n, &x2, &w2, _state); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(x.ptr.p_double[i]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(w.ptr.p_double[i]-w2.ptr.p_double[i], _state), _state); } } else { specerrors = ae_true; } specerrors = specerrors||ae_fp_greater(err,nonstricterrtol); } /* * end */ waserrors = recerrors||specerrors; if( !silent ) { printf("TESTING GAUSS QUADRATURES\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* SPECIAL CASES (LEGENDRE/JACOBI/..) "); if( specerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* RECURRENCE-BASED: "); if( recerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testgq(ae_bool silent, ae_state *_state) { return testgq(silent, _state); } /************************************************************************* Maps: 0 => -0.9 1 => -0.5 2 => -0.1 3 => 0.0 4 => +0.1 5 => +0.5 6 => +0.9 7 => +1.0 8 => +1.5 9 => +2.0 *************************************************************************/ static double testgqunit_mapkind(ae_int_t k, ae_state *_state) { double result; result = (double)(0); if( k==0 ) { result = -0.9; } if( k==1 ) { result = -0.5; } if( k==2 ) { result = -0.1; } if( k==3 ) { result = 0.0; } if( k==4 ) { result = 0.1; } if( k==5 ) { result = 0.5; } if( k==6 ) { result = 0.9; } if( k==7 ) { result = 1.0; } if( k==8 ) { result = 1.5; } if( k==9 ) { result = 2.0; } return result; } /************************************************************************* Gauss-Legendre, another variant *************************************************************************/ static void testgqunit_buildgausslegendrequadrature(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_int_t i; ae_int_t j; double r; double r1; double p1; double p2; double p3; double dp3; double tmp; ae_vector_clear(x); ae_vector_clear(w); ae_vector_set_length(x, n-1+1, _state); ae_vector_set_length(w, n-1+1, _state); for(i=0; i<=(n+1)/2-1; i++) { r = ae_cos(ae_pi*(4*i+3)/(4*n+2), _state); do { p2 = (double)(0); p3 = (double)(1); for(j=0; j<=n-1; j++) { p1 = p2; p2 = p3; p3 = ((2*j+1)*r*p2-j*p1)/(j+1); } dp3 = n*(r*p3-p2)/(r*r-1); r1 = r; r = r-p3/dp3; } while(ae_fp_greater_eq(ae_fabs(r-r1, _state),ae_machineepsilon*(1+ae_fabs(r, _state))*100)); x->ptr.p_double[i] = r; x->ptr.p_double[n-1-i] = -r; w->ptr.p_double[i] = 2/((1-r*r)*dp3*dp3); w->ptr.p_double[n-1-i] = 2/((1-r*r)*dp3*dp3); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater_eq(x->ptr.p_double[j],x->ptr.p_double[j+1]) ) { tmp = x->ptr.p_double[j]; x->ptr.p_double[j] = x->ptr.p_double[j+1]; x->ptr.p_double[j+1] = tmp; tmp = w->ptr.p_double[j]; w->ptr.p_double[j] = w->ptr.p_double[j+1]; w->ptr.p_double[j+1] = tmp; } } } } /************************************************************************* Gauss-Jacobi, another variant *************************************************************************/ static void testgqunit_buildgaussjacobiquadrature(ae_int_t n, double alpha, double beta, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_int_t i; ae_int_t j; double r; double r1; double t1; double t2; double t3; double p1; double p2; double p3; double pp; double an; double bn; double a; double b; double c; double tmpsgn; double tmp; double alfbet; double temp; ae_vector_clear(x); ae_vector_clear(w); ae_vector_set_length(x, n-1+1, _state); ae_vector_set_length(w, n-1+1, _state); r = (double)(0); for(i=0; i<=n-1; i++) { if( i==0 ) { an = alpha/n; bn = beta/n; t1 = (1+alpha)*(2.78/(4+n*n)+0.768*an/n); t2 = 1+1.48*an+0.96*bn+0.452*an*an+0.83*an*bn; r = (t2-t1)/t2; } else { if( i==1 ) { t1 = (4.1+alpha)/((1+alpha)*(1+0.156*alpha)); t2 = 1+0.06*(n-8)*(1+0.12*alpha)/n; t3 = 1+0.012*beta*(1+0.25*ae_fabs(alpha, _state))/n; r = r-t1*t2*t3*(1-r); } else { if( i==2 ) { t1 = (1.67+0.28*alpha)/(1+0.37*alpha); t2 = 1+0.22*(n-8)/n; t3 = 1+8*beta/((6.28+beta)*n*n); r = r-t1*t2*t3*(x->ptr.p_double[0]-r); } else { if( iptr.p_double[i-1]-3*x->ptr.p_double[i-2]+x->ptr.p_double[i-3]; } else { if( i==n-2 ) { t1 = (1+0.235*beta)/(0.766+0.119*beta); t2 = 1/(1+0.639*(n-4)/(1+0.71*(n-4))); t3 = 1/(1+20*alpha/((7.5+alpha)*n*n)); r = r+t1*t2*t3*(r-x->ptr.p_double[i-2]); } else { if( i==n-1 ) { t1 = (1+0.37*beta)/(1.67+0.28*beta); t2 = 1/(1+0.22*(n-8)/n); t3 = 1/(1+8*alpha/((6.28+alpha)*n*n)); r = r+t1*t2*t3*(r-x->ptr.p_double[i-2]); } } } } } } alfbet = alpha+beta; do { temp = 2+alfbet; p1 = (alpha-beta+temp*r)*0.5; p2 = (double)(1); for(j=2; j<=n; j++) { p3 = p2; p2 = p1; temp = 2*j+alfbet; a = 2*j*(j+alfbet)*(temp-2); b = (temp-1)*(alpha*alpha-beta*beta+temp*(temp-2)*r); c = 2*(j-1+alpha)*(j-1+beta)*temp; p1 = (b*p2-c*p3)/a; } pp = (n*(alpha-beta-temp*r)*p1+2*(n+alpha)*(n+beta)*p2)/(temp*(1-r*r)); r1 = r; r = r1-p1/pp; } while(ae_fp_greater_eq(ae_fabs(r-r1, _state),ae_machineepsilon*(1+ae_fabs(r, _state))*100)); x->ptr.p_double[i] = r; w->ptr.p_double[i] = ae_exp(lngamma(alpha+n, &tmpsgn, _state)+lngamma(beta+n, &tmpsgn, _state)-lngamma((double)(n+1), &tmpsgn, _state)-lngamma(n+alfbet+1, &tmpsgn, _state), _state)*temp*ae_pow((double)(2), alfbet, _state)/(pp*p2); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater_eq(x->ptr.p_double[j],x->ptr.p_double[j+1]) ) { tmp = x->ptr.p_double[j]; x->ptr.p_double[j] = x->ptr.p_double[j+1]; x->ptr.p_double[j+1] = tmp; tmp = w->ptr.p_double[j]; w->ptr.p_double[j] = w->ptr.p_double[j+1]; w->ptr.p_double[j+1] = tmp; } } } } /************************************************************************* Gauss-Laguerre, another variant *************************************************************************/ static void testgqunit_buildgausslaguerrequadrature(ae_int_t n, double alpha, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_int_t i; ae_int_t j; double r; double r1; double p1; double p2; double p3; double dp3; double tsg; double tmp; ae_vector_clear(x); ae_vector_clear(w); ae_vector_set_length(x, n-1+1, _state); ae_vector_set_length(w, n-1+1, _state); r = (double)(0); for(i=0; i<=n-1; i++) { if( i==0 ) { r = (1+alpha)*(3+0.92*alpha)/(1+2.4*n+1.8*alpha); } else { if( i==1 ) { r = r+(15+6.25*alpha)/(1+0.9*alpha+2.5*n); } else { r = r+((1+2.55*(i-1))/(1.9*(i-1))+1.26*(i-1)*alpha/(1+3.5*(i-1)))/(1+0.3*alpha)*(r-x->ptr.p_double[i-2]); } } do { p2 = (double)(0); p3 = (double)(1); for(j=0; j<=n-1; j++) { p1 = p2; p2 = p3; p3 = ((-r+2*j+alpha+1)*p2-(j+alpha)*p1)/(j+1); } dp3 = (n*p3-(n+alpha)*p2)/r; r1 = r; r = r-p3/dp3; } while(ae_fp_greater_eq(ae_fabs(r-r1, _state),ae_machineepsilon*(1+ae_fabs(r, _state))*100)); x->ptr.p_double[i] = r; w->ptr.p_double[i] = -ae_exp(lngamma(alpha+n, &tsg, _state)-lngamma((double)(n), &tsg, _state), _state)/(dp3*n*p2); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater_eq(x->ptr.p_double[j],x->ptr.p_double[j+1]) ) { tmp = x->ptr.p_double[j]; x->ptr.p_double[j] = x->ptr.p_double[j+1]; x->ptr.p_double[j+1] = tmp; tmp = w->ptr.p_double[j]; w->ptr.p_double[j] = w->ptr.p_double[j+1]; w->ptr.p_double[j+1] = tmp; } } } } /************************************************************************* Gauss-Hermite, another variant *************************************************************************/ static void testgqunit_buildgausshermitequadrature(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* w, ae_state *_state) { ae_int_t i; ae_int_t j; double r; double r1; double p1; double p2; double p3; double dp3; double pipm4; double tmp; ae_vector_clear(x); ae_vector_clear(w); ae_vector_set_length(x, n-1+1, _state); ae_vector_set_length(w, n-1+1, _state); pipm4 = ae_pow(ae_pi, -0.25, _state); r = (double)(0); for(i=0; i<=(n+1)/2-1; i++) { if( i==0 ) { r = ae_sqrt((double)(2*n+1), _state)-1.85575*ae_pow((double)(2*n+1), -(double)1/(double)6, _state); } else { if( i==1 ) { r = r-1.14*ae_pow((double)(n), 0.426, _state)/r; } else { if( i==2 ) { r = 1.86*r-0.86*x->ptr.p_double[0]; } else { if( i==3 ) { r = 1.91*r-0.91*x->ptr.p_double[1]; } else { r = 2*r-x->ptr.p_double[i-2]; } } } } do { p2 = (double)(0); p3 = pipm4; for(j=0; j<=n-1; j++) { p1 = p2; p2 = p3; p3 = p2*r*ae_sqrt((double)2/(double)(j+1), _state)-p1*ae_sqrt((double)j/(double)(j+1), _state); } dp3 = ae_sqrt((double)(2*j), _state)*p2; r1 = r; r = r-p3/dp3; } while(ae_fp_greater_eq(ae_fabs(r-r1, _state),ae_machineepsilon*(1+ae_fabs(r, _state))*100)); x->ptr.p_double[i] = r; w->ptr.p_double[i] = 2/(dp3*dp3); x->ptr.p_double[n-1-i] = -x->ptr.p_double[i]; w->ptr.p_double[n-1-i] = w->ptr.p_double[i]; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-2-i; j++) { if( ae_fp_greater_eq(x->ptr.p_double[j],x->ptr.p_double[j+1]) ) { tmp = x->ptr.p_double[j]; x->ptr.p_double[j] = x->ptr.p_double[j+1]; x->ptr.p_double[j+1] = tmp; tmp = w->ptr.p_double[j]; w->ptr.p_double[j] = w->ptr.p_double[j+1]; w->ptr.p_double[j+1] = tmp; } } } } static double testgkqunit_mapkind(ae_int_t k, ae_state *_state); /************************************************************************* Test *************************************************************************/ ae_bool testgkq(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t pkind; double errtol; double eps; double nonstricterrtol; ae_int_t n; ae_int_t i; ae_int_t k; ae_int_t info; double err; ae_int_t akind; ae_int_t bkind; double alphac; double betac; ae_vector x1; ae_vector wg1; ae_vector wk1; ae_vector x2; ae_vector wg2; ae_vector wk2; ae_int_t info1; ae_int_t info2; ae_bool successatleastonce; ae_bool intblerrors; ae_bool vstblerrors; ae_bool generrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&wg1, 0, DT_REAL, _state); ae_vector_init(&wk1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&wg2, 0, DT_REAL, _state); ae_vector_init(&wk2, 0, DT_REAL, _state); intblerrors = ae_false; vstblerrors = ae_false; generrors = ae_false; waserrors = ae_false; errtol = 10000*ae_machineepsilon; nonstricterrtol = 1000*errtol; /* * test recurrence-based Legendre nodes against the precalculated table */ for(pkind=0; pkind<=5; pkind++) { n = 0; if( pkind==0 ) { n = 15; } if( pkind==1 ) { n = 21; } if( pkind==2 ) { n = 31; } if( pkind==3 ) { n = 41; } if( pkind==4 ) { n = 51; } if( pkind==5 ) { n = 61; } gkqlegendrecalc(n, &info, &x1, &wk1, &wg1, _state); gkqlegendretbl(n, &x2, &wk2, &wg2, &eps, _state); if( info<=0 ) { generrors = ae_true; break; } for(i=0; i<=n-1; i++) { vstblerrors = vstblerrors||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-x2.ptr.p_double[i], _state),errtol); vstblerrors = vstblerrors||ae_fp_greater(ae_fabs(wk1.ptr.p_double[i]-wk2.ptr.p_double[i], _state),errtol); vstblerrors = vstblerrors||ae_fp_greater(ae_fabs(wg1.ptr.p_double[i]-wg2.ptr.p_double[i], _state),errtol); } } /* * Test recurrence-baced Gauss-Kronrod nodes against Gauss-only nodes * calculated with subroutines from GQ unit. */ for(k=1; k<=30; k++) { n = 2*k+1; /* * Gauss-Legendre */ err = (double)(0); gkqgenerategausslegendre(n, &info1, &x1, &wk1, &wg1, _state); gqgenerategausslegendre(k, &info2, &x2, &wg2, _state); if( info1>0&&info2>0 ) { for(i=0; i<=k-1; i++) { err = ae_maxreal(err, ae_fabs(x1.ptr.p_double[2*i+1]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(wg1.ptr.p_double[2*i+1]-wg2.ptr.p_double[i], _state), _state); } } else { generrors = ae_true; } generrors = generrors||ae_fp_greater(err,errtol); } for(k=1; k<=15; k++) { n = 2*k+1; /* * Gauss-Jacobi */ successatleastonce = ae_false; err = (double)(0); for(akind=0; akind<=9; akind++) { for(bkind=0; bkind<=9; bkind++) { alphac = testgkqunit_mapkind(akind, _state); betac = testgkqunit_mapkind(bkind, _state); gkqgenerategaussjacobi(n, alphac, betac, &info1, &x1, &wk1, &wg1, _state); gqgenerategaussjacobi(k, alphac, betac, &info2, &x2, &wg2, _state); if( info1>0&&info2>0 ) { successatleastonce = ae_true; for(i=0; i<=k-1; i++) { err = ae_maxreal(err, ae_fabs(x1.ptr.p_double[2*i+1]-x2.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(wg1.ptr.p_double[2*i+1]-wg2.ptr.p_double[i], _state), _state); } } else { generrors = generrors||info1!=-5; } } } generrors = (generrors||ae_fp_greater(err,errtol))||!successatleastonce; } /* * end */ waserrors = (intblerrors||vstblerrors)||generrors; if( !silent ) { printf("TESTING GAUSS-KRONROD QUADRATURES\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* PRE-CALCULATED TABLE: "); if( intblerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* CALCULATED AGAINST THE TABLE: "); if( vstblerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* GENERAL PROPERTIES: "); if( generrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testgkq(ae_bool silent, ae_state *_state) { return testgkq(silent, _state); } /************************************************************************* Maps: 0 => -0.9 1 => -0.5 2 => -0.1 3 => 0.0 4 => +0.1 5 => +0.5 6 => +0.9 7 => +1.0 8 => +1.5 9 => +2.0 *************************************************************************/ static double testgkqunit_mapkind(ae_int_t k, ae_state *_state) { double result; result = (double)(0); if( k==0 ) { result = -0.9; } if( k==1 ) { result = -0.5; } if( k==2 ) { result = -0.1; } if( k==3 ) { result = 0.0; } if( k==4 ) { result = 0.1; } if( k==5 ) { result = 0.5; } if( k==6 ) { result = 0.9; } if( k==7 ) { result = 1.0; } if( k==8 ) { result = 1.5; } if( k==9 ) { result = 2.0; } return result; } /************************************************************************* Test *************************************************************************/ ae_bool testautogk(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double a; double b; autogkstate state; autogkreport rep; double v; double exact; double eabs; double alpha; ae_int_t pkind; double errtol; ae_bool simpleerrors; ae_bool sngenderrors; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); _autogkstate_init(&state, _state); _autogkreport_init(&rep, _state); simpleerrors = ae_false; sngenderrors = ae_false; waserrors = ae_false; errtol = 10000*ae_machineepsilon; /* * Simple test: integral(exp(x),+-1,+-2), no maximum width requirements */ a = (2*ae_randominteger(2, _state)-1)*1.0; b = (2*ae_randominteger(2, _state)-1)*2.0; autogksmooth(a, b, &state, _state); while(autogkiteration(&state, _state)) { state.f = ae_exp(state.x, _state); } autogkresults(&state, &v, &rep, _state); exact = ae_exp(b, _state)-ae_exp(a, _state); eabs = ae_fabs(ae_exp(b, _state)-ae_exp(a, _state), _state); if( rep.terminationtype<=0 ) { simpleerrors = ae_true; } else { simpleerrors = simpleerrors||ae_fp_greater(ae_fabs(exact-v, _state),errtol*eabs); } /* * Simple test: integral(exp(x),+-1,+-2), XWidth=0.1 */ a = (2*ae_randominteger(2, _state)-1)*1.0; b = (2*ae_randominteger(2, _state)-1)*2.0; autogksmoothw(a, b, 0.1, &state, _state); while(autogkiteration(&state, _state)) { state.f = ae_exp(state.x, _state); } autogkresults(&state, &v, &rep, _state); exact = ae_exp(b, _state)-ae_exp(a, _state); eabs = ae_fabs(ae_exp(b, _state)-ae_exp(a, _state), _state); if( rep.terminationtype<=0 ) { simpleerrors = ae_true; } else { simpleerrors = simpleerrors||ae_fp_greater(ae_fabs(exact-v, _state),errtol*eabs); } /* * Simple test: integral(cos(100*x),0,2*pi), no maximum width requirements */ a = (double)(0); b = 2*ae_pi; autogksmooth(a, b, &state, _state); while(autogkiteration(&state, _state)) { state.f = ae_cos(100*state.x, _state); } autogkresults(&state, &v, &rep, _state); exact = (double)(0); eabs = (double)(4); if( rep.terminationtype<=0 ) { simpleerrors = ae_true; } else { simpleerrors = simpleerrors||ae_fp_greater(ae_fabs(exact-v, _state),errtol*eabs); } /* * Simple test: integral(cos(100*x),0,2*pi), XWidth=0.3 */ a = (double)(0); b = 2*ae_pi; autogksmoothw(a, b, 0.3, &state, _state); while(autogkiteration(&state, _state)) { state.f = ae_cos(100*state.x, _state); } autogkresults(&state, &v, &rep, _state); exact = (double)(0); eabs = (double)(4); if( rep.terminationtype<=0 ) { simpleerrors = ae_true; } else { simpleerrors = simpleerrors||ae_fp_greater(ae_fabs(exact-v, _state),errtol*eabs); } /* * singular problem on [a,b] = [0.1, 0.5] * f2(x) = (1+x)*(b-x)^alpha, -1 < alpha < 1 */ for(pkind=0; pkind<=6; pkind++) { a = 0.1; b = 0.5; alpha = 0.0; if( pkind==0 ) { alpha = -0.9; } if( pkind==1 ) { alpha = -0.5; } if( pkind==2 ) { alpha = -0.1; } if( pkind==3 ) { alpha = 0.0; } if( pkind==4 ) { alpha = 0.1; } if( pkind==5 ) { alpha = 0.5; } if( pkind==6 ) { alpha = 0.9; } /* * f1(x) = (1+x)*(x-a)^alpha, -1 < alpha < 1 * 1. use singular integrator for [a,b] * 2. use singular integrator for [b,a] */ exact = ae_pow(b-a, alpha+2, _state)/(alpha+2)+(1+a)*ae_pow(b-a, alpha+1, _state)/(alpha+1); eabs = ae_fabs(exact, _state); autogksingular(a, b, alpha, 0.0, &state, _state); while(autogkiteration(&state, _state)) { if( ae_fp_less(state.xminusa,0.01) ) { state.f = ae_pow(state.xminusa, alpha, _state)*(1+state.x); } else { state.f = ae_pow(state.x-a, alpha, _state)*(1+state.x); } } autogkresults(&state, &v, &rep, _state); if( rep.terminationtype<=0 ) { sngenderrors = ae_true; } else { sngenderrors = sngenderrors||ae_fp_greater(ae_fabs(v-exact, _state),errtol*eabs); } autogksingular(b, a, 0.0, alpha, &state, _state); while(autogkiteration(&state, _state)) { if( ae_fp_greater(state.bminusx,-0.01) ) { state.f = ae_pow(-state.bminusx, alpha, _state)*(1+state.x); } else { state.f = ae_pow(state.x-a, alpha, _state)*(1+state.x); } } autogkresults(&state, &v, &rep, _state); if( rep.terminationtype<=0 ) { sngenderrors = ae_true; } else { sngenderrors = sngenderrors||ae_fp_greater(ae_fabs(-v-exact, _state),errtol*eabs); } /* * f1(x) = (1+x)*(b-x)^alpha, -1 < alpha < 1 * 1. use singular integrator for [a,b] * 2. use singular integrator for [b,a] */ exact = (1+b)*ae_pow(b-a, alpha+1, _state)/(alpha+1)-ae_pow(b-a, alpha+2, _state)/(alpha+2); eabs = ae_fabs(exact, _state); autogksingular(a, b, 0.0, alpha, &state, _state); while(autogkiteration(&state, _state)) { if( ae_fp_less(state.bminusx,0.01) ) { state.f = ae_pow(state.bminusx, alpha, _state)*(1+state.x); } else { state.f = ae_pow(b-state.x, alpha, _state)*(1+state.x); } } autogkresults(&state, &v, &rep, _state); if( rep.terminationtype<=0 ) { sngenderrors = ae_true; } else { sngenderrors = sngenderrors||ae_fp_greater(ae_fabs(v-exact, _state),errtol*eabs); } autogksingular(b, a, alpha, 0.0, &state, _state); while(autogkiteration(&state, _state)) { if( ae_fp_greater(state.xminusa,-0.01) ) { state.f = ae_pow(-state.xminusa, alpha, _state)*(1+state.x); } else { state.f = ae_pow(b-state.x, alpha, _state)*(1+state.x); } } autogkresults(&state, &v, &rep, _state); if( rep.terminationtype<=0 ) { sngenderrors = ae_true; } else { sngenderrors = sngenderrors||ae_fp_greater(ae_fabs(-v-exact, _state),errtol*eabs); } } /* * end */ waserrors = simpleerrors||sngenderrors; if( !silent ) { printf("TESTING AUTOGK\n"); printf("INTEGRATION WITH GIVEN ACCURACY: "); if( simpleerrors||sngenderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* SIMPLE PROBLEMS: "); if( simpleerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* SINGULAR PROBLEMS (ENDS OF INTERVAL): "); if( sngenderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testautogk(ae_bool silent, ae_state *_state) { return testautogk(silent, _state); } static void testidwintunit_testxy(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, ae_bool* idwerrors, ae_state *_state); static void testidwintunit_testdegree(ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t dtask, ae_bool* idwerrors, ae_state *_state); static void testidwintunit_testnoisy(ae_bool* idwerrors, ae_state *_state); /************************************************************************* Testing IDW interpolation *************************************************************************/ ae_bool testidwint(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_int_t i; ae_int_t j; double vx; double vy; double vz; ae_int_t d; ae_int_t dtask; ae_int_t nx; ae_int_t nq; ae_int_t nw; ae_int_t smalln; ae_int_t largen; ae_bool waserrors; ae_bool idwerrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); idwerrors = ae_false; smalln = 256; largen = 1024; nq = 10; nw = 18; /* * Simple test: * * F = x^3 + sin(pi*y)*z^2 - (x+y)^2 * * space is either R1=[-1,+1] (other dimensions are * fixed at 0), R1^2 or R1^3. ** D = -1, 0, 1, 2 */ for(nx=1; nx<=2; nx++) { ae_matrix_set_length(&xy, largen, nx+1, _state); for(i=0; i<=largen-1; i++) { for(j=0; j<=nx-1; j++) { xy.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } if( nx>=1 ) { vx = xy.ptr.pp_double[i][0]; } else { vx = (double)(0); } if( nx>=2 ) { vy = xy.ptr.pp_double[i][1]; } else { vy = (double)(0); } if( nx>=3 ) { vz = xy.ptr.pp_double[i][2]; } else { vz = (double)(0); } xy.ptr.pp_double[i][nx] = vx*vx*vx+ae_sin(ae_pi*vy, _state)*ae_sqr(vz, _state)-ae_sqr(vx+vy, _state); } for(d=-1; d<=2; d++) { testidwintunit_testxy(&xy, largen, nx, d, nq, nw, &idwerrors, _state); } } /* * Another simple test: * * five points in 2D - (0,0), (0,1), (1,0), (-1,0) (0,-1) * * F is random * * D = -1, 0, 1, 2 */ nx = 2; ae_matrix_set_length(&xy, 5, nx+1, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(0); xy.ptr.pp_double[0][2] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(0); xy.ptr.pp_double[1][2] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[2][0] = (double)(0); xy.ptr.pp_double[2][1] = (double)(1); xy.ptr.pp_double[2][2] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[3][0] = (double)(-1); xy.ptr.pp_double[3][1] = (double)(0); xy.ptr.pp_double[3][2] = 2*ae_randomreal(_state)-1; xy.ptr.pp_double[4][0] = (double)(0); xy.ptr.pp_double[4][1] = (double)(-1); xy.ptr.pp_double[4][2] = 2*ae_randomreal(_state)-1; for(d=-1; d<=2; d++) { testidwintunit_testxy(&xy, 5, nx, d, nq, nw, &idwerrors, _state); } /* * Degree test. * * F is either: * * constant (DTask=0) * * linear (DTask=1) * * quadratic (DTask=2) * * Nodal functions are either * * constant (D=0) * * linear (D=1) * * quadratic (D=2) * * When DTask<=D, we can interpolate without errors. * When DTask>D, we MUST have errors. */ for(nx=1; nx<=3; nx++) { for(d=0; d<=2; d++) { for(dtask=0; dtask<=2; dtask++) { testidwintunit_testdegree(smalln, nx, d, dtask, &idwerrors, _state); } } } /* * Noisy test */ testidwintunit_testnoisy(&idwerrors, _state); /* * report */ waserrors = idwerrors; if( !silent ) { printf("TESTING INVERSE DISTANCE WEIGHTING\n"); printf("* IDW: "); if( !idwerrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testidwint(ae_bool silent, ae_state *_state) { return testidwint(silent, _state); } /************************************************************************* Testing IDW: * generate model using N/NX/D/NQ/NW * test basic properties *************************************************************************/ static void testidwintunit_testxy(/* Real */ ae_matrix* xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, ae_bool* idwerrors, ae_state *_state) { ae_frame _frame_block; double threshold; double lipschitzstep; ae_int_t i; ae_int_t i1; ae_int_t i2; double v; double v1; double v2; double t; double l1; double l2; idwinterpolant z1; ae_vector x; ae_frame_make(_state, &_frame_block); _idwinterpolant_init(&z1, _state); ae_vector_init(&x, 0, DT_REAL, _state); threshold = 1000*ae_machineepsilon; lipschitzstep = 0.001; ae_vector_set_length(&x, nx, _state); /* * build */ idwbuildmodifiedshepard(xy, n, nx, d, nq, nw, &z1, _state); /* * first, test interpolation properties at nodes */ for(i=0; i<=n-1; i++) { ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); *idwerrors = *idwerrors||ae_fp_neq(idwcalc(&z1, &x, _state),xy->ptr.pp_double[i][nx]); } /* * test Lipschitz continuity */ i1 = ae_randominteger(n, _state); do { i2 = ae_randominteger(n, _state); } while(i2==i1); l1 = (double)(0); t = (double)(0); while(ae_fp_less(t,(double)(1))) { v = 1-t; ae_v_moved(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i1][0], 1, ae_v_len(0,nx-1), v); v = t; ae_v_addd(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i2][0], 1, ae_v_len(0,nx-1), v); v1 = idwcalc(&z1, &x, _state); v = 1-(t+lipschitzstep); ae_v_moved(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i1][0], 1, ae_v_len(0,nx-1), v); v = t+lipschitzstep; ae_v_addd(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i2][0], 1, ae_v_len(0,nx-1), v); v2 = idwcalc(&z1, &x, _state); l1 = ae_maxreal(l1, ae_fabs(v2-v1, _state)/lipschitzstep, _state); t = t+lipschitzstep; } l2 = (double)(0); t = (double)(0); while(ae_fp_less(t,(double)(1))) { v = 1-t; ae_v_moved(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i1][0], 1, ae_v_len(0,nx-1), v); v = t; ae_v_addd(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i2][0], 1, ae_v_len(0,nx-1), v); v1 = idwcalc(&z1, &x, _state); v = 1-(t+lipschitzstep/3); ae_v_moved(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i1][0], 1, ae_v_len(0,nx-1), v); v = t+lipschitzstep/3; ae_v_addd(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i2][0], 1, ae_v_len(0,nx-1), v); v2 = idwcalc(&z1, &x, _state); l2 = ae_maxreal(l2, ae_fabs(v2-v1, _state)/(lipschitzstep/3), _state); t = t+lipschitzstep/3; } *idwerrors = *idwerrors||ae_fp_greater(l2,2.0*l1); ae_frame_leave(_state); } /************************************************************************* Testing degree properties F is either: * constant (DTask=0) * linear (DTask=1) * quadratic (DTask=2) Nodal functions are either * constant (D=0) * linear (D=1) * quadratic (D=2) When DTask<=D, we can interpolate without errors. When DTask>D, we MUST have errors. *************************************************************************/ static void testidwintunit_testdegree(ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t dtask, ae_bool* idwerrors, ae_state *_state) { ae_frame _frame_block; double threshold; ae_int_t nq; ae_int_t nw; ae_int_t i; ae_int_t j; double v; double c0; ae_vector c1; ae_matrix c2; ae_vector x; ae_matrix xy; idwinterpolant z1; double v1; double v2; ae_frame_make(_state, &_frame_block); ae_vector_init(&c1, 0, DT_REAL, _state); ae_matrix_init(&c2, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); _idwinterpolant_init(&z1, _state); threshold = 1.0E6*ae_machineepsilon; nq = 2*(nx*nx+nx+1); nw = 10; ae_assert(nq<=n, "TestDegree: internal error", _state); /* * prepare model */ c0 = 2*ae_randomreal(_state)-1; ae_vector_set_length(&c1, nx, _state); for(i=0; i<=nx-1; i++) { c1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_matrix_set_length(&c2, nx, nx, _state); for(i=0; i<=nx-1; i++) { for(j=i+1; j<=nx-1; j++) { c2.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; c2.ptr.pp_double[j][i] = c2.ptr.pp_double[i][j]; } do { c2.ptr.pp_double[i][i] = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_fabs(c2.ptr.pp_double[i][i], _state),0.3)); } /* * prepare points */ ae_matrix_set_length(&xy, n, nx+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { xy.ptr.pp_double[i][j] = 4*ae_randomreal(_state)-2; } xy.ptr.pp_double[i][nx] = c0; if( dtask>=1 ) { v = ae_v_dotproduct(&c1.ptr.p_double[0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); xy.ptr.pp_double[i][nx] = xy.ptr.pp_double[i][nx]+v; } if( dtask==2 ) { for(j=0; j<=nx-1; j++) { v = ae_v_dotproduct(&c2.ptr.pp_double[j][0], 1, &xy.ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); xy.ptr.pp_double[i][nx] = xy.ptr.pp_double[i][nx]+xy.ptr.pp_double[i][j]*v; } } } /* * build interpolant, calculate value at random point */ idwbuildmodifiedshepard(&xy, n, nx, d, nq, nw, &z1, _state); ae_vector_set_length(&x, nx, _state); for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = 4*ae_randomreal(_state)-2; } v1 = idwcalc(&z1, &x, _state); /* * calculate model value at the same point */ v2 = c0; if( dtask>=1 ) { v = ae_v_dotproduct(&c1.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,nx-1)); v2 = v2+v; } if( dtask==2 ) { for(j=0; j<=nx-1; j++) { v = ae_v_dotproduct(&c2.ptr.pp_double[j][0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,nx-1)); v2 = v2+x.ptr.p_double[j]*v; } } /* * Compare */ if( dtask<=d ) { *idwerrors = *idwerrors||ae_fp_greater(ae_fabs(v2-v1, _state),threshold); } else { *idwerrors = *idwerrors||ae_fp_less(ae_fabs(v2-v1, _state),threshold); } ae_frame_leave(_state); } /************************************************************************* Noisy test: * F = x^2 + y^2 + z^2 + noise on [-1,+1]^3 * space is either R1=[-1,+1] (other dimensions are fixed at 0), R1^2 or R1^3. * D = 1, 2 * 4096 points is used for function generation, 4096 points - for testing * RMS error of "noisy" model on test set must be lower than RMS error of interpolation model. *************************************************************************/ static void testidwintunit_testnoisy(ae_bool* idwerrors, ae_state *_state) { ae_frame _frame_block; double noiselevel; ae_int_t nq; ae_int_t nw; ae_int_t d; ae_int_t nx; ae_int_t ntrn; ae_int_t ntst; ae_int_t i; ae_int_t j; double v; double t; double v1; double v2; double ve; ae_matrix xy; ae_vector x; idwinterpolant z1; idwinterpolant z2; double rms1; double rms2; ae_frame_make(_state, &_frame_block); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); _idwinterpolant_init(&z1, _state); _idwinterpolant_init(&z2, _state); nq = 20; nw = 40; noiselevel = 0.2; ntrn = 256; ntst = 1024; for(d=1; d<=2; d++) { for(nx=1; nx<=2; nx++) { /* * prepare dataset */ ae_matrix_set_length(&xy, ntrn, nx+1, _state); for(i=0; i<=ntrn-1; i++) { v = noiselevel*(2*ae_randomreal(_state)-1); for(j=0; j<=nx-1; j++) { t = 2*ae_randomreal(_state)-1; v = v+ae_sqr(t, _state); xy.ptr.pp_double[i][j] = t; } xy.ptr.pp_double[i][nx] = v; } /* * build interpolants */ idwbuildmodifiedshepard(&xy, ntrn, nx, d, nq, nw, &z1, _state); idwbuildnoisy(&xy, ntrn, nx, d, nq, nw, &z2, _state); /* * calculate RMS errors */ ae_vector_set_length(&x, nx, _state); rms1 = (double)(0); rms2 = (double)(0); for(i=0; i<=ntst-1; i++) { ve = (double)(0); for(j=0; j<=nx-1; j++) { t = 2*ae_randomreal(_state)-1; x.ptr.p_double[j] = t; ve = ve+ae_sqr(t, _state); } v1 = idwcalc(&z1, &x, _state); v2 = idwcalc(&z2, &x, _state); rms1 = rms1+ae_sqr(v1-ve, _state); rms2 = rms2+ae_sqr(v2-ve, _state); } *idwerrors = *idwerrors||ae_fp_greater(rms2,rms1); } } ae_frame_leave(_state); } static void testratintunit_poldiff2(/* Real */ ae_vector* x, /* Real */ ae_vector* f, ae_int_t n, double t, double* p, double* dp, double* d2p, ae_state *_state); static void testratintunit_brcunset(barycentricinterpolant* b, ae_state *_state); ae_bool testratint(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool bcerrors; ae_bool nperrors; double threshold; double lipschitztol; ae_int_t maxn; ae_int_t passcount; barycentricinterpolant b1; barycentricinterpolant b2; ae_vector x; ae_vector x2; ae_vector y; ae_vector y2; ae_vector w; ae_vector w2; ae_vector xc; ae_vector yc; ae_vector dc; double h; double s1; double s2; ae_int_t n; ae_int_t n2; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t d; ae_int_t pass; double maxerr; double t; double a; double b; double s; double v0; double v1; double v2; double v3; double d0; double d1; double d2; ae_bool result; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_init(&b1, _state); _barycentricinterpolant_init(&b2, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); nperrors = ae_false; bcerrors = ae_false; waserrors = ae_false; /* * PassCount number of repeated passes * Threshold error tolerance * LipschitzTol Lipschitz constant increase allowed * when calculating constant on a twice denser grid */ passcount = 5; maxn = 15; threshold = 1000000*ae_machineepsilon; lipschitztol = 1.3; /* * Basic barycentric functions */ for(n=1; n<=10; n++) { /* * randomized tests */ for(pass=1; pass<=passcount; pass++) { /* * generate weights from polynomial interpolation */ v0 = 1+0.4*ae_randomreal(_state)-0.2; v1 = 2*ae_randomreal(_state)-1; v2 = 2*ae_randomreal(_state)-1; v3 = 2*ae_randomreal(_state)-1; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=n-1; i++) { if( n==1 ) { x.ptr.p_double[i] = (double)(0); } else { x.ptr.p_double[i] = v0*ae_cos(i*ae_pi/(n-1), _state); } y.ptr.p_double[i] = ae_sin(v1*x.ptr.p_double[i], _state)+ae_cos(v2*x.ptr.p_double[i], _state)+ae_exp(v3*x.ptr.p_double[i], _state); } for(j=0; j<=n-1; j++) { w.ptr.p_double[j] = (double)(1); for(k=0; k<=n-1; k++) { if( k!=j ) { w.ptr.p_double[j] = w.ptr.p_double[j]/(x.ptr.p_double[j]-x.ptr.p_double[k]); } } } barycentricbuildxyw(&x, &y, &w, n, &b1, _state); /* * unpack, then pack again and compare */ testratintunit_brcunset(&b2, _state); barycentricunpack(&b1, &n2, &x2, &y2, &w2, _state); bcerrors = bcerrors||n2!=n; barycentricbuildxyw(&x2, &y2, &w2, n2, &b2, _state); t = 2*ae_randomreal(_state)-1; bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, t, _state)-barycentriccalc(&b2, t, _state), _state),threshold); /* * copy, compare */ testratintunit_brcunset(&b2, _state); barycentriccopy(&b1, &b2, _state); t = 2*ae_randomreal(_state)-1; bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, t, _state)-barycentriccalc(&b2, t, _state), _state),threshold); /* * test interpolation properties */ for(i=0; i<=n-1; i++) { /* * test interpolation at nodes */ bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, x.ptr.p_double[i], _state)-y.ptr.p_double[i], _state),threshold*ae_fabs(y.ptr.p_double[i], _state)); /* * compare with polynomial interpolation */ t = 2*ae_randomreal(_state)-1; testratintunit_poldiff2(&x, &y, n, t, &v0, &v1, &v2, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, t, _state)-v0, _state),threshold*ae_maxreal(ae_fabs(v0, _state), (double)(1), _state)); /* * test continuity between nodes * calculate Lipschitz constant on two grids - * dense and even more dense. If Lipschitz constant * on a denser grid is significantly increased, * continuity test is failed */ t = 3.0; k = 100; s1 = (double)(0); for(j=0; j<=k-1; j++) { v1 = x.ptr.p_double[i]+(t-x.ptr.p_double[i])*j/k; v2 = x.ptr.p_double[i]+(t-x.ptr.p_double[i])*(j+1)/k; s1 = ae_maxreal(s1, ae_fabs(barycentriccalc(&b1, v2, _state)-barycentriccalc(&b1, v1, _state), _state)/ae_fabs(v2-v1, _state), _state); } k = 2*k; s2 = (double)(0); for(j=0; j<=k-1; j++) { v1 = x.ptr.p_double[i]+(t-x.ptr.p_double[i])*j/k; v2 = x.ptr.p_double[i]+(t-x.ptr.p_double[i])*(j+1)/k; s2 = ae_maxreal(s2, ae_fabs(barycentriccalc(&b1, v2, _state)-barycentriccalc(&b1, v1, _state), _state)/ae_fabs(v2-v1, _state), _state); } bcerrors = bcerrors||(ae_fp_greater(s2,lipschitztol*s1)&&ae_fp_greater(s1,threshold*k)); } /* * test differentiation properties */ for(i=0; i<=n-1; i++) { t = 2*ae_randomreal(_state)-1; testratintunit_poldiff2(&x, &y, n, t, &v0, &v1, &v2, _state); d0 = (double)(0); d1 = (double)(0); d2 = (double)(0); barycentricdiff1(&b1, t, &d0, &d1, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(v0-d0, _state),threshold*ae_maxreal(ae_fabs(v0, _state), (double)(1), _state)); bcerrors = bcerrors||ae_fp_greater(ae_fabs(v1-d1, _state),threshold*ae_maxreal(ae_fabs(v1, _state), (double)(1), _state)); d0 = (double)(0); d1 = (double)(0); d2 = (double)(0); barycentricdiff2(&b1, t, &d0, &d1, &d2, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(v0-d0, _state),threshold*ae_maxreal(ae_fabs(v0, _state), (double)(1), _state)); bcerrors = bcerrors||ae_fp_greater(ae_fabs(v1-d1, _state),threshold*ae_maxreal(ae_fabs(v1, _state), (double)(1), _state)); bcerrors = bcerrors||ae_fp_greater(ae_fabs(v2-d2, _state),ae_sqrt(threshold, _state)*ae_maxreal(ae_fabs(v2, _state), (double)(1), _state)); } /* * test linear translation */ t = 2*ae_randomreal(_state)-1; a = 2*ae_randomreal(_state)-1; b = 2*ae_randomreal(_state)-1; testratintunit_brcunset(&b2, _state); barycentriccopy(&b1, &b2, _state); barycentriclintransx(&b2, a, b, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, a*t+b, _state)-barycentriccalc(&b2, t, _state), _state),threshold); a = (double)(0); b = 2*ae_randomreal(_state)-1; testratintunit_brcunset(&b2, _state); barycentriccopy(&b1, &b2, _state); barycentriclintransx(&b2, a, b, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, a*t+b, _state)-barycentriccalc(&b2, t, _state), _state),threshold); a = 2*ae_randomreal(_state)-1; b = 2*ae_randomreal(_state)-1; testratintunit_brcunset(&b2, _state); barycentriccopy(&b1, &b2, _state); barycentriclintransy(&b2, a, b, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(a*barycentriccalc(&b1, t, _state)+b-barycentriccalc(&b2, t, _state), _state),threshold); } } for(pass=0; pass<=3; pass++) { /* * Crash-test: small numbers, large numbers */ ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); ae_vector_set_length(&w, 4, _state); h = (double)(1); if( pass%2==0 ) { h = 100*ae_minrealnumber; } if( pass%2==1 ) { h = 0.01*ae_maxrealnumber; } x.ptr.p_double[0] = 0*h; x.ptr.p_double[1] = 1*h; x.ptr.p_double[2] = 2*h; x.ptr.p_double[3] = 3*h; y.ptr.p_double[0] = 0*h; y.ptr.p_double[1] = 1*h; y.ptr.p_double[2] = 2*h; y.ptr.p_double[3] = 3*h; w.ptr.p_double[0] = -1/(x.ptr.p_double[1]-x.ptr.p_double[0]); w.ptr.p_double[1] = 1*(1/(x.ptr.p_double[1]-x.ptr.p_double[0])+1/(x.ptr.p_double[2]-x.ptr.p_double[1])); w.ptr.p_double[2] = -1*(1/(x.ptr.p_double[2]-x.ptr.p_double[1])+1/(x.ptr.p_double[3]-x.ptr.p_double[2])); w.ptr.p_double[3] = 1/(x.ptr.p_double[3]-x.ptr.p_double[2]); v0 = (double)(0); if( pass/2==0 ) { v0 = (double)(0); } if( pass/2==1 ) { v0 = 0.6*h; } barycentricbuildxyw(&x, &y, &w, 4, &b1, _state); t = barycentriccalc(&b1, v0, _state); d0 = (double)(0); d1 = (double)(0); d2 = (double)(0); barycentricdiff1(&b1, v0, &d0, &d1, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(t-v0, _state),threshold*v0); bcerrors = bcerrors||ae_fp_greater(ae_fabs(d0-v0, _state),threshold*v0); bcerrors = bcerrors||ae_fp_greater(ae_fabs(d1-1, _state),1000*threshold); } /* * crash test: large abscissas, small argument * * test for errors in D0 is not very strict * because renormalization used in Diff1() * destroys part of precision. */ ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); ae_vector_set_length(&w, 4, _state); h = 0.01*ae_maxrealnumber; x.ptr.p_double[0] = 0*h; x.ptr.p_double[1] = 1*h; x.ptr.p_double[2] = 2*h; x.ptr.p_double[3] = 3*h; y.ptr.p_double[0] = 0*h; y.ptr.p_double[1] = 1*h; y.ptr.p_double[2] = 2*h; y.ptr.p_double[3] = 3*h; w.ptr.p_double[0] = -1/(x.ptr.p_double[1]-x.ptr.p_double[0]); w.ptr.p_double[1] = 1*(1/(x.ptr.p_double[1]-x.ptr.p_double[0])+1/(x.ptr.p_double[2]-x.ptr.p_double[1])); w.ptr.p_double[2] = -1*(1/(x.ptr.p_double[2]-x.ptr.p_double[1])+1/(x.ptr.p_double[3]-x.ptr.p_double[2])); w.ptr.p_double[3] = 1/(x.ptr.p_double[3]-x.ptr.p_double[2]); v0 = 100*ae_minrealnumber; barycentricbuildxyw(&x, &y, &w, 4, &b1, _state); t = barycentriccalc(&b1, v0, _state); d0 = (double)(0); d1 = (double)(0); d2 = (double)(0); barycentricdiff1(&b1, v0, &d0, &d1, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(t, _state),v0*(1+threshold)); bcerrors = bcerrors||ae_fp_greater(ae_fabs(d0, _state),v0*(1+threshold)); bcerrors = bcerrors||ae_fp_greater(ae_fabs(d1-1, _state),1000*threshold); /* * crash test: test safe barycentric formula */ ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); ae_vector_set_length(&w, 4, _state); h = 2*ae_minrealnumber; x.ptr.p_double[0] = 0*h; x.ptr.p_double[1] = 1*h; x.ptr.p_double[2] = 2*h; x.ptr.p_double[3] = 3*h; y.ptr.p_double[0] = 0*h; y.ptr.p_double[1] = 1*h; y.ptr.p_double[2] = 2*h; y.ptr.p_double[3] = 3*h; w.ptr.p_double[0] = -1/(x.ptr.p_double[1]-x.ptr.p_double[0]); w.ptr.p_double[1] = 1*(1/(x.ptr.p_double[1]-x.ptr.p_double[0])+1/(x.ptr.p_double[2]-x.ptr.p_double[1])); w.ptr.p_double[2] = -1*(1/(x.ptr.p_double[2]-x.ptr.p_double[1])+1/(x.ptr.p_double[3]-x.ptr.p_double[2])); w.ptr.p_double[3] = 1/(x.ptr.p_double[3]-x.ptr.p_double[2]); v0 = ae_minrealnumber; barycentricbuildxyw(&x, &y, &w, 4, &b1, _state); t = barycentriccalc(&b1, v0, _state); bcerrors = bcerrors||ae_fp_greater(ae_fabs(t-v0, _state)/v0,threshold); /* * Testing "No Poles" interpolation */ maxerr = (double)(0); for(pass=1; pass<=passcount-1; pass++) { ae_vector_set_length(&x, 1, _state); ae_vector_set_length(&y, 1, _state); x.ptr.p_double[0] = 2*ae_randomreal(_state)-1; y.ptr.p_double[0] = 2*ae_randomreal(_state)-1; barycentricbuildfloaterhormann(&x, &y, 1, 1, &b1, _state); maxerr = ae_maxreal(maxerr, ae_fabs(barycentriccalc(&b1, 2*ae_randomreal(_state)-1, _state)-y.ptr.p_double[0], _state), _state); } for(n=2; n<=10; n++) { /* * compare interpolant built by subroutine * with interpolant built by hands */ ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&w2, n, _state); /* * D=1, non-equidistant nodes */ for(pass=1; pass<=passcount; pass++) { /* * Initialize X, Y, W */ a = -1-1*ae_randomreal(_state); b = 1+1*ae_randomreal(_state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_atan((b-a)*i/(n-1)+a, _state); } for(i=0; i<=n-1; i++) { y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } w.ptr.p_double[0] = -1/(x.ptr.p_double[1]-x.ptr.p_double[0]); s = (double)(1); for(i=1; i<=n-2; i++) { w.ptr.p_double[i] = s*(1/(x.ptr.p_double[i]-x.ptr.p_double[i-1])+1/(x.ptr.p_double[i+1]-x.ptr.p_double[i])); s = -s; } w.ptr.p_double[n-1] = s/(x.ptr.p_double[n-1]-x.ptr.p_double[n-2]); for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = x.ptr.p_double[i]; x.ptr.p_double[i] = x.ptr.p_double[k]; x.ptr.p_double[k] = t; t = y.ptr.p_double[i]; y.ptr.p_double[i] = y.ptr.p_double[k]; y.ptr.p_double[k] = t; t = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = t; } } /* * Build and test */ barycentricbuildfloaterhormann(&x, &y, n, 1, &b1, _state); barycentricbuildxyw(&x, &y, &w, n, &b2, _state); for(i=1; i<=2*n; i++) { t = a+(b-a)*ae_randomreal(_state); maxerr = ae_maxreal(maxerr, ae_fabs(barycentriccalc(&b1, t, _state)-barycentriccalc(&b2, t, _state), _state), _state); } } /* * D = 0, 1, 2. Equidistant nodes. */ for(d=0; d<=2; d++) { for(pass=1; pass<=passcount; pass++) { /* * Skip incorrect (N,D) pairs */ if( n<2*d ) { continue; } /* * Initialize X, Y, W */ a = -1-1*ae_randomreal(_state); b = 1+1*ae_randomreal(_state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (b-a)*i/(n-1)+a; } for(i=0; i<=n-1; i++) { y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } s = (double)(1); if( d==0 ) { for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = s; s = -s; } } if( d==1 ) { w.ptr.p_double[0] = -s; for(i=1; i<=n-2; i++) { w.ptr.p_double[i] = 2*s; s = -s; } w.ptr.p_double[n-1] = s; } if( d==2 ) { w.ptr.p_double[0] = s; w.ptr.p_double[1] = -3*s; for(i=2; i<=n-3; i++) { w.ptr.p_double[i] = 4*s; s = -s; } w.ptr.p_double[n-2] = 3*s; w.ptr.p_double[n-1] = -s; } /* * Mix */ for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = x.ptr.p_double[i]; x.ptr.p_double[i] = x.ptr.p_double[k]; x.ptr.p_double[k] = t; t = y.ptr.p_double[i]; y.ptr.p_double[i] = y.ptr.p_double[k]; y.ptr.p_double[k] = t; t = w.ptr.p_double[i]; w.ptr.p_double[i] = w.ptr.p_double[k]; w.ptr.p_double[k] = t; } } /* * Build and test */ barycentricbuildfloaterhormann(&x, &y, n, d, &b1, _state); barycentricbuildxyw(&x, &y, &w, n, &b2, _state); for(i=1; i<=2*n; i++) { t = a+(b-a)*ae_randomreal(_state); maxerr = ae_maxreal(maxerr, ae_fabs(barycentriccalc(&b1, t, _state)-barycentriccalc(&b2, t, _state), _state), _state); } } } } if( ae_fp_greater(maxerr,threshold) ) { nperrors = ae_true; } /* * report */ waserrors = bcerrors||nperrors; if( !silent ) { printf("TESTING RATIONAL INTERPOLATION\n"); printf("BASIC BARYCENTRIC FUNCTIONS: "); if( bcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("FLOATER-HORMANN: "); if( nperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testratint(ae_bool silent, ae_state *_state) { return testratint(silent, _state); } static void testratintunit_poldiff2(/* Real */ ae_vector* x, /* Real */ ae_vector* f, ae_int_t n, double t, double* p, double* dp, double* d2p, ae_state *_state) { ae_frame _frame_block; ae_vector _f; ae_int_t m; ae_int_t i; ae_vector df; ae_vector d2f; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_f, f, _state); f = &_f; *p = 0; *dp = 0; *d2p = 0; ae_vector_init(&df, 0, DT_REAL, _state); ae_vector_init(&d2f, 0, DT_REAL, _state); n = n-1; ae_vector_set_length(&df, n+1, _state); ae_vector_set_length(&d2f, n+1, _state); for(i=0; i<=n; i++) { d2f.ptr.p_double[i] = (double)(0); df.ptr.p_double[i] = (double)(0); } for(m=1; m<=n; m++) { for(i=0; i<=n-m; i++) { d2f.ptr.p_double[i] = ((t-x->ptr.p_double[i+m])*d2f.ptr.p_double[i]+(x->ptr.p_double[i]-t)*d2f.ptr.p_double[i+1]+2*df.ptr.p_double[i]-2*df.ptr.p_double[i+1])/(x->ptr.p_double[i]-x->ptr.p_double[i+m]); df.ptr.p_double[i] = ((t-x->ptr.p_double[i+m])*df.ptr.p_double[i]+f->ptr.p_double[i]+(x->ptr.p_double[i]-t)*df.ptr.p_double[i+1]-f->ptr.p_double[i+1])/(x->ptr.p_double[i]-x->ptr.p_double[i+m]); f->ptr.p_double[i] = ((t-x->ptr.p_double[i+m])*f->ptr.p_double[i]+(x->ptr.p_double[i]-t)*f->ptr.p_double[i+1])/(x->ptr.p_double[i]-x->ptr.p_double[i+m]); } } *p = f->ptr.p_double[0]; *dp = df.ptr.p_double[0]; *d2p = d2f.ptr.p_double[0]; ae_frame_leave(_state); } static void testratintunit_brcunset(barycentricinterpolant* b, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector w; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_set_length(&x, 1, _state); ae_vector_set_length(&y, 1, _state); ae_vector_set_length(&w, 1, _state); x.ptr.p_double[0] = (double)(0); y.ptr.p_double[0] = (double)(0); w.ptr.p_double[0] = (double)(1); barycentricbuildxyw(&x, &y, &w, 1, b, _state); ae_frame_leave(_state); } static double testpolintunit_internalpolint(/* Real */ ae_vector* x, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state); static void testpolintunit_brcunset(barycentricinterpolant* b, ae_state *_state); /************************************************************************* Unit test *************************************************************************/ ae_bool testpolint(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool interrors; double threshold; ae_vector x; ae_vector y; ae_vector w; ae_vector c; ae_vector c0; ae_vector c1; ae_vector c2; ae_vector x2; ae_vector y2; ae_vector w2; ae_vector xfull; ae_vector yfull; double a; double b; double t; ae_int_t i; ae_int_t k; ae_vector xc; ae_vector yc; ae_vector dc; double v; double v0; double v1; double v2; double v3; double v4; double pscale; double poffset; double eps; barycentricinterpolant p; barycentricinterpolant p1; barycentricinterpolant p2; ae_int_t n; ae_int_t maxn; ae_int_t pass; ae_int_t passcount; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&c0, 0, DT_REAL, _state); ae_vector_init(&c1, 0, DT_REAL, _state); ae_vector_init(&c2, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xfull, 0, DT_REAL, _state); ae_vector_init(&yfull, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); _barycentricinterpolant_init(&p, _state); _barycentricinterpolant_init(&p1, _state); _barycentricinterpolant_init(&p2, _state); waserrors = ae_false; interrors = ae_false; maxn = 5; passcount = 20; threshold = 1.0E8*ae_machineepsilon; /* * Test equidistant interpolation */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { /* * prepare task: * * equidistant points * * random Y * * T in [A,B] or near (within 10% of its width) */ do { a = 2*ae_randomreal(_state)-1; b = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_fabs(a-b, _state),0.2)); t = a+(1.2*ae_randomreal(_state)-0.1)*(b-a); taskgenint1dequidist(a, b, n, &x, &y, _state); /* * test "fast" equidistant interpolation (no barycentric model) */ interrors = interrors||ae_fp_greater(ae_fabs(polynomialcalceqdist(a, b, &y, n, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "slow" equidistant interpolation (create barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuild(&x, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "fast" interpolation (create "fast" barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuildeqdist(a, b, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); } } /* * Test Chebyshev-1 interpolation */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { /* * prepare task: * * equidistant points * * random Y * * T in [A,B] or near (within 10% of its width) */ do { a = 2*ae_randomreal(_state)-1; b = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_fabs(a-b, _state),0.2)); t = a+(1.2*ae_randomreal(_state)-0.1)*(b-a); taskgenint1dcheb1(a, b, n, &x, &y, _state); /* * test "fast" interpolation (no barycentric model) */ interrors = interrors||ae_fp_greater(ae_fabs(polynomialcalccheb1(a, b, &y, n, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "slow" interpolation (create barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuild(&x, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "fast" interpolation (create "fast" barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuildcheb1(a, b, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); } } /* * Test Chebyshev-2 interpolation */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { /* * prepare task: * * equidistant points * * random Y * * T in [A,B] or near (within 10% of its width) */ do { a = 2*ae_randomreal(_state)-1; b = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_fabs(a-b, _state),0.2)); t = a+(1.2*ae_randomreal(_state)-0.1)*(b-a); taskgenint1dcheb2(a, b, n, &x, &y, _state); /* * test "fast" interpolation (no barycentric model) */ interrors = interrors||ae_fp_greater(ae_fabs(polynomialcalccheb2(a, b, &y, n, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "slow" interpolation (create barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuild(&x, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); /* * test "fast" interpolation (create "fast" barycentric model) */ testpolintunit_brcunset(&p, _state); polynomialbuildcheb2(a, b, &y, n, &p, _state); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, t, _state)-testpolintunit_internalpolint(&x, &y, n, t, _state), _state),threshold); } } /* * Testing conversion Barycentric<->Chebyshev */ for(pass=1; pass<=passcount; pass++) { for(k=1; k<=3; k++) { /* * Allocate */ ae_vector_set_length(&x, k, _state); ae_vector_set_length(&y, k, _state); /* * Generate problem */ a = 2*ae_randomreal(_state)-1; b = a+(0.1+ae_randomreal(_state))*(2*ae_randominteger(2, _state)-1); v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; v2 = 2*ae_randomreal(_state)-1; if( k==1 ) { x.ptr.p_double[0] = 0.5*(a+b); y.ptr.p_double[0] = v0; } if( k==2 ) { x.ptr.p_double[0] = a; y.ptr.p_double[0] = v0-v1; x.ptr.p_double[1] = b; y.ptr.p_double[1] = v0+v1; } if( k==3 ) { x.ptr.p_double[0] = a; y.ptr.p_double[0] = v0-v1+v2; x.ptr.p_double[1] = 0.5*(a+b); y.ptr.p_double[1] = v0-v2; x.ptr.p_double[2] = b; y.ptr.p_double[2] = v0+v1+v2; } /* * Test forward conversion */ polynomialbuild(&x, &y, k, &p, _state); ae_vector_set_length(&c, 1, _state); polynomialbar2cheb(&p, a, b, &c, _state); interrors = interrors||c.cnt!=k; if( k>=1 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[0]-v0, _state),threshold); } if( k>=2 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[1]-v1, _state),threshold); } if( k>=3 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[2]-v2, _state),threshold); } /* * Test backward conversion */ polynomialcheb2bar(&c, k, a, b, &p2, _state); v = a+ae_randomreal(_state)*(b-a); interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, v, _state)-barycentriccalc(&p2, v, _state), _state),threshold); } } /* * Testing conversion Barycentric<->Power */ for(pass=1; pass<=passcount; pass++) { for(k=1; k<=5; k++) { /* * Allocate */ ae_vector_set_length(&x, k, _state); ae_vector_set_length(&y, k, _state); /* * Generate problem */ poffset = 2*ae_randomreal(_state)-1; pscale = (0.1+ae_randomreal(_state))*(2*ae_randominteger(2, _state)-1); v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; v2 = 2*ae_randomreal(_state)-1; v3 = 2*ae_randomreal(_state)-1; v4 = 2*ae_randomreal(_state)-1; if( k==1 ) { x.ptr.p_double[0] = poffset; y.ptr.p_double[0] = v0; } if( k==2 ) { x.ptr.p_double[0] = poffset-pscale; y.ptr.p_double[0] = v0-v1; x.ptr.p_double[1] = poffset+pscale; y.ptr.p_double[1] = v0+v1; } if( k==3 ) { x.ptr.p_double[0] = poffset-pscale; y.ptr.p_double[0] = v0-v1+v2; x.ptr.p_double[1] = poffset; y.ptr.p_double[1] = v0; x.ptr.p_double[2] = poffset+pscale; y.ptr.p_double[2] = v0+v1+v2; } if( k==4 ) { x.ptr.p_double[0] = poffset-pscale; y.ptr.p_double[0] = v0-v1+v2-v3; x.ptr.p_double[1] = poffset-0.5*pscale; y.ptr.p_double[1] = v0-0.5*v1+0.25*v2-0.125*v3; x.ptr.p_double[2] = poffset+0.5*pscale; y.ptr.p_double[2] = v0+0.5*v1+0.25*v2+0.125*v3; x.ptr.p_double[3] = poffset+pscale; y.ptr.p_double[3] = v0+v1+v2+v3; } if( k==5 ) { x.ptr.p_double[0] = poffset-pscale; y.ptr.p_double[0] = v0-v1+v2-v3+v4; x.ptr.p_double[1] = poffset-0.5*pscale; y.ptr.p_double[1] = v0-0.5*v1+0.25*v2-0.125*v3+0.0625*v4; x.ptr.p_double[2] = poffset; y.ptr.p_double[2] = v0; x.ptr.p_double[3] = poffset+0.5*pscale; y.ptr.p_double[3] = v0+0.5*v1+0.25*v2+0.125*v3+0.0625*v4; x.ptr.p_double[4] = poffset+pscale; y.ptr.p_double[4] = v0+v1+v2+v3+v4; } /* * Test forward conversion */ polynomialbuild(&x, &y, k, &p, _state); ae_vector_set_length(&c, 1, _state); polynomialbar2pow(&p, poffset, pscale, &c, _state); interrors = interrors||c.cnt!=k; if( k>=1 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[0]-v0, _state),threshold); } if( k>=2 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[1]-v1, _state),threshold); } if( k>=3 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[2]-v2, _state),threshold); } if( k>=4 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[3]-v3, _state),threshold); } if( k>=5 ) { interrors = interrors||ae_fp_greater(ae_fabs(c.ptr.p_double[4]-v4, _state),threshold); } /* * Test backward conversion */ polynomialpow2bar(&c, k, poffset, pscale, &p2, _state); v = poffset+(2*ae_randomreal(_state)-1)*pscale; interrors = interrors||ae_fp_greater(ae_fabs(barycentriccalc(&p, v, _state)-barycentriccalc(&p2, v, _state), _state),threshold); } } /* * crash-test: ability to solve tasks which will overflow/underflow * weights with straightforward implementation */ for(n=1; n<=20; n++) { a = -0.1*ae_maxrealnumber; b = 0.1*ae_maxrealnumber; taskgenint1dequidist(a, b, n, &x, &y, _state); polynomialbuild(&x, &y, n, &p, _state); for(i=0; i<=n-1; i++) { interrors = interrors||ae_fp_eq(p.w.ptr.p_double[i],(double)(0)); } } /* * Test issue #634: instability in PolynomialBar2Pow(). * * Function returns incorrect coefficients when called with * approximately-unit scale for data which have significantly * non-unit scale. */ n = 7; eps = 1.0E-8; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x2, n, _state); ae_vector_set_length(&y, n, _state); x.ptr.p_double[0] = ae_randomreal(_state)-0.5; y.ptr.p_double[0] = ae_randomreal(_state)-0.5; for(i=1; i<=n-1; i++) { x.ptr.p_double[i] = x.ptr.p_double[i-1]+ae_randomreal(_state)+0.1; y.ptr.p_double[i] = ae_randomreal(_state)-0.5; } polynomialbuild(&x, &y, n, &p, _state); polynomialbar2pow(&p, 0.0, 1.0, &c0, _state); pscale = 1.0E-10; for(i=0; i<=n-1; i++) { x2.ptr.p_double[i] = x.ptr.p_double[i]*pscale; } polynomialbuild(&x2, &y, n, &p, _state); polynomialbar2pow(&p, 0.0, 1.0, &c1, _state); for(i=0; i<=n-1; i++) { seterrorflag(&interrors, ae_fp_greater(ae_fabs(c0.ptr.p_double[i]-c1.ptr.p_double[i]*ae_pow(pscale, (double)(i), _state), _state),eps), _state); } pscale = 1.0E10; for(i=0; i<=n-1; i++) { x2.ptr.p_double[i] = x.ptr.p_double[i]*pscale; } polynomialbuild(&x2, &y, n, &p, _state); polynomialbar2pow(&p, 0.0, 1.0, &c2, _state); for(i=0; i<=n-1; i++) { seterrorflag(&interrors, ae_fp_greater(ae_fabs(c0.ptr.p_double[i]-c2.ptr.p_double[i]*ae_pow(pscale, (double)(i), _state), _state),eps), _state); } /* * report */ waserrors = interrors; if( !silent ) { printf("TESTING POLYNOMIAL INTERPOLATION\n"); /* * Normal tests */ printf("INTERPOLATION TEST: "); if( interrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testpolint(ae_bool silent, ae_state *_state) { return testpolint(silent, _state); } static double testpolintunit_internalpolint(/* Real */ ae_vector* x, /* Real */ ae_vector* f, ae_int_t n, double t, ae_state *_state) { ae_frame _frame_block; ae_vector _f; ae_int_t i; ae_int_t j; double result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_f, f, _state); f = &_f; n = n-1; for(j=0; j<=n-1; j++) { for(i=j+1; i<=n; i++) { f->ptr.p_double[i] = ((t-x->ptr.p_double[j])*f->ptr.p_double[i]-(t-x->ptr.p_double[i])*f->ptr.p_double[j])/(x->ptr.p_double[i]-x->ptr.p_double[j]); } } result = f->ptr.p_double[n]; ae_frame_leave(_state); return result; } static void testpolintunit_brcunset(barycentricinterpolant* b, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector w; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_set_length(&x, 1, _state); ae_vector_set_length(&y, 1, _state); ae_vector_set_length(&w, 1, _state); x.ptr.p_double[0] = (double)(0); y.ptr.p_double[0] = (double)(0); w.ptr.p_double[0] = (double)(1); barycentricbuildxyw(&x, &y, &w, 1, b, _state); ae_frame_leave(_state); } static void testspline1dunit_lconst(double a, double b, spline1dinterpolant* c, double lstep, double* l0, double* l1, double* l2, ae_state *_state); static ae_bool testspline1dunit_enumerateallsplines(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t* splineindex, spline1dinterpolant* s, ae_state *_state); static ae_bool testspline1dunit_testunpack(spline1dinterpolant* c, /* Real */ ae_vector* x, ae_state *_state); static void testspline1dunit_unsetspline1d(spline1dinterpolant* c, ae_state *_state); static ae_bool testspline1dunit_testmonotonespline(ae_state *_state); ae_bool testspline1d(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool crserrors; ae_bool cserrors; ae_bool hserrors; ae_bool aserrors; ae_bool lserrors; ae_bool dserrors; ae_bool uperrors; ae_bool cperrors; ae_bool lterrors; ae_bool ierrors; ae_bool monotoneerr; double nonstrictthreshold; double threshold; ae_int_t passcount; double lstep; double h; ae_int_t maxn; ae_int_t bltype; ae_int_t brtype; ae_bool periodiccond; ae_int_t n; ae_int_t i; ae_int_t k; ae_int_t pass; ae_vector x; ae_vector y; ae_vector yp; ae_vector w; ae_vector w2; ae_vector y2; ae_vector d; ae_vector xc; ae_vector yc; ae_vector xtest; ae_int_t n2; ae_vector tmp0; ae_vector tmp1; ae_vector tmp2; ae_vector tmpx; ae_vector dc; spline1dinterpolant c; spline1dinterpolant c2; double a; double b; double bl; double br; double t; double sa; double sb; double v; double l10; double l11; double l12; double l20; double l21; double l22; double p0; double p1; double p2; double s; double ds; double d2s; double s2; double ds2; double d2s2; double vl; double vm; double vr; double err; double tension; double intab; ae_int_t splineindex; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&yp, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&xtest, 0, DT_REAL, _state); ae_vector_init(&tmp0, 0, DT_REAL, _state); ae_vector_init(&tmp1, 0, DT_REAL, _state); ae_vector_init(&tmp2, 0, DT_REAL, _state); ae_vector_init(&tmpx, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); _spline1dinterpolant_init(&c, _state); _spline1dinterpolant_init(&c2, _state); waserrors = ae_false; passcount = 20; lstep = 0.005; h = 0.00001; maxn = 10; threshold = 10000*ae_machineepsilon; nonstrictthreshold = 0.00001; lserrors = ae_false; cserrors = ae_false; crserrors = ae_false; hserrors = ae_false; aserrors = ae_false; dserrors = ae_false; cperrors = ae_false; uperrors = ae_false; lterrors = ae_false; ierrors = ae_false; /* * General test: linear, cubic, Hermite, Akima */ for(n=2; n<=maxn; n++) { ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); ae_vector_set_length(&yp, n-1+1, _state); ae_vector_set_length(&d, n-1+1, _state); for(pass=1; pass<=passcount; pass++) { /* * Prepare task: * * X contains abscissas from [A,B] * * Y contains function values * * YP contains periodic function values */ a = -1-ae_randomreal(_state); b = 1+ae_randomreal(_state); bl = 2*ae_randomreal(_state)-1; br = 2*ae_randomreal(_state)-1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(2*i+1)/(2*n), _state); if( i==0 ) { x.ptr.p_double[i] = a; } if( i==n-1 ) { x.ptr.p_double[i] = b; } y.ptr.p_double[i] = ae_cos(1.3*ae_pi*x.ptr.p_double[i]+0.4, _state); yp.ptr.p_double[i] = y.ptr.p_double[i]; d.ptr.p_double[i] = -1.3*ae_pi*ae_sin(1.3*ae_pi*x.ptr.p_double[i]+0.4, _state); } yp.ptr.p_double[n-1] = yp.ptr.p_double[0]; for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = x.ptr.p_double[i]; x.ptr.p_double[i] = x.ptr.p_double[k]; x.ptr.p_double[k] = t; t = y.ptr.p_double[i]; y.ptr.p_double[i] = y.ptr.p_double[k]; y.ptr.p_double[k] = t; t = yp.ptr.p_double[i]; yp.ptr.p_double[i] = yp.ptr.p_double[k]; yp.ptr.p_double[k] = t; t = d.ptr.p_double[i]; d.ptr.p_double[i] = d.ptr.p_double[k]; d.ptr.p_double[k] = t; } } /* * Build linear spline * Test for general interpolation scheme properties: * * values at nodes * * continuous function * Test for specific properties is implemented below. */ spline1dbuildlinear(&x, &y, n, &c, _state); err = (double)(0); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state), _state); } lserrors = lserrors||ae_fp_greater(err,threshold); testspline1dunit_lconst(a, b, &c, lstep, &l10, &l11, &l12, _state); testspline1dunit_lconst(a, b, &c, lstep/3, &l20, &l21, &l22, _state); lserrors = lserrors||ae_fp_greater(l20/l10,1.2); /* * Build cubic spline. * Test for interpolation scheme properties: * * values at nodes * * boundary conditions * * continuous function * * continuous first derivative * * continuous second derivative * * periodicity properties * * Spline1DGridDiff(), Spline1DGridDiff2() and Spline1DDiff() * calls must return same results */ for(bltype=-1; bltype<=2; bltype++) { for(brtype=-1; brtype<=2; brtype++) { /* * skip meaningless combination of boundary conditions * (one condition is periodic, another is not) */ periodiccond = bltype==-1||brtype==-1; if( periodiccond&&bltype!=brtype ) { continue; } /* * build */ if( periodiccond ) { spline1dbuildcubic(&x, &yp, n, bltype, bl, brtype, br, &c, _state); } else { spline1dbuildcubic(&x, &y, n, bltype, bl, brtype, br, &c, _state); } /* * interpolation properties */ err = (double)(0); if( periodiccond ) { /* * * check values at nodes; spline is periodic so * we add random number of periods to nodes * * we also test for periodicity of derivatives */ for(i=0; i<=n-1; i++) { v = x.ptr.p_double[i]; vm = v+(b-a)*(ae_randominteger(5, _state)-2); t = yp.ptr.p_double[i]-spline1dcalc(&c, vm, _state); err = ae_maxreal(err, ae_fabs(t, _state), _state); spline1ddiff(&c, v, &s, &ds, &d2s, _state); spline1ddiff(&c, vm, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); err = ae_maxreal(err, ae_fabs(d2s-d2s2, _state), _state); } /* * periodicity between nodes */ v = a+(b-a)*ae_randomreal(_state); vm = v+(b-a)*(ae_randominteger(5, _state)-2); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, v, _state)-spline1dcalc(&c, vm, _state), _state), _state); spline1ddiff(&c, v, &s, &ds, &d2s, _state); spline1ddiff(&c, vm, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); err = ae_maxreal(err, ae_fabs(d2s-d2s2, _state), _state); } else { /* * * check values at nodes */ for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state), _state); } } cserrors = cserrors||ae_fp_greater(err,threshold); /* * check boundary conditions */ err = (double)(0); if( bltype==0 ) { spline1ddiff(&c, a-h, &s, &ds, &d2s, _state); spline1ddiff(&c, a+h, &s2, &ds2, &d2s2, _state); t = (d2s2-d2s)/(2*h); err = ae_maxreal(err, ae_fabs(t, _state), _state); } if( bltype==1 ) { t = (spline1dcalc(&c, a+h, _state)-spline1dcalc(&c, a-h, _state))/(2*h); err = ae_maxreal(err, ae_fabs(bl-t, _state), _state); } if( bltype==2 ) { t = (spline1dcalc(&c, a+h, _state)-2*spline1dcalc(&c, a, _state)+spline1dcalc(&c, a-h, _state))/ae_sqr(h, _state); err = ae_maxreal(err, ae_fabs(bl-t, _state), _state); } if( brtype==0 ) { spline1ddiff(&c, b-h, &s, &ds, &d2s, _state); spline1ddiff(&c, b+h, &s2, &ds2, &d2s2, _state); t = (d2s2-d2s)/(2*h); err = ae_maxreal(err, ae_fabs(t, _state), _state); } if( brtype==1 ) { t = (spline1dcalc(&c, b+h, _state)-spline1dcalc(&c, b-h, _state))/(2*h); err = ae_maxreal(err, ae_fabs(br-t, _state), _state); } if( brtype==2 ) { t = (spline1dcalc(&c, b+h, _state)-2*spline1dcalc(&c, b, _state)+spline1dcalc(&c, b-h, _state))/ae_sqr(h, _state); err = ae_maxreal(err, ae_fabs(br-t, _state), _state); } if( bltype==-1||brtype==-1 ) { spline1ddiff(&c, a+100*ae_machineepsilon, &s, &ds, &d2s, _state); spline1ddiff(&c, b-100*ae_machineepsilon, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); err = ae_maxreal(err, ae_fabs(d2s-d2s2, _state), _state); } cserrors = cserrors||ae_fp_greater(err,1.0E-3); /* * Check Lipschitz continuity */ testspline1dunit_lconst(a, b, &c, lstep, &l10, &l11, &l12, _state); testspline1dunit_lconst(a, b, &c, lstep/3, &l20, &l21, &l22, _state); if( ae_fp_greater(l10,1.0E-6) ) { cserrors = cserrors||ae_fp_greater(l20/l10,1.2); } if( ae_fp_greater(l11,1.0E-6) ) { cserrors = cserrors||ae_fp_greater(l21/l11,1.2); } if( ae_fp_greater(l12,1.0E-6) ) { cserrors = cserrors||ae_fp_greater(l22/l12,1.2); } /* * compare spline1dgriddiff() and spline1ddiff() results */ err = (double)(0); if( periodiccond ) { spline1dgriddiffcubic(&x, &yp, n, bltype, bl, brtype, br, &tmp1, _state); } else { spline1dgriddiffcubic(&x, &y, n, bltype, bl, brtype, br, &tmp1, _state); } ae_assert(tmp1.cnt>=n, "Assertion failed", _state); for(i=0; i<=n-1; i++) { spline1ddiff(&c, x.ptr.p_double[i], &s, &ds, &d2s, _state); err = ae_maxreal(err, ae_fabs(ds-tmp1.ptr.p_double[i], _state), _state); } if( periodiccond ) { spline1dgriddiff2cubic(&x, &yp, n, bltype, bl, brtype, br, &tmp1, &tmp2, _state); } else { spline1dgriddiff2cubic(&x, &y, n, bltype, bl, brtype, br, &tmp1, &tmp2, _state); } for(i=0; i<=n-1; i++) { spline1ddiff(&c, x.ptr.p_double[i], &s, &ds, &d2s, _state); err = ae_maxreal(err, ae_fabs(ds-tmp1.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(d2s-tmp2.ptr.p_double[i], _state), _state); } cserrors = cserrors||ae_fp_greater(err,threshold); /* * compare spline1dconv()/convdiff()/convdiff2() and spline1ddiff() results */ n2 = 2+ae_randominteger(2*n, _state); ae_vector_set_length(&tmpx, n2, _state); for(i=0; i<=n2-1; i++) { tmpx.ptr.p_double[i] = 0.5*(a+b)+(a-b)*(2*ae_randomreal(_state)-1); } err = (double)(0); if( periodiccond ) { spline1dconvcubic(&x, &yp, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, _state); } else { spline1dconvcubic(&x, &y, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, _state); } for(i=0; i<=n2-1; i++) { spline1ddiff(&c, tmpx.ptr.p_double[i], &s, &ds, &d2s, _state); err = ae_maxreal(err, ae_fabs(s-tmp0.ptr.p_double[i], _state), _state); } if( periodiccond ) { spline1dconvdiffcubic(&x, &yp, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, &tmp1, _state); } else { spline1dconvdiffcubic(&x, &y, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, &tmp1, _state); } for(i=0; i<=n2-1; i++) { spline1ddiff(&c, tmpx.ptr.p_double[i], &s, &ds, &d2s, _state); err = ae_maxreal(err, ae_fabs(s-tmp0.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(ds-tmp1.ptr.p_double[i], _state), _state); } if( periodiccond ) { spline1dconvdiff2cubic(&x, &yp, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, &tmp1, &tmp2, _state); } else { spline1dconvdiff2cubic(&x, &y, n, bltype, bl, brtype, br, &tmpx, n2, &tmp0, &tmp1, &tmp2, _state); } for(i=0; i<=n2-1; i++) { spline1ddiff(&c, tmpx.ptr.p_double[i], &s, &ds, &d2s, _state); err = ae_maxreal(err, ae_fabs(s-tmp0.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(ds-tmp1.ptr.p_double[i], _state), _state); err = ae_maxreal(err, ae_fabs(d2s-tmp2.ptr.p_double[i], _state), _state); } cserrors = cserrors||ae_fp_greater(err,threshold); } } /* * Build Catmull-Rom spline. * Test for interpolation scheme properties: * * values at nodes * * boundary conditions * * continuous function * * continuous first derivative * * periodicity properties */ for(bltype=-1; bltype<=0; bltype++) { periodiccond = bltype==-1; /* * select random tension value, then build */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { if( ae_fp_greater(ae_randomreal(_state),0.5) ) { tension = (double)(0); } else { tension = (double)(1); } } else { tension = ae_randomreal(_state); } if( periodiccond ) { spline1dbuildcatmullrom(&x, &yp, n, bltype, tension, &c, _state); } else { spline1dbuildcatmullrom(&x, &y, n, bltype, tension, &c, _state); } /* * interpolation properties */ err = (double)(0); if( periodiccond ) { /* * * check values at nodes; spline is periodic so * we add random number of periods to nodes * * we also test for periodicity of first derivative */ for(i=0; i<=n-1; i++) { v = x.ptr.p_double[i]; vm = v+(b-a)*(ae_randominteger(5, _state)-2); t = yp.ptr.p_double[i]-spline1dcalc(&c, vm, _state); err = ae_maxreal(err, ae_fabs(t, _state), _state); spline1ddiff(&c, v, &s, &ds, &d2s, _state); spline1ddiff(&c, vm, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); } /* * periodicity between nodes */ v = a+(b-a)*ae_randomreal(_state); vm = v+(b-a)*(ae_randominteger(5, _state)-2); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, v, _state)-spline1dcalc(&c, vm, _state), _state), _state); spline1ddiff(&c, v, &s, &ds, &d2s, _state); spline1ddiff(&c, vm, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); } else { /* * * check values at nodes */ for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state), _state); } } crserrors = crserrors||ae_fp_greater(err,threshold); /* * check boundary conditions */ err = (double)(0); if( bltype==0 ) { spline1ddiff(&c, a-h, &s, &ds, &d2s, _state); spline1ddiff(&c, a+h, &s2, &ds2, &d2s2, _state); t = (d2s2-d2s)/(2*h); err = ae_maxreal(err, ae_fabs(t, _state), _state); spline1ddiff(&c, b-h, &s, &ds, &d2s, _state); spline1ddiff(&c, b+h, &s2, &ds2, &d2s2, _state); t = (d2s2-d2s)/(2*h); err = ae_maxreal(err, ae_fabs(t, _state), _state); } if( bltype==-1 ) { spline1ddiff(&c, a+100*ae_machineepsilon, &s, &ds, &d2s, _state); spline1ddiff(&c, b-100*ae_machineepsilon, &s2, &ds2, &d2s2, _state); err = ae_maxreal(err, ae_fabs(s-s2, _state), _state); err = ae_maxreal(err, ae_fabs(ds-ds2, _state), _state); } crserrors = crserrors||ae_fp_greater(err,1.0E-3); /* * Check Lipschitz continuity */ testspline1dunit_lconst(a, b, &c, lstep, &l10, &l11, &l12, _state); testspline1dunit_lconst(a, b, &c, lstep/3, &l20, &l21, &l22, _state); if( ae_fp_greater(l10,1.0E-6) ) { crserrors = crserrors||ae_fp_greater(l20/l10,1.2); } if( ae_fp_greater(l11,1.0E-6) ) { crserrors = crserrors||ae_fp_greater(l21/l11,1.2); } } /* * Build Hermite spline. * Test for interpolation scheme properties: * * values and derivatives at nodes * * continuous function * * continuous first derivative */ spline1dbuildhermite(&x, &y, &d, n, &c, _state); err = (double)(0); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state), _state); } hserrors = hserrors||ae_fp_greater(err,threshold); err = (double)(0); for(i=0; i<=n-1; i++) { t = (spline1dcalc(&c, x.ptr.p_double[i]+h, _state)-spline1dcalc(&c, x.ptr.p_double[i]-h, _state))/(2*h); err = ae_maxreal(err, ae_fabs(d.ptr.p_double[i]-t, _state), _state); } hserrors = hserrors||ae_fp_greater(err,1.0E-3); testspline1dunit_lconst(a, b, &c, lstep, &l10, &l11, &l12, _state); testspline1dunit_lconst(a, b, &c, lstep/3, &l20, &l21, &l22, _state); hserrors = hserrors||ae_fp_greater(l20/l10,1.2); hserrors = hserrors||ae_fp_greater(l21/l11,1.2); /* * Build Akima spline * Test for general interpolation scheme properties: * * values at nodes * * continuous function * * continuous first derivative * Test for Akima-specific properties is implemented below. */ spline1dbuildakima(&x, &y, n, &c, _state); err = (double)(0); for(i=0; i<=n-1; i++) { err = ae_maxreal(err, ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state), _state); } aserrors = aserrors||ae_fp_greater(err,threshold); testspline1dunit_lconst(a, b, &c, lstep, &l10, &l11, &l12, _state); testspline1dunit_lconst(a, b, &c, lstep/3, &l20, &l21, &l22, _state); hserrors = hserrors||(ae_fp_greater(l10,1.0E-10)&&ae_fp_greater(l20/l10,1.2)); hserrors = hserrors||(ae_fp_greater(l11,1.0E-10)&&ae_fp_greater(l21/l11,1.2)); } } /* * Special linear spline test: * test for linearity between x[i] and x[i+1] */ for(n=2; n<=maxn; n++) { ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); /* * Prepare task */ a = (double)(-1); b = (double)(1); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = a+(b-a)*i/(n-1); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } spline1dbuildlinear(&x, &y, n, &c, _state); /* * Test */ err = (double)(0); for(k=0; k<=n-2; k++) { a = x.ptr.p_double[k]; b = x.ptr.p_double[k+1]; for(pass=1; pass<=passcount; pass++) { t = a+(b-a)*ae_randomreal(_state); v = y.ptr.p_double[k]+(t-a)/(b-a)*(y.ptr.p_double[k+1]-y.ptr.p_double[k]); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, t, _state)-v, _state), _state); } } lserrors = lserrors||ae_fp_greater(err,threshold); } /* * Special Akima test: test outlier sensitivity * Spline value at (x[i], x[i+1]) should depend from * f[i-2], f[i-1], f[i], f[i+1], f[i+2], f[i+3] only. */ for(n=5; n<=maxn; n++) { ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); ae_vector_set_length(&y2, n-1+1, _state); /* * Prepare unperturbed Akima spline */ a = (double)(-1); b = (double)(1); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = a+(b-a)*i/(n-1); y.ptr.p_double[i] = ae_cos(1.3*ae_pi*x.ptr.p_double[i]+0.4, _state); } spline1dbuildakima(&x, &y, n, &c, _state); /* * Process perturbed tasks */ err = (double)(0); for(k=0; k<=n-1; k++) { ae_v_move(&y2.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); y2.ptr.p_double[k] = (double)(5); spline1dbuildakima(&x, &y2, n, &c2, _state); /* * Test left part independence */ if( k-3>=1 ) { a = (double)(-1); b = x.ptr.p_double[k-3]; for(pass=1; pass<=passcount; pass++) { t = a+(b-a)*ae_randomreal(_state); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, t, _state)-spline1dcalc(&c2, t, _state), _state), _state); } } /* * Test right part independence */ if( k+3<=n-2 ) { a = x.ptr.p_double[k+3]; b = (double)(1); for(pass=1; pass<=passcount; pass++) { t = a+(b-a)*ae_randomreal(_state); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, t, _state)-spline1dcalc(&c2, t, _state), _state), _state); } } } aserrors = aserrors||ae_fp_greater(err,threshold); } /* * Differentiation, copy/unpack test */ for(n=2; n<=maxn; n++) { ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); /* * Prepare cubic spline */ a = -1-ae_randomreal(_state); b = 1+ae_randomreal(_state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = a+(b-a)*i/(n-1); y.ptr.p_double[i] = ae_cos(1.3*ae_pi*x.ptr.p_double[i]+0.4, _state); } spline1dbuildcubic(&x, &y, n, 2, 0.0, 2, 0.0, &c, _state); /* * Test diff */ err = (double)(0); for(pass=1; pass<=passcount; pass++) { t = a+(b-a)*ae_randomreal(_state); spline1ddiff(&c, t, &s, &ds, &d2s, _state); vl = spline1dcalc(&c, t-h, _state); vm = spline1dcalc(&c, t, _state); vr = spline1dcalc(&c, t+h, _state); err = ae_maxreal(err, ae_fabs(s-vm, _state), _state); err = ae_maxreal(err, ae_fabs(ds-(vr-vl)/(2*h), _state), _state); err = ae_maxreal(err, ae_fabs(d2s-(vr-2*vm+vl)/ae_sqr(h, _state), _state), _state); } dserrors = dserrors||ae_fp_greater(err,0.001); /* * Test copy */ testspline1dunit_unsetspline1d(&c2, _state); spline1dcopy(&c, &c2, _state); err = (double)(0); for(pass=1; pass<=passcount; pass++) { t = a+(b-a)*ae_randomreal(_state); err = ae_maxreal(err, ae_fabs(spline1dcalc(&c, t, _state)-spline1dcalc(&c2, t, _state), _state), _state); } cperrors = cperrors||ae_fp_greater(err,threshold); /* * Test unpack */ uperrors = uperrors||!testspline1dunit_testunpack(&c, &x, _state); } /* * Linear translation errors */ for(n=2; n<=maxn; n++) { /* * Prepare: * * X, Y - grid points * * XTest - test points */ ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); a = -1-ae_randomreal(_state); b = 1+ae_randomreal(_state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = a+(b-a)*(i+0.2*ae_randomreal(_state)-0.1)/(n-1); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } ae_vector_set_length(&xtest, 5*n+2, _state); for(i=0; i<=xtest.cnt-1; i++) { xtest.ptr.p_double[i] = a+(b-a)*(i-1)/(xtest.cnt-3); } splineindex = 0; while(testspline1dunit_enumerateallsplines(&x, &y, n, &splineindex, &c, _state)) { /* * LinTransX, general A */ sa = 4*ae_randomreal(_state)-2; sb = 2*ae_randomreal(_state)-1; spline1dcopy(&c, &c2, _state); spline1dlintransx(&c2, sa, sb, _state); for(i=0; i<=xtest.cnt-1; i++) { lterrors = lterrors||ae_fp_greater(ae_fabs(spline1dcalc(&c, xtest.ptr.p_double[i], _state)-spline1dcalc(&c2, (xtest.ptr.p_double[i]-sb)/sa, _state), _state),threshold); } /* * LinTransX, special case: A=0 */ sb = 2*ae_randomreal(_state)-1; spline1dcopy(&c, &c2, _state); spline1dlintransx(&c2, (double)(0), sb, _state); for(i=0; i<=xtest.cnt-1; i++) { lterrors = lterrors||ae_fp_greater(ae_fabs(spline1dcalc(&c, sb, _state)-spline1dcalc(&c2, xtest.ptr.p_double[i], _state), _state),threshold); } /* * LinTransY */ sa = 2*ae_randomreal(_state)-1; sb = 2*ae_randomreal(_state)-1; spline1dcopy(&c, &c2, _state); spline1dlintransy(&c2, sa, sb, _state); for(i=0; i<=xtest.cnt-1; i++) { lterrors = lterrors||ae_fp_greater(ae_fabs(sa*spline1dcalc(&c, xtest.ptr.p_double[i], _state)+sb-spline1dcalc(&c2, xtest.ptr.p_double[i], _state), _state),threshold); } } } /* * Testing integration. * Three tests are performed: * * * approximate test (well behaved smooth function, many points, * integration inside [a,b]), non-periodic spline * * * exact test (integration of parabola, outside of [a,b], non-periodic spline * * * approximate test for periodic splines. F(x)=cos(2*pi*x)+1. * Period length is equals to 1.0, so all operations with * multiples of period are done exactly. For each value of PERIOD * we calculate and test integral at four points: * - 0 < t0 < PERIOD * - t1 = PERIOD-eps * - t2 = PERIOD * - t3 = PERIOD+eps */ err = (double)(0); for(n=20; n<=35; n++) { ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); for(pass=1; pass<=passcount; pass++) { /* * Prepare cubic spline */ a = -1-0.2*ae_randomreal(_state); b = 1+0.2*ae_randomreal(_state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = a+(b-a)*i/(n-1); y.ptr.p_double[i] = ae_sin(ae_pi*x.ptr.p_double[i]+0.4, _state)+ae_exp(x.ptr.p_double[i], _state); } bl = ae_pi*ae_cos(ae_pi*a+0.4, _state)+ae_exp(a, _state); br = ae_pi*ae_cos(ae_pi*b+0.4, _state)+ae_exp(b, _state); spline1dbuildcubic(&x, &y, n, 1, bl, 1, br, &c, _state); /* * Test */ t = a+(b-a)*ae_randomreal(_state); v = -ae_cos(ae_pi*a+0.4, _state)/ae_pi+ae_exp(a, _state); v = -ae_cos(ae_pi*t+0.4, _state)/ae_pi+ae_exp(t, _state)-v; v = v-spline1dintegrate(&c, t, _state); err = ae_maxreal(err, ae_fabs(v, _state), _state); } } ierrors = ierrors||ae_fp_greater(err,0.001); p0 = 2*ae_randomreal(_state)-1; p1 = 2*ae_randomreal(_state)-1; p2 = 2*ae_randomreal(_state)-1; a = -ae_randomreal(_state)-0.5; b = ae_randomreal(_state)+0.5; n = 2; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&d, n, _state); x.ptr.p_double[0] = a; y.ptr.p_double[0] = p0+p1*a+p2*ae_sqr(a, _state); d.ptr.p_double[0] = p1+2*p2*a; x.ptr.p_double[1] = b; y.ptr.p_double[1] = p0+p1*b+p2*ae_sqr(b, _state); d.ptr.p_double[1] = p1+2*p2*b; spline1dbuildhermite(&x, &y, &d, n, &c, _state); bl = ae_minreal(a, b, _state)-ae_fabs(b-a, _state); br = ae_minreal(a, b, _state)+ae_fabs(b-a, _state); err = (double)(0); for(pass=1; pass<=100; pass++) { t = bl+(br-bl)*ae_randomreal(_state); v = p0*t+p1*ae_sqr(t, _state)/2+p2*ae_sqr(t, _state)*t/3-(p0*a+p1*ae_sqr(a, _state)/2+p2*ae_sqr(a, _state)*a/3); v = v-spline1dintegrate(&c, t, _state); err = ae_maxreal(err, ae_fabs(v, _state), _state); } ierrors = ierrors||ae_fp_greater(err,threshold); n = 100; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)i/(double)(n-1); y.ptr.p_double[i] = ae_cos(2*ae_pi*x.ptr.p_double[i], _state)+1; } y.ptr.p_double[0] = (double)(2); y.ptr.p_double[n-1] = (double)(2); spline1dbuildcubic(&x, &y, n, -1, 0.0, -1, 0.0, &c, _state); intab = spline1dintegrate(&c, 1.0, _state); v = ae_randomreal(_state); vr = spline1dintegrate(&c, v, _state); ierrors = ierrors||ae_fp_greater(ae_fabs(intab-1, _state),0.001); for(i=-10; i<=10; i++) { ierrors = ierrors||ae_fp_greater(ae_fabs(spline1dintegrate(&c, i+v, _state)-(i*intab+vr), _state),0.001); ierrors = ierrors||ae_fp_greater(ae_fabs(spline1dintegrate(&c, i-1000*ae_machineepsilon, _state)-i*intab, _state),0.001); ierrors = ierrors||ae_fp_greater(ae_fabs(spline1dintegrate(&c, (double)(i), _state)-i*intab, _state),0.001); ierrors = ierrors||ae_fp_greater(ae_fabs(spline1dintegrate(&c, i+1000*ae_machineepsilon, _state)-i*intab, _state),0.001); } /* * Test fo monotone cubic Hermit interpolation */ monotoneerr = testspline1dunit_testmonotonespline(_state); /* * report */ waserrors = (((((((((lserrors||cserrors)||crserrors)||hserrors)||aserrors)||dserrors)||cperrors)||uperrors)||lterrors)||ierrors)||monotoneerr; if( !silent ) { printf("TESTING SPLINE INTERPOLATION\n"); /* * Normal tests */ printf("LINEAR SPLINE TEST: "); if( lserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CUBIC SPLINE TEST: "); if( cserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CATMULL-ROM SPLINE TEST: "); if( crserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("HERMITE SPLINE TEST: "); if( hserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("AKIMA SPLINE TEST: "); if( aserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("DIFFERENTIATION TEST: "); if( dserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("COPY/SERIALIZATION TEST: "); if( cperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("UNPACK TEST: "); if( uperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LIN.TRANS. TEST: "); if( lterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("INTEGRATION TEST: "); if( ierrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST MONOTONE CUBIC HERMITE SPLINE: "); if( monotoneerr ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testspline1d(ae_bool silent, ae_state *_state) { return testspline1d(silent, _state); } /************************************************************************* Lipschitz constants for spline inself, first and second derivatives. *************************************************************************/ static void testspline1dunit_lconst(double a, double b, spline1dinterpolant* c, double lstep, double* l0, double* l1, double* l2, ae_state *_state) { double t; double vl; double vm; double vr; double prevf; double prevd; double prevd2; double f; double d; double d2; *l0 = 0; *l1 = 0; *l2 = 0; *l0 = (double)(0); *l1 = (double)(0); *l2 = (double)(0); t = a-0.1; vl = spline1dcalc(c, t-2*lstep, _state); vm = spline1dcalc(c, t-lstep, _state); vr = spline1dcalc(c, t, _state); f = vm; d = (vr-vl)/(2*lstep); d2 = (vr-2*vm+vl)/ae_sqr(lstep, _state); while(ae_fp_less_eq(t,b+0.1)) { prevf = f; prevd = d; prevd2 = d2; vl = vm; vm = vr; vr = spline1dcalc(c, t+lstep, _state); f = vm; d = (vr-vl)/(2*lstep); d2 = (vr-2*vm+vl)/ae_sqr(lstep, _state); *l0 = ae_maxreal(*l0, ae_fabs((f-prevf)/lstep, _state), _state); *l1 = ae_maxreal(*l1, ae_fabs((d-prevd)/lstep, _state), _state); *l2 = ae_maxreal(*l2, ae_fabs((d2-prevd2)/lstep, _state), _state); t = t+lstep; } } /************************************************************************* This function is used to enumerate all spline types which can be built from given dataset. It should be used as follows: > > init X, Y, N > SplineIndex:=0; > while EnumerateAllSplines(X, Y, N, SplineIndex, S) do > begin > do something with S > end; > On initial call EnumerateAllSplines accepts: * dataset X, Y, number of points N (N>=2) * SplineIndex, equal to 0 It returns: * True, in case there is a spline type which corresponds to SplineIndex. In this case S contains spline which was built using X/Y and spline type, as specified by input value of SplineIndex. SplineIndex is advanced to the next value. * False, in case SplineIndex contains past-the-end value, spline is not built. This function tries different variants of linear/cubic, periodic/nonperiodic splines. *************************************************************************/ static ae_bool testspline1dunit_enumerateallsplines(/* Real */ ae_vector* x, /* Real */ ae_vector* y, ae_int_t n, ae_int_t* splineindex, spline1dinterpolant* s, ae_state *_state) { ae_int_t idxoffs; ae_bool result; _spline1dinterpolant_clear(s); ae_assert(*splineindex>=0, "Assertion failed", _state); result = ae_false; if( *splineindex==0 ) { /* * Linear spline */ spline1dbuildlinear(x, y, n, s, _state); *splineindex = *splineindex+1; result = ae_true; return result; } else { if( *splineindex>=1&&*splineindex<11 ) { /* * Cubic spline, either periodic or non-periodic */ idxoffs = *splineindex-1; if( idxoffs==9 ) { /* * Periodic spline */ spline1dbuildcubic(x, y, n, -1, 0.0, -1, 0.0, s, _state); } else { /* * Non-periodic spline */ spline1dbuildcubic(x, y, n, idxoffs/3, 2*ae_randomreal(_state)-1, idxoffs%3, 2*ae_randomreal(_state)-1, s, _state); } *splineindex = *splineindex+1; result = ae_true; return result; } } return result; } /************************************************************************* Unpack testing *************************************************************************/ static ae_bool testspline1dunit_testunpack(spline1dinterpolant* c, /* Real */ ae_vector* x, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t n; double err; double t; double v1; double v2; ae_int_t pass; ae_int_t passcount; ae_matrix tbl; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&tbl, 0, 0, DT_REAL, _state); passcount = 20; err = (double)(0); spline1dunpack(c, &n, &tbl, _state); for(i=0; i<=n-2; i++) { for(pass=1; pass<=passcount; pass++) { t = ae_randomreal(_state)*(tbl.ptr.pp_double[i][1]-tbl.ptr.pp_double[i][0]); v1 = tbl.ptr.pp_double[i][2]+t*tbl.ptr.pp_double[i][3]+ae_sqr(t, _state)*tbl.ptr.pp_double[i][4]+t*ae_sqr(t, _state)*tbl.ptr.pp_double[i][5]; v2 = spline1dcalc(c, tbl.ptr.pp_double[i][0]+t, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); } } for(i=0; i<=n-2; i++) { err = ae_maxreal(err, ae_fabs(x->ptr.p_double[i]-tbl.ptr.pp_double[i][0], _state), _state); } for(i=0; i<=n-2; i++) { err = ae_maxreal(err, ae_fabs(x->ptr.p_double[i+1]-tbl.ptr.pp_double[i][1], _state), _state); } result = ae_fp_less(err,100*ae_machineepsilon); ae_frame_leave(_state); return result; } /************************************************************************* Unset spline, i.e. initialize it with random garbage *************************************************************************/ static void testspline1dunit_unsetspline1d(spline1dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_vector d; ae_frame_make(_state, &_frame_block); _spline1dinterpolant_clear(c); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&y, 2, _state); ae_vector_set_length(&d, 2, _state); x.ptr.p_double[0] = (double)(-1); y.ptr.p_double[0] = ae_randomreal(_state); d.ptr.p_double[0] = ae_randomreal(_state); x.ptr.p_double[1] = (double)(1); y.ptr.p_double[1] = ae_randomreal(_state); d.ptr.p_double[1] = ae_randomreal(_state); spline1dbuildhermite(&x, &y, &d, 2, c, _state); ae_frame_leave(_state); } /************************************************************************* Tests that built spline is monotone. *************************************************************************/ static ae_bool testspline1dunit_testmonotonespline(ae_state *_state) { ae_frame _frame_block; spline1dinterpolant c; spline1dinterpolant s2; double c0; double c1; ae_vector x; ae_vector y; ae_vector d; ae_int_t m; ae_vector n; ae_int_t alln; ae_int_t shift; double sign0; double sign1; double r; double st; double eps; double delta; double v; double dv; double d2v; ae_int_t nseg; ae_int_t npoints; ae_int_t tp; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t kmax; ae_int_t l; ae_bool result; ae_frame_make(_state, &_frame_block); _spline1dinterpolant_init(&c, _state); _spline1dinterpolant_init(&s2, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&n, 0, DT_INT, _state); eps = 100*ae_machineepsilon; /* * Special test - N=2. * * Following properties are tested: * * monotone spline must be equal to the Hermite spline with * zero derivative at the ends * * monotone spline is constant beyond left/right boundaries */ ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&y, 2, _state); ae_vector_set_length(&d, 2, _state); x.ptr.p_double[0] = -0.1-ae_randomreal(_state); y.ptr.p_double[0] = 2*ae_randomreal(_state)-1; d.ptr.p_double[0] = 0.0; x.ptr.p_double[1] = 0.1+ae_randomreal(_state); y.ptr.p_double[1] = y.ptr.p_double[0]; d.ptr.p_double[1] = 0.0; spline1dbuildmonotone(&x, &y, 2, &c, _state); spline1dbuildhermite(&x, &y, &d, 2, &s2, _state); v = 2*ae_randomreal(_state)-1; if( ae_fp_greater(ae_fabs(spline1dcalc(&c, v, _state)-spline1dcalc(&s2, v, _state), _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } if( ae_fp_neq(spline1dcalc(&c, (double)(-5), _state),y.ptr.p_double[0]) ) { result = ae_true; ae_frame_leave(_state); return result; } if( ae_fp_neq(spline1dcalc(&c, (double)(5), _state),y.ptr.p_double[0]) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Special test - N=3, x=[0,1,2], y=[0,1,0]. * Monotone spline must be equal to the Hermite spline with * zero derivative at all points. */ ae_vector_set_length(&x, 3, _state); ae_vector_set_length(&y, 3, _state); ae_vector_set_length(&d, 3, _state); x.ptr.p_double[0] = 0.0; y.ptr.p_double[0] = 0.0; d.ptr.p_double[0] = 0.0; x.ptr.p_double[1] = 1.0; y.ptr.p_double[1] = 1.0; d.ptr.p_double[1] = 0.0; x.ptr.p_double[2] = 2.0; y.ptr.p_double[2] = 0.0; d.ptr.p_double[2] = 0.0; spline1dbuildmonotone(&x, &y, 3, &c, _state); spline1dbuildhermite(&x, &y, &d, 3, &s2, _state); for(i=0; i<=10; i++) { v = x.ptr.p_double[0]+(double)i/(double)10*(x.ptr.p_double[2]-x.ptr.p_double[0]); if( ae_fp_greater(ae_fabs(spline1dcalc(&c, v, _state)-spline1dcalc(&s2, v, _state), _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Special test - N=5, x=[0,1,2,3,4], y=[0,1,1,2,3]. * * 1) spline passes through all prescribed points * 2) spline derivative at all points except x=3 is exactly zero * 3) spline derivative at x=3 is 1.0 (within machine epsilon) */ ae_vector_set_length(&x, 5, _state); ae_vector_set_length(&y, 5, _state); x.ptr.p_double[0] = 0.0; y.ptr.p_double[0] = 0.0; x.ptr.p_double[1] = 1.0; y.ptr.p_double[1] = 1.0; x.ptr.p_double[2] = 2.0; y.ptr.p_double[2] = 1.0; x.ptr.p_double[3] = 3.0; y.ptr.p_double[3] = 2.0; x.ptr.p_double[4] = 4.0; y.ptr.p_double[4] = 3.0; spline1dbuildmonotone(&x, &y, 5, &c, _state); for(i=0; i<=4; i++) { spline1ddiff(&c, x.ptr.p_double[i], &v, &dv, &d2v, _state); if( ae_fp_greater(ae_fabs(v-y.ptr.p_double[i], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } if( (ae_fp_eq(x.ptr.p_double[i],3.0)&&ae_fp_greater(ae_fabs(dv-1.0, _state),eps))||(ae_fp_neq(x.ptr.p_double[i],3.0)&&ae_fp_neq(dv,(double)(0))) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Special test: * * N=4 * * three fixed points - (0,0), (1,1), (2,0) * * one special point (x,y) with x in [0.1,0.9], y in [0.1,0.9] * * monotonicity of the interpolant at [0,1] is checked with very small step 1/KMax */ ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); x.ptr.p_double[0] = 0.0; y.ptr.p_double[0] = 0.0; x.ptr.p_double[2] = 1.0; y.ptr.p_double[2] = 1.0; x.ptr.p_double[3] = 2.0; y.ptr.p_double[3] = 0.0; for(i=1; i<=9; i++) { for(j=1; j<=9; j++) { x.ptr.p_double[1] = (double)i/(double)10; y.ptr.p_double[1] = (double)j/(double)10; spline1dbuildmonotone(&x, &y, 4, &c, _state); kmax = 1000; for(k=0; k<=kmax-1; k++) { if( ae_fp_greater(spline1dcalc(&c, (double)k/(double)kmax, _state),spline1dcalc(&c, (double)(k+1)/(double)kmax, _state)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } /* * General case */ delta = (double)(0); nseg = 10; npoints = 15; passcount = 30; for(pass=1; pass<=passcount; pass++) { tp = ae_randominteger(6, _state)+4; r = (double)(ae_randominteger(76, _state)+25); m = ae_randominteger(nseg, _state)+1; ae_vector_set_length(&n, m, _state); alln = 0; for(i=0; i<=m-1; i++) { n.ptr.p_int[i] = ae_randominteger(npoints, _state)+2; alln = alln+n.ptr.p_int[i]; } ae_vector_set_length(&x, alln, _state); ae_vector_set_length(&y, alln, _state); x.ptr.p_double[0] = r*(2*ae_randomreal(_state)-1); y.ptr.p_double[0] = r*(2*ae_randomreal(_state)-1); /* * Builds monotone function */ st = 0.1+0.7*ae_randomreal(_state); shift = 0; sign0 = ae_pow((double)(-1), (double)(0), _state); for(i=0; i<=m-1; i++) { for(j=1; j<=n.ptr.p_int[i]-1; j++) { x.ptr.p_double[shift+j] = x.ptr.p_double[shift+j-1]+st+ae_randomreal(_state); delta = ae_maxreal(delta, x.ptr.p_double[shift+j]-x.ptr.p_double[shift+j-1], _state); y.ptr.p_double[shift+j] = y.ptr.p_double[shift+j-1]+sign0*(st+ae_randomreal(_state)); } shift = shift+n.ptr.p_int[i]; if( i!=m-1 ) { sign0 = ae_pow((double)(-1), (double)(i+1), _state); x.ptr.p_double[shift] = x.ptr.p_double[shift-1]+st+ae_randomreal(_state); y.ptr.p_double[shift] = y.ptr.p_double[shift-1]+sign0*ae_randomreal(_state); } } delta = 3*delta; spline1dbuildmonotone(&x, &y, alln, &c, _state); /* * Check that built function is monotone */ shift = 0; for(i=0; i<=m-1; i++) { for(j=1; j<=n.ptr.p_int[i]-1; j++) { st = (x.ptr.p_double[shift+j]-x.ptr.p_double[shift+j-1])/tp; sign0 = y.ptr.p_double[shift+j]-y.ptr.p_double[shift+j-1]; if( ae_fp_neq(sign0,(double)(0)) ) { sign0 = sign0/ae_fabs(sign0, _state); } for(l=0; l<=tp-1; l++) { c0 = spline1dcalc(&c, x.ptr.p_double[shift+j-1]+l*st, _state); c1 = spline1dcalc(&c, x.ptr.p_double[shift+j-1]+(l+1)*st, _state); sign1 = c1-c0; if( ae_fp_neq(sign1,(double)(0)) ) { sign1 = sign1/ae_fabs(sign1, _state); } if( ae_fp_less(sign0*sign1,(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } c0 = spline1dcalc(&c, x.ptr.p_double[0]-delta, _state); c1 = spline1dcalc(&c, x.ptr.p_double[0], _state); if( ae_fp_greater(ae_fabs(c0-c1, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } c0 = spline1dcalc(&c, x.ptr.p_double[alln-1], _state); c1 = spline1dcalc(&c, x.ptr.p_double[alln-1]+delta, _state); if( ae_fp_greater(ae_fabs(c0-c1, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Builds constant function */ y.ptr.p_double[0] = r*(2*ae_randomreal(_state)-1); for(i=1; i<=alln-1; i++) { y.ptr.p_double[i] = y.ptr.p_double[0]; } spline1dbuildmonotone(&x, &y, alln, &c, _state); shift = 0; for(i=0; i<=m-1; i++) { for(j=1; j<=n.ptr.p_int[i]-1; j++) { st = (x.ptr.p_double[shift+j]-x.ptr.p_double[shift+j-1])/tp; sign0 = y.ptr.p_double[shift+j]-y.ptr.p_double[shift+j-1]; for(l=0; l<=tp-1; l++) { c0 = spline1dcalc(&c, x.ptr.p_double[shift+j-1]+l*st, _state); c1 = spline1dcalc(&c, x.ptr.p_double[shift+j-1]+(l+1)*st, _state); sign1 = c1-c0; if( ae_fp_greater(sign0,eps)||ae_fp_greater(sign1,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } result = ae_false; ae_frame_leave(_state); return result; } ae_bool testnormestimator(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double tol; ae_int_t maxmn; ae_int_t m; ae_int_t n; ae_int_t pass; ae_int_t passcount; ae_matrix a; ae_vector rowsizes; sparsematrix s; double snorm; double enorm; double enorm2; ae_int_t nbetter; double sigma; ae_int_t i; ae_int_t j; normestimatorstate e; normestimatorstate e2; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&rowsizes, 0, DT_INT, _state); _sparsematrix_init(&s, _state); _normestimatorstate_init(&e, _state); _normestimatorstate_init(&e2, _state); tol = 0.01; maxmn = 5; waserrors = ae_false; /* * First test: algorithm must correctly determine matrix norm */ for(m=1; m<=maxmn; m++) { for(n=1; n<=maxmn; n++) { /* * Create estimator with quite large NStart and NIts. * It should guarantee that we converge to the correct solution. */ normestimatorcreate(m, n, 15, 15, &e, _state); /* * Try with zero A first */ sparsecreate(m, n, 1, &s, _state); sparseconverttocrs(&s, _state); normestimatorestimatesparse(&e, &s, _state); normestimatorresults(&e, &enorm, _state); waserrors = waserrors||ae_fp_neq(enorm,(double)(0)); /* * Choose random norm, try with non-zero matrix * with specified norm. */ snorm = ae_exp(10*ae_randomreal(_state)-5, _state); sparsecreate(m, n, 1, &s, _state); if( m>=n ) { /* * Generate random orthogonal M*M matrix, * use N leading columns as columns of A */ rmatrixrndorthogonal(m, &a, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&s, i, j, snorm*a.ptr.pp_double[i][j], _state); } } } else { /* * Generate random orthogonal N*N matrix, * use M leading rows as rows of A */ rmatrixrndorthogonal(n, &a, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&s, i, j, snorm*a.ptr.pp_double[i][j], _state); } } } sparseconverttocrs(&s, _state); normestimatorestimatesparse(&e, &s, _state); normestimatorresults(&e, &enorm, _state); waserrors = (waserrors||ae_fp_greater(enorm,snorm*(1+tol)))||ae_fp_less(enorm,snorm*(1-tol)); } } /* * NStart=10 should give statistically better results than NStart=1. * In order to test it we perform PassCount attempts to solve random * problem by means of two estimators: one with NStart=10 and another * one with NStart=1. Every time we compare two estimates and choose * better one. * * Random variable NBetter is a number of cases when NStart=10 was better. * Under null hypothesis (no difference) it is binomially distributed * with mean PassCount/2 and variance PassCount/4. However, we expect * to have significant deviation to the right, in the area of larger * values. * * NOTE: we use fixed N because this test is independent of problem size. */ n = 3; normestimatorcreate(n, n, 1, 1, &e, _state); normestimatorcreate(n, n, 10, 1, &e2, _state); normestimatorsetseed(&e, 0, _state); normestimatorsetseed(&e2, 0, _state); nbetter = 0; passcount = 2000; sigma = 5.0; for(pass=1; pass<=passcount; pass++) { snorm = ae_pow(10.0, 2*ae_randomreal(_state)-1, _state); sparsecreate(n, n, 1, &s, _state); rmatrixrndcond(n, 2.0, &a, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&s, i, j, snorm*a.ptr.pp_double[i][j], _state); } } sparseconverttocrs(&s, _state); normestimatorestimatesparse(&e, &s, _state); normestimatorresults(&e, &enorm, _state); normestimatorestimatesparse(&e2, &s, _state); normestimatorresults(&e2, &enorm2, _state); if( ae_fp_less(ae_fabs(enorm2-snorm, _state),ae_fabs(enorm-snorm, _state)) ) { nbetter = nbetter+1; } } waserrors = waserrors||ae_fp_less((double)(nbetter),0.5*passcount+sigma*ae_sqrt(0.25*passcount, _state)); /* * Same as previous one (for NStart), but tests dependence on NIts. */ n = 3; normestimatorcreate(n, n, 1, 1, &e, _state); normestimatorcreate(n, n, 1, 10, &e2, _state); normestimatorsetseed(&e, 0, _state); normestimatorsetseed(&e2, 0, _state); nbetter = 0; passcount = 2000; sigma = 5.0; for(pass=1; pass<=passcount; pass++) { snorm = ae_pow(10.0, 2*ae_randomreal(_state)-1, _state); sparsecreate(n, n, 1, &s, _state); rmatrixrndcond(n, 2.0, &a, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&s, i, j, snorm*a.ptr.pp_double[i][j], _state); } } sparseconverttocrs(&s, _state); normestimatorestimatesparse(&e, &s, _state); normestimatorresults(&e, &enorm, _state); normestimatorestimatesparse(&e2, &s, _state); normestimatorresults(&e2, &enorm2, _state); if( ae_fp_less(ae_fabs(enorm2-snorm, _state),ae_fabs(enorm-snorm, _state)) ) { nbetter = nbetter+1; } } waserrors = waserrors||ae_fp_less((double)(nbetter),0.5*passcount+sigma*ae_sqrt(0.25*passcount, _state)); /* * report */ if( !silent ) { printf("TESTING NORM ESTIMATOR\n"); printf("TEST: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testnormestimator(ae_bool silent, ae_state *_state) { return testnormestimator(silent, _state); } static void testminqpunit_bcqptest(ae_bool* wereerrors, ae_state *_state); static ae_bool testminqpunit_ecqptest(ae_state *_state); static void testminqpunit_icqptest(ae_bool* err, ae_state *_state); static ae_bool testminqpunit_specialicqptests(ae_state *_state); static double testminqpunit_projectedantigradnorm(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* g, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state); static void testminqpunit_testbcgradandfeasibility(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_int_t n, /* Real */ ae_vector* x, double eps, ae_bool* errorflag, ae_state *_state); static void testminqpunit_setrandomalgoallmodern(minqpstate* s, ae_state *_state); static void testminqpunit_setrandomalgononconvex(minqpstate* s, ae_state *_state); static void testminqpunit_setrandomalgosemidefinite(minqpstate* s, ae_state *_state); static void testminqpunit_setrandomalgobc(minqpstate* s, ae_state *_state); static void testminqpunit_setrandomalgoconvexlc(minqpstate* s, ae_state *_state); static void testminqpunit_setrandomalgononconvexlc(minqpstate* s, ae_state *_state); static void testminqpunit_densetosparse(/* Real */ ae_matrix* a, ae_int_t n, sparsematrix* s, ae_state *_state); ae_bool testminqp(ae_bool silent, ae_state *_state) { ae_bool simpleerrors; ae_bool func1errors; ae_bool func2errors; ae_bool bcqperrors; ae_bool ecqperrors; ae_bool icqperrors; ae_bool cholerrors; ae_bool quickqperrors; ae_bool bleicerrors; ae_bool waserrors; ae_bool result; bcqperrors = ae_false; /* * The VERY basic tests for Cholesky and BLEIC */ simpleerrors = simpletest(_state); func1errors = functest1(_state); func2errors = functest2(_state); /* * Cholesky-specific tests */ cholerrors = choleskytests(_state); /* * QuickQP-specific tests */ quickqperrors = quickqptests(_state); /* * BLEIC-specific tests */ bleicerrors = bleictests(_state); /* * Test all solvers on bound-constrained problems */ testminqpunit_bcqptest(&bcqperrors, _state); /* * Test Cholesky and BLEIC solvers on equality-constrained problems */ ecqperrors = testminqpunit_ecqptest(_state); /* * Test Cholesky and BLEIC solvers on inequality-constrained problems */ icqperrors = ae_false; testminqpunit_icqptest(&icqperrors, _state); icqperrors = icqperrors||testminqpunit_specialicqptests(_state); /* * report */ waserrors = (((((((simpleerrors||func1errors)||func2errors)||bcqperrors)||ecqperrors)||icqperrors)||quickqperrors)||cholerrors)||bleicerrors; if( !silent ) { printf("TESTING MinQP\n"); printf("SimpleTest: "); if( simpleerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Func1Test: "); if( func1errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Func2Test: "); if( func2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Bound constrained: "); if( bcqperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Equality constrained: "); if( ecqperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Inequality constrained: "); if( icqperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Cholesky solver tests: "); if( cholerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("QuickQP solver tests: "); if( quickqperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BLEIC solver tests: "); if( bleicerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminqp(ae_bool silent, ae_state *_state) { return testminqp(silent, _state); } /************************************************************************* Function to test: 'MinQPCreate', 'MinQPSetQuadraticTerm', 'MinQPSetBC', 'MinQPSetOrigin', 'MinQPSetStartingPoint', 'MinQPOptimize', 'MinQPResults'. Test problem: A = diag(aii), aii>0 (random) b = 0 random bounds (either no bounds, one bound, two bounds av_neginf; ub.ptr.p_double[j] = _state->v_posinf; } else { if( infd==1 ) { db.ptr.p_double[j] = _state->v_neginf; ub.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } else { if( infd==2 ) { db.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; ub.ptr.p_double[j] = _state->v_posinf; } else { if( infd==3 ) { db.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; ub.ptr.p_double[j] = db.ptr.p_double[j]+maxstb*ae_randomreal(_state)+0.01; } else { db.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; ub.ptr.p_double[j] = db.ptr.p_double[j]; } } } } } minqpsetbc(&state, &db, &ub, _state); /* *initialization for shifting *initial value for 'XORi' *and searching true results */ for(j=0; j<=sn-1; j++) { xori.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; tx.ptr.p_double[j] = boundval(xori.ptr.p_double[j], db.ptr.p_double[j], ub.ptr.p_double[j], _state); } minqpsetorigin(&state, &xori, _state); /* *initialization for starting point */ for(j=0; j<=sn-1; j++) { stx.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } minqpsetstartingpoint(&state, &stx, _state); /* *optimize and get result */ minqpoptimize(&state, _state); minqpresults(&state, &x, &rep, _state); for(j=0; j<=sn-1; j++) { if( ae_fp_greater(ae_fabs(tx.ptr.p_double[j]-x.ptr.p_double[j], _state),eps)||(ae_fp_less(x.ptr.p_double[j],db.ptr.p_double[j])||ae_fp_greater(x.ptr.p_double[j],ub.ptr.p_double[j])) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function to test: 'MinQPCreate', 'MinQPSetLinearTerm', 'MinQPSetQuadraticTerm', 'MinQPSetOrigin', 'MinQPSetStartingPoint', 'MinQPOptimize', 'MinQPResults'. Test problem: A = positive-definite matrix, obtained by 'SPDMatrixRndCond' function b <> 0 without bounds random start point dimension - from 1 to 5. *************************************************************************/ ae_bool functest1(ae_state *_state) { ae_frame _frame_block; minqpstate state; ae_int_t nexp; ae_int_t msn; ae_int_t sn; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix a; ae_vector ub; ae_vector db; ae_vector x; ae_vector tx; double maxstb; ae_vector stx; ae_vector xori; ae_vector xoric; minqpreport rep; double maxn; double minn; double maxnb; double minnb; double eps; ae_vector b; ae_int_t c2; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&ub, 0, DT_REAL, _state); ae_vector_init(&db, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&tx, 0, DT_REAL, _state); ae_vector_init(&stx, 0, DT_REAL, _state); ae_vector_init(&xori, 0, DT_REAL, _state); ae_vector_init(&xoric, 0, DT_REAL, _state); _minqpreport_init(&rep, _state); ae_vector_init(&b, 0, DT_REAL, _state); eps = 0.001; msn = 5; c2 = 1000; maxstb = (double)(10); nexp = 1000; maxn = (double)(10); minn = (double)(-10); maxnb = (double)(1000); minnb = (double)(-1000); for(sn=1; sn<=msn; sn++) { ae_vector_set_length(&b, sn, _state); ae_vector_set_length(&tx, sn, _state); ae_vector_set_length(&xori, sn, _state); ae_vector_set_length(&xoric, sn, _state); ae_vector_set_length(&stx, sn, _state); for(i=0; i<=nexp; i++) { /* *create simmetric matrix 'A' */ spdmatrixrndcond(sn, ae_exp(ae_randomreal(_state)*ae_log((double)(c2), _state), _state), &a, _state); minqpcreate(sn, &state, _state); testminqpunit_setrandomalgobc(&state, _state); minqpsetquadraticterm(&state, &a, ae_false, _state); for(j=0; j<=sn-1; j++) { xoric.ptr.p_double[j] = 2*ae_randomreal(_state)-1; } /* *create linear part */ for(j=0; j<=sn-1; j++) { b.ptr.p_double[j] = (double)(0); for(k=0; k<=sn-1; k++) { b.ptr.p_double[j] = b.ptr.p_double[j]-xoric.ptr.p_double[k]*a.ptr.pp_double[k][j]; } } minqpsetlinearterm(&state, &b, _state); /* *initialization for shifting *initial value for 'XORi' *and searching true results */ for(j=0; j<=sn-1; j++) { xori.ptr.p_double[j] = 2*ae_randomreal(_state)-1; tx.ptr.p_double[j] = xori.ptr.p_double[j]+xoric.ptr.p_double[j]; } minqpsetorigin(&state, &xori, _state); /* *initialization for starting point */ for(j=0; j<=sn-1; j++) { stx.ptr.p_double[j] = 2*ae_randomreal(_state)-1; } minqpsetstartingpoint(&state, &stx, _state); /* *optimize and get result */ minqpoptimize(&state, _state); minqpresults(&state, &x, &rep, _state); for(j=0; j<=sn-1; j++) { if( ae_fp_greater(ae_fabs(tx.ptr.p_double[j]-x.ptr.p_double[j], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function to test: 'MinQPCreate', 'MinQPSetLinearTerm', 'MinQPSetQuadraticTerm', 'MinQPSetBC', 'MinQPSetOrigin', 'MinQPSetStartingPoint', 'MinQPOptimize', 'MinQPResults'. Test problem: A = positive-definite matrix, obtained by 'SPDMatrixRndCond' function b <> 0 boundary constraints random start point dimension - from 1 to 5. *************************************************************************/ ae_bool functest2(ae_state *_state) { ae_frame _frame_block; minqpstate state; ae_int_t nexp; ae_int_t msn; ae_int_t sn; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix a; ae_vector ub; ae_vector db; ae_vector x; ae_vector tmpx; double maxstb; ae_vector stx; ae_vector xori; ae_vector xoric; ae_int_t infd; minqpreport rep; double maxn; double minn; double maxnb; double minnb; double eps; ae_vector b; ae_vector g; ae_vector c; ae_vector y0; ae_vector y1; ae_int_t c2; double anti; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&ub, 0, DT_REAL, _state); ae_vector_init(&db, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&tmpx, 0, DT_REAL, _state); ae_vector_init(&stx, 0, DT_REAL, _state); ae_vector_init(&xori, 0, DT_REAL, _state); ae_vector_init(&xoric, 0, DT_REAL, _state); _minqpreport_init(&rep, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); eps = 0.001; msn = 5; c2 = 1000; maxstb = (double)(10); nexp = 1000; maxn = (double)(10); minn = (double)(-10); maxnb = (double)(1000); minnb = (double)(-1000); for(sn=1; sn<=msn; sn++) { ae_vector_set_length(&tmpx, sn, _state); ae_vector_set_length(&b, sn, _state); ae_vector_set_length(&c, sn, _state); ae_vector_set_length(&g, sn, _state); ae_vector_set_length(&xori, sn, _state); ae_vector_set_length(&xoric, sn, _state); ae_vector_set_length(&stx, sn, _state); ae_vector_set_length(&db, sn, _state); ae_vector_set_length(&ub, sn, _state); ae_vector_set_length(&y0, sn, _state); ae_vector_set_length(&y1, sn, _state); for(i=0; i<=nexp; i++) { /* *create simmetric matrix 'A' */ spdmatrixrndcond(sn, ae_exp(ae_randomreal(_state)*ae_log((double)(c2), _state), _state), &a, _state); minqpcreate(sn, &state, _state); testminqpunit_setrandomalgobc(&state, _state); minqpsetquadraticterm(&state, &a, ae_false, _state); for(j=0; j<=sn-1; j++) { xoric.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } /* *create linear part */ for(j=0; j<=sn-1; j++) { b.ptr.p_double[j] = (double)(0); for(k=0; k<=sn-1; k++) { b.ptr.p_double[j] = b.ptr.p_double[j]-xoric.ptr.p_double[k]*a.ptr.pp_double[k][j]; } } minqpsetlinearterm(&state, &b, _state); for(j=0; j<=sn-1; j++) { infd = ae_randominteger(4, _state); if( infd==0 ) { db.ptr.p_double[j] = _state->v_neginf; ub.ptr.p_double[j] = _state->v_posinf; } else { if( infd==1 ) { db.ptr.p_double[j] = _state->v_neginf; ub.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } else { if( infd==2 ) { db.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; ub.ptr.p_double[j] = _state->v_posinf; } else { db.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; ub.ptr.p_double[j] = db.ptr.p_double[j]+maxstb*ae_randomreal(_state)+0.01; } } } } minqpsetbc(&state, &db, &ub, _state); /* *initialization for shifting *initial value for 'XORi' *and searching true results */ for(j=0; j<=sn-1; j++) { xori.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } minqpsetorigin(&state, &xori, _state); for(j=0; j<=sn-1; j++) { c.ptr.p_double[j] = (double)(0); for(k=0; k<=sn-1; k++) { c.ptr.p_double[j] = c.ptr.p_double[j]-xori.ptr.p_double[k]*a.ptr.pp_double[k][j]; } } /* *initialization for starting point */ for(j=0; j<=sn-1; j++) { stx.ptr.p_double[j] = (maxnb-minnb)*ae_randomreal(_state)+minnb; } minqpsetstartingpoint(&state, &stx, _state); /* *optimize and get result */ minqpoptimize(&state, _state); minqpresults(&state, &x, &rep, _state); rmatrixmv(sn, sn, &a, 0, 0, 0, &x, 0, &y0, 0, _state); for(j=0; j<=sn-1; j++) { g.ptr.p_double[j] = y0.ptr.p_double[j]+c.ptr.p_double[j]+b.ptr.p_double[j]; } anti = testminqpunit_projectedantigradnorm(sn, &x, &g, &db, &ub, _state); for(j=0; j<=sn-1; j++) { if( ae_fp_greater(ae_fabs(anti, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* ConsoleTest. *************************************************************************/ ae_bool consoletest(ae_state *_state) { ae_frame _frame_block; minqpstate state; ae_int_t nexp; ae_int_t msn; ae_int_t sn; ae_int_t i; ae_int_t j; ae_int_t k; ae_matrix a; ae_vector ub; ae_vector db; ae_vector x; double maxstb; ae_vector stx; ae_vector xori; ae_vector xoric; minqpreport rep; double maxn; double minn; double maxnb; double minnb; double eps; ae_vector b; ae_vector g; ae_vector y0; ae_vector y1; ae_int_t c2; double c; double anti; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&ub, 0, DT_REAL, _state); ae_vector_init(&db, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&stx, 0, DT_REAL, _state); ae_vector_init(&xori, 0, DT_REAL, _state); ae_vector_init(&xoric, 0, DT_REAL, _state); _minqpreport_init(&rep, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); eps = 0.001; msn = 2; c2 = 1000; maxstb = (double)(10); nexp = 0; maxn = (double)(10); minn = (double)(-10); maxnb = (double)(1000); minnb = (double)(-1000); for(sn=2; sn<=msn; sn++) { ae_vector_set_length(&b, sn, _state); ae_vector_set_length(&g, sn, _state); ae_vector_set_length(&xori, sn, _state); ae_vector_set_length(&xoric, sn, _state); ae_vector_set_length(&stx, sn, _state); ae_vector_set_length(&db, sn, _state); ae_vector_set_length(&ub, sn, _state); ae_vector_set_length(&y0, sn, _state); ae_vector_set_length(&y1, sn, _state); for(i=0; i<=nexp; i++) { /* *create simmetric matrix 'A' */ ae_matrix_set_length(&a, sn, sn, _state); for(j=0; j<=sn-1; j++) { for(k=0; k<=sn-1; k++) { if( j==k ) { a.ptr.pp_double[j][k] = (double)(1); } else { a.ptr.pp_double[j][k] = (double)(0); } printf("%0.5f ", (double)(a.ptr.pp_double[j][k])); } printf("\n"); } minqpcreate(sn, &state, _state); testminqpunit_setrandomalgobc(&state, _state); minqpsetquadraticterm(&state, &a, ae_false, _state); for(j=0; j<=sn-1; j++) { xoric.ptr.p_double[j] = (double)(1); printf("XoriC=%0.5f \n", (double)(xoric.ptr.p_double[j])); } /* *create linear part */ for(j=0; j<=sn-1; j++) { b.ptr.p_double[j] = (double)(0); for(k=0; k<=sn-1; k++) { b.ptr.p_double[j] = b.ptr.p_double[j]-xoric.ptr.p_double[k]*a.ptr.pp_double[k][j]; } printf("B[%0d]=%0.5f\n", (int)(j), (double)(b.ptr.p_double[j])); } minqpsetlinearterm(&state, &b, _state); for(j=0; j<=sn-1; j++) { db.ptr.p_double[j] = (double)(10); ub.ptr.p_double[j] = (double)(20); } minqpsetbc(&state, &db, &ub, _state); /* *initialization for shifting *initial value for 'XORi' *and searching true results */ for(j=0; j<=sn-1; j++) { xori.ptr.p_double[j] = (double)(1); } minqpsetorigin(&state, &xori, _state); /* *optimize and get result */ minqpoptimize(&state, _state); minqpresults(&state, &x, &rep, _state); rmatrixmv(sn, sn, &a, 0, 0, 0, &x, 0, &y0, 0, _state); rmatrixmv(sn, sn, &a, 0, 0, 0, &x, 0, &y1, 0, _state); for(j=0; j<=sn-1; j++) { c = (double)(0); for(k=0; k<=sn-1; k++) { c = c-xori.ptr.p_double[k]*a.ptr.pp_double[k][j]; } g.ptr.p_double[j] = b.ptr.p_double[j]+c+y0.ptr.p_double[j]+y1.ptr.p_double[j]; } anti = testminqpunit_projectedantigradnorm(sn, &x, &b, &db, &ub, _state); printf("SN=%0d\n", (int)(sn)); printf("NEXP=%0d\n", (int)(i)); printf("TermType=%0d\n", (int)(rep.terminationtype)); for(j=0; j<=sn-1; j++) { printf("X[%0d]=%0.5f;\n", (int)(j), (double)(x.ptr.p_double[j])); printf("DB[%0d]=%0.5f; UB[%0d]=%0.5f\n", (int)(j), (double)(db.ptr.p_double[j]), (int)(j), (double)(ub.ptr.p_double[j])); printf("XORi[%0d]=%0.5f; XORiC[%0d]=%0.5f;\n", (int)(j), (double)(xori.ptr.p_double[j]), (int)(j), (double)(xoric.ptr.p_double[j])); printf("Anti[%0d]=%0.5f;\n", (int)(j), (double)(anti)); if( ae_fp_greater(ae_fabs(anti, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function performs tests specific for Cholesky solver Returns True on success, False on failure. *************************************************************************/ ae_bool choleskytests(ae_state *_state) { ae_frame _frame_block; minqpstate state; minqpreport rep; sparsematrix sa; ae_matrix a; ae_int_t n; ae_int_t i; ae_int_t j; ae_vector bndl; ae_vector bndu; ae_vector x; ae_vector xend; ae_vector xend0; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); _minqpreport_init(&rep, _state); _sparsematrix_init(&sa, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xend, 0, DT_REAL, _state); ae_vector_init(&xend0, 0, DT_REAL, _state); result = ae_false; /* * TEST: Cholesky solver should return -5 on sparse matrices. */ n = 5; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, 1.0, _state); } minqpcreate(n, &state, _state); minqpsetalgocholesky(&state, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); seterrorflag(&result, rep.terminationtype!=-5, _state); /* * TEST: default solver is Cholesky one. * * It is tested by checking that default solver returns -5 on sparse matrices. */ n = 5; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, 1.0, _state); } minqpcreate(n, &state, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); seterrorflag(&result, rep.terminationtype!=-5, _state); /* * Test CQP solver on non-convex problems, * which are bounded from below on the feasible set: * * min -||x||^2 s.t. x[i] in [-1,+1] * * We test ability of the solver to detect such problems * and report failure. */ n = 20; ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = -1.0; } ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x.ptr.p_double[i] = ae_randomreal(_state)-0.5; } minqpcreate(n, &state, _state); minqpsetalgocholesky(&state, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetstartingpoint(&state, &x, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype!=-5, _state); /* * Test CQP solver on non-convex problems, * which are unbounded from below: * * min -||x||^2 * * We test ability of the solver to detect such problems * and report failure. */ n = 20; ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = -1.0; } ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)-0.5; } minqpcreate(n, &state, _state); minqpsetalgocholesky(&state, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpsetstartingpoint(&state, &x, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype!=-5, _state); ae_frame_leave(_state); return result; } /************************************************************************* This function performs tests specific for QuickQP solver Returns True on failure. *************************************************************************/ ae_bool quickqptests(ae_state *_state) { ae_frame _frame_block; minqpstate state; minqpreport rep; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t k; double v; double g; double gnorm; ae_bool flag; ae_int_t origintype; ae_int_t scaletype; ae_bool isupper; ae_bool issparse; ae_int_t itscnt; ae_vector nlist; ae_int_t nidx; ae_matrix a; ae_matrix za; ae_matrix fulla; ae_matrix halfa; ae_matrix c; sparsematrix sa; ae_vector ct; ae_vector b; ae_vector zb; ae_vector bndl; ae_vector bndu; ae_vector x0; ae_vector x1; ae_vector xend0; ae_vector xend1; ae_vector xori; ae_vector xz; ae_vector s; double eps; hqrndstate rs; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); _minqpreport_init(&rep, _state); ae_vector_init(&nlist, 0, DT_INT, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&za, 0, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_matrix_init(&halfa, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); _sparsematrix_init(&sa, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&zb, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&xend0, 0, DT_REAL, _state); ae_vector_init(&xend1, 0, DT_REAL, _state); ae_vector_init(&xori, 0, DT_REAL, _state); ae_vector_init(&xz, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); result = ae_false; hqrndrandomize(&rs, _state); /* * Convex test: * * N dimensions * * random number (0..N) of random boundary constraints * * positive-definite A * * algorithm randomly choose dense or sparse A, and for * sparse matrix it randomly choose format. * * random B with normal entries * * initial point is random, feasible * * random origin (zero or non-zero) and scale (unit or * non-unit) are generated */ eps = 1.0E-5; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ origintype = hqrnduniformi(&rs, 2, _state); scaletype = hqrnduniformi(&rs, 2, _state); isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); issparse = ae_fp_less(hqrnduniformr(&rs, _state),0.5); spdmatrixrndcond(n, 1.0E3, &fulla, _state); ae_matrix_set_length(&halfa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { halfa.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]; } else { halfa.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } testminqpunit_densetosparse(&halfa, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xori, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = hqrndnormal(&rs, _state); if( origintype==0 ) { xori.ptr.p_double[i] = (double)(0); } else { xori.ptr.p_double[i] = hqrndnormal(&rs, _state); } if( scaletype==0 ) { s.ptr.p_double[i] = (double)(1); } else { s.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); } j = hqrnduniformi(&rs, 5, _state); if( j==0 ) { bndl.ptr.p_double[i] = (double)(0); x0.ptr.p_double[i] = ae_fabs(x0.ptr.p_double[i], _state); } if( j==1 ) { bndu.ptr.p_double[i] = (double)(0); x0.ptr.p_double[i] = -ae_fabs(x0.ptr.p_double[i], _state); } if( j==2 ) { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; x0.ptr.p_double[i] = bndl.ptr.p_double[i]; } if( j==3 ) { bndl.ptr.p_double[i] = -0.1; bndu.ptr.p_double[i] = 0.1; x0.ptr.p_double[i] = 0.2*hqrnduniformr(&rs, _state)-0.1; } } /* * Solve problem */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 0, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlinearterm(&state, &b, _state); if( issparse ) { minqpsetquadratictermsparse(&state, &sa, isupper, _state); } else { minqpsetquadraticterm(&state, &halfa, isupper, _state); } if( origintype!=0 ) { minqpsetorigin(&state, &xori, _state); } if( scaletype!=0 ) { minqpsetscale(&state, &s, _state); } minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+fulla.ptr.pp_double[i][j]*(x1.ptr.p_double[j]-xori.ptr.p_double[j]); } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(&result, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(&result, ae_fp_greater(gnorm,eps), _state); } } /* * Strongly non-convex test: * * N dimensions, N>=2 * * box constraints, x[i] in [-1,+1] * * A = A0-0.5*I, where A0 is SPD with unit norm and smallest * singular value equal to 1.0E-3, I is identity matrix * * random B with normal entries * * initial point is random, feasible * * We perform two tests: * * unconstrained problem must be recognized as unbounded * * constrained problem can be successfully solved * * NOTE: it is important to have N>=2, because formula for A * can be applied only to matrix with at least two * singular values */ eps = 1.0E-5; for(n=2; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ spdmatrixrndcond(n, 1.0E3, &fulla, _state); for(i=0; i<=n-1; i++) { fulla.ptr.pp_double[i][i] = fulla.ptr.pp_double[i][i]-0.5; } isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); ae_matrix_set_length(&halfa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { halfa.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]; } else { halfa.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } testminqpunit_densetosparse(&halfa, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 0, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlinearterm(&state, &b, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { minqpsetquadraticterm(&state, &halfa, isupper, _state); } else { minqpsetquadratictermsparse(&state, &sa, isupper, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fulla.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,n-1)); g = v+b.ptr.p_double[i]; if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(&result, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(&result, ae_fp_greater(gnorm,eps), _state); } } /* * Basic semi-definite test: * * N dimensions, N>=2 * * box constraints, x[i] in [-1,+1] * [ 1 1 ... 1 1 ] * * A = [ ... ... ... ] * [ 1 1 ... 1 1 ] * * random B with normal entries * * initial point is random, feasible * * We perform two tests: * * unconstrained problem must be recognized as unbounded * * constrained problem must be recognized as bounded and * successfully solved * * Both problems require subtle programming when we work * with semidefinite QP. * * NOTE: unlike BLEIC-QP algorthm, QQP may detect unboundedness * of the problem when started from any x0, with any b. * BLEIC-based solver requires carefully chosen x0 and b * to find direction of zero curvature, but this solver * can find it from any point. */ ae_vector_set_length(&nlist, 12, _state); nlist.ptr.p_int[0] = 2; nlist.ptr.p_int[1] = 3; nlist.ptr.p_int[2] = 4; nlist.ptr.p_int[3] = 5; nlist.ptr.p_int[4] = 6; nlist.ptr.p_int[5] = 7; nlist.ptr.p_int[6] = 8; nlist.ptr.p_int[7] = 9; nlist.ptr.p_int[8] = 10; nlist.ptr.p_int[9] = 20; nlist.ptr.p_int[10] = 40; nlist.ptr.p_int[11] = 80; eps = 1.0E-5; for(nidx=0; nidx<=nlist.cnt-1; nidx++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ n = nlist.ptr.p_int[nidx]; ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { do { b.ptr.p_double[i] = hqrndnormal(&rs, _state); } while(ae_fp_eq(b.ptr.p_double[i],(double)(0))); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 1.0; } } testminqpunit_densetosparse(&a, n, &sa, _state); /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 0, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlinearterm(&state, &b, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { minqpsetquadraticterm(&state, &a, ae_true, _state); } else { minqpsetquadratictermsparse(&state, &sa, ae_true, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+a.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(&result, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(&result, ae_fp_greater(gnorm,eps), _state); } } /* * Linear (zero-quadratic) test: * * N dimensions, N>=1 * * box constraints, x[i] in [-1,+1] * * A = 0 * * random B with normal entries * * initial point is random, feasible * * We perform two tests: * * unconstrained problem must be recognized as unbounded * * constrained problem can be successfully solved * * NOTE: we may explicitly set zero A, or assume that by * default it is zero. During test we will try both * ways. */ eps = 1.0E-5; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { do { b.ptr.p_double[i] = hqrndnormal(&rs, _state); } while(ae_fp_eq(b.ptr.p_double[i],(double)(0))); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 0, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlinearterm(&state, &b, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } minqpsetquadraticterm(&state, &a, ae_true, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(b.ptr.p_double[i],(double)(0))&&ae_fp_greater(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_less(b.ptr.p_double[i],(double)(0))&&ae_fp_less(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } } } /* * Test for Newton phase of QQP algorithm - we test that Newton * phase can find good solution within one step. In order to do * so we: * * solve convex QP problem (dense or sparse) * * with K<=N equality-only constraints ai=x=bi * * with number of outer iterations limited to just 1 * * and with CG phase turned off (we modify internal structures * of the QQP solver in order to make it) */ eps = 1.0E-5; for(pass=1; pass<=10; pass++) { /* * Generate problem */ n = 50+hqrnduniformi(&rs, 51, _state); spdmatrixrndcond(n, 1.0E3, &a, _state); testminqpunit_densetosparse(&a, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; } else { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } } /* * Solve problem * * NOTE: we modify internal structures of QQP solver in order * to deactivate CG phase */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 1, ae_true, _state); state.qqpsettingsuser.cgphase = ae_false; minqpsetlinearterm(&state, &b, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { minqpsetquadraticterm(&state, &a, ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)), _state); } else { minqpsetquadratictermsparse(&state, &sa, ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)), _state); } minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+a.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(&result, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(&result, ae_fp_greater(gnorm,eps), _state); } /* * Test for Newton phase of QQP algorithm - we test that Newton * updates work correctly, i.e. that CNewtonUpdate() internal * function correctly updates inverse Hessian matrix. * * To test it we: * * solve ill conditioned convex QP problem * * with unconstrained solution XZ whose components are within [-0.5,+0.5] * * with one inequality constraint X[k]>=5 * * with initial point such that: * * X0[i] = 100 for i<>k * * X0[k] = 5+1.0E-5 * * with number of outer iterations limited to just 1 * * and with CG phase turned off (we modify internal structures * of the QQP solver in order to make it) * * The idea is that single Newton step is not enough to find solution, * but with just one update we can move exactly to the solution. * * We perform two tests: * * first one with State.QQP.NewtMaxIts set to 1, in order to * make sure that algorithm fails with just one iteration * * second one with State.QQP.NewtMaxIts set to 2, in order to * make sure that algorithm converges when it can perform update */ eps = 1.0E-5; for(pass=1; pass<=10; pass++) { /* * Generate problem */ n = 20+hqrnduniformi(&rs, 20, _state); spdmatrixrndcond(n, 1.0E5, &a, _state); testminqpunit_densetosparse(&a, n, &sa, _state); sparseconverttocrs(&sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xz, n, _state); for(i=0; i<=n-1; i++) { xz.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; x0.ptr.p_double[i] = (double)(100); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; } k = hqrnduniformi(&rs, n, _state); x0.ptr.p_double[k] = 5.00001; bndl.ptr.p_double[k] = 5.0; sparsemv(&sa, &xz, &b, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = -b.ptr.p_double[i]; } /* * Create solver */ minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 1, ae_true, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)), _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetstartingpoint(&state, &x0, _state); /* * Solve problem. First time, with no Newton updates. * It must fail. * * NOTE: we modify internal structures of QQP solver in order * to deactivate CG phase and turn off Newton updates. */ state.qqpsettingsuser.cgphase = ae_false; state.qqpsettingsuser.cnphase = ae_true; state.qqpsettingsuser.cnmaxupdates = 0; minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( result ) { ae_frame_leave(_state); return result; } flag = ae_false; testminqpunit_testbcgradandfeasibility(&a, &b, &bndl, &bndu, n, &x1, eps, &flag, _state); seterrorflag(&result, !flag, _state); /* * Now with Newton updates - it must succeeed. */ state.qqpsettingsuser.cgphase = ae_false; state.qqpsettingsuser.cnmaxupdates = n; minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( result ) { ae_frame_leave(_state); return result; } flag = ae_false; testminqpunit_testbcgradandfeasibility(&a, &b, &bndl, &bndu, n, &x1, eps, &flag, _state); seterrorflag(&result, flag, _state); } /* * Check that problem with general constraints results in * correct error code (-5 should be returned). */ ae_matrix_set_length(&c, 1, 3, _state); ae_vector_set_length(&ct, 1, _state); c.ptr.pp_double[0][0] = 1.0; c.ptr.pp_double[0][1] = 1.0; c.ptr.pp_double[0][2] = 2.0; ct.ptr.p_int[0] = 0; minqpcreate(2, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 0, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlc(&state, &c, &ct, 1, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype!=-5, _state); /* * Test sparse functionality. QQP solver must perform * same steps independently of matrix type (dense or sparse). * * We generate random unconstrained test problem and solve it * twice - first time we solve dense version, second time - * sparse version is solved. * * During this test we: * * use stringent stopping criteria (one outer iteration) * * turn off Newton phase of the algorithm to slow down * convergence */ eps = 1.0E-3; itscnt = 1; n = 20; isupper = ae_fp_greater(ae_randomreal(_state),0.5); spdmatrixrndcond(n, 1.0E3, &za, _state); sparsecreate(n, n, 0, &sa, _state); ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( j>=i&&isupper ) { sparseset(&sa, i, j, za.ptr.pp_double[i][j], _state); a.ptr.pp_double[i][j] = za.ptr.pp_double[i][j]; } if( j<=i&&!isupper ) { sparseset(&sa, i, j, za.ptr.pp_double[i][j], _state); a.ptr.pp_double[i][j] = za.ptr.pp_double[i][j]; } } } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); s.ptr.p_double[i] = ae_pow(10.0, randomnormal(_state)/10, _state); } minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, itscnt, ae_false, _state); minqpsetscale(&state, &s, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, isupper, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, itscnt, ae_false, _state); minqpsetscale(&state, &s, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadratictermsparse(&state, &sa, isupper, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend1, &rep, _state); for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(ae_fabs(xend0.ptr.p_double[i]-xend1.ptr.p_double[i], _state),eps), _state); } /* * Test scale-invariance. QQP performs same steps on scaled and * unscaled problems (assuming that scale of the variables is known). * * We generate random scale matrix S and random well-conditioned and * well scaled matrix A. Then we solve two problems: * * (1) f = 0.5*x'*A*x+b'*x * (identity scale matrix is used) * * and * * (2) f = 0.5*y'*(inv(S)*A*inv(S))*y + (inv(S)*b)'*y * (scale matrix S is used) * * Solution process is started from X=0, we perform ItsCnt=1 outer * iterations with Newton phase turned off (to slow down convergence; * we want to prevent algorithm from converging to exact solution which * is exactly same for both problems; the idea is to test that same * intermediate tests are taken). * * As result, we must get S*x=y */ eps = 1.0E-3; itscnt = 1; n = 100; ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = ae_pow(10.0, randomnormal(_state)/10, _state); } spdmatrixrndcond(n, 1.0E3, &a, _state); ae_matrix_set_length(&za, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { za.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]/(s.ptr.p_double[i]*s.ptr.p_double[j]); } } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&zb, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); zb.ptr.p_double[i] = b.ptr.p_double[i]/s.ptr.p_double[i]; } minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, itscnt, ae_false, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, itscnt, ae_false, _state); minqpsetlinearterm(&state, &zb, _state); minqpsetquadraticterm(&state, &za, ae_true, _state); minqpsetscale(&state, &s, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend1, &rep, _state); for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(ae_fabs(s.ptr.p_double[i]*xend0.ptr.p_double[i]-xend1.ptr.p_double[i], _state),eps), _state); } /* * Test that QQP can efficiently use sparse matrices (i.e. it is * not disguised version of some dense QP solver). In order to test * it we create very large and very sparse problem (diagonal matrix * with N=40.000) and perform 10 iterations of QQP solver. * * In case QP solver uses some form of dense linear algebra to solve * this problem, it will take TOO much time to solve it. And we will * notice it by EXTREME slowdown during testing. */ n = 40000; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, ae_pow(10.0, -3*ae_randomreal(_state), _state), _state); } ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); } minqpcreate(n, &state, _state); minqpsetalgoquickqp(&state, 0.0, 0.0, 0.0, 10, ae_fp_greater(hqrnduniformr(&rs, _state),0.5), _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); ae_frame_leave(_state); return result; } /************************************************************************* This function performs tests specific for BLEIC solver Returns True on error, False on success. *************************************************************************/ ae_bool bleictests(ae_state *_state) { ae_frame _frame_block; minqpstate state; minqpreport rep; ae_vector nlist; ae_int_t nidx; ae_matrix a; ae_matrix za; ae_matrix c; ae_vector b; ae_vector zb; ae_vector bndl; ae_vector bndu; ae_vector s; ae_vector x; ae_vector ct; sparsematrix sa; ae_int_t n; ae_vector x0; ae_vector x1; hqrndstate rs; ae_int_t i; ae_int_t j; ae_int_t pass; ae_vector xend0; ae_vector xend1; double eps; double v; double g; double gnorm; ae_int_t itscnt; ae_bool isupper; ae_bool result; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); _minqpreport_init(&rep, _state); ae_vector_init(&nlist, 0, DT_INT, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&za, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&zb, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _sparsematrix_init(&sa, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); ae_vector_init(&xend0, 0, DT_REAL, _state); ae_vector_init(&xend1, 0, DT_REAL, _state); result = ae_false; hqrndrandomize(&rs, _state); /* * Test sparse functionality. BLEIC-based solver must perform * same steps independently of matrix type (dense or sparse). * * We generate random unconstrained test problem and solve it * twice - first time we solve dense version, second time - * sparse version is solved. */ eps = 1.0E-3; itscnt = 5; n = 20; isupper = ae_fp_greater(ae_randomreal(_state),0.5); spdmatrixrndcond(n, 1.0E3, &za, _state); sparsecreate(n, n, 0, &sa, _state); ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( j>=i&&isupper ) { sparseset(&sa, i, j, za.ptr.pp_double[i][j], _state); a.ptr.pp_double[i][j] = za.ptr.pp_double[i][j]; } if( j<=i&&!isupper ) { sparseset(&sa, i, j, za.ptr.pp_double[i][j], _state); a.ptr.pp_double[i][j] = za.ptr.pp_double[i][j]; } } } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); s.ptr.p_double[i] = ae_pow(10.0, randomnormal(_state)/10, _state); } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, itscnt, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, isupper, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, itscnt, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadratictermsparse(&state, &sa, isupper, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend1, &rep, _state); for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(ae_fabs(xend0.ptr.p_double[i]-xend1.ptr.p_double[i], _state),eps), _state); } /* * Test scale-invariance. BLEIC performs same steps on scaled and * unscaled problems (assuming that scale of the variables is known). * * We generate random scale matrix S and random well-conditioned and * well scaled matrix A. Then we solve two problems: * * (1) f = 0.5*x'*A*x+b'*x * (identity scale matrix is used) * * and * * (2) f = 0.5*y'*(inv(S)*A*inv(S))*y + (inv(S)*b)'*y * (scale matrix S is used) * * Solution process is started from X=0, we perform ItsCnt=5 steps. * As result, we must get S*x=y */ eps = 1.0E-3; itscnt = 5; n = 20; ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = ae_pow(10.0, randomnormal(_state)/10, _state); } spdmatrixrndcond(n, 1.0E3, &a, _state); ae_matrix_set_length(&za, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { za.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]/(s.ptr.p_double[i]*s.ptr.p_double[j]); } } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&zb, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); zb.ptr.p_double[i] = b.ptr.p_double[i]/s.ptr.p_double[i]; } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, itscnt, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, itscnt, _state); minqpsetlinearterm(&state, &zb, _state); minqpsetquadraticterm(&state, &za, ae_true, _state); minqpsetscale(&state, &s, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend1, &rep, _state); for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(ae_fabs(s.ptr.p_double[i]*xend0.ptr.p_double[i]-xend1.ptr.p_double[i], _state),eps), _state); } /* * Test that BLEIC can efficiently use sparse matrices (i.e. it is * not disguised version of some dense QP solver). In order to test * it we create very large and very sparse problem (diagonal matrix * with N=20.000) and perform 10 iterations of BLEIC-based QP solver. * * In case QP solver uses some form of dense linear algebra to solve * this problem, it will take TOO much time to solve it. And we will * notice it by EXTREME slowdown during testing. */ n = 20000; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, ae_pow(10.0, -3*ae_randomreal(_state), _state), _state); } ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = randomnormal(_state); } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, 10, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); /* * Special semi-definite test: * * N dimensions, N>=2 (important!) * * box constraints, x[i] in [-1,+1] * [ 1 1 ... 1 1 ] * * A = [ ... ... ... ] * [ 1 1 ... 1 1 ] * * random B such that SUM(b[i])=0.0 (important!) * * initial point x0 is chosen in such way that SUM(x[i])=0.0 * (important!) * * We perform two tests: * * unconstrained problem must be recognized as unbounded * (when starting from x0!) * * constrained problem must be recognized as bounded * and successfully solved * * Both problems require subtle programming when we work * with semidefinite QP. * * NOTE: it is very important to have N>=2 (otherwise problem * will be bounded from below even without boundary * constraints) and to have x0/b0 such that sum of * components is zero (such x0 is exact minimum of x'*A*x, * which allows algorithm to find direction of zero curvature * at the very first step). If x0/b are chosen in other way, * algorithm may be unable to find direction of zero * curvature and will cycle forever, slowly decreasing * function value at each iteration. * This is major difference from similar test for QQP solver - * QQP can find direction of zero curvature from almost any * point due to internal CG solver which favors such directions. * BLEIC uses LBFGS, which is less able to find direction of * zero curvature. */ ae_vector_set_length(&nlist, 12, _state); nlist.ptr.p_int[0] = 2; nlist.ptr.p_int[1] = 3; nlist.ptr.p_int[2] = 4; nlist.ptr.p_int[3] = 5; nlist.ptr.p_int[4] = 6; nlist.ptr.p_int[5] = 7; nlist.ptr.p_int[6] = 8; nlist.ptr.p_int[7] = 9; nlist.ptr.p_int[8] = 10; nlist.ptr.p_int[9] = 20; nlist.ptr.p_int[10] = 40; nlist.ptr.p_int[11] = 80; eps = 1.0E-5; for(nidx=0; nidx<=nlist.cnt-1; nidx++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ n = nlist.ptr.p_int[nidx]; ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { do { b.ptr.p_double[i] = hqrndnormal(&rs, _state); } while(ae_fp_eq(b.ptr.p_double[i],(double)(0))); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } v = 0.0; for(i=0; i<=n-1; i++) { v = v+x0.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = x0.ptr.p_double[i]-v/n; } v = 0.0; for(i=0; i<=n-1; i++) { v = v+b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = b.ptr.p_double[i]-v/n; } ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 1.0; } } testminqpunit_densetosparse(&a, n, &sa, _state); /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, 0, _state); minqpsetlinearterm(&state, &b, _state); minqpsetstartingpoint(&state, &x0, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { minqpsetquadraticterm(&state, &a, ae_true, _state); } else { minqpsetquadratictermsparse(&state, &sa, ae_true, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return result; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+a.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(&result, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(&result, ae_fp_greater(gnorm,eps), _state); } } /* * Test that BLEIC-based QP solver can solve non-convex problems * which are bounded from below on the feasible set: * * min -||x||^2 s.t. x[i] in [-1,+1] * * We also test ability of the solver to detect unbounded problems * (we remove one of the constraints and repeat solution process). */ n = 20; eps = 1.0E-14; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, (double)(-1), _state); } ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x.ptr.p_double[i] = ae_randomreal(_state)-0.5; } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, eps, 0.0, 0.0, 0, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetstartingpoint(&state, &x, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_neq(xend0.ptr.p_double[i],(double)(-1))&&ae_fp_neq(xend0.ptr.p_double[i],(double)(1)), _state); } } i = ae_randominteger(n, _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); /* * Test that BLEIC-based QP solver can solve non-convex problems * which are bounded from below on the feasible set: * * min -||x||^2 s.t. x[i] in [-1,+1], * with inequality constraints handled as general linear ones * * We also test ability of the solver to detect unbounded problems * (we remove last pair of constraints and try to solve modified * problem). */ n = 20; eps = 1.0E-14; sparsecreate(n, n, 0, &sa, _state); for(i=0; i<=n-1; i++) { sparseset(&sa, i, i, (double)(-1), _state); } ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n; j++) { c.ptr.pp_double[2*i+0][j] = (double)(0); c.ptr.pp_double[2*i+1][j] = (double)(0); } c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = 1.0; ct.ptr.p_int[2*i+0] = -1; c.ptr.pp_double[2*i+1][i] = 1.0; c.ptr.pp_double[2*i+1][n] = -1.0; ct.ptr.p_int[2*i+1] = 1; } ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = ae_randomreal(_state)-0.5; } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, eps, 0.0, 0.0, 0, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpsetlc(&state, &c, &ct, 2*n, _state); minqpsetstartingpoint(&state, &x, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(ae_fabs(xend0.ptr.p_double[i]+1, _state),100*ae_machineepsilon)&&ae_fp_greater(ae_fabs(xend0.ptr.p_double[i]-1, _state),100*ae_machineepsilon), _state); } } minqpsetlc(&state, &c, &ct, 2*(n-1), _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype!=-4, _state); /* * Test that BLEIC-based QP solver can solve QP problems with * zero quadratic term: * * min b'*x s.t. x[i] in [-1,+1] * * It means that QP solver can be used as linear programming solver * (altough performance of such solver is worse than that of specialized * LP solver). * * NOTE: we perform this test twice - first time without explicitly setting * quadratic term (we test that default quadratic term is zero), and * second time - with explicitly set quadratic term. */ n = 20; sparsecreate(n, n, 0, &sa, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); b.ptr.p_double[i] = randomnormal(_state); } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, eps, 0.0, 0.0, 0, _state); minqpsetlinearterm(&state, &b, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(b.ptr.p_double[i],(double)(0))&&ae_fp_neq(xend0.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_less(b.ptr.p_double[i],(double)(0))&&ae_fp_neq(xend0.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } } minqpcreate(n, &state, _state); minqpsetalgobleic(&state, eps, 0.0, 0.0, 0, _state); minqpsetlinearterm(&state, &b, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetquadratictermsparse(&state, &sa, ae_true, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend0, &rep, _state); seterrorflag(&result, rep.terminationtype<=0, _state); if( rep.terminationtype>0 ) { for(i=0; i<=n-1; i++) { seterrorflag(&result, ae_fp_greater(b.ptr.p_double[i],(double)(0))&&ae_fp_neq(xend0.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(&result, ae_fp_less(b.ptr.p_double[i],(double)(0))&&ae_fp_neq(xend0.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } } /* * Test specific problem sent by V.Semenenko, which resulted in * the initinite loop in FindFeasiblePoint (before fix). We do * not test results returned by solver - simply being able to * stop is enough for this test. * * NOTE: it is important that modifications to problem are applied * sequentially. Test fails after 100-5000 such modifications. * One modification is not enough to cause failure. */ n = 3; ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } a.ptr.pp_double[0][0] = 1.222990; a.ptr.pp_double[1][1] = 1.934900; a.ptr.pp_double[2][2] = 0.603924; ae_vector_set_length(&b, n, _state); b.ptr.p_double[0] = -4.97245; b.ptr.p_double[1] = -9.09039; b.ptr.p_double[2] = -4.63856; ae_matrix_set_length(&c, 8, n+1, _state); for(i=0; i<=c.rows-1; i++) { for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 0.0; } } c.ptr.pp_double[0][0] = (double)(1); c.ptr.pp_double[0][n] = 4.94298; c.ptr.pp_double[1][0] = (double)(1); c.ptr.pp_double[1][n] = 4.79981; c.ptr.pp_double[2][1] = (double)(1); c.ptr.pp_double[2][n] = -0.4848; c.ptr.pp_double[3][1] = (double)(1); c.ptr.pp_double[3][n] = -0.73804; c.ptr.pp_double[4][2] = (double)(1); c.ptr.pp_double[4][n] = 0.575729; c.ptr.pp_double[5][2] = (double)(1); c.ptr.pp_double[5][n] = 0.458645; c.ptr.pp_double[6][0] = (double)(1); c.ptr.pp_double[6][2] = (double)(-1); c.ptr.pp_double[6][n] = -0.0546574; c.ptr.pp_double[7][0] = (double)(1); c.ptr.pp_double[7][2] = (double)(-1); c.ptr.pp_double[7][n] = -0.5900440; ae_vector_set_length(&ct, 8, _state); ct.ptr.p_int[0] = -1; ct.ptr.p_int[1] = 1; ct.ptr.p_int[2] = -1; ct.ptr.p_int[3] = 1; ct.ptr.p_int[4] = -1; ct.ptr.p_int[5] = 1; ct.ptr.p_int[6] = -1; ct.ptr.p_int[7] = 1; ae_vector_set_length(&s, n, _state); s.ptr.p_double[0] = 0.143171; s.ptr.p_double[1] = 0.253240; s.ptr.p_double[2] = 0.117084; ae_vector_set_length(&x0, n, _state); x0.ptr.p_double[0] = 3.51126; x0.ptr.p_double[1] = 4.05731; x0.ptr.p_double[2] = 6.63307; for(pass=1; pass<=10000; pass++) { /* * Apply random distortion */ for(j=0; j<=n-1; j++) { b.ptr.p_double[j] = b.ptr.p_double[j]+(2*hqrnduniformi(&rs, 2, _state)-1)*0.1; } for(j=0; j<=6-1; j++) { c.ptr.pp_double[j][n] = c.ptr.pp_double[j][n]+(2*hqrnduniformi(&rs, 2, _state)-1)*0.1; } /* * Solve */ minqpcreate(3, &state, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpsetlinearterm(&state, &b, _state); minqpsetlc(&state, &c, &ct, 8, _state); minqpsetalgobleic(&state, 0.0, 0.0, 0.0, 0, _state); minqpsetstartingpoint(&state, &x0, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); } ae_frame_leave(_state); return result; } /************************************************************************* This function tests bound constrained quadratic programming algorithm. On failure sets error flag. *************************************************************************/ static void testminqpunit_bcqptest(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; minqpstate state; minqpreport rep; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; double v; double g; double gnorm; ae_int_t origintype; ae_int_t scaletype; ae_bool isupper; ae_bool issparse; ae_matrix a; ae_matrix fulla; ae_matrix halfa; ae_matrix c; sparsematrix sa; ae_vector ct; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector x0; ae_vector x1; ae_vector xori; ae_vector xz; ae_vector s; double eps; hqrndstate rs; ae_frame_make(_state, &_frame_block); _minqpstate_init(&state, _state); _minqpreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_matrix_init(&halfa, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); _sparsematrix_init(&sa, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&xori, 0, DT_REAL, _state); ae_vector_init(&xz, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Convex test: * * N dimensions * * random number (0..N) of random boundary constraints * * positive-definite A * * algorithm randomly choose dense or sparse A, and for * sparse matrix it randomly choose format. * * random B with normal entries * * initial point is random, feasible * * random origin (zero or non-zero) and scale (unit or * non-unit) are generated */ eps = 1.0E-4; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ origintype = hqrnduniformi(&rs, 2, _state); scaletype = hqrnduniformi(&rs, 2, _state); isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); issparse = ae_fp_less(hqrnduniformr(&rs, _state),0.5); spdmatrixrndcond(n, 1.0E3, &fulla, _state); ae_matrix_set_length(&halfa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { halfa.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]; } else { halfa.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } testminqpunit_densetosparse(&halfa, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xori, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = hqrndnormal(&rs, _state); if( origintype==0 ) { xori.ptr.p_double[i] = (double)(0); } else { xori.ptr.p_double[i] = hqrndnormal(&rs, _state); } if( scaletype==0 ) { s.ptr.p_double[i] = (double)(1); } else { s.ptr.p_double[i] = ae_exp(hqrndnormal(&rs, _state), _state); } j = hqrnduniformi(&rs, 5, _state); if( j==0 ) { bndl.ptr.p_double[i] = (double)(0); x0.ptr.p_double[i] = ae_fabs(x0.ptr.p_double[i], _state); } if( j==1 ) { bndu.ptr.p_double[i] = (double)(0); x0.ptr.p_double[i] = -ae_fabs(x0.ptr.p_double[i], _state); } if( j==2 ) { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; x0.ptr.p_double[i] = bndl.ptr.p_double[i]; } if( j==3 ) { bndl.ptr.p_double[i] = -0.1; bndu.ptr.p_double[i] = 0.1; x0.ptr.p_double[i] = 0.2*hqrnduniformr(&rs, _state)-0.1; } } /* * Solve problem */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoallmodern(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetstartingpoint(&state, &x0, _state); if( issparse ) { minqpsetquadratictermsparse(&state, &sa, isupper, _state); } else { minqpsetquadraticterm(&state, &halfa, isupper, _state); } if( origintype!=0 ) { minqpsetorigin(&state, &xori, _state); } if( scaletype!=0 ) { minqpsetscale(&state, &s, _state); } minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+fulla.ptr.pp_double[i][j]*(x1.ptr.p_double[j]-xori.ptr.p_double[j]); } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,eps), _state); } } /* * Semidefinite test: * * N dimensions * * nonnegativity constraints * * A = [ 1 1 ... 1 1 ; 1 1 ... 1 1 ; .... ; 1 1 ... 1 1 ] * * algorithm randomly choose dense or sparse A, and for * sparse matrix it randomly choose format. * * random B with normal entries * * initial point is random, feasible */ eps = 1.0E-4; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); issparse = ae_fp_less(hqrnduniformr(&rs, _state),0.5); ae_matrix_set_length(&fulla, n, n, _state); ae_matrix_set_length(&halfa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { fulla.ptr.pp_double[i][j] = 1.0; if( (j>=i&&isupper)||(j<=i&&!isupper) ) { halfa.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]; } else { halfa.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } testminqpunit_densetosparse(&halfa, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = 0.0; bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = (double)(hqrnduniformi(&rs, 2, _state)); } /* * Solve problem */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgosemidefinite(&state, _state); minqpsetstartingpoint(&state, &x0, _state); minqpsetlinearterm(&state, &b, _state); if( issparse ) { minqpsetquadratictermsparse(&state, &sa, isupper, _state); } else { minqpsetquadraticterm(&state, &halfa, isupper, _state); } minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+fulla.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,eps), _state); } } /* * Non-convex test: * * N dimensions, N>=2 * * box constraints, x[i] in [-1,+1] * * A = A0-0.5*I, where A0 is SPD with unit norm and smallest * singular value equal to 1.0E-3, I is identity matrix * * random B with normal entries * * initial point is random, feasible * * We perform two tests: * * unconstrained problem must be recognized as unbounded * * constrained problem can be successfully solved * * NOTE: it is important to have N>=2, because formula for A * can be applied only to matrix with at least two * singular values */ eps = 1.0E-4; for(n=2; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ spdmatrixrndcond(n, 1.0E3, &fulla, _state); for(i=0; i<=n-1; i++) { fulla.ptr.pp_double[i][i] = fulla.ptr.pp_double[i][i]-0.5; } isupper = ae_fp_less(hqrnduniformr(&rs, _state),0.5); ae_matrix_set_length(&halfa, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( (j>=i&&isupper)||(j<=i&&!isupper) ) { halfa.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]; } else { halfa.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } } testminqpunit_densetosparse(&halfa, n, &sa, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgononconvex(&state, _state); minqpsetstartingpoint(&state, &x0, _state); minqpsetlinearterm(&state, &b, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { minqpsetquadraticterm(&state, &halfa, isupper, _state); } else { minqpsetquadratictermsparse(&state, &sa, isupper, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return; } /* * Test - calculate constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fulla.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,n-1)); g = v+b.ptr.p_double[i]; if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,eps), _state); } } /* * Linear (zero-quadratic) test: * * N dimensions, N>=1 * * box constraints, x[i] in [-1,+1] * * A = 0 * * random B with normal entries * * initial point is random, feasible * * We perform two tests: * * unconstrained problem must be recognized as unbounded * * constrained problem can be successfully solved * * NOTE: we may explicitly set zero A, or assume that by * default it is zero. During test we will try both * ways. */ eps = 1.0E-4; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { do { b.ptr.p_double[i] = hqrndnormal(&rs, _state); } while(ae_fp_eq(b.ptr.p_double[i],(double)(0))); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgononconvex(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetstartingpoint(&state, &x0, _state); if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { ae_matrix_set_length(&a, n, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } minqpsetquadraticterm(&state, &a, ae_true, _state); } minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype!=-4, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpoptimize(&state, _state); minqpresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( rep.terminationtype<=0 ) { ae_frame_leave(_state); return; } /* * Test - calculate constrained gradient at solution, * check its norm. */ for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(b.ptr.p_double[i],(double)(0))&&ae_fp_greater(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_fp_less(b.ptr.p_double[i],(double)(0))&&ae_fp_less(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } } } ae_frame_leave(_state); } /************************************************************************* This function tests equality constrained quadratic programming algorithm. Returns True on errors. *************************************************************************/ static ae_bool testminqpunit_ecqptest(ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t k; ae_matrix a; ae_matrix q; ae_matrix c; ae_matrix a2; ae_vector b; ae_vector b2; ae_vector xstart; ae_vector xstart2; ae_vector xend; ae_vector xend2; ae_vector x0; ae_vector x1; ae_vector xd; ae_vector xs; ae_vector tmp; ae_vector g; ae_vector bndl; ae_vector bndu; ae_vector xorigin; ae_vector ct; double eps; double theta; double f0; double f1; minqpstate state; minqpstate state2; minqpreport rep; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t rk; double v; ae_int_t aulits; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&b2, 0, DT_REAL, _state); ae_vector_init(&xstart, 0, DT_REAL, _state); ae_vector_init(&xstart2, 0, DT_REAL, _state); ae_vector_init(&xend, 0, DT_REAL, _state); ae_vector_init(&xend2, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&xd, 0, DT_REAL, _state); ae_vector_init(&xs, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&xorigin, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minqpstate_init(&state, _state); _minqpstate_init(&state2, _state); _minqpreport_init(&rep, _state); waserrors = ae_false; /* * First test: * * N*N identity A * * K=0, where q is random unit vector * * optimization problem has form 0.5*x'*A*x-(x1*A)*x, * where x1 is some random vector * * either: * a) x1 is feasible => we must stop at x1 * b) x1 is infeasible => we must stop at the boundary q'*x=0 and * projection of gradient onto q*x=0 must be zero * * NOTE: we make several passes because some specific kind of errors is rarely * caught by this test, so we need several repetitions. */ eps = 1.0E-4; for(n=2; n<=6; n++) { for(pass=0; pass<=4; pass++) { /* * Generate problem: A, b, CMatrix, x0, XStart */ spdmatrixrndcond(n, ae_pow(10.0, 3*ae_randomreal(_state), _state), &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x1, n, _state); ae_vector_set_length(&xstart, n, _state); ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xstart.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } do { v = (double)(0); for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; v = v+ae_sqr(c.ptr.pp_double[0][i], _state); } v = ae_sqrt(v, _state); } while(ae_fp_eq(v,(double)(0))); for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][i] = c.ptr.pp_double[0][i]/v; } c.ptr.pp_double[0][n] = (double)(0); ct.ptr.p_int[0] = 1; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = -v; } /* * Create optimizer, solve */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetlc(&state, &c, &ct, 1, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); /* * Test */ if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } v = ae_v_dotproduct(&x1.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); if( ae_fp_greater_eq(v,(double)(0)) ) { /* * X1 is feasible */ for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-x1.ptr.p_double[i], _state),eps), _state); } } else { /* * X1 is infeasible: * * XEnd must be approximately feasible * * gradient projection onto c'*x=0 must be zero */ v = ae_v_dotproduct(&xend.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); seterrorflag(err, ae_fp_less(v,-eps), _state); ae_vector_set_length(&g, n, _state); ae_v_move(&g.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xend.ptr.p_double[0], 1, ae_v_len(0,n-1)); g.ptr.p_double[i] = g.ptr.p_double[i]+v; } v = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); ae_v_subd(&g.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1), v); v = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); seterrorflag(err, ae_fp_greater(ae_sqrt(v, _state),eps), _state); } } } /* * Boundary and linear equality/inequality constrained QP problem, * test for correct handling of non-zero XOrigin: * * N*N SPD A with moderate condtion number (up to 100) * * boundary constraints 0<=x[i]<=1 * * K0 ) { seterrorflag(err, ae_fp_less(v,c.ptr.pp_double[i][n]-eps), _state); } if( ct.ptr.p_int[i]<0 ) { seterrorflag(err, ae_fp_greater(v,c.ptr.pp_double[i][n]+eps), _state); } } for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-xend2.ptr.p_double[i], _state),eps), _state); seterrorflag(err, ae_fp_less(xend.ptr.p_double[i],(double)(0)), _state); seterrorflag(err, ae_fp_greater(xend.ptr.p_double[i],(double)(1)), _state); } } } /* * Boundary constraints vs linear ones: * * N*N SPD A * * optimization problem has form 0.5*x'*A*x-(x1*A)*x, * where x1 is some random vector from [-1,+1] * * K=2*N constraints of the form ai<=x[i] or x[i]<=b[i], * with ai in [-1.0,-0.1], bi in [+0.1,+1.0] * * initial point xstart is from [-1,+2] * * we solve two related QP problems: * a) one with constraints posed as boundary ones * b) another one with same constraints posed as general linear ones * both problems must have same solution. * Here we test that boundary constrained and linear inequality constrained * solvers give same results. */ eps = 1.0E-4; for(n=1; n<=6; n++) { /* * Generate problem: A, b, x0, XStart, C, CT */ spdmatrixrndcond(n, ae_pow(10.0, 3*ae_randomreal(_state), _state), &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x1, n, _state); ae_vector_set_length(&xstart, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); for(i=0; i<=n-1; i++) { x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xstart.ptr.p_double[i] = 3*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = -(0.1+0.9*ae_randomreal(_state)); bndu.ptr.p_double[i] = 0.1+0.9*ae_randomreal(_state); for(j=0; j<=n-1; j++) { c.ptr.pp_double[2*i+0][j] = (double)(0); c.ptr.pp_double[2*i+1][j] = (double)(0); } c.ptr.pp_double[2*i+0][i] = (double)(1); c.ptr.pp_double[2*i+0][n] = bndl.ptr.p_double[i]; ct.ptr.p_int[2*i+0] = 1; c.ptr.pp_double[2*i+1][i] = (double)(1); c.ptr.pp_double[2*i+1][n] = bndu.ptr.p_double[i]; ct.ptr.p_int[2*i+1] = -1; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = -v; } /* * Solve linear inequality constrained problem */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetlc(&state, &c, &ct, 2*n, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); /* * Solve boundary constrained problem */ minqpcreate(n, &state2, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state2, &b, _state); minqpsetquadraticterm(&state2, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state2, &xstart, _state); minqpsetbc(&state2, &bndl, &bndu, _state); minqpoptimize(&state2, _state); minqpresults(&state2, &xend2, &rep2, _state); /* * Calculate gradient, check projection */ if( rep.terminationtype<=0||rep2.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_less(xend.ptr.p_double[i],bndl.ptr.p_double[i]-eps), _state); seterrorflag(err, ae_fp_greater(xend.ptr.p_double[i],bndu.ptr.p_double[i]+eps), _state); seterrorflag(err, ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-xend2.ptr.p_double[i], _state),eps), _state); } } /* * Boundary constraints posed as general linear ones: * * no bound constraints * * 2*N linear constraints 0 <= x[i] <= 1 * * preconditioner is chosen at random (we just want to be * sure that preconditioning won't prevent us from converging * to the feasible point): * * unit preconditioner * * random diagonal-based preconditioner * * random scale-based preconditioner * * F(x) = |x-x0|^P, where P={2,4} and x0 is randomly selected from [-1,+2]^N * * with such simple constraints and function it is easy to find * analytic form of solution: S[i] = bound(x0[i], 0, 1). * * however, we can't guarantee that solution is strictly feasible * with respect to nonlinearity constraint, so we check * for approximate feasibility. */ for(n=1; n<=5; n++) { /* * Generate X, BL, BU. */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&xstart, n, _state); ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(i=0; i<=n-1; i++) { xstart.ptr.p_double[i] = ae_randomreal(_state); x0.ptr.p_double[i] = 3*ae_randomreal(_state)-1; b.ptr.p_double[i] = -x0.ptr.p_double[i]; for(j=0; j<=n; j++) { c.ptr.pp_double[2*i+0][j] = (double)(0); c.ptr.pp_double[2*i+1][j] = (double)(0); } c.ptr.pp_double[2*i+0][i] = (double)(1); c.ptr.pp_double[2*i+0][n] = (double)(0); ct.ptr.p_int[2*i+0] = 1; c.ptr.pp_double[2*i+1][i] = (double)(1); c.ptr.pp_double[2*i+1][n] = (double)(1); ct.ptr.p_int[2*i+1] = -1; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_double[i][j] = (double)(1); } else { a.ptr.pp_double[i][j] = (double)(0); } } } /* * Create and optimize */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlc(&state, &c, &ct, 2*n, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } /* * * compare solution with analytic one * * check feasibility */ for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-boundval(x0.ptr.p_double[i], 0.0, 1.0, _state), _state),0.05), _state); seterrorflag(err, ae_fp_less(xend.ptr.p_double[i],0.0-1.0E-6), _state); seterrorflag(err, ae_fp_greater(xend.ptr.p_double[i],1.0+1.0E-6), _state); } } /* * Boundary and linear equality/inequality constrained QP problem with * excessive constraints: * * N*N SPD A with moderate condtion number (up to 100) * * boundary constraints 0<=x[i]<=1 * * K=2*N equality/inequality constraints Q*x = Q*x0, where Q is random matrix, * x0 is some random vector from the feasible hypercube (0.1<=x0[i]<=0.9) * * optimization problem has form 0.5*x'*A*x-b*x, * where b is some random vector * * because constraints are excessive, the main problem is to find * feasible point; usually, the only existing feasible point is solution, * so we have to check only feasibility */ eps = 1.0E-4; for(n=1; n<=6; n++) { /* * Generate problem: A, b, BndL, BndU, CMatrix, x0, x1, XStart */ k = 2*n; spdmatrixrndcond(n, ae_pow(10.0, 3*ae_randomreal(_state), _state), &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x1, n, _state); ae_vector_set_length(&xstart, n, _state); ae_matrix_set_length(&c, k, n+1, _state); ae_vector_set_length(&ct, k, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 0.1+0.8*ae_randomreal(_state); x1.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = 0.0; bndu.ptr.p_double[i] = 1.0; xstart.ptr.p_double[i] = (double)(ae_randominteger(2, _state)); } for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); ct.ptr.p_int[i] = ae_randominteger(3, _state)-1; if( ct.ptr.p_int[i]==0 ) { c.ptr.pp_double[i][n] = v; } if( ct.ptr.p_int[i]>0 ) { c.ptr.pp_double[i][n] = v-1.0E-3; } if( ct.ptr.p_int[i]<0 ) { c.ptr.pp_double[i][n] = v+1.0E-3; } } for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } /* * Create optimizer, solve */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetlc(&state, &c, &ct, k, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); /* * Check feasibility properties of the solution */ if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&xend.ptr.p_double[0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); if( ct.ptr.p_int[i]==0 ) { seterrorflag(err, ae_fp_greater(ae_fabs(v-c.ptr.pp_double[i][n], _state),eps), _state); } if( ct.ptr.p_int[i]>0 ) { seterrorflag(err, ae_fp_less(v,c.ptr.pp_double[i][n]-eps), _state); } if( ct.ptr.p_int[i]<0 ) { seterrorflag(err, ae_fp_greater(v,c.ptr.pp_double[i][n]+eps), _state); } } } /* * General inequality constrained problem: * * N*N SPD diagonal A with moderate condtion number * * no boundary constraints * * K=N inequality constraints C*x >= C*x0, where C is N*N well conditioned * matrix, x0 is some random vector [-1,+1] * * optimization problem has form 0.5*x'*A*x-b'*x, * where b is random vector from [-1,+1] * * using duality, we can obtain solution of QP problem as follows: * a) intermediate problem min(0.5*y'*B*y + d'*y) s.t. y>=0 * is solved, where B = C*inv(A)*C', d = -(C*inv(A)*b + C*x0) * b) after we got dual solution ys, we calculate primal solution * xs = inv(A)*(C'*ys-b) */ eps = 1.0E-3; for(n=1; n<=6; n++) { /* * Generate problem */ ae_vector_set_length(&da, n, _state); ae_matrix_set_length(&a, n, n, _state); rmatrixrndcond(n, ae_pow(10.0, 2*ae_randomreal(_state), _state), &t2, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xstart, n, _state); ae_matrix_set_length(&c, n, n+1, _state); ae_vector_set_length(&ct, n, _state); for(i=0; i<=n-1; i++) { da.ptr.p_double[i] = ae_exp(8*ae_randomreal(_state)-4, _state); for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } a.ptr.pp_double[i][i] = da.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xstart.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { ae_v_move(&c.ptr.pp_double[i][0], 1, &t2.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[i][n] = v; ct.ptr.p_int[i] = 1; } /* * Solve primal problem, check feasibility */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetlc(&state, &c, &ct, n, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&xend.ptr.p_double[0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); seterrorflag(err, ae_fp_less(v,c.ptr.pp_double[i][n]-eps), _state); } /* * Generate dual problem: * * A2 stores new quadratic term * * B2 stores new linear term * * BndL/BndU store boundary constraints */ ae_matrix_set_length(&t3, n, n, _state); ae_matrix_set_length(&a2, n, n, _state); rmatrixtranspose(n, n, &c, 0, 0, &t3, 0, 0, _state); for(i=0; i<=n-1; i++) { v = 1/ae_sqrt(da.ptr.p_double[i], _state); ae_v_muld(&t3.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); } rmatrixsyrk(n, n, 1.0, &t3, 0, 0, 2, 0.0, &a2, 0, 0, ae_true, _state); ae_vector_set_length(&tmp0, n, _state); ae_v_move(&tmp0.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { tmp0.ptr.p_double[i] = tmp0.ptr.p_double[i]/da.ptr.p_double[i]; } ae_vector_set_length(&b2, n, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1)); b2.ptr.p_double[i] = -(v+c.ptr.pp_double[i][n]); } ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); for(i=0; i<=n-1; i++) { bndl.ptr.p_double[i] = 0.0; bndu.ptr.p_double[i] = _state->v_posinf; } minqpcreate(n, &state2, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state2, &b2, _state); minqpsetquadraticterm(&state2, &a2, ae_true, _state); minqpsetbc(&state2, &bndl, &bndu, _state); minqpoptimize(&state2, _state); minqpresults(&state2, &xend2, &rep2, _state); if( rep2.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[0][i], c.stride, &xend2.ptr.p_double[0], 1, ae_v_len(0,n-1)); tmp0.ptr.p_double[i] = v-b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { tmp0.ptr.p_double[i] = tmp0.ptr.p_double[i]/da.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_greater(ae_fabs(tmp0.ptr.p_double[i]-xend.ptr.p_double[i], _state),eps*ae_maxreal(ae_fabs(tmp0.ptr.p_double[i], _state), 1.0, _state)), _state); } } /* * Boundary and linear equality/inequality constrained QP problem, * test checks that different starting points yield same final point: * * random N from [1..6], random K from [1..2*N] * * N*N SPD A with moderate condtion number (up to 100) * * boundary constraints 0<=x[i]<=1 * * K<2*N linear inequality constraints Q*x <= Q*x0, where * Q is random K*N matrix, x0 is some random vector from the * inner area of the feasible hypercube (0.1<=x0[i]<=0.9) * * optimization problem has form 0.5*x'*A*x+b*x, * where b is some random vector with -5<=b[i]<=+5 * * every component of the initial point XStart is random from [-2,+2] * * we perform two starts from random different XStart and compare values * of the target function (although final points may be slightly different, * function values should match each other) */ eps = 1.0E-4; for(pass=1; pass<=50; pass++) { /* * Generate problem: N, K, A, b, BndL, BndU, CMatrix, x0, x1, XStart. */ n = ae_randominteger(5, _state)+2; k = ae_randominteger(2*n, _state)+1; spdmatrixrndcond(n, ae_pow(10.0, 2*ae_randomreal(_state), _state), &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&b2, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xstart, n, _state); ae_vector_set_length(&xstart2, n, _state); ae_matrix_set_length(&c, k, n+1, _state); ae_vector_set_length(&ct, k, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 0.1+0.8*ae_randomreal(_state); b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = 0.0; bndu.ptr.p_double[i] = 1.0; xstart.ptr.p_double[i] = 4*ae_randomreal(_state)-2; xstart2.ptr.p_double[i] = 4*ae_randomreal(_state)-2; } for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[i][n] = v; ct.ptr.p_int[i] = ae_randominteger(3, _state)-1; } /* * Solve with XStart */ minqpcreate(n, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetlc(&state, &c, &ct, k, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } /* * Solve with XStart2 */ minqpsetstartingpoint(&state, &xstart2, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend2, &rep, _state); if( rep.terminationtype<=0 ) { seterrorflag(err, ae_true, _state); continue; } /* * Calculate function value and XEnd and XEnd2, compare solutions */ f0 = 0.0; f1 = 0.0; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { f0 = f0+0.5*xend.ptr.p_double[i]*a.ptr.pp_double[i][j]*xend.ptr.p_double[j]; f1 = f1+0.5*xend2.ptr.p_double[i]*a.ptr.pp_double[i][j]*xend2.ptr.p_double[j]; } f0 = f0+xend.ptr.p_double[i]*b.ptr.p_double[i]; f1 = f1+xend2.ptr.p_double[i]*b.ptr.p_double[i]; } seterrorflag(err, ae_fp_greater(ae_fabs(f0-f1, _state),eps), _state); } /* * Convex/nonconvex optimization problem with excessive * (degenerate constraints): * * * N=2..5 * * f = 0.5*x'*A*x+b'*x * * b has normally distributed entries with scale 10^BScale * * several kinds of A are tried: zero, well conditioned SPD, well conditioned indefinite, low rank * * box constraints: x[i] in [-1,+1] * * 2^N "excessive" general linear constraints (v_k,x)<=(v_k,v_k)+v_shift, * where v_k is one of 2^N vertices of feasible hypercube, v_shift is * a shift parameter: * * with zero v_shift such constraints are degenerate (each vertex has * N box constraints and one "redundant" linear constraint) * * with positive v_shift linear constraint is always inactive * * with small (about machine epsilon) but negative v_shift, * constraint is close to degenerate - but not exactly * * We check that constrained gradient is close to zero at solution. * Box constraint is considered active if distance to boundary is less * than TolConstr. * * NOTE: TolConstr must be large enough so it won't conflict with * perturbation introduced by v_shift */ tolconstr = 1.0E-8; for(n=2; n<=8; n++) { for(akind=0; akind<=3; akind++) { for(shiftkind=-5; shiftkind<=1; shiftkind++) { for(bscale=0; bscale>=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } if( akind==2 ) { /* * Dense well conditioned indefinite */ smatrixrndcond(n, 50.0, &a, _state); } if( akind==3 ) { /* * Low rank */ ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(k=1; k<=ae_minint(3, n-1, _state); k++) { for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = hqrndnormal(&rs, _state); } v = hqrndnormal(&rs, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+v*tmp.ptr.p_double[i]*tmp.ptr.p_double[j]; } } } } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_round(ae_pow((double)(2), (double)(n), _state), _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = -1; k = i; c.ptr.pp_double[i][n] = ae_sign((double)(shiftkind), _state)*ae_pow((double)(10), ae_fabs((double)(shiftkind), _state), _state)*ae_machineepsilon; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = (double)(2*(k%2)-1); c.ptr.pp_double[i][n] = c.ptr.pp_double[i][n]+c.ptr.pp_double[i][j]*c.ptr.pp_double[i][j]; k = k/2; } } /* * Create and optimize */ minqpcreate(n, &state, _state); minqpsetstartingpoint(&state, &x, _state); testminqpunit_setrandomalgononconvexlc(&state, _state); minqpsetbc(&state, &bl, &bu, _state); minqpsetlc(&state, &c, &ct, ccnt, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpoptimize(&state, _state); minqpresults(&state, &xs0, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( *err ) { ae_frame_leave(_state); return; } /* * Evaluate gradient at solution and test */ vv = 0.0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+b.ptr.p_double[i]; if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr)&&ae_fp_greater(v,(double)(0)) ) { v = 0.0; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr)&&ae_fp_less(v,(double)(0)) ) { v = 0.0; } vv = vv+ae_sqr(v, _state); } vv = ae_sqrt(vv, _state); seterrorflag(err, ae_fp_greater(vv,1.0E-5), _state); } } } } /* * Convex/nonconvex optimization problem with combination of * box and linear constraints: * * * N=2..8 * * f = 0.5*x'*A*x+b'*x * * b has normally distributed entries with scale 10^BScale * * several kinds of A are tried: zero, well conditioned SPD, * well conditioned indefinite, low rank * * box constraints: x[i] in [-1,+1] * * initial point x0 = [0 0 ... 0 0] * * CCnt=min(3,N-1) general linear constraints of form (c,x)=0. * random mix of equality/inequality constraints is tried. * x0 is guaranteed to be feasible. * * We check that constrained gradient is close to zero at solution. * Inequality constraint is considered active if distance to boundary * is less than TolConstr. We use nonnegative least squares solver * in order to compute constrained gradient. */ tolconstr = 1.0E-8; for(n=2; n<=8; n++) { for(akind=0; akind<=3; akind++) { for(bscale=0; bscale>=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = 0.0; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } if( akind==2 ) { /* * Dense well conditioned indefinite */ smatrixrndcond(n, 50.0, &a, _state); } if( akind==3 ) { /* * Low rank */ ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(k=1; k<=ae_minint(3, n-1, _state); k++) { for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = hqrndnormal(&rs, _state); } v = hqrndnormal(&rs, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+v*tmp.ptr.p_double[i]*tmp.ptr.p_double[j]; } } } } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_minint(3, n-1, _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = hqrnduniformi(&rs, 3, _state)-1; c.ptr.pp_double[i][n] = 0.0; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } /* * Create and optimize */ minqpcreate(n, &state, _state); minqpsetstartingpoint(&state, &x, _state); testminqpunit_setrandomalgononconvexlc(&state, _state); minqpsetbc(&state, &bl, &bu, _state); minqpsetlc(&state, &c, &ct, ccnt, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_fp_greater(ae_randomreal(_state),0.5), _state); minqpoptimize(&state, _state); minqpresults(&state, &xs0, &rep, _state); seterrorflag(err, rep.terminationtype<=0, _state); if( *err ) { ae_frame_leave(_state); return; } /* * 1. evaluate unconstrained gradient at solution * * 2. calculate constrained gradient (NNLS solver is used * to evaluate gradient subject to active constraints). * In order to do this we form CE matrix, matrix of active * constraints (columns store constraint vectors). Then * we try to approximate gradient vector by columns of CE, * subject to non-negativity restriction placed on variables * corresponding to inequality constraints. * * Residual from such regression is a constrained gradient vector. */ ae_vector_set_length(&g, n, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); g.ptr.p_double[i] = v+b.ptr.p_double[i]; } ae_matrix_set_length(&ce, n, n+ccnt, _state); ae_vector_set_length(&nonnegative, n+ccnt, _state); k = 0; for(i=0; i<=n-1; i++) { seterrorflag(err, ae_fp_less(xs0.ptr.p_double[i],bl.ptr.p_double[i]), _state); seterrorflag(err, ae_fp_greater(xs0.ptr.p_double[i],bu.ptr.p_double[i]), _state); if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = 1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = -1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } for(i=0; i<=ccnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-c.ptr.pp_double[i][n]; seterrorflag(err, ct.ptr.p_int[i]==0&&ae_fp_greater(ae_fabs(v, _state),tolconstr), _state); seterrorflag(err, ct.ptr.p_int[i]>0&&ae_fp_less(v,-tolconstr), _state); seterrorflag(err, ct.ptr.p_int[i]<0&&ae_fp_greater(v,tolconstr), _state); if( ct.ptr.p_int[i]==0 ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_false; inc(&k, _state); continue; } if( (ct.ptr.p_int[i]>0&&ae_fp_less_eq(v,tolconstr))||(ct.ptr.p_int[i]<0&&ae_fp_greater_eq(v,-tolconstr)) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = ae_sign((double)(ct.ptr.p_int[i]), _state)*c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } snnlsinit(0, 0, 0, &nnls, _state); snnlssetproblem(&nnls, &ce, &g, 0, k, n, _state); for(i=0; i<=k-1; i++) { if( !nonnegative.ptr.p_bool[i] ) { snnlsdropnnc(&nnls, i, _state); } } snnlssolve(&nnls, &tmp, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { g.ptr.p_double[j] = g.ptr.p_double[j]-tmp.ptr.p_double[i]*ce.ptr.pp_double[j][i]; } } vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = ae_sqrt(vv, _state); seterrorflag(err, ae_fp_greater(vv,1.0E-5), _state); } } } ae_frame_leave(_state); } /************************************************************************* This function tests special inequality constrained QP problems. Returns True on errors. *************************************************************************/ static ae_bool testminqpunit_specialicqptests(ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_matrix c; ae_vector xstart; ae_vector xend; ae_vector xexact; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector ct; minqpstate state; minqpreport rep; ae_bool waserrors; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&xstart, 0, DT_REAL, _state); ae_vector_init(&xend, 0, DT_REAL, _state); ae_vector_init(&xexact, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minqpstate_init(&state, _state); _minqpreport_init(&rep, _state); waserrors = ae_false; /* * Test 1: reported by Vanderlande Industries. * Tests algorithm ability to handle degenerate constraints. */ ae_matrix_set_length(&a, 3, 3, _state); for(i=0; i<=2; i++) { for(j=0; j<=2; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=2; i++) { a.ptr.pp_double[i][i] = (double)(1); } ae_vector_set_length(&b, 3, _state); b.ptr.p_double[0] = (double)(-50); b.ptr.p_double[1] = (double)(-50); b.ptr.p_double[2] = (double)(-75); ae_vector_set_length(&bndl, 3, _state); bndl.ptr.p_double[0] = (double)(0); bndl.ptr.p_double[1] = (double)(0); bndl.ptr.p_double[2] = (double)(0); ae_vector_set_length(&bndu, 3, _state); bndu.ptr.p_double[0] = (double)(100); bndu.ptr.p_double[1] = (double)(100); bndu.ptr.p_double[2] = (double)(150); ae_vector_set_length(&xstart, 3, _state); xstart.ptr.p_double[0] = (double)(0); xstart.ptr.p_double[1] = (double)(100); xstart.ptr.p_double[2] = (double)(0); ae_vector_set_length(&xexact, 3, _state); xexact.ptr.p_double[0] = (double)(0); xexact.ptr.p_double[1] = (double)(100); xexact.ptr.p_double[2] = (double)(50); ae_matrix_set_length(&c, 3, 4, _state); c.ptr.pp_double[0][0] = (double)(1); c.ptr.pp_double[0][1] = (double)(-1); c.ptr.pp_double[0][2] = (double)(0); c.ptr.pp_double[0][3] = (double)(-100); c.ptr.pp_double[1][0] = (double)(1); c.ptr.pp_double[1][1] = (double)(0); c.ptr.pp_double[1][2] = (double)(-1); c.ptr.pp_double[1][3] = (double)(0); c.ptr.pp_double[2][0] = (double)(-1); c.ptr.pp_double[2][1] = (double)(0); c.ptr.pp_double[2][2] = (double)(1); c.ptr.pp_double[2][3] = (double)(50); ae_vector_set_length(&ct, 3, _state); ct.ptr.p_int[0] = -1; ct.ptr.p_int[1] = -1; ct.ptr.p_int[2] = -1; minqpcreate(3, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetlc(&state, &c, &ct, 3, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=2; i++) { waserrors = waserrors||ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-xexact.ptr.p_double[i], _state),1.0E6*ae_machineepsilon); } } else { waserrors = ae_true; } /* * Test 2: reported by Vanderlande Industries. * Tests algorithm ability to handle degenerate constraints. */ ae_matrix_set_length(&a, 3, 3, _state); for(i=0; i<=2; i++) { for(j=0; j<=2; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=2; i++) { a.ptr.pp_double[i][i] = (double)(1); } ae_vector_set_length(&b, 3, _state); b.ptr.p_double[0] = (double)(-50); b.ptr.p_double[1] = (double)(-50); b.ptr.p_double[2] = (double)(-75); ae_vector_set_length(&bndl, 3, _state); bndl.ptr.p_double[0] = (double)(0); bndl.ptr.p_double[1] = (double)(0); bndl.ptr.p_double[2] = (double)(0); ae_vector_set_length(&bndu, 3, _state); bndu.ptr.p_double[0] = (double)(100); bndu.ptr.p_double[1] = (double)(100); bndu.ptr.p_double[2] = (double)(150); ae_vector_set_length(&xstart, 3, _state); xstart.ptr.p_double[0] = (double)(0); xstart.ptr.p_double[1] = (double)(100); xstart.ptr.p_double[2] = (double)(150); ae_vector_set_length(&xexact, 3, _state); xexact.ptr.p_double[0] = (double)(0); xexact.ptr.p_double[1] = (double)(100); xexact.ptr.p_double[2] = (double)(100); ae_matrix_set_length(&c, 3, 4, _state); c.ptr.pp_double[0][0] = (double)(1); c.ptr.pp_double[0][1] = (double)(-1); c.ptr.pp_double[0][2] = (double)(0); c.ptr.pp_double[0][3] = (double)(-100); c.ptr.pp_double[1][0] = (double)(0); c.ptr.pp_double[1][1] = (double)(1); c.ptr.pp_double[1][2] = (double)(-1); c.ptr.pp_double[1][3] = (double)(0); c.ptr.pp_double[2][0] = (double)(0); c.ptr.pp_double[2][1] = (double)(-1); c.ptr.pp_double[2][2] = (double)(1); c.ptr.pp_double[2][3] = (double)(50); ae_vector_set_length(&ct, 3, _state); ct.ptr.p_int[0] = -1; ct.ptr.p_int[1] = -1; ct.ptr.p_int[2] = -1; minqpcreate(3, &state, _state); testminqpunit_setrandomalgoconvexlc(&state, _state); minqpsetlinearterm(&state, &b, _state); minqpsetquadraticterm(&state, &a, ae_true, _state); minqpsetstartingpoint(&state, &xstart, _state); minqpsetbc(&state, &bndl, &bndu, _state); minqpsetlc(&state, &c, &ct, 3, _state); minqpoptimize(&state, _state); minqpresults(&state, &xend, &rep, _state); if( rep.terminationtype>0 ) { for(i=0; i<=2; i++) { waserrors = waserrors||ae_fp_greater(ae_fabs(xend.ptr.p_double[i]-xexact.ptr.p_double[i], _state),1.0E6*ae_machineepsilon); } } else { waserrors = ae_true; } result = waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Function normal *************************************************************************/ static double testminqpunit_projectedantigradnorm(ae_int_t n, /* Real */ ae_vector* x, /* Real */ ae_vector* g, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_state *_state) { ae_int_t i; double r; double result; r = (double)(0); for(i=0; i<=n-1; i++) { ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])&&ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "ProjectedAntiGradNormal: boundary constraints violation", _state); if( ((ae_fp_greater(x->ptr.p_double[i],bndl->ptr.p_double[i])&&ae_fp_less(x->ptr.p_double[i],bndu->ptr.p_double[i]))||(ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])&&ae_fp_greater(-g->ptr.p_double[i],(double)(0))))||(ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])&&ae_fp_less(-g->ptr.p_double[i],(double)(0))) ) { r = r+g->ptr.p_double[i]*g->ptr.p_double[i]; } } result = ae_sqrt(r, _state); return result; } /************************************************************************* This function tests that norm of bound-constrained gradient at point X is less than Eps: * unconstrained gradient is A*x+b * if I-th component is at the boundary, and antigradient points outside of the feasible area, I-th component of constrained gradient is zero This function accepts QP terms A and B, bound constraints, current point, and performs test. Additionally, it checks that point is feasible w.r.t. boundary constraints. In case of failure, error flag is set. Otherwise, it is not modified. IMPORTANT: this function does NOT use SetErrorFlag() to modify flag. If you want to use SetErrorFlag() for easier tracking of errors, you should store flag returned by this function into separate variable TmpFlag and call SetErrorFlag(ErrorFlag, TmpFlag) yourself. *************************************************************************/ static void testminqpunit_testbcgradandfeasibility(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, /* Real */ ae_vector* bndl, /* Real */ ae_vector* bndu, ae_int_t n, /* Real */ ae_vector* x, double eps, ae_bool* errorflag, ae_state *_state) { ae_int_t i; ae_int_t j; double g; double gnorm; gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b->ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+a->ptr.pp_double[i][j]*x->ptr.p_double[j]; } if( ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); if( ae_fp_less(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) { *errorflag = ae_true; } if( ae_fp_greater(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) { *errorflag = ae_true; } } gnorm = ae_sqrt(gnorm, _state); if( ae_fp_greater(gnorm,eps) ) { *errorflag = ae_true; } } /************************************************************************* set random type of the QP solver. All "modern" solvers can be chosen. *************************************************************************/ static void testminqpunit_setrandomalgoallmodern(minqpstate* s, ae_state *_state) { ae_int_t i; i = 1+ae_randominteger(2, _state); if( i==1 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } if( i==2 ) { minqpsetalgoquickqp(s, 1.0E-12, 0.0, 0.0, 0, ae_fp_greater(ae_randomreal(_state),0.5), _state); } } /************************************************************************* set random type of theQP solver *************************************************************************/ static void testminqpunit_setrandomalgononconvex(minqpstate* s, ae_state *_state) { ae_int_t i; i = 1+ae_randominteger(2, _state); if( i==1 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } if( i==2 ) { minqpsetalgoquickqp(s, 1.0E-12, 0.0, 0.0, 0, ae_fp_greater(ae_randomreal(_state),0.5), _state); } } /************************************************************************* set random type of theQP solver *************************************************************************/ static void testminqpunit_setrandomalgosemidefinite(minqpstate* s, ae_state *_state) { ae_int_t i; i = 1+ae_randominteger(2, _state); if( i==1 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } if( i==2 ) { minqpsetalgoquickqp(s, 1.0E-12, 0.0, 0.0, 0, ae_fp_greater(ae_randomreal(_state),0.5), _state); } } /************************************************************************* set random type of the QP solver, must support boundary constraints *************************************************************************/ static void testminqpunit_setrandomalgobc(minqpstate* s, ae_state *_state) { ae_int_t i; i = ae_randominteger(2, _state); if( i==0 ) { minqpsetalgocholesky(s, _state); } if( i==1 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } } /************************************************************************* set random type of the QP solver, must support convex problems with boundary/linear constraints *************************************************************************/ static void testminqpunit_setrandomalgoconvexlc(minqpstate* s, ae_state *_state) { ae_int_t i; i = ae_randominteger(2, _state); if( i==0 ) { minqpsetalgocholesky(s, _state); } if( i==1 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } } /************************************************************************* set random type of the QP solver, must support nonconvex problems with boundary/linear constraints *************************************************************************/ static void testminqpunit_setrandomalgononconvexlc(minqpstate* s, ae_state *_state) { ae_int_t i; i = ae_randominteger(1, _state); if( i==0 ) { minqpsetalgobleic(s, 1.0E-12, 0.0, 0.0, 0, _state); } } /************************************************************************* Convert dense matrix to sparse matrix using random format *************************************************************************/ static void testminqpunit_densetosparse(/* Real */ ae_matrix* a, ae_int_t n, sparsematrix* s, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; sparsematrix s0; ae_frame_make(_state, &_frame_block); _sparsematrix_clear(s); _sparsematrix_init(&s0, _state); sparsecreate(n, n, n*n, &s0, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&s0, i, j, a->ptr.pp_double[i][j], _state); } } sparsecopytobuf(&s0, ae_randominteger(3, _state), s, _state); ae_frame_leave(_state); } static ae_bool testminlmunit_rkindvsstatecheck(ae_int_t rkind, minlmstate* state, ae_state *_state); static void testminlmunit_axmb(minlmstate* state, /* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t n, ae_state *_state); static void testminlmunit_tryreproducefixedbugs(ae_bool* err, ae_state *_state); static ae_bool testminlmunit_gradientchecktest(ae_state *_state); static void testminlmunit_funcderiv(/* Real */ ae_vector* a, /* Real */ ae_vector* x0, /* Real */ ae_vector* x, ae_int_t m, ae_int_t n, double anyconst, ae_int_t functype, /* Real */ ae_vector* f, /* Real */ ae_matrix* j, ae_state *_state); ae_bool testminlm(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool referror; ae_bool lin1error; ae_bool lin2error; ae_bool eqerror; ae_bool converror; ae_bool scerror; ae_bool restartserror; ae_bool othererrors; ae_bool graderrors; ae_int_t rkind; ae_int_t ckind; ae_int_t tmpkind; double epsf; double epsx; double epsg; ae_int_t maxits; ae_int_t n; ae_int_t m; ae_vector x; ae_vector xe; ae_vector b; ae_vector bl; ae_vector bu; ae_vector xlast; ae_int_t i; ae_int_t j; double v; double s; double stpmax; double h; ae_matrix a; double fprev; double xprev; minlmstate state; minlmreport rep; ae_int_t stopcallidx; ae_int_t callidx; ae_bool terminationrequested; ae_int_t pass; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); _minlmstate_init(&state, _state); _minlmreport_init(&rep, _state); waserrors = ae_false; referror = ae_false; lin1error = ae_false; lin2error = ae_false; eqerror = ae_false; converror = ae_false; scerror = ae_false; othererrors = ae_false; restartserror = ae_false; /* * Try to reproduce previously fixed bugs */ testminlmunit_tryreproducefixedbugs(&othererrors, _state); /* * Reference problem. * See comments for RKindVsStateCheck() for more info about RKind. * * NOTES: we also test negative RKind's corresponding to "inexact" schemes * which use approximate finite difference Jacobian. */ ae_vector_set_length(&x, 3, _state); n = 3; m = 3; h = 0.0001; for(rkind=-2; rkind<=5; rkind++) { x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; x.ptr.p_double[1] = 100*ae_randomreal(_state)-50; x.ptr.p_double[2] = 100*ae_randomreal(_state)-50; if( rkind==-2 ) { minlmcreatev(n, m, &x, h, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==-1 ) { minlmcreatev(n, m, &x, h, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==0 ) { minlmcreatefj(n, m, &x, &state, _state); } if( rkind==1 ) { minlmcreatefgj(n, m, &x, &state, _state); } if( rkind==2 ) { minlmcreatefgh(n, &x, &state, _state); } if( rkind==3 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==4 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==5 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 2, _state); } while(minlmiteration(&state, _state)) { /* * (x-2)^2 + y^2 + (z-x)^2 */ if( state.needfi ) { state.fi.ptr.p_double[0] = state.x.ptr.p_double[0]-2; state.fi.ptr.p_double[1] = state.x.ptr.p_double[1]; state.fi.ptr.p_double[2] = state.x.ptr.p_double[2]-state.x.ptr.p_double[0]; } if( state.needfij ) { state.fi.ptr.p_double[0] = state.x.ptr.p_double[0]-2; state.fi.ptr.p_double[1] = state.x.ptr.p_double[1]; state.fi.ptr.p_double[2] = state.x.ptr.p_double[2]-state.x.ptr.p_double[0]; state.j.ptr.pp_double[0][0] = (double)(1); state.j.ptr.pp_double[0][1] = (double)(0); state.j.ptr.pp_double[0][2] = (double)(0); state.j.ptr.pp_double[1][0] = (double)(0); state.j.ptr.pp_double[1][1] = (double)(1); state.j.ptr.pp_double[1][2] = (double)(0); state.j.ptr.pp_double[2][0] = (double)(-1); state.j.ptr.pp_double[2][1] = (double)(0); state.j.ptr.pp_double[2][2] = (double)(1); } if( (state.needf||state.needfg)||state.needfgh ) { state.f = ae_sqr(state.x.ptr.p_double[0]-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); } if( state.needfg||state.needfgh ) { state.g.ptr.p_double[0] = 2*(state.x.ptr.p_double[0]-2)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } if( state.needfgh ) { state.h.ptr.pp_double[0][0] = (double)(4); state.h.ptr.pp_double[0][1] = (double)(0); state.h.ptr.pp_double[0][2] = (double)(-2); state.h.ptr.pp_double[1][0] = (double)(0); state.h.ptr.pp_double[1][1] = (double)(2); state.h.ptr.pp_double[1][2] = (double)(0); state.h.ptr.pp_double[2][0] = (double)(-2); state.h.ptr.pp_double[2][1] = (double)(0); state.h.ptr.pp_double[2][2] = (double)(2); } scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); } minlmresults(&state, &x, &rep, _state); referror = (((referror||rep.terminationtype<=0)||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-2, _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.001))||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-2, _state),0.001); } /* * Reference bound constrained problem: * * min sum((x[i]-xe[i])^4) subject to 0<=x[i]<=1 * * NOTES: * 1. we test only two optimization modes - V and FGH, * because from algorithm internals we can assume that actual * mode being used doesn't matter for bound constrained optimization * process. */ for(tmpkind=0; tmpkind<=1; tmpkind++) { for(n=1; n<=5; n++) { ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&xe, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = (double)(0); bu.ptr.p_double[i] = (double)(1); xe.ptr.p_double[i] = 3*ae_randomreal(_state)-1; x.ptr.p_double[i] = ae_randomreal(_state); } if( tmpkind==0 ) { minlmcreatefgh(n, &x, &state, _state); } if( tmpkind==1 ) { minlmcreatev(n, n, &x, 1.0E-3, &state, _state); } minlmsetcond(&state, 1.0E-6, (double)(0), (double)(0), 0, _state); minlmsetbc(&state, &bl, &bu, _state); while(minlmiteration(&state, _state)) { if( state.needfi ) { for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[i] = ae_pow(state.x.ptr.p_double[i]-xe.ptr.p_double[i], (double)(2), _state); } } if( (state.needf||state.needfg)||state.needfgh ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+ae_pow(state.x.ptr.p_double[i]-xe.ptr.p_double[i], (double)(4), _state); } } if( state.needfg||state.needfgh ) { for(i=0; i<=n-1; i++) { state.g.ptr.p_double[i] = 4*ae_pow(state.x.ptr.p_double[i]-xe.ptr.p_double[i], (double)(3), _state); } } if( state.needfgh ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { state.h.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { state.h.ptr.pp_double[i][i] = 12*ae_pow(state.x.ptr.p_double[i]-xe.ptr.p_double[i], (double)(2), _state); } } } minlmresults(&state, &x, &rep, _state); if( rep.terminationtype==4 ) { for(i=0; i<=n-1; i++) { referror = referror||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-boundval(xe.ptr.p_double[i], bl.ptr.p_double[i], bu.ptr.p_double[i], _state), _state),5.0E-2); } } else { referror = ae_true; } } } /* * 1D problem #1 * * NOTES: we also test negative RKind's corresponding to "inexact" schemes * which use approximate finite difference Jacobian. */ for(rkind=-2; rkind<=5; rkind++) { ae_vector_set_length(&x, 1, _state); n = 1; m = 1; h = 0.00001; x.ptr.p_double[0] = 100*ae_randomreal(_state)-50; if( rkind==-2 ) { minlmcreatev(n, m, &x, h, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==-1 ) { minlmcreatev(n, m, &x, h, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==0 ) { minlmcreatefj(n, m, &x, &state, _state); } if( rkind==1 ) { minlmcreatefgj(n, m, &x, &state, _state); } if( rkind==2 ) { minlmcreatefgh(n, &x, &state, _state); } if( rkind==3 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==4 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==5 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 2, _state); } while(minlmiteration(&state, _state)) { if( state.needfi ) { state.fi.ptr.p_double[0] = ae_sin(state.x.ptr.p_double[0], _state); } if( state.needfij ) { state.fi.ptr.p_double[0] = ae_sin(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][0] = ae_cos(state.x.ptr.p_double[0], _state); } if( (state.needf||state.needfg)||state.needfgh ) { state.f = ae_sqr(ae_sin(state.x.ptr.p_double[0], _state), _state); } if( state.needfg||state.needfgh ) { state.g.ptr.p_double[0] = 2*ae_sin(state.x.ptr.p_double[0], _state)*ae_cos(state.x.ptr.p_double[0], _state); } if( state.needfgh ) { state.h.ptr.pp_double[0][0] = 2*(ae_cos(state.x.ptr.p_double[0], _state)*ae_cos(state.x.ptr.p_double[0], _state)-ae_sin(state.x.ptr.p_double[0], _state)*ae_sin(state.x.ptr.p_double[0], _state)); } scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); } minlmresults(&state, &x, &rep, _state); lin1error = rep.terminationtype<=0||ae_fp_greater(ae_fabs(x.ptr.p_double[0]/ae_pi-ae_round(x.ptr.p_double[0]/ae_pi, _state), _state),0.001); } /* * Linear equations: test normal optimization and optimization with restarts */ for(n=1; n<=10; n++) { /* * Prepare task */ h = 0.00001; rmatrixrndcond(n, (double)(100), &a, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xe, n, _state); ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xe.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = v; } /* * Test different RKind * * NOTES: we also test negative RKind's corresponding to "inexact" schemes * which use approximate finite difference Jacobian. */ for(rkind=-2; rkind<=5; rkind++) { /* * Solve task (first attempt) */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( rkind==-2 ) { minlmcreatev(n, n, &x, h, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==-1 ) { minlmcreatev(n, n, &x, h, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==0 ) { minlmcreatefj(n, n, &x, &state, _state); } if( rkind==1 ) { minlmcreatefgj(n, n, &x, &state, _state); } if( rkind==2 ) { minlmcreatefgh(n, &x, &state, _state); } if( rkind==3 ) { minlmcreatevj(n, n, &x, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==4 ) { minlmcreatevj(n, n, &x, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==5 ) { minlmcreatevj(n, n, &x, &state, _state); minlmsetacctype(&state, 2, _state); } while(minlmiteration(&state, _state)) { testminlmunit_axmb(&state, &a, &b, n, _state); scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); } minlmresults(&state, &x, &rep, _state); eqerror = eqerror||rep.terminationtype<=0; for(i=0; i<=n-1; i++) { eqerror = eqerror||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-xe.ptr.p_double[i], _state),0.001); } /* * Now we try to restart algorithm from new point */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minlmrestartfrom(&state, &x, _state); while(minlmiteration(&state, _state)) { testminlmunit_axmb(&state, &a, &b, n, _state); scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); } minlmresults(&state, &x, &rep, _state); restartserror = restartserror||rep.terminationtype<=0; for(i=0; i<=n-1; i++) { restartserror = restartserror||ae_fp_greater(ae_fabs(x.ptr.p_double[i]-xe.ptr.p_double[i], _state),0.001); } } } /* * Testing convergence properties using * different optimizer types and different conditions. * * Only limited subset of optimizers is tested because some * optimizers converge too quickly. */ s = (double)(100); for(rkind=0; rkind<=5; rkind++) { /* * Skip FGH optimizer - it converges too quickly */ if( rkind==2 ) { continue; } /* * Test */ for(ckind=0; ckind<=3; ckind++) { epsg = (double)(0); epsf = (double)(0); epsx = (double)(0); maxits = 0; if( ckind==0 ) { epsf = 0.000001; } if( ckind==1 ) { epsx = 0.000001; } if( ckind==2 ) { maxits = 2; } if( ckind==3 ) { epsg = 0.0001; } ae_vector_set_length(&x, 3, _state); n = 3; m = 3; for(i=0; i<=2; i++) { x.ptr.p_double[i] = (double)(6); } if( rkind==0 ) { minlmcreatefj(n, m, &x, &state, _state); } if( rkind==1 ) { minlmcreatefgj(n, m, &x, &state, _state); } ae_assert(rkind!=2, "Assertion failed", _state); if( rkind==3 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==4 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==5 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 2, _state); } minlmsetcond(&state, epsg, epsf, epsx, maxits, _state); while(minlmiteration(&state, _state)) { if( state.needfi||state.needfij ) { state.fi.ptr.p_double[0] = s*(ae_exp(state.x.ptr.p_double[0], _state)-2); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[1], _state)+1; state.fi.ptr.p_double[2] = state.x.ptr.p_double[2]-state.x.ptr.p_double[0]; } if( state.needfij ) { state.j.ptr.pp_double[0][0] = s*ae_exp(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][1] = (double)(0); state.j.ptr.pp_double[0][2] = (double)(0); state.j.ptr.pp_double[1][0] = (double)(0); state.j.ptr.pp_double[1][1] = 2*state.x.ptr.p_double[1]; state.j.ptr.pp_double[1][2] = (double)(0); state.j.ptr.pp_double[2][0] = (double)(-1); state.j.ptr.pp_double[2][1] = (double)(0); state.j.ptr.pp_double[2][2] = (double)(1); } if( (state.needf||state.needfg)||state.needfgh ) { state.f = s*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(ae_sqr(state.x.ptr.p_double[1], _state)+1, _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); } if( state.needfg||state.needfgh ) { state.g.ptr.p_double[0] = s*2*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*(ae_sqr(state.x.ptr.p_double[1], _state)+1)*2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } if( state.needfgh ) { state.h.ptr.pp_double[0][0] = s*(4*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state), _state)-4*ae_exp(state.x.ptr.p_double[0], _state))+2; state.h.ptr.pp_double[0][1] = (double)(0); state.h.ptr.pp_double[0][2] = (double)(-2); state.h.ptr.pp_double[1][0] = (double)(0); state.h.ptr.pp_double[1][1] = 12*ae_sqr(state.x.ptr.p_double[1], _state)+4; state.h.ptr.pp_double[1][2] = (double)(0); state.h.ptr.pp_double[2][0] = (double)(-2); state.h.ptr.pp_double[2][1] = (double)(0); state.h.ptr.pp_double[2][2] = (double)(2); } scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); } minlmresults(&state, &x, &rep, _state); if( ckind==0 ) { converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.05); converror = converror||rep.terminationtype!=1; } if( ckind==1 ) { converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.05); converror = converror||rep.terminationtype!=2; } if( ckind==2 ) { converror = (converror||rep.terminationtype!=5)||rep.iterationscount!=maxits; } if( ckind==3 ) { converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[0]-ae_log((double)(2), _state), _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[1], _state),0.05); converror = converror||ae_fp_greater(ae_fabs(x.ptr.p_double[2]-ae_log((double)(2), _state), _state),0.05); converror = converror||rep.terminationtype!=4; } } } /* * Other properties: * 1. test reports (F should form monotone sequence) * 2. test maximum step */ for(rkind=0; rkind<=5; rkind++) { /* * reports: * * check that first report is initial point * * check that F is monotone decreasing * * check that last report is final result */ n = 3; m = 3; s = (double)(100); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(6); } if( rkind==0 ) { minlmcreatefj(n, m, &x, &state, _state); } if( rkind==1 ) { minlmcreatefgj(n, m, &x, &state, _state); } if( rkind==2 ) { minlmcreatefgh(n, &x, &state, _state); } if( rkind==3 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 0, _state); } if( rkind==4 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 1, _state); } if( rkind==5 ) { minlmcreatevj(n, m, &x, &state, _state); minlmsetacctype(&state, 2, _state); } minlmsetcond(&state, (double)(0), (double)(0), (double)(0), 4, _state); minlmsetxrep(&state, ae_true, _state); fprev = ae_maxrealnumber; while(minlmiteration(&state, _state)) { if( state.needfi||state.needfij ) { state.fi.ptr.p_double[0] = ae_sqrt(s, _state)*(ae_exp(state.x.ptr.p_double[0], _state)-2); state.fi.ptr.p_double[1] = state.x.ptr.p_double[1]; state.fi.ptr.p_double[2] = state.x.ptr.p_double[2]-state.x.ptr.p_double[0]; } if( state.needfij ) { state.j.ptr.pp_double[0][0] = ae_sqrt(s, _state)*ae_exp(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][1] = (double)(0); state.j.ptr.pp_double[0][2] = (double)(0); state.j.ptr.pp_double[1][0] = (double)(0); state.j.ptr.pp_double[1][1] = (double)(1); state.j.ptr.pp_double[1][2] = (double)(0); state.j.ptr.pp_double[2][0] = (double)(-1); state.j.ptr.pp_double[2][1] = (double)(0); state.j.ptr.pp_double[2][2] = (double)(1); } if( (state.needf||state.needfg)||state.needfgh ) { state.f = s*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state)-2, _state)+ae_sqr(state.x.ptr.p_double[1], _state)+ae_sqr(state.x.ptr.p_double[2]-state.x.ptr.p_double[0], _state); } if( state.needfg||state.needfgh ) { state.g.ptr.p_double[0] = s*2*(ae_exp(state.x.ptr.p_double[0], _state)-2)*ae_exp(state.x.ptr.p_double[0], _state)+2*(state.x.ptr.p_double[0]-state.x.ptr.p_double[2]); state.g.ptr.p_double[1] = 2*state.x.ptr.p_double[1]; state.g.ptr.p_double[2] = 2*(state.x.ptr.p_double[2]-state.x.ptr.p_double[0]); } if( state.needfgh ) { state.h.ptr.pp_double[0][0] = s*(4*ae_sqr(ae_exp(state.x.ptr.p_double[0], _state), _state)-4*ae_exp(state.x.ptr.p_double[0], _state))+2; state.h.ptr.pp_double[0][1] = (double)(0); state.h.ptr.pp_double[0][2] = (double)(-2); state.h.ptr.pp_double[1][0] = (double)(0); state.h.ptr.pp_double[1][1] = (double)(2); state.h.ptr.pp_double[1][2] = (double)(0); state.h.ptr.pp_double[2][0] = (double)(-2); state.h.ptr.pp_double[2][1] = (double)(0); state.h.ptr.pp_double[2][2] = (double)(2); } scerror = scerror||!testminlmunit_rkindvsstatecheck(rkind, &state, _state); if( state.xupdated ) { othererrors = othererrors||ae_fp_greater(state.f,fprev); if( ae_fp_eq(fprev,ae_maxrealnumber) ) { for(i=0; i<=n-1; i++) { othererrors = othererrors||ae_fp_neq(state.x.ptr.p_double[i],x.ptr.p_double[i]); } } fprev = state.f; ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } minlmresults(&state, &x, &rep, _state); for(i=0; i<=n-1; i++) { othererrors = othererrors||ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]); } } n = 1; ae_vector_set_length(&x, n, _state); x.ptr.p_double[0] = (double)(100); stpmax = 0.05+0.05*ae_randomreal(_state); minlmcreatefgh(n, &x, &state, _state); minlmsetcond(&state, 1.0E-9, (double)(0), (double)(0), 0, _state); minlmsetstpmax(&state, stpmax, _state); minlmsetxrep(&state, ae_true, _state); xprev = x.ptr.p_double[0]; while(minlmiteration(&state, _state)) { if( (state.needf||state.needfg)||state.needfgh ) { state.f = ae_exp(state.x.ptr.p_double[0], _state)+ae_exp(-state.x.ptr.p_double[0], _state); } if( state.needfg||state.needfgh ) { state.g.ptr.p_double[0] = ae_exp(state.x.ptr.p_double[0], _state)-ae_exp(-state.x.ptr.p_double[0], _state); } if( state.needfgh ) { state.h.ptr.pp_double[0][0] = ae_exp(state.x.ptr.p_double[0], _state)+ae_exp(-state.x.ptr.p_double[0], _state); } othererrors = othererrors||ae_fp_greater(ae_fabs(state.x.ptr.p_double[0]-xprev, _state),(1+ae_sqrt(ae_machineepsilon, _state))*stpmax); if( state.xupdated ) { xprev = state.x.ptr.p_double[0]; } } /* * Check algorithm ability to handle request for termination: * * to terminate with correct return code = 8 * * to return point which was "current" at the moment of termination */ for(pass=1; pass<=50; pass++) { n = 3; m = 3; s = (double)(100); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 6+ae_randomreal(_state); } stopcallidx = ae_randominteger(20, _state); maxits = 25; minlmcreatevj(n, m, &x, &state, _state); minlmsetcond(&state, (double)(0), (double)(0), (double)(0), maxits, _state); minlmsetxrep(&state, ae_true, _state); callidx = 0; terminationrequested = ae_false; ae_v_move(&xlast.ptr.p_double[0], 1, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); while(minlmiteration(&state, _state)) { if( state.needfi||state.needfij ) { state.fi.ptr.p_double[0] = ae_sqrt(s, _state)*(ae_exp(state.x.ptr.p_double[0], _state)-2); state.fi.ptr.p_double[1] = state.x.ptr.p_double[1]; state.fi.ptr.p_double[2] = state.x.ptr.p_double[2]-state.x.ptr.p_double[0]; if( state.needfij ) { state.j.ptr.pp_double[0][0] = ae_sqrt(s, _state)*ae_exp(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][1] = (double)(0); state.j.ptr.pp_double[0][2] = (double)(0); state.j.ptr.pp_double[1][0] = (double)(0); state.j.ptr.pp_double[1][1] = (double)(1); state.j.ptr.pp_double[1][2] = (double)(0); state.j.ptr.pp_double[2][0] = (double)(-1); state.j.ptr.pp_double[2][1] = (double)(0); state.j.ptr.pp_double[2][2] = (double)(1); } if( callidx==stopcallidx ) { minlmrequesttermination(&state, _state); terminationrequested = ae_true; } inc(&callidx, _state); continue; } if( state.xupdated ) { if( !terminationrequested ) { ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minlmresults(&state, &x, &rep, _state); seterrorflag(&othererrors, rep.terminationtype!=8, _state); for(i=0; i<=n-1; i++) { seterrorflag(&othererrors, ae_fp_neq(x.ptr.p_double[i],xlast.ptr.p_double[i]), _state); } } /* * Test for MinLMGradientCheck */ graderrors = testminlmunit_gradientchecktest(_state); /* * end */ waserrors = (((((((referror||lin1error)||lin2error)||eqerror)||converror)||scerror)||othererrors)||restartserror)||graderrors; if( !silent ) { printf("TESTING LEVENBERG-MARQUARDT OPTIMIZATION\n"); printf("REFERENCE PROBLEMS: "); if( referror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("1-D PROBLEM #1: "); if( lin1error ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("1-D PROBLEM #2: "); if( lin2error ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LINEAR EQUATIONS: "); if( eqerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RESTARTS: "); if( restartserror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CONVERGENCE PROPERTIES: "); if( converror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("STATE FIELDS CONSISTENCY: "); if( scerror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("OTHER PROPERTIES: "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST FOR VERIFICATION OF DERIVATIVES: "); if( graderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminlm(ae_bool silent, ae_state *_state) { return testminlm(silent, _state); } /************************************************************************* Asserts that State fields are consistent with RKind. Returns False otherwise. RKind is an algorithm selector: * -2 = V, AccType=1 * -1 = V, AccType=0 * 0 = FJ * 1 = FGJ * 2 = FGH * 3 = VJ, AccType=0 * 4 = VJ, AccType=1 * 5 = VJ, AccType=2 *************************************************************************/ static ae_bool testminlmunit_rkindvsstatecheck(ae_int_t rkind, minlmstate* state, ae_state *_state) { ae_int_t nset; ae_bool result; nset = 0; if( state->needfi ) { nset = nset+1; } if( state->needf ) { nset = nset+1; } if( state->needfg ) { nset = nset+1; } if( state->needfij ) { nset = nset+1; } if( state->needfgh ) { nset = nset+1; } if( state->xupdated ) { nset = nset+1; } if( nset!=1 ) { result = ae_false; return result; } if( rkind==-2 ) { result = state->needfi||state->xupdated; return result; } if( rkind==-1 ) { result = state->needfi||state->xupdated; return result; } if( rkind==0 ) { result = (state->needf||state->needfij)||state->xupdated; return result; } if( rkind==1 ) { result = ((state->needf||state->needfij)||state->needfg)||state->xupdated; return result; } if( rkind==2 ) { result = ((state->needf||state->needfg)||state->needfgh)||state->xupdated; return result; } if( rkind==3 ) { result = (state->needfi||state->needfij)||state->xupdated; return result; } if( rkind==4 ) { result = (state->needfi||state->needfij)||state->xupdated; return result; } if( rkind==5 ) { result = (state->needfi||state->needfij)||state->xupdated; return result; } result = ae_false; return result; } /************************************************************************* Calculates FI/F/G/H for problem min(||Ax-b||) *************************************************************************/ static void testminlmunit_axmb(minlmstate* state, /* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; ae_int_t k; double v; if( (state->needf||state->needfg)||state->needfgh ) { state->f = (double)(0); } if( state->needfg||state->needfgh ) { for(i=0; i<=n-1; i++) { state->g.ptr.p_double[i] = (double)(0); } } if( state->needfgh ) { for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { state->h.ptr.pp_double[i][j] = (double)(0); } } } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a->ptr.pp_double[i][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( (state->needf||state->needfg)||state->needfgh ) { state->f = state->f+ae_sqr(v-b->ptr.p_double[i], _state); } if( state->needfg||state->needfgh ) { for(j=0; j<=n-1; j++) { state->g.ptr.p_double[j] = state->g.ptr.p_double[j]+2*(v-b->ptr.p_double[i])*a->ptr.pp_double[i][j]; } } if( state->needfgh ) { for(j=0; j<=n-1; j++) { for(k=0; k<=n-1; k++) { state->h.ptr.pp_double[j][k] = state->h.ptr.pp_double[j][k]+2*a->ptr.pp_double[i][j]*a->ptr.pp_double[i][k]; } } } if( state->needfi ) { state->fi.ptr.p_double[i] = v-b->ptr.p_double[i]; } if( state->needfij ) { state->fi.ptr.p_double[i] = v-b->ptr.p_double[i]; ae_v_move(&state->j.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } } /************************************************************************* This function tries to reproduce previously fixed bugs; in case of bug being present sets Err to True; *************************************************************************/ static void testminlmunit_tryreproducefixedbugs(ae_bool* err, ae_state *_state) { ae_frame _frame_block; minlmstate s; minlmreport rep; ae_vector bl; ae_vector bu; ae_vector x; ae_frame_make(_state, &_frame_block); _minlmstate_init(&s, _state); _minlmreport_init(&rep, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); /* * Reproduce bug reported by ISS: * when solving bound constrained problem with numerical differentiation * and starting from infeasible point, we won't stop at the feasible point */ ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&bl, 2, _state); ae_vector_set_length(&bu, 2, _state); x.ptr.p_double[0] = 2.0; bl.ptr.p_double[0] = -1.0; bu.ptr.p_double[0] = 1.0; x.ptr.p_double[1] = 2.0; bl.ptr.p_double[1] = -1.0; bu.ptr.p_double[1] = 1.0; minlmcreatev(2, 2, &x, 0.001, &s, _state); minlmsetbc(&s, &bl, &bu, _state); while(minlmiteration(&s, _state)) { if( s.needfi ) { s.fi.ptr.p_double[0] = ae_sqr(s.x.ptr.p_double[0], _state); s.fi.ptr.p_double[1] = ae_sqr(s.x.ptr.p_double[1], _state); } } minlmresults(&s, &x, &rep, _state); *err = ((ae_fp_less(x.ptr.p_double[0],bl.ptr.p_double[0])||ae_fp_greater(x.ptr.p_double[0],bu.ptr.p_double[0]))||ae_fp_less(x.ptr.p_double[1],bl.ptr.p_double[1]))||ae_fp_greater(x.ptr.p_double[1],bu.ptr.p_double[1]); ae_frame_leave(_state); } /************************************************************************* This function tests, that gradient verified correctly. *************************************************************************/ static ae_bool testminlmunit_gradientchecktest(ae_state *_state) { ae_frame _frame_block; minlmstate state; minlmreport rep; ae_int_t n; ae_int_t m; ae_vector a; ae_vector x0; ae_vector x; ae_vector bl; ae_vector bu; ae_int_t infcomp; double teststep; double noise; double rndconst; ae_int_t nbrfunc; ae_int_t nbrcomp; double spp; ae_int_t func; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_bool result; ae_frame_make(_state, &_frame_block); _minlmstate_init(&state, _state); _minlmreport_init(&rep, _state); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); passcount = 35; spp = 1.0; teststep = 0.01; for(pass=1; pass<=passcount; pass++) { n = ae_randominteger(10, _state)+1; m = ae_randominteger(10, _state)+1; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&a, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); /* * Prepare test's parameters */ func = ae_randominteger(3, _state)+1; nbrfunc = ae_randominteger(m, _state); nbrcomp = ae_randominteger(n, _state); noise = (double)(2*ae_randominteger(2, _state)-1); rndconst = 2*ae_randomreal(_state)-1; /* * Prepare function's parameters */ for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 5*randomnormal(_state); a.ptr.p_double[i] = 5*ae_randomreal(_state)+1; x0.ptr.p_double[i] = 5*(2*ae_randomreal(_state)-1); } /* * Prepare boundary parameters */ for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -3*ae_randomreal(_state)-0.1; bu.ptr.p_double[i] = 3*ae_randomreal(_state)+0.1; } infcomp = ae_randominteger(n+1, _state); if( infcompv_neginf; } infcomp = ae_randominteger(n+1, _state); if( infcompv_posinf; } minlmcreatevj(n, m, &x, &state, _state); minlmsetcond(&state, (double)(0), (double)(0), (double)(0), 0, _state); minlmsetgradientcheck(&state, teststep, _state); minlmsetbc(&state, &bl, &bu, _state); /* * Check that the criterion passes a derivative if it is correct */ while(minlmiteration(&state, _state)) { if( state.needfij ) { /* * Check hat .X within the boundaries */ for(i=0; i<=n-1; i++) { if( (ae_isfinite(bl.ptr.p_double[i], _state)&&ae_fp_less(state.x.ptr.p_double[i],bl.ptr.p_double[i]))||(ae_isfinite(bu.ptr.p_double[i], _state)&&ae_fp_greater(state.x.ptr.p_double[i],bu.ptr.p_double[i])) ) { result = ae_true; ae_frame_leave(_state); return result; } } testminlmunit_funcderiv(&a, &x0, &state.x, m, n, rndconst, func, &state.fi, &state.j, _state); } } minlmresults(&state, &x, &rep, _state); /* * Check that error code does not equal to -7 and parameter .VarIdx * equal to -1. */ if( (rep.terminationtype==-7||rep.funcidx!=-1)||rep.varidx!=-1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 5*randomnormal(_state); } minlmrestartfrom(&state, &x, _state); /* * Check that the criterion does not miss a derivative if * it is incorrect */ while(minlmiteration(&state, _state)) { if( state.needfij ) { for(i=0; i<=n-1; i++) { if( (ae_isfinite(bl.ptr.p_double[i], _state)&&ae_fp_less(state.x.ptr.p_double[i],bl.ptr.p_double[i]))||(ae_isfinite(bu.ptr.p_double[i], _state)&&ae_fp_greater(state.x.ptr.p_double[i],bu.ptr.p_double[i])) ) { result = ae_true; ae_frame_leave(_state); return result; } } testminlmunit_funcderiv(&a, &x0, &state.x, m, n, rndconst, func, &state.fi, &state.j, _state); state.j.ptr.pp_double[nbrfunc][nbrcomp] = state.j.ptr.pp_double[nbrfunc][nbrcomp]+noise; } } minlmresults(&state, &x, &rep, _state); /* * Check that error code equal to -7 and parameter .VarIdx * equal to number of incorrect component. */ if( (rep.terminationtype!=-7||rep.funcidx!=nbrfunc)||rep.varidx!=nbrcomp ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function return function value and it derivatives. The number of functions is M, dimension for each of functions is N. F(XI)=SUM(fi(XI)); (XI={x,y,z}; i=0..M-1); Function's list: * funcType=1: fi(X)=(Aj*Xj-X0j)^2; * funcType=2: fi(X)=Aj*sin(Xj-X0j); * funcType=3: fi(X)=Aj*Xj-X0j; fM-1(X)=A(M-1)*((X(M-1)-X0(M-1))-(X0-X00)). *************************************************************************/ static void testminlmunit_funcderiv(/* Real */ ae_vector* a, /* Real */ ae_vector* x0, /* Real */ ae_vector* x, ae_int_t m, ae_int_t n, double anyconst, ae_int_t functype, /* Real */ ae_vector* f, /* Real */ ae_matrix* j, ae_state *_state) { ae_int_t i0; ae_int_t j0; ae_assert(functype>=1&&functype<=3, "FuncDeriv: incorrect funcType(funcType<1 or funcType>3).", _state); ae_assert(n>0, "FuncDeriv: N<=0", _state); ae_assert(m>0, "FuncDeriv: M<=0", _state); ae_assert(x->cnt>=n, "FuncDeriv: Length(X)cnt>=n, "FuncDeriv: Length(X0)cnt>=n, "FuncDeriv: Length(X)ptr.p_double[i0] = a->ptr.p_double[i0]*x->ptr.p_double[i0]-x0->ptr.p_double[i0]; } else { f->ptr.p_double[i0] = anyconst; } } for(i0=0; i0<=m-1; i0++) { for(j0=0; j0<=n-1; j0++) { if( i0==j0 ) { j->ptr.pp_double[i0][j0] = a->ptr.p_double[j0]; } else { j->ptr.pp_double[i0][j0] = (double)(0); } } } return; } if( functype==2 ) { for(i0=0; i0<=m-1; i0++) { if( i0ptr.p_double[i0] = a->ptr.p_double[i0]*ae_sin(x->ptr.p_double[i0]-x0->ptr.p_double[i0], _state); } else { f->ptr.p_double[i0] = anyconst; } } for(i0=0; i0<=m-1; i0++) { for(j0=0; j0<=n-1; j0++) { if( i0==j0 ) { j->ptr.pp_double[i0][j0] = a->ptr.p_double[j0]*ae_cos(x->ptr.p_double[j0]-x0->ptr.p_double[j0], _state); } else { j->ptr.pp_double[i0][j0] = (double)(0); } } } return; } if( functype==3 ) { for(i0=0; i0<=m-1; i0++) { if( i0ptr.p_double[i0] = a->ptr.p_double[i0]*x->ptr.p_double[i0]-x0->ptr.p_double[i0]; } else { f->ptr.p_double[i0] = anyconst; } } for(i0=0; i0<=m-1; i0++) { for(j0=0; j0<=n-1; j0++) { if( i0==j0 ) { j->ptr.pp_double[i0][j0] = a->ptr.p_double[j0]; } else { j->ptr.pp_double[i0][j0] = (double)(0); } } } if( m>n&&n>1 ) { f->ptr.p_double[n-1] = a->ptr.p_double[n-1]*(x->ptr.p_double[n-1]-x0->ptr.p_double[n-1]-(x->ptr.p_double[0]-x0->ptr.p_double[0])); j->ptr.pp_double[n-1][0] = -a->ptr.p_double[n-1]; j->ptr.pp_double[n-1][n-1] = a->ptr.p_double[n-1]; for(i0=1; i0<=n-2; i0++) { j->ptr.pp_double[n-1][i0] = (double)(0); } } return; } } static void testlsfitunit_testpolynomialfitting(ae_bool* fiterrors, ae_state *_state); static void testlsfitunit_testrationalfitting(ae_bool* fiterrors, ae_state *_state); static void testlsfitunit_testsplinefitting(ae_bool* fiterrors, ae_state *_state); static void testlsfitunit_testgeneralfitting(ae_bool* llserrors, ae_bool* nlserrors, ae_state *_state); static void testlsfitunit_testrdp(ae_bool* errorflag, ae_state *_state); static void testlsfitunit_testlogisticfitting(ae_bool* fiterrors, ae_state *_state); static ae_bool testlsfitunit_isglssolution(ae_int_t n, ae_int_t m, ae_int_t k, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, /* Real */ ae_vector* c, ae_state *_state); static double testlsfitunit_getglserror(ae_int_t n, ae_int_t m, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_vector* c, ae_state *_state); static void testlsfitunit_fitlinearnonlinear(ae_int_t m, ae_int_t deravailable, /* Real */ ae_matrix* xy, lsfitstate* state, ae_bool* nlserrors, ae_state *_state); static void testlsfitunit_testgradientcheck(ae_bool* testg, ae_state *_state); static void testlsfitunit_funcderiv(/* Real */ ae_vector* c, /* Real */ ae_vector* x, /* Real */ ae_vector* x0, ae_int_t k, ae_int_t m, ae_int_t functype, double* f, /* Real */ ae_vector* g, ae_state *_state); ae_bool testlsfit(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool llserrors; ae_bool nlserrors; ae_bool polfiterrors; ae_bool ratfiterrors; ae_bool splfiterrors; ae_bool graderrors; ae_bool logisticerrors; ae_bool rdperrors; ae_bool result; waserrors = ae_false; polfiterrors = ae_false; ratfiterrors = ae_false; splfiterrors = ae_false; llserrors = ae_false; nlserrors = ae_false; graderrors = ae_false; logisticerrors = ae_false; rdperrors = ae_false; testlsfitunit_testrdp(&rdperrors, _state); testlsfitunit_testlogisticfitting(&logisticerrors, _state); testlsfitunit_testpolynomialfitting(&polfiterrors, _state); testlsfitunit_testrationalfitting(&ratfiterrors, _state); testlsfitunit_testsplinefitting(&splfiterrors, _state); testlsfitunit_testgeneralfitting(&llserrors, &nlserrors, _state); testlsfitunit_testgradientcheck(&graderrors, _state); /* * report */ waserrors = ((((((llserrors||nlserrors)||polfiterrors)||ratfiterrors)||splfiterrors)||graderrors)||logisticerrors)||rdperrors; if( !silent ) { printf("TESTING LEAST SQUARES\n"); printf("POLYNOMIAL LEAST SQUARES: "); if( polfiterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RATIONAL LEAST SQUARES: "); if( ratfiterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("SPLINE LEAST SQUARES: "); if( splfiterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LINEAR LEAST SQUARES: "); if( llserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("NON-LINEAR LEAST SQUARES: "); if( nlserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TEST FOR VERIFICATION OF THE GRADIENT: "); if( graderrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LOGISTIC FITTING (4PL/5PL): "); if( logisticerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RDP ALGORITHM: "); if( rdperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlsfit(ae_bool silent, ae_state *_state) { return testlsfit(silent, _state); } /************************************************************************* Unit test *************************************************************************/ static void testlsfitunit_testpolynomialfitting(ae_bool* fiterrors, ae_state *_state) { ae_frame _frame_block; double threshold; ae_vector x; ae_vector y; ae_vector w; ae_vector x2; ae_vector y2; ae_vector w2; ae_vector xfull; ae_vector yfull; double t; ae_int_t i; ae_int_t k; ae_vector xc; ae_vector yc; ae_vector dc; ae_int_t info; ae_int_t info2; double v; double v0; double v1; double v2; double s; double xmin; double xmax; double refrms; double refavg; double refavgrel; double refmax; barycentricinterpolant p; barycentricinterpolant p1; barycentricinterpolant p2; polynomialfitreport rep; polynomialfitreport rep2; ae_int_t n; ae_int_t m; ae_int_t maxn; ae_int_t pass; ae_int_t passcount; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xfull, 0, DT_REAL, _state); ae_vector_init(&yfull, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); _barycentricinterpolant_init(&p, _state); _barycentricinterpolant_init(&p1, _state); _barycentricinterpolant_init(&p2, _state); _polynomialfitreport_init(&rep, _state); _polynomialfitreport_init(&rep2, _state); *fiterrors = ae_false; maxn = 5; passcount = 20; threshold = 1.0E8*ae_machineepsilon; /* * Test polunomial fitting */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { /* * N=M+K fitting (i.e. interpolation) */ for(k=0; k<=n-1; k++) { taskgenint1d((double)(-1), (double)(1), n, &xfull, &yfull, _state); ae_vector_set_length(&x, n-k, _state); ae_vector_set_length(&y, n-k, _state); ae_vector_set_length(&w, n-k, _state); if( k>0 ) { ae_vector_set_length(&xc, k, _state); ae_vector_set_length(&yc, k, _state); ae_vector_set_length(&dc, k, _state); } for(i=0; i<=n-k-1; i++) { x.ptr.p_double[i] = xfull.ptr.p_double[i]; y.ptr.p_double[i] = yfull.ptr.p_double[i]; w.ptr.p_double[i] = 1+ae_randomreal(_state); } for(i=0; i<=k-1; i++) { xc.ptr.p_double[i] = xfull.ptr.p_double[n-k+i]; yc.ptr.p_double[i] = yfull.ptr.p_double[n-k+i]; dc.ptr.p_int[i] = 0; } polynomialfitwc(&x, &y, &w, n-k, &xc, &yc, &dc, k, n, &info, &p1, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=n-k-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(barycentriccalc(&p1, x.ptr.p_double[i], _state)-y.ptr.p_double[i], _state),threshold); } for(i=0; i<=k-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(barycentriccalc(&p1, xc.ptr.p_double[i], _state)-yc.ptr.p_double[i], _state),threshold); } } } /* * Testing constraints on derivatives. * Special tasks which will always have solution: * 1. P(0)=YC[0] * 2. P(0)=YC[0], P'(0)=YC[1] */ if( n>1 ) { for(m=3; m<=5; m++) { for(k=1; k<=2; k++) { taskgenint1d((double)(-1), (double)(1), n, &x, &y, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 2, _state); ae_vector_set_length(&yc, 2, _state); ae_vector_set_length(&dc, 2, _state); for(i=0; i<=n-1; i++) { w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = (double)(0); yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = 0; xc.ptr.p_double[1] = (double)(0); yc.ptr.p_double[1] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[1] = 1; polynomialfitwc(&x, &y, &w, n, &xc, &yc, &dc, k, m, &info, &p1, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { barycentricdiff1(&p1, 0.0, &v0, &v1, _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v0-yc.ptr.p_double[0], _state),threshold); if( k==2 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v1-yc.ptr.p_double[1], _state),threshold); } } } } } } } for(m=2; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { /* * General fitting * * interpolating function through M nodes should have * greater RMS error than fitting it through the same M nodes */ n = 100; ae_vector_set_length(&x2, n, _state); ae_vector_set_length(&y2, n, _state); ae_vector_set_length(&w2, n, _state); xmin = (double)(0); xmax = 2*ae_pi; for(i=0; i<=n-1; i++) { x2.ptr.p_double[i] = 2*ae_pi*ae_randomreal(_state); y2.ptr.p_double[i] = ae_sin(x2.ptr.p_double[i], _state); w2.ptr.p_double[i] = (double)(1); } ae_vector_set_length(&x, m, _state); ae_vector_set_length(&y, m, _state); for(i=0; i<=m-1; i++) { x.ptr.p_double[i] = xmin+(xmax-xmin)*i/(m-1); y.ptr.p_double[i] = ae_sin(x.ptr.p_double[i], _state); } polynomialbuild(&x, &y, m, &p1, _state); polynomialfitwc(&x2, &y2, &w2, n, &xc, &yc, &dc, 0, m, &info, &p2, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * calculate P1 (interpolant) RMS error, compare with P2 error */ v1 = (double)(0); v2 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(barycentriccalc(&p1, x2.ptr.p_double[i], _state)-y2.ptr.p_double[i], _state); v2 = v2+ae_sqr(barycentriccalc(&p2, x2.ptr.p_double[i], _state)-y2.ptr.p_double[i], _state); } v1 = ae_sqrt(v1/n, _state); v2 = ae_sqrt(v2/n, _state); *fiterrors = *fiterrors||ae_fp_greater(v2,v1); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v2-rep.rmserror, _state),threshold); } /* * compare weighted and non-weighted */ n = 20; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = i+(ae_randomreal(_state)-0.5); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = (double)(1); } polynomialfitwc(&x, &y, &w, n, &xc, &yc, &dc, 0, m, &info, &p1, &rep, _state); polynomialfit(&x, &y, n, m, &info2, &p2, &rep2, _state); if( info<=0||info2<=0 ) { *fiterrors = ae_true; } else { /* * calculate P1 (interpolant), compare with P2 error * compare RMS errors */ t = 2*ae_randomreal(_state)-1; v1 = barycentriccalc(&p1, t, _state); v2 = barycentriccalc(&p2, t, _state); *fiterrors = *fiterrors||!approxequalrel(v2, v1, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.rmserror, rep2.rmserror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgerror, rep2.avgerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgrelerror, rep2.avgrelerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.maxerror, rep2.maxerror, threshold, _state); } } } for(m=1; m<=maxn; m++) { for(pass=1; pass<=passcount; pass++) { ae_assert(passcount>=2, "PassCount should be 2 or greater!", _state); /* * solve simple task (all X[] are the same, Y[] are specially * calculated to ensure simple form of all types of errors) * and check correctness of the errors calculated by subroutines * * First pass is done with zero Y[], other passes - with random Y[]. * It should test both ability to correctly calculate errors and * ability to not fail while working with zeros :) */ n = 4*maxn; if( pass==1 ) { v1 = (double)(0); v2 = (double)(0); v = (double)(0); } else { v1 = ae_randomreal(_state); v2 = ae_randomreal(_state); v = 1+ae_randomreal(_state); } ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=maxn-1; i++) { x.ptr.p_double[4*i+0] = (double)(i); y.ptr.p_double[4*i+0] = v-v2; w.ptr.p_double[4*i+0] = (double)(1); x.ptr.p_double[4*i+1] = (double)(i); y.ptr.p_double[4*i+1] = v-v1; w.ptr.p_double[4*i+1] = (double)(1); x.ptr.p_double[4*i+2] = (double)(i); y.ptr.p_double[4*i+2] = v+v1; w.ptr.p_double[4*i+2] = (double)(1); x.ptr.p_double[4*i+3] = (double)(i); y.ptr.p_double[4*i+3] = v+v2; w.ptr.p_double[4*i+3] = (double)(1); } refrms = ae_sqrt((ae_sqr(v1, _state)+ae_sqr(v2, _state))/2, _state); refavg = (ae_fabs(v1, _state)+ae_fabs(v2, _state))/2; if( pass==1 ) { refavgrel = (double)(0); } else { refavgrel = 0.25*(ae_fabs(v2, _state)/ae_fabs(v-v2, _state)+ae_fabs(v1, _state)/ae_fabs(v-v1, _state)+ae_fabs(v1, _state)/ae_fabs(v+v1, _state)+ae_fabs(v2, _state)/ae_fabs(v+v2, _state)); } refmax = ae_maxreal(v1, v2, _state); /* * Test errors correctness */ polynomialfit(&x, &y, n, m, &info, &p, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { s = barycentriccalc(&p, (double)(0), _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-v, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } } } ae_frame_leave(_state); } static void testlsfitunit_testrationalfitting(ae_bool* fiterrors, ae_state *_state) { ae_frame _frame_block; double threshold; ae_int_t maxn; ae_int_t passcount; barycentricinterpolant b1; barycentricinterpolant b2; ae_vector x; ae_vector x2; ae_vector y; ae_vector y2; ae_vector w; ae_vector w2; ae_vector xc; ae_vector yc; ae_vector dc; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t k; ae_int_t pass; double t; double s; double v; double v0; double v1; double v2; ae_int_t info; ae_int_t info2; double xmin; double xmax; double refrms; double refavg; double refavgrel; double refmax; barycentricfitreport rep; barycentricfitreport rep2; ae_frame_make(_state, &_frame_block); _barycentricinterpolant_init(&b1, _state); _barycentricinterpolant_init(&b2, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); _barycentricfitreport_init(&rep, _state); _barycentricfitreport_init(&rep2, _state); *fiterrors = ae_false; /* * PassCount number of repeated passes * Threshold error tolerance * LipschitzTol Lipschitz constant increase allowed * when calculating constant on a twice denser grid */ passcount = 5; maxn = 15; threshold = 1000000*ae_machineepsilon; /* * Test rational fitting: */ for(pass=1; pass<=passcount; pass++) { for(n=2; n<=maxn; n++) { /* * N=M+K fitting (i.e. interpolation) */ for(k=0; k<=n-1; k++) { ae_vector_set_length(&x, n-k, _state); ae_vector_set_length(&y, n-k, _state); ae_vector_set_length(&w, n-k, _state); if( k>0 ) { ae_vector_set_length(&xc, k, _state); ae_vector_set_length(&yc, k, _state); ae_vector_set_length(&dc, k, _state); } for(i=0; i<=n-k-1; i++) { x.ptr.p_double[i] = (double)i/(double)(n-1); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } for(i=0; i<=k-1; i++) { xc.ptr.p_double[i] = (double)(n-k+i)/(double)(n-1); yc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[i] = 0; } barycentricfitfloaterhormannwc(&x, &y, &w, n-k, &xc, &yc, &dc, k, n, &info, &b1, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=n-k-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, x.ptr.p_double[i], _state)-y.ptr.p_double[i], _state),threshold); } for(i=0; i<=k-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(barycentriccalc(&b1, xc.ptr.p_double[i], _state)-yc.ptr.p_double[i], _state),threshold); } } } /* * Testing constraints on derivatives: * * several M's are tried * * several K's are tried - 1, 2. * * constraints at the ends of the interval */ for(m=3; m<=5; m++) { for(k=1; k<=2; k++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 2, _state); ae_vector_set_length(&yc, 2, _state); ae_vector_set_length(&dc, 2, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = (double)(-1); yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = 0; xc.ptr.p_double[1] = (double)(1); yc.ptr.p_double[1] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[1] = 0; barycentricfitfloaterhormannwc(&x, &y, &w, n, &xc, &yc, &dc, k, m, &info, &b1, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=k-1; i++) { barycentricdiff1(&b1, xc.ptr.p_double[i], &v0, &v1, _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v0-yc.ptr.p_double[i], _state),threshold); } } } } } } for(m=2; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { /* * General fitting * * interpolating function through M nodes should have * greater RMS error than fitting it through the same M nodes */ n = 100; ae_vector_set_length(&x2, n, _state); ae_vector_set_length(&y2, n, _state); ae_vector_set_length(&w2, n, _state); xmin = ae_maxrealnumber; xmax = -ae_maxrealnumber; for(i=0; i<=n-1; i++) { x2.ptr.p_double[i] = 2*ae_pi*ae_randomreal(_state); y2.ptr.p_double[i] = ae_sin(x2.ptr.p_double[i], _state); w2.ptr.p_double[i] = (double)(1); xmin = ae_minreal(xmin, x2.ptr.p_double[i], _state); xmax = ae_maxreal(xmax, x2.ptr.p_double[i], _state); } ae_vector_set_length(&x, m, _state); ae_vector_set_length(&y, m, _state); for(i=0; i<=m-1; i++) { x.ptr.p_double[i] = xmin+(xmax-xmin)*i/(m-1); y.ptr.p_double[i] = ae_sin(x.ptr.p_double[i], _state); } barycentricbuildfloaterhormann(&x, &y, m, 3, &b1, _state); barycentricfitfloaterhormannwc(&x2, &y2, &w2, n, &xc, &yc, &dc, 0, m, &info, &b2, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * calculate B1 (interpolant) RMS error, compare with B2 error */ v1 = (double)(0); v2 = (double)(0); for(i=0; i<=n-1; i++) { v1 = v1+ae_sqr(barycentriccalc(&b1, x2.ptr.p_double[i], _state)-y2.ptr.p_double[i], _state); v2 = v2+ae_sqr(barycentriccalc(&b2, x2.ptr.p_double[i], _state)-y2.ptr.p_double[i], _state); } v1 = ae_sqrt(v1/n, _state); v2 = ae_sqrt(v2/n, _state); *fiterrors = *fiterrors||ae_fp_greater(v2,v1); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v2-rep.rmserror, _state),threshold); } /* * compare weighted and non-weighted */ n = 20; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = i+(ae_randomreal(_state)-0.5); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = (double)(1); } barycentricfitfloaterhormannwc(&x, &y, &w, n, &xc, &yc, &dc, 0, m, &info, &b1, &rep, _state); barycentricfitfloaterhormann(&x, &y, n, m, &info2, &b2, &rep2, _state); if( info<=0||info2<=0 ) { *fiterrors = ae_true; } else { /* * calculate B1 (interpolant), compare with B2 * compare RMS errors */ t = 2*ae_randomreal(_state)-1; v1 = barycentriccalc(&b1, t, _state); v2 = barycentriccalc(&b2, t, _state); *fiterrors = *fiterrors||!approxequalrel(v2, v1, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.rmserror, rep2.rmserror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgerror, rep2.avgerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgrelerror, rep2.avgrelerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.maxerror, rep2.maxerror, threshold, _state); } } } for(pass=1; pass<=passcount; pass++) { ae_assert(passcount>=2, "PassCount should be 2 or greater!", _state); /* * solve simple task (all X[] are the same, Y[] are specially * calculated to ensure simple form of all types of errors) * and check correctness of the errors calculated by subroutines * * First pass is done with zero Y[], other passes - with random Y[]. * It should test both ability to correctly calculate errors and * ability to not fail while working with zeros :) */ n = 4; if( pass==1 ) { v1 = (double)(0); v2 = (double)(0); v = (double)(0); } else { v1 = ae_randomreal(_state); v2 = ae_randomreal(_state); v = 1+ae_randomreal(_state); } ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); ae_vector_set_length(&w, 4, _state); x.ptr.p_double[0] = (double)(0); y.ptr.p_double[0] = v-v2; w.ptr.p_double[0] = (double)(1); x.ptr.p_double[1] = (double)(0); y.ptr.p_double[1] = v-v1; w.ptr.p_double[1] = (double)(1); x.ptr.p_double[2] = (double)(0); y.ptr.p_double[2] = v+v1; w.ptr.p_double[2] = (double)(1); x.ptr.p_double[3] = (double)(0); y.ptr.p_double[3] = v+v2; w.ptr.p_double[3] = (double)(1); refrms = ae_sqrt((ae_sqr(v1, _state)+ae_sqr(v2, _state))/2, _state); refavg = (ae_fabs(v1, _state)+ae_fabs(v2, _state))/2; if( pass==1 ) { refavgrel = (double)(0); } else { refavgrel = 0.25*(ae_fabs(v2, _state)/ae_fabs(v-v2, _state)+ae_fabs(v1, _state)/ae_fabs(v-v1, _state)+ae_fabs(v1, _state)/ae_fabs(v+v1, _state)+ae_fabs(v2, _state)/ae_fabs(v+v2, _state)); } refmax = ae_maxreal(v1, v2, _state); /* * Test errors correctness */ barycentricfitfloaterhormann(&x, &y, 4, 2, &info, &b1, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { s = barycentriccalc(&b1, (double)(0), _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-v, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } } ae_frame_leave(_state); } static void testlsfitunit_testsplinefitting(ae_bool* fiterrors, ae_state *_state) { ae_frame _frame_block; double threshold; double nonstrictthreshold; ae_int_t passcount; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t k; ae_int_t pass; ae_vector x; ae_vector y; ae_vector w; ae_vector w2; ae_vector xc; ae_vector yc; ae_vector d; ae_vector dc; double sa; double sb; ae_int_t info; ae_int_t info1; ae_int_t info2; spline1dinterpolant c; spline1dinterpolant c2; spline1dfitreport rep; spline1dfitreport rep2; double s; double ds; double d2s; ae_int_t stype; double t; double v; double v1; double v2; double refrms; double refavg; double refavgrel; double refmax; double rho; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&yc, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&dc, 0, DT_INT, _state); _spline1dinterpolant_init(&c, _state); _spline1dinterpolant_init(&c2, _state); _spline1dfitreport_init(&rep, _state); _spline1dfitreport_init(&rep2, _state); /* * Valyes: * * pass count * * threshold - for tests which must be satisfied exactly * * nonstrictthreshold - for approximate tests */ passcount = 20; threshold = 10000*ae_machineepsilon; nonstrictthreshold = 1.0E-4; *fiterrors = ae_false; /* * Test fitting by Cubic and Hermite splines (obsolete, but still supported) */ for(pass=1; pass<=passcount; pass++) { /* * Cubic splines * Ability to handle boundary constraints (1-4 constraints on F, dF/dx). */ for(m=4; m<=8; m++) { for(k=1; k<=4; k++) { if( k>=m ) { continue; } n = 100; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 4, _state); ae_vector_set_length(&yc, 4, _state); ae_vector_set_length(&dc, 4, _state); sa = 1+ae_randomreal(_state); sb = 2*ae_randomreal(_state)-1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = sa*ae_randomreal(_state)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = sb; yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = 0; xc.ptr.p_double[1] = sb; yc.ptr.p_double[1] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[1] = 1; xc.ptr.p_double[2] = sa+sb; yc.ptr.p_double[2] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[2] = 0; xc.ptr.p_double[3] = sa+sb; yc.ptr.p_double[3] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[3] = 1; spline1dfitcubicwc(&x, &y, &w, n, &xc, &yc, &dc, k, m, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * Check that constraints are satisfied */ for(i=0; i<=k-1; i++) { spline1ddiff(&c, xc.ptr.p_double[i], &s, &ds, &d2s, _state); if( dc.ptr.p_int[i]==0 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-yc.ptr.p_double[i], _state),threshold); } if( dc.ptr.p_int[i]==1 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(ds-yc.ptr.p_double[i], _state),threshold); } if( dc.ptr.p_int[i]==2 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(d2s-yc.ptr.p_double[i], _state),threshold); } } } } } /* * Cubic splines * Ability to handle one internal constraint */ for(m=4; m<=8; m++) { n = 100; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 1, _state); ae_vector_set_length(&yc, 1, _state); ae_vector_set_length(&dc, 1, _state); sa = 1+ae_randomreal(_state); sb = 2*ae_randomreal(_state)-1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = sa*ae_randomreal(_state)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = sa*ae_randomreal(_state)+sb; yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = ae_randominteger(2, _state); spline1dfitcubicwc(&x, &y, &w, n, &xc, &yc, &dc, 1, m, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * Check that constraints are satisfied */ spline1ddiff(&c, xc.ptr.p_double[0], &s, &ds, &d2s, _state); if( dc.ptr.p_int[0]==0 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-yc.ptr.p_double[0], _state),threshold); } if( dc.ptr.p_int[0]==1 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(ds-yc.ptr.p_double[0], _state),threshold); } if( dc.ptr.p_int[0]==2 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(d2s-yc.ptr.p_double[0], _state),threshold); } } } /* * Hermite splines * Ability to handle boundary constraints (1-4 constraints on F, dF/dx). */ for(m=4; m<=8; m++) { for(k=1; k<=4; k++) { if( k>=m ) { continue; } if( m%2!=0 ) { continue; } n = 100; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 4, _state); ae_vector_set_length(&yc, 4, _state); ae_vector_set_length(&dc, 4, _state); sa = 1+ae_randomreal(_state); sb = 2*ae_randomreal(_state)-1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = sa*ae_randomreal(_state)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = sb; yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = 0; xc.ptr.p_double[1] = sb; yc.ptr.p_double[1] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[1] = 1; xc.ptr.p_double[2] = sa+sb; yc.ptr.p_double[2] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[2] = 0; xc.ptr.p_double[3] = sa+sb; yc.ptr.p_double[3] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[3] = 1; spline1dfithermitewc(&x, &y, &w, n, &xc, &yc, &dc, k, m, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * Check that constraints are satisfied */ for(i=0; i<=k-1; i++) { spline1ddiff(&c, xc.ptr.p_double[i], &s, &ds, &d2s, _state); if( dc.ptr.p_int[i]==0 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-yc.ptr.p_double[i], _state),threshold); } if( dc.ptr.p_int[i]==1 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(ds-yc.ptr.p_double[i], _state),threshold); } if( dc.ptr.p_int[i]==2 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(d2s-yc.ptr.p_double[i], _state),threshold); } } } } } /* * Hermite splines * Ability to handle one internal constraint */ for(m=4; m<=8; m++) { if( m%2!=0 ) { continue; } n = 100; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&xc, 1, _state); ae_vector_set_length(&yc, 1, _state); ae_vector_set_length(&dc, 1, _state); sa = 1+ae_randomreal(_state); sb = 2*ae_randomreal(_state)-1; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = sa*ae_randomreal(_state)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = 1+ae_randomreal(_state); } xc.ptr.p_double[0] = sa*ae_randomreal(_state)+sb; yc.ptr.p_double[0] = 2*ae_randomreal(_state)-1; dc.ptr.p_int[0] = ae_randominteger(2, _state); spline1dfithermitewc(&x, &y, &w, n, &xc, &yc, &dc, 1, m, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { /* * Check that constraints are satisfied */ spline1ddiff(&c, xc.ptr.p_double[0], &s, &ds, &d2s, _state); if( dc.ptr.p_int[0]==0 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-yc.ptr.p_double[0], _state),threshold); } if( dc.ptr.p_int[0]==1 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(ds-yc.ptr.p_double[0], _state),threshold); } if( dc.ptr.p_int[0]==2 ) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(d2s-yc.ptr.p_double[0], _state),threshold); } } } } for(m=4; m<=8; m++) { for(stype=0; stype<=1; stype++) { for(pass=1; pass<=passcount; pass++) { if( stype==1&&m%2!=0 ) { continue; } /* * cubic/Hermite spline fitting: * * generate "template spline" C2 * * generate 2*N points from C2, such that result of * ideal fit should be equal to C2 * * fit, store in C * * compare C and C2 */ sa = 1+ae_randomreal(_state); sb = 2*ae_randomreal(_state)-1; if( stype==0 ) { ae_vector_set_length(&x, m-2, _state); ae_vector_set_length(&y, m-2, _state); for(i=0; i<=m-2-1; i++) { x.ptr.p_double[i] = sa*i/(m-2-1)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } spline1dbuildcubic(&x, &y, m-2, 1, 2*ae_randomreal(_state)-1, 1, 2*ae_randomreal(_state)-1, &c2, _state); } if( stype==1 ) { ae_vector_set_length(&x, m/2, _state); ae_vector_set_length(&y, m/2, _state); ae_vector_set_length(&d, m/2, _state); for(i=0; i<=m/2-1; i++) { x.ptr.p_double[i] = sa*i/(m/2-1)+sb; y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } spline1dbuildhermite(&x, &y, &d, m/2, &c2, _state); } n = 50; ae_vector_set_length(&x, 2*n, _state); ae_vector_set_length(&y, 2*n, _state); ae_vector_set_length(&w, 2*n, _state); for(i=0; i<=n-1; i++) { /* * "if i=0" and "if i=1" are needed to * synchronize interval size for C2 and * spline being fitted (i.e. C). */ t = ae_randomreal(_state); x.ptr.p_double[i] = sa*ae_randomreal(_state)+sb; if( i==0 ) { x.ptr.p_double[i] = sb; } if( i==1 ) { x.ptr.p_double[i] = sa+sb; } v = spline1dcalc(&c2, x.ptr.p_double[i], _state); y.ptr.p_double[i] = v+t; w.ptr.p_double[i] = 1+ae_randomreal(_state); x.ptr.p_double[n+i] = x.ptr.p_double[i]; y.ptr.p_double[n+i] = v-t; w.ptr.p_double[n+i] = w.ptr.p_double[i]; } info = -1; if( stype==0 ) { spline1dfitcubicwc(&x, &y, &w, 2*n, &xc, &yc, &dc, 0, m, &info, &c, &rep, _state); } if( stype==1 ) { spline1dfithermitewc(&x, &y, &w, 2*n, &xc, &yc, &dc, 0, m, &info, &c, &rep, _state); } if( info<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=n-1; i++) { v = sa*ae_randomreal(_state)+sb; *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(spline1dcalc(&c, v, _state)-spline1dcalc(&c2, v, _state), _state),threshold); } } } } } for(m=4; m<=8; m++) { for(pass=1; pass<=passcount; pass++) { /* * prepare points/weights */ n = 10+ae_randominteger(10, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = i+(ae_randomreal(_state)-0.5); y.ptr.p_double[i] = 2*ae_randomreal(_state)-1; w.ptr.p_double[i] = (double)(1); } /* * Fit cubic with unity weights, without weights, then compare */ if( m>=4 ) { spline1dfitcubicwc(&x, &y, &w, n, &xc, &yc, &dc, 0, m, &info1, &c, &rep, _state); spline1dfitcubic(&x, &y, n, m, &info2, &c2, &rep2, _state); if( info1<=0||info2<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=n-1; i++) { v = ae_randomreal(_state)*(n-1); *fiterrors = *fiterrors||!approxequalrel(spline1dcalc(&c, v, _state), spline1dcalc(&c2, v, _state), threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.taskrcond, rep2.taskrcond, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.rmserror, rep2.rmserror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgerror, rep2.avgerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgrelerror, rep2.avgrelerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.maxerror, rep2.maxerror, threshold, _state); } } } /* * Fit Hermite with unity weights, without weights, then compare */ if( m>=4&&m%2==0 ) { spline1dfithermitewc(&x, &y, &w, n, &xc, &yc, &dc, 0, m, &info1, &c, &rep, _state); spline1dfithermite(&x, &y, n, m, &info2, &c2, &rep2, _state); if( info1<=0||info2<=0 ) { *fiterrors = ae_true; } else { for(i=0; i<=n-1; i++) { v = ae_randomreal(_state)*(n-1); *fiterrors = *fiterrors||!approxequalrel(spline1dcalc(&c, v, _state), spline1dcalc(&c2, v, _state), threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.taskrcond, rep2.taskrcond, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.rmserror, rep2.rmserror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgerror, rep2.avgerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.avgrelerror, rep2.avgrelerror, threshold, _state); *fiterrors = *fiterrors||!approxequalrel(rep.maxerror, rep2.maxerror, threshold, _state); } } } } } /* * check basic properties of penalized splines which are * preserved independently of Rho parameter. */ for(m=4; m<=10; m++) { for(k=-5; k<=5; k++) { rho = (double)(k); /* * when we have two points (even with different weights), * resulting spline must be equal to the straight line */ ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&y, 2, _state); ae_vector_set_length(&w, 2, _state); x.ptr.p_double[0] = -0.5-ae_randomreal(_state); y.ptr.p_double[0] = 0.5+ae_randomreal(_state); w.ptr.p_double[0] = 1+ae_randomreal(_state); x.ptr.p_double[1] = 0.5+ae_randomreal(_state); y.ptr.p_double[1] = 0.5+ae_randomreal(_state); w.ptr.p_double[1] = 1+ae_randomreal(_state); spline1dfitpenalized(&x, &y, 2, m, rho, &info, &c, &rep, _state); if( info>0 ) { v = 2*ae_randomreal(_state)-1; v1 = (v-x.ptr.p_double[0])/(x.ptr.p_double[1]-x.ptr.p_double[0])*y.ptr.p_double[1]+(v-x.ptr.p_double[1])/(x.ptr.p_double[0]-x.ptr.p_double[1])*y.ptr.p_double[0]; *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v1-spline1dcalc(&c, v, _state), _state),nonstrictthreshold); } else { *fiterrors = ae_true; } spline1dfitpenalizedw(&x, &y, &w, 2, m, rho, &info, &c, &rep, _state); if( info>0 ) { v = 2*ae_randomreal(_state)-1; v1 = (v-x.ptr.p_double[0])/(x.ptr.p_double[1]-x.ptr.p_double[0])*y.ptr.p_double[1]+(v-x.ptr.p_double[1])/(x.ptr.p_double[0]-x.ptr.p_double[1])*y.ptr.p_double[0]; *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v1-spline1dcalc(&c, v, _state), _state),nonstrictthreshold); } else { *fiterrors = ae_true; } /* * spline fitting is invariant with respect to * scaling of weights (of course, ANY fitting algorithm * must be invariant, but we want to test this property * just to be sure that it is correctly implemented) */ for(n=2; n<=2*m; n++) { ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); ae_vector_set_length(&w2, n, _state); s = 1+ae_exp(10*ae_randomreal(_state), _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)i/(double)(n-1); y.ptr.p_double[i] = ae_randomreal(_state); w.ptr.p_double[i] = 0.1+ae_randomreal(_state); w2.ptr.p_double[i] = w.ptr.p_double[i]*s; } spline1dfitpenalizedw(&x, &y, &w, n, m, rho, &info, &c, &rep, _state); spline1dfitpenalizedw(&x, &y, &w2, n, m, rho, &info2, &c2, &rep2, _state); if( info>0&&info2>0 ) { v = ae_randomreal(_state); v1 = spline1dcalc(&c, v, _state); v2 = spline1dcalc(&c2, v, _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(v1-v2, _state),nonstrictthreshold); } else { *fiterrors = ae_true; } } } } /* * Advanced proprties: * * penalized spline with M about 5*N and sufficiently small Rho * must pass through all points on equidistant grid */ for(n=2; n<=10; n++) { m = 5*n; rho = (double)(-5); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)i/(double)(n-1); y.ptr.p_double[i] = ae_randomreal(_state); w.ptr.p_double[i] = 0.1+ae_randomreal(_state); } spline1dfitpenalized(&x, &y, n, m, rho, &info, &c, &rep, _state); if( info>0 ) { for(i=0; i<=n-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state),nonstrictthreshold); } } else { *fiterrors = ae_true; } spline1dfitpenalizedw(&x, &y, &w, n, m, rho, &info, &c, &rep, _state); if( info>0 ) { for(i=0; i<=n-1; i++) { *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(y.ptr.p_double[i]-spline1dcalc(&c, x.ptr.p_double[i], _state), _state),nonstrictthreshold); } } else { *fiterrors = ae_true; } } /* * Check correctness of error reports */ for(pass=1; pass<=passcount; pass++) { ae_assert(passcount>=2, "PassCount should be 2 or greater!", _state); /* * solve simple task (all X[] are the same, Y[] are specially * calculated to ensure simple form of all types of errors) * and check correctness of the errors calculated by subroutines * * First pass is done with zero Y[], other passes - with random Y[]. * It should test both ability to correctly calculate errors and * ability to not fail while working with zeros :) */ n = 4; if( pass==1 ) { v1 = (double)(0); v2 = (double)(0); v = (double)(0); } else { v1 = ae_randomreal(_state); v2 = ae_randomreal(_state); v = 1+ae_randomreal(_state); } ae_vector_set_length(&x, 4, _state); ae_vector_set_length(&y, 4, _state); ae_vector_set_length(&w, 4, _state); x.ptr.p_double[0] = (double)(0); y.ptr.p_double[0] = v-v2; w.ptr.p_double[0] = (double)(1); x.ptr.p_double[1] = (double)(0); y.ptr.p_double[1] = v-v1; w.ptr.p_double[1] = (double)(1); x.ptr.p_double[2] = (double)(0); y.ptr.p_double[2] = v+v1; w.ptr.p_double[2] = (double)(1); x.ptr.p_double[3] = (double)(0); y.ptr.p_double[3] = v+v2; w.ptr.p_double[3] = (double)(1); refrms = ae_sqrt((ae_sqr(v1, _state)+ae_sqr(v2, _state))/2, _state); refavg = (ae_fabs(v1, _state)+ae_fabs(v2, _state))/2; if( pass==1 ) { refavgrel = (double)(0); } else { refavgrel = 0.25*(ae_fabs(v2, _state)/ae_fabs(v-v2, _state)+ae_fabs(v1, _state)/ae_fabs(v-v1, _state)+ae_fabs(v1, _state)/ae_fabs(v+v1, _state)+ae_fabs(v2, _state)/ae_fabs(v+v2, _state)); } refmax = ae_maxreal(v1, v2, _state); /* * Test penalized spline */ spline1dfitpenalizedw(&x, &y, &w, 4, 4, 0.0, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { s = spline1dcalc(&c, (double)(0), _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-v, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } /* * Test cubic fitting */ spline1dfitcubic(&x, &y, 4, 4, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { s = spline1dcalc(&c, (double)(0), _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-v, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } /* * Test Hermite fitting */ spline1dfithermite(&x, &y, 4, 4, &info, &c, &rep, _state); if( info<=0 ) { *fiterrors = ae_true; } else { s = spline1dcalc(&c, (double)(0), _state); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(s-v, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *fiterrors = *fiterrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } } ae_frame_leave(_state); } static void testlsfitunit_testgeneralfitting(ae_bool* llserrors, ae_bool* nlserrors, ae_state *_state) { ae_frame _frame_block; double threshold; double nlthreshold; ae_int_t maxn; ae_int_t maxm; ae_int_t skind; ae_int_t pkind; ae_int_t passcount; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t pass; double xscale; double cscale; double wscale; double noiselevel; double tol; double diffstep; ae_vector x; ae_vector y; ae_vector y2; ae_vector w; ae_vector w2; ae_vector s; ae_vector c; ae_vector cstart; ae_vector cend; ae_vector c2; ae_matrix a; ae_matrix a2; ae_matrix cm; double v; double v1; double v2; lsfitreport rep; lsfitreport rep2; ae_int_t info; ae_int_t info2; double refrms; double refavg; double refavgrel; double refmax; double avgdeviationpar; double avgdeviationcurve; double avgdeviationnoise; double adccnt; double adpcnt; double adncnt; lsfitstate state; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&w2, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&cstart, 0, DT_REAL, _state); ae_vector_init(&cend, 0, DT_REAL, _state); ae_vector_init(&c2, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&a2, 0, 0, DT_REAL, _state); ae_matrix_init(&cm, 0, 0, DT_REAL, _state); _lsfitreport_init(&rep, _state); _lsfitreport_init(&rep2, _state); _lsfitstate_init(&state, _state); *llserrors = ae_false; *nlserrors = ae_false; threshold = 10000*ae_machineepsilon; nlthreshold = 0.00001; diffstep = 0.0001; maxn = 6; maxm = 6; passcount = 4; /* * Testing unconstrained least squares (linear/nonlinear) */ for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { for(pass=1; pass<=passcount; pass++) { /* * Solve non-degenerate linear least squares task * Use Chebyshev basis. Its condition number is very good. */ ae_matrix_set_length(&a, n, m, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); xscale = 0.9+0.1*ae_randomreal(_state); for(i=0; i<=n-1; i++) { if( n==1 ) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { x.ptr.p_double[i] = xscale*((double)(2*i)/(double)(n-1)-1); } y.ptr.p_double[i] = 3*x.ptr.p_double[i]+ae_exp(x.ptr.p_double[i], _state); w.ptr.p_double[i] = 1+ae_randomreal(_state); a.ptr.pp_double[i][0] = (double)(1); if( m>1 ) { a.ptr.pp_double[i][1] = x.ptr.p_double[i]; } for(j=2; j<=m-1; j++) { a.ptr.pp_double[i][j] = 2*x.ptr.p_double[i]*a.ptr.pp_double[i][j-1]-a.ptr.pp_double[i][j-2]; } } /* * 1. test weighted fitting (optimality) * 2. Solve degenerate least squares task built on the basis * of previous task */ lsfitlinearw(&y, &w, &a, n, m, &info, &c, &rep, _state); if( info<=0 ) { *llserrors = ae_true; } else { *llserrors = *llserrors||!testlsfitunit_isglssolution(n, m, 0, &y, &w, &a, &cm, &c, _state); } ae_matrix_set_length(&a2, n, 2*m, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { a2.ptr.pp_double[i][2*j+0] = a.ptr.pp_double[i][j]; a2.ptr.pp_double[i][2*j+1] = a.ptr.pp_double[i][j]; } } lsfitlinearw(&y, &w, &a2, n, 2*m, &info, &c2, &rep, _state); if( info<=0 ) { *llserrors = ae_true; } else { /* * test answer correctness using design matrix properties * and previous task solution */ for(j=0; j<=m-1; j++) { *llserrors = *llserrors||ae_fp_greater(ae_fabs(c2.ptr.p_double[2*j+0]+c2.ptr.p_double[2*j+1]-c.ptr.p_double[j], _state),threshold); } } /* * test non-weighted fitting */ ae_vector_set_length(&w2, n, _state); for(i=0; i<=n-1; i++) { w2.ptr.p_double[i] = (double)(1); } lsfitlinearw(&y, &w2, &a, n, m, &info, &c, &rep, _state); lsfitlinear(&y, &a, n, m, &info2, &c2, &rep2, _state); if( info<=0||info2<=0 ) { *llserrors = ae_true; } else { /* * test answer correctness */ for(j=0; j<=m-1; j++) { *llserrors = *llserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[j]-c2.ptr.p_double[j], _state),threshold); } *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.taskrcond-rep2.taskrcond, _state),threshold); } /* * test nonlinear fitting on the linear task * (only non-degenerate tasks are tested) * and compare with answer from linear fitting subroutine */ if( n>=m ) { ae_vector_set_length(&c2, m, _state); /* * test function/gradient/Hessian-based weighted fitting */ lsfitlinearw(&y, &w, &a, n, m, &info, &c, &rep, _state); for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatewf(&a, &y, &w, &c2, n, m, m, diffstep, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 0, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatewfg(&a, &y, &w, &c2, n, m, m, ae_fp_greater(ae_randomreal(_state),0.5), &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 1, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatewfgh(&a, &y, &w, &c2, n, m, m, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 2, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } /* * test gradient-only or Hessian-based fitting without weights */ lsfitlinear(&y, &a, n, m, &info, &c, &rep, _state); for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatef(&a, &y, &c2, n, m, m, diffstep, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 0, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatefg(&a, &y, &c2, n, m, m, ae_fp_greater(ae_randomreal(_state),0.5), &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 1, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } for(i=0; i<=m-1; i++) { c2.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lsfitcreatefgh(&a, &y, &c2, n, m, m, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); testlsfitunit_fitlinearnonlinear(m, 2, &a, &state, nlserrors, _state); lsfitresults(&state, &info, &c2, &rep2, _state); if( info<=0 ) { *nlserrors = ae_true; } else { for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[i]-c2.ptr.p_double[i], _state),100*nlthreshold); } } } } } /* * test correctness of the RCond field */ ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, n-1+1, _state); ae_vector_set_length(&w, n-1+1, _state); v1 = ae_maxrealnumber; v2 = ae_minrealnumber; for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = 0.1+0.9*ae_randomreal(_state); y.ptr.p_double[i] = 0.1+0.9*ae_randomreal(_state); w.ptr.p_double[i] = (double)(1); for(j=0; j<=n-1; j++) { if( i==j ) { a.ptr.pp_double[i][i] = 0.1+0.9*ae_randomreal(_state); v1 = ae_minreal(v1, a.ptr.pp_double[i][i], _state); v2 = ae_maxreal(v2, a.ptr.pp_double[i][i], _state); } else { a.ptr.pp_double[i][j] = (double)(0); } } } lsfitlinearw(&y, &w, &a, n, n, &info, &c, &rep, _state); if( info<=0 ) { *llserrors = ae_true; } else { *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.taskrcond-v1/v2, _state),threshold); } } /* * Test constrained least squares */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(m=1; m<=maxm; m++) { /* * test for K<>0 */ for(k=1; k<=m-1; k++) { /* * Prepare Chebyshev basis. Its condition number is very good. * Prepare constraints (random numbers) */ ae_matrix_set_length(&a, n, m, _state); ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); ae_vector_set_length(&w, n, _state); xscale = 0.9+0.1*ae_randomreal(_state); for(i=0; i<=n-1; i++) { if( n==1 ) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } else { x.ptr.p_double[i] = xscale*((double)(2*i)/(double)(n-1)-1); } y.ptr.p_double[i] = 3*x.ptr.p_double[i]+ae_exp(x.ptr.p_double[i], _state); w.ptr.p_double[i] = 1+ae_randomreal(_state); a.ptr.pp_double[i][0] = (double)(1); if( m>1 ) { a.ptr.pp_double[i][1] = x.ptr.p_double[i]; } for(j=2; j<=m-1; j++) { a.ptr.pp_double[i][j] = 2*x.ptr.p_double[i]*a.ptr.pp_double[i][j-1]-a.ptr.pp_double[i][j-2]; } } ae_matrix_set_length(&cm, k, m+1, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=m; j++) { cm.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } /* * Solve constrained task */ lsfitlinearwc(&y, &w, &a, &cm, n, m, k, &info, &c, &rep, _state); if( info<=0 ) { *llserrors = ae_true; } else { *llserrors = *llserrors||!testlsfitunit_isglssolution(n, m, k, &y, &w, &a, &cm, &c, _state); } /* * test non-weighted fitting */ ae_vector_set_length(&w2, n, _state); for(i=0; i<=n-1; i++) { w2.ptr.p_double[i] = (double)(1); } lsfitlinearwc(&y, &w2, &a, &cm, n, m, k, &info, &c, &rep, _state); lsfitlinearc(&y, &a, &cm, n, m, k, &info2, &c2, &rep2, _state); if( info<=0||info2<=0 ) { *llserrors = ae_true; } else { /* * test answer correctness */ for(j=0; j<=m-1; j++) { *llserrors = *llserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[j]-c2.ptr.p_double[j], _state),threshold); } *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.taskrcond-rep2.taskrcond, _state),threshold); } } } } } /* * nonlinear task for nonlinear fitting: * * f(X,C) = 1/(1+C*X^2), * C(true) = 2. */ n = 100; ae_vector_set_length(&c, 1, _state); c.ptr.p_double[0] = 1+2*ae_randomreal(_state); ae_matrix_set_length(&a, n, 1, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][0] = 4*ae_randomreal(_state)-2; y.ptr.p_double[i] = 1/(1+2*ae_sqr(a.ptr.pp_double[i][0], _state)); } lsfitcreatefg(&a, &y, &c, n, 1, 1, ae_true, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); while(lsfititeration(&state, _state)) { if( state.needf ) { state.f = 1/(1+state.c.ptr.p_double[0]*ae_sqr(state.x.ptr.p_double[0], _state)); } if( state.needfg ) { state.f = 1/(1+state.c.ptr.p_double[0]*ae_sqr(state.x.ptr.p_double[0], _state)); state.g.ptr.p_double[0] = -ae_sqr(state.x.ptr.p_double[0], _state)/ae_sqr(1+state.c.ptr.p_double[0]*ae_sqr(state.x.ptr.p_double[0], _state), _state); } } lsfitresults(&state, &info, &c, &rep, _state); if( info<=0 ) { *nlserrors = ae_true; } else { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[0]-2, _state),100*nlthreshold); } /* * solve simple task (fitting by constant function) and check * correctness of the errors calculated by subroutines */ for(pass=1; pass<=passcount; pass++) { /* * test on task with non-zero Yi */ n = 4; v1 = ae_randomreal(_state); v2 = ae_randomreal(_state); v = 1+ae_randomreal(_state); ae_vector_set_length(&c, 1, _state); c.ptr.p_double[0] = 1+2*ae_randomreal(_state); ae_matrix_set_length(&a, 4, 1, _state); ae_vector_set_length(&y, 4, _state); a.ptr.pp_double[0][0] = (double)(1); y.ptr.p_double[0] = v-v2; a.ptr.pp_double[1][0] = (double)(1); y.ptr.p_double[1] = v-v1; a.ptr.pp_double[2][0] = (double)(1); y.ptr.p_double[2] = v+v1; a.ptr.pp_double[3][0] = (double)(1); y.ptr.p_double[3] = v+v2; refrms = ae_sqrt((ae_sqr(v1, _state)+ae_sqr(v2, _state))/2, _state); refavg = (ae_fabs(v1, _state)+ae_fabs(v2, _state))/2; refavgrel = 0.25*(ae_fabs(v2, _state)/ae_fabs(v-v2, _state)+ae_fabs(v1, _state)/ae_fabs(v-v1, _state)+ae_fabs(v1, _state)/ae_fabs(v+v1, _state)+ae_fabs(v2, _state)/ae_fabs(v+v2, _state)); refmax = ae_maxreal(v1, v2, _state); /* * Test LLS */ lsfitlinear(&y, &a, 4, 1, &info, &c, &rep, _state); if( info<=0 ) { *llserrors = ae_true; } else { *llserrors = *llserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[0]-v, _state),threshold); *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *llserrors = *llserrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } /* * Test NLS */ lsfitcreatefg(&a, &y, &c, 4, 1, 1, ae_true, &state, _state); lsfitsetcond(&state, 0.0, nlthreshold, 0, _state); while(lsfititeration(&state, _state)) { if( state.needf ) { state.f = state.c.ptr.p_double[0]; } if( state.needfg ) { state.f = state.c.ptr.p_double[0]; state.g.ptr.p_double[0] = (double)(1); } } lsfitresults(&state, &info, &c, &rep, _state); if( info<=0 ) { *nlserrors = ae_true; } else { *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(c.ptr.p_double[0]-v, _state),threshold); *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(rep.rmserror-refrms, _state),threshold); *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(rep.avgerror-refavg, _state),threshold); *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(rep.avgrelerror-refavgrel, _state),threshold); *nlserrors = *nlserrors||ae_fp_greater(ae_fabs(rep.maxerror-refmax, _state),threshold); } } /* * Check covariance matrix, errors-in-parameters. * * We test three different solvers: * * nonlinear solver * * unconstrained linear solver * * constrained linear solver with empty set of constrains * on two random problems: * * problem with known prior, noise, unit weights * * problem with known prior, noise, non-unit weights * * We test that: * * rep.ErrPar=sqrt(diag(Rep.CovPar)) * * Rep.ErrPar is not too optimistic - average value of ratio * between |c_fit-c_prior| and ErrPar[] is less than TOL * * Rep.ErrPar is not too pessimistic - average value of ratio * is larger than 1/TOL * * similarly, Rep.ErrCurve gives good estimate of |A*c_fit - A*c_prior| * - not optimistic, not pessimistic. * * similarly, per-point noise estimates are good enough (we use * slightly different tolerances, though) * In order to have these estimates we perform many different tests * and calculate average deviation divided by ErrPar/ErrCurve. Then * we perform test. * * Due to stochastic nature of the test it is not good idea to * consider each case individually - it is better to average over * many runs. * */ tol = 10.0; for(n=1; n<=10; n++) { for(skind=0; skind<=2; skind++) { for(pkind=0; pkind<=1; pkind++) { /* * Generate problem: * * PKind=0 - unit weights * * PKind=1 - non-unit weights, exact estimate of noise at I-th point * * We generate: * * C - prior values of parameters * * CStart - random initial point * * A - function matrix * * Y - noisy version of A*C * * W - weights vector * * S - vector of per-point estimates of noise */ cscale = ae_pow(10.0, 2*randomnormal(_state), _state); xscale = ae_pow(10.0, 2*randomnormal(_state), _state); noiselevel = 0.01*cscale*xscale; ae_vector_set_length(&c, n, _state); ae_vector_set_length(&cstart, n, _state); for(i=0; i<=n-1; i++) { c.ptr.p_double[i] = cscale*randomnormal(_state); cstart.ptr.p_double[i] = cscale*randomnormal(_state); } ae_matrix_set_length(&a, 1000, n, _state); ae_vector_set_length(&y, a.rows, _state); ae_vector_set_length(&w, a.rows, _state); ae_vector_set_length(&s, a.rows, _state); for(i=0; i<=a.rows-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = xscale*randomnormal(_state); } v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( pkind==0 ) { w.ptr.p_double[i] = (double)(1); s.ptr.p_double[i] = noiselevel; y.ptr.p_double[i] = v+s.ptr.p_double[i]*randomnormal(_state); } if( pkind==1 ) { w.ptr.p_double[i] = 1/noiselevel; s.ptr.p_double[i] = noiselevel; y.ptr.p_double[i] = v+s.ptr.p_double[i]*randomnormal(_state); } } /* * Test different solvers: * * SKind=0 - nonlinear solver * * SKind=1 - linear unconstrained * * SKind=2 - linear constrained with empty set of constraints */ info = -1; if( skind==0 ) { if( ae_fp_greater(ae_randomreal(_state),0.5) ) { lsfitcreatefg(&a, &y, &cstart, a.rows, n, n, ae_true, &state, _state); } else { lsfitcreatef(&a, &y, &cstart, a.rows, n, n, 0.001*cscale, &state, _state); } lsfitsetcond(&state, 0.0, 0.0, 10, _state); while(lsfititeration(&state, _state)) { if( state.needf ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.c.ptr.p_double[i]*state.x.ptr.p_double[i]; } } if( state.needfg ) { state.f = (double)(0); for(i=0; i<=n-1; i++) { state.f = state.f+state.c.ptr.p_double[i]*state.x.ptr.p_double[i]; state.g.ptr.p_double[i] = state.x.ptr.p_double[i]; } } } lsfitresults(&state, &info, &cend, &rep, _state); } if( skind==1 ) { if( pkind==0 ) { lsfitlinear(&y, &a, a.rows, n, &info, &cend, &rep, _state); } else { lsfitlinearw(&y, &w, &a, a.rows, n, &info, &cend, &rep, _state); } } if( skind==2 ) { if( pkind==0 ) { lsfitlinearc(&y, &a, &a2, a.rows, n, 0, &info, &cend, &rep, _state); } else { lsfitlinearwc(&y, &w, &a, &a2, a.rows, n, 0, &info, &cend, &rep, _state); } } /* * Tests: * * check relation between CovPar and ErrPar * * accumulate average deviation in parameters * * accumulate average deviation in curve fit * * accumulate average deviation in noise estimate */ avgdeviationpar = (double)(0); adpcnt = (double)(0); avgdeviationcurve = (double)(0); adccnt = (double)(0); avgdeviationnoise = (double)(0); adncnt = (double)(0); for(i=0; i<=n-1; i++) { seterrorflag(llserrors, ae_fp_greater(ae_fabs(rep.covpar.ptr.pp_double[i][i]-ae_sqr(rep.errpar.ptr.p_double[i], _state), _state),100*ae_machineepsilon*ae_maxreal(ae_sqr(rep.errpar.ptr.p_double[i], _state), rep.covpar.ptr.pp_double[i][i], _state)), _state); } for(i=0; i<=n-1; i++) { avgdeviationpar = (avgdeviationpar*adpcnt+ae_fabs(c.ptr.p_double[i]-cend.ptr.p_double[i], _state)/rep.errpar.ptr.p_double[i])/(adpcnt+1); adpcnt = adpcnt+1; } for(i=0; i<=a.rows-1; i++) { v1 = ae_v_dotproduct(&c.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v2 = ae_v_dotproduct(&cend.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); avgdeviationcurve = (avgdeviationcurve*adccnt+ae_fabs(v1-v2, _state)/rep.errcurve.ptr.p_double[i])/(adccnt+1); adccnt = adccnt+1; avgdeviationnoise = (avgdeviationnoise*adncnt+rep.noise.ptr.p_double[i]/s.ptr.p_double[i])/(adncnt+1); adncnt = adncnt+1; } /* * Check that estimates are not too optimistic. * This test is performed always. */ seterrorflag(llserrors, ae_fp_greater(avgdeviationpar,tol), _state); seterrorflag(llserrors, ae_fp_greater(avgdeviationcurve,tol), _state); seterrorflag(llserrors, ae_fp_greater(avgdeviationnoise,1.50), _state); seterrorflag(llserrors, ae_fp_less(avgdeviationnoise,0.66), _state); /* * Test for estimates being too pessimistic is performed only * when we have more than 4 parameters. */ seterrorflag(llserrors, n>=5&&ae_fp_less(avgdeviationcurve,0.01), _state); seterrorflag(llserrors, n>=5&&ae_fp_less(avgdeviationpar,0.01), _state); } } } /* * Check special property of the LSFit solver: it does not include points with * zero weight in the estimate of the noise level. Such property seems to be * quite natural, but in fact it requires some additional code in order to * ignore such points. * * In order to test it we solve two problems: one 300xN, with 150 non-zero * weights and 150 zero weights - and another one with only 150 points with * non-zero weights. Both problems should give us same covariance matrix. */ tol = (double)(10); for(n=1; n<=10; n++) { /* * Generate N-dimensional linear problem with 300 points: * * y = c'*x + noise * * prior values of coefficients C has scale CScale * * coordinates X has scale XScale * * noise in I-th point has magnitude 0.1*CScale*XScale*WScale/W[i] */ cscale = ae_pow(10.0, 2*randomnormal(_state), _state); xscale = ae_pow(10.0, 2*randomnormal(_state), _state); wscale = ae_pow(10.0, 2*randomnormal(_state), _state); noiselevel = 0.1*cscale*xscale; ae_vector_set_length(&c, n, _state); ae_vector_set_length(&cstart, n, _state); for(i=0; i<=n-1; i++) { c.ptr.p_double[i] = cscale*randomnormal(_state); cstart.ptr.p_double[i] = cscale*randomnormal(_state); } ae_matrix_set_length(&a, 300, n, _state); ae_vector_set_length(&y, a.rows, _state); ae_vector_set_length(&w, a.rows, _state); for(i=0; i<=a.rows-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = xscale*randomnormal(_state); } v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,n-1)); if( i0 and NZ<>0, but in * some cases either N or NZ (but not both) is zero. * * X-values have scale equal to ScaleX */ scalex = ae_pow((double)(10), 30*hqrnduniformr(&rs, _state)-15, _state); n = 40+hqrnduniformi(&rs, 40, _state); nz = 4+hqrnduniformi(&rs, 4, _state); if( ae_fp_less(hqrnduniformr(&rs, _state),0.1) ) { if( ae_fp_less(hqrnduniformr(&rs, _state),0.5) ) { n = 0; } else { nz = 0; } } ntotal = 2*(n+nz); ae_vector_set_length(&x, ntotal, _state); for(i=0; i<=n-1; i++) { v = scalex*ae_exp(ae_log((double)(5), _state)*(2*hqrnduniformr(&rs, _state)-1), _state); x.ptr.p_double[2*i+0] = v; x.ptr.p_double[2*i+1] = v; } for(i=0; i<=nz-1; i++) { x.ptr.p_double[2*n+2*i+0] = (double)(0); x.ptr.p_double[2*n+2*i+1] = (double)(0); } /* * Fenerate A/B/C/D: * * A/D are random with scale equal to ScaleY * * B is in [0.25,4.0] (always positive) * * for C we choose one of X[], if N>0; * if N=0, we set C=1. */ scaley = ae_pow((double)(10), 30*hqrnduniformr(&rs, _state)-15, _state); ae = scaley*(hqrnduniformr(&rs, _state)-0.5); be = ae_exp(ae_log((double)(4), _state)*(2*hqrnduniformr(&rs, _state)-1), _state); ce = scalex*ae_exp(ae_log((double)(2), _state)*(2*hqrnduniformr(&rs, _state)-1), _state); de = ae+scaley*(2*hqrnduniformi(&rs, 2, _state)-1)*(hqrnduniformr(&rs, _state)+0.5); /* * Choose noise level and generate Y[]. */ noise = 0.05*scaley; ae_vector_set_length(&y, ntotal, _state); for(i=0; i<=ntotal/2-1; i++) { if( ae_fp_neq(x.ptr.p_double[2*i+0],(double)(0)) ) { v = de+(ae-de)/(1.0+ae_pow(x.ptr.p_double[2*i+0]/ce, be, _state)); } else { v = ae; } y.ptr.p_double[2*i+0] = v+noise; y.ptr.p_double[2*i+1] = v-noise; } /* * Unconstrained fit and test * * NOTE: we test that B>=0 is returned. If BE<0, we use * symmetry property of 4PL model. */ logisticfit4(&x, &y, ntotal, &a, &b, &c, &d, &rep, _state); seterrorflag(fiterrors, !ae_isfinite(a, _state), _state); seterrorflag(fiterrors, !ae_isfinite(b, _state), _state); seterrorflag(fiterrors, !ae_isfinite(c, _state), _state); seterrorflag(fiterrors, !ae_isfinite(d, _state), _state); seterrorflag(fiterrors, ae_fp_less(b,(double)(0)), _state); v = 0.0; for(i=0; i<=ntotal-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { vv = d+(a-d)/(1.0+ae_pow(x.ptr.p_double[i]/c, b, _state)); } else { vv = a; } v = v+ae_sqr(y.ptr.p_double[i]-vv, _state); } v = ae_sqrt(v/ntotal, _state); seterrorflag(fiterrors, ae_fp_greater(v,(1+tol)*noise), _state); /* * Constrained fit and test * * NOTE: we test that B>=0 is returned. If BE<0, we use * symmetry property of 4PL model. */ for(k0=0; k0<=1; k0++) { for(k1=0; k1<=1; k1++) { /* * Choose constraints. */ if( k0==0 ) { v0 = _state->v_nan; } else { v0 = ae; } if( k1==0 ) { v1 = _state->v_nan; } else { v1 = de; } /* * Fit */ logisticfit4ec(&x, &y, ntotal, v0, v1, &a, &b, &c, &d, &rep, _state); /* * Check */ seterrorflag(fiterrors, !ae_isfinite(a, _state), _state); seterrorflag(fiterrors, !ae_isfinite(b, _state), _state); seterrorflag(fiterrors, !ae_isfinite(c, _state), _state); seterrorflag(fiterrors, !ae_isfinite(d, _state), _state); seterrorflag(fiterrors, ae_fp_less(b,(double)(0)), _state); seterrorflag(fiterrors, k0!=0&&ae_fp_neq(a,v0), _state); seterrorflag(fiterrors, k1!=0&&ae_fp_neq(d,v1), _state); v = 0.0; for(i=0; i<=ntotal-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { vv = d+(a-d)/(1.0+ae_pow(x.ptr.p_double[i]/c, b, _state)); } else { if( ae_fp_greater_eq(b,(double)(0)) ) { vv = a; } else { vv = d; } } v = v+ae_sqr(y.ptr.p_double[i]-vv, _state); } v = ae_sqrt(v/ntotal, _state); seterrorflag(fiterrors, ae_fp_greater(v,(1+tol)*noise), _state); } } } /* * 5PL fitting * * Generate random AE/BE/CE/DE/GE, generate random set of points and for * each point generate two function values: F(x)+eps and F(x)-eps. * Such problem has solution which is exactly AE/BE/CE/DE which were * used to generate points. * * NOTE: because problem has higher condition number, we use lower * tolerance for power parameters B and G. * * This test checks both unconstrained and constrained fitting. */ tol = 0.01; for(pass=1; pass<=100; pass++) { /* * Generate N points, N-1 of them with non-zero X and * last one with zero X. * X-values have scale equal to ScaleX */ scalex = ae_pow((double)(10), 30*hqrnduniformr(&rs, _state)-15, _state); n = 22; ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = scalex*ae_pow((double)(2), (double)(i-10), _state); } x.ptr.p_double[n-1] = (double)(0); /* * Generate A/B/C/D/G: * * A/D are random with scale equal to ScaleY * * B is in +-[0.25,4.0] * * G is in [0.25,4.0] * * C is in [0.25,4.0]*ScaleX * if N=0, we set C=1. * Generate Y[]. */ scaley = ae_pow((double)(10), 30*hqrnduniformr(&rs, _state)-15, _state); ae = scaley*(hqrnduniformr(&rs, _state)-0.5); be = (2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(ae_log((double)(4), _state)*(2*hqrnduniformr(&rs, _state)-1), _state); ce = scalex*ae_exp(ae_log((double)(5), _state)*(2*hqrnduniformr(&rs, _state)-1), _state); de = ae+scaley*(2*hqrnduniformi(&rs, 2, _state)-1)*(hqrnduniformr(&rs, _state)+0.5); ge = ae_exp(ae_log(1.5, _state)*(2*hqrnduniformr(&rs, _state)-1), _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { v = de+(ae-de)/ae_pow(1.0+ae_pow(x.ptr.p_double[i]/ce, be, _state), ge, _state); } else { if( ae_fp_greater_eq(be,(double)(0)) ) { v = ae; } else { v = de; } } y.ptr.p_double[i] = v; } /* * Unconstrained fit and test * * NOTE: we test that B>=0 is returned. If BE<0, we use * symmetry property of 4PL model. */ logisticfit5(&x, &y, n, &a, &b, &c, &d, &g, &rep, _state); v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { vv = d+(a-d)/ae_pow(1.0+ae_pow(x.ptr.p_double[i]/c, b, _state), g, _state); } else { if( ae_fp_greater_eq(b,(double)(0)) ) { vv = a; } else { vv = d; } } v = v+ae_sqr(y.ptr.p_double[i]-vv, _state); } v = ae_sqrt(v/n, _state); seterrorflag(fiterrors, ae_fp_greater(v,scaley*1.0E-6), _state); /* * Constrained fit and test */ for(k0=0; k0<=1; k0++) { for(k1=0; k1<=1; k1++) { /* * Choose constraints. */ if( k0==0 ) { v0 = _state->v_nan; } else { if( ae_fp_greater_eq(be,(double)(0)) ) { v0 = ae; } else { v0 = de; } } if( k1==0 ) { v1 = _state->v_nan; } else { if( ae_fp_greater_eq(be,(double)(0)) ) { v1 = de; } else { v1 = ae; } } /* * Fit */ logisticfit5ec(&x, &y, n, v0, v1, &a, &b, &c, &d, &g, &rep, _state); seterrorflag(fiterrors, !ae_isfinite(a, _state), _state); seterrorflag(fiterrors, !ae_isfinite(b, _state), _state); seterrorflag(fiterrors, !ae_isfinite(c, _state), _state); seterrorflag(fiterrors, !ae_isfinite(d, _state), _state); if( ae_fp_greater(b,(double)(0)) ) { seterrorflag(fiterrors, k0!=0&&ae_fp_neq(a,v0), _state); seterrorflag(fiterrors, k1!=0&&ae_fp_neq(d,v1), _state); } else { seterrorflag(fiterrors, k0!=0&&ae_fp_neq(d,v0), _state); seterrorflag(fiterrors, k1!=0&&ae_fp_neq(a,v1), _state); } v = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { vv = d+(a-d)/ae_pow(1.0+ae_pow(x.ptr.p_double[i]/c, b, _state), g, _state); } else { if( ae_fp_greater_eq(b,(double)(0)) ) { vv = a; } else { vv = d; } } v = v+ae_sqr(y.ptr.p_double[i]-vv, _state); } v = ae_sqrt(v/n, _state); seterrorflag(fiterrors, ae_fp_greater(v,scaley*1.0E-6), _state); } } } /* * Test correctness of errors */ tol = 1.0E-6; for(pass=1; pass<=50; pass++) { n = 10; meany = 0.0; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(i); y.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; meany = meany+y.ptr.p_double[i]; } meany = meany/n; x.ptr.p_double[1] = (double)(0); /* * Choose model fitting function to test */ k = hqrnduniformi(&rs, 4, _state); a = (double)(0); d = (double)(0); c = (double)(1); b = (double)(1); g = (double)(1); if( k==0 ) { logisticfit4(&x, &y, n, &a, &b, &c, &d, &rep, _state); g = 1.0; } if( k==1 ) { logisticfit4ec(&x, &y, n, hqrnduniformr(&rs, _state)-0.5, hqrnduniformr(&rs, _state)-0.5, &a, &b, &c, &d, &rep, _state); g = 1.0; } if( k==2 ) { logisticfit5(&x, &y, n, &a, &b, &c, &d, &g, &rep, _state); } if( k==3 ) { logisticfit5ec(&x, &y, n, hqrnduniformr(&rs, _state)-0.5, hqrnduniformr(&rs, _state)-0.5, &a, &b, &c, &d, &g, &rep, _state); } k = 0; erms = (double)(0); eavg = (double)(0); eavgrel = (double)(0); emax = (double)(0); rss = 0.0; tss = 0.0; for(i=0; i<=n-1; i++) { if( ae_fp_neq(x.ptr.p_double[i],(double)(0)) ) { v = d+(a-d)/ae_pow(1.0+ae_pow(x.ptr.p_double[i]/c, b, _state), g, _state); } else { if( ae_fp_greater_eq(b,(double)(0)) ) { v = a; } else { v = d; } } v = v-y.ptr.p_double[i]; rss = rss+v*v; tss = tss+ae_sqr(y.ptr.p_double[i]-meany, _state); erms = erms+ae_sqr(v, _state); eavg = eavg+ae_fabs(v, _state); if( ae_fp_neq(y.ptr.p_double[i],(double)(0)) ) { eavgrel = eavgrel+ae_fabs(v/y.ptr.p_double[i], _state); k = k+1; } emax = ae_maxreal(emax, ae_fabs(v, _state), _state); } er2 = 1.0-rss/tss; erms = ae_sqrt(erms/n, _state); eavg = eavg/n; if( k>0 ) { eavgrel = eavgrel/k; } seterrorflag(fiterrors, ae_fp_greater(ae_fabs(erms-rep.rmserror, _state),tol), _state); seterrorflag(fiterrors, ae_fp_greater(ae_fabs(eavg-rep.avgerror, _state),tol), _state); seterrorflag(fiterrors, ae_fp_greater(ae_fabs(emax-rep.maxerror, _state),tol), _state); seterrorflag(fiterrors, ae_fp_greater(ae_fabs(eavgrel-rep.avgrelerror, _state),tol), _state); seterrorflag(fiterrors, ae_fp_greater(ae_fabs(er2-rep.r2, _state),tol), _state); } ae_frame_leave(_state); } /************************************************************************* Tests whether C is solution of (possibly) constrained LLS problem *************************************************************************/ static ae_bool testlsfitunit_isglssolution(ae_int_t n, ae_int_t m, ae_int_t k, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_matrix* cmatrix, /* Real */ ae_vector* c, ae_state *_state) { ae_frame _frame_block; ae_vector _c; ae_int_t i; ae_int_t j; ae_vector c2; ae_vector sv; ae_vector deltac; ae_vector deltaproj; ae_matrix u; ae_matrix vt; double v; double s1; double s2; double s3; double delta; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init_copy(&_c, c, _state); c = &_c; ae_vector_init(&c2, 0, DT_REAL, _state); ae_vector_init(&sv, 0, DT_REAL, _state); ae_vector_init(&deltac, 0, DT_REAL, _state); ae_vector_init(&deltaproj, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); /* * Setup. * Threshold is small because CMatrix may be ill-conditioned */ delta = 0.001; threshold = ae_sqrt(ae_machineepsilon, _state); ae_vector_set_length(&c2, m, _state); ae_vector_set_length(&deltac, m, _state); ae_vector_set_length(&deltaproj, m, _state); /* * test whether C is feasible point or not (projC must be close to C) */ for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&cmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); if( ae_fp_greater(ae_fabs(v-cmatrix->ptr.pp_double[i][m], _state),threshold) ) { result = ae_false; ae_frame_leave(_state); return result; } } /* * find orthogonal basis of Null(CMatrix) (stored in rows from K to M-1) */ if( k>0 ) { rmatrixsvd(cmatrix, k, m, 0, 2, 2, &sv, &u, &vt, _state); } /* * Test result */ result = ae_true; s1 = testlsfitunit_getglserror(n, m, y, w, fmatrix, c, _state); for(j=0; j<=m-1; j++) { /* * prepare modification of C which leave us in the feasible set. * * let deltaC be increment on Jth coordinate, then project * deltaC in the Null(CMatrix) and store result in DeltaProj */ ae_v_move(&c2.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); for(i=0; i<=m-1; i++) { if( i==j ) { deltac.ptr.p_double[i] = delta; } else { deltac.ptr.p_double[i] = (double)(0); } } if( k==0 ) { ae_v_move(&deltaproj.ptr.p_double[0], 1, &deltac.ptr.p_double[0], 1, ae_v_len(0,m-1)); } else { for(i=0; i<=m-1; i++) { deltaproj.ptr.p_double[i] = (double)(0); } for(i=k; i<=m-1; i++) { v = ae_v_dotproduct(&vt.ptr.pp_double[i][0], 1, &deltac.ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_addd(&deltaproj.ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); } } /* * now we have DeltaProj such that if C is feasible, * then C+DeltaProj is feasible too */ ae_v_move(&c2.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_add(&c2.ptr.p_double[0], 1, &deltaproj.ptr.p_double[0], 1, ae_v_len(0,m-1)); s2 = testlsfitunit_getglserror(n, m, y, w, fmatrix, &c2, _state); ae_v_move(&c2.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); ae_v_sub(&c2.ptr.p_double[0], 1, &deltaproj.ptr.p_double[0], 1, ae_v_len(0,m-1)); s3 = testlsfitunit_getglserror(n, m, y, w, fmatrix, &c2, _state); result = (result&&ae_fp_greater_eq(s2,s1/(1+threshold)))&&ae_fp_greater_eq(s3,s1/(1+threshold)); } ae_frame_leave(_state); return result; } /************************************************************************* Tests whether C is solution of LLS problem *************************************************************************/ static double testlsfitunit_getglserror(ae_int_t n, ae_int_t m, /* Real */ ae_vector* y, /* Real */ ae_vector* w, /* Real */ ae_matrix* fmatrix, /* Real */ ae_vector* c, ae_state *_state) { ae_int_t i; double v; double result; result = (double)(0); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); result = result+ae_sqr(w->ptr.p_double[i]*(v-y->ptr.p_double[i]), _state); } return result; } /************************************************************************* Subroutine for nonlinear fitting of linear problem DerAvailable: * 0 when only function value should be used * 1 when we can provide gradient/function * 2 when we can provide Hessian/gradient/function When something which is not permitted by DerAvailable is requested, this function sets NLSErrors to True. *************************************************************************/ static void testlsfitunit_fitlinearnonlinear(ae_int_t m, ae_int_t deravailable, /* Real */ ae_matrix* xy, lsfitstate* state, ae_bool* nlserrors, ae_state *_state) { ae_int_t i; ae_int_t j; double v; while(lsfititeration(state, _state)) { /* * assume that one and only one of flags is set * test that we didn't request hessian in hessian-free setting */ if( deravailable<1&&state->needfg ) { *nlserrors = ae_true; } if( deravailable<2&&state->needfgh ) { *nlserrors = ae_true; } i = 0; if( state->needf ) { i = i+1; } if( state->needfg ) { i = i+1; } if( state->needfgh ) { i = i+1; } if( i!=1 ) { *nlserrors = ae_true; } /* * test that PointIndex is consistent with actual point passed */ for(i=0; i<=m-1; i++) { *nlserrors = *nlserrors||ae_fp_neq(xy->ptr.pp_double[state->pointindex][i],state->x.ptr.p_double[i]); } /* * calculate */ if( state->needf ) { v = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->f = v; continue; } if( state->needfg ) { v = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->f = v; ae_v_move(&state->g.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,m-1)); continue; } if( state->needfgh ) { v = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,m-1)); state->f = v; ae_v_move(&state->g.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,m-1)); for(i=0; i<=m-1; i++) { for(j=0; j<=m-1; j++) { state->h.ptr.pp_double[i][j] = (double)(0); } } continue; } } } /************************************************************************* This function tests, that gradient verified correctly. *************************************************************************/ static void testlsfitunit_testgradientcheck(ae_bool* testg, ae_state *_state) { ae_frame _frame_block; lsfitstate state; lsfitreport rep; ae_int_t n; ae_int_t m; ae_int_t k; ae_vector c; ae_vector cres; ae_matrix x; ae_vector y; ae_vector x0; ae_int_t info; ae_vector bl; ae_vector bu; ae_int_t infcomp; double teststep; double noise; ae_int_t nbrcomp; double spp; ae_int_t func; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_frame_make(_state, &_frame_block); *testg = ae_false; _lsfitstate_init(&state, _state); _lsfitreport_init(&rep, _state); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&cres, 0, DT_REAL, _state); ae_matrix_init(&x, 0, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); passcount = 35; spp = 1.0; teststep = 0.01; for(pass=1; pass<=passcount; pass++) { m = ae_randominteger(5, _state)+1; ae_vector_set_length(&x0, m, _state); k = ae_randominteger(5, _state)+1; ae_vector_set_length(&c, k, _state); ae_vector_set_length(&bl, k, _state); ae_vector_set_length(&bu, k, _state); /* * Prepare test's parameters */ func = ae_randominteger(3, _state)+1; n = ae_randominteger(8, _state)+3; ae_matrix_set_length(&x, n, m, _state); ae_vector_set_length(&y, n, _state); nbrcomp = ae_randominteger(k, _state); noise = (double)(2*ae_randominteger(2, _state)-1); /* * Prepare function's parameters */ for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { x.ptr.pp_double[i][j] = spp*(2*ae_randomreal(_state)-1); } y.ptr.p_double[i] = spp*(2*ae_randomreal(_state)-1); } for(i=0; i<=k-1; i++) { c.ptr.p_double[i] = spp*(2*ae_randomreal(_state)-1); } for(i=0; i<=m-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); } /* * Prepare boundary parameters */ for(i=0; i<=k-1; i++) { bl.ptr.p_double[i] = ae_randomreal(_state)-spp; bu.ptr.p_double[i] = ae_randomreal(_state)+spp-1; } infcomp = ae_randominteger(k+1, _state); if( infcompv_neginf; } infcomp = ae_randominteger(k+1, _state); if( infcompv_posinf; } lsfitcreatefg(&x, &y, &c, n, m, k, ae_true, &state, _state); lsfitsetgradientcheck(&state, teststep, _state); lsfitsetcond(&state, 0.0, 0.0, 100, _state); lsfitsetbc(&state, &bl, &bu, _state); /* * Check that the criterion passes a derivative if it is correct */ while(lsfititeration(&state, _state)) { if( state.needfg ) { testlsfitunit_funcderiv(&state.c, &state.x, &x0, k, m, func, &state.f, &state.g, _state); } } lsfitresults(&state, &info, &cres, &rep, _state); /* * Check that error code does not equal to -7 and parameter .VarIdx * equal to -1. */ if( info==-7||rep.varidx!=-1 ) { *testg = ae_true; ae_frame_leave(_state); return; } /* * Create again and... */ lsfitcreatefg(&x, &y, &c, n, m, k, ae_true, &state, _state); lsfitsetgradientcheck(&state, teststep, _state); lsfitsetcond(&state, 0.0, 0.0, 100, _state); lsfitsetbc(&state, &bl, &bu, _state); /* * Check that the criterion does not miss a derivative if * it is incorrect */ while(lsfititeration(&state, _state)) { if( state.needfg ) { testlsfitunit_funcderiv(&state.c, &state.x, &x0, k, m, func, &state.f, &state.g, _state); state.g.ptr.p_double[nbrcomp] = state.g.ptr.p_double[nbrcomp]+noise; } } lsfitresults(&state, &info, &cres, &rep, _state); /* * Check that error code equal to -7 and parameter .VarIdx * equal to number of incorrect component. */ if( info!=-7||rep.varidx!=nbrcomp ) { *testg = ae_true; ae_frame_leave(_state); return; } } *testg = ae_false; ae_frame_leave(_state); } /************************************************************************* This function return function's value(F=F(X,C)) and it derivatives(DF=dF/dC). Function dimension is M. Length(C) is K. Function's list: * funcType=1: K>M: F(X)=C0^2*(X0-CX0)^2+C1^2*(X1-CX1)^2+...+CM^2*(XM-CXM)^2 +C(M+1)^2+...+CK^2; KM: F(X)=C0*sin(X0-CX0)^2+C1*sin(X1-CX1)^2+...+CM*sin(XM-CXM)^2 +C(M+1)^3+...+CK^3; K=1&&functype<=3, "FuncDeriv: incorrect funcType(funcType<1 or funcType>3).", _state); ae_assert(k>0, "FuncDeriv: K<=0", _state); ae_assert(m>0, "FuncDeriv: M<=0", _state); ae_assert(x->cnt>=m, "FuncDeriv: Length(X)cnt>=m, "FuncDeriv: Length(X0)cnt>=k, "FuncDeriv: Length(X)ptr.p_double[i]*(x->ptr.p_double[i]-x0->ptr.p_double[i]), _state); g->ptr.p_double[i] = 2*c->ptr.p_double[i]*ae_sqr(x->ptr.p_double[i]-x0->ptr.p_double[i], _state); } if( k>m ) { for(i=m; i<=k-1; i++) { *f = *f+ae_sqr(c->ptr.p_double[i], _state); g->ptr.p_double[i] = 2*c->ptr.p_double[i]; } } if( kptr.p_double[i]-x0->ptr.p_double[i], _state); } } return; } if( functype==2 ) { *f = (double)(0); for(i=0; i<=ae_minint(m, k, _state)-1; i++) { *f = *f+c->ptr.p_double[i]*ae_sqr(ae_sin(x->ptr.p_double[i]-x0->ptr.p_double[i], _state), _state); g->ptr.p_double[i] = ae_sqr(ae_sin(x->ptr.p_double[i]-x0->ptr.p_double[i], _state), _state); } if( k>m ) { for(i=m; i<=k-1; i++) { *f = *f+c->ptr.p_double[i]*c->ptr.p_double[i]*c->ptr.p_double[i]; g->ptr.p_double[i] = 3*ae_sqr(c->ptr.p_double[i], _state); } } if( kptr.p_double[i]-x0->ptr.p_double[i], _state), _state); } } return; } if( functype==3 ) { *f = (double)(0); for(i=0; i<=m-1; i++) { *f = *f+ae_sqr(x->ptr.p_double[i]-x0->ptr.p_double[i], _state); } for(i=0; i<=k-1; i++) { *f = *f+c->ptr.p_double[i]*c->ptr.p_double[i]; } for(i=0; i<=k-1; i++) { g->ptr.p_double[i] = 2*c->ptr.p_double[i]; } return; } } static void testparametricunit_testrdp(ae_bool* errorflag, ae_state *_state); static void testparametricunit_unsetp2(pspline2interpolant* p, ae_state *_state); static void testparametricunit_unsetp3(pspline3interpolant* p, ae_state *_state); ae_bool testparametric(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool p2errors; ae_bool p3errors; ae_bool rdperrors; double nonstrictthreshold; double threshold; ae_int_t passcount; double lstep; double h; ae_int_t maxn; ae_int_t periodicity; ae_int_t skind; ae_int_t pkind; ae_bool periodic; double a; double b; ae_int_t n; ae_int_t tmpn; ae_int_t i; double vx; double vy; double vz; double vx2; double vy2; double vz2; double vdx; double vdy; double vdz; double vdx2; double vdy2; double vdz2; double vd2x; double vd2y; double vd2z; double vd2x2; double vd2y2; double vd2z2; double v0; double v1; ae_vector x; ae_vector y; ae_vector z; ae_vector t; ae_vector t2; ae_vector t3; ae_matrix xy; ae_matrix xyz; pspline2interpolant p2; pspline3interpolant p3; spline1dinterpolant s; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&t, 0, DT_REAL, _state); ae_vector_init(&t2, 0, DT_REAL, _state); ae_vector_init(&t3, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&xyz, 0, 0, DT_REAL, _state); _pspline2interpolant_init(&p2, _state); _pspline3interpolant_init(&p3, _state); _spline1dinterpolant_init(&s, _state); waserrors = ae_false; passcount = 20; lstep = 0.005; h = 0.00001; maxn = 10; threshold = 10000*ae_machineepsilon; nonstrictthreshold = 0.00001; p2errors = ae_false; p3errors = ae_false; rdperrors = ae_false; testparametricunit_testrdp(&rdperrors, _state); /* * Test basic properties of 2- and 3-dimensional splines: * * PSpline2ParameterValues() properties * * values at nodes * * for periodic splines - periodicity properties * * Variables used: * * N points count * * SKind spline * * PKind parameterization * * Periodicity whether we have periodic spline or not */ for(n=2; n<=maxn; n++) { for(skind=0; skind<=2; skind++) { for(pkind=0; pkind<=2; pkind++) { for(periodicity=0; periodicity<=1; periodicity++) { periodic = periodicity==1; /* * skip unsupported combinations of parameters */ if( periodic&&n<3 ) { continue; } if( periodic&&skind==0 ) { continue; } if( n<5&&skind==0 ) { continue; } /* * init */ ae_matrix_set_length(&xy, n, 2, _state); ae_matrix_set_length(&xyz, n, 3, _state); taskgenint1dequidist((double)(-1), (double)(1), n, &t2, &x, _state); ae_v_move(&xy.ptr.pp_double[0][0], xy.stride, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&xyz.ptr.pp_double[0][0], xyz.stride, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); taskgenint1dequidist((double)(-1), (double)(1), n, &t2, &y, _state); ae_v_move(&xy.ptr.pp_double[0][1], xy.stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&xyz.ptr.pp_double[0][1], xyz.stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); taskgenint1dequidist((double)(-1), (double)(1), n, &t2, &z, _state); ae_v_move(&xyz.ptr.pp_double[0][2], xyz.stride, &z.ptr.p_double[0], 1, ae_v_len(0,n-1)); testparametricunit_unsetp2(&p2, _state); testparametricunit_unsetp3(&p3, _state); if( periodic ) { pspline2buildperiodic(&xy, n, skind, pkind, &p2, _state); pspline3buildperiodic(&xyz, n, skind, pkind, &p3, _state); } else { pspline2build(&xy, n, skind, pkind, &p2, _state); pspline3build(&xyz, n, skind, pkind, &p3, _state); } /* * PSpline2ParameterValues() properties */ pspline2parametervalues(&p2, &tmpn, &t2, _state); if( tmpn!=n ) { p2errors = ae_true; continue; } pspline3parametervalues(&p3, &tmpn, &t3, _state); if( tmpn!=n ) { p3errors = ae_true; continue; } p2errors = p2errors||ae_fp_neq(t2.ptr.p_double[0],(double)(0)); p3errors = p3errors||ae_fp_neq(t3.ptr.p_double[0],(double)(0)); for(i=1; i<=n-1; i++) { p2errors = p2errors||ae_fp_less_eq(t2.ptr.p_double[i],t2.ptr.p_double[i-1]); p3errors = p3errors||ae_fp_less_eq(t3.ptr.p_double[i],t3.ptr.p_double[i-1]); } if( periodic ) { p2errors = p2errors||ae_fp_greater_eq(t2.ptr.p_double[n-1],(double)(1)); p3errors = p3errors||ae_fp_greater_eq(t3.ptr.p_double[n-1],(double)(1)); } else { p2errors = p2errors||ae_fp_neq(t2.ptr.p_double[n-1],(double)(1)); p3errors = p3errors||ae_fp_neq(t3.ptr.p_double[n-1],(double)(1)); } /* * Now we have parameter values stored at T, * and want to test whether the actully correspond to * points */ for(i=0; i<=n-1; i++) { /* * 2-dimensional test */ pspline2calc(&p2, t2.ptr.p_double[i], &vx, &vy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); /* * 3-dimensional test */ pspline3calc(&p3, t3.ptr.p_double[i], &vx, &vy, &vz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-z.ptr.p_double[i], _state),threshold); } /* * Test periodicity (if needed) */ if( periodic ) { /* * periodicity at nodes */ for(i=0; i<=n-1; i++) { /* * 2-dimensional test */ pspline2calc(&p2, t2.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); pspline2diff(&p2, t2.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vdx, &vy, &vdy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); pspline2diff2(&p2, t2.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); /* * 3-dimensional test */ pspline3calc(&p3, t3.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vy, &vz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-z.ptr.p_double[i], _state),threshold); pspline3diff(&p3, t3.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vdx, &vy, &vdy, &vz, &vdz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-z.ptr.p_double[i], _state),threshold); pspline3diff2(&p3, t3.ptr.p_double[i]+ae_randominteger(10, _state)-5, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, &vz, &vdz, &vd2z, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-x.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-y.ptr.p_double[i], _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-z.ptr.p_double[i], _state),threshold); } /* * periodicity between nodes */ v0 = ae_randomreal(_state); pspline2calc(&p2, v0, &vx, &vy, _state); pspline2calc(&p2, v0+ae_randominteger(10, _state)-5, &vx2, &vy2, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); pspline3calc(&p3, v0, &vx, &vy, &vz, _state); pspline3calc(&p3, v0+ae_randominteger(10, _state)-5, &vx2, &vy2, &vz2, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); /* * near-boundary test for continuity of function values and derivatives: * 2-dimensional curve */ ae_assert(skind==1||skind==2, "TEST: unexpected spline type!", _state); v0 = 100*ae_machineepsilon; v1 = 1-v0; pspline2calc(&p2, v0, &vx, &vy, _state); pspline2calc(&p2, v1, &vx2, &vy2, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); pspline2diff(&p2, v0, &vx, &vdx, &vy, &vdy, _state); pspline2diff(&p2, v1, &vx2, &vdx2, &vy2, &vdy2, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),nonstrictthreshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),nonstrictthreshold); pspline2diff2(&p2, v0, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, _state); pspline2diff2(&p2, v1, &vx2, &vdx2, &vd2x2, &vy2, &vdy2, &vd2y2, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),nonstrictthreshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),nonstrictthreshold); if( skind==2 ) { /* * second derivative test only for cubic splines */ p2errors = p2errors||ae_fp_greater(ae_fabs(vd2x-vd2x2, _state),nonstrictthreshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vd2y-vd2y2, _state),nonstrictthreshold); } /* * near-boundary test for continuity of function values and derivatives: * 3-dimensional curve */ ae_assert(skind==1||skind==2, "TEST: unexpected spline type!", _state); v0 = 100*ae_machineepsilon; v1 = 1-v0; pspline3calc(&p3, v0, &vx, &vy, &vz, _state); pspline3calc(&p3, v1, &vx2, &vy2, &vz2, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); pspline3diff(&p3, v0, &vx, &vdx, &vy, &vdy, &vz, &vdz, _state); pspline3diff(&p3, v1, &vx2, &vdx2, &vy2, &vdy2, &vz2, &vdz2, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdz-vdz2, _state),nonstrictthreshold); pspline3diff2(&p3, v0, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, &vz, &vdz, &vd2z, _state); pspline3diff2(&p3, v1, &vx2, &vdx2, &vd2x2, &vy2, &vdy2, &vd2y2, &vz2, &vdz2, &vd2z2, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdz-vdz2, _state),nonstrictthreshold); if( skind==2 ) { /* * second derivative test only for cubic splines */ p3errors = p3errors||ae_fp_greater(ae_fabs(vd2x-vd2x2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vd2y-vd2y2, _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vd2z-vd2z2, _state),nonstrictthreshold); } } } } } } /* * Test differentiation, tangents, calculation between nodes. * * Because differentiation is done in parameterization/spline/periodicity * oblivious manner, we don't have to test all possible combinations * of spline types and parameterizations. * * Actually we test special combination with properties which allow us * to easily solve this problem: * * 2 (3) variables * * first variable is sampled from equidistant grid on [0,1] * * other variables are random * * uniform parameterization is used * * periodicity - none * * spline type - any (we use cubic splines) * Same problem allows us to test calculation BETWEEN nodes. */ for(n=2; n<=maxn; n++) { /* * init */ ae_matrix_set_length(&xy, n, 2, _state); ae_matrix_set_length(&xyz, n, 3, _state); taskgenint1dequidist((double)(0), (double)(1), n, &t, &x, _state); ae_v_move(&xy.ptr.pp_double[0][0], xy.stride, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&xyz.ptr.pp_double[0][0], xyz.stride, &x.ptr.p_double[0], 1, ae_v_len(0,n-1)); taskgenint1dequidist((double)(0), (double)(1), n, &t, &y, _state); ae_v_move(&xy.ptr.pp_double[0][1], xy.stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); ae_v_move(&xyz.ptr.pp_double[0][1], xyz.stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); taskgenint1dequidist((double)(0), (double)(1), n, &t, &z, _state); ae_v_move(&xyz.ptr.pp_double[0][2], xyz.stride, &z.ptr.p_double[0], 1, ae_v_len(0,n-1)); testparametricunit_unsetp2(&p2, _state); testparametricunit_unsetp3(&p3, _state); pspline2build(&xy, n, 2, 0, &p2, _state); pspline3build(&xyz, n, 2, 0, &p3, _state); /* * Test 2D/3D spline: * * build non-parametric cubic spline from T and X/Y * * calculate its value and derivatives at V0 * * compare with Spline2Calc/Spline2Diff/Spline2Diff2 * Because of task properties both variants should * return same answer. */ v0 = ae_randomreal(_state); spline1dbuildcubic(&t, &x, n, 0, 0.0, 0, 0.0, &s, _state); spline1ddiff(&s, v0, &vx2, &vdx2, &vd2x2, _state); spline1dbuildcubic(&t, &y, n, 0, 0.0, 0, 0.0, &s, _state); spline1ddiff(&s, v0, &vy2, &vdy2, &vd2y2, _state); spline1dbuildcubic(&t, &z, n, 0, 0.0, 0, 0.0, &s, _state); spline1ddiff(&s, v0, &vz2, &vdz2, &vd2z2, _state); /* * 2D test */ pspline2calc(&p2, v0, &vx, &vy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); pspline2diff(&p2, v0, &vx, &vdx, &vy, &vdy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),threshold); pspline2diff2(&p2, v0, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vd2x-vd2x2, _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vd2y-vd2y2, _state),threshold); /* * 3D test */ pspline3calc(&p3, v0, &vx, &vy, &vz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); pspline3diff(&p3, v0, &vx, &vdx, &vy, &vdy, &vz, &vdz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdz-vdz2, _state),threshold); pspline3diff2(&p3, v0, &vx, &vdx, &vd2x, &vy, &vdy, &vd2y, &vz, &vdz, &vd2z, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vz2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdx-vdx2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdy-vdy2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vdz-vdz2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vd2x-vd2x2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vd2y-vd2y2, _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vd2z-vd2z2, _state),threshold); /* * Test tangents for 2D/3D */ pspline2tangent(&p2, v0, &vx, &vy, _state); p2errors = p2errors||ae_fp_greater(ae_fabs(vx-vdx2/safepythag2(vdx2, vdy2, _state), _state),threshold); p2errors = p2errors||ae_fp_greater(ae_fabs(vy-vdy2/safepythag2(vdx2, vdy2, _state), _state),threshold); pspline3tangent(&p3, v0, &vx, &vy, &vz, _state); p3errors = p3errors||ae_fp_greater(ae_fabs(vx-vdx2/safepythag3(vdx2, vdy2, vdz2, _state), _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vy-vdy2/safepythag3(vdx2, vdy2, vdz2, _state), _state),threshold); p3errors = p3errors||ae_fp_greater(ae_fabs(vz-vdz2/safepythag3(vdx2, vdy2, vdz2, _state), _state),threshold); } /* * Arc length test. * * Simple problem with easy solution (points on a straight line with * uniform parameterization). */ for(n=2; n<=maxn; n++) { ae_matrix_set_length(&xy, n, 2, _state); ae_matrix_set_length(&xyz, n, 3, _state); for(i=0; i<=n-1; i++) { xy.ptr.pp_double[i][0] = (double)(i); xy.ptr.pp_double[i][1] = (double)(i); xyz.ptr.pp_double[i][0] = (double)(i); xyz.ptr.pp_double[i][1] = (double)(i); xyz.ptr.pp_double[i][2] = (double)(i); } pspline2build(&xy, n, 1, 0, &p2, _state); pspline3build(&xyz, n, 1, 0, &p3, _state); a = ae_randomreal(_state); b = ae_randomreal(_state); p2errors = p2errors||ae_fp_greater(ae_fabs(pspline2arclength(&p2, a, b, _state)-(b-a)*ae_sqrt((double)(2), _state)*(n-1), _state),nonstrictthreshold); p3errors = p3errors||ae_fp_greater(ae_fabs(pspline3arclength(&p3, a, b, _state)-(b-a)*ae_sqrt((double)(3), _state)*(n-1), _state),nonstrictthreshold); } /* * report */ waserrors = (p2errors||p3errors)||rdperrors; if( !silent ) { printf("TESTING PARAMETRIC INTERPOLATION\n"); /* * Normal tests */ printf("2D SPLINES: "); if( p2errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("3D SPLINES: "); if( p3errors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("RDP: "); if( rdperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testparametric(ae_bool silent, ae_state *_state) { return testparametric(silent, _state); } /************************************************************************* This function tests 4PL/5PL fitting. On error sets FitErrors flag variable; on success - flag is not changed. *************************************************************************/ static void testparametricunit_testrdp(ae_bool* errorflag, ae_state *_state) { ae_frame _frame_block; hqrndstate rs; ae_vector x; ae_vector y; ae_vector e; ae_vector x2; ae_vector y2; ae_vector x3; ae_vector y3; ae_matrix xy; ae_matrix xy2; ae_matrix xy3; ae_vector idx2; ae_vector idx3; ae_int_t nsections; ae_int_t nsections3; double eps; double v; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t d; spline1dinterpolant s; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&rs, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&e, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&y2, 0, DT_REAL, _state); ae_vector_init(&x3, 0, DT_REAL, _state); ae_vector_init(&y3, 0, DT_REAL, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_init(&xy2, 0, 0, DT_REAL, _state); ae_matrix_init(&xy3, 0, 0, DT_REAL, _state); ae_vector_init(&idx2, 0, DT_INT, _state); ae_vector_init(&idx3, 0, DT_INT, _state); _spline1dinterpolant_init(&s, _state); hqrndrandomize(&rs, _state); /* * Parametric test 1: non-closed curve */ ae_matrix_set_length(&xy, 4, 2, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(0); xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(2); xy.ptr.pp_double[2][0] = (double)(3); xy.ptr.pp_double[2][1] = (double)(1); xy.ptr.pp_double[3][0] = (double)(3); xy.ptr.pp_double[3][1] = (double)(3); parametricrdpfixed(&xy, 4, 2, 0, ae_sqrt((double)(2), _state)+0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=1, _state); if( nsections==1 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=3, _state); } parametricrdpfixed(&xy, 4, 2, 0, ae_sqrt((double)(2), _state)-0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=3, _state); if( nsections==3 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(2)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=1, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[3]!=3, _state); } parametricrdpfixed(&xy, 4, 2, 1, 0.0, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=1, _state); if( nsections==1 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=3, _state); } parametricrdpfixed(&xy, 4, 2, 2, 0.0, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=2, _state); if( nsections==2 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=3, _state); } parametricrdpfixed(&xy, 4, 2, 3, 0.0, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=3, _state); if( nsections==3 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(2)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=1, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[3]!=3, _state); } parametricrdpfixed(&xy, 4, 2, 4, 0.0, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=3, _state); if( nsections==3 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(2)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=1, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][0],(double)(3)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][1],(double)(3)), _state); seterrorflag(errorflag, idx2.ptr.p_int[3]!=3, _state); } /* * Parametric test 2: closed curve */ ae_matrix_set_length(&xy, 5, 2, _state); xy.ptr.pp_double[0][0] = (double)(0); xy.ptr.pp_double[0][1] = (double)(0); xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(0); xy.ptr.pp_double[2][0] = (double)(1); xy.ptr.pp_double[2][1] = (double)(1); xy.ptr.pp_double[3][0] = (double)(0); xy.ptr.pp_double[3][1] = (double)(1); xy.ptr.pp_double[4][0] = (double)(0); xy.ptr.pp_double[4][1] = (double)(0); parametricrdpfixed(&xy, 5, 2, 0, ae_sqrt((double)(2), _state)+0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=1, _state); if( nsections==1 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=4, _state); } parametricrdpfixed(&xy, 5, 2, 0, ae_sqrt((double)(2), _state)-0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=2, _state); if( nsections==2 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=4, _state); } parametricrdpfixed(&xy, 5, 2, 0, ae_sqrt((double)(2), _state)/2+0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=2, _state); if( nsections==2 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=4, _state); } parametricrdpfixed(&xy, 5, 2, 0, ae_sqrt((double)(2), _state)/2-0.001, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections!=4, _state); if( nsections==4 ) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[0][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[1][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[1]!=1, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][0],(double)(1)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[2][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[2]!=2, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[3][1],(double)(1)), _state); seterrorflag(errorflag, idx2.ptr.p_int[3]!=3, _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[4][0],(double)(0)), _state); seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[4][1],(double)(0)), _state); seterrorflag(errorflag, idx2.ptr.p_int[4]!=4, _state); } /* * Parametric, variable precision test (non-fixed), results are compared against fixed-section test */ eps = 10.0; n = 100; while(ae_fp_greater_eq(eps,0.0001)) { /* * Try different dimension counts */ for(d=1; d<=5; d++) { /* * Generate dataset */ ae_matrix_set_length(&xy, n, d, _state); for(i=0; i<=n-1; i++) { v = ae_pi*i/(n-1); for(j=0; j<=d-1; j++) { xy.ptr.pp_double[i][j] = ae_pow(ae_sin(v, _state), (double)(j+1), _state)+0.01*(hqrnduniformr(&rs, _state)-0.5); } } /* * Perform run of eps-based RDP algorithm */ parametricrdpfixed(&xy, n, d, 0, eps, &xy2, &idx2, &nsections, _state); seterrorflag(errorflag, nsections==0, _state); if( nsections==0 ) { ae_frame_leave(_state); return; } /* * Check properties */ seterrorflag(errorflag, idx2.ptr.p_int[0]!=0, _state); for(i=0; i<=nsections-1; i++) { seterrorflag(errorflag, idx2.ptr.p_int[i]>=idx2.ptr.p_int[i+1], _state); } seterrorflag(errorflag, idx2.ptr.p_int[nsections]!=n-1, _state); for(i=0; i<=nsections; i++) { for(j=0; j<=d-1; j++) { seterrorflag(errorflag, ae_fp_neq(xy2.ptr.pp_double[i][j],xy.ptr.pp_double[idx2.ptr.p_int[i]][j]), _state); } } ae_vector_set_length(&x, nsections+1, _state); ae_vector_set_length(&y, nsections+1, _state); ae_vector_set_length(&e, n, _state); for(i=0; i<=n-1; i++) { e.ptr.p_double[i] = (double)(0); } for(j=0; j<=d-1; j++) { for(i=0; i<=nsections; i++) { x.ptr.p_double[i] = (double)(idx2.ptr.p_int[i]); y.ptr.p_double[i] = xy2.ptr.pp_double[i][j]; } spline1dbuildlinear(&x, &y, nsections+1, &s, _state); for(i=0; i<=n-1; i++) { e.ptr.p_double[i] = e.ptr.p_double[i]+ae_sqr(spline1dcalc(&s, (double)(i), _state)-xy.ptr.pp_double[i][j], _state); } } for(i=0; i<=n-1; i++) { seterrorflag(errorflag, ae_fp_greater(ae_sqrt(e.ptr.p_double[i], _state),eps), _state); } /* * compare results with values returned by section-based algorithm */ parametricrdpfixed(&xy, n, d, nsections, 0.0, &xy3, &idx3, &nsections3, _state); seterrorflag(errorflag, nsections3!=nsections, _state); if( *errorflag ) { ae_frame_leave(_state); return; } for(i=0; i<=nsections; i++) { seterrorflag(errorflag, idx2.ptr.p_int[i]!=idx3.ptr.p_int[i], _state); for(j=0; j<=d-1; j++) { seterrorflag(errorflag, ae_fp_greater(ae_fabs(xy2.ptr.pp_double[i][j]-xy3.ptr.pp_double[i][j], _state),1000*ae_machineepsilon), _state); } } } /* * Next epsilon */ eps = eps*0.5; } ae_frame_leave(_state); } /************************************************************************* Unset spline, i.e. initialize it with random garbage *************************************************************************/ static void testparametricunit_unsetp2(pspline2interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_frame_make(_state, &_frame_block); _pspline2interpolant_clear(p); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_set_length(&xy, 2, 2, _state); xy.ptr.pp_double[0][0] = (double)(-1); xy.ptr.pp_double[0][1] = (double)(-1); xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(1); pspline2build(&xy, 2, 1, 0, p, _state); ae_frame_leave(_state); } /************************************************************************* Unset spline, i.e. initialize it with random garbage *************************************************************************/ static void testparametricunit_unsetp3(pspline3interpolant* p, ae_state *_state) { ae_frame _frame_block; ae_matrix xy; ae_frame_make(_state, &_frame_block); _pspline3interpolant_clear(p); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_matrix_set_length(&xy, 2, 3, _state); xy.ptr.pp_double[0][0] = (double)(-1); xy.ptr.pp_double[0][1] = (double)(-1); xy.ptr.pp_double[0][2] = (double)(-1); xy.ptr.pp_double[1][0] = (double)(1); xy.ptr.pp_double[1][1] = (double)(1); xy.ptr.pp_double[1][2] = (double)(1); pspline3build(&xy, 2, 1, 0, p, _state); ae_frame_leave(_state); } static double testlinlsqrunit_e0 = 1.0E-6; static double testlinlsqrunit_tolort = 1.0E-4; static double testlinlsqrunit_e1 = 1.0E+6; static double testlinlsqrunit_emergencye0 = 1.0E-12; static ae_bool testlinlsqrunit_svdtest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_mwcranksvdtest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_mwicranksvdtest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_bidiagonaltest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_zeromatrixtest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_reportcorrectnesstest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_stoppingcriteriatest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_analytictest(ae_bool silent, ae_state *_state); static ae_bool testlinlsqrunit_isitgoodsolution(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t m, ae_int_t n, double lambdav, /* Real */ ae_vector* x, double epserr, double epsort, ae_state *_state); static ae_bool testlinlsqrunit_preconditionertest(ae_state *_state); ae_bool testlinlsqr(ae_bool silent, ae_state *_state) { ae_bool svdtesterrors; ae_bool mwcranksvderr; ae_bool mwicranksvderr; ae_bool bidiagonalerr; ae_bool zeromatrixerr; ae_bool reportcorrectnesserr; ae_bool stoppingcriteriaerr; ae_bool analytictesterrors; ae_bool prectesterrors; ae_bool waserrors; ae_bool result; svdtesterrors = testlinlsqrunit_svdtest(ae_true, _state); mwcranksvderr = testlinlsqrunit_mwcranksvdtest(ae_true, _state); mwicranksvderr = testlinlsqrunit_mwicranksvdtest(ae_true, _state); bidiagonalerr = testlinlsqrunit_bidiagonaltest(ae_true, _state); zeromatrixerr = testlinlsqrunit_zeromatrixtest(ae_true, _state); reportcorrectnesserr = testlinlsqrunit_reportcorrectnesstest(ae_true, _state); stoppingcriteriaerr = testlinlsqrunit_stoppingcriteriatest(ae_true, _state); analytictesterrors = testlinlsqrunit_analytictest(ae_true, _state); prectesterrors = testlinlsqrunit_preconditionertest(_state); /* * report */ waserrors = (((((((svdtesterrors||mwcranksvderr)||mwicranksvderr)||bidiagonalerr)||zeromatrixerr)||reportcorrectnesserr)||stoppingcriteriaerr)||analytictesterrors)||prectesterrors; if( !silent ) { printf("TESTING LinLSQR\n"); printf("SVDTest: "); if( svdtesterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MWCRankSVDTest: "); if( mwcranksvderr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MWICRankSVDTest: "); if( mwicranksvderr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BidiagonalTest: "); if( bidiagonalerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("ZeroMatrixTest: "); if( zeromatrixerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("ReportCorrectnessTest: "); if( reportcorrectnesserr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("StoppingCriteriaTest: "); if( stoppingcriteriaerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Analytic properties: "); if( analytictesterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Preconditioner test: "); if( prectesterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } /* *was errors? */ if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlinlsqr(ae_bool silent, ae_state *_state) { return testlinlsqr(silent, _state); } /************************************************************************* This function generates random MxN problem, solves it with LSQR and compares with results obtained from SVD solver. Matrix A is generated as MxN matrix with uniformly distributed random entries, i.e. it has no special properties (like conditioning or separation of singular values). We apply random amount regularization to our problem (from zero to large) in order to test regularizer. Default stopping criteria are used. Preconditioning is turned off because it skews results for rank-deficient problems. INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_svdtest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; sparsematrix spa; ae_matrix a; ae_vector b; ae_vector x0; ae_int_t szn; ae_int_t szm; ae_int_t n; ae_int_t m; double lambdai; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); _sparsematrix_init(&spa, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); szm = 5; szn = 5; for(m=1; m<=szm; m++) { for(n=1; n<=szn; n++) { /* * Prepare MxN matrix A, right part B, lambda */ lambdai = ae_randomreal(_state); ae_matrix_set_length(&a, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } sparsecreate(m, n, 1, &spa, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { sparseset(&spa, i, j, a.ptr.pp_double[i][j], _state); } } sparseconverttocrs(&spa, _state); ae_vector_set_length(&b, m, _state); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } /* * Solve by calling LinLSQRIteration */ linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetlambdai(&s, lambdai, _state); linlsqrsetprecunit(&s, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, lambdai, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } /* *test LinLSQRRestart and LinLSQRSolveSparse */ linlsqrrestart(&s, _state); linlsqrsolvesparse(&s, &spa, &b, _state); linlsqrresults(&s, &x0, &rep, _state); if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, lambdai, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } if( !silent ) { printf("SVDTest::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The test checks that algorithm can solve MxN (with N<=M) well-conditioned problems - and can do so within exactly N iterations. We use moderate condition numbers, from 1.0 to 10.0, because larger condition number may require several additional iterations to converge. We try different scalings of the A and B. INPUT: Silent - if true then function does not outputs results to console -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_mwcranksvdtest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_vector b; double bnorm; ae_vector x0; ae_int_t szm; ae_int_t n; ae_int_t m; ae_int_t ns0; ae_int_t ns1; ae_int_t nlambdai; double s0; double s1; double lambdai; double c; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); szm = 5; for(m=1; m<=szm; m++) { for(n=1; n<=m; n++) { for(nlambdai=0; nlambdai<=3; nlambdai++) { for(ns0=-1; ns0<=1; ns0++) { for(ns1=-1; ns1<=1; ns1++) { /* * Generate problem: * * scale factors s0, s1 * * MxN well conditioned A (with condition number C in [1,10] and norm s0) * * regularization coefficient LambdaI * * right part b, with |b|=s1 */ s0 = ae_pow((double)(10), (double)(10*ns0), _state); s1 = ae_pow((double)(10), (double)(10*ns1), _state); lambdai = (double)(0); if( nlambdai==0 ) { lambdai = (double)(0); } if( nlambdai==1 ) { lambdai = s0/1000; } if( nlambdai==2 ) { lambdai = s0; } if( nlambdai==3 ) { lambdai = s0*1000; } c = (10-1)*ae_randomreal(_state)+1; rmatrixrndcond(m, c, &a, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = s0*a.ptr.pp_double[i][j]; } } ae_vector_set_length(&b, m, _state); do { bnorm = (double)(0); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bnorm = bnorm+b.ptr.p_double[i]*b.ptr.p_double[i]; } bnorm = ae_sqrt(bnorm, _state); } while(ae_fp_less_eq(bnorm,testlinlsqrunit_e0)); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = b.ptr.p_double[i]*s1/bnorm; } /* * Solve by LSQR method */ linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, (double)(0), (double)(0), n, _state); linlsqrsetlambdai(&s, lambdai, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, lambdai, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The test checks that algorithm can find a solution with minimum norm for a singular rectangular problem. System matrix has special property - singular values are either zero or well separated from zero. INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_mwicranksvdtest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; sparsematrix spa; ae_vector b; double bnorm; ae_vector x0; ae_int_t szm; ae_int_t n; ae_int_t m; ae_int_t nz; ae_int_t ns0; ae_int_t ns1; ae_int_t nlambdai; double s0; double s1; double lambdai; ae_int_t i; ae_int_t j; ae_matrix a; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); _sparsematrix_init(&spa, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); result = ae_false; szm = 5; for(m=1; m<=szm; m++) { for(n=1; n<=m; n++) { for(nlambdai=0; nlambdai<=2; nlambdai++) { for(ns0=-1; ns0<=1; ns0++) { for(ns1=-1; ns1<=1; ns1++) { for(nz=0; nz<=n-1; nz++) { /* * Generate problem: * * scale coefficients s0, s1 * * regularization coefficient LambdaI * * MxN matrix A, norm(A)=s0, with NZ zero singular values and N-NZ nonzero ones * * right part b with norm(b)=s1 */ s0 = ae_pow((double)(10), (double)(10*ns0), _state); s1 = ae_pow((double)(10), (double)(10*ns1), _state); lambdai = (double)(0); if( nlambdai==0 ) { lambdai = (double)(0); } if( nlambdai==1 ) { lambdai = s0; } if( nlambdai==2 ) { lambdai = s0*1000; } ae_matrix_set_length(&a, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-nz-1; i++) { a.ptr.pp_double[i][i] = s0*(0.1+0.9*ae_randomreal(_state)); } rmatrixrndorthogonalfromtheleft(&a, m, n, _state); rmatrixrndorthogonalfromtheright(&a, m, n, _state); ae_vector_set_length(&b, m, _state); do { bnorm = (double)(0); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bnorm = bnorm+b.ptr.p_double[i]*b.ptr.p_double[i]; } bnorm = ae_sqrt(bnorm, _state); } while(ae_fp_less_eq(bnorm,testlinlsqrunit_e0)); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = b.ptr.p_double[i]*s1/bnorm; } /* * Solve by LSQR method */ linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, testlinlsqrunit_emergencye0, testlinlsqrunit_emergencye0, n, _state); linlsqrsetlambdai(&s, lambdai, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); /* * Check */ if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, lambdai, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } ae_frame_leave(_state); return result; } /************************************************************************* The test does check, that algorithm can find a solution with minimum norm, if a problem has bidiagonal matrix on diagonals of a lot of zeros. This problem has to lead to case when State.Alpha and State.Beta are zero, and we we can be sure that the algorithm correctly handles it. We do not use iteration count as stopping condition, because problem can be degenerate and we may need more than N iterations to converge. INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_bidiagonaltest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_vector b; double bnorm; ae_vector x0; ae_int_t sz; ae_int_t n; ae_int_t m; ae_int_t minmn; ae_int_t ns0; ae_int_t ns1; double s0; double s1; ae_int_t i; ae_int_t j; ae_int_t p; ae_int_t diag; double pz; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); sz = 5; for(m=1; m<=sz; m++) { for(n=1; n<=sz; n++) { minmn = ae_minint(m, n, _state); for(p=0; p<=2; p++) { for(ns0=-1; ns0<=1; ns0++) { for(ns1=-1; ns1<=1; ns1++) { for(diag=0; diag<=1; diag++) { /* * Generate problem: * * scaling coefficients s0, s1 * * bidiagonal A, with probability of having zero element at diagonal equal to PZ */ s0 = ae_pow((double)(10), (double)(10*ns0), _state); s1 = ae_pow((double)(10), (double)(10*ns1), _state); pz = 0.0; if( p==0 ) { pz = 0.25; } if( p==1 ) { pz = 0.5; } if( p==2 ) { pz = 0.75; } ae_matrix_set_length(&a, m, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=minmn-1; i++) { if( ae_fp_greater_eq(ae_randomreal(_state),pz) ) { a.ptr.pp_double[i][i] = 2*ae_randomreal(_state)-1; } } for(i=1; i<=minmn-1; i++) { if( ae_fp_greater_eq(ae_randomreal(_state),pz) ) { if( diag==0 ) { a.ptr.pp_double[i-1][i] = 2*ae_randomreal(_state)-1; } if( diag==1 ) { a.ptr.pp_double[i][i-1] = 2*ae_randomreal(_state)-1; } } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = s0*a.ptr.pp_double[i][j]; } } ae_vector_set_length(&b, m, _state); do { bnorm = (double)(0); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bnorm = bnorm+b.ptr.p_double[i]*b.ptr.p_double[i]; } bnorm = ae_sqrt(bnorm, _state); } while(ae_fp_less_eq(bnorm,testlinlsqrunit_e0)); for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = b.ptr.p_double[i]*s1/bnorm; } /* * LSQR solution */ linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, testlinlsqrunit_e0, testlinlsqrunit_e0, 0, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); /* * Check */ if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, 0.0, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The test does check, that algorithm correctly solves a problem in cases: 1. A=0, B<>0; 2. A<>0, B=0; 3. A=0, B=0. If some part is not zero then it filled with ones. INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_zeromatrixtest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_vector b; ae_vector x0; ae_int_t sz; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; ae_int_t nzeropart; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); sz = 5; result = ae_false; for(m=1; m<=sz; m++) { for(n=1; n<=sz; n++) { for(nzeropart=0; nzeropart<=2; nzeropart++) { /* * Initialize A, b */ ae_matrix_set_length(&a, m, n, _state); if( nzeropart==0||nzeropart==2 ) { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } } else { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = (double)(1); } } } ae_vector_set_length(&b, m, _state); if( nzeropart==1||nzeropart==2 ) { for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = (double)(0); } } else { for(i=0; i<=m-1; i++) { b.ptr.p_double[i] = (double)(1); } } /* * LSQR */ linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, (double)(0), (double)(0), n, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); /* * Check */ if( !testlinlsqrunit_isitgoodsolution(&a, &b, m, n, 0.0, &x0, testlinlsqrunit_e0, testlinlsqrunit_tolort, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } ae_frame_leave(_state); return result; } /************************************************************************* The test does check, that algorithm correctly displays a progress report. INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_reportcorrectnesstest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_matrix u; ae_matrix v; ae_vector w; ae_vector b; ae_vector x0; ae_vector firstx; ae_vector lastx; double rnorm; double tnorm; ae_int_t sz; ae_int_t n; ae_int_t m; ae_int_t lambdai; double mn; double mx; double c; ae_int_t i; ae_int_t j; ae_int_t its; double tmp; double eps; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&firstx, 0, DT_REAL, _state); ae_vector_init(&lastx, 0, DT_REAL, _state); eps = 0.001; sz = 5; mn = (double)(-100); mx = (double)(100); c = (double)(100); for(m=1; m<=sz; m++) { for(n=1; n<=m; n++) { for(lambdai=0; lambdai<=1; lambdai++) { its = -1; /* *initialize matrix A */ spdmatrixrndcond(m+n, c, &a, _state); for(i=m; i<=m+n-1; i++) { for(j=0; j<=n-1; j++) { if( i-m==j ) { a.ptr.pp_double[i][j] = (double)(lambdai); } else { a.ptr.pp_double[i][j] = (double)(0); } } } /* *initialize b */ ae_vector_set_length(&b, m+n, _state); rnorm = (double)(0); for(i=0; i<=m+n-1; i++) { if( imaxits||rep.terminationtype<=0 ) { if( !silent ) { printf("StoppingCriteriaTest::Fail\n"); printf("N=%0d\n", (int)(n)); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); } result = ae_true; ae_frame_leave(_state); return result; } /* * Test EpsB. * Set EpsB=eps, check that |r|=2) and using first N-1 columns as rectangular * system matrix, and sum of all columns with random non-zero coefficients * as right part. */ for(n=2; n<=sz; n++) { for(k0=-1; k0<=1; k0++) { for(k1=-1; k1<=1; k1++) { /* * Initialize A with non-unit norm 10^(10*K0), b with non-unit norm 10^(10*K1) */ anorm = ae_pow((double)(10), (double)(10*k0), _state); rmatrixrndorthogonal(n, &a, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = anorm*a.ptr.pp_double[i][j]; } } ae_vector_set_length(&b, n, _state); for(j=0; j<=n-1; j++) { b.ptr.p_double[j] = (double)(0); } for(i=0; i<=n-1; i++) { tmp = 1+ae_randomreal(_state); ae_v_addd(&b.ptr.p_double[0], 1, &a.ptr.pp_double[0][i], a.stride, ae_v_len(0,n-1), tmp); } tmp = (double)(0); for(i=0; i<=n-1; i++) { tmp = tmp+ae_sqr(b.ptr.p_double[i], _state); } tmp = ae_pow((double)(10), (double)(10*k1), _state)/ae_sqrt(tmp, _state); ae_v_muld(&b.ptr.p_double[0], 1, ae_v_len(0,n-1), tmp); /* * Test EpsA * * NOTE: it is guaranteed that algorithm will terminate with correct * TerminationType because other stopping criteria (EpsB) won't be satisfied * on such system. */ eps = ae_pow((double)(10), (double)(-(2+ae_randominteger(3, _state))), _state); epsmod = 1.1*eps; linlsqrcreate(n, n-1, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, eps, (double)(0), 0, _state); while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-2; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-2; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } } linlsqrresults(&s, &x0, &rep, _state); /* * Check condition */ ae_vector_set_length(&rk, n, _state); ae_vector_set_length(&ark, n-1, _state); rknorm = (double)(0); for(i=0; i<=n-1; i++) { rk.ptr.p_double[i] = b.ptr.p_double[i]; for(j=0; j<=n-2; j++) { rk.ptr.p_double[i] = rk.ptr.p_double[i]-a.ptr.pp_double[i][j]*x0.ptr.p_double[j]; } rknorm = rknorm+ae_sqr(rk.ptr.p_double[i], _state); } rknorm = ae_sqrt(rknorm, _state); arknorm = (double)(0); for(i=0; i<=n-2; i++) { ark.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { ark.ptr.p_double[i] = ark.ptr.p_double[i]+a.ptr.pp_double[j][i]*rk.ptr.p_double[j]; } arknorm = arknorm+ae_sqr(ark.ptr.p_double[i], _state); } arknorm = ae_sqrt(arknorm, _state); if( ae_fp_greater(arknorm/(anorm*rknorm),epsmod)||rep.terminationtype!=4 ) { if( !silent ) { printf("StoppingCriteriaTest::Fail\n"); printf("N=%0d\n", (int)(n)); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); } result = ae_true; ae_frame_leave(_state); return result; } } } } if( !silent ) { printf("StoppingCriteriaTest::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This test compares LSQR for original system A*x=b against CG for a modified system (A'*A)x = A*b. Both algorithms should give same sequences of trial points (under exact arithmetics, or for very good conditioned systems). INPUT: Silent - if true then function does not output report -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_analytictest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_matrix xk; ae_matrix ap; ae_matrix r; ae_vector b; ae_vector tmp; ae_int_t n; ae_int_t m; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t smallk; ae_int_t pointsstored; double v; double tol; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&xk, 0, 0, DT_REAL, _state); ae_matrix_init(&ap, 0, 0, DT_REAL, _state); ae_matrix_init(&r, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); /* * Set: * * SmallK - number of steps to check, must be small number in order * to reduce influence of the rounding errors * * Tol - error tolerance for orthogonality/conjugacy criteria */ result = ae_false; smallk = 4; tol = 1.0E-7; for(m=smallk; m<=smallk+5; m++) { for(n=smallk; n<=m; n++) { /* * Prepare problem: * * MxN matrix A, Mx1 vector B * * A is filled with random values from [-1,+1] * * diagonal elements are filled with large positive values * (should make system better conditioned) */ ae_matrix_set_length(&a, m, n, _state); ae_vector_set_length(&b, m, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=n-1; i++) { a.ptr.pp_double[i][i] = 10*(1+ae_randomreal(_state)); } /* * Solve with LSQR, save trial points into XK[] array */ ae_matrix_set_length(&xk, smallk+1, n, _state); linlsqrcreate(m, n, &s, _state); linlsqrsetb(&s, &b, _state); linlsqrsetcond(&s, (double)(0), (double)(0), smallk, _state); linlsqrsetxrep(&s, ae_true, _state); pointsstored = 0; while(linlsqriteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=m-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needmtv ) { for(i=0; i<=n-1; i++) { s.mtv.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { s.mtv.ptr.p_double[i] = s.mtv.ptr.p_double[i]+a.ptr.pp_double[j][i]*s.x.ptr.p_double[j]; } } } if( s.xupdated ) { ae_assert(pointsstoredj * * (p[i]^T)*A'*A*p[j]=0 for i<>j * where r[i]=(A'*A)*x[i]-A'*b is I-th residual , p[i] is I-th step. * * In order to test these criteria we generate two matrices: * * (PointsStored-1)*M matrix AP (matrix of A*p products) * * (PointsStored-1)*N matrix R (matrix of residuals) * Then, we check that each matrix has orthogonal rows. */ ae_matrix_set_length(&ap, pointsstored-1, m, _state); ae_matrix_set_length(&r, pointsstored-1, n, _state); ae_vector_set_length(&tmp, m, _state); for(k=0; k<=pointsstored-2; k++) { /* * Calculate K-th row of AP */ for(i=0; i<=m-1; i++) { ap.ptr.pp_double[k][i] = 0.0; for(j=0; j<=n-1; j++) { ap.ptr.pp_double[k][i] = ap.ptr.pp_double[k][i]+a.ptr.pp_double[i][j]*(xk.ptr.pp_double[k+1][j]-xk.ptr.pp_double[k][j]); } } /* * Calculate K-th row of R */ for(i=0; i<=m-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1)); tmp.ptr.p_double[i] = v-b.ptr.p_double[i]; } for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&a.ptr.pp_double[0][j], a.stride, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); r.ptr.pp_double[k][j] = v; } } for(i=0; i<=pointsstored-2; i++) { for(j=0; j<=pointsstored-2; j++) { if( i!=j ) { v = ae_v_dotproduct(&ap.ptr.pp_double[i][0], 1, &ap.ptr.pp_double[j][0], 1, ae_v_len(0,m-1)); result = result||ae_fp_greater(ae_fabs(v, _state),tol); v = ae_v_dotproduct(&r.ptr.pp_double[i][0], 1, &r.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); result = result||ae_fp_greater(ae_fabs(v, _state),tol); } } } } } ae_frame_leave(_state); return result; } /************************************************************************* This function compares solution calculated by LSQR with one calculated by SVD solver. Following comparisons are performed: 1. either: 1.a) residual norm |Rk| for LSQR solution is at most epsErr*|B| 1.b) |A^T*Rk|/(|A|*|Rk|)<=EpsOrt 2. norm(LSQR_solution) is at most 1.2*norm(SVD_solution) Test (1) verifies that LSQR found good solution, test (2) verifies that LSQR finds solution with close-to-minimum norm. We use factor as large as 1.2 to test deviation from SVD solution because LSQR is not very good at solving degenerate problems. INPUT PARAMETERS: A - array[M,N], system matrix B - right part M, N - problem size LambdaV - regularization value for the problem, >=0 X - array[N], solution found by LSQR EpsErr - tolerance for |A*x-b| EpsOrt - tolerance for |A^T*Rk|/(|A|*|Rk|) RESULT True, for solution which passess all the tests *************************************************************************/ static ae_bool testlinlsqrunit_isitgoodsolution(/* Real */ ae_matrix* a, /* Real */ ae_vector* b, ae_int_t m, ae_int_t n, double lambdav, /* Real */ ae_vector* x, double epserr, double epsort, ae_state *_state) { ae_frame _frame_block; ae_matrix svda; ae_matrix u; ae_matrix vt; ae_vector w; ae_vector svdx; ae_vector tmparr; ae_vector r; ae_int_t i; ae_int_t j; ae_int_t minmn; ae_bool svdresult; double v; double rnorm; double bnorm; double anorm; double atrnorm; double xnorm; double svdxnorm; ae_bool clause1holds; ae_bool clause2holds; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&svda, 0, 0, DT_REAL, _state); ae_matrix_init(&u, 0, 0, DT_REAL, _state); ae_matrix_init(&vt, 0, 0, DT_REAL, _state); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&svdx, 0, DT_REAL, _state); ae_vector_init(&tmparr, 0, DT_REAL, _state); ae_vector_init(&r, 0, DT_REAL, _state); /* * Solve regularized problem with SVD solver */ ae_matrix_set_length(&svda, m+n, n, _state); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { svda.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } for(i=m; i<=m+n-1; i++) { for(j=0; j<=n-1; j++) { if( i-m==j ) { svda.ptr.pp_double[i][j] = lambdav; } else { svda.ptr.pp_double[i][j] = (double)(0); } } } svdresult = rmatrixsvd(&svda, m+n, n, 1, 1, 0, &w, &u, &vt, _state); ae_assert(svdresult, "LINLSQR: internal error in unit test (SVD failed)", _state); minmn = ae_minint(m, n, _state); ae_vector_set_length(&svdx, n, _state); ae_vector_set_length(&tmparr, minmn, _state); for(i=0; i<=minmn-1; i++) { tmparr.ptr.p_double[i] = (double)(0); for(j=0; j<=m-1; j++) { tmparr.ptr.p_double[i] = tmparr.ptr.p_double[i]+u.ptr.pp_double[j][i]*b->ptr.p_double[j]; } if( ae_fp_less_eq(w.ptr.p_double[i],ae_sqrt(ae_machineepsilon, _state)*w.ptr.p_double[0]) ) { tmparr.ptr.p_double[i] = (double)(0); } else { tmparr.ptr.p_double[i] = tmparr.ptr.p_double[i]/w.ptr.p_double[i]; } } for(i=0; i<=n-1; i++) { svdx.ptr.p_double[i] = (double)(0); for(j=0; j<=minmn-1; j++) { svdx.ptr.p_double[i] = svdx.ptr.p_double[i]+vt.ptr.pp_double[j][i]*tmparr.ptr.p_double[j]; } } /* * Calculate residual, perform checks 1.a and 1.b: * * first, we check 1.a * * in case 1.a fails we check 1.b */ ae_vector_set_length(&r, m+n, _state); for(i=0; i<=m+n-1; i++) { v = ae_v_dotproduct(&svda.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); r.ptr.p_double[i] = v; if( iptr.p_double[i]; } } v = ae_v_dotproduct(&r.ptr.p_double[0], 1, &r.ptr.p_double[0], 1, ae_v_len(0,m+n-1)); rnorm = ae_sqrt(v, _state); v = ae_v_dotproduct(&b->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,m-1)); bnorm = ae_sqrt(v, _state); if( ae_fp_less_eq(rnorm,epserr*bnorm) ) { /* * 1.a is true, no further checks is needed */ clause1holds = ae_true; } else { /* * 1.a is false, we have to check 1.b * * In order to do so, we calculate ||A|| and ||A^T*Rk||. We do * not store product of A and Rk to some array, all we need is * just one component of product at time, stored in V. * */ anorm = (double)(0); atrnorm = (double)(0); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=m+n-1; j++) { v = v+svda.ptr.pp_double[j][i]*r.ptr.p_double[j]; anorm = anorm+ae_sqr(svda.ptr.pp_double[j][i], _state); } atrnorm = atrnorm+ae_sqr(v, _state); } anorm = ae_sqrt(anorm, _state); atrnorm = ae_sqrt(atrnorm, _state); clause1holds = ae_fp_eq(anorm*rnorm,(double)(0))||ae_fp_less_eq(atrnorm/(anorm*rnorm),epsort); } /* * Check (2). * Here we assume that Result=True when we enter this block. */ v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); xnorm = ae_sqrt(v, _state); v = ae_v_dotproduct(&svdx.ptr.p_double[0], 1, &svdx.ptr.p_double[0], 1, ae_v_len(0,n-1)); svdxnorm = ae_sqrt(v, _state); clause2holds = ae_fp_less_eq(xnorm,1.2*svdxnorm); /* * End */ result = clause1holds&&clause2holds; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing preconditioned LSQR method. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlinlsqrunit_preconditionertest(ae_state *_state) { ae_frame _frame_block; linlsqrstate s; linlsqrreport rep; ae_matrix a; ae_matrix ta; sparsematrix sa; ae_vector b; ae_vector d; ae_vector xe; ae_vector x0; ae_bool bflag; ae_int_t i; ae_int_t j; ae_int_t n; ae_bool result; ae_frame_make(_state, &_frame_block); _linlsqrstate_init(&s, _state); _linlsqrreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&ta, 0, 0, DT_REAL, _state); _sparsematrix_init(&sa, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); /* * Test 1. * * We test automatic diagonal preconditioning used by SolveSparse. * In order to do so we: * 1. generate 20*20 matrix A0 with condition number equal to 1.0E1 * 2. generate random "exact" solution xe and right part b=A0*xe * 3. generate random ill-conditioned diagonal scaling matrix D with * condition number equal to 1.0E50: * 4. transform A*x=b into badly scaled problem: * A0*x0=b0 * (A0*D)*(inv(D)*x0)=b0 * finally we got new problem A*x=b with A=A0*D, b=b0, x=inv(D)*x0 * * Then we solve A*x=b: * 1. with default preconditioner * 2. with explicitly activayed diagonal preconditioning * 3. with unit preconditioner. * 1st and 2nd solutions must be close to xe, 3rd solution must be very * far from the true one. */ n = 20; rmatrixrndcond(n, 1.0E1, &ta, _state); ae_vector_set_length(&xe, n, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = randomnormal(_state); } ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { b.ptr.p_double[i] = b.ptr.p_double[i]+ta.ptr.pp_double[i][j]*xe.ptr.p_double[j]; } } ae_vector_set_length(&d, n, _state); for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = ae_pow((double)(10), 100*ae_randomreal(_state)-50, _state); } ae_matrix_set_length(&a, n, n, _state); sparsecreate(n, n, n*n, &sa, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = ta.ptr.pp_double[i][j]*d.ptr.p_double[j]; sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } xe.ptr.p_double[i] = xe.ptr.p_double[i]/d.ptr.p_double[i]; } sparseconverttocrs(&sa, _state); linlsqrcreate(n, n, &s, _state); linlsqrsetcond(&s, (double)(0), (double)(0), 2*n, _state); linlsqrsolvesparse(&s, &sa, &b, _state); linlsqrresults(&s, &x0, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]) ) { result = ae_true; ae_frame_leave(_state); return result; } } linlsqrsetprecunit(&s, _state); linlsqrsolvesparse(&s, &sa, &b, _state); linlsqrresults(&s, &x0, &rep, _state); if( rep.terminationtype>0 ) { bflag = ae_false; for(i=0; i<=n-1; i++) { bflag = bflag||ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]); } if( !bflag ) { result = ae_true; ae_frame_leave(_state); return result; } } linlsqrsetprecdiag(&s, _state); linlsqrsolvesparse(&s, &sa, &b, _state); linlsqrresults(&s, &x0, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* *test has been passed */ result = ae_false; ae_frame_leave(_state); return result; } static ae_int_t testrbfunit_mxnx = 3; static double testrbfunit_eps = 1.0E-6; static double testrbfunit_tol = 1.0E-10; static ae_int_t testrbfunit_mxits = 0; static double testrbfunit_heps = 1.0E-12; static ae_bool testrbfunit_specialtest(ae_state *_state); static ae_bool testrbfunit_basicrbftest(ae_state *_state); static ae_bool testrbfunit_irregularrbftest(ae_state *_state); static ae_bool testrbfunit_linearitymodelrbftest(ae_state *_state); static ae_bool testrbfunit_serializationtest(ae_state *_state); static ae_bool testrbfunit_searcherr(/* Real */ ae_matrix* y0, /* Real */ ae_matrix* y1, ae_int_t n, ae_int_t ny, ae_int_t errtype, /* Real */ ae_vector* b1, /* Real */ ae_vector* delta, ae_state *_state); static ae_bool testrbfunit_basicmultilayerrbftest(ae_state *_state); ae_bool testrbf(ae_bool silent, ae_state *_state) { ae_bool specialerrors; ae_bool basicrbferrors; ae_bool irregularrbferrors; ae_bool linearitymodelrbferr; ae_bool sqrdegmatrixrbferr; ae_bool sererrors; ae_bool multilayerrbf1derrors; ae_bool multilayerrbferrors; ae_bool waserrors; ae_bool result; specialerrors = testrbfunit_specialtest(_state); basicrbferrors = testrbfunit_basicrbftest(_state); irregularrbferrors = testrbfunit_irregularrbftest(_state); linearitymodelrbferr = testrbfunit_linearitymodelrbftest(_state); sqrdegmatrixrbferr = sqrdegmatrixrbftest(ae_true, _state); multilayerrbf1derrors = ae_false; multilayerrbferrors = testrbfunit_basicmultilayerrbftest(_state); sererrors = testrbfunit_serializationtest(_state); /* * report */ waserrors = ((((((specialerrors||basicrbferrors)||irregularrbferrors)||linearitymodelrbferr)||sqrdegmatrixrbferr)||sererrors)||multilayerrbf1derrors)||multilayerrbferrors; if( !silent ) { printf("TESTING RBF\n"); printf("Special cases: "); if( specialerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BasicRBFTest: "); if( basicrbferrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("IrregularRBFTest: "); if( irregularrbferrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LinearityModelRBFTest: "); if( linearitymodelrbferr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("SqrDegMatrixRBFTest: "); if( sqrdegmatrixrbferr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("Serialization test: "); if( sererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MultiLayerRBFErrors in 1D test: "); if( multilayerrbf1derrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("MultiLayerRBFErrors in 2-3D test: "); if( multilayerrbferrors ) { printf("FAILED\n"); } else { printf("OK\n"); } /* * was errors? */ if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testrbf(ae_bool silent, ae_state *_state) { return testrbf(silent, _state); } /************************************************************************* The test has to check, that algorithm can solve problems of matrix are degenerate. * used model with linear term; * points locate in a subspace of dimension less than an original space. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ ae_bool sqrdegmatrixrbftest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t np; double sx; double sy; double zx; double px; double zy; double py; double q; double z; ae_vector point; ae_matrix a; ae_vector d0; ae_vector d1; ae_int_t gen; ae_vector pvd0; ae_vector pvd1; double pvdnorm; double vnorm; double dd0; double dd1; ae_matrix gp; ae_vector x; ae_vector y; ae_int_t unx; ae_int_t uny; ae_matrix xwr; ae_matrix v; ae_int_t i; ae_int_t j; ae_int_t k; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&point, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&d0, 0, DT_REAL, _state); ae_vector_init(&d1, 0, DT_REAL, _state); ae_vector_init(&pvd0, 0, DT_REAL, _state); ae_vector_init(&pvd1, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&xwr, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); zx = (double)(10); px = (double)(15); zy = (double)(10); py = (double)(15); ny = 1; for(nx=2; nx<=3; nx++) { /* * prepare test problem */ sx = ae_pow(zx, px*(ae_randominteger(3, _state)-1), _state); sy = ae_pow(zy, py*(ae_randominteger(3, _state)-1), _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&point, nx, _state); rbfcreate(nx, ny, &s, _state); rbfsetcond(&s, testrbfunit_heps, testrbfunit_heps, testrbfunit_mxits, _state); q = 0.25+ae_randomreal(_state); z = 4.5+ae_randomreal(_state); rbfsetalgoqnn(&s, q, z, _state); /* * start points for grid */ for(i=0; i<=nx-1; i++) { point.ptr.p_double[i] = sx*(2*ae_randomreal(_state)-1); } if( nx==2 ) { for(k0=2; k0<=4; k0++) { rmatrixrndorthogonal(nx, &a, _state); ae_vector_set_length(&d0, nx, _state); ae_v_move(&d0.ptr.p_double[0], 1, &a.ptr.pp_double[0][0], a.stride, ae_v_len(0,nx-1)); np = k0; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { gp.ptr.pp_double[i][0] = point.ptr.p_double[0]+sx*i*d0.ptr.p_double[0]; gp.ptr.pp_double[i][1] = point.ptr.p_double[1]+sx*i*d0.ptr.p_double[1]; for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i][nx+k] = sy*(2*ae_randomreal(_state)-1); } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } if( nx==3 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { for(gen=1; gen<=2; gen++) { rmatrixrndorthogonal(nx, &a, _state); ae_vector_set_length(&d0, nx, _state); ae_v_move(&d0.ptr.p_double[0], 1, &a.ptr.pp_double[0][0], a.stride, ae_v_len(0,nx-1)); /* * create grid */ np = -1; if( gen==1 ) { np = k0; ae_matrix_set_length(&gp, np, nx+ny, _state); for(i=0; i<=k0-1; i++) { gp.ptr.pp_double[i][0] = point.ptr.p_double[0]+sx*i*d0.ptr.p_double[0]; gp.ptr.pp_double[i][1] = point.ptr.p_double[1]+sx*i*d0.ptr.p_double[1]; gp.ptr.pp_double[i][2] = point.ptr.p_double[2]+sx*i*d0.ptr.p_double[2]; for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i][nx+k] = sy*(2*ae_randomreal(_state)-1); } } } if( gen==2 ) { ae_vector_set_length(&d1, nx, _state); ae_v_move(&d1.ptr.p_double[0], 1, &a.ptr.pp_double[0][1], a.stride, ae_v_len(0,nx-1)); np = k0*k1; ae_matrix_set_length(&gp, np, nx+ny, _state); for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { gp.ptr.pp_double[i*k1+j][0] = sx*i*d0.ptr.p_double[0]+sx*j*d1.ptr.p_double[0]; gp.ptr.pp_double[i*k1+j][1] = sx*i*d0.ptr.p_double[1]+sx*j*d1.ptr.p_double[1]; gp.ptr.pp_double[i*k1+j][2] = sx*i*d0.ptr.p_double[2]+sx*j*d1.ptr.p_double[2]; for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i*k1+j][nx+k] = sy*(2*ae_randomreal(_state)-1); } } } } ae_assert(np>=0, "rbf test: integrity error", _state); rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; x.ptr.p_double[2] = gp.ptr.pp_double[i][2]; rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } if( gen==2 ) { rbfunpack(&s, &unx, &uny, &xwr, &np, &v, _state); dd0 = (d0.ptr.p_double[0]*v.ptr.pp_double[0][0]+d0.ptr.p_double[1]*v.ptr.pp_double[0][1]+d0.ptr.p_double[2]*v.ptr.pp_double[0][2])/(d0.ptr.p_double[0]*d0.ptr.p_double[0]+d0.ptr.p_double[1]*d0.ptr.p_double[1]+d0.ptr.p_double[2]*d0.ptr.p_double[2]); dd1 = (d1.ptr.p_double[0]*v.ptr.pp_double[0][0]+d1.ptr.p_double[1]*v.ptr.pp_double[0][1]+d1.ptr.p_double[2]*v.ptr.pp_double[0][2])/(d1.ptr.p_double[0]*d1.ptr.p_double[0]+d1.ptr.p_double[1]*d1.ptr.p_double[1]+d1.ptr.p_double[2]*d1.ptr.p_double[2]); ae_vector_set_length(&pvd0, nx, _state); ae_vector_set_length(&pvd1, nx, _state); for(i=0; i<=nx-1; i++) { pvd0.ptr.p_double[i] = dd0*d0.ptr.p_double[i]; pvd1.ptr.p_double[i] = dd1*d1.ptr.p_double[i]; } pvdnorm = ae_sqrt(ae_sqr(v.ptr.pp_double[0][0]-pvd0.ptr.p_double[0]-pvd1.ptr.p_double[0], _state)+ae_sqr(v.ptr.pp_double[0][1]-pvd0.ptr.p_double[1]-pvd1.ptr.p_double[1], _state)+ae_sqr(v.ptr.pp_double[0][2]-pvd0.ptr.p_double[2]-pvd1.ptr.p_double[2], _state), _state); vnorm = ae_sqrt(ae_sqr(v.ptr.pp_double[0][0], _state)+ae_sqr(v.ptr.pp_double[0][1], _state)+ae_sqr(v.ptr.pp_double[0][2], _state), _state); if( ae_fp_greater(pvdnorm,vnorm*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing basic functionality of RBF module on regular grids with multi-layer algorithm in 1D. -- ALGLIB -- Copyright 2.03.2012 by Bochkanov Sergey *************************************************************************/ ae_bool basicmultilayerrbf1dtest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t linterm; ae_int_t n; double q; double r; ae_int_t errtype; ae_vector delta; ae_int_t nlayers; double a; double b; double f1; double f2; ae_vector a1; ae_vector b1; ae_matrix gp; ae_vector x; ae_vector y; ae_matrix mody0; ae_matrix mody1; ae_matrix gy; ae_vector gpgx0; ae_vector gpgx1; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&delta, 0, DT_REAL, _state); ae_vector_init(&a1, 0, DT_REAL, _state); ae_vector_init(&b1, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&mody0, 0, 0, DT_REAL, _state); ae_matrix_init(&mody1, 0, 0, DT_REAL, _state); ae_matrix_init(&gy, 0, 0, DT_REAL, _state); ae_vector_init(&gpgx0, 0, DT_REAL, _state); ae_vector_init(&gpgx1, 0, DT_REAL, _state); a = 1.0; b = (double)1/(double)9; f1 = 1.0; f2 = 10.0; passcount = 5; n = 100; ae_vector_set_length(&gpgx0, n, _state); ae_vector_set_length(&gpgx1, n, _state); for(i=0; i<=n-1; i++) { gpgx0.ptr.p_double[i] = (double)i/(double)n; gpgx1.ptr.p_double[i] = (double)(0); } r = (double)(1); for(pass=0; pass<=passcount-1; pass++) { nx = ae_randominteger(2, _state)+2; ny = ae_randominteger(3, _state)+1; linterm = ae_randominteger(3, _state)+1; ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&a1, ny, _state); ae_vector_set_length(&b1, ny, _state); ae_vector_set_length(&delta, ny, _state); ae_matrix_set_length(&mody0, n, ny, _state); ae_matrix_set_length(&mody1, n, ny, _state); for(i=0; i<=ny-1; i++) { a1.ptr.p_double[i] = a+0.01*a*(2*ae_randomreal(_state)-1); b1.ptr.p_double[i] = b+0.01*b*(2*ae_randomreal(_state)-1); delta.ptr.p_double[i] = 0.35*b1.ptr.p_double[i]; } ae_matrix_set_length(&gp, n, nx+ny, _state); /* * create grid */ for(i=0; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { gp.ptr.pp_double[i][j] = (double)(0); } gp.ptr.pp_double[i][0] = (double)i/(double)n; for(j=0; j<=ny-1; j++) { gp.ptr.pp_double[i][nx+j] = a1.ptr.p_double[j]*ae_cos(f1*2*ae_pi*gp.ptr.pp_double[i][0], _state)+b1.ptr.p_double[j]*ae_cos(f2*2*ae_pi*gp.ptr.pp_double[i][0], _state); mody0.ptr.pp_double[i][j] = gp.ptr.pp_double[i][nx+j]; } } q = (double)(1); nlayers = 1; errtype = 1; /* * test multilayer algorithm with different parameters */ while(ae_fp_greater_eq(q,1/(2*f2))) { rbfcreate(nx, ny, &s, _state); rbfsetalgomultilayer(&s, r, nlayers, 0.0, _state); if( linterm==1 ) { rbfsetlinterm(&s, _state); } if( linterm==2 ) { rbfsetconstterm(&s, _state); } if( linterm==3 ) { rbfsetzeroterm(&s, _state); } rbfsetpoints(&s, &gp, n, _state); rbfbuildmodel(&s, &rep, _state); if( ny==1 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { x.ptr.p_double[j] = gp.ptr.pp_double[i][j]; } if( nx==2 ) { mody1.ptr.pp_double[i][0] = rbfcalc2(&s, x.ptr.p_double[0], x.ptr.p_double[1], _state); } else { if( nx==3 ) { mody1.ptr.pp_double[i][0] = rbfcalc3(&s, x.ptr.p_double[0], x.ptr.p_double[1], x.ptr.p_double[2], _state); } else { ae_assert(ae_false, "BasicMultiLayerRBFTest1D: Invalid variable NX(NX neither 2 nor 3)", _state); } } } if( testrbfunit_searcherr(&mody0, &mody1, n, ny, errtype, &b1, &delta, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } if( nx==2 ) { rbfgridcalc2(&s, &gpgx0, n, &gpgx1, n, &gy, _state); for(i=0; i<=n-1; i++) { mody1.ptr.pp_double[i][0] = gy.ptr.pp_double[i][0]; } } if( testrbfunit_searcherr(&mody0, &mody1, n, ny, errtype, &b1, &delta, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } } for(i=0; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { x.ptr.p_double[j] = gp.ptr.pp_double[i][j]; } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { mody1.ptr.pp_double[i][j] = y.ptr.p_double[j]; } } if( testrbfunit_searcherr(&mody0, &mody1, n, ny, errtype, &b1, &delta, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { for(j=0; j<=nx-1; j++) { x.ptr.p_double[j] = gp.ptr.pp_double[i][j]; } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { mody1.ptr.pp_double[i][j] = y.ptr.p_double[j]; } } if( testrbfunit_searcherr(&mody0, &mody1, n, ny, errtype, &b1, &delta, _state) ) { result = ae_true; ae_frame_leave(_state); return result; } q = q/2; nlayers = nlayers+1; if( errtype==1&&ae_fp_less_eq(q,1/f2) ) { errtype = 2; } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests special cases: * uninitialized RBF model will correctly return zero values * RBF correctly handles 1 or 2 distinct points * when we have many uniformly spaced points and one outlier, filter which is applied to radii, makes all radii equal. * RBF with NLayers=0 gives linear model -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_specialtest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t n; ae_int_t nx; ae_int_t ny; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t t; ae_matrix xy; ae_vector x; ae_vector y; ae_int_t termtype; double errtol; ae_int_t tmpnx; ae_int_t tmpny; ae_int_t tmpnc; ae_matrix xwr; ae_matrix v; double sx; double z; double va; double vb; double vc; double vd; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&xwr, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); errtol = 1.0E-9; result = ae_false; /* * Create model in the default state (no parameters/points specified). * With probability 0.5 we do one of the following: * * test that default state of the model is a zero model (all Calc() * functions return zero) * * call RBFBuildModel() (without specifying anything) and test that * all Calc() functions return zero. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { rbfcreate(nx, ny, &s, _state); if( ae_fp_greater(ae_randomreal(_state),0.5) ) { rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } } ae_vector_set_length(&x, nx, _state); for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } rbfcalc(&s, &x, &y, _state); if( y.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=ny-1; i++) { if( ae_fp_neq(y.ptr.p_double[i],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } /* * Create model with 1 point and different types of linear term. * Test algorithm on such dataset. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { rbfcreate(nx, ny, &s, _state); for(termtype=0; termtype<=2; termtype++) { if( termtype==0 ) { rbfsetlinterm(&s, _state); } if( termtype==1 ) { rbfsetconstterm(&s, _state); } if( termtype==2 ) { rbfsetzeroterm(&s, _state); } ae_matrix_set_length(&xy, 1, nx+ny, _state); for(i=0; i<=nx+ny-1; i++) { xy.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; } rbfsetpoints(&s, &xy, 1, _state); rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } /* * First, test that model exactly reproduces our dataset */ ae_vector_set_length(&x, nx, _state); for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = xy.ptr.pp_double[0][i]; } rbfcalc(&s, &x, &y, _state); if( y.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=ny-1; i++) { if( ae_fp_greater(ae_fabs(y.ptr.p_double[i]-xy.ptr.pp_double[0][nx+i], _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Second, test that model is constant unless it has zero polynomial term * (in the latter case we have small "bump" around lone interpolation center) */ if( termtype==0||termtype==1 ) { for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } rbfcalc(&s, &x, &y, _state); if( y.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=ny-1; i++) { if( ae_fp_greater(ae_fabs(y.ptr.p_double[i]-xy.ptr.pp_double[0][nx+i], _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } /* * Create model with 2 points and different types of linear term. * Test algorithm on such dataset. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { rbfcreate(nx, ny, &s, _state); for(termtype=0; termtype<=2; termtype++) { if( termtype==0 ) { rbfsetlinterm(&s, _state); } if( termtype==1 ) { rbfsetconstterm(&s, _state); } if( termtype==2 ) { rbfsetzeroterm(&s, _state); } ae_matrix_set_length(&xy, 2, nx+ny, _state); for(i=0; i<=nx+ny-1; i++) { xy.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; } for(i=0; i<=nx+ny-1; i++) { xy.ptr.pp_double[1][i] = xy.ptr.pp_double[0][i]+1.0; } rbfsetpoints(&s, &xy, 2, _state); rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } for(j=0; j<=1; j++) { ae_vector_set_length(&x, nx, _state); for(i=0; i<=nx-1; i++) { x.ptr.p_double[i] = xy.ptr.pp_double[j][i]; } rbfcalc(&s, &x, &y, _state); if( y.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=ny-1; i++) { if( ae_fp_greater(ae_fabs(y.ptr.p_double[i]-xy.ptr.pp_double[j][nx+i], _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } /* * Generate a set of points (xi,yi) = (SX*i,0), and one * outlier (x_far,y_far)=(-1000*SX,0). * * Radii filtering should place a bound on the radius of outlier. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { sx = ae_exp(-5+10*ae_randomreal(_state), _state); rbfcreate(nx, ny, &s, _state); ae_matrix_set_length(&xy, 20, nx+ny, _state); for(i=0; i<=xy.rows-1; i++) { xy.ptr.pp_double[i][0] = sx*i; for(j=1; j<=nx-1; j++) { xy.ptr.pp_double[i][j] = (double)(0); } for(j=0; j<=ny-1; j++) { xy.ptr.pp_double[i][nx+j] = ae_randomreal(_state); } } xy.ptr.pp_double[xy.rows-1][0] = -1000*sx; rbfsetpoints(&s, &xy, xy.rows, _state); /* * Try random Z from [1,5] */ z = 1+ae_randomreal(_state)*4; rbfsetalgoqnn(&s, 1.0, z, _state); rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } rbfunpack(&s, &tmpnx, &tmpny, &xwr, &tmpnc, &v, _state); if( (((tmpnx!=nx||tmpny!=ny)||tmpnc!=xy.rows)||xwr.cols!=nx+ny+1)||xwr.rows!=tmpnc ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=tmpnc-2; i++) { if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[i][nx+ny]-sx, _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[tmpnc-1][nx+ny]-z*sx, _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * RBF with NLayers=0 gives us linear model. * * In order to perform this test, we use test function which * is perfectly linear and see whether RBF model is able to * reproduce such function. */ n = 5; for(ny=1; ny<=3; ny++) { va = 2*ae_randomreal(_state)-1; vb = 2*ae_randomreal(_state)-1; vc = 2*ae_randomreal(_state)-1; vd = 2*ae_randomreal(_state)-1; /* * Test NX=2. * Generate linear function using random coefficients VA/VB/VC. * Function is K-dimensional vector-valued, each component has slightly * different coefficients. */ ae_matrix_set_length(&xy, n*n, 2+ny, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { xy.ptr.pp_double[n*i+j][0] = (double)(i); xy.ptr.pp_double[n*i+j][1] = (double)(j); for(k=0; k<=ny-1; k++) { xy.ptr.pp_double[n*i+j][2+k] = (va+0.1*k)*i+(vb+0.2*k)*j+(vc+0.3*k); } } } rbfcreate(2, ny, &s, _state); rbfsetpoints(&s, &xy, n*n, _state); rbfsetalgomultilayer(&s, 1.0, 0, 0.01, _state); rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = (n-1)*ae_randomreal(_state); x.ptr.p_double[1] = (n-1)*ae_randomreal(_state); if( ny==1&&ae_fp_greater(ae_fabs(rbfcalc2(&s, x.ptr.p_double[0], x.ptr.p_double[1], _state)-(va*x.ptr.p_double[0]+vb*x.ptr.p_double[1]+vc), _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } rbfcalc(&s, &x, &y, _state); for(k=0; k<=ny-1; k++) { if( ae_fp_greater(ae_fabs(y.ptr.p_double[k]-((va+0.1*k)*x.ptr.p_double[0]+(vb+0.2*k)*x.ptr.p_double[1]+(vc+0.3*k)), _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Test NX=3. * Generate linear function using random coefficients VA/VB/VC/VC. * Function is K-dimensional vector-valued, each component has slightly * different coefficients. */ ae_matrix_set_length(&xy, n*n*n, 3+ny, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { for(t=0; t<=n-1; t++) { xy.ptr.pp_double[n*n*i+n*j+t][0] = (double)(i); xy.ptr.pp_double[n*n*i+n*j+t][1] = (double)(j); xy.ptr.pp_double[n*n*i+n*j+t][2] = (double)(t); for(k=0; k<=ny-1; k++) { xy.ptr.pp_double[n*n*i+n*j+t][3+k] = (va+0.1*k)*i+(vb+0.2*k)*j+(vc+0.3*k)*t+(vd+0.4*k); } } } } rbfcreate(3, ny, &s, _state); rbfsetpoints(&s, &xy, n*n*n, _state); rbfsetalgomultilayer(&s, 1.0, 0, 0.01, _state); rbfbuildmodel(&s, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } ae_vector_set_length(&x, 3, _state); x.ptr.p_double[0] = (n-1)*ae_randomreal(_state); x.ptr.p_double[1] = (n-1)*ae_randomreal(_state); x.ptr.p_double[2] = (n-1)*ae_randomreal(_state); if( ny==1&&ae_fp_greater(ae_fabs(rbfcalc3(&s, x.ptr.p_double[0], x.ptr.p_double[1], x.ptr.p_double[2], _state)-(va*x.ptr.p_double[0]+vb*x.ptr.p_double[1]+vc*x.ptr.p_double[2]+vd), _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } rbfcalc(&s, &x, &y, _state); for(k=0; k<=ny-1; k++) { if( ae_fp_greater(ae_fabs(y.ptr.p_double[k]-((va+0.1*k)*x.ptr.p_double[0]+(vb+0.2*k)*x.ptr.p_double[1]+(vc+0.3*k)*x.ptr.p_double[2]+(vd+0.4*k)), _state),errtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } ae_frame_leave(_state); return result; } /************************************************************************* Function for testing basic functionality of RBF module on regular grids. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_basicrbftest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t k2; ae_int_t linterm; ae_int_t np; double sx; double sy; double zx; double px; double zy; double py; double q; double z; ae_vector point; ae_matrix gp; ae_vector x; ae_vector y; ae_matrix gy; ae_int_t unx; ae_int_t uny; ae_matrix xwr; ae_matrix v; ae_vector gpgx0; ae_vector gpgx1; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&point, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&gy, 0, 0, DT_REAL, _state); ae_matrix_init(&xwr, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); ae_vector_init(&gpgx0, 0, DT_REAL, _state); ae_vector_init(&gpgx1, 0, DT_REAL, _state); zx = (double)(10); px = (double)(15); zy = (double)(10); py = (double)(15); /* * Problem types: * * 2 and 3-dimensional problems * * problems with zero, constant, linear terms * * different scalings of X and Y values (1.0, 1E-15, 1E+15) * * regular grids different grid sizes (from 2 to 4 points for each dimension) * * We check that: * * RBF model correctly reproduces function value (testes with different Calc() functions) * * unpacked model containt correct radii * * linear term has correct form */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { for(linterm=1; linterm<=3; linterm++) { /* * prepare test problem */ sx = ae_pow(zx, px*(ae_randominteger(3, _state)-1), _state); sy = ae_pow(zy, py*(ae_randominteger(3, _state)-1), _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&point, nx, _state); rbfcreate(nx, ny, &s, _state); rbfsetcond(&s, testrbfunit_heps, testrbfunit_heps, testrbfunit_mxits, _state); q = 0.25+ae_randomreal(_state); z = 4.5+ae_randomreal(_state); rbfsetalgoqnn(&s, q, z, _state); if( linterm==1 ) { rbfsetlinterm(&s, _state); } if( linterm==2 ) { rbfsetconstterm(&s, _state); } if( linterm==3 ) { rbfsetzeroterm(&s, _state); } /* * start points for grid */ for(i=0; i<=nx-1; i++) { point.ptr.p_double[i] = sx*(2*ae_randomreal(_state)-1); } /* * 2-dimensional test problem */ if( nx==2 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { np = k0*k1; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { gp.ptr.pp_double[i*k1+j][0] = point.ptr.p_double[0]+sx*i; gp.ptr.pp_double[i*k1+j][1] = point.ptr.p_double[1]+sx*j; for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i*k1+j][nx+k] = sy*(2*ae_randomreal(_state)-1); } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); if( ny==1 ) { ae_vector_set_length(&gpgx0, k0, _state); ae_vector_set_length(&gpgx1, k1, _state); for(i=0; i<=k0-1; i++) { gpgx0.ptr.p_double[i] = point.ptr.p_double[0]+sx*i; } for(i=0; i<=k1-1; i++) { gpgx1.ptr.p_double[i] = point.ptr.p_double[1]+sx*i; } rbfgridcalc2(&s, &gpgx0, k0, &gpgx1, k1, &gy, _state); for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { if( ae_fp_greater(ae_fabs(gy.ptr.pp_double[i][j]-gp.ptr.pp_double[i*k1+j][nx], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc2(&s, x.ptr.p_double[0], x.ptr.p_double[1], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * test for RBFUnpack */ rbfunpack(&s, &unx, &uny, &xwr, &np, &v, _state); if( ((((nx!=unx||ny!=uny)||xwr.rows!=np)||xwr.cols!=nx+ny+1)||v.rows!=ny)||v.cols!=nx+1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=np-1; i++) { if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[i][unx+uny]-q*sx, _state),sx*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( linterm==2 ) { for(i=0; i<=unx-1; i++) { for(j=0; j<=uny-1; j++) { if( ae_fp_neq(v.ptr.pp_double[j][i],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } if( linterm==3 ) { for(i=0; i<=unx; i++) { for(j=0; j<=uny-1; j++) { if( ae_fp_neq(v.ptr.pp_double[j][i],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } /* * 3-dimensional test problems */ if( nx==3 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { for(k2=2; k2<=4; k2++) { np = k0*k1*k2; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { for(k=0; k<=k2-1; k++) { gp.ptr.pp_double[(i*k1+j)*k2+k][0] = point.ptr.p_double[0]+sx*i; gp.ptr.pp_double[(i*k1+j)*k2+k][1] = point.ptr.p_double[1]+sx*j; gp.ptr.pp_double[(i*k1+j)*k2+k][2] = point.ptr.p_double[2]+sx*k; for(l=0; l<=ny-1; l++) { gp.ptr.pp_double[(i*k1+j)*k2+k][nx+l] = sy*(2*ae_randomreal(_state)-1); } } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; x.ptr.p_double[2] = gp.ptr.pp_double[i][2]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc3(&s, x.ptr.p_double[0], x.ptr.p_double[1], x.ptr.p_double[2], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * test for RBFUnpack */ rbfunpack(&s, &unx, &uny, &xwr, &np, &v, _state); if( ((((nx!=unx||ny!=uny)||xwr.rows!=np)||xwr.cols!=nx+ny+1)||v.rows!=ny)||v.cols!=nx+1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=np-1; i++) { if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[i][unx+uny]-q*sx, _state),sx*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( linterm==2 ) { for(i=0; i<=unx-1; i++) { for(j=0; j<=uny-1; j++) { if( ae_fp_neq(v.ptr.pp_double[j][i],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } if( linterm==3 ) { for(i=0; i<=unx; i++) { for(j=0; j<=uny-1; j++) { if( ae_fp_neq(v.ptr.pp_double[j][i],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing RBF module on irregular grids. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_irregularrbftest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t k2; ae_int_t linterm; ae_int_t np; double sx; double sy; double zx; double px; double zy; double py; double q; double z; ae_vector point; ae_matrix gp; ae_vector x; ae_vector y; ae_matrix gy; double noiselevel; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&point, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&gy, 0, 0, DT_REAL, _state); zx = (double)(10); px = (double)(15); zy = (double)(10); py = (double)(15); noiselevel = 0.1; /* * Problem types: * * 2 and 3-dimensional problems * * problems with zero, constant, linear terms * * different scalings of X and Y values (1.0, 1E-15, 1E+15) * * noisy grids, which are just regular grids with different grid sizes * (from 2 to 4 points for each dimension) and moderate amount of random * noise added to all node positions. * * We check that: * * RBF model correctly reproduces function value (testes with different Calc() functions) */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=3; ny++) { for(linterm=1; linterm<=3; linterm++) { /* * prepare test problem */ sx = ae_pow(zx, px*(ae_randominteger(3, _state)-1), _state); sy = ae_pow(zy, py*(ae_randominteger(3, _state)-1), _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&point, nx, _state); rbfcreate(nx, ny, &s, _state); rbfsetcond(&s, testrbfunit_heps, testrbfunit_heps, testrbfunit_mxits, _state); q = 0.25+ae_randomreal(_state); z = 4.5+ae_randomreal(_state); rbfsetalgoqnn(&s, q, z, _state); if( linterm==1 ) { rbfsetlinterm(&s, _state); } if( linterm==2 ) { rbfsetconstterm(&s, _state); } if( linterm==3 ) { rbfsetzeroterm(&s, _state); } /* * start points for grid */ for(i=0; i<=nx-1; i++) { point.ptr.p_double[i] = sx*(2*ae_randomreal(_state)-1); } /* * 2-dimensional test problems */ if( nx==2 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { np = k0*k1; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { gp.ptr.pp_double[i*k1+j][0] = point.ptr.p_double[0]+sx*i+noiselevel*sx*(2*ae_randomreal(_state)-1); gp.ptr.pp_double[i*k1+j][1] = point.ptr.p_double[1]+sx*j+noiselevel*sx*(2*ae_randomreal(_state)-1); for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i*k1+j][nx+k] = sy*(2*ae_randomreal(_state)-1); } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc2(&s, x.ptr.p_double[0], x.ptr.p_double[1], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } /* * 2-dimensional test problems */ if( nx==3 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { for(k2=2; k2<=4; k2++) { np = k0*k1*k2; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { for(k=0; k<=k2-1; k++) { gp.ptr.pp_double[(i*k1+j)*k2+k][0] = point.ptr.p_double[0]+sx*i+noiselevel*sx*(2*ae_randomreal(_state)-1); gp.ptr.pp_double[(i*k1+j)*k2+k][1] = point.ptr.p_double[1]+sx*j+noiselevel*sx*(2*ae_randomreal(_state)-1); gp.ptr.pp_double[(i*k1+j)*k2+k][2] = point.ptr.p_double[2]+sx*k+noiselevel*sx*(2*ae_randomreal(_state)-1); for(l=0; l<=ny-1; l++) { gp.ptr.pp_double[(i*k1+j)*k2+k][nx+l] = sy*(2*ae_randomreal(_state)-1); } } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; x.ptr.p_double[2] = gp.ptr.pp_double[i][2]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc3(&s, x.ptr.p_double[0], x.ptr.p_double[1], x.ptr.p_double[2], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),sy*testrbfunit_eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* The test does check, that algorithm can build linear model for the data sets, when Y depends on X linearly. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_linearitymodelrbftest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t k2; ae_int_t linterm; ae_int_t np; double sx; double sy; double zx; double px; double zy; double py; double q; double z; ae_vector point; ae_vector a; ae_matrix gp; ae_vector x; ae_vector y; ae_int_t unx; ae_int_t uny; ae_matrix xwr; ae_matrix v; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&point, 0, DT_REAL, _state); ae_vector_init(&a, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&xwr, 0, 0, DT_REAL, _state); ae_matrix_init(&v, 0, 0, DT_REAL, _state); zx = (double)(10); px = (double)(15); zy = (double)(10); py = (double)(15); ny = 1; for(nx=2; nx<=3; nx++) { for(linterm=1; linterm<=3; linterm++) { /* * prepare test problem */ sx = ae_pow(zx, px*(ae_randominteger(3, _state)-1), _state); sy = ae_pow(zy, py*(ae_randominteger(3, _state)-1), _state); ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&point, nx, _state); rbfcreate(nx, ny, &s, _state); q = 0.25+ae_randomreal(_state); z = 4.5+ae_randomreal(_state); rbfsetalgoqnn(&s, q, z, _state); ae_vector_set_length(&a, nx+1, _state); if( linterm==1 ) { rbfsetlinterm(&s, _state); for(i=0; i<=nx-1; i++) { a.ptr.p_double[i] = sy*(2*ae_randomreal(_state)-1)/sx; } a.ptr.p_double[nx] = sy*(2*ae_randomreal(_state)-1); } if( linterm==2 ) { rbfsetconstterm(&s, _state); for(i=0; i<=nx-1; i++) { a.ptr.p_double[i] = (double)(0); } a.ptr.p_double[nx] = sy*(2*ae_randomreal(_state)-1); } if( linterm==3 ) { rbfsetzeroterm(&s, _state); for(i=0; i<=nx; i++) { a.ptr.p_double[i] = (double)(0); } } /* * start points for grid */ for(i=0; i<=nx-1; i++) { point.ptr.p_double[i] = sx*(2*ae_randomreal(_state)-1); } if( nx==2 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { np = k0*k1; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { gp.ptr.pp_double[i*k1+j][0] = point.ptr.p_double[0]+sx*i; gp.ptr.pp_double[i*k1+j][1] = point.ptr.p_double[1]+sx*j; gp.ptr.pp_double[i*k1+j][nx] = a.ptr.p_double[nx]; for(k=0; k<=nx-1; k++) { gp.ptr.pp_double[i*k1+j][nx] = gp.ptr.pp_double[i*k1+j][nx]+gp.ptr.pp_double[i*k1+j][k]*a.ptr.p_double[k]; } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); /* * test for RBFUnpack */ rbfunpack(&s, &unx, &uny, &xwr, &np, &v, _state); if( ((((nx!=unx||ny!=uny)||xwr.rows!=np)||xwr.cols!=nx+ny+1)||v.rows!=ny)||v.cols!=nx+1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=nx-1; i++) { if( ae_fp_greater(ae_fabs(v.ptr.pp_double[0][i]-a.ptr.p_double[i], _state),sy/sx*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( ae_fp_greater(ae_fabs(v.ptr.pp_double[0][nx]-a.ptr.p_double[nx], _state),sy*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=np-1; i++) { if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[i][unx], _state),sy*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } if( nx==3 ) { for(k0=2; k0<=4; k0++) { for(k1=2; k1<=4; k1++) { for(k2=2; k2<=4; k2++) { np = k0*k1*k2; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { for(k=0; k<=k2-1; k++) { gp.ptr.pp_double[(i*k1+j)*k2+k][0] = point.ptr.p_double[0]+sx*i; gp.ptr.pp_double[(i*k1+j)*k2+k][1] = point.ptr.p_double[1]+sx*j; gp.ptr.pp_double[(i*k1+j)*k2+k][2] = point.ptr.p_double[2]+sx*k; gp.ptr.pp_double[(i*k1+j)*k2+k][nx] = a.ptr.p_double[nx]; for(l=0; l<=nx-1; l++) { gp.ptr.pp_double[(i*k1+j)*k2+k][nx] = gp.ptr.pp_double[(i*k1+j)*k2+k][nx]+gp.ptr.pp_double[(i*k1+j)*k2+k][l]*a.ptr.p_double[l]; } } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); /* * test for RBFUnpack */ rbfunpack(&s, &unx, &uny, &xwr, &np, &v, _state); if( ((((nx!=unx||ny!=uny)||xwr.rows!=np)||xwr.cols!=nx+ny+1)||v.rows!=ny)||v.cols!=nx+1 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=nx-1; i++) { if( ae_fp_greater(ae_fabs(v.ptr.pp_double[0][i]-a.ptr.p_double[i], _state),sy/sx*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( ae_fp_greater(ae_fabs(v.ptr.pp_double[0][nx]-a.ptr.p_double[nx], _state),sy*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=np-1; i++) { if( ae_fp_greater(ae_fabs(xwr.ptr.pp_double[i][unx], _state),sy*testrbfunit_tol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function tests serialization -- ALGLIB -- Copyright 02.02.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_serializationtest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfmodel s2; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t k2; ae_int_t i0; ae_int_t i1; ae_int_t i2; ae_int_t j; ae_matrix xy; ae_vector testpoint; ae_vector y0; ae_vector y1; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfmodel_init(&s2, _state); _rbfreport_init(&rep, _state); ae_matrix_init(&xy, 0, 0, DT_REAL, _state); ae_vector_init(&testpoint, 0, DT_REAL, _state); ae_vector_init(&y0, 0, DT_REAL, _state); ae_vector_init(&y1, 0, DT_REAL, _state); result = ae_false; /* * This function generates random 2 or 3 dimensional problem, * builds RBF model (QNN is used), serializes/unserializes it, then compares * models by calculating model value at some random point. * * Additionally we test that new model (one which was restored * after serialization) has lost all model construction settings, * i.e. if we call RBFBuildModel() on a NEW model, we will get * empty (zero) model. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=2; ny++) { /* * prepare test problem */ rbfcreate(nx, ny, &s, _state); rbfsetalgoqnn(&s, 1.0, 5.0, _state); rbfsetlinterm(&s, _state); if( nx==2 ) { /* * 2-dimensional problem */ k0 = 2+ae_randominteger(4, _state); k1 = 2+ae_randominteger(4, _state); ae_matrix_set_length(&xy, k0*k1, nx+ny, _state); for(i0=0; i0<=k0-1; i0++) { for(i1=0; i1<=k1-1; i1++) { xy.ptr.pp_double[i0*k1+i1][0] = i0+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1+i1][1] = i1+0.1*(2*ae_randomreal(_state)-1); for(j=0; j<=ny-1; j++) { xy.ptr.pp_double[i0*k1+i1][nx+j] = 2*ae_randomreal(_state)-1; } } } ae_vector_set_length(&testpoint, nx, _state); testpoint.ptr.p_double[0] = ae_randomreal(_state)*(k0-1); testpoint.ptr.p_double[1] = ae_randomreal(_state)*(k1-1); } else { /* * 3-dimensional problem */ k0 = 2+ae_randominteger(4, _state); k1 = 2+ae_randominteger(4, _state); k2 = 2+ae_randominteger(4, _state); ae_matrix_set_length(&xy, k0*k1*k2, nx+ny, _state); for(i0=0; i0<=k0-1; i0++) { for(i1=0; i1<=k1-1; i1++) { for(i2=0; i2<=k2-1; i2++) { xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][0] = i0+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][1] = i1+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][2] = i2+0.1*(2*ae_randomreal(_state)-1); for(j=0; j<=ny-1; j++) { xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][nx+j] = 2*ae_randomreal(_state)-1; } } } } ae_vector_set_length(&testpoint, nx, _state); testpoint.ptr.p_double[0] = ae_randomreal(_state)*(k0-1); testpoint.ptr.p_double[1] = ae_randomreal(_state)*(k1-1); testpoint.ptr.p_double[2] = ae_randomreal(_state)*(k2-1); } rbfsetpoints(&s, &xy, xy.rows, _state); /* * Build model, serialize, compare */ rbfbuildmodel(&s, &rep, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); rbfalloc(&_local_serializer, &s, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rbfserialize(&_local_serializer, &s, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rbfunserialize(&_local_serializer, &s2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } rbfcalc(&s, &testpoint, &y0, _state); rbfcalc(&s2, &testpoint, &y1, _state); if( y0.cnt!=ny||y1.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(j=0; j<=ny-1; j++) { if( ae_fp_neq(y0.ptr.p_double[j],y1.ptr.p_double[j]) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Check that calling RBFBuildModel() on S2 (new model) * will result in construction of zero model, i.e. test * that serialization restores model, but not dataset * which was used to build model. */ rbfbuildmodel(&s2, &rep, _state); rbfcalc(&s2, &testpoint, &y1, _state); if( y1.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(j=0; j<=ny-1; j++) { if( ae_fp_neq(y1.ptr.p_double[j],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } /* * This function generates random 2 or 3 dimensional problem, * builds model using RBF-NN algo, serializes/unserializes it, * then compares models by calculating model value at some * random point. * * Additionally we test that new model (one which was restored * after serialization) has lost all model construction settings, * i.e. if we call RBFBuildModel() on a NEW model, we will get * empty (zero) model. */ for(nx=2; nx<=3; nx++) { for(ny=1; ny<=2; ny++) { /* * prepare test problem */ rbfcreate(nx, ny, &s, _state); rbfsetalgomultilayer(&s, 5.0, 5, 1.0E-3, _state); rbfsetlinterm(&s, _state); if( nx==2 ) { /* * 2-dimensional problem */ k0 = 2+ae_randominteger(4, _state); k1 = 2+ae_randominteger(4, _state); ae_matrix_set_length(&xy, k0*k1, nx+ny, _state); for(i0=0; i0<=k0-1; i0++) { for(i1=0; i1<=k1-1; i1++) { xy.ptr.pp_double[i0*k1+i1][0] = i0+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1+i1][1] = i1+0.1*(2*ae_randomreal(_state)-1); for(j=0; j<=ny-1; j++) { xy.ptr.pp_double[i0*k1+i1][nx+j] = 2*ae_randomreal(_state)-1; } } } ae_vector_set_length(&testpoint, nx, _state); testpoint.ptr.p_double[0] = ae_randomreal(_state)*(k0-1); testpoint.ptr.p_double[1] = ae_randomreal(_state)*(k1-1); } else { /* * 3-dimensional problem */ k0 = 2+ae_randominteger(4, _state); k1 = 2+ae_randominteger(4, _state); k2 = 2+ae_randominteger(4, _state); ae_matrix_set_length(&xy, k0*k1*k2, nx+ny, _state); for(i0=0; i0<=k0-1; i0++) { for(i1=0; i1<=k1-1; i1++) { for(i2=0; i2<=k2-1; i2++) { xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][0] = i0+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][1] = i1+0.1*(2*ae_randomreal(_state)-1); xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][2] = i2+0.1*(2*ae_randomreal(_state)-1); for(j=0; j<=ny-1; j++) { xy.ptr.pp_double[i0*k1*k2+i1*k2+i2][nx+j] = 2*ae_randomreal(_state)-1; } } } } ae_vector_set_length(&testpoint, nx, _state); testpoint.ptr.p_double[0] = ae_randomreal(_state)*(k0-1); testpoint.ptr.p_double[1] = ae_randomreal(_state)*(k1-1); testpoint.ptr.p_double[2] = ae_randomreal(_state)*(k2-1); } rbfsetpoints(&s, &xy, xy.rows, _state); /* * Build model, serialize, compare */ rbfbuildmodel(&s, &rep, _state); { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); rbfalloc(&_local_serializer, &s, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rbfserialize(&_local_serializer, &s, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rbfunserialize(&_local_serializer, &s2, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } rbfcalc(&s, &testpoint, &y0, _state); rbfcalc(&s2, &testpoint, &y1, _state); if( y0.cnt!=ny||y1.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(j=0; j<=ny-1; j++) { if( ae_fp_neq(y0.ptr.p_double[j],y1.ptr.p_double[j]) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* * Check that calling RBFBuildModel() on S2 (new model) * will result in construction of zero model, i.e. test * that serialization restores model, but not dataset * which was used to build model. */ rbfbuildmodel(&s2, &rep, _state); rbfcalc(&s2, &testpoint, &y1, _state); if( y1.cnt!=ny ) { result = ae_true; ae_frame_leave(_state); return result; } for(j=0; j<=ny-1; j++) { if( ae_fp_neq(y1.ptr.p_double[j],(double)(0)) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } ae_frame_leave(_state); return result; } static ae_bool testrbfunit_searcherr(/* Real */ ae_matrix* y0, /* Real */ ae_matrix* y1, ae_int_t n, ae_int_t ny, ae_int_t errtype, /* Real */ ae_vector* b1, /* Real */ ae_vector* delta, ae_state *_state) { ae_frame _frame_block; ae_matrix _y0; ae_matrix _y1; ae_vector _b1; ae_vector _delta; double oralerr; double iralerr; ae_vector irerr; ae_vector orerr; ae_int_t lb; ae_int_t rb; ae_int_t i; ae_int_t j; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init_copy(&_y0, y0, _state); y0 = &_y0; ae_matrix_init_copy(&_y1, y1, _state); y1 = &_y1; ae_vector_init_copy(&_b1, b1, _state); b1 = &_b1; ae_vector_init_copy(&_delta, delta, _state); delta = &_delta; ae_vector_init(&irerr, 0, DT_REAL, _state); ae_vector_init(&orerr, 0, DT_REAL, _state); ae_assert(n>0, "SearchErr: invalid parameter N(N<=0).", _state); ae_assert(ny>0, "SearchErr: invalid parameter NY(NY<=0).", _state); oralerr = 1.0E-1; iralerr = 1.0E-2; lb = 25; rb = 75; ae_vector_set_length(&orerr, ny, _state); ae_vector_set_length(&irerr, ny, _state); for(j=0; j<=ny-1; j++) { orerr.ptr.p_double[j] = (double)(0); irerr.ptr.p_double[j] = (double)(0); } if( errtype==1 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=ny-1; j++) { if( ae_fp_less(orerr.ptr.p_double[j],ae_fabs(y0->ptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state)) ) { orerr.ptr.p_double[j] = ae_fabs(y0->ptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state); } } } for(i=0; i<=ny-1; i++) { if( ae_fp_greater(orerr.ptr.p_double[i],b1->ptr.p_double[i]+delta->ptr.p_double[i])||ae_fp_less(orerr.ptr.p_double[i],b1->ptr.p_double[i]-delta->ptr.p_double[i]) ) { result = ae_true; ae_frame_leave(_state); return result; } } } else { if( errtype==2 ) { for(i=0; i<=n-1; i++) { for(j=0; j<=ny-1; j++) { if( i>lb&&iptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state)) ) { irerr.ptr.p_double[j] = ae_fabs(y0->ptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state); } } else { if( ae_fp_less(orerr.ptr.p_double[j],ae_fabs(y0->ptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state)) ) { orerr.ptr.p_double[j] = ae_fabs(y0->ptr.pp_double[i][j]-y1->ptr.pp_double[i][j], _state); } } } } for(i=0; i<=ny-1; i++) { if( ae_fp_greater(orerr.ptr.p_double[i],oralerr)||ae_fp_greater(irerr.ptr.p_double[i],iralerr) ) { result = ae_true; ae_frame_leave(_state); return result; } } } else { ae_assert(ae_false, "SearchErr: invalid argument ErrType(ErrType neither 1 nor 2)", _state); } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing basic functionality of RBF module on regular grids with multi-layer algorithm in 2-3D. -- ALGLIB -- Copyright 2.03.2012 by Bochkanov Sergey *************************************************************************/ static ae_bool testrbfunit_basicmultilayerrbftest(ae_state *_state) { ae_frame _frame_block; rbfmodel s; rbfreport rep; ae_int_t nx; ae_int_t ny; ae_int_t k0; ae_int_t k1; ae_int_t k2; ae_int_t linterm; ae_int_t np; double q; ae_int_t layers; ae_vector epss; ae_int_t range; double s1; double s2; double gstep; ae_vector point; ae_matrix gp; ae_vector x; ae_vector y; ae_matrix gy; ae_vector gpgx0; ae_vector gpgx1; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; ae_bool result; ae_frame_make(_state, &_frame_block); _rbfmodel_init(&s, _state); _rbfreport_init(&rep, _state); ae_vector_init(&epss, 0, DT_REAL, _state); ae_vector_init(&point, 0, DT_REAL, _state); ae_matrix_init(&gp, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&gy, 0, 0, DT_REAL, _state); ae_vector_init(&gpgx0, 0, DT_REAL, _state); ae_vector_init(&gpgx1, 0, DT_REAL, _state); range = 10; k0 = 6; k1 = 6; k2 = 6; passcount = 10; ae_vector_set_length(&epss, 2, _state); epss.ptr.p_double[0] = 0.05; epss.ptr.p_double[1] = 1.0E-6; for(pass=0; pass<=passcount-1; pass++) { /* * prepare test problem */ s1 = ae_pow((double)(range), (double)(ae_randominteger(3, _state)-1), _state); s2 = ae_pow((double)(range), (double)(ae_randominteger(3, _state)-1), _state); nx = ae_randominteger(2, _state)+2; ny = ae_randominteger(2, _state)+1; linterm = ae_randominteger(3, _state)+1; layers = ae_randominteger(2, _state); gstep = s1/6; ae_vector_set_length(&x, nx, _state); ae_vector_set_length(&y, ny, _state); ae_vector_set_length(&point, nx, _state); rbfcreate(nx, ny, &s, _state); q = s1; rbfsetalgomultilayer(&s, q, layers+5, 0.0, _state); if( linterm==1 ) { rbfsetlinterm(&s, _state); } if( linterm==2 ) { rbfsetconstterm(&s, _state); } if( linterm==3 ) { rbfsetzeroterm(&s, _state); } /* * start points for grid */ for(i=0; i<=nx-1; i++) { point.ptr.p_double[i] = s1*(2*ae_randomreal(_state)-1); } /* * 2-dimensional test problem */ if( nx==2 ) { np = k0*k1; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { gp.ptr.pp_double[i*k1+j][0] = point.ptr.p_double[0]+gstep*i; gp.ptr.pp_double[i*k1+j][1] = point.ptr.p_double[1]+gstep*j; for(k=0; k<=ny-1; k++) { gp.ptr.pp_double[i*k1+j][nx+k] = s2*(2*ae_randomreal(_state)-1); } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); if( ny==1 ) { ae_vector_set_length(&gpgx0, k0, _state); ae_vector_set_length(&gpgx1, k1, _state); for(i=0; i<=k0-1; i++) { gpgx0.ptr.p_double[i] = point.ptr.p_double[0]+gstep*i; } for(i=0; i<=k1-1; i++) { gpgx1.ptr.p_double[i] = point.ptr.p_double[1]+gstep*i; } rbfgridcalc2(&s, &gpgx0, k0, &gpgx1, k1, &gy, _state); for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { if( ae_fp_greater(ae_fabs(gy.ptr.pp_double[i][j]-gp.ptr.pp_double[i*k1+j][nx], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc2(&s, x.ptr.p_double[0], x.ptr.p_double[1], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } /* * 3-dimensional test problems */ if( nx==3 ) { np = k0*k1*k2; ae_matrix_set_length(&gp, np, nx+ny, _state); /* * create grid */ for(i=0; i<=k0-1; i++) { for(j=0; j<=k1-1; j++) { for(k=0; k<=k2-1; k++) { gp.ptr.pp_double[(i*k1+j)*k2+k][0] = point.ptr.p_double[0]+gstep*i; gp.ptr.pp_double[(i*k1+j)*k2+k][1] = point.ptr.p_double[1]+gstep*j; gp.ptr.pp_double[(i*k1+j)*k2+k][2] = point.ptr.p_double[2]+gstep*k; for(l=0; l<=ny-1; l++) { gp.ptr.pp_double[(i*k1+j)*k2+k][nx+l] = s2*(2*ae_randomreal(_state)-1); } } } } rbfsetpoints(&s, &gp, np, _state); rbfbuildmodel(&s, &rep, _state); for(i=0; i<=np-1; i++) { x.ptr.p_double[0] = gp.ptr.pp_double[i][0]; x.ptr.p_double[1] = gp.ptr.pp_double[i][1]; x.ptr.p_double[2] = gp.ptr.pp_double[i][2]; if( ny==1 ) { y.ptr.p_double[0] = rbfcalc3(&s, x.ptr.p_double[0], x.ptr.p_double[1], x.ptr.p_double[2], _state); if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx]-y.ptr.p_double[0], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalc(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } rbfcalcbuf(&s, &x, &y, _state); for(j=0; j<=ny-1; j++) { if( ae_fp_greater(ae_fabs(gp.ptr.pp_double[i][nx+j]-y.ptr.p_double[j], _state),s2*epss.ptr.p_double[layers]) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } result = ae_false; ae_frame_leave(_state); return result; } static void testspline2dunit_lconst(spline2dinterpolant* c, /* Real */ ae_vector* lx, /* Real */ ae_vector* ly, ae_int_t m, ae_int_t n, double lstep, double* lc, double* lcx, double* lcy, double* lcxy, ae_state *_state); static void testspline2dunit_twodnumder(spline2dinterpolant* c, double x, double y, double h, double* f, double* fx, double* fy, double* fxy, ae_state *_state); static ae_bool testspline2dunit_testunpack(spline2dinterpolant* c, /* Real */ ae_vector* lx, /* Real */ ae_vector* ly, ae_state *_state); static ae_bool testspline2dunit_testlintrans(spline2dinterpolant* c, ae_int_t d, double ax, double bx, double ay, double by, ae_state *_state); static void testspline2dunit_unsetspline2d(spline2dinterpolant* c, ae_state *_state); static ae_bool testspline2dunit_testspline2dvf(ae_bool silent, ae_state *_state); ae_bool testspline2d(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool blerrors; ae_bool bcerrors; ae_bool dserrors; ae_bool cperrors; ae_bool uperrors; ae_bool lterrors; ae_bool syerrors; ae_bool rlerrors; ae_bool rcerrors; ae_bool vferrors; ae_int_t pass; ae_int_t passcount; ae_int_t jobtype; double lstep; double h; ae_vector x; ae_vector y; spline2dinterpolant c; spline2dinterpolant c2; ae_vector lx; ae_vector ly; ae_vector fv; ae_matrix f; ae_matrix fr; ae_matrix ft; double ax; double ay; double bx; double by; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t m; ae_int_t d; ae_int_t n2; ae_int_t m2; double err; double t; double t1; double t2; double l1; double l1x; double l1y; double l1xy; double l2; double l2x; double l2y; double l2xy; double fm; double f1; double f2; double f3; double f4; double v1; double v1x; double v1y; double v1xy; double v2; double v2x; double v2y; double v2xy; double mf; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); _spline2dinterpolant_init(&c, _state); _spline2dinterpolant_init(&c2, _state); ae_vector_init(&lx, 0, DT_REAL, _state); ae_vector_init(&ly, 0, DT_REAL, _state); ae_vector_init(&fv, 0, DT_REAL, _state); ae_matrix_init(&f, 0, 0, DT_REAL, _state); ae_matrix_init(&fr, 0, 0, DT_REAL, _state); ae_matrix_init(&ft, 0, 0, DT_REAL, _state); waserrors = ae_false; passcount = 10; h = 0.00001; lstep = 0.001; blerrors = ae_false; bcerrors = ae_false; dserrors = ae_false; cperrors = ae_false; uperrors = ae_false; lterrors = ae_false; syerrors = ae_false; rlerrors = ae_false; rcerrors = ae_false; vferrors = ae_false; /* * Test: bilinear, bicubic */ for(n=2; n<=7; n++) { for(m=2; m<=7; m++) { d = ae_randominteger(2, _state)+2; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&y, m, _state); ae_vector_set_length(&lx, 2*n-1, _state); ae_vector_set_length(&ly, 2*m-1, _state); ae_matrix_set_length(&f, m, n, _state); ae_vector_set_length(&fv, m*n*d, _state); ae_matrix_set_length(&ft, n, m, _state); for(pass=1; pass<=passcount; pass++) { /* * Prepare task: * * X and Y stores grid * * F stores function values * * LX and LY stores twice dense grid (for Lipschitz testing) */ ax = -1-ae_randomreal(_state); bx = 1+ae_randomreal(_state); ay = -1-ae_randomreal(_state); by = 1+ae_randomreal(_state); for(j=0; j<=n-1; j++) { x.ptr.p_double[j] = 0.5*(bx+ax)-0.5*(bx-ax)*ae_cos(ae_pi*(2*j+1)/(2*n), _state); if( j==0 ) { x.ptr.p_double[j] = ax; } if( j==n-1 ) { x.ptr.p_double[j] = bx; } lx.ptr.p_double[2*j] = x.ptr.p_double[j]; if( j>0 ) { lx.ptr.p_double[2*j-1] = 0.5*(x.ptr.p_double[j]+x.ptr.p_double[j-1]); } } for(j=0; j<=n-1; j++) { k = ae_randominteger(n, _state); if( k!=j ) { t = x.ptr.p_double[j]; x.ptr.p_double[j] = x.ptr.p_double[k]; x.ptr.p_double[k] = t; } } for(i=0; i<=m-1; i++) { y.ptr.p_double[i] = 0.5*(by+ay)-0.5*(by-ay)*ae_cos(ae_pi*(2*i+1)/(2*m), _state); if( i==0 ) { y.ptr.p_double[i] = ay; } if( i==m-1 ) { y.ptr.p_double[i] = by; } ly.ptr.p_double[2*i] = y.ptr.p_double[i]; if( i>0 ) { ly.ptr.p_double[2*i-1] = 0.5*(y.ptr.p_double[i]+y.ptr.p_double[i-1]); } } for(i=0; i<=m-1; i++) { k = ae_randominteger(m, _state); if( k!=i ) { t = y.ptr.p_double[i]; y.ptr.p_double[i] = y.ptr.p_double[k]; y.ptr.p_double[k] = t; } } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { f.ptr.pp_double[i][j] = ae_exp(0.6*x.ptr.p_double[j], _state)-ae_exp(-0.3*y.ptr.p_double[i]+0.08*x.ptr.p_double[j], _state)+2*ae_cos(ae_pi*(x.ptr.p_double[j]+1.2*y.ptr.p_double[i]), _state)+0.1*ae_cos(20*x.ptr.p_double[j]+15*y.ptr.p_double[i], _state); } } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { for(k=0; k<=d-1; k++) { fv.ptr.p_double[d*(n*j+i)+k] = ae_exp(0.6*x.ptr.p_double[i], _state)-ae_exp(-0.3*y.ptr.p_double[j]+0.08*x.ptr.p_double[i], _state)+2*ae_cos(ae_pi*(x.ptr.p_double[i]+1.2*y.ptr.p_double[j]+k), _state)+0.1*ae_cos(20*x.ptr.p_double[i]+15*y.ptr.p_double[j]+k, _state); } } } /* * Test bilinear interpolation: * * interpolation at the nodes * * linearity * * continuity * * differentiation in the inner points */ spline2dbuildbilinear(&x, &y, &f, m, n, &c, _state); err = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { err = ae_maxreal(err, ae_fabs(f.ptr.pp_double[i][j]-spline2dcalc(&c, x.ptr.p_double[j], y.ptr.p_double[i], _state), _state), _state); } } blerrors = blerrors||ae_fp_greater(err,10000*ae_machineepsilon); err = (double)(0); for(i=0; i<=m-2; i++) { for(j=0; j<=n-2; j++) { /* * Test for linearity between grid points * (test point - geometric center of the cell) */ fm = spline2dcalc(&c, lx.ptr.p_double[2*j+1], ly.ptr.p_double[2*i+1], _state); f1 = spline2dcalc(&c, lx.ptr.p_double[2*j], ly.ptr.p_double[2*i], _state); f2 = spline2dcalc(&c, lx.ptr.p_double[2*j+2], ly.ptr.p_double[2*i], _state); f3 = spline2dcalc(&c, lx.ptr.p_double[2*j+2], ly.ptr.p_double[2*i+2], _state); f4 = spline2dcalc(&c, lx.ptr.p_double[2*j], ly.ptr.p_double[2*i+2], _state); err = ae_maxreal(err, ae_fabs(0.25*(f1+f2+f3+f4)-fm, _state), _state); } } blerrors = blerrors||ae_fp_greater(err,10000*ae_machineepsilon); testspline2dunit_lconst(&c, &lx, &ly, m, n, lstep, &l1, &l1x, &l1y, &l1xy, _state); testspline2dunit_lconst(&c, &lx, &ly, m, n, lstep/3, &l2, &l2x, &l2y, &l2xy, _state); blerrors = blerrors||ae_fp_greater(l2/l1,1.2); err = (double)(0); for(i=0; i<=m-2; i++) { for(j=0; j<=n-2; j++) { spline2ddiff(&c, lx.ptr.p_double[2*j+1], ly.ptr.p_double[2*i+1], &v1, &v1x, &v1y, &v1xy, _state); testspline2dunit_twodnumder(&c, lx.ptr.p_double[2*j+1], ly.ptr.p_double[2*i+1], h, &v2, &v2x, &v2y, &v2xy, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); err = ae_maxreal(err, ae_fabs(v1x-v2x, _state), _state); err = ae_maxreal(err, ae_fabs(v1y-v2y, _state), _state); err = ae_maxreal(err, ae_fabs(v1xy-v2xy, _state), _state); } } dserrors = dserrors||ae_fp_greater(err,1.0E-3); uperrors = uperrors||!testspline2dunit_testunpack(&c, &lx, &ly, _state); lterrors = lterrors||!testspline2dunit_testlintrans(&c, 1, ax, bx, ay, by, _state); /* * Lin.Trans. test for vector-function */ spline2dbuildbilinearv(&x, n, &y, m, &fv, d, &c, _state); lterrors = lterrors||!testspline2dunit_testlintrans(&c, d, ax, bx, ay, by, _state); /* * Test bicubic interpolation. * * interpolation at the nodes * * smoothness * * differentiation */ spline2dbuildbicubic(&x, &y, &f, m, n, &c, _state); err = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { err = ae_maxreal(err, ae_fabs(f.ptr.pp_double[i][j]-spline2dcalc(&c, x.ptr.p_double[j], y.ptr.p_double[i], _state), _state), _state); } } bcerrors = bcerrors||ae_fp_greater(err,10000*ae_machineepsilon); testspline2dunit_lconst(&c, &lx, &ly, m, n, lstep, &l1, &l1x, &l1y, &l1xy, _state); testspline2dunit_lconst(&c, &lx, &ly, m, n, lstep/3, &l2, &l2x, &l2y, &l2xy, _state); bcerrors = bcerrors||ae_fp_greater(l2/l1,1.2); bcerrors = bcerrors||ae_fp_greater(l2x/l1x,1.2); bcerrors = bcerrors||ae_fp_greater(l2y/l1y,1.2); if( ae_fp_greater(l2xy,0.01)&&ae_fp_greater(l1xy,0.01) ) { /* * Cross-derivative continuity is tested only when * bigger than 0.01. When the task size is too * small, the d2F/dXdY is nearly zero and Lipschitz * constant ratio is ill-conditioned. */ bcerrors = bcerrors||ae_fp_greater(l2xy/l1xy,1.2); } err = (double)(0); for(i=0; i<=2*m-2; i++) { for(j=0; j<=2*n-2; j++) { spline2ddiff(&c, lx.ptr.p_double[j], ly.ptr.p_double[i], &v1, &v1x, &v1y, &v1xy, _state); testspline2dunit_twodnumder(&c, lx.ptr.p_double[j], ly.ptr.p_double[i], h, &v2, &v2x, &v2y, &v2xy, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); err = ae_maxreal(err, ae_fabs(v1x-v2x, _state), _state); err = ae_maxreal(err, ae_fabs(v1y-v2y, _state), _state); err = ae_maxreal(err, ae_fabs(v1xy-v2xy, _state), _state); } } dserrors = dserrors||ae_fp_greater(err,1.0E-3); uperrors = uperrors||!testspline2dunit_testunpack(&c, &lx, &ly, _state); lterrors = lterrors||!testspline2dunit_testlintrans(&c, 1, ax, bx, ay, by, _state); /* * Lin.Trans. test for vector-function */ spline2dbuildbicubicv(&x, n, &y, m, &fv, d, &c, _state); lterrors = lterrors||!testspline2dunit_testlintrans(&c, d, ax, bx, ay, by, _state); /* * Copy test */ if( ae_fp_greater(ae_randomreal(_state),0.5) ) { spline2dbuildbicubic(&x, &y, &f, m, n, &c, _state); } else { spline2dbuildbilinear(&x, &y, &f, m, n, &c, _state); } testspline2dunit_unsetspline2d(&c2, _state); spline2dcopy(&c, &c2, _state); err = (double)(0); for(i=1; i<=5; i++) { t1 = ax+(bx-ax)*ae_randomreal(_state); t2 = ay+(by-ay)*ae_randomreal(_state); err = ae_maxreal(err, ae_fabs(spline2dcalc(&c, t1, t2, _state)-spline2dcalc(&c2, t1, t2, _state), _state), _state); } cperrors = cperrors||ae_fp_greater(err,10000*ae_machineepsilon); /* * Special symmetry test */ err = (double)(0); for(jobtype=0; jobtype<=1; jobtype++) { /* * Prepare */ for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ft.ptr.pp_double[j][i] = f.ptr.pp_double[i][j]; } } if( jobtype==0 ) { spline2dbuildbilinear(&x, &y, &f, m, n, &c, _state); spline2dbuildbilinear(&y, &x, &ft, n, m, &c2, _state); } else { spline2dbuildbicubic(&x, &y, &f, m, n, &c, _state); spline2dbuildbicubic(&y, &x, &ft, n, m, &c2, _state); } /* * Test */ for(i=1; i<=10; i++) { t1 = ax+(bx-ax)*ae_randomreal(_state); t2 = ay+(by-ay)*ae_randomreal(_state); err = ae_maxreal(err, ae_fabs(spline2dcalc(&c, t1, t2, _state)-spline2dcalc(&c2, t2, t1, _state), _state), _state); } } syerrors = syerrors||ae_fp_greater(err,10000*ae_machineepsilon); } } } /* * Test resample */ for(m=2; m<=6; m++) { for(n=2; n<=6; n++) { ae_matrix_set_length(&f, m-1+1, n-1+1, _state); ae_vector_set_length(&x, n-1+1, _state); ae_vector_set_length(&y, m-1+1, _state); for(j=0; j<=n-1; j++) { x.ptr.p_double[j] = (double)j/(double)(n-1); } for(i=0; i<=m-1; i++) { y.ptr.p_double[i] = (double)i/(double)(m-1); } for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { f.ptr.pp_double[i][j] = ae_exp(0.6*x.ptr.p_double[j], _state)-ae_exp(-0.3*y.ptr.p_double[i]+0.08*x.ptr.p_double[j], _state)+2*ae_cos(ae_pi*(x.ptr.p_double[j]+1.2*y.ptr.p_double[i]), _state)+0.1*ae_cos(20*x.ptr.p_double[j]+15*y.ptr.p_double[i], _state); } } for(m2=2; m2<=6; m2++) { for(n2=2; n2<=6; n2++) { for(pass=1; pass<=passcount; pass++) { for(jobtype=0; jobtype<=1; jobtype++) { if( jobtype==0 ) { spline2dresamplebilinear(&f, m, n, &fr, m2, n2, _state); spline2dbuildbilinear(&x, &y, &f, m, n, &c, _state); } if( jobtype==1 ) { spline2dresamplebicubic(&f, m, n, &fr, m2, n2, _state); spline2dbuildbicubic(&x, &y, &f, m, n, &c, _state); } err = (double)(0); mf = (double)(0); for(i=0; i<=m2-1; i++) { for(j=0; j<=n2-1; j++) { v1 = spline2dcalc(&c, (double)j/(double)(n2-1), (double)i/(double)(m2-1), _state); v2 = fr.ptr.pp_double[i][j]; err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); mf = ae_maxreal(mf, ae_fabs(v1, _state), _state); } } if( jobtype==0 ) { rlerrors = rlerrors||ae_fp_greater(err/mf,10000*ae_machineepsilon); } if( jobtype==1 ) { rcerrors = rcerrors||ae_fp_greater(err/mf,10000*ae_machineepsilon); } } } } } } } /* * Test for vector-function */ vferrors = testspline2dunit_testspline2dvf(ae_true, _state); /* * Report */ waserrors = ((((((((blerrors||bcerrors)||dserrors)||cperrors)||uperrors)||lterrors)||syerrors)||rlerrors)||rcerrors)||vferrors; if( !silent ) { printf("TESTING 2D SPLINE\n"); /* * Normal tests */ printf("BILINEAR TEST: "); if( blerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BICUBIC TEST: "); if( bcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("DIFFERENTIATION TEST: "); if( dserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("COPY/SERIALIZE TEST: "); if( cperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("UNPACK TEST: "); if( uperrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LIN.TRANS. TEST: "); if( lterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("SPECIAL SYMMETRY TEST: "); if( syerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BILINEAR RESAMPLING TEST: "); if( rlerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("BICUBIC RESAMPLING TEST: "); if( rcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("VECTOR FUNCTION TEST: "); if( vferrors ) { printf("FAILED\n"); } else { printf("OK\n"); } /* * Summary */ if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } /* * end */ result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testspline2d(ae_bool silent, ae_state *_state) { return testspline2d(silent, _state); } /************************************************************************* Lipschitz constants for spline inself, first and second derivatives. *************************************************************************/ static void testspline2dunit_lconst(spline2dinterpolant* c, /* Real */ ae_vector* lx, /* Real */ ae_vector* ly, ae_int_t m, ae_int_t n, double lstep, double* lc, double* lcx, double* lcy, double* lcxy, ae_state *_state) { ae_int_t i; ae_int_t j; double f1; double f2; double f3; double f4; double fx1; double fx2; double fx3; double fx4; double fy1; double fy2; double fy3; double fy4; double fxy1; double fxy2; double fxy3; double fxy4; double s2lstep; *lc = 0; *lcx = 0; *lcy = 0; *lcxy = 0; *lc = (double)(0); *lcx = (double)(0); *lcy = (double)(0); *lcxy = (double)(0); s2lstep = ae_sqrt((double)(2), _state)*lstep; for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { /* * Calculate */ testspline2dunit_twodnumder(c, lx->ptr.p_double[j]-lstep/2, ly->ptr.p_double[i]-lstep/2, lstep/4, &f1, &fx1, &fy1, &fxy1, _state); testspline2dunit_twodnumder(c, lx->ptr.p_double[j]+lstep/2, ly->ptr.p_double[i]-lstep/2, lstep/4, &f2, &fx2, &fy2, &fxy2, _state); testspline2dunit_twodnumder(c, lx->ptr.p_double[j]+lstep/2, ly->ptr.p_double[i]+lstep/2, lstep/4, &f3, &fx3, &fy3, &fxy3, _state); testspline2dunit_twodnumder(c, lx->ptr.p_double[j]-lstep/2, ly->ptr.p_double[i]+lstep/2, lstep/4, &f4, &fx4, &fy4, &fxy4, _state); /* * Lipschitz constant for the function itself */ *lc = ae_maxreal(*lc, ae_fabs((f1-f2)/lstep, _state), _state); *lc = ae_maxreal(*lc, ae_fabs((f2-f3)/lstep, _state), _state); *lc = ae_maxreal(*lc, ae_fabs((f3-f4)/lstep, _state), _state); *lc = ae_maxreal(*lc, ae_fabs((f4-f1)/lstep, _state), _state); *lc = ae_maxreal(*lc, ae_fabs((f1-f3)/s2lstep, _state), _state); *lc = ae_maxreal(*lc, ae_fabs((f2-f4)/s2lstep, _state), _state); /* * Lipschitz constant for the first derivative */ *lcx = ae_maxreal(*lcx, ae_fabs((fx1-fx2)/lstep, _state), _state); *lcx = ae_maxreal(*lcx, ae_fabs((fx2-fx3)/lstep, _state), _state); *lcx = ae_maxreal(*lcx, ae_fabs((fx3-fx4)/lstep, _state), _state); *lcx = ae_maxreal(*lcx, ae_fabs((fx4-fx1)/lstep, _state), _state); *lcx = ae_maxreal(*lcx, ae_fabs((fx1-fx3)/s2lstep, _state), _state); *lcx = ae_maxreal(*lcx, ae_fabs((fx2-fx4)/s2lstep, _state), _state); /* * Lipschitz constant for the first derivative */ *lcy = ae_maxreal(*lcy, ae_fabs((fy1-fy2)/lstep, _state), _state); *lcy = ae_maxreal(*lcy, ae_fabs((fy2-fy3)/lstep, _state), _state); *lcy = ae_maxreal(*lcy, ae_fabs((fy3-fy4)/lstep, _state), _state); *lcy = ae_maxreal(*lcy, ae_fabs((fy4-fy1)/lstep, _state), _state); *lcy = ae_maxreal(*lcy, ae_fabs((fy1-fy3)/s2lstep, _state), _state); *lcy = ae_maxreal(*lcy, ae_fabs((fy2-fy4)/s2lstep, _state), _state); /* * Lipschitz constant for the cross-derivative */ *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy1-fxy2)/lstep, _state), _state); *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy2-fxy3)/lstep, _state), _state); *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy3-fxy4)/lstep, _state), _state); *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy4-fxy1)/lstep, _state), _state); *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy1-fxy3)/s2lstep, _state), _state); *lcxy = ae_maxreal(*lcxy, ae_fabs((fxy2-fxy4)/s2lstep, _state), _state); } } } /************************************************************************* Numerical differentiation. *************************************************************************/ static void testspline2dunit_twodnumder(spline2dinterpolant* c, double x, double y, double h, double* f, double* fx, double* fy, double* fxy, ae_state *_state) { *f = 0; *fx = 0; *fy = 0; *fxy = 0; *f = spline2dcalc(c, x, y, _state); *fx = (spline2dcalc(c, x+h, y, _state)-spline2dcalc(c, x-h, y, _state))/(2*h); *fy = (spline2dcalc(c, x, y+h, _state)-spline2dcalc(c, x, y-h, _state))/(2*h); *fxy = (spline2dcalc(c, x+h, y+h, _state)-spline2dcalc(c, x-h, y+h, _state)-spline2dcalc(c, x+h, y-h, _state)+spline2dcalc(c, x-h, y-h, _state))/ae_sqr(2*h, _state); } /************************************************************************* Unpack test *************************************************************************/ static ae_bool testspline2dunit_testunpack(spline2dinterpolant* c, /* Real */ ae_vector* lx, /* Real */ ae_vector* ly, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t n; ae_int_t m; ae_int_t ci; ae_int_t cj; ae_int_t p; double err; double tx; double ty; double v1; double v2; ae_int_t pass; ae_int_t passcount; ae_matrix tbl; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&tbl, 0, 0, DT_REAL, _state); passcount = 20; err = (double)(0); spline2dunpack(c, &m, &n, &tbl, _state); for(i=0; i<=m-2; i++) { for(j=0; j<=n-2; j++) { for(pass=1; pass<=passcount; pass++) { p = (n-1)*i+j; tx = (0.001+0.999*ae_randomreal(_state))*(tbl.ptr.pp_double[p][1]-tbl.ptr.pp_double[p][0]); ty = (0.001+0.999*ae_randomreal(_state))*(tbl.ptr.pp_double[p][3]-tbl.ptr.pp_double[p][2]); /* * Interpolation properties */ v1 = (double)(0); for(ci=0; ci<=3; ci++) { for(cj=0; cj<=3; cj++) { v1 = v1+tbl.ptr.pp_double[p][4+ci*4+cj]*ae_pow(tx, (double)(ci), _state)*ae_pow(ty, (double)(cj), _state); } } v2 = spline2dcalc(c, tbl.ptr.pp_double[p][0]+tx, tbl.ptr.pp_double[p][2]+ty, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); /* * Grid correctness */ err = ae_maxreal(err, ae_fabs(lx->ptr.p_double[2*j]-tbl.ptr.pp_double[p][0], _state), _state); err = ae_maxreal(err, ae_fabs(lx->ptr.p_double[2*(j+1)]-tbl.ptr.pp_double[p][1], _state), _state); err = ae_maxreal(err, ae_fabs(ly->ptr.p_double[2*i]-tbl.ptr.pp_double[p][2], _state), _state); err = ae_maxreal(err, ae_fabs(ly->ptr.p_double[2*(i+1)]-tbl.ptr.pp_double[p][3], _state), _state); } } } result = ae_fp_less(err,10000*ae_machineepsilon); ae_frame_leave(_state); return result; } /************************************************************************* LinTrans test for scalar *************************************************************************/ static ae_bool testspline2dunit_testlintrans(spline2dinterpolant* c, ae_int_t d, double ax, double bx, double ay, double by, ae_state *_state) { ae_frame _frame_block; double err; double a1; double a2; double b1; double b2; double tx; double ty; double vx; double vy; ae_vector v1; ae_vector v2; ae_int_t pass; ae_int_t passcount; ae_int_t xjob; ae_int_t yjob; spline2dinterpolant c2; ae_int_t di; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&v1, 0, DT_REAL, _state); ae_vector_init(&v2, 0, DT_REAL, _state); _spline2dinterpolant_init(&c2, _state); passcount = 5; err = (double)(0); for(xjob=0; xjob<=1; xjob++) { for(yjob=0; yjob<=1; yjob++) { for(pass=1; pass<=passcount; pass++) { /* * Prepare */ do { a1 = 2*ae_randomreal(_state)-1; } while(ae_fp_eq(a1,(double)(0))); a1 = a1*xjob; b1 = 2*ae_randomreal(_state)-1; do { a2 = 2*ae_randomreal(_state)-1; } while(ae_fp_eq(a2,(double)(0))); a2 = a2*yjob; b2 = 2*ae_randomreal(_state)-1; /* * Test XY */ spline2dcopy(c, &c2, _state); spline2dlintransxy(&c2, a1, b1, a2, b2, _state); tx = ax+ae_randomreal(_state)*(bx-ax); ty = ay+ae_randomreal(_state)*(by-ay); if( xjob==0 ) { tx = b1; vx = ax+ae_randomreal(_state)*(bx-ax); } else { vx = (tx-b1)/a1; } if( yjob==0 ) { ty = b2; vy = ay+ae_randomreal(_state)*(by-ay); } else { vy = (ty-b2)/a2; } spline2dcalcv(c, tx, ty, &v1, _state); spline2dcalcv(&c2, vx, vy, &v2, _state); for(di=0; di<=d-1; di++) { err = ae_maxreal(err, ae_fabs(v1.ptr.p_double[di]-v2.ptr.p_double[di], _state), _state); } /* * Test F */ spline2dcopy(c, &c2, _state); spline2dlintransf(&c2, a1, b1, _state); tx = ax+ae_randomreal(_state)*(bx-ax); ty = ay+ae_randomreal(_state)*(by-ay); spline2dcalcv(c, tx, ty, &v1, _state); spline2dcalcv(&c2, tx, ty, &v2, _state); for(di=0; di<=d-1; di++) { err = ae_maxreal(err, ae_fabs(a1*v1.ptr.p_double[di]+b1-v2.ptr.p_double[di], _state), _state); } } } } result = ae_fp_less(err,10000*ae_machineepsilon); ae_frame_leave(_state); return result; } /************************************************************************* Unset spline, i.e. initialize it with random garbage *************************************************************************/ static void testspline2dunit_unsetspline2d(spline2dinterpolant* c, ae_state *_state) { ae_frame _frame_block; ae_vector x; ae_vector y; ae_matrix f; ae_frame_make(_state, &_frame_block); _spline2dinterpolant_clear(c); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_matrix_init(&f, 0, 0, DT_REAL, _state); ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&y, 2, _state); ae_matrix_set_length(&f, 2, 2, _state); x.ptr.p_double[0] = (double)(-1); x.ptr.p_double[1] = (double)(1); y.ptr.p_double[0] = (double)(-1); y.ptr.p_double[1] = (double)(1); f.ptr.pp_double[0][0] = (double)(0); f.ptr.pp_double[0][1] = (double)(0); f.ptr.pp_double[1][0] = (double)(0); f.ptr.pp_double[1][1] = (double)(0); spline2dbuildbilinear(&x, &y, &f, 2, 2, c, _state); ae_frame_leave(_state); } /************************************************************************* The function check, that follow functions works correctly: Spline2DBilinearV, Spline2DBicubicV, Spline2DCalcV and Spline2DUnpackV. *************************************************************************/ static ae_bool testspline2dunit_testspline2dvf(ae_bool silent, ae_state *_state) { ae_frame _frame_block; spline2dinterpolant vc; spline2dinterpolant sc; double range; ae_vector x; ae_vector y; ae_vector f; double rndx; double rndy; ae_int_t nrnd; ae_vector resf; ae_matrix ef; double resef; ae_int_t m; ae_int_t n; ae_int_t d; ae_int_t tstn; ae_int_t tstm; ae_int_t tstd; ae_matrix tsttbl0; ae_matrix tsttbl1; double eps; double st; ae_int_t p0; ae_int_t p1; ae_int_t variant; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t i0; ae_int_t j0; double xmin; double xmax; double ymin; double ymax; ae_bool result; ae_frame_make(_state, &_frame_block); _spline2dinterpolant_init(&vc, _state); _spline2dinterpolant_init(&sc, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_vector_init(&resf, 0, DT_REAL, _state); ae_matrix_init(&ef, 0, 0, DT_REAL, _state); ae_matrix_init(&tsttbl0, 0, 0, DT_REAL, _state); ae_matrix_init(&tsttbl1, 0, 0, DT_REAL, _state); eps = 10000.0*ae_machineepsilon; st = 0.1; passcount = 5; for(pass=1; pass<=passcount; pass++) { for(variant=1; variant<=2; variant++) { range = ae_randominteger(71, _state)+30.0; nrnd = ae_randominteger(26, _state)+25; range = (double)(ae_randominteger(71, _state)+30); m = ae_randominteger(4, _state)+2; n = ae_randominteger(4, _state)+2; d = ae_randominteger(3, _state)+1; rvectorsetlengthatleast(&x, n, _state); rvectorsetlengthatleast(&y, m, _state); rvectorsetlengthatleast(&f, n*m*d, _state); rmatrixsetlengthatleast(&ef, m, n, _state); /* * Build a grid for spline */ x.ptr.p_double[0] = range*(2*ae_randomreal(_state)-1); y.ptr.p_double[0] = range*(2*ae_randomreal(_state)-1); for(i=1; i<=n-1; i++) { x.ptr.p_double[i] = x.ptr.p_double[i-1]+st+ae_randomreal(_state); } for(i=1; i<=m-1; i++) { y.ptr.p_double[i] = y.ptr.p_double[i-1]+st+ae_randomreal(_state); } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { for(k=0; k<=d-1; k++) { f.ptr.p_double[d*(n*j+i)+k] = range*(2*ae_randomreal(_state)-1); } } } xmin = x.ptr.p_double[0]; xmax = x.ptr.p_double[n-1]; ymin = y.ptr.p_double[0]; ymax = y.ptr.p_double[m-1]; /* * Build a spline */ if( variant==1 ) { spline2dbuildbilinearv(&x, n, &y, m, &f, d, &vc, _state); } if( variant==2 ) { spline2dbuildbicubicv(&x, n, &y, m, &f, d, &vc, _state); } /* * Part of test, which shows that Spline2DBuildBilinearV function * works correctly. * And there is test for Spline2DUnpackV. */ spline2dunpackv(&vc, &tstm, &tstn, &tstd, &tsttbl1, _state); if( (tstm!=m||tstn!=n)||tstd!=d ) { if( !silent ) { printf("TestSpline2DVF fail Spline2DUnpack:\n"); printf(" TstM=%0d; M=%0d;\n TstN=%0d; N=%0d;\n TstD=%0d; D=%0d.\n", (int)(tstm), (int)(m), (int)(tstn), (int)(n), (int)(tstd), (int)(d)); } result = ae_true; ae_frame_leave(_state); return result; } for(k=0; k<=d-1; k++) { for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { ef.ptr.pp_double[i][j] = f.ptr.p_double[d*(i*n+j)+k]; } } if( variant==1 ) { spline2dbuildbilinear(&x, &y, &ef, m, n, &sc, _state); } if( variant==2 ) { spline2dbuildbicubic(&x, &y, &ef, m, n, &sc, _state); } spline2dunpack(&sc, &tstm, &tstn, &tsttbl0, _state); if( tstm!=m||tstn!=n ) { if( !silent ) { printf("TestSpline2DVF fail Spline2DUnpack:\n"); printf(" TstM=%0d; M=%0d;\n TstN=%0d; N=%0d.\n", (int)(tstm), (int)(m), (int)(tstn), (int)(n)); } result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=m-2; i++) { for(j=0; j<=n-2; j++) { p0 = i*(n-1)+j; p1 = d*p0; for(i0=0; i0<=19; i0++) { if( ae_fp_neq(tsttbl1.ptr.pp_double[p1+k][i0],tsttbl0.ptr.pp_double[p0][i0]) ) { if( !silent ) { printf("TestSpline2DVF: Tbl error\n"); } result = ae_true; ae_frame_leave(_state); return result; } } } } } /* * Part of test, which shows that functions Spline2DCalcVBuf and Spline2DCalcV * works correctly */ for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { /* * Test for grid points */ spline2dcalcv(&vc, x.ptr.p_double[i], y.ptr.p_double[j], &resf, _state); for(k=0; k<=d-1; k++) { for(i0=0; i0<=m-1; i0++) { for(j0=0; j0<=n-1; j0++) { ef.ptr.pp_double[i0][j0] = f.ptr.p_double[d*(i0*n+j0)+k]; } } if( variant==1 ) { spline2dbuildbilinear(&x, &y, &ef, m, n, &sc, _state); } if( variant==2 ) { spline2dbuildbicubic(&x, &y, &ef, m, n, &sc, _state); } resef = spline2dcalc(&sc, x.ptr.p_double[i], y.ptr.p_double[j], _state); if( ae_fp_greater(ae_fabs(resf.ptr.p_double[k]-resef, _state),eps) ) { if( !silent ) { printf("TestSpline2DVF fail Spline2DCalcV:\n"); printf(" %0.5f=|resF[%0d]-resEF|=|%0.5f-%0.5f|>Eps=%0.2e;\n", (double)(ae_fabs(resf.ptr.p_double[k]-resef, _state)), (int)(k), (double)(resf.ptr.p_double[k]), (double)(resef), (double)(eps)); printf(" resF[%0d]=%0.5f;\n", (int)(k), (double)(resf.ptr.p_double[k])); printf(" resEF=%0.5f.\n", (double)(resef)); } result = ae_true; ae_frame_leave(_state); return result; } } } } /* * Test for random points */ for(i=1; i<=nrnd; i++) { rndx = xmin+(xmax-xmin)*ae_randomreal(_state); rndy = ymin+(ymax-ymin)*ae_randomreal(_state); /* * Calculate value for vector-function in random point */ spline2dcalcv(&vc, rndx, rndy, &resf, _state); for(k=0; k<=d-1; k++) { /* * Build spline for scalar-function, each of which correspond * to one of vector-function's components. */ for(i0=0; i0<=m-1; i0++) { for(j0=0; j0<=n-1; j0++) { ef.ptr.pp_double[i0][j0] = f.ptr.p_double[d*(i0*n+j0)+k]; } } if( variant==1 ) { spline2dbuildbilinear(&x, &y, &ef, m, n, &sc, _state); } if( variant==2 ) { spline2dbuildbicubic(&x, &y, &ef, m, n, &sc, _state); } resef = spline2dcalc(&sc, rndx, rndy, _state); if( ae_fp_greater(ae_fabs(resf.ptr.p_double[k]-resef, _state),eps) ) { if( !silent ) { printf("TestSpline2DVF fail Spline2DCalcV:\n"); printf(" %0.5f=|resF[%0d]-resEF|=|%0.5f-%0.5f|>Eps=%0.2e;\n", (double)(ae_fabs(resf.ptr.p_double[k]-resef, _state)), (int)(k), (double)(resf.ptr.p_double[k]), (double)(resef), (double)(eps)); printf(" resF[%0d]=%0.5f;\n", (int)(k), (double)(resf.ptr.p_double[k])); printf(" resEF=%0.5f.\n", (double)(resef)); } result = ae_true; ae_frame_leave(_state); return result; } } } } } if( !silent ) { printf("TestSpline2DVF: OK\n"); } result = ae_false; ae_frame_leave(_state); return result; } static ae_bool testspline3dunit_basictest(ae_state *_state); static ae_bool testspline3dunit_testunpack(ae_state *_state); static ae_bool testspline3dunit_testlintrans(ae_state *_state); static ae_bool testspline3dunit_testtrilinearresample(ae_state *_state); static void testspline3dunit_buildrndgrid(ae_bool isvect, ae_bool reorder, ae_int_t* n, ae_int_t* m, ae_int_t* l, ae_int_t* d, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* z, /* Real */ ae_vector* f, ae_state *_state); ae_bool testspline3d(ae_bool silence, ae_state *_state) { ae_bool waserrors; ae_bool basicerr; ae_bool unpackerr; ae_bool lintransferr; ae_bool trilinreserr; ae_bool result; basicerr = testspline3dunit_basictest(_state); unpackerr = testspline3dunit_testunpack(_state); lintransferr = testspline3dunit_testlintrans(_state); trilinreserr = testspline3dunit_testtrilinearresample(_state); waserrors = ((basicerr||unpackerr)||lintransferr)||trilinreserr; if( !silence ) { printf("TESTING 3D SPLINE\n"); printf("BASIC TEST: "); if( basicerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("UNPACK TEST: "); if( unpackerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("LIN_TRANSF TEST: "); if( lintransferr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("TRILINEAR RESAMPLING TEST: "); if( trilinreserr ) { printf("FAILED\n"); } else { printf("OK\n"); } /* * Summary */ if( waserrors ) { printf("TEST FAILED"); } else { printf("TEST PASSED"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testspline3d(ae_bool silence, ae_state *_state) { return testspline3d(silence, _state); } /************************************************************************* The function does test basic functionality. *************************************************************************/ static ae_bool testspline3dunit_basictest(ae_state *_state) { ae_frame _frame_block; spline3dinterpolant c; spline3dinterpolant cc; ae_vector vvf; double vsf; ae_int_t d; ae_int_t m; ae_int_t n; ae_int_t l; ae_vector x; ae_vector y; ae_vector z; ae_vector sf; ae_vector vf; double eps; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t offs; ae_int_t di; double ax; double ay; double az; double axy; double ayz; double vx; double vy; double vz; ae_bool result; ae_frame_make(_state, &_frame_block); _spline3dinterpolant_init(&c, _state); _spline3dinterpolant_init(&cc, _state); ae_vector_init(&vvf, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&sf, 0, DT_REAL, _state); ae_vector_init(&vf, 0, DT_REAL, _state); eps = 1000*ae_machineepsilon; /* * Test spline ability to reproduce D-dimensional vector function * f[idx](x,y,z) = idx+AX*x + AY*y + AZ*z + AXY*x*y + AYZ*y*z * with random AX/AY/... * * We generate random test function, build spline, then evaluate * it in the random test point. */ for(d=1; d<=3; d++) { n = 2+ae_randominteger(4, _state); m = 2+ae_randominteger(4, _state); l = 2+ae_randominteger(4, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)(i); } ae_vector_set_length(&y, m, _state); for(i=0; i<=m-1; i++) { y.ptr.p_double[i] = (double)(i); } ae_vector_set_length(&z, l, _state); for(i=0; i<=l-1; i++) { z.ptr.p_double[i] = (double)(i); } ae_vector_set_length(&vf, l*m*n*d, _state); offs = 0; ax = 2*ae_randomreal(_state)-1; ay = 2*ae_randomreal(_state)-1; az = 2*ae_randomreal(_state)-1; axy = 2*ae_randomreal(_state)-1; ayz = 2*ae_randomreal(_state)-1; for(k=0; k<=l-1; k++) { for(j=0; j<=m-1; j++) { for(i=0; i<=n-1; i++) { for(di=0; di<=d-1; di++) { vf.ptr.p_double[offs] = di+ax*i+ay*j+az*k+axy*i*j+ayz*j*k; offs = offs+1; } } } } spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &vf, d, &c, _state); vx = ae_randomreal(_state)*n; vy = ae_randomreal(_state)*m; vz = ae_randomreal(_state)*l; spline3dcalcv(&c, vx, vy, vz, &vf, _state); for(di=0; di<=d-1; di++) { if( ae_fp_greater(ae_fabs(di+ax*vx+ay*vy+az*vz+axy*vx*vy+ayz*vy*vz-vf.ptr.p_double[di], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } if( d==1 ) { vsf = spline3dcalc(&c, vx, vy, vz, _state); if( ae_fp_greater(ae_fabs(ax*vx+ay*vy+az*vz+axy*vx*vy+ayz*vy*vz-vsf, _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } /* * Generate random grid and test function. * Test spline ability to reproduce function values at grid nodes. */ passcount = 20; for(pass=1; pass<=passcount; pass++) { /* * Prepare a model and check that functions (Spline3DBuildTrilinear, * Spline3DCalc,Spline3DCalcV) work correctly and */ testspline3dunit_buildrndgrid(ae_true, ae_true, &n, &m, &l, &d, &x, &y, &z, &vf, _state); rvectorsetlengthatleast(&sf, n*m*l, _state); /* * Check that the model's values are equal to the function's values * in grid points */ spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &vf, d, &c, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { for(k=0; k<=l-1; k++) { spline3dcalcv(&c, x.ptr.p_double[i], y.ptr.p_double[j], z.ptr.p_double[k], &vvf, _state); for(di=0; di<=d-1; di++) { if( ae_fp_greater(ae_fabs(vf.ptr.p_double[d*(n*(m*k+j)+i)+di]-vvf.ptr.p_double[di], _state),eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } } } } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Unpack/UnpackV test *************************************************************************/ static ae_bool testspline3dunit_testunpack(ae_state *_state) { ae_frame _frame_block; spline3dinterpolant c; ae_matrix tbl0; ae_matrix tbl1; ae_int_t n; ae_int_t m; ae_int_t l; ae_int_t d; ae_int_t sz; ae_int_t un; ae_int_t um; ae_int_t ul; ae_int_t ud; ae_int_t ust; ae_int_t uvn; ae_int_t uvm; ae_int_t uvl; ae_int_t uvd; ae_int_t uvst; ae_int_t ci; ae_int_t cj; ae_int_t ck; ae_vector x; ae_vector y; ae_vector z; ae_vector sf; ae_vector vf; ae_int_t p0; ae_int_t p1; double tx; double ty; double tz; double v1; double v2; double err; ae_int_t pass; ae_int_t passcount; ae_bool bperr; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t di; ae_int_t i0; ae_bool result; ae_frame_make(_state, &_frame_block); _spline3dinterpolant_init(&c, _state); ae_matrix_init(&tbl0, 0, 0, DT_REAL, _state); ae_matrix_init(&tbl1, 0, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&sf, 0, DT_REAL, _state); ae_vector_init(&vf, 0, DT_REAL, _state); passcount = 20; err = (double)(0); for(pass=1; pass<=passcount; pass++) { /* * generate random grid. * NOTE: for this test we need ordered grid, i.e. grid * with nodes in ascending order */ testspline3dunit_buildrndgrid(ae_true, ae_false, &n, &m, &l, &d, &x, &y, &z, &vf, _state); sz = n*m*l; rvectorsetlengthatleast(&sf, sz, _state); spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &vf, d, &c, _state); spline3dunpackv(&c, &uvn, &uvm, &uvl, &uvd, &uvst, &tbl0, _state); for(di=0; di<=d-1; di++) { /* * DI-th component copy of a vector-function to * a scalar function */ for(i=0; i<=sz-1; i++) { sf.ptr.p_double[i] = vf.ptr.p_double[d*i+di]; } spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &sf, 1, &c, _state); spline3dunpackv(&c, &un, &um, &ul, &ud, &ust, &tbl1, _state); for(i=0; i<=n-2; i++) { for(j=0; j<=m-2; j++) { for(k=0; k<=l-2; k++) { p1 = (n-1)*((m-1)*k+j)+i; p0 = d*p1+di; /* * Check that all components are correct: * *first check, that unpacked componets are equal * to packed components; */ bperr = (((((((((((((((((un!=n||um!=m)||ul!=l)||ae_fp_neq(tbl1.ptr.pp_double[p1][0],x.ptr.p_double[i]))||ae_fp_neq(tbl1.ptr.pp_double[p1][1],x.ptr.p_double[i+1]))||ae_fp_neq(tbl1.ptr.pp_double[p1][2],y.ptr.p_double[j]))||ae_fp_neq(tbl1.ptr.pp_double[p1][3],y.ptr.p_double[j+1]))||ae_fp_neq(tbl1.ptr.pp_double[p1][4],z.ptr.p_double[k]))||ae_fp_neq(tbl1.ptr.pp_double[p1][5],z.ptr.p_double[k+1]))||uvn!=n)||uvm!=m)||uvl!=l)||uvd!=d)||ae_fp_neq(tbl0.ptr.pp_double[p0][0],x.ptr.p_double[i]))||ae_fp_neq(tbl0.ptr.pp_double[p0][1],x.ptr.p_double[i+1]))||ae_fp_neq(tbl0.ptr.pp_double[p0][2],y.ptr.p_double[j]))||ae_fp_neq(tbl0.ptr.pp_double[p0][3],y.ptr.p_double[j+1]))||ae_fp_neq(tbl0.ptr.pp_double[p0][4],z.ptr.p_double[k]))||ae_fp_neq(tbl0.ptr.pp_double[p0][5],z.ptr.p_double[k+1]); /* * *check, that all components unpacked by Unpack * function are equal to all components unpacked * by UnpackV function. */ for(i0=0; i0<=13; i0++) { bperr = bperr||ae_fp_neq(tbl0.ptr.pp_double[p0][i0],tbl1.ptr.pp_double[p1][i0]); } if( bperr ) { result = ae_true; ae_frame_leave(_state); return result; } tx = (0.001+0.999*ae_randomreal(_state))*(tbl1.ptr.pp_double[p1][1]-tbl1.ptr.pp_double[p1][0]); ty = (0.001+0.999*ae_randomreal(_state))*(tbl1.ptr.pp_double[p1][3]-tbl1.ptr.pp_double[p1][2]); tz = (0.001+0.999*ae_randomreal(_state))*(tbl1.ptr.pp_double[p1][5]-tbl1.ptr.pp_double[p1][4]); /* * Interpolation properties for: * *scalar function; */ v1 = (double)(0); for(ci=0; ci<=1; ci++) { for(cj=0; cj<=1; cj++) { for(ck=0; ck<=1; ck++) { v1 = v1+tbl1.ptr.pp_double[p1][6+2*(2*ck+cj)+ci]*ae_pow(tx, (double)(ci), _state)*ae_pow(ty, (double)(cj), _state)*ae_pow(tz, (double)(ck), _state); } } } v2 = spline3dcalc(&c, tbl1.ptr.pp_double[p1][0]+tx, tbl1.ptr.pp_double[p1][2]+ty, tbl1.ptr.pp_double[p1][4]+tz, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); /* * *component of vector function. */ v1 = (double)(0); for(ci=0; ci<=1; ci++) { for(cj=0; cj<=1; cj++) { for(ck=0; ck<=1; ck++) { v1 = v1+tbl0.ptr.pp_double[p0][6+2*(2*ck+cj)+ci]*ae_pow(tx, (double)(ci), _state)*ae_pow(ty, (double)(cj), _state)*ae_pow(tz, (double)(ck), _state); } } } v2 = spline3dcalc(&c, tbl0.ptr.pp_double[p0][0]+tx, tbl0.ptr.pp_double[p0][2]+ty, tbl0.ptr.pp_double[p0][4]+tz, _state); err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); } } } } } result = ae_fp_greater(err,1.0E+5*ae_machineepsilon); ae_frame_leave(_state); return result; } /************************************************************************* LinTrans test *************************************************************************/ static ae_bool testspline3dunit_testlintrans(ae_state *_state) { ae_frame _frame_block; spline3dinterpolant c; spline3dinterpolant c2; ae_int_t m; ae_int_t n; ae_int_t l; ae_int_t d; ae_vector x; ae_vector y; ae_vector z; ae_vector f; double a1; double a2; double a3; double b1; double b2; double b3; double tx; double ty; double tz; double vx; double vy; double vz; ae_vector v1; ae_vector v2; ae_int_t pass; ae_int_t passcount; ae_int_t xjob; ae_int_t yjob; ae_int_t zjob; double err; ae_int_t i; ae_bool result; ae_frame_make(_state, &_frame_block); _spline3dinterpolant_init(&c, _state); _spline3dinterpolant_init(&c2, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_vector_init(&v1, 0, DT_REAL, _state); ae_vector_init(&v2, 0, DT_REAL, _state); err = (double)(0); passcount = 15; for(pass=1; pass<=passcount; pass++) { testspline3dunit_buildrndgrid(ae_true, ae_false, &n, &m, &l, &d, &x, &y, &z, &f, _state); spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &f, d, &c, _state); for(xjob=0; xjob<=1; xjob++) { for(yjob=0; yjob<=1; yjob++) { for(zjob=0; zjob<=1; zjob++) { /* * Prepare */ do { a1 = 2.0*ae_randomreal(_state)-1.0; } while(ae_fp_eq(a1,(double)(0))); a1 = a1*xjob; b1 = x.ptr.p_double[0]+ae_randomreal(_state)*(x.ptr.p_double[n-1]-x.ptr.p_double[0]+2.0)-1.0; do { a2 = 2.0*ae_randomreal(_state)-1.0; } while(ae_fp_eq(a2,(double)(0))); a2 = a2*yjob; b2 = y.ptr.p_double[0]+ae_randomreal(_state)*(y.ptr.p_double[m-1]-y.ptr.p_double[0]+2.0)-1.0; do { a3 = 2.0*ae_randomreal(_state)-1.0; } while(ae_fp_eq(a3,(double)(0))); a3 = a3*zjob; b3 = z.ptr.p_double[0]+ae_randomreal(_state)*(z.ptr.p_double[l-1]-z.ptr.p_double[0]+2.0)-1.0; /* * Test XYZ */ spline3dcopy(&c, &c2, _state); spline3dlintransxyz(&c2, a1, b1, a2, b2, a3, b3, _state); tx = x.ptr.p_double[0]+ae_randomreal(_state)*(x.ptr.p_double[n-1]-x.ptr.p_double[0]); ty = y.ptr.p_double[0]+ae_randomreal(_state)*(y.ptr.p_double[m-1]-y.ptr.p_double[0]); tz = z.ptr.p_double[0]+ae_randomreal(_state)*(z.ptr.p_double[l-1]-z.ptr.p_double[0]); if( xjob==0 ) { tx = b1; vx = x.ptr.p_double[0]+ae_randomreal(_state)*(x.ptr.p_double[n-1]-x.ptr.p_double[0]); } else { vx = (tx-b1)/a1; } if( yjob==0 ) { ty = b2; vy = y.ptr.p_double[0]+ae_randomreal(_state)*(y.ptr.p_double[m-1]-y.ptr.p_double[0]); } else { vy = (ty-b2)/a2; } if( zjob==0 ) { tz = b3; vz = z.ptr.p_double[0]+ae_randomreal(_state)*(z.ptr.p_double[l-1]-z.ptr.p_double[0]); } else { vz = (tz-b3)/a3; } spline3dcalcv(&c, tx, ty, tz, &v1, _state); spline3dcalcv(&c2, vx, vy, vz, &v2, _state); for(i=0; i<=d-1; i++) { err = ae_maxreal(err, ae_fabs(v1.ptr.p_double[i]-v2.ptr.p_double[i], _state), _state); } if( ae_fp_greater(err,1.0E+4*ae_machineepsilon) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Test F */ spline3dcopy(&c, &c2, _state); spline3dlintransf(&c2, a1, b1, _state); tx = x.ptr.p_double[0]+ae_randomreal(_state)*(x.ptr.p_double[n-1]-x.ptr.p_double[0]); ty = y.ptr.p_double[0]+ae_randomreal(_state)*(y.ptr.p_double[m-1]-y.ptr.p_double[0]); tz = z.ptr.p_double[0]+ae_randomreal(_state)*(z.ptr.p_double[l-1]-z.ptr.p_double[0]); spline3dcalcv(&c, tx, ty, tz, &v1, _state); spline3dcalcv(&c2, tx, ty, tz, &v2, _state); for(i=0; i<=d-1; i++) { err = ae_maxreal(err, ae_fabs(a1*v1.ptr.p_double[i]+b1-v2.ptr.p_double[i], _state), _state); } } } } } result = ae_fp_greater(err,1.0E+4*ae_machineepsilon); ae_frame_leave(_state); return result; } /************************************************************************* Resample test *************************************************************************/ static ae_bool testspline3dunit_testtrilinearresample(ae_state *_state) { ae_frame _frame_block; spline3dinterpolant c; ae_int_t n; ae_int_t m; ae_int_t l; ae_int_t n2; ae_int_t m2; ae_int_t l2; ae_vector x; ae_vector y; ae_vector z; ae_vector f; ae_vector fr; double v1; double v2; double err; double mf; ae_int_t pass; ae_int_t passcount; ae_int_t i; ae_int_t j; ae_int_t k; ae_bool result; ae_frame_make(_state, &_frame_block); _spline3dinterpolant_init(&c, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&z, 0, DT_REAL, _state); ae_vector_init(&f, 0, DT_REAL, _state); ae_vector_init(&fr, 0, DT_REAL, _state); result = ae_false; passcount = 20; for(pass=1; pass<=passcount; pass++) { n = ae_randominteger(4, _state)+2; m = ae_randominteger(4, _state)+2; l = ae_randominteger(4, _state)+2; n2 = ae_randominteger(4, _state)+2; m2 = ae_randominteger(4, _state)+2; l2 = ae_randominteger(4, _state)+2; rvectorsetlengthatleast(&x, n, _state); rvectorsetlengthatleast(&y, m, _state); rvectorsetlengthatleast(&z, l, _state); rvectorsetlengthatleast(&f, n*m*l, _state); for(i=0; i<=n-1; i++) { x.ptr.p_double[i] = (double)i/(double)(n-1); } for(i=0; i<=m-1; i++) { y.ptr.p_double[i] = (double)i/(double)(m-1); } for(i=0; i<=l-1; i++) { z.ptr.p_double[i] = (double)i/(double)(l-1); } for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { for(k=0; k<=l-1; k++) { f.ptr.p_double[n*(m*k+j)+i] = 2*ae_randomreal(_state)-1; } } } spline3dresampletrilinear(&f, l, m, n, l2, m2, n2, &fr, _state); spline3dbuildtrilinearv(&x, n, &y, m, &z, l, &f, 1, &c, _state); err = (double)(0); mf = (double)(0); for(i=0; i<=n2-1; i++) { for(j=0; j<=m2-1; j++) { for(k=0; k<=l2-1; k++) { v1 = spline3dcalc(&c, (double)i/(double)(n2-1), (double)j/(double)(m2-1), (double)k/(double)(l2-1), _state); v2 = fr.ptr.p_double[n2*(m2*k+j)+i]; err = ae_maxreal(err, ae_fabs(v1-v2, _state), _state); mf = ae_maxreal(mf, ae_fabs(v1, _state), _state); } } } result = result||ae_fp_greater(err/mf,1.0E+4*ae_machineepsilon); if( result ) { ae_frame_leave(_state); return result; } } ae_frame_leave(_state); return result; } /************************************************************************* The function does build random function on random grid with random number of points: * N, M, K - random from 2 to 5 * D - 1 in case IsVect=False, 1..3 in case IsVect=True * X, Y, Z - each variable spans from MinV to MaxV, with MinV is random number from [-1.5,0.5] and MaxV is random number from [0.5,1.5]. All nodes are well separated. All nodes are randomly reordered in case Reorder=False. When Reorder=True, nodes are returned in ascending order. * F - random values from [-1,+1] *************************************************************************/ static void testspline3dunit_buildrndgrid(ae_bool isvect, ae_bool reorder, ae_int_t* n, ae_int_t* m, ae_int_t* l, ae_int_t* d, /* Real */ ae_vector* x, /* Real */ ae_vector* y, /* Real */ ae_vector* z, /* Real */ ae_vector* f, ae_state *_state) { double st; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t di; double v; double mx; double maxv; double minv; *n = 0; *m = 0; *l = 0; *d = 0; ae_vector_clear(x); ae_vector_clear(y); ae_vector_clear(z); ae_vector_clear(f); st = 0.3; *m = ae_randominteger(4, _state)+2; *n = ae_randominteger(4, _state)+2; *l = ae_randominteger(4, _state)+2; if( isvect ) { *d = ae_randominteger(3, _state)+1; } else { *d = 1; } rvectorsetlengthatleast(x, *n, _state); rvectorsetlengthatleast(y, *m, _state); rvectorsetlengthatleast(z, *l, _state); rvectorsetlengthatleast(f, *n*(*m)*(*l)*(*d), _state); /* * Fill X */ x->ptr.p_double[0] = (double)(0); for(i=1; i<=*n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i-1]+st+ae_randomreal(_state); } minv = -0.5-ae_randomreal(_state); maxv = 0.5+ae_randomreal(_state); mx = x->ptr.p_double[*n-1]; for(i=0; i<=*n-1; i++) { x->ptr.p_double[i] = x->ptr.p_double[i]/mx*(maxv-minv)+minv; } if( reorder ) { for(i=0; i<=*n-1; i++) { k = ae_randominteger(*n, _state); v = x->ptr.p_double[i]; x->ptr.p_double[i] = x->ptr.p_double[k]; x->ptr.p_double[k] = v; } } /* * Fill Y */ y->ptr.p_double[0] = (double)(0); for(i=1; i<=*m-1; i++) { y->ptr.p_double[i] = y->ptr.p_double[i-1]+st+ae_randomreal(_state); } minv = -0.5-ae_randomreal(_state); maxv = 0.5+ae_randomreal(_state); mx = y->ptr.p_double[*m-1]; for(i=0; i<=*m-1; i++) { y->ptr.p_double[i] = y->ptr.p_double[i]/mx*(maxv-minv)+minv; } if( reorder ) { for(i=0; i<=*m-1; i++) { k = ae_randominteger(*m, _state); v = y->ptr.p_double[i]; y->ptr.p_double[i] = y->ptr.p_double[k]; y->ptr.p_double[k] = v; } } /* * Fill Z */ z->ptr.p_double[0] = (double)(0); for(i=1; i<=*l-1; i++) { z->ptr.p_double[i] = z->ptr.p_double[i-1]+st+ae_randomreal(_state); } minv = -0.5-ae_randomreal(_state); maxv = 0.5+ae_randomreal(_state); mx = z->ptr.p_double[*l-1]; for(i=0; i<=*l-1; i++) { z->ptr.p_double[i] = z->ptr.p_double[i]/mx*(maxv-minv)+minv; } if( reorder ) { for(i=0; i<=*l-1; i++) { k = ae_randominteger(*l, _state); v = z->ptr.p_double[i]; z->ptr.p_double[i] = z->ptr.p_double[k]; z->ptr.p_double[k] = v; } } /* * Fill F */ for(i=0; i<=*n-1; i++) { for(j=0; j<=*m-1; j++) { for(k=0; k<=*l-1; k++) { for(di=0; di<=*d-1; di++) { f->ptr.p_double[*d*(*n*(*m*k+j)+i)+di] = 2*ae_randomreal(_state)-1; } } } } } /************************************************************************* Testing bidiagonal SVD decomposition subroutine *************************************************************************/ ae_bool testspdgevd(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_int_t pass; ae_int_t n; ae_int_t passcount; ae_int_t maxn; ae_int_t atask; ae_int_t btask; ae_vector d; ae_vector t1; ae_matrix a; ae_matrix b; ae_matrix afull; ae_matrix bfull; ae_matrix l; ae_matrix z; ae_bool isuppera; ae_bool isupperb; ae_int_t i; ae_int_t j; ae_int_t minij; double v; double v1; double v2; double err; double valerr; double threshold; ae_bool waserrors; ae_bool wfailed; ae_bool wnsorted; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&t1, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&b, 0, 0, DT_REAL, _state); ae_matrix_init(&afull, 0, 0, DT_REAL, _state); ae_matrix_init(&bfull, 0, 0, DT_REAL, _state); ae_matrix_init(&l, 0, 0, DT_REAL, _state); ae_matrix_init(&z, 0, 0, DT_REAL, _state); threshold = 10000*ae_machineepsilon; valerr = (double)(0); wfailed = ae_false; wnsorted = ae_false; maxn = 20; passcount = 5; /* * Main cycle */ for(n=1; n<=maxn; n++) { for(pass=1; pass<=passcount; pass++) { for(atask=0; atask<=1; atask++) { for(btask=0; btask<=1; btask++) { isuppera = atask==0; isupperb = btask==0; /* * Initialize A, B, AFull, BFull */ ae_vector_set_length(&t1, n-1+1, _state); ae_matrix_set_length(&a, n-1+1, n-1+1, _state); ae_matrix_set_length(&b, n-1+1, n-1+1, _state); ae_matrix_set_length(&afull, n-1+1, n-1+1, _state); ae_matrix_set_length(&bfull, n-1+1, n-1+1, _state); ae_matrix_set_length(&l, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; a.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; afull.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]; afull.ptr.pp_double[j][i] = a.ptr.pp_double[i][j]; } } for(i=0; i<=n-1; i++) { for(j=i+1; j<=n-1; j++) { l.ptr.pp_double[i][j] = ae_randomreal(_state); l.ptr.pp_double[j][i] = l.ptr.pp_double[i][j]; } l.ptr.pp_double[i][i] = 1.5+ae_randomreal(_state); } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { minij = ae_minint(i, j, _state); v = ae_v_dotproduct(&l.ptr.pp_double[i][0], 1, &l.ptr.pp_double[0][j], l.stride, ae_v_len(0,minij)); b.ptr.pp_double[i][j] = v; b.ptr.pp_double[j][i] = v; bfull.ptr.pp_double[i][j] = v; bfull.ptr.pp_double[j][i] = v; } } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( isuppera ) { if( jptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } } /************************************************************************* LU decomposition *************************************************************************/ static void testinverseupdateunit_matlu(/* Real */ ae_matrix* a, ae_int_t m, ae_int_t n, /* Integer */ ae_vector* pivots, ae_state *_state) { ae_frame _frame_block; ae_int_t i; ae_int_t j; ae_int_t jp; ae_vector t1; double s; ae_frame_make(_state, &_frame_block); ae_vector_clear(pivots); ae_vector_init(&t1, 0, DT_REAL, _state); ae_vector_set_length(pivots, ae_minint(m-1, n-1, _state)+1, _state); ae_vector_set_length(&t1, ae_maxint(m-1, n-1, _state)+1, _state); ae_assert(m>=0&&n>=0, "Error in LUDecomposition: incorrect function arguments", _state); /* * Quick return if possible */ if( m==0||n==0 ) { ae_frame_leave(_state); return; } for(j=0; j<=ae_minint(m-1, n-1, _state); j++) { /* * Find pivot and test for singularity. */ jp = j; for(i=j+1; i<=m-1; i++) { if( ae_fp_greater(ae_fabs(a->ptr.pp_double[i][j], _state),ae_fabs(a->ptr.pp_double[jp][j], _state)) ) { jp = i; } } pivots->ptr.p_int[j] = jp; if( ae_fp_neq(a->ptr.pp_double[jp][j],(double)(0)) ) { /* *Apply the interchange to rows */ if( jp!=j ) { ae_v_move(&t1.ptr.p_double[0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[j][0], 1, &a->ptr.pp_double[jp][0], 1, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[jp][0], 1, &t1.ptr.p_double[0], 1, ae_v_len(0,n-1)); } /* *Compute elements J+1:M of J-th column. */ if( j+1ptr.pp_double[j][j]; ae_v_muld(&a->ptr.pp_double[jp][j], a->stride, ae_v_len(jp,m-1), s); } } if( jptr.pp_double[i][j]; ae_v_subd(&a->ptr.pp_double[i][jp], 1, &a->ptr.pp_double[j][jp], 1, ae_v_len(jp,n-1), s); } } } ae_frame_leave(_state); } /************************************************************************* Generate matrix with given condition number C (2-norm) *************************************************************************/ static void testinverseupdateunit_generaterandomorthogonalmatrix(/* Real */ ae_matrix* a0, ae_int_t n, ae_state *_state) { ae_frame _frame_block; double t; double lambdav; ae_int_t s; ae_int_t i; ae_int_t j; double u1; double u2; ae_vector w; ae_vector v; ae_matrix a; double sm; ae_frame_make(_state, &_frame_block); ae_vector_init(&w, 0, DT_REAL, _state); ae_vector_init(&v, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); if( n<=0 ) { ae_frame_leave(_state); return; } ae_vector_set_length(&w, n+1, _state); ae_vector_set_length(&v, n+1, _state); ae_matrix_set_length(&a, n+1, n+1, _state); ae_matrix_set_length(a0, n-1+1, n-1+1, _state); /* * Prepare A */ for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if( i==j ) { a.ptr.pp_double[i][j] = (double)(1); } else { a.ptr.pp_double[i][j] = (double)(0); } } } /* * Calculate A using Stewart algorithm */ for(s=2; s<=n; s++) { /* * Prepare v and Lambda = v'*v */ do { i = 1; while(i<=s) { u1 = 2*ae_randomreal(_state)-1; u2 = 2*ae_randomreal(_state)-1; sm = u1*u1+u2*u2; if( ae_fp_eq(sm,(double)(0))||ae_fp_greater(sm,(double)(1)) ) { continue; } sm = ae_sqrt(-2*ae_log(sm, _state)/sm, _state); v.ptr.p_double[i] = u1*sm; if( i+1<=s ) { v.ptr.p_double[i+1] = u2*sm; } i = i+2; } lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); } while(ae_fp_eq(lambdav,(double)(0))); lambdav = 2/lambdav; /* * A * (I - 2 vv'/v'v ) = * = A - (2/v'v) * A * v * v' = * = A - (2/v'v) * w * v' * where w = Av */ for(i=1; i<=s; i++) { t = ae_v_dotproduct(&a.ptr.pp_double[i][1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); w.ptr.p_double[i] = t; } for(i=1; i<=s; i++) { t = w.ptr.p_double[i]*lambdav; ae_v_subd(&a.ptr.pp_double[i][1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s), t); } } /* * */ for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { a0->ptr.pp_double[i-1][j-1] = a.ptr.pp_double[i][j]; } } ae_frame_leave(_state); } static void testinverseupdateunit_generaterandommatrixcond(/* Real */ ae_matrix* a0, ae_int_t n, double c, ae_state *_state) { ae_frame _frame_block; double l1; double l2; ae_matrix q1; ae_matrix q2; ae_vector cc; ae_int_t i; ae_int_t j; ae_int_t k; ae_frame_make(_state, &_frame_block); ae_matrix_init(&q1, 0, 0, DT_REAL, _state); ae_matrix_init(&q2, 0, 0, DT_REAL, _state); ae_vector_init(&cc, 0, DT_REAL, _state); testinverseupdateunit_generaterandomorthogonalmatrix(&q1, n, _state); testinverseupdateunit_generaterandomorthogonalmatrix(&q2, n, _state); ae_vector_set_length(&cc, n-1+1, _state); l1 = (double)(0); l2 = ae_log(1/c, _state); cc.ptr.p_double[0] = ae_exp(l1, _state); for(i=1; i<=n-2; i++) { cc.ptr.p_double[i] = ae_exp(ae_randomreal(_state)*(l2-l1)+l1, _state); } cc.ptr.p_double[n-1] = ae_exp(l2, _state); ae_matrix_set_length(a0, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a0->ptr.pp_double[i][j] = (double)(0); for(k=0; k<=n-1; k++) { a0->ptr.pp_double[i][j] = a0->ptr.pp_double[i][j]+q1.ptr.pp_double[i][k]*cc.ptr.p_double[k]*q2.ptr.pp_double[j][k]; } } } ae_frame_leave(_state); } /************************************************************************* triangular inverse *************************************************************************/ static ae_bool testinverseupdateunit_invmattr(/* Real */ ae_matrix* a, ae_int_t n, ae_bool isupper, ae_bool isunittriangular, ae_state *_state) { ae_frame _frame_block; ae_bool nounit; ae_int_t i; ae_int_t j; double v; double ajj; ae_vector t; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&t, 0, DT_REAL, _state); result = ae_true; ae_vector_set_length(&t, n-1+1, _state); /* * Test the input parameters. */ nounit = !isunittriangular; if( isupper ) { /* * Compute inverse of upper triangular matrix. */ for(j=0; j<=n-1; j++) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } /* * Compute elements 1:j-1 of j-th column. */ if( j>0 ) { ae_v_move(&t.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1)); for(i=0; i<=j-1; i++) { if( iptr.pp_double[i][i+1], 1, &t.ptr.p_double[i+1], 1, ae_v_len(i+1,j-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[0][j], a->stride, ae_v_len(0,j-1), ajj); } } } else { /* * Compute inverse of lower triangular matrix. */ for(j=n-1; j>=0; j--) { if( nounit ) { if( ae_fp_eq(a->ptr.pp_double[j][j],(double)(0)) ) { result = ae_false; ae_frame_leave(_state); return result; } a->ptr.pp_double[j][j] = 1/a->ptr.pp_double[j][j]; ajj = -a->ptr.pp_double[j][j]; } else { ajj = (double)(-1); } if( jptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1)); for(i=j+1; i<=n-1; i++) { if( i>j+1 ) { v = ae_v_dotproduct(&a->ptr.pp_double[i][j+1], 1, &t.ptr.p_double[j+1], 1, ae_v_len(j+1,i-1)); } else { v = (double)(0); } if( nounit ) { a->ptr.pp_double[i][j] = v+a->ptr.pp_double[i][i]*t.ptr.p_double[i]; } else { a->ptr.pp_double[i][j] = v+t.ptr.p_double[i]; } } ae_v_muld(&a->ptr.pp_double[j+1][j], a->stride, ae_v_len(j+1,n-1), ajj); } } } ae_frame_leave(_state); return result; } /************************************************************************* LU inverse *************************************************************************/ static ae_bool testinverseupdateunit_invmatlu(/* Real */ ae_matrix* a, /* Integer */ ae_vector* pivots, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector work; ae_int_t i; ae_int_t j; ae_int_t jp; double v; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&work, 0, DT_REAL, _state); result = ae_true; /* * Quick return if possible */ if( n==0 ) { ae_frame_leave(_state); return result; } ae_vector_set_length(&work, n-1+1, _state); /* * Form inv(U) */ if( !testinverseupdateunit_invmattr(a, n, ae_true, ae_false, _state) ) { result = ae_false; ae_frame_leave(_state); return result; } /* * Solve the equation inv(A)*L = inv(U) for inv(A). */ for(j=n-1; j>=0; j--) { /* * Copy current column of L to WORK and replace with zeros. */ for(i=j+1; i<=n-1; i++) { work.ptr.p_double[i] = a->ptr.pp_double[i][j]; a->ptr.pp_double[i][j] = (double)(0); } /* * Compute current column of inv(A). */ if( jptr.pp_double[i][j+1], 1, &work.ptr.p_double[j+1], 1, ae_v_len(j+1,n-1)); a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]-v; } } } /* * Apply column interchanges. */ for(j=n-2; j>=0; j--) { jp = pivots->ptr.p_int[j]; if( jp!=j ) { ae_v_move(&work.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[0][j], a->stride, &a->ptr.pp_double[0][jp], a->stride, ae_v_len(0,n-1)); ae_v_move(&a->ptr.pp_double[0][jp], a->stride, &work.ptr.p_double[0], 1, ae_v_len(0,n-1)); } } ae_frame_leave(_state); return result; } /************************************************************************* Matrix inverse *************************************************************************/ static ae_bool testinverseupdateunit_invmat(/* Real */ ae_matrix* a, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); testinverseupdateunit_matlu(a, n, n, &pivots, _state); result = testinverseupdateunit_invmatlu(a, &pivots, n, _state); ae_frame_leave(_state); return result; } /************************************************************************* Diff *************************************************************************/ static double testinverseupdateunit_matrixdiff(/* Real */ ae_matrix* a, /* Real */ ae_matrix* b, ae_int_t m, ae_int_t n, ae_state *_state) { ae_int_t i; ae_int_t j; double result; result = (double)(0); for(i=0; i<=m-1; i++) { for(j=0; j<=n-1; j++) { result = ae_maxreal(result, ae_fabs(b->ptr.pp_double[i][j]-a->ptr.pp_double[i][j], _state), _state); } } return result; } /************************************************************************* Update and inverse *************************************************************************/ static ae_bool testinverseupdateunit_updandinv(/* Real */ ae_matrix* a, /* Real */ ae_vector* u, /* Real */ ae_vector* v, ae_int_t n, ae_state *_state) { ae_frame _frame_block; ae_vector pivots; ae_int_t i; double r; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&pivots, 0, DT_INT, _state); for(i=0; i<=n-1; i++) { r = u->ptr.p_double[i]; ae_v_addd(&a->ptr.pp_double[i][0], 1, &v->ptr.p_double[0], 1, ae_v_len(0,n-1), r); } testinverseupdateunit_matlu(a, n, n, &pivots, _state); result = testinverseupdateunit_invmatlu(a, &pivots, n, _state); ae_frame_leave(_state); return result; } static void testschurunit_fillsparsea(/* Real */ ae_matrix* a, ae_int_t n, double sparcity, ae_state *_state); static void testschurunit_testschurproblem(/* Real */ ae_matrix* a, ae_int_t n, double* materr, double* orterr, ae_bool* errstruct, ae_bool* wfailed, ae_state *_state); /************************************************************************* Testing Schur decomposition subroutine *************************************************************************/ ae_bool testschur(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_matrix a; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t j; ae_int_t pass; ae_int_t passcount; ae_bool waserrors; ae_bool errstruct; ae_bool wfailed; double materr; double orterr; double threshold; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&a, 0, 0, DT_REAL, _state); materr = (double)(0); orterr = (double)(0); errstruct = ae_false; wfailed = ae_false; waserrors = ae_false; maxn = 70; passcount = 1; threshold = 5*100*ae_machineepsilon; ae_matrix_set_length(&a, maxn-1+1, maxn-1+1, _state); /* * zero matrix, several cases */ for(i=0; i<=maxn-1; i++) { for(j=0; j<=maxn-1; j++) { a.ptr.pp_double[i][j] = (double)(0); } } for(n=1; n<=maxn; n++) { if( n>30&&n%2==0 ) { continue; } testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); } /* * Dense matrix */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { if( n>30&&n%2==0 ) { continue; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } } testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); } } /* * Sparse matrices, very sparse matrices, incredible sparse matrices */ for(pass=1; pass<=1; pass++) { for(n=1; n<=maxn; n++) { if( n>30&&n%3!=0 ) { continue; } testschurunit_fillsparsea(&a, n, 0.8, _state); testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); testschurunit_fillsparsea(&a, n, 0.9, _state); testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); testschurunit_fillsparsea(&a, n, 0.95, _state); testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); testschurunit_fillsparsea(&a, n, 0.997, _state); testschurunit_testschurproblem(&a, n, &materr, &orterr, &errstruct, &wfailed, _state); } } /* * report */ waserrors = ((ae_fp_greater(materr,threshold)||ae_fp_greater(orterr,threshold))||errstruct)||wfailed; if( !silent ) { printf("TESTING SCHUR DECOMPOSITION\n"); printf("Schur decomposition error: %5.3e\n", (double)(materr)); printf("Schur orthogonality error: %5.3e\n", (double)(orterr)); printf("T matrix structure: "); if( !errstruct ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("Always converged: "); if( !wfailed ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("Threshold: %5.3e\n", (double)(threshold)); if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testschur(ae_bool silent, ae_state *_state) { return testschur(silent, _state); } static void testschurunit_fillsparsea(/* Real */ ae_matrix* a, ae_int_t n, double sparcity, ae_state *_state) { ae_int_t i; ae_int_t j; for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater_eq(ae_randomreal(_state),sparcity) ) { a->ptr.pp_double[i][j] = 2*ae_randomreal(_state)-1; } else { a->ptr.pp_double[i][j] = (double)(0); } } } } static void testschurunit_testschurproblem(/* Real */ ae_matrix* a, ae_int_t n, double* materr, double* orterr, ae_bool* errstruct, ae_bool* wfailed, ae_state *_state) { ae_frame _frame_block; ae_matrix s; ae_matrix t; ae_vector sr; ae_vector astc; ae_vector sastc; ae_int_t i; ae_int_t j; ae_int_t k; double v; double locerr; ae_frame_make(_state, &_frame_block); ae_matrix_init(&s, 0, 0, DT_REAL, _state); ae_matrix_init(&t, 0, 0, DT_REAL, _state); ae_vector_init(&sr, 0, DT_REAL, _state); ae_vector_init(&astc, 0, DT_REAL, _state); ae_vector_init(&sastc, 0, DT_REAL, _state); ae_vector_set_length(&sr, n-1+1, _state); ae_vector_set_length(&astc, n-1+1, _state); ae_vector_set_length(&sastc, n-1+1, _state); /* * Schur decomposition, convergence test */ ae_matrix_set_length(&t, n-1+1, n-1+1, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; } } if( !rmatrixschur(&t, n, &s, _state) ) { *wfailed = ae_true; ae_frame_leave(_state); return; } /* * decomposition error */ locerr = (double)(0); for(j=0; j<=n-1; j++) { ae_v_move(&sr.ptr.p_double[0], 1, &s.ptr.pp_double[j][0], 1, ae_v_len(0,n-1)); for(k=0; k<=n-1; k++) { v = ae_v_dotproduct(&t.ptr.pp_double[k][0], 1, &sr.ptr.p_double[0], 1, ae_v_len(0,n-1)); astc.ptr.p_double[k] = v; } for(k=0; k<=n-1; k++) { v = ae_v_dotproduct(&s.ptr.pp_double[k][0], 1, &astc.ptr.p_double[0], 1, ae_v_len(0,n-1)); sastc.ptr.p_double[k] = v; } for(k=0; k<=n-1; k++) { locerr = ae_maxreal(locerr, ae_fabs(sastc.ptr.p_double[k]-a->ptr.pp_double[k][j], _state), _state); } } *materr = ae_maxreal(*materr, locerr, _state); /* * orthogonality error */ locerr = (double)(0); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = ae_v_dotproduct(&s.ptr.pp_double[0][i], s.stride, &s.ptr.pp_double[0][j], s.stride, ae_v_len(0,n-1)); if( i!=j ) { locerr = ae_maxreal(locerr, ae_fabs(v, _state), _state); } else { locerr = ae_maxreal(locerr, ae_fabs(v-1, _state), _state); } } } *orterr = ae_maxreal(*orterr, locerr, _state); /* * T matrix structure */ for(j=0; j<=n-1; j++) { for(i=j+2; i<=n-1; i++) { if( ae_fp_neq(t.ptr.pp_double[i][j],(double)(0)) ) { *errstruct = ae_true; } } } ae_frame_leave(_state); } static double testminnlcunit_barriertolerance = 0.05; static void testminnlcunit_testbc(ae_bool* wereerrors, ae_state *_state); static void testminnlcunit_testlc(ae_bool* wereerrors, ae_state *_state); static void testminnlcunit_testnlc(ae_bool* wereerrors, ae_state *_state); static void testminnlcunit_testother(ae_bool* wereerrors, ae_state *_state); static void testminnlcunit_testbugs(ae_bool* wereerrors, ae_state *_state); ae_bool testminnlc(ae_bool silent, ae_state *_state) { ae_bool waserrors; ae_bool bcerr; ae_bool lcerr; ae_bool nlcerr; ae_bool othererr; ae_bool bugs; ae_bool result; waserrors = ae_false; bcerr = ae_false; lcerr = ae_false; nlcerr = ae_false; othererr = ae_false; bugs = ae_false; testminnlcunit_testbugs(&bugs, _state); testminnlcunit_testbc(&bcerr, _state); testminnlcunit_testlc(&lcerr, _state); testminnlcunit_testnlc(&nlcerr, _state); testminnlcunit_testother(&othererr, _state); /* * end */ waserrors = (((bcerr||lcerr)||nlcerr)||othererr)||bugs; if( !silent ) { printf("TESTING MINNLC OPTIMIZATION\n"); printf("TESTS:\n"); printf("* BOUND CONSTRAINED "); if( bcerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* LINEARLY CONSTRAINED "); if( lcerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* NONLINEARLY CONSTRAINED "); if( nlcerr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* OTHER PROPERTIES "); if( othererr ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* FIXED BUGS: "); if( bugs ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminnlc(ae_bool silent, ae_state *_state) { return testminnlc(silent, _state); } /************************************************************************* This function tests bound constrained quadratic programming algorithm. On failure sets error flag. *************************************************************************/ static void testminnlcunit_testbc(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; minnlcstate state; minnlcreport rep; ae_int_t n; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t aulits; double tolx; double tolg; ae_int_t scaletype; double rho; ae_matrix fulla; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector s; ae_vector x0; ae_vector x1; double gnorm; double g; hqrndstate rs; ae_frame_make(_state, &_frame_block); _minnlcstate_init(&state, _state); _minnlcreport_init(&rep, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Convex test: * * N dimensions * * random number (0..N) of random boundary constraints * * positive-definite quadratic programming problem * * initial point is random (maybe infeasible!) * * random scale (unit or non-unit) */ aulits = 50; rho = 200.0; tolx = 0.0005; tolg = 0.01; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate well-conditioned problem with unit scale */ spdmatrixrndcond(n, 1.0E2, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = hqrndnormal(&rs, _state); j = hqrnduniformi(&rs, 5, _state); if( j==0 ) { bndl.ptr.p_double[i] = (double)(0); } if( j==1 ) { bndu.ptr.p_double[i] = (double)(0); } if( j==2 ) { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } if( j==3 ) { bndl.ptr.p_double[i] = -0.1; bndu.ptr.p_double[i] = 0.1; } } /* * Apply scaling to quadratic/linear term, so problem becomes * well-conditioned in the scaled coordinates. */ scaletype = hqrnduniformi(&rs, 2, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { if( scaletype==0 ) { s.ptr.p_double[i] = (double)(1); } else { s.ptr.p_double[i] = ae_exp(20*hqrndnormal(&rs, _state), _state); } } for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = x0.ptr.p_double[i]*s.ptr.p_double[i]; bndl.ptr.p_double[i] = bndl.ptr.p_double[i]*s.ptr.p_double[i]; bndu.ptr.p_double[i] = bndu.ptr.p_double[i]*s.ptr.p_double[i]; b.ptr.p_double[i] = b.ptr.p_double[i]/s.ptr.p_double[i]; for(j=0; j<=n-1; j++) { fulla.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]/(s.ptr.p_double[i]*s.ptr.p_double[j]); } } /* * Solve problem */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); if( scaletype!=0 ) { minnlcsetscale(&state, &s, _state); } minnlcsetbc(&state, &bndl, &bndu, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Check feasibility properties */ for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i]-tolx*s.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_greater_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i]+tolx*s.ptr.p_double[i]), _state); } /* * Test - calculate scaled constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+fulla.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } g = s.ptr.p_double[i]*g; if( (ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndl.ptr.p_double[i], _state),tolx*s.ptr.p_double[i]))&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( (ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndu.ptr.p_double[i], _state),tolx*s.ptr.p_double[i]))&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,tolg), _state); } } /* * Non-convex test: * * N dimensions, N>=2 * * box constraints, x[i] in [-1,+1] * * A is symmetric indefinite with condition number 50.0 * * random B with normal entries * * initial point is random, feasible * * scale is always unit * * We check that constrained problem can be successfully solved. * We do not check ability to detect unboundedness of unconstrained * problem because there is such functionality in MinNLC. */ aulits = 50; rho = 200.0; tolx = 0.0005; tolg = 0.01; for(n=2; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate problem */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { fulla.ptr.pp_double[i][j] = 0.0; } } for(i=0; i<=n-1; i++) { fulla.ptr.pp_double[i][i] = -1-hqrnduniformr(&rs, _state); } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = 0.05*hqrndnormal(&rs, _state); bndl.ptr.p_double[i] = (double)(-1); bndu.ptr.p_double[i] = (double)(1); x0.ptr.p_double[i] = 2*hqrnduniformr(&rs, _state)-1; } /* * Solve problem: * * without constraints we expect failure * * with constraints algorithm must succeed */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetbc(&state, &bndl, &bndu, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Check feasibility properties */ for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i]-tolx), _state); seterrorflag(wereerrors, ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_greater_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i]+tolx), _state); } /* * Test - calculate scaled constrained gradient at solution, * check its norm. */ gnorm = 0.0; for(i=0; i<=n-1; i++) { g = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g = g+fulla.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } g = g; if( (ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndl.ptr.p_double[i], _state),tolx))&&ae_fp_greater(g,(double)(0)) ) { g = (double)(0); } if( (ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndu.ptr.p_double[i], _state),tolx))&&ae_fp_less(g,(double)(0)) ) { g = (double)(0); } gnorm = gnorm+ae_sqr(g, _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,tolg), _state); } } ae_frame_leave(_state); } /************************************************************************* This function tests linearly constrained quadratic programming algorithm. Sets error flag on failure. *************************************************************************/ static void testminnlcunit_testlc(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t k; ae_int_t i; ae_int_t j; ae_int_t pass; ae_matrix q; ae_matrix fulla; double v; double vv; ae_vector tmp; ae_vector bl; ae_vector bu; ae_vector b; ae_vector xs0; ae_vector xstart; ae_vector x; ae_vector x0; ae_vector x1; ae_vector x2; ae_vector xm; ae_vector s; ae_vector g; ae_vector bndl; ae_vector bndu; ae_matrix a; ae_matrix c; ae_matrix ce; ae_vector ct; ae_vector nonnegative; double tolx; double tolg; double tolf; ae_int_t aulits; double rho; minnlcstate state; minnlcreport rep; ae_int_t scaletype; double f0; double f1; double tolconstr; ae_int_t bscale; ae_int_t akind; ae_int_t ccnt; ae_int_t shiftkind; hqrndstate rs; snnlssolver nnls; ae_frame_make(_state, &_frame_block); ae_matrix_init(&q, 0, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_vector_init(&tmp, 0, DT_REAL, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xs0, 0, DT_REAL, _state); ae_vector_init(&xstart, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&xm, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&ce, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&nonnegative, 0, DT_BOOL, _state); _minnlcstate_init(&state, _state); _minnlcreport_init(&rep, _state); _hqrndstate_init(&rs, _state); _snnlssolver_init(&nnls, _state); hqrndrandomize(&rs, _state); /* * First test: * * K=0, where q is random unit vector * * optimization problem has form 0.5*x'*A*x-(x1*A)*x, * where x1 is some random vector * * either: * a) x1 is feasible => we must stop at x1 * b) x1 is infeasible => we must stop at the boundary q'*x=0 and * projection of gradient onto q*x=0 must be zero * * NOTE: we make several passes because some specific kind of errors is rarely * caught by this test, so we need several repetitions. */ rho = 200.0; tolx = 0.0005; tolg = 0.01; aulits = 50; for(n=2; n<=6; n++) { for(pass=0; pass<=4; pass++) { /* * Generate problem: A, b, CMatrix, x0, XStart */ spdmatrixrndcond(n, 1.0E2, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&xm, n, _state); ae_vector_set_length(&xstart, n, _state); ae_matrix_set_length(&c, 1, n+1, _state); ae_vector_set_length(&ct, 1, _state); for(i=0; i<=n-1; i++) { xm.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xstart.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } do { v = (double)(0); for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][i] = 2*ae_randomreal(_state)-1; v = v+ae_sqr(c.ptr.pp_double[0][i], _state); } v = ae_sqrt(v, _state); } while(ae_fp_eq(v,(double)(0))); for(i=0; i<=n-1; i++) { c.ptr.pp_double[0][i] = c.ptr.pp_double[0][i]/v; } c.ptr.pp_double[0][n] = (double)(0); ct.ptr.p_int[0] = 1; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fulla.ptr.pp_double[i][0], 1, &xm.ptr.p_double[0], 1, ae_v_len(0,n-1)); b.ptr.p_double[i] = -v; } /* * Apply scaling to linear term and known solution, * so problem becomes well-conditioned in the scaled coordinates. */ scaletype = hqrnduniformi(&rs, 2, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { if( scaletype==0 ) { s.ptr.p_double[i] = (double)(1); } else { s.ptr.p_double[i] = ae_exp(20*hqrndnormal(&rs, _state), _state); } } for(i=0; i<=n-1; i++) { xm.ptr.p_double[i] = xm.ptr.p_double[i]*s.ptr.p_double[i]; xstart.ptr.p_double[i] = xstart.ptr.p_double[i]*s.ptr.p_double[i]; b.ptr.p_double[i] = b.ptr.p_double[i]/s.ptr.p_double[i]; for(j=0; j<=n-1; j++) { fulla.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]/(s.ptr.p_double[i]*s.ptr.p_double[j]); } } for(j=0; j<=n-1; j++) { c.ptr.pp_double[0][j] = c.ptr.pp_double[0][j]/s.ptr.p_double[j]; } /* * Create optimizer, solve */ minnlccreate(n, &xstart, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetlc(&state, &c, &ct, 1, _state); minnlcsetscale(&state, &s, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Test solution */ ae_vector_set_length(&g, n, _state); ae_v_move(&g.ptr.p_double[0], 1, &b.ptr.p_double[0], 1, ae_v_len(0,n-1)); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&fulla.ptr.pp_double[i][0], 1, &x1.ptr.p_double[0], 1, ae_v_len(0,n-1)); g.ptr.p_double[i] = g.ptr.p_double[i]+v; } v = ae_v_dotproduct(&x1.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); seterrorflag(wereerrors, ae_fp_less(v,-tolx), _state); if( ae_fp_less(v,tolx) ) { /* * Point at the boundary, project gradient into * equality-constrained subspace. */ v = 0.0; vv = 0.0; for(i=0; i<=n-1; i++) { v = v+g.ptr.p_double[i]*c.ptr.pp_double[0][i]; vv = vv+c.ptr.pp_double[0][i]*c.ptr.pp_double[0][i]; } v = v/vv; ae_v_subd(&g.ptr.p_double[0], 1, &c.ptr.pp_double[0][0], 1, ae_v_len(0,n-1), v); } v = 0.0; for(i=0; i<=n-1; i++) { v = v+ae_sqr(g.ptr.p_double[i]*s.ptr.p_double[i], _state); } seterrorflag(wereerrors, ae_fp_greater(ae_sqrt(v, _state),tolg), _state); } } /* * Equality-constrained test: * * N*N SPD A * * K0 ) { c.ptr.pp_double[i][n] = v; } if( ct.ptr.p_int[i]<0 ) { c.ptr.pp_double[i][n] = v; } } /* * Create optimizer, solve */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetbc(&state, &bndl, &bndu, _state); minnlcsetlc(&state, &c, &ct, k, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&x1.ptr.p_double[0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); if( ct.ptr.p_int[i]==0 ) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(v-c.ptr.pp_double[i][n], _state),tolx), _state); } if( ct.ptr.p_int[i]>0 ) { seterrorflag(wereerrors, ae_fp_less(v,c.ptr.pp_double[i][n]-tolx), _state); } if( ct.ptr.p_int[i]<0 ) { seterrorflag(wereerrors, ae_fp_greater(v,c.ptr.pp_double[i][n]+tolx), _state); } } } /* * Boundary and linear equality constrained QP problem, * test checks that different starting points yield same final point: * * random N from [1..6], random K from [1..N-1] * * N*N SPD A with moderate condtion number (important!) * * boundary constraints 0<=x[i]<=1 * * K=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = hqrnduniformr(&rs, _state)-0.5; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } if( akind==2 ) { /* * Dense well conditioned indefinite */ smatrixrndcond(n, 50.0, &a, _state); } if( akind==3 ) { /* * Low rank */ ae_vector_set_length(&tmp, n, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } for(k=1; k<=ae_minint(3, n-1, _state); k++) { for(i=0; i<=n-1; i++) { tmp.ptr.p_double[i] = hqrndnormal(&rs, _state); } v = hqrndnormal(&rs, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]+v*tmp.ptr.p_double[i]*tmp.ptr.p_double[j]; } } } } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_round(ae_pow((double)(2), (double)(n), _state), _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = -1; k = i; c.ptr.pp_double[i][n] = ae_sign((double)(shiftkind), _state)*ae_pow((double)(10), ae_fabs((double)(shiftkind), _state), _state)*ae_machineepsilon; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = (double)(2*(k%2)-1); c.ptr.pp_double[i][n] = c.ptr.pp_double[i][n]+c.ptr.pp_double[i][j]*c.ptr.pp_double[i][j]; k = k/2; } } /* * Create and optimize */ minnlccreate(n, &x, &state, _state); minnlcsetbc(&state, &bl, &bu, _state); minnlcsetlc(&state, &c, &ct, ccnt, _state); minnlcsetcond(&state, 1.0E-12, 0.0, 0.0, 0, _state); minnlcsetalgoaul(&state, 1000.0, 10, _state); while(minnlciteration(&state, _state)) { ae_assert(state.needfij, "Assertion failed", _state); state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+state.x.ptr.p_double[i]*b.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*v; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+v; } } minnlcresults(&state, &xs0, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Evaluate gradient at solution and test */ vv = 0.0; for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v+b.ptr.p_double[i]; if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr)&&ae_fp_greater(v,(double)(0)) ) { v = 0.0; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr)&&ae_fp_less(v,(double)(0)) ) { v = 0.0; } vv = vv+ae_sqr(v, _state); } vv = ae_sqrt(vv, _state); seterrorflag(wereerrors, ae_fp_greater(vv,1.0E-3), _state); } } } } /* * Linear/convex optimization problem with combination of * box and linear constraints: * * * N=2..8 * * f = 0.5*x'*A*x+b'*x * * b has normally distributed entries with scale 10^BScale * * several kinds of A are tried: zero, well conditioned SPD * * box constraints: x[i] in [-1,+1] * * initial point x0 = [0 0 ... 0 0] * * CCnt=min(3,N-1) general linear constraints of form (c,x)=0. * random mix of equality/inequality constraints is tried. * x0 is guaranteed to be feasible. * * We check that constrained gradient is close to zero at solution. * Inequality constraint is considered active if distance to boundary * is less than TolConstr. We use nonnegative least squares solver * in order to compute constrained gradient. */ tolconstr = 1.0E-2; for(n=2; n<=8; n++) { for(akind=0; akind<=1; akind++) { for(bscale=0; bscale>=-2; bscale--) { /* * Generate A, B and initial point */ ae_matrix_set_length(&a, n, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = ae_pow((double)(10), (double)(bscale), _state)*hqrndnormal(&rs, _state); x.ptr.p_double[i] = 0.0; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = 0.0; } } if( akind==1 ) { /* * Dense well conditioned SPD */ spdmatrixrndcond(n, 50.0, &a, _state); } /* * Generate constraints */ ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); for(i=0; i<=n-1; i++) { bl.ptr.p_double[i] = -1.0; bu.ptr.p_double[i] = 1.0; } ccnt = ae_minint(3, n-1, _state); ae_matrix_set_length(&c, ccnt, n+1, _state); ae_vector_set_length(&ct, ccnt, _state); for(i=0; i<=ccnt-1; i++) { ct.ptr.p_int[i] = hqrnduniformi(&rs, 3, _state)-1; c.ptr.pp_double[i][n] = 0.0; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = hqrnduniformr(&rs, _state)-0.5; } } /* * Create and optimize */ minnlccreate(n, &x, &state, _state); minnlcsetbc(&state, &bl, &bu, _state); minnlcsetlc(&state, &c, &ct, ccnt, _state); minnlcsetcond(&state, 1.0E-9, 0.0, 0.0, 0, _state); minnlcsetalgoaul(&state, 1000.0, 10, _state); while(minnlciteration(&state, _state)) { ae_assert(state.needfij, "Assertion failed", _state); state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+state.x.ptr.p_double[i]*b.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*v; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+v; } } minnlcresults(&state, &xs0, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * 1. evaluate unconstrained gradient at solution * * 2. calculate constrained gradient (NNLS solver is used * to evaluate gradient subject to active constraints). * In order to do this we form CE matrix, matrix of active * constraints (columns store constraint vectors). Then * we try to approximate gradient vector by columns of CE, * subject to non-negativity restriction placed on variables * corresponding to inequality constraints. * * Residual from such regression is a constrained gradient vector. */ ae_vector_set_length(&g, n, _state); for(i=0; i<=n-1; i++) { v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); g.ptr.p_double[i] = v+b.ptr.p_double[i]; } ae_matrix_set_length(&ce, n, n+ccnt, _state); ae_vector_set_length(&nonnegative, n+ccnt, _state); k = 0; for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_less(xs0.ptr.p_double[i],bl.ptr.p_double[i]-tolconstr), _state); seterrorflag(wereerrors, ae_fp_greater(xs0.ptr.p_double[i],bu.ptr.p_double[i]+tolconstr), _state); if( ae_fp_less_eq(xs0.ptr.p_double[i],bl.ptr.p_double[i]+tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = 1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } if( ae_fp_greater_eq(xs0.ptr.p_double[i],bu.ptr.p_double[i]-tolconstr) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = 0.0; } ce.ptr.pp_double[i][k] = -1.0; nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } for(i=0; i<=ccnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &xs0.ptr.p_double[0], 1, ae_v_len(0,n-1)); v = v-c.ptr.pp_double[i][n]; seterrorflag(wereerrors, ct.ptr.p_int[i]==0&&ae_fp_greater(ae_fabs(v, _state),tolconstr), _state); seterrorflag(wereerrors, ct.ptr.p_int[i]>0&&ae_fp_less(v,-tolconstr), _state); seterrorflag(wereerrors, ct.ptr.p_int[i]<0&&ae_fp_greater(v,tolconstr), _state); if( ct.ptr.p_int[i]==0 ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_false; inc(&k, _state); continue; } if( (ct.ptr.p_int[i]>0&&ae_fp_less_eq(v,tolconstr))||(ct.ptr.p_int[i]<0&&ae_fp_greater_eq(v,-tolconstr)) ) { for(j=0; j<=n-1; j++) { ce.ptr.pp_double[j][k] = ae_sign((double)(ct.ptr.p_int[i]), _state)*c.ptr.pp_double[i][j]; } nonnegative.ptr.p_bool[k] = ae_true; inc(&k, _state); continue; } } snnlsinit(0, 0, 0, &nnls, _state); snnlssetproblem(&nnls, &ce, &g, 0, k, n, _state); for(i=0; i<=k-1; i++) { if( !nonnegative.ptr.p_bool[i] ) { snnlsdropnnc(&nnls, i, _state); } } snnlssolve(&nnls, &tmp, _state); for(i=0; i<=k-1; i++) { for(j=0; j<=n-1; j++) { g.ptr.p_double[j] = g.ptr.p_double[j]-tmp.ptr.p_double[i]*ce.ptr.pp_double[j][i]; } } vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,n-1)); vv = ae_sqrt(vv, _state); seterrorflag(wereerrors, ae_fp_greater(vv,1.0E-3), _state); } } } ae_frame_leave(_state); } /************************************************************************* This function tests nonlinearly constrained quadratic programming algorithm. Sets error flag on failure. *************************************************************************/ static void testminnlcunit_testnlc(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t n2; double tolx; double tolg; ae_int_t aulits; double rho; minnlcstate state; minnlcreport rep; ae_int_t scaletype; ae_vector x0; ae_vector x1; ae_vector b; ae_vector bndl; ae_vector bndu; ae_vector s; ae_vector g; ae_vector ckind; ae_matrix fulla; ae_matrix c; ae_vector ct; ae_int_t cntbc; ae_int_t cntlc; ae_int_t cntnlec; ae_int_t cntnlic; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t pass; ae_int_t klc; ae_int_t knlc; ae_int_t knlec; ae_int_t knlic; double v; double vv; double vx; double vy; double gnorm; hqrndstate rs; ae_frame_make(_state, &_frame_block); _minnlcstate_init(&state, _state); _minnlcreport_init(&rep, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&g, 0, DT_REAL, _state); ae_vector_init(&ckind, 0, DT_INT, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _hqrndstate_init(&rs, _state); hqrndrandomize(&rs, _state); /* * Basic test: * * 2-dimensional problem * * target function F(x0,x1) = (x0-1)^2 + (x1-1)^2 * * one nonlinear constraint Z(x0,x1) = x0^2+x1^2-1, * which is tried as equality and inequality one */ rho = 200.0; tolx = 0.0005; aulits = 50; n = 2; ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); minnlcsetnlc(&state, 0, 1, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = ae_sqr(state.x.ptr.p_double[0]-1, _state)+ae_sqr(state.x.ptr.p_double[1]-1, _state); state.j.ptr.pp_double[0][0] = 2*(state.x.ptr.p_double[0]-1); state.j.ptr.pp_double[0][1] = 2*(state.x.ptr.p_double[1]-1); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1], _state)-1; state.j.ptr.pp_double[1][0] = 2*state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][1] = 2*state.x.ptr.p_double[1]; continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); minnlcsetnlc(&state, 1, 0, _state); minnlcrestartfrom(&state, &x0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = ae_sqr(state.x.ptr.p_double[0]-1, _state)+ae_sqr(state.x.ptr.p_double[1]-1, _state); state.j.ptr.pp_double[0][0] = 2*(state.x.ptr.p_double[0]-1); state.j.ptr.pp_double[0][1] = 2*(state.x.ptr.p_double[1]-1); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1], _state)-1; state.j.ptr.pp_double[1][0] = 2*state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][1] = 2*state.x.ptr.p_double[1]; continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); /* * This test checks correctness of scaling being applied to nonlinear * constraints. We solve bound constrained scaled problem and check * that solution is correct. */ aulits = 50; rho = 200.0; tolx = 0.0005; tolg = 0.01; for(n=1; n<=10; n++) { for(pass=1; pass<=10; pass++) { /* * Generate well-conditioned problem with unit scale */ spdmatrixrndcond(n, 1.0E2, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } cntnlec = hqrnduniformi(&rs, n, _state); cntnlic = n-cntnlec; for(i=0; i<=cntnlec-1; i++) { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } for(i=cntnlec; i<=n-1; i++) { bndl.ptr.p_double[i] = hqrndnormal(&rs, _state); bndu.ptr.p_double[i] = bndl.ptr.p_double[i]+0.5; } /* * Apply scaling to quadratic/linear term, so problem becomes * well-conditioned in the scaled coordinates. */ scaletype = hqrnduniformi(&rs, 2, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { if( scaletype==0 ) { s.ptr.p_double[i] = (double)(1); } else { s.ptr.p_double[i] = ae_exp(20*hqrndnormal(&rs, _state), _state); } } for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = x0.ptr.p_double[i]*s.ptr.p_double[i]; bndl.ptr.p_double[i] = bndl.ptr.p_double[i]*s.ptr.p_double[i]; bndu.ptr.p_double[i] = bndu.ptr.p_double[i]*s.ptr.p_double[i]; b.ptr.p_double[i] = b.ptr.p_double[i]/s.ptr.p_double[i]; for(j=0; j<=n-1; j++) { fulla.ptr.pp_double[i][j] = fulla.ptr.pp_double[i][j]/(s.ptr.p_double[i]*s.ptr.p_double[j]); } } /* * Solve problem with boundary constraints posed as nonlinear ones */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetscale(&state, &s, _state); minnlcsetnlc(&state, cntnlec, 2*cntnlic, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { for(i=0; i<=cntnlec+2*cntnlic; i++) { state.fi.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[i][j] = (double)(0); } } /* * Function itself */ for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } /* * Equality constraints */ for(i=0; i<=cntnlec-1; i++) { state.fi.ptr.p_double[1+i] = (state.x.ptr.p_double[i]-bndl.ptr.p_double[i])/s.ptr.p_double[i]; state.j.ptr.pp_double[1+i][i] = 1/s.ptr.p_double[i]; } /* * Inequality constraints */ for(i=0; i<=cntnlic-1; i++) { k = cntnlec+i; state.fi.ptr.p_double[1+cntnlec+2*i+0] = (bndl.ptr.p_double[k]-state.x.ptr.p_double[k])/s.ptr.p_double[k]; state.j.ptr.pp_double[1+cntnlec+2*i+0][k] = -1/s.ptr.p_double[k]; state.fi.ptr.p_double[1+cntnlec+2*i+1] = (state.x.ptr.p_double[k]-bndu.ptr.p_double[k])/s.ptr.p_double[k]; state.j.ptr.pp_double[1+cntnlec+2*i+1][k] = 1/s.ptr.p_double[k]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Check feasibility properties */ for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i]-tolx*s.ptr.p_double[i]), _state); seterrorflag(wereerrors, ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_greater_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i]+tolx*s.ptr.p_double[i]), _state); } /* * Test - calculate scaled constrained gradient at solution, * check its norm. */ ae_vector_set_length(&g, n, _state); gnorm = 0.0; for(i=0; i<=n-1; i++) { g.ptr.p_double[i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { g.ptr.p_double[i] = g.ptr.p_double[i]+fulla.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } g.ptr.p_double[i] = s.ptr.p_double[i]*g.ptr.p_double[i]; if( (ae_isfinite(bndl.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndl.ptr.p_double[i], _state),tolx*s.ptr.p_double[i]))&&ae_fp_greater(g.ptr.p_double[i],(double)(0)) ) { g.ptr.p_double[i] = (double)(0); } if( (ae_isfinite(bndu.ptr.p_double[i], _state)&&ae_fp_less(ae_fabs(x1.ptr.p_double[i]-bndu.ptr.p_double[i], _state),tolx*s.ptr.p_double[i]))&&ae_fp_less(g.ptr.p_double[i],(double)(0)) ) { g.ptr.p_double[i] = (double)(0); } gnorm = gnorm+ae_sqr(g.ptr.p_double[i], _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,tolg), _state); } } /* * Complex problem with mix of boundary, linear and nonlinear constraints: * * quadratic target function f(x) = 0.5*x'*A*x + b'*x * * unit scaling is used * * problem size N is even * * all variables are divided into pairs: x[0] and x[1], x[2] and x[3], ... * * constraints are set for pairs of variables, i.e. each constraint involves * only pair of adjacent variables (x0/x1, x2/x3, x4/x5 and so on), and each * pair of variables has at most one constraint which binds them * * for variables u and v following kinds of constraints can be randomly set: * * CKind=0 no constraint * * CKind=1 boundary equality constraint: u=a, v=b * * CKind=2 boundary inequality constraint: a0<=u<=b0, a1<=v<=b1 * * CKind=3 linear equality constraint: a*u+b*v = c * * CKind=4 linear inequality constraint: a*u+b*v <= c * * CKind=5 nonlinear equality constraint: u^2+v^2 = 1 * * CKind=6 nonlinear inequality constraint: u^2+v^2 <= 1 * * it is relatively easy to calculated projected gradient for such problem */ aulits = 50; rho = 200.0; tolx = 0.0005; tolg = 0.01; n = 20; n2 = n/2; for(pass=1; pass<=50; pass++) { /* * Generate well-conditioned problem with unit scale */ spdmatrixrndcond(n, 1.0E2, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_matrix_set_length(&c, n, n+1, _state); ae_vector_set_length(&ct, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&ckind, n2, _state); cntbc = 0; cntlc = 0; cntnlec = 0; cntnlic = 0; for(i=0; i<=n-1; i++) { bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = hqrndnormal(&rs, _state); b.ptr.p_double[i] = hqrndnormal(&rs, _state); } for(i=0; i<=n2-1; i++) { ckind.ptr.p_int[i] = hqrnduniformi(&rs, 7, _state); if( ckind.ptr.p_int[i]==0 ) { /* * Unconstrained */ continue; } if( ckind.ptr.p_int[i]==1 ) { /* * Bound equality constrained */ bndl.ptr.p_double[2*i+0] = hqrnduniformr(&rs, _state)-0.5; bndu.ptr.p_double[2*i+0] = bndl.ptr.p_double[2*i+0]; bndl.ptr.p_double[2*i+1] = hqrnduniformr(&rs, _state)-0.5; bndu.ptr.p_double[2*i+1] = bndl.ptr.p_double[2*i+1]; inc(&cntbc, _state); continue; } if( ckind.ptr.p_int[i]==2 ) { /* * Bound inequality constrained */ bndl.ptr.p_double[2*i+0] = hqrnduniformr(&rs, _state)-0.5; bndu.ptr.p_double[2*i+0] = bndl.ptr.p_double[2*i+0]+0.5; bndl.ptr.p_double[2*i+1] = hqrnduniformr(&rs, _state)-0.5; bndu.ptr.p_double[2*i+1] = bndl.ptr.p_double[2*i+1]+0.5; inc(&cntbc, _state); continue; } if( ckind.ptr.p_int[i]==3 ) { /* * Linear equality constrained */ for(j=0; j<=n; j++) { c.ptr.pp_double[cntlc][j] = 0.0; } vx = hqrnduniformr(&rs, _state)-0.5; vy = hqrnduniformr(&rs, _state)-0.5; c.ptr.pp_double[cntlc][2*i+0] = vx; c.ptr.pp_double[cntlc][2*i+1] = vy; c.ptr.pp_double[cntlc][n] = hqrnduniformr(&rs, _state)-0.5; ct.ptr.p_int[cntlc] = 0; inc(&cntlc, _state); continue; } if( ckind.ptr.p_int[i]==4 ) { /* * Linear inequality constrained */ for(j=0; j<=n; j++) { c.ptr.pp_double[cntlc][j] = 0.0; } vx = hqrnduniformr(&rs, _state)-0.5; vy = hqrnduniformr(&rs, _state)-0.5; c.ptr.pp_double[cntlc][2*i+0] = vx; c.ptr.pp_double[cntlc][2*i+1] = vy; c.ptr.pp_double[cntlc][n] = hqrnduniformr(&rs, _state)-0.5; ct.ptr.p_int[cntlc] = -1; inc(&cntlc, _state); continue; } if( ckind.ptr.p_int[i]==5 ) { /* * Nonlinear equality constrained */ inc(&cntnlec, _state); continue; } if( ckind.ptr.p_int[i]==6 ) { /* * Nonlinear inequality constrained */ inc(&cntnlic, _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } /* * Solve problem */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetbc(&state, &bndl, &bndu, _state); minnlcsetlc(&state, &c, &ct, cntlc, _state); minnlcsetnlc(&state, cntnlec, cntnlic, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { /* * Evaluate target function */ state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } /* * Evaluate constraint functions */ knlec = 1; knlic = 1+cntnlec; for(i=0; i<=n2-1; i++) { if( ckind.ptr.p_int[i]==5 ) { state.fi.ptr.p_double[knlec] = (double)(0); for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[knlec][j] = 0.0; } state.fi.ptr.p_double[knlec] = ae_sqr(state.x.ptr.p_double[2*i+0], _state)+ae_sqr(state.x.ptr.p_double[2*i+1], _state)-1; state.j.ptr.pp_double[knlec][2*i+0] = 2*state.x.ptr.p_double[2*i+0]; state.j.ptr.pp_double[knlec][2*i+1] = 2*state.x.ptr.p_double[2*i+1]; inc(&knlec, _state); continue; } if( ckind.ptr.p_int[i]==6 ) { state.fi.ptr.p_double[knlic] = (double)(0); for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[knlic][j] = 0.0; } state.fi.ptr.p_double[knlic] = ae_sqr(state.x.ptr.p_double[2*i+0], _state)+ae_sqr(state.x.ptr.p_double[2*i+1], _state)-1; state.j.ptr.pp_double[knlic][2*i+0] = 2*state.x.ptr.p_double[2*i+0]; state.j.ptr.pp_double[knlic][2*i+1] = 2*state.x.ptr.p_double[2*i+1]; inc(&knlic, _state); continue; } } ae_assert(knlec==1+cntnlec, "Assertion failed", _state); ae_assert(knlic==1+cntnlec+cntnlic, "Assertion failed", _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } /* * Check feasibility properties */ klc = 0; for(i=0; i<=n2-1; i++) { if( ckind.ptr.p_int[i]==0 ) { /* * Unconstrained */ continue; } if( ckind.ptr.p_int[i]==1 ) { /* * Bound equality constrained */ seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[2*i+0]-bndl.ptr.p_double[2*i+0], _state),tolx), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[2*i+1]-bndl.ptr.p_double[2*i+1], _state),tolx), _state); continue; } if( ckind.ptr.p_int[i]==2 ) { /* * Bound inequality constrained */ seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[2*i+0],bndl.ptr.p_double[2*i+0]-tolx), _state); seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[2*i+0],bndu.ptr.p_double[2*i+0]+tolx), _state); seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[2*i+1],bndl.ptr.p_double[2*i+1]-tolx), _state); seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[2*i+1],bndu.ptr.p_double[2*i+1]+tolx), _state); continue; } if( ckind.ptr.p_int[i]==3 ) { /* * Linear equality constrained */ v = x1.ptr.p_double[2*i+0]*c.ptr.pp_double[klc][2*i+0]+x1.ptr.p_double[2*i+1]*c.ptr.pp_double[klc][2*i+1]-c.ptr.pp_double[klc][n]; seterrorflag(wereerrors, ae_fp_greater(ae_fabs(v, _state),tolx), _state); inc(&klc, _state); continue; } if( ckind.ptr.p_int[i]==4 ) { /* * Linear inequality constrained */ v = x1.ptr.p_double[2*i+0]*c.ptr.pp_double[klc][2*i+0]+x1.ptr.p_double[2*i+1]*c.ptr.pp_double[klc][2*i+1]-c.ptr.pp_double[klc][n]; seterrorflag(wereerrors, ae_fp_greater(v,tolx), _state); inc(&klc, _state); continue; } if( ckind.ptr.p_int[i]==5 ) { /* * Nonlinear equality constrained */ v = ae_sqr(x1.ptr.p_double[2*i+0], _state)+ae_sqr(x1.ptr.p_double[2*i+1], _state)-1; seterrorflag(wereerrors, ae_fp_greater(ae_fabs(v, _state),tolx), _state); continue; } if( ckind.ptr.p_int[i]==6 ) { /* * Nonlinear inequality constrained */ v = ae_sqr(x1.ptr.p_double[2*i+0], _state)+ae_sqr(x1.ptr.p_double[2*i+1], _state)-1; seterrorflag(wereerrors, ae_fp_greater(v,tolx), _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } /* * Test - calculate scaled constrained gradient at solution, * check its norm. */ ae_vector_set_length(&g, n, _state); for(i=0; i<=n-1; i++) { v = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { v = v+fulla.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } g.ptr.p_double[i] = v; } klc = 0; knlc = 0; for(i=0; i<=n2-1; i++) { if( ckind.ptr.p_int[i]==0 ) { /* * Unconstrained */ continue; } if( ckind.ptr.p_int[i]==1 ) { /* * Bound equality constrained, unconditionally set gradient to zero */ g.ptr.p_double[2*i+0] = 0.0; g.ptr.p_double[2*i+1] = 0.0; continue; } if( ckind.ptr.p_int[i]==2 ) { /* * Bound inequality constrained, conditionally set gradient to zero * (when constraint is active) */ if( ae_fp_less(x1.ptr.p_double[2*i+0],bndl.ptr.p_double[2*i+0]+tolx)||ae_fp_greater(x1.ptr.p_double[2*i+0],bndu.ptr.p_double[2*i+0]-tolx) ) { g.ptr.p_double[2*i+0] = 0.0; } if( ae_fp_less(x1.ptr.p_double[2*i+1],bndl.ptr.p_double[2*i+1]+tolx)||ae_fp_greater(x1.ptr.p_double[2*i+1],bndu.ptr.p_double[2*i+1]-tolx) ) { g.ptr.p_double[2*i+1] = 0.0; } continue; } if( ckind.ptr.p_int[i]==3 ) { /* * Linear equality constrained, unconditionally project gradient into * equality constrained subspace */ v = g.ptr.p_double[2*i+0]*c.ptr.pp_double[klc][2*i+0]+g.ptr.p_double[2*i+1]*c.ptr.pp_double[klc][2*i+1]; vv = ae_sqr(c.ptr.pp_double[klc][2*i+0], _state)+ae_sqr(c.ptr.pp_double[klc][2*i+1], _state); g.ptr.p_double[2*i+0] = g.ptr.p_double[2*i+0]-c.ptr.pp_double[klc][2*i+0]*(v/vv); g.ptr.p_double[2*i+1] = g.ptr.p_double[2*i+1]-c.ptr.pp_double[klc][2*i+1]*(v/vv); inc(&klc, _state); continue; } if( ckind.ptr.p_int[i]==4 ) { /* * Linear inequality constrained, conditionally project gradient * (when constraint is active) */ v = x1.ptr.p_double[2*i+0]*c.ptr.pp_double[klc][2*i+0]+x1.ptr.p_double[2*i+1]*c.ptr.pp_double[klc][2*i+1]-c.ptr.pp_double[klc][n]; if( ae_fp_greater(v,-tolx) ) { v = g.ptr.p_double[2*i+0]*c.ptr.pp_double[klc][2*i+0]+g.ptr.p_double[2*i+1]*c.ptr.pp_double[klc][2*i+1]; vv = ae_sqr(c.ptr.pp_double[klc][2*i+0], _state)+ae_sqr(c.ptr.pp_double[klc][2*i+1], _state); g.ptr.p_double[2*i+0] = g.ptr.p_double[2*i+0]-c.ptr.pp_double[klc][2*i+0]*(v/vv); g.ptr.p_double[2*i+1] = g.ptr.p_double[2*i+1]-c.ptr.pp_double[klc][2*i+1]*(v/vv); } inc(&klc, _state); continue; } if( ckind.ptr.p_int[i]==5 ) { /* * Nonlinear equality constrained, unconditionally project gradient * * NOTE: here we rely on the fact that corresponding components of X * sum to one. */ v = g.ptr.p_double[2*i+0]*x1.ptr.p_double[2*i+0]+g.ptr.p_double[2*i+1]*x1.ptr.p_double[2*i+1]; g.ptr.p_double[2*i+0] = g.ptr.p_double[2*i+0]-x1.ptr.p_double[2*i+0]*v; g.ptr.p_double[2*i+1] = g.ptr.p_double[2*i+1]-x1.ptr.p_double[2*i+1]*v; continue; } if( ckind.ptr.p_int[i]==6 ) { /* * Nonlinear inequality constrained, conditionally project gradient * (when constraint is active) * * NOTE: here we rely on the fact that corresponding components of X * sum to one. */ v = ae_sqr(x1.ptr.p_double[2*i+0], _state)+ae_sqr(x1.ptr.p_double[2*i+1], _state)-1; if( ae_fp_greater(v,-tolx) ) { v = g.ptr.p_double[2*i+0]*x1.ptr.p_double[2*i+0]+g.ptr.p_double[2*i+1]*x1.ptr.p_double[2*i+1]; g.ptr.p_double[2*i+0] = g.ptr.p_double[2*i+0]-x1.ptr.p_double[2*i+0]*v; g.ptr.p_double[2*i+1] = g.ptr.p_double[2*i+1]-x1.ptr.p_double[2*i+1]*v; } continue; } ae_assert(ae_false, "Assertion failed", _state); } gnorm = 0.0; for(i=0; i<=n-1; i++) { gnorm = gnorm+ae_sqr(g.ptr.p_double[i], _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(wereerrors, ae_fp_greater(gnorm,tolg), _state); } ae_frame_leave(_state); } /************************************************************************* This function performs additional tests On failure sets error flag. *************************************************************************/ static void testminnlcunit_testother(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; hqrndstate rs; double v; double h; double fl; double fr; double fl2; double fr2; double dfl; double dfr; double dfl2; double dfr2; double d2fl; double d2fr; double d2fl2; double d2fr2; double f0; double df; double d2f; double ndf; double nd2f; double dtol; double diffstep; minnlcstate state; minnlcreport rep; double rho; ae_int_t aulits; double tolx; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_vector b; ae_vector x0; ae_vector x1; ae_vector x2; ae_vector x3; ae_vector xlast; ae_vector bndl; ae_vector bndu; double condv; ae_matrix a; ae_matrix c; ae_matrix fulla; ae_vector ct; ae_int_t nlbfgs; ae_int_t nexact; ae_int_t nnone; ae_int_t prectype; ae_int_t ctype; ae_int_t trialidx; ae_int_t blocksize; ae_int_t blockcnt; ae_int_t maxits; ae_int_t spoiliteration; ae_int_t stopiteration; ae_int_t spoilvar; double spoilval; ae_int_t pass; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&rs, _state); _minnlcstate_init(&state, _state); _minnlcreport_init(&rep, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&x3, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&fulla, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); hqrndrandomize(&rs, _state); /* * Test equality penalty function (correctly calculated and smooth) */ h = 1.0E-4; v = -0.98; dtol = 1.0E-3; while(ae_fp_less_eq(v,0.98)) { /* * Test numerical derivative; this test also checks continuity of the * function */ minnlcequalitypenaltyfunction(v-2*h, &fl2, &dfl2, &d2fl2, _state); minnlcequalitypenaltyfunction(v-h, &fl, &dfl, &d2fl, _state); minnlcequalitypenaltyfunction(v+h, &fr, &dfr, &d2fr, _state); minnlcequalitypenaltyfunction(v+2*h, &fr2, &dfr2, &d2fr2, _state); minnlcequalitypenaltyfunction(v, &f0, &df, &d2f, _state); ndf = (-fr2+8*fr-8*fl+fl2)/(12*h); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(ndf-df, _state),dtol*ae_maxreal(ae_fabs(ndf, _state), (double)(1), _state)), _state); nd2f = (-dfr2+8*dfr-8*dfl+dfl2)/(12*h); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(nd2f-d2f, _state),dtol*ae_maxreal(ae_fabs(nd2f, _state), (double)(1), _state)), _state); /* * Next point */ v = v+h; } minnlcequalitypenaltyfunction(0.0, &f0, &df, &d2f, _state); seterrorflag(wereerrors, ae_fp_neq(f0,(double)(0)), _state); seterrorflag(wereerrors, ae_fp_neq(df,(double)(0)), _state); /* * Test inequality penalty function (correctly calculated and smooth) */ h = 1.0E-4; v = 0.02; dtol = 1.0E-3; while(ae_fp_less_eq(v,2.00)) { /* * Test numerical derivative; this test also checks continuity of the * function */ minnlcinequalityshiftfunction(v-2*h, &fl2, &dfl2, &d2fl2, _state); minnlcinequalityshiftfunction(v-h, &fl, &dfl, &d2fl, _state); minnlcinequalityshiftfunction(v+h, &fr, &dfr, &d2fr, _state); minnlcinequalityshiftfunction(v+2*h, &fr2, &dfr2, &d2fr2, _state); minnlcinequalityshiftfunction(v, &f0, &df, &d2f, _state); ndf = (-fr2+8*fr-8*fl+fl2)/(12*h); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(ndf-df, _state),dtol*ae_maxreal(ae_fabs(ndf, _state), (double)(1), _state)), _state); nd2f = (-dfr2+8*dfr-8*dfl+dfl2)/(12*h); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(nd2f-d2f, _state),dtol*ae_maxreal(ae_fabs(nd2f, _state), (double)(1), _state)), _state); /* * Next point */ v = v+h; } minnlcinequalityshiftfunction(1.0, &f0, &df, &d2f, _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(f0, _state),1.0E-6), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(df+1, _state),1.0E-6), _state); /* * Test location reports */ aulits = 50; rho = 200.0; tolx = 0.0005; n = 2; ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xlast, n, _state); x0.ptr.p_double[0] = 0.1; x0.ptr.p_double[1] = 0.2; xlast.ptr.p_double[0] = (double)(0); xlast.ptr.p_double[1] = (double)(0); minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); minnlcsetnlc(&state, 0, 1, _state); minnlcsetxrep(&state, ae_true, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = ae_sqr(state.x.ptr.p_double[0]-1, _state)+ae_sqr(state.x.ptr.p_double[1]-1, _state); state.j.ptr.pp_double[0][0] = 2*(state.x.ptr.p_double[0]-1); state.j.ptr.pp_double[0][1] = 2*(state.x.ptr.p_double[1]-1); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1], _state)-1; state.j.ptr.pp_double[1][0] = 2*state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][1] = 2*state.x.ptr.p_double[1]; continue; } if( state.xupdated ) { /* * Save last point */ xlast.ptr.p_double[0] = state.x.ptr.p_double[0]; xlast.ptr.p_double[1] = state.x.ptr.p_double[1]; continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-xlast.ptr.p_double[0], _state),1.0E4*ae_machineepsilon), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-xlast.ptr.p_double[1], _state),1.0E4*ae_machineepsilon), _state); /* * Test numerical differentiation */ aulits = 50; rho = 200.0; tolx = 0.0001; diffstep = 0.001; n = 2; ae_vector_set_length(&x0, n, _state); x0.ptr.p_double[0] = 0.1; x0.ptr.p_double[1] = 0.2; minnlccreatef(n, &x0, diffstep, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); minnlcsetnlc(&state, 0, 1, _state); while(minnlciteration(&state, _state)) { if( state.needfi ) { state.fi.ptr.p_double[0] = ae_sqr(state.x.ptr.p_double[0]-1, _state)+ae_sqr(state.x.ptr.p_double[1]-1, _state); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1], _state)-1; continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-ae_sqrt((double)(2), _state)/2, _state),tolx), _state); /* * Test gradient checking */ aulits = 50; rho = 200.0; tolx = 0.0001; diffstep = 0.001; n = 2; ae_vector_set_length(&x0, n, _state); x0.ptr.p_double[0] = 0.1; x0.ptr.p_double[1] = 0.2; minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetgradientcheck(&state, diffstep, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); minnlcsetnlc(&state, 0, 1, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = ae_sqr(state.x.ptr.p_double[0]-1, _state)+ae_sqr(state.x.ptr.p_double[1]-1, _state); state.j.ptr.pp_double[0][0] = 2*(state.x.ptr.p_double[0]-1); state.j.ptr.pp_double[0][1] = 2*(state.x.ptr.p_double[1]-1); state.fi.ptr.p_double[1] = ae_sqr(state.x.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1], _state)-1; state.j.ptr.pp_double[1][0] = 2*state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][1] = (double)(0); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype!=-7, _state); seterrorflag(wereerrors, rep.varidx!=1, _state); seterrorflag(wereerrors, rep.funcidx!=1, _state); /* * Check handling of general linear constraints: solve linearly * constrained twice, first time with constraints posed as linear * ones, second time with constraints posed as nonlinear ones. * * Linear constraints are normalized because we know that optimizer * normalizes them internally. * * We perform small amount of inner iterations - just 3 steps. * Only one outer iteration is performed. Such small number of * iterations allows to reduce influence of round-off errors * and compare results returned by different control paths within * optimizer (control path for linear constraints and one for * nonlinear constraints). * * We test following kinds of preconditioners: * * "none" * * "exact low rank", restart frequency is 1 * Inexact LBFGS-based preconditioner is not tested because its * behavior greatly depends on order of equations. */ n = 30; k = 5; rho = 1.0E3; aulits = 1; maxits = 3; ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, k, n+1, _state); ae_vector_set_length(&ct, k, _state); for(prectype=0; prectype<=1; prectype++) { for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } for(i=0; i<=k-1; i++) { v = 0.0; for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = hqrndnormal(&rs, _state); v = v+ae_sqr(c.ptr.pp_double[i][j], _state); } v = 1/ae_sqrt(v, _state); ae_v_muld(&c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[i][n] = v; ct.ptr.p_int[i] = 0; } minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, maxits, _state); if( prectype==0 ) { minnlcsetprecnone(&state, _state); } if( prectype==1 ) { minnlcsetprecexactlowrank(&state, 1, _state); } minnlcsetlc(&state, &c, &ct, k, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+ae_sqr(state.x.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = 2*state.x.ptr.p_double[i]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, maxits, _state); if( prectype==0 ) { minnlcsetprecnone(&state, _state); } if( prectype==1 ) { minnlcsetprecexactlowrank(&state, 1, _state); } minnlcsetnlc(&state, k, 0, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+ae_sqr(state.x.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = 2*state.x.ptr.p_double[i]; } for(i=0; i<=k-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[1+i] = v-c.ptr.pp_double[i][n]; ae_v_move(&state.j.ptr.pp_double[1+i][0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x2, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x2, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(wereerrors, ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-x2.ptr.p_double[i], _state),1.0E-4), _state); } } /* * Test preconditioning: * * compare number of iterations required to solve problem with * different preconditioners (LBFGS, exact, none) * * a set of trials is performed (100 trials) * * each trial is a solution of boundary/linearly constrained problem * (linear constraints may be posed as nonlinear ones) with normalized * constraint matrix. Normalization is essential for reproducibility * of results . * * Outer loop checks handling of different types of constraints * (posed as linear or nonlinear ones) */ n = 30; blocksize = 3; blockcnt = 3; rho = 1.0E3; aulits = 5; condv = 1.0E2; ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_matrix_set_length(&c, blocksize*blockcnt, n+1, _state); ae_vector_set_length(&ct, blocksize*blockcnt, _state); for(ctype=0; ctype<=1; ctype++) { /* * First, initialize iteration counters */ nlbfgs = 0; nexact = 0; nnone = 0; /* * Perform trials */ for(trialidx=0; trialidx<=99; trialidx++) { /* * Generate: * * boundary constraints BndL/BndU and initial point X0 * * block-diagonal matrix of linear constraints C such * that X0 is feasible w.r.t. constraints given by C */ for(i=0; i<=n-1; i++) { if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { bndl.ptr.p_double[i] = (double)(0); bndu.ptr.p_double[i] = _state->v_posinf; x0.ptr.p_double[i] = hqrnduniformr(&rs, _state); } else { bndl.ptr.p_double[i] = (double)(0); bndu.ptr.p_double[i] = (double)(0); x0.ptr.p_double[i] = (double)(0); } } for(i=0; i<=blocksize*blockcnt-1; i++) { for(j=0; j<=n-1; j++) { c.ptr.pp_double[i][j] = 0.0; } } for(k=0; k<=blockcnt-1; k++) { rmatrixrndcond(blocksize, condv, &a, _state); for(i=0; i<=blocksize-1; i++) { for(j=0; j<=blocksize-1; j++) { c.ptr.pp_double[k*blocksize+i][k*blocksize+j] = a.ptr.pp_double[i][j]; } } } for(i=0; i<=blocksize*blockcnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = 1/ae_sqrt(v, _state); ae_v_muld(&c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); c.ptr.pp_double[i][n] = v; ct.ptr.p_int[i] = hqrnduniformi(&rs, 3, _state)-1; } /* * Test unpreconditioned iteration */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); if( ctype==0 ) { minnlcsetlc(&state, &c, &ct, blocksize*blockcnt, _state); } else { minnlcsetnlc(&state, blocksize*blockcnt, 0, _state); } minnlcsetprecnone(&state, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+ae_sqr(state.x.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = 2*state.x.ptr.p_double[i]; } if( ctype==1 ) { for(i=0; i<=blocksize*blockcnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[1+i] = v-c.ptr.pp_double[i][n]; ae_v_move(&state.j.ptr.pp_double[1+i][0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } nnone = nnone+rep.iterationscount; /* * Test LBFGS preconditioned iteration */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); if( ctype==0 ) { minnlcsetlc(&state, &c, &ct, blocksize*blockcnt, _state); } else { minnlcsetnlc(&state, blocksize*blockcnt, 0, _state); } minnlcsetprecinexact(&state, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+ae_sqr(state.x.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = 2*state.x.ptr.p_double[i]; } if( ctype==1 ) { for(i=0; i<=blocksize*blockcnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[1+i] = v-c.ptr.pp_double[i][n]; ae_v_move(&state.j.ptr.pp_double[1+i][0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } nlbfgs = nlbfgs+rep.iterationscount; /* * Test exact preconditioner */ minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 1.0E-9, 0, _state); if( ctype==0 ) { minnlcsetlc(&state, &c, &ct, blocksize*blockcnt, _state); } else { minnlcsetnlc(&state, blocksize*blockcnt, 0, _state); } minnlcsetprecexactlowrank(&state, 3, _state); while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+ae_sqr(state.x.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = 2*state.x.ptr.p_double[i]; } if( ctype==1 ) { for(i=0; i<=blocksize*blockcnt-1; i++) { v = ae_v_dotproduct(&c.ptr.pp_double[i][0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); state.fi.ptr.p_double[1+i] = v-c.ptr.pp_double[i][n]; ae_v_move(&state.j.ptr.pp_double[1+i][0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, !isfinitevector(&x1, n, _state), _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } nexact = nexact+rep.iterationscount; } /* * Compare. * * Preconditioners must be significantly different, * with exact being best one, inexact being second, * "none" being worst option. */ seterrorflag(wereerrors, !ae_fp_less((double)(nexact),0.9*nlbfgs), _state); seterrorflag(wereerrors, !ae_fp_less((double)(nlbfgs),0.9*nnone), _state); } /* * Test integrity checks for NAN/INF: * * algorithm solves optimization problem, which is normal for some time (quadratic) * * after 5-th step we choose random component of gradient and consistently spoil * it by NAN or INF. * * we check that correct termination code is returned (-8) */ n = 100; for(pass=1; pass<=10; pass++) { spoiliteration = 5; stopiteration = 8; if( ae_fp_greater(hqrndnormal(&rs, _state),(double)(0)) ) { /* * Gradient can be spoiled by +INF, -INF, NAN */ spoilvar = hqrnduniformi(&rs, n, _state); i = hqrnduniformi(&rs, 3, _state); spoilval = _state->v_nan; if( i==0 ) { spoilval = _state->v_neginf; } if( i==1 ) { spoilval = _state->v_posinf; } } else { /* * Function value can be spoiled only by NAN * (+INF can be recognized as legitimate value during optimization) */ spoilvar = -1; spoilval = _state->v_nan; } spdmatrixrndcond(n, 1.0E5, &fulla, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = hqrndnormal(&rs, _state); x0.ptr.p_double[i] = hqrndnormal(&rs, _state); } minnlccreate(n, &x0, &state, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, stopiteration, _state); minnlcsetxrep(&state, ae_true, _state); k = -1; while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = (double)(0); for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; state.j.ptr.pp_double[0][i] = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.f+0.5*state.x.ptr.p_double[i]*fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+fulla.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } if( k>=spoiliteration ) { if( spoilvar<0 ) { state.fi.ptr.p_double[0] = spoilval; } else { state.j.ptr.pp_double[0][spoilvar] = spoilval; } } continue; } if( state.xupdated ) { inc(&k, _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype!=-8, _state); } ae_frame_leave(_state); } /************************************************************************* This function performs tests for fixed bugs On failure sets error flag. *************************************************************************/ static void testminnlcunit_testbugs(ae_bool* wereerrors, ae_state *_state) { ae_frame _frame_block; hqrndstate rs; ae_int_t n; ae_int_t aulits; ae_int_t maxits; double rho; ae_int_t ckind; minnlcstate state; minnlcreport rep; ae_vector x0; ae_vector x1; ae_vector bndl; ae_vector bndu; ae_vector ct; ae_matrix c; ae_frame_make(_state, &_frame_block); _hqrndstate_init(&rs, _state); _minnlcstate_init(&state, _state); _minnlcreport_init(&rep, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); hqrndrandomize(&rs, _state); /* * Bug description (fixed): sometimes on non-convex problems, when * Lagrange coefficient for inequality constraint becomes small, * algorithm performs VERY deep step into infeasible area (step is 1E50), * which de-stabilizes it and prevents from converging back to feasible area. * * Very rare situation, but must be fixed with additional "convexifying" term. * This test reproduces situation with convexified term turned off, then * checks that introduction of term solves issue. * * We perform three kinds of tests: * * with box inequality constraint * * with linear inequality constraint * * with nonlinear inequality constraint * * In all three cases we: * * first time solve non-convex problem with artificially moved stabilizing * point and decreased initial value of Lagrange multiplier. * * second time we solve problem with good stabilizing point, but zero Lagrange multiplier * * last time solve same problem, but with default settings */ aulits = 1; maxits = 1; rho = 100.0; n = 1; ae_vector_set_length(&x0, n, _state); x0.ptr.p_double[0] = 0.0; ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); bndl.ptr.p_double[0] = 0.0; bndu.ptr.p_double[0] = _state->v_posinf; ae_matrix_set_length(&c, 1, 2, _state); ae_vector_set_length(&ct, 1, _state); c.ptr.pp_double[0][0] = 1.0; c.ptr.pp_double[0][1] = 0.0; ct.ptr.p_int[0] = 1; for(ckind=0; ckind<=2; ckind++) { minnlccreate(n, &x0, &state, _state); state.stabilizingpoint = -1.0E300; state.initialinequalitymultiplier = 1.0E-12; minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, maxits, _state); if( ckind==0 ) { minnlcsetbc(&state, &bndl, &bndu, _state); } if( ckind==1 ) { minnlcsetlc(&state, &c, &ct, 1, _state); } if( ckind==2 ) { minnlcsetnlc(&state, 0, 1, _state); } while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = state.x.ptr.p_double[0]-ae_sqr(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][0] = 1-2*state.x.ptr.p_double[0]; if( ckind==2 ) { state.fi.ptr.p_double[1] = -state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][0] = (double)(-1); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_greater(x1.ptr.p_double[0],-1.0E6), _state); minnlccreate(n, &x0, &state, _state); state.stabilizingpoint = -1.0E2; state.initialinequalitymultiplier = 1.0E-12; minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, maxits, _state); if( ckind==0 ) { minnlcsetbc(&state, &bndl, &bndu, _state); } if( ckind==1 ) { minnlcsetlc(&state, &c, &ct, 1, _state); } if( ckind==2 ) { minnlcsetnlc(&state, 0, 1, _state); } while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = state.x.ptr.p_double[0]-ae_sqr(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][0] = 1-2*state.x.ptr.p_double[0]; if( ckind==2 ) { state.fi.ptr.p_double[1] = -state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][0] = (double)(-1); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[0],3*state.stabilizingpoint), _state); minnlccreate(n, &x0, &state, _state); minnlcsetalgoaul(&state, rho, aulits, _state); minnlcsetcond(&state, 0.0, 0.0, 0.0, maxits, _state); if( ckind==0 ) { minnlcsetbc(&state, &bndl, &bndu, _state); } if( ckind==1 ) { minnlcsetlc(&state, &c, &ct, 1, _state); } if( ckind==2 ) { minnlcsetnlc(&state, 0, 1, _state); } while(minnlciteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = state.x.ptr.p_double[0]-ae_sqr(state.x.ptr.p_double[0], _state); state.j.ptr.pp_double[0][0] = 1-2*state.x.ptr.p_double[0]; if( ckind==2 ) { state.fi.ptr.p_double[1] = -state.x.ptr.p_double[0]; state.j.ptr.pp_double[1][0] = (double)(-1); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnlcresults(&state, &x1, &rep, _state); seterrorflag(wereerrors, rep.terminationtype<=0, _state); if( *wereerrors ) { ae_frame_leave(_state); return; } seterrorflag(wereerrors, ae_fp_less(x1.ptr.p_double[0],3*state.stabilizingpoint), _state); } ae_frame_leave(_state); } static double testminnsunit_scalingtesttol = 1.0E-6; static ae_int_t testminnsunit_scalingtestcnt = 5; static void testminnsunit_basictest0uc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest1uc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest0bc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest1bc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest0lc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest1lc(ae_bool* errors, ae_state *_state); static void testminnsunit_basictest0nlc(ae_bool* errors, ae_state *_state); static void testminnsunit_testuc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state); static void testminnsunit_testbc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state); static void testminnsunit_testlc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state); static void testminnsunit_testnlc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state); static void testminnsunit_testother(ae_bool* othererrors, ae_state *_state); ae_bool testminns(ae_bool silent, ae_state *_state) { ae_bool wereerrors; ae_bool ucerrors; ae_bool bcerrors; ae_bool lcerrors; ae_bool nlcerrors; ae_bool othererrors; ae_bool result; wereerrors = ae_false; ucerrors = ae_false; bcerrors = ae_false; lcerrors = ae_false; nlcerrors = ae_false; othererrors = ae_false; /* * Basic tests */ testminnsunit_basictest0nlc(&nlcerrors, _state); testminnsunit_basictest0uc(&ucerrors, _state); testminnsunit_basictest1uc(&ucerrors, _state); testminnsunit_basictest0bc(&bcerrors, _state); testminnsunit_basictest1bc(&bcerrors, _state); testminnsunit_basictest0lc(&lcerrors, _state); testminnsunit_basictest1lc(&lcerrors, _state); /* * Special tests */ testminnsunit_testother(&othererrors, _state); /* * Full scale tests */ testminnsunit_testuc(&ucerrors, &othererrors, _state); testminnsunit_testbc(&bcerrors, &othererrors, _state); testminnsunit_testlc(&lcerrors, &othererrors, _state); testminnsunit_testnlc(&nlcerrors, &othererrors, _state); /* * end */ wereerrors = (((ucerrors||bcerrors)||lcerrors)||nlcerrors)||othererrors; if( !silent ) { printf("TESTING MINNS OPTIMIZATION\n"); printf("TESTS:\n"); printf("* UNCONSTRAINED "); if( ucerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BOUND CONSTRAINED "); if( bcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* LINEARLY CONSTRAINED "); if( lcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* NONLINEARLY CONSTRAINED "); if( nlcerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* OTHER PROPERTIES "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( wereerrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !wereerrors; return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testminns(ae_bool silent, ae_state *_state) { return testminns(silent, _state); } /************************************************************************* Basic unconstrained test *************************************************************************/ static void testminnsunit_basictest0uc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_vector x0; ae_vector x1; ae_vector d; minnsstate s; minnsreport rep; double sumits; double sumnfev; ae_int_t pass; ae_int_t passcount; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); n = 5; passcount = 10; sumits = (double)(0); sumnfev = (double)(0); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&d, n, _state); for(pass=1; pass<=10; pass++) { for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); } minnscreate(n, &x0, &s, _state); minnssetalgoags(&s, 0.1, 0.0, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { s.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { s.fi.ptr.p_double[0] = s.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(s.x.ptr.p_double[i], _state); s.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(s.x.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i], _state),0.001), _state); } sumits = sumits+(double)rep.iterationscount/(double)passcount; sumnfev = sumnfev+(double)rep.nfev/(double)passcount; } ae_frame_leave(_state); } /************************************************************************* Basic unconstrained test: nonsmooth Rosenbrock posed as unconstrained problem. [ ] minimize [ 10*|x0^2-x1| + (1-x0)^2 + 100*max(sqrt(2)*x0-1,0) + 100*max(2*x1-1,0) ] [ ] It's exact solution is x0=1/sqrt(2), x1=1/2 *************************************************************************/ static void testminnsunit_basictest1uc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; double v0; double v1; ae_vector x0; ae_vector x1; minnsstate s; minnsreport rep; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); n = 2; ae_vector_set_length(&x0, n, _state); x0.ptr.p_double[0] = (double)(0); x0.ptr.p_double[1] = (double)(0); minnscreate(n, &x0, &s, _state); minnssetalgoags(&s, 0.1, 0.0, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { v0 = s.x.ptr.p_double[0]; v1 = s.x.ptr.p_double[1]; s.fi.ptr.p_double[0] = 10*ae_fabs(ae_sqr(v0, _state)-v1, _state)+ae_sqr(v0-1, _state); s.j.ptr.pp_double[0][0] = 10*ae_sign(ae_sqr(v0, _state)-v1, _state)*2*v0+2*(v0-1); s.j.ptr.pp_double[0][1] = (double)(10*ae_sign(ae_sqr(v0, _state)-v1, _state)*(-1)); if( ae_fp_greater(ae_sqrt((double)(2), _state)*v0-1,0.0) ) { s.fi.ptr.p_double[0] = s.fi.ptr.p_double[0]+100*(ae_sqrt((double)(2), _state)*v0-1); s.j.ptr.pp_double[0][0] = s.j.ptr.pp_double[0][0]+100*ae_sqrt((double)(2), _state); } if( ae_fp_greater(2*v1-1,0.0) ) { s.fi.ptr.p_double[0] = s.fi.ptr.p_double[0]+100*(2*v1-1); s.j.ptr.pp_double[0][1] = s.j.ptr.pp_double[0][1]+100*2; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[0], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-1/ae_sqrt((double)(2), _state), _state),0.001), _state); seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[1], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-(double)1/(double)2, _state),0.001), _state); ae_frame_leave(_state); } /************************************************************************* Basic box constrained test *************************************************************************/ static void testminnsunit_basictest0bc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_vector x0; ae_vector x1; ae_vector d; ae_vector bl; ae_vector bu; minnsstate s; minnsreport rep; double sumits; double sumnfev; ae_int_t pass; ae_int_t passcount; double v0; double v1; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&bl, 0, DT_REAL, _state); ae_vector_init(&bu, 0, DT_REAL, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); n = 5; passcount = 10; sumits = (double)(0); sumnfev = (double)(0); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bl, n, _state); ae_vector_set_length(&bu, n, _state); ae_vector_set_length(&d, n, _state); for(pass=1; pass<=10; pass++) { for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; bl.ptr.p_double[i] = ae_minreal(v0, v1, _state); bu.ptr.p_double[i] = ae_maxreal(v0, v1, _state); } minnscreate(n, &x0, &s, _state); minnssetalgoags(&s, 0.1, 0.0, _state); minnssetbc(&s, &bl, &bu, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { s.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { s.fi.ptr.p_double[0] = s.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(s.x.ptr.p_double[i], _state); s.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(s.x.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-boundval(0.0, bl.ptr.p_double[i], bu.ptr.p_double[i], _state), _state),0.001), _state); } sumits = sumits+(double)rep.iterationscount/(double)passcount; sumnfev = sumnfev+(double)rep.nfev/(double)passcount; } ae_frame_leave(_state); } /************************************************************************* Basic constrained test: nonsmooth Rosenbrock posed as box constrained problem. [ ] minimize [ 10*|x0^2-x1| + (1-x0)^2 ] [ ] s.t. x0<=1/sqrt(2), x1<=0.5 It's exact solution is x0=1/sqrt(2), x1=1/2 *************************************************************************/ static void testminnsunit_basictest1bc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; double v0; double v1; ae_vector x0; ae_vector x1; ae_vector bndl; ae_vector bndu; minnsstate s; minnsreport rep; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); n = 2; ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); x0.ptr.p_double[0] = (double)(0); x0.ptr.p_double[1] = (double)(0); bndl.ptr.p_double[0] = _state->v_neginf; bndl.ptr.p_double[1] = _state->v_neginf; bndu.ptr.p_double[0] = 1/ae_sqrt((double)(2), _state); bndu.ptr.p_double[1] = (double)1/(double)2; minnscreate(n, &x0, &s, _state); minnssetbc(&s, &bndl, &bndu, _state); minnssetalgoags(&s, 0.1, 0.0, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { v0 = s.x.ptr.p_double[0]; v1 = s.x.ptr.p_double[1]; s.fi.ptr.p_double[0] = 10*ae_fabs(ae_sqr(v0, _state)-v1, _state)+ae_sqr(v0-1, _state); s.j.ptr.pp_double[0][0] = 10*ae_sign(ae_sqr(v0, _state)-v1, _state)*2*v0+2*(v0-1); s.j.ptr.pp_double[0][1] = (double)(10*ae_sign(ae_sqr(v0, _state)-v1, _state)*(-1)); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[0], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-1/ae_sqrt((double)(2), _state), _state),0.001), _state); seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[1], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-(double)1/(double)2, _state),0.001), _state); ae_frame_leave(_state); } /************************************************************************* Basic linearly constrained test *************************************************************************/ static void testminnsunit_basictest0lc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_vector x0; ae_vector x1; ae_matrix c; ae_vector ct; double d; minnsstate s; minnsreport rep; double sumits; double sumnfev; ae_int_t pass; ae_int_t passcount; ae_int_t nc; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); d = -10.0; n = 5; passcount = 10; sumits = (double)(0); sumnfev = (double)(0); ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(pass=1; pass<=10; pass++) { nc = 0; for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; if( ae_fp_less(ae_randomreal(_state),0.5) ) { for(j=0; j<=n; j++) { c.ptr.pp_double[nc][j] = 0.0; } c.ptr.pp_double[nc][i] = 1.0+ae_randomreal(_state); ct.ptr.p_int[nc] = 0; inc(&nc, _state); } else { for(j=0; j<=n; j++) { c.ptr.pp_double[nc+0][j] = 0.0; c.ptr.pp_double[nc+1][j] = 0.0; } c.ptr.pp_double[nc+0][i] = 1.0+ae_randomreal(_state); c.ptr.pp_double[nc+1][i] = 1.0+ae_randomreal(_state); ct.ptr.p_int[nc+0] = 1; ct.ptr.p_int[nc+1] = -1; nc = nc+2; } } minnscreate(n, &x0, &s, _state); minnssetalgoags(&s, 0.1, 0.0, _state); minnssetlc(&s, &c, &ct, nc, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { s.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { s.fi.ptr.p_double[0] = d*ae_sqr(s.x.ptr.p_double[i], _state); s.j.ptr.pp_double[0][i] = d*2*s.x.ptr.p_double[i]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i], _state),0.001), _state); } sumits = sumits+(double)rep.iterationscount/(double)passcount; sumnfev = sumnfev+(double)rep.nfev/(double)passcount; } ae_frame_leave(_state); } /************************************************************************* Basic constrained test: nonsmooth Rosenbrock posed as linearly constrained problem. [ ] minimize [ 10*|x0^2-x1| + (1-x0)^2 ] [ ] s.t. x0<=1/sqrt(2), x1<=0.5 It's exact solution is x0=1/sqrt(2), x1=1/2 *************************************************************************/ static void testminnsunit_basictest1lc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; double v0; double v1; ae_vector x0; ae_vector x1; ae_matrix c; ae_vector ct; minnsstate s; minnsreport rep; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); n = 2; ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, 2, n+1, _state); ae_vector_set_length(&ct, 2, _state); x0.ptr.p_double[0] = (double)(0); x0.ptr.p_double[1] = (double)(0); c.ptr.pp_double[0][0] = 1.0; c.ptr.pp_double[0][1] = 0.0; c.ptr.pp_double[0][2] = 1/ae_sqrt((double)(2), _state); c.ptr.pp_double[1][0] = 0.0; c.ptr.pp_double[1][1] = 1.0; c.ptr.pp_double[1][2] = (double)1/(double)2; ct.ptr.p_int[0] = -1; ct.ptr.p_int[1] = -1; minnscreate(n, &x0, &s, _state); minnssetlc(&s, &c, &ct, 2, _state); minnssetalgoags(&s, 0.1, 0.0, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { v0 = s.x.ptr.p_double[0]; v1 = s.x.ptr.p_double[1]; s.fi.ptr.p_double[0] = 10*ae_fabs(ae_sqr(v0, _state)-v1, _state)+ae_sqr(v0-1, _state); s.j.ptr.pp_double[0][0] = 10*ae_sign(ae_sqr(v0, _state)-v1, _state)*2*v0+2*(v0-1); s.j.ptr.pp_double[0][1] = (double)(10*ae_sign(ae_sqr(v0, _state)-v1, _state)*(-1)); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[0], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[0]-1/ae_sqrt((double)(2), _state), _state),0.001), _state); seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[1], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[1]-(double)1/(double)2, _state),0.001), _state); ae_frame_leave(_state); } /************************************************************************* Basic nonlinearly constrained test *************************************************************************/ static void testminnsunit_basictest0nlc(ae_bool* errors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_vector x0; ae_vector x1; ae_matrix ec; ae_matrix ic; ae_int_t nec; ae_int_t nic; double d; minnsstate s; minnsreport rep; double sumits; double sumnfev; ae_int_t pass; ae_int_t passcount; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_matrix_init(&ec, 0, 0, DT_REAL, _state); ae_matrix_init(&ic, 0, 0, DT_REAL, _state); _minnsstate_init(&s, _state); _minnsreport_init(&rep, _state); d = -10.0; n = 5; passcount = 10; sumits = (double)(0); sumnfev = (double)(0); ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&ec, 2*n, n+1, _state); ae_matrix_set_length(&ic, 2*n, n+1, _state); for(pass=1; pass<=10; pass++) { nec = 0; nic = 0; for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; if( ae_fp_less(ae_randomreal(_state),0.5) ) { for(j=0; j<=n; j++) { ec.ptr.pp_double[nec][j] = 0.0; } ec.ptr.pp_double[nec][i] = 1.0+ae_randomreal(_state); inc(&nec, _state); } else { for(j=0; j<=n; j++) { ic.ptr.pp_double[nic+0][j] = 0.0; ic.ptr.pp_double[nic+1][j] = 0.0; } ic.ptr.pp_double[nic+0][i] = 1.0+ae_randomreal(_state); ic.ptr.pp_double[nic+1][i] = -1.0-ae_randomreal(_state); nic = nic+2; } } minnscreate(n, &x0, &s, _state); minnssetalgoags(&s, 0.1, 100.0, _state); minnssetnlc(&s, nec, nic, _state); while(minnsiteration(&s, _state)) { if( s.needfij ) { s.fi.ptr.p_double[0] = 0.0; for(j=0; j<=n-1; j++) { s.fi.ptr.p_double[0] = d*ae_sqr(s.x.ptr.p_double[j], _state); s.j.ptr.pp_double[0][j] = d*2*s.x.ptr.p_double[j]; } for(i=0; i<=nec-1; i++) { s.fi.ptr.p_double[1+i] = -ec.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { s.fi.ptr.p_double[1+i] = s.fi.ptr.p_double[1+i]+s.x.ptr.p_double[j]*ec.ptr.pp_double[i][j]; s.j.ptr.pp_double[1+i][j] = ec.ptr.pp_double[i][j]; } } for(i=0; i<=nic-1; i++) { s.fi.ptr.p_double[1+nec+i] = -ic.ptr.pp_double[i][n]; for(j=0; j<=n-1; j++) { s.fi.ptr.p_double[1+nec+i] = s.fi.ptr.p_double[1+nec+i]+s.x.ptr.p_double[j]*ic.ptr.pp_double[i][j]; s.j.ptr.pp_double[1+nec+i][j] = ic.ptr.pp_double[i][j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&s, &x1, &rep, _state); seterrorflag(errors, rep.terminationtype<=0, _state); if( *errors ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(errors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i], _state),0.001), _state); } sumits = sumits+(double)rep.iterationscount/(double)passcount; sumnfev = sumnfev+(double)rep.nfev/(double)passcount; } ae_frame_leave(_state); } /************************************************************************* Unconstrained test *************************************************************************/ static void testminnsunit_testuc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_vector x0; ae_vector x0s; ae_vector x1; ae_vector x1s; ae_vector d; ae_vector xc; ae_vector s; ae_vector xrfirst; ae_vector xrlast; minnsstate state; minnsreport rep; double v; ae_int_t pass; ae_int_t passcount; ae_bool requirexrep; double epsrad; ae_bool werexreports; double repferr; double xtol; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x0s, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x1s, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&xrfirst, 0, DT_REAL, _state); ae_vector_init(&xrlast, 0, DT_REAL, _state); _minnsstate_init(&state, _state); _minnsreport_init(&rep, _state); passcount = 10; for(pass=1; pass<=10; pass++) { for(n=1; n<=5; n++) { /* * First test: * * test that problem is successfully solved * * test that X-reports are performed correctly - present * when requested, return first and last points correctly, * not present by default, function value is reported * correctly. * * we use non-unit scale, randomly chosen one, which results * in badly conditioned problems (to check robustness) */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrfirst, n, _state); ae_vector_set_length(&xrlast, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); } requirexrep = ae_fp_greater(ae_randomreal(_state),0.5); epsrad = 0.01*ae_pow((double)(10), -2*ae_randomreal(_state), _state); xtol = 15.0*epsrad; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetscale(&state, &s, _state); if( requirexrep ) { minnssetxrep(&state, ae_true, _state); } werexreports = ae_false; repferr = 0.0; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } if( state.xupdated ) { if( !werexreports ) { ae_v_move(&xrfirst.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } ae_v_move(&xrlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); werexreports = ae_true; v = 0.0; for(i=0; i<=n-1; i++) { v = v+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } repferr = ae_maxreal(repferr, ae_fabs(v-state.f, _state), _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(othererrors, werexreports&&!requirexrep, _state); seterrorflag(othererrors, requirexrep&&!werexreports, _state); seterrorflag(othererrors, ae_fp_greater(repferr,10000*ae_machineepsilon), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-xc.ptr.p_double[i], _state)/s.ptr.p_double[i],xtol), _state); if( requirexrep ) { seterrorflag(othererrors, !ae_isfinite(xrfirst.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x0.ptr.p_double[i]-xrfirst.ptr.p_double[i], _state),100*ae_machineepsilon), _state); seterrorflag(othererrors, !ae_isfinite(xrlast.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-xrlast.ptr.p_double[i], _state),100*ae_machineepsilon), _state); } } /* * Test numerical differentiation: * * test that problem is successfully solved * * test that correct function value is reported */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrlast, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); } epsrad = 0.01*ae_pow((double)(10), -2*ae_randomreal(_state), _state); xtol = 15.0*epsrad; minnscreatef(n, &x0, epsrad/100, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetscale(&state, &s, _state); minnssetxrep(&state, ae_true, _state); repferr = 0.0; while(minnsiteration(&state, _state)) { if( state.needfi ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } if( state.xupdated ) { v = 0.0; for(i=0; i<=n-1; i++) { v = v+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } repferr = ae_maxreal(repferr, ae_fabs(v-state.f, _state), _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(othererrors, ae_fp_greater(repferr,10000*ae_machineepsilon), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-xc.ptr.p_double[i], _state)/s.ptr.p_double[i],xtol), _state); } /* * Test scaling: we perform several steps on unit-scale problem, * then we perform same amount of steps on re-scaled problem, * starting from same point (but scaled according to chosen scale). * * Correctly written optimizer should perform essentially same steps * (up to scale) on both problems. At least, it holds within first * several steps, before rounding errors start to accumulate. * * NOTE: we also check that correctly scaled points are reported. * And, as side effect, we check MinNSRestartFrom(). * * NOTE: we use moderate scale and diagonal coefficients in order * to have well-conditioned system. We test correctness of * formulae here, not robustness of algorithm. */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&x0s, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrlast, n, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); d.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x0s.ptr.p_double[i] = x0.ptr.p_double[i]*s.ptr.p_double[i]; } minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, 0.0, testminnsunit_scalingtestcnt, _state); minnssetxrep(&state, ae_false, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } minnssetscale(&state, &s, _state); minnssetxrep(&state, ae_true, _state); minnsrestartfrom(&state, &x0s, _state); werexreports = ae_false; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state)/s.ptr.p_double[i]; } continue; } if( state.xupdated ) { ae_v_move(&xrlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); werexreports = ae_true; continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1s, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, (!ae_isfinite(x1.ptr.p_double[i], _state)||!ae_isfinite(x1s.ptr.p_double[i], _state))||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-x1s.ptr.p_double[i]/s.ptr.p_double[i], _state),1.0E-4), _state); seterrorflag(othererrors, !ae_isfinite(xrlast.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1s.ptr.p_double[i]-xrlast.ptr.p_double[i], _state),testminnsunit_scalingtesttol), _state); } } } ae_frame_leave(_state); } /************************************************************************* Box constrained test *************************************************************************/ static void testminnsunit_testbc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_vector x0; ae_vector x0s; ae_vector x1; ae_vector x1s; ae_vector b; ae_vector d; ae_vector xc; ae_vector s; ae_vector bndl; ae_vector bndu; ae_vector scaledbndl; ae_vector scaledbndu; ae_vector xrfirst; ae_vector xrlast; ae_matrix a; minnsstate state; minnsreport rep; double v; double v0; double v1; ae_int_t pass; ae_int_t passcount; ae_bool requirexrep; double epsrad; ae_bool werexreports; double repferr; double xtol; ae_int_t maxn; double conda; double gnorm; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x0s, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x1s, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&scaledbndl, 0, DT_REAL, _state); ae_vector_init(&scaledbndu, 0, DT_REAL, _state); ae_vector_init(&xrfirst, 0, DT_REAL, _state); ae_vector_init(&xrlast, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); _minnsstate_init(&state, _state); _minnsreport_init(&rep, _state); passcount = 10; maxn = 5; /* * First test: * * sparse function * * test that problem is successfully solved * * non-unit scale is used, which results in badly conditioned problem * * check that all iterates are feasible (box-constrained) */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrfirst, n, _state); ae_vector_set_length(&xrlast, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; k = ae_randominteger(5, _state); if( k==1 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==2 ) { bndu.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==3 ) { v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = ae_minreal(v0, v1, _state); bndu.ptr.p_double[i] = ae_maxreal(v0, v1, _state); } if( k==4 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } } requirexrep = ae_fp_greater(ae_randomreal(_state),0.5); epsrad = 0.01*ae_pow((double)(10), -2*ae_randomreal(_state), _state); xtol = 15.0*epsrad; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetbc(&state, &bndl, &bndu, _state); minnssetscale(&state, &s, _state); if( requirexrep ) { minnssetxrep(&state, ae_true, _state); } werexreports = ae_false; repferr = 0.0; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } if( state.xupdated ) { if( !werexreports ) { ae_v_move(&xrfirst.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); } ae_v_move(&xrlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); werexreports = ae_true; v = 0.0; for(i=0; i<=n-1; i++) { v = v+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } repferr = ae_maxreal(repferr, ae_fabs(v-state.f, _state), _state); for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, ae_fp_less(state.x.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(primaryerrors, ae_fp_greater(state.x.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(othererrors, werexreports&&!requirexrep, _state); seterrorflag(othererrors, requirexrep&&!werexreports, _state); seterrorflag(othererrors, ae_fp_greater(repferr,10000*ae_machineepsilon), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-boundval(xc.ptr.p_double[i], bndl.ptr.p_double[i], bndu.ptr.p_double[i], _state), _state)/s.ptr.p_double[i],xtol), _state); seterrorflag(primaryerrors, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(primaryerrors, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); if( requirexrep ) { seterrorflag(othererrors, !ae_isfinite(xrfirst.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(boundval(x0.ptr.p_double[i], bndl.ptr.p_double[i], bndu.ptr.p_double[i], _state)-xrfirst.ptr.p_double[i], _state),100*ae_machineepsilon), _state); seterrorflag(othererrors, !ae_isfinite(xrlast.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-xrlast.ptr.p_double[i], _state),100*ae_machineepsilon), _state); } } } } /* * A bit harder test: * * dense quadratic function (smooth), may be prone to different * rounding-related issues * * non-negativity box constraints * * unit scale is used * * extreme stopping criteria (EpsX=1.0E-12) * * single pass for each problem size * * check that constrained gradient at solution is small */ conda = 1.0E3; epsrad = 1.0E-12; for(n=1; n<=10; n++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 1.0; b.ptr.p_double[i] = ae_randomreal(_state)-0.5; bndl.ptr.p_double[i] = 0.0; bndu.ptr.p_double[i] = _state->v_posinf; } spdmatrixrndcond(n, conda, &a, _state); minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetbc(&state, &bndl, &bndu, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.j.ptr.pp_double[0][i] = 0.0; } for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+b.ptr.p_double[i]*state.x.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+0.5*state.x.ptr.p_double[i]*a.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } for(i=0; i<=n-1; i++) { state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[0][i] = state.j.ptr.pp_double[0][i]+a.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } gnorm = 0.0; for(i=0; i<=n-1; i++) { v = b.ptr.p_double[i]; for(j=0; j<=n-1; j++) { v = v+a.ptr.pp_double[i][j]*x1.ptr.p_double[j]; } if( ae_fp_eq(x1.ptr.p_double[i],bndl.ptr.p_double[i])&&ae_fp_greater(v,(double)(0)) ) { v = (double)(0); } if( ae_fp_eq(x1.ptr.p_double[i],bndu.ptr.p_double[i])&&ae_fp_less(v,(double)(0)) ) { v = (double)(0); } gnorm = gnorm+ae_sqr(v, _state); seterrorflag(primaryerrors, ae_fp_less(x1.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(primaryerrors, ae_fp_greater(x1.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } gnorm = ae_sqrt(gnorm, _state); seterrorflag(primaryerrors, ae_fp_greater(gnorm,1.0E-5), _state); } /* * Test on HIGHLY nonconvex bound constrained problem. * Algorithm should be able to stop. * * NOTE: because algorithm can be attracted to saddle points, * x[i] may be -1, +1 or approximately zero. */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = ae_randomreal(_state)-0.5; bndl.ptr.p_double[i] = -1.0; bndu.ptr.p_double[i] = 1.0; } epsrad = 0.0001; xtol = 15.0*epsrad; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetbc(&state, &bndl, &bndu, _state); v = -1000.0; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { v0 = ae_fabs(state.x.ptr.p_double[i], _state); v1 = (double)(ae_sign(state.x.ptr.p_double[i], _state)); state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+v*(v0+v0*v0); state.j.ptr.pp_double[0][i] = v*(v1+2*v0*v1); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); for(i=0; i<=n-1; i++) { v = ae_fabs(x1.ptr.p_double[i], _state); seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state), _state); seterrorflag(primaryerrors, ae_fp_neq(v,1.0)&&ae_fp_greater(v,xtol), _state); } } } /* * Test numerical differentiation: * * test that problem is successfully solved * * test that correct function value is reported * * test that all iterates are within bound-constrained area */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrlast, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); s.ptr.p_double[i] = ae_pow((double)(10), 2*(2*ae_randomreal(_state)-1), _state); bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; k = ae_randominteger(5, _state); if( k==1 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==2 ) { bndu.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==3 ) { v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = ae_minreal(v0, v1, _state); bndu.ptr.p_double[i] = ae_maxreal(v0, v1, _state); } if( k==4 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } } epsrad = 0.01*ae_pow((double)(10), -2*ae_randomreal(_state), _state); xtol = 15.0*epsrad; minnscreatef(n, &x0, epsrad/100, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetscale(&state, &s, _state); minnssetbc(&state, &bndl, &bndu, _state); minnssetxrep(&state, ae_true, _state); repferr = 0.0; while(minnsiteration(&state, _state)) { if( state.needfi ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); seterrorflag(primaryerrors, ae_fp_less(state.x.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(primaryerrors, ae_fp_greater(state.x.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } continue; } if( state.xupdated ) { v = 0.0; for(i=0; i<=n-1; i++) { v = v+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); seterrorflag(primaryerrors, ae_fp_less(state.x.ptr.p_double[i],bndl.ptr.p_double[i]), _state); seterrorflag(primaryerrors, ae_fp_greater(state.x.ptr.p_double[i],bndu.ptr.p_double[i]), _state); } repferr = ae_maxreal(repferr, ae_fabs(v-state.f, _state), _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(othererrors, ae_fp_greater(repferr,10000*ae_machineepsilon), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state)||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-boundval(xc.ptr.p_double[i], bndl.ptr.p_double[i], bndu.ptr.p_double[i], _state), _state)/s.ptr.p_double[i],xtol), _state); } } } /* * Test scaling: we perform several steps on unit-scale problem, * then we perform same amount of steps on re-scaled problem, * starting from same point (but scaled according to chosen scale). * * Correctly written optimizer should perform essentially same steps * (up to scale) on both problems. At least, it holds within first * several steps, before rounding errors start to accumulate. * * NOTE: we also check that correctly scaled points are reported. * And, as side effect, we check MinNSRestartFrom(). * * NOTE: we use very low scale and diagonal coefficients in order * to have well-conditioned system. We test correctness of * formulae here, not robustness of algorithm. */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&x0s, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrlast, n, _state); ae_vector_set_length(&bndl, n, _state); ae_vector_set_length(&bndu, n, _state); ae_vector_set_length(&scaledbndl, n, _state); ae_vector_set_length(&scaledbndu, n, _state); for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = ae_pow((double)(10), ae_randomreal(_state)-0.5, _state); d.ptr.p_double[i] = ae_pow((double)(10), ae_randomreal(_state)-0.5, _state); x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x0s.ptr.p_double[i] = x0.ptr.p_double[i]*s.ptr.p_double[i]; bndl.ptr.p_double[i] = _state->v_neginf; bndu.ptr.p_double[i] = _state->v_posinf; k = ae_randominteger(5, _state); if( k==1 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==2 ) { bndu.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } if( k==3 ) { v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; bndl.ptr.p_double[i] = ae_minreal(v0, v1, _state); bndu.ptr.p_double[i] = ae_maxreal(v0, v1, _state); } if( k==4 ) { bndl.ptr.p_double[i] = 2*ae_randomreal(_state)-1; bndu.ptr.p_double[i] = bndl.ptr.p_double[i]; } scaledbndl.ptr.p_double[i] = bndl.ptr.p_double[i]*s.ptr.p_double[i]; scaledbndu.ptr.p_double[i] = bndu.ptr.p_double[i]*s.ptr.p_double[i]; } minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.01, 0.0, _state); minnssetcond(&state, 0.0, testminnsunit_scalingtestcnt, _state); minnssetbc(&state, &bndl, &bndu, _state); minnssetxrep(&state, ae_false, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } minnssetscale(&state, &s, _state); minnssetbc(&state, &scaledbndl, &scaledbndu, _state); minnsrestartfrom(&state, &x0s, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state)/s.ptr.p_double[i]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1s, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, (!ae_isfinite(x1.ptr.p_double[i], _state)||!ae_isfinite(x1s.ptr.p_double[i], _state))||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-x1s.ptr.p_double[i]/s.ptr.p_double[i], _state),testminnsunit_scalingtesttol), _state); } } } ae_frame_leave(_state); } /************************************************************************* Linearly constrained test *************************************************************************/ static void testminnsunit_testlc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t nc; ae_vector x0; ae_vector x0s; ae_vector x1; ae_vector x2; ae_vector x1s; ae_vector d; ae_vector xc; ae_vector s; ae_vector bndl; ae_vector bndu; ae_matrix c; ae_matrix scaledc; ae_vector ct; ae_vector scaledbndl; ae_vector scaledbndu; ae_vector xrfirst; ae_vector xrlast; minnsstate state; minnsreport rep; double v; double v0; double v1; double vv; double flast0; double flast1; ae_int_t pass; ae_int_t passcount; double epsrad; double repferr; double xtol; double ftol; double rho; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x0s, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&x1s, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&scaledc, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&scaledbndl, 0, DT_REAL, _state); ae_vector_init(&scaledbndu, 0, DT_REAL, _state); ae_vector_init(&xrfirst, 0, DT_REAL, _state); ae_vector_init(&xrlast, 0, DT_REAL, _state); _minnsstate_init(&state, _state); _minnsreport_init(&rep, _state); passcount = 10; for(pass=1; pass<=10; pass++) { for(n=1; n<=5; n++) { /* * First test: * * smooth problem * * subject to random linear constraints * * with non-unit scale * * We: * * compare function value at constrained solution with function * value for penalized unconstrained problem. We do not compare * actual X-values returned, because they are highly unstable - * function values at minimum show better stability. * * check that correct function values are reported */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 10*(2*ae_randomreal(_state)-1); xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = 1+ae_randomreal(_state); s.ptr.p_double[i] = 1+ae_randomreal(_state); } nc = ae_randominteger((n+1)/2, _state); if( nc>0 ) { ae_matrix_set_length(&c, nc, n+1, _state); ae_vector_set_length(&ct, nc, _state); for(i=0; i<=nc-1; i++) { ct.ptr.p_int[i] = ae_randominteger(3, _state)-1; for(j=0; j<=n; j++) { c.ptr.pp_double[i][j] = ae_randomreal(_state)-0.5; } } } epsrad = 0.00001; ftol = 0.01; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetscale(&state, &s, _state); minnssetxrep(&state, ae_true, _state); minnssetlc(&state, &c, &ct, nc, _state); repferr = 0.0; flast0 = _state->v_nan; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_sqr(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*(2*(state.x.ptr.p_double[i]-xc.ptr.p_double[i])); } continue; } if( state.xupdated ) { flast0 = 0.0; for(i=0; i<=n-1; i++) { flast0 = flast0+d.ptr.p_double[i]*ae_sqr(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } repferr = ae_maxreal(repferr, ae_fabs(flast0-state.f, _state), _state); continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(primaryerrors, !ae_isfinite(flast0, _state), _state); seterrorflag(othererrors, ae_fp_greater(repferr,10000*ae_machineepsilon), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } minnssetlc(&state, &c, &ct, 0, _state); minnsrestartfrom(&state, &x0, _state); rho = 1000.0; repferr = 0.0; flast1 = _state->v_nan; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_sqr(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*(2*(state.x.ptr.p_double[i]-xc.ptr.p_double[i])); } for(i=0; i<=nc-1; i++) { v = ae_v_dotproduct(&state.x.ptr.p_double[0], 1, &c.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); v = v-c.ptr.pp_double[i][n]; vv = 0.0; if( ct.ptr.p_int[i]<0 ) { vv = (double)(ae_sign(ae_maxreal(v, 0.0, _state), _state)); v = ae_maxreal(v, 0.0, _state); } if( ct.ptr.p_int[i]==0 ) { vv = (double)(ae_sign(v, _state)); v = ae_fabs(v, _state); } if( ct.ptr.p_int[i]>0 ) { vv = (double)(-ae_sign(ae_maxreal(-v, 0.0, _state), _state)); v = ae_maxreal(-v, 0.0, _state); } state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+rho*v; for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[0][j] = state.j.ptr.pp_double[0][j]+rho*vv*c.ptr.pp_double[i][j]; } } continue; } if( state.xupdated ) { flast1 = 0.0; for(i=0; i<=n-1; i++) { flast1 = flast1+d.ptr.p_double[i]*ae_sqr(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x2, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); seterrorflag(primaryerrors, !ae_isfinite(flast1, _state), _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } seterrorflag(primaryerrors, ae_fp_greater(ae_fabs(flast0-flast1, _state),ftol), _state); /* * Test on HIGHLY nonconvex linearly constrained problem. * Algorithm should be able to stop at the bounds. */ ae_vector_set_length(&x0, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = ae_randomreal(_state)-0.5; for(j=0; j<=n-1; j++) { c.ptr.pp_double[2*i+0][j] = 0.0; c.ptr.pp_double[2*i+1][j] = 0.0; } c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = -1.0; ct.ptr.p_int[2*i+0] = 1; c.ptr.pp_double[2*i+1][i] = 1.0; c.ptr.pp_double[2*i+1][n] = 1.0; ct.ptr.p_int[2*i+1] = -1; } epsrad = 0.0001; xtol = 15.0*epsrad; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, epsrad, 0, _state); minnssetlc(&state, &c, &ct, 2*n, _state); v = -1000.0; while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { v0 = ae_fabs(state.x.ptr.p_double[i], _state); v1 = (double)(ae_sign(state.x.ptr.p_double[i], _state)); state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+v*(v0+v0*v0); state.j.ptr.pp_double[0][i] = v*(v1+2*v0*v1); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, !ae_isfinite(x1.ptr.p_double[i], _state), _state); seterrorflag(primaryerrors, (ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-1, _state),xtol)&&ae_fp_greater(ae_fabs(x1.ptr.p_double[i], _state),xtol))&&ae_fp_greater(ae_fabs(x1.ptr.p_double[i]+1, _state),xtol), _state); } /* * Test scaling: we perform several steps on unit-scale problem, * then we perform same amount of steps on re-scaled problem, * starting from same point (but scaled according to chosen scale). * * Correctly written optimizer should perform essentially same steps * (up to scale) on both problems. At least, it holds within first * several steps, before rounding errors start to accumulate. * * NOTE: we also check that correctly scaled points are reported. * And, as side effect, we check MinNSRestartFrom(). * * NOTE: we use moderate scale and diagonal coefficients in order * to have well-conditioned system. We test correctness of * formulae here, not robustness of algorithm. */ ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&x0s, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&s, n, _state); ae_vector_set_length(&xrlast, n, _state); ae_matrix_set_length(&c, 2*n, n+1, _state); ae_matrix_set_length(&scaledc, 2*n, n+1, _state); ae_vector_set_length(&ct, 2*n, _state); for(i=0; i<=2*n-1; i++) { ct.ptr.p_int[i] = 0; for(j=0; j<=n; j++) { c.ptr.pp_double[i][j] = (double)(0); } } for(i=0; i<=n-1; i++) { s.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); d.ptr.p_double[i] = ae_pow((double)(10), 2*ae_randomreal(_state)-1, _state); x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; x0s.ptr.p_double[i] = x0.ptr.p_double[i]*s.ptr.p_double[i]; k = ae_randominteger(5, _state); if( k==1 ) { c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = 2*ae_randomreal(_state)-1; ct.ptr.p_int[2*i+0] = 1; } if( k==2 ) { c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = 2*ae_randomreal(_state)-1; ct.ptr.p_int[2*i+0] = -1; } if( k==3 ) { v0 = 2*ae_randomreal(_state)-1; v1 = 2*ae_randomreal(_state)-1; c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = ae_minreal(v0, v1, _state); c.ptr.pp_double[2*i+1][i] = 1.0; c.ptr.pp_double[2*i+1][n] = ae_maxreal(v0, v1, _state); ct.ptr.p_int[2*i+0] = 1; ct.ptr.p_int[2*i+1] = -1; } if( k==4 ) { c.ptr.pp_double[2*i+0][i] = 1.0; c.ptr.pp_double[2*i+0][n] = 2*ae_randomreal(_state)-1; ct.ptr.p_int[2*i+0] = 0; } } for(i=0; i<=2*n-1; i++) { for(j=0; j<=n-1; j++) { scaledc.ptr.pp_double[i][j] = c.ptr.pp_double[i][j]/s.ptr.p_double[j]; } scaledc.ptr.pp_double[i][n] = c.ptr.pp_double[i][n]; } minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, 0.0, _state); minnssetcond(&state, 0.0, testminnsunit_scalingtestcnt, _state); minnssetlc(&state, &c, &ct, 2*n, _state); minnssetxrep(&state, ae_false, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } minnssetscale(&state, &s, _state); minnssetlc(&state, &scaledc, &ct, 2*n, _state); minnsrestartfrom(&state, &x0s, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]/s.ptr.p_double[i]-xc.ptr.p_double[i], _state)/s.ptr.p_double[i]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1s, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { seterrorflag(primaryerrors, (!ae_isfinite(x1.ptr.p_double[i], _state)||!ae_isfinite(x1s.ptr.p_double[i], _state))||ae_fp_greater(ae_fabs(x1.ptr.p_double[i]-x1s.ptr.p_double[i]/s.ptr.p_double[i], _state),testminnsunit_scalingtesttol), _state); } } } ae_frame_leave(_state); } /************************************************************************* Nonlinearly constrained test *************************************************************************/ static void testminnsunit_testnlc(ae_bool* primaryerrors, ae_bool* othererrors, ae_state *_state) { ae_frame _frame_block; ae_int_t n; ae_int_t i; ae_int_t j; ae_int_t nc; ae_int_t nec; ae_vector x0; ae_vector x0s; ae_vector x1; ae_vector x2; ae_vector x1s; ae_vector d; ae_vector xc; ae_vector s; ae_vector bndl; ae_vector bndu; ae_vector b; ae_vector r; ae_matrix c; ae_matrix scaledc; ae_vector ct; ae_vector scaledbndl; ae_vector scaledbndu; ae_vector xrfirst; ae_vector xrlast; minnsstate state; minnsreport rep; double v; ae_int_t pass; ae_int_t passcount; double epsrad; double xtol; double rho; ae_int_t maxn; double diffstep; ae_frame_make(_state, &_frame_block); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x0s, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); ae_vector_init(&x2, 0, DT_REAL, _state); ae_vector_init(&x1s, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xc, 0, DT_REAL, _state); ae_vector_init(&s, 0, DT_REAL, _state); ae_vector_init(&bndl, 0, DT_REAL, _state); ae_vector_init(&bndu, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&r, 0, DT_REAL, _state); ae_matrix_init(&c, 0, 0, DT_REAL, _state); ae_matrix_init(&scaledc, 0, 0, DT_REAL, _state); ae_vector_init(&ct, 0, DT_INT, _state); ae_vector_init(&scaledbndl, 0, DT_REAL, _state); ae_vector_init(&scaledbndu, 0, DT_REAL, _state); ae_vector_init(&xrfirst, 0, DT_REAL, _state); ae_vector_init(&xrlast, 0, DT_REAL, _state); _minnsstate_init(&state, _state); _minnsreport_init(&rep, _state); passcount = 10; maxn = 5; rho = 100.0; /* * First test: * * simple problem * * subject to random nonlinear constraints of form r[i]*x[i] OPERATION 0.0, * where OPERATION is <= or = * * with non-unit scale * * We: * * compare numerical solution with analytic one, which can be * easily calculated */ for(pass=1; pass<=passcount; pass++) { for(n=1; n<=maxn; n++) { for(nc=1; nc<=n; nc++) { for(nec=0; nec<=nc; nec++) { ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xc, n, _state); ae_vector_set_length(&d, n, _state); ae_vector_set_length(&r, n, _state); ae_vector_set_length(&s, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; xc.ptr.p_double[i] = 2*ae_randomreal(_state)-1; d.ptr.p_double[i] = ae_pow((double)(10), ae_randomreal(_state)-0.5, _state); s.ptr.p_double[i] = ae_pow((double)(10), ae_randomreal(_state)-0.5, _state); r.ptr.p_double[i] = (2*ae_randominteger(2, _state)-1)*(0.1+ae_randomreal(_state)); } epsrad = 0.001; xtol = 0.01; minnscreate(n, &x0, &state, _state); minnssetalgoags(&state, 0.1, rho, _state); minnssetcond(&state, epsrad, 0, _state); minnssetscale(&state, &s, _state); minnssetnlc(&state, nec, nc-nec, _state); while(minnsiteration(&state, _state)) { if( state.needfij ) { state.fi.ptr.p_double[0] = 0.0; for(i=0; i<=n-1; i++) { state.fi.ptr.p_double[0] = state.fi.ptr.p_double[0]+d.ptr.p_double[i]*ae_fabs(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); state.j.ptr.pp_double[0][i] = d.ptr.p_double[i]*ae_sign(state.x.ptr.p_double[i]-xc.ptr.p_double[i], _state); } for(i=1; i<=nc; i++) { state.fi.ptr.p_double[i] = state.x.ptr.p_double[i-1]*r.ptr.p_double[i-1]; for(j=0; j<=n-1; j++) { state.j.ptr.pp_double[i][j] = 0.0; } state.j.ptr.pp_double[i][i-1] = r.ptr.p_double[i-1]; } continue; } ae_assert(ae_false, "Assertion failed", _state); } minnsresults(&state, &x1, &rep, _state); seterrorflag(primaryerrors, rep.terminationtype<=0, _state); if( *primaryerrors||(*othererrors) ) { ae_frame_leave(_state); return; } for(i=0; i<=n-1; i++) { v = xc.ptr.p_double[i]; if( i=nec&&i=nec&&ik; 2. (rk,rm)=0 for any m<>k; 3. (rk,pm)=0 for any m<>k; INPUT: Silent - if true then function output report -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_complextest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate state; lincgreport rep; ae_matrix a; ae_vector b; ae_int_t n; double c; ae_vector x0; ae_vector residual; double normofresidual; double sclr; double na; double nv0; double nv1; ae_int_t sz; double mx; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t l; double tmp; ae_matrix mtx; ae_matrix mtp; ae_matrix mtr; double getrnorm; ae_int_t numofit; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&state, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&residual, 0, DT_REAL, _state); ae_matrix_init(&mtx, 0, 0, DT_REAL, _state); ae_matrix_init(&mtp, 0, 0, DT_REAL, _state); ae_matrix_init(&mtr, 0, 0, DT_REAL, _state); mx = (double)(100); n = 5; for(sz=1; sz<=n; sz++) { /* * Generate: * * random A with norm NA (equal to 1.0), * * random right part B whose elements are uniformly distributed in [-MX,+MX] * * random starting point X0 whose elements are uniformly distributed in [-MX,+MX] */ c = 15+15*ae_randomreal(_state); spdmatrixrndcond(sz, c, &a, _state); na = (double)(1); ae_vector_set_length(&b, sz, _state); for(i=0; i<=sz-1; i++) { b.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } ae_vector_set_length(&x0, sz, _state); for(i=0; i<=sz-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } ae_matrix_set_length(&mtx, sz+1, sz, _state); /* * Start optimization, record its progress for further analysis * NOTE: we set update frequency of R to 2 in order to test that R is updated correctly */ lincgcreate(sz, &state, _state); lincgsetxrep(&state, ae_true, _state); lincgsetb(&state, &b, _state); lincgsetstartingpoint(&state, &x0, _state); lincgsetcond(&state, (double)(0), sz, _state); lincgsetrupdatefreq(&state, 2, _state); numofit = 0; getrnorm = ae_maxrealnumber; while(lincgiteration(&state, _state)) { if( state.needmv ) { for(i=0; i<=sz-1; i++) { state.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=sz-1; j++) { state.mv.ptr.p_double[i] = state.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } } } if( state.needvmv ) { state.vmv = (double)(0); for(i=0; i<=sz-1; i++) { state.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=sz-1; j++) { state.mv.ptr.p_double[i] = state.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*state.x.ptr.p_double[j]; } state.vmv = state.vmv+state.mv.ptr.p_double[i]*state.x.ptr.p_double[i]; } } if( state.needprec ) { for(i=0; i<=sz-1; i++) { state.pv.ptr.p_double[i] = state.x.ptr.p_double[i]; } } if( state.xupdated ) { /* * Save current point to MtX, it will be used later for additional tests */ if( numofit>=mtx.rows ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=sz-1; i++) { mtx.ptr.pp_double[numofit][i] = state.x.ptr.p_double[i]; } getrnorm = state.r2; numofit = numofit+1; } } lincgresults(&state, &x0, &rep, _state); if( ae_fp_neq(getrnorm,rep.r2) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::GetRNorm<>Rep.R2!(%0.2e<>%0.2e)\n", (int)(sz), (double)(c), (double)(getrnorm), (double)(rep.r2)); } result = ae_true; ae_frame_leave(_state); return result; } /* * Calculate residual, check result */ ae_vector_set_length(&residual, sz, _state); for(i=0; i<=sz-1; i++) { tmp = (double)(0); for(j=0; j<=sz-1; j++) { tmp = tmp+a.ptr.pp_double[i][j]*x0.ptr.p_double[j]; } residual.ptr.p_double[i] = b.ptr.p_double[i]-tmp; } normofresidual = (double)(0); for(i=0; i<=sz-1; i++) { if( ae_fp_greater(ae_fabs(residual.ptr.p_double[i], _state),testlincgunit_e0) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::Discripancy[%0d]>E0!(%0.2e>%0.2e)\n", (int)(sz), (double)(c), (int)(i), (double)(residual.ptr.p_double[i]), (double)(testlincgunit_e0)); } result = ae_true; ae_frame_leave(_state); return result; } normofresidual = normofresidual+residual.ptr.p_double[i]*residual.ptr.p_double[i]; } if( ae_fp_greater(ae_fabs(normofresidual-rep.r2, _state),testlincgunit_e0) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::||NormOfResidual-Rep.R2||>E0!(%0.2e>%0.2e)\n", (int)(sz), (double)(c), (double)(ae_fabs(normofresidual-rep.r2, _state)), (double)(testlincgunit_e0)); printf("NormOfResidual=%0.2e; Rep.R2=%0.2e\n", (double)(normofresidual), (double)(rep.r2)); } result = ae_true; ae_frame_leave(_state); return result; } /* * Check algorithm properties (conjugacy/orthogonality). * Here we use MtX which was filled during algorithm progress towards solution. * * NOTE: this test is skipped when algorithm converged in less than SZ iterations. */ if( sz>1&&rep.iterationscount==sz ) { ae_matrix_set_length(&mtp, sz, sz, _state); ae_matrix_set_length(&mtr, sz, sz, _state); for(i=0; i<=sz-1; i++) { for(j=0; j<=sz-1; j++) { mtp.ptr.pp_double[i][j] = mtx.ptr.pp_double[i+1][j]-mtx.ptr.pp_double[i][j]; tmp = (double)(0); for(k=0; k<=sz-1; k++) { tmp = tmp+a.ptr.pp_double[j][k]*mtx.ptr.pp_double[i][k]; } mtr.ptr.pp_double[i][j] = b.ptr.p_double[j]-tmp; } } /* *(Api,pj)=0? */ sclr = (double)(0); nv0 = (double)(0); nv1 = (double)(0); for(i=0; i<=sz-1; i++) { for(j=0; j<=sz-1; j++) { if( i==j ) { continue; } for(k=0; k<=sz-1; k++) { tmp = (double)(0); for(l=0; l<=sz-1; l++) { tmp = tmp+a.ptr.pp_double[k][l]*mtp.ptr.pp_double[i][l]; } sclr = sclr+tmp*mtp.ptr.pp_double[j][k]; nv0 = nv0+mtp.ptr.pp_double[i][k]*mtp.ptr.pp_double[i][k]; nv1 = nv1+mtp.ptr.pp_double[j][k]*mtp.ptr.pp_double[j][k]; } nv0 = ae_sqrt(nv0, _state); nv1 = ae_sqrt(nv1, _state); if( ae_fp_greater(ae_fabs(sclr, _state),testlincgunit_e0*na*nv0*nv1) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::(Ap%0d,p%0d)!=0\n{Sclr=%0.15f; NA=%0.15f NV0=%0.15f NV1=%0.15f;}\n", (int)(sz), (double)(c), (int)(i), (int)(j), (double)(sclr), (double)(na), (double)(nv0), (double)(nv1)); } result = ae_true; ae_frame_leave(_state); return result; } } } /* *(ri,pj)=0? */ for(i=1; i<=sz-1; i++) { for(j=0; j<=i-1; j++) { sclr = (double)(0); nv0 = (double)(0); nv1 = (double)(0); for(k=0; k<=sz-1; k++) { sclr = sclr+mtr.ptr.pp_double[i][k]*mtp.ptr.pp_double[j][k]; nv0 = nv0+mtr.ptr.pp_double[i][k]*mtr.ptr.pp_double[i][k]; nv1 = nv1+mtp.ptr.pp_double[j][k]*mtp.ptr.pp_double[j][k]; } nv0 = ae_sqrt(nv0, _state); nv1 = ae_sqrt(nv1, _state); if( ae_fp_greater(ae_fabs(sclr, _state),testlincgunit_e0*nv0*nv1) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::(r%0d,p%0d)!=0\n{Sclr=%0.15f; NV0=%0.15f NV1=%0.15f;}\n", (int)(sz), (double)(c), (int)(i), (int)(j), (double)(sclr), (double)(nv0), (double)(nv1)); } result = ae_true; ae_frame_leave(_state); return result; } } } /* *(ri,rj)=0? */ for(i=0; i<=sz-1; i++) { for(j=i+1; j<=sz-1; j++) { sclr = (double)(0); nv0 = (double)(0); nv1 = (double)(0); for(k=0; k<=sz-1; k++) { sclr = sclr+mtr.ptr.pp_double[i][k]*mtr.ptr.pp_double[j][k]; nv0 = nv0+mtr.ptr.pp_double[i][k]*mtr.ptr.pp_double[i][k]; nv1 = nv1+mtr.ptr.pp_double[j][k]*mtr.ptr.pp_double[j][k]; } nv0 = ae_sqrt(nv0, _state); nv1 = ae_sqrt(nv1, _state); if( ae_fp_greater(ae_fabs(sclr, _state),testlincgunit_e0*nv0*nv1) ) { if( !silent ) { printf("IterationsCount=%0d;\nNMV=%0d;\nTerminationType=%0d;\n", (int)(rep.iterationscount), (int)(rep.nmv), (int)(rep.terminationtype)); printf("Size=%0d;\nCond=%0.5f;\nComplexTest::Fail::(rm,rk)!=0\n{Sclr=%0.15f; NV0=%0.15f NV1=%0.15f;}\n", (int)(sz), (double)(c), (double)(sclr), (double)(nv0), (double)(nv1)); } result = ae_true; ae_frame_leave(_state); return result; } } } } } if( !silent ) { printf("ComplexTest::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function prepare problem with a known solution 'Xs'(A*Xs-b=0). There b is A*Xs. After, function check algorithm result and 'Xs'. There used two stopping criterions: 1. achieved the required precision(StCrit=0); 2. execution of the required number of iterations(StCrit=1). -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_complexres(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_vector xs; ae_vector x0; double err; ae_int_t n; ae_int_t sz; double c; ae_int_t i; ae_int_t j; ae_int_t stcrit; double mx; double tmp; double eps; ae_int_t xp; ae_int_t nxp; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xs, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); sz = 5; mx = (double)(100); nxp = 100; for(xp=0; xp<=nxp-1; xp++) { for(n=1; n<=sz; n++) { for(stcrit=0; stcrit<=1; stcrit++) { /* * Generate: * * random A with norm NA (equal to 1.0), * * random solution XS whose elements are uniformly distributed in [-MX,+MX] * * random starting point X0 whose elements are uniformly distributed in [-MX,+MX] * * B = A*Xs */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&xs, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); xs.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } eps = (double)(0); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { b.ptr.p_double[i] = b.ptr.p_double[i]+a.ptr.pp_double[i][j]*xs.ptr.p_double[j]; } eps = eps+b.ptr.p_double[i]*b.ptr.p_double[i]; } eps = 1.0E-6*ae_sqrt(eps, _state); /* * Solve with different stopping criteria */ lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetstartingpoint(&s, &x0, _state); lincgsetxrep(&s, ae_true, _state); if( stcrit==0 ) { lincgsetcond(&s, 1.0E-6, 0, _state); } else { lincgsetcond(&s, (double)(0), n, _state); } while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } } lincgresults(&s, &x0, &rep, _state); /* * Check result */ err = 0.0; for(i=0; i<=n-1; i++) { tmp = (double)(0); for(j=0; j<=n-1; j++) { tmp = tmp+a.ptr.pp_double[i][j]*x0.ptr.p_double[j]; } err = err+ae_sqr(b.ptr.p_double[i]-tmp, _state); } err = ae_sqrt(err, _state); if( ae_fp_greater(err,eps) ) { if( !silent ) { printf("ComplexRes::fail\n"); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); printf("X and Xs...\n"); for(j=0; j<=n-1; j++) { printf("x[%0d]=%0.10f; xs[%0d]=%0.10f\n", (int)(j), (double)(x0.ptr.p_double[j]), (int)(j), (double)(xs.ptr.p_double[j])); } } result = ae_true; ae_frame_leave(_state); return result; } } } } /* *test has been passed */ if( !silent ) { printf("ComplexRes::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function check, that XUpdated return State.X=X0 at zero iteration and State.X=X(algorithm result) at last. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_basictestx(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_vector x0; ae_vector x00; ae_vector x01; ae_int_t n; ae_int_t sz; double c; ae_int_t i; ae_int_t j; double mx; ae_int_t iters; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x00, 0, DT_REAL, _state); ae_vector_init(&x01, 0, DT_REAL, _state); sz = 5; mx = (double)(100); for(n=1; n<=sz; n++) { /* * Generate: * * random A with norm NA (equal to 1.0), * * random right part B whose elements are uniformly distributed in [-MX,+MX] * * random starting point X0 whose elements are uniformly distributed in [-MX,+MX] */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&x00, n, _state); ae_vector_set_length(&x01, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); b.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } /* * Solve, save first and last reported points to x00 and x01 */ lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetstartingpoint(&s, &x0, _state); lincgsetxrep(&s, ae_true, _state); lincgsetcond(&s, (double)(0), n, _state); iters = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { if( iters==0 ) { for(i=0; i<=n-1; i++) { x00.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( iters==n ) { for(i=0; i<=n-1; i++) { x01.ptr.p_double[i] = s.x.ptr.p_double[i]; } } iters = iters+1; } } /* * Check first and last points */ for(i=0; i<=n-1; i++) { if( ae_fp_neq(x00.ptr.p_double[i],x0.ptr.p_double[i]) ) { if( !silent ) { printf("BasicTestX::fail\n"); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); for(j=0; j<=n-1; j++) { printf("x0=%0.5f; x00=%0.5f;\n", (double)(x0.ptr.p_double[j]), (double)(x00.ptr.p_double[j])); } } result = ae_true; ae_frame_leave(_state); return result; } } lincgresults(&s, &x0, &rep, _state); for(i=0; i<=n-1; i++) { if( ae_fp_neq(x01.ptr.p_double[i],x0.ptr.p_double[i]) ) { if( !silent ) { printf("BasicTestX::fail\n"); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); for(j=0; j<=n-1; j++) { printf("x0=%0.5f; x01=%0.5f;\n", (double)(x0.ptr.p_double[j]), (double)(x01.ptr.p_double[j])); } } result = ae_true; ae_frame_leave(_state); return result; } } } /* *test has been passed */ if( !silent ) { printf("BasicTestIters::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function checks that XUpdated returns correct State.R2. It creates large badly conditioned problem (N=50), which should be large enough and ill-conditioned enough to cause periodic recalculation of R. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_testrcorrectness(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_int_t n; double c; ae_int_t i; ae_int_t j; double r2; double v; double rtol; ae_int_t maxits; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); rtol = 1.0E6*ae_machineepsilon; n = 50; maxits = n/2; c = (double)(10000); spdmatrixrndcond(n, c, &a, _state); ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetxrep(&s, ae_true, _state); lincgsetcond(&s, (double)(0), maxits, _state); while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { /* * calculate R2, compare with value returned in state.R2 */ r2 = (double)(0); for(i=0; i<=n-1; i++) { v = (double)(0); for(j=0; j<=n-1; j++) { v = v+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } r2 = r2+ae_sqr(v-b.ptr.p_double[i], _state); } if( ae_fp_greater(ae_fabs(r2-s.r2, _state),rtol) ) { result = ae_true; ae_frame_leave(_state); return result; } } } lincgresults(&s, &b, &rep, _state); if( rep.iterationscount!=maxits ) { result = ae_true; ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function check, that number of iterations are't more than MaxIts. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_basictestiters(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_vector x0; ae_int_t n; ae_int_t sz; double c; ae_int_t i; ae_int_t j; double mx; ae_int_t iters; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); sz = 5; mx = (double)(100); for(n=1; n<=sz; n++) { /* * Generate: * * random A with norm NA (equal to 1.0), * * random right part B whose elements are uniformly distributed in [-MX,+MX] * * random starting point X0 whose elements are uniformly distributed in [-MX,+MX] */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); b.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } /* * Solve */ lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetstartingpoint(&s, &x0, _state); lincgsetxrep(&s, ae_true, _state); lincgsetcond(&s, (double)(0), n, _state); iters = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { iters = iters+1; } } lincgresults(&s, &x0, &rep, _state); /* * Check */ if( iters!=rep.iterationscount+1||iters>n+1 ) { if( !silent ) { printf("BasicTestIters::fail\n"); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); printf("Iters=%0d\n", (int)(iters)); } result = ae_true; ae_frame_leave(_state); return result; } /* * Restart problem */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); b.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } lincgsetstartingpoint(&s, &x0, _state); lincgrestart(&s, _state); lincgsetb(&s, &b, _state); iters = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { iters = iters+1; } } lincgresults(&s, &x0, &rep, _state); /* *check */ if( iters!=rep.iterationscount+1||iters>n+1 ) { if( !silent ) { printf("BasicTestIters::fail\n"); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); printf("Iters=%0d\n", (int)(iters)); } result = ae_true; ae_frame_leave(_state); return result; } } /* *test has been passed */ if( !silent ) { printf("BasicTestIters::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* This function check, that programmed method is Krylov subspace methed. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_krylovsubspacetest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_vector x0; ae_matrix ksr; ae_vector r0; ae_vector tarray; ae_matrix mtx; ae_int_t n; ae_int_t sz; double c; ae_int_t i; ae_int_t j; ae_int_t l; ae_int_t m; double mx; double tmp; double normr0; ae_int_t numofit; ae_int_t maxits; ae_int_t k2; double eps; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_matrix_init(&ksr, 0, 0, DT_REAL, _state); ae_vector_init(&r0, 0, DT_REAL, _state); ae_vector_init(&tarray, 0, DT_REAL, _state); ae_matrix_init(&mtx, 0, 0, DT_REAL, _state); eps = 1.0E-6; maxits = 3; sz = 5; mx = (double)(100); for(n=1; n<=sz; n++) { /* * Generate: * * random A with unit norm * * cond(A) in [0.5*MaxCond, 1.0*MaxCond] * * random x0 and b such that |A*x0-b| is large enough for algorithm to make at least one iteration. * * IMPORTANT: it is very important to have cond(A) both (1) not very large and * (2) not very small. Large cond(A) will make our problem ill-conditioned, * thus analytic properties won't hold. Small cond(A), from the other side, * will give us rapid convergence of the algorithm - in fact, too rapid. * Krylov basis will be dominated by numerical noise and test may fail. */ c = testlincgunit_maxcond*(0.5*ae_randomreal(_state)+0.5); spdmatrixrndcond(n, c, &a, _state); ae_matrix_set_length(&mtx, n+1, n, _state); ae_matrix_set_length(&ksr, n, n, _state); ae_vector_set_length(&r0, n, _state); ae_vector_set_length(&tarray, n, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&x0, n, _state); do { for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); b.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } normr0 = (double)(0); for(i=0; i<=n-1; i++) { tmp = (double)(0); for(j=0; j<=n-1; j++) { tmp = tmp+a.ptr.pp_double[i][j]*x0.ptr.p_double[j]; } r0.ptr.p_double[i] = b.ptr.p_double[i]-tmp; normr0 = normr0+r0.ptr.p_double[i]*r0.ptr.p_double[i]; } } while(ae_fp_less_eq(ae_sqrt(normr0, _state),eps)); /* * Fill KSR by {r0, A*r0, A^2*r0, ... } */ for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ksr.ptr.pp_double[i][j] = r0.ptr.p_double[j]; } for(j=0; j<=i-1; j++) { for(l=0; l<=n-1; l++) { tarray.ptr.p_double[l] = (double)(0); for(m=0; m<=n-1; m++) { tarray.ptr.p_double[l] = tarray.ptr.p_double[l]+a.ptr.pp_double[l][m]*ksr.ptr.pp_double[i][m]; } } for(l=0; l<=n-1; l++) { ksr.ptr.pp_double[i][l] = tarray.ptr.p_double[l]; } } } /* * Solve system, record intermediate points for futher analysis. * NOTE: we set update frequency of R to 2 in order to test that R is updated correctly */ lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetstartingpoint(&s, &x0, _state); lincgsetxrep(&s, ae_true, _state); lincgsetcond(&s, (double)(0), n, _state); lincgsetrupdatefreq(&s, 2, _state); numofit = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { for(i=0; i<=n-1; i++) { mtx.ptr.pp_double[numofit][i] = s.x.ptr.p_double[i]; } numofit = numofit+1; } } /* * Check that I-th step S_i=X[I+1]-X[i] belongs to I-th Krylov subspace. * Checks are done for first K2 steps, with K2 small enough to avoid * numerical errors. */ if( n<=maxits ) { k2 = n; } else { k2 = maxits; } for(i=0; i<=k2-1; i++) { for(j=0; j<=n-1; j++) { tarray.ptr.p_double[j] = mtx.ptr.pp_double[i+1][j]-mtx.ptr.pp_double[i][j]; } if( !testlincgunit_frombasis(&tarray, &ksr, n, i+1, testlincgunit_e0, _state) ) { if( !silent ) { printf("KrylovSubspaceTest::FAIL\n"); printf("Size=%0d; Iters=%0d;\n", (int)(n), (int)(i)); } result = ae_true; ae_frame_leave(_state); return result; } } } if( !silent ) { printf("KrylovSubspaceTest::OK\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing LinCgSolveSparse. This function prepare problem with a known solution 'Xs'(A*Xs-b=0). There b is A*Xs. After, function calculate result by LinCGSolveSparse and compares it with 'Xs'. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_sparsetest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_vector b; ae_vector xs; ae_vector x0; ae_vector x1; sparsematrix uppera; sparsematrix lowera; double err; ae_int_t n; ae_int_t sz; double c; ae_int_t i; ae_int_t j; double mx; double eps; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&xs, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&x1, 0, DT_REAL, _state); _sparsematrix_init(&uppera, _state); _sparsematrix_init(&lowera, _state); sz = 5; mx = (double)(100); for(n=1; n<=sz; n++) { /* * Generate: * * random A with unit norm * * random X0 (starting point) and XS (known solution) * Copy dense A to sparse SA */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); ae_vector_set_length(&b, n, _state); ae_vector_set_length(&xs, n, _state); for(i=0; i<=n-1; i++) { xs.ptr.p_double[i] = mx*(2*ae_randomreal(_state)-1); } eps = (double)(0); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { b.ptr.p_double[i] = b.ptr.p_double[i]+a.ptr.pp_double[i][j]*xs.ptr.p_double[j]; } eps = eps+b.ptr.p_double[i]*b.ptr.p_double[i]; } eps = 1.0E-6*ae_sqrt(eps, _state); sparsecreate(n, n, 0, &uppera, _state); sparsecreate(n, n, 0, &lowera, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { if( j>=i ) { sparseset(&uppera, i, j, a.ptr.pp_double[i][j], _state); } if( j<=i ) { sparseset(&lowera, i, j, a.ptr.pp_double[i][j], _state); } } } sparseconverttocrs(&uppera, _state); sparseconverttocrs(&lowera, _state); /* * Test upper triangle */ lincgcreate(n, &s, _state); lincgsetcond(&s, (double)(0), n, _state); lincgsolvesparse(&s, &uppera, ae_true, &b, _state); lincgresults(&s, &x0, &rep, _state); err = (double)(0); for(i=0; i<=n-1; i++) { err = err+ae_sqr(x0.ptr.p_double[i]-xs.ptr.p_double[i], _state); } err = ae_sqrt(err, _state); if( ae_fp_greater(err,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } /* * Test lower triangle */ lincgcreate(n, &s, _state); lincgsetcond(&s, (double)(0), n, _state); lincgsolvesparse(&s, &lowera, ae_false, &b, _state); lincgresults(&s, &x1, &rep, _state); err = (double)(0); for(i=0; i<=n-1; i++) { err = err+ae_sqr(x1.ptr.p_double[i]-xs.ptr.p_double[i], _state); } err = ae_sqrt(err, _state); if( ae_fp_greater(err,eps) ) { result = ae_true; ae_frame_leave(_state); return result; } } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Function for testing the preconditioned conjugate gradient method. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/ static ae_bool testlincgunit_precondtest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; lincgstate s; lincgreport rep; ae_matrix a; ae_matrix ta; sparsematrix sa; ae_vector m; ae_matrix mtx; ae_matrix mtprex; ae_vector de; ae_vector rde; ae_vector b; ae_vector tb; ae_vector d; ae_vector xe; ae_vector x0; ae_vector tx0; ae_vector err; ae_int_t n; ae_int_t sz; ae_int_t numofit; double c; ae_int_t i; ae_int_t j; ae_int_t k; double eps; ae_bool bflag; ae_bool result; ae_frame_make(_state, &_frame_block); _lincgstate_init(&s, _state); _lincgreport_init(&rep, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); ae_matrix_init(&ta, 0, 0, DT_REAL, _state); _sparsematrix_init(&sa, _state); ae_vector_init(&m, 0, DT_REAL, _state); ae_matrix_init(&mtx, 0, 0, DT_REAL, _state); ae_matrix_init(&mtprex, 0, 0, DT_REAL, _state); ae_vector_init(&de, 0, DT_REAL, _state); ae_vector_init(&rde, 0, DT_REAL, _state); ae_vector_init(&b, 0, DT_REAL, _state); ae_vector_init(&tb, 0, DT_REAL, _state); ae_vector_init(&d, 0, DT_REAL, _state); ae_vector_init(&xe, 0, DT_REAL, _state); ae_vector_init(&x0, 0, DT_REAL, _state); ae_vector_init(&tx0, 0, DT_REAL, _state); ae_vector_init(&err, 0, DT_REAL, _state); /* * Test 1. * * Preconditioned CG for A*x=b with preconditioner M=E*E' is algebraically * equivalent to non-preconditioned CG for (inv(E)*A*inv(E'))*z = inv(E)*b * with z=E'*x. * * We test it by generating random preconditioner, running algorithm twice - * one time for original problem with preconditioner , another one for * modified problem without preconditioner. */ sz = 5; for(n=1; n<=sz; n++) { /* * Generate: * * random A with unit norm * * random positive definite diagonal preconditioner M * * dE=sqrt(M) * * rdE=dE^(-1) * * tA = rdE*A*rdE * * random x0 and b - for original preconditioned problem * * tx0 and tb - for modified problem */ c = (testlincgunit_maxcond-1)*ae_randomreal(_state)+1; spdmatrixrndcond(n, c, &a, _state); ae_matrix_set_length(&ta, n, n, _state); ae_matrix_set_length(&mtx, n+1, n, _state); ae_matrix_set_length(&mtprex, n+1, n, _state); ae_vector_set_length(&m, n, _state); ae_vector_set_length(&de, n, _state); ae_vector_set_length(&rde, n, _state); for(i=0; i<=n-1; i++) { m.ptr.p_double[i] = ae_randomreal(_state)+0.5; de.ptr.p_double[i] = ae_sqrt(m.ptr.p_double[i], _state); rde.ptr.p_double[i] = 1/de.ptr.p_double[i]; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { ta.ptr.pp_double[i][j] = rde.ptr.p_double[i]*a.ptr.pp_double[i][j]*rde.ptr.p_double[j]; } } ae_vector_set_length(&b, n, _state); ae_vector_set_length(&tb, n, _state); ae_vector_set_length(&x0, n, _state); ae_vector_set_length(&tx0, n, _state); ae_vector_set_length(&err, n, _state); for(i=0; i<=n-1; i++) { x0.ptr.p_double[i] = 2*ae_randomreal(_state)-1; b.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } eps = 1.0E-5; for(i=0; i<=n-1; i++) { tx0.ptr.p_double[i] = de.ptr.p_double[i]*x0.ptr.p_double[i]; tb.ptr.p_double[i] = rde.ptr.p_double[i]*b.ptr.p_double[i]; } /* * Solve two problems, intermediate points are saved to MtX and MtPreX */ lincgcreate(n, &s, _state); lincgsetb(&s, &b, _state); lincgsetstartingpoint(&s, &x0, _state); lincgsetxrep(&s, ae_true, _state); lincgsetcond(&s, (double)(0), n, _state); numofit = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+a.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]/m.ptr.p_double[i]; } } if( s.xupdated ) { if( numofit>=mtx.rows ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { mtx.ptr.pp_double[numofit][i] = s.x.ptr.p_double[i]; } numofit = numofit+1; } } lincgsetstartingpoint(&s, &tx0, _state); lincgsetb(&s, &tb, _state); lincgrestart(&s, _state); numofit = 0; while(lincgiteration(&s, _state)) { if( s.needmv ) { for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+ta.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } } } if( s.needvmv ) { s.vmv = (double)(0); for(i=0; i<=n-1; i++) { s.mv.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { s.mv.ptr.p_double[i] = s.mv.ptr.p_double[i]+ta.ptr.pp_double[i][j]*s.x.ptr.p_double[j]; } s.vmv = s.vmv+s.mv.ptr.p_double[i]*s.x.ptr.p_double[i]; } } if( s.needprec ) { for(i=0; i<=n-1; i++) { s.pv.ptr.p_double[i] = s.x.ptr.p_double[i]; } } if( s.xupdated ) { if( numofit>=mtprex.rows ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { mtprex.ptr.pp_double[numofit][i] = s.x.ptr.p_double[i]; } numofit = numofit+1; } } /* * Compare results - sequence of points generated when solving original problem with * points generated by modified problem. */ for(i=0; i<=numofit-1; i++) { for(j=0; j<=n-1; j++) { if( ae_fp_greater(ae_fabs(mtx.ptr.pp_double[i][j]-rde.ptr.p_double[j]*mtprex.ptr.pp_double[i][j], _state),eps) ) { if( !silent ) { printf("PrecondTest::fail\n"); printf("Size=%0d\n", (int)(n)); printf("IterationsCount=%0d\n", (int)(rep.iterationscount)); printf("NMV=%0d\n", (int)(rep.nmv)); printf("TerminationType=%0d\n", (int)(rep.terminationtype)); printf("X and X^...\n"); for(k=0; k<=n-1; k++) { printf("I=%0d; mtx[%0d]=%0.10f; mtx^[%0d]=%0.10f\n", (int)(i), (int)(k), (double)(mtx.ptr.pp_double[i][k]), (int)(k), (double)(mtprex.ptr.pp_double[i][k])); } } result = ae_true; ae_frame_leave(_state); return result; } } } } /* * Test 2. * * We test automatic diagonal preconditioning used by SolveSparse. * In order to do so we: * 1. generate 20*20 matrix A0 with condition number equal to 1.0E1 * 2. generate random "exact" solution xe and right part b=A0*xe * 3. generate random ill-conditioned diagonal scaling matrix D with * condition number equal to 1.0E50: * 4. transform A*x=b into badly scaled problem: * A0*x0=b0 * A0*D*(inv(D)*x0)=b0 * (D*A0*D)*(inv(D)*x0)=(D*b0) * finally we got new problem A*x=b with A=D*A0*D, b=D*b0, x=inv(D)*x0 * * Then we solve A*x=b: * 1. with default preconditioner * 2. with explicitly activayed diagonal preconditioning * 3. with unit preconditioner. * 1st and 2nd solutions must be close to xe, 3rd solution must be very * far from the true one. */ n = 20; spdmatrixrndcond(n, 1.0E1, &ta, _state); ae_vector_set_length(&xe, n, _state); for(i=0; i<=n-1; i++) { xe.ptr.p_double[i] = randomnormal(_state); } ae_vector_set_length(&b, n, _state); for(i=0; i<=n-1; i++) { b.ptr.p_double[i] = (double)(0); for(j=0; j<=n-1; j++) { b.ptr.p_double[i] = b.ptr.p_double[i]+ta.ptr.pp_double[i][j]*xe.ptr.p_double[j]; } } ae_vector_set_length(&d, n, _state); for(i=0; i<=n-1; i++) { d.ptr.p_double[i] = ae_pow((double)(10), 100*ae_randomreal(_state)-50, _state); } ae_matrix_set_length(&a, n, n, _state); sparsecreate(n, n, n*n, &sa, _state); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { a.ptr.pp_double[i][j] = d.ptr.p_double[i]*ta.ptr.pp_double[i][j]*d.ptr.p_double[j]; sparseset(&sa, i, j, a.ptr.pp_double[i][j], _state); } b.ptr.p_double[i] = b.ptr.p_double[i]*d.ptr.p_double[i]; xe.ptr.p_double[i] = xe.ptr.p_double[i]/d.ptr.p_double[i]; } sparseconverttocrs(&sa, _state); lincgcreate(n, &s, _state); lincgsetcond(&s, (double)(0), 2*n, _state); lincgsolvesparse(&s, &sa, ae_true, &b, _state); lincgresults(&s, &x0, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]) ) { result = ae_true; ae_frame_leave(_state); return result; } } lincgsetprecunit(&s, _state); lincgsolvesparse(&s, &sa, ae_true, &b, _state); lincgresults(&s, &x0, &rep, _state); if( rep.terminationtype>0 ) { bflag = ae_false; for(i=0; i<=n-1; i++) { bflag = bflag||ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]); } if( !bflag ) { result = ae_true; ae_frame_leave(_state); return result; } } lincgsetprecdiag(&s, _state); lincgsolvesparse(&s, &sa, ae_true, &b, _state); lincgresults(&s, &x0, &rep, _state); if( rep.terminationtype<=0 ) { result = ae_true; ae_frame_leave(_state); return result; } for(i=0; i<=n-1; i++) { if( ae_fp_greater(ae_fabs(xe.ptr.p_double[i]-x0.ptr.p_double[i], _state),5.0E-2/d.ptr.p_double[i]) ) { result = ae_true; ae_frame_leave(_state); return result; } } /* *test has been passed */ if( !silent ) { printf("PrecondTest::Ok\n"); } result = ae_false; ae_frame_leave(_state); return result; } /************************************************************************* Orthogonalization by Gram-Shmidt method. *************************************************************************/ static void testlincgunit_gramshmidtortnorm(/* Real */ ae_matrix* a, ae_int_t n, ae_int_t k, double eps, /* Real */ ae_matrix* b, ae_int_t* k2, ae_state *_state) { double scaling; double tmp; double e; ae_int_t i; ae_int_t j; ae_int_t l; ae_int_t m; double sc; ae_matrix_clear(b); *k2 = 0; *k2 = 0; scaling = (double)(0); ae_matrix_set_length(b, k, n, _state); for(i=0; i<=k-1; i++) { tmp = (double)(0); for(j=0; j<=n-1; j++) { tmp = tmp+a->ptr.pp_double[i][j]*a->ptr.pp_double[i][j]; } if( ae_fp_greater(tmp,scaling) ) { scaling = tmp; } } scaling = ae_sqrt(scaling, _state); e = eps*scaling; for(i=0; i<=k-1; i++) { tmp = (double)(0); for(j=0; j<=n-1; j++) { b->ptr.pp_double[*k2][j] = a->ptr.pp_double[i][j]; tmp = tmp+a->ptr.pp_double[i][j]*a->ptr.pp_double[i][j]; } tmp = ae_sqrt(tmp, _state); if( ae_fp_less_eq(tmp,e) ) { continue; } for(j=0; j<=*k2-1; j++) { sc = (double)(0); for(m=0; m<=n-1; m++) { sc = sc+b->ptr.pp_double[*k2][m]*b->ptr.pp_double[j][m]; } for(l=0; l<=n-1; l++) { b->ptr.pp_double[*k2][l] = b->ptr.pp_double[*k2][l]-sc*b->ptr.pp_double[j][l]; } } tmp = (double)(0); for(j=0; j<=n-1; j++) { tmp = tmp+b->ptr.pp_double[*k2][j]*b->ptr.pp_double[*k2][j]; } tmp = ae_sqrt(tmp, _state); if( ae_fp_less_eq(tmp,e) ) { continue; } else { for(j=0; j<=n-1; j++) { b->ptr.pp_double[*k2][j] = b->ptr.pp_double[*k2][j]/tmp; } } *k2 = *k2+1; } } /************************************************************************* Checks that a vector belongs to the basis. *************************************************************************/ static ae_bool testlincgunit_frombasis(/* Real */ ae_vector* x, /* Real */ ae_matrix* basis, ae_int_t n, ae_int_t k, double eps, ae_state *_state) { ae_frame _frame_block; double normx; ae_matrix ortnormbasis; ae_int_t k2; ae_int_t i; ae_int_t j; double alpha; ae_vector alphas; ae_bool result; ae_frame_make(_state, &_frame_block); ae_matrix_init(&ortnormbasis, 0, 0, DT_REAL, _state); ae_vector_init(&alphas, 0, DT_REAL, _state); ae_vector_set_length(&alphas, k, _state); /* *calculating NORM for X */ normx = (double)(0); for(i=0; i<=n-1; i++) { normx = normx+x->ptr.p_double[i]*x->ptr.p_double[i]; } normx = ae_sqrt(normx, _state); /* *Gram-Shmidt method */ testlincgunit_gramshmidtortnorm(basis, n, k, eps, &ortnormbasis, &k2, _state); for(i=0; i<=k2-1; i++) { alpha = (double)(0); for(j=0; j<=n-1; j++) { alpha = alpha+x->ptr.p_double[j]*ortnormbasis.ptr.pp_double[i][j]; } alphas.ptr.p_double[i] = alpha; } /* *check */ for(i=0; i<=n-1; i++) { alpha = (double)(0); for(j=0; j<=k2-1; j++) { alpha = alpha+alphas.ptr.p_double[j]*ortnormbasis.ptr.pp_double[j][i]; } if( ae_fp_greater(ae_fabs(x->ptr.p_double[i]-alpha, _state),normx*eps) ) { result = ae_false; ae_frame_leave(_state); return result; } } result = ae_true; ae_frame_leave(_state); return result; } static void testnlequnit_testfunchbm(nleqstate* state, ae_state *_state); static void testnlequnit_testfunchb1(nleqstate* state, ae_state *_state); static void testnlequnit_testfuncshbm(nleqstate* state, ae_state *_state); ae_bool testnleq(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; ae_bool basicserrors; ae_bool converror; ae_bool othererrors; ae_int_t n; ae_vector x; ae_int_t i; ae_int_t k; double v; double flast; ae_vector xlast; ae_bool firstrep; ae_int_t nfunc; ae_int_t njac; ae_int_t itcnt; nleqstate state; nleqreport rep; ae_int_t pass; ae_int_t passcount; double epsf; double stpmax; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&xlast, 0, DT_REAL, _state); _nleqstate_init(&state, _state); _nleqreport_init(&rep, _state); waserrors = ae_false; basicserrors = ae_false; converror = ae_false; othererrors = ae_false; /* * Basic tests * * Test with Himmelblau's function (M): * * ability to find correct result * * ability to work after soft restart (restart after finish) * * ability to work after hard restart (restart in the middle of optimization) */ passcount = 100; for(pass=0; pass<=passcount-1; pass++) { /* * Ability to find correct result */ ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqcreatelm(2, 2, &x, &state, _state); epsf = 1.0E-9; nleqsetcond(&state, epsf, 0, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfunchbm(&state, _state); } nleqresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { basicserrors = basicserrors||ae_fp_greater(ae_sqr(x.ptr.p_double[0]*x.ptr.p_double[0]+x.ptr.p_double[1]-11, _state)+ae_sqr(x.ptr.p_double[0]+x.ptr.p_double[1]*x.ptr.p_double[1]-7, _state),ae_sqr(epsf, _state)); } else { basicserrors = ae_true; } /* * Ability to work after soft restart */ ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqcreatelm(2, 2, &x, &state, _state); epsf = 1.0E-9; nleqsetcond(&state, epsf, 0, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfunchbm(&state, _state); } nleqresults(&state, &x, &rep, _state); ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqrestartfrom(&state, &x, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfunchbm(&state, _state); } nleqresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { basicserrors = basicserrors||ae_fp_greater(ae_sqr(x.ptr.p_double[0]*x.ptr.p_double[0]+x.ptr.p_double[1]-11, _state)+ae_sqr(x.ptr.p_double[0]+x.ptr.p_double[1]*x.ptr.p_double[1]-7, _state),ae_sqr(epsf, _state)); } else { basicserrors = ae_true; } /* * Ability to work after hard restart: * * stopping condition: small F * * StpMax is so small that we need about 10000 iterations to * find solution (steps are small) * * choose random K significantly less that 9999 * * iterate for some time, then break, restart optimization */ ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = (double)(100); x.ptr.p_double[1] = (double)(100); nleqcreatelm(2, 2, &x, &state, _state); epsf = 1.0E-9; nleqsetcond(&state, epsf, 0, _state); nleqsetstpmax(&state, 0.01, _state); k = 1+ae_randominteger(100, _state); for(i=0; i<=k-1; i++) { if( !nleqiteration(&state, _state) ) { break; } testnlequnit_testfunchbm(&state, _state); } ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqrestartfrom(&state, &x, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfunchbm(&state, _state); } nleqresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { basicserrors = basicserrors||ae_fp_greater(ae_sqr(x.ptr.p_double[0]*x.ptr.p_double[0]+x.ptr.p_double[1]-11, _state)+ae_sqr(x.ptr.p_double[0]+x.ptr.p_double[1]*x.ptr.p_double[1]-7, _state),ae_sqr(epsf, _state)); } else { basicserrors = ae_true; } } /* * Basic tests * * Test with Himmelblau's function (1): * * ability to find correct result */ passcount = 100; for(pass=0; pass<=passcount-1; pass++) { /* * Ability to find correct result */ ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqcreatelm(2, 1, &x, &state, _state); epsf = 1.0E-9; nleqsetcond(&state, epsf, 0, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfunchb1(&state, _state); } nleqresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { basicserrors = basicserrors||ae_fp_greater(ae_sqr(x.ptr.p_double[0]*x.ptr.p_double[0]+x.ptr.p_double[1]-11, _state)+ae_sqr(x.ptr.p_double[0]+x.ptr.p_double[1]*x.ptr.p_double[1]-7, _state),epsf); } else { basicserrors = ae_true; } } /* * Basic tests * * Ability to detect situation when we can't find minimum */ passcount = 100; for(pass=0; pass<=passcount-1; pass++) { ae_vector_set_length(&x, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; nleqcreatelm(2, 3, &x, &state, _state); epsf = 1.0E-9; nleqsetcond(&state, epsf, 0, _state); while(nleqiteration(&state, _state)) { testnlequnit_testfuncshbm(&state, _state); } nleqresults(&state, &x, &rep, _state); basicserrors = basicserrors||rep.terminationtype!=-4; } /* * Test correctness of intermediate reports and final report: * * first report is starting point * * function value decreases on subsequent reports * * function value is correctly reported * * last report is final point * * NFunc and NJac are compared with values counted directly * * IterationsCount is compared with value counter directly */ n = 2; ae_vector_set_length(&x, n, _state); ae_vector_set_length(&xlast, n, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)-10; x.ptr.p_double[1] = 20*ae_randomreal(_state)-10; xlast.ptr.p_double[0] = ae_maxrealnumber; xlast.ptr.p_double[1] = ae_maxrealnumber; nleqcreatelm(n, 2, &x, &state, _state); nleqsetcond(&state, 1.0E-6, 0, _state); nleqsetxrep(&state, ae_true, _state); firstrep = ae_true; flast = ae_maxrealnumber; nfunc = 0; njac = 0; itcnt = 0; while(nleqiteration(&state, _state)) { if( state.xupdated ) { /* * first report must be starting point */ if( firstrep ) { for(i=0; i<=n-1; i++) { othererrors = othererrors||ae_fp_neq(state.x.ptr.p_double[i],x.ptr.p_double[i]); } firstrep = ae_false; } /* * function value must decrease */ othererrors = othererrors||ae_fp_greater(state.f,flast); /* * check correctness of function value */ v = ae_sqr(state.x.ptr.p_double[0]*state.x.ptr.p_double[0]+state.x.ptr.p_double[1]-11, _state)+ae_sqr(state.x.ptr.p_double[0]+state.x.ptr.p_double[1]*state.x.ptr.p_double[1]-7, _state); othererrors = othererrors||ae_fp_greater(ae_fabs(v-state.f, _state)/ae_maxreal(v, (double)(1), _state),100*ae_machineepsilon); /* * update info and continue */ ae_v_move(&xlast.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); flast = state.f; itcnt = itcnt+1; continue; } if( state.needf ) { nfunc = nfunc+1; } if( state.needfij ) { nfunc = nfunc+1; njac = njac+1; } testnlequnit_testfunchbm(&state, _state); } nleqresults(&state, &x, &rep, _state); if( rep.terminationtype>0 ) { othererrors = (othererrors||ae_fp_neq(xlast.ptr.p_double[0],x.ptr.p_double[0]))||ae_fp_neq(xlast.ptr.p_double[1],x.ptr.p_double[1]); v = ae_sqr(x.ptr.p_double[0]*x.ptr.p_double[0]+x.ptr.p_double[1]-11, _state)+ae_sqr(x.ptr.p_double[0]+x.ptr.p_double[1]*x.ptr.p_double[1]-7, _state); othererrors = othererrors||ae_fp_greater(ae_fabs(flast-v, _state)/ae_maxreal(v, (double)(1), _state),100*ae_machineepsilon); } else { converror = ae_true; } othererrors = othererrors||rep.nfunc!=nfunc; othererrors = othererrors||rep.njac!=njac; othererrors = othererrors||rep.iterationscount!=itcnt-1; /* * Test ability to set limit on algorithm steps */ ae_vector_set_length(&x, 2, _state); ae_vector_set_length(&xlast, 2, _state); x.ptr.p_double[0] = 20*ae_randomreal(_state)+20; x.ptr.p_double[1] = 20*ae_randomreal(_state)+20; xlast.ptr.p_double[0] = x.ptr.p_double[0]; xlast.ptr.p_double[1] = x.ptr.p_double[1]; stpmax = 0.1+0.1*ae_randomreal(_state); epsf = 1.0E-9; nleqcreatelm(2, 3, &x, &state, _state); nleqsetstpmax(&state, stpmax, _state); nleqsetcond(&state, epsf, 0, _state); nleqsetxrep(&state, ae_true, _state); while(nleqiteration(&state, _state)) { if( state.needf||state.needfij ) { testnlequnit_testfunchbm(&state, _state); } if( (state.needf||state.needfij)||state.xupdated ) { othererrors = othererrors||ae_fp_greater(ae_sqrt(ae_sqr(state.x.ptr.p_double[0]-xlast.ptr.p_double[0], _state)+ae_sqr(state.x.ptr.p_double[1]-xlast.ptr.p_double[1], _state), _state),1.00001*stpmax); } if( state.xupdated ) { xlast.ptr.p_double[0] = state.x.ptr.p_double[0]; xlast.ptr.p_double[1] = state.x.ptr.p_double[1]; } } /* * end */ waserrors = (basicserrors||converror)||othererrors; if( !silent ) { printf("TESTING NLEQ SOLVER\n"); printf("BASIC FUNCTIONALITY: "); if( basicserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("CONVERGENCE: "); if( converror ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("OTHER PROPERTIES: "); if( othererrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testnleq(ae_bool silent, ae_state *_state) { return testnleq(silent, _state); } /************************************************************************* Himmelblau's function F = (x^2+y-11)^2 + (x+y^2-7)^2 posed as system of M functions: f0 = x^2+y-11 f1 = x+y^2-7 *************************************************************************/ static void testnlequnit_testfunchbm(nleqstate* state, ae_state *_state) { double x; double y; ae_assert(state->needf||state->needfij, "TestNLEQUnit: internal error!", _state); x = state->x.ptr.p_double[0]; y = state->x.ptr.p_double[1]; if( state->needf ) { state->f = ae_sqr(x*x+y-11, _state)+ae_sqr(x+y*y-7, _state); return; } if( state->needfij ) { state->fi.ptr.p_double[0] = x*x+y-11; state->fi.ptr.p_double[1] = x+y*y-7; state->j.ptr.pp_double[0][0] = 2*x; state->j.ptr.pp_double[0][1] = (double)(1); state->j.ptr.pp_double[1][0] = (double)(1); state->j.ptr.pp_double[1][1] = 2*y; return; } } /************************************************************************* Himmelblau's function F = (x^2+y-11)^2 + (x+y^2-7)^2 posed as system of 1 function *************************************************************************/ static void testnlequnit_testfunchb1(nleqstate* state, ae_state *_state) { double x; double y; ae_assert(state->needf||state->needfij, "TestNLEQUnit: internal error!", _state); x = state->x.ptr.p_double[0]; y = state->x.ptr.p_double[1]; if( state->needf ) { state->f = ae_sqr(ae_sqr(x*x+y-11, _state)+ae_sqr(x+y*y-7, _state), _state); return; } if( state->needfij ) { state->fi.ptr.p_double[0] = ae_sqr(x*x+y-11, _state)+ae_sqr(x+y*y-7, _state); state->j.ptr.pp_double[0][0] = 2*(x*x+y-11)*2*x+2*(x+y*y-7); state->j.ptr.pp_double[0][1] = 2*(x*x+y-11)+2*(x+y*y-7)*2*y; return; } } /************************************************************************* Shifted Himmelblau's function F = (x^2+y-11)^2 + (x+y^2-7)^2 + 1 posed as system of M functions: f0 = x^2+y-11 f1 = x+y^2-7 f2 = 1 This function is used to test algorithm on problem which has no solution. *************************************************************************/ static void testnlequnit_testfuncshbm(nleqstate* state, ae_state *_state) { double x; double y; ae_assert(state->needf||state->needfij, "TestNLEQUnit: internal error!", _state); x = state->x.ptr.p_double[0]; y = state->x.ptr.p_double[1]; if( state->needf ) { state->f = ae_sqr(x*x+y-11, _state)+ae_sqr(x+y*y-7, _state)+1; return; } if( state->needfij ) { state->fi.ptr.p_double[0] = x*x+y-11; state->fi.ptr.p_double[1] = x+y*y-7; state->fi.ptr.p_double[2] = (double)(1); state->j.ptr.pp_double[0][0] = 2*x; state->j.ptr.pp_double[0][1] = (double)(1); state->j.ptr.pp_double[1][0] = (double)(1); state->j.ptr.pp_double[1][1] = 2*y; state->j.ptr.pp_double[2][0] = (double)(0); state->j.ptr.pp_double[2][1] = (double)(0); return; } } /************************************************************************* Test *************************************************************************/ ae_bool testpolynomialsolver(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool wereerrors; ae_vector a; ae_vector x; double eps; ae_int_t n; polynomialsolverreport rep; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_REAL, _state); ae_vector_init(&x, 0, DT_COMPLEX, _state); _polynomialsolverreport_init(&rep, _state); wereerrors = ae_false; /* * Basic tests */ eps = 1.0E-6; n = 1; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(2); a.ptr.p_double[1] = (double)(3); polynomialsolve(&a, n, &x, &rep, _state); seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[0].x+(double)2/(double)3, _state),eps), _state); seterrorflag(&wereerrors, ae_fp_neq(x.ptr.p_complex[0].y,(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); n = 2; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(1); a.ptr.p_double[1] = (double)(-2); a.ptr.p_double[2] = (double)(1); polynomialsolve(&a, n, &x, &rep, _state); seterrorflag(&wereerrors, ae_fp_greater(ae_c_abs(ae_c_sub_d(x.ptr.p_complex[0],1), _state),eps), _state); seterrorflag(&wereerrors, ae_fp_greater(ae_c_abs(ae_c_sub_d(x.ptr.p_complex[1],1), _state),eps), _state); seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); n = 2; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(2); a.ptr.p_double[1] = (double)(-3); a.ptr.p_double[2] = (double)(1); polynomialsolve(&a, n, &x, &rep, _state); if( ae_fp_less(x.ptr.p_complex[0].x,x.ptr.p_complex[1].x) ) { seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[0].x-1, _state),eps), _state); seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[1].x-2, _state),eps), _state); } else { seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[0].x-2, _state),eps), _state); seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[1].x-1, _state),eps), _state); } seterrorflag(&wereerrors, ae_fp_neq(x.ptr.p_complex[0].y,(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_neq(x.ptr.p_complex[1].y,(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); n = 2; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(1); a.ptr.p_double[1] = (double)(0); a.ptr.p_double[2] = (double)(1); polynomialsolve(&a, n, &x, &rep, _state); seterrorflag(&wereerrors, ae_fp_greater(ae_c_abs(ae_c_add_d(ae_c_mul(x.ptr.p_complex[0],x.ptr.p_complex[0]),(double)(1)), _state),eps), _state); seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); n = 4; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(0); a.ptr.p_double[1] = (double)(0); a.ptr.p_double[2] = (double)(0); a.ptr.p_double[3] = (double)(0); a.ptr.p_double[4] = (double)(1); polynomialsolve(&a, n, &x, &rep, _state); seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[0],(double)(0)), _state); seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[1],(double)(0)), _state); seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[2],(double)(0)), _state); seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[3],(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); n = 2; ae_vector_set_length(&a, n+1, _state); a.ptr.p_double[0] = (double)(0); a.ptr.p_double[1] = (double)(3); a.ptr.p_double[2] = (double)(2); polynomialsolve(&a, n, &x, &rep, _state); if( ae_fp_greater(x.ptr.p_complex[0].x,x.ptr.p_complex[1].x) ) { seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[0],(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[1].x+(double)3/(double)2, _state),eps), _state); seterrorflag(&wereerrors, ae_fp_neq(x.ptr.p_complex[1].y,(double)(0)), _state); } else { seterrorflag(&wereerrors, ae_c_neq_d(x.ptr.p_complex[1],(double)(0)), _state); seterrorflag(&wereerrors, ae_fp_greater(ae_fabs(x.ptr.p_complex[0].x+(double)3/(double)2, _state),eps), _state); seterrorflag(&wereerrors, ae_fp_neq(x.ptr.p_complex[0].y,(double)(0)), _state); } seterrorflag(&wereerrors, ae_fp_greater(rep.maxerr,100*ae_machineepsilon), _state); if( !silent ) { printf("TESTING POLYNOMIAL SOLVER\n"); if( wereerrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !wereerrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testpolynomialsolver(ae_bool silent, ae_state *_state) { return testpolynomialsolver(silent, _state); } ae_bool testchebyshev(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double err; double sumerr; double cerr; double ferr; double threshold; double x; double v; ae_int_t pass; ae_int_t i; ae_int_t j; ae_int_t k; ae_int_t n; ae_int_t maxn; ae_vector c; ae_vector p1; ae_vector p2; ae_matrix a; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&c, 0, DT_REAL, _state); ae_vector_init(&p1, 0, DT_REAL, _state); ae_vector_init(&p2, 0, DT_REAL, _state); ae_matrix_init(&a, 0, 0, DT_REAL, _state); err = (double)(0); sumerr = (double)(0); cerr = (double)(0); ferr = (double)(0); threshold = 1.0E-9; waserrors = ae_false; /* * Testing Chebyshev polynomials of the first kind */ err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 0, 0.00, _state)-1, _state), _state); err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 0, 0.33, _state)-1, _state), _state); err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 0, -0.42, _state)-1, _state), _state); x = 0.2; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 1, x, _state)-0.2, _state), _state); x = 0.4; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 1, x, _state)-0.4, _state), _state); x = 0.6; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 1, x, _state)-0.6, _state), _state); x = 0.8; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 1, x, _state)-0.8, _state), _state); x = 1.0; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 1, x, _state)-1.0, _state), _state); x = 0.2; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 2, x, _state)+0.92, _state), _state); x = 0.4; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 2, x, _state)+0.68, _state), _state); x = 0.6; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 2, x, _state)+0.28, _state), _state); x = 0.8; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 2, x, _state)-0.28, _state), _state); x = 1.0; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, 2, x, _state)-1.00, _state), _state); n = 10; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, n, 0.2, _state)-0.4284556288, _state), _state); n = 11; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, n, 0.2, _state)+0.7996160205, _state), _state); n = 12; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(1, n, 0.2, _state)+0.7483020370, _state), _state); /* * Testing Chebyshev polynomials of the second kind */ n = 0; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)-1.0000000000, _state), _state); n = 1; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)-0.4000000000, _state), _state); n = 2; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)+0.8400000000, _state), _state); n = 3; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)+0.7360000000, _state), _state); n = 4; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)-0.5456000000, _state), _state); n = 10; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)-0.6128946176, _state), _state); n = 11; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)+0.6770370970, _state), _state); n = 12; err = ae_maxreal(err, ae_fabs(chebyshevcalculate(2, n, 0.2, _state)+0.8837094564, _state), _state); /* * Testing Clenshaw summation */ maxn = 20; ae_vector_set_length(&c, maxn+1, _state); for(k=1; k<=2; k++) { for(pass=1; pass<=10; pass++) { x = 2*ae_randomreal(_state)-1; v = (double)(0); for(n=0; n<=maxn; n++) { c.ptr.p_double[n] = 2*ae_randomreal(_state)-1; v = v+chebyshevcalculate(k, n, x, _state)*c.ptr.p_double[n]; sumerr = ae_maxreal(sumerr, ae_fabs(v-chebyshevsum(&c, k, n, x, _state), _state), _state); } } } /* * Testing coefficients */ chebyshevcoefficients(0, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); chebyshevcoefficients(1, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-1, _state), _state); chebyshevcoefficients(2, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]+1, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-2, _state), _state); chebyshevcoefficients(3, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+3, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-4, _state), _state); chebyshevcoefficients(4, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]+8, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-8, _state), _state); chebyshevcoefficients(9, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-9, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]-432, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[6]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[7]+576, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[8]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[9]-256, _state), _state); /* * Testing FromChebyshev */ maxn = 10; ae_matrix_set_length(&a, maxn+1, maxn+1, _state); for(i=0; i<=maxn; i++) { for(j=0; j<=maxn; j++) { a.ptr.pp_double[i][j] = (double)(0); } chebyshevcoefficients(i, &c, _state); ae_v_move(&a.ptr.pp_double[i][0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,i)); } ae_vector_set_length(&c, maxn+1, _state); ae_vector_set_length(&p1, maxn+1, _state); for(n=0; n<=maxn; n++) { for(pass=1; pass<=10; pass++) { for(i=0; i<=n; i++) { p1.ptr.p_double[i] = (double)(0); } for(i=0; i<=n; i++) { c.ptr.p_double[i] = 2*ae_randomreal(_state)-1; v = c.ptr.p_double[i]; ae_v_addd(&p1.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,i), v); } fromchebyshev(&c, n, &p2, _state); for(i=0; i<=n; i++) { ferr = ae_maxreal(ferr, ae_fabs(p1.ptr.p_double[i]-p2.ptr.p_double[i], _state), _state); } } } /* * Reporting */ waserrors = ((ae_fp_greater(err,threshold)||ae_fp_greater(sumerr,threshold))||ae_fp_greater(cerr,threshold))||ae_fp_greater(ferr,threshold); if( !silent ) { printf("TESTING CALCULATION OF THE CHEBYSHEV POLYNOMIALS\n"); printf("Max error against table %5.2e\n", (double)(err)); printf("Summation error %5.2e\n", (double)(sumerr)); printf("Coefficients error %5.2e\n", (double)(cerr)); printf("FrobChebyshev error %5.2e\n", (double)(ferr)); printf("Threshold %5.2e\n", (double)(threshold)); if( !waserrors ) { printf("TEST PASSED\n"); } else { printf("TEST FAILED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testchebyshev(ae_bool silent, ae_state *_state) { return testchebyshev(silent, _state); } ae_bool testhermite(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double err; double sumerr; double cerr; double threshold; ae_int_t n; ae_int_t maxn; ae_int_t pass; ae_vector c; double x; double v; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&c, 0, DT_REAL, _state); err = (double)(0); sumerr = (double)(0); cerr = (double)(0); threshold = 1.0E-9; waserrors = ae_false; /* * Testing Hermite polynomials */ n = 0; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-1, _state), _state); n = 1; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-2, _state), _state); n = 2; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-2, _state), _state); n = 3; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)+4, _state), _state); n = 4; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)+20, _state), _state); n = 5; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)+8, _state), _state); n = 6; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-184, _state), _state); n = 7; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-464, _state), _state); n = 11; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-230848, _state), _state); n = 12; err = ae_maxreal(err, ae_fabs(hermitecalculate(n, (double)(1), _state)-280768, _state), _state); /* * Testing Clenshaw summation */ maxn = 10; ae_vector_set_length(&c, maxn+1, _state); for(pass=1; pass<=10; pass++) { x = 2*ae_randomreal(_state)-1; v = (double)(0); for(n=0; n<=maxn; n++) { c.ptr.p_double[n] = 2*ae_randomreal(_state)-1; v = v+hermitecalculate(n, x, _state)*c.ptr.p_double[n]; sumerr = ae_maxreal(sumerr, ae_fabs(v-hermitesum(&c, n, x, _state), _state), _state); } } /* * Testing coefficients */ hermitecoefficients(0, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); hermitecoefficients(1, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-2, _state), _state); hermitecoefficients(2, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]+2, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-4, _state), _state); hermitecoefficients(3, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+12, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-8, _state), _state); hermitecoefficients(4, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-12, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]+48, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-16, _state), _state); hermitecoefficients(5, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+160, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]-32, _state), _state); hermitecoefficients(6, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]+120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]+480, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[6]-64, _state), _state); /* * Reporting */ waserrors = (ae_fp_greater(err,threshold)||ae_fp_greater(sumerr,threshold))||ae_fp_greater(cerr,threshold); if( !silent ) { printf("TESTING CALCULATION OF THE HERMITE POLYNOMIALS\n"); printf("Max error %5.2e\n", (double)(err)); printf("Summation error %5.2e\n", (double)(sumerr)); printf("Coefficients error %5.2e\n", (double)(cerr)); printf("Threshold %5.2e\n", (double)(threshold)); if( !waserrors ) { printf("TEST PASSED\n"); } else { printf("TEST FAILED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testhermite(ae_bool silent, ae_state *_state) { return testhermite(silent, _state); } ae_bool testlaguerre(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double err; double sumerr; double cerr; double threshold; ae_int_t n; ae_int_t maxn; ae_int_t pass; ae_vector c; double x; double v; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&c, 0, DT_REAL, _state); err = (double)(0); sumerr = (double)(0); cerr = (double)(0); threshold = 1.0E-9; waserrors = ae_false; /* * Testing Laguerre polynomials */ n = 0; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)-1.0000000000, _state), _state); n = 1; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)-0.5000000000, _state), _state); n = 2; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)-0.1250000000, _state), _state); n = 3; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.1458333333, _state), _state); n = 4; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.3307291667, _state), _state); n = 5; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.4455729167, _state), _state); n = 6; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.5041449653, _state), _state); n = 7; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.5183392237, _state), _state); n = 8; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.4983629984, _state), _state); n = 9; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.4529195204, _state), _state); n = 10; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.3893744141, _state), _state); n = 11; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.3139072988, _state), _state); n = 12; err = ae_maxreal(err, ae_fabs(laguerrecalculate(n, 0.5, _state)+0.2316496389, _state), _state); /* * Testing Clenshaw summation */ maxn = 20; ae_vector_set_length(&c, maxn+1, _state); for(pass=1; pass<=10; pass++) { x = 2*ae_randomreal(_state)-1; v = (double)(0); for(n=0; n<=maxn; n++) { c.ptr.p_double[n] = 2*ae_randomreal(_state)-1; v = v+laguerrecalculate(n, x, _state)*c.ptr.p_double[n]; sumerr = ae_maxreal(sumerr, ae_fabs(v-laguerresum(&c, n, x, _state), _state), _state); } } /* * Testing coefficients */ laguerrecoefficients(0, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); laguerrecoefficients(1, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+1, _state), _state); laguerrecoefficients(2, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)2/(double)2, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)4/(double)2, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)1/(double)2, _state), _state); laguerrecoefficients(3, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)6/(double)6, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)18/(double)6, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)9/(double)6, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+(double)1/(double)6, _state), _state); laguerrecoefficients(4, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)24/(double)24, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)96/(double)24, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)72/(double)24, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+(double)16/(double)24, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-(double)1/(double)24, _state), _state); laguerrecoefficients(5, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)120/(double)120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)600/(double)120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)600/(double)120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+(double)200/(double)120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-(double)25/(double)120, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]+(double)1/(double)120, _state), _state); laguerrecoefficients(6, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)720/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)4320/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)5400/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+(double)2400/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-(double)450/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]+(double)36/(double)720, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[6]-(double)1/(double)720, _state), _state); /* * Reporting */ waserrors = (ae_fp_greater(err,threshold)||ae_fp_greater(sumerr,threshold))||ae_fp_greater(cerr,threshold); if( !silent ) { printf("TESTING CALCULATION OF THE LAGUERRE POLYNOMIALS\n"); printf("Max error %5.2e\n", (double)(err)); printf("Summation error %5.2e\n", (double)(sumerr)); printf("Coefficients error %5.2e\n", (double)(cerr)); printf("Threshold %5.2e\n", (double)(threshold)); if( !waserrors ) { printf("TEST PASSED\n"); } else { printf("TEST FAILED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlaguerre(ae_bool silent, ae_state *_state) { return testlaguerre(silent, _state); } ae_bool testlegendre(ae_bool silent, ae_state *_state) { ae_frame _frame_block; double err; double sumerr; double cerr; double threshold; ae_int_t n; ae_int_t maxn; ae_int_t i; ae_int_t pass; ae_vector c; double x; double v; double t; ae_bool waserrors; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&c, 0, DT_REAL, _state); err = (double)(0); sumerr = (double)(0); cerr = (double)(0); threshold = 1.0E-9; waserrors = ae_false; /* * Testing Legendre polynomials values */ for(n=0; n<=10; n++) { legendrecoefficients(n, &c, _state); for(pass=1; pass<=10; pass++) { x = 2*ae_randomreal(_state)-1; v = legendrecalculate(n, x, _state); t = (double)(1); for(i=0; i<=n; i++) { v = v-c.ptr.p_double[i]*t; t = t*x; } err = ae_maxreal(err, ae_fabs(v, _state), _state); } } /* * Testing Clenshaw summation */ maxn = 20; ae_vector_set_length(&c, maxn+1, _state); for(pass=1; pass<=10; pass++) { x = 2*ae_randomreal(_state)-1; v = (double)(0); for(n=0; n<=maxn; n++) { c.ptr.p_double[n] = 2*ae_randomreal(_state)-1; v = v+legendrecalculate(n, x, _state)*c.ptr.p_double[n]; sumerr = ae_maxreal(sumerr, ae_fabs(v-legendresum(&c, n, x, _state), _state), _state); } } /* * Testing coefficients */ legendrecoefficients(0, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-1, _state), _state); legendrecoefficients(1, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-1, _state), _state); legendrecoefficients(2, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]+(double)1/(double)2, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-(double)3/(double)2, _state), _state); legendrecoefficients(3, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]+(double)3/(double)2, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-(double)5/(double)2, _state), _state); legendrecoefficients(4, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-(double)3/(double)8, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]+(double)30/(double)8, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-(double)35/(double)8, _state), _state); legendrecoefficients(9, &c, _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[0]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[1]-(double)315/(double)128, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[2]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[3]+(double)4620/(double)128, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[4]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[5]-(double)18018/(double)128, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[6]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[7]+(double)25740/(double)128, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[8]-0, _state), _state); cerr = ae_maxreal(cerr, ae_fabs(c.ptr.p_double[9]-(double)12155/(double)128, _state), _state); /* * Reporting */ waserrors = (ae_fp_greater(err,threshold)||ae_fp_greater(sumerr,threshold))||ae_fp_greater(cerr,threshold); if( !silent ) { printf("TESTING CALCULATION OF THE LEGENDRE POLYNOMIALS\n"); printf("Max error %5.2e\n", (double)(err)); printf("Summation error %5.2e\n", (double)(sumerr)); printf("Coefficients error %5.2e\n", (double)(cerr)); printf("Threshold %5.2e\n", (double)(threshold)); if( !waserrors ) { printf("TEST PASSED\n"); } else { printf("TEST FAILED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testlegendre(ae_bool silent, ae_state *_state) { return testlegendre(silent, _state); } ae_bool teststest(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_vector x; double taill; double tailr; double tailb; ae_bool waserrors; double eps; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); waserrors = ae_false; eps = 1.0E-3; /* * Test 1 */ ae_vector_set_length(&x, 6, _state); x.ptr.p_double[0] = (double)(-3); x.ptr.p_double[1] = (double)(-2); x.ptr.p_double[2] = (double)(-1); x.ptr.p_double[3] = (double)(1); x.ptr.p_double[4] = (double)(2); x.ptr.p_double[5] = (double)(3); onesamplesigntest(&x, 6, 0.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.65625, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.65625, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-1.00000, _state),eps); onesamplesigntest(&x, 6, -1.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.81250, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.50000, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-1.00000, _state),eps); onesamplesigntest(&x, 6, -1.5, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.89062, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.34375, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.68750, _state),eps); onesamplesigntest(&x, 6, -3.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-1.00000, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.03125, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.06250, _state),eps); /* * Test 2 */ ae_vector_set_length(&x, 3, _state); x.ptr.p_double[0] = (double)(2); x.ptr.p_double[1] = (double)(2); x.ptr.p_double[2] = (double)(2); onesamplesigntest(&x, 3, 2.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); /* * Final report */ if( !silent ) { printf("SIGN TEST: "); if( !waserrors ) { printf("OK\n"); } else { printf("FAILED\n"); } if( waserrors ) { printf("TEST SUMMARY: FAILED\n"); } else { printf("TEST SUMMARY: PASSED\n"); } printf("\n\n"); } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_teststest(ae_bool silent, ae_state *_state) { return teststest(silent, _state); } ae_bool teststudentttests(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool waserrors; double eps; ae_vector x; ae_vector y; ae_vector xa; ae_vector ya; ae_vector xb; ae_vector yb; ae_int_t n; double taill; double tailr; double tailb; double taill1; double tailr1; double tailb1; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&x, 0, DT_REAL, _state); ae_vector_init(&y, 0, DT_REAL, _state); ae_vector_init(&xa, 0, DT_REAL, _state); ae_vector_init(&ya, 0, DT_REAL, _state); ae_vector_init(&xb, 0, DT_REAL, _state); ae_vector_init(&yb, 0, DT_REAL, _state); waserrors = ae_false; eps = 0.001; /* * 1-sample test */ n = 8; ae_vector_set_length(&x, 8, _state); x.ptr.p_double[0] = -3.0; x.ptr.p_double[1] = -1.5; x.ptr.p_double[2] = -1.0; x.ptr.p_double[3] = -0.5; x.ptr.p_double[4] = 0.5; x.ptr.p_double[5] = 1.0; x.ptr.p_double[6] = 1.5; x.ptr.p_double[7] = 3.0; studentttest1(&x, n, 0.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-1.00000, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.50000, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.50000, _state),eps); studentttest1(&x, n, 1.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.17816, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.08908, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.91092, _state),eps); studentttest1(&x, n, -1.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.17816, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.91092, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.08908, _state),eps); x.ptr.p_double[0] = 1.1; x.ptr.p_double[1] = 1.1; x.ptr.p_double[2] = 1.1; x.ptr.p_double[3] = 1.1; x.ptr.p_double[4] = 1.1; x.ptr.p_double[5] = 1.1; x.ptr.p_double[6] = 1.1; x.ptr.p_double[7] = 1.1; studentttest1(&x, n, 1.1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest1(&x, n, 0.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(0)); x.ptr.p_double[7] = 1.1; studentttest1(&x, 1, 1.1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest1(&x, 1, 0.0, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(0)); /* * 2-sample pooled (equal variance) test */ n = 8; ae_vector_set_length(&x, 8, _state); ae_vector_set_length(&y, 8, _state); x.ptr.p_double[0] = -3.0; x.ptr.p_double[1] = -1.5; x.ptr.p_double[2] = -1.0; x.ptr.p_double[3] = -0.5; x.ptr.p_double[4] = 0.5; x.ptr.p_double[5] = 1.0; x.ptr.p_double[6] = 1.5; x.ptr.p_double[7] = 3.0; y.ptr.p_double[0] = -2.0; y.ptr.p_double[1] = -0.5; y.ptr.p_double[2] = 0.0; y.ptr.p_double[3] = 0.5; y.ptr.p_double[4] = 1.5; y.ptr.p_double[5] = 2.0; y.ptr.p_double[6] = 2.5; y.ptr.p_double[7] = 4.0; studentttest2(&x, n, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.30780, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.15390, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.84610, _state),eps); studentttest2(&x, n, &y, n-1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.53853, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.26927, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.73074, _state),eps); studentttest2(&x, n-1, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.13829, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.06915, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.93086, _state),eps); x.ptr.p_double[0] = -1.0; x.ptr.p_double[1] = -1.0; x.ptr.p_double[2] = -1.0; x.ptr.p_double[3] = -1.0; x.ptr.p_double[4] = -1.0; x.ptr.p_double[5] = -1.0; x.ptr.p_double[6] = -1.0; x.ptr.p_double[7] = -1.0; y.ptr.p_double[0] = 1.0; y.ptr.p_double[1] = 1.0; y.ptr.p_double[2] = 1.0; y.ptr.p_double[3] = 1.0; y.ptr.p_double[4] = 1.0; y.ptr.p_double[5] = 1.0; y.ptr.p_double[6] = 1.0; y.ptr.p_double[7] = 1.0; studentttest2(&x, n, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n, &y, n-1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n, &y, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n-1, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, 1, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, 1, &y, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&y, 1, &x, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(0)); x.ptr.p_double[0] = 1.1; x.ptr.p_double[1] = 1.1; x.ptr.p_double[2] = 1.1; x.ptr.p_double[3] = 1.1; x.ptr.p_double[4] = 1.1; x.ptr.p_double[5] = 1.1; x.ptr.p_double[6] = 1.1; x.ptr.p_double[7] = 1.1; y.ptr.p_double[0] = 1.1; y.ptr.p_double[1] = 1.1; y.ptr.p_double[2] = 1.1; y.ptr.p_double[3] = 1.1; y.ptr.p_double[4] = 1.1; y.ptr.p_double[5] = 1.1; y.ptr.p_double[6] = 1.1; y.ptr.p_double[7] = 1.1; studentttest2(&x, n, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n, &y, n-1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n, &y, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, n-1, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, 1, &y, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); studentttest2(&x, 1, &y, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); /* * 2-sample unpooled (unequal variance) test: * * test on two non-constant samples * * tests on different combinations of non-constant and constant samples */ n = 8; ae_vector_set_length(&xa, 8, _state); ae_vector_set_length(&ya, 8, _state); ae_vector_set_length(&xb, 8, _state); ae_vector_set_length(&yb, 8, _state); xa.ptr.p_double[0] = -3.0; xa.ptr.p_double[1] = -1.5; xa.ptr.p_double[2] = -1.0; xa.ptr.p_double[3] = -0.5; xa.ptr.p_double[4] = 0.5; xa.ptr.p_double[5] = 1.0; xa.ptr.p_double[6] = 1.5; xa.ptr.p_double[7] = 3.0; ya.ptr.p_double[0] = -1.0; ya.ptr.p_double[1] = -0.5; ya.ptr.p_double[2] = 0.0; ya.ptr.p_double[3] = 0.5; ya.ptr.p_double[4] = 1.5; ya.ptr.p_double[5] = 2.0; ya.ptr.p_double[6] = 2.5; ya.ptr.p_double[7] = 3.0; xb.ptr.p_double[0] = -1.1; xb.ptr.p_double[1] = -1.1; xb.ptr.p_double[2] = -1.1; xb.ptr.p_double[3] = -1.1; xb.ptr.p_double[4] = -1.1; xb.ptr.p_double[5] = -1.1; xb.ptr.p_double[6] = -1.1; xb.ptr.p_double[7] = -1.1; yb.ptr.p_double[0] = 1.1; yb.ptr.p_double[1] = 1.1; yb.ptr.p_double[2] = 1.1; yb.ptr.p_double[3] = 1.1; yb.ptr.p_double[4] = 1.1; yb.ptr.p_double[5] = 1.1; yb.ptr.p_double[6] = 1.1; yb.ptr.p_double[7] = 1.1; unequalvariancettest(&xa, n, &ya, n, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-0.25791, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-0.12896, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-0.87105, _state),eps); unequalvariancettest(&xa, n, &yb, n, &tailb, &taill, &tailr, _state); studentttest1(&xa, n, 1.1, &tailb1, &taill1, &tailr1, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-tailb1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-taill1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-tailr1, _state),eps); unequalvariancettest(&xa, n, &yb, 1, &tailb, &taill, &tailr, _state); studentttest1(&xa, n, 1.1, &tailb1, &taill1, &tailr1, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-tailb1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-taill1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-tailr1, _state),eps); unequalvariancettest(&xb, n, &ya, n, &tailb, &taill, &tailr, _state); studentttest1(&ya, n, -1.1, &tailb1, &taill1, &tailr1, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-tailb1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-tailr1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-taill1, _state),eps); unequalvariancettest(&xb, 1, &ya, n, &tailb, &taill, &tailr, _state); studentttest1(&ya, n, -1.1, &tailb1, &taill1, &tailr1, _state); waserrors = waserrors||ae_fp_greater(ae_fabs(tailb-tailb1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(taill-tailr1, _state),eps); waserrors = waserrors||ae_fp_greater(ae_fabs(tailr-taill1, _state),eps); unequalvariancettest(&xb, 1, &yb, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(0)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); unequalvariancettest(&yb, 1, &xb, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(0)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(0)); unequalvariancettest(&xb, 1, &xb, 1, &tailb, &taill, &tailr, _state); waserrors = waserrors||ae_fp_neq(tailb,(double)(1)); waserrors = waserrors||ae_fp_neq(taill,(double)(1)); waserrors = waserrors||ae_fp_neq(tailr,(double)(1)); /* * */ if( !silent ) { if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; ae_frame_leave(_state); return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_teststudentttests(ae_bool silent, ae_state *_state) { return teststudentttests(silent, _state); } static ae_bool testalglibbasicsunit_testcomplexarithmetics(ae_bool silent, ae_state *_state); static ae_bool testalglibbasicsunit_testieeespecial(ae_bool silent, ae_state *_state); static ae_bool testalglibbasicsunit_testswapfunctions(ae_bool silent, ae_state *_state); static ae_bool testalglibbasicsunit_teststandardfunctions(ae_bool silent, ae_state *_state); static ae_bool testalglibbasicsunit_testserializationfunctions(ae_bool silent, ae_state *_state); static void testalglibbasicsunit_createpoolandrecords(poolrec2* seedrec2, poolrec2* seedrec2copy, ae_shared_pool* pool, ae_state *_state); static ae_bool testalglibbasicsunit_sharedpoolerrors(ae_state *_state); static ae_bool testalglibbasicsunit_testsharedpool(ae_bool silent, ae_state *_state); static void testalglibbasicsunit_testsort0func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_state *_state); static ae_bool testalglibbasicsunit_performtestsort0(ae_state *_state); static void testalglibbasicsunit_testsort1func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_bool usesmp, ae_state *_state); static ae_bool testalglibbasicsunit_performtestsort1(ae_state *_state); static void testalglibbasicsunit_testsort2func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_state *_state); static ae_bool testalglibbasicsunit_performtestsort2(ae_state *_state); static ae_bool testalglibbasicsunit_performtestpoolsum(ae_state *_state); static void testalglibbasicsunit_parallelpoolsum(ae_shared_pool* sumpool, ae_int_t ind0, ae_int_t ind1, ae_state *_state); static void testalglibbasicsunit_mergesortedarrays(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx1, ae_int_t idx2, ae_state *_state); static ae_bool testalglibbasicsunit_testsmp(ae_bool silent, ae_state *_state); void rec4serializationalloc(ae_serializer* s, rec4serialization* v, ae_state *_state) { ae_int_t i; /* * boolean fields */ ae_serializer_alloc_entry(s); for(i=0; i<=v->b.cnt-1; i++) { ae_serializer_alloc_entry(s); } /* * integer fields */ ae_serializer_alloc_entry(s); for(i=0; i<=v->i.cnt-1; i++) { ae_serializer_alloc_entry(s); } /* * real fields */ ae_serializer_alloc_entry(s); for(i=0; i<=v->r.cnt-1; i++) { ae_serializer_alloc_entry(s); } } void rec4serializationserialize(ae_serializer* s, rec4serialization* v, ae_state *_state) { ae_int_t i; /* * boolean fields */ ae_serializer_serialize_int(s, v->b.cnt, _state); for(i=0; i<=v->b.cnt-1; i++) { ae_serializer_serialize_bool(s, v->b.ptr.p_bool[i], _state); } /* * integer fields */ ae_serializer_serialize_int(s, v->i.cnt, _state); for(i=0; i<=v->i.cnt-1; i++) { ae_serializer_serialize_int(s, v->i.ptr.p_int[i], _state); } /* * real fields */ ae_serializer_serialize_int(s, v->r.cnt, _state); for(i=0; i<=v->r.cnt-1; i++) { ae_serializer_serialize_double(s, v->r.ptr.p_double[i], _state); } } void rec4serializationunserialize(ae_serializer* s, rec4serialization* v, ae_state *_state) { ae_int_t i; ae_int_t k; ae_bool bv; ae_int_t iv; double rv; _rec4serialization_clear(v); /* * boolean fields */ ae_serializer_unserialize_int(s, &k, _state); if( k>0 ) { ae_vector_set_length(&v->b, k, _state); for(i=0; i<=k-1; i++) { ae_serializer_unserialize_bool(s, &bv, _state); v->b.ptr.p_bool[i] = bv; } } /* * integer fields */ ae_serializer_unserialize_int(s, &k, _state); if( k>0 ) { ae_vector_set_length(&v->i, k, _state); for(i=0; i<=k-1; i++) { ae_serializer_unserialize_int(s, &iv, _state); v->i.ptr.p_int[i] = iv; } } /* * real fields */ ae_serializer_unserialize_int(s, &k, _state); if( k>0 ) { ae_vector_set_length(&v->r, k, _state); for(i=0; i<=k-1; i++) { ae_serializer_unserialize_double(s, &rv, _state); v->r.ptr.p_double[i] = rv; } } } ae_bool testalglibbasics(ae_bool silent, ae_state *_state) { ae_bool result; result = ae_true; result = result&&testalglibbasicsunit_testcomplexarithmetics(silent, _state); result = result&&testalglibbasicsunit_testieeespecial(silent, _state); result = result&&testalglibbasicsunit_testswapfunctions(silent, _state); result = result&&testalglibbasicsunit_teststandardfunctions(silent, _state); result = result&&testalglibbasicsunit_testserializationfunctions(silent, _state); result = result&&testalglibbasicsunit_testsharedpool(silent, _state); result = result&&testalglibbasicsunit_testsmp(silent, _state); if( !silent ) { printf("\n\n"); } return result; } /************************************************************************* Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. *************************************************************************/ ae_bool _pexec_testalglibbasics(ae_bool silent, ae_state *_state) { return testalglibbasics(silent, _state); } /************************************************************************* Complex arithmetics test *************************************************************************/ static ae_bool testalglibbasicsunit_testcomplexarithmetics(ae_bool silent, ae_state *_state) { ae_bool absc; ae_bool addcc; ae_bool addcr; ae_bool addrc; ae_bool subcc; ae_bool subcr; ae_bool subrc; ae_bool mulcc; ae_bool mulcr; ae_bool mulrc; ae_bool divcc; ae_bool divcr; ae_bool divrc; ae_complex ca; ae_complex cb; ae_complex res; double ra; double rb; double threshold; ae_int_t pass; ae_int_t passcount; ae_bool result; threshold = 100*ae_machineepsilon; passcount = 1000; result = ae_true; absc = ae_true; addcc = ae_true; addcr = ae_true; addrc = ae_true; subcc = ae_true; subcr = ae_true; subrc = ae_true; mulcc = ae_true; mulcr = ae_true; mulrc = ae_true; divcc = ae_true; divcr = ae_true; divrc = ae_true; for(pass=1; pass<=passcount; pass++) { /* * Test AbsC */ ca.x = 2*ae_randomreal(_state)-1; ca.y = 2*ae_randomreal(_state)-1; ra = ae_c_abs(ca, _state); absc = absc&&ae_fp_less(ae_fabs(ra-ae_sqrt(ae_sqr(ca.x, _state)+ae_sqr(ca.y, _state), _state), _state),threshold); /* * test Add */ ca.x = 2*ae_randomreal(_state)-1; ca.y = 2*ae_randomreal(_state)-1; cb.x = 2*ae_randomreal(_state)-1; cb.y = 2*ae_randomreal(_state)-1; ra = 2*ae_randomreal(_state)-1; rb = 2*ae_randomreal(_state)-1; res = ae_c_add(ca,cb); addcc = (addcc&&ae_fp_less(ae_fabs(res.x-ca.x-cb.x, _state),threshold))&&ae_fp_less(ae_fabs(res.y-ca.y-cb.y, _state),threshold); res = ae_c_add_d(ca,rb); addcr = (addcr&&ae_fp_less(ae_fabs(res.x-ca.x-rb, _state),threshold))&&ae_fp_less(ae_fabs(res.y-ca.y, _state),threshold); res = ae_c_add_d(cb,ra); addrc = (addrc&&ae_fp_less(ae_fabs(res.x-ra-cb.x, _state),threshold))&&ae_fp_less(ae_fabs(res.y-cb.y, _state),threshold); /* * test Sub */ ca.x = 2*ae_randomreal(_state)-1; ca.y = 2*ae_randomreal(_state)-1; cb.x = 2*ae_randomreal(_state)-1; cb.y = 2*ae_randomreal(_state)-1; ra = 2*ae_randomreal(_state)-1; rb = 2*ae_randomreal(_state)-1; res = ae_c_sub(ca,cb); subcc = (subcc&&ae_fp_less(ae_fabs(res.x-(ca.x-cb.x), _state),threshold))&&ae_fp_less(ae_fabs(res.y-(ca.y-cb.y), _state),threshold); res = ae_c_sub_d(ca,rb); subcr = (subcr&&ae_fp_less(ae_fabs(res.x-(ca.x-rb), _state),threshold))&&ae_fp_less(ae_fabs(res.y-ca.y, _state),threshold); res = ae_c_d_sub(ra,cb); subrc = (subrc&&ae_fp_less(ae_fabs(res.x-(ra-cb.x), _state),threshold))&&ae_fp_less(ae_fabs(res.y+cb.y, _state),threshold); /* * test Mul */ ca.x = 2*ae_randomreal(_state)-1; ca.y = 2*ae_randomreal(_state)-1; cb.x = 2*ae_randomreal(_state)-1; cb.y = 2*ae_randomreal(_state)-1; ra = 2*ae_randomreal(_state)-1; rb = 2*ae_randomreal(_state)-1; res = ae_c_mul(ca,cb); mulcc = (mulcc&&ae_fp_less(ae_fabs(res.x-(ca.x*cb.x-ca.y*cb.y), _state),threshold))&&ae_fp_less(ae_fabs(res.y-(ca.x*cb.y+ca.y*cb.x), _state),threshold); res = ae_c_mul_d(ca,rb); mulcr = (mulcr&&ae_fp_less(ae_fabs(res.x-ca.x*rb, _state),threshold))&&ae_fp_less(ae_fabs(res.y-ca.y*rb, _state),threshold); res = ae_c_mul_d(cb,ra); mulrc = (mulrc&&ae_fp_less(ae_fabs(res.x-ra*cb.x, _state),threshold))&&ae_fp_less(ae_fabs(res.y-ra*cb.y, _state),threshold); /* * test Div */ ca.x = 2*ae_randomreal(_state)-1; ca.y = 2*ae_randomreal(_state)-1; do { cb.x = 2*ae_randomreal(_state)-1; cb.y = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_c_abs(cb, _state),0.5)); ra = 2*ae_randomreal(_state)-1; do { rb = 2*ae_randomreal(_state)-1; } while(ae_fp_less_eq(ae_fabs(rb, _state),0.5)); res = ae_c_div(ca,cb); divcc = (divcc&&ae_fp_less(ae_fabs(ae_c_mul(res,cb).x-ca.x, _state),threshold))&&ae_fp_less(ae_fabs(ae_c_mul(res,cb).y-ca.y, _state),threshold); res = ae_c_div_d(ca,rb); divcr = (divcr&&ae_fp_less(ae_fabs(res.x-ca.x/rb, _state),threshold))&&ae_fp_less(ae_fabs(res.y-ca.y/rb, _state),threshold); res = ae_c_d_div(ra,cb); divrc = (divrc&&ae_fp_less(ae_fabs(ae_c_mul(res,cb).x-ra, _state),threshold))&&ae_fp_less(ae_fabs(ae_c_mul(res,cb).y, _state),threshold); } /* * summary */ result = result&&absc; result = result&&addcc; result = result&&addcr; result = result&&addrc; result = result&&subcc; result = result&&subcr; result = result&&subrc; result = result&&mulcc; result = result&&mulcr; result = result&&mulrc; result = result&&divcc; result = result&&divcr; result = result&&divrc; if( !silent ) { if( result ) { printf("COMPLEX ARITHMETICS: OK\n"); } else { printf("COMPLEX ARITHMETICS: FAILED\n"); printf("* AddCC - - - - - - - - - - - - - - - - "); if( addcc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* AddCR - - - - - - - - - - - - - - - - "); if( addcr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* AddRC - - - - - - - - - - - - - - - - "); if( addrc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* SubCC - - - - - - - - - - - - - - - - "); if( subcc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* SubCR - - - - - - - - - - - - - - - - "); if( subcr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* SubRC - - - - - - - - - - - - - - - - "); if( subrc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* MulCC - - - - - - - - - - - - - - - - "); if( mulcc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* MulCR - - - - - - - - - - - - - - - - "); if( mulcr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* MulRC - - - - - - - - - - - - - - - - "); if( mulrc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* DivCC - - - - - - - - - - - - - - - - "); if( divcc ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* DivCR - - - - - - - - - - - - - - - - "); if( divcr ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* DivRC - - - - - - - - - - - - - - - - "); if( divrc ) { printf("OK\n"); } else { printf("FAILED\n"); } } } return result; } /************************************************************************* Tests for IEEE special quantities *************************************************************************/ static ae_bool testalglibbasicsunit_testieeespecial(ae_bool silent, ae_state *_state) { ae_bool oknan; ae_bool okinf; ae_bool okother; double v1; double v2; ae_bool result; result = ae_true; oknan = ae_true; okinf = ae_true; okother = ae_true; /* * Test classification functions */ okother = okother&&!ae_isinf(_state->v_nan, _state); okother = okother&&ae_isinf(_state->v_posinf, _state); okother = okother&&!ae_isinf(ae_maxrealnumber, _state); okother = okother&&!ae_isinf(1.0, _state); okother = okother&&!ae_isinf(ae_minrealnumber, _state); okother = okother&&!ae_isinf(0.0, _state); okother = okother&&!ae_isinf(-ae_minrealnumber, _state); okother = okother&&!ae_isinf(-1.0, _state); okother = okother&&!ae_isinf(-ae_maxrealnumber, _state); okother = okother&&ae_isinf(_state->v_neginf, _state); okother = okother&&!ae_isposinf(_state->v_nan, _state); okother = okother&&ae_isposinf(_state->v_posinf, _state); okother = okother&&!ae_isposinf(ae_maxrealnumber, _state); okother = okother&&!ae_isposinf(1.0, _state); okother = okother&&!ae_isposinf(ae_minrealnumber, _state); okother = okother&&!ae_isposinf(0.0, _state); okother = okother&&!ae_isposinf(-ae_minrealnumber, _state); okother = okother&&!ae_isposinf(-1.0, _state); okother = okother&&!ae_isposinf(-ae_maxrealnumber, _state); okother = okother&&!ae_isposinf(_state->v_neginf, _state); okother = okother&&!ae_isneginf(_state->v_nan, _state); okother = okother&&!ae_isneginf(_state->v_posinf, _state); okother = okother&&!ae_isneginf(ae_maxrealnumber, _state); okother = okother&&!ae_isneginf(1.0, _state); okother = okother&&!ae_isneginf(ae_minrealnumber, _state); okother = okother&&!ae_isneginf(0.0, _state); okother = okother&&!ae_isneginf(-ae_minrealnumber, _state); okother = okother&&!ae_isneginf(-1.0, _state); okother = okother&&!ae_isneginf(-ae_maxrealnumber, _state); okother = okother&&ae_isneginf(_state->v_neginf, _state); okother = okother&&ae_isnan(_state->v_nan, _state); okother = okother&&!ae_isnan(_state->v_posinf, _state); okother = okother&&!ae_isnan(ae_maxrealnumber, _state); okother = okother&&!ae_isnan(1.0, _state); okother = okother&&!ae_isnan(ae_minrealnumber, _state); okother = okother&&!ae_isnan(0.0, _state); okother = okother&&!ae_isnan(-ae_minrealnumber, _state); okother = okother&&!ae_isnan(-1.0, _state); okother = okother&&!ae_isnan(-ae_maxrealnumber, _state); okother = okother&&!ae_isnan(_state->v_neginf, _state); okother = okother&&!ae_isfinite(_state->v_nan, _state); okother = okother&&!ae_isfinite(_state->v_posinf, _state); okother = okother&&ae_isfinite(ae_maxrealnumber, _state); okother = okother&&ae_isfinite(1.0, _state); okother = okother&&ae_isfinite(ae_minrealnumber, _state); okother = okother&&ae_isfinite(0.0, _state); okother = okother&&ae_isfinite(-ae_minrealnumber, _state); okother = okother&&ae_isfinite(-1.0, _state); okother = okother&&ae_isfinite(-ae_maxrealnumber, _state); okother = okother&&!ae_isfinite(_state->v_neginf, _state); /* * Test NAN */ v1 = _state->v_nan; v2 = _state->v_nan; oknan = oknan&&ae_isnan(v1, _state); oknan = oknan&&ae_fp_neq(v1,v2); oknan = oknan&&!ae_fp_eq(v1,v2); /* * Test INF: * * basic properties * * comparisons involving PosINF on one of the sides * * comparisons involving NegINF on one of the sides */ v1 = _state->v_posinf; v2 = _state->v_neginf; okinf = okinf&&ae_isinf(_state->v_posinf, _state); okinf = okinf&&ae_isinf(v1, _state); okinf = okinf&&ae_isinf(_state->v_neginf, _state); okinf = okinf&&ae_isinf(v2, _state); okinf = okinf&&ae_isposinf(_state->v_posinf, _state); okinf = okinf&&ae_isposinf(v1, _state); okinf = okinf&&!ae_isposinf(_state->v_neginf, _state); okinf = okinf&&!ae_isposinf(v2, _state); okinf = okinf&&!ae_isneginf(_state->v_posinf, _state); okinf = okinf&&!ae_isneginf(v1, _state); okinf = okinf&&ae_isneginf(_state->v_neginf, _state); okinf = okinf&&ae_isneginf(v2, _state); okinf = okinf&&ae_fp_eq(_state->v_posinf,_state->v_posinf); okinf = okinf&&ae_fp_eq(_state->v_posinf,v1); okinf = okinf&&!ae_fp_eq(_state->v_posinf,_state->v_neginf); okinf = okinf&&!ae_fp_eq(_state->v_posinf,v2); okinf = okinf&&!ae_fp_eq(_state->v_posinf,(double)(0)); okinf = okinf&&!ae_fp_eq(_state->v_posinf,1.2); okinf = okinf&&!ae_fp_eq(_state->v_posinf,-1.2); okinf = okinf&&ae_fp_eq(v1,_state->v_posinf); okinf = okinf&&!ae_fp_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_eq(v2,_state->v_posinf); okinf = okinf&&!ae_fp_eq((double)(0),_state->v_posinf); okinf = okinf&&!ae_fp_eq(1.2,_state->v_posinf); okinf = okinf&&!ae_fp_eq(-1.2,_state->v_posinf); okinf = okinf&&!ae_fp_neq(_state->v_posinf,_state->v_posinf); okinf = okinf&&!ae_fp_neq(_state->v_posinf,v1); okinf = okinf&&ae_fp_neq(_state->v_posinf,_state->v_neginf); okinf = okinf&&ae_fp_neq(_state->v_posinf,v2); okinf = okinf&&ae_fp_neq(_state->v_posinf,(double)(0)); okinf = okinf&&ae_fp_neq(_state->v_posinf,1.2); okinf = okinf&&ae_fp_neq(_state->v_posinf,-1.2); okinf = okinf&&!ae_fp_neq(v1,_state->v_posinf); okinf = okinf&&ae_fp_neq(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_neq(v2,_state->v_posinf); okinf = okinf&&ae_fp_neq((double)(0),_state->v_posinf); okinf = okinf&&ae_fp_neq(1.2,_state->v_posinf); okinf = okinf&&ae_fp_neq(-1.2,_state->v_posinf); okinf = okinf&&!ae_fp_less(_state->v_posinf,_state->v_posinf); okinf = okinf&&!ae_fp_less(_state->v_posinf,v1); okinf = okinf&&!ae_fp_less(_state->v_posinf,_state->v_neginf); okinf = okinf&&!ae_fp_less(_state->v_posinf,v2); okinf = okinf&&!ae_fp_less(_state->v_posinf,(double)(0)); okinf = okinf&&!ae_fp_less(_state->v_posinf,1.2); okinf = okinf&&!ae_fp_less(_state->v_posinf,-1.2); okinf = okinf&&!ae_fp_less(v1,_state->v_posinf); okinf = okinf&&ae_fp_less(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_less(v2,_state->v_posinf); okinf = okinf&&ae_fp_less((double)(0),_state->v_posinf); okinf = okinf&&ae_fp_less(1.2,_state->v_posinf); okinf = okinf&&ae_fp_less(-1.2,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(_state->v_posinf,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(_state->v_posinf,v1); okinf = okinf&&!ae_fp_less_eq(_state->v_posinf,_state->v_neginf); okinf = okinf&&!ae_fp_less_eq(_state->v_posinf,v2); okinf = okinf&&!ae_fp_less_eq(_state->v_posinf,(double)(0)); okinf = okinf&&!ae_fp_less_eq(_state->v_posinf,1.2); okinf = okinf&&!ae_fp_less_eq(_state->v_posinf,-1.2); okinf = okinf&&ae_fp_less_eq(v1,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(v2,_state->v_posinf); okinf = okinf&&ae_fp_less_eq((double)(0),_state->v_posinf); okinf = okinf&&ae_fp_less_eq(1.2,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(-1.2,_state->v_posinf); okinf = okinf&&!ae_fp_greater(_state->v_posinf,_state->v_posinf); okinf = okinf&&!ae_fp_greater(_state->v_posinf,v1); okinf = okinf&&ae_fp_greater(_state->v_posinf,_state->v_neginf); okinf = okinf&&ae_fp_greater(_state->v_posinf,v2); okinf = okinf&&ae_fp_greater(_state->v_posinf,(double)(0)); okinf = okinf&&ae_fp_greater(_state->v_posinf,1.2); okinf = okinf&&ae_fp_greater(_state->v_posinf,-1.2); okinf = okinf&&!ae_fp_greater(v1,_state->v_posinf); okinf = okinf&&!ae_fp_greater(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_greater(v2,_state->v_posinf); okinf = okinf&&!ae_fp_greater((double)(0),_state->v_posinf); okinf = okinf&&!ae_fp_greater(1.2,_state->v_posinf); okinf = okinf&&!ae_fp_greater(-1.2,_state->v_posinf); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,_state->v_posinf); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,v1); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,v2); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,(double)(0)); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,1.2); okinf = okinf&&ae_fp_greater_eq(_state->v_posinf,-1.2); okinf = okinf&&ae_fp_greater_eq(v1,_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq(v2,_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq((double)(0),_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq(1.2,_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq(-1.2,_state->v_posinf); okinf = okinf&&!ae_fp_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_eq(_state->v_neginf,v1); okinf = okinf&&ae_fp_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_eq(_state->v_neginf,v2); okinf = okinf&&!ae_fp_eq(_state->v_neginf,(double)(0)); okinf = okinf&&!ae_fp_eq(_state->v_neginf,1.2); okinf = okinf&&!ae_fp_eq(_state->v_neginf,-1.2); okinf = okinf&&!ae_fp_eq(v1,_state->v_neginf); okinf = okinf&&ae_fp_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_eq(v2,_state->v_neginf); okinf = okinf&&!ae_fp_eq((double)(0),_state->v_neginf); okinf = okinf&&!ae_fp_eq(1.2,_state->v_neginf); okinf = okinf&&!ae_fp_eq(-1.2,_state->v_neginf); okinf = okinf&&ae_fp_neq(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_neq(_state->v_neginf,v1); okinf = okinf&&!ae_fp_neq(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_neq(_state->v_neginf,v2); okinf = okinf&&ae_fp_neq(_state->v_neginf,(double)(0)); okinf = okinf&&ae_fp_neq(_state->v_neginf,1.2); okinf = okinf&&ae_fp_neq(_state->v_neginf,-1.2); okinf = okinf&&ae_fp_neq(v1,_state->v_neginf); okinf = okinf&&!ae_fp_neq(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_neq(v2,_state->v_neginf); okinf = okinf&&ae_fp_neq((double)(0),_state->v_neginf); okinf = okinf&&ae_fp_neq(1.2,_state->v_neginf); okinf = okinf&&ae_fp_neq(-1.2,_state->v_neginf); okinf = okinf&&ae_fp_less(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_less(_state->v_neginf,v1); okinf = okinf&&!ae_fp_less(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_less(_state->v_neginf,v2); okinf = okinf&&ae_fp_less(_state->v_neginf,(double)(0)); okinf = okinf&&ae_fp_less(_state->v_neginf,1.2); okinf = okinf&&ae_fp_less(_state->v_neginf,-1.2); okinf = okinf&&!ae_fp_less(v1,_state->v_neginf); okinf = okinf&&!ae_fp_less(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_less(v2,_state->v_neginf); okinf = okinf&&!ae_fp_less((double)(0),_state->v_neginf); okinf = okinf&&!ae_fp_less(1.2,_state->v_neginf); okinf = okinf&&!ae_fp_less(-1.2,_state->v_neginf); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,v1); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,v2); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,(double)(0)); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,1.2); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,-1.2); okinf = okinf&&!ae_fp_less_eq(v1,_state->v_neginf); okinf = okinf&&ae_fp_less_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_less_eq(v2,_state->v_neginf); okinf = okinf&&!ae_fp_less_eq((double)(0),_state->v_neginf); okinf = okinf&&!ae_fp_less_eq(1.2,_state->v_neginf); okinf = okinf&&!ae_fp_less_eq(-1.2,_state->v_neginf); okinf = okinf&&!ae_fp_greater(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_greater(_state->v_neginf,v1); okinf = okinf&&!ae_fp_greater(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_greater(_state->v_neginf,v2); okinf = okinf&&!ae_fp_greater(_state->v_neginf,(double)(0)); okinf = okinf&&!ae_fp_greater(_state->v_neginf,1.2); okinf = okinf&&!ae_fp_greater(_state->v_neginf,-1.2); okinf = okinf&&ae_fp_greater(v1,_state->v_neginf); okinf = okinf&&!ae_fp_greater(_state->v_neginf,_state->v_neginf); okinf = okinf&&!ae_fp_greater(v2,_state->v_neginf); okinf = okinf&&ae_fp_greater((double)(0),_state->v_neginf); okinf = okinf&&ae_fp_greater(1.2,_state->v_neginf); okinf = okinf&&ae_fp_greater(-1.2,_state->v_neginf); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,_state->v_posinf); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,v1); okinf = okinf&&ae_fp_greater_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(_state->v_neginf,v2); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,(double)(0)); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,1.2); okinf = okinf&&!ae_fp_greater_eq(_state->v_neginf,-1.2); okinf = okinf&&ae_fp_greater_eq(v1,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(_state->v_neginf,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(v2,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq((double)(0),_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(1.2,_state->v_neginf); okinf = okinf&&ae_fp_greater_eq(-1.2,_state->v_neginf); /* * summary */ result = result&&oknan; result = result&&okinf; result = result&&okother; if( !silent ) { if( result ) { printf("IEEE SPECIAL VALUES: OK\n"); } else { printf("IEEE SPECIAL VALUES: FAILED\n"); printf("* NAN - - - - - - - - - - - - - - - - - "); if( oknan ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* INF - - - - - - - - - - - - - - - - - "); if( okinf ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* FUNCTIONS - - - - - - - - - - - - - - "); if( okother ) { printf("OK\n"); } else { printf("FAILED\n"); } } } return result; } /************************************************************************* Tests for swapping functions *************************************************************************/ static ae_bool testalglibbasicsunit_testswapfunctions(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool okb1; ae_bool okb2; ae_bool oki1; ae_bool oki2; ae_bool okr1; ae_bool okr2; ae_bool okc1; ae_bool okc2; ae_vector b11; ae_vector b12; ae_vector i11; ae_vector i12; ae_vector r11; ae_vector r12; ae_vector c11; ae_vector c12; ae_matrix b21; ae_matrix b22; ae_matrix i21; ae_matrix i22; ae_matrix r21; ae_matrix r22; ae_matrix c21; ae_matrix c22; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&b11, 0, DT_BOOL, _state); ae_vector_init(&b12, 0, DT_BOOL, _state); ae_vector_init(&i11, 0, DT_INT, _state); ae_vector_init(&i12, 0, DT_INT, _state); ae_vector_init(&r11, 0, DT_REAL, _state); ae_vector_init(&r12, 0, DT_REAL, _state); ae_vector_init(&c11, 0, DT_COMPLEX, _state); ae_vector_init(&c12, 0, DT_COMPLEX, _state); ae_matrix_init(&b21, 0, 0, DT_BOOL, _state); ae_matrix_init(&b22, 0, 0, DT_BOOL, _state); ae_matrix_init(&i21, 0, 0, DT_INT, _state); ae_matrix_init(&i22, 0, 0, DT_INT, _state); ae_matrix_init(&r21, 0, 0, DT_REAL, _state); ae_matrix_init(&r22, 0, 0, DT_REAL, _state); ae_matrix_init(&c21, 0, 0, DT_COMPLEX, _state); ae_matrix_init(&c22, 0, 0, DT_COMPLEX, _state); result = ae_true; okb1 = ae_true; okb2 = ae_true; oki1 = ae_true; oki2 = ae_true; okr1 = ae_true; okr2 = ae_true; okc1 = ae_true; okc2 = ae_true; /* * Test B1 swaps */ ae_vector_set_length(&b11, 1, _state); ae_vector_set_length(&b12, 2, _state); b11.ptr.p_bool[0] = ae_true; b12.ptr.p_bool[0] = ae_false; b12.ptr.p_bool[1] = ae_true; ae_swap_vectors(&b11, &b12); if( b11.cnt==2&&b12.cnt==1 ) { okb1 = okb1&&!b11.ptr.p_bool[0]; okb1 = okb1&&b11.ptr.p_bool[1]; okb1 = okb1&&b12.ptr.p_bool[0]; } else { okb1 = ae_false; } /* * Test I1 swaps */ ae_vector_set_length(&i11, 1, _state); ae_vector_set_length(&i12, 2, _state); i11.ptr.p_int[0] = 1; i12.ptr.p_int[0] = 2; i12.ptr.p_int[1] = 3; ae_swap_vectors(&i11, &i12); if( i11.cnt==2&&i12.cnt==1 ) { oki1 = oki1&&i11.ptr.p_int[0]==2; oki1 = oki1&&i11.ptr.p_int[1]==3; oki1 = oki1&&i12.ptr.p_int[0]==1; } else { oki1 = ae_false; } /* * Test R1 swaps */ ae_vector_set_length(&r11, 1, _state); ae_vector_set_length(&r12, 2, _state); r11.ptr.p_double[0] = 1.5; r12.ptr.p_double[0] = 2.5; r12.ptr.p_double[1] = 3.5; ae_swap_vectors(&r11, &r12); if( r11.cnt==2&&r12.cnt==1 ) { okr1 = okr1&&ae_fp_eq(r11.ptr.p_double[0],2.5); okr1 = okr1&&ae_fp_eq(r11.ptr.p_double[1],3.5); okr1 = okr1&&ae_fp_eq(r12.ptr.p_double[0],1.5); } else { okr1 = ae_false; } /* * Test C1 swaps */ ae_vector_set_length(&c11, 1, _state); ae_vector_set_length(&c12, 2, _state); c11.ptr.p_complex[0] = ae_complex_from_i(1); c12.ptr.p_complex[0] = ae_complex_from_i(2); c12.ptr.p_complex[1] = ae_complex_from_i(3); ae_swap_vectors(&c11, &c12); if( c11.cnt==2&&c12.cnt==1 ) { okc1 = okc1&&ae_c_eq_d(c11.ptr.p_complex[0],(double)(2)); okc1 = okc1&&ae_c_eq_d(c11.ptr.p_complex[1],(double)(3)); okc1 = okc1&&ae_c_eq_d(c12.ptr.p_complex[0],(double)(1)); } else { okc1 = ae_false; } /* * Test B2 swaps */ ae_matrix_set_length(&b21, 1, 2, _state); ae_matrix_set_length(&b22, 2, 1, _state); b21.ptr.pp_bool[0][0] = ae_true; b21.ptr.pp_bool[0][1] = ae_false; b22.ptr.pp_bool[0][0] = ae_false; b22.ptr.pp_bool[1][0] = ae_true; ae_swap_matrices(&b21, &b22); if( ((b21.rows==2&&b21.cols==1)&&b22.rows==1)&&b22.cols==2 ) { okb2 = okb2&&!b21.ptr.pp_bool[0][0]; okb2 = okb2&&b21.ptr.pp_bool[1][0]; okb2 = okb2&&b22.ptr.pp_bool[0][0]; okb2 = okb2&&!b22.ptr.pp_bool[0][1]; } else { okb2 = ae_false; } /* * Test I2 swaps */ ae_matrix_set_length(&i21, 1, 2, _state); ae_matrix_set_length(&i22, 2, 1, _state); i21.ptr.pp_int[0][0] = 1; i21.ptr.pp_int[0][1] = 2; i22.ptr.pp_int[0][0] = 3; i22.ptr.pp_int[1][0] = 4; ae_swap_matrices(&i21, &i22); if( ((i21.rows==2&&i21.cols==1)&&i22.rows==1)&&i22.cols==2 ) { oki2 = oki2&&i21.ptr.pp_int[0][0]==3; oki2 = oki2&&i21.ptr.pp_int[1][0]==4; oki2 = oki2&&i22.ptr.pp_int[0][0]==1; oki2 = oki2&&i22.ptr.pp_int[0][1]==2; } else { oki2 = ae_false; } /* * Test R2 swaps */ ae_matrix_set_length(&r21, 1, 2, _state); ae_matrix_set_length(&r22, 2, 1, _state); r21.ptr.pp_double[0][0] = (double)(1); r21.ptr.pp_double[0][1] = (double)(2); r22.ptr.pp_double[0][0] = (double)(3); r22.ptr.pp_double[1][0] = (double)(4); ae_swap_matrices(&r21, &r22); if( ((r21.rows==2&&r21.cols==1)&&r22.rows==1)&&r22.cols==2 ) { okr2 = okr2&&ae_fp_eq(r21.ptr.pp_double[0][0],(double)(3)); okr2 = okr2&&ae_fp_eq(r21.ptr.pp_double[1][0],(double)(4)); okr2 = okr2&&ae_fp_eq(r22.ptr.pp_double[0][0],(double)(1)); okr2 = okr2&&ae_fp_eq(r22.ptr.pp_double[0][1],(double)(2)); } else { okr2 = ae_false; } /* * Test C2 swaps */ ae_matrix_set_length(&c21, 1, 2, _state); ae_matrix_set_length(&c22, 2, 1, _state); c21.ptr.pp_complex[0][0] = ae_complex_from_i(1); c21.ptr.pp_complex[0][1] = ae_complex_from_i(2); c22.ptr.pp_complex[0][0] = ae_complex_from_i(3); c22.ptr.pp_complex[1][0] = ae_complex_from_i(4); ae_swap_matrices(&c21, &c22); if( ((c21.rows==2&&c21.cols==1)&&c22.rows==1)&&c22.cols==2 ) { okc2 = okc2&&ae_c_eq_d(c21.ptr.pp_complex[0][0],(double)(3)); okc2 = okc2&&ae_c_eq_d(c21.ptr.pp_complex[1][0],(double)(4)); okc2 = okc2&&ae_c_eq_d(c22.ptr.pp_complex[0][0],(double)(1)); okc2 = okc2&&ae_c_eq_d(c22.ptr.pp_complex[0][1],(double)(2)); } else { okc2 = ae_false; } /* * summary */ result = result&&okb1; result = result&&okb2; result = result&&oki1; result = result&&oki2; result = result&&okr1; result = result&&okr2; result = result&&okc1; result = result&&okc2; if( !silent ) { if( result ) { printf("SWAPPING FUNCTIONS: OK\n"); } else { printf("SWAPPING FUNCTIONS: FAILED\n"); } } ae_frame_leave(_state); return result; } /************************************************************************* Tests for standard functions *************************************************************************/ static ae_bool testalglibbasicsunit_teststandardfunctions(ae_bool silent, ae_state *_state) { ae_bool result; result = ae_true; /* * Test Sign() */ result = result&&ae_sign(1.2, _state)==1; result = result&&ae_sign((double)(0), _state)==0; result = result&&ae_sign(-1.2, _state)==-1; /* * summary */ if( !silent ) { if( result ) { printf("STANDARD FUNCTIONS: OK\n"); } else { printf("STANDARD FUNCTIONS: FAILED\n"); } } return result; } /************************************************************************* Tests for serualization functions *************************************************************************/ static ae_bool testalglibbasicsunit_testserializationfunctions(ae_bool silent, ae_state *_state) { ae_frame _frame_block; ae_bool okb; ae_bool oki; ae_bool okr; ae_int_t nb; ae_int_t ni; ae_int_t nr; ae_int_t i; rec4serialization r0; rec4serialization r1; ae_bool result; ae_frame_make(_state, &_frame_block); _rec4serialization_init(&r0, _state); _rec4serialization_init(&r1, _state); result = ae_true; okb = ae_true; oki = ae_true; okr = ae_true; for(nb=1; nb<=4; nb++) { for(ni=1; ni<=4; ni++) { for(nr=1; nr<=4; nr++) { ae_vector_set_length(&r0.b, nb, _state); for(i=0; i<=nb-1; i++) { r0.b.ptr.p_bool[i] = ae_randominteger(2, _state)!=0; } ae_vector_set_length(&r0.i, ni, _state); for(i=0; i<=ni-1; i++) { r0.i.ptr.p_int[i] = ae_randominteger(10, _state)-5; } ae_vector_set_length(&r0.r, nr, _state); for(i=0; i<=nr-1; i++) { r0.r.ptr.p_double[i] = 2*ae_randomreal(_state)-1; } { /* * This code passes data structure through serializers * (serializes it to string and loads back) */ ae_serializer _local_serializer; ae_int_t _local_ssize; ae_frame _local_frame_block; ae_dyn_block _local_dynamic_block; ae_frame_make(_state, &_local_frame_block); ae_serializer_init(&_local_serializer); ae_serializer_alloc_start(&_local_serializer); rec4serializationalloc(&_local_serializer, &r0, _state); _local_ssize = ae_serializer_get_alloc_size(&_local_serializer); ae_db_malloc(&_local_dynamic_block, _local_ssize+1, _state, ae_true); ae_serializer_sstart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rec4serializationserialize(&_local_serializer, &r0, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_serializer_init(&_local_serializer); ae_serializer_ustart_str(&_local_serializer, (char*)_local_dynamic_block.ptr); rec4serializationunserialize(&_local_serializer, &r1, _state); ae_serializer_stop(&_local_serializer); ae_serializer_clear(&_local_serializer); ae_frame_leave(_state); } if( (r0.b.cnt==r1.b.cnt&&r0.i.cnt==r1.i.cnt)&&r0.r.cnt==r1.r.cnt ) { for(i=0; i<=nb-1; i++) { okb = okb&&((r0.b.ptr.p_bool[i]&&r1.b.ptr.p_bool[i])||(!r0.b.ptr.p_bool[i]&&!r1.b.ptr.p_bool[i])); } for(i=0; i<=ni-1; i++) { oki = oki&&r0.i.ptr.p_int[i]==r1.i.ptr.p_int[i]; } for(i=0; i<=nr-1; i++) { okr = okr&&ae_fp_eq(r0.r.ptr.p_double[i],r1.r.ptr.p_double[i]); } } else { oki = ae_false; } } } } /* * summary */ result = result&&okb; result = result&&oki; result = result&&okr; if( !silent ) { if( result ) { printf("SERIALIZATION FUNCTIONS: OK\n"); } else { printf("SERIALIZATION FUNCTIONS: FAILED\n"); printf("* BOOLEAN - - - - - - - - - - - - - - - "); if( okb ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* INTEGER - - - - - - - - - - - - - - - "); if( oki ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* REAL - - - - - - - - - - - - - - - - "); if( okr ) { printf("OK\n"); } else { printf("FAILED\n"); } } } ae_frame_leave(_state); return result; } /************************************************************************* Tests for pool functions *************************************************************************/ static void testalglibbasicsunit_createpoolandrecords(poolrec2* seedrec2, poolrec2* seedrec2copy, ae_shared_pool* pool, ae_state *_state) { _poolrec2_clear(seedrec2); _poolrec2_clear(seedrec2copy); ae_shared_pool_clear(pool); seedrec2->bval = ae_fp_greater(ae_randomreal(_state),0.5); seedrec2->recval.bval = ae_fp_greater(ae_randomreal(_state),0.5); seedrec2->recval.ival = ae_randominteger(10, _state); seedrec2->recval.rval = ae_randomreal(_state); seedrec2->recval.cval.x = ae_randomreal(_state); seedrec2->recval.cval.y = ae_randomreal(_state); ae_vector_set_length(&seedrec2->recval.i1val, 3, _state); seedrec2->recval.i1val.ptr.p_int[0] = ae_randominteger(10, _state); seedrec2->recval.i1val.ptr.p_int[1] = ae_randominteger(10, _state); seedrec2->recval.i1val.ptr.p_int[2] = ae_randominteger(10, _state); seedrec2copy->bval = seedrec2->bval; seedrec2copy->recval.bval = seedrec2->recval.bval; seedrec2copy->recval.ival = seedrec2->recval.ival; seedrec2copy->recval.rval = seedrec2->recval.rval; seedrec2copy->recval.cval = seedrec2->recval.cval; ae_vector_set_length(&seedrec2copy->recval.i1val, 3, _state); seedrec2copy->recval.i1val.ptr.p_int[0] = seedrec2->recval.i1val.ptr.p_int[0]; seedrec2copy->recval.i1val.ptr.p_int[1] = seedrec2->recval.i1val.ptr.p_int[1]; seedrec2copy->recval.i1val.ptr.p_int[2] = seedrec2->recval.i1val.ptr.p_int[2]; ae_shared_pool_set_seed(pool, seedrec2, sizeof(*seedrec2), _poolrec2_init, _poolrec2_init_copy, _poolrec2_destroy, _state); } static ae_bool testalglibbasicsunit_sharedpoolerrors(ae_state *_state) { ae_frame _frame_block; poolrec1 seedrec1; poolrec2 seedrec2; poolrec2 seedrec2copy; ae_shared_pool pool; ae_shared_pool pool2; poolrec2 *prec2; ae_smart_ptr _prec2; poolrec2 *p0; ae_smart_ptr _p0; poolrec2 *p1; ae_smart_ptr _p1; poolrec2 *p2; ae_smart_ptr _p2; poolrec1 *q0; ae_smart_ptr _q0; poolrec1 *q1; ae_smart_ptr _q1; ae_shared_pool *ppool0; ae_smart_ptr _ppool0; ae_shared_pool *ppool1; ae_smart_ptr _ppool1; ae_int_t val100cnt; ae_int_t val101cnt; ae_int_t val102cnt; ae_int_t tmpval; ae_bool result; ae_frame_make(_state, &_frame_block); _poolrec1_init(&seedrec1, _state); _poolrec2_init(&seedrec2, _state); _poolrec2_init(&seedrec2copy, _state); ae_shared_pool_init(&pool, _state); ae_shared_pool_init(&pool2, _state); ae_smart_ptr_init(&_prec2, (void**)&prec2, _state); ae_smart_ptr_init(&_p0, (void**)&p0, _state); ae_smart_ptr_init(&_p1, (void**)&p1, _state); ae_smart_ptr_init(&_p2, (void**)&p2, _state); ae_smart_ptr_init(&_q0, (void**)&q0, _state); ae_smart_ptr_init(&_q1, (void**)&q1, _state); ae_smart_ptr_init(&_ppool0, (void**)&ppool0, _state); ae_smart_ptr_init(&_ppool1, (void**)&ppool1, _state); result = ae_true; /* * Test 1: test that: * a) smart pointer is null by default * b) "conventional local" is valid by default * b) unitinitialized shared pool is "not initialized" */ if( prec2!=NULL ) { ae_frame_leave(_state); return result; } if( !(&seedrec1!=NULL) ) { ae_frame_leave(_state); return result; } if( ae_shared_pool_is_initialized(&pool) ) { ae_frame_leave(_state); return result; } /* * Test 2: basic copying of complex structures * * check that pool is recognized as "initialized" * * change original seed record, * * retrieve value from pool, * * check that it is valid * * and it is unchanged. */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); if( !ae_shared_pool_is_initialized(&pool) ) { ae_frame_leave(_state); return result; } seedrec2.bval = !seedrec2.bval; seedrec2.recval.i1val.ptr.p_int[0] = seedrec2.recval.i1val.ptr.p_int[0]+1; ae_shared_pool_retrieve(&pool, &_prec2, _state); if( !(prec2!=NULL) ) { ae_frame_leave(_state); return result; } if( (seedrec2copy.bval&&!prec2->bval)||(prec2->bval&&!seedrec2copy.bval) ) { ae_frame_leave(_state); return result; } if( seedrec2copy.recval.i1val.ptr.p_int[0]!=prec2->recval.i1val.ptr.p_int[0] ) { ae_frame_leave(_state); return result; } /* * Test 3: unrecycled values are lost * * retrieve value from pool, * * change it, * * retrieve one more time, * * check that it is unchanged. */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_prec2, _state); prec2->recval.ival = prec2->recval.ival+1; ae_shared_pool_retrieve(&pool, &_prec2, _state); if( prec2->recval.ival!=seedrec2copy.recval.ival ) { ae_frame_leave(_state); return result; } /* * Test 4: recycled values are reused, PoolClearRecycled() removes recycled values * * retrieve value from pool, * * change it, * * recycle, * * check that recycled pointer is null * * retrieve one more time, * * check that modified value was returned, * * recycle, * * clear pool, * * retrieve one more time, * * check that unmodified value was returned, */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_prec2, _state); prec2->recval.ival = prec2->recval.ival+1; ae_shared_pool_recycle(&pool, &_prec2, _state); if( prec2!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_retrieve(&pool, &_prec2, _state); if( !(prec2!=NULL) ) { ae_frame_leave(_state); return result; } if( prec2->recval.ival!=seedrec2copy.recval.ival+1 ) { ae_frame_leave(_state); return result; } ae_shared_pool_recycle(&pool, &_prec2, _state); ae_shared_pool_clear_recycled(&pool, _state); ae_shared_pool_retrieve(&pool, &_prec2, _state); if( !(prec2!=NULL) ) { ae_frame_leave(_state); return result; } if( prec2->recval.ival!=seedrec2copy.recval.ival ) { ae_frame_leave(_state); return result; } /* * Test 5: basic enumeration * * retrieve 3 values from pool * * fill RecVal.iVal by 100, 101, 102 * * recycle values * * enumerate, check that each iVal occurs only once during enumeration * * repeat enumeration to make sure that it can be repeated */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_p0, _state); ae_shared_pool_retrieve(&pool, &_p1, _state); ae_shared_pool_retrieve(&pool, &_p2, _state); p0->recval.ival = 100; p1->recval.ival = 101; p2->recval.ival = 102; ae_shared_pool_recycle(&pool, &_p1, _state); ae_shared_pool_recycle(&pool, &_p2, _state); ae_shared_pool_recycle(&pool, &_p0, _state); val100cnt = 0; val101cnt = 0; val102cnt = 0; ae_shared_pool_first_recycled(&pool, &_prec2, _state); while(prec2!=NULL) { if( prec2->recval.ival==100 ) { val100cnt = val100cnt+1; } if( prec2->recval.ival==101 ) { val101cnt = val101cnt+1; } if( prec2->recval.ival==102 ) { val102cnt = val102cnt+1; } ae_shared_pool_next_recycled(&pool, &_prec2, _state); } if( (val100cnt!=1||val101cnt!=1)||val102cnt!=1 ) { ae_frame_leave(_state); return result; } val100cnt = 0; val101cnt = 0; val102cnt = 0; ae_shared_pool_first_recycled(&pool, &_prec2, _state); while(prec2!=NULL) { if( prec2->recval.ival==100 ) { val100cnt = val100cnt+1; } if( prec2->recval.ival==101 ) { val101cnt = val101cnt+1; } if( prec2->recval.ival==102 ) { val102cnt = val102cnt+1; } ae_shared_pool_next_recycled(&pool, &_prec2, _state); } if( (val100cnt!=1||val101cnt!=1)||val102cnt!=1 ) { ae_frame_leave(_state); return result; } /* * Test 6: pool itself can be pooled * * pool can be seeded with another pool * * smart pointers to pool are correctly handled * * pool correctly returns different references on "retrieve": * * we retrieve, modify and recycle back to PPool0 * * we retrieve from PPool1 - unmodified value is returned * * we retrievefrom PPool0 - modified value is returned */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_set_seed(&pool2, &pool, sizeof(pool), ae_shared_pool_init, ae_shared_pool_init_copy, ae_shared_pool_destroy, _state); if( ppool0!=NULL||ppool1!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_retrieve(&pool2, &_ppool0, _state); ae_shared_pool_retrieve(&pool2, &_ppool1, _state); if( !(ppool0!=NULL&&ppool1!=NULL) ) { ae_frame_leave(_state); return result; } ae_shared_pool_retrieve(ppool0, &_p0, _state); p0->recval.ival = p0->recval.ival+1; tmpval = p0->recval.ival; ae_shared_pool_recycle(ppool0, &_p0, _state); ae_shared_pool_retrieve(ppool1, &_p1, _state); if( p1->recval.ival==tmpval ) { ae_frame_leave(_state); return result; } ae_shared_pool_recycle(ppool1, &_p1, _state); ae_shared_pool_retrieve(ppool0, &_p0, _state); if( p0->recval.ival!=tmpval ) { ae_frame_leave(_state); return result; } /* * Test 7: pools which are fields of records are correctly handled * * pool can be seeded with record which has initialized pool as its field * * when record is retrieved from pool, its fields are correctly copied (including * fields which are pools) */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); tmpval = 99; seedrec1.ival = tmpval; ae_shared_pool_set_seed(&seedrec2.pool, &seedrec1, sizeof(seedrec1), _poolrec1_init, _poolrec1_init_copy, _poolrec1_destroy, _state); ae_shared_pool_set_seed(&pool, &seedrec2, sizeof(seedrec2), _poolrec2_init, _poolrec2_init_copy, _poolrec2_destroy, _state); ae_shared_pool_retrieve(&pool, &_p0, _state); ae_shared_pool_retrieve(&p0->pool, &_q0, _state); q0->ival = tmpval-1; ae_shared_pool_recycle(&p0->pool, &_q0, _state); ae_shared_pool_retrieve(&pool, &_p1, _state); ae_shared_pool_retrieve(&p1->pool, &_q1, _state); if( q1->ival!=tmpval ) { ae_frame_leave(_state); return result; } ae_shared_pool_recycle(&p1->pool, &_q1, _state); ae_shared_pool_retrieve(&p0->pool, &_q0, _state); if( q0->ival!=tmpval-1 ) { ae_frame_leave(_state); return result; } /* * Test 8: after call to PoolReset(), call to PoolFirstRecycled() returns null references */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_p0, _state); ae_shared_pool_retrieve(&pool, &_p1, _state); ae_shared_pool_retrieve(&pool, &_p2, _state); ae_shared_pool_recycle(&pool, &_p1, _state); ae_shared_pool_recycle(&pool, &_p2, _state); ae_shared_pool_recycle(&pool, &_p0, _state); ae_shared_pool_first_recycled(&pool, &_p0, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( p0!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_reset(&pool, _state); ae_shared_pool_first_recycled(&pool, &_p0, _state); if( p0!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( p0!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( p0!=NULL ) { ae_frame_leave(_state); return result; } ae_shared_pool_next_recycled(&pool, &_p0, _state); if( p0!=NULL ) { ae_frame_leave(_state); return result; } /* * Test 9: invalid pointer is recognized as non-null (we do not reference it, just test) */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_p0, _state); ae_shared_pool_retrieve(&pool, &_p1, _state); ae_shared_pool_retrieve(&pool, &_p2, _state); ae_shared_pool_recycle(&pool, &_p1, _state); ae_shared_pool_recycle(&pool, &_p2, _state); ae_shared_pool_recycle(&pool, &_p0, _state); ae_shared_pool_first_recycled(&pool, &_p0, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } ae_shared_pool_clear_recycled(&pool, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } /* * Test 9: non-null pointer is nulled by calling SetNull() */ testalglibbasicsunit_createpoolandrecords(&seedrec2, &seedrec2copy, &pool, _state); ae_shared_pool_retrieve(&pool, &_p0, _state); if( !(p0!=NULL) ) { ae_frame_leave(_state); return result; } ae_smart_ptr_assign(&_p0, NULL, ae_false, ae_false, NULL); if( p0!=NULL ) { ae_frame_leave(_state); return result; } result = ae_false; ae_frame_leave(_state); return result; } static ae_bool testalglibbasicsunit_testsharedpool(ae_bool silent, ae_state *_state) { ae_bool result; result = !testalglibbasicsunit_sharedpoolerrors(_state); if( !silent ) { if( result ) { printf("SHARED POOL: OK\n"); } else { printf("SHARED POOL: FAILED\n"); } } return result; } /************************************************************************* Tests for SMP functions testSort0: sort function *************************************************************************/ static void testalglibbasicsunit_testsort0func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_state *_state) { ae_int_t idx1; if( idx2<=idx0+1 ) { return; } idx1 = (idx0+idx2)/2; testalglibbasicsunit_testsort0func(a, buf, idx0, idx1, _state); testalglibbasicsunit_testsort0func(a, buf, idx1, idx2, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0, idx1, idx2, _state); } /************************************************************************* testSort0: recursive sorting by splitting array into two subarrays. Returns True on success, False on failure. *************************************************************************/ static ae_bool testalglibbasicsunit_performtestsort0(ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector buf; ae_int_t i; ae_int_t k; ae_int_t t; ae_int_t n; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_INT, _state); ae_vector_init(&buf, 0, DT_INT, _state); n = 100000; ae_vector_set_length(&a, n, _state); ae_vector_set_length(&buf, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_int[i] = i; } for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = a.ptr.p_int[i]; a.ptr.p_int[i] = a.ptr.p_int[k]; a.ptr.p_int[k] = t; } } testalglibbasicsunit_testsort0func(&a, &buf, 0, n, _state); result = ae_true; for(i=0; i<=n-1; i++) { result = result&&a.ptr.p_int[i]==i; } ae_frame_leave(_state); return result; } /************************************************************************* TestSort0: sort function *************************************************************************/ static void testalglibbasicsunit_testsort1func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_bool usesmp, ae_state *_state) { ae_int_t idxa; ae_int_t idxb; ae_int_t idxc; ae_int_t cnt4; if( idx2<=idx0+1 ) { return; } if( idx2==idx0+2 ) { testalglibbasicsunit_mergesortedarrays(a, buf, idx0, idx0+1, idx0+2, _state); return; } if( idx2==idx0+3 ) { testalglibbasicsunit_mergesortedarrays(a, buf, idx0+0, idx0+1, idx0+2, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0+0, idx0+2, idx0+3, _state); return; } if( idx2==idx0+4 ) { testalglibbasicsunit_mergesortedarrays(a, buf, idx0+0, idx0+1, idx0+2, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0+2, idx0+3, idx0+4, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0+0, idx0+2, idx0+4, _state); return; } cnt4 = (idx2-idx0)/4; idxa = idx0+cnt4; idxb = idx0+2*cnt4; idxc = idx0+3*cnt4; testalglibbasicsunit_testsort1func(a, buf, idx0, idxa, usesmp, _state); testalglibbasicsunit_testsort1func(a, buf, idxa, idxb, usesmp, _state); testalglibbasicsunit_testsort1func(a, buf, idxb, idxc, usesmp, _state); testalglibbasicsunit_testsort1func(a, buf, idxc, idx2, usesmp, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0, idxa, idxb, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idxb, idxc, idx2, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0, idxb, idx2, _state); } /************************************************************************* TestSort0: recursive sorting by splitting array into 4 subarrays. Sorting is performed in three rounds: * parallel sorting of randomly permuted array * result is randomly shuffled and sequentially sorted * result is randomly shuffled (again) and sorted in parallel mode (again) The idea of such "multitry sort" is that we test ability of SMP core to interleave highly parallel parts of code with long sequential parts. Returns True on success, False on failure. *************************************************************************/ static ae_bool testalglibbasicsunit_performtestsort1(ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector buf; ae_int_t i; ae_int_t k; ae_int_t t; ae_int_t n; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_INT, _state); ae_vector_init(&buf, 0, DT_INT, _state); /* * Generate array */ n = 100000; ae_vector_set_length(&a, n, _state); ae_vector_set_length(&buf, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_int[i] = i; } /* * round 0: parallel sorting of randomly permuted array */ for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = a.ptr.p_int[i]; a.ptr.p_int[i] = a.ptr.p_int[k]; a.ptr.p_int[k] = t; } } testalglibbasicsunit_testsort1func(&a, &buf, 0, n, ae_true, _state); /* * round 1: result is randomly shuffled and sequentially sorted */ for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = a.ptr.p_int[i]; a.ptr.p_int[i] = a.ptr.p_int[k]; a.ptr.p_int[k] = t; } } testalglibbasicsunit_testsort1func(&a, &buf, 0, n, ae_false, _state); /* * round 2: result is randomly shuffled (again) and sorted in parallel mode (again) */ for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = a.ptr.p_int[i]; a.ptr.p_int[i] = a.ptr.p_int[k]; a.ptr.p_int[k] = t; } } testalglibbasicsunit_testsort1func(&a, &buf, 0, n, ae_true, _state); /* * Test */ result = ae_true; for(i=0; i<=n-1; i++) { result = result&&a.ptr.p_int[i]==i; } ae_frame_leave(_state); return result; } /************************************************************************* Tests for SMP functions testSort2: sort function *************************************************************************/ static void testalglibbasicsunit_testsort2func(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx2, ae_state *_state) { ae_int_t idx1; if( idx2<=idx0+1 ) { return; } idx1 = idx0+1+ae_randominteger(idx2-idx0-1, _state); testalglibbasicsunit_testsort0func(a, buf, idx0, idx1, _state); testalglibbasicsunit_testsort0func(a, buf, idx1, idx2, _state); testalglibbasicsunit_mergesortedarrays(a, buf, idx0, idx1, idx2, _state); } /************************************************************************* testSort2: recursive sorting by splitting array into two subarrays of different length (main difference from testsort0). Returns True on success, False on failure. *************************************************************************/ static ae_bool testalglibbasicsunit_performtestsort2(ae_state *_state) { ae_frame _frame_block; ae_vector a; ae_vector buf; ae_int_t i; ae_int_t k; ae_int_t t; ae_int_t n; ae_bool result; ae_frame_make(_state, &_frame_block); ae_vector_init(&a, 0, DT_INT, _state); ae_vector_init(&buf, 0, DT_INT, _state); n = 100000; ae_vector_set_length(&a, n, _state); ae_vector_set_length(&buf, n, _state); for(i=0; i<=n-1; i++) { a.ptr.p_int[i] = i; } for(i=0; i<=n-1; i++) { k = ae_randominteger(n, _state); if( k!=i ) { t = a.ptr.p_int[i]; a.ptr.p_int[i] = a.ptr.p_int[k]; a.ptr.p_int[k] = t; } } testalglibbasicsunit_testsort2func(&a, &buf, 0, n, _state); result = ae_true; for(i=0; i<=n-1; i++) { result = result&&a.ptr.p_int[i]==i; } ae_frame_leave(_state); return result; } /************************************************************************* TestPoolSum: summation with pool We perform summation of 500000 numbers (each of them is equal to 1) in the recurrent manner, by accumulation of result in the pool. This test checks pool ability to handle continuous stream of operations. Returns True on success, False on failure. *************************************************************************/ static ae_bool testalglibbasicsunit_performtestpoolsum(ae_state *_state) { ae_frame _frame_block; ae_shared_pool pool; poolsummand *ptr; ae_smart_ptr _ptr; poolsummand seed; ae_int_t n; ae_int_t sum; ae_bool result; ae_frame_make(_state, &_frame_block); ae_shared_pool_init(&pool, _state); ae_smart_ptr_init(&_ptr, (void**)&ptr, _state); _poolsummand_init(&seed, _state); n = 500000; seed.val = 0; ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _poolsummand_init, _poolsummand_init_copy, _poolsummand_destroy, _state); testalglibbasicsunit_parallelpoolsum(&pool, 0, n, _state); sum = 0; ae_shared_pool_first_recycled(&pool, &_ptr, _state); while(ptr!=NULL) { sum = sum+ptr->val; ae_shared_pool_next_recycled(&pool, &_ptr, _state); } result = sum==n; ae_frame_leave(_state); return result; } /************************************************************************* Summation routune for parallel summation test. *************************************************************************/ static void testalglibbasicsunit_parallelpoolsum(ae_shared_pool* sumpool, ae_int_t ind0, ae_int_t ind1, ae_state *_state) { ae_frame _frame_block; ae_int_t i; poolsummand *ptr; ae_smart_ptr _ptr; ae_frame_make(_state, &_frame_block); ae_smart_ptr_init(&_ptr, (void**)&ptr, _state); if( ind1-ind0<=2 ) { ae_shared_pool_retrieve(sumpool, &_ptr, _state); ptr->val = ptr->val+ind1-ind0; ae_shared_pool_recycle(sumpool, &_ptr, _state); } else { i = (ind0+ind1)/2; testalglibbasicsunit_parallelpoolsum(sumpool, ind0, i, _state); testalglibbasicsunit_parallelpoolsum(sumpool, i, ind1, _state); } ae_frame_leave(_state); } /************************************************************************* This function merges sorted A[Idx0,Idx1) and A[Idx1,Idx2) into sorted array A[Idx0,Idx2) using corresponding elements of Buf. *************************************************************************/ static void testalglibbasicsunit_mergesortedarrays(/* Integer */ ae_vector* a, /* Integer */ ae_vector* buf, ae_int_t idx0, ae_int_t idx1, ae_int_t idx2, ae_state *_state) { ae_int_t srcleft; ae_int_t srcright; ae_int_t dst; srcleft = idx0; srcright = idx1; dst = idx0; for(;;) { if( srcleft==idx1&&srcright==idx2 ) { break; } if( srcleft==idx1 ) { buf->ptr.p_int[dst] = a->ptr.p_int[srcright]; srcright = srcright+1; dst = dst+1; continue; } if( srcright==idx2 ) { buf->ptr.p_int[dst] = a->ptr.p_int[srcleft]; srcleft = srcleft+1; dst = dst+1; continue; } if( a->ptr.p_int[srcleft]ptr.p_int[srcright] ) { buf->ptr.p_int[dst] = a->ptr.p_int[srcleft]; srcleft = srcleft+1; dst = dst+1; } else { buf->ptr.p_int[dst] = a->ptr.p_int[srcright]; srcright = srcright+1; dst = dst+1; } } for(dst=idx0; dst<=idx2-1; dst++) { a->ptr.p_int[dst] = buf->ptr.p_int[dst]; } } static ae_bool testalglibbasicsunit_testsmp(ae_bool silent, ae_state *_state) { ae_bool t0; ae_bool t1; ae_bool t2; ae_bool ts; ae_bool result; t0 = testalglibbasicsunit_performtestsort0(_state); t1 = testalglibbasicsunit_performtestsort1(_state); t2 = testalglibbasicsunit_performtestsort2(_state); ts = testalglibbasicsunit_performtestpoolsum(_state); result = ((t0&&t1)&&t2)&&ts; if( !silent ) { if( result ) { printf("SMP FUNCTIONS: OK\n"); } else { printf("SMP FUNCTIONS: FAILED\n"); printf("* TEST SORT0 (sorting, split-2) "); if( t0 ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* TEST SORT1 (sorting, split-4) "); if( t1 ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* TEST SORT2 (sorting, split-2, unequal) "); if( t2 ) { printf("OK\n"); } else { printf("FAILED\n"); } printf("* TEST POOLSUM (accumulation with pool) "); if( ts ) { printf("OK\n"); } else { printf("FAILED\n"); } } } return result; } void _rec1_init(void* _p, ae_state *_state) { rec1 *p = (rec1*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->b1field, 0, DT_BOOL, _state); ae_vector_init(&p->r1field, 0, DT_REAL, _state); ae_vector_init(&p->i1field, 0, DT_INT, _state); ae_vector_init(&p->c1field, 0, DT_COMPLEX, _state); ae_matrix_init(&p->b2field, 0, 0, DT_BOOL, _state); ae_matrix_init(&p->r2field, 0, 0, DT_REAL, _state); ae_matrix_init(&p->i2field, 0, 0, DT_INT, _state); ae_matrix_init(&p->c2field, 0, 0, DT_COMPLEX, _state); } void _rec1_init_copy(void* _dst, void* _src, ae_state *_state) { rec1 *dst = (rec1*)_dst; rec1 *src = (rec1*)_src; dst->bfield = src->bfield; dst->rfield = src->rfield; dst->ifield = src->ifield; dst->cfield = src->cfield; ae_vector_init_copy(&dst->b1field, &src->b1field, _state); ae_vector_init_copy(&dst->r1field, &src->r1field, _state); ae_vector_init_copy(&dst->i1field, &src->i1field, _state); ae_vector_init_copy(&dst->c1field, &src->c1field, _state); ae_matrix_init_copy(&dst->b2field, &src->b2field, _state); ae_matrix_init_copy(&dst->r2field, &src->r2field, _state); ae_matrix_init_copy(&dst->i2field, &src->i2field, _state); ae_matrix_init_copy(&dst->c2field, &src->c2field, _state); } void _rec1_clear(void* _p) { rec1 *p = (rec1*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->b1field); ae_vector_clear(&p->r1field); ae_vector_clear(&p->i1field); ae_vector_clear(&p->c1field); ae_matrix_clear(&p->b2field); ae_matrix_clear(&p->r2field); ae_matrix_clear(&p->i2field); ae_matrix_clear(&p->c2field); } void _rec1_destroy(void* _p) { rec1 *p = (rec1*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->b1field); ae_vector_destroy(&p->r1field); ae_vector_destroy(&p->i1field); ae_vector_destroy(&p->c1field); ae_matrix_destroy(&p->b2field); ae_matrix_destroy(&p->r2field); ae_matrix_destroy(&p->i2field); ae_matrix_destroy(&p->c2field); } void _rec4serialization_init(void* _p, ae_state *_state) { rec4serialization *p = (rec4serialization*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->b, 0, DT_BOOL, _state); ae_vector_init(&p->i, 0, DT_INT, _state); ae_vector_init(&p->r, 0, DT_REAL, _state); } void _rec4serialization_init_copy(void* _dst, void* _src, ae_state *_state) { rec4serialization *dst = (rec4serialization*)_dst; rec4serialization *src = (rec4serialization*)_src; ae_vector_init_copy(&dst->b, &src->b, _state); ae_vector_init_copy(&dst->i, &src->i, _state); ae_vector_init_copy(&dst->r, &src->r, _state); } void _rec4serialization_clear(void* _p) { rec4serialization *p = (rec4serialization*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->b); ae_vector_clear(&p->i); ae_vector_clear(&p->r); } void _rec4serialization_destroy(void* _p) { rec4serialization *p = (rec4serialization*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->b); ae_vector_destroy(&p->i); ae_vector_destroy(&p->r); } void _poolrec1_init(void* _p, ae_state *_state) { poolrec1 *p = (poolrec1*)_p; ae_touch_ptr((void*)p); ae_vector_init(&p->i1val, 0, DT_INT, _state); } void _poolrec1_init_copy(void* _dst, void* _src, ae_state *_state) { poolrec1 *dst = (poolrec1*)_dst; poolrec1 *src = (poolrec1*)_src; dst->cval = src->cval; dst->rval = src->rval; dst->ival = src->ival; dst->bval = src->bval; ae_vector_init_copy(&dst->i1val, &src->i1val, _state); } void _poolrec1_clear(void* _p) { poolrec1 *p = (poolrec1*)_p; ae_touch_ptr((void*)p); ae_vector_clear(&p->i1val); } void _poolrec1_destroy(void* _p) { poolrec1 *p = (poolrec1*)_p; ae_touch_ptr((void*)p); ae_vector_destroy(&p->i1val); } void _poolrec2_init(void* _p, ae_state *_state) { poolrec2 *p = (poolrec2*)_p; ae_touch_ptr((void*)p); _poolrec1_init(&p->recval, _state); ae_shared_pool_init(&p->pool, _state); } void _poolrec2_init_copy(void* _dst, void* _src, ae_state *_state) { poolrec2 *dst = (poolrec2*)_dst; poolrec2 *src = (poolrec2*)_src; dst->bval = src->bval; _poolrec1_init_copy(&dst->recval, &src->recval, _state); ae_shared_pool_init_copy(&dst->pool, &src->pool, _state); } void _poolrec2_clear(void* _p) { poolrec2 *p = (poolrec2*)_p; ae_touch_ptr((void*)p); _poolrec1_clear(&p->recval); ae_shared_pool_clear(&p->pool); } void _poolrec2_destroy(void* _p) { poolrec2 *p = (poolrec2*)_p; ae_touch_ptr((void*)p); _poolrec1_destroy(&p->recval); ae_shared_pool_destroy(&p->pool); } void _poolsummand_init(void* _p, ae_state *_state) { poolsummand *p = (poolsummand*)_p; ae_touch_ptr((void*)p); } void _poolsummand_init_copy(void* _dst, void* _src, ae_state *_state) { poolsummand *dst = (poolsummand*)_dst; poolsummand *src = (poolsummand*)_src; dst->val = src->val; } void _poolsummand_clear(void* _p) { poolsummand *p = (poolsummand*)_p; ae_touch_ptr((void*)p); } void _poolsummand_destroy(void* _p) { poolsummand *p = (poolsummand*)_p; ae_touch_ptr((void*)p); } #if (AE_OS==AE_WINDOWS) || defined(AE_DEBUG4WINDOWS) #include #endif #if (AE_OS==AE_POSIX) || defined(AE_DEBUG4POSIX) #include #include #endif #define AE_SINGLECORE 1 #define AE_SEQUENTIAL_MULTICORE 2 #define AE_PARALLEL_SINGLECORE 3 #define AE_PARALLEL_MULTICORE 4 #define AE_SKIP_TEST 5 unsigned seed; int global_failure_flag = 0; ae_bool use_smp = ae_false; #if (AE_OS==AE_WINDOWS) || defined(AE_DEBUG4WINDOWS) CRITICAL_SECTION tests_lock; CRITICAL_SECTION print_lock; #elif (AE_OS==AE_POSIX) || defined(AE_DEBUG4POSIX) pthread_mutex_t tests_lock; pthread_mutex_t print_lock; #else void *tests_lock = NULL; void *print_lock = NULL; #endif typedef struct { const char *name; ae_bool (*seq_testfunc)(ae_bool, ae_state*); ae_bool(*smp_testfunc)(ae_bool, ae_state*); } _s_testrecord; int unittests_processed = 0; _s_testrecord unittests[] = { {"hqrnd",testhqrnd,_pexec_testhqrnd}, {"tsort",testtsort,_pexec_testtsort}, {"nearestneighbor",testnearestneighbor,_pexec_testnearestneighbor}, {"ablas",testablas,_pexec_testablas}, {"basestat",testbasestat,_pexec_testbasestat}, {"bdss",testbdss,_pexec_testbdss}, {"blas",testblas,_pexec_testblas}, {"clustering",testclustering,_pexec_testclustering}, {"dforest",testdforest,_pexec_testdforest}, {"gammafunc",testgammafunc,_pexec_testgammafunc}, {"hblas",testhblas,_pexec_testhblas}, {"reflections",testreflections,_pexec_testreflections}, {"creflections",testcreflections,_pexec_testcreflections}, {"sblas",testsblas,_pexec_testsblas}, {"ortfac",testortfac,_pexec_testortfac}, {"bdsvd",testbdsvd,_pexec_testbdsvd}, {"svd",testsvd,_pexec_testsvd}, {"linreg",testlinreg,_pexec_testlinreg}, {"filters",testfilters,_pexec_testfilters}, {"evd",testevd,_pexec_testevd}, {"matgen",testmatgen,_pexec_testmatgen}, {"sparse",testsparse,_pexec_testsparse}, {"trfac",testtrfac,_pexec_testtrfac}, {"trlinsolve",testtrlinsolve,_pexec_testtrlinsolve}, {"safesolve",testsafesolve,_pexec_testsafesolve}, {"rcond",testrcond,_pexec_testrcond}, {"matinv",testmatinv,_pexec_testmatinv}, {"lda",testlda,_pexec_testlda}, {"mlpbase",testmlpbase,_pexec_testmlpbase}, {"xblas",testxblas,_pexec_testxblas}, {"densesolver",testdensesolver,_pexec_testdensesolver}, {"optserv",testoptserv,_pexec_testoptserv}, {"fbls",testfbls,_pexec_testfbls}, {"cqmodels",testcqmodels,_pexec_testcqmodels}, {"snnls",testsnnls,_pexec_testsnnls}, {"sactivesets",testsactivesets,_pexec_testsactivesets}, {"linmin",testlinmin,_pexec_testlinmin}, {"mincg",testmincg,_pexec_testmincg}, {"minbleic",testminbleic,_pexec_testminbleic}, {"mcpd",testmcpd,_pexec_testmcpd}, {"mlpe",testmlpe,_pexec_testmlpe}, {"minlbfgs",testminlbfgs,_pexec_testminlbfgs}, {"mlptrain",testmlptrain,_pexec_testmlptrain}, {"pca",testpca,_pexec_testpca}, {"odesolver",testodesolver,_pexec_testodesolver}, {"fft",testfft,_pexec_testfft}, {"conv",testconv,_pexec_testconv}, {"corr",testcorr,_pexec_testcorr}, {"fht",testfht,_pexec_testfht}, {"gq",testgq,_pexec_testgq}, {"gkq",testgkq,_pexec_testgkq}, {"autogk",testautogk,_pexec_testautogk}, {"idwint",testidwint,_pexec_testidwint}, {"ratint",testratint,_pexec_testratint}, {"polint",testpolint,_pexec_testpolint}, {"spline1d",testspline1d,_pexec_testspline1d}, {"normestimator",testnormestimator,_pexec_testnormestimator}, {"minqp",testminqp,_pexec_testminqp}, {"minlm",testminlm,_pexec_testminlm}, {"lsfit",testlsfit,_pexec_testlsfit}, {"parametric",testparametric,_pexec_testparametric}, {"linlsqr",testlinlsqr,_pexec_testlinlsqr}, {"rbf",testrbf,_pexec_testrbf}, {"spline2d",testspline2d,_pexec_testspline2d}, {"spline3d",testspline3d,_pexec_testspline3d}, {"spdgevd",testspdgevd,_pexec_testspdgevd}, {"inverseupdate",testinverseupdate,_pexec_testinverseupdate}, {"schur",testschur,_pexec_testschur}, {"minnlc",testminnlc,_pexec_testminnlc}, {"minns",testminns,_pexec_testminns}, {"lincg",testlincg,_pexec_testlincg}, {"nleq",testnleq,_pexec_testnleq}, {"polynomialsolver",testpolynomialsolver,_pexec_testpolynomialsolver}, {"chebyshev",testchebyshev,_pexec_testchebyshev}, {"hermite",testhermite,_pexec_testhermite}, {"laguerre",testlaguerre,_pexec_testlaguerre}, {"legendre",testlegendre,_pexec_testlegendre}, {"stest",teststest,_pexec_teststest}, {"studentttests",teststudentttests,_pexec_teststudentttests}, {"alglibbasics",testalglibbasics,_pexec_testalglibbasics}, {NULL, NULL, NULL} }; #if (AE_OS==AE_WINDOWS) || defined(AE_DEBUG4WINDOWS) void acquire_lock(CRITICAL_SECTION *p_lock) { EnterCriticalSection(p_lock); } void release_lock(CRITICAL_SECTION *p_lock) { LeaveCriticalSection(p_lock); } #elif (AE_OS==AE_POSIX) || defined(AE_DEBUG4POSIX) void acquire_lock(pthread_mutex_t *p_lock) { pthread_mutex_lock(p_lock); } void release_lock(pthread_mutex_t *p_lock) { pthread_mutex_unlock(p_lock); } #else void acquire_lock(void **p_lock) { } void release_lock(void **p_lock) { } #endif ae_bool call_unittest( ae_bool(*seq_testfunc)(ae_bool, ae_state*), ae_bool(*smp_testfunc)(ae_bool, ae_state*), int *psticky) { #ifndef AE_USE_CPP_ERROR_HANDLING ae_state _alglib_env_state; ae_frame _frame_block; jmp_buf _break_jump; ae_bool result; ae_state_init(&_alglib_env_state); if( setjmp(_break_jump) ) { *psticky = 1; return ae_false; } ae_state_set_break_jump(&_alglib_env_state, &_break_jump); ae_frame_make(&_alglib_env_state, &_frame_block); if( use_smp ) result = smp_testfunc(ae_true, &_alglib_env_state); else result = seq_testfunc(ae_true, &_alglib_env_state); ae_state_clear(&_alglib_env_state); if( !result ) *psticky = 1; return result; #else try { ae_state _alglib_env_state; ae_frame _frame_block; ae_bool result; ae_state_init(&_alglib_env_state); ae_frame_make(&_alglib_env_state, &_frame_block); if( use_smp ) result = smp_testfunc(ae_true, &_alglib_env_state); else result = seq_testfunc(ae_true, &_alglib_env_state); ae_state_clear(&_alglib_env_state); if( !result ) *psticky = 1; return result; } catch(...) { *psticky = 1; return ae_false; } #endif } #if (AE_OS==AE_WINDOWS) || defined(AE_DEBUG4WINDOWS) DWORD WINAPI tester_function(LPVOID T) #elif AE_OS==AE_POSIX || defined(AE_DEBUG4POSIX) void* tester_function(void *T) #else void tester_function(void *T) #endif { int idx; ae_bool status; for(;;) { /* * try to acquire test record */ acquire_lock(&tests_lock); if( unittests[unittests_processed].name==NULL ) { release_lock(&tests_lock); break; } idx = unittests_processed; unittests_processed++; release_lock(&tests_lock); /* * Call unit test */ status = call_unittest( unittests[idx].seq_testfunc, unittests[idx].smp_testfunc, &global_failure_flag); acquire_lock(&print_lock); if( status ) printf("%-32s OK\n", unittests[idx].name); else printf("%-32s FAILED\n", unittests[idx].name); fflush(stdout); release_lock(&print_lock); } #if AE_OS==AE_WINDOWS || defined(AE_DEBUG4WINDOWS) return 0; #elif AE_OS==AE_POSIX || defined(AE_DEBUG4POSIX) return NULL; #else #endif } int main(int argc, char **argv) { time_t time_0, time_1; union { double a; ae_int32_t p[2]; } u; if( argc==2 ) seed = (unsigned)atoi(argv[1]); else { time_t t; seed = (unsigned)time(&t); } #if (AE_OS==AE_WINDOWS) || defined(AE_DEBUG4WINDOWS) InitializeCriticalSection(&tests_lock); InitializeCriticalSection(&print_lock); #elif (AE_OS==AE_POSIX) || defined(AE_DEBUG4POSIX) pthread_mutex_init(&tests_lock, NULL); pthread_mutex_init(&print_lock, NULL); #endif /* * SMP settings */ #if AE_TEST==AE_PARALLEL_MULTICORE || AE_TEST==AE_SEQUENTIAL_MULTICORE use_smp = ae_true; #else use_smp = ae_false; #endif /* * Seed */ printf("SEED: %u\n", (unsigned int)seed); srand(seed); /* * Compiler */ #if AE_COMPILER==AE_GNUC printf("COMPILER: GCC\n"); #elif AE_COMPILER==AE_SUNC printf("COMPILER: SunStudio\n"); #elif AE_COMPILER==AE_MSVC printf("COMPILER: MSVC\n"); #else printf("COMPILER: unknown\n"); #endif /* * Architecture */ if( sizeof(void*)==4 ) printf("HARDWARE: 32-bit\n"); else if( sizeof(void*)==8 ) printf("HARDWARE: 64-bit\n"); else printf("HARDWARE: strange (non-32, non-64)\n"); /* * determine endianness of hardware. * 1983 is a good number - non-periodic double representation allow us to * easily distinguish between upper and lower halfs and to detect mixed endian hardware. */ u.a = 1.0/1983.0; if( u.p[1]==0x3f408642 ) printf("HARDWARE: little-endian\n"); else if( u.p[0]==0x3f408642 ) printf("HARDWARE: big-endian\n"); else printf("HARDWARE: mixed-endian\n"); /* * CPU (as defined) */ #if AE_CPU==AE_INTEL printf("CPU: Intel\n"); #elif AE_CPU==AE_SPARC printf("CPU: SPARC\n"); #else printf("CPU: unknown\n"); #endif /* * Cores count */ #ifdef AE_HPC printf("CORES: %d\n", (int)ae_cores_count()); #else printf("CORES: 1 (serial version)\n"); #endif /* * Support for vendor libraries */ #ifdef AE_MKL printf("LIBS: MKL (Intel)\n"); #else printf("LIBS: \n"); #endif /* * CPUID results */ printf("CPUID: %s\n", ae_cpuid()&CPU_SSE2 ? "sse2" : ""); /* * OS */ #if AE_OS==AE_WINDOWS printf("OS: Windows\n"); #elif AE_OS==AE_POSIX printf("OS: POSIX\n"); #else printf("OS: unknown\n"); #endif /* * Testing mode */ #if (AE_TEST==0) || (AE_TEST==AE_SINGLECORE) printf("TESTING MODE: single core\n"); #elif AE_TEST==AE_PARALLEL_SINGLECORE printf("TESTING MODE: single core, parallel\n"); #elif AE_TEST==AE_SEQUENTIAL_MULTICORE printf("TESTING MODE: milti-core, sequential\n"); #elif AE_TEST==AE_PARALLEL_MULTICORE printf("TESTING MODE: milti-core, parallel\n"); #elif AE_TEST==AE_SKIP_TEST printf("TESTING MODE: just compiling\n"); printf("Done in 0 seconds\n"); return 0; #else #error Unknown AE_TEST being passed #endif /* * now we are ready to test! */ time(&time_0); #ifdef AE_HPC if( ae_smpselftests() ) printf("%-32s OK\n", "SMP self tests"); else { printf("%-32s FAILED\n", "SMP self tests"); return 1; } #endif fflush(stdout); #if AE_TEST==0 || AE_TEST==AE_SINGLECORE || AE_TEST==AE_SEQUENTIAL_MULTICORE || AE_TEST==AE_SKIP_TEST tester_function(NULL); #elif AE_TEST==AE_PARALLEL_MULTICORE || AE_TEST==AE_PARALLEL_SINGLECORE #ifdef AE_HPC ae_set_cores_to_use(0); #endif #if AE_OS==AE_WINDOWS || defined(AE_DEBUG4WINDOWS) { SYSTEM_INFO sysInfo; HANDLE *hThreads = NULL; int idx; GetSystemInfo(&sysInfo); ae_assert(sysInfo.dwNumberOfProcessors>=1, "processors count is less than 1", NULL); hThreads = (HANDLE*)malloc(sizeof(HANDLE)*sysInfo.dwNumberOfProcessors); ae_assert(hThreads!=NULL, "malloc failure", NULL); for(idx=0; idx=1, "processors count is less than 1", NULL); threads = (pthread_t*)malloc(sizeof(pthread_t)*cpu_cnt); ae_assert(threads!=NULL, "malloc failure", NULL); for(idx=0; idx Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. qmapshack-1.10.0/3rdparty/alglib/CMakeLists.txt000644 001750 000144 00000001535 13015033052 022460 0ustar00oeichlerxusers000000 000000 # Set source files # ---------------- set(alg_SRCS src/alglibinternal.cpp src/alglibmisc.cpp src/ap.cpp src/dataanalysis.cpp src/diffequations.cpp src/fasttransforms.cpp src/integration.cpp src/interpolation.cpp src/linalg.cpp src/optimization.cpp src/solvers.cpp src/specialfunctions.cpp src/statistics.cpp ) # Set header files # ---------------- set(alg_HDRS src/alglibinternal.h src/alglibmisc.h src/ap.h src/dataanalysis.h src/diffequations.h src/fasttransforms.h src/integration.h src/interpolation.h src/linalg.h src/optimization.h src/solvers.h src/specialfunctions.h src/statistics.h src/stdafx.h ) # The target to build # ------------------- add_library(alg STATIC ${alg_SRCS} ${alg_HDRS}) qmapshack-1.10.0/3rdparty/alglib/gpl3.txt000755 001750 000144 00000105753 13015033052 021340 0ustar00oeichlerxusers000000 000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .qmapshack-1.10.0/3rdparty/alglib/manual.cpp.html000755 001750 000144 00010313056 13015033052 022654 0ustar00oeichlerxusers000000 000000

1 Introduction

1.2 1.1 What is ALGLIB

ALGLIB is a cross-platform numerical analysis and data mining library. It supports several programming languages (C++, C#, Pascal, VBA) and several operating systems (Windows, *nix family).

ALGLIB features include:

  • Data analysis (classification/regression, including neural networks)
  • Optimization and nonlinear solvers
  • Interpolation and linear/nonlinear least-squares fitting
  • Linear algebra (direct algorithms, EVD/SVD), direct and iterative linear solvers, Fast Fourier Transform and many other algorithms (numerical integration, ODEs, statistics, special functions)

ALGLIB Project (the company behind ALGLIB) delivers to you several editions of ALGLIB:

  • ALGLIB Free Edition - full functionality but limited performance
  • ALGLIB Commercial Edition - high-performance version of ALGLIB

Free Edition is a serial version without multithreading support or extensive low-level optimizations (generic C or C# code). Commercial Edition is a heavily optimized version of ALGLIB. It supports multithreading, it was extensively optimized, and (on Intel platforms) - our commercial users may enjoy precompiled version of ALGLIB which internally calls Intel MKL to accelerate low-level tasks. We obtained license from Intel corp., which allows us to integrate Intel MKL into ALGLIB, so you don't have to buy separate license from Intel.

1.2 1.1 ALGLIB license

ALGLIB Free Edition is distributed under GPL 2+, GPL license version 2 or at your option any later version. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses

ALGLIB Commercial Edition is distributed under license which is friendly to commericial users. A copy of the commercial license can be found at http://www.alglib.net/commercial.php.

1.3 Documentation license

This reference manual is licensed under BSD-like documentation license:

Copyright 1994-2009 Sergey Bochkanov, ALGLIB Project. All rights reserved.

Redistribution and use of this document (ALGLIB Reference Manual) with or without modification, are permitted provided that such redistributions will retain the above copyright notice, this condition and the following disclaimer as the first (or last) lines of this file.

THIS DOCUMENTATION IS PROVIDED BY THE ALGLIB PROJECT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ALGLIB PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1.4 Reference Manual and User Guide

ALGLIB Project provides two sources of information: ALGLIB Reference Manual (this document) and ALGLIB User Guide.

ALGLIB Reference Manual contains full description of all publicly accessible ALGLIB units accompanied with examples. Reference Manual is focused on the source code: it documents units, functions, structures and so on. If you want to know what unit YYY can do or what subroutines unit ZZZ contains Reference Manual is a place to go. Free software needs free documentation - that's why ALGLIB Reference Manual is licensed under BSD-like documentation license.

Additionally to the Reference Manual we provide you User Guide. User Guide is focused on more general questions: how fast ALGLIB is? how reliable it is? what are the strong and weak sides of the algorithms used? We aim to make ALGLIB User Guide an important source of information both about ALGLIB and numerical analysis algorithms in general. We want it to be a book about algorithms, not just software documentation. And we want it to be unique - that's why ALGLIB User Guide is distributed under less-permissive personal-use-only license.

1.5 Acknowledgements

ALGLIB was not possible without contribution of the next open source projects:

We also want to thank developers of the Intel's local development center (Nizhny Novgorod branch) for their help during MKL integration.

2 ALGLIB structure

2.1 Packages

ALGLIB is a C++ interface to the computational core written in C. Both C library and C++ wrapper are automatically generated by code generation tools developed within ALGLIB project. Pre-3.0 versions of ALGLIB included more than 100 units, but it was difficult to work with such large number of files. Since ALGLIB 3.0 all units are merged into 11 packages and two support units:

  • alglibmisc.cpp - contains different algorithms which are hard to classify
  • dataanalysis.cpp - contains data mining algorithms
  • diffequations.cpp - contains differential equation solvers
  • fasttransforms.cpp - contains FFT and other related algorithms
  • integration.cpp - contains numerical integration algorithms
  • interpolation.cpp - contains interpolation algorithms
  • linalg.cpp - contains linear algebra algorithms
  • optimization.cpp - contains optimization algorithms
  • solvers.cpp - contains linear and nonlinear solvers
  • specialfunctions.cpp - contains special functions
  • statistics.cpp - statistics
  • alglibinternal.cpp - contains internal functions which are used by other packages, but not exposed to the external world
  • ap.cpp - contains publicly accessible vector/matrix classes, most important and general functions and other "basic" functionality

One package may rely on other ones, but we have tried to reduce number of dependencies. Every package relies on ap.cpp and many packages rely on alglibinternal.cpp. But many packages require only these two to work, and many other packages need significantly less than 13 packages. For example, statistics.cpp requires two packages mentioned above and only one additional package - specialfunctions.cpp.

2.2 Subpackages

There is one more concept to learn - subpackages. Every package was created from several source files. For example (as of ALGLIB 3.0.0), linalg.cpp was created by merging together 14 .cpp files (C++ interface) and 14 .c files (computational core). These files provide different functionality: one of them calculates triangular factorizations, another generates random matrices, and so on. We've merged source code, but what to do with their documentation?

Of course, we can merge their documentation (as we've merged units) in one big list of functions and data structures, but such list will be hard to read. Instead, we have decided to merge source code, but leave documentation separate.

If you look at the list of ALGLIB packages, you will see that each package includes several subpackages. For example, linalg.cpp includes trfac, svd, evd and other subpackages. These subpackages do no exist as separate files, namespaces or other entities. They are just subsets of one large unit which provide significantly different functionality. They have separate documentation sections, but if you want to use svd subpackage, you have to include linalg.h, not svd.h.

2.3 Open Source and Commercial versions

ALGLIB comes in two versions - open source (GPL-licensed) and commercial (closed source) one. Both versions have same functionality, i.e. may solve same set of problems. However, commercial version differs from open source one in following aspects:

  • License. Commercial ALGLIB is licensed under non-copyleft license which is friendly to commercial users.
  • Performance. Many algorithms in commercial ALGLIB are multi-threaded and SSE-optimized (when used on Intel systems). Open source ALGLIB is single-threaded and can not efficiently use modern multicore CPU's.
    You have to study comments on specific functions if you want to know whether they have multithreaded versions or not.

This documentation applies to both versions of ALGLIB. Detailed description of commercial version can be found below.

3 Compatibility

3.1 CPU

ALGLIB is compatible with any CPU which:

  • supports double precision arithmetics
  • complies with IEEE 754 floating point standard (especially in its handling of IEEE special values)
  • either big-endian or little-endian (but not mixed-endian)

Most mainstream CPU's (in particular, x86, x86_64, ARM and SPARC) satisfy these requirements.

As for Intel architecture, ALGLIB works with both FPU-based and SSE-based implementations of floating point math. 80-bit internal representation used by Intel FPU is not a problem for ALGLIB.

3.2 OS

ALGLIB for C++ (both open source and commercial versions) can be compiled in OS-agnostic mode (no OS-specific preprocessor definitions), when it is compatible with any OS which supports C++98 standard library. In particular, it will work under any POSIX-compatible OS and under Windows.

If you want to use multithreaded capabilities of commercial version of ALGLIB, you should compile it in OS-specific mode by #defining either AE_OS=AE_WINDOWS or AE_OS=AE_POSIX at compile time, depending on OS being used. Former corresponds to any modern OS (32/64-bit Windows XP and later) from Windows family, while latter means almost any POSIX-compatible OS. It applies only to commercial version of ALGLIB. Open source version is always OS-agnostic, even in the presence of OS-specific definitions.

3.3 Compiler

ALGLIB is compatible with any C++ compiler which:

  • supports 32-bit and 64-bit signed integer datatypes
  • emits code which handles comparisons with IEEE special values without raising exception. We don't require that x/0 will return INF. But at least we must be able to compare double precision value with infinity or NAN without raising exception.

All modern compilers (in particular, reasonably new versions of MSVC, GCC and Sun Studio) satisfy these requirements.

However, some very old compilers (ten years old version of Borland C++ Builder, for example) may emit code which does not correctly work with IEEE special values. If you use one of these old compilers, we recommend you to run ALGLIB test suite to ensure that library works.

3.4 Optimization settings

ALGLIB is compatible with any kind of optimizing compiler as long as:

  • volatile modifier is correctly handled (i.e. compiler does not optimize volatile reads/writes)
  • optimized code correctly handles IEEE special values

Generally, all kinds of optimization that were marked by compiler vendor as "safe" are possible. For example, ALGLIB can be compiled:

  • under MSVC: with /O1, /O2, /Og, /Os, /Ox, /Ot, /Oy, /fp:precise, /fp:except, /fp:strict
  • under GCC: with -O1, -O2, -O3, -Os

From the other side, following "unsafe" optimizations will break ALGLIB:

  • under MSVC: /fp:fast
  • under GCC: -Ofast, -ffast-math

4 Compiling ALGLIB

4.1 Adding to your project

Adding ALGLIB to your project is easy - just pick packages you need and... add them to your project! Under most used compilers (GCC, MSVC, Sun Studio) it will work without any additional settings. In other cases you will need to define several preprocessor definitions (this topic will be detailed below), but everything will still be simple.

By "adding to your project" we mean that you should a) compile .cpp files with the rest of your project, and b) include .h files you need. Do not include .cpp files - these files must be compiled separately, not as part of some larger source file. The only files you should include are .h files, stored in the /src folder of the ALGLIB distribution.

As you see, ALGLIB has no project files or makefiles. Why? There are several reasons:

  • first, because many ALGLIB users don't need separate static library (which will be created by invoking makefile) - they prefer to integrate source code in their projects. We have provided script-based build system before, but majority of our users prefer to build ALGLIB themselves.
  • second, because we want ALGLIB to be usable in any programming environment, whether it is Visual Studio, GNU build system or something else. The best solution is to write package which doesn't depend on any particular programming environment.

In any case, compiling ALGLIB is so simple that even without project file you can do it in several minutes.

4.2 Configuring for your compiler

If you use modern versions of MSVC, GCC or Sun Studio, you don't need to configure ALGLIB at all. But if you use outdated versions of these compilers (or something else), then you may need to tune definitions of several data types:

  • alglib_impl::ae_int32_t - signed integer which is 32 bits wide
  • alglib_impl::ae_int64_t - signed integer which is 64 bits wide
  • alglib_impl::ae_int_t - signed integer which has same width as pointer

ALGLIB tries to autodetect your compiler and to define these types in compiler-specific manner:

  • ae_int32_t is defined as int, because this type is 32 bits wide in all modern compilers.
  • ae_int64_t is defined as _int64 (MSVC) or as signed long long (GCC, Sun Studio).
  • ae_int_t is defined as ptrdiff_t.

In most cases, it is enough. But if anything goes wrong, you have several options:

  • if your compiler provides stdint.h, you can define AE_HAVE_STDINT conditional symbol
  • alternatively, you can manually define AE_INT32_T and/or AE_INT64_T and/or AE_INT_T symbols. Just assign datatype name to them, and ALGLIB will automatically use your definition. You can define only one or two types (those which are not defined automatically).

4.3 Improving performance (CPU-specific and OS-specific optimizations)

You can improve performance of ALGLIB in a several ways:

  • by compiling with advanced optimization turned on
  • by telling ALGLIB about CPU it will run on

ALGLIB has two-layered structure: some set of basic performance-critical primitives is implemented using optimized code, and the rest of the library is built on top of these primitives. By default, ALGLIB uses generic C code to implement these primitives (matrix multiplication, decompositions, etc.). This code works everywhere from Intel to SPARC. However, you can tell ALGLIB that it will work under particular architecture by defining appropriate macro at the global level:

  • defining AE_CPU=AE_INTEL - to tell ALGLIB that it will work under Intel

When AE_CPU macro is defined and equals to the AE_INTEL, it enables SSE2 support. ALGLIB will use cpuid instruction to determine SSE2 presence at run-time and - in case we have SSE2 - to use SSE2-capable code. ALGLIB uses SSE2 intrinsics which are portable across different compilers and efficient enough for most practical purposes. As of ALGLIB 3.4, SSE2 support is available for MSVC, GCC and Sun Studio users only.

5 Working with commercial version

5.1 Benefits of commercial version

Commercial version of ALGLIB for C++ features four important improvements over open source one:

  • License. Commercial license used by ALGLIB is friendly to closed source applications. Unlike GPL, it does not require you to open source your application. Thus, almost any commercial software developer is interested in obtaining commercial license.
  • Low-level optimizations. Commercial version of ALGLIB includes SSE-optimized versions of many computationally intensive functions. In particular, commercial version of neural networks outperforms open source one with 2-3x increase in speed - even without multithreading! It allows to increase performance on Intel/AMD platforms while still being able to use software under non-x86 CPU's.
  • Multithreading. Commercial version of ALGLIB can utilize multicore capabilities of modern CPU's. Large computational problems can be automatically split between different cores. ALGLIB uses its own multithreading framework which does not depend on vendor/compiler support for technologies like OpenMP/MPI/... It gives ALGLIB unprecedented portability across operating systems and compilers.
  • Integrated Intel MKL. Commercial version of ALGLIB includes special MKL extensions - special lightweight distribution of Intel MKL, high-performance numerical analysis library, accompanied by ALGLIB-MKL interface. We obtained license from Intel which allows us to integrate MKL into ALGLIB distribution. Linking with MKL accelerates many ALGLIB functions, however due to license restrictions you can not use MKL directly (i.e. bypass ALGLIB interface between your program and MKL).

5.2 Working with SSE support (Intel/AMD users)

ALGLIB for C++ can utilize SSE2 set of instructions supported by all modern Intel and AMD x86 processors. This feature is optional and must be explicitly turned on during compile-time. If you do not activate it, ALGLIB will use generic C code, without any processor-specific assembly/intrinsics.

Thus, if you turn on this feature, your code will run faster on x86_32 and x86_64 processors, but will be unportable to non-x86 platforms (and Intel MIC platform, which is not exactly x86 and does not support SSE!). From the other side, if you do not activate this feature, your code will be portable to almost any modern CPU (SPARC, ARM, ...).

In order to turn on x86-specific optimizations, you should define AE_CPU=AE_INTEL preprocessor definition at global level. It will tell ALGLIB to use SSE intrinsics supported by GCC, MSVC and Intel compilers. Additionally you should tell compiler to generate SSE-capable code. It can be done in the project settings of your IDE or in the command line:


GCC example:
> g++ -msse2 -I. -DAE_CPU=AE_INTEL *.cpp -lm

MSVC example:
> cl /I. /EHsc /DAE_CPU=AE_INTEL *.cpp

5.3 Using multithreading

Commercial version of ALGLIB includes out-of-the-box support for multithreading. Many (not all) computationally intensive problems can be solved in multithreaded mode. You should read comments on specific ALGLIB functions to determine what can be multithreaded and what can not.

ALGLIB does not depend on vendor/compiler support for technologies like OpenMP/MPI/... Under Windows ALGLIB uses OS threads and custom synchronization framework. Under POSIX-compatible OS (Solaris, Linux, FreeBSD, NetBSD, OpenBSD, ...) ALGLIB uses POSIX Threads (standard *nix library which is shipped with any POSIX system) with its threading and synchronization primitives. It gives ALGLIB unprecedented portability across operating systems and compilers. ALGLIB does not depend on presence of any custom multithreading library or compiler support for any multithreading technology.

If you want to use multithreaded capabilities of ALGLIB, you should:

  1. compile it in OS-specific mode (ALGLIB have to know what OS it is running on)
  2. tell ALGLIB about number of worker threads to use
  3. call multithreaded versions of computational functions

Let explain it in more details...

1. You should compile ALGLIB in OS-specific mode by #defining either AE_OS=AE_WINDOWS or AE_OS=AE_POSIX at compile time, depending on OS being used. Former corresponds to any modern OS (32/64-bit Windows XP and later) from Windows family, while latter means almost any POSIX-compatible OS. When compiling on POSIX, do not forget to link ALGLIB with libpthread library.

2. ALGLIB automatically determines number of cores on application startup. On Windows it is done using GetSystemInfo() call. On POSIX systems ALGLIB performs sysconf(_SC_NPROCESSORS_ONLN) system call. This system call is supported by all modern POSIX-compatible systems: Solaris, Linux, FreeBSD, NetBSD, OpenBSD.

By default, ALGLIB uses all available cores except for one. Say, on 4-core system it will use three cores - unless being told to use more or less. It will keep your system responsive during lengthy computations. Such behavior may be changed with setnworkers() call:

  • alglib::setnworkers(0) = use all cores
  • alglib::setnworkers(-1) = leave one core unused
  • alglib::setnworkers(-2) = leave two cores unused
  • alglib::setnworkers(+2) = use 2 cores (even if you have more)

You may want to specify maximum number of worker threads during compile time by means of preprocessor definition AE_NWORKERS=N. You can add this definition to compiler command line or change corresponding project settings in your IDE. Here N can be any positive number. ALGLIB will use exactly N worker threads, unless being told to use less by setnworkers() call.

Some old POSIX-compatible operating systems do not support sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order to automatically determine number of active cores. On these systems you should specify number of cores manually at compile time. Without it ALGLIB will run in single-threaded mode.

3. When you use commercial edition of ALGLIB, you may choose between serial and multithreaded versions of SMP-capable functions:

  • serial version works as usual, in the context of the calling thread
  • multithreaded version (with smp_ prefix in its name) creates (or wakes up) worker threads, inserts task in the worker queue, and waits for completion of the task. All processing is done in context of worker thread(s).

You should carefully decide what version of function to use. Starting/stopping worker thread costs tens of thousands of CPU cycles. Thus you won't get multithreading speedup on small computational problems.

5.3.1 SMT (CMT/hyper-threading) issues

Simultaneous multithreading (SMT) also known as Hyper-threading (Intel) and Cluster-based Multithreading (AMD) is a CPU design where several (usually two) logical cores share resources of one physical core. Say, on dual-core system with 2x HT scale factor you will see 4 logical cores. Each pair of these 4 cores, however, share same hardware resources. Thus, you may get only marginal speedup when running highly optimized software which fully utilizes CPU resources.

Say, if one thread occupies floating-point unit, another thread on the same physical core may work with integer numbers at the same time without any performance penalties. In this case you may get some speedup due to having additional cores. But if both threads keep FPU unit 100% busy, they won't get any multithreaded speedup.

So, if 2 math-intensive threads are dispatched by OS scheduler to different physical cores, you will get 2x speedup due to use of multithreading. But if these threads are dispatched to different logical cores - but same physical core - you won't get any speedup at all! One physical core will be 100% busy, and another one will be 100% idle. From the other side, if you start four threads instead of two, your system will be 100% utilized independently of thread scheduling details.

Let we stress it one more time - multithreading speedup on SMT systems is highly dependent on number of threads you are running and decisions made by OS scheduler. It is not 100% deterministic! With "true SMP" when you run 2 threads, you get 2x speedup (or 1.95, or 1.80 - it depends on algorithm, but this factor is always same). With SMT when you run 2 threads you may get your 2x speedup - or no speedup at all. Modern OS schedulers do a good job on single-socket hardware, but even in this "simple" case they give no guarantees of fair distribution of hardware resources. And things become a bit tricky when you work with multi-socket hardware. On SMT systems the only guaranteed way to 100% utilize your CPU is to create as many worker threads as there are logical cores. In this case OS scheduler has no chance to make its work in a wrong way.

5.4 Linking with Intel MKL

5.4.1 Using lightweight Intel MKL supplied by ALGLIB Project

Commercial edition of ALGLIB includes MKL extensions - special lightweight distribution of Intel MKL, highly optimized numerical library from Intel - and precompiled ALGLIB-MKL interface libraries. Linking your programs with MKL extensions allows you to run ALGLIB with maximum performance.

Current version of ALGLIB features Windows-only MKL extensions, but in future ALGLIB releases we will introduce MKL extensions for Linux systems.

Unlike the rest of the library, MKL extensions are distributed in binary-only form. ALGLIB itself is still distributed in source code form, but Intel MKL and ALGLIB-MKL interface are distributed as precompiled dynamic/static libraries. We can not distribute them in source because of license restrictions associated with Intel MKL. Also due to license restrictions we can not give you direct access to MKL functionality. You may use MKL to accelerate ALGLIB - without paying for MKL license - but you may not call its functions directly. It is technically possible, but strictly prohibited by both MKL's EULA and ALGLIB License Agreement. If you want to work with MKL, you should buy separate license from Intel.

MKL extensions are located in the /cpp/mkl-windows subdirectory of the ALGLIB distribution. This directory includes:

  • mkl4alglib_32.lib - 32-bit import library for Intel MKL
  • mkl4alglib_32.dll - 32-bit external DLL with Intel MKL
  • mkl4alglib_64.lib - 64-bit import library for Intel MKL
  • mkl4alglib_64.dll - 64-bit external DLL with Intel MKL

In order to activate MKL extensions you should:

  • compile ALGLIB source files with following preprocessor symbols defined on at global level:
        AE_OS=AE_WINDOWS (to activate multithreading capabilities)
        AE_CPU=AE_INTEL (to use SSE instructions provided by x86/x64 CPU's)
        AE_MKL (to use Intel MKL functions in ALGLIB)
    If you compile from command line, you may write "/DAE_OS=AE_WINDOWS /DAE_CPU=AE_INTEL /DAE_MKL"
  • depending on CPU architecture, choose 32-bit or 64-bit LIB file - mkl4alglib_32/64.lib - and link it with your application.
  • place mkl4alglib_32/64.dll into directory where it can be found during application startup (usually - application dir)

Examples on linking from command line can be found in the next section.

5.4.2 Using your own installation of Intel MKL

If you bought separate license for Intel MKL, and want to use your own installation of MKL - and not our lightweight distribution - then you should compile ALGLIB as it was told in the previous section, with all necessary preprocessor definitions. But instead of linking with mkl4alglib dynamic library, you should add to your project mkl4alglib.c file from mkl-interface directory and compile it (as C file) along with the rest of ALGLIB.

This C file implements interface between MKL and ALGLIB. Having this file in your project and defining AE_MKL preprocessor definition results in ALGLIB using MKL functions.

However, this C file is just interface! It is your responsibility to make sure that C/C++ compiler can find MKL headers, and appropriate MKL static/dynamic libraries are linked to your application.

If you link ALGLIB with your own installation if Intel MKL, you may do so on any OS where MKL works - Windows or Linux.

5.5 Examples - compiling commercial edition of ALGLIB

5.5.1 Introduction

In this section we'll consider different compilation scenarios for commercial version of ALGLIB - from simple platform-agnostic compilation to linking with MKL extensions.

We assume that you unpacked ALGLIB distribution in the current directory and saved here demo.cpp file, whose code is given below. Thus, in the current directory you should have exactly one file (demo.cpp) and exactly one subdirectory (cpp folder with ALGLIB distribution).

5.5.2 Compiling under Windows

File listing below contains the very basic program which uses ALGLIB to perform matrix-matrix multiplication. After that program evaluates performance of GEMM (function being called) and prints result to console. We'll show how performance of this program continually increases as we add more and more sophisticated compiler options.

demo.cpp
#include <stdio.h>
#include <windows.h>
#include "LinAlg.h"

double counter()
{
    return 0.001*GetTickCount();
}

int main()
{
    alglib::real_2d_array a, b, c;
    int n = 2000;
    int i, j;
    double timeneeded, flops;
    
    // Initialize arrays
    a.setlength(n, n);
    b.setlength(n, n);
    c.setlength(n, n);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
        {
            a[i][j] = alglib::randomreal()-0.5;
            b[i][j] = alglib::randomreal()-0.5;
            c[i][j] = 0.0;
        }
    
    // Set number of worker threads: "4" means "use 4 cores".
    // This line is ignored if AE_OS is UNDEFINED.
    alglib::setnworkers(4);
    
    // Perform matrix-matrix product.
    // We call function with "smp_" prefix, which means that ALGLIB
    // will try to execute it in parallel manner whenever it is possible.
    flops = 2*pow((double)n, (double)3);
    timeneeded = counter();
    alglib::smp_rmatrixgemm(
        n, n, n,
        1.0,
        a, 0, 0, 0,
        b, 0, 0, 1,
        0.0,
        c, 0, 0);
    timeneeded = counter()-timeneeded;
    
    // Evaluate performance
    printf("Performance is %.1f GFLOPS\n", (double)(1.0E-9*flops/timeneeded));
    
    return 0;
}

Examples below cover Windows compilation from command line with MSVC. It is very straightforward to adapt them to compilation from MSVC IDE - or to another compilers. We assume that you already called %VCINSTALLDIR%\bin\amd64\vcvars64.bat batch file which loads 64-bit build environment (or its 32-bit counterpart). We also assume that current directory is clean before example is executed (i.e. it has ONLY demo.cpp file and cpp folder). We used 3.2 GHz 4-core CPU for this test.

First example covers platform-agnostic compilation without optimization settings - the most simple way to compile ALGLIB. However, in platform-agnostic mode ALGLIB is unable to use all performance related features present in commercial edition.

We starts from copying all cpp and h files to current directory, then we will compile them along with demo.cpp. In this and following examples we will omit compiler output for the sake of simplicity.

OS-agnostic mode, no compiler optimizations
> copy cpp\src\*.* .
> cl /I. /EHsc /Fedemo.exe *.cpp
> demo.exe
Performance is 0.7 GFLOPS

Well, 0.7 GFLOPS is not very impressing for a 3.2GHz CPU... Let's add /Ox to compiler parameters.

OS-agnostic mode, /Ox optimization
> copy cpp\src\*.* .
> cl /I. /EHsc /Fedemo.exe /Ox *.cpp
> demo.exe
Performance is 0.9 GFLOPS

Still not impressed. Let's turn on optimizations for x86 architecture: define AE_CPU=AE_INTEL.

OS-agnostic mode, ALGLIB knows it is x86/x64
> copy cpp\src\*.* .
> cl /I. /EHsc /Fedemo.exe /Ox /DAE_CPU=AE_INTEL *.cpp
> demo.exe
Performance is 4.5 GFLOPS

It is good, but we have 4 cores - and only one of them was used. Defining AE_OS=AE_WINDOWS allows ALGLIB to use Windows threads to parallelize execution of some functions.

ALGLIB knows it is Windows on x86/x64 CPU
> copy cpp\src\*.* .
> cl /I. /EHsc /Fedemo.exe /Ox /DAE_CPU=AE_INTEL /DAE_OS=AE_WINDOWS *.cpp
> demo.exe
Performance is 16.0 GFLOPS

Not bad. And now we are ready to the final test - linking with MKL extensions.

Linking with MKL extensions differs a bit from standard way of linking with ALGLIB. ALGLIB itself is compiled with one more preprocessor definition: we define AE_MKL symbol. We also link ALGLIB with appropriate (32-bit or 64-bit) mkl4alglib static library, which is import library for special lightweight MKL distribution, shipped with ALGLIB for no additional price. We also should copy to current directory appropriate mkl4alglib DLL file which contains Intel MKL.

Linking with MKL extensions
> copy cpp\src\*.* .
> copy cpp\mkl-windows\mkl4alglib_64.lib .
> copy cpp\mkl-windows\mkl4alglib_64.dll .
> cl /I. /EHsc /Fedemo.exe /Ox /DAE_CPU=AE_INTEL /DAE_OS=AE_WINDOWS /DAE_MKL demo.cpp mkl4alglib_64.lib
> demo.exe
Performance is 33.1 GFLOPS

From 0.7 GFLOPS to 33.1 GFLOPS - you may see that commercial version of ALGLIB is really worth it!

6 Using ALGLIB

6.1 Thread-safety

Both open source and commercial versions of ALGLIB are 100% thread-safe as long as different user threads work with different instances of objects/arrays. Thread-safety is guaranteed by having no global shared variables.

However, any kind of sharing ALGLIB objects/arrays between different threads is potentially hazardous. Even when this object is seemingly used in read-only mode!

Say, you use ALGLIB neural network NET to process two input vectors X0 and X1, and get two output vectors Y0 and Y1. You may decide that neural network is used in read-only mode which does not change state of NET, because output is written to distinct arrays Y. Thus, you may want to process these vectors from parallel threads.

But it is not read-only operation, even if it looks like this! Neural network object NET allocates internal temporary buffers, which are modified by neural processing functions. Thus, sharing one instance of neural network between two threads is thread-unsafe!

6.2 Global definitions

ALGLIB defines several conditional symbols (all start with "AE_" which means "ALGLIB environment") and two namespaces: alglib_impl (contains computational core) and alglib (contains C++ interface).

Although this manual mentions both alglib_impl and alglib namespaces, only alglib namespace should be used by you. It contains user-friendly C++ interface with automatic memory management, exception handling and all other nice features. alglib_impl is less user-friendly, is less documented, and it is too easy to crash your system or cause memory leak if you use it directly.

6.3 Datatypes

ALGLIB (ap.h header) defines several "basic" datatypes (types which are used by all packages) and many package-specific datatypes. "Basic" datatypes are:

  • alglib::ae_int_t - signed integer type used by library
  • alglib::complex - double precision complex datatype, safer replacement for std::complex
  • alglib::ap_error - exception which is thrown by library
  • boolean_1d_array - 1-dimensional boolean array
  • integer_1d_array - 1-dimensional integer array
  • real_1d_array - 1-dimensional real (double precision) array
  • complex_1d_array - 1-dimensional complex array
  • boolean_2d_array - 2-dimensional boolean array
  • integer_2d_array - 2-dimensional integer array
  • real_2d_array - 2-dimensional real (double precision) array
  • complex_2d_array - 2-dimensional complex array

Package-specific datatypes are classes which can be divided into two distinct groups:

  • "struct-like" classes with public fields which you can access directly.
  • "object-like" classes which have no public fields. You should use ALGLIB functions to work with them.

6.4 Constants

The most important constants (defined in the ap.h header) from ALGLIB namespace are:

  • alglib::machineepsilon - small number which is close to the double precision &eps;, but is slightly larger
  • alglib::maxrealnumber - very large number which is close to the maximum real number, but is slightly smaller
  • alglib::minrealnumber - very small number which is close to the minimum nonzero real number, but is slightly larger
  • alglib::fp_nan - NAN (non-signalling under most platforms except for PA-RISC, where it is signalling; but when PA-RISC CPU is in its default state, it is silently converted to the quiet NAN)
  • alglib::fp_posinf - positive infinity
  • alglib::fp_neginf - negative infinity

6.5 Functions

The most important "basic" functions from ALGLIB namespace (ap.h header) are:

  • alglib::randomreal() - returns random real number from [0,1)
  • alglib::randominteger(mx) - returns random integer number from [0,nx); mx must be less than RAND_MAX
  • alglib::fp_eq(v1,v2) - makes IEEE-compliant comparison of two double precision numbers. If numbers are represented with greater precision than specified by IEEE 754 (as with Intel 80-bit FPU), this functions converts them to 64 bits before comparing.
  • alglib::fp_neq(v1,v2) - makes IEEE-compliant comparison of two double precision numbers.
  • alglib::fp_less(v1,v2) - makes IEEE-compliant comparison of two double precision numbers.
  • alglib::fp_less_eq(v1,v2) - makes IEEE-compliant comparison of two double precision numbers.
  • alglib::fp_greater(v1,v2) - makes IEEE-compliant comparison of two double precision numbers.
  • alglib::fp_greater_eq(v1,v2) - makes IEEE-compliant comparison of two double precision numbers.
  • alglib::fp_isnan - checks whether number is NAN
  • alglib::fp_isposinf - checks whether number is +INF
  • alglib::fp_isneginf - checks whether number is -INF
  • alglib::fp_isinf - checks whether number is +INF or -INF
  • alglib::fp_isfinite - checks whether number is finite value (possibly subnormalized)

6.6 Working with vectors and matrices

ALGLIB (ap.h header) supports matrixes and vectors (one-dimensional and two-dimensional arrays) of variable size, with numeration starting from zero.

Everything starts from array creation. You should distinguish the creation of array class instance and the memory allocation for the array. When creating the class instance, you can use constructor without any parameters, that creates an empty array without any elements. An attempt to address them may cause the program failure.

You can use copy and assignment constructors that copy one array into another. If, during the copy operation, the source array has no memory allocated for the array elements, destination array will contain no elements either. If the source array has memory allocated for its elements, destination array will allocate the same amount of memory and copy the elements there. That is, the copy operation yields into two independent arrays with indentical contents.

You can also create array from formatted string like "[]", "[true,FALSE,tRUe]", "[[]]]" or "[[1,2],[3.2,4],[5.2]]" (note: '.' is used as decimal point independently from locale settings).

alglib::boolean_1d_array b1;
b1 = "[true]";

alglib::real_2d_array r2("[[2,3],[3,4]]");
alglib::real_2d_array r2_1("[[]]");
alglib::real_2d_array r2_2(r2);
r2_1 = r2;

alglib::complex_1d_array c2;
c2 = "[]";
c2 = "[0]";
c2 = "[1,2i]";
c2 = "[+1-2i,-1+5i]";
c2 = "[ 4i-2,  8i+2]";
c2 = "[+4i-2, +8i+2]";
c2 = "[-4i-2, -8i+2]";

After an empty array has been created, you can allocate memory for its elements, using the setlength() method. The content of the created array elements is not defined. If the setlength method is called for the array with already allocated memory, then, after changing its parameters, the newly allocated elements also become undefined and the old content is destroyed.

alglib::boolean_1d_array b1;
b1.setlength(2);

alglib::integer_2d_array r2;
r2.setlength(4,3);

Another way to initialize array is to call setcontent() method. This method accepts pointer to data which are copied into newly allocated array. Vectors are stored in contiguous order, matrices are stored row by row.

alglib::real_1d_array r1;
double _r1[] = {2, 3};
r1.setcontent(2,_r1);

alglib::real_2d_array r2;
double _r2[] = {11, 12, 13, 21, 22, 23};
r2.setcontent(2,3,_r2);

To access the array elements, an overloaded operator() or operator[] can used. That is, the code addressing the element of array a with indexes [i,j] can look like a(i,j) or a[i][j].

alglib::integer_1d_array a("[1,2,3]");
alglib::integer_1d_array b("[3,9,27]");
a[0] = b(0);

alglib::integer_2d_array c("[[1,2,3],[9,9,9]]");
alglib::integer_2d_array d("[[3,9,27],[8,8,8]]");
d[1][1] = c(0,0);

You can access contents of 1-dimensional array by calling getcontent() method which returns pointer to the array memory. For historical reasons 2-dimensional arrays do not provide getcontent() method, but you can use create reference to any element of array. 2-dimensional arrays store data in row-major order with aligned rows (i.e. generally distance between rows is not equal to number of columns). You can get stride (distance between consequtive elements in different rows) with getstride() call.

alglib::integer_1d_array a("[1,2]");
alglib::real_2d_array b("[[0,1],[10,11]]");

alglib::ae_int_t *a_row = a.getcontent();

// all three pointers point to the same location
double *b_row0 = &b[0][0];
double *b_row0_2 = &b(0,0);
double *b_row0_3 = b[0];

// advancing to the next row of 2-dimensional array
double *b_row1 = b_row0 + b.getstride();

Finally, you can get array size with length(), rows() or cols() methods:

alglib::integer_1d_array a("[1,2]");
alglib::real_2d_array b("[[0,1],[10,11]]");

printf("%ld\n", (long)a.length());
printf("%ld\n", (long)b.rows());
printf("%ld\n", (long)b.cols());

6.7 Using functions: 'expert' and 'friendly' interfaces

Most ALGLIB functions provide two interfaces: 'expert' and 'friendly'. What is the difference between two? When you use 'friendly' interface, ALGLIB:

  • tries to automatically determine size of input arguments
  • throws an exception when arguments have inconsistent size (for example, square matrix is expected, but non-square is passed; another example - two parameters must have same size, but have different size)
  • if semantics of input parameter assumes that it is symmetric/Hermitian matrix, checks that lower triangle is equal to upper triangle (conjugate of upper triangle) and throws an exception otherwise
  • if semantics of output parameter assumes that it is symmetric/Hermitian matrix, returns full matrix (both upper and lower triangles)

When you use 'expert' interface, ALGLIB:

  • requires caller to explicitly specify size of input arguments. If vector/matrix is larger than size being specified (say, N), only N leading elements are used
  • if semantics of input parameter assumes that it is symmetric/Hermitian matrix, uses only upper or lower triangle of input matrix and requires caller to specify what triangle to use
  • if semantics of output parameter assumes that it is symmetric/Hermitian matrix, returns only upper or lower triangle (when you look at specific function, it is clear what triangle is returned)

Here are several examples of 'friendly' and 'expert' interfaces:

#include "interpolation.h"

...

alglib::real_1d_array    x("[0,1,2,3]");
alglib::real_1d_array    y("[1,5,3,9]");
alglib::real_1d_array   y2("[1,5,3,9,0]");
alglib::spline1dinterpolant s;

alglib::spline1dbuildlinear(x, y, 4, s);  // 'expert' interface is used
alglib::spline1dbuildlinear(x, y, s);     // 'friendly' interface - input size is
                                          // automatically determined

alglib::spline1dbuildlinear(x, y2, 4, s); // y2.length() is 5, but it will work

alglib::spline1dbuildlinear(x, y2, s);    // it won't work because sizes of x and y2
                                          // are inconsistent

'Friendly' interface - matrix semantics:

#include "linalg.h"

...

alglib::real_2d_array a;
alglib::matinvreport  rep;
alglib::ae_int_t      info;

// 
// 'Friendly' interface: spdmatrixinverse() accepts and returns symmetric matrix
// 

// symmetric positive definite matrix
a = "[[2,1],[1,2]]";

// after this line A will contain [[0.66,-0.33],[-0.33,0.66]]
// which is symmetric too
alglib::spdmatrixinverse(a, info, rep); 

// you may try to pass nonsymmetric matrix
a = "[[2,1],[0,2]]";

// but exception will be thrown in such case
alglib::spdmatrixinverse(a, info, rep); 

Same function but with 'expert' interface:

#include "linalg.h"

...

alglib::real_2d_array a;
alglib::matinvreport  rep;
alglib::ae_int_t      info;

// 
// 'Expert' interface, spdmatrixinverse()
// 

// only upper triangle is used; a[1][0] is initialized by NAN,
// but it can be arbitrary number
a = "[[2,1],[NAN,2]]";

// after this line A will contain [[0.66,-0.33],[NAN,0.66]]
// only upper triangle is modified
alglib::spdmatrixinverse(a, 2 /* N */, true /* upper triangle is used */, info, rep); 

6.8 Handling errors

ALGLIB uses two error handling strategies:

  • returning error code
  • throwing exception

What is actually done depends on function being used and error being reported:

  1. if function returns some error code and has corresponding value for this kind of error, ALLGIB returns error code
  2. if function does not return error code (or returns error code, but there is no code for error being reported), ALGLIB throws alglib::ap_error exception. Exception object has msg parameter which contains short description of error.

To make things clear we consider several examples of error handling.

Example 1. mincgreate function creates nonlinear CG optimizer. It accepts problem size N and initial point X. Several things can go wrong - you may pass array which is too short, filled by NAN's, or otherwise pass incorrect data. However, this function returns no error code - so it throws an exception in case something goes wrong. There is no other way to tell caller that something went wrong.

Example 2. rmatrixinverse function calculates inverse matrix. It returns error code, which is set to +1 when problem is solved and is set to -3 if singular matrix was passed to the function. However, there is no error code for matrix which is non-square or contains infinities. Well, we could have created corresponding error codes - but we didn't. So if you pass singular matrix to rmatrixinverse, you will get completion code -3. But if you pass matrix which contains INF in one of its elements, alglib::ap_error will be thrown.

First error handling strategy (error codes) is used to report "frequent" errors, which can occur during normal execution of user program. Second error handling strategy (exceptions) is used to report "rare" errors which are result of serious flaws in your program (or ALGLIB) - infinities/NAN's in the inputs, inconsistent inputs, etc.

6.9 Working with Level 1 BLAS functions

ALGLIB (ap.h header) includes following Level 1 BLAS functions:

  • alglib::vdotproduct() family, which allows to calculate dot product of two real or complex vectors
  • alglib::vmove() family, which allows to copy real/complex vector to another location with optimal multiplication by real/complex value
  • alglib::vmoveneg() family, which allows to copy real/complex vector to another location with multiplication by -1
  • alglib::vadd() and alglib::vsub() families, which allows to add or subtract two real/complex vectors with optimal multiplication by real/complex value
  • alglib::vmul() family, which implements in-place multiplication of real/complex vector by real/complex value

Each Level 1 BLAS function accepts input stride and output stride, which are expected to be positive. Input and output vectors should not overlap. Functions operating with complex vectors accept additional parameter conj_src, which specifies whether input vector is conjugated or not.

For each real/complex function there exists "simple" companion which accepts no stride or conjugation modifier. "Simple" function assumes that input/output stride is +1, and no input conjugation is required.

alglib::real_1d_array    rvec("[0,1,2,3]");
alglib::real_2d_array    rmat("[[1,2],[3,4]]");
alglib::complex_1d_array cvec("[0+1i,1+2i,2-1i,3-2i]");
alglib::complex_2d_array cmat("[[3i,1],[9,2i]]");

alglib::vmove(&rvec[0],  1, &rmat[0][0], rmat.getstride(), 2); // now rvec is [1,3,2,3]

alglib::vmove(&cvec[0],  1, &cmat[0][0], rmat.getstride(), "No conj", 2); // now cvec is [3i, 9, 2-1i, 3-2i]
alglib::vmove(&cvec[2],  1, &cmat[0][0], 1,                "Conj", 2);    // now cvec is [3i, 9, -3i,  1]

Here is full list of Level 1 BLAS functions implemented in ALGLIB:

double vdotproduct(
    const double *v0,
     ae_int_t stride0,
     const double *v1,
     ae_int_t stride1,
     ae_int_t n);
double vdotproduct(
    const double *v1,
     const double *v2,
     ae_int_t N);

alglib::complex vdotproduct(
    const alglib::complex *v0,
     ae_int_t stride0,
     const char *conj0,
     const alglib::complex *v1,
     ae_int_t stride1,
     const char *conj1,
     ae_int_t n);
alglib::complex vdotproduct(
    const alglib::complex *v1,
     const alglib::complex *v2,
     ae_int_t N);

void vmove(
    double *vdst,
      ae_int_t stride_dst,
     const double* vsrc,
      ae_int_t stride_src,
     ae_int_t n);
void vmove(
    double *vdst,
     const double* vsrc,
     ae_int_t N);

void vmove(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex* vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n);
void vmove(
    alglib::complex *vdst,
     const alglib::complex* vsrc,
     ae_int_t N);

void vmoveneg(
    double *vdst,
      ae_int_t stride_dst,
     const double* vsrc,
      ae_int_t stride_src,
     ae_int_t n);
void vmoveneg(
    double *vdst,
     const double *vsrc,
     ae_int_t N);

void vmoveneg(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex* vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n);
void vmoveneg(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N);

void vmove(
    double *vdst,
      ae_int_t stride_dst,
     const double* vsrc,
      ae_int_t stride_src,
     ae_int_t n,
     double alpha);
void vmove(
    double *vdst,
     const double *vsrc,
     ae_int_t N,
     double alpha);

void vmove(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex* vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     double alpha);
void vmove(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     double alpha);

void vmove(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex* vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     alglib::complex alpha);
void vmove(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     alglib::complex alpha);

void vadd(
    double *vdst,
      ae_int_t stride_dst,
     const double *vsrc,
      ae_int_t stride_src,
     ae_int_t n);
void vadd(
    double *vdst,
     const double *vsrc,
     ae_int_t N);

void vadd(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n);
void vadd(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N);

void vadd(
    double *vdst,
      ae_int_t stride_dst,
     const double *vsrc,
      ae_int_t stride_src,
     ae_int_t n,
     double alpha);
void vadd(
    double *vdst,
     const double *vsrc,
     ae_int_t N,
     double alpha);

void vadd(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     double alpha);
void vadd(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     double alpha);

void vadd(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     alglib::complex alpha);
void vadd(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     alglib::complex alpha);

void vsub(
    double *vdst,
      ae_int_t stride_dst,
     const double *vsrc,
      ae_int_t stride_src,
     ae_int_t n);
void vsub(
    double *vdst,
     const double *vsrc,
     ae_int_t N);

void vsub(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n);
void vsub(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N);

void vsub(
    double *vdst,
      ae_int_t stride_dst,
     const double *vsrc,
      ae_int_t stride_src,
     ae_int_t n,
     double alpha);
void vsub(
    double *vdst,
     const double *vsrc,
     ae_int_t N,
     double alpha);

void vsub(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     double alpha);
void vsub(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     double alpha);

void vsub(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     const alglib::complex *vsrc,
     ae_int_t stride_src,
     const char *conj_src,
     ae_int_t n,
     alglib::complex alpha);
void vsub(
    alglib::complex *vdst,
     const alglib::complex *vsrc,
     ae_int_t N,
     alglib::complex alpha);

void vmul(
    double *vdst,
      ae_int_t stride_dst,
     ae_int_t n,
     double alpha);
void vmul(
    double *vdst,
     ae_int_t N,
     double alpha);

void vmul(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     ae_int_t n,
     double alpha);
void vmul(
    alglib::complex *vdst,
     ae_int_t N,
     double alpha);

void vmul(
    alglib::complex *vdst,
     ae_int_t stride_dst,
     ae_int_t n,
     alglib::complex alpha);
void vmul(
    alglib::complex *vdst,
     ae_int_t N,
     alglib::complex alpha);

6.10 Reading data from CSV files

ALGLIB (ap.h header) has alglib::read_csv() function which allows to read data from CSV file. Entire file is loaded into memory as double precision 2D array (alglib::real_2d_array object). This function provides following features:

  • support for ASCI encoding and UTF-8 without BOM (in header names)
  • ability to use any character (comma/tab/space) as field separator (as long as it is distinct from one used for decimal point)
  • ability to use both comma and full stop as decimal point (as long is decimal point is distinct from field separator).
  • support for Unix and Windows text files (CR vs CRLF)

See comments on alglib::read_csv() function for more information about its functionality.

7 Advanced topics

7.1 Testing ALGLIB

There are two test suites in ALGLIB: computational tests and interface tests. Computational tests are located in /tests/test_c.cpp. They are focused on numerical properties of algorithms, stress testing and "deep" tests (large automatically generated problems). They require significant amount of time to finish (tens of minutes).

Interface tests are located in /tests/test_i.cpp. These tests are focused on ability to correctly pass data between computational core and caller, ability to detect simple problems in inputs, and on ability to at least compile ALGLIB with your compiler. They are very fast (about a minute to finish including compilation time).

Running test suite is easy - just

  1. compile one of these files (test_c.cpp or test_i.cpp) along with the rest of the library
  2. launch executable you will get. It may take from several seconds (interface tests) to several minutes (computational tests) to get final results

If you want to be sure that ALGLIB will work with some sophisticated optimization settings, set corresponding flags during compile time. If your compiler/system are not in the list of supported ones, we recommend you to run both test suites. But if you are running out of time, run at least test_i.cpp.

8 ALGLIB packages and subpackages

8.1 AlglibMisc package

hqrnd High quality random numbers generator
nearestneighbor Nearest neighbor search: approximate and exact
xdebug Debug functions to test ALGLIB interface generator
 

8.2 DataAnalysis package

bdss Basic dataset functions
clustering Clustering functions (hierarchical, k-means, k-means++)
datacomp Backward compatibility functions
dforest Decision forest classifier (regression model)
filters Different filters used in data analysis
lda Linear discriminant analysis
linreg Linear models
logit Logit models
mcpd Markov Chains for Population/proportional Data
mlpbase Basic functions for neural networks
mlpe Basic functions for neural ensemble models
mlptrain Neural network training
pca Principal component analysis
 

8.3 DiffEquations package

odesolver Ordinary differential equation solver
 

8.4 FastTransforms package

conv Fast real/complex convolution
corr Fast real/complex cross-correlation
fft Real/complex FFT
fht Real Fast Hartley Transform
 

8.5 Integration package

autogk Adaptive 1-dimensional integration
gkq Gauss-Kronrod quadrature generator
gq Gaussian quadrature generator
 

8.6 Interpolation package

idwint Inverse distance weighting: interpolation/fitting
lsfit Linear and nonlinear least-squares solvers
parametric Parametric curves
polint Polynomial interpolation/fitting
ratint Rational interpolation/fitting
rbf Scattered 2/3-dimensional interpolation with RBF models
spline1d 1D spline interpolation/fitting
spline2d 2D spline interpolation
spline3d 3D spline interpolation
 

8.7 LinAlg package

ablas Level 2 and Level 3 BLAS operations
bdsvd Bidiagonal SVD
evd Eigensolvers
inverseupdate Sherman-Morrison update of the inverse matrix
matdet Determinant calculation
matgen Random matrix generation
matinv Matrix inverse
normestimator Estimates norm of the sparse matrix (from below)
ortfac Real/complex QR/LQ, bi(tri)diagonal, Hessenberg decompositions
rcond Condition number estimate
schur Schur decomposition
sparse Sparse matrices
spdgevd Generalized symmetric eigensolver
svd Singular value decomposition
trfac LU and Cholesky decompositions (dense and sparse)
 

8.8 Optimization package

minbleic Bound constrained optimizer with additional linear equality/inequality constraints
mincg Conjugate gradient optimizer
mincomp Backward compatibility functions
minlbfgs Limited memory BFGS optimizer
minlm Improved Levenberg-Marquardt optimizer
minnlc Nonlinearly constrained optimizer
minns Nonsmooth constrained optimizer
minqp Quadratic programming with bound and linear equality/inequality constraints
 

8.9 Solvers package

densesolver Dense linear system solver
lincg Sparse linear CG solver
linlsqr Sparse linear LSQR solver
nleq Solvers for nonlinear equations
polynomialsolver Polynomial solver
 

8.10 SpecialFunctions package

airyf Airy functions
bessel Bessel functions
betaf Beta function
binomialdistr Binomial distribution
chebyshev Chebyshev polynomials
chisquaredistr Chi-Square distribution
dawson Dawson integral
elliptic Elliptic integrals
expintegrals Exponential integrals
fdistr F-distribution
fresnel Fresnel integrals
gammafunc Gamma function
hermite Hermite polynomials
ibetaf Incomplete beta function
igammaf Incomplete gamma function
jacobianelliptic Jacobian elliptic functions
laguerre Laguerre polynomials
legendre Legendre polynomials
normaldistr Normal distribution
poissondistr Poisson distribution
psif Psi function
studenttdistr Student's t-distribution
trigintegrals Trigonometric integrals
 

8.11 Statistics package

basestat Mean, variance, covariance, correlation, etc.
correlationtests Hypothesis testing: correlation tests
jarquebera Hypothesis testing: Jarque-Bera test
mannwhitneyu Hypothesis testing: Mann-Whitney-U test
stest Hypothesis testing: sign test
studentttests Hypothesis testing: Student's t-test
variancetests Hypothesis testing: F-test and one-sample variance test
wsr Hypothesis testing: Wilcoxon signed rank test
 
cmatrixcopy
cmatrixgemm
cmatrixherk
cmatrixlefttrsm
cmatrixmv
cmatrixrank1
cmatrixrighttrsm
cmatrixsyrk
cmatrixtranspose
rmatrixcopy
rmatrixenforcesymmetricity
rmatrixgemm
rmatrixlefttrsm
rmatrixmv
rmatrixrank1
rmatrixrighttrsm
rmatrixsyrk
rmatrixtranspose
ablas_d_gemm Matrix multiplication (single-threaded)
ablas_d_syrk Symmetric rank-K update (single-threaded)
ablas_smp_gemm Matrix multiplication (multithreaded)
ablas_smp_syrk Symmetric rank-K update (multithreaded)
/************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/
void alglib::cmatrixcopy( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t ia, ae_int_t ja, complex_2d_array& b, ae_int_t ib, ae_int_t jb);
/************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition, conjugate transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition Beta - coefficient C - matrix (PREALLOCATED, large enough to store result) IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixgemm( ae_int_t m, ae_int_t n, ae_int_t k, alglib::complex alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, complex_2d_array b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, alglib::complex beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc); void alglib::smp_cmatrixgemm( ae_int_t m, ae_int_t n, ae_int_t k, alglib::smp_complex alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, complex_2d_array b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, alglib::smp_complex beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C where: * C is NxN Hermitian matrix given by its upper/lower triangle * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^H is calculated * 2 - A^H*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether upper or lower triangle of C is updated; this function updates only one half of C, leaving other half unchanged (not referenced at all). -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixherk( ae_int_t n, ae_int_t k, double alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper); void alglib::smp_cmatrixherk( ae_int_t n, ae_int_t k, double alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlefttrsm( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, complex_2d_array& x, ae_int_t i2, ae_int_t j2); void alglib::smp_cmatrixlefttrsm( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, complex_2d_array& x, ae_int_t i2, ae_int_t j2);
/************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) M>=0 N - number of columns of op(A) N>=0 A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T * OpA=2 => op(A) = A^H X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixmv( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t opa, complex_1d_array x, ae_int_t ix, complex_1d_array& y, ae_int_t iy);
/************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/
void alglib::cmatrixrank1( ae_int_t m, ae_int_t n, complex_2d_array& a, ae_int_t ia, ae_int_t ja, complex_1d_array& u, ae_int_t iu, complex_1d_array& v, ae_int_t iv);
/************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition, conjugate transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition * 2 - conjugate transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixrighttrsm( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, complex_2d_array& x, ae_int_t i2, ae_int_t j2); void alglib::smp_cmatrixrighttrsm( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, complex_2d_array& x, ae_int_t i2, ae_int_t j2);
/************************************************************************* This subroutine is an older version of CMatrixHERK(), one with wrong name (it is HErmitian update, not SYmmetric). It is left here for backward compatibility. -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixsyrk( ae_int_t n, ae_int_t k, double alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper); void alglib::smp_cmatrixsyrk( ae_int_t n, ae_int_t k, double alpha, complex_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, complex_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper);
/************************************************************************* Cache-oblivous complex "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/
void alglib::cmatrixtranspose( ae_int_t m, ae_int_t n, complex_2d_array a, ae_int_t ia, ae_int_t ja, complex_2d_array& b, ae_int_t ib, ae_int_t jb);
/************************************************************************* Copy Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/
void alglib::rmatrixcopy( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t ia, ae_int_t ja, real_2d_array& b, ae_int_t ib, ae_int_t jb);
/************************************************************************* This code enforces symmetricy of the matrix by copying Upper part to lower one (or vice versa). INPUT PARAMETERS: A - matrix N - number of rows/columns IsUpper - whether we want to copy upper triangle to lower one (True) or vice versa (False). *************************************************************************/
void alglib::rmatrixenforcesymmetricity( real_2d_array& a, ae_int_t n, bool isupper);
/************************************************************************* This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: * C is MxN general matrix * op1(A) is MxK matrix * op2(B) is KxN matrix * "op" may be identity transformation, transposition Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. IMPORTANT: This function does NOT preallocate output matrix C, it MUST be preallocated by caller prior to calling this function. In case C does not have enough space to store result, exception will be generated. INPUT PARAMETERS M - matrix size, M>0 N - matrix size, N>0 K - matrix size, K>0 Alpha - coefficient A - matrix IA - submatrix offset JA - submatrix offset OpTypeA - transformation type: * 0 - no transformation * 1 - transposition B - matrix IB - submatrix offset JB - submatrix offset OpTypeB - transformation type: * 0 - no transformation * 1 - transposition Beta - coefficient C - PREALLOCATED output matrix, large enough to store result IC - submatrix offset JC - submatrix offset -- ALGLIB routine -- 2009-2013 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixgemm( ae_int_t m, ae_int_t n, ae_int_t k, double alpha, real_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, real_2d_array b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, real_2d_array& c, ae_int_t ic, ae_int_t jc); void alglib::smp_rmatrixgemm( ae_int_t m, ae_int_t n, ae_int_t k, double alpha, real_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, real_2d_array b, ae_int_t ib, ae_int_t jb, ae_int_t optypeb, double beta, real_2d_array& c, ae_int_t ic, ae_int_t jc);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates op(A^-1)*X where: * X is MxN general matrix * A is MxM upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlefttrsm( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, real_2d_array& x, ae_int_t i2, ae_int_t j2); void alglib::smp_rmatrixlefttrsm( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, real_2d_array& x, ae_int_t i2, ae_int_t j2);
/************************************************************************* Matrix-vector product: y := op(A)*x INPUT PARAMETERS: M - number of rows of op(A) N - number of columns of op(A) A - target matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpA - operation type: * OpA=0 => op(A) = A * OpA=1 => op(A) = A^T X - input vector IX - subvector offset IY - subvector offset Y - preallocated matrix, must be large enough to store result OUTPUT PARAMETERS: Y - vector which stores result if M=0, then subroutine does nothing. if N=0, Y is filled by zeros. -- ALGLIB routine -- 28.01.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixmv( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t opa, real_1d_array x, ae_int_t ix, real_1d_array& y, ae_int_t iy);
/************************************************************************* Rank-1 correction: A := A + u*v' INPUT PARAMETERS: M - number of rows N - number of columns A - target matrix, MxN submatrix is updated IA - submatrix offset (row index) JA - submatrix offset (column index) U - vector #1 IU - subvector offset V - vector #2 IV - subvector offset *************************************************************************/
void alglib::rmatrixrank1( ae_int_t m, ae_int_t n, real_2d_array& a, ae_int_t ia, ae_int_t ja, real_1d_array& u, ae_int_t iu, real_1d_array& v, ae_int_t iv);
/************************************************************************* This subroutine calculates X*op(A^-1) where: * X is MxN general matrix * A is NxN upper/lower triangular/unitriangular matrix * "op" may be identity transformation, transposition Multiplication result replaces X. Cache-oblivious algorithm is used. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 M - matrix size, N>=0 A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] I1 - submatrix offset J1 - submatrix offset IsUpper - whether matrix is upper triangular IsUnit - whether matrix is unitriangular OpType - transformation type: * 0 - no transformation * 1 - transposition X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] I2 - submatrix offset J2 - submatrix offset -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixrighttrsm( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, real_2d_array& x, ae_int_t i2, ae_int_t j2); void alglib::smp_rmatrixrighttrsm( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t i1, ae_int_t j1, bool isupper, bool isunit, ae_int_t optype, real_2d_array& x, ae_int_t i2, ae_int_t j2);
/************************************************************************* This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C where: * C is NxN symmetric matrix given by its upper/lower triangle * A is NxK matrix when A*A^T is calculated, KxN matrix otherwise Additional info: * cache-oblivious algorithm is used. * multiplication result replaces C. If Beta=0, C elements are not used in calculations (not multiplied by zero - just not referenced) * if Alpha=0, A is not used (not multiplied by zero - just not referenced) * if both Beta and Alpha are zero, C is filled by zeros. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Because starting/stopping worker thread always ! involves some overhead, parallelism starts to be profitable for N's ! larger than 128. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS N - matrix size, N>=0 K - matrix size, K>=0 Alpha - coefficient A - matrix IA - submatrix offset (row index) JA - submatrix offset (column index) OpTypeA - multiplication type: * 0 - A*A^T is calculated * 2 - A^T*A is calculated Beta - coefficient C - preallocated input/output matrix IC - submatrix offset (row index) JC - submatrix offset (column index) IsUpper - whether C is upper triangular or lower triangular -- ALGLIB routine -- 16.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsyrk( ae_int_t n, ae_int_t k, double alpha, real_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, real_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper); void alglib::smp_rmatrixsyrk( ae_int_t n, ae_int_t k, double alpha, real_2d_array a, ae_int_t ia, ae_int_t ja, ae_int_t optypea, double beta, real_2d_array& c, ae_int_t ic, ae_int_t jc, bool isupper);

Examples:   [1]  [2]  

/************************************************************************* Cache-oblivous real "copy-and-transpose" Input parameters: M - number of rows N - number of columns A - source matrix, MxN submatrix is copied and transposed IA - submatrix offset (row index) JA - submatrix offset (column index) B - destination matrix, must be large enough to store result IB - submatrix offset (row index) JB - submatrix offset (column index) *************************************************************************/
void alglib::rmatrixtranspose( ae_int_t m, ae_int_t n, real_2d_array a, ae_int_t ia, ae_int_t ja, real_2d_array& b, ae_int_t ib, ae_int_t jb);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array a = "[[2,1],[1,3]]";
    real_2d_array b = "[[2,1],[0,1]]";
    real_2d_array c = "[[0,0],[0,0]]";

    //
    // rmatrixgemm() function allows us to calculate matrix product C:=A*B or
    // to perform more general operation, C:=alpha*op1(A)*op2(B)+beta*C,
    // where A, B, C are rectangular matrices, op(X) can be X or X^T,
    // alpha and beta are scalars.
    //
    // This function:
    // * can apply transposition and/or multiplication by scalar to operands
    // * can use arbitrary part of matrices A/B (given by submatrix offset)
    // * can store result into arbitrary part of C
    // * for performance reasons requires C to be preallocated
    //
    // Parameters of this function are:
    // * M, N, K            -   sizes of op1(A) (which is MxK), op2(B) (which
    //                          is KxN) and C (which is MxN)
    // * Alpha              -   coefficient before A*B
    // * A, IA, JA          -   matrix A and offset of the submatrix
    // * OpTypeA            -   transformation type:
    //                          0 - no transformation
    //                          1 - transposition
    // * B, IB, JB          -   matrix B and offset of the submatrix
    // * OpTypeB            -   transformation type:
    //                          0 - no transformation
    //                          1 - transposition
    // * Beta               -   coefficient before C
    // * C, IC, JC          -   preallocated matrix C and offset of the submatrix
    //
    // Below we perform simple product C:=A*B (alpha=1, beta=0)
    //
    // IMPORTANT: this function works with preallocated C, which must be large
    //            enough to store multiplication result.
    //
    ae_int_t m = 2;
    ae_int_t n = 2;
    ae_int_t k = 2;
    double alpha = 1.0;
    ae_int_t ia = 0;
    ae_int_t ja = 0;
    ae_int_t optypea = 0;
    ae_int_t ib = 0;
    ae_int_t jb = 0;
    ae_int_t optypeb = 0;
    double beta = 0.0;
    ae_int_t ic = 0;
    ae_int_t jc = 0;
    rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[4,3],[2,4]]

    //
    // Now we try to apply some simple transformation to operands: C:=A*B^T
    //
    optypeb = 1;
    rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[5,1],[5,3]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // rmatrixsyrk() function allows us to calculate symmetric rank-K update
    // C := beta*C + alpha*A'*A, where C is square N*N matrix, A is square K*N
    // matrix, alpha and beta are scalars. It is also possible to update by
    // adding A*A' instead of A'*A.
    //
    // Parameters of this function are:
    // * N, K       -   matrix size
    // * Alpha      -   coefficient before A
    // * A, IA, JA  -   matrix and submatrix offsets
    // * OpTypeA    -   multiplication type:
    //                  * 0 - A*A^T is calculated
    //                  * 2 - A^T*A is calculated
    // * Beta       -   coefficient before C
    // * C, IC, JC  -   preallocated input/output matrix and submatrix offsets
    // * IsUpper    -   whether upper or lower triangle of C is updated;
    //                  this function updates only one half of C, leaving
    //                  other half unchanged (not referenced at all).
    //
    // Below we will show how to calculate simple product C:=A'*A
    //
    // NOTE: beta=0 and we do not use previous value of C, but still it
    //       MUST be preallocated.
    //
    ae_int_t n = 2;
    ae_int_t k = 1;
    double alpha = 1.0;
    ae_int_t ia = 0;
    ae_int_t ja = 0;
    ae_int_t optypea = 2;
    double beta = 0.0;
    ae_int_t ic = 0;
    ae_int_t jc = 0;
    bool isupper = true;
    real_2d_array a = "[[1,2]]";

    // preallocate space to store result
    real_2d_array c = "[[0,0],[0,0]]";

    // calculate product, store result into upper part of c
    rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper);

    // output result.
    // IMPORTANT: lower triangle of C was NOT updated!
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[1,2],[0,4]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we assume that you already know how to work with
    // rmatrixgemm() function. Below we concentrate on its multithreading
    // capabilities.
    //
    // SMP edition of ALGLIB includes smp_rmatrixgemm() - multithreaded
    // version of rmatrixgemm() function. In the basic edition of ALGLIB
    // (GPL edition or commercial version without SMP support) this function
    // just calls single-threaded stub. So, you may call this function from
    // ANY edition of ALGLIB, but only in SMP edition it will work in really
    // multithreaded mode.
    //
    // In order to use multithreading, you have to:
    // 1) Install SMP edition of ALGLIB.
    // 2) This step is specific for C++ users: you should activate OS-specific
    //    capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems)
    //    or AE_OS=AE_WINDOWS (for Windows systems).
    //    C# users do not have to perform this step because C# programs are
    //    portable across different systems without OS-specific tuning.
    // 3) Allow ALGLIB to know about number of worker threads to use:
    //    a) autodetection (C++, C#):
    //          ALGLIB will automatically determine number of CPU cores and
    //          (by default) will use all cores except for one. Say, on 4-core
    //          system it will use three cores - unless you manually told it
    //          to use more or less. It will keep your system responsive during
    //          lengthy computations.
    //          Such behavior may be changed with setnworkers() call:
    //          * alglib::setnworkers(0)  = use all cores
    //          * alglib::setnworkers(-1) = leave one core unused
    //          * alglib::setnworkers(-2) = leave two cores unused
    //          * alglib::setnworkers(+2) = use 2 cores (even if you have more)
    //    b) manual specification (C++, C#):
    //          You may want to specify maximum number of worker threads during
    //          compile time by means of preprocessor definition AE_NWORKERS.
    //          For C++ it will be "AE_NWORKERS=X" where X can be any positive number.
    //          For C# it is "AE_NWORKERSX", where X should be replaced by number of
    //          workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...).
    //          You can add this definition to compiler command line or change
    //          corresponding project settings in your IDE.
    //
    // After you installed and configured SMP edition of ALGLIB, you may choose
    // between serial and multithreaded versions of SMP-capable functions:
    // * serial version works as usual, in the context of the calling thread
    // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker
    //   threads, inserts task in the worker queue, and waits for completion of
    //   the task. All processing is done in context of worker thread(s).
    //
    // NOTE: because starting/stopping worker threads costs thousands of CPU cycles,
    //       you should not use multithreading for lightweight computational problems.
    //
    // NOTE: some old POSIX-compatible operating systems do not support
    //       sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order
    //       to automatically determine number of active cores. On these systems
    //       you should specify number of cores manually at compile time.
    //       Without it ALGLIB will run in single-threaded mode.
    //
    // Now, back to our example. In this example we will show you:
    // * how to call SMP version of rmatrixgemm(). Because we work with tiny 2x2
    //   matrices, we won't expect to see ANY speedup from using multithreading.
    //   The only purpose of this demo is to show how to call SMP functions.
    // * how to modify number of worker threads used by ALGLIB
    //
    real_2d_array a = "[[2,1],[1,3]]";
    real_2d_array b = "[[2,1],[0,1]]";
    real_2d_array c = "[[0,0],[0,0]]";
    ae_int_t m = 2;
    ae_int_t n = 2;
    ae_int_t k = 2;
    double alpha = 1.0;
    ae_int_t ia = 0;
    ae_int_t ja = 0;
    ae_int_t optypea = 0;
    ae_int_t ib = 0;
    ae_int_t jb = 0;
    ae_int_t optypeb = 0;
    double beta = 0.0;
    ae_int_t ic = 0;
    ae_int_t jc = 0;

    // serial code
    c = "[[0,0],[0,0]]";
    rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc);

    // SMP code with default number of worker threads
    c = "[[0,0],[0,0]]";
    smp_rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[4,3],[2,4]]

    // override number of worker threads - use two cores
    alglib::setnworkers(+2);
    c = "[[0,0],[0,0]]";
    smp_rmatrixgemm(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[4,3],[2,4]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we assume that you already know how to work with
    // rmatrixsyrk() function. Below we concentrate on its multithreading
    // capabilities.
    //
    // SMP edition of ALGLIB includes smp_rmatrixsyrk() - multithreaded
    // version of rmatrixsyrk() function. In the basic edition of ALGLIB
    // (GPL edition or commercial version without SMP support) this function
    // just calls single-threaded stub. So, you may call this function from
    // ANY edition of ALGLIB, but only in SMP edition it will work in really
    // multithreaded mode.
    //
    // In order to use multithreading, you have to:
    // 1) Install SMP edition of ALGLIB.
    // 2) This step is specific for C++ users: you should activate OS-specific
    //    capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems)
    //    or AE_OS=AE_WINDOWS (for Windows systems).
    //    C# users do not have to perform this step because C# programs are
    //    portable across different systems without OS-specific tuning.
    // 3) Allow ALGLIB to know about number of worker threads to use:
    //    a) autodetection (C++, C#):
    //          ALGLIB will automatically determine number of CPU cores and
    //          (by default) will use all cores except for one. Say, on 4-core
    //          system it will use three cores - unless you manually told it
    //          to use more or less. It will keep your system responsive during
    //          lengthy computations.
    //          Such behavior may be changed with setnworkers() call:
    //          * alglib::setnworkers(0)  = use all cores
    //          * alglib::setnworkers(-1) = leave one core unused
    //          * alglib::setnworkers(-2) = leave two cores unused
    //          * alglib::setnworkers(+2) = use 2 cores (even if you have more)
    //    b) manual specification (C++, C#):
    //          You may want to specify maximum number of worker threads during
    //          compile time by means of preprocessor definition AE_NWORKERS.
    //          For C++ it will be "AE_NWORKERS=X" where X can be any positive number.
    //          For C# it is "AE_NWORKERSX", where X should be replaced by number of
    //          workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...).
    //          You can add this definition to compiler command line or change
    //          corresponding project settings in your IDE.
    //
    // After you installed and configured SMP edition of ALGLIB, you may choose
    // between serial and multithreaded versions of SMP-capable functions:
    // * serial version works as usual, in the context of the calling thread
    // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker
    //   threads, inserts task in the worker queue, and waits for completion of
    //   the task. All processing is done in context of worker thread(s).
    //
    // NOTE: because starting/stopping worker threads costs thousands of CPU cycles,
    //       you should not use multithreading for lightweight computational problems.
    //
    // NOTE: some old POSIX-compatible operating systems do not support
    //       sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order
    //       to automatically determine number of active cores. On these systems
    //       you should specify number of cores manually at compile time.
    //       Without it ALGLIB will run in single-threaded mode.
    //
    // Now, back to our example. In this example we will show you:
    // * how to call SMP version of rmatrixsyrk(). Because we work with tiny 2x2
    //   matrices, we won't expect to see ANY speedup from using multithreading.
    //   The only purpose of this demo is to show how to call SMP functions.
    // * how to modify number of worker threads used by ALGLIB
    //
    ae_int_t n = 2;
    ae_int_t k = 1;
    double alpha = 1.0;
    ae_int_t ia = 0;
    ae_int_t ja = 0;
    ae_int_t optypea = 2;
    double beta = 0.0;
    ae_int_t ic = 0;
    ae_int_t jc = 0;
    bool isupper = true;
    real_2d_array a = "[[1,2]]";
    real_2d_array c = "[[]]";

    //
    // Default number of worker threads.
    // Preallocate space to store result, call multithreaded version, test.
    //
    // NOTE: this function updates only one triangular part of C. In our
    //       example we choose to update upper triangle.
    //
    c = "[[0,0],[0,0]]";
    smp_rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[1,2],[0,4]]

    //
    // Override default number of worker threads (set to 2).
    // Preallocate space to store result, call multithreaded version, test.
    //
    // NOTE: this function updates only one triangular part of C. In our
    //       example we choose to update upper triangle.
    //
    alglib::setnworkers(+2);
    c = "[[0,0],[0,0]]";
    smp_rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[1,2],[0,4]]
    return 0;
}


airy
/************************************************************************* Airy function Solution of the differential equation y"(x) = xy. The function returns the two independent solutions Ai, Bi and their first derivatives Ai'(x), Bi'(x). Evaluation is by power series summation for small x, by rational minimax approximations for large x. ACCURACY: Error criterion is absolute when function <= 1, relative when function > 1, except * denotes relative error criterion. For large negative x, the absolute error increases as x^1.5. For large positive x, the relative error increases as x^1.5. Arithmetic domain function # trials peak rms IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
void alglib::airy( double x, double& ai, double& aip, double& bi, double& bip);
autogkreport
autogkstate
autogkintegrate
autogkresults
autogksingular
autogksmooth
autogksmoothw
autogk_d1 Integrating f=exp(x) by adaptive integrator
/************************************************************************* Integration report: * TerminationType = completetion code: * -5 non-convergence of Gauss-Kronrod nodes calculation subroutine. * -1 incorrect parameters were specified * 1 OK * Rep.NFEV countains number of function calculations * Rep.NIntervals contains number of intervals [a,b] was partitioned into. *************************************************************************/
class autogkreport { ae_int_t terminationtype; ae_int_t nfev; ae_int_t nintervals; };
/************************************************************************* This structure stores state of the integration algorithm. Although this class has public fields, they are not intended for external use. You should use ALGLIB functions to work with this class: * autogksmooth()/AutoGKSmoothW()/... to create objects * autogkintegrate() to begin integration * autogkresults() to get results *************************************************************************/
class autogkstate { };
/************************************************************************* This function is used to launcn iterations of ODE solver It accepts following parameters: diff - callback which calculates dy/dx for given y and x obj - optional object which is passed to diff; can be NULL -- ALGLIB -- Copyright 07.05.2009 by Bochkanov Sergey *************************************************************************/
void autogkintegrate(autogkstate &state, void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), void *ptr = NULL);

Examples:   [1]  

/************************************************************************* Adaptive integration results Called after AutoGKIteration returned False. Input parameters: State - algorithm state (used by AutoGKIteration). Output parameters: V - integral(f(x)dx,a,b) Rep - optimization report (see AutoGKReport description) -- ALGLIB -- Copyright 14.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::autogkresults( autogkstate state, double& v, autogkreport& rep);

Examples:   [1]  

/************************************************************************* Integration on a finite interval [A,B]. Integrand have integrable singularities at A/B. F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates from below can be used (but these estimates should be greater than -1 too). One of alpha/beta variables (or even both alpha/beta) may be equal to 0, which means than function F(x) is non-singular at A/B. Anyway (singular at bounds or not), function F(x) is supposed to be continuous on (A,B). Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. INPUT PARAMETERS: A, B - interval boundaries (A<B, A=B or A>B) Alpha - power-law coefficient of the F(x) at A, Alpha>-1 Beta - power-law coefficient of the F(x) at B, Beta>-1 OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSmoothW, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::autogksingular( double a, double b, double alpha, double beta, autogkstate& state);
/************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result is calculated with accuracy close to the machine precision. Algorithm works well only with smooth integrands. It may be used with continuous non-smooth integrands, but with less performance. It should never be used with integrands which have integrable singularities at lower or upper limits - algorithm may crash. Use AutoGKSingular in such cases. INPUT PARAMETERS: A, B - interval boundaries (A<B, A=B or A>B) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::autogksmooth(double a, double b, autogkstate& state);

Examples:   [1]  

/************************************************************************* Integration of a smooth function F(x) on a finite interval [a,b]. This subroutine is same as AutoGKSmooth(), but it guarantees that interval [a,b] is partitioned into subintervals which have width at most XWidth. Subroutine can be used when integrating nearly-constant function with narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth subroutine can overlook them. INPUT PARAMETERS: A, B - interval boundaries (A<B, A=B or A>B) OUTPUT PARAMETERS State - structure which stores algorithm state SEE ALSO AutoGKSmooth, AutoGKSingular, AutoGKResults. -- ALGLIB -- Copyright 06.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::autogksmoothw( double a, double b, double xwidth, autogkstate& state);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "integration.h"

using namespace alglib;
void int_function_1_func(double x, double xminusa, double bminusx, double &y, void *ptr) 
{
    // this callback calculates f(x)=exp(x)
    y = exp(x);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates integration of f=exp(x) on [0,1]:
    // * first, autogkstate is initialized
    // * then we call integration function
    // * and finally we obtain results with autogkresults() call
    //
    double a = 0;
    double b = 1;
    autogkstate s;
    double v;
    autogkreport rep;

    autogksmooth(a, b, s);
    alglib::autogkintegrate(s, int_function_1_func);
    autogkresults(s, v, rep);

    printf("%.2f\n", double(v)); // EXPECTED: 1.7182
    return 0;
}


cov2
covm
covm2
pearsoncorr2
pearsoncorrelation
pearsoncorrm
pearsoncorrm2
rankdata
rankdatacentered
sampleadev
samplekurtosis
samplemean
samplemedian
samplemoments
samplepercentile
sampleskewness
samplevariance
spearmancorr2
spearmancorrm
spearmancorrm2
spearmanrankcorrelation
basestat_d_base Basic functionality (moments, adev, median, percentile)
basestat_d_c2 Correlation (covariance) between two random variables
basestat_d_cm Correlation (covariance) between components of random vector
basestat_d_cm2 Correlation (covariance) between two random vectors
/************************************************************************* 2-sample covariance Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: covariance (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
double alglib::cov2(real_1d_array x, real_1d_array y); double alglib::cov2(real_1d_array x, real_1d_array y, ae_int_t n);

Examples:   [1]  

/************************************************************************* Covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::covm(real_2d_array x, real_2d_array& c); void alglib::covm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c); void alglib::smp_covm(real_2d_array x, real_2d_array& c); void alglib::smp_covm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c);

Examples:   [1]  

/************************************************************************* Cross-covariance matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with covariance matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::covm2(real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::covm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c); void alglib::smp_covm2(real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::smp_covm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c);

Examples:   [1]  

/************************************************************************* Pearson product-moment correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Pearson product-moment correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
double alglib::pearsoncorr2(real_1d_array x, real_1d_array y); double alglib::pearsoncorr2(real_1d_array x, real_1d_array y, ae_int_t n);

Examples:   [1]  

/************************************************************************* Obsolete function, we recommend to use PearsonCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
double alglib::pearsoncorrelation( real_1d_array x, real_1d_array y, ae_int_t n);
/************************************************************************* Pearson product-moment correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pearsoncorrm(real_2d_array x, real_2d_array& c); void alglib::pearsoncorrm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c); void alglib::smp_pearsoncorrm(real_2d_array x, real_2d_array& c); void alglib::smp_pearsoncorrm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c);

Examples:   [1]  

/************************************************************************* Pearson product-moment cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pearsoncorrm2( real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::pearsoncorrm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c); void alglib::smp_pearsoncorrm2( real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::smp_pearsoncorrm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c);

Examples:   [1]  

/************************************************************************* This function replaces data in XY by their ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * ranking starts from 0, ends at NFeatures-1 * sum of within-row values is equal to (NFeatures-1)*NFeatures/2 SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/
void alglib::rankdata(real_2d_array& xy); void alglib::rankdata( real_2d_array& xy, ae_int_t npoints, ae_int_t nfeatures); void alglib::smp_rankdata(real_2d_array& xy); void alglib::smp_rankdata( real_2d_array& xy, ae_int_t npoints, ae_int_t nfeatures);
/************************************************************************* This function replaces data in XY by their CENTERED ranks: * XY is processed row-by-row * rows are processed separately * tied data are correctly handled (tied ranks are calculated) * centered ranks are just usual ranks, but centered in such way that sum of within-row values is equal to 0.0. * centering is performed by subtracting mean from each row, i.e it changes mean value, but does NOT change higher moments SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! ones where expected operations count is less than 100.000 INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points NFeatures- number of features OUTPUT PARAMETERS: XY - data are replaced by their within-row ranks; ranking starts from 0, ends at NFeatures-1 -- ALGLIB -- Copyright 18.04.2013 by Bochkanov Sergey *************************************************************************/
void alglib::rankdatacentered(real_2d_array& xy); void alglib::rankdatacentered( real_2d_array& xy, ae_int_t npoints, ae_int_t nfeatures); void alglib::smp_rankdatacentered(real_2d_array& xy); void alglib::smp_rankdatacentered( real_2d_array& xy, ae_int_t npoints, ae_int_t nfeatures);
/************************************************************************* ADev Input parameters: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: ADev- ADev -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::sampleadev(real_1d_array x, double& adev); void alglib::sampleadev(real_1d_array x, ae_int_t n, double& adev);

Examples:   [1]  

/************************************************************************* Calculation of the kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Kurtosis' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
double alglib::samplekurtosis(real_1d_array x); double alglib::samplekurtosis(real_1d_array x, ae_int_t n);
/************************************************************************* Calculation of the mean. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Mean' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
double alglib::samplemean(real_1d_array x); double alglib::samplemean(real_1d_array x, ae_int_t n);
/************************************************************************* Median calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X Output parameters: Median -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::samplemedian(real_1d_array x, double& median); void alglib::samplemedian(real_1d_array x, ae_int_t n, double& median);

Examples:   [1]  

/************************************************************************* Calculation of the distribution moments: mean, variance, skewness, kurtosis. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X OUTPUT PARAMETERS Mean - mean. Variance- variance. Skewness- skewness (if variance<>0; zero otherwise). Kurtosis- kurtosis (if variance<>0; zero otherwise). NOTE: variance is calculated by dividing sum of squares by N-1, not N. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::samplemoments( real_1d_array x, double& mean, double& variance, double& skewness, double& kurtosis); void alglib::samplemoments( real_1d_array x, ae_int_t n, double& mean, double& variance, double& skewness, double& kurtosis);

Examples:   [1]  

/************************************************************************* Percentile calculation. Input parameters: X - sample (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X P - percentile (0<=P<=1) Output parameters: V - percentile -- ALGLIB -- Copyright 01.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::samplepercentile(real_1d_array x, double p, double& v); void alglib::samplepercentile( real_1d_array x, ae_int_t n, double p, double& v);

Examples:   [1]  

/************************************************************************* Calculation of the skewness. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Skewness' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
double alglib::sampleskewness(real_1d_array x); double alglib::sampleskewness(real_1d_array x, ae_int_t n);
/************************************************************************* Calculation of the variance. INPUT PARAMETERS: X - sample N - N>=0, sample size: * if given, only leading N elements of X are processed * if not given, automatically determined from size of X NOTE: This function return result which calculated by 'SampleMoments' function and stored at 'Variance' variable. -- ALGLIB -- Copyright 06.09.2006 by Bochkanov Sergey *************************************************************************/
double alglib::samplevariance(real_1d_array x); double alglib::samplevariance(real_1d_array x, ae_int_t n);
/************************************************************************* Spearman's rank correlation coefficient Input parameters: X - sample 1 (array indexes: [0..N-1]) Y - sample 2 (array indexes: [0..N-1]) N - N>=0, sample size: * if given, only N leading elements of X/Y are processed * if not given, automatically determined from input sizes Result: Spearman's rank correlation coefficient (zero for N=0 or N=1) -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
double alglib::spearmancorr2(real_1d_array x, real_1d_array y); double alglib::spearmancorr2( real_1d_array x, real_1d_array y, ae_int_t n);

Examples:   [1]  

/************************************************************************* Spearman's rank correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X are used * if not given, automatically determined from input size M - M>0, number of variables: * if given, only leading M columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M,M], correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spearmancorrm(real_2d_array x, real_2d_array& c); void alglib::spearmancorrm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c); void alglib::smp_spearmancorrm(real_2d_array x, real_2d_array& c); void alglib::smp_spearmancorrm( real_2d_array x, ae_int_t n, ae_int_t m, real_2d_array& c);

Examples:   [1]  

/************************************************************************* Spearman's rank cross-correlation matrix SMP EDITION OF ALGLIB: ! This function can utilize multicore capabilities of your system. In ! order to do this you have to call version with "smp_" prefix, which ! indicates that multicore code will be used. ! ! This note is given for users of SMP edition; if you use GPL edition, ! or commercial edition of ALGLIB without SMP support, you still will ! be able to call smp-version of this function, but all computations ! will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. ! ! You should remember that starting/stopping worker thread always have ! non-zero cost. Although multicore version is pretty efficient on ! large problems, we do not recommend you to use it on small problems - ! with correlation matrices smaller than 128*128. INPUT PARAMETERS: X - array[N,M1], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation Y - array[N,M2], sample matrix: * J-th column corresponds to J-th variable * I-th row corresponds to I-th observation N - N>=0, number of observations: * if given, only leading N rows of X/Y are used * if not given, automatically determined from input sizes M1 - M1>0, number of variables in X: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size M2 - M2>0, number of variables in Y: * if given, only leading M1 columns of X are used * if not given, automatically determined from input size OUTPUT PARAMETERS: C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) -- ALGLIB -- Copyright 28.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spearmancorrm2( real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::spearmancorrm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c); void alglib::smp_spearmancorrm2( real_2d_array x, real_2d_array y, real_2d_array& c); void alglib::smp_spearmancorrm2( real_2d_array x, real_2d_array y, ae_int_t n, ae_int_t m1, ae_int_t m2, real_2d_array& c);

Examples:   [1]  

/************************************************************************* Obsolete function, we recommend to use SpearmanCorr2(). -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
double alglib::spearmanrankcorrelation( real_1d_array x, real_1d_array y, ae_int_t n);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "statistics.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]";
    double mean;
    double variance;
    double skewness;
    double kurtosis;
    double adev;
    double p;
    double v;

    //
    // Here we demonstrate calculation of sample moments
    // (mean, variance, skewness, kurtosis)
    //
    samplemoments(x, mean, variance, skewness, kurtosis);
    printf("%.1f\n", double(mean)); // EXPECTED: 28.5
    printf("%.1f\n", double(variance)); // EXPECTED: 801.1667
    printf("%.1f\n", double(skewness)); // EXPECTED: 0.5751
    printf("%.1f\n", double(kurtosis)); // EXPECTED: -1.2666

    //
    // Average deviation
    //
    sampleadev(x, adev);
    printf("%.1f\n", double(adev)); // EXPECTED: 23.2

    //
    // Median and percentile
    //
    samplemedian(x, v);
    printf("%.1f\n", double(v)); // EXPECTED: 20.5
    p = 0.5;
    samplepercentile(x, p, v);
    printf("%.1f\n", double(v)); // EXPECTED: 20.5
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "statistics.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We have two samples - x and y, and want to measure dependency between them
    //
    real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]";
    real_1d_array y = "[0,1,2,3,4,5,6,7,8,9]";
    double v;

    //
    // Three dependency measures are calculated:
    // * covariation
    // * Pearson correlation
    // * Spearman rank correlation
    //
    v = cov2(x, y);
    printf("%.2f\n", double(v)); // EXPECTED: 82.5
    v = pearsoncorr2(x, y);
    printf("%.2f\n", double(v)); // EXPECTED: 0.9627
    v = spearmancorr2(x, y);
    printf("%.2f\n", double(v)); // EXPECTED: 1.000
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "statistics.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // X is a sample matrix:
    // * I-th row corresponds to I-th observation
    // * J-th column corresponds to J-th variable
    //
    real_2d_array x = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]";
    real_2d_array c;

    //
    // Three dependency measures are calculated:
    // * covariation
    // * Pearson correlation
    // * Spearman rank correlation
    //
    // Result is stored into C, with C[i,j] equal to correlation
    // (covariance) between I-th and J-th variables of X.
    //
    covm(x, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[1.80,0.60,-1.40],[0.60,0.70,-0.80],[-1.40,-0.80,14.70]]
    pearsoncorrm(x, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[1.000,0.535,-0.272],[0.535,1.000,-0.249],[-0.272,-0.249,1.000]]
    spearmancorrm(x, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[1.000,0.556,-0.306],[0.556,1.000,-0.750],[-0.306,-0.750,1.000]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "statistics.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // X and Y are sample matrices:
    // * I-th row corresponds to I-th observation
    // * J-th column corresponds to J-th variable
    //
    real_2d_array x = "[[1,0,1],[1,1,0],[-1,1,0],[-2,-1,1],[-1,0,9]]";
    real_2d_array y = "[[2,3],[2,1],[-1,6],[-9,9],[7,1]]";
    real_2d_array c;

    //
    // Three dependency measures are calculated:
    // * covariation
    // * Pearson correlation
    // * Spearman rank correlation
    //
    // Result is stored into C, with C[i,j] equal to correlation
    // (covariance) between I-th variable of X and J-th variable of Y.
    //
    covm2(x, y, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[4.100,-3.250],[2.450,-1.500],[13.450,-5.750]]
    pearsoncorrm2(x, y, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[0.519,-0.699],[0.497,-0.518],[0.596,-0.433]]
    spearmancorrm2(x, y, c);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [[0.541,-0.649],[0.216,-0.433],[0.433,-0.135]]
    return 0;
}


/************************************************************************* Optimal binary classification Algorithms finds optimal (=with minimal cross-entropy) binary partition. Internal subroutine. INPUT PARAMETERS: A - array[0..N-1], variable C - array[0..N-1], class numbers (0 or 1). N - array size OUTPUT PARAMETERS: Info - completetion code: * -3, all values of A[] are same (partition is impossible) * -2, one of C[] is incorrect (<0, >1) * -1, incorrect pararemets were passed (N<=0). * 1, OK Threshold- partiton boundary. Left part contains values which are strictly less than Threshold. Right part contains values which are greater than or equal to Threshold. PAL, PBL- probabilities P(0|v<Threshold) and P(1|v<Threshold) PAR, PBR- probabilities P(0|v>=Threshold) and P(1|v>=Threshold) CVE - cross-validation estimate of cross-entropy -- ALGLIB -- Copyright 22.05.2008 by Bochkanov Sergey *************************************************************************/
void alglib::dsoptimalsplit2( real_1d_array a, integer_1d_array c, ae_int_t n, ae_int_t& info, double& threshold, double& pal, double& pbl, double& par, double& pbr, double& cve);
/************************************************************************* Optimal partition, internal subroutine. Fast version. Accepts: A array[0..N-1] array of attributes array[0..N-1] C array[0..N-1] array of class labels TiesBuf array[0..N] temporaries (ties) CntBuf array[0..2*NC-1] temporaries (counts) Alpha centering factor (0<=alpha<=1, recommended value - 0.05) BufR array[0..N-1] temporaries BufI array[0..N-1] temporaries Output: Info error code (">0"=OK, "<0"=bad) RMS training set RMS error CVRMS leave-one-out RMS error Note: content of all arrays is changed by subroutine; it doesn't allocate temporaries. -- ALGLIB -- Copyright 11.12.2008 by Bochkanov Sergey *************************************************************************/
void alglib::dsoptimalsplit2fast( real_1d_array& a, integer_1d_array& c, integer_1d_array& tiesbuf, integer_1d_array& cntbuf, real_1d_array& bufr, integer_1d_array& bufi, ae_int_t n, ae_int_t nc, double alpha, ae_int_t& info, double& threshold, double& rms, double& cvrms);
rmatrixbdsvd
/************************************************************************* Singular value decomposition of a bidiagonal matrix (extended algorithm) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm performs the singular value decomposition of a bidiagonal matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - orthogonal matrices, S - diagonal matrix with non-negative elements on the main diagonal, in descending order. The algorithm finds singular values. In addition, the algorithm can calculate matrices Q and P (more precisely, not the matrices, but their product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, matrices U and VT can be of any type, including identity. Furthermore, the algorithm can calculate Q'*C (this product is calculated more effectively than U*Q, because this calculation operates with rows instead of matrix columns). The feature of the algorithm is its ability to find all singular values including those which are arbitrarily close to 0 with relative accuracy close to machine precision. If the parameter IsFractionalAccuracyRequired is set to True, all singular values will have high relative accuracy close to machine precision. If the parameter is set to False, only the biggest singular value will have relative accuracy close to machine precision. The absolute error of other singular values is equal to the absolute error of the biggest singular value. Input parameters: D - main diagonal of matrix B. Array whose index ranges within [0..N-1]. E - superdiagonal (or subdiagonal) of matrix B. Array whose index ranges within [0..N-2]. N - size of matrix B. IsUpper - True, if the matrix is upper bidiagonal. IsFractionalAccuracyRequired - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. U - matrix to be multiplied by Q. Array whose indexes range within [0..NRU-1, 0..N-1]. The matrix can be bigger, in that case only the submatrix [0..NRU-1, 0..N-1] will be multiplied by Q. NRU - number of rows in matrix U. C - matrix to be multiplied by Q'. Array whose indexes range within [0..N-1, 0..NCC-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCC-1] will be multiplied by Q'. NCC - number of columns in matrix C. VT - matrix to be multiplied by P^T. Array whose indexes range within [0..N-1, 0..NCVT-1]. The matrix can be bigger, in that case only the submatrix [0..N-1, 0..NCVT-1] will be multiplied by P^T. NCVT - number of columns in matrix VT. Output parameters: D - singular values of matrix B in descending order. U - if NRU>0, contains matrix U*Q. VT - if NCVT>0, contains matrix (P^T)*VT. C - if NCC>0, contains matrix Q'*C. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). NOTE: multiplication U*Q is performed by means of transposition to internal buffer, multiplication and backward transposition. It helps to avoid costly columnwise operations and speed-up algorithm. Additional information: The type of convergence is controlled by the internal parameter TOL. If the parameter is greater than 0, the singular values will have relative accuracy TOL. If TOL<0, the singular values will have absolute accuracy ABS(TOL)*norm(B). By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, where Epsilon is the machine precision. It is not recommended to use TOL less than 10*Epsilon since this will considerably slow down the algorithm and may not lead to error decreasing. History: * 31 March, 2007. changed MAXITR from 6 to 12. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1999. *************************************************************************/
bool alglib::rmatrixbdsvd( real_1d_array& d, real_1d_array e, ae_int_t n, bool isupper, bool isfractionalaccuracyrequired, real_2d_array& u, ae_int_t nru, real_2d_array& c, ae_int_t ncc, real_2d_array& vt, ae_int_t ncvt);
/************************************************************************* Modified Bessel function of order zero Returns modified Bessel function of order zero of the argument. The function is defined as i0(x) = j0( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 5.8e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besseli0(double x);
/************************************************************************* Modified Bessel function of order one Returns modified Bessel function of order one of the argument. The function is defined as i1(x) = -i j1( ix ). The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.9e-15 2.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besseli1(double x);
/************************************************************************* Bessel function of order zero Returns Bessel function of order zero of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval the following rational approximation is used: 2 2 (w - r ) (w - r ) P (w) / Q (w) 1 2 3 8 2 where w = x and the two r's are zeros of the function. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 60000 4.2e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselj0(double x);
/************************************************************************* Bessel function of order one Returns Bessel function of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 24 term Chebyshev expansion is used. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 2.6e-16 1.1e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselj1(double x);
/************************************************************************* Bessel function of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The ratio of jn(x) to j0(x) is computed by backward recurrence. First the ratio jn/jn-1 is found by a continued fraction expansion. Then the recurrence relating successive orders is applied until j0 or j1 is reached. If n = 0 or 1 the routine for j0 or j1 is called directly. ACCURACY: Absolute error: arithmetic range # trials peak rms IEEE 0, 30 5000 4.4e-16 7.9e-17 Not suitable for large n or x. Use jv() (fractional order) instead. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besseljn(ae_int_t n, double x);
/************************************************************************* Modified Bessel function, second kind, order zero Returns modified Bessel function of the second kind of order zero of the argument. The range is partitioned into the two intervals [0,8] and (8, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Tested at 2000 random points between 0 and 8. Peak absolute error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselk0(double x);
/************************************************************************* Modified Bessel function, second kind, order one Computes the modified Bessel function of the second kind of order one of the argument. The range is partitioned into the two intervals [0,2] and (2, infinity). Chebyshev polynomial expansions are employed in each interval. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.2e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselk1(double x);
/************************************************************************* Modified Bessel function, second kind, integer order Returns modified Bessel function of the second kind of order n of the argument. The range is partitioned into the two intervals [0,9.55] and (9.55, infinity). An ascending power series is used in the low range, and an asymptotic expansion in the high range. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 90000 1.8e-8 3.0e-10 Error is high only near the crossover point x = 9.55 between the two expansions used. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselkn(ae_int_t nn, double x);
/************************************************************************* Bessel function of the second kind, order zero Returns Bessel function of the second kind, of order zero, of the argument. The domain is divided into the intervals [0, 5] and (5, infinity). In the first interval a rational approximation R(x) is employed to compute y0(x) = R(x) + 2 * log(x) * j0(x) / PI. Thus a call to j0() is required. In the second interval, the Hankel asymptotic expansion is employed with two rational functions of degree 6/6 and 7/7. ACCURACY: Absolute error, when y0(x) < 1; else relative error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.3e-15 1.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::bessely0(double x);
/************************************************************************* Bessel function of second kind of order one Returns Bessel function of the second kind of order one of the argument. The domain is divided into the intervals [0, 8] and (8, infinity). In the first interval a 25 term Chebyshev expansion is used, and a call to j1() is required. In the second, the asymptotic trigonometric representation is employed using two rational functions of degree 5/5. ACCURACY: Absolute error: arithmetic domain # trials peak rms IEEE 0, 30 30000 1.0e-15 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::bessely1(double x);
/************************************************************************* Bessel function of second kind of integer order Returns Bessel function of order n, where n is a (possibly negative) integer. The function is evaluated by forward recurrence on n, starting with values computed by the routines y0() and y1(). If n = 0 or 1 the routine for y0 or y1 is called directly. ACCURACY: Absolute error, except relative when y > 1: arithmetic domain # trials peak rms IEEE 0, 30 30000 3.4e-15 4.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::besselyn(ae_int_t n, double x);
beta
/************************************************************************* Beta function - - | (a) | (b) beta( a, b ) = -----------. - | (a+b) For large arguments the logarithm of the function is evaluated using lgam(), then exponentiated. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 30000 8.1e-14 1.1e-14 Cephes Math Library Release 2.0: April, 1987 Copyright 1984, 1987 by Stephen L. Moshier *************************************************************************/
double alglib::beta(double a, double b);
/************************************************************************* Complemented binomial distribution Returns the sum of the terms k+1 through n of the Binomial probability density: n -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=k+1 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 6.7e-15 8.2e-16 For p between 0 and .001: IEEE 0,100 100000 1.5e-13 2.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::binomialcdistribution(ae_int_t k, ae_int_t n, double p);
/************************************************************************* Binomial distribution Returns the sum of the terms 0 through k of the Binomial probability density: k -- ( n ) j n-j > ( ) p (1-p) -- ( j ) j=0 The terms are not summed directly; instead the incomplete beta integral is employed, according to the formula y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). The arguments must be positive, with p ranging from 0 to 1. ACCURACY: Tested at random points (a,b,p), with p between 0 and 1. a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 4.3e-15 2.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::binomialdistribution(ae_int_t k, ae_int_t n, double p);
/************************************************************************* Inverse binomial distribution Finds the event probability p such that the sum of the terms 0 through k of the Binomial probability density is equal to the given cumulative probability y. This is accomplished using the inverse beta integral function and the relation 1 - p = incbi( n-k, k+1, y ). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between 0.001 and 1: IEEE 0,100 100000 2.3e-14 6.4e-16 IEEE 0,10000 100000 6.6e-12 1.2e-13 For p between 10^-6 and 0.001: IEEE 0,100 100000 2.0e-12 1.3e-14 IEEE 0,10000 100000 1.5e-12 3.2e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invbinomialdistribution(ae_int_t k, ae_int_t n, double y);
/************************************************************************* Calculation of the value of the Chebyshev polynomials of the first and second kinds. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument, -1 <= x <= 1 Result: the value of the Chebyshev polynomial at x *************************************************************************/
double alglib::chebyshevcalculate(ae_int_t r, ae_int_t n, double x);
/************************************************************************* Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/
void alglib::chebyshevcoefficients(ae_int_t n, real_1d_array& c);
/************************************************************************* Summation of Chebyshev polynomials using Clenshaws recurrence formula. This routine calculates c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) or c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) depending on the R. Parameters: r - polynomial kind, either 1 or 2. n - degree, n>=0 x - argument Result: the value of the Chebyshev polynomial at x *************************************************************************/
double alglib::chebyshevsum( real_1d_array c, ae_int_t r, ae_int_t n, double x);
/************************************************************************* Conversion of a series of Chebyshev polynomials to a power series. Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as B[0] + B[1]*X + ... + B[N]*X^N. Input parameters: A - Chebyshev series coefficients N - degree, N>=0 Output parameters B - power series coefficients *************************************************************************/
void alglib::fromchebyshev(real_1d_array a, ae_int_t n, real_1d_array& b);
/************************************************************************* Complemented Chi-square distribution Returns the area under the right hand tail (from x to infinity) of the Chi square probability density function with v degrees of freedom: inf. - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - x where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::chisquarecdistribution(double v, double x);
/************************************************************************* Chi-square distribution Returns the area under the left hand tail (from 0 to x) of the Chi square probability density function with v degrees of freedom. x - 1 | | v/2-1 -t/2 P( x | v ) = ----------- | t e dt v/2 - | | 2 | (v/2) - 0 where x is the Chi-square variable. The incomplete gamma integral is used, according to the formula y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::chisquaredistribution(double v, double x);
/************************************************************************* Inverse of complemented Chi-square distribution Finds the Chi-square argument x such that the integral from x to infinity of the Chi-square density is equal to the given cumulative probability y. This is accomplished using the inverse gamma integral function and the relation x/2 = igami( df/2, y ); ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invchisquaredistribution(double v, double y);
ahcreport
clusterizerstate
kmeansreport
clusterizercreate
clusterizergetdistances
clusterizergetkclusters
clusterizerrunahc
clusterizerrunkmeans
clusterizerseparatedbycorr
clusterizerseparatedbydist
clusterizersetahcalgo
clusterizersetdistances
clusterizersetkmeansinit
clusterizersetkmeanslimits
clusterizersetpoints
clst_ahc Simple hierarchical clusterization with Euclidean distance function
clst_distance Clusterization with different metric types
clst_kclusters Obtaining K top clusters from clusterization tree
clst_kmeans Simple k-means clusterization
clst_linkage Clusterization with different linkage types
/************************************************************************* This structure is used to store results of the agglomerative hierarchical clustering (AHC). Following information is returned: * TerminationType - completion code: * 1 for successful completion of algorithm * -5 inappropriate combination of clustering algorithm and distance function was used. As for now, it is possible only when Ward's method is called for dataset with non-Euclidean distance function. In case negative completion code is returned, other fields of report structure are invalid and should not be used. * NPoints contains number of points in the original dataset * Z contains information about merges performed (see below). Z contains indexes from the original (unsorted) dataset and it can be used when you need to know what points were merged. However, it is not convenient when you want to build a dendrograd (see below). * if you want to build dendrogram, you can use Z, but it is not good option, because Z contains indexes from unsorted dataset. Dendrogram built from such dataset is likely to have intersections. So, you have to reorder you points before building dendrogram. Permutation which reorders point is returned in P. Another representation of merges, which is more convenient for dendorgram construction, is returned in PM. * more information on format of Z, P and PM can be found below and in the examples from ALGLIB Reference Manual. FORMAL DESCRIPTION OF FIELDS: NPoints number of points Z array[NPoints-1,2], contains indexes of clusters linked in pairs to form clustering tree. I-th row corresponds to I-th merge: * Z[I,0] - index of the first cluster to merge * Z[I,1] - index of the second cluster to merge * Z[I,0]<Z[I,1] * clusters are numbered from 0 to 2*NPoints-2, with indexes from 0 to NPoints-1 corresponding to points of the original dataset, and indexes from NPoints to 2*NPoints-2 correspond to clusters generated by subsequent merges (I-th row of Z creates cluster with index NPoints+I). IMPORTANT: indexes in Z[] are indexes in the ORIGINAL, unsorted dataset. In addition to Z algorithm outputs permutation which rearranges points in such way that subsequent merges are performed on adjacent points (such order is needed if you want to build dendrogram). However, indexes in Z are related to original, unrearranged sequence of points. P array[NPoints], permutation which reorders points for dendrogram construction. P[i] contains index of the position where we should move I-th point of the original dataset in order to apply merges PZ/PM. PZ same as Z, but for permutation of points given by P. The only thing which changed are indexes of the original points; indexes of clusters remained same. MergeDist array[NPoints-1], contains distances between clusters being merged (MergeDist[i] correspond to merge stored in Z[i,...]): * CLINK, SLINK and average linkage algorithms report "raw", unmodified distance metric. * Ward's method reports weighted intra-cluster variance, which is equal to ||Ca-Cb||^2 * Sa*Sb/(Sa+Sb). Here A and B are clusters being merged, Ca is a center of A, Cb is a center of B, Sa is a size of A, Sb is a size of B. PM array[NPoints-1,6], another representation of merges, which is suited for dendrogram construction. It deals with rearranged points (permutation P is applied) and represents merges in a form which different from one used by Z. For each I from 0 to NPoints-2, I-th row of PM represents merge performed on two clusters C0 and C1. Here: * C0 contains points with indexes PM[I,0]...PM[I,1] * C1 contains points with indexes PM[I,2]...PM[I,3] * indexes stored in PM are given for dataset sorted according to permutation P * PM[I,1]=PM[I,2]-1 (only adjacent clusters are merged) * PM[I,0]<=PM[I,1], PM[I,2]<=PM[I,3], i.e. both clusters contain at least one point * heights of "subdendrograms" corresponding to C0/C1 are stored in PM[I,4] and PM[I,5]. Subdendrograms corresponding to single-point clusters have height=0. Dendrogram of the merge result has height H=max(H0,H1)+1. NOTE: there is one-to-one correspondence between merges described by Z and PM. I-th row of Z describes same merge of clusters as I-th row of PM, with "left" cluster from Z corresponding to the "left" one from PM. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
class ahcreport { ae_int_t terminationtype; ae_int_t npoints; integer_1d_array p; integer_2d_array z; integer_2d_array pz; integer_2d_array pm; real_1d_array mergedist; };
/************************************************************************* This structure is a clusterization engine. You should not try to access its fields directly. Use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
class clusterizerstate { };
/************************************************************************* This structure is used to store results of the k-means clustering algorithm. Following information is always returned: * NPoints contains number of points in the original dataset * TerminationType contains completion code, negative on failure, positive on success * K contains number of clusters For positive TerminationType we return: * NFeatures contains number of variables in the original dataset * C, which contains centers found by algorithm * CIdx, which maps points of the original dataset to clusters FORMAL DESCRIPTION OF FIELDS: NPoints number of points, >=0 NFeatures number of variables, >=1 TerminationType completion code: * -5 if distance type is anything different from Euclidean metric * -3 for degenerate dataset: a) less than K distinct points, b) K=0 for non-empty dataset. * +1 for successful completion K number of clusters C array[K,NFeatures], rows of the array store centers CIdx array[NPoints], which contains cluster indexes IterationsCount actual number of iterations performed by clusterizer. If algorithm performed more than one random restart, total number of iterations is returned. Energy merit function, "energy", sum of squared deviations from cluster centers -- ALGLIB -- Copyright 27.11.2012 by Bochkanov Sergey *************************************************************************/
class kmeansreport { ae_int_t npoints; ae_int_t nfeatures; ae_int_t terminationtype; ae_int_t iterationscount; double energy; ae_int_t k; real_2d_array c; integer_1d_array cidx; };
/************************************************************************* This function initializes clusterizer object. Newly initialized object is empty, i.e. it does not contain dataset. You should use it as follows: 1. creation 2. dataset is added with ClusterizerSetPoints() 3. additional parameters are set 3. clusterization is performed with one of the clustering functions -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizercreate(clusterizerstate& s);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function returns distance matrix for dataset COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm, non-squared) * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| OUTPUT PARAMETERS: D - array[NPoints,NPoints], distance matrix (full matrix is returned, with lower and upper triangles) NOTE: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizergetdistances( real_2d_array xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, real_2d_array& d); void alglib::smp_clusterizergetdistances( real_2d_array xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype, real_2d_array& d);
/************************************************************************* This function takes as input clusterization report Rep, desired clusters count K, and builds top K clusters from hierarchical clusterization tree. It returns assignment of points to clusters (array of cluster indexes). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY K - desired number of clusters, 1<=K<=NPoints. K can be zero only when NPoints=0. OUTPUT PARAMETERS: CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]<CZ[I+1]. NOTE: K clusters built by this subroutine are assumed to have no hierarchy. Although they were obtained by manipulation with top K nodes of dendrogram (i.e. hierarchical decomposition of dataset), this function does not return information about hierarchy. Each of the clusters stand on its own. NOTE: Cluster indexes returned by this function does not correspond to indexes returned in Rep.Z/PZ/PM. Either you work with hierarchical representation of the dataset (dendrogram), or you work with "flat" representation returned by this function. Each of representations has its own clusters indexing system (former uses [0, 2*NPoints-2]), while latter uses [0..K-1]), although it is possible to perform conversion from one system to another by means of CZ array, returned by this function, which allows you to convert indexes stored in CIdx to the numeration system used by Rep.Z. NOTE: this subroutine is optimized for moderate values of K. Say, for K=5 it will perform many times faster than for K=100. Its worst-case performance is O(N*K), although in average case it perform better (up to O(N*log(K))). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizergetkclusters( ahcreport rep, ae_int_t k, integer_1d_array& cidx, integer_1d_array& cz);

Examples:   [1]  [2]  

/************************************************************************* This function performs agglomerative hierarchical clustering COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Agglomerative hierarchical clustering algorithm has two phases: ! distance matrix calculation and clustering itself. Only first phase ! (distance matrix calculation) is accelerated by Intel MKL and multi- ! threading. Thus, acceleration is significant only for medium or high- ! dimensional problems. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() OUTPUT PARAMETERS: Rep - clustering results; see description of AHCReport structure for more information. NOTE 1: hierarchical clustering algorithms require large amounts of memory. In particular, this implementation needs sizeof(double)*NPoints^2 bytes, which are used to store distance matrix. In case we work with user-supplied matrix, this amount is multiplied by 2 (we have to store original matrix and to work with its copy). For example, problem with 10000 points would require 800M of RAM, even when working in a 1-dimensional space. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizerrunahc(clusterizerstate s, ahcreport& rep); void alglib::smp_clusterizerrunahc(clusterizerstate s, ahcreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function performs clustering by k-means++ algorithm. You may change algorithm properties by calling: * ClusterizerSetKMeansLimits() to change number of restarts or iterations * ClusterizerSetKMeansInit() to change initialization algorithm By default, one restart and unlimited number of iterations are used. Initialization algorithm is chosen automatically. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (can be used from C# and C++) ! * access to high-performance C++ core (actual for C# users) ! ! K-means clustering algorithm has two phases: selection of initial ! centers and clustering itself. ALGLIB parallelizes both phases. ! Parallel version is optimized for the following scenario: medium or ! high-dimensional problem (20 or more dimensions) with large number of ! points and clusters. However, some speed-up can be obtained even when ! assumptions above are violated. ! ! As for native-vs-managed comparison, working with native core brings ! 30-40% improvement in speed over pure C# version of ALGLIB. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() K - number of clusters, K>=0. K can be zero only when algorithm is called for empty dataset, in this case completion code is set to success (+1). If K=0 and dataset size is non-zero, we can not meaningfully assign points to some center (there are no centers because K=0) and return -3 as completion code (failure). OUTPUT PARAMETERS: Rep - clustering results; see description of KMeansReport structure for more information. NOTE 1: k-means clustering can be performed only for datasets with Euclidean distance function. Algorithm will return negative completion code in Rep.TerminationType in case dataset was added to clusterizer with DistType other than Euclidean (or dataset was specified by distance matrix instead of explicitly given points). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizerrunkmeans( clusterizerstate s, ae_int_t k, kmeansreport& rep); void alglib::smp_clusterizerrunkmeans( clusterizerstate s, ae_int_t k, kmeansreport& rep);
/************************************************************************* This function accepts AHC report Rep, desired maximum intercluster correlation and returns top clusters from hierarchical clusterization tree which are separated by correlation R or LOWER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByDist, which returns clusters with intercluster distance equal to R or HIGHER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired maximum intercluster correlation, -1<=R<=+1 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]<CZ[I+1]. NOTE: K clusters built by this subroutine are assumed to have no hierarchy. Although they were obtained by manipulation with top K nodes of dendrogram (i.e. hierarchical decomposition of dataset), this function does not return information about hierarchy. Each of the clusters stand on its own. NOTE: Cluster indexes returned by this function does not correspond to indexes returned in Rep.Z/PZ/PM. Either you work with hierarchical representation of the dataset (dendrogram), or you work with "flat" representation returned by this function. Each of representations has its own clusters indexing system (former uses [0, 2*NPoints-2]), while latter uses [0..K-1]), although it is possible to perform conversion from one system to another by means of CZ array, returned by this function, which allows you to convert indexes stored in CIdx to the numeration system used by Rep.Z. NOTE: this subroutine is optimized for moderate values of K. Say, for K=5 it will perform many times faster than for K=100. Its worst-case performance is O(N*K), although in average case it perform better (up to O(N*log(K))). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizerseparatedbycorr( ahcreport rep, double r, ae_int_t& k, integer_1d_array& cidx, integer_1d_array& cz);
/************************************************************************* This function accepts AHC report Rep, desired minimum intercluster distance and returns top clusters from hierarchical clusterization tree which are separated by distance R or HIGHER. It returns assignment of points to clusters (array of cluster indexes). There is one more function with similar name - ClusterizerSeparatedByCorr, which returns clusters with intercluster correlation equal to R or LOWER (note: higher for distance, lower for correlation). INPUT PARAMETERS: Rep - report from ClusterizerRunAHC() performed on XY R - desired minimum intercluster distance, R>=0 OUTPUT PARAMETERS: K - number of clusters, 1<=K<=NPoints CIdx - array[NPoints], I-th element contains cluster index (from 0 to K-1) for I-th point of the dataset. CZ - array[K]. This array allows to convert cluster indexes returned by this function to indexes used by Rep.Z. J-th cluster returned by this function corresponds to CZ[J]-th cluster stored in Rep.Z/PZ/PM. It is guaranteed that CZ[I]<CZ[I+1]. NOTE: K clusters built by this subroutine are assumed to have no hierarchy. Although they were obtained by manipulation with top K nodes of dendrogram (i.e. hierarchical decomposition of dataset), this function does not return information about hierarchy. Each of the clusters stand on its own. NOTE: Cluster indexes returned by this function does not correspond to indexes returned in Rep.Z/PZ/PM. Either you work with hierarchical representation of the dataset (dendrogram), or you work with "flat" representation returned by this function. Each of representations has its own clusters indexing system (former uses [0, 2*NPoints-2]), while latter uses [0..K-1]), although it is possible to perform conversion from one system to another by means of CZ array, returned by this function, which allows you to convert indexes stored in CIdx to the numeration system used by Rep.Z. NOTE: this subroutine is optimized for moderate values of K. Say, for K=5 it will perform many times faster than for K=100. Its worst-case performance is O(N*K), although in average case it perform better (up to O(N*log(K))). -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizerseparatedbydist( ahcreport rep, double r, ae_int_t& k, integer_1d_array& cidx, integer_1d_array& cz);
/************************************************************************* This function sets agglomerative hierarchical clustering algorithm INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Algo - algorithm type: * 0 complete linkage (default algorithm) * 1 single linkage * 2 unweighted average linkage * 3 weighted average linkage * 4 Ward's method NOTE: Ward's method works correctly only with Euclidean distance, that's why algorithm will return negative termination code (failure) for any other distance type. It is possible, however, to use this method with user-supplied distance matrix. It is your responsibility to pass one which was calculated with Euclidean distance function. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizersetahcalgo(clusterizerstate s, ae_int_t algo);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function adds dataset given by distance matrix to the clusterizer structure. It is important that dataset is not given explicitly - only distance matrix is given. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() D - array[NPoints,NPoints], distance matrix given by its upper or lower triangle (main diagonal is ignored because its entries are expected to be zero). NPoints - number of points IsUpper - whether upper or lower triangle of D is given. NOTE 1: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric, including one which is given by distance matrix * k-means++ clustering algorithm may be used only with Euclidean distance function and explicitly given points - it can not be used with dataset given by distance matrix Thus, if you call this function, you will be unable to use k-means clustering algorithm to process your problem. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizersetdistances( clusterizerstate s, real_2d_array d, bool isupper); void alglib::clusterizersetdistances( clusterizerstate s, real_2d_array d, ae_int_t npoints, bool isupper);

Examples:   [1]  

/************************************************************************* This function sets k-means initialization algorithm. Several different algorithms can be chosen, including k-means++. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() InitAlgo- initialization algorithm: * 0 automatic selection ( different versions of ALGLIB may select different algorithms) * 1 random initialization * 2 k-means++ initialization (best quality of initial centers, but long non-parallelizable initialization phase with bad cache locality) * 3 "fast-greedy" algorithm with efficient, easy to parallelize initialization. Quality of initial centers is somewhat worse than that of k-means++. This algorithm is a default one in the current version of ALGLIB. *-1 "debug" algorithm which always selects first K rows of dataset; this algorithm is used for debug purposes only. Do not use it in the industrial code! -- ALGLIB -- Copyright 21.01.2015 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizersetkmeansinit( clusterizerstate s, ae_int_t initalgo);
/************************************************************************* This function sets k-means properties: number of restarts and maximum number of iterations per one run. INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() Restarts- restarts count, >=1. k-means++ algorithm performs several restarts and chooses best set of centers (one with minimum squared distance). MaxIts - maximum number of k-means iterations performed during one run. >=0, zero value means that algorithm performs unlimited number of iterations. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizersetkmeanslimits( clusterizerstate s, ae_int_t restarts, ae_int_t maxits);
/************************************************************************* This function adds dataset to the clusterizer structure. This function overrides all previous calls of ClusterizerSetPoints() or ClusterizerSetDistances(). INPUT PARAMETERS: S - clusterizer state, initialized by ClusterizerCreate() XY - array[NPoints,NFeatures], dataset NPoints - number of points, >=0 NFeatures- number of features, >=1 DistType- distance function: * 0 Chebyshev distance (L-inf norm) * 1 city block distance (L1 norm) * 2 Euclidean distance (L2 norm), non-squared * 10 Pearson correlation: dist(a,b) = 1-corr(a,b) * 11 Absolute Pearson correlation: dist(a,b) = 1-|corr(a,b)| * 12 Uncentered Pearson correlation (cosine of the angle): dist(a,b) = a'*b/(|a|*|b|) * 13 Absolute uncentered Pearson correlation dist(a,b) = |a'*b|/(|a|*|b|) * 20 Spearman rank correlation: dist(a,b) = 1-rankcorr(a,b) * 21 Absolute Spearman rank correlation dist(a,b) = 1-|rankcorr(a,b)| NOTE 1: different distance functions have different performance penalty: * Euclidean or Pearson correlation distances are the fastest ones * Spearman correlation distance function is a bit slower * city block and Chebyshev distances are order of magnitude slower The reason behing difference in performance is that correlation-based distance functions are computed using optimized linear algebra kernels, while Chebyshev and city block distance functions are computed using simple nested loops with two branches at each iteration. NOTE 2: different clustering algorithms have different limitations: * agglomerative hierarchical clustering algorithms may be used with any kind of distance metric * k-means++ clustering algorithm may be used only with Euclidean distance function Thus, list of specific clustering algorithms you may use depends on distance function you specify when you set your dataset. -- ALGLIB -- Copyright 10.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::clusterizersetpoints( clusterizerstate s, real_2d_array xy, ae_int_t disttype); void alglib::clusterizersetpoints( clusterizerstate s, real_2d_array xy, ae_int_t npoints, ae_int_t nfeatures, ae_int_t disttype);

Examples:   [1]  [2]  [3]  [4]  [5]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // The very simple clusterization example
    //
    // We have a set of points in 2D space:
    //     (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5))
    //
    //  |
    //  |     P3
    //  |
    //  | P1          
    //  |             P4
    //  | P0          P2
    //  |-------------------------
    //
    // We want to perform Agglomerative Hierarchic Clusterization (AHC),
    // using complete linkage (default algorithm) and Euclidean distance
    // (default metric).
    //
    // In order to do that, we:
    // * create clusterizer with clusterizercreate()
    // * set points XY and metric (2=Euclidean) with clusterizersetpoints()
    // * run AHC algorithm with clusterizerrunahc
    //
    // You may see that clusterization itself is a minor part of the example,
    // most of which is dominated by comments :)
    //
    clusterizerstate s;
    ahcreport rep;
    real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]";

    clusterizercreate(s);
    clusterizersetpoints(s, xy, 2);
    clusterizerrunahc(s, rep);

    //
    // Now we've built our clusterization tree. Rep.z contains information which
    // is required to build dendrogram. I-th row of rep.z represents one merge
    // operation, with first cluster to merge having index rep.z[I,0] and second
    // one having index rep.z[I,1]. Merge result has index NPoints+I.
    //
    // Clusters with indexes less than NPoints are single-point initial clusters,
    // while ones with indexes from NPoints to 2*NPoints-2 are multi-point
    // clusters created during merges.
    //
    // In our example, Z=[[2,4], [0,1], [3,6], [5,7]]
    //
    // It means that:
    // * first, we merge C2=(P2) and C4=(P4),    and create C5=(P2,P4)
    // * then, we merge  C2=(P0) and C1=(P1),    and create C6=(P0,P1)
    // * then, we merge  C3=(P3) and C6=(P0,P1), and create C7=(P0,P1,P3)
    // * finally, we merge C5 and C7 and create C8=(P0,P1,P2,P3,P4)
    //
    // Thus, we have following dendrogram:
    //  
    //      ------8-----
    //      |          |
    //      |      ----7----
    //      |      |       |
    //   ---5---   |    ---6---
    //   |     |   |    |     |
    //   P2   P4   P3   P0   P1
    //
    printf("%s\n", rep.z.tostring().c_str()); // EXPECTED: [[2,4],[0,1],[3,6],[5,7]]

    //
    // We've built dendrogram above by reordering our dataset.
    //
    // Without such reordering it would be impossible to build dendrogram without
    // intersections. Luckily, ahcreport structure contains two additional fields
    // which help to build dendrogram from your data:
    // * rep.p, which contains permutation applied to dataset
    // * rep.pm, which contains another representation of merges 
    //
    // In our example we have:
    // * P=[3,4,0,2,1]
    // * PZ=[[0,0,1,1,0,0],[3,3,4,4,0,0],[2,2,3,4,0,1],[0,1,2,4,1,2]]
    //
    // Permutation array P tells us that P0 should be moved to position 3,
    // P1 moved to position 4, P2 moved to position 0 and so on:
    //
    //   (P0 P1 P2 P3 P4) => (P2 P4 P3 P0 P1)
    //
    // Merges array PZ tells us how to perform merges on the sorted dataset.
    // One row of PZ corresponds to one merge operations, with first pair of
    // elements denoting first of the clusters to merge (start index, end
    // index) and next pair of elements denoting second of the clusters to
    // merge. Clusters being merged are always adjacent, with first one on
    // the left and second one on the right.
    //
    // For example, first row of PZ tells us that clusters [0,0] and [1,1] are
    // merged (single-point clusters, with first one containing P2 and second
    // one containing P4). Third row of PZ tells us that we merge one single-
    // point cluster [2,2] with one two-point cluster [3,4].
    //
    // There are two more elements in each row of PZ. These are the helper
    // elements, which denote HEIGHT (not size) of left and right subdendrograms.
    // For example, according to PZ, first two merges are performed on clusterization
    // trees of height 0, while next two merges are performed on 0-1 and 1-2
    // pairs of trees correspondingly.
    //
    printf("%s\n", rep.p.tostring().c_str()); // EXPECTED: [3,4,0,2,1]
    printf("%s\n", rep.pm.tostring().c_str()); // EXPECTED: [[0,0,1,1,0,0],[3,3,4,4,0,0],[2,2,3,4,0,1],[0,1,2,4,1,2]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We have three points in 4D space:
    //     (P0,P1,P2) = ((1, 2, 1, 2), (6, 7, 6, 7), (7, 6, 7, 6))
    //
    // We want to try clustering them with different distance functions.
    // Distance function is chosen when we add dataset to the clusterizer.
    // We can choose several distance types - Euclidean, city block, Chebyshev,
    // several correlation measures or user-supplied distance matrix.
    //
    // Here we'll try three distances: Euclidean, Pearson correlation,
    // user-supplied distance matrix. Different distance functions lead
    // to different choices being made by algorithm during clustering.
    //
    clusterizerstate s;
    ahcreport rep;
    ae_int_t disttype;
    real_2d_array xy = "[[1, 2, 1, 2], [6, 7, 6, 7], [7, 6, 7, 6]]";
    clusterizercreate(s);

    // With Euclidean distance function (disttype=2) two closest points
    // are P1 and P2, thus:
    // * first, we merge P1 and P2 to form C3=[P1,P2]
    // * second, we merge P0 and C3 to form C4=[P0,P1,P2]
    disttype = 2;
    clusterizersetpoints(s, xy, disttype);
    clusterizerrunahc(s, rep);
    printf("%s\n", rep.z.tostring().c_str()); // EXPECTED: [[1,2],[0,3]]

    // With Pearson correlation distance function (disttype=10) situation
    // is different - distance between P0 and P1 is zero, thus:
    // * first, we merge P0 and P1 to form C3=[P0,P1]
    // * second, we merge P2 and C3 to form C4=[P0,P1,P2]
    disttype = 10;
    clusterizersetpoints(s, xy, disttype);
    clusterizerrunahc(s, rep);
    printf("%s\n", rep.z.tostring().c_str()); // EXPECTED: [[0,1],[2,3]]

    // Finally, we try clustering with user-supplied distance matrix:
    //     [ 0 3 1 ]
    // P = [ 3 0 3 ], where P[i,j] = dist(Pi,Pj)
    //     [ 1 3 0 ]
    //
    // * first, we merge P0 and P2 to form C3=[P0,P2]
    // * second, we merge P1 and C3 to form C4=[P0,P1,P2]
    real_2d_array d = "[[0,3,1],[3,0,3],[1,3,0]]";
    clusterizersetdistances(s, d, true);
    clusterizerrunahc(s, rep);
    printf("%s\n", rep.z.tostring().c_str()); // EXPECTED: [[0,2],[1,3]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We have a set of points in 2D space:
    //     (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5))
    //
    //  |
    //  |     P3
    //  |
    //  | P1          
    //  |             P4
    //  | P0          P2
    //  |-------------------------
    //
    // We perform Agglomerative Hierarchic Clusterization (AHC) and we want
    // to get top K clusters from clusterization tree for different K.
    //
    clusterizerstate s;
    ahcreport rep;
    real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]";
    integer_1d_array cidx;
    integer_1d_array cz;

    clusterizercreate(s);
    clusterizersetpoints(s, xy, 2);
    clusterizerrunahc(s, rep);

    // with K=5, every points is assigned to its own cluster:
    // C0=P0, C1=P1 and so on...
    clusterizergetkclusters(rep, 5, cidx, cz);
    printf("%s\n", cidx.tostring().c_str()); // EXPECTED: [0,1,2,3,4]

    // with K=1 we have one large cluster C0=[P0,P1,P2,P3,P4,P5]
    clusterizergetkclusters(rep, 1, cidx, cz);
    printf("%s\n", cidx.tostring().c_str()); // EXPECTED: [0,0,0,0,0]

    // with K=3 we have three clusters C0=[P3], C1=[P2,P4], C2=[P0,P1]
    clusterizergetkclusters(rep, 3, cidx, cz);
    printf("%s\n", cidx.tostring().c_str()); // EXPECTED: [2,2,1,0,1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // The very simple clusterization example
    //
    // We have a set of points in 2D space:
    //     (P0,P1,P2,P3,P4) = ((1,1),(1,2),(4,1),(2,3),(4,1.5))
    //
    //  |
    //  |     P3
    //  |
    //  | P1          
    //  |             P4
    //  | P0          P2
    //  |-------------------------
    //
    // We want to perform k-means++ clustering with K=2.
    //
    // In order to do that, we:
    // * create clusterizer with clusterizercreate()
    // * set points XY and metric (must be Euclidean, distype=2) with clusterizersetpoints()
    // * (optional) set number of restarts from random positions to 5
    // * run k-means algorithm with clusterizerrunkmeans()
    //
    // You may see that clusterization itself is a minor part of the example,
    // most of which is dominated by comments :)
    //
    clusterizerstate s;
    kmeansreport rep;
    real_2d_array xy = "[[1,1],[1,2],[4,1],[2,3],[4,1.5]]";

    clusterizercreate(s);
    clusterizersetpoints(s, xy, 2);
    clusterizersetkmeanslimits(s, 5, 0);
    clusterizerrunkmeans(s, 2, rep);

    //
    // We've performed clusterization, and it succeeded (completion code is +1).
    //
    // Now first center is stored in the first row of rep.c, second one is stored
    // in the second row. rep.cidx can be used to determine which center is
    // closest to some specific point of the dataset.
    //
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1

    // We called clusterizersetpoints() with disttype=2 because k-means++
    // algorithm does NOT support metrics other than Euclidean. But what if we
    // try to use some other metric?
    //
    // We change metric type by calling clusterizersetpoints() one more time,
    // and try to run k-means algo again. It fails.
    //
    clusterizersetpoints(s, xy, 0);
    clusterizerrunkmeans(s, 2, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: -5
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We have a set of points in 1D space:
    //     (P0,P1,P2,P3,P4) = (1, 3, 10, 16, 20)
    //
    // We want to perform Agglomerative Hierarchic Clusterization (AHC),
    // using either complete or single linkage and Euclidean distance
    // (default metric).
    //
    // First two steps merge P0/P1 and P3/P4 independently of the linkage type.
    // However, third step depends on linkage type being used:
    // * in case of complete linkage P2=10 is merged with [P0,P1]
    // * in case of single linkage P2=10 is merged with [P3,P4]
    //
    clusterizerstate s;
    ahcreport rep;
    real_2d_array xy = "[[1],[3],[10],[16],[20]]";
    integer_1d_array cidx;
    integer_1d_array cz;

    clusterizercreate(s);
    clusterizersetpoints(s, xy, 2);

    // use complete linkage, reduce set down to 2 clusters.
    // print clusterization with clusterizergetkclusters(2).
    // P2 must belong to [P0,P1]
    clusterizersetahcalgo(s, 0);
    clusterizerrunahc(s, rep);
    clusterizergetkclusters(rep, 2, cidx, cz);
    printf("%s\n", cidx.tostring().c_str()); // EXPECTED: [1,1,1,0,0]

    // use single linkage, reduce set down to 2 clusters.
    // print clusterization with clusterizergetkclusters(2).
    // P2 must belong to [P2,P3]
    clusterizersetahcalgo(s, 1);
    clusterizerrunahc(s, rep);
    clusterizergetkclusters(rep, 2, cidx, cz);
    printf("%s\n", cidx.tostring().c_str()); // EXPECTED: [0,0,1,1,1]
    return 0;
}


/************************************************************************* 1-dimensional complex convolution. For given A/B returns conv(A,B) (non-circular). Subroutine can automatically choose between three implementations: straightforward O(M*N) formula for very small N (or M), overlap-add algorithm for cases where max(M,N) is significantly larger than min(M,N), but O(M*N) algorithm is too slow, and general FFT-based formula for cases where two previois algorithms are too slow. Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. INPUT PARAMETERS A - array[0..M-1] - complex function to be transformed M - problem size B - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convc1d( complex_1d_array a, ae_int_t m, complex_1d_array b, ae_int_t n, complex_1d_array& r);
/************************************************************************* 1-dimensional circular complex convolution. For given S/R returns conv(S,R) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: normal convolution is commutative, i.e. it is symmetric - conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a signal, periodic function, and another - R - is a response, non-periodic function with limited length. INPUT PARAMETERS S - array[0..M-1] - complex periodic signal M - problem size B - array[0..N-1] - complex non-periodic response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convc1dcircular( complex_1d_array s, ae_int_t m, complex_1d_array r, ae_int_t n, complex_1d_array& c);
/************************************************************************* 1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved periodic signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - non-periodic response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-1]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convc1dcircularinv( complex_1d_array a, ae_int_t m, complex_1d_array b, ae_int_t n, complex_1d_array& r);
/************************************************************************* 1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convc1dinv( complex_1d_array a, ae_int_t m, complex_1d_array b, ae_int_t n, complex_1d_array& r);
/************************************************************************* 1-dimensional real convolution. Analogous to ConvC1D(), see ConvC1D() comments for more details. INPUT PARAMETERS A - array[0..M-1] - real function to be transformed M - problem size B - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..N+M-2]. NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convr1d( real_1d_array a, ae_int_t m, real_1d_array b, ae_int_t n, real_1d_array& r);
/************************************************************************* 1-dimensional circular real convolution. Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. INPUT PARAMETERS S - array[0..M-1] - real signal M - problem size B - array[0..N-1] - real response N - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convr1dcircular( real_1d_array s, ae_int_t m, real_1d_array r, ae_int_t n, real_1d_array& c);
/************************************************************************* 1-dimensional complex deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that B is zero at T<0. If it has non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convr1dcircularinv( real_1d_array a, ae_int_t m, real_1d_array b, ae_int_t n, real_1d_array& r);
/************************************************************************* 1-dimensional real deconvolution (inverse of ConvC1D()). Algorithm has M*log(M)) complexity for any M (composite or prime). INPUT PARAMETERS A - array[0..M-1] - convolved signal, A = conv(R, B) M - convolved signal length B - array[0..N-1] - response N - response length, N<=M OUTPUT PARAMETERS R - deconvolved signal. array[0..M-N]. NOTE: deconvolution is unstable process and may result in division by zero (if your response function is degenerate, i.e. has zero Fourier coefficient). NOTE: It is assumed that A is zero at T<0, B is zero too. If one or both functions have non-zero values at negative T's, you can still use this subroutine - just shift its result correspondingly. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::convr1dinv( real_1d_array a, ae_int_t m, real_1d_array b, ae_int_t n, real_1d_array& r);
/************************************************************************* 1-dimensional complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(conj(pattern[j])*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::corrc1d( complex_1d_array signal, ae_int_t n, complex_1d_array pattern, ae_int_t m, complex_1d_array& r);
/************************************************************************* 1-dimensional circular complex cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - complex function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - complex function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::corrc1dcircular( complex_1d_array signal, ae_int_t m, complex_1d_array pattern, ae_int_t n, complex_1d_array& c);
/************************************************************************* 1-dimensional real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). Correlation is calculated using reduction to convolution. Algorithm with max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info about performance). IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, pattern to search withing signal M - problem size OUTPUT PARAMETERS R - cross-correlation, array[0..N+M-2]: * positive lags are stored in R[0..N-1], R[i] = sum(pattern[j]*signal[i+j] * negative lags are stored in R[N..N+M-2], R[N+M-1-i] = sum(pattern[j]*signal[-i+j] NOTE: It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero on [-K..M-1], you can still use this subroutine, just shift result by K. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::corrr1d( real_1d_array signal, ae_int_t n, real_1d_array pattern, ae_int_t m, real_1d_array& r);
/************************************************************************* 1-dimensional circular real cross-correlation. For given Pattern/Signal returns corr(Pattern,Signal) (circular). Algorithm has linearithmic complexity for any M/N. IMPORTANT: for historical reasons subroutine accepts its parameters in reversed order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using traditional definition of cross-correlation, denoting cross-correlation as "x"). INPUT PARAMETERS Signal - array[0..N-1] - real function to be transformed, periodic signal containing pattern N - problem size Pattern - array[0..M-1] - real function to be transformed, non-periodic pattern to search withing signal M - problem size OUTPUT PARAMETERS R - convolution: A*B. array[0..M-1]. -- ALGLIB -- Copyright 21.07.2009 by Bochkanov Sergey *************************************************************************/
void alglib::corrr1dcircular( real_1d_array signal, ae_int_t m, real_1d_array pattern, ae_int_t n, real_1d_array& c);
/************************************************************************* Pearson's correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5 * normality of distributions of X and Y. Input parameters: R - Pearson's correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
void alglib::pearsoncorrelationsignificance( double r, ae_int_t n, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* Spearman's rank correlation coefficient significance test This test checks hypotheses about whether X and Y are samples of two continuous distributions having zero correlation or whether their correlation is non-zero. The following tests are performed: * two-tailed test (null hypothesis - X and Y have zero correlation) * left-tailed test (null hypothesis - the correlation coefficient is greater than or equal to 0) * right-tailed test (null hypothesis - the correlation coefficient is less than or equal to 0). Requirements: * the number of elements in each sample is not less than 5. The test is non-parametric and doesn't require distributions X and Y to be normal. Input parameters: R - Spearman's rank correlation coefficient for X and Y N - number of elements in samples, N>=5. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spearmanrankcorrelationsignificance( double r, ae_int_t n, double& bothtails, double& lefttail, double& righttail);
kmeansgenerate
/************************************************************************* k-means++ clusterization. Backward compatibility function, we recommend to use CLUSTERING subpackage as better replacement. -- ALGLIB -- Copyright 21.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::kmeansgenerate( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t k, ae_int_t restarts, ae_int_t& info, real_2d_array& c, integer_1d_array& xyc);
dawsonintegral
/************************************************************************* Dawson's Integral Approximates the integral x - 2 | | 2 dawsn(x) = exp( -x ) | exp( t ) dt | | - 0 Three different rational approximations are employed, for the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,10 10000 6.9e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::dawsonintegral(double x);
/************************************************************************* *************************************************************************/
class densesolverlsreport { double r2; real_2d_array cx; ae_int_t n; ae_int_t k; };
/************************************************************************* *************************************************************************/
class densesolverreport { double r1; double rinf; };
/************************************************************************* Complex dense linear solver for A*x=b with complex N*N A given by its LU decomposition and N*1 vectors x and b. This is "slow-but-robust" version of the complex linear solver with additional features which add significant performance overhead. Faster version is CMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlusolve( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x);
/************************************************************************* Complex dense linear solver for A*x=b with N*N complex A given by its LU decomposition and N*1 vectors x and b. This is fast lightweight version of solver, which is significantly faster than CMatrixLUSolve(), but does not provide additional information (like condition numbers). Algorithm features: * O(N^2) complexity * no additional time-consuming features, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros NOTE: unlike CMatrixLUSolve(), this function does NOT check for near-degeneracy of input matrix. It checks for EXACT degeneracy, because this check is easy to do. However, very badly conditioned matrices may went unnoticed. -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlusolvefast( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! CMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlusolvem( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x); void alglib::smp_cmatrixlusolvem( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x);
/************************************************************************* Dense solver for A*X=B with N*N complex A given by its LU decomposition, and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * no additional time-consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlusolvemfast( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_cmatrixlusolvemfast( complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixmixedsolve( complex_2d_array a, complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x);
/************************************************************************* Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result P - array[0..N-1], pivots array, CMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixmixedsolvem( complex_2d_array a, complex_2d_array lua, integer_1d_array p, ae_int_t n, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x);
/************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixsolve( complex_2d_array a, ae_int_t n, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x); void alglib::smp_cmatrixsolve( complex_2d_array a, ae_int_t n, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x);
/************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * no additional time consuming features, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixsolvefast( complex_2d_array a, ae_int_t n, complex_1d_array& b, ae_int_t& info); void alglib::smp_cmatrixsolvefast( complex_2d_array a, ae_int_t n, complex_1d_array& b, ae_int_t& info);
/************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Slow-but-feature-rich" version which provides additional functions, at the cost of slower performance. Faster version may be invoked with CMatrixSolveMFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, CMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixsolvem( complex_2d_array a, ae_int_t n, complex_2d_array b, ae_int_t m, bool rfs, ae_int_t& info, densesolverreport& rep, complex_2d_array& x); void alglib::smp_cmatrixsolvem( complex_2d_array a, ae_int_t n, complex_2d_array b, ae_int_t m, bool rfs, ae_int_t& info, densesolverreport& rep, complex_2d_array& x);
/************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Fast-but-lightweight" version which provides just triangular solver - and no additional functions like iterative refinement or condition number estimation. Algorithm features: * O(N^3+M*N^2) complexity * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixsolvemfast( complex_2d_array a, ae_int_t n, complex_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_cmatrixsolvemfast( complex_2d_array a, ae_int_t n, complex_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "slow-but-feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixcholeskysolve( complex_2d_array cha, ae_int_t n, bool isupper, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x);
/************************************************************************* Dense solver for A*x=b with N*N Hermitian positive definite matrix A given by its Cholesky decomposition, and N*1 complex vectors x and b. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixcholeskysolvefast( complex_2d_array cha, ae_int_t n, bool isupper, complex_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "slow-but-feature-rich" version of the solver which, in addition to the solution, estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large Cholesky decomposition. However, if you call ! this function many times for the same left side, this ! overhead BECOMES significant. It also becomes significant ! for small-scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixcholeskysolvem( complex_2d_array cha, ae_int_t n, bool isupper, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x); void alglib::smp_hpdmatrixcholeskysolvem( complex_2d_array cha, ae_int_t n, bool isupper, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x);
/************************************************************************* Dense solver for A*X=B with N*N Hermitian positive definite matrix A given by its Cholesky decomposition and N*M complex matrices X and B. This is "fast-but-lightweight" version of the solver. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time-consuming features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, HPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixcholeskysolvemfast( complex_2d_array cha, ae_int_t n, bool isupper, complex_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_hpdmatrixcholeskysolvemfast( complex_2d_array cha, ae_int_t n, bool isupper, complex_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, HPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - same as in RMatrixSolve Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixsolve( complex_2d_array a, ae_int_t n, bool isupper, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x); void alglib::smp_hpdmatrixsolve( complex_2d_array a, ae_int_t n, bool isupper, complex_1d_array b, ae_int_t& info, densesolverreport& rep, complex_1d_array& x);
/************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver without additional functions. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or not positive definite X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[0..N-1]: * overwritten by solution * zeros, if A is exactly singular (diagonal of its LU decomposition has exact zeros). -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixsolvefast( complex_2d_array a, ae_int_t n, bool isupper, complex_1d_array& b, ae_int_t& info); void alglib::smp_hpdmatrixsolvefast( complex_2d_array a, ae_int_t n, bool isupper, complex_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems (N<100). ! ! In such cases we strongly recommend you to use faster solver, ! HPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - same as in RMatrixSolve. Returns -3 for non-HPD matrices. Rep - same as in RMatrixSolve X - same as in RMatrixSolve -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixsolvem( complex_2d_array a, ae_int_t n, bool isupper, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x); void alglib::smp_hpdmatrixsolvem( complex_2d_array a, ae_int_t n, bool isupper, complex_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, complex_2d_array& x);
/************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or is not positive definite. B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[0..N-1]: * overwritten by solution * zeros, if problem was not solved -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixsolvemfast( complex_2d_array a, ae_int_t n, bool isupper, complex_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_hpdmatrixsolvemfast( complex_2d_array a, ae_int_t n, bool isupper, complex_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "slow-but-robust" version of the linear LU-based solver. Faster version is RMatrixLUSolveFast() function. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveFast() function. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlusolve( real_2d_array lua, integer_1d_array p, ae_int_t n, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x);
/************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix given by its LU decomposition, x and b are real vectors. This is "fast-without-any-checks" version of the linear LU-based solver. Slower but more robust version is RMatrixLUSolve() function. Algorithm features: * O(N^2) complexity * fast algorithm without ANY additional checks, just triangular solver INPUT PARAMETERS LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlusolvefast( real_2d_array lua, integer_1d_array p, ae_int_t n, real_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "robust-but-slow" version of LU-based solver which performs additional checks for non-degeneracy of inputs (condition number estimation). If you need best performance, use "fast-without-any-checks" version, RMatrixLUSolveMFast(). Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation No iterative refinement is provided because exact form of original matrix is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. ! ! This performance penalty is especially apparent when you use ! ALGLIB parallel capabilities (condition number estimation is ! inherently sequential). It also becomes significant for ! small-scale problems. ! ! In such cases we strongly recommend you to use faster solver, ! RMatrixLUSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS LUA - array[N,N], LU decomposition, RMatrixLU result P - array[N], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlusolvem( real_2d_array lua, integer_1d_array p, ae_int_t n, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x); void alglib::smp_rmatrixlusolvem( real_2d_array lua, integer_1d_array p, ae_int_t n, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x);
/************************************************************************* Dense solver. Similar to RMatrixLUSolve() but solves task with multiple right parts, where b and x are NxM matrices. This is "fast-without-any-checks" version of LU-based solver. It does not estimate condition number of a system, so it is extremely fast. If you need better detection of near-degenerate cases, use RMatrixLUSolveM() function. Algorithm features: * O(M*N^2) complexity * fast algorithm without ANY additional checks, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. Triangular solver is relatively easy to parallelize. ! However, parallelization will be efficient only for large number of ! right parts M. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlusolvemfast( real_2d_array lua, integer_1d_array p, ae_int_t n, real_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_rmatrixlusolvemfast( real_2d_array lua, integer_1d_array p, ae_int_t n, real_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver. This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have both A and its LU decomposition. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixmixedsolve( real_2d_array a, real_2d_array lua, integer_1d_array p, ae_int_t n, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x);
/************************************************************************* Dense solver. Similar to RMatrixMixedSolve() but solves task with multiple right parts (where b and x are NxM matrices). Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(M*N^2) complexity INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result P - array[0..N-1], pivots array, RMatrixLU result N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixmixedsolvem( real_2d_array a, real_2d_array lua, integer_1d_array p, ae_int_t n, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x);
/************************************************************************* Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and b. This is "slow-but-feature rich" version of the linear solver. Faster version is RMatrixSolveFast() function. Algorithm features: * automatic detection of degenerate cases * condition number estimation * iterative refinement * O(N^3) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or exactly singular. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsolve( real_2d_array a, ae_int_t n, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x); void alglib::smp_rmatrixsolve( real_2d_array a, ae_int_t n, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x);
/************************************************************************* Dense solver. This subroutine solves a system A*x=b, where A is NxN non-denegerate real matrix, x and b are vectors. This is a "fast" version of linear solver which does NOT provide any additional functions like condition number estimation or iterative refinement. Algorithm features: * efficient algorithm O(N^3) complexity * no performance overhead from additional functionality If you need condition number estimation or iterative refinement, use more feature-rich version - RMatrixSolve(). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsolvefast( real_2d_array a, ae_int_t n, real_1d_array& b, ae_int_t& info); void alglib::smp_rmatrixsolvefast( real_2d_array a, ae_int_t n, real_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver. This subroutine finds solution of the linear system A*X=B with non-square, possibly degenerate A. System is solved in the least squares sense, and general least squares solution X = X0 + CX*y which minimizes |A*X-B| is returned. If A is non-degenerate, solution in the usual sense is returned. Algorithm features: * automatic detection (and correct handling!) of degenerate cases * iterative refinement * O(N^3) complexity COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..NRows-1,0..NCols-1], system matrix NRows - vertical size of A NCols - horizontal size of A B - array[0..NCols-1], right part Threshold- a number in [0,1]. Singular values beyond Threshold are considered zero. Set it to 0.0, if you don't understand what it means, so the solver will choose good value on its own. OUTPUT PARAMETERS Info - return code: * -4 SVD subroutine failed * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed * 1 if task is solved Rep - solver report, see below for more info X - array[0..N-1,0..M-1], it contains: * solution of A*X=B (even for singular A) * zeros, if SVD subroutine failed SOLVER REPORT Subroutine sets following fields of the Rep structure: * R2 reciprocal of condition number: 1/cond(A), 2-norm. * N = NCols * K dim(Null(A)) * CX array[0..N-1,0..K-1], kernel of A. Columns of CX store such vectors that A*CX[i]=0. -- ALGLIB -- Copyright 24.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsolvels( real_2d_array a, ae_int_t nrows, ae_int_t ncols, real_1d_array b, double threshold, ae_int_t& info, densesolverlsreport& rep, real_1d_array& x); void alglib::smp_rmatrixsolvels( real_2d_array a, ae_int_t nrows, ae_int_t ncols, real_1d_array b, double threshold, ae_int_t& info, densesolverlsreport& rep, real_1d_array& x);
/************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "slow-but-robust" version of linear solver with additional functionality like condition number estimation. There also exists faster version - RMatrixSolveMFast(). Algorithm features: * automatic detection of degenerate cases * condition number estimation * optional iterative refinement * O(N^3+M*N^2) complexity IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system ! and performs iterative refinement, which results in ! significant performance penalty when compared with "fast" ! version which just performs LU decomposition and calls ! triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. It also very significant on small matrices. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, RMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 A is ill conditioned or singular. X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsolvem( real_2d_array a, ae_int_t n, real_2d_array b, ae_int_t m, bool rfs, ae_int_t& info, densesolverreport& rep, real_2d_array& x); void alglib::smp_rmatrixsolvem( real_2d_array a, ae_int_t n, real_2d_array b, ae_int_t m, bool rfs, ae_int_t& info, densesolverreport& rep, real_2d_array& x);
/************************************************************************* Dense solver. Similar to RMatrixSolve() but solves task with multiple right parts (where b and x are NxM matrices). This is "fast" version of linear solver which does NOT offer additional functions like condition number estimation or iterative refinement. Algorithm features: * O(N^3+M*N^2) complexity * no additional functionality, highest performance COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size RFS - iterative refinement switch: * True - refinement is used. Less performance, more precision. * False - refinement is not used. More performance, less precision. OUTPUT PARAMETERS Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixsolvemfast( real_2d_array a, ae_int_t n, real_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_rmatrixsolvemfast( real_2d_array a, ae_int_t n, real_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- but-feature-rich" version of the solver which, in addition to the solution, performs condition number estimation. Algorithm features: * automatic detection of degenerate cases * O(N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in 10-15x performance penalty when compared ! with "fast" version which just calls triangular solver. ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveFast() function. INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 - solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixcholeskysolve( real_2d_array cha, ae_int_t n, bool isupper, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x);
/************************************************************************* Dense solver for A*x=b with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- but-lightweight" version of the solver. Algorithm features: * O(N^2) complexity * matrix is represented by its upper or lower triangle * no additional features INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of A IsUpper - what half of CHA is provided B - array[N], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or ill conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[N]: * for info>0 - overwritten by solution * for info=-3 - filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixcholeskysolvefast( real_2d_array cha, ae_int_t n, bool isupper, real_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- feature-rich" version of the solver which estimates condition number of the system. Algorithm features: * automatic detection of degenerate cases * O(M*N^2) complexity * condition number estimation * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just calls triangular ! solver. Amount of overhead introduced depends on M (the ! larger - the more efficient). ! ! This performance penalty is insignificant when compared with ! cost of large LU decomposition. However, if you call this ! function many times for the same left side, this overhead ! BECOMES significant. It also becomes significant for small- ! scale problems (N<50). ! ! In such cases we strongly recommend you to use faster solver, ! SPDMatrixCholeskySolveMFast() function. INPUT PARAMETERS CHA - array[0..N-1,0..N-1], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N]: * for info>0 contains solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixcholeskysolvem( real_2d_array cha, ae_int_t n, bool isupper, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x); void alglib::smp_spdmatrixcholeskysolvem( real_2d_array cha, ae_int_t n, bool isupper, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x);
/************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A given by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- lightweight" version of the solver which just solves linear system, without any additional functions. Algorithm features: * O(M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional functionality INPUT PARAMETERS CHA - array[N,N], Cholesky decomposition, SPDMatrixCholesky result N - size of CHA IsUpper - what half of CHA is provided B - array[N,M], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or badly conditioned X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[N]: * for info>0 overwritten by solution * for info=-3 filled by zeros -- ALGLIB -- Copyright 18.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixcholeskysolvemfast( real_2d_array cha, ae_int_t n, bool isupper, real_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_spdmatrixcholeskysolvemfast( real_2d_array cha, ae_int_t n, bool isupper, real_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixsolve( real_2d_array a, ae_int_t n, bool isupper, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x); void alglib::smp_spdmatrixsolve( real_2d_array a, ae_int_t n, bool isupper, real_1d_array b, ae_int_t& info, densesolverreport& rep, real_1d_array& x);
/************************************************************************* Dense linear solver for A*x=b with N*N real symmetric positive definite matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or non-SPD * -1 N<=0 was passed * 1 task was solved B - array[N], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixsolvefast( real_2d_array a, ae_int_t n, bool isupper, real_1d_array& b, ae_int_t& info); void alglib::smp_spdmatrixsolvefast( real_2d_array a, ae_int_t n, bool isupper, real_1d_array& b, ae_int_t& info);
/************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. Algorithm features: * automatic detection of degenerate cases * condition number estimation * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle No iterative refinement is provided because such partial representation of matrix does not allow efficient calculation of extra-precise matrix-vector products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you need iterative refinement. IMPORTANT: ! this function is NOT the most efficient linear solver provided ! by ALGLIB. It estimates condition number of linear system, ! which results in significant performance penalty when ! compared with "fast" version which just performs Cholesky ! decomposition and calls triangular solver. ! ! This performance penalty is especially visible in the ! multithreaded mode, because both condition number estimation ! and iterative refinement are inherently sequential ! calculations. ! ! Thus, if you need high performance and if you are pretty sure ! that your system is well conditioned, we strongly recommend ! you to use faster solver, SPDMatrixSolveMFast() function. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 matrix is very badly conditioned or non-SPD. * -1 N<=0 was passed * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - additional report, following fields are set: * rep.r1 condition number in 1-norm * rep.rinf condition number in inf-norm X - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixsolvem( real_2d_array a, ae_int_t n, bool isupper, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x); void alglib::smp_spdmatrixsolvem( real_2d_array a, ae_int_t n, bool isupper, real_2d_array b, ae_int_t m, ae_int_t& info, densesolverreport& rep, real_2d_array& x);
/************************************************************************* Dense solver for A*X=B with N*N symmetric positive definite matrix A, and N*M vectors X and B. It is "fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular * -1 N<=0 was passed * 1 task was solved B - array[N,M], it contains: * info>0 => solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixsolvemfast( real_2d_array a, ae_int_t n, bool isupper, real_2d_array& b, ae_int_t m, ae_int_t& info); void alglib::smp_spdmatrixsolvemfast( real_2d_array a, ae_int_t n, bool isupper, real_2d_array& b, ae_int_t m, ae_int_t& info);
/************************************************************************* *************************************************************************/
class decisionforest { };
/************************************************************************* *************************************************************************/
class dfreport { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; double oobrelclserror; double oobavgce; double oobrmserror; double oobavgerror; double oobavgrelerror; };
/************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::dfavgce( decisionforest df, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::dfavgerror( decisionforest df, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average relative error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::dfavgrelerror( decisionforest df, real_2d_array xy, ae_int_t npoints);
/************************************************************************* This subroutine builds random decision forest. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. R - percent of a training set used to build individual trees. 0<R<=1. recommended values: 0.1 <= R <= 0.66. OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<1, NVars<1, NClasses<1, NTrees<1, R<=0 or R>1). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::dfbuildrandomdecisionforest( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, double r, ae_int_t& info, decisionforest& df, dfreport& rep);
/************************************************************************* This subroutine builds random decision forest. This function gives ability to tune number of variables used when choosing best split. INPUT PARAMETERS: XY - training set NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - task type: * NClasses=1 - regression task with one dependent variable * NClasses>1 - classification task with NClasses classes. NTrees - number of trees in a forest, NTrees>=1. recommended values: 50-100. NRndVars - number of variables used when choosing best split R - percent of a training set used to build individual trees. 0<R<=1. recommended values: 0.1 <= R <= 0.66. OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<1, NVars<1, NClasses<1, NTrees<1, R<=0 or R>1). * 1, if task has been solved DF - model built Rep - training report, contains error on a training set and out-of-bag estimates of generalization error. -- ALGLIB -- Copyright 19.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::dfbuildrandomdecisionforestx1( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t ntrees, ae_int_t nrndvars, double r, ae_int_t& info, decisionforest& df, dfreport& rep);
/************************************************************************* Procesing INPUT PARAMETERS: DF - decision forest model X - input vector, array[0..NVars-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also DFProcessI. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::dfprocess( decisionforest df, real_1d_array x, real_1d_array& y);
/************************************************************************* 'interactive' variant of DFProcess for languages like Python which support constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::dfprocessi( decisionforest df, real_1d_array x, real_1d_array& y);
/************************************************************************* Relative classification error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Zero if model solves regression task. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::dfrelclserror( decisionforest df, real_2d_array xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set INPUT PARAMETERS: DF - decision forest model XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 16.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::dfrmserror( decisionforest df, real_2d_array xy, ae_int_t npoints);
/************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/
void dfserialize(decisionforest &obj, std::string &s_out);
/************************************************************************* This function unserializes data structure from string. *************************************************************************/
void dfunserialize(std::string &s_in, decisionforest &obj);
/************************************************************************* Complete elliptic integral of the second kind Approximates the integral pi/2 - | | 2 E(m) = | sqrt( 1 - m sin t ) dt | | - 0 using the approximation P(x) - x log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 1 10000 2.1e-16 7.3e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::ellipticintegrale(double m);
/************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 using the approximation P(x) - log x Q(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::ellipticintegralk(double m);
/************************************************************************* Complete elliptic integral of the first kind Approximates the integral pi/2 - | | | dt K(m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 where m = 1 - m1, using the approximation P(x) - log x Q(x). The argument m1 is used rather than m so that the logarithmic singularity at m = 1 will be shifted to the origin; this preserves maximum accuracy. K(0) = pi/2. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 2.5e-16 6.8e-17 Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::ellipticintegralkhighprecision(double m1);
/************************************************************************* Incomplete elliptic integral of the second kind Approximates the integral phi - | | | 2 E(phi_\m) = | sqrt( 1 - m sin t ) dt | | | - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random arguments with phi in [-10, 10] and m in [0, 1]. Relative error: arithmetic domain # trials peak rms IEEE -10,10 150000 3.3e-15 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::incompleteellipticintegrale(double phi, double m);
/************************************************************************* Incomplete elliptic integral of the first kind F(phi|m) Approximates the integral phi - | | | dt F(phi_\m) = | ------------------ | 2 | | sqrt( 1 - m sin t ) - 0 of amplitude phi and modulus m, using the arithmetic - geometric mean algorithm. ACCURACY: Tested at random points with m in [0, 1] and phi as indicated. Relative error: arithmetic domain # trials peak rms IEEE -10,10 200000 7.4e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::incompleteellipticintegralk(double phi, double m);
/************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/
bool alglib::hmatrixevd( complex_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, real_1d_array& d, complex_2d_array& z);
/************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a Hermitian matrix with given indexes by using bisection and inverse iteration methods Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/
bool alglib::hmatrixevdi( complex_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, ae_int_t i1, ae_int_t i2, real_1d_array& w, complex_2d_array& z);
/************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian matrix in a given half-interval (A, B] by using a bisection and inverse iteration Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half-interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval, M>=0 W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/
bool alglib::hmatrixevdr( complex_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, double b1, double b2, ae_int_t& m, real_1d_array& w, complex_2d_array& z);
/************************************************************************* Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Speed-up provided by MKL for this particular problem (EVD) ! is really high, because MKL uses combination of (a) better low-level ! optimizations, and (b) better EVD algorithms. ! ! On one particular SSE-capable machine for N=1024, commercial MKL- ! -capable ALGLIB was: ! * 7-10 times faster than open source "generic C" version ! * 15-18 times faster than "pure C#" version ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm finds eigenvalues and eigenvectors of a general matrix by using the QR algorithm with multiple shifts. The algorithm can find eigenvalues and both left and right eigenvectors. The right eigenvector is a vector x such that A*x = w*x, and the left eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex conjugate transposition of vector y). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. VNeeded - flag controlling whether eigenvectors are needed or not. If VNeeded is equal to: * 0, eigenvectors are not returned; * 1, right eigenvectors are returned; * 2, left eigenvectors are returned; * 3, both left and right eigenvectors are returned. Output parameters: WR - real parts of eigenvalues. Array whose index ranges within [0..N-1]. WR - imaginary parts of eigenvalues. Array whose index ranges within [0..N-1]. VL, VR - arrays of left and right eigenvectors (if they are needed). If WI[i]=0, the respective eigenvalue is a real number, and it corresponds to the column number I of matrices VL/VR. If WI[i]>0, we have a pair of complex conjugate numbers with positive and negative imaginary parts: the first eigenvalue WR[i] + sqrt(-1)*WI[i]; the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; WI[i]>0 WI[i+1] = -WI[i] < 0 In that case, the eigenvector corresponding to the first eigenvalue is located in i and i+1 columns of matrices VL/VR (the column number i contains the real part, and the column number i+1 contains the imaginary part), and the vector corresponding to the second eigenvalue is a complex conjugate to the first vector. Arrays whose indexes range within [0..N-1, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm has not converged. Note 1: Some users may ask the following question: what if WI[N-1]>0? WI[N] must contain an eigenvalue which is complex conjugate to the N-th eigenvalue, but the array has only size N? The answer is as follows: such a situation cannot occur because the algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is strictly less than N-1. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms of linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. See also the InternalTREVC subroutine. The algorithm is based on the LAPACK 3.0 library. *************************************************************************/
bool alglib::rmatrixevd( real_2d_array a, ae_int_t n, ae_int_t vneeded, real_1d_array& wr, real_1d_array& wi, real_2d_array& vl, real_2d_array& vr);
/************************************************************************* Finding the eigenvalues and eigenvectors of a symmetric matrix The algorithm finds eigen pairs of a symmetric matrix by reducing it to tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpper - storage format. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixevd( real_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, real_1d_array& d, real_2d_array& z);
/************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a symmetric matrix with given indexes by using bisection and inverse iteration methods. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixevdi( real_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, ae_int_t i1, ae_int_t i2, real_1d_array& w, real_2d_array& z);
/************************************************************************* Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric matrix in a given half open interval (A, B] by using a bisection and inverse iteration Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. B1, B2 - half open interval (B1, B2] to search eigenvalues in. Output parameters: M - number of eigenvalues found in a given half-interval (M>=0). W - array of the eigenvalues found. Array whose index ranges within [0..M-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..M-1]. The eigenvectors are stored in the matrix columns. Result: True, if successful. M contains the number of eigenvalues in the given half-interval (could be equal to 0), W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 07.01.2006 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixevdr( real_2d_array a, ae_int_t n, ae_int_t zneeded, bool isupper, double b1, double b2, ae_int_t& m, real_1d_array& w, real_2d_array& z);
/************************************************************************* Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by using an QL/QR algorithm with implicit shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix; * 2, the eigenvectors of a tridiagonal matrix replace the square matrix Z; * 3, matrix Z contains the first row of the eigenvectors matrix. Z - if ZNeeded=1, Z contains the square matrix by which the eigenvectors are multiplied. Array whose indexes range within [0..N-1, 0..N-1]. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains the product of a given matrix (from the left) and the eigenvectors matrix (from the right); * 2, Z contains the eigenvectors. * 3, Z contains the first row of the eigenvectors matrix. If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. In that case, the eigenvectors are stored in the matrix columns. If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/
bool alglib::smatrixtdevd( real_1d_array& d, real_1d_array e, ae_int_t n, ae_int_t zneeded, real_2d_array& z);
/************************************************************************* Subroutine for finding tridiagonal matrix eigenvalues/vectors with given indexes (in ascending order) by using the bisection and inverse iteraion. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix. N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and Nx(I2-I1) matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..I2-I1]. * 2, contains the matrix of the eigenvalues found. Array whose indexes range within [0..N-1, 0..I2-I1]. Result: True, if successful. In that case, D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. -- ALGLIB -- Copyright 25.12.2005 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixtdevdi( real_1d_array& d, real_1d_array e, ae_int_t n, ae_int_t zneeded, ae_int_t i1, ae_int_t i2, real_2d_array& z);
/************************************************************************* Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a given half-interval (A, B] by using bisection and inverse iteration. Input parameters: D - the main diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-1]. E - the secondary diagonal of a tridiagonal matrix. Array whose index ranges within [0..N-2]. N - size of matrix, N>=0. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not needed; * 1, the eigenvectors of a tridiagonal matrix are multiplied by the square matrix Z. It is used if the tridiagonal matrix is obtained by the similarity transformation of a symmetric matrix. * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. A, B - half-interval (A, B] to search eigenvalues in. Z - if ZNeeded is equal to: * 0, Z isn't used and remains unchanged; * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) which reduces the given symmetric matrix to tridiagonal form; * 2, Z isn't used (but changed on the exit). Output parameters: D - array of the eigenvalues found. Array whose index ranges within [0..M-1]. M - number of eigenvalues found in the given half-interval (M>=0). Z - if ZNeeded is equal to: * 0, doesn't contain any information; * 1, contains the product of a given NxN matrix Z (from the left) and NxM matrix of the eigenvectors found (from the right). Array whose indexes range within [0..N-1, 0..M-1]. * 2, contains the matrix of the eigenvectors found. Array whose indexes range within [0..N-1, 0..M-1]. Result: True, if successful. In that case, M contains the number of eigenvalues in the given half-interval (could be equal to 0), D contains the eigenvalues, Z contains the eigenvectors (if needed). It should be noted that the subroutine changes the size of arrays D and Z. False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned, M is equal to 0. -- ALGLIB -- Copyright 31.03.2008 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixtdevdr( real_1d_array& d, real_1d_array e, ae_int_t n, ae_int_t zneeded, double a, double b, ae_int_t& m, real_2d_array& z);
/************************************************************************* Exponential integral Ei(x) x - t | | e Ei(x) = -|- --- dt . | | t - -inf Not defined for x <= 0. See also expn.c. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,100 50000 8.6e-16 1.3e-16 Cephes Math Library Release 2.8: May, 1999 Copyright 1999 by Stephen L. Moshier *************************************************************************/
double alglib::exponentialintegralei(double x);
/************************************************************************* Exponential integral En(x) Evaluates the exponential integral inf. - | | -xt | e E (x) = | ---- dt. n | n | | t - 1 Both n and x must be nonnegative. The routine employs either a power series, a continued fraction, or an asymptotic formula depending on the relative values of n and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0, 30 10000 1.7e-15 3.6e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::exponentialintegralen(double x, ae_int_t n);
/************************************************************************* Complemented F distribution Returns the area from x to infinity under the F density function (also known as Snedcor's density or the variance ratio density). inf. - 1 | | a-1 b-1 1-P(x) = ------ | t (1-t) dt B(a,b) | | - x The incomplete beta integral is used, according to the formula P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). ACCURACY: Tested at random points (a,b,x) in the indicated intervals. x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::fcdistribution(ae_int_t a, ae_int_t b, double x);
/************************************************************************* F distribution Returns the area from zero to x under the F density function (also known as Snedcor's density or the variance ratio density). This is the density of x = (u1/df1)/(u2/df2), where u1 and u2 are random variables having Chi square distributions with df1 and df2 degrees of freedom, respectively. The incomplete beta integral is used, according to the formula P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). The arguments a and b are greater than zero, and x is nonnegative. ACCURACY: Tested at random points (a,b,x). x a,b Relative error: arithmetic domain domain # trials peak rms IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::fdistribution(ae_int_t a, ae_int_t b, double x);
/************************************************************************* Inverse of complemented F distribution Finds the F density argument x such that the integral from x to infinity of the F density is equal to the given probability p. This is accomplished using the inverse beta integral function and the relations z = incbi( df2/2, df1/2, p ) x = df2 (1-z) / (df1 z). Note: the following relations hold for the inverse of the uncomplemented F distribution: z = incbi( df1/2, df2/2, p ) x = df2 z / (df1 (1-z)). ACCURACY: Tested at random points (a,b,p). a,b Relative error: arithmetic domain # trials peak rms For p between .001 and 1: IEEE 1,100 100000 8.3e-15 4.7e-16 IEEE 1,10000 100000 2.1e-11 1.4e-13 For p between 10^-6 and 10^-3: IEEE 1,100 50000 1.3e-12 8.4e-15 IEEE 1,10000 50000 3.0e-12 4.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invfdistribution(ae_int_t a, ae_int_t b, double y);
fftc1d
fftc1dinv
fftr1d
fftr1dinv
fft_complex_d1 Complex FFT: simple example
fft_complex_d2 Complex FFT: advanced example
fft_real_d1 Real FFT: simple example
fft_real_d2 Real FFT: advanced example
/************************************************************************* 1-dimensional complex FFT. Array size N may be arbitrary number (composite or prime). Composite N's are handled with cache-oblivious variation of a Cooley-Tukey algorithm. Small prime-factors are transformed using hard coded codelets (similar to FFTW codelets, but without low-level optimization), large prime-factors are handled with Bluestein's algorithm. Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), most fast for powers of 2. When N have prime factors larger than these, but orders of magnitude smaller than N, computations will be about 4 times slower than for nearby highly composite N's. When N itself is prime, speed will be 6 times lower. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex function to be transformed N - problem size OUTPUT PARAMETERS A - DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fftc1d(complex_1d_array& a); void alglib::fftc1d(complex_1d_array& a, ae_int_t n);

Examples:   [1]  [2]  

/************************************************************************* 1-dimensional complex inverse FFT. Array size N may be arbitrary number (composite or prime). Algorithm has O(N*logN) complexity for any N (composite or prime). See FFTC1D() description for more information about algorithm performance. INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fftc1dinv(complex_1d_array& a); void alglib::fftc1dinv(complex_1d_array& a, ae_int_t n);

Examples:   [1]  [2]  

/************************************************************************* 1-dimensional real FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS F - DFT of a input array, array[0..N-1] F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) NOTE: F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half of array is usually needed. But for convinience subroutine returns full complex array (with frequencies above N/2), so its result may be used by other FFT-related subroutines. -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fftr1d(real_1d_array a, complex_1d_array& f); void alglib::fftr1d(real_1d_array a, ae_int_t n, complex_1d_array& f);

Examples:   [1]  [2]  

/************************************************************************* 1-dimensional real inverse FFT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS F - array[0..floor(N/2)] - frequencies from forward real FFT N - problem size OUTPUT PARAMETERS A - inverse DFT of a input array, array[0..N-1] NOTE: F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one half of frequencies array is needed - elements from 0 to floor(N/2). F[0] is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then F[floor(N/2)] has no special properties. Relying on properties noted above, FFTR1DInv subroutine uses only elements from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case N is even it ignores imaginary part of F[floor(N/2)] too. When you call this function using full arguments list - "FFTR1DInv(F,N,A)" - you can pass either either frequencies array with N elements or reduced array with roughly N/2 elements - subroutine will successfully transform both. If you call this function using reduced arguments list - "FFTR1DInv(F,A)" - you must pass FULL array with N elements (although higher N/2 are still not used) because array size is used to automatically determine FFT length -- ALGLIB -- Copyright 01.06.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fftr1dinv(complex_1d_array f, real_1d_array& a); void alglib::fftr1dinv(complex_1d_array f, ae_int_t n, real_1d_array& a);

Examples:   [1]  [2]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "fasttransforms.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // first we demonstrate forward FFT:
    // [1i,1i,1i,1i] is converted to [4i, 0, 0, 0]
    //
    complex_1d_array z = "[1i,1i,1i,1i]";
    fftc1d(z);
    printf("%s\n", z.tostring(3).c_str()); // EXPECTED: [4i,0,0,0]

    //
    // now we convert [4i, 0, 0, 0] back to [1i,1i,1i,1i]
    // with backward FFT
    //
    fftc1dinv(z);
    printf("%s\n", z.tostring(3).c_str()); // EXPECTED: [1i,1i,1i,1i]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "fasttransforms.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // first we demonstrate forward FFT:
    // [0,1,0,1i] is converted to [1+1i, -1-1i, -1-1i, 1+1i]
    //
    complex_1d_array z = "[0,1,0,1i]";
    fftc1d(z);
    printf("%s\n", z.tostring(3).c_str()); // EXPECTED: [1+1i, -1-1i, -1-1i, 1+1i]

    //
    // now we convert result back with backward FFT
    //
    fftc1dinv(z);
    printf("%s\n", z.tostring(3).c_str()); // EXPECTED: [0,1,0,1i]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "fasttransforms.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // first we demonstrate forward FFT:
    // [1,1,1,1] is converted to [4, 0, 0, 0]
    //
    real_1d_array x = "[1,1,1,1]";
    complex_1d_array f;
    real_1d_array x2;
    fftr1d(x, f);
    printf("%s\n", f.tostring(3).c_str()); // EXPECTED: [4,0,0,0]

    //
    // now we convert [4, 0, 0, 0] back to [1,1,1,1]
    // with backward FFT
    //
    fftr1dinv(f, x2);
    printf("%s\n", x2.tostring(3).c_str()); // EXPECTED: [1,1,1,1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "fasttransforms.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // first we demonstrate forward FFT:
    // [1,2,3,4] is converted to [10, -2+2i, -2, -2-2i]
    //
    // note that output array is self-adjoint:
    // * f[0] = conj(f[0])
    // * f[1] = conj(f[3])
    // * f[2] = conj(f[2])
    //
    real_1d_array x = "[1,2,3,4]";
    complex_1d_array f;
    real_1d_array x2;
    fftr1d(x, f);
    printf("%s\n", f.tostring(3).c_str()); // EXPECTED: [10, -2+2i, -2, -2-2i]

    //
    // now we convert [10, -2+2i, -2, -2-2i] back to [1,2,3,4]
    //
    fftr1dinv(f, x2);
    printf("%s\n", x2.tostring(3).c_str()); // EXPECTED: [1,2,3,4]

    //
    // remember that F is self-adjoint? It means that we can pass just half
    // (slightly larger than half) of F to inverse real FFT and still get our result.
    //
    // I.e. instead [10, -2+2i, -2, -2-2i] we pass just [10, -2+2i, -2] and everything works!
    //
    // NOTE: in this case we should explicitly pass array length (which is 4) to ALGLIB;
    // if not, it will automatically use array length to determine FFT size and
    // will erroneously make half-length FFT.
    //
    f = "[10, -2+2i, -2]";
    fftr1dinv(f, 4, x2);
    printf("%s\n", x2.tostring(3).c_str()); // EXPECTED: [1,2,3,4]
    return 0;
}


fhtr1d
fhtr1dinv
/************************************************************************* 1-dimensional Fast Hartley Transform. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS A - FHT of a input array, array[0..N-1], A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) -- ALGLIB -- Copyright 04.06.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fhtr1d(real_1d_array& a, ae_int_t n);
/************************************************************************* 1-dimensional inverse FHT. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - complex array to be transformed N - problem size OUTPUT PARAMETERS A - inverse FHT of a input array, array[0..N-1] -- ALGLIB -- Copyright 29.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::fhtr1dinv(real_1d_array& a, ae_int_t n);
filterema
filterlrma
filtersma
filters_d_ema EMA(alpha) filter
filters_d_lrma LRMA(k) filter
filters_d_sma SMA(k) filter
/************************************************************************* Filters: exponential moving averages. This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is defined as filter which replaces X[] by S[]: S[0] = X[0] S[t] = alpha*X[t] + (1-alpha)*S[t-1] INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 alpha - 0<alpha<=1, smoothing parameter. OUTPUT PARAMETERS: X - array, whose first N elements were processed with EMA(alpha) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. NOTE 3: technical analytis users quite often work with EMA coefficient expressed in DAYS instead of fractions. If you want to calculate EMA(N), where N is a number of days, you can use alpha=2/(N+1). -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::filterema(real_1d_array& x, double alpha); void alglib::filterema(real_1d_array& x, ae_int_t n, double alpha);

Examples:   [1]  

/************************************************************************* Filters: linear regression moving averages. This filter replaces array by results of LRMA(K) filter. LRMA(K) is defined as filter which, for each data point, builds linear regression model using K prevous points (point itself is included in these K points) and calculates value of this linear model at the point in question. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::filterlrma(real_1d_array& x, ae_int_t k); void alglib::filterlrma(real_1d_array& x, ae_int_t n, ae_int_t k);

Examples:   [1]  

/************************************************************************* Filters: simple moving averages (unsymmetric). This filter replaces array by results of SMA(K) filter. SMA(K) is defined as filter which averages at most K previous points (previous - not points AROUND central point) - or less, in case of the first K-1 points. INPUT PARAMETERS: X - array[N], array to process. It can be larger than N, in this case only first N points are processed. N - points count, N>=0 K - K>=1 (K can be larger than N , such cases will be correctly handled). Window width. K=1 corresponds to identity transformation (nothing changes). OUTPUT PARAMETERS: X - array, whose first N elements were processed with SMA(K) NOTE 1: this function uses efficient in-place algorithm which does not allocate temporary arrays. NOTE 2: this algorithm makes only one pass through array and uses running sum to speed-up calculation of the averages. Additional measures are taken to ensure that running sum on a long sequence of zero elements will be correctly reset to zero even in the presence of round-off error. NOTE 3: this is unsymmetric version of the algorithm, which does NOT averages points after the current one. Only X[i], X[i-1], ... are used when calculating new value of X[i]. We should also note that this algorithm uses BOTH previous points and current one, i.e. new value of X[i] depends on BOTH previous point and X[i] itself. -- ALGLIB -- Copyright 25.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::filtersma(real_1d_array& x, ae_int_t k); void alglib::filtersma(real_1d_array& x, ae_int_t n, ae_int_t k);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Here we demonstrate EMA(0.5) filtering for time series.
    //
    real_1d_array x = "[5,6,7,8]";

    //
    // Apply filter.
    // We should get [5, 5.5, 6.25, 7.125] as result
    //
    filterema(x, 0.5);
    printf("%s\n", x.tostring(4).c_str()); // EXPECTED: [5,5.5,6.25,7.125]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Here we demonstrate LRMA(3) filtering for time series.
    //
    real_1d_array x = "[7,8,8,9,12,12]";

    //
    // Apply filter.
    // We should get [7.0000, 8.0000, 8.1667, 8.8333, 11.6667, 12.5000] as result
    //    
    filterlrma(x, 3);
    printf("%s\n", x.tostring(4).c_str()); // EXPECTED: [7.0000,8.0000,8.1667,8.8333,11.6667,12.5000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Here we demonstrate SMA(k) filtering for time series.
    //
    real_1d_array x = "[5,6,7,8]";

    //
    // Apply filter.
    // We should get [5, 5.5, 6.5, 7.5] as result
    //
    filtersma(x, 2);
    printf("%s\n", x.tostring(4).c_str()); // EXPECTED: [5,5.5,6.5,7.5]
    return 0;
}


fresnelintegral
/************************************************************************* Fresnel integral Evaluates the Fresnel integrals x - | | C(x) = | cos(pi/2 t**2) dt, | | - 0 x - | | S(x) = | sin(pi/2 t**2) dt. | | - 0 The integrals are evaluated by a power series for x < 1. For x >= 1 auxiliary functions f(x) and g(x) are employed such that C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) ACCURACY: Relative error. Arithmetic function domain # trials peak rms IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier *************************************************************************/
void alglib::fresnelintegral(double x, double& c, double& s);
gammafunction
lngamma
/************************************************************************* Gamma function Input parameters: X - argument Domain: 0 < X < 171.6 -170 < X < 0, X is not an integer. Relative error: arithmetic domain # trials peak rms IEEE -170,-33 20000 2.3e-15 3.3e-16 IEEE -33, 33 20000 9.4e-16 2.2e-16 IEEE 33, 171.6 20000 2.3e-15 3.2e-16 Cephes Math Library Release 2.8: June, 2000 Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/
double alglib::gammafunction(double x);
/************************************************************************* Natural logarithm of gamma function Input parameters: X - argument Result: logarithm of the absolute value of the Gamma(X). Output parameters: SgnGam - sign(Gamma(X)) Domain: 0 < X < 2.55e305 -2.55e305 < X < 0, X is not an integer. ACCURACY: arithmetic domain # trials peak rms IEEE 0, 3 28000 5.4e-16 1.1e-16 IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 The error criterion was relative when the function magnitude was greater than one but absolute when it was less than one. The following test used the relative error criterion, though at certain points the relative error could be much higher than indicated. IEEE -200, -4 10000 4.8e-16 1.3e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). *************************************************************************/
double alglib::lngamma(double x, double& sgngam);
/************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK * +2 OK, but quadrature rule have exterior nodes, x[0]<-1 or x[n-1]>+1 X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gkqgenerategaussjacobi( ae_int_t n, double alpha, double beta, ae_int_t& info, real_1d_array& x, real_1d_array& wkronrod, real_1d_array& wgauss);
/************************************************************************* Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre quadrature with N points. GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is used depending on machine precision and number of nodes. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gkqgenerategausslegendre( ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& wkronrod, real_1d_array& wgauss);
/************************************************************************* Computation of nodes and weights of a Gauss-Kronrod quadrature formula The algorithm generates the N-point Gauss-Kronrod quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zero moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha alpha coefficients, array[0..floor(3*K/2)]. Beta beta coefficients, array[0..ceil(3*K/2)]. Beta[0] is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the Gauss-Kronrod quadrature formula, N >= 3, N = 2*K+1. OUTPUT PARAMETERS: Info - error code: * -5 no real and positive Gauss-Kronrod formula can be created for such a weight function with a given number of nodes. * -4 N is too large, task may be ill conditioned - x[i]=x[i+1] found. * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 08.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gkqgeneraterec( real_1d_array alpha, real_1d_array beta, double mu0, ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& wkronrod, real_1d_array& wgauss);
/************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. Reduction to tridiagonal eigenproblem is used. INPUT PARAMETERS: N - number of Kronrod nodes, must be odd number, >=3. OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gkqlegendrecalc( ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& wkronrod, real_1d_array& wgauss);
/************************************************************************* Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using pre-calculated table. Nodes/weights were computed with accuracy up to 1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision accuracy reduces to something about 2.0E-16 (depending on your compiler's handling of long floating point constants). INPUT PARAMETERS: N - number of Kronrod nodes. N can be 15, 21, 31, 41, 51, 61. OUTPUT PARAMETERS: X - array[0..N-1] - array of quadrature nodes, ordered in ascending order. WKronrod - array[0..N-1] - Kronrod weights WGauss - array[0..N-1] - Gauss weights (interleaved with zeros corresponding to extended Kronrod nodes). -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gkqlegendretbl( ae_int_t n, real_1d_array& x, real_1d_array& wkronrod, real_1d_array& wgauss, double& eps);
/************************************************************************* Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with weight function W(x)=Exp(-x*x) INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. May be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategausshermite( ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 Beta - power-law coefficient, Beta>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha or Beta are too close to -1 to obtain weights/nodes with high enough accuracy, or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha/Beta was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategaussjacobi( ae_int_t n, double alpha, double beta, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with weight function W(x)=Power(x,Alpha)*Exp(-x) INPUT PARAMETERS: N - number of nodes, >=1 Alpha - power-law coefficient, Alpha>-1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. Alpha is too close to -1 to obtain weights/nodes with high enough accuracy or, may be, N is too large. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N/Alpha was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategausslaguerre( ae_int_t n, double alpha, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N nodes. INPUT PARAMETERS: N - number of nodes, >=1 OUTPUT PARAMETERS: Info - error code: * -4 an error was detected when calculating weights/nodes. N is too large to obtain weights/nodes with high enough accuracy. Try to use multiple precision version. * -3 internal eigenproblem solver hasn't converged * -1 incorrect N was passed * +1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 12.05.2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategausslegendre( ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Computation of nodes and weights for a Gauss-Lobatto quadrature formula The algorithm generates the N-point Gauss-Lobatto quadrature formula with weight function given by coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients Beta array[0..N-2], beta coefficients. Zero-indexed element is not used, may be arbitrary. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. B right boundary of the integration interval. N number of nodes of the quadrature formula, N>=3 (including the left and right boundary nodes). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategausslobattorec( real_1d_array alpha, real_1d_array beta, double mu0, double a, double b, ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Computation of nodes and weights for a Gauss-Radau quadrature formula The algorithm generates the N-point Gauss-Radau quadrature formula with weight function given by the coefficients alpha and beta of a recurrence which generates a system of orthogonal polynomials. P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-2], alpha coefficients. Beta array[0..N-1], beta coefficients Zero-indexed element is not used. Beta[I]>0 Mu0 zeroth moment of the weighting function. A left boundary of the integration interval. N number of nodes of the quadrature formula, N>=2 (including the left boundary node). OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgenerategaussradaurec( real_1d_array alpha, real_1d_array beta, double mu0, double a, ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Computation of nodes and weights for a Gauss quadrature formula The algorithm generates the N-point Gauss quadrature formula with weight function given by coefficients alpha and beta of a recurrence relation which generates a system of orthogonal polynomials: P-1(x) = 0 P0(x) = 1 Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) and zeroth moment Mu0 Mu0 = integral(W(x)dx,a,b) INPUT PARAMETERS: Alpha array[0..N-1], alpha coefficients Beta array[0..N-1], beta coefficients Zero-indexed element is not used and may be arbitrary. Beta[I]>0. Mu0 zeroth moment of the weight function. N number of nodes of the quadrature formula, N>=1 OUTPUT PARAMETERS: Info - error code: * -3 internal eigenproblem solver hasn't converged * -2 Beta[i]<=0 * -1 incorrect N was passed * 1 OK X - array[0..N-1] - array of quadrature nodes, in ascending order. W - array[0..N-1] - array of quadrature weights. -- ALGLIB -- Copyright 2005-2009 by Bochkanov Sergey *************************************************************************/
void alglib::gqgeneraterec( real_1d_array alpha, real_1d_array beta, double mu0, ae_int_t n, ae_int_t& info, real_1d_array& x, real_1d_array& w);
/************************************************************************* Calculation of the value of the Hermite polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial Hn at x *************************************************************************/
double alglib::hermitecalculate(ae_int_t n, double x);
/************************************************************************* Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/
void alglib::hermitecoefficients(ae_int_t n, real_1d_array& c);
/************************************************************************* Summation of Hermite polynomials using Clenshaws recurrence formula. This routine calculates c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Hermite polynomial at x *************************************************************************/
double alglib::hermitesum(real_1d_array c, ae_int_t n, double x);
/************************************************************************* Portable high quality random number generator state. Initialized with HQRNDRandomize() or HQRNDSeed(). Fields: S1, S2 - seed values V - precomputed value MagicV - 'magic' value used to determine whether State structure was correctly initialized. *************************************************************************/
class hqrndstate { };
/************************************************************************* This function generates random number from continuous distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample, array[N] (can be larger, in this case only leading N elements are used). THIS ARRAY MUST BE SORTED BY ASCENDING. N - number of elements to use, N>=1 RESULT this function returns random number from continuous distribution which tries to approximate X as mush as possible. min(X)<=Result<=max(X). -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/
double alglib::hqrndcontinuous( hqrndstate state, real_1d_array x, ae_int_t n);
/************************************************************************* This function generates random number from discrete distribution given by finite sample X. INPUT PARAMETERS State - high quality random number generator, must be initialized with HQRNDRandomize() or HQRNDSeed(). X - finite sample N - number of elements to use, N>=1 RESULT this function returns one of the X[i] for random i=0..N-1 -- ALGLIB -- Copyright 08.11.2011 by Bochkanov Sergey *************************************************************************/
double alglib::hqrnddiscrete( hqrndstate state, real_1d_array x, ae_int_t n);
/************************************************************************* Random number generator: exponential distribution State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 11.08.2007 by Bochkanov Sergey *************************************************************************/
double alglib::hqrndexponential(hqrndstate state, double lambdav);
/************************************************************************* Random number generator: normal numbers This function generates one random number from normal distribution. Its performance is equal to that of HQRNDNormal2() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
double alglib::hqrndnormal(hqrndstate state);
/************************************************************************* Random number generator: normal numbers This function generates two independent random numbers from normal distribution. Its performance is equal to that of HQRNDNormal() State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::hqrndnormal2(hqrndstate state, double& x1, double& x2);
/************************************************************************* HQRNDState initialization with random values which come from standard RNG. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::hqrndrandomize(hqrndstate& state);
/************************************************************************* HQRNDState initialization with seed values -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::hqrndseed(ae_int_t s1, ae_int_t s2, hqrndstate& state);
/************************************************************************* This function generates random integer number in [0, N) 1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() 2. N can be any positive number except for very large numbers: * close to 2^31 on 32-bit systems * close to 2^62 on 64-bit systems An exception will be generated if N is too large. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::hqrnduniformi(hqrndstate state, ae_int_t n);
/************************************************************************* This function generates random real number in (0,1), not including interval boundaries State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
double alglib::hqrnduniformr(hqrndstate state);
/************************************************************************* Random number generator: random X and Y such that X^2+Y^2=1 State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::hqrndunit2(hqrndstate state, double& x, double& y);
incompletebeta
invincompletebeta
/************************************************************************* Incomplete beta integral Returns incomplete beta integral of the arguments, evaluated from zero to x. The function is defined as x - - | (a+b) | | a-1 b-1 ----------- | t (1-t) dt. - - | | | (a) | (b) - 0 The domain of definition is 0 <= x <= 1. In this implementation a and b are restricted to positive values. The integral from x to 1 may be obtained by the symmetry relation 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). The integral is evaluated by a continued fraction expansion or, when b*x is small, by a power series. ACCURACY: Tested at uniformly distributed random points (a,b,x) with a and b in "domain" and x between 0 and 1. Relative error arithmetic domain # trials peak rms IEEE 0,5 10000 6.9e-15 4.5e-16 IEEE 0,85 250000 2.2e-13 1.7e-14 IEEE 0,1000 30000 5.3e-12 6.3e-13 IEEE 0,10000 250000 9.3e-11 7.1e-12 IEEE 0,100000 10000 8.7e-10 4.8e-11 Outputs smaller than the IEEE gradual underflow threshold were excluded from these statistics. Cephes Math Library, Release 2.8: June, 2000 Copyright 1984, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::incompletebeta(double a, double b, double x);
/************************************************************************* Inverse of imcomplete beta integral Given y, the function finds x such that incbet( a, b, x ) = y . The routine performs interval halving or Newton iterations to find the root of incbet(a,b,x) - y = 0. ACCURACY: Relative error: x a,b arithmetic domain domain # trials peak rms IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 With a and b constrained to half-integer or integer values: IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 With a = .5, b constrained to half-integer or integer values: IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1996, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invincompletebeta(double a, double b, double y);
/************************************************************************* IDW interpolant. *************************************************************************/
class idwinterpolant { };
/************************************************************************* IDW interpolant using modified Shepard method for uniform point distributions. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function type, either: * 0 constant model. Just for demonstration only, worst model ever. * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). * -1 "fast" linear model, use with caution!!! It is significantly faster than linear/quadratic and better than constant model. But it is less robust (especially in the presence of noise). NQ - number of points used to calculate nodal functions (ignored for constant models). NQ should be LARGER than: * max(1.5*(1+NX),2^NX+1) for linear model, * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, worst - with constant models * when N is large, NQ and NW must be significantly smaller than N both to obtain optimal performance and to obtain optimal accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are good values to start with. * NQ and NW may be greater than N. In such cases they will be automatically decreased. * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. * this subroutine assumes that point distribution is uniform at the small scales. If it isn't - for example, points are concentrated along "lines", but "lines" distribution is uniform at the larger scale - then you should use IDWBuildModifiedShepardR() -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/
void alglib::idwbuildmodifiedshepard( real_2d_array xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant& z);
/************************************************************************* IDW interpolant using modified Shepard method for non-uniform datasets. This type of model uses constant nodal functions and interpolates using all nodes which are closer than user-specified radius R. It may be used when points distribution is non-uniform at the small scale, but it is at the distances as large as R. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. R - radius, R>0 OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * if there is less than IDWKMin points within R-ball, algorithm selects IDWKMin closest ones, so that continuity properties of interpolant are preserved even far from points. -- ALGLIB PROJECT -- Copyright 11.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::idwbuildmodifiedshepardr( real_2d_array xy, ae_int_t n, ae_int_t nx, double r, idwinterpolant& z);
/************************************************************************* IDW model for noisy data. This subroutine may be used to handle noisy data, i.e. data with noise in OUTPUT values. It differs from IDWBuildModifiedShepard() in the following aspects: * nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, i.e. we have fitting instead of interpolation. * weights which are used during least squares fitting stage are all equal to 1.0 (independently of distance) * "fast"-linear or constant nodal functions are not supported (either not robust enough or too rigid) This problem require far more complex tuning than interpolation problems. Below you can find some recommendations regarding this problem: * focus on tuning NQ; it controls noise reduction. As for NW, you can just make it equal to 2*NQ. * you can use cross-validation to determine optimal NQ. * optimal NQ is a result of complex tradeoff between noise level (more noise = larger NQ required) and underlying function complexity (given fixed N, larger NQ means smoothing of compex features in the data). For example, NQ=N will reduce noise to the minimum level possible, but you will end up with just constant/linear/quadratic (depending on D) least squares model for the whole dataset. INPUT PARAMETERS: XY - X and Y values, array[0..N-1,0..NX]. First NX columns contain X-values, last column contain Y-values. N - number of nodes, N>0. NX - space dimension, NX>=1. D - nodal function degree, either: * 1 linear model, least squares fitting. Simpe model for datasets too small for quadratic models (or for very noisy problems). * 2 quadratic model, least squares fitting. Best model available (if your dataset is large enough). NQ - number of points used to calculate nodal functions. NQ should be significantly larger than 1.5 times the number of coefficients in a nodal function to overcome effects of noise: * larger than 1.5*(1+NX) for linear model, * larger than 3/4*(NX+2)*(NX+1) for quadratic model. Values less than this threshold will be silently increased. NW - number of points used to calculate weights and to interpolate. Required: >=2^NX+1, values less than this threshold will be silently increased. Recommended value: about 2*NQ or larger OUTPUT PARAMETERS: Z - IDW interpolant. NOTES: * best results are obtained with quadratic models, linear models are not recommended to use unless you are pretty sure that it is what you want * this subroutine is always succeeds (as long as correct parameters are passed). * see 'Multivariate Interpolation of Large Sets of Scattered Data' by Robert J. Renka for more information on this algorithm. -- ALGLIB PROJECT -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/
void alglib::idwbuildnoisy( real_2d_array xy, ae_int_t n, ae_int_t nx, ae_int_t d, ae_int_t nq, ae_int_t nw, idwinterpolant& z);
/************************************************************************* IDW interpolation INPUT PARAMETERS: Z - IDW interpolant built with one of model building subroutines. X - array[0..NX-1], interpolation point Result: IDW interpolant Z(X) -- ALGLIB -- Copyright 02.03.2010 by Bochkanov Sergey *************************************************************************/
double alglib::idwcalc(idwinterpolant z, real_1d_array x);
/************************************************************************* Incomplete gamma integral The function is defined by x - 1 | | -t a-1 igam(a,x) = ----- | e t dt. - | | | (a) - 0 In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,30 200000 3.6e-14 2.9e-15 IEEE 0,100 300000 9.9e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::incompletegamma(double a, double x);
/************************************************************************* Complemented incomplete gamma integral The function is defined by igamc(a,x) = 1 - igam(a,x) inf. - 1 | | -t a-1 = ----- | e t dt. - | | | (a) - x In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x. ACCURACY: Tested at random a, x. a x Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1985, 1987, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::incompletegammac(double a, double x);
/************************************************************************* Inverse of complemented imcomplete gamma integral Given p, the function finds x such that igamc( a, x ) = p. Starting with the approximate value 3 x = a t where t = 1 - d - ndtri(p) sqrt(d) and d = 1/9a, the routine performs up to 10 Newton iterations to find the root of igamc(a,x) - p = 0. ACCURACY: Tested at random a, p in the intervals indicated. a p Relative error: arithmetic domain domain # trials peak rms IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invincompletegammac(double a, double y0);
/************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a column of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdColumn - the column of A whose vector U was added. 0 <= UpdColumn <= N-1 U - the vector to be added to a column. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixinvupdatecolumn( real_2d_array& inva, ae_int_t n, ae_int_t updcolumn, real_1d_array u);
/************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a vector to a row of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - the row of A whose vector V was added. 0 <= Row <= N-1 V - the vector to be added to a row. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixinvupdaterow( real_2d_array& inva, ae_int_t n, ae_int_t updrow, real_1d_array v);
/************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm updates matrix A^-1 when adding a number to an element of matrix A. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. UpdRow - row where the element to be updated is stored. UpdColumn - column where the element to be updated is stored. UpdVal - a number to be added to the element. Output parameters: InvA - inverse of modified matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixinvupdatesimple( real_2d_array& inva, ae_int_t n, ae_int_t updrow, ae_int_t updcolumn, double updval);
/************************************************************************* Inverse matrix update by the Sherman-Morrison formula The algorithm computes the inverse of matrix A+u*v by using the given matrix A^-1 and the vectors u and v. Input parameters: InvA - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. U - the vector modifying the matrix. Array whose index ranges within [0..N-1]. V - the vector modifying the matrix. Array whose index ranges within [0..N-1]. Output parameters: InvA - inverse of matrix A + u*v'. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixinvupdateuv( real_2d_array& inva, ae_int_t n, real_1d_array u, real_1d_array v);
jacobianellipticfunctions
/************************************************************************* Jacobian Elliptic Functions Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), and dn(u|m) of parameter m between 0 and 1, and real argument u. These functions are periodic, with quarter-period on the real axis equal to the complete elliptic integral ellpk(1.0-m). Relation to incomplete elliptic integral: If u = ellik(phi,m), then sn(u|m) = sin(phi), and cn(u|m) = cos(phi). Phi is called the amplitude of u. Computation is by means of the arithmetic-geometric mean algorithm, except when m is within 1e-9 of 0 or 1. In the latter case with m close to 1, the approximation applies only for phi < pi/2. ACCURACY: Tested at random points with u between 0 and 10, m between 0 and 1. Absolute error (* = relative error): arithmetic function # trials peak rms IEEE phi 10000 9.2e-16* 1.4e-16* IEEE sn 50000 4.1e-15 4.6e-16 IEEE cn 40000 3.6e-15 4.4e-16 IEEE dn 10000 1.3e-12 1.8e-14 Peak error observed in consistency check using addition theorem for sn(u+v) was 4e-16 (absolute). Also tested by the above relation to the incomplete elliptic integral. Accuracy deteriorates when u is large. Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
void alglib::jacobianellipticfunctions( double u, double m, double& sn, double& cn, double& dn, double& ph);
jarqueberatest
/************************************************************************* Jarque-Bera test This test checks hypotheses about the fact that a given sample X is a sample of normal random variable. Requirements: * the number of elements in the sample is not less than 5. Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Output parameters: P - p-value for the test Accuracy of the approximation used (5<=N<=1951): p-value relative error (5<=N<=1951) [1, 0.1] < 1% [0.1, 0.01] < 2% [0.01, 0.001] < 6% [0.001, 0] wasn't measured For N>1951 accuracy wasn't measured but it shouldn't be sharply different from table values. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
void alglib::jarqueberatest(real_1d_array x, ae_int_t n, double& p);
/************************************************************************* Calculation of the value of the Laguerre polynomial. Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial Ln at x *************************************************************************/
double alglib::laguerrecalculate(ae_int_t n, double x);
/************************************************************************* Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/
void alglib::laguerrecoefficients(ae_int_t n, real_1d_array& c);
/************************************************************************* Summation of Laguerre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Laguerre polynomial at x *************************************************************************/
double alglib::laguerresum(real_1d_array c, ae_int_t n, double x);
fisherlda
fisherldan
/************************************************************************* Multiclass Fisher LDA Subroutine finds coefficients of linear combination which optimally separates training set on classes. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - linear combination coefficients, array[0..NVars-1] -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/
void alglib::fisherlda( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t& info, real_1d_array& w);
/************************************************************************* N-dimensional multiclass Fisher LDA Subroutine finds coefficients of linear combinations which optimally separates training set on classes. It returns N-dimensional basis whose vector are sorted by quality of training set separation (in descending order). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! Multithreading is used to accelerate initial phase of LDA, which ! includes calculation of products of large matrices. Again, for best ! efficiency problem must be high-dimensional. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars]. First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=0 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -4, if internal EVD subroutine hasn't converged * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, NVars<1, NClasses<2) * 1, if task has been solved * 2, if there was a multicollinearity in training set, but task has been solved. W - basis, array[0..NVars-1,0..NVars-1] columns of matrix stores basis vectors, sorted by quality of training set separation (in descending order) -- ALGLIB -- Copyright 31.05.2008 by Bochkanov Sergey *************************************************************************/
void alglib::fisherldan( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t& info, real_2d_array& w); void alglib::smp_fisherldan( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t& info, real_2d_array& w);
/************************************************************************* Calculation of the value of the Legendre polynomial Pn. Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial Pn at x *************************************************************************/
double alglib::legendrecalculate(ae_int_t n, double x);
/************************************************************************* Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N Input parameters: N - polynomial degree, n>=0 Output parameters: C - coefficients *************************************************************************/
void alglib::legendrecoefficients(ae_int_t n, real_1d_array& c);
/************************************************************************* Summation of Legendre polynomials using Clenshaws recurrence formula. This routine calculates c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) Parameters: n - degree, n>=0 x - argument Result: the value of the Legendre polynomial at x *************************************************************************/
double alglib::legendresum(real_1d_array c, ae_int_t n, double x);
/************************************************************************* *************************************************************************/
class lincgreport { ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; double r2; };
/************************************************************************* This object stores state of the linear CG method. You should use ALGLIB functions to work with this object. Never try to access its fields directly! *************************************************************************/
class lincgstate { };
/************************************************************************* This function initializes linear CG Solver. This solver is used to solve symmetric positive definite problems. If you want to solve nonsymmetric (or non-positive definite) problem you may use LinLSQR solver provided by ALGLIB. USAGE: 1. User initializes algorithm state with LinCGCreate() call 2. User tunes solver parameters with LinCGSetCond() and other functions 3. Optionally, user sets starting point with LinCGSetStartingPoint() 4. User calls LinCGSolveSparse() function which takes algorithm state and SparseMatrix object. 5. User calls LinCGResults() to get solution 6. Optionally, user may call LinCGSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinCGState structure. INPUT PARAMETERS: N - problem dimension, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgcreate(ae_int_t n, lincgstate& state);

Examples:   [1]  

/************************************************************************* CG-solver: results. This function must be called after LinCGSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * -5 input matrix is either not positive definite, too large or too small * -4 overflow/underflow during solution (ill conditioned problem) * 1 ||residual||<=EpsF*||b|| * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, best point found is returned * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgresults( lincgstate state, real_1d_array& x, lincgreport& rep);

Examples:   [1]  

/************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsF - algorithm will be stopped if norm of residual is less than EpsF*||b||. MaxIts - algorithm will be stopped if number of iterations is more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: If both EpsF and MaxIts are zero then small EpsF will be set to small value. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetcond(lincgstate state, double epsf, ae_int_t maxits);
/************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetprecdiag(lincgstate state);
/************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetprecunit(lincgstate state);
/************************************************************************* This function sets restart frequency. By default, algorithm is restarted after N subsequent iterations. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetrestartfreq(lincgstate state, ae_int_t srf);
/************************************************************************* This function sets frequency of residual recalculations. Algorithm updates residual r_k using iterative formula, but recalculates it from scratch after each 10 iterations. It is done to avoid accumulation of numerical errors and to stop algorithm when r_k starts to grow. Such low update frequence (1/10) gives very little overhead, but makes algorithm a bit more robust against numerical errors. However, you may change it INPUT PARAMETERS: Freq - desired update frequency, Freq>=0. Zero value means that no updates will be done. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetrupdatefreq(lincgstate state, ae_int_t freq);
/************************************************************************* This function sets starting point. By default, zero starting point is used. INPUT PARAMETERS: X - starting point, array[N] OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetstartingpoint(lincgstate state, real_1d_array x);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsetxrep(lincgstate state, bool needxrep);
/************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function). IsUpper - whether upper or lower triangle of A is used: * IsUpper=True => only upper triangle is used and lower triangle is not referenced at all * IsUpper=False => only lower triangle is used and upper triangle is not referenced at all B - right part, array[N] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinCGSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 14.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lincgsolvesparse( lincgstate state, sparsematrix a, bool isupper, real_1d_array b);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "solvers.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example illustrates solution of sparse linear systems with
    // conjugate gradient method.
    // 
    // Suppose that we have linear system A*x=b with sparse symmetric
    // positive definite A (represented by sparsematrix object)
    //         [ 5 1       ]
    //         [ 1 7 2     ]
    //     A = [   2 8 1   ]
    //         [     1 4 1 ]
    //         [       1 4 ]
    // and right part b
    //     [  7 ]
    //     [ 17 ]
    // b = [ 14 ]
    //     [ 10 ]
    //     [  6 ]
    // and we want to solve this system using sparse linear CG. In order
    // to do so, we have to create left part (sparsematrix object) and
    // right part (dense array).
    //
    // Initially, sparse matrix is created in the Hash-Table format,
    // which allows easy initialization, but do not allow matrix to be
    // used in the linear solvers. So after construction you should convert
    // sparse matrix to CRS format (one suited for linear operations).
    //
    // It is important to note that in our example we initialize full
    // matrix A, both lower and upper triangles. However, it is symmetric
    // and sparse solver needs just one half of the matrix. So you may
    // save about half of the space by filling only one of the triangles.
    //
    sparsematrix a;
    sparsecreate(5, 5, a);
    sparseset(a, 0, 0, 5.0);
    sparseset(a, 0, 1, 1.0);
    sparseset(a, 1, 0, 1.0);
    sparseset(a, 1, 1, 7.0);
    sparseset(a, 1, 2, 2.0);
    sparseset(a, 2, 1, 2.0);
    sparseset(a, 2, 2, 8.0);
    sparseset(a, 2, 3, 1.0);
    sparseset(a, 3, 2, 1.0);
    sparseset(a, 3, 3, 4.0);
    sparseset(a, 3, 4, 1.0);
    sparseset(a, 4, 3, 1.0);
    sparseset(a, 4, 4, 4.0);

    //
    // Now our matrix is fully initialized, but we have to do one more
    // step - convert it from Hash-Table format to CRS format (see
    // documentation on sparse matrices for more information about these
    // formats).
    //
    // If you omit this call, ALGLIB will generate exception on the first
    // attempt to use A in linear operations. 
    //
    sparseconverttocrs(a);

    //
    // Initialization of the right part
    //
    real_1d_array b = "[7,17,14,10,6]";

    //
    // Now we have to create linear solver object and to use it for the
    // solution of the linear system.
    //
    // NOTE: lincgsolvesparse() accepts additional parameter which tells
    //       what triangle of the symmetric matrix should be used - upper
    //       or lower. Because we've filled both parts of the matrix, we
    //       can use any part - upper or lower.
    //
    lincgstate s;
    lincgreport rep;
    real_1d_array x;
    lincgcreate(5, s);
    lincgsolvesparse(s, a, true, b);
    lincgresults(s, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [1.000,2.000,1.000,2.000,1.000]
    return 0;
}


/************************************************************************* *************************************************************************/
class linlsqrreport { ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; };
/************************************************************************* This object stores state of the LinLSQR method. You should use ALGLIB functions to work with this object. *************************************************************************/
class linlsqrstate { };
/************************************************************************* This function initializes linear LSQR Solver. This solver is used to solve non-symmetric (and, possibly, non-square) problems. Least squares solution is returned for non-compatible systems. USAGE: 1. User initializes algorithm state with LinLSQRCreate() call 2. User tunes solver parameters with LinLSQRSetCond() and other functions 3. User calls LinLSQRSolveSparse() function which takes algorithm state and SparseMatrix object. 4. User calls LinLSQRResults() to get solution 5. Optionally, user may call LinLSQRSolveSparse() again to solve another problem with different matrix and/or right part without reinitializing LinLSQRState structure. INPUT PARAMETERS: M - number of rows in A N - number of variables, N>0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrcreate(ae_int_t m, ae_int_t n, linlsqrstate& state);

Examples:   [1]  

/************************************************************************* LSQR solver: results. This function must be called after LinLSQRSolve INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[N], solution Rep - optimization report: * Rep.TerminationType completetion code: * 1 ||Rk||<=EpsB*||B|| * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA * 5 MaxIts steps was taken * 7 rounding errors prevent further progress, X contains best point found so far. (sometimes returned on singular systems) * Rep.IterationsCount contains iterations count * NMV countains number of matrix-vector calculations -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrresults( linlsqrstate state, real_1d_array& x, linlsqrreport& rep);

Examples:   [1]  

/************************************************************************* This function sets stopping criteria. INPUT PARAMETERS: EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| MaxIts - algorithm will be stopped if number of iterations more than MaxIts. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will be setted as default values. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsetcond( linlsqrstate state, double epsa, double epsb, ae_int_t maxits);
/************************************************************************* This function sets optional Tikhonov regularization coefficient. It is zero by default. INPUT PARAMETERS: LambdaI - regularization factor, LambdaI>=0 OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsetlambdai(linlsqrstate state, double lambdai);
/************************************************************************* This function changes preconditioning settings of LinCGSolveSparse() function. LinCGSolveSparse() will use diagonal of the system matrix as preconditioner. This preconditioning mode is active by default. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsetprecdiag(linlsqrstate state);
/************************************************************************* This function changes preconditioning settings of LinLSQQSolveSparse() function. By default, SolveSparse() uses diagonal preconditioner, but if you want to use solver without preconditioning, you can call this function which forces solver to use unit matrix for preconditioning. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 19.11.2012 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsetprecunit(linlsqrstate state);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsetxrep(linlsqrstate state, bool needxrep);
/************************************************************************* Procedure for solution of A*x=b with sparse A. INPUT PARAMETERS: State - algorithm state A - sparse M*N matrix in the CRS format (you MUST contvert it to CRS format by calling SparseConvertToCRS() function BEFORE you pass it to this function). B - right part, array[M] RESULT: This function returns no result. You can get solution by calling LinCGResults() NOTE: this function uses lightweight preconditioning - multiplication by inverse of diag(A). If you want, you can turn preconditioning off by calling LinLSQRSetPrecUnit(). However, preconditioning cost is low and preconditioner is very important for solution of badly scaled problems. -- ALGLIB -- Copyright 30.11.2011 by Bochkanov Sergey *************************************************************************/
void alglib::linlsqrsolvesparse( linlsqrstate state, sparsematrix a, real_1d_array b);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "solvers.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example illustrates solution of sparse linear least squares problem
    // with LSQR algorithm.
    // 
    // Suppose that we have least squares problem min|A*x-b| with sparse A
    // represented by sparsematrix object
    //         [ 1 1 ]
    //         [ 1 1 ]
    //     A = [ 2 1 ]
    //         [ 1   ]
    //         [   1 ]
    // and right part b
    //     [ 4 ]
    //     [ 2 ]
    // b = [ 4 ]
    //     [ 1 ]
    //     [ 2 ]
    // and we want to solve this system in the least squares sense using
    // LSQR algorithm. In order to do so, we have to create left part
    // (sparsematrix object) and right part (dense array).
    //
    // Initially, sparse matrix is created in the Hash-Table format,
    // which allows easy initialization, but do not allow matrix to be
    // used in the linear solvers. So after construction you should convert
    // sparse matrix to CRS format (one suited for linear operations).
    //
    sparsematrix a;
    sparsecreate(5, 2, a);
    sparseset(a, 0, 0, 1.0);
    sparseset(a, 0, 1, 1.0);
    sparseset(a, 1, 0, 1.0);
    sparseset(a, 1, 1, 1.0);
    sparseset(a, 2, 0, 2.0);
    sparseset(a, 2, 1, 1.0);
    sparseset(a, 3, 0, 1.0);
    sparseset(a, 4, 1, 1.0);

    //
    // Now our matrix is fully initialized, but we have to do one more
    // step - convert it from Hash-Table format to CRS format (see
    // documentation on sparse matrices for more information about these
    // formats).
    //
    // If you omit this call, ALGLIB will generate exception on the first
    // attempt to use A in linear operations. 
    //
    sparseconverttocrs(a);

    //
    // Initialization of the right part
    //
    real_1d_array b = "[4,2,4,1,2]";

    //
    // Now we have to create linear solver object and to use it for the
    // solution of the linear system.
    //
    linlsqrstate s;
    linlsqrreport rep;
    real_1d_array x;
    linlsqrcreate(5, 2, s);
    linlsqrsolvesparse(s, a, b);
    linlsqrresults(s, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [1.000,2.000]
    return 0;
}


linearmodel
lrreport
lravgerror
lravgrelerror
lrbuild
lrbuilds
lrbuildz
lrbuildzs
lrpack
lrprocess
lrrmserror
lrunpack
linreg_d_basic Linear regression used to build the very basic model and unpack coefficients
/************************************************************************* *************************************************************************/
class linearmodel { };
/************************************************************************* LRReport structure contains additional information about linear model: * C - covariation matrix, array[0..NVars,0..NVars]. C[i,j] = Cov(A[i],A[j]) * RMSError - root mean square error on a training set * AvgError - average error on a training set * AvgRelError - average relative error on a training set (excluding observations with zero function value). * CVRMSError - leave-one-out cross-validation estimate of generalization error. Calculated using fast algorithm with O(NVars*NPoints) complexity. * CVAvgError - cross-validation estimate of average error * CVAvgRelError - cross-validation estimate of average relative error All other fields of the structure are intended for internal use and should not be used outside ALGLIB. *************************************************************************/
class lrreport { real_2d_array c; double rmserror; double avgerror; double avgrelerror; double cvrmserror; double cvavgerror; double cvavgrelerror; ae_int_t ncvdefects; integer_1d_array cvdefects; };
/************************************************************************* Average error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::lravgerror( linearmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: average relative error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::lravgrelerror( linearmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Linear regression Subroutine builds model: Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) and model found in ALGLIB format, covariation matrix, training set errors (rms, average, average relative) and leave-one-out cross-validation estimate of the generalization error. CV estimate calculated using fast algorithm with O(NPoints*NVars) complexity. When covariation matrix is calculated standard deviations of function values are assumed to be equal to RMS error on the training set. INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints<NVars+2, NVars<1). * 1, if subroutine successfully finished LM - linear model in the ALGLIB format. Use subroutines of this unit to work with the model. AR - additional results -- ALGLIB -- Copyright 02.08.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrbuild( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t& info, linearmodel& lm, lrreport& ar);

Examples:   [1]  

/************************************************************************* Linear regression Variant of LRBuild which uses vector of standatd deviations (errors in function values). INPUT PARAMETERS: XY - training set, array [0..NPoints-1,0..NVars]: * NVars columns - independent variables * last column - dependent variable S - standard deviations (errors in function values) array[0..NPoints-1], S[i]>0. NPoints - training set size, NPoints>NVars+1 NVars - number of independent variables OUTPUT PARAMETERS: Info - return code: * -255, in case of unknown internal error * -4, if internal SVD subroutine haven't converged * -1, if incorrect parameters was passed (NPoints<NVars+2, NVars<1). * -2, if S[I]<=0 * 1, if subroutine successfully finished LM - linear model in the ALGLIB format. Use subroutines of this unit to work with the model. AR - additional results -- ALGLIB -- Copyright 02.08.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrbuilds( real_2d_array xy, real_1d_array s, ae_int_t npoints, ae_int_t nvars, ae_int_t& info, linearmodel& lm, lrreport& ar);
/************************************************************************* Like LRBuild but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrbuildz( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t& info, linearmodel& lm, lrreport& ar);
/************************************************************************* Like LRBuildS, but builds model Y = A(0)*X[0] + ... + A(N-1)*X[N-1] i.e. with zero constant term. -- ALGLIB -- Copyright 30.10.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrbuildzs( real_2d_array xy, real_1d_array s, ae_int_t npoints, ae_int_t nvars, ae_int_t& info, linearmodel& lm, lrreport& ar);
/************************************************************************* "Packs" coefficients and creates linear model in ALGLIB format (LRUnpack reversed). INPUT PARAMETERS: V - coefficients, array[0..NVars] NVars - number of independent variables OUTPUT PAREMETERS: LM - linear model. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrpack(real_1d_array v, ae_int_t nvars, linearmodel& lm);
/************************************************************************* Procesing INPUT PARAMETERS: LM - linear model X - input vector, array[0..NVars-1]. Result: value of linear model regression estimate -- ALGLIB -- Copyright 03.09.2008 by Bochkanov Sergey *************************************************************************/
double alglib::lrprocess(linearmodel lm, real_1d_array x);
/************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - linear model XY - test set NPoints - test set size RESULT: root mean square error. -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::lrrmserror( linearmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Unpacks coefficients of linear model. INPUT PARAMETERS: LM - linear model in ALGLIB format OUTPUT PARAMETERS: V - coefficients, array[0..NVars] constant term (intercept) is stored in the V[NVars]. NVars - number of independent variables (one less than number of coefficients) -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lrunpack(linearmodel lm, real_1d_array& v, ae_int_t& nvars);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we demonstrate linear fitting by f(x|a) = a*exp(0.5*x).
    //
    // We have:
    // * xy - matrix of basic function values (exp(0.5*x)) and expected values
    //
    real_2d_array xy = "[[0.606531,1.133719],[0.670320,1.306522],[0.740818,1.504604],[0.818731,1.554663],[0.904837,1.884638],[1.000000,2.072436],[1.105171,2.257285],[1.221403,2.534068],[1.349859,2.622017],[1.491825,2.897713],[1.648721,3.219371]]";
    ae_int_t info;
    ae_int_t nvars;
    linearmodel model;
    lrreport rep;
    real_1d_array c;

    lrbuildz(xy, 11, 1, info, model, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    lrunpack(model, c, nvars);
    printf("%s\n", c.tostring(4).c_str()); // EXPECTED: [1.98650,0.00000]
    return 0;
}


/************************************************************************* *************************************************************************/
class logitmodel { };
/************************************************************************* MNLReport structure contains information about training process: * NGrad - number of gradient calculations * NHess - number of Hessian calculations *************************************************************************/
class mnlreport { ae_int_t ngrad; ae_int_t nhess; };
/************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*ln(2)). -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mnlavgce( logitmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mnlavgerror( logitmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average relative error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: average relative error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mnlavgrelerror( logitmodel lm, real_2d_array xy, ae_int_t ssize);
/************************************************************************* Classification error on test set = MNLRelClsError*NPoints -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mnlclserror( logitmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* "Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack reversed). INPUT PARAMETERS: A - model (see MNLUnpack) NVars - number of independent variables NClasses - number of classes OUTPUT PARAMETERS: LM - logit model. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mnlpack( real_2d_array a, ae_int_t nvars, ae_int_t nclasses, logitmodel& lm);
/************************************************************************* Procesing INPUT PARAMETERS: LM - logit model, passed by non-constant reference (some fields of structure are used as temporaries when calculating model output). X - input vector, array[0..NVars-1]. Y - (possibly) preallocated buffer; if size of Y is less than NClasses, it will be reallocated.If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result, array[0..NClasses-1] Vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mnlprocess(logitmodel lm, real_1d_array x, real_1d_array& y);
/************************************************************************* 'interactive' variant of MNLProcess for languages like Python which support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mnlprocessi( logitmodel lm, real_1d_array x, real_1d_array& y);
/************************************************************************* Relative classification error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mnlrelclserror( logitmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set INPUT PARAMETERS: LM - logit model XY - test set NPoints - test set size RESULT: root mean square error (error when estimating posterior probabilities). -- ALGLIB -- Copyright 30.08.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mnlrmserror( logitmodel lm, real_2d_array xy, ae_int_t npoints);
/************************************************************************* This subroutine trains logit model. INPUT PARAMETERS: XY - training set, array[0..NPoints-1,0..NVars] First NVars columns store values of independent variables, next column stores number of class (from 0 to NClasses-1) which dataset element belongs to. Fractional values are rounded to nearest integer. NPoints - training set size, NPoints>=1 NVars - number of independent variables, NVars>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<NVars+2, NVars<1, NClasses<2). * 1, if task has been solved LM - model built Rep - training report -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mnltrainh( real_2d_array xy, ae_int_t npoints, ae_int_t nvars, ae_int_t nclasses, ae_int_t& info, logitmodel& lm, mnlreport& rep);
/************************************************************************* Unpacks coefficients of logit model. Logit model have form: P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when i<M-1 S(M-1) = 1 INPUT PARAMETERS: LM - logit model in ALGLIB format OUTPUT PARAMETERS: V - coefficients, array[0..NClasses-2,0..NVars] NVars - number of independent variables NClasses - number of classes -- ALGLIB -- Copyright 10.09.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mnlunpack( logitmodel lm, real_2d_array& a, ae_int_t& nvars, ae_int_t& nclasses);
barycentricfitreport
lsfitreport
lsfitstate
polynomialfitreport
spline1dfitreport
barycentricfitfloaterhormann
barycentricfitfloaterhormannwc
logisticcalc4
logisticcalc5
logisticfit4
logisticfit45x
logisticfit4ec
logisticfit5
logisticfit5ec
lsfitcreatef
lsfitcreatefg
lsfitcreatefgh
lsfitcreatewf
lsfitcreatewfg
lsfitcreatewfgh
lsfitfit
lsfitlinear
lsfitlinearc
lsfitlinearw
lsfitlinearwc
lsfitresults
lsfitsetbc
lsfitsetcond
lsfitsetgradientcheck
lsfitsetscale
lsfitsetstpmax
lsfitsetxrep
lstfitpiecewiselinearrdp
lstfitpiecewiselinearrdpfixed
polynomialfit
polynomialfitwc
spline1dfitcubic
spline1dfitcubicwc
spline1dfithermite
spline1dfithermitewc
spline1dfitpenalized
spline1dfitpenalizedw
lsfit_d_lin Unconstrained (general) linear least squares fitting with and without weights
lsfit_d_linc Constrained (general) linear least squares fitting with and without weights
lsfit_d_nlf Nonlinear fitting using function value only
lsfit_d_nlfb Bound contstrained nonlinear fitting using function value only
lsfit_d_nlfg Nonlinear fitting using gradient
lsfit_d_nlfgh Nonlinear fitting using gradient and Hessian
lsfit_d_nlscale Nonlinear fitting with custom scaling and bound constraints
lsfit_d_pol Unconstrained polynomial fitting
lsfit_d_polc Constrained polynomial fitting
lsfit_d_spline Unconstrained fitting by penalized regression spline
lsfit_t_4pl 4-parameter logistic fitting
lsfit_t_5pl 5-parameter logistic fitting
/************************************************************************* Barycentric fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error TaskRCond reciprocal of task's condition number *************************************************************************/
class barycentricfitreport { double taskrcond; ae_int_t dbest; double rmserror; double avgerror; double avgrelerror; double maxerror; };
/************************************************************************* Least squares fitting report. This structure contains informational fields which are set by fitting functions provided by this unit. Different functions initialize different sets of fields, so you should read documentation on specific function you used in order to know which fields are initialized. TaskRCond reciprocal of task's condition number IterationsCount number of internal iterations VarIdx if user-supplied gradient contains errors which were detected by nonlinear fitter, this field is set to index of the first component of gradient which is suspected to be spoiled by bugs. RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error WRMSError weighted RMS error CovPar covariance matrix for parameters, filled by some solvers ErrPar vector of errors in parameters, filled by some solvers ErrCurve vector of fit errors - variability of the best-fit curve, filled by some solvers. Noise vector of per-point noise estimates, filled by some solvers. R2 coefficient of determination (non-weighted, non-adjusted), filled by some solvers. *************************************************************************/
class lsfitreport { double taskrcond; ae_int_t iterationscount; ae_int_t varidx; double rmserror; double avgerror; double avgrelerror; double maxerror; double wrmserror; real_2d_array covpar; real_1d_array errpar; real_1d_array errcurve; real_1d_array noise; double r2; };
/************************************************************************* Nonlinear fitter. You should use ALGLIB functions to work with fitter. Never try to access its fields directly! *************************************************************************/
class lsfitstate { };
/************************************************************************* Polynomial fitting report: TaskRCond reciprocal of task's condition number RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error *************************************************************************/
class polynomialfitreport { double taskrcond; double rmserror; double avgerror; double avgrelerror; double maxerror; };
/************************************************************************* Spline fitting report: RMSError RMS error AvgError average error AvgRelError average relative error (for non-zero Y[I]) MaxError maximum error Fields below are filled by obsolete functions (Spline1DFitCubic, Spline1DFitHermite). Modern fitting functions do NOT fill these fields: TaskRCond reciprocal of task's condition number *************************************************************************/
class spline1dfitreport { double taskrcond; double rmserror; double avgerror; double avgrelerror; double maxerror; };
/************************************************************************* Rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9]. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0. M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricfitfloaterhormann( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, barycentricinterpolant& b, barycentricfitreport& rep); void alglib::smp_barycentricfitfloaterhormann( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, barycentricinterpolant& b, barycentricfitreport& rep);
/************************************************************************* Weghted rational least squares fitting using Floater-Hormann rational functions with optimal D chosen from [0,9], with constraints and individual weights. Equidistant grid with M node on [min(x),max(x)] is used to build basis functions. Different values of D are tried, optimal D (least WEIGHTED root mean square error) is chosen. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2) (mostly dominated by the least squares solver). SEE ALSO * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual weights and constraints. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. XC - points where function values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K<M. K=0 means no constraints (XC/YC/DC are not used in such cases) M - number of basis functions ( = number_of_nodes), M>=2. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -1 means another errors in parameters passed (N<=0, for example) B - barycentric interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * DBest best value of the D parameter * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroutine doesn't calculate task's condition number for K<>0. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained barycentric interpolants: * excessive constraints can be inconsistent. Floater-Hormann basis functions aren't as flexible as splines (although they are very smooth). * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function VALUES at the interval boundaries. Note that consustency of the constraints on the function DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines which are more flexible). * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricfitfloaterhormannwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, barycentricinterpolant& b, barycentricfitreport& rep); void alglib::smp_barycentricfitfloaterhormannwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, barycentricinterpolant& b, barycentricfitreport& rep);
/************************************************************************* This function calculates value of four-parameter logistic (4PL) model at specified point X. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D- parameters of 4PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/
double alglib::logisticcalc4( double x, double a, double b, double c, double d);

Examples:   [1]  

/************************************************************************* This function calculates value of five-parameter logistic (5PL) model at specified point X. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) INPUT PARAMETERS: X - current point, X>=0: * zero X is correctly handled even for B<=0 * negative X results in exception. A, B, C, D, G- parameters of 5PL model: * A is unconstrained * B is unconstrained; zero or negative values are handled correctly. * C>0, non-positive value results in exception * D is unconstrained * G>0, non-positive value results in exception RESULT: model value at X NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for zero X (strictly speaking, 0^0 is undefined). NOTE: this function also throws exception if all input parameters are correct, but overflow was detected during calculations. NOTE: this function performs a lot of checks; if you need really high performance, consider evaluating model yourself, without checking for degenerate cases. -- ALGLIB PROJECT -- Copyright 14.05.2014 by Bochkanov Sergey *************************************************************************/
double alglib::logisticcalc5( double x, double a, double b, double c, double d, double g);

Examples:   [1]  

/************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::logisticfit4( real_1d_array x, real_1d_array y, ae_int_t n, double& a, double& b, double& c, double& d, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* This is "expert" 4PL/5PL fitting function, which can be used if you need better control over fitting process than provided by LogisticFit4() or LogisticFit5(). This function fits model of the form F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) or F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) Here: * A, D - unconstrained * B>=0 for 4PL, unconstrained for 5PL * C>0 * G>0 (if present) INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. Is4PL - whether 4PL or 5PL models are fitted LambdaV - regularization coefficient, LambdaV>=0. Set it to zero unless you know what you are doing. EpsX - stopping condition (step size), EpsX>=0. Zero value means that small step is automatically chosen. See notes below for more information. RsCnt - number of repeated restarts from random points. 4PL/5PL models are prone to problem of bad local extrema. Utilizing multiple random restarts allows us to improve algorithm convergence. RsCnt>=0. Zero value means that function automatically choose small amount of restarts (recommended). OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model G - parameter of 5PL model; for Is4PL=True, G=1 is returned. Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. For 5PL model things are different. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::logisticfit45x( real_1d_array x, real_1d_array y, ae_int_t n, double cnstrleft, double cnstrright, bool is4pl, double lambdav, double epsx, ae_int_t rscnt, double& a, double& b, double& c, double& d, double& g, lsfitreport& rep);
/************************************************************************* This function fits four-parameter logistic (4PL) model to data provided by user, with optional constraints on parameters A and D. 4PL model has following form: F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) Here: * A, D - with optional equality constraints * B>=0 * C>0 IMPORTANT: output of this function is constrained in such way that B>0. Because 4PL model is symmetric with respect to B, there is no need to explore B<0. Constraining B makes algorithm easier to stabilize and debug. Users who for some reason prefer to work with negative B's should transform output themselves (swap A and D, replace B by -B). 4PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". * second Levenberg-Marquardt round is performed without excessive constraints. Results from the previous round are used as initial guess. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A, B, C, D- parameters of 4PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc4() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 4PL/5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. For 4PL, left constraint ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on D. That's because 4PL model is normalized in such way that B>=0. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::logisticfit4ec( real_1d_array x, real_1d_array y, ae_int_t n, double cnstrleft, double cnstrright, double& a, double& b, double& c, double& d, lsfitreport& rep);
/************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - unconstrained * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::logisticfit5( real_1d_array x, real_1d_array y, ae_int_t n, double& a, double& b, double& c, double& d, double& g, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* This function fits five-parameter logistic (5PL) model to data provided by user, subject to optional equality constraints on parameters A and D. 5PL model has following form: F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) Here: * A, D - with optional equality constraints * B - unconstrained * C>0 * G>0 IMPORTANT: unlike in 4PL fitting, output of this function is NOT constrained in such way that B is guaranteed to be positive. Furthermore, unlike 4PL, 5PL model is NOT symmetric with respect to B, so you can NOT transform model to equivalent one, with B having desired sign (>0 or <0). 5PL fitting is implemented as follows: * we perform small number of restarts from random locations which helps to solve problem of bad local extrema. Locations are only partially random - we use input data to determine good initial guess, but we include controlled amount of randomness. * we perform Levenberg-Marquardt fitting with very tight constraints on parameters B and C - it allows us to find good initial guess for the second stage without risk of running into "flat spot". Parameter G is fixed at G=1. * second Levenberg-Marquardt round is performed without excessive constraints on B and C, but with G still equal to 1. Results from the previous round are used as initial guess. * third Levenberg-Marquardt round relaxes constraints on G and tries two different models - one with B>0 and one with B<0. * after fitting is done, we compare results with best values found so far, rewrite "best solution" if needed, and move to next random location. Overall algorithm is very stable and is not prone to bad local extrema. Furthermore, it automatically scales when input data have very large or very small range. INPUT PARAMETERS: X - array[N], stores X-values. MUST include only non-negative numbers (but may include zero values). Can be unsorted. Y - array[N], values to fit. N - number of points. If N is less than length of X/Y, only leading N elements are used. CnstrLeft- optional equality constraint for model value at the left boundary (at X=0). Specify NAN (Not-a-Number) if you do not need constraint on the model value at X=0 (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. CnstrRight- optional equality constraint for model value at X=infinity. Specify NAN (Not-a-Number) if you do not need constraint on the model value (in C++ you can pass alglib::fp_nan as parameter, in C# it will be Double.NaN). See below, section "EQUALITY CONSTRAINTS" for more information about constraints. OUTPUT PARAMETERS: A,B,C,D,G- parameters of 5PL model Rep - fitting report. This structure has many fields, but ONLY ONES LISTED BELOW ARE SET: * Rep.IterationsCount - number of iterations performed * Rep.RMSError - root-mean-square error * Rep.AvgError - average absolute error * Rep.AvgRelError - average relative error (calculated for non-zero Y-values) * Rep.MaxError - maximum absolute error * Rep.R2 - coefficient of determination, R-squared. This coefficient is calculated as R2=1-RSS/TSS (in case of nonlinear regression there are multiple ways to define R2, each of them giving different results). NOTE: after you obtained coefficients, you can evaluate model with LogisticCalc5() function. NOTE: if you need better control over fitting process than provided by this function, you may use LogisticFit45X(). NOTE: step is automatically scaled according to scale of parameters being fitted before we compare its length with EpsX. Thus, this function can be used to fit data with very small or very large values without changing EpsX. EQUALITY CONSTRAINTS ON PARAMETERS 5PL solver supports equality constraints on model values at the left boundary (X=0) and right boundary (X=infinity). These constraints are completely optional and you can specify both of them, only one - or no constraints at all. Parameter CnstrLeft contains left constraint (or NAN for unconstrained fitting), and CnstrRight contains right one. Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign of B. Thus, negative B's are possible, and left constraint may constrain parameter A (for positive B's) - or parameter D (for negative B's). Similarly changes meaning of right constraint. You do not have to decide what parameter to constrain - algorithm will automatically determine correct parameters as fitting progresses. However, question highlighted above is important when you interpret fitting results. -- ALGLIB PROJECT -- Copyright 14.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::logisticfit5ec( real_1d_array x, real_1d_array y, ae_int_t n, double cnstrleft, double cnstrright, double& a, double& b, double& c, double& d, double& g, lsfitreport& rep);
/************************************************************************* Nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatef( real_2d_array x, real_1d_array y, real_1d_array c, double diffstep, lsfitstate& state); void alglib::lsfitcreatef( real_2d_array x, real_1d_array y, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* Nonlinear least squares fitting using gradient only, without individual weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatefg( real_2d_array x, real_1d_array y, real_1d_array c, bool cheapfg, lsfitstate& state); void alglib::lsfitcreatefg( real_2d_array x, real_1d_array y, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, bool cheapfg, lsfitstate& state);

Examples:   [1]  

/************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatefgh( real_2d_array x, real_1d_array y, real_1d_array c, lsfitstate& state); void alglib::lsfitcreatefgh( real_2d_array x, real_1d_array y, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate& state);

Examples:   [1]  

/************************************************************************* Weighted nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatewf( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, double diffstep, lsfitstate& state); void alglib::lsfitcreatewf( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, double diffstep, lsfitstate& state);

Examples:   [1]  [2]  

/************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatewfg( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, bool cheapfg, lsfitstate& state); void alglib::lsfitcreatewfg( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, bool cheapfg, lsfitstate& state);

Examples:   [1]  

/************************************************************************* Weighted nonlinear least squares fitting using gradient/Hessian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitcreatewfgh( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, lsfitstate& state); void alglib::lsfitcreatewfgh( real_2d_array x, real_1d_array y, real_1d_array w, real_1d_array c, ae_int_t n, ae_int_t m, ae_int_t k, lsfitstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear fitter These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x hess - callback which calculates function (or merit function) value func, gradient grad and Hessian hess at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL); void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL); void lsfitfit(lsfitstate &state, void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* Linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitlinear( real_1d_array y, real_2d_array fmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::lsfitlinear( real_1d_array y, real_2d_array fmatrix, ae_int_t n, ae_int_t m, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinear( real_1d_array y, real_2d_array fmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinear( real_1d_array y, real_2d_array fmatrix, ae_int_t n, ae_int_t m, ae_int_t& info, real_1d_array& c, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* Constained linear least squares fitting. This is variation of LSFitLinear(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitlinearc( real_1d_array y, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::lsfitlinearc( real_1d_array y, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearc( real_1d_array y, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearc( real_1d_array y, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t& info, real_1d_array& c, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* Weighted linear least squares fitting. QR decomposition is used to reduce task to MxM, then triangular solver or SVD-based solver is used depending on condition number of the system. It allows to maximize speed and retain decent accuracy. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I, J] - value of J-th basis function in I-th point. N - number of points used. N>=1. M - number of basis functions, M>=1. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -1 incorrect N/M were specified * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * Rep.TaskRCond reciprocal of condition number * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitlinearw( real_1d_array y, real_1d_array w, real_2d_array fmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::lsfitlinearw( real_1d_array y, real_1d_array w, real_2d_array fmatrix, ae_int_t n, ae_int_t m, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearw( real_1d_array y, real_1d_array w, real_2d_array fmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearw( real_1d_array y, real_1d_array w, real_2d_array fmatrix, ae_int_t n, ae_int_t m, ae_int_t& info, real_1d_array& c, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* Weighted constained linear least squares fitting. This is variation of LSFitLinearW(), which searchs for min|A*x=b| given that K additional constaints C*x=bc are satisfied. It reduces original task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() is called. IMPORTANT: if you want to perform polynomial fitting, it may be more convenient to use PolynomialFit() function. This function gives best results on polynomial problems and solves numerical stability issues which arise when you fit high-degree polynomials to your data. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: Y - array[0..N-1] Function values in N points. W - array[0..N-1] Weights corresponding to function values. Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. FMatrix[I,J] - value of J-th basis function in I-th point. CMatrix - a table of constaints, array[0..K-1,0..M]. I-th row of CMatrix corresponds to I-th linear constraint: CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] N - number of points used. N>=1. M - number of basis functions, M>=1. K - number of constraints, 0 <= K < M K=0 corresponds to absence of constraints. OUTPUT PARAMETERS: Info - error code: * -4 internal SVD decomposition subroutine failed (very rare and for degenerate systems only) * -3 either too many constraints (M or more), degenerate constraints (some constraints are repetead twice) or inconsistent constraints were specified. * 1 task is solved C - decomposition coefficients, array[0..M-1] Rep - fitting report. Following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(F*CovPar*F')), where F is functions matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 07.09.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitlinearwc( real_1d_array y, real_1d_array w, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::lsfitlinearwc( real_1d_array y, real_1d_array w, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearwc( real_1d_array y, real_1d_array w, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t& info, real_1d_array& c, lsfitreport& rep); void alglib::smp_lsfitlinearwc( real_1d_array y, real_1d_array w, real_2d_array fmatrix, real_2d_array cmatrix, ae_int_t n, ae_int_t m, ae_int_t k, ae_int_t& info, real_1d_array& c, lsfitreport& rep);

Examples:   [1]  

/************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. On success following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitresults( lsfitstate state, ae_int_t& info, real_1d_array& c, lsfitreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function sets boundary constraints for underlying optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[K]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[K]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: unlike other constrained optimization algorithms, this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetbc( lsfitstate state, real_1d_array bndl, real_1d_array bndu);
/************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by LSFitSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetcond( lsfitstate state, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before fitting begins * LSFitFit() is called * prior to actual fitting, for each point in data set X_i and each component of parameters being fited C_j algorithm performs following steps: * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], where C_j is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on C[] * F(X_i|C) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N*K (points count * parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with LSFitSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. NOTE 4: this function works only for optimizers created with LSFitCreateWFG() or LSFitCreateFG() constructors. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetgradientcheck(lsfitstate state, double teststep);
/************************************************************************* This function sets scaling coefficients for underlying optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetscale(lsfitstate state, real_1d_array s);

Examples:   [1]  

/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetstpmax(lsfitstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/
void alglib::lsfitsetxrep(lsfitstate state, bool needxrep);
/************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after achieving desired precision. IMPORTANT: * it performs non-least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y Eps - positive number, desired precision. OUTPUT PARAMETERS: X2 - X-values of corner points for piecewise approximation, has length NSections+1 or zero (for NSections=0). Y2 - Y-values of corner points, has length NSections+1 or zero (for NSections=0). NSections- number of sections found by algorithm, NSections can be zero for degenerate datasets (N<=1 or all X[] are non-distinct). NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is a first point of curve, (X2[NSection-1],Y2[NSection-1]) is the last point. -- ALGLIB -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::lstfitpiecewiselinearrdp( real_1d_array x, real_1d_array y, ae_int_t n, double eps, real_1d_array& x2, real_1d_array& y2, ae_int_t& nsections);
/************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm, which stops after generating specified number of linear sections. IMPORTANT: * it does NOT perform least-squares fitting; it builds curve, but this curve does not minimize some least squares metric. See description of RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. * this function does NOT work with parametric curves (i.e. curves which can be represented as {X(t),Y(t)}. It works with curves which can be represented as Y(X). Thus, it is impossible to model figures like circles with this functions. If you want to work with parametric curves, you should use ParametricRDPFixed() function provided by "Parametric" subpackage of "Interpolation" package. INPUT PARAMETERS: X - array of X-coordinates: * at least N elements * can be unordered (points are automatically sorted) * this function may accept non-distinct X (see below for more information on handling of such inputs) Y - array of Y-coordinates: * at least N elements N - number of elements in X/Y M - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N<M (or some X are non-distinct). OUTPUT PARAMETERS: X2 - X-values of corner points for piecewise approximation, has length NSections+1 or zero (for NSections=0). Y2 - Y-values of corner points, has length NSections+1 or zero (for NSections=0). NSections- number of sections found by algorithm, NSections<=M, NSections can be zero for degenerate datasets (N<=1 or all X[] are non-distinct). NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is a first point of curve, (X2[NSection-1],Y2[NSection-1]) is the last point. -- ALGLIB -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::lstfitpiecewiselinearrdpfixed( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, real_1d_array& x2, real_1d_array& y2, ae_int_t& nsections);
/************************************************************************* Fitting by polynomials in barycentric form. This function provides simple unterface for unconstrained unweighted fitting. See PolynomialFitWC() if you need constrained fitting. Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFitWC() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points, N>0 * if given, only leading N elements of X/Y are used * if not given, automatically determined from sizes of X/Y M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialfit( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::polynomialfit( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::smp_polynomialfit( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::smp_polynomialfit( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep);

Examples:   [1]  

/************************************************************************* Weighted fitting by polynomials in barycentric form, with constraints on function values or first derivatives. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO: PolynomialFit() COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points, N>0. * if given, only leading N elements of X/Y/W are used * if not given, automatically determined from sizes of X/Y/W XC - points where polynomial values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that P(XC[i])=YC[i] * DC[i]=1 means that P'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints, 0<=K<M. K=0 means no constraints (XC/YC/DC are not used in such cases) M - number of basis functions (= polynomial_degree + 1), M>=1 OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints P - interpolant in barycentric form. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTES: you can convert P from barycentric form to the power or Chebyshev basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from POLINT subpackage. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * even simple constraints can be inconsistent, see Wikipedia article on this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the one special cases, however, we can guarantee consistency. This case is: M>1 and constraints on the function values (NOT DERIVATIVES) Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 10.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialfitwc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::polynomialfitwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::smp_polynomialfitwc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep); void alglib::smp_polynomialfitwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, barycentricinterpolant& p, polynomialfitreport& rep);

Examples:   [1]  

/************************************************************************* Least squares fitting by cubic spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information about subroutine parameters (we don't duplicate it here because of length) COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfitcubic( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfitcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitcubic( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);
/************************************************************************* Weighted fitting by cubic spline, with constraints on function values or derivatives. Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with continuous second derivatives and non-fixed first derivatives at interval ends. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, less smooth) Spline1DFitCubic() - "lightweight" fitting by cubic splines, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K<M. * K=0 means no constraints (XC/YC/DC are not used) * if given, only first K elements of XC/YC/DC are used * if not given, automatically determined from XC/YC/DC M - number of basis functions ( = number_of_nodes+2), M>=4. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints S - spline interpolant. Rep - report, same format as in LSFitLinearWC() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints IS NOT GUARANTEED. * in the several special cases, however, we CAN guarantee consistency. * one of this cases is constraints on the function values AND/OR its derivatives at the interval boundaries. * another special case is ONE constraint on the function value (OR, but not AND, derivative) anywhere in the interval Our final recommendation is to use constraints WHEN AND ONLY WHEN you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfitcubicwc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfitcubicwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitcubicwc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitcubicwc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);
/************************************************************************* Least squares fitting by Hermite spline. This subroutine is "lightweight" alternative for more complex and feature- rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for more information about subroutine parameters (we don't duplicate it here because of length). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfithermite( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfithermite( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfithermite( real_1d_array x, real_1d_array y, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfithermite( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);
/************************************************************************* Weighted fitting by Hermite spline, with constraints on function values or first derivatives. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are Hermite splines. Small regularizing term is used when solving constrained tasks (to improve stability). Task is linear, so linear least squares solver is used. Complexity of this computational scheme is O(N*M^2), mostly dominated by least squares solver SEE ALSO Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, more smooth) Spline1DFitHermite() - "lightweight" Hermite fitting, without invididual weights and constraints COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted task. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes XC - points where spline values/derivatives are constrained, array[0..K-1]. YC - values of constraints, array[0..K-1] DC - array[0..K-1], types of constraints: * DC[i]=0 means that S(XC[i])=YC[i] * DC[i]=1 means that S'(XC[i])=YC[i] SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS K - number of constraints (optional): * 0<=K<M. * K=0 means no constraints (XC/YC/DC are not used) * if given, only first K elements of XC/YC/DC are used * if not given, automatically determined from XC/YC/DC M - number of basis functions (= 2 * number of nodes), M>=4, M IS EVEN! OUTPUT PARAMETERS: Info- same format as in LSFitLinearW() subroutine: * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD -3 means inconsistent constraints -2 means odd M was passed (which is not supported) -1 means another errors in parameters passed (N<=0, for example) S - spline interpolant. Rep - report, same format as in LSFitLinearW() subroutine. Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. IMPORTANT: this subroitine supports only even M's ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: Setting constraints can lead to undesired results, like ill-conditioned behavior, or inconsistency being detected. From the other side, it allows us to improve quality of the fit. Here we summarize our experience with constrained regression splines: * excessive constraints can be inconsistent. Splines are piecewise cubic functions, and it is easy to create an example, where large number of constraints concentrated in small area will result in inconsistency. Just because spline is not flexible enough to satisfy all of them. And same constraints spread across the [min(x),max(x)] will be perfectly consistent. * the more evenly constraints are spread across [min(x),max(x)], the more chances that they will be consistent * the greater is M (given fixed constraints), the more chances that constraints will be consistent * in the general case, consistency of constraints is NOT GUARANTEED. * in the several special cases, however, we can guarantee consistency. * one of this cases is M>=4 and constraints on the function value (AND/OR its derivative) at the interval boundaries. * another special case is M>=4 and ONE constraint on the function value (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] Our final recommendation is to use constraints WHEN AND ONLY when you can't solve your task without them. Anything beyond special cases given above is not guaranteed and may result in inconsistency. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfithermitewc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfithermitewc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfithermitewc( real_1d_array x, real_1d_array y, real_1d_array w, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfithermitewc( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, real_1d_array xc, real_1d_array yc, integer_1d_array dc, ae_int_t k, ae_int_t m, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);
/************************************************************************* Fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. N - number of points (optional): * N>0 * if given, only first N elements of X/Y are processed * if not given, automatically determined from X/Y sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when x<min(x,xc) or x>max(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 18.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfitpenalized( real_1d_array x, real_1d_array y, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfitpenalized( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitpenalized( real_1d_array x, real_1d_array y, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitpenalized( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);

Examples:   [1]  

/************************************************************************* Weighted fitting by penalized cubic spline. Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build basis functions. Basis functions are cubic splines with natural boundary conditions. Problem is regularized by adding non-linearity penalty to the usual least squares penalty function: S(x) = arg min { LS + P }, where LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty rho - tunable constant given by user C - automatically determined scale parameter, makes penalty invariant with respect to scaling of X, Y, W. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multithreading support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Speed-up provided by multithreading greatly depends on problem size ! - only large problems (number of coefficients is more than 500) can be ! efficiently multithreaded. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - points, array[0..N-1]. Y - function values, array[0..N-1]. W - weights, array[0..N-1] Each summand in square sum of approximation deviations from given values is multiplied by the square of corresponding weight. Fill it by 1's if you don't want to solve weighted problem. N - number of points (optional): * N>0 * if given, only first N elements of X/Y/W are processed * if not given, automatically determined from X/Y/W sizes M - number of basis functions ( = number_of_nodes), M>=4. Rho - regularization constant passed by user. It penalizes nonlinearity in the regression spline. It is logarithmically scaled, i.e. actual value of regularization constant is calculated as 10^Rho. It is automatically scaled so that: * Rho=2.0 corresponds to moderate amount of nonlinearity * generally, it should be somewhere in the [-8.0,+8.0] If you do not want to penalize nonlineary, pass small Rho. Values as low as -15 should work. OUTPUT PARAMETERS: Info- same format as in LSFitLinearWC() subroutine. * Info>0 task is solved * Info<=0 an error occured: -4 means inconvergence of internal SVD or Cholesky decomposition; problem may be too ill-conditioned (very rare) S - spline interpolant. Rep - Following fields are set: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED IMPORTANT: this subroitine doesn't calculate task's condition number for K<>0. NOTE 1: additional nodes are added to the spline outside of the fitting interval to force linearity when x<min(x,xc) or x>max(x,xc). It is done for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so it is natural to force linearity outside of this interval. NOTE 2: function automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 19.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dfitpenalizedw( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::spline1dfitpenalizedw( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitpenalizedw( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep); void alglib::smp_spline1dfitpenalizedw( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, ae_int_t m, double rho, ae_int_t& info, spline1dinterpolant& s, spline1dfitreport& rep);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we demonstrate linear fitting by f(x|a) = a*exp(0.5*x).
    //
    // We have:
    // * y - vector of experimental data
    // * fmatrix -  matrix of basis functions calculated at sample points
    //              Actually, we have only one basis function F0 = exp(0.5*x).
    //
    real_2d_array fmatrix = "[[0.606531],[0.670320],[0.740818],[0.818731],[0.904837],[1.000000],[1.105171],[1.221403],[1.349859],[1.491825],[1.648721]]";
    real_1d_array y = "[1.133719, 1.306522, 1.504604, 1.554663, 1.884638, 2.072436, 2.257285, 2.534068, 2.622017, 2.897713, 3.219371]";
    ae_int_t info;
    real_1d_array c;
    lsfitreport rep;

    //
    // Linear fitting without weights
    //
    lsfitlinear(y, fmatrix, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", c.tostring(4).c_str()); // EXPECTED: [1.98650]

    //
    // Linear fitting with individual weights.
    // Slightly different result is returned.
    //
    real_1d_array w = "[1.414213, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]";
    lsfitlinearw(y, w, fmatrix, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", c.tostring(4).c_str()); // EXPECTED: [1.983354]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we demonstrate linear fitting by f(x|a,b) = a*x+b
    // with simple constraint f(0)=0.
    //
    // We have:
    // * y - vector of experimental data
    // * fmatrix -  matrix of basis functions sampled at [0,1] with step 0.2:
    //                  [ 1.0   0.0 ]
    //                  [ 1.0   0.2 ]
    //                  [ 1.0   0.4 ]
    //                  [ 1.0   0.6 ]
    //                  [ 1.0   0.8 ]
    //                  [ 1.0   1.0 ]
    //              first column contains value of first basis function (constant term)
    //              second column contains second basis function (linear term)
    // * cmatrix -  matrix of linear constraints:
    //                  [ 1.0  0.0  0.0 ]
    //              first two columns contain coefficients before basis functions,
    //              last column contains desired value of their sum.
    //              So [1,0,0] means "1*constant_term + 0*linear_term = 0" 
    //
    real_1d_array y = "[0.072436,0.246944,0.491263,0.522300,0.714064,0.921929]";
    real_2d_array fmatrix = "[[1,0.0],[1,0.2],[1,0.4],[1,0.6],[1,0.8],[1,1.0]]";
    real_2d_array cmatrix = "[[1,0,0]]";
    ae_int_t info;
    real_1d_array c;
    lsfitreport rep;

    //
    // Constrained fitting without weights
    //
    lsfitlinearc(y, fmatrix, cmatrix, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [0,0.932933]

    //
    // Constrained fitting with individual weights
    //
    real_1d_array w = "[1, 1.414213, 1, 1, 1, 1]";
    lsfitlinearwc(y, w, fmatrix, cmatrix, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [0,0.938322]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;
void function_cx_1_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0))
    // where x is a position on X-axis and c is adjustable parameter
    func = exp(-c[0]*pow(x[0],2));
}

int main(int argc, char **argv)
{
    //
    // In this example we demonstrate exponential fitting
    // by f(x) = exp(-c*x^2)
    // using function value only.
    //
    // Gradient is estimated using combination of numerical differences
    // and secant updates. diffstep variable stores differentiation step 
    // (we have to tell algorithm what step to use).
    //
    real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]";
    real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]";
    real_1d_array c = "[0.3]";
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t info;
    lsfitstate state;
    lsfitreport rep;
    double diffstep = 0.0001;

    //
    // Fitting without weights
    //
    lsfitcreatef(x, y, c, diffstep, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]

    //
    // Fitting with weights
    // (you can change weights and see how it changes result)
    //
    real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]";
    lsfitcreatewf(x, y, w, c, diffstep, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;
void function_cx_1_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0))
    // where x is a position on X-axis and c is adjustable parameter
    func = exp(-c[0]*pow(x[0],2));
}

int main(int argc, char **argv)
{
    //
    // In this example we demonstrate exponential fitting by
    //     f(x) = exp(-c*x^2)
    // subject to bound constraints
    //     0.0 <= c <= 1.0
    // using function value only.
    //
    // Gradient is estimated using combination of numerical differences
    // and secant updates. diffstep variable stores differentiation step 
    // (we have to tell algorithm what step to use).
    //
    // Unconstrained solution is c=1.5, but because of constraints we should
    // get c=1.0 (at the boundary).
    //
    real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]";
    real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]";
    real_1d_array c = "[0.3]";
    real_1d_array bndl = "[0.0]";
    real_1d_array bndu = "[1.0]";
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t info;
    lsfitstate state;
    lsfitreport rep;
    double diffstep = 0.0001;

    lsfitcreatef(x, y, c, diffstep, state);
    lsfitsetbc(state, bndl, bndu);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func);
    lsfitresults(state, info, c, rep);
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.0]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;
void function_cx_1_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0))
    // where x is a position on X-axis and c is adjustable parameter
    func = exp(-c[0]*pow(x[0],2));
}
void function_cx_1_grad(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0)) and gradient G={df/dc[i]}
    // where x is a position on X-axis and c is adjustable parameter.
    // IMPORTANT: gradient is calculated with respect to C, not to X
    func = exp(-c[0]*pow(x[0],2));
    grad[0] = -pow(x[0],2)*func;
}

int main(int argc, char **argv)
{
    //
    // In this example we demonstrate exponential fitting
    // by f(x) = exp(-c*x^2)
    // using function value and gradient (with respect to c).
    //
    real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]";
    real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]";
    real_1d_array c = "[0.3]";
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t info;
    lsfitstate state;
    lsfitreport rep;

    //
    // Fitting without weights
    //
    lsfitcreatefg(x, y, c, true, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]

    //
    // Fitting with weights
    // (you can change weights and see how it changes result)
    //
    real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]";
    lsfitcreatewfg(x, y, w, c, true, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;
void function_cx_1_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0))
    // where x is a position on X-axis and c is adjustable parameter
    func = exp(-c[0]*pow(x[0],2));
}
void function_cx_1_grad(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0)) and gradient G={df/dc[i]}
    // where x is a position on X-axis and c is adjustable parameter.
    // IMPORTANT: gradient is calculated with respect to C, not to X
    func = exp(-c[0]*pow(x[0],2));
    grad[0] = -pow(x[0],2)*func;
}
void function_cx_1_hess(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr) 
{
    // this callback calculates f(c,x)=exp(-c0*sqr(x0)), gradient G={df/dc[i]} and Hessian H={d2f/(dc[i]*dc[j])}
    // where x is a position on X-axis and c is adjustable parameter.
    // IMPORTANT: gradient/Hessian are calculated with respect to C, not to X
    func = exp(-c[0]*pow(x[0],2));
    grad[0] = -pow(x[0],2)*func;
    hess[0][0] = pow(x[0],4)*func;
}

int main(int argc, char **argv)
{
    //
    // In this example we demonstrate exponential fitting
    // by f(x) = exp(-c*x^2)
    // using function value, gradient and Hessian (with respect to c)
    //
    real_2d_array x = "[[-1],[-0.8],[-0.6],[-0.4],[-0.2],[0],[0.2],[0.4],[0.6],[0.8],[1.0]]";
    real_1d_array y = "[0.223130, 0.382893, 0.582748, 0.786628, 0.941765, 1.000000, 0.941765, 0.786628, 0.582748, 0.382893, 0.223130]";
    real_1d_array c = "[0.3]";
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t info;
    lsfitstate state;
    lsfitreport rep;

    //
    // Fitting without weights
    //
    lsfitcreatefgh(x, y, c, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad, function_cx_1_hess);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]

    //
    // Fitting with weights
    // (you can change weights and see how it changes result)
    //
    real_1d_array w = "[1,1,1,1,1,1,1,1,1,1,1]";
    lsfitcreatewfgh(x, y, w, c, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    alglib::lsfitfit(state, function_cx_1_func, function_cx_1_grad, function_cx_1_hess);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(1).c_str()); // EXPECTED: [1.5]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;
void function_debt_func(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr) 
{
    //
    // this callback calculates f(c,x)=c[0]*(1+c[1]*(pow(x[0]-1999,c[2])-1))
    //
    func = c[0]*(1+c[1]*(pow(x[0]-1999,c[2])-1));
}

int main(int argc, char **argv)
{
    //
    // In this example we demonstrate fitting by
    //     f(x) = c[0]*(1+c[1]*((x-1999)^c[2]-1))
    // subject to bound constraints
    //     -INF  < c[0] < +INF
    //      -10 <= c[1] <= +10
    //      0.1 <= c[2] <= 2.0
    // Data we want to fit are time series of Japan national debt
    // collected from 2000 to 2008 measured in USD (dollars, not
    // millions of dollars).
    //
    // Our variables are:
    //     c[0] - debt value at initial moment (2000),
    //     c[1] - direction coefficient (growth or decrease),
    //     c[2] - curvature coefficient.
    // You may see that our variables are badly scaled - first one 
    // is order of 10^12, and next two are somewhere about 1 in 
    // magnitude. Such problem is difficult to solve without some
    // kind of scaling.
    // That is exactly where lsfitsetscale() function can be used.
    // We set scale of our variables to [1.0E12, 1, 1], which allows
    // us to easily solve this problem.
    //
    // You can try commenting out lsfitsetscale() call - and you will 
    // see that algorithm will fail to converge.
    //
    real_2d_array x = "[[2000],[2001],[2002],[2003],[2004],[2005],[2006],[2007],[2008]]";
    real_1d_array y = "[4323239600000.0, 4560913100000.0, 5564091500000.0, 6743189300000.0, 7284064600000.0, 7050129600000.0, 7092221500000.0, 8483907600000.0, 8625804400000.0]";
    real_1d_array c = "[1.0e+13, 1, 1]";
    double epsf = 0;
    double epsx = 1.0e-5;
    real_1d_array bndl = "[-inf, -10, 0.1]";
    real_1d_array bndu = "[+inf, +10, 2.0]";
    real_1d_array s = "[1.0e+12, 1, 1]";
    ae_int_t maxits = 0;
    ae_int_t info;
    lsfitstate state;
    lsfitreport rep;
    double diffstep = 1.0e-5;

    lsfitcreatef(x, y, c, diffstep, state);
    lsfitsetcond(state, epsf, epsx, maxits);
    lsfitsetbc(state, bndl, bndu);
    lsfitsetscale(state, s);
    alglib::lsfitfit(state, function_debt_func);
    lsfitresults(state, info, c, rep);
    printf("%d\n", int(info)); // EXPECTED: 2
    printf("%s\n", c.tostring(-2).c_str()); // EXPECTED: [4.142560E+12, 0.434240, 0.565376]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates polynomial fitting.
    //
    // Fitting is done by two (M=2) functions from polynomial basis:
    //     f0 = 1
    //     f1 = x
    // Basically, it just a linear fit; more complex polynomials may be used
    // (e.g. parabolas with M=3, cubic with M=4), but even such simple fit allows
    // us to demonstrate polynomialfit() function in action.
    //
    // We have:
    // * x      set of abscissas
    // * y      experimental data
    //
    // Additionally we demonstrate weighted fitting, where second point has
    // more weight than other ones.
    //
    real_1d_array x = "[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]";
    real_1d_array y = "[0.00,0.05,0.26,0.32,0.33,0.43,0.60,0.60,0.77,0.98,1.02]";
    ae_int_t m = 2;
    double t = 2;
    ae_int_t info;
    barycentricinterpolant p;
    polynomialfitreport rep;
    double v;

    //
    // Fitting without individual weights
    //
    // NOTE: result is returned as barycentricinterpolant structure.
    //       if you want to get representation in the power basis,
    //       you can use barycentricbar2pow() function to convert
    //       from barycentric to power representation (see docs for 
    //       POLINT subpackage for more info).
    //
    polynomialfit(x, y, m, info, p, rep);
    v = barycentriccalc(p, t);
    printf("%.2f\n", double(v)); // EXPECTED: 2.011

    //
    // Fitting with individual weights
    //
    // NOTE: slightly different result is returned
    //
    real_1d_array w = "[1,1.414213562,1,1,1,1,1,1,1,1,1]";
    real_1d_array xc = "[]";
    real_1d_array yc = "[]";
    integer_1d_array dc = "[]";
    polynomialfitwc(x, y, w, xc, yc, dc, m, info, p, rep);
    v = barycentriccalc(p, t);
    printf("%.2f\n", double(v)); // EXPECTED: 2.023
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates polynomial fitting.
    //
    // Fitting is done by two (M=2) functions from polynomial basis:
    //     f0 = 1
    //     f1 = x
    // with simple constraint on function value
    //     f(0) = 0
    // Basically, it just a linear fit; more complex polynomials may be used
    // (e.g. parabolas with M=3, cubic with M=4), but even such simple fit allows
    // us to demonstrate polynomialfit() function in action.
    //
    // We have:
    // * x      set of abscissas
    // * y      experimental data
    // * xc     points where constraints are placed
    // * yc     constraints on derivatives
    // * dc     derivative indices
    //          (0 means function itself, 1 means first derivative)
    //
    real_1d_array x = "[1.0,1.0]";
    real_1d_array y = "[0.9,1.1]";
    real_1d_array w = "[1,1]";
    real_1d_array xc = "[0]";
    real_1d_array yc = "[0]";
    integer_1d_array dc = "[0]";
    double t = 2;
    ae_int_t m = 2;
    ae_int_t info;
    barycentricinterpolant p;
    polynomialfitreport rep;
    double v;

    polynomialfitwc(x, y, w, xc, yc, dc, m, info, p, rep);
    v = barycentriccalc(p, t);
    printf("%.2f\n", double(v)); // EXPECTED: 2.000
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we demonstrate penalized spline fitting of noisy data
    //
    // We have:
    // * x - abscissas
    // * y - vector of experimental data, straight line with small noise
    //
    real_1d_array x = "[0.00,0.10,0.20,0.30,0.40,0.50,0.60,0.70,0.80,0.90]";
    real_1d_array y = "[0.10,0.00,0.30,0.40,0.30,0.40,0.62,0.68,0.75,0.95]";
    ae_int_t info;
    double v;
    spline1dinterpolant s;
    spline1dfitreport rep;
    double rho;

    //
    // Fit with VERY small amount of smoothing (rho = -5.0)
    // and large number of basis functions (M=50).
    //
    // With such small regularization penalized spline almost fully reproduces function values
    //
    rho = -5.0;
    spline1dfitpenalized(x, y, 50, rho, info, s, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    v = spline1dcalc(s, 0.0);
    printf("%.1f\n", double(v)); // EXPECTED: 0.10

    //
    // Fit with VERY large amount of smoothing (rho = 10.0)
    // and large number of basis functions (M=50).
    //
    // With such regularization our spline should become close to the straight line fit.
    // We will compare its value in x=1.0 with results obtained from such fit.
    //
    rho = +10.0;
    spline1dfitpenalized(x, y, 50, rho, info, s, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    v = spline1dcalc(s, 1.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.969

    //
    // In real life applications you may need some moderate degree of fitting,
    // so we try to fit once more with rho=3.0.
    //
    rho = +3.0;
    spline1dfitpenalized(x, y, 50, rho, info, s, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_1d_array x = "[1,2,3,4,5,6,7,8]";
    real_1d_array y = "[0.06313223,0.44552624,0.61838364,0.71385108,0.77345838,0.81383140,0.84280033,0.86449822]";
    ae_int_t n = 8;
    double a;
    double b;
    double c;
    double d;
    lsfitreport rep;

    //
    // Test logisticfit4() on carefully designed data with a priori known answer.
    //
    logisticfit4(x, y, n, a, b, c, d, rep);
    printf("%.1f\n", double(a)); // EXPECTED: -1.000
    printf("%.1f\n", double(b)); // EXPECTED: 1.200
    printf("%.1f\n", double(c)); // EXPECTED: 0.900
    printf("%.1f\n", double(d)); // EXPECTED: 1.000

    //
    // Evaluate model at point x=0.5
    //
    double v;
    v = logisticcalc4(0.5, a, b, c, d);
    printf("%.2f\n", double(v)); // EXPECTED: -0.33874308
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_1d_array x = "[1,2,3,4,5,6,7,8]";
    real_1d_array y = "[0.1949776139,0.5710060208,0.726002637,0.8060434158,0.8534547965,0.8842071579,0.9054773317,0.9209088299]";
    ae_int_t n = 8;
    double a;
    double b;
    double c;
    double d;
    double g;
    lsfitreport rep;

    //
    // Test logisticfit5() on carefully designed data with a priori known answer.
    //
    logisticfit5(x, y, n, a, b, c, d, g, rep);
    printf("%.1f\n", double(a)); // EXPECTED: -1.000
    printf("%.1f\n", double(b)); // EXPECTED: 1.200
    printf("%.1f\n", double(c)); // EXPECTED: 0.900
    printf("%.1f\n", double(d)); // EXPECTED: 1.000
    printf("%.1f\n", double(g)); // EXPECTED: 1.200

    //
    // Evaluate model at point x=0.5
    //
    double v;
    v = logisticcalc5(0.5, a, b, c, d, g);
    printf("%.2f\n", double(v)); // EXPECTED: -0.2354656824
    return 0;
}


mannwhitneyutest
/************************************************************************* Mann-Whitney U-test This test checks hypotheses about whether X and Y are samples of two continuous distributions of the same shape and same median or whether their medians are different. The following tests are performed: * two-tailed test (null hypothesis - the medians are equal) * left-tailed test (null hypothesis - the median of the first sample is greater than or equal to the median of the second sample) * right-tailed test (null hypothesis - the median of the first sample is less than or equal to the median of the second sample). Requirements: * the samples are independent * X and Y are continuous distributions (or discrete distributions well- approximating continuous distributions) * distributions of X and Y have the same shape. The only possible difference is their position (i.e. the value of the median) * the number of elements in each sample is not less than 5 * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distributions to be normal. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. N>=5 Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. M>=5 Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with satisfactory accuracy in interval [0.0001, 1]. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. Relative precision of approximation of p-value: N M Max.err. Rms.err. 5..10 N..10 1.4e-02 6.0e-04 5..10 N..100 2.2e-02 5.3e-06 10..15 N..15 1.0e-02 3.2e-04 10..15 N..100 1.0e-02 2.2e-05 15..100 N..100 6.1e-03 2.7e-06 For N,M>100 accuracy checks weren't put into practice, but taking into account characteristics of asymptotic approximation used, precision should not be sharply different from the values for interval [5, 100]. NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, P's outside of this interval are enforced to these bounds. Say, you may quite often get P equal to exactly 0.25 or 0.0001. -- ALGLIB -- Copyright 09.04.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mannwhitneyutest( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, double& bothtails, double& lefttail, double& righttail);
cmatrixdet
cmatrixludet
rmatrixdet
rmatrixludet
spdmatrixcholeskydet
spdmatrixdet
matdet_d_1 Determinant calculation, real matrix, short form
matdet_d_2 Determinant calculation, real matrix, full form
matdet_d_3 Determinant calculation, complex matrix, short form
matdet_d_4 Determinant calculation, complex matrix, full form
matdet_d_5 Determinant calculation, complex matrix with zero imaginary part, short form
/************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
alglib::complex alglib::cmatrixdet(complex_2d_array a); alglib::complex alglib::cmatrixdet(complex_2d_array a, ae_int_t n);

Examples:   [1]  [2]  [3]  

/************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
alglib::complex alglib::cmatrixludet( complex_2d_array a, integer_1d_array pivots); alglib::complex alglib::cmatrixludet( complex_2d_array a, integer_1d_array pivots, ae_int_t n);
/************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
double alglib::rmatrixdet(real_2d_array a); double alglib::rmatrixdet(real_2d_array a, ae_int_t n);

Examples:   [1]  [2]  

/************************************************************************* Determinant calculation of the matrix given by its LU decomposition. Input parameters: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations which were made during the LU decomposition. Output of RMatrixLU subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: matrix determinant. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
double alglib::rmatrixludet(real_2d_array a, integer_1d_array pivots); double alglib::rmatrixludet( real_2d_array a, integer_1d_array pivots, ae_int_t n);
/************************************************************************* Determinant calculation of the matrix given by the Cholesky decomposition. Input parameters: A - Cholesky decomposition, output of SMatrixCholesky subroutine. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) As the determinant is equal to the product of squares of diagonal elements, its not necessary to specify which triangle - lower or upper - the matrix is stored in. Result: matrix determinant. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/
double alglib::spdmatrixcholeskydet(real_2d_array a); double alglib::spdmatrixcholeskydet(real_2d_array a, ae_int_t n);
/************************************************************************* Determinant calculation of the symmetric positive definite matrix. Input parameters: A - matrix. Array with elements [0..N-1, 0..N-1]. N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Result: determinant of matrix A. If matrix A is not positive definite, exception is thrown. -- ALGLIB -- Copyright 2005-2008 by Bochkanov Sergey *************************************************************************/
double alglib::spdmatrixdet(real_2d_array a); double alglib::spdmatrixdet(real_2d_array a, ae_int_t n, bool isupper);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array b = "[[1,2],[2,1]]";
    double a;
    a = rmatrixdet(b);
    printf("%.3f\n", double(a)); // EXPECTED: -3
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array b = "[[5,4],[4,5]]";
    double a;
    a = rmatrixdet(b, 2);
    printf("%.3f\n", double(a)); // EXPECTED: 9
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    complex_2d_array b = "[[1+1i,2],[2,1-1i]]";
    alglib::complex a;
    a = cmatrixdet(b);
    printf("%s\n", a.tostring(3).c_str()); // EXPECTED: -2
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    alglib::complex a;
    complex_2d_array b = "[[5i,4],[4i,5]]";
    a = cmatrixdet(b, 2);
    printf("%s\n", a.tostring(3).c_str()); // EXPECTED: 9i
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    alglib::complex a;
    complex_2d_array b = "[[9,1],[2,1]]";
    a = cmatrixdet(b);
    printf("%s\n", a.tostring(3).c_str()); // EXPECTED: 7
    return 0;
}


/************************************************************************* Generation of random NxN complex matrix with given condition number C and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixrndcond(ae_int_t n, double c, complex_2d_array& a);
/************************************************************************* Generation of a random Haar distributed orthogonal complex matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixrndorthogonal(ae_int_t n, complex_2d_array& a);
/************************************************************************* Multiplication of MxN complex matrix by MxM random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixrndorthogonalfromtheleft( complex_2d_array& a, ae_int_t m, ae_int_t n);
/************************************************************************* Multiplication of MxN complex matrix by NxN random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixrndorthogonalfromtheright( complex_2d_array& a, ae_int_t m, ae_int_t n);
/************************************************************************* Generation of random NxN Hermitian matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::hmatrixrndcond(ae_int_t n, double c, complex_2d_array& a);
/************************************************************************* Hermitian multiplication of NxN matrix by random Haar distributed complex orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q^H*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::hmatrixrndmultiply(complex_2d_array& a, ae_int_t n);
/************************************************************************* Generation of random NxN Hermitian positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random HPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixrndcond(ae_int_t n, double c, complex_2d_array& a);
/************************************************************************* Generation of random NxN matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixrndcond(ae_int_t n, double c, real_2d_array& a);
/************************************************************************* Generation of a random uniformly distributed (Haar) orthogonal matrix INPUT PARAMETERS: N - matrix size, N>=1 OUTPUT PARAMETERS: A - orthogonal NxN matrix, array[0..N-1,0..N-1] NOTE: this function uses algorithm described in Stewart, G. W. (1980), "The Efficient Generation of Random Orthogonal Matrices with an Application to Condition Estimators". Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: * takes an NxN one * takes uniformly distributed unit vector of dimension N+1. * constructs a Householder reflection from the vector, then applies it to the smaller matrix (embedded in the larger size with a 1 at the bottom right corner). -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixrndorthogonal(ae_int_t n, real_2d_array& a);
/************************************************************************* Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - Q*A, where Q is random MxM orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixrndorthogonalfromtheleft( real_2d_array& a, ae_int_t m, ae_int_t n);
/************************************************************************* Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..M-1, 0..N-1] M, N- matrix size OUTPUT PARAMETERS: A - A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixrndorthogonalfromtheright( real_2d_array& a, ae_int_t m, ae_int_t n);
/************************************************************************* Generation of random NxN symmetric matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::smatrixrndcond(ae_int_t n, double c, real_2d_array& a);
/************************************************************************* Symmetric multiplication of NxN matrix by random Haar distributed orthogonal matrix INPUT PARAMETERS: A - matrix, array[0..N-1, 0..N-1] N - matrix size OUTPUT PARAMETERS: A - Q'*A*Q, where Q is random NxN orthogonal matrix -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::smatrixrndmultiply(real_2d_array& a, ae_int_t n);
/************************************************************************* Generation of random NxN symmetric positive definite matrix with given condition number and norm2(A)=1 INPUT PARAMETERS: N - matrix size C - condition number (in 2-norm) OUTPUT PARAMETERS: A - random SPD matrix with norm2(A)=1 and cond(A)=C -- ALGLIB routine -- 04.12.2009 Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixrndcond(ae_int_t n, double c, real_2d_array& a);
/************************************************************************* Matrix inverse report: * R1 reciprocal of condition number in 1-norm * RInf reciprocal of condition number in inf-norm *************************************************************************/
class matinvreport { double r1; double rinf; };
/************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::cmatrixinverse( complex_2d_array& a, ae_int_t n, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixinverse( complex_2d_array& a, ae_int_t n, ae_int_t& info, matinvreport& rep);

Examples:   [1]  

/************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of CMatrixLU subroutine). Pivots - table of permutations (the output of CMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixluinverse( complex_2d_array& a, integer_1d_array pivots, ae_int_t& info, matinvreport& rep); void alglib::cmatrixluinverse( complex_2d_array& a, integer_1d_array pivots, ae_int_t n, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixluinverse( complex_2d_array& a, integer_1d_array pivots, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixluinverse( complex_2d_array& a, integer_1d_array pivots, ae_int_t n, ae_int_t& info, matinvreport& rep);
/************************************************************************* Triangular matrix inverse (complex) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::cmatrixtrinverse( complex_2d_array& a, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::cmatrixtrinverse( complex_2d_array& a, ae_int_t n, bool isupper, bool isunit, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixtrinverse( complex_2d_array& a, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_cmatrixtrinverse( complex_2d_array& a, ae_int_t n, bool isupper, bool isunit, ae_int_t& info, matinvreport& rep);
/************************************************************************* Inversion of a Hermitian positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of HPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixcholeskyinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::hpdmatrixcholeskyinverse( complex_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_hpdmatrixcholeskyinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_hpdmatrixcholeskyinverse( complex_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep);
/************************************************************************* Inversion of a Hermitian positive definite matrix. Given an upper or lower triangle of a Hermitian positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::hpdmatrixinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::hpdmatrixinverse( complex_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_hpdmatrixinverse( complex_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_hpdmatrixinverse( complex_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep);

Examples:   [1]  

/************************************************************************* Inversion of a general matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse Result: True, if the matrix is not singular. False, if the matrix is singular. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::rmatrixinverse( real_2d_array& a, ae_int_t n, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixinverse( real_2d_array& a, ae_int_t n, ae_int_t& info, matinvreport& rep);

Examples:   [1]  

/************************************************************************* Inversion of a matrix given by its LU decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that matrix inversion is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - LU decomposition of the matrix (output of RMatrixLU subroutine). Pivots - table of permutations (the output of RMatrixLU subroutine). N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) OUTPUT PARAMETERS: Info - return code: * -3 A is singular, or VERY close to singular. it is filled by zeros in such cases. * 1 task is solved (but matrix A may be ill-conditioned, check R1/RInf parameters for condition numbers). Rep - solver report, see below for more info A - inverse of matrix A. Array whose indexes range within [0..N-1, 0..N-1]. SOLVER REPORT Subroutine sets following fields of the Rep structure: * R1 reciprocal of condition number: 1/cond(A), 1-norm. * RInf reciprocal of condition number: 1/cond(A), inf-norm. -- ALGLIB routine -- 05.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixluinverse( real_2d_array& a, integer_1d_array pivots, ae_int_t& info, matinvreport& rep); void alglib::rmatrixluinverse( real_2d_array& a, integer_1d_array pivots, ae_int_t n, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixluinverse( real_2d_array& a, integer_1d_array pivots, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixluinverse( real_2d_array& a, integer_1d_array pivots, ae_int_t n, ae_int_t& info, matinvreport& rep);
/************************************************************************* Triangular matrix inverse (real) The subroutine inverts the following types of matrices: * upper triangular * upper triangular with unit diagonal * lower triangular * lower triangular with unit diagonal In case of an upper (lower) triangular matrix, the inverse matrix will also be upper (lower) triangular, and after the end of the algorithm, the inverse matrix replaces the source matrix. The elements below (above) the main diagonal are not changed by the algorithm. If the matrix has a unit diagonal, the inverse matrix also has a unit diagonal, and the diagonal elements are not passed to the algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that triangular inverse is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix, array[0..N-1, 0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - True, if the matrix is upper triangular. IsUnit - diagonal type (optional): * if True, matrix has unit diagonal (a[i,i] are NOT used) * if False, matrix diagonal is arbitrary * if not given, False is assumed Output parameters: Info - same as for RMatrixLUInverse Rep - same as for RMatrixLUInverse A - same as for RMatrixLUInverse. -- ALGLIB -- Copyright 05.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::rmatrixtrinverse( real_2d_array& a, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::rmatrixtrinverse( real_2d_array& a, ae_int_t n, bool isupper, bool isunit, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixtrinverse( real_2d_array& a, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_rmatrixtrinverse( real_2d_array& a, ae_int_t n, bool isupper, bool isunit, ae_int_t& info, matinvreport& rep);
/************************************************************************* Inversion of a symmetric positive definite matrix which is given by Cholesky decomposition. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Cholesky decomposition of the matrix to be inverted: A=U*U or A = L*L'. Output of SPDMatrixCholesky subroutine. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, lower half is used. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixcholeskyinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::spdmatrixcholeskyinverse( real_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_spdmatrixcholeskyinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_spdmatrixcholeskyinverse( real_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep);
/************************************************************************* Inversion of a symmetric positive definite matrix. Given an upper or lower triangle of a symmetric positive definite matrix, the algorithm generates matrix A^-1 and saves the upper or lower triangle depending on the input. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. However, Cholesky inversion is a "difficult" ! algorithm - it has lots of internal synchronization points which ! prevents efficient parallelization of algorithm. Only very large ! problems (N=thousands) can be efficiently parallelized. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be inverted (upper or lower triangle). Array with elements [0..N-1,0..N-1]. N - size of matrix A (optional) : * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, size is automatically determined from matrix size (A must be square matrix) IsUpper - storage type (optional): * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used/changed by function * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used/changed by function * if not given, both lower and upper triangles must be filled. Output parameters: Info - return code, same as in RMatrixLUInverse Rep - solver report, same as in RMatrixLUInverse A - inverse of matrix A, same as in RMatrixLUInverse -- ALGLIB routine -- 10.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::spdmatrixinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::spdmatrixinverse( real_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep); void alglib::smp_spdmatrixinverse( real_2d_array& a, ae_int_t& info, matinvreport& rep); void alglib::smp_spdmatrixinverse( real_2d_array& a, ae_int_t n, bool isupper, ae_int_t& info, matinvreport& rep);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    complex_2d_array a = "[[1i,-1],[1i,1]]";
    ae_int_t info;
    matinvreport rep;
    cmatrixinverse(a, info, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", a.tostring(4).c_str()); // EXPECTED: [[-0.5i,-0.5i],[-0.5,0.5]]
    printf("%.4f\n", double(rep.r1)); // EXPECTED: 0.5
    printf("%.4f\n", double(rep.rinf)); // EXPECTED: 0.5
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    complex_2d_array a = "[[2,1],[1,2]]";
    ae_int_t info;
    matinvreport rep;
    hpdmatrixinverse(a, info, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", a.tostring(4).c_str()); // EXPECTED: [[0.666666,-0.333333],[-0.333333,0.666666]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array a = "[[1,-1],[1,1]]";
    ae_int_t info;
    matinvreport rep;
    rmatrixinverse(a, info, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", a.tostring(4).c_str()); // EXPECTED: [[0.5,0.5],[-0.5,0.5]]
    printf("%.4f\n", double(rep.r1)); // EXPECTED: 0.5
    printf("%.4f\n", double(rep.rinf)); // EXPECTED: 0.5
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array a = "[[2,1],[1,2]]";
    ae_int_t info;
    matinvreport rep;
    spdmatrixinverse(a, info, rep);
    printf("%d\n", int(info)); // EXPECTED: 1
    printf("%s\n", a.tostring(4).c_str()); // EXPECTED: [[0.666666,-0.333333],[-0.333333,0.666666]]
    return 0;
}


mcpdreport
mcpdstate
mcpdaddbc
mcpdaddec
mcpdaddtrack
mcpdcreate
mcpdcreateentry
mcpdcreateentryexit
mcpdcreateexit
mcpdresults
mcpdsetbc
mcpdsetec
mcpdsetlc
mcpdsetpredictionweights
mcpdsetprior
mcpdsettikhonovregularizer
mcpdsolve
mcpd_simple1 Simple unconstrained MCPD model (no entry/exit states)
mcpd_simple2 Simple MCPD model (no entry/exit states) with equality constraints
/************************************************************************* This structure is a MCPD training report: InnerIterationsCount - number of inner iterations of the underlying optimization algorithm OuterIterationsCount - number of outer iterations of the underlying optimization algorithm NFEV - number of merit function evaluations TerminationType - termination type (same as for MinBLEIC optimizer, positive values denote success, negative ones - failure) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
class mcpdreport { ae_int_t inneriterationscount; ae_int_t outeriterationscount; ae_int_t nfev; ae_int_t terminationtype; };
/************************************************************************* This structure is a MCPD (Markov Chains for Population Data) solver. You should use ALGLIB functions in order to work with this object. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
class mcpdstate { };
/************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD bound constraint for one element of P without changing constraints for other elements. You can also use MCPDSetBC() function which allows to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF<x<=0.5 or 0.1<=x<+INF). These functions (MCPDSetBC and MCPDAddBC) interact as follows: * there is internal matrix of bound constraints which is stored in the MCPD solver * MCPDSetBC() replaces this matrix by another one (SET) * MCPDAddBC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddBC() call preserves all modifications done by previous calls, while MCPDSetBC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver I - row index of element being constrained J - column index of element being constrained BndL - lower bound BndU - upper bound -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdaddbc( mcpdstate s, ae_int_t i, ae_int_t j, double bndl, double bndu);
/************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to ADD equality constraint for one element of P without changing constraints for other elements. You can also use MCPDSetEC() function which allows you to specify arbitrary set of equality constraints in one call. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver I - row index of element being constrained J - column index of element being constrained C - value (constraint for P[I,J]). Can be either NAN (no constraint) or finite value from [0,1]. NOTES: 1. infinite values of C will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdaddec(mcpdstate s, ae_int_t i, ae_int_t j, double c);

Examples:   [1]  

/************************************************************************* This function is used to add a track - sequence of system states at the different moments of its evolution. You may add one or several tracks to the MCPD solver. In case you have several tracks, they won't overwrite each other. For example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont try to model transition from t=A+3 to t=B+1. INPUT PARAMETERS: S - solver XY - track, array[K,N]: * I-th row is a state at t=I * elements of XY must be non-negative (exception will be thrown on negative elements) K - number of points in a track * if given, only leading K rows of XY are used * if not given, automatically determined from size of XY NOTES: 1. Track may contain either proportional or population data: * with proportional data all rows of XY must sum to 1.0, i.e. we have proportions instead of absolute population values * with population data rows of XY contain population counts and generally do not sum to 1.0 (although they still must be non-negative) -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdaddtrack(mcpdstate s, real_2d_array xy); void alglib::mcpdaddtrack(mcpdstate s, real_2d_array xy, ae_int_t k);

Examples:   [1]  [2]  

/************************************************************************* DESCRIPTION: This function creates MCPD (Markov Chains for Population Data) solver. This solver can be used to find transition matrix P for N-dimensional prediction problem where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional population vectors (components of each X are non-negative), and P is a N*N transition matrix (elements of P are non-negative, each column sums to 1.0). Such models arise when when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is constant, i.e. there is no new individuals and no one leaves population * you want to model transitions of individuals from one state into another USAGE: Here we give very brief outline of the MCPD. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on data analysis which is available at http://www.alglib.net/dataanalysis/ 1. User initializes algorithm state with MCPDCreate() call 2. User adds one or more tracks - sequences of states which describe evolution of a system being modelled from different starting conditions 3. User may add optional boundary, equality and/or linear constraints on the coefficients of P by calling one of the following functions: * MCPDSetEC() to set equality constraints * MCPDSetBC() to set bound constraints * MCPDSetLC() to set linear constraints 4. Optionally, user may set custom weights for prediction errors (by default, algorithm assigns non-equal, automatically chosen weights for errors in the prediction of different components of X). It can be done with a call of MCPDSetPredictionWeights() function. 5. User calls MCPDSolve() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 6. User calls MCPDResults() to get solution INPUT PARAMETERS: N - problem dimension, N>=1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdcreate(ae_int_t n, mcpdstate& s);

Examples:   [1]  [2]  

/************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state Such conditions basically mean that row of P which corresponds to "entry" state is zero. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn, but still no one leaves population * you want to model transitions of individuals from one state into another * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdcreateentry( ae_int_t n, ae_int_t entrystate, mcpdstate& s);
/************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Entry-Exit-states" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix one selected component of X[] is called "entry" state and is treated in a special way: system state always transits from "entry" state to some another state system state can not transit from any state into "entry" state and another one component of X[] is called "exit" state and is treated in a special way too: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that: row of P which corresponds to "entry" state is zero column of P which corresponds to "exit" state is zero Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant * at every moment of time there is some (unpredictable) amount of "new" individuals, which can transit into one of the states at the next turn * some individuals can move (predictably) into "exit" state and leave population at the next turn * you want to model transitions of individuals from one state into another, including transitions from the "entry" state and into the "exit" state. * but you do NOT want to predict amount of "new" individuals because it does not depends on individuals already present (hence system can not transit INTO entry state - it can only transit FROM it). This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 EntryState- index of entry state, in 0..N-1 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdcreateentryexit( ae_int_t n, ae_int_t entrystate, ae_int_t exitstate, mcpdstate& s);
/************************************************************************* DESCRIPTION: This function is a specialized version of MCPDCreate() function, and we recommend you to read comments for this function for general information about MCPD solver. This function creates MCPD (Markov Chains for Population Data) solver for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] is modelled as X[i+1] = P*X[i] where X[i] and X[i+1] are N-dimensional state vectors P is a N*N transition matrix and one selected component of X[] is called "exit" state and is treated in a special way: system state can transit from any state into "exit" state system state can not transit from "exit" state into any other state transition operator discards "exit" state (makes it zero at each turn) Such conditions basically mean that column of P which corresponds to "exit" state is zero. Multiplication by such P may decrease sum of vector components. Such models arise when: * there is some population of individuals * individuals can have different states * individuals can transit from one state to another * population size is NOT constant - individuals can move into "exit" state and leave population at the next turn, but there are no new individuals * amount of individuals which leave population can be predicted * you want to model transitions of individuals from one state into another (including transitions into the "exit" state) This model is discussed in more details in the ALGLIB User Guide (see http://www.alglib.net/dataanalysis/ for more data). INPUT PARAMETERS: N - problem dimension, N>=2 ExitState- index of exit state, in 0..N-1 OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdcreateexit(ae_int_t n, ae_int_t exitstate, mcpdstate& s);
/************************************************************************* MCPD results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: P - array[N,N], transition matrix Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one. Speaking short, positive values denote success, negative ones are failures. More information about fields of this structure can be found in the comments on MCPDReport datatype. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdresults(mcpdstate s, real_2d_array& p, mcpdreport& rep);

Examples:   [1]  [2]  

/************************************************************************* This function is used to add bound constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place bound constraints on arbitrary subset of elements of P. Set of constraints is specified by BndL/BndU matrices, which may contain arbitrary combination of finite numbers or infinities (like -INF<x<=0.5 or 0.1<=x<+INF). You can also use MCPDAddBC() function which allows to ADD bound constraint for one element of P without changing constraints for other elements. These functions (MCPDSetBC and MCPDAddBC) interact as follows: * there is internal matrix of bound constraints which is stored in the MCPD solver * MCPDSetBC() replaces this matrix by another one (SET) * MCPDAddBC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddBC() call preserves all modifications done by previous calls, while MCPDSetBC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver BndL - lower bounds constraints, array[N,N]. Elements of BndL can be finite numbers or -INF. BndU - upper bounds constraints, array[N,N]. Elements of BndU can be finite numbers or +INF. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsetbc( mcpdstate s, real_2d_array bndl, real_2d_array bndu);
/************************************************************************* This function is used to add equality constraints on the elements of the transition matrix P. MCPD solver has four types of constraints which can be placed on P: * user-specified equality constraints (optional) * user-specified bound constraints (optional) * user-specified general linear constraints (optional) * basic constraints (always present): * non-negativity: P[i,j]>=0 * consistency: every column of P sums to 1.0 Final constraints which are passed to the underlying optimizer are calculated as intersection of all present constraints. For example, you may specify boundary constraint on P[0,0] and equality one: 0.1<=P[0,0]<=0.9 P[0,0]=0.5 Such combination of constraints will be silently reduced to their intersection, which is P[0,0]=0.5. This function can be used to place equality constraints on arbitrary subset of elements of P. Set of constraints is specified by EC, which may contain either NAN's or finite numbers from [0,1]. NAN denotes absence of constraint, finite number denotes equality constraint on specific element of P. You can also use MCPDAddEC() function which allows to ADD equality constraint for one element of P without changing constraints for other elements. These functions (MCPDSetEC and MCPDAddEC) interact as follows: * there is internal matrix of equality constraints which is stored in the MCPD solver * MCPDSetEC() replaces this matrix by another one (SET) * MCPDAddEC() modifies one element of this matrix and leaves other ones unchanged (ADD) * thus MCPDAddEC() call preserves all modifications done by previous calls, while MCPDSetEC() completely discards all changes done to the equality constraints. INPUT PARAMETERS: S - solver EC - equality constraints, array[N,N]. Elements of EC can be either NAN's or finite numbers from [0,1]. NAN denotes absence of constraints, while finite value denotes equality constraint on the corresponding element of P. NOTES: 1. infinite values of EC will lead to exception being thrown. Values less than 0.0 or greater than 1.0 will lead to error code being returned after call to MCPDSolve(). -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsetec(mcpdstate s, real_2d_array ec);
/************************************************************************* This function is used to set linear equality/inequality constraints on the elements of the transition matrix P. This function can be used to set one or several general linear constraints on the elements of P. Two types of constraints are supported: * equality constraints * inequality constraints (both less-or-equal and greater-or-equal) Coefficients of constraints are specified by matrix C (one of the parameters). One row of C corresponds to one constraint. Because transition matrix P has N*N elements, we need N*N columns to store all coefficients (they are stored row by row), and one more column to store right part - hence C has N*N+1 columns. Constraint kind is stored in the CT array. Thus, I-th linear constraint is P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). Your constraint may involve only some subset of P (less than N*N elements). For example it can be something like P[0,0] + P[0,1] = 0.5 In this case you still should pass matrix with N*N+1 columns, but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. INPUT PARAMETERS: S - solver C - array[K,N*N+1] - coefficients of constraints (see above for complete description) CT - array[K] - constraint types (see above for complete description) K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsetlc(mcpdstate s, real_2d_array c, integer_1d_array ct); void alglib::mcpdsetlc( mcpdstate s, real_2d_array c, integer_1d_array ct, ae_int_t k);
/************************************************************************* This function is used to change prediction weights MCPD solver scales prediction errors as follows Error(P) = ||W*(y-P*x)||^2 where x is a system state at time t y is a system state at time t+1 P is a transition matrix W is a diagonal scaling matrix By default, weights are chosen in order to minimize relative prediction error instead of absolute one. For example, if one component of state is about 0.5 in magnitude and another one is about 0.05, then algorithm will make corresponding weights equal to 2.0 and 20.0. INPUT PARAMETERS: S - solver PW - array[N], weights: * must be non-negative values (exception will be thrown otherwise) * zero values will be replaced by automatically chosen values -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsetpredictionweights(mcpdstate s, real_1d_array pw);
/************************************************************************* This function allows to set prior values used for regularization of your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change prior values prior_P. You can also change r with MCPDSetTikhonovRegularizer() function. INPUT PARAMETERS: S - solver PP - array[N,N], matrix of prior values: 1. elements must be real numbers from [0,1] 2. columns must sum to 1.0. First property is checked (exception is thrown otherwise), while second one is not checked/enforced. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsetprior(mcpdstate s, real_2d_array pp);
/************************************************************************* This function allows to tune amount of Tikhonov regularization being applied to your problem. By default, regularizing term is equal to r*||P-prior_P||^2, where r is a small non-zero value, P is transition matrix, prior_P is identity matrix, ||X||^2 is a sum of squared elements of X. This function allows you to change coefficient r. You can also change prior values with MCPDSetPrior() function. INPUT PARAMETERS: S - solver V - regularization coefficient, finite non-negative value. It is not recommended to specify zero value unless you are pretty sure that you want it. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsettikhonovregularizer(mcpdstate s, double v);
/************************************************************************* This function is used to start solution of the MCPD problem. After return from this function, you can use MCPDResults() to get solution and completion code. -- ALGLIB -- Copyright 23.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mcpdsolve(mcpdstate s);

Examples:   [1]  [2]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // The very simple MCPD example
    //
    // We have a loan portfolio. Our loans can be in one of two states:
    // * normal loans ("good" ones)
    // * past due loans ("bad" ones)
    //
    // We assume that:
    // * loans can transition from any state to any other state. In 
    //   particular, past due loan can become "good" one at any moment 
    //   with same (fixed) probability. Not realistic, but it is toy example :)
    // * portfolio size does not change over time
    //
    // Thus, we have following model
    //     state_new = P*state_old
    // where
    //         ( p00  p01 )
    //     P = (          )
    //         ( p10  p11 )
    //
    // We want to model transitions between these two states using MCPD
    // approach (Markov Chains for Proportional/Population Data), i.e.
    // to restore hidden transition matrix P using actual portfolio data.
    // We have:
    // * poportional data, i.e. proportion of loans in the normal and past 
    //   due states (not portfolio size measured in some currency, although 
    //   it is possible to work with population data too)
    // * two tracks, i.e. two sequences which describe portfolio
    //   evolution from two different starting states: [1,0] (all loans 
    //   are "good") and [0.8,0.2] (only 80% of portfolio is in the "good"
    //   state)
    //
    mcpdstate s;
    mcpdreport rep;
    real_2d_array p;
    real_2d_array track0 = "[[1.00000,0.00000],[0.95000,0.05000],[0.92750,0.07250],[0.91738,0.08263],[0.91282,0.08718]]";
    real_2d_array track1 = "[[0.80000,0.20000],[0.86000,0.14000],[0.88700,0.11300],[0.89915,0.10085]]";

    mcpdcreate(2, s);
    mcpdaddtrack(s, track0);
    mcpdaddtrack(s, track1);
    mcpdsolve(s);
    mcpdresults(s, p, rep);

    //
    // Hidden matrix P is equal to
    //         ( 0.95  0.50 )
    //         (            )
    //         ( 0.05  0.50 )
    // which means that "good" loans can become "bad" with 5% probability, 
    // while "bad" loans will return to good state with 50% probability.
    //
    printf("%s\n", p.tostring(2).c_str()); // EXPECTED: [[0.95,0.50],[0.05,0.50]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Simple MCPD example
    //
    // We have a loan portfolio. Our loans can be in one of three states:
    // * normal loans
    // * past due loans
    // * charged off loans
    //
    // We assume that:
    // * normal loan can stay normal or become past due (but not charged off)
    // * past due loan can stay past due, become normal or charged off
    // * charged off loan will stay charged off for the rest of eternity
    // * portfolio size does not change over time
    // Not realistic, but it is toy example :)
    //
    // Thus, we have following model
    //     state_new = P*state_old
    // where
    //         ( p00  p01    )
    //     P = ( p10  p11    )
    //         (      p21  1 )
    // i.e. four elements of P are known a priori.
    //
    // Although it is possible (given enough data) to In order to enforce 
    // this property we set equality constraints on these elements.
    //
    // We want to model transitions between these two states using MCPD
    // approach (Markov Chains for Proportional/Population Data), i.e.
    // to restore hidden transition matrix P using actual portfolio data.
    // We have:
    // * poportional data, i.e. proportion of loans in the current and past 
    //   due states (not portfolio size measured in some currency, although 
    //   it is possible to work with population data too)
    // * two tracks, i.e. two sequences which describe portfolio
    //   evolution from two different starting states: [1,0,0] (all loans 
    //   are "good") and [0.8,0.2,0.0] (only 80% of portfolio is in the "good"
    //   state)
    //
    mcpdstate s;
    mcpdreport rep;
    real_2d_array p;
    real_2d_array track0 = "[[1.000000,0.000000,0.000000],[0.950000,0.050000,0.000000],[0.927500,0.060000,0.012500],[0.911125,0.061375,0.027500],[0.896256,0.060900,0.042844]]";
    real_2d_array track1 = "[[0.800000,0.200000,0.000000],[0.860000,0.090000,0.050000],[0.862000,0.065500,0.072500],[0.851650,0.059475,0.088875],[0.838805,0.057451,0.103744]]";

    mcpdcreate(3, s);
    mcpdaddtrack(s, track0);
    mcpdaddtrack(s, track1);
    mcpdaddec(s, 0, 2, 0.0);
    mcpdaddec(s, 1, 2, 0.0);
    mcpdaddec(s, 2, 2, 1.0);
    mcpdaddec(s, 2, 0, 0.0);
    mcpdsolve(s);
    mcpdresults(s, p, rep);

    //
    // Hidden matrix P is equal to
    //         ( 0.95 0.50      )
    //         ( 0.05 0.25      )
    //         (      0.25 1.00 ) 
    // which means that "good" loans can become past due with 5% probability, 
    // while past due loans will become charged off with 25% probability or
    // return back to normal state with 50% probability.
    //
    printf("%s\n", p.tostring(2).c_str()); // EXPECTED: [[0.95,0.50,0.00],[0.05,0.25,0.00],[0.00,0.25,1.00]]
    return 0;
}


minbleicreport
minbleicstate
minbleiccreate
minbleiccreatef
minbleicoptimize
minbleicrequesttermination
minbleicrestartfrom
minbleicresults
minbleicresultsbuf
minbleicsetbc
minbleicsetcond
minbleicsetgradientcheck
minbleicsetlc
minbleicsetprecdefault
minbleicsetprecdiag
minbleicsetprecscale
minbleicsetscale
minbleicsetstpmax
minbleicsetxrep
minbleic_d_1 Nonlinear optimization with bound constraints
minbleic_d_2 Nonlinear optimization with linear inequality constraints
minbleic_ftrim Nonlinear optimization by BLEIC, function with singularities
minbleic_numdiff Nonlinear optimization with bound constraints and numerical differentiation
/************************************************************************* This structure stores optimization report: * IterationsCount number of iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. ADDITIONAL FIELDS There are additional fields which can be used for debugging: * DebugEqErr error in the equality constraints (2-norm) * DebugFS f, calculated at projection of initial point to the feasible set * DebugFF f, calculated at the final point * DebugDX |X_start-X_final| *************************************************************************/
class minbleicreport { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; double debugeqerr; double debugfs; double debugff; double debugdx; ae_int_t debugfeasqpits; ae_int_t debugfeasgpaits; ae_int_t inneriterationscount; ae_int_t outeriterationscount; };
/************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinBLEIC subpackage to work with this object *************************************************************************/
class minbleicstate { };
/************************************************************************* BOUND CONSTRAINED OPTIMIZATION WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints REQUIREMENTS: * user must provide function value and gradient * starting point X0 must be feasible or not too far away from the feasible set * grad(f) must be Lipschitz continuous on a level set: L = { x : f(x)<=f(x0) } * function must be defined everywhere on the feasible set F USAGE: Constrained optimization if far more complex than the unconstrained one. Here we give very brief outline of the BLEIC optimizer. We strongly recommend you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinBLEICCreate() call 2. USer adds boundary and/or linear constraints by calling MinBLEICSetBC() and MinBLEICSetLC() functions. 3. User sets stopping conditions with MinBLEICSetCond(). 4. User calls MinBLEICOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 5. User calls MinBLEICResults() to get solution 6. Optionally user may call MinBLEICRestartFrom() to solve another problem with same N but another starting point. MinBLEICRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleiccreate(real_1d_array x, minbleicstate& state); void alglib::minbleiccreate( ae_int_t n, real_1d_array x, minbleicstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* The subroutine is finite difference variant of MinBLEICCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinBLEICCreate() in order to get more information about creation of BLEIC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinBLEICSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. CG needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minbleiccreatef( real_1d_array x, double diffstep, minbleicstate& state); void alglib::minbleiccreatef( ae_int_t n, real_1d_array x, double diffstep, minbleicstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() for numerical differentiation) you should choose appropriate variant of MinBLEICOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinBLEICOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinBLEICOptimize() and specific function used to create optimizer. | USER PASSED TO MinBLEICOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinBLEICCreateF() | work FAIL MinBLEICCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinBLEICOptimize() version. Attemps to use such combination (for example, to create optimizer with MinBLEICCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void minbleicoptimize(minbleicstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minbleicoptimize(minbleicstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicrequesttermination(minbleicstate state);
/************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicrestartfrom(minbleicstate state, real_1d_array x);
/************************************************************************* BLEIC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinBLEICSetGradientCheck() for more information. * -3 inconsistent constraints. Feasible point is either nonexistent or too hard to find. Try to restart optimizer with better initial approximation * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken * 8 terminated by user who called minbleicrequesttermination(). X contains point which was "current accepted" when termination request was submitted. More information about fields of this structure can be found in the comments on MinBLEICReport datatype. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicresults( minbleicstate state, real_1d_array& x, minbleicreport& rep);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* BLEIC results Buffered implementation of MinBLEICResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicresultsbuf( minbleicstate state, real_1d_array& x, minbleicreport& rep);
/************************************************************************* This function sets boundary constraints for BLEIC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetbc( minbleicstate state, real_1d_array bndl, real_1d_array bndu);

Examples:   [1]  [2]  

/************************************************************************* This function sets stopping conditions for the optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinBLEICSetScale() EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinBLEICSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform slightly more than MaxIts iterations. I.e., MaxIts sets non-strict limit on iterations count. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetcond( minbleicstate state, double epsg, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinBLEICOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinBLEICSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetgradientcheck( minbleicstate state, double teststep);
/************************************************************************* This function sets linear constraints for BLEIC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinBLEICRestartFrom(). INPUT PARAMETERS: State - structure previously allocated with MinBLEICCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about Epsilon in magnitude) due to rounding errors * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetlc( minbleicstate state, real_2d_array c, integer_1d_array ct); void alglib::minbleicsetlc( minbleicstate state, real_2d_array c, integer_1d_array ct, ae_int_t k);

Examples:   [1]  

/************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetprecdefault(minbleicstate state);
/************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE 1: D[i] should be positive. Exception will be thrown otherwise. NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetprecdiag(minbleicstate state, real_1d_array d);
/************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetprecscale(minbleicstate state);
/************************************************************************* This function sets scaling coefficients for BLEIC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the BLEIC too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinBLEICSetPrec...() functions. There is a special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetscale(minbleicstate state, real_1d_array s);
/************************************************************************* This function sets maximum step length IMPORTANT: this feature is hard to combine with preconditioning. You can't set upper limit on step length, when you solve optimization problem with linear (non-boundary) constraints AND preconditioner turned on. When non-boundary constraints are present, you have to either a) use preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! In this case algorithm will terminate with appropriate error code. INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetstpmax(minbleicstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinBLEICOptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetxrep(minbleicstate state, bool needxrep);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // subject to bound constraints -1<=x<=+1, -1<=y<=+1, using BLEIC optimizer.
    //
    real_1d_array x = "[0,0]";
    real_1d_array bndl = "[-1,-1]";
    real_1d_array bndu = "[+1,+1]";
    minbleicstate state;
    minbleicreport rep;

    //
    // These variables define stopping conditions for the optimizer.
    //
    // We use very simple condition - |g|<=epsg
    //
    double epsg = 0.000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;

    //
    // Now we are ready to actually optimize something:
    // * first we create optimizer
    // * we add boundary constraints
    // * we tune stopping conditions
    // * and, finally, optimize and obtain results...
    //
    minbleiccreate(x, state);
    minbleicsetbc(state, bndl, bndu);
    minbleicsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minbleicoptimize(state, function1_grad);
    minbleicresults(state, x, rep);

    //
    // ...and evaluate these results
    //
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-1,1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // subject to inequality constraints:
    // * x>=2 (posed as general linear constraint),
    // * x+y>=6
    // using BLEIC optimizer.
    //
    real_1d_array x = "[5,5]";
    real_2d_array c = "[[1,0,2],[1,1,6]]";
    integer_1d_array ct = "[1,1]";
    minbleicstate state;
    minbleicreport rep;

    //
    // These variables define stopping conditions for the optimizer.
    //
    // We use very simple condition - |g|<=epsg
    //
    double epsg = 0.000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;

    //
    // Now we are ready to actually optimize something:
    // * first we create optimizer
    // * we add linear constraints
    // * we tune stopping conditions
    // * and, finally, optimize and obtain results...
    //
    minbleiccreate(x, state);
    minbleicsetlc(state, c, ct);
    minbleicsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minbleicoptimize(state, function1_grad);
    minbleicresults(state, x, rep);

    //
    // ...and evaluate these results
    //
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [2,4]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void s1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr)
{
    //
    // this callback calculates f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x and its gradient.
    //
    // function is trimmed when we calculate it near the singular points or outside of the [-1,+1].
    // Note that we do NOT calculate gradient in this case.
    //
    if( (x[0]<=-0.999999999999) || (x[0]>=+0.999999999999) )
    {
        func = 1.0E+300;
        return;
    }
    func = pow(1+x[0],-0.2) + pow(1-x[0],-0.3) + 1000*x[0];
    grad[0] = -0.2*pow(1+x[0],-1.2) +0.3*pow(1-x[0],-1.3) + 1000;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x.
    //
    // This function is undefined outside of (-1,+1) and has singularities at x=-1 and x=+1.
    // Special technique called "function trimming" allows us to solve this optimization problem 
    // - without using boundary constraints!
    //
    // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information
    // on this subject.
    //
    real_1d_array x = "[0]";
    double epsg = 1.0e-6;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minbleicstate state;
    minbleicreport rep;

    minbleiccreate(x, state);
    minbleicsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minbleicoptimize(state, s1_grad);
    minbleicresults(state, x, rep);

    printf("%s\n", x.tostring(5).c_str()); // EXPECTED: [-0.99917305]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_func(const real_1d_array &x, double &func, void *ptr)
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // subject to bound constraints -1<=x<=+1, -1<=y<=+1, using BLEIC optimizer.
    //
    real_1d_array x = "[0,0]";
    real_1d_array bndl = "[-1,-1]";
    real_1d_array bndu = "[+1,+1]";
    minbleicstate state;
    minbleicreport rep;

    //
    // These variables define stopping conditions for the optimizer.
    //
    // We use very simple condition - |g|<=epsg
    //
    double epsg = 0.000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;

    //
    // This variable contains differentiation step
    //
    double diffstep = 1.0e-6;

    //
    // Now we are ready to actually optimize something:
    // * first we create optimizer
    // * we add boundary constraints
    // * we tune stopping conditions
    // * and, finally, optimize and obtain results...
    //
    minbleiccreatef(x, diffstep, state);
    minbleicsetbc(state, bndl, bndu);
    minbleicsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minbleicoptimize(state, function1_func);
    minbleicresults(state, x, rep);

    //
    // ...and evaluate these results
    //
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-1,1]
    return 0;
}


mincgreport
mincgstate
mincgcreate
mincgcreatef
mincgoptimize
mincgrequesttermination
mincgrestartfrom
mincgresults
mincgresultsbuf
mincgsetcgtype
mincgsetcond
mincgsetgradientcheck
mincgsetprecdefault
mincgsetprecdiag
mincgsetprecscale
mincgsetscale
mincgsetstpmax
mincgsetxrep
mincgsuggeststep
mincg_d_1 Nonlinear optimization by CG
mincg_d_2 Nonlinear optimization with additional settings and restarts
mincg_ftrim Nonlinear optimization by CG, function with singularities
mincg_numdiff Nonlinear optimization by CG with numerical differentiation
/************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinCGSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called mincgrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/
class mincgreport { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; };
/************************************************************************* This object stores state of the nonlinear CG optimizer. You should use ALGLIB functions to work with this object. *************************************************************************/
class mincgstate { };
/************************************************************************* NONLINEAR CONJUGATE GRADIENT METHOD DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using one of the nonlinear conjugate gradient methods. These CG methods are globally convergent (even on non-convex functions) as long as grad(f) is Lipschitz continuous in a some neighborhood of the L = { x : f(x)<=f(x0) }. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinCGCreate() call 2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and other functions 3. User calls MinCGOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinCGResults() to get solution 5. Optionally, user may call MinCGRestartFrom() to solve another problem with same N but another starting point and/or another function. MinCGRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgcreate(real_1d_array x, mincgstate& state); void alglib::mincgcreate(ae_int_t n, real_1d_array x, mincgstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* The subroutine is finite difference variant of MinCGCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinCGCreate() in order to get more information about creation of CG optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinCGSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. L-BFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mincgcreatef( real_1d_array x, double diffstep, mincgstate& state); void alglib::mincgcreatef( ae_int_t n, real_1d_array x, double diffstep, mincgstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinCGCreate() for analytical gradient or MinCGCreateF() for numerical differentiation) you should choose appropriate variant of MinCGOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinCGOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinCGOptimize() and specific function used to create optimizer. | USER PASSED TO MinCGOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinCGCreateF() | work FAIL MinCGCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinCGOptimize() version. Attemps to use such combination (for example, to create optimizer with MinCGCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/
void mincgoptimize(mincgstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void mincgoptimize(mincgstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::mincgrequesttermination(mincgstate state);
/************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgrestartfrom(mincgstate state, real_1d_array x);

Examples:   [1]  

/************************************************************************* Conjugate gradient results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinCGSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, we return best X found so far * 8 terminated by user * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mincgresults( mincgstate state, real_1d_array& x, mincgreport& rep);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* Conjugate gradient results Buffered implementation of MinCGResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.04.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mincgresultsbuf( mincgstate state, real_1d_array& x, mincgreport& rep);
/************************************************************************* This function sets CG algorithm. INPUT PARAMETERS: State - structure which stores algorithm state CGType - algorithm type: * -1 automatic selection of the best algorithm * 0 DY (Dai and Yuan) algorithm * 1 Hybrid DY-HS algorithm -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetcgtype(mincgstate state, ae_int_t cgtype);
/************************************************************************* This function sets stopping conditions for CG optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinCGSetScale() EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinCGSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetcond( mincgstate state, double epsg, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinCGOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinCGSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 31.05.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetgradientcheck(mincgstate state, double teststep);
/************************************************************************* Modification of the preconditioner: preconditioning is turned off. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetprecdefault(mincgstate state);
/************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetprecdiag(mincgstate state, real_1d_array d);
/************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinCGSetScale() call (before or after MinCGSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetprecscale(mincgstate state);
/************************************************************************* This function sets scaling coefficients for CG optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of CG optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the CG too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinCGSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetscale(mincgstate state, real_1d_array s);
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetstpmax(mincgstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinCGOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsetxrep(mincgstate state, bool needxrep);
/************************************************************************* This function allows to suggest initial step length to the CG algorithm. Suggested step length is used as starting point for the line search. It can be useful when you have badly scaled problem, i.e. when ||grad|| (which is used as initial estimate for the first step) is many orders of magnitude different from the desired step. Line search may fail on such problems without good estimate of initial step length. Imagine, for example, problem with ||grad||=10^50 and desired step equal to 0.1 Line search function will use 10^50 as initial step, then it will decrease step length by 2 (up to 20 attempts) and will get 10^44, which is still too large. This function allows us to tell than line search should be started from some moderate step length, like 1.0, so algorithm will be able to detect desired step length in a several searches. Default behavior (when no step is suggested) is to use preconditioner, if it is available, to generate initial estimate of step length. This function influences only first iteration of algorithm. It should be called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. Suggested step is ignored if you have preconditioner. INPUT PARAMETERS: State - structure used to store algorithm state. Stp - initial estimate of the step length. Can be zero (no estimate). -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mincgsuggeststep(mincgstate state, double stp);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // with nonlinear conjugate gradient method.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    mincgstate state;
    mincgreport rep;

    mincgcreate(x, state);
    mincgsetcond(state, epsg, epsf, epsx, maxits);
    alglib::mincgoptimize(state, function1_grad);
    mincgresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // with nonlinear conjugate gradient method.
    //
    // Several advanced techniques are demonstrated:
    // * upper limit on step size
    // * restart from new point
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    double stpmax = 0.1;
    ae_int_t maxits = 0;
    mincgstate state;
    mincgreport rep;

    // first run
    mincgcreate(x, state);
    mincgsetcond(state, epsg, epsf, epsx, maxits);
    mincgsetstpmax(state, stpmax);
    alglib::mincgoptimize(state, function1_grad);
    mincgresults(state, x, rep);

    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]

    // second run - algorithm is restarted with mincgrestartfrom()
    x = "[10,10]";
    mincgrestartfrom(state, x);
    alglib::mincgoptimize(state, function1_grad);
    mincgresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void s1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr)
{
    //
    // this callback calculates f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x and its gradient.
    //
    // function is trimmed when we calculate it near the singular points or outside of the [-1,+1].
    // Note that we do NOT calculate gradient in this case.
    //
    if( (x[0]<=-0.999999999999) || (x[0]>=+0.999999999999) )
    {
        func = 1.0E+300;
        return;
    }
    func = pow(1+x[0],-0.2) + pow(1-x[0],-0.3) + 1000*x[0];
    grad[0] = -0.2*pow(1+x[0],-1.2) +0.3*pow(1-x[0],-1.3) + 1000;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x.
    // This function has singularities at the boundary of the [-1,+1], but technique called
    // "function trimming" allows us to solve this optimization problem.
    //
    // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information
    // on this subject.
    //
    real_1d_array x = "[0]";
    double epsg = 1.0e-6;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    mincgstate state;
    mincgreport rep;

    mincgcreate(x, state);
    mincgsetcond(state, epsg, epsf, epsx, maxits);
    alglib::mincgoptimize(state, s1_grad);
    mincgresults(state, x, rep);

    printf("%s\n", x.tostring(5).c_str()); // EXPECTED: [-0.99917305]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_func(const real_1d_array &x, double &func, void *ptr)
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // using numerical differentiation to calculate gradient.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    double diffstep = 1.0e-6;
    ae_int_t maxits = 0;
    mincgstate state;
    mincgreport rep;

    mincgcreatef(x, diffstep, state);
    mincgsetcond(state, epsg, epsf, epsx, maxits);
    alglib::mincgoptimize(state, function1_func);
    mincgresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


/************************************************************************* *************************************************************************/
class minasareport { ae_int_t iterationscount; ae_int_t nfev; ae_int_t terminationtype; ae_int_t activeconstraints; };
/************************************************************************* *************************************************************************/
class minasastate { };
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 25.03.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasacreate( real_1d_array x, real_1d_array bndl, real_1d_array bndu, minasastate& state); void alglib::minasacreate( ae_int_t n, real_1d_array x, real_1d_array bndl, real_1d_array bndu, minasastate& state);
/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/
void minasaoptimize(minasastate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasarestartfrom( minasastate state, real_1d_array x, real_1d_array bndl, real_1d_array bndu);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minasaresults( minasastate state, real_1d_array& x, minasareport& rep);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minasaresultsbuf( minasastate state, real_1d_array& x, minasareport& rep);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasasetalgorithm(minasastate state, ae_int_t algotype);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasasetcond( minasastate state, double epsg, double epsf, double epsx, ae_int_t maxits);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasasetstpmax(minasastate state, double stpmax);
/************************************************************************* Obsolete optimization algorithm. Was replaced by MinBLEIC subpackage. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minasasetxrep(minasastate state, bool needxrep);
/************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetbarrierdecay(minbleicstate state, double mudecay);
/************************************************************************* This is obsolete function which was used by previous version of the BLEIC optimizer. It does nothing in the current version of BLEIC. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minbleicsetbarrierwidth(minbleicstate state, double mu);
/************************************************************************* Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetcholeskypreconditioner( minlbfgsstate state, real_2d_array p, bool isupper);
/************************************************************************* Obsolete function, use MinLBFGSSetPrecDefault() instead. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetdefaultpreconditioner(minlbfgsstate state);
minlbfgsreport
minlbfgsstate
minlbfgscreate
minlbfgscreatef
minlbfgsoptimize
minlbfgsrequesttermination
minlbfgsrestartfrom
minlbfgsresults
minlbfgsresultsbuf
minlbfgssetcond
minlbfgssetgradientcheck
minlbfgssetpreccholesky
minlbfgssetprecdefault
minlbfgssetprecdiag
minlbfgssetprecscale
minlbfgssetscale
minlbfgssetstpmax
minlbfgssetxrep
minlbfgs_d_1 Nonlinear optimization by L-BFGS
minlbfgs_d_2 Nonlinear optimization with additional settings and restarts
minlbfgs_ftrim Nonlinear optimization by LBFGS, function with singularities
minlbfgs_numdiff Nonlinear optimization by L-BFGS with numerical differentiation
/************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. Other fields of this structure are not documented and should not be used! *************************************************************************/
class minlbfgsreport { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t terminationtype; };
/************************************************************************* *************************************************************************/
class minlbfgsstate { };
/************************************************************************* LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION DESCRIPTION: The subroutine minimizes function F(x) of N arguments by using a quasi- Newton method (LBFGS scheme) which is optimized to use a minimum amount of memory. The subroutine generates the approximation of an inverse Hessian matrix by using information about the last M steps of the algorithm (instead of N). It lessens a required amount of memory from a value of order N^2 to a value of order 2*N*M. REQUIREMENTS: Algorithm will request following information during its operation: * function value F and its gradient G (simultaneously) at given point X USAGE: 1. User initializes algorithm state with MinLBFGSCreate() call 2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() and other functions 3. User calls MinLBFGSOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G. 4. User calls MinLBFGSResults() to get solution 5. Optionally user may call MinLBFGSRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLBFGSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension. N>0 M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - initial solution approximation, array[0..N-1]. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLBFGSSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLBFGSSetStpMax() function to bound algorithm's steps. However, L-BFGS rarely needs such a tuning. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgscreate( ae_int_t m, real_1d_array x, minlbfgsstate& state); void alglib::minlbfgscreate( ae_int_t n, ae_int_t m, real_1d_array x, minlbfgsstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* The subroutine is finite difference variant of MinLBFGSCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinLBFGSCreate() in order to get more information about creation of LBFGS optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of corrections in the BFGS scheme of Hessian approximation update. Recommended value: 3<=M<=7. The smaller value causes worse convergence, the bigger will not cause a considerably better convergence, but will cause a fall in the performance. M<=N. X - starting point, array[0..N-1]. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinLBFGSSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large truncation errors, while too small step will result in too large numerical errors. 1.0E-6 can be good value to start with. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. LBFGS needs exact gradient values. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 16.05.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgscreatef( ae_int_t m, real_1d_array x, double diffstep, minlbfgsstate& state); void alglib::minlbfgscreatef( ae_int_t n, ae_int_t m, real_1d_array x, double diffstep, minlbfgsstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied gradient, and one which uses function value only and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() for numerical differentiation) you should choose appropriate variant of MinLBFGSOptimize() - one which accepts function AND gradient or one which accepts function ONLY. Be careful to choose variant of MinLBFGSOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinLBFGSOptimize() and specific function used to create optimizer. | USER PASSED TO MinLBFGSOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinLBFGSCreateF() | work FAIL MinLBFGSCreate() | FAIL work Here "FAIL" denotes inappropriate combinations of optimizer creation function and MinLBFGSOptimize() version. Attemps to use such combination (for example, to create optimizer with MinLBFGSCreateF() and to pass gradient information to MinCGOptimize()) will lead to exception being thrown. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/
void minlbfgsoptimize(minlbfgsstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlbfgsoptimize(minlbfgsstate &state, void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgsrequesttermination(minlbfgsstate state);
/************************************************************************* This subroutine restarts LBFGS algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used to store algorithm state X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgsrestartfrom(minlbfgsstate state, real_1d_array x);

Examples:   [1]  

/************************************************************************* L-BFGS algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinLBFGSSetGradientCheck() for more information. * -2 rounding errors prevent further improvement. X contains best point found. * -1 incorrect parameters were specified * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlbfgsrequesttermination(). X contains point which was "current accepted" when termination request was submitted. * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgsresults( minlbfgsstate state, real_1d_array& x, minlbfgsreport& rep);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* L-BFGS algorithm results Buffered implementation of MinLBFGSResults which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgsresultsbuf( minlbfgsstate state, real_1d_array& x, minlbfgsreport& rep);
/************************************************************************* This function sets stopping conditions for L-BFGS optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinLBFGSSetScale() EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLBFGSSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetcond( minlbfgsstate state, double epsg, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLBFGSOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * if needed, steps are bounded with respect to constraints on X[] * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLBFGSSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 24.05.2012 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetgradientcheck( minlbfgsstate state, double teststep);
/************************************************************************* Modification of the preconditioner: Cholesky factorization of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state P - triangular preconditioner, Cholesky factorization of the approximate Hessian. array[0..N-1,0..N-1], (if larger, only leading N elements are used). IsUpper - whether upper or lower triangle of P is given (other triangle is not referenced) After call to this function preconditioner is changed to P (P is copied into the internal buffer). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: P should be nonsingular. Exception will be thrown otherwise. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetpreccholesky( minlbfgsstate state, real_2d_array p, bool isupper);
/************************************************************************* Modification of the preconditioner: default preconditioner (simple scaling, same for all elements of X) is used. INPUT PARAMETERS: State - structure which stores algorithm state NOTE: you can change preconditioner "on the fly", during algorithm iterations. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetprecdefault(minlbfgsstate state);
/************************************************************************* Modification of the preconditioner: diagonal of approximate Hessian is used. INPUT PARAMETERS: State - structure which stores algorithm state D - diagonal of the approximate Hessian, array[0..N-1], (if larger, only leading N elements are used). NOTE: you can change preconditioner "on the fly", during algorithm iterations. NOTE 2: D[i] should be positive. Exception will be thrown otherwise. NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetprecdiag(minlbfgsstate state, real_1d_array d);
/************************************************************************* Modification of the preconditioner: scale-based diagonal preconditioning. This preconditioning mode can be useful when you don't have approximate diagonal of Hessian, but you know that your variables are badly scaled (for example, one variable is in [1,10], and another in [1000,100000]), and most part of the ill-conditioning comes from different scales of vars. In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), can greatly improve convergence. IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() call). Without knowledge of the scale of your variables scale-based preconditioner will be just unit matrix. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 13.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetprecscale(minlbfgsstate state);
/************************************************************************* This function sets scaling coefficients for LBFGS optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. In most optimizers (and in the LBFGS too) scaling is NOT a form of preconditioning. It just affects stopping conditions. You should set preconditioner by separate call to one of the MinLBFGSSetPrec...() functions. There is special preconditioning mode, however, which uses scaling coefficients to form diagonal preconditioning matrix. You can turn this mode on, if you want. But you should understand that scaling is not the same thing as preconditioning - these are two different, although related forms of tuning solver. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetscale(minlbfgsstate state, real_1d_array s);
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetstpmax(minlbfgsstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLBFGSOptimize(). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlbfgssetxrep(minlbfgsstate state, bool needxrep);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // using LBFGS method.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlbfgsstate state;
    minlbfgsreport rep;

    minlbfgscreate(1, x, state);
    minlbfgssetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlbfgsoptimize(state, function1_grad);
    minlbfgsresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // using LBFGS method.
    //
    // Several advanced techniques are demonstrated:
    // * upper limit on step size
    // * restart from new point
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    double stpmax = 0.1;
    ae_int_t maxits = 0;
    minlbfgsstate state;
    minlbfgsreport rep;

    // first run
    minlbfgscreate(1, x, state);
    minlbfgssetcond(state, epsg, epsf, epsx, maxits);
    minlbfgssetstpmax(state, stpmax);
    alglib::minlbfgsoptimize(state, function1_grad);
    minlbfgsresults(state, x, rep);

    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]

    // second run - algorithm is restarted
    x = "[10,10]";
    minlbfgsrestartfrom(state, x);
    alglib::minlbfgsoptimize(state, function1_grad);
    minlbfgsresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void s1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr)
{
    //
    // this callback calculates f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x and its gradient.
    //
    // function is trimmed when we calculate it near the singular points or outside of the [-1,+1].
    // Note that we do NOT calculate gradient in this case.
    //
    if( (x[0]<=-0.999999999999) || (x[0]>=+0.999999999999) )
    {
        func = 1.0E+300;
        return;
    }
    func = pow(1+x[0],-0.2) + pow(1-x[0],-0.3) + 1000*x[0];
    grad[0] = -0.2*pow(1+x[0],-1.2) +0.3*pow(1-x[0],-1.3) + 1000;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x) = (1+x)^(-0.2) + (1-x)^(-0.3) + 1000*x.
    // This function has singularities at the boundary of the [-1,+1], but technique called
    // "function trimming" allows us to solve this optimization problem.
    //
    // See http://www.alglib.net/optimization/tipsandtricks.php#ftrimming for more information
    // on this subject.
    //
    real_1d_array x = "[0]";
    double epsg = 1.0e-6;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlbfgsstate state;
    minlbfgsreport rep;

    minlbfgscreate(1, x, state);
    minlbfgssetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlbfgsoptimize(state, s1_grad);
    minlbfgsresults(state, x, rep);

    printf("%s\n", x.tostring(5).c_str()); // EXPECTED: [-0.99917305]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_func(const real_1d_array &x, double &func, void *ptr)
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of f(x,y) = 100*(x+3)^4+(y-3)^4
    // using numerical differentiation to calculate gradient.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    double diffstep = 1.0e-6;
    ae_int_t maxits = 0;
    minlbfgsstate state;
    minlbfgsreport rep;

    minlbfgscreatef(1, x, diffstep, state);
    minlbfgssetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlbfgsoptimize(state, function1_func);
    minlbfgsresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,3]
    return 0;
}


minlmreport
minlmstate
minlmcreatefgh
minlmcreatefgj
minlmcreatefj
minlmcreatev
minlmcreatevgj
minlmcreatevj
minlmoptimize
minlmrequesttermination
minlmrestartfrom
minlmresults
minlmresultsbuf
minlmsetacctype
minlmsetbc
minlmsetcond
minlmsetgradientcheck
minlmsetscale
minlmsetstpmax
minlmsetxrep
minlm_d_fgh Nonlinear Hessian-based optimization for general functions
minlm_d_restarts Efficient restarts of LM optimizer
minlm_d_v Nonlinear least squares optimization using function vector only
minlm_d_vb Bound constrained nonlinear least squares optimization
minlm_d_vj Nonlinear least squares optimization using function vector and Jacobian
/************************************************************************* Optimization report, filled by MinLMResults() function FIELDS: * TerminationType, completetion code: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called MinLMRequestTermination(). X contains point which was "current accepted" when termination request was submitted. * IterationsCount, contains iterations count * NFunc, number of function calculations * NJac, number of Jacobi matrix calculations * NGrad, number of gradient calculations * NHess, number of Hessian calculations * NCholesky, number of Cholesky decomposition calculations *************************************************************************/
class minlmreport { ae_int_t iterationscount; ae_int_t terminationtype; ae_int_t funcidx; ae_int_t varidx; ae_int_t nfunc; ae_int_t njac; ae_int_t ngrad; ae_int_t nhess; ae_int_t ncholesky; };
/************************************************************************* Levenberg-Marquardt optimizer. This structure should be created using one of the MinLMCreate???() functions. You should not access its fields directly; use ALGLIB functions to work with it. *************************************************************************/
class minlmstate { };
/************************************************************************* LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION DESCRIPTION: This function is used to find minimum of general form (not "sum-of- -squares") function F = F(x[0], ..., x[n-1]) using its gradient and Hessian. Levenberg-Marquardt modification with L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step is used. REQUIREMENTS: This algorithm will request following information during its operation: * function value F at given point X * F and gradient G (simultaneously) at given point X * F, G and Hessian H (simultaneously) at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts func(), grad() and hess() function pointers. First pointer is used to calculate F at given point, second one calculates F(x) and grad F(x), third one calculates F(x), grad F(x), hess F(x). You can try to initialize MinLMState structure with FGH-function and then use incorrect version of MinLMOptimize() (for example, version which does not provide Hessian matrix), but it will lead to exception being thrown after first attempt to calculate Hessian. USAGE: 1. User initializes algorithm state with MinLMCreateFGH() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and pointers (delegates, etc.) to callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatefgh(real_1d_array x, minlmstate& state); void alglib::minlmcreatefgh( ae_int_t n, real_1d_array x, minlmstate& state);

Examples:   [1]  

/************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatefgj( ae_int_t m, real_1d_array x, minlmstate& state); void alglib::minlmcreatefgj( ae_int_t n, ae_int_t m, real_1d_array x, minlmstate& state);
/************************************************************************* This function is considered obsolete since ALGLIB 3.1.0 and is present for backward compatibility only. We recommend to use MinLMCreateVJ, which provides similar, but more consistent and feature-rich interface. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatefj( ae_int_t m, real_1d_array x, minlmstate& state); void alglib::minlmcreatefj( ae_int_t n, ae_int_t m, real_1d_array x, minlmstate& state);
/************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] only. Finite differences are used to calculate Jacobian. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() callback. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not accept function vector), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateV() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure which stores algorithm state See also MinLMIteration, MinLMResults. NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatev( ae_int_t m, real_1d_array x, double diffstep, minlmstate& state); void alglib::minlmcreatev( ae_int_t n, ae_int_t m, real_1d_array x, double diffstep, minlmstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* This is obsolete function. Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatevgj( ae_int_t m, real_1d_array x, minlmstate& state); void alglib::minlmcreatevgj( ae_int_t n, ae_int_t m, real_1d_array x, minlmstate& state);
/************************************************************************* IMPROVED LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR LEAST SQUARES OPTIMIZATION DESCRIPTION: This function is used to find minimum of function which is represented as sum of squares: F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) using value of function vector f[] and Jacobian of f[]. REQUIREMENTS: This algorithm will request following information during its operation: * function vector f[] at given point X * function vector f[] and Jacobian of f[] (simultaneously) at given point There are several overloaded versions of MinLMOptimize() function which correspond to different LM-like optimization algorithms provided by this unit. You should choose version which accepts fvec() and jac() callbacks. First one is used to calculate f[] at given point, second one calculates f[] and Jacobian df[i]/dx[j]. You can try to initialize MinLMState structure with VJ function and then use incorrect version of MinLMOptimize() (for example, version which works with general form function and does not provide Jacobian), but it will lead to exception being thrown after first attempt to calculate Jacobian. USAGE: 1. User initializes algorithm state with MinLMCreateVJ() call 2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and other functions 3. User calls MinLMOptimize() function which takes algorithm state and callback functions. 4. User calls MinLMResults() to get solution 5. Optionally, user may call MinLMRestartFrom() to solve another problem with same N/M but another starting point and/or another function. MinLMRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - dimension, N>1 * if given, only leading N elements of X are used * if not given, automatically determined from size of X M - number of functions f[i] X - initial solution, array[0..N-1] OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with MinLMSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use MinLMSetStpMax() function to bound algorithm's steps. -- ALGLIB -- Copyright 30.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmcreatevj( ae_int_t m, real_1d_array x, minlmstate& state); void alglib::minlmcreatevj( ae_int_t n, ae_int_t m, real_1d_array x, minlmstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x grad - callback which calculates function (or merit function) value func and gradient grad at given point x hess - callback which calculates function (or merit function) value func, gradient grad and Hessian hess at given point x fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. Depending on function used to create state structure, this algorithm may accept Jacobian and/or Hessian and/or gradient. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with MinLMCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minlmoptimize(minlmstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 08.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minlmrequesttermination(minlmstate state);
/************************************************************************* This subroutine restarts LM algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinLMCreateXXX call. X - new starting point. -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlmrestartfrom(minlmstate state, real_1d_array x);

Examples:   [1]  

/************************************************************************* Levenberg-Marquardt algorithm results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report; includes termination codes and additional information. Termination codes are listed below, see comments for this structure for more info. Termination code is stored in rep.terminationtype field: * -7 derivative correctness check failed; see rep.funcidx, rep.varidx for more information. * -3 constraints are inconsistent * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient is no more than EpsG. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * 8 terminated by user who called minlmrequesttermination(). X contains point which was "current accepted" when termination request was submitted. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmresults( minlmstate state, real_1d_array& x, minlmreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* Levenberg-Marquardt algorithm results Buffered implementation of MinLMResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::minlmresultsbuf( minlmstate state, real_1d_array& x, minlmreport& rep);
/************************************************************************* This function is used to change acceleration settings You can choose between three acceleration strategies: * AccType=0, no acceleration. * AccType=1, secant updates are used to update quadratic model after each iteration. After fixed number of iterations (or after model breakdown) we recalculate quadratic model using analytic Jacobian or finite differences. Number of secant-based iterations depends on optimization settings: about 3 iterations - when we have analytic Jacobian, up to 2*N iterations - when we use finite differences to calculate Jacobian. AccType=1 is recommended when Jacobian calculation cost is prohibitive high (several Mx1 function vector calculations followed by several NxN Cholesky factorizations are faster than calculation of one M*N Jacobian). It should also be used when we have no Jacobian, because finite difference approximation takes too much time to compute. Table below list optimization protocols (XYZ protocol corresponds to MinLMCreateXYZ) and acceleration types they support (and use by default). ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: protocol 0 1 comment V + + VJ + + FGH + DAFAULT VALUES: protocol 0 1 comment V x without acceleration it is so slooooooooow VJ x FGH x NOTE: this function should be called before optimization. Attempt to call it during algorithm iterations may result in unexpected behavior. NOTE: attempt to call this function with unsupported protocol/acceleration combination will result in exception being thrown. -- ALGLIB -- Copyright 14.10.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetacctype(minlmstate state, ae_int_t acctype);
/************************************************************************* This function sets boundary constraints for LM optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints or at its boundary -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetbc( minlmstate state, real_1d_array bndl, real_1d_array bndu);
/************************************************************************* This function sets stopping conditions for Levenberg-Marquardt optimization algorithm. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinLMSetScale() EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinLMSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (small EpsX). -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetcond( minlmstate state, double epsg, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinLMOptimize() is called * prior to actual optimization, for each function Fi and each component of parameters being optimized X[j] algorithm performs following steps: * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], where X[j] is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on X[] * Fi(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) Jacobian evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinLMSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetgradientcheck(minlmstate state, double teststep);
/************************************************************************* This function sets scaling coefficients for LM optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetscale(minlmstate state, real_1d_array s);
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetstpmax(minlmstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS iterations are reported. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minlmsetxrep(minlmstate state, bool needxrep);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void function1_func(const real_1d_array &x, double &func, void *ptr)
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
}
void function1_grad(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr) 
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // and its derivatives df/d0 and df/dx1
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
}
void function1_hess(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr)
{
    //
    // this callback calculates f(x0,x1) = 100*(x0+3)^4 + (x1-3)^4
    // its derivatives df/d0 and df/dx1
    // and its Hessian.
    //
    func = 100*pow(x[0]+3,4) + pow(x[1]-3,4);
    grad[0] = 400*pow(x[0]+3,3);
    grad[1] = 4*pow(x[1]-3,3);
    hess[0][0] = 1200*pow(x[0]+3,2);
    hess[0][1] = 0;
    hess[1][0] = 0;
    hess[1][1] = 12*pow(x[1]-3,2);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = 100*(x0+3)^4+(x1-3)^4
    // using "FGH" mode of the Levenberg-Marquardt optimizer.
    //
    // F is treated like a monolitic function without internal structure,
    // i.e. we do NOT represent it as a sum of squares.
    //
    // Optimization algorithm uses:
    // * function value F(x0,x1)
    // * gradient G={dF/dxi}
    // * Hessian H={d2F/(dxi*dxj)}
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlmstate state;
    minlmreport rep;

    minlmcreatefgh(x, state);
    minlmsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlmoptimize(state, function1_func, function1_grad, function1_hess);
    minlmresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,+3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  function1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = 100*(x0+3)^4,
    // f1(x0,x1) = (x1-3)^4
    //
    fi[0] = 10*pow(x[0]+3,2);
    fi[1] = pow(x[1]-3,2);
}
void  function2_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = x0^2+1
    // f1(x0,x1) = x1-1
    //
    fi[0] = x[0]*x[0]+1;
    fi[1] = x[1]-1;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where 
    //
    //     f0(x0,x1) = 10*(x0+3)^2
    //     f1(x0,x1) = (x1-3)^2
    //
    // using several starting points and efficient restarts.
    //
    real_1d_array x;
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlmstate state;
    minlmreport rep;

    //
    // create optimizer using minlmcreatev()
    //
    x = "[10,10]";
    minlmcreatev(2, x, 0.0001, state);
    minlmsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlmoptimize(state, function1_fvec);
    minlmresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,+3]

    //
    // restart optimizer using minlmrestartfrom()
    //
    // we can use different starting point, different function,
    // different stopping conditions, but problem size
    // must remain unchanged.
    //
    x = "[4,4]";
    minlmrestartfrom(state, x);
    alglib::minlmoptimize(state, function2_fvec);
    minlmresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [0,1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  function1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = 100*(x0+3)^4,
    // f1(x0,x1) = (x1-3)^4
    //
    fi[0] = 10*pow(x[0]+3,2);
    fi[1] = pow(x[1]-3,2);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where 
    //
    //     f0(x0,x1) = 10*(x0+3)^2
    //     f1(x0,x1) = (x1-3)^2
    //
    // using "V" mode of the Levenberg-Marquardt optimizer.
    //
    // Optimization algorithm uses:
    // * function vector f[] = {f1,f2}
    //
    // No other information (Jacobian, gradient, etc.) is needed.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlmstate state;
    minlmreport rep;

    minlmcreatev(2, x, 0.0001, state);
    minlmsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlmoptimize(state, function1_fvec);
    minlmresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,+3]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  function1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = 100*(x0+3)^4,
    // f1(x0,x1) = (x1-3)^4
    //
    fi[0] = 10*pow(x[0]+3,2);
    fi[1] = pow(x[1]-3,2);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where 
    //
    //     f0(x0,x1) = 10*(x0+3)^2
    //     f1(x0,x1) = (x1-3)^2
    //
    // with boundary constraints
    //
    //     -1 <= x0 <= +1
    //     -1 <= x1 <= +1
    //
    // using "V" mode of the Levenberg-Marquardt optimizer.
    //
    // Optimization algorithm uses:
    // * function vector f[] = {f1,f2}
    //
    // No other information (Jacobian, gradient, etc.) is needed.
    //
    real_1d_array x = "[0,0]";
    real_1d_array bndl = "[-1,-1]";
    real_1d_array bndu = "[+1,+1]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlmstate state;
    minlmreport rep;

    minlmcreatev(2, x, 0.0001, state);
    minlmsetbc(state, bndl, bndu);
    minlmsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlmoptimize(state, function1_fvec);
    minlmresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-1,+1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  function1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = 100*(x0+3)^4,
    // f1(x0,x1) = (x1-3)^4
    //
    fi[0] = 10*pow(x[0]+3,2);
    fi[1] = pow(x[1]-3,2);
}
void  function1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    // f0(x0,x1) = 100*(x0+3)^4,
    // f1(x0,x1) = (x1-3)^4
    // and Jacobian matrix J = [dfi/dxj]
    //
    fi[0] = 10*pow(x[0]+3,2);
    fi[1] = pow(x[1]-3,2);
    jac[0][0] = 20*(x[0]+3);
    jac[0][1] = 0;
    jac[1][0] = 0;
    jac[1][1] = 2*(x[1]-3);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = f0^2+f1^2, where 
    //
    //     f0(x0,x1) = 10*(x0+3)^2
    //     f1(x0,x1) = (x1-3)^2
    //
    // using "VJ" mode of the Levenberg-Marquardt optimizer.
    //
    // Optimization algorithm uses:
    // * function vector f[] = {f1,f2}
    // * Jacobian matrix J = {dfi/dxj}.
    //
    real_1d_array x = "[0,0]";
    double epsg = 0.0000000001;
    double epsf = 0;
    double epsx = 0;
    ae_int_t maxits = 0;
    minlmstate state;
    minlmreport rep;

    minlmcreatevj(2, x, state);
    minlmsetcond(state, epsg, epsf, epsx, maxits);
    alglib::minlmoptimize(state, function1_fvec, function1_jac);
    minlmresults(state, x, rep);

    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [-3,+3]
    return 0;
}


minnlcreport
minnlcstate
minnlccreate
minnlccreatef
minnlcoptimize
minnlcrestartfrom
minnlcresults
minnlcresultsbuf
minnlcsetalgoaul
minnlcsetbc
minnlcsetcond
minnlcsetgradientcheck
minnlcsetlc
minnlcsetnlc
minnlcsetprecexactlowrank
minnlcsetprecinexact
minnlcsetprecnone
minnlcsetscale
minnlcsetxrep
minnlc_d_equality Nonlinearly constrained optimization (equality constraints)
minnlc_d_inequality Nonlinearly constrained optimization (inequality constraints)
minnlc_d_mixed Nonlinearly constrained optimization with mixed equality/inequality constraints
/************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. 1 relative function improvement is no more than EpsF. 2 relative step is no more than EpsX. 4 gradient norm is no more than EpsG 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. Other fields of this structure are not documented and should not be used! *************************************************************************/
class minnlcreport { ae_int_t iterationscount; ae_int_t nfev; ae_int_t varidx; ae_int_t funcidx; ae_int_t terminationtype; ae_int_t dbgphase0its; };
/************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNLC subpackage to work with this object *************************************************************************/
class minnlcstate { };
/************************************************************************* NONLINEARLY CONSTRAINED OPTIMIZATION WITH PRECONDITIONED AUGMENTED LAGRANGIAN ALGORITHM DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 REQUIREMENTS: * user must provide function value and gradient for F(), H(), G() * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are twice continuously differentiable on the feasible set and its neighborhood * nonlinear constraints G() and H() must have non-zero gradient at G(x)=0 and at H(x)=0. Say, constraint like x^2>=1 is supported, but x^2>=0 is NOT supported. USAGE: Constrained optimization if far more complex than the unconstrained one. Nonlinearly constrained optimization is one of the most esoteric numerical procedures. Here we give very brief outline of the MinNLC optimizer. We strongly recommend you to study examples in the ALGLIB Reference Manual and to read ALGLIB User Guide on optimization, which is available at http://www.alglib.net/optimization/ 1. User initializes algorithm state with MinNLCCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AUL solver (activated with MinNLCSetAlgoAUL() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNLCSetBC() for boundary constraints b) MinNLCSetLC() for linear constraints c) MinNLCSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNLCSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNLCSetCond(). If NLC solver uses inner/outer iteration layout, this function sets stopping conditions for INNER iterations. 5. User chooses one of the preconditioning methods. Preconditioning is very important for efficient handling of boundary/linear/nonlinear constraints. Without preconditioning algorithm would require thousands of iterations even for simple problems. Two preconditioners can be used: * approximate LBFGS-based preconditioner which should be used for problems with almost orthogonal constraints (activated by calling MinNLCSetPrecInexact) * exact low-rank preconditiner (activated by MinNLCSetPrecExactLowRank) which should be used for problems with moderate number of constraints which do not have to be orthogonal. 6. Finally, user calls MinNLCOptimize() function which takes algorithm state and pointer (delegate, etc.) to callback function which calculates F/G/H. 7. User calls MinNLCResults() to get solution 8. Optionally user may call MinNLCRestartFrom() to solve another problem with same N but another starting point. MinNLCRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlccreate(real_1d_array x, minnlcstate& state); void alglib::minnlccreate( ae_int_t n, real_1d_array x, minnlcstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine is a finite difference variant of MinNLCCreate(). It uses finite differences in order to differentiate target function. Description below contains information which is specific to this function only. We recommend to read comments on MinNLCCreate() in order to get more information about creation of NLC optimizer. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size ofX X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, >0 OUTPUT PARAMETERS: State - structure stores algorithm state NOTES: 1. algorithm uses 4-point central formula for differentiation. 2. differentiation step along I-th axis is equal to DiffStep*S[I] where S[] is scaling vector which can be set by MinNLCSetScale() call. 3. we recommend you to use moderate values of differentiation step. Too large step will result in too large TRUNCATION errors, while too small step will result in too large NUMERICAL errors. 1.0E-4 can be good value to start from. 4. Numerical differentiation is very inefficient - one gradient calculation needs 4*N function evaluations. This function will work for any N - either small (1...10), moderate (10...100) or large (100...). However, performance penalty will be too severe for any N's except for small ones. We should also say that code which relies on numerical differentiation is less robust and precise. Imprecise gradient may slow down convergence, especially on highly nonlinear problems. Thus we recommend to use this function for fast prototyping on small- dimensional problems only, and to implement analytical gradient as soon as possible. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlccreatef( real_1d_array x, double diffstep, minnlcstate& state); void alglib::minnlccreatef( ae_int_t n, real_1d_array x, double diffstep, minnlcstate& state);
/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of MinNLCOptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of MinNLCOptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to MinNLCOptimize() and specific function used to create optimizer. | USER PASSED TO MinNLCOptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ MinNLCCreateF() | works FAILS MinNLCCreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and MinNLCOptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void minnlcoptimize(minnlcstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minnlcoptimize(minnlcstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. X - new starting point. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcrestartfrom(minnlcstate state, real_1d_array x);
/************************************************************************* MinNLC results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -7 gradient verification failed. See MinNLCSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken More information about fields of this structure can be found in the comments on MinNLCReport datatype. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcresults( minnlcstate state, real_1d_array& x, minnlcreport& rep);

Examples:   [1]  [2]  [3]  

/************************************************************************* NLC results Buffered implementation of MinNLCResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcresultsbuf( minnlcstate state, real_1d_array& x, minnlcreport& rep);
/************************************************************************* This function tells MinNLC unit to use Augmented Lagrangian algorithm for nonlinearly constrained optimization. This algorithm is a slight modification of one described in "A Modified Barrier-Augmented Lagrangian Method for Constrained Minimization (1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH. Augmented Lagrangian algorithm works by converting problem of minimizing F(x) subject to equality/inequality constraints to unconstrained problem of the form min[ f(x) + + Rho*PENALTY_EQ(x) + SHIFT_EQ(x,Nu1) + + Rho*PENALTY_INEQ(x) + SHIFT_INEQ(x,Nu2) ] where: * Rho is a fixed penalization coefficient * PENALTY_EQ(x) is a penalty term, which is used to APPROXIMATELY enforce equality constraints * SHIFT_EQ(x) is a special "shift" term which is used to "fine-tune" equality constraints, greatly increasing precision * PENALTY_INEQ(x) is a penalty term which is used to approximately enforce inequality constraints * SHIFT_INEQ(x) is a special "shift" term which is used to "fine-tune" inequality constraints, greatly increasing precision * Nu1/Nu2 are vectors of Lagrange coefficients which are fine-tuned during outer iterations of algorithm This version of AUL algorithm uses preconditioner, which greatly accelerates convergence. Because this algorithm is similar to penalty methods, it may perform steps into infeasible area. All kinds of constraints (boundary, linear and nonlinear ones) may be violated in intermediate points - and in the solution. However, properly configured AUL method is significantly better at handling constraints than barrier and/or penalty methods. The very basic outline of algorithm is given below: 1) first outer iteration is performed with "default" values of Lagrange multipliers Nu1/Nu2. Solution quality is low (candidate point can be too far away from true solution; large violation of constraints is possible) and is comparable with that of penalty methods. 2) subsequent outer iterations refine Lagrange multipliers and improve quality of the solution. INPUT PARAMETERS: State - structure which stores algorithm state Rho - penalty coefficient, Rho>0: * large enough that algorithm converges with desired precision. Minimum value is 10*max(S'*diag(H)*S), where S is a scale matrix (set by MinNLCSetScale) and H is a Hessian of the function being minimized. If you can not easily estimate Hessian norm, see our recommendations below. * not TOO large to prevent ill-conditioning * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * it is important to note that Rho is internally multiplied by scaling matrix, i.e. optimum value of Rho depends on scale of variables specified by MinNLCSetScale(). ItsCnt - number of outer iterations: * ItsCnt=0 means that small number of outer iterations is automatically chosen (10 iterations in current version). * ItsCnt=1 means that AUL algorithm performs just as usual barrier method. * ItsCnt>1 means that AUL algorithm performs specified number of outer iterations HOW TO CHOOSE PARAMETERS Nonlinear optimization is a tricky area and Augmented Lagrangian algorithm is sometimes hard to tune. Good values of Rho and ItsCnt are problem- specific. In order to help you we prepared following set of recommendations: * for unit-scale problems (variables and Hessian have unit magnitude), Rho=100 or Rho=1000 can be used. * start from some small value of Rho and solve problem with just one outer iteration (ItcCnt=1). In this case algorithm behaves like penalty method. Increase Rho in 2x or 10x steps until you see that one outer iteration returns point which is "rough approximation to solution". It is very important to have Rho so large that penalty term becomes constraining i.e. modified function becomes highly convex in constrained directions. From the other side, too large Rho may prevent you from converging to the solution. You can diagnose it by studying number of inner iterations performed by algorithm: too few (5-10 on 1000-dimensional problem) or too many (orders of magnitude more than dimensionality) usually means that Rho is too large. * with just one outer iteration you usually have low-quality solution. Some constraints can be violated with very large margin, while other ones (which are NOT violated in the true solution) can push final point too far in the inner area of the feasible set. For example, if you have constraint x0>=0 and true solution x0=1, then merely a presence of "x0>=0" will introduce a bias towards larger values of x0. Say, algorithm may stop at x0=1.5 instead of 1.0. * after you found good Rho, you may increase number of outer iterations. ItsCnt=10 is a good value. Subsequent outer iteration will refine values of Lagrange multipliers. Constraints which were violated will be enforced, inactive constraints will be dropped (corresponding multipliers will be decreased). Ideally, you should see 10-1000x improvement in constraint handling (constraint violation is reduced). * if you see that algorithm converges to vicinity of solution, but additional outer iterations do not refine solution, it may mean that algorithm is unstable - it wanders around true solution, but can not approach it. Sometimes algorithm may be stabilized by increasing Rho one more time, making it 5x or 10x larger. SCALING OF CONSTRAINTS [IMPORTANT] AUL optimizer scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, because function being optimized is a mix of original function and constraint-dependent penalty functions, it is important to rescale both variables AND constraints. Say, if you minimize f(x)=x^2 subject to 1000000*x>=0, then you have constraint whose scale is different from that of target function (another example is 0.000001*x>=0). It is also possible to have constraints whose scales are misaligned: 1000000*x0>=0, 0.000001*x1<=0. Inappropriate scaling may ruin convergence because minimizing x^2 subject to x>=0 is NOT same as minimizing it subject to 1000000*x>=0. Because we know coefficients of boundary/linear constraints, we can automatically rescale and normalize them. However, there is no way to automatically rescale nonlinear constraints Gi(x) and Hi(x) - they are black boxes. It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to rescale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). WHAT IF IT DOES NOT CONVERGE? It is possible that AUL algorithm fails to converge to precise values of Lagrange multipliers. It stops somewhere around true solution, but candidate point is still too far from solution, and some constraints are violated. Such kind of failure is specific for Lagrangian algorithms - technically, they stop at some point, but this point is not constrained solution. There are exist several reasons why algorithm may fail to converge: a) too loose stopping criteria for inner iteration b) degenerate, redundant constraints c) target function has unconstrained extremum exactly at the boundary of some constraint d) numerical noise in the target function In all these cases algorithm is unstable - each outer iteration results in large and almost random step which improves handling of some constraints, but violates other ones (ideally outer iterations should form a sequence of progressively decreasing steps towards solution). First reason possible is that too loose stopping criteria for inner iteration were specified. Augmented Lagrangian algorithm solves a sequence of intermediate problems, and requries each of them to be solved with high precision. Insufficient precision results in incorrect update of Lagrange multipliers. Another reason is that you may have specified degenerate constraints: say, some constraint was repeated twice. In most cases AUL algorithm gracefully handles such situations, but sometimes it may spend too much time figuring out subtle degeneracies in constraint matrix. Third reason is tricky and hard to diagnose. Consider situation when you minimize f=x^2 subject to constraint x>=0. Unconstrained extremum is located exactly at the boundary of constrained area. In this case algorithm will tend to oscillate between negative and positive x. Each time it stops at x<0 it "reinforces" constraint x>=0, and each time it is bounced to x>0 it "relaxes" constraint (and is attracted to x<0). Such situation sometimes happens in problems with hidden symetries. Algorithm is got caught in a loop with Lagrange multipliers being continuously increased/decreased. Luckily, such loop forms after at least three iterations, so this problem can be solved by DECREASING number of outer iterations down to 1-2 and increasing penalty coefficient Rho as much as possible. Final reason is numerical noise. AUL algorithm is robust against moderate noise (more robust than, say, active set methods), but large noise may destabilize algorithm. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetalgoaul( minnlcstate state, double rho, ae_int_t itscnt);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function sets boundary constraints for NLC optimizer. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine boundary constraints with general linear ones - and with nonlinear ones! Boundary constraints are handled more efficiently than other types. Thus, if your problem has mixed constraints, you may explicitly specify some of them as boundary and save some time/space. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: when you solve your problem with augmented Lagrangian solver, boundary constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetbc( minnlcstate state, real_1d_array bndl, real_1d_array bndu);
/************************************************************************* This function sets stopping conditions for inner iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinNLCSetScale() EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinNLCSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetcond( minnlcstate state, double epsg, double epsf, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  

/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before optimization begins * MinNLCOptimize() is called * prior to actual optimization, for each component of parameters being optimized X[i] algorithm performs following steps: * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], where X[i] is i-th component of the initial point and S[i] is a scale of i-th parameter * F(X) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative, and Rep.FuncIdx is set to index of the function. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N (parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with MinNLCSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetgradientcheck(minnlcstate state, double teststep);
/************************************************************************* This function sets linear constraints for MinNLC optimizer. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with MinNLCRestartFrom(). You may combine linear constraints with boundary ones - and with nonlinear ones! If your problem has mixed constraints, you may explicitly specify some of them as linear. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: when you solve your problem with augmented Lagrangian solver, linear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetlc( minnlcstate state, real_2d_array c, integer_1d_array ct); void alglib::minnlcsetlc( minnlcstate state, real_2d_array c, integer_1d_array ct, ae_int_t k);
/************************************************************************* This function sets nonlinear constraints for MinNLC optimizer. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to MinNLCOptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] corresponds to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with MinNLCCreate call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: when you solve your problem with augmented Lagrangian solver, nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of feasible area! NOTE 2: algorithm scales variables according to scale specified by MinNLCSetScale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by MinNLCSetScale() function). -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetnlc( minnlcstate state, ae_int_t nlec, ae_int_t nlic);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function sets preconditioner to "exact low rank" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss low rank preconditioner. Exact low-rank preconditioner uses Woodbury matrix identity to build quadratic model of the penalized function. It has no special assumptions about orthogonality, so it is quite general. However, for a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K^2) cost per iteration (for comparison: inexact LBFGS-based preconditioner has O(N*K) cost). INPUT PARAMETERS: State - structure stores algorithm state UpdateFreq- update frequency. Preconditioner is rebuilt after every UpdateFreq iterations. Recommended value: 10 or higher. Zero value means that good default value will be used. -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetprecexactlowrank( minnlcstate state, ae_int_t updatefreq);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function sets preconditioner to "inexact LBFGS-based" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. Comments below discuss LBFGS-based preconditioner. Inexact LBFGS-based preconditioner uses L-BFGS formula combined with orthogonality assumption to perform very fast updates. For a N-dimensional problem with K general linear or nonlinear constraints (boundary ones are not counted) it has O(N*K) cost per iteration. This preconditioner has best quality (less iterations) when general linear and nonlinear constraints are orthogonal to each other (orthogonality with respect to boundary constraints is not required). Number of iterations increases when constraints are non-orthogonal, because algorithm assumes orthogonality, but still it is better than no preconditioner at all. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetprecinexact(minnlcstate state);
/************************************************************************* This function sets preconditioner to "turned off" mode. Preconditioning is very important for convergence of Augmented Lagrangian algorithm because presence of penalty term makes problem ill-conditioned. Difference between performance of preconditioned and unpreconditioned methods can be as large as 100x! MinNLC optimizer may utilize two preconditioners, each with its own benefits and drawbacks: a) inexact LBFGS-based, and b) exact low rank one. It also provides special unpreconditioned mode of operation which can be used for test purposes. This function activates this test mode. Do not use it in production code to solve real-life problems. INPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 26.09.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetprecnone(minnlcstate state);
/************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 06.06.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetscale(minnlcstate state, real_1d_array s);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to MinNLCOptimize(). NOTE: algorithm passes two parameters to rep() callback - current point and penalized function value at current point. Important - function value which is returned is NOT function being minimized. It is sum of the value of the function being minimized - and penalty term. -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minnlcsetxrep(minnlcstate state, bool needxrep);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nlcfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1) = -x0+x1
    //     f1(x0,x1) = x0^2+x1^2-1
    //
    // and Jacobian matrix J = [dfi/dxj]
    //
    fi[0] = -x[0]+x[1];
    fi[1] = x[0]*x[0] + x[1]*x[1] - 1.0;
    jac[0][0] = -1.0;
    jac[0][1] = +1.0;
    jac[1][0] = 2*x[0];
    jac[1][1] = 2*x[1];
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = -x0+x1
    //
    // subject to nonlinear equality constraint
    //
    //    x0^2 + x1^2 - 1 = 0
    //
    real_1d_array x0 = "[0,0]";
    real_1d_array s = "[1,1]";
    double epsg = 0;
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t outerits = 5;
    ae_int_t updatefreq = 10;
    double rho = 1000;
    minnlcstate state;
    minnlcreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AUL algorithm and tune its settings:
    // * rho=1000       penalty coefficient
    // * outerits=5     number of outer iterations to tune Lagrange coefficients
    // * epsx=0.000001  stopping condition for inner iterations
    // * s=[1,1]        all variables have unit scale
    // * exact low-rank preconditioner is used, updated after each 10 iterations
    //
    minnlccreate(2, x0, state);
    minnlcsetalgoaul(state, rho, outerits);
    minnlcsetcond(state, epsg, epsf, epsx, maxits);
    minnlcsetscale(state, s);
    minnlcsetprecexactlowrank(state, updatefreq);

    //
    // Set constraints:
    //
    // Nonlinear constraints are tricky - you can not "pack" general
    // nonlinear function into double precision array. That's why
    // minnlcsetnlc() does not accept constraints itself - only constraint
    // counts are passed: first parameter is number of equality constraints,
    // second one is number of inequality constraints.
    //
    // As for constraining functions - these functions are passed as part
    // of problem Jacobian (see below).
    //
    // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general
    //       linear and general nonlinear constraints. This example does not
    //       show how to work with general linear constraints, but you can
    //       easily find it in documentation on minnlcsetbc() and
    //       minnlcsetlc() functions.
    //
    minnlcsetnlc(state, 1, 0);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints.
    //
    // So, our vector function has form
    //
    //     {f0,f1} = { -x0+x1 , x0^2+x1^2-1 }
    //
    // with Jacobian
    //
    //         [  -1    +1  ]
    //     J = [            ]
    //         [ 2*x0  2*x1 ]
    //
    // with f0 being target function, f1 being constraining function. Number
    // of equality/inequality constraints is specified by minnlcsetnlc(),
    // with equality ones always being first, inequality ones being last.
    //
    alglib::minnlcoptimize(state, nlcfunc1_jac);
    minnlcresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [0.70710,-0.70710]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nlcfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1) = -x0+x1
    //     f1(x0,x1) = x0^2+x1^2-1
    //
    // and Jacobian matrix J = [dfi/dxj]
    //
    fi[0] = -x[0]+x[1];
    fi[1] = x[0]*x[0] + x[1]*x[1] - 1.0;
    jac[0][0] = -1.0;
    jac[0][1] = +1.0;
    jac[1][0] = 2*x[0];
    jac[1][1] = 2*x[1];
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = -x0+x1
    //
    // subject to boundary constraints
    //
    //    x0>=0, x1>=0
    //
    // and nonlinear inequality constraint
    //
    //    x0^2 + x1^2 - 1 <= 0
    //
    real_1d_array x0 = "[0,0]";
    real_1d_array s = "[1,1]";
    double epsg = 0;
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t outerits = 5;
    ae_int_t updatefreq = 10;
    double rho = 1000;
    real_1d_array bndl = "[0,0]";
    real_1d_array bndu = "[+inf,+inf]";
    minnlcstate state;
    minnlcreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AUL algorithm and tune its settings:
    // * rho=1000       penalty coefficient
    // * outerits=5     number of outer iterations to tune Lagrange coefficients
    // * epsx=0.000001  stopping condition for inner iterations
    // * s=[1,1]        all variables have unit scale
    // * exact low-rank preconditioner is used, updated after each 10 iterations
    //
    minnlccreate(2, x0, state);
    minnlcsetalgoaul(state, rho, outerits);
    minnlcsetcond(state, epsg, epsf, epsx, maxits);
    minnlcsetscale(state, s);
    minnlcsetprecexactlowrank(state, updatefreq);

    //
    // Set constraints:
    //
    // 1. boundary constraints are passed with minnlcsetbc() call
    //
    // 2. nonlinear constraints are more tricky - you can not "pack" general
    //    nonlinear function into double precision array. That's why
    //    minnlcsetnlc() does not accept constraints itself - only constraint
    //    counts are passed: first parameter is number of equality constraints,
    //    second one is number of inequality constraints.
    //
    //    As for constraining functions - these functions are passed as part
    //    of problem Jacobian (see below).
    //
    // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general
    //       linear and general nonlinear constraints. This example does not
    //       show how to work with general linear constraints, but you can
    //       easily find it in documentation on minnlcsetlc() function.
    //
    minnlcsetbc(state, bndl, bndu);
    minnlcsetnlc(state, 0, 1);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints.
    //
    // So, our vector function has form
    //
    //     {f0,f1} = { -x0+x1 , x0^2+x1^2-1 }
    //
    // with Jacobian
    //
    //         [  -1    +1  ]
    //     J = [            ]
    //         [ 2*x0  2*x1 ]
    //
    // with f0 being target function, f1 being constraining function. Number
    // of equality/inequality constraints is specified by minnlcsetnlc(),
    // with equality ones always being first, inequality ones being last.
    //
    alglib::minnlcoptimize(state, nlcfunc1_jac);
    minnlcresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [1.0000,0.0000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nlcfunc2_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1,x2) = x0+x1
    //     f1(x0,x1,x2) = x2-exp(x0)
    //     f2(x0,x1,x2) = x0^2+x1^2-1
    //
    // and Jacobian matrix J = [dfi/dxj]
    //
    fi[0] = x[0]+x[1];
    fi[1] = x[2]-exp(x[0]);
    fi[2] = x[0]*x[0] + x[1]*x[1] - 1.0;
    jac[0][0] = 1.0;
    jac[0][1] = 1.0;
    jac[0][2] = 0.0;
    jac[1][0] = -exp(x[0]);
    jac[1][1] = 0.0;
    jac[1][2] = 1.0;
    jac[2][0] = 2*x[0];
    jac[2][1] = 2*x[1];
    jac[2][2] = 0.0;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = x0+x1
    //
    // subject to nonlinear inequality constraint
    //
    //    x0^2 + x1^2 - 1 <= 0
    //
    // and nonlinear equality constraint
    //
    //    x2-exp(x0) = 0
    //
    real_1d_array x0 = "[0,0,0]";
    real_1d_array s = "[1,1,1]";
    double epsg = 0;
    double epsf = 0;
    double epsx = 0.000001;
    ae_int_t maxits = 0;
    ae_int_t outerits = 5;
    ae_int_t updatefreq = 10;
    double rho = 1000;
    minnlcstate state;
    minnlcreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AUL algorithm and tune its settings:
    // * rho=1000       penalty coefficient
    // * outerits=5     number of outer iterations to tune Lagrange coefficients
    // * epsx=0.000001  stopping condition for inner iterations
    // * s=[1,1]        all variables have unit scale
    // * exact low-rank preconditioner is used, updated after each 10 iterations
    //
    minnlccreate(3, x0, state);
    minnlcsetalgoaul(state, rho, outerits);
    minnlcsetcond(state, epsg, epsf, epsx, maxits);
    minnlcsetscale(state, s);
    minnlcsetprecexactlowrank(state, updatefreq);

    //
    // Set constraints:
    //
    // Nonlinear constraints are tricky - you can not "pack" general
    // nonlinear function into double precision array. That's why
    // minnlcsetnlc() does not accept constraints itself - only constraint
    // counts are passed: first parameter is number of equality constraints,
    // second one is number of inequality constraints.
    //
    // As for constraining functions - these functions are passed as part
    // of problem Jacobian (see below).
    //
    // NOTE: MinNLC optimizer supports arbitrary combination of boundary, general
    //       linear and general nonlinear constraints. This example does not
    //       show how to work with boundary or general linear constraints, but you
    //       can easily find it in documentation on minnlcsetbc() and
    //       minnlcsetlc() functions.
    //
    minnlcsetnlc(state, 1, 1);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints.
    //
    // So, our vector function has form
    //
    //     {f0,f1,f2} = { x0+x1 , x2-exp(x0) , x0^2+x1^2-1 }
    //
    // with Jacobian
    //
    //         [  +1      +1       0 ]
    //     J = [-exp(x0)  0        1 ]
    //         [ 2*x0    2*x1      0 ]
    //
    // with f0 being target function, f1 being equality constraint "f1=0",
    // f2 being inequality constraint "f2<=0". Number of equality/inequality
    // constraints is specified by minnlcsetnlc(), with equality ones always
    // being first, inequality ones being last.
    //
    alglib::minnlcoptimize(state, nlcfunc2_jac);
    minnlcresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [-0.70710,-0.70710,0.49306]
    return 0;
}


minnsreport
minnsstate
minnscreate
minnscreatef
minnsoptimize
minnsrequesttermination
minnsrestartfrom
minnsresults
minnsresultsbuf
minnssetalgoags
minnssetbc
minnssetcond
minnssetlc
minnssetnlc
minnssetscale
minnssetxrep
minns_d_bc Nonsmooth box constrained optimization
minns_d_diff Nonsmooth unconstrained optimization with numerical differentiation
minns_d_nlc Nonsmooth nonlinearly constrained optimization
minns_d_unconstrained Nonsmooth unconstrained optimization
/************************************************************************* This structure stores optimization report: * IterationsCount total number of inner iterations * NFEV number of gradient evaluations * TerminationType termination type (see below) * CErr maximum violation of all types of constraints * LCErr maximum violation of linear constraints * NLCErr maximum violation of nonlinear constraints TERMINATION CODES TerminationType field contains completion code, which can be: -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. -3 box constraints are inconsistent -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() 2 sampling radius decreased below epsx 5 MaxIts steps was taken 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. 8 User requested termination via MinNSRequestTermination() Other fields of this structure are not documented and should not be used! *************************************************************************/
class minnsreport { ae_int_t iterationscount; ae_int_t nfev; double cerr; double lcerr; double nlcerr; ae_int_t terminationtype; ae_int_t varidx; ae_int_t funcidx; };
/************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinNS subpackage to work with this object *************************************************************************/
class minnsstate { };
/************************************************************************* NONSMOOTH NONCONVEX OPTIMIZATION SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS DESCRIPTION: The subroutine minimizes function F(x) of N arguments subject to any combination of: * bound constraints * linear inequality constraints * linear equality constraints * nonlinear equality constraints Gi(x)=0 * nonlinear inequality constraints Hi(x)<=0 IMPORTANT: see MinNSSetAlgoAGS for important information on performance restrictions of AGS solver. REQUIREMENTS: * starting point X0 must be feasible or not too far away from the feasible set * F(), G(), H() are continuous, locally Lipschitz and continuously (but not necessarily twice) differentiable in an open dense subset of R^N. Functions F(), G() and H() may be nonsmooth and non-convex. Informally speaking, it means that functions are composed of large differentiable "patches" with nonsmoothness having place only at the boundaries between these "patches". Most real-life nonsmooth functions satisfy these requirements. Say, anything which involves finite number of abs(), min() and max() is very likely to pass the test. Say, it is possible to optimize anything of the following: * f=abs(x0)+2*abs(x1) * f=max(x0,x1) * f=sin(max(x0,x1)+abs(x2)) * for nonlinearly constrained problems: F() must be bounded from below without nonlinear constraints (this requirement is due to the fact that, contrary to box and linear constraints, nonlinear ones require special handling). * user must provide function value and gradient for F(), H(), G() at all points where function/gradient can be calculated. If optimizer requires value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), where gradient is not defined, user may resolve tie arbitrarily (in our case - return +1 or -1 at its discretion). * NS solver supports numerical differentiation, i.e. it may differentiate your function for you, but it results in 2N increase of function evaluations. Not recommended unless you solve really small problems. See minnscreatef() for more information on this functionality. USAGE: 1. User initializes algorithm state with MinNSCreate() call and chooses what NLC solver to use. There is some solver which is used by default, with default settings, but you should NOT rely on default choice. It may change in future releases of ALGLIB without notice, and no one can guarantee that new solver will be able to solve your problem with default settings. From the other side, if you choose solver explicitly, you can be pretty sure that it will work with new ALGLIB releases. In the current release following solvers can be used: * AGS solver (activated with MinNSSetAlgoAGS() function) 2. User adds boundary and/or linear and/or nonlinear constraints by means of calling one of the following functions: a) MinNSSetBC() for boundary constraints b) MinNSSetLC() for linear constraints c) MinNSSetNLC() for nonlinear constraints You may combine (a), (b) and (c) in one optimization problem. 3. User sets scale of the variables with MinNSSetScale() function. It is VERY important to set scale of the variables, because nonlinearly constrained problems are hard to solve when variables are badly scaled. 4. User sets stopping conditions with MinNSSetCond(). 5. Finally, user calls MinNSOptimize() function which takes algorithm state and pointer (delegate, etc) to callback function which calculates F/G/H. 7. User calls MinNSResults() to get solution 8. Optionally user may call MinNSRestartFrom() to solve another problem with same N but another starting point. MinNSRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. OUTPUT PARAMETERS: State - structure stores algorithm state NOTE: minnscreatef() function may be used if you do not have analytic gradient. This function creates solver which uses numerical differentiation with user-specified step. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnscreate(real_1d_array x, minnsstate& state); void alglib::minnscreate(ae_int_t n, real_1d_array x, minnsstate& state);

Examples:   [1]  [2]  [3]  

/************************************************************************* Version of minnscreatef() which uses numerical differentiation. I.e., you do not have to calculate derivatives yourself. However, this version needs 2N times more function evaluations. 2-point differentiation formula is used, because more precise 4-point formula is unstable when used on non-smooth functions. INPUT PARAMETERS: N - problem dimension, N>0: * if given, only leading N elements of X are used * if not given, automatically determined from size of X X - starting point, array[N]: * it is better to set X to a feasible point * but X can be infeasible, in which case algorithm will try to find feasible point first, using X as initial approximation. DiffStep- differentiation step, DiffStep>0. Algorithm performs numerical differentiation with step for I-th variable being equal to DiffStep*S[I] (here S[] is a scale vector, set by minnssetscale() function). Do not use too small steps, because it may lead to catastrophic cancellation during intermediate calculations. OUTPUT PARAMETERS: State - structure stores algorithm state -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnscreatef( real_1d_array x, double diffstep, minnsstate& state); void alglib::minnscreatef( ae_int_t n, real_1d_array x, double diffstep, minnsstate& state);

Examples:   [1]  

/************************************************************************* This family of functions is used to launcn iterations of nonlinear optimizer These functions accept following parameters: state - algorithm state fvec - callback which calculates function vector fi[] at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL NOTES: 1. This function has two different implementations: one which uses exact (analytical) user-supplied Jacobian, and one which uses only function vector and numerically differentiates function in order to obtain gradient. Depending on the specific function used to create optimizer object you should choose appropriate variant of minnsoptimize() - one which accepts function AND Jacobian or one which accepts ONLY function. Be careful to choose variant of minnsoptimize() which corresponds to your optimization scheme! Table below lists different combinations of callback (function/gradient) passed to minnsoptimize() and specific function used to create optimizer. | USER PASSED TO minnsoptimize() CREATED WITH | function only | function and gradient ------------------------------------------------------------ minnscreatef() | works FAILS minnscreate() | FAILS works Here "FAILS" denotes inappropriate combinations of optimizer creation function and minnsoptimize() version. Attemps to use such combination will lead to exception. Either you did not pass gradient when it WAS needed or you passed gradient when it was NOT needed. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void minnsoptimize(minnsstate &state, void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL); void minnsoptimize(minnsstate &state, void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This subroutine submits request for termination of running optimizer. It should be called from user-supplied callback when user decides that it is time to "smoothly" terminate optimization process. As result, optimizer stops at point which was "current accepted" when termination request was submitted and returns error code 8 (successful termination). INPUT PARAMETERS: State - optimizer structure NOTE: after request for termination optimizer may perform several additional calls to user-supplied callbacks. It does NOT guarantee to stop immediately - it just guarantees that these additional calls will be discarded later. NOTE: calling this function on optimizer which is NOT running will have no effect. NOTE: multiple calls to this function are possible. First call is counted, subsequent calls are silently ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnsrequesttermination(minnsstate state);
/************************************************************************* This subroutine restarts algorithm from new point. All optimization parameters (including constraints) are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. X - new starting point. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnsrestartfrom(minnsstate state, real_1d_array x);
/************************************************************************* MinNS results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report. You should check Rep.TerminationType in order to distinguish successful termination from unsuccessful one: * -8 internal integrity control detected infinite or NAN values in function/gradient. Abnormal termination signalled. * -3 box constraints are inconsistent * -1 inconsistent parameters were passed: * penalty parameter for minnssetalgoags() is zero, but we have nonlinear constraints set by minnssetnlc() * 2 sampling radius decreased below epsx * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. * 8 User requested termination via minnsrequesttermination() -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnsresults( minnsstate state, real_1d_array& x, minnsreport& rep);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* Buffered implementation of minnsresults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnsresultsbuf( minnsstate state, real_1d_array& x, minnsreport& rep);
/************************************************************************* This function tells MinNS unit to use AGS (adaptive gradient sampling) algorithm for nonsmooth constrained optimization. This algorithm is a slight modification of one described in "An Adaptive Gradient Sampling Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. This optimizer has following benefits and drawbacks: + robustness; it can be used with nonsmooth and nonconvex functions. + relatively easy tuning; most of the metaparameters are easy to select. - it has convergence of steepest descent, slower than CG/LBFGS. - each iteration involves evaluation of ~2N gradient values and solution of 2Nx2N quadratic programming problem, which limits applicability of algorithm by small-scale problems (up to 50-100). IMPORTANT: this algorithm has convergence guarantees, i.e. it will steadily move towards some stationary point of the function. However, "stationary point" does not always mean "solution". Nonsmooth problems often have "flat spots", i.e. areas where function do not change at all. Such "flat spots" are stationary points by definition, and algorithm may be caught here. Nonsmooth CONVEX tasks are not prone to this problem. Say, if your function has form f()=MAX(f0,f1,...), and f_i are convex, then f() is convex too and you have guaranteed convergence to solution. INPUT PARAMETERS: State - structure which stores algorithm state Radius - initial sampling radius, >=0. Internally multiplied by vector of per-variable scales specified by minnssetscale()). You should select relatively large sampling radius, roughly proportional to scaled length of the first steps of the algorithm. Something close to 0.1 in magnitude should be good for most problems. AGS solver can automatically decrease radius, so too large radius is not a problem (assuming that you won't choose so large radius that algorithm will sample function in too far away points, where gradient value is irrelevant). Too small radius won't cause algorithm to fail, but it may slow down algorithm (it may have to perform too short steps). Penalty - penalty coefficient for nonlinear constraints: * for problem with nonlinear constraints should be some problem-specific positive value, large enough that penalty term changes shape of the function. Starting from some problem-specific value penalty coefficient becomes large enough to exactly enforce nonlinear constraints; larger values do not improve precision. Increasing it too much may slow down convergence, so you should choose it carefully. * can be zero for problems WITHOUT nonlinear constraints (i.e. for unconstrained ones or ones with just box or linear constraints) * if you specify zero value for problem with at least one nonlinear constraint, algorithm will terminate with error code -1. ALGORITHM OUTLINE The very basic outline of unconstrained AGS algorithm is given below: 0. If sampling radius is below EpsX or we performed more then MaxIts iterations - STOP. 1. sample O(N) gradient values at random locations around current point; informally speaking, this sample is an implicit piecewise linear model of the function, although algorithm formulation does not mention that explicitly 2. solve quadratic programming problem in order to find descent direction 3. if QP solver tells us that we are near solution, decrease sampling radius and move to (0) 4. perform backtracking line search 5. after moving to new point, goto (0) As for the constraints: * box constraints are handled exactly by modification of the function being minimized * linear/nonlinear constraints are handled by adding L1 penalty. Because our solver can handle nonsmoothness, we can use L1 penalty function, which is an exact one (i.e. exact solution is returned under such penalty). * penalty coefficient for linear constraints is chosen automatically; however, penalty coefficient for nonlinear constraints must be specified by user. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetalgoags( minnsstate state, double radius, double penalty);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This function sets boundary constraints. Boundary constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF. BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF. NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: AGS solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints, even when numerical differentiation is used (algorithm adjusts nodes according to boundary constraints) -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetbc( minnsstate state, real_1d_array bndl, real_1d_array bndu);

Examples:   [1]  

/************************************************************************* This function sets stopping conditions for iterations of optimizer. INPUT PARAMETERS: State - structure which stores algorithm state EpsX - >=0 The AGS solver finishes its work if on k+1-th iteration sampling radius decreases below EpsX. MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection. We do not recommend you to rely on default choice in production code. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetcond(minnsstate state, double epsx, ae_int_t maxits);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This function sets linear constraints. Linear constraints are inactive by default (after initial creation). They are preserved after algorithm restart with minnsrestartfrom(). INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE: linear (non-bound) constraints are satisfied only approximately: * there always exists some minor violation (about current sampling radius in magnitude during optimization, about EpsX in the solution) due to use of penalty method to handle constraints. * numerical differentiation, if used, may lead to function evaluations outside of the feasible area, because algorithm does NOT change numerical differentiation formula according to linear constraints. If you want constraints to be satisfied exactly, try to reformulate your problem in such manner that all constraints will become boundary ones (this kind of constraints is always satisfied exactly, both in the final solution and in all intermediate points). -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetlc( minnsstate state, real_2d_array c, integer_1d_array ct); void alglib::minnssetlc( minnsstate state, real_2d_array c, integer_1d_array ct, ae_int_t k);
/************************************************************************* This function sets nonlinear constraints. In fact, this function sets NUMBER of nonlinear constraints. Constraints itself (constraint functions) are passed to minnsoptimize() method. This method requires user-defined vector function F[] and its Jacobian J[], where: * first component of F[] and first row of Jacobian J[] correspond to function being minimized * next NLEC components of F[] (and rows of J) correspond to nonlinear equality constraints G_i(x)=0 * next NLIC components of F[] (and rows of J) correspond to nonlinear inequality constraints H_i(x)<=0 NOTE: you may combine nonlinear constraints with linear/boundary ones. If your problem has mixed constraints, you may explicitly specify some of them as linear ones. It may help optimizer to handle them more efficiently. INPUT PARAMETERS: State - structure previously allocated with minnscreate() call. NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 NOTE 1: nonlinear constraints are satisfied only approximately! It is possible that algorithm will evaluate function outside of the feasible area! NOTE 2: algorithm scales variables according to scale specified by minnssetscale() function, so it can handle problems with badly scaled variables (as long as we KNOW their scales). However, there is no way to automatically scale nonlinear constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may ruin convergence. Solving problem with constraint "1000*G0(x)=0" is NOT same as solving it with constraint "0.001*G0(x)=0". It means that YOU are the one who is responsible for correct scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you to scale nonlinear constraints in such way that I-th component of dG/dX (or dH/dx) has approximately unit magnitude (for problems with unit scale) or has magnitude approximately equal to 1/S[i] (where S is a scale set by minnssetscale() function). NOTE 3: nonlinear constraints are always hard to handle, no matter what algorithm you try to use. Even basic box/linear constraints modify function curvature by adding valleys and ridges. However, nonlinear constraints add valleys which are very hard to follow due to their "curved" nature. It means that optimization with single nonlinear constraint may be significantly slower than optimization with multiple linear ones. It is normal situation, and we recommend you to carefully choose Rho parameter of minnssetalgoags(), because too large value may slow down convergence. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetnlc(minnsstate state, ae_int_t nlec, ae_int_t nlic);

Examples:   [1]  

/************************************************************************* This function sets scaling coefficients for NLC optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Scaling is also used by finite difference variant of the optimizer - step along I-th axis is equal to DiffStep*S[I]. INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 18.05.2015 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetscale(minnsstate state, real_1d_array s);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to minnsoptimize(). -- ALGLIB -- Copyright 28.11.2010 by Bochkanov Sergey *************************************************************************/
void alglib::minnssetxrep(minnsstate state, bool needxrep);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nsfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1) = 2*|x0|+x1
    //
    // and Jacobian matrix J = [df0/dx0 df0/dx1]
    //
    fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1]));
    jac[0][0] = 2*alglib::sign(x[0]);
    jac[0][1] = alglib::sign(x[1]);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = 2*|x0|+|x1|
    //
    // subject to box constraints
    //
    //        1 <= x0 < +INF
    //     -INF <= x1 < +INF
    //
    // using nonsmooth nonlinear optimizer.
    //
    real_1d_array x0 = "[1,1]";
    real_1d_array s = "[1,1]";
    real_1d_array bndl = "[1,-inf]";
    real_1d_array bndu = "[+inf,+inf]";
    double epsx = 0.00001;
    double radius = 0.1;
    double rho = 0.0;
    ae_int_t maxits = 0;
    minnsstate state;
    minnsreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AGS algorithm and tune its settings:
    // * radius=0.1     good initial value; will be automatically decreased later.
    // * rho=0.0        penalty coefficient for nonlinear constraints; can be zero
    //                  because we do not have such constraints
    // * epsx=0.000001  stopping conditions
    // * s=[1,1]        all variables have unit scale
    //
    minnscreate(2, x0, state);
    minnssetalgoags(state, radius, rho);
    minnssetcond(state, epsx, maxits);
    minnssetscale(state, s);

    //
    // Set box constraints.
    //
    // General linear constraints are set in similar way (see comments on
    // minnssetlc() function for more information).
    //
    // You may combine box, linear and nonlinear constraints in one optimization
    // problem.
    //
    minnssetbc(state, bndl, bndu);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints
    // (box/linear ones are passed separately by means of minnssetbc() and
    // minnssetlc() calls).
    //
    // If you do not have nonlinear constraints (exactly our situation), then
    // you will have one-component function vector and 1xN Jacobian matrix.
    //
    // So, our vector function has form
    //
    //     {f0} = { 2*|x0|+|x1| }
    //
    // with Jacobian
    //
    //         [                       ]
    //     J = [ 2*sign(x0)   sign(x1) ]
    //         [                       ]
    //
    // NOTE: nonsmooth optimizer requires considerably more function
    //       evaluations than smooth solver - about 2N times more. Using
    //       numerical differentiation introduces additional (multiplicative)
    //       2N speedup.
    //
    //       It means that if smooth optimizer WITH user-supplied gradient
    //       needs 100 function evaluations to solve 50-dimensional problem,
    //       then AGS solver with user-supplied gradient will need about 10.000
    //       function evaluations, and with numerical gradient about 1.000.000
    //       function evaluations will be performed.
    //
    // NOTE: AGS solver used by us can handle nonsmooth and nonconvex
    //       optimization problems. It has convergence guarantees, i.e. it will
    //       converge to stationary point of the function after running for some
    //       time.
    //
    //       However, it is important to remember that "stationary point" is not
    //       equal to "solution". If your problem is convex, everything is OK.
    //       But nonconvex optimization problems may have "flat spots" - large
    //       areas where gradient is exactly zero, but function value is far away
    //       from optimal. Such areas are stationary points too, and optimizer
    //       may be trapped here.
    //
    //       "Flat spots" are nonsmooth equivalent of the saddle points, but with
    //       orders of magnitude worse properties - they may be quite large and
    //       hard to avoid. All nonsmooth optimizers are prone to this kind of the
    //       problem, because it is impossible to automatically distinguish "flat
    //       spot" from true solution.
    //
    //       This note is here to warn you that you should be very careful when
    //       you solve nonsmooth optimization problems. Visual inspection of
    //       results is essential.
    //
    //
    alglib::minnsoptimize(state, nsfunc1_jac);
    minnsresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [1.0000,0.0000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nsfunc1_fvec(const real_1d_array &x, real_1d_array &fi, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1) = 2*|x0|+x1
    //
    fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1]));
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = 2*|x0|+|x1|
    //
    // using nonsmooth nonlinear optimizer with numerical
    // differentiation provided by ALGLIB.
    //
    // NOTE: nonsmooth optimizer requires considerably more function
    //       evaluations than smooth solver - about 2N times more. Using
    //       numerical differentiation introduces additional (multiplicative)
    //       2N speedup.
    //
    //       It means that if smooth optimizer WITH user-supplied gradient
    //       needs 100 function evaluations to solve 50-dimensional problem,
    //       then AGS solver with user-supplied gradient will need about 10.000
    //       function evaluations, and with numerical gradient about 1.000.000
    //       function evaluations will be performed.
    //
    real_1d_array x0 = "[1,1]";
    real_1d_array s = "[1,1]";
    double epsx = 0.00001;
    double diffstep = 0.000001;
    double radius = 0.1;
    double rho = 0.0;
    ae_int_t maxits = 0;
    minnsstate state;
    minnsreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AGS algorithm and tune its settings:
    // * radius=0.1     good initial value; will be automatically decreased later.
    // * rho=0.0        penalty coefficient for nonlinear constraints; can be zero
    //                  because we do not have such constraints
    // * epsx=0.000001  stopping conditions
    // * s=[1,1]        all variables have unit scale
    //
    minnscreatef(2, x0, diffstep, state);
    minnssetalgoags(state, radius, rho);
    minnssetcond(state, epsx, maxits);
    minnssetscale(state, s);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function, with first component
    // being target function, and next components being nonlinear equality
    // and inequality constraints (box/linear ones are passed separately
    // by means of minnssetbc() and minnssetlc() calls).
    //
    // If you do not have nonlinear constraints (exactly our situation), then
    // you will have one-component function vector.
    //
    // So, our vector function has form
    //
    //     {f0} = { 2*|x0|+|x1| }
    //
    alglib::minnsoptimize(state, nsfunc1_fvec);
    minnsresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [0.0000,0.0000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nsfunc2_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates function vector
    //
    //     f0(x0,x1) = 2*|x0|+x1
    //     f1(x0,x1) = x0-1
    //     f2(x0,x1) = -x1-1
    //
    // and Jacobian matrix J
    //
    //         [ df0/dx0   df0/dx1 ]
    //     J = [ df1/dx0   df1/dx1 ]
    //         [ df2/dx0   df2/dx1 ]
    //
    fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1]));
    jac[0][0] = 2*alglib::sign(x[0]);
    jac[0][1] = alglib::sign(x[1]);
    fi[1] = x[0]-1;
    jac[1][0] = 1;
    jac[1][1] = 0;
    fi[2] = -x[1]-1;
    jac[2][0] = 0;
    jac[2][1] = -1;
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = 2*|x0|+|x1|
    //
    // subject to combination of equality and inequality constraints
    //
    //      x0  =  1
    //      x1 >= -1
    //
    // using nonsmooth nonlinear optimizer. Although these constraints
    // are linear, we treat them as general nonlinear ones in order to
    // demonstrate nonlinearly constrained optimization setup.
    //
    real_1d_array x0 = "[1,1]";
    real_1d_array s = "[1,1]";
    double epsx = 0.00001;
    double radius = 0.1;
    double rho = 50.0;
    ae_int_t maxits = 0;
    minnsstate state;
    minnsreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AGS algorithm and tune its settings:
    // * radius=0.1     good initial value; will be automatically decreased later.
    // * rho=50.0       penalty coefficient for nonlinear constraints. It is your
    //                  responsibility to choose good one - large enough that it
    //                  enforces constraints, but small enough in order to avoid
    //                  extreme slowdown due to ill-conditioning.
    // * epsx=0.000001  stopping conditions
    // * s=[1,1]        all variables have unit scale
    //
    minnscreate(2, x0, state);
    minnssetalgoags(state, radius, rho);
    minnssetcond(state, epsx, maxits);
    minnssetscale(state, s);

    //
    // Set general nonlinear constraints.
    //
    // This part is more tricky than working with box/linear constraints - you
    // can not "pack" general nonlinear function into double precision array.
    // That's why minnssetnlc() does not accept constraints itself - only
    // constraint COUNTS are passed: first parameter is number of equality
    // constraints, second one is number of inequality constraints.
    //
    // As for constraining functions - these functions are passed as part
    // of problem Jacobian (see below).
    //
    // NOTE: MinNS optimizer supports arbitrary combination of boundary, general
    //       linear and general nonlinear constraints. This example does not
    //       show how to work with general linear constraints, but you can
    //       easily find it in documentation on minnlcsetlc() function.
    //
    minnssetnlc(state, 1, 1);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints
    // (box/linear ones are passed separately by means of minnssetbc() and
    // minnssetlc() calls).
    //
    // Nonlinear equality constraints have form Gi(x)=0, inequality ones
    // have form Hi(x)<=0, so we may have to "normalize" constraints prior
    // to passing them to optimizer (right side is zero, constraints are
    // sorted, multiplied by -1 when needed).
    //
    // So, our vector function has form
    //
    //     {f0,f1,f2} = { 2*|x0|+|x1|,  x0-1, -x1-1 }
    //
    // with Jacobian
    //
    //         [ 2*sign(x0)   sign(x1) ]
    //     J = [     1           0     ]
    //         [     0          -1     ]
    //
    // which means that we have optimization problem
    //
    //     min{f0} subject to f1=0, f2<=0
    //
    // which is essentially same as
    //
    //     min { 2*|x0|+|x1| } subject to x0=1, x1>=-1
    //
    // NOTE: AGS solver used by us can handle nonsmooth and nonconvex
    //       optimization problems. It has convergence guarantees, i.e. it will
    //       converge to stationary point of the function after running for some
    //       time.
    //
    //       However, it is important to remember that "stationary point" is not
    //       equal to "solution". If your problem is convex, everything is OK.
    //       But nonconvex optimization problems may have "flat spots" - large
    //       areas where gradient is exactly zero, but function value is far away
    //       from optimal. Such areas are stationary points too, and optimizer
    //       may be trapped here.
    //
    //       "Flat spots" are nonsmooth equivalent of the saddle points, but with
    //       orders of magnitude worse properties - they may be quite large and
    //       hard to avoid. All nonsmooth optimizers are prone to this kind of the
    //       problem, because it is impossible to automatically distinguish "flat
    //       spot" from true solution.
    //
    //       This note is here to warn you that you should be very careful when
    //       you solve nonsmooth optimization problems. Visual inspection of
    //       results is essential.
    //
    alglib::minnsoptimize(state, nsfunc2_jac);
    minnsresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [1.0000,0.0000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;
void  nsfunc1_jac(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr)
{
    //
    // this callback calculates
    //
    //     f0(x0,x1) = 2*|x0|+x1
    //
    // and Jacobian matrix J = [df0/dx0 df0/dx1]
    //
    fi[0] = 2*fabs(double(x[0]))+fabs(double(x[1]));
    jac[0][0] = 2*alglib::sign(x[0]);
    jac[0][1] = alglib::sign(x[1]);
}

int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of
    //
    //     f(x0,x1) = 2*|x0|+|x1|
    //
    // using nonsmooth nonlinear optimizer.
    //
    real_1d_array x0 = "[1,1]";
    real_1d_array s = "[1,1]";
    double epsx = 0.00001;
    double radius = 0.1;
    double rho = 0.0;
    ae_int_t maxits = 0;
    minnsstate state;
    minnsreport rep;
    real_1d_array x1;

    //
    // Create optimizer object, choose AGS algorithm and tune its settings:
    // * radius=0.1     good initial value; will be automatically decreased later.
    // * rho=0.0        penalty coefficient for nonlinear constraints; can be zero
    //                  because we do not have such constraints
    // * epsx=0.000001  stopping conditions
    // * s=[1,1]        all variables have unit scale
    //
    minnscreate(2, x0, state);
    minnssetalgoags(state, radius, rho);
    minnssetcond(state, epsx, maxits);
    minnssetscale(state, s);

    //
    // Optimize and test results.
    //
    // Optimizer object accepts vector function and its Jacobian, with first
    // component (Jacobian row) being target function, and next components
    // (Jacobian rows) being nonlinear equality and inequality constraints
    // (box/linear ones are passed separately by means of minnssetbc() and
    // minnssetlc() calls).
    //
    // If you do not have nonlinear constraints (exactly our situation), then
    // you will have one-component function vector and 1xN Jacobian matrix.
    //
    // So, our vector function has form
    //
    //     {f0} = { 2*|x0|+|x1| }
    //
    // with Jacobian
    //
    //         [                       ]
    //     J = [ 2*sign(x0)   sign(x1) ]
    //         [                       ]
    //
    // NOTE: nonsmooth optimizer requires considerably more function
    //       evaluations than smooth solver - about 2N times more. Using
    //       numerical differentiation introduces additional (multiplicative)
    //       2N speedup.
    //
    //       It means that if smooth optimizer WITH user-supplied gradient
    //       needs 100 function evaluations to solve 50-dimensional problem,
    //       then AGS solver with user-supplied gradient will need about 10.000
    //       function evaluations, and with numerical gradient about 1.000.000
    //       function evaluations will be performed.
    //
    // NOTE: AGS solver used by us can handle nonsmooth and nonconvex
    //       optimization problems. It has convergence guarantees, i.e. it will
    //       converge to stationary point of the function after running for some
    //       time.
    //
    //       However, it is important to remember that "stationary point" is not
    //       equal to "solution". If your problem is convex, everything is OK.
    //       But nonconvex optimization problems may have "flat spots" - large
    //       areas where gradient is exactly zero, but function value is far away
    //       from optimal. Such areas are stationary points too, and optimizer
    //       may be trapped here.
    //
    //       "Flat spots" are nonsmooth equivalent of the saddle points, but with
    //       orders of magnitude worse properties - they may be quite large and
    //       hard to avoid. All nonsmooth optimizers are prone to this kind of the
    //       problem, because it is impossible to automatically distinguish "flat
    //       spot" from true solution.
    //
    //       This note is here to warn you that you should be very careful when
    //       you solve nonsmooth optimization problems. Visual inspection of
    //       results is essential.
    //
    alglib::minnsoptimize(state, nsfunc1_jac);
    minnsresults(state, x1, rep);
    printf("%s\n", x1.tostring(2).c_str()); // EXPECTED: [0.0000,0.0000]
    return 0;
}


minqpreport
minqpstate
minqpcreate
minqpoptimize
minqpresults
minqpresultsbuf
minqpsetalgobleic
minqpsetalgocholesky
minqpsetalgoquickqp
minqpsetbc
minqpsetlc
minqpsetlinearterm
minqpsetorigin
minqpsetquadraticterm
minqpsetquadratictermsparse
minqpsetscale
minqpsetstartingpoint
minqp_d_bc1 Bound constrained dense quadratic programming
minqp_d_lc1 Linearly constrained dense quadratic programming
minqp_d_nonconvex Nonconvex quadratic programming
minqp_d_u1 Unconstrained dense quadratic programming
minqp_d_u2 Unconstrained sparse quadratic programming
/************************************************************************* This structure stores optimization report: * InnerIterationsCount number of inner iterations * OuterIterationsCount number of outer iterations * NCholesky number of Cholesky decomposition * NMV number of matrix-vector products (only products calculated as part of iterative process are counted) * TerminationType completion code (see below) Completion codes: * -5 inappropriate solver was used: * QuickQP solver for problem with general linear constraints * Cholesky solver for semidefinite or indefinite problems * Cholesky solver for problems with non-boundary constraints * -4 BLEIC-QP or QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or, maybe, feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. * -1 solver error * 1..4 successful completion * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible, X contains best point found so far. *************************************************************************/
class minqpreport { ae_int_t inneriterationscount; ae_int_t outeriterationscount; ae_int_t nmv; ae_int_t ncholesky; ae_int_t terminationtype; };
/************************************************************************* This object stores nonlinear optimizer state. You should use functions provided by MinQP subpackage to work with this object *************************************************************************/
class minqpstate { };
/************************************************************************* CONSTRAINED QUADRATIC PROGRAMMING The subroutine creates QP optimizer. After initial creation, it contains default optimization problem with zero quadratic and linear terms and no constraints. You should set quadratic/linear terms with calls to functions provided by MinQP subpackage. You should also choose appropriate QP solver and set it and its stopping criteria by means of MinQPSetAlgo??????() function. Then, you should start solution process by means of MinQPOptimize() call. Solution itself can be obtained with MinQPResults() function. INPUT PARAMETERS: N - problem size OUTPUT PARAMETERS: State - optimizer with zero quadratic/linear terms and no constraints -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpcreate(ae_int_t n, minqpstate& state);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function solves quadratic programming problem. Prior to calling this function you should choose solver by means of one of the following functions: * MinQPSetAlgoQuickQP() - for QuickQP solver * MinQPSetAlgoBLEIC() - for BLEIC-QP solver These functions also allow you to control stopping criteria of the solver. If you did not set solver, MinQP subpackage will automatically select solver for your problem and will run it with default stopping criteria. However, it is better to set explicitly solver and its stopping criteria. INPUT PARAMETERS: State - algorithm state You should use MinQPResults() function to access results after calls to this function. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey. Special thanks to Elvira Illarionova for important suggestions on the linearly constrained QP algorithm. *************************************************************************/
void alglib::minqpoptimize(minqpstate state);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* QP solver results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: X - array[0..N-1], solution. This array is allocated and initialized only when Rep.TerminationType parameter is positive (success). Rep - optimization report. You should check Rep.TerminationType, which contains completion code, and you may check another fields which contain another information about algorithm functioning. Failure codes returned by algorithm are: * -5 inappropriate solver was used: * Cholesky solver for (semi)indefinite problems * Cholesky solver for problems with sparse matrix * QuickQP solver for problem with general linear constraints * -4 BLEIC-QP/QuickQP solver found unconstrained direction of negative curvature (function is unbounded from below even under constraints), no meaningful minimum can be found. * -3 inconsistent constraints (or maybe feasible point is too hard to find). If you are sure that constraints are feasible, try to restart optimizer with better initial approximation. Completion codes specific for Cholesky algorithm: * 4 successful completion Completion codes specific for BLEIC/QuickQP algorithms: * 1 relative function improvement is no more than EpsF. * 2 scaled step is no more than EpsX. * 4 scaled gradient norm is no more than EpsG. * 5 MaxIts steps was taken -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpresults( minqpstate state, real_1d_array& x, minqpreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* QP results Buffered implementation of MinQPResults() which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpresultsbuf( minqpstate state, real_1d_array& x, minqpreport& rep);
/************************************************************************* This function tells solver to use BLEIC-based algorithm and sets stopping criteria for the algorithm. ALGORITHM FEATURES: * supports dense and sparse QP problems * supports boundary and general linear equality/inequality constraints * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". Of course, global minimum is found only for positive definite and semidefinite problems. As for indefinite ones - only local minimum is found. ALGORITHM OUTLINE: * BLEIC-QP solver is just a driver function for MinBLEIC solver; it solves quadratic programming problem as general linearly constrained optimization problem, which is solved by means of BLEIC solver (part of ALGLIB, active set method). ALGORITHM LIMITATIONS: * unlike QuickQP solver, this algorithm does not perform Newton steps and does not use Level 3 BLAS. Being general-purpose active set method, it can activate constraints only one-by-one. Thus, its performance is lower than that of QuickQP. * its precision is also a bit inferior to that of QuickQP. BLEIC-QP performs only LBFGS steps (no Newton steps), which are good at detecting neighborhood of the solution, buy need many iterations to find solution with more than 6 digits of precision. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled constrained gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinQPSetScale() EpsF - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. NOTE: this algorithm uses LBFGS iterations, which are relatively cheap, but improve function value only a bit. So you will need many iterations to converge - from 0.1*N to 10*N, depending on problem's condition number. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetalgobleic( minqpstate state, double epsg, double epsf, double epsx, ae_int_t maxits);
/************************************************************************* This function tells solver to use Cholesky-based algorithm. This algorithm was deprecated in ALGLIB 3.9.0 because its performance is inferior to that of BLEIC-QP or QuickQP on high-dimensional problems. Furthermore, it supports only dense convex QP problems. This solver is no longer active by default. We recommend you to switch to BLEIC-QP or QuickQP solver. INPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetalgocholesky(minqpstate state);
/************************************************************************* This function tells solver to use QuickQP algorithm: special extra-fast algorithm for problems with boundary-only constrants. It may solve non-convex problems as long as they are bounded from below under constraints. ALGORITHM FEATURES: * many times (from 5x to 50x!) faster than BLEIC-based QP solver; utilizes accelerated methods for activation of constraints. * supports dense and sparse QP problems * supports ONLY boundary constraints; general linear constraints are NOT supported by this solver * can solve all types of problems (convex, semidefinite, nonconvex) as long as they are bounded from below under constraints. Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". In convex/semidefinite case global minimum is returned, in nonconvex case - algorithm returns one of the local minimums. ALGORITHM OUTLINE: * algorithm performs two kinds of iterations: constrained CG iterations and constrained Newton iterations * initially it performs small number of constrained CG iterations, which can efficiently activate/deactivate multiple constraints * after CG phase algorithm tries to calculate Cholesky decomposition and to perform several constrained Newton steps. If Cholesky decomposition failed (matrix is indefinite even under constraints), we perform more CG iterations until we converge to such set of constraints that system matrix becomes positive definite. Constrained Newton steps greatly increase convergence speed and precision. * algorithm interleaves CG and Newton iterations which allows to handle indefinite matrices (CG phase) and quickly converge after final set of constraints is found (Newton phase). Combination of CG and Newton phases is called "outer iteration". * it is possible to turn off Newton phase (beneficial for semidefinite problems - Cholesky decomposition will fail too often) ALGORITHM LIMITATIONS: * algorithm does not support general linear constraints; only boundary ones are supported * Cholesky decomposition for sparse problems is performed with Skyline Cholesky solver, which is intended for low-profile matrices. No profile- reducing reordering of variables is performed in this version of ALGLIB. * problems with near-zero negative eigenvalues (or exacty zero ones) may experience about 2-3x performance penalty. The reason is that Cholesky decomposition can not be performed until we identify directions of zero and negative curvature and activate corresponding boundary constraints - but we need a lot of trial and errors because these directions are hard to notice in the matrix spectrum. In this case you may turn off Newton phase of algorithm. Large negative eigenvalues are not an issue, so highly non-convex problems can be solved very efficiently. INPUT PARAMETERS: State - structure which stores algorithm state EpsG - >=0 The subroutine finishes its work if the condition |v|<EpsG is satisfied, where: * |.| means Euclidian norm * v - scaled constrained gradient vector, v[i]=g[i]*s[i] * g - gradient * s - scaling coefficients set by MinQPSetScale() EpsF - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} EpsX - >=0 The subroutine finishes its work if exploratory steepest descent step on k+1-th iteration satisfies following condition: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - step vector, dx=X(k+1)-X(k) * s - scaling coefficients set by MinQPSetScale() MaxOuterIts-maximum number of OUTER iterations. One outer iteration includes some amount of CG iterations (from 5 to ~N) and one or several (usually small amount) Newton steps. Thus, one outer iteration has high cost, but can greatly reduce funcation value. UseNewton- use Newton phase or not: * Newton phase improves performance of positive definite dense problems (about 2 times improvement can be observed) * can result in some performance penalty on semidefinite or slightly negative definite problems - each Newton phase will bring no improvement (Cholesky failure), but still will require computational time. * if you doubt, you can turn off this phase - optimizer will retain its most of its high speed. IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (presently it is small step length, but it may change in the future versions of ALGLIB). -- ALGLIB -- Copyright 22.05.2014 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetalgoquickqp( minqpstate state, double epsg, double epsf, double epsx, ae_int_t maxouterits, bool usenewton);
/************************************************************************* This function sets boundary constraints for QP solver Boundary constraints are inactive by default (after initial creation). After being set, they are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[N]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[N]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetbc( minqpstate state, real_1d_array bndl, real_1d_array bndu);

Examples:   [1]  

/************************************************************************* This function sets linear constraints for QP optimizer. Linear constraints are inactive by default (after initial creation). INPUT PARAMETERS: State - structure previously allocated with MinQPCreate call. C - linear constraints, array[K,N+1]. Each row of C represents one constraint, either equality or inequality (see below): * first N elements correspond to coefficients, * last element corresponds to the right part. All elements of C (including right part) must be finite. CT - type of constraints, array[K]: * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] K - number of equality/inequality constraints, K>=0: * if given, only leading K elements of C/CT are used * if not given, automatically determined from sizes of C/CT NOTE 1: linear (non-bound) constraints are satisfied only approximately - there always exists some minor violation (about 10^-10...10^-13) due to numerical errors. -- ALGLIB -- Copyright 19.06.2012 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetlc( minqpstate state, real_2d_array c, integer_1d_array ct); void alglib::minqpsetlc( minqpstate state, real_2d_array c, integer_1d_array ct, ae_int_t k);

Examples:   [1]  

/************************************************************************* This function sets linear term for QP solver. By default, linear term is zero. INPUT PARAMETERS: State - structure which stores algorithm state B - linear term, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetlinearterm(minqpstate state, real_1d_array b);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function sets origin for QP solver. By default, following QP program is solved: min(0.5*x'*A*x+b'*x) This function allows to solve different problem: min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) INPUT PARAMETERS: State - structure which stores algorithm state XOrigin - origin, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetorigin(minqpstate state, real_1d_array xorigin);
/************************************************************************* This function sets dense quadratic term for QP solver. By default, quadratic term is zero. SUPPORT BY ALGLIB QP ALGORITHMS: Dense quadratic term can be handled by any of the QP algorithms supported by ALGLIB QP Solver. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetquadraticterm(minqpstate state, real_2d_array a); void alglib::minqpsetquadraticterm( minqpstate state, real_2d_array a, bool isupper);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This function sets sparse quadratic term for QP solver. By default, quadratic term is zero. IMPORTANT: This solver minimizes following function: f(x) = 0.5*x'*A*x + b'*x. Note that quadratic term has 0.5 before it. So if you want to minimize f(x) = x^2 + x you should rewrite your problem as follows: f(x) = 0.5*(2*x^2) + x and your matrix A will be equal to [[2.0]], not to [[1.0]] INPUT PARAMETERS: State - structure which stores algorithm state A - matrix, array[N,N] IsUpper - (optional) storage type: * if True, symmetric matrix A is given by its upper triangle, and the lower triangle isnt used * if False, symmetric matrix A is given by its lower triangle, and the upper triangle isnt used * if not given, both lower and upper triangles must be filled. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetquadratictermsparse( minqpstate state, sparsematrix a, bool isupper);

Examples:   [1]  

/************************************************************************* This function sets scaling coefficients. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function BLEIC-based QP solver uses scale for two purposes: * to evaluate stopping conditions * for preconditioning of the underlying BLEIC solver INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetscale(minqpstate state, real_1d_array s);
/************************************************************************* This function sets starting point for QP solver. It is useful to have good initial approximation to the solution, because it will increase speed of convergence and identification of active constraints. INPUT PARAMETERS: State - structure which stores algorithm state X - starting point, array[N]. -- ALGLIB -- Copyright 11.01.2011 by Bochkanov Sergey *************************************************************************/
void alglib::minqpsetstartingpoint(minqpstate state, real_1d_array x);

Examples:   [1]  [2]  [3]  [4]  [5]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1
    // subject to bound constraints 0<=x0<=2.5, 0<=x1<=2.5
    //
    // Exact solution is [x0,x1] = [2.5,2]
    //
    // We provide algorithm with starting point. With such small problem good starting
    // point is not really necessary, but with high-dimensional problem it can save us
    // a lot of time.
    //
    // IMPORTANT: this solver minimizes  following  function:
    //     f(x) = 0.5*x'*A*x + b'*x.
    // Note that quadratic term has 0.5 before it. So if you want to minimize
    // quadratic function, you should rewrite it in such way that quadratic term
    // is multiplied by 0.5 too.
    // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as 
    //     f(x) = 0.5*(2*x0^2+2*x1^2) + ....
    // and pass diag(2,2) as quadratic term - NOT diag(1,1)!
    //
    real_2d_array a = "[[2,0],[0,2]]";
    real_1d_array b = "[-6,-4]";
    real_1d_array x0 = "[0,1]";
    real_1d_array s = "[1,1]";
    real_1d_array bndl = "[0.0,0.0]";
    real_1d_array bndu = "[2.5,2.5]";
    real_1d_array x;
    minqpstate state;
    minqpreport rep;

    // create solver, set quadratic/linear terms
    minqpcreate(2, state);
    minqpsetquadraticterm(state, a);
    minqpsetlinearterm(state, b);
    minqpsetstartingpoint(state, x0);
    minqpsetbc(state, bndl, bndu);

    // Set scale of the parameters.
    // It is strongly recommended that you set scale of your variables.
    // Knowing their scales is essential for evaluation of stopping criteria
    // and for preconditioning of the algorithm steps.
    // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php
    minqpsetscale(state, s);

    // solve problem with QuickQP solver, default stopping criteria are used
    minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [2.5,2]

    // solve problem with BLEIC-based QP solver
    // default stopping criteria are used.
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [2.5,2]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1
    // subject to linear constraint x0+x1<=2
    //
    // Exact solution is [x0,x1] = [1.5,0.5]
    //
    // IMPORTANT: this solver minimizes  following  function:
    //     f(x) = 0.5*x'*A*x + b'*x.
    // Note that quadratic term has 0.5 before it. So if you want to minimize
    // quadratic function, you should rewrite it in such way that quadratic term
    // is multiplied by 0.5 too.
    // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as 
    //     f(x) = 0.5*(2*x0^2+2*x1^2) + ....
    // and pass diag(2,2) as quadratic term - NOT diag(1,1)!
    //
    real_2d_array a = "[[2,0],[0,2]]";
    real_1d_array b = "[-6,-4]";
    real_1d_array s = "[1,1]";
    real_2d_array c = "[[1.0,1.0,2.0]]";
    integer_1d_array ct = "[-1]";
    real_1d_array x;
    minqpstate state;
    minqpreport rep;

    // create solver, set quadratic/linear terms
    minqpcreate(2, state);
    minqpsetquadraticterm(state, a);
    minqpsetlinearterm(state, b);
    minqpsetlc(state, c, ct);

    // Set scale of the parameters.
    // It is strongly recommended that you set scale of your variables.
    // Knowing their scales is essential for evaluation of stopping criteria
    // and for preconditioning of the algorithm steps.
    // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php
    minqpsetscale(state, s);

    // solve problem with BLEIC-based QP solver
    // default stopping criteria are used.
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%s\n", x.tostring(1).c_str()); // EXPECTED: [1.500,0.500]

    // solve problem with QuickQP solver, default stopping criteria are used
    // Oops! It does not support general linear constraints, -5 returned as completion code!
    minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: -5
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of nonconvex function
    //     F(x0,x1) = -(x0^2+x1^2)
    // subject to constraints x0,x1 in [1.0,2.0]
    // Exact solution is [x0,x1] = [2,2].
    //
    // IMPORTANT: this solver minimizes  following  function:
    //     f(x) = 0.5*x'*A*x + b'*x.
    // Note that quadratic term has 0.5 before it. So if you want to minimize
    // quadratic function, you should rewrite it in such way that quadratic term
    // is multiplied by 0.5 too.
    //
    // For example, our function is f(x)=-(x0^2+x1^2), but we rewrite it as 
    //     f(x) = 0.5*(-2*x0^2-2*x1^2)
    // and pass diag(-2,-2) as quadratic term - NOT diag(-1,-1)!
    //
    real_2d_array a = "[[-2,0],[0,-2]]";
    real_1d_array x0 = "[1,1]";
    real_1d_array s = "[1,1]";
    real_1d_array bndl = "[1.0,1.0]";
    real_1d_array bndu = "[2.0,2.0]";
    real_1d_array x;
    minqpstate state;
    minqpreport rep;

    // create solver, set quadratic/linear terms, constraints
    minqpcreate(2, state);
    minqpsetquadraticterm(state, a);
    minqpsetstartingpoint(state, x0);
    minqpsetbc(state, bndl, bndu);

    // Set scale of the parameters.
    // It is strongly recommended that you set scale of your variables.
    // Knowing their scales is essential for evaluation of stopping criteria
    // and for preconditioning of the algorithm steps.
    // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php
    minqpsetscale(state, s);

    // solve problem with BLEIC-QP solver.
    // default stopping criteria are used.
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [2,2]

    // Hmm... this problem is bounded from below (has solution) only under constraints.
    // What it we remove them?
    //
    // You may see that algorithm detects unboundedness of the problem, 
    // -4 is returned as completion code.
    real_1d_array nobndl = "[-inf,-inf]";
    real_1d_array nobndu = "[+inf,+inf]";
    minqpsetbc(state, nobndl, nobndu);
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: -4
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1
    //
    // Exact solution is [x0,x1] = [3,2]
    //
    // We provide algorithm with starting point, although in this case
    // (dense matrix, no constraints) it can work without such information.
    //
    // IMPORTANT: this solver minimizes  following  function:
    //     f(x) = 0.5*x'*A*x + b'*x.
    // Note that quadratic term has 0.5 before it. So if you want to minimize
    // quadratic function, you should rewrite it in such way that quadratic term
    // is multiplied by 0.5 too.
    //
    // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as 
    //     f(x) = 0.5*(2*x0^2+2*x1^2) + ....
    // and pass diag(2,2) as quadratic term - NOT diag(1,1)!
    //
    real_2d_array a = "[[2,0],[0,2]]";
    real_1d_array b = "[-6,-4]";
    real_1d_array x0 = "[0,1]";
    real_1d_array s = "[1,1]";
    real_1d_array x;
    minqpstate state;
    minqpreport rep;

    // create solver, set quadratic/linear terms
    minqpcreate(2, state);
    minqpsetquadraticterm(state, a);
    minqpsetlinearterm(state, b);
    minqpsetstartingpoint(state, x0);

    // Set scale of the parameters.
    // It is strongly recommended that you set scale of your variables.
    // Knowing their scales is essential for evaluation of stopping criteria
    // and for preconditioning of the algorithm steps.
    // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php
    minqpsetscale(state, s);

    // solve problem with QuickQP solver, default stopping criteria are used, Newton phase is active
    minqpsetalgoquickqp(state, 0.0, 0.0, 0.0, 0, true);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 4
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [3,2]

    // solve problem with BLEIC-based QP solver.
    // default stopping criteria are used.
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [3,2]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "optimization.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates minimization of F(x0,x1) = x0^2 + x1^2 -6*x0 - 4*x1,
    // with quadratic term given by sparse matrix structure.
    //
    // Exact solution is [x0,x1] = [3,2]
    //
    // We provide algorithm with starting point, although in this case
    // (dense matrix, no constraints) it can work without such information.
    //
    // IMPORTANT: this solver minimizes  following  function:
    //     f(x) = 0.5*x'*A*x + b'*x.
    // Note that quadratic term has 0.5 before it. So if you want to minimize
    // quadratic function, you should rewrite it in such way that quadratic term
    // is multiplied by 0.5 too.
    //
    // For example, our function is f(x)=x0^2+x1^2+..., but we rewrite it as 
    //     f(x) = 0.5*(2*x0^2+2*x1^2) + ....
    // and pass diag(2,2) as quadratic term - NOT diag(1,1)!
    //
    sparsematrix a;
    real_1d_array b = "[-6,-4]";
    real_1d_array x0 = "[0,1]";
    real_1d_array s = "[1,1]";
    real_1d_array x;
    minqpstate state;
    minqpreport rep;

    // initialize sparsematrix structure
    sparsecreate(2, 2, 0, a);
    sparseset(a, 0, 0, 2.0);
    sparseset(a, 1, 1, 2.0);

    // create solver, set quadratic/linear terms
    minqpcreate(2, state);
    minqpsetquadratictermsparse(state, a, true);
    minqpsetlinearterm(state, b);
    minqpsetstartingpoint(state, x0);

    // Set scale of the parameters.
    // It is strongly recommended that you set scale of your variables.
    // Knowing their scales is essential for evaluation of stopping criteria
    // and for preconditioning of the algorithm steps.
    // You can find more information on scaling at http://www.alglib.net/optimization/scaling.php
    minqpsetscale(state, s);

    // solve problem with BLEIC-based QP solver.
    // default stopping criteria are used.
    minqpsetalgobleic(state, 0.0, 0.0, 0.0, 0);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%s\n", x.tostring(2).c_str()); // EXPECTED: [3,2]

    // try to solve problem with Cholesky-based QP solver...
    // Oops! It does not support sparse matrices, -5 returned as completion code!
    minqpsetalgocholesky(state);
    minqpoptimize(state);
    minqpresults(state, x, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: -5
    return 0;
}


/************************************************************************* Model's errors: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/
class modelerrors { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; };
/************************************************************************* *************************************************************************/
class multilayerperceptron { };
/************************************************************************* Neural network activation function INPUT PARAMETERS: NET - neuron input K - function index (zero for linear function) OUTPUT PARAMETERS: F - function DF - its derivative D2F - its second derivative -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpactivationfunction( double net, ae_int_t k, double& f, double& df, double& d2f);
/************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset given by sparse matrix; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpallerrorssparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize, modelerrors& rep); void alglib::smp_mlpallerrorssparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize, modelerrors& rep);
/************************************************************************* Calculation of all types of errors on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. OUTPUT PARAMETERS: Rep - it contains all type of errors. -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpallerrorssubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize, modelerrors& rep); void alglib::smp_mlpallerrorssubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize, modelerrors& rep);
/************************************************************************* Average cross-entropy (in bits per element) on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 08.01.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgce( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlpavgce( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average cross-entropy (in bits per element) on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: CrossEntropy/(NPoints*LN(2)). Zero if network solves regression task. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 9.08.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgcesparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlpavgcesparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* Average absolute error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgerror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlpavgerror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average absolute error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgerrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlpavgerrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* Average relative error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 11.03.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgrelerror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlpavgrelerror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average relative error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Its meaning for regression task is obvious. As for classification task, it means average relative error when estimating posterior probability of belonging to the correct class. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlpavgrelerrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlpavgrelerrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* Classification error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: classification error (number of misclassified cases) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpclserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); ae_int_t alglib::smp_mlpclserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Copying of neural network INPUT PARAMETERS: Network1 - original OUTPUT PARAMETERS: Network2 - copy -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcopy( multilayerperceptron network1, multilayerperceptron& network2);
/************************************************************************* This function copies tunable parameters (weights/means/sigmas) from one network to another with same architecture. It performs some rudimentary checks that architectures are same, and throws exception if check fails. It is intended for fast copying of states between two network which are known to have same geometry. INPUT PARAMETERS: Network1 - source, must be correctly initialized Network2 - target, must have same architecture OUTPUT PARAMETERS: Network2 - network state is copied from source to target -- ALGLIB -- Copyright 20.06.2013 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcopytunableparameters( multilayerperceptron network1, multilayerperceptron network2);
/************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers, with linear output layer. Network weights are filled with small random values. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreate0( ae_int_t nin, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Same as MLPCreate0, but with one hidden layer (NHid neurons) with non-linear activation function. Output layer is linear. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreate1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) with non-linear activation function. Output layer is linear. $ALL -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreate2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values: (B, +INF), if D>=0 or (-INF, B), if D<0. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreateb0( ae_int_t nin, ae_int_t nout, double b, double d, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateB0 but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreateb1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateB0 but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreateb2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, multilayerperceptron& network);
/************************************************************************* Creates classifier network with NIn inputs and NOut possible classes. Network contains no hidden layers and linear output layer with SOFTMAX- normalization (so outputs sums up to 1.0 and converge to posterior probabilities). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreatec0( ae_int_t nin, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateC0, but with one non-linear hidden layer. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreatec1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateC0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreatec2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, multilayerperceptron& network);
/************************************************************************* Creates neural network with NIn inputs, NOut outputs, without hidden layers with non-linear output layer. Network weights are filled with small random values. Activation function of the output layer takes values [A,B]. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreater0( ae_int_t nin, ae_int_t nout, double a, double b, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateR0, but with non-linear hidden layer. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreater1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, multilayerperceptron& network);
/************************************************************************* Same as MLPCreateR0, but with two non-linear hidden layers. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreater2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, multilayerperceptron& network);
/************************************************************************* Error of the neural network on dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
double alglib::mlperror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlperror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Natural error function for neural network, internal subroutine. NOTE: this function is single-threaded. Unlike other error function, it receives no speed-up from being executed in SMP mode. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
double alglib::mlperrorn( multilayerperceptron network, real_2d_array xy, ae_int_t ssize);
/************************************************************************* Error of the neural network on dataset given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x, depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0 RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlperrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlperrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* Error of the neural network on subset of sparse dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. SetSize - real size of XY, SetSize>=0; it is used when SubsetSize<0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlperrorsparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize); double alglib::smp_mlperrorsparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize);
/************************************************************************* Error of the neural network on subset of dataset. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; SetSize - real size of XY, SetSize>=0; Subset - subset of SubsetSize elements, array[SubsetSize]; SubsetSize- number of elements in Subset[] array: * if SubsetSize>0, rows of XY with indices Subset[0]... ...Subset[SubsetSize-1] are processed * if SubsetSize=0, zeros are returned * if SubsetSize<0, entire dataset is processed; Subset[] array is ignored in this case. RESULT: sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.09.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlperrorsubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize); double alglib::smp_mlperrorsubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array subset, ae_int_t subsetsize);
/************************************************************************* This function returns offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgetinputscaling( multilayerperceptron network, ae_int_t i, double& mean, double& sigma);
/************************************************************************* Returns number of inputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpgetinputscount(multilayerperceptron network);
/************************************************************************* This function returns total number of layers (including input, hidden and output layers). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpgetlayerscount(multilayerperceptron network);
/************************************************************************* This function returns size of K-th layer. K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. Size of the output layer is always equal to the number of outputs, although when we have softmax-normalized network, last neuron doesn't have any connections - it is just zero. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpgetlayersize( multilayerperceptron network, ae_int_t k);
/************************************************************************* This function returns information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) OUTPUT PARAMETERS: FKind - activation function type (used by MLPActivationFunction()) this value is zero for input or linear neurons Threshold - also called offset, bias zero for input neurons NOTE: this function throws exception if layer or neuron with given index do not exists. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgetneuroninfo( multilayerperceptron network, ae_int_t k, ae_int_t i, ae_int_t& fkind, double& threshold);
/************************************************************************* This function returns offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index OUTPUT PARAMETERS: Mean - mean term Sigma - sigma term, guaranteed to be nonzero. I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. In case we have SOFTMAX-normalized network, we return (Mean,Sigma)=(0.0,1.0). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgetoutputscaling( multilayerperceptron network, ae_int_t i, double& mean, double& sigma);
/************************************************************************* Returns number of outputs. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpgetoutputscount(multilayerperceptron network);
/************************************************************************* This function returns information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) RESULT: connection weight (zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. returns zero if neurons exist, but there is no connection between them -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
double alglib::mlpgetweight( multilayerperceptron network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1);
/************************************************************************* Returns number of weights. -- ALGLIB -- Copyright 19.10.2011 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::mlpgetweightscount(multilayerperceptron network);
/************************************************************************* Gradient calculation INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgrad( multilayerperceptron network, real_1d_array x, real_1d_array desiredy, double& e, real_1d_array& grad);
/************************************************************************* Batch gradient calculation for a set of inputs/outputs FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradbatch( multilayerperceptron network, real_2d_array xy, ae_int_t ssize, double& e, real_1d_array& grad); void alglib::smp_mlpgradbatch( multilayerperceptron network, real_2d_array xy, ae_int_t ssize, double& e, real_1d_array& grad);
/************************************************************************* Batch gradient calculation for a set of inputs/outputs given by sparse matrices FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs. * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradbatchsparse( multilayerperceptron network, sparsematrix xy, ae_int_t ssize, double& e, real_1d_array& grad); void alglib::smp_mlpgradbatchsparse( multilayerperceptron network, sparsematrix xy, ae_int_t ssize, double& e, real_1d_array& grad);
/************************************************************************* Batch gradient calculation for a set of inputs/outputs for a subset of dataset given by set of indexes. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in sparse format; one sample = one row: * MATRIX MUST BE STORED IN CRS FORMAT * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse function. -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradbatchsparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array idx, ae_int_t subsetsize, double& e, real_1d_array& grad); void alglib::smp_mlpgradbatchsparsesubset( multilayerperceptron network, sparsematrix xy, ae_int_t setsize, integer_1d_array idx, ae_int_t subsetsize, double& e, real_1d_array& grad);
/************************************************************************* Batch gradient calculation for a subset of dataset FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - original dataset in dense format; one sample = one row: * first NIn columns contain inputs, * for regression problem, next NOut columns store desired outputs. * for classification problem, next column (just one!) stores class number. SetSize - real size of XY, SetSize>=0; Idx - subset of SubsetSize elements, array[SubsetSize]: * Idx[I] stores row index in the original dataset which is given by XY. Gradient is calculated with respect to rows whose indexes are stored in Idx[]. * Idx[] must store correct indexes; this function throws an exception in case incorrect index (less than 0 or larger than rows(XY)) is given * Idx[] may store indexes in any order and even with repetitions. SubsetSize- number of elements in Idx[] array: * positive value means that subset given by Idx[] is processed * zero value results in zero gradient * negative value means that full dataset is processed Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 26.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradbatchsubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array idx, ae_int_t subsetsize, double& e, real_1d_array& grad); void alglib::smp_mlpgradbatchsubset( multilayerperceptron network, real_2d_array xy, ae_int_t setsize, integer_1d_array idx, ae_int_t subsetsize, double& e, real_1d_array& grad);
/************************************************************************* Gradient calculation (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs X - input vector, length of array must be at least NIn DesiredY- desired outputs, length of array must be at least NOut Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradn( multilayerperceptron network, real_1d_array x, real_1d_array desiredy, double& e, real_1d_array& grad);
/************************************************************************* Batch gradient calculation for a set of inputs/outputs (natural error function is used) INPUT PARAMETERS: Network - network initialized with one of the network creation funcs XY - set of inputs/outputs; one sample = one row; first NIn columns contain inputs, next NOut columns - desired outputs. SSize - number of elements in XY Grad - possibly preallocated array. If size of array is smaller than WCount, it will be reallocated. It is recommended to reuse previously allocated array to reduce allocation overhead. OUTPUT PARAMETERS: E - error function, sum-of-squares for regression networks, cross-entropy for classification networks. Grad - gradient of E with respect to weights of network, array[WCount] -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpgradnbatch( multilayerperceptron network, real_2d_array xy, ae_int_t ssize, double& e, real_1d_array& grad);
/************************************************************************* Batch Hessian calculation using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/
void alglib::mlphessianbatch( multilayerperceptron network, real_2d_array xy, ae_int_t ssize, double& e, real_1d_array& grad, real_2d_array& h);
/************************************************************************* Batch Hessian calculation (natural error function) using R-algorithm. Internal subroutine. -- ALGLIB -- Copyright 26.01.2008 by Bochkanov Sergey. Hessian calculation based on R-algorithm described in "Fast Exact Multiplication by the Hessian", B. A. Pearlmutter, Neural Computation, 1994. *************************************************************************/
void alglib::mlphessiannbatch( multilayerperceptron network, real_2d_array xy, ae_int_t ssize, double& e, real_1d_array& grad, real_2d_array& h);
/************************************************************************* Internal subroutine. -- ALGLIB -- Copyright 30.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlpinitpreprocessor( multilayerperceptron network, real_2d_array xy, ae_int_t ssize);
/************************************************************************* Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
bool alglib::mlpissoftmax(multilayerperceptron network);
/************************************************************************* Procesing INPUT PARAMETERS: Network - neural network X - input vector, array[0..NIn-1]. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. See also MLPProcessI -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpprocess( multilayerperceptron network, real_1d_array x, real_1d_array& y);
/************************************************************************* 'interactive' variant of MLPProcess for languages like Python which support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 21.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::mlpprocessi( multilayerperceptron network, real_1d_array x, real_1d_array& y);
/************************************************************************* Returns information about initialized network: number of inputs, outputs, weights. -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpproperties( multilayerperceptron network, ae_int_t& nin, ae_int_t& nout, ae_int_t& wcount);
/************************************************************************* Randomization of neural network weights -- ALGLIB -- Copyright 06.11.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlprandomize(multilayerperceptron network);
/************************************************************************* Randomization of neural network weights and standartisator -- ALGLIB -- Copyright 10.03.2008 by Bochkanov Sergey *************************************************************************/
void alglib::mlprandomizefull(multilayerperceptron network);
/************************************************************************* Relative classification error on the test set. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 25.12.2008 by Bochkanov Sergey *************************************************************************/
double alglib::mlprelclserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlprelclserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Relative classification error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Percent of incorrectly classified cases. Works both for classifier networks and general purpose networks used as classifiers. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlprelclserrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlprelclserrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set given. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format; NPoints - points count. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 04.11.2007 by Bochkanov Sergey *************************************************************************/
double alglib::mlprmserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints); double alglib::smp_mlprmserror( multilayerperceptron network, real_2d_array xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set given by sparse matrix. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support ! ! First improvement gives close-to-linear speedup on multicore systems. ! Second improvement gives constant speedup (2-3x depending on your CPU) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: Network - neural network; XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Sparse matrix must use CRS format for storage. NPoints - points count, >=0. RESULT: Root mean square error. Its meaning for regression task is obvious. As for classification task, RMS error means error when estimating posterior probabilities. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following dataset format is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 09.08.2012 by Bochkanov Sergey *************************************************************************/
double alglib::mlprmserrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints); double alglib::smp_mlprmserrorsparse( multilayerperceptron network, sparsematrix xy, ae_int_t npoints);
/************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/
void mlpserialize(multilayerperceptron &obj, std::string &s_out);
/************************************************************************* This function sets offset/scaling coefficients for I-th input of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) NTE: I-th input is passed through linear transformation IN[i] = (IN[i]-Mean)/Sigma before feeding to the network. This function sets Mean and Sigma. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetinputscaling( multilayerperceptron network, ae_int_t i, double mean, double sigma);
/************************************************************************* This function modifies information about Ith neuron of Kth layer INPUT PARAMETERS: Network - network K - layer index I - neuron index (within layer) FKind - activation function type (used by MLPActivationFunction()) this value must be zero for input neurons (you can not set activation function for input neurons) Threshold - also called offset, bias this value must be zero for input neurons (you can not set threshold for input neurons) NOTES: 1. this function throws exception if layer or neuron with given index do not exists. 2. this function also throws exception when you try to set non-linear activation function for input neurons (any kind of network) or for output neurons of classifier network. 3. this function throws exception when you try to set non-zero threshold for input neurons (any kind of network). -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetneuroninfo( multilayerperceptron network, ae_int_t k, ae_int_t i, ae_int_t fkind, double threshold);
/************************************************************************* This function sets offset/scaling coefficients for I-th output of the network. INPUT PARAMETERS: Network - network I - input index Mean - mean term Sigma - sigma term (if zero, will be replaced by 1.0) OUTPUT PARAMETERS: NOTE: I-th output is passed through linear transformation OUT[i] = OUT[i]*Sigma+Mean before returning it to user. This function sets Sigma/Mean. In case we have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything other than(0.0,1.0) - this function will throw exception. -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetoutputscaling( multilayerperceptron network, ae_int_t i, double mean, double sigma);
/************************************************************************* This function modifies information about connection from I0-th neuron of K0-th layer to I1-th neuron of K1-th layer. INPUT PARAMETERS: Network - network K0 - layer index I0 - neuron index (within layer) K1 - layer index I1 - neuron index (within layer) W - connection weight (must be zero for non-existent connections) This function: 1. throws exception if layer or neuron with given index do not exists. 2. throws exception if you try to set non-zero weight for non-existent connection -- ALGLIB -- Copyright 25.03.2011 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetweight( multilayerperceptron network, ae_int_t k0, ae_int_t i0, ae_int_t k1, ae_int_t i1, double w);
/************************************************************************* This function unserializes data structure from string. *************************************************************************/
void mlpunserialize(std::string &s_in, multilayerperceptron &obj);
/************************************************************************* Neural networks ensemble *************************************************************************/
class mlpensemble { };
/************************************************************************* Average cross-entropy (in bits per element) on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: CrossEntropy/(NPoints*LN(2)). Zero if ensemble solves regression task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlpeavgce( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlpeavgerror( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Average relative error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: Its meaning for regression task is obvious. As for classification task it means average relative error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlpeavgrelerror( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints);
/************************************************************************* Like MLPCreate0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreate0( ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreate1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreate1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreate2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreate2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateB0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreateb0( ae_int_t nin, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateB1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreateb1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateB2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreateb2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double b, double d, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateC0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreatec0( ae_int_t nin, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateC1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreatec1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateC2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreatec2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Creates ensemble from network. Only network geometry is copied. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreatefromnetwork( multilayerperceptron network, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateR0, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreater0( ae_int_t nin, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateR1, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreater1( ae_int_t nin, ae_int_t nhid, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Like MLPCreateR2, but for ensembles. -- ALGLIB -- Copyright 18.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpecreater2( ae_int_t nin, ae_int_t nhid1, ae_int_t nhid2, ae_int_t nout, double a, double b, ae_int_t ensemblesize, mlpensemble& ensemble);
/************************************************************************* Return normalization type (whether ensemble is SOFTMAX-normalized or not). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
bool alglib::mlpeissoftmax(mlpensemble ensemble);
/************************************************************************* Procesing INPUT PARAMETERS: Ensemble- neural networks ensemble X - input vector, array[0..NIn-1]. Y - (possibly) preallocated buffer; if size of Y is less than NOut, it will be reallocated. If it is large enough, it is NOT reallocated, so we can save some time on reallocation. OUTPUT PARAMETERS: Y - result. Regression estimate when solving regression task, vector of posterior probabilities for classification task. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpeprocess( mlpensemble ensemble, real_1d_array x, real_1d_array& y);
/************************************************************************* 'interactive' variant of MLPEProcess for languages like Python which support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the interpreter This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpeprocessi( mlpensemble ensemble, real_1d_array x, real_1d_array& y);
/************************************************************************* Return ensemble properties (number of inputs and outputs). -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpeproperties( mlpensemble ensemble, ae_int_t& nin, ae_int_t& nout);
/************************************************************************* Randomization of MLP ensemble -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlperandomize(mlpensemble ensemble);
/************************************************************************* Relative classification error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: percent of incorrectly classified cases. Works both for classifier betwork and for regression networks which are used as classifiers. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlperelclserror( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints);
/************************************************************************* RMS error on the test set INPUT PARAMETERS: Ensemble- ensemble XY - test set NPoints - test set size RESULT: root mean square error. Its meaning for regression task is obvious. As for classification task RMS error means error when estimating posterior probabilities. -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
double alglib::mlpermserror( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints);
/************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/
void mlpeserialize(mlpensemble &obj, std::string &s_out);
/************************************************************************* This function unserializes data structure from string. *************************************************************************/
void mlpeunserialize(std::string &s_in, mlpensemble &obj);
mlpcvreport
mlpreport
mlptrainer
mlpcontinuetraining
mlpcreatetrainer
mlpcreatetrainercls
mlpebagginglbfgs
mlpebagginglm
mlpetraines
mlpkfoldcv
mlpkfoldcvlbfgs
mlpkfoldcvlm
mlpsetalgobatch
mlpsetcond
mlpsetdataset
mlpsetdecay
mlpsetsparsedataset
mlpstarttraining
mlptrainensemblees
mlptraines
mlptrainlbfgs
mlptrainlm
mlptrainnetwork
nn_cls2 Binary classification problem
nn_cls3 Multiclass classification problem
nn_crossvalidation Cross-validation
nn_ensembles_es Early stopping ensembles
nn_parallel Parallel training
nn_regr Regression problem with one output (2=>1)
nn_regr_n Regression problem with multiple outputs (2=>2)
nn_trainerobject Advanced example on trainer object
/************************************************************************* Cross-validation estimates of generalization error *************************************************************************/
class mlpcvreport { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; };
/************************************************************************* Training report: * RelCLSError - fraction of misclassified cases. * AvgCE - acerage cross-entropy * RMSError - root-mean-square error * AvgError - average error * AvgRelError - average relative error * NGrad - number of gradient calculations * NHess - number of Hessian calculations * NCholesky - number of Cholesky decompositions NOTE 1: RelCLSError/AvgCE are zero on regression problems. NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain errors in prediction of posterior probabilities *************************************************************************/
class mlpreport { double relclserror; double avgce; double rmserror; double avgerror; double avgrelerror; ae_int_t ngrad; ae_int_t nhess; ae_int_t ncholesky; };
/************************************************************************* Trainer object for neural network. You should not try to access fields of this object directly - use ALGLIB functions to work with this object. *************************************************************************/
class mlptrainer { };
/************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. This function performs one more iteration of the training and returns either True (training continues) or False (training stopped). In case True was returned, Network weights are updated according to the current state of the optimization progress. In case False was returned, no additional updates is performed (previous update of the network weights moved us to the final point, and no additional updates is needed). EXAMPLE: > > [initialize network and trainer object] > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > [visualize training progress] > INPUT PARAMETERS: S - trainer object Network - neural network structure, which is used to store current state of the training process. OUTPUT PARAMETERS: Network - weights of the neural network are rewritten by the current approximation. NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. NOTE: It is expected that Network is the same one which was passed to MLPStartTraining() function. However, THIS function checks only following: * that number of network inputs is consistent with trainer object settings * that number of network outputs/classes is consistent with trainer object settings * that number of network weights is the same as number of weights in the network passed to MLPStartTraining() function Exception is thrown when these conditions are violated. It is also expected that you do not change state of the network on your own - the only party who has right to change network during its training is a trainer object. Any attempt to interfere with trainer may lead to unpredictable results. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::mlpcontinuetraining( mlptrainer s, multilayerperceptron network); bool alglib::smp_mlpcontinuetraining( mlptrainer s, multilayerperceptron network);
/************************************************************************* Creation of the network trainer object for regression networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NOut - number of outputs, NOut>=1 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any regression network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreatetrainer(ae_int_t nin, ae_int_t nout, mlptrainer& s);

Examples:   [1]  [2]  [3]  [4]  [5]  [6]  

/************************************************************************* Creation of the network trainer object for classification networks INPUT PARAMETERS: NIn - number of inputs, NIn>=1 NClasses - number of classes, NClasses>=2 OUTPUT PARAMETERS: S - neural network trainer object. This structure can be used to train any classification network with NIn inputs and NOut outputs. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpcreatetrainercls( ae_int_t nin, ae_int_t nclasses, mlptrainer& s);

Examples:   [1]  [2]  

/************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). L-BFGS algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpebagginglbfgs( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t& info, mlpreport& rep, mlpcvreport& ooberrors);
/************************************************************************* Training neural networks ensemble using bootstrap aggregating (bagging). Modified Levenberg-Marquardt algorithm is used as base training method. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 17.02.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpebagginglm( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t& info, mlpreport& rep, mlpcvreport& ooberrors);
/************************************************************************* Training neural networks ensemble using early stopping. INPUT PARAMETERS: Ensemble - model with initialized geometry XY - training set NPoints - training set size Decay - weight decay coefficient, >=0.001 Restarts - restarts, >0. OUTPUT PARAMETERS: Ensemble - trained model Info - return code: * -2, if there is a point with class number outside of [0..NClasses-1]. * -1, if incorrect parameters was passed (NPoints<0, Restarts<1). * 6, if task has been solved. Rep - training report. OOBErrors - out-of-bag generalization error estimate -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlpetraines( mlpensemble ensemble, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t& info, mlpreport& rep);
/************************************************************************* This function estimates generalization error using cross-validation on the current dataset with current training settings. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * FoldsCount cross-validation rounds (always) ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. Network is not changed during cross- validation and is not trained - it is used only as representative of its architecture. I.e., we estimate generalization properties of ARCHITECTURE, not some specific network. NRestarts - number of restarts, >=0: * NRestarts>0 means that for each cross-validation round specified number of random restarts is performed, with best network being chosen after training. * NRestarts=0 is same as NRestarts=1 FoldsCount - number of folds in k-fold cross-validation: * 2<=FoldsCount<=size of dataset * recommended value: 10. * values larger than dataset size will be silently truncated down to dataset size OUTPUT PARAMETERS: Rep - structure which contains cross-validation estimates: * Rep.RelCLSError - fraction of misclassified cases. * Rep.AvgCE - acerage cross-entropy * Rep.RMSError - root-mean-square error * Rep.AvgError - average error * Rep.AvgRelError - average relative error NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or subset with only one point was given, zeros are returned as estimates. NOTE: this method performs FoldsCount cross-validation rounds, each one with NRestarts random starts. Thus, FoldsCount*NRestarts networks are trained in total. NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError contain errors in prediction of posterior probabilities. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpkfoldcv( mlptrainer s, multilayerperceptron network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport& rep); void alglib::smp_mlpkfoldcv( mlptrainer s, multilayerperceptron network, ae_int_t nrestarts, ae_int_t foldscount, mlpreport& rep);

Examples:   [1]  [2]  

/************************************************************************* Cross-validation estimate of generalization error. Base algorithm - L-BFGS. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. WStep - stopping criterion, same as in MLPTrainLBFGS MaxIts - stopping criterion, same as in MLPTrainLBFGS FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpkfoldcvlbfgs( multilayerperceptron network, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t foldscount, ae_int_t& info, mlpreport& rep, mlpcvreport& cvrep);
/************************************************************************* Cross-validation estimate of generalization error. Base algorithm - Levenberg-Marquardt. INPUT PARAMETERS: Network - neural network with initialized geometry. Network is not changed during cross-validation - it is used only as a representative of its architecture. XY - training set. SSize - training set size Decay - weight decay, same as in MLPTrainLBFGS Restarts - number of restarts, >0. restarts are counted for each partition separately, so total number of restarts will be Restarts*FoldsCount. FoldsCount - number of folds in k-fold cross-validation, 2<=FoldsCount<=SSize. recommended value: 10. OUTPUT PARAMETERS: Info - return code, same as in MLPTrainLBFGS Rep - report, same as in MLPTrainLM/MLPTrainLBFGS CVRep - generalization error estimates -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlpkfoldcvlm( multilayerperceptron network, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t foldscount, ae_int_t& info, mlpreport& rep, mlpcvreport& cvrep);
/************************************************************************* This function sets training algorithm: batch training using L-BFGS will be used. This algorithm: * the most robust for small-scale problems, but may be too slow for large scale ones. * perfoms full pass through the dataset before performing step * uses conditions specified by MLPSetCond() for stopping * is default one used by trainer object INPUT PARAMETERS: S - trainer object -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetalgobatch(mlptrainer s);
/************************************************************************* This function sets stopping criteria for the optimizer. INPUT PARAMETERS: S - trainer object WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. WStep>=0. MaxIts - stopping criterion. Algorithm stops after MaxIts epochs (full passes over entire dataset). Zero MaxIts means stopping when step is sufficiently small. MaxIts>=0. NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also used when MLPSetCond() is called with WStep=0 and MaxIts=0. NOTE: these stopping criteria are used for all kinds of neural training - from "conventional" networks to early stopping ensembles. When used for "conventional" networks, they are used as the only stopping criteria. When combined with early stopping, they used as ADDITIONAL stopping criteria which can terminate early stopping algorithm. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetcond(mlptrainer s, double wstep, ae_int_t maxits);
/************************************************************************* This function sets "current dataset" of the trainer object to one passed by user. INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. NPoints - points count, >=0. DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetdataset( mlptrainer s, real_2d_array xy, ae_int_t npoints);

Examples:   [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  

/************************************************************************* This function sets weight decay coefficient which is used for training. INPUT PARAMETERS: S - trainer object Decay - weight decay coefficient, >=0. Weight decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 1.0E-3. Weight decay can be set to zero, in this case network is trained without weight decay. NOTE: by default network uses some small nonzero value for weight decay. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetdecay(mlptrainer s, double decay);
/************************************************************************* This function sets "current dataset" of the trainer object to one passed by user (sparse matrix is used to store dataset). INPUT PARAMETERS: S - trainer object XY - training set, see below for information on the training set format. This function checks correctness of the dataset (no NANs/INFs, class numbers are correct) and throws exception when incorrect dataset is passed. Any sparse storage format can be used: Hash-table, CRS... NPoints - points count, >=0 DATASET FORMAT: This function uses two different dataset formats - one for regression networks, another one for classification networks. For regression networks with NIn inputs and NOut outputs following dataset format is used: * dataset is given by NPoints*(NIn+NOut) matrix * each row corresponds to one example * first NIn columns are inputs, next NOut columns are outputs For classification networks with NIn inputs and NClasses clases following datasetformat is used: * dataset is given by NPoints*(NIn+1) matrix * each row corresponds to one example * first NIn columns are inputs, last column stores class number (from 0 to NClasses-1). -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpsetsparsedataset( mlptrainer s, sparsematrix xy, ae_int_t npoints);
/************************************************************************* IMPORTANT: this is an "expert" version of the MLPTrain() function. We do not recommend you to use it unless you are pretty sure that you need ability to monitor training progress. This function performs step-by-step training of the neural network. Here "step-by-step" means that training starts with MLPStartTraining() call, and then user subsequently calls MLPContinueTraining() to perform one more iteration of the training. After call to this function trainer object remembers network and is ready to train it. However, no training is performed until first call to MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() will advance training progress one iteration further. EXAMPLE: > > ...initialize network and trainer object.... > > MLPStartTraining(Trainer, Network, True) > while MLPContinueTraining(Trainer, Network) do > ...visualize training progress... > INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. RandomStart - randomize network before training or not: * True means that network is randomized and its initial state (one which was passed to the trainer object) is lost. * False means that training is started from the current state of the network OUTPUT PARAMETERS: Network - neural network which is ready to training (weights are initialized, preprocessor is initialized using current training set) NOTE: this method uses sum-of-squares error function for training. NOTE: it is expected that trainer object settings are NOT changed during step-by-step training, i.e. no one changes stopping criteria or training set during training. It is possible and there is no defense against such actions, but algorithm behavior in such cases is undefined and can be unpredictable. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlpstarttraining( mlptrainer s, multilayerperceptron network, bool randomstart);
/************************************************************************* This function trains neural network ensemble passed to this function using current dataset and early stopping training algorithm. Each early stopping round performs NRestarts random restarts (thus, EnsembleSize*NRestarts training rounds is performed in total). FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * EnsembleSize training sessions performed for each of ensemble ! members (always parallelized) ! * NRestarts training sessions performed within each of training ! sessions (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object; Ensemble - neural network ensemble. It must have same number of inputs and outputs/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed during each ES round; * NRestarts=0 is silently replaced by 1. OUTPUT PARAMETERS: Ensemble - trained ensemble; Rep - it contains all type of errors. NOTE: this training method uses BOTH early stopping and weight decay! So, you should select weight decay before starting training just as you select it before training "conventional" networks. NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), or single-point dataset was passed, ensemble is filled by zero values. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 22.08.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlptrainensemblees( mlptrainer s, mlpensemble ensemble, ae_int_t nrestarts, mlpreport& rep); void alglib::smp_mlptrainensemblees( mlptrainer s, mlpensemble ensemble, ae_int_t nrestarts, mlpreport& rep);

Examples:   [1]  [2]  

/************************************************************************* Neural network training using early stopping (base algorithm - L-BFGS with regularization). INPUT PARAMETERS: Network - neural network with initialized geometry TrnXY - training set TrnSize - training set size, TrnSize>0 ValXY - validation set ValSize - validation set size, ValSize>0 Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts, either: * strictly positive number - algorithm make specified number of restarts from random position. * -1, in which case algorithm makes exactly one run from the initial state of the network (no randomization). If you don't know what Restarts to choose, choose one one the following: * -1 (deterministic start) * +1 (one random restart) * +5 (moderate amount of random restarts) OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1, ...). * 2, task has been solved, stopping criterion met - sufficiently small step size. Not expected (we use EARLY stopping) but possible and not an error. * 6, task has been solved, stopping criterion met - increasing of validation set error. Rep - training report NOTE: Algorithm stops if validation set error increases for a long enough or step size is small enought (there are task where validation set may decrease for eternity). In any case solution returned corresponds to the minimum of validation set error. -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlptraines( multilayerperceptron network, real_2d_array trnxy, ae_int_t trnsize, real_2d_array valxy, ae_int_t valsize, double decay, ae_int_t restarts, ae_int_t& info, mlpreport& rep);
/************************************************************************* Neural network training using L-BFGS algorithm with regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for problems of any dimensionality (memory requirements and step complexity are linear by weights number). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. WStep - stopping criterion. Algorithm stops if step size is less than WStep. Recommended value - 0.01. Zero step size means stopping after MaxIts iterations. MaxIts - stopping criterion. Algorithm stops after MaxIts iterations (NOT gradient calculations). Zero MaxIts means stopping when step is sufficiently small. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -8, if both WStep=0 and MaxIts=0 * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 09.12.2007 by Bochkanov Sergey *************************************************************************/
void alglib::mlptrainlbfgs( multilayerperceptron network, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, double wstep, ae_int_t maxits, ae_int_t& info, mlpreport& rep);
/************************************************************************* Neural network training using modified Levenberg-Marquardt with exact Hessian calculation and regularization. Subroutine trains neural network with restarts from random positions. Algorithm is well suited for small and medium scale problems (hundreds of weights). INPUT PARAMETERS: Network - neural network with initialized geometry XY - training set NPoints - training set size Decay - weight decay constant, >=0.001 Decay term 'Decay*||Weights||^2' is added to error function. If you don't know what Decay to choose, use 0.001. Restarts - number of restarts from random position, >0. If you don't know what Restarts to choose, use 2. OUTPUT PARAMETERS: Network - trained neural network. Info - return code: * -9, if internal matrix inverse subroutine failed * -2, if there is a point with class number outside of [0..NOut-1]. * -1, if wrong parameters specified (NPoints<0, Restarts<1). * 2, if task has been solved. Rep - training report -- ALGLIB -- Copyright 10.03.2009 by Bochkanov Sergey *************************************************************************/
void alglib::mlptrainlm( multilayerperceptron network, real_2d_array xy, ae_int_t npoints, double decay, ae_int_t restarts, ae_int_t& info, mlpreport& rep);
/************************************************************************* This function trains neural network passed to this function, using current dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) and current training settings. Training from NRestarts random starting positions is performed, best network is chosen. Training is performed using current training algorithm. FOR USERS OF COMMERCIAL EDITION: ! Commercial version of ALGLIB includes two important improvements of ! this function: ! * multicore support (C++ and C# computational cores) ! * SSE support (C++ computational core) ! ! Second improvement gives constant speedup (2-3X). First improvement ! gives close-to-linear speedup on multicore systems. Following ! operations can be executed in parallel: ! * NRestarts training sessions performed within each of ! cross-validation rounds (if NRestarts>1) ! * gradient calculation over large dataset (if dataset is large enough) ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! In order to use SSE features you have to: ! * use commercial version of ALGLIB on Intel processors ! * use C++ computational core ! ! This note is given for users of commercial edition; if you use GPL ! edition, you still will be able to call smp-version of this function, ! but all computations will be done serially. ! ! We recommend you to carefully read ALGLIB Reference Manual, section ! called 'SMP support', before using parallel version of this function. INPUT PARAMETERS: S - trainer object Network - neural network. It must have same number of inputs and output/classes as was specified during creation of the trainer object. NRestarts - number of restarts, >=0: * NRestarts>0 means that specified number of random restarts are performed, best network is chosen after training * NRestarts=0 means that current state of the network is used for training. OUTPUT PARAMETERS: Network - trained network NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), network is filled by zero values. Same behavior for functions MLPStartTraining and MLPContinueTraining. NOTE: this method uses sum-of-squares error function for training. -- ALGLIB -- Copyright 23.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::mlptrainnetwork( mlptrainer s, multilayerperceptron network, ae_int_t nrestarts, mlpreport& rep); void alglib::smp_mlptrainnetwork( mlptrainer s, multilayerperceptron network, ae_int_t nrestarts, mlpreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  [6]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Suppose that we want to classify numbers as positive (class 0) and negative
    // (class 1). We have training set which includes several strictly positive
    // or negative numbers - and zero.
    //
    // The problem is that we are not sure how to classify zero, so from time to
    // time we mark it as positive or negative (with equal probability). Other
    // numbers are marked in pure deterministic setting. How will neural network
    // cope with such classification task?
    //
    // NOTE: we use network with excessive amount of neurons, which guarantees
    //       almost exact reproduction of the training set. Generalization ability
    //       of such network is rather low, but we are not concerned with such
    //       questions in this basic demo.
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpreport rep;
    real_1d_array x = "[0]";
    real_1d_array y = "[0,0]";

    //
    // Training set. One row corresponds to one record [A => class(A)].
    //
    // Classes are denoted by numbers from 0 to 1, where 0 corresponds to positive
    // numbers and 1 to negative numbers.
    //
    // [ +1  0]
    // [ +2  0]
    // [ -1  1]
    // [ -2  1]
    // [  0  0]   !! sometimes we classify 0 as positive, sometimes as negative
    // [  0  1]   !!
    //
    real_2d_array xy = "[[+1,0],[+2,0],[-1,1],[-2,1],[0,0],[0,1]]";

    //
    //
    // When we solve classification problems, everything is slightly different from
    // the regression ones:
    //
    // 1. Network is created. Because we solve classification problem, we use
    //    mlpcreatec1() function instead of mlpcreate1(). This function creates
    //    classifier network with SOFTMAX-normalized outputs. This network returns
    //    vector of class membership probabilities which are normalized to be
    //    non-negative and sum to 1.0
    //
    // 2. We use mlpcreatetrainercls() function instead of mlpcreatetrainer() to
    //    create trainer object. Trainer object process dataset and neural network
    //    slightly differently to account for specifics of the classification
    //    problems.
    //
    // 3. Dataset is attached to trainer object. Note that dataset format is slightly
    //    different from one used for regression.
    //
    mlpcreatetrainercls(1, 2, trn);
    mlpcreatec1(1, 5, 2, network);
    mlpsetdataset(trn, xy, 6);

    //
    // Network is trained with 5 restarts from random positions
    //
    mlptrainnetwork(trn, network, 5, rep);

    //
    // Test our neural network on strictly positive and strictly negative numbers.
    //
    // IMPORTANT! Classifier network returns class membership probabilities instead
    // of class indexes. Network returns two values (probabilities) instead of one
    // (class index).
    //
    // Thus, for +1 we expect to get [P0,P1] = [1,0], where P0 is probability that
    // number is positive (belongs to class 0), and P1 is probability that number
    // is negative (belongs to class 1).
    //
    // For -1 we expect to get [P0,P1] = [0,1]
    //
    // Following properties are guaranteed by network architecture:
    // * P0>=0, P1>=0   non-negativity
    // * P0+P1=1        normalization
    //
    x = "[1]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [1.000,0.000]
    x = "[-1]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [0.000,1.000]

    //
    // But what our network will return for 0, which is between classes 0 and 1?
    //
    // In our dataset it has two different marks assigned (class 0 AND class 1).
    // So network will return something average between class 0 and class 1:
    //     0 => [0.5, 0.5]
    //
    x = "[0]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [0.500,0.500]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Suppose that we want to classify numbers as positive (class 0) and negative
    // (class 1). We also have one more class for zero (class 2).
    //
    // NOTE: we use network with excessive amount of neurons, which guarantees
    //       almost exact reproduction of the training set. Generalization ability
    //       of such network is rather low, but we are not concerned with such
    //       questions in this basic demo.
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpreport rep;
    real_1d_array x = "[0]";
    real_1d_array y = "[0,0,0]";

    //
    // Training set. One row corresponds to one record [A => class(A)].
    //
    // Classes are denoted by numbers from 0 to 2, where 0 corresponds to positive
    // numbers, 1 to negative numbers, 2 to zero
    //
    // [ +1  0]
    // [ +2  0]
    // [ -1  1]
    // [ -2  1]
    // [  0  2]
    //
    real_2d_array xy = "[[+1,0],[+2,0],[-1,1],[-2,1],[0,2]]";

    //
    //
    // When we solve classification problems, everything is slightly different from
    // the regression ones:
    //
    // 1. Network is created. Because we solve classification problem, we use
    //    mlpcreatec1() function instead of mlpcreate1(). This function creates
    //    classifier network with SOFTMAX-normalized outputs. This network returns
    //    vector of class membership probabilities which are normalized to be
    //    non-negative and sum to 1.0
    //
    // 2. We use mlpcreatetrainercls() function instead of mlpcreatetrainer() to
    //    create trainer object. Trainer object process dataset and neural network
    //    slightly differently to account for specifics of the classification
    //    problems.
    //
    // 3. Dataset is attached to trainer object. Note that dataset format is slightly
    //    different from one used for regression.
    //
    mlpcreatetrainercls(1, 3, trn);
    mlpcreatec1(1, 5, 3, network);
    mlpsetdataset(trn, xy, 5);

    //
    // Network is trained with 5 restarts from random positions
    //
    mlptrainnetwork(trn, network, 5, rep);

    //
    // Test our neural network on strictly positive and strictly negative numbers.
    //
    // IMPORTANT! Classifier network returns class membership probabilities instead
    // of class indexes. Network returns three values (probabilities) instead of one
    // (class index).
    //
    // Thus, for +1 we expect to get [P0,P1,P2] = [1,0,0],
    // for -1 we expect to get [P0,P1,P2] = [0,1,0],
    // and for 0 we will get [P0,P1,P2] = [0,0,1].
    //
    // Following properties are guaranteed by network architecture:
    // * P0>=0, P1>=0, P2>=0    non-negativity
    // * P0+P1+P2=1             normalization
    //
    x = "[1]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [1.000,0.000,0.000]
    x = "[-1]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [0.000,1.000,0.000]
    x = "[0]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [0.000,0.000,1.000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example shows how to perform cross-validation with ALGLIB
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpreport rep;

    //
    // Training set: f(x)=1/(x^2+1)
    // One row corresponds to one record [x,f(x)]
    //
    real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]";

    //
    // Trainer object is created.
    // Dataset is attached to trainer object.
    //
    // NOTE: it is not good idea to perform cross-validation on sample
    //       as small as ours (13 examples). It is done for demonstration
    //       purposes only. Generalization error estimates won't be
    //       precise enough for practical purposes.
    //
    mlpcreatetrainer(1, 1, trn);
    mlpsetdataset(trn, xy, 13);

    //
    // The key property of the cross-validation is that it estimates
    // generalization properties of neural ARCHITECTURE. It does NOT
    // estimates generalization error of some specific network which
    // is passed to the k-fold CV routine.
    //
    // In our example we create 1x4x1 neural network and pass it to
    // CV routine without training it. Original state of the network
    // is not used for cross-validation - each round is restarted from
    // random initial state. Only geometry of network matters.
    //
    // We perform 5 restarts from different random positions for each
    // of the 10 cross-validation rounds.
    //
    mlpcreate1(1, 4, 1, network);
    mlpkfoldcv(trn, network, 5, 10, rep);

    //
    // Cross-validation routine stores estimates of the generalization
    // error to MLP report structure. You may examine its fields and
    // see estimates of different errors (RMS, CE, Avg).
    //
    // Because cross-validation is non-deterministic, in our manual we
    // can not say what values will be stored to rep after call to
    // mlpkfoldcv(). Every CV round will return slightly different
    // estimates.
    //
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example shows how to train early stopping ensebles.
    //
    mlptrainer trn;
    mlpensemble ensemble;
    mlpreport rep;

    //
    // Training set: f(x)=1/(x^2+1)
    // One row corresponds to one record [x,f(x)]
    //
    real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]";

    //
    // Trainer object is created.
    // Dataset is attached to trainer object.
    //
    // NOTE: it is not good idea to use early stopping ensemble on sample
    //       as small as ours (13 examples). It is done for demonstration
    //       purposes only. Ensemble training algorithm won't find good
    //       solution on such small sample.
    //
    mlpcreatetrainer(1, 1, trn);
    mlpsetdataset(trn, xy, 13);

    //
    // Ensemble is created and trained. Each of 50 network is trained
    // with 5 restarts.
    //
    mlpecreate1(1, 4, 1, 50, ensemble);
    mlptrainensemblees(trn, ensemble, 5, rep);
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example shows how to use parallel functionality of ALGLIB.
    // We generate simple 1-dimensional regression problem and show how
    // to use parallel training, parallel cross-validation, parallel
    // training of neural ensembles.
    //
    // We assume that you already know how to use ALGLIB in serial mode
    // and concentrate on its parallel capabilities.
    //
    // NOTE: it is not good idea to use parallel features on sample as small
    //       as ours (13 examples). It is done only for demonstration purposes.
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpensemble ensemble;
    mlpreport rep;
    real_2d_array xy = "[[-2.0,0.2],[-1.6,0.3],[-1.3,0.4],[-1,0.5],[-0.6,0.7],[-0.3,0.9],[0,1],[2.0,0.2],[1.6,0.3],[1.3,0.4],[1,0.5],[0.6,0.7],[0.3,0.9]]";
    mlpcreatetrainer(1, 1, trn);
    mlpsetdataset(trn, xy, 13);
    mlpcreate1(1, 4, 1, network);
    mlpecreate1(1, 4, 1, 50, ensemble);

    //
    // Below we demonstrate how to perform:
    // * parallel training of individual networks
    // * parallel cross-validation
    // * parallel training of neural ensembles
    //
    // In order to use multithreading, you have to:
    // 1) Install SMP edition of ALGLIB.
    // 2) This step is specific for C++ users: you should activate OS-specific
    //    capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems)
    //    or AE_OS=AE_WINDOWS (for Windows systems).
    //    C# users do not have to perform this step because C# programs are
    //    portable across different systems without OS-specific tuning.
    // 3) Allow ALGLIB to know about number of worker threads to use:
    //    a) autodetection (C++, C#):
    //          ALGLIB will automatically determine number of CPU cores and
    //          (by default) will use all cores except for one. Say, on 4-core
    //          system it will use three cores - unless you manually told it
    //          to use more or less. It will keep your system responsive during
    //          lengthy computations.
    //          Such behavior may be changed with setnworkers() call:
    //          * alglib::setnworkers(0)  = use all cores
    //          * alglib::setnworkers(-1) = leave one core unused
    //          * alglib::setnworkers(-2) = leave two cores unused
    //          * alglib::setnworkers(+2) = use 2 cores (even if you have more)
    //    b) manual specification (C++, C#):
    //          You may want to specify maximum number of worker threads during
    //          compile time by means of preprocessor definition AE_NWORKERS.
    //          For C++ it will be "AE_NWORKERS=X" where X can be any positive number.
    //          For C# it is "AE_NWORKERSX", where X should be replaced by number of
    //          workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...).
    //          You can add this definition to compiler command line or change
    //          corresponding project settings in your IDE.
    //
    // After you installed and configured SMP edition of ALGLIB, you may choose
    // between serial and multithreaded versions of SMP-capable functions:
    // * serial version works as usual, in the context of the calling thread
    // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker
    //   threads, inserts task in the worker queue, and waits for completion of
    //   the task. All processing is done in context of worker thread(s).
    //
    // NOTE: because starting/stopping worker threads costs thousands of CPU cycles,
    //       you should not use multithreading for lightweight computational problems.
    //
    // NOTE: some old POSIX-compatible operating systems do not support
    //       sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order
    //       to automatically determine number of active cores. On these systems
    //       you should specify number of cores manually at compile time.
    //       Without it ALGLIB will run in single-threaded mode.
    //

    //
    // First, we perform parallel training of individual network with 5
    // restarts from random positions. These 5 rounds of  training  are
    // executed in parallel manner,  with  best  network  chosen  after
    // training.
    //
    // ALGLIB can use additional way to speed up computations -  divide
    // dataset   into   smaller   subsets   and   process these subsets
    // simultaneously. It allows us  to  efficiently  parallelize  even
    // single training round. This operation is performed automatically
    // for large datasets, but our toy dataset is too small.
    //
    smp_mlptrainnetwork(trn, network, 5, rep);

    //
    // Then, we perform parallel 10-fold cross-validation, with 5 random
    // restarts per each CV round. I.e., 5*10=50  networks  are trained
    // in total. All these operations can be parallelized.
    //
    // NOTE: again, ALGLIB can parallelize  calculation   of   gradient
    //       over entire dataset - but our dataset is too small.
    //
    smp_mlpkfoldcv(trn, network, 5, 10, rep);

    //
    // Finally, we train early stopping ensemble of 50 neural networks,
    // each  of them is trained with 5 random restarts. I.e.,  5*50=250
    // networks aretrained in total.
    //
    smp_mlptrainensemblees(trn, ensemble, 5, rep);
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // The very simple example on neural network: network is trained to reproduce
    // small 2x2 multiplication table.
    //
    // NOTE: we use network with excessive amount of neurons, which guarantees
    //       almost exact reproduction of the training set. Generalization ability
    //       of such network is rather low, but we are not concerned with such
    //       questions in this basic demo.
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpreport rep;

    //
    // Training set:
    // * one row corresponds to one record A*B=C in the multiplication table
    // * first two columns store A and B, last column stores C
    //
    // [1 * 1 = 1]
    // [1 * 2 = 2]
    // [2 * 1 = 2]
    // [2 * 2 = 4]
    //
    real_2d_array xy = "[[1,1,1],[1,2,2],[2,1,2],[2,2,4]]";

    //
    // Network is created.
    // Trainer object is created.
    // Dataset is attached to trainer object.
    //
    mlpcreatetrainer(2, 1, trn);
    mlpcreate1(2, 5, 1, network);
    mlpsetdataset(trn, xy, 4);

    //
    // Network is trained with 5 restarts from random positions
    //
    mlptrainnetwork(trn, network, 5, rep);

    //
    // 2*2=?
    //
    real_1d_array x = "[2,2]";
    real_1d_array y = "[0]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [4.000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Network with 2 inputs and 2 outputs is trained to reproduce vector function:
    //     (x0,x1) => (x0+x1, x0*x1)
    //
    // Informally speaking, we want neural network to simultaneously calculate
    // both sum of two numbers and their product.
    //
    // NOTE: we use network with excessive amount of neurons, which guarantees
    //       almost exact reproduction of the training set. Generalization ability
    //       of such network is rather low, but we are not concerned with such
    //       questions in this basic demo.
    //
    mlptrainer trn;
    multilayerperceptron network;
    mlpreport rep;

    //
    // Training set. One row corresponds to one record [A,B,A+B,A*B].
    //
    // [ 1   1  1+1  1*1 ]
    // [ 1   2  1+2  1*2 ]
    // [ 2   1  2+1  2*1 ]
    // [ 2   2  2+2  2*2 ]
    //
    real_2d_array xy = "[[1,1,2,1],[1,2,3,2],[2,1,3,2],[2,2,4,4]]";

    //
    // Network is created.
    // Trainer object is created.
    // Dataset is attached to trainer object.
    //
    mlpcreatetrainer(2, 2, trn);
    mlpcreate1(2, 5, 2, network);
    mlpsetdataset(trn, xy, 4);

    //
    // Network is trained with 5 restarts from random positions
    //
    mlptrainnetwork(trn, network, 5, rep);

    //
    // 2+1=?
    // 2*1=?
    //
    real_1d_array x = "[2,1]";
    real_1d_array y = "[0,0]";
    mlpprocess(network, x, y);
    printf("%s\n", y.tostring(1).c_str()); // EXPECTED: [3.000,2.000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "dataanalysis.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Trainer object is used to train network. It stores dataset, training settings,
    // and other information which is NOT part of neural network. You should use
    // trainer object as follows:
    // (1) you create trainer object and specify task type (classification/regression)
    //     and number of inputs/outputs
    // (2) you add dataset to the trainer object
    // (3) you may change training settings (stopping criteria or weight decay)
    // (4) finally, you may train one or more networks
    //
    // You may interleave stages 2...4 and repeat them many times. Trainer object
    // remembers its internal state and can be used several times after its creation
    // and initialization.
    //
    mlptrainer trn;

    //
    // Stage 1: object creation.
    //
    // We have to specify number of inputs and outputs. Trainer object can be used
    // only for problems with same number of inputs/outputs as was specified during
    // its creation.
    //
    // In case you want to train SOFTMAX-normalized network which solves classification
    // problems,  you  must  use  another  function  to  create  trainer  object:
    // mlpcreatetrainercls().
    //
    // Below we create trainer object which can be used to train regression networks
    // with 2 inputs and 1 output.
    //
    mlpcreatetrainer(2, 1, trn);

    //
    // Stage 2: specification of the training set
    //
    // By default trainer object stores empty dataset. So to solve your non-empty problem
    // you have to set dataset by passing to trainer dense or sparse matrix.
    //
    // One row of the matrix corresponds to one record A*B=C in the multiplication table.
    // First two columns store A and B, last column stores C
    //
    //     [1 * 1 = 1]   [ 1 1 1 ]
    //     [1 * 2 = 2]   [ 1 2 2 ]
    //     [2 * 1 = 2] = [ 2 1 2 ]
    //     [2 * 2 = 4]   [ 2 2 4 ]
    //
    real_2d_array xy = "[[1,1,1],[1,2,2],[2,1,2],[2,2,4]]";
    mlpsetdataset(trn, xy, 4);

    //
    // Stage 3: modification of the training parameters.
    //
    // You may modify parameters like weights decay or stopping criteria:
    // * we set moderate weight decay
    // * we choose iterations limit as stopping condition (another condition - step size -
    //   is zero, which means than this condition is not active)
    //
    double wstep = 0.000;
    ae_int_t maxits = 100;
    mlpsetdecay(trn, 0.01);
    mlpsetcond(trn, wstep, maxits);

    //
    // Stage 4: training.
    //
    // We will train several networks with different architecture using same trainer object.
    // We may change training parameters or even dataset, so different networks are trained
    // differently. But in this simple example we will train all networks with same settings.
    //
    // We create and train three networks:
    // * network 1 has 2x1 architecture     (2 inputs, no hidden neurons, 1 output)
    // * network 2 has 2x5x1 architecture   (2 inputs, 5 hidden neurons, 1 output)
    // * network 3 has 2x5x5x1 architecture (2 inputs, two hidden layers, 1 output)
    //
    // NOTE: these networks solve regression problems. For classification problems you
    //       should use mlpcreatec0/c1/c2 to create neural networks which have SOFTMAX-
    //       normalized outputs.
    //
    multilayerperceptron net1;
    multilayerperceptron net2;
    multilayerperceptron net3;
    mlpreport rep;

    mlpcreate0(2, 1, net1);
    mlpcreate1(2, 5, 1, net2);
    mlpcreate2(2, 5, 5, 1, net3);

    mlptrainnetwork(trn, net1, 5, rep);
    mlptrainnetwork(trn, net2, 5, rep);
    mlptrainnetwork(trn, net3, 5, rep);
    return 0;
}


/************************************************************************* *************************************************************************/
class kdtree { };
/************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values N - number of points, N>=0. NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreebuild( real_2d_array xy, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree& kdt); void alglib::kdtreebuild( real_2d_array xy, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree& kdt);

Examples:   [1]  [2]  

/************************************************************************* KD-tree creation This subroutine creates KD-tree from set of X-values, integer tags and optional Y-values INPUT PARAMETERS XY - dataset, array[0..N-1,0..NX+NY-1]. one row corresponds to one point. first NX columns contain X-values, next NY (NY may be zero) columns may contain associated Y-values Tags - tags, array[0..N-1], contains integer tags associated with points. N - number of points, N>=0 NX - space dimension, NX>=1. NY - number of optional Y-values, NY>=0. NormType- norm type: * 0 denotes infinity-norm * 1 denotes 1-norm * 2 denotes 2-norm (Euclidean norm) OUTPUT PARAMETERS KDT - KD-tree NOTES 1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory requirements. 2. Although KD-trees may be used with any combination of N and NX, they are more efficient than brute-force search only when N >> 4^NX. So they are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another inefficient case, because simple binary search (without additional structures) is much more efficient in such tasks than KD-trees. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreebuildtagged( real_2d_array xy, integer_1d_array tags, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree& kdt); void alglib::kdtreebuildtagged( real_2d_array xy, integer_1d_array tags, ae_int_t n, ae_int_t nx, ae_int_t ny, ae_int_t normtype, kdtree& kdt);

Examples:   [1]  

/************************************************************************* K-NN query: approximate K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True Eps - approximation factor, Eps>=0. eps-approximate nearest neighbor is a neighbor whose distance from X is at most (1+eps) times distance of true nearest neighbor. RESULT number of actual neighbors found (either K or N, if K>N). NOTES significant performance gain may be achieved only when Eps is is on the order of magnitude of 1 or larger. This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::kdtreequeryaknn( kdtree kdt, real_1d_array x, ae_int_t k, double eps); ae_int_t alglib::kdtreequeryaknn( kdtree kdt, real_1d_array x, ae_int_t k, bool selfmatch, double eps);

Examples:   [1]  

/************************************************************************* K-NN query: K nearest neighbors INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. K - number of neighbors to return, K>=1 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of actual neighbors found (either K or N, if K>N). This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain these results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::kdtreequeryknn(kdtree kdt, real_1d_array x, ae_int_t k); ae_int_t alglib::kdtreequeryknn( kdtree kdt, real_1d_array x, ae_int_t k, bool selfmatch);

Examples:   [1]  

/************************************************************************* Distances from last query INPUT PARAMETERS KDT - KD-tree R - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS R - filled with distances (in corresponding norm) NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsdistances(kdtree kdt, real_1d_array& r);

Examples:   [1]  

/************************************************************************* Distances from last query; 'interactive' variant for languages like Python which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsdistancesi(kdtree kdt, real_1d_array& r);
/************************************************************************* Tags from last query INPUT PARAMETERS KDT - KD-tree Tags - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS Tags - filled with tags associated with points, or, when no tags were supplied, with zeros NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultstags(kdtree kdt, integer_1d_array& tags);

Examples:   [1]  

/************************************************************************* Tags from last query; 'interactive' variant for languages like Python which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultstagsi(kdtree kdt, integer_1d_array& tags);
/************************************************************************* X-values from last query INPUT PARAMETERS KDT - KD-tree X - possibly pre-allocated buffer. If X is too small to store result, it is resized. If size(X) is enough to store result, it is left unchanged. OUTPUT PARAMETERS X - rows are filled with X-values NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsXY() X- and Y-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsx(kdtree kdt, real_2d_array& x);

Examples:   [1]  

/************************************************************************* X-values from last query; 'interactive' variant for languages like Python which support constructs like "X = KDTreeQueryResultsXI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsxi(kdtree kdt, real_2d_array& x);
/************************************************************************* X- and Y-values from last query INPUT PARAMETERS KDT - KD-tree XY - possibly pre-allocated buffer. If XY is too small to store result, it is resized. If size(XY) is enough to store result, it is left unchanged. OUTPUT PARAMETERS XY - rows are filled with points: first NX columns with X-values, next NY columns - with Y-values. NOTES 1. points are ordered by distance from the query point (first = closest) 2. if XY is larger than required to store result, only leading part will be overwritten; trailing part will be left unchanged. So if on input XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is done purposely to increase performance; if you want function to resize array according to result size, use function with same name and suffix 'I'. SEE ALSO * KDTreeQueryResultsX() X-values * KDTreeQueryResultsTags() tag values * KDTreeQueryResultsDistances() distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsxy(kdtree kdt, real_2d_array& xy);

Examples:   [1]  

/************************************************************************* XY-values from last query; 'interactive' variant for languages like Python which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and interactive mode of interpreter. This function allocates new array on each call, so it is significantly slower than its 'non-interactive' counterpart, but it is more convenient when you call it from command line. -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
void alglib::kdtreequeryresultsxyi(kdtree kdt, real_2d_array& xy);
/************************************************************************* R-NN query: all points within R-sphere centered at X INPUT PARAMETERS KDT - KD-tree X - point, array[0..NX-1]. R - radius of sphere (in corresponding norm), R>0 SelfMatch - whether self-matches are allowed: * if True, nearest neighbor may be the point itself (if it exists in original dataset) * if False, then only points with non-zero distance are returned * if not given, considered True RESULT number of neighbors found, >=0 This subroutine performs query and stores its result in the internal structures of the KD-tree. You can use following subroutines to obtain actual results: * KDTreeQueryResultsX() to get X-values * KDTreeQueryResultsXY() to get X- and Y-values * KDTreeQueryResultsTags() to get tag values * KDTreeQueryResultsDistances() to get distances -- ALGLIB -- Copyright 28.02.2010 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::kdtreequeryrnn(kdtree kdt, real_1d_array x, double r); ae_int_t alglib::kdtreequeryrnn( kdtree kdt, real_1d_array x, double r, bool selfmatch);

Examples:   [1]  

/************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/
void kdtreeserialize(kdtree &obj, std::string &s_out);
/************************************************************************* This function unserializes data structure from string. *************************************************************************/
void kdtreeunserialize(std::string &s_in, kdtree &obj);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "alglibmisc.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array a = "[[0,0],[0,1],[1,0],[1,1]]";
    ae_int_t nx = 2;
    ae_int_t ny = 0;
    ae_int_t normtype = 2;
    kdtree kdt;
    real_1d_array x;
    real_2d_array r = "[[]]";
    ae_int_t k;
    kdtreebuild(a, nx, ny, normtype, kdt);
    x = "[-1,0]";
    k = kdtreequeryknn(kdt, x, 1);
    printf("%d\n", int(k)); // EXPECTED: 1
    kdtreequeryresultsx(kdt, r);
    printf("%s\n", r.tostring(1).c_str()); // EXPECTED: [[0,0]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "alglibmisc.h"

using namespace alglib;


int main(int argc, char **argv)
{
    real_2d_array a = "[[0,0],[0,1],[1,0],[1,1]]";
    ae_int_t nx = 2;
    ae_int_t ny = 0;
    ae_int_t normtype = 2;
    kdtree kdt0;
    kdtree kdt1;
    std::string s;
    real_1d_array x;
    real_2d_array r0 = "[[]]";
    real_2d_array r1 = "[[]]";

    //
    // Build tree and serialize it
    //
    kdtreebuild(a, nx, ny, normtype, kdt0);
    alglib::kdtreeserialize(kdt0, s);
    alglib::kdtreeunserialize(s, kdt1);

    //
    // Compare results from KNN queries
    //
    x = "[-1,0]";
    kdtreequeryknn(kdt0, x, 1);
    kdtreequeryresultsx(kdt0, r0);
    kdtreequeryknn(kdt1, x, 1);
    kdtreequeryresultsx(kdt1, r1);
    printf("%s\n", r0.tostring(1).c_str()); // EXPECTED: [[0,0]]
    printf("%s\n", r1.tostring(1).c_str()); // EXPECTED: [[0,0]]
    return 0;
}


/************************************************************************* *************************************************************************/
class nleqreport { ae_int_t iterationscount; ae_int_t nfunc; ae_int_t njac; ae_int_t terminationtype; };
/************************************************************************* *************************************************************************/
class nleqstate { };
/************************************************************************* LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER DESCRIPTION: This algorithm solves system of nonlinear equations F[0](x[0], ..., x[n-1]) = 0 F[1](x[0], ..., x[n-1]) = 0 ... F[M-1](x[0], ..., x[n-1]) = 0 with M/N do not necessarily coincide. Algorithm converges quadratically under following conditions: * the solution set XS is nonempty * for some xs in XS there exist such neighbourhood N(xs) that: * vector function F(x) and its Jacobian J(x) are continuously differentiable on N * ||F(x)|| provides local error bound on N, i.e. there exists such c1, that ||F(x)||>c1*distance(x,XS) Note that these conditions are much more weaker than usual non-singularity conditions. For example, algorithm will converge for any affine function F (whether its Jacobian singular or not). REQUIREMENTS: Algorithm will request following information during its operation: * function vector F[] and Jacobian matrix at given point X * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X USAGE: 1. User initializes algorithm state with NLEQCreateLM() call 2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and other functions 3. User calls NLEQSolve() function which takes algorithm state and pointers (delegates, etc.) to callback functions which calculate merit function value and Jacobian. 4. User calls NLEQResults() to get solution 5. Optionally, user may call NLEQRestartFrom() to solve another problem with same parameters (N/M) but another starting point and/or another function vector. NLEQRestartFrom() allows to reuse already initialized structure. INPUT PARAMETERS: N - space dimension, N>1: * if provided, only leading N elements of X are used * if not provided, determined automatically from size of X M - system size X - starting point OUTPUT PARAMETERS: State - structure which stores algorithm state NOTES: 1. you may tune stopping conditions with NLEQSetCond() function 2. if target function contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow, use NLEQSetStpMax() function to bound algorithm's steps. 3. this algorithm is a slightly modified implementation of the method described in 'Levenberg-Marquardt method for constrained nonlinear equations with strong local convergence properties' by Christian Kanzow Nobuo Yamashita and Masao Fukushima and further developed in 'On the convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang Yuan. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::nleqcreatelm(ae_int_t m, real_1d_array x, nleqstate& state); void alglib::nleqcreatelm( ae_int_t n, ae_int_t m, real_1d_array x, nleqstate& state);
/************************************************************************* This subroutine restarts CG algorithm from new point. All optimization parameters are left unchanged. This function allows to solve multiple optimization problems (which must have same number of dimensions) without object reallocation penalty. INPUT PARAMETERS: State - structure used for reverse communication previously allocated with MinCGCreate call. X - new starting point. BndL - new lower bounds BndU - new upper bounds -- ALGLIB -- Copyright 30.07.2010 by Bochkanov Sergey *************************************************************************/
void alglib::nleqrestartfrom(nleqstate state, real_1d_array x);
/************************************************************************* NLEQ solver results INPUT PARAMETERS: State - algorithm state. OUTPUT PARAMETERS: X - array[0..N-1], solution Rep - optimization report: * Rep.TerminationType completetion code: * -4 ERROR: algorithm has converged to the stationary point Xf which is local minimum of f=F[0]^2+...+F[m-1]^2, but is not solution of nonlinear system. * 1 sqrt(f)<=EpsF. * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible * Rep.IterationsCount contains iterations count * NFEV countains number of function calculations * ActiveConstraints contains number of active constraints -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::nleqresults( nleqstate state, real_1d_array& x, nleqreport& rep);
/************************************************************************* NLEQ solver results Buffered implementation of NLEQResults(), which uses pre-allocated buffer to store X[]. If buffer size is too small, it resizes buffer. It is intended to be used in the inner cycles of performance critical algorithms where array reallocation penalty is too large to be ignored. -- ALGLIB -- Copyright 20.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::nleqresultsbuf( nleqstate state, real_1d_array& x, nleqreport& rep);
/************************************************************************* This function sets stopping conditions for the nonlinear solver INPUT PARAMETERS: State - structure which stores algorithm state EpsF - >=0 The subroutine finishes its work if on k+1-th iteration the condition ||F||<=EpsF is satisfied MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic stopping criterion selection (small EpsF). NOTES: -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/
void alglib::nleqsetcond(nleqstate state, double epsf, ae_int_t maxits);
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when target function contains exp() or other fast growing functions, and algorithm makes too large steps which lead to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/
void alglib::nleqsetstpmax(nleqstate state, double stpmax);
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not If NeedXRep is True, algorithm will call rep() callback function if it is provided to NLEQSolve(). -- ALGLIB -- Copyright 20.08.2010 by Bochkanov Sergey *************************************************************************/
void alglib::nleqsetxrep(nleqstate state, bool needxrep);
/************************************************************************* This family of functions is used to launcn iterations of nonlinear solver These functions accept following parameters: state - algorithm state func - callback which calculates function (or merit function) value func at given point x jac - callback which calculates function vector fi[] and Jacobian jac at given point x rep - optional callback which is called after each iteration can be NULL ptr - optional pointer which is passed to func/grad/hess/jac/rep can be NULL -- ALGLIB -- Copyright 20.03.2009 by Bochkanov Sergey *************************************************************************/
void nleqsolve(nleqstate &state, void (*func)(const real_1d_array &x, double &func, void *ptr), void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, void *ptr = NULL);
/************************************************************************* Error function The integral is x - 2 | | 2 erf(x) = -------- | exp( - t ) dt. sqrt(pi) | | - 0 For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise erf(x) = 1 - erfc(x). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,1 30000 3.7e-16 1.0e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::errorfunction(double x);
/************************************************************************* Complementary error function 1 - erf(x) = inf. - 2 | | 2 erfc(x) = -------- | exp( - t ) dt sqrt(pi) | | - x For small x, erfc(x) = 1 - erf(x); otherwise rational approximations are computed. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0,26.6417 30000 5.7e-14 1.5e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::errorfunctionc(double x);
/************************************************************************* Inverse of the error function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::inverf(double e);
/************************************************************************* Inverse of Normal distribution function Returns the argument, x, for which the area under the Gaussian probability density function (integrated from minus infinity to x) is equal to y. For small arguments 0 < y < exp(-2), the program computes z = sqrt( -2.0 * log(y) ); then the approximation is x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). There are two rational functions P/Q, one for 0 < y < exp(-32) and the other for y up to exp(-2). For larger arguments, w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE 0.125, 1 20000 7.2e-16 1.3e-16 IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invnormaldistribution(double y0);
/************************************************************************* Normal distribution function Returns the area under the Gaussian probability density function, integrated from minus infinity to x: x - 1 | | 2 ndtr(x) = --------- | exp( - t /2 ) dt sqrt(2pi) | | - -inf. = ( 1 + erf(z) ) / 2 = erfc(z) / 2 where z = x/sqrt(2). Computation is via the functions erf and erfc. ACCURACY: Relative error: arithmetic domain # trials peak rms IEEE -13,0 30000 3.4e-14 6.7e-15 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::normaldistribution(double x);
/************************************************************************* This object stores state of the iterative norm estimation algorithm. You should use ALGLIB functions to work with this object. *************************************************************************/
class normestimatorstate { };
/************************************************************************* This procedure initializes matrix norm estimator. USAGE: 1. User initializes algorithm state with NormEstimatorCreate() call 2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) 3. User calls NormEstimatorResults() to get solution. INPUT PARAMETERS: M - number of rows in the matrix being estimated, M>0 N - number of columns in the matrix being estimated, N>0 NStart - number of random starting vectors recommended value - at least 5. NIts - number of iterations to do with best starting vector recommended value - at least 5. OUTPUT PARAMETERS: State - structure which stores algorithm state NOTE: this algorithm is effectively deterministic, i.e. it always returns same result when repeatedly called for the same matrix. In fact, algorithm uses randomized starting vectors, but internal random numbers generator always generates same sequence of the random values (it is a feature, not bug). Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::normestimatorcreate( ae_int_t m, ae_int_t n, ae_int_t nstart, ae_int_t nits, normestimatorstate& state);
/************************************************************************* This function estimates norm of the sparse M*N matrix A. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() A - sparse M*N matrix, must be converted to CRS format prior to calling this function. After this function is over you can call NormEstimatorResults() to get estimate of the norm(A). -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::normestimatorestimatesparse( normestimatorstate state, sparsematrix a);
/************************************************************************* Matrix norm estimation results INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Nrm - estimate of the matrix norm, Nrm>=0 -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::normestimatorresults(normestimatorstate state, double& nrm);
/************************************************************************* This function changes seed value used by algorithm. In some cases we need deterministic processing, i.e. subsequent calls must return equal results, in other cases we need non-deterministic algorithm which returns different results for the same matrix on every pass. Setting zero seed will lead to non-deterministic algorithm, while non-zero value will make our algorithm deterministic. INPUT PARAMETERS: State - norm estimator state, must be initialized with a call to NormEstimatorCreate() SeedVal - seed value, >=0. Zero value = non-deterministic algo. -- ALGLIB -- Copyright 06.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::normestimatorsetseed( normestimatorstate state, ae_int_t seedval);
odesolverreport
odesolverstate
odesolverresults
odesolverrkck
odesolversolve
odesolver_d1 Solving y'=-y with ODE solver
/************************************************************************* *************************************************************************/
class odesolverreport { ae_int_t nfev; ae_int_t terminationtype; };
/************************************************************************* *************************************************************************/
class odesolverstate { };
/************************************************************************* ODE solver results Called after OdeSolverIteration returned False. INPUT PARAMETERS: State - algorithm state (used by OdeSolverIteration). OUTPUT PARAMETERS: M - number of tabulated values, M>=1 XTbl - array[0..M-1], values of X YTbl - array[0..M-1,0..N-1], values of Y in X[i] Rep - solver report: * Rep.TerminationType completetion code: * -2 X is not ordered by ascending/descending or there are non-distinct X[], i.e. X[i]=X[i+1] * -1 incorrect parameters were specified * 1 task has been solved * Rep.NFEV contains number of function calculations -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/
void alglib::odesolverresults( odesolverstate state, ae_int_t& m, real_1d_array& xtbl, real_2d_array& ytbl, odesolverreport& rep);

Examples:   [1]  

/************************************************************************* Cash-Karp adaptive ODE solver. This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys (here Y may be single variable or vector of N variables). INPUT PARAMETERS: Y - initial conditions, array[0..N-1]. contains values of Y[] at X[0] N - system size X - points at which Y should be tabulated, array[0..M-1] integrations starts at X[0], ends at X[M-1], intermediate values at X[i] are returned too. SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! M - number of intermediate points + first point + last point: * M>2 means that you need both Y(X[M-1]) and M-2 values at intermediate points * M=2 means that you want just to integrate from X[0] to X[1] and don't interested in intermediate values. * M=1 means that you don't want to integrate :) it is degenerate case, but it will be handled correctly. * M<1 means error Eps - tolerance (absolute/relative error on each step will be less than Eps). When passing: * Eps>0, it means desired ABSOLUTE error * Eps<0, it means desired RELATIVE error. Relative errors are calculated with respect to maximum values of Y seen so far. Be careful to use this criterion when starting from Y[] that are close to zero. H - initial step lenth, it will be adjusted automatically after the first step. If H=0, step will be selected automatically (usualy it will be equal to 0.001 of min(x[i]-x[j])). OUTPUT PARAMETERS State - structure which stores algorithm state between subsequent calls of OdeSolverIteration. Used for reverse communication. This structure should be passed to the OdeSolverIteration subroutine. SEE ALSO AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/
void alglib::odesolverrkck( real_1d_array y, real_1d_array x, double eps, double h, odesolverstate& state); void alglib::odesolverrkck( real_1d_array y, ae_int_t n, real_1d_array x, ae_int_t m, double eps, double h, odesolverstate& state);

Examples:   [1]  

/************************************************************************* This function is used to launcn iterations of ODE solver It accepts following parameters: diff - callback which calculates dy/dx for given y and x ptr - optional pointer which is passed to diff; can be NULL -- ALGLIB -- Copyright 01.09.2009 by Bochkanov Sergey *************************************************************************/
void odesolversolve(odesolverstate &state, void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), void *ptr = NULL);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "diffequations.h"

using namespace alglib;
void ode_function_1_diff(const real_1d_array &y, double x, real_1d_array &dy, void *ptr) 
{
    // this callback calculates f(y[],x)=-y[0]
    dy[0] = -y[0];
}

int main(int argc, char **argv)
{
    real_1d_array y = "[1]";
    real_1d_array x = "[0, 1, 2, 3]";
    double eps = 0.00001;
    double h = 0;
    odesolverstate s;
    ae_int_t m;
    real_1d_array xtbl;
    real_2d_array ytbl;
    odesolverreport rep;
    odesolverrkck(y, x, eps, h, s);
    alglib::odesolversolve(s, ode_function_1_diff);
    odesolverresults(s, m, xtbl, ytbl, rep);
    printf("%d\n", int(m)); // EXPECTED: 4
    printf("%s\n", xtbl.tostring(2).c_str()); // EXPECTED: [0, 1, 2, 3]
    printf("%s\n", ytbl.tostring(2).c_str()); // EXPECTED: [[1], [0.367], [0.135], [0.050]]
    return 0;
}


/************************************************************************* LQ decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and L in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/
void alglib::cmatrixlq( complex_2d_array& a, ae_int_t m, ae_int_t n, complex_1d_array& tau); void alglib::smp_cmatrixlq( complex_2d_array& a, ae_int_t m, ae_int_t n, complex_1d_array& tau);
/************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of CMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlqunpackl( complex_2d_array a, ae_int_t m, ae_int_t n, complex_2d_array& l);
/************************************************************************* Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixLQ subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixLQ subroutine . QRows - required number of rows in matrix Q. N>=QColumns>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose index ranges within [0..QRows-1, 0..N-1]. If QRows=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlqunpackq( complex_2d_array a, ae_int_t m, ae_int_t n, complex_1d_array tau, ae_int_t qrows, complex_2d_array& q); void alglib::smp_cmatrixlqunpackq( complex_2d_array a, ae_int_t m, ae_int_t n, complex_1d_array tau, ae_int_t qrows, complex_2d_array& q);
/************************************************************************* QR decomposition of a rectangular complex matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form Tau - array of scalar factors which are used to form matrix Q. Array whose indexes range within [0.. Min(M,N)-1] Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 *************************************************************************/
void alglib::cmatrixqr( complex_2d_array& a, ae_int_t m, ae_int_t n, complex_1d_array& tau); void alglib::smp_cmatrixqr( complex_2d_array& a, ae_int_t m, ae_int_t n, complex_1d_array& tau);
/************************************************************************* Partial unpacking of matrix Q from QR decomposition of a complex matrix A. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine . M - number of rows in matrix A. M>=0. N - number of columns in matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of CMatrixQR subroutine . QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose index ranges within [0..M-1, 0..QColumns-1]. If QColumns=0, array isn't changed. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixqrunpackq( complex_2d_array a, ae_int_t m, ae_int_t n, complex_1d_array tau, ae_int_t qcolumns, complex_2d_array& q); void alglib::smp_cmatrixqrunpackq( complex_2d_array a, ae_int_t m, ae_int_t n, complex_1d_array tau, ae_int_t qcolumns, complex_2d_array& q);
/************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of CMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixqrunpackr( complex_2d_array a, ae_int_t m, ae_int_t n, complex_2d_array& r);
/************************************************************************* Reduction of a Hermitian matrix which is given by its higher or lower triangular part to a real tridiagonal matrix using unitary similarity transformation: Q'*A*Q = T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of real symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of real symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a complex scalar, and v is a complex vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/
void alglib::hmatrixtd( complex_2d_array& a, ae_int_t n, bool isupper, complex_1d_array& tau, real_1d_array& d, real_1d_array& e);
/************************************************************************* Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a HMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of HMatrixTD subroutine) Tau - the result of a HMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/
void alglib::hmatrixtdunpackq( complex_2d_array a, ae_int_t n, bool isupper, complex_1d_array tau, complex_2d_array& q);
/************************************************************************* Reduction of a rectangular matrix to bidiagonal form The algorithm reduces the rectangular matrix A to bidiagonal form by orthogonal transformations P and Q: A = Q*B*(P^T). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function because ! bidiagonal decompostion is inherently sequential in nature. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - source matrix. array[0..M-1, 0..N-1] M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q, B, P in compact form (see below). TauQ - scalar factors which are used to form matrix Q. TauP - scalar factors which are used to form matrix P. The main diagonal and one of the secondary diagonals of matrix A are replaced with bidiagonal matrix B. Other elements contain elementary reflections which form MxM matrix Q and NxN matrix P, respectively. If M>=N, B is the upper bidiagonal MxN matrix and is stored in the corresponding elements of matrix A. Matrix Q is represented as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i). Matrix P is as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). If M<N, B is the lower bidiagonal MxN matrix and is stored in the corresponding elements of matrix A. Q = H(0)*H(1)*...*H(m-2), where H(i) = 1 - tau*v*v', tau is stored in TauQ, v(0:i)=0, v(i+1)=1, v(i+2:m-1) is stored in elements A(i+2:m-1,i). P = G(0)*G(1)*...*G(m-1), G(i) = 1-tau*u*u', tau is stored in TauP, u(0:i-1)=0, u(i)=1, u(i+1:n-1) is stored in A(i,i+1:n-1). EXAMPLE: m=6, n=5 (m > n): m=5, n=6 (m < n): ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) ( v1 v2 v3 v4 v5 ) Here vi and ui are vectors which form H(i) and G(i), and d and e - are the diagonal and off-diagonal elements of matrix B. -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994. Sergey Bochkanov, ALGLIB project, translation from FORTRAN to pseudocode, 2007-2010. *************************************************************************/
void alglib::rmatrixbd( real_2d_array& a, ae_int_t m, ae_int_t n, real_1d_array& tauq, real_1d_array& taup);
/************************************************************************* Multiplication by matrix P which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by P or P'. Input parameters: QP - matrices Q and P in compact form. Output of RMatrixBD subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of RMatrixBD subroutine. Z - multiplied matrix. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=N, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=N, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by P or P'. Output parameters: Z - product of Z and P. Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixbdmultiplybyp( real_2d_array qp, ae_int_t m, ae_int_t n, real_1d_array taup, real_2d_array& z, ae_int_t zrows, ae_int_t zcolumns, bool fromtheright, bool dotranspose);
/************************************************************************* Multiplication by matrix Q which reduces matrix A to bidiagonal form. The algorithm allows pre- or post-multiply by Q or Q'. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. Z - multiplied matrix. array[0..ZRows-1,0..ZColumns-1] ZRows - number of rows in matrix Z. If FromTheRight=False, ZRows=M, otherwise ZRows can be arbitrary. ZColumns - number of columns in matrix Z. If FromTheRight=True, ZColumns=M, otherwise ZColumns can be arbitrary. FromTheRight - pre- or post-multiply. DoTranspose - multiply by Q or Q'. Output parameters: Z - product of Z and Q. Array[0..ZRows-1,0..ZColumns-1] If ZRows=0 or ZColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixbdmultiplybyq( real_2d_array qp, ae_int_t m, ae_int_t n, real_1d_array tauq, real_2d_array& z, ae_int_t zrows, ae_int_t zcolumns, bool fromtheright, bool dotranspose);
/************************************************************************* Unpacking of the main and secondary diagonals of bidiagonal decomposition of matrix A. Input parameters: B - output of RMatrixBD subroutine. M - number of rows in matrix B. N - number of columns in matrix B. Output parameters: IsUpper - True, if the matrix is upper bidiagonal. otherwise IsUpper is False. D - the main diagonal. Array whose index ranges within [0..Min(M,N)-1]. E - the secondary diagonal (upper or lower, depending on the value of IsUpper). Array index ranges within [0..Min(M,N)-1], the last element is not used. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixbdunpackdiagonals( real_2d_array b, ae_int_t m, ae_int_t n, bool& isupper, real_1d_array& d, real_1d_array& e);
/************************************************************************* Unpacking matrix P which reduces matrix A to bidiagonal form. The subroutine returns transposed matrix P. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUP - scalar factors which are used to form P. Output of ToBidiagonal subroutine. PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. Output parameters: PT - first PTRows columns of matrix P^T Array[0..PTRows-1, 0..N-1] If PTRows=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixbdunpackpt( real_2d_array qp, ae_int_t m, ae_int_t n, real_1d_array taup, ae_int_t ptrows, real_2d_array& pt);
/************************************************************************* Unpacking matrix Q which reduces a matrix to bidiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: QP - matrices Q and P in compact form. Output of ToBidiagonal subroutine. M - number of rows in matrix A. N - number of columns in matrix A. TAUQ - scalar factors which are used to form Q. Output of ToBidiagonal subroutine. QColumns - required number of columns in matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array[0..M-1, 0..QColumns-1] If QColumns=0, the array is not modified. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixbdunpackq( real_2d_array qp, ae_int_t m, ae_int_t n, real_1d_array tauq, ae_int_t qcolumns, real_2d_array& q);
/************************************************************************* Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, where Q is an orthogonal matrix, H - Hessenberg matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A with elements [0..N-1, 0..N-1] N - size of matrix A. Output parameters: A - matrices Q and P in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..N-2] Matrix H is located on the main diagonal, on the lower secondary diagonal and above the main diagonal of matrix A. The elements which are used to form matrix Q are situated in array Tau and below the lower secondary diagonal of matrix A as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(n-2), where each H(i) is given by H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - is a real vector, so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/
void alglib::rmatrixhessenberg( real_2d_array& a, ae_int_t n, real_1d_array& tau);
/************************************************************************* Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Output parameters: H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixhessenbergunpackh( real_2d_array a, ae_int_t n, real_2d_array& h);
/************************************************************************* Unpacking matrix Q which reduces matrix A to upper Hessenberg form COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - output of RMatrixHessenberg subroutine. N - size of matrix A. Tau - scalar factors which are used to form Q. Output of RMatrixHessenberg subroutine. Output parameters: Q - matrix Q. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- 2005-2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixhessenbergunpackq( real_2d_array a, ae_int_t n, real_1d_array tau, real_2d_array& q);
/************************************************************************* LQ decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices L and Q in compact form (see below) Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0..Min(M,N)-1]. Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. The elements of matrix L are located on and below the main diagonal of matrix A. The elements which are located in Tau array and above the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(k-1)*H(k-2)*...*H(1)*H(0), where k = min(m,n), and each H(i) is of the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlq( real_2d_array& a, ae_int_t m, ae_int_t n, real_1d_array& tau); void alglib::smp_rmatrixlq( real_2d_array& a, ae_int_t m, ae_int_t n, real_1d_array& tau);
/************************************************************************* Unpacking of matrix L from the LQ decomposition of a matrix A Input parameters: A - matrices Q and L in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: L - matrix L, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlqunpackl( real_2d_array a, ae_int_t m, ae_int_t n, real_2d_array& l);
/************************************************************************* Partial unpacking of matrix Q from the LQ decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices L and Q in compact form. Output of RMatrixLQ subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixLQ subroutine. QRows - required number of rows in matrix Q. N>=QRows>=0. Output parameters: Q - first QRows rows of matrix Q. Array whose indexes range within [0..QRows-1, 0..N-1]. If QRows=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlqunpackq( real_2d_array a, ae_int_t m, ae_int_t n, real_1d_array tau, ae_int_t qrows, real_2d_array& q); void alglib::smp_rmatrixlqunpackq( real_2d_array a, ae_int_t m, ae_int_t n, real_1d_array tau, ae_int_t qrows, real_2d_array& q);
/************************************************************************* QR decomposition of a rectangular matrix of size MxN COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix A whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. Output parameters: A - matrices Q and R in compact form (see below). Tau - array of scalar factors which are used to form matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. Matrix A is represented as A = QR, where Q is an orthogonal matrix of size MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. The elements of matrix R are located on and above the main diagonal of matrix A. The elements which are located in Tau array and below the main diagonal of matrix A are used to form matrix Q as follows: Matrix Q is represented as a product of elementary reflections Q = H(0)*H(2)*...*H(k-1), where k = min(m,n), and each H(i) is in the form H(i) = 1 - tau * v * (v^T) where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixqr( real_2d_array& a, ae_int_t m, ae_int_t n, real_1d_array& tau); void alglib::smp_rmatrixqr( real_2d_array& a, ae_int_t m, ae_int_t n, real_1d_array& tau);
/************************************************************************* Partial unpacking of matrix Q from the QR decomposition of a matrix A COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that QP decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=512, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Tau - scalar factors which are used to form Q. Output of the RMatrixQR subroutine. QColumns - required number of columns of matrix Q. M>=QColumns>=0. Output parameters: Q - first QColumns columns of matrix Q. Array whose indexes range within [0..M-1, 0..QColumns-1]. If QColumns=0, the array remains unchanged. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixqrunpackq( real_2d_array a, ae_int_t m, ae_int_t n, real_1d_array tau, ae_int_t qcolumns, real_2d_array& q); void alglib::smp_rmatrixqrunpackq( real_2d_array a, ae_int_t m, ae_int_t n, real_1d_array tau, ae_int_t qcolumns, real_2d_array& q);
/************************************************************************* Unpacking of matrix R from the QR decomposition of a matrix A Input parameters: A - matrices Q and R in compact form. Output of RMatrixQR subroutine. M - number of rows in given matrix A. M>=0. N - number of columns in given matrix A. N>=0. Output parameters: R - matrix R, array[0..M-1, 0..N-1]. -- ALGLIB routine -- 17.02.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixqrunpackr( real_2d_array a, ae_int_t m, ae_int_t n, real_2d_array& r);
/************************************************************************* Reduction of a symmetric matrix which is given by its higher or lower triangular part to a tridiagonal matrix using orthogonal similarity transformation: Q'*A*Q=T. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - matrix to be transformed array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. If IsUpper = True, then matrix A is given by its upper triangle, and the lower triangle is not used and not modified by the algorithm, and vice versa if IsUpper = False. Output parameters: A - matrices T and Q in compact form (see lower) Tau - array of factors which are forming matrices H(i) array with elements [0..N-2]. D - main diagonal of symmetric matrix T. array with elements [0..N-1]. E - secondary diagonal of symmetric matrix T. array with elements [0..N-2]. If IsUpper=True, the matrix Q is represented as a product of elementary reflectors Q = H(n-2) . . . H(2) H(0). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in A(0:i-1,i+1), and tau in TAU(i). If IsUpper=False, the matrix Q is represented as a product of elementary reflectors Q = H(0) H(2) . . . H(n-2). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), and tau in TAU(i). The contents of A on exit are illustrated by the following examples with n = 5: if UPLO = 'U': if UPLO = 'L': ( d e v1 v2 v3 ) ( d ) ( d e v2 v3 ) ( e d ) ( d e v3 ) ( v0 e d ) ( d e ) ( v0 v1 e d ) ( d ) ( v0 v1 v2 e d ) where d and e denote diagonal and off-diagonal elements of T, and vi denotes an element of the vector defining H(i). -- LAPACK routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 *************************************************************************/
void alglib::smatrixtd( real_2d_array& a, ae_int_t n, bool isupper, real_1d_array& tau, real_1d_array& d, real_1d_array& e);
/************************************************************************* Unpacking matrix Q which reduces symmetric matrix to a tridiagonal form. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - the result of a SMatrixTD subroutine N - size of matrix A. IsUpper - storage format (a parameter of SMatrixTD subroutine) Tau - the result of a SMatrixTD subroutine Output parameters: Q - transformation matrix. array with elements [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005-2010 by Bochkanov Sergey *************************************************************************/
void alglib::smatrixtdunpackq( real_2d_array a, ae_int_t n, bool isupper, real_1d_array tau, real_2d_array& q);
/************************************************************************* Parametric spline inteprolant: 2-dimensional curve. You should not try to access its members directly - use PSpline2XXXXXXXX() functions instead. *************************************************************************/
class pspline2interpolant { };
/************************************************************************* Parametric spline inteprolant: 3-dimensional curve. You should not try to access its members directly - use PSpline3XXXXXXXX() functions instead. *************************************************************************/
class pspline3interpolant { };
/************************************************************************* This subroutine fits piecewise linear curve to points with Ramer-Douglas- Peucker algorithm. This function performs PARAMETRIC fit, i.e. it can be used to fit curves like circles. On input it accepts dataset which describes parametric multidimensional curve X(t), with X being vector, and t taking values in [0,N), where N is a number of points in dataset. As result, it returns reduced dataset X2, which can be used to build parametric curve X2(t), which approximates X(t) with desired precision (or has specified number of sections). INPUT PARAMETERS: X - array of multidimensional points: * at least N elements, leading N elements are used if more than N elements were specified * order of points is IMPORTANT because it is parametric fit * each row of array is one point which has D coordinates N - number of elements in X D - number of dimensions (elements per row of X) StopM - stopping condition - desired number of sections: * at most M sections are generated by this function * less than M sections can be generated if we have N<M (or some X are non-distinct). * zero StopM means that algorithm does not stop after achieving some pre-specified section count StopEps - stopping condition - desired precision: * algorithm stops after error in each section is at most Eps * zero Eps means that algorithm does not stop after achieving some pre-specified precision OUTPUT PARAMETERS: X2 - array of corner points for piecewise approximation, has length NSections+1 or zero (for NSections=0). Idx2 - array of indexes (parameter values): * has length NSections+1 or zero (for NSections=0). * each element of Idx2 corresponds to same-numbered element of X2 * each element of Idx2 is index of corresponding element of X2 at original array X, i.e. I-th row of X2 is Idx2[I]-th row of X. * elements of Idx2 can be treated as parameter values which should be used when building new parametric curve * Idx2[0]=0, Idx2[NSections]=N-1 NSections- number of sections found by algorithm, NSections<=M, NSections can be zero for degenerate datasets (N<=1 or all X[] are non-distinct). NOTE: algorithm stops after: a) dividing curve into StopM sections b) achieving required precision StopEps c) dividing curve into N-1 sections If both StopM and StopEps are non-zero, algorithm is stopped by the FIRST criterion which is satisfied. In case both StopM and StopEps are zero, algorithm stops because of (c). -- ALGLIB -- Copyright 02.10.2014 by Bochkanov Sergey *************************************************************************/
void alglib::parametricrdpfixed( real_2d_array x, ae_int_t n, ae_int_t d, ae_int_t stopm, double stopeps, real_2d_array& x2, integer_1d_array& idx2, ae_int_t& nsections);

Examples:   [1]  

/************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * B<A will result in negative length returned RESULT: length of arc starting at T=A and ending at T=B. -- ALGLIB PROJECT -- Copyright 30.05.2010 by Bochkanov Sergey *************************************************************************/
double alglib::pspline2arclength( pspline2interpolant p, double a, double b);
/************************************************************************* This function builds non-periodic 2-dimensional parametric spline which starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. Order of points is important! N - points count, N>=5 for Akima splines, N>=2 for other types of splines. ST - spline type: * 0 Akima spline * 1 parabolically terminated Catmull-Rom spline (Tension=0) * 2 parabolically terminated cubic spline PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2build( real_2d_array xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant& p);
/************************************************************************* This function builds periodic 2-dimensional parametric spline which starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then back to (X[0],Y[0]). INPUT PARAMETERS: XY - points, array[0..N-1,0..1]. XY[I,0:1] corresponds to the Ith point. XY[N-1,0:1] must be different from XY[0,0:1]. Order of points is important! N - points count, N>=3 for other types of splines. ST - spline type: * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions * 2 cubic spline with cyclic boundary conditions PT - parameterization type: * 0 uniform * 1 chord length * 2 centripetal OUTPUT PARAMETERS: P - parametric spline interpolant NOTES: * this function assumes that there all consequent points are distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. However, non-consequent points may coincide, i.e. we can have (x0,y0)= =(x2,y2). * last point of sequence is NOT equal to the first point. You shouldn't make curve "explicitly periodic" by making them equal. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2buildperiodic( real_2d_array xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline2interpolant& p);
/************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2calc( pspline2interpolant p, double t, double& x, double& y);
/************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2diff( pspline2interpolant p, double t, double& x, double& dx, double& y, double& dy);
/************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2diff2( pspline2interpolant p, double t, double& x, double& dx, double& d2x, double& y, double& dy, double& d2y);
/************************************************************************* This function returns vector of parameter values correspoding to points. I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we have (X[0],Y[0]) = PSpline2Calc(P,U[0]), (X[1],Y[1]) = PSpline2Calc(P,U[1]), (X[2],Y[2]) = PSpline2Calc(P,U[2]), ... INPUT PARAMETERS: P - parametric spline interpolant OUTPUT PARAMETERS: N - array size T - array[0..N-1] NOTES: * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1 * for periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1 -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2parametervalues( pspline2interpolant p, ae_int_t& n, real_1d_array& t);
/************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) NOTE: X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline2tangent( pspline2interpolant p, double t, double& x, double& y);
/************************************************************************* This function calculates arc length, i.e. length of curve between t=a and t=b. INPUT PARAMETERS: P - parametric spline interpolant A,B - parameter values corresponding to arc ends: * B>A will result in positive length returned * B<A will result in negative length returned RESULT: length of arc starting at T=A and ending at T=B. -- ALGLIB PROJECT -- Copyright 30.05.2010 by Bochkanov Sergey *************************************************************************/
double alglib::pspline3arclength( pspline3interpolant p, double a, double b);
/************************************************************************* This function builds non-periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3build( real_2d_array xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant& p);
/************************************************************************* This function builds periodic 3-dimensional parametric spline which starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) and then back to (X[0],Y[0],Z[0]). Same as PSpline2Build() function, but for 3D, so we won't duplicate its description here. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3buildperiodic( real_2d_array xy, ae_int_t n, ae_int_t st, ae_int_t pt, pspline3interpolant& p);
/************************************************************************* This function calculates the value of the parametric spline for a given value of parameter T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-position Y - Y-position Z - Z-position -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3calc( pspline3interpolant p, double t, double& x, double& y, double& z);
/************************************************************************* This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - X-derivative Y - Y-value DY - Y-derivative Z - Z-value DZ - Z-derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3diff( pspline3interpolant p, double t, double& x, double& dx, double& y, double& dy, double& z, double& dz);
/************************************************************************* This function calculates first and second derivative with respect to T. INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-value DX - derivative D2X - second derivative Y - Y-value DY - derivative D2Y - second derivative Z - Z-value DZ - derivative D2Z - second derivative -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3diff2( pspline3interpolant p, double t, double& x, double& dx, double& d2x, double& y, double& dy, double& d2y, double& z, double& dz, double& d2z);
/************************************************************************* This function returns vector of parameter values correspoding to points. Same as PSpline2ParameterValues(), but for 3D. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3parametervalues( pspline3interpolant p, ae_int_t& n, real_1d_array& t);
/************************************************************************* This function calculates tangent vector for a given value of parameter T INPUT PARAMETERS: P - parametric spline interpolant T - point: * T in [0,1] corresponds to interval spanned by points * for non-periodic splines T<0 (or T>1) correspond to parts of the curve before the first (after the last) point * for periodic splines T<0 (or T>1) are projected into [0,1] by making T=T-floor(T). OUTPUT PARAMETERS: X - X-component of tangent vector (normalized) Y - Y-component of tangent vector (normalized) Z - Z-component of tangent vector (normalized) NOTE: X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. -- ALGLIB PROJECT -- Copyright 28.05.2010 by Bochkanov Sergey *************************************************************************/
void alglib::pspline3tangent( pspline3interpolant p, double t, double& x, double& y, double& z);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use RDP algorithm to approximate parametric 2D curve given by
    // locations in t=0,1,2,3 (see below), which form piecewise linear
    // trajectory through D-dimensional space (2-dimensional in our example).
    // 
    //     |
    //     |
    //     -     *     *     X2................X3
    //     |                .
    //     |               .
    //     -     *     *  .  *     *     *     *
    //     |             .
    //     |            .
    //     -     *     X1    *     *     *     *
    //     |      .....
    //     |  ....
    //     X0----|-----|-----|-----|-----|-----|---
    //
    ae_int_t npoints = 4;
    ae_int_t ndimensions = 2;
    real_2d_array x = "[[0,0],[2,1],[3,3],[6,3]]";

    //
    // Approximation of parametric curve is performed by another parametric curve
    // with lesser amount of points. It allows to work with "compressed"
    // representation, which needs smaller amount of memory. Say, in our example
    // (we allow points with error smaller than 0.8) approximation will have
    // just two sequential sections connecting X0 with X2, and X2 with X3.
    // 
    //     |
    //     |
    //     -     *     *     X2................X3
    //     |               . 
    //     |             .  
    //     -     *     .     *     *     *     *
    //     |         .    
    //     |       .     
    //     -     .     X1    *     *     *     *
    //     |   .       
    //     | .    
    //     X0----|-----|-----|-----|-----|-----|---
    //
    //
    real_2d_array y;
    integer_1d_array idxy;
    ae_int_t nsections;
    ae_int_t limitcnt = 0;
    double limiteps = 0.8;
    parametricrdpfixed(x, npoints, ndimensions, limitcnt, limiteps, y, idxy, nsections);
    printf("%d\n", int(nsections)); // EXPECTED: 2
    printf("%s\n", idxy.tostring().c_str()); // EXPECTED: [0,2,3]
    return 0;
}


pcabuildbasis
/************************************************************************* Principal components analysis Subroutine builds orthogonal basis where first axis corresponds to direction with maximum variance, second axis maximizes variance in subspace orthogonal to first axis and so on. It should be noted that, unlike LDA, PCA does not use class labels. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. Best results are achieved for high-dimensional problems ! (NVars is at least 256). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: X - dataset, array[0..NPoints-1,0..NVars-1]. matrix contains ONLY INDEPENDENT VARIABLES. NPoints - dataset size, NPoints>=0 NVars - number of independent variables, NVars>=1 OUTPUT PARAMETERS: Info - return code: * -4, if SVD subroutine haven't converged * -1, if wrong parameters has been passed (NPoints<0, NVars<1) * 1, if task is solved S2 - array[0..NVars-1]. variance values corresponding to basis vectors. V - array[0..NVars-1,0..NVars-1] matrix, whose columns store basis vectors. -- ALGLIB -- Copyright 25.08.2008 by Bochkanov Sergey *************************************************************************/
void alglib::pcabuildbasis( real_2d_array x, ae_int_t npoints, ae_int_t nvars, ae_int_t& info, real_1d_array& s2, real_2d_array& v);
/************************************************************************* Inverse Poisson distribution Finds the Poisson variable x such that the integral from 0 to x of the Poisson density is equal to the given probability y. This is accomplished using the inverse gamma integral function and the relation m = igami( k+1, y ). ACCURACY: See inverse incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invpoissondistribution(ae_int_t k, double y);
/************************************************************************* Complemented Poisson distribution Returns the sum of the terms k+1 to infinity of the Poisson distribution: inf. j -- -m m > e -- -- j! j=k+1 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the formula y = pdtrc( k, m ) = igam( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::poissoncdistribution(ae_int_t k, double m);
/************************************************************************* Poisson distribution Returns the sum of the first k+1 terms of the Poisson distribution: k j -- -m m > e -- -- j! j=0 The terms are not summed directly; instead the incomplete gamma integral is employed, according to the relation y = pdtr( k, m ) = igamc( k+1, m ). The arguments must both be positive. ACCURACY: See incomplete gamma function Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::poissondistribution(ae_int_t k, double m);
polynomialbar2cheb
polynomialbar2pow
polynomialbuild
polynomialbuildcheb1
polynomialbuildcheb2
polynomialbuildeqdist
polynomialcalccheb1
polynomialcalccheb2
polynomialcalceqdist
polynomialcheb2bar
polynomialpow2bar
polint_d_calcdiff Interpolation and differentiation using barycentric representation
polint_d_conv Conversion between power basis and barycentric representation
polint_d_spec Polynomial interpolation on special grids (equidistant, Chebyshev I/II)
/************************************************************************* Conversion from barycentric representation to Chebyshev basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form A,B - base interval for Chebyshev polynomials (see below) A<>B OUTPUT PARAMETERS T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, where Ti - I-th Chebyshev polynomial. NOTES: barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbar2cheb( barycentricinterpolant p, double a, double b, real_1d_array& t);
/************************************************************************* Conversion from barycentric representation to power basis. This function has O(N^2) complexity. INPUT PARAMETERS: P - polynomial in barycentric form C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if P was obtained as result of interpolation on [-1,+1], you can set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such representation can be obtained by using 1000.0 as offset C and 1.0 as scale S. 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return coefficients in any case, but for N>8 they will become unreliable. However, N's less than 5 are pretty safe. 3. barycentric interpolant passed as P may be either polynomial obtained from polynomial interpolation/ fitting or rational function which is NOT polynomial. We can't distinguish between these two cases, and this algorithm just tries to work assuming that P IS a polynomial. If not, algorithm will return results, but they won't have any meaning. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbar2pow( barycentricinterpolant p, real_1d_array& a); void alglib::polynomialbar2pow( barycentricinterpolant p, double c, double s, real_1d_array& a);

Examples:   [1]  

/************************************************************************* Lagrange intepolant: generation of the model on the general grid. This function has O(N^2) complexity. INPUT PARAMETERS: X - abscissas, array[0..N-1] Y - function values, array[0..N-1] N - number of points, N>=1 OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbuild( real_1d_array x, real_1d_array y, barycentricinterpolant& p); void alglib::polynomialbuild( real_1d_array x, real_1d_array y, ae_int_t n, barycentricinterpolant& p);

Examples:   [1]  

/************************************************************************* Lagrange intepolant on Chebyshev grid (first kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbuildcheb1( double a, double b, real_1d_array y, barycentricinterpolant& p); void alglib::polynomialbuildcheb1( double a, double b, real_1d_array y, ae_int_t n, barycentricinterpolant& p);

Examples:   [1]  

/************************************************************************* Lagrange intepolant on Chebyshev grid (second kind). This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1], Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbuildcheb2( double a, double b, real_1d_array y, barycentricinterpolant& p); void alglib::polynomialbuildcheb2( double a, double b, real_1d_array y, ae_int_t n, barycentricinterpolant& p);

Examples:   [1]  

/************************************************************************* Lagrange intepolant: generation of the model on equidistant grid. This function has O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] Y - function values at the nodes, array[0..N-1] N - number of points, N>=1 for N=1 a constant model is constructed. OUTPUT PARAMETERS P - barycentric model which represents Lagrange interpolant (see ratint unit info and BarycentricCalc() description for more information). -- ALGLIB -- Copyright 03.12.2009 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialbuildeqdist( double a, double b, real_1d_array y, barycentricinterpolant& p); void alglib::polynomialbuildeqdist( double a, double b, real_1d_array y, ae_int_t n, barycentricinterpolant& p);

Examples:   [1]  

/************************************************************************* Fast polynomial interpolation function on Chebyshev points (first kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (first kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb1()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
double alglib::polynomialcalccheb1( double a, double b, real_1d_array f, double t); double alglib::polynomialcalccheb1( double a, double b, real_1d_array f, ae_int_t n, double t);

Examples:   [1]  

/************************************************************************* Fast polynomial interpolation function on Chebyshev points (second kind) with O(N) complexity. INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on Chebyshev grid (second kind), X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolIntBuildCheb2()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
double alglib::polynomialcalccheb2( double a, double b, real_1d_array f, double t); double alglib::polynomialcalccheb2( double a, double b, real_1d_array f, ae_int_t n, double t);

Examples:   [1]  

/************************************************************************* Fast equidistant polynomial interpolation function with O(N) complexity INPUT PARAMETERS: A - left boundary of [A,B] B - right boundary of [A,B] F - function values, array[0..N-1] N - number of points on equidistant grid, N>=1 for N=1 a constant model is constructed. T - position where P(x) is calculated RESULT value of the Lagrange interpolant at T IMPORTANT this function provides fast interface which is not overflow-safe nor it is very precise. the best option is to use PolynomialBuildEqDist()/BarycentricCalc() subroutines unless you are pretty sure that your data will not result in overflow. -- ALGLIB -- Copyright 02.12.2009 by Bochkanov Sergey *************************************************************************/
double alglib::polynomialcalceqdist( double a, double b, real_1d_array f, double t); double alglib::polynomialcalceqdist( double a, double b, real_1d_array f, ae_int_t n, double t);

Examples:   [1]  

/************************************************************************* Conversion from Chebyshev basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: T - coefficients of Chebyshev representation; P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, where Ti - I-th Chebyshev polynomial. N - number of coefficients: * if given, only leading N elements of T are used * if not given, automatically determined from size of T A,B - base interval for Chebyshev polynomials (see above) A<B OUTPUT PARAMETERS P - polynomial in barycentric form -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialcheb2bar( real_1d_array t, double a, double b, barycentricinterpolant& p); void alglib::polynomialcheb2bar( real_1d_array t, ae_int_t n, double a, double b, barycentricinterpolant& p);
/************************************************************************* Conversion from power basis to barycentric representation. This function has O(N^2) complexity. INPUT PARAMETERS: A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } N - number of coefficients (polynomial degree plus 1) * if given, only leading N elements of A are used * if not given, automatically determined from size of A C - offset (see below); 0.0 is used as default value. S - scale (see below); 1.0 is used as default value. S<>0. OUTPUT PARAMETERS P - polynomial in barycentric form NOTES: 1. this function accepts offset and scale, which can be set to improve numerical properties of polynomial. For example, if you interpolate on [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, x^3 and so on. In most cases you it is exactly what you need. However, if your interpolation model was built on [999,1001], you will see significant growth of numerical errors when using {1, x, x^2, x^3} as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option (you have to specify 1000.0 as offset C and 1.0 as scale S). 2. power basis is ill-conditioned and tricks described above can't solve this problem completely. This function will return barycentric model in any case, but for N>8 accuracy well degrade. However, N's less than 5 are pretty safe. -- ALGLIB -- Copyright 30.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialpow2bar( real_1d_array a, barycentricinterpolant& p); void alglib::polynomialpow2bar( real_1d_array a, ae_int_t n, double c, double s, barycentricinterpolant& p);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Here we demonstrate polynomial interpolation and differentiation
    // of y=x^2-x sampled at [0,1,2]. Barycentric representation of polynomial is used.
    //
    real_1d_array x = "[0,1,2]";
    real_1d_array y = "[0,0,2]";
    double t = -1;
    double v;
    double dv;
    double d2v;
    barycentricinterpolant p;

    // barycentric model is created
    polynomialbuild(x, y, p);

    // barycentric interpolation is demonstrated
    v = barycentriccalc(p, t);
    printf("%.4f\n", double(v)); // EXPECTED: 2.0

    // barycentric differentation is demonstrated
    barycentricdiff1(p, t, v, dv);
    printf("%.4f\n", double(v)); // EXPECTED: 2.0
    printf("%.4f\n", double(dv)); // EXPECTED: -3.0

    // second derivatives with barycentric representation
    barycentricdiff1(p, t, v, dv);
    printf("%.4f\n", double(v)); // EXPECTED: 2.0
    printf("%.4f\n", double(dv)); // EXPECTED: -3.0
    barycentricdiff2(p, t, v, dv, d2v);
    printf("%.4f\n", double(v)); // EXPECTED: 2.0
    printf("%.4f\n", double(dv)); // EXPECTED: -3.0
    printf("%.4f\n", double(d2v)); // EXPECTED: 2.0
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Here we demonstrate conversion of y=x^2-x
    // between power basis and barycentric representation.
    //
    real_1d_array a = "[0,-1,+1]";
    double t = 2;
    real_1d_array a2;
    double v;
    barycentricinterpolant p;

    //
    // a=[0,-1,+1] is decomposition of y=x^2-x in the power basis:
    //
    //     y = 0 - 1*x + 1*x^2
    //
    // We convert it to the barycentric form.
    //
    polynomialpow2bar(a, p);

    // now we have barycentric interpolation; we can use it for interpolation
    v = barycentriccalc(p, t);
    printf("%.2f\n", double(v)); // EXPECTED: 2.0

    // we can also convert back from barycentric representation to power basis
    polynomialbar2pow(p, a2);
    printf("%s\n", a2.tostring(2).c_str()); // EXPECTED: [0,-1,+1]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Temporaries:
    // * values of y=x^2-x sampled at three special grids:
    //   * equdistant grid spanning [0,2],     x[i] = 2*i/(N-1), i=0..N-1
    //   * Chebyshev-I grid spanning [-1,+1],  x[i] = 1 + Cos(PI*(2*i+1)/(2*n)), i=0..N-1
    //   * Chebyshev-II grid spanning [-1,+1], x[i] = 1 + Cos(PI*i/(n-1)), i=0..N-1
    // * barycentric interpolants for these three grids
    // * vectors to store coefficients of quadratic representation
    //
    real_1d_array y_eqdist = "[0,0,2]";
    real_1d_array y_cheb1 = "[-0.116025,0.000000,1.616025]";
    real_1d_array y_cheb2 = "[0,0,2]";
    barycentricinterpolant p_eqdist;
    barycentricinterpolant p_cheb1;
    barycentricinterpolant p_cheb2;
    real_1d_array a_eqdist;
    real_1d_array a_cheb1;
    real_1d_array a_cheb2;

    //
    // First, we demonstrate construction of barycentric interpolants on
    // special grids. We unpack power representation to ensure that
    // interpolant was built correctly.
    //
    // In all three cases we should get same quadratic function.
    //
    polynomialbuildeqdist(0.0, 2.0, y_eqdist, p_eqdist);
    polynomialbar2pow(p_eqdist, a_eqdist);
    printf("%s\n", a_eqdist.tostring(4).c_str()); // EXPECTED: [0,-1,+1]

    polynomialbuildcheb1(-1, +1, y_cheb1, p_cheb1);
    polynomialbar2pow(p_cheb1, a_cheb1);
    printf("%s\n", a_cheb1.tostring(4).c_str()); // EXPECTED: [0,-1,+1]

    polynomialbuildcheb2(-1, +1, y_cheb2, p_cheb2);
    polynomialbar2pow(p_cheb2, a_cheb2);
    printf("%s\n", a_cheb2.tostring(4).c_str()); // EXPECTED: [0,-1,+1]

    //
    // Now we demonstrate polynomial interpolation without construction 
    // of the barycentricinterpolant structure.
    //
    // We calculate interpolant value at x=-2.
    // In all three cases we should get same f=6
    //
    double t = -2;
    double v;
    v = polynomialcalceqdist(0.0, 2.0, y_eqdist, t);
    printf("%.4f\n", double(v)); // EXPECTED: 6.0

    v = polynomialcalccheb1(-1, +1, y_cheb1, t);
    printf("%.4f\n", double(v)); // EXPECTED: 6.0

    v = polynomialcalccheb2(-1, +1, y_cheb2, t);
    printf("%.4f\n", double(v)); // EXPECTED: 6.0
    return 0;
}


polynomialsolverreport
polynomialsolve
/************************************************************************* *************************************************************************/
class polynomialsolverreport { double maxerr; };
/************************************************************************* Polynomial root finding. This function returns all roots of the polynomial P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n Both real and complex roots are returned (see below). INPUT PARAMETERS: A - array[N+1], polynomial coefficients: * A[0] is constant term * A[N] is a coefficient of X^N N - polynomial degree OUTPUT PARAMETERS: X - array of complex roots: * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 * complex roots are always returned in pairs - roots occupy positions I and I+1, with: * X[I+1]=Conj(X[I]) * IMAGE(X[I]) > 0 * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 * multiple real roots may have non-zero imaginary part due to roundoff errors. There is no reliable way to distinguish real root of multiplicity 2 from two complex roots in the presence of roundoff errors. Rep - report, additional information, following fields are set: * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field allows to quickly estimate "quality" of the roots being returned. NOTE: this function uses companion matrix method to find roots. In case internal EVD solver fails do find eigenvalues, exception is generated. NOTE: roots are not "polished" and no matrix balancing is performed for them. -- ALGLIB -- Copyright 24.02.2014 by Bochkanov Sergey *************************************************************************/
void alglib::polynomialsolve( real_1d_array a, ae_int_t n, complex_1d_array& x, polynomialsolverreport& rep);
psi
/************************************************************************* Psi (digamma) function d - psi(x) = -- ln | (x) dx is the logarithmic derivative of the gamma function. For integer x, n-1 - psi(n) = -EUL + > 1/k. - k=1 This formula is used for 0 < n <= 10. If x is negative, it is transformed to a positive argument by the reflection formula psi(1-x) = psi(x) + pi cot(pi x). For general positive x, the argument is made greater than 10 using the recurrence psi(x+1) = psi(x) + 1/x. Then the following asymptotic expansion is applied: inf. B - 2k psi(x) = log(x) - 1/2x - > ------- - 2k k=1 2k x where the B2k are Bernoulli numbers. ACCURACY: Relative error (except absolute when |psi| < 1): arithmetic domain # trials peak rms IEEE 0,30 30000 1.3e-15 1.4e-16 IEEE -30,0 40000 1.5e-15 2.2e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::psi(double x);
/************************************************************************* Barycentric interpolant. *************************************************************************/
class barycentricinterpolant { };
/************************************************************************* Rational interpolant without poles The subroutine constructs the rational interpolating function without real poles (see 'Barycentric rational interpolation with no poles and high rates of approximation', Michael S. Floater. and Kai Hormann, for more information on this subject). Input parameters: X - interpolation nodes, array[0..N-1]. Y - function values, array[0..N-1]. N - number of nodes, N>0. D - order of the interpolation scheme, 0 <= D <= N-1. D<0 will cause an error. D>=N it will be replaced with D=N-1. if you don't know what D to choose, use small value about 3-5. Output parameters: B - barycentric interpolant. Note: this algorithm always succeeds and calculates the weights with close to machine precision. -- ALGLIB PROJECT -- Copyright 17.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricbuildfloaterhormann( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t d, barycentricinterpolant& b);
/************************************************************************* Rational interpolant from X/Y/W arrays F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) INPUT PARAMETERS: X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] N - nodes count, N>0 OUTPUT PARAMETERS: B - barycentric interpolant built from (X, Y, W) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricbuildxyw( real_1d_array x, real_1d_array y, real_1d_array w, ae_int_t n, barycentricinterpolant& b);
/************************************************************************* Rational interpolation using barycentric formula F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) Input parameters: B - barycentric interpolant built with one of model building subroutines. T - interpolation point Result: barycentric interpolant F(t) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
double alglib::barycentriccalc(barycentricinterpolant b, double t);
/************************************************************************* Differentiation of barycentric interpolant: first derivative. Algorithm used in this subroutine is very robust and should not fail until provided with values too close to MaxRealNumber (usually MaxRealNumber/N or greater will overflow). INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative NOTE -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricdiff1( barycentricinterpolant b, double t, double& f, double& df);
/************************************************************************* Differentiation of barycentric interpolant: first/second derivatives. INPUT PARAMETERS: B - barycentric interpolant built with one of model building subroutines. T - interpolation point OUTPUT PARAMETERS: F - barycentric interpolant at T DF - first derivative D2F - second derivative NOTE: this algorithm may fail due to overflow/underflor if used on data whose values are close to MaxRealNumber or MinRealNumber. Use more robust BarycentricDiff1() subroutine in such cases. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricdiff2( barycentricinterpolant b, double t, double& f, double& df, double& d2f);
/************************************************************************* This subroutine performs linear transformation of the argument. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: x = CA*t + CB OUTPUT PARAMETERS: B - transformed interpolant with X replaced by T -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentriclintransx( barycentricinterpolant b, double ca, double cb);
/************************************************************************* This subroutine performs linear transformation of the barycentric interpolant. INPUT PARAMETERS: B - rational interpolant in barycentric form CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB OUTPUT PARAMETERS: B - transformed interpolant -- ALGLIB PROJECT -- Copyright 19.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentriclintransy( barycentricinterpolant b, double ca, double cb);
/************************************************************************* Extracts X/Y/W arrays from rational interpolant INPUT PARAMETERS: B - barycentric interpolant OUTPUT PARAMETERS: N - nodes count, N>0 X - interpolation nodes, array[0..N-1] F - function values, array[0..N-1] W - barycentric weights, array[0..N-1] -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/
void alglib::barycentricunpack( barycentricinterpolant b, ae_int_t& n, real_1d_array& x, real_1d_array& y, real_1d_array& w);
rbfmodel
rbfreport
rbfbuildmodel
rbfcalc
rbfcalc2
rbfcalc3
rbfcalcbuf
rbfcreate
rbfgridcalc2
rbfserialize
rbfsetalgomultilayer
rbfsetalgoqnn
rbfsetconstterm
rbfsetlinterm
rbfsetpoints
rbfsetzeroterm
rbfunpack
rbfunserialize
rbf_d_ml_ls Least squares problem solved with RBF-ML algorithm
rbf_d_ml_simple Simple model built with RBF-ML algorithm
rbf_d_polterm RBF models - working with polynomial term
rbf_d_qnn Simple model built with RBF-QNN algorithm
rbf_d_serialize Serialization/unserialization
rbf_d_vector Working with vector functions
/************************************************************************* RBF model. Never try to directly work with fields of this object - always use ALGLIB functions to use this object. *************************************************************************/
class rbfmodel { };
/************************************************************************* RBF solution report: * TerminationType - termination type, positive values - success, non-positive - failure. *************************************************************************/
class rbfreport { ae_int_t arows; ae_int_t acols; ae_int_t annz; ae_int_t iterationscount; ae_int_t nmv; ae_int_t terminationtype; };
/************************************************************************* This function builds RBF model and returns report (contains some information which can be used for evaluation of the algorithm properties). Call to this function modifies RBF model by calculating its centers/radii/ weights and saving them into RBFModel structure. Initially RBFModel contain zero coefficients, but after call to this function we will have coefficients which were calculated in order to fit our dataset. After you called this function you can call RBFCalc(), RBFGridCalc() and other model calculation functions. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Rep - report: * Rep.TerminationType: * -5 - non-distinct basis function centers were detected, interpolation aborted * -4 - nonconvergence of the internal SVD solver * 1 - successful termination Fields are used for debugging purposes: * Rep.IterationsCount - iterations count of the LSQR solver * Rep.NMV - number of matrix-vector products * Rep.ARows - rows count for the system matrix * Rep.ACols - columns count for the system matrix * Rep.ANNZ - number of significantly non-zero elements (elements above some algorithm-determined threshold) NOTE: failure to build model will leave current state of the structure unchanged. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfbuildmodel(rbfmodel s, rbfreport& rep);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function calculates values of the RBF model at the given point. This is general function which can be used for arbitrary NX (dimension of the space of arguments) and NY (dimension of the function itself). However when you have NY=1 you may find more convenient to use RBFCalc2() or RBFCalc3(). This function returns 0.0 when model is not initialized. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. OUTPUT PARAMETERS: Y - function value, array[NY]. Y is out-parameter and reallocated after call to this function. In case you want to reuse previously allocated Y, you may use RBFCalcBuf(), which reallocates Y only when it is too small. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfcalc(rbfmodel s, real_1d_array x, real_1d_array& y);

Examples:   [1]  

/************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=2 (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). If you want to calculate function values many times, consider using RBFGridCalc2(), which is far more efficient than many subsequent calls to RBFCalc2(). This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
double alglib::rbfcalc2(rbfmodel s, double x0, double x1);

Examples:   [1]  [2]  [3]  [4]  

/************************************************************************* This function calculates values of the RBF model in the given point. This function should be used when we have NY=1 (scalar function) and NX=3 (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If you have general situation (NX-dimensional space, NY-dimensional function) you should use general, less efficient implementation RBFCalc(). This function returns 0.0 when: * model is not initialized * NX<>3 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - first coordinate, finite number X1 - second coordinate, finite number X2 - third coordinate, finite number RESULT: value of the model or 0.0 (as defined above) -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
double alglib::rbfcalc3(rbfmodel s, double x0, double x1, double x2);
/************************************************************************* This function calculates values of the RBF model at the given point. Same as RBFCalc(), but does not reallocate Y when in is large enough to store function values. INPUT PARAMETERS: S - RBF model X - coordinates, array[NX]. X may have more than NX elements, in this case only leading NX will be used. Y - possibly preallocated array OUTPUT PARAMETERS: Y - function value, array[NY]. Y is not reallocated when it is larger than NY. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfcalcbuf(rbfmodel s, real_1d_array x, real_1d_array& y);
/************************************************************************* This function creates RBF model for a scalar (NY=1) or vector (NY>1) function in a NX-dimensional space (NX=2 or NX=3). Newly created model is empty. It can be used for interpolation right after creation, but it just returns zeros. You have to add points to the model, tune interpolation settings, and then call model construction function RBFBuildModel() which will update model according to your specification. USAGE: 1. User creates model with RBFCreate() 2. User adds dataset with RBFSetPoints() (points do NOT have to be on a regular grid) 3. (OPTIONAL) User chooses polynomial term by calling: * RBFLinTerm() to set linear term * RBFConstTerm() to set constant term * RBFZeroTerm() to set zero term By default, linear term is used. 4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) or ML (RBFSetAlgoMultiLayer). 5. User calls RBFBuildModel() function which rebuilds model according to the specification 6. User may call RBFCalc() to calculate model value at the specified point, RBFGridCalc() to calculate model values at the points of the regular grid. User may extract model coefficients with RBFUnpack() call. INPUT PARAMETERS: NX - dimension of the space, NX=2 or NX=3 NY - function dimension, NY>=1 OUTPUT PARAMETERS: S - RBF model (initially equals to zero) NOTE 1: memory requirements. RBF models require amount of memory which is proportional to the number of data points. Memory is allocated during model construction, but most of this memory is freed after model coefficients are calculated. Some approximate estimates for N centers with default settings are given below: * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is needed during model construction stage. * about 15*N*sizeof(double) bytes is needed after model is built. For example, for N=100000 we may need 0.6 GB of memory to build model, but just about 0.012 GB to store it. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel& s);

Examples:   [1]  [2]  [3]  [4]  [5]  [6]  

/************************************************************************* This function calculates values of the RBF model at the regular grid. Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) This function returns 0.0 when: * model is not initialized * NX<>2 *NY<>1 INPUT PARAMETERS: S - RBF model X0 - array of grid nodes, first coordinates, array[N0] N0 - grid size (number of nodes) in the first dimension X1 - array of grid nodes, second coordinates, array[N1] N1 - grid size (number of nodes) in the second dimension OUTPUT PARAMETERS: Y - function values, array[N0,N1]. Y is out-variable and is reallocated by this function. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfgridcalc2( rbfmodel s, real_1d_array x0, ae_int_t n0, real_1d_array x1, ae_int_t n1, real_2d_array& y);
/************************************************************************* This function serializes data structure to string. Important properties of s_out: * it contains alphanumeric characters, dots, underscores, minus signs * these symbols are grouped into words, which are separated by spaces and Windows-style (CR+LF) newlines * although serializer uses spaces and CR+LF as separators, you can replace any separator character by arbitrary combination of spaces, tabs, Windows or Unix newlines. It allows flexible reformatting of the string in case you want to include it into text or XML file. But you should not insert separators into the middle of the "words" nor you should change case of letters. * s_out can be freely moved between 32-bit and 64-bit systems, little and big endian machines, and so on. You can serialize structure on 32-bit machine and unserialize it on 64-bit one (or vice versa), or serialize it on SPARC and unserialize on x86. You can also serialize it in C++ version of ALGLIB and unserialize in C# one, and vice versa. *************************************************************************/
void rbfserialize(rbfmodel &obj, std::string &s_out);
/************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. model with subsequently decreasing radii, which allows us to combine smoothness (due to large radii of the first layers) with exactness (due to small radii of the last layers) and fast convergence. Internally RBF-ML uses many different means of acceleration, from sparse matrices to KD-trees, which results in algorithm whose working time is roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a number of points, Density is an average density if points per unit of the interpolation space, RBase is an initial radius, NLayers is a number of layers. RBF-ML is good for following kinds of interpolation problems: 1. "exact" problems (perfect fit) with well separated points 2. least squares problems with arbitrary distribution of points (algorithm gives perfect fit where it is possible, and resorts to least squares fit in the hard areas). 3. noisy problems where we want to apply some controlled amount of smoothing. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call RBase - RBase parameter, RBase>0 NLayers - NLayers parameter, NLayers>0, recommended value to start with - about 5. LambdaV - regularization value, can be useful when solving problem in the least squares sense. Optimal lambda is problem- dependent and require trial and error. In our experience, good lambda can be as large as 0.1, and you can use 0.001 as initial guess. Default value - 0.01, which is used when LambdaV is not given. You can specify zero value, but it is not recommended to do so. TUNING ALGORITHM In order to use this algorithm you have to choose three parameters: * initial radius RBase * number of layers in the model NLayers * regularization coefficient LambdaV Initial radius is easy to choose - you can pick any number several times larger than the average distance between points. Algorithm won't break down if you choose radius which is too large (model construction time will increase, but model will be built correctly). Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used by the last layer) will be smaller than the typical distance between points. In case model error is too large, you can increase number of layers. Having more layers will make model construction and evaluation proportionally slower, but it will allow you to have model which precisely fits your data. From the other side, if you want to suppress noise, you can DECREASE number of layers to make your model less flexible. Regularization coefficient LambdaV controls smoothness of the individual models built for each layer. We recommend you to use default value in case you don't want to tune this parameter, because having non-zero LambdaV accelerates and stabilizes internal iterative algorithm. In case you want to suppress noise you can use LambdaV as additional parameter (larger value = more smoothness) to tune. TYPICAL ERRORS 1. Using initial radius which is too large. Memory requirements of the RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is an average density of points per unit of the interpolation space). In the extreme case of the very large RBase we will need O(N^2) units of memory - and many layers in order to decrease radius to some reasonably small value. 2. Using too small number of layers - RBF models with large radius are not flexible enough to reproduce small variations in the target function. You need many layers with different radii, from large to small, in order to have good model. 3. Using initial radius which is too small. You will get model with "holes" in the areas which are too far away from interpolation centers. However, algorithm will work correctly (and quickly) in this case. 4. Using too many layers - you will get too large and too slow model. This model will perfectly reproduce your function, but maybe you will be able to achieve similar results with less layers (and less memory). -- ALGLIB -- Copyright 02.03.2012 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetalgomultilayer( rbfmodel s, double rbase, ae_int_t nlayers); void alglib::rbfsetalgomultilayer( rbfmodel s, double rbase, ae_int_t nlayers, double lambdav);

Examples:   [1]  [2]  

/************************************************************************* This function sets RBF interpolation algorithm. ALGLIB supports several RBF algorithms with different properties. This algorithm is called RBF-QNN and it is good for point sets with following properties: a) all points are distinct b) all points are well separated. c) points distribution is approximately uniform. There is no "contour lines", clusters of points, or other small-scale structures. Algorithm description: 1) interpolation centers are allocated to data points 2) interpolation radii are calculated as distances to the nearest centers times Q coefficient (where Q is a value from [0.75,1.50]). 3) after performing (2) radii are transformed in order to avoid situation when single outlier has very large radius and influences many points across all dataset. Transformation has following form: new_r[i] = min(r[i],Z*median(r[])) where r[i] is I-th radius, median() is a median radius across entire dataset, Z is user-specified value which controls amount of deviation from median radius. When (a) is violated, we will be unable to build RBF model. When (b) or (c) are violated, model will be built, but interpolation quality will be low. See http://www.alglib.net/interpolation/ for more information on this subject. This algorithm is used by default. Additional Q parameter controls smoothness properties of the RBF basis: * Q<0.75 will give perfectly conditioned basis, but terrible smoothness properties (RBF interpolant will have sharp peaks around function values) * Q around 1.0 gives good balance between smoothness and condition number * Q>1.5 will lead to badly conditioned systems and slow convergence of the underlying linear solver (although smoothness will be very good) * Q>2.0 will effectively make optimizer useless because it won't converge within reasonable amount of iterations. It is possible to set such large Q, but it is advised not to do so. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call Q - Q parameter, Q>0, recommended value - 1.0 Z - Z parameter, Z>0, recommended value - 5.0 NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetalgoqnn(rbfmodel s); void alglib::rbfsetalgoqnn(rbfmodel s, double q, double z);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function sets constant term (model is a sum of radial basis functions plus constant). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetconstterm(rbfmodel s);

Examples:   [1]  

/************************************************************************* This function sets linear term (model is a sum of radial basis functions plus linear polynomial). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetlinterm(rbfmodel s);

Examples:   [1]  

/************************************************************************* This function adds dataset. This function overrides results of the previous calls, i.e. multiple calls of this function will result in only the last set being added. INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call. XY - points, array[N,NX+NY]. One row corresponds to one point in the dataset. First NX elements are coordinates, next NY elements are function values. Array may be larger than specific, in this case only leading [N,NX+NY] elements will be used. N - number of points in the dataset After you've added dataset and (optionally) tuned algorithm settings you should call RBFBuildModel() in order to build a model for you. NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetpoints(rbfmodel s, real_2d_array xy); void alglib::rbfsetpoints(rbfmodel s, real_2d_array xy, ae_int_t n);

Examples:   [1]  [2]  [3]  [4]  [5]  

/************************************************************************* This function sets zero term (model is a sum of radial basis functions without polynomial term). This function won't have effect until next call to RBFBuildModel(). INPUT PARAMETERS: S - RBF model, initialized by RBFCreate() call NOTE: this function has some serialization-related subtleties. We recommend you to study serialization examples from ALGLIB Reference Manual if you want to perform serialization of your models. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfsetzeroterm(rbfmodel s);

Examples:   [1]  

/************************************************************************* This function "unpacks" RBF model by extracting its coefficients. INPUT PARAMETERS: S - RBF model OUTPUT PARAMETERS: NX - dimensionality of argument NY - dimensionality of the target function XWR - model information, array[NC,NX+NY+1]. One row of the array corresponds to one basis function: * first NX columns - coordinates of the center * next NY columns - weights, one per dimension of the function being modelled * last column - radius, same for all dimensions of the function being modelled NC - number of the centers V - polynomial term , array[NY,NX+1]. One row per one dimension of the function being modelled. First NX elements are linear coefficients, V[NX] is equal to the constant part. -- ALGLIB -- Copyright 13.12.2011 by Bochkanov Sergey *************************************************************************/
void alglib::rbfunpack( rbfmodel s, ae_int_t& nx, ae_int_t& ny, real_2d_array& xwr, ae_int_t& nc, real_2d_array& v);

Examples:   [1]  

/************************************************************************* This function unserializes data structure from string. *************************************************************************/
void rbfunserialize(std::string &s_in, rbfmodel &obj);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example shows how to solve least squares problems with RBF-ML algorithm.
    // Below we assume that you already know basic concepts shown in the RBF_D_QNN and
    // RBF_D_ML_SIMPLE examples.
    //
    rbfmodel model;
    rbfreport rep;
    double v;

    //
    // We have 2-dimensional space and very simple fitting problem - all points
    // except for two are well separated and located at straight line. Two
    // "exceptional" points are very close, with distance between them as small
    // as 0.01. RBF-QNN algorithm will have many difficulties with such distribution
    // of points:
    //     X        Y
    //     -2       1
    //     -1       0
    //     -0.005   1
    //     +0.005   2
    //     +1      -1
    //     +2       1
    // How will RBF-ML handle such problem?
    //
    rbfcreate(2, 1, model);
    real_2d_array xy0 = "[[-2,0,1],[-1,0,0],[-0.005,0,1],[+0.005,0,2],[+1,0,-1],[+2,0,1]]";
    rbfsetpoints(model, xy0);

    // First, we try to use R=5.0 with single layer (NLayers=1) and moderate amount
    // of regularization. Well, we already expected that results will be bad:
    //     Model(x=-2,y=0)=0.8407    (instead of 1.0)
    //     Model(x=0.005,y=0)=0.6584 (instead of 2.0)
    // We need more layers to show better results.
    rbfsetalgomultilayer(model, 5.0, 1, 1.0e-3);
    rbfbuildmodel(model, rep);
    v = rbfcalc2(model, -2.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.8407981659
    v = rbfcalc2(model, 0.005, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.6584267649

    // With 4 layers we got better result at x=-2 (point which is well separated
    // from its neighbors). Model is now many times closer to the original data
    //     Model(x=-2,y=0)=0.9992    (instead of 1.0)
    //     Model(x=0.005,y=0)=1.5534 (instead of 2.0)
    // We may see that at x=0.005 result is a bit closer to 2.0, but does not
    // reproduce function value precisely because of close neighbor located at
    // at x=-0.005. Let's add two layers...
    rbfsetalgomultilayer(model, 5.0, 4, 1.0e-3);
    rbfbuildmodel(model, rep);
    v = rbfcalc2(model, -2.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.9992673278
    v = rbfcalc2(model, 0.005, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.5534666012

    // With 6 layers we got almost perfect fit:
    //     Model(x=-2,y=0)=1.000    (perfect fit)
    //     Model(x=0.005,y=0)=1.996 (instead of 2.0)
    // Of course, we can reduce error at x=0.005 down to zero by adding more
    // layers. But do we really need it?
    rbfsetalgomultilayer(model, 5.0, 6, 1.0e-3);
    rbfbuildmodel(model, rep);
    v = rbfcalc2(model, -2.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.0000000000
    v = rbfcalc2(model, 0.005, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.9965775952

    // Do we really need zero error? We have f(+0.005)=2 and f(-0.005)=1.
    // Two points are very close, and in real life situations it often means
    // that difference in function values can be explained by noise in the
    // data. Thus, true value of the underlying function should be close to
    // 1.5 (halfway between 1.0 and 2.0).
    //
    // How can we get such result with RBF-ML? Well, we can:
    // a) reduce number of layers (make model less flexible)
    // b) increase regularization coefficient (another way of reducing flexibility)
    //
    // Having NLayers=5 and LambdaV=0.1 gives us good least squares fit to the data:
    //     Model(x=-2,y=0)=1.000
    //     Model(x=-0.005,y=0)=1.504
    //     Model(x=+0.005,y=0)=1.496
    rbfsetalgomultilayer(model, 5.0, 5, 1.0e-1);
    rbfbuildmodel(model, rep);
    v = rbfcalc2(model, -2.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.0000001620
    v = rbfcalc2(model, -0.005, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.5042954378
    v = rbfcalc2(model, 0.005, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.4957042013
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example shows how to build models with RBF-ML algorithm. Below
    // we assume that you already know basic concepts shown in the example
    // on RBF-QNN algorithm.
    //
    // RBF-ML is a multilayer RBF algorithm, which fits a sequence of models
    // with decreasing radii. Each model is fitted with fixed number of
    // iterations of linear solver. First layers give only inexact approximation
    // of the target function, because RBF problems with large radii are
    // ill-conditioned. However, as we add more and more layers with smaller
    // and smaller radii, we get better conditioned systems - and more precise models.
    //
    rbfmodel model;
    rbfreport rep;
    double v;

    //
    // We have 2-dimensional space and very simple interpolation problem - all
    // points are distinct and located at straight line. We want to solve it
    // with RBF-ML algorithm. This problem is very simple, and RBF-QNN will
    // solve it too, but we want to evaluate RBF-ML and to start from the simple
    // problem.
    //     X        Y
    //     -2       1
    //     -1       0
    //      0       1
    //     +1      -1
    //     +2       1
    //
    rbfcreate(2, 1, model);
    real_2d_array xy0 = "[[-2,0,1],[-1,0,0],[0,0,1],[+1,0,-1],[+2,0,1]]";
    rbfsetpoints(model, xy0);

    // First, we try to use R=5.0 with single layer (NLayers=1) and moderate amount
    // of regularization.... but results are disappointing: Model(x=0,y=0)=-0.02,
    // and we need 1.0 at (x,y)=(0,0). Why?
    //
    // Because first layer gives very smooth and imprecise approximation of the
    // function. Average distance between points is 1.0, and R=5.0 is too large
    // to give us flexible model. It can give smoothness, but can't give precision.
    // So we need more layers with smaller radii.
    rbfsetalgomultilayer(model, 5.0, 1, 1.0e-3);
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    v = rbfcalc2(model, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: -0.021690

    // Now we know that single layer is not enough. We still want to start with
    // R=5.0 because it has good smoothness properties, but we will add more layers,
    // each with R[i+1]=R[i]/2. We think that 4 layers is enough, because last layer
    // will have R = 5.0/2^3 = 5/8 ~ 0.63, which is smaller than the average distance
    // between points. And it works!
    rbfsetalgomultilayer(model, 5.0, 4, 1.0e-3);
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    v = rbfcalc2(model, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 1.000000

    // BTW, if you look at v, you will see that it is equal to 0.9999999997, not to 1.
    // This small error can be fixed by adding one more layer.
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example show how to work with polynomial term
    // 
    // Suppose that we have set of 2-dimensional points with associated
    // scalar function values, and we want to build a RBF model using
    // our data.
    //
    double v;
    rbfmodel model;
    real_2d_array xy = "[[-1,0,2],[+1,0,3]]";
    rbfreport rep;

    rbfcreate(2, 1, model);
    rbfsetpoints(model, xy);
    rbfsetalgoqnn(model);

    //
    // By default, RBF model uses linear term. It means that model
    // looks like
    //     f(x,y) = SUM(RBF[i]) + a*x + b*y + c
    // where RBF[i] is I-th radial basis function and a*x+by+c is a
    // linear term. Having linear terms in a model gives us:
    // (1) improved extrapolation properties
    // (2) linearity of the model when data can be perfectly fitted
    //     by the linear function
    // (3) linear asymptotic behavior
    //
    // Our simple dataset can be modelled by the linear function
    //     f(x,y) = 0.5*x + 2.5
    // and rbfbuildmodel() with default settings should preserve this
    // linearity.
    //
    ae_int_t nx;
    ae_int_t ny;
    ae_int_t nc;
    real_2d_array xwr;
    real_2d_array c;
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    rbfunpack(model, nx, ny, xwr, nc, c);
    printf("%s\n", c.tostring(2).c_str()); // EXPECTED: [[0.500,0.000,2.500]]

    // asymptotic behavior of our function is linear
    v = rbfcalc2(model, 1000.0, 0.0);
    printf("%.1f\n", double(v)); // EXPECTED: 502.50

    //
    // Instead of linear term we can use constant term. In this case
    // we will get model which has form
    //     f(x,y) = SUM(RBF[i]) + c
    // where RBF[i] is I-th radial basis function and c is a constant,
    // which is equal to the average function value on the dataset.
    //
    // Because we've already attached dataset to the model the only
    // thing we have to do is to call rbfsetconstterm() and then
    // rebuild model with rbfbuildmodel().
    //
    rbfsetconstterm(model);
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    rbfunpack(model, nx, ny, xwr, nc, c);
    printf("%s\n", c.tostring(2).c_str()); // EXPECTED: [[0.000,0.000,2.500]]

    // asymptotic behavior of our function is constant
    v = rbfcalc2(model, 1000.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.500

    //
    // Finally, we can use zero term. Just plain RBF without polynomial
    // part:
    //     f(x,y) = SUM(RBF[i])
    // where RBF[i] is I-th radial basis function.
    //
    rbfsetzeroterm(model);
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1
    rbfunpack(model, nx, ny, xwr, nc, c);
    printf("%s\n", c.tostring(2).c_str()); // EXPECTED: [[0.000,0.000,0.000]]

    // asymptotic behavior of our function is just zero constant
    v = rbfcalc2(model, 1000.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.000
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example illustrates basic concepts of the RBF models: creation, modification,
    // evaluation.
    // 
    // Suppose that we have set of 2-dimensional points with associated
    // scalar function values, and we want to build a RBF model using
    // our data.
    // 
    // NOTE: we can work with 3D models too :)
    // 
    // Typical sequence of steps is given below:
    // 1. we create RBF model object
    // 2. we attach our dataset to the RBF model and tune algorithm settings
    // 3. we rebuild RBF model using QNN algorithm on new data
    // 4. we use RBF model (evaluate, serialize, etc.)
    //
    double v;

    //
    // Step 1: RBF model creation.
    //
    // We have to specify dimensionality of the space (2 or 3) and
    // dimensionality of the function (scalar or vector).
    //
    rbfmodel model;
    rbfcreate(2, 1, model);

    // New model is empty - it can be evaluated,
    // but we just get zero value at any point.
    v = rbfcalc2(model, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.000

    //
    // Step 2: we add dataset.
    //
    // XY arrays containt two points - x0=(-1,0) and x1=(+1,0) -
    // and two function values f(x0)=2, f(x1)=3.
    //
    real_2d_array xy = "[[-1,0,2],[+1,0,3]]";
    rbfsetpoints(model, xy);

    // We added points, but model was not rebuild yet.
    // If we call rbfcalc2(), we still will get 0.0 as result.
    v = rbfcalc2(model, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.000

    //
    // Step 3: rebuild model
    //
    // After we've configured model, we should rebuild it -
    // it will change coefficients stored internally in the
    // rbfmodel structure.
    //
    // By default, RBF uses QNN algorithm, which works well with
    // relatively uniform datasets (all points are well separated,
    // average distance is approximately same for all points).
    // This default algorithm is perfectly suited for our simple
    // made up data.
    //
    // NOTE: we recommend you to take a look at example of RBF-ML,
    // multilayer RBF algorithm, which sometimes is a better
    // option than QNN.
    //
    rbfreport rep;
    rbfsetalgoqnn(model);
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1

    //
    // Step 4: model was built
    //
    // After call of rbfbuildmodel(), rbfcalc2() will return
    // value of the new model.
    //
    v = rbfcalc2(model, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.500
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example show how to serialize and unserialize RBF model
    // 
    // Suppose that we have set of 2-dimensional points with associated
    // scalar function values, and we want to build a RBF model using
    // our data. Then we want to serialize it to string and to unserialize
    // from string, loading to another instance of RBF model.
    //
    // Here we assume that you already know how to create RBF models.
    //
    std::string s;
    double v;
    rbfmodel model0;
    rbfmodel model1;
    real_2d_array xy = "[[-1,0,2],[+1,0,3]]";
    rbfreport rep;

    // model initialization
    rbfcreate(2, 1, model0);
    rbfsetpoints(model0, xy);
    rbfsetalgoqnn(model0);
    rbfbuildmodel(model0, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1

    //
    // Serialization - it looks easy,
    // but you should carefully read next section.
    //
    alglib::rbfserialize(model0, s);
    alglib::rbfunserialize(s, model1);

    // both models return same value
    v = rbfcalc2(model0, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.500
    v = rbfcalc2(model1, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.500

    //
    // Previous section shows that model state is saved/restored during
    // serialization. However, some properties are NOT serialized.
    //
    // Serialization saves/restores RBF model, but it does NOT saves/restores
    // settings which were used to build current model. In particular, dataset
    // which were used to build model, is not preserved.
    //
    // What does it mean in for us?
    //
    // Do you remember this sequence: rbfcreate-rbfsetpoints-rbfbuildmodel?
    // First step creates model, second step adds dataset and tunes model
    // settings, third step builds model using current dataset and model
    // construction settings.
    //
    // If you call rbfbuildmodel() without calling rbfsetpoints() first, you
    // will get empty (zero) RBF model. In our example, model0 contains
    // dataset which was added by rbfsetpoints() call. However, model1 does
    // NOT contain dataset - because dataset is NOT serialized.
    //
    // This, if we call rbfbuildmodel(model0,rep), we will get same model,
    // which returns 2.5 at (x,y)=(0,0). However, after same call model1 will
    // return zero - because it contains RBF model (coefficients), but does NOT
    // contain dataset which was used to build this model.
    //
    // Basically, it means that:
    // * serialization of the RBF model preserves anything related to the model
    //   EVALUATION
    // * but it does NOT creates perfect copy of the original object.
    //
    rbfbuildmodel(model0, rep);
    v = rbfcalc2(model0, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.500

    rbfbuildmodel(model1, rep);
    v = rbfcalc2(model1, 0.0, 0.0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.000
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Suppose that we have set of 2-dimensional points with associated VECTOR
    // function values, and we want to build a RBF model using our data.
    // 
    // Typical sequence of steps is given below:
    // 1. we create RBF model object
    // 2. we attach our dataset to the RBF model and tune algorithm settings
    // 3. we rebuild RBF model using new data
    // 4. we use RBF model (evaluate, serialize, etc.)
    //
    real_1d_array x;
    real_1d_array y;

    //
    // Step 1: RBF model creation.
    //
    // We have to specify dimensionality of the space (equal to 2) and
    // dimensionality of the function (2-dimensional vector function).
    //
    rbfmodel model;
    rbfcreate(2, 2, model);

    // New model is empty - it can be evaluated,
    // but we just get zero value at any point.
    x = "[+1,+1]";
    rbfcalc(model, x, y);
    printf("%s\n", y.tostring(2).c_str()); // EXPECTED: [0.000,0.000]

    //
    // Step 2: we add dataset.
    //
    // XY arrays containt four points:
    // * (x0,y0) = (+1,+1), f(x0,y0)=(0,-1)
    // * (x1,y1) = (+1,-1), f(x1,y1)=(-1,0)
    // * (x2,y2) = (-1,-1), f(x2,y2)=(0,+1)
    // * (x3,y3) = (-1,+1), f(x3,y3)=(+1,0)
    //
    // By default, RBF uses QNN algorithm, which works well with
    // relatively uniform datasets (all points are well separated,
    // average distance is approximately same for all points).
    //
    // This default algorithm is perfectly suited for our simple
    // made up data.
    //
    real_2d_array xy = "[[+1,+1,0,-1],[+1,-1,-1,0],[-1,-1,0,+1],[-1,+1,+1,0]]";
    rbfsetpoints(model, xy);

    // We added points, but model was not rebuild yet.
    // If we call rbfcalc(), we still will get 0.0 as result.
    rbfcalc(model, x, y);
    printf("%s\n", y.tostring(2).c_str()); // EXPECTED: [0.000,0.000]

    //
    // Step 3: rebuild model
    //
    // After we've configured model, we should rebuild it -
    // it will change coefficients stored internally in the
    // rbfmodel structure.
    //
    rbfreport rep;
    rbfbuildmodel(model, rep);
    printf("%d\n", int(rep.terminationtype)); // EXPECTED: 1

    //
    // Step 4: model was built
    //
    // After call of rbfbuildmodel(), rbfcalc() will return
    // value of the new model.
    //
    rbfcalc(model, x, y);
    printf("%s\n", y.tostring(2).c_str()); // EXPECTED: [0.000,-1.000]
    return 0;
}


/************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixlurcond1(complex_2d_array lua, ae_int_t n);
/************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the CMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixlurcondinf(complex_2d_array lua, ae_int_t n);
/************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixrcond1(complex_2d_array a, ae_int_t n);
/************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixrcondinf(complex_2d_array a, ae_int_t n);
/************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixtrrcond1( complex_2d_array a, ae_int_t n, bool isupper, bool isunit);
/************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::cmatrixtrrcondinf( complex_2d_array a, ae_int_t n, bool isupper, bool isunit);
/************************************************************************* Condition number estimate of a Hermitian positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::hpdmatrixcholeskyrcond( complex_2d_array a, ae_int_t n, bool isupper);
/************************************************************************* Condition number estimate of a Hermitian positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - Hermitian positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::hpdmatrixrcond( complex_2d_array a, ae_int_t n, bool isupper);
/************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixlurcond1(real_2d_array lua, ae_int_t n);
/************************************************************************* Estimate of the condition number of a matrix given by its LU decomposition (infinity norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: LUA - LU decomposition of a matrix in compact form. Output of the RMatrixLU subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixlurcondinf(real_2d_array lua, ae_int_t n);
/************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixrcond1(real_2d_array a, ae_int_t n);
/************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixrcondinf(real_2d_array a, ae_int_t n);
/************************************************************************* Triangular matrix: estimate of a condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array[0..N-1, 0..N-1]. N - size of A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixtrrcond1( real_2d_array a, ae_int_t n, bool isupper, bool isunit);
/************************************************************************* Triangular matrix: estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - True, if the matrix is upper triangular. IsUnit - True, if the matrix has a unit diagonal. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::rmatrixtrrcondinf( real_2d_array a, ae_int_t n, bool isupper, bool isunit);
/************************************************************************* Condition number estimate of a symmetric positive definite matrix given by Cholesky decomposition. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: CD - Cholesky decomposition of matrix A, output of SMatrixCholesky subroutine. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::spdmatrixcholeskyrcond( real_2d_array a, ae_int_t n, bool isupper);
/************************************************************************* Condition number estimate of a symmetric positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - symmetric positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/
double alglib::spdmatrixrcond(real_2d_array a, ae_int_t n, bool isupper);
rmatrixschur
/************************************************************************* Subroutine performing the Schur decomposition of a general matrix by using the QR algorithm with multiple shifts. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The source matrix A is represented as S'*A*S = T, where S is an orthogonal matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..N-1, 0..N-1]. N - size of A, N>=0. Output parameters: A - contains matrix T. Array whose indexes range within [0..N-1, 0..N-1]. S - contains Schur vectors. Array whose indexes range within [0..N-1, 0..N-1]. Note 1: The block structure of matrix T can be easily recognized: since all the elements below the blocks are zeros, the elements a[i+1,i] which are equal to 0 show the block border. Note 2: The algorithm performance depends on the value of the internal parameter NS of the InternalSchurDecomposition subroutine which defines the number of shifts in the QR algorithm (similarly to the block width in block-matrix algorithms in linear algebra). If you require maximum performance on your machine, it is recommended to adjust this parameter manually. Result: True, if the algorithm has converged and parameters A and S contain the result. False, if the algorithm has not converged. Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). *************************************************************************/
bool alglib::rmatrixschur(real_2d_array& a, ae_int_t n, real_2d_array& s);
/************************************************************************* Temporary buffers for sparse matrix operations. You should pass an instance of this structure to factorization functions. It allows to reuse memory during repeated sparse factorizations. You do not have to call some initialization function - simply passing an instance to factorization function is enough. *************************************************************************/
class sparsebuffers { };
/************************************************************************* Sparse matrix structure. You should use ALGLIB functions to work with sparse matrix. Never try to access its fields directly! NOTES ON THE SPARSE STORAGE FORMATS Sparse matrices can be stored using several formats: * Hash-Table representation * Compressed Row Storage (CRS) * Skyline matrix storage (SKS) Each of the formats has benefits and drawbacks: * Hash-table is good for dynamic operations (insertion of new elements), but does not support linear algebra operations * CRS is good for operations like matrix-vector or matrix-matrix products, but its initialization is less convenient - you have to tell row sizes at the initialization, and you have to fill matrix only row by row, from left to right. * SKS is a special format which is used to store triangular factors from Cholesky factorization. It does not support dynamic modification, and support for linear algebra operations is very limited. Tables below outline information about these two formats: OPERATIONS WITH MATRIX HASH CRS SKS creation + + + SparseGet + + + SparseRewriteExisting + + + SparseSet + SparseAdd + SparseGetRow + + SparseGetCompressedRow + + sparse-dense linear algebra + + *************************************************************************/
class sparsematrix { };
/************************************************************************* This function adds value to S[i,j] - element of the sparse matrix. Matrix must be in a Hash-Table mode. In case S[i,j] already exists in the table, V i added to its value. In case S[i,j] is non-existent, it is inserted in the table. Table automatically grows when necessary. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I<M J - column index of the element to modify, 0<=J<N V - value to add, must be finite number OUTPUT PARAMETERS S - modified matrix NOTE 1: when S[i,j] is exactly zero after modification, it is deleted from the table. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparseadd(sparsematrix s, ae_int_t i, ae_int_t j, double v);

Examples:   [1]  

/************************************************************************* This function performs in-place conversion to desired sparse storage format. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S0 - sparse matrix in requested format. NOTE: in-place conversion wastes a lot of memory which is used to store temporaries. If you perform a lot of repeated conversions, we recommend to use out-of-place buffered conversion functions, like SparseCopyToBuf(), which can reuse already allocated memory. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparseconvertto(sparsematrix s0, ae_int_t fmt);
/************************************************************************* This function converts matrix to CRS format. Some algorithms (linear algebra ones, for example) require matrices in CRS format. This function allows to perform in-place conversion. INPUT PARAMETERS S - sparse M*N matrix in any format OUTPUT PARAMETERS S - matrix in CRS format NOTE: this function has no effect when called with matrix which is already in CRS mode. NOTE: this function allocates temporary memory to store a copy of the matrix. If you perform a lot of repeated conversions, we recommend you to use SparseCopyToCRSBuf() function, which can reuse previously allocated memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparseconverttocrs(sparsematrix s);

Examples:   [1]  

/************************************************************************* This function performs in-place conversion to Hash table storage. INPUT PARAMETERS S - sparse matrix in CRS format. OUTPUT PARAMETERS S - sparse matrix in Hash table format. NOTE: this function has no effect when called with matrix which is already in Hash table mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToHashBuf() function in this case. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparseconverttohash(sparsematrix s);
/************************************************************************* This function performs in-place conversion to SKS format. INPUT PARAMETERS S - sparse matrix in any format. OUTPUT PARAMETERS S - sparse matrix in SKS format. NOTE: this function has no effect when called with matrix which is already in SKS mode. NOTE: in-place conversion involves allocation of temporary arrays. If you perform a lot of repeated in- place conversions, it may lead to memory fragmentation. Consider using out-of-place SparseCopyToSKSBuf() function in this case. -- ALGLIB PROJECT -- Copyright 15.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparseconverttosks(sparsematrix s);
/************************************************************************* This function copies S0 to S1. This function completely deallocates memory owned by S1 before creating a copy of S0. If you want to reuse memory, use SparseCopyBuf. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopy(sparsematrix s0, sparsematrix& s1);
/************************************************************************* This function copies S0 to S1. Memory already allocated in S1 is reused as much as possible. NOTE: this function does not verify its arguments, it just copies all fields of the structure. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopybuf(sparsematrix s0, sparsematrix s1);
/************************************************************************* This function performs out-of-place conversion to desired sparse storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. Fmt - desired storage format of the output, as returned by SparseGetMatrixType() function: * 0 for hash-based storage * 1 for CRS * 2 for SKS OUTPUT PARAMETERS S1 - sparse matrix in requested format. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytobuf( sparsematrix s0, ae_int_t fmt, sparsematrix s1);
/************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting CRS conversion. If you perform a lot of repeated CRS conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToCRSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytocrs(sparsematrix s0, sparsematrix& s1);
/************************************************************************* This function performs out-of-place conversion to CRS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. S1 - matrix which may contain some pre-allocated memory, or can be just uninitialized structure. OUTPUT PARAMETERS S1 - sparse matrix in CRS format. NOTE: if S0 is stored as CRS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytocrsbuf(sparsematrix s0, sparsematrix s1);
/************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToHashBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytohash(sparsematrix s0, sparsematrix& s1);
/************************************************************************* This function performs out-of-place conversion to Hash table storage format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in Hash table format. NOTE: if S0 is stored as Hash-table, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytohashbuf(sparsematrix s0, sparsematrix s1);
/************************************************************************* This function performs out-of-place conversion to SKS storage format. S0 is copied to S1 and converted on-the-fly. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. NOTE: this function de-allocates memory occupied by S1 before starting conversion. If you perform a lot of repeated conversions, it may lead to memory fragmentation. In this case we recommend you to use SparseCopyToSKSBuf() function which re-uses memory in S1 as much as possible. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytosks(sparsematrix s0, sparsematrix& s1);
/************************************************************************* This function performs out-of-place conversion to SKS format. S0 is copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to maximum extent possible. INPUT PARAMETERS S0 - sparse matrix in any format. OUTPUT PARAMETERS S1 - sparse matrix in SKS format. NOTE: if S0 is stored as SKS, it is just copied without conversion. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecopytosksbuf(sparsematrix s0, sparsematrix s1);
/************************************************************************* This function creates sparse matrix in a Hash-Table format. This function creates Hast-Table matrix, which can be converted to CRS format after its initialization is over. Typical usage scenario for a sparse matrix is: 1. creation in a Hash-Table format 2. insertion of the matrix elements 3. conversion to the CRS representation 4. matrix is passed to some linear algebra algorithm Some information about different matrix formats can be found below, in the "NOTES" section. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. NOTE 1 Hash-tables use memory inefficiently, and they have to keep some amount of the "spare memory" in order to have good performance. Hash table for matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, where C is a small constant, about 1.5-2 in magnitude. CRS storage, from the other side, is more memory-efficient, and needs just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows in a matrix. When you convert from the Hash-Table to CRS representation, all unneeded memory will be freed. NOTE 2 Comments of SparseMatrix structure outline information about different sparse storage formats. We recommend you to read them before starting to use ALGLIB sparse matrices. NOTE 3 This function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreate(ae_int_t m, ae_int_t n, sparsematrix& s); void alglib::sparsecreate( ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix& s);

Examples:   [1]  

/************************************************************************* This version of SparseCreate function creates sparse matrix in Hash-Table format, reusing previously allocated storage as much as possible. Read comments for SparseCreate() for more information. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 K - K>=0, expected number of non-zero elements in a matrix. K can be inexact approximation, can be less than actual number of elements (table will grow when needed) or even zero). It is important to understand that although hash-table may grow automatically, it is better to provide good estimate of data size. S - SparseMatrix structure which MAY contain some already allocated storage. OUTPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. All elements of the matrix are zero. Previously allocated storage is reused, if its size is compatible with expected number of non-zeros K. -- ALGLIB PROJECT -- Copyright 14.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreatebuf(ae_int_t m, ae_int_t n, sparsematrix s); void alglib::sparsecreatebuf( ae_int_t m, ae_int_t n, ae_int_t k, sparsematrix s);
/************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateCRSBuf function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreatecrs( ae_int_t m, ae_int_t n, integer_1d_array ner, sparsematrix& s);

Examples:   [1]  

/************************************************************************* This function creates sparse matrix in a CRS format (expert function for situations when you are running out of memory). This version of CRS matrix creation function may reuse memory already allocated in S. This function creates CRS matrix. Typical usage scenario for a CRS matrix is: 1. creation (you have to tell number of non-zero elements at each row at this moment) 2. insertion of the matrix elements (row by row, from left to right) 3. matrix is passed to some linear algebra algorithm This function is a memory-efficient alternative to SparseCreate(), but it is more complex because it requires you to know in advance how large your matrix is. Some information about different matrix formats can be found in comments on SparseMatrix structure. We recommend you to read them before starting to use ALGLIB sparse matrices.. INPUT PARAMETERS M - number of rows in a matrix, M>=1 N - number of columns in a matrix, N>=1 NER - number of elements at each row, array[M], NER[I]>=0 S - sparse matrix structure with possibly preallocated memory. OUTPUT PARAMETERS S - sparse M*N matrix in CRS representation. You have to fill ALL non-zero elements by calling SparseSet() BEFORE you try to use this matrix. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreatecrsbuf( ae_int_t m, ae_int_t n, integer_1d_array ner, sparsematrix s);
/************************************************************************* This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], D[I]>=0. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], U[I]>=0. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseRewriteExisting() to change their values. NOTE: this function completely overwrites S with new sparse matrix. Previously allocated storage is NOT reused. If you want to reuse already allocated memory, call SparseCreateSKSBuf function. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreatesks( ae_int_t m, ae_int_t n, integer_1d_array d, integer_1d_array u, sparsematrix& s);
/************************************************************************* This is "buffered" version of SparseCreateSKS() which reuses memory previously allocated in S (of course, memory is reallocated if needed). This function creates sparse matrix in a SKS format (skyline storage format). In most cases you do not need this function - CRS format better suits most use cases. INPUT PARAMETERS M, N - number of rows(M) and columns (N) in a matrix: * M=N (as for now, ALGLIB supports only square SKS) * N>=1 * M>=1 D - "bottom" bandwidths, array[M], 0<=D[I]<=I. I-th element stores number of non-zeros at I-th row, below the diagonal (diagonal itself is not included) U - "top" bandwidths, array[N], 0<=U[I]<=I. I-th element stores number of non-zeros at I-th row, above the diagonal (diagonal itself is not included) OUTPUT PARAMETERS S - sparse M*N matrix in SKS representation. All elements are filled by zeros. You may use SparseSet()/SparseAdd() to change their values. -- ALGLIB PROJECT -- Copyright 13.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsecreatesksbuf( ae_int_t m, ae_int_t n, integer_1d_array d, integer_1d_array u, sparsematrix s);
/************************************************************************* This function is used to enumerate all elements of the sparse matrix. Before first call user initializes T0 and T1 counters by zero. These counters are used to remember current position in a matrix; after each call they are updated by the function. Subsequent calls to this function return non-zero elements of the sparse matrix, one by one. If you enumerate CRS matrix, matrix is traversed from left to right, from top to bottom. In case you enumerate matrix stored as Hash table, elements are returned in random order. EXAMPLE > T0=0 > T1=0 > while SparseEnumerate(S,T0,T1,I,J,V) do > ....do something with I,J,V INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. T0 - internal counter T1 - internal counter OUTPUT PARAMETERS T0 - new value of the internal counter T1 - new value of the internal counter I - row index of non-zero element, 0<=I<M. J - column index of non-zero element, 0<=J<N V - value of the T-th element RESULT True in case of success (next non-zero element was retrieved) False in case all non-zero elements were enumerated NOTE: you may call SparseRewriteExisting() during enumeration, but it is THE ONLY matrix modification function you can call!!! Other matrix modification functions should not be called during enumeration! -- ALGLIB PROJECT -- Copyright 14.03.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::sparseenumerate( sparsematrix s, ae_int_t& t0, ae_int_t& t1, ae_int_t& i, ae_int_t& j, double& v);
/************************************************************************* The function frees all memory occupied by sparse matrix. Sparse matrix structure becomes unusable after this call. OUTPUT PARAMETERS S - sparse matrix to delete -- ALGLIB PROJECT -- Copyright 24.07.2012 by Bochkanov Sergey *************************************************************************/
void alglib::sparsefree(sparsematrix& s);
/************************************************************************* This function returns S[i,j] - element of the sparse matrix. Matrix can be in any mode (Hash-Table, CRS, SKS), but this function is less efficient for CRS matrices. Hash-Table and SKS matrices can find element in O(1) time, while CRS matrices need O(log(RS)) time, where RS is an number of non-zero elements in a row. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - row index of the element to modify, 0<=I<M J - column index of the element to modify, 0<=J<N RESULT value of S[I,J] or zero (in case no element with such index is found) -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
double alglib::sparseget(sparsematrix s, ae_int_t i, ae_int_t j);

Examples:   [1]  [2]  

/************************************************************************* This function returns I-th row of the sparse matrix IN COMPRESSED FORMAT - only non-zero elements are returned (with their indexes). Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=I<M ColIdx - output buffer for column indexes, can be preallocated. In case buffer size is too small to store I-th row, it is automatically reallocated. Vals - output buffer for values, can be preallocated. In case buffer size is too small to store I-th row, it is automatically reallocated. OUTPUT PARAMETERS: ColIdx - column indexes of non-zero elements, sorted by ascending. Symbolically non-zero elements are counted (i.e. if you allocated place for element, but it has zero numerical value - it is counted). Vals - values. Vals[K] stores value of matrix element with indexes (I,ColIdx[K]). Symbolically non-zero elements are counted (i.e. if you allocated place for element, but it has zero numerical value - it is counted). NZCnt - number of symbolically non-zero elements per row. NOTE: when incorrect I (outside of [0,M-1]) or matrix (non CRS/SKS) is passed, this function throws exception. NOTE: this function may allocate additional, unnecessary place for ColIdx and Vals arrays. It is dictated by performance reasons - on SKS matrices it is faster to allocate space at the beginning with some "extra"-space, than performing two passes over matrix - first time to calculate exact space required for data, second time - to store data itself. -- ALGLIB PROJECT -- Copyright 10.12.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsegetcompressedrow( sparsematrix s, ae_int_t i, integer_1d_array& colidx, real_1d_array& vals, ae_int_t& nzcnt);
/************************************************************************* This function returns I-th diagonal element of the sparse matrix. Matrix can be in any mode (Hash-Table or CRS storage), but this function is most efficient for CRS matrices - it requires less than 50 CPU cycles to extract diagonal element. For Hash-Table matrices we still have O(1) query time, but function is many times slower. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table representation. Exception will be thrown for CRS matrix. I - index of the element to modify, 0<=I<min(M,N) RESULT value of S[I,I] or zero (in case no element with such index is found) -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
double alglib::sparsegetdiagonal(sparsematrix s, ae_int_t i);
/************************************************************************* The function returns number of strictly lower triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly below main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::sparsegetlowercount(sparsematrix s);
/************************************************************************* This function returns type of the matrix storage format. INPUT PARAMETERS: S - sparse matrix. RESULT: sparse storage format used by matrix: 0 - Hash-table 1 - CRS (compressed row storage) 2 - SKS (skyline) NOTE: future versions of ALGLIB may include additional sparse storage formats. -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::sparsegetmatrixtype(sparsematrix s);
/************************************************************************* The function returns number of columns of a sparse matrix. RESULT: number of columns of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::sparsegetncols(sparsematrix s);
/************************************************************************* The function returns number of rows of a sparse matrix. RESULT: number of rows of a sparse matrix. -- ALGLIB PROJECT -- Copyright 23.08.2012 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::sparsegetnrows(sparsematrix s);
/************************************************************************* This function returns I-th row of the sparse matrix. Matrix must be stored in CRS or SKS format. INPUT PARAMETERS: S - sparse M*N matrix in CRS format I - row index, 0<=I<M IRow - output buffer, can be preallocated. In case buffer size is too small to store I-th row, it is automatically reallocated. OUTPUT PARAMETERS: IRow - array[M], I-th row. NOTE: this function has O(N) running time, where N is a column count. It allocates and fills N-element array, even although most of its elemets are zero. NOTE: If you have O(non-zeros-per-row) time and memory requirements, use SparseGetCompressedRow() function. It returns data in compressed format. NOTE: when incorrect I (outside of [0,M-1]) or matrix (non CRS/SKS) is passed, this function throws exception. -- ALGLIB PROJECT -- Copyright 10.12.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsegetrow( sparsematrix s, ae_int_t i, real_1d_array& irow);
/************************************************************************* The function returns number of strictly upper triangular non-zero elements in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries in the sparse matrix data structure. If some element has zero numerical value, it is still counted. This function has different cost for different types of matrices: * for hash-based matrices it involves complete pass over entire hash-table with O(NNZ) cost, where NNZ is number of non-zero elements * for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). RESULT: number of non-zero elements strictly above main diagonal -- ALGLIB PROJECT -- Copyright 12.02.2014 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::sparsegetuppercount(sparsematrix s);
/************************************************************************* This function checks matrix storage format and returns True when matrix is stored using CRS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is CRS False if matrix type is not CRS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::sparseiscrs(sparsematrix s);
/************************************************************************* This function checks matrix storage format and returns True when matrix is stored using Hash table representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is Hash table False if matrix type is not Hash table -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::sparseishash(sparsematrix s);
/************************************************************************* This function checks matrix storage format and returns True when matrix is stored using SKS representation. INPUT PARAMETERS: S - sparse matrix. RESULT: True if matrix type is SKS False if matrix type is not SKS -- ALGLIB PROJECT -- Copyright 20.07.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::sparseissks(sparsematrix s);
/************************************************************************* This function calculates matrix-matrix product S*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemm( sparsematrix s, real_2d_array a, ae_int_t k, real_2d_array& b);
/************************************************************************* This function simultaneously calculates two matrix-matrix products: S*A and S^T*A. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. B1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B0 - array[N][K], S*A B1 - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemm2( sparsematrix s, real_2d_array a, ae_int_t k, real_2d_array& b0, real_2d_array& b1);
/************************************************************************* This function calculates matrix-matrix product S^T*A. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. A - array[M][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[N][K], S^T*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemtm( sparsematrix s, real_2d_array a, ae_int_t k, real_2d_array& b);
/************************************************************************* This function calculates matrix-vector product S^T*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[M], input vector. For performance reasons we make only quick checks - we check that array size is at least M, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemtv(sparsematrix s, real_1d_array x, real_1d_array& y);
/************************************************************************* This function calculates matrix-vector product S*x. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemv(sparsematrix s, real_1d_array x, real_1d_array& y);

Examples:   [1]  [2]  

/************************************************************************* This function simultaneously calculates two matrix-vector products: S*x and S^T*x. S must be square (non-rectangular) matrix stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse N*N matrix in CRS or SKS format. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y0 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. Y1 - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y0 - array[N], S*x Y1 - array[N], S^T*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsemv2( sparsematrix s, real_1d_array x, real_1d_array& y0, real_1d_array& y1);
/************************************************************************* This procedure resizes Hash-Table matrix. It can be called when you have deleted too many elements from the matrix, and you want to free unneeded memory. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparseresizematrix(sparsematrix s);
/************************************************************************* This function rewrites existing (non-zero) element. It returns True if element exists or False, when it is called for non-existing (zero) element. This function works with any kind of the matrix. The purpose of this function is to provide convenient thread-safe way to modify sparse matrix. Such modification (already existing element is rewritten) is guaranteed to be thread-safe without any synchronization, as long as different threads modify different elements. INPUT PARAMETERS S - sparse M*N matrix in any kind of representation (Hash, SKS, CRS). I - row index of non-zero element to modify, 0<=I<M J - column index of non-zero element to modify, 0<=J<N V - value to rewrite, must be finite number OUTPUT PARAMETERS S - modified matrix RESULT True in case when element exists False in case when element doesn't exist or it is zero -- ALGLIB PROJECT -- Copyright 14.03.2012 by Bochkanov Sergey *************************************************************************/
bool alglib::sparserewriteexisting( sparsematrix s, ae_int_t i, ae_int_t j, double v);
/************************************************************************* This function modifies S[i,j] - element of the sparse matrix. For Hash-based storage format: * this function can be called at any moment - during matrix initialization or later * new value can be zero or non-zero. In case new value of S[i,j] is zero, this element is deleted from the table. * this function has no effect when called with zero V for non-existent element. For CRS-bases storage format: * this function can be called ONLY DURING MATRIX INITIALIZATION * new value MUST be non-zero. Exception will be thrown for zero V. * elements must be initialized in correct order - from top row to bottom, within row - from left to right. For SKS storage: NOT SUPPORTED! Use SparseRewriteExisting() to work with SKS matrices. INPUT PARAMETERS S - sparse M*N matrix in Hash-Table or CRS representation. I - row index of the element to modify, 0<=I<M J - column index of the element to modify, 0<=J<N V - value to set, must be finite number, can be zero OUTPUT PARAMETERS S - modified matrix -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparseset(sparsematrix s, ae_int_t i, ae_int_t j, double v);

Examples:   [1]  [2]  

/************************************************************************* This function calculates matrix-matrix product S*A, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. A - array[N][K], input dense matrix. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. K - number of columns of matrix (A). B - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS B - array[M][K], S*A NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsesmm( sparsematrix s, bool isupper, real_2d_array a, ae_int_t k, real_2d_array& b);
/************************************************************************* This function calculates matrix-vector product S*x, when S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - output buffer, possibly preallocated. In case buffer size is too small to store result, this buffer is automatically resized. OUTPUT PARAMETERS Y - array[M], S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 14.10.2011 by Bochkanov Sergey *************************************************************************/
void alglib::sparsesmv( sparsematrix s, bool isupper, real_1d_array x, real_1d_array& y);
/************************************************************************* This function efficiently swaps contents of S0 and S1. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparseswap(sparsematrix s0, sparsematrix s1);
/************************************************************************* This function performs efficient in-place transpose of SKS matrix. No additional memory is allocated during transposition. This function supports only skyline storage format (SKS). INPUT PARAMETERS S - sparse matrix in SKS format. OUTPUT PARAMETERS S - sparse matrix, transposed. -- ALGLIB PROJECT -- Copyright 16.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsetransposesks(sparsematrix s);
/************************************************************************* This function calculates matrix-vector product op(S)*x, when x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. Y - possibly preallocated input buffer. Automatically resized if its size is too small. OUTPUT PARAMETERS Y - array[N], op(S)*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsetrmv( sparsematrix s, bool isupper, bool isunit, ae_int_t optype, real_1d_array& x, real_1d_array& y);
/************************************************************************* This function solves linear system op(S)*y=x where x is vector, S is symmetric triangular matrix, op(S) is transposition or no operation. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse square matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is used: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. IsUnit - unit or non-unit diagonal: * if True, diagonal elements of triangular matrix are considered equal to 1.0. Actual elements stored in S are not referenced at all. * if False, diagonal stored in S is used. It is your responsibility to make sure that diagonal is non-zero. OpType - operation type: * if 0, S*x is calculated * if 1, (S^T)*x is calculated (transposition) X - array[N] which stores input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. OUTPUT PARAMETERS X - array[N], inv(op(S))*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. NOTE: no assertion or tests are done during algorithm operation. It is your responsibility to provide invertible matrix to algorithm. -- ALGLIB PROJECT -- Copyright 20.01.2014 by Bochkanov Sergey *************************************************************************/
void alglib::sparsetrsv( sparsematrix s, bool isupper, bool isunit, ae_int_t optype, real_1d_array& x);
/************************************************************************* This function calculates vector-matrix-vector product x'*S*x, where S is symmetric matrix. Matrix S must be stored in CRS or SKS format (exception will be thrown otherwise). INPUT PARAMETERS S - sparse M*M matrix in CRS or SKS format. IsUpper - whether upper or lower triangle of S is given: * if upper triangle is given, only S[i,j] for j>=i are used, and lower triangle is ignored (it can be empty - these elements are not referenced at all). * if lower triangle is given, only S[i,j] for j<=i are used, and upper triangle is ignored. X - array[N], input vector. For performance reasons we make only quick checks - we check that array size is at least N, but we do not check for NAN's or INF's. RESULT x'*S*x NOTE: this function throws exception when called for non-CRS/SKS matrix. You must convert your matrix with SparseConvertToCRS/SKS() before using this function. -- ALGLIB PROJECT -- Copyright 27.01.2014 by Bochkanov Sergey *************************************************************************/
double alglib::sparsevsmv(sparsematrix s, bool isupper, real_1d_array x);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates creation/initialization of the sparse matrix
    // and matrix-vector multiplication.
    //
    // First, we have to create matrix and initialize it. Matrix is initially created
    // in the Hash-Table format, which allows convenient initialization. We can modify
    // Hash-Table matrix with sparseset() and sparseadd() functions.
    //
    // NOTE: Unlike CRS format, Hash-Table representation allows you to initialize
    // elements in the arbitrary order. You may see that we initialize a[0][0] first,
    // then move to the second row, and then move back to the first row.
    //
    sparsematrix s;
    sparsecreate(2, 2, s);
    sparseset(s, 0, 0, 2.0);
    sparseset(s, 1, 1, 1.0);
    sparseset(s, 0, 1, 1.0);

    sparseadd(s, 1, 1, 4.0);

    //
    // Now S is equal to
    //   [ 2 1 ]
    //   [   5 ]
    // Lets check it by reading matrix contents with sparseget().
    // You may see that with sparseget() you may read both non-zero
    // and zero elements.
    //
    double v;
    v = sparseget(s, 0, 0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.0000
    v = sparseget(s, 0, 1);
    printf("%.2f\n", double(v)); // EXPECTED: 1.0000
    v = sparseget(s, 1, 0);
    printf("%.2f\n", double(v)); // EXPECTED: 0.0000
    v = sparseget(s, 1, 1);
    printf("%.2f\n", double(v)); // EXPECTED: 5.0000

    //
    // After successful creation we can use our matrix for linear operations.
    //
    // However, there is one more thing we MUST do before using S in linear
    // operations: we have to convert it from HashTable representation (used for
    // initialization and dynamic operations) to CRS format with sparseconverttocrs()
    // call. If you omit this call, ALGLIB will generate exception on the first
    // attempt to use S in linear operations. 
    //
    sparseconverttocrs(s);

    //
    // Now S is in the CRS format and we are ready to do linear operations.
    // Lets calculate A*x for some x.
    //
    real_1d_array x = "[1,-1]";
    real_1d_array y = "[]";
    sparsemv(s, x, y);
    printf("%s\n", y.tostring(2).c_str()); // EXPECTED: [1.000,-5.000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // This example demonstrates creation/initialization of the sparse matrix in the
    // CRS format.
    //
    // Hash-Table format used by default is very convenient (it allows easy
    // insertion of elements, automatic memory reallocation), but has
    // significant memory and performance overhead. Insertion of one element 
    // costs hundreds of CPU cycles, and memory consumption is several times
    // higher than that of CRS.
    //
    // When you work with really large matrices and when you can tell in 
    // advance how many elements EXACTLY you need, it can be beneficial to 
    // create matrix in the CRS format from the very beginning.
    //
    // If you want to create matrix in the CRS format, you should:
    // * use sparsecreatecrs() function
    // * know row sizes in advance (number of non-zero entries in the each row)
    // * initialize matrix with sparseset() - another function, sparseadd(), is not allowed
    // * initialize elements from left to right, from top to bottom, each
    //   element is initialized only once.
    //
    sparsematrix s;
    integer_1d_array row_sizes = "[2,2,2,1]";
    sparsecreatecrs(4, 4, row_sizes, s);
    sparseset(s, 0, 0, 2.0);
    sparseset(s, 0, 1, 1.0);
    sparseset(s, 1, 1, 4.0);
    sparseset(s, 1, 2, 2.0);
    sparseset(s, 2, 2, 3.0);
    sparseset(s, 2, 3, 1.0);
    sparseset(s, 3, 3, 9.0);

    //
    // Now S is equal to
    //   [ 2 1     ]
    //   [   4 2   ]
    //   [     3 1 ]
    //   [       9 ]
    //
    // We should point that we have initialized S elements from left to right,
    // from top to bottom. CRS representation does NOT allow you to do so in
    // the different order. Try to change order of the sparseset() calls above,
    // and you will see that your program generates exception.
    //
    // We can check it by reading matrix contents with sparseget().
    // However, you should remember that sparseget() is inefficient on
    // CRS matrices (it may have to pass through all elements of the row 
    // until it finds element you need).
    //
    double v;
    v = sparseget(s, 0, 0);
    printf("%.2f\n", double(v)); // EXPECTED: 2.0000
    v = sparseget(s, 2, 3);
    printf("%.2f\n", double(v)); // EXPECTED: 1.0000

    // you may see that you can read zero elements (which are not stored) with sparseget()
    v = sparseget(s, 3, 2);
    printf("%.2f\n", double(v)); // EXPECTED: 0.0000

    //
    // After successful creation we can use our matrix for linear operations.
    // Lets calculate A*x for some x.
    //
    real_1d_array x = "[1,-1,1,-1]";
    real_1d_array y = "[]";
    sparsemv(s, x, y);
    printf("%s\n", y.tostring(2).c_str()); // EXPECTED: [1.000,-2.000,2.000,-9]
    return 0;
}


smatrixgevd
smatrixgevdreduce
/************************************************************************* Algorithm for solving the following generalized symmetric positive-definite eigenproblem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3). where A is a symmetric matrix, B - symmetric positive-definite matrix. The problem is solved by reducing it to an ordinary symmetric eigenvalue problem. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ZNeeded - if ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasnt changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in matrix columns. It should be noted that the eigenvectors in such problems do not form an orthogonal system. Result: True, if the problem was solved successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix isnt positive-definite) or during the work of the iterative algorithm for solving the symmetric eigenproblem. See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixgevd( real_2d_array a, ae_int_t n, bool isuppera, real_2d_array b, bool isupperb, ae_int_t zneeded, ae_int_t problemtype, real_1d_array& d, real_2d_array& z);
/************************************************************************* Algorithm for reduction of the following generalized symmetric positive- definite eigenvalue problem: A*x = lambda*B*x (1) or A*B*x = lambda*x (2) or B*A*x = lambda*x (3) to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and the given problems are the same, and the eigenvectors of the given problem could be obtained by multiplying the obtained eigenvectors by the transformation matrix x = R*y). Here A is a symmetric matrix, B - symmetric positive-definite matrix. Input parameters: A - symmetric matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrices A and B. IsUpperA - storage format of matrix A. B - symmetric positive-definite matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. IsUpperB - storage format of matrix B. ProblemType - if ProblemType is equal to: * 1, the following problem is solved: A*x = lambda*B*x; * 2, the following problem is solved: A*B*x = lambda*x; * 3, the following problem is solved: B*A*x = lambda*x. Output parameters: A - symmetric matrix which is given by its upper or lower triangle depending on IsUpperA. Contains matrix C. Array whose indexes range within [0..N-1, 0..N-1]. R - upper triangular or low triangular transformation matrix which is used to obtain the eigenvectors of a given problem as the product of eigenvectors of C (from the right) and matrix R (from the left). If the matrix is upper triangular, the elements below the main diagonal are equal to 0 (and vice versa). Thus, we can perform the multiplication without taking into account the internal structure (which is an easier though less effective way). Array whose indexes range within [0..N-1, 0..N-1]. IsUpperR - type of matrix R (upper or lower triangular). Result: True, if the problem was reduced successfully. False, if the error occurred during the Cholesky decomposition of matrix B (the matrix is not positive-definite). -- ALGLIB -- Copyright 1.28.2006 by Bochkanov Sergey *************************************************************************/
bool alglib::smatrixgevdreduce( real_2d_array& a, ae_int_t n, bool isuppera, real_2d_array b, bool isupperb, ae_int_t problemtype, real_2d_array& r, bool& isupperr);
/************************************************************************* 1-dimensional spline interpolant *************************************************************************/
class spline1dinterpolant { };
/************************************************************************* This subroutine builds Akima spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildakima( real_1d_array x, real_1d_array y, spline1dinterpolant& c); void alglib::spline1dbuildakima( real_1d_array x, real_1d_array y, ae_int_t n, spline1dinterpolant& c);
/************************************************************************* This subroutine builds Catmull-Rom spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundType - boundary condition type: * -1 for periodic boundary condition * 0 for parabolically terminated spline (default) Tension - tension parameter: * tension=0 corresponds to classic Catmull-Rom spline (default) * 0<tension<1 corresponds to more general form - cardinal spline OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildcatmullrom( real_1d_array x, real_1d_array y, spline1dinterpolant& c); void alglib::spline1dbuildcatmullrom( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundtype, double tension, spline1dinterpolant& c);
/************************************************************************* This subroutine builds cubic spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Y - function values, array[0..N-1]. OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildcubic( real_1d_array x, real_1d_array y, spline1dinterpolant& c); void alglib::spline1dbuildcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, spline1dinterpolant& c);
/************************************************************************* This subroutine builds Hermite spline interpolant. INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] D - derivatives, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant. ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildhermite( real_1d_array x, real_1d_array y, real_1d_array d, spline1dinterpolant& c); void alglib::spline1dbuildhermite( real_1d_array x, real_1d_array y, real_1d_array d, ae_int_t n, spline1dinterpolant& c);
/************************************************************************* This subroutine builds linear spline interpolant INPUT PARAMETERS: X - spline nodes, array[0..N-1] Y - function values, array[0..N-1] N - points count (optional): * N>=2 * if given, only first N points are used to build spline * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) OUTPUT PARAMETERS: C - spline interpolant ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildlinear( real_1d_array x, real_1d_array y, spline1dinterpolant& c); void alglib::spline1dbuildlinear( real_1d_array x, real_1d_array y, ae_int_t n, spline1dinterpolant& c);

Examples:   [1]  [2]  

/************************************************************************* This function builds monotone cubic Hermite interpolant. This interpolant is monotonic in [x(0),x(n-1)] and is constant outside of this interval. In case y[] form non-monotonic sequence, interpolant is piecewise monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will monotonically grow at [0..2] and monotonically decrease at [2..4]. INPUT PARAMETERS: X - spline nodes, array[0..N-1]. Subroutine automatically sorts points, so caller may pass unsorted array. Y - function values, array[0..N-1] N - the number of points(N>=2). OUTPUT PARAMETERS: C - spline interpolant. -- ALGLIB PROJECT -- Copyright 21.06.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dbuildmonotone( real_1d_array x, real_1d_array y, spline1dinterpolant& c); void alglib::spline1dbuildmonotone( real_1d_array x, real_1d_array y, ae_int_t n, spline1dinterpolant& c);

Examples:   [1]  

/************************************************************************* This subroutine calculates the value of the spline at the given point X. INPUT PARAMETERS: C - spline interpolant X - point Result: S(x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/
double alglib::spline1dcalc(spline1dinterpolant c, double x);

Examples:   [1]  [2]  [3]  

/************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dconvcubic( real_1d_array x, real_1d_array y, real_1d_array x2, real_1d_array& y2); void alglib::spline1dconvcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, real_1d_array x2, ae_int_t n2, real_1d_array& y2);

Examples:   [1]  

/************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[], first and second derivatives d2[] and dd2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] DD2 - second derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dconvdiff2cubic( real_1d_array x, real_1d_array y, real_1d_array x2, real_1d_array& y2, real_1d_array& d2, real_1d_array& dd2); void alglib::spline1dconvdiff2cubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, real_1d_array x2, ae_int_t n2, real_1d_array& y2, real_1d_array& d2, real_1d_array& dd2);

Examples:   [1]  

/************************************************************************* This function solves following problem: given table y[] of function values at old nodes x[] and new nodes x2[], it calculates and returns table of function values y2[] and derivatives d2[] (calculated at x2[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - old spline nodes Y - function values X2 - new spline nodes OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points from X/Y are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) N2 - new points count: * N2>=2 * if given, only first N2 points from X2 are used * if not given, automatically detected from X2 size OUTPUT PARAMETERS: F2 - function values at X2[] D2 - first derivatives at X2[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Function values are correctly reordered on return, so F2[I] is always equal to S(X2[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dconvdiffcubic( real_1d_array x, real_1d_array y, real_1d_array x2, real_1d_array& y2, real_1d_array& d2); void alglib::spline1dconvdiffcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, real_1d_array x2, ae_int_t n2, real_1d_array& y2, real_1d_array& d2);

Examples:   [1]  

/************************************************************************* This subroutine differentiates the spline. INPUT PARAMETERS: C - spline interpolant. X - point Result: S - S(x) DS - S'(x) D2S - S''(x) -- ALGLIB PROJECT -- Copyright 24.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1ddiff( spline1dinterpolant c, double x, double& s, double& ds, double& d2s);
/************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns tables of first and second function derivatives d1[] and d2[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D1 - S' values at X[] D2 - S'' values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dgriddiff2cubic( real_1d_array x, real_1d_array y, real_1d_array& d1, real_1d_array& d2); void alglib::spline1dgriddiff2cubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, real_1d_array& d1, real_1d_array& d2);

Examples:   [1]  

/************************************************************************* This function solves following problem: given table y[] of function values at nodes x[], it calculates and returns table of function derivatives d[] (calculated at the same nodes x[]). This function yields same result as Spline1DBuildCubic() call followed by sequence of Spline1DDiff() calls, but it can be several times faster when called for ordered X[] and X2[]. INPUT PARAMETERS: X - spline nodes Y - function values OPTIONAL PARAMETERS: N - points count: * N>=2 * if given, only first N points are used * if not given, automatically detected from X/Y sizes (len(X) must be equal to len(Y)) BoundLType - boundary condition type for the left boundary BoundL - left boundary condition (first or second derivative, depending on the BoundLType) BoundRType - boundary condition type for the right boundary BoundR - right boundary condition (first or second derivative, depending on the BoundRType) OUTPUT PARAMETERS: D - derivative values at X[] ORDER OF POINTS Subroutine automatically sorts points, so caller may pass unsorted array. Derivative values are correctly reordered on return, so D[I] is always equal to S'(X[I]) independently of points order. SETTING BOUNDARY VALUES: The BoundLType/BoundRType parameters can have the following values: * -1, which corresonds to the periodic (cyclic) boundary conditions. In this case: * both BoundLType and BoundRType must be equal to -1. * BoundL/BoundR are ignored * Y[last] is ignored (it is assumed to be equal to Y[first]). * 0, which corresponds to the parabolically terminated spline (BoundL and/or BoundR are ignored). * 1, which corresponds to the first derivative boundary condition * 2, which corresponds to the second derivative boundary condition * by default, BoundType=0 is used PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. However, this subroutine doesn't require you to specify equal values for the first and last points - it automatically forces them to be equal by copying Y[first_point] (corresponds to the leftmost, minimal X[]) to Y[last_point]. However it is recommended to pass consistent values of Y[], i.e. to make Y[first_point]=Y[last_point]. -- ALGLIB PROJECT -- Copyright 03.09.2010 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dgriddiffcubic( real_1d_array x, real_1d_array y, real_1d_array& d); void alglib::spline1dgriddiffcubic( real_1d_array x, real_1d_array y, ae_int_t n, ae_int_t boundltype, double boundl, ae_int_t boundrtype, double boundr, real_1d_array& d);

Examples:   [1]  

/************************************************************************* This subroutine integrates the spline. INPUT PARAMETERS: C - spline interpolant. X - right bound of the integration interval [a, x], here 'a' denotes min(x[]) Result: integral(S(t)dt,a,x) -- ALGLIB PROJECT -- Copyright 23.06.2007 by Bochkanov Sergey *************************************************************************/
double alglib::spline1dintegrate(spline1dinterpolant c, double x);
/************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: x = A*t + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dlintransx(spline1dinterpolant c, double a, double b);
/************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x) = A*S(x) + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dlintransy(spline1dinterpolant c, double a, double b);
/************************************************************************* This subroutine unpacks the spline into the coefficients table. INPUT PARAMETERS: C - spline interpolant. X - point OUTPUT PARAMETERS: Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. For I = 0...N-2: Tbl[I,0] = X[i] Tbl[I,1] = X[i+1] Tbl[I,2] = C0 Tbl[I,3] = C1 Tbl[I,4] = C2 Tbl[I,5] = C3 On [x[i], x[i+1]] spline is equals to: S(x) = C0 + C1*t + C2*t^2 + C3*t^3 t = x-x[i] NOTE: You can rebuild spline with Spline1DBuildHermite() function, which accepts as inputs function values and derivatives at nodes, which are easy to calculate when you have coefficients. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline1dunpack( spline1dinterpolant c, ae_int_t& n, real_2d_array& tbl);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use cubic spline to do resampling, i.e. having
    // values of f(x)=x^2 sampled at 5 equidistant nodes on [-1,+1]
    // we calculate values/derivatives of cubic spline on 
    // another grid (equidistant with 9 nodes on [-1,+1])
    // WITHOUT CONSTRUCTION OF SPLINE OBJECT.
    //
    // There are efficient functions spline1dconvcubic(),
    // spline1dconvdiffcubic() and spline1dconvdiff2cubic() 
    // for such calculations.
    //
    // We use default boundary conditions ("parabolically terminated
    // spline") because cubic spline built with such boundary conditions 
    // will exactly reproduce any quadratic f(x).
    //
    // Actually, we could use natural conditions, but we feel that 
    // spline which exactly reproduces f() will show us more 
    // understandable results.
    //
    real_1d_array x_old = "[-1.0,-0.5,0.0,+0.5,+1.0]";
    real_1d_array y_old = "[+1.0,0.25,0.0,0.25,+1.0]";
    real_1d_array x_new = "[-1.00,-0.75,-0.50,-0.25,0.00,+0.25,+0.50,+0.75,+1.00]";
    real_1d_array y_new;
    real_1d_array d1_new;
    real_1d_array d2_new;

    //
    // First, conversion without differentiation.
    //
    //
    spline1dconvcubic(x_old, y_old, x_new, y_new);
    printf("%s\n", y_new.tostring(3).c_str()); // EXPECTED: [1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]

    //
    // Then, conversion with differentiation (first derivatives only)
    //
    //
    spline1dconvdiffcubic(x_old, y_old, x_new, y_new, d1_new);
    printf("%s\n", y_new.tostring(3).c_str()); // EXPECTED: [1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]
    printf("%s\n", d1_new.tostring(3).c_str()); // EXPECTED: [-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]

    //
    // Finally, conversion with first and second derivatives
    //
    //
    spline1dconvdiff2cubic(x_old, y_old, x_new, y_new, d1_new, d2_new);
    printf("%s\n", y_new.tostring(3).c_str()); // EXPECTED: [1.0000, 0.5625, 0.2500, 0.0625, 0.0000, 0.0625, 0.2500, 0.5625, 1.0000]
    printf("%s\n", d1_new.tostring(3).c_str()); // EXPECTED: [-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]
    printf("%s\n", d2_new.tostring(3).c_str()); // EXPECTED: [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use cubic spline to interpolate f(x)=x^2 sampled 
    // at 5 equidistant nodes on [-1,+1].
    //
    // First, we use default boundary conditions ("parabolically terminated
    // spline") because cubic spline built with such boundary conditions 
    // will exactly reproduce any quadratic f(x).
    //
    // Then we try to use natural boundary conditions
    //     d2S(-1)/dx^2 = 0.0
    //     d2S(+1)/dx^2 = 0.0
    // and see that such spline interpolated f(x) with small error.
    //
    real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]";
    real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]";
    double t = 0.25;
    double v;
    spline1dinterpolant s;
    ae_int_t natural_bound_type = 2;
    //
    // Test exact boundary conditions: build S(x), calculare S(0.25)
    // (almost same as original function)
    //
    spline1dbuildcubic(x, y, s);
    v = spline1dcalc(s, t);
    printf("%.4f\n", double(v)); // EXPECTED: 0.0625

    //
    // Test natural boundary conditions: build S(x), calculare S(0.25)
    // (small interpolation error)
    //
    spline1dbuildcubic(x, y, 5, natural_bound_type, 0.0, natural_bound_type, 0.0, s);
    v = spline1dcalc(s, t);
    printf("%.3f\n", double(v)); // EXPECTED: 0.0580
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use cubic spline to do grid differentiation, i.e. having
    // values of f(x)=x^2 sampled at 5 equidistant nodes on [-1,+1]
    // we calculate derivatives of cubic spline at nodes WITHOUT
    // CONSTRUCTION OF SPLINE OBJECT.
    //
    // There are efficient functions spline1dgriddiffcubic() and
    // spline1dgriddiff2cubic() for such calculations.
    //
    // We use default boundary conditions ("parabolically terminated
    // spline") because cubic spline built with such boundary conditions 
    // will exactly reproduce any quadratic f(x).
    //
    // Actually, we could use natural conditions, but we feel that 
    // spline which exactly reproduces f() will show us more 
    // understandable results.
    //
    real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]";
    real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]";
    real_1d_array d1;
    real_1d_array d2;

    //
    // We calculate first derivatives: they must be equal to 2*x
    //
    spline1dgriddiffcubic(x, y, d1);
    printf("%s\n", d1.tostring(3).c_str()); // EXPECTED: [-2.0, -1.0, 0.0, +1.0, +2.0]

    //
    // Now test griddiff2, which returns first AND second derivatives.
    // First derivative is 2*x, second is equal to 2.0
    //
    spline1dgriddiff2cubic(x, y, d1, d2);
    printf("%s\n", d1.tostring(3).c_str()); // EXPECTED: [-2.0, -1.0, 0.0, +1.0, +2.0]
    printf("%s\n", d2.tostring(3).c_str()); // EXPECTED: [ 2.0,  2.0, 2.0,  2.0,  2.0]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use piecewise linear spline to interpolate f(x)=x^2 sampled 
    // at 5 equidistant nodes on [-1,+1].
    //
    real_1d_array x = "[-1.0,-0.5,0.0,+0.5,+1.0]";
    real_1d_array y = "[+1.0,0.25,0.0,0.25,+1.0]";
    double t = 0.25;
    double v;
    spline1dinterpolant s;

    // build spline
    spline1dbuildlinear(x, y, s);

    // calculate S(0.25) - it is quite different from 0.25^2=0.0625
    v = spline1dcalc(s, t);
    printf("%.4f\n", double(v)); // EXPECTED: 0.125
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // Spline built witn spline1dbuildcubic() can be non-monotone even when
    // Y-values form monotone sequence. Say, for x=[0,1,2] and y=[0,1,1]
    // cubic spline will monotonically grow until x=1.5 and then start
    // decreasing.
    //
    // That's why ALGLIB provides special spline construction function
    // which builds spline which preserves monotonicity of the original
    // dataset.
    //
    // NOTE: in case original dataset is non-monotonic, ALGLIB splits it
    // into monotone subsequences and builds piecewise monotonic spline.
    //
    real_1d_array x = "[0,1,2]";
    real_1d_array y = "[0,1,1]";
    spline1dinterpolant s;

    // build spline
    spline1dbuildmonotone(x, y, s);

    // calculate S at x = [-0.5, 0.0, 0.5, 1.0, 1.5, 2.0]
    // you may see that spline is really monotonic
    double v;
    v = spline1dcalc(s, -0.5);
    printf("%.4f\n", double(v)); // EXPECTED: 0.0000
    v = spline1dcalc(s, 0.0);
    printf("%.4f\n", double(v)); // EXPECTED: 0.0000
    v = spline1dcalc(s, +0.5);
    printf("%.4f\n", double(v)); // EXPECTED: 0.5000
    v = spline1dcalc(s, 1.0);
    printf("%.4f\n", double(v)); // EXPECTED: 1.0000
    v = spline1dcalc(s, 1.5);
    printf("%.4f\n", double(v)); // EXPECTED: 1.0000
    v = spline1dcalc(s, 2.0);
    printf("%.4f\n", double(v)); // EXPECTED: 1.0000
    return 0;
}


/************************************************************************* 2-dimensional spline inteprolant *************************************************************************/
class spline2dinterpolant { };
/************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBicubicV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dbuildbicubic( real_1d_array x, real_1d_array y, real_2d_array f, ae_int_t m, ae_int_t n, spline2dinterpolant& c);
/************************************************************************* This subroutine builds bicubic vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dbuildbicubicv( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, real_1d_array f, ae_int_t d, spline2dinterpolant& c);

Examples:   [1]  

/************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DBuildBilinearV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dbuildbilinear( real_1d_array x, real_1d_array y, real_2d_array f, ae_int_t m, ae_int_t n, spline2dinterpolant& c);
/************************************************************************* This subroutine builds bilinear vector-valued spline. Input parameters: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] F - function values, array[0..M*N*D-1]: * first D elements store D values at (X[0],Y[0]) * next D elements store D values at (X[1],Y[0]) * general form - D function values at (X[i],Y[j]) are stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. M,N - grid size, M>=2, N>=2 D - vector dimension, D>=1 Output parameters: C - spline interpolant -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dbuildbilinearv( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, real_1d_array f, ae_int_t d, spline2dinterpolant& c);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X. Input parameters: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y- point Result: S(x,y) -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/
double alglib::spline2dcalc(spline2dinterpolant c, double x, double y);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dcalcv( spline2dinterpolant c, double x, double y, real_1d_array& f);

Examples:   [1]  

/************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y). INPUT PARAMETERS: C - spline interpolant. X, Y- point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dcalcvbuf( spline2dinterpolant c, double x, double y, real_1d_array& f);
/************************************************************************* This subroutine makes the copy of the spline model. Input parameters: C - spline interpolant Output parameters: CC - spline copy -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dcopy(spline2dinterpolant c, spline2dinterpolant& cc);

Examples:   [1]  

/************************************************************************* This subroutine calculates the value of the bilinear or bicubic spline at the given point X and its derivatives. Input parameters: C - spline interpolant. X, Y- point Output parameters: F - S(x,y) FX - dS(x,y)/dX FY - dS(x,y)/dY FXY - d2S(x,y)/dXdY -- ALGLIB PROJECT -- Copyright 05.07.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2ddiff( spline2dinterpolant c, double x, double y, double& f, double& fx, double& fy, double& fxy);
/************************************************************************* This subroutine performs linear transformation of the spline. Input parameters: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B Output parameters: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dlintransf(spline2dinterpolant c, double a, double b);

Examples:   [1]  

/************************************************************************* This subroutine performs linear transformation of the spline argument. Input parameters: C - spline interpolant AX, BX - transformation coefficients: x = A*t + B AY, BY - transformation coefficients: y = A*u + B Result: C - transformed spline -- ALGLIB PROJECT -- Copyright 30.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dlintransxy( spline2dinterpolant c, double ax, double bx, double ay, double by);

Examples:   [1]  

/************************************************************************* Bicubic spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 15 May, 2007 Copyright by Bochkanov Sergey *************************************************************************/
void alglib::spline2dresamplebicubic( real_2d_array a, ae_int_t oldheight, ae_int_t oldwidth, real_2d_array& b, ae_int_t newheight, ae_int_t newwidth);
/************************************************************************* Bilinear spline resampling Input parameters: A - function values at the old grid, array[0..OldHeight-1, 0..OldWidth-1] OldHeight - old grid height, OldHeight>1 OldWidth - old grid width, OldWidth>1 NewHeight - new grid height, NewHeight>1 NewWidth - new grid width, NewWidth>1 Output parameters: B - function values at the new grid, array[0..NewHeight-1, 0..NewWidth-1] -- ALGLIB routine -- 09.07.2007 Copyright by Bochkanov Sergey *************************************************************************/
void alglib::spline2dresamplebilinear( real_2d_array a, ae_int_t oldheight, ae_int_t oldwidth, real_2d_array& b, ae_int_t newheight, ae_int_t newwidth);
/************************************************************************* This subroutine was deprecated in ALGLIB 3.6.0 We recommend you to switch to Spline2DUnpackV(), which is more flexible and accepts its arguments in more convenient order. -- ALGLIB PROJECT -- Copyright 29.06.2007 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dunpack( spline2dinterpolant c, ae_int_t& m, ae_int_t& n, real_2d_array& tbl);
/************************************************************************* This subroutine unpacks two-dimensional spline into the coefficients table Input parameters: C - spline interpolant. Result: M, N- grid size (x-axis and y-axis) D - number of components Tbl - coefficients table, unpacked format, D - components: [0..(N-1)*(M-1)*D-1, 0..19]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index): K := T + I*D + J*D*(N-1) K-th row stores decomposition for T-th component of the vector-valued function Tbl[K,0] = X[i] Tbl[K,1] = X[i+1] Tbl[K,2] = Y[j] Tbl[K,3] = Y[j+1] Tbl[K,4] = C00 Tbl[K,5] = C01 Tbl[K,6] = C02 Tbl[K,7] = C03 Tbl[K,8] = C10 Tbl[K,9] = C11 ... Tbl[K,19] = C33 On each grid square spline is equals to: S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) t = x-x[j] u = y-y[i] -- ALGLIB PROJECT -- Copyright 16.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline2dunpackv( spline2dinterpolant c, ae_int_t& m, ae_int_t& n, ae_int_t& d, real_2d_array& tbl);

Examples:   [1]  

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use bilinear spline to interpolate f(x,y)=x^2+2*y^2 sampled 
    // at (x,y) from [0.0, 0.5, 1.0] X [0.0, 1.0].
    //
    real_1d_array x = "[0.0, 0.5, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array f = "[0.00,0.25,1.00,2.00,2.25,3.00]";
    double vx = 0.25;
    double vy = 0.50;
    double v;
    double dx;
    double dy;
    double dxy;
    spline2dinterpolant s;

    // build spline
    spline2dbuildbicubicv(x, 3, y, 2, f, 1, s);

    // calculate S(0.25,0.50)
    v = spline2dcalc(s, vx, vy);
    printf("%.4f\n", double(v)); // EXPECTED: 1.0625

    // calculate derivatives
    spline2ddiff(s, vx, vy, v, dx, dy, dxy);
    printf("%.4f\n", double(v)); // EXPECTED: 1.0625
    printf("%.4f\n", double(dx)); // EXPECTED: 0.5000
    printf("%.4f\n", double(dy)); // EXPECTED: 2.0000
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use bilinear spline to interpolate f(x,y)=x^2+2*y^2 sampled 
    // at (x,y) from [0.0, 0.5, 1.0] X [0.0, 1.0].
    //
    real_1d_array x = "[0.0, 0.5, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array f = "[0.00,0.25,1.00,2.00,2.25,3.00]";
    double vx = 0.25;
    double vy = 0.50;
    double v;
    spline2dinterpolant s;

    // build spline
    spline2dbuildbilinearv(x, 3, y, 2, f, 1, s);

    // calculate S(0.25,0.50)
    v = spline2dcalc(s, vx, vy);
    printf("%.4f\n", double(v)); // EXPECTED: 1.1250
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We build bilinear spline for f(x,y)=x+2*y for (x,y) in [0,1].
    // Then we apply several transformations to this spline.
    //
    real_1d_array x = "[0.0, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array f = "[0.00,1.00,2.00,3.00]";
    spline2dinterpolant s;
    spline2dinterpolant snew;
    double v;
    spline2dbuildbilinearv(x, 2, y, 2, f, 1, s);

    // copy spline, apply transformation x:=2*xnew, y:=4*ynew
    // evaluate at (xnew,ynew) = (0.25,0.25) - should be same as (x,y)=(0.5,1.0)
    spline2dcopy(s, snew);
    spline2dlintransxy(snew, 2.0, 0.0, 4.0, 0.0);
    v = spline2dcalc(snew, 0.25, 0.25);
    printf("%.4f\n", double(v)); // EXPECTED: 2.500

    // copy spline, apply transformation SNew:=2*S+3
    spline2dcopy(s, snew);
    spline2dlintransf(snew, 2.0, 3.0);
    v = spline2dcalc(snew, 0.5, 1.0);
    printf("%.4f\n", double(v)); // EXPECTED: 8.000

    //
    // Same example, but for vector spline (f0,f1) = {x+2*y, 2*x+y}
    //
    real_1d_array f2 = "[0.00,0.00, 1.00,2.00, 2.00,1.00, 3.00,3.00]";
    real_1d_array vr;
    spline2dbuildbilinearv(x, 2, y, 2, f2, 2, s);

    // copy spline, apply transformation x:=2*xnew, y:=4*ynew
    spline2dcopy(s, snew);
    spline2dlintransxy(snew, 2.0, 0.0, 4.0, 0.0);
    spline2dcalcv(snew, 0.25, 0.25, vr);
    printf("%s\n", vr.tostring(4).c_str()); // EXPECTED: [2.500,2.000]

    // copy spline, apply transformation SNew:=2*S+3
    spline2dcopy(s, snew);
    spline2dlintransf(snew, 2.0, 3.0);
    spline2dcalcv(snew, 0.5, 1.0, vr);
    printf("%s\n", vr.tostring(4).c_str()); // EXPECTED: [8.000,7.000]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We build bilinear spline for f(x,y)=x+2*y+3*xy for (x,y) in [0,1].
    // Then we demonstrate how to unpack it.
    //
    real_1d_array x = "[0.0, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array f = "[0.00,1.00,2.00,6.00]";
    real_2d_array c;
    ae_int_t m;
    ae_int_t n;
    ae_int_t d;
    spline2dinterpolant s;

    // build spline
    spline2dbuildbilinearv(x, 2, y, 2, f, 1, s);

    // unpack and test
    spline2dunpackv(s, m, n, d, c);
    printf("%s\n", c.tostring(4).c_str()); // EXPECTED: [[0, 1, 0, 1, 0,2,0,0, 1,3,0,0, 0,0,0,0, 0,0,0,0 ]]
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We build bilinear vector-valued spline (f0,f1) = {x+2*y, 2*x+y}
    // Spline is built using function values at 2x2 grid: (x,y)=[0,1]*[0,1]
    // Then we perform evaluation at (x,y)=(0.1,0.3)
    //
    real_1d_array x = "[0.0, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array f = "[0.00,0.00, 1.00,2.00, 2.00,1.00, 3.00,3.00]";
    spline2dinterpolant s;
    real_1d_array vr;
    spline2dbuildbilinearv(x, 2, y, 2, f, 2, s);
    spline2dcalcv(s, 0.1, 0.3, vr);
    printf("%s\n", vr.tostring(4).c_str()); // EXPECTED: [0.700,0.500]
    return 0;
}


/************************************************************************* 3-dimensional spline inteprolant *************************************************************************/
class spline3dinterpolant { };
/************************************************************************* This subroutine builds trilinear vector-valued spline. INPUT PARAMETERS: X - spline abscissas, array[0..N-1] Y - spline ordinates, array[0..M-1] Z - spline applicates, array[0..L-1] F - function values, array[0..M*N*L*D-1]: * first D elements store D values at (X[0],Y[0],Z[0]) * next D elements store D values at (X[1],Y[0],Z[0]) * next D elements store D values at (X[2],Y[0],Z[0]) * ... * next D elements store D values at (X[0],Y[1],Z[0]) * next D elements store D values at (X[1],Y[1],Z[0]) * next D elements store D values at (X[2],Y[1],Z[0]) * ... * next D elements store D values at (X[0],Y[0],Z[1]) * next D elements store D values at (X[1],Y[0],Z[1]) * next D elements store D values at (X[2],Y[0],Z[1]) * ... * general form - D function values at (X[i],Y[j]) are stored at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. M,N, L - grid size, M>=2, N>=2, L>=2 D - vector dimension, D>=1 OUTPUT PARAMETERS: C - spline interpolant -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dbuildtrilinearv( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, real_1d_array z, ae_int_t l, real_1d_array f, ae_int_t d, spline3dinterpolant& c);

Examples:   [1]  [2]  

/************************************************************************* This subroutine calculates the value of the trilinear or tricubic spline at the given point (X,Y,Z). INPUT PARAMETERS: C - coefficients table. Built by BuildBilinearSpline or BuildBicubicSpline. X, Y, Z - point Result: S(x,y,z) -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
double alglib::spline3dcalc( spline3dinterpolant c, double x, double y, double z);

Examples:   [1]  

/************************************************************************* This subroutine calculates trilinear or tricubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point OUTPUT PARAMETERS: F - array[D] which stores function values. F is out-parameter and it is reallocated after call to this function. In case you want to reuse previously allocated F, you may use Spline2DCalcVBuf(), which reallocates F only when it is too small. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dcalcv( spline3dinterpolant c, double x, double y, double z, real_1d_array& f);

Examples:   [1]  

/************************************************************************* This subroutine calculates bilinear or bicubic vector-valued spline at the given point (X,Y,Z). INPUT PARAMETERS: C - spline interpolant. X, Y, Z - point F - output buffer, possibly preallocated array. In case array size is large enough to store result, it is not reallocated. Array which is too short will be reallocated OUTPUT PARAMETERS: F - array[D] (or larger) which stores function values -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dcalcvbuf( spline3dinterpolant c, double x, double y, double z, real_1d_array& f);
/************************************************************************* This subroutine performs linear transformation of the spline. INPUT PARAMETERS: C - spline interpolant. A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dlintransf(spline3dinterpolant c, double a, double b);
/************************************************************************* This subroutine performs linear transformation of the spline argument. INPUT PARAMETERS: C - spline interpolant AX, BX - transformation coefficients: x = A*u + B AY, BY - transformation coefficients: y = A*v + B AZ, BZ - transformation coefficients: z = A*w + B OUTPUT PARAMETERS: C - transformed spline -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dlintransxyz( spline3dinterpolant c, double ax, double bx, double ay, double by, double az, double bz);
/************************************************************************* Trilinear spline resampling INPUT PARAMETERS: A - array[0..OldXCount*OldYCount*OldZCount-1], function values at the old grid, : A[0] x=0,y=0,z=0 A[1] x=1,y=0,z=0 A[..] ... A[..] x=oldxcount-1,y=0,z=0 A[..] x=0,y=1,z=0 A[..] ... ... OldZCount - old Z-count, OldZCount>1 OldYCount - old Y-count, OldYCount>1 OldXCount - old X-count, OldXCount>1 NewZCount - new Z-count, NewZCount>1 NewYCount - new Y-count, NewYCount>1 NewXCount - new X-count, NewXCount>1 OUTPUT PARAMETERS: B - array[0..NewXCount*NewYCount*NewZCount-1], function values at the new grid: B[0] x=0,y=0,z=0 B[1] x=1,y=0,z=0 B[..] ... B[..] x=newxcount-1,y=0,z=0 B[..] x=0,y=1,z=0 B[..] ... ... -- ALGLIB routine -- 26.04.2012 Copyright by Bochkanov Sergey *************************************************************************/
void alglib::spline3dresampletrilinear( real_1d_array a, ae_int_t oldzcount, ae_int_t oldycount, ae_int_t oldxcount, ae_int_t newzcount, ae_int_t newycount, ae_int_t newxcount, real_1d_array& b);
/************************************************************************* This subroutine unpacks tri-dimensional spline into the coefficients table INPUT PARAMETERS: C - spline interpolant. Result: N - grid size (X) M - grid size (Y) L - grid size (Z) D - number of components SType- spline type. Currently, only one spline type is supported: trilinear spline, as indicated by SType=1. Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. For T=0..D-1 (component index), I = 0...N-2 (x index), J=0..M-2 (y index), K=0..L-2 (z index): Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), Q-th row stores decomposition for T-th component of the vector-valued function Tbl[Q,0] = X[i] Tbl[Q,1] = X[i+1] Tbl[Q,2] = Y[j] Tbl[Q,3] = Y[j+1] Tbl[Q,4] = Z[k] Tbl[Q,5] = Z[k+1] Tbl[Q,6] = C000 Tbl[Q,7] = C100 Tbl[Q,8] = C010 Tbl[Q,9] = C110 Tbl[Q,10]= C001 Tbl[Q,11]= C101 Tbl[Q,12]= C011 Tbl[Q,13]= C111 On each grid square spline is equals to: S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) t = x-x[j] u = y-y[i] v = z-z[k] NOTE: format of Tbl is given for SType=1. Future versions of ALGLIB can use different formats for different values of SType. -- ALGLIB PROJECT -- Copyright 26.04.2012 by Bochkanov Sergey *************************************************************************/
void alglib::spline3dunpackv( spline3dinterpolant c, ae_int_t& n, ae_int_t& m, ae_int_t& l, ae_int_t& d, ae_int_t& stype, real_2d_array& tbl);
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use trilinear spline to interpolate f(x,y,z)=x+xy+z sampled 
    // at (x,y,z) from [0.0, 1.0] X [0.0, 1.0] X [0.0, 1.0].
    //
    // We store x, y and z-values at local arrays with same names.
    // Function values are stored in the array F as follows:
    //     f[0]     (x,y,z) = (0,0,0)
    //     f[1]     (x,y,z) = (1,0,0)
    //     f[2]     (x,y,z) = (0,1,0)
    //     f[3]     (x,y,z) = (1,1,0)
    //     f[4]     (x,y,z) = (0,0,1)
    //     f[5]     (x,y,z) = (1,0,1)
    //     f[6]     (x,y,z) = (0,1,1)
    //     f[7]     (x,y,z) = (1,1,1)
    //
    real_1d_array x = "[0.0, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array z = "[0.0, 1.0]";
    real_1d_array f = "[0,1,0,2,1,2,1,3]";
    double vx = 0.50;
    double vy = 0.50;
    double vz = 0.50;
    double v;
    spline3dinterpolant s;

    // build spline
    spline3dbuildtrilinearv(x, 2, y, 2, z, 2, f, 1, s);

    // calculate S(0.5,0.5,0.5)
    v = spline3dcalc(s, vx, vy, vz);
    printf("%.4f\n", double(v)); // EXPECTED: 1.2500
    return 0;
}


#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "interpolation.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // We use trilinear vector-valued spline to interpolate {f0,f1}={x+xy+z,x+xy+yz+z}
    // sampled at (x,y,z) from [0.0, 1.0] X [0.0, 1.0] X [0.0, 1.0].
    //
    // We store x, y and z-values at local arrays with same names.
    // Function values are stored in the array F as follows:
    //     f[0]     f0, (x,y,z) = (0,0,0)
    //     f[1]     f1, (x,y,z) = (0,0,0)
    //     f[2]     f0, (x,y,z) = (1,0,0)
    //     f[3]     f1, (x,y,z) = (1,0,0)
    //     f[4]     f0, (x,y,z) = (0,1,0)
    //     f[5]     f1, (x,y,z) = (0,1,0)
    //     f[6]     f0, (x,y,z) = (1,1,0)
    //     f[7]     f1, (x,y,z) = (1,1,0)
    //     f[8]     f0, (x,y,z) = (0,0,1)
    //     f[9]     f1, (x,y,z) = (0,0,1)
    //     f[10]    f0, (x,y,z) = (1,0,1)
    //     f[11]    f1, (x,y,z) = (1,0,1)
    //     f[12]    f0, (x,y,z) = (0,1,1)
    //     f[13]    f1, (x,y,z) = (0,1,1)
    //     f[14]    f0, (x,y,z) = (1,1,1)
    //     f[15]    f1, (x,y,z) = (1,1,1)
    //
    real_1d_array x = "[0.0, 1.0]";
    real_1d_array y = "[0.0, 1.0]";
    real_1d_array z = "[0.0, 1.0]";
    real_1d_array f = "[0,0, 1,1, 0,0, 2,2, 1,1, 2,2, 1,2, 3,4]";
    double vx = 0.50;
    double vy = 0.50;
    double vz = 0.50;
    spline3dinterpolant s;

    // build spline
    spline3dbuildtrilinearv(x, 2, y, 2, z, 2, f, 2, s);

    // calculate S(0.5,0.5,0.5) - we have vector of values instead of single value
    real_1d_array v;
    spline3dcalcv(s, vx, vy, vz, v);
    printf("%s\n", v.tostring(4).c_str()); // EXPECTED: [1.2500,1.5000]
    return 0;
}


onesamplesigntest
/************************************************************************* Sign test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. While calculating p-values high-precision binomial distribution approximation is used, so significance levels have about 15 exact digits. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::onesamplesigntest( real_1d_array x, ae_int_t n, double median, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* Functional inverse of Student's t distribution Given probability p, finds the argument t such that stdtr(k,t) is equal to p. ACCURACY: Tested at random 1 <= k <= 100. The "domain" refers to p: Relative error: arithmetic domain # trials peak rms IEEE .001,.999 25000 5.7e-15 8.0e-16 IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::invstudenttdistribution(ae_int_t k, double p);
/************************************************************************* Student's t distribution Computes the integral from minus infinity to t of the Student t distribution with integer k > 0 degrees of freedom: t - | | - | 2 -(k+1)/2 | ( (k+1)/2 ) | ( x ) ---------------------- | ( 1 + --- ) dx - | ( k ) sqrt( k pi ) | ( k/2 ) | | | - -inf. Relation to incomplete beta integral: 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) where z = k/(k + t**2). For t < -2, this is the method of computation. For higher t, a direct method is derived from integration by parts. Since the function is symmetric about t=0, the area under the right tail of the density is found by calling the function with -t instead of t. ACCURACY: Tested at random 1 <= k <= 25. The "domain" refers to t. Relative error: arithmetic domain # trials peak rms IEEE -100,-2 50000 5.9e-15 1.4e-15 IEEE -2,100 500000 2.7e-15 4.9e-17 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier *************************************************************************/
double alglib::studenttdistribution(ae_int_t k, double t);
/************************************************************************* One-sample t-test This test checks three hypotheses about the mean of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the mean is equal to the given value) * left-tailed test (null hypothesis - the mean is greater than or equal to the given value) * right-tailed test (null hypothesis - the mean is less than or equal to the given value). The test is based on the assumption that a given sample has a normal distribution and an unknown dispersion. If the distribution sharply differs from normal, the test will work incorrectly. INPUT PARAMETERS: X - sample. Array whose index goes from 0 to N-1. N - size of sample, N>=0 Mean - assumed value of the mean. OUTPUT PARAMETERS: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0, all p-values are set to 1.0 * when variance of X[] is exactly zero, p-values are set to 1.0 or 0.0, depending on difference between sample mean and value of mean being tested. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::studentttest1( real_1d_array x, ae_int_t n, double mean, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* Two-sample pooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * dispersions are equal * samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has exactly zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::studentttest2( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* Two-sample unpooled test This test checks three hypotheses about the mean of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the means are equal) * left-tailed test (null hypothesis - the mean of the first sample is greater than or equal to the mean of the second sample) * right-tailed test (null hypothesis - the mean of the first sample is less than or equal to the mean of the second sample). Test is based on the following assumptions: * given samples have normal distributions * samples are independent. Equality of variances is NOT required. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Y - sample 2. Array whose index goes from 0 to M-1. M - size of the sample. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. NOTE: this function correctly handles degenerate cases: * when N=0 or M=0, all p-values are set to 1.0 * when both samples has zero variance, p-values are set to 1.0 or 0.0, depending on difference between means. * when only one sample has zero variance, test reduces to 1-sample version. -- ALGLIB -- Copyright 18.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::unequalvariancettest( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, double& bothtails, double& lefttail, double& righttail);
rmatrixsvd
/************************************************************************* Singular value decomposition of a rectangular matrix. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is only partially supported (some parts are ! optimized, but most - are not). ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. The algorithm calculates the singular value decomposition of a matrix of size MxN: A = U * S * V^T The algorithm finds the singular values and, optionally, matrices U and V^T. The algorithm can find both first min(M,N) columns of matrix U and rows of matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM and NxN respectively). Take into account that the subroutine does not return matrix V but V^T. Input parameters: A - matrix to be decomposed. Array whose indexes range within [0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. UNeeded - 0, 1 or 2. See the description of the parameter U. VTNeeded - 0, 1 or 2. See the description of the parameter VT. AdditionalMemory - If the parameter: * equals 0, the algorithm doesnt use additional memory (lower requirements, lower performance). * equals 1, the algorithm uses additional memory of size min(M,N)*min(M,N) of real numbers. It often speeds up the algorithm. * equals 2, the algorithm uses additional memory of size M*min(M,N) of real numbers. It allows to get a maximum performance. The recommended value of the parameter is 2. Output parameters: W - contains singular values in descending order. U - if UNeeded=0, U isn't changed, the left singular vectors are not calculated. if Uneeded=1, U contains left singular vectors (first min(M,N) columns of matrix U). Array whose indexes range within [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U contains matrix U wholly. Array whose indexes range within [0..M-1, 0..M-1]. VT - if VTNeeded=0, VT isnt changed, the right singular vectors are not calculated. if VTNeeded=1, VT contains right singular vectors (first min(M,N) rows of matrix V^T). Array whose indexes range within [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT contains matrix V^T wholly. Array whose indexes range within [0..N-1, 0..N-1]. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/
bool alglib::rmatrixsvd( real_2d_array a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, real_1d_array& w, real_2d_array& u, real_2d_array& vt); bool alglib::smp_rmatrixsvd( real_2d_array a, ae_int_t m, ae_int_t n, ae_int_t uneeded, ae_int_t vtneeded, ae_int_t additionalmemory, real_1d_array& w, real_2d_array& u, real_2d_array& vt);
/************************************************************************* LU decomposition of a general complex matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/
void alglib::cmatrixlu( complex_2d_array& a, ae_int_t m, ae_int_t n, integer_1d_array& pivots); void alglib::smp_cmatrixlu( complex_2d_array& a, ae_int_t m, ae_int_t n, integer_1d_array& pivots);
/************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a Hermitian positive- definite matrix. The result of an algorithm is a representation of A as A=U'*U or A=L*L' (here X' detones conj(X^T)). COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U'*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
bool alglib::hpdmatrixcholesky( complex_2d_array& a, ae_int_t n, bool isupper); bool alglib::smp_hpdmatrixcholesky( complex_2d_array& a, ae_int_t n, bool isupper);
/************************************************************************* LU decomposition of a general real matrix with row pivoting A is represented as A = P*L*U, where: * L is lower unitriangular matrix * U is upper triangular matrix * P = P0*P1*...*PK, K=min(M,N)-1, Pi - permutation matrix for I and Pivots[I] This is cache-oblivous implementation of LU decomposition. It is optimized for square matrices. As for rectangular matrices: * best case - M>>N * worst case - N>>M, small M, large N, matrix does not fit in CPU cache COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..M-1, 0..N-1]. M - number of rows in matrix A. N - number of columns in matrix A. OUTPUT PARAMETERS: A - matrices L and U in compact form: * L is stored under main diagonal * U is stored on and above main diagonal Pivots - permutation matrix in compact form. array[0..Min(M-1,N-1)]. -- ALGLIB routine -- 10.01.2010 Bochkanov Sergey *************************************************************************/
void alglib::rmatrixlu( real_2d_array& a, ae_int_t m, ae_int_t n, integer_1d_array& pivots); void alglib::smp_rmatrixlu( real_2d_array& a, ae_int_t m, ae_int_t n, integer_1d_array& pivots);
/************************************************************************* Sparse Cholesky decomposition for skyline matrixm using in-place algorithm without allocating additional storage. The algorithm computes Cholesky decomposition of a symmetric positive- definite sparse matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T This function is a more efficient alternative to general, but slower SparseCholeskyX(), because it does not create temporary copies of the target. It performs factorization in-place, which gives best performance on low-profile matrices. Its drawback, however, is that it can not perform profile-reducing permutation of input matrix. INPUT PARAMETERS: A - sparse matrix in skyline storage (SKS) format. N - size of matrix A (can be smaller than actual size of A) IsUpper - if IsUpper=True, then factorization is performed on upper triangle. Another triangle is ignored (it may contant some data, but it is not changed). OUTPUT PARAMETERS: A - the result of factorization, stored in SKS. If IsUpper=True, then the upper triangle contains matrix U, such that A = U^T*U. Lower triangle is not changed. Similarly, if IsUpper = False. In this case L is returned, and we have A = L*(L^T). Note that THIS function does not perform permutation of rows to reduce bandwidth. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. NOTE: for performance reasons this function does NOT check that input matrix includes only finite values. It is your responsibility to make sure that there are no infinite or NAN values in the matrix. -- ALGLIB routine -- 16.01.2014 Bochkanov Sergey *************************************************************************/
bool alglib::sparsecholeskyskyline( sparsematrix a, ae_int_t n, bool isupper);
/************************************************************************* Cache-oblivious Cholesky decomposition The algorithm computes Cholesky decomposition of a symmetric positive- definite matrix. The result of an algorithm is a representation of A as A=U^T*U or A=L*L^T COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - upper or lower triangle of a factorized matrix. array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - if IsUpper=True, then A contains an upper triangle of a symmetric matrix, otherwise A contains a lower one. OUTPUT PARAMETERS: A - the result of factorization. If IsUpper=True, then the upper triangle contains matrix U, so that A = U^T*U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. RESULT: If the matrix is positive-definite, the function returns True. Otherwise, the function returns False. Contents of A is not determined in such case. -- ALGLIB routine -- 15.12.2009 Bochkanov Sergey *************************************************************************/
bool alglib::spdmatrixcholesky( real_2d_array& a, ae_int_t n, bool isupper); bool alglib::smp_spdmatrixcholesky( real_2d_array& a, ae_int_t n, bool isupper);
/************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateAdd1Buf(). INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/
void alglib::spdmatrixcholeskyupdateadd1( real_2d_array& a, ae_int_t n, bool isupper, real_1d_array u);
/************************************************************************* Update of Cholesky decomposition: rank-1 update to original A. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateAdd1() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. U - array[N], rank-1 update to A: A_mod = A + u*u' Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/
void alglib::spdmatrixcholeskyupdateadd1buf( real_2d_array& a, ae_int_t n, bool isupper, real_1d_array u, real_1d_array& bufr);
/************************************************************************* Update of Cholesky decomposition: "fixing" some variables. This function uses internally allocated buffer which is not saved between subsequent calls. So, if you perform a lot of subsequent updates, we recommend you to use "buffered" version of this function: SPDMatrixCholeskyUpdateFixBuf(). "FIXING" EXPLAINED: Suppose we have N*N positive definite matrix A. "Fixing" some variable means filling corresponding row/column of A by zeros, and setting diagonal element to 1. For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) ( A10 A11 A12 A13 ) ( 0 1 0 0 ) ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) If we have Cholesky decomposition of A, it must be recalculated after variables were fixed. However, it is possible to use efficient algorithm, which needs O(K*N^2) time to "fix" K variables, given Cholesky decomposition of original, "unfixed" A. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. NOTE: this function always succeeds, so it does not return completion code NOTE: this function checks sizes of input arrays, but it does NOT checks for presence of infinities or NAN's. NOTE: this function is efficient only for moderate amount of updated variables - say, 0.1*N or 0.3*N. For larger amount of variables it will still work, but you may get better performance with straightforward Cholesky. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/
void alglib::spdmatrixcholeskyupdatefix( real_2d_array& a, ae_int_t n, bool isupper, boolean_1d_array fix);
/************************************************************************* Update of Cholesky decomposition: "fixing" some variables. "Buffered" version which uses preallocated buffer which is saved between subsequent function calls. See comments for SPDMatrixCholeskyUpdateFix() for more information. INPUT PARAMETERS: A - upper or lower Cholesky factor. array with elements [0..N-1, 0..N-1]. Exception is thrown if array size is too small. N - size of matrix A, N>0 IsUpper - if IsUpper=True, then A contains upper Cholesky factor; otherwise A contains a lower one. Fix - array[N], I-th element is True if I-th variable must be fixed. Exception is thrown if array size is too small. BufR - possibly preallocated buffer; automatically resized if needed. It is recommended to reuse this buffer if you perform a lot of subsequent decompositions. OUTPUT PARAMETERS: A - updated factorization. If IsUpper=True, then the upper triangle contains matrix U, and the elements below the main diagonal are not modified. Similarly, if IsUpper = False. -- ALGLIB -- 03.02.2014 Sergey Bochkanov *************************************************************************/
void alglib::spdmatrixcholeskyupdatefixbuf( real_2d_array& a, ae_int_t n, bool isupper, boolean_1d_array fix, real_1d_array& bufr);
/************************************************************************* Hyperbolic sine and cosine integrals Approximates the integrals x - | | cosh t - 1 Chi(x) = eul + ln x + | ----------- dt, | | t - 0 x - | | sinh t Shi(x) = | ------ dt | | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are evaluated by power series for x < 8 and by Chebyshev expansions for x between 8 and 88. For large x, both functions approach exp(x)/2x. Arguments greater than 88 in magnitude return MAXNUM. ACCURACY: Test interval 0 to 88. Relative error: arithmetic function # trials peak rms IEEE Shi 30000 6.9e-16 1.6e-16 Absolute error, except relative when |Chi| > 1: IEEE Chi 30000 8.4e-16 1.4e-16 Cephes Math Library Release 2.8: June, 2000 Copyright 1984, 1987, 2000 by Stephen L. Moshier *************************************************************************/
void alglib::hyperbolicsinecosineintegrals( double x, double& shi, double& chi);
/************************************************************************* Sine and cosine integrals Evaluates the integrals x - | cos t - 1 Ci(x) = eul + ln x + | --------- dt, | t - 0 x - | sin t Si(x) = | ----- dt | t - 0 where eul = 0.57721566490153286061 is Euler's constant. The integrals are approximated by rational functions. For x > 8 auxiliary functions f(x) and g(x) are employed such that Ci(x) = f(x) sin(x) - g(x) cos(x) Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) ACCURACY: Test interval = [0,50]. Absolute error, except relative when > 1: arithmetic function # trials peak rms IEEE Si 30000 4.4e-16 7.3e-17 IEEE Ci 30000 6.9e-16 5.1e-17 Cephes Math Library Release 2.1: January, 1989 Copyright 1984, 1987, 1989 by Stephen L. Moshier *************************************************************************/
void alglib::sinecosineintegrals(double x, double& si, double& ci);
ftest
onesamplevariancetest
/************************************************************************* Two-sample F-test This test checks three hypotheses about dispersions of the given samples. The following tests are performed: * two-tailed test (null hypothesis - the dispersions are equal) * left-tailed test (null hypothesis - the dispersion of the first sample is greater than or equal to the dispersion of the second sample). * right-tailed test (null hypothesis - the dispersion of the first sample is less than or equal to the dispersion of the second sample) The test is based on the following assumptions: * the given samples have normal distributions * the samples are independent. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - sample size. Y - sample 2. Array whose index goes from 0 to M-1. M - sample size. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::ftest( real_1d_array x, ae_int_t n, real_1d_array y, ae_int_t m, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* One-sample chi-square test This test checks three hypotheses about the dispersion of the given sample The following tests are performed: * two-tailed test (null hypothesis - the dispersion equals the given number) * left-tailed test (null hypothesis - the dispersion is greater than or equal to the given number) * right-tailed test (null hypothesis - dispersion is less than or equal to the given number). Test is based on the following assumptions: * the given sample has a normal distribution. Input parameters: X - sample 1. Array whose index goes from 0 to N-1. N - size of the sample. Variance - dispersion value to compare with. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. -- ALGLIB -- Copyright 19.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::onesamplevariancetest( real_1d_array x, ae_int_t n, double variance, double& bothtails, double& lefttail, double& righttail);
wilcoxonsignedranktest
/************************************************************************* Wilcoxon signed-rank test This test checks three hypotheses about the median of the given sample. The following tests are performed: * two-tailed test (null hypothesis - the median is equal to the given value) * left-tailed test (null hypothesis - the median is greater than or equal to the given value) * right-tailed test (null hypothesis - the median is less than or equal to the given value) Requirements: * the scale of measurement should be ordinal, interval or ratio (i.e. the test could not be applied to nominal variables). * the distribution should be continuous and symmetric relative to its median. * number of distinct values in the X array should be greater than 4 The test is non-parametric and doesn't require distribution X to be normal Input parameters: X - sample. Array whose index goes from 0 to N-1. N - size of the sample. Median - assumed median value. Output parameters: BothTails - p-value for two-tailed test. If BothTails is less than the given significance level the null hypothesis is rejected. LeftTail - p-value for left-tailed test. If LeftTail is less than the given significance level, the null hypothesis is rejected. RightTail - p-value for right-tailed test. If RightTail is less than the given significance level the null hypothesis is rejected. To calculate p-values, special approximation is used. This method lets us calculate p-values with two decimal places in interval [0.0001, 1]. "Two decimal places" does not sound very impressive, but in practice the relative error of less than 1% is enough to make a decision. There is no approximation outside the [0.0001, 1] interval. Therefore, if the significance level outlies this interval, the test returns 0.0001. -- ALGLIB -- Copyright 08.09.2006 by Bochkanov Sergey *************************************************************************/
void alglib::wilcoxonsignedranktest( real_1d_array x, ae_int_t n, double e, double& bothtails, double& lefttail, double& righttail);
/************************************************************************* *************************************************************************/
class xdebugrecord1 { ae_int_t i; alglib::complex c; real_1d_array a; };
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb1appendcopy(boolean_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 1D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::xdebugb1count(boolean_1d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb1not(boolean_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered elements set to True. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb1outeven(ae_int_t n, boolean_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Counts number of True values in the boolean 2D array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::xdebugb2count(boolean_2d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by NOT(a[i]). Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb2not(boolean_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb2outsin(ae_int_t m, ae_int_t n, boolean_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugb2transpose(boolean_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc1appendcopy(complex_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc1neg(complex_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc1outeven(ae_int_t n, complex_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
alglib::complex alglib::xdebugc1sum(complex_1d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc2neg(complex_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc2outsincos( ae_int_t m, ae_int_t n, complex_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
alglib::complex alglib::xdebugc2sum(complex_2d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugc2transpose(complex_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi1appendcopy(integer_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi1neg(integer_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I, and odd-numbered ones set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi1outeven(ae_int_t n, integer_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::xdebugi1sum(integer_1d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi2neg(integer_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi2outsin(ae_int_t m, ae_int_t n, integer_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
ae_int_t alglib::xdebugi2sum(integer_2d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugi2transpose(integer_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Creates and returns XDebugRecord1 structure: * integer and complex fields of Rec1 are set to 1 and 1+i correspondingly * array field of Rec1 is set to [2,3] -- ALGLIB -- Copyright 27.05.2014 by Bochkanov Sergey *************************************************************************/
void alglib::xdebuginitrecord1(xdebugrecord1& rec1);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
double alglib::xdebugmaskedbiasedproductsum( ae_int_t m, ae_int_t n, real_2d_array a, real_2d_array b, boolean_2d_array c);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Appends copy of array to itself. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr1appendcopy(real_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -A[I] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr1neg(real_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate N-element array with even-numbered A[I] set to I*0.25, and odd-numbered ones are set to 0. Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr1outeven(ae_int_t n, real_1d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
double alglib::xdebugr1sum(real_1d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Replace all values in array by -a[i,j] Array is passed using "shared" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr2neg(real_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Generate MxN matrix with elements set to "Sin(3*I+5*J)" Array is passed using "out" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr2outsin(ae_int_t m, ae_int_t n, real_2d_array& a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Returns sum of elements in the array. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
double alglib::xdebugr2sum(real_2d_array a);
/************************************************************************* This is debug function intended for testing ALGLIB interface generator. Never use it in any real life project. Transposes array. Array is passed using "var" convention. -- ALGLIB -- Copyright 11.10.2013 by Bochkanov Sergey *************************************************************************/
void alglib::xdebugr2transpose(real_2d_array& a);
qmapshack-1.10.0/cmake_uninstall.cmake.in000644 001750 000144 00000001654 12374350216 021513 0ustar00oeichlerxusers000000 000000 IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF(EXISTS "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF(EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) qmapshack-1.10.0/GpxExamples/000755 001750 000144 00000000000 13216664442 017167 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/GpxExamples/qlandkarte.gpx000644 001750 000144 00000006161 12374350216 022034 0ustar00oeichlerxusers000000 000000 7 point Flag, Blue user 100 1405320550point0 Track DarkGray 1405344192Track0 14 bis 1421 140534419214 bis 14210 001 14 14 Waypoint 002 141 141 Waypoint 003 85 85 Waypoint 004 142 142 Waypoint 005 1421 1421 Waypoint qmapshack-1.10.0/GpxExamples/basecamp.gpx000644 001750 000144 00000017061 12374350216 021462 0ustar00oeichlerxusers000000 000000  Garmin International 7 point Flag, Blue user 100 5 1 SymbolAndName 8 2 4 9 6 3 100 5 1 SymbolAndName 8 2 4 9 6 3 2014-07-14T06:49:10Z 14 bis 1421 true Magenta Walking 14 Waypoint ShorterDistance Standard 02004ACE7C00100021230D2308000833274F 141 Waypoint ShorterDistance Standard 000000000000FFFFFFFFFFFFFFFFFFFFFFFF 85 Waypoint ShorterDistance Standard 03004ACE7C000C0021230D230800F43C1052 142 Waypoint ShorterDistance Standard 02004ACE7C00100021230D2308007E396B67 1421 Waypoint ShorterDistance Standard 000000000000FFFFFFFFFFFFFFFFFFFFFFFF Track DarkGray qmapshack-1.10.0/GpxExamples/COPYRIGHT000644 001750 000144 00000001776 12374364620 020474 0ustar00oeichlerxusers000000 000000 *.gpx files in this dir are created by Oliver Eichler and released under GPL-3.0+ license /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ qmapshack-1.10.0/features.txt000644 001750 000144 00000002252 12705713523 017307 0ustar00oeichlerxusers000000 000000 Maps: * Garmin vector maps and *.jnx raster maps * Raster maps supported by GDAL * Online maps (TMS and WTMS (partially)) * Display multiple maps in one view * Reproject maps on-the-fly to view's projection * Digital elevation model independent from maps * Hillshading and slope coloring GIS Data: * 100% project oriented data handling * Summarize project by a diary * Support for tracks, waypoints and areas * Simple geocache support * Store projects in a database * Support for multiple databases Planning: * Undo/redo history for all items * Track point edit mode to create/change tracks * Cut/copy/combine/reverse tracks * Various filter to enhance tracks GPS Devices: * Support for newer Garmin devices * Support for TwoNav devices * Project oriented data organization on devices * Synchronize your project with several devices attached System: * License GPL3+ * Runs on all *nix systems as well as on Windows Probably on OS X, too, but so far no one volunteers to maintain a binary. * GUI has been translated to Czech, French, German and Spanish * Wiki documentation is English * Needs Qt5, GDAL, Proj4 installed * For device support on Linux DBus and UDisk2 must be installed qmapshack-1.10.0/call_Uncrustify.cfg000644 001750 000144 00000007047 12705713523 020566 0ustar00oeichlerxusers000000 000000 newlines=lf tok_split_gte=false utf8_byte=false utf8_force=false indent_cmt_with_tabs=false indent_align_string=false indent_braces=false indent_braces_no_func=false indent_braces_no_class=false indent_braces_no_struct=false indent_brace_parent=false indent_namespace=false indent_extern=false indent_class=true indent_class_colon=false indent_else_if=false indent_var_def_cont=false indent_func_call_param=false indent_func_def_param=false indent_func_proto_param=false indent_func_class_param=false indent_func_ctor_var_param=false indent_template_param=false indent_func_param_double=false indent_relative_single_line_comments=false indent_col1_comment=false indent_access_spec_body=false indent_paren_nl=false indent_comma_paren=false indent_bool_paren=false indent_first_bool_expr=false indent_square_nl=false indent_preserve_sql=false indent_align_assign=true sp_balance_nested_parens=false align_keep_tabs=false align_with_tabs=false align_on_tabstop=false align_number_left=false align_func_params=false align_same_func_call_params=false align_var_def_colon=false align_var_def_attribute=false align_var_def_inline=false align_right_cmt_mix=false align_on_operator=false align_mix_var_proto=false align_single_line_func=false align_single_line_brace=false align_nl_cont=false align_left_shift=true align_oc_decl_colon=false nl_collapse_empty_body=false nl_assign_leave_one_liners=true nl_class_leave_one_liners=true nl_enum_leave_one_liners=false nl_getset_leave_one_liners=false nl_func_leave_one_liners=false nl_if_leave_one_liners=false nl_multi_line_cond=false nl_multi_line_define=false nl_before_case=true nl_after_case=true nl_after_return=false nl_after_semicolon=true nl_after_brace_open=false nl_after_brace_open_cmt=false nl_after_vbrace_open=false nl_after_vbrace_open_empty=false nl_after_brace_close=false nl_after_vbrace_close=false nl_define_macro=false nl_squeeze_ifdef=false nl_ds_struct_enum_cmt=false nl_ds_struct_enum_close_brace=false nl_create_if_one_liner=false nl_create_for_one_liner=false nl_create_while_one_liner=false nl_cpp_lambda_leave_one_liners=true ls_for_split_full=false ls_func_split_full=false nl_after_multiline_comment=false eat_blanks_after_open_brace=true eat_blanks_before_close_brace=true mod_full_brace_if_chain=false mod_pawn_semicolon=false mod_full_paren_if_bool=false mod_remove_extra_semicolon=true mod_sort_import=false mod_sort_using=true mod_sort_include=true mod_move_case_break=false mod_remove_empty_return=true cmt_indent_multi=true cmt_c_group=false cmt_c_nl_start=false cmt_c_nl_end=false cmt_cpp_group=false cmt_cpp_nl_start=false cmt_cpp_nl_end=false cmt_cpp_to_c=false cmt_star_cont=false cmt_multi_check_last=true cmt_insert_before_preproc=false pp_indent_at_level=false pp_region_indent_code=false pp_if_indent_code=false pp_define_at_level=false indent_columns=4 indent_with_tabs=0 nl_assign_brace=add nl_fcall_brace=add nl_enum_brace=add nl_struct_brace=add nl_union_brace=add nl_if_brace=add nl_brace_else=add nl_elseif_brace=ignore nl_else_brace=add nl_brace_finally=add nl_finally_brace=add nl_try_brace=add nl_getset_brace=add nl_for_brace=add nl_catch_brace=add nl_brace_catch=add nl_while_brace=add nl_using_brace=add nl_brace_brace=add nl_do_brace=add nl_brace_while=add nl_switch_brace=add nl_case_colon_brace=add nl_namespace_brace=add nl_template_class=add nl_class_brace=add nl_fdef_brace=add nl_after_switch=add mod_full_brace_do=add mod_full_brace_for=add mod_full_brace_function=add mod_full_brace_if=add mod_full_brace_while=add mod_full_brace_using=add mod_paren_on_return=remove sp_func_proto_paren=remove sp_func_def_paren=remove qmapshack-1.10.0/src/000755 001750 000144 00000000000 13216664445 015524 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/cursors/000755 001750 000144 00000000000 13216664443 017222 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/cursors/wptHighlightBlue.png000644 001750 000144 00000011176 13107015720 023173 0ustar00oeichlerxusers000000 000000 PNG  IHDR==basBIT|d pHYstEXtSoftwarewww.inkscape.org<IDAThY&Ugez8VDD$$8 KDlR @xHH AC$xx^=PLxY$P8ҧ[߭) 0v@@Az& "pEw#UI06yNNm]/r`sҬlv,]0<?>hkN7白0/:}'IA!ݜ0;d[8:T<[>A>}2nMD qSqcnsm"zګ*@1$]p兕z p3皵yԽ$m&\zq8%f9@Dǖ(Dh wCjL[Zt~jnZ`nso lnU':զMuUERN,^9(Q(<ӔQ(j:sx)UjV4T6C++@T0=o{ѤE+"2U*"&" "]PzE{5Iꦞj.ڒ}8w#q?NjKJJ蜘RI#.ds8EUVd fq'vzcs33 }jnTKY[R], ~>7}6@f՜DrI"U,Ք5Sd]ȋppfvq#!=} pdp\;!LkT/=l?F_zl[%Mg咘jp2<&OC$q&!v(,A iGQDPp`bZZbpemR=: ]Բ%ÍqW7g^47bHB%% jIj##0$Dp``f `=z0ZdU"Rv\D#(DQela?:Cr!Mb?gsB55QÒDLU!U$/NV_=pb,K޷pᅓ qF1 5TD"ù(tPA4+@lޏK5ݽ<߮ꙜjP%'Ԡ d)aH١L&rU7?_|/NYsﱽ @+wM6>{jRKpu`Ԃ\ҮϊRCn}ӐjnP3~ :n\&17TġUfGiA>>ޭߏp}Ͽ}RԔ*TUjuZ]\&v7OIfAh6iK'"2n\4T5)ӠMO,?3\sxn?/i 4hfӆ&s!sjAO:B!Ua3|3M#ק<1+>J-xw~_Eƥ/WfVEU&Bց;BRRTrEkFXapuӍœ9+='<X+k]]KT 8D=H#."ZKSM7)z31SY܄b$U &_G=(GZ5+a%M ul6 #<3@a<{x),c,Bc W[3u;G<OM W!,2>FbiZt WaY`Kotera';kN}sD0EtpU {yGN1[sD9@DcL˘g`COav}Ea14 y v`<fiô) QHyzlo:±OT 39/ 1Fdmwbbt )15ƴcă"hZ+wa'K{E"2!31#QYYY:chKQHfQKEaj^ڋ9؛BHUmC6W1R5UMo a'=b<箇,gUpSGe%l߁_=3N<+\h$1Jup Q-zMܸZPQ1*'3.Y4FQ&h DNG$G~@9\փh #cl?b&" "8f(E0nuT"#KKG8A ߴc܏_g'ݗFcQeF#GҬtsR1jKyw,'œWmvKlFjjdL4=rqrih7Z;˘PXHc<,`bo[fb6J|x?m.fVlvJcb3k\ѿ abCjj23FtT֮,uuasGm.whn9|wӫRdɂƣɆԘʘt)z MZj5"68\ke2Q[*_S&?T+8ͷx+O^DeYwQȯV+A t25RkEMY"l}h\Grn=|Ax-K/<5mWʣRufffZ4[Z:2IԼR0Vu !ZjuZFbh{ϬM6p [ G㡳?gY,G0&G3C#6-j(<75~n-nl!M{_fwСaJaqz|?J])ׇ}<߮RFܚ9Xno4fsMƵeFI>SwnW~k He.˵dСR{j}`,M^׆j~úo(9P N c\:d>;biX|Kny.d{x8߃贇r>=Tbh~S3l-,:zW((ٗng!+I- (2I"pO{ϞGn2NM.>syo{@;f"R{M&˜Ae.NZ,tєcF!y'w4d}e;:k;~@LƳ|ks뷔s֯ ܏v4rYlQhjQj:.N,s݉{;%(R{/a5_2"7U3:T .RzhJT2D3tPQR°y^‘Ej ^±3ؐG2ITP8Cݫ{LkUB\171hAZj[BV2f|]|9c3?7x Y7{xY,#a=kq}kz/:VzHsN%u8IENDB`qmapshack-1.10.0/src/cursors/cursorPointMove.png000644 001750 000144 00000002640 13107540101 023067 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME 4X|h-IDATXý_henM3v!M>Ik`Ul"FAL4R d-"Z*j-JR`җ[(TRJiR0wwvfvfvݦi]Ł ;3{wϹR0^* XKDJ I$O&_,,,H{{S]]=<$] j@Du]9xWSSs u@ 0W l""AhSkzAcU x'8r%u 8\}.\۾}{G<Tq2 ($.b&###ޭxF/@(@Rm#"aX(O/^(]]]Y۶1`9 $OAd2wX D)${u0 Oi6A`vvT*uWҥ@Dl6KGG;55,Ƀ(XyXűcbi> 4jaV rܲ/mq)< ,8,bllL&@ę['+rm?B'/ ] eXuBxa _&xM<ʛDh ʫw$˟<|' Cb9u/Sbeе*6JϏJj 8*D  m޼9B= zI0 |bB(UkWR*eh.`&gϞ5bA.mmmFOks9"8x(`V}"x|t/v~ Q%;D8aHBD jҭm}}}#dY6l؀M|$pRz$ GW_ DELɓ'vvvZlfܘ!B.>&pZJy`p![2(i`nׁMOLLP]]Phdi⬣mT,0Ȁ$LrxJTsK78-mەRD,_R4}|EcA9|*PGFrXvT?xYV2R:Qt4Dks6/P@q[:^iFX|j\;//\04l ` eDR\Ώݥ.@)=;{oDU9""p+:s韏FZbmMqC唅Si_ı\Qh[!F!%}]?4qBdgE5x'AlN=g:Ƒ0@U3SfsJU%IdsfLJlj ZdҁpYò;L;sӛs"03_u7i|nfZė'pꇈ|.k~os&/!#``·i9uI,6P}˚|ys#Μ:4mZ!k{t@ۥ9"GukKD~YxKߠmOm aIZ6 ?|8#9|0;mZXp]{Ni|Lhv/򗨾x~B;wG® ^ DOQ7luعYo担[Yz8c:@K ׁ61_dž]-kFuyDOzؔL~:˚9&;Ӓ$b'dU9D?~O p.?DͮI7tߝervksle"1 5`Hl_b5OhpL??OU>`? Sb(OJ&sEg>fW77ө=i {je:"۝'O7r{,ik=өgs3=szOJE 2aOڤ*.cl&ww_3|v=71:Ξuy.^4enœ_l<~ITsLwO/aFd4g^Et]m/{] kYzb{Pr<{cS2Ng#2f'}pwD9wO_ ׯcwh:Gz;<``ny1<ƾBѶ ޷ؔ72cp4RHci$e-[:Uvd|.yB3 Lz,`m7c @\/ 8-9Zb42ڶa6k{)[[i潬q]un!ƣ_nIDATxMlEuۀR !z䂔cS)=Q=p@H@HPDV*Ԑu F?g8kNb#H#{wv}o3[8F@ Dz&"HK⽖eWeY9`:4HV*sssR*dvvV,rN4 ,@xXB H*˲(*fB@P(H>qD)%mK24 I щD3f4]DD)%lVemmM._,h4 /G~a[`2aYV.JI.۶%ښ̌Y>@ 2@zܲ|2D"bf F"uพg 6x`ki06R"lV (3i.^(i:z^7[X"JquVP姁>@R$m צinܸ!LF460iDչ-TȢwS"FEfT4V/TfpaM\@=Dg&ohfZ+炚]Ӣl2۵fkD҂hKWZ_-6ZoIENDB`qmapshack-1.10.0/src/cursors/cursorArrow.png000644 001750 000144 00000002423 12647363442 022263 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzgAMA asRGB, cHRMz&u0a:p pHYs  ~tIME0*C|0tEXtFile NameC:\Eric\Eric'stuff\polar\1.4\Arrow.png7EctEXtSoftwareAdobe Photoshop4ˎg!tEXtWriterSuperPNG by Brendan BollestIDATxݗK,gq?4qIb\D#)cJogW 6)L`-nVPJR\..&$~;_';z37 v9] 蘦 PƀQ ,233Ji`#RPVπ`=&3rr2읽}JIENDB`qmapshack-1.10.0/src/cursors/cursorMoveArea.png000644 001750 000144 00000003411 12647363442 022666 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME  {IDATXý}lUg?9=z&-lK%a+"88^*.M[Tj$b h!Dkt:cXjlXѶFK=ןVIy~o_R01 @1CDf4*v `bbB֬Y+++U@ c&1+q-//X,.ĬDD HE@RǴ f+H.3gN0ulħp]WlۖL&#tZR;wNjjjrhx.읂s@y$IDn`vGdy`p1itww677J$J`vGBNm! é pSNIcccֶHY@ .1kd2D)07ov&''aC aNbVccc1v!ͲuVgttEqځ1 S)ʕ+Rp. m\6J>K>ܫ3,p`RD@hax&϶t:X#r -pjPB|8 Da@C$u؍%gZ| (} h\DD"m "? CGa؇!DV0O~p u Apq˲ }?q ˰"@*ZMz qqp]u<u}0 ,Aq3ɼ`|>Mث^qwsu娨qD \bŊ iWNuUp!?o-a%!\_t\ڀRʫ549|aYA8˗/7b£8F.XR?QaT䢩~ ѕIHR;/"r  pywaxOa/HL%K`Ƃ$<].'{E(<^Gj;Iz7( NuM҅咈^z|4f$I\M 2N hgͪ/MwD䄀}V|RQ]iSsx Ѳ˱cǤ1,k:O@pPy ~WJB4tZi=3/T툆 T7 &\|^)Y,<OޙxKCu-}:hxe`:@˰k|.@e g]EhTKօ:72^y9/^zwM^("$X@~;RkZXPг)̳`&a  p6aà W8Mt,> ¯߀R=OSBJa6 lN6[:N6Îgn2Zh-2NhH` %)X>chf4& OKJJJRb ()eeeH$E@ #@DĶmYzSTT #@0n'R__8D !8b۶i9r?:`F?%>q$LeY%ɓ'eP(TLd<u<F:t(8cƌp8\ p}%N. aPWWXbpxp/0@O2D$L&2 "[T2\ 41 KX 'iRQQa'MLS[ _e'Jڶ[zs4ټys0 %୦hWf4gq\4M/_&\Gg6 m2c?Ԯȹm& rҥV m.XR@#>Ȭ ?iG/^JgΜŋ4."R^^Z#|^ o[}|VjVAUt.--M97m]qt]&yqT 6вf!qnJaZ䊫seH|ATA t yضMLn4 ǎsm>obBB: { w>cx ws':6-UIENDB`qmapshack-1.10.0/src/cursors/COPYRIGHT000644 001750 000144 00000000537 12374350216 020514 0ustar00oeichlerxusers000000 000000 All icons in this directory are from http://www.rw-designer.com/cursor-set/proton files are public domain. Quote from source web pages: -------------------------------------------- Released to Public Domain You are free: To use this work for any legal purpose. -------------------------------------------- http://www.rw-designer.com/licenses qmapshack-1.10.0/src/cursors/cursorMoveWpt.png000644 001750 000144 00000002552 12647363442 022575 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME % IDATXýMh\UL#i3ic*6jńhA\XALj!RB)Pi6HdJ nLhA0 "d!bb-I$M&޼"w/I g1{s~Ry0I1@Q @d2 4i0y*d210*FU""ȑ#Gܺ@ HfUA A:m@V, uq) r/qخ*GU+eI>\.' r imm-֎ÕY)!y>lK.%:::0PTk (i>\:6t$aY"BaXzp||\zzzl˲1`)bwQJ155ž}Sa~!,)BT0;;K.[t%`6EqY _`] u]b 4;F-D#V{T^ϲ/tGP@1sX,ؘMYSI^uX~߲/ÈIJSj0Ex\]fu] `hh(}*0CnUv(u }3uK}0 I$LLLx\bw/|k(5RV JH*BD;wuHJg3l}bI(xx}YR^{{ ɹsD"A8C[[L&ڶiwe'f0.ϡe4H4-IVBD^;0<<\mر06 v_DN_K/wܑeYg76刳*mے$‚LLLHkkkvl'JXAyB<&❝ݩTjxh0tD+z}0H$pԩSS-%CGEPdYlFD`=A,o}8mHAr+QJ155šCA|c@؀. lvե@Dq״ +35P:.hx$0֏h1 šL&-ضI׹ (z`KF)S=k*IRPtzV(l 81b$۲ @Zes]˲ <ϻL$l~r ¹DEDMlB+."{>YXXqڰ,kKk$.X! lō5i,͜ DJ&itGFaӦM۴tA\pRE'OD@J5@|$uuu eeJ^q`||DT0}֟f`V|&.hv1NZ6- T3 image/svg+xml qmapshack-1.10.0/src/cursors/cursorPointAdd.png000644 001750 000144 00000002476 13107540153 022667 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME 4+$IDATXýMh\UJ&Xkm]X,DlE]n\7f+D`h Rth"EpQjb^Iy_wsr,z hJ@&4d嵴 l:2`yyY>췵MO]@H4Z˙3g` (V!Xr\*F[h c @\~]:::|˲OmnEMA 8RդZٳ/Jc>Q~lH(Ð(Jd\.\hXq.mӧC&j$jx$Y}ڵkr u`1 i XZZq5ARrqA$)DS j{]""xG__'h`S \ma?riaX:u*t] ӮLH#PoѬr9&&&dqqqz]RWJ Ii oda088Q}1I+",^o XmkB_,I(̘{ #̣M(Bk}O7REB-d* Zo >PVW{@߿?ƍ3@E>TCI:!hR~S;JlҥKVX$ctww[---y`>3u}63ϯtvCݔVQD >::Vx޽{,kgBB5o D& D|ŋ image/svg+xml qmapshack-1.10.0/src/cursors/cursorSelectArea.png000644 001750 000144 00000002271 12705713524 023175 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME ) rFIDATXý=hG3{w H1"E Q&۠]0ܦ vB *TH`ƖP>$Y~KYyu-d`cYC)kjb%"6fG0 :}::0 l*@D$cvZ2<<>\9+""Y[[3v>Vg#IHEޱh yAazV{c}Y.>L8~doyy9 (bttpj1cHӔkB5$BT:==Kqܹ]CLNNfA +ȸS9Z|5??J!ϟGk~R` /Jt_"rwggq0$IfJ$4*S$lO'(llltX^^ε;/P Tqܱ`5k43JFm`fjfͳZ6T6>z2vzm :<@'Nkц'i"51m1ÉSu$TDcJݼ>|> "-+q1wI2ig{o{\,rm~:$,iiHOOyH[XYYr&znS j "#G3sV 8B "DZ 8NW@)8 D)%rY.^(ll1Qf@y+RIŢ\rEo^2wg6֚(Ð(\.xjϞ=tS kڑhU q-q=8&Lg'{L;wT*y"ֺVu.\ c@e[n e1??޽{Za RiC " Ry` pVA@"ĉ)q3L;?]a÷_"BWW =ص[׆h~% dyyyjVzTK |>yQ[eYgZXP)U[A`6###:I`Δ@l۽{ﳳ?~Ǯ]oQ8+[ŲHRLLLJI53Lگfz|ֲWX'" k.bla}ԩo3}d*W r$Mw~|E׭ ˲¾>pӧO۩T8QJkwvv>~X)xoIGh{kih(dhh(L5ڹs'm?X|%ZȈiʿnN<9r9 șJYp ?>*X+ׁz\>V(Vd2h۶4ܸVfnNHTy˜I81~˲>H&>R}`Tj8GϿ-"oUauFuof<ʙm3I1b {%s$u̞[1?L!"?1MB:zs B|o~l"4Ɋf,F0]cpd: A֏@/[[[r̙R#@&=hڵkq` xSDD1RL\nc@#1DZh%"w DJVN@/FC<~X= 9=&qv ,#MS$!MS4Z>}z\.G\|)c̎Vu_zT\|cӑ?FAY'˲wޕ/AL@04S5&q%Ξ=ȲlBnBNxn! CZouoBtKv1\Iu/!+Lkނ$I<}JW\I Ŗk% 4#֕嘟%o=){jٳg\D(% 7D%ȥ!":;͡1͹ydi>mIx:rpԴ MAh_ɽ1%yOs|%w;ؽODQT*!"c0Ɛ$ };ƶINjvv^!ǏG)~R-`x#"wJ]% C*qWmm` XOQݨjۋT*fff2Al76emj||>ZD6r֭G ;rXmL$7kk|U; ([zWA}^"7{'2'][+>_%Ýs2 h.1yDd ծ"՞OfvXbݰm3stis~ѣλ~Sv Dڒ&\ t^bM]s aeeD+Kӌ > Nt;DCIENDB`qmapshack-1.10.0/src/cursors/cursorMoveMap.png000644 001750 000144 00000003306 12647363442 022536 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME /sSIDATXý]h|dQq+ʬpii/VĠKHFmR,jaW7bIv%I5XGq>ϧ}fS }\/=s΃()UU |(2QYY Vˀ``vvVl߾=[ZZ|d4D(!0MS=z*++>~@[(DBẮ~ 'ZBcAE+,il6+Ē%K6J"΢,tZR)L&ܜ"g@ VKP(LOOk.ŋ=Hf(D"A2/Ad2k>z 4O X,50eYŋ},?)m/4!%%%t3YSi( W9-4]Ϟ=&d4S_ ` !u'N8tW+0; Ei4ͼY\|sg!Y`0;@#EQE)qY8xgxx6MsT:O/ N@ ~v^ dY-[˗SRRu)ڰa!̒O؀onnݪ*ԩSMMMu]PVP}>(qF.iW\Q~?b& j0|'*477W|>'}뮮.G42 XU!#aݷoߟ/\p###=BK}555?Ǐ"˥#Ee {uݿ褀ٙIEQlݺTUUݻٳgI$K,cՔfꚻuO"哓q|1J͍7گ_)*TWWb1oO4M;|Z8ii2 K]!"ԵJYhq$BUӵo}}}zHU_/5M\("!T.aeA9nD"7^MLLx<.޽+zzzp8%cyD^J4eK}0155}ڵtqf>7qckfiZymmme[Wo@0 g6miOR?BBo{\+mcIENDB`qmapshack-1.10.0/src/cursors/cursorPrint.png000644 001750 000144 00000002704 12647363442 022267 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME   q.QIDATXý]hUwfM棑ŪS[j(RD/C[P4/HD( " VCbZǝލFa`3ws.J)ϲ4 HX @teh@`/.\[GvDê%K @644\ \^,ĒDDrQfsNZcQKZK 9y466,zXcY8/I.Y²eˆN*JH88fN8nٲ7M:ZŹвAlfhh(wl`IG꿀Pr9|GDHd> 0==M. "B>7(~`J\V q8xk@ᔪ /7!ɰgϞMҰ4R9-7q ങu(sqc3OLm:ЁRϞ"~U0 +j+Ç8O>Gv]筷͘tUqL^k=u 8e{\Yėӿֲp 步L&Oڵkt =Ȥv (n/`6Öh .+Nnh l_Dl8tRyo-9l1<W)yժU9rnvv۶;wy{~Vlx]fK1wر󴵵aWBЦ;PJɖV@V礰&46y0s-̡Cرcק]=gNjOE3L'wz* x/eSCŊ9psilƥM\D6AlI*)~d/O.)9V|ffB@1Jʫ+)-m ?+˜I p^\(JH(JX A.QWL"e`*Dmغ6lh:p~b \#R |ٸ?lD\E\`' W7Y"URl&jU-,7WMLTR乿SIW,IENDB`qmapshack-1.10.0/src/cursors/cursorPointDel.png000644 001750 000144 00000002556 13107540216 022702 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME 5ٝIDATXýMh\eI&dRڄ "Xu!Z?](T"4MB( UFb[dQ0. fU6?s"L'͌ ay}E)U,F (8Db*:l:h@6>exZ V-l@D}9qDzځ$`oDDD8qpxHl D]8 }WZ#AEF8WJE)$SSS&yWT@drSjPYsj^ŀytttfD8610/’ DPɭt%r{JpϞ=VE_XAoیXd8}+Jm/TwBE_&/)]Zh_ZZZDQtvpp0t܀vލeY]w߹|Ra+Uג'M:pSD?sLd6bt:MiÔZ.(',0l.m24y`\nxwrtt4?33CKK LF[5_H,x Sz/HqKFӧ}3[3^@DYw*5?ԧNQ @VՊl[MOY2$עX f[#0Zdۦr]cxC2Fv xLFہ+aZ4Jf81`:ѰR ǔ"stG|(GEdk6F?f0nK~y X)W5Fo<˷6%y+%"޻snC I+_}{P=o/-nIIENDB`qmapshack-1.10.0/src/cursors/cursorMoveLine.png000644 001750 000144 00000002737 12647363442 022717 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzbKGD pHYs  ~tIME :4=lIDATXý[let@ʭ SK%ĈHD@4 !PAAn& ^)Q@/T7!i &HJc"@--efvoR$'9T0@ P'%@GΝ,((8 T@VqG֭[&ŀ Å5(J?1*u]qGɤ455IQQQ0M1\וx<.XLѨJKKL:5[Ln nfΑAJr H4%#"A0 O7666ʪUxe( $I`b(hmmeѢEN__A|!–@WWh􆤃ADD"AMMvq׀. )|u],ˢ6MaLӾ+ g ktbu<˲Xv?@J) ߾2HK-r{zvbMGG@ |:N*؛E[ہ6Ѥ~sn_9lх<_鲩>Y"{&aa `8X ,f  \+M@~ХNk!k`鋾@ߓңԓGW J1By-J5(|o`qNKSQߒizIkTj."hJ\^`қ .KX]Gp.~x  D2K3ArMg`1V y hxa`k{-`oo-9Ӂ 5%r%"[YC IENDB`qmapshack-1.10.0/src/resources.qrc000644 001750 000144 00000066160 13216234261 020243 0ustar00oeichlerxusers000000 000000 animation/loader.gif animation/loader2.gif cursors/cursorArrow.png cursors/cursorDelete.png cursors/cursorMove.png cursors/cursorMoveArea.png cursors/cursorMoveLine.png cursors/cursorMoveMap.png cursors/cursorMoveWpt.png cursors/cursorPointAdd.png cursors/cursorPointDel.png cursors/cursorPointMove.png cursors/cursorPrint.png cursors/cursorRadiusWpt.png cursors/cursorSave.png cursors/cursorSelectArea.png cursors/cursorSelectRange.png cursors/wptHighlightBlue.png cursors/wptHighlightRed.png icons/16x16/ActAero.png icons/16x16/ActBike.png icons/16x16/ActCable.png icons/16x16/ActCar.png icons/16x16/ActCycle.png icons/16x16/ActFoot.png icons/16x16/ActNone.png icons/16x16/ActShip.png icons/16x16/ActSki.png icons/16x16/ActSwim.png icons/16x16/ActTrain.png icons/16x16/EditDetails.png icons/32x32/2NavProject.png icons/32x32/A.png icons/32x32/ActAero.png icons/32x32/ActBike.png icons/32x32/ActCable.png icons/32x32/ActCar.png icons/32x32/ActCycle.png icons/32x32/ActFoot.png icons/32x32/ActNone.png icons/32x32/ActShip.png icons/32x32/ActSki.png icons/32x32/ActSwim.png icons/32x32/ActTrain.png icons/32x32/Activity.png icons/32x32/Add.png icons/32x32/AddArea.png icons/32x32/AddImage.png icons/32x32/AddMapWorkspace.png icons/32x32/AddProject.png icons/32x32/AddRte.png icons/32x32/AddTrk.png icons/32x32/AddWpt.png icons/32x32/Apply.png icons/32x32/Area.png icons/32x32/AreaMove.png icons/32x32/AreaOn.png icons/32x32/ArrowDef.png icons/32x32/ArrowUser.png icons/32x32/AutoSave.png icons/32x32/Bubble.png icons/32x32/CSrcATemp.png icons/32x32/CSrcAccel.png icons/32x32/CSrcCAD.png icons/32x32/CSrcCourse.png icons/32x32/CSrcDepth.png icons/32x32/CSrcDistance.png icons/32x32/CSrcElevation.png icons/32x32/CSrcEnergy.png icons/32x32/CSrcHR.png icons/32x32/CSrcSeaLevelPressure.png icons/32x32/CSrcSlope.png icons/32x32/CSrcSolid.png icons/32x32/CSrcSpeed.png icons/32x32/CSrcUnknown.png icons/32x32/CSrcVertSpeed.png icons/32x32/CSrcWTemp.png icons/32x32/Cancel.png icons/32x32/Check.png icons/32x32/CloneMapWorkspace.png icons/32x32/Close.png icons/32x32/Combine.png icons/32x32/Copy.png icons/32x32/CopyTrkWithWpt.png icons/32x32/Cut.png icons/32x32/CutHistoryAfter.png icons/32x32/CutHistoryBefore.png icons/32x32/CutMode1.png icons/32x32/CutMode2.png icons/32x32/DBProject.png icons/32x32/Database.png icons/32x32/DatabaseConvert.png icons/32x32/DatabaseSetup.png icons/32x32/DatabaseSync.png icons/32x32/DelImage.png icons/32x32/DeleteMultiple.png icons/32x32/DeleteOne.png icons/32x32/Device.png icons/32x32/Down.png icons/32x32/EditDetails.png icons/32x32/EditText.png icons/32x32/Empty.png icons/32x32/Error.png icons/32x32/Filter.png icons/32x32/FilterModifyExtension.png icons/32x32/FilterSubPt2Pt.png icons/32x32/FitProject.png icons/32x32/FolderDEM.png icons/32x32/FolderMap.png icons/32x32/Font.png icons/32x32/FromMap.png icons/32x32/FullScreen.png icons/32x32/GpxProject.png icons/32x32/Grid.png icons/32x32/GridSetup.png icons/32x32/GridWizzard.png icons/32x32/Help.png icons/32x32/Image.png icons/32x32/Info.png icons/32x32/Left.png icons/32x32/Limit.png icons/32x32/LimitSys.png icons/32x32/LimitUsr.png icons/32x32/LineMove.png icons/32x32/LineWidthDef.png icons/32x32/LineWidthUser.png icons/32x32/Link.png icons/32x32/LoadGIS.png icons/32x32/LoadView.png icons/32x32/Lock.png icons/32x32/LogProject.png icons/32x32/Map.png icons/32x32/MimeDemVRT.png icons/32x32/MimeGEMF.png icons/32x32/MimeIMG.png icons/32x32/MimeJNX.png icons/32x32/MimeMAP.png icons/32x32/MimeRMAP.png icons/32x32/MimeTMS.png icons/32x32/MimeVRT.png icons/32x32/MimeWMTS.png icons/32x32/MouseWheel.png icons/32x32/Move.png icons/32x32/MoveArrow.png icons/32x32/MySQL.png icons/32x32/MySQLNoConn.png icons/32x32/NightDay.png icons/32x32/NoGo.png icons/32x32/O.png icons/32x32/Off.png icons/32x32/Opacity.png icons/32x32/POIText.png icons/32x32/Paste.png icons/32x32/PasteNormal.png icons/32x32/PastePlain.png icons/32x32/PathBlue.png icons/32x32/PathGreen.png icons/32x32/PathOrange.png icons/32x32/Pattern.png icons/32x32/PointAdd.png icons/32x32/PointDel.png icons/32x32/PointHide.png icons/32x32/PointMove.png icons/32x32/PointShow.png icons/32x32/Print.png icons/32x32/PrintSave.png icons/32x32/ProfileToWindow.png icons/32x32/Progress.png icons/32x32/QMapShack.png icons/32x32/QlbProject.png icons/32x32/QmsProject.png icons/32x32/Redo.png icons/32x32/RegularScreen.png icons/32x32/ReloadImage.png icons/32x32/Reset.png icons/32x32/Reverse.png icons/32x32/Right.png icons/32x32/Route.png icons/32x32/RouteOn.png icons/32x32/RouteSetup.png icons/32x32/RteInstr.png icons/32x32/SQLite.png icons/32x32/SQLiteNoConn.png icons/32x32/Save.png icons/32x32/SaveAllGIS.png icons/32x32/SaveGIS.png icons/32x32/SaveGISAs.png icons/32x32/SaveGISAsGpx11.png icons/32x32/SaveView.png icons/32x32/Scale.png icons/32x32/SearchDatabase.png icons/32x32/SearchGoogle.png icons/32x32/SelectArea.png icons/32x32/SelectColor.png icons/32x32/SelectExactArea.png icons/32x32/SelectIntersectArea.png icons/32x32/SelectRange.png icons/32x32/SetEle.png icons/32x32/SetupCoordFormat.png icons/32x32/SetupMapWorkspace.png icons/32x32/SetupWptSym.png icons/32x32/ShowAll.png icons/32x32/ShowNone.png icons/32x32/SizeArrow.png icons/32x32/SlfProject.png icons/32x32/SmlProject.png icons/32x32/SortName.png icons/32x32/Start.png icons/32x32/Tainted.png icons/32x32/TcxProject.png icons/32x32/Template.png icons/32x32/TextBold.png icons/32x32/TextCenter.png icons/32x32/TextItalic.png icons/32x32/TextJustified.png icons/32x32/TextLeft.png icons/32x32/TextRight.png icons/32x32/TextUnderlined.png icons/32x32/Time.png icons/32x32/TimeZoneSetup.png icons/32x32/ToBottom.png icons/32x32/ToTop.png icons/32x32/ToggleDatabase.png icons/32x32/ToggleDem.png icons/32x32/ToggleDocks.png icons/32x32/ToggleGis.png icons/32x32/ToggleMaps.png icons/32x32/ToggleRouter.png icons/32x32/ToolBar.png icons/32x32/ToolBarSetup.png icons/32x32/ToolTip.png icons/32x32/Track.png icons/32x32/TrackMinMax.png icons/32x32/TrackOn.png icons/32x32/TrkCut.png icons/32x32/TrkProfile.png icons/32x32/UnLock.png icons/32x32/Undo.png icons/32x32/UnitSetup.png icons/32x32/Up.png icons/32x32/V.png icons/32x32/VrtBuilder.png icons/32x32/WaypointOn.png icons/32x32/WptAvoid.png icons/32x32/WptDelProx.png icons/32x32/WptEditProx.png icons/32x32/WptMove.png icons/32x32/WptProj.png icons/32x32/WptProx.png icons/32x32/Zoom.png icons/48x48/2NavProject.png icons/48x48/A.png icons/48x48/ActAero.png icons/48x48/ActBike.png icons/48x48/ActCable.png icons/48x48/ActCar.png icons/48x48/ActCycle.png icons/48x48/ActFoot.png icons/48x48/ActNone.png icons/48x48/ActShip.png icons/48x48/ActSki.png icons/48x48/ActSwim.png icons/48x48/ActTrain.png icons/48x48/Activity.png icons/48x48/Add.png icons/48x48/AddArea.png icons/48x48/AddImage.png icons/48x48/AddMapWorkspace.png icons/48x48/AddProject.png icons/48x48/AddRte.png icons/48x48/AddTrk.png icons/48x48/AddWpt.png icons/48x48/Apply.png icons/48x48/Area.png icons/48x48/AreaMove.png icons/48x48/AreaOn.png icons/48x48/ArrowDef.png icons/48x48/ArrowUser.png icons/48x48/AutoSave.png icons/48x48/Bubble.png icons/48x48/CSrcATemp.png icons/48x48/CSrcAccel.png icons/48x48/CSrcCAD.png icons/48x48/CSrcCourse.png icons/48x48/CSrcDepth.png icons/48x48/CSrcDistance.png icons/48x48/CSrcElevation.png icons/48x48/CSrcEnergy.png icons/48x48/CSrcHR.png icons/48x48/CSrcSeaLevelPressure.png icons/48x48/CSrcSlope.png icons/48x48/CSrcSolid.png icons/48x48/CSrcSpeed.png icons/48x48/CSrcUnknown.png icons/48x48/CSrcVertSpeed.png icons/48x48/CSrcWTemp.png icons/48x48/Cancel.png icons/48x48/Check.png icons/48x48/CloneMapWorkspace.png icons/48x48/Close.png icons/48x48/Combine.png icons/48x48/Copy.png icons/48x48/CopyTrkWithWpt.png icons/48x48/Cut.png icons/48x48/CutHistoryAfter.png icons/48x48/CutHistoryBefore.png icons/48x48/CutMode1.png icons/48x48/CutMode2.png icons/48x48/DBProject.png icons/48x48/Database.png icons/48x48/DatabaseConvert.png icons/48x48/DatabaseSetup.png icons/48x48/DatabaseSync.png icons/48x48/DelImage.png icons/48x48/DeleteMultiple.png icons/48x48/DeleteOne.png icons/48x48/Device.png icons/48x48/Down.png icons/48x48/EditDetails.png icons/48x48/EditText.png icons/48x48/Empty.png icons/48x48/Error.png icons/48x48/Filter.png icons/48x48/FilterModifyExtension.png icons/48x48/FilterSubPt2Pt.png icons/48x48/FitProject.png icons/48x48/FolderDEM.png icons/48x48/FolderMap.png icons/48x48/Font.png icons/48x48/FromMap.png icons/48x48/FullScreen.png icons/48x48/GpxProject.png icons/48x48/Grid.png icons/48x48/GridSetup.png icons/48x48/GridWizzard.png icons/48x48/Help.png icons/48x48/Image.png icons/48x48/Info.png icons/48x48/Left.png icons/48x48/Limit.png icons/48x48/LimitSys.png icons/48x48/LimitUsr.png icons/48x48/LineMove.png icons/48x48/LineWidthDef.png icons/48x48/LineWidthUser.png icons/48x48/Link.png icons/48x48/LoadGIS.png icons/48x48/LoadView.png icons/48x48/Lock.png icons/48x48/LogProject.png icons/48x48/Map.png icons/48x48/MimeDemVRT.png icons/48x48/MimeGEMF.png icons/48x48/MimeIMG.png icons/48x48/MimeJNX.png icons/48x48/MimeMAP.png icons/48x48/MimeRMAP.png icons/48x48/MimeTMS.png icons/48x48/MimeVRT.png icons/48x48/MimeWMTS.png icons/48x48/MouseWheel.png icons/48x48/Move.png icons/48x48/MoveArrow.png icons/48x48/MySQL.png icons/48x48/MySQLNoConn.png icons/48x48/NightDay.png icons/48x48/NoGo.png icons/48x48/O.png icons/48x48/Off.png icons/48x48/Opacity.png icons/48x48/POIText.png icons/48x48/Paste.png icons/48x48/PasteNormal.png icons/48x48/PastePlain.png icons/48x48/PathBlue.png icons/48x48/PathGreen.png icons/48x48/PathOrange.png icons/48x48/Pattern.png icons/48x48/PointAdd.png icons/48x48/PointDel.png icons/48x48/PointHide.png icons/48x48/PointMove.png icons/48x48/PointShow.png icons/48x48/Print.png icons/48x48/PrintSave.png icons/48x48/ProfileToWindow.png icons/48x48/Progress.png icons/48x48/QMapShack.png icons/48x48/QlbProject.png icons/48x48/QmsProject.png icons/48x48/Redo.png icons/48x48/RegularScreen.png icons/48x48/ReloadImage.png icons/48x48/Reset.png icons/48x48/Reverse.png icons/48x48/Right.png icons/48x48/Route.png icons/48x48/RouteOn.png icons/48x48/RouteSetup.png icons/48x48/RteInstr.png icons/48x48/SQLite.png icons/48x48/SQLiteNoConn.png icons/48x48/Save.png icons/48x48/SaveAllGIS.png icons/48x48/SaveGIS.png icons/48x48/SaveGISAs.png icons/48x48/SaveGISAsGpx11.png icons/48x48/SaveView.png icons/48x48/Scale.png icons/48x48/SearchDatabase.png icons/48x48/SearchGoogle.png icons/48x48/SelectArea.png icons/48x48/SelectColor.png icons/48x48/SelectExactArea.png icons/48x48/SelectIntersectArea.png icons/48x48/SelectRange.png icons/48x48/SetEle.png icons/48x48/SetupCoordFormat.png icons/48x48/SetupMapWorkspace.png icons/48x48/SetupWptSym.png icons/48x48/ShowAll.png icons/48x48/ShowNone.png icons/48x48/SizeArrow.png icons/48x48/SlfProject.png icons/48x48/SmlProject.png icons/48x48/SortName.png icons/48x48/Start.png icons/48x48/Tainted.png icons/48x48/TcxProject.png icons/48x48/Template.png icons/48x48/TextBold.png icons/48x48/TextCenter.png icons/48x48/TextItalic.png icons/48x48/TextJustified.png icons/48x48/TextLeft.png icons/48x48/TextRight.png icons/48x48/TextUnderlined.png icons/48x48/Time.png icons/48x48/TimeZoneSetup.png icons/48x48/ToBottom.png icons/48x48/ToTop.png icons/48x48/ToggleDatabase.png icons/48x48/ToggleDem.png icons/48x48/ToggleDocks.png icons/48x48/ToggleGis.png icons/48x48/ToggleMaps.png icons/48x48/ToggleRouter.png icons/48x48/ToolBar.png icons/48x48/ToolBarSetup.png icons/48x48/ToolTip.png icons/48x48/Track.png icons/48x48/TrackMinMax.png icons/48x48/TrackOn.png icons/48x48/TrkCut.png icons/48x48/TrkProfile.png icons/48x48/UnLock.png icons/48x48/Undo.png icons/48x48/UnitSetup.png icons/48x48/Up.png icons/48x48/V.png icons/48x48/VrtBuilder.png icons/48x48/WaypointOn.png icons/48x48/WptAvoid.png icons/48x48/WptEditProx.png icons/48x48/WptMove.png icons/48x48/WptProj.png icons/48x48/WptProx.png icons/48x48/WptDelProx.png icons/48x48/Zoom.png icons/8x8/bullet_black.png icons/8x8/bullet_blue.png icons/8x8/bullet_brown.png icons/8x8/bullet_cyan.png icons/8x8/bullet_dark_blue.png icons/8x8/bullet_dark_cyan.png icons/8x8/bullet_dark_gray.png icons/8x8/bullet_dark_green.png icons/8x8/bullet_dark_magenta.png icons/8x8/bullet_dark_red.png icons/8x8/bullet_dark_yellow.png icons/8x8/bullet_gray.png icons/8x8/bullet_green.png icons/8x8/bullet_magenta.png icons/8x8/bullet_orange.png icons/8x8/bullet_red.png icons/8x8/bullet_white.png icons/8x8/bullet_yellow.png icons/cache/32x32/DistIcon.png icons/cache/32x32/OCMLogo.png icons/cache/32x32/OCMLogoSmall.png icons/cache/32x32/SearchIcon.png icons/cache/32x32/bluepin.png icons/cache/32x32/cito.png icons/cache/32x32/corrected.png icons/cache/32x32/dnf.png icons/cache/32x32/down_icon.png icons/cache/32x32/earth.png icons/cache/32x32/event.png icons/cache/32x32/found.png icons/cache/32x32/ftf.png icons/cache/32x32/greenpin.png icons/cache/32x32/halfstar.png icons/cache/32x32/letterbox.png icons/cache/32x32/log.png icons/cache/32x32/maxicon.png icons/cache/32x32/mega.png icons/cache/32x32/minicon.png icons/cache/32x32/multi.png icons/cache/32x32/needs_maintenance.png icons/cache/32x32/other.png icons/cache/32x32/parking.png icons/cache/32x32/pushpin.png icons/cache/32x32/restore.png icons/cache/32x32/star.png icons/cache/32x32/star_empty.png icons/cache/32x32/traditional.png icons/cache/32x32/trailhead.png icons/cache/32x32/treasure.png icons/cache/32x32/unknown.png icons/cache/32x32/up_icon.png icons/cache/32x32/virtual.png icons/cache/32x32/waypoint-flag-red.png icons/cache/32x32/webcam.png icons/cache/32x32/wherigo.png icons/cache/32x32/write_note.png icons/waypoints/32x32/1stCategory.png icons/waypoints/32x32/2ndCategory.png icons/waypoints/32x32/3rdCategory.png icons/waypoints/32x32/4thCategory.png icons/waypoints/32x32/BoxBlue.png icons/waypoints/32x32/BoxGreen.png icons/waypoints/32x32/BoxRed.png icons/waypoints/32x32/CityCapitol.png icons/waypoints/32x32/CityLarge.png icons/waypoints/32x32/CityMedium.png icons/waypoints/32x32/CitySmall.png icons/waypoints/32x32/Danger.png icons/waypoints/32x32/Default.png icons/waypoints/32x32/DiamondBlue.png icons/waypoints/32x32/DiamondGreen.png icons/waypoints/32x32/DiamondRed.png icons/waypoints/32x32/End.png icons/waypoints/32x32/FirstAid.png icons/waypoints/32x32/FlagBlue.png icons/waypoints/32x32/FlagGreen.png icons/waypoints/32x32/FlagRed.png icons/waypoints/32x32/Food.png icons/waypoints/32x32/Generic.png icons/waypoints/32x32/HorsCategory.png icons/waypoints/32x32/Left.png icons/waypoints/32x32/LeftFork.png icons/waypoints/32x32/MiddleFork.png icons/waypoints/32x32/PinBlue.png icons/waypoints/32x32/PinGreen.png icons/waypoints/32x32/PinRed.png icons/waypoints/32x32/Residence.png icons/waypoints/32x32/Right.png icons/waypoints/32x32/RightFork.png icons/waypoints/32x32/SharpLeft.png icons/waypoints/32x32/SharpRight.png icons/waypoints/32x32/SlightLeft.png icons/waypoints/32x32/SlightRight.png icons/waypoints/32x32/Sprint.png icons/waypoints/32x32/Start.png icons/waypoints/32x32/Straight.png icons/waypoints/32x32/Summit.png icons/waypoints/32x32/UTurn.png icons/waypoints/32x32/Valley.png icons/waypoints/32x32/Water.png icons/waypoints/32x32/Waypoint.png map/OSM_Topo.tms map/OpenCycleMap.tms map/OpenStreetMap.tms map/WorldSat.wmts map/WorldTopo.wmts pics/about.png pics/compass.png pics/noMap256x256.png pics/splash.png pics/timezones.png templates/Hiking_Tour_Summary.ui qmapshack-1.10.0/src/IMainWindow.ui000644 001750 000144 00000063174 13216234261 020250 0ustar00oeichlerxusers000000 000000 IMainWindow 0 0 800 600 true QMapShack :/icons/48x48/QMapShack.png:/icons/48x48/QMapShack.png 0 0 0 0 0 -1 true 0 0 800 23 File View Window ? Workspace Tool QDockWidget::DockWidgetFeatureMask Maps 1 0 0 0 0 0 -1 QDockWidget::DockWidgetFeatureMask Dig. Elev. Model (DEM) 1 0 0 0 0 0 QDockWidget::DockWidgetFeatureMask Workspace 2 Toolbar TopToolBarArea false QDockWidget::DockWidgetFeatureMask Database 2 QDockWidget::DockWidgetFeatureMask Routing 2 :/icons/32x32/AddMapWorkspace.png:/icons/32x32/AddMapWorkspace.png Add Map View Add Map View Ctrl+T QAction::NoRole true :/icons/32x32/Scale.png:/icons/32x32/Scale.png Show Scale QAction::NoRole :/icons/32x32/Font.png:/icons/32x32/Font.png Setup Map Font QAction::NoRole true :/icons/32x32/Grid.png:/icons/32x32/Grid.png Show Grid Ctrl+G QAction::NoRole :/icons/32x32/GridSetup.png:/icons/32x32/GridSetup.png Setup Grid Ctrl+Alt+G QAction::NoRole true :/icons/32x32/MouseWheel.png:/icons/32x32/MouseWheel.png Flip Mouse Wheel QAction::NoRole :/icons/32x32/FolderMap.png:/icons/32x32/FolderMap.png Setup Map Paths Setup Map Paths QAction::NoRole true :/icons/32x32/POIText.png:/icons/32x32/POIText.png POI Text QAction::NoRole true :/icons/32x32/NightDay.png:/icons/32x32/NightDay.png Night / Day QAction::NoRole true :/icons/32x32/ToolTip.png:/icons/32x32/ToolTip.png Map Tool Tip Ctrl+I QAction::NoRole :/icons/32x32/FolderDEM.png:/icons/32x32/FolderDEM.png Setup DEM Paths QAction::NoRole :/icons/32x32/Info.png:/icons/32x32/Info.png About QAction::AboutRole :/icons/32x32/Help.png:/icons/32x32/Help.png Help F1 QAction::NoRole :/icons/32x32/SetupMapWorkspace.png:/icons/32x32/SetupMapWorkspace.png Setup Map View Setup Map View QAction::NoRole :/icons/32x32/LoadGIS.png:/icons/32x32/LoadGIS.png Load GIS Data Load projects from file Ctrl+L QAction::NoRole :/icons/32x32/SaveAllGIS.png:/icons/32x32/SaveAllGIS.png Save All GIS Data Save all projects in the workspace Ctrl+S QAction::NoRole :/icons/32x32/TimeZoneSetup.png:/icons/32x32/TimeZoneSetup.png Setup Time Zone QAction::NoRole :/icons/32x32/AddProject.png:/icons/32x32/AddProject.png Add empty project QAction::NoRole true :/icons/32x32/SearchGoogle.png:/icons/32x32/SearchGoogle.png Search Google QAction::NoRole :/icons/32x32/Close.png:/icons/32x32/Close.png Close all projects F8 QAction::NoRole :/icons/32x32/UnitSetup.png:/icons/32x32/UnitSetup.png Setup Units QAction::NoRole :/icons/32x32/DatabaseSetup.png:/icons/32x32/DatabaseSetup.png Setup Workspace Setup save on exit. QAction::NoRole :/icons/32x32/DatabaseConvert.png:/icons/32x32/DatabaseConvert.png Import Database from QLandkarte Import QLandkarte GT database QAction::NoRole :/icons/32x32/VrtBuilder.png:/icons/32x32/VrtBuilder.png VRT Builder GUI front end to gdalbuildvrt QAction::NoRole :/icons/32x32/SaveView.png:/icons/32x32/SaveView.png Store Map View Write current active map and DEM list including the properties to a file QAction::NoRole :/icons/32x32/LoadView.png:/icons/32x32/LoadView.png Load Map View Restore view with active map and DEM list including the properties from a file QAction::NoRole true :/icons/32x32/ProfileToWindow.png:/icons/32x32/ProfileToWindow.png Ext. Profile Ctrl+E QAction::NoRole :/icons/32x32/Off.png:/icons/32x32/Off.png Close Ctrl+Q QAction::QuitRole :/icons/32x32/CloneMapWorkspace.png:/icons/32x32/CloneMapWorkspace.png Clone Map View Ctrl+Shift+T QAction::NoRole :/icons/32x32/RouteSetup.png:/icons/32x32/RouteSetup.png Create Routino Database QAction::NoRole :/icons/32x32/PrintSave.png:/icons/32x32/PrintSave.png Save(Print) Map Screenshot Print a selected area of the map Ctrl+P QAction::NoRole :/icons/32x32/SetupCoordFormat.png:/icons/32x32/SetupCoordFormat.png Setup Coord. Format Change the format coordinates are displayed QAction::NoRole :/icons/32x32/SelectColor.png:/icons/32x32/SelectColor.png Setup Map Background QAction::NoRole :/icons/32x32/SetupWptSym.png:/icons/32x32/SetupWptSym.png Setup Waypoint Icons Setup path to custom icons :/icons/32x32/Close.png:/icons/32x32/Close.png Close Tab Ctrl+W :/icons/32x32/Help.png:/icons/32x32/Help.png Quickstart Help :/icons/32x32/ToolBarSetup.png:/icons/32x32/ToolBarSetup.png Setup Toolbar true :/icons/32x32/ToggleDocks.png:/icons/32x32/ToggleDocks.png Toggle Docks Toggle visibility of dockable windows Ctrl+D :/icons/32x32/FullScreen.png:/icons/32x32/FullScreen.png Full Screen F11 true :/icons/32x32/TrackMinMax.png:/icons/32x32/TrackMinMax.png Min./Max. Track Values Show the minimum and maximum values of the track properties along the track in the map view. Ctrl+N CRouterSetup QWidget
gis/rte/router/CRouterSetup.h
1
qmapshack-1.10.0/src/qlgt/000755 001750 000144 00000000000 13216664443 016471 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/qlgt/CQmsDb.h000644 001750 000144 00000003641 13216234142 017744 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQMSDB_H #define CQMSDB_H #include "gis/db/IDBSqlite.h" #include #include class CImportDatabase; class IGisItem; class CQlgtFolder; class CQlgtWpt; class CQlgtTrack; class CQlgtRoute; class IQlgtOverlay; class CQmsDb : public QObject, private IDBSqlite { Q_DECLARE_TR_FUNCTIONS(CQmsDb) public: CQmsDb(const QString& filename, CImportDatabase * parent); virtual ~CQmsDb(); void addFolder2FolderRelation(quint64 parent, quint64 child); void addFolder2ItemRelation(quint64 parent, quint64 child); void addFolder(CQlgtFolder &folder); void addWpt(CQlgtWpt &wpt1); void addTrk(CQlgtTrack &trk1); void addTrk(IQlgtOverlay &trk1); void addRte(CQlgtRoute& rte1); void addArea(IQlgtOverlay& ovl1); bool isValid() { return valid; } private: bool valid; quint64 store(IGisItem &item); CImportDatabase * gui; QMap mapFolderTypes; QMap mapFolderIDs; QMap mapItemIDs; }; #endif //CQMSDB_H qmapshack-1.10.0/src/qlgt/CQlgtDiary.h000644 001750 000144 00000002516 13216234142 020636 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTDIARY_H #define CQLGTDIARY_H #include "qlgt/IItem.h" #include class CQlgtDiary : public QObject, public IItem { public: CQlgtDiary(quint64 id, QObject * parent); virtual ~CQlgtDiary(); enum type_e {eEnd,eBase, eWpt, eTrk, eRte}; quint64 keyProjectGeoDB = 0; }; QDataStream& operator >>(QDataStream& s, CQlgtDiary& diary); QDataStream& operator <<(QDataStream& s, CQlgtDiary& diary); #endif //CQLGTDIARY_H qmapshack-1.10.0/src/qlgt/CQlb.h000644 001750 000144 00000006160 13216234142 017453 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2007 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLB_H #define CQLB_H #include #include #include class CQlgtWpt; class CQlgtTrack; class CQlgtRoute; class CQlgtDiary; class IQlgtOverlay; /// qlandkarte binary to store private geo data /** The file will store data like waypoints, tracks, map selections. These elements will be collected in a dedicated byte array, e.g. all waypoints are serialized in wpts and so on. These byte arrays a stored like: qint32 eWpt, QByteArray wpts ... qint32 eEnd */ class CQlb : public QObject { Q_OBJECT public: CQlb(QObject * parent); virtual ~CQlb(); enum type_e {eEnd, eWpt, eTrack, eDiary, eOverlay, eRoute, eMapSel}; /// collect waypoint data /** This will serialize the waypoint object to wpts */ CQlb& operator <<(CQlgtWpt &wpt); CQlb& operator <<(CQlgtTrack &trk); CQlb& operator <<(CQlgtDiary &dry); CQlb& operator <<(IQlgtOverlay &ovl); CQlb& operator <<(CQlgtRoute &rte); /// get access to stored waypoint data QByteArray& waypoints() { return wpts; } /// get access to stored track data QByteArray& tracks() { return trks; } /// get access to stored diary data QByteArray& diary() { return drys; } /// get access to stored overlay data QByteArray& overlays() { return ovls; } /// get access to stored route data QByteArray& routes() { return rtes; } /// get access to stored map selection data QByteArray& mapsels() { return sels; } /// write collected data to file void save(const QString& filename); void save(QIODevice *ioDevice); /// read file and store elements in their designated byte arrays void load(const QString& filename); void load(QIODevice *ioDevice); private: /// byte array to hold all waypoints QByteArray wpts; /// byte array to hold all tracks QByteArray trks; /// byte array to hold all routes QByteArray rtes; /// byte array to hold diary QByteArray drys; /// byte array to hold overlays QByteArray ovls; /// byte array to hold map selections QByteArray sels; }; #endif //CQLB_H qmapshack-1.10.0/src/qlgt/CQlgtRoute.cpp000644 001750 000144 00000016026 13216234137 021224 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CQlgtRoute.h" struct rte_head_entry_t { rte_head_entry_t() : type(CQlgtRoute::eEnd), offset(0) { } qint32 type; quint32 offset; QByteArray data; }; QDataStream& operator >>(QDataStream& s, CQlgtRoute& route) { quint32 nRtePts = 0; QIODevice * dev = s.device(); qint64 pos = dev->pos(); char magic[9]; s.readRawData(magic,9); if(strncmp(magic,"QLRte ",9)) { dev->seek(pos); return s; } QList entries; while(1) { rte_head_entry_t entry; s >> entry.type >> entry.offset; entries << entry; if(entry.type == CQlgtRoute::eEnd) { break; } } QList::iterator entry = entries.begin(); while(entry != entries.end()) { qint64 o = pos + entry->offset; dev->seek(o); s >> entry->data; switch(entry->type) { case CQlgtRoute::eBase: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); s1 >> route.key; s1 >> route.timestamp; s1 >> route.name; s1 >> route.iconString; s1 >> route.ttime; s1 >> route.parentWpt; break; } case CQlgtRoute::eRtePts: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 n; route.priRoute.clear(); s1 >> nRtePts; for(n = 0; n < nRtePts; ++n) { CQlgtRoute::pt_t rtept; float u, v; QString action; s1 >> u; s1 >> v; s1 >> action; rtept.lon = u; rtept.lat = v; rtept.action = action; route.priRoute << rtept; } break; } // case CQlgtRoute::eRteSec: // { // QDataStream s1(&entry->data, QIODevice::ReadOnly); // s1.setVersion(QDataStream::Qt_4_5); // quint32 n; // route.secRoute.clear(); // s1 >> nRtePts; // for(n = 0; n < nRtePts; ++n) // { // CQlgtRoute::pt_t rtept; // float u, v; // QString action; // s1 >> u; // s1 >> v; // s1 >> action; // rtept.lon = u; // rtept.lat = v; // rtept.action = action; // route.secRoute << rtept; // } // break; // } default: ; } ++entry; } return s; } QDataStream& operator <<(QDataStream& s, CQlgtRoute& route) { QList entries; //--------------------------------------- // prepare base data //--------------------------------------- rte_head_entry_t entryBase; entryBase.type = CQlgtRoute::eBase; QDataStream s1(&entryBase.data, QIODevice::WriteOnly); s1.setVersion(QDataStream::Qt_4_5); s1 << route.key; s1 << route.timestamp; s1 << route.name; s1 << route.iconString; s1 << route.ttime; s1 << route.parentWpt; entries << entryBase; //--------------------------------------- // prepare primary routepoint data //--------------------------------------- rte_head_entry_t entryPriRtePts; entryPriRtePts.type = CQlgtRoute::eRtePts; QDataStream s2(&entryPriRtePts.data, QIODevice::WriteOnly); s2.setVersion(QDataStream::Qt_4_5); { QVector& rtepts = route.priRoute; QVector::iterator rtept = rtepts.begin(); s2 << (quint32)rtepts.size(); while(rtept != rtepts.end()) { s2 << (float)rtept->lon; s2 << (float)rtept->lat; s2 << rtept->action; ++rtept; } } entries << entryPriRtePts; // //--------------------------------------- // // prepare secondary routepoint data // //--------------------------------------- // rte_head_entry_t entrySecRtePts; // entrySecRtePts.type = CQlgtRoute::eRteSec; // QDataStream s3(&entrySecRtePts.data, QIODevice::WriteOnly); // s3.setVersion(QDataStream::Qt_4_5); // { // QVector& rtepts = route.getSecRtePoints(); // QVector::iterator rtept = rtepts.begin(); // if(!rtepts.isEmpty()) // { // s3 << (quint32)rtepts.size(); // while(rtept != rtepts.end()) // { // s3 << (float)rtept->lon; // s3 << (float)rtept->lat; // s3 << rtept->action; // ++rtept; // } // entries << entrySecRtePts; // } // } //--------------------------------------- // prepare terminator //--------------------------------------- rte_head_entry_t entryEnd; entryEnd.type = CQlgtRoute::eEnd; entries << entryEnd; //--------------------------------------- //--------------------------------------- // now start to actually write data; //--------------------------------------- //--------------------------------------- // write magic key s.writeRawData("QLRte ",9); // calculate offset table quint32 offset = entries.count() * 8 + 9; QList::iterator entry = entries.begin(); while(entry != entries.end()) { entry->offset = offset; offset += entry->data.size() + sizeof(quint32); ++entry; } // write offset table entry = entries.begin(); while(entry != entries.end()) { s << entry->type << entry->offset; ++entry; } // write entry data entry = entries.begin(); while(entry != entries.end()) { s << entry->data; ++entry; } return s; } CQlgtRoute::CQlgtRoute(quint64 id, QObject *parent) : QObject(parent) , IItem(id) { } CQlgtRoute::~CQlgtRoute() { } qmapshack-1.10.0/src/qlgt/CQlgtDb.h000644 001750 000144 00000004524 13216234142 020114 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTDB_H #define CQLGTDB_H #include #include #include #include #include #include class CImportDatabase; class CQmsDb; class CQlgtDb : public QObject { Q_DECLARE_TR_FUNCTIONS(CQlgtDb) public: enum EntryType_e { eWpt = QTreeWidgetItem::UserType + 3, eTrk = QTreeWidgetItem::UserType + 4, eRte = QTreeWidgetItem::UserType + 5, eOvl = QTreeWidgetItem::UserType + 6, eMap = QTreeWidgetItem::UserType + 7, eDry = QTreeWidgetItem::UserType + 8, eFolder0 = QTreeWidgetItem::UserType + 100, eFolderT = QTreeWidgetItem::UserType + 101, eFolder1 = QTreeWidgetItem::UserType + 102, eFolder2 = QTreeWidgetItem::UserType + 103, eFolderN = QTreeWidgetItem::UserType + 104 }; CQlgtDb(const QString& filename, CImportDatabase * parent); virtual ~CQlgtDb(); void start(const QString& filename); private: void initDB(); void migrateDB(int version); void printStatistic(); void xferFolders(); void xferItems(); void xferItem(quint64 id); QSqlDatabase db; QDir path; QString name; CImportDatabase * gui; QPointer dbQms; quint32 nItems; quint32 nFolders; quint32 nWpt; quint32 nTrk; quint32 nRte; quint32 nOvl; quint32 nDiary; }; #endif //CQLGTDB_H qmapshack-1.10.0/src/qlgt/CQlgtFolder.h000644 001750 000144 00000002444 13216234142 021001 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTFOLDER_H #define CQLGTFOLDER_H #include #include class QSqlDatabase; class CQlgtDiary; class CQlgtFolder : public QObject { public: CQlgtFolder(quint64 id, QSqlDatabase& db); virtual ~CQlgtFolder(); qint32 type; QString name; QString comment; bool locked; CQlgtDiary * diary; quint64 id; QSet items; }; #endif //CQLGTFOLDER_H qmapshack-1.10.0/src/qlgt/CQmsDb.cpp000644 001750 000144 00000017731 13216234137 020310 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/db/CDBProject.h" #include "gis/db/IDBFolder.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "qlgt/CQlgtDb.h" #include "qlgt/CQlgtFolder.h" #include "qlgt/CQlgtRoute.h" #include "qlgt/CQlgtTrack.h" #include "qlgt/CQlgtWpt.h" #include "qlgt/CQmsDb.h" #include "qlgt/IQlgtOverlay.h" #include "tool/CImportDatabase.h" #include #include CQmsDb::CQmsDb(const QString &filename, CImportDatabase *parent) : QObject(parent) , valid(false) , gui(parent) { if(QFile::exists(filename)) { int res = QMessageBox::question(CMainWindow::getBestWidgetForParent(), tr("Existing file..."), tr("Remove existing %1?").arg(filename), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok); if(res != QMessageBox::Ok) { return; } gui->stdErr(tr("Remove existing file %1").arg(filename)); QFile::remove(filename); } QString error; valid = setupDB(filename, "qlgt2qms", error); if(!valid) { return; } mapFolderTypes[CQlgtDb::eFolder1] = IDBFolder::eTypeGroup; mapFolderTypes[CQlgtDb::eFolder2] = IDBFolder::eTypeProject; mapFolderTypes[CQlgtDb::eFolderN] = IDBFolder::eTypeOther; mapFolderIDs[1] = 1; mapFolderIDs[0] = 1; } CQmsDb::~CQmsDb() { db.close(); } void CQmsDb::addFolder2FolderRelation(quint64 parent, quint64 child) { QSqlQuery query(db); query.prepare("INSERT INTO folder2folder (parent, child) VALUES (:parent, :child)"); query.bindValue(":parent", mapFolderIDs[parent]); query.bindValue(":child", mapFolderIDs[child]); QUERY_EXEC(return ); } void CQmsDb::addFolder2ItemRelation(quint64 parent, quint64 child) { QSqlQuery query(db); query.prepare("INSERT INTO folder2item (parent, child) VALUES (:parent, :child)"); query.bindValue(":parent", mapFolderIDs[parent]); query.bindValue(":child", mapItemIDs[child]); QUERY_EXEC(return ); } void CQmsDb::addFolder(CQlgtFolder& folder) { if(folder.id < 2) { return; } QSqlQuery query(db); // folders without child items if(folder.items.isEmpty()) { query.prepare("INSERT INTO folders (type, name, locked) VALUES (:type, :name, :locked)"); query.bindValue(":type", mapFolderTypes[folder.type]); query.bindValue(":name", folder.name); query.bindValue(":locked", folder.locked); QUERY_EXEC(return ); query.prepare("SELECT last_insert_rowid() from folders"); QUERY_EXEC(return ); query.next(); quint64 id = query.value(0).toULongLong(); if(id == 0) { qDebug() << "CGisListDB::slotAddFolder(): childId equals 0. bad."; return; } mapFolderIDs[folder.id] = id; return; } /* Folders with child items will be loaded as complete CDBProject first, to generate key and info text properly */ CDBProject project(folder); for(quint64 id : folder.items) { quint64 idChild = mapItemIDs[id]; query.prepare("SELECT type FROM items WHERE id=:id"); query.bindValue(":id", idChild); QUERY_EXEC(continue); if(query.next()) { int type = query.value(0).toInt(); switch(type) { case IGisItem::eTypeWpt: new CGisItemWpt(idChild, db, &project); break; case IGisItem::eTypeTrk: new CGisItemTrk(idChild, db, &project); break; case IGisItem::eTypeRte: new CGisItemRte(idChild, db, &project); break; case IGisItem::eTypeOvl: new CGisItemOvlArea(idChild, db, &project); break; default: ; } } else { gui->stdErr(tr("%1: drop item with QLGT DB ID %2").arg(folder.name).arg(id)); } } // serialize metadata of project QByteArray data; QDataStream in(&data, QIODevice::WriteOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); project >> in; query.prepare("INSERT INTO folders (type, keyqms, name, comment, locked, data) VALUES (:type, :keyqms, :name, :comment, :locked, :data)"); query.bindValue(":type", mapFolderTypes[folder.type]); query.bindValue(":keyqms", project.getKey()); query.bindValue(":name", project.getName()); query.bindValue(":comment", project.getInfo()); query.bindValue(":locked", folder.locked); query.bindValue(":data", data); QUERY_EXEC(return ); query.prepare("SELECT last_insert_rowid() from folders"); QUERY_EXEC(return ); query.next(); quint64 id = query.value(0).toULongLong(); if(id == 0) { qDebug() << "CGisListDB::slotAddFolder(): childId equals 0. bad."; return; } mapFolderIDs[folder.id] = id; } void CQmsDb::addWpt(CQlgtWpt& wpt1) { CGisItemWpt wpt(wpt1); quint64 id = store(wpt); if(id != 0) { mapItemIDs[wpt1.id] = id; } } void CQmsDb::addTrk(CQlgtTrack &trk1) { CGisItemTrk trk(trk1); quint64 id = store(trk); if(id != 0) { mapItemIDs[trk1.id] = id; } } void CQmsDb::addTrk(IQlgtOverlay &trk1) { CGisItemTrk trk(trk1); quint64 id = store(trk); if(id != 0) { mapItemIDs[trk1.id] = id; } } void CQmsDb::addRte(CQlgtRoute& rte1) { CGisItemRte rte(rte1); quint64 id = store(rte); if(id != 0) { mapItemIDs[rte1.id] = id; } } void CQmsDb::addArea(IQlgtOverlay& ovl1) { CGisItemOvlArea ovl(ovl1); quint64 id = store(ovl); if(id != 0) { mapItemIDs[ovl1.id] = id; } } quint64 CQmsDb::store(IGisItem& item) { // serialize complete history of item QByteArray data; QDataStream in(&data, QIODevice::WriteOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in << item.getHistory(); QBuffer buffer; buffer.open(QIODevice::ReadWrite); QPixmap pixmap = item.getIcon(); pixmap.save(&buffer, "PNG"); buffer.seek(0); QSqlQuery query(db); // item is unknown to database -> create item in database query.prepare("INSERT INTO items (type, keyqms, icon, name, date, comment, data, hash) VALUES (:type, :keyqms, :icon, :name, :date, :comment, :data, :hash)"); query.bindValue(":type", item.type()); query.bindValue(":keyqms", item.getKey().item); query.bindValue(":icon", buffer.data()); query.bindValue(":name", item.getName()); query.bindValue(":date", item.getTimestamp()); query.bindValue(":comment", item.getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText)); query.bindValue(":data", data); query.bindValue(":hash", item.getHash()); QUERY_EXEC(return 0); query.prepare("SELECT last_insert_rowid() from items"); QUERY_EXEC(return 0); query.next(); quint64 idItem = query.value(0).toULongLong(); return idItem; } qmapshack-1.10.0/src/qlgt/IQlgtOverlay.h000644 001750 000144 00000003024 13216234142 021210 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IQLGTOVERLAY_H #define IQLGTOVERLAY_H #include "qlgt/IItem.h" #include #include class IQlgtOverlay : public QObject, public IItem { public: IQlgtOverlay(quint64 id, QObject * parent); virtual ~IQlgtOverlay(); enum type_e {eEnd,eBase}; struct pt_t : public projXY { int idx; }; QString type; QColor color; QList points; qint32 style = 0; quint32 width = 0; quint8 opacity = 0; float speed = 0; }; QDataStream& operator >>(QDataStream& s, IQlgtOverlay& ovl); QDataStream& operator <<(QDataStream& s, IQlgtOverlay& ovl); #endif //IQLGTOVERLAY_H qmapshack-1.10.0/src/qlgt/CQlb.cpp000644 001750 000144 00000006652 13216234137 020020 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2007 Oliver Eichler oliver.eichler@gmx.de 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 "CQlb.h" #include "qlgt/CQlgtDiary.h" #include "qlgt/CQlgtRoute.h" #include "qlgt/CQlgtTrack.h" #include "qlgt/CQlgtWpt.h" #include "qlgt/IQlgtOverlay.h" #include CQlb::CQlb(QObject * parent) : QObject(parent) { } CQlb::~CQlb() { } CQlb& CQlb::operator <<(CQlgtWpt& wpt) { QDataStream stream(&wpts, QIODevice::Append); stream.setVersion(QDataStream::Qt_4_5); stream << wpt; return *this; } CQlb& CQlb::operator <<(CQlgtTrack& trk) { QDataStream stream(&trks, QIODevice::Append); stream.setVersion(QDataStream::Qt_4_5); stream << trk; return *this; } CQlb& CQlb::operator <<(CQlgtRoute& rte) { QDataStream stream(&rtes, QIODevice::Append); stream.setVersion(QDataStream::Qt_4_5); stream << rte; return *this; } CQlb& CQlb::operator <<(CQlgtDiary& dry) { QDataStream stream(&drys, QIODevice::Append); stream.setVersion(QDataStream::Qt_4_5); stream << dry; return *this; } CQlb& CQlb::operator <<(IQlgtOverlay& ovl) { QDataStream stream(&ovls, QIODevice::Append); stream.setVersion(QDataStream::Qt_4_5); stream << ovl; return *this; } void CQlb::load(const QString& filename) { QFile file(filename); load(&file); } void CQlb::load(QIODevice* ioDevice) { qint32 type; ioDevice->open(QIODevice::ReadOnly); QDataStream stream(ioDevice); stream.setVersion(QDataStream::Qt_4_5); stream >> type; while(type != eEnd) { switch(type) { case eWpt: stream >> wpts; break; case eTrack: stream >> trks; break; case eDiary: stream >> drys; break; case eOverlay: stream >> ovls; break; case eRoute: stream >> rtes; break; case eMapSel: stream >> sels; break; default: ioDevice->close(); return; } stream >> type; } ioDevice->close(); } void CQlb::save(const QString& filename) { QFile file(filename); save(&file); } void CQlb::save(QIODevice* ioDevice) { ioDevice->open(QIODevice::WriteOnly); QDataStream stream(ioDevice); stream.setVersion(QDataStream::Qt_4_5); stream << (qint32)eWpt << wpts; stream << (qint32)eTrack << trks; stream << (qint32)eRoute << rtes; stream << (qint32)eDiary << drys; stream << (qint32)eOverlay << ovls; stream << (qint32)eMapSel << sels; stream << (qint32)eEnd; ioDevice->close(); } qmapshack-1.10.0/src/qlgt/CQlgtTrack.cpp000644 001750 000144 00000023266 13216234137 021176 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "CQlgtTrack.h" #include QDataStream& operator >>(QDataStream& s, CFlags& flag) { quint32 f; s >> f; flag.setFlags(f); flag.setChanged(true); return s; } QDataStream& operator <<(QDataStream& s, CFlags& flag) { s << flag.flag(); return s; } struct trk_head_entry_t { trk_head_entry_t() : type(CQlgtTrack::eEnd), offset(0) { } qint32 type; quint32 offset; QByteArray data; }; QDataStream& operator >>(QDataStream& s, CQlgtTrack& track) { quint32 nTrkPts = 0; QIODevice * dev = s.device(); qint64 pos = dev->pos(); char magic[9]; s.readRawData(magic,9); if(strncmp(magic,"QLTrk ",9)) { dev->seek(pos); return s; } QList entries; while(1) { trk_head_entry_t entry; s >> entry.type >> entry.offset; entries << entry; if(entry.type == CQlgtTrack::eEnd) { break; } } QList::iterator entry = entries.begin(); while(entry != entries.end()) { qint64 o = pos + entry->offset; dev->seek(o); s >> entry->data; switch(entry->type) { case CQlgtTrack::eBase: { QString key; QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); s1 >> track.key; s1 >> track.timestamp; s1 >> track.name; s1 >> track.comment; s1 >> track.colorIdx; s1 >> track.parentWpt; if(!s1.atEnd()) { s1 >> track.doScaleWpt2Track; } if(!s1.atEnd()) { s1 >> track.cntMedianFilterApplied; } if(!s1.atEnd()) { s1 >> track.useMultiColor; } if(!s1.atEnd()) { s1 >> track.idMultiColor; } //track.setColor(track.colorIdx); break; } case CQlgtTrack::eTrkPts: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 n; track.track.clear(); s1 >> nTrkPts; for(n = 0; n < nTrkPts; ++n) { CQlgtTrack::pt_t trkpt; s1 >> trkpt.lon; s1 >> trkpt.lat; s1 >> trkpt.ele; s1 >> trkpt.timestamp; s1 >> trkpt.flags; trkpt._lon = trkpt.lon; trkpt._lat = trkpt.lat; trkpt._ele = trkpt.ele; trkpt._timestamp = trkpt.timestamp; trkpt._timestamp_msec = trkpt.timestamp_msec; track << trkpt; } break; } case CQlgtTrack::eTrkPts2: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 nTrkPts1 = 0; s1 >> nTrkPts1; if(nTrkPts1 != nTrkPts) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."), CQlgtTrack::tr("Number of trackpoints is not equal the number of training data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore); break; } QList::iterator pt1 = track.track.begin(); while (pt1 != track.track.end()) { quint32 dummy; s1 >> pt1->timestamp_msec; s1 >> dummy; s1 >> dummy; s1 >> dummy; s1 >> dummy; s1 >> dummy; ++pt1; } break; } // case CQlgtTrack::eTrain: // { // QDataStream s1(&entry->data, QIODevice::ReadOnly); // s1.setVersion(QDataStream::Qt_4_5); // quint32 nTrkPts1 = 0; // s1 >> nTrkPts1; // if(nTrkPts1 != nTrkPts) // { // QMessageBox::warning(0, tr("Corrupt track ..."), tr("Number of trackpoints is not equal the number of training data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore); // break; // } // QList::iterator pt1 = track.track.begin(); // while (pt1 != track.track.end()) // { // s1 >> pt1->heartReateBpm; // s1 >> pt1->cadenceRpm; // pt1++; // } // track.setTraineeData(); // break; // } case CQlgtTrack::eTrkExt1: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 nTrkPts1 = 0; s1 >> nTrkPts1; if(nTrkPts1 != nTrkPts) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."), CQlgtTrack::tr("Number of trackpoints is not equal the number of extended data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore); break; } QList::iterator pt1 = track.track.begin(); while (pt1 != track.track.end()) { ///< [m] s1 >> pt1->altitude; ///< [m] s1 >> pt1->height; ///< [m/s] s1 >> pt1->velocity; ///< [deg] s1 >> pt1->heading; ///< [deg] s1 >> pt1->magnetic; s1 >> pt1->vdop; s1 >> pt1->hdop; s1 >> pt1->pdop; s1 >> pt1->x; ///< [m] cartesian gps coordinate s1 >> pt1->y; ///< [m] cartesian gps coordinate s1 >> pt1->z; ///< [m] cartesian gps coordinate ///< [m/s] velocity s1 >> pt1->vx; ///< [m/s] velocity s1 >> pt1->vy; ///< [m/s] velocity s1 >> pt1->vz; ++pt1; } track.setExt1Data(); break; } case CQlgtTrack::eTrkShdw: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 n; quint32 nTrkPts1 = 0; s1 >> nTrkPts1; if(nTrkPts1 != nTrkPts) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."), CQlgtTrack::tr("Number of trackpoints is not equal the number of shadow data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore); break; } for(n = 0; n < nTrkPts; ++n) { CQlgtTrack::pt_t& trkpt = track.track[n]; s1 >> trkpt._lon; s1 >> trkpt._lat; s1 >> trkpt._ele; } track.hasShadow1 = true; break; } case CQlgtTrack::eTrkShdw2: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); quint32 n; quint32 nTrkPts1 = 0; s1 >> nTrkPts1; if(nTrkPts1 != nTrkPts) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."), CQlgtTrack::tr("Number of trackpoints is not equal the number of shadow data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore); break; } for(n = 0; n < nTrkPts; ++n) { quint32 dummy; CQlgtTrack::pt_t& trkpt = track.track[n]; s1 >> trkpt._timestamp; s1 >> trkpt._timestamp_msec; s1 >> dummy; s1 >> dummy; s1 >> dummy; s1 >> dummy; s1 >> dummy; } track.hasShadow2 = true; break; } default: ; } ++entry; } return s; } QDataStream& operator <<(QDataStream& s, CQlgtTrack& trk) { return s; } CQlgtTrack::CQlgtTrack(quint64 id, QObject *parent) : QObject(parent) , IItem(id) , ext1Data(false) , hasShadow1(false) , hasShadow2(false) { } CQlgtTrack::~CQlgtTrack() { } CQlgtTrack& CQlgtTrack::operator<<(const pt_t& pt) { track.push_back(pt); track.last().idx = track.size() - 1; track.last().flags &= ~pt_t::eCursor; track.last().flags &= ~pt_t::eFocus; track.last().flags &= ~pt_t::eSelected; return *this; } qmapshack-1.10.0/src/qlgt/CQlgtWpt.h000644 001750 000144 00000005715 13216234142 020344 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTWPT_H #define CQLGTWPT_H #include "qlgt/IItem.h" class CQlgtWpt : public QObject, public IItem { public: CQlgtWpt(quint64 id, QObject * parent); virtual ~CQlgtWpt(); void setIcon(const QString& str); enum geocacheservice_e {eGC, eOC, eTC}; enum type_e {eEnd,eBase,eImage,eGeoCache}; struct geocachelog_t { geocachelog_t() : id(0) { } quint32 id; QString date; QString type; QString finderId; QString finder; QString text; }; struct geocache_t { geocache_t() : service(eOC), hasData(false), id(0), available(true), archived(false), difficulty(0), terrain(0), exportBuddies(false) { } geocacheservice_e service; bool hasData; quint32 id; bool available; bool archived; float difficulty; float terrain; QString status; QString name; QString owner; QString ownerId; QString type; QString container; QString shortDesc; QString longDesc; QString hint; QString country; QString state; QString locale; QList logs; bool exportBuddies; }; geocache_t geocache; quint32 selected = 0; quint32 sticky = 0; float lat = 0; ///< [deg] float lon = 0; ///< [deg] float ele = 0; ///< [m] float prx = 0; ///< [m] float dir = 0; ///< [deg] QString link; QString urlname; QString type; struct image_t { quint32 offset; QString info; QPixmap pixmap; QString filePath; QString fileName; }; QList images; struct buddy_t { QString name; QSet pos; float lon; float lat; }; QList buddies; }; QDataStream& operator >>(QDataStream& s, CQlgtWpt& wpt); QDataStream& operator <<(QDataStream& s, CQlgtWpt& wpt); #endif //CQLGTWPT_H qmapshack-1.10.0/src/qlgt/CQlgtDiary.cpp000644 001750 000144 00000015425 13216234137 021200 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CQlgtDiary.h" struct diary_head_entry_t { diary_head_entry_t() : type(CQlgtDiary::eEnd), offset(0) { } qint32 type; quint32 offset; QByteArray data; }; QDataStream& operator >>(QDataStream& s, CQlgtDiary& diary) { QIODevice * dev = s.device(); qint64 pos = dev->pos(); char magic[9]; s.readRawData(magic,9); if(strncmp(magic,"QLDry ",9)) { dev->seek(pos); return s; } QList entries; while(1) { diary_head_entry_t entry; s >> entry.type >> entry.offset; entries << entry; if(entry.type == CQlgtDiary::eEnd) { break; } } QList::iterator entry = entries.begin(); while(entry != entries.end()) { qint64 o = pos + entry->offset; dev->seek(o); s >> entry->data; switch(entry->type) { case CQlgtDiary::eBase: { QString comment, name,key; QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); s1 >> diary.timestamp; s1 >> diary.comment; s1 >> diary.name; s1 >> diary.keyProjectGeoDB; s1 >> diary.key; break; } // case CQlgtDiary::eWpt: // { // int cnt; // QDataStream s1(&entry->data, QIODevice::ReadOnly); // s1.setVersion(QDataStream::Qt_4_5); // s1 >> cnt; // for(int i=0; i < cnt; i++) // { // CWpt * wpt = new CWpt(&diary); // s1 >> *wpt; // diary.wpts << wpt; // } // break; // } // case CQlgtDiary::eTrk: // { // int cnt; // QDataStream s1(&entry->data, QIODevice::ReadOnly); // s1.setVersion(QDataStream::Qt_4_5); // s1 >> cnt; // for(int i=0; i < cnt; i++) // { // CTrack * trk = new CTrack(&diary); // s1 >> *trk; // trk->rebuild(true); // diary.trks << trk; // } // break; // } // case CQlgtDiary::eRte: // { // int cnt; // QDataStream s1(&entry->data, QIODevice::ReadOnly); // s1.setVersion(QDataStream::Qt_4_5); // s1 >> cnt; // for(int i=0; i < cnt; i++) // { // CRoute * rte = new CRoute(&diary); // s1 >> *rte; // diary.rtes << rte; // } // break; // } default: ; } ++entry; } return s; } QDataStream& operator <<(QDataStream& s, CQlgtDiary& diary) { QList entries; //--------------------------------------- // prepare base data //--------------------------------------- diary_head_entry_t entryBase; entryBase.type = CQlgtDiary::eBase; QDataStream s1(&entryBase.data, QIODevice::WriteOnly); s1.setVersion(QDataStream::Qt_4_5); s1 << diary.timestamp; s1 << diary.comment; s1 << diary.name; s1 << diary.keyProjectGeoDB; s1 << diary.key; entries << entryBase; // //--------------------------------------- // // prepare waypoint data // //--------------------------------------- // diary_head_entry_t entryWpt; // entryWpt.type = CQlgtDiary::eWpt; // QDataStream s2(&entryWpt.data, QIODevice::WriteOnly); // s2.setVersion(QDataStream::Qt_4_5); // s2 << diary.wpts.count(); // for(CWpt * wpt : diary.wpts) // { // s2 << *wpt; // } // entries << entryWpt; // //--------------------------------------- // // prepare track data // //--------------------------------------- // diary_head_entry_t entryTrk; // entryTrk.type = CQlgtDiary::eTrk; // QDataStream s3(&entryTrk.data, QIODevice::WriteOnly); // s3.setVersion(QDataStream::Qt_4_5); // s3 << diary.trks.count(); // for(CTrack * trk : diary.trks) // { // s3 << *trk; // } // entries << entryTrk; // //--------------------------------------- // // prepare route data // //--------------------------------------- // diary_head_entry_t entryRte; // entryRte.type = CQlgtDiary::eRte; // QDataStream s4(&entryRte.data, QIODevice::WriteOnly); // s4.setVersion(QDataStream::Qt_4_5); // s4 << diary.rtes.count(); // for(CRoute * rte : diary.rtes) // { // s4 << *rte; // } // entries << entryRte; //--------------------------------------- // prepare terminator //--------------------------------------- diary_head_entry_t entryEnd; entryEnd.type = CQlgtDiary::eEnd; entries << entryEnd; //--------------------------------------- //--------------------------------------- // now start to actually write data; //--------------------------------------- //--------------------------------------- // write magic key s.writeRawData("QLDry ",9); // calculate offset table quint32 offset = entries.count() * 8 + 9; QList::iterator entry = entries.begin(); while(entry != entries.end()) { entry->offset = offset; offset += entry->data.size() + sizeof(quint32); ++entry; } // write offset table entry = entries.begin(); while(entry != entries.end()) { s << entry->type << entry->offset; ++entry; } // write entry data entry = entries.begin(); while(entry != entries.end()) { s << entry->data; ++entry; } return s; } CQlgtDiary::CQlgtDiary(quint64 id, QObject *parent) : QObject(parent) , IItem(id) { } CQlgtDiary::~CQlgtDiary() { } qmapshack-1.10.0/src/qlgt/IItem.h000644 001750 000144 00000002511 13216234142 017635 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IITEM_H #define IITEM_H #include #include #define WPT_NOFLOAT 1e25f class IItem { public: IItem(quint64 id); virtual ~IItem(); QString getInfo() { return "no info"; } quint32 timestamp = 0; QString name; QString comment; QString description; QPixmap iconPixmap; QString iconString; QString parentWpt; QString key; quint64 id; }; #endif //IITEM_H qmapshack-1.10.0/src/qlgt/CQlgtTrack.h000644 001750 000144 00000020651 13216234142 020632 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTTRACK_H #define CQLGTTRACK_H #include "qlgt/IItem.h" #include class CQlgtWpt; class CFlags { public: CFlags(quint32 f=0) { flags = f; changed = true; } virtual ~CFlags() { } quint32 flag() const { return flags; } void setFlags( quint32 f ) { if ( flags != f ) { changed = true; } flags = f; } quint32 operator &(quint32 f) const { return flags&f; } quint32 operator |=(quint32 f) { if ( flags != (flags|f) ) { changed = true; } flags|=f; return flags; } quint32 operator &=(quint32 f) { if ( flags != (flags&f) ) { changed = true; } flags&=f; return flags; } quint32 operator >>(quint32 & f) { if ( flags != f ) { changed = true; } flags = f; return flags; } bool isChanged() const { return changed; } void setChanged(bool b) { changed = b; } protected: /// display flags quint32 flags; bool changed; }; QDataStream& operator >>(QDataStream& s, CFlags& flag); QDataStream& operator <<(QDataStream& s, CFlags& flag); class CQlgtTrack : public QObject, public IItem { Q_DECLARE_TR_FUNCTIONS(CQlgtTrack) public: CQlgtTrack(quint64 id, QObject * parent); virtual ~CQlgtTrack(); enum type_e {eEnd,eBase,eTrkPts,eTrain,eTrkExt1,eTrkGpxExt,eTrkShdw, eTrkShdw2, eTrkPts2}; struct pt_t { enum flag_e { eSelected = 1 ///< selected by track info view ,eCursor = 2 ///< selected by cursor ,eDeleted = 4 ///< mark point as deleted ,eFocus = 8 ///< mark current point of user focus }; pt_t() : idx(-1), lon(WPT_NOFLOAT), lat(WPT_NOFLOAT), ele(WPT_NOFLOAT), timestamp(0), timestamp_msec(0), speed(WPT_NOFLOAT), avgspeed(0), delta(WPT_NOFLOAT), azimuth(WPT_NOFLOAT), distance(WPT_NOFLOAT), ascent(0), descent(0), heartReateBpm(-1), cadenceRpm(-1), slope(0), slope2(WPT_NOFLOAT), timeSinceStart(0), fix(""), sat(0), velocity(WPT_NOFLOAT), heading(WPT_NOFLOAT), vdop(WPT_NOFLOAT), hdop(WPT_NOFLOAT), pdop(WPT_NOFLOAT), _lon(WPT_NOFLOAT),_lat(WPT_NOFLOAT),_ele(WPT_NOFLOAT), _timestamp(0), _timestamp_msec(0), flags(0), px_valid(false), dem(WPT_NOFLOAT), editItem(nullptr) { } bool operator==(const pt_t& pt) const { return pt.idx == idx; } /// index counter for easy QVector access qint32 idx; /// longitude [deg] float lon; /// latitude [deg] float lat; /// elevation [m] float ele; /// timestamp for track creation quint32 timestamp; quint32 timestamp_msec; /// secondary data: the speed between this and the previous point float speed; /// secondary data: the short term average speed float avgspeed; /// secondary data: the distance between this and the previous point float delta; /// secondary data: the azimuth to the next point double azimuth; /// secondary data: the total distance of all visible points up to this point float distance; /// secondary data: the total ascent of all visible points up to this point float ascent; /// secondary data: the total descent of all visible points up to this point float descent; /// secondary data: the heart rate in bpm int heartReateBpm; /// secondary data: cadence in rpm int cadenceRpm; /// secondary data: slope in % float slope; /// secondary data: slope in % float slope2; quint32 timeSinceStart; // extended data 1 QString fix; qint32 sat; float altitude = 0; ///< [m] Altitude, Meters, above mean sea level float height = 0; ///< [m] Height of geoid (mean sea level) above WGS84 ellipsoid float velocity; ///< [m/s] Ground speed, meters per hour float heading; ///< [] Track angle in degrees True float magnetic = 0; ///< [] Magnetic Variation float vdop; ///< Vertical dilution of precision (VDOP) float hdop; ///< Horizontal dilution of precision (HDOP) float pdop; ///< PDOP (dilution of precision) float x = 0; ///< [m] cartesian gps coordinate float y = 0; ///< [m] cartesian gps coordinate float z = 0; ///< [m] cartesian gps coordinate float vx = 0; ///< [m/s] velocity float vy = 0; ///< [m/s] velocity float vz = 0; ///< [m/s] velocity #ifdef GPX_EXTENSIONS CGpxExtPt gpx_exts; #endif // track shadow data (copy of original data) /// longitude [deg] float _lon; /// latitude [deg] float _lat; /// elevation [m] float _ele; quint32 _timestamp; quint32 _timestamp_msec; /// display flags CFlags flags; /// the current location in pixel QPoint px; bool px_valid; float dem; /// QTreeWidgetItem QPointer editItem; QColor color; }; struct wpt_t { wpt_t() : wpt(0), d(1e25f), x(0), y(0) { } CQlgtWpt * wpt; double d; double x; double y; pt_t trkpt; }; CQlgtTrack& operator<<(const pt_t& pt); /// a track URL QString url; /// the track line color QColor color; QPixmap bullet; /// the track line color by index unsigned colorIdx = 0; /// the track points QList track; /// set true to draw track highlighted bool highlight = 0; /// total time covered by all track points double totalTime = 0; /// total time moving double totalTimeMoving = 0; /// total distance of track [m] double totalDistance = 0; /// total ascent in [m] double totalAscent = 0; /// total descent in [m] double totalDescent = 0; /// the Qt polyline for faster processing QPolygon polyline; /// the color attached to each point in polyline (only used in multicolor mode) QVector polylineColor; float avgspeed0 = 0; float avgspeed1 = 0; pt_t ptMaxEle; pt_t ptMinEle; pt_t ptMaxSpeed; pt_t ptMinSpeed; bool traineeData = 0; bool ext1Data = 0; bool firstTime = 0; bool m_hide = 0; quint32 doScaleWpt2Track = 0; quint32 visiblePointCount = 0; quint32 cntMedianFilterApplied = 0; QList waypoints; bool replaceOrigData = 0; enum state_select_e {eNoSel, e1stSel, e2ndSel}; state_select_e stateSelect = eNoSel; QString timezone; enum multi_color_item_e { eMultiColorNone , eMultiColorSlope , eMultiColorEle , eMultiColorSpeed , eMultiColorMax }; quint32 useMultiColor = 0; qint32 idMultiColor = 0; bool hasExt1Data() const { return ext1Data; } void setExt1Data() { ext1Data = true; } bool hasShadow1; bool hasShadow2; }; QDataStream& operator >>(QDataStream& s, CQlgtTrack& trk); QDataStream& operator <<(QDataStream& s, CQlgtTrack& trk); #endif //CQLGTTRACK_H qmapshack-1.10.0/src/qlgt/CQlgtFolder.cpp000644 001750 000144 00000004272 13216234137 021341 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/db/macros.h" #include "qlgt/CQlgtDb.h" #include "qlgt/CQlgtDiary.h" #include "qlgt/CQlgtFolder.h" #include CQlgtFolder::CQlgtFolder(quint64 id, QSqlDatabase &db) : type(0) , locked(false) , diary(nullptr) , id(id) { QSqlQuery query(db); query.prepare("SELECT type, name, comment, locked FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(query.next()) { type = query.value(0).toInt(); name = query.value(1).toString(); comment = query.value(2).toString(); locked = query.value(3).toBool(); } query.prepare("SELECT id, data FROM diarys WHERE parent=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(query.next()) { quint64 idDiary = query.value(0).toULongLong(); QByteArray data = query.value(1).toByteArray(); QDataStream stream(&data, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); diary = new CQlgtDiary(idDiary, this); stream >> *diary; } query.prepare("SELECT child FROM folder2item WHERE parent=:folder"); query.bindValue(":folder", id); QUERY_EXEC(return ); while(query.next()) { items << query.value(0).toULongLong(); } } CQlgtFolder::~CQlgtFolder() { } qmapshack-1.10.0/src/qlgt/CQlgtDb.cpp000644 001750 000144 00000053322 13216234137 020453 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "qlgt/CQlb.h" #include "qlgt/CQlgtDb.h" #include "qlgt/CQlgtFolder.h" #include "qlgt/CQlgtRoute.h" #include "qlgt/CQlgtTrack.h" #include "qlgt/CQlgtWpt.h" #include "qlgt/CQmsDb.h" #include "qlgt/IQlgtOverlay.h" #include "tool/CImportDatabase.h" #include "gis/WptIcons.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include "CMainWindow.h" #include #include #define DB_QLGT_VERSION 9 CQlgtDb::CQlgtDb(const QString &filename, CImportDatabase *parent) : gui(parent) , nItems(0) , nFolders(0) , nWpt(0) , nTrk(0) , nRte(0) , nOvl(0) , nDiary(0) { db = QSqlDatabase::addDatabase("QSQLITE","qlandkarte"); db.setDatabaseName(filename); db.open(); QFileInfo fi(filename); path = fi.absoluteDir(); name = fi.fileName(); QSqlQuery query(db); if(!query.exec("PRAGMA locking_mode=EXCLUSIVE")) { return; } if(!query.exec("PRAGMA synchronous=OFF")) { return; } if(!query.exec("PRAGMA temp_store=MEMORY")) { return; } if(!query.exec("PRAGMA default_cache_size=1000")) { return; } if(!query.exec("PRAGMA page_size=8192")) { return; } if(!query.exec("SELECT version FROM versioninfo")) { initDB(); } else if(query.next()) { int version = query.value(0).toInt(); if(version != DB_QLGT_VERSION) { migrateDB(version); } } else { initDB(); } printStatistic(); } CQlgtDb::~CQlgtDb() { } void CQlgtDb::initDB() { qDebug() << "void CGeoDB::initDB()"; QSqlQuery query(db); if(query.exec( "CREATE TABLE versioninfo ( version TEXT )")) { query.prepare( "INSERT INTO versioninfo (version) VALUES(:version)"); query.bindValue(":version", DB_QLGT_VERSION); QUERY_EXEC(); } if(!query.exec( "CREATE TABLE folders (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "icon TEXT NOT NULL," "name TEXT NOT NULL," "comment TEXT," "locked BOOLEAN DEFAULT FALSE" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec( "CREATE TABLE items (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER," "key TEXT NOT NULL," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "icon TEXT NOT NULL," "name TEXT NOT NULL," "comment TEXT," "data BLOB NOT NULL" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec( "CREATE TABLE workspace (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," "changed BOOLEAN DEFAULT FALSE," "data BLOB NOT NULL," "key TEXT NOT NULL" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec("INSERT INTO folders (icon, name, comment) VALUES ('', 'database', '')")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec( "CREATE TABLE folder2folder (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES folders(id)" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec( "CREATE TABLE folder2item (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES items(id)" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } if(!query.exec( "CREATE TABLE diarys (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "key TEXT NOT NULL," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "data BLOB NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); } } void CQlgtDb::migrateDB(int version) { qDebug() << "void CGeoDB::migrateDB(int version)" << version; QSqlQuery query(db); for(version++; version <= DB_QLGT_VERSION; version++) { switch(version) { case 1: break; case 2: { if(!query.exec( "CREATE TABLE workspace (" "id INTEGER PRIMARY KEY NOT NULL," "changed BOOLEAN DEFAULT FALSE," "data BLOB NOT NULL" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } break; } case 3: { if(!query.exec("ALTER TABLE workspace ADD COLUMN key TEXT")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } if(!query.exec("ALTER TABLE workspace ADD COLUMN type INTEGER")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } break; } case 4: { if(!query.exec("ALTER TABLE folders ADD COLUMN type INTEGER")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } query.prepare("UPDATE folders SET type=:type WHERE icon=:icon"); query.bindValue("type", eFolder1); query.bindValue("icon", ":/icons/iconFolderBlue16x16.png"); if(!query.exec()) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } query.prepare("UPDATE folders SET type=:type WHERE icon=:icon"); query.bindValue(":type", eFolder2); query.bindValue(":icon", ":/icons/iconFolderGreen16x16.png"); if(!query.exec()) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } break; } case 5: { if (QFile::exists(path.absoluteFilePath("qlgt_save_v4.db"))) { QFile::remove(path.absoluteFilePath("qlgt_save_v4.db")); } QFile f(path.absoluteFilePath(name)); f.copy(path.absoluteFilePath("qlgt_save_v4.db")); QSqlQuery query2(db); if(!query.exec("SELECT id, type, icon FROM items")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } const int total = query.size(); quint32 progCnt = 0; PROGRESS_SETUP(tr("Migrating database from version 4 to 5."), 0, total, CMainWindow::getBestWidgetForParent()); while(query.next()) { QPixmap pixmap; if(query.value(1).toInt() == eWpt || query.value(1).toInt() == eRte) { QPointF focus; pixmap = getWptIconByName(query.value(2).toString(), focus); } else if(query.value(1).toInt() == eTrk) { pixmap = QPixmap(16,16); pixmap.fill(query.value(2).toString()); } else { pixmap = QPixmap(query.value(2).toString()); } QByteArray bytes; QBuffer buffer(&bytes); buffer.open(QIODevice::WriteOnly); pixmap.save(&buffer, "XPM"); query2.prepare("UPDATE items SET icon=:icon WHERE id=:id"); query2.bindValue(":id", query.value(0).toULongLong()); query2.bindValue(":icon", bytes); if(!query2.exec()) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } PROGRESS(progCnt++, continue); } break; } case 6: { QSqlQuery query2(db); if(!query.exec("SELECT id, data, type FROM items")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } const int total = query.size(); quint32 progCnt = 0; PROGRESS_SETUP(tr("Migrating database from version 5 to 6."), 0, total, CMainWindow::getBestWidgetForParent()); while(query.next()) { QByteArray array = query.value(1).toByteArray(); QBuffer buffer(&array); CQlb qlb(this); qlb.load(&buffer); switch(query.value(2).toInt()) { case eWpt: array = qlb.waypoints(); break; case eTrk: array = qlb.tracks(); break; case eRte: array = qlb.routes(); break; case eOvl: array = qlb.overlays(); break; } query2.prepare("UPDATE items SET data=:data WHERE id=:id"); query2.bindValue(":data", array); query2.bindValue(":id", query.value(0)); if(!query2.exec()) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } PROGRESS(progCnt++, continue); } break; } case 7: { QSqlQuery query2(db); if(!query.exec("SELECT id, data, type FROM items")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } const int total = query.size(); quint32 progCnt = 0; PROGRESS_SETUP(tr("Migrating database from version 6 to 7."), 0, total, CMainWindow::getBestWidgetForParent()); while(query.next()) { QString comment; QByteArray array = query.value(1).toByteArray(); QDataStream stream(&array, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); quint64 id = query.value(0).toULongLong(); switch(query.value(2).toInt()) { case eWpt: { CQlgtWpt wpt(id, nullptr); stream >> wpt; comment = wpt.getInfo(); } break; case eTrk: { CQlgtTrack trk(id, nullptr); stream >> trk; comment = trk.getInfo(); } break; case eRte: { CQlgtRoute rte(id, nullptr); stream >> rte; comment = rte.getInfo(); } break; case eOvl: { // IOverlay ovl(0); // stream >> ovl; // comment = ovl.getInfo(); continue; } break; } query2.prepare("UPDATE items SET comment=:comment WHERE id=:id"); query2.bindValue(":comment", comment); query2.bindValue(":id", query.value(0)); if(!query2.exec()) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } PROGRESS(progCnt++, continue); } break; } case 8: { PROGRESS_SETUP(tr("Migrating database from version 7 to 8."), 0, 1, CMainWindow::getBestWidgetForParent()); if(!query.exec( "CREATE TABLE diarys (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "key TEXT NOT NULL," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "data BLOB NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)" ")")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } PROGRESS(1, return ); break; } case 9: { if (QFile::exists(path.absoluteFilePath(name))) { QFile::remove(path.absoluteFilePath("qlgt_save_v8.db")); } QFile f(path.absoluteFilePath(name)); f.copy(path.absoluteFilePath("qlgt_save_v4.db")); PROGRESS_SETUP(tr("Migrating database from version 8 to 9."), 0, 1, CMainWindow::getBestWidgetForParent()); if(!query.exec("ALTER TABLE folders ADD COLUMN locked BOOLEAN DEFAULT FALSE")) { qDebug() << query.lastQuery(); qDebug() << query.lastError(); return; } PROGRESS(1, return ); break; } } } query.prepare( "UPDATE versioninfo set version=:version"); query.bindValue(":version", version - 1); QUERY_EXEC(); } void CQlgtDb::printStatistic() { QSqlQuery query(db); gui->stdOut(tr("Open database: %1").arg(db.databaseName())); nItems = 0; query.prepare("SELECT COUNT() FROM folders"); QUERY_EXEC(); if(query.next()) { nFolders = query.value(0).toInt(); gui->stdOut(tr("Folders: %1").arg(nFolders)); } query.prepare("SELECT COUNT() FROM items WHERE type=:type"); query.bindValue(":type", eTrk); QUERY_EXEC(); if(query.next()) { nItems += query.value(0).toInt(); gui->stdOut(tr("Tracks: %1").arg(query.value(0).toInt())); } query.prepare("SELECT COUNT() FROM items WHERE type=:type"); query.bindValue(":type", eRte); QUERY_EXEC(); if(query.next()) { nItems += query.value(0).toInt(); gui->stdErr(tr("Routes: %1 (Only the basic route will be copied)").arg(query.value(0).toInt())); } query.prepare("SELECT COUNT() FROM items WHERE type=:type"); query.bindValue(":type", eWpt); QUERY_EXEC(); if(query.next()) { nItems += query.value(0).toInt(); gui->stdOut(tr("Waypoints: %1").arg(query.value(0).toInt())); } query.prepare("SELECT COUNT() FROM items WHERE type=:type"); query.bindValue(":type", eOvl); QUERY_EXEC(); if(query.next()) { nItems += query.value(0).toInt(); gui->stdErr(tr("Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost)").arg(query.value(0).toInt())); } query.prepare("SELECT COUNT() FROM diarys"); query.bindValue(":type", eDry); QUERY_EXEC(); if(query.next()) { gui->stdOut(tr("Diaries: %1").arg(query.value(0).toInt())); } query.prepare("SELECT COUNT() FROM items WHERE type=:type"); query.bindValue(":type", eMap); QUERY_EXEC(); if(query.next()) { gui->stdErr(tr("Map selections: %1 (can't be converted to QMapShack)").arg(query.value(0).toInt())); } } void CQlgtDb::start(const QString& filename) { gui->stdOut(tr("------ Start to convert database to %1------").arg(filename)); dbQms = new CQmsDb(filename, gui); if(!dbQms->isValid()) { gui->stdErr(tr("Failed to create target database.")); gui->stdOut(tr("------ Abort ------")); return; } xferItems(); xferFolders(); QSqlQuery query(db); query.prepare("Select parent, child FROM folder2folder"); QUERY_EXEC(return ); while(query.next()) { quint64 idParent = query.value(0).toULongLong(); quint64 idChild = query.value(1).toULongLong(); dbQms->addFolder2FolderRelation(idParent, idChild); } query.prepare("Select parent, child FROM folder2item"); QUERY_EXEC(return ); while(query.next()) { quint64 idParent = query.value(0).toULongLong(); quint64 idChild = query.value(1).toULongLong(); dbQms->addFolder2ItemRelation(idParent, idChild); } delete dbQms; gui->stdOut(tr("------ Done ------")); } void CQlgtDb::xferFolders() { nDiary = 0; quint32 cnt = 1; PROGRESS_SETUP(tr("Restore folders..."), 0, nFolders, gui); QSqlQuery query(db); query.prepare("SELECT id FROM folders"); QUERY_EXEC(return ); while(query.next()) { PROGRESS(cnt++, break); quint64 idFolder = query.value(0).toULongLong(); CQlgtFolder folder1(idFolder, db); if(folder1.diary) { nDiary++; } dbQms->addFolder(folder1); } progress.setValue(100); gui->stdOut(tr("Imported %1 folders and %2 diaries").arg(nFolders).arg(nDiary)); } void CQlgtDb::xferItems() { quint32 cnt = 1; PROGRESS_SETUP(tr("Copy items..."), 0, nItems, gui); nWpt = 0; nTrk = 0; nRte = 0; nOvl = 0; QSqlQuery query(db); query.prepare("SELECT id FROM items"); QUERY_EXEC(return ); while(query.next()) { PROGRESS(cnt++, break); xferItem(query.value(0).toULongLong()); } progress.setValue(100); gui->stdOut(tr("Imported %1 tracks, %2 waypoints, %3 routes, %4 areas").arg(nTrk).arg(nWpt).arg(nRte).arg(nOvl)); gui->stdOut(tr("Import folders...")); query.prepare("SELECT id FROM folders"); QUERY_EXEC(return ); } void CQlgtDb::xferItem(quint64 id) { QSqlQuery query(db); query.prepare("SELECT type, data FROM items WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(query.next()) { QByteArray data = query.value(1).toByteArray(); QDataStream stream(&data, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); switch(query.value(0).toInt()) { case eWpt: { CQlgtWpt wpt1(id, 0); stream >> wpt1; dbQms->addWpt(wpt1); nWpt++; break; } case eTrk: { CQlgtTrack trk1(id, 0); stream >> trk1; dbQms->addTrk(trk1); nTrk++; break; } case eRte: { CQlgtRoute rte1(id, 0); stream >> rte1; dbQms->addRte(rte1); nRte++; break; } case eOvl: { IQlgtOverlay ovl1(id, 0); stream >> ovl1; if(ovl1.type == "Area") { dbQms->addArea(ovl1); nOvl++; } else if(ovl1.type == "Distance") { dbQms->addTrk(ovl1); nTrk++; } else { gui->stdErr(tr("Overlay of type '%1' cant be converted").arg(ovl1.type)); nOvl++; break; } break; } } } } qmapshack-1.10.0/src/qlgt/converter.cpp000644 001750 000144 00000021402 13216234261 021172 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/WptIcons.h" #include "gis/db/CDBProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "qlgt/CQlgtDiary.h" #include "qlgt/CQlgtFolder.h" #include "qlgt/CQlgtRoute.h" #include "qlgt/CQlgtTrack.h" #include "qlgt/CQlgtWpt.h" #include "qlgt/IQlgtOverlay.h" #include "units/IUnit.h" inline qreal readFloat(float val) { return val > NOFLOAT ? NOFLOAT : val; } CDBProject::CDBProject(CQlgtFolder& folder) : IGisProject(eTypeDb, "", (CGisListWks*) nullptr) { metadata.name = folder.name; if(folder.diary) { metadata.desc = folder.diary->comment; } } CGisItemWpt::CGisItemWpt(const CQlgtWpt& wpt1, IGisProject * project) : IGisItem(project, eTypeWpt, NOIDX) { qreal direction; QDateTime time = QDateTime::fromTime_t(wpt1.timestamp,QTimeZone("UTC")); wpt.time = time.toUTC(); wpt.name = wpt1.name; wpt.cmt = wpt1.comment; wpt.desc = wpt1.description; wpt.sym = wpt1.iconString; wpt.lat = readFloat(wpt1.lat); wpt.lon = readFloat(wpt1.lon); wpt.ele = wpt1.ele == WPT_NOFLOAT ? NOINT : qRound(wpt1.ele); proximity = readFloat(wpt1.prx); direction = readFloat(wpt1.dir); if(!wpt1.link.isEmpty()) { IGisItem::link_t link; link.uri = wpt1.link; wpt.links << link; } if(!wpt1.urlname.isEmpty()) { IGisItem::link_t link; link.uri = wpt1.urlname; wpt.links << link; } wpt.type = wpt1.type; if(wpt1.geocache.hasData) { geocache.service = CGisItemWpt::geocacheservice_e(wpt1.geocache.service); geocache.hasData = wpt1.geocache.hasData; geocache.id = wpt1.geocache.id; geocache.available = wpt1.geocache.available; geocache.archived = wpt1.geocache.archived; geocache.difficulty = wpt1.geocache.difficulty; geocache.terrain = wpt1.geocache.terrain; geocache.status = wpt1.geocache.status; geocache.name = wpt1.geocache.name; geocache.owner = wpt1.geocache.owner; geocache.ownerId = wpt1.geocache.ownerId; geocache.type = wpt1.geocache.type; geocache.container = wpt1.geocache.container; geocache.shortDescIsHtml = wpt1.geocache.shortDesc.contains("> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(event.data); event.hash = md5.result().toHex(); history.histIdxCurrent = history.events.size() - 1; } } CGisItemTrk::CGisItemTrk(const IQlgtOverlay& ovl, IGisProject * project) : IGisItem(project, eTypeTrk, NOIDX) , activities(this) { trk.name = ovl.name; trk.cmt = ovl.comment; trk.desc = ovl.description; trk.color = ovl.color.name(); CTrackData::trkseg_t seg; for(const IQlgtOverlay::pt_t& pt1 : ovl.points) { CTrackData::trkpt_t pt; pt.lon = pt1.u * RAD_TO_DEG; pt.lat = pt1.v * RAD_TO_DEG; seg.pts << pt; } trk.segs << seg; setColor(str2color(trk.color)); deriveSecondaryData(); filterReplaceElevation(); if(ovl.speed != 0) { filterSpeed(ovl.speed); } genKey(); setupHistory(); } CGisItemOvlArea::CGisItemOvlArea(const IQlgtOverlay& ovl, IGisProject * project) : IGisItem(project, eTypeOvl, NOIDX) { area.name = ovl.name; area.cmt = ovl.comment; area.desc = ovl.description; area.color = ovl.color.name(); area.width = ovl.width; area.style = ovl.style; area.opacity = ovl.opacity != 255; for(const IQlgtOverlay::pt_t& pt1 : ovl.points) { pt_t pt; pt.lon = pt1.u * RAD_TO_DEG; pt.lat = pt1.v * RAD_TO_DEG; area.pts << pt; } setColor(str2color(area.color)); deriveSecondaryData(); genKey(); setupHistory(); } CGisItemRte::CGisItemRte(const CQlgtRoute& rte1, IGisProject * project) : IGisItem(project, eTypeRte, NOIDX) { rte.name = rte1.name; rte.cmt = rte1.comment; rte.desc = rte1.description; QPointF focus; QPixmap icon = getWptIconByName(rte1.iconString, focus); for(const CQlgtRoute::pt_t& pt1 : rte1.priRoute) { rtept_t pt; pt.lon = pt1.lon; pt.lat = pt1.lat; pt.icon = icon; pt.focus = focus; rte.pts << pt; } deriveSecondaryData(); setSymbol(); genKey(); setupHistory(); } qmapshack-1.10.0/src/qlgt/CQlgtRoute.h000644 001750 000144 00000003271 13216234142 020663 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLGTROUTE_H #define CQLGTROUTE_H #include "qlgt/IItem.h" #include #include class CQlgtRoute : public QObject, public IItem { public: CQlgtRoute(quint64 id, QObject * parent); virtual ~CQlgtRoute(); enum type_e {eEnd, eBase, eRtePts, eRteSec}; struct pt_t { float lon; float lat; QString action; operator const projXY () { projXY p; p.u = lon; p.v = lat; return p; } }; /// primary route, just the basic points like A to B via C QVector priRoute; quint32 ttime = 0; QString iconString; }; QDataStream& operator >>(QDataStream& s, CQlgtRoute& rte); QDataStream& operator <<(QDataStream& s, CQlgtRoute& rte); #endif //CQLGTROUTE_H qmapshack-1.10.0/src/qlgt/IQlgtOverlay.cpp000644 001750 000144 00000012112 13216234137 021545 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "IQlgtOverlay.h" struct ovl_head_entry_t { ovl_head_entry_t() : type(IQlgtOverlay::eEnd), offset(0) { } qint32 type; quint32 offset; QByteArray data; }; QDataStream& operator >>(QDataStream& s, IQlgtOverlay& ovl) { QIODevice * dev = s.device(); qint64 pos = dev->pos(); char magic[9]; s.readRawData(magic,9); if(strncmp(magic,"QLOvl ",9)) { dev->seek(pos); return s; } QList entries; while(1) { ovl_head_entry_t entry; s >> entry.type >> entry.offset; entries << entry; if(entry.type == IQlgtOverlay::eEnd) { break; } } QList::iterator entry = entries.begin(); while(entry != entries.end()) { qint64 o = pos + entry->offset; dev->seek(o); s >> entry->data; switch(entry->type) { case IQlgtOverlay::eBase: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); s1 >> ovl.type; if(ovl.type == "Text") { QRect rect; QString text; s1 >> rect >> text >> ovl.key; } else if(ovl.type == "TextBox") { QRect rect; QPoint pt; QString text; double lon, lat; s1 >> lon >> lat >> pt >> rect >> text >> ovl.key; } else if(ovl.type == "Distance") { int size, idx = 0; IQlgtOverlay::pt_t pt; s1 >> ovl.name >> ovl.comment >> size; for(int i = 0; i < size; ++i) { s1 >> pt.u >> pt.v; pt.idx = idx++; ovl.points << pt; } s1 >> ovl.speed >> ovl.key >> ovl.parentWpt; } else if(ovl.type == "Area") { int size, idx = 0; IQlgtOverlay::pt_t pt; s1 >> ovl.name >> ovl.comment >> size; for(int i = 0; i < size; ++i) { s1 >> pt.u >> pt.v; pt.idx = idx++; ovl.points << pt; } s1 >> ovl.color >> ovl.key >> ovl.parentWpt >> ovl.style >> ovl.width >> ovl.opacity; } break; } default: ; } ++entry; } return s; } QDataStream& operator <<(QDataStream& s, IQlgtOverlay& ovl) { QList entries; //--------------------------------------- // prepare base data //--------------------------------------- ovl_head_entry_t entryBase; entryBase.type = IQlgtOverlay::eBase; QDataStream s1(&entryBase.data, QIODevice::WriteOnly); s1.setVersion(QDataStream::Qt_4_5); s1 << ovl.type; // ovl.save(s1); entries << entryBase; //--------------------------------------- // prepare terminator //--------------------------------------- ovl_head_entry_t entryEnd; entryEnd.type = IQlgtOverlay::eEnd; entries << entryEnd; //--------------------------------------- //--------------------------------------- // now start to actually write data; //--------------------------------------- //--------------------------------------- // write magic key s.writeRawData("QLOvl ",9); // calculate offset table quint32 offset = entries.count() * 8 + 9; QList::iterator entry = entries.begin(); while(entry != entries.end()) { entry->offset = offset; offset += entry->data.size() + sizeof(quint32); ++entry; } // write offset table entry = entries.begin(); while(entry != entries.end()) { s << entry->type << entry->offset; ++entry; } // write entry data entry = entries.begin(); while(entry != entries.end()) { s << entry->data; ++entry; } return s; } IQlgtOverlay::IQlgtOverlay(quint64 id, QObject *parent) : IItem(id) { } IQlgtOverlay::~IQlgtOverlay() { } qmapshack-1.10.0/src/qlgt/IItem.cpp000644 001750 000144 00000001737 13216234137 020205 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "IItem.h" IItem::IItem(quint64 id) : id(id) { } IItem::~IItem() { } qmapshack-1.10.0/src/qlgt/CQlgtWpt.cpp000644 001750 000144 00000022512 13216234137 020675 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CQlgtWpt.h" #include "gis/WptIcons.h" struct wpt_head_entry_t { wpt_head_entry_t() : type(CQlgtWpt::eEnd), offset(0) { } qint32 type; quint32 offset; QByteArray data; }; QDataStream& operator >>(QDataStream& s, CQlgtWpt& wpt) { QIODevice * dev = s.device(); qint64 pos = dev->pos(); char magic[9]; s.readRawData(magic,9); if(strncmp(magic,"QLWpt ",9)) { dev->seek(pos); // throw(tr("This is not waypoint data.")); return s; } QList entries; while(1) { wpt_head_entry_t entry; s >> entry.type >> entry.offset; entries << entry; if(entry.type == CQlgtWpt::eEnd) { break; } } QList::iterator entry = entries.begin(); while(entry != entries.end()) { qint64 o = pos + entry->offset; dev->seek(o); s >> entry->data; switch(entry->type) { case CQlgtWpt::eBase: { QString icon; QString key; QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); s1 >> wpt.key; s1 >> wpt.sticky; s1 >> wpt.timestamp; s1 >> icon; s1 >> wpt.name; s1 >> wpt.comment; s1 >> wpt.lat; s1 >> wpt.lon; s1 >> wpt.ele; s1 >> wpt.prx; s1 >> wpt.link; s1 >> wpt.description; s1 >> wpt.urlname; s1 >> wpt.type; s1 >> wpt.parentWpt; s1 >> wpt.selected; if(!s1.atEnd()) { s1 >> wpt.dir; } else { wpt.dir = WPT_NOFLOAT; } wpt.setIcon(icon); break; } case CQlgtWpt::eImage: { QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); CQlgtWpt::image_t img; wpt.images.clear(); s1 >> img.offset; while(img.offset) { wpt.images << img; s1 >> img.offset; } QList::iterator image = wpt.images.begin(); while(image != wpt.images.end()) { s1.device()->seek(image->offset); s1 >> image->filePath; s1 >> image->info; s1 >> image->pixmap; ++image; } break; } case CQlgtWpt::eGeoCache: { quint32 N, n; QDataStream s1(&entry->data, QIODevice::ReadOnly); s1.setVersion(QDataStream::Qt_4_5); wpt.geocache = CQlgtWpt::geocache_t(); CQlgtWpt::geocache_t& cache = wpt.geocache; s1 >> (quint8&)cache.service; s1 >> cache.hasData; s1 >> cache.id; s1 >> cache.available; s1 >> cache.archived; s1 >> cache.difficulty; s1 >> cache.terrain; s1 >> cache.status; s1 >> cache.name; s1 >> cache.owner; s1 >> cache.ownerId; s1 >> cache.type; s1 >> cache.container; s1 >> cache.shortDesc; s1 >> cache.longDesc; s1 >> cache.hint; s1 >> cache.country; s1 >> cache.state; s1 >> cache.locale; s1 >> N; for(n = 0; n < N; n++) { CQlgtWpt::geocachelog_t log; s1 >> log.id; s1 >> log.date; s1 >> log.type; s1 >> log.finderId; s1 >> log.finder; s1 >> log.text; cache.logs << log; } s1 >> cache.exportBuddies; cache.hasData = true; break; } default: ; } ++entry; } return s; } QDataStream& operator <<(QDataStream& s, CQlgtWpt& wpt) { QList entries; //--------------------------------------- // prepare base data //--------------------------------------- wpt_head_entry_t entryBase; entryBase.type = CQlgtWpt::eBase; QDataStream s1(&entryBase.data, QIODevice::WriteOnly); s1.setVersion(QDataStream::Qt_4_5); s1 << wpt.key; s1 << wpt.sticky; s1 << wpt.timestamp; s1 << wpt.iconString; s1 << wpt.name; s1 << wpt.comment; s1 << wpt.lat; s1 << wpt.lon; s1 << wpt.ele; s1 << wpt.prx; s1 << wpt.link; s1 << wpt.description; s1 << wpt.urlname; s1 << wpt.type; s1 << QString(); s1 << wpt.selected; s1 << wpt.dir; entries << entryBase; //--------------------------------------- // prepare image data //--------------------------------------- wpt_head_entry_t entryImage; entryImage.type = CQlgtWpt::eImage; QDataStream s2(&entryImage.data, QIODevice::WriteOnly); s2.setVersion(QDataStream::Qt_4_5); // write place holder for image offset QList::iterator image = wpt.images.begin(); while(image != wpt.images.end()) { s2 << (quint32)0; ++image; } // offset terminator s2 << (quint32)0; // write image data and store the actual offset image = wpt.images.begin(); while(image != wpt.images.end()) { image->offset = (quint32)s2.device()->pos(); s2 << image->filePath; s2 << image->info; s2 << image->pixmap; ++image; } // finally write image offset table s2.device()->seek(0); image = wpt.images.begin(); while(image != wpt.images.end()) { s2 << image->offset; ++image; } entries << entryImage; //--------------------------------------- // prepare geocache data //--------------------------------------- if(wpt.geocache.hasData) { wpt_head_entry_t entryGeoCache; entryGeoCache.type = CQlgtWpt::eGeoCache; QDataStream s3(&entryGeoCache.data, QIODevice::WriteOnly); s3.setVersion(QDataStream::Qt_4_5); CQlgtWpt::geocache_t& cache = wpt.geocache; s3 << (quint8)cache.service; s3 << cache.hasData; s3 << cache.id; s3 << cache.available; s3 << cache.archived; s3 << cache.difficulty; s3 << cache.terrain; s3 << cache.status; s3 << cache.name; s3 << cache.owner; s3 << cache.ownerId; s3 << cache.type; s3 << cache.container; s3 << cache.shortDesc; s3 << cache.longDesc; s3 << cache.hint; s3 << cache.country; s3 << cache.state; s3 << cache.locale; s3 << cache.logs.count(); for(const CQlgtWpt::geocachelog_t& log : cache.logs) { s3 << log.id; s3 << log.date; s3 << log.type; s3 << log.finderId; s3 << log.finder; s3 << log.text; } s3 << cache.exportBuddies; entries << entryGeoCache; } //--------------------------------------- // prepare terminator //--------------------------------------- wpt_head_entry_t entryEnd; entryEnd.type = CQlgtWpt::eEnd; entries << entryEnd; //--------------------------------------- //--------------------------------------- // now start to actually write data; //--------------------------------------- //--------------------------------------- // write magic key s.writeRawData("QLWpt ",9); // calculate offset table quint32 offset = entries.count() * 8 + 9; QList::iterator entry = entries.begin(); while(entry != entries.end()) { entry->offset = offset; offset += entry->data.size() + sizeof(quint32); ++entry; } // write offset table entry = entries.begin(); while(entry != entries.end()) { s << entry->type << entry->offset; ++entry; } // write entry data entry = entries.begin(); while(entry != entries.end()) { s << entry->data; ++entry; } return s; } CQlgtWpt::CQlgtWpt(quint64 id, QObject *parent) : QObject(parent) , IItem(id) { } CQlgtWpt::~CQlgtWpt() { } void CQlgtWpt::setIcon(const QString& str) { QPointF focus; iconString = str; iconPixmap = getWptIconByName(str, focus); } qmapshack-1.10.0/src/CAbout.cpp000644 001750 000144 00000003536 13216234137 017403 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CAbout.h" #include "version.h" #include #include #include #include CAbout::CAbout(QWidget *parent) : QDialog(parent) { setupUi(this); labelVersion->setText(VER_STR); labelQtVersion->setText(qVersion()); labelGDALVersion->setText(GDALVersionInfo("--version")); labelProj4Version->setText(QString::number(PJ_VERSION)); if(Routino_CheckAPIVersion() != ROUTINO_ERROR_NONE) { labelRoutinoVersion->setText(tr("%1 (API V%2, expected V%3)").arg(Routino_Version).arg(ROUTINO_API_VERSION).arg(Routino_APIVersion)); } else { labelRoutinoVersion->setText(tr("%1 (API V%2)").arg(Routino_Version).arg(Routino_APIVersion)); } #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) #if defined (HAVE_DBUS) labelNoDBus->setText(""); #else labelNoDBus->setText(tr("(no DBUS: device detection and handling disabled)")); #endif #endif } CAbout::~CAbout() { } qmapshack-1.10.0/src/units/000755 001750 000144 00000000000 13216664443 016664 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/units/CUnitMetric.cpp000644 001750 000144 00000006103 13216234137 021547 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #include "units/CUnitMetric.h" CUnitMetric::CUnitMetric(QObject * parent) : IUnit(eTypeMetric, "m", 1.0, "km/h", 3.6, parent) { } void CUnitMetric::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT || meter == NOINT) { val = "-"; unit = ""; } else { val.sprintf("%1.0f", meter); unit = "m"; } } void CUnitMetric::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else if(meter < 10) { val.sprintf("%1.1f", meter); unit = "m"; } else if(meter < 1000) { val.sprintf("%1.0f", meter); unit = "m"; } else if(meter < 10000) { val.sprintf("%1.2f", meter / 1000); unit = "km"; } else if(meter < 20000) { val.sprintf("%1.1f", meter / 1000); unit = "km"; } else { val.sprintf("%1.0f", meter / 1000); unit = "km"; } } void CUnitMetric::meter2speed(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else if (meter < 0.27) { val.sprintf("%1.0f",meter * speedfactor * 1000); unit = "m/h"; } else if (meter < 10.0) { val.sprintf("%1.1f",meter * speedfactor); unit = speedunit; } else { val.sprintf("%1.0f",meter * speedfactor); unit = speedunit; } } void CUnitMetric::meter2area(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.2f", meter / 1000000); unit = "km²"; } } qreal CUnitMetric::elevation2meter(const QString& val) const /* override */ { return val.toDouble(); } void CUnitMetric::meter2unit(qreal meter, qreal& scale, QString& unit) const { if(meter > 1000) { scale = 0.001; unit = "km"; } else { scale = 1.0; unit = "m"; } } qmapshack-1.10.0/src/units/CUnitImperial.cpp000644 001750 000144 00000005633 13216234137 022075 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #include "units/CUnitImperial.h" const qreal CUnitImperial::footPerMeter = 3.28084; const qreal CUnitImperial::milePerMeter = 0.6213699E-3; const qreal CUnitImperial::meterPerSecToMilePerHour = 2.23693164; CUnitImperial::CUnitImperial(QObject * parent) : IUnit(eTypeImperial, "ft", footPerMeter, "ml/h", meterPerSecToMilePerHour, parent) { } void CUnitImperial::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.0f", meter * footPerMeter); unit = "ft"; } } void CUnitImperial::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else if(meter < 10) { val.sprintf("%1.1f", meter * footPerMeter); unit = "ft"; } else if(meter < 1600) { val.sprintf("%1.0f", meter * footPerMeter); unit = "ft"; } else if(meter < 16000) { val.sprintf("%1.2f", meter * milePerMeter); unit = "ml"; } else if(meter < 32000) { val.sprintf("%1.1f", meter * milePerMeter); unit = "ml"; } else { val.sprintf("%1.0f", meter * milePerMeter); unit = "ml"; } } void CUnitImperial::meter2area(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.2f", meter / (1/milePerMeter * 1/milePerMeter)); unit = "ml²"; } } qreal CUnitImperial::elevation2meter(const QString& val) const /* override */ { return val.toDouble() / footPerMeter; } void CUnitImperial::meter2unit(qreal meter, qreal& scale, QString& unit) const { if(meter > 1600) { scale = milePerMeter; unit = "ml"; } else { scale = footPerMeter; unit = "ft"; } } qmapshack-1.10.0/src/units/CUnitMetric.h000644 001750 000144 00000003150 13216234142 021207 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #ifndef CUNITMETRIC_H #define CUNITMETRIC_H #include "IUnit.h" class CUnitMetric : public IUnit { public: CUnitMetric(QObject * parent); virtual ~CUnitMetric() = default; void meter2elevation(qreal meter, QString& val, QString& unit) const override; void meter2distance(qreal meter, QString& val, QString& unit) const override; void meter2speed(qreal meter, QString& val, QString& unit) const override; void meter2area(qreal meter, QString& val, QString& unit) const override; qreal elevation2meter(const QString& val) const override; void meter2unit(qreal meter, qreal& scale, QString& unit) const override; }; #endif // CUNITMETRIC_H qmapshack-1.10.0/src/units/CUnitsSetup.cpp000644 001750 000144 00000004241 13216234137 021610 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "units/CUnitsSetup.h" #include "units/IUnit.h" CUnitsSetup::CUnitsSetup(QWidget *parent) : QDialog(parent) { setupUi(this); switch(IUnit::self().type) { case IUnit::eTypeMetric: radioMetric->setChecked(true); break; case IUnit::eTypeImperial: radioImperial->setChecked(true); break; case IUnit::eTypeNautic: radioNautic->setChecked(true); break; } switch(IUnit::getSlopeMode()) { case IUnit::eSlopeDegrees: radioDegrees->setChecked(true); break; case IUnit::eSlopePercent: radioPercent->setChecked(true); break; } } void CUnitsSetup::accept() { if(radioMetric->isChecked()) { IUnit::setUnitType(IUnit::eTypeMetric, &CMainWindow::self()); } else if(radioImperial->isChecked()) { IUnit::setUnitType(IUnit::eTypeImperial, &CMainWindow::self()); } else if(radioNautic->isChecked()) { IUnit::setUnitType(IUnit::eTypeNautic, &CMainWindow::self()); } if(radioDegrees->isChecked()) { IUnit::setSlopeMode(IUnit::eSlopeDegrees); } else if(radioPercent->isChecked()) { IUnit::setSlopeMode(IUnit::eSlopePercent); } QDialog::accept(); } qmapshack-1.10.0/src/units/IUnitsSetup.ui000644 001750 000144 00000011376 13176536631 021471 0ustar00oeichlerxusers000000 000000 IUnitsSetup 0 0 269 229 Setup units... 0 1 0 false false Length unit 10 0 343 20 Nautic 10 20 343 20 Imperial 10 40 343 20 Metric Slope unit 10 10 343 20 Degrees (°) 10 30 343 20 Percent (%) Qt::Vertical 20 7 0 0 <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IUnitsSetup accept() 248 254 157 274 buttonBox rejected() IUnitsSetup reject() 316 260 286 274 qmapshack-1.10.0/src/units/IUnit.cpp000644 001750 000144 00000050257 13216234261 020420 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #include "CMainWindow.h" #include "GeoMath.h" #include "units/CUnitImperial.h" #include "units/CUnitMetric.h" #include "units/CUnitNautic.h" #include #include const IUnit * IUnit::m_self = nullptr; const QPointF NOPOINTF(NOFLOAT, NOFLOAT); const QPoint NOPOINT (NOINT, NOINT); IUnit::tz_mode_e IUnit::timeZoneMode = IUnit::eTZUtc; IUnit::coord_format_e IUnit::coordFormat = IUnit::eCoordFormat1; QByteArray IUnit::timeZone = "UTC"; bool IUnit::useShortFormat = false; IUnit::slope_mode_e IUnit::slopeMode = IUnit::eSlopeDegrees; const char * IUnit::tblTimezone[] = { "Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", "Africa/Algiers", "Africa/Asmara", "Africa/Bamako", "Africa/Bangui", "Africa/Banjul", "Africa/Bissau", "Africa/Blantyre", "Africa/Brazzaville", "Africa/Bujumbura", "Africa/Cairo", "Africa/Casablanca", "Africa/Conakry", "Africa/Dakar", "Africa/Dar_es_Salaam", "Africa/Djibouti", "Africa/Douala", "Africa/El_Aaiun", "Africa/Freetown", "Africa/Gaborone", "Africa/Harare", "Africa/Johannesburg", "Africa/Kampala", "Africa/Khartoum", "Africa/Kigali", "Africa/Kinshasa", "Africa/Lagos", "Africa/Libreville", "Africa/Lome", "Africa/Luanda", "Africa/Lubumbashi", "Africa/Lusaka", "Africa/Malabo", "Africa/Maputo", "Africa/Maseru", "Africa/Mbabane", "Africa/Mogadishu", "Africa/Monrovia", "Africa/Nairobi", "Africa/Ndjamena", "Africa/Niamey", "Africa/Nouakchott", "Africa/Ouagadougou", "Africa/Porto-Novo", "Africa/Sao_Tome", "Africa/Tripoli", "Africa/Tunis", "Africa/Windhoek", "America/Adak", "America/Anguilla", "America/Antigua", "America/Araguaina", "America/Argentina/Buenos_Aires", "America/Argentina/Catamarca", "America/Argentina/Cordoba", "America/Argentina/Jujuy", "America/Argentina/La_Rioja", "America/Argentina/Mendoza", "America/Argentina/Rio_Gallegos", "America/Argentina/San_Juan", "America/Argentina/San_Luis", "America/Argentina/Tucuman", "America/Argentina/Ushuaia", "America/Aruba", "America/Asuncion", "America/Atikokan", "America/Bahia", "America/Barbados", "America/Belem", "America/Belize", "America/Blanc-Sablon", "America/Boa_Vista", "America/Bogota", "America/Boise", "America/Cambridge_Bay", "America/Campo_Grande", "America/Cancun", "America/Caracas", "America/Cayenne", "America/Cayman", "America/Chicago", "America/Chihuahua", "America/Coral_Harbour", "America/Costa_Rica", "America/Cuiaba", "America/Curacao", "America/Dawson", "America/Dawson_Creek", "America/Denver", "America/Dominica", "America/Edmonton", "America/Eirunepe", "America/El_Salvador", "America/Fortaleza", "America/Glace_Bay", "America/Goose_Bay", "America/Grand_Turk", "America/Grenada", "America/Guadeloupe", "America/Guatemala", "America/Guayaquil", "America/Guyana", "America/Halifax", "America/Havana", "America/Hermosillo", "America/Indiana/Indianapolis", "America/Indiana/Knox", "America/Indiana/Marengo", "America/Indiana/Petersburg", "America/Indiana/Vevay", "America/Indiana/Vincennes", "America/Indiana/Winamac", "America/Inuvik", "America/Iqaluit", "America/Jamaica", "America/Juneau", "America/Kentucky/Louisville", "America/Kentucky/Monticello", "America/La_Paz", "America/Lima", "America/Los_Angeles", "America/Maceio", "America/Managua", "America/Manaus", "America/Marigot", "America/Martinique", "America/Mazatlan", "America/Menominee", "America/Merida", "America/Mexico_City", "America/Miquelon", "America/Moncton", "America/Monterrey", "America/Montevideo", "America/Montreal", "America/Montserrat", "America/Nassau", "America/New_York", "America/Nipigon", "America/Noronha", "America/North_Dakota/Center", "America/North_Dakota/Salem", "America/Panama", "America/Pangnirtung", "America/Paramaribo", "America/Phoenix", "America/Port-au-Prince", "America/Port_of_Spain", "America/Porto_Velho", "America/Puerto_Rico", "America/Rainy_River", "America/Rankin_Inlet", "America/Recife", "America/Regina", "America/Resolute", "America/Rio_Branco", "America/Santarem", "America/Santiago", "America/Santo_Domingo", "America/Sao_Paulo", "America/St_Barthelemy", "America/St_Johns", "America/St_Kitts", "America/St_Lucia", "America/St_Thomas", "America/St_Vincent", "America/Tegucigalpa", "America/Thunder_Bay", "America/Tijuana", "America/Toronto", "America/Tortola", "America/Vancouver", "America/Whitehorse", "America/Winnipeg", "America/Yellowknife", "Ameriica/Swift_Current", "Arctic/Longyearbyen", "Asia/Aden", "Asia/Almaty", "Asia/Amman", "Asia/Anadyr", "Asia/Aqtau", "Asia/Aqtobe", "Asia/Ashgabat", "Asia/Baghdad", "Asia/Bahrain", "Asia/Baku", "Asia/Bangkok", "Asia/Beirut", "Asia/Bishkek", "Asia/Brunei", "Asia/Choibalsan", "Asia/Chongqing", "Asia/Colombo", "Asia/Damascus", "Asia/Dhaka", "Asia/Dili", "Asia/Dubai", "Asia/Dushanbe", "Asia/Gaza", "Asia/Harbin", "Asia/Ho_Chi_Minh", "Asia/Hong_Kong", "Asia/Hovd", "Asia/Irkutsk", "Asia/Jakarta", "Asia/Jayapura", "Asia/Jerusalem", "Asia/Kabul", "Asia/Kamchatka", "Asia/Karachi", "Asia/Kashgar", "Asia/Katmandu", "Asia/Kolkata", "Asia/Krasnoyarsk", "Asia/Kuala_Lumpur", "Asia/Kuching", "Asia/Kuwait", "Asia/Macau", "Asia/Magadan", "Asia/Makassar", "Asia/Manila", "Asia/Muscat", "Asia/Nicosia", "Asia/Novosibirsk", "Asia/Omsk", "Asia/Oral", "Asia/Phnom_Penh", "Asia/Pontianak", "Asia/Pyongyang", "Asia/Qatar", "Asia/Qyzylorda", "Asia/Rangoon", "Asia/Riyadh", "Asia/Sakhalin", "Asia/Samarkand", "Asia/Seoul", "Asia/Shanghai", "Asia/Singapore", "Asia/Taipei", "Asia/Tashkent", "Asia/Tbilisi", "Asia/Tehran", "Asia/Thimphu", "Asia/Tokyo", "Asia/Ulaanbaatar", "Asia/Urumqi", "Asia/Vientiane", "Asia/Vladivostok", "Asia/Yakutsk", "Asia/Yekaterinburg", "Asia/Yerevan", "Atlantic/Azores", "Atlantic/Bermuda", "Atlantic/Canary", "Atlantic/Cape_Verde", "Atlantic/Faroe", "Atlantic/Madeira", "Atlantic/Reykjavik", "Atlantic/South_Georgia", "Atlantic/St_Helena", "Atlantic/Stanley", "Australia/Adelaide", "Australia/Brisbane", "Australia/Broken_Hill", "Australia/Currie", "Australia/Darwin", "Australia/Eucla", "Australia/Hobart", "Australia/Lindeman", "Australia/Lord_Howe", "Australia/Melbourne", "Australia/Perth", "Australia/Sydney", "Europe/Amsterdam", "Europe/Andorra", "Europe/Athens", "Europe/Belgrade", "Europe/Berlin", "Europe/Bratislava", "Europe/Brussels", "Europe/Bucharest", "Europe/Budapest", "Europe/Chisinau", "Europe/Copenhagen", "Europe/Dublin", "Europe/Gibraltar", "Europe/Guernsey", "Europe/Helsinki", "Europe/Isle_of_Man", "Europe/Istanbul", "Europe/Jersey", "Europe/Kaliningrad", "Europe/Kiev", "Europe/Lisbon", "Europe/Ljubljana", "Europe/London", "Europe/Luxembourg", "Europe/Madrid", "Europe/Malta", "Europe/Marienhamn", "Europe/Minsk", "Europe/Monaco", "Europe/Moscow", "Europe/Oslo", "Europe/Paris", "Europe/Podgorica", "Europe/Prague", "Europe/Riga", "Europe/Rome", "Europe/Samara", "Europe/San_Marino", "Europe/Sarajevo", "Europe/Simferopol", "Europe/Skopje", "Europe/Sofia", "Europe/Stockholm", "Europe/Tallinn", "Europe/Tirane", "Europe/Uzhgorod", "Europe/Vaduz", "Europe/Vatican", "Europe/Vienna", "Europe/Vilnius", "Europe/Volgograd", "Europe/Warsaw", "Europe/Zagreb", "Europe/Zaporozhye", "Europe/Zurich", "Indian/Antananarivo", "Indian/Chagos", "Indian/Christmas", "Indian/Cocos", "Indian/Comoro", "Indian/Kerguelen", "Indian/Mahe", "Indian/Maldives", "Indian/Mauritius", "Indian/Mayotte", "Indian/Reunion", "Pacific/Apia", "Pacific/Auckland", "Pacific/Chatham", "Pacific/Easter", "Pacific/Efate", "Pacific/Enderbury", "Pacific/Fakaofo", "Pacific/Fiji", "Pacific/Funafuti", "Pacific/Galapagos", "Pacific/Gambier", "Pacific/Guadalcanal", "Pacific/Guam", "Pacific/Honolulu", "Pacific/Johnston", "Pacific/Kiritimati", "Pacific/Kosrae", "Pacific/Kwajalein", "Pacific/Majuro", "Pacific/Marquesas", "Pacific/Midway", "Pacific/Nauru", "Pacific/Niue", "Pacific/Norfolk", "Pacific/Noumea", "Pacific/Pago_Pago", "Pacific/Palau", "Pacific/Pitcairn", "Pacific/Ponape", "Pacific/Port_Moresby", "Pacific/Rarotonga", "Pacific/Saipan", "Pacific/Tahiti", "Pacific/Tarawa", "Pacific/Tongatapu", "Pacific/Truk", "Pacific/Wake", "Pacific/Wallis", 0 }; const int N_TIMEZONES = sizeof(IUnit::tblTimezone)/sizeof(const char*); const QRegExp IUnit::reCoord1("^\\s*([N|S]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s+([E|W|O]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s*$"); const QRegExp IUnit::reCoord2("^\\s*([N|S]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s+([E|W|O]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s*$"); const QRegExp IUnit::reCoord3("^\\s*([-0-9]+\\.[0-9]+)\\s+([-0-9]+\\.[0-9]+)\\s*$"); const QRegExp IUnit::reCoord4("^\\s*([N|S]){1}\\s*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*([E|W|O]){1}\\W*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*\\s*$"); const QRegExp IUnit::reCoord5("^\\s*([-0-9]+\\.[0-9]+)([N|S])\\s+([-0-9]+\\.[0-9]+)([W|E])\\s*$"); IUnit::IUnit(const type_e &type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject * parent) : QObject(parent) , type(type) , baseunit(baseunit) , basefactor(basefactor) , speedunit(speedunit) , speedfactor(speedfactor) { //there can be only one... delete m_self; m_self = this; } void IUnit::slope2string(qreal slope, QString &val, QString &unit) { switch(slopeMode) { case eSlopeDegrees: val.sprintf("%.1f", slope); unit = "°"; break; case eSlopePercent: val.sprintf("%.0f", qTan(qDegreesToRadians(slope))*100.0); unit = "%"; break; } } void IUnit::slope2unit(qreal slope, qreal &val, QString &unit) { switch(slopeMode) { case eSlopeDegrees: val = slope; unit = "°"; break; case eSlopePercent: val = qTan(qDegreesToRadians(slope))*100.0; unit = "%"; break; } } void IUnit::setUnitType(type_e t, QObject * parent) { switch(t) { case eTypeMetric: new CUnitMetric(parent); break; case eTypeImperial: new CUnitImperial(parent); break; case eTypeNautic: new CUnitNautic(parent); break; } QSettings cfg; cfg.setValue("Units/type",t); } void IUnit::meter2speed(qreal meter, QString& val, QString& unit) const { val.sprintf("%2.2f",meter * speedfactor); unit = speedunit; } void IUnit::seconds2time(quint32 ttime, QString& val, QString& unit) const { QTime time(0,0,0); quint32 days = ttime / 86400; time = time.addSecs(ttime); if(days) { val = QString("%1:").arg(days) + time.toString("HH:mm:ss"); unit = "d"; } else { val = time.toString("HH:mm:ss"); unit = "h"; } } bool IUnit::parseTimestamp(const QString &time, QDateTime &datetime) { int tzoffset; datetime = parseTimestamp(time, tzoffset); return datetime.isValid(); } QDateTime IUnit::parseTimestamp(const QString &timetext, int& tzoffset) { const QRegExp tzRE("[-+]\\d\\d:\\d\\d$"); int i; tzoffset = 0; bool applyTzOffset = false; QString format = "yyyy-MM-dd'T'hh:mm:ss"; i = timetext.indexOf("."); if (i != NOIDX) { if(timetext[i+1] == '0') { format += ".zzz"; } else { format += ".z"; } } // trailing "Z" explicitly declares the timestamp to be UTC if (timetext.indexOf("Z") != NOIDX) { format += "'Z'"; applyTzOffset = true; } else if ((i = tzRE.indexIn(timetext)) != NOIDX) { // trailing timezone offset [-+]HH:MM present // This does not match the original intentions of the GPX // file format but appears to be found occasionally in // the wild. Try our best parsing it. // add the literal string to the format so fromString() // will succeed format += "'"; format += timetext.right(6); format += "'"; // calculate the offset int offsetHours(timetext.mid(i + 1, 2).toUInt()); int offsetMinutes(timetext.mid(i + 4, 2).toUInt()); if (timetext[i] == '-') { tzoffset = -(60 * offsetHours + offsetMinutes); } else { tzoffset = 60 * offsetHours + offsetMinutes; } tzoffset *= 60; // seconds applyTzOffset = true; } QDateTime datetime = QDateTime::fromString(timetext, format); if (applyTzOffset) { datetime.setOffsetFromUtc(tzoffset); } else { // if timetext has no 'Z' and no [-+]HH:MM then this is local time then simply switch to UTC without applying any offset datetime = datetime.toUTC(); } return datetime; } QString IUnit::datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos) { QTimeZone tz; tz_mode_e tmpMode = (pos != NOPOINTF) ? timeZoneMode : eTZLocal; switch(tmpMode) { case eTZUtc: tz = QTimeZone("UTC"); break; case eTZLocal: tz = QTimeZone(QTimeZone::systemTimeZoneId()); break; case eTZAuto: tz = QTimeZone(pos2timezone(pos)); break; case eTZSelected: tz = QTimeZone(timeZone); break; } QDateTime tmp = time.toTimeZone(tz); return tmp.toString((shortDate|useShortFormat) ? Qt::ISODate : Qt::SystemLocaleLongDate); } QByteArray IUnit::pos2timezone(const QPointF& pos) { static QImage imgTimezone = QPixmap(":/pics/timezones.png").toImage(); int x = qRound(2048.0 / 360.0 * (180.0 + pos.x() * RAD_TO_DEG)); int y = qRound(1024.0 / 180.0 * (90.0 - pos.y() * RAD_TO_DEG)); QRgb rgb = imgTimezone.pixel(x,y); if(qRed(rgb) == 0 && qGreen(rgb) == 0) { return "UTC"; } int tz = ((qRed(rgb) & 248) << 1) + ((qGreen(rgb) >> 4) & 15); if(tz >= N_TIMEZONES) { return 0; } return tblTimezone[tz]; } void IUnit::degToStr(const qreal& x, const qreal& y, QString& str) { switch(coordFormat) { case eCoordFormat1: { qint32 degN,degE; qreal minN,minE; bool signLat = GPS_Math_Deg_To_DegMin(y, °N, &minN); bool signLon = GPS_Math_Deg_To_DegMin(x, °E, &minE); const QString &lat = signLat ? "S" : "N"; const QString &lng = signLon ? "W" : "E"; str.sprintf("%s%02d° %06.3f %s%03d° %06.3f",lat.toUtf8().data(),qAbs(degN),minN,lng.toUtf8().data(),qAbs(degE),minE); break; } case eCoordFormat2: { const QString &lat = (y < 0) ? "S" : "N"; const QString &lng = (x < 0) ? "W" : "E"; str.sprintf("%s%02.6f° %s%03.6f°",lat.toUtf8().data(),qAbs(y),lng.toUtf8().data(),qAbs(x)); break; } case eCoordFormat3: { qint32 degN,degE; qreal minN,minE; bool signLat = GPS_Math_Deg_To_DegMin(y, °N, &minN); bool signLon = GPS_Math_Deg_To_DegMin(x, °E, &minE); qreal secN = (minN - qFloor(minN)) * 60; qreal secE = (minE - qFloor(minE)) * 60; const QString &lat = signLat ? "S" : "N"; const QString &lng = signLon ? "W" : "E"; str.sprintf("%s%02d° %02d' %02.2f'' %s%03d° %02d' %02.2f''",lat.toUtf8().data(),qAbs(degN),qFloor(minN),secN,lng.toUtf8().data(),qAbs(degE),qFloor(minE),secE); break; } } } bool IUnit::strToDeg(const QString& str, qreal& lon, qreal& lat) { if(reCoord2.exactMatch(str)) { bool signLat = reCoord2.cap(1) == "S"; qreal absLat = reCoord2.cap(2).toDouble(); lat = signLat ? -absLat : absLat; bool signLon = reCoord2.cap(3) == "W"; qreal absLon = reCoord2.cap(4).toDouble(); lon = signLon ? -absLon : absLon; } else if(reCoord1.exactMatch(str)) { bool signLat = reCoord1.cap(1) == "S"; int degLat = reCoord1.cap(2).toInt(); qreal minLat = reCoord1.cap(3).toDouble(); GPS_Math_DegMin_To_Deg(signLat, degLat, minLat, lat); bool signLon = reCoord1.cap(4) == "W"; int degLon = reCoord1.cap(5).toInt(); qreal minLon = reCoord1.cap(6).toDouble(); GPS_Math_DegMin_To_Deg(signLon, degLon, minLon, lon); } else if(reCoord3.exactMatch(str)) { lat = reCoord3.cap(1).toDouble(); lon = reCoord3.cap(2).toDouble(); } else if(reCoord4.exactMatch(str)) { bool signLat = reCoord4.cap(1) == "S"; int degLat = reCoord4.cap(2).toInt(); int minLat = reCoord4.cap(3).toInt(); qreal secLat = reCoord4.cap(4).toFloat(); GPS_Math_DegMinSec_To_Deg(signLat, degLat, minLat, secLat, lat); bool signLon = reCoord4.cap(5) == "W"; int degLon = reCoord4.cap(6).toInt(); int minLon = reCoord4.cap(7).toInt(); qreal secLon = reCoord4.cap(8).toFloat(); GPS_Math_DegMinSec_To_Deg(signLon, degLon, minLon, secLon, lon); } else if(reCoord5.exactMatch(str)) { bool signLon = reCoord4.cap(4) == "W"; bool signLat = reCoord4.cap(2) == "S"; lat = reCoord5.cap(1).toDouble(); lon = reCoord5.cap(3).toDouble(); if(signLon) { lon = -lon; } if(signLat) { lat = -lat; } } else { QMessageBox::warning(CMainWindow::getBestWidgetForParent(),tr("Error"),tr("Bad position format. Must be: \"[N|S] ddd mm.sss [W|E] ddd mm.sss\" or \"[N|S] ddd.ddd [W|E] ddd.ddd\""),QMessageBox::Ok,QMessageBox::NoButton); return false; } if(fabs(lon) > 180.0 || fabs(lat) > 90.0) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(),tr("Error"),tr("Position values out of bounds. "),QMessageBox::Ok,QMessageBox::NoButton); return false; } return true; } bool IUnit::isValidCoordString(const QString& str) { if(reCoord1.exactMatch(str)) { return true; } else if(reCoord2.exactMatch(str)) { return true; } else if(reCoord3.exactMatch(str)) { return true; } else if(reCoord4.exactMatch(str)) { return true; } else if(reCoord5.exactMatch(str)) { return true; } return false; } qmapshack-1.10.0/src/units/CTimeZoneSetup.cpp000644 001750 000144 00000005036 13216234137 022243 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "units/CTimeZoneSetup.h" #include "units/IUnit.h" CTimeZoneSetup::CTimeZoneSetup(QWidget *parent) : QDialog(parent) { setupUi(this); QByteArray zone; IUnit::tz_mode_e mode; bool useShortFormat; IUnit::getTimeZoneSetup(mode, zone, useShortFormat); switch(mode) { case IUnit::eTZUtc: radioUtc->setChecked(true); break; case IUnit::eTZLocal: radioLocal->setChecked(true); break; case IUnit::eTZAuto: radioAutomatic->setChecked(true); break; case IUnit::eTZSelected: radioSelected->setChecked(true); break; } const char ** tz = IUnit::tblTimezone; while(*tz) { comboTimeZone->addItem(*tz); tz++; } if(useShortFormat) { radioShortFormat->setChecked(true); } else { radioLongFormat->setChecked(true); } comboTimeZone->setCurrentIndex(comboTimeZone->findText(QString(zone))); } CTimeZoneSetup::~CTimeZoneSetup() { } void CTimeZoneSetup::accept() { QByteArray zone = comboTimeZone->currentText().toLatin1(); IUnit::tz_mode_e mode = IUnit::eTZUtc; bool useShortFormat = false; if(radioUtc->isChecked()) { mode = IUnit::eTZUtc; } else if(radioLocal->isChecked()) { mode = IUnit::eTZLocal; } else if(radioAutomatic->isChecked()) { mode = IUnit::eTZAuto; } else if(radioSelected->isChecked()) { mode = IUnit::eTZSelected; } if(radioShortFormat->isChecked()) { useShortFormat = true; } IUnit::setTimeZoneSetup(mode, zone, useShortFormat); QDialog::accept(); } qmapshack-1.10.0/src/units/CCoordFormatSetup.h000644 001750 000144 00000002366 13216234142 022374 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCOORDFORMATSETUP_H #define CCOORDFORMATSETUP_H #include "ui_ICoordFormatSetup.h" #include class CCoordFormatSetup : public QDialog, private Ui::ICoordFormatSetup { Q_OBJECT public: CCoordFormatSetup(QWidget * parent); virtual ~CCoordFormatSetup(); public slots: void accept() override; }; #endif //CCOORDFORMATSETUP_H qmapshack-1.10.0/src/units/CUnitsSetup.h000644 001750 000144 00000002275 13216234142 021256 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CUNITSSETUP_H #define CUNITSSETUP_H #include "ui_IUnitsSetup.h" #include class CUnitsSetup : public QDialog, private Ui::IUnitsSetup { public: CUnitsSetup(QWidget * parent); virtual ~CUnitsSetup() = default; public slots: void accept() override; }; #endif //CUNITSSETUP_H qmapshack-1.10.0/src/units/ITimeZoneSetup.ui000644 001750 000144 00000012275 13175553424 022116 0ustar00oeichlerxusers000000 000000 ITimeZoneSetup 0 0 398 176 Setup Time Zone ... UTC buttonGroup Local buttonGroup Automatic buttonGroup 0 0 buttonGroup Print date/time in long format, or buttonGroup_2 short format buttonGroup_2 Qt::Horizontal 40 20 0 0 <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ITimeZoneSetup accept() 248 254 157 274 buttonBox rejected() ITimeZoneSetup reject() 316 260 286 274 qmapshack-1.10.0/src/units/CUnitNautic.cpp000644 001750 000144 00000004572 13216234137 021557 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #include "units/CUnitNautic.h" CUnitNautic::CUnitNautic(QObject * parent) : IUnit(eTypeNautic, "nm", 0.00053989, "nm/h", 1.94361780, parent) { } void CUnitNautic::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.0f", meter); unit = "m"; } } void CUnitNautic::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.2f", meter * basefactor); unit = baseunit; } } void CUnitNautic::meter2speed(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.2f",meter * speedfactor); unit = speedunit; } } void CUnitNautic::meter2area(qreal meter, QString& val, QString& unit) const /* override */ { if(meter == NOFLOAT) { val = "-"; unit = ""; } else { val.sprintf("%1.2f", meter / (1852 * 1852)); unit = "nm²"; } } qreal CUnitNautic::elevation2meter(const QString& val) const /* override */ { return val.toDouble(); } void CUnitNautic::meter2unit(qreal meter, qreal& scale, QString& unit) const { scale = basefactor; unit = "nm"; } qmapshack-1.10.0/src/units/CUnitNautic.h000644 001750 000144 00000003147 13216234142 021215 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #ifndef CUNITNAUTIC_H #define CUNITNAUTIC_H #include "IUnit.h" class CUnitNautic : public IUnit { public: CUnitNautic(QObject * parent); virtual ~CUnitNautic() = default; void meter2elevation(qreal meter, QString& val, QString& unit) const override; void meter2distance(qreal meter, QString& val, QString& unit) const override; void meter2speed(qreal meter, QString& val, QString& unit) const override; void meter2area(qreal meter, QString& val, QString& unit) const override; qreal elevation2meter(const QString& val) const override; void meter2unit(qreal meter, qreal& scale, QString& unit) const override; }; #endif //CUNITNAUTIC_H qmapshack-1.10.0/src/units/IUnit.h000644 001750 000144 00000012401 13216234142 020050 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #ifndef IUNIT_H #define IUNIT_H #include #include #define NOFLOAT 1000000000000.0 #define NOINT 0x7FFFFFFF #define NOTIME 0xFFFFFFFF #define NOIDX (-1) extern const QPointF NOPOINTF; extern const QPoint NOPOINT; class IUnit : public QObject { Q_OBJECT public: virtual ~IUnit() = default; static const IUnit& self() { return *m_self; } /// convert meter of elevation into a value and unit string virtual void meter2elevation(qreal meter, QString& val, QString& unit) const = 0; /// convert meter of distance into a value and unit string virtual void meter2distance(qreal meter, QString& val, QString& unit) const = 0; /// convert meter per second to a speed value string and unit label virtual void meter2speed(qreal meter, QString& val, QString& unit) const; /// convert square meter to string and unit label virtual void meter2area(qreal meter, QString& val, QString& unit) const = 0; /// convert seconds to a timespan of days, hours, minutes and seconds virtual void seconds2time(quint32 ttime, QString& val, QString& unit) const; /// convert an elevation string to a float virtual qreal elevation2meter(const QString& val) const = 0; /// convert a range in meter into a scale and a matching unit virtual void meter2unit(qreal meter, qreal& scale, QString& unit) const = 0; enum type_e {eTypeMetric, eTypeImperial, eTypeNautic}; /// instantiate the correct unit object static void setUnitType(type_e t, QObject * parent); enum slope_mode_e {eSlopePercent, eSlopeDegrees}; static void setSlopeMode(slope_mode_e mode) { slopeMode = mode; } static enum slope_mode_e getSlopeMode() { return slopeMode; } static void slope2string(qreal slope, QString& val, QString& unit); static void slope2unit(qreal slope, qreal& val, QString& unit); /// parse a string for a timestamp static bool parseTimestamp(const QString &time, QDateTime &datetime); /** @brief Convert date time object to string using the current timezone configuration @param time the date/time object @param shortDate set true to get a short ISO time string @param pos optional a position attached to the date/time object [rad] @return A time string. */ static QString datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos = NOPOINTF); /// find the timezone setup by position static QByteArray pos2timezone(const QPointF& pos); const type_e type; const QString baseunit; const qreal basefactor; const QString speedunit; const qreal speedfactor; static const char *tblTimezone[]; enum tz_mode_e { eTZUtc ,eTZLocal ,eTZAuto ,eTZSelected }; static void getTimeZoneSetup(tz_mode_e& mode, QByteArray& zone, bool& format) { mode = timeZoneMode; zone = timeZone; format = useShortFormat; } static void setTimeZoneSetup(tz_mode_e mode, const QByteArray& zone, bool format) { timeZoneMode = mode; timeZone = zone; useShortFormat = format; } enum coord_format_e { eCoordFormat1 ,eCoordFormat2 ,eCoordFormat3 }; static enum coord_format_e getCoordFormat() { return coordFormat; } static void setCoordFormat(const coord_format_e format) { coordFormat = format; } static void degToStr(const qreal& x, const qreal& y, QString& str); static bool strToDeg(const QString& str, qreal& lon, qreal& lat); static bool isValidCoordString(const QString& str); protected: IUnit(const type_e& type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject *parent); static slope_mode_e slopeMode; static QDateTime parseTimestamp(const QString &timetext, int& tzoffset); static tz_mode_e timeZoneMode; static QByteArray timeZone; static bool useShortFormat; static coord_format_e coordFormat; private: static const IUnit * m_self; static const QRegExp reCoord1; static const QRegExp reCoord2; static const QRegExp reCoord3; static const QRegExp reCoord4; static const QRegExp reCoord5; }; #endif //IUNIT_H qmapshack-1.10.0/src/units/ICoordFormatSetup.ui000644 001750 000144 00000004623 12611356106 022571 0ustar00oeichlerxusers000000 000000 ICoordFormatSetup 0 0 287 126 Coordinate Format... N48° 53' 39.6" E13° 31' 6.78" N48.8943° E013.51855° N48° 53.660 E013° 31.113 Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ICoordFormatSetup accept() 248 254 157 274 buttonBox rejected() ICoordFormatSetup reject() 316 260 286 274 qmapshack-1.10.0/src/units/CTimeZoneSetup.h000644 001750 000144 00000002314 13216234142 021700 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CTIMEZONESETUP_H #define CTIMEZONESETUP_H #include "ui_ITimeZoneSetup.h" #include class CTimeZoneSetup : public QDialog, private Ui::ITimeZoneSetup { public: CTimeZoneSetup(QWidget * parent); virtual ~CTimeZoneSetup(); public slots: void accept() override; }; #endif //CTIMEZONESETUP_H qmapshack-1.10.0/src/units/CCoordFormatSetup.cpp000644 001750 000144 00000003607 13216234137 022732 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "units/CCoordFormatSetup.h" #include "units/IUnit.h" CCoordFormatSetup::CCoordFormatSetup(QWidget * parent) : QDialog(parent) { setupUi(this); IUnit::coord_format_e coordFormat = IUnit::getCoordFormat(); switch(coordFormat) { case IUnit::eCoordFormat1: radioFormat1->setChecked(true); break; case IUnit::eCoordFormat2: radioFormat2->setChecked(true); break; case IUnit::eCoordFormat3: radioFormat3->setChecked(true); break; } } CCoordFormatSetup::~CCoordFormatSetup() { } void CCoordFormatSetup::accept() { IUnit::coord_format_e coordFormat = IUnit::eCoordFormat1; if(radioFormat1->isChecked()) { coordFormat = IUnit::eCoordFormat1; } else if(radioFormat2->isChecked()) { coordFormat = IUnit::eCoordFormat2; } else if(radioFormat3->isChecked()) { coordFormat = IUnit::eCoordFormat3; } IUnit::setCoordFormat(coordFormat); QDialog::accept(); } qmapshack-1.10.0/src/units/CUnitImperial.h000644 001750 000144 00000003251 13216234142 021530 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA **********************************************************************************************/ #ifndef CUNITIMPERIAL_H #define CUNITIMPERIAL_H #include "IUnit.h" class CUnitImperial : public IUnit { public: CUnitImperial(QObject * parent); virtual ~CUnitImperial() = default; void meter2elevation(qreal meter, QString& val, QString& unit) const override; void meter2distance(qreal meter, QString& val, QString& unit) const override; void meter2area(qreal meter, QString& val, QString& unit) const override; qreal elevation2meter(const QString& val) const override; void meter2unit(qreal meter, qreal& scale, QString& unit) const override; private: static const qreal footPerMeter; static const qreal milePerMeter; static const qreal meterPerSecToMilePerHour; }; #endif //CUNITIMPERIAL_H qmapshack-1.10.0/src/dem/000755 001750 000144 00000000000 13216664443 016267 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/dem/CDemVRT.h000644 001750 000144 00000003131 13216234142 017627 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMVRT_H #define CDEMVRT_H #include "dem/IDem.h" #include class CDemDraw; class GDALDataset; class CDemVRT : public IDem { Q_OBJECT public: CDemVRT(const QString& filename, CDemDraw *parent); virtual ~CDemVRT(); void draw(IDrawContext::buffer_t& buf) override; qreal getElevationAt(const QPointF& pos) override; qreal getSlopeAt(const QPointF& pos) override; private: QMutex mutex; QString filename; /// instance of GDAL dataset GDALDataset * dataset; QPointF ref1; QPointF ref2; QPointF ref3; QPointF ref4; QTransform trFwd; QTransform trInv; bool hasOverviews = false; QRectF boundingBox; }; #endif //CDEMVRT_H qmapshack-1.10.0/src/dem/CDemList.cpp000644 001750 000144 00000013431 13216234137 020432 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "dem/CDemDraw.h" #include "dem/CDemItem.h" #include "dem/CDemList.h" #include "units/IUnit.h" #include void CDemTreeWidget::dragMoveEvent( QDragMoveEvent * event ) { CDemItem * item = dynamic_cast(itemAt(event->pos())); if(item && item->isActivated()) { event->setDropAction(Qt::MoveAction); QTreeWidget::dragMoveEvent(event); } else { event->setDropAction(Qt::IgnoreAction); } } void CDemTreeWidget::dropEvent( QDropEvent * event ) { CDemItem * item = dynamic_cast(currentItem()); if(item) { item->showChildren(false); } QTreeWidget::dropEvent(event); if(item) { item->showChildren(true); } emit sigChanged(); } CDemList::CDemList(QWidget *parent) : QWidget(parent) { setupUi(this); connect(treeWidget, &CDemTreeWidget::customContextMenuRequested, this, &CDemList::slotContextMenu); connect(actionMoveUp, &QAction::triggered, this, &CDemList::slotMoveUp); connect(actionMoveDown, &QAction::triggered, this, &CDemList::slotMoveDown); connect(actionActivate, &QAction::triggered, this, &CDemList::slotActivate); connect(actionReloadDem, &QAction::triggered, this, &CDemList::slotReloadDem); connect(treeWidget, &CDemTreeWidget::sigChanged, this, &CDemList::sigChanged); connect(labelHelpFillMapList, &QLabel::linkActivated, this, &CDemList::slotLinkActivated); menu = new QMenu(this); menu->addAction(actionActivate); menu->addAction(actionMoveUp); menu->addAction(actionMoveDown); menu->addSeparator(); menu->addAction(actionReloadDem); menu->addAction(CMainWindow::self().getDemSetupAction()); } CDemList::~CDemList() { } void CDemList::clear() { treeWidget->clear(); } int CDemList::count() { return treeWidget->topLevelItemCount(); } CDemItem * CDemList::item(int i) { return dynamic_cast(treeWidget->topLevelItem(i)); } void CDemList::updateHelpText() { if(treeWidget->topLevelItemCount() == 0) { labelIcon->show(); labelHelpFillMapList->show(); labelHelpActivateMap->hide(); } else { labelHelpFillMapList->hide(); CDemItem * item = dynamic_cast(treeWidget->topLevelItem(0)); bool haveActive = item && item->isActivated(); labelIcon->setVisible(!haveActive); labelHelpActivateMap->setVisible(!haveActive); } } void CDemList::slotActivate() { CDemItem * item = dynamic_cast(treeWidget->currentItem()); if(nullptr == item) { return; } bool activated = item->toggleActivate(); if(!activated) { treeWidget->setCurrentItem(0); } updateHelpText(); } void CDemList::slotMoveUp() { CDemItem * item = dynamic_cast(treeWidget->currentItem()); if(item == nullptr) { return; } int index = treeWidget->indexOfTopLevelItem(item); if(index == NOIDX) { return; } item->showChildren(false); treeWidget->takeTopLevelItem(index); treeWidget->insertTopLevelItem(index-1, item); item->showChildren(true); treeWidget->setCurrentItem(0); emit treeWidget->sigChanged(); } void CDemList::slotMoveDown() { CDemItem * item = dynamic_cast(treeWidget->currentItem()); if(item == nullptr) { return; } int index = treeWidget->indexOfTopLevelItem(item); if(index == NOIDX) { return; } item->showChildren(false); treeWidget->takeTopLevelItem(index); treeWidget->insertTopLevelItem(index+1, item); item->showChildren(true); treeWidget->setCurrentItem(0); emit treeWidget->sigChanged(); } void CDemList::slotContextMenu(const QPoint& point) { CDemItem * item = dynamic_cast(treeWidget->currentItem()); bool itemIsSelected = nullptr != item; bool itemIsActivated = item ? item->isActivated() : false; actionActivate->setEnabled(itemIsSelected); actionMoveUp->setEnabled(itemIsSelected); actionMoveDown->setEnabled(itemIsSelected); actionActivate->setChecked(itemIsActivated); actionActivate->setText(itemIsActivated ? tr("Deactivate") : tr("Activate")); if(itemIsSelected) { CDemItem * item1 = dynamic_cast(treeWidget->itemBelow(item)); actionMoveUp->setEnabled(itemIsActivated && (treeWidget->itemAbove(item) != nullptr)); actionMoveDown->setEnabled(itemIsActivated && item1 && item1->isActivated()); } QPoint p = treeWidget->mapToGlobal(point); menu->exec(p); } void CDemList::slotReloadDem() { CDemDraw::setupDemPath(CDemDraw::getDemPaths()); } void CDemList::slotLinkActivated(const QString& link) { if(link == "setup") { emit sigSetupDemPath(); } } qmapshack-1.10.0/src/dem/CDemPathSetup.h000644 001750 000144 00000002533 13216234142 021076 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMPATHSETUP_H #define CDEMPATHSETUP_H #include "ui_IDemPathSetup.h" #include class CDemPathSetup : public QDialog, private Ui::IDemPathSetup { Q_OBJECT public: CDemPathSetup(QStringList& paths); virtual ~CDemPathSetup(); public slots: void accept() override; private slots: void slotAddPath(); void slotDelPath(); void slotItemSelectionChanged(); private: QStringList& paths; }; #endif //CDEMPATHSETUP_H qmapshack-1.10.0/src/dem/CDemVRT.cpp000644 001750 000144 00000025310 13216234137 020171 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "dem/CDemDraw.h" #include "dem/CDemVRT.h" #include "helpers/CDraw.h" #include "units/IUnit.h" #include #include #include #define TILELIMIT 30000 #define TILESIZEX 64 #define TILESIZEY 64 CDemVRT::CDemVRT(const QString &filename, CDemDraw *parent) : IDem(parent) , filename(filename) { qDebug() << "------------------------------"; qDebug() << "VRT: try to open" << filename; dataset = (GDALDataset*)GDALOpen(filename.toUtf8(),GA_ReadOnly); if(nullptr == dataset) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to load file: %1").arg(filename)); return; } if(dataset->GetRasterCount() != 1) { GDALClose(dataset); dataset = nullptr; QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("DEM must have one band with 16bit or 32bit data.")); return; } GDALRasterBand *pBand = dataset->GetRasterBand(1); if(nullptr == pBand) { GDALClose(dataset); dataset = nullptr; QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("DEM must have one band with 16bit or 32bit data.")); return; } hasOverviews = pBand->GetOverviewCount() != 0; qDebug() << "has overviews" << hasOverviews; noData = pBand->GetNoDataValue(&hasNoData); qDebug() << "no data:" << hasNoData << noData; // ------- setup projection --------------- char str[1025] = {0}; if(dataset->GetProjectionRef()) { strncpy(str, dataset->GetProjectionRef(), sizeof(str) - 1); } OGRSpatialReference oSRS; char *wkt = str; oSRS.importFromWkt(&wkt); char *proj4 = nullptr; oSRS.exportToProj4(&proj4); pjsrc = pj_init_plus(proj4); free(proj4); if(pjsrc == 0) { GDALClose(dataset); dataset = nullptr; QMessageBox::warning(0, tr("Error..."), tr("No georeference information found.")); return; } xsize_px = dataset->GetRasterXSize(); ysize_px = dataset->GetRasterYSize(); qreal adfGeoTransform[6]; dataset->GetGeoTransform( adfGeoTransform ); xscale = adfGeoTransform[1]; yscale = adfGeoTransform[5]; trFwd.translate(adfGeoTransform[0], adfGeoTransform[3]); trFwd.scale(adfGeoTransform[1],adfGeoTransform[5]); if(adfGeoTransform[4] != 0.0) { trFwd.rotate(qAtan(adfGeoTransform[2]/adfGeoTransform[4])); } if(pj_is_latlong(pjsrc)) { xscale *= 111120; yscale *= 111120; // convert to RAD to match internal notations trFwd = trFwd * DEG_TO_RAD; } trInv = trFwd.inverted(); ref1 = trFwd.map(QPointF(0,0)); ref2 = trFwd.map(QPointF(xsize_px,0)); ref3 = trFwd.map(QPointF(xsize_px,ysize_px)); ref4 = trFwd.map(QPointF(0,ysize_px)); qDebug() << ref1 << ref2 << ref3 << ref4; boundingBox = QRectF(ref1, ref3); qDebug() << "FF" << trFwd; qDebug() << "RR" << trInv; isActivated = true; } CDemVRT::~CDemVRT() { GDALClose(dataset); } qreal CDemVRT::getElevationAt(const QPointF& pos) { if(pjsrc == 0) { return NOFLOAT; } qint16 e[4]; QPointF pt = pos; pj_transform(pjtar, pjsrc, 1, 0, &pt.rx(), &pt.ry(), 0); if(!boundingBox.contains(pt)) { return NOFLOAT; } pt = trInv.map(pt); qreal x = pt.x() - qFloor(pt.x()); qreal y = pt.y() - qFloor(pt.y()); mutex.lock(); CPLErr err = dataset->RasterIO(GF_Read, qFloor(pt.x()), qFloor(pt.y()), 2, 2, &e, 2, 2, GDT_Int16, 1, 0, 0, 0, 0); mutex.unlock(); if(err == CE_Failure) { return NOFLOAT; } if(hasNoData && ((e[0] == noData)||(e[1] == noData)||(e[2] == noData)||(e[3] == noData))) { return NOFLOAT; } qreal b1 = e[0]; qreal b2 = e[1] - e[0]; qreal b3 = e[2] - e[0]; qreal b4 = e[0] - e[1] - e[2] + e[3]; qreal ele = b1 + b2 * x + b3 * y + b4 * x * y; return ele; } qreal CDemVRT::getSlopeAt(const QPointF& pos) { if(pjsrc == 0) { return NOFLOAT; } QPointF pt = pos; pj_transform(pjtar, pjsrc, 1, 0, &pt.rx(), &pt.ry(), 0); if(!boundingBox.contains(pt)) { return NOFLOAT; } pt = trInv.map(pt); qreal x = pt.x() - qFloor(pt.x()); qreal y = pt.y() - qFloor(pt.y()); qint16 win[eWinsize4x4]; mutex.lock(); CPLErr err = dataset->RasterIO(GF_Read, qFloor(pt.x())-1, qFloor(pt.y())-1, 4, 4, &win, 4, 4, GDT_Int16, 1, 0, 0, 0, 0); mutex.unlock(); if(err == CE_Failure) { return NOFLOAT; } for(int i=0; ineedsRedraw()) { return; } if(!doHillshading() && !doSlopeColor()) { QThread::msleep(100); return; } QPointF bufferScale = buf.scale * buf.zoomFactor; // get pixel offset of top left buffer corner QPointF pp = buf.ref1; dem->convertRad2Px(pp); // calculate area to read from file QPointF pt1 = buf.ref1; QPointF pt2 = buf.ref2; QPointF pt3 = buf.ref3; QPointF pt4 = buf.ref4; pj_transform(pjtar,pjsrc, 1, 0, &pt1.rx(), &pt1.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt2.rx(), &pt2.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt3.rx(), &pt3.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt4.rx(), &pt4.ry(), 0); pt1 = trInv.map(pt1); pt2 = trInv.map(pt2); pt3 = trInv.map(pt3); pt4 = trInv.map(pt4); qreal left, right, top, bottom; left = qRound(pt1.x() < pt4.x() ? pt1.x() : pt4.x()); right = qRound(pt2.x() > pt3.x() ? pt2.x() : pt3.x()); top = qRound(pt1.y() < pt2.y() ? pt1.y() : pt2.y()); bottom = qRound(pt4.y() > pt3.y() ? pt4.y() : pt3.y()); if(left <= 0) { left = 1; } if(left >= xsize_px) { left = xsize_px - 1; } if(top <= 0) { top = 1; } if(top >= ysize_px) { top = ysize_px - 1; } if(right >= xsize_px) { right = xsize_px - 1; } if(right <= 0) { right = 1; } if(bottom >= ysize_px) { bottom = ysize_px - 1; } if(bottom <= 0) { bottom = 1; } qreal imgw = TILESIZEX; qreal imgh = TILESIZEY; qreal w = imgw; qreal h = imgh; /* As the 3x3 window will create a border of one pixel more data is read than displayed to compensate. */ int wp2 = w + 2; int hp2 = h + 2; // start to draw the map QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.translate(-pp); qreal o1 = getOpacity()/100.0; qreal o2 = ((o1 + 0.4) >= 1.0) ? o1 : (o1 + 0.4); p.setOpacity(o1); qreal nTiles = ((right - left) * (bottom - top) / (w * h)); qDebug() << "DEM> tiles:" << nTiles; if(!isOutOfScale(bufferScale) && (nTiles < TILELIMIT)) { for(qreal y = top - 1; y < bottom; y += h) { if(dem->needsRedraw()) { break; } for(qreal x = left - 1; x < right; x += w) { if(dem->needsRedraw()) { break; } CPLErr err = CE_Failure; qreal wp2_used = wp2; qreal hp2_used = hp2; qreal w_used = w; qreal h_used = h; if((x + wp2) > xsize_px) { wp2_used = xsize_px - x; w_used = wp2_used - 2; if(w_used < 2) { continue; } } if((y + hp2) > ysize_px) { hp2_used = ysize_px - y; h_used = hp2_used - 2; if(h_used < 2) { continue; } } QVector data(wp2_used * hp2_used); mutex.lock(); err = dataset->RasterIO(GF_Read, x, y, wp2_used, hp2_used, data.data(), wp2_used, hp2_used, GDT_Int16, 1, 0, 0, 0, 0); mutex.unlock(); if(err) { continue; } QPolygonF l(4); l[0] = QPointF(x + 1, y + 1); l[1] = QPointF(x + 1 + w_used, y + 1); l[2] = QPointF(x + 1 + w_used, y + 1 + h_used); l[3] = QPointF(x + 1, y + 1 + h_used); l = trFwd.map(l); pj_transform(pjsrc,pjtar, 1, 0, &l[0].rx(), &l[0].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[1].rx(), &l[1].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[2].rx(), &l[2].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[3].rx(), &l[3].ry(), 0); if(doHillshading()) { QPolygonF r = l; QImage img(w_used,h_used,QImage::Format_Indexed8); img.setColorTable(graytable); hillshading(data, w_used, h_used, img); drawTile(img, r, p); } if(doSlopeColor()) { QPolygonF r = l; QImage img(w_used,h_used,QImage::Format_Indexed8); img.setColorTable(slopetable); slopecolor(data, w_used, h_used, img); p.setOpacity(o2); drawTile(img, r, p); p.setOpacity(o1); } } } } } qmapshack-1.10.0/src/dem/CDemDraw.cpp000644 001750 000144 00000022304 13216234137 020413 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "dem/CDemDraw.h" #include "dem/CDemItem.h" #include "dem/CDemList.h" #include "dem/CDemPathSetup.h" #include "dem/IDem.h" #include "gis/IGisLine.h" #include "helpers/CSettings.h" #include "units/IUnit.h" #include QList CDemDraw::dems; QStringList CDemDraw::demPaths; QStringList CDemDraw::supportedFormats = QString("*.vrt").split('|'); CDemDraw::CDemDraw(CCanvas *canvas) : IDrawContext("dem", CCanvas::eRedrawDem, canvas) { demList = new CDemList(canvas); CMainWindow::self().addDemList(demList, canvas->objectName()); connect(canvas, &CCanvas::destroyed, demList, &CDemList::deleteLater); connect(demList, &CDemList::sigChanged, this, &CDemDraw::emitSigCanvasUpdate); buildMapList(); dems << this; } CDemDraw::~CDemDraw() { dems.removeOne(this); } void CDemDraw::setProjection(const QString& proj) { // --- save the active maps QStringList keys; saveActiveMapsList(keys); // --- now set the new projection IDrawContext::setProjection(proj); // --- now build the map list from scratch. This will deactivate -> activate all maps // By that everything is restored with the new projection buildMapList(); restoreActiveMapsList(keys); } void CDemDraw::setupDemPath() { QStringList paths = demPaths; CDemPathSetup dlg(paths); if(dlg.exec() != QDialog::Accepted) { return; } setupDemPath(paths); } void CDemDraw::setupDemPath(const QStringList &paths) { demPaths = paths; for(CDemDraw * dem : dems) { QStringList keys; dem->saveActiveMapsList(keys); dem->buildMapList(); dem->restoreActiveMapsList(keys); } } void CDemDraw::saveDemPath(QSettings& cfg) { cfg.setValue("demPaths", demPaths); } void CDemDraw::loadDemPath(QSettings& cfg) { demPaths = cfg.value("demPaths", demPaths).toStringList(); } void CDemDraw::saveConfig(QSettings& cfg) { // store group context for later use cfgGroup = cfg.group(); // ------------------- QStringList keys; cfg.beginGroup("dem"); saveActiveMapsList(keys, cfg); cfg.setValue("active", keys); cfg.endGroup(); } void CDemDraw::loadConfig(QSettings& cfg) { // store group context for later use cfgGroup = cfg.group(); // ------------------- cfg.beginGroup("dem"); if(cfgGroup.isEmpty()) { restoreActiveMapsList(cfg.value("active", "").toStringList(), cfg); } else { restoreActiveMapsList(cfg.value("active", "").toStringList()); } cfg.endGroup(); } void CDemDraw::buildMapList() { QCryptographicHash md5(QCryptographicHash::Md5); QMutexLocker lock(&CDemItem::mutexActiveDems); demList->clear(); for(const QString &path : demPaths) { QDir dir(path); // find available maps for(const QString &filename : dir.entryList(supportedFormats, QDir::Files|QDir::Readable, QDir::Name)) { QFileInfo fi(filename); CDemItem * item = new CDemItem(*demList, this); item->setText(0,fi.completeBaseName().replace("_", " ")); item->filename = dir.absoluteFilePath(filename); item->updateIcon(); // calculate MD5 hash from the file's first 1024 bytes QFile f(dir.absoluteFilePath(filename)); f.open(QIODevice::ReadOnly); md5.reset(); md5.addData(f.read(1024)); item->key = md5.result().toHex(); f.close(); } } demList->updateHelpText(); } void CDemDraw::saveActiveMapsList(QStringList& keys) { SETTINGS; cfg.beginGroup(cfgGroup); cfg.beginGroup("dem"); saveActiveMapsList(keys, cfg); cfg.endGroup(); cfg.endGroup(); } void CDemDraw::saveActiveMapsList(QStringList& keys, QSettings& cfg) { QMutexLocker lock(&CDemItem::mutexActiveDems); for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(item && !item->demfile.isNull()) { item->saveConfig(cfg); keys << item->key; } } } void CDemDraw::loadConfigForDemItem(CDemItem * item) { if(cfgGroup.isEmpty()) { return; } SETTINGS; cfg.beginGroup(cfgGroup); cfg.beginGroup("dem"); item->loadConfig(cfg); cfg.endGroup(); cfg.endGroup(); } void CDemDraw::restoreActiveMapsList(const QStringList& keys) { QMutexLocker lock(&CDemItem::mutexActiveDems); for(const QString &key : keys) { for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(item && item->key == key) { /** @Note the item will load it's configuration upon successful activation by calling loadConfigForDemItem(). */ item->activate(); break; } } } demList->updateHelpText(); } void CDemDraw::restoreActiveMapsList(const QStringList& keys, QSettings& cfg) { QMutexLocker lock(&CDemItem::mutexActiveDems); for(const QString &key : keys) { for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(item && item->key == key) { if(item->activate()) { item->loadConfig(cfg); } break; } } } demList->updateHelpText(); } qreal CDemDraw::getElevationAt(const QPointF& pos) { qreal ele = NOFLOAT; if(CDemItem::mutexActiveDems.tryLock()) { if(demList) { for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(!item || item->demfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } ele = item->demfile->getElevationAt(pos); if(ele != NOFLOAT) { break; } } } CDemItem::mutexActiveDems.unlock(); } return ele; } qreal CDemDraw::getSlopeAt(const QPointF& pos) { qreal slope = NOFLOAT; if(CDemItem::mutexActiveDems.tryLock()) { if(demList) { for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(!item || item->demfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } slope = item->demfile->getSlopeAt(pos); if(slope != NOFLOAT) { break; } } } CDemItem::mutexActiveDems.unlock(); } return slope; } void CDemDraw::getElevationAt(const QPolygonF& pos, QPolygonF& ele) { qreal basefactor = IUnit::self().basefactor; for(int i = 0; i < pos.size(); i++) { qreal tmp = getElevationAt(pos[i]); ele[i].ry() = (tmp == NOFLOAT) ? NOFLOAT : tmp * basefactor; } } void CDemDraw::getSlopeAt(const QPolygonF& pos, QPolygonF& slope) { for(int i = 0; i < pos.size(); i++) { slope[i].ry() = getSlopeAt(pos[i]); } } void CDemDraw::getElevationAt(SGisLine& line) { line.updateElevation(this); } void CDemDraw::drawt(buffer_t& currentBuffer) { // iterate over all active maps and call the draw method CDemItem::mutexActiveDems.lock(); if(demList) { for(int i = 0; i < demList->count(); i++) { CDemItem * item = demList->item(i); if(!item || item->demfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } item->demfile->draw(currentBuffer); } } CDemItem::mutexActiveDems.unlock(); } qmapshack-1.10.0/src/dem/IDemProp.cpp000644 001750 000144 00000002250 13216234137 020442 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "dem/CDemDraw.h" #include "dem/IDem.h" #include "dem/IDemProp.h" IDemProp::IDemProp(IDem *demfile, CDemDraw *dem) : demfile(demfile) , dem(dem) { connect(demfile, &IDem::sigPropertiesChanged, this, &IDemProp::slotPropertiesChanged); } IDemProp::~IDemProp() { } qmapshack-1.10.0/src/dem/CDemList.h000644 001750 000144 00000003631 13216234142 020074 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMLIST_H #define CDEMLIST_H #include #include class CDemItem; class CDemTreeWidget : public QTreeWidget { Q_OBJECT public: CDemTreeWidget(QWidget * parent) : QTreeWidget(parent) { } signals: void sigChanged(); protected: void dragMoveEvent(QDragMoveEvent *event) override; void dropEvent(QDropEvent *event) override; }; #include "ui_IDemList.h" class CDemList : public QWidget, private Ui::IDemsList { Q_OBJECT public: CDemList(QWidget * parent); virtual ~CDemList(); void clear(); int count(); CDemItem * item(int i); operator QTreeWidget*() { return treeWidget; } void updateHelpText(); signals: void sigChanged(); void sigSetupDemPath(); private slots: void slotActivate(); void slotMoveUp(); void slotMoveDown(); void slotReloadDem(); void slotContextMenu(const QPoint &point); void slotLinkActivated(const QString& link); private: QMenu * menu; }; #endif //CDEMLIST_H qmapshack-1.10.0/src/dem/IDemPropSetup.ui000644 001750 000144 00000041261 12627613665 021337 0ustar00oeichlerxusers000000 000000 IDemPropSetup 0 0 400 163 Form 3 3 3 3 3 <html><head/><body><p>Change opacity of map</p></body></html> Qt::Horizontal 3 <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> ... :/icons/8x8/bullet_green.png :/icons/8x8/bullet_red.png:/icons/8x8/bullet_green.png 8 8 true <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> true <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> ... :/icons/8x8/bullet_green.png :/icons/8x8/bullet_red.png:/icons/8x8/bullet_green.png 8 8 true 3 Hillshading -8 4 2 2 Qt::Horizontal Slope QComboBox::NoInsert 3 0 0 16777215 20 255 255 255 255 255 255 239 235 231 false false QAbstractSpinBox::NoButtons false ° > 4 0 0 20 10 TextLabel 0 0 20 10 TextLabel 16777215 20 255 255 255 255 255 255 239 235 231 false QAbstractSpinBox::NoButtons ° > 3 98 0 0 20 10 TextLabel 16777215 20 255 255 255 255 255 255 239 235 231 false QAbstractSpinBox::NoButtons ° > 1 96 0 0 20 10 TextLabel 16777215 20 255 255 255 255 255 255 239 235 231 false QAbstractSpinBox::NoButtons ° > 2 97 0 0 20 10 TextLabel 16777215 20 255 255 255 255 255 255 239 235 231 false QAbstractSpinBox::NoButtons ° > 95 CTinySpinBox QSpinBox
widgets/CTinySpinBox.h
qmapshack-1.10.0/src/dem/IDem.cpp000644 001750 000144 00000024632 13216234137 017611 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "dem/CDemDraw.h" #include "dem/CDemPropSetup.h" #include "dem/IDem.h" #include inline qint16 getValue(QVector& data, int x, int y, int dx) { return data[x + y * dx]; } inline void fillWindow(QVector& data, int x, int y, int dx, qint16 * w) { w[0] = getValue(data, x - 1, y - 1, dx); w[1] = getValue(data, x, y - 1, dx); w[2] = getValue(data, x + 1, y - 1, dx); w[3] = getValue(data, x - 1, y, dx); w[4] = getValue(data, x, y, dx); w[5] = getValue(data, x + 1, y, dx); w[6] = getValue(data, x - 1, y + 1, dx); w[7] = getValue(data, x, y + 1, dx); w[8] = getValue(data, x + 1, y + 1, dx); } inline void fillWindow4x4(QVector& data, qreal x, qreal y, int dx, qint16* w) { x = qFloor(x); y = qFloor(y); w[0] = getValue(data, x - 1, y - 1, dx); w[1] = getValue(data, x, y - 1, dx); w[2] = getValue(data, x + 1, y - 1, dx); w[3] = getValue(data, x + 2, y - 1, dx); w[4] = getValue(data, x - 1, y, dx); w[5] = getValue(data, x, y, dx); w[6] = getValue(data, x + 1, y, dx); w[7] = getValue(data, x + 2, y, dx); w[8] = getValue(data, x - 1, y + 1, dx); w[9] = getValue(data, x, y + 1, dx); w[10] = getValue(data, x + 1, y + 1, dx); w[11] = getValue(data, x + 2, y + 1, dx); w[12] = getValue(data, x - 1, y + 2, dx); w[13] = getValue(data, x, y + 2, dx); w[14] = getValue(data, x + 1, y + 2, dx); w[15] = getValue(data, x + 2, y + 2, dx); } const struct SlopePresets IDem::slopePresets[7] { /* http://www.alpenverein.de/bergsport/sicherheit/skitouren-schneeschuh-sicher-im-schnee/dav-snowcard_aid_10619.html */ { "Grade 1 (DAV Snowcard)", {27.0, 31.0, 34.0, 39.0, 50.0}}, { "Grade 2 (DAV Snowcard)", {27.0, 30.0, 32.0, 35.0, 39.0}}, { "Grade 3 (DAV Snowcard)", {27.0, 29.0, 30.0, 31.0, 34.0}}, { "Grade 4 (DAV Snowcard)", {23.0, 25.0, 27.0, 28.0, 30.0}}, { "level country", { 3.0, 6.0, 8.0, 12.0, 15.0}}, { "secondary mountain", { 4.0, 7.0, 10.0, 15.0, 20.0}}, { "lofty mountain", {10.0, 15.0, 20.0, 30.0, 50.0}} }; IDem::IDem(CDemDraw *parent) : IDrawObject(parent) , dem(parent) { slotSetOpacity(17); pjtar = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); graytable.resize(256); for(int i = 0; i < 255; i++) { graytable[i] = qRgba(i,i,i,255); } graytable[255] = qRgba(0,0,0,0); slopetable << qRgba(0,0,0,0); slopetable << qRgba(0,128,0,100); slopetable << qRgba(0,255,0,100); slopetable << qRgba(255,255,0,100); slopetable << qRgba(255,128,0,100); slopetable << qRgba(255,0,0,100); } IDem::~IDem() { pj_free(pjtar); pj_free(pjsrc); } void IDem::saveConfig(QSettings& cfg) { IDrawObject::saveConfig(cfg); cfg.setValue("doHillshading", bHillshading); cfg.setValue("factorHillshading", factorHillshading); cfg.setValue("doSlopeColor", bSlopeColor); cfg.setValue("gradeSlopeColor", gradeSlopeColor); cfg.setValue("slopeCustomValue0", slopeCustomStepTable[0]); cfg.setValue("slopeCustomValue1", slopeCustomStepTable[1]); cfg.setValue("slopeCustomValue2", slopeCustomStepTable[2]); cfg.setValue("slopeCustomValue3", slopeCustomStepTable[3]); cfg.setValue("slopeCustomValue4", slopeCustomStepTable[4]); } void IDem::loadConfig(QSettings& cfg) { IDrawObject::loadConfig(cfg); bHillshading = cfg.value("doHillshading", bHillshading ).toBool(); factorHillshading = cfg.value("factorHillshading", factorHillshading).toFloat(); bSlopeColor = cfg.value("doSlopeColor", bSlopeColor ).toBool(); gradeSlopeColor = cfg.value("gradeSlopeColor", gradeSlopeColor ).toInt(); slopeCustomStepTable[0] = cfg.value("slopeCustomValue0", 5.).toFloat(); slopeCustomStepTable[1] = cfg.value("slopeCustomValue1", 10.).toFloat(); slopeCustomStepTable[2] = cfg.value("slopeCustomValue2", 15.).toFloat(); slopeCustomStepTable[3] = cfg.value("slopeCustomValue3", 20.).toFloat(); slopeCustomStepTable[4] = cfg.value("slopeCustomValue4", 25.).toFloat(); } IDemProp * IDem::getSetup() { if(setup.isNull()) { setup = new CDemPropSetup(this, dem); } return setup; } void IDem::slotSetFactorHillshade(int f) { if(f == 0) { factorHillshading = 1.0; } else if(f < 0) { factorHillshading = -1.0/f; } else { factorHillshading = f; } } void IDem::setSlopeStepTableCustomValue(int idx, int val) { slopeCustomStepTable[idx] = (qreal) val; } void IDem::setSlopeStepTable(int idx) { gradeSlopeColor = idx; dem->emitSigCanvasUpdate(); } const qreal* IDem::getCurrentSlopeStepTable() { if(CUSTOM_SLOPE_COLORTABLE == gradeSlopeColor) { return slopeCustomStepTable; } else { return slopePresets[gradeSlopeColor].steps; } } int IDem::getFactorHillshading() { if(factorHillshading == 1.0) { return 0; } else if(factorHillshading < 1) { return -1.0/factorHillshading; } else { return factorHillshading; } } void IDem::hillshading(QVector& data, qreal w, qreal h, QImage& img) { int wp2 = w + 2; #define ZFACT 0.125 #define ZFACT_BY_ZFACT (ZFACT*ZFACT) #define SIN_ALT (qSin(45*DEG_TO_RAD)) #define ZFACT_COS_ALT (ZFACT*qCos(45*DEG_TO_RAD)) #define AZ (315 * DEG_TO_RAD) for(unsigned int m = 1; m <= h; m++) { unsigned char* scan = img.scanLine(m - 1); for(unsigned int n = 1; n <= w; n++) { qint16 win[eWinsize3x3]; fillWindow(data, n, m, wp2, win); if(hasNoData && win[4] == noData) { scan[n - 1] = 255; continue; } qreal dx = ((win[0] + win[3] + win[3] + win[6]) - (win[2] + win[5] + win[5] + win[8])) / (xscale*factorHillshading); qreal dy = ((win[6] + win[7] + win[7] + win[8]) - (win[0] + win[1] + win[1] + win[2])) / (yscale*factorHillshading); qreal aspect = qAtan2(dy, dx); qreal xx_plus_yy = dx * dx + dy * dy; qreal cang = (SIN_ALT - ZFACT_COS_ALT * qSqrt(xx_plus_yy) * qSin(aspect - AZ)) / qSqrt(1+ZFACT_BY_ZFACT*xx_plus_yy); if (cang <= 0.0) { cang = 1.0; } else { cang = 1.0 + (254.0 * cang); } scan[n - 1] = cang; } } } qreal IDem::slopeOfWindowInterp(qint16* win2, winsize_e size, qreal x, qreal y) { for(int i = 0; i < size; i++) { if(hasNoData && win2[i] == noData) { return NOFLOAT; } } qreal win[eWinsize3x3]; switch(size) { case eWinsize3x3: for(int i = 0; i < 9; i++) { win[i] = win2[i]; } break; case eWinsize4x4: win[0] = win2[0] + x * (win2[1]-win2[0]) + y * (win2[4]-win2[0]) + x*y*(win2[0]-win2[1]-win2[4]+win2[5]); win[1] = win2[1] + x * (win2[2]-win2[1]) + y * (win2[5]-win2[1]) + x*y*(win2[1]-win2[2]-win2[5]+win2[6]); win[2] = win2[2] + x * (win2[3]-win2[2]) + y * (win2[6]-win2[2]) + x*y*(win2[2]-win2[3]-win2[6]+win2[7]); win[3] = win2[4] + x * (win2[5]-win2[4]) + y * (win2[8]-win2[4]) + x*y*(win2[4]-win2[5]-win2[8]+win2[9]); win[4] = win2[5] + x * (win2[6]-win2[5]) + y * (win2[9]-win2[5]) + x*y*(win2[5]-win2[6]-win2[9]+win2[10]); win[5] = win2[6] + x * (win2[7]-win2[6]) + y * (win2[10]-win2[6]) + x*y*(win2[6]-win2[7]-win2[10]+win2[11]); win[6] = win2[8] + x * (win2[9]-win2[8]) + y * (win2[12]-win2[8]) + x*y*(win2[8]-win2[9]-win2[12]+win2[13]); win[7] = win2[9] + x * (win2[10]-win2[9]) + y * (win2[13]-win2[9]) + x*y*(win2[9]-win2[10]-win2[13]+win2[14]); win[8] = win2[10] + x * (win2[11]-win2[10]) + y * (win2[14]-win2[10]) + x*y*(win2[10]-win2[11]-win2[14]+win2[15]); break; default: return NOFLOAT; } qreal dx = ((win[0] + win[3] + win[3] + win[6]) - (win[2] + win[5] + win[5] + win[8])) / (xscale); qreal dy = ((win[6] + win[7] + win[7] + win[8]) - (win[0] + win[1] + win[1] + win[2])) / (yscale); qreal k = dx * dx + dy * dy; qreal slope = qAtan(qSqrt(k) / (8 * 1.0)) * 180.0 / M_PI; return slope; } void IDem::slopecolor(QVector& data, qreal w, qreal h, QImage &img) { int wp2 = w + 2; for(unsigned int m = 1; m <= h; m++) { unsigned char* scan = img.scanLine(m - 1); for(unsigned int n = 1; n <= w; n++) { qint16 win[eWinsize3x3]; fillWindow(data, n, m, wp2, win); qreal slope = slopeOfWindowInterp(win, eWinsize3x3, 0, 0); const qreal *currentSlopeStepTable = getCurrentSlopeStepTable(); if(slope > currentSlopeStepTable[4]) { scan[n - 1] = 5; } else if(slope > currentSlopeStepTable[3]) { scan[n - 1] = 4; } else if(slope > currentSlopeStepTable[2]) { scan[n - 1] = 3; } else if(slope > currentSlopeStepTable[1]) { scan[n - 1] = 2; } else if(slope > currentSlopeStepTable[0]) { scan[n - 1] = 1; } else { scan[n - 1] = 0; } } } } void IDem::drawTile(QImage& img, QPolygonF& l, QPainter& p) { drawTileLQ(img, l, p, *dem, pjsrc, pjtar); } qmapshack-1.10.0/src/dem/CDemDraw.h000644 001750 000144 00000006420 13216234142 020055 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMDRAW_H #define CDEMDRAW_H #include "canvas/IDrawContext.h" class QPainter; class CDemList; class CCanvas; class QSettings; class CDemItem; class CDemDraw : public IDrawContext { public: CDemDraw(CCanvas * canvas); virtual ~CDemDraw(); void saveConfig(QSettings& cfg); void loadConfig(QSettings& cfg); /** @brief This is called most likely from the item itself to call it's loadConfig() method. As the setup of a map is stored in the context of the view the correct groups have to be set prior to call the item's loadConfig() method. However the item does not know all that stuff. That is why it has to ask it's CMapDraw object to prepare the QSettings object and to call loadConfig(); @param item the item to call it's loadConfig() method */ void loadConfigForDemItem(CDemItem * item); qreal getElevationAt(const QPointF& pos); void getElevationAt(const QPolygonF& pos, QPolygonF& ele); void getElevationAt(SGisLine& line); qreal getSlopeAt(const QPointF& pos); void getSlopeAt(const QPolygonF& pos, QPolygonF& slope); void setProjection(const QString& proj) override; static const QStringList& getDemPaths() { return demPaths; } static void setupDemPath(); static void setupDemPath(const QStringList &paths); static void saveDemPath(QSettings &cfg); static void loadDemPath(QSettings &cfg); static const QStringList& getSupportedFormats() { return supportedFormats; } protected: void drawt(buffer_t& currentBuffer) override; private: /** @brief Search in paths found in mapPaths for files with supported extensions and add them to mapList. */ void buildMapList(); /** @brief Save list of active maps to configuration file */ void saveActiveMapsList(QStringList &keys, QSettings &cfg); void saveActiveMapsList(QStringList &keys); /** @brief Restore list of active maps from configuration file */ void restoreActiveMapsList(const QStringList &keys); void restoreActiveMapsList(const QStringList& keys, QSettings &cfg); CDemList * demList; /// the group label used in QSettings QString cfgGroup; static QStringList demPaths; static QList dems; /// a list of supported map formats static QStringList supportedFormats; }; #endif //CDEMDRAW_H qmapshack-1.10.0/src/dem/CDemItem.h000644 001750 000144 00000005303 13216234142 020055 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMITEM_H #define CDEMITEM_H #include #include #include #include class IDem; class CDemDraw; class QSettings; class CDemItem : public QTreeWidgetItem { public: CDemItem(QTreeWidget *parent, CDemDraw *dem); virtual ~CDemItem(); void saveConfig(QSettings& cfg); void loadConfig(QSettings& cfg); /** @brief As the drawing thread is using the list widget to iterate of all maps to draw, all access has to be synchronized. */ static QMutex mutexActiveDems; /** @brief Query if dem objects are loaded @return True if the internal list of dem objects is not empty. */ bool isActivated(); /** @brief Either loads or destroys internal map objects @return True if the internal list of maps is not empty after the operation. */ bool toggleActivate(); /** * @brief Load all internal map objects * @return Return true on success. */ bool activate(); /** @brief Delete all internal map objects */ void deactivate(); /** @brief Move item to top of list widget */ void moveToTop(); void moveToBottom(); void updateIcon(); /** @brief Show or hide child treewidget items @param yes set true to add children, false will remove all children and delete the attached widgets */ void showChildren(bool yes); private: friend class CDemDraw; CDemDraw * dem; /** @brief A MD5 hash over the first 1024 bytes of the map file, to identify the map */ QString key; /** @brief List of map files forming that particular map */ QString filename; /** @brief List of loaded map objects when map is activated. */ QPointer demfile; }; #endif //CDEMITEM_H qmapshack-1.10.0/src/dem/CDemPathSetup.cpp000644 001750 000144 00000005225 13216234137 021436 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "dem/CDemDraw.h" #include "dem/CDemPathSetup.h" #include CDemPathSetup::CDemPathSetup(QStringList &paths) : QDialog(CMainWindow::getBestWidgetForParent()) , paths(paths) { setupUi(this); connect(toolAdd, &QToolButton::clicked, this, &CDemPathSetup::slotAddPath); connect(toolDelete, &QToolButton::clicked, this, &CDemPathSetup::slotDelPath); connect(listWidget, &QListWidget::itemSelectionChanged, this, &CDemPathSetup::slotItemSelectionChanged); for(const QString &path : paths) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } labelHelp->setText(tr("Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1").arg(CDemDraw::getSupportedFormats().join(", "))); } CDemPathSetup::~CDemPathSetup() { } void CDemPathSetup::slotItemSelectionChanged() { QList items = listWidget->selectedItems(); toolDelete->setEnabled(!items.isEmpty()); } void CDemPathSetup::slotAddPath() { QString path = QFileDialog::getExistingDirectory(this, tr("Select DEM file path..."), QDir::homePath(), 0); if(!path.isEmpty()) { if(!paths.contains(path)) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } } } void CDemPathSetup::slotDelPath() { QList items = listWidget->selectedItems(); qDeleteAll(items); } void CDemPathSetup::accept() { paths.clear(); for(int i = 0; i < listWidget->count(); i++) { QListWidgetItem *item = listWidget->item(i); paths << item->text(); } QDialog::accept(); } qmapshack-1.10.0/src/dem/IDemPathSetup.ui000644 001750 000144 00000011321 12627613665 021305 0ustar00oeichlerxusers000000 000000 IDemPathSetup 0 0 450 200 Setup DEM file paths QAbstractItemView::ExtendedSelection ... :/icons/32x32/Add.png:/icons/32x32/Add.png 22 22 false ... :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png 22 22 Qt::Vertical 20 40 64 16777215 :/icons/48x48/Help.png Qt::AlignCenter 0 0 - Qt::AlignJustify|Qt::AlignVCenter true 0 0 Qt::Vertical QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IDemPathSetup accept() 248 254 157 274 buttonBox rejected() IDemPathSetup reject() 316 260 286 274 qmapshack-1.10.0/src/dem/CDemItem.cpp000644 001750 000144 00000011507 13216234137 020417 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "dem/CDemDraw.h" #include "dem/CDemItem.h" #include "dem/CDemVRT.h" #include "dem/IDemProp.h" #include QMutex CDemItem::mutexActiveDems(QMutex::Recursive); CDemItem::CDemItem(QTreeWidget * parent, CDemDraw *dem) : QTreeWidgetItem(parent) , dem(dem) { setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); } CDemItem::~CDemItem() { } void CDemItem::saveConfig(QSettings& cfg) { if(demfile.isNull()) { return; } cfg.beginGroup(key); demfile->saveConfig(cfg); cfg.endGroup(); } void CDemItem::loadConfig(QSettings& cfg) { if(demfile.isNull()) { return; } cfg.beginGroup(key); demfile->loadConfig(cfg); cfg.endGroup(); } void CDemItem::showChildren(bool yes) { if(yes && !demfile.isNull()) { QTreeWidget * tw = treeWidget(); QTreeWidgetItem * item = new QTreeWidgetItem(this); item->setFlags(Qt::ItemIsEnabled); tw->setItemWidget(item, 0, demfile->getSetup()); } else { QList items = takeChildren(); qDeleteAll(items); delete demfile->getSetup(); } } void CDemItem::updateIcon() { if(filename.isEmpty()) { return; } QPixmap img("://icons/32x32/Map.png"); QFileInfo fi(filename); if(fi.suffix().toLower() == "vrt") { img = QPixmap("://icons/32x32/MimeDemVRT.png"); } setIcon(0,QIcon(img)); } bool CDemItem::isActivated() { QMutexLocker lock(&mutexActiveDems); return !demfile.isNull(); } bool CDemItem::toggleActivate() { QMutexLocker lock(&mutexActiveDems); if(demfile.isNull()) { return activate(); } else { deactivate(); return false; } } void CDemItem::deactivate() { QMutexLocker lock(&mutexActiveDems); // remove demfile setup dialog as child of this item showChildren(false); // remove demfile object delete demfile; // maybe used to reflect changes in the icon updateIcon(); // move to bottom of the active dem list moveToBottom(); // deny drag-n-drop again setFlags(flags() & ~Qt::ItemIsDragEnabled); } bool CDemItem::activate() { QMutexLocker lock(&mutexActiveDems); // remove demfile object delete demfile; // load map by suffix QFileInfo fi(filename); if(fi.suffix().toLower() == "vrt") { demfile = new CDemVRT(filename, dem); } updateIcon(); // no mapfiles loaded? Bad. if(demfile.isNull()) { return false; } // if map is activated successfully add to the list of map files // else delete all previous loaded maps and abort if(!demfile->activated()) { delete demfile; return false; } moveToBottom(); setFlags(flags() | Qt::ItemIsDragEnabled); /* As the map file setup is stored in the context of the CMapDraw object the configuration has to be loaded via the CMapDraw object to select the correct group context in the QSetting object. This call will result into a call of loadConfig() of this CMapItem object. */ dem->loadConfigForDemItem(this); // Add the demfile setup dialog as child of this item showChildren(true); return true; } void CDemItem::moveToTop() { QTreeWidget * w = treeWidget(); QMutexLocker lock(&mutexActiveDems); w->takeTopLevelItem(w->indexOfTopLevelItem(this)); w->insertTopLevelItem(0, this); dem->emitSigCanvasUpdate(); } void CDemItem::moveToBottom() { int row; QTreeWidget * w = treeWidget(); QMutexLocker lock(&mutexActiveDems); w->takeTopLevelItem(w->indexOfTopLevelItem(this)); for(row = 0; row < w->topLevelItemCount(); row++) { CDemItem * item = dynamic_cast(w->topLevelItem(row)); if(item && item->demfile.isNull()) { break; } } w->insertTopLevelItem(row, this); dem->emitSigCanvasUpdate(); } qmapshack-1.10.0/src/dem/IDemProp.h000644 001750 000144 00000002353 13216234142 020107 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDEMPROP_H #define IDEMPROP_H #include class IDem; class CDemDraw; class IDemProp : public QWidget { Q_OBJECT public: IDemProp(IDem *demfile, CDemDraw *dem); virtual ~IDemProp(); protected slots: virtual void slotPropertiesChanged()= 0; protected: IDem * demfile; CDemDraw * dem; }; #endif //IDEMPROP_H qmapshack-1.10.0/src/dem/CDemPropSetup.cpp000644 001750 000144 00000020165 13216234137 021462 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "dem/CDemDraw.h" #include "dem/CDemPropSetup.h" #include "dem/IDem.h" #include "helpers/Signals.h" #include "units/IUnit.h" #include QPointF CDemPropSetup::scale; CDemPropSetup::CDemPropSetup(IDem * demfile, CDemDraw *dem) : IDemProp(demfile, dem) { setupUi(this); slopeSpins[0] = spinSlope0; slopeSpins[1] = spinSlope1; slopeSpins[2] = spinSlope2; slopeSpins[3] = spinSlope3; slopeSpins[4] = spinSlope4; slotPropertiesChanged(); connect(sliderOpacity, &QSlider::valueChanged, demfile, &IDem::slotSetOpacity); connect(sliderOpacity, &QSlider::valueChanged, dem, &CDemDraw::emitSigCanvasUpdate); connect(dem, &CDemDraw::sigScaleChanged, this, &CDemPropSetup::slotScaleChanged); connect(toolSetMinScale, &QToolButton::toggled, this, &CDemPropSetup::slotSetMinScale); connect(toolSetMaxScale, &QToolButton::toggled, this, &CDemPropSetup::slotSetMaxScale); connect(checkHillshading, &QCheckBox::toggled, demfile, &IDem::slotSetHillshading); connect(checkHillshading, &QCheckBox::clicked, dem, &CDemDraw::emitSigCanvasUpdate); connect(sliderHillshading, &QSlider::valueChanged, demfile, &IDem::slotSetFactorHillshade); connect(sliderHillshading, &QSlider::valueChanged, dem, &CDemDraw::emitSigCanvasUpdate); connect(checkSlopeColor, &QCheckBox::toggled, demfile, &IDem::slotSetSlopeColor); connect(checkSlopeColor, &QCheckBox::clicked, dem, &CDemDraw::emitSigCanvasUpdate); for(size_t i = 0; i < SLOPE_LEVELS; i++) { slopeSpins[i]->setProperty("level", (uint) i); connect(slopeSpins[i], &CTinySpinBox::editingFinished, this, &CDemPropSetup::slotSlopeValiddateAfterEdit); connect(slopeSpins[i], &CTinySpinBox::valueChangedByStep, this, &CDemPropSetup::slotSlopeValiddateAfterEdit); } for(size_t i = 0; i < IDem::slopePresetCount; i++) { comboGrades->addItem(IDem::slopePresets[i].name); } comboGrades->addItem("custom"); connect(comboGrades, static_cast(&QComboBox::currentIndexChanged), this, &CDemPropSetup::slotGradeIndex); const QVector& colortable = demfile->getSlopeColorTable(); QPixmap pixmap(20, 10); pixmap.fill(colortable[5]); labelColor5->setPixmap(pixmap); pixmap.fill(colortable[4]); labelColor4->setPixmap(pixmap); pixmap.fill(colortable[3]); labelColor3->setPixmap(pixmap); pixmap.fill(colortable[2]); labelColor2->setPixmap(pixmap); pixmap.fill(colortable[1]); labelColor1->setPixmap(pixmap); } CDemPropSetup::~CDemPropSetup() { } void CDemPropSetup::resizeEvent(QResizeEvent * e) { IDemProp::resizeEvent(e); updateScaleLabel(); } void CDemPropSetup::slotPropertiesChanged() { X______________BlockAllSignals______________X(this); sliderOpacity->setValue(demfile->getOpacity()); toolSetMinScale->setChecked( demfile->getMinScale() != NOFLOAT ); toolSetMaxScale->setChecked( demfile->getMaxScale() != NOFLOAT ); updateScaleLabel(); checkHillshading->setChecked(demfile->doHillshading()); sliderHillshading->setValue(demfile->getFactorHillshading()); checkSlopeColor->setChecked(demfile->doSlopeColor()); bool spinsReadonly = true; // calculate the index of the element, that should be selected in comboGrades // -1 indicates the `custom` entry (this allows adding DEM presets migration // of configuration during update int expectedComboGradesIndex = demfile->getSlopeStepTableIndex(); if(-1 == expectedComboGradesIndex) { spinsReadonly = false; expectedComboGradesIndex = comboGrades->count() - 1; } comboGrades->setCurrentIndex(expectedComboGradesIndex); for(size_t i = 0; i < SLOPE_LEVELS; i++) { slopeSpins[i]->setReadOnly(spinsReadonly); slopeSpins[i]->setValue(demfile->getCurrentSlopeStepTable()[i]); } dem->emitSigCanvasUpdate(); X_____________UnBlockAllSignals_____________X(this); } void CDemPropSetup::slotScaleChanged(const QPointF& s) { scale = s; slotPropertiesChanged(); } void CDemPropSetup::slotSetMinScale(bool checked) { demfile->setMinScale(checked ? scale.x() : NOFLOAT); slotPropertiesChanged(); } void CDemPropSetup::slotSetMaxScale(bool checked) { demfile->setMaxScale(checked ? scale.x() : NOFLOAT); slotPropertiesChanged(); } #define BAR_HEIGHT 6 #define HOR_MARGIN 3 void CDemPropSetup::updateScaleLabel() { int w = labelScale->width(); int h = labelScale->height(); QPixmap pix(w,h); if(pix.isNull()) { return; } pix.fill(Qt::transparent); QPainter p(&pix); // draw bar background int xBar = HOR_MARGIN; int yBar = (h - BAR_HEIGHT) / 2; QRect bar(xBar, yBar, w-2*HOR_MARGIN, BAR_HEIGHT); p.setPen(Qt::darkBlue); p.setBrush(Qt::white); p.drawRect(bar); // draw current scale range qreal minScale = demfile->getMinScale(); qreal maxScale = demfile->getMaxScale(); if((minScale != NOFLOAT) || (maxScale != NOFLOAT)) { int x1Range = minScale != NOFLOAT ? HOR_MARGIN + qRound(bar.width() * (1 + log10(minScale)) / 5) : bar.left(); int x2Range = maxScale != NOFLOAT ? HOR_MARGIN + qRound(bar.width() * (1 + log10(maxScale)) / 5) : bar.right(); int yRange = yBar; QRect range(x1Range, yRange, x2Range - x1Range, BAR_HEIGHT); p.setPen(Qt::NoPen); p.setBrush(Qt::darkGreen); p.drawRect(range); } // draw scale indicator int xInd = HOR_MARGIN + qRound(bar.width() * (1 + log10(scale.x())) / 5) - 3; int yInd = yBar - 1; QRect ind(xInd, yInd, 5, BAR_HEIGHT + 2); p.setPen(Qt::darkBlue); p.setBrush(Qt::NoBrush); p.drawRect(ind); labelScale->setPixmap(pix); } void CDemPropSetup::slotSlopeChanged(int val) { uint level = QObject::sender()->property("level").toUInt(); demfile->setSlopeStepTableCustomValue(level, val); } void CDemPropSetup::slotSlopeValiddateAfterEdit() { uint level = QObject::sender()->property("level").toUInt(); demfile->setSlopeStepTableCustomValue(level, slopeSpins[level]->value()); if(comboGrades->count() - 1 == comboGrades->currentIndex()) { // ensure the levels below/above the current level are // less/greater than the current level for(uint l = level; l < SLOPE_LEVELS - 1; l++) { int val = slopeSpins[l]->value(); if(slopeSpins[l + 1]->value() <= val) { slopeSpins[l + 1]->setValue(val + 1); demfile->setSlopeStepTableCustomValue(l + 1, val + 1); } } for(uint l = level; l >= 1; l--) { int val = slopeSpins[l]->value(); if(slopeSpins[l - 1]->value() >= val) { slopeSpins[l - 1]->setValue(val - 1); demfile->setSlopeStepTableCustomValue(l - 1, val - 1); } } } dem->emitSigCanvasUpdate(); } void CDemPropSetup::slotGradeIndex(int idx) { // enable the spins if the selected entry is `custom` demfile->setSlopeStepTable(idx == IDem::slopePresetCount ? -1 : idx); slotPropertiesChanged(); } qmapshack-1.10.0/src/dem/CDemPropSetup.h000644 001750 000144 00000003270 13216234142 021121 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEMPROPSETUP_H #define CDEMPROPSETUP_H #define SLOPE_LEVELS 5 #include "dem/IDemProp.h" #include "ui_IDemPropSetup.h" class CDemPropSetup : public IDemProp, private Ui::IDemPropSetup { Q_OBJECT public: CDemPropSetup(IDem *demfile, CDemDraw *dem); virtual ~CDemPropSetup(); protected slots: void slotPropertiesChanged() override; protected: void resizeEvent(QResizeEvent * e) override; private slots: void slotScaleChanged(const QPointF& s); void slotSetMinScale(bool checked); void slotSetMaxScale(bool checked); void slotGradeIndex(int idx); void slotSlopeValiddateAfterEdit(); void slotSlopeChanged(int val); private: void updateScaleLabel(); CTinySpinBox* slopeSpins[SLOPE_LEVELS]; static QPointF scale; }; #endif //CDEMPROPSETUP_H qmapshack-1.10.0/src/dem/IDem.h000644 001750 000144 00000011352 13216234142 017245 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDEM_H #define IDEM_H #include "canvas/IDrawObject.h" #include #include #include #define CUSTOM_SLOPE_COLORTABLE ( -1 ) class CDemDraw; class IDemProp; class QSettings; struct SlopePresets { const char *name; const qreal steps[5]; }; class IDem : public IDrawObject { Q_OBJECT public: IDem(CDemDraw * parent); virtual ~IDem(); void saveConfig(QSettings& cfg) override; void loadConfig(QSettings& cfg) override; virtual void draw(IDrawContext::buffer_t& buf) = 0; virtual qreal getElevationAt(const QPointF& pos) = 0; virtual qreal getSlopeAt(const QPointF& pos) = 0; bool activated() { return isActivated; } /** @brief Get the dem's setup widget. As default an instance of CDemPropSetup is used. For other setups you have to override this method. @return A pointer to the widget. Use a smart pointer to store as the widget can be destroyed at any time */ virtual IDemProp * getSetup(); bool doHillshading() { return bHillshading; } int getFactorHillshading(); bool doSlopeColor() { return bSlopeColor; } const QVector getSlopeColorTable() { return slopetable; } static const struct SlopePresets slopePresets[7]; static const size_t slopePresetCount = sizeof(IDem::slopePresets) / sizeof(IDem::slopePresets[0]); const qreal* getCurrentSlopeStepTable(); int getSlopeStepTableIndex() { return gradeSlopeColor; } void setSlopeStepTable(int idx); void setSlopeStepTableCustomValue(int idx, int val); enum winsize_e {eWinsize3x3 = 9, eWinsize4x4 = 16}; public slots: void slotSetHillshading(bool yes) { bHillshading = yes; } void slotSetFactorHillshade(int f); void slotSetSlopeColor(bool yes) { bSlopeColor = yes; } protected: void hillshading(QVector& data, qreal w, qreal h, QImage &img); void slopecolor(QVector& data, qreal w, qreal h, QImage &img); /** @brief Slope in degrees based on a window. Origin is at point (1,1), counting from zero. @param win2 window data @param size size of window (eWinsize3x3 or eWinsize4x4) @param x Fractional value (0..1) for interpolation in x (4x4 window only) @param y Fractional value (0..1) for interpolation in y (4x4 window only) @return Slope in degrees */ qreal slopeOfWindowInterp(qint16* win2, winsize_e size, qreal x, qreal y); /** @brief Reproject (translate, rotate, scale) tile before drawing it. @param img the tile as QImage @param l a 4 point polygon to fit the tile in @param p the QPainter used to paint the tile */ void drawTile(QImage& img, QPolygonF& l, QPainter& p); CDemDraw * dem; /// source projection of the current map file /** Has to be set by subclass. Destruction has to be handled by subclass. */ projPJ pjsrc = nullptr; /// target projection /** Is set by IMap() to WGS84. Will be freed by ~IMap() */ projPJ pjtar = nullptr; /// width in number of px quint32 xsize_px = 0; /// height in number of px quint32 ysize_px = 0; /// scale [px/m] qreal xscale = 1.0; /// scale [px/m] qreal yscale = 1.0; /** @brief True if map was loaded successfully */ bool isActivated = false; /// the setup dialog. Use getSetup() for access QPointer setup; QVector graytable; QVector slopetable; int hasNoData = 0; double noData = 0; private: bool bHillshading = false; qreal factorHillshading = 0.1666666716337204; bool bSlopeColor = false; int gradeSlopeColor = 0; qreal slopeCustomStepTable[5]; }; #endif //IDEM_H qmapshack-1.10.0/src/dem/IDemList.ui000644 001750 000144 00000013117 13205474716 020303 0ustar00oeichlerxusers000000 000000 IDemsList 0 0 245 250 Form 0 0 0 0 0 Qt::CustomContextMenu QAbstractItemView::InternalMove 32 32 false 1 3 3 3 3 3 0 0 :/icons/48x48/Help.png Qt::AlignHCenter|Qt::AlignTop 8 0 0 0 0 To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Qt::AlignJustify|Qt::AlignVCenter true Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Qt::AlignJustify|Qt::AlignVCenter true true :/icons/32x32/Check.png :/icons/32x32/Cancel.png:/icons/32x32/Check.png Activate :/icons/32x32/Up.png:/icons/32x32/Up.png Move Up Hide DEM behind previous one :/icons/32x32/Down.png:/icons/32x32/Down.png Move down Show DEM on top of next one :/icons/32x32/Reset.png:/icons/32x32/Reset.png Reload DEM CDemTreeWidget QTreeWidget
dem/CDemList.h
qmapshack-1.10.0/src/CSingleInstanceProxy.h000644 001750 000144 00000002437 13216234142 021741 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSINGLEINSTANCEPROXY_H #define CSINGLEINSTANCEPROXY_H #include class QLocalServer; class CSingleInstanceProxy : public QObject { public: CSingleInstanceProxy(const QStringList filenames); virtual ~CSingleInstanceProxy(); private slots: void slotNewConnection(); private: QLocalServer * server = nullptr; QString serverName; }; #endif //CSINGLEINSTANCEPROXY_H qmapshack-1.10.0/src/CMainWindow.cpp000644 001750 000144 00000125031 13216234261 020376 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CAbout.h" #include "CMainWindow.h" #include "canvas/CCanvas.h" #include "config.h" #include "dem/CDemDraw.h" #include "dem/CDemList.h" #include "gis/CGisDatabase.h" #include "gis/CGisWorkspace.h" #include "gis/IGisLine.h" #include "gis/WptIcons.h" #include "gis/db/CSetupWorkspace.h" #include "gis/prj/IGisProject.h" #include "gis/trk/CActivityTrk.h" #include "gis/trk/CKnownExtension.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include "helpers/CToolBarConfig.h" #include "helpers/CToolBarSetupDialog.h" #include "helpers/CWptIconDialog.h" #include "map/CMapDraw.h" #include "map/CMapItem.h" #include "map/CMapList.h" #include "tool/CImportDatabase.h" #include "tool/CMapVrtBuilder.h" #include "tool/CRoutinoDatabaseBuilder.h" #include "units/CCoordFormatSetup.h" #include "units/CTimeZoneSetup.h" #include "units/CUnitsSetup.h" #include "units/IUnit.h" #include "version.h" #include #include #include #ifdef WIN32 #include "device/CDeviceWatcherWindows.h" #include #include #include #include #include #endif // WIN32 CMainWindow * CMainWindow::pSelf = nullptr; QMutex CMainWindow::mutex(QMutex::NonRecursive); CMainWindow::CMainWindow() : id(qrand()) { qDebug() << "Application ID:" << id; SETTINGS; pSelf = this; setupUi(this); setWindowTitle(WHAT_STR); initWptIcons(); IUnit::setUnitType((IUnit::type_e)cfg.value("MainWindow/units",IUnit::eTypeMetric).toInt(), this); IUnit::setSlopeMode((IUnit::slope_mode_e)cfg.value("Units/slopeMode", IUnit::eSlopeDegrees).toInt()); QByteArray tz; IUnit::tz_mode_e tzmode; bool useShortFormat; tz = cfg.value("Units/timezone", "UTC").toByteArray(); tzmode = (IUnit::tz_mode_e)cfg.value("Units/timezone/mode", IUnit::eTZUtc).toInt(); useShortFormat = cfg.value("Units/time/useShortFormat", false).toBool(); IUnit::setTimeZoneSetup(tzmode, tz, useShortFormat); IUnit::coord_format_e coordFormat; coordFormat = (IUnit::coord_format_e)cfg.value("Units/coordFormat", IUnit::eCoordFormat1).toInt(); IUnit::setCoordFormat(coordFormat); CKnownExtension::init(IUnit::self()); CActivityTrk::init(); widgetGisWorkspace = new CGisWorkspace(menuProject, this); dockWorkspace->setWidget(widgetGisWorkspace); widgetGisDatabase = new CGisDatabase(this); dockDatabase->setWidget(widgetGisDatabase); // start ---- restore window geometry ----- cfg.beginGroup("MainWindow"); if ( cfg.contains("geometry")) { restoreGeometry(cfg.value("geometry").toByteArray()); } else { QTimer::singleShot(500, this, SLOT(showMaximized())); } if ( cfg.contains("state")) { restoreState(cfg.value("state").toByteArray()); } if (cfg.contains("displaymode")) { displayMode = static_cast(cfg.value("displaymode").toInt()); if (displayMode == Qt::WindowFullScreen) { displayMode = Qt::WindowMaximized; } } if (cfg.contains("dockstate")) { dockStates = cfg.value("dockstate").toByteArray(); } menuVisible = cfg.value("menuvisible",false).toBool(); if(windowState() == Qt::WindowFullScreen) { displayRegular(); } cfg.endGroup(); // end ---- restore window geometry ----- connect(actionAbout, &QAction::triggered, this, &CMainWindow::slotAbout); connect(actionHelp, &QAction::triggered, this, &CMainWindow::slotHelp); connect(actionQuickstart, &QAction::triggered, this, &CMainWindow::slotQuickstart); connect(actionAddMapView, &QAction::triggered, this, &CMainWindow::slotAddCanvas); connect(actionCloneMapView, &QAction::triggered, this, &CMainWindow::slotCloneCanvas); connect(actionShowScale, &QAction::changed, this, &CMainWindow::slotUpdateCurrentWidget); connect(actionShowGrid, &QAction::changed, this, static_cast(&CMainWindow::update)); connect(actionPOIText, &QAction::changed, this, &CMainWindow::slotUpdateCurrentWidget); connect(actionMapToolTip, &QAction::changed, this, &CMainWindow::slotUpdateCurrentWidget); connect(actionNightDay, &QAction::changed, this, &CMainWindow::slotUpdateCurrentWidget); connect(actionMinMaxTrackValues, &QAction::changed, this, &CMainWindow::slotUpdateCurrentWidget); connect(actionProfileIsWindow, &QAction::toggled, this, &CMainWindow::slotSetProfileMode); connect(actionSetupMapFont, &QAction::triggered, this, &CMainWindow::slotSetupMapFont); connect(actionSetupMapBackground, &QAction::triggered, this, &CMainWindow::slotSetupMapBackground); connect(actionSetupGrid, &QAction::triggered, this, &CMainWindow::slotSetupGrid); connect(actionSetupMapPaths, &QAction::triggered, this, &CMainWindow::slotSetupMapPath); connect(actionSetupDEMPaths, &QAction::triggered, this, &CMainWindow::slotSetupDemPath); connect(actionSetupMapView, &QAction::triggered, this, &CMainWindow::slotSetupMapView); connect(actionSetupTimeZone, &QAction::triggered, this, &CMainWindow::slotSetupTimeZone); connect(actionSetupUnits, &QAction::triggered, this, &CMainWindow::slotSetupUnits); connect(actionSetupWorkspace, &QAction::triggered, this, &CMainWindow::slotSetupWorkspace); connect(actionSetupCoordFormat, &QAction::triggered, this, &CMainWindow::slotSetupCoordFormat); connect(actionSetupToolbar, &QAction::triggered, this, &CMainWindow::slotSetupToolbar); connect(actionImportDatabase, &QAction::triggered, this, &CMainWindow::slotImportDatabase); connect(actionSaveGISData, &QAction::triggered, widgetGisWorkspace, &CGisWorkspace::slotSaveAll); connect(actionLoadGISData, &QAction::triggered, this, &CMainWindow::slotLoadGISData); connect(actionVrtBuilder, &QAction::triggered, this, &CMainWindow::slotBuildVrt); connect(actionStoreView, &QAction::triggered, this, &CMainWindow::slotStoreView); connect(actionLoadView, &QAction::triggered, this, &CMainWindow::slotLoadView); connect(actionClose, &QAction::triggered, this, &CMainWindow::close); connect(actionCreateRoutinoDatabase, &QAction::triggered, this, &CMainWindow::slotCreateRoutinoDatabase); connect(actionPrintMap, &QAction::triggered, this, &CMainWindow::slotPrintMap); connect(actionSetupWaypointIcons, &QAction::triggered, this, &CMainWindow::slotSetupWptIcons); connect(actionCloseTab, &QAction::triggered, this, &CMainWindow::slotCloseTab); connect(actionToggleDocks, &QAction::triggered, this, &CMainWindow::slotToggleDocks); connect(actionFullScreen, &QAction::triggered, this, &CMainWindow::slotFullScreen); connect(tabWidget, &QTabWidget::tabCloseRequested, this, &CMainWindow::slotTabCloseRequest); connect(tabWidget, &QTabWidget::currentChanged, this, &CMainWindow::slotCurrentTabCanvas); connect(tabMaps, &QTabWidget::currentChanged, this, &CMainWindow::slotCurrentTabMaps); connect(tabDem, &QTabWidget::currentChanged, this, &CMainWindow::slotCurrentTabDem); cfg.beginGroup("Canvas"); CMapDraw::loadMapPath(cfg); CDemDraw::loadDemPath(cfg); cfg.beginGroup("Views"); QStringList names = cfg.childGroups(); for(const QString &name : names) { CCanvas * view = addView(name); cfg.beginGroup(name); view->loadConfig(cfg); cfg.endGroup(); // name } if(names.isEmpty()) { CCanvas * view = addView(QString()); // call just to setup default values view->loadConfig(cfg); } cfg.endGroup(); // Views testForNoView(); CCanvas::gisLayerOpacity = cfg.value("gisLayerOpacity",1.0).toFloat(); widgetGisWorkspace->setOpacity(CCanvas::gisLayerOpacity); actionShowScale->setChecked(cfg.value("isScaleVisible", true).toBool()); actionShowGrid->setChecked(cfg.value("isGridVisible", false).toBool()); actionPOIText->setChecked(cfg.value("POIText", true).toBool()); actionMapToolTip->setChecked(cfg.value("MapToolTip", true).toBool()); actionNightDay->setChecked(cfg.value("isNight", false).toBool()); actionMinMaxTrackValues->setChecked(cfg.value("MinMaxTrackValues", false).toBool()); actionFlipMouseWheel->setChecked(cfg.value("flipMouseWheel", false).toBool()); actionProfileIsWindow->setChecked(cfg.value("profileIsWindow", false).toBool()); mapFont = cfg.value("mapFont", font()).value(); tabWidget->setCurrentIndex(cfg.value("visibleCanvas",0).toInt()); cfg.endGroup(); // Canvas QStatusBar * status = statusBar(); lblPosWGS84 = new QLabel(status); status->addPermanentWidget(lblPosWGS84); lblElevation = new QLabel(status); status->addPermanentWidget(lblElevation); lblSlope = new QLabel(status); status->addPermanentWidget(lblSlope); lblPosGrid = new QLabel(status); status->addPermanentWidget(lblPosGrid); docks << dockMaps << dockDem << dockWorkspace << dockDatabase << dockRte; if (cfg.contains("MainWindow/activedocks")) { const QStringList & dockNames = cfg.value("MainWindow/activedocks").toStringList(); for(QDockWidget * const & dock : docks) { if(dockNames.contains(dock->objectName())) { activeDocks << dock; } } } for (QDockWidget * const & dock : docks) { connect(dock, &QDockWidget::visibilityChanged, this, &CMainWindow::slotDockVisibilityChanged); } QAction * actionToggleToolBar = toolBar->toggleViewAction(); actionToggleToolBar->setObjectName("actionToggleToolBar"); actionToggleToolBar->setIcon(QIcon(":/icons/32x32/ToolBar.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleToolBar); QAction * actionToggleMaps = dockMaps->toggleViewAction(); actionToggleMaps->setObjectName("actionToggleMaps"); actionToggleMaps->setIcon(QIcon(":/icons/32x32/ToggleMaps.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleMaps); QAction * actionToggleDem = dockDem->toggleViewAction(); actionToggleDem->setObjectName("actionToggleDem"); actionToggleDem->setIcon(QIcon(":/icons/32x32/ToggleDem.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleDem); QAction * actionToggleWorkspace = dockWorkspace->toggleViewAction(); actionToggleWorkspace->setObjectName("actionToggleWorkspace"); actionToggleWorkspace->setIcon(QIcon(":/icons/32x32/ToggleGis.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleWorkspace); QAction * actionToggleDatabase = dockDatabase->toggleViewAction(); actionToggleDatabase->setObjectName("actionToggleDatabase"); actionToggleDatabase->setIcon(QIcon(":/icons/32x32/ToggleDatabase.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleDatabase); QAction * actionToggleRte = dockRte->toggleViewAction(); actionToggleRte->setObjectName("actionToggleRte"); actionToggleRte->setIcon(QIcon(":/icons/32x32/ToggleRouter.png")); menuWindow->insertAction(actionSetupToolbar,actionToggleRte); menuWindow->insertSeparator(actionSetupToolbar); QAction * separator = new QAction("---------------",this); separator->setSeparator(true); separator->setObjectName("separator"); QList availableActions; availableActions << separator << actionAddMapView << actionShowScale << actionSetupMapFont << actionShowGrid << actionSetupGrid << actionFlipMouseWheel << actionSetupMapPaths << actionPOIText << actionNightDay << actionMapToolTip << actionMinMaxTrackValues << actionSetupDEMPaths << actionAbout << actionHelp << actionSetupMapView << actionLoadGISData << actionSaveGISData << actionSetupTimeZone << actionAddEmptyProject << actionSearchGoogle << actionCloseAllProjects << actionSetupUnits << actionSetupWorkspace << actionImportDatabase << actionVrtBuilder << actionStoreView << actionLoadView << actionProfileIsWindow << actionClose << actionCloneMapView << actionCreateRoutinoDatabase << actionPrintMap << actionSetupCoordFormat << actionSetupMapBackground << actionSetupWaypointIcons << actionCloseTab << actionQuickstart << actionSetupToolbar << actionToggleMaps << actionToggleDem << actionToggleWorkspace << actionToggleDatabase << actionToggleRte << actionToggleDocks << actionToggleToolBar << actionFullScreen; QAction * separator1 = new QAction("---------------",this); separator1->setSeparator(true); separator1->setObjectName("separator"); QList defaultActions; defaultActions << actionSearchGoogle << actionAddEmptyProject << actionLoadGISData << actionSaveGISData << separator << actionShowScale << actionShowGrid << actionPOIText << actionNightDay << actionMapToolTip << actionMinMaxTrackValues << actionProfileIsWindow << separator1 << actionSetupToolbar << actionToggleMaps << actionToggleDem << actionToggleWorkspace << actionToggleDatabase << actionToggleRte << actionToggleDocks << actionFullScreen; toolBarConfig = new CToolBarConfig(this, toolBar, availableActions, defaultActions); toolBarConfig->loadSettings(); prepareMenuForMac(); // make sure all actions that have a shortcut are available even when menu and toolbar are not visible for (QAction * action : availableActions) { if (!action->shortcuts().isEmpty()) { addAction(action); } } loadGISData(qlOpts->arguments); QTimer::singleShot(100, this, SLOT(slotSanityTest())); } void CMainWindow::prepareMenuForMac() { toolBar->toggleViewAction()->setMenuRole(QAction::NoRole); dockMaps->toggleViewAction()->setMenuRole(QAction::NoRole); dockDem->toggleViewAction()->setMenuRole(QAction::NoRole); dockWorkspace->toggleViewAction()->setMenuRole(QAction::NoRole); dockDatabase->toggleViewAction()->setMenuRole(QAction::NoRole); dockRte->toggleViewAction()->setMenuRole(QAction::NoRole); } CMainWindow::~CMainWindow() { CActivityTrk::release(); SETTINGS; cfg.beginGroup("MainWindow"); cfg.setValue("state", saveState()); cfg.setValue("geometry", saveGeometry()); cfg.setValue("units", IUnit::self().type); QStringList activeDockNames; for (QDockWidget * const & dock : activeDocks) { activeDockNames << dock->objectName(); } cfg.setValue("activedocks",activeDockNames); cfg.setValue("displaymode",static_cast(displayMode)); cfg.setValue("dockstate",dockStates); cfg.setValue("menuvisible",menuVisible); cfg.endGroup(); /* The "Canvas" section will hold all settings global to all views and "Views" section containing a subsection for each view. */ cfg.beginGroup("Canvas"); QList allViews; QList allOtherTabs; // save setup of all views cfg.beginGroup("Views"); // remove all previous setups in this section first cfg.remove(QString()); for(int i = 0; i < tabWidget->count(); i++) { CCanvas * view = dynamic_cast(tabWidget->widget(i)); if(nullptr == view) { allOtherTabs << tabWidget->widget(i); continue; } // save views cfg.beginGroup(view->objectName()); view->saveConfig(cfg); cfg.endGroup(); allViews << view; } cfg.endGroup(); // Views cfg.setValue("gisLayerOpacity", CCanvas::gisLayerOpacity); cfg.setValue("visibleCanvas", tabWidget->currentIndex()); cfg.setValue("isScaleVisible", actionShowScale->isChecked()); cfg.setValue("isGridVisible", actionShowGrid->isChecked()); cfg.setValue("POIText", actionPOIText->isChecked()); cfg.setValue("MapToolTip", actionMapToolTip->isChecked()); cfg.setValue("isNight", actionNightDay->isChecked()); cfg.setValue("MinMaxTrackValues", actionMinMaxTrackValues->isChecked()); cfg.setValue("flipMouseWheel", actionFlipMouseWheel->isChecked()); cfg.setValue("profileIsWindow",actionProfileIsWindow->isChecked()); cfg.setValue("mapFont", mapFont); CMapDraw::saveMapPath(cfg); CDemDraw::saveDemPath(cfg); cfg.endGroup(); // Canvas /* Delete all widgets in the tab widget other than views. The IPlot objects in a track detail dialog send update events to the view on destruction. So it is important that these are destroyed first. */ qDeleteAll(allOtherTabs); /* Delete all canvas objects now to make sure they are destroyed before all other objects. This allows children of the canvas to access central objects like CGisWorkspace safely upon their destruction. (e.g. CMouseRangeTrk to reset it's track's draw mode by key) */ qDeleteAll(allViews); QByteArray tz; IUnit::tz_mode_e tzmode; bool useShortFormat; IUnit::getTimeZoneSetup(tzmode, tz, useShortFormat); cfg.setValue("Units/timezone", tz); cfg.setValue("Units/timezone/mode", tzmode); cfg.setValue("Units/time/useShortFormat", useShortFormat); cfg.setValue("Units/coordFormat", IUnit::getCoordFormat()); cfg.setValue("Units/slopeMode", IUnit::getSlopeMode()); toolBarConfig->saveSettings(); } CCanvas *CMainWindow::addView(const QString& name) { CCanvas * view = new CCanvas(tabWidget, name); tabWidget->addTab(view, view->objectName()); connect(view, &CCanvas::sigMousePosition, this, &CMainWindow::slotMousePosition); connect(actionMinMaxTrackValues, &QAction::triggered, view, &CCanvas::slotUpdateTrackStatistic); return view; } QWidget * CMainWindow::getBestWidgetForParent() { QWidget * w = CProgressDialog::self(); if(w) { return w; } // this is a workaround for unittesting if(nullptr == pSelf) { return nullptr; } w = self().getVisibleCanvas(); if(w) { return w; } return &self(); } QString CMainWindow::getUser() { QString user = getenv("USER"); if(user.isEmpty()) { user = getenv("USERNAME"); //for windows if(user.isEmpty()) { user = "QMapShack"; } } return user; } bool CMainWindow::isScaleVisible() const { return actionShowScale->isChecked(); } bool CMainWindow::isGridVisible() const { return actionShowGrid->isChecked(); } bool CMainWindow::isNight() const { return actionNightDay->isChecked(); } bool CMainWindow::isPOIText() const { return actionPOIText->isChecked(); } bool CMainWindow::isMapToolTip() const { return actionMapToolTip->isChecked(); } bool CMainWindow::isMinMaxTrackValues() const { return actionMinMaxTrackValues->isChecked(); } bool CMainWindow::flipMouseWheel() const { return actionFlipMouseWheel->isChecked(); } bool CMainWindow::profileIsWindow() const { return actionProfileIsWindow->isChecked(); } void CMainWindow::addMapList(CMapList * list, const QString &name) { tabMaps->addTab(list,name); connect(list, &CMapList::sigSetupMapPath, this, &CMainWindow::slotSetupMapPath); } void CMainWindow::addDemList(CDemList * list, const QString &name) { tabDem->addTab(list,name); connect(list, &CDemList::sigSetupDemPath, this, &CMainWindow::slotSetupDemPath); } void CMainWindow::addWidgetToTab(QWidget * w) { if(tabWidget->indexOf(w) == NOIDX) { tabWidget->addTab(w, w->objectName().replace("&", "&&")); } tabWidget->setCurrentWidget(w); } CCanvas* CMainWindow::getVisibleCanvas() const { return dynamic_cast(tabWidget->currentWidget()); } QList CMainWindow::getCanvas() const { QList result; const int N = tabWidget->count(); for(int n = 0; n < N; n++) { CCanvas * canvas = dynamic_cast(tabWidget->widget(n)); if(canvas != nullptr) { result << canvas; } } return result; } void CMainWindow::zoomCanvasTo(const QRectF rect) { CCanvas * canvas = getVisibleCanvas(); if(canvas) { canvas->zoomTo(rect); } } qreal CMainWindow::getElevationAt(const QPointF& pos) const { CCanvas * canvas = getVisibleCanvas(); if(canvas) { return canvas->getElevationAt(pos); } else { for(int i = 0; i < tabWidget->count(); i++) { canvas = dynamic_cast(tabWidget->widget(i)); if(canvas) { return canvas->getElevationAt(pos); } } } return NOFLOAT; } void CMainWindow::getElevationAt(SGisLine &line) const { CCanvas * canvas = getVisibleCanvas(); if(canvas) { canvas->getElevationAt(line); } else { for(int i = 0; i < tabWidget->count(); i++) { canvas = dynamic_cast(tabWidget->widget(i)); if(canvas) { canvas->getElevationAt(line); return; } } for(int i = 0; i < line.size(); i++) { line[i].resetElevation(); } } } void CMainWindow::getElevationAt(const QPolygonF &pos, QPolygonF& ele) const { CCanvas * canvas = getVisibleCanvas(); if(canvas) { canvas->getElevationAt(pos, ele); } else { for(int i = 0; i < tabWidget->count(); i++) { canvas = dynamic_cast(tabWidget->widget(i)); if(canvas) { canvas->getElevationAt(pos, ele); return; } } ele.clear(); } } qreal CMainWindow::getSlopeAt(const QPointF& pos) const { CCanvas * canvas = getVisibleCanvas(); if(canvas) { return canvas->getSlopeAt(pos); } else { for(int i = 0; i < tabWidget->count(); i++) { canvas = dynamic_cast(tabWidget->widget(i)); if(canvas) { return canvas->getSlopeAt(pos); } } } return NOFLOAT; } void CMainWindow::getSlopeAt(const QPolygonF &pos, QPolygonF& slope) const { CCanvas * canvas = getVisibleCanvas(); if(canvas) { canvas->getSlopeAt(pos, slope); } else { for(int i = 0; i < tabWidget->count(); i++) { canvas = dynamic_cast(tabWidget->widget(i)); if(canvas) { canvas->getSlopeAt(pos, slope); return; } } slope.clear(); } } void CMainWindow::slotAbout() { CAbout dlg(this); dlg.exec(); } void CMainWindow::slotHelp() { QDesktopServices::openUrl(QUrl("https://bitbucket.org/maproom/qmapshack/wiki/DocMain")); } void CMainWindow::slotQuickstart() { // show menu action for German help if system language is German. QString locale = QLocale::system().name(); if(locale.size() >= 2) { locale = locale.left(2).toLower(); if(locale == "de") { QDesktopServices::openUrl(QUrl("https://bitbucket.org/maproom/qmapshack/wiki/DocQuickStartGerman")); } else if(locale == "ru") { QDesktopServices::openUrl(QUrl("https://bitbucket.org/maproom/qmapshack/wiki/DocQuickStartRussian")); } else { QDesktopServices::openUrl(QUrl("https://bitbucket.org/maproom/qmapshack/wiki/DocQuickStartEnglish")); } } else { QDesktopServices::openUrl(QUrl("https://bitbucket.org/maproom/qmapshack/wiki/DocQuickStartEnglish")); } } void CMainWindow::slotAddCanvas() { int i, cnt = 0; for(i = 0; i < tabWidget->count(); i++) { CCanvas * canvas = dynamic_cast(tabWidget->widget(i)); if(nullptr != canvas) { cnt++; } } CCanvas * view = addView(QString()); tabWidget->setCurrentWidget(view); testForNoView(); } void CMainWindow::slotCloneCanvas() { CCanvas * source = getVisibleCanvas(); if(nullptr == source) { return; } QTemporaryFile temp; temp.open(); temp.close(); QSettings view(temp.fileName(), QSettings::IniFormat); view.clear(); source->saveConfig(view); slotAddCanvas(); CCanvas * target = getVisibleCanvas(); if(nullptr == target) { return; } target->loadConfig(view); target->slotTriggerCompleteUpdate(CCanvas::redraw_e::eRedrawGis); SETTINGS; cfg.beginGroup("Canvas"); cfg.beginGroup("Views"); cfg.beginGroup(target->objectName()); target->saveConfig(cfg); cfg.endGroup(); cfg.endGroup(); cfg.endGroup(); testForNoView(); } void CMainWindow::testForNoView() { if(tabWidget->count() == 0) { QLabel * label = new QLabel(tabWidget); label->setAlignment(Qt::AlignCenter); label->setWordWrap(true); label->setText(tr("Use Menu->View->Add Map View to open a new view. Or Menu->File->Load Map View to restore a saved one. Or click here.")); label->setObjectName("NoViewInfo"); connect(label, &QLabel::linkActivated, this, &CMainWindow::slotLinkActivated); tabWidget->addTab(label, "*"); return; } QLabel * label = tabWidget->findChild("NoViewInfo"); if(label && tabWidget->count() > 1) { delete label; } } void CMainWindow::slotTabCloseRequest(int i) { QMutexLocker lock(&CMapItem::mutexActiveMaps); delete tabWidget->widget(i); testForNoView(); } static inline bool compareNames(QString s1, QString s2) { return s1.replace("&", "") == s2.replace("&", ""); } void CMainWindow::slotCurrentTabCanvas(int i) { QString name = tabWidget->tabText(i); for(int n = 0; n < tabMaps->count(); n++) { bool isMapView = compareNames(name, tabMaps->tabText(n)); actionSetupGrid->setEnabled(isMapView); actionSetupMapBackground->setEnabled(isMapView); actionSetupMapView->setEnabled(isMapView); if(isMapView) { tabMaps->setCurrentIndex(n); break; } } for(int n = 0; n < tabDem->count(); n++) { if(compareNames(name, tabDem->tabText(n))) { tabDem->setCurrentIndex(n); break; } } for(int n = 0; n < tabWidget->count(); n++) { CCanvas * canvas = dynamic_cast(tabWidget->widget(n)); if(canvas) { if(n == i) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); canvas->showProfile(true); } else { canvas->showProfile(false); } } } } void CMainWindow::slotCurrentTabMaps(int i) { QString name = tabMaps->tabText(i); for(int n = 0; n < tabWidget->count(); n++) { if(compareNames(name, tabWidget->tabText(n))) { tabWidget->setCurrentIndex(n); break; } } for(int n = 0; n < tabDem->count(); n++) { if(compareNames(name, tabDem->tabText(n))) { tabDem->setCurrentIndex(n); break; } } } void CMainWindow::slotCurrentTabDem(int i) { QString name = tabMaps->tabText(i); for(int n = 0; n < tabWidget->count(); n++) { if(compareNames(name, tabWidget->tabText(n))) { tabWidget->setCurrentIndex(n); break; } } for(int n = 0; n < tabMaps->count(); n++) { if(compareNames(name, tabMaps->tabText(n))) { tabMaps->setCurrentIndex(n); break; } } } void CMainWindow::slotMousePosition(const QPointF& pos, qreal ele, qreal slope) { QString str; IUnit::degToStr(pos.x(), pos.y(), str); lblPosWGS84->setText(str); if(ele != NOFLOAT) { QString val, unit; IUnit::self().meter2elevation(ele, val, unit); lblElevation->setText(tr("Ele.: %1%2").arg(val).arg(unit)); lblElevation->show(); } else { lblElevation->hide(); } if(slope != NOFLOAT) { QString val; val.sprintf("%.1f", slope); lblSlope->setText(tr("Slope: %1%2", "terrain").arg(val).arg("°")); lblSlope->show(); } else { lblSlope->hide(); } if(actionShowGrid->isChecked()) { CCanvas * canvas = getVisibleCanvas(); if(canvas) { QString str; lblPosGrid->show(); canvas->convertGridPos2Str(pos, str, false); lblPosGrid->setText(tr("[Grid: %1]").arg(str)); } } else { lblPosGrid->hide(); } } void CMainWindow::slotUpdateCurrentWidget() { CCanvas * canvas = getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); return; } QWidget * w = tabWidget->currentWidget(); if(w) { w->update(); return; } } void CMainWindow::slotSetupMapFont() { bool ok = false; QFont f = QFontDialog::getFont(&ok, mapFont, this); if(ok) { mapFont = f; QWidget * w = tabWidget->currentWidget(); if(w) { w->update(); } } } void CMainWindow::slotSetupMapBackground() { CCanvas * canvas = getVisibleCanvas(); if(nullptr == canvas) { return; } canvas->setupBackgroundColor(); } void CMainWindow::slotSetupGrid() { CCanvas * canvas = getVisibleCanvas(); if(nullptr == canvas) { return; } canvas->setupGrid(); } void CMainWindow::slotSetupMapPath() { CMapDraw::setupMapPath(); } void CMainWindow::slotSetupDemPath() { CDemDraw::setupDemPath(); } void CMainWindow::slotSetupMapView() { CCanvas * canvas = getVisibleCanvas(); if(nullptr == canvas) { return; } canvas->setup(); } void CMainWindow::slotSetupTimeZone() { CTimeZoneSetup dlg(this); dlg.exec(); } void CMainWindow::slotSetupUnits() { CUnitsSetup dlg(this); dlg.exec(); if(QDialog::Accepted == dlg.result()) { CKnownExtension::init(IUnit::self()); } } void CMainWindow::slotSetupWorkspace() { CSetupWorkspace dlg(this); dlg.exec(); } void CMainWindow::slotSetupCoordFormat() { CCoordFormatSetup dlg(this); dlg.exec(); } void CMainWindow::slotSetupToolbar() { CToolBarSetupDialog dlg(this,toolBarConfig); dlg.exec(); } void CMainWindow::slotImportDatabase() { CImportDatabase * widget = new CImportDatabase(this); addWidgetToTab(widget); } void CMainWindow::slotBuildVrt() { CMapVrtBuilder * widget = new CMapVrtBuilder(this); addWidgetToTab(widget); } void CMainWindow::slotCreateRoutinoDatabase() { CRoutinoDatabaseBuilder * widget = new CRoutinoDatabaseBuilder(this); addWidgetToTab(widget); } void CMainWindow::slotLoadGISData() { SETTINGS; QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString(); QString filter = cfg.value("Paths/lastGisFilter", IGisProject::filedialogAllSupported).toString(); QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Load GIS Data..."), path, IGisProject::filedialogLoadFilters, &filter); if(filenames.isEmpty()) { return; } loadGISData(filenames); path = QFileInfo(filenames.first()).absolutePath(); cfg.setValue("Paths/lastGisPath", path); cfg.setValue("Paths/lastGisFilter", filter); } void CMainWindow::loadGISData(const QStringList& filenames) { for(const QString &filename : filenames) { widgetGisWorkspace->loadGisProject(filename); } } void CMainWindow::slotStoreView() { CCanvas * canvas = getVisibleCanvas(); if(nullptr == canvas) { return; } SETTINGS; QString path = cfg.value("Paths/lastViewPath", QDir::homePath()).toString(); QString filename = QFileDialog::getSaveFileName( this, tr("Select output file"), path, tr("QMapShack View (*.view)")); if(filename.isEmpty()) { return; } QFileInfo fi(filename); if(fi.suffix().toLower() != "view") { filename += ".view"; } QSettings view(filename, QSettings::IniFormat); view.clear(); canvas->saveConfig(view); path = fi.absolutePath(); cfg.setValue("Paths/lastViewPath", path); } void CMainWindow::slotLoadView() { SETTINGS; QString path = cfg.value("Paths/lastViewPath", QDir::homePath()).toString(); QString filename = QFileDialog::getOpenFileName(this, tr("Select file to load"), path, tr("QMapShack View (*.view)")); if(filename.isEmpty()) { return; } slotAddCanvas(); CCanvas * canvas = getVisibleCanvas(); if(nullptr == canvas) { return; } QSettings view(filename, QSettings::IniFormat); canvas->loadConfig(view); cfg.beginGroup("Canvas"); cfg.beginGroup("Views"); cfg.beginGroup(canvas->objectName()); canvas->saveConfig(cfg); cfg.endGroup(); // objectName cfg.endGroup(); // "Views" cfg.endGroup(); // "Canvas" QFileInfo fi(filename); path = fi.absolutePath(); cfg.setValue("Paths/lastViewPath", path); } void CMainWindow::slotSetProfileMode(bool on) { for(int i = 0; i < tabWidget->count(); i++) { CCanvas * view = dynamic_cast(tabWidget->widget(i)); if(nullptr != view) { view->showProfileAsWindow(on); } } } void CMainWindow::slotPrintMap() { CCanvas * canvas = getVisibleCanvas(); if(nullptr != canvas) { canvas->setMousePrint(); } } void CMainWindow::slotLinkActivated(const QString& link) { if(link == "newview") { actionAddMapView->trigger(); } } void CMainWindow::slotSetupWptIcons() { CWptIconDialog dlg(this); dlg.exec(); } void CMainWindow::slotCloseTab() { CCanvas * canvas = dynamic_cast(tabWidget->currentWidget()); if(canvas == nullptr) { QWidget * widget = tabWidget->currentWidget(); if(widget != nullptr) { widget->deleteLater(); } } } void CMainWindow::slotToggleDocks() { if (docksVisible()) { dockStates = saveState(); hideDocks(); } else { showDocks(); if (!dockStates.isEmpty()) { restoreState(dockStates); } } } bool CMainWindow::docksVisible() const { for (QDockWidget * const & dock : docks) { if (!dock->isHidden()) { return true; } } return false; } void CMainWindow::showDocks() const { if (activeDocks.isEmpty()) { for (QDockWidget * const & dock : docks) { dock->show(); } } else { const QList docksToShow(activeDocks); for (QDockWidget * const & dock : docksToShow) { dock->show(); } } } void CMainWindow::hideDocks() { activeDocks.clear(); for (QDockWidget * const & dock : docks) { if (!dock->isHidden()) { dock->hide(); activeDocks << dock; } } } void CMainWindow::slotDockVisibilityChanged(bool visible) { if (visible) { activeDocks.clear(); } else { for (QDockWidget * const & dock : docks) { if (!dock->isHidden()) { visible = true; break; } } } actionToggleDocks->setChecked(visible); } void CMainWindow::slotFullScreen() { QMutexLocker lock(&CMainWindow::mutex); Qt::WindowStates state = windowState(); if(state == Qt::WindowFullScreen) { displayRegular(); } else { displayMode = state; displayFullscreen(); } } void CMainWindow::displayRegular() { if (!dockStates.isEmpty()) { restoreState(dockStates); } tabWidget->tabBar()->setVisible(true); statusBar()->setVisible(true); if (menuVisible) { menuBar()->setVisible(true); } actionFullScreen->setIcon(QIcon(":/icons/32x32/FullScreen.png")); setWindowState(displayMode); } void CMainWindow::displayFullscreen() { dockStates = saveState(); setWindowState(Qt::WindowFullScreen); statusBar()->setVisible(false); menuVisible = menuBar()->isVisible(); // menu is handled dynamically as on some platforms (e.g. ubuntu with unity) // the menu is not visible but it's actions are active nevertheless if (menuVisible) { menuBar()->setVisible(false); } if (docksVisible()) { hideDocks(); } if (!toolBarConfig->visibleInFullscreen()) { toolBar->setVisible(false); } tabWidget->tabBar()->setVisible(false); actionFullScreen->setIcon(QIcon(":/icons/32x32/RegularScreen.png")); } #ifdef WIN32 static void sendDeviceEvent(DWORD unitmask, bool add) { for (char i = 0; i < 26; ++i) { if (unitmask & 0x1) { QString path = QString(i + 'A') + ":/"; qDebug() << "sendDeviceEvent" << path << add; CEventDevice * event = new CEventDevice(path, add); QCoreApplication::postEvent(CDeviceWatcherWindows::self(), event); //qDebug() << "postEvent"; } unitmask = unitmask >> 1; } } bool CMainWindow::nativeEvent(const QByteArray & eventType, void * message, long * result) { MSG* msg = (MSG*)message; //qDebug() << "nativeEvent" << eventType << msg->message << msg->lParam << msg->wParam; if (WM_DEVICECHANGE == msg->message) { //qDebug() << "WM_DEVICECHANGE"; PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)msg->lParam; switch (msg->wParam) { case DBT_DEVICEARRIVAL: { qDebug() << "DBT_DEVICEARRIVAL"<< pHdr->dbch_devicetype; if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME pHdrv = (PDEV_BROADCAST_VOLUME)pHdr; sendDeviceEvent(pHdrv->dbcv_unitmask, true); } break; } case DBT_DEVICEREMOVECOMPLETE: { qDebug() << "DBT_DEVICEREMOVECOMPLETE" << pHdr->dbch_devicetype; if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME pHdrv = (PDEV_BROADCAST_VOLUME)pHdr; sendDeviceEvent(pHdrv->dbcv_unitmask, false); } break; } default: { break; } } } return QWidget::nativeEvent(eventType, message, result); } #endif // WIN32 void CMainWindow::dragEnterEvent(QDragEnterEvent *event) { if(event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); QFileInfo fi(urls[0].path()); QString ext = fi.suffix().toUpper(); if ((ext == "QMS") || (ext == "GPX") || (ext == "SLF") || (ext == "FIT") || (ext == "TCX") || (ext == "SML") || (ext == "LOG")) { event->acceptProposedAction(); } } } void CMainWindow::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); QStringList filenames; for(const QUrl &url : urls) { filenames << url.toLocalFile(); } loadGISData(filenames); event->acceptProposedAction(); } void CMainWindow::slotSanityTest() { projPJ pjsrc = pj_init_plus("+init=epsg:32661"); if(pjsrc == nullptr) { QMessageBox::critical(this, tr("Fatal...") ,tr("QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it.") ,QMessageBox::Close); deleteLater(); return; } pj_free(pjsrc); qDebug() << "Sanity test passed."; } qmapshack-1.10.0/src/setup/000755 001750 000144 00000000000 13216664443 016662 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/setup/CAppOpts.h000644 001750 000144 00000003241 13216234142 020511 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2009 Joerg Wunsch 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 . **********************************************************************************************/ #ifndef CAPPOPTS_H #define CAPPOPTS_H /* * This class holds the options passed from the command-line, * including the positional arguments. */ #include class CAppOpts { public: const bool debug; // -d, print debug messages const bool logfile; // -f, print debug messages to logfile const bool nosplash; // -n, do not display splash screen const QString configfile; const QStringList arguments; CAppOpts(bool doDebug, bool doLogfile, bool noSplash, const QString& config, const QStringList& args) : debug(doDebug) , logfile(doLogfile) , nosplash(noSplash) , configfile(config) , arguments(args) { } }; extern CAppOpts *qlOpts; #endif //CAPPOPTS_H qmapshack-1.10.0/src/setup/CAppSetupLinux.cpp000644 001750 000144 00000004231 13216234137 022243 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "CAppSetupLinux.h" #include "config.h" #ifndef _MKSTR_1 #define _MKSTR_1(x) #x #define _MKSTR(x) _MKSTR_1(x) #endif void CAppSetupLinux::initQMapShack() { prepareGdal("", ""); // setup translators QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); QString translationPath = QCoreApplication::applicationDirPath(); translationPath.replace(QRegExp("bin$"), "share/qmapshack/translations"); prepareTranslator(resourceDir, "qt_"); prepareTranslator(translationPath, "qmapshack_"); // create directories IAppSetup::path(defaultCachePath(), 0, true, "CACHE"); IAppSetup::path(userDataPath("WaypointIcons"), 0, true, "USER DATA"); IAppSetup::path(logDir(), 0, true, "LOG"); } QString CAppSetupLinux::routinoPath(QString xmlFile) { QDir dirXml(_MKSTR(ROUTINO_XML_PATH)); return IAppSetup::path(dirXml.absolutePath(), xmlFile, false, "ROUTINO"); } QString CAppSetupLinux::defaultCachePath() { return IAppSetup::path(QDir::home().absolutePath(), ".QMapShack/", false, 0); } QString CAppSetupLinux::userDataPath(QString subdir) { QString path = QDir::home().absoluteFilePath(CONFIGDIR); return IAppSetup::path(path, subdir, false, 0); } QString CAppSetupLinux::logDir() { return QDir::temp().absolutePath(); } qmapshack-1.10.0/src/setup/CAppSetupWin.cpp000644 001750 000144 00000005136 13216234137 021706 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "CAppSetupWin.h" #include "config.h" void CAppSetupWin::initQMapShack() { // setup environment variables for GDAL/Proj4 QString apppath = QCoreApplication::applicationDirPath(); apppath = apppath.replace("/", "\\"); QString gdalDir = QString("%1\\data").arg(apppath); QString projDir = QString("%1\\share").arg(apppath); qunsetenv("GDAL_DRIVER_PATH"); IAppSetup::prepareGdal(gdalDir, projDir); QString appResourceDir = QString("%1\\translations").arg(apppath).toUtf8(); prepareTranslator(appResourceDir, "qtbase_"); prepareTranslator(appResourceDir, "qmapshack_"); path = qgetenv("PATH"); //reset PATH to avoid that wrong .dll's are loaded qputenv("PATH", ""); // create directories IAppSetup::path(defaultCachePath(), 0, true, "CACHE"); IAppSetup::path(userDataPath("WaypointIcons"), 0, true, "USER DATA"); IAppSetup::path(logDir(), 0, true, "LOG"); } QString CAppSetupWin::routinoPath(QString xmlFile) { QString apppath = QCoreApplication::applicationDirPath(); apppath = apppath.replace("/", "\\"); QDir dirXml(QString("%1\\routino-xml").arg(apppath).toUtf8()); return IAppSetup::path(dirXml.absolutePath(), xmlFile, false, "ROUTINO"); } QString CAppSetupWin::defaultCachePath() { return IAppSetup::path(QDir::home().absolutePath(), ".QMapShack/", false, 0); } QString CAppSetupWin::userDataPath(QString subdir) { QString path = QDir::home().absoluteFilePath(CONFIGDIR); return IAppSetup::path(path, subdir, false, 0); } QString CAppSetupWin::logDir() { return QDir::temp().absolutePath(); } QString CAppSetupWin::findExecutable(const QString &name) { qputenv("PATH",path); return QStandardPaths::findExecutable(name); qputenv("PATH",""); } qmapshack-1.10.0/src/setup/IAppSetup.h000644 001750 000144 00000003253 13216234142 020675 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IAPPSETUP_H #define IAPPSETUP_H #include "CAppOpts.h" #include #include class IAppSetup { public: static IAppSetup *getPlatformInstance(); virtual void initQMapShack() = 0; void initLogHandler(); void processArguments(); virtual QString routinoPath(QString xmlFile) = 0; virtual QString defaultCachePath() = 0; virtual QString userDataPath(QString subdir = 0) = 0; virtual QString logDir() = 0; virtual QString findExecutable(const QString &name) = 0; protected: void prepareGdal(QString gdalDir, QString projDir); void prepareTranslator(QString translationPath, QString translationPrefix); static IAppSetup* instance; QString path(QString path, QString subdir, bool mkdir, QString debugName); }; #endif // IAPPSETUP_H qmapshack-1.10.0/src/setup/CCommandProcessor.h000644 001750 000144 00000002241 13216234142 022400 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCOMMANDPROCESSOR_H #define CCOMMANDPROCESSOR_H #include "setup/CAppOpts.h" #include class CCommandProcessor { Q_DECLARE_TR_FUNCTIONS(CCommandProcessor) public: CAppOpts* processOptions(const QStringList &arguments); }; #endif // CCOMMANDPROCESSOR_H qmapshack-1.10.0/src/setup/CLogHandler.cpp000644 001750 000144 00000006667 13216234137 021520 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "CLogHandler.h" #include CLogHandler::CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput) : writeToFile(writeToFile), debugOutput(debugOutput), logFile(QDir(logDirectory).absoluteFilePath(logfileName())), fileStream(&logFile) { if (writeToFile) { fileStream.setCodec("UTF-8"); logFile.open(QIODevice::WriteOnly | QIODevice::Append); } qSetMessagePattern("%{time yyyy-MM-dd h:mm:ss.zzz} [%{type}] %{message}"); } void CLogHandler::log(QtMsgType type, const QMessageLogContext &context, const QString &msg) { #if QT_VERSION >= 0x050400 QString txt = qFormatLogMessage(type, context, msg); #else QString txt = msg; #endif printToConsole(type, txt); appendToFile(type, txt); } void CLogHandler::printLoggerInfo() { qDebug() << "Log configuration:" << "log file=" << logFile.fileName() << "write to file=" << writeToFile << "debug output=" << debugOutput; } QString CLogHandler::logfileName() { QStringList domainSplit = QCoreApplication::organizationDomain().split("."); QString fileName; for(const QString &part : domainSplit) { fileName = fileName.insert(0, part + "."); } fileName.append(QCoreApplication::applicationName() + ".log"); return fileName; } void CLogHandler::appendToFile(QtMsgType type, QString formatedMsg) { Q_UNUSED(type); if (writeToFile) { fileStream << formatedMsg << endl; } } void CLogHandler::printToConsole(QtMsgType type, QString formatedMsg) { switch (type) { case QtDebugMsg: if (debugOutput) { std::cout << formatedMsg.toUtf8().constData() << std::endl; } break; #if QT_VERSION >= 0x050500 case QtInfoMsg: std::cout << formatedMsg.toUtf8().constData() << std::endl; break; #endif case QtWarningMsg: std::cerr << formatedMsg.toUtf8().constData() << std::endl; break; case QtCriticalMsg: std::cerr << formatedMsg.toUtf8().constData() << std::endl; break; case QtFatalMsg: std::cerr << formatedMsg.toUtf8().constData() << std::endl; abort(); break; } } static CLogHandler* logHandler = nullptr; static void logCallback(QtMsgType type, const QMessageLogContext &context, const QString &msg) { logHandler->log(type, context, msg); } void CLogHandler::initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput) { logHandler = new CLogHandler(logDirectory, writeToFile, debugOutput); qInstallMessageHandler(logCallback); logHandler->printLoggerInfo(); } qmapshack-1.10.0/src/setup/CAppSetupLinux.h000644 001750 000144 00000002537 13216234142 021713 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CAPPSETUPLINUX_H #define CAPPSETUPLINUX_H #include "setup/IAppSetup.h" #include class CAppSetupLinux : public IAppSetup { public: void initQMapShack() override; QString routinoPath(QString xmlFile) override; QString defaultCachePath() override; QString userDataPath(QString subdir = 0) override; QString logDir() override; QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); } }; #endif // CAPPSETUPLINUX_H qmapshack-1.10.0/src/setup/IAppSetup.cpp000644 001750 000144 00000007045 13216234137 021237 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CCommandProcessor.h" #include "setup/CLogHandler.h" #include "setup/IAppSetup.h" #include "setup/CAppSetupLinux.h" #include "setup/CAppSetupMac.h" #include "setup/CAppSetupWin.h" #include IAppSetup* IAppSetup::instance = nullptr; IAppSetup* IAppSetup::getPlatformInstance() { if(nullptr == instance) { #if defined(Q_OS_MAC) instance = new CAppSetupMac(); #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(__FreeBSD_kernel__) || defined(__GNU__) instance = new CAppSetupLinux(); #elif defined (Q_OS_WIN32) instance = new CAppSetupWin(); #else #error OS not supported #endif } return instance; } void IAppSetup::prepareGdal(QString gdalDir, QString projDir) { if(!gdalDir.isEmpty()) { qputenv("GDAL_DATA", gdalDir.toUtf8()); qDebug() << "GDAL_DATA directory set to " + gdalDir; } if(!projDir.isEmpty()) { qputenv("PROJ_LIB", projDir.toUtf8()); qDebug() << "PROJ_LIB directory set to " + projDir; } GDALAllRegister(); } QString IAppSetup::path(QString path, QString subdir, bool mkdir, QString debugName) { QDir pathDir(path); if(subdir != 0) { pathDir = QDir(pathDir.absoluteFilePath(subdir)); } if(mkdir && !pathDir.exists()) { pathDir.mkpath(pathDir.absolutePath()); qDebug() << debugName << "path created" << pathDir.absolutePath(); } else if (debugName != 0) { qDebug() << debugName << "path" << pathDir.absolutePath(); } return pathDir.absolutePath(); } void IAppSetup::prepareTranslator(QString translationPath, QString translationPrefix) { QString locale = QLocale::system().name(); QDir dir(translationPath); if(!QFile::exists(dir.absoluteFilePath(translationPrefix + locale))) { locale = locale.left(2); } qDebug() << "locale" << locale; QApplication* app = (QApplication*) QCoreApplication::instance(); QTranslator *qtTranslator = new QTranslator(app); if (qtTranslator->load(translationPrefix + locale, translationPath)) { app->installTranslator(qtTranslator); qDebug() << "using file '"+ translationPath + "/" + translationPrefix + locale + ".qm' for translations."; } else { qWarning() << "no file found for translations '"+ translationPath + "/" + translationPrefix + locale + "' (using default)."; } } void IAppSetup::initLogHandler() { CLogHandler::initLogHandler(logDir(), qlOpts->logfile, qlOpts->debug); } CAppOpts *qlOpts = nullptr; void IAppSetup::processArguments() { CCommandProcessor cmdParse; qlOpts = cmdParse.processOptions(QCoreApplication::instance()->arguments()); } qmapshack-1.10.0/src/setup/CAppSetupWin.h000644 001750 000144 00000002474 13216234142 021351 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CAPPSETUPWIN_H #define CAPPSETUPWIN_H #include "setup/IAppSetup.h" #include class CAppSetupWin : public IAppSetup { public: void initQMapShack() override; QString routinoPath(QString xmlFile) override; QString defaultCachePath() override; QString userDataPath(QString subdir = 0) override; QString logDir() override; QString findExecutable(const QString &name) override; QByteArray path; }; #endif // CAPPSETUPWIN_H qmapshack-1.10.0/src/setup/CLogHandler.h000644 001750 000144 00000002767 13216234142 021156 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CLOGHANDLER_H #define CLOGHANDLER_H #include class CLogHandler { public: static void initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput); void log(QtMsgType type, const QMessageLogContext &context, const QString &msg); private: CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput); void printLoggerInfo(); void appendToFile(QtMsgType type, QString formatedMsg); void printToConsole(QtMsgType type, QString formatedMsg); QString logfileName(); bool writeToFile; bool debugOutput; QFile logFile; QTextStream fileStream; }; #endif // CLOGHANDLER_H qmapshack-1.10.0/src/setup/CAppSetupMac.cpp000644 001750 000144 00000012021 13216234137 021640 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "setup/CAppSetupMac.h" static QString relTranslationDir = "Resources/translations"; // app static QString relRoutinoDir = "Resources/routino"; // app static QString relGdalDir = "Resources/gdal"; // app static QString relProjDir = "Resources/proj"; // app static QString relBinDir = "Tools"; // app static QString relLogDir = "Library/Logs"; // home void CAppSetupMac::extendPath() { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QStringList envlist = env.toStringList(); QString value = ""; for(int i=0; i < envlist.size(); i++) { QString entry = envlist[i]; if(entry.startsWith("PATH=")) { int index = entry.indexOf("="); if(index != -1) { value = entry.right(entry.length() - (index+1)) + ":"; } break; } } QString binDir = getApplicationDir(relBinDir).absolutePath(); qDebug() << "BIN" << binDir; value += binDir; qputenv("PATH", value.toLatin1().constData()); } void CAppSetupMac::initQMapShack() { extendPath(); // setup gdal QString gdalDir = getApplicationDir(relGdalDir).absolutePath(); QString projDir = getApplicationDir(relProjDir).absolutePath(); prepareGdal(gdalDir, projDir); // setup translators QString translationPath = getApplicationDir(relTranslationDir).absolutePath(); prepareTranslator(translationPath, "qt_"); prepareTranslator(translationPath, "qmapshack_"); // load and apply style sheet QApplication* app = (QApplication*) QCoreApplication::instance(); QString fileName = QDir(getApplicationDir("Resources")).absoluteFilePath("qms-style.qss"); qDebug() << "Stylesheet" << fileName; QFile styleFile(fileName); styleFile.open(QFile::ReadOnly); QString style(QLatin1String(styleFile.readAll())); app->setStyleSheet(style); migrateDirContent(defaultCachePath()); migrateDirContent(userDataPath()); // create directories IAppSetup::path(defaultCachePath(), 0, true, "CACHE"); IAppSetup::path(userDataPath("WaypointIcons"), 0, true, "USER DATA"); IAppSetup::path(logDir(), 0, false, "LOG"); } QString CAppSetupMac::routinoPath(QString xmlFile) { QDir dirXml = getApplicationDir(relRoutinoDir); return IAppSetup::path(dirXml.absolutePath(), xmlFile, false, "ROUTINO"); } QString CAppSetupMac::defaultCachePath() { QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first(); return IAppSetup::path(cachePath, 0, false, 0); } QString CAppSetupMac::userDataPath(QString subdir) { #if QT_VERSION >= 0x050400 QString dataDir = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation).first(); #else QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); #endif return IAppSetup::path(dataDir, subdir, false, 0); } QString CAppSetupMac::logDir() { // home location returns / (root) instead of user home... QString home = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first(); QDir dir = QDir(home); dir.cdUp(); return IAppSetup::path(dir.absolutePath(), relLogDir, false, 0); } QDir CAppSetupMac::getApplicationDir(QString subdir) { QDir appDir(QCoreApplication::applicationDirPath()); appDir.cdUp(); appDir.cd(subdir); return appDir; } void CAppSetupMac::migrateDirContent(QString dest) { QString src = dest; src.replace("/QLandkarte/", "/"); QDir dirDest = QDir(dest); QDir dirSource = QDir(src); if (!dirDest.exists() && dirSource.exists()) { qDebug() << "src directory for migration" << src; qDebug() << "dst directory for migration" << dest; QDir wdir; QString newdir = dest; newdir.remove("/QMapShack"); wdir.mkdir(newdir); qDebug() << "directory created" << newdir; qDebug() << "migrate data from "<. **********************************************************************************************/ #include "CCommandProcessor.h" #include #include #include CAppOpts* CCommandProcessor::processOptions(const QStringList &arguments) { QCommandLineParser parser; QCommandLineOption helpOption = parser.addHelpOption(); // h help QCommandLineOption debugOption(QStringList() << "d" << "debug", tr("Print debug output to console.")); parser.addOption(debugOption); QCommandLineOption logfileOption(QStringList() << "f" << "logfile", tr("Print debug output to logfile (temp. path).")); parser.addOption(logfileOption); QCommandLineOption nosplashOption(QStringList() << "n" << "no-splash", tr("Do not show splash screen.")); parser.addOption(nosplashOption); QCommandLineOption configOption(QStringList() << "c" << "config", tr("File with QMapShack configuration."), tr("file")); parser.addOption(configOption); parser.addPositionalArgument("files", tr("Files for future use.")); if (!parser.parse(arguments)) { std::cerr << parser.errorText().toUtf8().constData(); std::cerr << parser.helpText().toUtf8().constData(); exit(1); } if (parser.isSet(helpOption)) { std::cout << parser.helpText().toUtf8().constData(); exit(0); } return new CAppOpts(parser.isSet(debugOption), parser.isSet(logfileOption), parser.isSet(nosplashOption), parser.value(configOption), parser.positionalArguments()); } qmapshack-1.10.0/src/setup/CAppSetupMac.h000644 001750 000144 00000002716 13216234142 021313 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CAPPSETUPMAC_H #define CAPPSETUPMAC_H #include "setup/IAppSetup.h" #include class CAppSetupMac : public IAppSetup { public: void initQMapShack() override; QString routinoPath(QString xmlFile) override; QString defaultCachePath() override; QString userDataPath(QString subdir = 0) override; QString logDir() override; QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); } private: QDir getApplicationDir(QString subdir); void migrateDirContent(QString dest); void extendPath(); }; #endif // CAPPSETUPMAC_H qmapshack-1.10.0/src/animation/000755 001750 000144 00000000000 13216664443 017501 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/animation/WTFPL-2000644 001750 000144 00000000762 12374350216 020456 0ustar00oeichlerxusers000000 000000 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. qmapshack-1.10.0/src/animation/COPYRIGHT000644 001750 000144 00000000511 12374350216 020763 0ustar00oeichlerxusers000000 000000 Loading indicators are from: http://ajaxload.info/ Quote from web pages: ------------------------------------------ Generated gifs can be used, modified and distributed under the terms of the ​"Do What The Fuck You Want To Public License" http://www.wtfpl.net/ ------------------------------------------ License: WTFPL-2 qmapshack-1.10.0/src/animation/loader2.gif000644 001750 000144 00000016304 12455143304 021514 0ustar00oeichlerxusers000000 000000 GIF89a00LηŲ˹۲f[i_囯:b,,WLVxJyKp?{r#P}İkaCi5/Z vlrhbWνod3\$Jo=_Sȶ&S6_(RvF[}POsBخ?f1yp;c.uFl9Y{N*U! NETSCAPE2.0!Created with ajaxload.info! ,00,".+,##* "$+5 ))& %*Ђ  &"+M h--ZdD 8‹r%XP(A0P2I 0p h! # Av֑L@ϖQAFhHIEUKZ,q C8YR61xǨ 䩈I ؑ,`8WATL+p@%- N3!p!3pmR j ]B, C&zՒvLstI!`\ ̮ ;nĹ7Ek#5 Aq @|yϲ XϞ֖:~q ϟ@=Y TK?)ˣ:IWg&٫ Znز-[`zR0,! ,00, .+,  " 6 +5)ς&36ղ * / "+=(pe\.@dA $``/ 9 |Цh@0覠ީf I=VxXPnzL1*Ȉ`nAVت# @p UZ pq|[ƚ MY/D{EAeQ :```Om!"fnuuY GM!+2i+!Δ]z,jtmrÏBTvb$N>B_~4ǟM|y'Y{""TD,00#:`3-`S"r \H6o T)n )FHm]Y"7qlԡ.RK%pX͈!)r嶢!59Yi3y9Ңd$l2!`:IOK ߋPhaǑq90b-dRytD:4hH)f*6 ©qjf7l`κ ~')fF¤p:׸ @+3->ٸx/tH ! ,00 7  6 36 ʭ+/ Ǩr @Ksg| GA >L[4@YSw(hAPVSU &hpA ~rPVX# @*UZ(XpF`[G L`F/DX{BUeQ :` _PMV`VY`|eiAjb4ٷ@Z-Hrͨ7M zv `̃`ᢺc {<O|B=9[`@[RE$T sTVVp< = 0`j9@jb]PG\C0h&"@ yO$!HMЗb(0",XB!XcDb $Qk ^ڒPSM>#">3O6Y!lBΙ@XI Pc."Jc}$R"0"G 0C IG+&YjI 4d^j7': cX&+& @X 6"$D 8J I &&^P0" X*+^IԳzd̩&!٦a0ノ! ,00 7  6   ʭ  ӾӯǨ͹ *pZh` PDkр'~;mP 0Mz}F@ n1h`@[GDE=1ԉ@(qV[c@!GR@@ ! ~.*1@P15G^p " ]<(7큪,) !"sL/VZϞ'\ZiU)Ac`a͏0dY}A,\..+WnУG@h0%?c;0e,,`+R`@ 0`_e9CdZ b\bH<wAuN$r pEF!И#:(A|g3, `@H)  `)Uh9 10#eRA.@?V#I]˃ ^|ITԧ&eg_g%4bYqB%=$4fbpA&b$ĩJ r Q+YAƃ@*\zh0% b]Z EF)=D{,Dpy[>D{;+&! ,00 7  6   ʭ  ӾӯǨ͹ *pZh` PDkр'~;mP 0Mz}F@ n1h`@[GDE=1ԉ@(qV[c@!GR@@ ! ~.*1@P15G^=P5%4X ӈrP[i֯N-4qV@RD.\ pu\jJ HwN7+WrZ熃!~HkǞ[i߁!B0y),X+R `@ #(grat5#DpNcN$Y26C^@!И# :(AΰP~%N 0H7X{> @d +P@2d>Ì d*dC50^Q@W CB T PzITPѴ@4`™P @@a X֛2 45,P8 b=>ě>{*(,h:'H ! ,00 7  6   ʭ  ӾӯǨ͹ *pZh` PDkр'~;mP 0Mz}F@ n1h`@[GDE=1ԉ@(qV[c@!GR@@ ! ~.*1@P15G^=P5%4X ӈrP[i֯N-4qV@RD.\ pu\jJ HwN7+WrZ熃!~HkǞ[i߁!B0y)3+)uY6dKt@k|#FX3xfogCt嗊;hfI_)|(0^K@! HM)V6D"!ذG`4,Ƞ=08 Ș5D` !x"#5 =0d 05`P6depPAF•.9Vv^pdRpk bo8f" ѧBC1#F š;d( p4"%H2`?PD 51 Dh P ($? >( pA 2s@X`-FR H B>; LE{ 雈(H 70#! ,00 7  6   ʭ  ӾӯǨ͹ *pZh` PDkр'~;mP 0Mz}F@ n1h`@[GDE=1ԉ@(qV[c@!GR@@ ! ~.*1@P15G^=P5%4X ӈrP[i֯N-4qV@RD.\ pu\jJ HwN7+WrZ熃!~HkǞ[i߁!B0y)3+)uY6dKt@k|#FX'B _*@H_)|PÉ:P `Dox  1A#]Z5A"l}FEyP5`ie-(0`<@d @(  ,d R"1C Y .9@~'pЊDe" d@$@cF%/x [@4F)2`B?x #oָɠ5@5!{ l"R2>Zc-b~Z 4 fnH6m L5#  G,ĕ! ,00 7  6   ʭ  ӾӯǨ͹ *pZh` PDkр'~;mP 0Mz}F@ n1h`@[GDE=1ԉ@(qV[c@!GR@@ ! ~.*1@P15G^=P5%4X ӈrP[i֯N-4qV@RD.\ pu\j؆{ i $+WnxУCO ƅسG<|2‹Ү;t "D2Hs0B,T`a6dN"Bv b_muE Aofpa+ ^#}06!蠣!T.!/Av20tp$ A"l0FE @2T RPF\ٕ  ء0A@3`Oƈ5 Bup H!-dRqЊX D4%d]b$$ʐJcvB C@+>uJ) 0&)  ʌppzY kֳݢ+-&krax 0 ,"! ,00 7  6   ʭ  ӾӯǨ͹ *ЃWh 0X @T(q3jUSն^&x^YyDǀ 4Š6o9@OW@qh!< j@*0Z7RD녠l:J,P D4ظ&k%`vP -T ,)(RofQ֨ pAkViY A`v!M)eve0q4Rg'MKzXΝn/^ FO^02˗BS[a"H@M8Ё!< @9Ldf9 ZgE``u`.+i9B"xJ+DV {DE@%@~1 B 0`["d9@]>Ne%p&M84$0e/TWFH.b吜\Iu(up&%#PBFc% 8"-dRvq xI9θ 9>9( b){$=DV$>ʭ)L>)1%]Iʭ>(E0ȭn.d>Tj+ȔҍJ0Ftp_xH ;qmapshack-1.10.0/src/animation/loader.gif000644 001750 000144 00000015244 12455143304 021434 0ustar00oeichlerxusers000000 000000 GIF89aBBLLzz! NETSCAPE2.0!Created with ajaxload.info! ,BBIT̻qֱUalK'eޠar,+0X4^epX!Gw@YfT1xRNJ*;gh%]~[5LIXLs{_}Rrul_^Ld!;a|]_k,qMmn8i-9~oi.)^)M.^?xmip-p%PX_ +O]{ XP A0B9F@!)N\ɲK?b6$89zlr ͜8m JhŒV YcL-"M&m:US7UQ8b~(`)+դԔ"UN'ֶN]q@Rkjkgoq1>uGu|f!xXR֙Ipaoʣ2xC _LPr`Dz/8͘BfIeY5E^%Gߜ}^8 }Nzczi$0Y@MR BT<! ,BBIT̻!qXalKfyV&ޠaTd0 l*VBAp@T |QNJTJ`Y%` slGI[GpkV~zet"G/,cz5awo8S)A!&hTdj7kAgBsj&aˀ#ԭ9/\훷 u}K8x `@['eq]>!]o\dC8sɳJ{JB@躟 Tg(FPJF96cT4Q<&\S*F"pT5eg]bcCo.V`Kx&#խUì@I/5GNtqhi-` UZqHZz'낗.d>N!UwWU59##/p/r7ڙ$JǍ{B_)E#+M:4R`OVW K4J\! ,BBIT̻!qX`lKVA8h|Un*R8 ,' %ep8Ni'bBIXrM^n5&4r`MqIMRl&W{x[{[1.di"S0no&,Ubm8U9"ASf&ȹIɌhơ)׾dD`ϰ-ÍT\sdX@@~* naxD˰=`aE-ԫD 0pE I͛8P)1g@FI͂H!ɴӧֲd(9$jHS*])jNe| *nIw({AD׾!(l .XvE#5o@s,F/L&F>Yz\j3f3ش+ѿ#LGY//DfZh_ 4[E1~Rқ/'z|y㾿GKw?u: |RzQ{_zy)( u_E! ,BBIt̻! pX`lK[%ĔI8hk}PR(X4M8 Pag'QTHRzz*0PiS1 eUK\)t0k)sZ);_`XpNv,od",vY)B~*Bgn.@RqdƟ&M-YCXY&bS^:ftU7NȦ+uk""FdGCs e >UBH!y_ʜI%5ֻ9!ϜO҄s ϣH*52fÌ!(bgȕW,0GQ+X"4dpUW eiNw]i#ykw-^SmT vwb )gߊ|f7FƳi!iͰjn\I֒T﹄"Kڷ A, jJ/Ro]\h@-q q\/wwk-8.|t+|x'9ן 1UimGN! ,BBIt ̻1 X`lKV@8( +E^nX U DAPaG4P6Qo2HVLi 1lMЇrm0 ys0*HvXh^fHYn]29)/C|lO8sHp9TfCeSRŪbécU{qdRNᚢS:ȹZC~A7)l">&DGc1"^G @8Œ.OʜIEF,rsBʐ"FS А}*]ʴ)=-c93Sb1ej6MwإRҺtb3պYcۓ"BrdL!^ikjp Ve O3RfH& iI$Y!J ̊$ՙu`@q_ Y3_ʾ{yᩮ79-oHx~*kƝԖT&|مLY^Ez! ,BBIt ̻1 f!,EU@8(<2Un@*Q'A (6I'N&*%3@F nb./<`J[LYm_sjvxdOu+YVc|6!r+uR(9Nn8ufmD9¦s|!{uRTN޺5dÚtOUXHWd#I JHpmaC/'Eo;hN\ɲ˗+IAき67賨ѣHyRgG:ٱz%Qx3#FN&G 0M#Zp"֚4r@eRDגօ"ԉ:)fhPyX,1@AIwtl V3:#?jwc[rA^\Lܼ|ͣVjbk8 ryd}'8K>x dD|,E'wC܂QL ӡ<! ,BBI̻Q 0X`lKV@8(IUn@*FIɚO"FTb=@)!|RB# ea ^-؎sdM[QNnV~iI/huQfU9c?u8_@:cp8v?.,s~l_!&a^ ~!#.)S޶6#"ئr^&++bG.F'F1tqE1$(S\r0[8 eΠS=: J#Icj$3xTXҟŞ^jS3\e.,h,CJG25[oIe+[y-VvWV9{[q ~֚\MR9Ϧbj%@u]]zْ*|@p|1*Ʊ3*>@ O|c@E ] *|-Ȭ$¦\Nȿ拜B/cHk썭pQ} v]|OPBd㛫egw6fDV\UW Ĝ=! ,BBI!̻VQXDalK[ޠhSE<n *Q ٳhpIL# Ti&&mSfO=pRZnP`{/!J3Ve.{bA!&9_HC8#`]v7wfl&C):D)eU-@{"ڱIT.a7FF3Fϋȭ=rŋ3j%G#' cȇTI˗0cA - 8@h){г\m2uX)x2;U6D (alDu]۔Kʧ1.VxB Yx/ps/Wvq'X0eW  )YCh[[a'U eTYxI=-?3sN5;38>]zSb'i (Xpb+Hfyy/lX_oi>WF]! ,BBI!̻f,%njko=!EX@;!J7Ś@(\<2o TptmNyiM Otysc'}sxQYr"T+D.S`X R#P][+RDd-Rj^G4m.^P?> HפvHP0 J%Ǐ CHRd SxHI3)c~yI͛0j#y`Zyv @KwфmםU]! ,BBI̻Yb,%nzm 4Ujщ2XF ļCC2&@ўtՆ$5! w"2QL)\5yD"_lQ5Ws@zPXe/Zx<{+y5Pz,qc-qn!`!"M([ѪAۈ˼΄+f$U-:rE[xg7z2nA]aȱǏ,\ē" (9!ڀ/_6cI͛]ȉe$Kde@J~XB 1z疨V;jkt<Xh\H;ςE;;')(K@8脽2 \=t@Y*4F m옂љ@نF(v5Е< a +3&|5䤏) eH7hE%ƌWV0z$cCžf}g5B\D`:! ,BBI̻qf,GUHޠϓI60XO =$p(CկPZY{(0DF>A{54:,F=KfY{kw(h8Uz}-vz\7HdCz+hCULlQƤHLy7'Lv_ּԺvA7=  S #( _:L0->4S^2ֈwaEiH\ɲ˗8$˜s8s>' U0o xѣHZU}zZ 3UP\H0N3xRNN1\Th_nޞ*}妉ȓP sK`9{C > 2Y2zq耴PjլIo(j6vDxPdM%=G s}K168v#qGq" hfU="ޱ\H5ßR1D^TQ#3q7]8_S N4O5&BQ;qmapshack-1.10.0/src/tool/000755 001750 000144 00000000000 13216664443 016477 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/tool/IImportDatabase.ui000644 001750 000144 00000005764 12544164164 022060 0ustar00oeichlerxusers000000 000000 IImportDatabase 0 0 400 300 Form ... :/icons/32x32/PathGreen.png:/icons/32x32/PathGreen.png 22 22 0 0 Source Database: - ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png 22 22 0 0 Target Database: - Start qmapshack-1.10.0/src/tool/IRoutinoDatabaseBuilder.ui000644 001750 000144 00000011734 13166707770 023555 0ustar00oeichlerxusers000000 000000 IRoutinoDatabaseBuilder 0 0 988 451 Form ... :/icons/32x32/PathGreen.png:/icons/32x32/PathGreen.png 22 22 Select source files: Start ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png 22 22 0 0 Target Path: - File Prefix 0 0 :/icons/48x48/Help.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true textBrowser pushStart listWidget qmapshack-1.10.0/src/tool/IToolShell.cpp000644 001750 000144 00000011135 13216234137 021213 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "IToolShell.h" #include IToolShell::IToolShell(QWidget * parent) : QWidget(parent) { connect(&cmd, &QProcess::readyReadStandardError, this, &IToolShell::slotStderr); connect(&cmd, &QProcess::readyReadStandardOutput, this, &IToolShell::slotStdout); connect(&cmd, static_cast(&QProcess::finished), this, &IToolShell::slotFinished); connect(&cmd, static_cast(&QProcess::error), this, &IToolShell::slotError); } IToolShell::~IToolShell() { text = nullptr; } void IToolShell::slotError(QProcess::ProcessError error) { if (text.isNull()) { return; } text->setTextColor(Qt::red); text->insertPlainText(QString(tr("Execution of external program `%1` failed: ")).arg(cmd.program())); switch(error) { case QProcess::FailedToStart: text->insertPlainText(QString(tr("Process cannot be started.\n"))); text->insertPlainText(QString(tr("Make sure the required packages are installed, `%1` exists and is executable.\n")).arg(cmd.program())); break; case QProcess::Crashed: text->insertPlainText(QString(tr("External process crashed.\n"))); break; default: text->insertPlainText(QString(tr("An unknown error occurred.\n"))); break; } } void IToolShell::slotStderr() { if (text.isNull()) { return; } QString str; text->setTextColor(Qt::red); str = cmd.readAllStandardError(); if(str[0] == '\r') { #ifdef WIN32 if(str.contains("\n")) { text->insertPlainText("\n"); } else #endif // WIN32 { text->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor ); text->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor ); text->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor ); text->textCursor().removeSelectedText(); } #ifdef WIN32 str = str.split("\r").last().remove("\r").remove("\n"); #else str = str.split("\r").last(); #endif } text->insertPlainText(str); text->verticalScrollBar()->setValue(text->verticalScrollBar()->maximum()); } void IToolShell::slotStdout() { if (text.isNull()) { return; } QString str; text->setTextColor(Qt::blue); str = cmd.readAllStandardOutput(); if(str[0] == '\r') { #ifdef WIN32 if(str.contains("\n")) { text->insertPlainText("\n"); } else #endif // WIN32 { text->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor ); text->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor ); text->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor ); text->textCursor().removeSelectedText(); } #ifdef WIN32 str = str.split("\r").last().remove("\r").remove("\n"); #else str = str.split("\r").last(); #endif } text->insertPlainText(str); text->verticalScrollBar()->setValue(text->verticalScrollBar()->maximum()); } void IToolShell::stdOut(const QString& str) { if (text.isNull()) { return; } text->setTextColor(Qt::black); text->append(str); } void IToolShell::stdErr(const QString& str) { if (text.isNull()) { return; } text->setTextColor(Qt::red); text->append(str); } void IToolShell::slotFinished(int exitCode, QProcess::ExitStatus status) { if(exitCode || status) { if (!text.isNull()) { text->setTextColor(Qt::red); text->append(tr("!!! failed !!!\n")); } return; } finished(exitCode, status); } qmapshack-1.10.0/src/tool/CImportDatabase.cpp000644 001750 000144 00000006675 13216234137 022214 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CSettings.h" #include "qlgt/CQlgtDb.h" #include "tool/CImportDatabase.h" #include CImportDatabase::CImportDatabase(QWidget *parent) : QWidget(parent) { setupUi(this); setObjectName(tr("Import QLandkarte Database")); SETTINGS; labelSource->setText(cfg.value("ConvertDB/source","-").toString()); labelTarget->setText(cfg.value("ConvertDB/target","-").toString()); textBrowser->setFont(QFont("Courier",10)); connect(toolSelectSource, &QToolButton::clicked, this, &CImportDatabase::slotSelectSource); connect(toolSelectTarget, &QToolButton::clicked, this, &CImportDatabase::slotSelectTarget); connect(pushStart, &QPushButton::clicked, this, &CImportDatabase::slotStart); pushStart->setEnabled(false); if(QFile::exists(labelSource->text())) { pushStart->setEnabled(true); dbQlgt = new CQlgtDb(labelSource->text(), this); } } CImportDatabase::~CImportDatabase() { SETTINGS; cfg.setValue("ConvertDB/source", labelSource->text()); cfg.setValue("ConvertDB/target", labelTarget->text()); } void CImportDatabase::stdOut(const QString& str) { textBrowser->setTextColor(Qt::black); textBrowser->append(str); } void CImportDatabase::stdErr(const QString& str) { textBrowser->setTextColor(Qt::red); textBrowser->append(str); } void CImportDatabase::slotSelectSource() { SETTINGS; QString path = cfg.value("ConvertDB/sourcePath",QDir::homePath()).toString(); QString filename = QFileDialog::getOpenFileName(this, tr("Select source database..."), path, "QLandkarte Database (*.db)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); cfg.setValue("ConvertDB/sourcePath", fi.absolutePath()); labelSource->setText(filename); delete dbQlgt; textBrowser->clear(); dbQlgt = new CQlgtDb(filename, this); pushStart->setEnabled(true); } void CImportDatabase::slotSelectTarget() { SETTINGS; QString path = cfg.value("ConvertDB/targetPath",QDir::homePath()).toString(); QString filename = QFileDialog::getSaveFileName(this, tr("Select target database..."), path, "QMapShack Database (*.db)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); cfg.setValue("ConvertDB/targetPath", fi.absolutePath()); if(fi.suffix().toLower() != "db") { filename += ".db"; } labelTarget->setText(filename); } void CImportDatabase::slotStart() { pushStart->setEnabled(false); dbQlgt->start(labelTarget->text()); pushStart->setEnabled(true); } qmapshack-1.10.0/src/tool/CRoutinoDatabaseBuilder.h000644 001750 000144 00000003303 13216234142 023332 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CROUTINODATABASEBUILDER_H #define CROUTINODATABASEBUILDER_H #include "tool/IToolShell.h" #include "ui_IRoutinoDatabaseBuilder.h" #include class CRoutinoDatabaseBuilder : public IToolShell, private Ui::IRoutinoDatabaseBuilder { Q_OBJECT public: CRoutinoDatabaseBuilder(QWidget * parent); virtual ~CRoutinoDatabaseBuilder(); private slots: void slotSelectSourceFiles(); void slotSelectTargetPath(); void slotStart(); void enabelStartButton(); void slotLinkActivated(const QUrl& url); private: void finished(int exitCode, QProcess::ExitStatus status) override; bool first = false; bool tainted = false; bool last = false; QStringList sourceFiles; QString targetPrefix; QString targetPath; }; #endif //CROUTINODATABASEBUILDER_H qmapshack-1.10.0/src/tool/CRoutinoDatabaseBuilder.cpp000644 001750 000144 00000012324 13216234137 023674 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CSettings.h" #include "setup/IAppSetup.h" #include "tool/CRoutinoDatabaseBuilder.h" #include CRoutinoDatabaseBuilder::CRoutinoDatabaseBuilder(QWidget * parent) : IToolShell(parent) { setupUi(this); setTextBrowser(textBrowser); setObjectName(tr("Create Routino Database")); connect(toolSourceFiles, &QToolButton::clicked, this, &CRoutinoDatabaseBuilder::slotSelectSourceFiles); connect(toolTargetPath, &QToolButton::clicked, this, &CRoutinoDatabaseBuilder::slotSelectTargetPath); connect(pushStart, &QPushButton::clicked, this, &CRoutinoDatabaseBuilder::slotStart); connect(lineTargetPrefix, &QLineEdit::textChanged, this, &CRoutinoDatabaseBuilder::enabelStartButton); connect(labelHelp, &QLabel::linkActivated, this, &CRoutinoDatabaseBuilder::slotLinkActivated); pushStart->setDisabled(true); SETTINGS; QString path = cfg.value("RoutinoDatabaseBuilder/targetPath",QDir::homePath()).toString(); labelTargetPath->setText(path); } CRoutinoDatabaseBuilder::~CRoutinoDatabaseBuilder() { } void CRoutinoDatabaseBuilder::slotSelectSourceFiles() { SETTINGS; QString path = cfg.value("RoutinoDatabaseBuilder/sourcePath",QDir::homePath()).toString(); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path, "OSM Database (*.pbf)"); if(files.isEmpty()) { return; } QFileInfo fi(files.first()); path = fi.absolutePath(); cfg.setValue("RoutinoDatabaseBuilder/sourcePath", path); listWidget->clear(); for(const QString &file : files) { new QListWidgetItem(QIcon("://icons/32x32/Map.png"), file, listWidget); } enabelStartButton(); } void CRoutinoDatabaseBuilder::slotSelectTargetPath() { SETTINGS; QString path = cfg.value("RoutinoDatabaseBuilder/targetPath",QDir::homePath()).toString(); path = QFileDialog::getExistingDirectory(this, tr("Select target path..."), path); if(path.isEmpty()) { return; } cfg.setValue("RoutinoDatabaseBuilder/targetPath", path); labelTargetPath->setText(path); enabelStartButton(); } void CRoutinoDatabaseBuilder::enabelStartButton() { pushStart->setDisabled(true); if(listWidget->count() == 0) { return; } if(labelTargetPath->text() == "-") { return; } if(lineTargetPrefix->text().isEmpty()) { return; } pushStart->setEnabled(true); } void CRoutinoDatabaseBuilder::slotStart() { pushStart->setDisabled(true); sourceFiles.clear(); for(const QListWidgetItem * item : listWidget->findItems("*", Qt::MatchWildcard)) { sourceFiles << item->text(); } targetPrefix = lineTargetPrefix->text(); targetPath = labelTargetPath->text(); first = true; last = false; textBrowser->clear(); slotFinished(0,QProcess::NormalExit); } void CRoutinoDatabaseBuilder::finished(int exitCode, QProcess::ExitStatus status) { if(last) { textBrowser->setTextColor(Qt::darkGreen); textBrowser->append(tr("!!! done !!!\n")); pushStart->setEnabled(true); return; } IAppSetup* instance = IAppSetup::getPlatformInstance(); if(sourceFiles.isEmpty()) { QStringList args; args << QString("--dir=%1").arg(targetPath); args << QString("--prefix=%1").arg(targetPrefix); args << QString("--tagging=%1").arg(instance->routinoPath("tagging.xml")); args << "--process-only"; stdOut("planetsplitter " + args.join(" ") + "\n"); cmd.start("planetsplitter", args); last = true; } else { QStringList args; args << QString("--dir=%1").arg(targetPath); args << QString("--prefix=%1").arg(targetPrefix); args << QString("--tagging=%1").arg(instance->routinoPath("tagging.xml")); if(first) { first = false; args << "--parse-only"; } else { args << "--parse-only" << "--append"; } args << sourceFiles.first(); sourceFiles.pop_front(); stdOut("planetsplitter " + args.join(" ") + "\n"); cmd.start("planetsplitter", args); } } void CRoutinoDatabaseBuilder::slotLinkActivated(const QUrl& url) { QDesktopServices::openUrl(url); } qmapshack-1.10.0/src/tool/IToolShell.h000644 001750 000144 00000003641 13216234142 020657 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef ITOOLSHELL_H #define ITOOLSHELL_H #include #include #include class QTextBrowser; class IToolShell : public QWidget { Q_OBJECT public: IToolShell(QWidget *parent); virtual ~IToolShell(); void setTextBrowser(QTextBrowser * textbrowser) { text = textbrowser; } protected slots: /// read the stderr from the process and paste it into the text browser void slotStderr(); /// read the stdout from the process and paste it into the text browser void slotStdout(); void slotError(QProcess::ProcessError error); virtual void slotFinished(int exitCode, QProcess::ExitStatus status); protected: virtual void finished(int exitCode, QProcess::ExitStatus status) = 0; /// write text to stdout color channel of the text browser void stdOut(const QString& str); /// write text to stderr color channel of the text browser void stdErr(const QString& str); QProcess cmd; QPointer text; }; #endif //ITOOLSHELL_H qmapshack-1.10.0/src/tool/CMapVrtBuilder.cpp000644 001750 000144 00000010764 13216234137 022027 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMapVrtBuilder.h" #include "helpers/CSettings.h" #include CMapVrtBuilder::CMapVrtBuilder(QWidget *parent) : IToolShell(parent) { setupUi(this); setTextBrowser(textBrowser); setObjectName(tr("Build GDAL VRT")); connect(toolSourceFiles, &QToolButton::clicked, this, &CMapVrtBuilder::slotSelectSourceFiles); connect(toolTargetFile, &QToolButton::clicked, this, &CMapVrtBuilder::slotSelectTargetFile); connect(pushStart, &QPushButton::clicked, this, &CMapVrtBuilder::slotStart); connect(labelHelpGDAL, &QLabel::linkActivated,this, &CMapVrtBuilder::slotLinkActivated); pushStart->setDisabled(true); SETTINGS; cfg.beginGroup("VrtBuilder"); groupAdvancedOptions->setChecked(cfg.value("AdvancedOptions", false).toBool()); lineASrs->setText(cfg.value("a_srs", "").toString()); lineSrcNoData->setText(cfg.value("srcndata", "").toString()); lineVrtNoData->setText(cfg.value("vrtndata", "").toString()); cfg.endGroup(); } CMapVrtBuilder::~CMapVrtBuilder() { SETTINGS; cfg.beginGroup("VrtBuilder"); cfg.setValue("AdvancedOptions", groupAdvancedOptions->isChecked()); cfg.setValue("a_srs", lineASrs->text()); cfg.setValue("srcndata", lineSrcNoData->text()); cfg.setValue("vrtndata", lineVrtNoData->text()); cfg.endGroup(); } void CMapVrtBuilder::slotSelectSourceFiles() { SETTINGS; QString path = cfg.value("VrtBuilder/sourcePath",QDir::homePath()).toString(); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path); if(files.isEmpty()) { return; } QFileInfo fi(files.first()); path = fi.absolutePath(); cfg.setValue("VrtBuilder/sourcePath", path); listWidget->clear(); for(const QString &file : files) { new QListWidgetItem(QIcon("://icons/32x32/Map.png"), file, listWidget); } enableStartButton(); } void CMapVrtBuilder::slotSelectTargetFile() { SETTINGS; QString path = cfg.value("VrtBuilder/targetPath",QDir::homePath()).toString(); QString file = QFileDialog::getSaveFileName(this, tr("Select target file..."), path, "GDAL vrt (*.vrt)"); if(file.isEmpty()) { return; } QFileInfo fi(file); path = fi.absolutePath(); cfg.setValue("VrtBuilder/targetPath", path); if(fi.suffix().toLower() != "vrt") { file += ".vrt"; } labelTargetFilename->setText(file); enableStartButton(); } void CMapVrtBuilder::enableStartButton() { pushStart->setEnabled(listWidget->count() > 0 && labelTargetFilename->text() != "-"); } void CMapVrtBuilder::slotStart() { pushStart->setDisabled(true); QStringList args; if(groupAdvancedOptions->isChecked()) { if(!lineASrs->text().isEmpty()) { args << "-a_srs" << lineASrs->text(); } if(!lineSrcNoData->text().isEmpty()) { args << "-srcnodata" << lineSrcNoData->text(); } if(!lineVrtNoData->text().isEmpty()) { args << "-vrtnodata" << lineVrtNoData->text(); } } args << labelTargetFilename->text(); for(const QListWidgetItem * item : listWidget->findItems("*", Qt::MatchWildcard)) { args << item->text(); } stdOut("gdalbuildvrt " + args.join(" ") + "\n"); cmd.start("gdalbuildvrt", args); } void CMapVrtBuilder::finished(int exitCode, QProcess::ExitStatus status) { textBrowser->setTextColor(Qt::darkGreen); textBrowser->append(tr("!!! done !!!\n")); pushStart->setEnabled(true); } void CMapVrtBuilder::slotLinkActivated(const QUrl& url) { QDesktopServices::openUrl(url); } qmapshack-1.10.0/src/tool/IMapVrtBuilder.ui000644 001750 000144 00000016325 13166657756 021713 0ustar00oeichlerxusers000000 000000 IMapVrtBuilder 0 0 980 616 Form Start Advanced Options true false Source No Data (-srcnodata) Target No Data (-vrtnodata) Target Projection (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. true 0 0 0 0 ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png 22 22 0 0 Target Filename: - ... :/icons/32x32/PathGreen.png:/icons/32x32/PathGreen.png 22 22 Select source files: 0 0 0 0 :/icons/48x48/Help.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true qmapshack-1.10.0/src/tool/CImportDatabase.h000644 001750 000144 00000002655 13216234142 021647 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CIMPORTDATABASE_H #define CIMPORTDATABASE_H #include "ui_IImportDatabase.h" #include #include class CQlgtDb; class CImportDatabase : public QWidget, private Ui::IImportDatabase { Q_OBJECT public: CImportDatabase(QWidget * parent); virtual ~CImportDatabase(); void stdOut(const QString& str); void stdErr(const QString& str); private slots: void slotSelectSource(); void slotSelectTarget(); void slotStart(); private: QPointer dbQlgt; }; #endif //CIMPORTDATABASE_H qmapshack-1.10.0/src/tool/CMapVrtBuilder.h000644 001750 000144 00000002723 13216234142 021464 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPVRTBUILDER_H #define CMAPVRTBUILDER_H #include "tool/IToolShell.h" #include "ui_IMapVrtBuilder.h" #include class CMapVrtBuilder : public IToolShell, private Ui::IMapVrtBuilder { Q_OBJECT public: CMapVrtBuilder(QWidget * parent); virtual ~CMapVrtBuilder(); private slots: void slotSelectSourceFiles(); void slotSelectTargetFile(); void slotStart(); void slotLinkActivated(const QUrl& url); private: void finished(int exitCode, QProcess::ExitStatus status) override; void enableStartButton(); }; #endif //CMAPVRTBUILDER_H qmapshack-1.10.0/src/device/000755 001750 000144 00000000000 13216664443 016761 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/device/CDeviceWatcherLinux.h000644 001750 000144 00000002720 13216234142 022760 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEVICEWATCHERLINUX_H #define CDEVICEWATCHERLINUX_H #include "device/IDeviceWatcher.h" class QDBusObjectPath; class CDeviceWatcherLinux : public IDeviceWatcher { Q_OBJECT public: CDeviceWatcherLinux(CGisListWks *parent); virtual ~CDeviceWatcherLinux(); private slots: void slotDeviceAdded(const QDBusObjectPath& path, const QVariantMap& map); void slotDeviceRemoved(const QDBusObjectPath& path, const QStringList& list); void slotUpdate() override; private: QString readMountPoint(const QString &path); }; #endif //CDEVICEWATCHERLINUX_H qmapshack-1.10.0/src/device/CDeviceGarminArchive.cpp000644 001750 000144 00000004401 13216234137 023417 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "device/CDeviceGarmin.h" #include "device/CDeviceGarminArchive.h" #include "gis/CGisListWks.h" #include "gis/gpx/CGpxProject.h" #include CDeviceGarminArchive::CDeviceGarminArchive(const QString &path, CDeviceGarmin *parent) : IDevice(path, eTypeGarmin, parent->getKey(), parent) { setText(CGisListWks::eColumnName, tr("Archive - expand to load")); setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); connect(treeWidget(), &QTreeWidget::itemExpanded, this, &CDeviceGarminArchive::slotExpanded); } void CDeviceGarminArchive::slotExpanded(QTreeWidgetItem * item) { if((item != this) || (childCount() != 0)) { return; } setText(CGisListWks::eColumnName, tr("Archive - loaded")); QMutexLocker lock(&IGisItem::mutexItems); CCanvas::setOverrideCursor(Qt::WaitCursor, "CDeviceGarminArchive::slotExpanded()"); mount(); qDebug() << "reading files from device: " << dir.path(); QStringList entries = dir.entryList(QStringList("*.gpx")); for(const QString &entry : entries) { const QString filename = dir.absoluteFilePath(entry); IGisProject * project = new CGpxProject(filename, this); if(!project->isValid()) { delete project; } } umount(); CCanvas::restoreOverrideCursor("CDeviceGarminArchive::slotExpanded()"); } qmapshack-1.10.0/src/device/CDeviceWatcherMac.h000644 001750 000144 00000003370 13216234142 022363 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CDEVICEWATCHERMAC_H #define CDEVICEWATCHERMAC_H #include #include #include #include #include "device/IDeviceWatcher.h" class CDeviceWorker : public QThread { Q_OBJECT public: CDeviceWorker(); void run() override; void stop(); signals: void sigDeviceAdded(QString dev); void sigDeviceRemoved(QString dev); private: volatile bool mStop; DASessionRef mSession; }; class CDeviceWatcherMac : public IDeviceWatcher { Q_OBJECT public: CDeviceWatcherMac(CGisListWks *parent); private slots: void slotUpdate() override; void slotDeviceAdded(QString dev); void slotDeviceRemoved(QString dev); void slotEndListing(); private: void addDevice(const QStorageInfo& storage); CDeviceWorker worker; QStringList deviceList; }; #endif //CDEVICEWATCHERMAC_H qmapshack-1.10.0/src/device/CDeviceTwoNav.h000644 001750 000144 00000002473 13216234142 021566 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEVICETWONAV_H #define CDEVICETWONAV_H #include "device/IDevice.h" class CDeviceTwoNav : public IDevice { public: CDeviceTwoNav(const QString &path, const QString &key, const QString &model, QTreeWidget * parent); virtual ~CDeviceTwoNav(); void insertCopyOfProject(IGisProject * project) override; private: void readReginfo(const QString& filename); QString pathData; }; #endif //CDEVICETWONAV_H qmapshack-1.10.0/src/device/CDeviceWatcherWindows.h000644 001750 000144 00000003320 13216234142 023310 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEVICEWATCHERWINDOWS_H #define CDEVICEWATCHERWINDOWS_H #include "device/IDeviceWatcher.h" #include class CEventDevice : public QEvent { public: enum event_types_e { eEvtDeviceWindows = QEvent::User + 200 }; CEventDevice(const QString& path, bool add) : QEvent(QEvent::Type(eEvtDeviceWindows)), add(add), path(path) { } bool add; QString path; }; class CDeviceWatcherWindows : public IDeviceWatcher { Q_OBJECT public: virtual ~CDeviceWatcherWindows(); static CDeviceWatcherWindows * self() { return pSelf; } bool event(QEvent * e); private slots: void slotUpdate(); private: friend class CGisListWks; CDeviceWatcherWindows(CGisListWks *parent); static CDeviceWatcherWindows * pSelf; }; #endif //CDEVICEWATCHERWINDOWS_H qmapshack-1.10.0/src/device/IDeviceWatcher.cpp000644 001750 000144 00000004555 13216234137 022315 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "device/CDeviceGarmin.h" #include "device/CDeviceTwoNav.h" #include "device/IDeviceWatcher.h" #include "gis/CGisListWks.h" #include #include IDeviceWatcher::IDeviceWatcher(CGisListWks *parent) : QObject(parent) , listWks(parent) { QTimer::singleShot(1000, this, SLOT(slotUpdate())); } IDeviceWatcher::~IDeviceWatcher() { } void IDeviceWatcher::probeForDevice(const QString& mountPoint, const QString& path, const QString& label) { QDir dir(mountPoint); if(!dir.exists()) { return; } qDebug() << "Probe device at" << mountPoint << path << label; QStringList entries = dir.entryList(); CCanvas::setOverrideCursor(Qt::WaitCursor,"probeForDevice"); if(entries.contains("Garmin")) { if(dir.exists("Garmin/GarminDevice.xml")) { new CDeviceGarmin(mountPoint, path, label, "Garmin/GarminDevice.xml", listWks); emit sigChanged(); } } else if(entries.contains("GARMIN")) { if(dir.exists("GARMIN/GarminDevice.xml")) { new CDeviceGarmin(mountPoint, path, label, "GARMIN/GarminDevice.xml", listWks); emit sigChanged(); } } else if(entries.contains("TwoNavData")) { new CDeviceTwoNav(mountPoint, path, label, listWks); emit sigChanged(); } else { qDebug() << "Don't know it :("; } CCanvas::restoreOverrideCursor("probeForDevice"); } qmapshack-1.10.0/src/device/CDeviceWatcherWindows.cpp000644 001750 000144 00000004461 13216234137 023656 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "device/CDeviceWatcherWindows.h" #include "gis/CGisListWks.h" #include "CMainWindow.h" #include CDeviceWatcherWindows * CDeviceWatcherWindows::pSelf = nullptr; CDeviceWatcherWindows::CDeviceWatcherWindows(CGisListWks *parent) : IDeviceWatcher(parent) { pSelf = this; } CDeviceWatcherWindows::~CDeviceWatcherWindows() { } void CDeviceWatcherWindows::slotUpdate() { QApplication::setOverrideCursor(Qt::WaitCursor); for(const QStorageInfo &storage : QStorageInfo::mountedVolumes()) { if (storage.isValid() && storage.isReady()) { probeForDevice(storage.rootPath(), storage.rootPath(), storage.name()); } } QApplication::restoreOverrideCursor(); } bool CDeviceWatcherWindows::event(QEvent * e) { if (e->type() == CEventDevice::eEvtDeviceWindows) { CEventDevice * evt = (CEventDevice*)e; qDebug() << "CDeviceWatcherWindows::event()" << evt->path << evt->add; if (evt->add) { QStorageInfo storage(evt->path); if (storage.isValid() && storage.isReady()) { QApplication::setOverrideCursor(Qt::WaitCursor); probeForDevice(evt->path, evt->path, storage.name()); QApplication::restoreOverrideCursor(); } } else { listWks->removeDevice(evt->path); } } return QObject::event(e); } qmapshack-1.10.0/src/device/IDevice.h000644 001750 000144 00000006775 13216234261 020450 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef IDEVICE_H #define IDEVICE_H #include #include #include "gis/IGisItem.h" #include "gis/rte/router/IRouter.h" class CGisDraw; class CGisItemWpt; class CDeviceGarmin; class IDevice : public QTreeWidgetItem { Q_DECLARE_TR_FUNCTIONS(IDevice) public: enum type_e { eTypeNone = 0 ,eTypeGarmin = 1 ,eTypeTwoNav = 2 }; IDevice(const QString& path, type_e type, const QString& key, QTreeWidget * parent); IDevice(const QString &path, type_e type, const QString &key, CDeviceGarmin *parent); virtual ~IDevice(); static void mount(const QString& path); static void umount(const QString &path); static int count() { return cnt; } void mount() { mount(key); } void umount() { umount(key); } const QString& getKey() const { return key; } QString getName() const; void getItemsByPos(const QPointF& pos, QList &items); void getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items); void getNogoAreas(QVector &areas); IGisItem * getItemByKey(const IGisItem::key_t& key); void getItemsByKeys(const QList& keys, QList& items); void editItemByKey(const IGisItem::key_t& key); void drawItem(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, CGisDraw * gis); void drawLabel(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis); void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis); void insertCopyOfProject(IGisProject * project, int& lastResult); void updateProject(IGisProject * project); virtual void startSavingProject(IGisProject * project) { } virtual void saveImages(CGisItemWpt& wpt) { } virtual void loadImages(CGisItemWpt& wpt) { } virtual void aboutToRemoveProject(IGisProject * project) { } IGisProject * getProjectByKey(const QString& key); protected: virtual void insertCopyOfProject(IGisProject * project) = 0; /** @brief Test if a project's filename/path is already used This can happen if there is already a project with the same name but different or no key. @param filename @return If the current operation should be aborted return true. */ bool testForExternalProject(const QString& filename); static int cnt; QDir dir; QString key; }; #endif //IDEVICE_H qmapshack-1.10.0/src/device/IDevice.cpp000644 001750 000144 00000024644 13216234261 020776 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "device/CDeviceGarmin.h" #include "device/IDevice.h" #include "gis/CGisListWks.h" #include "gis/prj/IGisProject.h" #include "gis/rte/router/IRouter.h" #include "helpers/CSelectCopyAction.h" #ifdef HAVE_DBUS #include #endif int IDevice::cnt = 0; IDevice::IDevice(const QString &path, type_e type, const QString &key, QTreeWidget *parent) : QTreeWidgetItem(parent, type) , dir(path) , key(key) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/Device.png")); cnt++; } IDevice::IDevice(const QString &path, type_e type, const QString &key, CDeviceGarmin *parent) : QTreeWidgetItem(parent, type) , dir(path) , key(key) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/PathGreen.png")); } IDevice::~IDevice() { cnt--; } void IDevice::mount(const QString& path) { #ifdef HAVE_DBUS QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.UDisks2",path,"org.freedesktop.UDisks2.Filesystem","Mount"); QVariantMap args; args.insert("options", "sync"); message << args; #if defined(Q_OS_FREEBSD) // XXX Hunc sint race conditions - call bsdisks (UDisks2) too fast, // get a malformed reply, crash. QThread::sleep(1); #endif QDBusConnection::systemBus().call(message); #endif } void IDevice::umount(const QString &path) { #ifdef HAVE_DBUS QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.UDisks2",path,"org.freedesktop.UDisks2.Filesystem","Unmount"); QVariantMap args; message << args; QDBusConnection::systemBus().call(message); #endif } QString IDevice::getName() const { return text(CGisListWks::eColumnName); } void IDevice::getItemsByPos(const QPointF& pos, QList &items) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->getItemsByPos(pos, items); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->getItemsByPos(pos, items); } } } void IDevice::getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->getItemsByArea(area, flags, items); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->getItemsByArea(area, flags, items); } } } void IDevice::getNogoAreas(QVector & areas) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->getNogoAreas(areas); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->getNogoAreas(areas); } } } IGisItem * IDevice::getItemByKey(const IGisItem::key_t& key) { IGisItem * item = nullptr; const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { if(project->getKey() != key.project) { continue; } item = project->getItemByKey(key); if(item != nullptr) { break; } } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { item = device->getItemByKey(key); if(item != nullptr) { break; } } } return item; } void IDevice::getItemsByKeys(const QList& keys, QList& items) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->getItemsByKeys(keys, items); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->getItemsByKeys(keys, items); } } } IGisProject * IDevice::getProjectByKey(const QString& key) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { if(project->getKey() != key) { continue; } return project; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { project = device->getProjectByKey(key); if(project != nullptr) { return project; } } } return nullptr; } void IDevice::editItemByKey(const IGisItem::key_t& key) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->editItemByKey(key); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->editItemByKey(key); } } } void IDevice::insertCopyOfProject(IGisProject * project, int& lastResult) { IGisProject * project2 = getProjectByKey(project->getKey()); if(project2) { int result = lastResult; if(lastResult == CSelectCopyAction::eResultNone) { CSelectCopyAction dlg(project, project2, CMainWindow::getBestWidgetForParent()); dlg.exec(); result = dlg.getResult(); if(dlg.allOthersToo()) { lastResult = result; } } if(result == CSelectCopyAction::eResultSkip) { return; } if(result == CSelectCopyAction::eResultNone) { return; } if(project2->remove()) { delete project2; } else { return; } } insertCopyOfProject(project); } void IDevice::updateProject(IGisProject * project) { IGisProject * project2 = getProjectByKey(project->getKey()); if(project2) { if(project2->remove()) { delete project2; } else { return; } } project->blockUpdateItems(true); insertCopyOfProject(project); project->blockUpdateItems(false); } bool IDevice::testForExternalProject(const QString& filename) { if(QDir(filename).exists() || QFile::exists(filename)) { QString msg = tr("There is another project with the same name. If you press 'ok' it will be removed and replaced."); int res = QMessageBox::warning(CMainWindow::getBestWidgetForParent(), getName(), msg, QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok); if(res != QMessageBox::Ok) { return true; } if(QDir(filename).exists()) { QDir(filename).removeRecursively(); } else if(QFile::exists(filename)) { QFile(filename).remove(); } QFileInfo fi(filename); const int N = childCount(); for(int n = 0; n < N; n++) { QTreeWidgetItem * item = child(n); if(item->text(CGisListWks::eColumnName) == fi.fileName()) { delete item; break; } } } return false; } void IDevice::drawItem(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, CGisDraw * gis) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->drawItem(p, viewport, blockedAreas, gis); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->drawItem(p, viewport, blockedAreas, gis); } } } void IDevice::drawLabel(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->drawLabel(p, viewport, blockedAreas, fm, gis); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->drawLabel(p, viewport, blockedAreas, fm, gis); } } } void IDevice::drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { const int N = childCount(); for(int n = 0; n < N; n++) { IGisProject * project = dynamic_cast(child(n)); if(project != nullptr) { project->drawItem(p, viewport, gis); continue; } IDevice * device = dynamic_cast(child(n)); if(device != nullptr) { device->drawItem(p, viewport, gis); } } } qmapshack-1.10.0/src/device/IDeviceWatcher.h000644 001750 000144 00000004123 13216234142 021745 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDEVICEWATCHER_H #define IDEVICEWATCHER_H #include class CGisListWks; class IDevice; class IDeviceWatcher : public QObject { Q_OBJECT public: IDeviceWatcher(CGisListWks *parent); virtual ~IDeviceWatcher(); signals: void sigChanged(); private slots: /** @brief Find all devices already connected This slot is called only once at startup. All paths to plug-n-play memory have to be passed to probeForDevice(). */ virtual void slotUpdate() = 0; protected: /** @brief Probe a path for a device @param mountPoint This is the mount point in a Linux sense (e.g. "/run/media/GARMIN"). For Windows this will be the drive letter (e.g. "d:\") @param path This is the device path in a Linux sense (e.g. "/org/freedesktop/UDisks2/block_devices/sdc1") For Windows this will be the drive letter, too (e.g. "d:\") @param label A name for the device. In Linux the last part of the mount point is used. In Windows it should be the name of the drive. */ void probeForDevice(const QString &mountPoint, const QString& path, const QString &label); CGisListWks * listWks; }; #endif //IDEVICEWATCHER_H qmapshack-1.10.0/src/device/CDeviceGarminArchive.h000644 001750 000144 00000002666 13216234142 023073 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEVICEGARMINARCHIVE_H #define CDEVICEGARMINARCHIVE_H #include "device/IDevice.h" #include #include #include class CDeviceGarmin; class CDeviceGarminArchive : public QObject, public IDevice { Q_OBJECT public: CDeviceGarminArchive(const QString& path, CDeviceGarmin * parent); virtual ~CDeviceGarminArchive() = default; protected: void insertCopyOfProject(IGisProject * project) override {} private slots: void slotExpanded(QTreeWidgetItem * item); }; #endif //CDEVICEGARMINARCHIVE_H qmapshack-1.10.0/src/device/CDeviceGarmin.cpp000644 001750 000144 00000026772 13216234137 022134 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "device/CDeviceGarmin.h" #include "device/CDeviceGarminArchive.h" #include "gis/CGisListWks.h" #include "gis/fit/CFitProject.h" #include "gis/gpx/CGpxProject.h" #include "gis/wpt/CGisItemWpt.h" #include #include CDeviceGarmin::CDeviceGarmin(const QString &path, const QString &key, const QString &model, const QString& garminDeviceXml, QTreeWidget *parent) : IDevice(path, eTypeGarmin, key, parent) , cntImages(0) { setText(CGisListWks::eColumnName, "Garmin"); QFile file(QDir(path).absoluteFilePath(garminDeviceXml)); if(!file.open(QIODevice::ReadOnly)) { qDebug() << "failed to open" << dir.absoluteFilePath(garminDeviceXml); } QDomDocument dom; QString msg; int line; int column; if(!dom.setContent(&file, false, &msg, &line, &column)) { qDebug() << QString("Failed to read: %1\nline %2, column %3:\n %4").arg(file.fileName()).arg(line).arg(column).arg(msg); } file.close(); const QDomElement& xmlDevice = dom.documentElement(); const QDomNode& xmlModel = xmlDevice.namedItem("Model"); id = xmlDevice.namedItem("Id").toElement().text(); description = xmlModel.namedItem("Description").toElement().text(); partno = xmlModel.namedItem("PartNumber").toElement().text(); setText(CGisListWks::eColumnName, QString("%1 (%2)").arg(description).arg(model)); setToolTip(CGisListWks::eColumnName, QString("%1 (%2, %3)").arg(description).arg(partno).arg(model)); const QDomNode& xmlMassStorageMode = xmlDevice.namedItem("MassStorageMode"); const QDomNodeList& xmlDataTypes = xmlMassStorageMode.toElement().elementsByTagName("DataType"); const int N = xmlDataTypes.count(); for(int n = 0; n < N; n++) { const QDomNode& xmlDataType = xmlDataTypes.item(n); const QDomNode& xmlName = xmlDataType.namedItem("Name"); const QDomNode& xmlFile = xmlDataType.namedItem("File"); const QDomNode& xmlLocation = xmlFile.namedItem("Location"); const QDomNode& xmlPath = xmlLocation.namedItem("Path"); QString name = xmlName.toElement().text(); if(name == "GPSData") { pathGpx = xmlPath.toElement().text(); } else if(name == "GeotaggedPhotos") { pathPictures = xmlPath.toElement().text(); } else if(name == "GeocachePhotos") { pathSpoilers = xmlPath.toElement().text(); } else if(name == "FIT_TYPE_4") { pathActivities = xmlPath.toElement().text(); } else if(name == "FIT_TYPE_6") { // courses pathCourses = xmlPath.toElement().text(); } else if(name == "FIT_TYPE_8") { pathLocations = xmlPath.toElement().text(); } else if(name == "Adventures") { pathAdventures = xmlPath.toElement().text(); } } qDebug() << dir.absoluteFilePath(pathGpx); qDebug() << dir.absoluteFilePath(pathPictures); qDebug() << dir.absoluteFilePath(pathSpoilers); qDebug() << dir.absoluteFilePath(pathActivities); qDebug() << dir.absoluteFilePath(pathCourses); qDebug() << dir.absoluteFilePath(pathLocations); qDebug() << dir.absoluteFilePath(pathAdventures); if(!dir.exists(pathGpx)) { dir.mkpath(pathGpx); } if(!dir.exists(pathPictures)) { dir.mkpath(pathPictures); } if(!dir.exists(pathSpoilers)) { dir.mkpath(pathSpoilers); } if(!pathAdventures.isEmpty() && !dir.exists(pathAdventures)) { dir.mkpath(pathAdventures); } this->createProjectsFromFiles(pathGpx, "gpx"); this->createProjectsFromFiles(pathGpx + "/Current", "gpx"); QDir dirArchive(dir.absoluteFilePath(pathGpx + "/Archive")); if(dirArchive.exists() && (dirArchive.entryList(QStringList("*.gpx")).count() != 0)) { archive = new CDeviceGarminArchive(dir.absoluteFilePath(pathGpx + "/Archive"), this); } this->createProjectsFromFiles(pathActivities, "fit"); this->createProjectsFromFiles(pathCourses, "fit"); this->createProjectsFromFiles(pathLocations, "fit"); } void CDeviceGarmin::createProjectsFromFiles(QString subdirecoty, QString fileEnding) { QDir dirLoop(dir.absoluteFilePath(subdirecoty)); qDebug() << "reading files from device: " << dirLoop.path(); QStringList entries = dirLoop.entryList(QStringList("*." + fileEnding)); for(const QString &entry : entries) { const QString filename = dirLoop.absoluteFilePath(entry); IGisProject * project = nullptr; if (fileEnding == "fit") { project = new CFitProject(filename, this); } if (fileEnding == "gpx") { project = new CGpxProject(filename, this); } if(!project->isValid()) { delete project; } } } CDeviceGarmin::~CDeviceGarmin() { } void CDeviceGarmin::insertCopyOfProject(IGisProject * project) { QString name = project->getName(); name = name.remove(QRegExp("[^A-Za-z0-9_]")); QDir dirGpx = dir.absoluteFilePath(pathGpx); QString filename = dirGpx.absoluteFilePath(name + ".gpx"); if(testForExternalProject(filename)) { return; } CGpxProject * gpx = new CGpxProject(filename, project, this); if(!gpx->isValid()) { delete gpx; return; } if(!gpx->save()) { delete gpx; return; } createAdventureFromProject(project, pathGpx + "/" + name + ".gpx"); // move new project to top of any sub-folder/sub-device item int newIdx = NOIDX; const int myIdx = childCount() - 1; for(int i = myIdx - 1; i >= 0; i--) { IDevice * device = dynamic_cast(child(i)); if(0 == device) { break; } newIdx = i; } if(newIdx != NOIDX) { takeChild(myIdx); insertChild(newIdx, gpx); } } void CDeviceGarmin::saveImages(CGisItemWpt& wpt) { if(wpt.isGeocache()) { QString name = wpt.getName(); quint32 size = name.size(); QString path = QString("%1/%2/%3").arg(name.at(size-1)).arg(name.at(size -2)).arg(name); const QDir dirSpoilers(dir.absoluteFilePath(pathSpoilers)); const QDir dirCache(dirSpoilers.absoluteFilePath(path)); const QList& images = wpt.getImages(); if(!dirCache.exists()) { dirCache.mkpath(dirCache.absolutePath()); } QString filename; for(const CGisItemWpt::image_t& image : images) { filename = image.info; filename = filename.remove(QRegExp("[^A-Za-z0-9_]")); if(!filename.endsWith("jpg")) { filename += ".jpg"; } image.pixmap.save(dirCache.absoluteFilePath(filename)); } } else { const QDir dirImages(dir.absoluteFilePath(pathPictures)); const QString& key = wpt.getKey().project; const QList& images = wpt.getImages(); QList links; QString filename; for(const CGisItemWpt::image_t& image : images) { filename = QString("%1.%2.jpg").arg(key).arg(cntImages); image.pixmap.save(dirImages.absoluteFilePath(filename)); IGisItem::link_t link; link.uri = pathPictures + "/" + filename; link.text = tr("Picture%1").arg(cntImages); link.type = "Garmin"; links << link; cntImages++; } wpt.appendLinks(links); } } void CDeviceGarmin::loadImages(CGisItemWpt& wpt) { if(wpt.isGeocache()) { QString name = wpt.getName(); quint32 size = name.size(); QString path = QString("%1/%2/%3").arg(name.at(size-1)).arg(name.at(size -2)).arg(name); const QDir dirSpoilers(dir.absoluteFilePath(pathSpoilers)); const QDir dirCache(dirSpoilers.absoluteFilePath(path)); QList images; QStringList entries = dirCache.entryList(QStringList("*.jpg"), QDir::Files); for(const QString &file : entries) { CGisItemWpt::image_t image; image.pixmap.load(dirCache.absoluteFilePath(file)); if(!image.pixmap.isNull()) { image.fileName = file; image.info = QFileInfo(file).completeBaseName(); images << image; } } if(!images.isEmpty()) { wpt.appendImages(images); } } else { const QList& links = wpt.getLinks(); QList images; for(const IGisItem::link_t& link : links) { if(link.type != "Garmin") { continue; } CGisItemWpt::image_t image; image.fileName = link.text; image.pixmap.load(dir.absoluteFilePath(link.uri.toString())); images << image; } if(!images.isEmpty()) { wpt.appendImages(images); wpt.removeLinksByType("Garmin"); } } } void CDeviceGarmin::startSavingProject(IGisProject * project) { cntImages = 0; } void CDeviceGarmin::aboutToRemoveProject(IGisProject * project) { // remove images attached to project const QString& key = project->getKey(); const QDir dirImages(dir.absoluteFilePath(pathPictures)); QStringList entries = dirImages.entryList(QStringList("*.jpg"), QDir::Files); for(const QString &entry : entries) { QString filename = dirImages.absoluteFilePath(entry); QFileInfo fi(filename); if(fi.baseName() == key) { QFile::remove(filename); } } // remove geo cache spoiler images const int N = project->childCount(); for(int n = 0; n < N; n++) { CGisItemWpt * wpt = dynamic_cast(project->child(n)); if(wpt && wpt->isGeocache()) { QString name = wpt->getName(); quint32 size = name.size(); QString path = QString("%1/%2/%3").arg(name.at(size-1)).arg(name.at(size -2)).arg(name); QDir dirSpoilers(dir.absoluteFilePath(pathSpoilers)); QDir dirCache(dirSpoilers.absoluteFilePath(path)); dirCache.removeRecursively(); } } if(!pathAdventures.isEmpty()) { const QDir dirAdventures(dir.absoluteFilePath(pathAdventures)); QString filename = dirAdventures.absoluteFilePath(key + ".adv"); QFile::remove(filename); } } qmapshack-1.10.0/src/device/CDeviceGarmin.h000644 001750 000144 00000004327 13216234142 021565 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDEVICEGARMIN_H #define CDEVICEGARMIN_H #include "device/IDevice.h" class CDeviceGarminArchive; class CDeviceGarmin : public IDevice { Q_DECLARE_TR_FUNCTIONS(CDeviceGarmin) public: CDeviceGarmin(const QString &path, const QString &key, const QString& model, const QString &garminDeviceXml, QTreeWidget * parent); virtual ~CDeviceGarmin(); void insertCopyOfProject(IGisProject *project) override; void startSavingProject(IGisProject *project) override; void saveImages(CGisItemWpt& wpt) override; void loadImages(CGisItemWpt& wpt) override; void aboutToRemoveProject(IGisProject *project) override; private: void createProjectsFromFiles(QString subdirecoty, QString fileEnding); void createAdventureFromProject(IGisProject * project, const QString &gpxFilename); QString id; QString partno; QString description; QString pathGpx = "Garmin/GPX"; QString pathPictures = "Garmin/JPEG"; QString pathSpoilers = "Garmin/GeocachePhotos"; QString pathActivities = "Garmin/Activities"; QString pathCourses = "Garmin/Courses"; QString pathLocations = "Garmin/Locations"; QString pathAdventures; // no default int cntImages = 0; CDeviceGarminArchive * archive = nullptr; }; #endif //CDEVICEGARMIN_H qmapshack-1.10.0/src/device/CDeviceTwoNav.cpp000644 001750 000144 00000010277 13216234137 022126 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "device/CDeviceTwoNav.h" #include "gis/CGisListWks.h" #include "gis/gpx/CGpxProject.h" #include "gis/tnv/CTwoNavProject.h" #include CDeviceTwoNav::CDeviceTwoNav(const QString &path, const QString &key, const QString& model, QTreeWidget *parent) : IDevice(path, eTypeTwoNav, key, parent) { setText(CGisListWks::eColumnName, QString("TwoNav (%1)").arg(model)); setToolTip(CGisListWks::eColumnName, QString("TwoNav (%1)").arg(model)); if(QFile::exists(dir.absoluteFilePath("TwoNav/RegInfo.ini"))) { readReginfo(dir.absoluteFilePath("TwoNav/RegInfo.ini")); } else if(QFile::exists(dir.absoluteFilePath("TwoNavData/RegInfo.ini"))) { readReginfo(dir.absoluteFilePath("TwoNavData/RegInfo.ini")); } pathData = "TwoNavData/Data/"; QDir dirData(dir.absoluteFilePath(pathData)); { IGisProject * project = new CTwoNavProject(dirData.absolutePath(), this); if(!project->isValid()) { delete project; } } QStringList entries = dirData.entryList(QStringList("*.gpx")); for(const QString &entry : entries) { IGisProject * project = new CGpxProject(dirData.absoluteFilePath(entry), this); if(!project->isValid()) { delete project; } } entries = dirData.entryList(QDir::NoDotAndDotDot|QDir::Dirs); for(const QString &entry : entries) { IGisProject * project = new CTwoNavProject(dirData.absoluteFilePath(entry), this); if(!project->isValid()) { delete project; } } // special case: read the gpx files in the track log directory. dirData = dir.absoluteFilePath(pathData + "Tracklog"); entries = dirData.entryList(QStringList("*.gpx")); for(const QString &entry : entries) { IGisProject * project = new CGpxProject(dirData.absoluteFilePath(entry), this); if(!project->isValid()) { delete project; } } } CDeviceTwoNav::~CDeviceTwoNav() { } void CDeviceTwoNav::readReginfo(const QString& filename) { QString product, unittype; QRegExp re("(.*)=(.*)"); QFile file(filename); file.open(QIODevice::ReadOnly); while(!file.atEnd()) { QString line = file.readLine().simplified(); if(re.exactMatch(line)) { QString tok = re.cap(1); QString val = re.cap(2); if(tok == "product") { product = val; } else if(tok == "unittype") { unittype = val; } } } if(!product.isEmpty() && !unittype.isEmpty()) { setText(CGisListWks::eColumnName, QString("%1 (%2)").arg(product).arg(unittype)); } } void CDeviceTwoNav::insertCopyOfProject(IGisProject * project) { QString name = project->getName(); name = name.remove(QRegExp("[^A-Za-z0-9_]")); QDir dirData = dir.absoluteFilePath(pathData); QString filename = dirData.absoluteFilePath(name); if(testForExternalProject(filename)) { return; } CTwoNavProject * proj = new CTwoNavProject(filename, project, this); if(!proj->isValid()) { delete proj; return; } if(!proj->save()) { proj->remove(); delete proj; return; } } qmapshack-1.10.0/src/device/CDeviceWatcherLinux.cpp000644 001750 000144 00000015370 13216234137 023324 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "device/CDeviceWatcherLinux.h" #include "device/IDevice.h" #include "gis/CGisListWks.h" #include #include #include CDeviceWatcherLinux::CDeviceWatcherLinux(CGisListWks *parent) : IDeviceWatcher(parent) { QDBusConnection::systemBus().connect("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", this, SLOT(slotDeviceAdded(QDBusObjectPath,QVariantMap))); QDBusConnection::systemBus().connect("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", this, SLOT(slotDeviceRemoved(QDBusObjectPath,QStringList))); } CDeviceWatcherLinux::~CDeviceWatcherLinux() { } void CDeviceWatcherLinux::slotDeviceAdded(const QDBusObjectPath& path, const QVariantMap& map) { // ignore all paths other than a filesystem if(!map.contains("org.freedesktop.UDisks2.Filesystem")) { return; } // create path of to drive the block device belongs to QDBusInterface * blockIface = new QDBusInterface("org.freedesktop.UDisks2", path.path(), "org.freedesktop.UDisks2.Block", QDBusConnection::systemBus(), this); QDBusObjectPath drive_object = blockIface->property("Drive").value(); // read vendor string attached to drive QDBusInterface * driveIface = new QDBusInterface("org.freedesktop.UDisks2", drive_object.path(),"org.freedesktop.UDisks2.Drive", QDBusConnection::systemBus(), this); QString vendor = driveIface->property("Vendor").toString(); QString model = driveIface->property("Model").toString(); delete blockIface; delete driveIface; #if !defined(Q_OS_FREEBSD) // currently bsdisks does not report model or vendor qDebug() << "model:" << model << "vendor:" << vendor; if(model.isEmpty() || vendor.isEmpty()) { return; } #endif QString strPath = path.path(); IDevice::mount(strPath); QString mountPoint = readMountPoint(strPath); probeForDevice(mountPoint, strPath, QFileInfo(mountPoint).fileName()); IDevice::umount(strPath); } void CDeviceWatcherLinux::slotDeviceRemoved(const QDBusObjectPath& path, const QStringList& list) { // ignore all paths other than a filesystem if(!list.contains("org.freedesktop.UDisks2.Filesystem")) { return; } qDebug() << "slotDeviceRemoved" << path.path() << list; listWks->removeDevice(path.path()); } void CDeviceWatcherLinux::slotUpdate() { QList paths; QDBusMessage call = QDBusMessage::createMethodCall("org.freedesktop.UDisks2","/org/freedesktop/UDisks2/block_devices","org.freedesktop.DBus.Introspectable","Introspect"); QDBusPendingReply reply = QDBusConnection::systemBus().call(call); if (!reply.isValid()) { qWarning("UDisks2Manager: error: %s", qPrintable(reply.error().name())); return; } QDomDocument doc; doc.setContent(reply); const QDomElement& xmlRoot = doc.documentElement(); const QDomNodeList& xmlNodes = xmlRoot.elementsByTagName("node"); const int N = xmlNodes.count(); for(int n = 0; n < N; n++) { const QDomNode& xmlNode = xmlNodes.item(n); const QDomNamedNodeMap& attr = xmlNode.attributes(); QString name = attr.namedItem("name").nodeValue(); if(!name.isEmpty()) { paths << QDBusObjectPath("/org/freedesktop/UDisks2/block_devices/" + name); } } for(const QDBusObjectPath &path : paths) { QDBusMessage call = QDBusMessage::createMethodCall("org.freedesktop.UDisks2", path.path(), "org.freedesktop.DBus.Introspectable","Introspect"); QDBusPendingReply reply = QDBusConnection::systemBus().call(call); if (!reply.isValid()) { qWarning("UDisks2Manager: error: %s", qPrintable(reply.error().name())); continue; } QDomDocument doc; doc.setContent(reply); const QDomElement& xmlRoot = doc.documentElement(); const QDomNodeList& xmlInterfaces = xmlRoot.elementsByTagName("interface"); const int N = xmlInterfaces.count(); for(int n = 0; n < N; n++) { const QDomNode& xmlInterface = xmlInterfaces.item(n); const QDomNamedNodeMap& attr = xmlInterface.attributes(); if(attr.namedItem("name").nodeValue() == "org.freedesktop.UDisks2.Filesystem") { QVariantMap map; map["org.freedesktop.UDisks2.Filesystem"] = QVariant(); slotDeviceAdded(path, map); } } } } QString CDeviceWatcherLinux::readMountPoint(const QString& path) { QStringList points; QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.UDisks2",path,"org.freedesktop.DBus.Properties","Get"); QList args; args << "org.freedesktop.UDisks2.Filesystem" << "MountPoints"; message.setArguments(args); QDBusMessage reply = QDBusConnection::systemBus().call(message); #if defined(Q_OS_FREEBSD) for(const QVariant &arg : reply.arguments()) { points.append(arg.value().variant().value().first()); } #else QList list; for(const QVariant &arg : reply.arguments()) { arg.value().variant().value() >> list; } for(const QByteArray &point : list) { points.append(point); } #endif if(!points.isEmpty()) { return points.first(); } return ""; } qmapshack-1.10.0/src/device/CDeviceWatcherMac.cpp000644 001750 000144 00000010513 13216234137 022717 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "device/CDeviceWatcherMac.h" #include "device/IDevice.h" #include "gis/CGisListWks.h" #include CDeviceWatcherMac::CDeviceWatcherMac(CGisListWks *parent) : IDeviceWatcher(parent), worker() { connect(&worker, &CDeviceWorker::sigDeviceAdded, this, &CDeviceWatcherMac::slotDeviceAdded); connect(&worker, &CDeviceWorker::sigDeviceRemoved, this, &CDeviceWatcherMac::slotDeviceRemoved); connect(qApp, &QApplication::aboutToQuit, this, &CDeviceWatcherMac::slotEndListing); } void CDeviceWatcherMac::addDevice(const QStorageInfo& storage) { if (storage.isValid() && storage.isReady()) { QString dev = QString(storage.device()).section('/', -1); if (!deviceList.contains(dev)) { // We don't care about content of device. This is done in the probeForDevice() method. deviceList.append(dev); QString path = storage.rootPath(); QString label = storage.name(); qDebug() << "label:" << label << " root path: " << path << " device: " << dev; probeForDevice(path, dev, label); } } } void CDeviceWatcherMac::slotEndListing() { worker.stop(); } // Aufruf 1s. nach instanzierung void CDeviceWatcherMac::slotUpdate() { qDebug() << "slotUpdate"; for(const QStorageInfo &storage : QStorageInfo::mountedVolumes()) { addDevice(storage); } } void CDeviceWatcherMac::slotDeviceAdded(QString dev) { // get mount point QStorageInfo storageInfo; for(const QStorageInfo &storage : QStorageInfo::mountedVolumes()) { QString diskName = QString(storage.device()).section('/', -1); if(dev == diskName) { storageInfo = storage; } } qDebug() << "slotDeviceAdded" << dev << " " << storageInfo.rootPath(); addDevice(storageInfo); } void CDeviceWatcherMac::slotDeviceRemoved(QString dev) { qDebug() << "slotDeviceRemoved" << dev; deviceList.removeAll(dev); listWks->removeDevice(dev); } static void onDiskAppear(DADiskRef disk, CFArrayRef keys, void* context) { CDeviceWorker *p = static_cast(context); QString diskName = DADiskGetBSDName(disk); qDebug() << "onDiskAppear" << diskName; emit p->sigDeviceAdded(diskName); } static void onDiskDisappear(DADiskRef disk, void *context) { CDeviceWorker *p = static_cast(context); QString diskName = DADiskGetBSDName(disk); qDebug() << "onDiskDisappear" << diskName; emit p->sigDeviceRemoved(diskName); } CDeviceWorker::CDeviceWorker() : QThread() { mSession = DASessionCreate(kCFAllocatorDefault); DARegisterDiskDescriptionChangedCallback(mSession, nullptr, kDADiskDescriptionWatchVolumePath, onDiskAppear, this); DARegisterDiskDisappearedCallback(mSession, nullptr, onDiskDisappear, this); QThread::start(); } void CDeviceWorker::stop() { mStop = true; wait(); DAUnregisterCallback(mSession, (void*)onDiskAppear, this); DAUnregisterCallback(mSession, (void*)onDiskDisappear, this); qDebug() << "CDeviceWorker Thread.stop"; } void CDeviceWorker::run() { qDebug() << "CDeviceWorker Thread.run"; mStop = false; DASessionScheduleWithRunLoop(mSession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); SInt32 result; do { result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, true); } while (!mStop && result); DASessionUnscheduleFromRunLoop(mSession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); } qmapshack-1.10.0/src/canvas/000755 001750 000144 00000000000 13216664443 016775 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/canvas/CCanvas.h000644 001750 000144 00000017312 13216234261 020457 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CCANVAS_H #define CCANVAS_H #include #include #include #include #include #include "gis/IGisItem.h" class CMapDraw; class CGrid; class CDemDraw; class QGestureEvent; class CGisDraw; class CGisItemWpt; class CGisItemTrk; class CGisItemRte; class CGisItemOvlArea; class CColorLegend; class QSettings; class QPointF; class IMouse; class QTimer; class QMovie; class QLabel; class IPlot; struct SGisLine; struct poi_t; class CCanvas : public QWidget { Q_OBJECT public: CCanvas(QWidget * parent, const QString& name); virtual ~CCanvas(); static void setOverrideCursor(const QCursor &cursor, const QString&); static void restoreOverrideCursor(const QString &src); static void changeOverrideCursor(const QCursor& cursor, const QString &src); void saveConfig(QSettings& cfg); void loadConfig(QSettings& cfg); void setupGrid(); void convertGridPos2Str(const QPointF& pos, QString& str, bool simple); void convertRad2Px(QPointF &pos) const; void convertPx2Rad(QPointF& pos) const; void setupBackgroundColor(); void setup(); QString getProjection(); void setProjection(const QString& proj); enum scales_type_e { eScalesDefault , eScalesSquare }; void setScales(const scales_type_e type); scales_type_e getScalesType(); qreal getElevationAt(const QPointF &pos) const; void getElevationAt(const QPolygonF& pos, QPolygonF &ele) const; void getElevationAt(SGisLine &line) const; qreal getSlopeAt(const QPointF &pos) const; void getSlopeAt(const QPolygonF& pos, QPolygonF& slope) const; void moveMap(const QPointF &delta); void zoomTo(const QRectF& rect); void displayInfo(const QPoint& px); poi_t findPOICloseBy(const QPoint& px) const; enum redraw_e { eRedrawNone = 0 , eRedrawMap = 0x01 , eRedrawDem = 0x02 , eRedrawGis = 0x04 , eRedrawMouse = 0x08 , eRedrawAll = 0xFFFFFFFF }; static void triggerCompleteUpdate(CCanvas::redraw_e flags); void resetMouse(); void mouseTrackingLost(); void setMouseMoveWpt(CGisItemWpt& wpt); void setMouseRadiusWpt(CGisItemWpt& wpt); void setMouseEditTrk(CGisItemTrk& trk); void setMouseRangeTrk(CGisItemTrk& trk); void setMouseEditTrk(const QPointF& pt); void setMouseEditRte(const QPointF& pt); void setMouseEditRte(CGisItemRte& rte); void setMouseEditArea(CGisItemOvlArea& area); void setMouseEditArea(const QPointF& pt); void setMouseWptBubble(const IGisItem::key_t& key); void setMousePrint(); void setMouseSelect(); void showProfileAsWindow(bool yes); void showProfile(bool yes); /** @brief Add a message by key to be reported on the canvas Messages from various sources will be collected in a list and displayed in the top left corner of the widget. @note The object reporting has to take care to remove the message by reporting an empty string. @param key the key to identify the reporting object @param msg the message to report */ void reportStatus(const QString& key, const QString& msg); /** @brief Find a matching street polyline The polyline must be close enough in terms of pixel to point 1 and 2. "Close enough" is defined by the threshold. The returned polyline uses lon/lat as coordinates. @param pt1 first point in [rad] @param pt2 second point in [rad] @param threshold the "close enough" threshold in [pixel] @param polyline the resulting polyline, if any, in [rad] @return Return true if a line has been found. */ bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline); void print(QPainter &p, const QRectF& area, const QPointF &focus); static qreal gisLayerOpacity; signals: void sigMousePosition(const QPointF& pos, qreal ele, qreal slope); void sigZoom(); void sigMove(); public slots: void slotTriggerCompleteUpdate(CCanvas::redraw_e flags); void slotUpdateTrackStatistic(bool show); protected: bool event(QEvent *) override; bool gestureEvent(QGestureEvent *e); void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseDoubleClickEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; void enterEvent(QEvent *e) override; void leaveEvent(QEvent *e) override; void keyPressEvent(QKeyEvent *e) override; private slots: void slotToolTip(); void slotCheckTrackOnFocus(); private: void drawStatusMessages(QPainter& p); void drawTrackStatistic(QPainter& p); void drawScale(QPainter& p); void setZoom(bool in, redraw_e &needsRedraw); void setSizeTrackProfile(); void saveSizeTrackProfile(); void setDrawContextSize(const QSize& s); void setMouseCursor(IMouse& mouse, const QString& src); QColor backColor = "#FFFFBF"; //< the background color used in case of missing map tiles redraw_e needsRedraw = eRedrawAll; //< set true to initiate a complete redraw of the screen content CMapDraw * map; //< the map object attached to this canvas CDemDraw * dem; //< the elevation data layer attached to this canvas CGisDraw * gis; //< the GIS data layer attached to this canvas CGrid * grid; //< the grid attached to this canvas /// the current point of focus (usually the canvas center) QPointF posFocus {12.00 * DEG_TO_RAD, 49.00 * DEG_TO_RAD}; /// the current mouse handler IMouse * mouse; /// tool tip timer for vector map tool tips QTimer * timerToolTip; /// the position of the tool tip QPoint posToolTip; /// load indicator for maps QMovie * loadIndicator1; QLabel * mapLoadIndicator; /// load indicator for DEM QMovie * loadIndicator2; QLabel * demLoadIndicator; QPointer colorLegend; /// current accumulated angleDelta, used/required for zooming on trackpads int zoomAngleDelta = 0; /// timer to poll for track gaining/loosing focus QTimer * timerTrackOnFocus; /// the key of the currently focused track IGisItem::key_t keyTrackOnFocus; /// the track profile plot QPointer plotTrackProfile; /// a label with a track QLabel * labelTrackStatistic; QLabel * labelStatusMessages; QMap statusMessages; QMutex mousePressMutex; bool mouseLost = false; }; #endif //CCANVAS_H qmapshack-1.10.0/src/canvas/IDrawContext.h000644 001750 000144 00000016065 13216234142 021516 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDRAWCONTEXT_H #define IDRAWCONTEXT_H #include #include #include #include #include #include "canvas/CCanvas.h" #define CANVAS_MAX_ZOOM_LEVELS 31 class IDrawContext : public QThread { Q_OBJECT public: IDrawContext(const QString &name, CCanvas::redraw_e maskRedraw, CCanvas *parent); virtual ~IDrawContext(); struct buffer_t { /// @note: all coordinate values are long/lat WGS84 [rad] QImage image; //< the canvas buffer projPJ pjsrc; //< the used projection int zoomLevels; //< the number of zoom levels QPointF zoomFactor {1.0,1.0}; //< the zoomfactor used to draw the canvas QPointF scale {1.0,1.0}; //< the scale of the global viewport QPointF ref1; //< top left corner QPointF ref2; //< top right corner QPointF ref3; //< bottom right corner QPointF ref4; //< bottom left corner QPointF focus; //< point of focus }; /** @brief resize the internal buffer @param size the new size of the canvas */ void resize(const QSize& size); /** @brief Zoom in and out of the map by the scale factors defined in CMapDB::scales. @param in set true to zoom in, and false to zoom out @param needsRedraw if the zoom action makes a redraw necessary needsRedraw is set true */ void zoom(bool in, CCanvas::redraw_e &needsRedraw); void zoom(int idx); void zoom(const QRectF& rect); int zoom() const { return zoomIndex; } /** @brief Convert a geo coordinate of format lon/lat WGS84 into the currently used coordinate/projection/datum system. @note The unit is dependent on the currently used projection and must not necessarily be meter @param p the point to convert */ void convertRad2M(QPointF &p) const; /** @brief Convert a geo coordinate of the currently used projection/datum to lon/lat WGS84 @note The unit is dependent on the currently used projection and must not necessarily be meter @param p the point to convert */ void convertM2Rad(QPointF &p) const; /** @brief Convert a pixel coordinate from the viewport to a geo coordinate in [rad] @param p the point to convert */ void convertPx2Rad(QPointF& p) const; /** @brief Convert a geo coordinate in [rad] to a pixel coordinate of the viewport @param p the point to convert */ void convertRad2Px(QPointF& p) const; void convertRad2Px(QPolygonF& poly) const; /** @brief Check if the internal needs redraw flag is set @return intNeedsRedraw is returned */ bool needsRedraw() const; /** @brief Draw the active map buffer to the painter @param p the painter used to draw the map @param needsRedraw set true to trigger a redraw in the background thread @param f the point of focus in [°] that is drawn in the middle of the viewport. */ void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QPointF &f); /** @brief Get the projection string of this map object @return A proj4 string. */ QString getProjection() const; CCanvas::scales_type_e getScalesType() const { return scalesType; } const QPointF& getZoomFactor() const { return zoomFactor; } /** @brief Set the projection of the draw context This will just create a new source projection object (pjsrc). Most likely you want to override this method to: 1) save what ever has to be saved 2) call this method 3) restore everything with the new projection @param proj a Proj4 projection string */ virtual void setProjection(const QString& proj); virtual void setScales(const CCanvas::scales_type_e type); signals: void sigCanvasUpdate(CCanvas::redraw_e flags); void sigStartThread(); void sigStopThread(); void sigScaleChanged(const QPointF& scale); public slots: void emitSigCanvasUpdate(); protected: void run() override; /** @brief The draw method called from the thread. That's where the actual drawing has to be done @param currentBuffer this is the current buffer reserved for the thread to draw on. */ virtual void drawt(buffer_t& currentBuffer) = 0; /** @brief The global list of available scale factors */ static const qreal scalesDefault[]; static const qreal scalesSquare[]; /// the mutex to serialize access mutable QMutex mutex; /// internal needs redraw flag bool intNeedsRedraw; /// the canvas this map object is attached to CCanvas * canvas; const CCanvas::redraw_e maskRedraw; /// map canvas twin buffer buffer_t buffer[2]; /// the main threads currently used map canvas buffer bool bufIndex = false; int bufWidth = 100; //< buffer width [px] int bufHeight = 100; //< buffer height [px] int viewWidth = 100; //< the viewports width [px] int viewHeight = 100; //< the viewports height [px] QPointF center; /// the center of the viewport projPJ pjsrc; //< source projection should be the same for all maps projPJ pjtar; //< target projection is always WGS84 /// index into scales table int zoomIndex = 0; private: /// the used scales and the type of scale levels const qreal *scales = nullptr; CCanvas::scales_type_e scalesType; /// the number of zoom levels int zoomLevels = 0; /// the basic scale of the map canvas QPointF scale {1.0,-1.0}; /// the actual used scaleFactor QPointF zoomFactor; QPointF focus; //< the next point of focus that will be displayed right in the middle of the viewport QPointF ref1; //< top left corner of next buffer QPointF ref2; //< top right corner of next buffer QPointF ref3; //< bottom right corner of next buffer QPointF ref4; //< bottom left corner of next buffer }; extern QPointF operator*(const QPointF& p1, const QPointF& p2); extern QPointF operator/(const QPointF& p1, const QPointF& p2); #endif //IDRAWCONTEXT_H qmapshack-1.10.0/src/canvas/CCanvasSetup.h000644 001750 000144 00000002450 13216234142 021473 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCANVASSETUP_H #define CCANVASSETUP_H #include "ui_ICanvasSetup.h" #include class CCanvas; class CCanvasSetup : public QDialog, private Ui::ICanvasSetup { Q_OBJECT public: CCanvasSetup(CCanvas *canvas); virtual ~CCanvasSetup(); public slots: void accept() override; protected slots: void slotProjWizard(); protected: CCanvas * canvas; }; #endif //CCANVASSETUP_H qmapshack-1.10.0/src/canvas/IDrawObject.cpp000644 001750 000144 00000014704 13216234137 021635 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/IDrawContext.h" #include "canvas/IDrawObject.h" #include "units/IUnit.h" #include IDrawObject::IDrawObject(QObject *parent) : QObject(parent) { } IDrawObject::~IDrawObject() { } void IDrawObject::saveConfig(QSettings& cfg) { cfg.setValue("opacity", getOpacity()); cfg.setValue("minScale", getMinScale()); cfg.setValue("maxScale", getMaxScale()); } void IDrawObject::loadConfig(QSettings& cfg) { slotSetOpacity(cfg.value("opacity", getOpacity() ).toDouble()); setMinScale( cfg.value("minScale", getMinScale()).toDouble()); setMaxScale( cfg.value("maxScale", getMaxScale()).toDouble()); emit sigPropertiesChanged(); } bool IDrawObject::isOutOfScale(const QPointF& scale) const { if((getMinScale() != NOFLOAT) && (scale.x() < getMinScale())) { return true; } if((getMaxScale() != NOFLOAT) && (scale.x() > getMaxScale())) { return true; } return false; } void IDrawObject::getLayers(QListWidget& list) { list.clear(); } void IDrawObject::setMinScale(qreal s) { if((s != NOFLOAT) && (maxScale != NOFLOAT)) { if(s > maxScale) { return; } } minScale = s; } void IDrawObject::setMaxScale(qreal s) { if((s != NOFLOAT) && (minScale != NOFLOAT)) { if(s < minScale) { return; } } maxScale = s; } void IDrawObject::drawTileLQ(const QImage& img, QPolygonF& l, QPainter& p, IDrawContext& context, projPJ pjsrc, projPJ pjtar) { QPolygonF tmp = l; context.convertRad2Px(l); // adjust the tiles width and height to fit the buffer's scale qreal dx1 = l[0].x() - l[1].x(); qreal dy1 = l[0].y() - l[1].y(); qreal dx2 = l[0].x() - l[3].x(); qreal dy2 = l[0].y() - l[3].y(); qreal w = qCeil( qSqrt(dx1*dx1 + dy1*dy1)); qreal h = qCeil( qSqrt(dx2*dx2 + dy2*dy2)); // switch to HQ if the gaps get visible if(context.getZoomFactor().x() > 70) { if((qAbs(dy1) > 2) || (qAbs(dx2) > 2)) { drawTileHQ(img, tmp, p, context, pjsrc, pjtar); return; } } // calculate rotation. This is not really a reprojection but might be good enough for close zoom levels qreal a = qAtan(dy1/dx1) * RAD_TO_DEG; // finally translate, scale, rotate and draw tile p.save(); p.translate(l[0]); p.scale(w/img.width(), h/img.height()); p.rotate(a); p.drawImage(0,0,img); p.restore(); } void IDrawObject::drawTileHQ(const QImage& img, QPolygonF& l, QPainter& p, IDrawContext& context, projPJ pjsrc, projPJ pjtar) { // the sub-tiles need a sensible size // if they get too small there will be too much // rounding effects. qint32 nStepsX = 8; qint32 nStepsY = 8; if(img.width()/nStepsX < 32) { nStepsX = 4; } if(img.height()/nStepsY < 32) { nStepsY = 4; } // transform the rad coordinates from l into the coord. system // of the map pj_transform(pjtar, pjsrc, 4, 2, &l[0].rx(), &l[0].ry(), 0); // calculate nStepsX*nStepsY squares evenly distributed over the tile // in map coords qreal subStepX = (l[1].x() - l[0].x()) / nStepsX; qreal subStepY = (l[3].y() - l[0].y()) / nStepsY; qreal offsetX = l[0].x(); qreal offsetY = l[0].y(); QPolygonF quads(nStepsX * nStepsY * 4); QPointF* pPt = quads.data(); for(int y = 0; y < nStepsY; ++y) { for(int x = 0; x < nStepsX; ++x) { pPt->rx() = offsetX; pPt->ry() = offsetY; ++pPt; pPt->rx() = offsetX + subStepX; pPt->ry() = offsetY; ++pPt; pPt->rx() = offsetX + subStepX; pPt->ry() = offsetY + subStepY; ++pPt; pPt->rx() = offsetX; pPt->ry() = offsetY + subStepY; ++pPt; offsetX += subStepX; } offsetX = l[0].x(); offsetY += subStepY; } // transform the squares back to lon/lat coords in rad pj_transform(pjsrc, pjtar, nStepsX * nStepsY * 4, 2, &quads[0].rx(), &quads[0].ry(), 0); // convert the lon/lat coords of the squares into pixel coords of the // canvas using the view's projection context.convertRad2Px(quads); QRectF rect(0,0, img.width()/nStepsX, img.height() / nStepsY); const qreal rw = rect.width(); const qreal rh = rect.height(); // iterate over all squares, calculate the translation and rotation and draw the part of the // tile matching the square. pPt = quads.data(); for(int y = 0; y < nStepsY; ++y) { rect.moveTop(y * rh); for(int x = 0; x < nStepsX; ++x, pPt += 4) { // adjust the tiles width and height to fit the buffer's scale qreal dx1 = pPt[0].x() - pPt[1].x(); qreal dy1 = pPt[0].y() - pPt[1].y(); qreal dx2 = pPt[0].x() - pPt[3].x(); qreal dy2 = pPt[0].y() - pPt[3].y(); qreal w = /*qRound*/ ( qSqrt(dx1*dx1 + dy1*dy1)); qreal h = /*qRound*/ ( qSqrt(dx2*dx2 + dy2*dy2)); // calculate rotation. This is not really a reprojection but might be good enough for close zoom levels qreal a = qAtan(dy1/dx1) * RAD_TO_DEG; // move rect to select the part of the tile to draw. rect.moveLeft(x * rw); // finally translate, scale, rotate and draw tile p.save(); p.translate(pPt[0]); p.scale(w/rw, h/rh); p.rotate(a); p.drawImage(QPoint(0,0),img, rect); p.restore(); } } } qmapshack-1.10.0/src/canvas/CCanvas.cpp000644 001750 000144 00000063644 13216234261 021023 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "canvas/CCanvasSetup.h" #include "dem/CDemDraw.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/IGisLine.h" #include "gis/Poi.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/trk/CGisItemTrk.h" #include "grid/CGrid.h" #include "grid/CGridSetup.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "map/CMapDraw.h" #include "mouse/CMouseEditArea.h" #include "mouse/CMouseEditRte.h" #include "mouse/CMouseEditTrk.h" #include "mouse/CMouseMoveWpt.h" #include "mouse/CMouseNormal.h" #include "mouse/CMousePrint.h" #include "mouse/CMouseRadiusWpt.h" #include "mouse/CMouseRangeTrk.h" #include "mouse/CMouseSelect.h" #include "mouse/CMouseWptBubble.h" #include "plot/CPlotProfile.h" #include "units/IUnit.h" #include "widgets/CColorLegend.h" #include qreal CCanvas::gisLayerOpacity = 1.0; CCanvas::CCanvas(QWidget *parent, const QString &name) : QWidget(parent) { setFocusPolicy(Qt::WheelFocus); if(name.isEmpty()) { for(int count = 1;; ++count) { QString name = tr("View %1").arg(count); if(nullptr == CMainWindow::self().findChild(name)) { setObjectName(name); break; } } } else { setObjectName(name); } setMouseTracking(true); grabGesture(Qt::PinchGesture); map = new CMapDraw(this); grid = new CGrid(map); dem = new CDemDraw(this); gis = new CGisDraw(this); mouse = new CMouseNormal(gis, this); connect(map, &CMapDraw::sigCanvasUpdate, this, &CCanvas::slotTriggerCompleteUpdate); connect(dem, &CDemDraw::sigCanvasUpdate, this, &CCanvas::slotTriggerCompleteUpdate); connect(gis, &CGisDraw::sigCanvasUpdate, this, &CCanvas::slotTriggerCompleteUpdate); timerToolTip = new QTimer(this); timerToolTip->setSingleShot(true); connect(timerToolTip, &QTimer::timeout, this, &CCanvas::slotToolTip); loadIndicator1 = new QMovie("://animation/loader.gif", QByteArray(), this); mapLoadIndicator = new QLabel(this); mapLoadIndicator->setMovie(loadIndicator1); loadIndicator1->start(); mapLoadIndicator->show(); loadIndicator2 = new QMovie("://animation/loader2.gif", QByteArray(), this); demLoadIndicator = new QLabel(this); demLoadIndicator->setMovie(loadIndicator2); loadIndicator2->start(); demLoadIndicator->show(); labelStatusMessages = new QLabel(this); labelStatusMessages->setWordWrap(true); labelStatusMessages->setMinimumWidth(300); labelStatusMessages->hide(); labelTrackStatistic = new QLabel(this); labelTrackStatistic->setWordWrap(true); labelTrackStatistic->setMinimumWidth(300); labelTrackStatistic->hide(); connect(map, &CMapDraw::sigStartThread, mapLoadIndicator, &QLabel::show); connect(map, &CMapDraw::sigStopThread, mapLoadIndicator, &QLabel::hide); connect(dem, &CDemDraw::sigStartThread, demLoadIndicator, &QLabel::show); connect(dem, &CDemDraw::sigStopThread, demLoadIndicator, &QLabel::hide); timerTrackOnFocus = new QTimer(this); timerTrackOnFocus->setSingleShot(false); timerTrackOnFocus->start(1000); connect(timerTrackOnFocus, &QTimer::timeout, this, &CCanvas::slotCheckTrackOnFocus); } CCanvas::~CCanvas() { /* stop running drawing-threads and don't destroy unless they have finished*/ map->quit(); dem->quit(); gis->quit(); map->wait(); dem->wait(); gis->wait(); /* Some mouse objects call methods from their canvas on destruction. So they are better deleted now explicitly before any other object in CCanvas is destroyed. */ delete mouse; saveSizeTrackProfile(); } void CCanvas::setOverrideCursor(const QCursor &cursor, const QString&) { // qDebug() << "setOverrideCursor" << src; QApplication::setOverrideCursor(cursor); } void CCanvas::restoreOverrideCursor(const QString& src) { // qDebug() << "restoreOverrideCursor" << src; QApplication::restoreOverrideCursor(); } void CCanvas::changeOverrideCursor(const QCursor& cursor, const QString &src) { // qDebug() << "changeOverrideCursor" << src; QApplication::changeOverrideCursor(cursor); } void CCanvas::triggerCompleteUpdate(CCanvas::redraw_e flags) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(flags); } } void CCanvas::saveConfig(QSettings& cfg) { map->saveConfig(cfg); dem->saveConfig(cfg); grid->saveConfig(cfg); cfg.setValue("posFocus", posFocus); cfg.setValue("proj", map->getProjection()); cfg.setValue("scales", map->getScalesType()); cfg.setValue("backColor", backColor.name()); } void CCanvas::loadConfig(QSettings& cfg) { posFocus = cfg.value("posFocus", posFocus).toPointF(); setProjection(cfg.value("proj", map->getProjection()).toString()); setScales((CCanvas::scales_type_e)cfg.value("scales", map->getScalesType()).toInt()); const QString &backColorStr = cfg.value("backColor", "#FFFFBF").toString(); backColor = QColor(backColorStr); map->loadConfig(cfg); dem->loadConfig(cfg); grid->loadConfig(cfg); dem->zoom(map->zoom()); gis->zoom(map->zoom()); } void CCanvas::resetMouse() { mouse->deleteLater(); mouse = new CMouseNormal(gis, this); if(underMouse()) { while(QApplication::overrideCursor()) { CCanvas::restoreOverrideCursor("resetMouse"); } CCanvas::setOverrideCursor(*mouse, "resetMouse"); } } void CCanvas::mouseTrackingLost() { mouseLost = true; } void CCanvas::setMouseCursor(IMouse& mouse, const QString& src) { if(underMouse()) { CCanvas::restoreOverrideCursor(src); CCanvas::setOverrideCursor(mouse, src); } } void CCanvas::setMouseMoveWpt(CGisItemWpt& wpt) { mouse->deleteLater(); mouse = new CMouseMoveWpt(wpt, gis, this); setMouseCursor(*mouse, "setMouseMoveWpt"); } void CCanvas::setMouseRadiusWpt(CGisItemWpt& wpt) { mouse->deleteLater(); mouse = new CMouseRadiusWpt(wpt, gis, this); setMouseCursor(*mouse, "setMouseWptRadius"); } void CCanvas::setMouseEditTrk(const QPointF &pt) { mouse->deleteLater(); mouse = new CMouseEditTrk(pt, gis, this); setMouseCursor(*mouse, "setMouseEditTrk"); } void CCanvas::setMouseEditRte(const QPointF &pt) { mouse->deleteLater(); mouse = new CMouseEditRte(pt, gis, this); setMouseCursor(*mouse, "setMouseEditRte"); } void CCanvas::setMouseEditTrk(CGisItemTrk& trk) { mouse->deleteLater(); mouse = new CMouseEditTrk(trk, gis, this); setMouseCursor(*mouse, "setMouseEditTrk"); } void CCanvas::setMouseRangeTrk(CGisItemTrk& trk) { mouse->deleteLater(); mouse = new CMouseRangeTrk(trk, gis, this); setMouseCursor(*mouse, "setMouseRangeTrk"); } void CCanvas::setMouseEditArea(const QPointF& pt) { mouse->deleteLater(); mouse = new CMouseEditArea(pt, gis, this); setMouseCursor(*mouse, "setMouseEditArea"); } void CCanvas::setMouseEditArea(CGisItemOvlArea& area) { mouse->deleteLater(); mouse = new CMouseEditArea(area, gis, this); setMouseCursor(*mouse, "setMouseEditArea"); } void CCanvas::setMouseEditRte(CGisItemRte& rte) { mouse->deleteLater(); mouse = new CMouseEditRte(rte, gis, this); setMouseCursor(*mouse, "setMouseEditRte"); } void CCanvas::setMouseWptBubble(const IGisItem::key_t& key) { mouse->deleteLater(); mouse = new CMouseWptBubble(key, gis, this); setMouseCursor(*mouse, "setMouseWptBubble"); } void CCanvas::setMousePrint() { mouse->deleteLater(); mouse = new CMousePrint(gis, this); setMouseCursor(*mouse, "setMousePrint"); } void CCanvas::setMouseSelect() { mouse->deleteLater(); mouse = new CMouseSelect(gis, this); setMouseCursor(*mouse, "setMouseSelect"); } void CCanvas::reportStatus(const QString& key, const QString& msg) { if(msg.isEmpty()) { statusMessages.remove(key); } else { statusMessages[key] = msg; } QString report; QStringList keys = statusMessages.keys(); keys.sort(); for(const QString &key : keys) { report += statusMessages[key] + "\n"; } if(report.isEmpty()) { labelStatusMessages->hide(); } else { labelStatusMessages->show(); labelStatusMessages->setText(report); labelStatusMessages->adjustSize(); } update(); } void CCanvas::resizeEvent(QResizeEvent * e) { needsRedraw = eRedrawAll; setDrawContextSize(e->size()); QWidget::resizeEvent(e); const QRect& r = rect(); // move map loading indicator to new center of canvas QPoint p1(mapLoadIndicator->width()>>1, mapLoadIndicator->height()>>1); mapLoadIndicator->move(r.center() - p1); QPoint p2(demLoadIndicator->width()>>1, demLoadIndicator->height()>>1); demLoadIndicator->move(r.center() - p2); labelStatusMessages->move(20,50); slotUpdateTrackStatistic(CMainWindow::self().isMinMaxTrackValues()); setSizeTrackProfile(); } void CCanvas::paintEvent(QPaintEvent*) { if(!isVisible()) { return; } QPainter p; p.begin(this); USE_ANTI_ALIASING(p,true); // fill the background with default pattern p.fillRect(rect(), backColor); // ----- start to draw thread based content ----- // move coordinate system to center of the screen p.translate(width() >> 1, height() >> 1); map->draw(p, needsRedraw, posFocus); dem->draw(p, needsRedraw, posFocus); p.setOpacity(gisLayerOpacity); gis->draw(p, needsRedraw, posFocus); p.setOpacity(1.0); // restore coordinate system to default p.resetTransform(); // ----- start to draw fast content ----- grid->draw(p, rect()); if(map->isFinished() && dem->isFinished() && gis->isFinished()) { gis->draw(p, rect()); } mouse->draw(p, needsRedraw, rect()); drawStatusMessages(p); drawTrackStatistic(p); drawScale(p); p.end(); needsRedraw = eRedrawNone; } void CCanvas::mousePressEvent(QMouseEvent * e) { if(!mousePressMutex.tryLock()) { return; } mouse->mousePressEvent(e); QWidget::mousePressEvent(e); e->accept(); mousePressMutex.unlock(); } void CCanvas::mouseMoveEvent(QMouseEvent * e) { QPointF pos = e->pos(); map->convertPx2Rad(pos); qreal ele = dem->getElevationAt(pos); qreal slope = dem->getSlopeAt(pos); emit sigMousePosition(pos * RAD_TO_DEG, ele, slope); mouse->mouseMoveEvent(e); QWidget::mouseMoveEvent(e); e->accept(); } void CCanvas::mouseReleaseEvent(QMouseEvent *e) { mouse->mouseReleaseEvent(e); QWidget::mouseReleaseEvent(e); e->accept(); } void CCanvas::mouseDoubleClickEvent(QMouseEvent * e) { mouse->mouseDoubleClickEvent(e); QWidget::mouseDoubleClickEvent(e); } void CCanvas::wheelEvent(QWheelEvent * e) { mouse->wheelEvent(e); // angleDelta() returns the eighths of a degree // of the mousewheel // -> zoom in/out every 15 degrees = every 120 eights const int EIGHTS_ZOOM = 15 * 8; zoomAngleDelta += e->angleDelta().y(); if(abs(zoomAngleDelta) < EIGHTS_ZOOM) { return; } zoomAngleDelta = 0; QPointF pos = e->posF(); QPointF pt1 = pos; map->convertPx2Rad(pt1); setZoom(CMainWindow::self().flipMouseWheel() ? (e->delta() < 0) : (e->delta() > 0), needsRedraw); map->convertRad2Px(pt1); map->convertRad2Px(posFocus); posFocus -= (pos - pt1); map->convertPx2Rad(posFocus); update(); } void CCanvas::enterEvent(QEvent * e) { Q_UNUSED(e); CCanvas::setOverrideCursor(*mouse, "enterEvent"); mouse->setMouseTracking(true); } void CCanvas::leaveEvent(QEvent *) { // bad hack to stop bad number of override cursors. while(QApplication::overrideCursor()) { CCanvas::restoreOverrideCursor("leaveEvent"); } mouse->setMouseTracking(false); } void CCanvas::keyPressEvent(QKeyEvent * e) { qDebug() << hex << e->key(); bool doUpdate = true; switch(e->key()) { case Qt::Key_Plus: setZoom(true, needsRedraw); break; case Qt::Key_Minus: setZoom(false, needsRedraw); break; /* move the map with keys up, down, left and right */ case Qt::Key_Up: moveMap(QPointF(0, height()/4)); break; case Qt::Key_Down: moveMap(QPointF(0, -height()/4)); break; case Qt::Key_Left: moveMap(QPointF( width()/4, 0)); break; case Qt::Key_Right: moveMap(QPointF(-width()/4, 0)); break; case Qt::Key_Escape: { IMouseEditLine *lineMouse = dynamic_cast(mouse); if(nullptr != lineMouse) { lineMouse->abortStep(); } else { doUpdate = false; } break; } default: doUpdate = false; } if(doUpdate) { mouse->keyPressEvent(e); e->accept(); update(); } else { QWidget::keyPressEvent(e); } } void CCanvas::drawStatusMessages(QPainter& p) { if(labelStatusMessages->isVisible()) { QRect r = labelStatusMessages->frameGeometry(); r.adjust(-5, -5, 5, 5); p.setPen(CDraw::penBorderGray); p.setBrush(CDraw::brushBackWhite); p.drawRoundedRect(r, RECT_RADIUS, RECT_RADIUS); } } void CCanvas::drawTrackStatistic(QPainter& p) { if(labelTrackStatistic->isVisible()) { QRect r = labelTrackStatistic->frameGeometry(); r.adjust(-5, -5, 5, 5); p.setPen(CDraw::penBorderGray); p.setBrush(CDraw::brushBackWhite); p.drawRoundedRect(r, RECT_RADIUS, RECT_RADIUS); } } void CCanvas::drawScale(QPainter& p) { if(!CMainWindow::self().isScaleVisible()) { return; } // step I: get the approximate distance for 200px in the bottom right corner QPointF brc(rect().bottomRight() - QPoint(50,30)); QPointF pt1 = brc; QPointF pt2 = brc - QPoint(-200,0); map->convertPx2Rad(pt1); map->convertPx2Rad(pt2); qreal d = GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt2.y()); // step II: derive the actual scale length in [m] qreal a = (int)log10(d); qreal b = log10(d) - a; if(0 <= b && b < log10(3.0f)) { d = 1 * qPow(10,a); } else if(log10(3.0f) < b && b < log10(5.0f)) { d = 3 * qPow(10,a); } else { d = 5 * qPow(10,a); } // step III: convert the scale length from [m] into [px] pt1 = brc; map->convertPx2Rad(pt1); pt2 = GPS_Math_Wpt_Projection(pt1, d, -90 * DEG_TO_RAD); map->convertRad2Px(pt1); map->convertRad2Px(pt2); p.setPen(QPen(Qt::white, 9)); p.drawLine(pt1, pt2 + QPoint(9,0)); p.setPen(QPen(Qt::black, 7)); p.drawLine(pt1, pt2 + QPoint(9,0)); p.setPen(QPen(Qt::white, 5)); p.drawLine(pt1, pt2 + QPoint(9,0)); QVector pattern; pattern << 2 << 4; QPen pen(Qt::black, 5, Qt::CustomDashLine); pen.setDashPattern(pattern); p.setPen(pen); p.drawLine(pt1, pt2 + QPoint(9,0)); QPoint pt3(pt2.x() + (pt1.x() - pt2.x())/2, pt2.y()); QString val, unit; IUnit::self().meter2distance(d,val,unit); CDraw::text(QString("%1 %2").arg(val).arg(unit), p, pt3, Qt::black); } void CCanvas::slotTriggerCompleteUpdate(CCanvas::redraw_e flags) { needsRedraw = (redraw_e)(needsRedraw | flags); update(); } void CCanvas::slotToolTip() { QString str; map->getToolTip(posToolTip, str); if(str.isEmpty()) { return; } QPoint p = mapToGlobal(posToolTip + QPoint(32,0)); QToolTip::showText(p,str); } void CCanvas::slotCheckTrackOnFocus() { const IGisItem::key_t& key = CGisItemTrk::getKeyUserFocus(); // any changes? if(key != keyTrackOnFocus) { saveSizeTrackProfile(); // get access to current track object delete plotTrackProfile; delete colorLegend; keyTrackOnFocus.clear(); labelTrackStatistic->clear(); labelTrackStatistic->hide(); // get access to next track object CGisItemTrk * trk2 = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr == trk2) { return; } // create new profile plot, the plot will register itself at the track plotTrackProfile = new CPlotProfile(trk2, trk2->limitsGraph1, CMainWindow::self().profileIsWindow() ? IPlot::eModeWindow : IPlot::eModeIcon, this); setSizeTrackProfile(); if(isVisible()) { plotTrackProfile->show(); } colorLegend = new CColorLegend(this, trk2); colorLegend->setGeometry(20, 20, 40, 300); // finally store the new key as track on focus keyTrackOnFocus = key; slotUpdateTrackStatistic(CMainWindow::self().isMinMaxTrackValues()); } } void CCanvas::slotUpdateTrackStatistic(bool show) { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(keyTrackOnFocus)); if(show && trk) { QString text = trk->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowActivity); text += trk->getInfoLimits(); labelTrackStatistic->setMinimumWidth((trk->getActivities().getActivityCount() > 1) ? 450 : 350); labelTrackStatistic->setText(text); labelTrackStatistic->adjustSize(); labelTrackStatistic->move(rect().width() - labelTrackStatistic->width() - 20, rect().height() - labelTrackStatistic->height() - 60); labelTrackStatistic->show(); update(); } else { labelTrackStatistic->clear(); labelTrackStatistic->hide(); } } void CCanvas::moveMap(const QPointF& delta) { map->convertRad2Px(posFocus); posFocus -= delta; map->convertPx2Rad(posFocus); emit sigMove(); slotTriggerCompleteUpdate(eRedrawAll); } void CCanvas::zoomTo(const QRectF& rect) { posFocus = rect.center(); map->zoom(rect); dem->zoom(map->zoom()); gis->zoom(map->zoom()); slotTriggerCompleteUpdate(eRedrawAll); } void CCanvas::setupGrid() { CGridSetup dlg(grid, map); dlg.exec(); update(); } void CCanvas::setupBackgroundColor() { QColorDialog::setCustomColor(0, "#FFFFBF"); const QColor &selected = QColorDialog::getColor(backColor, this, tr("Setup Map Background")); if(selected.isValid()) { backColor = selected; update(); } } void CCanvas::convertGridPos2Str(const QPointF& pos, QString& str, bool simple) { grid->convertPos2Str(pos, str, simple); } void CCanvas::convertRad2Px(QPointF& pos) const { map->convertRad2Px(pos); } void CCanvas::convertPx2Rad(QPointF& pos) const { map->convertPx2Rad(pos); } void CCanvas::displayInfo(const QPoint& px) { if(CMainWindow::self().isMapToolTip()) { posToolTip = px; timerToolTip->stop(); timerToolTip->start(500); } QToolTip::hideText(); } poi_t CCanvas::findPOICloseBy(const QPoint& px) const { return map->findPOICloseBy(px); } void CCanvas::setup() { CCanvasSetup dlg(this); dlg.exec(); } QString CCanvas::getProjection() { return map->getProjection(); } void CCanvas::setProjection(const QString& proj) { map->setProjection(proj); dem->setProjection(proj); gis->setProjection(proj); } void CCanvas::setScales(const scales_type_e type) { map->setScales(type); dem->setScales(type); gis->setScales(type); } CCanvas::scales_type_e CCanvas::getScalesType() { return map->getScalesType(); } qreal CCanvas::getElevationAt(const QPointF& pos) const { return dem->getElevationAt(pos); } void CCanvas::getElevationAt(const QPolygonF& pos, QPolygonF& ele) const { return dem->getElevationAt(pos, ele); } qreal CCanvas::getSlopeAt(const QPointF& pos) const { return dem->getSlopeAt(pos); } void CCanvas::getSlopeAt(const QPolygonF& pos, QPolygonF& slope) const { return dem->getSlopeAt(pos, slope); } void CCanvas::getElevationAt(SGisLine& line) const { return dem->getElevationAt(line); } void CCanvas::setZoom(bool in, redraw_e& needsRedraw) { map->zoom(in, needsRedraw); dem->zoom(map->zoom()); gis->zoom(map->zoom()); emit sigZoom(); } bool CCanvas::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline) { return map->findPolylineCloseBy(pt1, pt2, threshold, polyline); } void CCanvas::saveSizeTrackProfile() { if(plotTrackProfile.isNull()) { return; } if(plotTrackProfile->windowFlags() & Qt::Window) { SETTINGS; cfg.beginGroup("Canvas"); cfg.beginGroup("Profile"); cfg.beginGroup(objectName()); cfg.setValue("geometry", plotTrackProfile->saveGeometry()); cfg.endGroup(); // objectName() cfg.endGroup(); // Profile cfg.endGroup(); // Canvas } } void CCanvas::setSizeTrackProfile() { if(plotTrackProfile.isNull()) { return; } if(plotTrackProfile->windowFlags() & Qt::Window) { SETTINGS; cfg.beginGroup("Canvas"); cfg.beginGroup("Profile"); cfg.beginGroup(objectName()); if(cfg.contains("geometry")) { plotTrackProfile->restoreGeometry(cfg.value("geometry").toByteArray()); } else { plotTrackProfile->resize(300,200); plotTrackProfile->move(100,100); } cfg.endGroup(); // objectName() cfg.endGroup(); // Profile cfg.endGroup(); // Canvas } else { if(size().height() < 700) { plotTrackProfile->resize(200,80); } else { plotTrackProfile->resize(300,120); } plotTrackProfile->move(20, height() - plotTrackProfile->height() - 20); } } void CCanvas::showProfileAsWindow(bool yes) { if(plotTrackProfile) { const IGisItem::key_t key = CGisItemTrk::getKeyUserFocus(); delete plotTrackProfile; keyTrackOnFocus.clear(); CGisWorkspace::self().focusTrkByKey(true, key); } } void CCanvas::showProfile(bool yes) { if(nullptr != plotTrackProfile) { plotTrackProfile->setVisible(yes); } } void CCanvas::setDrawContextSize(const QSize& s) { if(map) { map->resize(s); } if(dem) { dem->resize(s); } if(gis) { gis->resize(s); } } void CCanvas::print(QPainter& p, const QRectF& area, const QPointF& focus) { const QSize oldSize = size(); const QSize newSize(area.size().toSize()); setDrawContextSize(newSize); // ----- start to draw thread based content ----- // move coordinate system to center of the screen p.translate(newSize.width() >> 1, newSize.height() >> 1); redraw_e redraw = eRedrawAll; map->draw(p, redraw, focus); dem->draw(p, redraw, focus); gis->draw(p, redraw, focus); map->wait(); dem->wait(); gis->wait(); map->draw(p, redraw, focus); dem->draw(p, redraw, focus); gis->draw(p, redraw, focus); // restore coordinate system to default p.resetTransform(); // ----- start to draw fast content ----- QRect r(QPoint(0,0), area.size().toSize()); grid->draw(p, r); gis->draw(p, r); setDrawContextSize(oldSize); } bool CCanvas::event(QEvent *event) { if (event->type() == QEvent::Gesture) { return gestureEvent(static_cast(event)); } else if (mouseLost) { QMouseEvent * me = dynamic_cast(event); if (me != nullptr) { // notify IMouse that the upcomming QMouseEvent needs special treatment // as some mouse-events may have been lost mouse->afterMouseLostEvent(me); mouseLost = false; } } return QWidget::event(event); } bool CCanvas::gestureEvent(QGestureEvent* e) { if (QPinchGesture *pinch = dynamic_cast(e->gesture(Qt::PinchGesture))) { if (pinch->changeFlags() & QPinchGesture::CenterPointChanged) { const QPointF & move = pinch->centerPoint() - pinch->lastCenterPoint(); if (!move.isNull()) { moveMap(move); } } if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged) { qreal pscale = pinch->totalScaleFactor(); if (pscale < 0.8f || pscale > 1.25f) { const QPointF & center = pinch->centerPoint(); const QPointF & pos = mapFromGlobal(QPoint(center.x(),center.y())); QPointF pt1 = pos; map->convertPx2Rad(pt1); setZoom(pscale > 1.0f, needsRedraw); map->convertRad2Px(pt1); const QPointF & move = pos - pt1; if (!move.isNull()) { moveMap(move); } pinch->setTotalScaleFactor(1.0f); slotTriggerCompleteUpdate(needsRedraw); } } mouseLost = true; mouse->pinchGestureEvent(pinch); } return true; } qmapshack-1.10.0/src/canvas/IDrawObject.h000644 001750 000144 00000010707 13216234142 021275 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDRAWOBJECT_H #define IDRAWOBJECT_H #include "units/IUnit.h" #include #include class QSettings; class QListWidget; class QPainter; class IDrawContext; class IDrawObject : public QObject { Q_OBJECT public: IDrawObject(QObject * parent); virtual ~IDrawObject(); virtual void saveConfig(QSettings& cfg); virtual void loadConfig(QSettings& cfg); /** @brief Read opacity value @return Return the opacity in a range of 0..100(full opacity) */ int getOpacity() const { return opacity; } /** @brief Read the minimum scale factor the object should be displayed @return A factor or NOFLOAT if no minimum has been set */ qreal getMinScale() const { return minScale; } /** @brief Read the maximum scale factor the object should be displayed @return A factor or NOFLOAT if no maximum has been set */ qreal getMaxScale() const { return maxScale; } /** @brief Write the minimum scale the object should be displayed at. @param s A factor or NOFLOAT if no minimum should be set */ void setMinScale(qreal s); /** @brief Write the maximum scale the object should be displayed at. @param s A factor or NOFLOAT if no maximum should be set */ void setMaxScale(qreal s); /** @brief Get QListWidgetItems to enable/disable map layers. As this property is a bit more complex the idea is to reimplement the method if the map type has layers. The implementation probably will clear the list and insert a checkable list widget item into the list. Additionally it will connect to the QListWidget's signals to be noticed by a change. Different to other properties, that will get queried when ever the property widget think it needs an update, getLayers() will only be called once upon property widget creation. The default implementation will simply clear the list. @param list */ virtual void getLayers(QListWidget& list); public slots: /** @brief Write opacity value @param value must be in the range of 0..100(full opacity) */ void slotSetOpacity(int value) { opacity = value; } signals: /** @brief Emitted every time a property of the object is changed */ void sigPropertiesChanged(); protected: /** @brief Test if the given scale is out of the min/max scale @param scale A scale factor for x and y axis @return True if x scale is out of the min/max range */ bool isOutOfScale(const QPointF& scale) const; /** @brief Setup a map cache using cachePath, cacheSizeMB and cacheExpiration The default implementation does noting. Streaming maps will probably override it to reconfigure their cache. The method is called when ever a cache property is changed. */ virtual void configureCache() { } // draw tiles with low quality re-projection but fast void drawTileLQ(const QImage& img, QPolygonF& l, QPainter& p, IDrawContext& context, projPJ pjsrc, projPJ pjtar); // draw tiles with high quality re-projection but slow void drawTileHQ(const QImage& img, QPolygonF& l, QPainter& p, IDrawContext& context, projPJ pjsrc, projPJ pjtar); private: /// the opacity level of a map qreal opacity = 100; /// the minimum scale a map is visible qreal minScale = NOFLOAT; /// the maximum scale a map is visible qreal maxScale = NOFLOAT; }; #endif //IDRAWOBJECT_H qmapshack-1.10.0/src/canvas/CCanvasSetup.cpp000644 001750 000144 00000004117 13216234137 022034 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "canvas/CCanvasSetup.h" #include "grid/CProjWizard.h" CCanvasSetup::CCanvasSetup(CCanvas * canvas) : QDialog(canvas) , canvas(canvas) { setupUi(this); lineProjection->setText(canvas->getProjection()); lineProjection->setCursorPosition(0); switch(canvas->getScalesType()) { case CCanvas::eScalesDefault: radioScalesDefault->setChecked(true); break; case CCanvas::eScalesSquare: radioScalesSquare->setChecked(true); break; } connect(toolWizard, &QToolButton::clicked, this, &CCanvasSetup::slotProjWizard); } CCanvasSetup::~CCanvasSetup() { } void CCanvasSetup::slotProjWizard() { CProjWizard dlg(*lineProjection); dlg.exec(); } void CCanvasSetup::accept() { if(!CProjWizard::validProjStr(lineProjection->text())) { return; } canvas->setProjection(lineProjection->text()); if(radioScalesDefault->isChecked()) { canvas->setScales(CCanvas::eScalesDefault); } else if(radioScalesSquare->isChecked()) { canvas->setScales(CCanvas::eScalesSquare); } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); QDialog::accept(); } qmapshack-1.10.0/src/canvas/ICanvasSetup.ui000644 001750 000144 00000006737 13155424212 021704 0ustar00oeichlerxusers000000 000000 ICanvasSetup 0 0 446 196 Setup Map View... Projection & Datum ... :/icons/32x32/GridWizzard.png:/icons/32x32/GridWizzard.png 22 22 Scales Logarithmic Square (optimized for TMS and WMTS tiles) Qt::Vertical 20 9 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ICanvasSetup accept() 248 254 157 274 buttonBox rejected() ICanvasSetup reject() 316 260 286 274 qmapshack-1.10.0/src/canvas/IDrawContext.cpp000644 001750 000144 00000031373 13216234137 022054 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/IDrawContext.h" #include #define BUFFER_BORDER 50 #define N_DEFAULT_ZOOM_LEVELS 31 const qreal IDrawContext::scalesDefault[N_DEFAULT_ZOOM_LEVELS] = { 0.10, 0.15, 0.20, 0.30, 0.50, 0.70, 1.0, 1.5, 2.0, 3.0, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 50.0, 70.0, 100.0, 150.0, 200.0, 300.0, 500.0, 700.0, 1000.0, 1500.0, 2000.0, 3000.0, 5000.0, 7000.0, 10000.0 //, 15000.0, 20000.0, 30000.0, 50000.0, 70000.0 }; #define N_SQUARE_ZOOM_LEVELS 17 const qreal IDrawContext::scalesSquare[N_SQUARE_ZOOM_LEVELS] = { 0.1492910709, 0.2985821417, 0.5971642834, 1.1943285668, 2.3886571336, 4.7773142672, 9.5546285344, 19.1092570688, 38.2185141376, 76.4370282752, 152.8740565504, 305.7481131008, 611.4962262016, 1222.9924524032, 2445.9849048064, 4891.9698096128, 9783.9396192256 }; QPointF operator*(const QPointF& p1, const QPointF& p2) { return QPointF(p1.x() * p2.x(), p1.y() * p2.y()); } QPointF operator/(const QPointF& p1, const QPointF& p2) { return QPointF(p1.x() / p2.x(), p1.y() / p2.y()); } IDrawContext::IDrawContext(const QString& name, CCanvas::redraw_e maskRedraw, CCanvas *parent) : QThread(parent) , canvas(parent) , maskRedraw(maskRedraw) { setObjectName(name); // setup map parameters and connect to canvas pjsrc = pj_init_plus("+proj=merc +a=6378137.0000 +b=6356752.3142 +towgs84=0,0,0,0,0,0,0,0 +units=m +no_defs"); pjtar = pj_init_plus("+proj=longlat +a=6378137.0000 +b=6356752.3142 +towgs84=0,0,0,0,0,0,0,0 +units=m +no_defs"); setScales(CCanvas::eScalesDefault); zoom(5); resize(canvas->size()); connect(this, &IDrawContext::finished, canvas, static_cast(&CCanvas::update)); connect(this, &IDrawContext::finished, this, &IDrawContext::sigStopThread); } IDrawContext::~IDrawContext() { pj_free(pjtar); pj_free(pjsrc); } void IDrawContext::emitSigCanvasUpdate() { emit sigCanvasUpdate(maskRedraw); } void IDrawContext::resize(const QSize& size) { if(isRunning()) { wait(); } mutex.lock(); // --------- start serialize with thread viewWidth = size.width(); viewHeight = size.height(); center = QPointF(viewWidth/2.0, viewHeight/2.0); bufWidth = viewWidth + 2 * BUFFER_BORDER; bufHeight = viewHeight + 2 * BUFFER_BORDER; buffer[0].image = QImage(bufWidth, bufHeight, QImage::Format_ARGB32); buffer[1].image = QImage(bufWidth, bufHeight, QImage::Format_ARGB32); mutex.unlock(); // --------- stop serialize with thread } QString IDrawContext::getProjection() const { if(pjsrc == nullptr) { return QString::Null(); } char *p = pj_get_def(pjsrc, 0); QString str(p); free(p); return str; } void IDrawContext::setProjection(const QString& proj) { if(pjsrc != nullptr) { pj_free(pjsrc); } pjsrc = pj_init_plus(proj.toLatin1()); } void IDrawContext::setScales(const CCanvas::scales_type_e type) { switch (type) { case CCanvas::eScalesDefault: scales = scalesDefault; zoomLevels = N_DEFAULT_ZOOM_LEVELS; scalesType = type; break; case CCanvas::eScalesSquare: scales = scalesSquare; zoomLevels = N_SQUARE_ZOOM_LEVELS; scalesType = type; break; default: qDebug() << "Invalid type of scales table" << scalesType; } } bool IDrawContext::needsRedraw() const { mutex.lock(); bool res = intNeedsRedraw; mutex.unlock(); return res; } void IDrawContext::zoom(const QRectF& rect) { if(pjsrc == nullptr) { return; } // special case for elements with no extent if(rect.width() == 0 || rect.height() == 0) { zoom(scalesType == CCanvas::eScalesDefault ? 8 : 4); return; } // zoom out from closest zoom level until a match is found for(int i = 0; i < zoomLevels; i++) { zoom(i); QPointF pt1 = rect.topLeft(); QPointF pt2 = rect.bottomRight(); convertRad2Px(pt1); convertRad2Px(pt2); QPointF pt = pt2 - pt1; if(qAbs(pt.x()) < (bufWidth - 2 * BUFFER_BORDER) && (qAbs(pt.y()) < (bufHeight - 2 * BUFFER_BORDER))) { break; } } } void IDrawContext::zoom(bool in, CCanvas::redraw_e& needsRedraw) { if(pjsrc == nullptr) { return; } zoom(zoomIndex + (in ? -1 : 1)); needsRedraw = CCanvas::eRedrawAll; } void IDrawContext::zoom(int idx) { idx = qMax(idx, 0); idx = qMin(idx, zoomLevels - 1); mutex.lock(); // --------- start serialize with thread if((zoomIndex != idx) || (zoomFactor.x() != scales[idx])) { zoomIndex = idx; zoomFactor.rx() = scales[idx]; zoomFactor.ry() = scales[idx]; intNeedsRedraw = true; emit sigScaleChanged(scale*zoomFactor); } mutex.unlock(); // --------- stop serialize with thread } void IDrawContext::convertRad2M(QPointF &p) const { if(pjsrc == nullptr) { return; } qreal y = p.y(); /* Proj4 makes a wrap around for values outside the range of -180..180°. But the draw context has no turnaround. It exceeds the values. We have to apply fixes in that case. */ bool fixWest = p.x() < (-180*DEG_TO_RAD); bool fixEast = p.x() > ( 180*DEG_TO_RAD); pj_transform(pjtar, pjsrc, 1, 0, &p.rx(), &p.ry(), 0); /* The idea of the fix is to calculate a point at the boundary with the same latitude and use it as offset. */ if(fixWest) { QPointF o(-180*DEG_TO_RAD,y); convertRad2M(o); p.rx() = 2*o.x() + p.x(); } if(fixEast) { QPointF o(180*DEG_TO_RAD,y); convertRad2M(o); p.rx() = 2*o.x() + p.x(); } } void IDrawContext::convertM2Rad(QPointF &p) const { if(pjsrc == nullptr) { return; } pj_transform(pjsrc, pjtar, 1, 0, &p.rx(), &p.ry(), 0); } void IDrawContext::convertPx2Rad(QPointF &p) const { mutex.lock(); // --------- start serialize with thread QPointF f = focus; convertRad2M(f); p = f + (p - center) * scale * zoomFactor; convertM2Rad(p); mutex.unlock(); // --------- stop serialize with thread } void IDrawContext::convertRad2Px(QPointF &p) const { mutex.lock(); // --------- start serialize with thread QPointF f = focus; convertRad2M(f); convertRad2M(p); p = (p - f) / (scale * zoomFactor) + center; mutex.unlock(); // --------- stop serialize with thread } void IDrawContext::convertRad2Px(QPolygonF& poly) const { if(pjsrc == nullptr) { return; } mutex.lock(); // --------- start serialize with thread QPointF f = focus; convertRad2M(f); const int N = poly.size(); struct p_t { qreal fixWest; qreal fixEast; }; QVector fixes(N, {NOFLOAT, NOFLOAT}); qreal * pY = &poly.data()->ry(); p_t * pFix = fixes.data(); /* Proj4 makes a wrap around for values outside the range of -180..180°. But the draw context has no turnaround. It exceeds the values. We have to apply fixes in that case. */ for(int i = 0; i < N; ++i, ++pFix, pY += 2) { if(*pY < (-180*DEG_TO_RAD)) { pFix->fixWest = *pY; } if(*pY > ( 180*DEG_TO_RAD)) { pFix->fixEast = *pY; } } pj_transform(pjtar, pjsrc, N, 2, &poly.data()->rx(), &poly.data()->ry(), 0); QPointF * pPt = poly.data(); pFix = fixes.data(); for(int i = 0; i < N; ++i, ++pFix, ++pPt) { /* The idea of the fix is to calculate a point at the boundary with the same latitude and use it as offset. */ if(pFix->fixWest != NOFLOAT) { QPointF o(-180*DEG_TO_RAD, pFix->fixWest); convertRad2M(o); pPt->rx() = 2*o.x() + pPt->x(); } if(pFix->fixEast != NOFLOAT) { QPointF o(180*DEG_TO_RAD, pFix->fixEast); convertRad2M(o); pPt->rx() = 2*o.x() + pPt->x(); } *pPt = (*pPt - f) / (scale * zoomFactor) + center; } mutex.unlock(); // --------- stop serialize with thread } void IDrawContext::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QPointF& f) { if(pjsrc == nullptr) { return; } // convert global coordinate of focus into point of map focus = f; QPointF f1 = focus; convertRad2M(f1); QPointF bufferScale = scale * zoomFactor; mutex.lock(); // --------- start serialize with thread // derive references for all corners coordinate of map buffer ref1 = f1 + QPointF(-bufWidth/2, -bufHeight/2) * bufferScale; ref2 = f1 + QPointF( bufWidth/2, -bufHeight/2) * bufferScale; ref3 = f1 + QPointF( bufWidth/2, bufHeight/2) * bufferScale; ref4 = f1 + QPointF(-bufWidth/2, bufHeight/2) * bufferScale; convertM2Rad(ref1); convertM2Rad(ref2); convertM2Rad(ref3); convertM2Rad(ref4); // adjust west <-> east boundaries if(ref1.x() > ref2.x()) { if(qAbs(ref1.x()) > qAbs(ref2.x())) { ref1.rx() = -2*(180*DEG_TO_RAD) + ref1.rx(); } if(qAbs(ref4.x()) > qAbs(ref3.x())) { ref4.rx() = -2*(180*DEG_TO_RAD) + ref4.rx(); } if(qAbs(ref1.x()) < qAbs(ref2.x())) { ref2.rx() = 2*(180*DEG_TO_RAD) + ref2.rx(); } if(qAbs(ref4.x()) < qAbs(ref3.x())) { ref3.rx() = 2*(180*DEG_TO_RAD) + ref3.rx(); } } // qDebug() << (ref1 * RAD_TO_DEG) << (ref2 * RAD_TO_DEG) << (ref3 * RAD_TO_DEG) << (ref4 * RAD_TO_DEG); // get current active buffer buffer_t& currentBuffer = buffer[bufIndex]; // convert buffers top left reference point to local coordinate system QPointF ref = currentBuffer.ref1; convertRad2M(ref); // derive offset to show coordinate of focus right in the middle of the draw // context. NOTE: the draw context's coordinate system has been moved into the // middle of the view port. QPointF off = (ref - f1) / (currentBuffer.scale * currentBuffer.zoomFactor); p.save(); // scale image if current zoomfactor does not match buffer's zoomfactor p.scale(currentBuffer.zoomFactor.x()/zoomFactor.x(), currentBuffer.zoomFactor.y()/zoomFactor.y()); // add offset p.translate(off); // draw buffer to painter p.drawImage(0,0, currentBuffer.image); p.restore(); // intNeedsRedraw is reset by the thread if(needsRedraw & maskRedraw) { intNeedsRedraw = true; } mutex.unlock(); // --------- stop serialize with thread if((needsRedraw & maskRedraw) && !isRunning()) { emit sigStartThread(); start(); } } void IDrawContext::run() { mutex.lock(); QTime t; t.start(); qDebug() << "start thread" << objectName(); IDrawContext::buffer_t& currentBuffer = buffer[!bufIndex]; while(intNeedsRedraw) { // copy all projection information need by the // map render objects to buffer structure currentBuffer.pjsrc = pjsrc; currentBuffer.zoomFactor = zoomFactor; currentBuffer.scale = scale; currentBuffer.ref1 = ref1; currentBuffer.ref2 = ref2; currentBuffer.ref3 = ref3; currentBuffer.ref4 = ref4; currentBuffer.focus = focus; intNeedsRedraw = false; mutex.unlock(); qDebug() << "bufferScale" << (currentBuffer.scale * currentBuffer.zoomFactor); // ----- reset buffer ----- currentBuffer.image.fill(Qt::transparent); drawt(currentBuffer); mutex.lock(); } // ----- switch buffer ------ bufIndex = !bufIndex; qDebug() << "stop thread" << objectName() << "after" << t.elapsed() << "ms"; mutex.unlock(); } qmapshack-1.10.0/src/locale/000755 001750 000144 00000000000 13216664443 016761 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/locale/qmapshack_ru.desktop000644 001750 000144 00000000152 13070364257 023026 0ustar00oeichlerxusers000000 000000 #Translations Name[ru]=QMapShack GenericName[ru]= Администрация GPS данных и карт qmapshack-1.10.0/src/locale/qmapshack_fr.ts000644 001750 000144 00001520245 13216473070 021773 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2, attendu V%3) %1 (API V%2) %1 (API V%2) (no DBUS: device detection and handling disabled) (DBUS absent : détection et gestion d'appareil désactivée) CActivityTrk Foot A pieds Bicycle Vélo Motor Bike Moto Car Voiture Cable Car Téléphérique Swim Natation Ship Bateau Ski/Winter Ski No Activity Pas d'activité Total Total Ascent: Montée: Descent: Descente: Aeronautics Aérien Public Transport Transports publics Distance: Distance: Speed Moving: Vitesse moyenne en déplacement: Speed Total: Vitesse moyenne totale: Time Moving: Temps en déplacement: Time Total: Temps total: CCanvas View %1 Vue %1 Setup Map Background Réglage de l'arrière-plan de la carte CColorChooser Esc. Echap CCommandProcessor Print debug output to console. Envoyer les messages de débogage vers la console Print debug output to logfile (temp. path). Envoyer les messages de débogage vers un fichier (temp. path). Do not show splash screen. Ne pas montrer l'image d'accueil File with QMapShack configuration. Fichier de configuration QMS. file fichier Files for future use. Fichiers pour usage futur. CCreateRouteFromWpt route route CDBFolderLostFound All your data grouped by folders. Vos données groupées par dossiers. Lost & Found (%1) Perdu & Trouvé (%1) Lost & Found Perdu & Trouvé CDBFolderMysql All your data grouped by folders. Vos données groupées par dossiers. MySQL Database Base de données MySQL Server: Serveur: (No PW) (aucun mot de passe) Error: Erreur: CDBFolderSqlite All your data grouped by folders. Vos données groupées par dossiers. SQLite Database Base de données SQLite File: Fichier: Error: Erreur: CDBItem %1 min. %1 min. %1 h %1 h %1 days %1 jours CDBProject Failed to load... Impossible de charger ... Can't load file "%1" . It will be skipped. Impossible de charger le fichier "%1". Il sera ignoré. Project already in database... Projet déjà présent dans le base de données The project "%1" has already been imported into the database. It will be skipped. Le projet "%1" a déjà été importé dans la base de données. Il sera ignoré. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database L'objet %1 a été modifié par %2 (%3). Pour résoudre ce conflit vous pouvez créer et sauvegarder un clone, forcer votre version ou abandonner votre version en prenant celle de la base de données Conflict with database... Confilt avec la base de données... Clone && Save Cloner && Sauvegarder Force Save Forcer la sauvegarde Take remote Prendre la version de la base de données Missing folder... Répertoire manquant... Failed to save project. The folder has been deleted in the database. Echec de la sauvegarde du projet. Le répertoire a été supprimé de la base de données. Save ... Enregistrer... Error Erreur There was an unexpected database error: %1 Erreur inattendue de la base de données: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Le projet '%1' est sur le point de se mettre à jour depuis la base de données.Néanmoins il y a des modifications non sauvegardées. Save changes? Enregistrer les modifications ? CDemList Deactivate Désactiver Activate Activer CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Ajoutez ou retirez des répertoires qui contiennent des données DEM. Il peut y avoir plusieurs fichiers dans un répertoire mais les sous-répertoires ne sont pas prises en compte. Formats acceptés sont: %1 Select DEM file path... Sélectionnez le répertoire qui contient les fichiers DEM CDemVRT Error... Erreur... Failed to load file: %1 DEM must have one band with 16bit or 32bit data. Le DEM doit contenir un seule bande avec des données en 16 ou 32 bits. No georeference information found. Aucune information de géoréférencement trouvé CDetailsGeoCache none ...indice? aucun ??? Searching for images... Recherche d'images... No images found Aucune image trouvée CDetailsPrj none aucun Build diary... Créer le journal... <h2>Waypoints</h2> <h2>Waypoints</h2> Info Information Comment Commentaire <h2>Tracks</h2> <h2>Traces</h2> From Start Depuis le début To Next Jusqu'au suivant To End Jusqu'à la fin <h2>Areas</h2> <h2>Surfaces</h2> You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Vous voulez trier des waypoints le long d'une trace, mais vous avez désactivé la corrélation des traces et waypoints. Voulez-vous la réactiver ? Correlation... Corrélation en cours... <b>Summary over all tracks in project</b><br/> Résumé de toutes les traces du projet Distance: Distance: Ascent: Montée: Descent: Descente: <h2>Routes</h2> <h2>Routes</h2> Edit name... Éditer le nom... Enter new project name. Entrez le nom du nouveau projet. Edit keywords... Éditer les mots-clés... Enter keywords. Saisir les mots-clés. Print Diary Imprimer le journal CDetailsTrk Reduce visible track points Réduire les points visibles de la trace Change elevation of track points Modifier l'altitude des points de la trace Change timestamp of track points Modifier l'horodatage des points de la trace Miscellaneous Divers Color Couleur Activity Activité CDetailsWpt Enter new proximity range. Entrez le rayon de l'alarme de proximité. CDeviceGarmin Picture%1 Image%1 Unknown Inconnu CDeviceGarminArchive Archive - expand to load Archive - développer pour charger Archive - loaded Archive - chargé CElevationDialog No DEM data found for that point. Pas de données DEM disponibles pour ce point. CExportDatabase Select export path... Selectionner le chemin d'exportation CExportDatabaseThread Create %1 Créer %1 Failed to create %1 Impossible de créer %1 Done! Fait ! Abort by user! Annulé par l'utilisateur ! Database Error: %1 Erreur de base de données : %1 Save project as %1 Sauvegarder le projet sous %1 Failed! Erreur ! CFilterDeleteExtension No extension available Aucune extension disponible CFilterInterpolateElevation coarse approximatif medium moyen fine précis CFitCrcState FIT decoding error : invalid CRC. erreur de décodage FIT : CRC invalide CFitDecoder FIT decoding error: unexpected end of file %1. erreur de décodage FIT : fin de fichier inatendue %1. CFitFieldBuilder FIT decoding error: unknown base type %1. erreur de décodage FIT : type de base %1 inconnu. CFitFieldDataState Missing field definition for development field. Définition de champ manquante pour le champ de développement FIT decoding error: invalid field def nr %1 while creating dev field profile. Erruer de décodage FIT : définition de champ invalide %1 lors de la création du profil de développement CFitHeaderState FIT decoding error: protocol %1 version not supported. erreur de décodage FIT : version du protocole %1 non supportée. FIT decoding error: file header signature mismatch. File is not FIT. erreur de décodage FIT : signature d'en-tête de fichier incompatible. Ce n'est pas un fichier FIT. CFitProject Failed to load file %1... Echec de l'ouverture du fichier %1... Failed to open FIT file %1. Echec de l'ouverture du fichier FIT %1... CFitRecordContentState FIT decoding error: architecture %1 not supported. Erreur de décodage FIT : architecture %1 non supportée FIT decoding error: invalid offset %1 for state 'record content' Erreur de décodage FIT : décalage invalide %1 pour l'état 'contenu d'enregistrement' CGarminTyp Warning... Avertissement... This is a typ file with unknown polygon encoding. Please report! Ceci est un fichier TYP avec un encodage de polygone inconnu. Veuillez signaler ce problème. This is a typ file with unknown polyline encoding. Please report! Ceci est un fichier TYP avec un encodage de polyligne inconnu. Veuillez signaler ce problème. CGisItemOvlArea thin fin normal normal wide large strong épaisse _Clone _Clone Area: %1%2 Surface: %1%2 Changed area shape. Forme de surface modifiée. Changed name. Nom modifié. Changed border width. Largeur de la bordure modifiée. Changed fill pattern. Remplissage modifié. Changed opacity. Opacité modifiée. Changed comment. Commentaire modifié. Changed description. Description modifiée. Changed links Liens modifiés. Changed color Couleur modifiée. CGisItemRte _Clone _Clone track trace Changed name. Nom modifié. Changed comment Commentaire modifié Changed description Description modifiée Changed links Liens modifiés Length: %1%2 Longueur: %1%2 Time: %1%2 Durée: %1%2 Distance: %1%2 Distance: %1%2 Length: - Longueur: - Time: - Heure : - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Date du dernier calcul d'itinéraire : <br/>%1 with %1 avec %1 Changed route points. Points de route modifiés. CGisItemTrk FIT file %1 contains no GPS data. Le fichier FIT %1 ne contient pas de donnée GPS. Error... Erreur... Failed to open %1. Impossible d'ouvrir %1 Only support lon/lat WGS 84 format. Le seul format lon/lat autorisé est WGS 84 Failed to read data. Impossible de lire les données. _Clone _Clone Changed trackpoints, sacrificed all previous data. Points de la trace modifiés, les données antérieures sont perdues. Time: %1%2, Speed: %3%4 Temps: %1%2, Vitesse: %3%4 Moving: %1%2, Speed: %3%4 En déplacement: %1%2, Vitesse: %3%4 Start: %1 Début: %1 Start: - Début: - End: %1 Fin: %1 End: - Fin: - Points: %1 (%2) Points: %1 (%2) Invalid elevations! Altitudes invalides ! Invalid timestamps! Temps invalides ! Invalid positions! Positions invalides ! Activities: %1 Activités: %1 Index: %1 Index: %1 Index: visible %1, total %2 Index: visibles %1, total %2 , Slope: %1%2 , Pente : %1%2 ... and %1 tags not displayed ... and %1 tags non affichés Distance: - (-) Distance: - (-) Moving: - (-) En déplacement: - (-) track trace Hide point %1. Cacher les points %1. Hide points %1..%2. Cacher les points %1..%2. , %1%2 ,%1,%2 Invalid points.... Points invalides ... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? La trace '%1' a %2 points invalides sur %3 points visibles. Voulez-vous cacher les points invalides maintenant ? min. min. max. max. Length: %1%2 Longueur: %1%2 , %1%2%3, %4%5%6 , %1%2%3, %4%5%6 , %1-, %2- , %1-, %2- Time: -, Speed: - Time: -, Speed: - Moving: -, Speed: - En déplacement: -, Vitesse: - Ele.: %1%2 Altitude: %1%2 , Speed: %1%2 , Vitesse: %1%2 Ascent: - (-) Montée: - (-) Descent: - (-) Descente: - (-) Ascent: %1%2 (%3%) Montée: %1%2 (%3%) , Descent: %1%2 (%3%) , Descente: %1%2 (%3%) Distance: %1%2 (%3%) Distance: %1%2 (%3%) , Moving: %1%2 (%3%) , En déplacement: %1%2 (%3%) Ascent: - Ascent: - Descent: - Descente: - Ascent: %1%2 Montée: %1%2 , Descent: %1%2 , Descente: %1%2 Distance: %1%2 Distance: %1%2 , Time: %1%2 , Durée: %1%2 Permanently removed points %1..%2 Points supprimés de manière permanente %1..%2 Show points. Afficher les points. Changed name Nom modifié Changed comment Commentaire modifié Changed description Description modifiée Changed links Liens modifiés Changed elevation of point %1 to %2 %3 Altitudes modifiées du point %1 à %2 %3 Changed activity to '%1' for complete track. Activité modifiée pour '%1' pour la trace complète. Changed activity to '%1' for range(%2..%3). Activité modifiée pur '%1' for la plage (%2..%3). Hide points by Douglas Peuker algorithm (%1%2) Cacher des points avec l'algorithme Douglas Peuker (%1%2) Hide points with invalid data. Cacher les points aux données invalides Reset all hidden track points to visible Restaurer les points cachés Permanently removed all hidden track points Supprimer définitivement tous les points cachés Smoothed profile with a Median filter of size %1 Profile lissé avec un filtre médian de dimension %1 Added terrain slope from DEM file. Ajouté la pente du terrain à partir du fichier MNT Replaced elevation data with data from DEM files. Les altitudes ont été remplacées par les données des fichiers MNT Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Les altitudes ont été remplacées par des valeurs interpolées. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Décaler les altitudes de %1%2. Changed start of track to %1. Début de la trace modifié à %1. Remove timestamps. Horodatage supprimé. Set artificial timestamps with delta of %1 sec. Horodatage artificiel ajouté avec un décalage de %1 sec. Changed speed to %1%2. Vitesse modifiée à %1%2. %1 (Segment %2) %1 (Segment %2) Removed extension %1 from all Track Points Extension %1 supprimée de tous les points Converted subpoints from routing to track points Converti les sous-points de routage en points de trace Copy flag information from QLandkarte GT track Copier la balise d'information de la trace QLandkarte GT CGisItemWpt Archived Archivé Available Disponible Not Available Non disponible _Clone _Clone Elevation: %1%2 Altitude: %1%2 Proximity: %1%2 Proximité: %1%2 Changed name Nom modifié Changed position Position modifiée Changed elevation Altitude modifiée Removed proximity Enlevé proximité Changed proximity Rayon de proximité modifié Changed icon Icône modifié Changed comment Commentaire modifié Changed description Description modifiée Changed links Liens modifiés Changed images Images modifiées Add image Ajouter une image Changed to proximity-radius Changé pour rayon de proximité Changed to nogo-area Changé pour zone interdite CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. A cause d'évolutions de la gestion des bases de données, QMapShack doit de nouveau connaître l'emplacement de votre base de données. '%1'. Indiquez-le à l'étape suivante. Select database file. Sélectionnez un fichier de base de données Add Database Ajouter une base de données Add Folder Ajouter un dossier Rename Folder Renommer dossier Copy Folder Copier dossier Move Folder Déplacer dossier Delete Folder Supprimer le dossier Import from Files... Importer depuis des fichiers ... Export to GPX... Exporter vers GPX... Delete Item Supprimer un élément Search Database Rechercher dans la base de données Sync. with Database Synchroniser avec la base de données Remove Database Enlever la base de données Empty Vider Remove database... Enlever la base de données Do you really want to remove '%1' from the list? Voulez-vous vraiment supprimere '%1' de la liste ? Are you sure you want to delete selected folders and all subfolders from the database? Etes-vous sûr de vouloir supprimer les dossiers selectionnés ainsi que leur sous-dossiers de la base de données ? Bad operation.... Mauvaise opération... The target folder is a subfolder of the one to move. This will not work. Le dossier cible est un sous-dossier de celui à déplacer. Cela ne fonctionnera pas. Folder name... Name du dossier... Rename folder: Renommer le dossier: Are you sure you want to delete '%1' from folder '%2'? Êtes-vous sûr de vouloir supprimer %1 du dossier %2? Delete... Supprimer... Import GIS Data... Importer des données SIG... Delete database folder... Supprimer la base de données... Remove items... Supprimer les éléments... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Êtes-vous sûr de vouloir supprimer tous les éléments dans Perdu & Trouvé ? Les éléments seront supprimés définitivement. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Êtes-vous sûr de vouloir supprimer les éléments sélectionnés dans Perdu & Trouvé ? Les éléments seront supprimés définitivement. CGisListWks Edit.. Éditer.. Show on Map Afficher sur la carte Hide from Map Masquer Sort by Time Trier par date Sort by Name Trier par nom Save Enregistrer Save as GPX 1.1 w/o ext... Sauvegarder comme GPX 1.1 sans extensions... Send to Devices Envoyer vers les appareils Sync. with Database Synchroniser avec la base de données Close Fermer Update Project on Device Mettre à jour le projet sur l'appareil Delete Supprimer Edit... Éditer... Copy to... Copier vers... Autom. Save Sauvg. auto Save as... Sauvegarder sous... Track Profile Profile de la trace Select Range Sélectionner des points Edit Track Points Éditer les points de la trace Reverse Track Inverser la trace Combine Tracks Joindre des traces Copy Track with Waypoints Copier la trace avec ses waypoints Show Bubble Afficher la bulle Move Waypoint Déplacer le waypoint Proj. Waypoint... Projection du waypoint... Change Radius Changer le rayon Toggle Nogo-Area Activer zone interdite Delete Radius Supprimer le rayon Route Instructions Instructions de guidage Calculate Route Calculer l'itinéraire Reset Route Réinitialiser la route Edit Route Éditer la route Convert to Track Convertir en trace Edit Area Points Éditer les points de la surface Create Route Créer une route Change Icon (sel. waypt. only) Change l'icône (waypoint séléctionné seulement) Set Track Activity Choisir l'activité de la trace Drop items... Saving workspace. Please wait. Sauvegarde de l'espace de travail. Patientez. Loading workspace. Please wait. Chargement de l'espace de travail. Patientez. Close all projects... Fermer tous les projets... This will remove all projects from the workspace. Ceci enlevera tous les projets de l'espace de travail. Delete project... Supprimer le projet... Do you really want to delete %1? Êtes-vous sûr de vouloir supprimer %1? <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Mise à jour des appareils</b><p>Mise à jour de %1<br/>Patientez...</p> CGisWorkspace Load project... Charger le projet... The project "%1" is already in the workspace. Le projet "%1" est déjà présent dans l'espace de travail. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Sélection d'objets : </b>Objet sélectionné depuis l'espace de travail. Cliquez sur la carte pour revenir au mode normal de sélection à la souris. Copy items... Copier les éléments... Change waypoint symbols. Changer les symboles de waypoint. Cut Track... Couper la trace... Do you want to delete the original track? Voulez-vous supprimer la trace originale? CGpxProject Failed to load file %1... Impossible de charger le fichier %1... Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Impossible de lire: %1 ligne %2, colonne %3: %4 Not a GPX file: %1 Ce n'est pas un fichier GPX: %1 File exists ... Le fichier existe... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Le fichier existe et n'a pas été créé par QMapShack. Si vous cliquez sur 'oui' tous les données de ce fichier seront perdues. Même si ce fichier contient des données GPX et sera ouvert par QMapShack certains éléments de ce fichier ne pourront pas être lus ou enregistrés. Ces élements seront perdus. Il est conseillé d'utiliser un autre fichier.<b>Voulez-vous vraiment écraser ce fichier ?</b> Failed to create file '%1' Impossible de créer le fichier: '%1' Failed to write file '%1' Impossible d'écrire le fichier: '%1' Saving GIS data failed... Impossible de sauvegarder les données SIG CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1m, %2m N %1m, E %2m N %1m, E %2m CHistoryListWidget by %1 par %1 Cut history before Tronquer l'historique antérieur Cut history after Tronquer l'historique postérieur History removal Supression de l'historique The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> La suppression est permanente et ne peut être annulée. <b>Voulez-vous vraiment supprimer l'historique antérieur à cette étape ?</b> CImportDatabase Import QLandkarte Database Importer une base de données QLandkarte Select source database... Choisissez la base de données à importer... Select target database... Choisissez la base de données cible... CKnownExtension Speed extLongName Vitesse Cadence extShortName Cadence Air Temp. extShortName Temp. Air Air Temperature extLongName Température de l'air Water Temp. extShortName Temp. eau Water Temperature extLongName Température de l'eau Depth extShortName Prof. Depth extLongName Profondeur Heart R. extShortName Fréq. Card. Heart Rate extLongName Fréquence cardiaque Cadence extLongName Cad. Speed extShortName Vit. Accel. extShortName Accel. Acceleration extLongName Accélération Course extShortName Cap Course extLongName Cap Temp. extShortName Temp. Temperature extLongName Température Dist. extShortName Dist. Distance extLongName Distance Ele. extShortName Alt. Elevation extLongName Altitude Energy extShortName Energ Energy extLongName Energie Sea Lev. Pres. extShortName Pres. Niv. Mer Sea Level Pressure extLongName Pression au niveau de la mer v. Speed extShortName Vit. vert. Vertical Speed extLongName Vitesse verticale Slope extShortName Pente Speed over Distance* extLongName Vitesse par rapport à la distance* Speed over Time* extLongName Vitesse par rapport au temps* Elevation* extLongName Altitude* Progress extShortName Progress. Progress* extLongName Progression* Terr. Slope extShortName Pent. Terr. Terrain Slope* extLongName Pente du terrain* Slope* Pente* CLogProject Failed to load file %1... Impossible de charger le fichier %1... Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Erreur de lecture: %1 ligne %2, colonne %3: %4 Not an Openambit log file: %1 Ce n'est pas un fichier Openambit : %1 Device: %1<br/> Appareil: %1<br/> Recovery time: %1 h<br/> Temps de récupération : %1 h<br/> Peak Training Effect: %1<br/> Pic d'effet d'entraînement : %1<br/> Energy: %1 kCal<br/> Energie: %1 kCal<br/> Use of local time... Utilisation de l'heure locale... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. Aucune heure UTC trouvée dans le fichier %1. L'heure locale de l'ordinateur sera utilisée. Vous pouvez utiliser un filtre pour ajuster l'heure si nécessaire. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 Ce fichier LOG ne contient aucune information de position et ne peut être affiché par QMapShack : %1 CLostFoundProject Lost & Found Perdu & Trouvé CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Utilisez <b>Menu->Vue->Add Map View</b> pour ouvrir une nouvelle vue. Ou <b>Menu->Fichier->Charger une vue cartographique</b> pour charger une vue sauvegardée. Ou cliquez <a href='newview'>ici</a>. Ele.: %1%2 Altitude: %1%2 Slope: %1%2 terrain Pente du terrain : %1%2 [Grid: %1] [Grille: %1] Load GIS Data... Charger des données SIG... Select output file Sélectionner le fichier de sortie QMapShack View (*.view) Vue QMapShack (*.view) Select file to load Sélectionner le fichier à charger Fatal... Fatal... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack a détecter une bibliothèque Proj4 mal installée. Les tables de translation pour les projections ESPG lstockées en généra dans /usr/share/proj sont manquantes. Contactez votre gestionnaire de distribution pour réparer cela. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. CMapIMG Failed ... Échec... Unspecified Non défini French Français German Deutsch Dutch Néerlandais English Anglais Italian Italien Finnish Finlandais Swedish Suédois Spanish Espagnol Basque Catalan Catalan Galician Galicien Welsh Gallois Gaelic Gaëlic Danish Danois Norwegian Norvégien Portuguese Portugais Slovak Slovaque Czech Tchèque Croatian Croate Hungarian Hongrois Polish Polonais Turkish Turque Greek Grèc Slovenian Slovène Russian Russe Estonian Estonien Latvian Letton Romanian Roumain Albanian Albanais Bosnian Bosnien Lithuanian Lituanien Serbian Serbe Macedonian Macédonien Bulgarian Bulgare Major highway Route majeure Principal highway Route principale Other highway Autre route Arterial road Artère urbaine Collector road Rue principale Residential street Rue résidentielle Alley/Private road Ruelle/Route privée Highway ramp, low speed Bretelle d'accès, basse vitesse Highway ramp, high speed Bretelle d'accès, grande vitesse Unpaved road Route non bitumé Major highway connector Bretelle majeure Roundabout Rond-point Railroad Voie ferrée Shoreline Ligne côtière Trail Sentier Stream Ruisseau Time zone Fuseau horaire Ferry Bac State/province border Frontière de province County/parish border Frontière de canton International border Frontière internationale River Rivière Minor land contour Courbe de niveau mineure Intermediate land contour Courbe de niveau intermédiaire Major land contour Courbe de niveau majeure Minor depth contour Courbe isobathe mineure Intermediate depth contour Courbe isobathe intermédiaire Major depth contour Courbe isobathe majeure Intermittent stream Ruisseau intermittent Airport runway Tarmac Pipeline Oléoduc Powerline Ligne à haute tension Marine boundary Frontière maritime Hazard boundary Limite de zone à risque Large urban area (&gt;200K) Grande agglomération urbaine (&gt;200K) Small urban area (&lt;200K) Petite agglomération urbaine (&lt;200K) Rural housing area Zone résidentielle rurale Military base Base militaire Parking lot Parking Parking garage Parking couvert Airport Aéroport Shopping center Centre commercial Marina Marina University/College Université Hospital Hôpital Industrial complex Complexe industriel Reservation Reserve naturelle Man-made area Zone industrielle Sports complex Complexe sportif Golf course Golf Cemetery Cimetière National park Parc national City park Parc urbain State park Parc régional Forest Forêt Ocean Océan Blue (unknown) Sea Mer Large lake Grand lac Medium lake Lac moyen Small lake Petit lac Major lake Lac majeur Major River Rivière majeure Large River Grande rivière Medium River Rivière moyenne Small River Petite rivière Intermittent water Cours d'eau intermittent Wetland/Swamp Marais Glacier Glacier Orchard/Plantation Verger Scrub Broussaille Tundra Tundra Flat Plaine ??? Read external type file... Lire un fichier TYP externe... Failed to read type file: %1 Fall back to internal types. Erreur de lecture du fichier TYP : %1 Utilisation du TYP interne. Failed to read: Erreur de lecture : Failed to open: Échec d'ouverture : Bad file format: Format de fichier invalide : Failed to read file structure: Erreur de lecture de la structure du fichier : Loading %1 Chargement de %1 User abort: Interruption par l'utilisateur : File is NT format. QMapShack is unable to read map files with NT format: Le fichier est au format NT. QMapShack ne peut pas lire des fichiers au format NT : File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Le fichier contient des données verrouillées / cryptées. Garmin ne vous autorise pas à utiliser ce fichier avec un logiciel non fourni par Garmin. Point of Interest Point d'intérêt Unknown Inconnu Area Surface CMapList Deactivate Désactiver Activate Activer Where do you want to store maps? Où voulez vous enregistrer les cartes ? CMapMAP Failed ... Échec... Failed to open: Échec d'ouverture : Bad file format: Format de fichier invalide : CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Ajoutez ou retirez des répertoires qui contiennent des cartes. Il peut y avoir plusieurs cartes dans un répertoire mais les sous-répertoires ne sont pas prises en compte. Les formats acceptés sont : %1 Select map path... Choisissez un répertoire... Select root path... Sélectionner le répertoire racine... CMapPropSetup Select type file... Sélctionnez un type de fichier... CMapRMAP Error... Erreur... This is not a TwoNav RMAP file. Ceci n'est pas un fichier TwoNav RMAP. Unknown sub-format. Sous-format inconnu. Unknown version. Version inconnue. Failed to read reference point. Impossible de lire les points de référence. Unknown projection and datum (%1%2). Projection et date inconnus (%1%2). CMapTMS Error... Erreur... Failed to open %1 Impossible d'ouvrir: %1 Failed to read: %1 line %2, column %3: %4 Impossible de lire: %1 ligne %2, colonne %3: %4 Layer %1 Calque %1 CMapVRT Error... Erreur... Failed to load file: %1 Impossible de charger le fichier: %1 File must be 8 bit palette or gray indexed. Le fichier doit avoir une palette à 8 bits ou être en niveaux de gris. No georeference information found. Aucune information de géoréférencement trouvé CMapVrtBuilder Build GDAL VRT Générer le VRT GDAL Select files... Sélectionnez les fichiers... Select target file... Sélectionnez le fichier à créer... !!! done !!! !!! fait !!! CMapWMTS Error... Erreur... Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Impossible de lire: %1 ligne %2, colonne %3: %4 Failed to read: %1 Unknown structure. Impossible de lire: %1 Structure inconnue. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Service inattendu. '* WMTS 1.0.0' est attendu mais '%1 %2' est lu. No georeference information found. Aucune information de géoréférencement trouvé CMouseEditArea Area Surface <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Éditer la surface</b><br/>Choisissez und fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seulement les points marqués d'un carré large peuvet être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/> area surface CMouseEditRte Route Calcul d'itinéraire <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Éditer les points de la route</b><br/>Choisissez une fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seul les points marqués d'un carré large peuvent être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/> route route CMouseEditTrk Track Trace <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Éditer les points de la trace</b><br/>Choisissez une fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seul les points marqués d'un carré large peuvent être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/> Warning! Avertissement ! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. La trace obtenue ne contiendra que des données de position. Toutes les autres données (altitude, temps, etc...) seront perdues. track trace CMouseNormal Add POI as Waypoint Ajouter PI comme waypoint Add Waypoint Ajouter un waypoint Add Track Ajouter une trace Add Route Ajouter une route Add Area Ajouter une surface Select Items On Map Selectionner des objets sur la carte Copy position Copier la position Copy position (Grid) Copier la position (grille) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Sauvegarder (Imprimer) la carte</b></br>Sélectionnez une zone rectangulaire sur la carte. Utilisez le clic gauche et déplacez la souris. Pour annuler utilisez le clic droit. Ajustez la sélection en déplaçant les coins en gardant enfoncé le bouton gauche de la souris. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Sélectionner une plage</b><br/>Sélectionner le 1er pointpar un clic gauche. Puis un second point. Clic droit pour quitter le mode "sélection de plage".<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Sélectionner des objets sur la carte</b><br/>Sélectionnez une surface rectangulaire sur la carte. Utilisez le bouton gauche de la souris et déplacez la souris. Clic droit pour annuler. Ajustez la sélection en déplaçant les coins. <b>Selected:</b><br/> <b>Sélectionné::</b><br/> %1 waypoints<br/> %1 points<br/> %1 tracks<br/> %1 traces<br/> %1 routes<br/> %1 routes<br/> %1 areas<br/> %1 surfaces<br/> CPhotoAlbum Select images... Sélectionner les images... CPlot Distance [%1] Distance [%1] Time Durée CPlotProfile Distance [%1] Distance [%1] Ele. [%1] Alt. [%1] CPrintDialog Print Map... Imprimer la carte... Save Map as Image... Sauvegarder la carte comme image... Printer Properties... Propriétés de l'imprimante... Pages: %1 x %2 Pages: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Zoomer la carte ci-dessous avec la roulette de la souris pour changer la résolution : %1x%2 pixel x: %3 m/px y: %4 m/px Printing pages. Impression des pages. Save map... Sauvegarder la carte... CProgressDialog Elapsed time: %1 Temps écoulé : %1 Elapsed time: %1 seconds. Temps écoulé : %1 secondes CProjWizard north nord south sud Error... Erreur... The value '%1' is not a valid coordinate system definition: %2 La valeur '%1' n'est pas une définition de système de coordonnées: %2 CProjWpt Edit name... Éditer le nom... Enter new waypoint name. Entrez le nom du nouveau waypoint. CQlbProject Failed to open... Impossible d'ouvrir... Failed to open %1 Impossible d'ouvrir %1 Could not convert... Impossible de convertir... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. Le fichier contient des superpositions qui ne peuvent être converties. QMapShack ne supporte pas tous les types de superpostion de QLandKarte. CQlgtDb Migrating database from version 4 to 5. Migration de la base de données de version 4 en version 5. Migrating database from version 5 to 6. Migration de la base de données de version 5 en version 6. Migrating database from version 6 to 7. Migration de la base de données de version 6 en version 7. Migrating database from version 7 to 8. Migration de la base de données de version 7 en version 8. Migrating database from version 8 to 9. Migration de la base de données de version 8 en version 9. Open database: %1 Ouvrir la base de données: %1 Folders: %1 Répertoires: %1 Tracks: %1 Traces: %1 Routes: %1 (Only the basic route will be copied) Routes: %1 (seulement la route de base sera copiée) Waypoints: %1 Waypoints: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Overlays : %1 (les surfaces seront convertis en surfaces, les lignes de distance en traces, tous les autres overlays seront perdus) Diaries: %1 Journaux: %1 Map selections: %1 (can't be converted to QMapShack) Sélections de carte: %1 (ne peuvent pas être convertis) ------ Start to convert database to %1------ ------ La conversion de base de donnée vers %1 commence ------ Failed to create target database. Erreur lors de la création de la base de données cible. ------ Abort ------ ------ Annuler ------ ------ Done ------ ------ Terminé ------ Restore folders... Restaurer ls dossiers... Imported %1 folders and %2 diaries %1 dossiers et %2 journaux ont été importés Copy items... Copier les éléments... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas %1 traces, %2 waypoints, %3 routes et %4 surfaces ont été importés Import folders... Importer les dossiers... Overlay of type '%1' cant be converted Overlay de type '%1' ne peut pas être converti CQlgtTrack Corrupt track ... Trace corrompue... Number of trackpoints is not equal the number of training data trackpoints. Le nombre de points de trace ne correspond pas au nombre de points de trace de training. Number of trackpoints is not equal the number of extended data trackpoints. Le nombre de points de trace ne correspond pas au nombre de points de trace étendus. Number of trackpoints is not equal the number of shadow data trackpoints. Le nombre de points de trace ne correspond pas au nombre des points cachés CQmsDb Existing file... Le fichier existe... Remove existing %1? Supprimer %1 qui existe ? Remove existing file %1 Supprimer le fichier existant %1 ? %1: drop item with QLGT DB ID %2 %1: poubellise l'élément avec l'identifiant QLGT DB %2 CQmsProject Failed to open... Impossible d'ouvrir... Failed to open %1 Impossible d'ouvrir %1 CRouterBRouter original first alternative second alternative third alternative BRouter (offline) BRouter (online) profile: %1, alternative: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade response is empty Bad response from server: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... Calculate route with %1 Calculer l'itinéraire avec %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <br/>Calculation time: %1s Error Erreur running starting QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. Warning... Avertissement... I understand the risk. Don't tell me again. stopped not installed online CRouterBRouterSetup %1 not accessible %1 invalid result Error parsing online-config: Network error: CRouterBRouterSetupWizard Restore Default Values Open Directory select Java Executable please select BRouter installation directory selected directory does not exist create directory and install BRouter there existing BRouter installation update existing BRouter installation empty directory, create new BRouter installation here create new BRouter installation seems to be a valid Java-executable doesn't seem to be a valid Java-executable Java Executable not found Error loading installation-page at %1 no brouter-version to install selected selected %1 for download and installation Warning... Avertissement... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. I understand the risk and wish to proceed. download %1 started Network Error: %1 download %1 finished unzipping: ready. download of brouter failed: %1 retrieving available profiles from %1 content of profile Error: Error creating directory %1 Error directory %1 does not exist Error creating file %1 Error writing to file %1 CRouterBRouterTilesPage Continue with Setup CRouterBRouterTilesSelect available routing-data is being determined. Select outdated Clear Selection Delete selection Download Error creating segments directory %1 cannot parse: %1 is not a date cannot parse: %1 is not a valid size Error retrieving available routing data from %1: %2 segments directory does not exist: error creating file %1: %2 no valid request for filename %1 no open file assigned to request for %1 error writing to file %1: %2 error renaming file %1 to %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) being downloaded: %1 of %2 no local data, online available: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Error removing %1: %2 Network Error invalid result, no files found local data up to date (%1, %2) no routing-data available CRouterBRouterToolShell !!! done !!! !!! fait !!!! !!! failed !!! !!! échec !!! CRouterMapQuest Fastest Le plus rapide Shortest le plus court Bicycle Vélo Pedestrian Piéton US English Anglais Etats Unis British English Anglais britannique Danish Danois Dutch Néerlandais French Français German Allemand Italian Italien Norwegian Norvégien Spanish Espagnol Swedish Suédois mode "%1" mode "%1" no highways Pas d'autoroutes no toll roads Pas de routes à péage no seasonal pas de routes saisonnières no unpaved Pas de route non revêtue no ferry Pas de ferry no crossing of country borders Pas de franchissement de frontière <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Requête de routage envoyée au serveur. Veuillez patienter... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Mauvaise réponse du serveur:<br/>%1 <br/>Calculation time: %1s <br/>Temps de calcul: %1s CRouterRoutino Foot à pied Horse à cheval Wheelchair en fauteuil roulant Bicycle Vélo Moped Cyclomoteur Motorcycle Moto Motorcar Voiture Goods Camion Shortest le plus court Found Routino with a wrong version. Expected %1 found %2 Mauvaise version de Routino trouvée. Attendu %1 trouvé %2 Quickest le plus rapide English Anglais German Allemand French Français Hungarian Hongrois Dutch Néerlandais Russian Russe Polish Polonais A function was called without the database variable set. Une fonction a été appelée sans variable de base de donnée assignée A function was called without the profile variable set. Une fonction a été appelée sans variable de profil assignée A function was called without the translation variable set. Une fonction a été appelée sans variable de traduction assignée The specified database to load did not exist. La base de donnée à charger n'existe pas The specified database could not be loaded. La base de donnée n'a pas pu être chargée The specified profiles XML file did not exist. Les profils XML choisis n'existent pas The specified profiles XML file could not be loaded. Les profils XML choisis n'ont pas pu être chargés The specified translations XML file did not exist. Le fichier de traduction XML n'existe pas The specified translations XML file could not be loaded. Le fichier de traduction XML n'a pas pu être chargé The requested profile name does not exist in the loaded XML file. Le nom de profil demandé n'existe pas dans le fichier XML chargé The requested translation language does not exist in the loaded XML file. La langue de traduction demandée n'existe pas dans le fichier XML chargé The profile and database do not work together. Le profile et la base de données ne fonctionnent pas ensemble The profile being used has not been validated. Le profil en cours d'utilisation n'a pas été validé The user specified profile contained invalid data. Le profil utilisé contient des données invalides The routing options specified are not consistent with each other. Les options de routage choisies ne sont pas compatibles entre elles There is a mismatch between the library and caller API version. La bibliothèque et l'API ne vont pas ensemble Route calculation was aborted by user. Le calcul de l'itinéraire a été annulé par l'utilisateur A route could not be found to waypoint %1. Aucune route vers le waypoint %1 n'a été trouvée Unknown error: %1 Erreur inconnue : %1 profile "%1" profile "%1" , mode "%1" , mode "%1" Warning... Avertissement... In the routing database there is no highway near the coordinates to place a waypoint. La base de donnée de routage ne contient aucune voie à cet endroit Calculate route with %1 Calculer l'itinéraire avec %1 <br/>Calculation time: %1s <br/>Temps de calcul : %1s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Ajouter ou enlever des répertoires contenant des données Routino. Il peut y avoir plusieurs bases de données dans un répertoire mais les sous-répertoires ne sont pas pris en compte. Select routing data file path... Sélectionner un répertoire de données de calcul d'itinéraire... CRouterSetup Routino (offline) Routino (hors ligne) MapQuest (online) MapQuest (en ligne) BRouter (online) Brouter (en ligne) CRoutinoDatabaseBuilder Create Routino Database Créer une base de données Routino Select files... Sélectionnez les fichiers... Select target path... Sélectionnez le répertoire cible... !!! done !!! !!! fait !!! CScrOptRangeTrk No range selected Aucune plage selectionnée CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Mode exact</b><br/>Tous les objets selectionnés doivent être totalement inclus dans la zone sélectionnée.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Mode intersection</b><br/>Tous les objets selectionnés doivent avoir au moins une partie incluse dans la zone sélectionnée.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Ajouter des traces</b><br/>Ajouter des traces à la liste d'objets selectionnés<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Ajouter des waypoints</b><br/>Ajouter des waypoints à la liste d'objets selectionnés<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Ajouter des routes</b><br/>Ajouter des routes à la liste d'objets selectionnés<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Ajouter des surfaces</b><br/>Ajouter des surfaces à la liste d'objets selectionnés<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Ignorer les traces</b><br/>Ignore les traces dans la liste d'objets selectionnés<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Ignorer les waypoints</b><br/>Ignore les waypoints dans la liste d'objets selectionnés<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Ignorer les routes</b><br/>Ignore les routes dans la liste d'objets selectionnés<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> <b>Ignorer les surfaces</b><br/>Ignore les surfaces dans la liste d'objets selectionnés<br/> CSearchDatabase Search database '%1': Rechercher dans la base de données '%1:' CSearchGoogle Unknown response Réponse inconnue Error: Erreur: CSetupDatabase Missing Requirement Elément obligatoire manquant MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. MySQL ne peut pas être utilisé, car le pilote correspondant (QMYSQL) n'est pas disponible. <br/>Assurez vous d'avoir installé le paquet correspondant. <br />Si vous ne savez pas quoi faire maintenant jetez <a href="%1">un coup d'oeil au wiki</a>. Error... Erreur... There is already a database with name '%1' Une database de ce nom existe déjà : %1 New database... Nouvelle base de données... Open database... Ouvrir la base de données... CSetupWorkspace Setup database... Mise en place la base de données... Changes will become active after an application's restart. Les modifications prennent effet après un redémarrage de l'application. CSlfProject Failed to load file %1... Echec du chargement du fichier %1... CSlfReader Failed to parse timestamp `%1` Echec lors du parcours du timestamp '%1' %1 does not exist %1 n'existe pas Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Impossible de lire: %1 ligne %2, colonne %3: %4 Not a SLF file: %1 Ce n'est pas un fichier SLF: %1 Unsupported revision %1: %2 Révision non supportée %1: %2 Break %1 Break %1 Lap %1 Tour %1 CSmlProject Failed to load file %1... Impossible de charger le fichier %1... Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Erreur de lecture : %1 ligne %2, colonne %3: %4 Not an sml file: %1 Ce n'est pas un fichier sml : %1 Recovery time: %1 h<br/> Temps de récupération : %1 h<br/> Peak Training Effect: %1<br/> Pic d'effet d'entraînemet : %1<br/> Energy: %1 kCal<br/> Energie : %1 kCal<br/> Device: %1<br/> Appareil : %1<br/> Battery usage: %1 %/hour Utilisation de la batterie : %1 %/heure Use of local time... Utilisation de l'heure locale... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. Aucune heure UTC trouvée dans le fichier %1. L'heure locale de l'ordinateur sera utilisée. Vous pouvez utiliser un filtre pour ajuster l'heure si nécessaire. This SML file does not contain any position data and can not be displayed by QMapShack: %1 Ce fichier SML ne contient aucune donnée de position et ne peut pas être affiché par QMapShack : %1 CTableTrk Double click to edit elevation value Double-clic pour éditer l'altitude %1%2 %1%2 CTcxProject Failed to load file %1... Impossible de charger le fichier %1... Failed to open %1 Impossible d'ouvrir %1 Failed to read: %1 line %2, column %3: %4 Erreur de lecture: %1 ligne %2, colonne %3: %4 Not a TCX file: %1 Ceci n'est pas un fichier TCX : %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Ce fichier TCX contient au moins 1 entraînement, mais aucune activité ni course. Comme les entraînements ne contiennent pas de données de position, ils ne peuvent pas être importés dans QMapShack. This TCX file does not contain any activity or course: %1 Ce fichier TCX ne contient ni activité ni course : %1 File exists ... Le fichier existe... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Le fichier existe et n'a pas été créé par QMapShack. Si vous cliquez sur 'oui' tous les données de ce fichier seront perdues. Même si ce fichier contient des données TCX et sera ouvert par QMapShack certains éléments de ce fichier ne pourront pas être lus ou enregistrés. Ces élements seront perdus. Il est conseillé d'utiliser un autre fichier.<b>Voulez-vous vraiment écraser ce fichier ?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> La trace <b>%1</b> que vous avez selectionnée contient des points à l'horodatage invalide. L'appareil risque de ne pas accepter le fichier TCX généré si la trace est laissée telle quelle. <b>Voulez-vous appliquer un filtre vitesse arbitraire (10 m/s) et continuer ?</b> Course Course Activity Activité Cancel Annuler Track with invalid timestamps... Trace à l'horodatage invalide... Activity or course? Activité ou course ? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack ne sait pas comment la trace <b>%1</b> doit être sauvegardée. <b>Voulez-vous la sauvegarder comme une activité ou comme une course ?</b> Seuls les waypoints proches de la trace seront inclus si "course" est choisi. Si "activité" est choisi aucun waypoint ne sera inclus. Failed to create file '%1' Impossible de créer le fichier: '%1' Failed to write file '%1' Impossible d'écrire le fichier: '%1' Saving GIS data failed... Impossible de sauvegarder les données SIG CTemplateWidget choose one... choisir ... Hiking Tour Summary (built-in) Compte-rendu de randonnée (intégré) - - Template path... Chemin du template Failed to read template file %1. Impossible de lire le template %1. Preview... Aperçu... CTextEditWidget &Color... &Couleur... Reset format Retour au format par défaut CToolBarSetupDialog Available Actions Actions Disponibles Selected Actions Actions Sélectionnées CTwoNavProject Error... Erreur... Failed to open %1. Impossible d'ouvrir %1. Save GIS data to... Enregistrer les données SIG dans... Only support lon/lat WGS 84 format. Le seul format lon/lat autorisé est WGS 84 Failed to read data. Impossible de lire les données. CWptIconDialog Path to user icons... Répertoire des icônes personnalisées... Form Form Formulaire Participants Participants Weather Climat rain pluie sunny ensoleillé snow neige clouds nuages windy venteux hot chaud warm tiède cold froid freezing gel foggy brouillard humid humide Character Caractéristiques easy hiking randonnée facile climbing montée alpine alpin large ascend longue descente long distance longue distance via ferrata via ferrata hail/soft hail Grêle / grêle molle Rating Notation Rating 5 stars Notation 5 étoiles Rating 4 stars Notation 4 étoiles Rating 3 stars Notation 3 étoiles Rating 2 stars Notation 2 étoiles Rating 1 star Notation 1 étoile aborted abandonné Equipment Equipement ferrata gear Equipement de via ferrata night gear Equipement de nuit snow shoes Bottes de neige climbing gear Equipement d'escalade ski ski camping gear Equipement de camping Details Détails IAbout About.... À propos... <b>QMapShack</b>, Version TextLabel Libellé Qt GDAL Proj4 Routino Routino Czech: Tchèque: German: Allemand: Oliver Eichler Oliver Eichler Dutch: Néerlandais: French: Français: Rainer Unseld Russian: Russe: Wolfgang Thämelt Wolfgang Thämelt © 2017 Oliver Eichler (oliver.eichler@gmx.de) © 2017 Oliver Eichler (oliver.eichler@gmx.de) Pavel Fric <b>Translation:</b> <b>Traduction:</b> Harrie Klomp Harrie Klomp Spanish: Espagnol: Win64: Win64: OS X: OS X: <b>Binaries:</b> <b>Fichiers binaires:</b> <b>Contributors:</b> <b>Contributeurs:</b> Jose Luis Domingo Lopez Ivo Kronenberg Ivo Kronenberg Helmut Schmidt Helmut Schmidt ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ... et merci à tous les gestionnaires de binaires Linux pour leur travail admirable. Remerciements particuliers à Dan Horák et Bas Couwenberg pour leur présence sur les mailing lists relatives aux distributions. Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Ce logiciel est distribué sous les termes de la licence GPL3 ou toute version utérieure ICanvasSetup Setup Map View... Configurer la vue cartographique... Projection & Datum Projection et date ... Scales Échelles Logarithmic Logarithmique Square (optimized for TMS and WMTS tiles) Carré (optimisé pour tuiles TMS et WMTS) IColorChooser Dialog Dialogue ICombineTrk Combine Tracks... Joindre des traces Available Tracks Traces Disponibles ... Combined Tracks Traces Combinées ICoordFormatSetup Coordinate Format... Format des coordonnées... N48° 53.660 E013° 31.113 N48° 53.660 E013° 31.113 N48.8943° E013.51855° N48.8943° E013.51855° N48° 53' 39.6" E13° 31' 6.78" N48° 53' 39.6" E13° 31' 6.78" ICreateRouteFromWpt Create Route from Waypoints Créer une route à partir de waypoints ... ... ICutTrk Cut Track Couper la trace Delete first part of the track and keep second one Supprimer le début de la trace Keep both parts of the track Séparer la trace en 2 Keep first part of the track and delete second one Supprimer la fin de la trace Cut Mode: Mode de découpe : Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Cocher la case pour stocker le résultat dans une nouvelle trace. Si vous voulez conserver les 2 parties de la trace vous devez en créer de nouvelles. Si vous voulez conserver seulement une moitié vous pouvez simplement enlever les points, ou cochez la case pour créer une nouvelle trace. Create a new track Créer une nouvelle trace IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Le format interne de la base de donnée %1 a changé. QMapShack va migrer votre base de donnée maintenant. Après la migration la base de données ne sera plus utilisable avec les versions précédentes de QMapShack. Il est recommandé de faire une sauvegarde de secours avant la migration. Migrate database... Migration de la base de données... Migration aborted by user Migration annulée par l'utilisateur Failed to migrate '%1'. Echec de la migration de %1. Error... Erreur... Migration failed Echec de la migration The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. La version de la base de données %1 est plus récente que celle acceptée par la version de QMapShack installée. QMapShack ne peut pas l'ouvrir. Initialization failed Echec de l'initialisation Wrong database version... Version de base donnée erronée... Database created by newer version of QMapShack Base de donnée créée par une version plus récent de QMapShack Failed to initialize '%1'. Echec de l'initialisation de '%1'. IDBMysql Password... Mot de passe... Password for database '%1': Mot de passe pour la base de données '%1': Update to database version 5. Migrate all GIS items. Mise à jour de la base de données en version 5. Migration de tous les objets SIG IDBSqlite Update to database version 3. Migrate all GIS items. Mise à jour de la base de données vers la version 3. Migration de tous les objets SIG. Update to database version 5. Migrate all GIS items. Mise à jour de la base de données vers la version 5. Migration de tous les objets SIG. Update to database version 6. Migrate all GIS items. Mise à jour de la base de données vers la version 6. Migration de tous les objets SIG. IDemPathSetup Setup DEM file paths Configurer les répertoires DEM ... - IDemPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Régler la transparence du calque DEM</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Cliquez pour utilser l'échelle courante comme échelle minimale d'affichage de la carte.</p></body></html> ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Définissez la plage d'échelle pour l'affichage de la carte. Utilisez les deux boutons à droite et à gauche pour définir l'échelle courante comme échelle maximale ou minimale.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Cliquez pour utilser l'échelle courante comme échelle maximale d'affichage de la carte.</p></body></html> Hillshading Relief ombré Slope Pente ° ° > > TextLabel Libellé IDemsList Form To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Pour ajouter des fichiers DEM cliquez sur <b>Fichier -> Configurer les répertoires DEM</b>. Or cliquez <a href=réglages'><b>ici</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Utilisez le menu contextuel (clic droite sur le fichier) pour activer un fichier. Utilisez glisser-déposer pour changer la position du fichier dans la liste. Activate Activer Move Up Déplacer vers le haut Hide DEM behind previous one Cacher le DEM derrière le précédent Move down Déplacer vers le bas Show DEM on top of next one Afficher DEM par-dessus le suivant Reload DEM Recharger DEM IDetailsGeoCache Dialog Dialogue Position: - Difficulty Difficulté Terrain Update spoilers Mise à jour des spoilers ... about:blank Hint: Indice: TextLabel Libellé IDetailsOvlArea Dialog Dialogue The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. La surface à été importée dans QMapShack et a été modifiée. Les données originales ne sont plus visibles. Voir l'historique pour connaître les changements. Toggle read only mode. You have to open the lock to edit the item. Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet. ... Color Couleur Border width Largeur de la bordure Style Opacity Opacité Info Info Points Position Hist. IDetailsPrj Form Keywords: Mots-clés: - Sort along track (multiple) Trier le long de la trace (multiple) Sort along track (single) Trier le long de la trace (individuel) Print diary Imprimer le journal ... Keep order of project Garder l'ordre du projet Rebuild diary. Restaurer le journal... IDetailsRte Info Information The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. L'itinéraire à été importé dans QMapShack et a été modifié. Les données originales ne sont plus visibles. Voir l'historique pour connaître les changements. - - Toggle read only mode. You have to open the lock to edit the item. Dés/activer le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet. ... ... Hist. Hist. IDetailsTrk Form - - Info ... Profile Speed Vitesse Toggle read only mode. You have to open the lock to edit the item. Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet. - Style Style Source Source Maximum Maximum Use/edit user defined visibility of arrows for this track Utiliser/éditer l'affichage personnalisé des flèches pour cette trace Use/edit system's visibility of arrows for all tracks Utiliser/éditer l'affichage global des flèches pour cette trace Minimum Minimum Use/edit user defined scale factor for this track Utiliser/éditer le facteur d'échelle personnalisé pour cette trace Use/edit system's default factor for all tracks Utiliser/éditer le facteur d'échelle global pour cette trace x x Width Largeur with arrows flèches Graphs Graphiques max. max. min. min. User defined limits for this track Limites personnalisées pour cette trace - - - - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. La trace à été importée dans QMapShack et a été modifiée. Les données originales ne sont plus visibles. Voir l'historique pour connaître les changements. Automatic limits Limites automatiques User defined limits for all tracks Limites personnalisées pour toutes les traces Color Couleur Activity Activité Set Track Activity Choisir l'activité de la trace To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Pour différencier les statistiques de la trace, selectionnez une activité dans la liste pour la trace complète. Ou bien sélectionnez une partie de la trace pour lui assigner une activité. Points Time Date Ele. Alt. Delta Dist. Slope Pente Ascent Montée Descent Descente Position Filter Filtre Hist. IDetailsWpt Dialog Dialogue Info Info Position: - Ele. Alt. Proximity: Proximité: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Le waypoint à été importé dans QMapShack et a été modifié. Les données originales ne sont plus visibles. Voir l'historique pour connaître les changements. Date/Time: Date/heure Hist. Hist. Toggle read only mode. You have to open the lock to edit the item. Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet. ... Add images. Ajouter des images Delete selected image. Supprimer l'image sélectionnée IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Un autre projet du même nom existe déjà. Si vous confirmez, il sera supprimé et remplacé. IElevationDialog Edit elevation... Modifier l'altitude... Elevation Altitude - Get elevation from active digital elevation model. Prendre l'altitude du modèle numérique de terrain (DEM) ... IExportDatabase Export database to GPX... Exporter la base de données en GPX ... ... ... Export Path: Chemin d'exportation : - - GPX 1.1 without extensions GPX 1.1 sans extensions Start Démarrer Abort Annuler Close Fermer IFilterDelete Form <b>Remove Track Points</b> <b>Supprimer des points de trace Remove all hidden track points permanently. Supprimer définitivement tous les points cachés. ... IFilterDeleteExtension Form <b>Remove Extension from all Track Points</b> <b>Enlever les extensions de tous les points de la trace</b> Remove Enlever from all Track Points de tous les points de la trace ... ... IFilterDouglasPeuker Form <b>Hide Points (Douglas Peuker)</b> <b>Cacher des points (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Cacher les points dont la distance de la ligne entre les points voisinants est inférieur à m Apply filter now. Appliquer le filtre maintenant. ... IFilterInterpolateElevation Form Formulaire <b>Interpolate Elevation Data</b> <b>Interpoler les altitudes</b> Replace elevation of track points with interpolated data. Remplacer les altitudes des points de la trace par des données interpolées. Quality Qualité Preview Aperçu ... ... IFilterInvalid Form Formulaire Hide Invalid Points Cacher les points invalides Hide points with invalid data. Cacher les points aux données invalides ... ... IFilterMedian Form <b>Smooth Profile (Median Method)</b> <b>Lisser le profile (méthode médian)</b> Smooth deviation of the track points elevation with a Median filter of size Lisse le profile avec un filtre médian de dimension points points ... IFilterNewDate Form <b>Change Time</b> <b>Modifier la date et l'heure Change start of track to Date et heure du début de la trace dd.MM.yy HH:mm:ss dd.MM.yy HH:mm:ss - - ... IFilterObscureDate Form <b>Obscure Timestamps</b> <b>Camoufler l'horodatage</b> Increase timestamp by Incrementer l'horodatage de sec. sec. with each track point. 0 sec. will remove timestamps. pour chaque point de la trace. O sec. supprimera l'horodatage. ... IFilterOffsetElevation Form <b>Offset Elevation</b> <b>Décalage de l'altitude</b> Add offset of Ajouter un décalage de to track points elevation. à l'altitude des points ... IFilterReplaceElevation Form <b>Replace Elevation Data</b> <b>Remplacer l'altitude</b> Replace elevation of track points with the values from loaded DEM files. Remplacer l'altitude des points par les données DEM ... IFilterReset Form <b>Reset Hidden Track Points</b> <b>Restaurer les points cachés</b> Make all trackpoints visible again. Rendre visible les points cachés ... IFilterSpeed Form <b>Change Speed</b> <b>Modifier la vitesse</b> Set speed to Mettre la vitesse à km/h ... IFilterSplitSegment Form <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Séparer les segments en traces</span></p></body></html> Creates a new track for every segment within this track. Créer une nouvelle trace pour chaque segment dans cette trace. ... ... IFilterSubPt2Pt Form Formulaire <b>Convert track subpoints to points</b> <b>Convertir les sous-points de la trace en points</b> Convert subpoints obtained from routing to ordinary track points Convertir les points calculés par le routage en points ordinaires ... ... IFilterTerrainSlope Form Formulaire <b>Calculate Terrain Slope</b> <b>Calculer la pente du terrain</b> Calculate slope of the terrain based on loaded DEM files. Calculer la pente du terrain à partir des fichies MNT chargés. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. Error de décodage FIT : le décodeur n'est pas dans l'état attendu %1 après le dernier octet de donnée du fichier FIT decoding error: a development field with the field_definition_number %1 already exists. Erreur de décodage FIT : un champ de développement avec le numéro de définition %1 existe déjà IGisDatabase Form Formulaire Name Nom Age Age To add a database do a right click on the database list above. Pour ajouter une base de données cliquez droit sur la liste ci-dessus. IGisItem [no name] [sans nom] The item is not part of the project in the database. L'objet ne fait pas partie du projet dans la base de données It is either a new item or it has been deleted in the database by someone else. Il s'agit soit d'un nouvel objet soit d'un objet qui a été supprimé de la base de donnée par quelqu'un d'autre The item is not in the database. L'objet n'est pas dans la base de données. The item might need to be saved L'objet aurait besoin d'être sauvegardé. Initial version. Version initiale Never ask again. Ne plus demander. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3>Cet élément est probablement en lecture seule car il n'a pas été créé dans QMapShack. En général les données importées ne sont pas modifiées par les utilisateurs. Mais si c'est bien votre intention cliquez 'OK'. Read Only Mode... Mode lecture seule <h4>Description:</h4> <h4>Description:</h4> <p>--- no description ---</p> <p>--- pas de description ---</p> <h4>Comment:</h4> <h4>Commentaire:</h4> <p>--- no comment ---</p> <p>--- pas de commentaire ---</p> <h4>Links:</h4> <h4>Liens:</h4> <p>--- no links ---</p> <p>--- pas de liens ---</p> Edit name... Éditer le nom... Enter new %1 name. Entrez un nouveau %1 nom. IGisProject Save project? Enregistrer le projet ? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>Le projet a été modifié. Sauvegarder avant de quitter ? %1: Correlate tracks and waypoints. %1: Corréler les traces et les waypoints. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>Etait-ce trop long ? Voulez-vous ne pas faire la corrélation des traces et waypoints la prochaine fois pour ce projet ? Canceled correlation... Corrélation annulée... Save "%1" to... Sauvegarder"%1" dans ... <br/> Filename: %1 <br/> Nom de fichier: %1 Waypoints: %1 Waypoints: %1 Tracks: %1 Traces: %1 Routes: %1 Routes: %1 Areas: %1 Surfaces: %1 Are you sure you want to delete '%1' from project '%2'? Êtes-vous sûr de vouloir supprimer %1 du projet '%2'? Delete... Supprimer... IGisWorkspace Form Formulaire Opacity Opacité Change the opacity of all GIS Items on the map. Modifier l'opacité de tous les objets SIG sur la carte. Filter Filtre Name Nom Clear Filter RAZ filtre Setup Filter Réglages Filtre IGridSetup Setup Grid... Configurer la grille... Projection Projection restore default Remise à zéro ... Get projection from current map. Utiliser la projection de la carte courante projection wizzard Assitant de projection Grid color Couleur de la grille setup grid color Choisir la couleur de la grille IImportDatabase Form ... Source Database: Base de donnée source - Target Database: Base de donnée cible Start Démarrer IInputDialog Edit... Éditer... TextLabel Libellé ILineOp Routing Routage ILinksDialog Links... Liens... Type Type Text Texte Uri ... IMainWindow QMapShack QMapShack File Fichier View Vue Window Fenêtre ? ? Tool Outils Maps Cartes Dig. Elev. Model (DEM) Modèle numérique de terrain (DEM) Workspace Espace de travail Toolbar Barre d'outils Routing Routage Add Map View Ajouter une vue cartographique Ctrl+T Show Scale Afficher l'échelle Setup Map Font Configurer la police de la carte Show Grid Afficher la grille Ctrl+G Setup Grid Configurer la grille Ctrl+Alt+G Flip Mouse Wheel Inverser le sens de la molette de souris Setup Map Paths Configurer les répertoires des cartes POI Text Libellés des points d'interêt Night / Day Jour / Nuit Map Tool Tip Infobulles sur la carte Ctrl+I CTRL + I Setup DEM Paths Configurer les répertoires DEM About À propos Help Aide F1 F1 Setup Map View Configurer la vue cartographique Load GIS Data Charger des données SIG... Load projects from file Charger un fichier projet Ctrl+L Save All GIS Data Enregistrer toutes les données SIG Save all projects in the workspace Enregistrer tous les projets de l'espace de travail Ctrl+S Setup Time Zone Configurer le fuseau horaire Add empty project Ajouter un projet vide Search Google Recherche Google Close all projects Fermer tous les projets F8 Setup Units Configurer les unités Setup Workspace Configurer l'espace de travail Setup save on exit. Sauvegarde de la configuration en quittant Import Database from QLandkarte Importer une base de données QLandkarte Import QLandkarte GT database Importer une base de données QLandkarte GT VRT Builder Générateur de VRT GUI front end to gdalbuildvrt Interface utilisateur pour gdalbuildvrt Store Map View Enregistrer une vue cartographique Write current active map and DEM list including the properties to a file Sauvegarder les cartes et calques DEM actives et leurs paramètres dans un fichier Load Map View Charger une vue cartographique Restore view with active map and DEM list including the properties from a file Rétablir une vue avec les cartes et calques DEM et leurs paramètres à partir d'un fichier Ext. Profile Profile externe Ctrl+E Close Fermer Ctrl+Q CTRL + Q Clone Map View Dupliquer une vue cartographique Ctrl+Shift+T Create Routino Database Créer une base de données Routino Save(Print) Map Screenshot Sauvegarder (Imprimer) une capture d'écran de la carte Print a selected area of the map Imprimer une zone sélectionnée de la carte Ctrl+P CTRL + P Setup Coord. Format Choisir le format de coordonnées Change the format coordinates are displayed Modifier le format des coordonnées affichées Setup Map Background Modifier l'arrière-plan de la carte Setup Waypoint Icons Modifer les icônes des waypoints Setup path to custom icons Modifier le chemin des icônes personnalisés Close Tab Fermer l'onglet Ctrl+W CTRL + W Quickstart Help Aide Rapide Setup Toolbar Réglages barre d'outils Toggle Docks Activer les docks Toggle visibility of dockable windows Activer la visibilité des fenêtres dockables Ctrl+D CTRL + D Full Screen Plein écran F11 F11 Min./Max. Track Values Valeurs Min./Max. des traces Show the minimum and maximum values of the track properties along the track in the map view. Afficher les valeurs min/max le long de la trace dans la vue carte Ctrl+N Ctrl+N Database Base de données IMapList Form To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Pour ajouter des cartes utilisez <b>Fichier->Configurer les répertoires des cartes</b>. Ou cliquez <a href='réglages'><b>ici</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Utilisez le menu contextuel (clic droite sur la carte) pour activer une carte. Utilisez glisser-déposer pour changer la position de la carte dans la liste. Help! I want maps! I don't want to read the documentation! Au secours ! Je veux des cartes ! Je n'ai pas envie de lire la documentation ! Activate Activer Move Up Déplacer vers le haut Hide map behind previous map Cacher la carte derrière la carte précédente Move down Déplacer vers le bas Show map on top of next map Montrer la carte au sommet de la carte suivante Reload Maps Recharger les cartes IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. L'affichage de cette carte nécessite l'utilisation d'OpenSSL. Par défaut OpenSSL n'est pas inclus dans QMapShack à cause de restriction légales dans certains pays. Vous pouvez consulter <a href='https://www.openssl.org/community/binaries.html'>la page d'accueil OpenSSL</a> pour trouver des fichiers binaires. Vous devez copier libeay32.dll et ssleay32.dll dans le répertoire programme de QMapShack. Error... Erreur... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 tuiles à charger<br/> IMapPathSetup Setup map paths Configurer les répertoires des cartes Root path of tile cache for online maps: Répertoire racine du cache de tuiles pour les cartes en ligne : ... ... Help! I want maps! I don't want to read the documentation! Au secours ! Je veux des cartes ! Je n'ai pas envie de lire la documentation ! - - IMapPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Régler la transparence de la carte</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Cliquez pour utilser l'échelle courante comme échelle minimale d'affichage de la carte.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Définissez la plage d'échelle pour l'affichage de la carte. Utilisez les deux boutons à droite et à gauche pour définir l'échelle courante comme échelle maximale ou minimale.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Cliquez pour utilser l'échelle courante comme échelle maximale d'affichage de la carte.</p></body></html> Areas Surfaces Lines Lignes Points Points Details Détails - - Cache Path Répertoire du cache Type File: Type de fichier : Forget external type file and use internal types. Ne pas utiliser de TYP¨externe et utiliser le TYP interne. Load an external type file. Charger un fichier TYP externe. Cache Size (MB) Taille du cache (MO) Expiration (Days) Durée du cache (jours) IMapVrtBuilder Form Advanced Options Options avancées Source No Data (-srcnodata) Target No Data (-vrtnodata) Target Projection (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> ... ... Select source files: Sélectionnez les fichiers source: Target Filename: Fichier cible: - - Start Démarrer IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Nouvelle ligne</b><br/>Déplacez la souris et utilisez le bouton gauche pour ajouter des points. Cliquez droit pour terminer.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Supprimer un point</b><br/>Approchez le pointeur du point et cliquez gauche pour le supprimer.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Sélectionner une série de points</b><br/> Pour commencer la sélection, cliquez gauche sur le premier point. Cliquez gauche sur le sur le deuxième point pour terminer la sélection et choisissez une option. Utilisez le bouton droit pour annuler.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Déplacer un point</b><br/>Approchez le pointeur près d'un point et cliquez gauche pour le coller au pointeur. Déplacez le point avec la souris. Déposez le point avec un clic gauche. Utilisez le bouton droit pour annuler.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Ajouter un point</b><br/>Placez le pointeur de la souris près d'un segment de ligne et cliquez gauche pour ajouter un point. Le nouveau point va coller au pointeur et vous pouvez le déplacer. Déposez le point par un clic gauche. Utilisez le clic droit pour annuler.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Aucun calcul d'itinéraire</b><br/>Les points seront connectés par une ligne droite.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Calcul d'itinéraire automatique</b><br/>Les paramètres de calcul d'itinéraire actuels serviront pour calculer un tracé entre les points. <b>Remarque :</b>Le routeur sélectionné doit être capable de faire le calcul à la volée. Généralement, les routeurs hors ligne en sont capables, les routeurs en ligne ne le sont pas.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Calcul d'itinéraire vecteur</b><br/>Connecter les points avec une ligne basée sur une carte vecteur active, si possible.<br/> <b>%1 Metrics</b> <b>%1 Mesures</b> Distance: Distance: Ascent: Montée: Descent: Descente: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> IPhotoAlbum Form ... IPlot Reset Zoom Zoom à la valeur initiale Stop Range tbc: range Terminer la série Save... Enregistrer... Add Waypoint Ajouter un waypoint Cut... Couper... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Enfoncez CTRL pour zoomer uniquement sur l'axe vertical. Enfoncez ALT pour zoomer uniquement sur l'axe horizontal. No or bad data. Aucune donnée ou données invalides. Select output file Sélectionner le fichier de sortie IPositionDialog Position ... Enter new position Saisissez la nouvelle position Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Mauvais format de position. Formats valides: "[N|S] ddd mm.sss [W|E] ddd mm.sss" ou "[N|S] ddd.ddd [W|E] ddd.ddd" IPrintDialog Print map... Imprimer la carte... When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. Pour l'impression de cartes en lignes assurez-vous que l'ensemble de la zone à imprimer est bien déjà stockée dans le cache. Save Enregistrer When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. Poursauvegarder des cartes en lignes assurez-vous que l'ensemble de la zone à sauvegarder est bien déjà stockée dans le cache. TextLabel Libellé Print Impression IProgressDialog Please wait... Patientez s'il-vous-plaît TextLabel Libellé IProjWizard Proj4 Wizzard Mercator UTM zone user defined personnalisé Datum Date World Mercator (OSM) Result: Resultat: UPS North (North Pole) UPS Nord (pôle nord) UPS South (South Pole) UPS Sud (pôle sud) Projection IProjWpt Waypoint Projection Dupliquer un waypoint ... - Clone waypoint and move by: Dupliquer le waypoint et déplacer de: m ° IRouterBRouter Form Formulaire Profile Profil Alternative Alternative display selected routing profile ... ... on-the-fly routing BRouter: not running start/stop BRouter show BRouter console Setup Caution! BRouter is listening on all ports for connections. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> IRouterBRouterInfo BRouter Profile TextLabel Libellé IRouterBRouterSetupWizard BRouter Setup choose which BRouter to use BRouter-Web (online) local Installation Expert Mode local BRouter Installation directory: select installation directory ... ... labelLocalDirResult create or update installation Java Executable labelLocalJavaResult search for installed java Download and install BRouter Version about:blank File to install Download and Install available Profiles install profile remove profile installed Profiles content of profile BRouter-Web URL: Service-URL Profile-URL Hostname Port Port Profile directory Segments directory Custom Profiles dir Max Runtime Number Threads Java Options Profiles Url IRouterMapQuest Form Highways Autoroutes Seasonal Routes saisonnières Language Langue Country Border Frontières Profile Profil Avoid: Eviter: Ferry Bac Toll Road Routes à péages Unpaved Routes non revêtues <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Itinéraires fournis par <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Profile Profile Mode Mode Database Base de données Add paths with Routino database. Ajouter des répertoires qui contiennent des bases de données Routino. ... ... Language Langue To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Pour pouvoir utiliser le calcul d'itinéraire hors ligne, vous devez spécifier les répertoires qui contiennent les données locales de calcul d'itinéraire. Utilisez le bouton de configuration pour ajouter des répertoires. Vous pouvez créer vos propres données de calcul d'itinéraires avec <b>Outils->Créer une base de données Routino</b>. IRouterRoutinoPathSetup Setup Routino database... Configurez la base de données Routino... ... ... - - IRouterSetup Form IRoutinoDatabaseBuilder Form Formulaire ... ... Select source files: Sélectionnez les fichiers source: Start Démarrer Target Path: Chemin cible: - - File Prefix Préfixe du fichier <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> IScrOptEditLine Form Formulaire Save to original Sauvegarder sur l'original Save as new Enregistrer sous... Abort Annuler Move points. (Ctrl+M) Déplacer les points. (CTRL + M) Ctrl+M CTRL + M Add new points. (Ctrl++) Ajouter des points (CTRL + + ) Ctrl++ CTRL + + Select a range of points. (Ctrl+R) Selectionner une plage de points (CTRL + R) Ctrl+R CTRL + R No auto-routing or line snapping (Ctrl+O) Pas d'autoroutge ou de suivi le ligne automatique (CTRL + O) Ctrl+O CTRL + O Use auto-routing to between points. (Ctrl+A) Utiliser l'autoroutage entre les points. (CTRL + A) Ctrl+A CTRL + A Snap line along lines of a vector map. (Ctrl+V) Suivre les lignes de la carte vectorielle (CTRL + V) ... ... Delete a point. (Ctrl+-) Supprimer un point. (Ctrl+-) Ctrl+- Ctrl+- 0 A V Ctrl+V CTRL + V Undo last change Annuler la dernière modification Redo last change Rétablir la dernière modification IScrOptOvlArea Form View details and edit. Voir les détails et éditer. ... Copy area into another project. Copier la surface dans un autre projet. Delete area from project. Supprimer la surface du projet. Edit shape of the area. Modifier la forme de la surface. TextLabel Libellé IScrOptPrint Form Formulaire Save selected area as image. Sauvegarder la zone sélectionnée comme image ... ... Print selected area. Imprimer la zone sélectionnée IScrOptRangeLine Form Delete all points between the first and last one. Supprimer tous les points entre le premier et le dernier point. ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Calculer un itinéraire entre le premier et le dernier point sélectionné.</p></body></html> IScrOptRangeTrk Form Hide all points. Cacher tous les points. ... Show all points. Afficher tous les points. Set an activity for the selected range. Sélectionner une activité pour la plage sélectionnée. Copy track points as new track. Créer une nouvelle trace à partir des points sélectionnés TextLabel Libellé IScrOptRte Form ... Copy route into another project. Copier la route dans un autre projet. View details and edit. Voir les détails et éditer. Delete route from project. Supprimer la route du projet. Calculate route. Calculer la route. Reset route calculation. Réinitialisationdu calcul d'itinéraire Move route points. Déplacer les points de la route. Convert route to track Convertir la route en trace TextLabel Libellé IScrOptSelect Form Formulaire Copy all selected items to a project. Copier tous les éléments sélectionnés dans un projet ... ... Create a route from selected waypoints. Créer une route à partir des waypoints sélectionnés Change the icon of all selected waypoints. Changer les icônes de tous les waypoints sélectionnés Combine all selected tracks to a new one. Combiner toutes les trcaes sélectionnées dans une seule nouvelle Set an activity for all selected tracks. Choisir un activité pour toutes les traces sélectionnées. Delete all selected items. Supprimer tous les objets sélectionnés Select all items that intersect the selected area. Sélectionner tous les objets dont au moins une partie est présente dans la zone sélectionnée Select all items that are completely inside the selected area. Sélectionner tous les objets qui sont totalement inclues dans la zone sélectionnée. Add tracks to selection. Ajouter des traces à la sélection Add waypoints to selection. Ajouter des waypoints à la sélection Add routes to selection. Ajouter des routes à la sélection Add areas to selection. Ajouter des surfaces à la sélection IScrOptTrk Form ... Copy track into another project. Copier la trace dans un autre projet View details and edit properties of track. Voir les détails et éditer les paramètres de la trace. Delete track from project. Supprimer la trace du projet. Show on-screen profile and detailed information about points. Afficher le profil d'altitude et des informations detaillées sur les points Select a range of points. Sélectionner une séquence de points. Edit position of track points. Modifier la position des points de la trace Reverse track. Inverser la trace Combine tracks. Joindre des traces Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Couper la trace au point selectionné. Vous pouvez faire ceci pour: * Supprimer des points erronnés au début ou à la fin de la trace * Utiliser les segments de trace obtenus pour préparer une nouvelle trace * Tronçonner une trace en plusieurs étapes Set an activity for the complete track. Choisir une activité pour la totalité de la trace. Copy track together with all attached waypoints into another project. Copier la trace et ses waypoints attachés dans une autre projet. TextLabel Libellé IScrOptWpt Form View details and edit. Voir les détails et éditer. ... Copy waypoint into another project. Copier le waypoint dans un autre projet. Delete waypoint from project. tbc: waypoint Supprimer le waypoint du projet. Show content as static bubble. Afficher le contenu comme bulle statique. Move waypoint to a new location. Déplacer le waypoint. Clone waypoint and move clone a given distance and angle. Dupliquer le waypoint et déplacer la copie d'une distance et d'un angle défini. edit radius of circular area changer le rayon de la zone circulaire Switch between proximity and nogo-area basculer entre proximité et zone interdite Delete circle defined by waypoint Supprimer le cercle défini par le waypoint TextLabel Libellé IScrOptWptRadius Form Formulaire edit radius of circular area changer le rayon de la zone circulaire ... ... Switch between proximity and nogo-area basculer entre proximité et zone interdite Delete circle defined by waypoint Supprimer le cercle défini par le waypoint TextLabel Libellé ISearchDatabase Search... Rechercher... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Entrez le mot à rechercher et cliquez sur le bouton "Rechercher". Si vous entrez 'mot' alors 'mot' uniquement sera recherché. Si vous entrez 'mot*', 'mot' doit âtre au début de la chaîne de caractères recherchée. Name Nom Search Rechercher Close Fermer ISelDevices Select devices... Sélectionner les appareils... ISelectActivityColor Form Formulaire ISelectCopyAction Copy item... Copier un élément... Replace existing item Remplacer l'élément existant TextLabel Libellé Do not copy item Ne pas copier l'élément Create a clone Dupliquer l'élément Replace with: Remplacer par: Keep item: Conserver l'élément: The clone's name will be appended with '_Clone' Le nom de la copie aura le suffixe '_Clone' And for all other items, too. et pour tous les autres éléments ISelectDBFolder Select Parent Folder... Sélectionner le répertoire parent... Name Nom ISelectDoubleListWidget Form Formulaire Available Disponible Add to selected items Ajouter aux objets sélectionnés Remove from selected items Enlever des objets sélectionnés Selected Sélectionné Move selected items up Déplacer les objets sémectionnés vers le haut Move selected items down Déplacer les objets sémectionnés vers le bas ... ... ISelectProjectDialog Select a project... Choisissez un projet... Select project from list or enter new project name. Choisissez un projet dans la liste ou entrez le nom d'un nouveau projet. New project's name Nom du nouveau projet New project is created as: Le nouveau projet sera de type: *.qms *.gpx Database Base de données ISelectSaveAction Copy item... Copier un élément... Replace existing item Remplacer l'élément existant Add a clone Ajouter un clone The clone's name will be appended with '_Clone' Le nom du clone aura le suffixe '_Clone' Replace with: Remplacer par: TextLabel Do not replace item Ne pas remplacer l'élément Use item: Utiliser l'élément: And for all other items, too. et pour tous les autres éléments ISetupDatabase Add database... Ajouter une base de données... - Name Nom <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Attention!</span> Il est recommandé de laisser le champ "mot de passe" vide,car QMapShack stocke les mots de passe en clair. Une mot de passe sera alors demandé à chaque démarrage.</p> Do not use a password. Ne pas utiliser de mot de passe SQLite SQLite MySQL MySQL Server Serveur Port Port 00000 00000 User Utilisateur Password Mot de passe <b>Port:</b> Leave the port field empty to use the default port. <b>Port:</b> Laissez le champ "Port" vide pour utiliser le port par défaut. File: Fichier: Add new database. Ajouter une nouvelle base de données. ... Open existing database. Ouvrir une base de données existante. ISetupFilter Form Formulaire Apply filter to Appliquer le filtre à name only nom seulement complete text texte complet ISetupFolder Database Folder... Dossier de base donnée... Folder name Nom du dossier Group Groupe Project Projet Other Autre ISetupNewWpt New Waypoint... Nouveau waypoint... Symbol Symbole ... ... Position Position Name Nom Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Mauvais format de position. Formats valides: "[N|S] ddd mm.sss [W|E] ddd mm.sss" ou "[N|S] ddd.ddd [W|E] ddd.ddd" ISetupWorkspace Setup workspace... Configurer l'espace de travail... save workspace on exit, and every Sauvegarde de l'espace de travail en quittant et toutes les minutes listen for database changes from other instances of QMapShack. On port Détecter des modiications de la base de données par d'autres instances de QMapShack. Sur le port 00000 00000 ITemplateWidget Insert Template... Insérer un template Templates Templates Select a path with your own templates. Séléctionner le chemin vers vos propres templates. ... ... Preview Aperçu ITextEditWidget Edit text... Éditer le texte... Undo Annuler Ctrl+Z Redo Répéter Ctrl+Shift+Z Cut Couper Ctrl+X Copy Copier Ctrl+C Paste Coller Templ. Templ. A:L A:G A:C A:C A:R A:D A:B A:J B G I I U S C C Standard Standard Bullet List (Disc) Puce de liste (disque) Bullet List (Circle) Puce de liste (Cercle) Bullet List (Square) Puce de liste (Carré) Ordered List (Decimal) Liste numérotée (chiffres) Ordered List (Alpha lower) Liste numérotée (lettres minuscules) Ordered List (Alpha upper) Liste numérotée (lettres majuscules) Ordered List (Roman lower) Liste numérotée (chiffres romains minuscules) Ordered List (Roman upper) Liste numérotée (chiffres romains majuscules) Ctrl+V Align Left Aligné à gauche Ctrl+L Align Right Aligné à droite Ctrl+R Align Center Centré Ctrl+E Align Block Justifié Ctrl+J Underline Soulignage Ctrl+U Bold Gras Ctrl+B Italic Italique Ctrl+I Plain Texte brut Reset the text's format before pasting Réinitialiser la mise en forme du texte avant de coller Select All Tout sélectionner Ctrl+A CTRL + A Delete Supprimer Reset Font Réinitialiser la police Reset Layout Réinitialiser la mise en forme Normal Normal Paste without resetting the text's format Coller sans réinitialiser la mise en forme du texte Insert From Template Insérer depuis le template Create text from template. Créer le texte depuis le template ITextEditWidgetSelMenu B B I I U U Cut Couper Copy Copier Paste Coller ITimeZoneSetup Setup Time Zone ... Configurer le fuseau horaire UTC UTC Local Local Automatic Automatique Print date/time in Afficher la date au format long format, or long short format court <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Note:</b> Le changement d'unités ne sera totalement visible qu'après le redémarrage de QMapShack. IToolBarSetupDialog Setup Toolbar Réglages de la barre d'outils Toolbar is visible in Fullscreen-mode Barre d'outils visible en mode plein écran IToolShell Execution of external program `%1` failed: Echec de l'execution du programme externe %1: Process cannot be started. Le process ne peut être démarré Make sure the required packages are installed, `%1` exists and is executable. Assurez-vous que les paquets requis sont installés, '%1' existe et est exécutable. External process crashed. Process externe planté. An unknown error occurred. Une erreur inconnue a eu lieu. !!! failed !!! !!! échec !!! IUnit Error Erreur Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Format de position incorrect. Formats valides: "[N|S] ddd mm.sss [W|E] ddd mm.sss" ou "[N|S] ddd.ddd [W|E] ddd.ddd" Position values out of bounds. Valeurs de la position hors de la plage autorisée. IUnitsSetup Setup units... Configurer les unités Length unit Unité de longueur Metric Métrique Slope unit Unité de pente Degrees (°) Degrés (°) Percent (%) Pourcents (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Note:</b> Le changement d'unités ne sera totalement visible qu'après le redémarrage de QMapShack. Imperial Impérial Nautic Nautique IWptIconDialog Icons... Icônes External Icons: Icônes externes: - - ... ... All custom icons have to be *.bmp or *.png format. Les icônes personnalisés doivent être de type *.bmp ou *.png qmapshack-1.10.0/src/locale/qmapshack_es.ts000644 001750 000144 00001551305 13216660772 022003 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2, se esperaba V%3) %1 (API V%2) %1 (API V%2) (no DBUS: device detection and handling disabled) (no DBUS: detección y manipulación de dispositivos desactivados) CActivityTrk Foot A pié Bicycle Bicicleta Motor Bike Moto Car Coche Cable Car Teleférico Swim Natación Ship Barco Ski/Winter Esquí No Activity Sin Actividad Total Total Ascent: Ascenso: Descent: Descenso: Aeronautics Aeronáutica Public Transport Transporte Público Distance: Distancia: Speed Moving: Velocidad en movimiento: Speed Total: Velocidad Total: Time Moving: Tiempo en movimiento: Time Total: Tiempo Total: CCanvas View %1 Vista %1 Setup Map Background Configuracion del Fondo del Mapa CColorChooser Esc. Esc. CCommandProcessor Print debug output to console. Imprimir salida de depuración en la consola. Print debug output to logfile (temp. path). Imprimir salida de depuración en archivo (carpeta temporal). Do not show splash screen. No mostrar pantalla de bienvenida File with QMapShack configuration. Archivo con la configuración de QMapShack file Archivo Files for future use. Archivos para uso futuro CCreateRouteFromWpt route Ruta CDBFolderLostFound All your data grouped by folders. Todos tus datos agrupados en carpetas. Lost & Found (%1) Objetos Perdidos (%1) Lost & Found Objetos Perdidos CDBFolderMysql All your data grouped by folders. Todos tus datos agrupados en carpetas. MySQL Database Mi base de datos SQL Server: Servidor: (No PW) (Sin PW) Error: Error: CDBFolderSqlite All your data grouped by folders. Todos tus datos agrupados en carpetas. SQLite Database Base de Datos SQLite File: Archivo: Error: Error: CDBItem %1 min. %1 min. %1 h %1 h %1 days %1 dias CDBProject Failed to load... Falló al cargar... Can't load file "%1" . It will be skipped. No se puede cargar el archivo "%1" . Se omitirá. Project already in database... Proyecto ya en base de datos ... The project "%1" has already been imported into the database. It will be skipped. El proyecto "%1" Ya se ha importado a la base de datos. Se omitirá. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database El elemento %1 se ha cambiado por %2 (%3). Para resolver este conflicto puedes crear y guardar una copia, forzar o eliminar tu versión y tomar la de la base de datos Conflict with database... Conflicto con la base de datos... Clone && Save Duplicar y Guardar Force Save Forzar guardado Take remote Toma remota Missing folder... Falta la carpeta Failed to save project. The folder has been deleted in the database. Error al guardar el proyecto. La carpeta se ha eliminado de la base de datos. Save ... Guardar... Error Error There was an unexpected database error: %1 Se produjo un error inesperado en la base de datos : %1 The project '%1' is about to update itself from the database. However there are changes not saved. El proyecto '%1' Está a punto de actualizarse desde la base de datos. Sin embargo, hay cambios no guardados. Save changes? ¿Guardar cambios? CDemList Deactivate Desactivar Activate Activar CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Añadir o quitar rutas que contienen datos DEM. Puede haber múltiples archivos en una ruta, pero no se buscará en los subdirectorios. Los formatos soportados son: %1 Select DEM file path... Seleccione la ruta al archivo DEM... CDemVRT Error... Error... Failed to load file: %1 Fallo al cargar el archivo: %1 DEM must have one band with 16bit or 32bit data. El DEM debe tener una sola banda con datos de 16 o 32 bits. No georeference information found. No se encontró información de georreferenciación. CDetailsGeoCache none ninguno ??? ??? Searching for images... Buscando imagenes... No images found No se encontraron imagenes CDetailsPrj none ninguna Build diary... Creando diario... <h2>Waypoints</h2> Waypoints Info Información Comment Comentario <h2>Tracks</h2> Tracks From Start Desde el inicio To Next Al siguiente To End Al Final Ascent: Ascenso: Descent: Descenso: <h2>Areas</h2> Áreas You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Desea ordenar waypoints a lo largo de un track, pero ha desactivado la correlación de track y waypoint. ¿Desea volver a encenderlo? Correlation... Correlación.. <b>Summary over all tracks in project</b><br/> <b>Resumen de todos los tracks del proyecto</b><br/> Distance: Distancia: <h2>Routes</h2> <h2>Rutas</h2> Edit name... Editar nombre... Enter new project name. Introducir nuevo nombre de proyecto. Edit keywords... Editar etiquetas... Enter keywords. Introducir etiquetas. Print Diary Imprimir Diario CDetailsTrk Reduce visible track points Reducir puntos visibles del track Change elevation of track points Cambiar altitud de puntos del track Change timestamp of track points Cambiar fecha/hora de puntos del track Miscellaneous Diversos Color Color Activity Actividad CDetailsWpt Enter new proximity range. Introduzca el nuevo valor de proximidad. CDeviceGarmin Picture%1 foto%1 Unknown Desconocido CDeviceGarminArchive Archive - expand to load Archivo: expanda para cargar Archive - loaded Archivo - cargado CElevationDialog No DEM data found for that point. No se encontraron datos DEM para ese punto. CExportDatabase Select export path... Seleccionar ruta de exportación ... CExportDatabaseThread Create %1 Crear %1 Failed to create %1 Fallo al crear %1 Done! ¡Hecho! Abort by user! ¡Cancelado por el usuario! Database Error: %1 Error de base de datos: %1 Save project as %1 Guardar proyecto como %1 Failed! ¡Falló! CFilterDeleteExtension No extension available Extensión no disponible CFilterInterpolateElevation coarse grueso medium medio fine fino CFitCrcState FIT decoding error : invalid CRC. Error decodificando FIT : CRC inválido. CFitDecoder FIT decoding error: unexpected end of file %1. FIT error de descodificación: final inesperado del archivo %1. CFitFieldBuilder FIT decoding error: unknown base type %1. Error de descodificación FIT: tipo de base desconocido %1. CFitFieldDataState Missing field definition for development field. Falta la definición de campo para el campo de desarrollo. FIT decoding error: invalid field def nr %1 while creating dev field profile. Error de decodificación FIT: campo no válido def nr %1 al crear el perfil de campo dev CFitHeaderState FIT decoding error: protocol %1 version not supported. Error de descodificación FIT: la versión del protocolo %1 no es compatible. FIT decoding error: file header signature mismatch. File is not FIT. Error de descodificación de FIT: falta de coincidencia de firma de encabezado de archivo. El archivo no es FIT. CFitProject Failed to load file %1... Falló al cargar archivo %1... Failed to open FIT file %1. Falló al cargar archivo FIT %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. Error decodificacion FIT: Arquitectura %1 no soportada FIT decoding error: invalid offset %1 for state 'record content' FIT error de decodificación: desplazamiento no válido %1 para el contenido de registro de estado CGarminTyp Warning... Aviso... This is a typ file with unknown polygon encoding. Please report! Este es un fichero TYP con una codificación de polígonos desconocida. ¡Por favor repórtelo! This is a typ file with unknown polyline encoding. Please report! Este es un fichero TYP con una codificación de polilíneas desconocida. ¡Por favor repórtelo! CGisItemOvlArea thin fino normal normal wide ancho strong intenso _Clone Duplicar Area: %1%2 Área: %1%2 Changed area shape. Se cambió la forma del área. Changed name. Se cambió el nombre. Changed border width. Se cambió la anchura del borde. Changed fill pattern. Se cambió el patró de relleno. Changed opacity. Se cambió la opacidad. Changed comment. Se cambió el comentario. Changed description. Se cambió la descripción. Changed links Se cambió el enlace Changed color Se cambió el color CGisItemRte _Clone _Duplicar track track Changed name. Se cambió el nombre. Changed comment Se cambió el comentario Changed description Se cambió la descripción Changed links Se cambió el enlace Length: %1%2 Longitud: %1%2 Time: %1%2 Tiempo: %1%2 Distance: %1%2 Distancia: %1%2 Length: - Longitud: - Time: - Tiempo: - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Última vez enrutado:<br/>%1 with %1 con %1 Changed route points. Puntos de ruta modificados. CGisItemTrk FIT file %1 contains no GPS data. Archivo FIT %1 no contiene datos GPS. Error... Error... Failed to open %1. Fallo al abrir %1. Only support lon/lat WGS 84 format. Solamente soporta formato lon/lat WGS84. Failed to read data. Fallo al leer los datos. _Clone _Duplicar Changed trackpoints, sacrificed all previous data. Se cambiaron los puntos del track, y descartados todos los datos previos. Time: %1%2, Speed: %3%4 Tiempo: %1%2, Velocidad: %3%4 Moving: %1%2, Speed: %3%4 Tiempo en movimiento: %1%2, Velocidad: %3%4 Start: %1 Inicio: %1 Start: - Inicio: - End: %1 Final: %1 End: - Final: - Points: %1 (%2) Puntos: %1 (%2) Invalid elevations! ¡Datos de altitud invalidos! Invalid timestamps! ¡Marcas de tiempo no válidas! Invalid positions! ¡Posiciones inválidas! Activities: %1 Actividades: %1 Index: %1 Indice: %1 Index: visible %1, total %2 Indice: visible %1. total %2 , Slope: %1%2 , Pendiente: %1%2 ... and %1 tags not displayed Y %1 etiquetas no mostradas Distance: - (-) Distancia: - (-) Moving: - (-) En movimiento: - (-) track track Hide point %1. Ocultar punto %1 Hide points %1..%2. Ocultar puntos %1..%2 , %1%2 , %1%2 Invalid points.... Puntos inválidos... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? El track '%1' tiene %2 puntos inválidos de %3 visibles. ¿Quiere ocultar los puntos inválidos? min. min. max. max. Length: %1%2 Longitud: %1%2 , %1%2%3, %4%5%6 , %1%2%3, %4%5%6 , %1-, %2- , %1-, %2- Time: -, Speed: - Tiempo: -, Velocidad: - Moving: -, Speed: - En movimiento: -, Velocidad: - Ele.: %1%2 Altitud: %1%2 , Speed: %1%2 , Velocidad: %1%2 Ascent: - (-) Ascenso: - (-) Descent: - (-) Descenso: - (-) Ascent: %1%2 (%3%) Ascenso: %1%2 (%3%) , Descent: %1%2 (%3%) , Descenso: %1%2 (%3%) Distance: %1%2 (%3%) Distancia: %1%2 (%3%) , Moving: %1%2 (%3%) , En Movimiento: %1%2 (%3%) Ascent: - Ascenso: - Descent: - Descenso: - Ascent: %1%2 Ascenso: %1%2 , Descent: %1%2 , Descenso: %1%2 Distance: %1%2 Distancia: %1%2 , Time: %1%2 , Tiempo: %1%2 Permanently removed points %1..%2 Puntos eliminados definitivamente %1..%2 Show points. Mostrar puntos. Changed name Se cambió el nombre Changed comment Se cambió el comentario Changed description Se cambió la descripción Changed links Se cambió el enlace Changed elevation of point %1 to %2 %3 Se cambió altitud de los puntos %1 a %2 %3 Changed activity to '%1' for complete track. Actividad cambiada a '%1' para todo el track. Changed activity to '%1' for range(%2..%3). Actividad cambiada a '%1' para el rango (%2..%3). Hide points by Douglas Peuker algorithm (%1%2) Ocultar puntos con algoritmo Douglas Peuker (%1%2) Hide points with invalid data. Ocultar puntos con datos inválidos Reset all hidden track points to visible Restaurados todos los puntos a visible Permanently removed all hidden track points Elminados definitivamente todos los puntos ocultos del track Smoothed profile with a Median filter of size %1 Pefil suavizado con Mediana de %1 puntos Added terrain slope from DEM file. Añadida pendiente del terreno desde archivo DEM Replaced elevation data with data from DEM files. Datos de altitud sustituidos por valores de fichero DEM. Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Reemplazados datos de altitud con valores interpolados. (M=%1, RMSErr=%2) Offset elevation data by %1%2. altitud desplazada %1%2. Changed start of track to %1. Cambiado el inicio de track a %1. Remove timestamps. Eliminadas las marcas de tiempo. Set artificial timestamps with delta of %1 sec. Marcas de tiempo ficticias con incremento de %1 sec. Changed speed to %1%2. Velocidad modificada a %1%2. %1 (Segment %2) %1 (Segmento %2) Removed extension %1 from all Track Points Eliminada extensión %1 a todos los puntos del track Converted subpoints from routing to track points Convertidos puntos secundarios del ruteo a puntos de track Copy flag information from QLandkarte GT track Copiar información del encabezado del track de QLandkarte GT CGisItemWpt Archived Archivado Available Disponible Not Available No Disponible _Clone Duplicar Elevation: %1%2 Altitud: %1%2 Proximity: %1%2 Proximidad: %1%2 Changed name Se cambió el nombre Changed position Se cambió la posición Changed elevation Se cambió la altitud Removed proximity Eliminada proximidad Changed proximity Se cambió la proximidad Changed icon Se cambió el icono Changed comment Se cambió el comentario Changed description Se cambió la descripción Changed links Se cambió el enlace Changed images Se cambió la imagen Add image Añadir Imagen Changed to proximity-radius Cambiado a radio de proximidad Changed to nogo-area Cambiado a área prohibida CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Debido a cambios en el sistema de base de datos QMapShack olvidó el nombre de archivo de su base de datos '%1'. Debe seleccionarlo de nuevo en el siguiente paso. Select database file. Seleccionar archivo de base de datos. Add Database Añadir Base de Datos Add Folder Añadir carpeta Rename Folder Renombrar carpeta Copy Folder Copiar carpeta Move Folder Mover carpeta Delete Folder Eliminar Carpeta Import from Files... Importar desde archivos.. Export to GPX... Exportar a GPX... Delete Item Eliminar Elemento Search Database Buscar base de datos Sync. with Database Sincronizar con base de datos Remove Database Quitar Base de Datos Empty Vacío Remove database... Quitar Base de Datos... Do you really want to remove '%1' from the list? ¿Seguro que quiere eliminar '%1' de la lista? Are you sure you want to delete selected folders and all subfolders from the database? ¿Está seguro que quiere borrar las carpetas seleccionadas y sus subcarpetas de la base de datos? Bad operation.... Mala operación... The target folder is a subfolder of the one to move. This will not work. La carpeta de destino es una subcarpeta de la que se va a mover. Esto no funcionará. Folder name... Nombre de carpeta... Rename folder: Renombrar carpeta: Are you sure you want to delete '%1' from folder '%2'? ¿Desea realmente eliminar '%1' de la carpeta '%2'? Delete... Borrar... Import GIS Data... Importar datos GIS... Delete database folder... Eliminar Carpeta de la Base de Datos... Remove items... Eliminar elementos... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. ¿Desea realmente eliminar todos los elementos de 'Objetos Perdidos'? Se eliminarán definitivamente. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. ¿Desea realmente eliminar todos los elementos.seleccionados de 'Objetos Perdidos'? Se eliminarán definitivamente. CGisListWks Save Guardar Edit.. Editar.. Close Cerrar Update Project on Device Actualizar Proyecto en Dispositivo Edit... Editar... Copy to... Copiar a... Autom. Save Guardado Automático Save as... Guardar como... Copy Track with Waypoints Copiar tracks y waypoints Show Bubble Mostrar burbuja de texto Move Waypoint Mover Waypoint Proj. Waypoint... Proyectar Waypoint... Change Radius Cambiar radio Toggle Nogo-Area Herramienta área prohibida Delete Radius Borrar Radio Route Instructions Instrucciones de ruta Calculate Route Calcular ruta Reset Route Recalcular ruta Edit Route Editar ruta Convert to Track Convertir en track Create Route Crear ruta Change Icon (sel. waypt. only) Cambiar icono Set Track Activity Establecer actividad del track Drop items... Descartar elementos <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Actualizar dispositivos</b><p>Actualizar %1<br/>Por favor espere...</p> Delete project... Eliminar Proyecto... Do you really want to delete %1? ¿Desea realmente eliminar %1? Track Profile Perfil del Track Show on Map Mostrar en el mapa Hide from Map Ocultar en el mapa Sort by Time Ordenar por fecha Sort by Name Ordenar por nombre Save as GPX 1.1 w/o ext... Guardar como GPX 1.1 w/o ext... Send to Devices Enviar a dispositivo Sync. with Database Sincronizar con base de datos Select Range Seleccionar Rango Edit Track Points Editar Puntos del Track Reverse Track Invertir Track Combine Tracks Combinar Tracks Edit Area Points Editar Puntos del Área Delete Borrar Saving workspace. Please wait. Guardando espacio de trabajo. Por favor espere. Loading workspace. Please wait. Cargando espacio de trabajo. Por favor espere. Close all projects... Cerrar todos los proyectos... This will remove all projects from the workspace. Esto eliminará todos los proyectos del espacio de trabajo. CGisWorkspace Load project... Cargar proyecto The project "%1" is already in the workspace. El proyecto "%1" ya está en el area de trabajo. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Selección de elementos: </b>Elemento seleccionado de la lista del espacio de trabajo. Haga clic en el mapa para volver al comportamiento normal de selección del mouse. Copy items... Copia elementos.... Change waypoint symbols. Cambiar símbolos de waypoint Cut Track... Dividir Track... Do you want to delete the original track? ¿Desea borrar el track original? CGpxProject Failed to load file %1... Fallo al cargar archivo %1... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Not a GPX file: %1 No es un archivo GPX: %1 File exists ... El archivo ya existe ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> El archivo ya existe y no lo ha creado QMapShack. Si pulsa 'sí' todos los datos de este archivo se perderán. Incluso si el archivo contiene datos GPX y QMapShack lo ha leído, QMapShack podría no ser capaz de leer y almacenar todos los elementos en el archivo, y aquellos que no haya leído se perderán. Se le recomienda usar otro archivo distinto. <b>¿Quiere realmente sobrescribir el archivo</b> Failed to create file '%1' Fallo al crear el archivo '%1' Failed to write file '%1' Fallo al escribir en el archivo '%1' Saving GIS data failed... Fallo guardando datos GIS... CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1m, %2m N %1m, E %2m N %1m, E %2m CHistoryListWidget by %1 de %1 Cut history before Cortar historial antes Cut history after Cortar historial despues History removal Borrar historial The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> El borrado es permanente y no se puede deshacer. <b>¿Esta seguro de querer borrar el historial anterior a este paso?</b> CImportDatabase Import QLandkarte Database Importar Base de Datos de QLandKarteGT Select source database... Seleccionar origen de base de datos... Select target database... Seleecionar destino de base de datos... CKnownExtension Speed extLongName Velocidad Cadence extShortName Cadencia Air Temp. extShortName Temp. Aire Air Temperature extLongName Temperatura del Aire Water Temp. extShortName Temp. Agua Water Temperature extLongName Temperatura del Agua Depth extShortName Profundidad Depth extLongName Profundidad Heart R. extShortName R. Cardiaco Heart Rate extLongName Ritmo Cardiaco Cadence extLongName Cadencia Speed extShortName Velocidad Accel. extShortName Acl. Acceleration extLongName Aceleración Course extShortName Carrera Course extLongName Carrera Temp. extShortName Temp. Temperature extLongName Temperatura Dist. extShortName Dist. Distance extLongName Distancia Ele. extShortName Alt. Elevation extLongName Altitud Energy extShortName Energía Energy extLongName Energía Sea Lev. Pres. extShortName Pres. N. Mar Sea Level Pressure extLongName Presión a Nivel del Mar v. Speed extShortName Vel. Vcal. Vertical Speed extLongName Velocidad Vertical Slope extShortName Pendiente Speed over Distance* extLongName Velocidad sobre la distancia * Speed over Time* extLongName Velocidad sobre el Tiempo* Elevation* extLongName Altitud* Progress extShortName Progreso Progress* extLongName Progreso* Terr. Slope extShortName Pendiente Terr Terrain Slope* extLongName Pendiente del Terreno* Slope* Pendiente* CLogProject Failed to load file %1... Fallo al cargar archivo %1... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Not an Openambit log file: %1 %1 no es un archivo log de Openambit Device: %1<br/> Dispositivo: %1<br/> Recovery time: %1 h<br/> Tiempo de recuperación: %1 h<br/> Peak Training Effect: %1<br/> Efecto Pico de Entrenamiento: %1<br/> Energy: %1 kCal<br/> Energía: %1 kCal<br/> Use of local time... Uso de la hora local ... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. No se ha encontrado hora UTC en el archivo %1. Se usará la hora local del ordenador. Puede ajustar la hora usando un filtro de tiempo si es necesario. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 Este archivo LOG no contiene datos de posición que puedan ser mostrados por QMapShack: %1 CLostFoundProject Lost & Found Objetos Perdidos CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Usar <b>Menu->ver->Añadir vista de mapa</b> para abrir nueva vista, o <b>Menu->archivo->cargar vista de mapa</b> para restaurar una vista guardada. O click <a href='nueva vista'>aquí</a>. Ele.: %1%2 Altitud: %1%2 Slope: %1%2 terrain Pendiente: %1%2 [Grid: %1] [Malla: %1] Load GIS Data... Cargar Datos GIS... Select output file Seleccionar archivo de salida QMapShack View (*.view) Vista de QMapShack (*.view) Select file to load Seleccionar archivo a cargar Fatal... Fatal... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack detectó una biblioteca Proj4 mal instalada. Las tablas de traducción para las proyecciones EPSG usualmente almacenadas en /usr/share/proj faltan. Póngase en contacto con el responsable del paquete de su distribución para solucionarlo. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. No hay mapas en este momento. QMapShack no es divertido sin mapas. Puede instalar mapas al presionar la tecla Ayuda! ¡Quiero mapas! En el botón ' mapas ',o puede presionar la tecla F1 para abrir la documentación en línea que le indica cómo usar QMapShack. Si no es divertido, ¿por qué no proporciona mapas? Bueno para alojar mapas listos para descargar e instalar requiere un buen servidor. Y esto no es un servicio gratuito. El proyecto carece de dinero. Además, los datos de mapa y DEM tienen un copyright. Por lo tanto, el titular de los derechos de autor tiene que ser preguntado antes de empaquetar los datos. Esto no es tan fácil como podría sonar y para algunos datos que tiene que pagar royalties. El proyecto simplemente carece de recursos para hacer esto. Y pensamos que instalar las cosas por ti mismo no es mucho pedir de ti. Después de todo el software se distribuye sin una cuota. CMapIMG Failed ... Falló ... Unspecified No especificado French Francés German Alemán Dutch Holandés English Inglés Italian Italiano Finnish Finés Swedish Sueco Spanish Español Basque Euskera Catalan Catalán Galician Gallego Welsh Galés Gaelic Gaélico Danish Danés Norwegian Noruego Portuguese Portugués Slovak Eslovaco Czech Checo Croatian Croata Hungarian Húngaro Polish Polaco Turkish Turco Greek Griego Slovenian Esloveno Russian Ruso Estonian Estonio Latvian Letón Romanian Rumano Albanian Albanés Bosnian Bosnio Lithuanian Lituano Serbian Serbio Macedonian Macedonio Bulgarian Búlgaro Major highway Autovía Primaria Principal highway Autovía secundaria Other highway Otras autovías Arterial road Carretera principal Collector road Carretera secundaria Residential street Calle residencial Alley/Private road Callejón/Carretera privada Highway ramp, low speed Acceso a autopista, baja velocidad Highway ramp, high speed Acceso a autopista, alta velocidad Unpaved road Carretera sin asfaltar Major highway connector Conexión con autovía principal Roundabout Rotonda Railroad Ferrocarril Shoreline Línea de costa Trail Sendero Stream Arroyo Time zone Zona horaria Ferry Ferry State/province border Frontera de estado/provincia County/parish border Frontera de condado/término municipal International border Frontera internacional River Río Minor land contour Curva de nivel menor Intermediate land contour Curva de nivel intermedia Major land contour Curva de nivel principal Minor depth contour Curva batimétrica menor Intermediate depth contour Curva batimétrica intermedia Major depth contour Curva batimétrica principal Intermittent stream Curso intermitente Airport runway Pista de aterrizaje Pipeline Tubería Powerline Línea eléctrica Marine boundary Límite marítimo Hazard boundary Límite de peligro Large urban area (&gt;200K) Área urbana grande (&gt;200K) Small urban area (&lt;200K) Área urbana pequeña (&lt;200K) Rural housing area Área de alojamienos rurales Military base Base militar Parking lot Aparcamiento Parking garage Garaje Airport Aeropuerto Shopping center Centro comercial Marina Puerto deportivo University/College Universidad/Facultad Hospital Hospital Industrial complex Complejo industrial Reservation Reserva natural Man-made area Área creada por el hombre Sports complex Complejo deportivo Golf course Campo de golf Cemetery Cementerio National park Parque nacional City park Parque urbano State park Parque regional Forest Bosque Ocean Océano Blue (unknown) Azul (desconocido) Sea Mar Large lake Lago grande Medium lake Lago mediano Small lake Lago pequeño Major lake Lago principal Major River Río Principal Large River Río Grande Medium River Río Mediano Small River Río Pequeño Intermittent water Agua intermitente Wetland/Swamp Marisma/Ciénaga Glacier Glaciar Orchard/Plantation Invernadero/Plantación Scrub Monte bajo Tundra Tundra Flat Llanura ??? Read external type file... Cargar archivo TYP externo... Failed to read type file: %1 Fall back to internal types. Fallo al cargar archivo TYP: %1 Se vuelve al TYP interno. Failed to read: Fallo al leer: Failed to open: Fallo al abrir: Bad file format: Formato de archivo incorrecto: Failed to read file structure: Fallo al leer la estructura del archivo: Loading %1 Cargando %1 User abort: Cancelado por el usuario: File is NT format. QMapShack is unable to read map files with NT format: El archivo está en formato NT. QMapShack no puede leer archivos en formato NT: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. El archivo contiene datos bloqueados y/o encriptados. Garmin no desea que utilice este archivo con ningún otro software que el suministrado por ellos. Point of Interest Punto de Interés Unknown Desconocido Area Área CMapList Deactivate Desactivar Activate Activar Where do you want to store maps? ¿Dónde desea almacenar mapas? CMapMAP Failed ... Falló... Failed to open: Fallo al abrir: Bad file format: Formato de archivo incorrecto: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Añada o elimine rutas que contengan mapas. Puede haber múltiples mapas en una ruta, pero no se buscará en subdirectorios. Los formatos soportados son: %1 Select map path... Selecciona la ruta del mapa... Select root path... Seleccionar carpeta raiz... CMapPropSetup Select type file... Seleccionar archivo TYP... CMapRMAP Error... Error... This is not a TwoNav RMAP file. Éste no es un archivo en formato RMAP de TwoNav. Unknown sub-format. Sub-formato desconocido. Unknown version. Versión desconocida. Failed to read reference point. Fallo al leer el punto de referencia. Unknown projection and datum (%1%2). Proyección y datum desconocidos (%1%2). CMapTMS Error... Error... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Layer %1 Capa %1 CMapVRT Error... Error... Failed to load file: %1 Fallo al leer el archivo: %1 File must be 8 bit palette or gray indexed. El archivo debe ser con paleta de 8 bits o escala de grises indexada. No georeference information found. No se encontró información de georreferenciación. CMapVrtBuilder Build GDAL VRT Crear GDAL VRT Select files... Seleccionar ficheros de origen... Select target file... Seleccionar fichero VRT de salida... !!! done !!! ¡¡¡ hecho !!! CMapWMTS Error... Error... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Failed to read: %1 Unknown structure. Fallo al leer: %1 Estructura desconocida. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Servicio inesperado. '* WMTS 1.0.0' es el esperado. pero se ha leido '%1 %2'. No georeference information found. No se encontró información de georreferenciación. CMouseEditArea Area Área <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Editar área</b><br/>Seleccione una función y un modo de dibujo a través de los botones de herramientas. A continuación, seleccione un punto del trazado. Sólo se pueden cambiar los puntos marcados con un cuadrado grande. Los puntitos negros son puntos secundarios introducidos automáticamente por el enrutamiento automático o el ajuste vectorial.<br/> area área CMouseEditRte Route Ruta <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> </b>Editar puntos de ruta<br/>Seleccione una función y un modo de dibujo a través de los botones de herramientas. A continuación, seleccione un punto del trazado. Sólo se pueden cambiar los puntos marcados con un cuadrado grande. Los puntitos negros son puntos secundarios introducidos automáticamente por el enrutamiento automático o el ajuste vectorial.<br/> route Ruta CMouseEditTrk Track Track <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Editar puntos del track</b><br/>Seleccione una función y un modo de dibujo a través de los botones de herramientas. A continuación, seleccione un punto del trazado. Sólo se pueden cambiar los puntos marcados con un cuadrado grande. Los puntitos negros son puntos secundarios introducidos automáticamente por el enrutamiento automático o el ajuste vectorial.<br/> Warning! ¡Cuidado! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Esto sustituirá todos los datos del original con una simple línea de coordenadas. Todos los demás datos se perderán definitivamente. track track CMouseNormal Add POI as Waypoint Añadir POI como Waypoint Add Waypoint Añadir Waypoint Add Track Añadir Track Add Route Añadir ruta Add Area Añadir Área Select Items On Map Seleccionar elementos del mapa Copy position Copiar posición Copy position (Grid) Copiar posicion (malla) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Guardar/imprimir mapa</b><br/>Seleccione un area rectangular en el mapa pulsando el boton izquierdo del ratón y moviendolo hacia la esquina opuesta. Cancele con el boton derecho. Ajuste la seleccion haciendo clic y moviendo las esquinas. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Seleccionar rango</b><br/>Seleccione el punto inicial con el botón izquierdo del raton. Fije el punto final con una segunda pulsacion. El rango seleccionado se marca en verde. Un clic con el botón derecho del ratón abandona la selección del rango<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Seleccionar elementos en el mapa</b><br/>Seleccione un area rectangular con el boton izquierdo del ratón. Cancelar con clic derecho. Ajuste la seleccion haciendo clic y desplazando en las esquinas. <b>Selected:</b><br/> <b>Seleccionado:</b><br/> %1 waypoints<br/> %1 waypoints<br/> %1 tracks<br/> %1 tracks<br/> %1 routes<br/> %1 rutas<br/> %1 areas<br/> %1 áreas<br/> CPhotoAlbum Select images... Seleccionar imagenes... CPlot Distance [%1] Distancia [%1] Time Tiempo CPlotProfile Distance [%1] Distancia [%1] Ele. [%1] Alt. [%1] CPrintDialog Print Map... Imprimir mapa... Save Map as Image... Guardar mapa como imagen... Printer Properties... Imprimir propiedades... Pages: %1 x %2 Páginas: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Zoom con la rueda del ratón en el mapa inferior para cambiar la resolución: %1x%2 pixel x: %3 m/px y: %4 m/px Printing pages. Imprimir páginas. Save map... Guardar mapa... CProgressDialog Elapsed time: %1 Tiempo transcurrido: %1 Elapsed time: %1 seconds. Tiempo transcurrido: %1 segundos. CProjWizard north norte south sur Error... Error... The value '%1' is not a valid coordinate system definition: %2 El valor '%1' no es una definición de sistema de coordenadas válido: %2 CProjWpt Edit name... Editar nombre... Enter new waypoint name. Introduzca el nuevo nombre del waypoint. CQlbProject Failed to open... Fallo al abrir... Failed to open %1 Fallo al abrir %1 Could not convert... No se pudo convertir ... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. El archivo contiene superposiciones que no se pueden convertir. Esto se debe a que QMapShack no es compatible con todos los tipos de superposición de QLandkarte. CQlgtDb Migrating database from version 4 to 5. Convirtiendo base de datos de version 4 a 5. Migrating database from version 5 to 6. Convirtiendo base de datos de version 5 a 6. Migrating database from version 6 to 7. Convirtiendo base de datos de version 6 a 7. Migrating database from version 7 to 8. Convirtiendo base de datos de version 7 a 8. Migrating database from version 8 to 9. Convirtiendo base de datos de version 8 a 9. Open database: %1 Abrir base de datos:%1 Folders: %1 Carpetas: %1 Tracks: %1 Tracks: %1 Routes: %1 (Only the basic route will be copied) Rutas: %1 (Sólo se copiará la ruta básica) Waypoints: %1 Waypoints: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Superposiciones: %1 (las áreas se convertirán como áreas, las líneas de distancia se convertirán en tracks, todos los demás elementos de superposición se perderán Diaries: %1 Diarios: %1 Map selections: %1 (can't be converted to QMapShack) Selecciones de mapa: %1 (NO pueden convertirse a QMapShack) ------ Start to convert database to %1------ ------ Comenzar a convertir base de datos a %1------ Failed to create target database. Fallo al crear la base de datos de destino. ------ Abort ------ ------ Cancelar ------ ------ Done ------ ------ Hecho ------ Restore folders... Restaurar carpetas... Imported %1 folders and %2 diaries Importadas %1 carpetas y %2 diarios Copy items... Copia elementos.... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Importado: %1 tracks, %2 waypoints, %3 routes, %4 areas Import folders... Importar carpetas... Overlay of type '%1' cant be converted No puede convertirse superposición del tipo '%1' CQlgtTrack Corrupt track ... Track corrupto... Number of trackpoints is not equal the number of training data trackpoints. El número de puntos del track no es igual al número de puntos de datos de entrenamiento. Number of trackpoints is not equal the number of extended data trackpoints. El número de puntos de track no es igual al número de datos extendidos Number of trackpoints is not equal the number of shadow data trackpoints. El número de puntos del track no es igual al número de datos extendidos ocultos. CQmsDb Existing file... Archivo existente... Remove existing %1? ¿Eliminar los %1? Remove existing file %1 Eliminar el archivo %1 %1: drop item with QLGT DB ID %2 Descartar elemento %2 de la base de datos de QLandKarteGT CQmsProject Failed to open... Fallo al abrir... Failed to open %1 Fallo al abrir %1 CRouterBRouter original original first alternative Primera alternativa second alternative Segunda alternativa third alternative Tercera alternativa BRouter (offline) BRouter (offline) BRouter (online) BRouter (online) profile: %1, alternative: %2 perfil: %1, alternativa: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade BRouter no admite más de un área prohibida en esta versión, considere actualizar response is empty La respuesta está vacía Bad response from server: %1 Mala respuesta del servidor: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... <b>BRouter</b><br/>Solicitud de enrutamiento enviada al servidor. por favor espere... Calculate route with %1 Calcular ruta con %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <b>BRouter</b><br/>Mala respuesta del servidor:<br/>%1 <br/>Calculation time: %1s Tiempo empleado en el cálculo: %1s Error Error running En marcha starting comenzando QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. QMapShack se comunica con BRouter a través de una conexión de red. Por lo general, esto se hace en una dirección especial que no se puede alcanzar desde fuera de su dispositivo. Sin embargo BRouter escucha las conexiones en todas las interfaces disponibles. Si usted está en su propia red privada con un cortafuegos activo, esto no es un gran problema. Si usted está en una red pública cada puerto abierto es un riesgo, ya que puede ser utilizado por otra persona para comprometer su sistema. No recomendamos utilizar el servicio local de BRouter en este caso. Warning... Aviso... I understand the risk. Don't tell me again. Comprendo el riesgo. No avisar de nuevo stopped Parado not installed No instalado online online CRouterBRouterSetup %1 not accessible %1 no accessible %1 invalid result %1 resultado inválido Error parsing online-config: Error al analizar configuración online: Network error: Error de red CRouterBRouterSetupWizard Restore Default Values Restablecer valores por defecto Open Directory Abrir carpeta select Java Executable Seleccionar ejecutable Java please select BRouter installation directory Seleccione carpeta de instalacion de BRouter selected directory does not exist La carpeta seleccionada no existe create directory and install BRouter there Cree una carpeta e instale BRouter allí existing BRouter installation Instalacion de BRouter exixtente update existing BRouter installation Actualizar instalación de BRouter empty directory, create new BRouter installation here Carpeta vacia, instale BRouter aquí create new BRouter installation Crear nueva instalacion de BRouter seems to be a valid Java-executable Parece ser un ejecutable Java válido doesn't seem to be a valid Java-executable no parece un ejecutable Java válido Java Executable not found Ejecutable Java no encontrado Error loading installation-page at %1 Error al cargar la página de instalación en %1 no brouter-version to install selected Ninguna versión de BRouter para instalar seleccionada selected %1 for download and installation Seleccione %1 para descargar e instalar Warning... Aviso... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. Descarga:%1<br/><br/> Esto descargará e instalará un archivo zip desde una ubicación de descarga que no está protegida por ningún estándar, usando HTTP normal. Normalmente esto debe ser HTTPS. El riesgo es que alguien redireccione la solicitud y le envíe un código postal de reemplazo con malware. No es posible que QMapShack lo detecte. <br/> Si no entiende esto o si tiene alguna duda, no proceda y cancele. Utilice la versión web de BRouter en su lugar. I understand the risk and wish to proceed. Entiendo el riesgo, continuar. download %1 started Iniciada descarga %1 Network Error: %1 Error de red: %1 download %1 finished Finalizada descarga %1 unzipping: Descomprimiendo: ready. Preparado download of brouter failed: %1 Descarga de BRouter fallida: %1 retrieving available profiles from %1 Recuperar los perfiles disponibles de %1 content of profile Contenido del perfil Error: Error creating directory %1 Error creando la carpeta %1 Error directory %1 does not exist Error: La carpeta %1 no existe Error creating file %1 Error creando archivo %1 Error writing to file %1 Error escribiendo el archivo %1 CRouterBRouterTilesPage Continue with Setup Continuar con la configuración CRouterBRouterTilesSelect available routing-data is being determined. Se están determinando los datos de enrutamiento disponibles. Select outdated Selección caducada Clear Selection Borrar selección Delete selection Borrar Selección Download Descargar Error creating segments directory %1 Error al crear la carpeta de segmentos cannot parse: %1 is not a date No se puede analizar: %1 no es una fecha cannot parse: %1 is not a valid size No se puede analizar: %1 No es un tamaño válido Error retrieving available routing data from %1: %2 Error al recuperar los datos de enrutamiento disponibles de %1: %2 segments directory does not exist: Carpeta de segmentos no existe: error creating file %1: %2 Error creando archivo %1: %2 no valid request for filename %1 %1 : Solicitud no válida de nombre de archivo no open file assigned to request for %1 Ningún archivo abierto asignado a la solicitud de %1 error writing to file %1: %2 Error al escribir el archivo %1: %2 error renaming file %1 to %2: %3 Error renombrando archivo %1 a %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) actualizado: %1 (%2), obsoleto: %3 (%4), Para descargar: %5 (%6) being downloaded: %1 of %2 Descargando: %1 of %2 no local data, online available: %1 (%2) Sin datos locales, disponible online: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Datos locales obsoletos (%1, %2 - remoto%3, %4) Error removing %1: %2 Error eliminando %1: %2 Network Error Error de red invalid result, no files found Resultado no válido, no se encuentran archivos local data up to date (%1, %2) Datos locales actualizados (%1, %2) no routing-data available Datos de ruteo no disponibles CRouterBRouterToolShell !!! done !!! ¡¡¡Hecho!!! !!! failed !!! !!! fallo !!! CRouterMapQuest Fastest Más rapido Shortest Más corto Bicycle Bicicleta Pedestrian Peatón US English Inglés USA British English Inglés UK Danish Danés Dutch Holandés French Francés German Alemán Italian Italiano Norwegian Noruego Spanish Español Swedish Sueco mode "%1" modo "%1" no highways Evitar autopistas no toll roads Evitar peajes no seasonal Evitar estacionales no unpaved Evitar no pavimentadas no ferry Evitar Ferrys no crossing of country borders No cruzar fronteras <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Solicitud de ruta enviada al servidor. Por favor,espere... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Mala respuesta del servidor:<br/>%1 <br/>Calculation time: %1s Tiempo calculando: %1s CRouterRoutino Foot A pie Horse A caballo Wheelchair Silla de ruedas Bicycle Bicicleta Moped Ciclomotor Motorcycle Moto Motorcar Automóvil Goods Mercancias Shortest El más corto Found Routino with a wrong version. Expected %1 found %2 Routino se encuentra en una versión incorrecta. Esperado %1 encontrado %2 Quickest El más rápido English Inglés German Alemán French Francés Hungarian Húngaro Dutch Holandés Russian Ruso Polish Polaco A function was called without the database variable set. Se llamó una función sin la variable de base de datos establecida. A function was called without the profile variable set. Se llamó una función sin la variable de perfil establecida. A function was called without the translation variable set. Se llamó una función sin el conjunto de variables de traducción The specified database to load did not exist. La base de datos especificada no existe The specified database could not be loaded. No se pudo cargar la base de datos especificada The specified profiles XML file did not exist. El archivo XML de perfiles no existe The specified profiles XML file could not be loaded. El archivo XML de perfiles especificado no está cargado The specified translations XML file did not exist. El archivo XML de traducción especificado no existe The specified translations XML file could not be loaded. El archivo XML de traducción especificado no está cargado The requested profile name does not exist in the loaded XML file. El nombre del perfil solicitado no existe en el archivo XML cargado The requested translation language does not exist in the loaded XML file. El idioma solicitado no existe en el archivo XML cargado The profile and database do not work together. El perfil y la base de datos no funcionan juntos The profile being used has not been validated. El perfil que se utiliza no ha sido validado The user specified profile contained invalid data. El perfil especificado por el usuario contenía datos no válidos The routing options specified are not consistent with each other. Las opciones de enrutamiento especificadas no son coherentes entre sí There is a mismatch between the library and caller API version. Hay un desajuste entre la biblioteca y la versión de la API del llamante Route calculation was aborted by user. El cálculo de la ruta ha sido cancelado por el usuario A route could not be found to waypoint %1. No se pudo encontrar una ruta al waypoint %1 Unknown error: %1 Error desconocido: %1 profile "%1" perfil "%1" , mode "%1" , modo "%1" Warning... Aviso... In the routing database there is no highway near the coordinates to place a waypoint. En la base de datos de enrutamiento no hay ninguna carretera cerca de las coordenadas para colocar un waypoint. Calculate route with %1 Calcular ruta con %1 <br/>Calculation time: %1s <br/>Tiempo de cálculo: %1s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Agregar o quitar carpetas que contienen datos de Routino. Puede haber varias bases de datos en una carpeta, pero no se analiza ninguna subcarpeta. Select routing data file path... Seleccione la carpeta del archivo de datos de enrutamiento CRouterSetup Routino (offline) Routino (offline) MapQuest (online) MapQuest (online) BRouter (online) BRouter (online) CRoutinoDatabaseBuilder Create Routino Database Crear base de datos de Routino Select files... Seleccionar ficheros de origen... Select target path... Seleccionar carpeta de destino... !!! done !!! ¡¡¡Hecho!!! CScrOptRangeTrk No range selected No hay rango seleccionado CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Modo exacto</b><br/>Todos los elementos seleccionados estan completamente dentro del área.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> Modo de intersección</b><br/>Todos los elementos seleccionados deben estar dentro o al menos intersecar el área seleccionada.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Agregar tracks</b><br/>Agregar tracks a la lista de elementos seleccionados<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Agregar waypoints</b><br/>Agregar waypoints a la lista de elementos seleccionados<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Agregar rutas</b><br/>Agregar rutas a la lista de elementos seleccionados <br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Agregar áreas</b><br/>Agregar áreas a la lista de elementos seleccionados<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Ignorar tracks</b><br/>Ignorar tracks de la lista de elementos seleccionados<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Ignorar Waypoints</b><br/>Ignorar waypoints de la lista de elementos seleccionados<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Ignorar rutas</b><br/>Ignorar rutas en la lista de elementos seleccionados<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> Ignorar áreas</b><br/>Ignorar áreas de la lista de elementos seleccionados<br/> CSearchDatabase Search database '%1': Buscar base de datos '%1': CSearchGoogle Unknown response Respuesta desconocida Error: Error: CSetupDatabase Missing Requirement Falta un requisito MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. SQL no se puede utilizar en este momento, ya que el controlador correspondiente (QMYSQL) no está disponible.<br />Asegúrese de haber instalado el paquete correspondiente.<br />Si usted no sabe qué hacer ahora debe <a href="%1">consultar la wiki</a>. Error... Error... There is already a database with name '%1' Ya existe una base de datos con el nombre '%1' New database... Nueva base de datos... Open database... Abrir base de datos... CSetupWorkspace Setup database... Configurar la base de datos... Changes will become active after an application's restart. Los cambios surtirán efecto tras reiniciar la aplicación. CSlfProject Failed to load file %1... Fallo al cargar el archivo %1... CSlfReader Failed to parse timestamp `%1` Error al analizar la marca de tiempo %1 %1 does not exist %1 no existe Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Not a SLF file: %1 %1 no es un archivo SLF Unsupported revision %1: %2 Revisión no admitida %1: %2 Break %1 Pausa %1 Lap %1 Vuelta %1 CSmlProject Failed to load file %1... Fallo al cargar archivo %1... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Not an sml file: %1 No es un archivo sml: %1 Recovery time: %1 h<br/> Tiempo de recuperación: %1 h<br/> Peak Training Effect: %1<br/> Efecto Pico de Entrenamiento: %1<br/> Energy: %1 kCal<br/> Energy: %1 kCal<br/> Device: %1<br/> Device: %1<br/> Battery usage: %1 %/hour Uso de la Batería: %1 %/hour Use of local time... Uso de hora loccal No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. No se ha encontrado hora UTC en el archivo %1. Se usará la hora local del ordenador. Puede ajustar hora usando un filtro de tiempo si es necesario. This SML file does not contain any position data and can not be displayed by QMapShack: %1 Este archivo SML no contiene ningún dato de posición y QMapShack no puede mostrarlo: %1 CTableTrk Double click to edit elevation value Doble clic para editar datos de altitud %1%2 %1%2 CTcxProject Failed to load file %1... Fallo al cargar el archivo %1... Failed to open %1 Fallo al abrir %1 Failed to read: %1 line %2, column %3: %4 Fallo al leer: %1 línea %2, columna %3. %4 Not a TCX file: %1 %1 no es un archivo TCX This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Este archivo TCX contiene al menos un entrenamiento, pero ninguna actividad ni carrera. Como los entrenamientos no contienen datos de posición, no se pueden importar a QMapShack This TCX file does not contain any activity or course: %1 El archivo TCX %1 no contiene ninguna actividad ni carrera File exists ... El archivo ya existe ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> El archivo existe y no ha sido creado por QMapShack. Si pulsa 'yes' Se perderán todos los datos de este archivo. Incluso si este archivo contiene datos y ha sido cargado por QMapShack, QMapShack puede no ser capaz de cargar y almacenar todos los elementos de este archivo. Estos elementos se perderán. Se recomienda usar otro archivo. <b>¿Realmente desea sobrescribir el archivo?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> El track <b>%1</b> Que ha seleccionado contiene puntos y marcas de tiempo no válidas. Es posible que el dispositivo no acepte el archivo de curso TCX generado si se deja como está <b>¿Desea aplicar un filtro con velocidad constante (10 m / s) y continuar?</b> Course Carrera Activity Actividad Cancel Cancelar Track with invalid timestamps... Track con marcas de tiempo inválidas. Activity or course? ¿Actividad o carrera? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack no sabe cómo <b>%1</b> Debe ser guardado. <b>¿Desea guardarlo como carrera o como actividad? </b>Recuerde que sólo se guardarán waypoints lo suficientemente cerca del track al guardar como carrera. Los waypoints no se guardarán al guardar como actividad. Failed to create file '%1' Fallo al crear el archivo '%1' Failed to write file '%1' Fallo al escribir en el archivo '%1' Saving GIS data failed... Error al guardar datos GIS CTemplateWidget choose one... elige una... Hiking Tour Summary (built-in) Datos de la actividad (genérico) - - Template path... Ruta de las Plantillas... Failed to read template file %1. Fallo al leer la plantilla %1. Preview... Previsualizar... CTextEditWidget &Color... &Color... Reset format Restablecer formato CToolBarSetupDialog Available Actions Acciones disponibles Selected Actions Acciones seleccionadas CTwoNavProject Error... Error... Failed to open %1. Fallo al abrir %1. Save GIS data to... Guardar los datos GIS en... Only support lon/lat WGS 84 format. Solamente soporta formato lon/lat WGS84. Failed to read data. Fallo al leer los datos. CWptIconDialog Path to user icons... Carpeta de iconos de usuario... Form Form Ficha Participants Participantes Weather Meteo rain lluvia sunny sol snow nieve clouds nubes windy viento hot caluroso warm templado cold frío freezing bajo cero foggy niebla humid humedad Character Carácter easy hiking Excursión fácil climbing escalada alpine Actividad alpina large ascend gran desnivel long distance larga distancia via ferrata ferrata hail/soft hail granizo Rating Calificación Rating 5 stars ***** Excepcional Rating 4 stars **** Muy buena Rating 3 stars *** Buena Rating 2 stars ** Regular Rating 1 star * Mala aborted Intento frustrado Equipment Material ferrata gear ferrata night gear iluminación snow shoes raquetas climbing gear escalada ski ski camping gear acampada / vivac Details Detalles IAbout About.... Acerca de... <b>QMapShack</b>, Version <b>QMapShack</b>, Versión TextLabel Denominación Qt Qt GDAL GDAL Proj4 Proj4 Routino Czech: checo: German: Alemán: Oliver Eichler Dutch: holandés: French: Francés: Rainer Unseld Russian: Ruso: Wolfgang Thämelt © 2017 Oliver Eichler (oliver.eichler@gmx.de) Pavel Fric <b>Translation:</b> <b>Traducción:</b> Harrie Klomp Spanish: Español: Win64: OS X: <b>Binaries:</b> <b>Binarios:</b> <b>Contributors:</b> <b>Colaboradores:</b> Jose Luis Domingo Lopez Jose Luis Domingo, Javi Segovia Ivo Kronenberg Helmut Schmidt ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ... y gracias a todos los mantenedores de Linux por hacer un gran trabajo. Agradecimientos especiales a Dan Horák y Bas Couwenberg por estar presentes en la lista de correo para discutir temas relacionados con la distribución Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Este software esta bajo licencia GPL3 o posterior ICanvasSetup Setup Map View... Configurar Vista de Mapa... Projection & Datum Proyección y Datum ... ... Scales Escalas Logarithmic Logarítmica Square (optimized for TMS and WMTS tiles) Cuadrada (optimizada para teselas TMS y WMTS) IColorChooser Dialog Diálogo ICombineTrk Combine Tracks... Combinar Tracks... Available Tracks Tracks disponibles ... ... Combined Tracks Tracks combinados ICoordFormatSetup Coordinate Format... Formato de coordenadas... N48° 53.660 E013° 31.113 N48° 53.660 E013° 31.113 N48.8943° E013.51855° N48.8943° E013.51855° N48° 53' 39.6" E13° 31' 6.78" N48° 53' 39.6" E13° 31' 6.78" ICreateRouteFromWpt Create Route from Waypoints Crear una ruta con los waypoints ... ... ICutTrk Cut Track Dividir track Delete first part of the track and keep second one Borrar primera parte del track y conservar la segunda Keep both parts of the track Mantener ambas partes del track Keep first part of the track and delete second one Conservar primera parte del track y borrar la segunda Cut Mode: Modo de división Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Compruebe esto para almacenar el resultado en un nuevo track. Si mantiene ambas partes del track, tiene que crear otros nuevos. Si desea mantener sólo una mitad puede simplemente eliminar los puntos, o marcar esto para crear un nuevo track Create a new track Crear nuevo track IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. El formato interno de base de datos de '%1' ha cambiado. QMapShack hará la conversión de tu base de datos ahora.Después de esta conversión la nueva base de datos no puede utilizarse en versiones más antiguas de QMapShack. Se recomienda hacer una copia de seguridad antes de comenzar. Migrate database... Migrar base de datos. Migration aborted by user Migracion cancelada por el usuario Failed to migrate '%1'. Fallo al migrar '%1'. Error... Error... Migration failed La migración falló The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. La versión de base de datos '%1' Está más avanzado que el entendido por su instalación de QMapShack. Esto no funcionará. Initialization failed Inicializacion fallida Wrong database version... Versión errónea de la base de datos Database created by newer version of QMapShack Base de datos creada por la nueva versión de QMapShack Failed to initialize '%1'. Fallo al iniciar '%1'. IDBMysql Password... Contraseña... Password for database '%1': Contraseña de la base de datos '%1': Update to database version 5. Migrate all GIS items. Actualizar a versión 5 de base de datos. Migrar todos los elementos GIS. IDBSqlite Update to database version 3. Migrate all GIS items. Actualizar base de datos a versión 3. Migrar todos los elementos GIS Update to database version 5. Migrate all GIS items. Actualizar base de datos a versión 5. Migrar todos los elementos GIS Update to database version 6. Migrate all GIS items. Actualizar base de datos a versión 6. Migrar todos los elementos GIS IDemPathSetup Setup DEM file paths Configurar carpeta de archivos DEM ... ... - - IDemPropSetup Form ficha <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Cambiar la opacidad del mapa</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Pulse para usar la escala actual como la escala mínima a la que mostrar el mapa.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Controle el rango de escalas para las cuales desea que se muestre el mapa. Use los dos botones a izquierda y derecha para definir la escala actual como la escala mínima o máxima para el mapa.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Pulse para usar la escala actual como la escala máxima a la que mostrar el mapa</p></body></html> Hillshading Sombreado Slope Pendiente ° º > TextLabel Denominación IDemsList Form To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Para añadir archivos con datos de altitud <b>File->configure rutas de DEM</b>. O clic <a href='setup'><b>aqui</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Use el menú contextual (botón derecho del ratón y seleccione) para activar un archivo. Use arrastrar y soltar para mover el archivo activado en el orden de procesamiento. Activate Activar Move Up Subir Hide DEM behind previous one Ocultar DEM detrás del anterior Move down Bajar Show DEM on top of next one Mostrar DEM encima del siguiente Reload DEM Recargar DEM's IDetailsGeoCache Dialog Diálogo - - about:blank about:blank Position: Posición: Difficulty Dificultad Terrain Terreno Update spoilers Actualizar spoilers ... ... Hint: Consejo: TextLabel Denominación IDetailsOvlArea Dialog Diálogo The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. El área se importó a QMapShack y se cambió. Ya no muestra los datos originales. Consulte el historial de cambios Toggle read only mode. You have to open the lock to edit the item. Cambia el modo de sólo lectura. Debe abrir el bloqueo para editar el elemento. ... ... Color Color Border width Ancho del borde Style Estilo Opacity Opacidad Info Información Points Puntos Position Posición Hist. Historial IDetailsPrj Form - - Print diary Imprimir diario ... ... Keep order of project Mantenga el orden del proyecto Sort along track (multiple) Ordenar a lo largo del track (múltiples) Sort along track (single) Ordenar a lo largo del track (único) Rebuild diary. Recargar diario. Keywords: Etiquetas: IDetailsRte Info Información The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. La ruta se importó a QMapShack y se cambió. Ya no muestra los datos originales. Consulte el historial de cambios. - - Toggle read only mode. You have to open the lock to edit the item. Cambia el modo de sólo lectura. Debe abrir el bloqueo para editar el elemento. ... ... Hist. Historial IDetailsTrk Form - - - - Use/edit user defined visibility of arrows for this track Utilizar / editar la visibilidad definida por el usuario de las flechas de este track Use/edit system's visibility of arrows for all tracks Utilizar / editar la visibilidad definida por el usuario de las flechas de todos los track Use/edit user defined scale factor for this track Utilizar / editar el factor de escala de este track Use/edit system's default factor for all tracks Utilice / edite el factor predeterminado del sistema para todas los tracks max. max. min. min. Profile Perfil User defined limits for this track Límites definidos por el usuario para este track Automatic limits Límites automáticos User defined limits for all tracks Límites definidos por el usuario para todos los track Speed Velocidad Toggle read only mode. You have to open the lock to edit the item. Cambia el modo de sólo lectura. Debe abrir el bloqueo para editar el elemento. ... ... Style Estilo Source Atributo Maximum Máximo Minimum Mínimo x x - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. El track se ha importado a QMapShack y se ha editado. No muestra los datos originales. Consulte el historial de cambios. Width Anchura with arrows Con flechas Color Color Graphs Gráficos Activity Actividad Set Track Activity Establecer actividad del track To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Para diferenciar las estadísticas seleccione una actividad de la lista para todo el track,o bien, seleccione una parte para asignar una actividad. Points Puntos Time Hora Ele. Altitud. Delta Delta Dist. Distancia Slope Pendiente Position Posición Info Información - - Ascent Ascenso Descent Descenso Filter Filtro Hist. Historial IDetailsWpt Dialog Diálogo The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. El waypoint se importó a QMapShack y se cambió. Ya no muestra los datos originales. Consulte el historial de cambios. Toggle read only mode. You have to open the lock to edit the item. Cambia el modo de sólo lectura. Debe abrir el bloqueo para editar el elemento. ... ... Position: Posición: Info Información - - Ele. Altitud. Proximity: Proximidad: Hist. Historial Add images. Añadir imagenes. Delete selected image. Eliminar imagen seleccionada. Date/Time: Fecha/Hora: IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Hay otro proyecto con el mismo nombre. Si pulsa 'ok'será eliminado y reemplazado. IElevationDialog Edit elevation... Editar altitud... Elevation Altitud - - Get elevation from active digital elevation model. Obtener la altitud desde el DEM activo. ... ... IExportDatabase Export database to GPX... Exportar base de datos a GPX ... ... Export Path: Carpeta de exportación - - GPX 1.1 without extensions GPX 1.1 sin extensiones Start Comenzar Abort Cancelar Close Cerrar IFilterDelete Form <b>Remove Track Points</b> <b>Eliminar puntos del Track</b> Remove all hidden track points permanently. Eliminar todos los puntos ocultos del track definitivamente. ... ... IFilterDeleteExtension Form <b>Remove Extension from all Track Points</b> <b>Eliminar extensión para todos los puntos del track</b> Remove Eliminar from all Track Points de todos los puntos del track ... ... IFilterDouglasPeuker Form <b>Hide Points (Douglas Peuker)</b> <b>Ocultar Puntos (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Ocultar puntos del track si la distancia entre puntos vecinos en linea recta es menor que m m Apply filter now. Aplicar filtro ahora. ... ... IFilterInterpolateElevation Form <b>Interpolate Elevation Data</b> <b>Interpolar datos de altitud</b> Replace elevation of track points with interpolated data. Sustituir la altitud de los puntos del track con datos interpolados. Quality Calidad Preview Vista previa ... ... IFilterInvalid Form Hide Invalid Points Ocultar puntos inválidos Hide points with invalid data. Ocultar puntos con datos no válidos. ... ... IFilterMedian Form <b>Smooth Profile (Median Method)</b> <b>Suavizar Perfil (Mediana)</b> Smooth deviation of the track points elevation with a Median filter of size Suavizar el desvio de la altitud de los puntos del track con la Mediana de points puntos ... ... IFilterNewDate Form <b>Change Time</b> <b>Cambiar Fecha/hora</b> Change start of track to Modificar el inicio del track a dd.MM.yy HH:mm:ss dd.MM.yy HH:mm:ss - - ... ... IFilterObscureDate Form <b>Obscure Timestamps</b> <b>Ocultar Marcas de tiempo</b> Increase timestamp by Incrementar marcas de tiempo en sec. with each track point. 0 sec. will remove timestamps. con cada punto del track. ( 0 sec. eliminará las marcas de tiempo). ... ... IFilterOffsetElevation Form <b>Offset Elevation</b> <b>Desplazar altitud</b> Add offset of Añadir corrección de to track points elevation. a la altitud de los puntos del track. ... ... IFilterReplaceElevation Form <b>Replace Elevation Data</b> <b>Reemplazar Datos de altitud</b> Replace elevation of track points with the values from loaded DEM files. Reemplazar altitud de los puntos del track utilizando los valores del fichero DEM cargado. ... ... IFilterReset Form <b>Reset Hidden Track Points</b> <b>Restaurar Puntos Ocultos del Track</b> Make all trackpoints visible again. Hacer visibles de nuevo todos los puntos del track. ... ... IFilterSpeed Form <b>Change Speed</b> <b>Modificar Velocidad</b> Set speed to Ajustar velocidad a km/h km/h ... ... IFilterSplitSegment Form <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Dividir el track en segmentos</span></p></body></html> Creates a new track for every segment within this track. Crear un nuevo track por cada segmento de este track. ... ... IFilterSubPt2Pt Form <b>Convert track subpoints to points</b> <b>Convertir subpuntos de track en puntos</b> Convert subpoints obtained from routing to ordinary track points Conviertir subpuntos obtenidos por el enrutamiento a puntos de track ordinarios ... ... IFilterTerrainSlope Form <b>Calculate Terrain Slope</b> <b>Calcular pendiente del terreno</b> Calculate slope of the terrain based on loaded DEM files. Calcular pendiente del terreno en base a los DEM cargados. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. Error decodificando FIT: El decodificador no está en el estado correcto %1 después del último byte de datos en el archivo. FIT decoding error: a development field with the field_definition_number %1 already exists. Error decodificando FIT: Ya existe un campo con el número de definición %1. IGisDatabase Form Name Nombre Age Edad To add a database do a right click on the database list above. Para añadir una base de datos haga click-derecho en el espacio superior. IGisItem [no name] [sin nombre] The item is not part of the project in the database. El elemento no forma parte del proyecto en la base de datos. It is either a new item or it has been deleted in the database by someone else. Es un elemento nuevo o ha sido eliminado en la base de datos por otra persona The item is not in the database. El elemento no está en la base de datos The item might need to be saved Es posible que deba guardar el elemento Initial version. Versión inicial Never ask again. No volver a preguntar <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3> Posiblemente este elemento es de sólo lectura porque no lo creó QMapShack. Por lo general no es conveniente cambiar los datos importados, pero si piensa que esta bien, presione 'Ok'. Read Only Mode... Modo Sólo Lectura... <h4>Description:</h4> <h4>Descripción:</h4> <p>--- no description ---</p> <p>---sin descripción---</p> <h4>Comment:</h4> <h4>Comentario:</h4> <p>--- no comment ---</p> <p>--- Sin comentario ---</p> <h4>Links:</h4> <h4>Enlaces:</h4> <p>--- no links ---</p> <p>--- sin enlaces ---</p> Edit name... Editar nombre... Enter new %1 name. Introducir nuevo nombre de %1 IGisProject Save project? ¿Guardar proyecto? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>Ha habido cambios en el proyecto. ¿Guardar antes de cerrar? %1: Correlate tracks and waypoints. %1: Correlacionar tracks y waypoints <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>¿Desea omitir la correlación de pistas y waypoints para este proyecto en el futuro? Canceled correlation... Correlación cancelada Save "%1" to... Guardar "%1" como... <br/> Filename: %1 <br/> Nombre de archivo %1 Waypoints: %1 Waypoints: %1 Tracks: %1 Tracks: %1 Routes: %1 Rutas: %1 Areas: %1 Áreas: %1 Are you sure you want to delete '%1' from project '%2'? ¿Desea realmente eliminar '%1' del proyecto '%2'? Delete... Borrar... IGisWorkspace Form Opacity Opacidad Change the opacity of all GIS Items on the map. Cambiar opacidad para todos los elementos GIS del mapa Filter Filtro Name Nombre Clear Filter Borrar filtro Setup Filter Configurar filtro IGridSetup Setup Grid... Configurar Malla... Projection Proyección restore default restaurar valores predeterminados ... ... Get projection from current map. Obtener la proyección desde el mapa actual. projection wizzard asistente de proyección Grid color Color de la malla setup grid color Configurar el color de la malla IImportDatabase Form Source Database: Origen de Base de datos: - - ... ... Target Database: Destino de Base de Datos: Start Comenzar IInputDialog Edit... Editar... TextLabel Denominación ILineOp Routing Enrutamiento ILinksDialog Links... Enlaces... Type Tipo Text Texto Uri Uri ... ... IMainWindow QMapShack QMapShack File Archivo View Ver Window Ventana ? ? Tool Herramientas Maps Mapas Dig. Elev. Model (DEM) la traducción literal "Modelo Digital del Terreno " es demasiado larga para el titulo de las pestaña, y hace que se oculten otras pestañas. Por ello se ha sustituido por su abreviatura "MDT" de uso frecuente, y también empleada por el IGN MDT (DEM) Toolbar Barra de herramientas Routing Enrutamiento Add Map View Añadir Vista de Mapa Ctrl+T Ctrl+T Show Scale Mostrar Escala Setup Map Font Configurar Fuente del Mapa Show Grid Mostrar Malla Ctrl+G Ctrl+G Setup Grid Configurar Malla Ctrl+Alt+G Ctrl+Alt+G Flip Mouse Wheel Invertir la Rueda del Ratón Setup Map Paths Configurar Rutas de Mapas POI Text Texto del POI Night / Day Noche / Día Map Tool Tip Mostrar descripción emergente en los Mapas Ctrl+I Ctrl+I Setup DEM Paths Configurar Rutas a los DEM About Acerca de Help Ayuda F1 F1 Setup Map View Configurar Vista de Mapa VRT Builder Asistente VRT GUI front end to gdalbuildvrt GUI front end para gdalbuildvrt Store Map View Guardar vista de mapa Write current active map and DEM list including the properties to a file Guardar en un archivo el mapa activo actual y la lista de DEM's incluyendo sus propiedades Load Map View Cargar vista de mapa Restore view with active map and DEM list including the properties from a file Restaurar vista de mapa activo y lista de DEM's incluyendo sus propiedades desde un archivo Ext. Profile Perfil en ventana externa Ctrl+E Ctrl+E Close Cerrar Ctrl+Q Ctrl+Q Clone Map View Duplicar vista de mapa Ctrl+Shift+T Ctrl+Shift+T Create Routino Database Crear base de datos de Routino Save(Print) Map Screenshot Guardar/Imprimir captura de pantalla de mapa Print a selected area of the map Imprimir area seleccionada del mapa Ctrl+P Ctrl+P Setup Coord. Format Configurar formato de coordenadas Change the format coordinates are displayed Cambiar el formato de coordenadas que se muestran Setup Map Background Configuración del Mapa de Fondo Setup Waypoint Icons Configurar Iconos de Waypoint Setup path to custom icons Configurar ruta de iconos personalizados Close Tab Cerrar pestaña Ctrl+W Ctrl+W Quickstart Help Guia de inicio rápido Setup Toolbar Configurar barra de herramientas Toggle Docks Panel de herramientas Toggle visibility of dockable windows Ver panel de herramientas Ctrl+D Ctrl+D Full Screen Pantalla Completa F11 F11 Min./Max. Track Values Valores Máx/min del track Show the minimum and maximum values of the track properties along the track in the map view. En la vista del mapa mostrar superpuestos los valores máximo y mínimo de los datos del track Ctrl+N Database Base de datos Workspace Espacio de trabajo Load GIS Data Cargar Datos GIS Load projects from file Cargar proyectos desde archivo Ctrl+L Ctrl+L Save All GIS Data Guardar todos los Datos GIS Save all projects in the workspace Guardar todos los proyectos del espacio de trabajo Ctrl+S Ctrl+S Setup Time Zone Configurar Zona Horaria Add empty project Añadir proyecto vacío Search Google Buscar en Google Close all projects Cerrar todos los proyectos F8 F8 Setup Units Configurar Unidades Setup Workspace Configurar Espacio de trabajo Setup save on exit. Guardar configuración al salir. Import Database from QLandkarte Importar base de datos de Qlandkarte Import QLandkarte GT database Importar base de datos de QLandKarteGT IMapList Form To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Para añadir mapas haga<b>Archivo->Configurar rutas de mapas</b>. O haga clic <a href='setup'><b>aqui</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Use el menú contextual (botón derecho del ratón, y seleccione) para activar un mapa. Use arrastrar y soltar para mover el mapa activado en el orden de dibujado. Help! I want maps! I don't want to read the documentation! Quiero mapas No quiero leer la documentación! Activate Activar Move Up Subir Hide map behind previous map Ocultar mapa detrás del anterior Move down Bajar Show map on top of next map Mostrar mapa encima del siguiente Reload Maps Recargar mapas IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Este mapa requiere soporte de OpenSSL. Sin embargo, debido a restricciones legales en algunos países, OpenSSL no se incluye con QMapShack. Puede consultar la página < a href = < https: //www.openssl.org/community/binaries.html '> OpenSSL Homepage</a> Para binarios. Tienes que copiar libeay32.dll y ssleay32.dll en el directorio del programa QMapShack. Error... Error... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 teselas pendientes<br/> IMapPathSetup Setup map paths Configurar rutas de mapas Root path of tile cache for online maps: Carpeta para la caché de mapas online ... ... Help! I want maps! I don't want to read the documentation! ¡Quiero mapas! ¡No quiero ver la documentación! - - IMapPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Cambiar la opacidad del mapa</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Pulse para usar la escala actual como la escala mínima a la que mostrar el mapa.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Controle el rango de escalas para las cuales desea que se muestre el mapa. Use los dos botones a izquierda y derecha para definir la escala actual como bien la escala mínima o máxima para el mapa.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Pulse para usar la escala actual como la escala máxima a la que mostrar el mapa.</p></body></html> Areas Áreas Lines Líneas Points Puntos Details Detalle - - Cache Path Carpeta Caché Type File: Archivo TYP: Forget external type file and use internal types. Olvidar TYP externo y utilizar el interno. Load an external type file. Cargar un archivo TYP externo. Cache Size (MB) Tamaño de Caché (MiB) Expiration (Days) Caducidad (Días) IMapVrtBuilder Form Advanced Options Opciones Avanzadas Source No Data (-srcnodata) No Data origen (-srcnodata) Target No Data (-vrtnodata) No Data salida (-vrtnodata) Target Projection (-a_srs) Proyección/Datum (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. Estas opciones son para casos particulares y normalmente se dejan en blanco. Consulta la <a href='http://www.gdal.org/gdalbuildvrt.html'>ayuda</a> de GDAL para más información. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> <ol> <li>Seleccione uno o varios archivos.</li> <li>Seleccione un nombre de archivo para el archivo VRT de destino.</li> <li>Pulse botón</li>"Comenzar". </ol> Consejos: <ul> <li>Si tiene varios archivos, colóquelos en una subcarpeta de su carpeta de mapas. Cree el archivo VRT en su carpeta de mapas</li> <li>Utilice las opciones avanzadas para añadir un valor de "sin datos" si sus archivos de origen no lo tiene y no forman un área rectangular. Las áreas sin mapa se volverán transparentes.</li> <li>La opción "-a_srs" está destinada a asignar una Proyección / Datum cuando el archivo de origen no lo tiene. Esto NO reproyecta los datos.</li> </ul> ... ... Select source files: Seleccionar ficheros de origen: Target Filename: Fichero VRT de salida: - - Start Comenzar IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Nuevo trazado</b><br/>Mueva el ratón y pulse el botón izquierdo para crear puntos. Puede alternar el modo de dibujo con los botones de herraminetas (O,A,V) sin interrumpir el trazado. Para terminar pulse botón derecho del ratón.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Borrar punto</b><br/>Mueva el ratón hasta un punto y pulse el botón izquierdo para eliminarlo.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Seleccionar Rango de Puntos</b><br/>Seleccione el punto inicial con el botón izquierdo del raton. Fije el punto final con una segunda pulsacion y elija entre las opciones. El rango seleccionado se marca en verde. Utilice el botón derecho del ratón para cancelar.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Mover punto</b><br/>Seleccione el punto con el botón izquierdo del raton y arrastrelo hasta la nueva posición. Suelte el punto con una segunda pulsacion. Utilice el botón derecho del ratón para cancelar.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Añadir punto</b><br/>Mueva el ratón cerca de una línea y presione el botón izquierdo para agregar un punto. El punto se pegará al cursor y se puede mover.Suelte el punto en la posición deseada con una segunda pulsacion. Utilice el botón derecho del ratón para cancelar..<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Sin enrutamiento ni ajuste vectorial</b><br/>Todos los puntos se conectarán con una línea recta.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Enrutamiento automático</b><br/>El trazado entre los puntos se calcula automáticamente atendiendo a la configuración actual del enrutador. <b>Nota:</b> El enrutador seleccionado debe ser capaz de trabajar al vuelo,por lo general, solo son capaces de hacerlo los instalados localmente.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Ajuste vectorial</b><br/> El trazado se dibuja ajustandose automáticamente a las lineas de un mapa vectorial.<br/> <b>%1 Metrics</b> <b>Datos %1 </b> Distance: Distancia: Ascent: Ascenso: Descent: Descenso: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> <br/><b>Mover el mapa</b><br/>Mantega pulsado el botón izquierdo mientras mueve el ratón y moverá el mapa.<br/><br/> IPhotoAlbum Form ... ... IPlot Reset Zoom Restablecer zoom Stop Range Rango de parada Save... Guardar... Add Waypoint Añadir Waypoint Cut... Cortar. Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Pulse tecla CTRL para zoom vertical unicamente. Pulse tecla ALT para zoom horizontal unicamente No or bad data. Datos incorrectos o inexistentes. Select output file Seleccione archivo de salida IPositionDialog Position ... Posición ... Enter new position Introduzca la nueva posición Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Formato de posición incorrecto. Debe ser: "[N|S] ggg mm.sss [W|E] ggg mm.sss" o "[N|S] ggg.ggg [W|E] ggg.ggg" IPrintDialog Print map... Imprimir mapa... When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. Al imprimir mapas en línea asegúrese de que se haya cargado previamente en la memoria caché el mapa correspondiente a la extensión que desea imprimir. Save Guardar When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. Al guardar mapas en línea asegúrese de que el mapa se ha cargado en la memoria caché en la medida en la que desea guardarlo. TextLabel Denominación Print Imprimir IProgressDialog Please wait... Por favor,espere... TextLabel Denominación IProjWizard Proj4 Wizzard Asistente de Proj4 Mercator Mercator UTM UTM zone zona user defined definido por el usuario Datum Datum World Mercator (OSM) World Mercator (OSM) Result: Resultado: UPS North (North Pole) UPS Norte (Polo Norte) UPS South (South Pole) UPS Sur (Polo Sur) Projection Proyección IProjWpt Waypoint Projection Proyección del Waypoint ... ... - - Clone waypoint and move by: Duplicar el waypoint y moverlo: m m ° º IRouterBRouter Form Profile Perfil Alternative Alternativa display selected routing profile Mostrar el perfil de enrutamiento seleccionado ... ... on-the-fly routing Enrutamiento al vuelo BRouter: BRouter: not running Parado start/stop BRouter iniciar/parar Brouter show BRouter console Mostrar consola de BRouter Setup Configuración Caution! BRouter is listening on all ports for connections. ¡Precaución! BRouter está escuchando en todos los puertos para las conexiones. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Direcciones de <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> <p>Enrutamiento de <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a></p> IRouterBRouterInfo BRouter Profile Perfil de BRouter TextLabel Denominación IRouterBRouterSetupWizard BRouter Setup Configuración de BRouter choose which BRouter to use Elija que BRouter usar BRouter-Web (online) BRouter-Web (online) local Installation Instalación local Expert Mode Modo experto local BRouter Installation directory: Carpeta de instalación de BRouter local: select installation directory Seleccionar carpeta de instalación ... ... labelLocalDirResult create or update installation Crear o actualizar instalacion Java Executable Ejecutable Java labelLocalJavaResult search for installed java Buscando Java instalado Download and install BRouter Version Descargar e instalar BRouter about:blank about:blank File to install Archivo para instalar Download and Install Descargar e instalar available Profiles Perfiles disponibles install profile Instalar perfil remove profile Eliminar perfil installed Profiles Perfiles instalados content of profile Contenido del perfil BRouter-Web URL: BRouter-Web URL: Service-URL Servicio-URL Profile-URL Perfil-URL Hostname Nombre de Host Port Puerto Profile directory Carpeta de perfiles Segments directory Carpeta de segmentos Custom Profiles dir Carpeta de perfiles personalizados Max Runtime Tiempo máximo de ejecución Number Threads Número de hilos Java Options Opciones de Java Profiles Url URL de perfiles IRouterMapQuest Form Highways Autopistas Seasonal Estacional Language Lenguaje Country Border Fronteras Profile Perfil Avoid: Evitar: Ferry Ferry Toll Road Carreteras de peaje Unpaved Sin pavimentar <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Direcciones cortesía de <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Profile Perfil Mode Modo Database Base de datos Add paths with Routino database. Añadir carpeta con base de datos de Routino. ... ... Language Lenguaje To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Para utilizar el enrutamiento sin conexión es necesario definir rutas de acceso a los datos de enrutamiento locales. Utilice el botón de la herramienta de configuración para indicar una carpeta. Puede crear sus propios datos de enrutamiento con la <b>herramienta->Crear base de datos de Routino</b>. IRouterRoutinoPathSetup Setup Routino database... Configurar base de datos de Routino... ... ... - - IRouterSetup Form IRoutinoDatabaseBuilder Form ... ... Select source files: Seleccionar ficheros de origen: Start Comenzar Target Path: Carpeta de destino: - - File Prefix Prefijo del archivo <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> <p>Para crear una base de atos de Routino se necesita descargar archivos *.pbf de <a href='http://download.geofabrik.de/'>GeoFabrik</a>. El proceso de creación de una base de datos Routino es bastante lento y los archivos resultantes son bastante grandes. Por lo tanto, se recomienda no descargar continentes completos. Limite su descarga a los países que realmente necesita. Sin embargo, como Routino puede crear una ruta usando varias bases de datos, debe incluir todos los países por los que pase la ruta.</p> <ol> <li>Seleccione uno o varios archivos *.pbf.</li> <li>Seleccione la carpeta para su base de datos de Routino.</li> <li>Seleccione un prefijo. La base de datos será listada por este prefijo.</li> <li>Presione botón </li>"Comenzar". </ol> IScrOptEditLine Form Save to original Guardar al original Save as new Guardar como nuevo... Abort Cancelar Move points. (Ctrl+M) Mover puntos. (Ctrl+M) Ctrl+M Ctrl+M Add new points. (Ctrl++) Añadir puntos. (Ctrl++) Ctrl++ Ctrl++ Select a range of points. (Ctrl+R) Seleccionar rango de puntos. (Ctrl+R) Ctrl+R Ctrl+R No auto-routing or line snapping (Ctrl+O) Dibuja libremente. Sin enrutamiento automático ni ajuste vectorial (Ctrl + O) Ctrl+O Ctrl+O Use auto-routing to between points. (Ctrl+A) Dibuja usando el enrutamiento automático entre puntos. (Ctrl+A) Ctrl+A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Dibuja ajustandose a las lineas de un mapa vectorial. (Ctrl+V) ... ... Delete a point. (Ctrl+-) Borrar un punto. (Ctrl+-) Ctrl+- Ctrl+- 0 0 A A V V Ctrl+V Ctrl+V Undo last change Deshacer Redo last change Rehacer IScrOptOvlArea Form View details and edit. Ver detalles y editar. ... ... Copy area into another project. Copiar área en otro proyecto. Delete area from project. Eliminar área de este proyecto Edit shape of the area. Editar el contorno del área. TextLabel Denominación IScrOptPrint Form Save selected area as image. Guardar el área seleccionada como imagen. ... ... Print selected area. Imprimir área seleccionada. IScrOptRangeLine Form Delete all points between the first and last one. Borre todos los puntos entre el primero y el último. ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Calcular una ruta entre el primero y el último punto seleccionado.</p></body></html> IScrOptRangeTrk Form Hide all points. Ocultar todos los puntos. ... ... Show all points. Mostrar todos los puntos. Set an activity for the selected range. Asigna una Actividad para el rango seleccionado. Copy track points as new track. Copiar los puntos del track como un nuevo track. TextLabel Denominación IScrOptRte Form ... ... Copy route into another project. Copiar ruta en otro proyecto. View details and edit. Ver detalles y editar. Delete route from project. Borrar ruta del proyecto. Calculate route. Calcular ruta. Reset route calculation. Reiniciar cálculo de ruta. Move route points. Mover puntos de ruta. Convert route to track Convertir ruta en track TextLabel Denominación IScrOptSelect Form Copy all selected items to a project. Copiar todos los elementos seleccionados a un proyecto. ... ... Create a route from selected waypoints. Crear ruta con los waypoints seleccionados. Change the icon of all selected waypoints. Cambiar el icono a los waypoints seleccionados. Combine all selected tracks to a new one. Combinar todos los tracks seleccionadas en uno nuevo. Set an activity for all selected tracks. Asigna una Actividad para todos los tracks seleccionados. Delete all selected items. Borrar los elementos seleccionados. Select all items that intersect the selected area. Seleccione los elementos que interseccionan el área seleccionada. Select all items that are completely inside the selected area. Seleccione los elementos que estan dentro del area seleccionada. Add tracks to selection. Añadir tracks a la selección. Add waypoints to selection. Añadir waypoints a la selección. Add routes to selection. Añadir rutas a selección. Add areas to selection. Añadir áreas a la selección. IScrOptTrk Form Show on-screen profile and detailed information about points. Mostrar el perfil en pantalla e información detallada de los puntos. Edit position of track points. Editar la posición de los puntos del track. View details and edit properties of track. Ver detalles y editar propiedades del track. ... ... Copy track into another project. Copiar track en otro proyecto. Delete track from project. Eliminar track del proyecto. Select a range of points. Seleccionar un rango de puntos. Reverse track. Invertir track. Combine tracks. Combinar tracks. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Dividir el track por el punto seleccionado. Puede usar esto para: * Eliminar puntos erróneos del principio o del final * Utilizar partes del track al planificar un nuevo recorrido * Dividir un track muy largo en varias etapas Set an activity for the complete track. Asigna una Actividad al track completo. Copy track together with all attached waypoints into another project. Copiar track junto con todos los waypoints conectados en otro proyecto. TextLabel Denominación IScrOptWpt Form View details and edit. Ver detalles y editar. ... ... Copy waypoint into another project. Copiar waypoint en otro proyecto. Delete waypoint from project. Eliminar waypoint del proyecto. Show content as static bubble. Mostrar contenido en globo de texto. Move waypoint to a new location. Mover el waypoint a una nueva ubicación. Clone waypoint and move clone a given distance and angle. Duplicar el waypoint y mover la copia a una distancia y un ángulo dados. edit radius of circular area editar radio de área circular Switch between proximity and nogo-area Cambiar entre proximidad y área prohibida Delete circle defined by waypoint Eliminar círculo definido por waypoint TextLabel Denominación IScrOptWptRadius Form edit radius of circular area editar radio de área circular ... ... Switch between proximity and nogo-area Cambiar entre proximidad y área prohibida Delete circle defined by waypoint Borrar circulo definido por waypoint TextLabel Denominación ISearchDatabase Search... Buscar... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Escriba la palabra que desea buscar y pulse botón de busqueda. Si introduce la 'palabra' entre apóstrofes se busca una coincidencia exacta . Si introduce 'palabra*', la 'palabra' se busca al principio de una cadena. Name Nombre Search Buscar Close Cerrar ISelDevices Select devices... Seleccionar dispositivos... ISelectActivityColor Form ISelectCopyAction Copy item... Copiar elemento... Replace existing item Sustituir el elemento existente TextLabel Denominación Do not copy item No copiar el elemento Create a clone Crear un duplicado Replace with: Sustituir por: Keep item: Mantener: The clone's name will be appended with '_Clone' Se añadirá el sufijo '_Clone' al nombre del duplicado And for all other items, too. Hacer igual para todos los elementos. ISelectDBFolder Select Parent Folder... Seleccione la carpeta principal... Name Nombre ISelectDoubleListWidget Form Available Disponible Add to selected items Añadir a los elementos seleccionados Remove from selected items Eliminar de los elementos seleccionados Selected Seleccionado Move selected items up Mover los elementos seleccionados arriba Move selected items down Mover los elementos seleccionados abajo ... ... ISelectProjectDialog Select a project... Seleccionar un proyecto... Select project from list or enter new project name. Seleccione un proyecto de la lista, o introduzca un nuevo nombre de proyecto. New project's name Nombre del nuevo proyecto New project is created as: El nuevo proyecto se creará como: *.qms *.qms *.gpx *.gpx Database Base de datos ISelectSaveAction Copy item... Copiar elemento... Replace existing item Sustituir el elemento existente Add a clone Añadir duplicado The clone's name will be appended with '_Clone' Se añadirá el sufijo '_Clone' al nombre del duplicado Replace with: Sustituir por: TextLabel Denominación Do not replace item No sustituir elemento Use item: Utilizar elemento: And for all other items, too. Hacer igual para todos los elementos. ISetupDatabase Add database... Añadir Base de Datos... - - Name Nombre <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Precaución</span> Se recomienda dejar la contraseña en blanco, ya que QMapShack lo almacenará como texto sin formato. Si no introduce una contraseña, se le pedirá en cada inicio.</p> Do not use a password. No usar contraseña. SQLite SQLite MySQL MySQL Server Servidor Port Puerto 00000 00000 User Usuario Password Contraseña <b>Port:</b> Leave the port field empty to use the default port. <b>Puerto:</b> Dejar vacio para usar el puerto predeterminado. File: Archivo: Add new database. Añadir nueva base de datos. ... ... Open existing database. Abrir base de datos existente. ISetupFilter Form Apply filter to Aplicar filtro a name only Solo nombre complete text Texto completo ISetupFolder Database Folder... Carpeta de base de datos Folder name Nombre de la carpeta Group Grupo Project Proyecto Other Otros ISetupNewWpt New Waypoint... Nuevo waypoint. Symbol Símbolo ... ... Position Posición Name Nombre Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Formato de posición incorrecto. Debe ser: "[N|S] ggg mm.sss [W|E] ggg mm.sss" o "[N|S] ggg.ggg [W|E] ggg.ggg" ISetupWorkspace Setup workspace... Configurar espacio de trabajo... save workspace on exit, and every guardar el espacio de trabajo al salir, y cada minutes minutos listen for database changes from other instances of QMapShack. On port Escuchar los cambios en la base de datos de otras instancias de QMapShack en puerto 00000 00000 ITemplateWidget Insert Template... Insertar plantilla... Templates Plantillas Select a path with your own templates. Selecciona una ruta con tus propias plantillas ... ... Preview Vista previa ITextEditWidget Edit text... Editar texto... Undo Deshacer Ctrl+Z Ctrl+Z Redo Rehacer Ctrl+Shift+Z Ctrl+Shift+Z Cut Cortar Ctrl+X Ctrl+X Copy Copiar Ctrl+C Ctrl+C Paste Pegar Templ. Plantilla. A:L A:L A:C A:C A:R A:R A:B A:B B B I I U U C C Standard Standard Bullet List (Disc) Lista de viñetas (Disco) Bullet List (Circle) Lista de viñetas (círculos) Bullet List (Square) Lista de viñetas(cuadrados) Ordered List (Decimal) Lista ordenada(decimal) Ordered List (Alpha lower) Lista ordenada (alfabético descendente) Ordered List (Alpha upper) Lista ordenada (alfabético ascendente) Ordered List (Roman lower) Lista ordenada (números romanos descendente) Ordered List (Roman upper) Lista ordenada (números romanos ascendente) Ctrl+V Ctrl+V Align Left Alinear a la Izquierda Ctrl+L Ctrl+L Align Right Alinear a la Derecha Ctrl+R Ctrl+R Align Center Alinear al Centro Ctrl+E Ctrl+E Align Block Alinear Bloque Ctrl+J Ctrl+J Underline Subrayar Ctrl+U Ctrl+U Bold Negrita Ctrl+B Ctrl+B Italic Cursiva Ctrl+I Ctrl+I Plain Plano Reset the text's format before pasting Restablecer el formato del texto antes del pegado Select All Seleccionar todo Ctrl+A Ctrl+A Delete Borrar Reset Font Restablecer fuente Reset Layout Restablecer diseño Normal Normal Paste without resetting the text's format Pegar sin restablecer el formato del texto Insert From Template Insertar desde plantilla Create text from template. Crear texto desde plantilla. ITextEditWidgetSelMenu B B I I U U Cut Cortar Copy Copiar Paste Pegar ITimeZoneSetup Setup Time Zone ... Configurar la Zona Horaria. UTC UTC Local Local Automatic Automático Print date/time in Imprimir fecha y hora en long format, or Formato largo, o short format formato corto <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Nota:</b> Para algunos elementos de la interfaz de usuario, cambiar las unidades no tendrá efecto hasta que se reinicie QMapShack. IToolBarSetupDialog Setup Toolbar Configuración de barra de herramientas Toolbar is visible in Fullscreen-mode Barra de herramientas visible en modo Pantalla Completa IToolShell Execution of external program `%1` failed: La ejecución del programa externo %1 falló: Process cannot be started. No se puede iniciar el proceso. Make sure the required packages are installed, `%1` exists and is executable. Asegúrese de que los paquetes necesarios estén instalados, `%1` existe y es ejecutable External process crashed. El proceso externo falló. An unknown error occurred. A ocurrido un error desconocido !!! failed !!! !!!falló!!! IUnit Error Error Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Formato de coordenadas incorrecto. Debe ser: "[N|S] ggg mm.sss [W|E] ggg mm.sss" o "[N|S] ggg.ggg [W|E] ggg.ggg" Position values out of bounds. Valores de posición fuera del límite. IUnitsSetup Setup units... Configurar unidades... Length unit Unidad de longitud Metric Métrico Slope unit ">Unidad de pendiente Degrees (°) Grados (°) Percent (%) Porcentaje (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Nota:</b> Para algunos elementos de la interfaz de usuario, cambiar las unidades no tendrá efecto hasta que se reinicie QMapShack. Imperial Imperial Nautic Naútico IWptIconDialog Icons... Iconos. External Icons: Iconos: - - ... ... All custom icons have to be *.bmp or *.png format. Los iconos personalizados deben de ser BMP o PNG qmapshack-1.10.0/src/locale/qmapshack_ru.ts000644 001750 000144 00001637614 13216417310 022016 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API версия %2, ожидаемая версия: %3) %1 (API V%2) %1 (API версия %2) (no DBUS: device detection and handling disabled) (Нет DBUS: обнаружение и управление устройств отключено) CActivityTrk Foot Пешком Bicycle Велосипед Motor Bike Мотоцикл Car Автомобиль Cable Car Фуникулер Swim Плавание Ship Корабль Ski/Winter Лыжи/зима No Activity Нет мероприятия Total Всего Ascent: Подъем: Descent: Спуск: Aeronautics Аэронавтика Public Transport Общественный транспорт Distance: Расстояние: Speed Moving: Скорость движения: Speed Total: Общая скорость: Time Moving: Время движения: Time Total: Общее время: CCanvas View %1 Вид %1 Setup Map Background Настройка фона карт CColorChooser Esc. Esc. CCommandProcessor Print debug output to console. Печатать отладочный вывод на консолью. Print debug output to logfile (temp. path). Печатать отладочную информацию в файл журнала (путь Temp). Do not show splash screen. Не показывать экран-заставку. File with QMapShack configuration. Файл с конфигурацией QMapShack. file файл Files for future use. Файлы для будущего использования. CCreateRouteFromWpt route маршрут CDBFolderLostFound All your data grouped by folders. Все ваши данные сгруппированы по папкам. Lost & Found (%1) Потеряно и найдено (%1) Lost & Found Потеряно и найдено CDBFolderMysql All your data grouped by folders. Все ваши данные сгруппированы по папкам. MySQL Database База данных MySQL Server: Сервер: (No PW) (Нет пароля) Error: Ошибка: CDBFolderSqlite All your data grouped by folders. Все ваши данные сгруппированы по папкам. SQLite Database База данных SQLite File: Файл: Error: Ошибка: CDBItem %1 min. %1 мин. %1 h %1 ч. %1 days %1 дней CDBProject Failed to load... Не удалось загрузить... Can't load file "%1" . It will be skipped. Загрузить файл %1 не удалось. Он будет пропущен. Project already in database... Проект уже в базе данных... The project "%1" has already been imported into the database. It will be skipped. Проект "%1" уже был загружен в базу данных. Он будет пропущен. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database Элемент %1 изменен пользователем %2 (%3). Для решения этого конфликта можно создать и сохранить клон, заставить вашу версию или бросить вашу версию и взять версию базы данных Conflict with database... Конфликт с базой данных... Clone && Save Клонировать и сохранить Force Save Сохранить принудительно Take remote Взять удаленную версию Missing folder... Отсутствует папка... Failed to save project. The folder has been deleted in the database. Не удалось сохранить проект. Папка удалена с базы данных. Save ... Сохранить ... Error Ошибка There was an unexpected database error: %1 Неожиданная ошибка в базе данных: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Проект '%1' собирается обновить себя с базы данных. Однако имеются несохранённые изменения. Save changes? Сохранить изменения? CDemList Deactivate Деактивировать Activate Активировать CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Добавить или удалить путь к данным ЦМР. Несколько файлов может быть в пути, но вложенные пути не проанализированы. Поддерживаемые форматы: %1 Select DEM file path... Выбрать путь к файлам ЦМР... CDemVRT Error... Ошибка... Failed to load file: %1 Не удалось загрузить файл: %1 DEM must have one band with 16bit or 32bit data. ЦМР должен иметь одну полосу с 16бит или 32бит данными. No georeference information found. Отсутствует геопозиционная информация. CDetailsGeoCache none Нет ??? ??? Searching for images... Поиск изображений... No images found Изображения не найдены CDetailsPrj You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Вы желаете отсортировать маршрутные точки вдоль трека, но отключили корреляцию между треком и точками. Желаете включить её снова? Correlation... Корреляция... none нет Build diary... Построить дневник... <b>Summary over all tracks in project</b><br/> <b>Резюме всех треков в проекте</b><br/> <h2>Waypoints</h2> <h2>Маршрутные точки</h2> Info Информация Comment Комментарий <h2>Tracks</h2> <h2>Треки</h2> From Start С начала To Next До следующего To End До конца Distance: Расстояние: Ascent: Подъем: Descent: Спуск: <h2>Areas</h2> <h2>Области</h2> <h2>Routes</h2> <h2>Маршруты</h2> Edit name... Изменить имя... Enter new project name. Ввести новое имя проекта. Edit keywords... Изменить ключевые слова... Enter keywords. Ввести ключевые слова. Print Diary Печатать дневник CDetailsTrk Reduce visible track points Уменьшить число видимых точек трека Change elevation of track points Изменить высоту точек трека Change timestamp of track points Изменить метки времени точек трека Miscellaneous Разное Color Цвет Activity Мероприятие CDetailsWpt Enter new proximity range. Ввести новый радиус близости. CDeviceGarmin Picture%1 Изображение %1 Unknown Неизвестно CDeviceGarminArchive Archive - expand to load Архив - развернуть чтобы загрузить Archive - loaded Архив - загружен CElevationDialog No DEM data found for that point. Данные ЦМР для этой точки не найдены. CExportDatabase Select export path... Выбрать путь экспорта... CExportDatabaseThread Create %1 Создать %1 Failed to create %1 Не удалось создать %1 Done! Сделано! Abort by user! Прекращение пользователем! Database Error: %1 Ошибка базы данных: %1 Save project as %1 Сохранить проект как %1 Failed! Не удалось! CFilterDeleteExtension No extension available Нет расширения CFilterInterpolateElevation coarse грубо medium нормально fine точно CFitCrcState FIT decoding error : invalid CRC. Ошибка декодирования FIT: неверная контрольная сумма. CFitDecoder FIT decoding error: unexpected end of file %1. Ошибка декодирования FIT: неожиданный конец файла %1. CFitFieldBuilder FIT decoding error: unknown base type %1. Ошибка декодирования FIT: неизвестный базовый тип %1. CFitFieldDataState Missing field definition for development field. Отсутствует определение поля для поля развития. FIT decoding error: invalid field def nr %1 while creating dev field profile. Ошибка декодирования FIT: неправильный номер определения поля %1 при создании профиля поля развития. CFitHeaderState FIT decoding error: protocol %1 version not supported. Ошибка декодирования FIT: версия протокола %1 не поддерживается. FIT decoding error: file header signature mismatch. File is not FIT. Ошибка декодирования FIT: некорректная сигнатура в заголовке файла. Это не файл типа FIT. CFitProject Failed to load file %1... Не удалось загрузить файл %1... Failed to open FIT file %1. Не удалось открыть FIT файл %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. Ошибка декодирования FIT: архитектура %1 не поддерживается. FIT decoding error: invalid offset %1 for state 'record content' Ошибка декодирования FIT: неправильное смещение %1 для состояния 'содержимое записи' CGarminTyp Warning... Предупреждение... This is a typ file with unknown polygon encoding. Please report! Файл типов с неизвестной кодировкой полигона. Сообщите об этой проблеме! This is a typ file with unknown polyline encoding. Please report! Файл типов с неизвестной кодировкой полилинии. Сообщите об этой проблеме! CGisItemOvlArea thin Тонко normal Нормально wide Широко strong Строго _Clone _клон Area: %1%2 Область: %1%2 Changed area shape. Изменена фигура области. Changed name. Изменено имя. Changed border width. Изменена ширина границы. Changed fill pattern. Изменен узор заливки. Changed opacity. Изменена прозрачность. Changed comment. Изменен комментарий. Changed description. Изменено описание. Changed links Изменены ссылки Changed color Изменен цвет CGisItemRte _Clone _клон track трек Changed name. Изменено имя. Changed comment Изменен комментарий Changed description Изменено описание Changed links Изменены ссылки Length: %1%2 Длина: %1%2 Time: %1%2 Время: %1%2 Distance: %1%2 Расстояние: %1 %2 Length: - Длина: - Time: - Время: - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Последнее время маршрутизации:<br/>%1 with %1 с %1 Changed route points. Изменены точки маршрута. CGisItemTrk FIT file %1 contains no GPS data. FIT файл %1 не содержит данных GPS. Error... Ошибка... Failed to open %1. Не удалось открыть %1. Only support lon/lat WGS 84 format. Поддерживается долгота/широта только в формате WGS 84. Failed to read data. Не удалось читать данные. _Clone _клон Changed trackpoints, sacrificed all previous data. Изменены точки трека, удалены все предыдущие данные. , %1-, %2- , %1-, %2- Time: %1%2, Speed: %3%4 Время: %1%2, Скорость: %3%4 Time: -, Speed: - Время: -, скорость: - Moving: %1%2, Speed: %3%4 В движении: %1%2, Скорость: %3%4 Moving: -, Speed: - В движении: -, скорость: - Start: %1 Начало: %1 Start: - Начало: - End: %1 Конец: %1 End: - Конец: - Points: %1 (%2) Точки: %1 (%2) Invalid elevations! Неверные высоты! Invalid timestamps! Неверные метки времени! Invalid positions! Неверные позиции! Activities: %1 Мероприятие: %1 Index: %1 Индекс: %1 Index: visible %1, total %2 Индекс: видимо %1, всего %2 , Slope: %1%2 , Склон: %1%2 ... and %1 tags not displayed ... и %1 не показанных элементов Distance: - (-) Расстояние: - (-) Moving: - (-) В движении: - (-) track трек Hide point %1. Скрыть точку %1. Hide points %1..%2. Скрыть точки %1..%2. , %1%2 , %1%2 Invalid points.... Неверные точки... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? Трек '%1' имеет %2 неверных точек из %3 видимых точек. Вы хотите скрыть неверные очки? min. мин. max. макс. Length: %1%2 Длина: %1%2 , %1%2%3, %4%5%6 , %1%2 %3, %4%5%6 Ele.: %1%2 Высота: %1%2 , Speed: %1%2 , Скорость: %1%2 Ascent: - (-) Подъем: -(-) Descent: - (-) Спуск: -(-) Ascent: %1%2 (%3%) Подъем: %1 %2 (%3%) , Descent: %1%2 (%3%) , Спуск: %1 %2 (%3%) Distance: %1%2 (%3%) Расстояние: %1 %2 (%3%) , Moving: %1%2 (%3%) , В движении: %1%2 (%3%) Ascent: - Подъем: - Descent: - Спуск: - Ascent: %1%2 Подъем: %1 %2 , Descent: %1%2 , Спуск: %1 %2 Distance: %1%2 Расстояние: %1 %2 , Time: %1%2 , Время: %1%2 Permanently removed points %1..%2 Удалены безвозвратно точки %1..%2 Show points. Показать точки. Changed name Изменено имя Changed comment Изменен комментарий Changed description Изменено описание Changed links Изменены ссылки Changed elevation of point %1 to %2 %3 Изменена высота точки %1 на %2 %3 Changed activity to '%1' for complete track. Изменено мероприятие на '%1' для всего трека. Changed activity to '%1' for range(%2..%3). Изменено мероприятие на '%1' для интервала (%2..%3). Hide points by Douglas Peuker algorithm (%1%2) Скрыть точки при помощи алгоритма Douglas-Peuker (%1%2) Hide points with invalid data. Скрыть точки с неверными данными. Reset all hidden track points to visible Сделать видимыми все скрытые точки трека Permanently removed all hidden track points Удалены безвозвратно все скрытые точки трека Smoothed profile with a Median filter of size %1 Сгладить профиль используя фильтр Медиан с размером %1 Added terrain slope from DEM file. Добавлен склон местности с файла ЦМР. Replaced elevation data with data from DEM files. Заменены высоты данными файлов ЦМР. Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Заменены высоты интерполированными значениями. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Добавить %1 %2 к высоте. Changed start of track to %1. Изменено начало трека на %1. Remove timestamps. Удалить метки времени. Set artificial timestamps with delta of %1 sec. Установить искусственные метки времени с интервалом в %1 секунд. Changed speed to %1%2. Изменена скорость на %1 %2. %1 (Segment %2) %1 (сегмент %2) Removed extension %1 from all Track Points Удалено расширение %1 со всех точек трека Converted subpoints from routing to track points Преобразованы подточки с маршрутных в точки трека Copy flag information from QLandkarte GT track Скопировать информацию о флагах с трека QLandkarte GT CGisItemWpt Archived Архивировано Available Доступно Not Available Не доступно _Clone _клон Elevation: %1%2 Высота: %1%2 Proximity: %1%2 Радиус близости: %1%2 Changed name Изменено имя Changed position Изменена позиция Changed elevation Изменена высота Removed proximity Удален радиус близости Changed proximity Изменен радиус близости Changed icon Изменена пиктограмма Changed comment Изменен комментарий Changed description Изменено описание Changed links Изменены ссылки Changed images Изменены изображения Add image Добавить изображение Changed to proximity-radius Изменено на круг близости Changed to nogo-area Изменено на запретную зону CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Из-за изменений в системе баз данных QMapShack забыл об имени файла базы данных '%1'. Выбрать его снова на следующем шаге. Select database file. Выбрать файл базы данных. Add Database Добавить базу данных Add Folder Добавить папку Rename Folder Переименовать папку Copy Folder Копировать папку Move Folder Переместить папку Delete Folder Удалить папку Import from Files... Импортировать файлы... Export to GPX... Экспортировать в GPX... Delete Item Удалить элемент Search Database Искать в базе данных Sync. with Database Синхронизировать с базой данных Remove Database Удалить базу данных Empty Удалить все элементы Remove database... Удалить базу данных... Do you really want to remove '%1' from the list? Вы действительно хотите удалить '%1' со списка? Delete database folder... Удалить папку с базы данных... Are you sure you want to delete selected folders and all subfolders from the database? Вы действительно хотите удалить все выбранные папки вместе с вложенными папками с базы данных? Bad operation.... Неверная операция... The target folder is a subfolder of the one to move. This will not work. Целевая папка есть вложенная папка папки которая перемещается. Так нельзя. Folder name... Имя папки... Rename folder: Переименовать папку: Remove items... Удалить элементы... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Вы действительно хотите удалить все элементы с 'Потеряно и найдено'? Это удалит их безвозвратно. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Вы действительно хотите удалить все выбранные элементы с 'Потеряно и найдено'? Это удалит их безвозвратно. Are you sure you want to delete '%1' from folder '%2'? Вы действительно хотите удалить '%1' с папки '%2'? Delete... Удалить... Import GIS Data... Импортировать данные GIS... CGisListWks Edit.. Изменить.. Show on Map Показать на карте Hide from Map Скрыть с карты Sort by Time Сортировать по времени Sort by Name Сортировать по именам Save Сохранить Save as GPX 1.1 w/o ext... Сохранить как GPX 1.1 без расширений... Send to Devices Отправить в устройства Sync. with Database Синхронизировать с базой данных Close Закрыть Update Project on Device Обновить проект на устройстве Delete Удалить Edit... Изменить... Copy to... Копировать в... Autom. Save Сохранить автоматически Save as... Сохранить как... Track Profile Профиль трека Select Range Выделить интервал Edit Track Points Изменить точки трека Reverse Track Обратить трек Combine Tracks Соединить треки Set Track Activity Добавить мероприятие Copy Track with Waypoints Копировать трек с маршрутными точками Show Bubble Показать пузырек Move Waypoint Переместить маршрутную точку Proj. Waypoint... Проекция маршрутной точки... Change Radius Изменить радиус близости Toggle Nogo-Area Переключить запретную зону Delete Radius Удалить радиус близости Route Instructions Маршрутные инструкции Calculate Route Вычислить маршрут Reset Route Сбросить маршрутизацию Edit Route Изменить маршрут Convert to Track Преобразовать в трек Edit Area Points Изменить точки области Create Route Создать маршрут Change Icon (sel. waypt. only) Изменить пиктограмму (выбрать только маршрутные точки) Drop items... Удалить элементы... <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Обновить устройства</b><p>Обновить %1<br/>Подождите...</p> Saving workspace. Please wait. Сохранить рабочую область. Подождите. Loading workspace. Please wait. Загрузка рабочей области. Подождите. Close all projects... Закрыть все проекты... This will remove all projects from the workspace. Это удалит все проекты с рабочей области. Delete project... Удалить проект... Do you really want to delete %1? Вы действительно хотите удалить %1? CGisWorkspace Load project... Загрузить проект... The project "%1" is already in the workspace. Проект "%1" уже находится в рабочей области. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Выбор элементов: </b>Элемент выбран из списка рабочей области. Нажать на карту, чтобы вернуться к обычному поведению мышки. Copy items... Копировать элементы ... Change waypoint symbols. Изменить символы путевых точек. Cut Track... Вырезать трек... Do you want to delete the original track? Желаете удалить изначальный трек? CGpxProject Failed to load file %1... Не удалось загрузить файл %1... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Not a GPX file: %1 Это не файл GPX: %1 File exists ... Файл существует... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Файл существует и не создан в QMapShack. Если нажать 'да' все данные в этом файле будут потеряны. Даже если этот файл содержит данные GPX и был загружен в QMapShack, QMapShack не может загрузить и сохранить все элементы этого файла. Такие элементы будут потеряны. Рекомендуется использовать другой файл. <b>Вы действительно хотите перезаписать этот файл?</b> Failed to create file '%1' Не удалось создать файл '%1' Failed to write file '%1' Не удалось записать файл '%1' Saving GIS data failed... Не удалось сохранить данные GIS... CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1м, %2м N %1m, E %2m С %1м, В %2м CHistoryListWidget by %1 от %1 Cut history before Удалить историю до этого шага Cut history after Удалить историю после этого шага History removal Удалить историю The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> Удаление является постоянным и не может быть отменено. <b>Вы действительно хотите удалить историю перед этим шагом?</b> CImportDatabase Import QLandkarte Database Импортировать базу данных QLandkarte Select source database... Выбрать исходную базу данных... Select target database... Выбрать целевую базу данных... CKnownExtension Air Temp. extShortName Темп. возд. Air Temperature extLongName Температура воздуха Water Temp. extShortName Темп. воды Water Temperature extLongName Температура воды Depth extShortName Глубина Depth extLongName Глубина Heart R. extShortName Пульс Heart Rate extLongName Пульс Cadence extShortName Каденция Cadence extLongName Каденция Speed extShortName Скорость Speed extLongName Скорость Accel. extShortName Ускор. Acceleration extLongName Ускорение Course extShortName Курс Course extLongName Курс Temp. extShortName Темп. Temperature extLongName Температура Dist. extShortName Расстояние Distance extLongName Расстояние Ele. extShortName Высота Elevation extLongName Высота Energy extShortName Энергия Energy extLongName Энергия Sea Lev. Pres. extShortName Давление Sea Level Pressure extLongName Давление на уровне моря v. Speed extShortName Скорость Vertical Speed extLongName Скорость (вертикальная) Slope extShortName Наклон Slope* Наклон* Speed over Distance* extLongName Скорость(расстояние)* Speed over Time* extLongName Скорость(время)* Elevation* extLongName Высота* Progress extShortName Расстояние Progress* extLongName Расстояние* Terr. Slope extShortName Склон местн. Terrain Slope* extLongName Склон местности* CLogProject Failed to load file %1... Не удалось загрузить файл %1... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Not an Openambit log file: %1 Это не файл Openambit LOG: %1 Device: %1<br/> Устройство: %1<br/> Recovery time: %1 h<br/> Время восстановления: %1 h<br/> Peak Training Effect: %1<br/> Пиковый эффект тренинга: %1<br/> Energy: %1 kCal<br/> Энергия: %1 kCal<br/> Use of local time... Использование местного времени... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. Не найдено время UTC в файле %1. Используется локальное время компьютера. При необходимости вы можете настроить время, используя фильтр времени. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 Этот файл LOG не содержит данных о местоположении и не может отображаться в QMapShack: %1 CLostFoundProject Lost & Found Потеряно и найдено CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Использовать <b>Меню->Вид->Добавить окно карты</b> для добавления нового вида. Или <b>Меню->Файл->Загрузить вид карты</b> для восстановления сохраненного вида. Или нажмите <a href='newview'>здесь</a>. Ele.: %1%2 Высота: %1%2 Slope: %1%2 terrain Склон: %1%2 [Grid: %1] [Координатная сетка: %1] Load GIS Data... Загрузить данные GIS... Select output file Выбрать выходной файл QMapShack View (*.view) QMapShack вид (*.view) Select file to load Выбрать файл для загрузки Fatal... Неустранимая ошибка... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack обнаружил плохо установленную библиотеку Proj4. Таблицы перевода для проекций EPSG обычно находятся в /usr/share/pro отсутствуют. Пожалуйста, сообщите об этом администратору пакета чтобы поправить это. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. В данный момент, карт ещё нет. Использование QMapShack без карт совсем непривлекательно. Вы можете установить карты, нажав кнопку 'Помогите! Я хочу карты!' в окне 'Карты'. Или Вы можете нажать клавишу F1, чтобы открыть документацию в Интернете, которая объяснит как использовать QMapShack. Так не очень удобно, почему не поставлять сразу с картами? Поддержка готовых для загрузки и установки карт требует хорошего сервера. И это не бесплатно. У проекта нет денег. Вдобавок карты и данные ЦМР зачастую распространяются под ограничительными лицензиями. Поэтому требуется разрешение правообладателя перед упаковкой его данных. Это не так просто как звучит, к тому же за некоторые данные требуется платить комиссионные. У проекта просто нет ресурсов для этого. И мы надеемся установка карт Вами лично не будет уж такой затруднительной. Кстати сама эта программа свободна и распространяется бесплатно. CMapIMG Failed ... Не удалось... Unspecified Не указано French Французский German Немецкий Dutch Голландский English Английский Italian Итальянский Finnish Финский Swedish Шведский Spanish Испанский Basque Баскский Catalan Каталонский Galician Галисийский Welsh Валлийский Gaelic Гэльский Danish Датский Norwegian Норвежский Portuguese Португальский Slovak Словацкий Czech Чешский Croatian Хорватский Hungarian Венгерский Polish Польский Turkish Турецкий Greek Греческий Slovenian Словенский Russian Русский Estonian Эстонский Latvian Латвийский Romanian Румынский Albanian Албанский Bosnian Боснийский Lithuanian Литовский Serbian Сербский Macedonian Македонский Bulgarian Болгарский Major highway Автомагистраль Principal highway Шоссе основное Other highway Прочие загородные дороги Arterial road Городская магистраль Collector road Улица крупная Residential street Улица малая Alley/Private road Переулок, внутриквартальный проезд Highway ramp, low speed Наклонный съезд с путепровода Highway ramp, high speed Наклонный съезд с путепровода скоростной Unpaved road Грунтовая дорога Major highway connector Соединительное шоссе Roundabout Круговое движение Railroad Железная дорога Shoreline Береговая линия Trail Тропа Stream Ручей Time zone Граница часового пояса Ferry Паром State/province border Граница области County/parish border Граница района, округа International border Международная граница River Река Minor land contour Изолиния высоты, вспомогательная Intermediate land contour Изолиния высоты, основная Major land contour Изолиния высоты, утолщённая Minor depth contour Изолиния глубины, вспомогательная Intermediate depth contour Изолиния глубины, основная Major depth contour Изолиния глубины, утолщённая Intermittent stream Пересыхающая река, ручей или канава Airport runway Взлетно-посадочная полоса Pipeline Трубопровод Powerline Линия электропередачи Marine boundary Морская граница Hazard boundary Опасность для плавания Large urban area (&gt;200K) Городская застройка (&gt;200 тыс.ж) Small urban area (&lt;200K) Городская застройка (&lt;200 тыс.ж) Rural housing area Застройка сельского типа Military base Военная база Parking lot Автостоянка Parking garage Гараж Airport Аэропорт Shopping center Место для торговли Marina Пристань University/College Университета или колледж Hospital Больница Industrial complex Промышленная зона Reservation Резервация, заповедник Man-made area Здание, искусственное сооружение Sports complex Спортивный комплекс Golf course Площадка для гольфа Cemetery Кладбище National park Национальный парк City park Городской парк State park Парк регионального значения Forest Лес Ocean Море/океан Blue (unknown) Синий (неизвестно) Sea Море Large lake Озеро, большое Medium lake Озеро, среднее Small lake Озеро, малое Major lake Озеро, крупное Major River Река, крупная Large River Река, большая Medium River Река, средняя Small River Река, малая Intermittent water Пересыхающая река, озеро Wetland/Swamp Болото Glacier Ледник Orchard/Plantation Фруктовый сад, огород Scrub Кустарник Tundra Тундра Flat Равнина ??? ??? Read external type file... Загрузить внешний файл типов... Failed to read type file: %1 Fall back to internal types. Не удалось читать файл типов: %1 Возврат к внутренним типам. Failed to read: Не удалось читать: Failed to open: Не удалось открыть: Bad file format: Неверный формат файла: Failed to read file structure: Не удалось читать структуру файла: Loading %1 Идет загрузка %1 User abort: Прекращение пользователем: File is NT format. QMapShack is unable to read map files with NT format: Файл имеет формат NT. QMapShack не может считывать этот формат: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Файл содержит заблокированные / зашифрованные данные. Garmin позволяет использовать этот файл только с помощью программного обеспечения Garmin. Point of Interest Достопримечательность Unknown Неизвестно Area Область CMapList Deactivate Деактивировать Activate Активировать Where do you want to store maps? Где вы хотите хранить карты? CMapMAP Failed ... Не удалось... Failed to open: Не удалось открыть: Bad file format: Неверный формат файла: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Добавить или удалить путь с картами. Несколько карт может быть в пути, но вложенные пути не поддерживаются. Поддерживаемые форматы: %1 Select map path... Выбрать путь к картам... Select root path... Выбрать корневой путь... CMapPropSetup Select type file... Выбрать файл типов... CMapRMAP Error... Ошибка... This is not a TwoNav RMAP file. Это не файл TwoNav RMAP. Unknown sub-format. Неизвестный подформат. Unknown version. Неизвестная версия. Failed to read reference point. Не удалось читать опорную точку. Unknown projection and datum (%1%2). Неизвестные проекция и датум (%1%2). CMapTMS Error... Ошибка... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Layer %1 Слой %1 CMapVRT Error... Ошибка... Failed to load file: %1 Не удалось загрузить файл: %1 File must be 8 bit palette or gray indexed. Файл должен быть 8 битной палитрой или серый проиндексирован. No georeference information found. Не удалось найти геопозиционную информацию. CMapVrtBuilder Build GDAL VRT Построить GDAL VRT Select files... Выбрать файлы... Select target file... Выбрать целевой файл... !!! done !!! Сделано! CMapWMTS Error... Ошибка... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Failed to read: %1 Unknown structure. Не удалось читать: %1. Неизвестная структура. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Неожиданный сервис. Ожидается '* WMTS 1.0.0'. Получено '%1 %2'. No georeference information found. Не удалось найти геопозиционную информацию. CMouseEditArea Area Область <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Изменить область</b><br/>Выберите функцию и режим маршрутизации с помощью кнопок панели инструментов. Потом выберите точку на линии. Только точки, отмеченные большим квадратиком могут быть изменены. Те с черной точкой являются подточки добавлены маршрутизацией<br/> area область CMouseEditRte Route Маршрут <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Изменить точки маршрута</b><br/>Выберите функцию и режим маршрутизации с помощью кнопок панели инструментов. Потом выберите точку на линии. Только точки, отмеченные большим квадратиком могут быть изменены. Точки с черным пунктиром являются подточки введены маршрутизацией<br/> route маршрут CMouseEditTrk Track Трек <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Изменить точки трека</b><br/>Выберите функцию и режим маршрутизации с помощью кнопок панели инструментов. Потом выберите точку на линии. Только точки, отмеченные большим квадратиком могут быть изменены. Точки с черным пунктиром являются подточки введены маршрутизацией<br/> Warning! Предупреждение! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Это заменит все данные оригинала простой линией. Все остальные данные будут потеряны безвозвратно. track трек CMouseNormal Add POI as Waypoint Добавить достопримечательность как маршрутную точку Add Waypoint Добавить маршрутную точку Add Track Добавить трек Add Route Добавить маршрут Add Area Добавить область Select Items On Map Выбрать элементы на карте Copy position Скопировать позицию Copy position (Grid) Скопировать позицию (координатная сетка) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Сохранить (Печатать) карту</b><br/> Выберите прямоугольную область на карте. Используйте левую кнопку мышки и двигайте её. Прервать с правой кнопкой мышки. Уточните выбор с помощью метода указать-нажать-переместить по углам. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Выбрать интервал</b><br/> Выберите первую точку трека с левой кнопкой мышки. А затем второй. Закончите выбор интервала с помощью щелчка правой кнопкой мышки. <br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Выбрать элементы на карте</b><br/> Выберите прямоугольную область на карте. Используйте левую кнопку мышки и двигайте её. Прервать с правой кнопкой мышки. Уточните выбор с помощью метода указать-нажать-переместить по углам. <b>Selected:</b><br/> <b>Выбрано:</b><br/> %1 waypoints<br/> %1 маршрутных точек<br/> %1 tracks<br/> %1 треков<br/> %1 routes<br/> %1 маршрутов<br/> %1 areas<br/> %1 областей<br/> CPhotoAlbum Select images... Выбрать изображения... CPlot Distance [%1] Расстояние [%1] Time Время CPlotProfile Distance [%1] Расстояние [%1] Ele. [%1] Высота: [%1] CPrintDialog Print Map... Печатать карту... Save Map as Image... Сохранить карту как изображение... Printer Properties... Свойства принтера... Pages: %1 x %2 Страницы: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Использовать колёсико мышки на нижней карте для изменения разрешения: %1x%2 пиксель x: %3 м/пиксель y: %4 м/пиксель Printing pages. Вывод страниц на печать. Save map... Сохранить карту... CProgressDialog Elapsed time: %1 Истёкшее время: %1 Elapsed time: %1 seconds. Истёкшее время: %1 сек. CProjWizard north север south юг Error... Ошибка... The value '%1' is not a valid coordinate system definition: %2 Значение '%1' недопустимое определение координатной системы: %2 CProjWpt Edit name... Изменить имя... Enter new waypoint name. Ввести новое имя маршрутной точки. CQlbProject Failed to open... Не удалось открыть... Failed to open %1 Не удалось открыть %1 Could not convert... Не удалось преобразовать... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. Файл содержит наложения, которые невозможно преобразовать. Это связано с тем, что QMapShack не поддерживает все типы наложений QLandkarte. CQlgtDb Migrating database from version 4 to 5. Миграции базы данных с версии 4 до версии 5. Migrating database from version 5 to 6. Миграции базы данных с версии 5 до версии 6. Migrating database from version 6 to 7. Миграции базы данных с версии 6 до версии 7. Migrating database from version 7 to 8. Миграции базы данных с версии 7 до версии 8. Migrating database from version 8 to 9. Миграции базы данных с версии 8 до версии 9. Open database: %1 Открыть базы данных: %1 Folders: %1 Папки: %1 Tracks: %1 Треки: %1 Routes: %1 (Only the basic route will be copied) Маршруты: %1 (скопируется только основной маршрут) Waypoints: %1 Маршрутные точки: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Наложения: %1 (области будут преобразованы в области, линии расстояния будут преобразованы в треки, все остальные элементы наложения будут потеряны) Diaries: %1 Дневники: %1 Map selections: %1 (can't be converted to QMapShack) Выборки карт: %1 (невозможно преобразовать в QMapShack) ------ Start to convert database to %1------ ------ Начиная преобразовать базу данных до %1------ Failed to create target database. Не удалось создать целевую базу данных. ------ Abort ------ ------Прекращение------ ------ Done ------ ------Сделано!------ Restore folders... Восстановить папки... Imported %1 folders and %2 diaries Импортированы %1 папок и %2 дневников Copy items... Копировать элементы ... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Импортированы %1 треков, %2 маршрутных точек, %3 маршрутов, %4 областей Import folders... Импортировать папки... Overlay of type '%1' cant be converted Наложение типа '%1' не может быть преобразовано CQlgtTrack Corrupt track ... Поврежденный трек... Number of trackpoints is not equal the number of training data trackpoints. Количество точек трека не равно количеству точек трека в данных тренировки. Number of trackpoints is not equal the number of extended data trackpoints. Количество точек трека не равно количеству расширенных точек трека. Number of trackpoints is not equal the number of shadow data trackpoints. Количество точек трека не равно количеству затененных точек трека. CQmsDb Existing file... Файл существует... Remove existing %1? Удалить существующий %1? Remove existing file %1 Удалить существующий файл %1 %1: drop item with QLGT DB ID %2 %1: удалить элемент с QLGT DB ID %2 CQmsProject Failed to open... Не удалось открыть... Failed to open %1 Не удалось открыть %1 CRouterBRouter original Оригинал first alternative Первая альтернатива second alternative Вторая альтернатива third alternative Третья альтернатива BRouter (offline) BRouter (без Интернета) BRouter (online) BRouter (требуется связь с Интернетом) profile: %1, alternative: %2 Профиль: %1, альтернатива: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade BRouter в данной версии не поддерживает более 1 запретной зоны, рассмотрите возможность обновления response is empty Ответ пуст Bad response from server: %1 Плохой ответ от сервера: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... <b>BRouter</b><br/>Запрос маршрутизации отправлен на сервер. Пожалуйста, подождите... Calculate route with %1 Вычислить маршрут с %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <b>BRouter</b><br/>Плохой ответ от сервера:<br/>%1 <br/>Calculation time: %1s <br/>Время расчета: %1 сек. Error Ошибка running Запущено starting Идет запуск QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. QMapShack взаимодействует с BRouter через сетевое соединение. Обычно это делается по специальному адресу, который не может быть достигнут вне вашего устройства. Однако BRouter слушает соединения на всех доступных интерфейсах. Если вы находитесь в своей частной сети с активным брандмауэром, это не проблема. Если вы находитесь в общедоступной сети, каждый открытый порт представляет собой риск, так как он может быть использован кем-то другим для компрометации вашей системы. В этом случае мы не рекомендуем использовать локальную службу BRouter. Warning... Предупреждение... I understand the risk. Don't tell me again. Я понимаю риск. Больше не говорите. stopped Остановлено not installed Не установлено online Онлайн CRouterBRouterSetup %1 not accessible %1 не доступно %1 invalid result %1 неверный результат Error parsing online-config: Ошибка при анализе онлайн конфигурации: Network error: Ошибка сети: CRouterBRouterSetupWizard Restore Default Values Восстановить умолчание Open Directory Открыть папку select Java Executable Выбрать исполняемый файл Java please select BRouter installation directory Выбрать папку установки BRouter selected directory does not exist Выбранная папка не существует create directory and install BRouter there Создать папку и установить там BRouter existing BRouter installation Существующая установка BRouter update existing BRouter installation Обновить существующую установку BRouter empty directory, create new BRouter installation here Пустая папка, создать там новую установку BRouter create new BRouter installation Создать новую установку BRouter seems to be a valid Java-executable Вероятно, является допустимым исполняемым файлом Java doesn't seem to be a valid Java-executable Не похоже на допустимый исполняемый файл Java Java Executable not found Исполняемый файл Java не найден Error loading installation-page at %1 Ошибка загрузки страницы установки в %1 no brouter-version to install selected Версия BRouter для установки не выбрана selected %1 for download and installation Выбрано %1 для загрузки и установки Warning... Предупреждение... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. Загрузка:%1 <br/>Это загрузит и установит файл ZIP из места загрузки, которое не защищено никаким стандартом вообще, используя простой HTTP. Обычно это должно быть HTTPS. Риск заключается в том, что кто-то перенаправляет запрос и отправляет вам заменяющий ZIP с помощью вредоносной программы. QMapShack не может обнаружить это. <br/> Если вы не понимаете этого или если у вас есть сомнения, не начинайте и прерываете. Вместо этого используйте веб-версию BRouter. I understand the risk and wish to proceed. Я понимаю риск и хочу продолжить. download %1 started Загрузка %1 началась Network Error: %1 Ошибка сети: %1 download %1 finished Загрузка %1 завершена unzipping: Распаковка: ready. Готово. download of brouter failed: %1 Загрузка BRouter не удалась: %1 retrieving available profiles from %1 Получить доступные профили из %1 content of profile Содержание профиля Error: Ошибка: Error creating directory %1 Ошибка создания папки %1 Error directory %1 does not exist Ошибка: папка %1 не существует Error creating file %1 Ошибка создания файла %1 Error writing to file %1 Ошибка записи в файл %1 CRouterBRouterTilesPage Continue with Setup Продолжать настройку CRouterBRouterTilesSelect available routing-data is being determined. Определяются доступные данные маршрутизации. Select outdated Выбрать устаревшее Clear Selection Очистить выделение Delete selection Удалить выделение Download Загрузка Error creating segments directory %1 Ошибка создания каталога сегментов %1 cannot parse: %1 is not a date Невозможно разобрать: %1 не является допустимой датой cannot parse: %1 is not a valid size Невозможно разобрать: %1 не является допустимым размером Error retrieving available routing data from %1: %2 Ошибка получения доступных данных маршрутизации из %1: %2 segments directory does not exist: Папка сегментов не существует: error creating file %1: %2 Ошибка создания файла сегментов %1: %2 no valid request for filename %1 Недействительный запрос имени файла %1 no open file assigned to request for %1 К запросу для %1 не был назначен открытый файл error writing to file %1: %2 Ошибка записи в файл %1: %2 error renaming file %1 to %2: %3 Ошибка переименования файла %1 до %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) Верно: %1 (%2), устарело: %3 (%4), загрузить: %5 (%6) being downloaded: %1 of %2 Загружено: %1 от %2 no local data, online available: %1 (%2) Нет локальных данных, доступно в Интернете: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Локальные данные устарели (%1, %2 - удаленные %3, %4) Error removing %1: %2 Ошибка удаления %1: %2 Network Error Ошибка сети invalid result, no files found Неверный результат, файлы не найдены local data up to date (%1, %2) Локальные данные верны (%1, %2) no routing-data available Нет доступных данных маршрутизации CRouterBRouterToolShell !!! done !!! Сделано! !!! failed !!! Не удалось! CRouterMapQuest Fastest Самый быстрый Shortest Самый короткий Bicycle Велосипед Pedestrian Пешеход US English Английский (США) British English Английский (Британский) Danish Датский Dutch Голландский French Французский German Немецкий Italian Итальянский Norwegian Норвежский Spanish Испанский Swedish Шведский mode "%1" режим "%1" no highways без шоссе no toll roads без платных дорог no seasonal без сезонных no unpaved нет без покрытия no ferry без парома no crossing of country borders без пересечений государственных границ <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Запрос маршрутизации отправленный до сервера. Пожалуйста, подождите... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Плохой ответ от сервера:<br/>%1 <br/>Calculation time: %1s <br/>Время расчета: %1 сек. CRouterRoutino Warning... Предупреждение... Found Routino with a wrong version. Expected %1 found %2 Найдено Routino с неправильной версией. Ожидаема %1б найдена %2 Shortest Самый короткий Quickest Самый быстрый Foot Пешком Horse Лошадь Wheelchair Инвалидная коляска Bicycle Велосипед Moped Мопед Motorcycle Мотоцикл Motorcar Автомобиль Goods Товары English Английский German Немецкий French Французский Hungarian Венгерский Dutch Голландский Russian Русский Polish Польский A function was called without the database variable set. Функция была вызвана без переменной для базы данных. A function was called without the profile variable set. Функция была вызвана без переменной профиля. A function was called without the translation variable set. Функция была вызвана без переменной перевода. The specified database to load did not exist. Указанная к загрузке база данных не существует. The specified database could not be loaded. Указанная база данных не может быть загружена. The specified profiles XML file did not exist. Указанный XML файл профилей не существует. The specified profiles XML file could not be loaded. Указанный XML файл профилей невозможно загрузить. The specified translations XML file did not exist. Указанный XML файл перевода не существует. The specified translations XML file could not be loaded. Указанный XML файл перевода невозможно загрузить. The requested profile name does not exist in the loaded XML file. Запрошенное имя профиля не существует в загруженном XML файле. The requested translation language does not exist in the loaded XML file. Запрошенный язык перевода не существует в загруженном XML файле. In the routing database there is no highway near the coordinates to place a waypoint. В базе данных маршрутизации нет дороги вблизи координат данной маршрутной точки. The profile and database do not work together. Профиль и базы данных не работают совместно. The profile being used has not been validated. Использованный профиль не был подтвержден. The user specified profile contained invalid data. Указанный профиль содержит недопустимые данные. The routing options specified are not consistent with each other. Параметры маршрутизации несовместимы между собой. There is a mismatch between the library and caller API version. Есть несоответствие между API версиями библиотеки и абонента. Route calculation was aborted by user. Расчет маршрута был прерван пользователем. A route could not be found to waypoint %1. Невозможно найти маршрут к маршрутной точке %1. Unknown error: %1 Неизвестная ошибка: %1 profile "%1" профиль "%1" , mode "%1" , режим "%1" Calculate route with %1 Вычислить маршрут с %1 <br/>Calculation time: %1s <br/>Время расчета: %1 сек. CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Добавить или удалить пути, содержащие данные Routino. Несколько баз данных возможно в папке, но вложенные папки не просматриваются. Select routing data file path... Выбрать путь к файлу с данными маршрутизации... CRouterSetup Routino (offline) Routino (без Интернета) MapQuest (online) MapQuest (требуется связь с Интернетом) BRouter (online) BRouter (требуется связь с Интернетом) CRoutinoDatabaseBuilder Create Routino Database Создать базу данных Routino Select files... Выбрать файлы... Select target path... Выбрать целевой путь... !!! done !!! Сделано! CScrOptRangeTrk No range selected Не выбран интервал CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Точный режим</b><br/> Все выбранные элементы должны полностью находиться внутри выбранной области<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Режим пересечения </b><br/> Все выбранные элементы должны пересекать выбранную область<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Добавить треки </b><br/>Добавить треки к списку выбранных элементов<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Добавить маршрутные точки </b><br/>Добавить маршрутные точки к списку выбранных элементов<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Добавить маршруты </b><br/>Добавить маршруты к списку выбранных элементов<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Добавить области </b><br/>Добавить области к списку выбранных элементов<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Игнорировать треки </b><br/> Игнорировать треки в списке выбранных элементов<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Игнорировать маршрутные точки </b><br/> Игнорировать маршрутные точки в списке выбранных элементов<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Игнорировать маршруты </b><br/> Игнорировать маршруты в списке выбранных элементов<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> <b>Игнорировать области </b><br/> Игнорировать области в списке выбранных элементов<br/> CSearchDatabase Search database '%1': Искать в базе данных '%1': CSearchGoogle Unknown response Неизвестный ответ Error: Ошибка: CSetupDatabase Missing Requirement Отсутствует требование MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. MySQL не может сейчас использован, так как соответствующий драйвер (QMYSQL) не доступен. <br />Пожалуйста, убедитесь, что установлен соответствующий пакет.<br/> Если вы не знаете, что делать, вам следует просмотреть <a href="%1">Wiki</a>. Error... Ошибка... There is already a database with name '%1' База данных с именем '%1' уже существует New database... Новая база данных... Open database... Открыть базу данных... CSetupWorkspace Setup database... Настройка базы данных... Changes will become active after an application's restart. Изменения вступит в силу после перезапуска приложения. CSlfProject Failed to load file %1... Не удалось загрузить файл %1... CSlfReader Failed to parse timestamp `%1` Не удалось проанализировать метку времени `%1` %1 does not exist %1 не существует Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Not a SLF file: %1 Это не файл SLF: %1 Unsupported revision %1: %2 Версия не поддерживается: %1: %2 Break %1 Прерывание %1 Lap %1 Круг %1 CSmlProject Failed to load file %1... Не удалось загрузить файл %1... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Not an sml file: %1 Это не файл SML: %1 Recovery time: %1 h<br/> Время восстановления: %1 h<br/> Peak Training Effect: %1<br/> Пиковый эффект тренинга: %1<br/> Energy: %1 kCal<br/> Энергия: %1 kCal<br/> Device: %1<br/> Устройство: %1<br/> Battery usage: %1 %/hour Изпользование батареи: %1 %/час Use of local time... Использование местного времени... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. Не найдено время UTC в файле %1. Используется локальное время компьютера. При необходимости вы можете настроить время, используя фильтр времени. This SML file does not contain any position data and can not be displayed by QMapShack: %1 Этот файл SML не содержит данных о местоположении и не может отображаться в QMapShack: %1 CTableTrk Double click to edit elevation value Двойной щелчок для изменения высоты %1%2 %1%2 CTcxProject Failed to load file %1... Не удалось загрузить файл %1... Failed to open %1 Не удалось открыть %1 Failed to read: %1 line %2, column %3: %4 Не удалось читать %1 строка %2, столбец %3: %4 Not a TCX file: %1 Это не файл TCX: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Этот файл TCX содержит по крайней мере 1 тренировку, но нет ни активности, ни курса. Поскольку тренировки не содержат данных позиции, они не могут быть импортированы в QMapShack. This TCX file does not contain any activity or course: %1 В файле TCX %1 нет мероприятий или курсов File exists ... Файл существует... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Файл существует и не создан в QMapShack. Если нажать 'да' все данные в этом файле будут потеряны. Даже если этот файл содержит данные GPX и был загружен в QMapShack, QMapShack не может загрузить и сохранить все элементы этого файла. Такие элементы будут потеряны. Рекомендуется использовать другой файл. <b>Вы действительно хотите перезаписать этот файл?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> Выбранный трек <b>%1</b> содержит точки трека с недопустимыми временными метками. Устройство может не принять сгенерированный файл курса TCX, если оставить его как есть. <b>Хотите вы применить фильтр с постоянной скоростью (10 м/с) и продолжить?</b> Course Курс Activity Мероприятие Cancel Отменить Track with invalid timestamps... Трек с неверными метками времени... Activity or course? Мероприятие или курс? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack не знает, как следует сохранить трек <b>%1</b>.<b> Сохранить его как курс или как мероприятие? </b>Помните, что только путевые точки, достаточно близкие к треку, будут сохранены при сохранении в качестве курса. Путевые точки не сохраняются при сохранении в качестве мероприятия. Failed to create file '%1' Не удалось создать файл '%1' Failed to write file '%1' Не удалось записать файл '%1' Saving GIS data failed... Не удалось сохранить данные GIS... CTemplateWidget choose one... выбрать один... Hiking Tour Summary (built-in) Сводка пеших экскурсий (встроенная) - - Template path... Путь к шаблонам... Failed to read template file %1. Не удалось читать шаблон %1. Preview... Просмотр... CTextEditWidget &Color... &Цвет... Reset format Сбросить форматирование CToolBarSetupDialog Available Actions Доступные действия Selected Actions Выбранные действия CTwoNavProject Error... Ошибка... Failed to open %1. Не удалось открыть %1. Save GIS data to... Сохранить данные ГИС в... Only support lon/lat WGS 84 format. Поддерживается долгота/широта только в формате WGS 84. Failed to read data. Не удалось читать данные. CWptIconDialog Path to user icons... Путь к пользовательским пиктограммам... Form Form Форма Participants Участники Weather Погода rain дождь sunny солнце snow снег clouds облака windy ветер hot жарко warm тепло cold холодно freezing заморозка foggy туман humid влажно Character Характер easy hiking легкий поход climbing альпинизм alpine высокогорно large ascend большой подъем long distance длинная дистанция via ferrata феррата hail/soft hail град Rating Рейтинг Rating 5 stars Рейтинг 5 звезд Rating 4 stars Рейтинг 4 звезды Rating 3 stars Рейтинг 3 звезды Rating 2 stars Рейтинг 2 звезды Rating 1 star Рейтинг 1 звезда aborted прервано Equipment Экипировка ferrata gear принадлежности для ферраты night gear ночные принадлежности snow shoes снежная обувь climbing gear альпинистские принадлежности ski лыжи camping gear походные принадлежности Details Деталь IAbout About.... О программе.... <b>QMapShack</b>, Version <b>QMapShack</b>, версия TextLabel Метка текста Qt Qt GDAL GDAL Proj4 Proj4 Routino Routino Czech: Чешский: Pavel Fric Pavel Fric German: Немецкий: Oliver Eichler Oliver Eichler Dutch: Голландский: Harrie Klomp Harrie Klomp French: Французский: Rainer Unseld Rainer Unseld Jose Luis Domingo Lopez Jose Luis Domingo Lopez Spanish: Испанский: <b>Translation:</b> <b>Перевод:</b> Russian: Русский: Wolfgang Thämelt Wolfgang Thämelt Win64: Win64: OS X: OS X: Helmut Schmidt Helmut Schmidt Ivo Kronenberg Ivo Kronenberg <b>Binaries:</b> <b>Бинарники:</b> ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ... и благодарность всем поставщикам пакетов для дистрибутивов Linux за отличную работу. Особая благодарность Dan Horák и Bas Couwenberg за участие в дискуссиях о распределении QMapShack в списке рассылки. <b>Contributors:</b> <b>Участники:</b> Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Это программное обеспечение лицензировано под GPL3 или любой более поздней версией © 2017 Oliver Eichler (oliver.eichler@gmx.de) © 2017 Oliver Eichler (oliver.eichler@gmx.de) ICanvasSetup Setup Map View... Настройка вида карт... Projection & Datum Проекция и датум ... ... Scales Масштаб Logarithmic Логарифмический Square (optimized for TMS and WMTS tiles) Квадратичный (оптимальный для карт TMS и WMTS) IColorChooser Dialog Диалог ICombineTrk Combine Tracks... Объединить треки... Available Tracks Доступные треки ... ... Combined Tracks Объединенные треки ICoordFormatSetup Coordinate Format... Формат координат... N48° 53' 39.6" E13° 31' 6.78" С48° 53' 39.6" В13° 31' 6.78" N48.8943° E013.51855° С48.8943° В013.51855° N48° 53.660 E013° 31.113 С48° 53.660 В013° 31.113 ICreateRouteFromWpt Create Route from Waypoints Создать маршрут с маршрутных точек ... ... ICutTrk Cut Track Вырезать трек Delete first part of the track and keep second one Удалить первую часть трека и сохранить вторую Keep both parts of the track Сохранить обе части трека Keep first part of the track and delete second one Сохранить первую часть трека и удалить вторую Cut Mode: Режим вырезания: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Выбрать, чтобы сохранить результат в новый трек. Если вы сохраните обе части трека, вы должны создать новые. Если вы желаете сохранить только одну часть вы можете просто удалить точки или выбрать это, чтобы создать новый трек. Create a new track Создать новый трек IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Внутренний формат базы данных '%1' изменился. Сейчас QMapShack будет мигрировать вашу базу данных. После миграции база данных не будет работать с более старыми версиями QMapShack. Рекомендуется создать резервную копию базы данных. Migrate database... Перенести базу данных... Migration aborted by user Перенесение прервано пользователем Failed to migrate '%1'. Не удалось перенести %1. Error... Ошибка... Migration failed Не удалось перенесение The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. Версия базы данных '%1' является более продвинутой чем та, которую знает ваша установка. Это не будет работать. Initialization failed Инициализация не удалось Wrong database version... Неверная версия базы данных... Database created by newer version of QMapShack База данных создан при помощи более новой версии QMapShack Failed to initialize '%1'. Не удалось инициализировать %1. IDBMysql Password... Пароль... Password for database '%1': Пароль для базы данных '%1': Update to database version 5. Migrate all GIS items. Обновить базы данных к версии 5. Перенести все элементы ГИС. IDBSqlite Update to database version 3. Migrate all GIS items. Обновить базы данных к версии 3. Перенести все элементы ГИС. Update to database version 5. Migrate all GIS items. Обновить базы данных к версии 5. Перенести все элементы ГИС. Update to database version 6. Migrate all GIS items. Обновить базы данных к версии 6. Перенести все элементы ГИС. IDemPathSetup Setup DEM file paths Настройка путей ЦМР ... ... - - IDemPropSetup Form Форма <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Изменить прозрачность карты</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Нажать, чтобы использовать текущий масштаб как минимальный масштаб для отображения карты.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Контролировать диапазон масштаба отображения карты. С помощью двух кнопок слева и справа определить данный масштаб как минимальный или максимальный масштаб.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Нажать, чтобы использовать текущий масштаб как максимальный масштаб для отображения карты.</p></body></html> Hillshading Затенения холмов Slope Наклон ° ° > > TextLabel Метка текста IDemsList Form Форма To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Чтобы добавить файлы с высотными данными использовать <b>Файл->Настройка пути к ЦМР</b>. Или нажать <a href='setup'><b>здесь</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Использовать контекстное меню (нажать правой кнопкой мышки на элемент), чтобы активировать файл. Использовать перетаскивание мышкой, чтобы переместить активированный файл в порядке обработки. Activate Активировать Move Up Переместить вверх Hide DEM behind previous one Скрыть ЦМР за предыдущей Move down Переместить вниз Show DEM on top of next one Показать ЦМР над следующей Reload DEM Перезагрузить ЦМР IDetailsGeoCache Dialog Диалог Position: Позиция: - - Difficulty Сложность Terrain Местность Update spoilers Обновить спойлеры ... ... about:blank about:blank Hint: Подсказка: TextLabel Метка текста IDetailsOvlArea Dialog Диалог The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Область была импортирована в QMapShack и была изменена. Она больше не показывает исходные данные. Пожалуйста, смотрите в историю изменений. Toggle read only mode. You have to open the lock to edit the item. Переключить режим 'только чтение'. Вы должны открыть замок для изменения элемента. ... ... Color Цвет Border width Ширина границы Style Стиль Opacity Прозрачность Info Сведение Points Точки Position Позиция Hist. История IDetailsPrj Form Форма Keywords: Ключевые слова: - - Keep order of project Сохранить порядок проекта Sort along track (multiple) Отсортировать вдоль трека (кратно) Sort along track (single) Отсортировать вдоль трека (одинарно) ... ... Print diary Печатать дневник Rebuild diary. Перестроить дневник. IDetailsRte Info Сведение The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Маршрут импортирован в QMapShack и был изменен. Он больше не показывает исходные данные. Пожалуйста, смотрите в историю изменений. Toggle read only mode. You have to open the lock to edit the item. Переключить режим 'только чтение'. Вы должны открыть замок для изменения элемента. ... ... - - Hist. История IDetailsTrk Form Форма - - - - Toggle read only mode. You have to open the lock to edit the item. Переключить режим 'только чтение'. Вы должны открыть замок для изменения элемента. ... ... - - Info Сведение Style Стиль Source Источник Maximum Максимум Use/edit user defined visibility of arrows for this track Использовать/изменить определённую пользователем видимость стрелок направления для этого трека Use/edit system's visibility of arrows for all tracks Использовать/изменить системная видимость стрелок направления для всех треков Minimum Минимум Graphs Графики Profile Профиль Width Ширина Use/edit user defined scale factor for this track Использовать/изменить пользовательский коэффициент масштабирования для этого трека Use/edit system's default factor for all tracks Использовать/изменить фактор по умолчанию система для всех треков with arrows со стрелками x х User defined limits for this track Определённые пользователем пределы для этого трека - - - - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Трек был импортирован в QMapShack и был изменен. Он больше не показывает исходные данные. Пожалуйста, смотрите в историю изменений. Automatic limits Автоматическая установка пределов User defined limits for all tracks Определённые пользователем пределы для всех треков Color Цвет max. макс. min. мин. Activity Мероприятие Set Track Activity Добавить мероприятие To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Чтобы получить статистику трека выбрать мероприятие для полного трека из списка. Или выбрать часть трека, чтобы назначить мероприятие. Points Точки Time Время Ele. Высота Delta Разница Dist. Расстояние Speed Скорость Slope Наклон Ascent Подъем Descent Спуск Position Позиция Filter Фильтр Hist. История IDetailsWpt Dialog Диалог Info Сведение Position: Позиция: - - Ele. Высота Proximity: Радиус близости: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Маршрутная точка была импортирована в QMapShack и была изменена. Она больше не показывает исходные данные. Пожалуйста, смотрите в историю изменений. Toggle read only mode. You have to open the lock to edit the item. Переключить режим 'только чтение'. Вы должны открыть замок для изменения элемента. ... ... Date/Time: Дата/время: Add images. Добавить изображения. Delete selected image. Удалить выбранное изображение. Hist. История IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Существует другой проект с таким же именем. Если нажать кнопку 'ОК', он будет удален и заменен. IElevationDialog Edit elevation... Изменить высоту... Elevation Высота - - Get elevation from active digital elevation model. Получить высоту из активной цифровой модели рельефа. ... ... IExportDatabase Export database to GPX... Экспортировать в GPX... ... ... Export Path: Путь для экспорта: - - GPX 1.1 without extensions GPX 1.1 без расширений Start Начать Abort Прервать Close Закрыть IFilterDelete Form Форма <b>Remove Track Points</b> <b>Удалить точки трека</b> Remove all hidden track points permanently. Удалить все скрытые точки безвозвратно. ... ... IFilterDeleteExtension Form Форма <b>Remove Extension from all Track Points</b> <b>Удалить расширение от всех маршрутных точек</b> Remove Удалить from all Track Points от всех точек трека ... ... IFilterDouglasPeuker Form Форма <b>Hide Points (Douglas Peuker)</b> <b>Скрыть точки (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Скрыть точки трека если расстояние до линии между соседними точками меньше чем m м Apply filter now. Применить фильтр. ... ... IFilterInterpolateElevation Form Форма <b>Interpolate Elevation Data</b> <b>Интерполировать высотные данные</b> Replace elevation of track points with interpolated data. Заменить высоты точек трека интерполированными значениями. Quality Качество Preview Просмотр ... ... IFilterInvalid Form Форма Hide Invalid Points Скрыть неверные точки Hide points with invalid data. Скрыть точки с неверными данными. ... ... IFilterMedian Form Форма <b>Smooth Profile (Median Method)</b> <b>Сгладить профиль (метод медиана)</b> Smooth deviation of the track points elevation with a Median filter of size Сгладить отклонение высот точек используя фильтр медиана размера points точек ... ... IFilterNewDate Form Форма <b>Change Time</b> <b>Изменить метки времени</b> Change start of track to Изменить начало трека на dd.MM.yy HH:mm:ss дд.ММ.гг ЧЧ.мм.сс - - ... ... IFilterObscureDate Form Форма <b>Obscure Timestamps</b> <b>Скрыть метки времени</b> Increase timestamp by Увеличить метку времени на sec. сек. with each track point. 0 sec. will remove timestamps. для каждой точки трека. Значение 0 сек.: удалить метки времени. ... ... IFilterOffsetElevation Form Форма <b>Offset Elevation</b> <b>Сместить высоту</b> Add offset of Добавить смещение to track points elevation. к высотам точек трека. ... ... IFilterReplaceElevation Form Форма <b>Replace Elevation Data</b> <b>Заменить высотные данные</b> Replace elevation of track points with the values from loaded DEM files. Заменить высотные данные данными файлов ЦМР. ... ... IFilterReset Form Форма <b>Reset Hidden Track Points</b> <b>Восстановить скрытые точки трека</b> Make all trackpoints visible again. Восстановить все скрытые точки трека. ... ... IFilterSpeed Form Форма <b>Change Speed</b> <b>Изменить скорость</b> Set speed to Установить скорость в km/h км/ч ... ... IFilterSplitSegment Form Форма <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Разделить сегменты в треки</span></p></body></html> Creates a new track for every segment within this track. Создать новый трек для каждого сегмента трека. ... ... IFilterSubPt2Pt Form Форма <b>Convert track subpoints to points</b> <b>Преобразовать подточки трека в точки трека</b> Convert subpoints obtained from routing to ordinary track points Преобразовать подточки полученные от маршрутизации в точки трека ... ... IFilterTerrainSlope Form Вычислить склон местности Форма <b>Calculate Terrain Slope</b> <b>Вычислить склон местности</b> Calculate slope of the terrain based on loaded DEM files. Вычислить склон местности с помощью данных ЦМР. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. Ошибка декодирования FIT: декодер в неверном состоянии %1 после последнего байта в файле. FIT decoding error: a development field with the field_definition_number %1 already exists. Ошибка декодирования FIT: поле развития с номером определения поля %1 уже существует. IGisDatabase Form Форма Name Имя Age Срок To add a database do a right click on the database list above. Для добавления базы данных сделайте щелчок правой кнопкой мышки на списке баз данных. IGisItem [no name] [нет имени] The item is not part of the project in the database. Элемент не является частью проекта в базе данных. It is either a new item or it has been deleted in the database by someone else. Это или новый элемент, или элемент был удален с базы данных кем-то другим. The item is not in the database. Элемент не в базе данных. The item might need to be saved Возможно нужно сохранить элемент Initial version. Исходная версия. Never ask again. Больше не спрашивать. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3> Вероятно, это элемент доступен только для чтения, потому что он не был создан внутри QMapShack. Обычно нет необходимости изменить импортированные данные. Но если для вас это приемлемо нажмите "Да". Read Only Mode... Режим 'только чтения'... <h4>Description:</h4> <h4>Описание:</h4> <p>--- no description ---</p> <p>---нет описания---</p> <h4>Comment:</h4> <h4>Комментарий:</h4> <p>--- no comment ---</p> <p>---нет комментария---</p> <h4>Links:</h4> <h4>Ссылки:</h4> <p>--- no links ---</p> <p>---нет ссылок---</p> Edit name... Изменить имя... Enter new %1 name. Задать новое имя (%1). IGisProject Save project? Сохранить проект? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3> Проект изменен. Сохранить его перед закрытием? %1: Correlate tracks and waypoints. %1: коррелировать треки и маршрутные точки. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3> Было слишком долго? Желаете ли вы пропускать корреляцию треков и маршрутных точек для этого проекта в будущем? Canceled correlation... Корреляция отменена ... Save "%1" to... Сохранить "%1" в... <br/> Filename: %1 <br/> Имя файла: %1 Waypoints: %1 Маршрутные точки: %1 Tracks: %1 Треки: %1 Routes: %1 Маршруты: %1 Areas: %1 Области: %1 Are you sure you want to delete '%1' from project '%2'? Вы уверены что хотите удалить '%1' из проекта '%2'? Delete... Удалить... IGisWorkspace Form Форма Opacity Прозрачность Change the opacity of all GIS Items on the map. Изменить прозрачность всех элементов ГИС на карте. Filter Фильтр Name Имя Clear Filter Очистить фильтр Setup Filter Настройка фильтра IGridSetup Setup Grid... Настройка координатной сетки... Projection Проекция restore default восстановить умолчание ... ... Get projection from current map. Получить проекцию с текущей карты. projection wizzard Мастер проекций Grid color Цвет координатной сетки setup grid color настройка цвета координатной сетки IImportDatabase Form Форма ... ... Source Database: Исходная база данных: - - Target Database: Целевая база данных: Start Начать IInputDialog Edit... Изменить... TextLabel Метка текста ILineOp Routing Маршрутизация ILinksDialog Links... Ссылки... Type Тип Text Текст Uri URI ... ... IMainWindow QMapShack QMapShack File Файл View Вид Window Окно ? ? Tool Инструмент Maps Карты Dig. Elev. Model (DEM) Цифровая модель рельефа (ЦМР) Workspace Рабочая область Toolbar Панель инструментов Routing Маршрутизация Add Map View Добавить окно карты Ctrl+T Ctrl+T Show Scale Показать масштаб Setup Map Font Настройка шрифта карты Show Grid Показать координатную сетку Ctrl+G Ctrl+G Setup Grid Настройка координатной сетки Ctrl+Alt+G Ctrl+Alt+G Flip Mouse Wheel Флип колесо мышки Setup Map Paths Настройка пути к картам POI Text Текст для точек интереса Night / Day Ночь/день Map Tool Tip Подсказка карты Ctrl+I Ctrl+I Setup DEM Paths Настройка пути к ЦМР About О программе Help Справки F1 F1 Setup Map View Настройка вида карт Load GIS Data Загрузить данные ГИС Load projects from file Загрузить проекты с файла Ctrl+L Ctrl+L Save All GIS Data Сохранить все данные ГИС Save all projects in the workspace Сохранить все проекты в рабочей области Ctrl+S Ctrl+S Setup Time Zone Настройка часового пояса Add empty project Добавить пустой проект Search Google Поиск в Google Close all projects Закрыть все проекты F8 F8 Setup Units Настройка единиц Setup Workspace Настройка рабочей области Setup save on exit. Настройка рабочей области. Import Database from QLandkarte Импортировать базу данных QLandkarte Import QLandkarte GT database Импортировать базу данных QLandkarte VRT Builder Создать файл VRT GUI front end to gdalbuildvrt Графический интерфейс к gdalbuildvrt Store Map View Сохранить вид карты Write current active map and DEM list including the properties to a file Сохранить вид карты Load Map View Загрузить вид карты Restore view with active map and DEM list including the properties from a file Tooltip?? Загрузить вид карты Ext. Profile Расширенный профиль Ctrl+E Ctrl+E Close Закрыть Ctrl+Q Ctrl+Q Clone Map View Клонировать вид карты Ctrl+Shift+T Ctrl+Shift+T Create Routino Database Создать базу данных Routino Save(Print) Map Screenshot Сохранить (Печатать) снимок экрана карты Print a selected area of the map Печатать выбранную область карты Ctrl+P Ctrl+P Setup Coord. Format Настройка формата координат Change the format coordinates are displayed Изменить формат отображения координат Setup Map Background Настройка фона карт Setup Waypoint Icons Настройка пиктограмм для маршрутных точек Setup path to custom icons Настройка пути к пользовательским пиктограммам Close Tab Закрыть вкладку Ctrl+W Ctrl+W Quickstart Help Помощь для быстрого старта Setup Toolbar Настройка панели инструментов Toggle Docks Переключить закрепленные окна Toggle visibility of dockable windows Переключить видимость закрепленных окон Ctrl+D Ctrl+D Full Screen Во весь экран F11 F11 Min./Max. Track Values Мин./макс. значения трека Show the minimum and maximum values of the track properties along the track in the map view. Показать минимальные и максимальные значения свойств трека в просмотре карт. Ctrl+N Ctrl+N Database База данных IMapList Form форма To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Чтобы добавить карты использовать <b>Файл->Настройка пути к картам</b>. Или нажать <a href='setup'><b>здесь</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Использовать контекстное меню (нажать правой кнопкой мышки на элемент), чтобы активировать карту. Использовать перетаскивание мышкой, для перемещения активированной карты в порядке рисования. Help! I want maps! I don't want to read the documentation! Помогите! Я хочу карты! Мне не хочется читать документацию! Activate Активировать Move Up Переместить вверх Hide map behind previous map Скрыть карту за предыдущей картой Move down Переместить вниз Show map on top of next map Показать карту над следующей картой Reload Maps Перезагрузить карты IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Эта карта требует поддержки OpenSSL. Однако для соблюдения законов некоторых стран OpenSSL не поставляется с QMapShack. Вы можете посетить <a href='https://www.openssl.org/community/binaries.html'> домашнюю страницу OpenSSL</a> для бинарных файлов. Вы должны скопировать libeay32.dll и ssleay32.dll в папку программы QMapShack. Error... Ошибка... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 плиток ожидается<br/> IMapPathSetup Setup map paths Настройка путей к картам Root path of tile cache for online maps: Корневой путь к кэшу плиток онлайновых карт: - - ... ... Help! I want maps! I don't want to read the documentation! Помогите! Я хочу карты! Мне не хочется читать документацию! IMapPropSetup Form Форма <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Изменить прозрачность карты</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Нажать, чтобы использовать текущий масштаб как минимальный масштаб для отображения карты.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Контролировать диапазон масштаба отображения карты. С помощью двух кнопок слева и справа определить данный масштаб как минимальный или максимальный масштаб.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Нажать, чтобы использовать текущий масштаб как максимальный масштаб для отображения карты.</p></body></html> Areas Области Lines Линии Points Точки Details Деталь Cache Size (MB) Размер кэша (МБ) Expiration (Days) Срок хранения (дни) - - Cache Path Путь к кэшу Type File: Файл типов: Forget external type file and use internal types. Забыть внешний файл типов и использовать внутренние типы. Load an external type file. Загрузить внешний файл типов. IMapVrtBuilder Form Форма Advanced Options Дополнительные параметры Source No Data (-srcnodata) Нет данных в источнике (-srcnodata) Target No Data (-vrtnodata) Нет данных в цели (-vrtnodata) Target Projection (-a_srs) Целевая проекция (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. Эти параметры относятся к частным случаям и обычно не заполняются. Сравните <a href='http://www.gdal.org/gdalbuildvrt.html'>GDAL справка </a> для дополнительной информации. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> <ol> <li>Выберите один или несколько исходных файлов.</li> <li>Выберите имя файла для целевого файла VRT.</li> <li>Нажмите кнопку "Начать".</li> </ol> Намек: <ul> <li>Если у вас несколько файлов, поместите их в подпапку вашей папки к карте. Создайте файл VRT в вашей папки к картам.</li> <li>Используйте дополнительные параметры, чтобы добавить значение для "нет данных", если исходные файлы не имеют этого и не образуют прямоугольную карту. Области без файла карты станут прозрачными.</li> <li>Параметр "-a_srs" предназначен для назначения проекции/датума, когда в исходном файле этого нет. Это НЕ перепроектирует данные.</li> </ul> ... ... Select source files: Выбрать исходные файлы: Target Filename: Имя целевого файла: - - Start Начать IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Новая линия</b><br/>Переместить мышку и использовать левую кнопку мышки, чтобы создать точки. Когда это сделано остановить с помощью правой кнопки мышки.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Удалить точку</b><br/>Переместить мышку близко к точке и нажать левую кнопку, чтобы удалить её.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Выбрать интервал точек</b><br/>Нажать левой кнопкой на первой точке, чтобы начать выбор. Нажать левой кнопкой на второй точке, чтобы завершить выбор и выбрать параметры. Использовать правую кнопку мышки для отмены.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Переместить точку</b><br/>Переместить мышку близко к точке и нажать левую кнопку. Точка будет прилипать к курсору, и вы можете переместить её. Использовать правую кнопку мышки для отмены.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Добавить точку</b><br/>Переместить мышку близко к сегменту линии и нажать левую кнопку, чтобы добавить точку. Точка будет прилипать к курсору, и вы можете переместить его. Отбросьте точку с помощью левой кнопки мышки. Использовать правую кнопку мышки для отмены.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Без маршрутизации</b><br/>Все точки будут соединены прямыми линиями.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Автоматическая маршрутизация</b><br/>Настройка маршрутизатора используется для вычисления маршрута между точками.<b>Замечание</b>Выбранный маршрутизатор должен быть способным вычислять маршруты налету. Оффлайновые маршрутизаторы обычно это могут, Интернет маршрутизаторы этого не могут.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Векторная маршрутизация</b><br/>Если возможно соединить точки линией с загруженной векторной карты.<br/> <b>%1 Metrics</b> <b>%1. Метрика</b> Distance: Расстояние: Ascent: Подъем: Descent: Спуск: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> <br/><b>Переместить карту</b><br/>Если удержите нажатой левую кнопку мышки и переместите мышку, вы будете перемещать карту.<br/><br/> IPhotoAlbum Form Форма ... ... IPlot Reset Zoom Сбросить увеличение Stop Range Отменить интервал Save... Сохранить... Add Waypoint Добавить маршрутную точку Cut... Вырезать... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Удерживать клавишу CTRL для вертикального увеличения. Удерживать клавишу ALT для горизонтального увеличения. No or bad data. Отсутствующие или неверные данные. Select output file Выбрать выходной файл IPositionDialog Position ... Позиция ... Enter new position Ввести новую позицию Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Неверный формат позиции. Должен быть: "[С|Ю] ddd mm.sss [З|В] ddd mm.sss" или "[С|Ю] ddd.ddd [З|В] ddd.ddd" IPrintDialog Print map... Печатать карту... When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. При сохранении онлайн-карты убедитесь, что карта была загружена в кэш в размере печати. Save Сохранить When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. При печати онлайн-карты убедитесь, что карта была загружена в кэш в размере печати. TextLabel Метка текста Print Печатать IProgressDialog Please wait... Пожалуйста, подождите... TextLabel Метка текста IProjWizard Proj4 Wizzard Проекции Proj4 Mercator Меркатор UTM UTM zone Зона user defined Задание пользователя Datum Датум World Mercator (OSM) World Mercator(OSM) Result: Результат: UPS North (North Pole) UPS Север (Северный полюс) UPS South (South Pole) UPS Юг (Южный полюс) Projection Проекция IProjWpt Waypoint Projection Переместить маршрутную точку ... ... - - Clone waypoint and move by: Клонировать маршрутную точку и переместить на: m м ° ° IRouterBRouter Form Форма Profile Профиль Alternative Альтернатива display selected routing profile Отобразить выбранный профиль маршрутизации ... ... on-the-fly routing Маршрутизация на лету BRouter: BRouter: not running Не запущено start/stop BRouter Старт / стоп BRouter show BRouter console Показать консоль BRouter Setup Настройка Caution! BRouter is listening on all ports for connections. Осторожно! BRouter прослушивает все порты для соединений. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, лицензия GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Любезно предоставлены <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> <p>Данные маршрутизации <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a></p> IRouterBRouterInfo BRouter Profile Профиль BRouter TextLabel Метка текста IRouterBRouterSetupWizard BRouter Setup Настройка BRouter choose which BRouter to use Выберите, какой BRouter использовать BRouter-Web (online) BRouter-Web (онлайн) local Installation Локальная установка Expert Mode Экспертный режим local BRouter Installation directory: Папка для локальной установки: select installation directory Выбрать папку установки ... ... labelLocalDirResult labelLocalDirResult create or update installation Создать или обновить установку Java Executable Исполняемый файл Java labelLocalJavaResult labelLocalJavaResult search for installed java Искать установленный Java Download and install BRouter Version Загрузить и установить версия BRouter about:blank about:blank about:blank File to install Файл для установки Download and Install Загрузить и установить available Profiles Доступные профили install profile Установить профиль remove profile Удалить профиль installed Profiles Установленные профили content of profile Содержание профиля BRouter-Web URL: BRouter-Web URL: Service-URL URL для сервисов Profile-URL URL для профилей Hostname Имя узла Port Порт Profile directory Папка для профилей Segments directory Папка для сегментов Custom Profiles dir Папка для настраиваемого профиля Max Runtime Максимальная продолжительность выполнения Number Threads Количество потоков Java Options Параметры Java Profiles Url URL для профилей IRouterMapQuest Form Форма Highways Автомагистрали Seasonal Сезонные дороги Language Язык Country Border Государственная граница Profile Профиль Avoid: Избегать: Ferry Парома Toll Road Платные дороги Unpaved Дороги без покрытия <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Маршрутные направления с разрешением <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Форма Profile Профиль Mode Режим Database База данных Add paths with Routino database. Добавить путь к базе данных Routino. ... ... Language Язык To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Для использования маршрутизации без доступа к сети вам необходимо определить пути к локальным данным маршрутизации. Использовать кнопку настройки чтобы зарегистрировать пути. Вы можете создать свои собственные данные для маршрутизации с помощью <b>Инструмент->Создать базу данных Routino</b>. IRouterRoutinoPathSetup Setup Routino database... Настройка базы данных Routino... ... ... - - IRouterSetup Form Форма IRoutinoDatabaseBuilder Form Форма ... ... Select source files: Выбрать исходные файлы: Start Начать Target Path: Целевой путь: - - File Prefix Префикс файла <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> <p>Чтобы создать базу данных маршрутизации Routino, вам необходимо загрузить файлы *.pbf из <a href='http://download.geofabrik.de/'>GeoFabrik</a>. Процесс создания базы данных Routino довольно медленный, и результирующие файлы довольно большие. Поэтому рекомендуется не загружать целые континенты. Ограничьте загрузку теми странами, которые вам действительно нужны. Однако, поскольку Routino не может маршрутизировать через несколько баз данных, вы должны включить все страны, затронутые трансграничным маршрутом.</p> <ol> <li>Выберите один или несколько исходных файлов *.pbf.</li> <li>Выберите путь для вашей базы данных Routino.</li> <li>Выберите префикс. База данных будет указана с этим префиксом.</li> <li>Нажмите кнопку "Начать".</li> </ol> IScrOptEditLine Form Форма Save to original Сохранить в оригинал Save as new Сохранить как новый Abort Прервать Move points. (Ctrl+M) Переместить точки. (Ctrl+M) ... ... Ctrl+M Ctrl+M Add new points. (Ctrl++) Добавить новые точки. (Ctrl++) Ctrl++ Ctrl++ Select a range of points. (Ctrl+R) Выбрать интервал точек. (Ctrl+R) Ctrl+R Ctrl+R Delete a point. (Ctrl+-) Удалить точку. (Ctrl+-) Ctrl+- Ctrl+- No auto-routing or line snapping (Ctrl+O) Без автоматической маршрутизации и прикрепления к линии (Ctrl+O) 0 0 Ctrl+O Ctrl+O Use auto-routing to between points. (Ctrl+A) Использовать автоматическую маршрутизацию между точками. (Ctrl+A) A A Ctrl+A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Прикрепления линии к линиям векторной карты. (Ctrl+V) V V Ctrl+V Ctrl+V Undo last change Отменить последнее изменение Redo last change Вернуть последнее изменение IScrOptOvlArea Form Форма View details and edit. Показать и изменить детали. ... ... Copy area into another project. Копировать область в другой проект. Delete area from project. Удалить область с проекта. Edit shape of the area. Изменить фигуру области. TextLabel Метка текста IScrOptPrint Form Форма Save selected area as image. Сохранить выбранную область как изображение. ... ... Print selected area. Печатать выбранную область. IScrOptRangeLine Form Форма Delete all points between the first and last one. Удалить все точки между первой и последней. ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Вычислить маршрут между первой и последней выбранной точками.</p></body></html> IScrOptRangeTrk Form Форма Hide all points. Скрыть все точки. ... ... Show all points. Показать все точки. Set an activity for the selected range. Установить мероприятие для выбранного интервала.. Copy track points as new track. Скопировать точки трека в новый трек. TextLabel Метка текста IScrOptRte Form Форма View details and edit. Показать и изменить детали. ... ... Copy route into another project. Скопировать маршрут в другой проект. Delete route from project. Удалить маршрут с проекта. Calculate route. Вычислить маршрут. Reset route calculation. Сбросить маршрутизацию. Move route points. Переместить точки маршрута. Convert route to track Преобразовать маршрут в трек TextLabel Метка текста IScrOptSelect Form Форма Copy all selected items to a project. Скопировать все выбранные элементы в проект. ... ... Create a route from selected waypoints. Создать маршрут с выбранных маршрутных точек. Change the icon of all selected waypoints. Изменить пиктограммы всех выбранных маршрутных точек. Combine all selected tracks to a new one. Объединить все выбранные треки в новый трек. Set an activity for all selected tracks. Установить мероприятие для всех выбранных треков. Delete all selected items. Удалить все выбранные элементы. Select all items that intersect the selected area. Выбрать все элементы, которые пересекают выбранную область. Select all items that are completely inside the selected area. Выбрать все элементы полностью внутри выбранной области. Add tracks to selection. Добавить треки к выбору. Add waypoints to selection. Добавить маршрутные точки к выбору. Add routes to selection. Добавить маршруты к выбору. Add areas to selection. Добавить области к выбору. IScrOptTrk Form Форма View details and edit properties of track. Показать детали и изменить свойства трека. ... ... Copy track into another project. Скопировать трек в другой проект. Delete track from project. Удалить трек с проекта. Show on-screen profile and detailed information about points. Показать на экране профиль и подробные сведения о точках. Select a range of points. Выбрать интервал трека. Edit position of track points. Изменить позиции точек трека. Reverse track. Обратить трек. Combine tracks. Объединить треки. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Разрезать трек в выбранной точки. Можно использовать это чтобы: * удалить неверные точки с начала или с конца трека, * создать новый трек из частей трека, * разрезать длинный трек на меньшие составляющие Set an activity for the complete track. Установить мероприятие для всего трека. Copy track together with all attached waypoints into another project. Скопировать трек вместе со всеми присоединёнными маршрутными точками в другой проект. TextLabel Метка текста IScrOptWpt Form Форма View details and edit. Показать детали и изменить. ... ... Copy waypoint into another project. Скопировать маршрутную точку в другой проект. Delete waypoint from project. Удалить маршрутную точку с проекта. Show content as static bubble. Показать содержимое в статическом пузырьке. Move waypoint to a new location. Переместить маршрутную точку в новую позицию. Clone waypoint and move clone a given distance and angle. Клонировать маршрутную точку и переместить клон на данное расстояние под указанным углом. edit radius of circular area Изменить радиус круга близости Switch between proximity and nogo-area Переключить между кругом близости и запретной зоной Delete circle defined by waypoint Удалить круг близости маршрутной точки TextLabel Метка текста IScrOptWptRadius Form Форма edit radius of circular area Изменить радиус круга близости ... ... Switch between proximity and nogo-area Переключить между кругом близости и запретной зоной Delete circle defined by waypoint Удалить круг близости маршрутной точки TextLabel Метка текста ISearchDatabase Search... Поиск... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Ввести слово, которое желаете найти, и нажать кнопку 'Найти'. Если ввести 'слово', будет произведён поиск с точным совпадением. Если ввести 'слово*', то 'слово' должно быть в начале строки. Name Имя Search Найти Close Закрыть ISelDevices Select devices... Выбрать устройства... ISelectActivityColor Form Форма ISelectCopyAction Copy item... Скопировать элемент... Replace existing item Заменить существующий элемент TextLabel Метка текста Do not copy item Не копировать элемент Create a clone Создать клон Replace with: Заменить на: Keep item: Оставить элемент: The clone's name will be appended with '_Clone' '_клон' будет добавлено к имени клона And for all other items, too. Также для всех остальных элементов. ISelectDBFolder Select Parent Folder... Выбрать корневую папку... Name Имя ISelectDoubleListWidget Form Форма Available Доступно Add to selected items Добавить к выбранным элементам Remove from selected items Удалить из выбранных элементов Selected Выбрано Move selected items up Переместить выбранные элементы вверх Move selected items down Переместить выбранные элементы вниз ... ... ISelectProjectDialog Select a project... Выбрать проект... Select project from list or enter new project name. Выбрать проект со списка или ввести имя нового проекта. New project's name Имя нового проекта New project is created as: Создать новый проект как: *.qms *.qms *.gpx *.gpx Database База данных ISelectSaveAction Copy item... Копировать элемент... Replace existing item Заменить существующий элемент TextLabel Метка текста Do not replace item Не заменять элемент Add a clone Добавить клон The clone's name will be appended with '_Clone' '_клон' будет добавлено к имени клона And for all other items, too. Также для всех остальных элементов. Use item: Использовать элемент: Replace with: Заменить на: ISetupDatabase Add database... Добавить базу данных... Name Имя Server Сервер Port Порт 00000 00000 User Пользователь Password Пароль <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Внимание!</span> Рекомендуется оставить поле пароля пустым, так как QMapShack сохранит его как простой текст. Если нет пароля, то программа будет запрашивать его при каждом запуске.</p> <b>Port:</b> Leave the port field empty to use the default port. <b>Порт:</b> Если оставить поле порт пустым, то будет использоваться порт по умолчанию. Do not use a password. Не использовать пароль. File: Файл: - - Add new database. Добавить новую базу данных. ... ... Open existing database. Открыть существующую базу данных. MySQL MySQL SQLite SQLite ISetupFilter Form Форма Apply filter to Применить фильтр name only только к имени complete text к полному тексту ISetupFolder Database Folder... Папка базы данных... Folder name Имя папки Group Группа Project Проект Other Остальное ISetupNewWpt New Waypoint... Новая маршрутная точка... Symbol Символ ... ... Position Позиция Name Имя Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Неверный формат позиции. Должен быть: "[С|Ю] ddd mm.sss [З|В] ddd mm.sss" или "[С|Ю] ddd.ddd [З|В] ddd.ddd" ISetupWorkspace Setup workspace... Настройка рабочей области... save workspace on exit, and every Сохранять рабочую область при выходе и каждые minutes минут listen for database changes from other instances of QMapShack. On port Прослушивать изменений в базе данных другой работающей QMapShack. Порт 00000 00000 ITemplateWidget Insert Template... Вставить шаблон... Templates Шаблоны Select a path with your own templates. Выбрать путь собственных шаблонов. ... ... Preview Просмотр ITextEditWidget Edit text... Изменить текст... Undo Отменить Ctrl+Z Ctrl+Z Redo Вернуть Ctrl+Shift+Z Ctrl+Shift+Z Cut Вырезать Ctrl+X Ctrl+X Copy Копировать Ctrl+C Ctrl+C Paste Вставить Templ. Шаблон A:L A:L A:C A:C A:R A:R A:B A:B B B I I U U C C Standard Стандарт Bullet List (Disc) Маркированный список (диск) Bullet List (Circle) Маркированный список (круг) Bullet List (Square) Маркированный список (квадрат) Ordered List (Decimal) Упорядоченный список (цифра, арабская) Ordered List (Alpha lower) Упорядоченный список (буква маленькая) Ordered List (Alpha upper) Упорядоченный список (буква большая) Ordered List (Roman lower) Упорядоченный список (цифра, латинская маленькая) Ordered List (Roman upper) Упорядоченный список (цифра, латинская большая) Ctrl+V Ctrl+V Align Left Выровнять по левому краю Ctrl+L Ctrl+L Align Right Выровнять по правому краю Ctrl+R Ctrl+R Align Center Выровнять по центру Ctrl+E Ctrl+E Align Block Выровнять в блок Ctrl+J Ctrl+J Underline Подчеркнуть Ctrl+U Ctrl+U Bold Жирный Ctrl+B Ctrl+B Italic Курсив Ctrl+I Ctrl+I Plain Обычный Reset the text's format before pasting Сбросить форматирование текста до вставки Select All Выделить все Ctrl+A Ctrl+A Delete Удалить Reset Font Сбросить шрифт Reset Layout Сбросить раскладку Normal Нормально Paste without resetting the text's format Вставить без сброса форматирования текста Insert From Template Вставить из шаблона Create text from template. Создать текст из шаблона. ITextEditWidgetSelMenu B B I I U ??? U Cut Вырезать Copy Скопировать Paste Вставить ITimeZoneSetup Setup Time Zone ... Настройка часового пояса... UTC UTC Local Местный Automatic Автоматический Print date/time in Печатать дату/время в long format, or длинном формате, или short format сокращённом формате <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Примечание:</b> Изменение единиц для некоторых элементов графического пользовательского интерфейса вступит в силу только после перезапуска QMapShack. IToolBarSetupDialog Setup Toolbar Настройка панели инструментов Toolbar is visible in Fullscreen-mode Панель инструментов видна в полноэкранном режиме IToolShell Execution of external program `%1` failed: Не удалось выполнить внешнюю программу `%1`: Process cannot be started. Невозможно запустить процесс. Make sure the required packages are installed, `%1` exists and is executable. Убедитесь, что установлены необходимые пакеты, `%1` существует и разрешено его исполнение. External process crashed. Крах внешнего процесса. An unknown error occurred. Случилась неизвестная ошибка. !!! failed !!! !Не удалось! IUnit Error Ошибка Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Неверный формат позиции. Должен быть: "[С|Ю] ddd mm.sss [З|В] ddd mm.sss" или "[С|Ю] ddd.ddd [З|В] ddd.ddd" Position values out of bounds. Значения позиции вне допустимого интервала. IUnitsSetup Setup units... Настройка единиц измерения... Length unit Единица длины Nautic Морские Imperial Британские Metric Метрические Slope unit Единица спуска Degrees (°) Градус (°) Percent (%) Процент (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Примечание:</b> Изменение единиц для некоторых элементов графического пользовательского интерфейса вступят в силу только после перезапуска QMapShack. IWptIconDialog Icons... Пиктограммы... External Icons: Внешние пиктограммы: - - ... ... All custom icons have to be *.bmp or *.png format. Все пользовательские пиктограммы должны быть в *.bmp или *.png формате. qmapshack-1.10.0/src/locale/qmapshack_ca.ts000644 001750 000144 00001526234 13216421215 021745 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2, s'esperava V%3) %1 (API V%2) %1 (API V%2) (no DBUS: device detection and handling disabled) (no DBUS: la detecció i manipulació de dispositius està desactivada) CActivityTrk Foot A peu Bicycle Bicicleta Motor Bike Moto Car Cotxe Cable Car Telefèric Swim Natació Ship Vaixell Ski/Winter Esquí/Hivern No Activity Sense activitat Total Total Ascent: Ascens: Descent: Descens: Aeronautics Aeronàutica Public Transport Transport Públic Distance: Distància: Speed Moving: Velocitat en Moviment: Speed Total: Velocitat Total: Time Moving: Temps en Moviment: Time Total: Temps Total: CCanvas View %1 Vista %1 Setup Map Background Configura el Fons del Mapa CColorChooser Esc. Esc. CCommandProcessor Print debug output to console. Imprimeix la sortida de depuració a la consola. Print debug output to logfile (temp. path). Imprimeix la sortida de depuració al fitxer de registre (temp. camí). Do not show splash screen. No mostrar la pantalla de presentació. File with QMapShack configuration. Fitxer amb configuració QMapShack. file Fitxer Files for future use. Fitxers per a utilitzar més endavant. CCreateRouteFromWpt route Ruta CDBFolderLostFound All your data grouped by folders. Totes les teves dades agrupades en carpetes. Lost & Found (%1) Perdut i trobat (%1) Lost & Found Perdut i trobat CDBFolderMysql All your data grouped by folders. Totes les teves dades agrupades en carpetes. MySQL Database Base de Dades MySQL Server: Servidor: (No PW) (No PI) Error: Error: CDBFolderSqlite All your data grouped by folders. Totes les teves dades agrupades en carpetes. SQLite Database Base de Dades SQLite File: Fitxer: Error: Error: CDBItem %1 min. %1 min. %1 h %1 h %1 days %1 dia CDBProject Failed to load... No s'ha pogut carregar... Can't load file "%1" . It will be skipped. No s'ha pogut carregar el fitxer "%1% . S'ometrà l'element. Project already in database... El Projecte ja és a la base de dades... The project "%1" has already been imported into the database. It will be skipped. El projecte "%1" ja és a la base de dades. S'ometrà l'element. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database %2 (%3) ha modificat l'element %1. Per a resolver aquest conflicte heu de crear i desar una còpia idèntica, forçar la vostra versió o deixar-la estar I agafar-ne una de la base de dades Conflict with database... Conflicte amb la base de dades... Clone && Save Clona && Desa Force Save Desa forçosament Take remote Agafa'l remot Missing folder... Manca la carpeta... Failed to save project. The folder has been deleted in the database. No s'ha pogut desar el projecte. La carpeta s'ha esborrat de la base de dades. Save ... Desa... Error Error There was an unexpected database error: %1 S'ha produït un error inesperat a la base de dades: %1 The project '%1' is about to update itself from the database. However there are changes not saved. El projecte '%1' és a punt de modificar-se desde la base de dades. Tanmateix hi ha canvis que no s'han desat. Save changes? Desar els canvis? CDemList Deactivate Desactivar Activate Activar CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Afegir o suprimir camins a dades DEM. Pot haver-hi diverses fitxers en un camí, però els camins secundaris no s'analitzaran. Els formats compatibles són: %1 Select DEM file path... Selecciona el camí als fitxers DEM... CDemVRT Error... Error... Failed to load file: %1   No s'ha pogut carregar el fitxer: %1 DEM must have one band with 16bit or 32bit data. Les dades DEM han de tenir un ample de banda de 16bit o 32bit. No georeference information found. No s'ha trobat informació de georeferència. CDetailsGeoCache none cap ??? ??? Searching for images... Cercant imatges... No images found   No s'ha trobat cap imatge CDetailsPrj You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Voleu ordenar les fites al llarg d'un track, pero la correlació entre track i fita està desactivada. La voleu tornar a activar? Correlation... Correlació... none Cap Build diary... Crea el registre... <b>Summary over all tracks in project</b><br/> <b>Resum de tots els tracks del projecte</b><br/> <h2>Waypoints</h2> <h2>Fites</h2> Info Info Comment Comentari <h2>Tracks</h2> <h2>Pistes</h2> From Start Des de l'inici To Next Al Següent To End Al Final Distance: Distància: Ascent: Ascens: Descent: Descens: <h2>Areas</h2> <h2>Àrees</h2> <h2>Routes</h2> <h2>Rutes</h2> Edit name... Edita el nom... Enter new project name. Introdueix el nom del nou projecte. Edit keywords... Edita les paraules clau... Enter keywords. Introduïu les paraules clau. Print Diary Imprimir Diari CDetailsTrk Reduce visible track points Redueix els punts visibles del track Change elevation of track points Canvia l'elevació dels punts del track Change timestamp of track points Canvia la data i hora dels punts del track Miscellaneous Miscel·lània Color Color Activity Activitat CDetailsWpt Enter new proximity range. Introducció d'un nou interval de proximitat. CDeviceGarmin Picture%1 Imatge%1 Unknown Desconegut CDeviceGarminArchive Archive - expand to load Arxiu - amplia per a carregar Archive - loaded S'ha carregat l'arxiu CElevationDialog No DEM data found for that point. No s'han trobat dades DEM per aquest punt. CExportDatabase Select export path... Selecciona el camí d'exportació... CExportDatabaseThread Create %1 Crear %1 Failed to create %1 S'ha produït un error al crear %1 Done! Fet ! Abort by user! Cancel·lat per l'usuari! Database Error: %1 Error de base de dades: %1 Save project as %1   Desa el projecte com a %1 Failed! S'ha produït un error! CFilterDeleteExtension No extension available No hi ha extensions disponibles CFilterInterpolateElevation coarse ample medium mitjà fine fi CFitCrcState FIT decoding error : invalid CRC. Error descodificant el fitxer FIT: CRC invàlid. CFitDecoder FIT decoding error: unexpected end of file %1. Error descodificant el fitxer FIT: Final de fitxer inesperat %1. CFitFieldBuilder FIT decoding error: unknown base type %1. Error descodificant el fitxer FIT: tipus base desconegut %1. CFitFieldDataState Missing field definition for development field. Manca la definició del camp pel camp desenvolupament. FIT decoding error: invalid field def nr %1 while creating dev field profile. Error descodificant el fitxer FIT: Definició numèrica invàlida en el camp %1 en crear la definició del perfil del camp. CFitHeaderState FIT decoding error: protocol %1 version not supported. Error descodificant el fitxer FIT: la versió del protocol %1 no està implementada. FIT decoding error: file header signature mismatch. File is not FIT. Error descodificant el fitxer FIT: la capçalera de signatura del fitxer no coincideix. No és un fitxer FIT. CFitProject Failed to load file %1...   No s'ha pogut carregar el fitxer %1... Failed to open FIT file %1.   No s'ha pogut obrir el fitxer FIT %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. Error descodificant el fitxer FIT: No està implementada l'arquitectura %1 . FIT decoding error: invalid offset %1 for state 'record content' Error descodificant el fitxer FIT: desplaçament no vàlid %1 en l'estat 'contingut del registre' CGarminTyp Warning... Avís... This is a typ file with unknown polygon encoding. Please report! Aquest és un típus de fitxer amb una codificació de polígon desconeguda. Informeu de l'error! This is a typ file with unknown polyline encoding. Please report! Aquest és un típus de fitxer amb una codificació de polilínia desconeguda. Informeu de l'error! CGisItemOvlArea thin prim normal normal wide ample strong fort _Clone _Clona Area: %1%2 Àrea: %1%2 Changed area shape. Forma de l'àrea canviada. Changed name. Nom canviat. Changed border width. Amplada del contorn canviada. Changed fill pattern. Patró d'emplenar canviat. Changed opacity. Opacitat canviada. Changed comment. Comentari canviat. Changed description. Descripció canviada. Changed links Enllaços canviats Changed color Color canviat CGisItemRte _Clone _Clona track track Changed name. Nom canviat. Changed comment Comentari canviat Changed description Descripció canviada Changed links Enllaços canviats Length: %1%2 Llargada: %1%2 Time: %1%2 Temps: %1%2 Distance: %1%2 Distància: %1%2 Length: - Llargada: - Time: - Temps: - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Enrutat per darrera vegada :<br/>%1 with %1 amb %1 Changed route points. Punts de la ruta canviats. CGisItemTrk FIT file %1 contains no GPS data. El fixer FIT %1 no conté dades GPS. Error... Error... Failed to open %1. Error en obrir %1. Only support lon/lat WGS 84 format. Sols s'admet lon/lat en format WGS 84. Failed to read data. Error en llegir les dades. _Clone _Clona Changed trackpoints, sacrificed all previous data. Punts del track canviats, les dades antigues s'han perdut. , %1-, %2- , %1-, %2- Time: %1%2, Speed: %3%4 Temps: %1%2, Velocitat: %3%4 Time: -, Speed: - Temps: -, Velocitat: - Moving: %1%2, Speed: %3%4 Moviment: %1%2, Velocitat: %3%4 Moving: -, Speed: - Moviment: -, Velocitat: - Start: %1 Inici: %1 Start: - Inici: - End: %1 Final: %1 End: - Final: - Points: %1 (%2) Punts: %1 (%2) Invalid elevations! Elevacions invàlidess! Invalid timestamps! Marques horàries invàlides ! Invalid positions! Posicions no vàlides! Activities: %1 Activitats: %1 Index: %1 Index: %1 Index: visible %1, total %2 Índex: visible %1, total %2 , Slope: %1%2 , Pendent: %1%2 ... and %1 tags not displayed ... I no es mostren %1 etiquetes Distance: - (-) Distància: - (-) Moving: - (-) En moviment: - (-) track track Hide point %1. Amagar punt %1. Hide points %1..%2. Amagar punts %1..%2. , %1%2 , %1%2 Invalid points.... punts invàlids.... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? El track '%1' té %2 punts invàlids dels %3 punts que es mostren. Vols amagar els punts invàlids? min. mín. max. màx. Length: %1%2 Longitud: %1%2 , %1%2%3, %4%5%6 , %1%2%3, %4%5%6 Ele.: %1%2 Ele.: %1%2 , Speed: %1%2 , Velocitat: %1%2 Ascent: - (-) Ascens: - (-) Descent: - (-) Descens: - (-) Ascent: %1%2 (%3%) Ascens: %1%2 (%3%) , Descent: %1%2 (%3%) , Descens: %1%2 (%3%) Distance: %1%2 (%3%) Distància: %1%2 (%3%) , Moving: %1%2 (%3%) , En moviment: %1%2 (%3%) Ascent: - Ascens: - Descent: - Descens: - Ascent: %1%2 Ascens: %1%2 , Descent: %1%2 , Descens: %1%2 Distance: %1%2 Distància: %1%2 , Time: %1%2 , Hora: %1%2 Permanently removed points %1..%2 S'han suprimit definitivament els punts %1..%2 Show points. Mostrar els punts. Changed name Nom canviat Changed comment Comentari canviat Changed description Descripció canviada Changed links Enllaços canviats Changed elevation of point %1 to %2 %3 Elevació dels punts %1 to %2 %3 canviada Changed activity to '%1' for complete track. Activitat de tot el track canviada a '%1'. Changed activity to '%1' for range(%2..%3). Activitat del rang(%2..%3) canviada a '%1'. Hide points by Douglas Peuker algorithm (%1%2) Utilitzar l'algoritme de Douglas Peuker per amagar punts (%1%2) Hide points with invalid data. Amagar punts amb dades invàlides. Reset all hidden track points to visible Fes visibles tots els punts amagats del track Permanently removed all hidden track points S'han suprimit definitivament tots els punts amagats del track. Smoothed profile with a Median filter of size %1 Perfil suau utilitzant un filtre de Mitjana de mida %1 Added terrain slope from DEM file. S'ha afegit des d'un fitxer DEM el pendent d'un terreny. Replaced elevation data with data from DEM files. Substituides les dades d'elevació amb les dades dels fitxers DEM Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Substituides les dades d'elevació amb valors interpolats. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Desplaçament de les dades d'elevació de %1%2. Changed start of track to %1. Inici del track canviat a %1. Remove timestamps. Suprimeix les marques horàries. Set artificial timestamps with delta of %1 sec. Posa una marca horària inventada amb %1 sec. de valor delta. Changed speed to %1%2. Velocitat canviada a %1%2. %1 (Segment %2) %1 (Segment %2) Removed extension %1 from all Track Points S'ha suprimit definitivament l'extensió %1 de tots els punts del track. Converted subpoints from routing to track points Convertir els subpunts obtinguts d'un itinerari a punts de track Copy flag information from QLandkarte GT track Copia del track de QLandkarte GT la informació de l'indicador CGisItemWpt Archived Arxivat Available Disponible Not Available No disponible _Clone _Clona Elevation: %1%2 Elevació: %1%2 Proximity: %1%2 Proximitat: %1%2 Changed name Nom canviat Changed position Posició canviada Changed elevation Elevació canviada Removed proximity Changed proximity Proximitat canviada Changed icon Icona canviada Changed comment Comentari canviat Changed description Descripció canviada Changed links Enllaços canviats Changed images Imatges canviades Add image Afegir imatge Changed to proximity-radius Changed to nogo-area CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Degut a canvis en el sistema de base de dades, QMapShack desconeix el nom de fitxer de la vostre base de dades '%1'. Heu de seleccionar-la de nou en el següent pas. Select database file. Selecciona el fitxer de base de dades Add Database Afegeix base de dades Add Folder Afegir Carpeta Rename Folder Canvia el nom de la Carpeta Copy Folder Copia la carpeta Move Folder Moure Carpeta Delete Folder Suprimeix Carpeta Import from Files... Importar de Fitxers... Export to GPX... Exportar a GPX... Delete Item Esborrar l'element Search Database Cercant Base de Dades Sync. with Database Sinc. amb Base de Dades Remove Database Suprimir base de dades Empty Buit Remove database... Suprimir base de dades... Do you really want to remove '%1' from the list? Esteu segur que voleu suprimir '%1' de la llista? Delete database folder... Elimina la carpeta de les bases de dades... Are you sure you want to delete selected folders and all subfolders from the database? Segur que voleu suprimir de la base de dades les carpetes seleccionades i totes les subcarpetes? Bad operation.... Operació incorrecta... The target folder is a subfolder of the one to move. This will not work. La carpeta destí és una subcarpeta d'una de les que voleu moure. No es pot fer aquesta operació. Folder name... Nom de la carpeta... Rename folder: Canvia el nom de la carpeta: Remove items... Suprimir elements... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Voleu esborrar tots els elements de Perdut i Trobat? Això els eliminarà de forma permament. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Voleu esborrar tots els elements seleccionats de Perdut i Trobat? Això els eliminarà de forma permament. Are you sure you want to delete '%1' from folder '%2'? Segur que voleu suprimir '%1' de la carpeta '%2'? Delete... Suprimeix... Import GIS Data... Importar Dades GIS... CGisListWks Edit.. Edita... Show on Map Mostra en el Mapa Hide from Map Amagar del Mapa Sort by Time Ordena per Hora Sort by Name Ordena per Nom Save Desa Save as GPX 1.1 w/o ext... Desa com a GPX 1.1 sense ext... Send to Devices Envia als Dispositius Sync. with Database Sinc. amb Base de Dades Close Tanca Update Project on Device Modifica el Projecte en el Dispositiu Delete Suprimeix Edit... Edita... Copy to... Copia a... Autom. Save Desa autom. Save as... Anomena i desa... Track Profile Perfil del Track Select Range Selecciona Rang Edit Track Points Edita els Punts del Track Reverse Track Invertir Track Combine Tracks Unir Tracks Copy Track with Waypoints Copia el track amb les Fites Show Bubble Mostra la Bombolla Move Waypoint Moure la Fita Proj. Waypoint... Proj. Fita... Change Radius Toggle Nogo-Area Delete Radius Route Instructions Instruccions de l'Itinerari Calculate Route Calcular l'Itinerari Reset Route Reinicia Ruta Edit Route Edita la Ruta Convert to Track Convertir a track Edit Area Points Edita els Punts de l'Àrea Create Route Crear Ruta Change Icon (sel. waypt. only) Canviar Icona (sols sel. fita) Set Track Activity Assigna una Activitat al Track Drop items... Deixar anar elements... <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Modifica els dispositius </b><p>Modifica %1<br/>Si us plau, espereu...</p> Saving workspace. Please wait. S'està desant l'espai de treball. Espera. Loading workspace. Please wait. S'està carregant l'espai de treball. Espera. Close all projects... Tancar tots els projectes... This will remove all projects from the workspace. S'eliminaran tots els projectes de l'espai de treball. Delete project... Suprimeix el projecte... Do you really want to delete %1? Esteu segur que voleu suprimir %1? CGisWorkspace Load project... Carregar projecte... The project "%1" is already in the workspace. El projecte "%1" ja és a l'espai de treball. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Selecció d'Element: </b>Element seleccionat de la llista d'espais de treball. Feu clic en el mapa per tornar al comportament normal de selecció del ratolí. Copy items... Copia elements... Change waypoint symbols. Canviar el símbol de les fites. Cut Track... Tallar el Track... Do you want to delete the original track? Voleu suprimir el track original? CGpxProject Failed to load file %1... Error en carregar el fitxer %1... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Not a GPX file: %1 No és un fitxer GPX: %1 File exists ... El fitxer existeix ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Aquest fitxer ja existeix i no s'ha creat a QMapShack. Si premeu 'si' es perdrà tota la informació d'aquest fitxer. Fins i tot si aquest fitxer té informació GPX i s'ha carregat a QMapShack, QMapShack no pot carregar i emmagatzemar tota la informació existent en aquest fitxer. La informació es perdrà. Recomano utilitzar un altre fitxer. <b>Segur que voleu sobreescriure el fitxer?</b> Failed to create file '%1' Ha fallat la creació del fitxer '%1' Failed to write file '%1' Error en escriure al fitxer '%1' Saving GIS data failed... Error desant dades GIS... CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1m, %2m N %1m, E %2m N %1m, E %2m CHistoryListWidget by %1 de %1 Cut history before Talla l'historial abans de Cut history after Talla l'historial després de History removal Supresión de l'historial The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> La supressió és permanent i no es pot desfer. <b>Realment vols suprimir tot l'historial abans de fer aquest pas?</b> CImportDatabase Import QLandkarte Database Importar Base de Dades QLandkarte Select source database... Selecciona la base de dades origen... Select target database... Selecciona la base de dades destí... CKnownExtension Speed extLongName Velocitat Cadence extShortName Cadència Air Temp. extShortName Temp. de l'Aire Air Temperature extLongName Temperatura de l'Aire Water Temp. extShortName Temp. de l'Aigua Water Temperature extLongName Temperatura de l'Aigua Depth extShortName Profunditat Depth extLongName Profunditat Heart R. extShortName Ritme cardíac Heart Rate extLongName Ritme cardíac Cadence extLongName Cadencia Speed extShortName Velocitat Accel. extShortName Accel. Acceleration extLongName Accel·leració Course extShortName Camí Course extLongName Camí Temp. extShortName Temp. Temperature extLongName Temperatura Dist. extShortName Dist. Distance extLongName Distància Ele. extShortName Ele. Elevation extLongName Elevació Energy extShortName Energia Energy extLongName Energia Sea Lev. Pres. extShortName Pres Niv. Mar. Sea Level Pressure extLongName Pressió a Nivell de Mar v. Speed extShortName v. Velocitat Vertical Speed extLongName Velocitat Vertical Slope extShortName Pendent Speed over Distance* extLongName Velocitat per Distància* Speed over Time* extLongName Velocitat per Temps* Elevation* extLongName Elevació* Progress extShortName Progrés Progress* extLongName Progrés* Terr. Slope extShortName Terr. Pendent Terrain Slope* extLongName Terreny Pendent* Slope* Pendent* CLogProject Failed to load file %1... Error en carregar el fitxer %1... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Not an Openambit log file: %1 No és un fitxer de registre Openambit: %1 Device: %1<br/> Dispositiu: %1<br/> Recovery time: %1 h<br/> Temps de recuperació: %1 h<br/> Peak Training Effect: %1<br/> Efecte de la Sessió d'Entrenament: %1<br/> Energy: %1 kCal<br/> Energia: %1 kCal<br/> Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 Aquest fitxer de LOG no conté cap dada i QMapShack no el pot visualitzar: %1 CLostFoundProject Lost & Found Perdut i trobat CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Utilitza <b>Menu->Vista->Afegir vista de Mapa</b> per a obrir una nova vista. O <b>Menu->Fitxer->Carregar vista de Mapa</b> per a recuperar-ne un de desat. O feu clic <a href='newview'>aquí</a>. Ele.: %1%2 Ele.: %1%2 Slope: %1%2 terrain Pendent: %1%2 [Grid: %1] [Graella: %1] Load GIS Data... Carregar Dades GIS... Select output file Selecciona el fitxer de sortida QMapShack View (*.view) Vista QMapShack (*.view) Select file to load Selecciona el fitxer a carregar Fatal... Fatal... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack ha detectat que la llibreria Proj4 no està instal·lada de forma correcte. Manquen les taules de conversió de les projeccions EPSG, emmagatzemades de normal a /usr/share/proj. Per a solucionar-ho contacteu el mantenidor del paquet de la distribució. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. En aquest moment no hi ha cap mapa instal·lat. QMapShack no es diverteix si no té mapes. Podeu instal·lar-ne prement la tecla 'Ajuda. Vull mapes!' a la finestra 'Mapes' de l'acoblador. O bé, podeu prémer la tecla F1 per accedir a la documentació en línia que us explicarà com utilitzar QMapShack. Si no es diverteix, perquè no l'hi doneu mapes? Per allotjar mapes a punt per a descarregar I instal·lar fa falta un bon servidor. I això no és un servei gratuït. El projecte no te els diners. A més, els mapes I les dades DEM tenen drets d'autor. Per tant, abans d'empaquetar les dades s'ha de demanar permís al propietari dels drets d'autor. Tot això no és tan senzill com sembla i, en alguns casos s'han de pagar royalties. El projecte simplement no disposa dels recursos necessaris per fer-ho. I pensem que no és excessiu demanar-vos que ho feu vosaltres mateixos. Després de tot el programari es distribueix sense cap càrrec. CMapIMG Failed ... Ha fallat ... Unspecified Sense especificar French Francès German Alemany Dutch Holandes English Anglès Italian Italià Finnish Finlandés Swedish Suec Spanish Espanyol Basque Basc Catalan Català Galician Gallec Welsh Gal·lès Gaelic Gaèlic Danish Danès Norwegian Noruec Portuguese Portuguès Slovak Eslovac Czech Txec Croatian Croat Hungarian Hongarès Polish Polonès Turkish Turc Greek Grec Slovenian Eslovè Russian Rus Estonian Estonià Latvian Letó Romanian Romanès Albanian Albanès Bosnian Bosnià Lithuanian Lituà Serbian Serbi Macedonian Macedoni Bulgarian Búlgar Major highway Autopista Principal highway Autovia Other highway Autovia Arterial road Carretera nacional Collector road Carretera comarcal Residential street Carrer Alley/Private road Carretera privada Highway ramp, low speed Enllaç autopista, baixa velocitat Highway ramp, high speed Enllaç autopista, alta velocitat Unpaved road Carretera sense asfaltar Major highway connector Enllaç d'autopistes Roundabout Rotonda Railroad Ferrocarril Shoreline Línia de costa Trail Camí Stream Rierol Time zone Zona horaria Ferry Transbordador State/province border Frontera provincial County/parish border Frontera estatal International border Frontera internacional River Riu Minor land contour Corba de nivell mínima Intermediate land contour Corba de nivell intermèdia Major land contour Corba de nivell màxima Minor depth contour Corba de profunditat mínima Intermediate depth contour Corba de profunditat intermèdia Major depth contour Corba de profunditat màxima Intermittent stream Riera Airport runway Pista d'aterratge Pipeline Oleoducte Powerline Línia d'alta tensió Marine boundary Límit marí Hazard boundary Límit de risc Large urban area (&gt;200K) Àrea urbana gran (&gt;200K) Small urban area (&lt;200K) Àrea urbana petita (&lt;200K) Rural housing area Entorn rural Military base Base militar Parking lot Aparcament Parking garage Garatge Airport Aeroport Shopping center Centre comercial Marina Port University/College Universitat/Institut Hospital Hospital Industrial complex Zona industrial Reservation Reserva Man-made area Zona artificial Sports complex Complex esportiu Golf course Camp de golf Cemetery Cementiri National park Parc Nacional City park Parc urbà State park Parc nacional Forest Bosc Ocean Oceà Blue (unknown) Blau (Desconegut) Sea Mar Large lake Llac gran Medium lake Llac mitjà Small lake LLac petit Major lake Llac Major River Riu Large River Riu Medium River Riu Small River Rierol Intermittent water Zona inundable Wetland/Swamp Aiguamolls / Pantà Glacier Glacera Orchard/Plantation Hort / Camp de cultiu Scrub Matolls Tundra Tundra Flat Pla ??? ??? Read external type file... Llegir un tipus de fitxer extern... Failed to read type file: %1 Fall back to internal types. Error en la lectura del tipus de fitxer: %1 Retorn als típus interns.. Failed to read: Error en llegir: Failed to open: Error en obrir: Bad file format: Format de fitxer incorrecte: Failed to read file structure: Error en llegir l'estructura del fitxer: Loading %1 S'està carregant %1 User abort: Interromput per l'usuari: File is NT format. QMapShack is unable to read map files with NT format: El fixer estates en format NT. QMapShack no és capaç de llegir fitxers de mapes en format NT: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. El fitxer conté dades bloquejades / xifrades. Garmin sols permet utilitzar aquest fitxer amb programari subministrat per Garmin. Point of Interest Fita Unknown Desconegut Area Àrea CMapList Deactivate Desactivat Activate Activat Where do you want to store maps? On vols desar els mapes? CMapMAP Failed ... Ha fallat ... Failed to open: Error en obrir: Bad file format: Format de fitxer incorrecte: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Afegir o suprimir camins a mapes. Pot haver-hi diversos mapes en un camí, però els camins secundaris no s'analitzaran. Els formats compatibles són: %1 Select map path... Selecciona el camí als mapes... Select root path... Selecciona el camí arrel... CMapPropSetup Select type file... Selecciona el tipus de fitxer... CMapRMAP Error... Error... This is not a TwoNav RMAP file. No és un fitxer RMAP de TwoNav. Unknown sub-format. Subformat desconegut. Unknown version. Versió desconeguda Failed to read reference point. Error en llegir el punt de referència. Unknown projection and datum (%1%2). Projecció i datum desconeguts (%1%2). CMapTMS Error... Error... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Layer %1 Capa %1 CMapVRT Error... Error... Failed to load file: %1 Error en carregar el fitxer: %1... File must be 8 bit palette or gray indexed. El fitxer ha de tenir una paleta de 8 bits o escala de grisos. No georeference information found. No s'ha trobat informació de georeferència. CMapVrtBuilder Build GDAL VRT Creació de GDAL VRT Select files... Selecciona els fitxers... Select target file... Selecciona el fitxer destí... !!! done !!! !!! fet !!! CMapWMTS Error... Error... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Failed to read: %1 Unknown structure. No s'ha pogut llegir: %1 Estructura desconeguda. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Servei inesperat. S'esperava'* WMTS 1.0.0'. S'ha llegit '%1 %2'. No georeference information found. No s'ha trobat informació de georeferència. CMouseEditArea Area Àrea <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Editar Àrea</b><br/>Selecciona una funció i un mode d'itinerari utilitzant els botons d'eines. Desprès, selecciona un punt de la línia. Només es poden canviar els punts assenyalats amb un quadrat gran. Els assenyalats amb un punt negre són subpunts que ha creat l'enrutament.<br/> area àrea CMouseEditRte Route Itinerari <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Editar Punts de Ruta</b><br/>Selecciona una funció i un mode d'itinerari utilitzant els botons d'eines. Desprès, selecciona un punt de la línia. Només es poden canviar els punts assenyalats amb un quadrat gran. Els assenyalats amb un punt negre són subpunts que ha creat l'enrutament.<br/> route itinerari CMouseEditTrk Track Track <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Editar Punts de Track</b><br/>Selecciona una funció i un mode d'itinerari utilitzant els botons d'eines. Desprès, selecciona un punt de la línia. Només es poden canviar els punts assenyalats amb un quadrat gran. Els assenyalats amb un punt negre són subpunts que ha creat l'enrutament.<br/> Warning! Avís! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Substitueix totes les dades originals per una simple línia de coordenades. Totes les altres dades es perdran definitivament. track track CMouseNormal Add POI as Waypoint Afegir Punt d'Interès com una Fita Add Waypoint Afegir Fita Add Track Afegir Track Add Route Afegir Ruta Add Area Afegir Àrea Select Items On Map Selecciona elements en el Mapa Copy position Copia la posició Copy position (Grid) Copia la posició (Graella) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Desa (Imprimeix) Mapa</b><br/>Selecciona una area rectangular en el mapa. Fes clic en el botó esquerra del ratolí i mou el ratolí. Fes clic al botó dret per interrompre. Per a ajustar la selecció apunta-fes clic-mou el ratolí a les cantonades. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Selecció de l'Interval</b><br/>Amb el botó esquerra del ratolí selecciona el primer punt del track. I després un segon. Fent un clic al botó esquerra del ratolí surts de la selecció de l'interval.<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Seleccionar Elements del Mapa</b><br/>Selecciona una àrea rectangular en el mapa. Fes clic en el botó esquerra del ratolí i mou el ratolí. Fes clic al botó dret per interrompre. Per a ajustar la selecció apunta-fes clic-mou el ratolí a les cantonades. <b>Selected:</b><br/> <b>Seleccionats:</b><br/> %1 waypoints<br/> %1 fites<br/> %1 tracks<br/> %1 tracks<br/> %1 routes<br/> %1 rutes<br/> %1 areas<br/> %1 àrees<br/> CPhotoAlbum Select images... Selecciona imatges... CPlot Distance [%1] Distància [%1] Time Hora CPlotProfile Distance [%1] Distància [%1] Ele. [%1] Ele. [%1] CPrintDialog Print Map... Imprimir Mapa... Save Map as Image... Desa el mapa com a imatge... Printer Properties... Propietats de la impresora... Pages: %1 x %2 Pàgines: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Per a canviar la resolució fes Zoom en el mapa de sota amb la roda del ratolí: %1x%2 píxel x: %3 m/px y: %4 m/px Printing pages. Impressió de les pàgines. Save map... Desa el mapa... CProgressDialog Elapsed time: %1 Temps transcorregut: %1 Elapsed time: %1 seconds. Temps transcorregut: %1 segons. CProjWizard north nord south sud Error... Error... The value '%1' is not a valid coordinate system definition: %2 El valor '%1' no és una coordenada vàlida en la configuración activa: %2 CProjWpt Edit name... Edita el nom... Enter new waypoint name. Introduïu un nom nou a la fita. CQlbProject Failed to open... Error en obrir... Failed to open %1 Error en obrir %1 Could not convert... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. CQlgtDb Migrating database from version 4 to 5. S'està migrant la base de dades de la versió 4 a la 5. Migrating database from version 5 to 6. S'està migrant la base de dades de la versió 5 a la 6. Migrating database from version 6 to 7. S'està migrant la base de dades de la versió 6 a la 7. Migrating database from version 7 to 8. S'està migrant la base de dades de la versió 7 a la 8. Migrating database from version 8 to 9. S'està migrant la base de dades de la versió 8 a la 9. Open database: %1 Obrir la base de dades: %1 Folders: %1 Carpetes: %1 Tracks: %1 Tracks: %1 Routes: %1 (Only the basic route will be copied) Itineraris: %1 (Sols es copiaran els itineraris bàsics) Waypoints: %1 Fites: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Superposicions: %1 (les àrees es convertiran a àrees, les línies de distància es convertiran a tracks, les altres superposicions es perdran) Diaries: %1 Diaris: %1 Map selections: %1 (can't be converted to QMapShack) Selecció de Mapes: %1 (no es pot convertir a QMapShack) ------ Start to convert database to %1------ ------ Inicia la conversió de la base de dades a %1------ Failed to create target database. Ha fallat la creació de la base de dades destinació. ------ Abort ------ ------ Interrompre ------ ------ Done ------ ------ Fet ------ Restore folders... Restaura les carpetes... Imported %1 folders and %2 diaries S'han importat %1 carpetes i %2 diaris Copy items... Copia elements... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas S'han importat %1 tracks, %2 fites, %3 rutes, %4 àrees Import folders... Importar de carpetes... Overlay of type '%1' cant be converted No es pot convertir una superposició de tipus '%1' CQlgtTrack Corrupt track ... Track Corrupte... Number of trackpoints is not equal the number of training data trackpoints. El nombre de punts del track no és igual al nombre de punts del track amd dades d'entrenament. Number of trackpoints is not equal the number of extended data trackpoints. El nombre de punts del track no és igual al nombre de punts de track amb dades ampliades. Number of trackpoints is not equal the number of shadow data trackpoints. El nombre de punts del track no és igual al nombre de punts del track amb dades complementaries. CQmsDb Existing file... Fitxer existent... Remove existing %1? Suprimir %1 existents? Remove existing file %1 Suprimir el fitxer existent %1 %1: drop item with QLGT DB ID %2 %1: deixa anar l'element amb QLGT DB ID %2 CQmsProject Failed to open... Error en obrir... Failed to open %1 Error en obrir %1 CRouterBRouter original original first alternative primera alternativa second alternative segona alternativa third alternative tercera alternativa BRouter (offline) BRouter (desconnectat) BRouter (online) BRouter (connectat) profile: %1, alternative: %2 perfil: %1, alternativa: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade response is empty resposta buida Bad response from server: %1 Resposta dolente del servidor: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... <b>BRouter</b><br/>La petició d'Itinerari s'ha enviat al servidor. Si us plau, espereu... Calculate route with %1 Calcular l'itinerari amb %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <b>BRouter</b><br/>Resposta dolenta del servidor:<br/>%1 <br/>Calculation time: %1s <br/>Calculant el temps: %1s Error Error running correr starting iniciant QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. QMapShack es comunica amb BRouter mitjançant una connexió de xarxa. De normal, això es fa mitjançant una adreça especial a la que no ets pots connectar des de fora del dispositiu. Tanmateix BRouter escolta les connexions de totes les interfícies disponibles. No hi ha cap problema si estàs connectat a una xarxa privada amb un tallafocs actiu. Si estàs connectat a una xarxa pública, cada un dels ports que tinguis oberts representa un risc que algú pot utilitzar per atacar el sistema. En aquest cas, no es recomana utilitzar BRouter. Warning... Avís... I understand the risk. Don't tell me again. Entenc el risc. No m'ho diguis un altre cop. stopped Aturat not installed No instal·lat online En línia CRouterBRouterSetup %1 not accessible %1 no és accessible %1 invalid result %1 resultat invàlid Error parsing online-config: Error en analitzar la configuració en línia: Network error: Error de xarxa: CRouterBRouterSetupWizard Restore Default Values Restaura els Valors per Defecte Open Directory Obrir Directori select Java Executable Selecciona l'Executable Java please select BRouter installation directory si us plau, selecciona el directori on instal·lar BRouter selected directory does not exist El directori seleccionat no existeix create directory and install BRouter there Crea un directori i hi instal·les BRrouter existing BRouter installation BRouter ja està instal·lat update existing BRouter installation actualitzar la instal·lació existent de BRouter empty directory, create new BRouter installation here el directori està buit, crea una nova instal·lació de BRouter create new BRouter installation Crea una nova instal·lació de BRouter seems to be a valid Java-executable sembla que el Java-executable és vàlid doesn't seem to be a valid Java-executable no sembla que el Java-executable sigui vàlid Java Executable not found No s'ha trobat l'Executable Java Error loading installation-page at %1 Error en carregar la pàgina d'instal·lació a %1 no brouter-version to install selected No s'ha seleccionat la versión per a instal·lar de brouter selected %1 for download and installation %1 seleccionats per a baixar I instal·lar Warning... Avís... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. Baixada: %1<br/><br/>Es baixarà I s'instal·lara un fitxer zip des d'un servidor de baixades quen no compleix cap dels standards de seguretat normalment acceptats, utilitza HTTP en text pla. De normal s'hauria d'utilitzar HTTPS. Correu el risc que algú redireccioni la petició i baixeu un fitter zip amb codi maliciós. QMapShack no pot detectar-ho. <br/>Si no enteneu l'explicació o teniu algum dubte, no seguiu I cancel·leu la operació. Com a alternativa podeu utilizer la plana Web de BRouter. I understand the risk and wish to proceed. Entenc el risc i vull continuar. download %1 started iniciada la baixada %1 Network Error: %1 Error de xarxa: %1 download %1 finished finalitzada la baixada %1 unzipping: descomprimint: ready. preparat. download of brouter failed: %1 error en la baixada de brouter: %1 retrieving available profiles from %1 Recuperant desde %1 els perfils disponibles content of profile contingut del perfil Error: Error: Error creating directory %1 S'ha produït un error en crear el directori %1 Error directory %1 does not exist Error el directori %1 no existeix Error creating file %1 S'ha produït un error en crear el fitxer %1 Error writing to file %1 S'ha produït un error en escriure al fitxer %1 CRouterBRouterTilesPage Continue with Setup Continuar amb la Configuració CRouterBRouterTilesSelect available routing-data is being determined. S'està determinant els itineraris disponibles. Select outdated Selecciona obsolets Clear Selection Elimina la Selecció Delete selection Suprimeix selecció Download Baixada Error removing %1: %2 S'ha produït un error en suprimir %1: %2 Error creating segments directory %1 Error en la creació de segments en el directori %1 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) actualitzat: %1 (%2), obsolets: %3 (%4), per a baixar: %5 (%6) being downloaded: %1 of %2 s'està baixant: %1 of %2 no local data, online available: %1 (%2) no hi ha dades locals, disponibles en línia: %1 (%2) local data outdated (%1, %2 - remote %3, %4) les dades locals estan obsoletes (%1, %2 - remotes %3, %4) Network Error Error de xarxa invalid result, no files found Resultat invàlid, no s'han trobat fitxers cannot parse: %1 is not a date no es pot analitzar: %1 no es una data cannot parse: %1 is not a valid size no es pot analitzar: %1 la mida no és vàlida Error retrieving available routing data from %1: %2 Error en la recuperació de les dades d'enrutament disponibles a %1: %2 segments directory does not exist: el directori de segments no existeix: error creating file %1: %2 Error en la creació del fitxer %1: %2 no valid request for filename %1 la sol·licitud amb aquest nom de fitxer no és vàlida %1 no open file assigned to request for %1 no hi ha cap fitxer obert per aquesta sol·licitud %1 error writing to file %1: %2 Error en escriure al fitxer %1: %2 error renaming file %1 to %2: %3 Error en canviar el nom del fitxer %1 a %2: %3 local data up to date (%1, %2) dades locals actualitzades (%1, %2) no routing-data available No hi ha itineraris disponibles CRouterBRouterToolShell !!! done !!! !!! fet !!! !!! failed !!! !!! ha fallat !!! CRouterMapQuest Fastest Més ràpid Shortest Més curt Bicycle Bicicleta Pedestrian Vianant US English Anglés US British English Angles Britànic Danish Danés Dutch Holandés French Francés German Alemany Italian Italià Norwegian Noruec Spanish Espanyol Swedish Suec mode "%1" mode "%1" no highways evitar autopistes no toll roads evitar carreteres de peatge no seasonal no estacional no unpaved evitar carreteres sense asfaltar no ferry no hi ha ferry no crossing of country borders no creuar fronteres de països <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>La petició d'Itinerari s'ha enviat al servidor. Si us plau, espereu... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Resposta dolente del servidor:<br/>%1 <br/>Calculation time: %1s <br/>Calculant el temps: %1s CRouterRoutino Warning... Avís... Found Routino with a wrong version. Expected %1 found %2 S'ha trobat una versió incorrecte de Routino. S'esperava %1 s'ha trobat %2 Shortest Més curt Quickest Més ràpid Foot Peu Horse Cavall Wheelchair Cadira de rodes Bicycle Bicicleta Moped Ciclomotor Motorcycle Moto Motorcar Cotxe amb motor Goods Béns English Anglès German Alemany French Francès Hungarian Hongarès Dutch Holandes Russian Rus Polish Polac A function was called without the database variable set. S'ha fet una crida a una funció sense estar activat l'entorn de variables de la base de dades. A function was called without the profile variable set. S'ha cridat a una funció sense establir les variables del perfil. A function was called without the translation variable set. S'ha cridat a una funció sense establir les variables de la traducció. The specified database to load did not exist. La base de dades especificada per carregar no existeix. The specified database could not be loaded. La base de dades especificada no es pot carregar. The specified profiles XML file did not exist. El perfil XML especificat no existeix. The specified profiles XML file could not be loaded. El perfil XML especificat no es pot carregar. The specified translations XML file did not exist. El fitxer de traducció XML especificat no existeix. The specified translations XML file could not be loaded. El fitxer de traducció XML especificat no es pot carregar. The requested profile name does not exist in the loaded XML file. El nom de perfil sol·licitat no existeix en el fitxer XML carregat. The requested translation language does not exist in the loaded XML file. En el fitxer XML carregat no existeix la traducció a aquest idioma. In the routing database there is no highway near the coordinates to place a waypoint. A la base de dades de rutes no existeix cap autopista propera a les coordenades per a posar-hi una fita. The profile and database do not work together. El perfil i la base de dades no són compatibles. The profile being used has not been validated. El perfil utilitzat no ha estat validat. The user specified profile contained invalid data. El perfil d'usuari especificat conté dades invàlides. The routing options specified are not consistent with each other. Les opciones especificades en l'itinerary no son coherentes entre si. There is a mismatch between the library and caller API version. No hi ha coincidència entre la llibreria i la versió de crida a la API. Route calculation was aborted by user. L'usuari ha interromput el càlcul de la ruta. A route could not be found to waypoint %1. No s'ha trobat cap ruta cap a la fita %1. Unknown error: %1 Error desconegut %1 profile "%1" perfil "%1" , mode "%1" , mode "%1" Calculate route with %1 Calcular l'itinerari amb %1 <br/>Calculation time: %1s <br/>Calculant el temps: %1s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Afegir o suprimir camins a dades Routino. Pot haver-hi diverses bases de dades en un camí, però els camins secundaris no s'analitzaran. Select routing data file path... Selecciona el camí dels fitxers amb dades d'itineraris... CRouterSetup Routino (offline) Routino (desconnectat) MapQuest (online) MapQuest (en línia) BRouter (online) BRouter (en línia) CRoutinoDatabaseBuilder Create Routino Database Crea una Base de Dades Routino Select files... Selecciona fitxers... Select target path... Selecciona el camí destí... !!! done !!! !!! fet !!! CScrOptRangeTrk No range selected No s'ha seleccionat cap interval CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Mode exacte</b><br/>Tots els elements han d'estar del tot dins de l'àrea seleccionada.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Mode d'intersecció</b><br/>Tots els elements han d'estar dins o com a mínim han d'interseccionar amb l'àrea seleccionada.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Afegir Tracks</b><br/>Afegir tracks a la llista d'elements seleccionats<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Afegir Fites</b><br/>Afegir fites a la llista d'elements seleccionats<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Afegir Itineraris</b><br/>Afegir itineraris a la llista d'elements seleccionats<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Afegir Àrees</b><br/>Afegir les àrees en la lista d'elements seleccionats<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Ignora Tracks</b><br/>Ignora tracks de la llista d'elements seleccionats<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Ignora Fites</b><br/>Ignora fites a la llista d'elements seleccionats<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Ignora Itineraris</b><br/>Ignora itineraris de la llista d'elements seleccionats<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> <b>Ignorar les Àrees</b><br/>Ignorar les àrees en la lista d'elements seleccionats<br/> CSearchDatabase Search database '%1': Cercant la base de dades '%1': CSearchGoogle Unknown response Resposta desconeguda Error: Error: CSetupDatabase Missing Requirement Manca Requeriment MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. No es pot utilitzar MySQL ja que el controlador (QMYSQL) no està disponible.<br />Assegureu-vos d'haver instal·lat els paquets necessaris.<br />Si en aquest moment no sabeu que fer <a href="%1">podeu donar un cop d'ull a la wiki</a>. Error... Error... There is already a database with name '%1' Ja existeix una base de dades amb nom '%1' New database... Nova base de dades... Open database... Obrir base de dades... CSetupWorkspace Setup database... Configura la base de dades... Changes will become active after an application's restart. Els canvis s'activaran després del reinici d'una aplicació. CSlfProject Failed to load file %1... Error en carregar el fitxer %1... CSlfReader Failed to parse timestamp `%1` Ha fallat l'anàlisi de la marca horària `%1` %1 does not exist %1 no existeix Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Not a SLF file: %1 No és un fitxer SLF: %1 Unsupported revision %1: %2 Revisió incompatible %1: %2 Break %1 Divisió %1 Lap %1 Volta %1 CSmlProject Failed to load file %1... Error en carregar el fitxer %1... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Not an sml file: %1 No és un fitxer sml: %1 Recovery time: %1 h<br/> Temps de recuperació: %1 h<br/> Peak Training Effect: %1<br/> Efecte de la Sessió d'Entrenament: %1<br/> Energy: %1 kCal<br/> Energia: %1 kCal<br/> Device: %1<br/> Dispositiu: %1<br/> Battery usage: %1 %/hour Ús de la bateria: %1 %/hores Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This SML file does not contain any position data and can not be displayed by QMapShack: %1 Aquest fitxer SML no conté cap dada i QMapShack no el pot visualitzar: %1 CTableTrk Double click to edit elevation value Doble clic per editar el valor de l'elevació %1%2 %1%2 CTcxProject Failed to load file %1... Error en carregar el fitxer %1... Failed to open %1 Error en obrir %1 Failed to read: %1 line %2, column %3: %4 Error en llegir %1 línia %2, columna %3: %4 Not a TCX file: %1 No és un fitxer TCX: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Aquest fitxer TCX conté almenys 1 exercici, però cap activitat o camí. Els exercicis que no tenen dades de posició, no es poden importar a QMapShack. This TCX file does not contain any activity or course: %1 Aquest fitxer TCX no conté cap activitat ni cap camí: %1 File exists ... El fitxer ja existeix ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Aquest fitxer ja existeix i no s'ha creat a QMapShack. Si premeu 'si' es perdrà tota la informació d'aquest fitxer. Fins i tot si aquest fitxer té informació i s'ha carregat a QMapShack, QMapShack no pot carregar i emmagatzemar tota la informació existent en aquest fitxer. La informació es perdrà. Recomano utilitzar un altre fitxer. Segur que voleu sobreescriure el fitxer? The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> El track <b>%1</b> que heu seleccionat conté punts de track amb marques horàries invàlides. Pot ser que el dispositiu no accepti el fitxer de camí TCX que s'ha generat si ho deixeu així. <b>Voleu aplicar un filtre amb velocitat constant de (10 m/s) i continuar?</b> Course Camí Activity Activitat Cancel Cancel·la Track with invalid timestamps... Track amb marques horàries invàlides... Activity or course? Activitat o camí? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack no sap en quin format vols desar el track <b>%1</b> . <b>El vols desar com a camí o com a activitat ? </b>Si el deseu com a camí, sols es desaran les fites molt properes al track. Si el deseu com a activitat les fites no es desaran. Failed to create file '%1' Ha fallat la creació del fitxer '%1' Failed to write file '%1' Error en escriure al fitxer '%1' Saving GIS data failed... Error desant dades GIS... CTemplateWidget choose one... Escolliu-ne un... Hiking Tour Summary (built-in) Resum del Recorregut de Senderisme (intern) - - Template path... Cami de les Plantilles... Failed to read template file %1. No s'ha pogut llegir el fitxer de plantilla %1. Preview... Previsualització... CTextEditWidget &Color... &Color... Reset format Reinicia format CToolBarSetupDialog Available Actions Accions Disponibles Selected Actions Accions Seleccionades CTwoNavProject Error... Error... Failed to open %1. Error en obrir %1. Save GIS data to... Desa les dades GIS a... Only support lon/lat WGS 84 format. Sols s'admet lon/lat en format WGS 84. Failed to read data. Error en llegir les dades. CWptIconDialog Path to user icons... Camí a les icones de l'usuari... Form Form Formulari Participants Participants Weather Meteorologia rain pluja sunny assolellat snow neu clouds nuvols windy ventades hot càlid warm temperat cold fred freezing gelades foggy boira humid humitat Character Caràcter easy hiking caminada fàcil climbing escalada alpine alpí large ascend pujada llarga long distance llarga distància via ferrata via ferrada hail/soft hail calamarsa/calamarsa suau Rating Valoració Rating 5 stars Valoració 5 estrelles Rating 4 stars Valoració 4 estrelles Rating 3 stars Valoració 3 estrelles Rating 2 stars Valoració 2 estrelles Rating 1 star Valoració 1 estrella aborted Interromput Equipment Equipament ferrata gear equip per a vies ferrades night gear equipació nocturna snow shoes sabates de neu climbing gear equip d'escalada ski esquí camping gear equip de càmping Details Detalls IAbout About.... Quant a.... <b>QMapShack</b>, Version <b>QMapShack</b>, Versió TextLabel EtiquetaDeText Qt Qt GDAL GDAL Proj4 Proj4 Routino Routino Czech: Txec: Pavel Fric Pavel Fric German: Alemany: Oliver Eichler Oliver Eichler Dutch: Holandes: Harrie Klomp Harrie Klomp French: Francès: Rainer Unseld Rainer Unseld Jose Luis Domingo Lopez Jose Luis Domingo Lopez Spanish: Espanyol: <b>Translation:</b> <b>Traducció:</b> Russian: Rus: Wolfgang Thämelt Wolfgang Thämelt Win64: Win64: OS X: OS X: Helmut Schmidt Helmut Schmidt Ivo Kronenberg Ivo Kronenberg <b>Binaries:</b> <b>Binaris:</b> ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ...I molted gràcies a tots els mantenidors dels binaris Linux pel gran treball que fan. Agraïments especials a Dan Horák i Bas Couwenberg per la seva presencia a les llistes de discusió de temes relacionats amb les distribucions. <b>Contributors:</b> <b>Col·laboradors:</b> Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Aquest programari es distribueix sota llicència GPL3 o qualsevol altre versió posterior © 2017 Oliver Eichler (oliver.eichler@gmx.de) © 2017 Oliver Eichler (oliver.eichler@gmx.de) ICanvasSetup Setup Map View... Configurar la Vista Mapa... Projection & Datum Projecció & Datum ... ... Scales Escales Logarithmic Logarítmic Square (optimized for TMS and WMTS tiles) Quadrat (optimitzat per tesel·les TMS i WMTS) IColorChooser Dialog Diàleg ICombineTrk Combine Tracks... Unir Tracks... Available Tracks Tracks Disponibles ... ... Combined Tracks Tracks units ICoordFormatSetup Coordinate Format... Format de les coordenades... N48° 53' 39.6" E13° 31' 6.78" N48° 53' 39.6" E13° 31' 6.78" N48.8943° E013.51855° N48.8943° E013.51855° N48° 53.660 E013° 31.113 N48° 53.660 E013° 31.113 ICreateRouteFromWpt Create Route from Waypoints Crear una ruta des de fites. ... ... ICutTrk Cut Track Tallar el Track Delete first part of the track and keep second one Suprimir la primera part del track i mantenir la segona Keep both parts of the track Mantenir les dues parts del track Keep first part of the track and delete second one Mantenir la primera part del track i suprimir la segona Cut Mode: Mode de Tall: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Marca això si voleu guardar el resultat en un track nou. Si manteniu totes dues parts del track n'heu de crear de noves. Si sols voleu mantenir una part suprimiu els punts, o marqueu això per a crear un track nou. Create a new track Crea un nou track IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Ha canviat el format de base de dades pròpi de '%1'. QMapShack migrarà ara la teva base de dades. Després de la migració no es podrà utilitzar la base de dades amb versions antigues de QMapShack. Es recomana fer una còpia de la base de dades abans d'iniciar la operació. Migrate database... Migrar base de dades... Migration aborted by user L'usuari ha interromput la migració Failed to migrate '%1'. Error en la migració de '%1'. Error... Error... Migration failed Error en la migració The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. La version de la base de dades '%1' és més moderna que la instal·lada a QMapShack. No funcionarà. Initialization failed Error en la inicialització Wrong database version... Versió incorrecte de la base de dades... Database created by newer version of QMapShack S'ha creat la base de dades amb la versió més recent de QMapShack Failed to initialize '%1'. Error en la inicialització de '%1'. IDBMysql Password... Contrasenya... Password for database '%1': Contrasenya de la base de dades '%1': Update to database version 5. Migrate all GIS items. Actualitzar la base de dades a la versió 5. Migrar tots els elements GIS. IDBSqlite Update to database version 3. Migrate all GIS items. Actualitzar la base de dades a la versió 3. Migrar tots els elements GIS. Update to database version 5. Migrate all GIS items. Actualitzar la base de dades a la versió 5. Migrar tots els elements GIS. Update to database version 6. Migrate all GIS items. Actualitzar la base de dades a la versió 6. Migrar tots els elements GIS. IDemPathSetup Setup DEM file paths Configurar els camins als fitxers DEM ... ... - - IDemPropSetup Form Formulari <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Canvia l'opacitat del mapa</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Click per utilitzar l'escala actual com a escala mínima per a visualitzar el mapa.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Controla els intervals de l'escala en que es mostra el mapa. Utilitza els botons esquerra i dreta per a definir l'escala actual i el màxim i mínim de l'escala.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Click per utilitzar l'escala actual com a escala màxima per a visualitzar el mapa.</p></body></html> Hillshading Relleu ombrejat Slope Pendent ° ° > > TextLabel EtiquetaDeText IDemsList Form Formulari To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Per afegir fitxers amb dades d'elevació feu <b>Fitxer->Configurar camins DEM</b>. O feu clic <a href='setup'><b>aquí</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Utilitza el menú contextual (clic al botó dret del ratolí o entrada) per activar un fitxer. Utilitzar arrossega I deixa anar per a moure el fitxer activat en el procés de selecció. Activate Activar Move Up Mou amunt Hide DEM behind previous one Amagar DEM darrere de l'anterior Move down Mou avall Show DEM on top of next one Mostra el DEM a sobre del següent Reload DEM Tornar a carregar DEM IDetailsGeoCache Dialog Diàleg Position: Posició: - - Difficulty Dificultat Terrain Terreny Update spoilers Actualitzar spoilers ... ... about:blank about:blank Hint: Consell: TextLabel EtiquetaDeText IDetailsOvlArea Dialog Diàleg The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Aquesta àrea s'ha importat a QMapShack I ha estat modificada. Ja no es poden mostrar les dades originals. Si us plau, mireu el historial per veure les modificacions. Toggle read only mode. You have to open the lock to edit the item. Commuta el mode de només lectura. S'ha de desbloquejar l'element per a editar-lo. ... ... Color Color Border width Amplada de la vora Style Estil Opacity Opacitat Info Info Points Punts Position Possició Hist. Hist. IDetailsPrj Form Formulari Keywords: Paraules clau: - - Keep order of project Mantenir l'ordre del projecte Sort along track (multiple) Ordena al llarg del track (diversos) Sort along track (single) Ordena al llarg del track (un de sol) ... ... Print diary Imprimir diari Rebuild diary. Reconstrueix el diari. IDetailsRte Info Info The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Aquesta ruta s'ha importat a QMapShack I ha estat modificada. Ja no es poden mostrar les dades originals. Si us plau, mireu el historial per veure les modificacions. Toggle read only mode. You have to open the lock to edit the item. Commuta el mode de només lectura. S'ha de desbloquejar l'element per a editar-lo. ... ... - - Hist. Hist. IDetailsTrk Form Formulari - - - - Toggle read only mode. You have to open the lock to edit the item. Commuta el mode de només lectura. S'ha de desbloquejar l'element per a editar-lo. ... ... - - Info Info Style Estil Source Origen Maximum Màxim Use/edit user defined visibility of arrows for this track Utilitza/edita mostrar fletxes de direcció en el track Use/edit system's visibility of arrows for all tracks Utilitza/edita mostrar fletxes de direcció en tots els tracks Minimum Mínim Graphs Gràfics Profile Perfil Width Amplada Use/edit user defined scale factor for this track Utilitza/edita l'escala del track definida per l'usuari Use/edit system's default factor for all tracks Utilitza/edita el valor per defecte de l'escala a tots els tracks with arrows amb fletxes x x User defined limits for this track Límits d'aquest track definits per l'usuari  - - - - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Aquest track s'ha importat a QMapShack I ha estat modificat. Ja no es poden mostrar les dades originals. Si us plau, mireu el historial per veure les modificacions. Automatic limits Límits automàtics User defined limits for all tracks Límits per a tots els tracks definits per l'usuari Color Color max. màx. min. min. Activity Activitat Set Track Activity Assigna una Activitat al Track To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Per a tenir estadístiques dels tracks, seleccionar de la llista una activitat per a tot el track. O assigneu una activitat a una part del track. Points Punts Time Temps Ele. Alt. Delta Delta Dist. Dist. Speed Velocitat Slope Pendent Ascent Ascens Descent Descens Position Possició Filter Filtre Hist. Hist. IDetailsWpt Dialog Diàleg Info Info Position: Possició: - - Ele. Alt. Proximity: Proximitat: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. La fita es va importar a QMapShack i es va modificar. Ja no es poden mostrar les dades originals. Vegeu l'historial de canvis. Toggle read only mode. You have to open the lock to edit the item. Commuta el mode de només lectura. S'ha de desbloquejar l'element per a editar-lo. ... ... Date/Time: Data/Hora: Add images. Afegir imatges. Delete selected image. Suprimeix la imatge seleccionada. Hist. Hist. IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Ja existeix un projecte amb el mateix nom. Si premeu el botó 'ok' el suprimireu i el substituireu pel nou. IElevationDialog Edit elevation... Editar elevació... Elevation Altura - - Get elevation from active digital elevation model. Obtenir l'elevació del model d'elevació digital actiu ... ... IExportDatabase Export database to GPX... Exportar base de dades a GPX... ... ... Export Path: Exportar Camí: - - GPX 1.1 without extensions GPX 1.1 sense extensions Start Inici Abort Aborta Close Tancar IFilterDelete Form Formulari <b>Remove Track Points</b> <b>Suprimeix Punts del Track</b> Remove all hidden track points permanently. Suprimeix definitivament els punts amagats del track. ... ... IFilterDeleteExtension Form Formulari <b>Remove Extension from all Track Points</b> <b>Suprimir l'extensió de tots els Punts del Track</b> Remove Suprimeix from all Track Points desde tots els Punts del Track ... ... IFilterDouglasPeuker Form Formulari <b>Hide Points (Douglas Peuker)</b> <b>Amagar Punts (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Amagar els punts del track que estiguin a una distància d'un altre inferior a m m Apply filter now. Aplica ara el filtre. ... ... IFilterInterpolateElevation Form Formulari <b>Interpolate Elevation Data</b> <b>Interpolar Dades d'Elevació</b> Replace elevation of track points with interpolated data. Substitueix l'elevació dels punts del track amb dades interpolades Quality Qualitat Preview Previsualització ... ... IFilterInvalid Form Formulari Hide Invalid Points Amagar Punts Invàlids Hide points with invalid data. Amagar punts amb dades invàlides. ... ... IFilterMedian Form Formulari <b>Smooth Profile (Median Method)</b> <b>Perfil Suau (Median Mètode)</b> Smooth deviation of the track points elevation with a Median filter of size Desplaçament suau dels punts d'elevació del track utilitzant un filtre de Mitjana de mida points punts ... ... IFilterNewDate Form Formulari <b>Change Time</b> <b>Canviar l'Hora</b> Change start of track to Caviar l'inici del track a dd.MM.yy HH:mm:ss dd.MM.aa HH:mm:ss - - ... ... IFilterObscureDate Form Formulari <b>Obscure Timestamps</b> <b>Marques horàries inhabituals</b> Increase timestamp by Incrementa la marca horària en sec. seg. with each track point. 0 sec. will remove timestamps. amb cada punt del track. 0 sec. es suprimiran les marques horàries. ... ... IFilterOffsetElevation Form Formulari <b>Offset Elevation</b> <b>Desplaçament de la Elevació</b> Add offset of Afegir un desplaçament de to track points elevation. a les elevacions dels punts del track. ... ... IFilterReplaceElevation Form Formulari <b>Replace Elevation Data</b> <b>Substitueix les Dades d'Elevació</b> Replace elevation of track points with the values from loaded DEM files. Substitueix l'elevació dels punts del track amb els valors carregats des dels fitxers DEM. ... ... IFilterReset Form Formulari <b>Reset Hidden Track Points</b> <b>Reinicia els Punts Amagats del Track</b> Make all trackpoints visible again. Tornar a mostrar tots els punts del track ... ... IFilterSpeed Form Formulari <b>Change Speed</b> <b>Canviar Velocitat</b> Set speed to Estableix la velocitat a km/h km/h ... ... IFilterSplitSegment Form Formulari <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Divideix els segments en Tracks</span></p></body></html> Creates a new track for every segment within this track. Crea un nou track per a cada un dels segments existents al track. ... ... IFilterSubPt2Pt Form Formulari <b>Convert track subpoints to points</b> <b>Convertir a punts els subpunts del track</b> Convert subpoints obtained from routing to ordinary track points Convertir els subpunts obtinguts d'un itinerari a punts de track normals ... ... IFilterTerrainSlope Form Formulari <b>Calculate Terrain Slope</b> <b>Calcular el Pendent del Terreny</b> Calculate slope of the terrain based on loaded DEM files. Calcular el pendent d'un terrent basant-se en fitxers DEM carregats. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. Error decodificant FIT: L'estat del decodificador no és correcte %1 després del darrer byte del fitxer. FIT decoding error: a development field with the field_definition_number %1 already exists. Error decodificant FIT: ja existeix un camp de desenvolupament amb field_definition_number %1. IGisDatabase Form Formulari Name Nom Age Edat To add a database do a right click on the database list above. Per afegir una base de dades feu clic en el botó dret sobre la llista de bases de dades. IGisItem [no name] [sense nom] The item is not part of the project in the database. L'element no forma part del projecte a la base de dades. It is either a new item or it has been deleted in the database by someone else. Es tracta d'un element nou o bé algú l'ha esborrat de la base de dades. The item is not in the database. L'element no existeix a la base de dades. The item might need to be saved És possible que s'hagi de desar l'element Initial version. Versió inicial. Never ask again. No tornar-ho a preguntar. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3> Aquest element probablement és sols de lectura perquè no es va crear amb QMapShack. Normalment no voldreu canviar les dades importades. Però si ho heu de fer premeu 'Ok'. Read Only Mode... Mode de només lectura... <h4>Description:</h4> <h4>Descripció:</h4> <p>--- no description ---</p> <p>--- sense descripció ---</p> <h4>Comment:</h4> <h4>Comentari:</h4> <p>--- no comment ---</p> <p>--- sense comentari ---</p> <h4>Links:</h4> <h4>Enllaços:</h4> <p>--- no links ---</p> <p>--- sense enllaços ---</p> Edit name... Edita el nom... Enter new %1 name. Introduir el Nou nom per a %1. IGisProject Save project? Desar el projecte? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>El projecte ha canviat. El voleu desar abans de tancar-lo? %1: Correlate tracks and waypoints. %1: Correlacionar tracks i fites. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>Va ser massa llarg per a tu? Per a d'altres cops, vols ometre en aquest projecte la correlació dels tracks i les fites? Canceled correlation... Correlació cancel·lada... Save "%1" to... Desa "%1" a... <br/> Filename: %1 <br/> Nom del fitxer: %1 Waypoints: %1 Fites: %1 Tracks: %1 Tracks: %1 Routes: %1 Itineraris: %1 Areas: %1 Àrees: %1 Are you sure you want to delete '%1' from project '%2'? Esteu segur que voleu suprimir '%1' del projecte '%2'? Delete... Suprimir... IGisWorkspace Form Formulari Opacity Opacitat Change the opacity of all GIS Items on the map. Canvia l'opacitat de tots els elements GIS del kapa. Filter Filtre Name Nom Clear Filter Neteja el Filtre Setup Filter Configura el Filtre IGridSetup Setup Grid... Configurar Graella... Projection Projecció restore default restaura valor per defecte ... ... Get projection from current map. Obtenir la projecció del mapa actual. projection wizzard assistent de projecció Grid color Color de la Graella setup grid color configurar el color de la graella IImportDatabase Form Formulari ... ... Source Database: Base de Dades origen: - - Target Database: Base de Dades destí: Start Inici IInputDialog Edit... Edita... TextLabel EtiquetaDeText ILineOp Routing Enrutament ILinksDialog Links... Enllaços... Type Tipus Text Text Uri Uri ... ... IMainWindow QMapShack QMapShack File Fitxer View Vista Window Finestra ? ? Tool Eina Maps Mapes Dig. Elev. Model (DEM) Model Dig. Elev. (DEM) Workspace Espai de treball Toolbar Barra d'eines Routing Enrutament Add Map View Afegir Vista de Mapa Ctrl+T Ctrl+T Show Scale Mostra l'Escala Setup Map Font Configurar el Tipus de Lletra del Mapa Show Grid Mostra la Graella Ctrl+G Ctrl+G Setup Grid Configurar Graella Ctrl+Alt+G Ctrl+Alt+G Flip Mouse Wheel Gira la Roda del Ratolí Setup Map Paths Configurar els Camins a Mapes POI Text Text del PI Night / Day Nit / Dia Map Tool Tip Consell Eina Mapa Ctrl+I Ctrl+I Setup DEM Paths Configurar els Camins a DEM About Quant a Help Ajuda F1 F1 Setup Map View Configurar la Vista Mapa Load GIS Data Carregar Dades GIS Load projects from file Carregar projectes des d'un fitxer Ctrl+L Ctrl+L Save All GIS Data Desa totes les dades GIS Save all projects in the workspace Desa tots els projectes existents a l'espai de treball Ctrl+S Ctrl+S Setup Time Zone Configurar la Zona Horària Add empty project Afegir un projecte buit Search Google Cerca a Google Close all projects Tancar tots els projectes F8 F8 Setup Units Configurar Unitats Setup Workspace Configuració de l'espai de treball Setup save on exit. Desa la configuració en sortir. Import Database from QLandkarte Importar Base de Dades de QLandkarte Import QLandkarte GT database Importar base de dades QLandkarte GT VRT Builder Creador de VRT GUI front end to gdalbuildvrt Frontal GUI per a gdalbuildvrt Store Map View Desa la Vista Mapa Write current active map and DEM list including the properties to a file Escriu a un fitxer el mapa actual i la llista de DEM, incloent les propietats Load Map View Carregar Vista Mapa Restore view with active map and DEM list including the properties from a file Restaura d'un fitxer la vista activa amb el mapa actual i la llista de DEM, incloent les propietats Ext. Profile Perfil Ext. Ctrl+E Ctrl+E Close Tanca Ctrl+Q Ctrl+Q Clone Map View Clona la Vista Mapa Ctrl+Shift+T Ctrl+Shift+T Create Routino Database Crea una Base de Dades Routino Save(Print) Map Screenshot Desa(Imprimeix) la captura de pantalla Print a selected area of the map Imprimir l'brea seleccionada del mapa Ctrl+P Ctrl+P Setup Coord. Format Configurar el Format de Coord. Change the format coordinates are displayed Canviar el format en que es mostren les coordenades Setup Map Background Configurar el Fons del Mapa Setup Waypoint Icons Configura les Icones de les Fites Setup path to custom icons Configurar el Camí a les Icones Personalitzades Close Tab Tanca la Pestanya Ctrl+W Ctrl+W Quickstart Help Ajuda d'inici ràpid Setup Toolbar Configurar la Barra d'Eines Toggle Docks Commuta Acoblador Toggle visibility of dockable windows Commutar la visivilitat de la finestra acoblable Ctrl+D Ctrl+D Full Screen Pantalla Completa F11 F11 Min./Max. Track Values Mín./Màx. Valors del Track Show the minimum and maximum values of the track properties along the track in the map view. En la vista de mapa, al llarg de tot el track, mostrar els valors màxims i mínims de les propietats del track. Ctrl+N Database Base de Dades IMapList Form Formulari To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Per afegir mapes feu <b>Fitxer->Configurar Camins a Mapes</b>. O feu clic <a href='setup'><b>aquí</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Utilitza el menú contextual (clic al botó dret del ratolí o entrada) per activar un mapa. Utilitzar arrossega I deixa anar per a moure el mapa activat en el procés de dibuix. Help! I want maps! I don't want to read the documentation! Ajuda! Vull mapes! No vull llegir la documentació! Activate Activar Move Up Mou amunt Hide map behind previous map Amagar mapa darrere del mapa anterior Move down Mou avall Show map on top of next map Mostra el mapa a sobre del següent mapa Reload Maps Tornar a carregar Mapes IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Aquest mapa requereix suport OpenSSL. Tanmateix donades les restriccions legals existents en alguns païssos, OpenSSL no és al paquet de QMapShack. Heu de cercar els binaris a la <a href='https://www.openssl.org/community/binaries.html'>Pàgina inicial de OpenSSL </a>. S'han de copiar a la carpeta del programa QMapShack els fitxers libeay32.dll i ssleay32.dll. Error... Error... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 tesel·les pendents<br/> IMapPathSetup Setup map paths Configurar els Camins a Mapes Root path of tile cache for online maps: Camí arrel de la memòria cau per a les tessel·les dels mapes en línia: - - ... ... Help! I want maps! I don't want to read the documentation! Ajuda! Vull mapes! No vull llegir la documentació! IMapPropSetup Form Formulari <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Canvia l'opacitat del mapa</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Click per utilitzar l'escala actual com a escala mínima per a visualitzar el mapa.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Controla els intervals de l'escala en que es mostra el mapa. Utilitza els botons esquerra i dreta per a definir l'escala actual i el màxim i mínim de l'escala.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Click per utilitzar l'escala actual com a escala màxima per a visualitzar el mapa. </p></body></html> Areas Àrees Lines Línies Points Punts Details Detalls Cache Size (MB) Mida de la memòria cau (MB) Expiration (Days) Venciment (Dies) - - Cache Path Camí a la Memòria Cau Type File: Tipus de fitxer: Forget external type file and use internal types. Oblida els tipus de fitxer externs i utilitza els propis. Load an external type file. Carregar un tipus de fitxer extern. IMapVrtBuilder Form Formulari Advanced Options Opcions Avançades Source No Data (-srcnodata) Sense font de Dades (-srcnodata) Target No Data (-vrtnodata) Sense Dades Destí (-vrtnodata) Target Projection (-a_srs) Projecció Objectiu (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. Aquestes opcions s'utilitzen en casos molt puntuals, normalment s'han de deixar en blanc. Veure GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Ajuda</a> per a obtenir més informació. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> <ol> <li>Selecciona una o múltiples fonts de fitxers *.pbf .</li> <li>Selecciona un nom per al fitxer VRT destí.</li> <li>Prem el botó "Inicia".</li> </ol> Consell: <ul> <li>Si tens diversos fitxers posa'ls en una subcarpeta del camí a la carpeta de mapes. Crea el fitxer VRT al camí a la carpeta de mapes.</li> <li>Utilitza les opcions avançades per afegir un valor "sense dades" si els fitxers origen no tenen dades o no tenen una forma de mapa rectangular. Les àrees sense fitxer de mapa es veuran transparents.</li> <li>Les opcions "-a_srs" s'utilitzen per assignar una Projecció/Datum si els fitxers origen no en tenen. Aquestes opcions NO re-projecten les dades.</li> </ul> ... ... Select source files: Selecciona els fitxers origen: Target Filename: Fitxer Destí: - - Start Inici IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Nova Línia</b><br/>Mou el ratolí, utilitzar el botó de l'esquerra per a crear punts. Un cop fet fes clic al botó esquerra del ratolí per a finalitzar.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Suprimir punt</b><br/>Moure el ratolí a prop d'un punt i fer clic al botó esquerra per suprimir-lo.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Selecció d'un Interval de Punts</b><br/>Inicia la selecció fent clic al botó esquerra sobre el primer punt. Finalitza la selecció fent clic al botó esquerra sobre el segon punt, selecciona les opcions. Per a cancel·lar fes clic al botó dret del ratolí.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Moure Punt</b><br/>Mou el ratolí prop del punt i prem el botó esquerra per adherir-l'ho al cursor. Mou el ratolí per a moure el punt. Deixa anar el punt fent clic al botó esquerra. Fes clic al botó dret del ratolí per a cancel·lar.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Afegir Punt</b><br/>Per afegir un punt, mou el ratolí prop de la línia del segment i prem el botó esquerra. El punt s'adherirà al cursor i el podràs moure. Deixa anar el punt fent clic al botó esquerra. Fes clic al botó dret del ratolí per a cancel·lar.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Sense Enrutament</b><br/>Tots els punts han d'ester connectats amb una línia recte.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Enrutament Automàtic</b><br/>La configuració actual de l'enrutador s'utiliza per a definir una ruta entre punts. <b>Nota:</b> L'enrutador seleccionat permet definir una ruta sobre la marxa. Els enrutadors Sense Connexió normalment permeten fer-ho, els enrutadors en línia no ho permeten.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Enrutament Vectorial</b><br/>Si es possible, connecta punts amb una línia en un mapa vectorial carregat, .<br/> <b>%1 Metrics</b> <b>%1 Mètrica</b> Distance: Distància: Ascent: Ascens: Descent: Descens: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> <br/><b>Moure el mapa</b><br/>Manteniu premut el botó esquerra del ratolí i podreu moure el mapa.<br/><br/> IPhotoAlbum Form Formulari ... ... IPlot Reset Zoom Reinicia Zoom Stop Range Final de l'Interval Save... Desa... Add Waypoint Afegir Fita Cut... Talla... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Mantenir premuda la tecla CTRL només per zoom vertical. Mantenir premuda la tecla ALT només per zoom horitzontal. No or bad data. No hi ha dades o són incorrectes. Select output file Selecciona el fitter de sortida IPositionDialog Position ... Posició ... Enter new position Introduir la nova posició Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Format amb possicions incorrectes. Ha de ser: "[N|S] ddd mm.sss [W|E] ddd mm.sss" o "[N|S] ddd.ddd [W|E] ddd.ddd" IPrintDialog Print map... Imprimir mapa... When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. En desar mapes en línia, assegureu-vos que tota l'extensió del mapa que vulgueu desar s'ha carregat a la memòria cau. Save Desa When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. En imprimir mapes en línia, assegurat que tots els mapes que s'han d'imprimir s'han carregat a la memòria cau. TextLabel EtiquetaDeText Print Imprimir IProgressDialog Please wait... Si us plau, espereu... TextLabel EtiquetaDeText IProjWizard Proj4 Wizzard Auxiliar Proj4 Mercator Mercator UTM UTM zone zona user defined definit per l'usuari Datum Datum World Mercator (OSM) Mercator Mundial (OSM) Result: Resultat: UPS North (North Pole) UPS Nord (Pol Nord) UPS South (South Pole) UPS Sud (Pol Sud) Projection Projecció IProjWpt Waypoint Projection Projecció de Fites ... ... - - Clone waypoint and move by: Clona la fita i ves-hi: m m ° ° IRouterBRouter Form Formulari Profile Perfil Alternative Alternativa display selected routing profile mostrar el perfil d'itineraris seleccionat ... ... on-the-fly routing enrutament al vol BRouter: BRouter: not running no s'està executant start/stop BRouter iniciar/parar BRouter show BRouter console Mostra la consola de BRouter Setup Configurar Caution! BRouter is listening on all ports for connections. Precaució! BRouter està mirant a tots els ports cercant connexions. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> IRouterBRouterInfo BRouter Profile Perfil BRouter TextLabel EtiquetaDeText IRouterBRouterSetupWizard BRouter Setup Configurar BRouter choose which BRouter to use escollir quin BRouter s'utilitzarà BRouter-Web (online) BRouter-Web (connectat) local Installation instal·lació local Expert Mode Mode Expert local BRouter Installation directory: Directori de la instal·lació local de BRouter: select installation directory selecciona el directori d'instal·lació ... ... labelLocalDirResult labelLocalDirResult create or update installation crea o modifica la instal·lació Java Executable Java Executable labelLocalJavaResult labelLocalJavaResult search for installed java cerca el java instal·lat Download and install BRouter Version Baixar i Instal·lar la Versió BRouter about:blank about:blank File to install Fitxer a instal·lar Download and Install Baixar i Instal·lar available Profiles Perfils Disponibles install profile Instal·lar perfil remove profile suprimir perfil installed Profiles Perfils instal·lats content of profile contingut del perfil BRouter-Web URL: BRouter-Web URL: Service-URL Servei-URL Profile-URL Perfil-URL Hostname Nom d'amfitrió Port Port Profile directory Directori del Perfil Segments directory Directori dels segments Custom Profiles dir Perfils Personalitzats dir Max Runtime Màx Temps d'execució Number Threads Nombre de Subprocessos Java Options Opcions de Java Profiles Url Perfils Url IRouterMapQuest Form Formulari Highways Autopistes Seasonal Estacional Language Idioma Country Border Frontera Internacional Profile Perfil Avoid: Evitar: Ferry Transbordador Toll Road Carretera de peatge Unpaved Sense asfaltar <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Direccions Cortesia de <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Formulari Profile Perfil Mode Mode Database Base de Dades Add paths with Routino database. Afegir camins a la base de dades Routino. ... ... Language idioma To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Per a utilitzar itineraris fora de línia cal definir el camí a les dades locals d'itineraris. Utilitza el boto configurar per a enregistrar un camí. Pots crear les teves dades locals d'itineraris fent <b>Eina->Crea Routino Base de Dades</b>. IRouterRoutinoPathSetup Setup Routino database... Configurar la base de dades Routino... ... ... - - IRouterSetup Form Formulari IRoutinoDatabaseBuilder Form Formulari ... ... Select source files: Selecciona els fitxers origen: Start Inici Target Path: Camí Destinació: - - File Prefix Prefix del Fitxer <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> <p>Per a crear una base de dades d'itineraris Routino s'han de baixar tots els fitxers *pbf de <a href='http://download.geofabrik.de/'>GeoFabrik</a>. El procés de creació d'una base de dades d'itineraris Routino és força lent i els fitxers resultants força grans. Per tot això es recomana que no baixeu tots els continents. Limiteu la baixada als països que realment necessiteu. No obstant, Routino no pot crear itineraris de diverses bases de dades i cal incloure tots els països per on passa una carretera transfronterera.</p> <ol> <li>Selecciona una o múltiples fonts de fitxers *.pbf .</li> <li>Selecciona el camí de la vostre base de dades Routino.</li> <li>Selecciona un prefixe. La base de dades apareixerà a la llista amb aquest prefix.</li> <li>Prem el botó "Inicia".</li> </ol> IScrOptEditLine Form Formulari Save to original Desa a l'original Save as new Desar com a nou Abort Interrompre Move points. (Ctrl+M) Moure punts. (Ctrl+M) ... ... Ctrl+M Ctrl+M Add new points. (Ctrl++) Afegir nous punts. (Ctrl++) Ctrl++ Ctrl++ Select a range of points. (Ctrl+R) Selecciona un interval de punts. (Ctrl+R) Ctrl+R Ctrl+R Delete a point. (Ctrl+-) Suprimir un punt. (Ctrl+-) Ctrl+- Ctrl+- No auto-routing or line snapping (Ctrl+O) No utilitzar ni auto-enrutament ni ajust de línia (Ctrl+O) 0 0 Ctrl+O Ctrl+O Use auto-routing to between points. (Ctrl+A) Utilitzar l'auto-enrutament entre punts. (Ctrl+A) A A Ctrl+A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Ajustar la línia amb les línies d'un mapa vectorial. (Ctrl+V) V V Ctrl+V Ctrl+V Undo last change Desfés el darrer canvi Redo last change Refès l'últim canvi IScrOptOvlArea Form Formulari View details and edit. Veure els detalls i editar. ... ... Copy area into another project. Copia l'àrea a un altre projecte. Delete area from project. Suprimir àrea del projecte. Edit shape of the area. Editar la forma de l'àrea. TextLabel EtiquetaDeText IScrOptPrint Form Formulari Save selected area as image. Desa l'àrea seleccionada com a imatge ... ... Print selected area. Imprimir l'àrea seleccionada IScrOptRangeLine Form Formulari Delete all points between the first and last one. Suprimir tots els punts entre el primer i l'últim ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Calcular una ruta entre el primer i el darrer punt seleccionats.</p></body></html> IScrOptRangeTrk Form Formulari Hide all points. Amaga tots els punts. ... ... Show all points. Mostra tots els punts. Set an activity for the selected range. Assigna una Activitat per a l'interval seleccionat. Copy track points as new track. Copia els punts del track a un nou track. TextLabel EtiquetaDeText IScrOptRte Form Formulari View details and edit. Veure els detalls i editar. ... ... Copy route into another project. Copia la ruta a un altre projecte. Delete route from project. Suprimeix itinerari del projecte. Calculate route. Calcula la ruta. Reset route calculation. Reinicia el càlcul de la ruta. Move route points. Moure els punts de l'itinerari. Convert route to track Converteix la ruta a track TextLabel EtiquetaDeText IScrOptSelect Form Formulari Copy all selected items to a project. Copia els elements seleccionats a un altre projecte. ... ... Create a route from selected waypoints. Crear una ruta des de les fites seleccionades. Change the icon of all selected waypoints. Canvia la icona de totes les fites seleccionades. Combine all selected tracks to a new one. Unir tots els tracks seleccionats en un de nou. Set an activity for all selected tracks. Assigna una Activitat per a tots els Tracks seleccionats. Delete all selected items. Esborrar tots els elements seleccionats Select all items that intersect the selected area. Selecciona tots els elements que intersecten amb l'àrea seleccionada. Select all items that are completely inside the selected area. Selecciona tots els elements que es troben de forma integra dins l'àrea seleccionada. Add tracks to selection. Afegeix tracks a la selecció. Add waypoints to selection. Afegeix fites a la selecció. Add routes to selection. Afegeix itineraris a la selecció. Add areas to selection. Afegir àrees a la selecció. IScrOptTrk Form Formulari View details and edit properties of track. Veure detalls del track I editar les propietats. ... ... Copy track into another project. Copia el track a un altre projecte. Delete track from project. Suprimeix track del projecte. Show on-screen profile and detailed information about points. Mostra a la pantalla el perfil i informació detallada sobre els punts. Select a range of points. Selecciona un interval de punts. Edit position of track points. Editar la posició dels punts del track. Reverse track. Invertir track. Combine tracks. Combinar tracks. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Retalla el track en el punt seleccionat. Es pot utilizar per: * suprimir punts sobrants a l'inici o al final del track * utilitzar parts del track per a planificar un nou recorregut * retallar un track molt llarg en vàries etapes Set an activity for the complete track. Assigna una Activitat per a tot el Track Copy track together with all attached waypoints into another project. Copia el track i totes les fites adjuntes a un altre projecte. TextLabel EtiquetaDeText IScrOptWpt Form Formulari View details and edit. Veure els detalls i editar. ... ... Copy waypoint into another project. Copia la fita a un altre projecte. Delete waypoint from project. Suprimeix fites del projecte. Show content as static bubble. Mostra el contingut en una bombolla estàtica. Move waypoint to a new location. Mou fites a una nova ubicació. Clone waypoint and move clone a given distance and angle. Clona la fita i mou el clon a la distància i angle que diguis. edit radius of circular area Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel EtiquetaDeText IScrOptWptRadius Form Formulari edit radius of circular area ... ... Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel EtiquetaDeText ISearchDatabase Search... Cerca... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Escriu la paraula que vols cercar i prem el botó de cerca. Si introduïu 'word' es fa una cerca de la paraula exacte. Si introduïu 'word*', la paraula 'word' ha d'estar a l'inici de la cadena de text. Name Nom Search Cerca Close Tanca ISelDevices Select devices... Selecciona els dispositius... ISelectActivityColor Form Formulari ISelectCopyAction Copy item... Copia l'element... Replace existing item Substituir l'element existent TextLabel EtiquetaDeText Do not copy item No copiïs l'element... Create a clone Crea un clon Replace with: Substituir amb: Keep item: Mantenir l'element: The clone's name will be appended with '_Clone' Al nom del clon s'hi afegirà '_Clone' And for all other items, too. I també per a tots els altres elements. ISelectDBFolder Select Parent Folder... Selecciona Carpeta Superior... Name Nom ISelectDoubleListWidget Form Formulari Available Disponible Add to selected items Afegir als elements seleccionats Remove from selected items Suprimir dels elements seleccionats Selected Seleccionat Move selected items up Mou els elements seleccionats amunt Move selected items down Mou els elements seleccionats avall ... ... ISelectProjectDialog Select a project... Selecciona un projecte... Select project from list or enter new project name. Selecciona un projecte de la llista o introdueix un nom de projecte nou. New project's name Nom del nou projecte New project is created as: S'ha creat un nou projecte com: *.qms *.qms *.gpx *.gpx Database Base de dades ISelectSaveAction Copy item... Copia l'element... Replace existing item Substituir l'element existent TextLabel EtiquetaDeText Do not replace item No substituir l'element Add a clone Afegir un clon The clone's name will be appended with '_Clone' Al nom del clon s'hi afegirà '_Clone' And for all other items, too. I també per a tots els altres elements. Use item: Utilitza l'element: Replace with: Substituir amb: ISetupDatabase Add database... Afegir base de dades... Name Nom Server Servidor Port Port 00000 00000 User Usuari Password Contrasenya <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Atenció!</span> Es recomanable deixar la contrasenya en blanc ja que QMapShack l'emmagatzema sense xifrar. En cas de deixar-la en blanc es demanara a cada arrancada.</p> <b>Port:</b> Leave the port field empty to use the default port. <b>Port:</b> Deixar el camp port buit si es vol utilizar el port per defecte. Do not use a password. No utilitzeu una contrasenya File: Fitxer: - - Add new database. Afegir una nova base de dades. ... ... Open existing database. Obrir una base de dades existent. MySQL MySQL SQLite SQLite ISetupFilter Form Formulari Apply filter to Aplica el filtre a name only només el nom complete text text complet ISetupFolder Database Folder... Carpeta de les Bases de Dades... Folder name Nom de la carpeta Group Grup Project Projecte Other Altres ISetupNewWpt New Waypoint... Nova Fita... Symbol Símbol ... ... Position Posició Name Nom Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Format amb possicions incorrectes. Ha de ser: "[N|S] ddd mm.sss [W|E] ddd mm.sss" o "[N|S] ddd.ddd [W|E] ddd.ddd" ISetupWorkspace Setup workspace... Configuració de l'espai de treball... save workspace on exit, and every A la sortida desa l'espai de treball, i tota la resta minutes minuts listen for database changes from other instances of QMapShack. On port mirant canvis a la base de dades fets per d'altres instàncies de QMapShack. Al port 00000 00000 ITemplateWidget Insert Template... Insereix la Plantilla... Templates Plantilles Select a path with your own templates. Selecciona el camí de les vostres plantilles. ... ... Preview Previsualització ITextEditWidget Edit text... Edita el text... Undo Desfés Ctrl+Z Ctrl+Z Redo Refès Ctrl+Shift+Z Ctrl+Maj+Z Cut Talla Ctrl+X Ctrl+X Copy Copia Ctrl+C Ctrl+C Paste Enganxa Templ. Plant. A:L A:L A:C A:C A:R A:R A:B A:B B B I I U U C C Standard Estàndard Bullet List (Disc) Llists de Pics (Disc) Bullet List (Circle) Llists de Pics (Cercle) Bullet List (Square) Llists de Pics (Quadrat) Ordered List (Decimal) Llista ordenada (Decimal) Ordered List (Alpha lower) Llista ordenada (Minúscules llatines) Ordered List (Alpha upper) Llista ordenada (Majúscules llatines) Ordered List (Roman lower) Llista ordenada (Minúscules romanes) Ordered List (Roman upper) Llista ordenada (Majúscules romanes) Ctrl+V Ctrl+V Align Left Alinea a l'esquerra Ctrl+L Ctrl+L Align Right Alinea a la dreta Ctrl+R Ctrl+R Align Center Alinea al centre Ctrl+E Ctrl+E Align Block Alinea el Bloc Ctrl+J Ctrl+J Underline Subratllat Ctrl+U Ctrl+U Bold Negreta Ctrl+B Ctrl+B Italic Itàlica Ctrl+I Ctrl+I Plain Normal Reset the text's format before pasting Reinicia el format del text abans d'enganxar Select All Selecciona-ho Tot Ctrl+A Ctrl+A Delete Suprimir Reset Font Reinicia Típus de Lletra Reset Layout Reinicia Disseny Normal Normal Paste without resetting the text's format Enganxa sense reiniciar el format del text Insert From Template Insereix des d'un Plantilla Create text from template. Crea text utilitzant una plantilla. ITextEditWidgetSelMenu B B I I U U Cut Retalla Copy Còpia Paste Enganxa ITimeZoneSetup Setup Time Zone ... Configura la zona horaria ... UTC UTC Local Local Automatic Automàtic Print date/time in Imprimir data/hora a long format, or format llarg, o short format format curt <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Nota:</b> En caviar algun dels elements GUI, les unitats no tindran efecte fins que no es reinicií QMapShack. IToolBarSetupDialog Setup Toolbar Configurar la Barra d'Eines Toolbar is visible in Fullscreen-mode La Barra d'Eines és visible en mode Pantalla Sencera IToolShell Execution of external program `%1` failed: Error en l'execució del programa extern `%1`: Process cannot be started. El procés no es pot iniciar. Make sure the required packages are installed, `%1` exists and is executable.  Assegureu-vos que els paquets necessaris estan instal·lats, `%1` existeix i es pot executar. External process crashed. El procés extern ha fallat. An unknown error occurred. S'ha product un error desconegut. !!! failed !!! !!! ha fallat !!! IUnit Error Error Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Format amb possicions incorrectes. Ha de ser: "[N|S] ddd mm.sss [W|E] ddd mm.sss" o "[N|S] ddd.ddd [W|E] ddd.ddd" Position values out of bounds. Els valors de la posició estan fora dels límits. IUnitsSetup Setup units... Configurar unitats... Length unit Unitat de longitud Nautic Nàutic Imperial Imperial Metric Mètric Slope unit Unitats del pendent Degrees (°) Graus (°) Percent (%) Percentatge (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Nota:</b> En caviar algun dels elements GUI, les unitats no tindran efecte fins que no es reinicií QMapShack. IWptIconDialog Icons... Icones... External Icons: Icones externes: - - ... ... All custom icons have to be *.bmp or *.png format. Les icones personalitzades han d'estar en format *.bmp o bé *.png. qmapshack-1.10.0/src/locale/qmapshack_de.ts000644 001750 000144 00001523245 13216421215 021751 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2, erwartet wird V%3) %1 (API V%2) (no DBUS: device detection and handling disabled) (kein DBUS: Keine Geräteerkennung und - verwaltung) CActivityTrk Foot Fußgänger Bicycle Fahrrad Motor Bike Motorrad Car Auto Cable Car Seilbahn Swim Schwimmen Ship Schiff No Activity keine Aktivität Total Total Ascent: Anstieg: Descent: Abstieg: Ski/Winter Aeronautics Aeronautik Public Transport Öffentl. Verkehrsmittel Distance: Entfernung: Speed Moving: Geschwindigkeit in Bewegung: Speed Total: Geschwindigkeit insgesamt: Time Moving: Zeit in Bewegung: Time Total: Zeit insgesamt: CCanvas View %1 Ansicht %1 Setup Map Background Kartenhintergrund einstellen CColorChooser Esc. Esc CCommandProcessor Print debug output to console. Debug-Ausgabe in die Konsole drucken. Print debug output to logfile (temp. path). Debug-Ausgabe in Log-Datei drucken (Systemordner für temporäre Dateien). Do not show splash screen. Startbildschirm nicht anzeigen. File with QMapShack configuration. Datei mit QMapShack Einstellungen. file Datei Files for future use. Dateien für den späteren Gebrauch. CCreateRouteFromWpt route Route CDBFolderLostFound All your data grouped by folders. Alle Daten nach Ordnern gruppiert. Lost & Found (%1) Verloren & Gefunden (%1) Lost & Found Verloren & Gefunden CDBFolderMysql All your data grouped by folders. Alle Daten nach Ordnern gruppiert. MySQL Database MySQL Datenbank Server: (No PW) (Kein Passwort) Error: Fehler: CDBFolderSqlite All your data grouped by folders. Alle Daten nach Ordnern gruppiert. SQLite Database SQLite Datenbank File: Datei: Error: Fehler: CDBItem %1 min. %1 min %1 h %1 days %1 Tage CDBProject Failed to load... Laden fehlgeschlagen... Can't load file "%1" . It will be skipped. Konnte die Datei "%1" nicht laden. Wird ausgelassen. Project already in database... Das Projekt ist schon in der Datenbank... The project "%1" has already been imported into the database. It will be skipped. Das Projekt "%1" wurde schon in die Datenbank importiert. Wird asugelassen. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database Das Element %1 wurde durch %2 (%3) geändert. Um den Konflikt zu lösen, erstellen und speichern Sie einen Klon, erzwingen Ihre Version oder verwerfen diese und nehmen die Version in der Datenbank Conflict with database... Konflikt mit der Datenbank... Clone && Save Klonen && Speichern Force Save Speichern erzwingen Take remote Entfernte Version nehmen Missing folder... Fehlender Ordner... Failed to save project. The folder has been deleted in the database. Speichern des Projektes fehlgeschlagen. Der Ordner wurde in der Datenbank gelöscht. Save ... Speichern ... Error Fehler There was an unexpected database error: %1 Da war ein unerwarteter Datenbankfehler: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Das Projekt '%1' will sich gerade aus der Datenbank aktualisieren. Es gibt allerdings nicht gespeicherte Änderungen. Save changes? Änderungen speichern? CDemList Deactivate Deaktivieren Activate Aktivieren CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Hinzufügen oder Entfernen von Verzeichnissen mit Höhendaten. In einem Verzeichnis können mehrere Dateien liegen. Unterverzeichnisse werden jedoch nicht durchsucht. Unterstützte Formate sind: %1 Select DEM file path... Pfad für DEM Dateien wählen... CDemVRT Error... Fehler... Failed to load file: %1 Die Datei konnte nicht geladen werden: %1 DEM must have one band with 16bit or 32bit data. DEM muss aus einem Satz mit 16 bit oder 32 bit Daten bestehen. No georeference information found. Keine Georeferenzierung gefunden. CDetailsGeoCache none keiner ??? Searching for images... Suche nach Bildern... No images found Keine Bilder gefunden CDetailsPrj none keine Build diary... Tagebuch erstellen... <b>Summary over all tracks in project</b><br/> <b>Auswertung aller Tracks im Projekt</b><br/> <h2>Waypoints</h2> <h2>Wegpunkte</h2> Info Information Comment Kommentar <h2>Tracks</h2> <h2>Tracks</h2> From Start Vom Anfang To Next Zum Nächsten To End Zum Ende <h2>Areas</h2> <h2>Gebiete</h2> You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Sie wollen Wegpunkte entlang eines Tracks sortieren, aber Sie haben die Verknüpfung von Wegpunkten und Tracks ausgeschaltet. Wollen Sie sie wieder einschalten? Correlation... Verknüpfungen... Distance: Entfernung: Ascent: Anstieg: Descent: Abstieg: <h2>Routes</h2> <h2>Routen</h2> Edit name... Name bearbeiten... Enter new project name. Geben Sie einen neuen Namen für das Projekt ein. Print Diary Tagebuch drucken Edit keywords... Stichwörter bearbeiten... Enter keywords. Stichwörter eingeben. CDetailsTrk Reduce visible track points Sichtbare Trackpunkte reduzieren Change elevation of track points Höhe von Trackpunkten ändern Change timestamp of track points Zeitstempel von Trackpunkten ändern Miscellaneous Verschiedenes Color Farbe Activity Aktivität CDetailsWpt Enter new proximity range. Geben Sie einen neuen Abstandsalarm ein. CDeviceGarmin Picture%1 Bild %1 Unknown Unbekannt CDeviceGarminArchive Archive - expand to load Archiv - zum Laden aufklappen Archive - loaded Archiv - geladen CElevationDialog No DEM data found for that point. Keine DEM Daten für diesen Punkt gefunden. CExportDatabase Select export path... Exportpfad auswählen... CExportDatabaseThread Create %1 Erstelle %1 Failed to create %1 Erstellen von %1 fehlgeschlagen Done! Fertig! Abort by user! Abbruch durch Benutzer! Database Error: %1 Datenbankfehler: %1 Save project as %1 Speichere das Projekt als %1 Failed! Fehlgeschlagen! CFilterDeleteExtension No extension available Keine Erweiterung vorhanden CFilterInterpolateElevation coarse grob medium mittel fine fein CFitCrcState FIT decoding error : invalid CRC. FIT Dekodierfehler: CRC ungültig. CFitDecoder FIT decoding error: unexpected end of file %1. FIT Dekodierfehler: Unerwartetes Ende der Datei %1. CFitFieldBuilder FIT decoding error: unknown base type %1. FIT Dekodierfehler: Unbekannter Datentyp %1. CFitFieldDataState Missing field definition for development field. FIT decoding error: invalid field def nr %1 while creating dev field profile. CFitHeaderState FIT decoding error: protocol %1 version not supported. FIT Dekodierfehler: Protokollversion %1 wird nicht unterstützt. FIT decoding error: file header signature mismatch. File is not FIT. FIT Dekodierfehler: Nicht übereinstimmende Dateikopfsignatur. Keine FIT Datei. CFitProject Failed to load file %1... Datei %1 konnte nicht geladen werden... Failed to open FIT file %1. Öffnen der FIT Datei %1 fehlgeschlagen. CFitRecordContentState FIT decoding error: architecture %1 not supported. FIT Dekodierfehler: Architektur %1 wird nicht unterstützt. FIT decoding error: invalid offset %1 for state 'record content' FIT Dekodierfehler: Ungültiger Offset %1 für Status 'aufgezeichneter Inhalt' CGarminTyp Warning... Warnung... This is a typ file with unknown polygon encoding. Please report! Dieser Dateityp hat eine unbekannte Polygon Kodierung. Bitte mitteilen! This is a typ file with unknown polyline encoding. Please report! Dieser Dateityp hat eine unbekannte Polyline Kodierung. Bitte mitteilen! CGisItemOvlArea thin dünn normal normal wide breit strong stark _Clone _Klon Area: %1%2 Gebiet: %1%2 Changed area shape. Gebietsform geändert. Changed name. Name geändert. Changed border width. Umrandungsbreite geändert. Changed fill pattern. Füllung geändert. Changed opacity. Deckkraft geändert. Changed comment. Kommentar geändert. Changed description. Beschreibung geändert. Changed links Geänderte Verknüpfungen Changed color Farbe geändert CGisItemRte _Clone _Klon track Track Changed name. Name geändert. Changed comment Kommentar geändert Changed description Beschreibung geändert Changed links Geänderte Verknüpfungen Length: %1%2 Länge: %1%2 Length: - Länge: - Time: %1%2 Gesamtzeit: %1%2 Time: - Gesamtzeit: - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Letzte Routenberechnung: <br/>%1 with %1 mit %1 Distance: %1%2 Entf.: %1%2 Changed route points. Geänderte Routenpunkte. CGisItemTrk FIT file %1 contains no GPS data. FIT Dekodierfehler: Datei %1 enthält keine GPS Daten. Error... Fehler... Failed to open %1. %1 konnte nicht geöffnet werden. Only support lon/lat WGS 84 format. Es wird nur lon/lat WGS 84 als Format unterstützt. Failed to read data. Lesen der Daten fehlgeschlagen. _Clone _Klon Changed trackpoints, sacrificed all previous data. Wegpunkte geändert, alle vorherigen Daten sind verloren. , %1-, %2- Time: %1%2, Speed: %3%4 Zeit: %1%2, Geschw.: %3%4 Time: -, Speed: - Zeit: -, Geschw.: - Moving: %1%2, Speed: %3%4 Zeit in Bew.: %1%2, Geschw.: %3%4 Moving: -, Speed: - Zeit in Bew.: -, Geschw.: - Start: %1 Beginn: %1 Start: - Beginn: - End: %1 Ende: %1 End: - Ende: - Points: %1 (%2) Punkte: %1 von %2 Invalid elevations! Ungültige Höhenwerte! Invalid timestamps! Ungültige Zeitmarken! Invalid positions! Ungültige Positionsdaten! Activities: %1 Aktivitäten: %1 Index: %1 Index: %1 Index: visible %1, total %2 Index: angez. %1, total %2 , Slope: %1%2 , Steigung: %1%2 ... and %1 tags not displayed ... und %1 Tags werden nicht angezeigt Distance: - (-) Entfernung: - (-) Moving: - (-) Zeit in Bew.: - (-) track Track Hide point %1. Punkt %1 verbergen. Hide points %1..%2. Punkte %1 %2 verbergen. , %1%2 Invalid points.... Ungültige Punkte... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? Der Track '%1' hat %2 ungültige Punkte von insgesamt %3 sichtbaren Punkten. Wollen Sie die ungültigen Punkte herausnehmen? min. min. max. max. Length: %1%2 Länge: %1%2 , %1%2%3, %4%5%6 , %1%2%3, %4%5%6 Ele.: %1%2 Höhe: %1%2 , Speed: %1%2 , Geschw.: %1%2 Ascent: - (-) Anstieg: - (-) Descent: - (-) Abstieg: - (-) Ascent: %1%2 (%3%) Anstieg: %1%2 (%3%) , Descent: %1%2 (%3%) , Abstieg: %1%2 (%3%) Distance: %1%2 (%3%) Entf.: %1%2 (%3%) , Moving: %1%2 (%3%) , Zeit in Bew.: %1%2 (%3%) Ascent: - Anstieg: - Descent: - Abstieg: - Ascent: %1%2 Anstieg: %1%2 , Descent: %1%2 , Abstieg: %1%2 Distance: %1%2 Entf.: %1%2 , Time: %1%2 , Zeit: %1%2 Permanently removed points %1..%2 Punkte %1..%2 dauerhaft entfernt Show points. Punkte anzeigen. Changed name Name geändert Changed comment Kommentar geändert Changed description Beschreibung geändert Changed links Geänderte Verknüpfungen Changed elevation of point %1 to %2 %3 Höhe von Punkt %1 auf %2 %3 geändert Changed activity to '%1' for complete track. Die Aktivität wurde für den gesamten Track auf '%1' geändert. Changed activity to '%1' for range(%2..%3). Die Aktivität wurde für den Bereich (%2..%3) auf '%1' geändert. Hide points by Douglas Peuker algorithm (%1%2) Punkte ausblenden mit dem Douglas-Peuker Algorithmus (%1%2) Hide points with invalid data. Punkte mit ungültigen Daten ausblenden. Reset all hidden track points to visible Alle verborgenen Trackpunkte zurücksetzen Permanently removed all hidden track points Alle verborgenen Trackpunkte wurden dauerhaft entfernt Smoothed profile with a Median filter of size %1 Mit einem Median-Filter der Größe %1 geglättetes Profil Added terrain slope from DEM file. Hangneigung aus dem Höhenmodell hinzufügen. Replaced elevation data with data from DEM files. Höhendaten durch Daten von DEM Dateien ersetzt. Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Höhenwerte durch interpolierte Werte ersetzt. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Versatz der Höhendaten um %1%2. Changed start of track to %1. Trackanfang auf %1 verschoben. Remove timestamps. Zeitstempel entfernt. Set artificial timestamps with delta of %1 sec. Künstliche Zeitstempel mit einem Abstand von %1 Sek. gesetzt. Changed speed to %1%2. Geschwindigkeit auf %1%2 geändert. %1 (Segment %2) Removed extension %1 from all Track Points Erweiterung %1 wurde von allen Trackpunkten entfernt Converted subpoints from routing to track points Punkte vom autom. Routing in Trackpunkte umgewandelt Copy flag information from QLandkarte GT track Kopiert das Informationsflag aus dem QLandkarte GT Track CGisItemWpt Archived Archiviert Available Verfügbar Not Available Nicht verfügbar _Clone _Klon Elevation: %1%2 Höhe: %1%2 Proximity: %1%2 Abstand: %1%2 Changed name Name geändert Changed position Position geändert Changed elevation Höhe geändert Removed proximity Abstandsalarm entfernen Changed proximity Abstandsalarm geändert Changed icon Symbol geändert Changed comment Kommentar geändert Changed description Beschreibung geändert Changed links Geänderte Verknüpfungen Changed images Bilder geändert Add image Bild hinzufügen Changed to proximity-radius Radius des Abstandsalarmes ändern Changed to nogo-area In eine Gebietsvermeidung ändern CGisListDB Add Folder Ordner hinzufügen Delete Folder Ordner löschen Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Aufgrund der Änderungen im Datenbanksystem kennt QMapShack den Dateinamen Ihrer Datenbank '%1' nicht mehr. Sie müssen diesen im nächsten Schritt erneut wählen. Select database file. Datenbankdatei wählen. Add Database Datenbank hinzufügen Rename Folder Ordner umbenennen Copy Folder Ordner kopieren Move Folder Ordner verschieben Import from Files... Aus Dateien importieren... Export to GPX... Als GPX exportieren... Delete Item Element löschen Search Database Datenbank durchsuchen Sync. with Database Mit der Datenbank synchronisieren Remove Database Datenbank entfernen Empty Leeren Remove database... Datenbank entfernen... Do you really want to remove '%1' from the list? Wollen Sie '%1' wirklich aus der Liste entfernen? Are you sure you want to delete selected folders and all subfolders from the database? Sind Sie sicher, dass Sie alle ausgewählten Ordner und alle Unterordner löschen wollen? Bad operation.... Falsche Funktion... The target folder is a subfolder of the one to move. This will not work. Der Zielordner ist ein Unterordner von dem zu verschiebenden. Das kann nicht funktionieren. Folder name... Ordnername... Rename folder: Ordner umbenennen: Are you sure you want to delete '%1' from folder '%2'? Sind Sie sicher, dass Sie '%1' aus dem Ordner '%2' löschen wollen? Delete... Löschen... Import GIS Data... GIS Daten importieren... Delete database folder... Datenbankordner löschen... Remove items... Element entfernen... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Sind Sie sicher, dass Sie alle Elemente in Verloren & Gefunden löschen wollen? Sie werden dauerhaft entfernt. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Sind Sie sicher, dass Sie alle ausgewählten Elemente in Verloren & Gefunden löschen wollen? Sie werden dauerhaft entfernt. CGisListWks Save Speichern Edit.. Bearbeiten.. Sort by Time Nach der Zeit sortieren Sort by Name Nach dem Namen sortieren Close Schließen Update Project on Device Aktualisiere das Projekt auf dem Gerät Edit... Bearbeiten... Copy to... Kopieren nach... Autom. Save Autom. Speichern Save as... Speichern unter... Copy Track with Waypoints Track mit Wegpunkten kopieren Show Bubble Infoblase anzeigen Move Waypoint Wegpunkt verschieben Change Radius Radius ändern Toggle Nogo-Area Gebietsvermeidung umschalten Delete Radius Radius entfernen Route Instructions Navigationsanweisungen Calculate Route Route berechnen Reset Route Route zurücksetzen Edit Route Route bearbeiten Convert to Track In einen Track umwandeln Create Route Route erstellen Change Icon (sel. waypt. only) Symbol änd. (nur ausgew. Wegp.) Set Track Activity Trackaktivität festlegen Drop items... Elemente verwerfen... <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Aktualisieren der Geräte</b><p>Aktualisiere %1<br/>Bitte warten...</p> Delete project... Projekt löschen... Do you really want to delete %1? Sind Sie sicher, dass sie %1 löschen wollen? Proj. Waypoint... Wegpunkt Projektion... Track Profile Trackprofil Send to Devices Ans Gerät senden Select Range Bereich wählen Edit Track Points Trackpunkte bearbeiten Reverse Track Track umkehren Combine Tracks Tracks verbinden Edit Area Points Gebietspunkte bearbeiten Delete Löschen Show on Map Auf der Karte anzeigen. Hide from Map Auf der Karte ausblenden. Save as GPX 1.1 w/o ext... Als GPX o. Erw. speichern... Sync. with Database Mit der Datenbank synchronisieren Saving workspace. Please wait. Arbeitsplatz wird gespeichert. Bitte warten. Loading workspace. Please wait. Arbeitsplatz laden. Bitte warten. Close all projects... Alle Projekte schließen... This will remove all projects from the workspace. Dies wird alle Projekte aus dem Arbeitsplatz entfernen. CGisWorkspace Load project... Lade Projekt... The project "%1" is already in the workspace. Das Projekt "%1" ist schon im Arbeitsplatz geladen. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Elementauswahl: </b> Ein Element wurde aus der Arbeitplatzliste heraus ausgewählt. Klicken Sie auf die Karte, um wieder auf die normale Auswahl mit der Maus umzuschalten. Copy items... Elemente kopieren... Change waypoint symbols. Symbol der Wegpunkte wird geändert. Cut Track... Track teilen... Do you want to delete the original track? Wollen Sie den ursprünglichen Track löschen? CGpxProject Failed to load file %1... Datei %1 konnte nicht geladen werden... Failed to open %1 Die Datei %1 konnte nicht geöffnet werden Failed to read: %1 line %2, column %3: %4 Fehler beim Lesen: %1 Zeile %2, Spalte %3: -%4 Not a GPX file: %1 Keine GPX Datei: %1 File exists ... Datei existiert... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Diese Datei wurde nicht mit QMapShack erstellt. Wenn Sie 'Ja' drücken werden alle Daten dieser Datei gelöscht. Selbst wenn diese Datei GPX Daten enthält und mit QMapShack geladen wurde, können nicht alle Elemente dieser Datei durch QMapShack geladen und gespeichert werden. Diese Elemente sind verloren. Ich empfehle die Nutzung einer anderen Datei. <b>Wollen Sie die Datei wirklich überschreiben?</b> Failed to create file '%1' Datei '%1' konnte nicht erstellt werden Failed to write file '%1' Datei '%1' konnte nicht geschrieben werden Saving GIS data failed... Das Speichern der GIS Daten ist fehlgeschlagen... CGrid %1 %2 %1%2%5 %3%4%5 %1m, %2m N %1m, E %2m CHistoryListWidget by %1 von %1 Cut history before Historie davor verkürzen Cut history after Historie danach verkürzen History removal Historie entfernen The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> Das Entfernen ist permanent und kann nicht rückgängig gemacht werden. <p> Wollen Sie wirklich die Historie vor diesem Eintrag löschen?</b> CImportDatabase Import QLandkarte Database QLandkarte Datenbank importieren Select source database... Quelldatenbank wählen... Select target database... Zieldatenbank wählen... CKnownExtension Speed extLongName Geschwindigkeit Cadence extShortName Trittfr. Air Temp. extShortName Temp. Air Temperature extLongName Lufttemperatur Water Temp. extShortName Temp. Water Temperature extLongName Wassertemperatur Depth extShortName Tiefe Depth extLongName Tiefe Heart R. extShortName Puls Heart Rate extLongName Pulsrate Cadence extLongName Trittfrequenz Speed extShortName Geschw. Accel. extShortName Beschl. Acceleration extLongName Beschleunigung Course extShortName Kurs Course extLongName Kurs Temp. extShortName Temp. Temperature extLongName Temperatur Dist. extShortName Entf. Distance extLongName Entfernung Ele. extShortName Höhe Elevation extLongName Höhe Energy extShortName Energie Energy extLongName Energie Sea Lev. Pres. extShortName Luftdr. M-Höhe Sea Level Pressure extLongName Luftdruck Meereshöhe v. Speed extShortName Geschw. (v). Vertical Speed extLongName Geschwindigkeit (vertikal) Slope extShortName Neigung Speed over Distance* extLongName Geschwindigkeit ü. Entfernung* Speed over Time* extLongName Geschwindigkeit ü. Zeit* Elevation* extLongName Höhe* Progress extShortName Verlauf Progress* extLongName Verlauf* Terr. Slope extShortName Hangn. Terrain Slope* extLongName Hangneigung* Slope* Neigung* CLogProject Failed to load file %1... Datei %1 konnte nicht geladen werden... Failed to open %1 Die Datei %1 konnte nicht geöffnet werden. Failed to read: %1 line %2, column %3: %4 Fehler beim Lesen: %1 Zeile %2, Spalte %3: -%4 Not an Openambit log file: %1 Keine Openambit Logdatei: %1 Device: %1<br/> Gerät: %1<br/> Recovery time: %1 h<br/> Erholungszeit: %1 h<br/> Peak Training Effect: %1<br/> Trainingseffekt Spitze: %1 <br/> Energy: %1 kCal<br/> Energie: %1 kCal<br/> Use of local time... Lokale Zeit benutzen... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. In der Datei wurde keine UTC Zeit gefunden. Deswegen wird die lokale Zeit auf dem Computer verwendet. Sie können nachträglich die Zeit im Track mit einem entsprechenden Filter ändern. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 Diese LOG Datei enthält keine Positionsdaten und kann nicht in QMapShack angezeigt werden: %1 CLostFoundProject Lost & Found Verloren & Gefunden CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Benützen Sie <b>Menü->Ansicht->Kartenansicht hinzufügen</b>, um eine neue Ansicht zu öffnen. Oder <b>Menü->Datei->Kartenansicht laden</b>, um eine gespeicherte wieder herzustellen. Oder Sie klicken einfach <a href='newview'>hier</a>. Ele.: %1%2 Höhe: %1%2 Slope: %1%2 terrain Hangneigung: %1%2 [Grid: %1] [Gitter: %1] Load GIS Data... GIS Daten laden... Select output file Ausgabedatei auswählen QMapShack View (*.view) QMapShack Ansicht (*.view) Select file to load Zu ladende Datei auswählen Fatal... Schwerer Fehler... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack hat eine unvollständig installierte Proj4 Bibliothek gefunden. Die Übersetzungstabellen für EPSG Projektionen, die normalerweise in /usr/share/proj installiert sind, fehlen. Bitte kontaktieren Sie den Paketbetreuer ihrer Distribution, um das zu beheben. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. Im Augenblick gibt es keine Karten. QMapShack macht ohne Karten überhaupt keinen Spaß. Sie können Online-Karten installieren, indem Sie den 'Hilfe! Ich will Karten!' Knopf im Fenster 'Karten' drücken. Oder drücken Sie F1 um zur Online-Hilfe zu gelangen. Sie erfahren dort mehr über die Bedienung von QMapShack. Wenn QMapShack ohne Karten keinen Spaß macht, warum werden dann keine mitgeliefert? Nun, um Karten fertig zur Installation zum Download anbieten zu können, benötigt man einen guten Server. Und der kostet. Dem Projekt fehlt hierzu das Geld. Zusätzlich unterliegen Karten- und DEM Daten dem Urheberrecht. Deswegen muss man den Urheber vorher fragen, ob man die Daten in ein Paket umwandeln und anbieten darf. Klingt einfacher als es oft ist. Und manchmal müsste man sogar Gebühren zahlen. Dem Projekt fehlen dafür schlicht die Ressourcen. Außerdem glauben wir, ist es nicht zu viel verlangt, wenn Sie die Daten selber installieren. Immerhin steht ihnen die Software kostenlos zur Verfügung. CMapIMG Failed ... Fehlgeschlagen... Unspecified Nicht angegeben French Französisch German Deutsch Dutch Niederländisch English Englisch Italian Italienisch Finnish Finnisch Swedish Schwedisch Spanish Spanisch Basque Baskisch Catalan Katalanisch Galician Galizisch Welsh Walisisch Gaelic Gälisch Danish Dänisch Norwegian Norwegisch Portuguese Portugiesisch Slovak Slowakisch Czech Tschechisch Croatian Kroatisch Hungarian Ungarisch Polish Polnisch Turkish Türkisch Greek Griechisch Slovenian Slowenisch Russian Russisch Estonian Estnisch Latvian Lettisch Romanian Rumänisch Albanian Albanisch Albanisch Bosnian Bosnisch Lithuanian Litauisch Serbian Serbisch Macedonian Makedonisch Bulgarian Bulgarisch Major highway Autobahn Principal highway Bundesstraße Other highway Schnellstraße Arterial road Fernstraße Collector road Sammelstraße Residential street Wohnstraße Alley/Private road Allee/Privatstraße Highway ramp, low speed Auffahrt (langsam) Highway ramp, high speed Auffahrt (schnell) Unpaved road Unbefestigte Straße Major highway connector Autobahnzubringer Roundabout Kreisverkehr Railroad Eisenbahn Shoreline Küstenlinie Trail Stream Bach Time zone Zeitzone Ferry Fähre State/province border Staats-/Landesgrenze County/parish border Kreis-/Gemeindegrenze International border Internationale Grenze River Fluss Minor land contour Höhenlinie klein Intermediate land contour Höhenlinie mittel Major land contour Höhenlinie groß Minor depth contour Tiefenlinie klein Intermediate depth contour Tiefenlinie mittel Major depth contour Tiefenlinie groß Intermittent stream Intermittierender Bach Airport runway Landebahn Pipeline Pipeline Powerline Stromleitung Marine boundary Meeresgrenze Hazard boundary Gefahrbereichgrenze Large urban area (&gt;200K) Großes Wohngebiet (&gt;200K) Small urban area (&lt;200K) Kleines Wohngebiet (&lt;200K) Rural housing area Ländliches Wohngebiet Military base Militärbasis Parking lot Parkplatz Parking garage Parkhaus Airport Flugplatz Shopping center Einkaufszentrum Marina Jachthafen University/College Universität/Hochschule Hospital Krankenhaus Industrial complex Industrie Reservation Schutzgebiet Man-made area Fabrikgelände Sports complex Sportanlage Golf course Golfplatz Cemetery Friedhof National park Nationalpark City park Stadtpark State park Forest Wald Ocean Ozean Blue (unknown) Sea Meer Large lake See Medium lake See Small lake See Major lake See Major River Strom Large River Fluss Medium River Fluss Small River Fluss Intermittent water Gewässer Wetland/Swamp Feuchtgebiet/Sumpf Glacier Gletscher Orchard/Plantation Obstgarten/Plantage Scrub Buschwerk Tundra Tundra Flat Ebene ??? Read external type file... Externe TYP Datei einlesen... Failed to read type file: %1 Fall back to internal types. Lesen der TYP Datei fehlgeschlagen: %1 Interne Typen werden wiederhergestellt. Failed to read: Lesen fehlgeschlagen: Failed to open: Öffnen fehlgeschlagen: Bad file format: Falsches Format: Failed to read file structure: Lesen der Dateistruktur fehlgeschlagen: Loading %1 Lädt %1 User abort: Benutzerabbruch: File is NT format. QMapShack is unable to read map files with NT format: Die Datei hat das NT Format. QMapShack kann dieses Format nicht lesen: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Die Datei enthält verschlüsselte Daten. Garmin möchte nicht, dass diese Datei mit einer anderen Software, als der von Garmin bereitgestellten, benutzt wird. Point of Interest Ort von Interesse Unknown Unbekannt Area Gebiet CMapList Deactivate Deaktivieren Activate Aktivieren Where do you want to store maps? Wo wollen Sie die Karten speichern? CMapMAP Failed ... Fehlgeschlagen... Failed to open: Öffnen fehlgeschlagen: Bad file format: Falsches Dateiformat: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Hinzufügen oder Entfernen von Verzeichnissen mit Karten. In einem Verzeichnis können mehrere Karten liegen. Unterverzeichnisse werden jedoch nicht durchsucht. Unterstützte Formate sind: %1 Select map path... Kartenpfad wählen... Select root path... Hauptverzeichnis auswählen... CMapPropSetup Select type file... TYP Datei auswählen... CMapRMAP Error... Fehler... This is not a TwoNav RMAP file. Das ist keine bekannte TwoNav RMAP Datei. Unknown sub-format. Unbekanntes Unterformat. Unknown version. Unbekannte Version. Failed to read reference point. Referenzpunkte konnten nicht gelesen werden. Unknown projection and datum (%1%2). Unbekannte Projektion und Datum (%1%2). CMapTMS Error... Fehler... Failed to open %1 Öffnen fehlgeschlagen: %1 Failed to read: %1 line %2, column %3: %4 Lesen fehlgeschlagen: %1 Zeile %2, Spalte %3: %4 Layer %1 CMapVRT Error... Fehler... Failed to load file: %1 Die Datei konnte nicht geladen werden: %1 File must be 8 bit palette or gray indexed. Die Datei muss eine 8 bit Palette oder Graustufen haben. No georeference information found. Keine Georeferenzierung gefunden. CMapVrtBuilder Build GDAL VRT GDAL VRT erstellen Select files... Dateien auswählen... Select target file... Zieldatei auswählen... !!! done !!! !!! erledigt !!! CMapWMTS Error... Fehler... Failed to open %1 Öffnen fehlgeschlagen: %1 Failed to read: %1 line %2, column %3: %4 Lesen fehlgeschlagen: %1 Zeile %2, Spalte %3: %4 Failed to read: %1 Unknown structure. Lesen fehlgeschlagen: %1 Unbekannte Struktur. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Unerwarteter Dienst. '* WMTS 1.0.0' wird erwartet. '%1 %2' wurde gelesen. No georeference information found. Keine Georeferenzierung gefunden. CMouseEditArea Area Gebiet <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Gebiet bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funktion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/> area Gebiet CMouseEditRte Route <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Routenpunkte bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funktion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/> route Route CMouseEditTrk Track Track <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Trackpunkte bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funktion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/> Warning! Warnung! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Alle ursprünglichen Daten werden durch eine einfache Koordinatenlinie ersetzt. Alle anderen Daten sind dauerhaft verloren. track Track CMouseNormal Add POI as Waypoint POI als Wegpunkt hinzufügen Add Waypoint Wegpunkt hinzufügen Add Track Track hinzufügen Add Route Route hinzufügen Add Area Gebiet hinzufügen Select Items On Map Elemente auf der Karte auswählen Copy position Position kopieren Copy position (Grid) Position kopieren (Gitter) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Karte speichern (drucken)</b><br/>Wählen Sie mit der linken Maustaste einen rechteckigen Bereich auf der Karte aus. Die Auswahl kann durch Verschieben der Eckpunkte mit der Maus angepasst werden. Abbruch mit Rechtsklick. Speichern/Drucken erfolgt durch Linksklick auf das entsprechende Symbol in der Mitte der Auswahl. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Punktebereich auswählen</b><br/>Mit der linken Maustaste wählen Sie den ersten Punkt aus. Mit einem erneuten Drücken der linken Maustaste wählen Sie den zweiten Punkt aus und dann wählen Sie eine der Optionen. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Elemente auf der Karte wählen</b><br/>Wählen Sie mit der linken Maustaste einen rechteckigen Bereich auf der Karte aus. Abbruch mit Rechtsklick. Die Auswahl kann durch Verschieben der Eckpunkte mit der Maus angepasst werden. <b>Selected:</b><br/> <b>Ausgewählt:</b><br/> %1 tracks<br/> %1 Tracks<br/> %1 waypoints<br/> %1 Wegpunkte<br/> %1 routes<br/> %1 Routen<br/> %1 areas<br/> %1 Gebiete<br/> CPhotoAlbum Select images... Bilder wählen... CPlot Distance [%1] Entfernung [%1] Time Zeit CPlotProfile Distance [%1] Entfernung [%1] Ele. [%1] Höhe [%1] CPrintDialog Print Map... Karte drucken... Save Map as Image... Karte als Bild speichern... Printer Properties... Drucker Eigenschaften... Pages: %1 x %2 Seiten: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Zoomen Sie mit dem Mausrad auf der Karte unten, um die Auflösung zu ändern: %1x%2 Pixel x: %3 m/px y: %4 m/px Printing pages. Drucke Seiten. Save map... Karte speichern... CProgressDialog Elapsed time: %1 Verstrichene Zeit: %1 Elapsed time: %1 seconds. Verstrichene Zeit: %1 Sekunden. CProjWizard north Norden south Süden Error... Fehler... The value '%1' is not a valid coordinate system definition: %2 Die Eingabe: '%1' ist keine gültige Koordinatensystemdefinition: %2 CProjWpt Edit name... Name bearbeiten... Enter new waypoint name. Geben Sie einen neuen Namen für den Wegpunkt ein. CQlbProject Failed to open... Öffnen fehlgeschlagen... Failed to open %1 Die Datei %1 konnte nicht geöffnet werden Could not convert... Konnte nicht umgewandelt werden... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. Die Datei enthält Einblendungen (Overlays), die nicht konvertiert werden können. Der Grund dafür ist, dass QMapShack nicht alle Einblendungstypen von QLandkarte unterstützt. CQlgtDb Migrating database from version 4 to 5. Datenbank von Version 4 nach 5 migrieren. Migrating database from version 5 to 6. Datenbank von Version 5 nach 6 migrieren. Migrating database from version 6 to 7. Datenbank von Version 6 nach 7 migrieren. Migrating database from version 7 to 8. Datenbank von Version 7 nach 8 migrieren. Migrating database from version 8 to 9. Datenbank von Version 8 nach 9 migrieren. Open database: %1 Öffne Datenbank: %1 Folders: %1 Ordner: %1 Tracks: %1 Tracks: %1 Routes: %1 (Only the basic route will be copied) Routen: %1 (Es wird nur die Basisroute kopiert) Waypoints: %1 Wegpunkte: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Overlays: %1 (Flächen werden als Flächen übernommen, Distanzlinien werden als Tracks übernommen, alle anderen Overlays gehen verloren) Diaries: %1 Tagebücher: %1 Map selections: %1 (can't be converted to QMapShack) Kartenselektionen: %1 (können nicht nach QMapShack konvertiert werden) ------ Start to convert database to %1------ ------ Konvertierung der Datenbank %1 beginnt ------ Failed to create target database. Erstellen der Zieldatenbank fehlgeschlagen. ------ Abort ------ ------ Abbrechen ------ ------ Done ------ ------ Fertig ------ Restore folders... Ordner wiederherstellen... Imported %1 folders and %2 diaries Importiert wurden %1 Ordner und %2 Tagebücher Copy items... Elemente kopieren... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Importiert wurden %1 Tracks, %2 Wegpunkte, %3 Routen, %4 Gebiete Import folders... Importiere Ordner... Overlay of type '%1' cant be converted Das Overlay vom Typ '%1' kann nicht konvertiert werden CQlgtTrack Corrupt track ... Beschädigter Track ... Number of trackpoints is not equal the number of training data trackpoints. Anzahl der Trackpunkte entspricht nicht der Anzahl der Trackpunkte der Trainingsdaten. Number of trackpoints is not equal the number of extended data trackpoints. Anzahl der Trackpunkte entspricht nicht der Anzahl der erweiterten Trackpunkte. Number of trackpoints is not equal the number of shadow data trackpoints. Anzahl der Trackpunkte entspricht nicht der Anzahl der ausgeblendeten Trackpunkte. CQmsDb Existing file... Vorhandene Datei... Remove existing %1? Entferne vorhandene %1? Remove existing file %1 Entferne vorhandene Datei %1 %1: drop item with QLGT DB ID %2 %1: verwerfe das Element mit der QLGT DB ID %2 CQmsProject Failed to open... Öffnen fehlgeschlagen... Failed to open %1 Öffnen von %1 fehlgeschlagen CRouterBRouter original first alternative erste Variante second alternative zweite Variante third alternative dritte Variante BRouter (offline) BRouter (online) profile: %1, alternative: %2 Profil: %1, Variante: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade BRouter unterstützt in dieser Version nicht mehr als ein Vermeidungsgebiet. Versuchen Sie es mit einem Update. response is empty Anwort ist leer Bad response from server: %1 Fehlerhafte Serverantwort: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... <b>BRouter</b><br/>Routen-anfrage an den Server geschickt. Bitte warten... Calculate route with %1 Berechne Route mit %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <b>BRouter</b><br/>Fehler-Antwort vom Server<br/>%1 <br/>Calculation time: %1s <br/>Berechnungszeit: %1 s Error Fehler running wird ausgeführt starting started QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. QMapShack kommuniziert mit BRouter über eine Netzwerkverbindung. Normalerweise wird das über eine spezielle Addresse gemacht, die von außen nicht zugänglich ist. Allerdings horcht BRouter auf allen verfügbaren Netzwerkschnittstellen. Wenn Sie in ihrem eigenen privaten Netzwerk mit einer aktiven Firewall sind, ist das kein großes Problem. Wenn Sie in einem öffentlichen Netzwerk sind, stellt jeder offene Zugang ein Risiko dar, weil er von jemanden missbraucht werden kann, ihr System anzugreifen. Wir empfehlen in diesem Fall auf den lokal laufenden BRouter zu verzichten. Warning... Warnung... I understand the risk. Don't tell me again. Ich verstehe das Risiko. Bitte nicht mehr zeigen. stopped angehalten not installed nicht installiert online CRouterBRouterSetup %1 not accessible %1 ist nicht erreichbar %1 invalid result ungültige Antwort von %1 Error parsing online-config: Fehler beim Auswerten der Online-konfiguration: Network error: Netzwerk Fehler: CRouterBRouterSetupWizard Restore Default Values Vorgabewerte wiederherstellen Open Directory Verzeichnis öffnen select Java Executable installiertes Java-Programm auswählen please select BRouter installation directory bitte das BRouter Installations-Verzeichnis auswählen selected directory does not exist ausgewähltes Verzeichnis existiert nicht create directory and install BRouter there Verzeichnis anlegen und BRouter darin installieren existing BRouter installation vorhandene BRouter-Installation gefunden update existing BRouter installation vorhandene BRouter-Installation aktualisieren empty directory, create new BRouter installation here leeres Verzeichnis, neue BRouter-Installation hier einrichten create new BRouter installation neue BRouter-Installation erzeugen seems to be a valid Java-executable es scheint eine gültige Java Installation zu geben doesn't seem to be a valid Java-executable es scheint keine gültige Java Installation zu geben Java Executable not found Java Programm nicht gefunden Error loading installation-page at %1 Fehler beim Laden der Installationsseite von %1 no brouter-version to install selected keine BRouter-Version zum Installieren ausgewählt selected %1 for download and installation %1 zum Herunterladen und Installieren ausgewählt Warning... Warnung... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. Download: %1<br/><br/>Sie sind dabei eine ZIP Datei aus dem Netz zu laden und zu installieren. Dies Aktion ist nach keinem Standard gesichert und benutzt nur HTTP. Es sollte aber HTTPS sein. Sie haben damit das Risiko, dass jemand die Verbindung umleitet und Ihnen eine Datei mit Schadsoftware sendet. QMapShack kann das nicht unterscheiden. <br/>Wenn Si das nicht verstanden haben oder im Zweifel sind, brechen Sie hier ab. Benützen Sie stattdessen die Web-Version von BRouter. I understand the risk and wish to proceed. Ich verstehe das Risiko und möchte weiter machen. download %1 started Herunterladen von %1 gestartet Network Error: %1 Netzwerkfehler: %1 download %1 finished Herunterladen von %1 ist fertig unzipping: entpacken: ready. fertig. download of brouter failed: %1 Herunterladen von BRouter fehlgeschlagen: %1 retrieving available profiles from %1 Unter %1 verfügbare Profile werden ermittelt content of profile Profil-Inhalt Error: Fehler: Error creating directory %1 Fehler beim Anlegen des Verzeichnisses %1 Error directory %1 does not exist Fehler: Das Verzeichnis %1 existiert nicht Error creating file %1 Fehler beim Anlegen der Datei %1 Error writing to file %1 Fehler beim Schreiben der Datei %1 CRouterBRouterTilesPage Continue with Setup weiter Einrichten CRouterBRouterTilesSelect available routing-data is being determined. verfügbare Routing-daten werden ermittelt. Select outdated Veraltete Daten auswählen Clear Selection Auswahl aufheben Delete selection Ausgewählte Daten löschen Download Herunterladen Error creating segments directory %1 Fehler beim Anlegen des Verzeichniss für die Routingdaten %1 cannot parse: %1 is not a date nicht interpretierbar: %1 ist kein Datum cannot parse: %1 is not a valid size nicht interpretierbar: %1 ist keine gültige Größenangabe Error retrieving available routing data from %1: %2 Fehler beim Abruf der verfügbaren Routingdaten von %1: %2 segments directory does not exist: Das Verzeichniss für die Routingdaten existiert nicht: error creating file %1: %2 Fehler beim Anlegen der Datei %1: %2 no valid request for filename %1 keine gültige Netzwerkanfrage für die Datei %1 vorhanden no open file assigned to request for %1 der Netzwerkanfrage für %1 ist keine offene Datei zugeordnet error writing to file %1: %2 Fehler beim Schreiben der Datei %1: %2 error renaming file %1 to %2: %3 Fehler beim Umbenennen der Datei von %1 nach %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) Aktuell: %1 (%2), Veraltet: %3 (%4), noch Herunterzuladen: %5 (%6) being downloaded: %1 of %2 wird heruntergeladen: %1 von %2 no local data, online available: %1 (%2) lokale keine Daten. Verfügbar: %1 (%2) local data outdated (%1, %2 - remote %3, %4) lokale Daten veraltet (%1, %2 - auf dem Server: %3, %4) Error removing %1: %2 Fehler beim Löschen der Datei %1: %2 Network Error Netzwerkfehler invalid result, no files found ungültige Anwort, keine Dateien gefunden local data up to date (%1, %2) lokale Daten sind aktuell (%1, %2) no routing-data available keine Routing-daten verfügbar CRouterBRouterToolShell !!! done !!! !!! erledigt !!! !!! failed !!! !!! fehlgeschlagen !!! CRouterMapQuest Fastest Schnellste Shortest Kürzeste Bicycle Fahrrad Pedestrian Fußgänger US English Englisch (USA) British English Englisch (Britisch) Danish Dänisch Dutch Niederländisch French Französisch German Deutsch Italian Italienisch Norwegian Norwegisch Spanish Spanisch Swedish Schwedisch mode "%1" Modus "%1" no highways keine Kraftfahrzeugstraßen no toll roads keine Mautstraßen no seasonal keine saisonalen Straßen no unpaved keine unbefestigten Straßen no ferry keine Fähren no crossing of country borders keine Überquerung von Landesgrenzen <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Routinganforderung an den Server gesendet. Bitte warten... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Falsche Antwort vom Server:<br/>%1 <br/>Calculation time: %1s <br/>Berechnungszeit: %1 s CRouterRoutino Foot Fußgänger Horse Reiter Wheelchair Rollstuhl Bicycle Fahrrad Moped Moped Motorcycle Motorrad Motorcar Auto Goods LKW Shortest Kürzeste Found Routino with a wrong version. Expected %1 found %2 Falsche Routino Version gefunden. Erwartet wird %1, gefunden wurde %2 Quickest Schnellste English Englisch German Deutsch French Französisch Hungarian Ungarisch Dutch Niederländisch Russian Russisch Polish Polnisch A function was called without the database variable set. Eine Funktion wurde ohne gesetzte Datenbank aufgerufen. A function was called without the profile variable set. Eine Funktion wurde ohne gesetztes Profil aufgerufen. A function was called without the translation variable set. Eine Funktion wurde ohne gesetzte Sprache aufgerufen. The specified database to load did not exist. Die zu ladende vorgegebene Datenbank existiert nicht. The specified database could not be loaded. Die vorgegebene Datenbank konnte nicht geladen werden. The specified profiles XML file did not exist. Die vorgegebene XML Profildatei existiert nicht. The specified profiles XML file could not be loaded. Die vorgegebene XML Profildatei konnte nicht geladen werden. The specified translations XML file did not exist. Die vorgegebene XML Sprachdatei existiert nicht. The specified translations XML file could not be loaded. Die vorgegebene XML Profildatei konnte nicht geladen werden. The requested profile name does not exist in the loaded XML file. Den geforderten Profilnamen gibt es in der geladenen XML Datei nicht. The requested translation language does not exist in the loaded XML file. Die geforderte Sprache gibt es in der geladenen XML Datei nicht. The profile and database do not work together. Profil und Datenbank funktionieren nicht zusammen. The profile being used has not been validated. Das zu benutzende Profil wurde nicht validiert. The user specified profile contained invalid data. Das vorgegebene Profil enthält ungültige Daten. The routing options specified are not consistent with each other. Die vorgegebenen Routingoptionen passen nicht zusammen. There is a mismatch between the library and caller API version. Die Library und die API Version passen nicht zusammen. Route calculation was aborted by user. Die Routenberechnung wurde vom Benutzer abgebrochen. A route could not be found to waypoint %1. Es konnte keine Route zum Wegpunkt %1 gefunden werden. Unknown error: %1 Unbekannter Fehler: %1 profile "%1" Profil "%1" , mode "%1" , Modus "%1" Warning... Warnung... In the routing database there is no highway near the coordinates to place a waypoint. Message text points now to problem with routing database Es gibt in der Routing-Datenbank keine Straße in der Nähe des zu platzierenden Wegpunktes. Calculate route with %1 Berechne Route mit %1 <br/>Calculation time: %1s <br/>Berechnungszeit: %1 s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Pfade mit Routino Daten hinzufügen oder entfernen. In einem Pfad können mehrere Datenbanken sein. Teilpfade werden nicht geparst. Select routing data file path... Pfad für Routingdatendatei wählen... CRouterSetup Routino (offline) MapQuest (online) BRouter (online) CRoutinoDatabaseBuilder Create Routino Database Routino Datenbank erstellen Select files... Dateien auswählen... Select target path... Zielpfad auswählen... !!! done !!! !!! erledigt !!! CScrOptRangeTrk No range selected Kein Bereich ausgewählt CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Genauer Modus</b><br/>Alle Elemente müssen vollständig innerhalb des gewählten Bereiches sein.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Überschneidender Modus</b><br/>Alle gewählten Elemente müssen innerhalb des gewählten Bereiches sein oder müssen diesen zumindest schneiden.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Tracks hinzufügen</b><br/>Fügt Tracks zur Liste der gewählten Elemente hinzu<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Wegpunkte hinzufügen</b><br/>Fügt Wegpunkte zur Liste der gewählten Elemente hinzu<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Routen hinzufügen</b><br/>Fügt Routen zur Liste der gewählten Elemente hinzu<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Gebiete hinzufügen</b><br/>Fügt Gebiete zur Liste der gewählten Elemente hinzu<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Tracks ignorieren</b><br/>Tracks werden in der Liste der gewählten Elemente nicht berücksichtigt<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Wegpunkte ignorieren</b><br/>Wegpunkte werden in der Liste der gewählten Elemente nicht berücksichtigt<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Routen ignorieren</b><br/>Routen werden in der Liste der gewählten Elemente nicht berücksichtigt<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> <b>Gebiete ignorieren</b><br/>Gebiete werden in der Liste der gewählten Elemente nicht berücksichtigt<br/> CSearchDatabase Search database '%1': Datenbank '%1' durchsuchen CSearchGoogle Unknown response Unbekannte Antwort Error: Fehler: CSetupDatabase Missing Requirement Fehlende Voraussetzung MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. MySQL kann derzeit nicht genutzt werden, weil der entsprechende Treiber (QMYSQL) nicht verfügbar ist.<br />Stellen Sie bitte sicher, dass das entsprechende Paket installiert ist.<br />Wenn Sie nicht wissen, was zu tun ist, sollten Sie einen Blick auf das <a href="%1">Wiki</a> werfen. Error... Fehler... There is already a database with name '%1' Es gibt schon eine Datenbank mit dem Namen '%1' New database... Neue Datenbank... Open database... Datenbank öffnen... CSetupWorkspace Setup database... Datenbank einrichten... Changes will become active after an application's restart. Änderungen werden erst nach Neustart der Anwendung aktiv. CSlfProject Failed to load file %1... Datei %1 konnte nicht geladen werden... CSlfReader Failed to parse timestamp `%1` Zeitmarke lesen fehlgeschlagen. '%1' %1 does not exist %1 existiert nicht Failed to open %1 Öffnen von %1 fehlgeschlagen Failed to read: %1 line %2, column %3: %4 Lesen von %1 fehlgeschlagen: Zeile %2, Spalte %3: %4 Not a SLF file: %1 Keine SLF Datei: %1 Unsupported revision %1: %2 Nicht unterstützte Revision %1: %2 Break %1 Pause %1 Lap %1 Runde %1 CSmlProject Failed to load file %1... Datei %1 konnte nicht geladen werden... Failed to open %1 Die Datei %1 konnte nicht geöffnet werden. Failed to read: %1 line %2, column %3: %4 Fehler beim Lesen: %1 Zeile %2, Spalte %3: -%4 Not an sml file: %1 Keine SML Datei: %1 Recovery time: %1 h<br/> Erholungszeit: %1 h<br/> Peak Training Effect: %1<br/> Trainingseffekt Spitze: %1 <br/> Energy: %1 kCal<br/> Energie: %1 kCal<br/> Device: %1<br/> Gerät: %1<br/> Battery usage: %1 %/hour Batteriebenutzung: %1 %/h Use of local time... Lokale Zeit benutzen... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. In der Datei wurde keine UTC Zeit gefunden. Deswegen wird die lokale Zeit auf dem Computer verwendet. Sie können nachträglich die Zeit im Track mit einem entsprechenden Filter ändern. This SML file does not contain any position data and can not be displayed by QMapShack: %1 Diese SML Datei enthält keine Positionsdaten und kann nicht in QMapShack angezeigt werden: %1 CTableTrk Double click to edit elevation value Doppelt klicken, um die Höhe zu ändern. %1%2 CTcxProject Failed to load file %1... Datei %1 konnte nicht geladen werden... Failed to open %1 Die Datei %1 konnte nicht geöffnet werden Failed to read: %1 line %2, column %3: %4 Fehler beim Lesen: %1 Zeile %2, Spalte %3: %4 Not a TCX file: %1 Keine TCX Datei: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Diese TCX Datei enthält mindestens einen Workout, aber keine Aktivität oder einen Kurs. Da Workouts keine Positionsdaten beinhalten, können sie nicht in QMapShack geladen werden. This TCX file does not contain any activity or course: %1 Diese TCX Datei enthält keine Aktivität oder Runden: %1 File exists ... Datei existiert... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Die Datei existiert schon und wurde nicht mit QMapShack erstellt. Wenn Sie 'Ja' drücken werden die ursprünglichen Daten verloren gehen. Auch wenn die Datei mit QMapShack geladen wurde. QMapShack ist möglicherweise nicht in der Lage alle Daten zu laden und wieder zu speichern. Diese Daten werden verloren gehen. Wir empfehlen eine andere Datei zu benutzen. <b>Wollen Sie wirklich die Datei überschreiben?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> Der Track <b>%1</b>, den Sie ausgewählt haben, beinhaltet Trackpunkte mit einer ungültigen Zeitmarke. Das Gerät wird die erzeugte TCX Kursdatei nicht akzeptieren, wenn sie so bleibt wie sie ist. <b> Wollen Sie einen Filter anwenden, der die Geschwindigkeit auf 10m/s setzt und fortfahren?</b> Course Kurs Activity Aktivität Cancel Abbrechen Track with invalid timestamps... Track mit ungültiger Zeitmarke... Activity or course? Aktivität oder Kurs? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack weiß nicht als was der Track <b>%1</b> gespeichert werden soll. <b> Wollen Sie ihn als Kurs oder als Aktivität speichern? <b> Bedenken Sie, dass nur Wegpunkte die nahe genug am Track sind bei einem Kurs gespeichert werden. Wegpunkte werden bei einer Aktivität nicht gespeichert. Failed to create file '%1' Datei '%1' konnte nicht erstellt werden Failed to write file '%1' Datei '%1' konnte nicht geschrieben werden Saving GIS data failed... Das Speichern der GIS Daten ist fehlgeschlagen... CTemplateWidget choose one... auswählen... Hiking Tour Summary (built-in) Wanderung Zusammenfassung (built-in) - Template path... Vorlagenpfad... Failed to read template file %1. Datei '%1' konnte nicht gelesen werden. Preview... Vorschau... CTextEditWidget &Color... &Farbe... Reset format Format zurücksetzen CToolBarSetupDialog Available Actions Verfügbare Werkzeuge Selected Actions Ausgewählte Werkzeuge CTwoNavProject Error... Fehler... Failed to open %1. Die Datei %1 konnte nicht geöffnet werden. Save GIS data to... GIS Daten speichern in... Only support lon/lat WGS 84 format. Es wird nur lon/lat WGS 84 als Format unterstützt. Failed to read data. Lesen der Daten fehlgeschlagen. CWptIconDialog Path to user icons... Pfad zu Benutzersymbolen... Form Form Participants Teilnehmer Weather Wetter rain Regen sunny Sonne snow Schnee clouds Wolken windy Wind hot heiß warm warm cold kalt freezing eiskalt foggy neblig humid schwül Character Charakter easy hiking einfache Wanderung climbing Klettern alpine alpine Tour large ascend langer Anstieg long distance lange Distanz via ferrata Klettersteig hail/soft hail Hagel/Graupel Rating Beurteilung Rating 5 stars Beurteilung 5 Sterne Rating 4 stars Beurteilung 4 Sterne Rating 3 stars Beurteilung 3 Sterne Rating 2 stars Beurteilung 2 Sterne Rating 1 star Beurteilung 1 Sterne aborted abgebrochen Equipment Ausrüstung ferrata gear Klettersteigset night gear Nachtausrüstung snow shoes Schneeschuhe climbing gear Kletterausrüstung ski Ski camping gear Campingausrüstung Details Details IAbout About.... Über.... <b>QMapShack</b>, Version TextLabel Bezeichnung Qt GDAL Proj4 Routino Routino Czech: Tschechisch: German: Deutsch: Oliver Eichler Dutch: Niederländisch: French: Französisch: Rainer Unseld Russian: Russisch: Wolfgang Thämelt © 2017 Oliver Eichler (oliver.eichler@gmx.de) Pavel Fric <b>Translation:</b> <b>Übersetzung:</b> Harrie Klomp Spanish: Spanisch: Win64: <b>Binaries:</b> <b>Ausführbare Dateien:</b> OS X: <b>Contributors:</b> <b>Mitwirkende:</b> Jose Luis Domingo Lopez Ivo Kronenberg Helmut Schmidt ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ... und Danke an alle Ersteller von ausführbaren Linux-Dateien für die gute Arbeit. Ganz besonderen Dank an Dan Horák und Bas Couwenberg für ihre Teilnahme an der Diskussion in der Mailingliste distributionsbezogene Punkte betreffend. Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Diese Software steht unter der GPL3 Lizenz (oder spätere Versionen) ICanvasSetup Setup Map View... Kartenansicht einstellen... Projection & Datum Projektion & Datum ... Scales Skalierung Logarithmic Logarithmisch Square (optimized for TMS and WMTS tiles) Quadratisch (optimiert für TMS und WMTS Kacheln) IColorChooser Dialog Dialog ICombineTrk Combine Tracks... Tracks verbinden... Available Tracks Vorh. Tracks ... Combined Tracks Verb. Tracks ICoordFormatSetup Coordinate Format... Koordinatenformat... N48° 53.660 E013° 31.113 N48.8943° E013.51855° N48° 53' 39.6" E13° 31' 6.78" ICreateRouteFromWpt Create Route from Waypoints Route aus Wegpunkten erstellen ... ICutTrk Cut Track Track teilen Delete first part of the track and keep second one Löscht den ersten Teil des Tracks und behält den zweiten Keep both parts of the track Behält beide Teile des Tracks Keep first part of the track and delete second one Behält den ersten Teil des Tracks und löscht den zweiten Cut Mode: Teilmodus: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Wählen Sie das aus, wenn das Ergebnis ein neuer Track sein soll. Wenn Sie beide Teile des Tracks behalten wollen, müssen neue Tracks erstellt werden. Wenn Sie nur die eine Hälfte behalten wollen, können Sie einfach die Punkte löschen, oder wählen Sie das, um einen neuen Track zu erstellen. Create a new track Neuen Track erstellen IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Das interne Datenbankformat von '%1' wurde geändert. QMapShack wird ihre Datenbank nun migrieren. Nach der Migration kann die Datenbank mit älteren QMapShack Versionen nicht mehr verwendet werden. Es wird empfohlen, zuerst ein Backup der Datenbank zu erstellen. Migrate database... Datenbank wird migriert... Migration aborted by user Migration durch den Benutzer abgebrochen Failed to migrate '%1'. Migrieren von '%1' fehlgeschlagen. Error... Fehler... Migration failed Migration fehlgeschlagen The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. Die Datenbankversion von '%1' ist höher als die, die von QMapShack gelesen werden kann. Das wird nicht gehen. Initialization failed Initialisierung fehlgeschlagen Wrong database version... Falsche Datenbankversion... Database created by newer version of QMapShack Die Datenbank wurde von einer aktuelleren Version von QMapShack erstellt Failed to initialize '%1'. Initialisieren von '%1' fehlgeschlagen. IDBMysql Password... Passwort... Password for database '%1': Passwort für Datenbank '%1': Update to database version 5. Migrate all GIS items. Wechsel zu Datenbankversion 5. Alle GIS Elemente werden übertragen. IDBSqlite Update to database version 3. Migrate all GIS items. Wechsel zu Datenbankversion 3. Alle GIS Elemente werden übertragen. Update to database version 5. Migrate all GIS items. Wechsel zu Datenbankversion 5. Alle GIS Elemente werden übertragen. Update to database version 6. Migrate all GIS items. Wechsel zu Datenbankversion 6. Alle GIS Elemente werden übertragen. IDemPathSetup Setup DEM file paths Pfad für DEM Dateien setzen ... - IDemPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Ändert die Deckkraft der Karte</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klicken, um die aktuelle Skalierung als minimale Skalierung zu benutzen.</p></body></html> ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Stellt den Skalierungsbereich ein, in dem die Karte sichtbar ist. Benutzen Sie die beiden Knöpfe links und rechts um die minimale und maximale Skalierung einzustellen.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klicken um die aktuelle Skalierung als maximale Skalierung zu benutzen.</p></body></html> Hillshading Schummerung Slope Hangneigung ° > TextLabel Bezeichnung IDemsList Form To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Sie können Höhendaten mit <b>"Menü -> Datei -> DEM Verzeichnisse angeben"</b> hinzufügen. Oder Sie klicken einfach <a href='setup'><b>hier</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Mit dem Kontextmenü (Klick mit rechter Maustaste auf einen Eintrag) können Sie einen Datensatz aktivieren. Um die Höhendaten in einer anderen Reihenfolge anzuzeigen, können Sie jeden Eintrag mit drag-n-drop verschieben. Activate Aktivieren Move Up Nach oben verschieben Hide DEM behind previous one Versteckt DEM hinter dem vorherigen Move down Nach unten verschieben Show DEM on top of next one DEM überlagert das nächste Reload DEM DEM erneut laden IDetailsGeoCache Dialog - about:blank Position: Position: Difficulty Schwierigkeit Terrain Gelände Update spoilers Spoiler erneut laden ... Hint: Hinweis: TextLabel Bezeichnung IDetailsOvlArea Dialog Dialog The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Das Gebiet wurde in QMapShack importiert und geändert. Die ursprünglichen Daten werden nicht mehr angezeigt. Näheres siehe Änderungshistorie. Toggle read only mode. You have to open the lock to edit the item. Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten. ... Color Farbe Border width Rahmenbreite Style Stil Opacity Deckkraft Info Info Points Punkte Position Position Hist. Historie IDetailsPrj Form - Print diary Tagebuch drucken ... Keep order of project Reihenfolge beibehalten Sort along track (multiple) Sort. entl. d. Tracks (mehrfach) Sort along track (single) Sort. entl. d. Tracks (einmalig) Rebuild diary. Tagebuch aktualisieren. Keywords: Stichwörter: IDetailsRte Info Info The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Die Route wurde in QMapShack importiert und geändert. Die ursprünglichen Daten werden nicht mehr angezeigt. Näheres siehe Änderungshistorie. - Toggle read only mode. You have to open the lock to edit the item. Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten. ... Hist. Historie IDetailsTrk Form - - Profile Profil Speed Geschw. Toggle read only mode. You have to open the lock to edit the item. Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten. ... Style Stil Source Quelle Maximum Minimum Width Breite - - - - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Der Track wurde in QMapShack importiert und geändert. Die ursprünglichen Daten werden nicht mehr angezeigt. Näheres siehe Änderungshistorie. with arrows mit Richtungspfeilen Graphs Diagramme Activity Aktivität Set Track Activity Trackaktivität festlegen To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Um Trackstatistiken zu differenzieren, wählen Sie für den gesamten Track eine Aktivität aus der Liste. Oder Sie wählen einen Teil des Tracks aus und weisen diesem eine Aktivität zu. Points Punkte Time Zeit Ele. Höhe Delta Delta Dist. Entf. Slope Neigung Position Position Info Info - Use/edit user defined visibility of arrows for this track Die benutzerdefinierte Sichtbarkeit der Richtungspfeile für diesen Track verwenden Use/edit system's visibility of arrows for all tracks Die vorgegebene Sichtbarkeit der Richtungspfeile für alle Tracks benutzen Use/edit user defined scale factor for this track Den benutzerdefinierten Skalierungsfaktor für diesen Track verwenden Use/edit system's default factor for all tracks Den vorgegebenen Skalierungsfaktor für alle Tracks benutzen x max. min. User defined limits for this track Benutzerdefinierte Grenzwerte für diesen Track Automatic limits Automatische Grenzwerte User defined limits for all tracks Benutzerdefinierte Grenzwerte für alle Tracks Color Farbe Ascent Anstieg Descent Abstieg Filter Filter Hist. Historie IDetailsWpt Dialog ... Info Info Position: Position: - Ele. Höhe Proximity: Abstand: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Der Wegpunkt wurde in QMapShack importiert und geändert. Die ursprünglichen Daten werden nicht mehr angezeigt. Näheres siehe Änderungshistorie. Toggle read only mode. You have to open the lock to edit the item. Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten. Hist. Historie Add images. Bilder hinzufügen. Delete selected image. Ausgewähltes Bild löschen. Date/Time: Datum/Zeit: IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Es gibt schon ein Projekt mit demselben Namen. Wenn Sie 'ok' drücken wird dieses entfernt und ersetzt. IElevationDialog Edit elevation... Höhe bearbeiten... Elevation Höhe - Get elevation from active digital elevation model. Höhe aus aktivem digitalen Höhenmodell entnehmen. ... IExportDatabase Export database to GPX... Datenbank als GPX exportieren... ... Export Path: Exportpfad: - GPX 1.1 without extensions GPX 1.1 ohne Erweiterungen Start Starten Abort Abbrechen Close Schließen IFilterDelete Form <b>Remove Track Points</b> <b>Trackpunkte entfernen</b> Remove all hidden track points permanently. Alle ausgeblendeten Trackpunkte werden dauerhaft entfernt. ... IFilterDeleteExtension Form <b>Remove Extension from all Track Points</b> <b>Erweiterung von allen Trackpunkten entfernen</b> Remove Entfernt from all Track Points von allen Trackpunkten ... IFilterDouglasPeuker Form <b>Hide Points (Douglas Peuker)</b> <b>Trackpunkte ausblenden (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Trackpunkte werden ausgeblendet, wenn der Abstand zu einer Linie zwischen benachbarten Punkten kleiner ist als m m Apply filter now. Den Filter jetzt anwenden. ... IFilterInterpolateElevation Form <b>Interpolate Elevation Data</b> <b>Höhendaten interpolieren</b> Replace elevation of track points with interpolated data. Die Höhe eines Trackpunktes durch einen interpolierten Wert ersetzen. Quality Qualität Preview Vorschau ... IFilterInvalid Form Hide Invalid Points Ungültige Punkte ausblenden Hide points with invalid data. Punkte mit ungültigen Daten ausblenden. ... IFilterMedian Form <b>Smooth Profile (Median Method)</b> <b>Profil glätten (Median-Methode) </b> Smooth deviation of the track points elevation with a Median filter of size Glättet die Abweichung der Höhe von Trackpunkten mit einem Median-Filter der Größe points Pkt. ... IFilterNewDate Form <b>Change Time</b> <b>Zeit ändern</b> Change start of track to Ändert den Trackbeginn auf dd.MM.yy HH:mm:ss dd.MM.yy HH:mm:ss - ... IFilterObscureDate Form <b>Obscure Timestamps</b> <b>Zeitstempel verschleiern</b> Increase timestamp by Erhöht den Zeitstempel um sec. s with each track point. 0 sec. will remove timestamps. für jeden Trackpunkt. 0 s entfernt alle Zeitstempel. ... IFilterOffsetElevation Form <b>Offset Elevation</b> <b>Höhenversatz</b> Add offset of Fügt einen Versatz von to track points elevation. zur Höhe der Trackpunkte hinzu. ... IFilterReplaceElevation Form <b>Replace Elevation Data</b> <b>Höhendaten ersetzen</b> Replace elevation of track points with the values from loaded DEM files. Ersetzt die Höhendaten durch Daten aus den geladenen DEM Dateien. ... IFilterReset Form <b>Reset Hidden Track Points</b> <b>Ausgeblendete Trackpunkte wiederherstellen</b> Make all trackpoints visible again. Alle Trackpunkte werden wieder sichtbar. ... IFilterSpeed Form <b>Change Speed</b> <b>Geschwindigkeit ändern</b> Set speed to Ändert Geschwindigkeit auf km/h km/h ... IFilterSplitSegment Form <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Tracksegmente in Tracks umwandeln</span></p></body></html> Creates a new track for every segment within this track. Für jedes Segment in diesem Track wird ein neuer Track erstellt. ... IFilterSubPt2Pt Form <b>Convert track subpoints to points</b> <p>Zwischenpunkte in Trackpunkte umwandeln</b> Convert subpoints obtained from routing to ordinary track points Zwischenpunkte vom autom. Routing werden in echte Trackpunkte umgewandelt ... IFilterTerrainSlope Form <b>Calculate Terrain Slope</b> <b>Hangneigung berechnen</b> Calculate slope of the terrain based on loaded DEM files. Berechnet die Hangneigung basierend auf dem geladenen Höhenmodell. ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. FIT Dekodierfehler: Nicht zutreffender Dekoderstatus %1 nach dem letzten Datenbyte der Datei. FIT decoding error: a development field with the field_definition_number %1 already exists. IGisDatabase Form Name Name Age Alter To add a database do a right click on the database list above. Eine neue Datenbank wird über einen Rechtsklick im Fenster erstellt. IGisItem [no name] [kein Name] The item is not part of the project in the database. Das Element ist nicht Teil des Projektes in der Datenbank. It is either a new item or it has been deleted in the database by someone else. Es ist entweder ein neues Symbol oder es wurde in der Datenbank gelöscht. The item is not in the database. Das Element ist nicht in der Datenbank. The item might need to be saved Es könnte notwendig sein, das Element zu speichern. Initial version. Erstversion. Never ask again. Aufhören nachzufragen. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3> Diese Element ist vermutlich schreibgeschützt, da nicht mit QMapShack erstellt. Normalerweise sollten importierte Daten nicht geändert werden. Wenn doch, drücken Sie 'OK'. Read Only Mode... Schreibgeschützt... <h4>Description:</h4> <h4>Beschreibung:</h4> <p>--- no description ---</p> <p>--- keine Beschreibung ---</p> <h4>Comment:</h4> <h4>Kommentar:</h4> <p>--- no comment ---</p> <p>--- kein Kommentar ---</p> <h4>Links:</h4> <h4>Verknüpfungen:</h4> <p>--- no links ---</p> <p>--- keine Verknüpfungen---</p> Edit name... Name bearbeiten... Enter new %1 name. Geben Sie einen neuen %1namen ein. IGisProject Save project? Projekt speichern? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>Das Projekt wurde geändert. Speichern, bevor es geschlossen wird? %1: Correlate tracks and waypoints. %1: Tracks und Wegpunkte verknüpfen. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>Hat das zu lange gedauert? Wollen Sie die Verknüpfung von Tracks und Wegpunkten auch in Zukunft für dieses Projekt überspringen? Canceled correlation... Verknüpfung abgebrochen... Save "%1" to... Speichere "%1" nach... <br/> Filename: %1 <br/> Dateiname: %1 Waypoints: %1 Wegpunkte: %1 Tracks: %1 Tracks: %1 Routes: %1 Routen: %1 Areas: %1 Gebiete: %1 Are you sure you want to delete '%1' from project '%2'? Sind Sie sicher, dass Sie '%1' aus dem Projekt '%2' löschen wollen? Delete... Löschen... IGisWorkspace Form Opacity Transparenz Change the opacity of all GIS Items on the map. Ändert die Transparenz von allen GIS Elementen auf der Karte. Filter Filter Name Name Clear Filter Filter zurücksetzen Setup Filter Filter einstellen IGridSetup Setup Grid... Gitter einstellen... Projection Projektion restore default Grundeinstellung wiederherstellen ... Get projection from current map. Projektion aus der aktuellen Karte nehmen. projection wizzard Projektionshilfe Grid color Gitterfarbe setup grid color Gitterfarbe einstellen IImportDatabase Form Source Database: Quelldatenbank: - Start Starten ... Target Database: Zieldatenbank: IInputDialog Edit... Bearbeiten... TextLabel Bezeichnung ILineOp Routing ILinksDialog Links... Verknüpfungen... Type Typ Text Text Uri URI ... IMainWindow QMapShack File Datei View Ansicht Window Fenster ? ? Tool Werkzeug Maps Karten Dig. Elev. Model (DEM) Dig. Höhenmodell (DEM) Toolbar Werkzeugleiste Routing Streckenführung Add Map View Kartenansicht hinzufügen Ctrl+T Show Scale Maßstab Setup Map Font Kartenfont einstellen Show Grid Gitter Ctrl+G Setup Grid Gitter einstellen Ctrl+Alt+G Flip Mouse Wheel Mausrad umdrehen Setup Map Paths Kartenverzeichnisse angeben POI Text POI Text Night / Day Nacht / Tag Map Tool Tip Kartentooltip Ctrl+I Setup DEM Paths DEM Verzeichnisse angeben About Über Help Hilfe F1 Setup Map View Kartenansicht einstellen VRT Builder VRT Builder GUI front end to gdalbuildvrt Eine graphische Benutzerschnittstelle zu gdalbuildvrt Store Map View Kartenansicht speichern Write current active map and DEM list including the properties to a file Speichert die aktiven Karten und DEM Dateien inklusive der Eigenschaften in einer Datei Load Map View Kartenansicht laden Restore view with active map and DEM list including the properties from a file Stellt die aktiven Karten und DEM Dateien inklusive der Eigenschaften aus einer Datei wieder her Ext. Profile Erw. Profil Ctrl+E Close Schließen Ctrl+Q Clone Map View Kartenansicht klonen Ctrl+Shift+T Create Routino Database Routino Datenbank erstellen Save(Print) Map Screenshot Kartenausschnitt speichern (drucken) Print a selected area of the map Einen ausgewählten Bereich der Karte drucken Ctrl+P Setup Coord. Format Koordinatenformat einstellen Change the format coordinates are displayed Ändert das Format der angezeigten Koordinaten Setup Map Background Kartenhintergrund einstellen Setup Waypoint Icons Wegpunktsymbole konfigurieren Setup path to custom icons Pfad zu individuellen Symbolen einrichten Close Tab Reiter schließen Ctrl+W Quickstart Help Schnellstartanleitung Setup Toolbar Werkzeugleiste einstellen Toggle Docks Fenster umschalten Toggle visibility of dockable windows Sichtbarkeit der andockbaren Fenster umschalten Ctrl+D Full Screen Vollbild F11 Min./Max. Track Values Min./Max. Trackwerte Show the minimum and maximum values of the track properties along the track in the map view. Zeigt die minimalen und maximalen Werte der Trackdaten in der Kartenansicht entlang des Tracks an. Ctrl+N Database Datenbank Workspace Arbeitsplatz Load GIS Data GIS Daten laden Load projects from file Lade Datei als Projekt Ctrl+L Save All GIS Data Alle GIS Daten speichern Save all projects in the workspace Alle Projekte, die sich auf dem Arbeitsplatz befinden, speichern Ctrl+S Setup Time Zone Zeitzone einstellen Add empty project Leeres Projekt hinzufügen Search Google Mit Google suchen Close all projects Alle Projekte schließen F8 Setup Units Einheiten einstellen Setup Workspace Arbeitsplatz konfigurieren Setup save on exit. Speichert Einstellungen beim Beenden. Import Database from QLandkarte Datenbankimport aus QLandkarte Import QLandkarte GT database QLandkarte GT Datenbank importieren IMapList Form To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Sie können Karten mit <b>"Menü -> Datei -> Kartenverzeichnisse angeben"</b> hinzufügen. Oder Sie klicken einfach <a href='setup'><b>hier</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Mit dem Kontextmenü (Klick mit rechter Maustaste auf einen Eintrag) können Sie eine Karte aktivieren. Um die Karten in einer anderen Reihenfolge anzuzeigen, können Sie jeden Eintrag mit drag-n-drop verschieben. Help! I want maps! I don't want to read the documentation! Hilfe! Ich will Karten! Keine Lust die Anleitung zu lesen! Activate Aktivieren Move Up Nach oben verschieben Hide map behind previous map Versteckt die Karte hinter der vorherigen Move down Nach unten verschieben Show map on top of next map Die Karte überlagert die nächste Reload Maps Karten erneut laden IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Diese Karte benötigt OpenSSL. Aufgrund rechtlicher Beschränkungen in einigen Ländern, ist OpenSSL nicht Bestandteil von QMapShack. Sie können sich auf der <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> nach Binäries umsehen. Sie müssen die Dateien libeay32.dll and ssleay32.dll in das QMapShack Programmverzeichnis kopieren. Error... Fehler... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: warte auf %2 Kacheln<br/> IMapPathSetup Setup map paths Kartenpfad einrichten Root path of tile cache for online maps: Hauptverzeichnis für den Kachelspeicher von Onlinekarten: ... Help! I want maps! I don't want to read the documentation! Hilfe! Ich will Karten! Keine Lust die Anleitung zu lesen! - IMapPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Ändert die Transparenz der Karte</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klicken um die aktuelle Skalierung als minimale Skalierung zu benutzen.</p></body></html> ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Stellt den Skalierungsbereich ein, in dem die Karte sichtbar ist. Benutzen Sie die beiden Knöpfe links und rechts um die minimale und maximale Skalierung einzustellen.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klicken um die aktuelle Skalierung als maximale Skalierung zu benutzen.</p></body></html> Areas Gebiete Lines Linien Points Punkte Details Details - Cache Path Speicherpfad Type File: TYP Datei: Forget external type file and use internal types. Externe TYP Datei vergessen und interne Typen verwenden. Load an external type file. Externe TYP Datei laden. Cache Size (MB) Cache (MB) Expiration (Days) Verfallzeit (Tage) IMapVrtBuilder Form Advanced Options Erweiterte Optionen Source No Data (-srcnodata) Kein Datenwert Quelle (-srcndata) Target No Data (-vrtnodata) Kein Datenwert Zieldatei (-vrtnodata) Target Projection (-a_srs) Projektion Zieldatei These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. Diese Optionen sind für spezielle Fälle. Normalerweise werden sie leer gelassen. Für mehr Information lesen Sie die GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Hilfe</a>. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> <ol> <li>Wählen Sie eine oder mehrere Quelldateien.</li> <li>Geben Sie einen Namen für die VRT Zieldatei an.</li> <li>Drücken Sie "Start".</li> </ol> Tipp: <ul> <li>Wenn Sie mehrere Dateien haben, verschieben Sie diese in einen Unterordner des Kartenpfades. Erstellen Sie die VRT Datei im Kartenpfad.</li> <li>Benützen Sie die erweiterten Optionen, um einen "keine Daten" Wert anzugeben, wenn ihre Quelldateien keinen haben und keinen rechteckigen Bereich abdecken. Gebiete ohne Karte werden dann transparent dargestellt.</li> <li>Mit der "-a_srs" Option können sie eine Projektion/Datum vorgeben, wenn dieses in den Quellen fehlt. Damit werden die Daten aber NICHT neu projiziert.</li> </ul> ... Select source files: Quelldateien auswählen: Target Filename: Zieldatei auswählen: - Start IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Neue Linie</b><br/>Erstellen Sie Punkte durch Verschieben des Mauscursors und Drücken der linken Maustaste. Mit der rechten Maustaste beenden Sie den Vorgang.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Punkt löschen</b><br/>Bewegen Sie den Mauscursor nahe an einen Punkt und drücken Sie die linke Maustaste um ihn zu löschen. <br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Punktebereich auswählen</b><br/>Mit der linken Maustaste wählen Sie den ersten Punkt aus. Mit einem erneuten Drücken der linken Maustaste wählen Sie den zweiten Punkt aus und dann wählen Sie eine der Optionen. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Punkt verschieben</b><br/>Bewegen Sie den Mauscursor nahe an einen Punkt und drücken die linke Maustaste, um ihn mit dem Cursor zu fangen. Verschieben Sie den Punkt mit der Maus. Setzen Sie den Punkt mit einem Linksklick. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Punkt hinzufügen</b><br/>Bewegen Sie den Mauscursor nahe an ein Liniensegment und drücken Sie die linke Maustaste, um einen Punkt hinzuzufügen. Der Punkt wird durch den Cursor gefangen und kann verschoben werden. Setzen Sie den Punkt mit einem Linksklick. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Kein Routing</b><br/>Alle Punkte werden mittels einer geraden Linie verbunden.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Auto Routing</b><br/>Die aktuellen Router Einstellungen erstellen eine Route zwischen Punkten. <b>Hinweis:</b> Der gewählte Router muss schnell routen können. Offline Router können dies gewöhnlich, Online Router nicht.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Vektor Routing</b><br/>Verbindet Punkte mit einer Linie einer geladenen Vektorkarte, soweit möglich.<br/> <b>%1 Metrics</b> <b>%1maße</b> Distance: Entfernung: Ascent: Anstieg: Descent: Abstieg: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> <br/><b>Karte verschieben</b><br/>Wenn Sie den linken Mausknopf gedrückt halten und die Maus bewegen, verschieben Sie die Karte.<br/><br/> IPhotoAlbum Form ... IPlot Reset Zoom Zoom zurücksetzen Stop Range Bereichsauswahl beenden Save... Speichern ... Add Waypoint Wegpunkt hinzufügen Cut... Teilen... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Um nur vertikale zu zoomen, STRG Taste gedrückt halten. Um nur horizontal zu zoomen, ALT Taste gedrückt halten. No or bad data. Keine oder schlechte Daten. Select output file Ausgabedatei auswählen IPositionDialog Position ... Position... Enter new position Neue Position eingeben Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Falsches Positionsformat. Muss entweder "[N|S] ddd mm.sss [W|E] ddd mm.sss" oder "[N|S] ddd.ddd [W|E] ddd.ddd" sein IPrintDialog Print map... Karte drucken... When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. Um einen Ausschnitt einer Online Karte zu drucken, müssen Sie sicherstellen, dass die Karte in den Cache geladen wurde. Save Speichern When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. Um einen Ausschnitt einer Online Karte zu speichern, müssen Sie sicherstellen, dass die Karte in den Cache geladen wurde. TextLabel Bezeichnung Print Drucken IProgressDialog Please wait... Bitte warten... TextLabel Bezeichnung IProjWizard Proj4 Wizzard Proj4 Wizard Mercator UTM zone Zone user defined Benutzer definiert Datum World Mercator (OSM) Result: Ergebnis: UPS North (North Pole) UPS Nord (Nordpol) UPS South (South Pole) UPS Süd (Südpol) Projection Projektion IProjWpt Waypoint Projection Wegpunkt Projektion ... - Clone waypoint and move by: Wegpunkt kopieren und verschieben um: m m ° IRouterBRouter Form Profile Profil Alternative Variante display selected routing profile ausgewähltes Profil anzeigen ... on-the-fly routing BRouter: not running nicht gestartet start/stop BRouter BRouter starten/stoppen show BRouter console BRouter Logausgabe anzeigen Setup Einrichten Caution! BRouter is listening on all ports for connections. Vorsicht! BRouter horcht auf allen verfügbaren Schnittstellen. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Lizenz GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Mit freundlicher Genehmigung von <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> <p>Routendaten <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a></p> IRouterBRouterInfo BRouter Profile BRouter Profil TextLabel Bezeichnung IRouterBRouterSetupWizard BRouter Setup BRouter Einrichtung choose which BRouter to use bitte den zu verwendenden BRouters auswählen: BRouter-Web (online) local Installation lokale Installation Expert Mode Experten Modus local BRouter Installation directory: lokales BRouter Installations-Verzeichnis: select installation directory Installationsverzeichnis auswählen ... labelLocalDirResult create or update installation Installation neu anlegen oder aktualisieren Java Executable ausführbares Java Programm labelLocalJavaResult search for installed java nach installiertem Java-programm suchen Download and install BRouter Version BRouter-Version herunterladen und installieren about:blank File to install zu installierende Datei Download and Install Herunterladen und Installieren available Profiles Verfügbare Profile install profile Profil installieren remove profile Profil entfernen installed Profiles Installierte Profile content of profile Profil-Inhalt BRouter-Web URL: Adresse (URL) von BRouter-Web Service-URL Adresse (URL) des Routing Service Profile-URL Adresse (URL) der Profile Hostname Servername Port Profile directory Profil-Verzeichnis Segments directory Segement-Verzeichnis Custom Profiles dir Verzeichnis für angepasste Profile Max Runtime Maximale Laufzeit Number Threads Anzahl Threads Java Options Java Optionen Profiles Url Profil-Url IRouterMapQuest Form Highways Autobahnen Toll Road Mautstraßen Seasonal saisonale Straßen Unpaved unbefestigte Straßen Ferry Fähren Language Sprache Country Border Landesgrenzen Profile Profil Avoid: Vermeide: <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Mit freundlicher Genehmigung von <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Profile Profil Mode Modus Database Datenbank Add paths with Routino database. Fügt Pfade mit Routino Datenbanken hinzu. ... Language Sprache To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Um Offline-Routing zu nutzen, müssen Sie einen Pfad zu einer lokalen Routendatenbank angeben. Benutzen Sie dazu den Knopf mit dem blauen Ordner. Sie können mit <b>Werkzeug->Routino Datenbank erstellen</b> eine solche Routendatenbank selber erzeugen. IRouterRoutinoPathSetup Setup Routino database... Routino Datenbank einrichten... ... - IRouterSetup Form IRoutinoDatabaseBuilder Form ... Select source files: Quelldateien auswählen: Start Starten Target Path: Zielpfad: - File Prefix Dateipräfix <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> <p>Damit Sie eine Routingdatenbank für Routino erstellen können, müssen Sie *pbf Dateien von <a href='http://download.geofabrik.de/'>GeoFabrik</a> herunterladen. Es dauert sehr lange eine Datenbank für Routino zu erstellen und die erstellten Dateien sind sehr groß. Deswegen ist es nicht empfehlenswert ganze Kontinente herunterzuladen. Allerdings kann Routino nicht über mehrere Datenbanken routen. Deswegen sollten alle Länder, die von einer länderübergreifenden Route berührt werden, in der Datenbank dabei sein.</p> <ol> <li>Eine oder mehrere *.pbf Dateien auswählen.</li> <li>Ein Verzeichnis für die Datenbank angeben.</li> <li>Einen Prefix bestimmen. Die Datenbank wird mit diesem Prefix gelistet.</li> <li>Den ""Start" Knopf drücken.</li> </ol> IScrOptEditLine Form Save to original Ins Original speichern Save as new Als neu speichern Abort Abbrechen Move points. (Ctrl+M) Punkte verschieben. (Strg+M) Ctrl+M Add new points. (Ctrl++) Punkte hinzufügen. (Strg++) Ctrl++ Select a range of points. (Ctrl+R) Einen Punktebereich wählen (Strg+R) Ctrl+R No auto-routing or line snapping (Ctrl+O) Kein Auto-Routing oder Fangen an Linie (Strg+O) Ctrl+O Use auto-routing to between points. (Ctrl+A) Auto-Routing zwischen Punkten benutzen. (Strg+A) Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Fängt die Linie entlang Linien einer Vektorkarte. (Strg+V) ... Delete a point. (Ctrl+-) Punkte löschen (Strg+-) Ctrl+- 0 A V Ctrl+V Undo last change Letzte Änderung rückgängig machen Redo last change Letzte Änderung wiederherstellen IScrOptOvlArea Form View details and edit. Details anzeigen und bearbeiten. ... Copy area into another project. Gebiet in ein anderes Projekt kopieren. Delete area from project. Gebiet aus einem Projekt entfernen. Edit shape of the area. Form eines Gebietes ändern. TextLabel Bezeichnung IScrOptPrint Form Save selected area as image. ... Print selected area. Druckt gewählten Bereich. IScrOptRangeLine Form Delete all points between the first and last one. Alle Punkte zwischen dem ersten und dem letzten Punkt löschen. ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Eine Route zwischen dem ersten und dem letzten gewählten Punkt berechnen.</p></body></html> IScrOptRangeTrk Form Hide all points. Blendet alle Punkte aus. Show all points. Blendet alle Punkte ein. Set an activity for the selected range. Für den ausgewählten Bereich eine Aktivität festlegen. Copy track points as new track. Kopiert Trackpunkte in neuen Track. ... TextLabel Bezeichnung IScrOptRte Form View details and edit. Details anzeigen und bearbeiten. ... Copy route into another project. Kopiert die Route in ein anderes Projekt. Delete route from project. Route aus einem Projekt entfernen. Reset route calculation. Routenberechnung zurücksetzen. Calculate route. Route berechnen. Move route points. Routenpunkte verschieben. Convert route to track Die Route in einen Track umwandeln TextLabel Bezeichnung IScrOptSelect Form Copy all selected items to a project. Kopiert alle gewählten Elemente in ein Projekt. ... Create a route from selected waypoints. Route aus den gewählten Wegpunkten erstellen. Change the icon of all selected waypoints. Das Symbol wird für alle ausgewählten Wegpunkte geändert. Combine all selected tracks to a new one. Alle ausgewählten Tracks zusammenführen. Set an activity for all selected tracks. Für alle ausgewählten Tracks eine Aktivität festlegen. Delete all selected items. Löscht alle gewählten Elemente. Select all items that intersect the selected area. Wählt alle Elemente, die den gewählten Bereich schneiden. Select all items that are completely inside the selected area. Alle Elemente auswählen, die komplett innerhalb des ausgewählten Gebietes sind. Add tracks to selection. Fügt Tracks zur Auswahl hinzu. Add waypoints to selection. Fügt Wegpunkte zur Auswahl hinzu. Add routes to selection. Fügt Routen zur Auswahl hinzu. Add areas to selection. Fügt Gebiete zur Auswahl hinzu. IScrOptTrk Form Copy track into another project. Track in ein anderes Projekt kopieren. Show on-screen profile and detailed information about points. Zeigt das Profil und detaillierte Informationen der Punkte. Edit position of track points. Position von Trackpunkten bearbeiten. View details and edit properties of track. Details anzeigen und Trackeigenschaften bearbeiten. Delete track from project. Track aus einem Projekt entfernen. Select a range of points. Wähle einen Punktebereich. Reverse track. Track umkehren. Combine tracks. Tracks verbinden. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Zerteilt den Track am ausgewählten Punkt. Damit kann man: * schlechte Punkte am Anfang oder Ende eines Tracks entfernen * die Teile zum Planen neuer Touren verwenden * einen langen Track in Etappen zerteilen Set an activity for the complete track. Für den ganzen Track eine Aktivität festlegen. ... Copy track together with all attached waypoints into another project. Kopiert den Track zusammen mit allen verknüpften Wegpunkten. TextLabel Bezeichnung IScrOptWpt Form View details and edit. Details anzeigen und editieren. ... Copy waypoint into another project. Wegpunkt in ein anderes Projekt kopieren. Delete waypoint from project. Wegpunkt aus einem Projekt entfernen. Show content as static bubble. Inhalt als statische Legende zeigen. Move waypoint to a new location. Wegpunkt an einen neuen Ort verschieben. Clone waypoint and move clone a given distance and angle. Wegpunkt klonen und um eine bestimmte Entfernung und einen bestimmten Winkel verschieben. edit radius of circular area Den Abstandsradius ändern Switch between proximity and nogo-area Zwischen Abstandsalarm und Gebietsvermeidung umschalten. Delete circle defined by waypoint Den Abstandskreis entfernen. TextLabel Bezeichnung IScrOptWptRadius Form edit radius of circular area Den Abstabdsradius ändern. ... Switch between proximity and nogo-area Zwischen Abstandsalarm und Gebietsvermeidung umschalten. Delete circle defined by waypoint Den Abstandskreis entfernen. TextLabel Bezeichnung ISearchDatabase Search... Suchen... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Tippen Sie das Wort, das sie suchen ein und drücken Sie den 'Suchen' Knopf. Wenn Sie das Wort 'wort' eingeben, wird exakt nach dem Wort gesucht. Wenn Sie das Wort 'wort*' eingeben, dann muss 'wort' nur am Anfang stehen. Name Name Search Suchen Close Schließen ISelDevices Select devices... Geräte auswählen... ISelectActivityColor Form ISelectCopyAction Copy item... Element kopieren... Replace existing item Ersetzt vorhandenes Element TextLabel Bezeichnung Do not copy item Element nicht kopieren Create a clone Einen Klon erstellen Replace with: Ersetzen mit: Keep item: Element behalten: The clone's name will be appended with '_Clone' Der Name des Klones wird mit '_Klon' erweitert And for all other items, too. Auch für alle anderen Elemente anwenden. ISelectDBFolder Select Parent Folder... Übergeordneten Ordner auswählen... Name Name ISelectDoubleListWidget Form Available Verfügbar Add to selected items Zu den ausgewählten Einträgen hinzufügen Remove from selected items Von den ausgewählten Einträgen entfernen Selected Ausgewählt Move selected items up Ausgewählte Einträge nach oben Move selected items down Ausgewählte Einträge nach unten ... ISelectProjectDialog Select a project... Ein Projekt auswählen... Select project from list or enter new project name. Wähle ein Projekt aus der Liste oder gib einen neuen Projektnamen ein. New project's name Neuer Projektname New project is created as: Das neue Projekt wird erstellt als: *.qms *.gpx Database Datenbank ISelectSaveAction Copy item... Element kopieren... Replace existing item Ersetzt vorhandenes Element Add a clone Einen Klon hinzufügen The clone's name will be appended with '_Clone' Der Name des Klones wird mit '_Klon' erweitert Replace with: Ersetzen mit: TextLabel Bezeichnung Do not replace item Das Element nicht ersetzen Use item: Element verwenden: And for all other items, too. Auch für alle anderen Elemente anwenden. ISetupDatabase Add database... Datenbank hinzufügen... - Name Name <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Achtung!</span> Es wird empfohlen, das Passwortfeld leer zulassen, da QMapShack dies als Klartext speichert. Wenn Sie kein Passwort vergeben, werden Sie bei jedem Start danach gefragt.</p> Do not use a password. Kein Passwort benutzen. SQLite MySQL Server Port 00000 User Benutzer Password Passwort <b>Port:</b> Leave the port field empty to use the default port. <b>Port:</b> Um den vorgegebenen Port zu nutzen, lassen Sie das Port-Feld leer. File: Datei: Add new database. Fügt eine neue Datenbank hinzu. ... Open existing database. Öffnet eine vorhandene Datenbank. ISetupFilter Form Apply filter to Filter anwenden auf name only den Namen complete text den vollständigen Text ISetupFolder Database Folder... Datenbankordner... Folder name Ordnername Group Gruppe Project Projekt Other Sonstige ISetupNewWpt New Waypoint... Neuer Wegpunkt... Symbol Symbol ... Position Position Name Name Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Falsches Positionsformat. Muss entweder "[N|S] ddd mm.sss [W|E] ddd mm.sss" oder "[N|S] ddd.ddd [W|E] ddd.ddd" sein ISetupWorkspace Setup workspace... Arbeitsplatz konfigurieren... save workspace on exit, and every Arbeitsplatz beim Beenden speichern, und alle minutes Minuten listen for database changes from other instances of QMapShack. On port lauscht nach Datenbankänderungen anderer QMapShack Instanzen. Auf Port 00000 ITemplateWidget Insert Template... Vorlage einfügen... Templates Vorlagen Select a path with your own templates. Wählen Sie einen Pfad mit ihren eigenen Vorlagen aus. ... Preview Vorschau ITextEditWidget Edit text... Text bearbeiten... Undo Rückgängig Ctrl+Z Redo Wiederherstellen Ctrl+Shift+Z Cut Ausschneiden Ctrl+X Copy Kopieren Ctrl+C Paste Einfügen Templ. Vorl. A:L A:C A:R A:B B I U C Standard Standard Bullet List (Disc) Bullet List (Circle) Bullet List (Square) Ordered List (Decimal) Ordered List (Alpha lower) Ordered List (Alpha upper) Ordered List (Roman lower) Ordered List (Roman upper) Ctrl+V Align Left Linksbündig Ctrl+L Align Right Rechtsbündig Ctrl+R Align Center Zentriert Ctrl+E Align Block Blocksatz Ctrl+J Underline Unterstreichen Ctrl+U Bold Fett Ctrl+B Italic Kursiv Ctrl+I Plain Schlicht Reset the text's format before pasting Das Textformat wird entfernt bevor der Text eingefügt wird Select All Alles auswählen Ctrl+A Delete Löschen Reset Font Font zurücksetzen Reset Layout Layout zurücksetzen Normal Normal Paste without resetting the text's format Einfügen ohne das Format zurückzusetzen Insert From Template Aus Vorlage einfügen Create text from template. Text aus einer Vorlage erzeugen. ITextEditWidgetSelMenu B I U Cut Ausschneiden Copy Kopieren Paste Einfügen ITimeZoneSetup Setup Time Zone ... Zeitzone einstellen... UTC Local Lokal Automatic Automatisch Print date/time in Datum/Uhrzeit in long format, or langem Format, oder short format kurzem Format ausgeben <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Anmerkung:</b> Das Ändern der Einheiten wird bei einigen GUI-Elementen erst nach einem Neustart von QMapShack wirksam. IToolBarSetupDialog Setup Toolbar Werkzeugleiste einstellen Toolbar is visible in Fullscreen-mode Werkzeugleiste ist im Vollbildmodus sichtbar IToolShell Execution of external program `%1` failed: Ausführen des externen Programms `%1` ist fehlgeschlagen: Process cannot be started. Der Prozess konnte nicht gestartet werden. Make sure the required packages are installed, `%1` exists and is executable. Stellen Sie sicher, dass die erforderlichen Pakete installiert sind, `%1` existiert und ist ausführbar. External process crashed. Der externe Prozess ist abgestürzt. An unknown error occurred. Ein unbekannter Fehler ist aufgetreten. !!! failed !!! !!! fehlgeschlagen !!! IUnit Error Fehler Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Falsches Positionsformat. Muss entweder "[N|S] ddd mm.sss [W|E] ddd mm.sss" oder "[N|S] ddd.ddd [W|E] ddd.ddd" sein. Position values out of bounds. Position außerhalb der gültigen Werte. IUnitsSetup Setup units... Einheiten einrichten... Length unit Längeneinheit Metric metrisch Slope unit Steigung Degrees (°) Grad (°) Percent (%) Prozent (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Anmerkung:</b> Das Ändern der Einheiten wird bei einigen GUI-Elementen erst nach einem Neustart von QMapShack wirksam. Imperial imperial Nautic nautisch IWptIconDialog Icons... Symbole... External Icons: Externe Symbole: - ... All custom icons have to be *.bmp or *.png format. Alle individuellen Symbole müssen im *.bmp oder *.png Format sein. qmapshack-1.10.0/src/locale/qmapshack_nl.ts000644 001750 000144 00001463273 13216421215 021776 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2, verwachte V%3) %1 (API V%2) %1 (API V%2) (no DBUS: device detection and handling disabled) CActivityTrk Foot Wandelen Bicycle Fiets Motor Bike Motorfiets Car Auto Cable Car Kabelbaan Swim Zwemmen Ship Boot No Activity Total Ascent: Descent: Ski/Winter Ski/Winter Aeronautics Vliegtuig Public Transport Distance: Afstand: Speed Moving: Bewogen snelheid: Speed Total: Totale snelheid: Time Moving: Bewogen tijd: Time Total: Totale tijd: CCanvas View %1 Venster %1 Setup Map Background CColorChooser Esc. CCommandProcessor Print debug output to console. Toon debug resultaat op scherm. Print debug output to logfile (temp. path). Sla debug resultaat op als bestand (tijdelijk psd). Do not show splash screen. Toon geen splash scherm. File with QMapShack configuration. Bestand met QMapShack. configuratie. file bestand Files for future use. Bestanden voor toekomstig gebruik. CCreateRouteFromWpt route CDBFolderLostFound All your data grouped by folders. Alle gegevens gegroepeerd per map. Lost & Found (%1) Lost & Found (%1) Lost & Found Lost & Found CDBFolderMysql All your data grouped by folders. Alle gegevens gegroepeerd per map. MySQL Database MySQL Database Server: (No PW) Error: Fout: CDBFolderSqlite All your data grouped by folders. Alle gegevens gegroepeerd per map. SQLite Database SQLite Database File: Bestand: Error: Fout: CDBItem %1 min. %1 h %1 days CDBProject Failed to load... Can't load file "%1" . It will be skipped. Project already in database... The project "%1" has already been imported into the database. It will be skipped. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database Het item %1 is verand door %2 (%3). Om dit conflict op te lossen kan een kloon gemaakt en opgelagen worden, forceer huidige versie of verwijder deze versie en kies een ander uit de database Conflict with database... Conflict met database... Clone && Save Kloon && Opslaan Force Save Forceer opslaan Take remote Neem huidige Missing folder... Failed to save project. The folder has been deleted in the database. Save ... Opslaan... Error Fout There was an unexpected database error: %1 Er is een onverwachte database fout opgetreden: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Het project '%1' zal geupdated worden met de database.Er zijn nog veranderingen niet opgeslagen. Save changes? Veranderingen opslaan? CDemList Deactivate Deactiveer Activate Activeer CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Maak of verwijder mappen naar DEM gegevens.-Er kunnen meerdere bestanden in een map zijn maar geen submappen Ondersteunende formaten zijn: %1 Select DEM file path... Selecteer map met DEM bestanden... CDemVRT Error... Fout... Failed to load file: %1 Kan bestand %1 niet laden DEM must have one band with 16bit or 32bit data. DEM moet 16 bit of 32 bit gegevens bevatten. No georeference information found. Geen geografische gegevens gevonden. CDetailsGeoCache none geen ??? ??? Searching for images... Zoeken naar afbeeldingen... No images found Geen afbeeldingen gevonden CDetailsPrj You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Om wayponts van een track te sorteren dient de correlatie van track en waypoints ingeschakeld zijn.. Moet dit weer ingeschakeld worden? Correlation... Correlatie... none geen Build diary... Dagboek maken... <b>Summary over all tracks in project</b><br/> <b>Overzicht van alle tracks in project</b><br/> <h2>Waypoints</h2> <h2>Waypoints</h2> Info Info Comment Notitie <h2>Tracks</h2> <h2>Tracks</h2> From Start To Next To End Distance: Ascent: Descent: <h2>Areas</h2> <h2>Gebieden</h2> <h2>Routes</h2> <h2>Routes</h2> Edit name... Bewerk naam... Enter new project name. Geef project een nieuwe naam. Edit keywords... Bewerkt sleutelwoorden... Enter keywords. Geef sleutelwoorden. Print Diary Dagboek afdrukken CDetailsTrk Reduce visible track points Reduceer zichtbare trackpunten Change elevation of track points Verander hoogte van trackpunten Change timestamp of track points Verander tijdstempels van trackpunten Miscellaneous Color Kleur Activity Activiteit CDetailsWpt Enter new proximity range. Geef nieuwe afstand in voor nabijheid. CDeviceGarmin Picture%1 Afbeelding%1 Unknown Onbekend CDeviceGarminArchive Archive - expand to load Archive - loaded CElevationDialog No DEM data found for that point. Geen OEM gegevens gevonden voor dit punt. CExportDatabase Select export path... CExportDatabaseThread Create %1 Failed to create %1 Done! Abort by user! Database Error: %1 Save project as %1 Failed! CFilterDeleteExtension No extension available CFilterInterpolateElevation coarse medium fine CFitCrcState FIT decoding error : invalid CRC. CFitDecoder FIT decoding error: unexpected end of file %1. CFitFieldBuilder FIT decoding error: unknown base type %1. CFitFieldDataState Missing field definition for development field. FIT decoding error: invalid field def nr %1 while creating dev field profile. CFitHeaderState FIT decoding error: protocol %1 version not supported. FIT decoding error: file header signature mismatch. File is not FIT. CFitProject Failed to load file %1... Kan bestand %1 niet laden... Failed to open FIT file %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. FIT decoding error: invalid offset %1 for state 'record content' CGarminTyp Warning... Waarschuwing... This is a typ file with unknown polygon encoding. Please report! Dit is een bestand met onbekende polygon codering. Alstublieft melden! This is a typ file with unknown polyline encoding. Please report! Dit is een bestand met onbekende polylijn codering. Alstublieft melden! CGisItemOvlArea thin dun normal normaal wide breed strong vet _Clone _Kloon Area: %1%2 Gebied: %1%2 Changed area shape. Vorm gebied aangepast. Changed name. Naam aangepast. Changed border width. Lijndikte aangepast. Changed fill pattern. Opvulling aangepast. Changed opacity. Transparantie aangepast. Changed comment. Notitie aangepast. Changed description. Beschrijving aangepast. Changed links Link aangepast Changed color Kleur aangepast CGisItemRte _Clone _Kloon track Changed name. Naam aangepast. Changed comment Notitie aangepast Changed description Beschrijving aangepast Changed links Link aangepast Length: %1%2 Lengte: %1%2 Time: %1%2 Tijd: %1%2 Distance: %1%2 Afstand: %1%2 Length: - Lengte: - Time: - Tijd: - %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Laatste routeberekening:<br/>%1 with %1 met %1 Changed route points. Routepunten aangepast. CGisItemTrk FIT file %1 contains no GPS data. Error... Fout... Failed to open %1. Kan %1 niet openen. Only support lon/lat WGS 84 format. Alleen lon/lat WGS 84 formaat word ondersteunt. Failed to read data. Lezen gegevens mislukt. _Clone _Kloon Changed trackpoints, sacrificed all previous data. Trackpunten aangepast, vorige gegevens overschreven. Time: %1%2, Speed: %3%4 Moving: %1%2, Speed: %3%4 Start: %1 Start: %1 Start: - End: %1 Einde: %1 End: - Points: %1 (%2) Punten: %1 (%2) Invalid elevations! Invalid timestamps! Invalid positions! Activities: %1 Index: %1 Index: visible %1, total %2 , Slope: %1%2 ... and %1 tags not displayed ... en %1 tags niet getoont Distance: - (-) Moving: - (-) track Hide point %1. Hide points %1..%2. , %1%2 , %1%2 Invalid points.... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? min. max. Length: %1%2 Lengte: %1%2 , %1%2%3, %4%5%6 , %1%2 %3, %4%5%6 {1%2%3,?} , %1-, %2- Time: -, Speed: - Moving: -, Speed: - Ele.: %1%2 Hoogte.: %1%2 , Speed: %1%2 Ascent: - (-) Descent: - (-) Ascent: %1%2 (%3%) , Descent: %1%2 (%3%) Distance: %1%2 (%3%) , Moving: %1%2 (%3%) Ascent: - Descent: - Ascent: %1%2 , Descent: %1%2 Distance: %1%2 Afstand: %1%2 , Time: %1%2 Permanently removed points %1..%2 Permanent verwijderde punten %1..%2 Show points. Toon punten. Changed name Naam aangepast Changed comment Notitie aangepast Changed description Beschrijving aangepast Changed links Link aangepast Changed elevation of point %1 to %2 %3 Changed activity to '%1' for complete track. Activiteit aangepast naar '%1' voor gehele track. Changed activity to '%1' for range(%2..%3). Activiteit aangepast naar '%1' voor bereik(%2..%3). Hide points by Douglas Peuker algorithm (%1%2) Verberg alle punten via Douglas Peuker algoritme (%1%2) Hide points with invalid data. Reset all hidden track points to visible Verander alle verborgen trackpunten naar zichtbaar Permanently removed all hidden track points Alle verborgen trackpunten permanent verwijderd Smoothed profile with a Median filter of size %1 Vloeiend profiel met een median filter van grootte %1 Added terrain slope from DEM file. Replaced elevation data with data from DEM files. Vervang hoogte gegevens met gegevens van DEM bestanden. Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Changed start of track to %1. Start van track veranderd naar %1. Remove timestamps. Verwijder tijdstempels. Set artificial timestamps with delta of %1 sec. Changed speed to %1%2. Snelheid veranderd naar %1%2. %1 (Segment %2) %1 (Segment %2) Removed extension %1 from all Track Points Converted subpoints from routing to track points Copy flag information from QLandkarte GT track Kopieer flag informatie vanuit QLandkarte GT track CGisItemWpt Archived Gearchiveerd Available Beschikbaar Not Available Niet beschikbaar _Clone _Kloon Elevation: %1%2 Hoogte: %1%2 Proximity: %1%2 Nabijheid: %1%2 Changed name Naam aangepast Changed position Positie aangepast Changed elevation Hoogte aangepast Removed proximity Changed proximity Nabijheid aangepast Changed icon Pictogram aangepast Changed comment Notitie aangepast Changed description Beschrijving aangepast Changed links Link aangepast Changed images Afbeelding aangepast Add image Afbeelding toevoegen Changed to proximity-radius Changed to nogo-area CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Door een aanpassing in het database systeem is QMapShack de bestandnaam van database ''%1' vergeten. Selecteer dit weer in de volgende stap. Select database file. Selecteer database bestand. Add Database Database toevoegen Add Folder Map toevoegen Rename Folder Copy Folder Move Folder Delete Folder Map verwijderen Import from Files... Export to GPX... Delete Item Element verwijderen Search Database Sync. with Database Syngroniseren met database Remove Database Database verwijderen Empty Leeg Remove database... Database verwijderen... Do you really want to remove '%1' from the list? Moet '%1' werkelijk uit de lijst verwijderd worden? Delete database folder... Verwijder database map... Are you sure you want to delete selected folders and all subfolders from the database? Bad operation.... The target folder is a subfolder of the one to move. This will not work. Folder name... Rename folder: Remove items... Elementen verwijderen... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Moeten alle elementen worden verwijderd uit Verloren & Gevonden? Dit zal pemanent zijn. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Moeten alle geselecteerde elementen worden verwijderd uit Verloren & Gevonden? Dit zal pemanent zijn. Are you sure you want to delete '%1' from folder '%2'? Moet '%1' uit map '%2' verwijderd worden? Delete... Verwijderen... Import GIS Data... CGisListWks Edit.. Bewerken.. Show on Map Toon op kaart Hide from Map Toon niet op kaart Sort by Time Sort by Name Save Opslaan Save as GPX 1.1 w/o ext... Send to Devices Verzend naar GPS Sync. with Database Syngroniseren met database Close Sluiten Update Project on Device Update project op GPS Delete Verwijder Edit... Bewerken... Copy to... Kopieer naar... Autom. Save Save as... Track Profile Track profiel Select Range Selecteer afstand Edit Track Points Trackpunten bewerken Reverse Track Track omdraaien Combine Tracks Combineer tracks Copy Track with Waypoints Show Bubble Toon ballon Move Waypoint Verplaats waypoint Proj. Waypoint... Projecteer waypoint... Change Radius Toggle Nogo-Area Delete Radius Route Instructions Route instructies Calculate Route Route berekenen Reset Route Route omkeren Edit Route Bewerk route Convert to Track Edit Area Points Bewerk gebied punten Create Route Maak route Change Icon (sel. waypt. only) Set Track Activity Drop items... Elementen wissen... <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Updaten GPS</b><p>Updaten %1<br/>Moment geduld...</p> Saving workspace. Please wait. Werkruimte opslaan. Moment geduld. Loading workspace. Please wait. Laden werkruimte. Moment geduld. Close all projects... Sluit alle projecten... This will remove all projects from the workspace. Dit zal alle projecten uit de werkruimte verwijderen. Delete project... Project verwijderen... Do you really want to delete %1? Moet %1 werkelijk verwijderd worden? CGisWorkspace Load project... Project laden... The project "%1" is already in the workspace. Het project "%1" is al geopend. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. Copy items... Kopieer elementen... Change waypoint symbols. Cut Track... Track knippen... Do you want to delete the original track? Moet de orginele track verwijderd worden? CGpxProject Failed to load file %1... Kan bestand %1 niet laden... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Not a GPX file: %1 Geen GPX bestand: %1 File exists ... Bestand bestaat al... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Dit bestand bestaat al en is niet in QMapShack gemaakt. Wanneer op 'Ja' geklikt wordt zullen er gegevens verloren gaan. Alhoewel QMapShack dit GPX bestand kan openen is het mogelijk dat niet alle elementen opgeslagen kunnen worden. Geadviseerd wordt om een ander bestand te kiezen. <b>Moet dit bestand werkelijk overschreven worden?<b/> Failed to create file '%1' Maken bestand mislukt '%1' Failed to write file '%1' Schrijven bestand mislukt '%1' Saving GIS data failed... Opslaan GIS gegevens mislukt... CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1m, %2m N %1m, E %2m N %1m, O %2m CHistoryListWidget by %1 per %1 Cut history before Cut history after History removal The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> CImportDatabase Import QLandkarte Database QLandkarte database importeren Select source database... Bron database selecteren... Select target database... Doel database selecteren... CKnownExtension Speed extLongName Snelheid Cadence extShortName Cadans Air Temp. extShortName Air Temperature extLongName Water Temp. extShortName Water Temperature extLongName Depth extShortName Diepte Depth extLongName Diepte Heart R. extShortName Heart Rate extLongName Cadence extLongName Cadans Speed extShortName Snelheid Accel. extShortName Acceleration extLongName Course extShortName Richting Course extLongName Richting Temp. extShortName Temperature extLongName Dist. extShortName Afstand. Distance extLongName Ele. extShortName Elevation extLongName Hoogte Energy extShortName Energy extLongName Sea Lev. Pres. extShortName Sea Level Pressure extLongName v. Speed extShortName Vertical Speed extLongName Slope extShortName Helling Speed over Distance* extLongName Speed over Time* extLongName Elevation* extLongName Progress extShortName Voortgang Progress* extLongName Terr. Slope extShortName Terrain Slope* extLongName Slope* CLogProject Failed to load file %1... Kan bestand %1 niet laden... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Not an Openambit log file: %1 Device: %1<br/> Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 CLostFoundProject Lost & Found Lost & Found CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Ele.: %1%2 Hoogte.: %1%2 Slope: %1%2 terrain [Grid: %1] [Raster: %1] Load GIS Data... GIS gegevens laden... Select output file Selecteer bestand QMapShack View (*.view) Select file to load Selecteer bestand Fatal... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. CMapIMG Failed ... Mislukt... Unspecified Ongespecificeerd French Frans German Duits Dutch Nederlands English Engels Italian Italiaans Finnish Fins Swedish Zweeds Spanish Spaans Basque Baskisch Catalan Catalaans Galician Galicisch Welsh Wels Gaelic Gaelisch Danish Deens Norwegian Noors Portuguese Portugees Slovak Slowaaks Czech Tsjechisch Croatian Kroatisch Hungarian Hongaars Polish Pools Turkish Turks Greek Grieks Slovenian Sloveens Russian Russisch Estonian Ests Latvian Lets Romanian Roemeens Albanian Albanisch Bosnian Bosnisch Lithuanian Litouws Serbian Servisch Macedonian Macedonisch Bulgarian Bulgaars Major highway Belangrijke snelweg Principal highway Gewone snelweg Other highway Andere snelweg Arterial road Uitvalsweg Collector road Verzamelweg Residential street Woonstraat Alley/Private road Laan/privéweg Highway ramp, low speed Snelweg oprit, langzame snelheid Highway ramp, high speed Snelweg oprit, hoge snelheid Unpaved road Onverharde weg Major highway connector Belangrijke snelwegknooppunt Roundabout Rotonde Railroad Spoorlijn Shoreline Kustlijn Trail Pad Stream Stroom Time zone Tijdzone Ferry Veerdienst State/province border Staat/provinciegrens County/parish border Provincie/gemeentegrens International border Internationale grens River Rivier Minor land contour Klein hoogteverschil Intermediate land contour Gemiddeld hoogteverschil Major land contour Groot hoogteverschil Minor depth contour Klein diepteverschil Intermediate depth contour Gemiddeld diepteverschil Major depth contour Groot diepteverschil Intermittent stream Intermitterende beek Airport runway Landingsbaan Pipeline Pijplijn Powerline Hoogspanningsleiding Marine boundary Zeegrens Hazard boundary Gevaarlijke grens Large urban area (&gt;200K) Groot bevolkt gebied (&gt;200K) Small urban area (&lt;200K) Klein bevolt gebied (&lt;200K) Rural housing area Landelijk woongebied Military base Militaire basis Parking lot Parkeerterrein Parking garage Parkeergarage Airport Vliegveld Shopping center Winkelcentrum Marina Jachthaven University/College Universiteit/College Hospital Ziekenhuis Industrial complex Industrie Reservation Reservaat Man-made area Gemaakt gebied Sports complex Sprtcomplex Golf course Golfbaan Cemetery Begraafplaats National park Nationaal park City park Stadspark State park Staatspark Forest Bos Ocean Oceaan Blue (unknown) Blauw (onbekend Sea Zee Large lake Groot meer Medium lake Middelmatig meer Small lake Klein meer Major lake Belangrijk meer Major River Belangrijke rivier Large River Groot rivier Medium River Middelmatig rivier Small River Klein rivier Intermittent water Intermitterende water Wetland/Swamp Moeras Glacier Gletsjer Orchard/Plantation Boomgaard/Plantage Scrub Struikgewas Tundra Toendra Flat Vlak ??? ??? Read external type file... Failed to read type file: %1 Fall back to internal types. Failed to read: Lezen mislukt: Failed to open: Openen mislukt: Bad file format: Verkeerd bestandsformaat: Failed to read file structure: Lezen bestandsstructuur mislukt: Loading %1 Laden %1 User abort: Afgebroken door gebruiker: File is NT format. QMapShack is unable to read map files with NT format: Bestand is in NT formaat. QMapShack kan geen kaarten lezen met NT formaat: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Point of Interest Interessant punt Unknown Onbekend Area Gebied CMapList Deactivate Deactiveer Activate Activeer Where do you want to store maps? Waar moeten de kaarten opgeslagen worden? CMapMAP Failed ... Failed to open: Openen mislukt: Bad file format: Verkeerd bestandsformaat: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Maak of verwijder mappen naar kaarten.-Er kunnen meerdere kaarten in een map zijn maar geen submappen Ondersteunende formaten zijn: %1 Select map path... Selecteer kaartmap... Select root path... Selecteer hoofdmap... CMapPropSetup Select type file... CMapRMAP Error... Fout... This is not a TwoNav RMAP file. Dit is geen TwoNav RMAP bestand. Unknown sub-format. Onbekend sub formaat. Unknown version. Onbekende versie. Failed to read reference point. Kan geen referentiepunten lezen. Unknown projection and datum (%1%2). Onbekende projectie en datum (%1%2). CMapTMS Error... Fout... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Layer %1 Laag-%1 CMapVRT Error... Fout... Failed to load file: %1 Bestand laden mislukt: %1 File must be 8 bit palette or gray indexed. Bestand moet 8 bit kleur of grijs geindexeerd zijn. No georeference information found. Geen geografische gegevens gevonden. CMapVrtBuilder Build GDAL VRT GDAL VRT maken Select files... Selecteer bestanden... Select target file... Selecteer doel bestand... !!! done !!! !!! klaar !!! CMapWMTS Error... Fout... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Failed to read: %1 Unknown structure. Lezen mislukt: %1 Onbekende structuur. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Onverwachte service. '*WMTS 1.0.0' is verwacht. '%1 %2' is gelezen. No georeference information found. Geen geografische gegevens gevonden. CMouseEditArea Area Gebied <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Bewerk gebied</b><br/>Selecteer een functie en een routeoptie via de gereedschapknoppen. Selecteer dan een punt op de lijn. Alleen zwarte vierkante punten kunnen gewijzigd worden. De ronde zwarte subpunten niet.<br/> area CMouseEditRte Route Route <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Bewerk route punten</b><br/>Selecteer een functie en een routeoptie via de gereedschapknoppen. Selecteer dan een punt op de lijn. Alleen zwarte vierkante punten kunnen gewijzigd worden. De ronde zwarte subpunten niet.<br/> route CMouseEditTrk Track Track <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Bewerk track punten</b><br/>Selecteer een functie en een routeoptie via de gereedschapknoppen. Selecteer dan een punt op de lijn. Alleen zwarte vierkante punten kunnen gewijzigd worden. De ronde zwarte subpunten niet.<br/> Warning! Waarschuwing! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Dit zal alle gegevens overschrijven van het origineel door een simpele lijn met coördinaten. Alle andere gegevens zullen verloren gaan. track CMouseNormal Add POI as Waypoint Add Waypoint Maak waypoint Add Track Maak track Add Route Maak route Add Area Maak gebied Select Items On Map Copy position Kopieer positie Copy position (Grid) Kopieer positie (Raster) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Selected:</b><br/> %1 waypoints<br/> %1 tracks<br/> %1 routes<br/> %1 areas<br/> CPhotoAlbum Select images... Selecteer afbeeldingen... CPlot Distance [%1] Time Tijd CPlotProfile Distance [%1] Ele. [%1] CPrintDialog Print Map... Kaart afdrukken... Save Map as Image... Sla kaart op als afbeelding... Printer Properties... Printer instellingen... Pages: %1 x %2 Pagina's: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Zoom met muiswiel op kaart om resulotie te veranderen: %1x%2 pixel x: %3 m/px y: %4 m/px Printing pages. Pagina's afdrukken. Save map... Kaart opslaan... CProgressDialog Elapsed time: %1 Verstreken tijd: %1 Elapsed time: %1 seconds. Verstreken tijd: %1 seconden. CProjWizard north noord south zuid Error... Fout... The value '%1' is not a valid coordinate system definition: %2 De waarde '%1' is geen geldig coordinaat definitie: %2 CProjWpt Edit name... Bewerk naam... Enter new waypoint name. Geef waypoint een nieuwe naam. CQlbProject Failed to open... Openen mislukt... Failed to open %1 Openen mislukt-%1 Could not convert... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. CQlgtDb Migrating database from version 4 to 5. Migreren database van versie 4 naar 5. Migrating database from version 5 to 6. Migreren database van versie 5 naar 6. Migrating database from version 6 to 7. Migreren database van versie 6 naar 7. Migrating database from version 7 to 8. Migreren database van versie 7 naar 8. Migrating database from version 8 to 9. Migreren database van versie 8 naar 9. Open database: %1 Open database: %1 Folders: %1 Mappen: %1 Tracks: %1 Tracks: %1 Routes: %1 (Only the basic route will be copied) Routes: %1 (Alleen de basis route zal gekopieerd worden) Waypoints: %1 Waypoints: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Overlays: %1 (gebieden zullen worden omgezet als gebieden, afstandlijnen zullen worden omgezet als tracks, alle andere overlay onderdelen zullen verloren gaan) Diaries: %1 Dagboeken: %1 Map selections: %1 (can't be converted to QMapShack) Kaarselecties: %1 Kunnen niet omgezet worden door QMapShack) ------ Start to convert database to %1------ ------ Start omzetten database naar %1------ Failed to create target database. Kan geen database maken. ------ Abort ------ ------ Geannuleerd ------ ------ Done ------ ------ Klaar ------ Restore folders... Herstel mappen... Imported %1 folders and %2 diaries Geimporteerd %1 mappen en %2 dagboeken Copy items... Kopieer elementen... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Geimporteerd %1 tracks, %2 waypoints, %3 routes, %4 gebieden Import folders... Importeer mappen... Overlay of type '%1' cant be converted Overlay van type '%1' kan niet omgezet worden CQlgtTrack Corrupt track ... Slechte track... Number of trackpoints is not equal the number of training data trackpoints. Number of trackpoints is not equal the number of extended data trackpoints. Number of trackpoints is not equal the number of shadow data trackpoints. CQmsDb Existing file... Bestaand bestand... Remove existing %1? Verwijder bestaand %1? Remove existing file %1 Verwijder bestaand bestand %1 %1: drop item with QLGT DB ID %2 %1: verwerp element met QLTG DB ID %2 CQmsProject Failed to open... Openen mislukt... Failed to open %1 Openen mislukt-%1 CRouterBRouter original first alternative second alternative third alternative BRouter (offline) BRouter (online) profile: %1, alternative: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade response is empty Bad response from server: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... Calculate route with %1 Bereken route met %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <br/>Calculation time: %1s <br/>Berekenen tijd: %1s Error Fout running starting QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. Warning... Waarschuwing... I understand the risk. Don't tell me again. stopped not installed online CRouterBRouterSetup %1 not accessible %1 invalid result Error parsing online-config: Network error: CRouterBRouterSetupWizard Restore Default Values Open Directory select Java Executable please select BRouter installation directory selected directory does not exist create directory and install BRouter there existing BRouter installation update existing BRouter installation empty directory, create new BRouter installation here create new BRouter installation seems to be a valid Java-executable doesn't seem to be a valid Java-executable Java Executable not found Error loading installation-page at %1 no brouter-version to install selected selected %1 for download and installation Warning... Waarschuwing... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. I understand the risk and wish to proceed. download %1 started Network Error: %1 download %1 finished unzipping: ready. download of brouter failed: %1 retrieving available profiles from %1 content of profile Error: Error creating directory %1 Error directory %1 does not exist Error creating file %1 Error writing to file %1 CRouterBRouterTilesPage Continue with Setup CRouterBRouterTilesSelect available routing-data is being determined. Select outdated Clear Selection Delete selection Download Error creating segments directory %1 cannot parse: %1 is not a date cannot parse: %1 is not a valid size Error retrieving available routing data from %1: %2 segments directory does not exist: error creating file %1: %2 no valid request for filename %1 no open file assigned to request for %1 error writing to file %1: %2 error renaming file %1 to %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) being downloaded: %1 of %2 no local data, online available: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Error removing %1: %2 Network Error invalid result, no files found local data up to date (%1, %2) no routing-data available CRouterBRouterToolShell !!! done !!! !!! klaar !!! !!! failed !!! !!! Mislukt !!! CRouterMapQuest Fastest Snelst Shortest Kortst Bicycle Fiets Pedestrian Wandelen US English VS Engels British English Brits Engels Danish Deens Dutch Nederlands French Frans German Duits Italian Italiaans Norwegian Noors Spanish Spaans Swedish Zweeds mode "%1" Modus '%1" no highways geen snelwegen no toll roads geen tolwegen no seasonal geen seizoenswegen no unpaved onverhard no ferry geen veer no crossing of country borders geen grensovergangen <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Route aanvraag naar server gezonden. Moment geduld... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Geen reactie van server:<br/>%1 <br/>Calculation time: %1s <br/>Berekenen tijd: %1s CRouterRoutino Warning... Waarschuwing... Found Routino with a wrong version. Expected %1 found %2 Routini gevonden met verkeerde versie. Verwachtte %1 gevonden %2 Shortest Kortst Quickest Snelst Foot Wandelen Horse Paard Wheelchair Rolstoel Bicycle Fiets Moped Brommer Motorcycle Motorfiets Motorcar Auto Goods Goederen English Engels German Duits French Frans Hungarian Hongaars Dutch Nederlands Russian Russisch Polish Pools A function was called without the database variable set. Een functie werd aangeroepen zonder database variabelen. A function was called without the profile variable set. Een functie werd aangeroepen zonder profiel variabelen. A function was called without the translation variable set. Een functie werd aangeroepen zonder vertaling variabelen. The specified database to load did not exist. De opgegeven database bestaat niet. The specified database could not be loaded. De opgegeven database kan niet geladen worden. The specified profiles XML file did not exist. Het opgegeven XML profiel bestaat niet. The specified profiles XML file could not be loaded. Het opgegeven XML profiel kan niet geladen worden. The specified translations XML file did not exist. De opgegeven XML vertaling bestaat niet. The specified translations XML file could not be loaded. De opgegeven XML vertaling kan niet geladen worden. The requested profile name does not exist in the loaded XML file. De opgevraagde profielnaam bestaat niet in geladen XML bestand. The requested translation language does not exist in the loaded XML file. De opgevraagde vertaling bestaat niet in geladen XML bestand. In the routing database there is no highway near the coordinates to place a waypoint. The profile and database do not work together. Profiel en database kunnen niet samenwerken. The profile being used has not been validated. Het gebruikte profiel is niet gevalideerd. The user specified profile contained invalid data. Door gebruiker opgegeven profiel bevat ongeldige gegevens. The routing options specified are not consistent with each other. De opgegeven routing opties komen niet overeen. There is a mismatch between the library and caller API version. Er is een verschil is tussen de bibliotheek en de gebruiker API-versie. Route calculation was aborted by user. Berekening route was geanuleerd door gebruiker. A route could not be found to waypoint %1. Er kon geen route gevonden worden naar waypoint %1. Unknown error: %1 Onbekende fout: %1 profile "%1" Profiel "%1" , mode "%1" , modus "%1" Calculate route with %1 Bereken route met %1 <br/>Calculation time: %1s <br/>Berekenen tijd: %1s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Maak of verwijder mappen naar Routino gegevens.-Er kunnen meerdere bestanden in een map zijn maar geen submappen. Select routing data file path... Selecteer routing gegevensmap... CRouterSetup Routino (offline) Routino (offline) MapQuest (online) MapQuest (online) BRouter (online) CRoutinoDatabaseBuilder Create Routino Database Maak Routino database Select files... Selecteer bestanden... Select target path... Selecteer doel map... !!! done !!! !!! klaar !!! CScrOptRangeTrk No range selected CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> CSearchDatabase Search database '%1': CSearchGoogle Unknown response Onbekende reactie Error: Fout: CSetupDatabase Missing Requirement MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. Error... Fout... There is already a database with name '%1' Er is al een database met naam '%1' New database... Nieuwe database... Open database... Open database... CSetupWorkspace Setup database... Instelling database... Changes will become active after an application's restart. Veranderingen zullen na herstart toegepast worden. CSlfProject Failed to load file %1... Kan bestand %1 niet laden... CSlfReader Failed to parse timestamp `%1` %1 does not exist %1 bestaat niet Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Not a SLF file: %1 Geen SLF bestand: %1 Unsupported revision %1: %2 Niet ondersteunende revisie %1: %2 Break %1 Pauze %1 Lap %1 Ronde %1 CSmlProject Failed to load file %1... Kan bestand %1 niet laden... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Not an sml file: %1 Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Device: %1<br/> Battery usage: %1 %/hour Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This SML file does not contain any position data and can not be displayed by QMapShack: %1 CTableTrk Double click to edit elevation value %1%2 %1%2 CTcxProject Failed to load file %1... Kan bestand %1 niet laden... Failed to open %1 Openen mislukt-%1 Failed to read: %1 line %2, column %3: %4 Lezen mislukt: %1 lijn %2, kolom %3: %4 Not a TCX file: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. This TCX file does not contain any activity or course: %1 File exists ... Bestand bestaat al... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> Course Richting Activity Activiteit Cancel Track with invalid timestamps... Activity or course? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. Failed to create file '%1' Maken bestand mislukt '%1' Failed to write file '%1' Schrijven bestand mislukt '%1' Saving GIS data failed... Opslaan GIS gegevens mislukt... CTemplateWidget choose one... Hiking Tour Summary (built-in) - - Template path... Failed to read template file %1. Preview... CTextEditWidget &Color... &Kleur... Reset format CToolBarSetupDialog Available Actions Selected Actions CTwoNavProject Error... Fout... Failed to open %1. Kan %1 niet openen. Save GIS data to... Sla GIS gegevens op naar... Only support lon/lat WGS 84 format. Alleen lon/lat WGS 84 formaat word ondersteunt. Failed to read data. Lezen gegevens mislukt. CWptIconDialog Path to user icons... Form Form Formulier Participants Weather rain sunny snow clouds windy hot warm cold freezing foggy humid Character easy hiking climbing alpine large ascend long distance via ferrata hail/soft hail Rating Rating 5 stars Rating 4 stars Rating 3 stars Rating 2 stars Rating 1 star aborted Equipment ferrata gear night gear snow shoes climbing gear ski camping gear Details IAbout About.... Over... <b>QMapShack</b>, Version <b>QMapShack<b>, Versie TextLabel TextLabel Qt Qt GDAL GDAL Proj4 Proj4 Routino Routino Czech: Tsjechisch: German: Duits: Oliver Eichler Dutch: Nederlands: French: Frans: Rainer Unseld Rainer Unseld Russian: Wolfgang Thämelt © 2017 Oliver Eichler (oliver.eichler@gmx.de) © 2014 Oliver Eichler (oliver.eichler@gmx.de) {2016 ?} {2017 ?} Pavel Fric Pavel Fric <b>Translation:</b> <b>Vertaling:</b> Harrie Klomp Spanish: Spaans: Win64: Win64: OS X: OS X: <b>Binaries:</b> <b>Binaries:</b> <b>Contributors:</b> <b>Medewerkers:</b> Jose Luis Domingo Lopez Jose Luis Domingo Lopez Ivo Kronenberg Ivo Kronenberg Helmut Schmidt Helmut Schmidt ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ..en een dank naar alle Linux binarie beheerders voor het geleverde werk. Speciale dank aan Dan Horák en Bas Couwenberg voor het tonen van hun aanwezigheid op de mailinglijst om de distributie-gerelateerde onderwerpen te bespreken. Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Deze software is gelicenseerd onder GPL3 of latere versies ICanvasSetup Setup Map View... Kaartinstellingen... Projection & Datum Projectie & Datum ... ... Scales Schalen Logarithmic Logarithmisch Square (optimized for TMS and WMTS tiles) IColorChooser Dialog Dialoog ICombineTrk Combine Tracks... Combineer tracks... Available Tracks ... ... Combined Tracks ICoordFormatSetup Coordinate Format... Coördinaat formaat... N48° 53.660 E013° 31.113 N48° 53.660 O013° 31.113 N48.8943° E013.51855° N48.8943° O013.51855° N48° 53' 39.6" E13° 31' 6.78" N48° 53' 39.6" O13° 31' 6.78" ICreateRouteFromWpt Create Route from Waypoints Maak route van waypoints ... ... ICutTrk Cut Track Track knippen Delete first part of the track and keep second one Verwijder eerste deel van track en bewaar tweede deel Keep both parts of the track Bewaar beide delen van track Keep first part of the track and delete second one Bewaar eerste deel van track en verwijder tweede deel Cut Mode: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Controleer eerst voordat dit in een nieuwe track opgelagen wordt. Voor het opslaan van beide delen dienen er nieuwe tracks gemaakt te worden. Als er alleen een halve track bewaard moet worden kunnen de overige punten verwijderd worden, of controleer dit bij het maken van de nieuwe track. Create a new track Maak een nieuwe track IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Migrate database... Migreren database... Migration aborted by user Failed to migrate '%1'. Error... Fout... Migration failed The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. Initialization failed Wrong database version... Database created by newer version of QMapShack Failed to initialize '%1'. IDBMysql Password... Wachtwoord... Password for database '%1': Wachtwoord voor database '%1': Update to database version 5. Migrate all GIS items. IDBSqlite Update to database version 3. Migrate all GIS items. Update to database version 5. Migrate all GIS items. Update to database version 6. Migrate all GIS items. IDemPathSetup Setup DEM file paths Map met DEM bestanden instellen ... ... - - IDemPropSetup Form Formulier <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Verander transparantie van kaart</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klik om huidige schaal als minimumschaal op kaart te tonen.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Instellen van het bereik van de schaal van de kaart wordt weergegeven. Gebruik de twee knoppen links en rechts om de omvang te definiëren als minimale of maximale omvang.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klik om huidige schaal als maximumschaal op kaart te tonen.</p></body></html> Hillshading Hillshading Slope Helling ° ° > > TextLabel Benaming IDemsList Form Formulier To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Gebruik het menu (rechter muisklik op item) om bestand te activeren. Gebruik selecteer en slepen om geactiveerde bestanden in volgorde te plaatsen. Activate Activeer Move Up Omhoog Hide DEM behind previous one Verberg DEM onder vorige Move down Omlaag Show DEM on top of next one Toon DEM op de volgende Reload DEM DEM herladen IDetailsGeoCache Dialog Dialoog Position: Positie: - - Difficulty Moeilijkheid Terrain Terrein Update spoilers Spoilers bijwerken ... ... about:blank Over:leeg Hint: Hint: TextLabel Benaming IDetailsOvlArea Dialog Dialoog The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Toggle read only mode. You have to open the lock to edit the item. Schrijfbeveiliging ingeschakeld. Klik op het slot om te kunnen bewerken. ... ... Color Kleur Border width Lijndikte Style Stijl Opacity Transparantie Info Info Points Punten Position Positie Hist. Historie IDetailsPrj Form Keywords: Sleutelwoorden: - - Keep order of project Behoud volgorde van project Sort along track (multiple) Sorteer langs route (multi) Sort along track (single) Sorteer langs route (enkel) ... ... Print diary Dagboek afdrukken Rebuild diary. Dagboek herindelen. IDetailsRte Info Info The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. - - Toggle read only mode. You have to open the lock to edit the item. Schrijfbeveiliging ingeschakeld. Klik op het slot om te kunnen bewerken. ... ... Hist. Hist. IDetailsTrk Form Formulier - - - - Profile Profiel Speed Snelheid Toggle read only mode. You have to open the lock to edit the item. Schrijfbeveiliging ingeschakeld. Klik op het slot om te kunnen bewerken. ... ... - - Info Info Style Stijl Source Bron Maximum Maximum Use/edit user defined visibility of arrows for this track Use/edit system's visibility of arrows for all tracks Minimum Minimum Use/edit user defined scale factor for this track Use/edit system's default factor for all tracks x Width with arrows Graphs Grafieken max. min. User defined limits for this track - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Automatic limits User defined limits for all tracks Color Kleur Activity Activiteit Set Track Activity To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Om de track statistieken te onderscheiden selecteer een activiteit uit de lijst voor de volledige track. Of selecteer een deel van de track om een activieteit toe te kennen. Points Punten Time Tijd Ele. Hoogte Delta Delta Dist. Afstand. Slope Helling Ascent Descent Position Positie Filter Filter Hist. Hist. IDetailsWpt Dialog Dialoog Info Info Position: Positie: - - Ele. Hoogte. Proximity: Nabijheid: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Toggle read only mode. You have to open the lock to edit the item. Schrijfbeveiliging ingeschakeld. Klik op het slot om te kunnen bewerken. ... ... Date/Time: Datum/Tijd: Add images. Afbeelding toevoegen. Delete selected image. Verwijder geselecteerde afbeelding. Hist. Hist. IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Er is al een ander project met dezelfde naam. Bij drukken op 'OK' zal deze overschreven worden. IElevationDialog Edit elevation... Bewerk hoogte... Elevation Hoogte - - Get elevation from active digital elevation model. Neem hoogte gegevens over van DEM (digital elevation model). ... ... IExportDatabase Export database to GPX... ... ... Export Path: - - GPX 1.1 without extensions Start Start Abort Annuleren Close Sluiten IFilterDelete Form Formulier <b>Remove Track Points</b> <b>Verwijder trackpunten</b> Remove all hidden track points permanently. Verwijder permanent alle verborgen trackpunten. ... ... IFilterDeleteExtension Form Formulier <b>Remove Extension from all Track Points</b> Remove from all Track Points ... ... IFilterDouglasPeuker Form Formulier <b>Hide Points (Douglas Peuker)</b> <b>Verberg punten (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Verberg trackpunten wanneer de afstand tussen naaste punten minder is dan m m Apply filter now. Nu filter toepassen. ... ... IFilterInterpolateElevation Form Formulier <b>Interpolate Elevation Data</b> Replace elevation of track points with interpolated data. Quality Preview ... ... IFilterInvalid Form Formulier Hide Invalid Points Verberg ongeldige punten Hide points with invalid data. ... ... IFilterMedian Form Formulier <b>Smooth Profile (Median Method)</b> <b>Vloeiend profiel (Mediaans methode)</b> Smooth deviation of the track points elevation with a Median filter of size Vloeiend hoogteverschil van trackpunten-maken met een Mediaans filter van points punten ... ... IFilterNewDate Form Formulier <b>Change Time</b> <b>Verander tijd</b> Change start of track to Verander start van track naar dd.MM.yy HH:mm:ss dd.MM.yy UU:mm:ss - - ... ... IFilterObscureDate Form Formulier <b>Obscure Timestamps</b> <b>Onduidelijke tijdstempels</b> Increase timestamp by Verhoog tijdstempels met sec. sec. with each track point. 0 sec. will remove timestamps. voor elk trackpunt. 0 sec. zal tijdstempels verwijderen. ... ... IFilterOffsetElevation Form Formulier <b>Offset Elevation</b> <b>Hoogte aanpassen</b> Add offset of Verander hoogte naar to track points elevation. van trackpunt hoogte. ... ... IFilterReplaceElevation Form Formulier <b>Replace Elevation Data</b> <b>Vervang hoogtegegevens</b> Replace elevation of track points with the values from loaded DEM files. Vervang hoogte van trackpunten met gegevens van geladen DEM bestand. ... ... IFilterReset Form Formulier <b>Reset Hidden Track Points</b> <b>Herstel verborgen trackpunten</b> Make all trackpoints visible again. Maak alle trackpunten weer zichtbaar. ... ... IFilterSpeed Form Formulier <b>Change Speed</b> <b>Verander snelheid</b> Set speed to Zet snelheid op km/h km/u ... ... IFilterSplitSegment Form Formulier <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Maak delen in een track</span></p></body></html> Creates a new track for every segment within this track. Maakt een nieuwe track van delen in deze track. ... ... IFilterSubPt2Pt Form Formulier <b>Convert track subpoints to points</b> Convert subpoints obtained from routing to ordinary track points ... ... IFilterTerrainSlope Form Formulier <b>Calculate Terrain Slope</b> Calculate slope of the terrain based on loaded DEM files. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. FIT decoding error: a development field with the field_definition_number %1 already exists. IGisDatabase Form Formulier Name Age To add a database do a right click on the database list above. Om nieuwe database te maken doe een rechterklik op database erboven. IGisItem [no name] [geen naam] The item is not part of the project in the database. Het item is geen deel van het project in de database. It is either a new item or it has been deleted in the database by someone else. The item is not in the database. Het item is niet in de database. The item might need to be saved Het item dient opgeslagen te worden Initial version. Orginele versie. Never ask again. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1<h3>Dit element is waarschijnlijk alleen lezen omdat dit niet gemaakt is in QMapShack. Normaal hoeven geen gegevens aangepast te worden na het importeren. Om toch aan te passen druk dan op 'OK'. Read Only Mode... Alleen lezen modus... <h4>Description:</h4> <h4>Beschrijving:</h4> <p>--- no description ---</p> <p>--- geen beschrijving ---</p> <h4>Comment:</h4> <h4>Notitie:</h4> <p>--- no comment ---</p> <p>--- geen notitie ---</p> <h4>Links:</h4> <h4>Links:</h4> <p>--- no links ---</p> <p>--- geen links ---</p> Edit name... Bewerk naam... Enter new %1 name. IGisProject Save project? Project opslaan? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>Het project is veranderd. Voor het sluiten opslaan? %1: Correlate tracks and waypoints. %1: Correlatie van tracks en waypointen. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>Duurde dit te lang? Moet de correlatie van tracks en waypointen in dit project in de toekomst overgeslagen worden? Canceled correlation... Correlatie geanuleerd... Save "%1" to... Opslaan "%1" als... <br/> Filename: %1 <br/> Bestandsnaam: %1 Waypoints: %1 Waypoints: %1 Tracks: %1 Tracks: %1 Routes: %1 Routes: %1 Areas: %1 Gebieden: %1 Are you sure you want to delete '%1' from project '%2'? Moet '%1' werkelijk verwijderd worden uit project '%2'? Delete... Verwijderen... IGisWorkspace Form Formulier Opacity Transparantie Change the opacity of all GIS Items on the map. Filter Filter Name Clear Filter Setup Filter IGridSetup Setup Grid... Raster instelling... Projection Projectie restore default standaardinstellingen herstellen ... ... Get projection from current map. Neem projectie van huidige kaart. projection wizzard projectie wizzard Grid color Rasterkleur setup grid color Instelling rasterkleur IImportDatabase Form Formulier ... ... Source Database: Bron database: - - Target Database: Doel database: Start Start IInputDialog Edit... Bewerken... TextLabel Benaming ILineOp Routing ILinksDialog Links... Links... Type Soort Text Tekst Uri URL ... ... IMainWindow QMapShack QMapShack File Bestand View Instellingen Window Venster ? ? Tool Extra Maps Kaarten Dig. Elev. Model (DEM) Dig. Elev. Model (DEM) Workspace Toolbar Routing Add Map View Nieuw venster Ctrl+T Ctrl+T Show Scale Toon schaal Setup Map Font Lettertype kaart instellen Show Grid Toon raster Ctrl+G Ctrl+G Setup Grid Raster instellen Ctrl+Alt+G Ctrl+Alt+G Flip Mouse Wheel Draai muiswiel om Setup Map Paths Map met kaarten instellen POI Text POI tekst Night / Day Dag/Nacht Map Tool Tip Map Tool Tip Ctrl+I Ctrl+I Setup DEM Paths Map DEM instellen About Over Help Help F1 F1 Setup Map View Kaartinstellingen Load GIS Data GIS gegevens laden Load projects from file Project laden uit bestand Ctrl+L Ctrl+L Save All GIS Data GIS gegevens opslaan Save all projects in the workspace Sla alle projecten op in werkruimte Ctrl+S Ctrl+S Setup Time Zone Tijdzone instellen Add empty project Nieuw leeg project Search Google Zoeken Google Close all projects Sluit alle projecten F8 F8 Setup Units Eenheden instellen Setup Workspace Werkruimte instellen Setup save on exit. Oplaan bij afsluiten instellen. Import Database from QLandkarte Database van QLandkarte importeren Import QLandkarte GT database QLandkarte database importeren VRT Builder VRT maken GUI front end to gdalbuildvrt GUI front end naar gdalbuildvrt Store Map View Kaart opslaan Write current active map and DEM list including the properties to a file Schrijf huidige actieve kaart en DEM lijst inclusief de eigenschappen naar een bestand Load Map View Kaart laden Restore view with active map and DEM list including the properties from a file Herstel huidige actieve kaart en DEM lijst inclusief de eigenschappen naar een bestand Ext. Profile Ext. profiel Ctrl+E Ctrl+E Close Sluiten Ctrl+Q Ctrl+Q Clone Map View Kloon venster Ctrl+Shift+T Ctrl+Shift+T Create Routino Database Maak Routino database Save(Print) Map Screenshot Kaartdeel opslaan/afdrukken Print a selected area of the map Geselecteerde deel van kaart afdrukken Ctrl+P Ctrl+P Setup Coord. Format Coördinaat formaat instellen Change the format coordinates are displayed Getoonde coördinaat formaat aanpassen Setup Map Background Setup Waypoint Icons Setup path to custom icons Close Tab Ctrl+W Quickstart Help Setup Toolbar Toggle Docks Toggle visibility of dockable windows Ctrl+D Ctrl+D Full Screen F11 F11 Min./Max. Track Values Show the minimum and maximum values of the track properties along the track in the map view. Ctrl+N Database Database IMapList Form Formulier To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Gebruik het menu (rechter muisklik op item) om kaart te activeren. Gebruik selecteer en slepen om geactiveerde kaarten in volgorde te plaatsen. Help! I want maps! I don't want to read the documentation! Help! Ik wil kaarten! Ik wil de documentatie niet lezen! Activate Activeer Move Up Omhoog Hide map behind previous map Verberg DEM onder vorige kaart Move down Omlaag Show map on top of next map Toon DEM op de volgende kaart Reload Maps Kaarten herladen IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Deze kaart heeft OpenSSL onderteuning nodig. Door restricte beperkingen in bepaalde landen kan QMapShack geen OpenSSL pakket aanbieden. Neem een kijkje op <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> voor binaries. Er kan wel libeay32.dll en ssleay32.dll in de QMapShack map gekopieerd worden. Error... Fout... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 delen ontvangen<br/> IMapPathSetup Setup map paths Map met kaarten instellen Root path of tile cache for online maps: Hoofdmap voor oplslaan van online kaarten: - - ... ... Help! I want maps! I don't want to read the documentation! Help! Ik wil kaarten! Ik wil de documentatie niet lezen! IMapPropSetup Form Formulier <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Verander transparantie van kaart</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klik om huidige schaal als minimumschaal op kaart te tonen.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Instellen van het bereik van de schaal van de kaart wordt weergegeven. Gebruik de twee knoppen links en rechts om de omvang te definiëren als minimale of maximale omvang.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klik om huidige schaal als maximumschaal op kaart te tonen.</p></body></html> Areas Gebieden Lines Lijnen Points Punten Details Cache Size (MB) Cache grootte (MB) Expiration (Days) Vervaltijd (dagen) - - Cache Path Cachemap Type File: Forget external type file and use internal types. Load an external type file. IMapVrtBuilder Form Formulier Advanced Options Source No Data (-srcnodata) Target No Data (-vrtnodata) Target Projection (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> ... ... Select source files: Selecteer bronbestand: Target Filename: Doel bestandsnaam: - - Start Start IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Nieuwe lijn</b><br/>Verplaats de muis en gebruik linker muisknop om een punt te plaatsen. Gebruik rechter muisknop om te stoppen.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Verwijder punt</b><br/>Beweeg de muis dicht bij een punt en druk op linkermuisknop om te verwijderen.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Selecteer reeks punten</b><br/>Klik op eerste punt van reeks. Klik op laatste punt van reeks en selecteer een optie. Gebruik rechter muisknop om te annuleren.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Verplaats punt</b><br/>Beweeg de muis dicht bij een punt en druk op linkermuisknop om het punt te laten plakken. Beweeg de muis om het punt te verplaatsen. Laat het punt los met linker muisknop. Gebruik rechterknop om te annuleren.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Punt toevoegen</b><br/>Beweeg de muis dicht bij een lijndeel en druk op linkermuisknop om het punt te laten plakken. Beweeg de muis om het punt te verplaatsen. Laat het punt los met linker muisknop. Gebruik rechterknop om te annuleren.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Geen routing</b><br/>Alle punten zullen met rechte lijnen verbonden worden.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Auto routing</b><br/>De huidige instelling wordt gebruikt voor berekening van een route tussen punten. <b>Notitie:</b>De geselecteerd route moet zelf routes kunnen maken. Offline routers kunnen dit online routers meestal niet.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Vector routing</b><br/>Verbind punten met een lijn op een geladen vector kaart indien mogelijk.</br> <b>%1 Metrics</b> <b>%1 gegevens</b> Distance: Afstand: Ascent: Descent: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> IPhotoAlbum Form Formulier ... ... IPlot Reset Zoom Herstel zoom Stop Range Stop bereik Save... Opslaan... Add Waypoint Maak waypoint Cut... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. No or bad data. Geen of ontbrekende gegevens. Select output file Selecteer bestand IPositionDialog Position ... Positie... Enter new position Geef nieuwe positie op Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Verkeerde invoer. Moet zijn: "[N|Z] ddd mm.sss [W|O] ddd mm.sss" of "[N|Z] ddd.ddd [W|O] ddd.ddd" IPrintDialog Print map... Kaart afdrukken... When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. Save Opslaan When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. TextLabel Benaming Print Afdrukken IProgressDialog Please wait... Moment geduld... TextLabel Benaming IProjWizard Proj4 Wizzard Proj4 instelling Mercator Mercator UTM UTM zone zone user defined gebruikersinstelling Datum Datum World Mercator (OSM) Wereld Mercator (OSM) Result: Resultaat: UPS North (North Pole) UPS noord (Noordpool) UPS South (South Pole) UPS zuid (Zuidpool) Projection Projectie IProjWpt Waypoint Projection Waypoint projectie ... ... - - Clone waypoint and move by: Kopieer waypoint en verplaats naar: m m ° ° IRouterBRouter Form Formulier Profile Profiel Alternative display selected routing profile ... ... on-the-fly routing BRouter: not running start/stop BRouter show BRouter console Setup Caution! BRouter is listening on all ports for connections. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> IRouterBRouterInfo BRouter Profile TextLabel IRouterBRouterSetupWizard BRouter Setup choose which BRouter to use BRouter-Web (online) local Installation Expert Mode local BRouter Installation directory: select installation directory ... ... labelLocalDirResult create or update installation Java Executable labelLocalJavaResult search for installed java Download and install BRouter Version about:blank Over:leeg File to install Download and Install available Profiles install profile remove profile installed Profiles content of profile BRouter-Web URL: Service-URL Profile-URL Hostname Port Profile directory Segments directory Custom Profiles dir Max Runtime Number Threads Java Options Profiles Url IRouterMapQuest Form Formulier Highways Snelwegen Seasonal Seizoenswegen Language Taal Country Border Landgrenzen Profile Profiel Avoid: Vermijd: Ferry Veerboten Toll Road Tolwegen Unpaved Onverhard <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>Routebeschrijving afkomstig van <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Formulier Profile Profiel Mode Modus Database Database Add paths with Routino database. Map toevoegen met Routino database. ... ... Language Taal To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. IRouterRoutinoPathSetup Setup Routino database... Routino database instellen... ... ... - - IRouterSetup Form Formulier IRoutinoDatabaseBuilder Form Formulier ... ... Select source files: Selecteer bronbestand: Start Start Target Path: Doelmap: - - File Prefix Bestandsextentie <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> IScrOptEditLine Form Formulier Save to original Opslaan als origineel Save as new Opslaan als nieuw Abort Annuleren Move points. (Ctrl+M) Verplaats punten. (Ctrl+M) ... ... Ctrl+M Ctrl+M Add new points. (Ctrl++) Maak nieuwe punten. (Ctrl++) Ctrl++ Ctrl++ Select a range of points. (Ctrl+R) Selecteer een reeks punten. (Ctrl+R) Ctrl+R Ctrl+R Delete a point. (Ctrl+-) Ctrl+- No auto-routing or line snapping (Ctrl+O) Geen auto-routing of startlijn (Ctrl+O) 0 O Ctrl+O Ctrl+O Use auto-routing to between points. (Ctrl+A) Gebruik auto-routing tussen punten. (Ctrl+A) A A Ctrl+A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Start de lijn langs een lijn van een vector kaart. (Ctrl+V) V V Ctrl+V Ctrl+V Undo last change Wis laatste verandering Redo last change Herplaats laatste verandering IScrOptOvlArea Form Formulier View details and edit. Bekijk details en bewerk. ... ... Copy area into another project. Kopieer gebied in ander project. Delete area from project. Verwijder gebied uit project. Edit shape of the area. Verander vorm van het gebied. TextLabel TextLabel IScrOptPrint Form Formulier Save selected area as image. ... ... Print selected area. IScrOptRangeLine Form Formulier Delete all points between the first and last one. Verwijder alle punten tussen eerste en laatste punt. ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Bereken een route tussen het eerste en laatst geselecteerde punt..</p></body></html> IScrOptRangeTrk Form Formulier Hide all points. Verberg alle punten. ... ... Show all points. Toon alle punten. Set an activity for the selected range. Copy track points as new track. Kopieer trackpunten naar een nieuwe track. TextLabel Benaming IScrOptRte Form Formulier View details and edit. Bekijk details en bewerk. ... ... Copy route into another project. Kopieer route in een ander project. Delete route from project. Verwijder route uit project. Calculate route. Bereken route. Reset route calculation. Herstel route berekening. Move route points. Verplaats route punten. Convert route to track TextLabel Benaming IScrOptSelect Form Formulier Copy all selected items to a project. ... ... Create a route from selected waypoints. Change the icon of all selected waypoints. Combine all selected tracks to a new one. Set an activity for all selected tracks. Delete all selected items. Select all items that intersect the selected area. Select all items that are completely inside the selected area. Add tracks to selection. Add waypoints to selection. Add routes to selection. Add areas to selection. IScrOptTrk Form Formulier View details and edit properties of track. Bekijk details en bewerk eigenschappen van de track. ... ... Copy track into another project. Kopieer track in een ander project. Delete track from project. Verwijder track uit project. Show on-screen profile and detailed information about points. Toon op scherm het profiel en gedetaileerde informatie van de punten. Select a range of points. Selecteer een reeks punten. Edit position of track points. Bewerk positie van trackpunten. Reverse track. Draai trackrichting. Combine tracks. Combineer tracks. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Knip track op geselecteerde punt. Dit kan ook gebruikt worden om: * ongeldige punten aan start of eind van track te verwijderen * trackdelen te gebruiken voor nieuwe track * een lange track in etappes te verdelen Set an activity for the complete track. Copy track together with all attached waypoints into another project. TextLabel Benaming IScrOptWpt Form Formulier View details and edit. Bekijk details en bewerk. ... ... Copy waypoint into another project. Kopieer waypoint in een ander project. Delete waypoint from project. Verwijder waypoint uit project. Show content as static bubble. Toon gegevens in een statische ballon. Move waypoint to a new location. Verplaats waypoint naar een nieuwe locatie. Clone waypoint and move clone a given distance and angle. Kloon waypoint en verplaats deze naar aangegeven afstand en hoek. edit radius of circular area Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel Benaming IScrOptWptRadius Form Formulier edit radius of circular area ... ... Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel ISearchDatabase Search... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Name Search Close Sluiten ISelDevices Select devices... Selecteer GPS... ISelectActivityColor Form Formulier ISelectCopyAction Copy item... Element kopiëren... Replace existing item Vervang bestand element TextLabel Benaming Do not copy item Element niet kopiëren Create a clone Maak een kloon Replace with: Vervang door: Keep item: Behoud element: The clone's name will be appended with '_Clone' De naam van de kloon zal aangeduid worden als '_Kloon' And for all other items, too. En ook voor alle andere elementen. ISelectDBFolder Select Parent Folder... Selecteer map... Name Naam ISelectDoubleListWidget Form Formulier Available Beschikbaar Add to selected items Remove from selected items Selected Move selected items up Move selected items down ... ... ISelectProjectDialog Select a project... Selecteer een project... Select project from list or enter new project name. Selecteer project uit lijst of maak nieuw project. New project's name Naam nieuw project New project is created as: Nieuw project wordt gemaakt als: *.qms *.qms *.gpx *.gpx Database Database ISelectSaveAction Copy item... Element kopiëren... Replace existing item Vervang bestand element Add a clone Maak een kloon The clone's name will be appended with '_Clone' De naam van de kloon zal aangeduid worden als '_Kloon' Replace with: Vervang door: TextLabel Benaming Do not replace item Vervang element niet Use item: Gebruik element: And for all other items, too. En ook voor alle andere elementen. ISetupDatabase Add database... Database toevoegen... - - Name Naam <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> Do not use a password. SQLite SQLite MySQL MySQL Server Server Port 00000 O {00000?} User Gebruiker Password Wachtwoord <b>Port:</b> Leave the port field empty to use the default port. File: Bestand: Add new database. Maak nieuwe database. ... ... Open existing database. Open bestaande database. ISetupFilter Form Formulier Apply filter to name only complete text ISetupFolder Database Folder... Databasemap... Folder name Mapnaam Group Groep Project Project Other Anders ISetupNewWpt New Waypoint... Nieuw waypoint... Symbol Symbool ... ... Position Positie Name Naam Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Verkeerde invoer. Moet zijn: "[N|S] ddd mm.sss [W|E] ddd mm.sss" of "[N|S] ddd.ddd [W|E] ddd.ddd" ISetupWorkspace Setup workspace... Instelling werkruimte... save workspace on exit, and every sla werkruimte op bij afsluiten en elke minutes minuten listen for database changes from other instances of QMapShack. On port 00000 O {00000?} ITemplateWidget Insert Template... Templates Select a path with your own templates. ... ... Preview ITextEditWidget Edit text... Bewerk tekst... Undo Ongedaan maken Ctrl+Z Ctrl+Z Redo Opnieuw Ctrl+Shift+Z Ctrl+Shift+Z Cut Knippen Ctrl+X Ctrl+X Copy Kopiëren Ctrl+C Ctrl+C Paste Plakken Templ. A:L A:C A:R A:B B I U C Standard Bullet List (Disc) Bullet List (Circle) Bullet List (Square) Ordered List (Decimal) Ordered List (Alpha lower) Ordered List (Alpha upper) Ordered List (Roman lower) Ordered List (Roman upper) Ctrl+V Ctrl+V Align Left Links uitlijnen Ctrl+L Ctrl+L Align Right Rechts uitlijnen Ctrl+R Ctrl+R Align Center Gecentreerd Ctrl+E Ctrl+E Align Block Uitgevuld Ctrl+J Ctrl+J Underline Onderstrepen Ctrl+U Ctrl+U Bold Vet Ctrl+B Ctrl+B Italic Cursief Ctrl+I Ctrl+I Plain Reset the text's format before pasting Select All Ctrl+A Ctrl+A Delete Verwijder Reset Font Reset Layout Normal Paste without resetting the text's format Insert From Template Create text from template. ITextEditWidgetSelMenu B I U Cut Knippen Copy Kopiëren Paste Plakken ITimeZoneSetup Setup Time Zone ... Tijdzone instellen... UTC UTC Local Lokaal Automatic Automatisch Print date/time in Toon datum/tijd als long format, or lang formaat, of short format kort formaat <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Notitie:</b>Na het wijzigingen van de eenheden is het nodig om QMapShack opnieuw op te starten. IToolBarSetupDialog Setup Toolbar Toolbar is visible in Fullscreen-mode IToolShell Execution of external program `%1` failed: Starten van extern programma `%1` mislukt: Process cannot be started. Het proces kan niet gestart worden. Make sure the required packages are installed, `%1` exists and is executable. De benodigde pakketten dienen geïnstalleerd te zijn, `%1` bestaat en is uitvoerbaar. External process crashed. Extern proces is vast gelopen. An unknown error occurred. Een onbekende fout is opgetreden. !!! failed !!! !!! Mislukt !!! IUnit Error Fout Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Verkeerde invoer. Moet zijn: "[N|Z] ddd mm.sss [W|O] ddd mm.sss" of "[N|Z] ddd.ddd [W|O] ddd.ddd" Position values out of bounds. Positiewaarden vallen buiten bereik. IUnitsSetup Setup units... Eenheden instellen... Length unit Metric Metrisch Slope unit Degrees (°) Percent (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Notitie:</b>Na het wijzigingen van de eenheden is het nodig om QMapShack opnieuw op te starten. Imperial Imperial Nautic Nautisch IWptIconDialog Icons... Iconen... External Icons: - - ... ... All custom icons have to be *.bmp or *.png format. qmapshack-1.10.0/src/locale/qmapshack_de.desktop000644 001750 000144 00000000121 13022456074 022760 0ustar00oeichlerxusers000000 000000 #Translations Name[de]=QMapShack GenericName[de]=GPS Daten- und Kartenverwaltung qmapshack-1.10.0/src/locale/qmapshack_cs.ts000644 001750 000144 00001521755 13216421215 021772 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API verze %2, očekávána verze %3) %1 (API V%2) %1 (API verze %2) (no DBUS: device detection and handling disabled) (žádné DBUS: zjišťování zařízení a zacházení s ním zakázáno) CActivityTrk Foot Chodec Bicycle Jízdní kolo Motor Bike Motocykl Car Auto Cable Car Lanovka Swim Plavání Ship Loď No Activity Žádná činnost Total Celkem Ascent: Stoupání: Descent: Klesání: Ski/Winter Lyže/Zima Aeronautics Letectví Public Transport Veřejná doprava Distance: Vzdálenost: Speed Moving: Rychlost při pohybu: Speed Total: Celková rychlost: Time Moving: Čas při pohybu: Time Total: Celkový čas: CCanvas View %1 Pohled %1 Setup Map Background Nastavit pozadí mapy CColorChooser Esc. Esc CCommandProcessor Print debug output to console. Zobrazit výstup ladění v konzoli. Print debug output to logfile (temp. path). Uložit výstup ladění do souboru se zápisem (cesta temp). Do not show splash screen. Neukazovat uvítací obrazovku. File with QMapShack configuration. Soubor s nastavením pro QMapShack. file Soubor Files for future use. Soubory pro pozdější potřebu. CCreateRouteFromWpt route Cesta CDBFolderLostFound All your data grouped by folders. Všechna data seskupená podle složek. Lost & Found (%1) Ztraceno a nalezeno (%1) Lost & Found Ztraceno a nalezeno CDBFolderMysql All your data grouped by folders. Všechna data seskupená podle složek. MySQL Database Databáze MySQL Server: Server: (No PW) (žádné heslo) Error: Chyba: CDBFolderSqlite All your data grouped by folders. Všechna data seskupená podle složek. SQLite Database Databáze SQLite File: Soubor: Error: Chyba: CDBItem %1 min. %1 m %1 h %1 h %1 days %1 dnů CDBProject Failed to load... Nepodařilo se nahrát... Can't load file "%1" . It will be skipped. Nelze nahrát soubor "%1". Bude přeskočen. Project already in database... Projekt již je v databázi... The project "%1" has already been imported into the database. It will be skipped. Projekt "%1" již byl zaveden do databáze. Bude přeskočen. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database Prvek %1 byl změněn pomocí %2 (%3). K vyřešení tohoto střetu můžete vytvořit a uložit klona, vynutit svoji verzi, nebo ji zahodit a vzít jednu z databáze Conflict with database... Střet s databází... Clone && Save Klonovat a uložit Force Save Vynutit uložení Take remote Vzít vzdálenou verzi Missing folder... Chybí složka... Failed to save project. The folder has been deleted in the database. Nepodařilo se uložit projekt. Složka byla v databázi smazána. Save ... Uložit... Error Chyba There was an unexpected database error: %1 Vyskytla se neočekávaná chyba databáze: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Projekt '%1' se právě bude aktualizovat z databáze. Jsou tu ovšem neuložené změny. Save changes? Uložit změny? CDemList Deactivate Vypnout Activate Zapnout CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Přidat nebo odstranit cesty obsahující data s výškovým modelem (DEM). V cestě může být více souborů, ale žádná podcesta není zpracována. Podporovanými formáty jsou: %1 Select DEM file path... Vybrat cestu k souboru s výškovým modelem... CDemVRT Error... Chyba... Failed to load file: %1 Nepodařilo se nahrát soubor %1 DEM must have one band with 16bit or 32bit data. Výškový model (DEM) musí mít jedno pásmo s 16bitovými nebo 32bitovými daty. No georeference information found. Nenalezeny žádné údaje o vyjádření prostorových vztahů. CDetailsGeoCache none žádné ??? ? Searching for images... Hledají se obrázky... No images found Nebyly nalezeny žádné obrázky CDetailsPrj none žádné Build diary... Sestavit deník... <h2>Waypoints</h2> <h2>Cestovní body</h2> Info Informace Comment Poznámka <h2>Tracks</h2> <h2>Stopy</h2> From Start Od začátku To Next K další To End Na konec <h2>Areas</h2> <h2>Oblasti</h2> You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Chcete řadit cestovní body podél cesty, ale vypnul jste svázání cestovních bodů a cest (dání do vzájemného vztahu). Chcete je opět zapnout? Correlation... Svázání... <b>Summary over all tracks in project</b><br/> <b>Přehled všech stop v projektu</b><br/> Distance: Ascent: Descent: <h2>Routes</h2> <h2>Cesty</h2> Edit name... Upravit název... Enter new project name. Zadejte nový název projektu. Edit keywords... Upravit klíčová slova... Enter keywords. Zadejte klíčová slova. Print Diary Tisk deníku CDetailsTrk Reduce visible track points Omezit počet viditelných bodů stopy Change elevation of track points Změnit informace o výškách bodů stopy Change timestamp of track points Změnit časová razítka bodů stopy Miscellaneous Různé Color Barva Activity Činnost CDetailsWpt Enter new proximity range. Zadat nový poplach kvůli odstupu. CDeviceGarmin Picture%1 Obrázek %1 Unknown Neznámý CDeviceGarminArchive Archive - expand to load Archiv - Rozbalit k nahrání Archive - loaded Archiv - Nahráno CElevationDialog No DEM data found for that point. Pro tento bod nebyla nalezena žádná data výškového modelu (DEM). CExportDatabase Select export path... Vybrat cestu pro vyvedeni... CExportDatabaseThread Create %1 Vytvořit %1 Failed to create %1 Nepodařilo se vytvořit %1 Done! Hotovo! Abort by user! Přerušeno uživatelem! Database Error: %1 Chyba databáze: %1 Save project as %1 Uložit projekt jako %1 Failed! Nepodařilo se! CFilterDeleteExtension No extension available Není dostupné žádné rozšíření CFilterInterpolateElevation coarse Hrubý medium Střední fine Jemný CFitCrcState FIT decoding error : invalid CRC. Chyba při dekódování FIT: Neplatné CRC. CFitDecoder FIT decoding error: unexpected end of file %1. Chyba při dekódování FIT: Neočekávaný konec souboru %1. CFitFieldBuilder FIT decoding error: unknown base type %1. Chyba při dekódování FIT: Neznámý datový typ %1. CFitFieldDataState Missing field definition for development field. Chybí vymezení pole pro vývojové pole. FIT decoding error: invalid field def nr %1 while creating dev field profile. Chyba dekódování FIT: neplatné vymezení pole číslo %1 při vytváření profilu vývojového pole. CFitHeaderState FIT decoding error: protocol %1 version not supported. Chyba při dekódování FIT: Verze protokolu %1 není podporována. FIT decoding error: file header signature mismatch. File is not FIT. Chyba při dekódování FIT: Nesouhlasí signatura hlavičky. Soubor není FIT. CFitProject Failed to load file %1... Nepodařilo se nahrát soubor %1... Failed to open FIT file %1. Nepodařilo se otevřít soubor FIT %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. Chyba při dekódování FIT: Architektura %1 není podporována. FIT decoding error: invalid offset %1 for state 'record content' Chyba při dekódování FIT: Neplatný posun %1 pro stav 'zaznamenaný obsah' CGarminTyp Warning... Varování... This is a typ file with unknown polygon encoding. Please report! Toto je souborový typ s neznámým kódováním mnohoúhelníku. Nahlašte to, prosím! This is a typ file with unknown polyline encoding. Please report! Toto je souborový typ s neznámým kódováním čáry. Nahlašte to, prosím! CGisItemOvlArea thin Tenký normal Obvyklý wide Široký strong Silný _Clone _Klon Area: %1%2 Oblast: %1%2 Changed area shape. Změněn tvar oblasti. Changed name. Změněn název. Changed border width. Změněna šířka okraje. Changed fill pattern. Změněn vzor výplně. Changed opacity. Změněna neprůhlednost. Changed comment. Změněna poznámka. Changed description. Změněn popis. Changed links Změněné odkazy Changed color Změněná barva CGisItemRte _Clone _Klon track Stopa Changed name. Změněn název. Changed comment Změněná poznámka Changed description Změněný popis Changed links Změněné odkazy Length: %1%2 Délka: %1%2 Time: %1%2 Čas: %1%2 Distance: %1%2 Vzdálenost: %1%2 Length: - Délka: - Time: - Výsledný čas: - %1%2 %3, %4%5 %6 %1%2 %3, %4%5 %6 Last time routed:<br/>%1 Poslední spočítání cesty:<br/>%1 with %1 s %1 Changed route points. Změněné body cesty. CGisItemTrk FIT file %1 contains no GPS data. Soubor FIT %1 neobsahuje žádná data GPS. Error... Chyba... Failed to open %1. Nepodařilo se otevřít %1. Only support lon/lat WGS 84 format. Jako formát je podporován jen lon/lat WGS 84. Failed to read data. Nepodařilo se přečíst data. _Clone _Klon Invalid points.... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? Changed trackpoints, sacrificed all previous data. Změněny body stop. Obětována veškerá předchozí data. min. min. max. max. Length: %1%2 Délka: %1%2 , %1%2%3, %4%5%6 , %1%2 %3, %4%5%6 {1%2%3,?} Time: %1%2, Speed: %3%4 Čas: %1, Rychlost: %3%4 {1%2,?} Moving: %1%2, Speed: %3%4 Pohyb: %1, Rychlost: %3%4 {1%2,?} Start: %1 Začátek: %1 Start: - Začátek: - End: %1 Konec: %1 End: - Konec: - Points: %1 (%2) Body: %1 (%2) Invalid elevations! Neplatné výšky! Invalid timestamps! Neplatná časová razítka! Invalid positions! Neplatné polohy! Activities: %1 Činnosti: %1 Index: %1 Rejstřík: %1 Index: visible %1, total %2 Rejstřík: viditelné %1, celkem %2 ... and %1 tags not displayed ... a %1 značek nezobrazeno Distance: - (-) Vzdálenost: - (-) Moving: - (-) Pohyb: - (-) , Descent: %1%2 (%3%) , Moving: %1%2 (%3%) , Descent: %1%2 track Stopa Hide point %1. Skrýt bod %1. Hide points %1..%2. Skrýt body %1 %2. , %1%2 , %1%2 , %1-, %2- , %1-, %2- Time: -, Speed: - Čas: -, Rychlost: - Moving: -, Speed: - Pohyb: -, Rychlost: - Ele.: %1%2 Výška: %1%2 , Slope: %1%2 , Speed: %1%2 Ascent: - (-) Stoupání: - (-) Descent: - (-) Klesání: - (-) Ascent: %1%2 (%3%) Stoupání: %1%2 (%3%) Distance: %1%2 (%3%) Vzdálenost: %1%2 (%3%) Ascent: - Stoupání: - Descent: - Klesání: - Ascent: %1%2 Stoupání: %1%2 Distance: %1%2 Vzdálenost: %1%2 , Time: %1%2 Permanently removed points %1..%2 Trvale odstraněné body %1 ... %2 Show points. Ukázat body. Changed name Změněný název Changed comment Změněná poznámka Changed description Změněný popis Changed links Změněné odkazy Changed elevation of point %1 to %2 %3 Výška bodu %1 byla změněna na %2 %3 Changed activity to '%1' for complete track. Činnost byla pro celou stopu změněna na '%1'. Changed activity to '%1' for range(%2..%3). Činnost byla změněna pro oblast (%2...%3) na '%1'. Hide points by Douglas Peuker algorithm (%1%2) Skrýt body pomocí algoritmu Douglas Peuker (%1%2) Hide points with invalid data. Skrýt body s neplatnými daty. Reset all hidden track points to visible Nastavit znovu všechny skryté body stopy na viditelné Permanently removed all hidden track points Všechny skryté body stopy odstraněny trvale Smoothed profile with a Median filter of size %1 Profil vyhlazen středovým filtrem o velikosti %1 Added terrain slope from DEM file. Přidán sklon území ze souboru s digitálním výškovým modelem (DEM). Replaced elevation data with data from DEM files. Výšková data nahrazena daty ze souborů s digitálním výškovým modelem (DEM). Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Výšková data nahrazena interpolovanými hodnotami. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Výšková data posunuta o %1%2. Changed start of track to %1. Začátek stopy změněn na %1. Remove timestamps. Odstranit časová razítka. Set artificial timestamps with delta of %1 sec. Uměle utvořená časová razítka nastavena s odstupem %1 s. Changed speed to %1%2. Rychlost změněna na %1%2. %1 (Segment %2) %1 (část %2) Removed extension %1 from all Track Points Rozšíření %1 bylo odstraněno ze všech bodů stopy Converted subpoints from routing to track points Podbody převedeny ze stanovení směru cesty na body stopy Copy flag information from QLandkarte GT track Kopírovat informační příznak ze stopy QLandkarte GT CGisItemWpt Archived Archivováno Available Dostupné Not Available Nedostupné _Clone _Klon Elevation: %1%2 Výška: %1%2 Proximity: %1%2 Blízkost: %1%2 Changed name Změněný název Changed position Změněná poloha Changed elevation Změněná výška Removed proximity Changed proximity Změněná blízkost Changed icon Změněná ikona Changed comment Změněná poznámka Changed description Změněný popis Changed links Změněné odkazy Changed images Změněné obrázky Add image Přidat obrázek Changed to proximity-radius Changed to nogo-area CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Na základě změn v databázovém systému QMapShack souborové názvy ve vaší databázi '%1' už nezná. Musíte je v dalším kroku znovu zvolit. Select database file. Vybrat soubor s databází. Add Database Přidat databázi Add Folder Přidat složku Rename Folder Přejmenovat složku Copy Folder Kopírovat složku Move Folder Přesunout složku Delete Folder Smazat složku Import from Files... Zavést ze souborů... Export to GPX... Vyvést do GPX... Delete Item Smazat prvek Search Database Prohledat databázi Sync. with Database Seřídit s databází Remove Database Odstranit databázi Empty Prázdný Remove database... Odstranit databázi... Do you really want to remove '%1' from the list? Opravdu chcete '%1' odstranit ze seznamu? Are you sure you want to delete selected folders and all subfolders from the database? Opravdu chcete smazat vybrané složky a všechny podsložky z databáze? Bad operation.... Špatná operace... The target folder is a subfolder of the one to move. This will not work. Cílová složka je podsložkou složky k přesunutí. Toto nebude pracovat. Folder name... Název složky... Rename folder: Přejmenovat složku: Are you sure you want to delete '%1' from folder '%2'? Jste si jistý, že chcete smazat '%1' ze složky '%2'? Delete... Smazat... Import GIS Data... Zavést údaje GIS... Delete database folder... Smazat složku s databází... Remove items... Odstranit prvky... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Opravdu chcete smazat všechny prvky ze ztracených a nalezených? Tím budou trvale odstraněny. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Opravdu chcete smazat všechny vybrané prvky ze ztracených a nalezených? Tím budou trvale odstraněny. CGisListWks Save Uložit Edit.. Upravit... Close Zavřít Update Project on Device Aktualizovat projekt na zařízení Edit... Upravit... Copy to... Kopírovat do... Autom. Save Automaticky. Uložit Save as... Uložit jako... Copy Track with Waypoints Kopírovat stopu s cestovními body Show Bubble Ukázat bublinu Move Waypoint Přesunout cestovní bod Proj. Waypoint... Promítnutí cestovního bodu... Change Radius Toggle Nogo-Area Delete Radius Route Instructions Pokyny pro cestu Calculate Route Spočítat cestu Reset Route Nastavit cestu znovu Edit Route Upravit cestu Convert to Track Převést na stopu Create Route Vytvořit cestu Change Icon (sel. waypt. only) Změnit ikonu (pouze vybrané cestovní body) Set Track Activity Nastavit činnost stopy Drop items... Zahodit prvky... <b>Update devices</b><p>Update %1<br/>Please wait...</p> <b>Aktualizovat zařízení</b><p>Aktualizovat %1<br/>Počkejte, prosím...</p> Delete project... Smazat projekt... Do you really want to delete %1? Opravdu chcete smazat %1? Track Profile Profil stopy Show on Map Ukázat na mapě Hide from Map Skrýt v mapě Sort by Time Řadit podle času Sort by Name Řadit podle názvu Save as GPX 1.1 w/o ext... Uložit jako GPX 1.1 w/o ext... Send to Devices Poslat do zařízení Sync. with Database Seřídit s databází Select Range Vybrat rozsah Edit Track Points Upravit body stopy Reverse Track Obrátit stopu Combine Tracks Spojit stopy Edit Area Points Upravit body oblasti Delete Smazat Saving workspace. Please wait. Ukládá se pracovní prostor. Počkejte, prosím. Loading workspace. Please wait. Nahrává se pracovní prostor. Počkejte, prosím. Close all projects... Zavřít všechny projekty... This will remove all projects from the workspace. Tímto budou všechny projekty odstraněny z pracovního prostoru. CGisWorkspace Load project... Nahrát projekt... The project "%1" is already in the workspace. Projekt "%1" je již náhrán do pracovního prostoru. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. <b>Výběr prvků: </b>Prvek vybrán ze seznamu pracovního prostoru. Klepněte na mapu pro přepnutí zpět do běžného chování při výběru myší. Copy items... Kopírovat prvky... Change waypoint symbols. Změnit značky cestovních bodů. Cut Track... Rozkrojit stopu... Do you want to delete the original track? Opravdu chcete smazat původní stopu? CGpxProject Failed to load file %1... Nepodařilo se nahrát soubor %1... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Not a GPX file: %1 Není souborem GPX: %1 File exists ... Soubor existuje... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Soubor existuje a nebyl vytvořen programem QMapShack. Pokud stisknete Ano, budou všechna data v tomto souboru ztracena. I když by tento soubor obsahoval data GPX a byl nahrán programem QMapShack, QMapShack nemusí být schopen nahrát a uložit všechny prvky tohoto souboru. Tyto prvky budou ztraceny. Doporučuje se použít jiný soubor. <b>Opravdu chcete soubor přepsat?</b> Failed to create file '%1' Nepodařilo se vytvořit soubor '%1' Failed to write file '%1' Nepodařilo se zapsat soubor '%1' Saving GIS data failed... Nepodařilo se uložit data GIS... CGrid %1 %2 %1 %2 %1%2%5 %3%4%5 %1%2%5 %3%4%5 %1m, %2m %1m, %2m N %1m, E %2m N %1 m, E %2 m CHistoryListWidget by %1 od %1 Cut history before Vyjmout záznam minulosti před Cut history after Vyjmout záznam minulosti po History removal Odstranění záznamu minulosti The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> Odstranění je trvalé a nelze je vrátit zpět. <b>Opravdu chcete smazat záznamy před tímto krokem?</b> CImportDatabase Import QLandkarte Database Zavést databázi QLandkarte Select source database... Vybrat zdrojovou databázi... Select target database... Vybrat cílovou databázi... CKnownExtension Air Temp. extShortName Air Temperature extLongName Teplota vzduchu Water Temp. extShortName Water Temperature extLongName Teplota vody Depth extShortName Hloubka Depth extLongName Hloubka Heart R. extShortName Heart Rate extLongName Tep srdce Cadence extShortName Rychlost chůze Cadence extLongName Rychlost chůze Speed extShortName Rychlost Speed extLongName Rychlost Accel. extShortName Acceleration extLongName Zrychlení Course extShortName Směr Course extLongName Směr Temp. extShortName Temperature extLongName Teplota Dist. extShortName Vzdál. Distance extLongName Vzdálenost Ele. extShortName Výška Elevation extLongName Výška Energy extShortName Síla Energy extLongName Síla Sea Lev. Pres. extShortName Sea Level Pressure extLongName Tlak u hladiny moře v. Speed extShortName Vertical Speed extLongName Slope* Sklon* Slope extShortName Sklon Speed over Distance* extLongName Speed over Time* extLongName Elevation* extLongName Progress extShortName Postup Progress* extLongName Terr. Slope extShortName Terrain Slope* extLongName CLogProject Failed to load file %1... Nepodařilo se nahrát soubor %1... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Not an Openambit log file: %1 Device: %1<br/> Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 CLostFoundProject Lost & Found Ztraceno a nalezeno CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Použít <b>Nabídka → Pohled → Přidat pohled na mapu</b> k otevření nového pohledu. Nebo <b>Nabídka → Soubor → Nahrát pohled na mapu</b> k obnovení uložené. Nebo klepněte <a href='newview'>sem</a>. Ele.: %1%2 Výška: %1%2 Slope: %1%2 terrain Sklon: %1%2 [Grid: %1] [Mřížka: %1] Load GIS Data... Nahrát data GIS... Select output file Vybrat výstupní soubor QMapShack View (*.view) Pohled QMapShack (*.view) Select file to load Vybrat soubor k nahrání Fatal... Kritické... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. QMapShack zjistil, že knihovna Proj4 je nainstalována špatně. Chybí překladové tabulky pro promítání EPSG, jež jsou obvykle uloženy v /usr/share/proj. Spojte se, prosím, s údržbářem balíčku ve vaší distribuci, aby to spravil. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. Nyní tu nejsou žádné mapy. S QMapShack bez map není žádná zábava. Mapy můžete nainstalovat po stisknutí tlačítka Pomoc! Potřebuji mapy! v panelovém okně Mapy. Nebo můžete stisknout klávesu F1 pro otevření dokumentace na internetu, která vám poví, jak QMapShack používat. A když to bez map nejde, proč je neposkytujete? Protože mít mapy připravené ke stažení vyžaduje dobrý server. A to není služba zadarmo. Projektu se (na to) nedostává peněz. A mapy a data výškových modelů (DEM) jsou chráněna autorskými právy (právy ke kopírování). Z toho důvodu musí být držitel práv před zabalením dat požádán. Není to tak lehké, jak to může znít a za některá data se platí poplatky za užívání. Projektu zkrátka chybí prostředky, aby to dělal. Myslíme si dále, že žádat po vás, abyste si tyto věci nainstalovali sami, není zas tak moc. Přece jen je tento program šířen bez poplatku. CMapIMG Failed ... Nepodařilo se... Unspecified Neurčeno French Francouzský German Německý Dutch Holandský English Anglický Italian Italský Finnish Finský Swedish Švédský Spanish Španělský Basque Baskický Catalan Katalánský Galician Galicijský Welsh Velšský Gaelic Gaelský Danish Dánský Norwegian Norský Portuguese Portugalský Slovak Slovenský Czech Český Croatian Chorvatský Hungarian Maďarský Polish Polský Turkish Turecký Greek Řecký Slovenian Slovinský Russian Ruský Estonian Estonský Latvian Lotyšský Romanian Rumunský Albanian Albánský Bosnian Bosenský Lithuanian Litevský Serbian Srbský Macedonian Makedonský Bulgarian Bulharský Major highway Dálnice Principal highway Silnice první třídy Other highway Jiné rychlostní silnice Arterial road Rychlostní silnice Collector road Státní silnice Residential street Silnice v obytné oblasti Alley/Private road Soukromá cesta Highway ramp, low speed Nájezd na dálnici/sjezd z dálnice Highway ramp, high speed Nájezd na dálnici/sjezd z dálnice Unpaved road Neasfaltovaná cesta Major highway connector Dalniční přivaděč Roundabout Kruhový objezd Railroad Železnice, koleje Shoreline Břeh Trail Cesta Stream Proud Time zone Časové pásmo Ferry Přívoz State/province border Státní/Zemská hranice County/parish border Krajská/Obecní hranice International border Mezinárodní hranice River Řeka Minor land contour Malá vrstevnice Intermediate land contour Střední vrstevnice Major land contour Velká vrstevnice Minor depth contour Malá hloubková čára Intermediate depth contour Střední hloubková čára Major depth contour Velká hloubková čára Intermittent stream Přerušovaný potok (Wadi) Airport runway Přistávací dráha Pipeline Dálkové potrubí Powerline Elektrické vedení Marine boundary Hranice moře Hazard boundary Nebezpečná hranice Large urban area (&gt;200K) Velkoměstská oblast (&gt;200 000) Small urban area (&lt;200K) Maloměstská oblast (&gt;200 000) Rural housing area Městská obytná oblast Military base Vojenská základna Parking lot Parkoviště Parking garage Parkovací budova Airport Letiště Shopping center Nákupní středisko Marina Přístav University/College Univerzita/Vysoká škola Hospital Nemocnice Industrial complex Průmyslový celek Reservation Chráněné území Man-made area Zástavba Sports complex Oblast pro tělesné činnosti Golf course Golfové hřiště Cemetery Hřbitov National park Národní park City park Městské sady State park Státní park Forest Les Ocean Oceán Blue (unknown) Modrá (neznámé) Sea Moře Large lake Velké jezero Medium lake Střední jezero Small lake Malé jezero Major lake Velmi velké jezero Major River Veletok Large River Velká řeka Medium River Střední řeka Small River Malá řeka Intermittent water Přerušovaná voda Wetland/Swamp Močál/Bažina Glacier Ledovec Orchard/Plantation Sad/Plantáž Scrub Křoví Tundra Tundra Flat Rovina ??? ??? Read external type file... Přečíst vnější typ souboru... Failed to read type file: %1 Fall back to internal types. Nepodařilo se přečíst typ souboru: %1 Návrat k vnitřním typům. Failed to read: Nepodařilo se přečíst: Failed to open: Nepodařilo se otevřít: Bad file format: Špatný formát souboru: Failed to read file structure: Nepodařilo se přečíst stavbu souboru: Loading %1 Nahrává se %1 User abort: Zrušeno uživatelem: File is NT format. QMapShack is unable to read map files with NT format: Soubor je ve formátu NT. QMapShack nedokáže číst mapové soubory ve formátu NT: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Soubor obsahuje zamknutá/zašifrovaná data. Garmin nechce, aby byl tento soubor použit s jiným programem než dodaným Garminem. Point of Interest Podivuhodnost Unknown Neznámý Area Oblast CMapList Deactivate Vypnout Activate Zapnout Where do you want to store maps? Kde chcete ukládat mapy? CMapMAP Failed ... Nepodařilo se... Failed to open: Nepodařilo se otevřít: Bad file format: Špatný formát souboru: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Přidat nebo odstranit cesty obsahující mapy. V cestě může být více map, ale žádná podcesta není zpracována. Podporovanými formáty jsou: %1 Select map path... Vybrat cestu k mapě... Select root path... Vybrat cestu ke kořeni... CMapPropSetup Select type file... Vybrat typ souboru... CMapRMAP Error... Chyba... This is not a TwoNav RMAP file. Toto není soubor TwoNav RMAP Unknown sub-format. Neznámý podformát. Unknown version. Neznámá verze Failed to read reference point. Nepodařilo se přečíst referenční bod. Unknown projection and datum (%1%2). Neznámé promítání a datum (%1%2). CMapTMS Error... Chyba... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Layer %1 Vrstva %1 CMapVRT Error... Chyba... Failed to load file: %1 Nepodařilo se nahrát soubor %1 File must be 8 bit palette or gray indexed. Soubor musí mít 8 bitovou barevnou paletu nebo být v odstínech šedi. No georeference information found. Nenalezeny žádné údaje o vyjádření prostorových vztahů. CMapVrtBuilder Build GDAL VRT Sestavit GDAL VRT Select files... Vybrat soubory... Select target file... Vybrat cílový soubor... !!! done !!! Hotovo! CMapWMTS Error... Chyba... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Failed to read: %1 Unknown structure. Chyba při čtení: %1 Neznámá stavba. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. Neočekávaná služba. Očekáváno '* WMTS 1.0.0'. Přečteno '%1 %2'. No georeference information found. Nenalezeny žádné údaje o soustavě souřadnic. CMouseEditArea Area Oblast <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Upravit oblast</b><br/>Vyberte funkci a režim stanovení směru cesty přes nástrojová tlačítka. Dále vyberte bod na čáře. Lze měnit pouze body označené velkým čtverečkem. Černé body jsou podbody vytvořenými při stanovení směru cesty.<br/> area Oblast CMouseEditRte Route Cesta <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Upravit body cesty</b><br/>Vyberte funkci a režim stanovení směru cesty přes nástrojová tlačítka. Dále vyberte bod na čáře. Lze měnit pouze body označené velkým čtverečkem. Černé body jsou podbody vytvořenými při stanovení směru cesty.<br/> route Cesta CMouseEditTrk Track Stopa <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> <b>Upravit body cesty</b><br/>Vyberte funkci a režim stanovení směru cesty přes nástrojová tlačítka. Dále vyberte bod na čáře. Lze měnit pouze body označené velkým čtverečkem. Černé body jsou podbody vytvořenými při stanovení směru cesty.<br/> Warning! Varování! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. Tímto budou všechny původní údaje nahrazeny jednoduchou čárou souřadnic. Všechna ostatní data budou trvale ztracena. track Stopa CMouseNormal Add POI as Waypoint Přidat POI jako cestovní bod Add Waypoint Přidat cestovní bod Add Track Přidat stopu Add Route Přidat cestu Add Area Přidat oblast Select Items On Map Vybrat prvky na mapě Copy position Kopírovat polohu Copy position (Grid) Kopírovat polohu (mřížka) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Uložit mapu (vytisknout)</b><br/>Vyberte na mapě obdélníkovou oblast. použijte levé tlačítko myši a pohybujte myší. Zrušte výběr klepnutím pravým tlačítkem myši. Výběr lze upravit posunutím rohových bodů myší. Uložení/Vytištění následuje po klepnutí levým tlačítkem myši na odpovídající symbol uprostřed výběru. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> <b>Upravit rozsah</b><br/>Vyberte první bod stopy klepnutím levým tlačítkem myši. A potom druhý bod. Opusťte výběr rozsahu klepnutím pravým tlačítkem myši.<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Vybrat prvky na mapě</b><br/>Vyberte na mapě klepnutím levým tlačítkem myši obdélníkovou oblast. Výběr zrušíte klepnutím pravým tlačítkem myši. Výběr lze upravit posunutím rohových bodů myší. <b>Selected:</b><br/> <b>Vybráno:</b><br/> %1 waypoints<br/> %1 cestovní body<br/> %1 tracks<br/> %1 stopy<br/> %1 routes<br/> %1 cesty<br/> %1 areas<br/> %1 oblasti<br/> CPhotoAlbum Select images... Vybrat obrázky... CPlot Distance [%1] Time Čas CPlotProfile Distance [%1] Ele. [%1] CPrintDialog Print Map... Tisk mapy... Save Map as Image... Uložit mapu jako obrázek... Printer Properties... Vlastnosti tiskárny... Pages: %1 x %2 Strany: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Přibližujte a oddalujte pomocí kolečka myši na mapě dole pro změnu rozlišení: %1x%2 pixel x: %3 m/px y: %4 m/px Printing pages. Probíhá tisk stran. Save map... Uložit mapu... CProgressDialog Elapsed time: %1 Uplynulý čas: %1 Elapsed time: %1 seconds. Uplynulý čas: %1 sekund. CProjWizard north Sever south Jih Error... Chyba... The value '%1' is not a valid coordinate system definition: %2 Zadání: '%1' není platným vymezením soustavy souřadnic %2 CProjWpt Edit name... Upravit název... Enter new waypoint name. Zadat nový název cestovního bodu. CQlbProject Failed to open... Nepodařilo se otevřít... Failed to open %1 Nepodařilo se otevřít %1 Could not convert... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. CQlgtDb Migrating database from version 4 to 5. Přestěhovat databázi z verze 4 na verzi 5. Migrating database from version 5 to 6. Přestěhovat databázi z verze 5 na verzi 6. Migrating database from version 6 to 7. Přestěhovat databázi z verze 6 na verzi 7. Migrating database from version 7 to 8. Přestěhovat databázi z verze 7 na verzi 8. Migrating database from version 8 to 9. Přestěhovat databázi z verze 8 na verzi 9. Open database: %1 Otevřít databázi: %1 Folders: %1 Složky: %1 Tracks: %1 Stopy: %1 Routes: %1 (Only the basic route will be copied) Cesty: %1 (Bude koírována pouze základní cesta) Waypoints: %1 Cestovní body: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Překrytí: %1 (oblasti budou převáděny jako oblasti, vzdálenostní čáry budou převedeny do stop, všechny ostatní překrývající prvky budou ztraceny) Diaries: %1 Deníky: %1 Map selections: %1 (can't be converted to QMapShack) Výběry map: %1 (nelze převést do QMapShack) ------ Start to convert database to %1------ ------ Začít převádět databázi do %1------ Failed to create target database. Nepodařilo se vytvořit cílovou databázi. ------ Abort ------ ------ Zrušit ------ ------ Done ------ ------ Hotovo ------ Restore folders... Obnovit složky... Imported %1 folders and %2 diaries Zavedeno %1 složek a %2 deníků Copy items... Kopírovat prvky... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Zavedeno %1 stop, %2 cestovních bodů, %3 cest, %4 oblastí Import folders... Zavést složky... Overlay of type '%1' cant be converted Překrytí typu '%1' nelze převést CQlgtTrack Corrupt track ... Poškozená stopa... Number of trackpoints is not equal the number of training data trackpoints. Počet bodů stopy neodpovídá počtu bodů stopy cvičebních dat. Number of trackpoints is not equal the number of extended data trackpoints. Počet bodů stopy neodpovídá počtu rozšířených bodů stopy. Number of trackpoints is not equal the number of shadow data trackpoints. Počet bodů stopy neodpovídá počtu stínových bodů stopy. CQmsDb Existing file... Stávající soubor... Remove existing %1? Odstranit stávající %1? Remove existing file %1 Odstranit stávající soubor %1 %1: drop item with QLGT DB ID %2 %1: Zahodit prvek s ID DB QLGT %2 CQmsProject Failed to open... Nepodařilo se otevřít... Failed to open %1 Nepodařilo se otevřít %1 CRouterBRouter original Původní first alternative První náhradní second alternative Druhý náhradní third alternative Třetí náhradní BRouter (offline) BRouter (nepřipojeno) BRouter (online) BRouter (připojeno) profile: %1, alternative: %2 Profil: %1, náhradní: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade response is empty Odpověď je prázdná Bad response from server: %1 Špatná odpověď od serveru: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... <b>BRouter</b><br/>Požadavek na stanovení cesty poslán serveru. Počkejte, prosím... Calculate route with %1 Spočítat cestu s %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <b>BRouter</b><br/>Špatná odpověď od serveru:<br/>%1 <br/>Calculation time: %1s <br/>Doba výpočtu: %1 s Error Chyba running Běží starting Začíná QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. QMapShack se s BRouter dorozumívá přes síťové spojení. Obyčejně se tak děje na zvláštní adrese, na kterou nelze dosáhnout vně vašeho zařízení. BRouter nicméně naslouchá spojení na všech dostupných rozhraních. Pokud jste ve své vlastní síti se zapnutým firewallem (ohnivou zdí), není to až zas takový problém. Pokud jste ve veřejné síti, každá otevřená přípojka (port) představuje nebezpečí, protože může být využita ještě někým dalším s možným úmyslem ohrozit váš systém. V tomto případě se nedoporučuje užití místní služby BRouter. Warning... Varování... I understand the risk. Don't tell me again. Rozumím nebezpečí. Znovu už mě neupozorňovat. stopped Zastaveno not installed Nenainstalováno online Připojeno CRouterBRouterSetup %1 not accessible %1: Není přístupný %1 invalid result %1 Neplatný výsledek Error parsing online-config: Chyba při zpracování nastavení na internetu: Network error: Síťová chyba: CRouterBRouterSetupWizard Restore Default Values Obnovit výchozí hodnoty Open Directory Otevřít adresář select Java Executable Vybrat spustitelný soubor Java please select BRouter installation directory Vyberte, prosím, instalační adresář pro BRouter selected directory does not exist Vybraný adresář neexistuje create directory and install BRouter there Vytvořit adresář a nainstalovat do něj BRouter existing BRouter installation Stávající instalace BRouter update existing BRouter installation Aktualizovat stávající instalaci BRouter empty directory, create new BRouter installation here Prázdný adresář. Vytvořit novou instalaci BRouter zde create new BRouter installation Vytvořit novou instalaci BRouter seems to be a valid Java-executable Zdá se, že se jedná o platný spustitelný soubor Java doesn't seem to be a valid Java-executable Zdá se, že se nejedná o platný spustitelný soubor Java Java Executable not found Spustitelný soubor Java nenalezen Error loading installation-page at %1 Chyba při nahrávání instalační stránky na %1 no brouter-version to install selected Nvybrána žádná verze BRouter k nainstalování selected %1 for download and installation Vybráno %1 pro stažení a instalaci Warning... Varování... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. Stáhnout: %1<br/><br/>Toto stáhne nainstaluje soubor zip z umístění se staženými soubory, které není jakkoli se to vezme bezpečné, používající prostý HTTP. Obyčejně by to mělo být HTTPS. Nebezpečí spočívá v tom, že někdo přesměruje požadavek a pošle vám náhradou archiv zip se škodlivým programem. QMapShack toto nemá jak zjistit. <br/>Pokud tomu nerozumíte a máte pochybnosti, nepokračujte a přerušte. Místo toho použijte internetovou verzi BRouter. I understand the risk and wish to proceed. Rozumím nebezpečí a přeji si pokračovat. download %1 started Stahování %1 začalo Network Error: %1 Chyba v síti: %1 download %1 finished Stahování %1 dokončeno unzipping: Rozbalení: ready. Připraven. download of brouter failed: %1 Nepodařilo se stáhnout BRouter: %1 retrieving available profiles from %1 Získávají se dostupné profily z %1 content of profile Obsah profilu Error: Chyba: Error creating directory %1 Chyba při vytváření adresáře %1 Error directory %1 does not exist Chyba adresář %1 neexistuje Error creating file %1 Chyba při vytváření souboru %1 Error writing to file %1 Chyba při zápisu do souboru %1. CRouterBRouterTilesPage Continue with Setup Pokračovat v nastavování CRouterBRouterTilesSelect available routing-data is being determined. Dostupná data se stanovením cesty jsou určena. Select outdated Vybrat zastaralé Clear Selection Vyprázdnit výběr Delete selection Smazat výběr Download Stáhnout Error creating segments directory %1 Chyba při vytváření adresáře s částmi %1 cannot parse: %1 is not a date Nelze zpracovat: %1 není datum cannot parse: %1 is not a valid size Nelze zpracovat: %1 není platná velikost Error retrieving available routing data from %1: %2 Chyba při získávání dostupných dat se stanovením cesty z %1: %2 segments directory does not exist: Adresář s částmi neexistuje: error creating file %1: %2 Chyba při vytváření souboru %1: %2 no valid request for filename %1 Žádný platný požadavek pro souborový název %1 no open file assigned to request for %1 Žádný otevřený soubor nepřiřazen k požadavku pro %1 error writing to file %1: %2 Chyba při zápisu do souboru %1: %2 error renaming file %1 to %2: %3 Chyba při přejmenovávání souboru %1 na %2: %3 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) Aktuální: %1 (%2), zastaralé: %3 (%4), ke stažení: %5 (%6) being downloaded: %1 of %2 Stahuje se: %1 z %2 no local data, online available: %1 (%2) Žádná místní data, dostupná na internetu: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Místní data zastaralá (%1, %2 - vzdálený %3, %4) Error removing %1: %2 Chyba při odstraňování souboru %1: %2 Network Error Síťová chyba invalid result, no files found Neplatný výsledek, nenalezeny žádné soubory local data up to date (%1, %2) Místní data aktuální (%1, %2) no routing-data available Nejsou dostupná žádná data se stanovením cesty CRouterBRouterToolShell !!! done !!! Hotovo! !!! failed !!! Nepodařilo se! CRouterMapQuest Fastest Nejrychlejší Shortest Nejkratší Bicycle Jízdní kolo Pedestrian Chodec US English Angličtina (USA) British English Angličtina (britská) Danish Dánský Dutch Holandský French Francouzský German Německý Italian Italský Norwegian Norský Spanish Španělský Swedish Švédský mode "%1" Režim "%1" no highways Žádné rychlostní silnice no toll roads Žádné silnice s mýtem no seasonal Žádné sezonní silnice no unpaved Žádné nezpevněné silnice no ferry Žádné přívozy no crossing of country borders Žádný přechod zemské hranice <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Požadavek na stanovení cesty poslán serveru. Počkejte, prosím... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <b>MapQuest</b><br/>Špatná odpověď od serveru:<br/>%1 <br/>Calculation time: %1s <br/>Doba výpočtu: %1 s CRouterRoutino Foot Chodec Horse Jezdec Wheelchair Invalidní vozík Bicycle Jízdní kolo Moped Moped Motorcycle Motorka Motorcar Automobil Goods Nákladní automobil Shortest Nejkratší Found Routino with a wrong version. Expected %1 found %2 Nalezeno Routino s nesprávnou verzí. Očekávána %1, nalezena %2 Quickest Nejrychlejší English Anglický German Německý French Francouzský Hungarian Maďarský Dutch Holandský Russian Ruský Polish Polský A function was called without the database variable set. Byla zavolána funkce, aniž by byla nastavena proměnná databáze. A function was called without the profile variable set. Byla zavolána funkce, aniž by byla nastavena proměnná profilu. A function was called without the translation variable set. Byla zavolána funkce, aniž by byla nastavena proměnná jazyka. The specified database to load did not exist. Databáze zadaná k nahrání neexistuje. The specified database could not be loaded. Zadanou databázi se nepodařilo nahrát. The specified profiles XML file did not exist. Zadaný soubor s profilem XML neexistuje. The specified profiles XML file could not be loaded. Zadaný soubor s profilem XML se nepodařilo nahrát. The specified translations XML file did not exist. Zadaný soubor s jazykem XML neexistuje. The specified translations XML file could not be loaded. Zadaný soubor s jazykem XML se nepodařilo nahrát. The requested profile name does not exist in the loaded XML file. Požadovaný název profilu v nahraném souboru XML není. The requested translation language does not exist in the loaded XML file. Požadovaný jazyk v nahraném souboru XML není. The profile and database do not work together. Profil a databáze dohromady nepracují. The profile being used has not been validated. Používaný profil nebyl schválen. The user specified profile contained invalid data. Uživatelem stanovený profil obsahoval neplatná data. The routing options specified are not consistent with each other. Zadané volby pro stanovení cesty si vzájemně neodpovídají. There is a mismatch between the library and caller API version. Knihovna a verze API si vzájemně neodpovídají. Route calculation was aborted by user. Výpočet cesty byl přerušen uživatelem. A route could not be found to waypoint %1. Nepodařilo se najít žádnou cestu k cestovnímu bodu %1. Unknown error: %1 Neznámá chyba: %1 profile "%1" Profil "%1" , mode "%1" , režim "%1" Warning... Varování... In the routing database there is no highway near the coordinates to place a waypoint. V databázi cest není žádná hlavní silnice poblíž souřadnic k umístění cestovního bodu. Calculate route with %1 Spočítat cestu s %1 <br/>Calculation time: %1s <br/>Doba výpočtu: %1 s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Přidat nebo odstranit cesty obsahující data Routino. V cestě může být více databází, ale žádná podcesta není zpracována. Select routing data file path... Vybrat cestu k souboru s daty se stanovením cesty... CRouterSetup Routino (offline) Routino (nepřipojeno) MapQuest (online) MapQuest (nepřipojeno) BRouter (online) BRouter (připojeno) CRoutinoDatabaseBuilder Create Routino Database Vytvořit databázi Routino Select files... Vybrat soubory... Select target path... Vybrat cílovou cestu... !!! done !!! Hotovo! CScrOptRangeTrk No range selected Nevybrán žádný rozsah CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Přesný režim</b><br/>Všechny vybrané prvky musí být úplně uvnitř vybrané oblasti.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Protínající se režim</b><br/>Všechny vybrané prvky musí být uvnitř nebo alespoň protínat vybranou oblast.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Přidat stopy</b><br/>Přidat stopy do seznamu vybraných prvků.<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Přidat cestovní body</b><br/>Přidat cestovní body do seznamu vybraných prvků.<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Přidat cesty</b><br/>Přidat cesty do seznamu vybraných prvků.<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Přidat oblasti</b><br/>Přidat oblasti do seznamu vybraných prvků.<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Přehlížet stopy</b><br/>Přehlížet stopy v seznamu vybraných prvků.<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Přehlížet cestovní body</b><br/>Přehlížet cestovní body v seznamu vybraných prvků.<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Přehlížet cesty</b><br/>Přehlížet cesty v seznamu vybraných prvků.<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> <b>Přehlížet oblasti</b><br/>Přehlížet oblasti v seznamu vybraných prvků.<br/> CSearchDatabase Search database '%1': Prohledat databázi '%1': CSearchGoogle Unknown response Neznámá odpověď Error: Chyba: CSetupDatabase Missing Requirement Chybí požadavek MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. MySQL nemůže být toho času použita, protože není dostupný odpovídající ovladač (QMYSQL).<br />Ujistěte se, prosím, že byl nainstalován odpovídající balíček.<br />Pokud nevíte, co se má dělat, podívejte se na dokumentaci na <a href="%1">Wiki</a>. Error... Chyba... There is already a database with name '%1' Již je databáze s názvem '%1' New database... Nová databáze... Open database... Otevřít databázi... CSetupWorkspace Setup database... Nastavit databázi... Changes will become active after an application's restart. Změny budou uvedeny v činnost po opětovném spuštění programu. CSlfProject Failed to load file %1... Nepodařilo se nahrát soubor %1... CSlfReader Failed to parse timestamp `%1` Nepodařilo se zpracovat časové razítko `%1` %1 does not exist %1: Neexistuje Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Not a SLF file: %1 Není souborem SLF: %1 Unsupported revision %1: %2 Nepodporovaná změna %1: %2 Break %1 Přestávka %1 Lap %1 Kolo %1 CSmlProject Failed to load file %1... Nepodařilo se nahrát soubor %1... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Not an sml file: %1 Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Battery usage: %1 %/hour Device: %1<br/> Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This SML file does not contain any position data and can not be displayed by QMapShack: %1 CTableTrk Double click to edit elevation value Dvakrát klepněte pro upravení hodnoty výšky %1%2 %1%2 CTcxProject Failed to load file %1... Nepodařilo se nahrát soubor %1... Failed to open %1 Nepodařilo se otevřít %1 Failed to read: %1 line %2, column %3: %4 Chyba při čtení: %1 Řádek %2, Sloupec %3: %4 Not a TCX file: %1 Není to soubor TCX: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. Tento soubor TCX obsahuje alespoň 1 řešení, ale není to ani činnost ani směr. A jelikož ta řešení neobsahují údaje o poloze, nelze je zavést do QMapShack. This TCX file does not contain any activity or course: %1 Tento soubor TCX neobsahuje žádnou činnost ani směr: %1 File exists ... Soubor existuje... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Soubor existuje a nebyl vytvořen QMapShack. Pokud stisknete Ano, všechna data v tomto poli budou ztracena.I když tento soubor obsahuje data a byl nahrán QMapShack, QMapShack nemusí být schopen nahrát a uložit všechny prvky tohoto souboru. Tyto prvky budou ztraceny. Doporučuje se použít jiný soubor. <b>Opravdu chcete soubor přepsat?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> Stopa <b>%1</b>, kterou jste vybrali, obsahuje body stopy s neplatnými časovými razítky. Zařízení nemusí vytvořený soubor TCX se směrem přijmout, pokud se to tak nechá. <b>Chcete použít filtr se stálou rychlostí (10 m/s) a pokračovat?</b> Course Směr Activity Činnost Cancel Zrušit Track with invalid timestamps... Stopa s neplatnými časovými razítky... Activity or course? Činnost nebo směr? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. QMapShack neví, jak má být stopa <b>%1</b> uložena. <b>Chcete ji uložit jako směr nebo jako činnost? </b> Zapamatujte si, že pouze cestovní body, které jsou dostatečně blízko stopy, budou uloženy, když bude uložena jako směr. Cestovní body nebudou uloženy, když je stopa ukládána jako činnost. Failed to create file '%1' Nepodařilo se vytvořit soubor '%1' Failed to write file '%1' Nepodařilo se zapsat soubor '%1' Saving GIS data failed... Nepodařilo se uložit data GIS... CTemplateWidget choose one... Vybrat jeden... Hiking Tour Summary (built-in) Přehled pěšího výletu (vestavěno) - - Template path... Cesta k předloze... Failed to read template file %1. Nepodařilo se přečíst soubor s předlohou %1. Preview... Náhled... CTextEditWidget &Color... B&arva... Reset format Nastavit formát znovu CToolBarSetupDialog Available Actions Dostupné činnosti Selected Actions Vybrané činnosti CTwoNavProject Error... Chyba... Failed to open %1. Nepodařilo se otevřít %1. Save GIS data to... Uložit data GIS do... Only support lon/lat WGS 84 format. Jako formát je podporován jen lon/lat WGS 84. Failed to read data. Nepodařilo se přečíst data. CWptIconDialog Path to user icons... Cesta k uživatelským značkám... Form Form Formulář Participants Účastníci Weather Počasí rain Déšť sunny Slunečno snow Sněžení clouds Oblačnost windy Větrno hot Horko warm Teplo cold Chladno freezing Mrazivo foggy Mlhavo humid Vlhko Character Povaha easy hiking Snadný pěší výlet climbing Lezení alpine Pěší výlet v horách large ascend Velké stoupání long distance Velká vzdálenost via ferrata Zajištěná cesta hail/soft hail Kroupy/sněhové krupky Rating Hodnocení Rating 5 stars Hodnocení 5 hvězd Rating 4 stars Hodnocení 4 hvězdy Rating 3 stars Hodnocení 3 hvězdy Rating 2 stars Hodnocení 2 hvězdy Rating 1 star Hodnocení 1 hvězda aborted Zrušeno Equipment Vybavení ferrata gear Výstroj pro zajištěnou cestu night gear Noční výstroj snow shoes Sněžnice climbing gear Horolezecká výstroj ski Lyže camping gear Tábornické vybavení Details Podrobnosti IAbout About.... O programu... <b>QMapShack</b>, Version <b>QMapShack</b>, verze TextLabel Textový štítek Qt Qt GDAL GDAL Proj4 Proj4 Routino Routino Czech: Čeština: German: Němčina: Oliver Eichler Oliver Eichler Dutch: Nizozemština: French: Francouzština: Rainer Unseld Rainer Unseld Russian: Ruština: Wolfgang Thämelt Wolfgang Thämelt © 2017 Oliver Eichler (oliver.eichler@gmx.de) © 2017 Oliver Eichler (oliver.eichler@gmx.de) Pavel Fric Pavel Fric <b>Translation:</b> <b>Překlad</b> Harrie Klomp Harrie Klomp Spanish: Španělština: Win64: Win64: OS X: OS X: <b>Binaries:</b> <b>Spustitelné soubory:</b> <b>Contributors:</b> <b>Přispěvatelé</b> Jose Luis Domingo Lopez Jose Luis Domingo Lopez Ivo Kronenberg Ivo Kronenberg Helmut Schmidt Helmut Schmidt ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. ... a poděkování všem tvůrcům spustitelných souborů pro Linux za jejich dobrou práci. Zvláštní poděkování Danovi Horákovi a Basi Couwenbergovi za účast v diskuzi v poštovním seznamu. Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version Tento program je licencován pod GPL3 nebo kteroukoli pozdější verzí ICanvasSetup Setup Map View... Nastavit pohled na mapu... Projection & Datum Promítání a datum ... ... Scales Měřítka Logarithmic Logaritmické Square (optimized for TMS and WMTS tiles) druhá mocnina (vyladěno pro dlaždice TMS a WMTS) IColorChooser Dialog Dialog ICombineTrk Combine Tracks... Spojit stopy... Available Tracks Dostupné stopy ... ... Combined Tracks Spojené stopy ICoordFormatSetup Coordinate Format... Formát souřadnic... N48° 53.660 E013° 31.113 N48° 53.660 E013° 31.113 N48.8943° E013.51855° N48.8943° E013.51855° N48° 53' 39.6" E13° 31' 6.78" N48° 53' 39.6" E13° 31' 6.78" ICreateRouteFromWpt Create Route from Waypoints Vytvořit cestu z cestovních bodů ... ... ICutTrk Cut Track Rozkrojit stopu Delete first part of the track and keep second one Smazat první část stopy a zachovat druhou Keep both parts of the track Zachovat obě části stopy Keep first part of the track and delete second one Zachovat první část stopy a smazat druhou Cut Mode: Režim rozkrojení: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Toto zaškrtněte pro uložení výsledku do nové stopy. Pokud zachováte obě části stopy, musíte vytvořit nové. Pokud chcete zachovat pouze jednu polovinu, můžete jednoduše odstranit body, nebo toto zaškrtnout pro vytvoření nové stopy. Create a new track Vytvořit novou stopu IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Vnitřní formát databáze '%1' se změnil. QMapShack nyní vaši databázi přestěhuje. Po přestěhování databáze se staršími verzemi QMapShack nebude použitelná. Doporučuje se databázi nejprve zazálohovat. Migrate database... Přestěhovat databázi... Migration aborted by user Přestěhování přerušeno uživatelem Failed to migrate '%1'. Nepodařilo se přestěhovat '%1'. Error... Chyba... Migration failed Přestěhování se nepodařilo The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. Verze databáze '%1'je pokročilejší než ta, jíž rozumí vaše instalace QMapShacku. Toto nebude pracovat. Initialization failed Nepodařilo se inicializovat Wrong database version... Nesprávná verze databáze... Database created by newer version of QMapShack Databáze vytvořena novější verzí QMapShack Failed to initialize '%1'. Nepodařilo se inicializovat '%1'. IDBMysql Password... Heslo... Password for database '%1': Heslo pro databázi '%1': Update to database version 5. Migrate all GIS items. Aktualizovat na verzi databáze 5. Přestěhovat všechny položky GIS. IDBSqlite Update to database version 3. Migrate all GIS items. Aktualizovat na verzi databáze 3. Přestěhovat všechny položky GIS. Update to database version 5. Migrate all GIS items. Aktualizovat na verzi databáze 5. Přestěhovat všechny položky GIS. Update to database version 6. Migrate all GIS items. Aktualizovat na verzi databáze 6. Přestěhovat všechny položky GIS. IDemPathSetup Setup DEM file paths Stanovit cesty k souborům s výškovými modely ... ... - - IDemPropSetup Form Formulář <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Změnit neprůhlednost mapy</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klepněte pro použití nynějšího měřítka jako nejmenšího měřítka pro zobrazení mapy.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Je zobrazeno ovládání rozmezí měřítka mapy. Použijte tlačítka vlevo a vpravo pro stanovení skutečného měřítka jako buď nejmenšího nebo největšího měřítka.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klepněte pro použití nynějšího měřítka jako nejmenšího měřítka pro zobrazení mapy.</p></body></html> Hillshading Stínování kopců Slope Sklon ° ° > > TextLabel Textový štítek IDemsList Form Formulář To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Pro přidání souborů s údaji o výšce použijte <b>Soubor → Nastavit cesty k výškovým modelům</b>. Nebo klepněte <a href='setup'><b>sem</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Použijte související nabídku (klepnutí pravým tlačítkem myši na položku) pro zapnutí souboru. Použijte přetažení a upuštění pro posunutí zapnutého souboru v pořadí procesů. Activate Zapnout Move Up Posunout nahoru Hide DEM behind previous one Skrýt výškový model za předchozí Move down Posunout dolů Show DEM on top of next one Výškový model překrývá další Reload DEM Nahrát výškový model znovu IDetailsGeoCache Dialog Dialog - - about:blank o:prázdný Position: Poloha: Difficulty Obtížnost Terrain Území Update spoilers Nahrát spoiler znovu ... ... Hint: Rada: TextLabel Textový štítek IDetailsOvlArea Dialog Dialog The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Oblast byla zavedena do QMapShack a byla změněna. Už více neukazuje původní údaje. Podívejte se, prosím, na záznam změn. Toggle read only mode. You have to open the lock to edit the item. Přepnout režim pouze pro čtení. Musíte otevřít zámek, abyste mohl prvek upravovat. ... ... Color Barva Border width Šířka okraje Style Styl Opacity Neprůhlednost Info Informace Points Body Position Poloha Hist. Hist. IDetailsPrj Form Formulář - - Print diary Tisk deníku ... ... Keep order of project Zachovat pořadí projektu Sort along track (multiple) Řadit podél stopy (vícenásobně) Sort along track (single) Řadit podél stopy (jednorázově) Rebuild diary. Sestavit deník znovu. Keywords: Klíčová slova: IDetailsRte Info Informace The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Cesta byla zavedena do QMapShack a byla změněna. Už více neukazuje původní údaje. Podívejte se, prosím, na záznam změn. - - Toggle read only mode. You have to open the lock to edit the item. Přepnout režim pouze pro čtení. Musíte otevřít zámek, abyste mohl prvek upravovat. ... ... Hist. Hist. IDetailsTrk Form Formulář - - - - Profile Profil Speed Rychlost Toggle read only mode. You have to open the lock to edit the item. Přepnout režim pouze pro čtení. Musíte otevřít zámek, abyste mohl prvek upravovat. ... ... Style Styl Source Zdroj Maximum Nejvyšší hodnota Use/edit user defined visibility of arrows for this track Použít/Upravit uživatelsky stanovenou viditelnost směrových šipek pro tuto stopu Use/edit system's visibility of arrows for all tracks Použít/Upravit v systému stanovenou viditelnost směrových šipek pro všechny stopy Minimum Nejnižší hodnota Use/edit user defined scale factor for this track Použít/Upravit uživatelsky stanovený násobek zvětšení pro tuto stopu Use/edit system's default factor for all tracks Použít/Upravit výchozí násobek zvětšení systému pro všechny stopy x x The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Stopa byla zavedena do QMapShack a byla změněna. Už více neukazuje původní údaje. Podívejte se, prosím, na záznam změn. Width Šířka with arrows se směrovými šipkami Graphs Grafy Activity Činnost Set Track Activity Nastavit činnost stopy To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. K rozlišení statistik stop zvolte v seznamu činnost pro celou stopu. Nebo vyberte část stopy a přiřaďte jí činnost. Points Body Time Čas Ele. Výška Delta Rozdíl Dist. Vzdál. Slope Sklon Position Poloha Info Informace - - max. max. min. min. User defined limits for this track Uživatelsky stanovené hraniční hodnoty pro tuto stopu - - - - - - Automatic limits Automatické hraniční hodnoty User defined limits for all tracks Uživatelsky stanovené hraniční hodnoty pro všechny stopy Color Barva Ascent Stoupání Descent Klesání Filter Filtr Hist. Historie IDetailsWpt Dialog Dialog The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Cestovní bod byl zaveden do QMapShack a byl změněn. Už více neukazuje původní údaje. Podívejte se, prosím, na záznam změn. Toggle read only mode. You have to open the lock to edit the item. Přepnout režim pouze pro čtení. Musíte otevřít zámek, abyste mohl prvek upravovat. ... ... Position: Poloha: Info Informace - - Ele. Výška Proximity: Blízkost: Hist. Historie Add images. Přidat obrázky. Delete selected image. Smazat vybraný obrázek. Date/Time: Datum/Čas: IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. Je jiný projekt se stejným názvem. Pokud stisknete OK, bude odstraněn a nahrazen. IElevationDialog Edit elevation... Upravit výšku... Elevation Výška - - Get elevation from active digital elevation model. Získat výšku z činného digitálního výškového modelu. ... ... IExportDatabase Export database to GPX... Vyvést databázi do GPX... ... ... Export Path: Cesta pro vyvedeni: - - GPX 1.1 without extensions GPX 1.1 bez rozšíření Start Spustit Abort Přerušit Close Zavřít IFilterDelete Form Formulář <b>Remove Track Points</b> <b>Odstranit body stopy</b> Remove all hidden track points permanently. Odstranit trvale všechny skryté body stopy. ... ... IFilterDeleteExtension Form Formulář <b>Remove Extension from all Track Points</b> <b>Odstranit rozšíření ze všech bodů stopy</b> Remove Odstranit from all Track Points ze všech bodů stopy ... ... IFilterDouglasPeuker Form Formulář <b>Hide Points (Douglas Peuker)</b> <b>Skrýt cestovní body (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than Skrýt body stopy, když je vzdálenost k čáře mezi sousedícími body méně než m m Apply filter now. Použít filtr nyní. ... ... IFilterInterpolateElevation Form Formulář <b>Interpolate Elevation Data</b> <b>Interpolovat výšková data</b> Replace elevation of track points with interpolated data. Nahradit výšková data bodů stopy interpolovanými daty. Quality Kvalita Preview Náhled ... ... IFilterInvalid Form Formulář Hide Invalid Points Skrýt neplatné body Hide points with invalid data. Skrýt body s neplatnými daty. ... ... IFilterMedian Form Formulář <b>Smooth Profile (Median Method)</b> <b>Vyhladit profil (Metoda střední hodnoty)</b> Smooth deviation of the track points elevation with a Median filter of size Zmenšit odchylku výšky bodů stopy pomocí filtru střední hodnoty o velikosti points Body ... ... IFilterNewDate Form Formulář <b>Change Time</b> <b>Změnit čas</b> Change start of track to Změnit začáteční čas stopy na dd.MM.yy HH:mm:ss dd.MM.yy HH:mm:ss - - ... ... IFilterObscureDate Form Formulář <b>Obscure Timestamps</b> <b>Zastřít časová razítka</b> Increase timestamp by Zvětšit časové razítko o sec. s with each track point. 0 sec. will remove timestamps. pro každý cestovní bod. 0 s odstraní všechna časová razítka. ... ... IFilterOffsetElevation Form Formulář <b>Offset Elevation</b> <b>Vyrovnat výšku</b> Add offset of Přidat posun to track points elevation. ke každé výšce bodu stopy. ... ... IFilterReplaceElevation Form Formulář <b>Replace Elevation Data</b> <b>Nahradit výšková data</b> Replace elevation of track points with the values from loaded DEM files. Nahradit výšková data bodů stopy daty z nahraných souborů s digitálními výškovými modely. ... ... IFilterReset Form Formulář <b>Reset Hidden Track Points</b> <b>Nastavit znovu skryté body stopy</b> Make all trackpoints visible again. Udělat všechny body stopy znovu viditelnými. ... ... IFilterSpeed Form Formulář <b>Change Speed</b> <b>Změnit rychlost</b> Set speed to Změnit rychlost na km/h km/h ... ... IFilterSplitSegment Form Formulář <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> <html><head/><body><p><span style=" font-weight:600;">Rozdělit části do stop</span></p></body></html> Creates a new track for every segment within this track. Pro každou část v této stopě se vytvoří nová stopa. ... ... IFilterSubPt2Pt Form Formulář <b>Convert track subpoints to points</b> <b>Převést podstopy cesty na body</b> Convert subpoints obtained from routing to ordinary track points Převést podbody obdržené ze stanovení směru cesty na řádné body stopy ... ... IFilterTerrainSlope Form Formulář <b>Calculate Terrain Slope</b> <b>Vypočítat sklon území</b> Calculate slope of the terrain based on loaded DEM files. Vypočítat sklon území z nahraných souborů s digitálními výškovými modely. ... ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. Chyba při dekódování FIT: Nesprávný stav dekodéru %1 po posledním bytu dat v souboru. FIT decoding error: a development field with the field_definition_number %1 already exists. Chyba dekódování FIT: vývojové pole s field_definition_number %1 již existuje. IGisDatabase Form Formulář Name Název Age Věk To add a database do a right click on the database list above. Pro přidání databáze klepněte pravým tlačítkem myši na seznam s databázemi výše. IGisItem [no name] [žádný název] The item is not part of the project in the database. Prvek není částí projektu v databázi. It is either a new item or it has been deleted in the database by someone else. Buď je to nový prvek nebo byl v databázi někým smazán. The item is not in the database. Prvek není v databázi. The item might need to be saved Může být potřeba prvek uložit. Initial version. Počáteční verze. Never ask again. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. <h3>%1</h3> Tento prvek je pravděpodobně pouze pro čtení, protože nebyl vytvořen v programu QMapShack. Obvykle nemáte zájem měnit zavedená data. Ale pokud si myslíte, že je to tentokrát na místě, stiskněte OK. Read Only Mode... Režim pouze pro čtení... <h4>Description:</h4> <h4>Popis:</h4> <p>--- no description ---</p> <p>--- žádný popis ---</p> <h4>Comment:</h4> <h4>Poznámka:</h4> <p>--- no comment ---</p> <p>--- žádná poznámka ---</p> <h4>Links:</h4> <h4>Odkazy:</h4> <p>--- no links ---</p> <p>--- žádné odkazy ---</p> Edit name... Upravit název... Enter new %1 name. Zadat nový název %1. IGisProject Save project? Uložit projekt? <h3>%1</h3>The project was changed. Save before closing it? <h3>%1</h3>Projekt byl změněn. Uložit jej před zavřením? %1: Correlate tracks and waypoints. %1: Svázat stopy a cestovní body. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? <h3>%1</h3>Trvalo to moc dlouho? Chcete svázání stop a cestovních bodů pro tento projekt přeskočit i v budoucnu? Canceled correlation... Svázání zrušeno... Save "%1" to... Uložit "%1" do... <br/> Filename: %1 <br/> Název souboru: %1 Waypoints: %1 Cestovní body: %1 Tracks: %1 Stopy: %1 Routes: %1 Cesty: %1 Areas: %1 Oblasti: %1 Are you sure you want to delete '%1' from project '%2'? Jste si jistý, že chcete smazat '%1' z projektu '%2'? Delete... Smazat... IGisWorkspace Form Formulář Opacity Neprůhlednost Change the opacity of all GIS Items on the map. Změnit neprůhlednost všech položek GIS na mapě. Filter Filtr Name Název Clear Filter Vyprázdnit filtr Setup Filter Nastavit filtr IGridSetup Setup Grid... Nastavení mřížky... Projection Promítání restore default Obnovit výchozí ... ... Get projection from current map. Promítání převzít z nynější mapy. projection wizzard Průvodce pro promítání Grid color Barva mřížky setup grid color Nastavení barvy mřížky IImportDatabase Form Formulář Source Database: Zdrojová databáze: - - ... ... Target Database: Cílová databáze: Start Spustit IInputDialog Edit... Upravit... TextLabel Textový štítek ILineOp Routing Cesta ILinksDialog Links... Odkazy... Type Typ Text Text Uri URI ... ... IMainWindow QMapShack QMapShack File Soubor View Pohled Window Okno ? Nápověda Tool Nástroj Maps Mapy Dig. Elev. Model (DEM) Digitální výškový model Ctrl+T Ctrl+T Show Scale Ukázat měřítko Setup Map Font Nastavit písmo mapy Show Grid Ukázat mřížku Ctrl+G Ctrl+G Setup Grid Nastavit mřížku Ctrl+Alt+G Ctrl+Alt+G Flip Mouse Wheel Obrátit kolečko myši Setup Map Paths Nastavit cesty k mapám POI Text Text POI Night / Day Noc/Den Map Tool Tip Rada k nástroji pro mapu Setup DEM Paths Nastavit cesty k výškovým modelům About O programu Help Nápověda Workspace Toolbar Nástrojový panel Database Databáze Routing Cesta Add Map View Přidat pohled na mapu Ctrl+I Ctrl+I F1 F1 Setup Map View Nastavit pohled na mapu Load GIS Data Nahrát data GIS Load projects from file Nahrát projekty ze souboru Ctrl+L Ctrl+L Save All GIS Data Uložit všechna data GIS Save all projects in the workspace Uložit všechny projekty nacházející se v pracovním prostoru Ctrl+S Ctrl+S Setup Time Zone Nastavit časové pásmo Add empty project Přidat prázdný projekt Search Google Hledat pomocí Google Close all projects Zavřít všechny projekty F8 F8 Setup Units Nastavit jednotky Setup Workspace Nastavit pracovní prostor Setup save on exit. Nastavit uložení při ukončení. Import Database from QLandkarte Zavést databázi z QLandkarte Import QLandkarte GT database Zavést databázi GT QLandkarte VRT Builder Sestavovač VRT GUI front end to gdalbuildvrt Rozhraní pro gdalbuildvrt Store Map View Uložit pohled na mapu Write current active map and DEM list including the properties to a file Zapsat nynější činnou mapu a seznam výškových modelů včetně vlastností do souboru Load Map View Nahrát pohled na mapu Restore view with active map and DEM list including the properties from a file Obnovit pohled s činnou mapou a seznam výškových modelů včetně vlastností ze souboru Ext. Profile Ext. Profil Ctrl+E Ctrl+E Close Zavřít Ctrl+Q Ctrl+Q Clone Map View Klonovat pohled na mapu Ctrl+Shift+T Ctrl+Shift+T Create Routino Database Vytvořit databázi Routino Save(Print) Map Screenshot Uložit (vytisknout) snímek obrazovky s mapou Print a selected area of the map Vytisknout vybranou oblast mapy Ctrl+P Ctrl+P Setup Coord. Format Nastavit formát souřadnic Change the format coordinates are displayed Změnit formát, v němž jsou souřadnice zobrazeny Setup Map Background Nastavit pozadí mapy Setup Waypoint Icons Stanovit ikony cestovních bodů Setup path to custom icons Stanovit cestu k vlastním ikonám Close Tab Zavřít kartu Ctrl+W Ctrl+W Quickstart Help Nápověda pro rychlý začátek Setup Toolbar Nastavit nástrojový panel Toggle Docks Přepnout panely Toggle visibility of dockable windows Přepnout viditelnost ukotvitelných oken Ctrl+D Ctrl+D Full Screen Celá obrazovka F11 F11 Min./Max. Track Values Show the minimum and maximum values of the track properties along the track in the map view. Ctrl+N IMapList Form Formulář To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Pro přidání map použijte <b>Soubor → Nastavit cesty k mapám</b>. Nebo klepněte <a href='setup'><b>sem</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Použijte související nabídku (klepnutí pravým tlačítkem myši na položku) pro zapnutí mapy. Použijte přetažení a upuštění pro posunutí zapnuté mapy v pořadí kreslení. Help! I want maps! I don't want to read the documentation! Pomoc! Chci mapy! Nechce se mi číst dokumentaci! Activate Zapnout Move Up Posunout nahoru Hide map behind previous map Skrýt mapu za předchozí mapou Move down Posunout dolů Show map on top of next map Mapa překrývá další Reload Maps Nahrát mapy znovu IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Tato mapa vyžaduje podporu pro OpenSSL. Nicméně kvůli právním omezením v některých zemích není OpenSSL k QMapShack přibaleno. Můžete se podívat na <a href='https://www.openssl.org/community/binaries.html'>stránky OpenSSL</a>, kde najdete spustitelné soubory. Musíte zkopírovat libeay32.dll a ssleay32.dll do adresáře s programem QMapShack. Error... Chyba... <b>%1</b>: %2 tiles pending<br/> <b>%1</b>: %2 dlaždic čeká<br/> IMapPathSetup Setup map paths Nastavit cesty k mapám Root path of tile cache for online maps: Kořenová cesta (root) vyrovnávací paměti dlaždic pro internetové mapy: ... ... Help! I want maps! I don't want to read the documentation! Pomoc! Chci mapy! Nechce se mi číst dokumentaci! - - IMapPropSetup Form Formulář <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Změnit neprůhlednost mapy</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> <html><head/><body><p>Klepněte pro použití nynějšího měřítka jako nejmenšího měřítka pro zobrazení mapy.</p></body></html> ... ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Je zobrazeno ovládání rozmezí měřítka mapy. Použijte tlačítka vlevo a vpravo pro stanovení skutečného měřítka jako buď nejmenšího nebo největšího měřítka.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> <html><head/><body><p>Klepněte pro použití nynějšího měřítka jako nejmenšího měřítka pro zobrazení mapy.</p></body></html> Areas Oblasti Lines Čáry Points Body Details Podrobnosti - - Cache Path Cesta k vyrovnávací paměti Type File: Typ souboru: Forget external type file and use internal types. Zapomenout na vnější souborový typ a použít vnitřní typy. Load an external type file. Nahrát vnější typ souboru. Cache Size (MB) Velikost vyrovnávací paměti (MB) Expiration (Days) Datum vypršení (dny) IMapVrtBuilder Form Formulář Advanced Options Pokročilé volby Source No Data (-srcnodata) Zdroj, žádná data (-srcnodata) Target No Data (-vrtnodata) Cíl, žádná data (-vrtnodata) Target Projection (-a_srs) Cíl, promítání (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. Tyto volby jsou pro určité případy a obyčejně je chcete ponechat prázdné. Podívejte se na GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Nápověda</a> pro další informace. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> ... ... Select source files: Vybrat zdrojové soubory: Target Filename: Název cílového souboru: - - Start Spustit IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Nová čára</b><br/>Posuňte ukazovátko myši a použijte levé tlačítko myši k upuštění bodů. Až to bude uděláno, použijte pravé tlačítko myši k zastavení.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Smazat bod</b><br/>Přesuňte ukazovátko myši blízko k bodu a stiskněte levé tlačítko myši pro jeho smazání.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Upravit rozsah bodů</b><br/>Klepněte levým tlačítkem myši na první bod pro započetí výběru. Klepněte levým tlačítkem myši na druhý bod pro dokončení výběru a vyberte z voleb. Použijte pravé tlačítko myši pro zrušení.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Přesunout bod</b><br/>Přesuňte ukazovátko myši blízko k bodu a stiskněte levé tlačítko myši pro jeho držení v blízkosti ukazovátka. Posuňte myší pro přesunutí bodu. Upustěte bod klepnutím levým tlačítkem myši. Použijte pravé tlačítko myši pro zrušení.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Přidat bod</b><br/>Přesuňte ukazovátko myši blízko k čáře a stiskněte levé tlačítko myši pro přidání bodu. Bod přilne k ukazovátku a vy jím budete moci pohnout. Bod upustěte klepnutím levým tlačítkem myši. Použijte pravé tlačítko myši pro zrušení.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Žádné stanovení cesty</b><br/>Všechny body budou spojeny přímou čarou.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Automatické stanovení cesty</b><br/>Nynější nastavení směrování je používáno k vytváření cesty mezi body. <b>Poznámka:</b> Vybraný směrovač musí být schopen rychle směrovat (za běhu). Směrovače nepřipojené k internetu toto obvykle dokáží, směrovače připojené k internetu to běžně neumí.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>Vektorové stanovení cesty</b><br/>Spojuje body čárou z nahrané vektorové mapy, je-li to možné.<br/> <b>%1 Metrics</b> <b>%1 metrika</b> Distance: Vzdálenost: Ascent: Stoupání: Descent: Klesání: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> <br/><b>Posunout mapu</b><br/>Pokud levé tlačítko myši podržíte stisknuté a myší pohnete, posunete mapu.<br/><br/> IPhotoAlbum Form Formulář ... ... IPlot Reset Zoom Nastavit znovu zvětšení Stop Range Ukončit výběr oblasti Save... Uložit... Add Waypoint Přidat cestovní bod Cut... Vyjmout... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. Pro (pouze) svislé přiblížení podržte klávesu Ctrl. Pro (pouze) vodorovné přiblížení podržte klávesu Alt. No or bad data. Žádná nebo špatná data. Select output file Vybrat výstupní soubor IPositionDialog Position ... Poloha... Enter new position Zadat novou polohu Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Špatný polohový formát. Musí být: "[N|S] ddd mm.sss [W|E] ddd mm.sss" nebo "[N|S] ddd.ddd [W|E] ddd.ddd" IPrintDialog Print map... Tisk mapy... When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. Když tisknete výřez internetové mapy, ujistěte se, že mapa byla nahrána do vyrovnávací paměti. Save Uložit When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. Když ukládáte výřez internetové mapy, ujistěte se, že mapa byla nahrána do vyrovnávací paměti. TextLabel Textový štítek Print Tisk IProgressDialog Please wait... Počkejte, prosím... TextLabel Textový štítek IProjWizard Proj4 Wizzard Průvodce pro Proj4 Mercator Mercatorovo zobrazení UTM UTM zone Pásmo user defined Stanoveno uživatelem Datum Datum World Mercator (OSM) Světový Mercator (OSM) Result: Výsledek: UPS North (North Pole) UPS Sever (Severní pól) UPS South (South Pole) UPS Jih (Jižní pól) Projection Promítání IProjWpt Waypoint Projection Promítnutí cestovního bodu ... ... - - Clone waypoint and move by: Klonovat cestovní bod a posunout o: m m ° ° IRouterBRouter Form Formulář Profile Profil Alternative Náhradní display selected routing profile Zobrazit vybraný profil stanovení cesty ... ... on-the-fly routing Stanovení cesty za běhu BRouter: BRouter: not running Neběží start/stop BRouter Spustit/Zastavit BRouter show BRouter console Ukázat konzoli BRouter Setup Nastavit Caution! BRouter is listening on all ports for connections. Pozor! BRouter kvůli připojení naslouchá na všech přípojkách (port). <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> IRouterBRouterInfo BRouter Profile Profil BRouter TextLabel Textový štítek IRouterBRouterSetupWizard BRouter Setup Nastavení BRouter choose which BRouter to use Vybrat, který BRouter použít BRouter-Web (online) Stránky BRouter (připojeno) local Installation Místní instalace Expert Mode Režim znalce local BRouter Installation directory: Místní instalační adresář BRouter: select installation directory Vybrat instalační adresář ... ... labelLocalDirResult create or update installation Vytvořit nebo aktualizovat instalaci Java Executable Spustitelný soubor Java labelLocalJavaResult search for installed java Hledat nainstalovanou Javu Download and install BRouter Version Stáhnout a nainstalovat verzi BRouter about:blank o:prázdný File to install Soubor k nainstalování Download and Install Stáhnout a nainstalovat available Profiles Dostupné profily install profile Instalovat profil remove profile Odstranit profil installed Profiles Nainstalované profily content of profile Obsah profilu BRouter-Web URL: Adresa (URL) stránek BRouter: Service-URL Adresa (URL) služby Profile-URL Adresa (URL) profilu Hostname Jméno hostitelského počítače Port Přípojka (port) Profile directory Adresář s profilem Segments directory Adresář s částmi Custom Profiles dir Adresář s vlastními profily Max Runtime Nejdelší doba běhu programu Number Threads Počet vláken Java Options Volby pro Java Profiles Url Adresa (URL) profilu IRouterMapQuest Form Formulář Highways Rychlostní silnice Seasonal Sezonní silnice Language Jazyk Country Border Zemské hranice Profile Profil Avoid: Vyhnout se: Ferry Přívoz Toll Road Silnice s mýtem Unpaved Nezpevněné silnice <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> <p>S přátelským povolením od <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Formulář Profile Profil Mode Režim Database Databáze Add paths with Routino database. Přidat cestu pomocí databáze Routino. ... ... Language Jazyk To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Pro použití stanovení cesty bez připojení k internetu je potřeba stanovit cesty k místním datům se stanovením cest. Použijte nástrojové tlačítko pro nastavení k zaregistrování cesty. Svá vlastní data se stanovením cest vytvoříte pomocí <b>Nástroj → Vytvořit databázi Routino</b>. IRouterRoutinoPathSetup Setup Routino database... Nastavit databázi Routino... ... ... - - IRouterSetup Form Formulář IRoutinoDatabaseBuilder Form Formulář ... ... Select source files: Vybrat zdrojové soubory: Start Spustit Target Path: Cílová cesta: - - File Prefix Předpona souboru <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> IScrOptEditLine Form Formulář Save to original Uložit do předlohy Save as new Uložit jako nový Abort Přerušit Move points. (Ctrl+M) Přesunout body. (Ctrl+M) Ctrl+M Ctrl+M Add new points. (Ctrl++) Přidat nové body. (Ctrl++) Ctrl++ Ctrl++ Select a range of points. (Ctrl+R) Vybrat rozsah bodů. (Ctrl+R) Ctrl+R Ctrl+R No auto-routing or line snapping (Ctrl+O) Žádné automatické stanovení cesty nebo přichycení k čáře (Ctrl+O) Ctrl+O Ctrl+O Use auto-routing to between points. (Ctrl+A) Použít automatické stanovení cesty mezi body. (Ctrl+A) Ctrl+A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) Přichytit čáru podél čáry vektorové mapy. (Ctrl+V) ... ... Delete a point. (Ctrl+-) Smazat bod. (Ctrl+-) Ctrl+- Ctrl+- 0 0 A A V V Ctrl+V Ctrl+V Undo last change Vrátit poslední změnu zpět Redo last change Obnovit poslední změnu IScrOptOvlArea Form Formulář View details and edit. Zobrazit podrobnosti a upravit. ... ... Copy area into another project. Kopírovat oblast do dalšího projektu. Delete area from project. Smazat oblast z projektu. Edit shape of the area. Upravit tvar oblasti. TextLabel Textový štítek IScrOptPrint Form Formulář Save selected area as image. Uložit vybranou oblast jako obrázek. ... ... Print selected area. Tisk vybrané oblasti. IScrOptRangeLine Form Formulář Delete all points between the first and last one. Smazat všechny body mezi prvním a posledním bodem. ... ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> <html><head/><body><p>Spočítat cestu mezi prvním a posledním vybraným bodem.</p></body></html> IScrOptRangeTrk Form Formulář Hide all points. Skrýt všechny body. ... ... Show all points. Ukázat všechny body. Set an activity for the selected range. Nastavit činnost pro vybraný rozsah. Copy track points as new track. Kopírovat body stopy jako novou stopu. TextLabel Textový štítek IScrOptRte Form Formulář ... ... Copy route into another project. Kopírovat cestu do dalšího projektu. View details and edit. Zobrazit podrobnosti a upravit. Delete route from project. Smazat cestu z projektu. Calculate route. Spočítat cestu. Reset route calculation. Vynulovat spočítání cesty. Move route points. Přesunout body cesty. Convert route to track Převést cestu na stopu TextLabel Textový štítek IScrOptSelect Form Formulář Copy all selected items to a project. Kopírovat všechny vybrané prvky do projektu. ... ... Create a route from selected waypoints. Vytvořit cestu z vybraných cestovních bodů. Change the icon of all selected waypoints. Změnit ikonu všech vybraných cestovních bodů. Combine all selected tracks to a new one. Spojit všechny vybrané stopy do nové. Set an activity for all selected tracks. Nastavit činnost pro všechny vybrané stopy. Delete all selected items. Smazat všechny vybrané prvky. Select all items that intersect the selected area. Vybrat všechny prvky, které protínají vybranou oblast. Select all items that are completely inside the selected area. Vybrat všechny prvky, které jsou úplně uvnitř vybrané oblasti. Add tracks to selection. Přidat stopy do výběru. Add waypoints to selection. Přidat cestovní body do výběru. Add routes to selection. Přidat cesty do výběru. Add areas to selection. Přidat oblasti do výběru. IScrOptTrk Form Formulář Copy track into another project. Kopírovat stopu do dalšího projektu. Show on-screen profile and detailed information about points. Ukázat promítnutý profil a podrobné údaje o bodech. Edit position of track points. Upravit polohu bodů stopy. View details and edit properties of track. Zobrazit podrobnosti a upravit vlastnosti stopy. Delete track from project. Smazat stopu z projektu. Select a range of points. Vybrat rozsah bodů. Reverse track. Obrátit stopu. Combine tracks. Spojit stopy. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Rozkrojit stopu na vybraném bodu. Můžete to použít na: * odstranění špatných bodů na začátku nebo na konci stopy * použití částí stopy k plánování nového výletu * vyjmutí dlouhé stopy do úseků Copy track together with all attached waypoints into another project. Kopírovat stopu společně se všemi připojenými cestovními body do jiného projektu. ... ... Set an activity for the complete track. Nastavit činnost pro celou stopu. TextLabel Textový štítek IScrOptWpt Form Formulář View details and edit. Zobrazit podrobnosti a upravit. ... ... Copy waypoint into another project. Kopírovat cestovní bod do dalšího projektu. Delete waypoint from project. Smazat cestovní bod z projektu. Show content as static bubble. Ukázat obsah stálé vysvětlivky. Move waypoint to a new location. Přesunout cestovní bod do nového umístění. Clone waypoint and move clone a given distance and angle. Klonovat cestovní bod a kopii přesunout o danou vzdálenost a ve stanoveném úhlu. edit radius of circular area Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel Textový štítek IScrOptWptRadius Form Formulář edit radius of circular area ... ... Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel Textový štítek ISearchDatabase Search... Hledat... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Napište slovo, které se má hledat, a stiskněte tlačítko pro hledání. Pokud zadáte 'slovo', provede se hledání přesné shody. Pokud zadáte 'slovo*', 'slovo' musí být na začátku řetězce. Name Název Search Hledat Close Zavřít ISelDevices Select devices... Vybrat zařízení... ISelectActivityColor Form Formulář ISelectCopyAction Copy item... Kopírovat prvek... Replace existing item Nahradit stávající prvek TextLabel Textový štítek Do not copy item Nekopírovat prvek Create a clone Vytvořit klon Replace with: Nahradit: Keep item: Zachovat prvek: The clone's name will be appended with '_Clone' Název klonu bude rozšířen o '_Klon' And for all other items, too. A také pro všechny další prvky. ISelectDBFolder Select Parent Folder... Vybrat nadřazenou složku... Name Název ISelectDoubleListWidget Form Formulář Available Dostupné Add to selected items Přidat k vybraným prvkům Remove from selected items Odstranit z vybraných prvků Selected Vybrané Move selected items up Posunout vybrané prvky nahoru Move selected items down Posunout vybrané prvky dolů ... ... ISelectProjectDialog Select a project... Vybrat projekt... Select project from list or enter new project name. Vybrat projekt ze seznamu nebo zadat nový název projektu. New project's name Nový název projektu New project is created as: Nový projekt je vytvořen jako: *.qms *.qms *.gpx *.gpx Database Databáze ISelectSaveAction Copy item... Kopírovat prvek... Replace existing item Nahradit stávající prvek Add a clone Přidat klona The clone's name will be appended with '_Clone' Název klonu bude rozšířen o '_Klon' Replace with: Nahradit: TextLabel Textový štítek Do not replace item Nenahrazovat prvek Use item: Použít prvek: And for all other items, too. A také pro všechny další prvky. ISetupDatabase Add database... Přidat databázi... - - Name Název <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <p align="justify"><span style=" font-weight:600;">Pozor!</span> Doporučuje se ponechat heslo prázdné, neboť QMapShack je uloží jako prostý text. Pokud heslo nezadáte, budete na ně dotazován při každém spuštění programu.</p> Do not use a password. Nepoužívat heslo. SQLite SQLite MySQL MySQL Server Server Port Přípojka 00000 00000 User Uživatel Password Heslo <b>Port:</b> Leave the port field empty to use the default port. <b>Přípojka:</b> Pro používání výchozí přípojky ponechejte pole s číslem přípojky prázdné. File: Soubor: Add new database. Přidat novou databázi. ... ... Open existing database. Otevřít stávající databázi. ISetupFilter Form Formulář Apply filter to Použít filtr na name only pouze název complete text celý text ISetupFolder Database Folder... Složka s databází... Folder name Název složky Group Skupina Project Projekt Other Jiné ISetupNewWpt New Waypoint... Nový cestovní bod... Symbol Značka ... ... Position Poloha Name Název Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Špatný polohový formát. Musí být: "[N|S] ddd mm.sss [W|E] ddd mm.sss" nebo "[N|S] ddd.ddd [W|E] ddd.ddd" ISetupWorkspace Setup workspace... Nastavit pracovní prostor... save workspace on exit, and every Uložit pracovní prostor při ukončení, a každých minutes minut listen for database changes from other instances of QMapShack. On port Naslouchat změnám v databázi jiných instancí QMapShack. Na přípojce 00000 00000 ITemplateWidget Insert Template... Vložit předlohu... Templates Předlohy Select a path with your own templates. Vybrat cestu s vašimi vlastními předlohami. ... ... Preview Náhled ITextEditWidget Edit text... Upravit text... Undo Zpět Ctrl+Z Ctrl+Z Redo Znovu Ctrl+Shift+Z Ctrl+Shift+Z Cut Vyjmout Ctrl+X Ctrl+X Copy Kopírovat Ctrl+C Ctrl+C Paste Vložit Templ. Předloha A:L A:L A:C A:C A:R A:R A:B A:B B B I I U U C C Standard Standardní Bullet List (Disc) Seznam kulatých odrážek (kotouč) Bullet List (Circle) Seznam kulatých odrážek (kroužek) Bullet List (Square) Seznam kulatých odrážek (čtvereček) Ordered List (Decimal) Uspořádaný seznam (desetinný) Ordered List (Alpha lower) Uspořádaný seznam (abecední dolní) Ordered List (Alpha upper) Uspořádaný seznam (abecední horní) Ordered List (Roman lower) Uspořádaný seznam (antikva dolní) Ordered List (Roman upper) Uspořádaný seznam (antikva horní) Ctrl+V Ctrl+V Align Left Zarovnat vlevo Ctrl+L Ctrl+L Align Right Zarovnat vpravo Ctrl+R Ctrl+R Align Center Zarovnat na střed Ctrl+E Ctrl+E Align Block Zarovnat do bloku Ctrl+J Ctrl+J Underline Podtržení Ctrl+U Ctrl+U Bold Tučné Ctrl+B Ctrl+B Italic Kurzíva Ctrl+I Ctrl+I Plain Prostý Reset the text's format before pasting Nastavit znovu formát textu před vložením Select All Vybrat vše Ctrl+A Ctrl+A Delete Smazat Reset Font Nastavit písmo znovu Reset Layout Nastavit rozvržení znovu Normal Normální Paste without resetting the text's format Vložit bez znovunastavení formátu textu Insert From Template Vložit z předlohy Create text from template. Vytvořit text z předlohy. ITextEditWidgetSelMenu B B I I U U Cut Vyjmout Copy Kopírovat Paste Vložit ITimeZoneSetup Setup Time Zone ... Nastavit časové pásmo... UTC Světový čas (UTC) Local Místní Automatic Automaticky Print date/time in Datum/Čas v long format, or dlouhém formátu nebo short format v krátkém formátu <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Poznámka:</b> Některé prvky uživatelského rozhraní změna jednotek neovlivní, dokud QMapShack nespustíte znovu. IToolBarSetupDialog Setup Toolbar Nastavit nástrojový panel Toolbar is visible in Fullscreen-mode Nástrojový panel je viditelný v režimu celé obrazovky IToolShell Execution of external program `%1` failed: Nepodařilo se spustit vnější program `%1`: Process cannot be started. Proces nelze spustit. Make sure the required packages are installed, `%1` exists and is executable. Ujistěte se, že jsou nainstalovány požadované balíčky, že `%1` existuje a je spustitelný. External process crashed. Vnější proces spadl. An unknown error occurred. Vyskytla se neznámá chyba. !!! failed !!! Nepodařilo se! IUnit Error Chyba Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Špatný polohový formát. Musí být: "[N|S] ddd mm.sss [W|E] ddd mm.sss" nebo "[N|S] ddd.ddd [W|E] ddd.ddd" Position values out of bounds. Polohy mimo platné hodnoty. IUnitsSetup Setup units... Nastavit jednotky... Length unit Metric Metrické Slope unit Degrees (°) Percent (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. <b>Poznámka:</b> Některé prvky uživatelského rozhraní změna jednotek neovlivní, dokud QMapShack nespustíte znovu. Imperial Anglické Nautic Nautické IWptIconDialog Icons... Ikony... External Icons: Vnější značky: - - ... ... All custom icons have to be *.bmp or *.png format. Všechny vlastní značky musí být ve formátu *.bmp nebo *.png. qmapshack-1.10.0/src/locale/qmapshack_cs.desktop000644 001750 000144 00000000112 13022456074 022775 0ustar00oeichlerxusers000000 000000 #Translations Name[cs]=QMapShack GenericName[cs]=Data GPS - a správa map qmapshack-1.10.0/src/locale/qmapshack.ts000644 001750 000144 00001440636 13216421215 021303 0ustar00oeichlerxusers000000 000000 CAbout %1 (API V%2, expected V%3) %1 (API V%2) (no DBUS: device detection and handling disabled) CActivityTrk Foot Bicycle Motor Bike Car Cable Car Swim Ship Ski/Winter No Activity Total Ascent: Descent: Aeronautics Public Transport Distance: Speed Moving: Speed Total: Time Moving: Time Total: CCanvas View %1 Setup Map Background CColorChooser Esc. CCommandProcessor Print debug output to console. Print debug output to logfile (temp. path). Do not show splash screen. File with QMapShack configuration. file Files for future use. CCreateRouteFromWpt route CDBFolderLostFound All your data grouped by folders. Lost & Found (%1) Lost & Found CDBFolderMysql All your data grouped by folders. MySQL Database Server: (No PW) Error: CDBFolderSqlite All your data grouped by folders. SQLite Database File: Error: CDBItem %1 min. %1 h %1 days CDBProject Failed to load... Can't load file "%1" . It will be skipped. Project already in database... The project "%1" has already been imported into the database. It will be skipped. The item %1 has been changed by %2 (%3). To solve this conflict you can create and save a clone, force your version or drop your version and take the one from the database Conflict with database... Clone && Save Force Save Take remote Missing folder... Failed to save project. The folder has been deleted in the database. Save ... Error There was an unexpected database error: %1 The project '%1' is about to update itself from the database. However there are changes not saved. Save changes? CDemList Deactivate Activate CDemPathSetup Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1 Select DEM file path... CDemVRT Error... Failed to load file: %1 DEM must have one band with 16bit or 32bit data. No georeference information found. CDetailsGeoCache none ??? Searching for images... No images found CDetailsPrj You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again? Correlation... none Build diary... <b>Summary over all tracks in project</b><br/> <h2>Waypoints</h2> Info Comment <h2>Tracks</h2> From Start To Next To End Distance: Ascent: Descent: <h2>Areas</h2> <h2>Routes</h2> Edit name... Enter new project name. Edit keywords... Enter keywords. Print Diary CDetailsTrk Reduce visible track points Change elevation of track points Change timestamp of track points Miscellaneous Color Activity CDetailsWpt Enter new proximity range. CDeviceGarmin Picture%1 Unknown CDeviceGarminArchive Archive - expand to load Archive - loaded CElevationDialog No DEM data found for that point. CExportDatabase Select export path... CExportDatabaseThread Create %1 Failed to create %1 Done! Abort by user! Database Error: %1 Save project as %1 Failed! CFilterDeleteExtension No extension available CFilterInterpolateElevation coarse medium fine CFitCrcState FIT decoding error : invalid CRC. CFitDecoder FIT decoding error: unexpected end of file %1. CFitFieldBuilder FIT decoding error: unknown base type %1. CFitFieldDataState Missing field definition for development field. FIT decoding error: invalid field def nr %1 while creating dev field profile. CFitHeaderState FIT decoding error: protocol %1 version not supported. FIT decoding error: file header signature mismatch. File is not FIT. CFitProject Failed to load file %1... Failed to open FIT file %1. CFitRecordContentState FIT decoding error: architecture %1 not supported. FIT decoding error: invalid offset %1 for state 'record content' CGarminTyp Warning... This is a typ file with unknown polygon encoding. Please report! This is a typ file with unknown polyline encoding. Please report! CGisItemOvlArea thin normal wide strong _Clone Area: %1%2 Changed area shape. Changed name. Changed border width. Changed fill pattern. Changed opacity. Changed comment. Changed description. Changed links Changed color CGisItemRte _Clone track Changed name. Changed comment Changed description Changed links Length: %1%2 Time: %1%2 Distance: %1%2 Length: - Time: - %1%2 %3, %4%5 %6 Last time routed:<br/>%1 with %1 Changed route points. CGisItemTrk FIT file %1 contains no GPS data. Error... Failed to open %1. Only support lon/lat WGS 84 format. Failed to read data. _Clone Changed trackpoints, sacrificed all previous data. , %1-, %2- Time: %1%2, Speed: %3%4 Time: -, Speed: - Moving: %1%2, Speed: %3%4 Moving: -, Speed: - Start: %1 Start: - End: %1 End: - Points: %1 (%2) Invalid elevations! Invalid timestamps! Invalid positions! Activities: %1 Index: %1 Index: visible %1, total %2 , Slope: %1%2 ... and %1 tags not displayed Distance: - (-) Moving: - (-) track Hide point %1. Hide points %1..%2. , %1%2 Invalid points.... The track '%1' has %2 invalid points out of %3 visible points. Do you want to hide invalid points now? min. max. Length: %1%2 , %1%2%3, %4%5%6 Ele.: %1%2 , Speed: %1%2 Ascent: - (-) Descent: - (-) Ascent: %1%2 (%3%) , Descent: %1%2 (%3%) Distance: %1%2 (%3%) , Moving: %1%2 (%3%) Ascent: - Descent: - Ascent: %1%2 , Descent: %1%2 Distance: %1%2 , Time: %1%2 Permanently removed points %1..%2 Show points. Changed name Changed comment Changed description Changed links Changed elevation of point %1 to %2 %3 Changed activity to '%1' for complete track. Changed activity to '%1' for range(%2..%3). Hide points by Douglas Peuker algorithm (%1%2) Hide points with invalid data. Reset all hidden track points to visible Permanently removed all hidden track points Smoothed profile with a Median filter of size %1 Added terrain slope from DEM file. Replaced elevation data with data from DEM files. Replaced elevation data with interpolated values. (M=%1, RMSErr=%2) Offset elevation data by %1%2. Changed start of track to %1. Remove timestamps. Set artificial timestamps with delta of %1 sec. Changed speed to %1%2. %1 (Segment %2) Removed extension %1 from all Track Points Converted subpoints from routing to track points Copy flag information from QLandkarte GT track CGisItemWpt Archived Available Not Available _Clone Elevation: %1%2 Proximity: %1%2 Changed name Changed position Changed elevation Removed proximity Changed proximity Changed icon Changed comment Changed description Changed links Changed images Add image Changed to proximity-radius Changed to nogo-area CGisListDB Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step. Select database file. Add Database Add Folder Rename Folder Copy Folder Move Folder Delete Folder Import from Files... Export to GPX... Delete Item Search Database Sync. with Database Remove Database Empty Remove database... Do you really want to remove '%1' from the list? Delete database folder... Are you sure you want to delete selected folders and all subfolders from the database? Bad operation.... The target folder is a subfolder of the one to move. This will not work. Folder name... Rename folder: Remove items... Are you sure you want to delete all items from Lost&Found? This will remove them permanently. Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently. Are you sure you want to delete '%1' from folder '%2'? Delete... Import GIS Data... CGisListWks Edit.. Show on Map Hide from Map Sort by Time Sort by Name Save Save as GPX 1.1 w/o ext... Send to Devices Sync. with Database Close Update Project on Device Delete Edit... Copy to... Autom. Save Save as... Track Profile Select Range Edit Track Points Reverse Track Combine Tracks Copy Track with Waypoints Show Bubble Move Waypoint Proj. Waypoint... Change Radius Toggle Nogo-Area Delete Radius Route Instructions Calculate Route Reset Route Edit Route Convert to Track Edit Area Points Create Route Change Icon (sel. waypt. only) Set Track Activity Drop items... <b>Update devices</b><p>Update %1<br/>Please wait...</p> Saving workspace. Please wait. Loading workspace. Please wait. Close all projects... This will remove all projects from the workspace. Delete project... Do you really want to delete %1? CGisWorkspace Load project... The project "%1" is already in the workspace. <b>Item Selection: </b>Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior. Copy items... Change waypoint symbols. Cut Track... Do you want to delete the original track? CGpxProject Failed to load file %1... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Not a GPX file: %1 File exists ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> Failed to create file '%1' Failed to write file '%1' Saving GIS data failed... CGrid %1 %2 %1%2%5 %3%4%5 %1m, %2m N %1m, E %2m CHistoryListWidget by %1 Cut history before Cut history after History removal The removal is permanent and cannot be undone. <b>Do you really want to delete history before this step?</b> CImportDatabase Import QLandkarte Database Select source database... Select target database... CKnownExtension Speed extLongName Cadence extShortName Air Temp. extShortName Air Temperature extLongName Water Temp. extShortName Water Temperature extLongName Depth extShortName Depth extLongName Heart R. extShortName Heart Rate extLongName Cadence extLongName Speed extShortName Accel. extShortName Acceleration extLongName Course extShortName Course extLongName Temp. extShortName Temperature extLongName Dist. extShortName Distance extLongName Ele. extShortName Elevation extLongName Energy extShortName Energy extLongName Sea Lev. Pres. extShortName Sea Level Pressure extLongName v. Speed extShortName Vertical Speed extLongName Slope extShortName Speed over Distance* extLongName Speed over Time* extLongName Elevation* extLongName Progress extShortName Progress* extLongName Terr. Slope extShortName Terrain Slope* extLongName Slope* CLogProject Failed to load file %1... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Not an Openambit log file: %1 Device: %1<br/> Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This LOG file does not contain any position data and can not be displayed by QMapShack: %1 CLostFoundProject Lost & Found CMainWindow Use <b>Menu->View->Add Map View</b> to open a new view. Or <b>Menu->File->Load Map View</b> to restore a saved one. Or click <a href='newview'>here</a>. Ele.: %1%2 Slope: %1%2 terrain [Grid: %1] Load GIS Data... Select output file QMapShack View (*.view) Select file to load Fatal... QMapShack detected a badly installed Proj4 library. The translation tables for EPSG projections usually stored in /usr/share/proj are missing. Please contact the package maintainer of your distribution to fix it. CMapDraw There are no maps right now. QMapShack is no fun without maps. You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. If it's no fun, why don't you provide maps? Well to host maps ready for download and installation requires a good server. And this is not a free service. The project lacks the money. Additionally map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package the data. This is not that easy as it might sound and for some data you have to pay royalties. The project simply lacks resources to do this. And we think installing the stuff yourself is not that much to ask from you. After all the software is distributed without a fee. CMapIMG Failed ... Unspecified French German Dutch English Italian Finnish Swedish Spanish Basque Catalan Galician Welsh Gaelic Danish Norwegian Portuguese Slovak Czech Croatian Hungarian Polish Turkish Greek Slovenian Russian Estonian Latvian Romanian Albanian Bosnian Lithuanian Serbian Macedonian Bulgarian Major highway Principal highway Other highway Arterial road Collector road Residential street Alley/Private road Highway ramp, low speed Highway ramp, high speed Unpaved road Major highway connector Roundabout Railroad Shoreline Trail Stream Time zone Ferry State/province border County/parish border International border River Minor land contour Intermediate land contour Major land contour Minor depth contour Intermediate depth contour Major depth contour Intermittent stream Airport runway Pipeline Powerline Marine boundary Hazard boundary Large urban area (&gt;200K) Small urban area (&lt;200K) Rural housing area Military base Parking lot Parking garage Airport Shopping center Marina University/College Hospital Industrial complex Reservation Man-made area Sports complex Golf course Cemetery National park City park State park Forest Ocean Blue (unknown) Sea Large lake Medium lake Small lake Major lake Major River Large River Medium River Small River Intermittent water Wetland/Swamp Glacier Orchard/Plantation Scrub Tundra Flat ??? Read external type file... Failed to read type file: %1 Fall back to internal types. Failed to read: Failed to open: Bad file format: Failed to read file structure: Loading %1 User abort: File is NT format. QMapShack is unable to read map files with NT format: File contains locked / encrypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin. Point of Interest Unknown Area CMapList Deactivate Activate Where do you want to store maps? CMapMAP Failed ... Failed to open: Bad file format: CMapPathSetup Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1 Select map path... Select root path... CMapPropSetup Select type file... CMapRMAP Error... This is not a TwoNav RMAP file. Unknown sub-format. Unknown version. Failed to read reference point. Unknown projection and datum (%1%2). CMapTMS Error... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Layer %1 CMapVRT Error... Failed to load file: %1 File must be 8 bit palette or gray indexed. No georeference information found. CMapVrtBuilder Build GDAL VRT Select files... Select target file... !!! done !!! CMapWMTS Error... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Failed to read: %1 Unknown structure. Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read. No georeference information found. CMouseEditArea Area <b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> area CMouseEditRte Route <b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> route CMouseEditTrk Track <b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/> Warning! This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently. track CMouseNormal Add POI as Waypoint Add Waypoint Add Track Add Route Add Area Select Items On Map Copy position Copy position (Grid) CMousePrint <b>Save(Print) Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. CMouseRangeTrk <b>Select Range</b><br/>Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.<br/> CMouseSelect <b>Select Items On Map</b><br/>Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners. <b>Selected:</b><br/> %1 waypoints<br/> %1 tracks<br/> %1 routes<br/> %1 areas<br/> CPhotoAlbum Select images... CPlot Distance [%1] Time CPlotProfile Distance [%1] Ele. [%1] CPrintDialog Print Map... Save Map as Image... Printer Properties... Pages: %1 x %2 Zoom with mouse wheel on map below to change resolution: %1x%2 pixel x: %3 m/px y: %4 m/px Printing pages. Save map... CProgressDialog Elapsed time: %1 Elapsed time: %1 seconds. CProjWizard north south Error... The value '%1' is not a valid coordinate system definition: %2 CProjWpt Edit name... Enter new waypoint name. CQlbProject Failed to open... Failed to open %1 Could not convert... The file contains overlays that can not be converted. This is because QMapShack does not support all overlay types of QLandkarte. CQlgtDb Migrating database from version 4 to 5. Migrating database from version 5 to 6. Migrating database from version 6 to 7. Migrating database from version 7 to 8. Migrating database from version 8 to 9. Open database: %1 Folders: %1 Tracks: %1 Routes: %1 (Only the basic route will be copied) Waypoints: %1 Overlays: %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost) Diaries: %1 Map selections: %1 (can't be converted to QMapShack) ------ Start to convert database to %1------ Failed to create target database. ------ Abort ------ ------ Done ------ Restore folders... Imported %1 folders and %2 diaries Copy items... Imported %1 tracks, %2 waypoints, %3 routes, %4 areas Import folders... Overlay of type '%1' cant be converted CQlgtTrack Corrupt track ... Number of trackpoints is not equal the number of training data trackpoints. Number of trackpoints is not equal the number of extended data trackpoints. Number of trackpoints is not equal the number of shadow data trackpoints. CQmsDb Existing file... Remove existing %1? Remove existing file %1 %1: drop item with QLGT DB ID %2 CQmsProject Failed to open... Failed to open %1 CRouterBRouter original first alternative second alternative third alternative BRouter (offline) BRouter (online) profile: %1, alternative: %2 BRouter does not support more then 1 nogo-area in this version, consider to upgrade response is empty Bad response from server: %1 <b>BRouter</b><br/>Routing request sent to server. Please wait... Calculate route with %1 <b>BRouter</b><br/>Bad response from server:<br/>%1 <br/>Calculation time: %1s Error running starting QMapShack communicates with BRouter via a network connection. Usually this is done on a special address that can't be reached from outside your device. However BRouter listens for connections on all available interfaces. If you are in your own private network with an active firewall, this is not much of a problem. If you are in a public network every open port is a risk as it can be used by someone else to compromise your system. We do not recommend to use the local BRouter service in this case. Warning... I understand the risk. Don't tell me again. stopped not installed online CRouterBRouterSetup %1 not accessible %1 invalid result Error parsing online-config: Network error: CRouterBRouterSetupWizard Restore Default Values Open Directory select Java Executable please select BRouter installation directory selected directory does not exist create directory and install BRouter there existing BRouter installation update existing BRouter installation empty directory, create new BRouter installation here create new BRouter installation seems to be a valid Java-executable doesn't seem to be a valid Java-executable Java Executable not found Error loading installation-page at %1 no brouter-version to install selected selected %1 for download and installation Warning... Download: %1<br/><br/>This will download and install a zip file from a download location that is not secured by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is someone redirecting the request and sending you a replacement zip with malware. There is no way for QMapShack to detect this. <br/>If you do not understand this or if you are in doubt, do not proceed and abort. Use the Web version of BRouter instead. I understand the risk and wish to proceed. download %1 started Network Error: %1 download %1 finished unzipping: ready. download of brouter failed: %1 retrieving available profiles from %1 content of profile Error: Error creating directory %1 Error directory %1 does not exist Error creating file %1 Error writing to file %1 CRouterBRouterTilesPage Continue with Setup CRouterBRouterTilesSelect available routing-data is being determined. Select outdated Clear Selection Delete selection Download Error removing %1: %2 Error creating segments directory %1 up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6) being downloaded: %1 of %2 no local data, online available: %1 (%2) local data outdated (%1, %2 - remote %3, %4) Network Error invalid result, no files found cannot parse: %1 is not a date cannot parse: %1 is not a valid size Error retrieving available routing data from %1: %2 segments directory does not exist: error creating file %1: %2 no valid request for filename %1 no open file assigned to request for %1 error writing to file %1: %2 error renaming file %1 to %2: %3 local data up to date (%1, %2) no routing-data available CRouterBRouterToolShell !!! done !!! !!! failed !!! CRouterMapQuest Fastest Shortest Bicycle Pedestrian US English British English Danish Dutch French German Italian Norwegian Spanish Swedish mode "%1" no highways no toll roads no seasonal no unpaved no ferry no crossing of country borders <b>MapQuest</b><br/>Routing request sent to server. Please wait... <b>MapQuest</b><br/>Bad response from server:<br/>%1 <br/>Calculation time: %1s CRouterRoutino Warning... Found Routino with a wrong version. Expected %1 found %2 Shortest Quickest Foot Horse Wheelchair Bicycle Moped Motorcycle Motorcar Goods English German French Hungarian Dutch Russian Polish A function was called without the database variable set. A function was called without the profile variable set. A function was called without the translation variable set. The specified database to load did not exist. The specified database could not be loaded. The specified profiles XML file did not exist. The specified profiles XML file could not be loaded. The specified translations XML file did not exist. The specified translations XML file could not be loaded. The requested profile name does not exist in the loaded XML file. The requested translation language does not exist in the loaded XML file. In the routing database there is no highway near the coordinates to place a waypoint. The profile and database do not work together. The profile being used has not been validated. The user specified profile contained invalid data. The routing options specified are not consistent with each other. There is a mismatch between the library and caller API version. Route calculation was aborted by user. A route could not be found to waypoint %1. Unknown error: %1 profile "%1" , mode "%1" Calculate route with %1 <br/>Calculation time: %1s CRouterRoutinoPathSetup Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed. Select routing data file path... CRouterSetup Routino (offline) MapQuest (online) BRouter (online) CRoutinoDatabaseBuilder Create Routino Database Select files... Select target path... !!! done !!! CScrOptRangeTrk No range selected CScrOptSelect <b>Exact Mode</b><br/>All selected items have to be completely inside the selected area.<br/> <b>Intersecting Mode</b><br/>All selected items have to be inside or at least intersect the selected area.<br/> <b>Add Tracks</b><br/>Add tracks to list of selected items<br/> <b>Add Waypoints</b><br/>Add waypoints to list of selected items<br/> <b>Add Routes</b><br/>Add routes to list of selected items<br/> <b>Add Areas</b><br/>Add areas to list of selected items<br/> <b>Ignore Tracks</b><br/>Ignore tracks in list of selected items<br/> <b>Ignore Waypoints</b><br/>Ignore waypoints in list of selected items<br/> <b>Ignore Routes</b><br/>Ignore routes in list of selected items<br/> <b>Ignore Areas</b><br/>Ignore areas in list of selected items<br/> CSearchDatabase Search database '%1': CSearchGoogle Unknown response Error: CSetupDatabase Missing Requirement MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.<br />Please make sure you have installed the corresponding package.<br />If you don't know what to do now you should have <a href="%1">a look at the wiki</a>. Error... There is already a database with name '%1' New database... Open database... CSetupWorkspace Setup database... Changes will become active after an application's restart. CSlfProject Failed to load file %1... CSlfReader Failed to parse timestamp `%1` %1 does not exist Failed to open %1 Failed to read: %1 line %2, column %3: %4 Not a SLF file: %1 Unsupported revision %1: %2 Break %1 Lap %1 CSmlProject Failed to load file %1... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Not an sml file: %1 Recovery time: %1 h<br/> Peak Training Effect: %1<br/> Energy: %1 kCal<br/> Device: %1<br/> Battery usage: %1 %/hour Use of local time... No UTC time has been found in file %1. Local computer time will be used. You can adjust time using a time filter if needed. This SML file does not contain any position data and can not be displayed by QMapShack: %1 CTableTrk Double click to edit elevation value %1%2 CTcxProject Failed to load file %1... Failed to open %1 Failed to read: %1 line %2, column %3: %4 Not a TCX file: %1 This TCX file contains at least 1 workout, but neither an activity nor a course. As workouts do not contain position data, they can not be imported to QMapShack. This TCX file does not contain any activity or course: %1 File exists ... The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file. Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b> The track <b>%1</b> you have selected contains trackpoints with invalid timestamps. Device might not accept the generated TCX course file if left as is. <b>Do you want to apply a filter with constant speed (10 m/s) and continue?</b> Course Activity Cancel Track with invalid timestamps... Activity or course? QMapShack does not know how track <b>%1</b> should be saved. <b>Do you want to save it as a course or as an activity? </b>Remember that only waypoints close enough to the track will be saved when saving as a course. Waypoints will not be saved when saving as an activity. Failed to create file '%1' Failed to write file '%1' Saving GIS data failed... CTemplateWidget choose one... Hiking Tour Summary (built-in) - Template path... Failed to read template file %1. Preview... CTextEditWidget &Color... Reset format CToolBarSetupDialog Available Actions Selected Actions CTwoNavProject Error... Failed to open %1. Save GIS data to... Only support lon/lat WGS 84 format. Failed to read data. CWptIconDialog Path to user icons... Form Form Participants Weather rain sunny snow clouds windy hot warm cold freezing foggy humid Character easy hiking climbing alpine large ascend long distance via ferrata hail/soft hail Rating Rating 5 stars Rating 4 stars Rating 3 stars Rating 2 stars Rating 1 star aborted Equipment ferrata gear night gear snow shoes climbing gear ski camping gear Details IAbout About.... <b>QMapShack</b>, Version TextLabel Qt GDAL Proj4 Routino Czech: Pavel Fric German: Oliver Eichler Dutch: Harrie Klomp French: Rainer Unseld Jose Luis Domingo Lopez Spanish: <b>Translation:</b> Russian: Wolfgang Thämelt Win64: OS X: Helmut Schmidt Ivo Kronenberg <b>Binaries:</b> ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. <b>Contributors:</b> Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) This software is licensed under GPL3 or any later version © 2017 Oliver Eichler (oliver.eichler@gmx.de) ICanvasSetup Setup Map View... Projection & Datum ... Scales Logarithmic Square (optimized for TMS and WMTS tiles) IColorChooser Dialog ICombineTrk Combine Tracks... Available Tracks ... Combined Tracks ICoordFormatSetup Coordinate Format... N48° 53' 39.6" E13° 31' 6.78" N48.8943° E013.51855° N48° 53.660 E013° 31.113 ICreateRouteFromWpt Create Route from Waypoints ... ICutTrk Cut Track Delete first part of the track and keep second one Keep both parts of the track Keep first part of the track and delete second one Cut Mode: Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Create a new track IDB The internal database format of '%1' has changed. QMapShack will migrate your database, now. After the migration the database won't be usable with older versions of QMapShack. It is recommended to backup the database first. Migrate database... Migration aborted by user Failed to migrate '%1'. Error... Migration failed The database version of '%1' is more advanced as the one understood by your QMapShack installation. This won't work. Initialization failed Wrong database version... Database created by newer version of QMapShack Failed to initialize '%1'. IDBMysql Password... Password for database '%1': Update to database version 5. Migrate all GIS items. IDBSqlite Update to database version 3. Migrate all GIS items. Update to database version 5. Migrate all GIS items. Update to database version 6. Migrate all GIS items. IDemPathSetup Setup DEM file paths ... - IDemPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> Hillshading Slope ° > TextLabel IDemsList Form To add files with elevation data use <b>File->Setup DEM Paths</b>. Or click <a href='setup'><b>here</b></a> Use the context menu (right mouse button click on entry) to activate a file. Use drag-n-drop to move the activated file in the process order. Activate Move Up Hide DEM behind previous one Move down Show DEM on top of next one Reload DEM IDetailsGeoCache Dialog Position: - Difficulty Terrain Update spoilers ... about:blank Hint: TextLabel IDetailsOvlArea Dialog The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Toggle read only mode. You have to open the lock to edit the item. ... Color Border width Style Opacity Info Points Position Hist. IDetailsPrj Form Keywords: - Keep order of project Sort along track (multiple) Sort along track (single) ... Print diary Rebuild diary. IDetailsRte Info The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Toggle read only mode. You have to open the lock to edit the item. ... - Hist. IDetailsTrk Form - - Toggle read only mode. You have to open the lock to edit the item. ... - Info Style Source Maximum Use/edit user defined visibility of arrows for this track Use/edit system's visibility of arrows for all tracks Minimum Graphs Profile Width Use/edit user defined scale factor for this track Use/edit system's default factor for all tracks with arrows x User defined limits for this track - - - The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Automatic limits User defined limits for all tracks Color max. min. Activity Set Track Activity To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Points Time Ele. Delta Dist. Speed Slope Ascent Descent Position Filter Hist. IDetailsWpt Dialog Info Position: - Ele. Proximity: The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. Toggle read only mode. You have to open the lock to edit the item. ... Date/Time: Add images. Delete selected image. Hist. IDevice There is another project with the same name. If you press 'ok' it will be removed and replaced. IElevationDialog Edit elevation... Elevation - Get elevation from active digital elevation model. ... IExportDatabase Export database to GPX... ... Export Path: - GPX 1.1 without extensions Start Abort Close IFilterDelete Form <b>Remove Track Points</b> Remove all hidden track points permanently. ... IFilterDeleteExtension Form <b>Remove Extension from all Track Points</b> Remove from all Track Points ... IFilterDouglasPeuker Form <b>Hide Points (Douglas Peuker)</b> Hide track points if the distance to a line between neighboring points is less than m Apply filter now. ... IFilterInterpolateElevation Form <b>Interpolate Elevation Data</b> Replace elevation of track points with interpolated data. Quality Preview ... IFilterInvalid Form Hide Invalid Points Hide points with invalid data. ... IFilterMedian Form <b>Smooth Profile (Median Method)</b> Smooth deviation of the track points elevation with a Median filter of size points ... IFilterNewDate Form <b>Change Time</b> Change start of track to dd.MM.yy HH:mm:ss - ... IFilterObscureDate Form <b>Obscure Timestamps</b> Increase timestamp by sec. with each track point. 0 sec. will remove timestamps. ... IFilterOffsetElevation Form <b>Offset Elevation</b> Add offset of to track points elevation. ... IFilterReplaceElevation Form <b>Replace Elevation Data</b> Replace elevation of track points with the values from loaded DEM files. ... IFilterReset Form <b>Reset Hidden Track Points</b> Make all trackpoints visible again. ... IFilterSpeed Form <b>Change Speed</b> Set speed to km/h ... IFilterSplitSegment Form <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> Creates a new track for every segment within this track. ... IFilterSubPt2Pt Form <b>Convert track subpoints to points</b> Convert subpoints obtained from routing to ordinary track points ... IFilterTerrainSlope Form <b>Calculate Terrain Slope</b> Calculate slope of the terrain based on loaded DEM files. ... IFitDecoderState FIT decoding error: Decoder not in correct state %1 after last data byte in file. FIT decoding error: a development field with the field_definition_number %1 already exists. IGisDatabase Form Name Age To add a database do a right click on the database list above. IGisItem [no name] The item is not part of the project in the database. It is either a new item or it has been deleted in the database by someone else. The item is not in the database. The item might need to be saved Initial version. Never ask again. <h3>%1</h3> This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'. Read Only Mode... <h4>Description:</h4> <p>--- no description ---</p> <h4>Comment:</h4> <p>--- no comment ---</p> <h4>Links:</h4> <p>--- no links ---</p> Edit name... Enter new %1 name. IGisProject Save project? <h3>%1</h3>The project was changed. Save before closing it? %1: Correlate tracks and waypoints. <h3>%1</h3>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future? Canceled correlation... Save "%1" to... <br/> Filename: %1 Waypoints: %1 Tracks: %1 Routes: %1 Areas: %1 Are you sure you want to delete '%1' from project '%2'? Delete... IGisWorkspace Form Opacity Change the opacity of all GIS Items on the map. Filter Name Clear Filter Setup Filter IGridSetup Setup Grid... Projection restore default ... Get projection from current map. projection wizzard Grid color setup grid color IImportDatabase Form ... Source Database: - Target Database: Start IInputDialog Edit... TextLabel ILineOp Routing ILinksDialog Links... Type Text Uri ... IMainWindow QMapShack File View Window ? Tool Maps Dig. Elev. Model (DEM) Workspace Toolbar Routing Add Map View Ctrl+T Show Scale Setup Map Font Show Grid Ctrl+G Setup Grid Ctrl+Alt+G Flip Mouse Wheel Setup Map Paths POI Text Night / Day Map Tool Tip Ctrl+I Setup DEM Paths About Help F1 Setup Map View Load GIS Data Load projects from file Ctrl+L Save All GIS Data Save all projects in the workspace Ctrl+S Setup Time Zone Add empty project Search Google Close all projects F8 Setup Units Setup Workspace Setup save on exit. Import Database from QLandkarte Import QLandkarte GT database VRT Builder GUI front end to gdalbuildvrt Store Map View Write current active map and DEM list including the properties to a file Load Map View Restore view with active map and DEM list including the properties from a file Ext. Profile Ctrl+E Close Ctrl+Q Clone Map View Ctrl+Shift+T Create Routino Database Save(Print) Map Screenshot Print a selected area of the map Ctrl+P Setup Coord. Format Change the format coordinates are displayed Setup Map Background Setup Waypoint Icons Setup path to custom icons Close Tab Ctrl+W Quickstart Help Setup Toolbar Toggle Docks Toggle visibility of dockable windows Ctrl+D Full Screen F11 Min./Max. Track Values Show the minimum and maximum values of the track properties along the track in the map view. Ctrl+N Database IMapList Form To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Help! I want maps! I don't want to read the documentation! Activate Move Up Hide map behind previous map Move down Show map on top of next map Reload Maps IMapOnline This map requires OpenSSL support. However due to legal restrictions in some countries OpenSSL is not packaged with QMapShack. You can have a look at the <a href='https://www.openssl.org/community/binaries.html'>OpenSSL Homepage</a> for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory. Error... <b>%1</b>: %2 tiles pending<br/> IMapPathSetup Setup map paths Root path of tile cache for online maps: - ... Help! I want maps! I don't want to read the documentation! IMapPropSetup Form <html><head/><body><p>Change opacity of map</p></body></html> <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> ... <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> Areas Lines Points Details Cache Size (MB) Expiration (Days) - Cache Path Type File: Forget external type file and use internal types. Load an external type file. IMapVrtBuilder Form Advanced Options Source No Data (-srcnodata) Target No Data (-vrtnodata) Target Projection (-a_srs) These options are for particular cases and usually you would like to leave blank.See GDAL <a href='http://www.gdal.org/gdalbuildvrt.html'>Help</a> for more information. <ol> <li>Select one or multiple source files.</li> <li>Select a file name for the target VRT file.</li> <li>Press "Start" button.</li> </ol> Tip: <ul> <li>If you have several files place them in a subfolder of your map path. Create the VRT file in your map path.</li> <li>Use the advanced options to add a "no data" value if your source files do not have one and do not form a rectangular map. Areas with no map file will become transparent.</li> <li>The "-a_srs" option is intended to assign a Projection/Datum when the source file lacks it. This does NOT re-project the data.</li> </ul> ... Select source files: Target Filename: - Start IMouseEditLine <b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/> <b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/> <b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/> <b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.<br/> <b>No Routing</b><br/>All points will be connected with a straight line.<br/> <b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/> <b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/> <b>%1 Metrics</b> Distance: Ascent: Descent: <br/><b>Move the map</b><br/>If you keep the left mouse button pressed and move the mouse, you will move the map.<br/><br/> IPhotoAlbum Form ... IPlot Reset Zoom Stop Range Save... Add Waypoint Cut... Hold CTRL key for vertical zoom, only. Hold ALT key for horizontal zoom, only. No or bad data. Select output file IPositionDialog Position ... Enter new position Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" IPrintDialog Print map... When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. Save When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. TextLabel Print IProgressDialog Please wait... TextLabel IProjWizard Proj4 Wizzard Mercator UTM zone user defined Datum World Mercator (OSM) Result: UPS North (North Pole) UPS South (South Pole) Projection IProjWpt Waypoint Projection ... - Clone waypoint and move by: m ° IRouterBRouter Form Profile Alternative display selected routing profile ... on-the-fly routing BRouter: not running start/stop BRouter show BRouter console Setup Caution! BRouter is listening on all ports for connections. <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> IRouterBRouterInfo BRouter Profile TextLabel IRouterBRouterSetupWizard BRouter Setup choose which BRouter to use BRouter-Web (online) local Installation Expert Mode local BRouter Installation directory: select installation directory ... labelLocalDirResult create or update installation Java Executable labelLocalJavaResult search for installed java Download and install BRouter Version about:blank File to install Download and Install available Profiles install profile remove profile installed Profiles content of profile BRouter-Web URL: Service-URL Profile-URL Hostname Port Profile directory Segments directory Custom Profiles dir Max Runtime Number Threads Java Options Profiles Url IRouterMapQuest Form Highways Seasonal Language Country Border Profile Avoid: Ferry Toll Road Unpaved <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> IRouterRoutino Form Profile Mode Database Add paths with Routino database. ... Language To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. IRouterRoutinoPathSetup Setup Routino database... ... - IRouterSetup Form IRoutinoDatabaseBuilder Form ... Select source files: Start Target Path: - File Prefix <p>To create a Routino routing database you need to download *pbf files from <a href='http://download.geofabrik.de/'>GeoFabrik</a>. The process of creating a Routino database is quite slow and the resulting files quite large. Therefore it's recommended not to download whole continents. Limit your download to those countries you really need. However as Routino can't route over several databases you have to include all countries that are touched by a cross country border route.</p> <ol> <li>Select one or multiple source *.pbf files.</li> <li>Select a path for your Routino database.</li> <li>Select a prefix. The database will be listed by this prefix.</li> <li>Press "Start" button.</li> </ol> IScrOptEditLine Form Save to original Save as new Abort Move points. (Ctrl+M) ... Ctrl+M Add new points. (Ctrl++) Ctrl++ Select a range of points. (Ctrl+R) Ctrl+R Delete a point. (Ctrl+-) Ctrl+- No auto-routing or line snapping (Ctrl+O) 0 Ctrl+O Use auto-routing to between points. (Ctrl+A) A Ctrl+A Snap line along lines of a vector map. (Ctrl+V) V Ctrl+V Undo last change Redo last change IScrOptOvlArea Form View details and edit. ... Copy area into another project. Delete area from project. Edit shape of the area. TextLabel IScrOptPrint Form Save selected area as image. ... Print selected area. IScrOptRangeLine Form Delete all points between the first and last one. ... <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> IScrOptRangeTrk Form Hide all points. ... Show all points. Set an activity for the selected range. Copy track points as new track. TextLabel IScrOptRte Form View details and edit. ... Copy route into another project. Delete route from project. Calculate route. Reset route calculation. Move route points. Convert route to track TextLabel IScrOptSelect Form Copy all selected items to a project. ... Create a route from selected waypoints. Change the icon of all selected waypoints. Combine all selected tracks to a new one. Set an activity for all selected tracks. Delete all selected items. Select all items that intersect the selected area. Select all items that are completely inside the selected area. Add tracks to selection. Add waypoints to selection. Add routes to selection. Add areas to selection. IScrOptTrk Form View details and edit properties of track. ... Copy track into another project. Delete track from project. Show on-screen profile and detailed information about points. Select a range of points. Edit position of track points. Reverse track. Combine tracks. Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages Set an activity for the complete track. Copy track together with all attached waypoints into another project. TextLabel IScrOptWpt Form View details and edit. ... Copy waypoint into another project. Delete waypoint from project. Show content as static bubble. Move waypoint to a new location. Clone waypoint and move clone a given distance and angle. edit radius of circular area Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel IScrOptWptRadius Form edit radius of circular area ... Switch between proximity and nogo-area Delete circle defined by waypoint TextLabel ISearchDatabase Search... Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. Name Search Close ISelDevices Select devices... ISelectActivityColor Form ISelectCopyAction Copy item... Replace existing item TextLabel Do not copy item Create a clone Replace with: Keep item: The clone's name will be appended with '_Clone' And for all other items, too. ISelectDBFolder Select Parent Folder... Name ISelectDoubleListWidget Form Available Add to selected items Remove from selected items Selected Move selected items up Move selected items down ... ISelectProjectDialog Select a project... Select project from list or enter new project name. New project's name New project is created as: *.qms *.gpx Database ISelectSaveAction Copy item... Replace existing item TextLabel Do not replace item Add a clone The clone's name will be appended with '_Clone' And for all other items, too. Use item: Replace with: ISetupDatabase Add database... Name Server Port 00000 User Password <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> <b>Port:</b> Leave the port field empty to use the default port. Do not use a password. File: - Add new database. ... Open existing database. MySQL SQLite ISetupFilter Form Apply filter to name only complete text ISetupFolder Database Folder... Folder name Group Project Other ISetupNewWpt New Waypoint... Symbol ... Position Name Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" ISetupWorkspace Setup workspace... save workspace on exit, and every minutes listen for database changes from other instances of QMapShack. On port 00000 ITemplateWidget Insert Template... Templates Select a path with your own templates. ... Preview ITextEditWidget Edit text... Undo Ctrl+Z Redo Ctrl+Shift+Z Cut Ctrl+X Copy Ctrl+C Paste Templ. A:L A:C A:R A:B B I U C Standard Bullet List (Disc) Bullet List (Circle) Bullet List (Square) Ordered List (Decimal) Ordered List (Alpha lower) Ordered List (Alpha upper) Ordered List (Roman lower) Ordered List (Roman upper) Ctrl+V Align Left Ctrl+L Align Right Ctrl+R Align Center Ctrl+E Align Block Ctrl+J Underline Ctrl+U Bold Ctrl+B Italic Ctrl+I Plain Reset the text's format before pasting Select All Ctrl+A Delete Reset Font Reset Layout Normal Paste without resetting the text's format Insert From Template Create text from template. ITextEditWidgetSelMenu B I U Cut Copy Paste ITimeZoneSetup Setup Time Zone ... UTC Local Automatic Print date/time in long format, or short format <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. IToolBarSetupDialog Setup Toolbar Toolbar is visible in Fullscreen-mode IToolShell Execution of external program `%1` failed: Process cannot be started. Make sure the required packages are installed, `%1` exists and is executable. External process crashed. An unknown error occurred. !!! failed !!! IUnit Error Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Position values out of bounds. IUnitsSetup Setup units... Length unit Nautic Imperial Metric Slope unit Degrees (°) Percent (%) <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapShack. IWptIconDialog Icons... External Icons: - ... All custom icons have to be *.bmp or *.png format. qmapshack-1.10.0/src/print/000755 001750 000144 00000000000 13216664443 016656 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/print/CPrintDialog.h000644 001750 000144 00000003617 13216234142 021342 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPRINTDIALOG_H #define CPRINTDIALOG_H #include "ui_IPrintDialog.h" #include #include class CCanvas; class CPrintDialog : public QDialog, private Ui::IPrintDialog { Q_OBJECT public: enum type_e { eTypePrint ,eTypeImage }; CPrintDialog(type_e type, const QRectF &area, CCanvas * source); virtual ~CPrintDialog(); protected: void resizeEvent(QResizeEvent *e) override; private slots: void slotGetPrinter(); void slotUpdateMetrics(); void slotPrint(); void slotSave(); private: void updateMetrics(); type_e type; CCanvas * canvas; QRectF rectSelArea; //< the selected area in coordinated of lon/lat QRectF rectSelAreaPixel; //< the selected area in coordinated of pixel QRectF rectPrinterPage; //< the page rectangle in pixel QPrinter printer; qreal xPages = 0.0; //< number of pages in x dimension qreal yPages = 0.0; //< number of pages in y dimension }; #endif //CPRINTDIALOG_H qmapshack-1.10.0/src/print/IPrintDialog.ui000644 001750 000144 00000012456 12705713523 021546 0ustar00oeichlerxusers000000 000000 IPrintDialog 0 0 500 450 200 200 Print map... QFrame::StyledPanel QFrame::Raised When saving online maps make sure that the map has been loaded into the cache for the extent to be saved. true Qt::Vertical 20 40 Save QFrame::StyledPanel QFrame::Raised When printing online maps make sure that the map has been loaded into the cache for the extent to be printed. true TextLabel 0 0 TextLabel Qt::AlignCenter 0 0 Print QFrame::StyledPanel QFrame::Raised 200 200 200 16777215 TextLabel Qt::AlignCenter true 200 200 200 200 QFrame::StyledPanel QFrame::Raised qmapshack-1.10.0/src/print/CPrintDialog.cpp000644 001750 000144 00000017647 13216234137 021711 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include "print/CPrintDialog.h" #include #include CPrintDialog::CPrintDialog(type_e type, const QRectF& area, CCanvas *source) : QDialog(&CMainWindow::self()) , type(type) , rectSelArea(area) { setupUi(this); // clone canvas by a temporary configuration file QTemporaryFile temp; temp.open(); temp.close(); QSettings view(temp.fileName(), QSettings::IniFormat); view.clear(); source->saveConfig(view); canvas = new CCanvas(this, "print"); canvas->loadConfig(view); canvas->show(); // add canvas canvas to dialog QLayout * layout = new QVBoxLayout(frameCanvas); layout->addWidget(canvas); layout->setSpacing(0); layout->setContentsMargins(0,0,0,0); connect(canvas, &CCanvas::sigZoom, this, &CPrintDialog::slotUpdateMetrics); connect(canvas, &CCanvas::sigMove, this, &CPrintDialog::slotUpdateMetrics); connect(pushPrint, &QPushButton::pressed, this, &CPrintDialog::slotPrint); connect(pushSave, &QPushButton::pressed, this, &CPrintDialog::slotSave); if(type == eTypePrint) { setWindowTitle(tr("Print Map...")); frameImage->hide(); // update zoom info and print metrics QTimer::singleShot(100, this, SLOT(slotGetPrinter())); } else { setWindowTitle(tr("Save Map as Image...")); framePrint->hide(); } } CPrintDialog::~CPrintDialog() { } void CPrintDialog::resizeEvent(QResizeEvent * e) { QDialog::resizeEvent(e); slotUpdateMetrics(); } void CPrintDialog::slotGetPrinter() { printer.setOrientation(QPrinter::Landscape); QPrintDialog dlg(&printer, this); dlg.setWindowTitle(tr("Printer Properties...")); dlg.exec(); slotUpdateMetrics(); } void CPrintDialog::slotUpdateMetrics() { // get corner points of selected area QPointF pt1 = rectSelArea.topLeft(); QPointF pt2 = rectSelArea.bottomRight(); // calculate real meter dimensions from corner points qreal mWidth = GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt1.y()); qreal mHeight = GPS_Math_Distance(pt1.x(), pt1.y(), pt1.x(), pt2.y()); // get pixel coordinates of corner points canvas->convertRad2Px(pt1); canvas->convertRad2Px(pt2); // the map area in [pixel] rectSelAreaPixel = QRectF(pt1, pt2); // the printer page in [pixel] rectPrinterPage = printer.pageRect(QPrinter::DevicePixel); // the label to show the page matrix in [pixel] QRectF rectLabel = labelPages->rect(); // calculate number of pages xPages = rectSelAreaPixel.width() / rectPrinterPage.width(); yPages = rectSelAreaPixel.height() / rectPrinterPage.height(); // width and hight of page matrix for full pages qreal wPages = rectPrinterPage.width() * qCeil(xPages); qreal hPages = rectPrinterPage.height() * qCeil(yPages); // derive scale for map area to page canvas either from x axis or // y axis. What ever fits better qreal scale = rectLabel.width() / wPages; if(hPages * scale > rectLabel.height()) { scale = rectLabel.height() / hPages; } // create the canvas image QPixmap img(wPages * scale, hPages * scale); img.fill(Qt::lightGray); // scaled page canvas width and height qreal w = rectPrinterPage.width() * scale; qreal h = rectPrinterPage.height() * scale; // the page rectangle QRectF rectTile(1,1, w-2, h-2); // paint page matrix QPainter p(&img); p.setPen(Qt::black); p.setBrush(Qt::white); for(int y = 0; y < qCeil(yPages); y++) { for(int x = 0; x < qCeil(xPages); x++) { rectTile.moveCenter(QPointF(w/2 + x * w, h/2 + y * h)); p.drawRect(rectTile); } } p.setBrush(Qt::NoBrush); p.drawRect(img.rect().adjusted(0,0,-1,-1)); p.setPen(QPen(Qt::darkGreen,2)); p.setBrush(Qt::BDiagPattern); p.drawRect(0,0, rectSelAreaPixel.width() * scale, rectSelAreaPixel.height() * scale); labelPages->setPixmap(img); labelPagesText->setText(tr("Pages: %1 x %2").arg(xPages,0,'f',1).arg(yPages,0,'f',1)); labelMapInfo->setText(tr("Zoom with mouse wheel on map below to change resolution:\n\n%1x%2 pixel\nx: %3 m/px\ny: %4 m/px").arg(rectSelAreaPixel.width()).arg(rectSelAreaPixel.height()).arg(mWidth/rectSelAreaPixel.width(),0,'f',1).arg(mHeight/rectSelAreaPixel.height(),0,'f',1)); } void CPrintDialog::slotPrint() { qreal wPage = rectPrinterPage.width(); qreal hPage = rectPrinterPage.height(); QPointF p11 = rectSelAreaPixel.topLeft(); QPointF p22 = p11 + QPointF(wPage, hPage); canvas->convertPx2Rad(p11); canvas->convertPx2Rad(p22); QPointF pxCenter0 = QRectF(p11, p22).center(); canvas->convertRad2Px(pxCenter0); QList centers; qreal yoff = 0; for(int y = 0; y < qCeil(yPages); y++) { qreal xoff = 0; for(int x = 0; x < qCeil(xPages); x++) { QPointF center = pxCenter0 + QPointF(xoff,yoff); canvas->convertPx2Rad(center); centers << center; xoff += wPage; } yoff += hPage; } QRectF rectPage(0,0,wPage, hPage); bool first = true; QPainter p; p.begin(&printer); p.setClipRect(rectPage); USE_ANTI_ALIASING(p,true); int N = centers.size(); int n = 0; PROGRESS_SETUP(tr("Printing pages."), 0, N, this); for(const QPointF &pt : centers) { if(!first) { printer.newPage(); } else { first = false; } canvas->print(p, rectPage, pt); PROGRESS(++n, break); } p.end(); QDialog::accept(); } void CPrintDialog::slotSave() { QPointF pt1 = rectSelArea.topLeft(); QPointF pt2 = rectSelArea.bottomRight(); canvas->convertRad2Px(pt1); canvas->convertRad2Px(pt2); QRectF rect(pt1, pt2); QImage img(rect.size().toSize(), QImage::Format_ARGB32); QPainter p(&img); USE_ANTI_ALIASING(p,true); canvas->print(p, rect, rectSelArea.center()); SETTINGS; QString path = cfg.value("Paths/lastImagePath", "./").toString(); QString filterPNG = "PNG Image (*.png)"; QString filterJPG = "JPEG Image (*.jpg)"; QString filter = filterPNG; QString filename = QFileDialog::getSaveFileName(this, tr("Save map..."), path, filterPNG + ";; " + filterJPG, &filter); if(filename.isEmpty()) { return; } QString expectedSuffix; if(filter == filterPNG) { expectedSuffix = "png"; } else if(filter == filterJPG) { expectedSuffix = "jpg"; } QFileInfo fi(filename); if(fi.suffix().toLower() != expectedSuffix) { filename += "." + expectedSuffix; } img.save(filename); cfg.setValue("Paths/lastImagePath", fi.absolutePath()); QDialog::accept(); } qmapshack-1.10.0/src/icons/000755 001750 000144 00000000000 13216664445 016637 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/MoveArrow.svg000644 001750 000144 00000005520 12517672561 021304 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Filter.svg000644 001750 000144 00000004325 13201005615 020567 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Device.svg000644 001750 000144 00000013636 12457375271 020572 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/RouteOn.svg000644 001750 000144 00000010204 12727447634 020755 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SelectIntersectArea.svg000644 001750 000144 00000013347 12705713523 023253 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Font.svg000644 001750 000144 00000006736 12455143304 020270 0ustar00oeichlerxusers000000 000000 image/svg+xml T T qmapshack-1.10.0/src/icons/Start.svg000644 001750 000144 00000006713 12455143304 020452 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToggleRouter.svg000644 001750 000144 00000011451 13126360003 021763 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcHR.svg000644 001750 000144 00000006074 12627613666 020457 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToggleMaps.svg000644 001750 000144 00000126121 13126360003 021404 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Image.svg000644 001750 000144 00000007222 12455663777 020420 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Area.svg000644 001750 000144 00002054733 12705713524 020241 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActCar.svg000644 001750 000144 00000010437 12600710657 020513 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/RteInstr.svg000644 001750 000144 00000007355 12551744506 021142 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/makeicons000755 001750 000144 00000003643 13026233641 020531 0ustar00oeichlerxusers000000 000000 #!/bin/bash function call_inkscape { # $1: width = height # $2: source file (*.svg) # $3: target file (*.png) echo -n "$1x$1 " if [ "$4" == "hicolor" ]; then inkscape -D -w $1 -h $1 $2 --export-png=./hicolor/$1x$1/apps/$3 >/dev/null 2>&1 else inkscape -D -w $1 -h $1 $2 --export-png=$1x$1/$3 >/dev/null 2>&1 fi if [ ! $? -eq 0 ]; then echo -n "ERROR " fi } function convert { # $1: source file echo -n "generating icons for $1... " NAME=`echo $1 | sed -e 's/svg$/png/'` if [[ $1 =~ Act.*\.svg ]]; then call_inkscape 16 $1 $NAME fi if [[ $1 =~ EditDetails\.svg ]]; then call_inkscape 16 $1 $NAME fi if [[ $1 =~ QMapShack\.svg ]]; then call_inkscape 8 $1 $NAME hicolor call_inkscape 16 $1 $NAME hicolor call_inkscape 22 $1 $NAME hicolor call_inkscape 24 $1 $NAME hicolor call_inkscape 32 $1 $NAME hicolor call_inkscape 36 $1 $NAME hicolor call_inkscape 40 $1 $NAME hicolor call_inkscape 42 $1 $NAME hicolor call_inkscape 48 $1 $NAME hicolor call_inkscape 64 $1 $NAME hicolor call_inkscape 72 $1 $NAME hicolor call_inkscape 80 $1 $NAME hicolor call_inkscape 96 $1 $NAME hicolor call_inkscape 128 $1 $NAME hicolor call_inkscape 192 $1 $NAME hicolor call_inkscape 256 $1 $NAME hicolor call_inkscape 512 $1 $NAME hicolor fi call_inkscape 32 $1 $NAME call_inkscape 48 $1 $NAME echo "" } which inkscape >/dev/null 2>&1 if [ ! $? -eq 0 ]; then echo "this script requires inkscape, aborting..." fi if [ "$1" == "" ]; then echo "generating ALL icons..." for i in *.svg; do convert "$i" done else if [ -f $1 ]; then convert "$1" else echo "$1 does not exist or is no regular file, aborting..." fi fi qmapshack-1.10.0/src/icons/LogProject.svg000755 001750 000144 00000007750 13201005615 021422 0ustar00oeichlerxusers000000 000000 image/svg+xml LOG qmapshack-1.10.0/src/icons/QMapShack.svg000644 001750 000144 00001113775 12705713524 021202 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SmlProject.svg000644 001750 000144 00000007737 13174544135 021454 0ustar00oeichlerxusers000000 000000 image/svg+xml SML qmapshack-1.10.0/src/icons/2NavProject.svg000644 001750 000144 00000010132 12461361423 021501 0ustar00oeichlerxusers000000 000000 image/svg+xml 2NV qmapshack-1.10.0/src/icons/AddImage.svg000644 001750 000144 00000006264 12455663777 021036 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/UnLock.svg000644 001750 000144 00000006715 12455143304 020552 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Check.svg000644 001750 000144 00000003772 12455143304 020374 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToolBar.svg000644 001750 000144 00000010171 13126360003 020701 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeDemVRT.svg000644 001750 000144 00000006774 12455143304 021275 0ustar00oeichlerxusers000000 000000 image/svg+xml VRT qmapshack-1.10.0/src/icons/GridSetup.svg000644 001750 000144 00000016156 12455143304 021265 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToggleDem.svg000644 001750 000144 00000006236 13126360003 021215 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/hicolor/000755 001750 000144 00000000000 13216664443 020274 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/24x24/000755 001750 000144 00000000000 13216664443 021057 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/24x24/apps/000755 001750 000144 00000000000 13216664443 022022 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/24x24/apps/QMapShack.png000644 001750 000144 00000002160 13145236406 024332 0ustar00oeichlerxusers000000 000000 PNG  IHDRw=sBIT|d pHYse.eVtEXtSoftwarewww.inkscape.org<IDATHՖ[LgorB) N(AҐ&K$¤Wj oG4q1Qb<ĨH1q!fJXr,=}]0Wb7=&'v~j^+[A7ڦ閂Bf+.A s--V= !@(ڵ_yX 47( &Y̓'S_ADPiB-oI!!A"#CGJJ"ss~"/= fq12~g`Muu6N_j3G]fEꩭ4TRK:pY[ (D%Eѣ Q{HmUZZ55"|0۶icdG" !%''Dן|a*:{~nϻ?e8Lտ-:{IENDB`qmapshack-1.10.0/src/icons/hicolor/192x192/000755 001750 000144 00000000000 13216664443 021233 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/192x192/apps/000755 001750 000144 00000000000 13216664443 022176 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/192x192/apps/QMapShack.png000644 001750 000144 00000045034 13145236412 024512 0ustar00oeichlerxusers000000 000000 PNG  IHDRRlsBIT|d pHYs_~VtEXtSoftwarewww.inkscape.org< IDATxwtև+ I I $!{KT@{(zŮUQ"4)( 'FBzmǘ&Z̼L޿-7fn5`G;@VV5(iXo}ei)GTciٹ3jZhڵ{i~qZ |miNӦi7v4NiӴ@;mvhMni 6MӦi7v4NiӴ@;mvhMni 6MӦi7v4NiӴ@;mvhMni 6MӦi7v4NR!3A7fnMdݺp\\>C{=7FUN#iSUFER }Mkj7K̟[[cNoBiM>ɓ):HiGoP\\MuK{2th'רTqB1bL^ҥLΟOC1y2~|v~HN.lV>/$PH^^%eeJ6m¨Q[x#dd??>*>ǎ%i˙TTذ! 9s~x~}vx$ѹ=RJnn&|Et:Wa߿#~JuH$Bmpu`L?, i/N4bM͛%L^\ w< ae%/1}NzЬ60mZWJBJww/SKٳiܸQFDA||> 틣ZM`c{x2/x3ZRŹs;̅ X[hQ&&LL\ͦMW Nj~a:NGR7)' XVVrFdNN=x_z5p9?ەgSQ(4l~Ii9C7ZJ>өk3?]0>|,Lrs+ir/.V(C"RYXԯPJqp0Jڵᤥ˿2i8TȰaixo_Liv翕\|}iy,X^y(}ba!eӦ+cJX$''S qfX/<֘Jx*"x"NX'mgCp@\B@.qL'?e `ǎk?ĉ>̘Y\~~v ԉj5[\ c ?7!C6{M&BlmMػ73ml DG?{-/|K2XjmWsKMnx. Lٻ-RXXEII50a+/g_HI͛#ӵ9qVG{;0h `lBC;pl*[4:t0K29{1jݭ |\矏KbbFDEesټy ^^֬Y3RB2//+ p3\sѢ H-gE`،(Ŝ)S|=ڋ5ksr6NNxzZEvv}P*5:۷+3e"sDpd iiM:_ е-wGGt:acGsJ |rݜfP4O<&023@dzφbj*E$bb"f޼CH$B:u{caQ{wov[ҩ%"Qӟ/2{8cK5+WɲIJӧL&džGkѶO୷Ni݁<|9lLdesR&XYG(-UpT* ztf:O͞ Y~gwƨ)g(/Cm C -4Di4:zorϹsTTԩ=Kpr̜ cc 㣏FR^Dұ%N$#ի W.aժde',ʈJi t$2r…Aһ5T*5h4{xjwZRQvLڵ9a uF /$Ysp>Ӡk91`ƍR-Ck=z84|ΞM%1G /ϲr`fW3,Y(**+U{*6oҠvlŔ)lϞ@.M>Q,\c6[ۆt;wF-ixNtTT|p.]l8 O<￧2aB@͐߹5e|d.^Lҥ ^~CSVV>b*yS`bbx≟(.՜Rn(͢A}22%xy5}%y>ȧa')V<1>8;a$b!jŋBi]|PF㣏ZS2`D^}uP|ۚ GaggĈ/_IUcc 4;ZmC||A-? Φ֠RoW7~7!cG (>LLjr\]fk,_~,_~gg3ƎL&Jͅ DE{gt)'OΟF%66H\.!!re/j5qvx ! _H\\>KV#?v-)c:uvbXqg SsMv Ч.2~w _~yJzrA,bqƍ{ٳ/K")*fҤ.ԆN_bNH$"Zy7,a,.\HgҞ+Y(װT*b=r`"wQϝ;;c*%݁s:ƈO>K^}K?yA7N{w,U~Cr`"O<ٳˣ Tɔ)ya\ՠJС$wwhp5ooy#MkQƏ?2jT7^7NRQ$*JHR ǹsXVn]8VFj>c>Y aþS쳋dg_qrkk FYTDDDadHM-aQ_?*X[[bn.T#"01Z´i;IO/E$bf&sg;jh:VDrrؠtgxoNH&&&eѹY:Urp"޶iztb+8[o SQrffz_caaDuJn_gO   7r%'1e]U Z͏?^'&&Y :v=Jhhrs+3,*&**>}\5SOeUU7no#9vl.zk2?M}\yر R%fmEJJ ))%@`*̻\i8̒% .nq|VT1l=BWD0xe [[fpMEEUS\\@;e;L6xxX!ckkLHΥJZ9y2޽]Ɋ+Wr(,-eL;;c4-yyUHb rC k:*rzP.==z8o:zBT{#2\elz4{ZKAA..憰ѽFy\Dbb!&DB^xB&m5RRkӰ,Ǚ3eNwNT_ŋdg!Վ]jСZ}ES# 恧;vDsx2?T*槟qu5G.`A*+U8@Igu;s\:eeJ23(*dk"*zrA PPPqp0S9sUUjT*-ǎ`u$jP(u$w"""]XnbrwBffzZ?D3`@Gl!<LaPwj'Ws@s9a+LʸqthAjj zذNZ7Wq G>|XZ(.Vzoڴ[7^o׭ܮ b#)FVzLVV96\\.A,`~yRC||YYZu]bەݻ30l8OPWa|Yn(GJkHI)Nu^)5V~qKP]6LnB" b_ `&NuYɓx>̜ ,arX2@!&&N,[{w~]bHM-'Э[ýw-f&&֬ k׆SZZME1w^ӻV'OO,++ajuT" rƘrط/;,XЃa:fA~~;Q`#=_o//WA7nѸ%Y(:0W*+3Ƌ@G&2%|vR7 "ͭ%W K/ޛ-fE)kݽ~ޭћr9sf!Z~nnUvm..#yuAR9}n…=ÑXZzy,,dDG瑔Tĉqvnxd#IXYeU@?͙2 J.\@&1tjGB3g\DpZ**ܸQܠ({}k׎Iebkkċ/y-f͛#ټ9.dT*- S[9v,`ڲz(z+|y }w𞗗~:ƐX;ښ;ja h:@|^\˅ @_裈 .eW&<{3wnw-OǎBbK}߿#*V>lj)-uFcd$ۆ{\DRR!>ۋ gy+_ɩ`Ҥm? x+%% ~%{#Fxޱ~aDDx /Ʀwǒ\DLL$ ډ͛#Y2a|Ϟ:v ::(*bp6M\fYУlMTTνOl%d2|3ѣ= qTX,D$0v>$`ŊAu rGPsFQ~dlL˖{X=ګJ*mۢxÌŶmQ}4lmM0`0 ?fqP 85K8&M/J$Zhv,PP=z8QUf,[v`Æ@ ώj,-eܼY;Gܹ4bbώ ͡G?=|7~%Єg)(Bo;3~7EEE_א<|/ŬZ5TR,r`|eeSPPW> ɺu-.XNL^;< @31ǖ-Wqp0OǰlY{2#G{w Jzc;U['jb!ee lm17agg̨Q9|8 t:vd0.\ȠTA*6*hNxofx? y9y2U~;Vz<*ާbcy䑮w݈7^}3PrZnLL$-j찴Â=طo&eXXIO/&)a zu@*ѧ+ ;(""aEUAa OqwoM)+S7DRR!ϧZRIIZ:;Z1BN0y,\؃YRi)+SgO r{Lظq'v1thNǜ9 ›6]w#2ra:vci|OO+>hcz1{vJXToFH3>G.L{Gvtr2c?8zF4}v5k. 8>;wN| rk7z5jóZTAÙ??\ `L&⫯YҴJBDGfx<[AAX[?)dӦ+nYFGՙ|\R .qMJN@}AgOʕlBC;0wnwFז ;cgg¼y884-:7*L%??^{cV:Bθ٢_ɹsH##v87ZK>ʉ ٰ2JLM%|uσ|M*k׆ӡ9:k1㊓)|hT* rFWؼ }6a!1qbf XO# uw/5vWht[juy7SChɔZ%>;;˰1XXȱځ-["kŽ4O?@W%4Vɓ)TWx챀 i 祗~ei:s4 ^}j^+2wo !5 b){Y "&N!-3 :"3i}3Y*%KBps$4ԹB~$ Q-ҦhT! tKTP(|}m,'́`gx3MN}to7 t7Fqc!!ZED&՞?Dff_|qg e׮XO1d%&΀37ѫ UU*JJ. !Rȵk!CkS*ڥr% 9r$v݁L^s腳QQaΜnu _k;zt;[2J F/SѡPh(ƨEt4k舣iƨ uwƠ 'fvB x lmqM| IDATv6W" IHǩw)  9'oRPPEtt.jLLDelʼy$$ uٜ={3`@GfC,!G۪zۧP舍gP\]ٲ*AܑE`ʦMW1ƒ)SVspZook||8q" G""'NiYvT_3kE~:tif6FMD"b}p vf޼TqX<366&ÀBUFVV݄`'^z:w棏rJ66uDK',-GG34 ˖&%=>ݏu©P!VaJ>Wsg r6o'va8lٺUmnbb!^LNN9kYQ?:rfX/,,HN.D22J6V<ss)RSS)BWԴzV n.66F8P9~<%d3ҘJٵ++OQ\ӧӯ_G v.ң# ΞMGGS tʕl- ܹT:)*rr6rI%0krɩo_W6hyy]'AB~^1rkń%'oOϞ9ͪUŖ>}\jfecoo*SsJ] N(*nΞMC(~e-y^9Ri~=2ht,^,5@4tB~9+baaٸ1ۖ;1y.=Rf((f?#=9thN:՘1^K YZR%Mm .%xYƊ'5+@Gvc zj?9̜ϯDPGٿ?#<vEr-P(M\D" NeNu$͒%!ebΨQ:Vkqp0Sk˳`(OrSU{ub&'PU2eގ ct;.tC{ <,,d RXR|KRUZr_23IL,kW;\]ͱ3Qy&/OTT^^֭b.@L&Z\.K[,-8;#X8;Xȹsi\T*b,XЃ &ֺN3ZUU05ydva͚8;QU&){{S:udz}nA~x{۠Phʈ?X_ZB$:uSPbw(Rוj֬ŋ|jI-D,T*-"^:yΞMG$0u/&tA$K}89ba!T23hO=~8:r, .0dH'F 1D{J79rǎ`(/P4H"lmPF/F߾$&^ʸqʈmۢTӯ+g95::?݁ZVf@t:1ÿV'V3x;/*}CibggF\[ g=!BqYvz?IL,B:o=ܰ˫\ɜ9L?'`i)G!C\0qMbkX /͒*Ŝ;w;v0~7 Uѣ# `ϞFo?_⽷ >++9JV<矏ͭ`+CnMa(O/תnj&'b@dRisgkJqՂ R1<1VVr t`̘TUY0~AڿFy2e}p@<:Y2e Tde"t[ Ge޼ ss9&&RLPTC:՗+WQr?>L-oZdd!!NTic? ۶]EΥK֮ ٘iuj=T}j(ߑzvaٲÆN?>r۶(8;DŽ ]+{ݚ̫֢REqq5#G((dX/7+Wk<7gg3'.N?ݳ'{{Xb jjAA?Btt&￧F|z쀇>DLBRExx6+W7O3B* T(4T.sBnA77\afFL& Z[o0\kcl,ٌ={bٹ3R;G 2JJbm ΜINhQ'N_f H$B,,dDFfgEBB![FqR%%J$%}5zvȑ ڣ, ܷ{FkW<ܴ)Ν,Wc(-Uys${4Bz4Ƭ[͑2o^wϟOg$!wkz9Ə\oEۣ8v,+WT6mDA|hJK_gQĚr~1JBCY0k DKK9ɟOu ݺ90u/=_+ 4V"I.oKEZZ)~:jCYj`9$& 4ۯ1u}Qe`wS!/Go0n\Z Ծv۱n]8o)ݹx18rA"KK~xjA^:Ș1]ht #Fx 3gP88m9aaJ?ރ=8zd"9ғn6͗r%u* (/WR^-ԦLeܹpT*6Lǖ.]l(+Sn]8>RSju=JWKK_YK' 0ls6,YBy3 }I|]$,]ړ:b_|UgL\.,|s0x;/>YV c,TMBH3Rmۢ4 !! q&5a__&>^8Hjj12KfpD""ᅬbO,,©Sše`Duu.3{?vvW\q7݊㒒RBRRίGǾ}qP23 D5 NpaPsv6ݲ^KH3M|y?6m-_f޼@d2Q*֯g=HZ5!3nE$ҷ+wCP(`ذNUbaaDh3&&JExyY1~7&HT?V32v8v*nOD@=nn( ;֋};bggd(Zôi\Uo=ٱuJͧ^ .r rgׯ]eEʔ{WܸqRannXZJnn  #k\_Crr5w [uo\ޞe5LLL֕q rB_5""7 zCt:8mC\\> gg&O<+2<l\^?ylTlP(@*~-"U]/ZZ`Ć J~~E8P]"66)S"BNN66thB\jp**… 2Υׯ#%%aHT<=rBC;гg|}m<,K17k=^o2llj9wmK=z8sIH(Ղ?< T0y%lv~WGnnnǖ^M\\>UU*T*ahB`a=ϯ$5Gԩ9Nyr]#; 2ٟӺLNI`o5Q^+f2饆C(IN^+J15]UglZz%/ݻc),&&NLĚ6n9\˖6 쳽 LCy°'CZ4UAfXZaf&1HC~~%]&""};R]OW Qvv&(.]ʠwoLMdf]뵅 k׌j( "#0Я| S?Grx$RX[jCaa5eJe̘V^FPP}/}7ATPPEjjV ׮bd$gCٹ3Q*5(jbb X.A 9m~YZ$$D_=%Jvu@GK7^:O#vpMM3ryy)YFxx6@FFFS^D, ҆P γQfIjju'_^Hĝ[.+*#5*;w׮1`ݺ9SI^^G #C^ϯ$;RZTDDd!\]WOߤG}r.;V |ػ7&ODQJVXGqB6@ZZ)EZg]JŜ9(.V Pr?<˥KjPWV(/W5FAA=]EP(#zF!1aB̮֯]>AN$%dž wN4Eb]$GjcGGNNؒ*ʔUukݵۛg **12z(_$&ie剗5ZVbb"a@,N'4"#sP(4TVp!w) ;@@ff 8ї?Өē6曧xܾ}כJE:pLwdȐN+~5Яs""RSq/rs+j-*k#LC. gik+V d ?^z:ޚ2ŗ{5k̙ ^880tb WWKbߍӧovm:YRXXȑDG?%:EYvʵj6SnhѾ: .W_1p`Bo5GjxO(4ܦ ooFrCo ^6k?[^RƸq]p!## 7 o:~9;c,-UPhHN.GVju\|mAŢ>j½֯_T*rCF`  {4hЦ@bl,RȑL ~{@Xp <|˅F +/3V0kVs|z-W79w.A s鼼J22J9ӿ;NNso kPW޳6o&x׮C$'?ώkɓ[vSncJEDD wn#ZԵZz5z]b8xp6=z8sen1`R r.V IDAT{QQфKC__[dW_=NAA77 ^xޞR%fgH7q9sFSȑ `μF) &"{4ȝz̤I]HH(L/snHر#S}U`O'P,-޽̼-ѹ5 <VkX{L5661ҥ-h4Zv< K͍օoGJJ1 4v93!hAu])-VisbRet?BCGWWa0pL*ٍj5fbr XZy1?,-Ubn]LSwR(~'&IL%3ƅb…Q7C10M011,A  0l)UD|VKZÇPtEiyzNsGbԆns{HJ6|*=?՗+\Y[ϟwsnq1sfo@xxs>T_dӷ_x7nl!Kgek'0WP(dh}DWBf/fNqqPG܏ "OQĽ(" q(r>4 a00Jsi0oEYY3m7㩭DII#[X,N.GGwRD]]<;F^}ݻWBV}!>n }}T*cOͭ(8 p+mv^(*zWPbL B!b©S9CedTb͚ ١sP*hk㐜`ɤXXy||lܸdea%sHO/U\g>hХe1\WsyXX 6mZu#ZwlN,2h4A(+-GD2٣A\%<ΝŅ ;[ qw~KWej+W[WN||ꇈy8p`-VR9P@UHHX-#=p(/{jal6,X ooe8yފGˍ hi<*()ocpR rrFyyȿq`0XQ\\ݫc?`BQ a;dj;75`!^:$$D"::IIŨh(K신 _qn/Щ6 5tV_Fi dQPCii39ض-ii3}@O?JxjQQkxkCݏdRanYgr-;,[(gYT* ^ܿ߂'O{npL~7CN'D}}7n G{; Hs:{zxH$Z폊VddT"='5P7H'jA[qq=N0]k'Y"O8ǘv%"<|>|}~}x~yyuP`׮(Hϐ/\xv9ayފv 7o;vyNՎ$%"&cOɸ)CFRRn@缭g< j vT*ʪF L&:lْ%J%Z.O(HEE"#C~~mn5Gn@B̻<&XP:q^ߺujZ*l9kz94JwvZ8# @1{F\*c?Q(Ԛ(ƫ;,ZE|= I4 a0@F LQ(i4 a0@F LQ(i4 a0@F LQ(i4 a0mp\т{j- a '2I!<BgɡkWsbFkxIENDB`qmapshack-1.10.0/src/icons/hicolor/scalable/000755 001750 000144 00000000000 13216664443 022042 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/scalable/apps/000755 001750 000144 00000000000 13216664443 023005 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/scalable/apps/QMapShack.svg000644 001750 000144 00001113775 12727447634 025364 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/hicolor/48x48/000755 001750 000144 00000000000 13216664443 021073 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/48x48/apps/000755 001750 000144 00000000000 13216664443 022036 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/48x48/apps/QMapShack.png000644 001750 000144 00000005272 13145236410 024350 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs../tEXtSoftwarewww.inkscape.org< 7IDAThklU;3osezaZޠ-PB% "QB$MPXW1pF-"Hw@A,m m[+̻f;thA f9<<9gϽ*.ףAZdnxI) ׸/^W,˸\^ᡴ}j [v:=HAA((!,,)SFTԴV+>3V<#V+y~KX^ȑzL&<@W;E~X**.砮gMGHI1ф0dg۴Z ^x"IZ[(.njj:Xr2II?-JgQm8p<V7<̫S?nsg> Y W$'Gn == }u:K'~d@47z{X,fΝ䭷gc44\A֮>*!!! ݍ$ݘRt:T#!!jOCVrt_}Uͱc _?çdH 8ƍ"?!ii^[NDNN*6g(-m&/Vl3bVE}}7 \0z}#FHI1jtВmG()i0a&NA^^mm6֭-8pP^ٽ{ @g`۫eNnĉ&::$%"pRwa /efLH]]vT8WQqKDFjc6·93iR,NSMF[ؽۆ zfӦ7.nIGVV sA\ Adjj))ibѢt")+#Cf%PW ]T 23M:t>!(HAnTRS#tS3&<_E!2RK^4@lsˆXb2,[Q wtJK!11c2iJDy c.v{hTX.)0rMMW1T^O&z4~" Ě515BN `43yHV>ѨA'`0QUu?棏gIM 4TMsU\.vc#x!0nT*m?!̞=9K3dryٵ499ciFtF"))I))i0~|4X,q#tt=zqK…i^ŋWlfI5IHeECC}WKyy WEv+]]vmXrsGFF *#۶君{/NG}AeAd'9y_8sQzAt 5,SUw#0iR̐^!#t3fija,\.}LZ9y{FᩧF%11IR0khZZ2{vv-$..X=Oq["7$ Ōb'$^bv7&w⥗- ETBp. H>Z Í(B8rS<96+;vojY|? W['c$IIEE3:]ii̜@\\(.+\M~)F5u3ccO@ć%@|7[xZ~!?X/T""1ȈlIrrPD,@FF4 ncӦttذZ]03sύ#==04M x^DDhE8~XGXd# ObC46AVryz3ðo3R)2u(JK4i$sbV$Cyy :ļyc@:nwW43iT"*P3CSSEEMLf&7w 3ܹ͝^DVVLP,_>,];Sk4*J_OeTmW./[W px=gd+˲,*;촲v IAFqQILIRg0q WA+ ס_!([IOv[[Xj2*5jY<4L"0|?A);+-m᧟mmIgv-i'?_a3l|s纈fٲLΞmgZ@}'0zt ft )`!UGogm[6"#Yɑ#խ :Z`aC1kEG_b17V Geƌ1rΜvQil9ΝHM+1~Vqo ׸/^C)˲Sy4eȲxmEOTIENDB`qmapshack-1.10.0/src/icons/hicolor/40x40/000755 001750 000144 00000000000 13216664443 021053 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/40x40/apps/000755 001750 000144 00000000000 13216664443 022016 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/40x40/apps/QMapShack.png000644 001750 000144 00000004163 13145236407 024334 0ustar00oeichlerxusers000000 000000 PNG  IHDR((msBIT|d pHYs||&I tEXtSoftwarewww.inkscape.org<IDATX{lTU?w3hc:,-VRP76<PI $j ̚KU$f!+-"UBȫikܙs2m[.f{߹w~n=_jk]a0zG 3?rj5O7_(v8ѣFʇWt5t:E֭OW/*rۇhԲia~^LxY瓉0jQEQ]Jjj$O<1Y).O'L %**ɘLZXܿˁF7*:dYE]͡C7ؘL:lP{p"`IJJ$--  TTr^ =e&s*mKHjز^Jl%>pB0uq e7*'OޥW`[O2\2۷E< Fן=?Pss/d0NcÆ|Q96 a۶|MNZov! -Omm'WgRZȌz_ *ʂEQQ/NaxKAtK9ӀEVV<>̭[Njj\Ը uXz 3`Eq:NRyyչ9u%% uUqHw,"Ȕ)(:j5ogΜ$n?55.\.-ش3f$`|yfd+VnvQ[IVV& 7n]7]a6n|A8"m%dɸq&͕+-!w]@n$""  h0h9~Olr̜ȪU Ut@Alڵ.^̧5U(u2$?Nntg޼$e98mGkHO"))N] Q(.C_DNN6[ nG^{mEEȲBa\f͚+X|ZNEPj=§ih⫯nrj++VdlY>^x1z{x<DTUg&dIpr23zoKbbx(B- aa#8[0AJJUU-:X07C}}Bvv";w. ܺAl7ޘJ♙.\p w8ٿ_QI81Ճ 3-I RTt`PAׄ(:ڌ(ۣ4qܽSY> ;wh0('#)ز%Sy$O%##zHbuŚ5Yj(mjk;={/O}x+٘L!b;`gغ5¹#S^J#)55ߞ[o`Тii0LKݡA%%ԕ+rOUx+Qހ u@}Y3I V+Վh-qbې1qP zUc쿯#BmAIvB?~ @mm<Ϝi`Tzz$nhˏFa8=LO޽<6m'NɓcE_OzPs!ǡz>(84TZ3BRumm}3 #/qFgIENDB`qmapshack-1.10.0/src/icons/hicolor/22x22/000755 001750 000144 00000000000 13216664443 021053 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/22x22/apps/000755 001750 000144 00000000000 13216664443 022016 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/22x22/apps/QMapShack.png000644 001750 000144 00000002001 13145236405 024317 0ustar00oeichlerxusers000000 000000 PNG  IHDRĴl;sBIT|d pHYsٶAtEXtSoftwarewww.inkscape.org<~IDAT8]HTi{Gi?leʏ W7 .ؐغI" n>خ6j[@hw/ͩtmRIGm5q>9^h.-+>_~pvg; Fr'[Q൵dR6/`hh87o~۝@4D$R zv}Y[qWp:dffАRHXLLq?|;M Ν뒃[%qsBܸᣤAgg2QT; shkssd|<3xi} dzӧ?R:TE*e I:fgWx4b)-Ųl6CO9s׮,Ņ 05L(H08ʾ}.6 <&&'#H,0u!>_=.ػ+W@SZ*uF'MTf>:Þ=Wq^˺uALOЧY"__ _ԩ2rrص+:bcήƍFBB4(ҾJO :{M_ /{egXDRRSc0dd<{OcX,"%%kP*h!8ؽԧ:hX(9sP1ض- EZE6ΟGW[?yyf+DlMιsش(ٚJ L<'˸xH…nY,"sDP^[F\ܧdS Qyݩ_˛ٳj_, LV\F' |T̙Chn6t"'T2_BskMеk|95xz5k55:JJ9ҟUߕ$t,Y2$Nع3Sy|L6wf+ᾕ%Y|/ 7.OO*N\Ng"<<CÇv ݎ}D)%ly^VScժ[l%35,Z4^o/c6[ >>y0L||0!ČxxLֶqv.KIb j˫/.`6[y^?Aj&99ŒؑCvvӧu <=UL&/@"T֫q?ρٵC'J9q-[CEE s G ojKJHI]Xܹ2jT& $%e^^*/7_K/]!Ǘ[Xt$VHvvgǗ#̝;CBhd]{&ϲo_!KƱ`pYկF\p:˱Xz/II;Zm?'~}6K`Nz$(5M6gU+…*a$JKغ5ZZZ.2tk֌cט5+FTJ&ƗPPd޼aE yf99<\WhL^NMT*膋%K$=}9Ѓ+ͭF"5+G ƍFJKy6@|?ƴia=D`ϞE5)hm5nBF 'g;I"6֏!C2%9DG~I۷™--C}7.oo5[fQPRJ%d%:l~dӦ$>|.?PDcc;z pxr =;O?=u pM6l8̩S+zlŌF H[&f,IXM A`X̉겳jNԩ2,7YN'Ց嫯.X6-c빺ʑ%$&j>ܗo߽pq榰?ر%%M;V<M}Wps*Rf+ .~wυ^DIIzw 36F7`h4Jnl랮Sy3¿0-j2e0Ǐ奦HAlWSF"PW׆VƨQHzʚʕۙAx{IIdn 6F~JJ??9sMbmkL@fr} DT_0L{%iatxjju׷QQ̉@mj*7ߜD"^ow`=鮂Lz`2YY.AH$Siiټ(w/&$DCVV9 }8}7͋F*Rɨё2hhh#+V\]DE`4Z9v&cʆ I{UqO)L}#%%;{=AkW~&M]=cY; pR5zf̈d ܩsR5fN,F+ h4JʚmwB]vVCrr8j/2wnSir( ZhF.j.UTJ 0d7'fBc!("cE?^JJrrpq፫ AЊ \\K@;j6\TV݅=zM((#55Nܼ֭$'{"$ӧ,iiY7f,b3&=zpL˖őb%;|-z j  3gF""CzZZ +|'K!Ijjt\pponhoo4yQ :tCVytL<يR)j1#L[>|/;wG&SbռdVܹQ$&"11pA~O9wӘ>=oNgbD&PU#7Wˣvj--Fx{h#D"HPգն!o~35/yXX\.}Y,9u Lj׷ܒٱORR(IITURXX7䒙Y˖!spw9tKgL2JJv'4ԓϹ O LV._!2Җ<9vZf֬ AV{|^~yR67ihh#4v{@1r-@$#-[5UB ?u̙J}aas^=[+Wjil40i\mg#vU"K! جY>^z:~"Og|y|zMPjaj ƠTJ3|yR R`! VܺO8P̲e9Jw39}Rԩ}jW̙2ܨ!@X'kLGvٳx晑F׿EXGzMЬYv$:0iҠ:0š9A?ANO9A?ANOy~Y)N^=R.GIENDB`qmapshack-1.10.0/src/icons/hicolor/36x36/000755 001750 000144 00000000000 13216664443 021065 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/36x36/apps/000755 001750 000144 00000000000 13216664443 022030 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/36x36/apps/QMapShack.png000644 001750 000144 00000003552 13145236406 024346 0ustar00oeichlerxusers000000 000000 PNG  IHDR$$sBIT|d pHYs##ZtEXtSoftwarewww.inkscape.org<IDATXmLTgޙ3y`x7(R mcMjٴ]Bml5$-iRi4ojX6Ԃjk~hDypaݸ1E]]@!mTT4ǁ x#?'G[9ut`۶s84#*5oHKsPZD E/.t24t`P IQccAhXwti 2~$=cυ ɤrY 6ʲeN:;}7_Og?/ej7/\_\ fXΝ29I[0}}㴴 ؿ!F7%uk׷2lޜ @v [H4c!+'زin6mb4$'[q:-a**q\죬>3&tZسgqq[@Bt]qw`x뭓@4.?GecUU,L .0eS uΞɤ 餥QURYBII,P$I2ӣ s#_cd$,w]鴐f3Ō]o\,+lؐje!?in %NgǍ~2Yf=4#9sdS4<@{mmhM3W_p SZl&;7]+SZZnxEB1̑#`X҅ᰠi&.\'r:~}4w ÷vDZ?#yy)xt;A`x8mGQ$dY"09j5ۥ(@ Q^`ϞXk=Ν35!pK:HI|U5b2)S/a E j?dY"1Q03 .΂(X,&TUܹ~t=[,#ANN<ճuQ4#$>7tAyVzz|&^zi50]2z<$$,gY& EmGUU+W@Uuʯ꣏~;vG:]D"1>4!|'B!֭+zO-A4g]tgFSӌ ZNKl== T5NMEn֤JRffΥ$ ja6.(I' <2v]!>^c ^X  6JQъ_7Nr zghhʕ!hk !AchhW~+ÇIMh``& V{ :;G1ԎǨU4̈́:`0˵֍{m_wtI+($ UIENDB`qmapshack-1.10.0/src/icons/hicolor/42x42/000755 001750 000144 00000000000 13216664443 021057 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/42x42/apps/000755 001750 000144 00000000000 13216664443 022022 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/42x42/apps/QMapShack.png000644 001750 000144 00000004333 13145236407 024337 0ustar00oeichlerxusers000000 000000 PNG  IHDR**[sBIT|d pHYstEXtSoftwarewww.inkscape.org<XIDATX{lTu?icbl ]ӭmd <*"T%bDECDB(5 ZV0=1t3ҁBm]wsO;/# [#m0\k 47?GOnh7N6nlh0pUU\ֿtN:Џ…~JJ9vʮ]`p_ٳ6x;IO:귲 &:_#;;n>[ɓ-8>lf tt8vk{k'hOGHڵΆkhk@tOb$>~=;#Z_G zfΌcѢtXj6&EFeU_zN23c4y`MPwv:ٴk~.'F_G+1~m hl%--Gv GZYsTU{ @vvBǻ6/1Cαx>'v//X}}ҥqa?il쥺 _ IIoutl *8~"~YVX('@kmrp%%X<ȗܹD5khyih*C~MRR$VkX -lr'ӧo'O&** IE`Pю 瑕Occ/K))Ѭ[cBoH~̉-45q44tSUeeD"f j6o^ Sy撓ĦM|a bf#(-eǎ"bcTWF~n-ɈO 膑GYJΞ1-!z'#paomm[ȱcVwo@o)*iif͙t:@sEQ{IOJ]]11QQUEY1:Ձ$L*CaY`͂33'0 ! `2MKgRYyɀGeT3v0/uk!(sm%kD[[ػuZ CQTDQHVKsze'-W'ń6̈́(~͎ItÆQUefM 33UUNEQ1+]8q?ͼyI$$ٜ$$0t9Œ%3Q#G ̉'6v zYVB-[`| ]!9P(/_ 8A7qqFٿ&;Xח"˪FrtWl]NB,h$Id \E~HȎE̜KO~| ((Hu+(׌~\~Z[)+gŊ||>@@ᮻٳg o]$ TT43ܪx Lfs8v <ي3aL&Ij~7QX;7UN` $jf6p((HCt8~pĢX,իbhkc4 `: l'r52cF=7m|Y F>m=zGճp>zKJJjBJ"#9P~BMr钛]{ /p*-CQTf?L b, Sxqm3FoSlj͛Qx*ˊu`PQUUUUEQ钒+i#sz>+ Y3N'yy7FQQz ,Jj^?9z-Lyڄ.["/]=/"3&맭l9" *7iv9r_?άY >D+?TU Uᇱ |C|oIkG| dkZ#|oȲॗE_5<}}אetO>iLN RƎ##3\1zDmm,+R>8襢"W_=ơC?Nj5p@?*+sg stt`-(̖-yYϽD"17p4'8}w.{^j53dfؿDXL7_}5DfB@_5:;[9v:|=;ζm9B(T^"Q`-'ij*e׮`e=|ӴWR(/H:$}YώE$7nSU`xx,HI'MiKK~ѣ{qʀjF{{$رKzbmm],};Q~P(ә٬i08GJP@P__ѨCE$$4dLtu]z7m4McddhZ.WntwQRA0EKKNXxVͅ$֭46nL  x/i8e0uu~_3#yHҒfwLyy6CC3(3sxs[yjna`c`(*"% Ηe[x{9{Ë/p]ټv l^L5W4 eeYTVPVcƍ ~!$ScLզ*C ipOd~>BSS)C(gO)Ѩ:n-hToqD"*F2]u TE-&Ѩ'5UaӦli Kq 2##47[wv [4XNv@,!"~]KnRU嗷%+L{{vvs|qqGp(FILNNj5;{3veyyhmu1;͛rvMSwo91EFCb"y I}kX&t;'PNkz OQ[[N&&tv㛘{9MD1|D*:DOL&Çϱa"0}Ʌ fg4xQUutc2y뭇xW=DMM>{xZhjrmntזzͷN-^KIENDB`qmapshack-1.10.0/src/icons/hicolor/80x80/000755 001750 000144 00000000000 13216664443 021063 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/80x80/apps/000755 001750 000144 00000000000 13216664443 022026 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/80x80/apps/QMapShack.png000644 001750 000144 00000012666 13145236411 024346 0ustar00oeichlerxusers000000 000000 PNG  IHDRPPsBIT|d pHYstEXtSoftwarewww.inkscape.org<3IDATxytTEڇ^ҝYɾ"%0 z\Q2B#AqD11h Nt'G M: ܺUVoUB˥&9AP((L樱c;7o#GJo$&y_O)47";[gP@AtAdP@AtAdP@An:f[YUU;̜]ķ[X#._Bt7Mᡇp\q23+1LdfVengn9E@̆ yB;0LuР"=?>O[f5--DDxLKK'͝>h{+rslPPQ78ɦM-`C @@KKb 3QQ^6()+k#99Un ܷ*%O=5.y|Qa7񮧤ŋGjnej>_`0YpR nnNLn:TEn vhHHss'rZlbU8C$$!_v`ӧADݺǐW'\["Zm qwb0x啙4כfϞ|v<<-[l r77"ر45\/0#ӧkw#(ȝիD VM\L&F(ЛP[alڴpVg„>]7|E>Jv`/  әػ7;r9y?d2Q_/&s#xTU=Ev =h~v"#=3//g孭]ORUՎT*^ond#ddxlC>9?P VaRKYY+O=DS`&L+˝h 8Y?5yr'u[LRIIv}{./0z֭;g"#=1#LgWWKS?:4ylݚCII+,[vZ_mOն֖ 7ލD"VZRkolĻʼy1jv꫖xJ_]} h0Bjjbc}ؽ^rryѯR6mr:zgRS?ZoŊd&22l#@hDnn{|]Y %+(gڴ/_C3w>zg*+ۭuF3v<Nży1̜٩g-o٩]K^^=?? JGrr8K|«fs>=DDW''!^=Ǿ(6mj qb^zi:f5sFE.b4g7~zٵ aaLf۵?.`++kԩZozbbb3''*ylJJZYSYͳylù|yt:J!%=>,`B"wwUHOgp_ZZ:),l…ffΌdǎ\V;!!Uƙ3 9`{ʔ]l6k3{–a޻ P\oQTtG(/W  yd::t|%BBP(@, cG.#Flʕ.zA1tuIJ a![wrMt[gG޽=ۀ^o)qtF""<0!@OOg_JC(瞛;Y>̟?MXr"Rv ΘLfVr[kx{س'@}b)NN"U e޼hRSwF$~M~CUJ׫=6,])'O>xݛJ} VDB)!* )+V…f.]j$}#Q~R$.44;֟=u sr6lNZ|{n*iimvtspa,YYUdgW!رlx7 N'>~H׿N:@3 EޔAee;qq|%77) slf j+?q4#FV뉊wDP,,@~~2\رDDxpVG&?]JĉJg-Z4)S%<>%KFX8P$?^ѭl8aa~m\f]X,YGRRqq,\8ѣjC; Μ ooee1a׮{)-m4nVǮ dr)_~ysMxz:*G7  q_ &:;z6*vr ;IIj])\1Lbrjrr &Y˫G7,ZB ]̜ɐ!.\喤$c5FQZ:gk?eZu\j  hjR{0SEx6 ))!!46̬$&ƇF>I#qw:$*vWgPh tv('!!ZGAA46 [hԩ::;(Zf̈h4QTJlBC=dfV3w qp1qq'&ƛ78InnZ ,̃[sX `<9DxO{*NNBmԩaf<=YL{ZjM F{NСtvikIMU yy:V3g(l0C-qƳq ^~nVVkHN#%e(%%mu}nƺDz|XJ#2ҋwͧC}*Hb"#=Ͳ77w2~| 11>x{0}z8..NlO>DDU<'y.f̈,a= c֬H48wտ'4ǡUF5H"ʪ駿A7QFm ۆX,dʔ0T*-cӧ E8;qMڵcK {S((h?9.P]d -!TzMER(4h FZvV~kFR_|qpOD44̬rF=%zuo@^^* HNh4HOO%26)q5!j6~|}˰a>Ys-C7QSI&wR(OvM*a6@"WGcVJKX#\]_2u5vۚ=;`d2'd21fCY4*u- n_?̧scpϕ!C\x뭟XcmwUbox@ `ʉt??-vsXW/xծT%[{#h4qܝ;{>%h511ހe80iZ]ܹ#hB.~H(p3mDDxu-W}ϬX1:ݍ(,ldԨ!/bne7@7^{mN;2Y*`M*L&-=qz#};"ʕtFkz?t3+Bm)]ܑ)mc' vӷy[ůdž&y@ѯ_MB5w[ h2طv}* qupX)ӧG%,_>΀d Nhh-s-SnI{3-lt jf3ZuWW'y챯hlONwû|֮ɓCHIeK6{PXga>:T̉si4H$"|}]P(4*:tF7`9SCNN 7g„ |r2˖ٽa6C/iOP;ZVܤDΞ*֭;?oF1:|3 XZچhB1}V'*ʋ8?v>ŋ-?}cEEW9sMM_KFN#=ߔrMKoI 雮K̿atAdP@AtAdP@AtAD O5_o? w7P(({I gIENDB`qmapshack-1.10.0/src/icons/hicolor/8x8/000755 001750 000144 00000000000 13216664443 020723 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/8x8/apps/000755 001750 000144 00000000000 13216664443 021666 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/8x8/apps/QMapShack.png000644 001750 000144 00000000530 13145236405 024174 0ustar00oeichlerxusers000000 000000 PNG  IHDRsBIT|d pHYskhtEXtSoftwarewww.inkscape.org<IDATjP@ws&B/n.]'q|gǼOP(A 1;n 稢xx?X.9io)J)<&;Hn_iΘ(zk 8<e3bAY$9ٯ v;XkovVߠN d%a9Z=uE]3EGn, IENDB`qmapshack-1.10.0/src/icons/hicolor/512x512/000755 001750 000144 00000000000 13216664443 021223 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/512x512/apps/000755 001750 000144 00000000000 13216664443 022166 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/512x512/apps/QMapShack.png000644 001750 000144 00000215243 13145236413 024504 0ustar00oeichlerxusers000000 000000 PNG  IHDRxsBIT|d pHYs,,IŌtEXtSoftwarewww.inkscape.org< IDATxwXᰧ *DTD=rkԆ鯲,a㛩YVQj8E!l PPz>9ϸ< V B!xQA1> l-aK!e;˻4B!(+AJhVEB!Dq5w)BQf] !B)3.B!ʞB!@!CϯY!BŎEgO8Ǐߦo_LM ^݆Ҩ K*$)8;[QcKOaڿ4BϞuKhBHj #99 __WWyD+)тwHLzJԮmKNN>iԪeGZ 4I \jjWơReS5?|\]3m֠Oz]T>_}u##fʄ -Nc3|1I]?nKÆ,]3Qԩc{%Jr;4>>1»\ޗBH J]bb'NܦiSg\\aܹ!=QWavM͚88[2/{XXsr3ԫWggK8˗_]ۛѲeUׯ|^(ܙ!ʍ#СfiGi|jҦMuo㑼ޮb_˖Ǖ_=KHH"5~ʥ\r|9'pf2l_7tS ֮Vs]'ܹ-[PTA!9p k_ DZܽ_&/O_ Ff_n6\Mll:+V\&** {1vlg^ބ{{3V?&''''K&O!;;cpvqJ|uAQ G>}>kWپ!!^)I ]$%eG@[>|>ڋW=i~iuxz:Һ3. ed_ vyE bfLz@2@M9x0Ç_Q*O61$(5]Fj￟ym׮Vg-:''{uʸ{wsڵ{ۛ1`''8[0s1UOu͢( 3KBog&22Er~=?%˙R3f3iK̐Iv2rFI`P/̚u^a`o~CNT~s tB' 3wocl&22{ӽ{]:urg͚RfnKkӦ`VǧM:s|4cl!!!W,yW㰳3cϞؘh{тykyQd x&.]_rb _@A*VZ5C?~*U<ˆt)%%8v,ɓ``ͭmjп.DwoS {3d'wߠnݟ#33رcM6t3IO&11OO>-Ou~!() Sq #Vwz\_)0rg^qӿG}1NmeeLZ611;;SFªUW[מ3`@-T4ȓqVdre’]ێa>uq @<={{˨Wg22r9qb,opzcsTjU*eׯ~tΜoxroDر۸000` ^$:ZMmPVVLЂݻjU<<SC1x:FDJJ8qV]eC̜y»d⟤@ؾ}ᤤdQU?٧PcؾZ oTOږuݽo ؀[[~=A{Qrر#l0~{L_?** pao:vt',dLyaˌ͛ _&ȀnnM6;B #<<@wӨQc6՘)S|3+Qل Dܿwg߾pL ^ԓ#<ؓ^NFN#"9{6۷Sٶm(ؿ_8tYAhàA}6c9v,={7Zӯ_jVط/3~~5J\F!@ŋ1\À  I(y5jp(P* QcceVôl//GLMu'N.ֵwDyTV&|@Z\|!ճg/ >}GݥSZ՟<-^^]!JD7w&"bƬYȐ!Jzn0`̚Յ-\8q6))ScbT><5.ŖjԜ9;tIƌi¶m!̘LiS0}zWG [^e<=KJ! *UVDGHH|&cT9rtLL 0ΝT J<}J 6,ލ@c&Ҭ/#7贻^}De*/UFQ)Sj]{W_]OttZ ãEzsB4'NFTb:&Fȑ9wnxd8$̩SQ ՚5+QMchh"((XcgԱcԨMVÓn]gDfM ժ0{vWׅeΝ͛ɏOn{.، hԙhժ%6lb߾pRSn!(/LGfb.XF89Ypr /}{(*}%y,XsvcžAngʄ - wj' (99 ĉ-7tR?|^k;sfG>MJY6++S22ru+o]yɒЩSMKZXZY._aϞ0I,Q$š5Wϫ%ONNFFJƍk{HI~9rVi۶Y27k=MxxcaaaDvGjM;m1b.ܥY3{eƄ Z'9{˙6FVs|4yyX[j1ޤV-[+yrMΞW?55_MJJ& ?oOժS^Ó8x&+V\"/O͘15 ˪$tFҷ۶uk(#1b#/T[R< ֵg֬#22}‹U(YoΜKRRζ~:UwX1՘3hE6RMTqcg6m ƍD&MjŔ)Xڊ-22~:Epp<'`ݺ vȑ[(qtlBMlo#G/<=*YN2u~С[ǒ@)--5*dIɚ~Ϗ?G˖.ZӾc6aŊ+̝ەW^YZw_Ɣ<ٵ˖]*0ժYbEsss6 ?p>/~N׈%;"++/'-->}acc"#11E.0c?NĨط/J~cc% =fJԬ…<<޽NYDl^ _ߢ1Hn%ӳ_ ؀l:uSsr,ի0iRk||`ҥ`jjHY?UZrB ܩ~Yhc"c}VҮCaC0ۛy(Hͭ9=&FE*~ƍpDRR1Zdi.L聓D!gF P婰vvfBTL"կ_W^{Rg1NC.tZ @=77֯bҤ]ܽ[p[׶7ӭ[B_OJ*D#i$$h8 iEĉ;ƻҘ~8E_՚Uլ]{M%tjղ֭!tNJDE_Wѝի0}?6 YiMΝ7WT*<%͵)x DbW59[曣88XЫW]̘2e/)ͨR%y5/³5@iS83 y4d5'0FF ֵ޼X*U6'OaܩɦأG]9E&Uq% ++c:wUjP(Tl ã GDr-VǕ;wҘ10֘A<177QݏW?nܹY/:RR*LQ(`zC]QĨc͚Zu̘O~~>|_q#*U,ٰa0NN굪DI>ڰXm\#&Fŝ;)|!t/+{HNdϞtVEzwpq"77>}VcGh}HK&;;cc%gϾSK&.>D6uĤtATT*xy9r]-غ5IItZsA˖U˻ 8Aǎˋ$E277/IFF> 7s+kQ1ljM2+?|֯V}6t݉I*GGs=m8uQQiĨ@L<۶K/=dBBv|n.7KKV+Z+{{ &Oރ2Y|mخ]a4im,Y S8wQX[ХK- ZGf&KJ̐Ivi[ ""}\ٗ3oz睖89YuullLJTΊ?4w~x^Q}y <%ӧe'ahh̙…ݻmTDIll:-R䯿{xG35U2sf'j5 80hP59,APa?bH^^N|E{K*222 ""]`Ao5qm!bnnČ|u"SYԩ7`GyQ󟻸X[+[&,,\oKl>V17$nu+>}VƎm jС&~GZ[RIZ$* #Ub9s朢FJ4hPp԰$Z^ȴipw33s]ŋ1g nիXFjIJeh #-_O_f[Ϣ,U/144`׮dzp2h\3䣏uu@< -?͇T)h={~qpÓ*꘢|HIN$;;S9_gޑۛqL' 33WZ 来];7|jf:Y͚9SF5bԨF.bb˜9M/Kb I5Q#'>̏>;ԩIJdP,-5]7{1xp@3_0aBsŨQ0*h5s_zк+L*h3Ό y ! @,]U C\\#5eݺAKDEaffヱ`^FϞuС&֏<÷ذ!!C/gUmBhwj~N?\}uZUM8I\`ټygP*6N6n 9ˑ ZH_ 5saA|:ljfL{ܽuw@88XЬ ĉ;,YrJLXzEWϞuZbԶAvvݘ/411C'a h5ku׮mǐ!^፽9!! XY@pp}144`Ѣt^G;j{@O,,Y"~~nannDVV7n$qk>|\rr ?Ul|M׫>>>c1W;aeeB׮+i L477b:uZѣ1o酔;v Q*)12RBA๗MBBի۠Vk>>Ӻ :xqƎSLpm5_={֥gϺ$ٶmvD06ִ(0x']Z5LL֭6С LFZ#sv׷*'۷}{NfOO ' wpw-b굆 |'x) ㉌L7=={¨YY,CCfgOxxTP%}?YVkbbb_%;;o鈽Ycx).daaDu:-mTgڴv=?Uhٞwᄏaü8%ii J rټySvə^…hrs8q*U~OB sFV#33exB IDATWxE /J QS ՠ{:( ,tR-[;@ѧVufLv7y,-122EnO)xz:`fVLLhܸ 11i佐󘳲 LlӦzykq`7nə᭓idrsQ* PQNN>AxNݻw`=KKcjղi*?͘1M޽Nc,-ٽ;۷S[8:Z׷f$--A<M yV4jRi@rr&&lgѢޜ::j5 s߽*t{a23sY*SkԨQϾ N/XZjU:ur/"Dɗ_A //'-3k\6I;Ewf2~/im*=zW sd0RR26ܹy߱c8I4nT 5+ٱ^OT0n\sƍk^`{6 Q#'ƍx?v,^Lv5J%,, ڵm91 Wی|5KAff.oѴB'R(T ƍkQghh@ݺԪeR)_TSkWYYIHIbJӡRf#o݂GƖR(vĈF|n= *ڵ0#[ǎ5曎|Ѿb￿]kadJKwJ̘q?8OTTZ #00cc%͛;o:Rz :R )9gmmLε17~~vvfL֖UKFori_gϺ]B]K^9 NuO/3$̙sچB?++c"#5uoHdҀBĨ|qv &7һ*$::;w4׺};Ҳ10PhW!k{{3ʴio)s.QYÓHJ*84y VabRx̘q@֊̈5kPV} ~rr?}XҲ}::cY3g֬@zz}2n6f8̅ PRQ =uN*_}:uyV̥zu^{qRSx-ؘ|y_3wqt46%$dn57w!55 7hԙ5+0ebbTհa`-3)nnt^~;_]_Orr&͚pV ˗_ȀRN*nIӦΌx,hBtt>>en,Zt3g M,2 aEwINdnEftʻeΝT~$gaQTtl%:@}Q""u#7v?fG<_$ !11 #ZJrr&;Ƅ+.3mQ5,,]nhAffTa4p`@V)S|5V.pv*Jm aO||\RV4#..޽둚uرaCZUW<o5Μy̵o ;!%̜y.>=#Fx?W,##}¹t)GG ~$!! ]}S 5J&Z:>[R׳dẕc*rr9{.664jT>ɓwhԨs%d^y^D iSg>܏+rX O#?_y8q>;j5*ReReѣHZ5k{ض-T{α733I ))Yt^m ohoCC^]̙(v)k>-cc%gDv.ۻ7.]VZ;;[}&GCyT>}\z +3O][?TKT0caX.wU\ǠAk8qg dkҤT`bbm05}On]Y,] UZѴ fDNʄ?nChh":-ͭ۷УGo%<<@Y-6aXqnY G>|S-lUa̘|2s?ZƁ39f꫌Y'Bꍟ_ Zv-.Űzu ]޽:yi7mq#;o|' 44kо} ]OӦUxՆrVx$\ޥKmllLP2ċ$>d?&&J}qG7~}{jT%Ŋ+Ӭ3nЧ*JvzabbӦE ˑzUáC7INΤ}{7?M,^Gd>̏5GjbOqMNSf}RnnppCbwug/,,7 30Pl+jrpn&m&OAN6jĨQY@sټ9x~ ͛;s->BƍPrxՆz7iH;wRIL --i1g) ʸ9#F4ʘ?Lnu3m>E+ILDTl AY@4ݶmu֬=￟5?ZluZ _ˑoL?DZ4|0`m^Iܼիq89YMU?SܦS=Y&\_aذlYw{UӧgP"Ço2dȺrv˖U:mx&76l{hANNu mҤ 7aC,Ztc"9quL˼ Cժi?%JXm *:uX7mV'##+WbiѢ*J>ks>++c~3gvN344;1tzݻkk zQÆ_…fٲ4RMt^;Lj_dYOe|V4kl*kh,n_ÆX[p[(իmʕXJT sAe}]|s 99XY0hP~ i,,h\ٜʕuuΎ8t&{ZӶmuMVV.;ӭJ00-]ٸ1ww[&MjKZՊ9sK*PU4oٌ+o5&Nl,[* Ξ}SlmFij?]4ҠPĉ-xV$$GTj]fJ4*5E% @t|4ܾ)4hȈE65kŋoqR,;z].4oȀ֭]Evv7o\,-Nؘ`dd޼LԊrW#-,X))g~ھMQ6駇:tS/tڽBJoכ{w=z-MZE֭vF$1bFmVV4mܹ̊6>> xz>iIiiAQnn N76Vj3=HN@oMTpٳ#G6hFȚ5l6T2߁,^||}UW wΨQ M,ۄ#ys[QnJ믏ХKuż$Pԯt&&MK>Kʹ=gϿhn1|O>ωe?i( (b3;bff_%?_[o5A_rs9}:J^庪_t[RVqjQQeޥK-#7ѯjΟqKK823Tڵ8rd4k^/LT@krn_zz۶i%&f2tzm{&MPhZ)>>gŊx6n bÆ!x{;o5NMbb&fiI[zł NC @TT*\\ S{Xͭ5ۆkre5"OeLTкuUV @Oׇ.< {8z4{ufnno_?,,066l-& 55QQuѠ#CCiwׯ̛o6gzTdRiyTRI|fj98~|vxrT0y|> …b9sNa``߾4n~ C5LLsݘΝk^6o$jڕl,w'&FŲe+qԬY CiSb.BӦU6!yLo7o&fM 8R&(11Q2vlqIѣNLq]L~??7w]cLvP%v_ p!eHO4{?`OǾfSfR`"88g}jղc˖!%^2:55$>-11\KHHπAHVKBJN_j{ba V+ر&VVp~6O|ͧQne._eS\p>|<~}V5V-[llL1)pyڵ{Lի`iY.&Tgۃ̧HP9r ]۲f@ym,]K/U_{B ++D Ko/3o^ JKW\va6YahP4hppxew2Y6u'ygׯ/Tx|}s= Ӷ$Mٿ?*U,Id̘ ؀7lwZpijόC;wūz?9;ݻiddpJ,F5Đ|nN)4M 5cOu'qz<ᄏMH`%:fPҞ="" ++,,13YOx1LM Y7E1~vG#i7vͧukMT-88Nv޼<5_{p52w>XYӼ SVkF?X,00N|F>}X3gXR9ye}ppcl";;-\5?*2fLU+iVҥ w'qv*~WS'wm14Tpԝ"ԗ@_Zuo9JJtZ-\pvU0 IPs)7;LkyyjoЀwmowͽNi:J&n*[/eÆ '0l7 ^˜=߫* *`H֭6chhԩY&ýqr`ԨOZ99y0zeԨɮl߮YfJ٨\ˣhk4K>˗cu*USvvj5̜y7oƁݻ KݖUХKz[[rxx'N>>٧ MʕXmZSRqزN DiHL̠cǚlU-Ey35%ҡCMj֔eLJHH<ٖ/qc';v Cڄ{n+/k[f<ۉMgpoz.J|5. $筷cccɚ JF.ɋB gQ 9;[үYYhUG||\K$ΞVGʣukWtg UbݺkK[ oo'FlA&_ /s۶7n$rs&֭׵AZ d<T>ۉ#]ێJL[מƍs n]u91{@~DD$`Qh`A~KKcmWVJ':ߑ#:res^}+j5F3\cN ضM7~QTbɠAg?MϞС&ffF|Qɕ+q߄)))Y:,-ܸɒرH h39lJddJATDD2˗_*־T Μ%K͊X'' *U2oo'mHn^i;jK/f455ɒtҟ=4O!Gob`WIҲؼ:W-UZ39|}Q\W` hޚ3]6T9db;*"sDD$υ ;lºu8ynō16V6xx8<2R1G@RR&'NDfM +V\Ѐ?nC^hܹB%`16V2kV@3E7W6\R IDATMglBN211ݻ3l.^KKcRR K/ۻm۫=xjl2TgċJVwo8;wbkkJʹi×ش)[h˂ k8TvW߻)hԪeK~3TL8ׯ؃AUFĊٷAQy>stw[ZLy=+ݿ$:,DFk;CMM Y?Rc7xq@iW<%++c\,5|@;./־/|wo;|~ ƎmBv502RbjjH6TnS>⊏'`_mN'DӦ\f.]j3{vׯ\൬<||{[~0:q6*ULG=+.e*_g4hP:fs {ճG\7Q6՘B&4eժX[g9p CCm+fVresuCOӸ36x~GFҮݒەy|qu޲#! !DBl*Z{VTVij#vHb"d r~kv$B}g}?<&3r\[Z*~^zA$&fW)IPiBBX/zgգd:6; Z`XڶdniSI'mD"dݺ,^PժuzL)g?cVD?!xz>fǎ؟B,,tI/KⴴŤdsz$2lv޽pr2!88Lʕ~=XYdڵ²ez%zP^YA<\γO+?**,tuyLʪlT!3f4a˖۴kgGDD2Z 55={04ԨIGn}SB]~;͕Y:/^dV 0Y:fg+ԩ0ۉun{=ZTW̔)e`W3Jҥ<:CҴ /*,-u3%z9;= ˊun)b`W3YLΣGIԪeD7oF)(+ j+ \pq1cŊNԪeo]U6CӰ7oF3|x<=-1)99e3rdb5tuՙ:՛ѣy6BSeKɢf>i=Vii9ť3fA,-u9x!r< 8d c*T-/]`޼DɃXD!= γp/z'ԣS'emȑi1~{{Cn܈ʳw+W꺆s[]Crf466 ⊺z?L<<,$&fůvk%2>zT6ۖ>Pdsp0[RXY颩j#cŊhh8v,s};,Ʀ)+`R un0p`}]l\.@Sh<=-10@&+ٳµ-,thӦJP(`߾x{(/^dѾ_jӬYu:vcZDG֭ҥ^Ṕ;޽_ߔjմSW;:V#..HPlVO7> yhQ g"Ob֬ظ1{1)\oǎE`С3fPn݊h?O֭X13c=[\._~ʜ9g.yDFll{˭[yss]\\PSSdʌmm1Kc۶>*22U27oFya˖@ 8P̔i)006DKK=B'YGdd bQmm1M"0gN tqDWl#iL Wϔ{p0W sy$'O^)eLpTƪU]3P)&zu=R:vW=ݏ%2yL9{qs[ÎwJ%ܴ~M6o#'[99֭ktdrƎ=Đ!8|8T3aܖycݺnɎ}qUnCBB&wL){)&;[FZZ6IIGػ7חP]iVV.x{[Ӭ rŋ/~ hށ<ؕ yt\./=mWgnt]",^]gk]bcӰѧSZQRQIL ==u.ϟ qٳ0lX8t(o@AfE0eqrs|g%!Hȷߞ%::Nϸccظ hٲϞӹ_ܸq|Asfͪ[ a< ͛/}*U۔F-3S'X=[({* "JX[W|PEy}O !!?Jx/&4(Vvv.Ӧqck5E&s#~/gk992ٖ3JW6 "Kj?|ѣ!yF33 _D׮G* ˖]̙Gx{[ӷ3-[֠wŎKWji߻wʒj\P8̟N%/ƍG9G}_dI{~\YM;a̞Bم =[[.eǎԬiWx$cǂYƏ7}Dd5qCQR/(ymg8oyzLiZ%+d?hڵ´iM?޳ǭJQ`d2ĥo"]AM.ILS1C}5UprS[fe,:~<իhv9,(D[|}#Tz_w(SѦf^BMz)|.7^OpLghʜ9-YӐq3d>˶ K,2p`.nׯG3fT_'55@ٳO1iRَ ]-yZ}ccӰg>O_}vH9"z5#Gެ$'Gc.JQ8kmy+gb_|ȃKVT 6kv T4be.cfH$tnތ"""l釷51lۦګoذ/ŋL!NZZEAhh^בJe\.M^GyZbΥY3se5?b!'Goo^/iNpu…(.lKV5::YlHHrqXԷc^BGG]k5v讐IO2iQZH ){ޣE [zvAUxlzu=flFrr#FWֹ̟#ܒU_\WGU=ש3w#Îw+%6m ֭g$%e"c'#G(0͔O?]bݺ%28|e1x_pu5c޼Ljgf{vX:77s, Qי="11i,^/03&1AV__@8zTaemǙ3C5K~${֚"{) QcعnIL=::'<]11DF}B% @X36P7)CMSKš5~̝S~~~Q*m͒%h׫gʷ߶MWJo11S ˗/4x@Qot%],x;}ˬ}{{Ԫe˗G]k R\֯8;XE@@t끴X,@͛{11)XbPWE(E{tdPW6mR 5C%UˈMzӖի; DD/A2~nތ7Ş+c[YǑ#]$`3TB'6^mĤ7ߜaذ⩽\ٙ>}J}Ѷ~ZZ ݷg:Jq"00#G:8pz]\KWӭێ| Q##/o]C EږQܘ> <'7&_;4 ƏgϷӹ> kr#5HD]G׮U_V-Vj&MjLÆ*)]p6\˜9-*iōQ|}k12d|ȑ0>۶H3_⒛СU,\./w\ΣG>6~} ӝE Сɑ!c r寿 :N%--mm1۵k/qs3W:Bb,\؆!CH;vfģ|&[ GOO==uVz*EO==kW克)Æ YƏa00Pӓp0BCpv6Q~J]IƦh0T\X=|O K NvhkK>ݻfh<=ߔ&L8Jz55ޙ[o @XZ2qb#DF0qQd~ԨaȩSy[jOc(/nڊ*Uy3X%YM%xi@S^oS јsgwq{FHH;s Lm G)^=lVO?,( fjνt +Wo^˱cСx&4mjS&Ώ:u1x Ww =;Mzѵk ss\8:VrbR ;w>i<{رػzףׯ^LF>H|y*xv-p-* Kdܸ#,]z)_IIfǎrMˊ#GҼV-ccNf.鎉3g6 P ڷGW`~~QxyYr(eyzzYkgǞ=9abͽYJ-m ԩG|i:t~v x̯v<04T,ilp3_rXAAq4iR~VU-l{XX2m7}IܾS8pɰ|ģZvر _ ):^ё`ooR9zABF̅44DV8h {[\\:+V\abU]]IސO?}]9s~_a&B//+7.Ktt$ -TxMM5kg =#wѵvڵE6(ןÇ* e<Z̛גIl[[ҙ28F?>;;C=*ѣ gժҺW%00#rg_~0=7b㽔KNB IDATp(n^͚LԈիJuUTQlҋ#G0u7%+w ǣG8xSU+ˢ"y/Je""JV]E>ݻ;RDnj+mq32>[wCeXuY33mSA̝ۂ Η~$tZ1coWW39~ڵ]qt4fѢD5~YUܰT*ƍ(?`-Ϯ_cY 5;[ם=T'\>ehw29r$GpcsJ:1-[ШR+͙WWs lڴɈ \wadNTN\\ƌiXېK/ˊ]زW]$=ڃ\Ҫ4??uD|'C7KSf 3g''j̝#B:dfJy\]gUο~ByC.3uqnH$DMM@۶vف&Ml06矯ͲeJ\$.eڛ\)ޘDV`R~̞݂ m-eJ?t,,th:ŋOv-TFLL*Q;;M;Y^Za4mZ--ի@HG7h3{+&P/*FFiSx=.;… B?b={aZeTo6ccMLfڴ&xyY婊 MEH$j,[vOVE%Ƈ癬͚\Y99YsmniŲecooI*4g7'%%b-[R=:͛hٲ LrsԭkB!ڥxkGvuNQR{~}SƌQdpF4׮=Diӎvm7ƌ9\Ӧy.eժ7(o2)/'ѭcgܖe E(GnjU> MTx5vV  !<<,pp0bȐU6U==uLMiȊ˗;}IM nŲiS2ލ2yRE&xѼ+1*bZ}} e>E^=pHS{v,zMQ ?Jf6DGҲ- xݲIk4&66ŋ;" X-ZTͿkHe+ux^ZkVV.7ҹs-wJJ L~?~o*lSеkgĈt= PWWcy3 ȑrPޥ*hؚ^꠫+A[[B۶vhj04$3Sʳgij!͜;f:FFߏk]௦&7HT pv6ހGCYӐt6qEwZ4 LԴ䃊6CTy|JeX[c:;Ͻ+\~*DDA?<17RLoͽ{qXYqv,ffOk^EGDDPY.*hQ[45Eܼƍy89ujH/g҈K~}S5ńaaU~UɀYmˇ"{55!=z(8{6Q(=lXKAQnѣ))Y$'gt6SZ ԮmLY-SxG&L8ʚ578}zϸtҥ/r_p<< &,_~Uӧ65*:)'O2b~ou7qcr9Fy( \Z̔R!vvӟg! ;++=tu%U-UȀX{ r>g*]S*M`~XX`fD1DGr3@дukoj6f @ `/:vEf m̓zwq@уvQiSO/:~89T2_߈^ܹ>eX Ӵ豃gJrKMfF._~Dӯ_]%ťyr{TT ^^KcɊgX:6?UQKŌ煓S2=Yؗ;wlOIɦodg] |}#8(u뚰~}w[p<<,PS{4[hh"Gy*#5k`fl3vlC7.ĉGoεEaC+>M@E)ƍ~g6'DUP}=Jbc֝4h`Ha|!??gd+ چucܖdgg'O00@CC=.'{hh c̘>Vl$e񟕕.oObn…mEus߾%^ ޥص/5jУN6nAݺ&estt$˅ ̙QkG7#((uu5i:ӧ7eʫLH)_nތfŊN\ cG3ECC mm rID tIys^}ZѷTdeIURiptd>.^|Bxx-[ 99 ܉s-BIKaO8w.)Ss`fj'ٵ̘Ѵfe" IL`ې/8LFFӧ7ŋ,&O> { 6IY`m6͕{=}gݙr/lEjZeŭ[df5] 9u*Q"/jj:uڵ7zcx1o^+tt$ƒ@n&MLkhggSLLUve„Ff݋#%%gع.~~QdOr~8_Ѻumڕi[rz$şXdgN 88[[} 4Lz+:2m9t\ ww b!brrr9pw>+sPP<&%11[bo2?ϵkJW PLhaPoƫW# IF  ˊcbiH$ӊ}"=yoeEjZ mnEپv]]͌#lKMBd\]嗯RI?Hd29;n0vÇ^S-299E&&:vnӧ.5js><~XmӦ䧟ڣg Ɂ3oY$gACCJѣ!\ (*ލ#99;wbK%f#_^uxpF5(IAAq<}4xS݋ɓRQ#+22r3%@UB N@.%QZ6o‚8{1h9|0 ?+79z4DflhٲZ3o~r6tհC*-|>,,اS>u`i…mYM*hn7me,-ٹL|/lRf̏S}M;))+ֺ3ux$7z_ __!h!ZyONO_xEdd[ʪT*#22TWGCCLLL11){ўAdfJ9;+g׮8H~;:(U ]jSm#' X޽ѣjjXJ%ΦޭjdhA>sE^縹[鎙6YYdg璔ɍQsFlС,YҮqp0bf XunhG!T\R2bPӓ`dU]ٝgsS*^ CI(&;;L̞ 4VMg 5*ƊcG0g/yk9s}}u BC)gB,)iXY!(Ak6&!!  oxi \]8{6R{k'w|.G sL^l5 X+͚٨]ԭk_`&N%ҥ K$++?̿z,ZV%ڵ(ns̉G3z;QQ)jkk] 49|8[kPlrmٳׯGs3a0WrAGG\?(j(ƌ9Djj6={ax/6lɜ9-:5FKB={֡Mǐ͞=ALEFFj'Oߪ\\.cG{c +:k77sl TkjS'.%ޜҕڵ#!!LJYZnߎQ#+w &!o+:}z}Tҥ'dr 48ZAU޽իѬٟ92)ӥ\l8p=zkq|8kW#..e.TǗ_6aW~ڴzu=tX(yHغxB%Ӧ66zibmEm[o29xǎUQy׮hƎ@ՔuTc079t!AAlY{ލ#3SѣŬYUΫ%bHw$l@Ӧqw !!e.{/-ZҮ^/nݻqs flN@@ GnebEf6ED1F_ߙ;X*X1)xƐ!3gѦ͖b[:~8OFִn]~vYx!2t+)BCCD||R B4mjGXX|F9?؆fN.16dǎ;wW=B{0zAڶ#<<{ktaɋ%'GFTT ZZb<|H$,uqT>}ũXsaѢvx@8~ǎ;[~:K/phٲ7?yg7%`Zuceʥ̙ՕiEHH<ǏfLd21󒯾Rʔ|Q=txg rrdx0>ONUФ5gϱys'7rBo d29'&^l~Z=_Òur~20z;9sFѩXX( ID(__d4 IDATj9~M.kd88JJN$'gX\HvBy[T]?h3wOG|7::Ĝ8FXXl3oúu7 F/ uuk/ "iSwC,YOI0Xf 15&!! Ϟή]w \-,)&xzZ¹sḸ3x QٷZ5m~I1+(_~T*C(4hiIxo]O'UìYPS8ur|B3**&sjUg2 JF/ tt$3GHd߾tHfook45Řp<~}ku (_/=2JbPU!7)SɼbH$oIz38~<9s|UY\[b߾ ¡ݻnQ`$34 ''SS-3f4kڕVt(S9~<ɓ:$'gҮ+V\aΜV<~֭S}\R-k4-[_ o̚՜ >M9pSn݊%::3wCL~OO6O^,O>ǽ{qlH$aC LLawC(rX[V5kYjYXHV58u*L%Elfͧg`Wd2Kg^*W'ٰb00 =]ʆ 7 m31<,\XvJѼ RNE"yٍ Ò7CMM #(_OEDHxxIÜ9-?(|/LzErbH԰܅*xy{p@ޙTE3p`}:t'--+ҡIjXZ:W\j07ww 4ii9,\؆c2ٹ&\}T\]͕ߟcϞ ^EӦ6舙<:]ң.bѢ$%ep1Ç1o^Kj2F__TF>\faɒvĤrUқ -ps3x-02$7WƼyg \PV̎w OjZ̞}.}{{v@\E=HqetWzz>!.=7!oZ0t+;w)ֵޔ.]j+HHff,i B:XR9ΙRi-lZ(ZypV,8;~Pr%*xс G=]`۶lۦjwpw "=z8X7>#,, zΑ#$ÓpsP^o]Ə513A(.elK̙ӒQqq1W/n]L@~E)$$dj_A =Fސ^07f y:usds̟XX ̛{{W_5cҋܹ>}޽A|]/=m!Zƹsƚt^{{y7YqhM{R(PVe(e2DLq˲Aٳ2K)=#ݥ*#uy]M<9IXƶŵhEwo/퍘2`]RRNnD"[)Z! *Rp\NVVEE24yӋ&x ( 2r}D…mL&gǎbd$Ãx@ڵu N0A?_ߋŋOpl MZwo3gQſU+zכ}IG__$de3y^fώ`޼#U Nޞ zRoo /?7Dk>t UE≊%$Ė ww?x5}w7LV7`˖Ga@YWV<͢E.FKKDNN1׽:A]+HH˜KOdP[qcߡz\*s BCm+\W S=\ATT,ZZBZtZ O!VСX_ʮ]75jWH"ΞMŔSV(gҤ-B:{_bNF&OX>hE/^uP"@;;CE\4kfĉ{11aРK;ҥTr3gPPPڵX<U{vHJՔ ;=%$4Ԏ͛Э{ڗ駫|i22=ZGY͛/{-lᣏZUҲ%%JÀk5_iaK?h 3Q븱7":=N.n,Xp|""uWo}}4ioŋ;W`15S _vm\\L0Ћ&x )*zڕn޼%KN0{,.]\).1qsy`zy1lv-Ĕ)/EOO;..NmX,D(  8r$_F _[Ӧ4m`7oTw&ՔU];'U_U}'N$rt2..\X,woOJJ9p --a ܿ_Hd9IvlVRٴ2^T4%ÆV:^.W;ormWfͱU7)$-rkҧ.]\>ZDus1iRK֭;Oll̟ߑƍ15ڵ{|]lyHW5oeU/X:gΤ5tqT==Kq KK}LLxxcA&VJiH͛/re7b!'N$a` Bww3$"nR履^O/vu:Ē%]ط/?H`pyq^^) C UꂷuKw]PM'& 98paG~{{9:tЯ 4r9R ?>KK}/>Q+Qgus#55| $i-fj}_yy9o4a˖'R?9226m`mBm[oJQ 3aBJQC@HƸqQ,_ޅ6m{|O!Ϛ!/0{cKPJߊ"ΰB1^Kvuر! |?HnnI)iʞẅ́ -x*_#F! 9p mm!!LކTݺ!qs3ՄgSgϞ[XYЬ :8ӸIqBmٽ ʕg a֬w]dt掃ãmĘ1Qّ?_cdžn矟P-dg31$U[.r;;UqKbe,錞_~is ~FFڪCL6oQk0Sr-nΚՎ(--[77.^E^^)^^U^sH ]\~O>iKϞ^6zɋ&xP(u: |PugexVystiرBƍ?#ne])K?oС>cŪiHvƴje@&VƏo Dp-R`ltOlڗ>}~ۂnJ~~[^gO/ÝխL22 H*]KH `Tea}kL\uX,D[[̸q!l~E ꫳ,[vŋ;h1RRԳr qB}hnG`]/w1wnEE=GG#iONN1233NJbٲS z_bcxewk>>=0[7w<=U"&x4on`;o@~MKKȤI- of͹Z-vvܼY};&&իݿ_DAA)cdžU{5_ծ1"™ݻ 3Y"?p;^'< ==-(.P(8w.>}򲠴͛/3rd02{ #( ڵsB__X,d׮XFة1lXGW)gm6mĔ)13E"Onn 66dfc ^z{tt4ZP;FI^^ r9$%'Nw"? .X05U+`0֭;)rB,֭o̪Ug6$$0y>8iRK+?/>ΐ!5?F! +i?)Ltt*..}(+f9,,t+5 w4mjŴim5ϯ3W4pA eڴCՎ2)VuV,%99O>9ccl,U 酓1fAy5lJ׮)*an֭W.K;ckkHjj>/gp 9{61c~J4r4kמ}{g<<8q"== 'N$RTYϘqSǙ93#G9p62SeDEB([[C֯Ȯ]}{OYTti&N܃\:G@Bzz&,]=zlKWڵsRfYsiY3Nm޽UZZBfWՃE s~J8{6bj4<)/g.i_r2q'r8.@[YTff!99Ř(AwNvkP?5vv̛wy:pt27nܧY3k}9{qrfB0r3d66oLVDGq}5SRRNTT,QQjPDfeᇭX$Ӧe?&OKnnZHQ˗YxBY$#Fv.,sR:sFwo|WWS ;9࿁@G3lX^^?KK=&Nl{X925F5,}qWpt4OhMbib> 胃my|9;nUc 9aB(fdr23 PTU^ +JD~=,^}5f ̚P:ef1~|(}tӞHOW?Ռ}1_}՝mۮȼJGGرs8[cǃ3rjbkkCxevuր~iЬ ,_P( *;++}+TƄ {pv6ᣏZۇLYO[!hh6mqp0ѳ'FFDD87x!ԋJzz>&ܺLV9J7mZH$`Æ5]5ib36֦?ΜIaٲShss]h֩no! =O:vtk׍,\؉#U#GZ+Wшe"Y& 99~NJJ~]=<7SW ]=Y}$ۼMZ6,,tQ>6nȑ5϶mӲ}h5O|12w<g`ΜIwoO5յEu\Uu=(>}e?}Mx{[h )x.\P@/))ÃHu7. @)]6j<ط/rƏ]B5e6-==m: TLHaܸ("#X3\NF.y:WUmμyG >Kp!M͍De~~)gΤ`kk@vN9w.NP( $'lY&Kh2O)cUwcGHIO۫t_D1GGa>2dmNX=g#$nzneakkT>˗f׮:Tΐ\֬9ϠAM9}z(FFMpw/[7w6mT^Jl>MZ!(k\`˖ sP R\*::9sT=fd_~ٍi^jgg6RFTӧ4(-[bi ꃥRg<¾{Ү]c,8Jxxcu s@,/aӻx݄;}L~έ[pq1_j R>O_'?^NWW ;ү&{,^܉7z9 e;4\kEvv_g[\ݔsRT5}{g■zO|)͋];g t) I99%0|NmCII9 (jekHJE:l,,t)y"?e|>PMO$P^o׷! JEܹ eptŤtI֭;_mO?]e@$& J$"Ztz]|wwJ-\A}jρs'__ tux%1Op`qlʂU>t(CӃ~S=V.[ =O΍ <ܑ=hq/L>|ν{,XБݻoq`ۤТKv2$ Ղ !~=;D"Qch嗟 _AG$:L}} 7nd"(iK3&Jmw\EE2U|ӦKLeBP0u~:UmP( >>,rrJD$bccrdaa\A~9>A?꺤j"(;QRR^+kkJ/Sw">\B-TqRaaJݴkW ٢mnOaayye(((C*aC/_ϤD1j`4S9۶'0pu= Dk^jǒ%>zyR{k۷矯" Yn@ 8PV^cgg@ff*.]{dfTYS`b":6%K:3~fz@*P(.f6t슻w_a곴l@ܽCBB;wOOstqw ^^lԛ[T,%䧟^ukZ-Nq;o嗧+U;:1~|s6nkJ5K5ذ IDATyW}03a۶DERDqR:!!k9vlHg͚YW*&&&_F`C[[Y+Z(jgU>H$"e>Z ]g7nɅ~z_DZ굅}V8esS12&::>}~ҥ Hb/_^S\{BKKܹ5='t8q")Sڠ]qm-uzH v9cwyOYYD {wwElYƍ e֬Ut,[v ;=Q|B;l@# ߿Zw(,8oTMokmel,e̘P6lȃE|a}zciA! ˳hys;V~r)槟࿾*Y ⍍AU Ɣ`gWk_4~2)ӫ',[vsx} ++}6oQ k?^~ٽµv]U8~< \Jr@.WJ;rzdv$&2qb tuŤRPPFTT,*úr]Vʞ=*100`@mYruKs ̙f8ĪUUUhΝ7y4 %րކ>1`22 ؽ;"e崖)((TvU ϨQ1"HMI.^}O>9̟nb?Vs"W_wYNN VV( r%KNPXXl|"B!Xqn\i KK=ll ظ2EEedfҿ/ |bbU.]\=zZ˖v̝Qi ;Dp-N%=gfüy50_}^*iϸqQj'$o_`]V._JQQY@Vbk< hg3yrkמcԶRZ\W5vӤʔ)?hk IDs&M1thCdJ,1"3?R[Vw8|>3=+ p=]ǢE'U~ -bW))9 =q/\S=~<,_ԩ}KPZ*ג㛳bũzujS5jg Cf͚>wT2ϧzKu+4ӻ'++ZHCm0N̝{ShƑ>j͔)8~rਨ[;{T՗==y`rrJHLBbvɟ&`gguԤcG:vty9^RR(,Tf~ CgΥݻ?~q%v#+ kDIϯNzu"='mپ&O'ӵ>>ܸɜ93&Ɵ&]+qu5];'luy&M-vo33]bbpuU~||zuw^ǪUg+ 誢uk"#ݘ:n:uݻpa$nn >ix0!!:јk{(Dv휐HDtB￿/2 fZbYdfg3lX޽+DrΟO_Xß'%/|TSz;Z>eqV6vMeۼ=CnoiDFz:U?ڏShH_ޯnٳ10 ɉ㉪Im IKH$࣏Zs^nnfR 07a+`*1cBC[[)SZ*G&+Zy@<((R5D53fnO߾Վ+*Y4ԟ㉈X_ 3BM'>{{1}zM5jgUZɹ+R~s洯ZXXHӓP@LL&'bRK= \ttXpZXW!sӹ_&, [QXXy6ndrx 7/p}.=ɴim&۶7~!?z>[oUÆri e׾/3YՔCUR«V/N3xpSgƌp&MڃH$dР~n=jߗg.=E6KjX,dP2kRoOƚӆ@ Toιs㍧9 \R;7G2yrKUMLM̧](c'Hmm))y| CqL@kZr@"p˩Sܿ_sED8W+󐘘 Qzzy:-sdecd9ÇѢ=&LޖcCqLEiIZrj/gTRڶuĉSՑUĩS<ObbÆ醗9zzhB8y2IuBYY9 .. Cq k_U;czzF_ >>/<sA>h?ZVyNLb6SQu^K_mdI/W:ͭ\ٍ1cBTnj3~G5'!;GwPT$Sz{[ti'ΝWʚҫ'sFj]]U6"™ysLwm,Ժp\ ))1uA AH-FFRtty͛c()y9m̆koo Ji̦恀e:4{hmRLM4mjX,ū_FÌ۰n]4ZZx!HO/P+KI/*jovN\X7^_UWXU2O0c!:wvɘ}Cز 7lH*>s];'^ݏ7Jnn <(BP0iRKHbV>0anf gʔO! x1Tzbr Tff2vf6W7Q;! V:4sFFFǎݥkW7ш>}GZZEkҪW//ZG(…iƑ^4B uP'Vة\?JϞ̟ߑ)S?Qm]7⋮,\x~eg6 ڌ… kKΛ(; ;vW_XEzzZ˰aA/%r5"+hҞofC ҔƍMذQ7$''&Nl'N4nl.gϦ^„Hb˘18rdHM sEcoo!F;qjwv;bD ')U<ƏߍȚ5zYf~T=gN{sprڎspׯgrL2S*[pN6R ߊlrrJpw7a\ ΜI楗lpQ%Tt@)͍#8qO2 $L֖_СHD 9RSg̘3H#]ŀ~Hb||,=cT-8T.3wQ΍ /O)擑Q@i .a%\\LǾ linltmn뾪B r!@hiP(˫ KӦ\T1\3c13嫯3rJ1"/1sf;J HxjB:gMbn˻6W ѽ}LPys ZHbKx ꃥ~,Zt5@%y'<^I@e*vrNmIjcU1dHz|ѣ#r}Ԛ2-:D"bĈ lm 1ZCYsըiiɐHD|INHd+ZZB t>Ԟ{뙵 OBB{wwTfHOB߾>Y'O7.<~jųpa'"# 03%..B~PPffub$&" UŃЦ#& DyDoJ$0kV;Pÿ 2/Fݮsgdu[LMuT?BLՕmαcosVG$0z.d2s綯Pgг'7n5UT*棏Z!+e:tkU4'te.LBfÆK\XQ !rXq15T'V s:PYs1c|J~SзOMv-M.ѻ'O|_Y"ss]ϵL&Mj=|yF Zu5k^"0Њy󎐛[J||::bΜ>6xx1vlj:J4g"RIS\\N< l1caBCZѻ9r|V>gE ҵ+%%2ƍM׮xoz\AbbntQ(8;_>>;ZkjDEȑ+?tUS`P&OާW 㭷UP-\x ]]-ƍ HYE  9Yޘ/ʄ V_m1"Ãܹbeݙ3|'/P:5jT\H, (}4xÏgSYB6:bb!KF2zNV~_Q#]23pu5ZcB`\ .zztt^Arr͕wny-T嘓'TRG^_[[ʕ8|=zΝ;2mZZ/QXXNn)((eϞ7).רzޟF,,G+9r''@*ө y͝c*7*,,cj1{v{nܸWW;u]]1D"bk@<=8w.L{{z) UgnnI93 ZrL۶<aaߨ=_tcϞXz7FE ;NP M֊mۮ~}oU]w`<_}}kb~! P(̞sF׷ҧ77i-Yrp'ww\NND"ٸy^ǼyG4J$оwN-q>!ٲ =zx2dH::bByH$B^~y ~~̘mm_~yUp ΞM!,́ډݺ);?V(@99hS\\Nbbׯgz9e˺UyLvV$79sp|*-[:`b"E[[ĕ+(((DpT;w$3-┺[;"7b@|}al,[7d29oֵV'{\^e[Wedglǵk5BO@ϧ:tpf(/V>T-iX{{#~jG%Kpl _xR%~JӝѣѻW]*HƖ-k}DŊ]Yc3>##Ttt*pꔲys{""`-ZسeeXX詎:ura:} s\\4v%6Z`jw"'kW7sYJqd29dj;9|y$EEeI儆rU?uII9{aaK.Y"pw7#;Qqz&~\.ZLALL:惮zynM(k[lޅTC_4jTZ:F=DPU?g~:л'~RJJdhkbdĉ)(Pw;w.ƍ˕|^вnsDbbǸq!zY,INΫbIOC..]\*-6~i}022th C2|x_}o#2$<󩘚jӪ .^L_?_RjL]>ˠO#,錓1[Đ]T*,LMu׸sGf%=zQvk̝{B3=6\ш==)..H)" QϪ0;;# IJ޽ڷw&55N:Cڧ:LNeCsMr͛1o^B(st $3vlNN&j_ˢF5kѩ EE23)SaIx]^5k1eJ~= =V8UN:MkҦccmtuj5:ll }y_5:8cfCl|k6b? B[ gOO~jϷiD?(}}ݢ=/s cmhDyfggmqt4м}zLY"ݻo^i?F5_ 4T; IDAT{-8v,Q%F+^{-[|ӏ`;~*}})54طo Y?bڴCL(]ww?5`ѢL1eJk- LGʞ=T;b K8Q{].B"f 2"LMuh GGcjm .q=M@$0xp ?|{ χP @ήKp/A п_@|||DP( 2ҕl v-.]\k2Ig8Cttj==-6bۜ>B]11 +j4:`hMǎ:YY( ΞMa.\y1cBlp#Əo9~<3g1SBYTinKH ӧ㫯N3w͋Ty9|v~z+mun1gN{;ҋ4):bD"\Al}s/eڴl*}XĒC͘qVpv6$m12D~;;Cut䌓1wdWx.#E!8؆}n3~s ::bcTk-fmUAZe-5[;*h uB,Ң#uwws$!66UՆժ?;ܺE^^5~7lx.]\x:w^ϢE|],,tՍ)SϹs+&%K:[LZZ!V=ZllBBBv}\ȑ;Y#:8&D"\AA [sHB@ClZdkúu/chM߾[i XȚ5Krr. ɝ;P(݃O/aذ@>*B72iʞ[nhs.D(>) fS{{#RR01U)QQ3-\zCCZeݞw4']IӤJQaV8w.""sT_bƋ8;pD=zxVjueN1cF[oNFz%zn-2޽BV>˹s)9_$P^`ƌG".b;;#=(<g--),,CKKıcUseTwɓt^maNVlxZ).}U55 me^@jj[İhQ]t֬9OB£,_#LyC%m['mB77S\@,%m['BBl8qmT׹33e[XXgI^^)))OUp}FŪUhs/l~r={zvh 7?_V'哘KVVf>|˗3bs: q=ttDDGD__N P,#UUp `j*ݜ'ض7!=TDAA\~ww3T*bpNHRq*"‰eNlYdcÓ÷3mZ[ƍbΜj1q8FlƊ˓u뢑_ߋuW?NTÇ+%0Њ HNozVΐ>{2`mСLr$+PBka88ʕgHLa.Y@t JiRL|B7ndt rnɓCs>`?EEemT'Dhh0|}1y^͸q!o<W]«ϟ&8ПHWn틕>e'::__Km OO Ԏ!ff,[D%neh .\H 9wo/ZWS+..[la䖵y8̛בA~t :K͕[PPPŝ/E"ciDŽ {Njk_djE.}X  `a|? ;w:rrJ cooȤIa6o_/ws&M,9w.BBCHO#?Y Z׷QQP(@CbEWnܸϐ!hؔ>}TgmН15աk̬9pv9ׯA1FwwG__BY% >G7cР߸y3_"X.[*o>4ߙ?R))yK…4jpGƍۍÆd iʁ[T?(~;~~`Ľ~SƠNAᄏYSXX7*('ѹ54ӓo矃5`Μ?ɅNLb8;QAPys ܵteب~ $aj*%--[>{yy 5E)+jʎw fݻ9-3̜ٖ3gRk5T! 3/q%-…K (Ȇ7DFlFNN]F(pD"NNƔ^hΜ*/a̞ݞx{[%d}T˜YWŻ6ώ8!r9L,ӓ7hL&ĉ$vgu "qkh $]LJdB ΎK$ A^}՗;o}u&OTTE{7ӧHO/`߾8ntiZ͙]̃EϕNM5h[:urfwM]oǿ "K@P[kӶvaڥuv١j:*(P2e G^@_Vsy}{ NO`h7:v" >8Q5o}ɓׂ7XٳTd@-OBB.v?Ch֤f>iiJ%!!)xz}/2{vBBR4`r7eѢCUKU ѡC p+WgZ#߹3/#ax{i6\\SN_樫-)DFfpJR;ٔnLgkz(j OGG]2iR'tvf|)]5[0sxzzON3x3&d-?m֘abGdd:.$0t FFz;V*__WNQ?Ί7OOkf쌽 N跳3aŊd2Wag{r-skٳq,Y2.e=GZ^7#+VJhs9D"!?wwK&MhC 9s&|lm:?Dm[HeeJJJ,{w;tt$\ܹݙ5s.)iΌA05mv̍)88'A*IIyg%% >6 Pjȑ܅Ν\N{Z}/{)S<ٳ-J%W+=nhw5uGi֘"  [/>w3DLtpu5G}x]Oۻ 5xٽ)5kFG*啾_Xaya(7ftdCm12C"Qti%_|7VV\yVߋC]Ɋ .0f;[LZs W pv6D"SLN_ltTqJ'vߦcbCu5:'EFn9 2..XX{VR/йsr={qܼr}H˘7osӕnNMͧTQ鮍$V`v0ݻkOAލW~9iR'x,\xR={ګ~Azuvv|Xf̨[L{0kV [XԪBތ^Gii;*[PPc*Mc^xaorJ׃}81t ܹxMqt4CKۣ>~0W>t99ߡd:%Kw%a˖I]\({+h޽Y*￿֭ט3 FF2&MPzk".^Lg{baaXl˗ֹs`K'лwDd]])ӧ{ҳ]mw3k6r[%Vֈ)S\X|}HPOEvͥKw(..#00E1p/ԇ/<]]zZ]])\BQUyD aͅA {|s-[t?ogv T vw+#ѷfu?B4ommŋ\X>_P?L=օ7dd_PƳa 6mCuH~R<í[<^epW?pa&IjOrBffQ q=(M*/'c3K`l|/)HTm7ZDÇ磏NPeLYlH?  sNLL&25kFp*| wBҊpp0?>ŪU'02QZw?*tحzǤIy3cvvƔT]\NvvjMk.۶'4SG;6l5AAw4wƍ GGS22 +4߼2Vĉtuux!kgF^?f8{*sj27osvvs*''' .]M3BIO/f CT%MLX$;aQ|yO$::\MuPO IaÆ ]{Μ+wlvv{ԺZ"?Ç3OJ%~;C?R&wwU-*c[1徼¾*_glONN:3Cn%P~A̝ BIrrz};ֽ<^q8;#ۜ?#GP*UGJA* TMBgkOYɓrd 2>`e(oߍ AJnn1űpa tٲ2[Լv4O^xw$**S2vlMBB.q6 ynndd=uwofIɤH~ǣVntJ;w1iR9A<҅? PWe4OFrr.3fxjA~~ W$dZBOOtpIIG_L~N?,$$}u||lsXPgwsvV^ի _%,^|:ƍAbz{;|RARR̓zA|Iyf7AA;wr-AN=$k׎D"έ[~RXXy>|z5#FOSxQwm[cRRY¯ʌۯyfI%JxQV$>>}kVVjϹj0^}Z߾=/gg4wllxлz;9cΜYHc J I婛;wrYp [5Q P377Kll Ԥ?CؾzLJoѣ1ˆW5o9~ү\庆r|<;v|d֬9ő#QH.\AfjT966-IfJ9zr֮ɔ)Hff!ODzjP-Su.Oxx:%% ֭;Khh*nerl jWAU[c=յ L={Uӧc<۷beez&J)/Vyٳ>ŇH/eU8e(7&Or,, (CIKR ߳*:}F5m13#FȨ?cR PBuÊʠ4cg{cgg¶m!aʔNˑ#ѤΞ#+bn !99,- p!>:?af&o_GV> L`Ӧ`>,..fܹY|Qb Da\A"..Ç7w}ILe 1'Nf>Ell}7kOk:T_Oaǎ0GDqb"|sa* J0b :ԕ2kN2;bnOHH neVzL~~ .$|i|h:txʎlv۷3qw;!HAGGP(;֝i<10RUk@//,7&t{`[o EӞbti.СsbeeHv渺Z`i)'22OO<fg1{v 5*}ka$.. ĕ+IXq %fH$UK0iܽ:`ՕVy7^b"#iNMP"dD"ȑhRX`JP!DGg"ҵk[J(?~@ IDAT..W/{fR J  2&gaaڵնBkd:$'U6u+~T5yA8165aiOYB22 INLSSUrӺucx|Z^&66VTQQYBJKÐ"6Ǝ_ϼy8pK&=QݹނhbWiQi<12P@II^@WWJ||مx{Ҁ;#]pI<نTBBR,, KBɤ{z5Yj#;5˛7XXrhK8:IeӷC)ʕ$:vҺ"L\9q~𜫫9۶]\6FuXXȱ1*(J6oTؚ$FJJ+WєU!pRRei;E8GWWJnbA{sH`ccDZZXY]LLL&k֜d„ڵdbkk 6n "11I<*5 %%qP$ƹË/F.epWw>0ѻCՖΝmHLeTڲA=[ٴiR4EB0 KK =jqV.+Ik-xcP?pZbckW}۝:YO,.&ѧOׄ!F`k{bmee4Ō!CT/};SwTر[on;k[[#{̇AXcbر#1Yx{!55o6|Dq&&&%뒑QȩSʔtfG$'t.DSS}Kr՚=ۛwժB#MTUϞ5ͻѻrܫ7?qbJKױ3.!cG &ODG\\,}KK*lgFC)BGGڢJ`R\ :bj[eSS *173lX{~CC=22 HjL$Jpr2@  ={UQ*NluI{ʀ8rq 6Сwo{<<&;[bc."3TJhh& ʖ-S>c1mvVGrDzrX'oӻCeߏ .;s'I[*Ǹr%M&bkk\|ΌXq_ϐ| ]lv 4_JJ>]nk^TxP KKBsw/F3cF G``B2_|1_+0~2y{\矏nuw;Yff!II\J2ss9>b>UZCC]JKL{#-y%TDL|'СHwH"v̴CSJH!#۷3Y#FU{B&2d ]T sL,~'SMƐRI]JFLБ :wo119ܾ],7ߜWbeeHbb6\h̡VСH>l}#j 㥥 IHfryz籵5fNk*+er_ %v1w.6o)QQ<.xc/w..p'O { VLܩݼΙ3q:^>߽֯RSTTshB*kUBN^^5uα|QΝ/оm6iByf7K)Ob $,,5kNrl::,臓o=ss9* ,#A&2lX{y1c:Ϸᅳ[:j,~1,j|~Jg{^wj2M#˗]HL婧v1~o.61 hLnm0}si"fO*M**ݝ\d]z/ ٙ4}7ש{xJŖ ;G,9)[7rwXZIJʥk 8;+yⲙ8|V]&8w.EY1QR@UnF>?zu׮%SRx1ܱw{4=3ƽV#"9x0A c )˗]ٶ-+;nqzz!{`ʡhFoc KK~ab/?|/sDlEEܗKNNgW_#+6nH6ƴkgZ.! TSvѱ7n A*]<;V[ 7o:&$73ݽ;6 ߡx1UN\n7O]t?KeT&Lѣ;8r$#Wq&/̙8-SD h s/ SlNEnp'솧5 >F##MpXH.S%_V[7[||l<L­[HPPP1ٳZ K`d'XoES*K][m99o#J8Kk!Jؽ;={윏=ssyAJZy3Sc,׾D h>}ϙStae6o'+yP_=w3jKt)~ե}+T|9ׯϸqjڵ3ftE)*[|~oLW|K,^~~tҦKNŒ[i<KTrrkgFicnq^|wݿ.>>|.\Hd&U~-M Ia޼=_';gRR׮%Zpsdprj%FZDUXX6##l~*X?OC=osj…Xw, /ny:!%%BUҥ$|}k<_\\KСUҧLm3u iU§)Jłr%IéTpp";w#]\Fw:'NkJaN1mZf;X~~.ܿl+oEٲ|؄63LJ޽-+ 9}:s\Lllo=G{wV=zU7&1~u'..?>͈[ΝaV{P[>ww*<BgvS V׮w ev Lnn FqT,f߮SV X <8l72`TOT|bb߬_~9={npp$Z_vTcVIe͙z]rxkZ_5kjUDIӶo΁l0GysHx;GUR 6'+Pc3"Rnnŋ |hR{T5\̇୷-Y1c۷_{[Y13clG߾nխJ$O2~>0ܚ}IB2UakH7 s-W2xĎ*"T-&&Y\-&00a\cF_Vu+WUnJQU.\'##ux^Kk|۱f͈Z'cʓFZ!aTm_,@"QU RY"T*ԴP|vn}M/qN.6MXj ZŋNBBdXqW^鋽 ǎ{5,8ȪUê}?//kyg'wH0_D+Q]rmqq1֭,|| M%44 o&<L<FF2>0w㫺jo8wlJII_}u5ʽ-P͸}; ӧc IСǪmhEڤ{"N\\6RB||v5vep?uhźuc;¸p![[#>lT Mƈ+Q2,,ݍM"ΉĭHNBB.'wr.7oL矏Y0m'|0kٚѾ cڙoӪm#hވuwoKǎt`ntd.eeeNjjŋ0bx!xz"@i5@AA)11Yoo.A-g`){oxc޽7X%eax wkYHIIzT۰Gw[tDGGBnmYd 'wB_ܹsy`s^^6\@㵰3eb2滲{w8_Q5H\Ib._s+?~> %}vSS}fz'#ٹaqoJKDDgI`<zs3~|u^|/SS*U[l4})**Kkת{vE$%kUU||lqr2} Э[[6ocMQQ&Boڷф,<<[|07'))S~VT5kFй (JrsS%FLiXWt Lъ@aa8q'…IIɯ$vBA7TRҩm,'.d2)J% #'5~* 15'#zޢ̯ o577 "" ñc?;۰|QJxzZcggIT/GGS2'BVV9N;"qQJ?X1dH;}ԇC]N2z:gѻ=2ڴ1\f $$dsʳTD h cc=@պ37v5ll )Ю);/~u:E)STJRAbŽVk/ AfbŊzM~ͺMieTKJ,,DsAB52i8 75J$ Z#(H8S&5*bmL@BKP(r,? /8$#//Xr;Z5XJZ!**mۮ?l:}}]?ޣ)dt=ڍҲ Bk&J8|8+Oj޽7嗩M^x/͊'2rd{fj1ԗ`h(c!DDxlϞ[Z5AȑnlLHH2&&M;~d r|oM*A+G驪]mLV ҮI} ]M01#'[[#||n?55ōfy7{7 hSb6՚^un5VVM4:AQ߾l01c8v&+tJO>S}2YZ{KXX*#GU{o woV_TrPL!6e8VWo)tu<3gzlʒ%*o_{ͮ AK8:B L&eHVyUˏӻHNpZJHᡇpA J5=)._}uCVNɘ1J<<}BLL.$PTTO];&v10o(,,\jٌĬM3ʕH$0qbG DA+qhY3^Sc`KÓJIDAT޴ۜ'Hݻ+,,cѢCMБ]jpTNѮne;O#]Ahl> ۓbMҀ e'i"\\5ʋW $ 66Fٙl/..;Gtt&/'qtfggLDDfmrJ_ѣ""Ak3t {;p-6̞/8˥Kw(..P6͓3X>PC4ބ=}Ox9ֱ1d\LiOO&N -D:tBOv̙^892A'Zcc}v옅~:uJ%a ԋv} }Lqr2ETָPSjS6J%'O"һ}S:bJzzoHqq99s"+H3Lسgr.ffUW=Ah("- J>UK  @AZ!|Lѧ^'AА#G;vPAhD ұ>; 4 @4cG+:vA 1  A  B"AVH  @AZ! B+$AAhD  A  B"Zb_}Ç#5=A# -Ni{!8WD 8R pR+WR(#Ycc= PAD Xǎ￯UD׮̙ヮAD  $,- 8~zoBFF!}:жm۶PAf/22+2lX{LX:]])?8[[c ů ħ9;2gi濸[axhzh ZKBrq\Ib`g~i mjzH ZMBϒ%9u*&.BH||666Fxy}{sMIܼŋtlC.5ϜrLЧCRhh"fΩS1t\ر5=,k Rԏ98{~LꉕGxY<}w,d2). ؎Y*w|NN>s≎ʀg…iƨNMDD:C;z۶PRRVx{{Sf쌗$698Æ6xZ hֈDM,}s4=DYv}}.ҥC40ꅆpj 66L'?D}ݺ%**6mHNΥ_OʕJobLjn93k7FovL5ʝ3uF__uVȟ^ȑhVk>}T^MF=x]ӥ*nLJcee@۶ƸZaCX[@hVNJ@h622 xՃ880rd{>4ݻѩU'={;[T|mˁ#\7FF)"Q%pFSXX$`JZZ~O"Qߩ2BCSH5̛דY:rdLٿ#޶pzy3-҂Y,4R ˖ 4=4).V믗߉3zݳcG+23Ɲc+!&&ΝeZ/W8s&_ЌJ)-U4ȹ6m5ֆxx"@h6 iGǎxy0yVpqiIZB=zS*$',rHT'w"7oHddANָcoo%ڙQ1ӧ{y "yϭ뛣_?kSzzR\]Ukyy%"@yy%?GccFxx*OW;td^kp Kl|Xj{ӧNŲsg8e^A.FL) L=JK>šC'rTlwaabccHHiBC+&iZZ~l<7^C(Ō9+**HgO;&OX;y`@9vnni˩S8ܹsT~Q Lh6{B^^ svl￉R$"" &3s{lr$ ::Hd2)ffrɤӮmρ]M*@TT&uz~!ίi*GiS0:YcG;NHI#8/z= A+0l+stӳ|)G=ڍ{oVzgcIIƦn5[lTw֝rL6 ~rFZsߵ+[dGGG0ֹխ^;Ο'11T}ן| Juyn̘Qz$A+H$JݭH'00 (8Ps2ty3UDDdл= 9<tؿ1r %J>{@R.%[oL99kz蒕UĦM;p }d@<=m44º6lŇk<... x|?xCY3̚>͹sOSPPŋx{OOZ@vv6M8:1o^>?Dff(..HI͛/sH4/__u-KEh)-U۴-Cҵ-/Wޙ.\FvɪL*ڻט(. "Q@Tt֨J6ZS661^bcKՐ^>X6V4Fѵ  hEJb[EQDX~`w\h<g ɓu` $I jtSz7X$k˳a vL+V$o_?-[8zJԹOaDr-X_QQZ>C6gTYپ[ c1N)SZ^CkN1/I6LWYl9[*qژEu42U죷 2)3w̖{]Cqq={.*3zqB{/ݫѮ]5aBXDQY&8%q)BBiԨ`GO.MDD)>~^|1\ow6Bguuո/z[]iܧ5thOY,Zl Ԗ-tv,߿,tοu*ͽ-w~Qllrs9ΠAV]n+L%wTj$V\]]ٳH>o*323(22D=0&׳gW7]ZZ/Q^>Waa~OZ6CuuVmOJӦ М9~ꁻ}e Z^ H.\(R\qX1N˓+^\\JJW_e6HXSжm3/NRU{I[`m{݀+ N^cǮ(:[ٯ%%U:tS]Gۻ uFӽ=<GVywF{hyxkaWɓו}S99TTjӦz fwlgX:|7ee|,$4jT5kU``WGO'Gt@6o#o/')$BCEeJ-VP#-RYYG/?zs.Llv_Pwhd:{#퐶vED=qBYD͘;f:zpb*,,ʕ) :^*7Y,ڵyglcCRD]/ݺUzxi߾\eevkEE9?1c`qI} pF~d'u=uyyzo5o^ҮHj\R5&fDrWJY!Ip:VUwX`gv__O%&EE / RPP ruf||<#uFo?a5OO7N{voKSF5GOnz^<__gVg8Vzi;v׶mxcgd\Ձy-~ݭjj{EE׆ So_󠈏VBBoGs պuS[4 SKF:z->>[oqPl83֯᎞c#AUU7ߜoB]}~ܹ^Q\ѭ;-5ƌ Ug/)ҰaURRz]}\ ||Mz Vd1 }7f”oر}>2;G[Q($ֱdI6WsMhi39ɉO RgKP*BMQSaw\~xV_ |KDcՌ ӧGH|| ;v^*֭u2sHfΌBKaa33fDVs8{VV}˖%z,*jf͚DD(yٽ1#P($B.W6-6^~{\5 __)Jl9`f(j9_|QBgR>^̚SW׉L&a9DE1jTYYn-ٻ\߇+IHPsm8 j@TWU"'AAr]qe\bқ9_}u??]]fb!>>R""LNg$;FɆ ɩ쿡(( c[d%nNj7g^99?-II!\w]/0O= ʉP^ӝ4S'pp k.B. Łjg߾sNn/v4ddoݑ~\:W_]g7U^:TuDFk޳vND,!Lҥ[93gZ 7ŋ A*\ÉV\ ^Lvv/x3*VDHiW̛ܹ;VGZZ(Ր;L!7̈nϐ PVO h<~e$&ysLIJJopC,Wgs $DR__/͋C,%KPQc̘@rsk))ifN>O>5G԰}{ L!/͛d  k (HARR[#bnwp`5!.DZ /̥yd >:{@iFrs9z^k?zu t6:&Lt! ]tƌ^T*/V;bC3miZާ.vF-Fgń+qddh4ICHgjiSWIRR˶\oFˤIRRBX8ʋ?/DFZ$'`Y{DX/;w(ǿ%33_D|f47{;4ԇۙC-WI{}wŊT&MdԨ>iFlY2WA-vɩ̙^f{\\?~kL̙*+0]먫`͚"Nl_7a4+!;x5gx\&LIYY399UkВ@BpC&[o[Vr>_:,Z@vva-{IIFpF-j'TjT3yS^(ش+pVT*onqT6jrskؿ@,Zс|y1[[뚢&4%v j=o63g;/=:W9Vj.xݝNoD"bѢέݗ_qdK&1rs;8~2֯&'܋P{(w8u3bE3q`5_<ܧ9_ο_"{eݺ)}:L7,*w$0<@:>(1$DOgr/~(NZwSZ** xx/݃A. 2җ{+ `֬d21:5 <\_XRRKLAAMM\@ @mi,֭ޫXhlHZh[H"2k'p8ؼoH1//?>@>4 ad^ZVH%--?0K&3gN v_~j(?Z=f #o# "~fϞsHB"Yju "9vޝG"F端bH:;ʹX#o_NH­:Zf"~*gL^̟NJi^Ԥ'-o<>Q*5][oa@Mͭ 11ʛGƩSTT"  ܌7&..ʻr,&*y)}t2fklʕibƌ Źh/^Uij=0Pɓ |I ~{Fmm;3iӢHN`jd,; wlR[ۉlϋٿ99?Khn6  0m:%IZθqZZn2d8XkZ~93ӧn'4TIZZ0ru`N 7"--6ENN%>>BEii B 9vXD"!g yVeI 74f=55Hb&N԰cGi&0P3y$ j~dtQ@W;Pe47r o8Ϗc޼47̌·!@UlץME J6n{ p}3~|f$7￯ ==PÕTUfd(Z~~R0mt]pbˬ X7Nzj/MD/eH#b>:@vv!].xyXn 2l6"{̅sW??MhO?-"..5_"V#Rʤ7gJe<~7P4##} jo7SPܹN?TAA=6튃DC*B!a*ؾp%:HK cԨ[o3g\.qG_ NW-[  Sgp߾J~:`bc9qS#1,=ʈ*yd*7PVeq|9&N #;e˒E=֓Mii ^^"ƏE$|!OK1uj4f}/z()0OXȶmEsڇ-~~l6**Z񣱱.Νg裓3xEֶP1-=>8Ixŋhi3z? lh|^9%݂6斕7cFg׮rQ_ߎl0rTqx=۶r.j*,Bh7(F p*GQRSO;g˗;<@TnK੧#8X"x5>>R΍% i1_l^ }, lJ6- P֭=ZKT? )ޔPVf}zhlB{wvZΙ3ٱv*v,%<܇;(+k%8؇DWƗ%KTiT2y'˓ٲVF@RSIee}w 2v,6ܡ_Kx  WDGxyg>õ|M9B!̚5F=2:(,l0ܮj4~DGwn&++N5-Fiu.r-GԱdI"))aΘMRR0WgD.T*d* Hq@ ILt-BI'!]]i5|@ff8 AC-vybҔ~n/WGcc_}ZB!&7 $'V$?scJ%}BzKUNbbz彮m6--J)ry\.J*PuuDEPl83O0mZ5+gǎ2yfR'6. V @w!'vuQ(?w$! 8q?.@"@,0>oׅx{{ƝFՈ`ab,f`2j,Z΃fw~&'++Mr8{;RSy|h,MD&N@r) ]UQWC}Iii3 >}z/48v5/^~N5rh-SDr@=c w9V; bbT9#>>Ξs)+YDGۭmUCb΀@ $55Tv>0P3qbF+ Eٳ:ʴDE!\v~L@uu;z8wNGd~~^6!:Ò*7uuwIwttvZ\>G;C"P]-Sfddh\^7C:ZZ L6JJ@,rt3"nIED""—& Duu;مu>MMz^^"d21gLKNLѫLzziVLBRR0 Occ]|bRSCy/7.'ΝNg׎lY6{FV¡^e +j3z:zbȥOAl6:c)ί=[oMT}jBC}{YFbؘ8QCS3OtZ[ =nwin֓rh_[Ӄ~^"#;81莐lFU'ᰳuk;w#%$Do/b9 pa<^3{x::L{w+jze۞9azc;fs`;:5nv.wߝ_PYM7qͣ!v{B.0s ҙ4IX|NFyY>" uuxq+:TJ a̘+֬$1霫YnK_ڹsmDF-u[@ls]Y8}/ݗvYɋ=;p ֬ s.Xw'nqџ),lb$>`1 >O#4Z[ }m:}q P_߉+Wt7B y•]1֬e˒/t6 jt˙.X+<6F&T˙3ګz?0]ܵc# ++N ]곅kn6-ξda4Z|bP1RRBuTBd~r`0^Lw]ֱҡƣ:Qa9^?X"_( _;vl:? ,ɦEEEMn?~NEEDWU:Us9xlͲe̙}/ _~Yƫh2}zj235=%MF@lq91D̀\ɑuנu̓ݔ{l)wE;nJl7_?JJJ([ryD"WkG9x 7.矟ˤIMwP nn R<>^|0RZihX綛!'?Dyy+2uH,uCF$#eӦz"erU"Μic'NԳbgbc98qɓGǎq㍱3yi{bq:<( IIy@@mZ֮s<ڼg.DZ#ӦGN -VJGNz)yZ*RW<AD"r@(tx>iRcC6]xnKYv Tث~vϙa<̰fX3, a0xa<̰fX3,3:=UOgN<+'~=ۜ-G?j`GIENDB`qmapshack-1.10.0/src/icons/hicolor/128x128/000755 001750 000144 00000000000 13216664443 021231 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/128x128/apps/000755 001750 000144 00000000000 13216664443 022174 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/128x128/apps/QMapShack.png000644 001750 000144 00000025417 13145236411 024512 0ustar00oeichlerxusers000000 000000 PNG  IHDR>asBIT|d pHYs & &ȰtEXtSoftwarewww.inkscape.org< IDATxw`_MҦ#{RJBX6ADzWP.2(,Zt6M4G$Z ھ&Os9| +a6 `tsK0=Dts3ؼ9k/Β%ѷW4ʯ {t -.N8t -.N8t -.N8t -.N8t @ff%Dzzŭʟqۇ: #WWVݷ/;cɒ\ZX,Kwܤ9-`2N.`L+2<=r F@>nDF=:w=ҥCX>/gtFUPVkDB!ZL&ٳÑHDؑReÆsͶ\Jrr) L'&Ə;IH(`/ a dgWѫ 'N1loǛL&*+qvnݦYd㩨gҡ8:ʸFG$U`oHM-h4nu''kΟ/Vǿ=\'9p SU 66 Bg_|']wn4=|y7`  DvII)v]XXK}}=z8M c0+ıys z1ўdeUkFӀZ۞p6FcӖ n)@&3t~z[SIN.%8š}XlRc9ҟ/u}+F"uW&xs GmĢE? cʔŷeְf);p,$=jf eժ?BBIH('Xs E>nm*w# ٱ>\\lJEz-wP_@ee=˗[nX˯ݻ3Q(dxycmm2'^AԲo_*yY7{f bvi11,^??{ OG 0*Dff5L&fg!LJ~m! 7xDFO?Δ)=;uޏ>:CAAmEFTj0!r5u:_{LB};G{iض-K`#Gb0j DEyeT*h4w|Y]6䓳u;;I=~|v̝c ӶCQZ\}x9x0[Xő#WylؐĨQ&Fzz9gKwCQS?Gҳ3;v3\\ڷ3E2Z{}fʔ k1yt"S 0L uShL&y|d^&<eG@ `¾>=w T|ݬV{k$yaףξ} 7uuo)6g%2f̗fh6[}%<>fXDD~~wmҨkhGlm%ih0ϲe9y2__Msrf„`QP(d|9JL?W@ґ"\L˕YsիO K>@@Q˗+0L'66|#Vk7GgX>X[[ ù>,6]ن f腵R9s"UR^^ǁWX(mX?<F3g 9r*Çz!BQQ"*^{mT_VVk֜FVD…6̏J`Dbb1DB{Zf eݺ3AYRuV:̧ǞѣyIyX1uGpP6~x8u+Y^/(…>7橧qh.zjjY4@_gѢ~dBf2cw$$TL~?4''&vCgժvtN'=cr򠲲"IIܙM||>wǽnZV8v,P@AA-Vʪ"+#o!5u/g쳱`2ܹ[JEDj=311XYS,gѢ(GwvT 0YY\Z Y$7yN.,h4\Jt'nnMk7pP6YۛR||yA;Kjj%%u7GGgsY?E5{\?E~ /^j z$,^܏'DT;.S{ذ111X>C爈1y7u>mْJq W_!a0غ5իOݶ-^|1 eyh4V v25Vp}ء. _N=o5 J8u*{!jd[o{{)f7iwo7/A>nl~rBBߓ @P#Wg+ߟuCFc`„ ˑ#kqP`BlXԶ,r>t}z@ JK˙iGbbA%'"mKcӦ KdY[7?]wk}dO\# @[o#*ʹm++J< & 7;3 e(-mW]VK]G7X,d߾HO/c0_Ο/%5o95bb8z4BƘ1A\P°aVs٫9~|{{ zןh4ߝfc4ٹ3pW &J ^^dfVVNX+j<=mٴ)3CIK3OQWVHiw;6OߣeUG81qq-Bϡ_?nd@D?Y se4vLtLLh3ey񝸺0ujIIߓA9wWW9qqWHI)YƠA^$$"YcGz۶<=pbc3ٿ r:gPH7.rf8p G\LZZ9n8:`2ꈎ?<``oN#66Q_ÆRzPWzr44;9mZ/j١16YUY ^2 ,  ) x0p7_Lrr uu.gZ܈ϧVǖ-)LЃZ^|122߈VXXX BVIll&Rj=#GR騭0mZu'% Hpnn6ᄓR&OP($)Cs_Cbb15@||>ʕjJ-11Fjj%Tİal~ LЃ v$0Љ={.7rFaa-~; GGWG.]6DG)(+k^R⧟y챁\ZMaa-K'ݰlߞoC3Yj ϗfÅ L ++z>}غ5K4)IzүGtk(,|P_ⲱPR~VV-ў+5 \2::ʨ3iR0Ӧ`A_8wi"߆wźu8pu7ǰxqgwm-Jg|r0 FFGP@Ϟ>,fe3kV8&ɒg( %nl9dɒK䈕ՍR#5!%3gػ7}1Ÿ>xjHw*+GB:JR;c~|a|93 *+<^,۱#[[+yN~8:LGUr|oMf޼>e.nqt!X,"!!yݓn`^ &<<ڿYnf.S9wu7n:'GwCmk+aٲhvNch~%%;S3uj8wS]8Fj +ڵhs#akk@ d2rHuPK qf?ٿ? oo{Tf `0-"э[mm;6G;9Y3zt^zzpX[;;i2--!!Ζt~gǎ Ξ-UN߾9rS{!!0mZB xb_|q2~?cr8wQlm%̜Ɗqړ|I".ӃkAdv=nc  tXvvR<{$Wњg wRRR˩SQSSO}` ]%:THVV%'j T e#q=E OϒpuNJ~>aX~9"s/4LLyy=JbBB3'С>89ps)mbyd[UEvv% }pADE#,A]hrRy+ Z(yYY#GP~Y1sf( 5  1̆AT;csrիTVֳxq~zp&ĉ<^}4c1IyXR۷_bٲϥ m.^,POs"Qnn6jf 3y9^UIjj9W_G\Bx+ɥKpreeEEPWjjtkezt"B9ҟ07>,5l0+lm%-&^<`?V>Aލiᾼ̦ZZ#˫ɺͲsm%0hutӖƊ޽ݨדSMAE~NrT;w^`02kVAAsJb""\IL,A3cG:uVk $ąӧ 92Xȅ ɹx غ5;쁯}糷hQ(;/\M{`֠PXsb1u;R騪4Wp-roL\ tdL>,}zgGll={ph.%%uvd\.OJKU KL?g3`aalp gء𰥦^P(pE*7~GGY8p  FKǾ}Y|}zaGH$"KDC* WTQ\ݖ\% (tuPYYX8ŋkW3gϙ3S:t^9=8LǞZ jPRj4}z(55: qWGx%rWWK5$={:[G~}"PR{h(RDd6^C*khTj+VS{dz ?ȩS8R!!5L\\D"ǾJTM^^ ;wHI);Z݀H$`ڴ/j9B(˩ҰcGpxןHZZ9((&z23u@,`D3 TLMb h*̙"5lْȑ8ۤ>pq's]{Z"#=M TTԷZMN "ǏXlmTqD}f$D_' IDAT<%#gN`esg:snKA^y|1g>°a|+ 5++1u6+w6;nMrџXĆ I-+*b$^Ks7ekynky(JӦB&7R&[K;˝wk=CVV%_}u}:5-".s]-:CZZ9S~IJjZOEsd?yիoFPZ2/\(ӳ ^` suu dd3uנA-d۶׽& wΝj e9n̛g??N/Aͮ]*&꫇ع3P(hltgv "t46?Rhb߾,d&=gN3fRPjK QR'1pWۍuj4zvnI{%ŪgLbע=YA&[]\lx)sH9sbF<''kƌ lIFg mZ}ˋZ-Cz}\̏?{Cqiz"@`q}[A$¤I=peɒhd21%%uZu YFN)<|ZFoC_X;;)ן[ʪj9[ ??۟~#wZ5T{`Ads_àAKn[G522*U^ EwhS1MmJy1̞m.rcBO&>m Z.޳a͚hKTr+ eDKX1L1zk\SP(/p 66Vj9w]#+'СNgZZm*'co5 ¼y}8}([v!;_=4PȰ~P(` iBDV5BpO׃i"7`_D7_D"AMF`sTWkbkkuŻ*||eMS^_w/L믓Yrt6^o JHĈB'̺ug;PrrdeU\Lp3#F_w@QQ ʕ#o/.V qL!yy5ኇ-~~̝ Jx\PⳎ?4޸\0ZH$lL//[|/4?nMG"ti,+Frxs^άY(*jիRyRAA>?m6$RPū!K7.#y ŋ%8)( iSuU\PBjj)Cwo6$Tj덈B$UI^^Xlv9>]&Kq_}uW˥hWS h4[ tFGp]aphnV̙Q(Z$!UUf;kӕ+mtٸ1ݻ3HIy]Op)()QQ]m Oam-7b!IP&'>_n5g _{XG덼~oq5DN/|wٰ! WW9IIvm~~L /! 5{q~;V(6 H~~kY0~%K#Yq=ḹ"qv&*ʛr7F]vÿc;ԟS12g@"jU*Vyf7X7K?'K8t -.N8t -.N8t -.N8t -.N8>K77_h.Il~JA75jǻ>IENDB`qmapshack-1.10.0/src/icons/hicolor/64x64/000755 001750 000144 00000000000 13216664443 021067 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/64x64/apps/000755 001750 000144 00000000000 13216664443 022032 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/64x64/apps/QMapShack.png000644 001750 000144 00000007766 13145236410 024356 0ustar00oeichlerxusers000000 000000 PNG  IHDR@@iqsBIT|d pHYsFtEXtSoftwarewww.inkscape.org<sIDATx{\Us2("36l_쪵?w_+_mff^JlD3$5BAea}cbrP߾̙rs9H*cGT\'A۷eİŋY$`ؐE]]>q}-@_Z}}l6Fͣ {7 5PYYO6heѢ-f X,vBB|HIs>SNoy0_&Of޼}6/WVLCd#5.m:Ϻu'gKiE7vmb *6le^VݹNN}իSIOQd,]z+򗿜GFDuGanxK Ą *p8VY:~sZ228|8]FdŊQZkC2e0DGxs8Μ)nx( Ζ-dbrrXW7ġCy5PHx~q K[ujm.⋧E\9ScILDr8vu2}zv-`ժoxj9RBBL23x͛ϒUhwⷿLyy#_Aۑ_ zۿ ,̏F׿v[l!8}VǩHML]$M@k/ހ 66#Gu%Bխ[7ūc y52d?))g8sĵ|}6v|gZܸG$F֬Ic׮7@s@QII<z33g%#GgkKW^o[Ʋe#8q_|QIj5t:?LgڴpN~ĤtkDmmmm|1cy(]1yrFG$?jmK'G{%RxkצmTʨ3+9sHLY!%))xRhyŊQDG`1X,vR1x{;JŌ՟6V{`4ZsnD.j՘c>8߼Zo>!?ވH$Bն1fBC}WSKP7hj2"..Έ\.a„AxyIqCNg`,^<u\ҩaa1_>OɡCy(-ɲeh4 chh0|9s!16eT28qؕjHL ̙R[SW_UE||0gGa: УnEaAxGyCyٱ䓣?>ҥ*22Jy0ʪaxJ0wPD"0lgxT2D"/Wb6ۈڵa2n \.bEdb ~ETvD"fc6ۘ<9 F*ٽ; ΄FEff%f +Ch05pJkL\?AUU #F]%.RCxG:5H//)))IDEi0HV.=޽Wʪ+F3vl(Zm+gϖp5ZZ,45hn6EZ,vZ5+# >wU?p,^obٲx*+ep;WTsp>Ϊ+[&Kb۶ ۗjx+\.ر!$'cѷiQ]~hnr{mΜ)q}7llzٳ6-U*RJwo_~,(+k&3 Xrt| RR!"¿K$%E0aB(2 c_`EsBZZ[x l~x`6zmܮl segnǎ &w Yf9xpi`mp;t\.jήA&PxӫQ%K:y}ON29  f޼\J}v¥ 6ldcذWk]qHD5O/@ B n}wpH${fdeU߫{ d:ܹQw&rIIA̚ɒ%qHb֭;W_`;\'عs>Æ-^7@VV ;v\}N:bxQ^Djj!Fu_Vāy%K-ļٳy饩7ЃXlT*gرo81 yŭնPQ+l-OEE3ytb4oHKF[Kw_Z(,QXXϦMgy9(&;ӧK:%\& ƫ b?{(-zO=p}-@_Z}}|/+DqFc,:IENDB`qmapshack-1.10.0/src/icons/hicolor/256x256/000755 001750 000144 00000000000 13216664443 021235 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/256x256/apps/000755 001750 000144 00000000000 13216664443 022200 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/256x256/apps/QMapShack.png000644 001750 000144 00000067274 13145236412 024526 0ustar00oeichlerxusers000000 000000 PNG  IHDR\rfsBIT|d pHYsLLҖtEXtSoftwarewww.inkscape.org< IDATxwxSU?I7ݴ@ t@""PQp/ /DDU@(e=ZF[JKtϤM (hѢiW= nn>(-Z<RSqwN1EK F+hih--ТZ`@Vh҂ -ZZ0ZEK F+hih--ТZ`@Vh҂ -ZZ0ZEK F+hih--ТZ`@Vh҂ -ZZ0ZEK F+hih--ТZ`@Vh҂ -ZZ0ZEK F+hih--ТZ`@Vh҂yro+KRF^nLx|!J᧟.eƍaooGߎV4\E88SP @!Z=T"93dBNNnn昚3,Pe1lOݑV< ee| Cbb!bNXd׮ӫFFnng2~Nؾ=?D"'22'nѣ;6]ji)`))f8D#)ذ2VE{C}X1GÇSXx ԠJFWWoN@-];@Y[>b/k׎Cjj1i׮D"G ?ArrQQu&?֭ B)S:"{:`mmGKg~% 1M;ҊHZњo2{ar2:uk/(dV%c\ <S8r$icCǎX1fL;v*ѮAFF)Θ2{n+ ᥗXӿ>>$֬oEPس:3aN>E"Æ0}zg*+eVgTZåK9|__?P%lk5gD+Is~'a`p-4ԙ almؼ9ӧ3$%Pf9GS2c5&$36Kx#i./f„̛++0m.]{:vgX[" x{@TT..j3T*SS<IY*]8뮎6=ziANLcqqy(*kN~q̛wwUYx&^s[P(HbbrLqOJKF+^ΝE|U_N՜DӦ^8w9@66V'@e ,c8EuV&KϺY $ܼYJMu{l-RR B<<,ppxx/NJj6oҥg))z6[;DGpLf=J^$׭+99H$ >zrgΜp JKfw||>OgbJ~!ԓB^^%SaZ{.P(wown,dɠ:B뷎S2 ̚NǎMӂVAEu.!+/x  ⣏aooLii+VgJ5 rdÆ88f*aQ eK,qqhl QQXX COVCn'rD:˖  9rs+u@⦳^XZ ᾴmkd>-6n(a8b)eDGgSZZͱciYsV%%bcc@>kYg=aB{/AY뜓_Iii/? bԨ6&䬬Oǜ9G8xOn79bd$RN..tDff饘qZ1dw)ss=D"!ff ر4""0=Ne`h(o_|m̬KgΦ8;0lX?t)[>I̛w̢EZVJ; K/{"^{-MWkOw^= F+pB-$7Kٶ-;`ǎx''SYfڬ$2hԮ55JD"bBZHL,;ΥKTUi*b=zyx{["+;y'bΜXrScX>rs+3(o#/]]R}۶ѣ:өvW V=+跲W^o^ڵ@Ҥ~fsF&a„9v,=?rs+ǃ_$O~]]! O(Jڴȑ\\L \]MٳEJ%˖ aٲnmōEd  gVjۺy46\ךM5)IK+fڴ4&@CKE"QS$ 33{n AAC?8970}"Â~52W.WpB6Νnjeq}T;Ǐ{w]܀^jL72㏻sgdsϵAP63ݸr2]k~-eeռj ֆW1iR:߄D"c޼cLAzzOxy*Ww'k5L?7ׅ :boob5uԯuuE9Gy} x ? z͕]35f肁1_ݯɯs7d2έx/~~᭹qC MN$&2{ad2~;BM7T#G9sD:C0b/ ĴnmCq pt4kW:}t⌡o9*n(jcA MEǎ|@ڶQ=ɟTȔ)qw`Mo\jX,H̵kYtOyO>Dκu#3&9//NcfTZ.۝GnN3cAm=xj\ň˫d̘m׿ vd۶ќ:uI:bfB;vıjU4gd6˽ߟȅ  i y6ywCPrMJ5/JںP(#+ᇳj&ի0`Upztkrs+3z>JNep\& /ȑ~PJ[aiiȊHO/!;[y(J%NeWQ,XзN8Rƍ"PyJJX,N33=c<:{`99L saܞިUGuu  | ;}a`B|F99ʸq;ػw,>1[e~:9۝H" {|џH$`XYy2,>O\EllǏ1f6YGQ>#f)䡯/bg[c(/fȐlO"D>{==Og`kС>ޝ@uu=|oۃM'D/zYƱcitd v숧wow>$ƛ-?LnԹSaVrҹB@Ijܸx"p-cXhRBB4_U+3uJxSSޘs{"ș6-iB߀BDWW7<{D5 Nݤᇳx.pi<=-10йgLѣxxX4UU5u4ڟ"OHj$b޽ Ulۦʼm#Z5W]]\yJ$~~KW{2$9eem:b}7ˇСF*kCfFwߝaΜ#=@jS,AvvB enRZ*Wv'fqbr.7]]!yyӪmɓ7Y2z,\ؗ" C d dҤNIDċ!V\cӂgi _ooK\\L))bލqsp*];>ǥhUF&S0|fnleWqt4aѢ{{ss3gÆpr2ٳ3{a?p:UWm'\S#P ,_>™4#Wbժdf1ojkEQ33}hʌ1cڑXuy0`L>xzZpVeƺqudbct)rrs˛${㠰P”)su̪E"h)J%7?͛%irL;6Z˝N{E"쌹t) d|sTBɕ+ԯ?(GOؙ3R \rKmY:ݻP(Y*[L $ N}X,D"!)ՌJfpƎm@=s&ɓE@P_T߿҃-/Jww&~=wwsuӂm-Oˆ&%nEcRR?~W"8ؑ{NjjPS!Z;t_u߯ saݺo_"J.]\qtT30aԽq-6nL߾X[6 w`oڴ!7 -is]';񿅝;sb)E=s:IYY5s!-q2%Y?QP]ypWqw@,DΟ"&&/8J66NhmeDزSSh==݈cƌѱDEݬwSynmM1d jA.9F^*o(1g38t(C}d13xNܸQH\\}Ϲ##1a_xB$ LAQjre3߉aK?_dذneҙ2erR&O_.lJ;˹jڃQP^^MX ~xjU4?|Kiddk,c۶8<=-15%7rFF _=GB"ӹsÅݲ?rW"V181< j\R+JSxX/> hdXv7WT?q&11990yrG]Xdda 1u߭[LYᘚvwŏ#G1rIIjseCY2gfrJ.ֆX+IN.fXqb)cǶXDLL:<9ڐgT=+^rmT*<<<HO/ 1rBx11gfbccT*O&@MIvi(j(ը駇))C{f KgQ*\MFF)R qr2!3 b!GD̅ |:5)'?Bdzro01RR rʀ.]\ " ^h@ Ŕr= s%?_ BeLMuϗi׮]OH8{6r1—+,[vB/m[{ K''S0W3K˅ h֖qX2J%l/?EII{}{;.]ʥOwLL 0БW_ݭ^yvo0~|@%y$PBddj>j'lLL';Yl}8yz|iO^|3gѽ/jرKdd*ynmCii F/lYf66Fu&u4ʳx՛'>RUp343ujӧwݽ^k ;ٳ: <|jq++C@ܼ*z Y/ޞI$ruJ3g2hʜB))Knn9 T޽9w.7a`~Y$̟Ettv >><Z35gfrl&$d lm>D"#4t%C.W{||rr1'x~yOob)>>V?΢E63gvU@'OHQCC1bIIy| :ur/믗4LMشi}tkUggQZZuߥWz6/mXk()֭ Jd3 wes*=P\V0cde'XY_),_~u㭷:ڵ3""7^AWWDjbco?8bbr!'@BGZZ l@W_{ . Ĭ[7I">MGG)gf]Frr9ʖ-С>䔫W' tBdd:,&&ATdg>5bÆ(|}gv|Mf7~W{/__k(02cooLtt6~n[o#(ȡNS>(.抡`۶{DNLLN~SHD ޚx,Y2UEp@$hXmqs`CuOOX\˹z2Jؽ{+,8΋/9ֈɓYR+̉|քJJJ̝{}#ە+$$L(G]k~I|dII)?nO$%7':53{XCH._ S"?3fL;(J&Nبtp, )G"SRRбcذM.yyMN̜Fw ZzSLF:p|zzCM"~|aAvVix^K&S 曓u ??EX<8[[b ׇŋgwf_IDċTWpVE''';FLL6 d,,ytT*۱B.#~7ΞO#}GO(fFغ5^ܘ1 5.T>/:Ն۷F*;32JyVg>Nil4<=-[;@;tfP|C3**ٵZ͈ EMͽ^O ffz5+!osk22J'w_?4ȋM 0zt[Sǀu'''S6mz9p`CMr42ڵU7?7"h(""}rDwRQ!c˖:g}AE$=]YZZ̙ YQ'*I套P@x+˖ !/~jFcٲu]]M7&&&++C&LE`=|M.ٳ:g7X{DGD*Ubܔlpn\꯿pa+W^TV!BChHcOߦ J6xү%X@n̟qc3wnFբ!u4iLS#]} fWVDdd b{/dmbӦ3uuet͐aTU*! K;W n2Ypp0KgVh7ά\~$tJߡR o¢Eį>]\^{u4d2E{YII)F__[bbr((0}zg.kln/ookUۜ~:ϙ37 s Nҡ=:k47'UUr22JO@LT?y̘رi(NHgܸ 9y&ǎ=ӎ*۶Vg<#gGrB6 Ռ>} ^oPWҧ;}5`G33.'\ '.nFѣ68]bj) ,[6")7nzu4]Ъk֌XJ`GYг;G4xLaozwrիc[?{6ŋOѭ[+,9,rJJ8;t󾻻9Cx10bq'VrrfXYObK7Cu~vǎxf:̨Qmd<~<Һ[[!̚Pp!!NYs=Í#n-qqy̚u7 a`/*>]$>>-[b9xɱz(X2q+GcޱP(_%MQ*9T*ܹ,پ=ؼ,f¾N~@c9&L؉B$'\ñQ (JmC"fͳD&LРsusPRdذۺGYtY{++ek\3 ggS,8p qyy+ S123aBbBB<6oϷ̙L||(ӊ9+V mk̚urFq#ii%YZʯY3}}Hu/tNJr=s?,sҥJKxڵ| wN\UӾֆ_J=ɩ~i(_|++…L,9`fMJXZ>PϚ1uݍb KפIqt?xsȲj[1`g]zz:Ihښ[$&>xX()"*&bƁI?7!5R,- qs3$J8r$={ɔtƢE' s?nbGE ''3M tHʏ?G PRSd`55J.]!,̕ԇHN:gKrrGA!0~|lD$" )+6) T]yF5-0%HMLѻ v械PʂQ m2`qB6ebnGp#eEERvCee5!!~ΜOvv911l|jNHO)+ӌ|P/>~]V&;yJC{wWt+/0vlbٙ3gZXBCqv6%3g3sPBVV9z! 7.ߵ# 3cS? +A&rUbWW&}1wnO:urjV;(*wY@@׺"cnԩCC1bl-Ogwo".0}>J%e爈H`9L:T[;12S]htZvu&-UDe+/|yΜBOOO#];m#!!߮k=eɒldž 9p ϭ// mY|}>>KM()DRk(/XJzX[<5ڵEPbiϜ9=ÇFGGDMM O8۷ǩ3Vfͥ::~}_"8tuz1 }Ǝ')JaȵkyLxOȭ[5k3|yfu?ye&;??%?pNm,665>J(kAf99`f%|'v^Ş= Iqwd͚hu2ɓ;bbϊ穬ѭ+JOOK**dSR"€_֭{6uu5G7Sj55[i1>>Esg'VeUڵ!,rNƎ oņ -y( qp0fuUH$2]U'2Ps`ٱ#{2oޱHBɍ1sfIIwM|':|`KOdQWcoỏ7}_b֬gcDTRV&wS]}{/jU4`ooNfjn+B$2lXk@,[vε z h&A==;v$BqqPժCC]jhζgtt9V'ΝˢC{m#?KusB޽ݩQ)Ϳ^foo̗_FqhjKnI66[7mm07ݜj .d|AWuN!ry K&/!%%0cFWU$}}᭰6B PrT&Ƿg˖ܸQ^ `j; %B^z=:1cAkZuX,Ui|}yR?33}I %[LԱN⒆rE\\xv\Sں5r)ۑ_ _ɔOB*q JL,U'cS"IM-jfƖ-WIN.OLM5+ 9v,UULO?g?V%ΦV2hjLP$U~ѣi혊B F5lr++F#/P TynCͭ/lgO=11euLf;:ЯCrWÇoٔ`G ~@֢^'..:qcjW*\^eƈ6mlדvlHꄻǏ=xz!ǫܘBeݜ 6{ o ؼ*l$guN b:M{sm*M|931wnO $hƆ?͵].;6ΝciQQ\| U=9ssiΆ*y"сWd„\ĉ޽$&kMLL.C  yW_U%0|AW5Ora޼dgrL&II9ɪ*QQ,YN t`Ӧ$%P]]qNDKK}ukEVVffzTqΊkXqB <{$4'֐BYvU9/OUe͚~qݺ5V_oeKL1— {{czb׋z5ӧo+G/Ԝlq>ޛ1t/̝S}K4|y4 (,pX*YYeL֙YT+Jii%ca2od ~{gfN||>_ݏ[ X:MH$%r萪xȝ=ՙr`|k+8 CC15T b]5Am ޚ0ҭ\yJzhEhcZji*\ӥ3lN*v^nOt @FFj 33]L TI$=2`۶8yfs˜caaH..nmMi3g29>~4\\xXZPT$XX{pɒAxxXs~̘q*O$$đwYw)`fT`aJecc[ZRUUSYC w%%EkAܸQLY>}T9#aʷ6LdddQT$B}}3wu( pp0Ҁ.Dii5'f&7KMIdd*.`ؖy5 Y~AUbJL4WU 5*9`blx}ߓPGnRP aǎ8֯1~o_ 5\NDRæMWysqeUgi`̘֬Bq)RޤWB$жmE5%Ol>]W5)~1ʪZN]qt4ƍ"L6㏻+ܹLn,E  (ɩkWWlm ٴ*/Մ r\Fj.?ߎKrII)F*SX(a@H1w!53g2*D7Сd_/@(о":t#&yÁ?O UN ˒uFҦR~ᜆ3Rdk,XENŷ<5{Oن~;ãOp' !!Nicˉ79+bVjRB[QQ!cƌ. Ezz1*;P;;#mMUU I EXX3l&uncٸ ZsZ>{w=1Ʋj-;ǧv_~@Y*ΦC?7[1˹lZ)\ykWSܸQDLL3f$8ؑKY㧟6Ǖ>va޼^,ò{uRW˫WI_@6,Yr;)+cەNPk(5 ۑWAP=3gVyEE3mZ*|TY)S+]ٺ5j@ \ /k`K԰XXӥ3,_~[ f军70%أD(䈮񱢦FLRxѸ..˄|Οۻ85L[Փ?,̕'~-NNQ=05c?Y89bh(wQ8X,"?IC < WIFF)ΦɅ TV(uk+*nU0eJ:8m/ )Tӧ3JՊg30$%5ƺHr ٬PMcK 8 oIk5,- ,ET6(Pd0iJJσvlz.66FMzKIk13coض *RJ0a"gT@yXYnut BC9w.G~~%GO7CX2]0thk~=\[Tu`>66FjoAPuJE? qwbnP9 IDAT ׯ7.9kN Z3Oɉ>VooKrr1巳1STTIdd&&LDNN ĉt:ԇEHmQDm&U+<@WWD׮Lc0`:+&&WmF>gټy* n֚S]]ѣi͚axyxdg J%NZS?,- iF]˛oжM<,eӦQ\Bؼ9nѾFD,[v/+UC{d2^^D$9V]D__}=~=ry ۱x JS1)܉\^ȸqlp1%?>닑twQi%3齒 @ DvEQ|EuEm\DD&B${&S#c )"9;sΙg9sVwl4-&}ʹi03XDBBΟϦDSSގ9BB7ؖUΪUPMv.*wo[lm<@<AANT6LlVi'!EdϞDmC1o^0<>:/3f0aBD"rwqĉtvJMll>V3 BVQ_9:ѻ nnV<`|r0aƎA".5%M5P*$&1<?Yرcn8q"R F!x1#GmdfV j-7g dK8:`A([41ßZIe8 2ss[WMzz LLyyrHĒ%aTV3jԗM\¬Y[P(9AJg_{riq| s#"…WKyC~xŵWpv'2h,ZF@nn{oZ_~IaYRM5Fj%NNV+ob". uM2QFEE7lN$>>=݊'.\NiʹixzZ5ZUSSVK |jjp!533yAA5~xɓEٓ wه[chQ}vXĬY ㏍WؙYbN7OUfݓj4\Ν @D{DR楗  ׵F<gdy k6!0 [$/gXWWKΞͺDNBgd@MᅃA<=Q(dxyY[/<kkSIB#GxjjꩭUqd7DzeK,w_Nl^^6qX:UU?_K"9UFam-D+FeKl…uu_;6ȖS0gN O=5?&2l??ɺHwibH^z!O=5dDEbeeG݅7GQ QxUtY @$`e bAUR~P .×_^V2l؍|Lٷ/Zyd\Kff |]|)ɤH.pbOgdI~[qq 2- qJz7BCH$"=ɾ {x{ܲch3|pYX(?&- Ldž~*#n`ۖ+GMN'|M,>>6ﱰ'˥,^ܸG~~UHDgف<0. {IM-ܹlR1˖ҥB ASj GWhή_?(*5p>s&2O;m[,.䒐PȉkϽPwxs` &իktnk{Λ|*i4%>~9|82llLyH֮ҥx{pdWV0/Ww䈇5Jr23˙2/6@~~F]LMTۣ[YO#nSM^l-NNń X[qr2믣 s#2R3gpr@"'e2 rTVѯCh RiCzwqjI||zY1Ԡh3'Z˶mq ر>YPYd w Fy5?t0p3?p~K%::KKS&Oc{oӧffFݺA[kj*u]{׮=MZZ)>>X4-01aMjj ֊FZRӦ;cccGK7MIO/oJɵkPpl]c}6⌛%mo;R>=ysj 2'col`gݺٳ˒Z?cRB!#< ??;6BBp3WK(Z V )\T@\\>60(l)s{'Ϳ ߌVnNٳ*)/;=ʕ" rRHDTKzz ^7WP̘s&Oԩ,N`h/jjQ4+XZJAA5..Lwő{ r"0бAzqG2p3|2>:-}t OO+֮=MX EE5|M vcx57s?UUJ} `?yx{gba!_Sٺ5I|wlpL[͝ԦtA9s@nnesrH7|rEE5M.]\H9JݔJ5>(RΟiW_8wx5,_jBCySeϞD{,Bt$&&D^xa\Ocpo7)oc&NNIːJ̘OX+11y|4܅T*"!:ܹd"夤hNjj)ѹTUx(ty0jD$&rH^^6mkRi,:jb"ŜիǒQ5JaKh~S%tsdM뇅 ZW^9̫LZ/'>>6mo&'u?W^?'E"ckkBNN%9nXZAW Oή V|) ԩHK+%+a< 293mZ?>xAְqE||l 9ZB!eÆ<^o˗b˜?Mx.XRRKBBo;2Xbx8V^Ӧ=K$"lڜRk8u1#kk9UU*+9u* ~$yyhx*+&-!= ss._U}U4+V`_~MzŢ?*UFff5ii|aʁhOHĿ51c61c6^{mAu3H$"?2򪈏/$+`T*bp/Kc0;2w4 y5GYsgѤѿ3۷'PXX Z-=ڛGã\s|NN:ƍшD )llLdžQdU^^L7JLL$|=DF~<ُjffRN̙kϣF&&FLFdvvr S6j\Ǐ:9:7+-(y&8\xu8ᆧ5_~yXtQV;}S\uiS46Ecc#˚ٳy]Z< 7ȑJxjsJ))%,[6瞻ſcG )S2[CװfV}=TZtCw凣'NdJA.@ee=Æybf&RQdKX[y=;^I߾N9Ogaj*џ=ÖLVrmP6W@X ۷ǡV/3Zط/ˇ0gN`Ψd|*8@VV9 :rRA^R`+z;:CcH$"^xacxQɓ kݟ_ȑ_"ghkyh4ZcgdٕSVr}T 6 dƋ77#RXlpQg{{6mάk L’%?weXYBB 1Wl`2\!H<[ӣVTV*9v,˗ Yp_B!EbffL&jBHWVQZŋ9Q5հhQ8;#7#'2ll-SW@ H]Ǜo߽n.S5^^ַL277i̴Z"K׷ / z7G^}0QQ9W7~Ո" Ő!]zbWR\\˹s8;[PSS9֪>;;~ G.Kc@g,A.{Y4>8@?˥xxXnITT$Vj@Hn#e3bթcܸ(󫱲2;6h vvr왯v b˖XmNqqE-rno NNAA5:[ c%M7ʝر4 ښw$ɨ7HM-E4Z$Oh\k~:VFkx#Ҩ[fvOۅ7VGIN.&9YW_ook- zǡwvş[ɩS ~]\,ɩ`Ӧh,[6>}ljUꋣF‘X,O/0f:߶ X&tZ:5t_oHDxxXnd}pNzxzZ#ӧubQ"d21<0T˅m>>݀ŋ#eBCx\T5DzhAZ`ޫ֬sx\ j{d wTywnŋzйl~{釩ivv l)ZRR_D3_F2t3fPPPđLا"1kV}6=>u*HT8SSbL)gf&&NWQdݺhZrs+Qq~) 78]Q[bo-w΄fc6ϝ„fF"ʕ""#]yp, G"qd?p@G"#27rYo-&Z5`۟j@Gf TBqq 68▖&nf&cȐ^D"zh@$5kq=[Yђ6n_6\.%,U?}h A]ˋ-A#R™3YLhʉtC;' thiԾ87\Yȑk}˚/bKGdžeM7I"R;RgЕWʕm: j@f?Zmu׍9{ZZ) i1_S\.e \];F[0Ո%`'=N7GooI\Wn$}vqU.\vv6߁{0}g1`@C4 :u@8R̤|yT;pR>{ Dy[Yw5޺lO?@bbk׿ӧb;>}{t$MLźua}믏3j F@g a믏宻 qP[Zg6k]C~-%66z7ٳwn-B80W1³SavフV5D}TV*7<bc+̟B`^#Ы5BCYbD¬Y30lp BZ}R楗~^/wLh 1Ao YY*Ԙdd5讬X1huObb$7ߟAHՆ B4ڟZBEE=>>rnLL>&8;w"//f3D#/)S!9ӧf @;hYs`n#xA]8*>h:`WP#Gz֡%@;ʥޠWB!ET5h cx3fwh'ff2'kQz6 e;}Im7Ϥw;th'BDYÂ!L6VFvlHe?;q` w5~-͛cz @;qu;_֠5Z%&&}С z t-=h$r̘8{$1b緾Rӭ#\.m8E<ȀUEx0aa,_>Z*fP(dΝkj]"vFx0ff2"#05Ղ)vY?YY=w9Tڠq]#LH' z4O?%PH7[g m@D & (H&#LXShUض _ vYE  Ѓ@@#@F F矯v0Љ1~/qHzWG@@ JKk̬OQ^^ᄆf@@TU)ٰǎe0bSW/+,,Lzh4x3gsw.?Tj8}:dtr!ee rs+9y2 FyODmr%naֻ =;._.D’%];(.+ڵ2̤=Fii"ZT)(4\.e@W7ѣYv]F0zKF2cF* .0`3II%8p+FTIJe{Q;oOP3ab"]{ oۯTg믩^}Z}x!XZ w?W?_go0!0ЁKam-ʪehII%QbbII)mri..H$b* ;;jŋyMwo[ rcժu~Fjj)>>n]ڵR*;;֭Kw_PXXCe hFuu=nn8;[Nm_AA|-[bHJ*ȏ.LM%l6tAlS Lի%)܄uNSWzhʊya88|~֯?G]` e)( )b.\G# 3,4.\uuj߉ { Yv zYv Ff1r'Z-Ց\LLL&Nq9z4_~IaXvN`Ҥ*/O\\>*vӪvҥ{غ5zLM%̙_G==j֬9BEJC} @NeexP*5ߟĚ5c'0kgpOFB,8ZիE:`j*fڴo ufř3LKQQIH̙ q϶wo"?N{__?{͌zJJ||><3ǘS{e+Zz{"m,GECC]̙,+4ɏ:֬9ƕ+$ GS;Ey=9D uqquH Y(eޝ@>v|lٸ"#GzQWWw*+<~\RF .F%%0@}ciϞ$Iazlm:e૯YW23o_ GV!m_'Qvizh NNsx:(j$yyUzIUWS[쯜 ,}[  :h4lϱcH. 8I1ZzKNzzJn: ]x1>IZZ~;0Km[\{:4%9??{FO@!@@T@O4 Ѓ@@#@F =Az0` Ѓ@@#@F =Az0` Ѓ@@#@F =Az0` Ѓ@@#@F =Az0` Ѓ@@#@F =icGވT*hJit{^֡uWB@@KPS]= .$ @}F@@sdA%z$YIENDB`qmapshack-1.10.0/src/icons/hicolor/16x16/000755 001750 000144 00000000000 13216664443 021061 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/16x16/apps/000755 001750 000144 00000000000 13216664443 022024 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/hicolor/16x16/apps/QMapShack.png000644 001750 000144 00000001321 13145236405 024331 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsee cv,tEXtSoftwarewww.inkscape.org<NIDAT8KQ$AZ 6 (J)nK,ع@.\X2 fSIVAl|Q3 (9=zkk$ؼ4X,KSų3$!M~[d2gzM"9{^LnayM.wn(&.O3;F61fU46VUe'_'&aqqYp8:;?2;}}?(-blnXZgaaLS!  ׅ *NN.lA$ׄTVNx #!$/LNd`3W CCax^QR (IV7$LL"#PU'լYDaop(47B|`2HD8M#-,!yxH'ͭD*2GloiלXfz{?Q^(tN ݏ6PU]d EQU'kyJs<{$?Qɉ'IENDB`qmapshack-1.10.0/src/icons/Up.svg000644 001750 000144 00000005642 12455143304 017741 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeJNX.svg000644 001750 000144 00000121176 12455143304 020625 0ustar00oeichlerxusers000000 000000 image/svg+xml JNX qmapshack-1.10.0/src/icons/MimeTMS.svg000644 001750 000144 00000126057 12455143304 020634 0ustar00oeichlerxusers000000 000000 image/svg+xml TMS qmapshack-1.10.0/src/icons/CopyTrkWithWpt.svg000644 001750 000144 00000021422 13015033052 022260 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToggleGis.svg000644 001750 000144 00000011262 13126360003 021225 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/POIText.svg000644 001750 000144 00000010155 12455143304 020644 0ustar00oeichlerxusers000000 000000 image/svg+xml T qmapshack-1.10.0/src/icons/48x48/000755 001750 000144 00000000000 13216664443 017434 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/48x48/FilterSubPt2Pt.png000644 001750 000144 00000001265 13145236344 022733 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  J-tEXtSoftwarewww.inkscape.org<2IDAThkA4RWB.* dN"DRPR=\=RU`&Z~6Ҥkkh: C`}l2I`0 3^ G8۶zpW՝ڌb5]2o`jG'9/e{YY7"jnmɭЍЍЍЍЍh&"rBDfvOV P h&IJ{؎ם{;1& L=u;NF<30/0EOѠM \OpHWJ"PY9ʙdr: C]N! f@c[^;s`>7  $Tffk^6غBcC~DBaYv=B4(@2$;gS]K.r_;@WK (Rݲ/tWJJŖЍЍЍЍЍ?/B~T_ok7#NK?nrw6_IENDB`qmapshack-1.10.0/src/icons/48x48/Paste.png000644 001750 000144 00000001014 13145236375 021212 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh?K@mC)Nvpqqss"BoPuqpgЩT]J(4v2%/{ƻ~=!,h־W6(Ҋݮl6}4c#d*AaHVTWBzIw>"J{!'Wͨr8X-X6)Lr11{V*P~Ԕ((Ws&@`$g@)|b|{V,P\[;;G) Hq8i4N@'  Hq8i4N@' @າ;i7 Qq#=J+pCddLxW&gB}ܛ!ܧC` /G,6hIENDB`qmapshack-1.10.0/src/icons/48x48/Info.png000644 001750 000144 00000002732 13145236353 021035 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<WIDATh՚]lU3eP"д1FQ T>Z>&C 1|MH!ml [ZceӥPZ 0vQO?ܙ{-P/s@&0c hU{V=K*{j`I~ap izC3Nc1lM# AlA[@   @LP/IV9sBp㆏>C m|u;6:`7(),k􃃂}XWU @3s(e`^UUK).$\I;7܉=K5(>mglz̟CCGqZR)T) b/%$E7J+[:cPl,hL>)͌Fi!P ";"PVxtN%au>f=tt$x( a(@lv'$Al 뱘\؆"n jk`<ׅ d6__'V¶ @ZMYMMkܾpr@9Qݲ 9K찋L ڽ^rs%#b2F 1ԚV;' AX`+-pr{TۥKm6` ̴NTە+m6@f1*} y2<3@@͑u?ge -- ,-a%i%>'w!`OnJ葁`nox }wZ:$B Lӧtv@*\`Nh/ J5 ^R6J!BFW86Bݹ6є zA6^TɓKze̛c=.P`ԃ%X̍,)w`p+OqVASC0YeJ+S8xpILٿMrrL~a*kkkfKJfGr9XJw$~#( ŀ???#ͬYPtV2j[N+RJzDn]HvD2gr^iB!ІPձ:>tgbuuweNjC c<$b}5xutɪL4"_ cG=忠 -H"#e_հWn@h s/Ĭc#l}vtT]Coζ';Brh2@5θYI9]}_&^vXO&hG)Q=yV™*N&C~+݋(~ /g`Nl'Eˀj<΄!u!9\I*S$y .-v0hS5Ze kyZN6,} W'eE{M>E!:RJJСYx : z?f[+pR)ܙU'H{.\Z*+-44Xpw7ͽޛ (*@D< :)fs=ZBuu.?zug{<9aadR].@DfˀAYYIK##l ??#uuW4c ƏL4A`'T>ⳳ/ͱc߷4ȟ} _zhc`S ʕHH 5R- ?++-=_~y۷:`̞֬Ő!!ΟONGYYz|@>p aaJ.9,-3XRL& LR,tl~I }1 ٱ}qsM䭷>aI2ɜ9RSeۣ,Z%nnKB.< H|U{"Kx<>]6o=6PWΜ`3T }1#>\$1q?ذI<< )J)ۍB43'ӤFW-$%eR&Gm|UUY$6CG&6&"$^,78 @LL%4jVOlnjػϸ9[:5WFzu<_R+ -yN>::왺Ys&oY.^^|tƌws."y|etD{TW7͉sZwHZ5BCߡʢ>(ȋҿae ?нyyss1DdtRRՍ |t(/رR=ѝff M iypHz^'ZwʰgvLܥEÈM>mȐLٰk$w`}Z)HJtv|nP[[WX+ꖿ^ЫDž=܁#Ll/ɑ#y dC\}z;uy&3"VE#Fk=ѣ%,]ѣîKn=< m_RRٟڵ2R Jl_9lV{__#f mQ\tF6S^^X~ \y-۷'"0snv*Mjq n`-{DF&MBQQHH,@ROȘOw^mfڴltJ`Fg2lX mz__SeeuB}LNbINq(TWn6ggn߀%%5RRٺM9:4ɓyDGлwZ�GWTX8|>VrIO/QH7aa>ya4cYǽĈ7qɓw&"204}{!{|CvŴJgD&'LMN jhqt9_]FQQ" . hR ,b<=ccFok{[ hEK/i p:33;ӹU)eVJ+j~i*NЩ0()S>@n~Ĺ-rqq}Wom:+\L}'hr\ {qhtc0U.^c<{=8ؓ{ǻ_w;:F7!:п7[锏~ 7+IENDB`qmapshack-1.10.0/src/icons/48x48/Help.png000644 001750 000144 00000003646 13145236352 021036 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYstEXtSoftwarewww.inkscape.org<#IDATh՚mlS{mjG,4(lTO#m`-,PvM֭RU{S!+)ժ&BRcIiRH:FH0 Mk_1\^i/s{s%C #`Xւ@V-{tcDK)<[4 5Pd>`~L\poP&XYPP:D$b@:opZ"0 @} xP̌W;s 9 t@ HƀW@ϛ-Yp:WsjoQTW n tkD,|$V^.{,WG Nt!=hOcѽZT|2a}L~℔fjC} yZpYQ#3Yc<@gh GSTIKˏ1Fc%'ڀZ.M|{ss\u\jj7O-0VS2 `(,bƒŶ@ o_.W?> 0iʒ$7j 0Cs}`%ߍQZConGr}XsO#I˗˵k߰v_ z 7\6܀"ǡ1#V/SQS]g{A`Lns5C _N@23t)>S€RPaMa˖rv7j@RM<7NYY.o%>d{ l'Ceeǎ5Chwws$$;f3Xj108hm}<|||_`0f UmzٱSi'L3#fAVҊj}{%--[5+ؘv3F3SVUU!ᄏ%==7ؽLMMq @͎NR76/p4 /!u))ar;Q^}|>5-s L:55Ř_ݻ~ϠI,;2GE)uJJr4i]6i 8,Z۟Yo:GqSMCJhLΟh H8JPz6UR0XP*AO6A=H*ٲyQ{瞫JXf$^#ov l6(|XaW@mJ DA8zvf&h0DZ Ҷ1N*sWeò""tѱ X测p0vo:ّ9Qo$v WBCKFյ_OD[|+?*+ x9u_I/eCY *(^Ćx^V˅**c#/( {kD3 AP<>)yO RZDn3|A&@$3{)Q%^)ވ->5ITB`y ZQtE*R"}+~X(FxJ ,*f]0͈6T'C>JIENDB`qmapshack-1.10.0/src/icons/48x48/Right.png000644 001750 000144 00000001545 13145236417 021221 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<IDATh=Uߙd, F$"q1~6؈` vb!  W(Q6Acc4|bXwdf9s^Ι. ɫCUCēM;ǥ&vSCYM9lYidjh2aCJ^I.דu+5/#LxNJܙw:q`נ-50HfK&W$ajfK îu:R%EFٙq›*le+gJ7gR2 5z}/I^baے g7"Z׎XJ2kh9@{RFא|Ώh9>:>%YuTmx+-vnĖHxY1&J!9A8Sִu o͓">رNαqc3098Ck|>_/(*.{Ͻ#x7ǧy)rS̯Ļ?jq*?st)gq0'ފ/* + p.-G-axMK/*l _*-SvӇ)vbJVKP?(PNE%d>ψSq1eH o:8p(xݒunsXqAz2#m-c\hE ;-.e*bd ~<(lhX:2`V۲ [}νG.tʋ s2Wӂ2 * PyU?WP^S6ɐԓ%4Ay6FI{{P*I^+!i`=yj@a@H.a=i`0#Cz2SO݅O'ךJqߢײy M(ʆ?5KtF#=#r#D#=TʆʵG=@]i.=zZk { cy;ꍍ.vfF.8׹VicS/<0~6 EЭ[ǩ\6E^7`"9ڬcYcHzNzOL"+k)wB$`1|~ASKJmQF Z-\ eůM}3A3*D2CwSDcfzLlfktÉ(-@tSX*,\-.Wp/J$X#.wVa)<a) I|H$6] \"V&U܊{lw3a.#sMp 6`IOTPq >..y>jjMXO8 bS^"yWP$ ynw0YHXڢ؍=x}|()[j70<$; Q})"1G|sMp%Զ/~:ϗ_oWy#}L M_.t74Q-C݈FIK#nNK#ǑzHA4';En&B*@)$fm9WX#8^oi /V` xiA\m?X##:u3 roRz9{¿Jò"%P'OΚL&*"M %'kOJ_'&7ego%J$#f?>4.rhIENDB`qmapshack-1.10.0/src/icons/48x48/TextRight.png000644 001750 000144 00000000602 13145236443 022056 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh= @GIEE6Dilڈ)vvb6醰Iv ˾M1 1>Z=$_]q4]b8[* hf(E|'?x;W pm4̗JC)J~L(=D)BIRZ) )%`va 0 &=@av!ۡӰ i"`vayɪmL$IENDB`qmapshack-1.10.0/src/icons/48x48/RouteOn.png000644 001750 000144 00000003525 13145236420 021531 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh͙{PT? qI\Į8NQt̴5MlZ!3GH`!SәQO̳!h}:SlmiRA V 8 xK0;" FG~>c.x?e3(N g ~X[PJOoΘe` a%Z"v>q5v <0y1Ż̾_xOJM{(lxq&X4k+GC5]!2U UW7Q#j UT}K_v{hO5X~0wY,:B^ #&0tiiP\ C]ۃtC}7M2=wef>GrUUWZ[䕓PUٿ_u _N0 s:|~~O|+_bc;{k_X<(ОnA(+7#عy] sAt^  (}DG=׀u`ʕs8th MM,47JqQ@Y`*(+{\3d}xtSW7> 5EgD0Q"r~FmC 4\Jl l 1Q&u-# <{OMK1j/԰ D±cHz@-Lw u {M 00ggafm^/ʾCD"~[@!=_S$%c̳B^:p6Irt2Q9n ( 0yٴs7(⓱f'6}휹z go= .PH,J)>NH\hîouEo:E P"G0*<Vprqʍ3ީjvs?a234)* 0D03a&i_>/^ȹ`FH#Rr]vesa!@lw\<ϴܾ֦-8Ueh]˰39'"/v.fն_˂i ٬@!MTEOv]Jk9FC۸~2j4-H\_Ci|yA  TV+hlxG R("{Vn`@"Rd%eiC֚yk&au_LT1)8(,|6v^IUWmAjZk[JFKN&ϕǦș݂<0(> ఻^[몦jeYnUU屚:[>jmhܖRUS h\SXפy85!!-6Uu8sY:CT&"iw:4@IENDB`qmapshack-1.10.0/src/icons/48x48/ShowNone.png000644 001750 000144 00000004262 13145236434 021702 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org</IDAThkP/"EE4&Q 2NDzɨc8c۱1:h4Dc1It$X[b6&Ew\e.ʹ|ys{9=VUjU  9IBAob)TRIaž\P)PC?5h;I?IW$Y\u.K:$iI= 5oijLH R@\GAA71RQQEU@z@Ϟ '!'aaAv2 J3az;0ƀONB`>obb?|݅ɓ:5##1 |O.eh0߀*Զ|ZYȆ {[]ў l6UܺU~`0}Q ,6`]Ӈ- %`áB/?•+6ӛ >'Cvc@,;:u.r%k5a4e0 8d;wF$HsA>Uzzw^}SM~tn>jC+>>i%}%I>`zm^$ۥe$??6ttrKnIKkk޼ʕGe?;$ݺ%%%y5#T#+HSJ6%騜H?XWgה)rGEAO1'D3gP\ G_]">,=8Q%K5n\'I'%^'f''{|۷5~H2-`lFβr,cI=zjjl7Im/]&MZTUUY=)7O^sr>}{[$|$'\II ^,m<]wc%ɣzRR|.]IrHߴak~2x]y={V4+)zE<ߩӇ5M qn}ÇuaD&L`֬kv*3^z <|Fyӝ;5={+q+qc~c2MC}%YKU;|Lt^ScGs}i!M/+zIo G z/{ylgt龖,Ux4͜CtCR7f_V?X3u ,,$%%.;Gzf5'Osurr.PPPX|q2F 5 "m(O%cb1S^YADD{""ӶfsׯXn_"ax=x@yu8p"%\/ȑLԩ1 ΃:`aThb#0׍XjjI87RPPAqL&%b#$$t֞^BFllƷsglr ÐY@-5J9H5m0qf|kFB{AN[E? O 0C~VUj B4 IENDB`qmapshack-1.10.0/src/icons/48x48/Add.png000644 001750 000144 00000000602 13145236310 020615 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsCtEXtSoftwarewww.inkscape.org<IDATh1j@EIo>ƤOJ.@aHXȽzJ\@;?r+e N @ Onb7Ж9G`;p*AX@X@X@MCZ^{H_>8?8c$|oj,j,j,f]PgęC67h:7cIENDB`qmapshack-1.10.0/src/icons/48x48/A.png000644 001750 000144 00000001554 13145236315 020321 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh혽kAM.4шE" A_\-Dl$h_aGM,,,&~ Ĭ3}ͼvwv P7 ?A]bɀ伟\-=ũz31Oy0cN+CA끓s%`Y)d-E; l: yv6f m;ʧWl nui峒6mTFsaSi=/@]@] :/(((_ؖ\IENDB`qmapshack-1.10.0/src/icons/48x48/MimeWMTS.png000644 001750 000144 00000005707 13145236366 021555 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org< DIDAThkp[⣛%۲qBlp.@8@Z2-)%t酖ҝN;ff)t)݄M !i8Ŏe[tN?H>,ɒt2fys$+ W$4 _n^M+$Ո7Ϟ ( o]j H43:E3sHh?VKT}J1" +Y8/2H(&4ssI*s ftȎÈN$m2c'RQ^NҺad:H τN()<꽪hs uq1-](?Zj-*AX6IIE5VeU+f$ >1q&==j wA5[ 'Y]6e5:l ׮Vp,&Oղ.K,4I -At`^nEe7.!D#F&;fPE " "AaNgPE:梨@k2vmF/BՋwZ^ MXq+omb?5N&3{W2 ~}$ 7S\Z};16o\C'9(m2󐻃Y-Zš-|s /EH9, z =_M&KFX8+ $Kɤo72f!2_ᮡCK2|w h<6_.*K]yEh|ݿFp{]7&Xg4!Nt9W5|A2N@<ĻYXq%Oʹ ( w;]mbҥEcu{{]:Qns4꼝 Fm-\k~q% XEs8>"d ~*Z1>nb6'|.W+~±!;mj&tfKU*m^b4t^/T\& 7h%ZT; p)_:[z xLf(eU |hL҄ i5e3Zg'\?O"shLLt+x\2 VNl3?瑱cz#C%sjb@n^WU-{)k\FD˰-ëc9?pVl>﮺fΕ:M2Z HV9k:g3,Hp%#Fa4̫v:5 ( k+8Z'S4}6_w5h3B>V0HVf~~J\tv*.L|ϣv8ܥ*E]A_$fd " h˯BٸvG6?B\Y;eЍ$Y]'fA4c\H*5~篍jΥc8EfL;.db%pgU^~3ο΅LpH!ί(k:eⴝo4t>yxYBvAc򭩳Fգy:r`@ҡh2LV׉jNdV7Ga%y7ԟ s<ےy_ wͬ,反3MBdGQLf'W^2£c<0z76WB ⓜJA:NހCtY8v5`̤u}AnX 8]B F vȳbo|̂XS\hbͲ6/  Hp̾ :Ի?2B%P% e~~SuCu Ky3c$G"&!_rr!`e*E%b54V,%HHLr!V}XͲG&atYY?;56}$+{x!2j3Z(u?4\fG,KP첨8DōVHs5Zd%xĻE0~<Ȇs1䎺BZh`d2rq/UfɂZg<FES g7p͂^븅Lx*B@6t/H6S!W_ C<>2h ^AD`/y&4hg YʮHIENDB`qmapshack-1.10.0/src/icons/48x48/FromMap.png000644 001750 000144 00000005745 13145236347 021515 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org< bIDATh՚yXgaq -50u憢dYVUqADpV[f>JjݛfQ5F9oadn><|{{s!@Y 4|)@)M,N: :';APӪRtv !?L{EY )e# &ۤV; Z)0)X)S5" 3jTwpr̾s)I HB\kho…amU=rRJVO?NkĚ͖;w^ؿ?Й37&mۨEQQ3f#??mn1bD3j.^q6axohW_J}:X,|yC7nCpp~~|: ƌ 7+wqɄ3(NXAyu e=(A@rԶR Ν1"9Fz3g^e˖ 222X ю%// SZ iil@[t@y^RH;$,:?d`7eW4PbEr-)%ϳgOC<<`ʔ|m@ѣ8xp ۷u^}ɄNѠGo0x>Z%8 eM v\þ}Wjt4#GD#OOe޼_qu-߫ b6]@yAЭȠ0z`ժc5/h>ˋ@Qo bLB~r-U@iYrs `h̽ +z 9th?BN]/Pf Z`P65 }@r 1m"LBƐXIDlҦۃj,]:`Zq9ecE9MnAqv}FUШQm<=[\:(J63Dp/?\fWѓ4>UF%gܸ.KLhf̸]e$&^dƗ >!$DހǓGR0*m#.bG} ?nn' "ꌏ:n`!̍KiDFhpD%=ݾ5 )~4F騋\"@MERF-@]<zo]gh>fI=&^)1nIX,2Y& UOU$/ !O݀.@)]|7pWf )͛KwRR]bbf6k7[ss@Ve4+trv0*0 !!}Ӛ䬼,4&L ٟjS\8P={zu0ɺd C0\IH)-08VU8PnK5YNNN,[Pɩ nnnh^|0|:ȿ{ DG ѓ .8{; BC1hPmz jťU^upn, 9쀔AS½s P4J.u$ߴСS xVsf^ުiy:׼+8^Jx>ƚZCA@ܴ9J  0}z ^^^g/1ҥlV [O=k{Ocm"†rYV]!vSTOGח` G` Pru~~k)d`\JAN63_ H۞(KKBB !]d SԯAx`ǐU3f196凜̀@Qw2~; 9T?!ęEѽ%wn0iR!7!"!"4  [!N G?=陥w9- 玁z _)5+Ҥ~M7BSqq8/zgɲ8<ت[y5bNΙӏ!f01kKMI)fP*ϫ"B@ohll_^䒡]I0wqO !ҭ6-A 3f<>#H.ڗ,2#Z?'~hJ:w@\HGcp7vg>ڨ:E+t߸4~:}ؼn^O`61YsMݛNBDXf?drc`56.dZ l(b%:]4EQ?zdINxPn@ERј@E}OW<@SQj;]ZfHKPRn69a{[CH |pqجHn=_׷3{vjX=ՓϖK9BH);+WccNzyL7PXP5&GwM!!BB|?BlMBܵQ`ru__ pB=sX`g|?4PHIENDB`qmapshack-1.10.0/src/icons/48x48/SetupMapWorkspace.png000644 001750 000144 00000006621 13145236432 023556 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs0&tEXtSoftwarewww.inkscape.org< IDATh{T?;3 %((7`ҕٲb+ٚGKp.Ҏ']n7h\$ݱL*)$(xPfy cNߵ}~??CzjVk < B_6.J!EQ?qbJK̙^mN cXt:' P;E1'2;yRO~~TSVf@XAA:O'* HSZKggGfiK(-5VRv5V Ooh8^xannm@^Q_\fJXfiV>L]]sAMtC<`ƍg?\]MY=^n{y9,\8;;U0WQ#wȿ)"] M> "7&\Lѣ(vhf))ыXDd+qG)"eIqpHQ{ϊjd<ɲ~Qg[;?;:,}S$5tuuoEwUKeM_'%]""]fE7DjJAA< ,!!grU;wa_Lin6|#"rVn!Y]]fgGkןpw\)ۘ3g/^W?ݻg:5VGG7s%7y8;k+ ?璒` |kk ݑ<_\dʔ,fmnA3Y`$_}sZ? 7TL޴km;ԩ^}dɇ=nGiw=lSLZ!#c:3g[Ɋ_&"(6lԨuMںMdM56ٛ8v2*¡C~*^XÞ>قLf=zf{GG;rrf*,X.` x %%z'-@9P|)*oJY{6TV^knA~nwc͚xΟAzz LqP-qqmޏ+8k4jۗ*BKKd(ٳgۊjjjT7]oh P2{v..D<qoٻwĉ=Ǐk.] uwwsII+Νx1_ oL&NWW'NdX,<ǒ%ho^dw xzOb>5;DEҦ曑6Mll&W;;Cxk~`Ӧu97n`wi4IIŋ.|뤥:#!!"<㵵M}=oObɨTw}̛Ͼ}) C{Ù6mZbaĈ!"<%&MoNJ&+ |UW?yr&/6DV֓6/ΝghDDgBزe)tDd]"guInnͭML&)--Jx),,ݻwKTTKbbʄ d֬}9do>:te//*N/D! {ğ|S}G %%qmZ+VPYY=Nb 8[|r"##61,x{?㏛ gvx oѶvZWh:>w3esW>=<)5p_\\4Ν;2$3>ֺV|}sظ0LjdȑjΞ=+---]k׮=ztpò("nn)V_h&=mNQ[ۄI^^yyU}>⢡Ɍl`5;~8 BNNmmm椤$@h4]޽^loZtP-|Tw|%ݘ7)BB;F=Ç#>>FCJJFѸ~녅B.,,Bjj7^~e˖ܫEO`.07nsk׷Њ*9uj܌V JWW'NaÆ)jXlY^KLL_޳gOSYYY}K/El-:4".nP 0pX(|"ʕ+5ÇJ ϟoiivuu5g+WHGG^eԩnIo߯q^Q>ݲeJDDDZNmҴi߿@ь;vg 4l PBQ6EQ~111Z-K.8pf-nG˯+BXXNVd? .Ν;wO.7>>W [`ggj2deN 4i>??_Z zW )R^t~.b"榪Ez_Qx{{{V{yy}j/y^^^g>IENDB`qmapshack-1.10.0/src/icons/48x48/CSrcSolid.png000644 001750 000144 00000000410 13145236327 021757 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<IDAThڡ AP: , `qn3_}d฿MZ`[l `+V[l `+V[l~ڒ) ^ n VIENDB`qmapshack-1.10.0/src/icons/48x48/Empty.png000644 001750 000144 00000001461 13145236342 021234 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsCCtEXtSoftwarewww.inkscape.org<IDAThnW8Yq]Et{- @CiUE@P%@̰GI&g*/ysΫX9f͚5kBADFh%#:?o.-g9n<5&")C+Z|+F ^VUb<%4eų%}q`UKb2q{EV.ypۜ'TcdHs Qj):&ÇdbQ00p+/rMMj>mh0{U~|`KHj-]/TgW?.IENDB`qmapshack-1.10.0/src/icons/48x48/AddMapWorkspace.png000644 001750 000144 00000004632 13145236306 023146 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDATh}PU?rryTXHB7iYE $]4jY]wڲ -L{^l1FP%LVQم p)% ;sf9y΅"84)Z+@D€  07'aSԷWg "A| hpӧhfN"4ԏ1"oLX_Q#mԙk V"}ϯf6qxx QE3qt < "~_M&׏aCKѾ G=kVÆ'Ʊ`A<ve`;kD$hj!;39HLԩ70Nۨhȑ]vN3`#GۛFWu"JD-:YLZ碩U֯?"ѯtᎉyUOEdxU4MV..乹_i?[xwh&5]ʒ5kJnDDvA"f}Ih45kJj_5a%'x{6űu&(6 [ٻ$11ؾ}6#F(,>ͦʼyIIt%VU52wv*+HJ '??~ GJEܶ6[ZJ8/ӧ{߫W w= g֙zjk1g), 1q{d`4 J);gŋ :ϙ3n?w\ع))c{3女h>;224XaD/e˖JfΌf˖ٝgv~PVvR8=<7Nc֬rs$3sRql廓Ȅ7Z5C{f-`#0<ܲ7mLBS= G-{dFFVF@tx6Nmg94aѢl@oIک @Y%UVQ3&[;:imaa~^=&z@-.//&O`ڻs`>\ewv7| vot:Edd@WzĜCX,v,ݻt*]1a} :zoUu)6Jش08l8[V_dI))M)>>wPR +VILRR8>>ƍӏJ1c@DBUU#=`V RR SOM 1q٥lTᶠ@oydK$tفC h`1iBJc0x;h ,YO҉p鄄` v!zgOII.mRSرc?V<1:-"5)SޥIJeE;_6l_G}).Πm۾ĉ&RDG0o^,S܂R}Ȳ'V*6]:vjjOGƍHN賀f*aŌc4Ñbxy 9M7|c0op:D$(liiGAAMXjjYYx=LHw׾ -PV3SDۀ͛+XSΞ5$t]l=]+F~IENDB`qmapshack-1.10.0/src/icons/48x48/FullScreen.png000644 001750 000144 00000002366 13145236347 022212 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs c c$/tEXtSoftwarewww.inkscape.org<sIDATh_hE?sbR)ڢ Z+B, A*Rc{KZ}}A_"UPk1EZjkE*UJ*rdwLJs{gv{ig7~sbaaC0l\k ja`[Xfp!)2BV+vpK޵h={(c+`? "}z~)WȘz hsv\*w TqĄ^ u1RmD(^ח@}jOB19 ZFKWU`;1hP 윁jMtӚHa`*E ާ1& 4Zϼ#ZeľM2ϝ'g tOQI{KFD2Mi01'"Imu؀ ^.KKc. o "-oxx K 17:h "Pt3qz,^\wj#DKA/VgK xÜ^ O_Q5GS@1 sQx&`:p\" y ւ}+w  - ΁;hyj/Φ^lCXo%㭈IENDB`qmapshack-1.10.0/src/icons/48x48/LimitSys.png000644 001750 000144 00000005502 13145236354 021716 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDATh}TU?33 30 o2$Bh(anfi6O{NٴZi亡r wP9eZB2 4 ü̳ ,9s}ws>(0ͭ[ZmV}j Zv{XܖiT5noogϞ=Ͷ'>>~ق odW#y@YJOOܹ響A999⫫ .huFFFDLL V+++{x񊊊 }j\.ǍAϟ?_xطo5$$D%Ǐ]__{mmmqUU*2%%%,))IVSS]pw5 KO:uPPPp?1!!AP*'pn/]PPPNrr2icccOU@9%%qqq+G… CCCw}|CCbsP'Nu8Bmm8;::Z,9DMZZ3g:::|>W#>11QuM7 l6>u:NgΜqʔ):IRQQv*ʻ" QQQBii:;;wxg!AծM|VYYvi4Bl6Ql/_hfcpp J %FRh4곳#DQ %%%eA $::z9stsl)6-iDPT$It3uu磲RJHHV^=NEn7f|xGښ^W| wmۖ+IdXf(ѨX,5Z,ޫT*MNNO>=bnwaG'L$V5u b5k(Ot|UT `<ܯÂ:]-b#.osI߀|qqg1OߗRG ( _:$g*h `PE:Yn+1x^q:y!w":a݄G7(`W v, 6@줈ecІVQO+9QPљۓ8q~1`zr L~r)k8; nDO.ȋ3>p@X?x 7\x2p7x}y,\x*˻r*t9`:`3i8;чD\PM'*/)dB]`߃[}5c;~ reً{aiYtŊ-ߡ㗜FDYnr2Mk0_n_)Z_kp#WIüH ~h("C#EXQ͂poX?=A%v" _ C|z͵HMS 1d&ɹcjڥIENDB`qmapshack-1.10.0/src/icons/48x48/NoGo.png000644 001750 000144 00000004200 13145236372 020775 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsqqF tEXtSoftwarewww.inkscape.org<IDAThŚ{pTݻI 0W2IEpPX!@vJ٤3tĶڎ jLCVG  !dw=#Q nv~3g=~߷={9WbDdM.:;#`(DmDikM|zdXC kL.uNCLH#@7vQiad{?fALzu:g\yG*9VžY,4R<~H(WZQ^{662h<'ih2~ ^Lqj2_3YBmu<#nJJmy ~IYXÂQL LN\UCEIsKE$-xM&GNJI{Lf? {Q HCt*G;ӹ0wcH3E%t_QʅAw@U%N . "DA* \ |CN=Eգ8qYGi8x3Eb ?R}<6( [-P?AMs>? Nk) ;qC=efXd\K*N%Tzj̪?Ύb I\{`mZ"*5~X3+np^C`/f/8/S,__,;nO[^h%Sqk8 @0ϣݘHi-S:{P"69>0s{9 >iTz)Y;x_7Sda5 D:UTxw)1Ѱ Ah̖!fl̶Nrٙf0КHxZ[4M kļ;{*o>x뼁{E$G ABȪUɾHo"=Y!*d 2:mO3v 6"l^aX@"?a7I6FLv) O}%\2MQXge f\ ac-KF3YAL╡|D<Γ7f'x1*X<PӾ.Ԩq0ZqzڪƳ> x Kuy|I ovr"-ȸWɾ2e1:#; P}t]7lSQ)u>j*TAqtbp }@+H kXNjǹ`M䱀>[P{vB7Ԣ8O.&3dR 2˶R.8iq=fȥe1lFLV  "~+b5UN\&$~*C}k)K!_I4Jwh;JCשTngK%WJ h!F%D"5suEZɤ{La,S'jpP|"J~b9Ytl7)aEFaE/ eLa+,3VT:B:IG'.Tql|AƨɄZlϐ~aߔL0N, yb9=H6"Bۂh `np~k" eIENDB`qmapshack-1.10.0/src/icons/48x48/ToolTip.png000644 001750 000144 00000002723 13145236452 021534 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<PIDATh[lUӛR@([XX.%(nx T"%&TI B4&}   ȵv)Ѱ-v|nwnMO&s|f9xPzӁzXjnHF^·DI>R"/qpQ` ʌsy@s|(kk9Tk.F<^2jG`\q<A}RXTWWPZJDFsƪ3ovϧADE\&$B_F ^MSEeeЦ#U3IVU^1)@)RP+T@vpUK ,YBv!{"ө-.FΛ`F6&s͓`7`w~`f(OnzJ h1.-OGŒqPܘoȿ~&h!/fS;mm~\,^*ˆn +;Ue;LtC^>g- SO^u\NMc~lR1qas#GGBzPOC2ҿ0E*3IENDB`qmapshack-1.10.0/src/icons/48x48/SetupCoordFormat.png000644 001750 000144 00000003251 13145236432 023375 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsfw8tEXtSoftwarewww.inkscape.org<&IDATh{U.KJKIbZDD jibLBC5itl߫XMX#@M@A MyĠC- R;;޽+cu~s~ A: o8t'r }6k0cvn%R1pYįLJ+")Z+"z}#?/Ov.b.Q"֝[uvEb;9^ 80֨'98=g99$ "Zń+*Mfc^Τ6߅ښ:PSC42^ ?r_Ux}  (GOvl.e |5A@zi]XuV9}ԣ"?ʙSE+ZwL&|', yFAb1IZw24!~fEgȍ#Ɨ{(;f \~!n?qhGpl;1ϗ16DĤS!#-CIrV#ݡzն'a? >lƭ Le遊kmRLvf.Gr;|3 {8pf&[&1 ދ/zmoP/}?cxw<ܑCW]8tya2x /=+Z$b~6S$QƯ՝f;vEݑ|}+0T6hzZJ7͓zWJx03#LbUh —=9+bd'~B{qjo7m!3 W_5ԋמJ.7@եS,(߉oUZc;Ź0>`i\ $Ǒ'AaH&N/S'.#b\4K4.A"~Zyg蛳#7hw E'т è-.:΍K23I4YNوC]YŸ[R G"W[g6rϱ/݋c"EyD͢WK,bEy+ /@)7"|.g^by;_ vZ}c$%iQFB:c g_QpmT\Z5&97V}?ks2XɴHr~KWq ]g 2]Emf}S>Ⱥ4ccŨJcց3NI SFq<6kQ vxg/cokq# dG_IXYamK'q N}>knӖx n_uRx;>gWzȰ3 c:&QawIENDB`qmapshack-1.10.0/src/icons/48x48/PastePlain.png000644 001750 000144 00000002240 13145236374 022177 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsittEXtSoftwarewww.inkscape.org<IDATh]H[g'hz2izl2(CShq^u27.&Q(*leԋBE2$ul KU܇fA=$p:3<>9=}_x!2P7|GQ=kjjbF1(~^E=pl6[FP(׭FS Vgʱtbf{쾚-F(oaOOpsӇĀ/4a فLeU MOvx<ڊJ)s|tp-jn=04+{ۚ|R^ePT^r!/UuDQ@QoEFQ@Qo躥`n/?Z=zH`>ì؟7lÆ1Uex" !fo/WF^cxxImhٗzyFFF4RnS[[|>@LGK2::#LEKG(JE']X,1??Y<+N"`)`ƳjNF8x쿴ܜy&]޼@D;?s<#vOlnn)>ENgzQUL! 7bZ8EQ!iq(}JgQU5IpAx.0 |{{"wbmjw?^ QZ.tt(?vdrg{,&''@0dmm$8$!9_8^׫W$>v1AO~B&9?%΍;V;xIe455P)\Y4'g{J/Jk\Iw:>ԏ /?fui‚iY61h0k2Ż}p~0;~0<>qJڂ ?sGSkCEKlV3@,QkQV|= 'nZk|(=<meIENDB`qmapshack-1.10.0/src/icons/48x48/Grid.png000644 001750 000144 00000001244 13145236351 021022 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsߔ%tEXtSoftwarewww.inkscape.org<!IDATh혽kAٻ\>q@l*RY  A"d,\ !B!v!- "D¯%r%9Ivc=H#4poTw90bLt0 Vez}-M5;.vJMH7|40&+_g@P\vlL8z,[̸M)0N50Aֿ [B] :آ Q_72 &J 9UD:3Ŕ6\WAo:epl 3`g6 (TNU!оRr#eIt.z<$쀺V7 uLb Be`x|©ap)>)c@};5 q8ty"IENDB`qmapshack-1.10.0/src/icons/48x48/ToolBar.png000644 001750 000144 00000000614 13145236451 021500 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs[FtEXtSoftwarewww.inkscape.org< IDAThرJ`B+tqqq;襔^C݊AZP5x' 2[78j ?o2,[wnzck䡾d ,s:^.zn~ɨvsͅU4w85,i, HMRӀ4 5 HMRӀ4 5 HMR۠"V>لP~,xy~$T7CfV^E[;!pMGPIDDDDDDDo{BOIENDB`qmapshack-1.10.0/src/icons/48x48/SortName.png000644 001750 000144 00000001662 13145236435 021674 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org</IDATh?UdMµXT4'ټT١(fǨ2ɮ, #`asbT*x !KEI'[tqS;cAHd ۮؼ݈=ڬ( #&pO4 ܃"s/p2M2h,W:Y" 4s"p \a\l5+o4d۱6"?b>o8tM`gNeCx3GM8w66'o4Dߩw-}..|leۉ*] +3Jm/ɶ4r]lW9/'L͗8w7OcMEO>SO9@3wx81v# nJlUj9dpZc,QWet eb` *B8ű**j^`A8N[}7ë3v牖Pȟz%[0 b2)߳n_zzj!܊ ?\3aMkpPӪAgϖMjI "G3WS6xeA⑅QiE<;"$׽XeK(8.ˑgldwUAĎ_4reC. GPg0? b^ *&_1.J̔lf bC$ 𲒯DpR,O,~iٟ:ĸJqގW#V|O.\d%і7'u'V`6@31؆)Bؚ|9YFf:vԋT7L,w/vsY_7CE'1y3;BT=./RKYl?X?\H7ɓ=b1O?MqdV[Y7úڻy}xJ kYDF,Iך[ 2{%E_J_] 3ǚ$㑰p1>c}ߝMi]w>oWP˿?Ä#OC|@z)>9a zv%[wq |II@roN2foq,H~̥rVdy6՜)uX-&uV-vQCߕ%J%izkG5ni&kV@eZ;k]2]ﶃfmvWp'VSXMx^z>?VäqO|i qUx f,6{ Ɯ+(v>-Mޛ=g276Mzʹ-4!]`ILB ƥ`(LG\%O3;}RܘZO,wk9l6Az*& Y0?kxKF|?](|_LjpQ_7?3* ɳ%]+n9vcueK=Š2nsƥ2NopX-+/Hm5~oosq) K$tUrs#]ݔgbOL5Ӥv,6ٔ ƔiqҋBL/Khdذ6Y~)`SY!+DKh0BU΅yADT// YOίU9h =u)%&u|"vC@w UI׆3i,,t7iyI{f-#\<Gߚ7kBhˮ [%kJ #ffP, ݰ5h;]gj xE ǙKC=ިmn CUJ~oIENDB`qmapshack-1.10.0/src/icons/48x48/Cut.png000644 001750 000144 00000003623 13145236333 020673 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsqtEXtSoftwarewww.inkscape.org<IDATh{li{N{J[ rMN萍фM,qK%KL&?Lu8qfM8FjcrB=圞rhO[=<߾^N/"Bl?NS,ʷSMŞ%3p g4pIo(^LM+w7V4&=,Ac`O dќCSX TTAD_E.,%H1伱n S`ט_r46i"D){'#T6JocA F M JOY\9z? Y_Q_1JH;:=\>wї LgNMt.D] D۹Al OqH r &ٍTx#,s.+\NjGHJ1.2G(T.6z=}\Hb5EkH YTz?GS#"TEp<0?/i~DPmc?*84ɸ5Yss6w߃8sy 0w6dQ>*h'947^G:1m٬h4ɂA z =Wnyf_"D͂>Vr7 `YNlXZpbJ R֎ #[~eA%74"ɗogqd%>DlTGDž2--h%l}aL==9x#1((wt+}opy^"7Gi\b'_ tы}Cn+ݏeHA݈2e_"[HO4X' N'L2=Y /k.5A0[*=ΊDnA4ϧdkAD?{H$cBpXm.qճ l$>x<r\dQäܝ̙u={z\IɊaGqD4k:URU?+s瞘uG_bW5a'5] h%KXT$0u qM AL\nt3O)8̵h\n/7mzƍKcG/X88h6uthɒ:Yn})G.>D`0<tkʎEFV r^c+kgId (e,Q>4܎^Zb L*!v+JO!ԒIENDB`qmapshack-1.10.0/src/icons/48x48/PointHide.png000644 001750 000144 00000002175 13145236401 022020 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs;tEXtSoftwarewww.inkscape.org<IDATh_h[U?ޘ̄g[u2(C:|2_""X涂L">c8-Nԭj۵lݍldwr|>{~νsh&h-gSg DQ9 ({ %!uN|O \OJ e2UZJb"pU8S%S-:յ\JAɭƁq/V ,.a̍.^G2y1JܓܶmʍFʊކF%Wk#bqӦdr}ayJgg fg@USXlvZ 7[t-oxD|E=A)JK--W/.tvV2"f<55vx|Rk+S{W0l>$sa'&&xzl喙G Bp9vl'k  ׂ1MC1fIfIRRZ<qN{9aww7<|w \iN6ݣzGz}4;  9""|Nh۶'R'|WlvRGjYD#orND|ÍJ)_/ ~f4\@:L"8pC.{x3{Zv<Lї\MF"?A`-;KW[Lf>:\nB)՟dtj+4ͪfSSQ@J<ٲujJ.xL)CDds [t\@KT8p= }KW[mO_޻%wut j-?. ۗd\ qEM4D:bIENDB`qmapshack-1.10.0/src/icons/48x48/RouteSetup.png000644 001750 000144 00000002302 13145236420 022245 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<?IDATh[h\E$$V((Z* AP >xAE`5n""PT*iтW jKQlLiieLJͶnVp9ϜYi<>R Eޏ\N3%g9&#Z&uUėVJdW1kΪD ArWZldCB[q2>%͗8!r6"VW gQmt|EȽx7non#f<>?՚z7JU}@Ѩ4my1Px7U+w':Y LY ]N \Y XⳁՉa\IťAsG E؞s͙0FnL:lpS@Rm~-W~$l& ^@n+^Ip U'[ -DzK x2{*'At^J*3 D ]qC/>r GP= \wfʸu.vz/zkXBQXMٸJ/|-$^.wB$7D~ȶZ3 //v[:oϓOZ2>6r9%֦ =oׯ`p@sm˺}Ji* 8P{28X>!]*eSS1Ϣ2k<߁XYՉ*^ ^ˊE[p)`RK$r3p( btlЁh$RFwe`6f0}d~ͅq޺RdSc$cR]0 U*1V>Je`8O em 9d L| 5z$ ڋ@7eZ}0i3Ѻ70%) 4m{Ia`W<|@QKgoS&20-2al)_'Z mU }SNFrO(i͇D[!Yy=g!1Ř9:4wy6E2+/IENDB`qmapshack-1.10.0/src/icons/48x48/ActSki.png000644 001750 000144 00000002465 13145236304 021317 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDAThy]s}UҨ}i$v[,цX]UK3;B!!҈?[%)EBwqμy|;=;(F1Q4{!1 /174 kOx/r74 ^@ry QIaE}$٧_'N*Z݋%ivZoEheNof=踐VDC۔܁S06[M=>:Bf7*֒'Jв)+#Y _7hx6`  %y lӸ_5mR;+0WKŘ%jXa2` ع96RsAxjc7JScNp vB\fopJԛ&mTӅL|G0B8LDS#t_>O|dD\u*J܃+vZs}o&[գ5ɲp.!<9*,N%TBi{?%PCg⟕$wbiMM?\xh< UDDfPIYrJi{uS;v`&6eHp%aAfs~qG3h_jϏx)XZq/-ǛDm d,v\fЈE$*C >5=b]rj;>QG'q/N(ydbOiyo\x:ɽx173wMzs™8lC!F\1#At6_D|vڗњ@07ߠV?}j_8>9MFy;fZsmrp/qae3-Pdi?w鿂\-79=7n'yя aOLDo? G8R+`6j䈧܏2B0Zl %$Ƅ؋qg-[8ag3[e/n#_[lboq{pZuh&o#p>". Q*ܩ.QA sAyfoIENDB`qmapshack-1.10.0/src/icons/48x48/PointShow.png000644 001750 000144 00000001440 13145236402 022062 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs;tEXtSoftwarewww.inkscape.org<IDATh=hA1"h ~,DDcBDA,E: ABIaj!"DA"jxr6pٛMnifߛg!G9reDjxZ A; lo{J`\ CPYtO o5W0 00AA)%Z1A֙ƁS/E-O ֦8|dt4у8"\Cʏ~8z ~ "؎FllA b}6B-'+.=;.$"req/[J, $?&Μw>º z a(Q6D}P|30C AU˼@ǐAyCy;dQȤ`S fU>9ne]d@/Q X]K8p?{JqolH0^֜k 8 t%9p-׳#G9.L +IENDB`qmapshack-1.10.0/src/icons/48x48/SelectIntersectArea.png000644 001750 000144 00000002155 13145236430 024026 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs BYtEXtSoftwarewww.inkscape.org<IDATh]hUwfc(ZTFXCRP*UKIsi"ւԶ ~?hSն 6Rff3L6;wfN&[p=s͙97JDFMvncD~0"bsX'" mZ tt=يfQJ=//|E^' .ڶY8,yODlNuvvV5u hQ"r@P8Y,f ȿ@-ˇrU5O,' +^"Cځsɮ(l7|xORfYO|Sk1\f{dȕ@W}~j`.piP:4B1>Lpo-W6T cLHL[)X oț7nJ栢kzU)#]ㄥEZu$:cYRY%"a-ȲN : !y.;r ȥ8 ( .!J R|NNNܬFWm0͵@_)ke5&.Lv C鞬$S 0' ?\5A)ödFw-p>{QG~p<{ GRYkknuGD<`7a+_5J/9 ~ Lzc @n3#pc4;`Cl^P44T^?L"%=xd xGL1+^`i~T/)jXl|.4:ЯS"~mID7c1"K~k ~qyH)(p0o [0~5,3,oQJ̽Çozipv7$=!IENDB`qmapshack-1.10.0/src/icons/48x48/ShowAll.png000644 001750 000144 00000004132 13145236433 021506 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThkPUr^F`%QH1EQLC$UqIt)(h+)fTF*"#&ȣSJ4 }{;@Pf8Yg^01a cz\EV8 ~8ĴnEJ;TDqEYY7on =O<1;鸹,i PJ=V" &ԓ]I^^h3}%4T3خ{Dľ=nUO<ww'F=f6nj١lSJu<9jrNwMy;ý&$d:MeðL& QPp'oiͻ;bR~#"把W 6RO]]V*ԋE$QD#%n""wјls>{_$3XQeܿ e۶sqV"#o3arybJjE7.7&s초$2jypgʕ=_ë3]"Ugʕ[Vv^ziMWV6v헔6pSdgfxb- lƽ!rsXx&ڟbcsaG⫳YE 89 Tn|efFSv3QQI:tu<ПѨ'+k%(,#r`k@Jj%v* 2rYY+1 %=υ| Nkػw911+|)wEd ++vc2Y4<@GSڭH]{8:jˎ&\PN8u*p9:`}Od`0ؑR3yg5hjꤰZpu5b `2Yd'I}zz999)wBX Qv֬MPVGD&,WWl_Z[o0cR)J䄄DEyVƎ57Ξl0_siaٲuc0ؑggZ][lnZF;j&i!<1YoRL)eb\\ ׏[D !! ZF'bm_q8,]M~/5z6aal 995k DWDxy}lW\;5UVU$6**%xFƿe@((}*QM&s^Vmo={J@D+A!Q^~?RfٺP\]hjfD/ED+dڴm6J%JTήy7|%&m;645uԉHxۛ:ݶl)d"677#$2r&Swav.]…rs(+\<۷/?#RJB؛7RS/o_)?N;ao{hi颦2/>MB|-z 5wJ#Z xb:\kVQ]ݬُѨ'4ԃh_}rB@Z_ZׄѶZ*+mbLfptg'<=]B@#[ Rj0DT`1@ 1mj]@pn;Z<ۀ.-m1a cFpRIENDB`qmapshack-1.10.0/src/icons/48x48/ActShip.png000644 001750 000144 00000001672 13145236303 021472 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs J J'?jtEXtSoftwarewww.inkscape.org<7IDAThAhelR*mUPAыx)@"z"*'JiMcP*h BAPU=DPԠ(xMMvof/3}><;<;Ahhr-%|2DKPVGi!?1lۋ>܁[ UԀ$?;-Yw~=&vY@3 %7<#U:A|* ku\r2pjךހSXG웒?-f莧vI!eh}Qp!ZA@x/c{_dµPQ&|;K1F~D* Cl ᣴ 4~buBCFl7K@ 0S0q.F?\Hq`\jN 6Z/.D iA R68J h?$m,q.0[bRޅHXʻ0@@iK9VPwR΅e4 va9JXG@i.,i.,Zi.,i. l&?HFh7̷\%F SY 6"U~Ǻ>/[u_> szj8QkusX8 A`>: WNcO5ɾ`\F4Blg y{ Xi#?3ėx$݋?wkY-X :uw ^81`{VJL'b5qLr1Ʈ[8Db.}LVZXCp⯓jyF& bGEIENDB`qmapshack-1.10.0/src/icons/48x48/CopyTrkWithWpt.png000644 001750 000144 00000003172 13145236321 023056 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs^^8-tEXtSoftwarewww.inkscape.org<IDAThř{lSU?vXuc؀286ÐGà(A#Q$b4$3Pj7 ؃vmqc:`뺶^s~sηqTB7=_b`ӏV~m/"datdEܧjˏsHYB,VXVɚ יC⛮ol7W'N\"Vtܵ>m{bNoÇU> :Z}^-o10VzlohhQW 1%Ftv8yYv޿HRlHuM&D r]r!B/m044GغG)$e`ځ5mjq7ps"\[H#͍-!zڛUzۄqK.ܵg[yçHL5>1m-m8˝^P0湸:ov="c2>e8S:+2琐* x]Hb"]n*8;V>5t*w2nۏGSj 2ef6{؃Pj&Ljcոgܷ7~>f9y䕇2j`p`̓riVs&cRd.ů~%cZFX!xZN;bH՞̆6q;'d/*ŕEW=]f̙1%wߤgs9x@˼_"dMZNQ1 OgFn.NlI<~ꞫCt'!-fdӕW g5wpe+D6@á.rCIPGLΝ9 0|2|bb~$'r;Yi%|>ȺmȜɊWD6Āl2QO"iV@cakH&F6Z2dYdҖn#;??;i={\gnLlC ̘3׏YHˎ4b`xH=[ 4Gc u\%twSTYD wx!4۸f>MM[Μ莾GGO&Eyk0Z߼%Y+-޽w$XcrbM֧+o^p\N)ѿпc-B)K8q֥"QYY7~/IR * !BO>aBWZCIENDB`qmapshack-1.10.0/src/icons/48x48/MimeGEMF.png000644 001750 000144 00000006110 13145236362 021462 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org< IDATh՚yt\}?-jXe-x`,lSɴ`'6 xChЄ&!6@'NEr(!M ZCq `clp lYv֙yoFO{μ};o{H6 lO8>XL 2[604 7E5 Cqq&$#.zl6fo;VO;fOr 6|-5G obR^B +(CZ~6挀A%#{zO3;Q1f3/d-HZ|h9H##` i6R-Uh=E+O V'3?-O=fɺ4m#P~)bH>5ЋPm8}} 1x+z~)y+ѣZDxE7  -s=%sI~x @ DТ+\WqH@ls+id]|w>MۏBǁ"YUÌ"T8g5]1ϑ8};O}a& ,>4o%j(#Y*Z@Co^Ir 1ALP.e@˞LZ 8w%_@ I1i@Q B(Hi Ȫw_ҍB~fgB1 W]Kߑ -EN5wp}X0,= iHc];׶PTPȮ^71IFse%gsvd8/x qi!ȿl|Щ?-Roys#[-Uо!|Ed-;90i䦏P^orl̾kyW)m̞63#PN[@"NWK#7 y5͇&zk@ dRDiGKɾ$s 9SuJqܢLjizx=m=0Ju#iB%!Pv 4 7ueP0-ן[X]ڹafȭ4=KWj˨ 8B͜{^rzAk) Jr9#0ARp F+(gHxѕ | u>h#ߣ1:zsOM_`p/zo3Gɿ|3g?(BSm/ދoA :-]/=8ohA-m=L#rD9xp M4

6ʞSm/_?KI'g-re:_|WeZPKo#q({Z$61Ch?Cn!8g:ݮRі>t~t;4*6aq:pP(e7BʌRqϴ E%0q[{/HANwj8l3t(_~i҈tLWl 5Bk?D /ozN)C&5K)ߓqlt6a'z{{ 1&~tWv7#X=mHB:`t4?Rr_gH#IN&7MGb㟹 ~S; A?C&wՖ);9@NfvZىWBxUУ ?w7#K4?溭$N[yc#Z/{shDHIv:X}DH2w^;9@볻h{~W 4 ?MRBx J HZw}l% Idj-z;FLXNJWPш4 ,c ı:`aePMH3-uvpS,/#P죿C$K'+P(IlKyjP Z{ ɗ8kdj.:P*pRqLxvj$Qj*Q;\N?f`Z4uOʷç~*kd%/4OeY޴i[E2Lnj$˲,oܸQdxMIرok/@^4Yxjl~+>ٳ!Vy{X3 TŋݸE@^^ݻP\I %-m0ST+$αcO?= N||GV\}H2!Ҷm|}3k|PdMhG¢SjK@P[;#*-E30:_*a{ 2PKw1`@99X\T}@555}h?f!Vj` @F/xzpza)ZJ5ٛr]̅cgCYBQ ,+f/13ɦv; jFpP ־͸ wٞ⟛5=֗'r4ߏ\:''Hy@2L"r,.i2Vaa8jwP}c Fm x ^K'0DdFv=L4$EF"˝ːRDvi4=%k&X-ul/q/ j #I;3}qVoNY_q`f/ɸ\ޝMVV22v V|0m;SR.# qHrH9UG aXAT`,˒e!@?ErTWdMBv͠VQxv?0y8~46N\dg',,:&$֧B(n.RHNtkpA8 8V* G>֎C-#<Q*gƿI/c4ya<1q0ۇ4隹A85ʏ^D@rnX FNUROj;[l*1t>~_ ++ YNóӧ?=1: # `Wc@Lq;(+v7t6 ]3Yoi.]…_ԠE/3q<3uzE~~>99X,@{(*9sDy'57#Fp˱6`#Z?!x 9*2tdĉc R9tIQKtc 7f$8 83mj@r9ܱV Ne>_w6c638 /a4UlEEx(ڴ `ǎlr.|-{oKqeEYJՀc5qt6=Go@J,q:4=,ǟlĝېefT OY/3R~W,jH;͛1:u*ϗtf~cCE"Bn=?>QQQ=!&l&M,?;PV\ɘ1cA8C-/ ATݾ/]?PT,^Օ,[ЈNϣRz}cƌDT&IGEfΜyE6h6ϾQ|۲+@ʍwɫo8B7Ǡ`wR`8ɐ!ޯ - ō esRk8ut=.>1{Q]]E^^*{ZGI`ê rZwJ@p eUmBc|-zW\-b7HJĤ'==[_et=^Sn|N7P=m%1:Uz{pW{?]oPr:=`*/GȌYpYbgxi]Rر~;e0zJjw $"ݱY(==稾z_]⻌rA$GPHBڈnC랛_Y..%wanD?=Sɽik2ײx볕lG&*1V?k5x6KjKL&ᤄ \ F`+T@,o;sw.TxALFbT:LWEhpn/"9dp0]%CȸN8yq\դ%K-ː8 RLG{ʘi`o-&~ a[.y-ܿn:tfE[~U1!ƥxf}WpH@n D]n\D/!3\=CWH\&C3E/fVm'aac8Ʉ8Y/ иp51%x |XĘp&uh.yHk90)M$v؊$ b$O$t{}e1'p ~|ވa!i p#EO$#AvWb>-8^5c.@1=/'E۶>=M'}"mcw3~p.aEX}\4KA:YhhU4 e7t4$ tXرxbop2cFo+&vY.ڋt]n)g'塜|l3+݁DGF#b,>vcB>׾ Wofc~첼Ƌ1aÔ!oIP,c\Y!ƌsϫ9ZwL t,L[ĉD_6/b1@QD|jK0kԈřD&6_wCoR7́햝c8?Caϛ@x v3 Lb+D9pH`]aJn𥒎nH`G?>]BqleDZӄmH6c,|5Ka6vƭ v]a}hj(aO@OWqn0_ 7 9_Eu-˛c{I.% ]qu*[M?g}~81ؙZS/.k^ 8ށjMg}i=?S rN|}Ëщw`RKA;xs\ɂ2\HL70RX۴Yts⺏9DSm)wHFo~6?wYvoB,KYBeBGQLK򬗯7Y8BтWgp;HzMgpx.>D4@-Q$r 6Ob!*8^jm"gB78!~/'rXy9%6|d@y(?xyƎV) ) sdV~M:;,<\B'i3pk=xvvt zHI zit ,q۰.S`SVG%{K@8&M<;^7|F+aQE!3ea/Q[u'P4v,m >-5ӃT:Dlg%KǼN*T?D/&\ Ѡ,cD~n9ά1n6^H%NO&Մ3ӾO:1w5d6ogo" ɯ afC?8c&aN X'^`HceS X]n}m=w`6amq"K5%CKpWc\jWG/fA܌غq$!KrGڅIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleDem.png000644 001750 000144 00000002336 13145236446 022014 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs tEXtSoftwarewww.inkscape.org<[IDATh[hUgm-^Њ}%З)|` **B@)bi^@>HS,m%&@jIB$&I4Ytc&l0I63t? |g΅{ 'mxpx!P%ypTP]ko=x I6.PpS l4sϚUwlBHX]y=CLk^Gˊ_[<%MDzC}};M*΢ER*xc0s:<.47XPhb?%ףx{9܇%H2?6w$4 o obȋ=T#,` _Mc3WbY -n]ґJ$glD\0- ]ӗҗy%1*җT]Բy-Й| S=p?KBDj;tMS!xnoiA 4.d뿿4'zFx0?44gE[CZH\>ذژptg۱ c7=Vv6n(;5ށ~aa{iX5I҅J{/ķ0||)K]ؖhuU˅cݠt~(rt.:{3偃&`GӔ&o}s\2Hp<)9@PB_P o 8|ԝлD.pݦTow #z 8h3%4I}1m]0tØចCV cK>Ue$k $bG/7gp7F PU-A($Ԝf狜X|?^-$tIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleDatabase.png000644 001750 000144 00000003775 13203507445 023016 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs M MέNtEXtSoftwarewww.inkscape.org<zIDAThklS5q| .!q iAD5&4ZTjwV>LJU5^}UJ*U FMԴ(i"H$R| >Kv*/Yy.} O?},k{@IҢe%Bx!"8JA׫Q(䔔rg0hrJFgftwO?E_u.^fjj7D"!35TTٌTVyuc,3˗Ň~C8^d`6k9(Ǚ Ÿ~O_}}S)Rv^}Gח@O5Z[ PΦMkhl`(Kp8g||QCCrN>hv|sZ[ CN (.VjkKsV fv3mmٳg3.ximEaTT"44G-lҾ6>p@48wnQ"i;l%4 ,<`jL`Phpsℋ'\lt:FJ@.a0 x2FACjndP_ | ̊@O>Y3grUN.䤟ٻ_Z5kJXx45Yilܼ7e` e H}YhQB!3;AUb2ihV͌YD1΃I7s@ f,v/c||+tv^IzAZ-IuO0#w(QQR-,$v_qUFF8FF<ݒ\ *Ѩf3RUe桇Vd=BU|.@_n`֊;މ&%Tj!߁GvHK O"LFN{%! ?? C%ffOG8zt:H/Ү@sZFSGQ*l޼j &̘Z  ZF\.#17'33aNa76)Msg- 'OsjvFd>|"{ųʻYe?lrː1$Ax.wrCzUY a*mqY|0( C}pkw6K#\c="=ާY|ݹeS9 U  ?u,@eFIENDB`qmapshack-1.10.0/src/icons/48x48/Copy.png000644 001750 000144 00000001173 13145236320 021044 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs^^8-tEXtSoftwarewww.inkscape.org<IDATh홿KaǿyA(AEQ)-K׆E!? ԩ T]`M"K)LQE3t%TswPx?}{wãrVGjI}/.,11&|"d2&$`SK\ v+w_$ktfOA40,'ߌPhCGG}81} hmoT<+n|:^tb>6g;X%);pDhi4Z@- F Hhi4Z@- /Ɉi;vqC͠m< <ȡs9ŧ;RZtV}ٙۻ%'v֡q#<~bG,2QQՂi+ 4^/oC.EN~η7=vrxd_8̬pZ`7oOH4^NGqF%3w>M /ey])=$3ueVo+TbZQ-ڱK^DĦv[l]|mz9g|*_}OeZbAcQx1k9qD=}#eg(|b‹E7;¢" 'ՅcO.U&s;8r2jr&x},[C$*w$,&/(1ɕD߽d!ڭmB%YZ,e rGrgĤD5ڃE+O3rJo!mR7 / (t7%W~Bd̴5^h+prq"*q>_'@Bι>ee( xY98Vdr>7Sa 'Yy[*w-c9%nBLꢝ:sJ# xILԄq~=e1 ^Kc5бP 6 )᝗BfRmIO|l 2Ė0qCt:iiŧ]6J㟫#)©]nF0fu:SBLd] Ks{hn2_='^:aMbS&apb7wPXL7zGGM}EEtw;m#ئ:jo^x޺c7QcR\@ue>yYi.EP[O~ r.z=f.7-5fNOC*qGW8ğڈw$^u ; هK~'%\^-Y(ܹR#[ IENDB`qmapshack-1.10.0/src/icons/48x48/DelImage.png000644 001750 000144 00000002661 13145236337 021614 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs emtEXtSoftwarewww.inkscape.org<.IDATh[legv)bVJA!!ZA#V4H$H|P!QK HhP>(J & AQK[J}3[Oߞg FM :, ?y7OYHNJ;+e0C@@93,!lGy/yX'QF8 4|T~Qc8r `׀ φ2~^-.-Ⱥ rqg[~v8: ,yDPZ]Yo5@ĩ` BEXec~ eN@`X Tmmhg)Tokep\ݟyʐ*m1 3]8o]"E8Ǥktq vuh:*,d:4o͍0Ѕ=@/0ϥOHJ=7\"P2^EJ;#m-|bY̨cyU@ l#<6Sbu7iwf{|` N-*@OϨHt42$wk_3EY#AEDeQ4{v0" q V +{NigpFx߷@,}5U@g>=؄%u=w{rT{)\xiPHYix&]ySukgyhuj}S[K@tҩ0NtUs>!Kl+ hԶoA YCe8nr:#x Feo ־"']Ozfa#Ga~U? dp.dms\}1XIxH9ψ$6Zc&Xsl|4RZ*l0ϧQhquKF߮f+f@7\V(t* PD`M 9TY$6-`^ogNzӨ9 2׏ -M&۬Xps1@<N$i4 R|V9q,VL \rNU"0A;J kp|dkI~6D(y4R`.*H>-͏e+z?!%.} 7V*Σ@D5j}`uyضB-m@[a12an68ck^@_ ⅾw Կuب^/^d2%v`]IENDB`qmapshack-1.10.0/src/icons/48x48/Image.png000644 001750 000144 00000002557 13145236352 021170 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs emtEXtSoftwarewww.inkscape.org<IDAThYlTeΰtC+%b2E-BШhb@!!& 6>h H"h C !!RڅDJRJJtۻ ߜ߽w7#`:.`D`c5qT :b!K@l6N%g0'%?$u(+5yS%di Eh/\bӀdɃZd'ôH#%YF1f4|TȔ10›B C!^} (+&.n]πr@ƽI$(OG>(]ErA'! ?E NHsW _n3K gQqU"(tu@½<1rB@a(; vg4?p)1L& o#ƗaoFDj@Ng:uµ a;+RR7h_f{` s.8= O&FZ08-` AfJ#k%(XMi9oyGA opWr\n*Ҟnmo4}Q .p[8١5(R߿M Hzk/Xs4)/Σw]T=~2Z}fF{ꞃm,ɂ+ L<=Oɲ/,NEt%2 ޷S| ا;ɢK,d_QJb| 4:pJ, ֻz7{`_\.<hΧd8U aïc1J*ܾ# Tj4K.c`[}l~4gTrNy6NAG*l4v7v7_7YZ0^u;I4U0RPd%xHl_ 0gw&VDKv$a Ezsf бR#z0lVIhO:^hy 2z|CB_඄I/ŗQXfSyېa &a'9ƅmā17u#dX?ZU!א^U`oZC)qpevPBm 8`P}А%ԖH+pt:n˜v[l 58JcPw6l7/ׁH/> a*H cѫk$V|`a 4E⣔װc=+{RZY++vk|x39m&[nTk¹X Зd\7 >p~Wv,q6.WyW|p"遺ߗg/{iR9%v&Y"J)pp 0<+:4#9Aa/B1H]~0"/Ho%Y> Ouܖ;z7a2tB3@hLݬng)LcrZfg݉]pG2 CU|+E{ Gr7xq%ڱ v pwuFvBI8 ejI0>[>4ɴא֙6p23pI> Sl0r:ɀZNӉcڊYQY%( m9G3$Ƹ( B/S|qffǫϏN'-CXEZK/CۈSw*px!!$ϐ{t}n' nނ:8PIENDB`qmapshack-1.10.0/src/icons/48x48/O.png000644 001750 000144 00000001775 13145236373 020350 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<zIDATh_Uϸא00,lbQIaD7EFe^i" !?TmKD EQdHE?vci;] yޙy7^>wmŮlἒO! f?w߸"J-N  jˮzg}!Cme3b'0FV $p}vz y_O+^U9~[]_N:B+F"|5n4/K! @O@冑Y8O&kϻ ݒ" L).p5n[ cWDUhfU:{tz~ÜƮ\8&|!ꗛGq?9/;#)h`Ïβk-:O^q0DkǛήS]O*:Y@>p$N縁 '=*h|E:Fr6J.U.=?i_%ZL.sG&q@SĀ^HWމ&E(M2t dIT=q˪юZNf+^aJ[roP+c% ~g`/cmcG3ٿ񉱸aEaRI58`ݒ8 `iocf\2~umf iQ?# SQ5O)& CP"Fyme_ʋq9h1k$ &еc D8>}b:$4̝o +lfdt_"@Q4aM/#W~h6~!Oe11ѯG^"VJEf > !mմ 6.5_Je:)MvOE"j<{ۉ7&RATi}(˴$ݵݙ&/<|Pdݩ0j=hkqkq'~W!GVn,1M'HF׵4 eGZ7%j6;)Vvp6zԈ,eK,: V}oSU)4cݮf NId[ď~,PVFoCnkhVY6pdc7xI*sW `Ek OiiqoexDpz*V@8p'Iwc1o^ .,Oe]X)b=u2YN|VI >V/n;ۋXHn ]Ti]s$Zp~!6[C bR=MZ,UETi _x:Ӷ&G߶z?Ј1SǗZ^`$k|:-l~~`m {$(Ff*kz4gVq5^[5E3Yc 6ήFo'eyh;&u3/.zk?^=Ʃof?UiR⚫]s7X\1:4Q9&Owm 9Ѭz{KlIő u8p>%JOfV#w  Cޅ&Ff DԷm:ٰ6De#m6!1?mE)2EwYۺ:l<18Pm,QXM$Q3H=uH& _H.z ΋EV6|EwOnς[/IENDB`qmapshack-1.10.0/src/icons/48x48/CSrcDistance.png000644 001750 000144 00000001630 13145236324 022441 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs((D;tEXtSoftwarewww.inkscape.org<IDATh=hA0i?"BjQI%I$& WPvbSFKA$sə7;8۷ff݃#o*T w*1QPG*;J+N-=֠Tf$ PlQ"l5 L`iE,Oǵ,<1BEpǥmx ~Nv艸>Nbɧ 4f@t˃vZ= fmL~{,5<VmѽlB2X;[+P0̢Y[$L@fѤ+5̢ގ5w.82c,׀{!s X D?8Aо.|7{Y!(G> "jlg!&"zju sM~9 t9&]X i(2pd^P{RҎ; |2pҶ^(-; Z=F;kM'i`^MCN4 ky pxȾC%ޅxu}K!`G^ȔhCذB{L+5%:{n%7slȫ4\ DWx0í.Dzd/螧%KH$fe:;ʧxQC `HihqfYZ  x)_+fB\\!1!(-cE(ܹs –-/f]JNd2r9˙={6َxkZ+Rje&_g~l~U)umGR/i !Kl,RJlۦ1˲Z11fR̽馛#D>qt?|8Ϊ+V8555+գ_`13YץRUƘMBGnpmma2_͚5˪ pĉqhhyWR===X,fΝ+-~ӦMΜ9s=uRsEEEceeehikkSc'OJ),_<8k֬'eP cYBh4իW>I۶J)< I *,p[mmn3;S)T*Eee%K..]ZNٻwSf)e xbF/+h8Ŋ<3}}}2hB| D"뺌:T;垿 u x<+++/r6n$S4xeY jܽ{8|AǶ".mR)h2^)uʕ+mgw}wDq!qXhф뺴f2gÆ ,OӴ|ߏL@ `Qx';)6FQ7 hٵk1J>t-wyg```cǎ庺R{@AuWuvvrAWkyA)Еoݺj϶m ႍCmZPE Rmppp9|8rRܹ+Z͛CKZ)-\00<<̞=)%+VdJKK6n,ɎB󸔷d֏߰,G]]][X,Rjy^ ɷCy]]]sfkkkCZkɤ NX,f ҢgɤhѢ@$OVō1?Ƈo޲lٲ3gx###Ƙ !_n]8p1Ƭd2n2 c~nxmVGG788xDk'lH$@, ?~|1&jԮ.6< )8[jRlnnOwy'{ck/~ 3dZ녀Z;*X\\}r競mOqR٩}^Jijj$KD^&3Mm_۶OP&O\H$v:;44eYK1|wWkGGG^tiв,٬lnn7pDd<1Edac'pmmw("ȺׇBLɩ̙3SN @@mٲŚ\ 2>>Ν;˗`7}_iQJy衇 aضm[իW ~xyaix o||Mx́H$뺼 s`?WhBlQcccÅ;vpGGG gO8Q^SSc &S%ɰ}\.{^kIa?~|U&1ΝgϞ=kyf@lhhq={}JZru]zo M8q:::d1f1_,?1[.p2}7ov(˝:uTUU9seee6>88cXfH$cǎ1u502i*WK䚾(|\ѨFfsܷ9rH̙| }}}Νm 뮮qWZ0e˂f)cUTT O5\uߴm;YHEe GR̛NG>)!DPk;}\)V.D XUOر;rt:\i6-R>*tZu}˲kjj=#f޼yc'ϵ,E˲A&dP(655۶=) brMY*$(|Q!Rǘו'~ IENDB`qmapshack-1.10.0/src/icons/48x48/SearchGoogle.png000644 001750 000144 00000006046 13145236426 022507 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDAThtTյ?;B Q)*"{Q뢊 Xs˵Z}R jaCS)Z$H@! $Ǚ@w̚}>{}Gh@Fu⠟'^ہh_5Vۅ^ UUpBwQR@i Od ` uĔpثpR@jA+0}h΁~ ]@C\.X %tPM^ˀ\OO`?PAxp@@zb>PSWӁ^ !nõ  $8,1&]Ok= :(A YCۿ*h%/4M~4 $D_o*v)|{n? 1Gn@m@M3:+c67N@6VgO:@}  uUuhH/Dz <, ztD4* bE&U zl ?nog/:_DM"K,zt?ѽF WG}/ZG@>C61GG7oFJl j-[̍S'+O~g G6Pm*C0՗ʴi]C4o%"r3mؾ` "nqyr;oTS+[``@^btB 8HD:T`p55 + az32j({yvp0Sޜ2)5њ{m`v/Pk>3V A'5N8CEeN/'y8TzGΘ1"gP5kG4j|/x{;$`N z=?:Q䙿^wM9 0:?wz ZxV G③3VyhwTd◗G b4&yIznxtISF죪7' /pl˶1'XvvvXWkpVLK{7:a5=Ƽ}PR]B빏B}*0JK8j6i"W9o) X۪z5n+X㚦ZsP^x<¸" ­ qm QQ߸ ߜ|.'|_q5w~=nuy)>YmsbU:XU3U~[UǫxW5- bq*jDs[AD :g4#d̒:FXu"Z夒W0=.a\giʈSSNTbBW z|:Uw­ %):ZMYMLm@ӥϯEfTS u'Vp!-L2RUoط^}7KK,fCE)(H-gJmamV&ܝL&.q=sνg;Ë Q^$o@}}-==}s{sU9@!|@QH ($o7|IÇ46|do|BR8X4**ijZsnsh,c?npL_IF㴴X;;RWWՠfffI?̧rs|% .+)\)ep\r_%xGWLO@8<\Q\Io(KU_]%P"ohW%CmnB<$5ÕZn@`T;qOhO xc!yNT| BDw2E A &vx5`H#J f\+[q#cࢦVk~˸""~'-N}Y:u.<#~לU(4.":'E)AlsKf1$X>(KsŸ +YXaA`K&Σ&U]y i:@w0!B_OQq^: ~p ʄKh<0ѭ;kkw&)VGQK ܂KbZeRwMMguQ/QU_d+ T, ,~sQj\Z3ߞ0S¿~8.mġUhulE]70l _W,| W~N@C:k'PԞjֽAāoPO:u||:@8"/D\Bw>M~Em[6mX37)ǁ^M5v::7RaT^_l_~ IENDB`qmapshack-1.10.0/src/icons/48x48/Progress.png000644 001750 000144 00000001200 13145236404 021730 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThؽKUqU&`A %BEDFAA8RHEl k/¿Y"pnz~sᾷ#yCښJ1WM*P`\zwqRR<L7~i#0=&Hܽ\ -. xfT 9YBp /# sx]IWH bҬ*@8U ]Y0aSHӇV*po?p&p__x"03%݆-.ڱsU֟b]#?F&Pm08DB&&S[@A`ͿWzr Lc 5L,rLac@F0^=*b=taQjXՏz$WKpa0^<Õf6g` قI_ ^4N ^⥂&6 A^0!%.o .|<3-^ ([\lV( JJs2+Ի*;ߥ  [ңOi.l܄ >A`H@-mSp@pDL g ֹ8XJ/ r=GdNwX!X&K];Cqc !媝B9Af+#$+.0q '+{B' (_|5݀jY0'>dv:3p#\xoKbf7q{^8 vnh{)_=<^Q˒U9ꘕxtfɺX\ L (;l)F9=p$ʁJ`~fJO!˗Cg<"ʰI@!l2˰Ts0>Ȁ]I WW P_Şm`u ,y`{ &)? yi}4Z93m̌5@pZj 6g)mlTR:J}^=h+_;*G?v5ɋˍ@vtR`ZmUWV`b&2&;_}t74!" "u;s=}= 5 vm_׀=b~&`ʭv}Cy DH &[[kFDe,!`[*]  DJaeΦ7̸ž/ÛnF Poy'x? 05JL@ `y sHwn&C`"`xHd:H<^>Zr2Hh{</ఀ'E:\ß߈XK:{\vLx@l9!t=EqlAG pxAn|$/{&+JX.MܪxX'p('.w|3"Dbo 6 t24 %Ӂ Ă޼dMs KWki(2!R Mďl6;wN i뇫VGPi^ayNӴF 0Cz~qcSsY3-'p:(0X,]wXMU/]8M qo&Z4`!P+bXJoƍ2MTN _L"B#3} vX_~I::t(2o<{UUsKIIIt>:;;+**,bd-p8ey$IQG΃>`"XBdM]k{$No' T*iivVUVVJk֬qlG@@ ` PE4$-YĵiӦ+_ee\ʷ}nZmC6VZN$prQ;88 X ǃ'D"Ν;C{ W^h@N G{h^piڏVչLܹs]2600gݺu`0xDUS˲*M.\0////=bBpy睾h4d<7^Cbofs[Va6 ZL|ԩS_}AY//Rߖ-[uIZBP0ƴ`ڵ;$ǏLlʘ0.=<(f m'r #z4-k~OPhnOOO8PQQL$D"ӷmG&.\4;ot\狊vq{? (|VOOaȵ^I0M^0Tj]kk?'NhkkkYs0lݺ|>?3g*,aÆЩSjs3;B8Ε ,ȿ뮻fرݻ7FB6`f40 i]ן$r4QRR"+gΜrˈH x>ɓc&O?e ,ZZZD"ZN2!jY%%%444lذm6[:ƌWcѶCxe˲1t_F D"o?~|q{{xޙ3g eS8_\29T]]mohhdh,ȑ#.Y;qD~-mLRپ褷Q@:whJש`0eYGr,p8cwneY$j477vvv&XUW(?* PJ:{].׿ !l6[*UU%LNƌ?@QI$]$Gv{セGIWi?N$qHD(QTUtB!ٳ߯VUU9O=T>i:t:p@,/_3k,wƍH$,_ղlo߾'NiD"b\Hp(FKNp8|8//f͚$ .k׮g&_Gѵ@oKYzN*yX8IQrnGAGGx{xD"3BТ̞=t:4-~t~JNw@Fi>Wt]﨨zx<뺾t`0BL:U&暤Kx<$I'xb́[(ߞ v}裏N3g 8}(**1c>DŽT*)隃$IN]痖ϟOD"]l)S~y'L jwwwsɾرlii9l]vIs>OA\(hij0dӦMe=Fn].ӪnO$W^_VV;v,|D֯_wIG[4:-!LFnݺσx<(B!p8n?  H45{agϞ+05]7o@VW:΋/0aB/EQJKK{-[&Fne٩].[]`}LIENDB`qmapshack-1.10.0/src/icons/48x48/CSrcVertSpeed.png000644 001750 000144 00000003441 13145236330 022607 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs AtEXtSoftwarewww.inkscape.org<IDAThUݟ*#C8Y4eBa9ZN 3Hb*+ cϽ (Q 9iYSdY+#+ff(!.w}sa}t4].+Y-f¹f.>->&p~ίg>/Qs)Аwz#Ox?F&1LZ/2w16oTKG.LTJg_ nV~u"ƎEXP~{*ѐ@'Y<ە) ''ƒY0hRZ]\Òdq@*9RP3ܖ*C ?}aއR,;C1߉=9L|&nz,8Y^){As'Sg=0.tC .^4S9klFg nBoaD2QR kmJ#w.|~0?q~&ؔ ے@ME/Y)/AuB3)J6Ǘ.ُ;q-~"2l.;_JqhX"x,{T/Yrz%(rAx#܎zv/T*[@K׋@{#{9;>4"vEёz-,~LW5<+{jvQi{KGuCNlg:҆i*}7@ SlN܃ o5' Q\8+&!>pwsΡnP*zvDb-0 XSQ C4̡?jHت!%m83>.0/ThtCURi-tX}$Z& HUpN Ǔ/\% hMjX}\@t$~ cE!h.(|k۟q5fwFF ,2d֯1w?;(2ɠ~DhV@ާ@ Pyn:{SjVn1YO,DhOĩ,to ?("t,`x23X/+KܸAE^IIBZ ;"w/̳'wX5̺b("쏤(BE31AAk0k f̼"=?~I7["Vib#(`@ tO`FFVSwҍזӍ5;Կ' q?XA.TEKBIENDB`qmapshack-1.10.0/src/icons/48x48/DeleteOne.png000644 001750 000144 00000002110 13145236337 021776 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  Tg_tEXtSoftwarewww.inkscape.org<IDATh͘oEݵD q4\PCo9A##"(sCmT5AٵQ~88018k{ ɗ;ٶ \Ҟ`_H)SSS͙q]ݬŒpٶ-!^\\ԕJE艉@JMrp%)eszzh@eq~,+\ZZҵZMDZJ)ۼ\BfxZZ㔀q?˩eh4zʷ) :e}$"GY]]m`.uK 599I>7KT'k?};) <`>ޣ7зAA9|Zi04A] /sPhNWJ.l%p r| TPA!Ri0&kpQRIy<y|l9E@ր-8 @o2J@(ʳ }J9CBP7#в }<p= u0N{D_`w Z܆zRIi pǴ{)I  Nt39(3Ut3\B3A(4ybB9r }zh:g4A<?Wb< G9^{ʼF~`.%.4x1:ļNεQ#Sdx7-}v_@cZ t /M ~e#t+1@`^XΧWo+ C>p(Q*)uЦML ֮_*GM~Z/s' R]+Gڥ:1-=L@4LS4Z# C έ!Pwp=a5ʫKG~TIENDB`qmapshack-1.10.0/src/icons/48x48/LoadGIS.png000644 001750 000144 00000002644 13145236357 021372 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs K4tEXtSoftwarewww.inkscape.org<!IDATh]]Eߜs?))p-H%H#>@Bh4Zښ>VH(Qڈ<\jkDXR06H+Ja{O{νd3̚̚5)1,xEݿzgaWX%p13`AѫmZa}IK%pTt譅%RITRFKTlLIįEcs5/5.O] >ZW%+Wur<‗볶T:Di~,ɇN:*6[mRX:r5@'ARN9&&WYIWM9i .-I$%baPlah V $0 䪢э[=g].:1`)Syа$ /|ӵ~|չ&}T ݢ)wkx۬wƥ`@!a>-'x.gz5\@qE[J}6$iQVa.KXkv`ro'/ l?K.E`)jߋ6Sx1=/A2 ӫմ?ǨͺhCh&`/GlNĎlDFgk_qY(wߕ#Y W ~n#vI*D{ c9a .'Ës789/ODԮy>ⷺ霓x n<撙ɝl5?z ؁q~__c2C,]E7wIl71>W;lPP#~Py"ptVyQ#|[(f;+p8;WIENDB`qmapshack-1.10.0/src/icons/48x48/SaveGISAs.png000644 001750 000144 00000003743 13145236423 021670 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs D D$GtEXtSoftwarewww.inkscape.org<`IDATh՚{LT?gAP@iYXYUyK25[룍&miܤiUۚMl\1JiA#q>&naw vaK "0# ~{~~~;{g]'Kdhn̙FjjԤ z6h!`ʧ)+ޤ ^RRŞ=56hxBSg!@DDdȈ9n~Tt ^r;-a̍ tD$qv-[.szۈGOj~("RA Vﵼ~th[*HR1u*ϳ®(XJ$ -hi @@_b|g"P"[` 6?p9t+M8Dh3?#oA#@Dvw# @p&3ۖm84£_obkW0+^)و4ZYºuG'Qss{OzG2zg˴uD$~{7dwh!@+a0/^pAHzx3a2gRFYرftX369j.铅~Ц-?$ <ن, 4hӖe\nC܆6w+vbb; lR֬:: =]^t  %*ܔ7lj"55bGӰ2qAi6 2WJ=T} [n~b҉2{Ճ6l\ʶtq~~>F(Q ٹ+>\ρ,M38,Y7vJg,d5LGU[:,Fd af0Uv6tf'/oI_iK&iGgtȞMz|z;pvjyU`Qe-hl v&>;wEDJDdΦMM5B!"Qv%MwDD^7t!݊Ry@Ѯ RS K$3Ew wk\)%8M `w,*$hb PQшl5l|RN Pyaq{p:C+Wؼ+s ea]b-UJ yo[}6| c}PKn}yW׽z}{@,d-̥ @R77y 3Dҋ /ppy4s: lTJy0xA/|b`^<8 CyJ/č 3;0@Dm7b^z\;U_v WcY 6|C\|K1DIĚc;b"%2lu\֭ٹJMx!/_9-j3L N[uFS|#gC'>rEccM(u(:GRIRK}e̿؉wM#6a`]ޠ HxQ8G7d[Tv#+~Vx6/_wpQwx9/G}Xcv4o eZdZ~"XnKӂQcPUfJ7?QbEb9Z MfR.l>["tQeRj Kd Sـg{Uμ(qJ7+QN<$<}"PE]eX 6E\-~%l~(Dԩ>T_[Lt? VU4o'Cf8L~+ {¬\toֳ1;|f+:|N3mA'GUSՇG?m.XqUڶm=Y߼i+dgcY1pdj |\Y]XTu"F4Wa>>5m"3rPR'|T#Hֆmriypz$k!}ny*pJaEՋ8xiKF}k(h${"0zbE9 ICaHgп^p ׎UrT"}kO0j]hP$ X놥ETaF՜]#;+[T8Kx]{^j /bI+nY}MzGfԐang=\F(WW7n H56,Ariha\q[I5:n5mF]$G}ѽb.oʴ#I!K'A˧*0EpxHW XYtbG#~dS~hӻ:ce{3;Lxy1dUWG02zG) Q0x%lMIY8 >Tj҇Qt3JB](Kt wǜ^^{ki3s~ߜCc^ Ndn"bX۽il^e{5`FnqCpuVZK4xuM&\^Y׽:Q6@PF`|pPc$ 9Ŝ=mYi^ՋF8ÌC9KYmY틏?>з48Udfa!1iWVowjgFB+ikF`Rhgz3$0mL+Ș}ߎͫuH'IhoU<E!E|,ZTۼC=:l# P Y̕t)rM(Ҭ֊ɥ3N=8Y lڞ+5夅7-e]>UaAK(5ĺRb! 9T#Y /vFBk1G)![3DN`t] 4+Y3P} L.Lɮ>u9 n1x7$e]} |>+JVq:d{nj y7ہ-zB}^B\ MNDh|њw>6G쑳?Z>sgŬSN4aZǎ 4EzB).@=.3|HZh;cF 4?/FXhM,TlI",kx?Lr榑rSv:KӷJkE`nXR_B7a1+U[)l@H3SJ?p/?ԅ񬸐+^Ξ+x=+N}8VWrx'Y7Kg :?#}J {-3~QeG,LgZz--٫Y˞wcȽȒ]s^@\c`AIa7dkM_p#PFຳ(>΁T;p"Rxm\-\dȥR  @Ҷ wR~R2~;Mx(ܧ$=I/qƣmP䢽5CA[{IENDB`qmapshack-1.10.0/src/icons/48x48/FilterModifyExtension.png000644 001750 000144 00000004670 13145236343 024436 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs ymtEXtSoftwarewww.inkscape.org< 5IDATh}Wy]U"i SFePEGf4DQ`/ )$Fh@MIK!%Xbb2D,1c KyY7{w]~g~<= ,x+KnˢÝQ7%9<W}D\NxR=նm&י*q9xTߝv-'3-<伾rZaYvFm9C.?ڼُp0@<t6wVoߔMݷ[܁K8f}>ϩğ+k#aQ-#ҒlYOq^Ay[j2Mw܏'RDvD?xmϢ߁ۈGv-}q }컫i(ZE _Z}a[xx=1G-u;řx2*K2lK$:eV5thcKBc0R"/[62+p+,CX72܉ &l޳m'dW i~G=\ӏAX wskW[t c1&-Ys]4R8r2<ُrpp4#Bt-a#CB(jliѰhJ d:X /"|'~HZ ks|RP7FbHeY~AJ'2FvjʑNy/p0*+FQABM+P_9XeD_Kh.a) QgfÞШ[3 ֑,ISѐfΤGxxU^?nlidD>oQgP ^l'B|0&ɸ7ǎ5_~#tgPpEW(XEQCݚ9o4ឃGOaO#*ePpaY|Mm~DRZZ/o+;|#$nr٨?: MvymѵE>umdi\EQ{GÉ&s OX}_=5gMm ) u+ė%ELH7~As!:cDŽF't_G_s1⁘nn6vʒQꅀ8߁ǨK20]}GLv뚍3#:%~!fl y"IbJr6T>=G68S>UؕQ{[qi͋?\9MXGt}%vNpǯTYR!_>4HN9gc|xvE38C1v=@qBQK{ˬ 7$d*KOw `@lh$e2xt#H+gSޕ\ +Hı,iy-YʲD؆2uT?%nįc:Qįeg";4,Ʌ"~n VVr?$ݫV7n Q2VriF(C]-bځTr}?]Z޲4]W+JbyEuzBPzJYIZ1rU{$~N&x8E>lP"Yɯ=[^Z>~x!NQ=9Vq]Ici7B{1;\/YZ% )O1& @ lp@S !ڽ[H2ϟ?oͭBAA JJa4 0@NL0sĔ):B!HBHOý2+fǎ8~ˮөJd؂+p:lxMV)B !f<1]z/>~[ʆ6Jju.8dH =fAZ,V/\?^zI\-bff G7=GN`$IoWT4222>IGV+WB|T }%$yȯ>}W%Sgr1nIRii'Zb+WbqH0,,B虖f kM55fwxx UWH7']y$SVxee3 E<+#.H;i҃ ؾ}//bС5;H>_}={`OPVؑT@ttP*a2YQ[ۂF?^-[ 4øqZH"Jq+$_jkxJe>ٶdf^^ͲBn5? EV$_:S"1aֶ f  VACii,9RU@0)a4HI娮6[p̉Ԗ7bݺ#HNNz_յ{Bܘ}8Ǝ Zu19fT̸T:N!IN5kIJ¥]~DN((KIʕw/pw`;gώ|bV#G.]Fyy#>pB;TČ3L0vCu!ZBx!32' o%/DAWAD]73?d &2³=P8~w8mvp̎+E H*`Hg[[ p >p'ǵVӏ+1.g[ p<P ռpy_v;|K]{c urta ਯk<ۃÔxpFf(>*ۭXyTtiUeamq=oh~M,—=u?h:QJve`p8-=9mwL#\.S/O.O!)\:uoqG a*y,P^6HTQJBȖtp9'=nkpmDKIENDB`qmapshack-1.10.0/src/icons/48x48/SaveAllGIS.png000644 001750 000144 00000002017 13145236422 022025 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs K4tEXtSoftwarewww.inkscape.org<IDAThhusmcbZH4"F?,C!RKJʿ DAB 034tDFʖmw;nwp==|. B„X̆J&L*E(XܘXj;XΝǭ[MbN))I/0j3wҠS|8x˒%UL%4r%o}۽s #P[0o̲bՔӧ&--̘Q[RlmD1-E@_߀5k]?޼~+V̮^WmI-$zbW>o40`)C.!&b-+q28EE~`T6%w?ܧd3CIENDB`qmapshack-1.10.0/src/icons/48x48/CSrcEnergy.png000644 001750 000144 00000003151 13145236325 022141 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs w w5ttEXtSoftwarewww.inkscape.org<IDATh{LG?{E*GK)1chb$55*bS[imcJhWhW0@sjCkZEA?q{_fv7\D#=t1(K^ ( O䦃| q r!: H]p}{oVSy~ \ Uy]fM`?{hAŸg 7qꝹbr{4z (.H ʀ4&0xƏK@\]E@?E"}6 49(o]gB^JF%9o,^2uu1;ZLCQ^Ygܹt;ݻ/z>JN*֒#119|x)/fXi;;픖I驇z&bfyխe8$u16.C5:Kbbqc"AA.|u] k^yyl6&UtJQ0 7/g#xȑ46oN<ѡ̝;A{_`H4c7M,cGݽ{br EK3.w- EE~htFc2HAOܗ@45tu-s/(n7<5|/էhIuKi Om;;(N\ʟ0WCJJ .?X 9nTVAr1ާO8t*K SlwmXNqX9d" T6DFjU< L$!abZZ:ZR^~Z\>tb&Rw QBTT8!DDÇ45=z |uMO|#%/ID >q݌cz\_kؗ4IENDB`qmapshack-1.10.0/src/icons/48x48/Error.png000644 001750 000144 00000003640 13145236343 021231 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsttfxtEXtSoftwarewww.inkscape.org<IDAThml4>8 ncЊH*6 .KUZȋ=0iZ"%QӦ7QH@U"p@[}N?ǝw_ngϳ3<;e=D =JU@ Is.8t=PZO]omt߯シ `8(4F0JiMYS|ZOtoj!E=+h8-84 cq;yy $ 3`dLp1rȩasOJO0s?lqhOY8P5xW}bx%оcc1,@2N6 F w(+@ R [56#&&2J=R<#W;JM}yh`om`{X̛ڌRF^{ ֢(gd]Z\\n>$ÒohAWg^ZRAPj̷'םADru@m-/ 7Y9RZ0o6{f[V d灯*~e1~(ί#mi".8\%G'0UDc-a_RwzޙY9O9c! T7">U pwd2<[=3[ rgM`CM#oIL^3]o!M )Wsn \ >&Nbஃ&zD S l?G7 ocʞ&-c,ڗ3r:靸?}Y1S١ d  ,tkf`%=޼wwyuP3xxM5"m_os3yqj& V$MutgJDCb.P5sQȫY{2Y$ E stv{T4-a߁x]ľTBݦK)ϵQ h/ė:hZJ1Q1mO a ف =b<\!@ue Eo&stH-DKkȍ@ )1q<>E%rՑ\?]QDVDpNSm^%Nhx{<p$ Ў;|"*Pwx3]Ht . yujh/4l}N* yZ/KG|p)9d:-Df O"|,zE{^k'0"g n: RF1tv:`?e7H\;vSV 1""OzTEԅ32y,qe˃\y4ܔl=+gQKE\yՋ* 0jTq*/h{J\}I(Cij"&Մ.:[92h"6._CK.C䚋?TA*"Έ+b!N|'>XG `D[ˆaz(/gDLDKA37+'z\%eT 6b:=O"nflW2"܈w1IjXqiv$ZQ:]&ê=sҥ>ʙwm-WaKjF9^B4ڵSjZCQW݁}IdE bIOނoVy3ر}A#?.EVke$O ۮ]cd&M!b˺#^C9uX=LiIv!̘ t:/ψZrѽ+a`8 ,[v"DE47JVTԫ : xʋ/z"p=/c/R;Y kv|wIqN-=5Tj<5vcƜݚE:)*j鈌pqFKI$]Yc<b">$EdkF_HeTm<7$a[ՙ/VIYv1[09/݅Ă&kj?D޿R#lڴDotqtbnU_6IOݡt~Wiwܹy>EƵ vu+ٶ{鿗yF,~(>vR%m8L\BW^GFn  o(/)R0h/A|uXM9G#\MrUQ%kZx78JZVӍ.GIan,mνnyWP_TJήnW:&P|Q/a .8K6K]:z|Γ9(xKFl=yheWauFARҙ1%ŬfZ"Bq/(ϒ+z9/jEX6tcN{f٥N?j7P;cg+93<2%R(v+%/%HN,@]Tɯ5uw3RPy;1B$ֳ5Nx54ŖVRt&KZdG)T7,|duǧ$3wX2@[֣j%)etR+aB2^ ?Y#D"Gx C3 |Jʵ/ A_JxZzT%1N%L9GDll\@|0Bz?HTͺN]lj)AޮJ&?Lfni}ٟf6-涶@ǧf9 ppj'?m7=/ Qf{*}yRZB[D R])'~.Q9e)VeG;ǽ_.VodMhR~0k'°@C䮫^;Z+}Np %SJOwTBWMF)e*XͲƩ餄s۔[,bшx=&Ň2 7|^%U}_e VO̽"q$& )ñf_;ӷ7x~^FIJTO7}7"=5 T%%e:+->C)j iN}W/0t/)'ڱpZ M'1k-#Eed$qNN<&@6>fFFIENDB`qmapshack-1.10.0/src/icons/48x48/ActFoot.png000644 001750 000144 00000001346 13145236301 021472 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<cIDATh?hQ?ˁX7UŢv$)H͡w:9Tu!J \]"nuR}k.r @w{_xS8_~~6^ڍ_70 lb3N|2 QŝOGuF67y3X JC.*rJT)`=Ŗ)@[Ps)r`_ ^\bK5c8؃-;/S [M4\A}nW_*cxxHCB8 0mˇb̯\1J*J;} f"wU^$F)pIR$F(` X"/+uIDx1}r!'u3\C!]JE|ofl1zLk\px!>( ,f/`"`8iNgpQLW?"wŕ,f ~u Km@jLy`qS}->8 $0ꃓ]iym \և|L+HIENDB`qmapshack-1.10.0/src/icons/48x48/ToTop.png000644 001750 000144 00000001544 13145236452 021207 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsV첆tEXtSoftwarewww.inkscape.org<IDATh_Teنm]d-)jbRb$DaQ$V"btUAM] ABb$b"TyBIVj*!33+3Y0s}~?gN+Jk^71m83}:^(41҇]ϫ2Pqo\'fF˫_*WoۍnuttZǚ^q `0o;Zsb&OyVc6cZiX2qZH& O2kO ^L^KE =$|8`EAW|u8>}^)͏B%&vͤVa'>;Ex+fb~=؄e,cPG0qod[1ỤA\VEv(.Ëvr^qP" X"&\zOt%T=}^B+ ҸsiN*q܀/G_5 v1[&u"i,;17(B|ۆfxsw-<τ_0O ]'Mfi'Y/5 ֆb#à8f vQT&m 8 <xMX.baV7-{P4)M)hJES (R@єP4wJ!.rg㼛O޻;K"Y-~R2"qN ( zIENDB`qmapshack-1.10.0/src/icons/48x48/ReloadImage.png000644 001750 000144 00000003306 13145236416 022311 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs emtEXtSoftwarewww.inkscape.org<CIDATh{Uϝ]>]"B6W؂15?H RhiZZ (@Kj*)kiv[ihj[ov6$~_w{>9@Ħ@6k+ךK3%-5A{:rseV8X}o9._SėM4!aW!!܇F$:;$[t#Xz1 i|-q 98^[E97`<2&:LpJ“BŎ2%O.vˆB:ȏ/#YY?ȿ"h͗pMnۼ/܆+^r^qK(c.B#G"W#*V\Qy\-ٸ%ELiD?%#\ƿ2 J˧'!hQ/'GO~QEտL~x r̚ Dz.XfgJT~bH(NRɥR- ese6`c6~GX[>%RyBwx2h8E_"~l >OTk^Ӆ{eU!sz !55&Zl$c v%θMd c~albNL4%ج q>n=А7q{DM%29cl08غi/9mw%E؇oV O+: 3 @łX/(z ZQQ3<O.ܘf8g8~p>7{m<PcΟ+CӮmp=aä]⎦2kO 3~ߞ2x]yãXa||M8OLUl}3Z蚁W~a%4Z[ز$[ß4x6.%^xq)."$S.S>Ζ;viNtkE{w.CC1;W&w:7mz2nXB&vU4'Z@v݃/)k֤덮=U1媽'q ;1/qEI䣥r+ BNnog*۩;rN_}[)p=, }U{$vaDǢ'+Bj Ģ#(Cp%7zʅ,jIF;>B7~#ɮGsUx'51;6 #2Co|@X5*'" dˎ^g.'He]b =RtQMn[K2(x|89i Jiю8SQ pz&<{n&~lbΣXL&'G\˝#2@8|Iko炣tB<H [GAJFsW9y ],MJ$fQ;D4?:*>gF1K$Y>O\mOܓ*mUCֱogl jj4ࣁA6MpFIENDB`qmapshack-1.10.0/src/icons/48x48/CutMode1.png000644 001750 000144 00000000725 13145236332 021560 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  6ltEXtSoftwarewww.inkscape.org<RIDAThJP/qFBŝJqQ)} O h۾D BPjbF2dJ7͹K !B!@ze-Eq_'ˇYHAL/ ʫ[*H߰mro*?_nB|;h6~R^*C XŻr.}[ 0M6;|!Nsc=yd 蜩.gEkt{NxKv|R`ۘ+`)a_nߟS<"9!?G?gaB!B!\?@ =IENDB`qmapshack-1.10.0/src/icons/48x48/SmlProject.png000644 001750 000144 00000003426 13174544135 022227 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs = tEXtSoftwarewww.inkscape.org<IDAThuswItm.4M͊G 3\+"08ȐH3TZXA p EN)kV:+jKjy|ܳc, <<Ͻ!"g2}|SAfv%Yml;լJE,"?)0Oa8o0MX+I6E LxK3_6MQs".1g*gߍWv]E0S2{Ɏd~N 뛄x9|w+y=qr#3_DqFM6q}/91ىz>*A\ްf *FxӉƲۜ|!9P&qsvDŸ".kLGħqD omt*@Tt(.B gOsݕLNk>wʙ #pCߘb>QJ.jU%W1>fWN+wtZ<Mχ|=Rmj܂|Y'czd},1"H(15>E0v$,*+99qPR2ڽc!d彻~\ d£#"#xSjŅX1_ĵߴ|w2`VV'b ] |R,>K&_Rؽ%BN†|el!<q6 p.>T]Dvkt1xel>v>^14:UlVB{u*%f+Ot[Q?(&>YvڇcmFZvEOə:(~S }_fg* N  vd^͈bHjƿqn̬wq&C8Sjo͸9ϩQ(NU|6sW~T ͷc"0DąPD\aGD,mxS msNA Oqu<'BD|k۬__ b l)#-LIENDB`qmapshack-1.10.0/src/icons/48x48/Undo.png000644 001750 000144 00000002427 13145236455 021053 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh{UuUwVRQXD!jf$ ,0֊^=(zRd j4V]u5ݹqgr[13;2_~3{}{JǙkK1  1pUw #C2NUEp?.pkYUCxzFEn-YSc q,ie)QP<\4H#5u؅#!H%}>]| -Ԟρ{05s؏=ϟVi~39PUXA}ih0~B#pb5@=^bFgblȁ@h%އQq1qNсQ=3\/͹yRt,Q>W(6!!ޒX8.&2aJ-4o6yy, \&ZjN@S;Uo1/v1r8֗t5~E۪`,#0%oޤsse>aq4iԕo*4Bi39Jp5F}ŧ `ah)ӓTn/͹ٜ!ae4?Dd_ĥDXنq>52-o3j l &%RIt(^B%rF`dymҶw >[V:5.0ZGz^dzD:6(~Mp6$P  s}$֋΀RND)-Sr4H;/ Ki?Rvٓ"J#t hBG),\4M{ӡ^VB}9-هᘁYWJtl}Խo3x,4m6)B4(ks: `a5BHK;obULe֮Taz]BM1x[tb5GSw)ܗb?eoHNu&.;@g^Wh "+"*Q;ڲJQ3,ʵsW)S$#wXWF`֔Zqű 2S6Fb[/bDW T09֢SbTKɜOTTDPtUѱr)n +x7{Pl^+v^Kt*nHȰJuT>+3Q/df():~IENDB`qmapshack-1.10.0/src/icons/48x48/LineWidthDef.png000644 001750 000144 00000006170 13145236356 022453 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDAThՙ{pTU?ǽ$t BKN Fg0(2 R k8.X;5;k-qU#Reg!aE !DLH:N?s#0SU}w{9 WY|{GTML*S}>_!C (J=,?"(^RgfΜ.UXP  =P8|`IY[o {`__N-QVL0!Ht]o V.`@eee477 ͝; s<›o ۷obOQC˵D_ż~TUݖ#]ן$)e^Ap8,qp8Aa=SLgϞ-8GzpƌV^=;' ڶ}`\ׯ96oDpŋZFR)^/&Mb4Mٓ2WZKӼ=x|&{=vfԩ/\gOf̙A__::::AfFi(,X0֭[䳩Tjx)dd2466z ꫯشiSokkkLv:}XlM:~KG"#G!˲;??d}J~Jf"gx  u &l۶TU΁hbd&=e滉DbVmmmv=mUUt\x pza۶2MsҥK' o .$IwB!gOOyj|i]׷9sfmqqRTT$Z|RQQtvvZݧ#!@eyueeeVEEy`RԫÃ^T]UU%g}嗯bix>;ugoǃ&]_3Ms+`УG"Cmmm@ P\PP@4EӴ_ 7VUիWO|:tH;s9}tܹsS  pq>|r ```@lmma{CfCzcYE`<P7b$`˲J$I&N̘NI,+Dŵ999jeee(m%sHWWZ}Eq6 L:{r;wikt:nW*,^VVV]^og6˲AYYt9{/z{{";;d2 7~$IzΞ=iGGGG @ usQ7VZ[ӏm۶ &LӼk444 655x<^0Nj_A@J&+kkkɲT^= Dػwo{{H$6-[lr8S.\8!;>q)󩹹Y4MƋ0DeY+4O:㡭D"1'Hm!Kpݮa;KWU5kݻ{M]d %%%Nx<ξ}bǎK4M3[׫8NV---֎;ZݪhM|a:FOqd0A!( \gGC ̀$Igx 577|8˲룷˅hlljkkO$J 1Td}ws.nfpypEQ6;qℭPTTtXpijkk{᰷UWW%L{T ]ft X{R;wx\+V'MDgg'a'"HM(ʭp744< aT0Hx$N\J͒$x;v ضX,=v===tITi}?iӦ9:t]"7xw> pAu)pQp}}"o`9 ΂ԩ+\p@,mLL>&%pǚE5Ԥ .b f?͉fazjo*ȎHDIZPfzf)Sv jٺu:xyy ]طOO97ƛ .#7wgg;4?^dz~Vc0j%aa*|}]imNhTUFKK**311^ x˗;̜#lG#<ܝ6-})YCT'61}'[iى瞩;( ~f[9vvbٵ[s X(DDx%0SnqP ,,-m`.]()i"33ޫ %Em|[[/Z_ɓ8; j NNv³D"',%1џq9<88BbUQQJh ;;^y c4!žwQ[}RT+"s ;g]p9ϷzuE%ٺ$ee͈Ȓ…(D[[Q.g׷}ׂ3w'sR=##m)gzu4]gEϕ__#W3'8uŁ 0 cg-XhR͛hmR={J.g<^|8ާPG˙;7佣V`磐$ w;D}}]Z44য়-ݹ"#=HO53ǟ9sc\\(,¬Y޴aCY[k6-"XqubQ`0Yp;PSs,X8oX)=/^#;;|ƃZҥvX}߾RN<?rI^oȑ~{ ݃B4$>P(H$GǍrV ([;KgXUg+ܸ1`SѴGguel39]'9n6)!!S'eTV& 6ևD7ذK22pHMR1ظ1j!g̟t-F3x(,'"_p%rrMkYxNJVRže"v!%Em|~ׯUW_ QL@Y,^fS r ..@`)Egg?IIxdB5mR4֮mSoozzu .R %]СL 2DDn"WyTFFLKN`$ Cql~5Ѵ`vŖ-3~?kŹs$[ʕ.ݝ_4tte88H%e@]6i3nVB@QQ[…DōTW=H_}}CWlE*`|J֯b6!>Dqq#uuHbJGg5k>!== 7** E]pa=O7M(f r$h47`9ɩ '$HMM._Z=eBq (lڔƍ%lJbD/bך?#|qq &TZĶmn.6f!0uN!V|`iWIENDB`qmapshack-1.10.0/src/icons/48x48/WptProx.png000644 001750 000144 00000002564 13145236462 021571 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThŚKlUE֚`*օXVDcTM]F F ЊVhx(o*HJ*s`93O&|?33\ Z

Gb _.0"0C|QxW;@MH3jL]@k<0R"KHHz~/f-:N`p#*U>YYq21 zD+#0J8h&]Y-Q-xLm-KNix}5t7*1Stb T L]"i|* ml_Dav +Av++΀<WZ+-jQ+1]| r , Ĭ:,hnG_+g^OLl=F%i!]WopƲ21HCz MzZG3+/eA.| r_JiDcVc|- Ga0Yz8S Ew4kMip@#PX TwԱ4@_ `yf@k64'  SJMR w[\e"9=wzT"+4p |o~ҞSoI:vzkw{k0=/I{wɠ隿@Ρ軁m1Z$; duКZZ;uS T9W֢=_j/c7+V* r?Kq$mG{>syc]"l%6 Вf LZ WmSo:p㉪NZ4-$DA`5LH'"F`(Bӗ9RFX7H(C[eF/*Q(Vue-QQQ iPJɿȸE3B>.*f%7+Arj䇷ˬY?hdTK`@utYa,+7-kOL9(V|zX4yp)ʼnuDSl,s\r%z:.?66$C->]}֊4؞E6mƪ7H [4hv^,eW_ܣ%"iFmPg XE<3pw?n\IENDB`qmapshack-1.10.0/src/icons/48x48/AddImage.png000644 001750 000144 00000003027 13145236306 021571 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs emtEXtSoftwarewww.inkscape.org<IDAThiler&"F)ҀPcL *xA9&T#D5/b%R$DCbhw#h-tK;fgv9ϼ>`&Z2,'F'@$F;O;19B R`0FцxY)`=M)c⣔~"<1n>`f;Rȍ̡J p_`n6DQh3Q+'_U33yL"OGv5- @&qsMD /2na礝)$SHPY|a9a CbhH3Os"nd6ff2L}\(Qx$@:O#rsF)C*'inr;̢z.4QBO41[3nm8C;H[ɞX{4-&DHs #`-2\C7g$:ɁlfRHzN"tι)ҧCh`K5EŶA`>P 03̀M[HCޢ&̺idNVc)?slAB}ekA3IF7GOڮvig z0 hçi#}L}ò+=@.Zc"p,#PUէ fFVvKwZp޳P,Dgw[]Su];r1|#U:{- M'D^(8 omFWǤ:FR:k%-9 i+4þ y'JK"f-]ꡝ+{iOY'oL̯ R}xiHܜ9@e)t0rphjT?|<8`З ޅh%ی#Je\׈JRT~=Gpsl|$iD%L:M%߮u/j9m/0Zn&?N6&d @-B΁AF/c`Y.p5S-/Y/cJB̈́(mPN 13Hra śR+(j PjK]vߨXP+Ⱥ Q jH$4h \͒pAd^){ vn!QPHYy`,"\]~(l"a(}Fp گPyVIBEP.`W~6al684Å3=q)T8,X58𨄾(j@khw24IENDB`qmapshack-1.10.0/src/icons/48x48/SelectArea.png000644 001750 000144 00000000654 13145236426 022154 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs oytEXtSoftwarewww.inkscape.org<)IDATh1N@gD8EWKACAEj@. $nDCCH $$ Uv1f"=R^ bp:3<ܙP3{ϼ n0\[Ec==s{ߗ>oz]2*DҢ@iQ(PZ(_XlަJY"[kp#WWB!k%3tI#w v* v1hk=v}x^EV(- JE־;tXi?X{%O`sCYM s|6"4%~IENDB`qmapshack-1.10.0/src/icons/48x48/MySQLNoConn.png000644 001750 000144 00000007306 13145236370 022223 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsUU OtEXtSoftwarewww.inkscape.org<CIDAThytTU\HBBH2Hـ- >XJ;P8Pv$6V @*$!Bƚ=TZVr|߽}3}5 %!O 1 r@#8JIpD#}qowr\cSUYU ]D@ķB lwwǩS-<ʋ@쥰1:|jR\>Ye G9Yߨ+XYm82i 0טL}=$e-x^Տ[ts.9#Z=Ք8>$nAp×$ຂ(2_ICbqkQ\Ecr~jj\LoYo,AE$-6RIHaM~S[nqMIx{a ,/wgwgIF K߄x,1*o ֋IG| _umzYː~d{@>}t>_9:*Ԉ}=NgN:OO}Q4@!f?=n 0rR"7bjXD.&/1 ]S8vIHHư}+aKR:Iw5j}SoYtþv cwG$ŃG~)P i\gbڊR JL@WhVDXJG.;ܨAH9V抇 ]若WwKN٣ %:?w) Nkwm?6F\F.h8`cl<琧؆ op@L??Ahp=>YHšy֭%4>a  L 﫥WWľ(D> )1W*$ dtS񆙚i 6KT5-ǎӯ 7wsM+Tu /)Ȓ e \ǚ]d N`dJLk {Dqff|A IᩧaHR*Kӹ2Nuۅٳ>;3LAIhO5]򎐞@YY=Ghjj{?{wJQMA}{t"\M:/%3dEX6lVBcE :;M;~0^LZxXXgTzCol]a<HH\;II\E!OC/(aٲTU5ȃg֬lM '3x KUwQʰ#ޟ ).> 衏%ܛ2$qxoyrjMh$ 1n&\71,~1x;rFm$=QoUn`{{ I7Voca9o-{_-5v?:ȗT;Wݘig%ϗ`;tce[_&;8E\+4V,Q7a,*e72B&sȪ`{|A5ǟ30%?? &YĤLLj2ӾZ:6߬ &@ss4JK04z=:Suϱ>%(>+fԨ4rrHN6sh ~"z UUx )f #iߡ:z.0PÐ~$4}nՇ1=t9wƠ栧 y<#U<[މ[*|]WE аy'!kB"ʞ4&U|LݮPr顋%ݔJ5{S/bƋ~;h<`p M M#&3g˖e T11$jbyGx8Cy3 &־,GYӧ'7x6 ^ N P)JB/f6:.MNN~G8y^͠":n dIPNMs0u#׀&8 _ <9KȪK2{U$=? fDjiHBWNO}q~-ݴbʝm_>>UX`B!$`h;B}u0TRfBg #W˘H/}8 [F;3UeȵjWmY" z=SEc$EG6ƀQau/s*<{ YL.Kr_' i4F6;&^h2DٟtS`8`iۥx9敭qO]YU.).n. =XꐟmzZ`$ $A_߸#Tkk:ڠvwV @)O[X#vٌn$D"XI`UЅgBGϩe}>Yo7&3 OVIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleGis.png000644 001750 000144 00000003252 13145236447 022030 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  5VtEXtSoftwarewww.inkscape.org<'IDAThmL[eڮ Y(c` $ֹ͌E.n fet1X/3etdtB0@_ E m7$)x|F=*qܱWqG=[AZlfT0=ʁYNt"3NDȡ XwhJ9e=E0 hgssl$\~q)r0D qpa5'j08x ^w~5Lg&$ p84tՀm4uq Ҕijj԰t'y=q|^T"ZuuuQVVb۲e: N 77]SX&%eXIly**嚤gm={~,V>\$86l{JTHee]]Ü8[o536楳(I\8ODх(q!.ƹzut+IENDB`qmapshack-1.10.0/src/icons/48x48/SQLite.png000644 001750 000144 00000006360 13145236436 021306 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs'wtEXtSoftwarewww.inkscape.org< mIDATh{XU?or\"K XI&iN=3h;錗OĄ@DJ%D;ܨ7o,"QQ=GB{IAI?Ø:3f %j&|@x2}mRStE?țRZYRPp; u1Ge38$(xJ9'۞B& 8e\!7 A7xԽvg3T@z*UTX*⛏t:'']ë@VtIPrKnVNSFNfw&x?CEN+?ԟYgH$pHSFYó z`~ipq~7V6˷ye"Hopa3lX?f&oyb*ϗs`L0?B+J 3-ߚQv,=XZTOg0&s qdn3ɚfI;#(Ray>&V0dSi鷫ΰ~6 ;Wt_W$F3n t:9{CĶ9mA[gҎJ ))&&M gÆӘL"ӦU .ksHr]#\-g>'5k2i=S |KvGQ '=-K {Hnw*\P[Yg>G\4z-cz9(A$m-{!O0Yq2\Q~rk}1'i $I"oI Wxv(r}dѫO߉q|a؇p7 iѺ'PK6>4vс''gú=qHSF+ >} _FVhV;;9zW;[) ]RҩPE{r1y'k8 qTfΌx@j1V>$ٳ]"#pɄ6Һcٰa cƄ}{&F}`%5uyy NlYsƲn]Z>Mr9C/@l^ 攙Vd֧x晑"SYw^~9U!I1g`UP GZYgP 7ITOsCㆠR+ sqrw8$.g(%V Lg#(V1xh!> [ D{:Vi&gTiD-m;B曙ܵ[1hZY j |2 [>,Y)`4vo1(=ҫs(BtƦZi-?~wO>/oƬЫ ঑.ȑHlصӪ ,P˟`K.P QD; ?~Ӛ5qC-+#?:~z:3v|RnBh'o’%E3f|@|RM_}{д޾72~- G"u>,v 73sf4 @mcr\zFRrۂ@; + 'S7O=ϯ~//| @eb?҅Vʈ~@~~9wP*{oAzN<^H*z-T~l@k~Xoj݁b]\>uiu*ԌM>+2hi ΐCO;+PW}ĘrYEYI5~^  \-g*BV6*U)Ȃa?zQnZ;`t7$*X]seoݻ級BEްl :diZ>kyG-loBۀg >ܟW^yAEahB5/k3ɬy!Gs/0b~$ ~ic(yC;ŠqI~gmϓ2Ok}#Ip^Ì7ֻz­H1g'ۏz 7rE|WEDBb9LdӉ:VtEXC>rkވ[S,FqaLTre0_Mn|m'h(6"_tn[uC7{M<5kiow-$) xh"1-1qiF+ߚJ6/{$0Ai/{ĸJ 8sHU8֓-/! "т@C` O$=rb9I_1UMyͿbKIENDB`qmapshack-1.10.0/src/icons/48x48/SaveGIS.png000644 001750 000144 00000002017 13145236423 021375 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs K4tEXtSoftwarewww.inkscape.org<IDAThhusmcbZH4"F?,C!RKJʿ DAB 034tDFʖmw;nwp==|. B„X̆J&L*E(XܘXj;XΝǭ[MbN))I/0j3wҠS|8x˒%UL%4r%o}۽s #P[0o̲bՔӧ&--̘Q[RlmD1-E@_߀5k]?޼~+V̮^WmI-$zbW>o40`)C.!&b-+q28EE~`T6%w?ܧd3CIENDB`qmapshack-1.10.0/src/icons/48x48/TrkProfile.png000644 001750 000144 00000002532 13145236454 022223 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh_HIǿ顢'`"5E(}ȃOAO%T+`}R/Eڇ>5JSdx=kNm?W5ېĹ?3̊!P -ӉJX,Pᤸ ^uShuuIIIhiiA\\\HrA4(АW=u`}}=RSSM_Y,_=b BD"+@ff&VިAyy98c8 χ4ў2(*4R`K T2Af`jj :z6+]osg ###hII 4 4V%2$''{@aavx/& .wEmnnb}}SňէH$#&X,$22RTk모`90p:Bף:2S/PTTR jfp8X鈏dY V"Hl) (D!33UUUp4Fz Z!&b6D"]]]$;;0NrJݵq3@!4MB4t$&&TH+7WC>=߁|477 ѰZ<1}«˗f<ى?k˅ctt`-dg߶ rKLQ133BMM?q&wSSkۓD"AOO`4A+k8u N| }ZFJJ)LS(P8rSP[tǿEJ|>h MO;~xxׯL7 \ۨ@S~1bq"55Zgncb=l-TWVv0;>} {!e`zz *Ϟ֭_߃ͥKOXK\m93s sܴ…]J lܹG^SiG׮`xϪw8ܨղR9뛑#;iիe\||| 7o>7C\F^]LNpv:= Nh<}:cc5aQ\҈Hi66`N&P0YI=BGzc ˑr'b?"¹ lN^DsJn7}._ F83h*T2':aV(%qě2p ;Jn>j8nT5\ DtCIl$w`IQIhܬ?=x& E ^\ qp]a"hN_UUEsL>Ue`.}U6&_U<"[:3#`I*%F6p##T46ҧ=]ĽU> bB/_h)/wx_70U<IENDB`qmapshack-1.10.0/src/icons/48x48/Move.png000644 001750 000144 00000002076 13145236367 021056 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs^^8-tEXtSoftwarewww.inkscape.org<IDATh]hWTMJf+("T) KE` (^AJ@h&B͖bZCjZjbR]ۍ&MvNj ˬٙ}`;?yg|3sF158,tN3'q>9=SdJ2}L ͯl&>4? b X./lrrլ^go:< T(4(_v!J[ pO`zQIhªEy E"RPv oٟ 6sdPshkhk\0"6>ʙOw1;~Ay%{>l߯0rĀ)5ZXn-)'$f麱Ȱn_BkRSbk{T.}fzڏ⡾n3zTwϩກ5?5K@c@DMP53GJuDr@kٙgЦѤj R7-u5zVu=.^6GNl^+PMV>"t?+/7ntY}*/(GFuV<`r;"%+1=m1+5~`a;6C74!fq+P$.;?fC3 5ZZ3hdEv^;5cSfKikoe6oG$?-Wйm;ty֠}X2LgMjݶ9Kt^]ޏ h*)-Lb*Q/>JU1':ܼnܸ?EܔY^横Ye Kii!I'Y&^gԤ>YG:ADb~% ǵcMښ_$6Uظ'I,L` B"& ǔxQrwxlIENDB`qmapshack-1.10.0/src/icons/48x48/Cancel.png000644 001750 000144 00000001740 13145236316 021324 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<]IDATh͚NAB3=@o`,ix zd E4ƨ11ނ$wr&Yf;;}Ϡ})tc< 5w}IM Gb_$&y ]7.2^1 JPP. vO7pKp,G ~R"_NHHHq"R@ xs!|! Cx3%|. Kl -J"'|%{hu0,E™ ݱ oM]Bp=p:GP JP+4gI@oO$6!P<UXZ"-฀x: 5 [ iO%÷;8gt WBY Wi ?ȺP"Zo%H"7s] JC-G*afp$`.JbAIlpű+~ *[: $yv6+ B}ϝx2)Dϊmp>wlJz_9$Ez?Cp[%c`1\<F vf`$5|\ GAceG2|+|gXt$Bi)N3:MsDki,9A_=pIqBTEq$/ճL.TGzk/_IENDB`qmapshack-1.10.0/src/icons/48x48/ProfileToWindow.png000644 001750 000144 00000003150 13145236404 023225 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs DHtEXtSoftwarewww.inkscape.org<IDAThmLSW )1|I%ͦÄL!qZa" 3:1jtK-̸jܢ2_@$mD -fgmm3 ھvn!deٲ?rـ,OmmO-deU,OX"!l`͚ӴoJY"%6TW?`2YOrs8vZq?[wfzf˲:N}ƍE[/!3}}VuEī!C\Sn $=&l)v^{5} O@8ptcIYWmŞN::z c9{vTzAR~„/?=R*} 3ŗ%uM|^6 N76#HttrrnRǀɻ@ h ,f BkbjIENDB`qmapshack-1.10.0/src/icons/48x48/TrkCut.png000644 001750 000144 00000004534 13145236454 021362 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5"tEXtSoftwarewww.inkscape.org<IDATh}}oە;B"!1S IFM2mXLښ66h3E8Q!% XP@;wo?{pd~?}~ R Xbf}h>@Dq'4mX.f&6cΘ3kqƵ\3=\ o`V5˘X~yEb(_Pl|^b7d Yvzk@bI PN7E-o["(<(p]DDd}X$(v,醲Ţ(vqlĿkPt:pߋ+"7\ٵ 6%ĸ#ƈٰIZiqX{%l-KـbP?>S:aX1Nپ!.pDh;RLd2/gMVtaI™Q 4| VQz6me\ZKX*҆h|6T">Vv GKtWsH♘OoHSn ?)Պ&!y*'Z)8܇sw ?sq6J}4I;j@=TWʖ\Br41W7ҏ0g>΢0m$P wwInDPV䩘ٸ+*v'A|97Ź Wg{́(c3ed{ fFt~YcWW/\[CŬN}JHB VzdGD [ =?b\_Eovy9ɹtSKnaFTgL>gא^C4vT(PsE3Cu+b}/KnP7u+Fݸ@C701d'nuJ>_QUWb8C8 jiEJLGb9ks$iVM"Yq~ޖ׻W. LKp%hq@lvuwuO~ZI/J>?43ߌ0̕׎Aȇ✏x Ou޼+Y-.8)^Gfxԋ-:ڵEaܹsuuoR( Ly^ %Ο ly6,PF9:z?~M^HqS88p@_ 7ra#ɪUҥ{> E8T)!&:^)ݽovKՈ qEn(N}ٴ޽{ 'ۑk1bv\xWW:ٓ$3$ (0 ;rR)o(Rd;v Apސg!בΛRêw=Ē[\~w_>tҁ\??|~M2ZEyzu)nǍ.P( n,dXQGY/R(K\LQ.CR"2?e~+;W.>P.zfZBUY`}lC LzR4>N=So\WOr9(M%Fߓ4 Ln>7x}}/m%7ѣњd髸`5Wl,0RFS%Z?2]8\v8O߿ÛpF_̤-5fd:[֙mJ,[~IʘڅaYjE;ƍ{3f qퟓ)[zS3RLodr.[0bDEh zy0Jt^R(xĈի8tUܿK+OF 8cHڵX (DvڈZ 7K3mS$Bi\IENDB`qmapshack-1.10.0/src/icons/48x48/Apply.png000644 001750 000144 00000006000 13145236311 021211 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsnnXtEXtSoftwarewww.inkscape.org< }IDATh{U}9)(@#U_GU6դvŨmӵ+MLZ"' Q\b`xt7DtnߝKr?rDy͵UBLm8-pf\M=tO)p3.hkap10_9S1}kXQ- ׋Xʦy܍S}8Nms)+9N4 O#`{1/[E q|9j^m`Y/~G`> n_1%FA?xgOguq?=MbBsHD~Th xIA!}0 ;&dOq<)aCvVX':瑓A~9֘Hukɧ}qZ͇Rґq ɥt˸b(b߅vџVKz&a,bV´S^ywC0z<3=xoXWXW41:A7UOJW=+]"  3]ak9:tΨ͑mQ). SLOUo4)'_Mk0Fr9уqYQ`p?0+:xF8]u>`X+ Kz/rz7)SSHv˽7Nqw0Nŵe.y;xp$1L8/>k(_ #᳎bSGTX0[h:Rfc O; #胴OX grS(ϘDo륷SjERhFmC:0{º3[4wsf_+,ă193eagHFo4~WvaY tQQ&S Qѿ'[dK8#U.]'xF%1mpubYJ>s]ci*vU 9Pb.ڑB# E]ol(}jmrKUM13um-I L$a|݁מY¾dOpP O`Ÿ'І .#ig@;sQ3I/& )Lt j$޾ڵS[03.Eŷ)X^*9/`:(>MÙGΈ ˱y@{'X(u XeUB ZtS%W%=stOXͨGst9^B2ڜ$tXJZL< `t4 /.G45bu_"YCz2^HAb>Ala2-Oj[+\VIaG48; d9Ռt;+Q{&&0gI'8WWqyk̻h^xyK|LZ@e5u-Grr6L\t+ɱ3/U81p'-lWʙlkR &dDG#LtVLqzJ쪡Y@c/܈?DFk]/?j6'eM_ ʹ'~OvMv٪!퇛I?pxֽ)K)ٖGt>1DC)a|_l~7c|A]){',@2@!]R{hʜt\4at1A<׮+iQ"R}FNNxӼ F)/'C -{< {%$3 {f,#\4[2VM< r$ 3-Ǝ7qOq7xaKTx /ԝ  kfӥf XOlVS6Fa`ܛ07O9Kxwg(Śmq p%'I,j+ j-]u=zVa¹'0ұ?'l㪍DZlƳewDC"Y+5bX{bN}ޝ-&?IכBh&ֳMFQ dOFzvTs+l_HmR*׽ />Nǁ\\ѡےXhvWk^W0}`oFyh@b[Xa*vNrDFbx&Q9D{>1M[QvJ60%7 >*TB<2Oc諨ÎCoӹYn0pf!'3ƨUl0 ֱ8Y 6iS/86-ග;r=d+ST%{4| !ovLRr& $trJ6nz b௣0z۹>^:Βr[˄Qxn`ObV\Ut6}+Jz=/S~[&}PeCC;W@lMHO5/}lÿPZD@-6^ ꊤ-3IENDB`qmapshack-1.10.0/src/icons/48x48/TextUnderlined.png000644 001750 000144 00000001011 13145236444 023066 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThرjTA_AQ4J $6+# %ϐNC4R>BHgXX(J Q):fswvx>\s^ hw=Mq>Qk ҄@iB4!P(M&J ҄@iI=1sIƯFMvz2gXW+r503I1QS7I=30<{٫1-Ϩ*pVU7+5챀}{ֱE|QxKma {̟QZwcpӸeƓQ?f'j~}:u{x85Utb ~Ű^ S'ǖa8+go:oTx4lfAP#o"uIENDB`qmapshack-1.10.0/src/icons/48x48/PathOrange.png000644 001750 000144 00000001301 13145236376 022166 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<>IDAThjPsMMTN_MAqӅKQe]0@fڂ8 MR[LIr4$38B>fn'ZZZF}2>^ Cj:WI_u] @g5/ê>W~Ff@y,O4ra}j!5,ܔ 'bx(/vQ,S}>CZ->#_ dX [jR<<:s70}Tn mt4{ P-58j!-~ 8M |&YB~@4/c,#wo%VtHK}sq%b H,Xe;GM];v` rāf> S˧|xn H h|Xj!G8^ @li@.|>20X0AHa)X0@o9,Cg>VK&Lp"FGR lv-bGv@92tu/| j[y{ZZZf_*ζIENDB`qmapshack-1.10.0/src/icons/48x48/PathBlue.png000644 001750 000144 00000001347 13145236375 021653 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<dIDAThnQs 5;}0&.\Յip;h|Dm1]w@1J- 0p]e: IKH g_3il뱾1NFaJ5:I .=҆pzs4[=(fdooVg/8,x8~d!#^,<-fd In#B?L*9tl#l!6+(-)q<>.Yp_eptG4q<@=yL ?Ng>HxBނ4?hĒ)P*ABg9>A0@6؊u+؅(X2E *h:-Jfh`Yqcnd uM"\h`cIA3aU<-3$Uj["&&&tgETihIENDB`qmapshack-1.10.0/src/icons/48x48/TrackOn.png000644 001750 000144 00000004235 13145236453 021504 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh{p?gHR D%< }0EiikJkR(U:IAR5jaU0X :jJGD;Md0D anowC3s9M`| IĂ< :lIh# O4d4MB A_vS@9&c ;oZm=o- fap/z_EDnh_N"5 \5v@(9L Ӂ$*81@: 8lm"PVsv`ԗ?& Ro"u@Ovׂtx0V Pg@1< m1~ ?{{BBVӐkBV:pPǍǢ~>w }PU (^>` @m ''<ۡ>:[_1v$&v:䗠>3_)1ÿNZ\<{},="Pk}mȯ_Qzb*վG`+ 7P|Ot8\ Q^ĂF(pun5¦ 17bjo(tBaB*h Zz SLQ Ö@@NhQ]ZAXn;PGbh(079V/< 8TC}i tn(A*A_µZq@.0)2 TE*Fl wN$֏ͥ]+7Ib[D@i t \FQ~o®aCm9 u/PXE{W{]bt"SY7{ 4 y"r$(w88Dcٰ!sf{W;hQt'/g=B"Rm`P5O@[(w߰!sfS{sgpH4& vQgFH@5hm#a{~hk d̖4:BPY1vJeI(VU>֧hl ,@Tp#<j^@ܼ+ܟѰ A8,vx7FdɃQ@m,n|YcN5BZCPUE@W7o =N5cʽQPK4mB@YC L}5yr"ʹue뷮q&/ab4A:5wͫ}L;/F;<dPw $<[* Ոc7 X *h)s: +}zGC j0#sgRpum}`t霥MMmOObts")&6p/k e>Y6AN ܇8RC bUU#CC6`U6?&؀>՘Z?v$aip%_`u\nܻ;nAX;{-ZkpL j!`H(wi^,'[Z>P^~99,N_oKg,eV,Dd0?Ji&"m7Pe~ϝ{_LMޜZ;B6u@ab%3+JKJ:ZĴq*מo'aE8}ȷ,$s/I_ќe3qn9ĉX/"vPi0} r0cY? $ .*桟ve-}!bz9o,ve-? .*&+"@}X&6?@fÈSkBDn֗:.*#ޡSR]"PacB_(5ǁxl/=b\Lh`ch6c|099|=ZomX˰g ~>gtu9yQ5kq]߰sL.&nB$٣a.L1q/\՝bwLY#5aw6 T"]zg`%.ru>7]*:IsFKftگk dx,m'<Ób5$.H &Wq:GJ =)1l*ВD Z/QH~5dy-껼Hsv$.J(\=P+E{ qQq\!>!*[[*= 0FCxJx0Bx0[Th/bC|V aZ[V3q-x.A* a$N δ )4`X!14V'|ګŇ}u OÉ᫺L B!aGN fDcu:5senyxF m河#o룏>܍k>p{ P?׆Eu5D}4j*D=sN NpV:SzfW'c/暣+LbIENDB`qmapshack-1.10.0/src/icons/48x48/MySQL.png000644 001750 000144 00000006571 13145236371 021114 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs'wtEXtSoftwarewww.inkscape.org< IDAThytչ;sN@ Q@AM@A-Z^@ .k+h](‚T(ժ-c^/P S 0Ӊ|o?0!' }:뜳<{x7-w )K!H!@&I `P@ƬhEB )EEx 3{\D@dϤ`<mێb0lZv_=m@'Uvَv ̽!H&)(Ds4ѦpBtnnR]Tk[@*795rθiXh!y]pgwl['s!b$BނEgB/t4ۈ[ )8($ r_vڪol֞CRw k?zG!E1C32L\ʶtND4[gĩ.{@ >uU˳r6pYNRw :j́-&J6Z-:ya^za$v=7|s:Oِ:]uQsnۨi1cp=fl>Cy zWh8y lX\q=7oyߞ 즼 ,A~jK> y[|MFCVp8lpED.c ]o;ErrYY;_ iYжi%i x]G6́[O1԰AڟAq$Yb~;С1VbƎMdؾhR㪫RN5`K)CP_w%IŚqukWy^ltB!N/SdNԢ3RxMՔ;5>=a3~q$՘4e  '[=VU^`Upn%Nɾ LOȮ?ZTQ6͔miuE l6e$E%̸%g{@4*)b&4=%>z`F$fOUű\(YSj"%MzmG1@o %YFOPҏL(Y0WOsatk9]ZrO-EL~'Q/hRE/t)Q!Ie'9{𓏊|x^z~}8Bn&L\p3ϻ\>>4~~jz !##ObԑٸpH ii L9&uu.HJ`l|,.ng4RRzRDҤ֙oo„$E'kg”)/׻`A*:]O 4}_ƌaR;=th Wh|>3Ӈ3w @bb8ޅ%8خ hmu;YW$K c5~XL=0yLd,Æ SxN('"0WQXX@jjMF; E\v(#2%.[@1 8+[NA~F0 '1X PuKd _BR?Ss^n 4ݶcϧ:&Ju|Ϙʖk8 tAr/{C蘎@Q“1n] 䒣.:(rVQanV0Ḭ^ Eh.+Kzq3̓I1g$EKO3ڰۻ8>,= AR{rO*3#"Œzq _~N:>MųWe* AފE1v]P>ov/S Y;,͂/9a$=} 9 7<To7rM3L+WjϯAZK/`V8pGIE4(h䀢zƏBX~/0qbJJ>}[Сbz7@vtz"ʕZz/{#Gf2ujZ Kܢ $DmGb+x}᷅g۟h̅spQG3J9fj(NnWxFG[[WeTC("ye_g2Bv C$  dRyZqΫ=%yP/{徏×1=a ת;:!$k"i])bude43ٴ)OB^l~MHcqȝAg"*Ѓ֦$ 4KJܳ^"~gaƌ]p>9YYSS}w2Ķ.XI嫯9sxܝ2?\K9I;62kc%}Z?6>Sؑ !h$d w Y7&ۤt$ 1ሞ-fx4{ѱff2_>"<+#Tnmdɭ'? h;;4,d~_֎"cfJ>5${H$^M#}5lJt(iߏztWE"$?hҿ5:f:IMDÈ0cUm/}Rũz.*O ] 1]\2[׋ЇkԵo@zv{W h/swyWx`H7 O߿ށ[/aC"$Cx)#$@X3āTHAR(g|zCͼnWQV٨IENDB`qmapshack-1.10.0/src/icons/48x48/WptEditProx.png000644 001750 000144 00000003364 13216234261 022370 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<qIDAThyUϛvʢlVj XԂ)MiI1іRB MK5mBZQcSbT$K4JEmY>RAf{s $}=v>}pэvk`F0'[zq~o.4Y  ȗD`h4x#`<:BO NΖ?%!L8{NK z-oeɂ<[Hf1x/*|C1ΦwBW~4,\^DŎ^8= `SA}%jV6W S-eG; ?!8F05yWϖ8C$n<_k9˃^5ZͰT 5Ƨ<ͺpY15+J&h?M=n6k~0<nhLDCLѦA< xmg1b 1 7r_-qI]Ve|QWj8V?SUJkK[5X:v 5tVT3C +`/I6D,@p5^iMxºܻ)QNhJRrW^gy2;5AU=C_GL''Fq c$ 2#'ehwbmio, Kqb74d;#x<2 ^mJܔ[PsxZMGҀKqo xNǗӴ߳ N$l8mSU7Iq4Ņ >"z~_CS2VZxŝ=cn;ڧMu+z$x\eJ+g5K3lFzZR;7$ %{o}bg;-aL`|V- ;\SVSze] pzg}HS s54^}2JIHVl&r,ɱ|N`}na y GKtÂ2EgNKpUvHfܜ!> Fx?:Tn30#x'gx$c,X{ꑆP5I*}XrzF:2(garI3s|vl/rI&#C+Epg lڑt]zG$_E'OW`8VےVh@E.IENDB`qmapshack-1.10.0/src/icons/48x48/SearchDatabase.png000644 001750 000144 00000006075 13145236425 023000 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs 7 7 stEXtSoftwarewww.inkscape.org< IDATh{P\?wタ.,Bx INkcLӖĦөΦ?ԶhLi v%ICj!<$R {Ye?v!YY).>>6jj\N1c6`9M,r|xApeQr8">x7<7co8|G:yc Ozkdvmee Y"4-`2R4RҥAq:N>čh\G E8}ӧfef`ZMlft:iFۑ %${b@<8s滜8qhnAbz3z{Gy5z~dY"n=z}V p8*q8*x|9w~p,蝠6{HiX`0L!/]TTd~}VkV[[NH`2RSlݺ[pU{1>1]&2,@&2 >]GP/_?۶1o ɨG&` ܧ2KP y!A+;wG`4^{\8@j&("x+f=A'1gQr  AۮAK]lXuC@2~=iѣTF۩A2jWO͆(_ߦOȋeBBBCww׽#I3=4wh*88ʕ/7p@@.]&IL((*b6tvvUۅlGAzq)*DE18H9U&"ḯ:C)m)+F6ܴDZXf|bg剟=-sCn;YB"L$)e:Qu:T;xIJ2jdII1be M QUXYVŹh 3!۵ݳq&4+qXӃ7 2OB lQ()`˖-) De? zv%E01l1uC@Jr}tkTEel,q8p bZ8VH &[Kx$8h ">s4S]TW7q$1m@ٟIzC;vV<^m,X0XfhhᶨvW4XW Ɯ޹O*-pT99x0<5LFF2iifl636iFF a<~$A0 Jo$".&!0'ĉ 9r gއTX|xx<1Q`YdXΖ-Kٸ]ޘ֯c۶b|%˖-C,6[m7O]@]-a-c=w|~`͚lrr78#+,,dߏ/FzWP7{&d#D/aSHHKRTwBcx<O~_y,9BoЋ'|R 8tZ%Fh8=^~Яҋ42N_i}a 00) MKK +7a'M_f hniCYElThc)//%.c 0tv#':MK#=v"SL&:ڃ\$X"$$)>pX_ FWdp1uvv|#o!c@3eDP)?MQ+I>%$03#ۓ\BeV΢<43_?M˿[0 d gBiWgyG1?3> AGlH&?FnYVHdeP[F~~|EG) 8 kzj55.ξD|>_ 7 L3g9w!Q 5%s@@c g Af3Lzz qf(b8_nņC4*%Lo$JKKkO't@zIBIb_y ̕@0|{WC@vpv<@\#O Kmg O$ m k[JQ\L<ßz8aufkI,l+pStڿ~Μ Mt86>T[HQgEz/#;Q(`6Z}8_'$bl\Dr1a.LY嶔<φY!zyzI//Dsdw'\&*m*acI%@yP-FY03^H\CXۗ( ;+ orp{ci$_%Noux:#y7bMX*yLJ;7XUjiѧډS뵘0--EqUlƋSħaY.<r[8Ոur3:oDtb6*$zPE^VLqm4 Go3YE8='\TR9׊ɩ*vko=ݜr #Ѱ$:r>5RI Z/i%KSyLG[[׎6vC[촤nzU'ǔw5* ۏW9:iA֔~NJӹ3>nCkH4^.iaIK ؋yj8-0P(fⲭr7tJ?ĸe O(-+GڎZDW(ظ{ 5fn@IENDB`qmapshack-1.10.0/src/icons/48x48/Check.png000644 001750 000144 00000002231 13145236316 021150 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<IDATh]Te3kERXhY7%[%y!^xEUQD]uaYF e3{fv4={ߙ3t&/-Qv!v ipM%'۬%7+ qQ䢏pZYO.N>B{%,şmUnT NۈEJd^Edq于3NDFtq);'DdfI%n9e{Kl,(SvjMrwniܘRvr;(MTY+'XbmYڊNp=+݃ f %Vokȸ0\ć3t(ޔqP4TDN92)4#>q+ʿBڜp)c,?C{ Xwp67T#~FRW4):K&eewBf ~+qfԖ=RA5X]ˑJ LZ.mQsc1mfot x _䝸ZyH}KQ+UsL +0-3t" .ڟPe1 `&.T|3 IWPv5zG ƏAgy*>"ld^gcnt\MQ?$e97lnDhd ]LZt,ܳ a,7Hgz0N&gy`Q3nj MX7K= M!ʴrjG3⩽*0% -)8< [S^c!>O>b,fq~7rȷxWb=aq 2Vw¹;S*LU q2d"Ɖ5< p`fWc|ȸ; QQ ]k,, 0Sc1d LZہ ~fO:(<fBby;@̈́%n-)NCθY. uuH*b7K[o,tnqǛKy͕S: !uP*Xl&u6dIENDB`qmapshack-1.10.0/src/icons/48x48/LineWidthUser.png000644 001750 000144 00000003354 13145236356 022674 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<iIDAThՙklTEow-"VJj`T-5FcD4Q/6 K/`բ.(baغ9g-MN:{̜9LABUs, CD!TՖ? 'uGϫnSUpt*jN]~I=N}yuPl -:*t>t‘QLP+eeDیMtüdcFC~fpkݪ^U$HW/0ۀcw7Yz=YcZ|̑;` 7p&"@ux= "DH'K׵s) Y0ZL%_LOmַS1@r@(]="Ӛv;aCTmQW%h i {c 8Jn:"rp(IoR 7=m7?yNU! 4ZP32<–U m 09?0}Ӱ`6Hp^qd86#π彘>Û>`_@T@8VFeb䅧 TsvmC!k% z^x=0a'-c:\{VH8P2Y%:#eT]ݻt;dvV1P%/:8h"V(;QA9ŏ;OU'\V)4c[[$ƤSf:]"rhh(e0r,fѾms P35y˂- A15 "9)]rS;f 6X ԁ\%?v<\-+"Wcl`p]p79Sx.gWB0`>+)Y'tV)>wO r{: <~v/SMk"Cq\]@)W$#` =nSZ Fв导"r̂CGC7np}&j~WM#%E%EՂ|5f=@=]VdJ@1J!13+f.6~w6,#Cb+_BDI:`^iIRV߁O?p;̸sYnYf9;Zc.gDŽnXmVq/,v~Y#/fm7< l_v0a0(JQy/j5;#G:+Fb I*=QJ%(c67coǶM!IW :cm A 7VN0^}!o XF)NRl %BA=ZVCd'0>~"=wH'_ (<fo0cbVN)!_|x]x Yn/'\?#=w@̇i`4p;鹬xsIENDB`qmapshack-1.10.0/src/icons/48x48/Tainted.png000644 001750 000144 00000003445 13145236437 021537 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThk]UߙP[ؒJ!&H@R"V$(iTTBw "R@шQ!\kx Q18NvH.!84]Aj1`(tmg|.*<ٟp3_fGfvuG=%Ә.>AVE?yJUkh~ɲpCFoȹJ_kqN'ߐ+%[w)|+<h't:1}JBL'Л)W^b- 3(ZwtJx#r7Χail og}W*[AD_[Ϧ[9Q. w>D |L˛a\iP7ęI5E8*0.), miB_qOX^o2EvJ KcİuA| m&sT58ghW6/Q>5c2<({^q|M_bK->78}pi}iZǢbWrfzt'E<^&373f"|F|*3=ʆzqoq XYb_1m/ ر̇Yeqd}I+:o-wUpQl{(n/kZ3 <\+_l)}Ʌ@tȰzz0hФ]7l; s7/[Q7j4:\1KCmDB Q4jڞ|seYsR|=P%b a}a:dq!uox/K /c{.d0y򛡄> lhQmy(UC| ox7KHo I\T?eܮq/ޭA*+K/h{έO,/jløxi Uh 44UfTNqVjx{Bt.6TkoNty׭*^x9KdB_ ^!(JR]bL-;xPv)C5̏Dz5;G7N|*CY'`z7nDcB9RQ.9ӈ%Ů54ߘ~AKg_/C e!*8bꁩ\ȁ)D|ֆ%#J#E GK !Jik9iVHYC萢Feǐ*9wCx}.>x=+ʟ4>RXSǍ{`vtE xjV_E{e_T=vPc=izs.U/3,>CP2K%yS$)hYYI6Ԉٌ>|Y2G)&d0=E"PS<>8~ /VxkidZgOW䅆Q*W\R}%6 Ƀ\% xIK>ԴÅb]G>m-_Stl/Ʌ s_Ҕ7bĻJr.TIENDB`qmapshack-1.10.0/src/icons/48x48/MimeJNX.png000644 001750 000144 00000005546 13145236363 021420 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org< IDAThyTU?002& ڀ "N@&eJvI1J-zpI{}qףKjV /!K"6((8°̼ 83Z7}s>繿%р :`(xoN#=w?-õu,X$lƀ/|~^=OD hB}u_e bFC#W(M֭<{T&1o݆Z$2Y[55hjJ%"th5lYi~>;w>{6 ܉~'Y`N Kd2t=xS[U(J\q-\pZ$PQT2oo*uq`:eW%>oŮR IIK}M`XW_1c(ΦCL y iiܾp+[[n_HmU;vtNlet1ĉF3*y4T𰴔ػ)*=(Ӧҥ 22Y/u{ݻ[Y֖-?z6n{x Gawet2DhTge^OyAmڠdG|<6o@ejr%摷};X olmgD”W㏴ # >dsZ[qq)J)s;77-\Ƚ{\IIػ9T,x&D/_ukrn%vYC1NXAVFFGo_O3J-μKd.ZDvJ 9gM,>k''wbŌ>pv}KrnF*%2.oFC~{`_XȽuFX#ݶ SG /JRzNfԯy-PUR"nj!41g^z8wҋÇ3>ׯ,kGGb>P*{2}34Tg-^LAzLӑ};֭3ۯUv`egBȁDgh(.X;95D"~.g\ 41d[ב#-:g'eeܿߢ>Miwme%'W W^1k о_?Ɔ:uzbrq:mgh('WhbVuiGF:-" Ji߿ q=kB5 =zW` \޽s?f{OD.'2hbpheTTw@v''G(kv}ltMH@WWOd$2.+'"Ad/[F{ v`oj׀Qqv96b*Qv*!!۷y\.jC҄TDT^b43ijRU*{Mv UB[T3k HvPRU**E׳m0RU*.#kG1z~?Md̚eMfo`R Z-y}Ǎ'pV*.ƚ 2oٲCLOd$ 9j˗[>k@$JJ%f_On<]%<iʋޠքBIENDB`qmapshack-1.10.0/src/icons/48x48/GridWizzard.png000644 001750 000144 00000004604 13145236351 022400 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsߔ%tEXtSoftwarewww.inkscape.org< IDATh}TU?w@W[5V4IW\VM-$Yi<[[bެ5#=Id'2 T`Wq0 $Edp?f`9s̽}3T_:@20@)ϾJD&iīL,@sCa2%RYf|m9 z0H]R!G|o@q]$X&N X6PDv={&)?`ٲ}㠵'fU¹Ծ}{9z(ZbŤM"R("D$ZD---ZHVdfVtQ|<5efs$ v<0x2bٲ2.\8P*l[&͟8شAAw*Eyyzm3>>\4`w:氞8Q}tX#:;R꼈Ϝ7:kmY]5s Z0aF2?u>WΝ@NN%Jjm(|&3>Z,&6? O͡W."`-SOmO ̞}tӯEi#m8}2#Ĕ~pA b׮4JJ2c-lj4>zt6DC6a}0@Sޞ< Q\|PVJ}_822;N3aD\(. ZTVv\YY%=})~s3ĦS|"!R DÕR9-=:szB. 1Zr~pAؔR_*]7|/ed׷69@c6w7~r&<__iD#@Ch4`Y]'oJl6dj,<./K3':EDf]g(>~kMM T׎plsf"r:M{<T۝\zt0*UV*ZOXTPhQ!ڂ9aδvxH_b'!ƴ0""@'?΄XڶvON: Zw?^\ IJHa\|F ?g?u! (-.Nf: MDbR̡s9흌tpWD~*"v>5̜2];go+ŷ*ؓR:3:Nvܜ>k{PJ}ܮCG$PU3 0)6Si[{,-6PE=i=h|ͭ+'}11o#Xy+crҿI"R??EdmG>A_uv 5:~u:8IENDB`qmapshack-1.10.0/src/icons/48x48/Link.png000644 001750 000144 00000002406 13145236357 021041 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh՚MlE5UB$cP ڢJq"VU$%N^KB !JZF(Ii.[]$ $Ƞ%MKH`?]+;yw][‘N5@"˹O%/%A}IH+ o9k$g# Q.$k4۔YI_U 5۬ؔ^0g oYiŸ'{m4`xYKAjKZDܹJu%J۷+9 615@cc=!<TL()nE@Q&\tz[Pw&QAiKzz^fl쭒&Ji/XZ>&Odb"NoۢX?=g]ZKU{Ւ8>h d'^[L=:3ʹ?k+.8>/ڊXF2# YЅjlG3#4: rVF@OP3χz_+Xg!d'uuΚ*.5}pJx 8j>>|h 8g3FchhxFsᅬK?AZÀ BGUDFce YZ1 " 6s3/|=[ј20tKQ7^nyuB8%oç3"p}bqxA] q1!N'gsM t̡ ' C vMh4j}3N?K!>CC rbq-.1ht #E$@8;&Z6XFx-10EV3y:OfςtSf.$_{Sf ^#4|/8U'qp&];zԁh -5MESBpa6qY)rcȵњqh}L/#:t)"^"[+.^V Zo4 pX=W,9?_G->2xJZC2` wF wR x0\n 1}(})9 R[ѯ=NډwtER@uݛ!OGfRSQH yS#6L|eV j/Yjoy_E⻓ osTi Gi8UVW̮ S+ۡvaY7af%+WYn7 13^;|p׫ɚswcXi A27U b?~I4?n| >n?LTq bًwhp Vζ?C/8E1-AoYU@!FpWqߨmg)!oLHTЯEqw{VVg_-W;~ $Uxx03"hq,jA˷IaK5 ' sl.3^ ?B,T AlvTlw{Qg-M,Mp,qЋO-fKЇ=9AVb3ƊД^̯3-F_4Ȩ5\GZ O-|:=jhaO_-n0~7Xs_+gV ]u8'8@:eYE: 45lIENDB`qmapshack-1.10.0/src/icons/48x48/CSrcElevation.png000644 001750 000144 00000000727 13145236324 022643 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs!!WtEXtSoftwarewww.inkscape.org<TIDATh1N0ECBJ! %tPRP9hRCp z=Gf,6bdc(((O,fvRZO:}?u,rW %jI"C"0h#4I _xHAIENDB`qmapshack-1.10.0/src/icons/48x48/CSrcHR.png000644 001750 000144 00000004172 13145236325 021225 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs00M.tEXtSoftwarewww.inkscape.org<IDATh{UU\^hYSjf:@QPGIJFIðSuyؔFf#Ӝd]ѱAHIQ {wu̙wo~{=a/p ;xN ?_Ť/^]/l2pݏQ]"$ݻ|g^~PÁp4~ۍOoPOv+1𧘬r`hڟO%kWv=N#<3[x K[؇l:d 5`9FF F##iD&4=ҍ+ ȗHg0* ݈\#fW~#9Ԙ\[0dLa쳴m|x00"si--O0v N(Ƚ2ti}5R0^gLĆJyi_ "÷ CBxqaMie[hgC C\WY& J=473 ςHC%N`E9ط8inB8 OD~{pE%h :#xIqRDQ1DAD2uGxk"'T<6Fz-|6X>_4A}}t੨|h":=0A*L ?",SQ{F:Gdsmf:uW!GTbvy|TM@vsygMn抍uB2$_:yK#PZGobv)vw7v{Mm 5GW06]3*c񥢲Q#O2ޥ(+t.yNri섉&N V#a +VT` ~dKpwd< w Dϊi 9CyiVҎ ?:H1./h_y#>82gB8x'Y –NITyU!s_u(3ىƨŹJ1o ˷ҌYR.r11:.ކshRIHK#0'J#vV|̎7qvacb!pr 0*ujbQ:Hz1d7FɅmVL2R$XsRvj^-*y1G~6t"*0uZ-:M =p`U3M.iig-:{#J ,Oq.`X u˓'=OF:{Ir:ϖ'cK8-/t5Qқ\V Ȼs0;k]YEt1}Ý`z;̊M ^Wcҹ +oo%,oC( 񷈼P#]Z*"l/a!07z0NMpSw]pO^e̥H +xK+K|&*(7&Km>R$5ߊ6*1DmeeRԎh< c}B=_G LPQg4w 3× ;y)(ʂ}tMxZ/EQ6oFg &cZG.8%[e0hǀLQeS TCfBM\=8PJ)9i@НGзj+w_q궪+-7(_шqdu?/U\E#\[N3/G]{ 9 kP Xr9N*腉eSRømslq>Yw=l؁H|8}RZ|;h |%81$Ja#fC%CT?\JRl ҀgeR%~*UiÅq[s&g+?E <ַنki),`w$yFR){.NSEXFӴ֒=U%^fAaob#=?t( _`Wo=>x#-BT99 }"0+'C!ӾL@8w1ޫRK@<.0UU pdTKQlfwTМV ȷ z bڔw?LwYgDƉMbF+~k8͊\`P ,q *"+޷A L:zCb:ӻʐoq^6 |hmw2! t \tz !ޙ#U@Q,/|.pxVFǀԗE91^`R #LN`h.@;>xPEHWI[#p?[3Mr+^L>T mK6nHwr3bߠ;zN)0{M_D L69_x@ עSzjA9K=>a̩t4iC`2*(;=F1wkM'7G`h1P__n_[Jxؐ*@O:- Y4oB\1#~`!sFx%zZж޿>\+߱5^"eg޺"rr@;F0r;ӏW34)%Ѐu+ɀ AǁJ'/ѵܨf+>؎Wj+PI`l9w) o=,=K/mxK/(CA=]{_ {ٯSSZ P~S! Uh!x3">?R>w2 *j+ |gB3;Z2JOC/qs9Bef JY1OX ܍v)3#'Јt"/n.IENDB`qmapshack-1.10.0/src/icons/48x48/LogProject.png000755 001750 000144 00000003540 13201005615 022177 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs B*tEXtSoftwarewww.inkscape.org<IDATh̖UyyF/ eN]˴F~pfs-kNsm<=6ڤnYFef G Y$Ea ^q~~~Sv\:uΝ"BRZsƴ9\T}k 1N0+dJTQb4{FpbzG"0 rZry\cO4uOaxr[ E1XM3@SM?fqU) 8iD r<"RZҡc.ފav [o.ZtcRR1g+wG3<`&xOk۱ H:)My /\>AһGZq2mV.?ľF-F9-t0#_`N')J8Η:g@+ȵ*8הȽ\Rmz%~8Pv$5c?HEmwcF`^?DA\:,[#bCA~`~qmB;.crߙ>WF-jbQp/Cz8rHw28eIq_>|68S5%bia-R:F Ӯ5JYd|CwCXЦ7醴Se[,8F pW eyoj9xa2v uёg^l1Nha};ȾդCpƁ; rQxaBObxFS !5,(m5.bLĩ9HށEh_+56vIz XhdUᅢͱTD}OM YRJ/㦈x>7&jRۋ*"O;%1f-dcD}W[q3v CJu#-O-/32Mlǚvَ)o tW+x/D;+/ďڈz4LNnƱzw'u 6Ӝ.Gw.2jy7ZR)ލF7hxGpMD1*Y!RZ{Kr}i!ƝQ#䞹5J)% ڭKq|ktƹ?;GL?VFD;&UɽXQߋU:bkIQQ_q1j(3iѦ%vɑk|Q}jB)5N?--V(dG!K;#>.:\j̓g{OׇCFhň~H2 l'DԻ k\aFi\QvuW.mGV[Fo^uGm"jyIʾ,hgcq[IENDB`qmapshack-1.10.0/src/icons/48x48/ActTrain.png000644 001750 000144 00000002102 13145311677 021641 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<IDATh]H[g') R,-27d](n2e+lt+fozQ2*B`kұ:LXYúwF9.11!#>ysx  k\ Prc"m6% `MmZqқ1wȊb49aRr9VhW^K)`08t"bM s,ooLu^<ݻ%Ux󯌋J rM^R |"VGfZز_Byo a 1%U葜qA"nSxH?JDQ`Q!^ubVm f@TԪpX=rXT](5` 佁vzNh ';-ݜ銰L\9e_mj</IhTɞ=_~wkH @YJ'ŖG~~>|&gw X]iu@vٙ ðM ##Bd1 OO = L-T˲^#fԋ-0(enl|vՏV=U!I?| P,΢XgBQPk@chL̼dRZ`R^1jytl,/KTk]?NYf81=f1b|Jg?ZDQVVnJ&5LL_EU % K"K3¯8Nf1 @BH$dlmG\X&+8rnp P}E LNq*OP( E-h9{bJ~DӀ W)y% Nqaaҫ}Ƃ Yjؿ>]:ζC[v2C B0WA=達I t5|ǮF\ǮNIQ!/1.Er+%ola6mPdOj p[am!cWc,+F_~|SB,@`X " cޏIb^\h<4͘T:njء|;Gvb8 mf9nΤ U33j8rypDŽt)~3@3i:j7sƌQՁ;zoKArCjcӀEE̘Vhi {?m}{a [yD;`{-+^Gl|"+wB#<_x2#@=N,â݂IRG^z%}8]\0zٕ <*֦`@sژĪ+35Po5585t ߁it^$wF/떅 i.MGwƢfii_l:Mderk9F yΣ̥TGюAe޽!!FU &vT($ U鶈Gm`ɓ2Q}5 (,*؟󒖞z%S1c'cj.xkK7m )7˙y2VI_hn,򮿝^O7z1L[+r 2}aDef#:qXDT jo{aQqtsw])`ԘBfߵ 4UesOSaqNG;ᓵyݹcxa"\3aSn\] &)wō%orS(|7/J.0Dh^Bpۀf5ʲtj6 '(XڂwAEŲ#Ƴ`jD? e J@Vvnhn|r&͈5deR_;SW2};_mdf36Uu(i![F^yWdTYKXYGF!P"$@Wwk&0HJ44k>+ֿwA@` :S|YIENDB`qmapshack-1.10.0/src/icons/48x48/2NavProject.png000644 001750 000144 00000003347 13145236274 022304 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs tEXtSoftwarewww.inkscape.org<dIDAThkU߻^j.EB"A1`m5Z 5D-el$^0֘P5ZX,KjV fvw;n,3?yYF u.Wp9~06TLJIˆoH<#pAP!x4phI,HZH\b`Td1Pm<ކ -\8RCA8]@e t*>G/ᑯ''>*}xEs^ũ\.l܆'k//95=WcU!T%N38TM?eoJdB3}^}iy!pG#-Ew;qfv@Nߑ%ޝ~ 7F1v7YcW!]JKW`}F%%?g7j\g92#%M+,TH4a<7}SЛ~>ItߙP?v9E@o($>Ƹ4\@c@98m ,ᢀp6JI1F>1:K; 5Q UjŁ7?E ]੠ fmPgy&};6D;LOy$s pfdm_IK-qkމ5ꞝI}7=w.k9İ)*l[b W w',G8"^TO+OƽX*ZlCtԂc{,,!,ۇ7Ym'`١J~Vs30jNjq&Ԩ-TOvެ#NEVQz%ePT܉Of Q|)Ǹэޝ9bTkV.$< F2J؂L[N}Q1V&n8XA7ˍv9TOq NoW-ݮSf$-EkO-b]o"%;et>M5ބ9OS)ۭ@dR=ǰ[YV[eFYb'^&uXfr,M|C۽b? 7: Xp8PO21xeNU^ǹkSR_7܃pu$DFK*@uc>=Yz*B4~>?dbA>fȜBqnd1x<Ʌ2 (Rp kwx^Ibρbs"Ѱ &r= `8ݎw4chMlC{+ZHZBhi93]ӓOqGV =qxiï)3KVV PޒuEӨ Ļ͔dZ‡p1gqLY1w hoiE/r2H۷0o`6hx<I0ҴX~Ef-C34>Ä2hTx$P1.Kf_~ Fc9  Ly.dy% +4]*hILĊM(/Q IENDB`qmapshack-1.10.0/src/icons/48x48/Pattern.png000644 001750 000144 00000005013 13145236377 021560 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs225_tEXtSoftwarewww.inkscape.org< IDATh{y~ [؂Zt%5b\m%eS+5QcLQIf$jhK$&ִ6JiD$b,gskg\{֬=߳y BL1:>-60N›T.h%.8ʟω2*z*~g>~B_%KYM tF3(PZ^+ 7l8I-ja8?[Mm>( ޏt]?5G]%{(gq:Y܂i2}8$o!L~*N|pBC'y-12|ٻ#VwL$.J+W'F5yԞ 7>࿅?K˔/8`^xr+wutB^Z>OD7?<(peX<ǰg/p1/h ca)/9ī E}:(dǧ_%80}@m0=F\FK2;FQveKerSXbR(_޹;䭇WcF 8pz$ſ|⃸7(gQ~_EK=zy~; Bx/Q}?McI{hPfQ^_HpZ0&;w߳ #-0!әRH1p :іo]DZW}Vxcд9|ӽߟ_m MB!۞G#1@jbFc+&d|p=x W%,&W_ل]Cp<8k6TW+i~C2&~xWvCqF8.'핅tuR/o3X5ߢIX'sIAt>'lܡN3KL\/cw~42R:4bw{l%|S!gox8~Еy::2DFgRtml/-g֛ iRY<c]̦6F1 )]MmF18 S oN+p>!Nٻ(&B</1|VVsش-diINaSJ$' O|]k9L8T*fGE,>*GB6N[u`#k>y}S:YsSCcsg՞ ¹\b"{\*aF26,9"!ZJ ZՍ^;Px9Tz_l![:-ohx C.ʙ"bSwoLNBg 9ELjVi/|_wNkz/M1vDl׿ &W{uiU l jaP ؁9})bӜ|xH N2bcͻ-M)6kRe!z qpag7?&u+#roK(|G{9ʣ|JkZIyPQ]BO蚾Mٔ!\;3ۏ,\iǽۊh;jH@'SDBNDB%bef2@{d{ ڼ\oVi!UVIƮ}h&)W/?+B&P:AR#޽QB@g! 2,l55eٛhe,)/jDCDq,cwmp,g" `@UdYOMHOˢP^6 {+ tt ڗ9/5%'Ҭ+B?!Ct0џ/nn7~kD~& NƝ]֤8Ip[_ebKQ qsrڏ}֔ z3>EbKr:9Ɍ,("+5(^RQ A<}gauz"[85Anfj b2xxj# lns1#e@F+$qehw1+Eku+E1<ɴ;o`.ԫ.kt0ET4#o F٠OWVS8t:o`Grbn`3P&4^;%y|; \l@5%:)1 lH=!#~|(Y_"Hp$rr"a6!3*! 'y=tfdr1 &8ݘ+l3"yߏ+2l7bNNdvsPd4⫪%30*ޯPK)2[%ijiY6y}J %MOzX!AlUP!9f7;{KoϜggIj4"y|N 6>i^iqD/DFMz6|}.'9aӶ _ä eGH~"]KXp5'ϟB9h*J$ً,3/qb>JTI 18NX;gyDz3Itsr ~0:=Myf~16?5nD5o1iHb ™.=JG1sk(cDaRVhJ*;~G3M`P9N$\@WʺTo)™f6y 5͂f|``Y00,oZx7:t&ܗ/~1-26!!J-S:l":%Li1l|+* Y W8Íad% $P5VH'Ti#StyQp S(trre· zLc1Vlj\ݢXJaUcG!HWV0HL|nc}R^yL>V9'׈x 5@s9DQ|_ ݋)L3PqY=lĜ~7x }5-%/%&;S=E!Z)ZJ}=5h|^M <3]Yܽ>&mhuT5\Z NՔ"3|>9ݯ,!IENDB`qmapshack-1.10.0/src/icons/48x48/CutHistoryBefore.png000644 001750 000144 00000004125 13145236332 023375 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsttJ}?tEXtSoftwarewww.inkscape.org<IDAThkPr"-D(Q⍔h$vbDmJ7t6jf6jvX1j:4R %,WXwYhgy̫-X ̝}~ L{vx)I4*7]Js K=*^2XOh{+KMԯNxda8w,XP=D֯Z$9[2D2QI_ҋ#aT`4>b>Sƾm?mGqΊ?F-ʳee8* N-W*,ZA`bxX!#[j*= Mu6LAʸƏw߽sӶyt)6MlgyQ\ѣoWBRj h#'bHؼY9)u؊!!Qv%3Ӷ+J9Ļ3hvG$'.]# rsw: GU@||j)z7dӕv\}&{v.}ܺ[,Y2y'AM#V:Ǔdp'8̥;>g=4W*,[N;V9yH-DZx`-(H$?ewtir`6Y61dM|-ɪ*@,g*5ρ. :/Y$ܗدpԦ |!1Rw=@\"L9p=Z*|  fewvqgBCB_ļyZ0v?3uc8og;^2kFyCX謶ֈbjm?߿_݉{D}=`Cc?vU 45ra& ",^jjJвߙKr7`3^}Qi+\^`5yy g%cUΜG`-OY(߼@Sre(J {J3wg^8Ip(^ށ64o<(vN ?Ѕ^5f͚3xyC4&젛wTV]#-"TIENDB`qmapshack-1.10.0/src/icons/48x48/Route.png000644 001750 000144 00000002373 13145236421 021235 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<xIDAThmTULj-)Ēʞ ʞ ʌ7If]W,$g +(6%B5 ,3[ym-Ӌ똮3q}13?sD_`r`a`]`g`s}7n %#{~xkm`xOi/\z@[BC`{oOҔcl^д"՜DBrF fђVdA}1?I'f0@>6(J*0ϙx]COn4kQj=RMFu`VrI)^Ovlq g+S N ܀Ĺ\Fwn|~Kk1<@4P1^\:V%x5'چ1:@ʜ}gZxӃ?8F\(nh+9v9$:Qw65v\ieC15˅/2~*Dg!WnhW2Sc-&H\fVvZnlI2sDq&ŪZ[<4ytCs=u8 U @s_0lUָͅŗiTF9h.F~}~(GܔXb"ǧBKj7#c4&77osK k]R6LBV :b)xEְn܇Jb_^Źq}^su!؀e;^iC$)q/ݶ,B*nAn5R*{桞exp7xϗ ,'?9=qћl?D|p[ye~~2f[݇x׊ >}Ŭ1hwt> ThSݮ(v*1 +ӈ^ Wb܄ś?ċ2O Nap&y^Sr oZnKeQ, tHN:$+)2 `d`[GZ+4?}Ǟ ߇R00?ݞYiۓBU6F/A$BM&IENDB`qmapshack-1.10.0/src/icons/48x48/SelectExactArea.png000644 001750 000144 00000001521 13145236427 023134 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs N NtEXtSoftwarewww.inkscape.org<IDATh?h@?W<"IRXT ^K[ .U鬫 tѭCDi␤>C$-\wK.2 X5΄Y xe`OqM<@;xͻyרQ<@_SРwS 6 v X9"X0жe k*E40nؿ-˺ec>A L نz\׽4 d =`18/˲O?RO$Ys[ǶOq~[5tDݲR}wwY<_jg*ql3RnH la`5CBa,Xڂj*kd25-Y25IH;b (f͙vYkq2p9$.hD[3%qW*<"rsyyBHoywg]GRS%3Y,.Ue5a=ouyfLA9h!i5P,R]&cܐ/Mr.Ll5sfn x.)~x¿w=YTJ]ug`ddSk=aq^I:}B`yiuPj2A/8NPt]$IAZo)e k@O րJ3@z*܋?5\`* auq a.9uHH -IENDB`qmapshack-1.10.0/src/icons/48x48/Bubble.png000644 001750 000144 00000001633 13145236315 021332 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsN7tEXtSoftwarewww.inkscape.org<IDAThKAǿoTLr?.zz&]C^Az)bԪw/ Zi{WA‚sFwOi sssjjKHa[3ՅIgށ3)viĐQsZ),tyyA[K*(`ٽ'q |d2)jАϰ<FFF7YȭiK!L: X jƏ4MZc||&6Kk- x^"H$7d!מQ|65ekjl.CT25P(e,c]j[[[RGu,--aee1+h}A B-B*#W吙pXihY|KB_9 ]%i {{{6G9c}}˒M99_*%1󫋋 @>ȍ[3b%ݍ ,..Z"DtH$x{{[;3fW*|tt$ո]3fDX4i|nmt+vp0d!oa DD:WZs;5#n%}IENDB`qmapshack-1.10.0/src/icons/48x48/V.png000644 001750 000144 00000001567 13145236457 020361 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThKQ'-\@EMܵmmE(Oڢ֙W332 2ZHIHau%qygby;)/Pvz$ :#Qnuˍ3xXg;@q;t_>|`6jbTa 7(CC#T6MHc+x&ďjJ{nj; 0&vPRO`$ R 8($$9w8ҌAVI0`m!A MK0VIZǨ [[ RZ  :{[JagbHʙ3qV| HZ;\[P/6`w`,v`G hE}'g=T1 ;]Y0K5>2` +G {*/_w,A};l{,wp^8,50@jb@|ĦP0g.^[{]7Ѯo,ɑ8 gڕ@,2`ǎࡲ]u['v 0F St+ 4ˎ`7@xvA:>|h*LN>4}`pJRǀJ9W7pOQ.׳z?yHk` ~+7?OtZvҮXx ꆫc-{pCddddo뼛HehIENDB`qmapshack-1.10.0/src/icons/48x48/Reverse.png000644 001750 000144 00000001712 13145236417 021553 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs4tEXtSoftwarewww.inkscape.org<GIDAThoUt  Z2FoH|!h_ O[/%^ibL5$ꅒM} ZZcK}bve)Kggw3'gO9!#;s^<v2X%ĮnZI0L<-;f1H{T>dj#1wƝ5G\,%+${vW"OTB99ʺ%|ZwCboCNGY,D5vw2`g砙ľmDt ǥۯ8M.JSJ % Vls^ 6ԏc~-6$⧛ e c jkъW N8?D@P(*-1qALTHbFV=zX40BV^!=> bp\80D ?j duCS( 6%~YP Yg~?GM~ÛBR~-=LcCӐD_I4f)?'Eb喲~'fD=\]/Sʹ-ğ}c)8s5hi,\XMd|73N4؜H B3sx&)Lg1vBsq,Ǘh5S6c"6^:%v50[[tR#\H@E:--Sz(qf/F)%o5ID>aTZܭK\&X77@BVa=yJuƾl⥳ ۯ & _&% -".cSɝPóy\0OL $\/ɤ^oIENDB`qmapshack-1.10.0/src/icons/48x48/Lock.png000644 001750 000144 00000002464 13145236360 021032 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATho^czŚ)!DgȰj:+}#f_ZewB#cReFsڞ۳ߤs͹}bq1n#L8xF~ ~M|/cwq獫 "riȵ"gM$E/ В:^BNĎ C8(h#Ţ9= ފ!Ѩ&+S)s NG22JrQp,SF=)$K֚=x>_y4"`Uz4#}sq BkK\Uo,^Σќߎw%<8/#4["6!W@;gģ $P1N$|>Ԍ3C(,oeKO^MlIQ8y_'rLň$o 9V@ck,B<) 80_4$i;'X2O:JV,m0~Soܕgo4','RB]es@ ׵"BӫC'?;牯0`Ѣa0>~*V#-7S[i֬l|ZV)4Z>N6mer>|͛ \EqQ=B岾>V$;4v YA!L+!yP_ Z1tiMu>h hE000PǮ]&Nk>yQ.{N ]EY7rնmfll設[ZE{3rGa!\>hxxXA[[Cx3 :} (L4SKKJS4S mܸHKww4/;b𩦦fGZ֭[RY,G- J!]]T~fjjj~}$4[(X>i13,8ɠ,3JkNttthiY4*P@>6tinnf-˺K!9jYQtDwwwY¢Xdq+fXB(+Q1(3\_B>sV/N^S8IENDB`qmapshack-1.10.0/src/icons/48x48/QMapShack.png000644 001750 000144 00000005272 13145236413 021751 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs../tEXtSoftwarewww.inkscape.org< 7IDAThklU;3osezaZޠ-PB% "QB$MPXW1pF-"Hw@A,m m[+̻f;thA f9<<9gϽ*.ףAZdnxI) ׸/^W,˸\^ᡴ}j [v:=HAA((!,,)SFTԴV+>3V<#V+y~KX^ȑzL&<@W;E~X**.砮gMGHI1ф0dg۴Z ^x"IZ[(.njj:Xr2II?-JgQm8p<V7<̫S?nsg> Y W$'Gn == }u:K'~d@47z{X,fΝ䭷gc44\A֮>*!!! ݍ$ݘRt:T#!!jOCVrt_}Uͱc _?çdH 8ƍ"?!ii^[NDNN*6g(-m&/Vl3bVE}}7 \0z}#FHI1jtВmG()i0a&NA^^mm6֭-8pP^ٽ{ @g`۫eNnĉ&::$%"pRwa /efLH]]vT8WQqKDFjc6·93iR,NSMF[ؽۆ zfӦ7.nIGVV sA\ Adjj))ibѢt")+#Cf%PW ]T 23M:t>!(HAnTRS#tS3&<_E!2RK^4@lsˆXb2,[Q wtJK!11c2iJDy c.v{hTX.)0rMMW1T^O&z4~" Ě515BN `43yHV>ѨA'`0QUu?棏gIM 4TMsU\.vc#x!0nT*m?!̞=9K3dryٵ499ciFtF"))I))i0~|4X,q#tt=zqK…i^ŋWlfI5IHeECC}WKyy WEv+]]vmXrsGFF *#۶君{/NG}AeAd'9y_8sQzAt 5,SUw#0iR̐^!#t3fija,\.}LZ9y{FᩧF%11IR0khZZ2{vv-$..X=Oq["7$ Ōb'$^bv7&w⥗- ETBp. H>Z Í(B8rS<96+;vojY|? W['c$IIEE3:]ii̜@\\(.+\M~)F5u3ccO@ć%@|7[xZ~!?X/T""1ȈlIrrPD,@FF4 ncӦttذZ]03sύ#==04M x^DDhE8~XGXd# ObC46AVryz3ðo3R)2u(JK4i$sbV$Cyy :ļyc@:nwW43iT"*P3CSSEEMLf&7w 3ܹ͝^DVVLP,_>,];Sk4*J_OeTmW./[W px=gd+˲,*;촲v IAFqQILIRg0q WA+ ס_!([IOv[[Xj2*5jY<4L"0|?A);+-m᧟mmIgv-i'?_a3l|s纈fٲLΞmgZ@}'0zt ft )`!UGogm[6"#Yɑ#խ :Z`aC1kEG_b17V Geƌ1rΜvQil9ΝHM+1~Vqo ׸/^C)˲Sy4eȲxmEOTIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleDocks.png000644 001750 000144 00000004441 13145236447 022352 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs W WF^ctEXtSoftwarewww.inkscape.org<IDAThݚkPT{aw,.oܢK%cQ2`4:4^҉Nb3ckՌc8ʤZu4G3Jl(r7QA,"²saX8YN&:y{Vŏl5#~*fXAJ~,G hC0һ|/| vHxgΟ P6mLQRzNnj-1/Gi:]XTy۽)M_O(kiN%.Y2F xBP^~#nbbLl:gzĉ;de0C6[6DRR4$R 7|vlߞѨp3vFŸqټ2{, '6پ=Ǝ5b2x0/G*!>~Tի5:UJdݻ]ŤIdd**>djj#I4Ęش)h4/dnXPPR{ahj֯Npc4Z"(!$QYi%.L||8%%6o&QZY zƆ0c RPPxpD{o*&FWز&gV#XHHVœ47; rg \Ap3 Ip !DDz0E%RRQLJvܼi%=[7p.j.»NFp@!-JBB8[ …pxz)))!33ZH(j`xO_ZsbbY}ѣlذd|Aǒ+ *ʛ :f#`Xv`SHIO!*{1{ LiPX 7vCW5ZZG]kDX2y fvDDΝ^'O\7PQa QSFlQwӎb70:-)[ ⋀nhksz˰۟zml>s6 $9\TX+VYY;sP[[olvBXAZinvPR'\7QKap#T 2@RM|D<S\|> flĚ53| ꍔ^wV*8Hc$o6^YEP@Р }sYȷ`Vk#?xމ? (-0g'C.'ýps{lܿocʔP Og,YFcS/ʲ?]$AFF/? 'znQOl+P$T%+`V]IcYW𿀇[X:fExq<;wA\\8fsW/8|XB> O6'.[@,?`7sUU>z?|SW\TSp R `v4I֧\=!7kq:,+s]ʮ]}Š>A^iP\ ] e]g\",nZl0#>5-\yѣCر㍡ԏdTnPh֯ԗsC~޷敲@ObmnXo"?q@~ȑC*@plpΞ}0ONFvn-=UOR,Y Pb"6go%ÆxP}i1|W7DBvM`9p@׼ N!j^=ŚrH慜C`aC^q qT1`QRg>k-X)!kyjpF/CP5';uDF6W>(t" zx,ACLW٣jN6^7`Kp-DrJ"@)C^z9Je^HBPjBv^Bs'P!wkMW];Cb|bOf&;$5UC~J‡ [ ՒX xЀ,fK)`xBJ, [5m^H@̴@tH\Jk "k+l[Hax7?߀52B<h@f@( :䣎߀yA`?$/Ac<> ׀qvfLBCEZ*vRׯ gg~xN_TnэFB*w=P*ŜczA{Q~9Z~ 0=( +avX=!/c5;ګP+GZUHZ!W$ɫנMc0bmtP9k ~6O^j%h܁*27hL9;6*9N;pn ype&1OiN3'sۍ;K"ĬOeXIGX_ɵmh }HuBH_"OCЃ|Ya HERu+-"8,4Kvx.µIMd+#*rvdKs+}/+%nMŽƁ؆eԽ;;*|EllKY[ʼw"-@e^{ Ǩ?W/cs 8IqqQeG-O8=Խ2OTOf'Sl#<Lx+͆[U<>rVẳTz 6d>|/ g-`Z QWX@0q_9G{0/ *$> ֑;*9c B+KjMXI뒱z eg*Ğ!όK M'V]R2J) H&l"Ij\R IcNRE%b"KH/ux˖}W$f1kb\kתK/}_5<Ĝ={?۟[b~|$w-͠~dpI7|۷?U8x0?ogammO9gmXLt?+e/g5fOK8g^{ eJǏ0+~osB5ܹ3 +VZ25,)S귯Y3b3VX1kZ@7v_uU\.e˚{CwBx1'6<ulEH)-;t`7u֬[BE2}0]pO)wyC(BpReC6Iwq5 [&@ ؉ o%-pBE~uD߬sd0^ǒnxۆ~EJCDw.FQqwbJLe\4GѠ N (v=n_gE-^Bq*~|l*oȋ/TVo},M{j{$w13:h5_mg_pGz0Vwl^v%BhA~7Rd덣uws߷J,bטn9c&4a/w 6L`zFx>b콿>fv[:n ܻC7tnnױ6 0kc{~KnnJ܃3;d Rw~#2pCzH|:oz97[o $Όy9\ۇ[Kd-]&!-Z=Ö7O]爕7!܇c㤤ݩkh nH~GE]2ʱ>l ozK6 ʦ*l_yIENDB`qmapshack-1.10.0/src/icons/48x48/QlbProject.png000644 001750 000144 00000003706 13216234261 022204 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs K4tEXtSoftwarewww.inkscape.org<CIDAThkEߜvf[܌0*t!ᚈIF%'ZMk%\!iIIErmRE3~s33g̡XCF>O*Gl[kp_Z<-yS;qѼC-!,f˭0¾ڪ/|ur h9qc_{/V J&1ɞN1* \͟؅'J:Hri!p!=ݧk,!Qv`ʆpRcq&N(}zJD16UBe]nJ PPgaq[gվs}̚P$[R>| O%6%'XZ~B{1X 1\ ?֋uH=V*jaZWUՆ}笺wcjS }e!qV'{c;~Z$8Aܔu4ڡ'!.ǼՏs;ax1+\?ev(CnʄmCBXzCk *'1 s%\/)7_1h|N. WK+?› 8"+W|pH$χb.lE! !o7n\>Yy]g dW$Ʈ-=]amӇC! aY(V^}ƍ6.l[ko~kyu4BPPW~eOaɡ_ƒ_,O!d307Z/Z̀KxCDZ*GF%<܎WG6qqw[v_`x& O"HЎ>~1rp qz^ųkx l1n,j [G'ڟzlmx~lR2Z 1=Ļ)?P ié!9c-cmpQ X;ŸGVRY+E*֐4G> Rk/`Vʻ/,io3YJXxӎ]+\oJ:(%Fmx1noV"~]oN\7p?~YR6aIp{̈́\Y-ƾf]P:͔ +U!9I%;vl!).}QJ1S(H/<p  P#C.3|H "'3\=S!{$'>`3 8\.Eɯ~#>O͢u6w;|56|;k)UI\G4KqSW+v&+o QZuGk@AUހ"8L:*FFqdmg}sF_[GY|,[ckLFn0H9Mh;tI[Ts>"bc".,gxO2{N$3ZO8k3sQ([Q#w Or.ۍ!GQ.PM#IENDB`qmapshack-1.10.0/src/icons/48x48/AutoSave.png000644 001750 000144 00000001377 13152263363 021674 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs PwtEXtSoftwarewww.inkscape.org<|IDAThOkA$X+EEjob[AMrRZͩ@z)=s֋/$zV [483f7NS%73 4))fK M|zzW!"Ĵ'h &4`ЀiB H/sfiڴ K Rhmd:| k,.~6dob ^ vJ#J6zp5r%N;H0m4} 5 !~ @{{J{[CUQ!~_ 1=5W;j,m ꫺Z2A}*|~\__|>C6wG9!jN0>\sI0R+SN+a=,oKȻT{:wM 7:ǥ:~`;F" 5ʚ &B׉'ʺmrI Qu-\IENDB`qmapshack-1.10.0/src/icons/48x48/Down.png000644 001750 000144 00000001531 13145236340 021041 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsWWFB~tEXtSoftwarewww.inkscape.org<IDAThUe4' !&]DLd@IARA_ FA, B&^AIcK͙㋵79ٗ3aayzz=,J|7J >=n Q Ŭb.\׹ &0Ӌ0XWN@ TM@ TM@ TM@ TM@ TS@fF ]eVg9Ϙo̞|f}4p¨&ꬲ^^Q 'zЋO=fCL.!2g6:2Y%׈';Oq?X0~qw=p4 _×x#NWbE$=z[Xy\_ۦ{7Ʒ#ֈ`F.B1~ICX\†X3 Hh&TDV;Fai22]p~3>Qـ2mxY-ZC.5VDž^E#L-b&6{p !>b2YE!bK\Tp=Ql2$fb*5܎2RUl7gI1[SMLU Tk lO X QE-Ž%,54E:mVUj>tj؃ؙXL2Xb25z/iK)~S=as8N hYV@ 鳜uBĞ԰M'UЍGLEW^,Uu>5U]=ܭj>?<[A:ߥv-ESh5^Wnu4>WG戶\(qΈ?r,/DK)?iW pVωu-]ߵ]n_'yGA후#9|*BQ4𬸢ĈKr֙;V|^Q LV8~Q' V?uO|0Wdُo g7)'t%UɓBB;pk| h'`6Stןpc)E/ #G/sH׆F6tо<Nqmdg2në5iF yjM+7q*Ġ>$;) KٻV0IENDB`qmapshack-1.10.0/src/icons/48x48/CSrcCourse.png000644 001750 000144 00000002502 13145236323 022145 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs k ktEXtSoftwarewww.inkscape.org<IDAThm\ߝMj kD)IE4//mI Ӫ)H_/QPD ~h X_ %j"TJ՘u3NfgJ/ws9osI*#?b)*):M0 ̤QƾUam8 8-@B'^Ң[FCM8sqT$$P|ڢe y .&.%kb/a|'cW dtP$}#Gȶ1lOߡc ϡ&B,("{0@x&[;lN6>xʭl~}*^fU;_RQ[24 7Jť]p#&FAX2:p (Gf#R?,oVcʍf!iOwДUjd+544p;N휇`lG]љٶA5\5"Lq%YIl3 R #Ձ@+[:[CS`V8r?N";A*qI lŗWw&"ԡn|pznBa d Py2 zy{˓nЭ9dw3{tSI٧Q*;1J8fr[=Ovhb;yԫ\;$0-::Ne,u_!|HO\rH53qƯШ)Rl~iszK'ɞby|EyOq>yO؜$?pO{jkB:O֭Dˡ&,o䭇j:tzV3qB ֊XUN}TPi%ARh&rI LJ)F MYoᘉZ"IF'x Fi(gBO@uD$J*MyIG|r")ploIf js Bb^jYp){{THSd4mIENDB`qmapshack-1.10.0/src/icons/48x48/NightDay.png000644 001750 000144 00000002513 13145236371 021646 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThYU_2: DMEG Ɲ5_]&Q1'_$Ѹ=.BDE F4 "|ClzjzRLs~s=>[D O$$9r]2d>ϐ0cbf',HX0'aL%؄[1 uNs3 ㋻~V2sX򞗼+90bFcaĸeE. oeds^<(V5̺.ZdLg~2u'MԘI)N G?Bm۱ASA6qځChU?x 3R|K@<˄) 7WVT9P83Bf UGёa'r siz %{[ ͓3t)eaD j~ Hi, o U-c]oxf km6C0+~c?R29ad2Vݼ5P|ה.O5޲ɽdz%j4Ǚpr)j9Smxv؟Iȿ,4Fb :3lzЗQܐֹg8lGKlj0a[SR+ݖpo¡&qMevv=B2F6lz01Uq\~L"!GߍF l7,СV.>_4 ӾCs );(}@%Nv Tŕ䯢<')R‹~9ŗ&S\^c2fZzN فJ L$@Hyo0w 23>zoLH+s3xG>,JiRIBKAX0;Y;1N̲Y+;ɴMc\gٕVF1|$=C+Bވw+~jpn^9Lk+5kAKuDF-LZux%]5nkyh#h_7 -5$IENDB`qmapshack-1.10.0/src/icons/48x48/TimeZoneSetup.png000644 001750 000144 00000007331 13145236445 022717 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs0&tEXtSoftwarewww.inkscape.org<VIDATh͙tU?U;?!$@tcPE382;z<+sF;geFFvDH0!#it?Q"L~ϩzoAzvvSRRKMMMeYn8 SRR֯_bpXkqPm5v]6)5k$=U h60ؿ4Hqۍ*u}W ްaC^4%8رcGh---[7ޯAY4`iiB "p7Gop0/G2 Ed; C˸^EA@0QI@>ཊ:\œ?g$%A<AMx lJ%3_p]@ P+ W@:]p@L|`$ph|K dckPZK<f3AN@d=wH^X$8 H@Ln&/HAj:rK,#4[0s#a i_ߋvIU@ ہpp%Kax 6xq}vAZ "!pK!pQI]( )Lo<`[V7Aݙ@X sPŜ ,S}z?m門1ǔ] D&-9J/W Hz6.^0GVs*P%C:ʰfiyF &0ȃ8-'x s#\v`%H[X~l>b5)c|xWd i_'^w`zG,A=zYӴ4:Wͼ0@s>,_$жxzq:wTu]nPUu>+\*%V4 M~iȔL fp3[ikn?㎤}֬5MQFZ>>(wȲ L66ZǎudJIIDQQQ:Y?`555TUIVʲ|< g`pRO1U_E =$ U,544(..gI1++,ʭp+ p8p\+%I=eʔfϞںukySS̉9S,ix!gaE9&:YQ**JSNMO$+:$߽wttގ'i,( eee4M˟?;wN]ןe >,}uqV54p u]bdeeqƞdnBy̙S뽬͛7_bߏbG\"R2bXG?Ɏp8M+..Vhnn7n<|eٜO]øqɜ .X,odcnny2~\ǯBv0T3߳ u͛7_-  %Uj$PD"޽_WWR\.Úr!''tFo:ˆ%hINa&,,2 aXpa%iӦP(48+IKUջm.\::%R 0| 4Mnnkر͛ϝ;gtvv2|: Hl ` נi#%%%A3228x`(|][[܌3UUUtv&%hBQ(rfm͵qƌCff|9]WC0եx3J\dMӶ)((H4i-==D"+BcA<|lvDEEEHVÍ5h1W]׍ - fdFcہB`| F'Os(r|媪81mLP@yyeeeHsqcǎ r%U! :x @< wo3K1Kc&iVx`(nˡC9tIJ`;/|-.x0P(#l,(ʋvWF:\x~u P SkYs͖p843s81AQ,Oɑp:rp@uuugWWCX|=i$^xxwUnPs,n"?e˖9srrPxHOO)SfL&)++FQHҭL:ߏ_2TUtHioo)dYևJۼEifg.UPUJF###+?D"9zX,ҥ #,`ݺu=`Lo4uժUNm۶u~g﫪:Rh4O@'fQ]89Z̺̕uEF?e>Ng ,HD{{;;w~ø ]/M6I$sεiii`0xl'OVN'BΞ=O'tTAHi/m$HR#yy텽{&l̏aŚp577t]nq-Zt:|x,[1pa_hp CVŧz$80NTQTt+t:rc[ Ζ>6˵ْH$ByyZXX~ԩCc61Kg@hvB%: T^Z!**J ;w,222gϞ %ݘP(25??}bţƏ/ٳ'}v]4i̘16Il~?lΡ6jL/3ln-[$I~M3p8ihhLo$@UU}ժUN4M>qℱ{p{n_T0&".ݮ:Ng< ÈZ+WJ`0HWWNCJJw*Ϡ.%aE7[յx^6m#gv'RSSmƍc`f6?\ٳ]RRػwoȑ#/E5ʍ(d3g{zzصkEYl6[%KGAkkUhAo Z{Xk =$Ww@ɲqGW<Ƽ#Smb.V#lMKr>/c~[PnN|gQ}ޅMx)IgW}BWA* g0HBv}A,g(vb%lY=FTf+$RXs (2d6\n sB2xlQjqDgOlcN\ >@GMQ:0^5Zr~?*k͵'(.ʉ-(^n/u>8;kI[< mkt> KGbeRi]vQE5ap}"+O$xgM6mڴUck1d3oIENDB`qmapshack-1.10.0/src/icons/48x48/Combine.png000644 001750 000144 00000001665 13145236320 021514 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs J J'?jtEXtSoftwarewww.inkscape.org<2IDAThMUe\Q*l'}yj3 c.! 6nBeN1 \Dn`0Z4"D_3Fɨܘ9s܏}y0B(߁ r~Lgto!X m-G[YD]lzW-z) īL􅥏|J6"v/U۝vTʢ[AN|Hl“OefAJwW DA6aIHϐ e/]3َ/qcFW6Ln|+Wыx7ᆜ!}iyN)_˪BZƎM7颺x]YB=@]n~OLoNoQi/[*7 װ-pbr ,SZ78h6m I}Kcܡt1:gwŃ@ƴP@`VzVu?n.vxzP78P7tÔ*1ex^[!?%]>pv و3^2s  yJDȄ=IENDB`qmapshack-1.10.0/src/icons/48x48/Left.png000644 001750 000144 00000001575 13145236353 021040 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<IDAThMUey :c)$ Z`B(E($pQhShWmsƤEP킘@zqh)9s{=g wwyQ$3޳=G7]IƊe` , yZ@҈T C}\;LzqSV4&C?^Σ5 kg4S؜M`U-MD`p|'OLZMڕJ/`P"%9L12P>BLg@b)<=l/U_w|mi Eftq lXKf^s-d5F1YYl؝u fWumD0<l@'>H΄b l(ۄO%}0J85;SV֥bRNf,T[ܕ)/.aspbF!!$yWYz _| VRg-ȟLsv~LOs @b9n|S9RQ=/%;|:hz9y/ nX'^O^&݌ k|/ftI(93@vN!iLmN~n3lPC:¾n/.)edIENDB`qmapshack-1.10.0/src/icons/48x48/Limit.png000644 001750 000144 00000003263 13145236354 021221 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<0IDATh}UeϹ ƫ`0/`V:4ɰ@j!@ Q3F1$f&,_(4P^R EYyY`˹gϽ{wٙ=y9{~ϹX4W^G9V8'+ʪ (@k-(ƣwr P) ƖYSP LGkE{עP)z2ON&VNQAJୄ/Ґ@$T'ϤsƲQJA2k97N;Xџ/PݩG"əC_O>Mx63z|*uMɽs;Ep]Qݜj6tzx)Ƣ+h@| #N Y~JFK!R)SQgӪ45DL"5ss.r-**Qט(Z{hۏXodyalq*ڥeS^2yWnjZF\*@ 0g>C26+ OMU.p!~<.iiY;́;yVcb@6߻OǙM#<>]E"|Cڝ{"m1F<;}w|<}p){5&ëh^/@fu_~]wBqnEa*> 䥰ޟ!qeWķb~oe91D:kH7Z cXw3ӊ/*#(:qn|hޥHP&H@TǨU!X[^5/ءOv%lп)sBEJ?7p\Sf?Ϻ>GTyq^-N{N89_<IENDB`qmapshack-1.10.0/src/icons/48x48/AddRte.png000644 001750 000144 00000002020 13145236307 021272 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThOhUg,Im.\Hԅ jA Xօ7VE+"*.TJB)X)$-ML14XM6&so&Iܙy9@0 Ƃ׬#A4hσ˗;@xprӋ ?ӎ`I^Zn=-`nbqMpcJKX"7yk <)BKElcxR@oUx$ƛ8d򥰬+`ʪ M!܄oKck*υr'~|1\5}*>6z.G=IENDB`qmapshack-1.10.0/src/icons/48x48/LoadView.png000644 001750 000144 00000004530 13145236360 021650 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThTU?w~L@]T4ZMͭ񘫨IOehuh/i3͎f brQQ7La}1y{=g;}y}gFaD$$C@,`r'(pL)ܕUw\`Zl6NDLL`Р;4L&Pd{CJ)@` H|9x,yy%Ըt fܸ1c>{3[R 9`@vy E#4mLڏK2}@L&UD \ˑ#0`̘;IJ{zҭ[52NZ /_Nv9FfȐh֯Ӧ ;2O)u 6sؽﻨn,\8$mv8Azz.''g^,UJmb1"eeKT:Uɛo~'[BcGl9&qqo扌|C>Tf [5M^ZLVQ*e2Q_$+VdK@j)dH>%Kysu;硇Z'+ٵ$EE@bb/I$1LJ^JK`޼al'MJ)O{V4Y(ӷ#FKI] :nIKM)eө2v쇾=xY0V0jT,_}wnGCu(ܟ?̚?ظ1/Jskȑ.e<ƍG:0^|:ǦMٽ{ _|&`Ӧy|"2@uާELL]zCۭUU]{wM䫫WizF"21--&"#cnTT4pHny%} $Lcc3_hC&`vaaϖ/ouv odk'OV]Zq挭p4~kGaN ?[ f8཭ f [L;CmjZiyA8^\| ,,ckhJXp81#tȄ KJ줦~ @ll~a,R*xW&1ztz>+=AϞ!<O=DD QA]LL&Ŗ-3XBk߭ 8oyg"`>=ۨ_J~ftԸ>SΜh xF)U#r3*33LSS3ga&&'gÇnW&))W_yy'oţySJ} /"ue/Y져ͺbFȤI$:zDE)S>>(ˣKG^^oͿdI47k"" "oߍ>%IIr%],\.r5Unzt"'-"e6[~SJ9qW॒{ʕU]. fƌAtKJ^Ի;{Xqdg鼚}wO֮CQJRR" NX[22N]39 R!^r®PV{4lXo.˼y|Y)nw{)o/ᚿuFuu46`bGcsPQVK[h;e"Wժ""xoY@]pG+.}D^SZ;2렔:zToi*@_]`2Ul43pOp:F ҫ6!B][0h\vS.!Atf.iv.;\@l62@!0`4u˗%Pc&Q7y2pޢFΟ]GT6Mro!@򡋡 pOϝr_Hv{&ԵoM0҅.7U݌ہhA_]vrhWq]Ƈ%mlz5D8&zz uQw?ͥBz' IENDB`qmapshack-1.10.0/src/icons/48x48/Print.png000644 001750 000144 00000002163 13145236403 021230 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs tEXtSoftwarewww.inkscape.org<IDAThoU3ݖveCJH-[ hMR \(1ՄSLD.P" cĀ IF+٤5.0-ACQt/ŵ9sɊs9{3svF}`6:.xGY>ً?4JA}!b߾##Op9nܝ_ylc`AUѐNa X7Pi Tuf@)G%V¿rN0~/=F-&|l:2?dvph )-މ…'SA? VtN짽ss>>=ΝM yRӷ=6DW5WfxOp6> /e`h0? jt=RR =C;xgx9r9s!||<% _VODil;Xpiޝe]`Xw5(?v&WfO_XV2+f82_ 4?k`MO2fY*%aӛ\a r2KȻWq}}o@VccX̛u+K:}GIl`bvި*3379xK%uA[[T)a)mqN(ض-BuN"QU2Ѡ̏9% V_I&땒#,e`mH4u 8 ρ*2h`VI's0p̪ xz6YZV㲌@voۇwQBL60=pƧ:>@Ee~Zd`X$$f8 wq~4p8#&7p hPBV~!4褑=--|+  %4`u?jrto(1 8T IFkځ DpXmN;\åK?B\~++3j|0N1\.@E{2eIENDB`qmapshack-1.10.0/src/icons/48x48/AreaMove.png000644 001750 000144 00000005325 13145236312 021635 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsG2QtEXtSoftwarewww.inkscape.org< RIDATh{Wù AQTolB[6b&ASyh"$Wj؈D YJ| A!">ou̜9{>Mi/w3M淊wSYE8<_8q vVǂK࿃`ipzNJ`^~\tݐvR OԑurAT2@ dWGnJ&>C&yNzSlKϤonnk^"H[ylTI^*lÓiuSsͬ8&Xteg fZ iTOWLrnO3k~eArEHX<V6/L,J}8"Euy%[h D)`kps>fL>H[q$FGxD?~@ߘڏ=@IKkH@إ:fSQӿ@smum).MM5rV\Y ,b>'6!RZd%mGz撾R_+iCK;K-䭘;.dKIaly&kPtI؊Kp\c1`Yj;g+uZzu-l)MĬ^Gk tI}=aJ *ORuvPK"Md'k"ນ8T nsɪM/Q;14Oev))v De^iJtEeaga݄Kסx OyEڽ$p8fIWۉ?rxer/>[~'J #mּ_AZ)& _ SGژ;[py>64:uzE \Q1ƞ:_`h nD92W2|+>;Ӗ*.Ak5mϾvh]%xI3 T:ʪ qZ+=tUF:5:Φes1OoD:/!pbHJ#:';|bYRi%N|iڃş | Cf&gd3jAxv l73\|,pB'E3E 7 |c|7Hwm{k`7i,H+ܔ2p5%B_vٟ~>[`SɤZŒ/X Tj,/[J*_穖L =BfilVE#aٱݷZQ蹝@tWXn{= ni@מ6r'F6ԛ,;} єo+ڃjk`RQ5rD*v'  b)o kvlWfبT-nJ,K DʘK @Q5&<ҟoQtmJ+lΉTn=]Y߬3RYO)Rvcpp6g-.ThxےJ8}ͼ[twfԏ rD |70H/bbn\lÑv?|=\bQG9tQVU jt_DyLM~X26!Nr/Y 0%MAjUk@UVF*E4eXؐ@03N|Lv~ۗvd%`u=15EऺtƱiدZR|7RLxJqaɑ2r=_M%gg,B0(8$R;|yfArVpj^#]xOT_zgK*4 |ɾh\*R\X\ C?`T^13$sgVG_R(]mR4|@E=ݫeS=[|ǀkÌIENDB`qmapshack-1.10.0/src/icons/48x48/ActSwim.png000644 001750 000144 00000002233 13145236305 021502 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs ~tEXtSoftwarewww.inkscape.org<IDATh[lE߶J%,Ax{_/D|2bPI $bGc|Cx17T"H@]v~k~Iv̞9g̜D%J􂨿 #I=W@iLK'?h#˺!<<+;UPeDiԊU]Yi 5V)&hpkXâ=\4͔X ]~9&6G¼ 0 u ^<#^O;RD.,3"wrh .!+"9ӗr,9MxT;u“/Et`A#%tj0Q(UH#^ 0:k7QtoX#M=}3]?GrIé鉏/,859)ǩف43h+E.xzzcLF-͠t.x&^1Sh('cqwZn^*"9Nz7({dߖ~3!.@Dh2dɹf"zal!vb:Q]6.1W2pi[̈́i7+@c5M1ZSKMC%s}d?)0`b<]Oex^rE+aohI'ռДn:^Tfw [>&±Ɯ9IAW^^̙YQc91fgЇI_"4>@34};SY BCz-p+:Vl:>syaDX(8GSO *_Dkxۅa$]$ _p.ՕɅa a[D8}a_ьL<eX _db6VӴ@}RJ*P'٭e[DFHގtuCxL/5߱g^Lb 'H{khfi -s%܀XJX>Q6ⴢ9UvW!rS "m?%J(%4NIENDB`qmapshack-1.10.0/src/icons/48x48/Scale.png000644 001750 000144 00000000751 13145236425 021170 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsߔ%tEXtSoftwarewww.inkscape.org<fIDATh1K1r׫!trsQ$nvp"r8~ (VpӂH'HXy&<ϐB1d'dWTsfK`7t:pC-)M 6d_|b$7V479jh6-Yk2J1\b&oN{O]Zkflxwo >Cq- M7~^cEUZ5ŠtR 4)Z_h<6\^>{wwX[cyxxcqB)u휛+}OqιkqFU}?xR 4)-NAnN!Bc`/FIENDB`qmapshack-1.10.0/src/icons/48x48/FolderDEM.png000644 001750 000144 00000002162 13145236345 021701 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs44\VtEXtSoftwarewww.inkscape.org<IDAThoSe?Scb[o BL/Qz FL &c cC`LcΖmuýҭ[׵Njl;=/=s'51c7^KELOصEO۽#v/a K[9C6j<|<$5Xa.^Bc*o< FbeO&o[.;: %xּL#Ex ƌe%0U@8 yg|^tw~,f`ߐppX;.Be;h>{yZ=58SqJ=7~p+ ; 84"o;:&X)+j!hh'l*Kn] |Qv]eC 0] :sm$s#~/R^֮PGFm9d"0핷Eff8xΑ"޳r?~ݻK,uttjnn666cÆ sdzŌ(ӧO/!Dϝ;k@"PYYYgƍKϰf qSS%W<x",*w /) ^tIooo:T҄n߾]"ܘJEQ/ٳwr U[[kڵC\pA a{^1Wk)/!;vUOR̙3U{ +2FhllL&V Yņ?'r=klOߝW47|q ^lߌ䷭(#g x7seB}|7 l(Z:;'QU<ŨwGL/4$҄coŐ_0;ԣ kp +޿IKDo?fGm%=W{?P,QW^$efED`"TO^ L 8K!(SIENDB`qmapshack-1.10.0/src/icons/48x48/AreaOn.png000644 001750 000144 00000006004 13145236312 021276 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYstEXtSoftwarewww.inkscape.org< IDAThyՙyo7")dD&1*HhVMLX5 ./(!aT DC(&f&$ 5}ކ mȜu}w9HI;ؚױUS_$&Hl$/^'tgq? H%$."'!K /dZ.-`iBQs4s}_ ,dҲ+ mG6gؼsO³F=ap"?7Q\/>zPƢeكU&(n0IZ0tΞ6S'FȰc(E xe[|Gpj>Mݩ!16,.FZ` N" $v(=DKh3Z9t- 2Gd['Qb)VAWI͝90ضr猩'ٍsԍ#$ЎHc+Lod+P= >ʠ$X;sx1tcN ˆ`\3m.mOP\u^>T 2pOصc˄K-(eha 8WZE܁!LS]˺},Ǯ ,u[3Ǯ$"F&g (ɔ(-g\8*@h:⭤yP̟oTi=3V#bYM* ߗB j7"S&J-ly뎷FP=X(F%*MIk)Z5:aP̼euǔ>p 7ϙtJc?I'_ {F83JA-8ե6+0%(_%;C3(h68j5$7N^c|K }Jp+\ ڞyt~@8>ȁ:͙]Fr VWڥOKQLL=RL@xbA}#OHGR)K5dvh<QGCĎYn(NbBޞ0HͅR\?I9PSDESlNxm0頬Q;7o [H09P_RvTHsb0YwHn`sZqIMG}vڹKօVr'B|,Al%ƤW\@N"}cIgJis)znj+իk~xB!QP ozoK6 zuP,8gekn~0B %t ?\v_ x8,V_i>1<[6Orʀ1'* ZV@e%t071voaP`?Q+ {`Xظ}(,eb5=µsJWgjՆUW?ڊ YV_aSc &4B)%/NO^}kg~آ< X]$xq^&A* ?C>6kB!1k,1/%ZrB,EUxd>xdڕ-yȐm,Xs7+k s%cT~0uSWVô&Ziҳgom|9'*߶ۛކ=м48t}pMa.h]w׆h9ds}̫t,CK{_Z{WT ƱUkϼL(UMT JBk]A׶]a]䎜]feg![+&_@'Ȃ kf=thawj!7'qi1*KmE9/ص:I+=\PT5M@5 IYX(8Em s|3$}cc/me/S__4vM<?;aҭfl{xɱM\r,<ğikzvZR<﹟hNGoѷ:ZLpĉ'^Ƅu9 NHfNJ hf<.G WL9 Mx݈ `=Z(/c]{o!vf,jk.#& ȮdcY~㍸LUl} G?=̜ewquX:ع]Ζdd$c0x IYYTUYHIDbb Z#X<LF)]ܮD:B%'nsf IŢtBl~Bxy?+Bƽ"X/2{!vvlj˒%$%0!AAwY( Ӑ*K.`.$I! UknRR'<\&c0t$(HgJਨ} #h#A#AH5w@M T ZCFF2k&bt¾h6oooov>Lzi!/a<==8ps6fl[h4H`y ASskh1:я3g8q0;vLg(<ıj?Ed2T?np^BO(GHOOC8mkymu`@Ɠ27gGdz7z(1?Muu$Lcڴ!-P]"#;K;[ou{v H$A`b6EAz;iԩCn0VL$ApWQIhkkO1b2uWFvqNN} "쀛r `N&(_7֩zx.vrhx^3֖X#²{6JQ Dp,r |@x~jŚ5E}3!ADʕ61o^L/q#_ A$$UsQs 4P^DmvRV0QTH?mOz CNE=GHl+JB|W_UQTT;W}!!LZСލj~iY#ܐ4q8 oSӆ`h4*{Sm,zEJlU*,dSVVGbb㳉Ӈ;fC۷Qڐ܆<}_Iۥi.5O2 1D={6AF#_Gwg1sΞ_P_ofŊi+4ibw@/,09|bj.lQn]G|=~AY t|TzÚlnIc)F F3L*PFdžB5z՟ich/Yx2kƦM%Lb>zNs4ns.LW`[.g4C斱sP0@mm?<}reB@A)rsGoR~y<݀|к7쑏{9wߵyaÁ~~:"# TT4NjʞT4sM@fɣ OO-7֭x/Y67[hhy!t6v=OcHwʈ:3-n&N5k(,< QZ5 jIg7T@(P| *#n-xƬY̝[@RX\gOjꇨ*}__%3Y؊! ؁|8OtbètYXgb;zZ/ALL06BMM+:hU^4Glz ߰]ے±.[:LzV@:y(3ݎz|+~0X(52Ή2˶ׅػ-r<D@r_d'*;|t&JP)W-?BMFuh3[PA/^6f8Eh#2 #-Xy@kFt0 ixFcf%FM;3Fe' -@IENDB`qmapshack-1.10.0/src/icons/48x48/CSrcCAD.png000644 001750 000144 00000002542 13145236322 021277 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<IDATh}\ϙ}K6Z⻂ Vl]JD EK@KQ]SK"6V)j"nQ J! ن[5u7lfw6;;wn py~9C-Zh&n '4G{) ,`Rҿ5xafļg{ŋ(Ѝvi&Ƴ;؀Il4<<҅8Wj\TTȣVGCXK?]Dz;^,,G(|7N7dKG Ou0 8k}j 1 x+ )@3tnжVXKSFJToΪ*I*W"눻Erv03,̔Cu'9{4waHNǒV:]?:*v^'/) Ĝk{'m? q#y,>[hJ}m/<Ry +C˄UQKּ:z=م}SЍdω Uc$+ 9<\luxӤ?9W}һJ%=,r 82J& )M%o7Z$?C˛A'7:?cTJN9x&0a ڗ1^cu0N,Opa ϧ$w L|6q~K8أ6!F?E\Kb @\l ";0U%| j [nfcZ¿Kd䝙du?gG 'm\Fa<0<[hDeO%.IENDB`qmapshack-1.10.0/src/icons/48x48/Filter.png000644 001750 000144 00000001744 13201005615 021355 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  .BHtEXtSoftwarewww.inkscape.org<aIDATh[O\e 4hj^XRZ)BLFc5im<ǶxPiZf`b̞fd7kN{ %Ӽsq)gjV:=cTS5yٸĔCͺ~G&1%u{BqEy%XR,}BEanFb_}/ WhoeǓeb @,qQ`bA&jQ{SdDɈhHuE_wFL dDܟ`@gLN<-]g7Y\?UT9բyuD}Ƈwkb̳)EL9"_rco |9NS~ϣ . [a(G&jyd9-½DS!5Jc3.>Js93[m36kfiĜFFͱbj nj nj nj nf k$--'dm3 O6 IENDB`qmapshack-1.10.0/src/icons/48x48/CSrcSlope.png000644 001750 000144 00000002537 13145236326 022002 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<IDATh_Eݭm)EKAjBlb4F $KPBZtjdM1$6K"!-Yi{>mtΜ3g73gf~La SNO W{6ށfqv%{%coLH@(ƩP^&\V*^ޔ'B[`|S a}@xCkiqvg^M`Z9ړh3b(d}M|RY_.|%]Bomla$I5C0*nzUIǡlbV*a.qbt1Mݱ(@XGߋ{}-+L,Pj;KrVPC[b@u\ `ӻ~c5o-%PҤŽU2y]ĥ/dvFRʠq>6y8c lkBBmg q8៦pm@% އK7=Q^EL 'M.q%.#i7 `+ 1Ao>ƒV6|Vp:dr,!a 6Oh c){7V%{|j183PYNRmrC'~ƞΤ߃7>xH ! ~¿x6/jV˗T e:5A27sӱtؔD?!Gʫ SQ '0cߏjjF^rqt.3x.'9u\mխ/3gmѡ9('j/ QisHAuCG@c3}I~=pI*aw(d!c[${VF,>~1_#,/64Tw'y~;Μ$ǝp*<RIENDB`qmapshack-1.10.0/src/icons/48x48/UnitSetup.png000644 001750 000144 00000007720 13145236455 022107 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs<tEXtSoftwarewww.inkscape.org<MIDAThYiXW~BhTltkvNLOg8$'m;=O3e63Y41ݶqMmi#>"@DtdAQ,%1 s[sEcO`X(b?@! c0fB|Bc~1IU WWGlGDDȈ41TAAg;׬=;LbOi0XF^c͛ $mgN1J-+kV"#_gN&ѣۭ|;2 2++ka./c]|ݓNsJ]U ] }׮O5&O~1(c,.w@ >hER] `ZBɓ x4E[q/ U5 h` !Z2%TP(QE)"z!` hFgnSvݎߏBc_5@)08޶`G-ѹzg:(LQ!m2dfN4BS :_ l`2q1$//]SS8_h$B5M{R!i+ j{kVU=ݟ@EQĴiӬ Oz<_%I(##cBjj&wFC`U ;ϰjA\{(;` DQ!dp3-ԥKʑy^0,%|+r`qqti|tg\.׹]]]x<f6z2qhii(  -?v u{cpaȑ\ lkkD ^E ,璉.Ыi}c$\6p+rFcgqp>^/? !'NDGG#::D*ap,?(EI233ó'O/\pPӴy|:(q nz-[J:6EVV,4:L&II̙ᜠ:R!33S_dÞ={:;;8x9%d`3Jaa6{pڿ.-\.r乜 ޽gz .00pB{{;"""É'ZEQ1F|,LhjJhh֯_/Bއ DE(--ECCl >#壃z ]eHB㭨LQ#z2ЋD{CIL'@)(~{Ͽ_j:Җ磱qsrr֭vN:F"Jcj+P(?'rcmQ٥_(p8~iiJ'+6 6XeYxnw9QQQ*q|[[[(ɣ$w,D8>u믂](:"#@tt **5x3f^K֭%xs8rdtia6 Ǒ!@NrٲefhllիW9s& R+i3GB@/֭Ilanbhh(DŽ |rBqAA2`s=,+6mWdZ W[{ӷsP`((?耢(eqqq֭[s<YӴo 䀶xhc^AȻYR}QnGjj*}}w<ݻȳϾ8d8RXX8'339X,>9==] M+Wpر><ߊ M+}q]-jjٳg#!D5kYx{ر#@=!G3gΔ̙3dҤI Ռ1\zUUj u]: 6? ֏@l^ߎbDz޷oc&M@R p¡ى ><%;;(n2U g[F?͛v?p80  ;wB4md* nI8NEPQ܁'p;9x\_)fن8pHNu7T"8؂\tɸ~C4b-[q<XQQpQQ={jl ٴdsrr2!rwXd*Fbb|GZܹsA)uK~xUUÃ}_ux<l6#!!p 6b8!%%eWTՅ(CJJʗVϟ7v;NV^mN:>{Ӧ[VEE둛APy7t]7Ap+O5UUUXxg7oDQfc=`޿y7@Q ̜’/$3f +Wx!ٚ4-@lĝ擧 8]e0#O%IZJ).^W5tvvR:;;q:~7_/_EEElq+VȲ,1|MӴ] ]͌ൄg~i+anUUps$A{v躾/O7o⿠@dFu2A2Ͷ`޼yaaa>$ &LPJ1Eq('Męf:0Ȳ˖-3 5J)RRRL}[00B@$̙3S֮]kǍ7 28CXXcBRz~y0www;wRik׮ѣGfϟ?.֮]k"z[[&BNĦ,׻8>06$$$l68mѢEҠ󵵵8~-dzb~}}ommE)GXUņk׮{{{$)SXjP@GG˕owwHzVVVpzzc׮]@(p7RZ(0MH :} /HEn1 ՊSNi|I3ye JI;@(g׬YcKX]] %$}"jjjprc֬Yb|| cQ܌(v!̞=;xb||r@(¬V+g ;%@)=]RRHUUn޼YC?HNNdvX;6:ujkRU5BH(+c 2t% 8NSVUK4cq\duttt,ndY7eoFF*r^%^<$FDQXw{0'IENDB`qmapshack-1.10.0/src/icons/48x48/Redo.png000644 001750 000144 00000002335 13145236415 021031 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<ZIDATh[UU>3yQK00j=8B]"YAB/PQCHEvӢ|)##G"01QkڌzX8Ǔsf=s/l6~{{؀@-I3fV[Pw@mwjCU0rOZZd.ă b9`hb4}u'B @U0 piWQ菉yӁ1kǒ40w`*ˣK= |R G"a1 nALtԲR#4B=qI1\vai)b:Yܪ\Ga8$V.0>OpE9FcL_$&vWk\iҴbX&;ӰRㆄkYoamX]Ż[Oħ$#~+ǽ֕%NbJ6wf`Zjꘗ0uK:,'A >F$1kJxbnciBYh ch#ʙ^YŶ$BLͅ-δZflK]x;/um.nux&Vy+?V0<$^eIhO~~ǟ#OHĺ-SRXO %n ⋻nͰ5M:_lF +w{#V$8.&wuT|i5]x_|~% _ˡD\.S[pA BZ/R'ٰ3,׼n3k.Q7:+ijb^1 x7Ii2aY p`dځDz ^@~{}8꙱mLɋ_ec Z6j,;ivj^ v^Nر:9q8bj^*j)BUi}tVUSH-rb~snJ؋},}ɉHg'O8W[H H.jIENDB`qmapshack-1.10.0/src/icons/48x48/DeleteMultiple.png000644 001750 000144 00000002451 13145236336 023057 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYspto:tEXtSoftwarewww.inkscape.org<IDATh՚oGٙ5QHP*B␊R!$* VrDHU.q=J6*$J? MćCRc0qpހuɗٳ:[Zq"0bސ1.FkΝ;{V] 0mkT000cn]ȱcǂR$ׯ_u9o#ZJ?::*r)q>HB\u%NRٳg`SZLFJƜJ"1| >.1WRrpaaA8qhȑ#a>sܹZo\׽]qguyR58p@Rly'###2<<, v풣Gf`uJCcMTd\.q-Cm޳g?~\Μ9#lV0EZ+|8Azz:x=cccÇ G1<<\ZOđTuiRn4JWfYZZbpp;bg~~R鉈;v95A NӋҌ|JZik pX:3'%`+W/؁ȭYgX,&(gR Ekz"@Ii'ZWE a2^b`]-u`{겾as?@?ynm;ÁLT sR{%>|XT(C'I͵<jl,dZ;'kB33cl̞Ǝ/s`S

a$beznpogaUiړX*7X7,>ϱ5XJ.ytm#)sx+|{5YЯ1jy{:`mA~6d,+ [QHI ӛےEGR曄׊ܨʤJfiPIO3EL0WEM N|amfĒ;O 6 *vD| zŐ~4IEY)W‹U[iYJXG\,2C8Ʈg$ogVs_OD"l §tkW| 8a(qO%k&vP;- SB'~)X' &aR2R$V)nI9 26SIENDB`qmapshack-1.10.0/src/icons/48x48/Map.png000644 001750 000144 00000003461 13145236361 020656 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org<IDATh{UoUʣB M bq RZQ& $TrۂDTH#mՖZcRD|4Q 4A miI .3ٝW!.$|ߝ{s$_ar](bEB(x)ߋb~߆QFp>&#\a0) ­ڣӇ ǒ޾GsmJ9$H%8#?'|cO(3 hկccnb+]ӰmggX2pB3!o>wq7a I^Q$P/[Ӏҭ9;$Zp,O*+l?#-/1f,u5&aNʃįDz۱q;xcqdفc4MrMbC,mQ3p-;lQ %L=%}g!4m#9tşo7%hZ$=UW.0⃄HePC%6<蹋t6TQ"ɓHphFhb %&Ѥ_|Sq*FJZ]7L1qx$mY^t#q;7'up" XG~uQܹxŏҘ;wWYpo]\)P+ǐҳ $~5z}XMZaXFz:aZq 'p…&$a7zDrC&3_%ڥJ7cEpv P׈qP/֐,&p'ٜMhJ=~L82~@YgT6\vff-Ü=l⻿G?wsbGQ1r]tԱwV,>?؋Hf!о'Oca6rv=xcfez`'#VߋcȎ%qg/W;[@sIO,PK<>H:8qs w7^dc$3a7.ubdX%u$f߭XI(7炩b66."eGpMBU=/=sx_YH{Fr%Y':eS;l cM8hhޜvCԁM*(.OsI @Fu[ |z`*f;yukR^6ZYG먷GEV]30B~4h@:pӽŘ!UB[]~G57E1ž, q=t+y&V7i bgd9$cmIB*=[ ⰪHz. qRJraұ0ך@ӽH u8es@MTCNj ك[Ko!C%xBQ,c޿Í#taio$D>y4:@sbm;E&bO:IENDB`qmapshack-1.10.0/src/icons/48x48/RegularScreen.png000644 001750 000144 00000002176 13140265126 022700 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs N N*ūtEXtSoftwarewww.inkscape.org<IDATh;U]WE@LU(D #XhQC,PCY`W`㣡0(P( P >b4"`DQݱ{w;oX.&59M&ws,9?9sS #xpt_(6X+Q<A@M# ![Węx-v.ïp|7'I2ԏ!nZs8FGE:ux_XZo @|}lng2{ޙ1 f&dJy~Jbf-ßYC\$lN_b$vFUQz5w]<8vaan>|3mF#U=%Ȟ Q<4!P&6DuĄ\yJ =40 0O$pwyp[y2ăY+ǏEVbzJٕ `*9Fj00ӛC-MXޛݸ#HnߴHH>fe#3BNdB(pb]&ې+d,m\Ⱥ[^E2`h$0~QZ̼TR': "^F@eQ5o,ȡO;L]f<5'QRPƩ$Ok\ӻVͻG̴~u\6qPN$fR8oJ f\2Ndԟ1nif DC%}~peJv5\,zrzw 5utvs9M-vPUR KC."_J92 A&HTd> W#NEgI!ǷCu/r+ >iu* ǜڊwo.qn.8jn&U=?YXLV6z]ƃ)єʡtGjI"k1Y)^."A31(T .Ha?*̼DHg81DQ$#/EOMִTF^yODYoNc0u]{Mm!gN& ).(BEf=2S{evN@ Įr4Aj.5stΐdµħ2t>+$`f OQs3)?pIЧGܰ۩'I#m(BDBqz?O8BA]zb}髋sW"|{0NF [c^&\_e;nגh;p{1M\+GJ /9Wvr|R<18`GEOx+!)Ci^QJ@XO-WfINzyXpI A>[9ؙOڱG_{}54cNcð sqf\bq=hɕYYXz+_ɴ}Uut-K ؛w.gf)&+m$\C8C|}qgD.WX|t#=ƇqL:P-4kɮ ֎71OL Kr2a)2<]~Tf8ůbR/?8^sK-W>sk5b9|i1xgd TjK#/ žԝ@X/X֜]lwZl.j[fT *5Wds_&<\CޟӼyQ=B藀/V HU } HYEO׵Y҈RPm``~) @uƋ.)Z([Q^Fgd!53Z ي 9';&:bU P.Eeށ8p3(j{U4V<^!Nh7/P G@|cT렝p1|^Z K}`+,Ñp_8: 8mDye>:'Mgee b+G9@mgA(; PNV?̙ X߁Ej$fnW*S:İծm b1aʌ׷T^&|닱vDKBOkʞJѮH$H2q)yAvN7ip( Md h"AaZKR-U^lZR[RmbqEff=/f rjr r :Xa&24 ˃Ԁdc@PVf:<Ixݚ?5ӎIENDB`qmapshack-1.10.0/src/icons/48x48/EditText.png000644 001750 000144 00000003035 13145236342 021667 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDATh]LTG, * j Ũ"/MjJjD14&}hBb5F,`CH j`lQ, (*"Bwٝ>Zƒ'3sϜs?;3 |B#0 Cjݾ ywj|%gϞŋ"+h42###0U>ƯBDC99zm}XYfvYԲUMd2}>00 J֥,{GDsërM̚mB͙I<9_ 402N'|ess@Icr@4R#<53J"4۞@rNJtʯBαϩN55io'Hr`бuDFqX;(6 ePG͕KFOnjd'ecҙJΩ8f@yS9AUh"gfFJGhB1fEd,ɸh2 iOe虵\t|qG" 4tJrSs BKumkchh8p׸ (fJ;ONǥ:FF3vĻdkBBxfe}|]7a)03;-O̊ .(bАcf )%%wJ:|T14y5BgSRR_+Ẃs<Nq@2ZmY(!LXX`;L-/?2DLS(K`ؖ)LaNrx{s]-  |4T麉pׇk2c< wDNw4#\^ MRzi#㔮\޸ tK;#q+K ُ5Iϫ 旫E~_eғq6ዪ1Cq<H CH OPzĤZAGriHn*m#ь6“YkIیxvZc_*9lJxy$:sdv6Qf `P XKÇLz  ]~XֵOL„*[.˜$?"=di$>k#t# p/ LsN:}^Of `) >v0u6&t1m[k"~xz/|5^])Ct-%tT{oD*#D~`@jQc ;b{ihP(Kzmh8Q=w?4NIo4.%|s+fx`F=Imd$Hu4bJxoǭŭ/΂8k %Ȥy:~0eж?Ӳ<~?"ɳ8vZ*Lqw"ɕ6M6U= Hcs#elI^XD:aW "aHw'F1`f?|Y5ĕG)=O?1.~]7VVԵqr}m&a6ɑA0VR:b.QO&-l{ lg9U)l-+hf!=gT"NXJob!m-MVT՞UBsYe F>U6/hLz'>Oz#W?^t ӛFuF[,U>x#{8Bz0l"k}z|3O7MzO& @AWesz(SÁPUwI˾MrO'ƭ/&LUa:*ɭ@et%E$ !XMzSؓt @,S,K[vMo&<gƟ[heP:J^Ff̤03:2 "suUՄc(==S6i4/ ܋Bo҅L}`@BnB=Un9ƇE7r :&ml{e٪EXBE'țJy73˯@e畟2yo#?{TK&>!,&#U'?=IÛt@~0 $H)Xl"itLΥKxxvLf/@[VbIn@ɛql`IcuY(}.bbp͒cXOB!{ONa+`8[0\:jvb&ncPFa'ͼtיR^{1; bE惇pՑX a嫻9BsWd 1~=|mP'טُe2.FbA @][ K}I2?~=z>.}fUkTYGNJwـoS|cH͍ 4`ʎ$"v+zQl6 'UMh˺Mk_3s˝ jkg<5 L 9 G՘n'*Ҋ'ĜIIzNvǷh[S,5%0Y!y?r&-߯Kyt'\Bw8uXHHCm=.R-O和 \7eXu ^itc&Rͤәvs6 xte|ɜSγ Y}_7'blEctJ©$=1F'Lr $ђE)p%+(wV\?} ?!V&h-w< Å<ߢkB-'Y&V2L͵ӬFVB -CL\][}NDnKpx KNxmji_} c }O=gjm:\OKw.vJxsVuL@7WNz1釄{*a4?U1/'bf>z2mc{zM,˄XL߭ImIgQRB(£?p~X qX~V~[3Ihp#Ub嚼6ɂܔMv00VE:y7`Lebv8'dn/#[|gkb ,>R?#k=7!CocQ.qdiܡ]FLىΟQ*J*C ܗr>atMўщe4Y4yn5M^OSFM׈\2=ٿ/Xў~_h_Q6IJgg}-M IF4oZPw Buޕ -~ m :/'3[.CVFp gpGz 4oc{25L h~67pq?6suL$]tZrU깽XӚQ$H=a1OĀ6bs0HlJC[$"pe=Js𖒵U:0RԷ"ڀKE{ž4XN/ƛ;q_=-ebA6`*抑Gab:yY]F%◚+Ug5g 'x4 EuPN%ydH#Hq}ƈ(eDc(%sōGˎDW)وw%qZGc񗽁q2P# npK*B^dR"O=P#wt}f Otq4#W8'$3>ht QG9K6wZIENDB`qmapshack-1.10.0/src/icons/48x48/Database.png000644 001750 000144 00000004055 13145236335 021646 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs 7 7 stEXtSoftwarewww.inkscape.org<IDAThݚ]lS'N;q8 '$"Ui&AmU1 vk.&U=bD]&b4:CSZT"_Ilvۻ1lj>ґ<9  I %Mn!]O/K @5 x'NHO`N/AkK` \f$ pҿa~ҟt.Ψ`\wTVMCȎX:f-:Q\IqBrp:LN26C\").U=-jVE[5_|1A_pw%Jz{8{]t:6,`0Ƒ#e`Ѳ)*ۯD}j8~<΍ ##?~+W_].{^MKF#VJQPx;LLSܺbq1#$OX\L18dpй٬`P׫0Ԕk2xff!_՞= @7n\8nR 'T>(iwrgM$ I=Q1}LLppC$9;Mee%Zjk OUtvZط~i>'o+!jz{mZeOӸaB8@`0F2:!RVDW!j y, J@ `re2 ˆD YԚG&t7sFŒŌm],.4k&!Cd#֬ *^z^xBGhr率!WN200O@`R{(cj42DQJ(T@`2.07q#!RԔm[No!{~4&ř333rr?۷݌zq:+~ӰtUa e2Vǎر=[F݊Lr ܩbb4jE5ju)Zm*p8A<|z#LMq8]}k12]sEyF(MM<>xp] +2sܸ1kj6kik3elz* NĉΌ-]0==ann?J<\3锔)0TTUSUf^D<mRhnc9"o$?\ũŅ91&,,VD" >JSY.?*W dYu:%GrP3vlYJoOpDv! RovMmtZ[MWcT`U`2Ֆ)Wmt'ipH$ I26ubNҧu > 5Ȇ, 0p\V,`IvVF@X^Htf^ LN`TP7WIENDB`qmapshack-1.10.0/src/icons/48x48/Close.png000644 001750 000144 00000002765 13145236317 021215 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<rIDATholULf6` 8i0hhg1!E!`{.v{1d/h#P!_;wfC)S58ԭe݋ sν%{kyV},b_~_cZ+)U߮OGXr<[I|r6t+y\B%%\ƣKNa L[1!X\TŪU_fPBuWٽ֪+V]wE1s2=" 16 FŦ\.+Itw/crᯖbdƢ\K_(;vd D%vT$kkQT*O7~Xƍ]ĞPiQɎ000 "*9O arU+XQܜEԊ-[ODY-VbIؔaYZ y:RDRL,xH#A3Y\R$"H.jІ%K&hKu4SƳIW@e}| VoSU%b)th ?{"2;(bӴG3\WJ-[߰n=+W;MPzs[m'هgI8U^z7rAW"SpLц k($MTuuEUʏi(UX28^m~jTˉ䑹`U&nZ",WwU9]X . ] X\楥%k0<V/n-*q^>Wz~xp@ML,Jjw0B;X+Yڬ{ P#D ϸ?''n'&=f]J)\bq02uzĘXAʫlqȓSp/Ҁ&Kv@:;sbE _%.<aѠFy2V:b^aǶVl+uIENDB`qmapshack-1.10.0/src/icons/48x48/CutHistoryAfter.png000644 001750 000144 00000004351 13145236331 023234 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsttJ}?tEXtSoftwarewww.inkscape.org<fIDAThiPUwר`ĸ/ըXR *`MC[ b:4:Th%q_hŪ6UeTUV` K {~8p\Q3y}}h? FPWDEOfflI6/̟o`06n2%PKff@vLhI/P8;JYt6mbbٶMY=&@CoA,nZO:eeJK0C2nw P*Rv#"m^g|$ty#xE!,]j/ ,]>\j]z4%Փ;<<`j7.񓉋q޼Eh8pCm<;ݵA럄Ognf/L=`/4ᤤ|M8}8t {ws;:>wSwv͍l(y \h(0PQ xO xa!3 m,XKDGbĉsv6[/ 8&u7_^0 _~ oa#G)ńBMa%А"1C uܡԩ~; :Z_OʕsgcY`g nY j`I J oo~]H`Ðӧ{gf̙pL k͹;X@O@P%RooϊĈL} vM^"}GCΝe%3Hү3Q@FrZ={7xzƻwaظžzI ̙KBUj<ҿQ0HK7f̀!N6`w!<:7~ ڞCz:)x5 =j#[l,#!#4 .pа$W9P EC;p|CC+bEY-!) MU7{@NppV(RfʀjXM dӦKc"~~ 9l0X!R]8Q;ƍѸJݼ[ s:uի$(hL]H|}Lgi=ǒBm@ەɱ).HWp/akLÀ*_יлq1 ۂwg/Hс4}p-; Z ; ߤ]^.H.wĠG\4掩4~ ݚ Fᱢ/ kp]_#hK =Df Oxi'~Zo-GG8 ΂ꃬaqz^e(C[Q.za6cZVJygpu=Iց ƕOjG с vVofE#VL,7qIrh|%C? لr.$MI 6Sْ=nsDUb~P>ZTiiF+^qeGDL~80RFvxXMw3qQWk5|SZCOMAV BC'|W,m&,_ f:xk0u`>#܃k h'xA> + _7p<_f[tٚx.vTjiG@ͅvÝzFyȾ=Yb`+egİ5ve*6y/S3ʮQ[T(²gcxU$X͑6GCT*aψf\xʆ㗴}Gpc긄嘆0䇦±XDxOv7X%~9<J~?cl44CHё*[Z9#Naft4j/]ƤAZdLټa~:rBaϛdZq4/B?bָa}0apM ]܃jXS{x,.^ Y*g&k 3k6K4.]2)4dt܂ \V5̫sXKa~e b0 Ł!l1UtU+RZ>gNx-Okgj2LÙ!Twƴce8'jNSᣉ6pI町u]3+~"е;x(8؟1OQeVxZ;33f6+aOx>M_)vdl*͡&̎]8"%dW^<3|A<ګJnt>>ГMZeZܳ5s1 [A][~]>cqn>8}3r֢PbgԏݨǁmLƿv"G'Kو"u6 ݜ8`'?+qY:6rJ|GhQYsZ0GK'QòԳCsKᮙqTTT[h.kx+]F8i4j#γzmoWǡے%"^WWϟIENDB`qmapshack-1.10.0/src/icons/48x48/ActCar.png000644 001750 000144 00000002037 13145236277 021302 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<IDATh}hUu׹JC afs(AJDA/#rF")ՠAf>DbTHM0M*Sǽ֘{wq~|?;'RRRRRRRR&H  PB5\<у@J|(G}C mG-_OCXM~!V}CEˎ/* 7- --SL2&Q0bENXc˖#NuOcѥMOJX\Xqgէ?a̙scD?so4]VLxqCE 53e2AZV,GWa#T__Mּy8.Kxc5;zM%KeVhV]]En8NsTQyV+UU6o>R̙ʹiuL̑i"zǸw%׎߱_ ?MU{A3*1>bv<;RF{|sm7>e\GQ i",ÝsM瘏Y0@C!u"j#I a8OthX-k mTRD[` ఘ-v}X@Ԅʵcm+6#z ¸V})!OPB|J8I d6u(d<51 62%Zw=$Is_8[)W}d$;#}>!;Cѓ]9'݉O`Bvf2K0n.i>Ag"{V^MM%:v. OPZ>.ytx E. {2}䖴ƞǞ|˙؃'GJJJJJJJJA؞ZIENDB`qmapshack-1.10.0/src/icons/48x48/Device.png000644 001750 000144 00000001457 13145236340 021340 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs N Nw#tEXtSoftwarewww.inkscape.org<IDATh횽KaKj6hr+XfTp?6utt ?"K AD--jp6`4y=ۑp^{}TǛy3#GcPw 7\>kz-M <\!BwvT`(ְKbkÞ~_FS IR# A4)L#`78v؍#`78v؍#`78vc,wчa lnvxW.H$$yÅ S_k KPUJ& )FR3r9tt88(˩0CC!2kk9J=x6z{\\$VVufg?1: pُVc(T M\p7|9ã|d)Ԥu аuMl?8fkO+69Kke8T)N$اO9_SĹq_p/]s}9s}g@|aX?i{jnpX٦Mn\6oKX 3g-СbalyU1uߑdFj8rd3^\颹"p8L(իd;5Ơ'U. g ہHӸ8Sۉ4̃ X 둳 'Rʀ@+hHvr]ƖFt!ߋ1rza[ؾJ 7f1ˣ/'̎'xdRZǢEVV3>_/@GW=47 1F%|Z9SoEyyugwp:өo.PVǺuX|.7mDw >YZ]]vM -rjj'n?H__!`T+99,^,g… h;a`pϷoOHDh%iJAb xFa:ylPl؄vwP[{^{&v2W X|Hz7hg7X<| +v4ޕgo2<2$d,S/3n-A/&++fM!~Gm=. Ct檁FdǎJ{hjΝC32\,]Gii :4Ơ'P)A:k'u6 컀?#}$Al)ϡ|aBOSwG: L%Q@{!0tǚ,XC'M7l=n6#yٷ,?4ZmKTyrħLB\yYY6.QWw Y(,TfB/HWW?o[^ϦR0?aṕXQg$&*(vb.GHWC[W/bvQVڵfG߫(([o넓&(TW/zh]__?$ pXJ##:F+]K.Vb ˦:ȒL/tXt#- D7VT;w_f36/BΜ ;H߬MvZ"Ю7-&''] _Wc?`,cm!2^A7!f%?Eaqd5vT9|~Z|yw>ʓ}XWU9>MY; ^>&0uZ4qyOƯTo}u!r|Wϻz]* @sG3Ề>Gbꃧ"?+~YzΞNXNA`qV\R ')ԟ>E@3܋' +f} @U[᳇N 8|P&<½@051kւ>g^"4 h?}7#S޿c{ N([Mh#'zypFN>09p1+0igO䞒F9/"eZ= @^uuwVy DdT>,/# oZ Q|."%}jt(`¼/9^T#쵦_龂V/mN㭺2s@*`,^P't)AUN{jRe#J_fX"֪uz[4E(}?GOiU >Ioh6@#zX7grD",cL~22@G@d'>;vLXˏTmo҃^E9pg[ l,ۈ~l߾}? &sx" 'Wy˩~z?ND╕au"b۫8c ̟ 'ptK0k8ѐ􌅣8_tm{[E{{{+Cb\4ɛŰtG\v)ZB7Β4l.A^]q1խ/P6xT@<7?7ݜK > ǔ8#B7S29h,RNFDD͜ԩ 4P^ѸIs98^;wJbE^5 7G&9?C~BEĤe \#H̿!ձ&벁F'RYvU`?YY CWFX@gD x:[d0|yc\q8@1^U܁:H)3J键Iq1z1070/ZFdV}eYWńXٸBh2:*Nϕrc_{ŃPTq/kNi8Ume}bǞ:8"葒h>88 )NgevE1UWetW/YI&:R( *ۡ2YlJŚ<߽V}?Ѷl+Z$[nژR(TO[MO-V~Ĭ&y'l|)ϫG$8S315 t ]R\S)WxmOI6+Ke't.bn"-x3rJiGom[cK*;ǰG"40moS|yq%#M!D4.߼FVT~by/oܶfƋ8iá 孹f 7dO| yY?48Z@;K,Ѭ٭n]RF x42Si|b 4뭷n-wD+)ءC<)dS"y~70|c1ԼUkJ}!n= ݛ֯Y]̀ǭwzTmt OdlEUuE}:RAmfQbudǫ1-"69ت6jþ%y\Ϊv:2.`jbM[݋(Ζw#+j l(YP|cr,Q/clOi?/uv geSK/IENDB`qmapshack-1.10.0/src/icons/48x48/SQLiteNoConn.png000644 001750 000144 00000007216 13145236436 022422 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs'wtEXtSoftwarewww.inkscape.org< IDAThy\VU>+<>< (HͨHhJ3/ƙ2i*ұ_5d:JC#e[K /~܇>N99s˹W.)Fatmq;@ p($r%5)qB"tiNɣVl apP/}T|^g :ЩA[NVo: T7BE=Bq m2o">za+6J`:|ߩk>fH>?#!~B_ IPR W`^ܺVBDω+3_]PHq6U+(oM 1 %ܺV !Ԁl=Vt3g|{en_g/T "^\>uw# FHR(@;mpܼK^F5}.-W*y%9 ]VcbN/?Gsm8iHMoVVcBiCzf5愢:]Jrh=t\?{IwoU՜QxGg~*gN7۩=t0{PWʠѪW.с x=FVgb=#N -v74v݃Nb0 j??7݁&!0(tJ,Y㷐2֧wmvj ? 0e@\ 6v̛7-[y:~\ά h[lxeh4"s ܹR|[TGtltZDQ`\8D I=\v =:к2REXmBYƍ% ĂWvņޠkQR`nL!]INA#]h<r~TZ#gSfsD5'@Drxu]9Q% |t̨;#aF< 9]wt1~<#5&LCϟ/ɓEkK}N\LDJy$$GasG^.uqTZ-:N -xhaws=& DL0z'Y]ȹͺiLh= _18ćZ̙CȘNwMFH$:#gtv횇f>8w=<͹_ u_3^ R{RqRFbZ+=UUf22sf5FbcC  'mTV9̢Eƶ]pFt\ W⍋Ph!$?S_P_"T*%K"ߧއ{2uvm`2xgHM J7òe4XpZNyw[q 7+]vѣ˅`ǧaʹܖcAa#- 7^GP]mTL*!Q)Q'/H̃ۇzRSqL⫉L^8F /b).ck; W/qy$ PFrC~y*sv-Ln }n z}*KAϣ~cgm f^q7 *D}>  8Ulnѩ(+`„ *ؖ&9kH7v?x #SFCGށo/B=o;5 5c39zp|lC9gZpD3߅ \ıO/O4Ҫ dkI%JNoN!?_.~,6h~ǫkgUw;p &3XS*a@nSRXI@H`9iQY\0~5^ڮyGCi:~W$x9rp{'0q㺤l{xÊ^>5C\jOs@'P2=uO;t͡8- ,Y:|-rth9]*3h$"Q~ 0ˍ)LRhjY ĉ^Z +T*p(/0U;Z֧~A`x0̋ĠfoɁ/QYm FWR,T|z.~H6I0JCXDω6.!rMom9*s8g7 7,H;z%0kr")hhRʉmRNm>r4Z5"Wy!QHkőG_ĿbӻM?$҈-;HG$$<=!=m/1+Ҿ[ &j}rlZ%V_`%ƥUem H@Ew&҃VNlzcRTuC+TwT4d7Ԕ)-GKn#NU*MGh'Eh?r8 7*%HI/^ʨv$<+϶R(ǧ.zS,9sFs)^$/` }XGs]z Č}|]FNY{׳/4e\D_]x$2EAcm.^k"aMM%\Gd`]I ExZ&FNEcH#j=EW?$O~ҔEFE?yɥF%څoRC͐YbWqc9qL1M#$">S1=xέ"\%mJJ.f7V阨i\NwO޻l+ufKLO+~7&)QV^>-7Z11 K HCʭ;i!k?SIENDB`qmapshack-1.10.0/src/icons/48x48/SizeArrow.png000644 001750 000144 00000001275 13145236434 022070 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsFFztEXtSoftwarewww.inkscape.org<:IDATh͚JP?7 pYj#^Y(g bbq5J4r93$n͸D w02"DC"¦yTr A@<5`gl$Jh "̤̃"5Jf]Їu9~ZA`ݶJg1! R<@%BL&א4U8!w DNA BS@U7 `G6qՉ>yoTV#!zSf>,TĿQhV=o Qj+J9F6T0AYRbs)åAR61}Pg,h=SHpCإ}+ Pn22q1-:NFr'v=iӂi3͆B#SBX3'8mbt Đ$E@J ؁ZUeSi]u`bt̃$!I iK+kz}T0]I:mP)%`D9n- g{ƕXM(+}^&]|Kq9xl3₈\-8=Ntm8 3 /SpE@X VNW ٪53 7E=yBRҒ:?(dȀ%2.i[,kx #2)tL6ѭG~'da8)Uqߛcd\Rfc W-- B+kJtyD>x^8n έ]@pX`]Jv~ R鶼33= 1P9$QݸT<WY{r"qk_?%"*>C'5{ܘ}W'YKqj\(j's,QvJ">5ˊ;$eM|z1=s[<"3wɗOfXv˥ekطI٧ۓIUNQcوUok7%W0Py!V ]h~i]AFf KJ|)#y"$s҄ƏVHkdBGxpm [wd¶ѕ^uŵ^86DlTdF$ksGiGe<op&5&^ m ]?FHAd-jᴪsg _5n;10_((uM%]'כ@)Oʭu{3D}%=mlƆXK|WgZ䒞G}seRruͦns*]uͲzQ)$ܼ>A_jj0Gbq7P\`p&OvJApU6&\!wW V*.J{3AD! ܂i8Qf?1^:R\p##;4QIENDB`qmapshack-1.10.0/src/icons/48x48/Font.png000644 001750 000144 00000001315 13145236346 021046 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsߔ%tEXtSoftwarewww.inkscape.org<JIDATh=kQ߮)b@Ab%Vl$6~`*_:ČvV(DDE ($1dvg;{Mppg;w8CAAK{1|c8R#qލ!'H5`yp2Τ~}xtw`>؎WtJ؄-nc{Z.17 n4ShH47-<j- >u9^iMO(f蒧0nz;qF^JQe[ag0Pgx/C謑7{XQ9)#0m1yy8i伈K7C4Mtw240@ZCi4p^hT/:,]c(䱑= $'U"Ms%*^J6Y=,l2nᆸOZ/>؏ 7r#xA{*o+cI_>FvSh7v%t\KQ-E݌Z;qNDEܤڰHOo8ET:s]h;UPߗdY.lIENDB`qmapshack-1.10.0/src/icons/48x48/LimitUsr.png000644 001750 000144 00000004003 13145236355 021705 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThmPY`YĬƱ$vI h*q06#$t:fڱM3L4}o8)i4M k| ,釻q>9{s}y D$VD&ȏEd4HqlĄS/K?>ʳt;W"RL)<>_%NsR9i>I)2hL%6Z_?۳MD,I6B:Y2c=|㗏 3,nr@Db.^X~Y,j0id|_)1范jlumz`"p9du3,B9Pub$0l8ȼ_I4Wa|9>hN)_@5yRJ8#Ʃ׆l_LT2l<@d둭 \(`$u rSs(Dm9 "eijG& 'r#UJ96#Pqb ԠSl1,,[4 "g**et<<^QQHjR;;O֕&Z~v%KJ3, xN]B- Q2cgW+6 I+o,/8~FO޳@3/\sĭ2א0:kJ~M6z$ًmQax+j:j5+p1~mH{"7W\}e>@xa nd^E\+2sfɆ+.v@Xmӣaɶȕ.M4\cMc N?zlI{*i=w#lIH$6n4mwPy`]aҽ5'Kd߾1^ow ܥ#c;8WuP G(G獖c'j w SMx<{ ``ǵ1v1o5HsQhUz@j4lqnZ`HSrGqj+i <,Uch$1:T^ڷf%l3dzEYo6ݎc#8[ҽ/k8r:nޢ6Nn^FY/ ߿fV5K2h}v] ӬZ|P5 $#S`Z '8GM5ٞSzw~-Q/Db+pfmTfPub&nPkuςe\ ҥA;9,OLvy@D/ce mp>7&q5-[7 wUkLL.rcM\[L~E:>5GB\ K7QkI5+gteL/F\1_l$Lp?u}vv ߋGprJ}1G*XeCaѡ0Ʋ&eO"Adfl5{xƾt. "A*%,." u@_wj7+Fg98t `%9OCܸſNl OAo0@0=HQLGw} :;Mtd sOv;oMP ̶,n<@7 X@sH*/[B*z6u Zd f,e"D y\#SeS:ergYa?eVn+:|4)40P&"/p]fe|:6_,ՏI (x tzV2Y51u1z8` tcAB+TݝX⛗8ZП3E\'cߌ;m(IENDB`qmapshack-1.10.0/src/icons/48x48/PathGreen.png000644 001750 000144 00000001366 13145236376 022026 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<sIDATh헿ka?۫  n?IQt8f"NY]G bu`R1$>פsMz >=~}<)SF:[+,,^;!jhe #iAN&t4j应K+\.^zP$P8!8YC 8B$ (\@ϝq@8ЁQ $ 8X>t]~ (sљv 4*۝hy1ɉM  L 13o`(!rS2fZxE%c!8#tOo .l`ch/l"uf:Emlxw^9{*`~ rQ5n SL9IENDB`qmapshack-1.10.0/src/icons/48x48/TextItalic.png000644 001750 000144 00000000707 13145236442 022213 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<DIDATh=JDA?]7T3dћ}<cf k ZjL]|tM󠫫(8wצK`97~щo#XjN40ZS%p4xfN4 X7dԚ)'6x>&I 4I;B!&YӄQ0P$>ȹ)}`Wj  okx"B r@؟QTn/QTih!?xY]⡚@3jkco"M1GIENDB`qmapshack-1.10.0/src/icons/48x48/DatabaseSync.png000644 001750 000144 00000005422 13145236335 022502 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDAThyp?&!$" T@LtAjtgڑ-^[G,CEju0+܄$&$dsfY!{Ew>'J_"7  D( R CO5CtD_b%# 5{oA: b&`($@ 0w-L#J9dgǓ!%ECbٳR3p28hjwA:;hi飦Ƅ'+&p+# //U,]#7w.YYuVTU9{gOG!y4T `|83!Dugr\\橽?bJIdu5oqL!^d_\.t̓zWRow63(,v'_嫯:1QWg-"K̟KvvF8V{Vәɴs=SHd+!Nh;p7 93uWHĵ+ٲ5kdQVv⇰Xn^!4' D.|$ oyHK[/O@}H1X[>as"t/xJ]fԟYdd~õPfqLݤt-+V,`D-r ǎ{y"&tQVٷa4je F.^ܹNvP9:pt&cC'|[45L&P|ݾ/jI:d,32/< zg>ѣq`.nY!vc22N. KH#P;"AFWֳz^**zkYioh XkLL Ē^?ŋY$bwo9'N\߱[wRF -7.Hik.b߾hDFkx?<9 w +$.AvA<^݄X.( e?B٦)ɂY0WA愂4S<$s D x/t@Kutef`cvH.,_ÇkoHl %}>dȀ;t50 **zش#j%+WQXʒ%%x%;WWټgyS镍pJ#|Emx!iQ8.x끩l*ƢQY9j@JIOoG^J{{?ݶ|]} x RgZo:*? ';팄|0u?]IV8@~Tey$mضmc>Ȍ\d:_ ^NtOSX$Iؼy?P^ BxV-)bFWW/7?XB]@#IIou|yYYmꩯ042 " " BkQ6P\=tN"`AԗIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleRouter.png000644 001750 000144 00000003163 13145236450 022561 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs M MέNtEXtSoftwarewww.inkscape.org<IDATh}HUg?UKw坚Y3M VȤ(X DhDXTCErl tE?.m^\EY^S1ͥygx^5[E}6igɊt(bؿ?gh9!+Vlo0?~I{z-\7iiyhjCrr$&b ֕ۯeCPXxOdmII%re?)iev;'g6x%1c^7[ξ%ޮzojFyN8r*+3Ѭ/X_pn[Yxxk|HFF4iiptrZ3ǎ=Myyϟ;dU<_^ 1}N$9(,o f1eq E~uY$ p:1CV|_] ^ vV"PŢK.C_^ uKq2}g#7c::\9{*5/HոP]]+WU=VGH}ND/:e7LJ1vlm*0}6=fs |990zgB̞SRQJ#|DF G:(MHZ.@Zkl\q:45IS'&&ħ(?΅+WZ[j Y݃fJ!sh̙R@ٚng45ua2 11ahIN`J Bw7J`%6j~WMcW"(JkG]X[FjϬ_Kl"$dsώp[?,T ENT.BJJ$fѣ2Vouu ļڜ,ZT/~޼(ә4;qqf mbv~ @U*(X8C@b͸q+sT@u Ɔb2r`OFIHJ j-^,5zz8a>i <~ 'Oœ9wlaZV9ҥaݻ#hy(p@}zmG}Om\@TDGG5kG& m$;wB?zBYK/V+,\(-J[`=!8X|}``WP R/55HRZvaúnIENDB`qmapshack-1.10.0/src/icons/48x48/ToggleMaps.png000644 001750 000144 00000004154 13145236450 022202 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs >˥tEXtSoftwarewww.inkscape.org<IDATh{LTw?af2̨ + v[unYdhcmU͚&Zb51}Ɋ(.( s`1Tt/{9]x'? 3= }@'S3O=0;+0 H>T+"hl^[8d`;3>Dfg~ ӆP yi~;U7G\L.+ai7dF'&9IIɫưn`3+Px x?]NInkyσ$I|m.^eڣX'&fA:#+W&& :ΟGlSBSq]VFww%%ul:~*+ə˜9&Qa Uhjzlv23EV0cFӧ !I``6O&*j2񁈢n)֎,`C46v=իDD6m f::J`} jrssMZ[{˜8qSBq:%zz), 1p~~*\͒%Qnw~ r;djhwhDF|y4(+kGUԴhT-TV6_)!}}AO]q|s @ jcc;1 TUxNl`(N(.e˖STWrR GR ,Ѥ dNrs#5 ("6%G~~}W5̾v7/rsPWȥW'#¾}YL~zLl۶Z( 7R PZ@BB0$8jOp8$njf8Xظqٳj47ws| Vk1G.j !5K :^'=Bxc^:'g.pvl23۝Jx˹s523Ey Vɉ7aݺ$&a0hX.AuwT|y1|I_;Qw_?ʕGF "zŇɤ_o/DyQ{$0kV(Gג5T{"" g4jjE6>d:jb >|tYewHkU(&׫ۣ>իArAm琻}J@6<@\ A`p (0~GNfO^^9m|E j4N q':-̛Qb waz>vmjꦢs97ʹ̀bטIQ6o˦MIL%z0'}"" ̙΁pMƎI )Ē%QVƂJvN{WRL%KGo^ُ`A$ӧ}r 5A7 {fMuYv̟vJ:`tun6X ); EA@|'̙ie>7&Iqp)sa5ܟ* w^)| OhW Ull8 &|(9_ֿ8jw`g% i/ L$(=<χ̚M߽$FHO8Sd0'~i 2(RJC$pxWPJN|KF^ ,y# p`ڵ+Wi{E L)f8n@0 ( k~F4н"0` À x<-,obia@u(R(i;C5 |,,;fԊs>F2<Ͽjfk@)u*7|:SQ! -]H TVVs|iva惿pGo0X'Ȧ _d̙3E9(4GF",PRRBJJJ )X,<ʕWua\g[ylݺu;M<?S[[묯_|ĉ YYsXYDq<22O4-pBQBhm ky|uaٲxTn/}@`ŊiG v5Lw 7n !|< %;aߏZ֓Nx[[[_u}3q-zyy\(8z}HWWkY֏M|~:zΝ;?O>v#GV7bAE 08Byyo)**KJJXӉKF@UUƑh4<c~J)GUU> 8)cm?z àI{wvaGEEt:122SN[po\effH)~>`qF( l^W$ mmmhjj(+W/ ԩShnnB!Fߎ7n ^ 05'mvO(A]}1RضMҵ͜rJ\ h;wi>S`]5o~cYF !hoo_{x<pzvvܛ%d)33E'!naX{AA-[6󝪪*6<$HNr0C<(Eyyy$Ɍi0M~?lF(˲zg}xRtHĪfϞr=}biC<|PYSW!͝.^\Ɵ;wz[ >ƽGMELkiiyKQ&P 0_)1TU햖VŲ+@Nʕ##@UU'OR._ Jū]mfrٲrg~~>a|)TMK)p9eÌis\ Tax 'm,ېH$8%K,DС!?H*뺎ޱ ǃ^@ ɔfRʉZJX.:bB ҃ɱq:5Bplzu;u]c<Z:YԤy^/bE/_.$Md߾}JssCQ`Gf̘wuug2; +; ^STTDTUE8apo g8Ynn7ވqSuJXbקk3ol2ղ,"˲LӜF6-Zp\# #Bl /`<`0h?cH-K) wR܍)>MϞ=@9,k ȃ^4]]]$n>o0~omSUd###Roo/FTU}uTnY={mیm;{Y!Ky\d H)$`,A$IENDB`qmapshack-1.10.0/src/icons/48x48/EditDetails.png000644 001750 000144 00000004737 13145236341 022341 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs itEXtSoftwarewww.inkscape.org< \IDATh}PU?•AQ@]SQPUk)Ōs]["56tl[٩flD{vF4\h5%M-"3 P^rw\\wٝ{Μ<=9įEEEIfަOiziK_7C0s$5אTU9FMʶmtfÆbh8.RSs裣U0`@g}tcD #I畆6cCiw9ƘH6UV:%$gϏ$%Ű|y">>M:}wI6rPuǎڵ}mB~^k'sֺMg͚n/.͒ز%\qoeJ0cpW9j' @9s| 2sǜ>}E}Nk_Цy!膕ԋ*Fwmv%K`~,Z[=CzzK~j>` Z+@dܲ?j>z0&詧6ЫWV=ܪ}}bm*m>Vf%J5` ={q/@'ۭ[9s c` +^pK(`(y5".80Z}F)?ԋ9rg>}x.\@{3lXX'`M]_-NС]Y.**p, /gblƣIwȴK~.'_}'ꉻG#FDcǓ&յդIVM1 = nxaZv\$1q$#Fmڷ7h Fb%qc1H <ᇓ򠼼1cRw_IJecm-u…[>ukk "DƘ:0Gyxx".n%YY'0|x8|0O٨|bEEddBօ>|ZbT#Nk1fc}!3dI'wl^^Ve˲؛g5DDX !,XON3{|jY^D̴! Ic%UBBlF|}kUvyeUU9Zu*|qLՈy,DU|$}~-&Ak<0jTg֭ᅯswPZZ֌s+J/H㨟 kAV1PIN,Z7̆Ox"M%r\(,<Ni† ֈȫM2u%I~lJizXPVV{x,*+ 6]ЋNLLg itS;vo=ɾ}'ض-/ph=vu 8uDoRc~*gEbFYY׊Y:׵ &4I8.Ut*;sz==/l?\k.FEa{S H :Ezz|R@vi-F߾ugxzlY"#:0 =zP0fzx$.(* /,U_/ _] ،1^&ðJ>`$̏Gc̢[&1 cށjX͑:|i"ԟ`4 lo,34$~NHۯIҦ,$5F5E;[' %nkBakD`y{]99%oI6G,{x(@CҘ"$}S6d|6})ib[ss ;Z%iF[rvD4b[sj$ضwRwJښO!ik]bRw oAG!K#$͖'&sRxtIENDB`qmapshack-1.10.0/src/icons/48x48/Start.png000644 001750 000144 00000002277 13145236437 021246 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs=tEXtSoftwarewww.inkscape.org<QͲ,yB4Y&`gYȦ, sfV=4Q4^cXՀK y F X^Ƿpu'\\ɵEr2`Ta"o"Of`2t7~fo$~Zr0U5x G#`rȡ#wa ~1:}+`Rq,K)vcT0a@ǃ m$jcl"M4e̮HI 6!3U_,3,D}`aĀpd&$[x(4=ǂt7~!E]$ .%=>:lRY qdjm]Q :/5r8r GБ"^K12D8I=;3Z |ElM&~V/O钭85dWDU#[7Fk4qNfY cb?BE;,Ǿ,  p_fBA+8JZ2k!$=N E65r3%)W-5h8!n/j@hX*O%MWUp-F]j*M ؜ƏD%cƤ O*%YCcN j'S"A/g3 +IENDB`qmapshack-1.10.0/src/icons/48x48/MimeRMAP.png000644 001750 000144 00000006115 13145236364 021512 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org< IDATh{P?~.,P(bMB% jcKZdh&qbFLti1P1hRDEP.c/Bә֙~gvs9s] dR-A 3?1l"/30^/;_He}3~9.w]AA-T}C[GK&?-k5PW:mjw@0 h{*>؂#yxbT*v @w(mRI0!Wxɽq tiP+hQDENo'4t4TL|X<^#kz*1 t% 8W, =QI0y4^Ffl&.bE<垔73ȫʳk\*''yu l"*:pb14hlϦQPpwRA.3:h4Ǟ>6?KJ=+E0m4з %;r7qjt*'3OdqlY̘i!'b9x dM :v-Y[ɫʣ/VS)>H\v㷜XqDǦەY`*Ì8̳ǞhץL*ԍSq *+h0t`e ^s/U).aFkυ u{nVǯvhDG ,%%%H%#؈s1O/.Ȥ2h|ʛʹr R_7_TT~VoX0 qdu2_>%SL%#СQ)TU3B1؂C3^ @{O;$Pz*7lCc58j-},X)kj%8LPQXAG\H%kJCȫ&%%t;zz{ɞMLp 2w*+<.UT0^iC95()YD[Q~JM[ =lf_C@8!UT>*~;t rP\W 7waLj 'ByS9J1cvKM677|6~7?FaBq3> l?݊m/WN\=AʨZc$H  {I#>46yζyШk2,Q(5wm7iq7z*` /vGjt obd"t>S{F| ti&@ 2fajf34͕6EZ^Gҩ_P.>4^7nT4WcV[͎9;,wɚw`zt]hY 2CC4%] U(5 HxzvS 6L`wlŸN U+; *!LRMPSʜW;l]Θ1kn,5/ɪ*5 :1l&.'2׆g@Ȥ2 gE&طcihhQcks_s*3+j`I+cWN:y@ꟹuϊva(<s&m@2)Rvͅo0>֮Vxub\\Ӈ IQI~@2>t9{|XTd{سt 耳OG ?}пZYNjt)UvKQ{I'uz-gNduP(=$F&h"ul; n+Z{ry^:XBHO`턵VrYYbK43j&Oyr@}} 3qP}\{L Uf}36߲w`oFᡠ+Է̻`>[{qzW? ?7?nu?%ԴPzT^/Ylə3H%RZZ9~ @Z|[4J  ca7FRaŦN['Ň#A¡ˇDȥrƅafS6PctihGJǫVbLt;9Q l@R9N5|84S7NYQ@hvÅfwKw87Ɉ͠YLN\=A [%\kƜas䩘0 &n?ގC񺂀(YD\Hw` сYj\oԓI]ΡK8|0,ot*+VHLd_;)P&`s2^)ܪ\qMt;w'eT Ǫa(Gܭ~f2uc"nc-\hKvawK$v[1 &qΈ@oc5+>&5kO_l3/^^comxbP5zW4.2|xsz笶&٣Ncٜ 7%%u, Ϗ:Μ jII5_ǸqJ~[l puudDF*x'T-[wĬVߞ5knn8p3GаF `""l/Lő>{gN0kƢT`ѢkW)/\̡CZhp{;N׍ͭ7mRvYj`:mYf= .!7Ӧ=яO?M!'Ҙ2L&Ly0Y)8X.|W]Oe VY\lDd2f7IIACR#GE򡡡 n =}˗' `F aErr!)){j/"boQVVOnnnG@'?xfx_='ŕwO`$?\] #wewV  "Ə%8X)D̛kIS{}7~MtFԤӮ>=iwk3 Nt]E ?̬IB`;qäCx0~/yyg"PSJ`dd|ɜ9ٽB.s+VLYO`ʟtnRSP;y!U EEOMM+֭.k\"< %++fPяp||HL k?DcƬ^(z`7Oϛ5@rr]}f#o(nn@`-ގ& qqCٸ1^? B=5m\P-;m-"#GzYr[9"B>ݫܚG͙LRRP)ު":fvP}};8Йx**pd1srNPYyUsز;Q(\>}sUoX]ZZcdeţR)?7hlk_J2zj]]rgj-;v\mf3>NDp^m fHkK_Jg8Tb0)(( P(\̚eS(\ϟŦMSB}"߿?vTW9~beSz{ꑐ05kb3u=a?_KEEe F~LQn D>=Wu:صRUOR[q>l4}_hnFE`@}xoijҰqc8 (-##KV,ڵ6/dɒ{ۮTB7RJsGڵVd2)Jgg)^^2F#/7#6̜PcKL7J!}z0[8~ܺӘg=NL]y`v4.}IENDB`qmapshack-1.10.0/src/icons/48x48/SelectColor.png000644 001750 000144 00000005015 13145236427 022357 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs  JmtEXtSoftwarewww.inkscape.org< IDATh{ŕADT"uY]1H Z*jDFD7(oL͖F1 k*$$ftY#GD XuT>aa{][5U}{9}z"' ?b >kXEQƇM'{DQ:g>B,@<suЄ XDQM aN\q;~E@JHWoRSxO0o{rߏIdgc|71wixcPNmowe6cZH'1r\O@a CȬ*n ǐ>T|K] O%Nt5en4Nc83̭bvX[؞3b!3@4 ]L"k; \l&gǴ@(88) &gIž?՘LN' Ał&-/lGZlkӉ&Zv~N;u7V1jwO`'J)-Zw>)H|JK=Ϛ0jF֭Ҳj4&pba9dnr>V,\̩SHxQ ee{U`_>Es0* MgI];:ʗZѣEn^?壩8I5m7|o.^HI6Mwֈݲ=±v4~~ƤY|[zFQ\G[G vnP8CeرzmdI%B蛡"KMlcjk}X`Gӧ5m>7& dg&+cֺcJ͜H&۲yk[;w᭷ Sg%`L1 Qlo^_ﭺ:;7m2NQU'uv44X]jkmx%\x#Z44pEy p`M'^wB`(A|}#GN~[YSc]^qcD| c wX1@[,eBDjBZ_>Fp{Gp#nvBVN㸤>VB<iB`'(%!p+%ܡshⴘ+ߙEm屜s8?k#VIá%hMߤ~M/=F҂kG0eXy_\m]DD?DMX= Hx00-hcl/<=dU~_3RRBpsჹ*2넴 l$;KD8✃Og lXtyDC7%/us;!+ۏPՖ.fGׇ/rx!^ l),<3ws Rw?+k "&Lv4C.-Bv\5_ՇOURKt,Ⱦ5-{ vސ_Si-<OGfzWw  nI ޺Mo+zczLgor;A ЎPv(~ccWNcc]iɑbx¤:R<\[vfXW^} +~_Nz4d.Pz~Q0"?&Oh„l:{w:W|y4JvPW;qE){c\R_'^!ߋA*2D'j<>M1gӓIv/J*x^Nz^;Dq[CՐ 1_Ll©]yJg ayd?+8PE {D7>lcS➘4t#}(P (~AUɡQHn6@5|磃#҇8kIENDB`qmapshack-1.10.0/src/icons/48x48/DatabaseSetup.png000644 001750 000144 00000006767 13145236334 022702 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYst"btEXtSoftwarewww.inkscape.org< tIDAThkpו{@C$("6@~+pz?( &L%[UĠƻok;ob FҼHwU]3={szS_<.:`6P xt ԸN#/r@f5smS;}T} |#hgW;PDpApVV`3,H,ؘbYTT(.΢8 rsݸzBP 14{.]>{勞ϟL83C68Ü99Z%KCuu.2)%={w9ѣ J;$r~_cV r'qLvA," twz}w)nK X/ٶ[ǵ=2gbCJ…TUͦn($ 7]W 5RJFioɓw \ ?`heH4-ֶ$j, 7Mvv*YY)@UuA0CCAtwbW6tΟ?۱m577 9UwWCd32f r7ر$ynS#ʦiʑ#GHKKC3ࡇv=B%!vPc8ZOz;6n2,3& yyy9>|1N`¥KΆ}<&ƸƍJ)[ 81q.F/'1K]W))ɢ(\wRHIp ҍiڄBx0>&B5f-|!jk[8v.Μ饹yPd\93>"Gp ϓ@f?L9x œ;߄B>PPR GUUi\.025 ぉ 3"ǣgoeaYRN6=MӰ,+}ٲeTTT`Y<ܻ DsٍGɤ!dtPPPSO=oHb(( 0008ȑ#TTT*EEEg{#|{0oc@Z0*kF r˅RcaA)06…s)=JOO@@ 1WqN8?Sԇ8A.`ƍOW~RJ[cZU:y?0/"$5m( p8bt]' ;;`0ȦMba墬Ç[?!4a0++rSM6o>q5,dYzlTUɠ:> .W̓47rw"ODJ_뮃J) !y!MXJJ?]hZ~2::{/TW2/xdD)2 U˵@ZzNca6{xQ0, 5 /,<832ƹ /0nݷo?\~F' ^ZZxq g7>n֦&??o7D\.BЏs.U)4^EQ֭R+!6wIOxAu~-DJɅ ؽ{wŋ)((`׮]B!H)0M4qIU7)RʯSRʣ6lllpСBQ8qǏcYxm:::ܮ˂-[]hY0&UȅbPSJ7[c։,>۶cL`K/UU)//\/--C߿?au@+pa$h[3BUUU}GGGB$J~)m)H\BoM(8vh+vrĴLB4B4Ν3`--jEQys$t{~ 8gSxSY:k5O墺UVt҄P^N.m޼~(]8R{WQI<7SRͷIaa:99wdN>''g{!9gljQC6Ra0 # <쳾);`%j0g㿭Xwӄ?k0yr,r0ci0 ~|dDzzu߀Xq"].>ITBRW"z\^P@ hqb#S t AN($uƖA~|G3UnsM} *IENDB`qmapshack-1.10.0/src/icons/48x48/WaypointOn.png000644 001750 000144 00000003422 13145236460 022245 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs` tEXtSoftwarewww.inkscape.org<IDATh͙olUg?SJia k]˶,Kl_fxX/$U5K7tXtaB7d:9Zfn m79wmo{)MNy<Q pcpehw%G\?&X!d$Xj'~+̆L."ী"ڡth|as@eؚ'g*f[<D`6:(T ͳS c9-OX,.υ/ 3gDXr8:ZK.Ի~u2 TnHs|-= G'I ) qwd'cNYV{냷r&-f92>4HZ!iPכ]yuœ=I5 ӈ7p32ۏm7O^Ycff ̫y[)M;2C ZB2Ȭ$Gg!ìpi箜hL(&e#Gߏ|w7pu 0! b da ~9 6,N 8O!p,j#P@YQYdŕԗ;$wB:TZlu,2تV`T"ϵFBf7=$8S@o$ΛuذvC|?ffveʛ}H:}eJqsMΙ39\ʼn-'Ң11 Plаo/*'X\sX]7*+*ð \ B?nlԉ' k7`80G}9+C3;N[wdI-B]-96pI/nŢ bc5\׌h0œCj%=yޤ$Mz^pw:rIoғM{ 8dGw aˇ}t83k 윳׷o[֒-'Ex:^X|l' #2o#+#",ph!·Ԩ8p&ڹ?1w2› 8|R:vp'25z / ƯnF+%b"OL]I\ޗD\O*!>i*~fȪkÑ<2Os]%.&0sx9w8dQOaUR_3t>\z(%ǐ"ONu"S87mAX^548[ /'O^TԀѯ`/Ns E}*z?)!l{Xy%';gonKաDT3! 7L]oJ'V cXX]f@ |(coN:K^Ľ=^G4]]xTŮ=}oZao]xPѹN-q >[PU_ 76IENDB`qmapshack-1.10.0/src/icons/48x48/PrintSave.png000644 001750 000144 00000002010 13145236403 022036 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs\:tEXtSoftwarewww.inkscape.org<IDATh_hSW?ޛDKl-Ed$8&{qNNFŇ! 6< ܋O(ʆvFVBI=hcr*@ w=wN~̃[$\[T`߾\YKIm yC#o:#o:#o^xuV&T꼫JW٩P*ܺBLLl<_Y1vO,Oˮ] ;{w^Nca!W-OMC#o/sjyrrĥ#gm`R[{~.xnbBwdlhgu> Xss5=-pϢQ R{ww(G#d/dog)[D)i7^Fuyc_L BS^a&ԔonzPTվ`Z˂^^>մc~~9b+45IN߾eZ9tҚ‰C}c>0V,?@&d8#b#m0 QQ3l+{B !wtݗ=-hG/hb}{L *x!ݳ@=o@@d+麓RVIENDB`qmapshack-1.10.0/src/icons/48x48/ArrowDef.png000644 001750 000144 00000006527 13145236313 021655 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org< IDAThYkpוLwHF#@l  +l6@PqY2Ə5UTC1`2` B1V! 4#i4~!#c<s9}>}HtPQwP!ļSȐ$i$I)N3 YVVV7HO.EQ%IZq 0 KI' >/\ޞZ҇,JKK'-Cpӊ\0@ @o__/p8썍?|'Mzrnv}zΝ;{Dl6(E9q0(ʎu]_|0}6-iӦ~_zdp>FEǍ'rxN(.;vlҥKGtuueB~ؑ@vغrJ'qxzCPϙ={HdHO>$~esɒ%NUUyX,V |'fGAAŋ; @kk+aѶӂ |AcxϘ1c&^WWoޓH$V$mM"L[0hOAu}ŋ9󥬬 rGGuK"z#G$ԟ^/]F4]L^tiǵ/ܤIl'O8BΞ=k}=NSrMMMo.Hn7YP!$ެ11MSNý_}/d VI X,{p8~cYV)dĈyXiWSJeff*@)Tdw]|y0)U3/CEGKKˏ4Msn[ [psP$M ~_t8*c Ǐ,˚eى222(attt ##DMx绿kYUU-p8HyyvӬ.D%K8|Taǎx|4͇F ohhn; h4mتH$L$iB2<*I҆2;!Pmii1|ǷmqfΜ GwN~~ZOi?4o@,ks,ioxnGss3xxbHdʡCz d(R53Cf͚z(ɲ\;! lI KR (X`SmFCZYFʲ9sܩO' eYS@eY><L>]4 ---M^1"e}@4>OBz8~j޼y9w;lb[[0]% N(r'p{M ϙ3gtiiX 9sF64 +W\B]vO$+16C4a%چ[l63 T1/myeYA8(PnoP__Ԝfwv (ߔBUU79u.YΝc|PJvv555a(++#?=zD"&ke뺾²PŘטG,;w3Lb!JYK-ZFGG4M(..G~H$^ B>S^^n{ *f۰nݺ1iRFZy^bصkWcl]4p8Nl6Www7/ WUy/Rژ1cǏw[<o#G:4cGk׮i'OaDȿ~-gUU-[p\2|L,Dss3DQDs:~4j(XU28;#-`pc/˲f'zYG)-pŮpaY"˲ɤ?eWO,UU4m-R 0w ` w=Gk}FT Xћ% 6mZ^^πF]@ZxJ醔 mU 68ϻï²ŋj0m1-| MYoU-! fx*K8ϝ &3x<kCwE@0 `ea9cLsB`Fi0-|v5CwTěŖEHm-Hm-A,vsq wڑZb:Ӄ֬uev64tpnRv2'|ݞ:o~w r? 0&_~)#)SJaz~QO`^/`LJW^麞=#`ժU}ڳZfAx}~*t5P= 'Wj$>/k17!n@I?lYB6ؐبlhRF-]Bl]HJ`Cv!S( e [Ȇv!Y(e/c6OmIENDB`qmapshack-1.10.0/src/icons/48x48/TextJustified.png000644 001750 000144 00000000553 13145236442 022733 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<IDAThڭ Al[EE,o/ŢE|G`ZڬV4hӁ\8 {=aOH<4rN7_~FtH$_Q+"ϒculh!/tb1v6G[" Lr "~{Z" |~sC_+%4 ( = 3A_i`V֧,"hh" ;@g) ! ,Ӕ1'UTU`6` h&¿QUa[-K)mC)Ӎ{Ξr%6hoq|-S-=iʐiYTb_(Ƨ*lߟ̙3in!;EF5:}>N*+[8~Ouu>U!4sWeMM0ƍG$h&&@{4idWw rW!T8BR2k( Mq#ں@SS'G^С 47Za^I0Ujdf:;VrsKnOn( ZNlDU"0ׯ/T}>];z!Ǐ}Yt cƤ*[ʑ#u~9!t&1s(^|6^z铈`'O>9+k44DL:;ø\V22dd8p8wXtw{`A. ^|>0u;vF!֭_`R ;׬,'YYNC @$.]:5Kyr 0 SULu͚y]qhsr@991]+V죬9.`0ΝlppLZܕ44QUرignp$ Q_Aiimm!UTUOAk/Yb] u ]7HK1qb&Gv'|:mmA**ZaHFpB!ܰᇌՔ6QUu&)q8pv#S6- '0uf# 4Fp#G|Pc(+k0aHKQPS;V*+[X#P?{ٳ=kii6,%K̙V0-|}/]S?j/dA]Oin 4%~ P"rĞ=X I2$5Նefѡz9}/wo5iǿШ<=&???x!ʚ9u?֋ŢEQef*ε_TU0aBVeӦ/eccg|GxTcGw4o<l̟ N`ca Y֯/Kuu0AJaìdg81-:ul*qWXYR2_'袼?~7ժv'3|qHsI!'')1%A5172#o0$)%ꫯ)`mN){»VSou6Qfxn؄G,UߞԩYetWwt\ࣴ'WQU_ݮ#8Id3iR&99\VPmk ̙VNhܹgh5yiJݻee9E&e}?ثcHqo}io`׮3\jUK箻Fssu+E, ÑOGuB0@nw24D3F2ckI|uJtKä́fe)@&.^E}&5KB{ժ#vǼeu}&(LS&;;:yuu\V<7z\ΟogǎӬ^}zu)|33RSmF~~ W )OQQѪ)TU\ EXUӆ!]"srR np$(--AYUulnTTU7 Dt\G@"OFH2Mda&p>D%fq/ș@qBX*-Ԁ8 sJ '4jIENDB`qmapshack-1.10.0/src/icons/48x48/AddProject.png000644 001750 000144 00000002010 13145236307 022145 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs K4tEXtSoftwarewww.inkscape.org<IDAThOhel6%bBֿhl EРE<ؓPiSтE ZcRIziTmmMfvg4@0 ;o 5 uj.لiRϚJȤuY46f@,xY&(TZJ׸T:\Rd^nYkȑkgJZ46f2i֔25rK*R,7iыln_}2 螆ƒdɿ[>my+K$06[*!8mhdv5X& 蘇Pw6c^Uy`Z(3Z_S2.cDA9@7N_@؀x 1Iqc8I{#a'8HoT[(!Z5)paO+\ FULl8)6SK'<@f mǒ'N w5'=^XMx kOL )ta?;v`3D;qcLB_c|A8TI909xq!/DVqD~$R00bS&\F=3V ީaL#z4݄UhW:vK:•^qV7v4X$N֎Jض(,&$oa4OSXNq5 #QŇQ &ؾ>76׍(Nߘai\ř0@،Cx\Ws),)cvdO'GJؗKщ2xϸذPS4!E=wM?bW5Wϓ IENDB`qmapshack-1.10.0/src/icons/48x48/Area.png000644 001750 000144 00000005446 13145236313 021013 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs-- etEXtSoftwarewww.inkscape.org< IDATh{y>3\ zEe)^@M ZARނ0AԢUh0"5&Qj֒&ֺ1Ѡa.g3}Ф{ {{=oq.'"[(~~ޯR+~ sS!럤~S7}2D0]Dxq$qo*Z9qoºdԈ-\l@Q!Gi`638ᝃ'8'aStn-P&|x%>8geqW5f?}hDZ#oJ{),\a.EqsX<}͸F}3K36o'Ɓ,.[OF(Ò]'(?e3F/`q3oK3p)qV,g=\;qΧvf}OSH籠JZT.eW;X;7HߡBM T"NɐZL<; ?_frRZ:+KψZJ..̓J|GJ8O&>S,$=[&lDZ/mG8^:=ZT:Ǵ u }TSkQ)w KA h@_џ=:YN<3y Tj $Rю~g|t~k3qIERAm)^kuO$@fFKOqM#!uL'gH! XojOH܋K~;T^2_A¡Ĉj?ohj4g:QH:ԟ{򉪨g&2r&W4Jӻ?AaBIޅT״ 0݂TQHQIɏ'K*Z-jwmr,pPIJ1Ny]Xr{,x=3;'ɿʵ pdI$˞՛ 'RW£,jQ,z+FQq#.ʿn!LO°)yRWR8x Ϛq]S~Fܞ3t Uxk5%-C9ZM~|p< ~!u% ޡ2Ηqćeskq jKx(b$NbkR]2xw('^5TΓ>'c41 \N,Ms[YϤ3C=O2:J7,ƎQрvlOaRMYtTVa5&shq*3ZꄮQ-dhC)1@R}1rp띘\F؃GRvZ脮Kގ2)I7IU#ZZܓ:7{qBH>¹ؕ~I0JMyr6ܡbX$_]Tƀ:)xq|^375A:Ji/#ӼNX2>{(nI% ?NOb{ϐUUy]?a=Fz͸b4EϫQ.he경GfRl 6AJ@iuѷM]͸[">b@'MuBDTt6N-rԵ^,mq5]R2 oCOew$732ث\-][~$r0KD*ne-H݌Ya'Rhu}8πh4 H3swB2'Lh`^ I'W/MC .ɐ>|oiyv/,v6'8 Bj62L$Nx)3¯yRN[߭̿Lk1ͳU˜+y~fpӉ+ x 3&uBJ yҁni\0'Mm8"sHJ?f #Ͳ$/gpcJF,|H=BŹn)rKI)#XEDѰ|qJM]Xk4/>F9x%2˒|IeU v $-}8m8:?ѥ)yf܊j[oO{'q#goD^K[W^T:f@M^r=?Y^J4xtֵ9bMZJ i_WY6(oйyb<%SoqɱvL]y0$W;4wSFu 8$"Q<nh1HyZsTmi7ˇp~v*·h^[;lFTZBmVIENDB`qmapshack-1.10.0/src/icons/48x48/ActCycle.png000644 001750 000144 00000002775 13145236300 021630 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs 5tEXtSoftwarewww.inkscape.org<zIDAThmU3"7P]y15`*($j"Q' mݖ"ִ& 1[ bM˛U-/ غvyfٖD??s=/KtAt1#ߺ\MO`#06@)!]@CoXJ)~͜˸t,fϔv0 PNYY6Qً  .?1)̀uh0lm#X% $f?c 5i6 -xC$϶8夗 ɗHs[Ffhlf}}|P }}lZĺjq۩bₙhcG yaqsI/$iB vB,$';V *VvlÒ\F\C~BahPWbnqq)o&]w,;NiƢLt7!3oF«qG3.fb/&iw @|+Ew u-[;^݃H8<ֺmytO%&_Ϡ=Uҋ+yV-q1]/|]jЃ? N\C)o璘U#èn QيVees>K^Exa MРt.埨/tj${sy.UF'&&]57oc^;d[*^pz> u9 a!IeGt> 8:CTdH_)U5om $z|[#o'KnbCUd'.?r4p#3d^彸d $H#_8CX\U&9eUeWUL⪌<*hdVԛ Y"{OAŔΗ4W5zE 2ƣy6OMЛ1gjiAAVL,eDof9۸U5}Wu$3t F3Qn* f -j7;[8yc? C2KNlR,V`P [o+l-]zh9M-,~Dz@K|S >5Ϛnͺr:@ycUЂy\Ǔ$k)MEHC8g|ap+x#d%b"*ۛfЃC$dW:蠃_VovHIENDB`qmapshack-1.10.0/src/icons/48x48/PointAdd.png000644 001750 000144 00000001401 13145236400 021625 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<~IDAThKhQPDl(X(ucG إ.ܹ$iݨ \H .|v#"T""5.ڤ̘L'^̽'gr' ˜bC)n̊U9DPhPzL0Mh45oz_i q% Mc'R<-tg@\}Btyâ/Ѐij@n:ծ<灃A΋ڭ^yS\"9ǫr| L0M02Ŀ₢UT@='Y8"ɴBvjAGM+u@ WK|AAeբ F&8u rgomLe+Έ/}] RETY/1q6Yhm8s!aG?@můNuţƿAdl#oECu&GoIx9fȲ6Q`(|)+[K;NW9m {bًz94S&2zΒڟf3d%zH귊2<.)-řZcZ=,s' fZ.Sgo/AmAf¿J']@3x B$|ΐyHEIENDB`qmapshack-1.10.0/src/icons/48x48/AddWpt.png000644 001750 000144 00000002123 13145236311 021311 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYsCtEXtSoftwarewww.inkscape.org<IDAThՙMH\WO12FF Z%U6YlWE$,B!.+YhMHhK-4@"6iMH3c}׹>wx<;s 22!ݕ xV>8tK _:r3jy $|@CcM) Hv+>6ј}ojnޖ^7lYy*@6_r1@0+S'pxAfl0+ 6Aw,=8ked/Sfm +ks=0|+0'pVT)Y6C/o:$ 3\Bug˧ʔP)& c,*gs=VE@+,o >A)Z`r& \&6 ty 5ۓ0Љ_Bu0ys92*,.5lAvga,8j;;, !z5Z=iT|-6n#מVMAnfWv![|w aK/@BWۺ P3ռ p gcK*h90\=Uv/ |%~WhC:(XYbY&F,Q^3ЈNtπF,+E4)d c]6}Y3p*#FtXD$ ,9_,^J;vxdt/1yq pFɋLe#'ihI ų,O!f*¯x@bտC 2O ~K?@w4@7*ϖC=X>am!4@+0W6Nl%5#s>rIENDB`qmapshack-1.10.0/src/icons/48x48/Off.png000644 001750 000144 00000003123 13145236372 020650 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYspto:tEXtSoftwarewww.inkscape.org<IDAThZ]H]~fgl]11"(P @"e.Z C, .JbAL@@d I>R3wu(囝9Aݞ<Ι3gޑXn⯁ f23P^A޽[2K4;OBi%%8 E&x xL:r{ ׬Ih=Ihɵ0p \yv69EA~=?j*ce_L/_B]R"E `Ǵ@@QLc\{7p^K sx 0\3h-|241( +Y}t"ܽKh@k@U\L ONJS"GT0lRЀ`!sGDqGw"/˃ XVUYJ 1ma~2z9554Ag@A{81Y{Ll.8uRRX#%' NfA|/-,R*x=# q"!"Iٳ@$"sr s P Y37oƯRAx[[lq (m#nY>Sbl="rʂǀ|fb-Yko]FX84iLO#4<,1rǀ%!4:*L4o*1)r-L*"33D.FC!r֨K "bi)NYA,7@hlt1n8'`>25[Ab^. "Ǻ+l rycoUEE7|9GMM@-ҵPhhH0XCsh9LY,pο􄆇1UQ[D( r"njF uuWU &ߜѳ;@Rӫ :A.t⟴4>gwu=|H<3HpA9HdeaD 1jH(4 ',fn_).߸d2$J@T0>~[s<--=( EjIۈIO}sXV+'UϜAx|H)Xcs3k%J1ۡرCt|Cr-plp76Eѐ}@oRd ׇ Yt AR{}uL-I;%J,vDӧEE8 ŋ7q:%-Vcٹs[ʅDn_p좿ѫVA4 dD"uvb5',R(4޿|7n$n^YJrDT*df6@)`aDHdFo?`#"IENDB`qmapshack-1.10.0/src/icons/48x48/MimeTMS.png000644 001750 000144 00000004261 13145236365 021417 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs5tEXtSoftwarewww.inkscape.org<.IDATh{lTNKl bK"߀4>TcB *1j4M-%"QV5Vig:g irdZ{ַԳ6y`!Ђ@zz[yU>yR;wrt~r?ԩ* ,]j0d]$oI?>hC hi_7߄+!+ bc!.,x8t(}`r^]vu=j\s ڵKKG';M{;?[oU%%yy G 0~7 Zͦ&9R 0>̛W]}&o׊Z8qJK%ST WڭF+ :s 쯿`سGQ)-`DĆ 4 LzYFA%&b;pղ/6nT nc=΅*?v  S=n\P122'վ:p]'N|ɽ^C,^xkk si7:m"\0FN.*Q9s?,CRSH5iRik߻WB$TW矉bNW#HIRh> elUlzr%KO!.kg AEEdE \,xj^ع3H^? ИݬY,e_zItvB|hz**4٣*ERl*vZ[+QB-(+؅*\}_y^8|eRœ-XzӋQ놆&MMbTEBN| k*m@Aª>/7f,4"#x^ r HIVM7V#22DKsb:b}&./r"&Fv =hʮ_jJ@anMqv:| Sե2.Ք֪kj7P_X V(MJ"un};¨ HI%%̙nxKa!<]"tB-no\Ҧ"g%zaQ 1`D|eUoQJJ1|FRy=xJED{Ő»Z,*R$9tuj[Br1*FtݭPqSד;v >(4bGщm]Z.'+K7.՝ * Ԉ띳ٺ՟TWo*WTl٢[?rOw6|m6MNdg%ڪOinAՙx쫓m ͸qV}6]b]-3a\r d}Vr01H]jL[)/|Yw+\yTC/\::XPSumabp PD1CUBd&EuKJ_)KKuPgS1>y&<2g.憮/6'yyZ5_gV{<ݬ-]ꓖkݻ]=5DC_ a % T Z 'sUIENDB`qmapshack-1.10.0/src/icons/48x48/Zoom.png000644 001750 000144 00000003260 13145236462 021064 0ustar00oeichlerxusers000000 000000 PNG  IHDR00WsBIT|d pHYs&:4tEXtSoftwarewww.inkscape.org<-IDAThkUߙmmmBmft{ôD`D%*@"cbh/DiPEhն[]B/?xge>ؑ)vULAA<֒ W(klpH Gc@k2_[2O}bi[*J*h Aoʤ*=㴝⮊˙Kj$\"M)޿el%2Oq|/\g&!_ h:mmgi]pKēi:$,br- eF++~ʸjULc)Wb*ނgxb:Uq؀u{~R cjf* "TF>8B~8&2]5P rrҁN8pcH\0"D4&Q^ճbND:y:=+ZHNjqp^^kw!--=u5Ÿq?4-ehwӾi_ϗ*B-q_>A %/j*eXQúZz\Ļ`A~.q7*x2%iXČʴN5O;.66"`mESHw"nz,tiDxP®oK0˷w_疢'Y| {24F|(%pFZ1=/~LŹ-MT]7ƔU؆e[,ZIJ9ԫ6<g@`-2Ii5QAwFqIN:3D<G@McDg]Nez# 7N40D-3(r-Nqi\uEumwIgX~]["6O EٚMĝ51a`lb|9 JR-#(|2"㗢;gb1_H+2"S*݁oAD W@|Uya>)1Т l>?|bЃ7R @{08"f#| DaX,jzJDnt,)1,sц'ϷB>]i-B3cwarL(Vw"\ EqZN щ Nv! XNď;J~t S?"k{y{ k|, BnM=IENDB`qmapshack-1.10.0/src/icons/Move.svg000644 001750 000144 00000007062 12455143304 020261 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Zoom.svg000644 001750 000144 00000005104 12574471525 020305 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Bubble.svg000644 001750 000144 00000006163 12517347554 020563 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToggleDatabase.svg000644 001750 000144 00000016655 13203507441 022227 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Waypoint.svg000644 001750 000144 00000004773 12727447634 021212 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextCenter.svg000644 001750 000144 00000006550 12455143304 021441 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SelectExactArea.svg000644 001750 000144 00000013423 12705713524 022353 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SortName.svg000644 001750 000144 00000005465 12745644236 021124 0ustar00oeichlerxusers000000 000000 image/svg+xml A Z qmapshack-1.10.0/src/icons/LineWidthDef.svg000644 001750 000144 00000014641 12705713524 021667 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AreaMove.svg000644 001750 000144 00000027176 12455143304 021062 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/LineMove.svg000644 001750 000144 00000013462 12455143304 021072 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/EditText.svg000644 001750 000144 00000013752 12455143304 021110 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Paste.svg000644 001750 000144 00000005451 12455143304 020427 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/DeleteMultiple.svg000644 001750 000144 00000006651 12455143304 022274 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/RegularScreen.svg000644 001750 000144 00000013213 13146470074 022114 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextItalic.svg000644 001750 000144 00000004765 12455143304 021434 0ustar00oeichlerxusers000000 000000 image/svg+xml I qmapshack-1.10.0/src/icons/ActCable.svg000644 001750 000144 00000006121 12600710657 021007 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Limit.svg000644 001750 000144 00000011553 12705713524 020436 0ustar00oeichlerxusers000000 000000 image/svg+xml A qmapshack-1.10.0/src/icons/ActShip.svg000644 001750 000144 00000006252 12600710657 020711 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcDistance.svg000644 001750 000144 00000012235 13127442230 021653 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/FilterSubPt2Pt.svg000644 001750 000144 00000014017 13021756454 022150 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Reverse.svg000644 001750 000144 00000004704 12455143304 020766 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToolBarSetup.svg000644 001750 000144 00000017553 13126360003 021735 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SaveAllGIS.svg000644 001750 000144 00000010201 12455143304 021232 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/VrtBuilder.svg000644 001750 000144 00000130536 12464363774 021457 0ustar00oeichlerxusers000000 000000 image/svg+xml VRT qmapshack-1.10.0/src/icons/Redo.svg000644 001750 000144 00000004216 12455143304 020242 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WptMove.svg000644 001750 000144 00000013316 12455143304 020753 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Save.svg000644 001750 000144 00000007160 13146537127 020260 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActFoot.svg000644 001750 000144 00000007334 12600710657 020717 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Right.svg000644 001750 000144 00000005644 13145234010 020424 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ShowAll.svg000644 001750 000144 00000007412 12610212702 020713 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActAero.svg000644 001750 000144 00000014145 12600710657 020674 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/QmsProject.svg000644 001750 000144 00000010173 12455143304 021437 0ustar00oeichlerxusers000000 000000 image/svg+xml QMS qmapshack-1.10.0/src/icons/CSrcSlope.svg000644 001750 000144 00000006060 12627613666 021223 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Close.svg000644 001750 000144 00000005441 12455143304 020417 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddMapWorkspace.svg000644 001750 000144 00000011402 12455143304 022351 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WptProx.svg000644 001750 000144 00000011671 12455143304 020777 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToBottom.svg000644 001750 000144 00000006412 12455143304 021120 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SetupCoordFormat.svg000644 001750 000144 00000004615 12605134254 022615 0ustar00oeichlerxusers000000 000000 image/svg+xml N48..E012 qmapshack-1.10.0/src/icons/Apply.svg000644 001750 000144 00000013003 12455143304 020430 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeIMG.svg000644 001750 000144 00000121202 12455143304 020570 0ustar00oeichlerxusers000000 000000 image/svg+xml IMG qmapshack-1.10.0/src/icons/PointMove.svg000644 001750 000144 00000035562 13107537426 021310 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WaypointOn.svg000644 001750 000144 00000006471 12727447634 021504 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcCAD.svg000644 001750 000144 00000011747 12627613666 020540 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Cancel.svg000644 001750 000144 00000004374 12455143304 020543 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TrackOn.svg000644 001750 000144 00000016772 12727447634 020743 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Empty.svg000644 001750 000144 00000004465 12455143304 020455 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcEnergy.svg000644 001750 000144 00000025405 13140265126 021357 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcElevation.svg000644 001750 000144 00000004625 12627613666 022074 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/LoadGIS.svg000644 001750 000144 00000007154 12455143304 020577 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextBold.svg000644 001750 000144 00000004324 12455143304 021076 0ustar00oeichlerxusers000000 000000 image/svg+xml B qmapshack-1.10.0/src/icons/NoGo.svg000644 001750 000144 00000005227 12511447537 020226 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Down.svg000644 001750 000144 00000005640 12455143304 020262 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/A.svg000644 001750 000144 00000004215 12551744506 017540 0ustar00oeichlerxusers000000 000000 image/svg+xml A qmapshack-1.10.0/src/icons/GpxProject.svg000644 001750 000144 00000010211 12455143304 021426 0ustar00oeichlerxusers000000 000000 image/svg+xml GPX qmapshack-1.10.0/src/icons/CSrcSolid.svg000644 001750 000144 00000004570 12627613666 021217 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Opacity.svg000644 001750 000144 00000006471 12455143304 020766 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/FolderDEM.svg000644 001750 000144 00000004770 12505261066 021121 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Route.svg000644 001750 000144 00000006024 12727447634 020465 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PathGreen.svg000644 001750 000144 00000004725 12455143304 021233 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PointHide.svg000644 001750 000144 00000016155 12455143304 021241 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeWMTS.svg000644 001750 000144 00000125663 12455143304 020765 0ustar00oeichlerxusers000000 000000 image/svg+xml WMTS qmapshack-1.10.0/src/icons/CutMode1.svg000644 001750 000144 00000007263 13044557066 021010 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToTop.svg000644 001750 000144 00000006427 12455143304 020424 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActNone.svg000644 001750 000144 00000024577 13151740741 020716 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/000755 001750 000144 00000000000 13216664444 020673 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/waypoints/Start.svg000644 001750 000144 00000006607 13145236203 022507 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/2ndCategory.svg000644 001750 000144 00000007042 13057473631 023577 0ustar00oeichlerxusers000000 000000 image/svg+xml 2 qmapshack-1.10.0/src/icons/waypoints/BoxBlue.svg000644 001750 000144 00000005204 12455143304 022744 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/makeicons000755 001750 000144 00000000166 12374350216 022566 0ustar00oeichlerxusers000000 000000 #!/bin/bash for i in *.svg; do inkscape -D -w 32 -h 32 $i --export-png=32x32/`echo $i | sed -e 's/svg$/png/'`; done qmapshack-1.10.0/src/icons/waypoints/PinRed.svg000644 001750 000144 00000005713 12455143304 022572 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/CityCapitol.svg000644 001750 000144 00000004630 12556335125 023640 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/4thCategory.svg000644 001750 000144 00000007070 13057473631 023614 0ustar00oeichlerxusers000000 000000 image/svg+xml 4 qmapshack-1.10.0/src/icons/waypoints/Default.svg000644 001750 000144 00000006101 12455143304 022765 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/SlightLeft.svg000644 001750 000144 00000007163 13145235235 023461 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Generic.svg000644 001750 000144 00000005617 13057473631 023000 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Waypoint.svg000644 001750 000144 00000006600 12455143304 023217 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/CityLarge.svg000644 001750 000144 00000004643 12556335125 023303 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Straight.svg000644 001750 000144 00000006015 13057473631 023202 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Food.svg000644 001750 000144 00000006307 13057473631 022310 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Water.svg000644 001750 000144 00000007205 13057473631 022501 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/FlagRed.svg000644 001750 000144 00000005012 12455143304 022705 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Right.svg000644 001750 000144 00000005625 13057473631 022500 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/1stCategory.svg000644 001750 000144 00000010112 13057473631 023613 0ustar00oeichlerxusers000000 000000 image/svg+xml 1 qmapshack-1.10.0/src/icons/waypoints/Summit.svg000644 001750 000144 00000006104 13162217226 022663 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/DiamondBlue.svg000644 001750 000144 00000004067 12455143304 023575 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/End.svg000644 001750 000144 00000006620 13145236237 022122 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/SharpLeft.svg000644 001750 000144 00000007243 13145235502 023300 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/CityMedium.svg000644 001750 000144 00000004646 12556335125 023474 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/32x32/000755 001750 000144 00000000000 13216664444 021454 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/waypoints/32x32/4thCategory.png000644 001750 000144 00000002006 13162217235 024345 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs jR&tEXtSoftwarewww.inkscape.org<IDATX_hSW?IhMCv.5ʊڗR芌9{ك7Ň|'> Oe"t`StkMLب6]&MdNmMn !{9{wI|>.\NV<.28(pOo/]""ŢH0h3mssS\.ukybm6l""ӁBxrv;JCpǶ6aFw2 OyFN"ID&eeu'OD:;k'- \+k;/,Xof %欽E8yʶvÐ&&<19j͛8 >ttVXwFFB|G2qg.\6:e Ǐp(uqXÁ_[3@(T~n~sׯD$\h0DBvpEv^ƅhu5#.U9tk)PhL(.O׉|^dyYXL&#_Dp오s m0r=>IҢ7*^Vwg ڷYOOCu* /%d~PU}H + nb8~ Xl:ÇiFF8|bO<33CC*Z!{zyOyFK!x607AE v6#3gBэGݴ%0^w-]PUn"rDHvL&΁$'xKip:?n^j DƗv'JT2"DӒL鵴( 5YQJM$gw~[(pȞ,dMjQSIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Danger.png000644 001750 000144 00000001702 13162217237 023354 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs tEXtSoftwarewww.inkscape.org<?IDATXOSAOo j_to0&hB[ ¦&@(\JQHt1&&. b  B1qaQc- H=.F;Ɍ—ܙ{/3^w>8t6aZZӧG]=wueSoOa&IjG @jo'ttz@:R)4#aYѥ""߯]j_gd͑p^^N3xZZ$p 19~+)!wP@st;<,_#wKO'9B@kSUSsׯ@UUY W`Ѯ*:PWpK'IѮOEf퉍Kگv JLA..IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/SlightLeft.png000644 001750 000144 00000001714 13162217246 024224 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IIDATXŗQH]s̕-2.b7v"QDdU7W n`rDQPP]D2T(3+=on_9}s{y^@sDb%0'-BO$jZ'ĽMN@8 kրVkn(#a@^۷EȺu""Xf!?@08cDE3*֭"G\ Al6fhT$^vI2UӧU;~]X”=*x<>;K2~dw,:ڵNNIu?gCv+wv;r濚-CWa|>yN^ZZZݭh4uTU%Yi]SEEj=sF왴qcW<Hdu2 $ӔêTZ ~f::… PR1b<Ϫ} hhǏSnSS >FFx9xUߍc/fPP0=φx|{[hk\4Z[aKT.Z]߿8ymmX;8u}*zusS/55|X,6Qq}#pt|x"Б#? uoNн݂Aʕ~ \QEED< ~40j ]]gO9a$e*̧K<k`۶UK2$6+̛KXV3˿8y"ݾ-K}qiÆyJÇOe_joWRq̼ 458:fbhH LNNi&.JϨ&xmh 嗾dvv|@';{vN~:Q_kY4Ѯ 8z:ǶMNx#[ #ޮu06Ưlm]6(7&lM vcqzc7rr\ә)^RF2wJv PVvL&7_OFU47Ö-Yb1ir0FRIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Right.png000644 001750 000144 00000001150 13162217245 023225 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IDATX헽K#Q 3X,](SvjB+[aA,l,- K-bf\HY4)cv]w-&3}r~we }:-umT.>~2Fu$ToZT((tuZ8?Bhbbfb! !<bh6'hCQmmlڊ i̓p*J&&5?IggR6+Ov\R)Zzz\ZFFJ%8<8ɼgw&'?{4>&|IccDLO-GyHC`DY=( #'Ao/4z{ |xNN^,Z}a`g'4_Zk-@پ>˓&fnUT$P*W\}IJ#3w7BIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/PinBlue.png000644 001750 000144 00000001036 13162217244 023510 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  d_tEXtSoftwarewww.inkscape.org<IDATXֱkaOSjm!Cguf?YA : b%RQۂ r{}><6D.I,֮mb 8 n/T*G,/;e\QxJ po1Ѣp8PT`#l%xUP`j)qo?%&eIK E]b3fyph͉8Nx`*8F7oLOıAތcd'˙Аf ߾*+U oa/T ؔ} V þW-p?)seej8\Au`Mvm-u'j;FtIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/3rdCategory.png000644 001750 000144 00000002214 13162217235 024337 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs G6tEXtSoftwarewww.inkscape.org< IDATX[Hg9x4*!eJqbv-tP7^c0q%+ ovhY\UXbTZ;vsSxHEЙ?s>EKeٟEQq>)DJٲېu#5}(WP(Q!4ilerjR&$F:EBʝ:tt@fm33c qff| 4v*Uhn2g~؊^vFD"oZ-ܽ N׻vu(/sncpp֣w2x6%obbىSRSSHK[v|6'Szv+K3g,RYLJyYڵ~7`ٙ[$?@E?uu |Hn6͛l ?OPPbBQR`tʆ`9cyN^Vfaa>8:A* D伀E7D4> IIjjd.]#`'_CwHFo"[;"ZGT;#_cp0. `GYݭ< H011σ?ۣE{X='%} q8+aYGi6Wo{Y.aCoDr"@/(e679:9aK%l|,7RW`0`Se>1qzJiT8vQole(/EOSF)_p,>d*37IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Valley.png000644 001750 000144 00000001703 13162217250 023404 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs֕tEXtSoftwarewww.inkscape.org<@IDATX]HSaƟmg0g7^AwEEDЧ(t@n蝕BEa`Ԉ Lp1XC ӄ>0ԩY&<]Wy~Wo6$H!U b^_5䗡 RLE$c]Xox<(-u!\ϰXn/#11 |Avmh4C\`V-MocFU Hr[m5ey4- I67`|Y99w81@`6\<~nt3. ܻT;|tt7&&VVu56 ?a߾u iHK23< !!Ws]zCش)5)o)I6_BD;Ff>E@d:ǖ3:{Gim3Ӂ~|?$%ԂA.8x GqlߞyZ?%z+# 4GQQHܳЬL( B#skAI'O޴1Fc ˗B=`{] ^IVT ֧a5MXT^oe].$ *+[C'N8t\IBW< _bvяa4ɓNԼ~lY04Mca}r,EK~hQUFr bDQԘ+ <23ydа: &a?ѡqIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/1stCategory.png000644 001750 000144 00000001467 13162217234 024366 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs jR&tEXtSoftwarewww.inkscape.org<IDATXŗOKAI6XRCFZ! DTHKxl>]8;]x 0\H$^:jt N)  ++/{|p T$|y ߟ^;R GG/ev؀.m21j؈Q~zz7 nV' U]+h@@yr,ڈjCHnGrb0<`m ˏa6ύ\b R)u:h& MՕnp0*{{ r+(,/- { apP diA(Q $f<[J)F\<!v7tp)a/1)Z1IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/LeftFork.png000644 001750 000144 00000001403 13162217243 023663 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IDATXŗK#AM*x"z-,J x\+[[;Jۃh"!v~V`DNB^1l~3{ygAx=>u]̒dh%x=>?-~{|Hh""F P\\n˪ňimI*1􊻻47s tluupyi2]]prp}m" CQ,-i(@OiR55 1P6X[S@-8;·ðvvTi0= JYJ0>N,$I:H8|u||5 ϔ+\MuJohn#L^Pcc97cJGVZar׬,~w-RY)"&2=-Nicy*0#0#X2MɃ==j(~l_hhWm!1 VWV#UMZu@4 lݰvʅLS UUp rT--jd=P oWTfS`%Kp kNf, _jٲ*H{eϯE1љIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Sprint.png000644 001750 000144 00000002603 13162217246 023434 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N N+aotEXtSoftwarewww.inkscape.org<IDATXW[LTW]"5 j+!MHM͠ժhĴQÏ56ڹԚ`bZ+Z#Q$P#HmUD 8Q1:ÝsNǽwkUX:!qij4x`sjCcsbG[uzZ곻^`j`2% UU@e% @zZ*|9 $)ƴ?@O=[P!w&IOxdkjʕCh$Η$pVV73!a+)|͛w-"l޽ H2,U؆lZ˜1piXrq32Z`֬ALb uBL|z<>XyM2GG.'P]tßm6rʔF6bp2T|.v pe*GVq?Cmwp~6tCIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/PinRed.png000644 001750 000144 00000001041 13162217244 023327 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  ~tEXtSoftwarewww.inkscape.org<IDATXֿk`O{ЊVJgJBIn.BǺ88 :."8)"7XuQѫ"k{p4M H>MBBbp?xtv nYOA2ςce£ ΗUtESNE ,s1/>{ʋhf9>\LS%p$o% 6K("W~`ws[ހ1|eR>|#8^L8,r84epmD9zZ8̖ j&M,`k½Oկ`iSeV*q6XV.p ߥɪHj8\Aǥwjp 1W~^7.a.etX5IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/CitySmall.png000644 001750 000144 00000000516 13162217237 024057 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX1 @_I'vbzE/!L$ U,k7"([+fc̟Nc&iR:ǼX}Y)_*~4E ت>?HS6ځ"tD $ oBT9y EA c-{ރ~M$Y{JU&>tc~ES6IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/SharpRight.png000644 001750 000144 00000001660 13162217246 024232 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<-IDATXŗOHq?3۶ZȺ :f!0XRR OAIBuk .ZB&Rf{X-vtk]uul[mMlc{3qLon߲eAMJٕD˒GFqV,\X|c%6Ph'X,*Eܹ󊾾\3XLx pսwﭹ[ٱ# ǏisTUi?8 Ɣs(+nFG5sa[ g~j>@NN5==Ƀ!- Mnn:"pl'rzabۭ\emm~Dt{FcBa K޼(Bc^OPW,1`hH?\a<@QQ6o9 l޼3 +3\ص?Լ. v p:;!+K_N wQPdÆ ֭Ѩ/ iB +x8~i֮]OqKPU'Tw}d ZZw7[Cj›K. gϜýw VhGqB SBS׬BJ)\S F T5L1.t7M~M8Ʊ'MxD<לMv;@-K ,p w[ 0Rvu&`$U>HCgeU,@Egqk|P9ߪbmWeR0]YC*[13Ƅ Pp@/E1b&|&*Eo~YM궩9fI߿G8m͈mv]긱WZ__,K>Y‹Ӛ,pBt,c*kx7ZsZ4=vf /᭨gyѭw'xEؐNtp?/8<j8j>ĺ'IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Summit.png000644 001750 000144 00000002221 13162217247 023430 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs|(tEXtSoftwarewww.inkscape.org<IDATX]L[ei -}Af1QX%F[f`%`n|$'AdWSьI\-Ёeԫ-1`)-mOy8=m)=擜m>>o+p&>Ź.yzs"YZ3=$ـl/J hi O(9 pf30 Q@ڥ@h;vxm]5߽fn4N^^ѨNI fh6h?^˥{8rdO( 07wE1ӃA-9-U+DqCss*=Ȑ@O!h=$B!eĉPR/(dv/d@l1DN@=i`h̵K161F8t*3 \}OOr[8Lwh}D@`]Fs]S5pb"e]溰n݂CL'sJ1gA5@99=R )c1)GGlly)22~E*M$N~M(5CQW[\|02 C)"zdi*+Q#[OeccrQKH mјBW=(H b_Xūn]@tnymLiOcN%8u"p2Y򱷣>J*lfgWy M3ظ`Päz $~"?&/@S@_C7QNIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/FlagBlue.png000644 001750 000144 00000001167 13162217241 023635 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs mtEXtSoftwarewww.inkscape.org<IDATXԽkSa'EZ۪E+JtPpREAPDEPP(~tDEAkQBIip%%IH~Oz a?-ru#(" )<ѽsI`J- J:{-C4|q 8{uZ@֕HqpcƞK1Nϓ*oV z(/SD0[d]Kw;q }8E/1N%ov:Zڇv/heۖ'%Gdb*:9l?j%y~Ewz],<ۧYbC;ٗFe?RNqf nI5*$q»NB'26#ޛxHaaktWmkX韡x8^k oMs'WT^ųV{1_yI^T1'`&l<'`< 'dckIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Waypoint.png000644 001750 000144 00000000761 13162217250 023765 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<nIDATXO+DQƔo J5HMj,1l`1s|5wl%) v(bDJP浸W{s鼧!!!!w̉IT@k  -`MCn;g gNLp2 Uc,=g?`Pht8Ǐ++GӅ0{`'ZhPɵr4-6OLۀQOz 4nx"54)(ӝbq\Edp<-27N94ꬪμ΀9s A0ׯ!>bg\XGTp(#5ҷ+>zwlȼas4]ɀIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/UTurn.png000644 001750 000144 00000002020 13162217247 023224 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IDATXŗMhSY/13"c>L&B 2  7Z ԍ(2tB Sw-.J' R͌eؕfahLwfqXїt枏s}Dq=.\N6Krq;!M;kYC[YqG^17 jv iZUߜCYSSxq/2~~+P5ƺ przسǃi ϟ/ igx8?U?EӢQ ~D")i~`ϊwS *GLO+ƪ@>^~x׮!YX׆ D#&++24cm0p/3LNl01СiNG$5`z: ޽>>]]?03wlQ}]0 0?8 @[۷}B@#qfZ>XT>v֌/`~P~ܦR!hk5 ʷ%,n(NC{; _wT\!9^Y)󱖁X A(I]iBoo6Dz}hj*okv tEXtSoftwarewww.inkscape.org<IDATXWkLTg~m0XJQK &)%Xj6lح8nܔƚnA4축*`e`93g20-q>Iy~{w(xj9`!ӯdQ"8"1CEk;P2Uj%0g$^ed3QQ  R``Nv68hXnqIzBw9Ծo_!1Ll6D㴄DNYl6>woϗyzOTMub芊_)C EE_}2E a8w.QQ;v;~br6KNj?fe6wА IsCG@CTrRU399E^PNڤk”B#c$/44Oؤ7&ɱc_>I ʪ!=lq)e͚ JE|3-67o} n>yh&|hjDWuu BLL `PjfF}nQ1](=u&Iq焢4А{k#ŮqRPpz_"z1djDj,JeY_j2<wb08x0ًgѣ7`4@mddcdd[V :]T0=-"$D 3'rϏÕ+/fs"'g,==CWiZpHϏ^Ɖ v³jiDD"33@v/o9R>QрqGD^x"Z[ gP^IoqN$&N7ݻ/#&& j96A9 ʢ(Aܲx&jk{pR\T[ |ЉI" @2 QYP%RR'BXNtwple9siikukV#yS ơC XUZ}~y݌v{ 7ha۷Gض-ҫF[= ޼wo3/yrr"HM]_"^9745 #RW**:^qe@3C4x=ihȫ;0?7q=Go澄O.C VftA<:8yѡdD4J%hcPe*!!vE{{cϞxՈ }#GuMXΤ 4<6 3z4 ]-1|P 1[?96}}Y,bW,;(>'gJJ$6ԩBCChWYt{sY)6<ϙ-OM e7;fMAK׮ a'cYSFPr9%1EQt8\J8"у( :L_gcIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/MiddleFork.png000644 001750 000144 00000001434 13162217243 024173 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IDATXUKA}nŐB zTAP(Q"1' AE<]*-b0/z( I?*l6àiPE%23|{ofvvKOԍS2]*>=]'&pH2DDD诌z!!%B论!*R2MDF||<:"n'Ξр/ dR77IIx %%BTd2y#gg3;30..HC[,1IGyO7<113DqQLݔkRi( W(,^s"CCkXZIfkzPS.v=8(JWY{;py)D"#۫4mR45Ufz׻goA@@ހFW#*@0^xc~+)$΁b]nw :;?|.7>}5ctIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/CityMedium.png000644 001750 000144 00000000656 13162217237 024234 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<+IDATX픽J`%ޏw@MiGZJt)_סK6Mӡ=ps o`03tVgi@P99>J)eRYw"N5 v) ћc"^}훤5q\|0j;p,~1WXvcAM@j.Ux.1`Q^ֈ.u~ŶroYzaٌ͋;FfmNJ ɂϭY6IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/SharpLeft.png000644 001750 000144 00000001652 13162217245 024047 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<'IDATXŗ_HQ?Q"ST%2#A z"|h= 7lj ?b%5 Sr/oeCײQ/\s.r{(JH+ o~Wtߦżjƍ7谑_dWX{7 %%ׯNKbs=J|M*Wo {N;`0 ѐ_s P&SAn|)z{p k paC!Nb4x p>fc_8O߈ݾ-XM._~ΧO ==S3\#GjٳjI+hoL8<˚5y\KO 02)]'{@[Nk ܾ "™3@yvےشIc1v$.W#%~))VkGֱ\(.E]db|\A[zee:q?vmlN,sew%`l QFG~QY^OV t-55%Xe?++hmUKkݼz笠ѓ  @rl,@(*ju=_ 0ܼ CU8%%pz.i$c,"V.b2/$zԀ_K3tt$'"=="`#)?}{b]V--pXBVO3RhlCV;[) qjǤKSQYј]#RB!{~ZQA# IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/HorsCategory.png000644 001750 000144 00000001554 13162217243 024567 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs G6tEXtSoftwarewww.inkscape.org<IDATXKHQV41>VV U7E]wōP)⾋ ֍ RcJj,\>-bECjbM$Θ̹ܘR**J0s#փe4ϰ/ J]-.Hӵr7dB2/=$$ct 7fgs0 !aq]\@4*?-]S_XYI]188'VW@@hE wp=K؅-\uΓkkٙz 2^C^Te4W^Sn7N5[[ӍUv  *'\\pXs8InN%%P[4,L66cr3$S\OOH'WKuǣX jE\^ic``N#^nEmx֛ ܁U?vv`j "' JKEso>HrwD60>RBo/+c\7>|~bjj1(+*ßh bIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/FlagRed.png000644 001750 000144 00000001161 13162217242 023453 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs mtEXtSoftwarewww.inkscape.org<IDATX=kQIL"(LBJE; A-FK_R"L֨B!J}, ala{5 || VYPF _ ƃAjA P\ ~W AX''7]`>烾x\[:|3v!^>@H}JD r׳\ 5ߌn0ψw@;g>(+n6#+ pǥ%^RØ%! ,*hml;meIG\h5/ ?2+udpT+vV拙+B=(FpY=R{A)#2F-krS2PxSDp^>mQ<^iQfva?-K+`FXEtc p d+&IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Left.png000644 001750 000144 00000001215 13162217243 023042 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org< IDATXֿKa]sB) "U⤐AɘYpuE2) i .n.NC4O5p?(㳼_ܣYJ2c bYT*C :bNOGQYԟǎ2v[z|/e2JsV*J8u$ S)hπfy/,^\]Ą@9 ,PB:- )8@\T(HR%9*r:=mg W:b}rުJͪVkhd[:>^-W[c1KD,$9N\Q(KZYy] wtB|<d>br~)nn`zGIV }D_1$q`m-d6zۆ`p./; x{,nFfu+2fuK&mۖU2 %h4e㫊kWpGP;IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/SlightRight.png000644 001750 000144 00000001706 13162217246 024410 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<CIDATXŗKSq?g:e&)If/aRR"!HݘA,"Z8((F!Kš"lkl{8:t=<~97J-jrF^5㿣/1,Qx%T` tu剀6_"nH}٬7DZ[EnՎt8/N#r예ݮ75DjkEn 4mw+.^ =QbG^PVG@K 8\yPbB]X,Z5pfm\zf'v~@Q`j*LNYi-92 ))y} WTNiV()## ^6yofZӹ|w"S00{ꪡhǏ?Cm̼܇8(~֎"+ѵ(K?"HQ|8=X Tuǎ& Cpp{iP%%%ϟ t꾺:hh0={EQ7jC[s\ԫ"D=65 ),g &訩5`L{B  .дA텻wXXPWRLnۆ.ϧ_ߟg"6 yV@!P]<+PYo-nfxڌ9͡"?k'B+Hζp0rB+-*c675_199oP +$4FƣG8y[x(R/ e)2IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Default.png000644 001750 000144 00000003742 13162217240 023540 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs XtEXtSoftwarewww.inkscape.org<_IDATXpT?ݘ%MB5b[  AP; Lkm; 8: /X-igZmmZP+B*Pvc~ov߻$i)כs{9)9`cd5yÁ3oasMk)DiL#W9`.2zPOə3)[kn/)\`o^v'N,M0OwSPp:t1ѫ~)/L[k$i9`0p[^vW;w$%% Ə0JGwz"d˃D"~f,fŊ/ 9V&M*)5sK4m;/?DdTUHmq|j}ȕWꩠGeeX+\(Z2%LQQM1r pV4gʞ fc[*B>KS0sVqz SZpbFs:}kH3-bC2=gYyyp]Q󬘰?2%MM& `dm7#5r6dz`c `MY\[$i^yyo;eayKUla]fQ[̫1_{bo̪ ]g y'acxs>8XEjl잱o_ҟN ݣ,HnZm0F`kk|β @WϦǏE(~niГW K<# m2Ҁ[Q4fy%|t;q=k‡8 ?Vl*'NsRPf=uvmۡ='++m[[_;h=?n;6,Jy_(ްmu .w'<1Gpf("l&_4DD< i1lnhH5;iosm w/1`,0PY4ɤE7'027pZ}NjI$ҶTxI»e<9IQi"}R { Z=+F l/?_!S f:NIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/BoxGreen.png000644 001750 000144 00000000712 13162217236 023664 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  ZtEXtSoftwarewww.inkscape.org<GIDATXM+DQc ("Rv (Ld x,p,.]y;w6:CL Ns[%~A9r a w&,v'97|&GX~% R_V3J:Q"8, ?=· V/p m|qpCƍJEyCXoljϲḧdB:F:hNi= @` 0{?.q. ΊaOĕhXvEѕh 4ST#/c'@x$3JfsE'µ,hUԥY`X# p|3ʈ .+&4-t^Mx`3,K8+rF;ncJhuI(WV4`~ &KvТ%a v` gpi"DٙZ%2]C$Ɉ;&NЦKʢ 5@ >u_Ȳ,, kV|ⱸ0W)丌$9m<>>SWW].ɩBkgDw ..~LrzZ 9_[٠5xPV !//03SSJi{{ޮ߯Z @m-ؘB'' σ$A4 N'loS D"3X,F8<`U`aEǧַ*//!Z0< WW[` $X=N-cDuu9|OO`0- ͣ9s"8n1?/$ BX,BBeC>~?Hqc#lnBss:p04jݭi巴4tv*>9  3nXZׂHFGAQl5X,PS&ll /@UN,S甞SVVbV`4ijzS?t[PQlC蕤t7c45)|oxV `^<d=IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Generic.png000644 001750 000144 00000001375 13162217242 023532 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsgotEXtSoftwarewww.inkscape.org<zIDATX_(a?[ !9[h ܙU$K\:N4WKIl6̟ґtm\ab󕿹 v;ջ H*/FG`X .IԔJg'tpPQHZam vvQy77*VLC<sь& w=g2"qH\ ךt :qO@xJ0U4{ovGJJ[B%21^/ey+6˾]ѨDgQ7L[˄p}0`0 X q@:֚RXi~ o,౴N8%=RZv*%O{ Y3id>'HxK݁gT2INIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/CityLarge.png000644 001750 000144 00000000764 13162217236 024045 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<qIDATXAN@ l,2%pQv4p!=PĸְO "l"ibL%/]4_&yBFF?MX BP'O.FQJQYAj6pRw]>z=v]IR28&|[J[-> ߖ @J?•BFJ{cri $ \fzh}}XĶ, 6kZ0PJ7&|Nrjb M@e߹\6DBP3G46֨д &16zTgQh;~m+𯮮~!IttXaؼp)HraJOŎ&YIENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/End.png000644 001750 000144 00000001414 13162217241 022655 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsRtEXtSoftwarewww.inkscape.org<IDATXKQ8I5iMK B ABʕ+q%tcSIU +fQI B1b@J! 3:Kh4M8o.\/񾄻9LRVgϽMβH|V/ё siM \7?#|`ɘ~7p:LAPkBJ]ܛy aÕ?>8R ,,|2ci|ή/oi( ށl^֨qgD t6?@ H +zQD&`6D"f, tc{{݈gLm?`"*/+Ȳd֪:z(X*&m$e "d^K& ˑ~Fd{ M# I"cbncCrtil̗KKK\֊擓:95U[]@}1W w0EF\;7b B񼬨U<*b½"pnµ&4opk#\|3C^}^j 9LD[xHQDR$B"pQ5WExQjD4^zdPJ+IENDB`qmapshack-1.10.0/src/icons/waypoints/32x32/Food.png000644 001750 000144 00000002773 13162217242 023050 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsE}tEXtSoftwarewww.inkscape.org<xIDATXMLSi[( E:P 2? 5j qJh21P7ğލ&"`bTVA*RPPgJm̻CբT* v챠P).Ngt"&788H[[MMMs/^xR=bǎ+ ;)l &09111A nZnOL&p>uBF&r9>wTTTPCCo󏽱;q=ڵfN_3J6nLc۶LT>kAĺuܽQ8t(}V^g9󐆆NzNN"q3/?';/xbtO(F39~Vk;ǭ/yزe \+gO ن҂3v9q7iSOo 7I`HFh<\.7󙢢n@`9  PUJy f^NNA`0$T=6[&S)MMP(DN*$+kǎY$;55/ſʈ/N0 ^obÆaRUjx*F-&D 'ع]ʕ>PVTc2iOaظ /rV{EQX' d d.G[jhjs"W"0Y: ͛`6mm@ w(>Xb.0*nx`]͏B>Z+=}Ż $ *+#0Oߟzbw€p$[6 -֯DO<҂3z**g&Ҝ 0u`N'46zˡ1qqjGpZ > ֛p:hA/ل\ߛw} `0^Xod j dg{ ȘN,fqM#npyz}jԻ]0y/'ǁIENDB`qmapshack-1.10.0/src/icons/waypoints/3rdCategory.svg000644 001750 000144 00000007070 13057473631 023605 0ustar00oeichlerxusers000000 000000 image/svg+xml 3 qmapshack-1.10.0/src/icons/waypoints/DiamondRed.svg000644 001750 000144 00000004065 12455143304 023416 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/BoxRed.svg000644 001750 000144 00000005202 12455143304 022565 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Residence.svg000644 001750 000144 00000011642 12455143304 023310 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Valley.svg000644 001750 000144 00000006002 13057473631 022645 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/MiddleFork.svg000644 001750 000144 00000007046 13145234770 023437 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/BoxGreen.svg000644 001750 000144 00000005202 12455143304 023113 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/Left.svg000644 001750 000144 00000006002 13057473631 022303 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/DiamondGreen.svg000644 001750 000144 00000004065 12455143304 023744 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/PinGreen.svg000644 001750 000144 00000005736 12455143304 023125 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/FlagBlue.svg000644 001750 000144 00000005017 12455143304 023067 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/HorsCategory.svg000644 001750 000144 00000007071 13057473631 024031 0ustar00oeichlerxusers000000 000000 image/svg+xml H qmapshack-1.10.0/src/icons/waypoints/Sprint.svg000644 001750 000144 00000007234 13057473631 022700 0ustar00oeichlerxusers000000 000000 image/svg+xml S qmapshack-1.10.0/src/icons/waypoints/Danger.svg000644 001750 000144 00000006352 13057473631 022621 0ustar00oeichlerxusers000000 000000 image/svg+xml ! qmapshack-1.10.0/src/icons/waypoints/FlagGreen.svg000644 001750 000144 00000005015 12455143304 023236 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/FirstAid.svg000644 001750 000144 00000007743 13057473631 023133 0ustar00oeichlerxusers000000 000000 image/svg+xml + qmapshack-1.10.0/src/icons/waypoints/UTurn.svg000644 001750 000144 00000010206 13145236005 022455 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/SharpRight.svg000644 001750 000144 00000007254 13145235532 023470 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/PinBlue.svg000644 001750 000144 00000005735 12455143304 022753 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/RightFork.svg000644 001750 000144 00000007045 13145234724 023314 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/LeftFork.svg000644 001750 000144 00000006765 13145234674 023145 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/CitySmall.svg000644 001750 000144 00000004640 12556335125 023316 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/waypoints/SlightRight.svg000644 001750 000144 00000007243 13145235260 023641 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/FitProject.svg000644 001750 000144 00000010142 12705713524 021422 0ustar00oeichlerxusers000000 000000 image/svg+xml FIT qmapshack-1.10.0/src/icons/SetupWptSym.svg000644 001750 000144 00000013370 12705713523 021642 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/LoadView.svg000644 001750 000144 00000010715 12475013404 021063 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Error.svg000644 001750 000144 00000004562 12455143304 020446 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/LimitSys.svg000644 001750 000144 00000017426 12705713524 021142 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ToolTip.svg000644 001750 000144 00000011155 12455143304 020743 0ustar00oeichlerxusers000000 000000 image/svg+xml Tip qmapshack-1.10.0/src/icons/ActBike.svg000644 001750 000144 00000010464 12600710657 020660 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TcxProject.svg000644 001750 000144 00000010230 13040352611 021421 0ustar00oeichlerxusers000000 000000 image/svg+xml TCX qmapshack-1.10.0/src/icons/SQLite.svg000644 001750 000144 00000017267 12705713524 020531 0ustar00oeichlerxusers000000 000000 image/svg+xml SQLite qmapshack-1.10.0/src/icons/Link.svg000644 001750 000144 00000010761 12455143304 020250 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TrkCut.svg000644 001750 000144 00000012147 12455143304 020567 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcCourse.svg000644 001750 000144 00000032777 12705713524 021406 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MySQL.svg000644 001750 000144 00000017147 12705713524 020332 0ustar00oeichlerxusers000000 000000 image/svg+xml MySQL qmapshack-1.10.0/src/icons/FromMap.svg000644 001750 000144 00000134115 12455143304 020714 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Track.svg000644 001750 000144 00000015532 12727447634 020437 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PrintSave.svg000644 001750 000144 00000013223 12576221163 021266 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CloneMapWorkspace.svg000644 001750 000144 00000014646 12540525371 022741 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Undo.svg000644 001750 000144 00000004216 12455143304 020256 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/DelImage.svg000644 001750 000144 00000010464 12455762631 021034 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/LineWidthUser.svg000644 001750 000144 00000011402 12705713524 022077 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Copy.svg000644 001750 000144 00000005206 12455143304 020263 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WptProj.svg000644 001750 000144 00000015172 12455143304 020761 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcATemp.svg000644 001750 000144 00000010564 12627613666 021153 0ustar00oeichlerxusers000000 000000 image/svg+xml °F °C qmapshack-1.10.0/src/icons/CutHistoryAfter.svg000644 001750 000144 00000015717 13073620730 022460 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Grid.svg000644 001750 000144 00000006375 12455143304 020246 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddWpt.svg000644 001750 000144 00000006215 12544430507 020540 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/DatabaseSetup.svg000644 001750 000144 00000024075 12455143304 022103 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Time.svg000644 001750 000144 00000014045 12455143304 020250 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcSpeed.svg000644 001750 000144 00000006162 12627613666 021204 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Print.svg000644 001750 000144 00000006742 12455143304 020453 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SaveGISAsGpx11.svg000644 001750 000144 00000010612 13015033052 021703 0ustar00oeichlerxusers000000 000000 image/svg+xml GPX 1.1 qmapshack-1.10.0/src/icons/ToggleDocks.svg000644 001750 000144 00000140432 13126360003 021550 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/NightDay.svg000644 001750 000144 00000014634 12455143304 021065 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextJustified.svg000644 001750 000144 00000006545 12455143304 022153 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TrackMinMax.svg000644 001750 000144 00000020502 13216234261 021522 0ustar00oeichlerxusers000000 000000 image/svg+xml min max qmapshack-1.10.0/src/icons/32x32/000755 001750 000144 00000000000 13216664444 017417 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/32x32/FilterSubPt2Pt.png000644 001750 000144 00000001011 13145236344 022702 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs,@tEXtSoftwarewww.inkscape.org<IDATXK(DQiH+P#$ca9efYPS& B"f泘kyCY|ש0eꗥLHpl;ykb(3Ynd@~沑M "=Q2uI}K_ `? "زS Ej3 wij鍅 .tv +Yz`XӢfd*t#Lp_ ~\90̥kpćZR>mJ`!y  "tƴϔj^њcŊ5>7F-X;-88{spJ$n3LGqI. G#FT uƘIENDB`qmapshack-1.10.0/src/icons/32x32/Paste.png000644 001750 000144 00000000646 13145236375 021206 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<#IDATXc``H&&?߿B888~:;;bۻwo߾dpa`(?ߟr$/o``x]{$fz!h \tb<7P#C܇p[=a`x$M(`bag+V~"E/A5DF#0Q:`uF0wF??yO`性3LM!_?e9`+Ա'w1Ee{Hَ)IENDB`qmapshack-1.10.0/src/icons/32x32/Info.png000644 001750 000144 00000002012 13145236352 021005 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXoTU -*嗢ŀ$F]TjIc4԰"҄lX0F ?B*R 7"Zj,ک-Ӗ>֡͘]{}ι1lA\yb?R 5!c؆f̍>7*>VgbR-28gΚuZMM io?- \wN!vL)ٳ_<Ǿn#jk?▩IvO8WQ%J$FsdXTxwK\nw9={Δ Hp=ۘ|NHZFoo?ik;U|/QN.r5 j` "<G;G0֕-?S;h:AiFf e1|GFܮPuIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcWTemp.png000644 001750 000144 00000002016 13145236331 021722 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATX]UU9~2&6FeEPR>(bAe:24ьJz҇Q!"-H2E)Bŏ{=wpk'QN{"ʮ&VespZ7bbi;_ 02v:|,`X q0d- H+,cLDa-2~|l!.[dP B1u XUg "`p-^B9zPi 'Li&ʎ@L+gN^H'On1Q FwG7`#ǔ-"aa ĝ!YMP Jo+((Ä  _HӅ0 ab|m}㆏Ba2.3|Hx#l/1;Mw$TY!ŎZbZvp>3NJ?H5oefS[SZ9aˮQ .,T%*)C-sa-P [;?;"a(EėzNOYB2SIPJ$Ysjs8F8BAوȣ9.YgHвrWߐpda\nRfWp5tl*F,d9k$xVļ/ dA_?3!ycʛG$MR bFՏtXyW8V%#n]eB|$cH @~p@˗u  cXqhm}A8c^ $&F %%q0^BlJ旕5Bh,0wFG+D~rddYB# 'ٝ;v%5sf ܰku\./_֭00))'$ Iu͕-PjxhEE^H$gG(k~Ef[:IO5ƅ ?%`mz!`]RQHy&jf~ x]ܷ{⊊flSIr!ɳǎ݌-*j(/-[ç'BP^$F5*+[`;!I X(o@Q}}6L`TzYuS(e:\[kES}tv0go:;|jfS۲쉷ڇHJ|.]e N&"::hVttO~j~klBy܀O9 jj:S| 3gQoU BCu͍) 9#05q@DFTl]I/% wノho1SSK1sU99&cOIENDB`qmapshack-1.10.0/src/icons/32x32/Help.png000644 001750 000144 00000002422 13145236351 021006 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs 7tEXtSoftwarewww.inkscape.org<IDATX]LSg=X= dXuB 5ud,,8/` ,Y4d1bo\1a.*#lR\sQ$1M]l V`TˁsR)8y}<0\ Z@CC *gA >݀HP" F!?h0ӴhLK@&-`as4c ioO@* A7 R^ @c7b ٗ=W0oڴr;eek)(0?199˗*1Bkm`(BB[2J@M44bԩA)u5\3Aw7M'i'qfH@_QY *P&tk#Wnbذb;:Q5!y$qp z X?[dEQ;3bs]<9HM8gٻ</E%qʄBXy8P ^w#ݻ qF a6 7sƫqQ|K@LDvOvOSN\#"O{YmoW_ݞmVPn/K.˫hkD7PQT&鰂\+v"ٴWuk|ǟd $@J4l66ĉ &Yb峖kdQ#W Gs` 1;tNQ4+WK`1%tǎ9h,,4-MvQ @'(O13BL{9wn_Qep xx =vF-6&hxJ 7/} gWHsj}Pf%TF? ,6PYDCvjwuz  /Ye|IENDB`qmapshack-1.10.0/src/icons/32x32/Right.png000644 001750 000144 00000001141 13145236417 021173 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXKTQόњp.¿ * (,ʨUM鯨Zm \()\AVܜ#3PaǗ;s|s~bSf'&; }GVW8hadcYw4!8Kwh<#$'x#2Zqשrn` Q7fjQ hFP㝌(+)Z dJ_`#,BxOz )j*d Nt0}ƫhi+;{ag?,jOeƧ.VU8KkkS؃5W^K!/z,b x6r6` ,>݀_'ĿMsL; þ_Er)IENDB`qmapshack-1.10.0/src/icons/32x32/Path.png000644 001750 000144 00000001030 12455143304 021002 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX헻JA Zie} o|7DYX%jBݘds?:&6g813;02H HHmG=jQUdc է7[E)Jy`-dtM_;Yuf64_,60a[3섥 ڤow(XDֺk.rһŏa&oul GUm F F cPQ^@d/DAلVGDP944z,P*F  _|?fw ;lvV˞6}i@"^W_>TI;SmajK*$9R]NNKZF'"IENDB`qmapshack-1.10.0/src/icons/32x32/FitProject.png000644 001750 000144 00000002044 13145236344 022171 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<IDATXKlUWPB "B4A(K1ąq% G"FbD\PtP61 DM mmig:#r3sCye ?|\F$mw_CV"Zv/Dwm!^msK@3!> qk-C8hVa.XBqhcuCbdB!X"I@sjv= DRڍe&{_k;TIcסR=o[EKB k܁R!GJ5:ɷi3ɤzȷ`K"9=4!?ŔZ?s9lÅL MЍA|͉D59i܎l6?%f5PfSYi\7ag"F\ĨZJlWfГe0Z KzQ\Ivs,j(U)|y&ZVJnej]rǢ< bD*pjM5@wSy[HΘ̜*0k~B06U\uSX]P(ƹ?0%%`8 ͠< :`s:y+΃QO =&2h${u@4& QNmd^:RtAqEUhcub3fqrIU(M ğ"푍5ܜ9盞jRe,5>ιsjVZV5BL#c+6I'b *-5m5OUI^UxJ&5-*Dxs.. c8BZ/׭}*G4=!4ҕIENDB`qmapshack-1.10.0/src/icons/32x32/ShowNone.png000644 001750 000144 00000002620 13145236433 021657 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org< IDATXYlUUJ[lJAJ@ Z2H|I4AH4!bp h5T[kː1`hJb[ |(^$JoΑC i8҄ bm"5#yp$#P]Duu#>u`-,`n{!mC$xIoHzIQi8qE ma{xee ˙=z`hʔdmVD?%.j,kٸgϩ[T$o RR%I~;w]UUWHz6^7#CHhdرdemGrx챏XǏ_&~4g6V0Bn H֞^gbcW)i/¸qD7Ž l50,*<!;{'ՍQY%%5!6l(Z(*~['OcZ'Hg dFXk?>w7{!$)9bM.!,W"gǻ&Puƒ真c:O(V5CEE{Z-aŊѲF̣Gkq֐+jMM$&Cr zq44DU//sq()X"s}Fޞ;g~ 4D#nb*& T rm@ p Gx:t+:yU&)55 IAI=]TfklkW5CK ScΜWvv1M6o~a}Q姬 ;04Z䐐ƍ!^C|]@m- Z{zH6_[!.. l% 4X}`ʕ%Q>cw?uc|u3ftfd:[N{ݺo%;{'CAA9~9 ^hllk;vû?">{M/SYy͛+X0ZyE%ӷbÆ ǀhpbkk᳜7p1lm,{>.k }|޽FKRnwQ7c)ӧ Bװp$$t̋)Sz(⺵E3T A3Sc$I%kĈ2{ $קqKK@H& S~8e*mcLiOEkyTyIVvoiEEVN]SSSA#S3R!iBc*{t&Ҭ5-c pjll ? wFIb' "ǽIEI )|hnp.R[IENDB`qmapshack-1.10.0/src/icons/32x32/Add.png000644 001750 000144 00000000536 13145236310 020605 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs Zm+tEXtSoftwarewww.inkscape.org<IDATXAJA@7C'¸0 "%;/C"ƻ! 2* Z+٥~bݏu['~EPJ ؽ "˨K/cztDm;;=PJ@Ee,i.ymbu,o~X%fxPJU*-XIENDB`qmapshack-1.10.0/src/icons/32x32/A.png000644 001750 000144 00000001146 13145236314 020277 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXOKQߨ I,kweҢL?C[}˖)D>jWQAKOʹ߷l\3s{ιG8HڿF߷pwW}n-&{=х$ + ~*E PGҶD`dq# }ümf(rvJr?*30 0wsa+5B䈔Ug9O MRkgg{B1\ܮÖ4ǻqw.I\8G?Vd¿7Ӏq1Vp /龤6psR*QudgadKRn4X7gSp"9 V2p{_?`l1G$U "pW#rzqȖ.'>&${U\.d*Ϸ_g&,P@!oWD\ܪNQDXFh<~9|gNrӱ,`I ͪQmuCZ6ulFT`jVeVdW/s>yu#(_mH-|h?C,mR=@jV-S^2:u?wvnB\Y3c,p3ĥ fcÆR!#i,~e#Efޗ$;Sth\KROk?(VЄ 썮<ˍ,XlbFW.eͥxS;Wo]U #cc뾕G}H@PXaƪY<ZWs ޡO@+1䡚ج6~xl)x`)r1%!f¨eQ;۔)|OR+X ;Τ]/ rxLֵ Z]@-{te +N@Y,t()~"~֓qm6]m잸Q /pl=iB>łs%ɼ=y]d4!v\S%<?De9s<3FuqNet+)I 7qboD`c+QW+P![#fQfToc1Nf6Jzz61;`ddC9uW@qNg|+tS\̧Yen0xi,!ѪZwL*y#S<183Nu?wO@vjvIENDB`qmapshack-1.10.0/src/icons/32x32/FromMap.png000644 001750 000144 00000003440 13145236346 021464 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<IDATXŗPT?wY\ïJ$Ɗ A`(&A1۴cR!`mұ5HG-TQښ#BBEvvOGYV~dLro9{{ |5vިw_\ڲ%"F X+}1}H4%W"#"Ԕ'ܞ7 DdsUՕTU]^gϛ͍хih {0G.FE}%v{·J1c2IL]"a>֑`Kn@}ػ___GXXyv?)6NC0{?lcȣaL?D߈26@bMRSH~~,CΜY {c.q݆_y,#*ɓ-AA x1cNJPyukdᘙOaq OԀ8{c2k* !=AKq""^#=oHU_n}K/>IIkj-ͭUp9Pa@RdQL?'!/Ík6xuc0+OЌyRGFL( ]pR4 4; }?@b8}:v0o~ Bo/4Mä:S\&:i'9).l6̌ȹsx],zHV$L3|HE W@ŌFYYu===O]JJAx|T'';gc:Mi47=Y*K{ VJ]O)l%%]w)ϣN4߫BPw_{<1VhEM<&".#g=$EDDq=hA\3߅ ۋVtFn -%NjD$n>< _AD.@kWtF;!NQNXNM}p &wђ"9!~HJc-Ѱm9,T8 Q9rM QUx}:(#6l=%:v!yB4?s:*gjk_f}5`ֵLy{vXDк0/@ n+ʒi0SOׯ1;,>06wEe*CG=p璉$"\ ƒra:~Ny _2gƛЮIENDB`qmapshack-1.10.0/src/icons/32x32/SetupMapWorkspace.png000644 001750 000144 00000003733 13145236432 023541 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  #utEXtSoftwarewww.inkscape.org<XIDATXmPSg7bH`TtȒ&_`5V][RU:Tkqήvj[G1`V *.(&{2mPٝp9{s~Y^$"wz8(a X `.+λ@@RFD@ Sa P[k2]ڎnyERR4͛ QU0{0  _":|1棏P_ P*HNVaڴ 7N xB]]7x4\i8I!h< n<)w,T[I(CwwSB^p߉H$x(WmncGy.u{`>a8pR@DKHЃ0DG=+jmmdxbiqq1+"Fn #0L|B!g 0KjdJ.*bP\΁a,fhZ0NioogǎXUv_}#KW*6l^E5I2 c?^iV^L7#!a/JJj<5l8gÉĉa6m6ހ(rXd?iX~ =z}-[(LC" Ԓ~i2e^=/.q=$%%v`fۏ;W xn"n%''SSS:}k׮m: @bϞora&OGTT~MM^AG-9Dr@hhRwΜ92uFZS*^'-$$jONjAuu . 6IIh\n@Vb֬TTTT8|>'+--+77jVV֔!۷1$fJ 'y uI8lRm8hG̨4ӻ14 4A@eqxk`8g4.`i)@gZ'@=j`Z Hvf!tq2 6G9\t[-xa~cYD3ʬ/ YO2imL6 [sWk WxIENDB`qmapshack-1.10.0/src/icons/32x32/AddMapWorkspace.png000644 001750 000144 00000003031 13145236306 023120 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXkPeϲ(ll"A(9^(rƬLG(nL4]fm&QLi)慶1lM Q56a>kT_Ϝy9sPך("fآr_KUEi@0Dt`D!"@ =PJT[e189|X)oO`ġ̘1 njRJUJ%"~hÃ~Zզ'0l: uӧYB"X&NѴIG>dg&^'utR\TW7׷JF'={x&99[M)nOO&[hZX(,t 8d9/o(o pRnQJDPzLa9c:de"#ODyyNg.) {X(-)FhZ.Gzᇳzh4KKgrY`;FMQG43bD,VI?_wL@Uul3!k N ?~ЮDd;T=}+WN zMۋ<9΍!WG׎^jj'&3 +yyMAII%w@W3܉ n(# Ma>#ydl744Ǐh.RJURڴ)yٝTx)̚u˟i,Y2I71+V̙/!,i.ׅ5w9?d׾C|'jcd.8𔴐SmoS{in"%¼ydef 9cBv/0f=NUvm5MM bb Ct:;7p㰰 EcI$$ (4u:OPVvFicDQ?' HH0+ٝ---݃۽lٝGC$Ͽ$hMb;Rl~Q1l5~F4#¤5"{rW1ؐn\8HH:0"ȕ(pp]AǮRp(HPڋJ=+S`js]UONL~4wqOrIENDB`qmapshack-1.10.0/src/icons/32x32/FullScreen.png000644 001750 000144 00000001500 13145236347 022161 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATXOhU۬x=hR-E X,F at.# fri%aT|#c;OxaofxAL7/t6A n/7E_#68vo!)bľrPV' |vmDAa"v" pP`s(.aWx>~&8LbN%녷G*h2"mUv6|1:PVOVt""{&fHOw[ܢp:^$p_{ntiv_o>,vHFs{Agp4@ͤ=wwfrzC7*>SIENDB`qmapshack-1.10.0/src/icons/32x32/LimitSys.png000644 001750 000144 00000003304 13145236354 021676 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<AIDATXŗolSIH'G.4`?J6Qh"UEEckYǧutЮj7mʄ4vZ.hCJ ц1aR',HĉccC%52ycϗ{νs*jy~~h4I299yxnnn"D &gRUUh4rrr^۵k7TkZvvvc0tHT]UUUlaaN$FD $}zz5j/Լt:wJd2L7nxeY޳l.\ DX|>߆mmm4Mwwsϫ.t8{EQ,NMMDP[,_dff,I^+9bu\:=?khhBr/^a0ܛY%ɴj xމtnN/))YVMrJ𫉈fff>h4~{ttp8yy<^mmm\nݲ81 X,ro[grv*J 훁۷l6[n4v1wnX^^n0OuwwO>ݓƍsdwttl P{<ccc9FRիWNd__ER}j*Ch4TZ6ctt[333Pk^vnjUe> vTmeeeAYWWsss)))###Ѭ* =wnr׬aj|^$ Q`0ةS%Z>R|#Uy$Y7#3=5g{DrY:w$.@57}]hkotth ٟܰ42n߾GZ |FQ~ ܋g;OaU/aw$MTs+F @FV Oe)]@!p 3JP *v>/ I 6 yP\z@NP6Q?W.<#m e_\Fc :-FȐ I{ qrp ZѶN*>u&f4aa7 `.!߷mƔ Q7n+!8IqI}sD};CJ)p ڥ=Xۨ 6 G,N|m?n|?gYA`:ɍZV,EHK/&GB&tYe?r4ꢋ×9^PIF*vu5D\LYtq+ɼ MYu"|>lndW!}%W^C‘Y8d>N"#MO6jpto:1AT'cA[=/GEx/yw<<1'A\#(8 *vT1={@'xNETd "B<3=69|y.7hFr06ii 7ٹ:pp3VUʓtG)`Հh+HLA RE_Ε||-nH:ȟyBF+pXNM0"G'c^Yyx&&iQ/ ਜԟg6Q:х|lTVމ;L(SJpr&ACp)#oG9A dnƮ6]yI6N @50"KK|~z6XFi )e6?W/s,wE,jC'~Li*70Au(M284juJ2PY]:ILNPuờ©I4;mfE}be]*?.ƛV-nQ b1Jd9ٻN-0kc)H,]@ҀJOC)g?꿿X_2IENDB`qmapshack-1.10.0/src/icons/32x32/ToolTip.png000644 001750 000144 00000002014 13145236451 021506 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX]HY36Mb!YbDnTKŲ V^lW[ؽ(""]֊lOj>)*K ^Y(3Ə؜p<9sy>"p8,zo&`{1VdFۻ.%vER=>Wf&fžŪ^Fkh~?1~?zz9Idv.^Lmw7RJHa>E-0f؊N'锸T)(h$҆^clYᄥDMNfc_ )99ԷBplr ׂt Q(ckdzGuuэ;&$ .8&C9p@iX6 clϟO"05Wb5 gVeڄICss7s&yP߁h40q?_E,DӠpar'NٳIt8h`A8, m4us>]gGyyVZlo!h73p 7`"` 1}NՉfl +@4Kg@AY L>WWGhG<-+OxS`,« 8i@-} )WJK¥U?jf<|GѮt(^ŸxLٶ_Hk?D8>f5''5A:)$=G1&K[ _`f`0!Nn=+mE2,))܆QO`NѮG.gΑILOJF>ɦ2P2*\QcK߁|8c=v/}fEݓ@YЌX6"ԏs|ڐmh̊~E>Љt-/?xڏ/q#gDF_hXˢfA]G"uZO,SDa/9о/gn \|#]IKϷe81BaIENDB`qmapshack-1.10.0/src/icons/32x32/PastePlain.png000644 001750 000144 00000001564 13145236374 022171 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs |.tEXtSoftwarewww.inkscape.org<IDATX_HSq?ι0Cfփ!P|QI AAك鋳`iY?ܦnы=~w/g"-E!˲[Ms\~_I0:5]tQ۝"o`ߐX,5&lCU6%øww;*# x+#-BvfLhS6^tV@e%ZwU05Fj /#- kbL-,,,DaoB$G3 4QHHLB+'>_43G#24uu/at-;;A0}>V[۸yyei9G1e02L rKǩoa | jH^CUCڣeIE=3gC2|'~I )xU`CWH8[D6(\|T,b7o8:ȟ@~ 01&R΍=g6 wҝ)<` W{q8ٚl LR=u)e"Tt&%]!I'x+H֑%T-Aԙ$E30`|}69m765xcm xh{Yw]g`ZzPZ5T\M |ī_hHt>$X>8WC;;u_q$}u4T4aR>1ϑ?]He:l+O.Y,6*_g5biTUp xwa܇l^&eT~iMرt1q/'Mmi-T"K`nᠰ؉CP0%x>cQךּH9i_j55˃)/B~ g;46#ҞTT̚N(F0:?.{G<;#-vU#.@کn3E771ߐ׈IENDB`qmapshack-1.10.0/src/icons/32x32/Cut.png000644 001750 000144 00000002251 13145236333 020651 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ] ] tEXtSoftwarewww.inkscape.org<&IDATXKlTUߴS32EJ[- b">01c#((qaL+t.QiX"QA(>ZPZ)}RZ:.@Aj[췺s9s/ ywFߐAl3w&pG)" w$k{w2p{]iF0?R|ȢPy",yK9dD!hA`JS+n"JQuZ:Ӳwq[Tfwc 2rnh b UT4E0 $̝dl55'%xNŐx8!nݓزT4z_ۓX#gY9g  VXvWFaP*ի\tӦ57?Q;CH3mu[]^q㫶m;oh 35 #ukNJ7RũѬ]iG#|W샎jIENDB`qmapshack-1.10.0/src/icons/32x32/PointHide.png000644 001750 000144 00000001505 13145236400 021775 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  >tEXtSoftwarewww.inkscape.org<IDATXOHq?oՒ$t(+ I0 .`I>-t(NDynmMԤ cz(<kiٷ4<ˬ޺$ {$.!ҍ_NZ>;"dmy_k >,]YCa][󸣣E[**0~3L7 *^WL*T|V9x-eY;Ed~wo@gggR6U-[PU{M |q &Y"HDIIߔ@oA>xp 7=D+W| W H$rPD$[WիA4u``` &"nYDTUTՌbA<upe8%؀nSƖ۶~ 8:U-r97P^ ЏS97Fm4GA!eYUu8bZ"t@2TIENDB`qmapshack-1.10.0/src/icons/32x32/RouteSetup.png000644 001750 000144 00000001474 13145236420 022240 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs)ntEXtSoftwarewww.inkscape.org<IDATXMh\UI2cn*F,bU(tů" nʍJEnEAwY uaŅM4(ŖjiQRdq4o&<yyH12-wdNk.Fn(+)qCp6 HI;O }pS|̓-q7=[[8%M lښҕ1<}Sh?8'HN'WuXySój_F92? BU}mwY1|}a>{.7l{K z1_3Hg/%sh/lYEMKIG=i[kjr;p4-&?WI8052ؘoc3m/sr/}m xӋġ$DZ͋o(Rms$ų+.\x/Ip#:4ULv=PXmݖ|'e?hczӣ=}lfWgh4a h2c-|A3\k1 0Uq&V\2TjsS42Li\pH?J-_&2}j2ԛ y.d.ۜ( tbA#P@`R_ROt% yhv!>pĊNiA4&uqMGƙ`A?9_WT랕LSn/5 `$_`唎WDfb|cK9}K/ޯ."$%;E4##Mۛ9-\Y'Lj.c DqgmD1ȢFЎu!ω_"Zv:`d 45%oTj"œ |+lk$kp<x~#hQؖlZfh㹞W\iNlU5}ЎQ%R\܈͸#5ot%#B/OEEg<ӳ%gx"S/6 Sq5囈z0wwsx~IENDB`qmapshack-1.10.0/src/icons/32x32/PointShow.png000644 001750 000144 00000001114 13145236401 022041 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  >tEXtSoftwarewww.inkscape.org<IDATXϋQQ ;lGQ[I PR+ذ$ &? ;"La\pq;ܙ}{9=0ˌF4A^m8q,V’=1r?'Y+4f/z!R1fsN~p'84{6튺{Yݍ IWP3~Dwmk`m53ٓqoE.Uq(hM:eikڹ@jLF3WtbሲjZUwK]l[;>)ĥ ZҚS870#,+~+?*פIENDB`qmapshack-1.10.0/src/icons/32x32/SelectIntersectArea.png000644 001750 000144 00000001413 13145236430 024004 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs yktEXtSoftwarewww.inkscape.org<IDATX?hSQ}-WEJiqAɡ:Ʃ4E N.bpMQKũU!]Mh3]Խ Lp8 uHZRĝm Q@ ]1/z?[_j_IENDB`qmapshack-1.10.0/src/icons/32x32/ShowAll.png000644 001750 000144 00000002516 13145236433 021474 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXmlg96z%-F4AӆIL2TDDp,J%n,fAR- FWI1èj9}9ye9w=r]Ze^v$0tc6{FaY6}vk@=p8c,Ò8`.rENʭ[m377nӧ2fL?? (5ƴp޷m۹~ ՜:uxF2xpOzN.\ͩSWil 0bD3IͳTVSsEii_ |k-:+ m=Muu״tiY'i/TYyQJ,xm W*s UXXΧB#-kY#s/P8l4$*ܲrr~Q盢ZWĉQ]ج |1L5I=m>{=̙{nEt Ȯ6sf,+Ba[}NRV>Gs$IdŋG]g۶/iɒÒtH1ޫ{ܸ"qZZ:o=q<..-z˲:;9ĉ8 r9ٱ#y 4=n 7D[N bbY$&;w?;$]MM`#5 1gޤC04;1_Mܹ&~6%=n Q $gn^<۶MGJe˖() peF33q]Ӧҥ;Krrb1޼{%=}ʨٲl͚7!;{::"_ݛ7(TTT%I?IzJz-G-j ՗TRr\+VTByǏ_RJFSqq$HJ&IЭ׻^[V( V-\bb>dzFvK.A trϞ?\"iРZR 7 :rį9s)>~)S;,H'8b9ֽO7o>޴69/zp]H؊!ɓPP0I1G#Ր$ڶVU|TW_:91f(/&JJJ@1ƎxPx{-Y:0< ;w 1R'di~Y?Z\4& <IENDB`qmapshack-1.10.0/src/icons/32x32/ActShip.png000644 001750 000144 00000001324 13145236303 021446 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs_<tEXtSoftwarewww.inkscape.org<QIDATX͋Mq׽3aHQ,H(J 1˘i,Ĉ҄,,,RbI1)2wŽG3νsgXlN}{?T{2S+Jt2ڰۥa&n,,\2hgU~tV L\MCSl*l2E{@h%E/#҅!xC28}Ι@MXMVv / +L*B NuB@o+x8*u؏݄Uv @N\'K?9ЎASʻ0@vm6>.VN>Dc0 wڽv)5 HviUڅaI9viUڅ" W&~x?]-\z[s 棯鄍K8OX,tFOԁaGQ壙5xP<>5p<2%CmwW`/;jWUXH )lr0g()eqSŕn /*&Y7*;L:ñ]+Kq:Q& )C !g_ӟGh7zIENDB`qmapshack-1.10.0/src/icons/32x32/CopyTrkWithWpt.png000644 001750 000144 00000002137 13145236320 023037 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ? ?pSxtEXtSoftwarewww.inkscape.org<IDATX]LUo+P(ZQ)t@ZH6Eq3 /,N Lم/D$f˦򡛲1ײܲQWZ1VSF@W=<'+juxrAi9.!@Q& $`Kc1fu :@BN=VEm V0}o?jXS&RI<c8':MO4a3/*H$o `D,N8KK%W2dInNW\kр,_տP7Pa5Pp-;rnf[+0u*F_xC@$Gwd|MLi^V,@-!'7#rvk^>飿(%}_FG#!7;"TUb8m0C p#Cab(2lU)#PK=Qt*a[z  C895!IO,Dpk}tX$q+D@l*3[xG}| mmYħ]FWVLPMaRSF>n#mEl_[TކQT ZPp, L BH :G GɟgIol +94U)./kv4PV+ћ\H]hi ୞Ax4 Q ҝ'Rjy./V92O#4;G6Je"B^i1#|rq?6;!啥QxZ QNwh tw6f vdCltJS 7aVp3)P OI9B"4 B:>lkcdfoF~ $4uSP!/LGٽ("y "@)Wk>HT:IKPÜփe" EK~fog]V-Ŋu¡9;мAˇC.?тCe YDuT:snP* ;V^i!2\5HoAjĉò3K70cxѶamOSQ{O ۴&H h0EKב7{9%pA+C8#e(ĊGzgݻ^^۹e+]8V.&ΣAHd=s v0;Px7ЂDȫoBh.f@c$ep)&dDꛐPvoǣD|I)3֝l3XR=tKg?"J%h[?xk3HoL*V}oqL'8v&I o}H}'La`¶f wHu2vY[ 1~k0~tI͘Np .۰WeKmE#[,ԙsЯtpߠ ,ު)N&_[Ot[g4o}_ξUϸ>e݅2ӴdRxq"yp. XuzvoAH  ݆0~tz:K7Qr3ޒxco|HДoS?M=pǙMK9i)7 M+vE(e050 F0zGUO'}|m!qVQr3?ū-A ~(NDK3v|c >ď#y {{fIENDB`qmapshack-1.10.0/src/icons/32x32/VrtBuilder.png000644 001750 000144 00000004451 13145236457 022213 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs MtEXtSoftwarewww.inkscape.org<IDATXipTUkӝY Ƭ@HYه Au" T Ԍ "%:0D K$}GH@ԼN}u}|\a\RvK9 WDPo=t^BwFvD\ez s+[qr({4h?1ȒDg2c=Qփkx#Ә=a :H>CY{V[O 7ns(=; "eee$&&fg̚n/aӦChBBɦ)(wȺî]϶yna =֎S\#i|/Z[۱Xhjґ1<E*!⃫3 #l~1dpsFRG{FF\)"VJss.JeJѲt 9K-)4gNP@13}8N~ A )P(5 HDIǍ jCw5H(Zu-KL$G!bρ-I4tP\:<rOSCXX0^ܩ|t;tw08n,twg'2 7m :\CG&ㄩl uuaS)q0_#]/> qVkp;j!%_GղzLcwHۈԟ4@]]FL@G> ;Bx t?hhBq G3v~)#$$#9uu&FT'pB&$:X.\W^ڄGV7Dƙ?807VtbDȣgc\:{GV/kKiZ?c6?KUGS.r ^{-u MC.BG҂RRRz~v }֪&OR3.W.w&+}훙={fvd+{_%,QݮAzz:J}P^t@$j!\Ddt/p)/_/8kN+J(?7@.V7W\Ά IJ(A_g^Dll1FA'$nd £ނ;f223)hT9s`uri^ 27Ver/I q Gnmz?C8խer \ SHz-)ޱ`}hZW˿цIEa Wt׋9ze,]gEXїHHT^(p[:2ڀ7%U6*>jCN*n {K "zrZY1O?/ǖq~VגYK'şo sk!܋( e[yx F|p#~iɝ5XM0.|=T즥;f? ^o |?nWx{ub>.VFqnnZk{r*qx܏zcxi=Y+鲉ͷ]Cu;+ɒU htدbM]loؓ||.?;DG rGV$0Wuq _]~ ;ŭUG~R Qi]*rXG&WIxՇ"yyx,I̾v-ҙ '[t gGIENDB`qmapshack-1.10.0/src/icons/32x32/Track.png000644 001750 000144 00000002034 13145236453 021164 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATX[UU9hj7"1 {Hty rJ5#H0ȻuQ'*H%J0vU$3|!(a*c3sv{gs{9]oSpmHv"7 |tLF"|Snp㠋@|)j,+|!Q{&x_Aܙ9-6Npv)55Aȩ# nuDQ])xF&_wl{ݍ ؆SWP5YC3W u iCs ֱGʏSʱx'OVϼ3 F彤8 =I_'Zc7ڡ,?9 n#X0X_Sɬ#K[9>#xQP Cdq9,JCRLCE'ңG kTBQJņ tf¯Yd+0'KDؚsJ8SOJG2  )FLHׁ FUєy*m'[/Yp"Ui3sSƤr\B\5PDs9M>:,?SBXN`6kbJÁ MNMK7.bIYerٹ`Ng:Ӂx13s](a[RҲ]Jo`Ҁnw ߴqqy`sP(ZÛ ǃ±i G L |gka.][pftV)QP2c0b^y"`wv}V5Dv*N4C ң ż^CroA4F?+k>@E [Ȟc{f*Rj7T! rJ-v13yTJ>N^M~7%4A^#mk֖ •sm:ˣNԵCmCܬN s _V)0kj?Q5棶~ Xl%ܿ`L!f>ZTAQ(owoƸK" ~٫nA .>zc",RK-6PBYbRh CJW6FZb4m7v aub MODQdDt:Q};4IENDB`qmapshack-1.10.0/src/icons/32x32/ToggleDatabase.png000644 001750 000144 00000002514 13203507444 022765 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs33HtEXtSoftwarewww.inkscape.org<IDATXŗ]LSg8==~AHPQjPfŒ-l"QɒE.+;.tq],f2CK\1qHFQ P,mJXyy~y<[c@Ww׹?rիכ =8WѸ/Wx'WѼ|(*9 M?HO$I_M(Er(O᳟PU6%pq3g/^o]IE1Ŵ7ȃNvdB:l< 6YqPVG5J&4NO/p-چuk!AX˗ao?ad>LEE--[gf~AkG44T`0I$&inD"jw*V8vw^z#݌ LLw{&CQqmr<#dwW(*2oJg\B,R\?h\5Њ|X,$ѨRox\v(HNf42z,EMF@v*r7[))1k$EQB,,Dp|ʣG^/ P\O}*p%?_t^@i*f='NJzl:*Rp`0Zb.f~> UURDQz &BW$.׷&m-lyYDcr7##  I&}=-EQ,yTI0޽gkcv1ݓq`Z%vUQ\JHĵ!::B y@FN2_Hg|JOtNgge_@0(-5񼢺;JJTVzj F>̳gFG} xŃ+lEQ?- bI ۸pHrXX`2Y9z휊ey`|<\6OQUs pXfE(j ϟ3 Fs>@Ysg ~B1_=͛!jVժgF#{s{mAra\6\.[N`0&Y,_r,77y1 FRIENDB`qmapshack-1.10.0/src/icons/32x32/CutMode2.png000644 001750 000144 00000000441 13145236333 021537 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYssEtEXtSoftwarewww.inkscape.org<IDATX1 @cmZ ^Rbkley^B<0E F! 4v.l  ޔ%#ф {gHj;;"k.}r+ +`iݷY#Tw ev̠IENDB`qmapshack-1.10.0/src/icons/32x32/Copy.png000644 001750 000144 00000001000 13145236320 021013 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ? ?pSxtEXtSoftwarewww.inkscape.org<}IDATX?HQǿ|!Waxq-PKMY"hhZ"!sr@) ;B_K(ͻ{t<;<0+JxT 1Bc k3i Wk~ @cb Ll!8bc\np 4gI"}֫ 0oP,jZ O#B@!~Kܜe1ryŶ&` _1] $ד0Bz=C<>}[Z4 -Z7tC"^ 9Cdt.j`Tz佯9OcJ0{1#ɌBL{xyl.(IENDB`qmapshack-1.10.0/src/icons/32x32/MimeVRT.png000644 001750 000144 00000003345 13145236365 021413 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<bIDATXŗkpw߯lɆ,l ! с@@jULik<ƙZZu:BH5 )(%0 %;wo?,츳e&tw9{ٻbK2*,3dM:yLS8m%EtqLu+Cg\+PH)B|={ldUq0E% | p93qL_~#(B @(G'拏HX3K03PuXmqɪٶ. RCRJ6fK.B(×P4,^ f)Cxw#NҪetCg|vRX35>Ey 5-"/5ͤg;xV?_P{)Drݍ^$W(Մ~?x @V~uSEJ5~ts}J )%'*-l'^BDP h&;`J5^Ϝ?pܵYmuYw*g}|[P(A08R!P4 \x )C{w"Sݮ!TԮ[3tw RƜ1}9MhΈO` =ɳX@ܖ{a[1'!ύ)911'qob"ƤIXI}fjC58|ʥN<P7:T G10ƸQ }6:>ۉR!3*nfvGb0YoKb׭EP\E1޽J߽o/B!pbY&ω|wg,qJ/`cL`Ap'TkAgHIL`#u E BrP{g3zFoMlC3VpmR]Cný[L[S*Vwjaq,h~;KrZťD>Hҳ[˸Pk4mLh빎DoLCJ7 )1A0-PME4F* 2כ'Gޘ JA ~oHm;v{Es}?lɱ~yS3n [Fu1r@@-0#{SQ^e< & #g=@?67Gor+ 7C׆BNe-'i1-U*L= _[Kvm7FabA)n*-SW|L8-2a^n)2eIENDB`qmapshack-1.10.0/src/icons/32x32/Image.png000644 001750 000144 00000001762 13145236352 021147 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs+ptEXtSoftwarewww.inkscape.org<oIDATXŗ]hWggcG"֏"nRP Zh-5"*bQ) ~mCU,֖]h4iHf~dgu5e98sϽf0p=' :`IV/1Xf_*XLg)%JVѤQRӀILGS,9  ~y'zRŐ|E i{"PBz+P(:%c/ VV$`= P[bWYiF\;&sԒ+@%OhGAKpʚi80w|Xe;VA|\ו=k% @y/@ 2* ·(6`t`#_"vc? HssNX~O̥=Y*׆O;[Lq*_W>h*=օwg@Dn"+ԭu wvV|?n<-r pi .w@0Or>"qW3졎v30(s_jNzP θ ̅SEJtN? (vudҸ87Ľ/?ɼ(u&H,Ee<6Wgv~]@8! 3i<; cj8zZ`lCд)ri܀]"־%U7y`- 1&d 0IsR.ȗ ;+Xf0S/&|Cϟ²dIENDB`qmapshack-1.10.0/src/icons/32x32/Activity.png000644 001750 000144 00000002501 13145236301 021703 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs11#tEXtSoftwarewww.inkscape.org<IDATXkU߹3D tؚQ2l4%ZHDB+6%RhD->ƦEE C(Bb|Obc"p}sr9{u^{0%9Xs'*<2Lш|}riCߞ'݄y}_HT&LLSx n88~Ć LZIe-&S)<֬zd8=/EL$"v?V9wKRXȝFmXJ|urY$W/}/ju.z!Sq=؅g%+I] 1NY $mb^܂}h3=&nEZJ^x{I7$"oɿKa^j^n R8`,Lw)~ sQq-Xͳ;%cZ (\Nr)*}b.~Ix>`u);91:ޕ2iMFc6-> Կb)ɞ8>Ls>ˏΥw'VbM8£1?HIENDB`qmapshack-1.10.0/src/icons/32x32/WptAvoid.png000644 001750 000144 00000003310 13216234261 021645 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<EIDATX}lS:vlv|HBB:ڊ"m@dP3$[ u ʶ1J6ml:T,Bu $M!!v>8v>6`G>}{s^ۀ`=,)S `v# yMl_C`9@: a_mW@bPC5cgL]tJR6e];[֖6)B9cM$TdO@}b*)s;Dr_ ;WeKވ01}&W癉t_U8b[vx^Wr~F7Kx}U"k%fpxMQkymg͜~u6G4ul.AxEm߫#CUϸ_۳e7J.1U08#c{6Lj C2Tio-)l5vc"Y'k*,j_Uk#\-ZP?ϐ5ހOGz:nwճ9餖KĒes+ ,Zo #WUr?1a wj[wχ~]C6HV9Äm\ِ67<՛Fk;;6o詉I!2wdciq@Ho>_"dDVyҊ]ώ. F3/:ˎݝd`%wM.oT\Wsto0_;t>pں8~N!y1i,R@4IXi XQ4axf-,(e$Ihf.T !ϙř^Ґoa{JZ{%% b$ɺDc:L𢊏GWi;ms $H  +@KTXwi8k'MuYOs$o2&tU#BoTg93 |h9w%SиY KB?Lto$*4Q8fB>WxS8_I.w,<\唳|kpgrc$( x?+#SS4f+7w ḑ3-_9qd0x*ͫKl!wx{lmAȼȦڝ7vV( Dょx_l(!"GU)|sKgȷnO7 I^˕UӋ*]\TqSۭ pX%R"\[@BZm`};,ϬX ~{<[Dž_y+%,lRƹ3,O/<4e(S0-8}'O{&wYRR@I6`7P Ћ#޳0P:D"$xbbB?QVhxYD6`4gP^q{Ίi+/q=|Hǀ佮"hHIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcDistance.png000644 001750 000144 00000001132 13145236323 022417 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs0tEXtSoftwarewww.inkscape.org<IDATX햽OAw! cPK;J ;H:zZ "PQqfnf!$}ޙy}fv@:GbLHwqb:O'y XW~~w =yK-N}# ^&kFT(oo#$O@c`{NƸ<yf?|8}xHv:6)S9$d3 |z=I|4`*Ê?:C61 )$@3Qz rVߧr؄卨qnmDPbQBFQC1~B臥)+PumvsKf.ky,O¢/B+^< Ǖ (BBRUfd<ـ;^rLQIENDB`qmapshack-1.10.0/src/icons/32x32/ToolBarSetup.png000644 001750 000144 00000004450 13145236450 022504 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATXWklW汳]]cod: jjmM&(**Q TPDU "%iI(/v?8MOٙ?M+I8ҕftw;;L,aWGbZa)(?*A^&Ib}wa6.=? ˲[T,Zj uW}եQamܸ~L\I> `1TJ#8yYP/@*$Ƀ!eYL|fֶ.4x! 5 Hgp҂,@ ,wE0 igAo@Xd2KN{XX@?\.a4 xWqitvZ|PUCCEGim[Y\Ia>P+/!-˂с?NB!@EEŵ$>x XgZxZ{nxK@dC=$OTQϣX,p$0MEI!e+rwu1d߷l6 继[T$ 3433Ku" 2$I" R_rݛ6m&KR-n=Zj#۶m4&D $122REѶb jlllN坥RuM~377GMOO\." ֭[3 SN)c* Noʕ6IE!O>&UU$Fl6{CE[xQ155{IEQ3Mͫ@eĉ=tk׮8p@4ͷdYTUw붶\p4<<$K$OąuBeٯ$:wٳgkznS]Ӵ-Yg$`fgg/4{ORbQEQ^a+.J\r<4g%Ir[Pwj>+4Mn]n{{$$L&y]ۆa|eq< [0OQjjjXA ܩ뺿T*L\,8NaÆ B-[x CCCf y^a>r2|~bb54MCE~(^4 o悪kJ}tt9\܊.eEdVp8{>{l*++555x1666wv=z4=99K^A#e^JEY+rhjjrW;6 i^qWqb^VT<ϋ###E˲fS@Hr?D, èuekAdYv G޽{-} W8{Ml0AX d9IENDB`qmapshack-1.10.0/src/icons/32x32/SearchGoogle.png000644 001750 000144 00000003647 13145236426 022475 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<$IDATXypSWzzd@ )$@žRH &4ȴt44 CR&:4` ,-&L-Y֓nV~httssޅ߁:r,a=O^!mPҡ H@W ī0 b@ +Xp@pP? 04lga8v?( }@h#aX&@V=T":>X#a>Pzu=1;%A$~`jeKHPS=y bL[ʺy!oЮqbW%(~";6.#0+9h@[5 ƩpWz|!NmYW}}3l*tZ 97B%9^ oV14;XYY>D4b<39SQӔw%L ʿ0@9p@jу]n">/bNY[[#Y TYo.!T+` .%5PuN ny`9R1@e%'Vܔ1jj):oˏ-*^ک9= ;f'>J=+wIg09 &*A[|ЩqH)nPeCص&]t_Dv; 0_[y _$Yzm@6(a|A` pz|H)m ՞jysKi \6Wpupd!ugs-G|r v-GIENDB`qmapshack-1.10.0/src/icons/32x32/SaveGISAsGpx11.png000644 001750 000144 00000001446 13145236422 022470 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsrutEXtSoftwarewww.inkscape.org<IDATXMh\Ug&Kk 6m7[4UPEtR p% \fEm,-(ԶTU4 8vqΤdFg2 ˝s|{er V-CQ:x੩/Y@OOm rMSX#F9,ƾ51q[+GTW*7p`hGgg[GL)#׷u|4"-+'*ohɒd5y ho/tw:E$Is--~,wWwV{9Dw{m<)ڟs^*/2ZpiߢPd*sxs"*?&|*XL8}g?>EvE6dW(C\|8#dqONU `"ڊ`2?Ffo 7z+XBMlE\B Z1_Ͽڏq.!p/ [?ȿ  j~_Ё*{Y/7*FFIENDB`qmapshack-1.10.0/src/icons/32x32/Progress.png000644 001750 000144 00000000734 13145236404 021725 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<YIDATX핫N@) Ԑ ׀^ 0`Pk$:C@!8B0/CpK:.٦;tjw=3ssiaI`")~]#xf@5?'PGqxdtz@ƀ{`nPz,em(@Q}`@lguZ%LlǠtz<ˠ/M|s1>pi H1[@ hYLlͱ< s\EIX/b@Sc#Lw;n$ft:g_)Q`m$S8d:H{C0w_!jԣkZo_=!IENDB`qmapshack-1.10.0/src/icons/32x32/AddArea.png000644 001750 000144 00000002522 13145236305 021377 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ,tEXtSoftwarewww.inkscape.org<IDATXe뀿!M$6 6+LbZS"׏ժ妎VKc*Z "Db.x<Gs@}_M>FU\llӉ6W:Dp5|+`b(< Nw0J,LtN:|o x݉c<+s: >l y5{`s(M![tX0Q\[6`ۂˊ`kQg%[m5:mF &U˷,nCІmW ^ ~[vL)k0F9XWj؝@<%x.x1[c(x>8F[lmx%`x?`bĹ35%v!Bਗ਼ӂh3W5څm/-kIܚ$W`jW5ڬJ;lR_r6)x%^M>~l\Fˉ/jqI>KAFk&\6ю<mr j 7~ꅏSGfĥ/f1ި ]uXpG_FD_'f~!Lz oѯ5׽b~hj,1i8|SgaXUaЁ?aybyh{=-؜52x,3FQSLn_'!s#6/zon˂3[ݹɈL=~ߠ+׀ rWhrbkavY|;v~e)(k"ô.)Nk\fVұ1WnNZ<2_a~Ļs*(f3S޸q IDJ2E jp\g&^-LMU5=~{ )"'}-?;#vZZJ&~GmG;}7?/`IENDB`qmapshack-1.10.0/src/icons/32x32/Save.png000644 001750 000144 00000000563 13146511336 021020 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXcd`h0i -g````Aq`eG>e()9Ҽ 4q0< F0Q:``DoHHp3psIJ_3xE :FW@k0Q , rrT͛ _  &Sa6lڵ #2/ /a#uII* **;``aaCV:L_pr23prRRd0Q\/eksIENDB`qmapshack-1.10.0/src/icons/32x32/SetupWptSym.png000644 001750 000144 00000003552 13145236432 022407 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs mtEXtSoftwarewww.inkscape.org<IDATXklS'ıߝع00DL!TQt4fmDES;)+j u0u_ @$ĸMd #I9HHDZc2d)#=ҹzsG_rf{Pe1( $hV`p4RJbB1xCW IiU !~m}Ox\YK @ad<<_(/ pPA`GF".=R(q|<~@٘.LMڠo+` @y O `*LTQqҵUijO/c@ < }阒^‹s k:X`L TE%%f'0 P`}LIBdn(, P}~V`Xp8ή]@^^Of0@r1W`7z]#Y+8$fdggeYVT[&h@ ]%mwU*U}8*ݿ9::d۶m, [8>>^("'OEQ[PPpuҥ ;::Wh40 HCpYp^H ]INN;;v쓂lՊ D"dYVljxQcrX,v0N' tSMH$v^o$I ȗ/_ݸqq{{{hieeeEuu͛k׮b@8":)Y(jNt5vDBF$Μ9?66j-x.\x֭[a- nͲn^r&f >`/ӘVWsssUdK@IGGUV?'ɽ`WRwvvFnwޮ]J0.]$)MvL'F8uo~h8~PL&ADөnhhX(xٌj9|pW(>p{2|:@$iD"ES ^Tjjj,GE%wM477`n_^WWWkZdfVkht\( 6d*(IAܹsM@fhhh(N$ō2 0<2o޼5UUU%CCCT*EUUkƍ.Y۫xRQ9P"90hq\8N(~?~ܓH$:'N 桡w 6mh4P(4.++|ǁ@W)Cpk6@W4=3udR(//MRC@w(k v{{+Vm6n^uuu$Ijkkw[,]!0عsFY'|>e:nsİ(k<boZhX,yPH?22r u?g [վɲlؼy+n;+Lrؽ{%Izx9<'rMR7&f#l4`P> ǮP69 bաk-&N:dG6%`)$%J}a X#zԗw4w)I%."F 6Se ~)PR)+.h7a${3lR{ PRI% @c)m),A&<#L$|[5{I"Iw^d3 Mvwgqg0;0^gI)t.T3|)mYrjg(͞SmE6 {>F<*" .IM-y~{Y®M}[  }fZ[vaNnODExItJaH= 嶉*38N\[xQ\_a?% ,< pҘd`akၻJc)mk%! x%&"-~Q n tt\B瘂x}~ui":ʰ iϡ;-/0p D'7_D׳\%CM0"=x Ip5B-]NJ*:^4R(ÍBC9ĈNjޘHO'm؈"yĵ8,)7} {RӠoM.2 s_(`,50Kޞg5\%1_p PuSb_`p%a]4i*іD[sTrI+$ta $Z(50$J@%w -R$A*De*~mShQ=LP=H΁qTB( Iq!*;(lT+5z'Z4Da5 !|%V.,T>:@z I +Zg_ u|@? [`\˧~cquXL3fJ8m.LsWb#RI0z<G@@vpN}@ 6n 9#m]ի8Q#+>?`%8lEĝwaބ'@!}`?}l|IENDB`qmapshack-1.10.0/src/icons/32x32/DeleteOne.png000644 001750 000144 00000001333 13145236337 021766 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ڝtEXtSoftwarewww.inkscape.org<XIDATXֽO@o|Mq,!u]:tB03wԝ. *U D&$TDRR8 j+3x(!ēh4㯼􉉉7D+DI4d!ijeYRJ0i&(I]׷dRv⢣iZ ;82::" 8woknn`%ZcEU#xLyFѾ]esséTA9\F`,0}@u \ls  PQ 9ffuUI̯ PBf~Y7<@5AʄzpBpD3?CpjK6Zn< US\ o&@4@w:e8.HW  A|*@ NFg = jk HÕP!cȺ`6lB eBWZրW8 s`?@u Cmlʇ ad` ;E[.\@4IENDB`qmapshack-1.10.0/src/icons/32x32/LoadGIS.png000644 001750 000144 00000001643 13145236357 021352 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org< IDATXOh\U'ILj6m-.vci RB7 ].ĕNh `UD VQJ1 @KmT&1<oL$oLz;{Ho:nsDP[ƴeƵa>M VPouX#Qgch bouX)I? >ܱ\@N/&n|+8ǽK QL.F0-@XiL ^ɔzd]^-~yECXЀD7InH?`BZ܇]؎-ȖsmtyoS؍%Qnɓ9Ma0 0\&؏S~.\E᫉3óSu sL _.όL{%Z}Exfoq39D\*|{u0(.l+% $|mx{*w 9<'NSk]IWwT% !.XDZ4ײ-JnƵOKsIWj0k Mڍ͔\)62HFz  >ARYa> oE߉2L'\Y(=wQM@ E2=ڈ/;ie8$N^0XeoIENDB`qmapshack-1.10.0/src/icons/32x32/SaveGISAs.png000644 001750 000144 00000002453 13145236423 021647 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs--LE|tEXtSoftwarewww.inkscape.org<IDATXŗoLUu?s v]**eHM3˵ld2AZZ阢10.\xrk9ۋ{1tg=o9>w(0l@1lEGޛk!#cfPʫ V&EҥCRІT!x8yOD^u۶z#$n[>>Mc{#-(u9*uUPSb[6ҦS Ddڡ?8@D0mŋxKG{(PX" n5G@淫J]Y9k%Hg8~nu%P_>$9'Ɔ$Hnfʲj)GvɅ8 7TƎ+uT)Wdd1U,ׯt^y], ɜIQ SII{@"2ׂJWH@" -ٙO0@zTx]DF;D$2VA8KNxoB%-$ $ 8"">sSs7@a ;KA^ ~q?=?nMؔ!rQJ5>ƀ"x;k@%z6Uy@kqZS|3\3(]^*Oc)@>BlN8ڃct>TLmBMEq㲔RchFlu½8qDWp9p@L f77DEo`]&1amIENDB`qmapshack-1.10.0/src/icons/32x32/QmsProject.png000644 001750 000144 00000002340 13145236414 022204 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<]IDATXie{fZYZYهPhQRI)"(w"!++,ȢFR-"hl1 Ds7sFgyws^GCpﳜsypUfdNA*We_-|)n x=q 32OqLD>!T:t#~'ZMRs.ށUtN(c_;)waQ"ćNdu PQG)? szP=ze@q"d"ׯ i&p , @Q"Iu>ٵ"0iJ"ֶZ d,:]u~ihq]/@N9$Z^d_}'3'h. !0:}$^@y pfJ 2y\o/-l)L ɾAAQ+.xPXU9[DHa:p=P)KvU 0{D[;pA<(f m YY5OC6$G&턎 ahuLţ+GdWpXllmӮ2;0c٘DBM 7ڼ=nAe ڪb1NTQW(dbσTj*LQZOmT{'J휽V]?$\;N}PtM1Q~01g#z@wqj&MOa f¯Ht$L ]0a-Ăzu`/,:Yp6_ /g'KvCBl6QV;0'C ^* NkcvI#/ aL $&H8et$N՗yr;/+ u`IENDB`qmapshack-1.10.0/src/icons/32x32/FilterModifyExtension.png000644 001750 000144 00000002777 13145236343 024426 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsgtEXtSoftwarewww.inkscape.org<|IDATX}lWoZk/3Ќe&81dJ`Q.,~ڧeĩ:'t|Nca&%9VGdھ?޷|s_>u=soϣU%>$|uj녀}㇮A:$3>%\dLO&jrPh;=aTzgyÚ 3I/ 2EW0 Qf: c_|0PͫVg6} %s#XC]m/]DA=YBBB≹ ɦ ZIlwC{!2]MlMvS`Ԍ͓œL,zr&P qޠi\"]~Bx8:cױ]BA;/|ˏ{#IYcXGbINMeDOP4Lt sBz{BfmқN}23>fw5Lݝn(SjֈY+{ON?x2yi4ڱG),\Xá:؆$'M/0,'([ KdAk!Ζm6 wL6{z "Z_7 !Cƍ+jYt(hdAN6(QdܝVGQz X6OcA6ޡf%dοWo8A{y;qU R_XO2vnjKH2Yw{{'$jBEEE ޼aHN'\CL"fm-aX nI B㇌_EQNO&""ZX3duُ+/ORHtʼnԾBsƷc1fw΁;Χ?~k 'Ġ)F@jIꙗ'øgHCƮd\oCwM'iz_i<+}kxΝCYO!g*6uM`6^*یXu#^8hB_Nx}J&| ω oO>_:SAk؀6<<5Q"`9+5G)h3!GḑƄ>>+y+~ZHt$5 &܆pSaAy*#yӎƒ7* n .?B9v_c0`ʆUzZR>ǶpqRMiƺ__||(:Ļ}={!;Hz,^pSzK#7!g_y9^#~گ!|(2IENDB`qmapshack-1.10.0/src/icons/32x32/CloneMapWorkspace.png000644 001750 000144 00000003210 13145236316 023470 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs B4tEXtSoftwarewww.inkscape.org<IDATXWmLSg=oi _ snS;uTDn΍ltcj?Hh\̢p2 : :,F6up(4C%`8% EJ=@K:$}>yɭ#@2 ;YPWrCÃDS8c˄ 1'P,?*O #TUڵT !a`XNܹ;9dfNI/,+k$'f|vnTRQTzCs4|YUDrP?ޱ*Ifn|]].QŚVn6_d==$3D|0*jyyo$?3*ɥG|sX]◸d&E#Ifwq(If]s8V* @y}.;n-h̙MhmM47w`FdIIbƿgL0/v{@  N =݄de@k]$$D >ݍ.47DRR<-V$!ą@Gv~5667oZzRKJr!naFFNǽuʂJN=ccsk92Eff1Fw7| *ʪ&66>CrĈ<(!ì yS$gixM._`03$+7/LMSjDzyy YZz11?'. Qߛa6qv7M+%IaϊcϞwa!YGE]Atv|L1+.t7s/%"bbŋǍBY+J*ϊ1@RׂB%? I: ^_oj9ׯ[,xi"pэ#Gjs9KX# :[71fL&!mPRHJJnsu`>B|ɰl7_gRz\Yy…E71yr! (;iDz5vf$/'k}Eq;>BTvXo۶S3SR~Dj(| g'"!!:)'7fYZPEқ~Q=m1:ZƂ5W{wWdE¤anub{cQCq\ $_ZԻ.;nV'60H.pu^C  $ԅ/5Sk$A1ŅR?0CVA.>'~8ߪ< ؄pDm7Xcd@reI5T5 },5AP Dg0HF&  Sux(`Dn3-g{4mǑ۾HDL\svaVyCk}<6U !ZC@0iX[WQ_xA8 (zԁO݀-O w\\~ZO3c/IENDB`qmapshack-1.10.0/src/icons/32x32/SaveAllGIS.png000644 001750 000144 00000001365 13145236421 022013 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<rIDATXOk{ ci 1h$CH$LWvdG4]رbJ, F)\ e1ːi& {baL󫷞z #JWbMe[7(sWWCn`Z64eXR8Ja``D}7(/K~**e~OmDݻYdZbʕWӟ~@Ne?ZZf\R+l"h"^yyn<'yO`p%DڷhBհ4=~=x OH~hqvutʌ;~g PS3Ig9-#)gILe(ۈi I37J,G1zޏ ^KAy^"@N6R_ke oG '[h/ 657䣑#Hf6tע.b:f&\#|smi6'P&?2ػPe>A?Л#ꥺo2&bSg7. [&heωb :<k :> $dIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcEnergy.png000644 001750 000144 00000002065 13145236324 022125 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsbldtEXtSoftwarewww.inkscape.org<IDATXmhe9{q:͜4AK(C[C] ͢\h$!z H JKPSVC$o,QҔԉ"wY>γy}{zs_M`"݄1$҂-XFL#:4.5 n6< %  &gCA!"p_rs |). |^y5nK4+@%Q2=Q9ċZN0$sp`'*p_JP:;OWbb{q_!9UWWHPo4sa͚'wq^cDr<~,qz!/F46>>Y#Z[ۻ3+Ak-8]/"WUbOٴY}3܍y |3y7(a9sW͙ gH$z ~l3fda-!`3v8J^Xl&+[9r.o()v݁dA km;ԩydo^o~TaR}[?qD~$ `IENDB`qmapshack-1.10.0/src/icons/32x32/Error.png000644 001750 000144 00000002332 13145236342 021207 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N Nw#tEXtSoftwarewww.inkscape.org<WIDATXmlSe}uok76&Uo(d(s5~d.!b2_b$"e` *JH@.Ā]m׹ㇶuI=<<ڰ `g==:tPՂ*@Nj,P:ZȊU"/Ŕ`uB*UL8qnC`ߴ WP %.F:z5hpIFT/ۗ8,_7!Ҋq^:#IhJA}qC"8",y "9EDYFF;OqdD~@ /"!HɃܼz9$\n'Gh\ڻR$ƣ8q~𕯢{ +HϯZZ 7T8!IjXl0S "aЈG6NBASS+Hslqksa{>\tiOwsUqsNT{:l_ȻDlkcrif<}h'o057EX(p9FKuq3Bz'>Nĵ"VQ qSf̨%`gDLFZ \Xv?,"2gή (UycI}1:brϖe=,i/Dq éz"]eUX2Wzq 4uaؒ?%jD$ 8YrԵ8+%/(S?j<~6ͳ,↭#ݧsE bcuvnzj:1;'.?(_nǛX(YJNyH'^ˆLۮ(:h=IoHrykt༜Ŕub g4|$^oxH'ɹķ }էkIv7JߢdUS\/.rTXT O&r6UNz336z% )UH tS:IENDB`qmapshack-1.10.0/src/icons/32x32/ActFoot.png000644 001750 000144 00000001136 13145236300 021450 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsbb8ztEXtSoftwarewww.inkscape.org<IDATXֽkASkV;ɡ"`aE1wƀ(Xha#z ZX ZKTU5@pMk"E|.w< -Wq#nC::* Ad 0SpC*CPAP[E)j_/5wwKcK1e.$ge_X lZ) ooc\U[ݙȕ~hØA2xYpUpA^maMTݎ2JL#tf<qʒG X:&8ҁ[; 3UXN!cH\ ubw"AO2yJ#)>fi\ٳXV% w0b%Eq3 \(ȗmMӬ;ag+rHoe+Xsʷ3/мeWۚ\GL"dg)[_:m8d #~:DSۂθq~Odi\9*xb /!{6fNt o._(~(v>{9Q_)$emO/V& N,{FH?,j *[ƣxFDFO]0Q$m02J2Lk%ҒoƖ1籁-(֋ -zvlntռaZ^L濉݆ٺ/g ꃀǤFk% UHr#|@x.gFciN$^@qu.y=y]_a ڂ)QLixԫ,=/17> [IENDB`qmapshack-1.10.0/src/icons/32x32/CutMode1.png000644 001750 000144 00000000532 13145236332 021536 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYssEtEXtSoftwarewww.inkscape.org<IDATXұJAoִcmYA`/!bem KY- E3gs/AAfbr%`ׂ7TyCd {-;63yڣo'M4QX 2=|Hd/ 1GT쫗pH|w l)W@fyIENDB`qmapshack-1.10.0/src/icons/32x32/SmlProject.png000644 001750 000144 00000002306 13174544135 022205 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs [tEXtSoftwarewww.inkscape.org<CIDATXou|tbponj=XY=6uMpsZ2g3?y>^;.IJ*_Vb2d('"vJ2׾~[fKLo)dƶnj؇;<̈Uɜqbbyb,Œ{M{7fNOBm&-cjn9VR=3+]F9Y?Ef9{p73zV2vMlʌ82 حtD' yږj/%| ;25?[?)Xfoԇg*[.q,B !IENDB`qmapshack-1.10.0/src/icons/32x32/Undo.png000644 001750 000144 00000001576 13145236454 021040 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXMh\U$J"bRTU]HD(6?+wPs"E(]4.*JK%MH56Lr纸&if&S,Ϲ}ϡ6~q\CT Fi' W$.+rQ&gK+ ICCto f%Y'1 0^`˄dĎ?,3E2c=!苹{ea$,1ocVb^f/Y2y 9PfhՑ|qĕ!. %/x L>c.Y B-e3[L" ؼZUԩ[C&"Ry_~r8M=2qgzu qW`3Md_{B8Rمpcqĥt!$,l3T>(:Ӽr_L㸈ūLTBNJvBi^]rt3?0K8 s\ CZ-LUl1k d_DB,>`}9&yGv4-^J.ߺ5)2ARD%z|+xzhEYvfƎh-p-iOmDS9k{Q$F%vg>U$MV'B=똧nE$CxZ]z)z~ۀ)? c뢿No掑n T  0NVHsOgeIENDB`qmapshack-1.10.0/src/icons/32x32/LineWidthDef.png000644 001750 000144 00000003571 13145236356 022437 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX{LT0Wf3}ʭYZbeMSe ٥Icmbڍ-Fۤ51qfwUw1]vY:3l`9bj)"h'ys>fȝ.u\Niiȉ]Y .ҥK/Ϲ\oe;5kּp8vh6MݼyrTQ/%I rzK L&o:M I .Foڴi d2L&澻wfQZZ+W"kO"r$IV~Xjِe7oFd$Ii555h__d2yi:wΝ6l,[lQ|E---ʮ|>_ REE{ҥKGGGGh p8vE,kԩS'zF BUUp8Y,U˗/O n˵=//uYd!tF[lYfY寃/W^}EFoׯ_O=x˗/t:BZigff_>M9sx=ñ555탪N\2#55X,FZZln.T.}ŞZ`08/֭8vOeGpp8wuuul2;LLLysGv+(#EQDףiiO$)m6䤧`0L[hZ2000*9UUU9SSS\v- G6nܸ\EچE zs999UU9tP055^"\9[Ǐ^4Ѹ8ɓP(_[V߳v ɔ2>>> t:wuuiX읁%Y$e2LoK$e{llIQy>n4?_YY!//ϔ*8Hd؉H$齭[EQ٬VkQ$i!EQDQ(--- 5#33622|TEQPP`RUϗ鉈Hyyyn@QwfR^]fy 0 8g84JA<?\Y.P}2`}!n`5hۡZ?zTh4Pڋ: kF-z*).tҴeeM'f ű7M@ x[AGƣ ~3xaކᴀ_Ya| ZrTY1BK[[Jӭ'O(ZX<[pR=۶M'#chQ",C[!x֭&nc:N[[{2LAAgǰiJJ,s>3yP2kE3KbӦ Դ BBՂ'aa#{gOqq5{dy??%Kbڴ1PS;OəɤCܼssn3!\ ({(*zÇj$%) uuWVVʕɼn$fs [dR_A^^43gaɒpeEzb9O?}P֬9?aΜz KiOj  3s;;իf$`} IvvgnȂ$*OkC`֬<.')ɀ<45d˰U  WfM+(/r s! tv:smEvwPY%::44trc>nh * >>UR{/v֭GTNOclӧTc)ɠF (H򦰰I`:hs&2;#[7؜"t{7B(@m$IENDB`qmapshack-1.10.0/src/icons/32x32/WptProx.png000644 001750 000144 00000001707 13145236462 021551 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<DIDATXKk]U߽iLi9Q!86_H'"N`Pk/HUbgE|ւiR}&99ùg]{!b;%p?K|zSuw3A4|f`o^AoZ^ ϘM>ţؔ>+#Pp:GAb}lΔuQL ֟uJI0+Q]G' ?:l?\ͶJ,,=v\ s-~ceb:x3 䌏B+x}#N+Ӻ2T|X.nΚBY';j8&nSמsȦy.w֬Zf8nБ" V6~/w8 {Kq/Uet ?)nhVȔTم3Mh wi]T\?S m\M 3ҭaZi$]ƝX,~=GiTѶj\h[`pozkLPS8#x2kDuЃ;grFN j2RDc Un}et$g 1me~f̷ZU8*do6$lŐS)8/[)>c )<Kx!x0WӗL`赼/F1lԶtd^}J~ѬGP_E_ZoWLGMGbt{nxXMuq4@3Yq*h TҍE4OKV19:IENDB`qmapshack-1.10.0/src/icons/32x32/AddImage.png000644 001750 000144 00000002130 13145236305 021544 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs+ptEXtSoftwarewww.inkscape.org<IDATX[U>gK3XFj3ᠡC!KIQTnT]0|BA7+"Dbqs )5GP'{8G眙s\/g^{O ]k-ˉ-tnB ;XnGz=N:\Ȳ=O_ӄjNoچ]kvX@NT&8Y $r2zKͱ/{}qpCYT-|R$n{?lIVږ/BEn(Bm0!d?3 QْK<آRQ}X 27K~vtʾ9|XkAۆrJv-ӲsVaH?>ӽYv6'nȬC^wyϭ:Ke+La:* Onvr=u1IENDB`qmapshack-1.10.0/src/icons/32x32/SelectArea.png000644 001750 000144 00000000442 13145236426 022131 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs 9 9]ݳ'tEXtSoftwarewww.inkscape.org<IDATXֱAoe(yd z1 *VbDܿ>3)LJNs,&EAnV:STUIH-.[B&Ih^9wtÚhС@ @ub9gCQmaIENDB`qmapshack-1.10.0/src/icons/32x32/MySQLNoConn.png000644 001750 000144 00000004465 13145236370 022210 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ?tEXtSoftwarewww.inkscape.org<IDATX{pT?޻MyH^% :6EbA+H;11 c T JL@/y&d_?q~gw~s<7ArjKW!QS} B dPtn"P)"r( 1XpƹH!_z3BR6tan.)X `THxK, #C $'IW+W5r kصϳ8wnWb1c03DěR|=ǗClH EAivgg-MMSv(ƦN~Q=f}Ө՞6Q "H TÈ ŬIرyzs>Z Tm6wtaURHR|a*O~SmE\訠Hu]4kO.Èf̪by}y.=v@P7QEϲpjن[zH/ ͣ~Y5]<6s\ъ5Ph:JV `u i?t@)xSԀC.RVl̜cݺddzS`+jY~AtJ/>CChTVpm!=3)|Z[>ayF?+C^c795>8&Omy1- !f@ r4>Y芁QF#1XvӻQmcg񋕷;Lz9 Mmz XݩS]gP4v$&l8)7Pno)(YAA&i05Q|-k{:~0D֙Js Xghc%gXI:g36s1(4a h-u=<822$j*lPDDTa 5ddY+YNOEJP5fhA tuwj7}z [HP_p8<ąiN(Ε4~HC`j$K]X<c] ƌqhF#rr+YYeXINE&b\,嗖ƅ3s:KN[1Mn+8/?*w :PЄk g%? <;@%v>wWLF{_&CwЄJvfm)RhLH7  @gz("F˶}QɖX.ǹh>:@8)ms/ʺ:RN|S*kee|`~yz.+w+YN %L.ɓ}c=')meȔe\\n6JHFkrgK!dqqb!!cdR{ul6G^&=}KL:QX؈+iks2oc PVSb?6!3<#% $ރ7͑QT ȑJK t?Ɲ)`3!buSΨv/y/w7:З-X́E,r:pz8|nxQ)@}xqb+4H3{@v7؊ 1ȹi έ.274SNѣ}`jRe >1WmܓW`xˆM;< 4ZFvF|ŬYEuZ23KY RƲul~h`rS#RMU@\Shfj@ {7 B|%(be"v}O lxm:'?ah,A=dR"D{9 1?WT@l$qcc6 Ф3!UN5ji'j%{;H|eko6.+gY?!`d54-;cc&l 6ih7ĶBlOˤ89Ĵu]8~wôYN(x{] N`R5c 'JNbDW !0+:&w)^䙌n/mv[vP=MԄ!L^xBd !.~Σ}`ߴJU~CM% ft:G )Hh!A| _VݲmgKZGNo%ʀ`C 9IENDB`qmapshack-1.10.0/src/icons/32x32/ToggleGis.png000644 001750 000144 00000002152 13145236447 022010 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<IDATXŕ[Hw_.x1^6^B;mt@dèPێ<8 B>RNaXac>(U0Z=ؖEn$&L4=̹|@9;ۘ~3"PH`R0&/ |'@G E fpIi &,wZ L&ZAP/Hed| n* H"LOϝܭ`$99ccBd(3DJ%OnW=sssx^9aDp S)[ S\xΌ ai?ڎւB&奒(º;tx~?M5CafGyT0$I HCQj kr Fr 85g5"HJ6 sR~Ӊ2]Ih_hz22j\|"\4T e9ec=jTW7KKKur0h >JvZK% ~4EZͭtхQk\W<|tEXtSoftwarewww.inkscape.org<wIDATX{PT?w. -Cx(Q2.[`,3BxZpׂjrS:nl8$%9$ ̫ԽGf  k{y0GEdmZNm~v~q!WjAA7@btMpJFC`2n6Q>)0 Sџc~#0X K. 6) hvK%,éclzԙYNAP1Q fI X d50@ 0 ^%ɄMjIļ(y(s~EaaI/=k lak$ӯz$ >>79O\VƏ&33={=7 DQwzaweWL C̜ӧ4iy; I27CgСu>]5vƉ Ix4h;)ntZ>~ C?uqFQcPkDxPy߿xErB}Nle깨&!Ȓ^>};7q1~DL?%@EeYWoh#bW*jЊ YM6hN;DM13/>6m=V "2yO %HI|{$'%ZQ{# 0arrjw0v/9|x~/>?dxMgz266;g –-0,^YpsŲe1l_r^{Pjnn kוTaK$+cٷؿ~BBX *N& ~w9.r ;M y7lZ,-dwCEZuәpv%XmPoUC jF֬!NSUNT!Jth+GԈD CL^cW!b¦w u|RȽ6ROjSvjTЊ`pSnM_B߂عН5) ue<9,OYY==ht9C=K`N2xNZ4i_E 냾?N.U/梷7YzrA~(T owIݓ~ܢnc_qxWs,шʳx0tM醖e$Y毂!y Y0"adHdlģϓvdv`?:S+.˄a@(xv+ 8GBJ.#m{mYIENDB`qmapshack-1.10.0/src/icons/32x32/SaveGIS.png000644 001750 000144 00000001365 13145236423 021364 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<rIDATXOk{ ci 1h$CH$LWvdG4]رbJ, F)\ e1ːi& {baL󫷞z #JWbMe[7(sWWCn`Z64eXR8Ja``D}7(/K~**e~OmDݻYdZbʕWӟ~@Ne?ZZf\R+l"h"^yyn<'yO`p%DڷhBհ4=~=x OH~hqvutʌ;~g PS3Ig9-#)gILe(ۈi I37J,G1zޏ ^KAy^"@N6R_ke oG '[h/ 657䣑#Hf6tע.b:f&\#|smi6'P&?2ػPe>A?Л#ꥺo2&bSg7. [&heωb :<k :> $dIENDB`qmapshack-1.10.0/src/icons/32x32/TrkProfile.png000644 001750 000144 00000001734 13145236454 022210 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<YIDATXOLg?&Ej`/A%M Ɠ''Cm.<`rОHV6z0 38X%R@恕9͆@mΔ?]*%?{vp@˾y~~(=i|>TU=pCNGOO(""x&144Duu5_hkkCUUxэ0 2yHtwwxr9  -AQ333xޢwvvҒ j{@"`nnX,bcccE0Ll|@MḾv@UUVWWwl20 xzEQ(//H`4X,XJBz&''x<8$ɬ\II f}B ^Fv 4MnA˕5 .7nLH,zY\\әɯ'fZ`@j hllp8<$dD:``` MQD"4VΞK^~g--;Ν;w~޵q w~ɓٷ[/sv$Ç{2XZs7<}wV>o67S\XXXɓnN_[KRWgy=t~Dûoہ˗ٳ7$*]]… 6 q&`|ׯGG2q0RyZW6[y/V&9b`v+**y:o/㛤R\1O?c>7\%~nbC핇fnW/ }HIENDB`qmapshack-1.10.0/src/icons/32x32/TextBold.png000644 001750 000144 00000000766 13145236441 021654 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<sIDATX֭K&Q(Ţ`%`ٲEP F ,l5Y" &Ŧe7,&(/aa >_0?νw9\jw*h~k? 0VTrO/rRl\g4H{'$KOx0bJ!#2bcş@/I+ZCheh2}%v<]0Ժ;[f}3y U jŰd6DA"i^G1;` DE` _me ehК2Ѐ $fq. ыyW^˒ΨJm,i1"Jp/.p,66qdTb`IENDB`qmapshack-1.10.0/src/icons/32x32/Move.png000644 001750 000144 00000001520 13145236367 021031 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ? ?pSxtEXtSoftwarewww.inkscape.org<IDATXKHTQ8i%AhiJEa+\JZTH-"$!ZEQQlIgN_tgxmu}=pϕYՏ#$a*Ҩ9@@b8d$i氺4\o@/(흼=fRc68oǜ$-@M~tXTz`|s:#,4v`A'/ yKzU\fM^rLu0N_{%3ϏC%u:|@7rUXt~@Ǜz_UDFo kar+m ?@21LG{IJD2̱%zE&B}W2Cx #@;ę1F2U=@Na99 ~Hݹ%ؼ}_*m1 BU":מEB`T5*BbZ I8UƜkހ%3?tY6k|N?ig`YU@N[*T- 61E1>x(EHd1e QGAAʫK1 rΨ:m>=e$IU[pq+uVkL\_ߔ&}5`\m$8><<}WJ ;;;l.$`y2IENDB`qmapshack-1.10.0/src/icons/32x32/Cancel.png000644 001750 000144 00000001475 13145236315 021312 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXMOAv]V!*$x=h⁃45Q&5F?OxA7OHQ1ZӺ]۴e?fHyyf33H@#Ąc 2L4 0]G"l ]O|R2e_par8a@,8ྏ p[)s`;H G  @SCD<\B$TRːS1VOl@rU"m[Pʤ= |1HpD[_ fUO3G efW`lê&m9uxS"/%&`2ZL[%R(TD}eIENDB`qmapshack-1.10.0/src/icons/32x32/ProfileToWindow.png000644 001750 000144 00000002012 13145236403 023202 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs P[tEXtSoftwarewww.inkscape.org<IDATX_LW?-ŕs{Y aaDא)Nb$|j%y#݃Y!*`KҀ(,Ђ)4@U?= M)es~|νTU=lII9Vڵׅ ~ddT8)#r\+ QسGFӁi;w~g^=N !"̓dgW`chAI;jHH?y#[l瓟_Gzzk$򥋝;ٿ=#LL{Wb6r䈑-[(,4kW]]}}{VܸimKɍHsot%''Ueq(8p`2pv'## T(러<+tz),4R52==2q6mjgY5͆_y"BOju;yyu`;j-wo@-dgW35 ?~+t:;fZri#nwr/wwÇ ag۝Q'G}1`Mpb[~t=h}tN>3g|Њ訋⦘8N,AGwwOXt ֭KN(?ry{PX$$/eefI ćoB&IENDB`qmapshack-1.10.0/src/icons/32x32/TrkCut.png000644 001750 000144 00000002702 13145236453 021336 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ] ] tEXtSoftwarewww.inkscape.org<?IDATXklgӾ=PzFuU cnfcs.F1fL8ؠ,$pn+ =d-Ouu빞}s0e!c4!ьz4ţ-8.Z԰IaZ*d!.;d6+m Q'w`אO|jB *1l̏ 'E6ҀA穚~q1.6܈! `brWps{zu60ҏ`j!(0Yɐw"lS&2.WXď3"ND~ѥc j?)+> xR-q?к$>9jװ+R!?)s g){[ϰ?WðNnxE]^:'r7eShj%yR6謏H34I+q[]L :ԅ[YDAv^IT h_wqYq )fTfƇ;ntFܟA#yG29>{V /Byn|:n4U$!My9zD3b斁˗?f$P)tmQm%6@A.>Ň{.I/'\LK57G>fg7sq"8ű&Z<؇HJ1΁ǜ={VAAg{ e#f=%ʡ>̹-v5ѹߒLf9}@{{%o2cE6K ?q8ɝEf15NƲ@N\./ }$}ci ZI?\RȠJ0  $vњ%yU&?#Z툿 d Dϑ~1빮m5:19k5^8aw.ejWQC3 Bf#O%>>7؅]ńv.o;)N;'Hg$cC_aÎn,s*oxEIQ̎ы5Z#|;e1'9A]7%J i{~>n`uqHqmLy=?:f0-0oL Awo_皱j!x =|%v!P5uMzK~ )JbXQw3{_f&]o E^•!9f0!z*^2f03aAYRl)F4b^)P™d adQxב|f63^țF ]|;JhHБg_d,JSTX>Hk g.br-T3E65rV:K&qEDSi95x!R$'v ,PyehOyW`k]Ay_m^LƉiSCT lX7FXD[Ko¶) 2i fr.LwxBswB/( 3, Xr|hEe$SKDt/ILI /ؔ*LOv_7 NAG[ Ί="l8+- ;v1:,ڋoBr^8AC.H60,ErP('9KR4 c2hxbr?=rlYv4Q!5YwYɲQ!5Dw"bzT7 By.mHk1P>UTzMCh0"SyP ;ٚ7ζ}7݆ ϤEtr5£֐y 0щU%*Ӆ\E41J1tb`lF.VG?hr4e(eJxҧ'x ,8e/wmZ^^Z8oѷ)BdQ%͞xG+Yd^/ 0ɍ鷸5]_z]ilz0GN1>#ՈlDaw-4]ND8\'7u:\R#kE̟!󇡬aǮuca VIENDB`qmapshack-1.10.0/src/icons/32x32/TextUnderlined.png000644 001750 000144 00000000600 13145236444 023053 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX-KAUV5f(7˘nYEQAї W .씹{X7a󟙲uj3I4h֡ @( 0J`7ʺ/I=['v`+o67Ϛoa?_<i{k_UO~oe`Q&-B} f=~m4wjLhM:SGsw6}L5IENDB`qmapshack-1.10.0/src/icons/32x32/PathOrange.png000644 001750 000144 00000001016 13145236376 022153 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX=/Q{gD#"*_?z #$z"!DA)4H`3v6ޣQ=or93}̙3c:>LfrkfC" aܬLT()_ffX@OC L#Ӝ} #Kf0o\nS+FMQ6y &R}pC1w?J,yZ2G܁r*6cdNnA@Ȇ6.Aiƪv"@ hwz2_0h7 + /ǶI0V8 fv\qsOA @XPpTU"*=Z^jH}d8:IENDB`qmapshack-1.10.0/src/icons/32x32/PathBlue.png000644 001750 000144 00000001027 13145236375 021630 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXJBAωEEDB-MIԦD-ER)N)4=0l&:mza`އ2J pr0ߥrXg_] !*0P{V,-sPD,QEx;e@bF4,eMe`oi pzp`ҹÿI% @lV%W 3T*%xz 6tA!*!lwPg Z&@·l͂(,xG&X|\JV@_C 1rC"P@{Š|% w )ޞ@.al7oܧSU.'1)L @AP<]e`+><v nPaJ>0Ʈź+q(2pe>Q0 j/^On}#jj!x}n«F!@ƗI)F0p0Ul#6أqs!3E+P܈[~fΨ)! C6.-v\ZdF䉀 p8.#5ȂޝS@AlN3BJ9B4͙p'p8hٷ !GU qIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcUnknown.png000644 001750 000144 00000001212 13145236327 022327 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsFFU?]tEXtSoftwarewww.inkscape.org<IDATXkNq3Ba-KɒHDZJɅ܈5?-kQ "\ieD%p\lqyvxJ9=Of5Q:L |$xo 8˫o(0\`bm?p{if(diƱ8+W1JkcҒ3<J4&\.0q1qekPzCcgQ󘸂=i ؔm˸FDŽּ i c=,|d{@-!cp5Ą2KnֱKX㣜y_aƄ)w*23EgLp] pR 6LC OؑeuݻvOťtPϚ@؀qlDv?|!y HzXWIńن%I9F)~5%.CsdKGjMs&xw6 ڇ xFķ_j5IENDB`qmapshack-1.10.0/src/icons/32x32/MySQL.png000644 001750 000144 00000004171 13145236370 021067 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs G>tEXtSoftwarewww.inkscape.org<IDATX{pT?} ɆXፊ<VmAdm`i 3hPPV PQQ,c " q! ydžd׽3<j=tA6WkK0!e+&).2HAb'vbBa88g ) d*u&&K!v\vx̊Nu(a,RQB,nseeමH:IQ8T;!.M2N &*HUCߞ6S!XcVsZ]1􌻘B-9T{cB#;i~ZŮbdA:\ƞ8cR2ؕ} wH v~ $O/@<|qid݃@S(TA3L " Rn.LU*-O;9Ja#U KW`>B44|>kHbSz{wzK`5pTq~vDm:&҄nFЍ(eCǥh|NX|ySpTN>1\F{h@u ŕ\/#/[AssX:K;mEEǥxӾz9dsҖB }ϩtK &2aGYP(Ƙ1Y'ڵyuA4m8rPsH>] ֯?N|[/+Q4 K#L\3*frsb'dD߱)qʍݻ'qFz ZuSʦM%+Lqm(*?2pM*55.%db-\iƘo kkss2InM!͖] FČ4"0A#L}JpuKWKiCOY|cisZO)oePqsK;L׊G(4WXr[r2O 9H &d%pT1EqzkcGmjIENDB`qmapshack-1.10.0/src/icons/32x32/WptEditProx.png000644 001750 000144 00000002156 13216234261 022350 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATX[UQ'74* Z)Q!ؐJt"})&Q@p"QXa74Kf&nt엳}kgv.^CZ# rNc4VYOB˂ d1Ȓ ҟ1I_7֕w7y`E0?TSPSʴXa=1\˃3I)AHKI>i-ҠD1Tn$6w:P ^J/{>FE$We)h0eJwgIHbq2 eI;q.)KqT'ƞo Nr5DwB--l2=rvZMe*:BȚPىLOjVi._*euh܁ZZb 5% /Kǻל5&b%9֖;hf{ΐZ:Hs17b<^3S;ݡ C19;T5Mx7{s*137T-(ߝNVKۗԴ%|KN# {Ϗ؝j|W[ܳ 0W~ƽ|^4`iKC b,3;׽z86mgN\7kPFmSd R/`e2 S hz|(Ge'?^;=pG+i|(Ьe46Kz ^4q8(8p:c9Gx}R#'(jȽ.{ hKJ~.%IR:`L:AM^JI&V_5j^k]L/<}`J02@^`QL N w5~Mߕ~A_+<\ 12M| twvRuf-IENDB`qmapshack-1.10.0/src/icons/32x32/SearchDatabase.png000644 001750 000144 00000003761 13145236425 022761 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs{EntEXtSoftwarewww.inkscape.org<nIDATX{PT{_v]Y** 0ڪ%$dLT3Mt0$ј̄8*[-Mqx#AsX={Ug̞w>~k@b8 @p4 @Pta oف7 V("=#dg'DVm81b3D8܅v!:hhhA.O7vӵy k~w@1}qHP.BU_׉P$c?tq)efCzz<:_+ Eʕ?(E QGyy :RR\=ځfl֣jp8tv rjd FQM7?ɤћTT4A]D](@3 #zIN"'g >Rb //U#?~|HJى 1oqY-fΜCB}?b( b /D%. h!4!@hN:^N8gm;QP\@+h88Hٟ?` |w;|}ȋdJ-ųÁh ϊFStDl"?\{Lď# bɢy^|rv ivQX!ŋ͢aQUA*,뽌)exğI+>!)Ɂ٬'6ֈfDޮ|-%43؆]64I6(> PP,Rd͸;sٰT3,:.Tug;P(֭ƐErrBW&r ͞WPW'(x!EeX lFn*#BY v~ ]%wYE^~98]e*4}㵃˴Im`jnаX,hT _S9L?~pl6⩉!H%k-զB;HŮ](+ΡC7z5F_`rWT3b†Msɤgn7a?B932Rq*7Ktl2uo ABWUpG sD'1JԩOpS46v! f37|b38q^QAQT< ~!VU\iA4صc&E8o0ZYg̖odXv*9H$AC x{Xf)G}@sL3&%jQF9B )2+*$YOvR'ԲfϟocHKKdk+y&_4I_eS@g16bʨ8!r(p{t0~|.9ӗrOǎy!_/3<@^[>UPVVnt;b30 ()%// uuK27H{ݝlc6Ll`?[gDXu6' a `g$:~8Z{&%Xf`Fu$J1ƿOd聁%NAE#Cal|?L2?Aser\XS hN&%ĕzdŠ , >X/$B<5V%U TbМ])Xzʜ_&R̃b ħCCKE6*X-i(0jI濃tza7uCxLgh;gXF~|"zd$ncY|&{Q^ mXS&{P!&VCjm6nTpsX-3. JM?EWJ3ϲ5*؞=}9Ya4݀'^&rbI\AE{y'rX7cCHLƁbib9=f2{9z gP c4="~fj?#U?0pۧ`= ?&&C}l:!{OYP/mt깝?ȏK,:ߤiTͨs/4yAϹ/#UM0IENDB`qmapshack-1.10.0/src/icons/32x32/Check.png000644 001750 000144 00000001507 13145236316 021137 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXMTey{'z2%*+%*A/J"EuҦ &l"(Ʌm BZDV M"X4RWΜ8w̝3lrȱu+IaKi *J9f$IދOC إ4emfh<(!lU4YAռjJH^H{id6hIENDB`qmapshack-1.10.0/src/icons/32x32/LineWidthUser.png000644 001750 000144 00000002230 13145236356 022646 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXmLe9Q4͕c9d9r-֘PZ~skkap3552$ߘn MCJ)P^&1ryso=sw_qHUmNUw :DUYj#C1Ѵ]izeJ7%vSnܥxs|rPͮ;Z '|!b|E#JaƦF?f:G:+F``C.>i_a$ mQ{?uu(B2^Sj{&=]`Q_=~xAc=ǞZYiզ"r)Lޕ\G9Ҋr>#Q>a+Oti,`X ]TT)д[ݍ6_@`zlEdpA<'2.pE! W2+U]V2`ɶ((k=`c׆ΆU]43FY( |gDj +gh@V#|琓̔;3bx|15  WX0 N9q8)C=`I H .W~v"ohFvۀH[H/u`[=J;P~hm"ronQ`i%4`@&ZV϶Om)57Y;k$UBuo4Ӈ%'T5erGvkm_/&)k4GXx 9| hEPGHHmt!l oK zN tH&Η. |"^w@ s6?7<CG/&Ewov?@aݡq  ^` ,7`c͚g_Z@\ }p 3n0$W:lӗH(q0'%B:` 89?~ *tIENDB`qmapshack-1.10.0/src/icons/32x32/Tainted.png000644 001750 000144 00000002200 13145236437 021505 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXyUK N(I.َ`f:%d%ifhfQIDIQJZ)aBX6DBo̼y~q=ss]^ eބrg p-zRUQD&UPMx.5ie枇{3X^m~ċg$FbDSr-{po@nO:).‘FKv/s.6lml!1p~TG [Z6Hv bⷩy)3l+B Ba QSP 'RG9@g]G#og"ލ'qO!>Ima8 [!a >)϶ Pq%ꚪDfDS;c4R_w6|4V`x'cV?LnCp;2q`cM@(8J}r/1`[* qdw>kIYFaՌ'^8ZҖskݤ>iQA%Wp[0DfQђ91Lj&Du6nɰ6sp36-@=`.uY_O8DhܾH |'eī$N&_InHvn%Af@}hgDNߑ=OHo[$0L sŅѮiǤhl_1 })x2cLNxqogysWefjh/ WՅ_Fx=pSI~Eifea qg,^ B6 aPW>0,Fvȴ惏H&i;C!5kΒ=$ ]kC޵Yq.OnxĽ ˋ9n-9WEdʍ/;3mzc:d.V5j`5ɟECS4fK=֝LT:] Z>[{ )1yMB a p\;zm'xg5|ӿae>tg.jr<_y<)f=U"[6u: i܂~yN@f "zK7"Z:ݓeU2+uN&8O+iZm20ljWsVƩd^W?n#5->땐W:ˈ$~F|nr *.&^,iTXPp_Gi;t_4^#<±Op~io$n'$ۣnwTߩ2wpO$Γ%Iycr#p &5[IENDB`qmapshack-1.10.0/src/icons/32x32/MimeJNX.png000644 001750 000144 00000003474 13145236363 021400 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<IDATXŗmLTWw^8ȫ,XT(Xe 6ҤjZj,6mi6i[m-+vE@ꆮ] KD"f@f.ܻhLq_}>99G'WeY! .,zt,IHx\ajx8 () jFzQ<ЬN~fAAۋujȜ\ݑeA/vdY5ȭV$--x9årj$}$(VQiCSOC018HJ@JV1>0R&!b@%{;w\Ol21ۋmzfDJWWtٶB"16n&XFF7&ڢ" Y(T*LON,4݋MA`J*ՊP8*VπVKXF ڈzv [054WPCVYx.Rl͎ dYFedY'V5USc`aϳ,-ݻ|T5;v T,c@ၫ7 Z?s \TIW;l2&nvx={)A2:77`4v'b0<3EEND={0vws!(Xf<qYΛOΝ,IH@:}^`/^Za[0ى^<^VF{e%J%=a>X ,]R޼IMTegs'$9eAۗ^?>3/_dlvpڼFWPhm XF͸k: i3rڊg,~6Qwg+NNdbjҥLܾOx8qq, 3c܌ol,ȅKM>ptTNN`zrv A$,#pA{a]oL !)).f,yvU"j<n>>(ju+p{䑅";t -";mm77v-,KO`jx#YYl:|HAm-* $噙4*Dɗ[Lfy999ccLOL"2 "Yܾ|q|7nD[o0r:#}}Rɹjj謩!~8x"lp?%^\:p>))x"wKOOXux9݂FF2EOG lH_Cf iffxYC=kuTWcv ?R76rgri,ݽ--rϳ=%" Eduuu""9w2IDD|CCӧˋEħt8N/m5~Y||&,_z"UTre ڵTV^;apnw|^Izz\ȀI3FJpG.aLf\.PJ7Х/@9 ט1i&8 ݄o3zommJue> UKDbEDFIp<###VJ5-R 7ۚ G:Nyet]3 |VDCXR%>E7c׮l#"bm } aŢwͬZG="uͩ@D6AZ?`sξd+U ~)̝{Sv;?ƍѭ[4G#@̭H lLƏOW/L?LT$f`z3"wo!N !?߈i"33ȑeXAk>AoFX,CIJRg;42 +^af`SPo,hTrC#@"s&E^ݾ}w u9ܡ}h@d/^ HD5DѨ׭ճo @R5Ż}".} [*`)R/ ,>:w~+utz~D֭IR[  EndP>n;[YYُ=pK޳4}/DGO;vrDRM ;mvGoB4HF<$ıE5pgPu3Rj&XQ% .\$$|4J;6ZymWUՋGE"b»'CRݡvVGBsIENDB`qmapshack-1.10.0/src/icons/32x32/Link.png000644 001750 000144 00000001566 13145236357 021031 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXMHQ2Md+ dHAď]<: DH^D!J;t.AAj7T溺mtM8yy! e ؈Eo5kZ\M)SQBG2hb ~ y<|dgSQQfc#*FPF @{5Xl2 .!{{2kkuo'*+}.?DY] u(wAToG+p(ENN.CjzMBNjNo2oI hU46[TC9V3 X  l(OzŢP C dÏ X%.~N6=|j|{;mᅅp'>>H[(EnnyxuG@cI߄\F_Zoo&5 8DIup o(&++]j D8'\5?vwOXD(xNv;].QҨI"3"!O=xL"男@NBrw9<"@!V7Dm%+pH| q lmhh^ QS?ɑ A<[[1TV~0 7 iAdC@HiЯ> f@y hDT#=:?R5eoMLOIENDB`qmapshack-1.10.0/src/icons/32x32/MouseWheel.png000644 001750 000144 00000002200 13145236366 022173 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs $ $I #2tEXtSoftwarewww.inkscape.org<IDATXkUU߽s1GLƊJK=5(Ge *BA0,4|͜Ri HSӂ&SDGE13{^gSO{{އ:%5HR4son,KD#7LpJq Im`/kiY+I#H~ۥe4ԐOVQyXUL\*?l(sg9jZ(=9B}',Ù&xjZǑQxS8$7Sm ]Dz&=Vsr% r+bD[|功f,8li %km: ?;ZϮ$֠&Fӫӛ0)o,F ܌Il'\i{#b%FgZNsaA*Hҟ}&|EY|0ώWt9M˜mCð`"4sr_6 ǑC#`0X-şb-AsDpEfOSZ PLA+,t=(>k׀XF~vtsd%'qF 1\}{*:>>I-gP1 "|ҙu7Vk[t`?OEv+3: Z;sUq:O3ə]| HDmEqp64pꤧFaFxv mG\T?k32L EoT@*Ҹ;#ANjԶHzi5Uke*tp؛a)TвdG)^\Ⱥ= __YI%E+J8UAa홍Hr8' ܠ,WY@iҦ@p5Ba9u gU(9O ΞxƖ (ѿ6 2׈F[ݒ@Gwiy<s3x89IENDB`qmapshack-1.10.0/src/icons/32x32/CSrcHR.png000644 001750 000144 00000002456 13145236325 021212 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ѪtEXtSoftwarewww.inkscape.org<IDATXk̛F0#dieV'c4A8tQADw:stfϨ~(nN}(0)4cSFEM*˙y>=}~k}y2$\0 ` `9_K8\q8 siD;^>qɖ̀K(&b1iAO<< h,`|#^r-g c'MMT(NhMJfl`y`v3\C >ZgQ|c'wa"|IX'RowSqQ\oiš kJ5(p.F=_v _9Nk6HN NjGizcu$ejQϿΤ"fb!۞#sbX, [3XSO8a2 p koɄʱ5uN 3c8K3^9(48I=6SpL\7_+1kc$҇ Mέ .c:+'9_oW UהޝRW}:=[df³ds(HH$?yrw =~"AUZ\a#4L{*$w}N UC 0rf~&`'E+-)315fmѷNzUm;~ Bс.7o:=?8Cv9qVSxn/RdՉѾS}`T߅c!N8[|9C ^AjT|3_f=aI-׋//=xIRg-gU2 -QN[ A@Ʉ&iZϨAI۫<{ WWwtՅO/:71?,sr.t!aXl8%R[Pl`sgp:_؅s/tMFLŶp^v/z"RidHwc!aXӱS<`&b8Gm `t4m4F|GPzXIENDB`qmapshack-1.10.0/src/icons/32x32/WptDelProx.png000644 001750 000144 00000001307 13216234261 022164 0ustar00oeichlerxusers000000 000000 PNG  IHDR  hsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<DIDATHAkSY/qԊ*"v@܌?0 ŭT:]q8 kڢXLbI\4&M9K7lro47\wA'W{BpvOLRp:I׏SM'9L=hsy+iRO%a,X Zn̈́]|*IgR|PȪ)%y!<~~БU ަ)4 2@ʵ~Bʧ !@w{mXVɮRuFWeŏ+J#Fs ȀGEn6͛E귙ʸaT1OsP4:P#<^g&so/fV\xY>4[6jPКVAUdzqx" 3Vͯiԡ5KuH !4ƙmnmG$χ;(2 Ran55vLTB ^.o<>WA&ݝ1o4Q  k\;ɞ_s7k|lZOsIENDB`qmapshack-1.10.0/src/icons/32x32/Time.png000644 001750 000144 00000002261 13145236444 021020 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<.IDATX[UU߹34pHMF+P5/ABE(C QAAQt/2LCł0:1Yf39g: 63^g[k{eԀZ[[7-X`VcccJ(<'ܗnWqx R^ Fcxl&Ml~6RzaMh` 3p1:K?ٔ>d%^hO@% ai/^Ccal%}-pz Ĵ5Pz4#FwD894ىExk)&\op,O(?|LKp qߎ1Q9խ3 9Na&*tf Ĩn )2'GpKF>G6dB 6 86z ݱ:Q -AW xߔ~v<,8rFltGe_'" EQybaPIڧN0 IL7{RpuUlȱ'%{M@J>9k̟K%NB|qtvOcJj䶆Ɣ)+dKe}6\Y)3=?h灈L5n\/ٟLHku\(48[Q@D"jnX&V =?0[h |P! 廌&60(C{dB a ~HfTĻ Odnr\DRG.FJ';piĶNtc\ ,Qp0afIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcAccel.png000644 001750 000144 00000001166 13145236321 021701 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATXkq&ram0IQs!wnrL%mm5r#W\R$ȝrc.hs\Si=gs]~|??h]Qm顃h*|cP#8*/ɝ``r n`1$ElEGb Yr)SG9 G14;[pYn/~esq#8y-ݒǫzp6qse%AoB>&6%[ B ;)&jS.qԴ 0O~˗kBi}06L[=)3pm-aΏzBJكh.;y#sԦ4*\. ~p:qopg*Y(#sM)a) )4sHϰQD(^ƆR ΁I-̿a;xeۓ^'Yzs{m5jJjeUIIENDB`qmapshack-1.10.0/src/icons/32x32/AddTrk.png000644 001750 000144 00000001735 13145236310 021270 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  #utEXtSoftwarewww.inkscape.org<ZIDATX]UUg&s J4˘$22"0)*6DER@"/2" (I+8i=g z{[{oxMD %Nø+W@ %N45vb^S͚点08[:M`ehJܽ2O烫,%q/* f4c0#=/KoG3Ծ6.jv;}gu'9 ߟ̄=͚(, O=\V;|S0^%PtS$0i`e|HgS sxdϚcD~V~=%oc#cU, EVy8<06Y킸FKxȃ҈-'˴$+=cs꿀2܌ARYZ⦬vܭVӯe##'ԪaEV;d^Z͡f~ok#KYZom}px, `C>ayp0^x6FoFo ^ov@3(\H}5"mSAT3>dΐ "oe<'`*=MnIf7c&n/h4#Lz<9@7xb.'w m<#b-<e{t6'W1q7~ T_J[Qug x˺]y~M},l;cIwj%^5s;3Vmt cbydvۯe|sCrC {2{R]x,z^eAlpzRM;JQ XWvVmO)HoiC\ԈSy'K*9QWs4VŦ\Omm?LNn의@:Ef3ә=| "EKc՗ #~8}NXo(7or*;ŮoV(C<\љ [u0>x@D$en?Ç[9վ݈x[.j/Aqkx|RQY7ˎW2K Q1,p/z/rj/^%Wr]Nw1oU&q.ίX, _#r-`H}-tLtu. -@9Mg_kUb0W,t:_@@LG5i7QJ@(M(~.X 'A$ _/S6Hg[qi) H<~ 2ERI44Y[ۢoٕil4ω^J.ua@Y+'6 b>nᨦ|BM>4z+ Ol8M--Cdͳ*)`c#6ݲ"efqyY\3T4X [Y{n0Fs`9ri4 >ntߣdGU'k IRUU7^;g^ kg uJͫ۵++G## swjj̛L'$I  -~pxbb1h<8WPsCОBBB*Q !J?OZcĺIENDB`qmapshack-1.10.0/src/icons/32x32/Template.png000644 001750 000144 00000001024 13145236440 021665 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs0/tEXtSoftwarewww.inkscape.org<IDATXcddl?FF,3h1XX'0<~IZa`: 2r-ÊWX'O>' ſ~esCP^7 EŻhb9L&V.dX2EH1h==q==qW󏡢b۷'z"o};wa(acҥ6lPP`}̠$&c8-hPB˗_ W_P8ږonn6?aUx{X ,̉{LLb.p3Y|;!-͘y^\0Q P&5nrlG aajO{mzoioÝIENDB`qmapshack-1.10.0/src/icons/32x32/MimeDemVRT.png000644 001750 000144 00000002242 13145236361 022030 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<IDATXkh[eJWgeq`h.h2L^pӪ t. "łCj~\EtСuz4M[.mM/iINrv=MKV/?>Ɏቶ8 #\8 ߊq?"MآU Т>FmApeΟ)azJ?Tٳ2@7iy^3b1h4؇BX Pa.Wɨb(;>gU\NCBha;B ^ُt0UA.ZR!T œχ!Qp7h1h hnlGp.-6}qΰfݰ @So 3ں@.O>IqO,`>T Zl: : I`3̀ m^1ӌ3<Ϝ=Ͻ#?%P{ 1& a_E!g,~t$h 1ci-Ygxa m3H[iڮEWCo@^@#Ы\Y*,Wp52#}y;XPi lDkJ' .ۈ=$=U*x)KZKSK 4ژJ<8>I+)!h,qS1<0t iҀ_+;'w'R].X5x.ګ$#8"aO^9{"cx2X&' aoQ>Xo֒mO[sř"0:<P)F1=к1ox^G؃KLdo)yNaf#M>V ë,Hp"I|_H^J|Ji6a"> i{e"!#nn0I'aԟi߃J06JkN,c>[ Äg%̿xwcȾ,n_) VQ\s?@8{# eföRZIZɗ@CU!_%xa=-zl'(ǟLafp)Pnz#RAؓ/ÿKR㛸[Fzld ݗPuR?(pװf4c&YPG68QG*3x&>AϷpuFN4l;t' *T~>SN^Lvxc;3F_5P^xȁ3QJ;qR$,7,L>91M`"q4aR@.U{=#N]hsMRSw1o|O8IENDB`qmapshack-1.10.0/src/icons/32x32/Waypoint.png000644 001750 000144 00000001301 13145236460 021724 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs mtEXtSoftwarewww.inkscape.org<>IDATXMKq\%*X7ڄVAEBz.d"(ZF J DP."Em Lsii1w4x,9 %+`S= hF2m n1nRXb37vh7|*NqcgPKnknc` ioQ…:Kn!'r͢(n]4G}[oI`0I+oljǭnwhN\ar $'Q@OuMքF\G,UG?Z2EaEzjv$/Q7J\UN4ӸBW}eAD?ᇭf'BVs `)J%id 72%DDRR~2$ADt3(,GG" ^Pw|j ohvq(8WqMloZR5aWK]M'ӟgБUJfdb9,"KVY|G8=z*w\IENDB`qmapshack-1.10.0/src/icons/32x32/CSrcATemp.png000644 001750 000144 00000001326 13145236321 021676 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<SIDATXKa7H[F.İ͔%;P.YXWbB,(eԠ$J;3swtΙ9眙c7z}>| H:Jщ݄8(\3Zq0W"D8RZ>كƐ!CKxoMؚoE_Ix Il)p$.#B2G&) g+'' q ]ԭvp8oxH؜.fJp@0'4bމp 8)nZOW5\^Ʉ<FVOD%L+3Q蛠"sޛ\\A3ޕ'Nj8E4H2'̟>aH6Hn$$edH6Z\\PS㥚!}ޮnf'V3덄TTP;)) \5Zlfl%e;n=@tƛ(*:_vsgz&u@VKv_cYΝWjjblHj9}C`O-,_>_ prFJ'ZuuRb"9Y| AFd ZC"JVHݰͳ2@ *+DaQ̿_A6x=̔@L\{iP07o·ܖIt黚7ol [ 1Ȕ@gPZ%v:pӘÛ2Svee+X( 4;7'T&’nxR3N_mq`Q_lE\\4tu!Ä >syOe>yLSO(€)%t˒I]]3g8@ݱ˗F~j-yp~ hf.9ޮe\pmA\ ! ,XXwB|x:z݆ ?pK }Cp pmaw@ǐdq ٴ) e;0jK~۱#%*N*sbPSs+`QsjmS\9ط+jk-@>s)SBKK}F `""b[[;:lcn l 4 8>>|~M}Aooڦ&yvAdu4}?^c /O"IENDB`qmapshack-1.10.0/src/icons/32x32/Route.png000644 001750 000144 00000001536 13145236420 021216 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsbb8ztEXtSoftwarewww.inkscape.org<IDATXQhe9nZ+fIC*3alav]tU]%2k2*"GԢ]#M6.`Jtk3tq΁y?g8yߗy}^ NP#X :^kJ ya[k,6WPi@c콻Y Ff#i4S[_ىa~[ pw A4 >cIOU 8mg@WG\> c$@=K#E U ZKq?dyJ+ɒyxkEŏ}zf?n* UPл=+7_bT(g]r{\kIoiw$/7l~˗UH$˭$q-tf*X5xjʚJ^w؄$zfi?9d4;l/AGHxj;sJzK#~,<>R+\*A2Hj"ez&Ƴ )@XJz?L,et?S߳-j215 IENDB`qmapshack-1.10.0/src/icons/32x32/SelectExactArea.png000644 001750 000144 00000001256 13145236427 023123 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs2Q~QtEXtSoftwarewww.inkscape.org<+IDATXn@@ $ϋXroBb<@7^"uC){ @i@$I"&v6ge|_ D6Y2<Ts 6rJ1 1r"M( t:BZc^?khDT"28 ZDL q?,/߁7zduPҠbƘoV=֞x/ENZVNTaݞzF3@1IQ8skZ 8Spp\?}&6Y.f ꗥS9<7SzMIENDB`qmapshack-1.10.0/src/icons/32x32/Bubble.png000644 001750 000144 00000001172 13145236315 021312 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs 4btEXtSoftwarewww.inkscape.org<IDATXU=A=Ύ2kJ$F$O,Fe ]BqŨB\l6Bځp8d2 $ _%@)q|% B A{ՁvJTu~^D J)m2xJd2Y.J) {xt0chofk=B=QJ{ ۶GjoۿJqpOEOb;5/5mYlvw"q C9 )mՒa"&JZH)vύFCH)s~3Ͽv:')<-h4rk{2n"1Z`\xX@4M ?@o@eIENDB`qmapshack-1.10.0/src/icons/32x32/V.png000644 001750 000144 00000001156 13145236457 020335 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX햻K$AvEEQNC@W䮗` *'x-* ("(NM>"`MU׏ng7nj65}_w v*w`[ t{5;ֶSC@Ń/B :U}V',(A C;`_urwN!qy%mr~{x pz !6|[oBL>+@P0Sc z\ p=g# LBB>I(٠La*d8GM64)ᬪ(}* uC y̦ӣ??h L%!|ܒZ ;xSm[~8|_߆Ppj1!&aPU et:Y/IENDB`qmapshack-1.10.0/src/icons/32x32/Reverse.png000644 001750 000144 00000001144 13145236416 021533 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  *tEXtSoftwarewww.inkscape.org<IDATXOKTQg;$sA,Dm keڴCZ]E l lHŌ9N\۝syy8rK$IT&/htR ,b+/,"#oe^Q6EKVE:`;79FU7̭mP%֊՝G&NE y2h ]tm_70йh*q(`d1K8:@?"'bl  %h@[OPǿAKk$/_*%pwSxZHbb_) ؼZ g)^S:C}toy yh_iOg>iVfӨՎ#bQ$O+XmG q5|܎ `9I *s{Ι:y7!4 vK#ځ:! Nط*X=7 Xǀ P@b ^.@诡~P@qP]<%NBz;e1):J&r4}vA{mk]bp@(x+?iµ A l`ɜ!p`/!s=WHaB@%[:e$XHҵy2n6^Z ^ns:Z!Rɳ[drsw`mzwZj, }OS! pR$c̬q.@P JYu{~e UM|5zYJc=B#H ]mtߞ$4;FKbL 0(-5hEQۨM"1T`ƈD3D"a }WkO#`JTHrT*E2$kfx8 l-@&'v!꺅e&^DP]XO!F躎iDGMWLsSNb'0͡3-7 {!9zM>؈ PUx>D+?TU Uᇱ |C|oIkG| dkZ#|oȲॗE_5<}}אetO>iLN RƎ##3\1zDmm,+R>8襢"W_=ơC?Nj5p@?*+sg stt`-(̖-yYϽD"17p4'8}w.{^j53dfؿDXL7_}5DfB@_5:;[9v:|=;ζm9B(T^"Q`-'ij*e׮`e=|ӴWR(/H:$}YώE$7nSU`xx,HI'MiKK~ѣ{qʀjF{{$رKzbmm],};Q~P(ә٬i08GJP@P__ѨCE$$4dLtu]z7m4McddhZ.WntwQRA0EKKNXxVͅ$֭46nL  x/i8e0uu~_3#yHҒfwLyy6CC3(3sxs[yjna`c`(*"% Ηe[x{9{Ë/p]ټv l^L5W4 eeYTVPVcƍ ~!$ScLզ*C ipOd~>BSS)C(gO)Ѩ:n-hToqD"*F2]u TE-&Ѩ'5UaӦli Kq 2##47[wv [4XNv@,!"~]KnRU嗷%+L{{vvs|qqGp(FILNNj5;{3veyyhmu1;͛rvMSwo91EFCb"y I}kX&t;'PNkz OQ[[N&&tv㛘{9MD1|D*:DOL&Çϱa"0}Ʌ fg4xQUutc2y뭇xW=DMM>{xZhjrmntזzͷN-^KIENDB`qmapshack-1.10.0/src/icons/32x32/ToggleDocks.png000644 001750 000144 00000003022 13145236446 022325 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsyp&tEXtSoftwarewww.inkscape.org<IDATX{LSw?Z^Je@"Z":a ̩1׶ ˌF|Lc\˶(DR| AOZ"m( s'ir{|~rn^?*^@2Y^40݆K^SՅfҁj }z$ 'd)' 0+_yz 6[{Vdw5гigF;ܱ}ŲeK ,LMzؗ'Oh >>J yO.Ve@V4Ν{Q8PBu{<Gevj/L Sq~Vn߮%:: JNZq**x̂Ngx Gлwp#>h[/>Ox`CY:z)JB@OG|7 46 QUiN-:nezsDQTB8 TdWs)|y.=FjLBAجo0,/aB~,buǴXDfʮ] jbf~**|`IfX= 5joANCc2tU*9YYWIJoEee:7^ju\pz(cTa sfH\x_)|8&\ 33 z8Klr6"{f=d߁05ǎ-86r*G*a% 8tEWyFٶ\ʼn|]m@`s´5Ȍ&1nǓi <*3kQ|: <,K7m.LwMC~UJP:afb){@2;"#D(˟3urz:uK!>$:_GZg&bswsS{ęE5'ZD%%HJ5D`$!8'Lܹ{q66ζ~}]9a)G:NHAUsA&hN\i%Sb{ &.>t gP턱[˰ SE> =DS'zMC\Bn5[I/ᝓ)q} '{6;ziI@8puk_@\LlRj[mʧss?f7]ff$gdg9XIy(?e(\"`A'OiF(iPJt/i8h!qy ڇ$F즢GQºDik"%7 {/XN GAI]'nJ[-1ѿq< *Ox9;T3Мљ3-]7q8՛Ξ]kQQމ7?wnᡎ1xKOw)/:ۚS P^> wq'D5T^;6kOQQK;#GZ˚x)O)0b5$~юG6&`&HY<Ĩ>x9~[w&do?%)a삸bRF i۰[&ҟu&59;IENDB`qmapshack-1.10.0/src/icons/32x32/Up.png000644 001750 000144 00000001142 13145236456 020506 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs A_,tEXtSoftwarewww.inkscape.org<IDATXKqof7TDCfu@QQQt .]S:tF ѡ( u:ku7.3/LЏ5,Ә'S Eǿ*?Ou = ywlm-RL3.f~J &<@{g٢ 芘F 橖b= vq4w $$9\-ɶ%/QGfMdOpǚlHY1ϫin.[c.ǴTQ@3=p7۪e/Eg[AlG? h'`@^ `, F1H4P*1@EIJ[ZIz{3skph';{}f{ 6W |Fns>[jisG&tRmwt%3 p! Jr[|jC}w6@vJ)!uD(~d ?zAw1Wk1NYnd W ,R. RKk!lY?2;+Vǡf3$WwD>s17I=~d蝚pǑÕGؾ}w҃tR.LxIJЁV 6laĪVJ3*!ISj]#*U܎S؂Ÿh&]Ht%!cp cy|`e"(`c!x𽻞|u+&%n^<=n g<(7rwe viH>]ڱW0?k?70kꯥ]5YハWGGn&pq)*H GӐN$B:[_{4Ibc |?T+!5'ۇvc |ӌx l ʻ'w&`Wj,ťqrI؀%3 j~Z g;9*c-3;dAga0EWlpO;yq|i6eT\l<|bna3[) Gp3g"^Ix+Zjl{O6mT[I$a;zK)8mȕoy)A-Iz,cORzܚiGlgl;~cpgum-Q3 `0IENDB`qmapshack-1.10.0/src/icons/32x32/AutoSave.png000644 001750 000144 00000001132 13152263363 021643 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs K K>tEXtSoftwarewww.inkscape.org<IDATX햿KBQ?>ՐF?BB(hZZ=h(( $( *ɨ 5xg(|Y.{ϹwxXR0Ĭx5 {]'Z5xukJnnn 6j5@㯜kJ| `VJ܇,;yddT*m@S)($826[$.q(Qd@ B !4T~Ȝ_&F(m`X*0 @%|J-ǁi5޵bO 媤5XE#k*fxV-q!C(]2Bt U`V%lx_;UmG@`d]\@o/ []5 lf"7z, W Ywַ81"ȵ/hSL/IENDB`qmapshack-1.10.0/src/icons/32x32/Down.png000644 001750 000144 00000001155 13145236340 021025 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs A_,tEXtSoftwarewww.inkscape.org<IDATXAKTa3"-(B[8ѦM\j"Zg(-ZdD  )HQ Qgkqgbi9p7{{9[{R: Ǝ ttF Tq3r?c"3n`s666666 } 8}߇b\w#$ m 'ēHex%TIr‘Ų=Fˬ\dڙ'#3ݓz$Ds')FxCXu^C|e<") 6nbe-#ԙaN߈kXH2:8ɡ4G32ˋTof/x8L{/K9ڝo|."Kڊ a;z C 'Ca 0F@k /@?8(l<շ O PԖ/gQ%Z2lxB5 Pc+\D.z_7jƦg;Z C_!rIS  /'¶,Xk?";'}[{(m=Θ663&3V+b֥Y WsUl:9a Z/ KМ:xi7'lɱ(^c"re*#FIz5%4" T 35kE0 |܆5OoIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcCourse.png000644 001750 000144 00000001564 13145236322 022135 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsdtEXtSoftwarewww.inkscape.org<IDATXOhE&QHjh(mh&XA у x(*FQQJ/=҃CAT7* V[-J[4aߚ7?ot`ٙ=>[R M|:ިB^W ޸ b I''f&IV!͖RHvB!SO}oIhi1f^!l+b]X ^b+~ ~o$kH>&Z~g#N>W…%r ݔ/6gPθ>AK <#UYB0&ik0MNxww_]ôtYI81DƎҠʕJ~Jo L4Ԩ}y5H/.ZFP :ca 1dUvL4Lb rmWȿE0E @<" bկIENDB`qmapshack-1.10.0/src/icons/32x32/NightDay.png000644 001750 000144 00000001566 13145236371 021637 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXMlU_afJS߅4 a!MP`cƄDإqĐ *$&FA@Bb,2unj-Lۅ=~h o 4N!S:$+wiVrYވx=ki9Ɩy0AP.erOS<Ԉh5-XMIfcw{#d2Z~lIgv/x@7黹+Җ'bd#Z@j67CٰS&P|[qUĦdHרʜI ;XwRLL|G|Ϊ<T}=QK`.E7[?`kT mD7 mSl#SepaQo& {^i=#s+1PuL v N(\|]81w5Y+P[4abCf0+_m/~Ts FVcϣ?49]xؠr뽂AiPox'"_ЗIENDB`qmapshack-1.10.0/src/icons/32x32/TimeZoneSetup.png000644 001750 000144 00000004222 13145236445 022675 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  #utEXtSoftwarewww.inkscape.org<IDATX}l?w~;v$RCBKFY @BݪM+k'T[^mjt2(,4 i->0MhCNw=y9lAEEEb.\+WN$ )\ o78X,vW" iD]a%Z׻--5D````p|u`>)\^ ;Aưno5%` JXn:r i:@i @ aY$0h:)z t@mu;6ܓ+EHo*pAcN>X&0L~! L!XBaV Lʛa֧'[s̶iaYL /+ uxRK >;R h}ӍAH)xJp'A'2h߅߾dC@5/\ PRk$`@ Pt P1ϋ }xFP$\ʳy^$hswrJ %I/--2I5SiXr1M-L pdNvӹ;:{Iz\u~?f3r]eժ,VFP @Ϯx >o7nxjS:gbb"t]t0[֍;n]@PAWٜQF"h4Zu\f6oL:F݋ Βjjj|w>5 B&٩ҍ@0Y.ܔ6^{-~Xr@,CxIMM6ѱV>uH2s#][@dNhK_Lʹ{~ٳsSG̟??رc𰭷w)8(&e˖YCP̙3/W.uRg >&px~jDd2?pGFFb1\¹0Ϭ^Ƭ3<\QQXhчvۆl8ExwG,u˖-tJdxZ"زpBGLƈyb1Guuu^mmX,vl0١B j^e~iZҥKթT\WWg @ UQ^Yp=jkkKd>Tonn[UU7>>dW^y?I$mF>!p(TQ7e=חe2<300 [@Q__h<? 4 ?Zus@aСCᱱYaÆ2hs\Ϗ);a#~3:Ꮰvq:dQ#p8JAb1!I]4Mx.lݺLQݻw/<`> +4|hx CCCZ}}Ř5kTN2 FΟ?iImjjzJ~999x<@;U#,`2 ]d׮ )P]]=5M7U/|vj5RnZBj"}՟a vH PSTl6uRUA]WTr(KeIW\v[H$RM=ANȌe ޷)ɣ>H2[_p`P*77؞d{{{_]]]f9tжH$ߧ/GQ% > JϞ=eݡ(wlll(L7t:9-Go߮{7%K\nnn%P3rss _xIDATX_he.ԶJÒ"((Ȥ4#(+0 /VIaY`FJ˨AHެY*s\X-[ssYU /9sILOYZ΢}ߟEp"_ELKl@ZtKsQ.( >؆# \Ř^xrVn8yڀ, .'=\%t;Ṋу)8a&4gw" tFIENDB`qmapshack-1.10.0/src/icons/32x32/Combine.png000644 001750 000144 00000001240 13145236317 021471 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs_<tEXtSoftwarewww.inkscape.org<IDATX׻kQ)TB'$ G HRdQ4 vY+ >  > &1c]g7$ e9p.S -@Ԭ{f.!#ʦ }kWŴSzږ91 !wC* ,1ExP *TY:>_jqeEPa-(/HU8@OlIUN@vGUF>V PÈy٩:Gq pGY|Ř8cr4Mx{q7Lz'HuU S(٫䪖0lBqk|FFVz \jEu :W b%:5bs,]AhBiݺ]O>؆W G<(-.X@E0*ma¯\196 $L5 2؏xqFEObAדh B+Oki?' =KmZzɥփIENDB`qmapshack-1.10.0/src/icons/32x32/Left.png000644 001750 000144 00000001153 13145236353 021012 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXMKTae&DD$"z2! z! HjQ}AVZEFѪEaHA m?@bLY43؜3s-}?7}~&?E>Z?6ciCþx)& q@Ԫ 3 Gz5[y9]V;[fx.xIENDB`qmapshack-1.10.0/src/icons/32x32/Limit.png000644 001750 000144 00000002135 13145236353 021177 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX[lU߷mr)@H5. r&B"bBE!, M4Fhb1X`Złh (.+>AYeϙ33GD9Mm/ꑍ0EDfd&y#m[>Q{ ?RȲ^Dѭc柨h` 5Z.ލ̂e"6!vqAjO" #0U 7Iܐe&*c} a RY{I5ڀc:p~ \7{,FU2Eˆ{hW7ɑK%00w_H1ȑp&PMCƯ|e[m]Iܳ6| rrj N<^~<W"(%ţubD7)&cU#eNflR"xā"6lF[1.,SSlQN0+b;8F&̢@5Hס؆benݮ[Bק"5Xb) ^I&:b}Jc#< R⠍(TIr&Ƿ_N؀x,7p]x~j 3\υYIG4<I>NZov*O߀lv,t 4&W1dBQ~q[(rqsbV.&^QQP$4})\܉xGNn$F}CC%0M{-)/Mϰ.Ile$?ANS}k1tI٥P)u5NYU3x%6R,[ AgY!8:)0 .~tb셂C\3IcLV{F]XL񱱾iby-NF*xǀδ ? zv۵vVE5 wp+N/ۦ[IENDB`qmapshack-1.10.0/src/icons/32x32/AddRte.png000644 001750 000144 00000001416 13145236307 021264 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXAhwhZJ`RHxEжBAQAOVR!jh*TEs!5zݐMc?_޼? G{X0|,0|,{xWO8A[߆M9?n5i Z p'@/@WEdE9 N@zo)nW|o:Þ8 A7Gq+!@Vڂσ+2 UzeP-74Q໦!* }t+% p04xP0|\v]ݗy}FS[$*:J:<&R>}3'ᱶ=i\hRPڱلN8ClBJM:(ޫDYGM_);s#G!rׯ5Eipnp^h6@/rcI:zE/[Ԯ' nԮM8caF+WN|{;#>AB 3iM e!nn`sfgp&ғp95K%7YbaZβT{GIENDB`qmapshack-1.10.0/src/icons/32x32/LoadView.png000644 001750 000144 00000002772 13145236360 021640 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  ~tEXtSoftwarewww.inkscape.org<wIDATXmlU3G[XBc ۠ )lM[BJJаc dK@,Mjb$l`Q7b uBՠi|XKV,mgڙ{VRt^LǛq_y1LR"`x pse2oNNF[ d?EfQZ:L? cb i9]N܅e #<ļy`` ̵kCdt4@Y);VSijo)I SϔԺoy<;CUU֭[S;CX55dzSw6IgYuSOEE{t\A[ }w-)iF Kc }WRK/@ tB˲ysw;ڴ,J:&iʃ֭;"I풦NxUSOH$n;Na>1jk%z^+IT~e\ZZ֒J̙ghLH>:gٲsuZZcsu۶lirr\! ittڙ8s7(Yx<jl|'k IZZz((ZU7%1#@|3pNhvܑHiccW^-}`>P4sc<;rRXTdCCsvr;͛^7hwmkIee : 0cF F^}Օ3c?.*#cm6G"q=.]ɏn0O>.I_IrA(ieoo0pa^+/~mk֋/~C.)O^.\G[ɲo$&&I+FGVhTX}e[ix8W_B^X)o֟gJ*t護4388JIl*+j/9ܝ͎ivٍih)ZAD( ՝Jp!REq"t+qqᦾ_(>I胤ɤƳg93w’P#yZP8V:H@8`:*Agtt%@2x<$"'?<@N(B}.AkZkO% Ð+04]k}T2':7C]-yfԃ`YݰŸۭlvx x*06SU ycCܾ1YqG qP"%m6kmJ|jl^ԋM~GVdnLvҦ߼$5,/ATR1zV 'Aala"9@m$e2.H@vݳs( j]sڇ֒{lYZodHd2-@&XEggS[[w=-,dndm,q I`:MMõ=P@Y< y6GOOP,K,?ppq@ţ;ĻMSX `MGE˷,v# 3E(w,Pۋ?>t4e, T|j`Yd2zԙb?]T~j1ذaq\}>c[,zbAm4N_ NVP]0 S<~/6 sV ζIENDB`qmapshack-1.10.0/src/icons/32x32/AreaMove.png000644 001750 000144 00000003162 13145236312 021614 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ,tEXtSoftwarewww.inkscape.org<IDATX{WU\PPAv+2h&lhDrT|Ĩ+S1N2hL0H0SLT:#!"p?t&:3?~k߽^k? ]úWvM*?1)dp|o}ž<}$8U݂˃炻*/2,6gC2 13uA`Z`Gp*9j m%, f@/#XL ʆ`m5ѻsSyJ;9ꟇoAca`UУdӒ_XI{d1\tSi =L 85/X\[KAkIᝉx QӸo5*"I< ~U`{pf`i8ĢmYas}eC#^lBoQlD[8CBB7XZ$נ_I!XR`Tb?KK6C])NA2{ qR'~˅q4POA[s D 5x 뺳Nʍ{tRG"}D`5Y,vJNjxs7k:qo ~\ƥASm-uh%F^Y=O3Omjoiהavne|z7}Y /e8Zw_Zއ'[߼REb|>;;E630>G_+M` PK=q&o6}zs`Xs4)Ta3y<{Ʒ:"#]?z#8?cUZ7cĹ\#Ɵzc^= Y:̫>e.xb,f]G˜ gcDH-z# t؝Ş9Eg]@ TQ |5a! 0uծKU5*J'ҥtW#TMwPQ3x`QҕNu!\h].z)s~obgt1 6^C<>=`~a"T;X|vlNwe`v:[<-X|L#y_JcW*l&U1Ҍ97L;j*ek§T،DĒ1XL ,p44xy ch|+6<{zz XQ%E2l dSki-|UwHJ)$=6`SpB cʽfZ ]ܕ6b?=6 Ӄ`L`a[x 18dJ𗠹$,"/$538Swl">YH]Q ˂^婨&1>Xa(/͂[X۪@߿.xIENDB`qmapshack-1.10.0/src/icons/32x32/ActSwim.png000644 001750 000144 00000001447 13145236304 021471 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsz<@tEXtSoftwarewww.inkscape.org<IDATXMUϹhh@(2BTljE#J6pUNLP lѢ -D %A_"%Թ}y{_?ppgzfǻjZҋ[G8je}#}ݸgRڳe|J!#+E ,ڈegSt|šTH`%֩:|ykc59?ѝ-^!ޗ}?_='mgckf{FC9-ڈM-譣LjF3ɜE&lpc= c =*]KGѐҹ'7Rgv$]宅\i!JP譣LX t~r3Ϙ\N WEDyV>)a:"M\ fSKǙ+B os8M!KU{ЈX߾s'Th(-SKn eu—8@8Jq/ w6r0r}<ir 83+YW? N4N/utz}ԿqNjRӨnZ'>IENDB`qmapshack-1.10.0/src/icons/32x32/Scale.png000644 001750 000144 00000000756 13145236425 021157 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  'tEXtSoftwarewww.inkscape.org<kIDATX?KBQ{妖(B4DSK7h4u1phqsiJ}\lq?{Z"zI-}*B68* L8V6BWKGE!#O8y'xI5-ZHp].]GX.-A~@SFPJae*w}qɕ//Դ&3LBA14|Y0eJ9q5x,;@ȭ) B{F0j3d Ķ2TW M7JԀkj JZRڕ r""W;fgֶmV=ߡOANp nx^+g rgիg7\z3@{@@Qb~ocP߾. (z( hױO{hwI p,$|!}!I[@"M_VTw;i2U*~IENDB`qmapshack-1.10.0/src/icons/32x32/RteInstr.png000644 001750 000144 00000002116 13145236421 021666 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs n n-tEXtSoftwarewww.inkscape.org<IDATXŖ_HdU?ν3F2EB(9#fa5K/=BK-2aB DX#Bl!Omul]#D IVQqFQqp}~Νr Xe+ݭ8NE""_& UUUX ضm㌌4pee%`J)Db*** zvخ>WPGJ)e*XZZbeeKKKz F NWWWV ęP(D(*(#lq [``0XPG޷g!͛h}(1 O_Ǯ\XX>yJR뷀i[?%zukj|,:(~;ݻKq$\pU0($߲՞t椬l˲)dhu/u^=lZ8A u#Oƛ0503R%|޹rI]]I_Z@9M\sU'@ͩSb1^nmMnnybZ4P>[Q9 .ݛ*eq-GNfvf֭<03E px4e _6?8/pv?{0 9:pQm'GJ l\5 m AH`0ȏ^8(KgY/7_ovn"K*0os yЙL?s3@iAR'X]W2?пNÃIENDB`qmapshack-1.10.0/src/icons/32x32/AreaOn.png000644 001750 000144 00000003563 13145236312 021267 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  R:gtEXtSoftwarewww.inkscape.org<IDATX}U׹wA1)ci] r&B!A-v(Is4m ߂ؐf5C<)F(f)b" >ǽ->s=_?YԃUdf'qx[>9ڝ±@LU(!2 "$:\ݔr@*g,C،ިvEWIfMv}3|.p<*pv,@t !f -݉u 0oaEz% =ң@0̋DĺS͹ qO'?J(!\ͬ-Loqܼ/ߦǘ>o26 Q,k}i fQD`ð!s {.tU4lǎAg+N5\č1{w>=T~٪^DtCT> quC]m;zcO_L9uj~eU_\v>GF٪^K45~=G]mj޺& o6lpV^מq~- plŴempشto;XυÎ;;jl]ȧtvos\וZ%6kdeS8h;0^j#d#LlFBp} ;8"]޷Gܟ`W+JXmhj'b3K KUWTs&dӆ=͇e? ?hED ]^<)C9jx&UV2(َ{˾hzgeTYPERB9BfŤ5qYQeEeWr54wWNR &>%^ (#u5]w+Wϲ+Om?hV^^~(@ŨX{/ Q$B6_.pHʆXc{SiH!+'WNqJ Jr$t ڿvD1٫O!nhi,IK !4$ٿ|zIENDB`qmapshack-1.10.0/src/icons/32x32/PasteNormal.png000644 001750 000144 00000003116 13145236374 022351 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs =ŋCtEXtSoftwarewww.inkscape.org<IDATXŖkPTegwE]YA׼% !01Jac:N5JfY ԴlF'+hV:4!"8Qؤ ¢.d/}XeЖej9gsypT*]׻ٜNg(piB쑑a:n &?&d(1q(ÐNmm_J3$aݎjS*  &%z-)Hu٠CSXtF+؃ƄzAx!!W @aw@˴u xcILNdp `ow`c@} \jBG܇HG.Rv0|I9ccR~;laƋc $ͰZ$%*mV]ЪU^,DoԊaI "u"E ;8\>8HIIEt8hlp1{A녤nOSc!;,z%N\DrXDPZZ@L\ 6m6\wf%=U1=hDrrx<6$ Vl5`Æh4<!;FDwG3v0IyX#2Ul ^ @^*bc.Ytttv8||8)㶰a"=lBQ~¹'ΚB*z| oYNr$Xd!08 Htޱ}ᓲN)LݎDóϔvKFja&R ѦU`</2[)Hϱa[?~ j+#=;˟sS96,[,v q} 29OA#GRWc,_>|1߼OWw3duWR0 C0&֭@$1}5FW T2p6/qƂ{ٴiVK(,OQ!,ɢu˾(V?| !%:!?FfXg>i  \Ӈ{IM1qhrE-\i` pTcVk}oiy`> FNs_L8}O~lDqw@+E3*_8)!!w>]6si7Ad&0% °![u;π:@B~Gf2 awE/~IENDB`qmapshack-1.10.0/src/icons/32x32/CSrcCAD.png000644 001750 000144 00000001531 13145236322 021256 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATXKlUE*|E% (jbtah%Qݹ@7&…h 6.tah0! +wYH1TqjE3.ibo魉 [yÊVWh[܅u*&Q*Ⱦ')S9qs|."a/&;'3m#CO35Tɮ] ėJ.Y[=x &4Nm tQ»/ٴfza?:T# @=U\ 쌝pQo-x2p* Mxi w7Z?r[K@mg5hE٦ S2lZ{{ɆauBpfz.U VQJ~gl%u,ݜ%tu(a xs ҕ5 HF^$%5N嫳ae/Y|Ԡ8)ٿ7$@9% B#T/%4G܉fVh"y^YeIENDB`qmapshack-1.10.0/src/icons/32x32/Filter.png000644 001750 000144 00000001266 13201005615 021336 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsL ftEXtSoftwarewww.inkscape.org<3IDATXKoa;hUiH(ZH+dNl--}PDh,"!6pCRi2m5Ԍvfvk乯sx߀.*V ,`j J_h7vdȔq  Fbȅ%9$DkB kyw&&A]uȵcGwT㫨hd]e]4~&@,DRw7| +V[Mr:#~D7zjC5UtcM1r”SA*{ٴ%kTb)a]YZ;7arj;!~+gU'a @C\zEGq}4_2| 98Ep {l‡Bf7͇2 !,.%~}38a}@Cغ <ԵOX`L0ݳ\Gέ*ޜff)m}A"2Zj2 .ɔճLTgO'[SlUIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcSlope.png000644 001750 000144 00000001572 13145236326 021762 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATX]U3-A Dm/Q)%yE&Xk-YΙj]B )؋ +/H|IaAb/zeyxm`]gnwusyִR_K'd.=4/=P= 0j!adj/D1!:CM),R'!&P" K::&KO8=E¬Fs~B! ᪽ e-,£d h6#F̓(ad(HL¯ǰFu%d'i*.PO3k 7w WjԸ+ Nja_Ĝ0w3Tp$Fr [.b^2f }M6Oߞt0MU7 IENDB`qmapshack-1.10.0/src/icons/32x32/UnitSetup.png000644 001750 000144 00000004436 13145236455 022072 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXVlܝvrv;1qr Ii7[!i" VN**"BPK-,h i4ЖvlwHP)m¦}{{}y>fLFx_Aeq~W"lj?(: p*GQ6nUUUZ[o?WUU֬9\>Q݈Y z5vڕs}}(E+/p\IF"n};W+0u7KKe%% 全)͟4톧|: NLJL#9'(Ȫ(T )KRhB({gOYG*@y:?xA_{ ?BpѨV]>YFVBa! $ɠiH2"@4PTͲl$Iɥ3Kd\#EvkS4`XoٲEP n =  \jP*2It:l6UUU|>s79x@iSӣ{% A$Ix^s.{'L ePd2*5;w)=*WpbSZm{lIAQn| ]>G0DQl---. 7E|>@d m߉3g~  aѢ?&-I'Oˉŋ`z||<|Yy g6[_c%Ȣ"V|iQ3"YrxXx1<S~;.|kZ:Cv 'bOlv^L>vp8\{hT.**n71 Gd&[V_ڐr5sN=6t^嗕6p`Yv̷ٞ0ۜNojkkYNөE1,IҥaI= jxxxbmnnviZaʕzaCl6l,s:{ׯ_o ^|>!NyAŸ(|.u:]3/onnvL&|ܱc PF A8HR0yVKgdYrHp8REvf[p+Y$ٳ':55tp l,[jv]N2 ǣVAM$?}\.̓{ނCbnFTkk_Fiժu8ίd2ydÆ (>5qwl6/\&˲[c+Vuc+vLd2u{߈K(,cz3p"X@QԭuJ좰p 2xeW]8CXIENDB`qmapshack-1.10.0/src/icons/32x32/Redo.png000644 001750 000144 00000001541 13145236414 021010 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXMhuf+U*VP֗x0 AZ*h{=DA1RS"UPJ)7I%K}5nvv;̳a2Hne+!!FO')`M'UJ\ Mx7^a(bWŖp;v \:'s;D&/@еxiI V6ö64M%{9 ^'y:6?bod7H#P ;E 1zkNaO~t"0J6h͜D =p t_M\J&#lY֠^]:ދ/9zn-28 _[D m]ӈemU`dO0%U2{!);q9p$4 Lm{4JcQV+E4 ^Nzfq"*Ds Y2R`cS,k(mXh{L:Q qZ* DZ/ۭ0Tb->@M|&e9|AAn?c1S ɖeM\6b _<0V'wv,0rq#e&/c3B|Ezٻe3VuSu;+4YҏJ!{mO]&8r?rDW#!@2R_%/5oIENDB`qmapshack-1.10.0/src/icons/32x32/DeleteMultiple.png000644 001750 000144 00000001562 13145236336 023043 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs tEXtSoftwarewww.inkscape.org<IDATX=Lao{6҄D.HPH ;N,م8@%b1&jHL9#!R(Rw(RsiUU?zex0\]y% qiiix<{ЇP(t~_L}}boooF4m[:p8FCMMMp8333#{3::*bY!F%H]]].Fvww&pfEQ.shh4MI{{466Jgg J"0vωb߯5# t{ G{zzjBPImیߠmmmEϱ,1۶s׀ܟvoW3D ^UIx^v`nnhR}|x KZ4 ;? Z%myR|.E5u$B,(k_% `sMFl)y@2٩"R'Pl`$Xpx_0q0Fpd:+`K 8wxJx BYpO0R˿|$ ەh[`OT%`+,[aU9|D~>3Yd8C + ZIֶ#')W  IK%ë~|]̓q{^:kӒO~f$l=Vr_JT \Cu#up#~J+Yg?[sW+x] p$̧v&PLS4O'*j޻-ӣz6m-f)6~[2k#%%* 81zvc`VFe.:4v!n޴d ϲBt-3p0r?U;거|#ɔ00 p;&ˢR*c[GPY*NZ:Bw)/VNI\&#, ,t U&$;3U9u=?KӮ\++Ned6&pw8Lm_]Haqy^0 HKÞ*<γ_v'U`/Ru ±wJRAr\^B[DL:d~=GrQB L~8 Cⷱ${H'bF ' cYuS3BZV}/CxnYn( neW'{#];IENDB`qmapshack-1.10.0/src/icons/32x32/RegularScreen.png000644 001750 000144 00000001531 13140265126 022654 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATXMh\UߝIi(B(~%sQ(*.XE;"ΝƍPn@UU"JR7EAi RjCۙy.$wgƸl9μ{?1ͨͲH~_vBc;@'`^(rcBxüzo!ua8v ['0OY΅qN^"7FBQl§elcq!ѷ!Ә$bgG13CMोCd $fh8|oUJ` $ p{HU0V?¶D97$u&N\]³ƍe@s'.qÖ$p͝@V·\it/@4ͽAK/}@؍Yp/cxY&#YyNS鷝eXBؑ/$@ a@Fؽ|XXu<; ;!rc^:r~h Hư(&1SiT ., 'g  =? @}RL"u$[xu/06G; <./M,OXp:KQXܦ/ͽķE:(ql_C|9:u =ܠ IENDB`qmapshack-1.10.0/src/icons/32x32/MimeMAP.png000644 001750 000144 00000003533 13145236363 021352 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<IDATXŖ{PT?w <Vsaψ͍wOxs9^`2a B gQ7V2y$IB!j $I p.Є-cOa4 ?Ax[7i+&b23Z:ZAf$dd`*Nf|mY Tx65ס7$~6xiN!sb H3=L(f7(]:7300-f?Qʘl;Az9#] =RO1d?3s5=F9 e *C5W3\NaMu$˹UQALRci1Y[gsg4:WK妎Y/HB%NLR$q7p =3dՋ(0Q* !&#ʐ:&<ڂ rMzg^Z6YHޔ!$Fgp5[v^< ^;HPyV\ "gOhi@ԬLҥ1ۂsPm*gw J]8z%οS /`5Ƞˋ9҄N3feQQMՄ-\q O]UTq Mnz;W5q'?(*S7a߸bms_/.Qū;V5U4lUwT8u]_'ס7ά{Ncڀ[Jv.+M{dfP,qเƹɗvoǙCN\&7{?;SqX&Q~jIOxc:/b]%#|$q-K!<;[P+}oT_GoG?ZJdqp_1t ysg凯=œtu5%@%=3Q 61_.%>#iY,߾uHcƹ$#F2uHK 4nَ6g{n@߽YρѰzIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcSpeed.png000644 001750 000144 00000002276 13145236327 021743 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs >6tEXtSoftwarewww.inkscape.org<;IDATX[]c>3-m) jxpIHh#B%Ut2`wP:5:HSQ'>I%hE[ӢըE8'x;}G%Qn<"kA:_:?8AIT9_t bEnҭhⷂ6ЍqoQ}GzC q2>\N܇P!YOݻkIڞè2Aomd90Ј LԼ_HpgܘEC{ t/E,ŕ8{=[#h|(MտP*Q%튷ZG,`wp Ffxa8[1]va}3@.ZFNZzO~vZߢoKi)|3}unCҁE,;$RFWMlkJK Z#8t6&N O3NŘGhS0; cjK07l{IG t64ZU_mT'َQGw 082 qaZMҎ 4쨧1$ǃ%benXWn_qxp#f'q>`_-uIqI]h^O^`Si=L@8 7HvJ9v1/^o |7磇S>,إN$_/(t{K6?{:' =sNT ֪b:"+; Y DOD`( dyl+A«]$w? h K.DL'.zO\/{@J&|FNTqj(ncXk9`pbr+<1V&om0XVWYfAbpf֫Fp]+xJp3 8M6ި.*I~.uwkȭX\42Ldz>r~G2tl_.7Qs-Ty-+` sySL5d>?S>?s2 oF;vW3рkMxװxNz/MqN5%-IENDB`qmapshack-1.10.0/src/icons/32x32/EditText.png000644 001750 000144 00000002033 13145236341 021645 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATXݗML\UX:t&* 6[lj(}iIL$U'MmB"+AM\b2 !PԘ4SkLChFM:j)6Pf3XLfbYr={ǦOy\?Zᱴy>33 piu}N`an-3)'ӟ`._sy.{]-P$T9WoTDR6EEΥqyKP w5tdz]5R#(B b|򱈜WJ}k;wNF"`\uEe<"b*qa1m%aI@3nx>p:+x|..^|bU1ln%aawApilum{)?&Q쀿 Gy{k;b"L?~s}=h3EiO9<7j?66b(%gnR/q=ȶ#]FFw[p,(KW {Ji~/Źt)srqH>;`o11MS׮*O>{D6P(jKk(u#)$«VIxw\DgJ7 8Tp66QJeXiZj;qPrNK6y7R\FP(¡Cgshm},@ȷBv菷Ǫn@[ۮ}8M6n;G>8bH[IkWq4pa;0W]U,#Ԕ-^h4J"mdNq;].皦?X,z>?-D8 lIENDB`qmapshack-1.10.0/src/icons/32x32/CSrcSeaLevelPressure.png000644 001750 000144 00000003354 13145236325 024130 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs<<*ƀtEXtSoftwarewww.inkscape.org<iIDATXk]U9s3meF[RP+E TIGhQX@K{gl@|5$E@P**E, /Ji)}Mgn?swrg{:ӄ}zU;l;C8Ireb*C"{e+31@PF!)88 H|9kd"P+%&nnN.2Ԉmdۉ0sGdN{_I,jN3| { ޣihSZW-aT7-ߤrŠO${oVybL|HAl'N|%/Rts{[݄ җ݄McxLLmP~6%>ñӱwu9bP ¿1S)c ٗԦ4C l> ['S|m9c"؝n-&oor@j/t6_Btg؟7W6zZhrw1x1Rs|(f ~Ȏsq}eVzM랦vu\8GѐY1]'B"HįO66 n4ƻ݄{Zpwo:h<˶i]ñI †d5lKpǽ8_R^߼SfjoşyhV`h|㯏lLyUpoܒ<8#%~#yzƗw5pcԡ;|m=?_5 q3y) uϽxb',}&Om88&"ނ"E9¤._|z1}6ci Cϧ|3b~#_nruk'B.j0A9xw22;UJڿ}ٙQ:&d_$>Cn.®F[W@|[庙RwHG9C\;ޣ).Ƣt\aMip1nNNMЃeTʿNQ\k#JlDJS?)>YDO[HxK/;0;MyZQ&,JٸܛKl]"KpW2y"ۗʄv J\aᏣS dn 6By7{p ;%x~. wf f.O'A4Nˈwַz[2чͥ@Xc6T&eD7l^NB+I46v|x՘bUXIEoF]3z(*@>һV2߇@h/E14=BX$.:sԕ_: \E'0!}\t37dB2 ׿?Ǘ'"IENDB`qmapshack-1.10.0/src/icons/32x32/Database.png000644 001750 000144 00000002730 13145236335 021626 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs{EntEXtSoftwarewww.inkscape.org<UIDATXŗ_LSgmҖ`-VM0x1F~ɒ&^nۢ1dSj^lY W He*Z`JEg,j-{s}}}OP]h!pg lxjqkqmei)Q.Iv~WAbL)U Y* )pe[ (koDiocjJzN+6_I/241cK"z{g uu&*2a0bj I$M#I $)$%"-"ZTj P&֭j5~X,MKQN:Z;cd$ȣGtt<dn "?b6\V,44X8pQ,R`hԄIb4X8~e|Pg& \Ҍ,g`ll=MrQ5TB݌{k>%M6e$ILD"\zNW `29btZ1`*pmݶݵ^" UBKO n[yfSѹUzz{r#+FOlV044侩,b4jA_N;3?ܾ9@wCC ܽZ*N^(`0xzH!%$)A2)"Ϡ( z@UNWѨ0tZj59e45TSZ@ H$2ZT{ƹwo ?K.36[ **ʩQ Ng3,.ƙy2{˗5&_b``=M0zL&KGG^p传)ЦD")$ɤL<@rp8,8\.+F؇ F-O-OZ/*hOlV/($Pp(ϟflV^n-tnix?( 3ghlnn7SWgB/G1bsA(`~>H AVVR= H|Mpr~:>p8-vh؁Cu@}x@(\^ة?f4/IENDB`qmapshack-1.10.0/src/icons/32x32/Close.png000644 001750 000144 00000002115 13145236317 021164 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATX]lU)-(`֟16(XpMTkt[+/a 셁DIxS. JJ{ƄBhCZ ͲH[;;^fvvv{߻9;}ϙ3iK@V~f@/!̬p+ n¦axF>nP') lBwa@4I`ON\ $ [ tTŀh?}Pm^ 4PGVx4BN4l 6)>:##9-޵b}F$~Ν룮NuRN[,#GڋoNL,p˫ţ~h+E Y]۩43@qX''NP"57ϢFIH$i-߽aoa 0Rp7쫯J; KФXY2>~lҮ.^o][ πw`nm<>@wX*5P1 镦Tl5VUaj*fUj?2L^%g*p[)s$*FhbQ.UcXM_#̲/|W~@hoQ`0^u cmm#ߒϗTLe .ށxb_+I2nHMD"W9|8>@xxi"qkdrLf')44 t(oJlJXS6\qpb=.q}=p3P!UMf 0 l{Rgoκ$.O-K % Xa^BYW&@ܑ_p*)AIENDB`qmapshack-1.10.0/src/icons/32x32/CutHistoryAfter.png000644 001750 000144 00000002631 13145236331 023215 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs f&<tEXtSoftwarewww.inkscape.org<IDATXkLW,,,X`@()>][cVVZk+FhbRkՆVƴWc"QALZ >1 ">f0<EI{;s3GGX6mnvdͣt**Evc_'b0|?< xf@_NX,!N—.RU5+"^7<9sLQ"nn$%%WZGU[UU! eϞbx=$h|eE!Z$ӵ1~m sHߎlFDHMMyu`HˆbH}22vYXUEnii1RTTĉcپ}7Vm<*J#}2~>p*+ h*0.^uz;#a>HNUGTWìYPTPwmmwofhV$/K`0!=IU.b9M#*`Km* iDz@.HfD])&CqktK|~ : 98irwFh|Hqqee"ÇkEaa$)cZ?y`tL$2cV`w1cEjjʄ~qf[,DDdb-p`훎啋vyw&.d8sQ>i̷z]NagСSJKnnn&5u17n\;gپ?k }ŻXw[Quzr͚!(5'>?w(kE# ["s|![.NE._}>UDt:m 2wHkkQ/@Z u< џHUU"ch"+Vh"c>|pGyy"QQ!RQՉLizE7dfͩjoԩ" O+"ÆiEvžEJJD5~\(N6vq"wId\] (21}yjڂT?t ~ߺV6kJO޽^<~@~Ԇ#6E5?Z3 IENDB`qmapshack-1.10.0/src/icons/32x32/TrackMinMax.png000644 001750 000144 00000002334 13216234261 022273 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs | |]VtEXtSoftwarewww.inkscape.org<YIDATXyWUϛfF+մD, 33h!#+BlA&&BGF QQYFVaTn8^sFe<;s{ιe:C,ݝ=UtR,pJw8/fuvSACՙjg܄jjw{dëc k-fjtD%Xn@xHq /*Vܚ9d_MPz<țwe=cJ2#}1O+6c`Or>bbZ x1P΁&~*a=2b)}(#[Dg[Meb cC`,N VY^ 'W~lU&߹ߟ#>uzZzjܓ$vTXOE[u$e E9rRĩdž7`nyPx7'fa&L 6 @@F,O&Za=Lgl,nŽXĞ1d`5s@W04FX`QTR#w `e'/[!{#*{gdû1#̢j8ShM] kڡ71[4ibTwēqs%cq~؈k֎İXqxdnEnsq(" mx 8\w:-_OIhsl,Ljd2/uy[+;2V$~q`8ԧXsGAO' W)P \|RLr͠sL*3-&- ޽7O#Q● qgDYo NyZuOӒ.h։2zh=~#)+2[4 I)]OJx gprGC+s2mIENDB`qmapshack-1.10.0/src/icons/32x32/ActCar.png000644 001750 000144 00000001344 13145236277 021264 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ǠtEXtSoftwarewww.inkscape.org<aIDATXAh\UߛHIh)b EōYZt[+Wm B[3A"u!A+R%"H!JBI:si߼7Wosν\N:3Qu)0m]"|XˆBJ(޷Ѫ?.yHSS]=SK Cw$NܹOOH]_Xo1DV'ESۊkWc^|կ )eSx j{x K8}}SfF^''zx_!G}%05uChgN텙$4doD'h>ҝ0BL/ЂXm,mTi| ldڕɊN_.YDo:W*^2ЉߒD3DģΉ|_'C6y"G79;ԛ`AdshT})fp:cӗ;ȭ"Q8Aſz?"9P)AC~>mY1g78vl喾p7p qDZ0^F:up$IENDB`qmapshack-1.10.0/src/icons/32x32/Device.png000644 001750 000144 00000001154 13145236340 021314 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs44X7tEXtSoftwarewww.inkscape.org<IDATX1K#A19N R.X_'XYy~|"j"xXVԍ;\zdj(z`$|+o͵   \?W^i|<\!̶mk8R5F&#NQmZ-4mxo H 0!L7Fj+bjgj*,,n4HAͱ:8<4e\BAR.8 ۶qr|^W`cKkk]rׯxyayevYkS 4⃤+*~ ]z }OW=LPa=~"<`O\ϊ}NJ7ea[ Dx[ z!bޖ!iX,i xܻ<NgF`Uq ,7yaB`|_@YOIFXMM:$ޑװ|p̤~$hTYҁ՚FaItu@r Z鋀p/dz7RaVZH~~&F /#np( {08_o' "ݜ>}۷ikQUAfΝe[OD|)|^N Bna۶zqFɽ 'K%IrEgC])>z0^x5OL={O\lfdY STa=#6KB r*!heM `~+, 2Hw?L,bX(m.?Leׯ/b N\hp*l k׺&u4+S|4&  BzPYyܺcG|1˖-OW{9YL]/gݐ'Y2 [GF1FPD+lP՟GPݥ1c9HgT!ɫBe;4]FFN(+&@ 8c%LQ p^SFf,lK[sF n0 /*Z0nSMG M\UkfL ZTo%DkPl Bf{fP&hR`^Iz .4$C>9ݢnxpGkP)Pžjwkj:kH9V 8ފ$7<\C;᳹N 2>I l,-IENDB`qmapshack-1.10.0/src/icons/32x32/ArrowUser.png000644 001750 000144 00000002331 13145236314 022045 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<VIDATXmhUu?sϽ=4EkDmto6lCZC/ȝ{ͅF/W2B>hb)^6 uݚvpws~Clzܾpޜ} U-Q՚C7}4Ek/rآmUT.w+[:[R2tj@UcWU Џ|S0 S{(N+Pzu`bPj}8=YI):mA}->]}xKimPeW-A^^TVd۶=Ld2Mŏ ([h }% >2 ÌhNm&f*!eY*l`x;DD6oޜƪqw}$u(==wkiɶ;>+ƺ"rQ'kF>{nwNZXVw @B7"5"ra>۶hp+qU&?;yc"DP(4oh bvkutMe`1н{| OTm{'Y-fAVAŸ"m= QUy{nOWWWqdlL^x(2N0 XhNQaÆsIP(Tv횻PQO[/A gO'wp!З6u 999B^dfcv8\ͅr22dViv}}< ρǑiru{ui\6 am IENDB`qmapshack-1.10.0/src/icons/32x32/GisProject.png000644 001750 000144 00000002354 12455143304 022171 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsI ktEXtSoftwarewww.inkscape.org<iIDATX}he罷ץL#cʑ[:C0$5 U#zl$IܢY$J$ $FZ()wwxOܻݽ^%?9y΋,πJUe,AT>s"E1AOCg0'f*"Or;D T}?3a82Ě 4(&BxJ3W[ PWf  @Q-? $ Z)T&@$`-`|ԨkD)z`UT3 yGUT;N/; Rv$~3nJUhP5 3wX{D6="o14%ݏɿ{-2娈O 0_/V7x">)a@Q ?GzREdAJ!3jփ LXl\z㦷 vo.I0/ :@f`IH4i\κRqeihw]U ONSO[Avj`$Ȧ`+bT?mL`1f6ԼOx+pP] n Hw U0-Fj 'w"2&<)-fGu eE]Yd$ʑ#PE="V9P<UP1HO0w!?"{j{Io%&nID,˽/;۫d:x\)фFjE{TJxĎ,(p^`V54F2Ipt_Ӌx#Kny_-Uݟ y6DJ`V)vpi2'c 9 `@v`4V(45L2%P\pjY fOrhWT\褓ZjC5ԄlS^7 0- I [Nq q‡ZUOCEgV- cϩj0 0fs6/*PTkU5Wa6]BtTX4<.u:IENDB`qmapshack-1.10.0/src/icons/32x32/SQLiteNoConn.png000644 001750 000144 00000004301 13145236435 022373 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs G>tEXtSoftwarewww.inkscape.org<>IDATXXU?;g@DTPR4.)jf 3mϮfm jk#>k XFBX$:0<>s{%:cc3 ".@hKHXQDPEJkS+uO$ˀ@ב!]pQ΀q-dJ̓":IbI'C@`_ |@Ymr&k B^?!j5聳xȬ-mt2[}4wjjX1i9{~}-|9=kiW6(j$ܥUV1޿塪p'"I`sK$I[]Ak}@@ Nhl+gH=:mRGg`S@Oe-ڸ `6}%#\3WjnM\Nz_=շ{=IG|?B2*ȎQ!*p!TF-TmQTXz٩dDe^1N&>X_p䅾1ЧßpY /l'g~0o?˴i9$<8֌jySn͚G#g@ a5oE&Mk5MI`pҠ{S\jlĉIMEU3HJˑ#W{ ]L h{-hѠ!]8쇏NNEbɚT*V8qӗ`O|n}ګ+H">:4݄+b`k`[xhL I3il,u)o_} s*k/9 ԠZ߲g8lvo;L^}"I=W'%'g|wGϒΎTN& \ƍƦ52j?s i͛9x`.ŕ {OB B]NEEfs{#3o^п?HN& HcTŠ)rLb'U# xIs̙ 3rd/rrf LfLW/Ҵu;eaG # < Ȩ@ /+K$OXxgn=C˜bSq8\ []O=L9'%|_ѧL-AZgO!ea CK`[DDEpVfE7 q6Ȏ_3V |ń_m4o ;8\1$oZ{'G1{FJ}ɲ'ʷnmm54染¼c!V*Ds"Vujuw:" SVy*!DDk\w[pdr`B@FF,Vp:F/ ӻ KT ,p SL!YbȐl"9y(.?=_Сbƌ< D^W_س\J3cS/MtAtB4rVmJ]؜ΐa(*8]pim/Iϡؽtk$y#/`- \$+.|,It ʏ bbظ\OqH w;FEl0Q=R~Ӧ d-A}Mh{+o<9@ȍ``.-%9 vvxbc{0k."#(+{ƫQٵ f싈**`v YF3wh:THƢ}-W3L UQZ%p#O:UeS=Н㻋^˸uL w0Yz6a77 ;}E%qn9txOSe!-I/kU j[X&Ull=w:k'}8P]{kRt[8vh3blKڷF0ʙIP5 @r]<;֐G+'r+ĽKJZڲ=aT 1>W^z7ā,q|K3Jxp g0Sg Clh| &L"rZwyNfN*gMbxٟjefo"^IjbQAх.$"KKK`@B BiPb: YeP]@A4qY=o9g.Pao^lȲڱSi|-6`&%qM.K%oJ09t`4f`yx$Nٚyff u##TU D(a.ˇ >_3>.ɖl+aE]X|,Vle.pTm%bLZvxYX]Q32E~ٌA;ćj0Hzq =EױckPQك4̢lvKhtV6 ى1 5IH)=jU2r$SI6gϬ$|/D^B>\˨ o~*V EB&Y5 5J֪^Vx7f>q+^&E%;ԈqI 0_3KxG 39kHb7ztҨ_U/ffbn b&c&C/ অ7HϋiM=PuQN|2?c,)vq|4rs !L@ƶW, SUfu-!ͤ`)HpW] !lqD5⵿6{b?{}oA·oοLi&@/Q^SnCC]f Yt^ŮYu׍,$fj3{^IRX&}lJg*[IYiY:=AO=b}Ҵ+ivwy[ϑ򲉐v+MW5#7Ӓ;;<wV9 \pc?[d38pþ䨍Qɇ}#DZχ8:ŋtÚ+,*BS:Z&o@uN /…yqh*C:z'槨ãėcn x0Vguuٓyq؜뛟N]t|mHٶ|m``y\"UU^/I܊NJ[.7#w>>i*uhN~i}lgЫ6נ3кIӥ$7L9\.5)YXA̳ʆAsn (t'N#Sx .&^ ;lmkj߽a3A5VKðߪUGq#j <$a+oZuaKfu7(N'}Tnp82u"{x44j:+>h(@=.W0M.]S\ I )IENDB`qmapshack-1.10.0/src/icons/32x32/PathGreen.png000644 001750 000144 00000001042 13145236376 021777 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX햻JA[# "HP| v$^$ĉZhgf.돥ڳf41JsSf }mqE `r)ޯʲ6@[W2P3`~ ZoܯNȼTb(G L'P@Bs1cqn J?X 6MW#h~)x(^Gr\@Q4ͽHtPmDi Vvі} V9Ȱ‚@G%pxݤXcv=@\U _"mP]47u:mJ|Mi$ ZNn*:~ >_paM 0 #)Icn.?3(45㏿e>?]]P^((Ȥv*̙.._X0ߩ*}}> f ,&,KٱciAs7d!Ѥl$UpP#H$Dz㙗 {jմٹwiI@D@bM8&6x;1 T0X+csإ欜?-+*v={aIKHj8T7·>>,꺤'%֭[٬lܸdL&#w p ִ:p֠(Fɓ/pO?CG x!}s`Qnv;edd o?*O̥hT٢k[ή`6Ζ-X^`H힣sHeB(,ـET.A '.\R^~XZ,ԯ(J4 ߑ&mmws臢(s Dtq8曭}~Jf~,4Gfptrs`z ^zD(ev6Bh+lAxmETUIWhhŋ.0? F6xa&'C@L_iuSF㑸=x&$?{_ScnxW|/UU - c \3fL3<|!{<Uxe?)NuG QDDMOD+Ȋ*XO@VEN<*³wmghhl I^^"::B%` zػ Se(j8 زJq7kv>Tu@oË cJZv4 Eƥݧ4U}񠦩Ʀc6'LvO28f O#@vLhk;)|3F*+ ؿ3 ^~^L `BVWQ]}tcxxS׻46**عsz>u\s0҅M'JuͧVl3D{6uZh;_(ԖQ *2$"AXR;KU+T36+]Iu^skts߽k_пOWlt͐ئ_jhf/2854_e &Mlu_&Sd0j t:ӟj"~-ߪ:'Lv<{%\h4r%VwhGP^j43ONg``qľ}47{%IRH7"I"ł;LGǯbKjk7Ǹwo\ihکZp VJJzsY+x\9v'˭\?/-M_l`.QW7?yjvzJ+m|<%Bx<߈nDWN>_̊BYB*|O>Og)JI(**`Bee 99`k,`e q> p&H@^:"۵k04[:7vC}Jwr27! =.WUv>݊+|T6-= oo`"MMxwqa@OR<H]UgaNa>UGGa~V:H[# R_:>_w~o:,- pؾ~_oy33p2Hr֖QSS`uΝԩӯ.\t=f|02[ѣ2fx3lm2@=%Db[R IENDB`qmapshack-1.10.0/src/icons/32x32/ToggleMaps.png000644 001750 000144 00000002610 13145236447 022165 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs^tEXtSoftwarewww.inkscape.org<IDATX͗kLWo^l)vc @Aa2&3&󋉉Kq⢉/d$N/[̜ CHq4.\ZmW(aOҴ=?OJ))A}nNgb&Lr=P|u*Qg'WpRS5 ygIp,=pF >ĔT _'. c (/Ca[c%69YV8Al†'X~nm:l '99,_ތۻ'L>zz<bz{05icNse 7L&->T5~,YIkkOj`|3*sJc߾Q bcrnjm2.jjk+x!6r':8ժض !"UN}}!(bѡөb_R3RX}\STd[|@ lݻq?x˗a lD*) ܈bAGnpwq_:up v{7owrVB^ѣv1Vd9!vX'.y;MMٵ?ĝ;/p X,G HDU*ZZ8x8t.\ fUUTWj5xv#ʲYLgk>졼<*rTh2B$AG+*+QY| ͛ק oFV[P^Hf~˗w"LZ4BB()ͬY*V؉vkFr4//͛xAYW,-MCi I:={.aٲH,˲f4, AMoP\1>n{D0;%G_qqjMۻ9~8 ųN EECJ 2KBfR۷Ϗ;yrV@ȃ=lѫx:QW)Ƣ"p8,߅ZY8D"bďĸj%99 xIK>kGJVɤᰠ9mm. NgTWo" BN@WgҥTTO݀$A @$5svQMIITf&-/eeٔeO Q/Swɠu?˒$s uGZj¦): IENDB`qmapshack-1.10.0/src/icons/32x32/GridSetup.png000644 001750 000144 00000003631 13145236350 022026 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs | |۵~tEXtSoftwarewww.inkscape.org<IDATXV[l=s]^fvgv6 K2u1D,ҀK"Ԉ^D P+T *n<A q zwv㝙\5؉ԇ|~į@3vov>3/{`op=}DX9p1 03,0I$su %嘙'}O'PAta38^s1i o@r9sgi<540{Eſ ìnhh m<J8"B~nhԗ,t8= 9|֯_BuuuY @QKӪ*X}pl,~& (5CCC94 ! [3xZtHaΜ*f۶msY9kkk)@wֱf͆`GG l  I~ӦMd23gхn$,4M˗ӊ9sFQNElݺZu[,[vo h<˳-W.H$de竫)]:->V{(-MYf_؞l4A?cf{FPL#IF&$dy4rM"%  og2{FIH#LZQQq?Msb>%K(IR>NmmmT*U<@{{{BỲeYy4 q>4\T*uay^7`'O'IkY$ۗ.]Z۸qc}8F*< F_755GGGMEQ͛7e2 2Ο&?$_tSd2\6=ۯPUue4˲0 eE.l$Ir\#G4튦m]H ہyp8\f?5Ml 0l SԷN:P(kjj[[[#l.\y>櫫V)r|ehh$+Zw($,o5 Ł^ITV˖-ukap|\6$eY^7I8.|y@ peU MMiULDyby70ks0"c:ws㖖JMK}}G$Is$$I:;;CcFcʀ5} 5kT%(~sbee=ewۻv*^8'~?zx\sfuuu}Wwiv$ M\.waUU4M,{~ Aeiie[,=uA~6SD6,4SIENDB`qmapshack-1.10.0/src/icons/32x32/EditDetails.png000644 001750 000144 00000003073 13145236341 022313 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs n n?tEXtSoftwarewww.inkscape.org<IDATX}l?w_siK[JYKjai iC YPd/,BcnA1 2!$ )MD ev\[ q/`?>|?=9l.d< h6 h3nizARc=Ge>>0[w@y8>\޽g>C ^O>dzQZhvc" iv$wm(x#tr٘;7-+--ex5rZ7Ydee׾&mcWJ?3/V\i/58aϞ%xϏ v+j=DnwܴpX\i~Aff2c#e'r޸13z;`r15&> HЅ%_kctX$ =dzlƍb„d tt624}ٛb~~~]V6~"fG.)ŋ/9nΓ;' | i\rcL{l /XKSy~BCq+:hCr8kl9:ln|Q8xф<( @yPܲe5fܦ>;?b;A}Q8xTZK ~8*_&In o?Z/c|Z}>A@XezD/ZvEohāp/uu|HG cѢJKCZZb8wc< c^ω !g_6ƬTw_uʾwo#_|q ):vIKކ]]7޶))ּ?`(u(Z]rFedeʉƘKw$ x X;ĉ/mmm=AFv$33?@Ӷxg1MMIc&M=9l \ɍWD LG2!=)&ivvIX2LQ͑ysȔBj]4f+|WRHXhU7$>0[lMG<3@Ix `a|IENDB`qmapshack-1.10.0/src/icons/32x32/Start.png000644 001750 000144 00000001432 13145236437 021220 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs N tEXtSoftwarewww.inkscape.org<IDATXAhgκfWnIVPmPCJi-($x^[/UTz+^^Z*T=bS((n6t{.q:<0y̼|ģ-HsREޚ&;Z{c/7 Еf6G ,]-ЗeIl]hCO9 XWwDet(ǒ_'9DnKD[}ADRVؿr~-mIW>AK֎a[NJ ,?Ag?mtJ9w){~%q"$~¡{s.erjc=9q<TתWkH搊b}mA4 0<(~)d&=ŏa`# J1c'3@w$itV $ !RlFijS-y+E/egʘ}"xPFgEтy@984%،6ݽAk`ˬ-̱ABB +ृ&nn'M&|]6 16ײ_cy=bfL>/m6`Sk8}#z"#6!+"!!-SFHH|꠱ƾ@Πg- ͕oxcdf~,JZ6O!‚$I?1(BQ)m?}F}Rn'ɶdRx" ZFjb1D,?ʜpݠ`2ɴGQ^0e١e46ǭDJZܲh;unr7a SD26 mP/e yLbd0X`g5} Kn:*+0h 0*As{|7ű/2!a6U9r Y0zP2b3xiK?½ qw 1MĚcբuO3&f 9rO'IS՘ f(`+t{>/'#h%-ӱYIK;HjTUf"#Tp͵D0:op95zǍbͤ5\L<ĈD$Icoi=NV|~<ݞ^zI$d &|]tLQDG`8~8ń jv(n4QéQ߯{&2`aP^Xf"231M}8ukhhm`oXHN'܀SpB<܏ 6H)@ |/GY&}]]:!Vt O_)nV=#n_z )EQ=U]].՟#U {?ԂԂq%0|R o@ ڱZIwUV^5W|Ug^kxw:STn&NE|T돮re&SY_ @ݕ:nn9(?S9LU};&X)sNnK_ @Vdr=y9s^MI.J[c@xn9{hM 36Di QUj`=VMq ޴#fLSf|W;qSxK:c|wF)? z4(Gj]D-zhIk@w6wb`yAgpeNI^E Yt7w'_+R* +V+X:X\2_APkDu ŌBQ6|BaOq7gl?a}WC0Z^%4U+P> =K{9ZU^|m$&FlW|je4hca⃞痭4lJ"CD[sK4'wxU_gM.{ta)[gn@k.YlT ]eG!nkCq1/–dSł7 J>aaB‘> +^GHv~ρ}ۊG6З0ODdv)]40Ī! MIENDB`qmapshack-1.10.0/src/icons/32x32/MimeIMG.png000644 001750 000144 00000003357 13145236362 021354 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs ::tEXtSoftwarewww.inkscape.org<lIDATXŗkLWgn\F0 7Q20)h5Q(^%mwkH&*&ڬ]XژHQUl.EK"09â|zsy~>9+nR JJׇ2wԧzwo<]_{˖Ўf `f !u#!!*!/RJ+WoEBB8{:jj.(pr8l.E޽W8}6--?nz{G ۅF$..p keׇ}F)/7!ݒ7Y2ob6[0chjIhԳys>/ V+8rej\ Z)/7a2ESYy߲{j`cc#fs!>'pu9aJdW(RJL08hEJ8x>ୁGoxN筷|\ΝϟFcc/8iၑBn镸/\B_f4=yTm;C}MUZebǎBƈش)>D/~ʬm6۶m`ТT ,S~#GgRt9/e͚tܹ֯S R9|ikg,yZ X0ׯ3kf˖}v ( |6tvyٳz6ITU5)ֱ~`4%/ߥ2g n:228`Q:n AF>֭g 9932b 11 >le ˛-Mnn"Z:`?ow6DEҥ 8_\̆ yLs`jjKsHJ8;PsLѼ€j|҉@II uӅR @Tf:АUJ)UZ|GFll~8tO? Md|\hӽݻ#O$$&:=^SS!117OM{RZA]]+7nˍOfΟ=55(.NBpUL ϏGdd,…Itu sNEi;gh45u"D5BTWmOtvm:/|$o0u47PX8e\oU '!fݺbP*vhPT4HOsٹs3gF9O>),۷իM̜DDQS/ Œ8K܃Խ IENDB`qmapshack-1.10.0/src/icons/32x32/SelectColor.png000644 001750 000144 00000003150 13145236427 022337 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs 4PtEXtSoftwarewww.inkscape.org<IDATX{Vu9*j c0AiM;"$"JC(c38\&qtQjE("@ 6\tabyOwȋN?>{~(آH0xLШ!w.'bƥQG0~ Qq^|Ft>M"y  [}qc'_Gq+w͹"8 [9?(9KGm'c]Ο|Uzj=jcYp@6b߻c{z1UT-'A"젶Ykأs>:)A~gLJ0_Ěw܍JKfP luP6/#go;RVT5n'G0,,$!,s9= sJ4jOTW{Hco[%zl#ZLĄ vϘae.ܫ¥c83HwU9ѷ1A,fukɡ!CLV=z?mÇ:yRب?`%%L>zű^Q5&!n@o+VxyG6mʕ z޽Z!YȺf;l"C ɫn78[9Y \~/44xz?鎚3h%](GGKiiǾTA8 4!iDo-C2bJdw>B]tgQKmC-[rϛX(WePGLRa0hg<9|UL(L@pr/ FD-g(^DOQBHrsgb)Xҙl8o|yX3ь1sLa*p~qJq`5KDMD1tcps9뉾zfhtI&%JKs--8 @.i F3\C4,0|Dǎ"\f]?$W)T@0*}qEB2}tҤὗ,1c;wi咑rFRwZp'dgXq{nJݒFw"V@ߥ&bdu}6dE6[~Jl^P_pe$ ө:HvÇ 7XDZ8hժk;cѣR^+l=?jF%WG툴SLpd={v:p ׉ v~#}ϭf8<4joߪ9o…s3i?rgHdN |6 n0,z.K*3IEIccs8K|-}D>܏q?|ۧW| ty89HKjS^ػk5gUH&IENDB`qmapshack-1.10.0/src/icons/32x32/DatabaseSetup.png000644 001750 000144 00000004321 13145236334 022644 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  WvtEXtSoftwarewww.inkscape.org<NIDATXmlSϽ~7CVt$j4lb4+Ԋ~hNZ5:ԩLZ[%"B1 "ju$( m慐0I{NHGu^9sba!7{RY`ACd*}D6~x X9Pow@%mxj6n0˗WRU!PY4mi, M144Ņ %3ܿ_C"x|V_RyvA?yoݡ|Wضcl..ؾx<Å 8 Gt q;;,,YDze44Cw`YB2?CCS\Zd8ʥX, .ŋ/p%>l89+a--uԱsgO?Jv459p`+l`f`,"B&S0,\.*zu0PJv߽O0覹%4~ xhlm}/Cmaqs ~!>ݥbdYRatfعVx$ٱd e 6};%e4LsQ()] -3Ghi)hSЏҴHN Y@@u0aV 8 * jfgm f0 qۆ|DV&V϶m;>;G3.^kNӧ],)ض ::녇;<TםNg%_@A$~;,\LNP\(%@iJ)J)lff&oRJDh$g*]TS#z) Iuu5O=t={ʽQmx }:lw`13S _E8m裏200 Q?v&&&(8Ξ5Q ^}^]WkEDSJFxDWGEP|I,6RKtvvFOO]]]d2ڵH&F3gط<yEX|>~x(OBĕEJ۾!EccM X1ۋdbgNj8`6˗3IefJI9nݺpp%N̙~z{'4KA`)I4Oq>U7 "RxRcoyׯ*(fhhg WcYy ֭N(4\9l\.eU O@\uhj Hub6JdWQ@2_}N.#`i+NkH$Lu%p?peY-.ðfzz;f&gY4lfjfh7xڲ5 R5 ,KX]"/j 6P[[Kmm-@`|>jjjؾ};+W27m, p[\LMHJӢYn5kh9 =\%$6س~H&aa^UV`nEl]]P q?,'Nrt?.s|RO> PYYzV4KCo? \y|رEZwöO[[QYdÆfMX‹+nPp:=8kΚh۴ؽA[>;tm>ݻݰ\?d7}@@ݰo_Iz_?ׯB8VDUſ*7CP\r] RR)@2#)~iYG`d=p\)Z!cIENDB`qmapshack-1.10.0/src/icons/32x32/WaypointOn.png000644 001750 000144 00000002245 13145236460 022231 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs CfStEXtSoftwarewww.inkscape.org<"IDATXMLe,RA@W[X{6ăiM!^ISw!5i41VT RJ XR`ve^3 [/y%PDZ 8AhIBdć`%"z#x PUZsC@+?:3 @O+|myA=_1\ҍJ2E)S| LXև=X^U'nLH?N6[j& r3PTw>nlݗ+0'Wp?jH1YxJY1, [kI0[J06 ԼgV)2Lk?h=[!1sP`Meky V:t%KYwtL S(Wkrp&f(tx:u ! m8tьZ2~L:مP,0:=ʂʂTsNm=B* 8;XYX)eogw5j4&VQ8-)?qJsr?c/by;~{܈ aek&pA:u5u\~ _Dp?呮L: $6s#_p`}.7z%蕨>95S7KFG4G4`3&s+@!4` INߕYUVaK{B}Ω#mܐո1i3 !WC3:Euaɞjj9XwPѡϹ!_6ax?LOs-B jbr0}fkEAť>y5E5K< ;`zR~{> ӪwF-e}ɦ&!2}a!'5_R̍L M)U<_ji]SIENDB`qmapshack-1.10.0/src/icons/32x32/UnLock.png000644 001750 000144 00000001714 13145236456 021322 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  @AtEXtSoftwarewww.inkscape.org<IIDATXohUu=ݫB %bHe1b0=A=-z P>IBlQPrff;ݽgN9>p8K25rNSŪF}vYvLb?LK*[׭XMx fQ G ń^ă*?Ol5ֶ:$_cb9曩g%@v 8i)I}Nq@AΖbܝiZ~ϧcw{&P/\xNRi09v4gJT4{}%n(q?j .)j4|w:!:jllxS5p#Glßbcfe*b'rUV*fЈA)P.߫RY*\"DXܫs}\yD5:;pҒ%A߿ۊ?~ EKutM' tt<󉣥kf>">9rCCgر訑== @ޏlܸ}\.zRa..Ìry#xd2lڴIr͛7 4u+-[^R,FEѨuMϴ6ApLww\rdY]]]0wȞ=W&'Es Pgu9{{; +hg O"347puNbC?%hm- 봴<jqL,/GF :$)mOAD@gߨv^HaJ98_nBSt$ CGףkl,675w_? }mmN֌*@eHP:f+^_ŀYХ9Zx#S-?OKD_#%dubrYf{rʶʜ RTN~)< ˲:8P`#S-Ѩ(>h@З 2tP0~(EAO*ZǠ}f6]my S16tu 6CDwwױ.Ipr|`N4a ^nR`E C^r={e$o%}6ԕۥ?=k1B+oէJBgIENDB`qmapshack-1.10.0/src/icons/32x32/ArrowDef.png000644 001750 000144 00000003655 13145236313 021636 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<*IDATX}lǿw9|6~9켯Fj&BɘF2MKy`AiP%H0ig @-hM(PTH;v_ξv V==Ppbjh4½Z׬Y3BZ2eklp˖-,y(!k׮:$I/ ZZց5jZ Z)' -VYZ]T7wܹ b@AA ޿p|h'xD8kv{ (bll,8998uCC^Q*  pirEy6o߾ݾnݺUPH|raM眞xJ@ 9?0(,2L$)I >JRVWW??r9o2ÊN۴~zY7+++ElB(v޽9 ,chhH$ %7nYSSwfgg.IґX,JsNiO&)^4L())loo/xN$/PuQQQ϶mۊϜ9EQꪙ]z^8l;0aY\\0͎>l6)ɴ\$If}h6766@$T*E!EŋoBW9޽{|4M;].l.CSSS*eoߎ;֓$Iz$U*\.'OZ\:[Hrk/hiH}}< Bziiiih4ELf,˻<==$Q+|5EQrvYYYEiiF^w,NE@*$i֭[+=NJV%XF7R (ٳ$Iݻ:^F?P$i$fQ-NsKmma||z:$IJ[[۾M.IDIDSSSdH'N|@0L&)h bl5::WWWk9 vb鞞e2JJjI3ͫ'''^orrp8|i93D>u@2~>Tk(L#IJEDwIENDB`qmapshack-1.10.0/src/icons/32x32/TextLeft.png000644 001750 000144 00000000536 13145236443 021663 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX헡 PFϽ@ %1 A`bXb-|j0 2dl!̭rpp࢔(;Czifsخ0lǥRkZv\G7zApEk0%W( (mU0L6bxôhtG?EF8Uop _,Vdq@v@z9s:S>d=rqYqIENDB`qmapshack-1.10.0/src/icons/32x32/TextJustified.png000644 001750 000144 00000000507 13145236442 022714 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<IDATX׭ PȄaX XLV d5 zqLcl6[Ny+t MR:V@1,6qz~폝37Yp>ҤBc=F5v4@iC(ڔNWE;kb@ 1 Ābq|p]~;h{RIENDB`qmapshack-1.10.0/src/icons/32x32/DatabaseConvert.png000644 001750 000144 00000002415 13145236334 023166 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs_<tEXtSoftwarewww.inkscape.org<IDATXŖ]lSU;ko[TBc0HG1C }@m0'A`h#q  vбMwҗs~=?G ? [@/py`^qt(8:9 84TxtN3ΫEa-:Oihekx#99Y} aZx~t L* v_?aPV:htSx\D*:fYP 5Z<9qG sxHarܘۙ9TQ—s,)<`aqX\C', s9O_k2P* $88DP3ה{ΦRp5U)sv,Tv fޅ:,'X,ٽd8a'iZvK˯ݜuo!MÚ55D"!A M+|]ۏ: GPS39s`֭gLϧfsg'ڵ;wCTϧf33ϧJ12bE4mL 5MK80Mg̑K)s%شiHPȇ+(A[[R H1"eDfZ[˗rFH%R^! qB#6fLx9@ .<[3¶/~q1kӶ펎myD!.]ˡC?zz!航1 ÇI >R{۶]+ene<<|UGN_='LX 'IENDB`qmapshack-1.10.0/src/icons/32x32/AddProject.png000644 001750 000144 00000001403 13145236307 022134 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs   tEXtSoftwarewww.inkscape.org<IDATXOhgϬ[5"i *搃b6Л''67@쩂Dԫ`AT0h%Pj04ݝMwMD^y};(hjȷ K\Үuv$4H%:f7QMkreL|/cJZص o03̽1.JԾ &jsPL@]|#?.M/?H7ߊ2Ds,f|+VVlz лvhc]$ Vv2y1븃s~o|3L\ qƛt. &ыp?4rF u&&/ yd']e>1a9)(70^'j .+cEG`Zߴ$ffv+-0luçpc*m57i&FԆsΘs,p9Z@Ѐzz˵z4O',P z^쑭Шle{__,3fJl=.SxNHyD] Z ܁xߑ8ŖtNw ͸:.Ig+=|`Lv*eIENDB`qmapshack-1.10.0/src/icons/32x32/Area.png000644 001750 000144 00000003354 13145236313 020771 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  tEXtSoftwarewww.inkscape.org<iIDATX{ewM2T&ʠ%F*tREj}+m bRihJF 㮗1nACk?λ.ӛ9}95P!gp?Pߞ7;3p _02  q5a)ôtK1UBKiM+fN FBAQlS~X9@dƨõa ? P|8x:x4}wn+=aXH\t9y7dVVy N;8́r;1oR\AUll&!H(D8uDkQz3sI>M{`Y)Ql!p ȷ"7p6SLG~6qohŸEOUR~rF9Cٴr3q[tmOeS^L)OL41ħH4=˱3lG`9N:uՅݢMFJ'+5 |0rZF5a%m6opq= xL3pۙpDx jrnF܇?]R-DȀ ձD*'P~9=;oVt,}.4kX0O#XO\_Ǟ[3q+ñlF&K ͩt!#y؄ 훃x(?XB܋Q#ug<,xwqʢ-G2ٌ7h˅e 78pjo a"#^Eyup8 ©Zr8~(sv1" }4Vzcpϯ/xCT"Q5MJ<;ۜn܌3`/:軂WyB}VY \;z,ݏfa3`ڳTވix0 ԃpe=/;wK̕m0p.]d_'.B/š/k:WrC' Fc ʇ=r*XnDFX1&g#-8 dv*[S҉'%FU_QBcRD1ɸ%5BJZJF Ehu _Ef.-FEN0^o)n?} /C IENDB`qmapshack-1.10.0/src/icons/32x32/ActCycle.png000644 001750 000144 00000001724 13145236300 021603 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsrQtEXtSoftwarewww.inkscape.org<QIDATXahVUyM*k4,"e%+( !J*%RY$2P(,B!!rA\aQ,KKӇ{ʢ r}s<9a cSȉG^Bl{)iHl9V ^y(A`X97b xM<sitfP5;Uvzɞt*a kՈF r(NhuYuh3gJ?gabgPµgbuK;w'q|J'[M<mvQqd%<V&ʷb!;Zm! 㤠Y_͸'F7 s}u"HdɎ ?P5&i\B t?ď]Ar822Rz$텕w$N"M6 [ d4oO\^XOq)a3$67'[ ?a 9\'C`Cr/K'}::-sӢzF( [nECE,;`/Ҵ؞ؒ>v0R+Gp~uq2pa|:~#HÃd_&?R.ޚg`ې-Ngj`L+.<"#)d+FFw\8Ux|M{+Eޖ7` NR2;q{EF=;Fl/8@UyKKa3@6O'a'a +LM<;M$NZ~/W@ NSoV*ha&]h#>p/M1b|}򞰎ly0;„MIENDB`qmapshack-1.10.0/src/icons/32x32/PointAdd.png000644 001750 000144 00000001105 13145236377 021625 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDATX׿kSQϭ PTt'EDMA\::"Aɿ "ҹ`KT *yLMҤɵ!y.-Ǩ쇼v-ੲB=48@.+3Kϱ)Ȼ*Z3Hk߂d߂ M=Ɖzi' ڿ\-y yCgTN7a8$}K"RF!{/1yoY"}y#_v TuD"f\iIXMg:hw8Pk6툜Zמ0d/jQ/֟j}polSR'o:Z:cўD)YsqR8[q(4A<#{&܅K8X YVksiRZIENDB`qmapshack-1.10.0/src/icons/32x32/AddWpt.png000644 001750 000144 00000001424 13145236311 021276 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs mtEXtSoftwarewww.inkscape.org<IDATXkUϛ)?RBbjłڥ@?A\\]@@[(!b+]HkjlVti'9.\:3$nNF%X ~o;qq$mN~IZC liO<3*%m,r^@+y-iKe{z Ʋ{邫m<`^Hٴ: &Zb@:R b,-e3I䴔NM``)ڜopXC/No1v3AM5b%xc_[mf`/8/ gڙ2Nzng-7"4 HCucU>7=TE}|Qm^jwr 7 tۼy ܄%\@j 덡?Xª'ښ}gel4wgl.]Wt[Pl0}m3+c+1WI?IENDB`qmapshack-1.10.0/src/icons/32x32/Off.png000644 001750 000144 00000002117 13145236372 020634 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs tEXtSoftwarewww.inkscape.org<IDATX՗MHT]ޙ;Z!-)]ԢB\DdF8+!DPQQD [1ȵhz{ qx s9s*1P@ohbhoܽvoh%{@--2E ڏ7rh;ਮ9zTs54<--b~M uuDP<;ѵg 5^͏mZ8LԲ2Ǐ3Ԅ$I;J.^,9/>x۷m@#Ղ, Ex=^_ a^T@~>y"eׯ*Y%%uv~( ȎߩSj I\%qVtَI9cinMݐm AAs76 OL@?p@6MϞmJ>Ugm UTF#%o i @($M0V-6`eiﴙP^IR)Lg] 1 UUI] ᪫432L Z[[aI3Q dNǙ>}姥Nɧ:5Ͽ<~@ӨnF+dsbdy,sGc6_:MǏŹ^Eq: ([>Wi nrss}Z.݄P|>Ah3nE{k|^k_hokDB7gfwrl{`O%K,Rϟ'3HQHDfD C$2z][p躶 aغUSOs>7a]OD# p=Ӏ*ͫ/p4DFG S xׯ뾈ݟV={45dg;&j]A::45 (.p!ap47["DGʕPPIIZ+:jjt>`(p:'X^iرC-(:dk̵ͦ{a|{B}֍\u0` GdfE*+EN+0qq"-v뺹YMez::x<)ܻ̙ 㡡&L!6֌4u>d݌T9G/yv58`) HÀÇ˗! HHTW4y>=`gghZYGKud5(Xt;a\-߿Z@SSݫWpZpkj iȑ<33a&X^y8r֮Uff >L[{`}~7ȯ( n@J ̚5_pπరV_tHfxt/<\)3!6[ UJJ.NI'͛0v]m٢Wah1CIc6t ‚$/O#vkxNMg?sFǸ`Ѣ˂X/ 2s&Rq1@>艹+Y@Z8L[9)ɱdk;*je@p^R U3e!KXG?/F 'XdBF,`YiDf> z+h@: ù $I*Wi']q@ {Mz gȽJ{E;bݜK3svi\A+~8I=˲D=>CE':3 :#5іᆐSHoxVrώ$MCgapj9G(~@a+2JD 81žqNc,K@4ayH+e;63 pq-41 Gz/eUv;VK ֱ~>.=S*^+*gb|AW]cf ɉIu$ιeXSv\D󝋕S?BߜO^C`mQ㩙|F yƼ[bf %IENDB`qmapshack-1.10.0/src/icons/SlfProject.svg000644 001750 000144 00000010177 12705713523 021433 0ustar00oeichlerxusers000000 000000 image/svg+xml SLF qmapshack-1.10.0/src/icons/ProfileToWindow.svg000644 001750 000144 00000007750 12505266227 022460 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/000755 001750 000144 00000000000 13216664444 017701 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/cache/event.svg000644 001750 000144 00000027160 12455143304 021540 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/wherigo.svg000644 001750 000144 00000013664 12455143304 022067 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/earth.svg000644 001750 000144 00000245537 12455143304 021534 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/makeicons000755 001750 000144 00000000166 12374350216 021574 0ustar00oeichlerxusers000000 000000 #!/bin/bash for i in *.svg; do inkscape -D -w 32 -h 32 $i --export-png=32x32/`echo $i | sed -e 's/svg$/png/'`; done qmapshack-1.10.0/src/icons/cache/star.svg000644 001750 000144 00000006426 12455143304 021372 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/bluepin.svg000644 001750 000144 00000014410 12455143304 022047 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/unknown.svg000644 001750 000144 00000015340 12455143304 022113 0ustar00oeichlerxusers000000 000000 image/svg+xml ? qmapshack-1.10.0/src/icons/cache/star_empty.svg000644 001750 000144 00000005353 12455143304 022606 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/corrected.svg000644 001750 000144 00000050174 12455143304 022372 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/greenpin.svg000644 001750 000144 00000014410 12455143304 022220 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/other.svg000644 001750 000144 00000011106 12455143304 021531 0ustar00oeichlerxusers000000 000000 image/svg+xml ? qmapshack-1.10.0/src/icons/cache/virtual.svg000644 001750 000144 00000026617 12455143304 022113 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/minicon.svg000644 001750 000144 00000004166 12455143304 022054 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/COPYRIGHT000644 001750 000144 00000000244 12374350216 021165 0ustar00oeichlerxusers000000 000000 All icons in this directory are from the Open Cache Manager project http://opencachemanage.sourceforge.net/ project has released files under Apache 2.0 lincense. qmapshack-1.10.0/src/icons/cache/Apache-2.0000644 001750 000144 00000026136 12455143304 021301 0ustar00oeichlerxusers000000 000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. qmapshack-1.10.0/src/icons/cache/restore.svg000644 001750 000144 00000007515 12455143304 022104 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/halfstar.svg000644 001750 000144 00000010577 12455143304 022227 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/down_icon.svg000644 001750 000144 00000005141 12455143304 022371 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/webcam.svg000644 001750 000144 00000216266 12455143304 021664 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/cito.svg000644 001750 000144 00000250031 12455143304 021350 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/found.svg000644 001750 000144 00000017130 12455143304 021526 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/32x32/000755 001750 000144 00000000000 13216664444 020462 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/cache/32x32/dnf.png000644 001750 000144 00000003463 12455143304 021734 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATXklWwfvnxWl8aSڍMjaF%wɘn$_>pؾt:}s9K(G| ߎGhgG|^(U Ǜz^gxFB54QV^ȆOqo'ozh!Yư:;$ޛbldr f]%dY9[j~.{ X[v jqzi d-7E%m)v8ȸoj Wu~'^܅TUoGY'oo{C[` Dj|y?VJrL*coFxkd34{(&PT; ܝ15mEUQH;5=kh 0ݱePMP(&xJ> BZbv1, 55 fۅ nHY)vJ X֕K_(LE,;ܝDM;d4Hd͕[L |M%5{pIH/mpMEY%:04Nj$Hj3a,D̼=wG[p/+pw )1.$T0MZxP],&^0 PBOL4># e[3T|)hwMH\г?0l۽}Md^Ihyz`‘ܧ@ $KokgP#[(88̰"s4o]Oi6 e* <#7 ;cʰ ܥ )ed CꆯʚU9Jrdr4c{I_=GYuVó\;N? 0bk8x>cP}H zZyɕa]/tNKG rk]畍/7S'm>?ShJr Q℣A;$`q?v't-V$IENDB`qmapshack-1.10.0/src/icons/cache/32x32/trailhead.png000644 001750 000144 00000003452 12455143304 023120 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs? tEXtSoftwarewww.inkscape.org<IDATX]hSi#9i#j_maXӮAXBԋ^^0Kխ"bN (S[/DJѭ;1ZئIyB9Myyy< iP҈/ժXe`&ʫT&5^FwEH~jcRbOL5Œ+t#^!Ҡٖl3ikWeGOgp8\ЍC&z15K6oP!=z$ AD"=}}9~/ & !D (i" }=g~~6|c9nIӋ]􉤞4% bˍby뤞>A/7Bd:6*3X+fq tƹsUr i#4)Y~ W^5GGG|rn=55Ǐ u~Z7Y/ JLJOi#+ގeӦM466R__oH)~V|޸{EFQ^xA8}޸UVU~'ᲹV4Ԅ-87o㌎2==֭[ٹs)*69a$j+[Ngڊlٲ(WV+IV WXh4ۿ?~سgOQV</WU,)>>>N رcLLL՜bJjvs$Ass3PVVF<f+6dJ- MTU TUU;;;p/_dnZZZBd4U]FWI E7~BuN8Çijj*ʱX`r~2_^_ Fn>---4440;;;vLLLj`䷑\:Lw5UK\Tt;w֭[b1D"\%kh!9[s%[*ǞVB0^W.Buq)!IضmصkO<1{6+5gk8 @tuujfǓ3iZ(ǢGU^[Gwu@v{%J~ݻu̽|ExdUgda#1;;Ï=jڜ @IENDB`qmapshack-1.10.0/src/icons/cache/32x32/mega.png000644 001750 000144 00000004044 12455143304 022072 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsY;tEXtSoftwarewww.inkscape.org<IDATXilTb %lb%RBH’F4UZ(jӦ-$)AP0$Ҙ/1cl7 ^f/緧.xjl=lRMϱmƷYPR?}EҳC\Z'פEQV#e5/`yX#V!8 B[/>pg1`ncmS !sd ~~铰( dg &9EFe2w$soF\i\yF5ïk=jķڸj.n~`SJ0]k{X#JRy5@gY-fu|v/kMF5|$i>)G 3)سRz y#m"Jɰ{VnSxRbcHq/ԌX81 Z]\mfU(s Ӓ( QAwa1I)GxyûxBr냓lwfR"gT\ epf6A4xސRXR6讄Uwn25Ó (3q\w][ߝ^T[HXYېdK`awzMpFxQBƠSz `w<0 `ֶxBw&kwO\u&͇E'L"A/lgxA*X.~^=YD7 xd3Qwy,{e%5F֋E[* Qh+"JBɎ~8~B6{a>u )B  vw"&azډwp+Ogu9!ZV,SgV#,MCY a 03r"ikY=Zb6h9A(Ku+f{oWK*VFǯ"W8נT j+L2K;"OG<y~'\6/HT|5]@S&z"T7L$0שvҁv^:I"*A`4aj}> -&A5RGE ఄL&%* BfiSEl@SLҠ)k`NnMA!x\hqV"6n1=ͣS ti(w:DEm6(-:p=/}¹2Ex 9,u,ևldYq&+0866?,SXXJ>6n7۝̏7-]:Z=*5Vf+&UnA%fAzOPTqi1Eoʐ0Q.<.dK e" dUieP$65 !/$L;'4 x$Ⲷܟ!%+f:C̥P.c"RR' G }'=r58@ۺ:T7>" i+£wރ tv=X2/yKma5qW} O> O75uy[ p$«Y^N/ׇQ`sLNwJ cm>{y3@<- 5 0jL 8uoC0 Kpy KzmqxmIENDB`qmapshack-1.10.0/src/icons/cache/32x32/OCMLogo.png000644 001750 000144 00000003171 12455143304 022420 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs<tEXtSoftwarewww.inkscape.org<IDATX{l?`H<( KC\&RHkI4LHBb6f҇bRD:R5emAmPp5$fGq|3c^i)=Oq;R->X:7%xq법kuPowm`?kD#yon73>ϧNoy䢙;d/=?ZL/+v|-}閼>۞O`_v%%OLv#3++++^Se}g5sBxR|_iyKPJw+&2`~ggskG-[vt׮]#6m:z-"}BqU>@s'::^5"Tmm</_fɒ% np<~ܬ>YLR\oߎbl6SZZՊ餷t:X,ɜJq7fU YxԶoAT1/ckՅ_E`+~kxxÇs﷬4tx?uqARMr;ZG;٩^I1xF0j***qn7۶mPmmm kwvS_$"P(p^nXBγ à˗KffqwM[OV sqf 0 rss Bg~V XR ""Y#]79++ `*pRFP)u*bXlt׆aal6[W~E5 D".'9:FUX[ȬvYfvsX.tg!#zVvϷ!EعsҐyEt#'ĆR2&5L/*#=(NL@ˊHW#y͈v3w0ۧL٭,C]e;L{RD1`د(n@rGjvWy<)y.p8<@Gz.0L%]=Pu8 %ұCׯ7'=)[H pi^N(Ha(%:۔Ci;li.h#CZt}0?ykE|X {2v& mR8;viW)eps -Z xUWHDk{rt cӶD5^M]4'}ސ<@j}DY"R0FogG)u&+ڞLxءZ ED&HQ)J%'*(J*(*(lseUOC~~>RYI "DQ $I(((Lye׮)])6oR0aA 4yXBrss4sO *щl=nuV9@idS^ >o7ܼgX,IrBbU81ϟz?_}}}C$= ֶmύܿ'># סCN577.**br9VkR(/plgFc8T6rN[,cYII=Yw6zhH@ggI˿ڗƧ;=::*~:88țL&C رϯet~uf%ν{vhvdv9 HZvNa\]J\vIENDB`qmapshack-1.10.0/src/icons/cache/32x32/down_icon.png000644 001750 000144 00000000646 12455143304 023144 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs774tEXtSoftwarewww.inkscape.org<#IDATXэ@\!׊uE\ ؇H]fe%? ~u8@&t.@MuED D@czZatױ^**~7]f m0 B{(, TM|}NB>+P(ח*)q lTX_ؠ`L&*T0כ zQU0(+ z@A!V(C aЍ) #~ Cy)<o/dIENDB`qmapshack-1.10.0/src/icons/cache/32x32/unknown.png000644 001750 000144 00000003513 12455143304 022660 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsTKtEXtSoftwarewww.inkscape.org<IDATXWoLSY^KU-qGp)@la #@!F:X1&Lf]M&~3 ;Y?H;``-C8*KBőm>)}'9=;s﹄1\nmm=PWWeZ bHA55w+VtmmmKCCQѼr}$7wrB?ew%?,be% Cee JKKVStܾ}{ihhܹs'c9lGqVVE ??BR=Baa{D(,… c/^x<[hoo{NӺ~:]z" `(|4/TTI;<<|d{B'N8p8,~/@BJ(&QP* IyD̠t7((Dmopf9# :uRccUePJp۷o&tr@<̌_}>_5(-} 33YX !Ptwwu<ؔ0N)E<AN *BR>.Guu91:(Z05uU===M@oT!˲b ߆#(86 čP B!ǏSp.ZDjWLR6>LNE6>zzZ^iZAxh+,u]9AX Μhn)dYy>H(EB3 Bde)- (ЗIeYޓ>_KK%?=?%% M?;$IZ^Hҳ,g4=<{_Ly T7+9/J /S8Iv/}Wz|>ݟRJe_fx?Ѯ+M)!$뛐8D"/*FBN4:~f) W~lfK[7:?Z FtفHNփU7oN~#tsss555Gh<̹L{GƎ Ըlv\zgަlIS&##c7o0!u%쫩Jq(**YޑawCW,L&Sb9]{wKlTTY%Rss{n-( QlFѡ/h j< x<O 1IENDB`qmapshack-1.10.0/src/icons/cache/32x32/pushpin.png000644 001750 000144 00000002270 12455143304 022646 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  OEtEXtSoftwarewww.inkscape.org<5IDATX_L[u??Zn˅4Ƥ[: F*y!1F4qouF,3d=4Q_䁨l.f`pĔs[hr=>gҖˀ{ϯ/D TZJ< n 0$".RʩEfZ T#p AH_Dd4ŧ q$"3ȔlbU/`eM*@Z Q>$q@sQ?A&@LA 2 O@BŘkR?솖8m˷qh#;DlUqRỡY(0gI ;=/pЯ[@Rg_GV:8g;ح+l6j!30cTB6(>AKCeL7(;LW_@U*-[:_P>t3Z廁8T[h֓` Gr",0UUcN){JDzUDN[x<fc jЪP]Phs$ `;fǐA)R[np߾}MMM<әYx= 4Pzo8WTTio8MB/1$2>""(p"RJO)4?66ƫ{Pc$pF ܹsK}}}@ Giiif/p\-ED2Pm۶Ħ*>11!pl%7;[lyxJaga5IENDB`qmapshack-1.10.0/src/icons/cache/32x32/bluepin.png000644 001750 000144 00000002442 12455143304 022617 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  OEtEXtSoftwarewww.inkscape.org<IDATX_lU?~m0Ɛ̸ͪ0g^4h[%i&." > xM$AH @ ' ]kF׵]ǿnsUN4ى8E# G'㪚,Ol])l]XkeH_bkheUHUm7UE3[K R=!`k33CE.T܉K[g=f-"bמj;Θ@U  )2'?ttRyqxŎt^g3kY([[B\hH4F,>pt "bbqVLꍼ~-2*^`}˲ldbRUyVv dn~TuW8x Is' F1LkW]̚uÒQ 2Pe[ Xif_p6T %Ɇ 2Ʉ'!VSR@sY)@sJK0,:Ȯ鬕(u>0ϕĄM5DQ[!Š HG!z"Ӭ?q$sKQB $8Nh溎o~hȨ +ٮcRՑ""˗/lӦMeӷKmӧ!u$N 6Bfۍal5MH{(ҫ=7T5 eND"RC"2(6I,H'C2$Et``g1 cւ GH3^L9 H'54bx Hwh׮]\8pLŒN4X<4+1$qHBE (vp8̡Cx|?9>bpi։f)t3_}}K[nDMLLm&CmC)`ZH$DbڿB 絧gwK|}1_8jxn hii̙3?\.WϽPSSwUUutt4qaŊq i(kY+W ~f{~ yvҥo3&rIENDB`qmapshack-1.10.0/src/icons/cache/32x32/waypoint-flag-red.png000644 001750 000144 00000001262 12455143304 024511 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs6VtEXtSoftwarewww.inkscape.org</IDATXӻkAf;s/8ba!VxKa-jaeqV`oeBPDQsF%q۟Ea I$~̲3Ì`fvL5uڱn0"7ǣb.@81Q`0{7 E$B;|z-J?Zߩ\.q>araq.("PD @p=xQ*=^?PBXT-+ijFc"D )a*EblLYBM& ь-! EL#`Qɀ'oXL0ķA;>(Z pu%h5̞ pp~!;l"1}{[%D睟hZ)At>3t~G x~f0XxW#)WZIBT=f6 "| [ݥR@ H) ӭc]Xrw*~˗\ d3 ɗ]hc c6n, s8XIENDB`qmapshack-1.10.0/src/icons/cache/32x32/star.png000644 001750 000144 00000002540 12455143304 022131 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsƺ5tEXtSoftwarewww.inkscape.org<IDATXL[UϡA[mhiQ-_)Mnn`-h8H`f-18 (l:qnR[8p1AM,0hGR#מw|ι!mZ-M_˸z19tr""(UJtSߏ9\u8W@ )IChN$WNȏS`@'NCD\1,v!!PlP+5ihy4""Rz]Lي "-Wa,0Td%|(6yJKԱ:Ц CBhɜCHīxiK g7_dz)"}|b2fMcc3SSS&:̙n¤˷J"|GQ<4ţh(O 7^% |+@fM"0 ",Ι2 1 1,掋TOD6yǍu"*^ J- 4QAv fc:wu!3ref;Օ|E6{m'{$򶕉>W%S:g}gg 7ˮʁ9XqIKC]&=GF&h?vg! "rg}*AB ],@˭k:SR"ڽKh( t=OEKk'kbxHOJz<4^dWkz ;;ޙakB[ai[W;_ rOI% h* #gc" :?# fGTx85%TGYѩ6)Ra:o^+ߚ}ͅ?G]׃W6<{ :[ܮ`OӾWi۰(JMlSs<0>o~o4Q{o uspݽ/w&n E}$3@r^(~`׉C!ڽ+AMI.[)Cñ=dZM4HoyAo(=U1d\Z9F߭LF']~xg(}aO2Y@RNTeP%(a]F]`E`tTJVԮA$2I(d4:n!Hbb;N챎?9yJeen~=55@Q4{*nٳbŊP|" dc&0> >c%p >5C($&np GO»XF6>f+HQ:{Ñ(I;;fw1ܡBs>6ژ+P[[1==s˕4lRz]{;,~!D>&.W,DKyO_Ν;s]!K LFFv7,Zb<I"ʥ) /sp:Yv{^9s,bd{.kk[۟ݛ~+9x"(Q )e#hvhGtSD3rpFiM.AbFcʤ)뚚 BBi%sKexz5]1#[)ׯ_䃃O +SPR7mH^jB aM+11՛_N;JC=>JXN`%Br/B$o[!'%ѺGЙJ,=:n;v~QV@1x9PffϽL_]S{KGFVs…a3IH0>-DJuN<7⃃(CjTp;?1SR10{c?mkQZt]zŀI)s~X^[[;_JѣGկO]]N+ͪ$G'<](\uEg\څ8#H4.]{K>%ikcVlY3eu}ytÇ9AHE556S|LQ`vZ(-f`0<'H3^!B$WW_~;WW&Pi-k6l7 <j{b|ԥ-.ɺx<ԊBcPE{2''ϒjÑsǟ6uï22K0wӀ0$SSsYMc2i="nlQÓg+f?OGXlνэ᫿ӘZ=;Ϣ+*uIFFGUeUw0eJ®%H/db N%ݭvb}QUF`drn]cN#Y,#_G (WDi} /##cz 3]G@ UŶ?,!SQߟ H>4-= ^$_%PKTʷ_O`ڷG0`)EPM,QU@vKJ5n:BRRrL߃`W]Xi6AlJ %Es::LlE"=C(b\Cp}F/^X~jrz#RRypX)#ptERJQi*3F@?/Rʇ}Vd29ޮ IOuw_^toD(D>ǼM0]`-~,R>:u+v{j L&:TSs~X ~!c311/ʣX[>tfMp3>tBܦ?xK biM5̦LYbX滜93|g>`u5۫%5IwRX7"pXlH$js0666T* ݭ( ÁF\׻n!T'MlcV]*UVIh*wύar Ns B?~۫z Xַjuq fh4@ (GZ^ikwBPYw%D"dL&󌢨)J_\\<:+ np`Eq0 m9|># q +(id25Kt6ei&ɴHd{crrݦj/6H$ aZr::;;B`pqww7 fl~M 3 P( ߋ㿰/W,7FS0633ĢH$**[[[zt:}J%FI X ߗ) NkWwbؓrqX˟+(P(V JZ[[[j0 ZL&h4]3Io677U 5H$/LH$~-5/tbVB/>|.kD"l6[R([|FGGGr )NN4-'VXZv @PKӽ1 #&K$_c 4ʾP:ێ'gxy<nwJ]]]$ApE' ( +9tͽ83??Q >}vvvړᐯFv+FFFsub|sޔӥc$IENDB`qmapshack-1.10.0/src/icons/cache/32x32/traditional.png000644 001750 000144 00000003203 12455143304 023467 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsKtEXtSoftwarewww.inkscape.org<IDATX{PUƟs|^lU\\bk  fx ^2/IYL֌h%5eӔ2]&GoC!T,4.&B(,Bv9}oĿ02$FkI%sw O1!"f-~ov+' %QTLzB2zto`M~W%z DG $M寶3vQKR7N]*zS)E-zh bo"yd8n ҆^@:w0^!a}F@gpdtD.BίO#,5[<V1Fܓy [1&v.'hg ,B [c{q]- MwAhh(Z-Vdgo<Ï祐K;\`EIɄNd2h49{ 7ཛྷ(*(vw:!/\JVEZJ"ߌf+9֭!zu6Qٰ`>yj@8jzV| ȌO-Wϊ3ETF=T<,Ǣus~zP(cskQS0-qpg3E奃Ah;v<0 \0@) yKŒs_Nwp'. ?n7mywTSBEэn6 Q()))2/oQ*dHI>\<%\asL&P`&#rg7.Ctt4 8f9zhv;mhhRTɤ "<σyaf0װ]-y,95QHz<܎W %qt:}1cƤdeeյy \.?X4S{zGu }f@brr/^7_Ju"oCuu5ҟ-=]pܹ;v$eff ZVV#<<<?. ̄e{aaI r9( zeZ?"YҵkZ|>~^tر7;v}9N޽{Cv[III;322Vm۶mTEii»;R ;w*-yVRRrnrCƿvqqq+rrrZ:::455FAφ!DAvvagΜD]]ZcUdd$ɵk׈r\ IENDB`qmapshack-1.10.0/src/icons/cache/32x32/DistIcon.png000644 001750 000144 00000001223 12455143304 022671 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs44{ FtEXtSoftwarewww.inkscape.org<IDATXVKAf3n6VQJ% AA "B7C[o='x^@E5ڒ?̆d=t`a|7W :9mF2NڅJ/*[}{b_-}CMغkc9m %>xc__SmMN@˜@8Q}1"3p"!|c"0cB@1aK8,xg u!uK"E@"5{(! H"$Š|q1͘,N]d Pj^b{/a3bl/ΕuB31Uci~؞kyE%aK(:fˀbZz:_3sR'a ] h 5wA EhKS|y *A(^{ HuY+'>RkҺ`RM s jL oGІxd.AEslfqw.h=IENDB`qmapshack-1.10.0/src/icons/cache/32x32/event.png000644 001750 000144 00000002152 12455143304 022300 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsNtEXtSoftwarewww.inkscape.org<IDATX_hWe?{3ԉXԍdȬN"D"n !."o&#Đ.B`]̙Ks@Ul=b;cn }{y=d=W6QdgϷmE^i&f&<]c1,n2!k,RϦj3ZW`}ңjͱmaW5"RHvNYHc'ND y_HSJcx3 U:}~ _dM5]N/%Uտ>UqpZUo\u/J?WUcN)'wZN+g`{|gGRܙ6gz`{(H߭pM7YfCKa-vMulIw,ˣ1`uzS\\s=V־NJaZ/x(*,S%L? h# |=ƾrдxʣCDkfcWoGllG(.4@sB vQeF( 2+Ӗd  u ݖJ2z1NMCp1WacF/8&R>]%/?$ :n^t W fji1~ {1񜌉TXhJܚ)`f-Q ?+i7m!'-@D|qn˵H1;YB~ij$"-26su {%Z._FZ70/`^90_#8JF:u}rkGAg,6z,%!bžPu0b脥``au@IENDB`qmapshack-1.10.0/src/icons/cache/32x32/minicon.png000644 001750 000144 00000000362 12455143304 022614 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsYtEXtSoftwarewww.inkscape.org<oIDATXױ 0 D!ؐ`#[ $"]YrOr,+Eج pWhAu\:}QU (۠ &kxv s@v@'o{w@skIENDB`qmapshack-1.10.0/src/icons/cache/32x32/greenpin.png000644 001750 000144 00000002437 12455143304 022774 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs  OEtEXtSoftwarewww.inkscape.org<IDATX]lUgv;v6-u[RRcJ}鋡h$bU$hbo"cHxhP" 1`RPP!4~wn[˶|drgUnk)4Qh`-$-Eh p- "[$Jo( B˪ODd5EA-.c /U 9|=lc]ĜU^0e#%UZl(,KAq%/ETՉy2,}5Ŭ̈R9@hp*Kv7@wΜG&/6Y5/qKW ÜNV>&|"GDy?)rɛ ΆXK\ąKaɔ@HdXSTnzKAޏV_n4|0][%ZQ`R2*\OFN&مoI:zsY?گvYi=z%?_&j7p= nYi؜jF}P(bttTw1Z[[ +W; i<-9ohh,--pYjjj>>tP\g/j[[݀^g a+muuuߟ?~ZsEEEmC8QUp४r?;44W~7-< |򷛛#@v?^`YY[Lu0wMIENDB`qmapshack-1.10.0/src/icons/cache/32x32/treasure.png000644 001750 000144 00000003325 12455143304 023014 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<RIDATXV{Tg;s絳3;;3ؔvyAB`hhcijXbl",m)I5es̾Rz/f9;{w?b0I7⋊;-P6?Nec8x_\N&O&rz90.tD8WnYs؄)Ab"{~cM!@D+N_7wGU`g9 ǐȔhR0^sW l wxR@ી7W>>Ӵ-Y" \ArH#7VSDX2D\.Z" nv߾.1S:΂8M#lݡTڼNmNyӶuPW@F?jSUgVs5MеwT\M}uPO#ԁ HOrwHI\_"rx4H@}duifI]Wl9jT +ٜvGpW rhTB]Om't޴ Sa&V1lY|;Thjm뛪rȗ,IJkY-x*Y:s!O}+|@D%?Po4XSk,piEI?INqp  YM⿺ym:,ճWͽN*oh:'ƀ7?_=0R9WRX " ;Ѥ[\}y_e1/}3f %s7c̚/% cl]Dҩ?MkjGiH` 8u>e9sPhb-c-4U W.=3btS_+w)k.]+vo :gWn[IENDB`qmapshack-1.10.0/src/icons/cache/32x32/wherigo.png000644 001750 000144 00000000765 12455143304 022633 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs9 tEXtSoftwarewww.inkscape.org<rIDATX[N@OĐ\:<}x@za(l@}{1&0ih;3N۾ϤsH@Ol33l?@_`s6؆H@5f 9لuȱiH:@\#Sl !**$h("# H` a^dy z 6(OлY.{5y.@LAo!R>@"4 `8 z%.r q1G3wAup1qdR: óp[Gx3G@ܙ!xA]lG@exxe"X{adXpVx翘CIENDB`qmapshack-1.10.0/src/icons/cache/32x32/needs_maintenance.png000644 001750 000144 00000001216 12455143304 024617 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org< IDATX׽kSQO%*)֗." b WA'W( "P"Ji6qu&WhCs~aP'VIENDB`qmapshack-1.10.0/src/icons/cache/32x32/cito.png000644 001750 000144 00000004137 12455143304 022122 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsԑPtEXtSoftwarewww.inkscape.org<IDATX{pT?}{f`AFhlT"hAXp:ZюLiQ:-F:ZbZA w>=c<$s|νWH)΂\!oŪ*]peFIt6-mѽ;wDL0.@.YY3,Nv MAyRĞXKt+.g-2^GҤ;8 ȹB//l'$`k ?PMbHYAP5G6$s.y^LsVN!NT7\J|ue0vQ^>xSL8IfR(\濶޼2i]nx!k1i.xEۏ VR !awO'*b_Ն9ܽ-ޅ5A2߹CaݭF>@!KxQ;5*K8i'襮7b[5ښrb1:j%l ۛa6} Z^=UndL<Oîb0&ҷT 26Ҟ/.4zx!7I?`VʅijEbG};Z+h`O؊!t;kD5š!;V+03ic%u@˱]㯎 &3纵>:vp%\XS-!83q=v'>' *%1; ܀p*4>@ );QŇ$8c'^Dx;w Yyw"txfm!<vY5B3GnlBʾw|IoBo=\UT-bbAчR/txnJy;_)8ǨNfD_Kueڞ￙ 6PJ򟢯jo8S5]PPMa(j -(eóahJ6ԽhR>cBWI]+f?Z؏3X\VIENDB`qmapshack-1.10.0/src/icons/cache/32x32/restore.png000644 001750 000144 00000000422 12455143304 022640 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs66NQtEXtSoftwarewww.inkscape.org<IDATX1 A oe =B-DY/ )ɃTo! $Vi@ Dt]u  #Ǧ4TJ)/G Kk S0]ś{G 0j`ZN)IENDB`qmapshack-1.10.0/src/icons/cache/32x32/multi.png000644 001750 000144 00000003775 12455143304 022325 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs-tEXtSoftwarewww.inkscape.org<zIDATXW{PTXvY`D F,$ DDQiQ8S"ZR&1*b%i'Q Ҁ/@@.]Ľ{a.6͜;|}{Sl-l}e'=a]IJk[ޘq4ꞡPz2iTӢ2eڂ 7){Dρ]Z3E]e`Jc'DZ^ #FYkcLCScƤHMڹBeE6!_)&S# c]\l+]bfYeee/47N@1ٱV,2oD||G.X5{W>R-~oc::x(`wXhj@6/پ/r͓RP`t:/?@W &8 )_H3cI qjqaWCĽUoVq˽o.BX-KpO/\S7G û'd*plpdq1X[uUHan.e bYQΌ[qD&A*2&41{NĦY [ǵbf+J `ccZvʱLk'.ltkCq!9rblY@)}1sUGÖ4'yw9SQ T<)_ը˲ 7xu33ZsI?JZicN&+g8y(  Z+ˍ:R FQsI83e߮s0x!h琏FΖIؖ#)qP(yި-JMMBM,J_ ZPgb?U c]\~ܗA'nL4 ݕ/[mV(|pVV3555;v$E 7X^4޴Sr9< }`ti$OzW80;2~_4?0JVQ]LkaKxΰE#zaáںhdTS@!c|h;#?"Z@Z+}tmVK.EgjZ-Jk"[Ѽpw֯"JQ{P9b19#)(3gy/#<&tiN1Q oh<H䲆YT@QH(ů4έXZsֲ!D)@k)y18-ghNf k8 5d`pTrz姰1'ֱϡ\Sad$3$Q@}7ᚵk{I_JM|2׺7E'IWuII> @+h}@w|_PN_ 02W>8Y_? 0ؽA{iRFG&7Tp @h(E6j/ojxI2ѫ/ wZpB.۽sCtv(IENDB`qmapshack-1.10.0/src/icons/cache/32x32/maxicon.png000644 001750 000144 00000000362 12455143304 022616 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsYtEXtSoftwarewww.inkscape.org<oIDATXױ 0 D!ؐ`#[ $"]YrOr,+Eج pWhAu\:}QU (۠ &kxv s@v@'o{w@skIENDB`qmapshack-1.10.0/src/icons/cache/32x32/earth.png000644 001750 000144 00000003300 12455143304 022256 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsF. tEXtSoftwarewww.inkscape.org<=IDATXlS?ٱ&!a $m6H *D(J uZU=?tkspuEyaWb&4_!y@'HD&v.v`OUsWayA3Y+JtZ@yކض8 (r~aH<aamй fՓϋٰ|:1/˲^ZJ:UHOn;w͋.^lS@a.l:럴}{Q@>OU߅y^Fo:lIqqκFR@9݇_ /yjRM6?qCe񫻿ɵ۳IT56/v˲^9A1jg6ȴPS㲩(7]ViY۪8S2АݼiSKM-2G5~Sիs; F`0Sþ;y>%sn TոWwhoo7HA m?(?ܱcG^cwݻkV m/Ft*yޓRʒH$2WB|~سgOu}E,#hޮ#S6@ss4G&''c!;v ye=111A8fvwwwpX{! PA8dK(UjY;iwN:et:~fSi[?)]]] !^iY7{zz؏a¶m5!D(ۏ=z!o! wIENDB`qmapshack-1.10.0/src/icons/cache/32x32/up_icon.png000644 001750 000144 00000000542 12455143304 022614 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs774tEXtSoftwarewww.inkscape.org<IDATX 0 @U:H'D٭tأTr/D E&$~*#"U}߰. " ևT4@|?`thf-PfS  ^fzgIYY!I!I!Oc}4-PH!BtBtBFBFBVBVyVkn@bB!~pELo5IENDB`qmapshack-1.10.0/src/icons/cache/32x32/found.png000644 001750 000144 00000003576 12455143304 022305 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATX]lgfwڤd[ KEC 6(|Y %/!I$6j#$Rh6 VR jU<D@SHĀ,Q[(~̎_2޹=3犪8*ڗ/^:W$ $\oISc(YZo5mQH`H$"wuC_v_zTՑ'xj}BɐT3$ř9˓C>/٩H$%q5OH4@Iplfwko,[&-[̻pT՚xw Kgj3?[㥖 O?]? ]9qHŊX KsbV@mg)qqB TU iHkOFjWvg_O{=SU٦?j7P ujShJ&'Umϧ>`l̢}|s9Ey'DZan\$T/ 4O2\IDbF]7BR#Xj!XiN1 Ʌ ȇ<[,h7} ,]RF:-Ldի-2pEDI&ʸ{7CUU^{UMUA(EwLBԘw4pTOE _TƐ8"ZmmRTMLD5%{"E#$3K c %uEQD"j 4(XN9x\&.Hh{(e8̛qAT&EA1x3id UJl"(&鋇{W7^ArH&#<<"'xFt/S,Y{-3__(ñ28 t/w8j _W+,d®]6Wj)!J '~/P`JpN2HscAIdZaxtش`ѢB~oLdW>ϰgmmZ>0wEPb?}T3ٰƍ:"K6Wy1vN D~OU@o 6 8zd*vg9 &=R ._  ᆱ~ ~uurz{NUUGzz8NOmQ8~䭷Lxa~ѹ1y; M"*M:pԮ]ߒ])sS1 ѴbR7(~3&f9Y4`<2k @4zBL1NӪZ7ICVp?Ú6 / /R*A5e 01 IZi4MeZ%UUL˲H2VVIENDB`qmapshack-1.10.0/src/icons/cache/32x32/webcam.png000644 001750 000144 00000003527 12455143304 022424 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYsTN0tEXtSoftwarewww.inkscape.org<IDATXklw޻޵k/~Įm$4J4mqkETJTUFjJ Rh6V@! Ƭ6>fg̽z ޏ39̽pQ:zڃnT"䩞+jB9g31b1ض<}@ ,DO(@uu.Y>@dm0B d2Auchh +x O˲|  }gvv6()AN_xqsBEQv*RC!c-SJ黄||)(877O)"Ư5666TVV*.+/zJ {ïsu}@WWW,4m -iV]lѿI[̙37na{+aJ=Y>< z$'0 law}enLJ%X$  GwކGƚDoo %bЌ]]/5 B& UYA7,錅C'PS"P퓧&QY˂(J)(h=9/ S!2 ZTOD}&G.q jW:~p~(z$˲f2$$hPQd `4뇭f18ڲ, UAWQ$lYIYɲ,Pdv^sнOAj~5SAԖe|S(i "&mEK~eAb0vq{^xUl 4i-_sޟ.es&5Rx|h-1;1n"ঁbŽMO2j8\?$O˷ m8\h?C;(@Y= xjU Clrj*0z= ,WRP 7*Eh[ml}Vh .\kƽ~+Zć8{E<0ՕiR0z5-ūa9Wh;[@)M2m ҺkMW^@`ƊwD_`=TAžwb_+u:`(MKPJ*8v<*,sI ,a$l|0&{8w]G /g [WZQQND>ۀO`'"&l tqFבF*rgPy9~t-k/))BC-D,O?M&C+UU(uEQy{$IV2Lf Rq8cLޤ5^_;B ,/󵕔Y:l{ ˲(JpȪGcr{p-b4k D\u8ŞRKqӤSEȒ A@iRL$t4Iz>J ! rZ**M1m"s5OТ1dnp^|y Gcjǫ*T'HyDc9H #^upy(`'ϯWx-6_Mի2&lX0&ѿ^#/?NdĦcz&bt7fmIMC!yXMoW6IENDB`qmapshack-1.10.0/src/icons/cache/32x32/ftf.png000644 001750 000144 00000004065 12455143304 021743 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs< tEXtSoftwarewww.inkscape.org<IDATX}lU?s}齽))m 4"(ƗmCj)oae1&NB&˲LPZKN[JX~os/- I~9nqF\.l@IƈDˮ?^ephO44-`=fh(jJ,j7~qhَhv;|4fQZ%K)##d!V 2` ?-s;83g{񚙈D{ٳ96!''M)- .6ۨ=[ܣMq[曠IY᧣ ͕(Ǐ_%\!9B_;Xc2u ,\.1@ &z),0iRH)if3S &ZTd=q~y SO)"IgP(v\1z5K. ='hM A&j"<7 0챌gH9|4ESM\`WcX$4f4*&wHdNN$刉Bp9jWR 9<- $b RpAM?cD"Aʕ[ qGf!%RL3hA$e2bq~ٛX)}fg鑱LSS$%%vljjb'NכR\\ @{{;1~| NŒfO Xgveپ`&egON,~;vP[[KAAAȑ#0w\Z[[ٲMIL6c{z &]eWk\Y[om#r ^]v ˲8vkYڅK,fqlUUHs7$nr(L2+V œ9s0ի:<`;9_{-}׭JUCUQUB!ck{shy%WԶ6nݼy9s&}9]zz<.}iS{{ǮB!ck7[;%G;wf .\HOPSSKss3˗/'NsvkE]ݘzd֮M5>ْ,kUd鸑]Lcd G-/ vvxn_[׬\12~yW7DB?+S 7L¦Mώu͹nz1YPvNO;jfY3Ɂ7-[]4_ƍEvVx;Qk=w.w )+wszzso= N1( 㰷JMF\, /~ʭGM\Fc˦udUp&JvH3'"7v 8unu'ĉŝwax`Alqe]:Vt~^׺PƏf N|Μb@$I5<6%2ac1-\L}GCϺn`P/e`mUڡ|\\︹,zml:i\]{kZw-Żu񱱄NdYZfQW<>>\bRLZe˗ƕHF/ FȲŸ]_8yH(=322lذ@9rdYbbbŒi:'bԩDFccc݇|Uz.]Bqa!1k-\.9g9pH3,˒$I+f$**:؇^Gyޯݻt̨*v:[NgZFq Eff\WZ;ч+л@ɳ(= Ba?U\\U\\UllUSSɓUɒ YWP'1߸GU̍?poIO_멻a4}xsSRt㤤"IRzGg%*|sfAn hF=fG@];uPEFk;+VGt!<"ѿN#;;CefGK=4,XѣS_{"7 P~ ^I>SCط25 /[?8O P]]-FX, C)1immeT~ȠA0V $::zPqqqxzzb41 +++!''7΁:u*/듀bE!--Ļacc… v'N1pvI||<&Lxm1}tF}Xzٳg1Ldggτ?FM;Ҷm۞z@/ϣ!Ch"##ۓ%^o$I<3oHTWW[]pAr$ TBIENDB`qmapshack-1.10.0/src/icons/cache/32x32/virtual.png000644 001750 000144 00000003015 12455143304 022644 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATXWmhSW~o4ަM? E(lE!eQժ0v`":Kcر?6m"tfcuZ6I7yc$6IS9=y~0h-`Bz} q&Fhtx~~_k"G/޽x<8PWWhZX g -Koss+,I Z??>/-iEEb4wцgϦU;33Qxdle orҥ _KoFSxa\ "l6ظ|ZTTh4~ZBI<f̲lf?zT-x I$qFebbBHԄSN-޻wϹ s}رح[|> O7 l8Nf||<(#lޢj5PHS|OQ Qr"+PZZ-v 0 s&A eeTa`W׾M߿Vц&@4=L)v'mI5{&7p!|+1`p$$N$µQa/ht, )vn7G:TUUm-(r^Muz_zzz󚚚1W"pRJ^: yyy8vXx+&^搛J&PżfYP1]ρ-5[躎09ѣG7-T/yquXˋXt.PPP>ZEx+XE RVBNNZ[[,a,:[hIB*)n0p욤guŦ廗߸f3d:MNTXuFfF04=ȇVJMN O&q)-zWHi)tp O< D*ݕW F@k>nʫFN ;}}~mݣf_sM涻)y᲼lmJ!Il6<#MhזRi{LفזQ\cȟL<Ha{Y<8>t)ΧzMa nF3+k<O^>]{ʖӅB4-AcbL-gHɼ> Xے~v< R"IENDB`qmapshack-1.10.0/src/icons/cache/32x32/log.png000644 001750 000144 00000003601 12455143304 021740 0ustar00oeichlerxusers000000 000000 PNG  IHDR szzsBIT|d pHYs< tEXtSoftwarewww.inkscape.org<IDATX[lgfwmzI]m."V6nD / W<8!"I$6U#$Ж8-ЇHBBr`qKm/T^ggNfvv}+O:ٙ9ߙ8CDBX&rJyUY,EDRSI{`o7T5X> @DX9_[n,40D ?:u7Dw<̛Wֶ|yEӶ֚gϴUOH(@I`?Ч?3'Ns}2=Z}F׮-=0oX :25UUP,j%>jQCʾ F@DWJ$/{R@%W[ \lv@ 4Cee\"R<{VsF!2yWpf+,\tUN}W-s ~J "CȰn}҂j<˟GUdQ2{;>/A~H; yMSZj3g: M/l/J$(+%!UfUfQfTQfi3bh9W_52j`2kf 0,\8x!/DH۷TUE~(YowMO@E zEM )C@5Wk~4oi&dιeʔ@u !: .0WQT D$He;'&(+ ܉3 (Rn! `2> d)-hG ,JA[X<o` 3 l ?"A_:Egċ}W{͒Jep! Tc$WGX$aˮ]6N}ٛ/6I{;ŵk߽0z{#j Ғ…q ZjԤ<;,&{>b>xh˖" B?ir)2ÍM{`n9`˖!v~e Ь[Ȱo_zggPlOcbAss+W&l/,ɢ7l<+invF%JcSլpz{}xjÀ={L r=LQH'JKil~[PenĿ02$FkI%sw O1!"f-~ov+' %QTLzB2zto`M~W%z DG $M寶3vQKR7N]*zS)E-zh bo"yd8n ҆^@:w0^!a}F@gpdtD.BίO#,5[<V1Fܓy [1&v.'hg ,B [c{q]- MwAhh(Z-Vdgo<Ï祐K;\`EIɄNd2h49{ 7ཛྷ(*(vw:!/\JVEZJ"ߌf+9֭!zu6Qٰ`>yj@8jzV| ȌO-Wϊ3ETF=T<,Ǣus~zP(cskQS0-qpg3E奃Ah;v<0 \0@) yKŒs_Nwp'. ?n7mywTSBEэn6 Q()))2/oQ*dHI>\<%\asL&P`&#rg7.Ctt4 8f9zhv;mhhRTɤ "<σyaf0װ]-y,95QHz<܎W %qt:}1cƤdeeյy \.?X4S{zGu }f@brr/^7_Ju"oCuu5ҟ-=]pܹ;v$eff ZVV#<<<?. ̄e{aaI r9( zeZ?"YҵkZ|>~^tر7;v}9N޽{Cv[III;322Vm۶mTEii»;R ;w*-yVRRrnrCƿvqqq+rrrZ:::455FAφ!DAvvagΜD]]ZcUdd$ɵk׈r\ IENDB`qmapshack-1.10.0/src/icons/cache/treasure.svg000644 001750 000144 00000056162 12455143304 022255 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/waypoint-flag-red.svg000644 001750 000144 00000012234 12455143304 023744 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/needs_maintenance.svg000644 001750 000144 00000013123 12455143304 024051 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/dnf.svg000644 001750 000144 00000017731 12455143304 021171 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/traditional.svg000644 001750 000144 00000022127 12455143304 022727 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/log.svg000644 001750 000144 00000020256 12455143304 021177 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/000755 001750 000144 00000000000 13216664444 022067 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/cache/attributes/yes_Scuba_gear.svg000755 001750 000144 00000046413 12455143304 025525 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Flashlight_required.svg000755 001750 000144 00000025446 12455143304 027462 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Snowmobiles.svg000755 001750 000144 00000015631 12455143304 025750 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Truck_Driver_RV.svg000755 001750 000144 00000017236 12455143304 026464 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Stealth_required.svg000755 001750 000144 00000022305 12455143304 026604 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Horses.svg000755 001750 000144 00000033223 12455143304 024544 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Snowmobiles.svg000755 001750 000144 00000015537 12455143304 025776 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Poison_plants.svg000755 001750 000144 00000022433 12455143304 026275 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Available_at_all_times.svg000755 001750 000144 00000013615 12455143304 027701 0ustar00oeichlerxusers000000 000000 image/svg+xml 24/7 qmapshack-1.10.0/src/icons/cache/attributes/yes_Dogs.svg000755 001750 000144 00000012473 12455143304 024365 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Parking_available.svg000755 001750 000144 00000012626 12455143304 027043 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/no_Parking_available.svg000755 001750 000144 00000013210 12455143304 026666 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/dis_Climbing_gear.svg000755 001750 000144 00000017425 12455143304 026174 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Drinking_water_nearby.svg000755 001750 000144 00000034471 12455143304 027616 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Abandoned_mines.svg000755 001750 000144 00000015043 12455143304 026533 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Recommended_at_night.svg000644 001750 000144 00000033576 12455143304 027574 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Snowmobiles.svg000755 001750 000144 00000016253 12455143304 025606 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Campfires.svg000755 001750 000144 00000042232 12455143304 025376 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Park_and_Grab.svg000755 001750 000144 00000115402 12455143304 026137 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/yes_Available_during_winter.svg000644 001750 000144 00000152715 12455143304 030312 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Off-road_vehicles.svg000755 001750 000144 00000014575 12455143304 027015 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Stroller_accessible.svg000755 001750 000144 00000016170 12455143304 027431 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Dangerous_area.svg000755 001750 000144 00000044702 12455143304 026367 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Available_during_winter.svg000644 001750 000144 00000156010 12455143304 030261 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Scenic_view.svg000755 001750 000144 00000014400 12455143304 025676 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Needs_maintenance.svg000644 001750 000144 00000015474 12455143304 027072 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Picnic_tables_nearby.svg000755 001750 000144 00000012362 12455143304 027565 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_May_require_swimming.svg000755 001750 000144 00000022064 12455143304 027662 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Dogs.svg000755 001750 000144 00000013505 12455143304 024341 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Telephone_nearby.svg000755 001750 000144 00000022315 12455143304 026750 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_May_require_wading.svg000755 001750 000144 00000035213 12455143304 027301 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Recommended_for_kids.svg000755 001750 000144 00000034713 12455143304 027574 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Public_restrooms_nearby.svg000755 001750 000144 00000020620 12455143304 030171 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Cross_Country_Skis.svg000755 001750 000144 00000016677 12455143304 027310 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Long_Hike_(+10km).svg000755 001750 000144 00000016451 12455143304 026333 0ustar00oeichlerxusers000000 000000 image/svg+xml >10km qmapshack-1.10.0/src/icons/cache/attributes/no_Campfires.svg000755 001750 000144 00000042750 12455143304 025217 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Horses.svg000755 001750 000144 00000032603 12455143304 024710 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Medium_hike_(1km-10km).svg000755 001750 000144 00000016461 12455143304 027330 0ustar00oeichlerxusers000000 000000 image/svg+xml <10km qmapshack-1.10.0/src/icons/cache/attributes/dis_Special_Tool_Required.svg000755 001750 000144 00000041731 12455143304 027664 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Picnic_tables_nearby.svg000755 001750 000144 00000013054 12455143304 027543 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Takes_less_than_an_hour.svg000755 001750 000144 00000102210 12455143304 030257 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Recommended_for_kids.svg000755 001750 000144 00000035764 12455143304 027562 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Cliff___falling_rocks.svg000755 001750 000144 00000025476 12455143304 027716 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Thorns.svg000755 001750 000144 00000017745 12455143304 024734 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Off-road_vehicles.svg000755 001750 000144 00000015271 12455143304 026766 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Horses.svg000755 001750 000144 00000032501 12455143304 024726 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Needs_maintenance.svg000644 001750 000144 00000014602 12455143304 027041 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Motorcycles.svg000755 001750 000144 00000020015 12455143304 025577 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Night_Cache.svg000755 001750 000144 00000133713 12455143304 025605 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Wireless_Beacon.svg000644 001750 000144 00000017762 12455143304 026517 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Off-road_vehicles.svg000755 001750 000144 00000015711 12455143304 026622 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Short_hike_(less_than_1km).svg000755 001750 000144 00000013315 12455143304 030515 0ustar00oeichlerxusers000000 000000 image/svg+xml <1km qmapshack-1.10.0/src/icons/cache/attributes/yes_Public_transportation.svg000755 001750 000144 00000016622 12455143304 030056 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Hunting.svg000755 001750 000144 00000023207 12455143304 025102 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Snowshoes.svg000755 001750 000144 00000020521 12455143304 025452 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Bicycles.svg000755 001750 000144 00000023310 12455143304 025216 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Abandoned_Structure.svg000755 001750 000144 00000017445 12455143304 027430 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Access_or_parking_fee.svg000755 001750 000144 00000011720 12455143304 027716 0ustar00oeichlerxusers000000 000000 image/svg+xml $ qmapshack-1.10.0/src/icons/cache/attributes/dis_Telephone_nearby.svg000755 001750 000144 00000022447 12455143304 026735 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Short_hike_(less_than_1km).svg000755 001750 000144 00000016044 12455143304 030476 0ustar00oeichlerxusers000000 000000 image/svg+xml <1km qmapshack-1.10.0/src/icons/cache/attributes/yes_Wheelchair_accessible.svg000755 001750 000144 00000015721 12455143304 027720 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Food_Nearby.svg000755 001750 000144 00000020376 12455143304 025661 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Available_at_all_times.svg000755 001750 000144 00000012477 12455143304 030072 0ustar00oeichlerxusers000000 000000 image/svg+xml 24/7 qmapshack-1.10.0/src/icons/cache/attributes/yes_Difficult_climbing.svg000755 001750 000144 00000017033 12455143304 027243 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Cliff___falling_rocks.svg000755 001750 000144 00000025721 12455143304 027666 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_UV_Light_Required.svg000755 001750 000144 00000014753 12455143304 026774 0ustar00oeichlerxusers000000 000000 image/svg+xml UV qmapshack-1.10.0/src/icons/cache/attributes/no_Significant_Hike.svg000755 001750 000144 00000017427 12455143304 026507 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Thorns.svg000755 001750 000144 00000020172 12455143304 024741 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Truck_Driver_RV.svg000755 001750 000144 00000021231 12455143304 026473 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Public_restrooms_nearby.svg000755 001750 000144 00000021204 12455143304 030333 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Park_and_Grab.svg000755 001750 000144 00000115610 12455143304 025754 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/dis_Hunting.svg000755 001750 000144 00000023350 12455143304 025060 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Abandoned_mines.svg000755 001750 000144 00000015170 12455143304 026513 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Campfires.svg000755 001750 000144 00000042406 12455143304 025360 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Wireless_Beacon.svg000644 001750 000144 00000017700 12455143304 026530 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Watch_for_livestock.svg000755 001750 000144 00000043257 12455143304 027474 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Dangerous_Animals.svg000755 001750 000144 00000021527 12455143304 027043 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Recommended_at_night.svg000644 001750 000144 00000030640 12455143304 027540 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Wheelchair_accessible.svg000755 001750 000144 00000016012 12455143304 027671 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Motorcycles.svg000755 001750 000144 00000017304 12455143304 025772 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Truck_Driver_RV.svg000755 001750 000144 00000021744 12455143304 026320 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Camping_available.svg000755 001750 000144 00000014602 12455143304 026657 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Bicycles.svg000755 001750 000144 00000024515 12455143304 025205 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Recommended_for_kids.svg000755 001750 000144 00000035407 12455143304 027411 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Camping_available.svg000755 001750 000144 00000014160 12455143304 027021 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_May_require_wading.svg000755 001750 000144 00000033677 12455143304 027274 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Motorcycles.svg000755 001750 000144 00000020376 12455143304 025754 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Short_hike_(less_than_1km).svg000755 001750 000144 00000015453 12455143304 030336 0ustar00oeichlerxusers000000 000000 image/svg+xml <1km qmapshack-1.10.0/src/icons/cache/attributes/no_Recommended_at_night.svg000644 001750 000144 00000031670 12455143304 027401 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Boat.svg000755 001750 000144 00000020145 12455143304 024351 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Stroller_accessible.svg000755 001750 000144 00000016621 12374350216 027271 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Dangerous_Animals.svg000755 001750 000144 00000020401 12374350216 027054 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_May_require_swimming.svg000755 001750 000144 00000023274 12374350216 027647 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Takes_less_than_an_hour.svg000755 001750 000144 00000077331 12374350216 030135 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Parking_available.svg000755 001750 000144 00000012073 12374350216 027062 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/dis_Stealth_required.svg000755 001750 000144 00000022621 12374350216 026752 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Long_Hike_(+10km).svg000755 001750 000144 00000013733 12374350216 026356 0ustar00oeichlerxusers000000 000000 image/svg+xml >10km qmapshack-1.10.0/src/icons/cache/attributes/dis_Field_Puzzle.svg000755 001750 000144 00000436300 12374350216 026045 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Abandoned_Structure.svg000755 001750 000144 00000016131 12374350216 027235 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Fuel_Nearby.svg000755 001750 000144 00000013675 12374350216 025673 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Food_Nearby.svg000755 001750 000144 00000021104 12374350216 025465 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Telephone_nearby.svg000755 001750 000144 00000023025 12374350216 026565 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Camping_available.svg000755 001750 000144 00000014066 12374350216 027051 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Special_Tool_Required.svg000755 001750 000144 00000042213 12374350216 027703 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Public_restrooms_nearby.svg000755 001750 000144 00000020110 12374350216 030351 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Wheelchair_accessible.svg000755 001750 000144 00000016433 12374350216 027537 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Watch_for_livestock.svg000755 001750 000144 00000043377 12374350216 027460 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Flashlight_required.svg000755 001750 000144 00000026175 12374350216 027443 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Scuba_gear.svg000755 001750 000144 00000046514 12374350216 025510 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Poison_plants.svg000755 001750 000144 00000021767 12374350216 026145 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Field_Puzzle.svg000755 001750 000144 00000627712 12374350216 026077 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Takes_less_than_an_hour.svg000755 001750 000144 00000076014 12374350216 030316 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Drinking_water_nearby.svg000755 001750 000144 00000033757 12374350216 030012 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Park_and_Grab.svg000755 001750 000144 00000114307 12374350216 026123 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/attributes/dis_Fuel_Nearby.svg000755 001750 000144 00000015001 12374350216 025633 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Food_Nearby.svg000755 001750 000144 00000021475 12374350216 025643 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Dangerous_area.svg000755 001750 000144 00000043603 12374350216 026411 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Significant_Hike.svg000755 001750 000144 00000016717 12374350216 026676 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Medium_hike_(1km-10km).svg000755 001750 000144 00000015467 12374350216 027174 0ustar00oeichlerxusers000000 000000 image/svg+xml <10km qmapshack-1.10.0/src/icons/cache/attributes/dis_Abandoned_Structure.svg000755 001750 000144 00000015557 12374350216 027413 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Night_Cache.svg000755 001750 000144 00000135605 12374350216 025446 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Medium_hike_(1km-10km).svg000755 001750 000144 00000013732 12374350216 027351 0ustar00oeichlerxusers000000 000000 image/svg+xml <10km qmapshack-1.10.0/src/icons/cache/attributes/dis_Boat.svg000755 001750 000144 00000021355 12374350216 024336 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Access_or_parking_fee.svg000755 001750 000144 00000013024 12374350216 027676 0ustar00oeichlerxusers000000 000000 image/svg+xml $ qmapshack-1.10.0/src/icons/cache/attributes/dis_Public_transportation.svg000755 001750 000144 00000020115 12374350216 030027 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Available_at_all_times.svg000755 001750 000144 00000014206 12374350216 030043 0ustar00oeichlerxusers000000 000000 image/svg+xml 24/7 qmapshack-1.10.0/src/icons/cache/attributes/yes_Poison_plants.svg000755 001750 000144 00000020646 12374350216 026324 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Available_during_winter.svg000644 001750 000144 00000153402 12374350216 030122 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Ticks.svg000755 001750 000144 00000041514 12374350216 024525 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Quads.svg000755 001750 000144 00000017046 12374350216 024365 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_UV_Light_Required.svg000755 001750 000144 00000013500 12374350216 027004 0ustar00oeichlerxusers000000 000000 image/svg+xml UV qmapshack-1.10.0/src/icons/cache/attributes/no_Long_Hike_(+10km).svg000755 001750 000144 00000015470 12374350216 026172 0ustar00oeichlerxusers000000 000000 image/svg+xml >10km qmapshack-1.10.0/src/icons/cache/attributes/no_Difficult_climbing.svg000755 001750 000144 00000017545 12374350216 027071 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Bicycles.svg000755 001750 000144 00000024031 12374350216 025035 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Significant_Hike.svg000755 001750 000144 00000017012 12374350216 026642 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Picnic_tables_nearby.svg000755 001750 000144 00000013476 12374350216 027412 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Drinking_water_nearby.svg000755 001750 000144 00000035053 12374350216 027760 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Night_Cache.svg000755 001750 000144 00000134063 12374350216 025627 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Stroller_accessible.svg000755 001750 000144 00000016112 12374350216 027450 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Difficult_climbing.svg000755 001750 000144 00000020161 12374350216 027220 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Quads.svg000755 001750 000144 00000017430 12374350216 024525 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Snowshoes.svg000755 001750 000144 00000020310 12374350216 025427 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/dis_Cross_Country_Skis.svg000755 001750 000144 00000016766 12374350216 027270 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Fuel_Nearby.svg000755 001750 000144 00000014406 12374350216 025500 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Stealth_required.svg000755 001750 000144 00000022176 12374350216 027000 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Scenic_view.svg000755 001750 000144 00000014307 12374350216 025727 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/no_Dogs.svg000755 001750 000144 00000013130 12374350216 024172 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Ticks.svg000755 001750 000144 00000051236 12374350216 024550 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Quads.svg000755 001750 000144 00000016334 12374350216 024550 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/attributes/yes_Climbing_gear.svg000755 001750 000144 00000017332 12374350216 026214 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/OCMLogo.svg000644 001750 000144 00000211432 12374350216 021655 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/OCMLogoSmall.svg000644 001750 000144 00000022127 12374350216 022647 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/mega.svg000644 001750 000144 00000060001 12374350216 021321 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/multi.svg000644 001750 000144 00000042250 12374350216 021550 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/up_icon.svg000644 001750 000144 00000005145 12374350216 022054 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/DistIcon.svg000644 001750 000144 00000020744 12374350216 022136 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/pushpin.svg000644 001750 000144 00000014165 12374350216 022110 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/letterbox.svg000644 001750 000144 00000150735 12374350216 022436 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/parking.svg000644 001750 000144 00000015742 12374350216 022057 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/cache/ftf.svg000644 001750 000144 00000022430 12374350216 021173 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/write_note.svg000644 001750 000144 00000013466 12374350216 022604 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/trailhead.svg000644 001750 000144 00000036417 12374350216 022363 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/SearchIcon.svg000644 001750 000144 00000012212 12374350216 022427 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/cache/maxicon.svg000644 001750 000144 00000004234 12374350216 022054 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/8x8/000755 001750 000144 00000000000 13216664444 017265 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/8x8/bullet_magenta.png000644 001750 000144 00000000321 12374350216 022743 0ustar00oeichlerxusers000000 000000 PNG  IHDRRWsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<NIDAT 0]讝7P! K+rԠkL0$#{|{铐4\IENDB`qmapshack-1.10.0/src/icons/8x8/bullet_black.png000644 001750 000144 00000000333 12374350216 022406 0ustar00oeichlerxusers000000 000000 PNG  IHDRRWsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<XIDATα 1a-J.\ "D ď )Ν [w*m #X- +8U( +5̷nn|\w`@(IENDB`qmapshack-1.10.0/src/icons/8x8/bullet_dark_magenta.png000644 001750 000144 00000000355 12374350216 023753 0ustar00oeichlerxusers000000 000000 PNG  IHDRRWsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<jIDAT}1 0\v`AؠU^fRXs_l`ҙp1U:ҙLl~]XZ۪7ٛRRSf{{nIIENDB`qmapshack-1.10.0/src/icons/8x8/bullet_brown.png000644 001750 000144 00000000345 12374350216 022464 0ustar00oeichlerxusers000000 000000 PNG  IHDRRWsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<bIDATA 0C@Ӳl|@b +Фi^zhH@Ι 4ܩfB5c$I@ Q*'ϷrB IENDB`qmapshack-1.10.0/src/icons/8x8/bullet_cyan.png000644 001750 000144 00000000323 12374350216 022263 0ustar00oeichlerxusers000000 000000 PNG  IHDRRWsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<PIDAT 0D.R^SAvAA\>g Xh(PvsK20,ˎY}$ͬ"m*@ b)*'Ϸ>r IENDB`qmapshack-1.10.0/src/icons/8x8/bullet_orange.png000644 001750 000144 00000000305 12374350216 022604 0ustar00oeichlerxusers000000 000000 PNG  IHDRo&sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<BIDATc?$ ")#)U.J I lۿvkɉ+YIX|"IENDB`qmapshack-1.10.0/src/icons/V.svg000644 001750 000144 00000004216 12551744506 017566 0ustar00oeichlerxusers000000 000000 image/svg+xml V qmapshack-1.10.0/src/icons/DeleteOne.svg000644 001750 000144 00000005043 12374350216 021216 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Tainted.svg000644 001750 000144 00000020332 12374365305 020745 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Info.svg000644 001750 000144 00000005675 12374350216 020260 0ustar00oeichlerxusers000000 000000 image/svg+xml ! qmapshack-1.10.0/src/icons/O.svg000644 001750 000144 00000004216 12551744506 017557 0ustar00oeichlerxusers000000 000000 image/svg+xml O qmapshack-1.10.0/src/icons/Template.svg000644 001750 000144 00000006766 13142547572 021151 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcSeaLevelPressure.svg000644 001750 000144 00000014234 13127442230 023353 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/EditDetails.svg000644 001750 000144 00000012736 12374350216 021554 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TimeZoneSetup.svg000644 001750 000144 00000022734 12374350216 022133 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActTrain.svg000644 001750 000144 00000012370 13145311664 021061 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/UnitSetup.svg000644 001750 000144 00000016067 12425622641 021323 0ustar00oeichlerxusers000000 000000 image/svg+xml m ft qmapshack-1.10.0/src/icons/QlbProject.svg000644 001750 000144 00000010036 13216234261 021412 0ustar00oeichlerxusers000000 000000 image/svg+xml QLB qmapshack-1.10.0/src/icons/PointShow.svg000644 001750 000144 00000014303 12417140444 021301 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ReloadImage.svg000644 001750 000144 00000012147 12464156220 021525 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/DatabaseSync.svg000644 001750 000144 00000017157 12705713524 021727 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcWTemp.svg000644 001750 000144 00000011443 12627613666 021176 0ustar00oeichlerxusers000000 000000 image/svg+xml °F °C qmapshack-1.10.0/src/icons/ArrowDef.svg000644 001750 000144 00000013776 12705713524 021102 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Left.svg000644 001750 000144 00000005656 13145234010 020244 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PastePlain.svg000644 001750 000144 00000010553 12741120171 021405 0ustar00oeichlerxusers000000 000000 image/svg+xml P qmapshack-1.10.0/src/icons/PointAdd.svg000644 001750 000144 00000031413 13107537221 021052 0ustar00oeichlerxusers000000 000000 image/svg+xml + qmapshack-1.10.0/src/icons/SelectArea.svg000644 001750 000144 00000012251 12705713524 021364 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SearchDatabase.svg000644 001750 000144 00000020043 12745644236 022213 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TrkProfile.svg000644 001750 000144 00000006634 12374621563 021450 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/DBProject.svg000644 001750 000144 00000017744 12430060201 021162 0ustar00oeichlerxusers000000 000000 image/svg+xml DB qmapshack-1.10.0/src/icons/FolderMap.svg000644 001750 000144 00000124172 12505261511 021223 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcVertSpeed.svg000644 001750 000144 00000037627 13127442230 022036 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActSki.svg000644 001750 000144 00000007255 12705713524 020542 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActCycle.svg000644 001750 000144 00000012323 12600710657 021041 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SetEle.svg000644 001750 000144 00000013034 12425622641 020533 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SizeArrow.svg000644 001750 000144 00000005515 12517672072 021311 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/RouteSetup.svg000644 001750 000144 00000010355 12542024310 021461 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextRight.svg000644 001750 000144 00000006541 12374350216 021300 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextUnderlined.svg000644 001750 000144 00000005213 12374350216 022307 0ustar00oeichlerxusers000000 000000 image/svg+xml U qmapshack-1.10.0/src/icons/WptAvoid.svg000644 001750 000144 00000015356 13216234261 021114 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AreaOn.svg000644 001750 000144 00002056237 12727447634 020551 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PasteNormal.svg000644 001750 000144 00000022713 12741120171 021573 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Reset.svg000644 001750 000144 00000005235 12374350216 020437 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ShowNone.svg000644 001750 000144 00000010152 12610212702 021075 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WptDelProx.svg000644 001750 000144 00000005232 13216234261 021417 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeMAP.svg000644 001750 000144 00000121175 12445773115 020612 0ustar00oeichlerxusers000000 000000 image/svg+xml MAP qmapshack-1.10.0/src/icons/SelectRange.svg000644 001750 000144 00000015134 12417406155 021552 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SelectColor.svg000644 001750 000144 00000015354 12374350216 021576 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CutMode2.svg000644 001750 000144 00000005453 13044557066 021010 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeVRT.svg000644 001750 000144 00000121226 12463705472 020646 0ustar00oeichlerxusers000000 000000 image/svg+xml VRT qmapshack-1.10.0/src/icons/PathOrange.svg000644 001750 000144 00000004727 12430060201 021373 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/GridWizzard.svg000644 001750 000144 00000017100 12374350216 021607 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ActSwim.svg000644 001750 000144 00000007334 12600710657 020727 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Lock.svg000644 001750 000144 00000006630 12374350216 020245 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/WptEditProx.svg000644 001750 000144 00000024526 13216234261 021607 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SetupMapWorkspace.svg000644 001750 000144 00000016211 12374350216 022766 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Pattern.svg000644 001750 000144 00000025203 12423367735 021000 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SQLiteNoConn.svg000644 001750 000144 00000020525 12734143660 021633 0ustar00oeichlerxusers000000 000000 image/svg+xml SQLite x qmapshack-1.10.0/src/icons/Scale.svg000644 001750 000144 00000007472 12374350216 020411 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Activity.svg000644 001750 000144 00000022506 12600710657 021152 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/FilterModifyExtension.svg000644 001750 000144 00000021067 12705713524 023653 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MySQLNoConn.svg000644 001750 000144 00000020410 12705713524 021430 0ustar00oeichlerxusers000000 000000 image/svg+xml MySQL x qmapshack-1.10.0/src/icons/AutoSave.svg000644 001750 000144 00000010552 13152263363 021103 0ustar00oeichlerxusers000000 000000 image/svg+xml A qmapshack-1.10.0/src/icons/CSrcDepth.svg000644 001750 000144 00000010361 12627613666 021204 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Help.svg000644 001750 000144 00000010177 12374350216 020246 0ustar00oeichlerxusers000000 000000 image/svg+xml ? qmapshack-1.10.0/src/icons/findunusedicons000755 001750 000144 00000000321 12741120171 021742 0ustar00oeichlerxusers000000 000000 #!/bin/bash for i in *.svg; do grep -r `echo $i | cut -d. -f1` --exclude-dir=".hg" --exclude-dir="icons" --exclude="resources.qrc" ../.. >/dev/null 2>&1 if [ $? -ne 0 ]; then echo $i is unused fi done qmapshack-1.10.0/src/icons/Map.svg000644 001750 000144 00000124312 12374350216 020070 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PointDel.svg000644 001750 000144 00000031455 13107537311 021074 0ustar00oeichlerxusers000000 000000 image/svg+xml + qmapshack-1.10.0/src/icons/LimitUsr.svg000644 001750 000144 00000013235 12705713524 021127 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/CSrcUnknown.svg000644 001750 000144 00000005230 12627613666 021576 0ustar00oeichlerxusers000000 000000 image/svg+xml ? qmapshack-1.10.0/src/icons/MimeRMAP.svg000644 001750 000144 00000121174 12445773115 020733 0ustar00oeichlerxusers000000 000000 image/svg+xml RMAP qmapshack-1.10.0/src/icons/Progress.svg000644 001750 000144 00000004330 12627613666 021170 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MimeGEMF.svg000644 001750 000144 00000121213 12705713524 020701 0ustar00oeichlerxusers000000 000000 image/svg+xml GEMF qmapshack-1.10.0/src/icons/FullScreen.svg000644 001750 000144 00000016627 13140265126 021423 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/ArrowUser.svg000644 001750 000144 00000010667 12705713524 021316 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Combine.svg000644 001750 000144 00000010015 12415503303 020712 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddTrk.svg000644 001750 000144 00000017716 12544430507 020536 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddRte.svg000644 001750 000144 00000010231 12544430507 020511 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SaveGISAs.svg000644 001750 000144 00000015257 12424464741 021114 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/MouseWheel.svg000644 001750 000144 00000011737 12374350216 021436 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SaveGIS.svg000644 001750 000144 00000010210 12424465076 020612 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Database.svg000644 001750 000144 00000016212 12430060201 021037 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/TextLeft.svg000644 001750 000144 00000006540 12374350216 021114 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Off.svg000644 001750 000144 00000005770 12374350216 020073 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/PathBlue.svg000644 001750 000144 00000004731 12430060201 021042 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddProject.svg000644 001750 000144 00000007125 12425622641 021375 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SearchGoogle.svg000644 001750 000144 00000006346 12421125024 021711 0ustar00oeichlerxusers000000 000000 image/svg+xml G qmapshack-1.10.0/src/icons/CSrcAccel.svg000644 001750 000144 00000007733 12705713524 021147 0ustar00oeichlerxusers000000 000000 image/svg+xml a qmapshack-1.10.0/src/icons/DatabaseConvert.svg000644 001750 000144 00000032205 12453154213 022414 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/Add.svg000644 001750 000144 00000004252 12374350216 020043 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/icons.svg.save000644 001750 000144 00001700557 12374350216 021437 0ustar00oeichlerxusers000000 000000 image/svg+xml 3D 2D X ! GPX Tip ? T T RMAP JNX IMG VRT MAP T qmapshack-1.10.0/src/icons/CutHistoryBefore.svg000644 001750 000144 00000015657 13073620730 022624 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/AddArea.svg000644 001750 000144 00002054733 12544430507 020650 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/SaveView.svg000644 001750 000144 00000012121 12475013404 021073 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/icons/16x16/000755 001750 000144 00000000000 13216664445 017424 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/icons/16x16/NoActivity.png000644 001750 000144 00000001415 13145507647 022225 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsUTtEXtSoftwarewww.inkscape.org<IDAT8[HTsvk HLIT2K!ԇʊJBMM)1,I$0H-@] 23R׵LI 0̏@@Q  t -*A3<,`h xwHy0hIXPe;_^X64/j5"x?/>54{}}4=-?6A2/&4@ 0Q#qvR   [u( ΍ҹcVΠtK-i>Rg T]sP̗3,Y4@w($A@ph:iѴn q `8q@&zcXY͆f*Eq+q י52i@AR@3.pª(uDddW'i9o-'(+` Pn (÷ Q\GCɹ eV ڶ?%%P&DIENDB`qmapshack-1.10.0/src/icons/16x16/ActSki.png000644 001750 000144 00000000717 13145236303 021302 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsItEXtSoftwarewww.inkscape.org<LIDAT8ұKa(DD\ !hj83 *) 9iBE" v]]{{}yNn=>Y og i*Ik(;wސu9ANvxFW%|Mj]?]0si*Kǩ VW$!<͟0s'#{r#y=|x"+?$!}M& c&P7h!FHJLoup֟y A8YJX%xtC(~%:4Sw|IENDB`qmapshack-1.10.0/src/icons/16x16/ActShip.png000644 001750 000144 00000000675 13145236303 021462 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsnnУhtEXtSoftwarewww.inkscape.org<:IDAT8ӱKQϑW!KC`tĩlr#jDBݜ]4Apݭ1IH p ^*s~;s3,,}):` %}b8NǏ'vF@sk) 2v9GxΓF"l5ӭ_Ku.-+i50_17s 3ZC~F#j!'4G| IpQa8SdR|J%a46r 6Xsol<[h/8Ln@\}IENDB`qmapshack-1.10.0/src/icons/16x16/Activity.png000644 001750 000144 00000001165 13145236301 021714 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsf&\tEXtSoftwarewww.inkscape.org<IDAT8MqfwG"ڶPڣrr+!-MmQ"\(p[[rRU+/2ea>Ϸ>_k8194| 28Pnjk]~αS+WΛ52kxxPU`)̩c}}c1s|/' |#; t̞]:I+JҊ|!3/Q:m$EBIfbx3kQ.7%J2}Z [P@+=5`k#9X?G$Ji}cB'Pi.t~ q>!G5^h֠%<KOI! 5=*@3' X͜U:B܀=!؟~ I(W p0RQ|$ő$e!9JHa؈c:bfH>a7uw˜~Sh|I< v+pp7Ư%GcIIENDB`qmapshack-1.10.0/src/icons/16x16/ActFoot.png000644 001750 000144 00000000607 13145236300 021456 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsItEXtSoftwarewww.inkscape.org<IDAT8?/QAt0X;&^Qt10hH4l6AĮ.UE=Yp^PE$Yg*+W1YE @ȕH>Hޱ/aD$N<iJ >?5Wb`70q' Im3 BE6_;8"yx?n^.y {,7qOCНsV(S[vMg=F1 8QAmIENDB`qmapshack-1.10.0/src/icons/16x16/ActNone.png000644 001750 000144 00000001415 13151740741 021452 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsUTtEXtSoftwarewww.inkscape.org<IDAT8[HTsvk HLIT2K!ԇʊJBMM)1,I$0H-@] 23R׵LI 0̏@@Q  t -*A3<,`h xwHy0hIXPe;_^X64/j5"x?/>54{}}4=-?6A2/&4@ 0Q#qvR   [u( ΍ҹcVΠtK-i>Rg T]sP̗3,Y4@w($A@ph:iѴn q `8q@&zcXY͆f*Eq+q י52i@AR@3.pª(uDddW'i9o-'(+` Pn (÷ Q\GCɹ eV ڶ?%%P&DIENDB`qmapshack-1.10.0/src/icons/16x16/ActTrain.png000644 001750 000144 00000000753 13145311676 021640 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsnrtEXtSoftwarewww.inkscape.org<hIDAT8?HBa=* *Tjh 6pId/qwjh&2 RDCD+!2?Y;p A`BL6w / R.HcBC۽GA)03$ҕPSxwq &K, Zt ڀY Vw8*p8Px2ڊك,H${BFń:7ӻ |Hdd2 d27;l6o7:޺TL檿 hBk,ho k(h"-IENDB`qmapshack-1.10.0/src/icons/16x16/ActAero.png000644 001750 000144 00000001037 13145236274 021445 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDAT8MHQOZ8J2Z !B FP mQ!(SV-MB"DčQFpt߈8tsޠ.&/P%a+2is\Ƒ/Y'ڬc(pNxـX%݋b@|xUeFhb&d*HIFF8K\gM*A=ƻx!^҃,NT]_O.g% WfWVTO+<:~'WYz̦YFF:A\(z3=C٩hoiiōlqXZ1P[Bs 0H^X>C|2y z|y2+Iu/vpl񞻚IENDB`qmapshack-1.10.0/src/icons/16x16/ActBike.png000644 001750 000144 00000000715 13145236275 021434 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYstEXtSoftwarewww.inkscape.org<JIDAT81HVaW3qTK$- 7©EA43DIpjqihp[A^w9}9\{Wo 󵾚\d|S_ EC6L~9>?yF %erx<{>_N k$)60SB36O LlxX.576RHH{qD|L )6p O1Fډ ?h%w,0W1I@1{Oh<& >tfZ?Vp*^w<dud:FJ+,`9W \'7IENDB`qmapshack-1.10.0/src/icons/16x16/ActSwim.png000644 001750 000144 00000000730 13145236304 021467 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYs'tEXtSoftwarewww.inkscape.org<UIDAT8AKQ}'L KET Q>AB+?@y-} M_2+(Hr1:^ոϽ{8pO1r=^~oh0Y*Si0Ik$#V)@h ( O 21ܫD\ B՝0q8JIzء}&:C: s M`O5:j/y6} \F^`n+~C{zӳop=Es*X"a 88 |EM dc?!ZU>,IENDB`qmapshack-1.10.0/src/icons/16x16/ActCable.png000644 001750 000144 00000000666 13145236276 021576 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsnrtEXtSoftwarewww.inkscape.org<3IDAT8=KQB]įB&傂)*N-;TVV6 +"!"؈QdkWQfO3ܙs s'}I4/e Z#3EAo/ƉXD;pL8vj<]]G3&i*M&K~ĵSW_Nn]6nFG> bC_r⥓RBg;+/<&= 4Ӳ\nUԲZ[PihoB$j((Jor6;~w**#‡G\ dVGK6IENDB`qmapshack-1.10.0/src/icons/16x16/ActCar.png000644 001750 000144 00000000701 13145236277 021264 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYsnrtEXtSoftwarewww.inkscape.org<>IDAT8ҿK[QOHA Bqn3u,29ĭ8tqB AhC?At(tpQ 8H!4VEzF\w9pyp}]yBޮg ǻFjzdj)8>>7x |\XJ;4Je#fvv=&VXRiDDQv;\~S#̱:A|Ƈz.)~f71+8N3Q;vH>9"7ˍ&i ;#$7q|Ck@(+h!~d%v8$IENDB`qmapshack-1.10.0/src/icons/16x16/EditDetails.png000644 001750 000144 00000001337 13145236341 022320 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYs777ltEXtSoftwarewww.inkscape.org<\IDAT8ROHq}߹Bl駇BPMH;&x1 ODaGB-bJ!bA1<ȈLTyaE=>|!H0 !j@ۭT[v≹5TFc 31f^捚;llVaC(槬}SN&&|O,6671$YQϪA|$p8; 3?pbiАÔ&uZ5ss23O"+ˤ̌R@E>&VWZ:[5!mG zN\^'&t}$I I:q+nͬ4 DS(0 -\Ѩ.EE],.IM%1wxO=97qz<~1{)})D/h7!H>\t^^B$B$$HHqN5ds!2jmTlaM%KBy3-s9BZ/1gcXxpvWih/LI+}wd!?mWIr)[|uIENDB`qmapshack-1.10.0/src/icons/16x16/ActCycle.png000644 001750 000144 00000000723 13145236277 021622 0ustar00oeichlerxusers000000 000000 PNG  IHDRasBIT|d pHYstEXtSoftwarewww.inkscape.org<PIDAT8ҿKaiEPCj1ZBhPZ\[pqhlU >TPA-"?@~,77Irohs}/nlrV8}uiC .5[1@fjp@u^vEIv1q'Dhn%3U=M\#\Dyzb/xCaQ E'h#278">AI?s(,uk #TrbQZ(ăeP,)^dc cإxMp5 EGpRV3 IENDB`qmapshack-1.10.0/src/icons/Cut.svg000644 001750 000144 00000012500 12374350216 020101 0ustar00oeichlerxusers000000 000000 image/svg+xml qmapshack-1.10.0/src/templates/000755 001750 000144 00000000000 13216664445 017522 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/templates/Hiking_Tour_Summary.ui000644 001750 000144 00000024262 13142547572 024025 0ustar00oeichlerxusers000000 000000 Form 0 0 564 578 Form Participants Weather rain sunny snow clouds hot warm cold freezing foggy windy humid Qt::Vertical 20 40 hail/soft hail Character large ascend climbing via ferrata Rating Rating 5 stars Rating 4 stars Rating 3 stars Rating 2 stars Rating 1 star easy hiking long distance alpine aborted Equipment ski climbing gear ferrata gear camping gear night gear snow shoes Details checkBox checkBox_5 checkBox_6 checkBox_7 checkBox_20 checkBox_18 checkBox_11 checkBox_2 radioButton radioButton_2 radioButton_3 radioButton_4 lineEdit_2 radioButton_6 radioButton_5 checkBox_4 checkBox_14 checkBox_13 checkBox_17 checkBox_16 comboBox lineEdit_3 checkBox_3 checkBox_19 checkBox_8 checkBox_12 checkBox_10 checkBox_9 lineEdit textEdit qmapshack-1.10.0/src/plot/000755 001750 000144 00000000000 13216664445 016502 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/plot/ITrack.h000644 001750 000144 00000003175 13216234142 020021 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef ITRACK_H #define ITRACK_H #include #include #include class QRectF; class QPainter; class CGisItemTrk; class ITrack { public: ITrack(); virtual ~ITrack(); void setSize(int w, int h); void setTrack(CGisItemTrk * track); void setTrack(const QPolygonF &track); void save(QImage& image); protected: void setupProjection(const QRectF &boundingBox); void updateData(); void draw(QPainter& p); void draw(); projPJ pjsrc = nullptr; projPJ pjtar = nullptr; bool needsRedraw = true; CGisItemTrk * trk = nullptr; QPolygonF coords; QPolygonF line; QImage buffer; QPointF scale; qint32 xoff = 0; qint32 yoff = 0; }; #endif //ITRACK_H qmapshack-1.10.0/src/plot/IPlot.h000644 001750 000144 00000012545 13216234142 017674 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IPLOT_H #define IPLOT_H #include "gis/trk/CGisItemTrk.h" #include "mouse/CMouseDummy.h" #include "plot/CPlotData.h" #include class QMenu; class CScrOptRangeTrk; class IPlot : public QWidget, public INotifyTrk { Q_OBJECT public: enum mode_e {eModeNormal, eModeIcon, eModeWindow}; enum mouse_click_state_e { eMouseClickIdle , eMouseClick1st , eMouseClick2nd }; IPlot(CGisItemTrk * trk, CPlotData::axistype_e type, mode_e mode, QWidget * parent); virtual ~IPlot(); void setMouseRangeFocus(const CTrackData::trkpt_t * ptRange1, const CTrackData::trkpt_t * ptRange2) override; void setMouseClickFocus(const CTrackData::trkpt_t * pt) override {} void save(QImage& image); void setSolid(bool yes) { solid = yes; } bool isZoomed() const; void clear(); using INotifyTrk::setMouseFocus; signals: void sigMouseClickState(int); private slots: void slotContextMenu(const QPoint & point); void slotSave(); void slotHidePoints(); void slotShowPoints(); void slotActivity(quint32 flags); void slotCopy(); void slotStopRange(); void slotResetZoom(); void slotAddWpt(); void slotCutTrk(); protected: void setXTicScale(qreal scale); void setYLabel(const QString& str); void setXLabel(const QString& str); void newLine(const QPolygonF& line, const QString& label); void addLine(const QPolygonF& line, const QString& label); void setLimits(); void resetZoom(); void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void leaveEvent(QEvent *e) override; void enterEvent(QEvent *e) override; void keyPressEvent(QKeyEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent * e) override; void wheelEvent(QWheelEvent *e) override; void setSizes(); void setLRTB(); void setSizeIconArea(); void setSizeXLabel(); void setSizeYLabel(); void setSizeTrackInfo(); void setSizeDrawArea(); QPointF getBasePoint(int ptx) const; void draw(QPainter& p); void draw(); void drawData(QPainter& p); void drawLabels(QPainter &p); void drawXScale(QPainter &p); void drawYScale(QPainter &p); void drawGridX(QPainter &p); void drawGridY(QPainter &p); void drawXTic(QPainter &p); void drawYTic(QPainter &p); void drawLegend(QPainter& p); void drawDecoration(QPainter &p); void drawTags(QPainter& p); void drawActivities(QPainter& p); bool graphAreaContainsMousePos(QPoint& pos); static int cnt; // different draw modes mode_e mode; // buffer needs update bool needsRedraw = true; bool showScale = true; bool thinLine = false; bool solid = false; bool mouseDidMove = false; QImage buffer; QPoint posMouse1 = NOPOINT; ///< pixel coordinate of mouse in graph area while in focus QPoint posMouse2 = NOPOINT; ///< pixel coordinate of mouse in graph area while in context menu function QPoint posLast = NOPOINT; /** @brief The track this plot is attached to @note It is save to store the pointer to the track item because the plot objects registers/unregisters with the track during construction and destruction. See CGisItem::registeredPlots for details. */ CGisItemTrk * trk; CPlotData * data; QFontMetrics fm; int left = 0; int right = 0; int top = 0; int bottom = 0; int deadAreaX = 0; int deadAreaY = 0; int fontWidth = 0; int fontHeight = 0; int scaleWidthX1 = 0; int scaleWidthY1 = 0; QRect rectX1Label; QRect rectY1Label; QRect rectGraphArea; QRect rectIconArea; QRect rectTrackInfo; static const QPen pens[]; static const QPen pensThin[]; static const QColor colors[]; QMenu * menu; QAction * actionResetZoom; QAction * actionPrint; QAction * actionStopRange; QAction * actionAddWpt; QAction * actionCutTrk; qint32 idxSel1 = NOIDX; qint32 idxSel2 = NOIDX; mouse_click_state_e mouseClickState = eMouseClickIdle; QPointer scrOptRange; CMouseDummy dummyMouse; private: void setMouseFocus(qreal pos, enum CGisItemTrk::focusmode_e fm); QPolygonF getVisiblePolygon(const QPolygonF &polyline, QPolygonF &line) const; }; #endif //IPLOT_H qmapshack-1.10.0/src/plot/CPlot.h000644 001750 000144 00000003320 13216234142 017655 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOT_H #define CPLOT_H #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CPropertyTrk.h" #include "plot/IPlot.h" #include class CLimit; class CPlot : public IPlot { Q_OBJECT public: CPlot(CGisItemTrk *trk, CLimit& limit, CPlotData::axistype_e type, const QString &xLabel, const QString &yLabel, qreal factor, fTrkPtGetVal getX, fTrkPtGetVal getY, QWidget *parent); CPlot(CGisItemTrk *trk, CLimit& limit, QWidget *parent); virtual ~CPlot() = default; void setup(const CPropertyTrk::property_t &p); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t * ptMouseMove) override; public slots: void setLimits(); private: CLimit& limit; qreal factor = 1.0; fTrkPtGetVal getX = nullptr; fTrkPtGetVal getY = nullptr; }; #endif //CPLOT_H qmapshack-1.10.0/src/plot/CPlot.cpp000644 001750 000144 00000007073 13216234137 020225 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CLimit.h" #include "plot/CPlot.h" #include "plot/CPlotAxis.h" CPlot::CPlot(CGisItemTrk * trk, CLimit& limit, CPlotData::axistype_e type, const QString& xLabel, const QString& yLabel, qreal factor, fTrkPtGetVal getX, fTrkPtGetVal getY, QWidget * parent) : IPlot(trk, type, eModeNormal, parent) , limit(limit) , factor(factor) , getX(getX) , getY(getY) { connect(&limit, &CLimit::sigChanged, this, &CPlot::setLimits); setXLabel(xLabel); setYLabel(yLabel); updateData(); } CPlot::CPlot(CGisItemTrk *trk, CLimit& limit, QWidget *parent) : IPlot(trk, CPlotData::eAxisLinear, eModeNormal, parent) , limit(limit) { connect(&limit, &CLimit::sigChanged, this, &CPlot::setLimits); } void CPlot::setup(const CPropertyTrk::property_t& p) { if(p.axisType == CPropertyTrk::property_t::eAxisDistance) { data->setXAxisType(CPlotData::eAxisLinear); qreal scale; QString unit; IUnit::self().meter2unit(trk->getTotalDistance(), scale, unit); setXTicScale(scale); setXLabel(tr("Distance [%1]").arg(unit)); } else if(p.axisType == CPropertyTrk::property_t::eAxisTime) { data->setXAxisType(CPlotData::eAxisTime); setXLabel(tr("Time")); } setYLabel(p.yLabel); factor = p.factor; getX = p.getX; getY = p.getY; limit.setSource(p.key); updateData(); } void CPlot::updateData() { clear(); if(isHidden() || (getX == nullptr) || (getY == nullptr)) { resetZoom(); update(); return; } QPolygonF line; const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { if(!trkpt.isHidden() && getY(trkpt) != NOFLOAT) { line << QPointF(getX(trkpt), getY(trkpt) * factor); } } newLine(line, "GPS"); setLimits(); } void CPlot::setMouseFocus(const CTrackData::trkpt_t * ptMouseMove) { if(nullptr == ptMouseMove || getX == nullptr || getY == nullptr) { if(posMouse1 != NOPOINT) { posMouse1 = NOPOINT; needsRedraw = true; } } else { if(posMouse1 == NOPOINT) { needsRedraw = true; } posMouse1.rx() = left + data->x().val2pt(getX(*ptMouseMove)); posMouse1.ry() = top + data->y().val2pt(getY(*ptMouseMove)); } update(); } void CPlot::setLimits() { IPlot::setLimits(); data->ymin = limit.getMin() == NOFLOAT ? data->ymin : limit.getMin(); data->ymax = limit.getMax() == NOFLOAT ? data->ymax : limit.getMax(); data->y().setLimits(data->ymin, data->ymax); resetZoom(); update(); } qmapshack-1.10.0/src/plot/CPlotProfile.cpp000644 001750 000144 00000011064 13216234137 021541 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "plot/CPlotAxis.h" #include "plot/CPlotProfile.h" #include "units/IUnit.h" #include #include CPlotProfile::CPlotProfile(QWidget * parent) : IPlot(nullptr, CPlotData::eAxisLinear, eModeNormal, parent) { } CPlotProfile::CPlotProfile(CGisItemTrk *trk, CLimit& lim, mode_e mode, QWidget *parent) : IPlot(trk, CPlotData::eAxisLinear, mode, parent) , limit(&lim) { connect(limit, &CLimit::sigChanged, this, &CPlotProfile::setLimits); setWindowTitle(trk->getNameEx()); updateData(); } CPlotProfile::~CPlotProfile() { } void CPlotProfile::setTrack(CGisItemTrk * track, CLimit &lim) { trk = track; trk->registerVisual(this); if(limit) { disconnect(limit, &CLimit::sigChanged, this, &CPlotProfile::setLimits); } limit = &lim; connect(limit, &CLimit::sigChanged, this, &CPlotProfile::setLimits); updateData(); } #define Q 32 void CPlotProfile::updateData() { clear(); qreal scale; QString unit; IUnit::self().meter2unit(trk->getTotalDistance(), scale, unit); setXTicScale(scale); if(mode == eModeIcon) { setXLabel(trk->getName()); setYLabel(""); } else { setXLabel(tr("Distance [%1]").arg(unit)); setYLabel(tr("Ele. [%1]").arg(IUnit::self().baseunit)); } QPolygonF lineEle; QPolygonF lineDem; QPolygonF coords; IGisProject * project = dynamic_cast(trk->parent()); qreal basefactor = IUnit::self().basefactor; const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { if(trkpt.isHidden()) { continue; } if(trkpt.ele == NOINT) { continue; } lineEle << QPointF(trkpt.distance, trkpt.ele * basefactor); coords << QPointF(trkpt.lon * DEG_TO_RAD, trkpt.lat * DEG_TO_RAD); lineDem << QPointF(trkpt.distance, NOFLOAT); if(nullptr == project || trkpt.keyWpt.item.isEmpty() || (mode == eModeIcon)) { continue; } CGisItemWpt * wpt = dynamic_cast(project->getItemByKey(trkpt.keyWpt)); if(wpt) { CPlotData::point_t tag; tag.point = lineEle.last(); tag.icon = wpt->getIcon(); tag.label = wpt->getName(); data->tags << tag; } } CMainWindow::self().getElevationAt(coords, lineDem); newLine(lineEle, "GPS"); if(!lineDem.isEmpty()) { addLine(lineDem, "DEM"); } if(trk->isInterpolationEnabled()) { QPolygonF spline; for(const QPointF& pt : lineEle) { spline << QPointF(pt.x(), trk->getElevationInterpolated(pt.x())); } addLine(spline, "Interp."); } setLimits(); resetZoom(); } void CPlotProfile::setMouseFocus(const CTrackData::trkpt_t * ptMouseMove) { if(nullptr == ptMouseMove) { if(posMouse1 != NOPOINT) { posMouse1 = NOPOINT; needsRedraw = true; } } else { if(posMouse1 == NOPOINT) { needsRedraw = true; } posMouse1.rx() = left + data->x().val2pt(ptMouseMove->distance); posMouse1.ry() = top + data->y().val2pt(ptMouseMove->ele); } update(); } void CPlotProfile::setLimits() { IPlot::setLimits(); data->ymin = limit->getMin() == NOFLOAT ? data->ymin : limit->getMin(); data->ymax = limit->getMax() == NOFLOAT ? data->ymax : limit->getMax(); data->y().setLimits(data->ymin, data->ymax); resetZoom(); update(); } qmapshack-1.10.0/src/plot/CPlotTrack.h000644 001750 000144 00000002600 13216234142 020642 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOTTRACK_H #define CPLOTTRACK_H #include "plot/ITrack.h" #include class CGisItemTrk; class CPlotTrack : public QWidget, public ITrack { public: CPlotTrack(QWidget * parent); CPlotTrack(CGisItemTrk * trk, QWidget * parent); virtual ~CPlotTrack(); void setMouseFocus(qreal lon, qreal lat); protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; private: QPointF pos = NOPOINTF; }; #endif //CPLOTTRACK_H qmapshack-1.10.0/src/plot/CPlotTrack.cpp000644 001750 000144 00000003461 13216234137 021207 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CDraw.h" #include "plot/CPlotTrack.h" #include CPlotTrack::CPlotTrack(QWidget *parent) : QWidget(parent) { } CPlotTrack::CPlotTrack(CGisItemTrk * trk, QWidget * parent) : QWidget(parent) , pos(NOPOINTF) { setTrack(trk); } CPlotTrack::~CPlotTrack() { } void CPlotTrack::setMouseFocus(qreal lon, qreal lat) { pos.rx() = lon * DEG_TO_RAD; pos.ry() = lat * DEG_TO_RAD; pj_transform(pjtar, pjsrc, 1, 0, &pos.rx(), &pos.ry(), 0); update(); } void CPlotTrack::resizeEvent(QResizeEvent * e) { QSize s = e->size(); setMinimumWidth(s.height()); setSize(s.height(), s.height()); } void CPlotTrack::paintEvent(QPaintEvent * e) { QPainter p(this); USE_ANTI_ALIASING(p, true); draw(p); p.setPen(Qt::red); p.setBrush(Qt::red); p.scale(scale.x(), scale.y()); p.translate(-xoff, -yoff); p.drawEllipse(pos,5/scale.x(),5/scale.x()); } qmapshack-1.10.0/src/plot/CPlotData.h000644 001750 000144 00000004500 13216234142 020450 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOTDATA_H #define CPLOTDATA_H #include #include #include #include class CPlotAxis; class CPlotData : public QObject { public: enum axistype_e {eAxisLinear, eAxisTime}; CPlotData(axistype_e type, QObject * parent); virtual ~CPlotData(); ///get a reference to the x axis CPlotAxis& x() const { return *xaxis; } ///get a reference to the y axis CPlotAxis& y() const { return *yaxis; } /// create a new x axis void setXAxisType(axistype_e type); /// setup all internal data to fit the dynamic range of all data points void setLimits(); struct line_t { QString label; QColor color; QPolygonF points; }; /// text shown below the x axis QString xlabel; /// text shown left of the y axis QString ylabel; /// set true for grid bool grid = true; /// list of plot lines QList lines; struct point_t { QColor color; QPointF point; QPixmap icon; QString label; }; QList focus; /// vector of plot tags such as waypoints QVector tags; bool badData = true; axistype_e axisType = eAxisLinear; qreal xmin = 0; qreal xmax = 0; qreal ymin = 0; qreal ymax = 0; protected: CPlotAxis * xaxis = nullptr; CPlotAxis * yaxis = nullptr; }; #endif //CPLOTDATA_H qmapshack-1.10.0/src/plot/CPlotAxis.h000644 001750 000144 00000011043 13216234142 020503 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOTAXIS_H #define CPLOTAXIS_H #include class QFontMetrics; class CPlotAxis : public QObject { Q_OBJECT public: CPlotAxis(QObject * parent) : QObject(parent) { } virtual ~CPlotAxis() { } /// tic mark information structure struct tic_t { tic_t() { } qreal val = 0; QString lbl = ""; }; ///tic type enum tictype_e { eNoTic, /**< no tics are produced*/ eTicMinMax, /**< only min max tics are produced*/ eTicNorm, /**< tics by interval*/ eTicFull /**< minmax && norm*/ }; ///zoom in/out with a given point as static virtual void zoom(bool in, int point); ///set the desired minimum and maximum value equal to limit values virtual void resetZoom(); ///add delta_pt to min and max values virtual void move(int delta); ///set the desired minimum and maximum value virtual void setMinMax(qreal givenMin, qreal givenMax); ///set the limit minimum and maximum value virtual void setLimits(qreal min, qreal max); ///set the scale factor for a given size in points virtual void setScale(const unsigned int pts); ///calculate format for the given value virtual const QString fmtsgl(qreal val); ///calculate format for the given value virtual const QString fmtdbl(qreal val); ///get the maximum width of a scale with provided fontmetrics virtual int getScaleWidth(const QFontMetrics& m); ///get a new ticmark object virtual const tic_t* ticmark(const tic_t *t = nullptr); /// get the total limits and the used ones virtual void getLimits(qreal& limMin, qreal& limMax, qreal& useMin, qreal& useMax); inline int val2pt( qreal val ) const { if ( scale == 0 ) { return 0; } return qRound(( val - usedMin ) * scale); } inline qreal pt2val( int pt ) const { if ( scale == 0 ) { return 0; } return qreal(pt) / scale + usedMin; } void setAutoscale(bool on) { autoscale = on; } void setTicScale(qreal scale) { ticScale = scale; } inline tictype_e getTicType() const { return ticType; } inline tictype_e setTicType(tictype_e t) { tictype_e old = ticType; ticType = t; return old; } qreal min() const { return usedMin; } qreal max() const { return usedMax; } bool isValid() const { return valid; } protected: virtual void calc(); ///true if axis has been initialized bool initialized = false; ///true if autoscaling bool autoscale = false; bool valid = false; ///scalefactor qreal scale = 1.0; qreal usedMin = 0.0; ///< the actual applied min value qreal usedMax = 0.0; ///< the actual applied max value qreal limitMin = 0.0; qreal limitMax = 0.0; qreal ticStart = 0.0; ///< start value of the ticmarks qreal interval = 0.0; ///< the interval of the ticmarks /** a value > 0 will override the dynamic value in getScaleWidth(); */ qint32 scaleWidth = 0; /// the ticmark generation type tictype_e ticType = eTicNorm; /// local copy of the last ticmark object tic_t tic; /// this is the scale used to convert meters into the scale's unit (km, ft, ml, nm) qreal ticScale = 1.0; ///points of dimension quint32 points = 0; private: bool firstTic = false; ///< used by ticmark() bool lastTic = false; ///< used by ticmark() }; #endif //CPLOTAXIS_H qmapshack-1.10.0/src/plot/CPlotAxisTime.cpp000644 001750 000144 00000006132 13216234137 021664 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "plot/CPlotAxisTime.h" #include void CPlotAxisTime::calc() /* override */ { int dSec = usedMax - usedMin; ticStart = usedMin; // abort if the xRange has a length of 0 if(0 == dSec) { valid = false; return; } if(dSec < 0) { qDebug() << "ouch"; valid = false; return; } else if(dSec < 20) { interval = 1; ticStart = usedMin; } else if(dSec < 100) { interval = 5; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 200) { interval = 10; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 600) { interval = 30; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 1200) { interval = 60; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 6000) { interval = 600; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 12000) { interval = 600; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 36000) { interval = 1800; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 72000) { interval = 3600; ticStart = qCeil(usedMin / interval) * interval; } else if(dSec < 216000) { interval = 10800; ticStart = qCeil(usedMin / interval) * interval; } else { qDebug() << "ouch"; valid = false; return; } if ( autoscale ) { usedMin = qFloor( usedMin / interval ) * interval; usedMax = qCeil( usedMax / interval ) * interval; } int t1 = ( int )( usedMin / interval + 0.5); ticStart = interval * t1; if ( ticStart < usedMin ) { ticStart += interval; } valid = true; } const CPlotAxis::tic_t* CPlotAxisTime::ticmark( const tic_t * t ) /* override */ { const tic_t * _tic_ = CPlotAxis::ticmark(t); if(_tic_) { QDateTime time = QDateTime::fromTime_t(tic.val); time.setTimeSpec(Qt::LocalTime); tic.lbl = time.toString(strFormat); } return _tic_; } qmapshack-1.10.0/src/plot/CPlotAxis.cpp000644 001750 000144 00000016276 13216234137 021057 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "plot/CPlotAxis.h" #include inline qreal qLog10(qreal x) { return qLn(x)/qLn(10); } void CPlotAxis::setLimits(qreal min, qreal max) { limitMin = min; limitMax = max; } void CPlotAxis::setMinMax( qreal givenMin, qreal givenMax ) { if(givenMin == givenMax) { if(0.0 != givenMin) { givenMin -= givenMin / 10.0; givenMax += givenMax / 10.0; } else { givenMin -= 0.1; givenMax += 0.1; } } if ( givenMin > givenMax ) { qSwap(givenMin, givenMax); } usedMin = givenMin; usedMax = givenMax; calc(); initialized = true; } void CPlotAxis::calc() { qreal tmpAbs = qFabs(usedMax - usedMin) * ticScale; qreal tmp = qLog10( tmpAbs / 10.0 ); qreal exponent = (int) tmp; qreal residue = tmp - exponent; qreal resSteps[] = {qLog10(0.1), qLog10(0.2), qLog10(0.5), qLog10(1.0), qLog10(2.0), qLog10(5.0), qLog10(10.0)}; for(const qreal &step : resSteps) { if(residue <= step) { residue = step; break; } } interval = exponent + residue; interval = qPow( 10, interval ) / ticScale; if ( autoscale ) { usedMin = qFloor( usedMin / interval ) * interval; usedMax = qCeil( usedMax / interval ) * interval; } int t1 = ( int )( usedMin / interval + 0.5); ticStart = interval * t1; if ( ticStart < usedMin ) { ticStart += interval; } valid = true; } const QString CPlotAxis::fmtsgl( qreal val ) { QString f; int exponent = (0. == val) ? 0 : (int) qLog10( qFabs(val) ); //val *= ticScale; if ( abs(exponent) > 5 ) { f = "%1.2e"; } else if ( exponent >= 0 ) { f = "%" + QString( "%1" ).arg(exponent + 1) + ( (0 == exponent) ? ".1f" : ".0f" ); } else { f = "%1." + QString( "%1" ).arg(-exponent + 1) + "f"; } return f; } /** Generates a sprintf style format string for a given value.
   0.001   -> "%1.4f"
   0.01    -> "%1.3f"
   0.1     -> "%1.2f"
   1       -> "%1.1f"
   10      -> "%2.1f"
   >10000 scientific notation "%1.3e"
   
@param val value to calculate the string on @return a zero terminated format string */ const QString CPlotAxis::fmtdbl( qreal val ) { int exponent = 0; qreal residue = 0; val *= ticScale; if ( val != 0 ) { qreal tmp = qLog10( qFabs(val) ); exponent = (int) tmp; residue = tmp - exponent; } QString f; if ( abs(exponent) > 5 ) { f = "%1.3e"; } else if ( exponent >= 0 ) { f = "%" + QString( "%1" ).arg(exponent + 1) + ( ((0. == exponent) && (0 > residue)) ? ".2f" : ".1f" ); } else { f = "%1." + QString( "%1" ).arg(-exponent + 2) + "f"; } return f; } int CPlotAxis::getScaleWidth( const QFontMetrics& m ) { if(!valid) { return 0; } if ( scaleWidth > 0 ) { return scaleWidth * m.width( "X" ); } int width = 6 * m.width( "X" ); QString format_single_prec = ((interval * ticScale) < 1) ? fmtdbl(interval) : fmtsgl(interval); const tic_t * t = ticmark(); while (nullptr != t) { int tmp = m.width( QString().sprintf( format_single_prec.toLatin1().data(), t->val * ticScale) ); width = qMax(width, tmp); t = ticmark(t); } return width; } void CPlotAxis::getLimits(qreal& limMin, qreal& limMax, qreal& useMin, qreal& useMax) { limMin = limitMin; limMax = limitMax; useMin = usedMin; useMax = usedMax; } const CPlotAxis::tic_t* CPlotAxis::ticmark( const tic_t * t ) { QString format_single_prec = ((interval * ticScale) < 1) ? fmtdbl(interval) : fmtsgl(interval); switch ( ticType ) { case eNoTic: return nullptr; break; case eTicMinMax: if (nullptr == t) { tic.val = usedMin; firstTic = true; } else if (firstTic) { tic.val = usedMax; firstTic = false; } else { return nullptr; } break; case eTicNorm: if (0. == interval) { //qWarning() << "CPlotAxis::ticmark() mode 'norm': interval == 0"; return nullptr; } if (nullptr == t) { tic.val = ticStart; } else { tic.val += interval; if(tic.val > usedMax) { return nullptr; } } break; case eTicFull: if (nullptr == t) { tic.val = usedMin; firstTic = true; } else if (firstTic) { tic.val = ticStart; firstTic = false; } else if (lastTic) { lastTic = false; return nullptr; } else { tic.val += interval; if(tic.val > usedMax) { tic.val = usedMax; lastTic = true; } } break; } tic.lbl.sprintf( format_single_prec.toLatin1(), tic.val * ticScale ); return &tic; } void CPlotAxis::setScale( const unsigned int pts ) { //if ( !initialized ) //qWarning( "you try to set the scale before defining the min & max value. not very sensible." ); points = pts; scale = pts / ( usedMax - usedMin ); } void CPlotAxis::resetZoom() { setMinMax(limitMin, limitMax); } void CPlotAxis::zoom(bool in, int point) { qreal factor = in ? (1 / 1.1) : 1.1; qreal p = pt2val(point); qreal min = (p - usedMin) * (1 - factor) + usedMin; qreal d = min - usedMin * factor; qreal max = usedMax * factor + d; if(qRound(max - min) <= qRound(limitMax - limitMin)) { setMinMax(min, max); move(0); } } void CPlotAxis::move(int delta_pt) { qreal delta_val = pt2val(delta_pt) - pt2val(0); bool f = !(usedMax - usedMin < limitMax - limitMin); if (f ^ (usedMin + delta_val < limitMin)) { delta_val = (limitMin - usedMin); } if (f ^ (usedMax + delta_val > limitMax)) { delta_val = (limitMax - usedMax); } setMinMax(usedMin + delta_val, usedMax + delta_val); } qmapshack-1.10.0/src/plot/IPlot.cpp000644 001750 000144 00000111170 13216234137 020225 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "plot/CPlotAxis.h" #include "plot/IPlot.h" #include "CMainWindow.h" #include "gis/CGisWorkspace.h" #include "gis/trk/CActivityTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "mouse/CScrOptRangeTrk.h" #include "widgets/CFadingIcon.h" #include #include const QPen IPlot::pens[] = { QPen(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(QColor("#C00000"), 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(Qt::yellow, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) }; const QPen IPlot::pensThin[] = { QPen(Qt::darkBlue, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(Qt::darkRed, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(Qt::darkYellow, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , QPen(Qt::darkGreen, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) }; const QColor IPlot::colors[] = { QColor(Qt::blue) , QColor(0, 0, 0, 0) , QColor(0, 0, 0, 0) , QColor(Qt::darkGreen) }; int IPlot::cnt = 0; IPlot::IPlot(CGisItemTrk *trk, CPlotData::axistype_e type, mode_e mode, QWidget *parent) : QWidget(parent) , INotifyTrk(CGisItemTrk::eVisualPlot) , mode(mode) , trk(trk) , fm(font()) { cnt++; setObjectName(QString("IPlot%1").arg(cnt)); setContextMenuPolicy(Qt::CustomContextMenu); setMouseTracking(true); if(trk) { trk->registerVisual(this); } data = new CPlotData(type, this); if(mode == eModeIcon) { showScale = false; thinLine = true; } if(mode == eModeWindow) { overrideWindowFlags(Qt::Tool); setAttribute(Qt::WA_DeleteOnClose, true); } menu = new QMenu(this); actionResetZoom = menu->addAction(QIcon("://icons/32x32/Zoom.png"), tr("Reset Zoom"), this, SLOT(slotResetZoom())); actionStopRange = menu->addAction(QIcon("://icons/32x32/SelectRange.png"), tr("Stop Range"), this, SLOT(slotStopRange())); actionPrint = menu->addAction(QIcon("://icons/32x32/Save.png"), tr("Save..."), this, SLOT(slotSave())); menu->addSeparator(); actionAddWpt = menu->addAction(QIcon("://icons/32x32/AddWpt.png"), tr("Add Waypoint"), this, SLOT(slotAddWpt())); actionCutTrk = menu->addAction(QIcon("://icons/32x32/TrkCut.png"), tr("Cut..."), this, SLOT(slotCutTrk())); connect(this, &IPlot::customContextMenuRequested, this, &IPlot::slotContextMenu); } IPlot::~IPlot() { cnt--; if(trk) { trk->unregisterVisual(this); /* Always set the mode to normal. If the object is not owner of the current mode, the request will be ignored. */ trk->setMode(CGisItemTrk::eModeNormal, objectName()); /* As having the user focus will always display an on screen plot, closing the plot has to result into the track loosing the focus. */ if(mode == eModeWindow) { trk->looseUserFocus(); CCanvas * canvas = dynamic_cast(parent()); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } } } } void IPlot::clear() { needsRedraw = true; data->lines.clear(); data->tags.clear(); data->badData = true; update(); } void IPlot::setXTicScale(qreal scale) { data->x().setTicScale(scale); setSizes(); update(); } void IPlot::setYLabel(const QString& str) { data->ylabel = str; setSizes(); update(); } void IPlot::setXLabel(const QString& str) { data->xlabel = str; setSizes(); update(); } void IPlot::newLine(const QPolygonF& line, const QString& label) { data->lines.clear(); QRectF r = line.boundingRect(); if((r.height() < 0) || (r.width() < 0) || line.isEmpty()) { data->badData = true; return; } CPlotData::line_t l; l.points = line; l.label = label; data->badData = false; data->lines << l; setSizes(); data->x().setScale( rectGraphArea.width() ); data->y().setScale( rectGraphArea.height() ); needsRedraw = true; update(); } void IPlot::addLine(const QPolygonF& line, const QString& label) { QRectF r = line.boundingRect(); if(!r.isValid() || line.isEmpty()) { return; } CPlotData::line_t l; l.points = line; l.label = label; data->lines << l; setSizes(); data->x().setScale( rectGraphArea.width() ); data->y().setScale( rectGraphArea.height() ); needsRedraw = true; update(); } void IPlot::setLimits() { data->setLimits(); } void IPlot::resetZoom() { data->x().resetZoom(); data->y().resetZoom(); setSizes(); needsRedraw = true; update(); } void IPlot::paintEvent(QPaintEvent * e) { QPainter p(this); draw(p); } void IPlot::resizeEvent(QResizeEvent * e) { setSizes(); buffer = QImage(e->size(), QImage::Format_ARGB32); needsRedraw = true; update(); } void IPlot::leaveEvent(QEvent * e) { needsRedraw = true; posMouse1 = NOPOINT; CCanvas::restoreOverrideCursor("IPlot::leaveEvent"); update(); } void IPlot::enterEvent(QEvent * e) { needsRedraw = true; CCanvas::setOverrideCursor(Qt::PointingHandCursor,"IPlot::enterEvent"); update(); } void IPlot::draw(QPainter& p) { if(needsRedraw) { draw(); needsRedraw = false; } p.drawImage(0,0,buffer); drawDecoration(p); } void IPlot::keyPressEvent(QKeyEvent *e) { // close the current window if `Esc` was pressed if(Qt::Key_Escape == e->key()) { e->accept(); deleteLater(); } else { QWidget::keyPressEvent(e); } } bool IPlot::graphAreaContainsMousePos(QPoint& pos) { if(rectGraphArea.contains(pos)) { return true; } if((pos.y() < rectGraphArea.bottom()) && (pos.y() > rectGraphArea.top())) { if(pos.x() < rectGraphArea.left()) { pos.rx() = rectGraphArea.left(); } if(pos.x() > rectGraphArea.right()) { pos.rx() = rectGraphArea.right(); } return true; } return false; } void IPlot::mouseMoveEvent(QMouseEvent * e) { if(data->lines.isEmpty() || data->badData || !data->x().isValid() || !data->y().isValid()) { return; } QPoint pos = e->pos(); mouseDidMove = (e->buttons() == Qt::LeftButton); if(mouseDidMove) { if(!scrOptRange.isNull()) { delete scrOptRange; } QPoint diff = pos - posLast; data->x().move(-diff.x()); data->y().move( diff.y()); needsRedraw = true; update(); posLast = pos; return; } posMouse1 = NOPOINT; if(graphAreaContainsMousePos(pos)) { posMouse1 = pos; // set point of focus at track object qreal x = data->x().pt2val(posMouse1.x() - left); setMouseFocus(x, CGisItemTrk::eFocusMouseMove); // update canvas if visible CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->update(); } e->accept(); } update(); } void IPlot::setMouseFocus(qreal pos, enum CGisItemTrk::focusmode_e fm) { if(nullptr == trk) { return; } if(data->axisType == CPlotData::eAxisLinear) { trk->setMouseFocusByDistance(pos, fm, objectName()); } else if(data->axisType == CPlotData::eAxisTime) { trk->setMouseFocusByTime(pos, fm, objectName()); } } void IPlot::mousePressEvent(QMouseEvent * e) { if((e->button() == Qt::LeftButton) && (mode == eModeIcon)) { trk->edit(); } mouseDidMove = false; posLast = e->pos(); } void IPlot::mouseReleaseEvent(QMouseEvent * e) { if(e->button() == Qt::LeftButton) { if((mode == eModeIcon) || mouseDidMove) { mouseDidMove = false; return; } else { QPoint pos = e->pos(); posMouse1 = graphAreaContainsMousePos(pos) ? pos : NOPOINT; bool wasProcessed = true; // set point of focus at track object qreal x = data->x().pt2val(posMouse1.x() - left); switch(mouseClickState) { case eMouseClickIdle: { // In idle state a mouse click will select the first point of a range if(trk->setMode(CGisItemTrk::eModeRange, objectName())) { setMouseFocus(x, CGisItemTrk::eFocusMouseClick); mouseClickState = eMouseClick1st; } else { /* If the object is not the owner of the range selection, no action has to be taken. However the user has to be informed, that he clicked on the wrong widget. */ new CFadingIcon(posMouse1, "://icons/48x48/NoGo.png", this); wasProcessed = false; } break; } case eMouseClick1st: { // In 1st click state a mouse click will select the second point of a range and display options setMouseFocus(x, CGisItemTrk::eFocusMouseClick); /* As the screen option is created on the fly it has to be connected to all slots,too. Later, when destroyed the slots will be disconnected automatically. */ delete scrOptRange; scrOptRange = new CScrOptRangeTrk(pos, trk, &dummyMouse, this); connect(scrOptRange->toolHidePoints, &QToolButton::clicked, this, &IPlot::slotHidePoints); connect(scrOptRange->toolShowPoints, &QToolButton::clicked, this, &IPlot::slotShowPoints); connect(scrOptRange->toolCopy, &QToolButton::clicked, this, &IPlot::slotCopy); connect(scrOptRange.data(), &CScrOptRangeTrk::activitySelected, this, &IPlot::slotActivity); /* Adjust position of screen option widget if the widget is out of the visible area*/ QRect r1 = scrOptRange->geometry(); QRect r2 = geometry(); r1.moveTopLeft(mapToParent(r1.topLeft())); if(!r2.contains(r1)) { // test if screen option is out of area on the right side if(!r2.contains(r1.topRight())) { QPoint pt = QPoint(r2.width(), r2.height()) - QPoint(r1.width(), r1.height()); scrOptRange->move(pt); } // test if screen option is out of area on the left side else if(!r2.contains(r1.topLeft())) { QPoint pt = QPoint(0, r2.height()) - QPoint(0, r1.height()); scrOptRange->move(pt); } // test if screen option is out of area on the bottom else if(!r2.contains(r1.bottomLeft())) { QPoint pt = QPoint(r1.left(), r2.height()) - QPoint(r2.left(), r1.height()); scrOptRange->move(pt); } } mouseClickState = eMouseClick2nd; break; } case eMouseClick2nd: { // In second click state a mouse click will reset the range selection delete scrOptRange; trk->setMode(CGisItemTrk::eModeNormal, objectName()); idxSel1 = idxSel2 = NOIDX; mouseClickState = eMouseClickIdle; break; } } // Update canvas only if the object is the owner of the range selection if(wasProcessed) { emit sigMouseClickState(mouseClickState); // update canvas if visible CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->update(); } } } e->accept(); } update(); } void IPlot::wheelEvent(QWheelEvent * e) { bool in = CMainWindow::self().flipMouseWheel() ? (e->delta() < 0) : (e->delta() > 0); bool doHorizontalZoom = false; bool doVerticalZoom = false; switch(QApplication::keyboardModifiers()) { case Qt::AltModifier: doHorizontalZoom = true; break; case Qt::ControlModifier: doVerticalZoom = true; break; case Qt::NoModifier: doHorizontalZoom = true; doVerticalZoom = true; break; } if(doHorizontalZoom) { data->x().zoom(in, e->pos().x() - left); setSizes(); data->x().setScale(rectGraphArea.width()); } if(doVerticalZoom) { data->y().zoom(in, bottom - e->pos().y()); setSizes(); data->y().setScale(rectGraphArea.height()); } QPoint p = mapToGlobal(e->pos() + QPoint(32,0)); QToolTip::showText(p,tr("Hold CTRL key for vertical zoom, only.\nHold ALT key for horizontal zoom, only."), this, QRect(), 500); needsRedraw = true; update(); } void IPlot::setSizes() { fm = QFontMetrics(CMainWindow::self().getMapFont()); left = 0; scaleWidthX1 = showScale ? data->x().getScaleWidth( fm ) : 0; scaleWidthY1 = showScale ? data->y().getScaleWidth( fm ) : 0; scaleWidthY1 = (scaleWidthX1/2) > scaleWidthY1 ? scaleWidthX1/2 : scaleWidthY1; fontWidth = fm.maxWidth(); fontHeight = fm.height(); deadAreaX = fontWidth >> 1; deadAreaY = ( fontHeight + 1 ) >> 1; setLRTB(); setSizeIconArea(); setSizeXLabel(); setSizeYLabel(); setSizeTrackInfo(); setSizeDrawArea(); } void IPlot::setLRTB() { left = 0; left += data->ylabel.isEmpty() ? 0 : fontHeight; left += scaleWidthY1; left += deadAreaX; right = size().width(); right -= deadAreaX; right -= scaleWidthX1 / 2; top = 0; if(!data->tags.isEmpty()) { top += 9; } top += deadAreaY; bottom = size().height(); bottom -= data->xlabel.isEmpty() ? 0 : fontHeight; // tick marks if(scaleWidthX1) { bottom -= fontHeight; } bottom -= deadAreaY; if(!data->xlabel.isEmpty()) { bottom -= deadAreaY; } } void IPlot::setSizeIconArea() { rectIconArea = QRect(left, deadAreaY, right - left, 16 + fontHeight + deadAreaY); } void IPlot::setSizeXLabel() { int y; if ( data->xlabel.isEmpty() ) { rectX1Label = QRect( 0, 0, 0, 0 ); } else { rectX1Label.setWidth( right - left ); rectX1Label.setHeight( fontHeight ); y = ( size().height() - rectX1Label.height()) - deadAreaY; rectX1Label.moveTopLeft( QPoint( left, y ) ); } } void IPlot::setSizeYLabel() { if ( data->ylabel.isEmpty() ) { rectY1Label = QRect( 0, 0, 0, 0 ); } else { rectY1Label.setWidth( bottom - top ); rectY1Label.setHeight( fontHeight ); rectY1Label.moveTopLeft( QPoint( size().height() - bottom, 0 ) ); } } void IPlot::setSizeTrackInfo() { if(data->tags.isEmpty() /*|| !CResources::self().showTrackProfileEleInfo()*/) { rectTrackInfo = QRect(); return; } rectTrackInfo.setWidth(right - left); rectTrackInfo.setHeight(fontHeight); rectTrackInfo.moveLeft(left); rectTrackInfo.moveTop(size().height() - fontHeight); } void IPlot::setSizeDrawArea() { rectGraphArea.setWidth( right - left ); rectGraphArea.setHeight( bottom - top ); rectGraphArea.moveTopLeft( QPoint( left, top ) ); data->x().setScale( rectGraphArea.width() ); data->y().setScale( rectGraphArea.height() ); } void IPlot::draw() { buffer.fill(Qt::transparent); QPainter p(&buffer); USE_ANTI_ALIASING(p, true); if(mode == eModeNormal) { p.fillRect(rect(),Qt::white); } else if(mode == eModeIcon) { QRect r = rect(); r.adjust(2,2,-2,-2); if(underMouse() || posMouse1 != NOPOINT || solid) { p.setPen(solid ? CDraw::penBorderBlack : CDraw::penBorderBlue); p.setOpacity(1.0); } else { p.setPen(CDraw::penBorderBlack); p.setOpacity(0.6); } p.setBrush(QColor(255,255,255,255)); PAINT_ROUNDED_RECT(p,r); } if(data->lines.isEmpty() || data->badData || !data->x().isValid() || !data->y().isValid()) { p.drawText(rect(), Qt::AlignCenter, tr("No or bad data.")); return; } p.setFont(CMainWindow::self().getMapFont()); drawTags(p); p.setClipping(true); p.setClipRect(rectGraphArea); drawData(p); p.setClipping(false); drawLabels(p); if(showScale) { drawXScale(p); drawYScale(p); } drawGridX(p); drawGridY(p); drawActivities(p); drawXTic(p); drawYTic(p); p.setPen(QPen(Qt::black,2)); p.drawRect(rectGraphArea); drawLegend(p); } QPointF IPlot::getBasePoint(int ptx) const { CPlotAxis& yaxis = data->y(); if(0 >= data->ymin && 0 <= data->ymax) { return QPointF(ptx, bottom - yaxis.val2pt(0)); } else if(data->ymin >= 0) { return QPointF(ptx, bottom - yaxis.val2pt(data->ymin)); } else if(data->ymax <= 0) { return QPointF(ptx, bottom - yaxis.val2pt(data->ymax)); } qWarning() << "Requesting basePoint for ptx = " << ptx << "; data->ymin/max = {" << data->ymin << ", " << data->ymax << "}"; return QPointF(ptx, bottom); } QPolygonF IPlot::getVisiblePolygon(const QPolygonF &polyline, QPolygonF &line) const { const CPlotAxis &xaxis = data->x(); const CPlotAxis &yaxis = data->y(); int ptx = NOINT; int pty = NOINT; for(const QPointF &pt : polyline) { int oldPtx = ptx; int oldPty = pty; ptx = left + xaxis.val2pt( pt.x() ); pty = bottom - yaxis.val2pt( pt.y() ); if(ptx >= left && ptx <= right) { // if oldPtx is < left, then ptx is the first visible point if(NOINT == oldPtx || oldPtx < left) { // we may need to interpolate things if we just found the first visible point if(NOINT != oldPtx && ptx > left) { line << getBasePoint(left); int intPty = oldPty + ((oldPty - pty) * (left - oldPtx)) / (oldPtx - ptx); line << QPointF(left, intPty); } else { line << getBasePoint(ptx); } } line << QPointF(ptx, pty); } else if(ptx > right) { // handle the special case `no point in the visible interval` // -> add interpolated left point if(oldPtx < left) { oldPty = oldPty + (pty - oldPty) / (left - oldPtx); oldPtx = left; line << getBasePoint(oldPtx); line << QPointF(oldPtx, oldPty); } // interpolate the value at `right` pty = oldPty + ((pty - oldPty) * (right - oldPtx)) / (ptx - oldPtx); ptx = right; line << QPointF(ptx, pty); } if(ptx >= right) { break; } } line << getBasePoint(ptx); return line; } void IPlot::drawData(QPainter& p) { int penIdx = 0; QList lines = data->lines; QList::const_iterator line = lines.begin(); while(line != lines.end()) { QPolygonF poly; getVisiblePolygon(line->points, poly); p.setPen(Qt::NoPen); p.setBrush(colors[penIdx]); p.drawPolygon(poly); p.setPen(thinLine ? pensThin[penIdx++] : pens[penIdx++]); p.setBrush(Qt::NoBrush); poly.pop_front(); poly.pop_back(); p.drawPolyline(poly); ++line; } } void IPlot::drawLabels( QPainter &p ) { p.setPen(Qt::darkBlue); if ( rectX1Label.isValid() ) { p.drawText( rectX1Label, Qt::AlignCenter, data->xlabel ); } p.save(); QMatrix m = p.matrix(); m.translate( 0, size().height() ); m.rotate( -90 ); p.setMatrix( m ); if ( rectY1Label.isValid() ) { p.drawText( rectY1Label, Qt::AlignCenter, data->ylabel ); } p.restore(); } void IPlot::drawXScale( QPainter &p ) { QRect recText; if ( data->x().getTicType() == CPlotAxis::eNoTic ) { return; } p.setPen(Qt::darkBlue); recText.setHeight( fontHeight ); recText.setWidth( scaleWidthX1 ); int ix_ = -1; const int iy = bottom + deadAreaY; const CPlotAxis::tic_t * t = data->x().ticmark(); while ( t ) { int ix = left + data->x().val2pt( t->val ) - ( scaleWidthX1 + 1 ) / 2; if ( ( ( ix_ < 0 ) || ( ( ix - ix_ ) > scaleWidthX1 + 5 ) ) && !t->lbl.isEmpty() ) { recText.moveTopLeft( QPoint( ix, iy ) ); p.drawText( recText, Qt::AlignCenter, t->lbl ); ix_ = ix; } t = data->x().ticmark( t ); } qreal limMin, limMax, useMin, useMax; data->x().getLimits(limMin, limMax, useMin, useMax); if(!isZoomed()) { return; } qreal scale = (right - left) / (limMax - limMin); int x = left + (useMin - limMin) * scale; int y = bottom + 5; int w = (useMax - useMin) * scale; p.setPen(QPen(Qt::red,3)); p.drawLine(x,y, x + w, y); } void IPlot::drawYScale( QPainter &p ) { QString format_single_prec; QRect recText; if ( data->y().getTicType() == CPlotAxis::eNoTic ) { return; } p.setPen(Qt::darkBlue); recText.setHeight( fontHeight ); recText.setWidth( scaleWidthY1 ); int ix = left - scaleWidthY1 - deadAreaX; int iy; qreal limMin, limMax, useMin, useMax; data->y().getLimits(limMin, limMax, useMin, useMax); // draw min/max labels 1st; QRect recTextMin; QRect recTextMax; format_single_prec = data->y().fmtsgl(data->ymin); if(data->ymin >= useMin) { iy = bottom - data->y().val2pt( data->ymin ) - fontHeight / 2; recText.moveTopLeft( QPoint( ix, iy ) ); p.drawText( recText, Qt::AlignRight, QString().sprintf( format_single_prec.toLatin1().data(), data->ymin )); recTextMin = recText; } format_single_prec = data->y().fmtsgl(data->ymax); if(data->ymax <= useMax) { iy = bottom - data->y().val2pt( data->ymax ) - fontHeight / 2; recText.moveTopLeft( QPoint( ix, iy ) ); p.drawText( recText, Qt::AlignRight, QString().sprintf( format_single_prec.toLatin1().data(), data->ymax )); recTextMax = recText; } // draw tic marks const CPlotAxis::tic_t * t = data->y().ticmark(); while ( t ) { iy = bottom - data->y().val2pt( t->val ) - fontHeight / 2; recText.moveTopLeft( QPoint( ix, iy ) ); if(!recTextMin.intersects(recText) && !recTextMax.intersects(recText)) { p.drawText( recText, Qt::AlignRight, t->lbl ); } t = data->y().ticmark( t ); } if(!isZoomed()) { return; } qreal scale = (top - bottom) / (limMax - limMin); int x = left - 5; int y = bottom + (useMin - limMin) * scale; int h = (useMax - useMin) * scale; p.setPen(QPen(Qt::red,3)); p.drawLine(x,y, x, y + h); } void IPlot::drawGridX( QPainter &p ) { CPlotAxis::tictype_e oldtic = data->x().setTicType( CPlotAxis::eTicNorm ); const int dy = rectGraphArea.height(); const CPlotAxis::tic_t * t = data->x().ticmark(); QPen oldpen = p.pen(); p.setPen( QPen( QColor(0,150,0,128), 1, Qt::DotLine ) ); const int iy = rectGraphArea.top(); while ( t ) { int ix = left + data->x().val2pt( t->val ); p.drawLine( ix, iy, ix, iy + dy ); t = data->x().ticmark( t ); } p.setPen( oldpen ); data->x().setTicType( oldtic ); } void IPlot::drawGridY( QPainter &p ) { CPlotAxis::tictype_e oldtic = data->y().setTicType( CPlotAxis::eTicNorm ); const int dx = rectGraphArea.width(); const CPlotAxis::tic_t * t = data->y().ticmark(); QPen oldpen = p.pen(); p.setPen( QPen( QColor(0,150,0,128), 1, Qt::DotLine ) ); const int ix = rectGraphArea.left(); while(nullptr != t) { int iy = bottom - data->y().val2pt( t->val ); p.drawLine( ix, iy, ix + dx, iy ); t = data->y().ticmark( t ); } // draw min/max lines qreal limMin, limMax, useMin, useMax; data->y().getLimits(limMin, limMax, useMin, useMax); if(data->ymin > useMin) { int iy = bottom - data->y().val2pt( data->ymin ); p.drawLine( ix, iy, ix + dx, iy ); } if(data->ymax < useMax) { int iy = bottom - data->y().val2pt( data->ymax ); p.drawLine( ix, iy, ix + dx, iy ); } p.setPen( oldpen ); data->y().setTicType( oldtic ); } void IPlot::drawXTic( QPainter & p ) { const CPlotAxis::tic_t * t = data->x().ticmark(); p.setPen(QPen(Qt::black, 2)); const int iyb = rectGraphArea.bottom(); const int iyt = rectGraphArea.top(); while(nullptr != t) { const int ix = left + data->x().val2pt( t->val ); p.drawLine( ix, iyb, ix, iyb - 5 ); p.drawLine( ix, iyt, ix, iyt + 5 ); t = data->x().ticmark( t ); } } void IPlot::drawYTic( QPainter &p ) { const CPlotAxis::tic_t * t = data->y().ticmark(); p.setPen(QPen(Qt::black, 2)); const int ixl = rectGraphArea.left(); const int ixr = rectGraphArea.right(); while ( t ) { const int iy = bottom - data->y().val2pt( t->val ); p.drawLine( ixl, iy, ixl + 5, iy ); p.drawLine( ixr, iy, ixr - 5, iy ); t = data->y().ticmark( t ); } } void IPlot::drawLegend(QPainter& p) { if((data->lines.size() < 2) || (mode == eModeIcon)) { return; } int penIdx = 0; QFontMetrics fm(p.font()); int h = fm.height(); int x = rectGraphArea.left() + 10; int y = rectGraphArea.top() + 2 + h; QList lines = data->lines; QList::const_iterator line = lines.begin(); while(line != lines.end()) { p.setPen(Qt::black); p.drawText(x + 30,y,line->label); p.setPen(pens[penIdx++]); p.drawLine(x, y, x + 20, y); y += fm.height(); ++line; } } void IPlot::drawDecoration( QPainter &p ) { if(posMouse1 != NOPOINT) { // draw the vertical `you are here` line int x = posMouse1.x(); p.setPen(QPen(Qt::red, 2)); if(x >= left && x <= right) { p.drawLine(x, top, x, bottom); // check if the mouse is near a waypoint for(const CPlotData::point_t& tag : data->tags) { int ptx = left + data->x().val2pt( tag.point.x() ); if(qAbs(x - ptx) < 10) { QFont f = CMainWindow::self().getMapFont(); f.setBold(true); QFontMetrics fm(f); QRect r = fm.boundingRect(tag.label); r.moveCenter(QPoint(ptx, top - fm.height()/2 - fm.descent())); r.adjust(-3,-2,3,0); p.setPen(Qt::NoPen); p.setBrush(Qt::white); p.drawRoundedRect(r, RECT_RADIUS, RECT_RADIUS); p.setFont(f); p.setPen(Qt::darkBlue); p.drawText(r, Qt::AlignCenter, tag.label); break; } } } } if((idxSel1 != NOIDX) && (idxSel2 != NOIDX) && !data->badData) { p.setClipRect(rectGraphArea); int penIdx = 3; const QPolygonF& polyline = data->lines.first().points.mid(idxSel1, idxSel2 - idxSel1 + 1); QPolygonF line; getVisiblePolygon(polyline, line); // avoid drawing if the whole interval is outside the visible range if(!(line.first().x() >= right || line.last().x() <= left)) { // draw the background p.setPen(Qt::NoPen); p.setBrush(colors[penIdx]); p.drawPolygon(line); // draw the foreground p.setPen(thinLine ? pensThin[penIdx] : pens[penIdx]); p.setBrush(Qt::NoBrush); line.pop_front(); line.pop_back(); p.drawPolyline(line); p.setPen(QPen(Qt::darkBlue, 2)); p.drawLine(line.first().x(), top, line.first().x(), bottom); p.drawLine(line.last().x(), top, line.last().x(), bottom); } p.setClipping(false); } if(!scrOptRange.isNull()) { scrOptRange->draw(p); } } void IPlot::drawTags(QPainter& p) { if(data->tags.isEmpty()) { return; } CPlotAxis& xaxis = data->x(); CPlotAxis& yaxis = data->y(); QVector::const_iterator tag = data->tags.begin(); while(tag != data->tags.end()) { int ptx = left + xaxis.val2pt( tag->point.x() ); int pty = bottom - yaxis.val2pt( tag->point.y() ); if (left < ptx && ptx < right) { QPixmap icon = tag->icon.scaled(10,10, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); p.drawPixmap(ptx - icon.width() / 2, 2, icon); p.setPen(QPen(Qt::white, 3)); if( 9 < pty) { if (pty > bottom) { pty = bottom; } p.drawLine(ptx, top, ptx, pty); p.setPen(QPen(Qt::black, 1)); p.drawLine(ptx, top, ptx, pty); } } ++tag; } } void IPlot::drawActivities(QPainter& p) { if((mode == eModeIcon) || (trk->getActivities().getAllFlags() == 0)) { return; } const QList& ranges = trk->getActivities().getActivityRanges(); QRect rectClipping = QRect(0,0,right - left,22); p.save(); p.translate(left, bottom - 22); p.setClipRect(rectClipping); p.setBrush(QColor(0,170,0,100)); p.setPen(Qt::NoPen); p.drawRect(rectClipping); QRect rectIconFrame(0,0,20,20); QRect rectIcon(2,2,16,16); for(const CActivityTrk::activity_range_t& range : ranges) { int x1, x2; if(data->axisType == CPlotData::eAxisTime) { x1 = data->x().val2pt(range.t1); x2 = data->x().val2pt(range.t2); } else { x1 = data->x().val2pt(range.d1); x2 = data->x().val2pt(range.d2); } p.setPen(QPen(Qt::darkGreen,2)); p.drawLine(x1, 0, x1, 20); p.drawLine(x2, 0, x2, 20); int d = (x2 - x1); if(d < 20) { continue; } int c = x1 + d/2; rectIconFrame.moveCenter(QPoint(c,10)); p.setBrush(QColor(255, 255, 255, 100)); p.drawRoundedRect(rectIconFrame, RECT_RADIUS, RECT_RADIUS); rectIcon.moveCenter(QPoint(c, 10)); p.drawPixmap(rectIcon, QPixmap(range.icon)); } p.restore(); } void IPlot::save(QImage& image) { resize(image.size()); setSizes(); buffer = QImage(image.size(), QImage::Format_ARGB32); draw(); image = buffer; } void IPlot::slotContextMenu(const QPoint & point) { QPoint p = mapToGlobal(point); actionResetZoom->setEnabled(isZoomed()); actionStopRange->setEnabled((mouseClickState != eMouseClickIdle) && !(idxSel1 == NOIDX || idxSel2 == NOIDX)); actionPrint->setEnabled(mouseClickState != eMouseClick2nd); actionAddWpt->setDisabled(posMouse1 == NOPOINT); actionCutTrk->setDisabled(actionStopRange->isEnabled()); posMouse2 = posMouse1; menu->exec(p); posMouse2 = NOPOINT; } void IPlot::slotSave() { SETTINGS; QString path = cfg.value("Paths/lastGraphPath", QDir::homePath()).toString(); QString filename = QFileDialog::getSaveFileName( this, tr("Select output file"), path, "PNG Image (*.png)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); if(fi.suffix().toLower() != "png") { filename += ".png"; } QImage img(size(), QImage::Format_ARGB32); QPainter p; p.begin(&img); p.fillRect(rect(), QBrush(Qt::white)); draw(p); p.end(); img.save(filename); path = fi.absolutePath(); cfg.setValue("Paths/lastGraphPath", path); } void IPlot::slotHidePoints() { trk->hideSelectedPoints(); slotStopRange(); } void IPlot::slotShowPoints() { trk->showSelectedPoints(); slotStopRange(); } void IPlot::slotActivity(quint32 flags) { trk->setActivityRange(flags); slotStopRange(); } void IPlot::slotCopy() { trk->copySelectedPoints(); slotStopRange(); } void IPlot::slotStopRange() { scrOptRange->deleteLater(); trk->setMode(CGisItemTrk::eModeNormal, objectName()); idxSel1 = idxSel2 = NOIDX; mouseClickState = eMouseClickIdle; emit sigMouseClickState(mouseClickState); // update canvas if visible CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->update(); } } void IPlot::slotResetZoom() { data->x().resetZoom(); data->y().resetZoom(); setSizes(); needsRedraw = true; update(); } void IPlot::slotAddWpt() { if(posMouse2 == NOPOINT) { return; } const CTrackData::trkpt_t * trkpt = trk->getMouseMoveFocusPoint(); if(trkpt == nullptr) { return; } CGisWorkspace::self().addWptByPos({trkpt->lon, trkpt->lat}); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } void IPlot::slotCutTrk() { // set point of mouse click focus to position of context menu stored in // secondary mouse point qreal x = data->x().pt2val(posMouse2.x() - left); setMouseFocus(x, CGisItemTrk::eFocusMouseClick); /* Trigger cut by event not by direct call to API. This is because cutting the track might result into deleting the original one. The original one is the parent of this plot and needs to destroy it. This would be impossible if we are still in this method because the API call did not return yet. */ CGisWorkspace::self().postEventForWks(new CEvtA2WCutTrk(trk->getKey())); } void IPlot::setMouseRangeFocus(const CTrackData::trkpt_t * ptRange1, const CTrackData::trkpt_t *ptRange2) { if(nullptr == ptRange1 || nullptr == ptRange2) { idxSel1 = NOIDX; idxSel2 = NOIDX; } else { if(ptRange1->idxTotal < ptRange2->idxTotal) { while(ptRange1->isHidden()) { ptRange1++; } while(ptRange2->isHidden()) { ptRange2--; } idxSel1 = ptRange1->idxVisible; idxSel2 = ptRange2->idxVisible; } else { while(ptRange1->isHidden()) { ptRange1--; } while(ptRange2->isHidden()) { ptRange2++; } idxSel1 = ptRange2->idxVisible; idxSel2 = ptRange1->idxVisible; } } update(); } bool IPlot::isZoomed() const { bool zoomed = false; qreal limMin, limMax, useMin, useMax; data->x().getLimits(limMin, limMax, useMin, useMax); zoomed |= !((limMax - limMin) <= (useMax - useMin)); data->y().getLimits(limMin, limMax, useMin, useMax); zoomed |= !((limMax - limMin) <= (useMax - useMin)); return zoomed; } qmapshack-1.10.0/src/plot/CPlotData.cpp000644 001750 000144 00000004545 13216234137 021020 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "plot/CPlotAxis.h" #include "plot/CPlotAxisTime.h" #include "plot/CPlotData.h" #include "units/IUnit.h" CPlotData::CPlotData(axistype_e type, QObject * parent) : QObject(parent) , axisType(type) { setXAxisType(type); yaxis = new CPlotAxis(this); } CPlotData::~CPlotData() { } void CPlotData::setXAxisType(axistype_e type) { delete xaxis; if(type == eAxisLinear) { xaxis = new CPlotAxis(this); } else { xaxis = new CPlotAxisTime(this); } xaxis->setAutoscale(false); axisType = type; } void CPlotData::setLimits() { if(lines.size() == 0 || badData) { return; } QList::const_iterator line = lines.begin(); if(line == lines.end()) { return; } QPolygonF::const_iterator p = line->points.begin(); xmin = p->x(); xmax = p->x(); ymin = p->y(); ymax = p->y(); while(line != lines.end()) { QPolygonF::const_iterator p = line->points.begin(); while(p != line->points.end()) { if(p->y() != NOFLOAT) { xmin = qMin(xmin, p->x()); xmax = qMax(xmax, p->x()); ymin = qMin(ymin, p->y()); ymax = qMax(ymax, p->y()); } ++p; } ++line; } if(xmin == xmax) { badData = true; } else { xaxis->setLimits(xmin, xmax); yaxis->setLimits(ymin, ymax); } } qmapshack-1.10.0/src/plot/ITrack.cpp000644 001750 000144 00000007543 13216234137 020363 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "plot/ITrack.h" #include ITrack::ITrack() { pjtar = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); } ITrack::~ITrack() { if(pjtar) { pj_free(pjtar); } if(pjsrc) { pj_free(pjsrc); } } void ITrack::save(QImage& image) { setSize(image.width(), image.height()); draw(); image = buffer; } void ITrack::setSize(int w, int h) { buffer = QImage(w, h, QImage::Format_ARGB32); updateData(); } void ITrack::setupProjection(const QRectF& boundingBox) { if(pjsrc) { pj_free(pjsrc); pjsrc = nullptr; } if(boundingBox.top() > (60*DEG_TO_RAD)) { pjsrc = pj_init_plus("+init=epsg:32661"); } else if(boundingBox.bottom() < (-60*DEG_TO_RAD)) { pjsrc = pj_init_plus("+init=epsg:32761"); } else { pjsrc = pj_init_plus("+init=epsg:3857"); } } void ITrack::setTrack(CGisItemTrk * track) { trk = track; setupProjection(trk->getBoundingRect()); updateData(); } void ITrack::setTrack(const QPolygonF& track) { coords = track; setupProjection(coords.boundingRect()); updateData(); } void ITrack::updateData() { if((pjsrc == nullptr) || (nullptr == trk && coords.isEmpty())) { return; } if(trk) { coords.clear(); const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { if(trkpt.isHidden()) { continue; } coords << trkpt.radPoint(); } } line.clear(); for(const QPointF &trkpt : coords) { QPointF pt(trkpt.x(), trkpt.y()); pj_transform(pjtar, pjsrc, 1, 0, &pt.rx(), &pt.ry(), 0); line << pt; } QRectF r1 = line.boundingRect(); qreal w1 = r1.width(); qreal h1 = r1.height(); QRectF r2 = buffer.rect(); qreal w2 = r2.width(); qreal h2 = r2.height(); if(qAbs(w1) > qAbs(h1)) { scale.rx() = (w2 - 10) / w1; scale.ry() = -scale.x(); xoff = 0; yoff = -((h2 - 10)/scale.y() + h1) / 2; } else { scale.ry() = (-h2 + 10) / h1; scale.rx() = -scale.y(); xoff = -((w2 - 10)/scale.x() - w1) / 2; yoff = 0; } xoff += r1.left() - 5/scale.x(); yoff += r1.bottom() - 5/scale.y(); needsRedraw = true; } void ITrack::draw(QPainter& p) { if(needsRedraw) { draw(); needsRedraw = false; } p.drawImage(0, 0, buffer); } void ITrack::draw() { buffer.fill(Qt::transparent); QPainter p(&buffer); USE_ANTI_ALIASING(p, true); p.setPen(CDraw::penBorderBlack); p.setBrush(QColor(255, 255, 255, 255)); PAINT_ROUNDED_RECT(p, buffer.rect().adjusted(1,1,-1,-1)); p.setPen(QPen(Qt::darkBlue, 2/scale.x())); p.scale(scale.x(), scale.y()); p.translate(-xoff, -yoff); p.drawPolyline(line); } qmapshack-1.10.0/src/plot/CPlotAxisTime.h000644 001750 000144 00000003061 13216234142 021323 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOTAXISTIME_H #define CPLOTAXISTIME_H #include "plot/CPlotAxis.h" class CPlotAxisTime : public CPlotAxis { Q_OBJECT public: CPlotAxisTime(QObject * parent) : CPlotAxis(parent) { } virtual ~CPlotAxisTime() { } ///calculate format for the given value const QString fmtsgl(qreal /*val*/) override { return strFormat; } ///calculate format for the given value const QString fmtdbl(qreal /*val*/) override { return strFormat; } const tic_t* ticmark( const tic_t * t ) override; protected: void calc() override; const QString strFormat = "hh:mm:ss"; }; #endif //CPLOTAXISTIME_H qmapshack-1.10.0/src/plot/CPlotProfile.h000644 001750 000144 00000002670 13216234142 021205 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPLOTPROFILE_H #define CPLOTPROFILE_H #include "plot/IPlot.h" class CLimit; class CPlotProfile : public IPlot { Q_OBJECT public: CPlotProfile(QWidget * parent); CPlotProfile(CGisItemTrk * trk, CLimit& lim, mode_e mode, QWidget * parent); virtual ~CPlotProfile(); void setTrack(CGisItemTrk * track, CLimit& lim); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t * ptMouseMove) override; public slots: void setLimits(); private: CLimit * limit = nullptr; }; #endif //CPLOTPROFILE_H qmapshack-1.10.0/src/helpers/000755 001750 000144 00000000000 13216664445 017166 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/helpers/IElevationDialog.ui000644 001750 000144 00000005115 13135614453 022700 0ustar00oeichlerxusers000000 000000 IElevationDialog 0 0 400 121 Edit elevation... Elevation - Get elevation from active digital elevation model. ... :/icons/32x32/SetEle.png:/icons/32x32/SetEle.png Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IElevationDialog accept() 248 254 157 274 buttonBox rejected() IElevationDialog reject() 316 260 286 274 qmapshack-1.10.0/src/helpers/CSettings.h000644 001750 000144 00000002760 13216234142 021232 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2012 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETTINGS_H #define CSETTINGS_H #include "setup/CAppOpts.h" #include class CSettings : public QObject { public: CSettings() { if(!qlOpts->configfile.isEmpty()) { cfg = new QSettings(qlOpts->configfile, QSettings::IniFormat, this); } else { cfg = new QSettings(this); } } ~CSettings() { } QSettings& get() { return *cfg; } private: QSettings * cfg; }; #define SETTINGS \ CSettings ccfg; \ QSettings& cfg = ccfg.get() #endif //CSETTINGS_H qmapshack-1.10.0/src/helpers/IToolBarSetupDialog.ui000644 001750 000144 00000003620 13140265126 023327 0ustar00oeichlerxusers000000 000000 IToolBarSetupDialog 0 0 847 549 Setup Toolbar Toolbar is visible in Fullscreen-mode QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults CSelectDoubleListWidget QWidget
widgets/CSelectDoubleListWidget.h
1
buttonBox accepted() IToolBarSetupDialog accept() 423 526 423 274 buttonBox rejected() IToolBarSetupDialog reject() 423 526 423 274
qmapshack-1.10.0/src/helpers/CElevationDialog.h000644 001750 000144 00000002641 13216234142 022476 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CELEVATIONDIALOG_H #define CELEVATIONDIALOG_H #include "ui_IElevationDialog.h" #include class CElevationDialog : public QDialog, private Ui::IElevationDialog { Q_OBJECT public: CElevationDialog(QWidget * parent, QVariant &val, const QVariant &reset, const QPointF& pos); virtual ~CElevationDialog(); public slots: void accept() override; private slots: void slotReset(); void slotGetEle(); private: QVariant& val; QVariant reset; QPointF pos; }; #endif //CELEVATIONDIALOG_H qmapshack-1.10.0/src/helpers/CPositionDialog.cpp000644 001750 000144 00000003577 13216234137 022724 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CPositionDialog.h" #include "units/IUnit.h" #include CPositionDialog::CPositionDialog(QWidget * parent, QPointF &pos) : QDialog(parent) , pos(pos) { setupUi(this); QString str; IUnit::degToStr(pos.x(), pos.y(), str); lineEdit->setText(str); labelWarning->hide(); connect(lineEdit, &QLineEdit::textEdited, this, &CPositionDialog::slotEdit); } CPositionDialog::~CPositionDialog() { } void CPositionDialog::accept() { if(getPosition(pos, lineEdit->text())) { QDialog::accept(); } } bool CPositionDialog::getPosition(QPointF& pt, const QString& str) { qreal lon, lat; bool res = IUnit::strToDeg(str, lon, lat); if(res) { pt.rx() = lon; pt.ry() = lat; } return res; } void CPositionDialog::slotEdit(const QString& str) { bool isValid = IUnit::isValidCoordString(str); labelWarning->setVisible(!isValid); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid); } qmapshack-1.10.0/src/helpers/CPhotoViewer.cpp000644 001750 000144 00000012242 13216234137 022240 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "CPhotoViewer.h" #include CPhotoViewer::CPhotoViewer(QList &images, int idx, QWidget *parent) : QDialog(parent) , images(images) , idx(idx) { setStyleSheet("background-color:black;"); setAttribute(Qt::WA_TranslucentBackground); Qt::WindowFlags flags = windowFlags() & Qt::WindowType_Mask; setWindowFlags(flags | Qt::CustomizeWindowHint); showMaximized(); // check if showMaximized() worked correctly by comparing our size with the MainWindow's size // if showMaximized() failed we change our size (manually) to match the MainWindow's size // this is hack, but does its job on px i3-wm QMainWindow &main = CMainWindow::self(); if(width() < main.width() && height() < main.height()) { qDebug() << "showMaximized() failed, using MainWindow.frameGeometry()"; setGeometry(main.frameGeometry()); } if(!images.isEmpty()) { setImageAtIdx(idx); } } CPhotoViewer::~CPhotoViewer() { } void CPhotoViewer::resizeEvent(QResizeEvent * e) { QDialog::resizeEvent(e); setImageAtIdx(idx); } void CPhotoViewer::setImageAtIdx(int i) { const QRect& rectScreen = rect(); const QPoint& center = rectScreen.center(); QImage& pixmap = images[i].pixmap; if(!images[i].filePath.isEmpty()) { pixmap = QImage(images[i].filePath); } double width = rectScreen.width() - 64; double height = rectScreen.height() - 64; if(pixmap.width() > width || pixmap.height() > height) { rectImage = pixmap.rect(); if(pixmap.width() > width) { double ratio = width / rectImage.width(); rectImage.setWidth(width); rectImage.setHeight(qFloor(rectImage.height() * ratio) - 1); } if(pixmap.height() > height) { double ratio = height / rectImage.height(); rectImage.setHeight(height); rectImage.setWidth(qFloor(rectImage.width() * ratio) - 1); } rectImage.moveCenter(center); } else { rectImage = pixmap.rect(); rectImage.moveCenter(center); } rectClose.moveCenter(rectImage.topRight()); rectPrev.setHeight(rectImage.height()); rectPrev.moveBottomLeft(rectImage.bottomLeft()); rectNext.setHeight(rectImage.height()); rectNext.moveBottomRight(rectImage.bottomRight()); } void CPhotoViewer::paintEvent(QPaintEvent * e) { QDialog::paintEvent(e); QPainter p(this); p.setPen(Qt::NoPen); p.setBrush(QColor(0,0,0,190)); p.drawRect(rect()); p.setPen(QPen(Qt::white, 11, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin)); p.setBrush(Qt::white); p.drawRect(rectImage); p.drawImage(rectImage, images[idx].pixmap.scaled(rectImage.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); if(idx != (images.size() - 1)) { p.setPen(Qt::NoPen); p.setBrush(QColor(255,255,255,128)); p.drawRect(rectNext); p.drawPixmap(rectNext.left(),rectNext.bottom() - 32, 32, 32, QPixmap("://icons/32x32/Right.png")); } if(idx != 0) { p.setPen(Qt::NoPen); p.setBrush(QColor(255,255,255,128)); p.drawRect(rectPrev); p.drawPixmap(rectPrev.left(), rectPrev.bottom() - 32, 32, 32, QPixmap("://icons/32x32/Left.png")); } p.drawPixmap(rectClose, QPixmap("://icons/32x32/Close.png")); } void CPhotoViewer::tryIdxStep(int delta) { int prevIdx = idx; idx += delta; idx = qMin(idx, images.size() - 1); idx = qMax(idx, 0); if(prevIdx != idx) { setImageAtIdx(idx); update(); } } void CPhotoViewer::mousePressEvent(QMouseEvent * e) { QPoint pos = e->pos(); if(rectClose.contains(pos)) { reject(); } else if(rectNext.contains(pos)) { tryIdxStep(1); } else if(rectPrev.contains(pos)) { tryIdxStep(-1); } else if(!rectImage.contains(pos)) { reject(); } e->accept(); } void CPhotoViewer::keyPressEvent(QKeyEvent *e) { switch(e->key()) { case Qt::Key_Left: tryIdxStep(-1); break; case Qt::Key_Right: tryIdxStep(1); break; case Qt::Key_Q: reject(); break; } QDialog::keyPressEvent(e); } qmapshack-1.10.0/src/helpers/CPhotoViewer.h000644 001750 000144 00000003213 13216234142 021677 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPHOTOVIEWER_H #define CPHOTOVIEWER_H #include #include "gis/wpt/CGisItemWpt.h" class CPhotoViewer : public QDialog { Q_OBJECT public: CPhotoViewer(QList &images, int idx, QWidget *parent); virtual ~CPhotoViewer(); protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void keyPressEvent(QKeyEvent *e) override; private: void tryIdxStep(int delta); void setImageAtIdx(int i); QList images; int idx; QRect rectImage {0,0,100,100}; QRect rectClose {0,0,32,32}; QRect rectPrev {0,0,32,32}; QRect rectNext {0,0,32,32}; }; #endif //CPHOTOVIEWER_H qmapshack-1.10.0/src/helpers/ILinksDialog.ui000644 001750 000144 00000006272 13135614453 022037 0ustar00oeichlerxusers000000 000000 ILinksDialog 0 0 700 150 Links... Type Text Uri ... :/icons/32x32/Add.png:/icons/32x32/Add.png 32 32 false ... :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png 32 32 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ILinksDialog accept() 248 254 157 274 buttonBox rejected() ILinksDialog reject() 316 260 286 274 qmapshack-1.10.0/src/helpers/CWptIconDialog.cpp000644 001750 000144 00000010623 13216234137 022471 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/WptIcons.h" #include "helpers/CSettings.h" #include "helpers/CWptIconDialog.h" #include "setup/IAppSetup.h" #include static bool keyLessThanAlpha(const QString& s1, const QString& s2) { QRegExp re("[0-9]*"); QString _s1 = s1; QString _s2 = s2; _s1.remove(re); _s2.remove(re); if(_s1 == _s2) { QRegExp re(".*([0-9]*).*"); if(re.exactMatch(s1)) { _s1 = re.cap(1); } else { _s1 = "0"; } if(re.exactMatch(s2)) { _s2 = re.cap(1); } else { _s2 = "0"; } return _s1.toInt() < _s2.toInt(); } return s1 < s2; } CWptIconDialog::CWptIconDialog(QAction *parent) : QDialog(CMainWindow::self().getBestWidgetForParent()) , action(parent) { setupUi(this); setupList(action); setupSignals(); } CWptIconDialog::CWptIconDialog(QToolButton *parent) : QDialog(CMainWindow::self().getBestWidgetForParent()) , button(parent) { setupUi(this); setupList(button); setupSignals(); } CWptIconDialog::CWptIconDialog(CMainWindow * parent) : QDialog(parent) { setupUi(this); setupList(nullptr); setupSignals(); } void CWptIconDialog::setupSignals() { connect(listWidget, &QListWidget::itemClicked, this, &CWptIconDialog::slotItemClicked); connect(listWidget, &QListWidget::itemActivated, this, &CWptIconDialog::slotItemClicked); connect(toolPath, &QToolButton::clicked, this, &CWptIconDialog::slotSetupPath); } void CWptIconDialog::setupList(QObject * obj) { listWidget->clear(); QString currentIcon = obj == nullptr ? QString() : obj->objectName(); QListWidgetItem * currentItem = nullptr; const QMap& wptIcons = getWptIcons(); QStringList keys = wptIcons.keys(); qSort(keys.begin(), keys.end(), keyLessThanAlpha); for(const QString &key : keys) { const QString& icon = wptIcons[key].path; QPixmap pixmap = loadIcon(icon); QListWidgetItem * item = new QListWidgetItem(pixmap, key, listWidget); if(currentIcon == key) { currentItem = item; } } if(currentItem) { listWidget->setCurrentItem(currentItem); listWidget->scrollToItem(currentItem); } SETTINGS; QString path = cfg.value("Paths/externalWptIcons", IAppSetup::getPlatformInstance()->userDataPath("WaypointIcons")).toString(); labelIconPath->setProperty("path", path); labelIconPath->setText(path.size() > 25 ? "..." + path.right(22) : path); labelIconPath->setToolTip(path); adjustSize(); } CWptIconDialog::~CWptIconDialog() { } void CWptIconDialog::slotItemClicked(QListWidgetItem * item) { if(button) { button->setIcon(item->icon()); button->setObjectName(item->text()); button->setToolTip(item->text()); } else if(action) { action->setIcon(item->icon()); action->setObjectName(item->text()); action->setToolTip(item->text()); } accept(); } void CWptIconDialog::slotSetupPath() { QString path = labelIconPath->property("path").toString(); path = QFileDialog::getExistingDirectory(this, tr("Path to user icons..."), path); if(path.isEmpty()) { return; } SETTINGS; cfg.setValue("Paths/externalWptIcons", path); initWptIcons(); setupList(button == nullptr ? dynamic_cast(action) : dynamic_cast(button)); } qmapshack-1.10.0/src/helpers/Platform.h000644 001750 000144 00000034003 13216234142 021106 0ustar00oeichlerxusers000000 000000 /* -*-mode:c++; c-style:k&r; c-basic-offset:4; -*- */ /********************************************************************************************** Copyright (C) 2008 Albrecht Dre This file contains macros for platform-independant access of data stored in little-endian format. 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 . ============================================================= Why does this file exist, and what should hackers do with it? ------------------------------------------------------------- 1. Background Garmin stores data in map files and in their devices in little-endian format. The data is usually packed, i.e. it is not guaranteed that multi-byte data is aligned at 16, 32 or 64 bit boundaries. This is fine as long as you run QLandkarte (or any derived software) on a little-endian machine which accepts accessing unaligned data. The `configure' script in the top-level folder tries to detect if your machine is a little endian (like Intel or ARM) or a big endian (like PowerPC or Sparc). In the latter case, it defines the macro HAVE_BIGENDIAN. In another test, it checks if your machine supports accessing unaligned memory (like Intel or PowerPC) or if such accesses would fail (as on ARM or Sparc). If unaligned accesses are supported, the macro CAN_UNALIGNED will be defined. Of course, the file config.h from the top-level folder has to be included. 2. How to access data To work around these problems, this file defines a number of access macros. On machines which do not need them, they always expand to nothing, but they are *absolutely* necessary on others. So *never* access multi-byte elements without using these macros. 2.1 Load data from Garmin The following rules apply if you want to access data in a source coming from a Garmin device or file: (a) the source is a constant or an aligned 16, 32 or 64-bit value Always use the macro gar_endian(, ) where type may be int16_t, int32_t, int64_t, uint16_t, quint32, uint64_t, float or double. The returned value will explicitly be cast'ed to . (b) the source is an unaligned 16, 32 or 64-bit value Always use the macro gar_load(, ) where type may be int16_t, int32_t, int64_t, uint16_t, quint32, uint64_t, float or double. The returned value will explicitly be cast'ed to . (c) the source is a pointer Always use the macro gar_ptr_load(, ) where type may be int16_t, int32_t, int64_t, uint16_t, quint32, uint64_t, float or double or the special Garmin types int24_t or uint24_t. The returned value will be of type except for the Garmin types int24_t or uint24_t which will be int32_t or quint32, respectively, but have the uppermost 8 bits always set to 0. 2.2 Store data to Garmin (a) the destination is a variable For unaligned variables, use the macro gar_store(, , ) where type may be int16_t, int32_t, int64_t, uint16_t, quint32, uint64_t, float or double. if the variable is aligned, use "destination = gar_endian(type, source)" which is faster. (b) the destination is a pointer For unaligned pointer destinations, use the macro gar_ptr_store(, , ) where type may be int16_t, int32_t, int64_t, uint16_t, quint32, uint64_t, float or double or the special Garmin types int24_t or uint24_t. For a standard type and an aligned pointer destination, use "*(type *)(ptr) = gar_endian(type, source)" which is faster. **********************************************************************************************/ #ifndef __PLATFORM_H__ #define __PLATFORM_H__ // include platform setup (HAVE_BIGENDIAN, CAN_UNALIGNED) #include "config.h" // need integer type definitions with fixed width #ifdef HAVE_INTTYPES_H # include #elif HAVE_STDINT_H # include #elif WIN32 #include typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 quint32; typedef unsigned __int64 uint64_t; #define qIsNaN(x) _isnan(x) #else # error neither inttypes.h nor stdint.h are available #endif #include // -------------------------------------------------------------------------------------------- // macros to fix the endianess of the constant or properly aligned argument x of type t #if !defined(HAVE_BIGENDIAN) // little endian platform: just return the argument #define gar_endian(t, x) (t)(x) #else // big endian platform #define gar_endian(t, x) (__gar_endian_ ## t(x)) // define swapping static inline uint16_t __gar_endian_uint16_t(uint16_t x) { return ((x >> 8) & 0xffu) | ((x & 0xffu) << 8); } static inline quint32 __gar_endian_quint32(quint32 x) { return ((x & 0xff000000u) >> 24) | ((x & 0x00ff0000u) >> 8) | ((x & 0x0000ff00u) << 8) | ((x & 0x000000ffu) << 24); } static inline uint64_t __gar_endian_uint64_t(uint64_t x) { return ((x & 0xff00000000000000ull) >> 56) | ((x & 0x00ff000000000000ull) >> 40) | ((x & 0x0000ff0000000000ull) >> 24) | ((x & 0x000000ff00000000ull) >> 8) | ((x & 0x00000000ff000000ull) << 8) | ((x & 0x0000000000ff0000ull) << 24) | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56); } static inline int16_t __gar_endian_int16_t(int16_t x) { return ((x >> 8) & 0xffu) | ((x & 0xffu) << 8); } static inline int32_t __gar_endian_int32_t(int32_t x) { return ((x & 0xff000000u) >> 24) | ((x & 0x00ff0000u) >> 8) | ((x & 0x0000ff00u) << 8) | ((x & 0x000000ffu) << 24); } static inline int64_t __gar_endian_int64_t(int64_t x) { return ((x & 0xff00000000000000ull) >> 56) | ((x & 0x00ff000000000000ull) >> 40) | ((x & 0x0000ff0000000000ull) >> 24) | ((x & 0x000000ff00000000ull) >> 8) | ((x & 0x00000000ff000000ull) << 8) | ((x & 0x0000000000ff0000ull) << 24) | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56); } static inline float __gar_endian_float(float x) { union { quint32 _u; float _f; } _v; _v._f = x; _v._u = gar_endian(quint32, _v._u); return _v._f; } static inline double __gar_endian_double(double x) { union { uint64_t _u; double _d; } _v; _v._d = x; _v._u = gar_endian(uint64_t, _v._u); return _v._d; } #endif // HAVE_BIGENDIAN // -------------------------------------------------------------------------------------------- // macros to deal with pointers or unaligned arguments // load argument of type t from pointer p #define gar_ptr_load(t, p) __gar_ptr_load_ ## t((const uint8_t *)(p)) // store argument src of type t in in the location to which the pointer p points #define gar_ptr_store(t, p, src) __gar_ptr_store_ ## t((uint8_t *)(p), (src)) #if defined(CAN_UNALIGNED) && !defined(HAVE_BIGENDIAN) // load argument x of type t - noop with proper cast #define gar_load(t, x) (t)(x) // store argument src of type t in the variable dst of type t - just assign #define gar_store(t, dst, src) (dst) = (src) // load from pointer - simply map memory #define __gar_ptr_load_int16_t(p) (*((int16_t *)(p))) #define __gar_ptr_load_int32_t(p) (*((int32_t *)(p))) #define __gar_ptr_load_int64_t(p) (*((int64_t *)(p))) #define __gar_ptr_load_uint16_t(p) (*((uint16_t *)(p))) #define __gar_ptr_load_quint32(p) (*((quint32 *)(p))) #define __gar_ptr_load_uint64_t(p) (*((uint64_t *)(p))) #define __gar_ptr_load_float(p) (*((float *)(p))) #define __gar_ptr_load_double(p) (*((double *)(p))) // special Garmin types - map memory and clear extra bits #define __gar_ptr_load_uint24_t(p) (__gar_ptr_load_quint32(p) & 0x00FFFFFFu) #define __gar_ptr_load_int24_t(p) (__gar_ptr_load_int32_t(p) & 0x00FFFFFFu) // store data to pointer - just assign after a proper cast #define __gar_ptr_store_int16_t(p, src) (*((int16_t *)(p))) = (src) #define __gar_ptr_store_int32_t(p, src) (*((int32_t *)(p))) = (src) #define __gar_ptr_store_int64_t(p, src) (*((int64_t *)(p))) = (src) #define __gar_ptr_store_uint16_t(p, src) (*((uint16_t *)(p))) = (src) #define __gar_ptr_store_quint32(p, src) (*((quint32 *)(p))) = (src) #define __gar_ptr_store_uint64_t(p, src) (*((uint64_t *)(p))) = (src) #define __gar_ptr_store_float(p, src) (*((float *)(p))) = (src) #define __gar_ptr_store_double(p, src) (*((double *)(p))) = (src) // special Garmin types - use memcpy static inline void __gar_ptr_store_int24_t(uint8_t * p, int32_t src) { __gar_ptr_store_uint16_t(p, src & 0xffffu); p[2] = src >> 16; } static inline void __gar_ptr_store_uint24_t(uint8_t * p, quint32 src) { __gar_ptr_store_uint16_t(p, src & 0xffffu); p[2] = src >> 16; } #else // machine is either Big Endian or does not support unaligned accesses // load argument x of type t - call pointer load macro #define gar_load(t, x) gar_ptr_load(t, (uint8_t *)&(x)) // store argument src of type t in the variable dst of type t - call pointer store macro #define gar_store(t, dst, src) gar_ptr_store(t, (uint8_t *)&(dst), src) // load from pointer - read'n'shift bytes // use Byte-Reverse operations for PowerPC static inline uint16_t __gar_ptr_load_uint16_t(const uint8_t *p) { #ifdef __powerpc__ register uint16_t temp; asm __volatile__ ("lhbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); return temp; #else return (uint16_t)(p[0] | (p[1] << 8)); #endif } static inline quint32 __gar_ptr_load_uint24_t(const uint8_t *p) { #ifdef __powerpc__ register quint32 temp; asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); asm __volatile__ ("rlwinm %0,%1,0,8,31" : "=r" (temp) : "r" (temp)); return temp; #else return (quint32)(p[0] | (p[1] << 8) | (p[2] << 16)); #endif } static inline quint32 __gar_ptr_load_quint32(const uint8_t *p) { #ifdef __powerpc__ register quint32 temp; asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); return temp; #else return (quint32)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); #endif } static inline uint64_t __gar_ptr_load_uint64_t(const uint8_t *p) { return (uint64_t)__gar_ptr_load_quint32(p) | ((uint64_t)__gar_ptr_load_quint32(p + 4) << 32); } static inline int16_t __gar_ptr_load_int16_t(const uint8_t *p) { #ifdef __powerpc__ register int16_t temp; asm __volatile__ ("lhbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); return temp; #else return (int16_t)(p[0] | (p[1] << 8)); #endif } static inline int32_t __gar_ptr_load_int24_t(const uint8_t *p) { #ifdef __powerpc__ register int32_t temp; asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); asm __volatile__ ("rlwinm %0,%1,0,8,31" : "=r" (temp) : "r" (temp)); return temp; #else return p[0] | (p[1] << 8) | (p[2] << 16); #endif } static inline int32_t __gar_ptr_load_int32_t(const uint8_t *p) { #ifdef __powerpc__ register int32_t temp; asm __volatile__ ("lwbrx %0,0,%1" : "=r" (temp) : "b" (p), "m" (*p)); return temp; #else return (int32_t)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); #endif } static inline int64_t __gar_ptr_load_int64_t(const uint8_t *p) { return (int64_t)__gar_ptr_load_quint32(p) | ((int64_t)__gar_ptr_load_int32_t(p + 4) << 32); } static inline float __gar_ptr_load_float(const uint8_t * p) { union { quint32 _u; float _f; } _v; _v._u = gar_ptr_load(quint32, p); return _v._f; } static inline double __gar_ptr_load_double(const uint8_t * p) { union { uint64_t _u; double _d; } _v; _v._u = gar_ptr_load(uint64_t, p); return _v._d; } // macros to store data - use memcpy to store data to pointer static inline void __gar_ptr_store_uint16_t(uint8_t *p, uint16_t src) { p[0] = src & 0xffu; p[1] = (src >> 8) & 0xffu; } static inline void __gar_ptr_store_uint24_t(uint8_t *p, quint32 src) { p[0] = src & 0xffu; p[1] = (src >> 8) & 0xffu; p[2] = (src >> 16) & 0xffu; } static inline void __gar_ptr_store_quint32(uint8_t *p, quint32 src) { p[0] = src & 0xffu; p[1] = (src >> 8) & 0xffu; p[2] = (src >> 16) & 0xffu; p[3] = (src >> 24) & 0xffu; } static inline void __gar_ptr_store_uint64_t(uint8_t *p, uint64_t src) { __gar_ptr_store_quint32(p, src & 0xffffffffu); __gar_ptr_store_quint32(p + 4, src >> 32); } #define __gar_ptr_store_int16_t(p, src) __gar_ptr_store_uint16_t(p, (uint16_t)src) #define __gar_ptr_store_int24_t(p, src) __gar_ptr_store_uint24_t(p, (quint32)src) #define __gar_ptr_store_int32_t(p, src) __gar_ptr_store_quint32(p, (quint32)src) #define __gar_ptr_store_int64_t(p, src) __gar_ptr_store_uint64_t(p, (uint64_t)src) static inline void __gar_ptr_store_float(uint8_t *p, float src) { float __fv = gar_endian(float, src); memcpy(p, &__fv, 4); } static inline void __gar_ptr_store_double(uint8_t *p, double src) { double __dv = gar_endian(double, src); memcpy(p, &__dv, 8); } #endif // cannot unaligned or big endian #endif // __PLATFORM_H__ qmapshack-1.10.0/src/helpers/CSelectCopyAction.cpp000644 001750 000144 00000006004 13216234137 023174 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/IGisItem.h" #include "gis/prj/IGisProject.h" #include "helpers/CProgressDialog.h" #include "helpers/CSelectCopyAction.h" #include CSelectCopyAction::CSelectCopyAction(const IGisItem *src, const IGisItem *tar, QWidget *parent) : QDialog(parent) { setupUi(this); labelIcon1->setPixmap(src->getIcon()); labelInfo1->setText(src->getInfo(IGisItem::eFeatureShowName)); labelIcon2->setPixmap(tar->getIcon()); labelInfo2->setText(tar->getInfo(IGisItem::eFeatureShowName)); adjustSize(); connect(pushCopy, &QPushButton::clicked, this, &CSelectCopyAction::slotSelectResult); connect(pushSkip, &QPushButton::clicked, this, &CSelectCopyAction::slotSelectResult); connect(pushClone, &QPushButton::clicked, this, &CSelectCopyAction::slotSelectResult); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelectCopyAction"); CProgressDialog::setAllVisible(false); } CSelectCopyAction::CSelectCopyAction(const IGisProject * src, const IGisProject * tar, QWidget * parent) : QDialog(parent) , result(eResultNone) { setupUi(this); labelIcon1->setPixmap(src->getIcon()); labelInfo1->setText(src->getInfo()); labelIcon2->setPixmap(tar->getIcon()); labelInfo2->setText(tar->getInfo()); pushClone->setEnabled(false); adjustSize(); connect(pushCopy, &QPushButton::clicked, this, &CSelectCopyAction::slotSelectResult); connect(pushSkip, &QPushButton::clicked, this, &CSelectCopyAction::slotSelectResult); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelectCopyAction"); CProgressDialog::setAllVisible(false); } CSelectCopyAction::~CSelectCopyAction() { CCanvas::restoreOverrideCursor("~CSelectCopyAction"); CProgressDialog::setAllVisible(true); } bool CSelectCopyAction::allOthersToo() { return checkAllOtherToo->isChecked(); } void CSelectCopyAction::slotSelectResult() { if(sender() == pushCopy) { result = eResultCopy; } else if(sender() == pushSkip) { result = eResultSkip; } else if(sender() == pushClone) { result = eResultClone; } accept(); } qmapshack-1.10.0/src/helpers/CValue.cpp000644 001750 000144 00000004756 13216234137 021054 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2016 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CSettings.h" #include "helpers/CValue.h" QSet CValue::allValues; CValue::CValue(const QString& cfgTag, const QVariant &initDefault, fMarkChanged markChanged, fValueOnChange onChange) : cfgTag(cfgTag) , initDefault(initDefault) , valUser(initDefault) , funcOnChange(onChange) , funcMarkChanged(markChanged) { if(onChange != nullptr) { onChange(val()); } allValues << this; } CValue::~CValue() { allValues.remove(this); } void CValue::setMode(mode_e m) { bool markAsChanged = mode != m; mode = m; if(funcOnChange != nullptr) { funcOnChange(val()); } if(markAsChanged) { funcMarkChanged(); } } QVariant CValue::val() const { if(mode == eModeUser) { return valUser; } SETTINGS; return cfg.value(cfgTag, initDefault); } const QVariant& CValue::operator=(const QVariant& v) { bool markAsChanged = false; if(mode == eModeUser) { markAsChanged = valUser != v; valUser = v; } else { SETTINGS; cfg.setValue(cfgTag, v); for(CValue * value : allValues) { if(value != this) { value->updateSys(cfgTag, v); } } } if(funcOnChange != nullptr) { funcOnChange(v); } if(markAsChanged) { funcMarkChanged(); } return v; } void CValue::updateSys(const QString& tag, const QVariant &val) { if((mode == eModeSys) && (tag == cfgTag) && (funcOnChange != nullptr)) { funcOnChange(val); } } qmapshack-1.10.0/src/helpers/CDraw.cpp000644 001750 000144 00000015375 13216234261 020672 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "canvas/CCanvas.h" #include "helpers/CDraw.h" #include #include #include #include QPen CDraw::penBorderBlue(QColor(10,10,150,220),2); QPen CDraw::penBorderGray(Qt::lightGray,2); QPen CDraw::penBorderBlack(QColor(0,0,0,200),2); QPen CDraw::penBorderRed(Qt::red,2); QBrush CDraw::brushBackWhite(QColor(255,255,255,255)); QBrush CDraw::brushBackYellow(QColor(0xff, 0xff, 0xcc, 0xE0)); QImage CDraw::createBasicArrow(const QBrush &brush, qreal scale) { QImage arrow(21*scale, 16*scale, QImage::Format_ARGB32); arrow.fill(qRgba(0, 0, 0, 0)); QPainter painter(&arrow); USE_ANTI_ALIASING(painter, true); // white background, same foreground as p painter.setPen(QPen(Qt::white, 2)); painter.setBrush(brush); QPointF arrowPoints[4] = { QPointF(20.0*scale, 7.0*scale), // front QPointF( 0.0*scale, 0.0*scale), // upper tail QPointF( 5.0*scale, 7.0*scale), // mid tail QPointF( 0.0*scale, 15.0*scale) // lower tail }; painter.drawPolygon(arrowPoints, 4); painter.end(); return arrow; } /** @brief Calculates the square distance between two points @return (int) ( (x2 - x1)^2 + (y2 - y1)^2 ) */ static inline int pointDistanceSquare(const QPointF &p1, const QPointF &p2) { return (p2.x() - p1.x()) * (p2.x() - p1.x()) + (p2.y() - p1.y()) * (p2.y() - p1.y()); } void CDraw::arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale) { QImage arrow = createBasicArrow(p.brush(), scale); qreal xoff = qCeil(arrow.width()/2.0); qreal yoff = qFloor((arrow.height()-1)/2.0); const qreal minArrowDistSquare = minArrowDist * minArrowDist; const qreal minPointDistSquare = minPointDist * minPointDist; QPointF prevArrow; bool firstArrow = true; for(int i = 1; i < line.size(); i++) { const QPointF &pt = line[i ]; const QPointF &prevPt = line[i - 1]; // ensure there is enough space between two linepts if( pointDistanceSquare(pt, prevPt) >= minPointDistSquare ) { QPointF arrowPos = prevPt + (pt - prevPt)/2; if( (viewport.contains(pt) || 0 == viewport.height()) // ensure the point is visible && (firstArrow || pointDistanceSquare(prevArrow, arrowPos) >= minArrowDistSquare) ) { p.save(); // rotate and draw the arrow (between bullets) p.translate(arrowPos); qreal direction = ( qAtan2((pt.y() - prevPt.y()), (pt.x() - prevPt.x())) * 180.) / M_PI; p.rotate(direction); p.drawImage(-xoff, -yoff, arrow); p.restore(); prevArrow = arrowPos; firstArrow = false; } } } } void CDraw::text(const QString &str, QPainter &p, const QPoint ¢er, const QColor &color, const QFont &font) { QFontMetrics fm(font); QRect r = fm.boundingRect(str); r.moveCenter(center); p.setFont(font); // draw the white `shadow` p.setPen(Qt::white); p.drawText(r.topLeft() - QPoint(-1, -1), str); p.drawText(r.topLeft() - QPoint( 0, -1), str); p.drawText(r.topLeft() - QPoint(+1, -1), str); p.drawText(r.topLeft() - QPoint(-1, 0), str); p.drawText(r.topLeft() - QPoint(+1, 0), str); p.drawText(r.topLeft() - QPoint(-1, +1), str); p.drawText(r.topLeft() - QPoint( 0, +1), str); p.drawText(r.topLeft() - QPoint(+1, +1), str); p.setPen(color); p.drawText(r.topLeft(), str); } void CDraw::text(const QString &str, QPainter &p, const QRect &r, const QColor &color) { p.setPen(Qt::white); p.setFont(CMainWindow::self().getMapFont()); // draw the white `shadow` p.drawText(r.adjusted(-1, -1, -1, -1), Qt::AlignCenter, str); p.drawText(r.adjusted( 0, -1, 0, -1), Qt::AlignCenter, str); p.drawText(r.adjusted(+1, -1, +1, -1), Qt::AlignCenter, str); p.drawText(r.adjusted(-1, 0, -1, 0), Qt::AlignCenter, str); p.drawText(r.adjusted(+1, 0, +1, 0), Qt::AlignCenter, str); p.drawText(r.adjusted(-1, +1, -1, +1), Qt::AlignCenter, str); p.drawText(r.adjusted( 0, +1, 0, +1), Qt::AlignCenter, str); p.drawText(r.adjusted(+1, +1, +1, +1), Qt::AlignCenter, str); p.setPen(color); p.drawText(r, Qt::AlignCenter, str); } QPoint CDraw::bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth, float pointerBasePos, const QPen &pen) { QPainterPath bubblePath; bubblePath.addRoundedRect(contentRect, RECT_RADIUS, RECT_RADIUS); // draw the arrow int pointerBaseCenterX = (pointerBasePos <= 1) ? contentRect.left() + (pointerBasePos * contentRect.width()) : contentRect.left() + (int) pointerBasePos; int pointerHeight = 0; if(pointerPos.y() < contentRect.top()) { pointerHeight = contentRect.top() - pointerPos.y() + 1; } else if(pointerPos.y() > contentRect.bottom()) { pointerHeight = contentRect.bottom() - pointerPos.y() - 1; } else { qDebug() << "cannot calculate pointerHeight/pointerBaseCenterX due to invalid parameters"; } if(0 != pointerHeight) { QPolygonF pointerPoly; pointerPoly << pointerPos << QPointF(pointerBaseCenterX - pointerBaseWidth / 2, pointerPos.y() + pointerHeight) << QPointF(pointerBaseCenterX + pointerBaseWidth / 2, pointerPos.y() + pointerHeight) << pointerPos; QPainterPath pointerPath; pointerPath.addPolygon(pointerPoly); bubblePath = bubblePath.united(pointerPath); } p.setPen (pen); p.setBrush(CDraw::brushBackWhite); p.drawPolygon(bubblePath.toFillPolygon()); return contentRect.topLeft(); } qmapshack-1.10.0/src/helpers/CInputDialog.cpp000644 001750 000144 00000003215 13216234137 022204 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CInputDialog.h" #include CInputDialog::CInputDialog(QWidget *parent, const QString& text, QVariant& val, const QVariant& reset) : QDialog(parent) , val(val) , reset(reset) { setupUi(this); QPushButton * pushReset = buttonBox->addButton(QDialogButtonBox::Reset); connect(pushReset, &QPushButton::clicked, this, &CInputDialog::slotReset); label->setText(text); if(val != reset) { lineEdit->setText(val.toString()); } } CInputDialog::~CInputDialog() { } void CInputDialog::accept() { if(lineEdit->text().isEmpty()) { val = reset; } else { val.setValue(lineEdit->text()); } QDialog::accept(); } void CInputDialog::slotReset() { lineEdit->clear(); } qmapshack-1.10.0/src/helpers/ISelectProjectDialog.ui000644 001750 000144 00000007731 12556677337 023546 0ustar00oeichlerxusers000000 000000 ISelectProjectDialog 0 0 400 359 Select a project... Select project from list or enter new project name. true New project's name New project is created as: 0 0 true QFrame::NoFrame QFrame::Plain 0 0 0 0 0 true *.qms true *.gpx Database Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISelectProjectDialog accept() 248 254 157 274 buttonBox rejected() ISelectProjectDialog reject() 316 260 286 274 qmapshack-1.10.0/src/helpers/CSelectCopyAction.h000644 001750 000144 00000003225 13216234142 022637 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELECTCOPYACTION_H #define CSELECTCOPYACTION_H #include "ui_ISelectCopyAction.h" #include class IGisItem; class IGisProject; class CSelectCopyAction : public QDialog, private Ui::ISelectCopyAction { Q_OBJECT public: CSelectCopyAction(const IGisItem * src, const IGisItem * tar, QWidget * parent); CSelectCopyAction(const IGisProject * src, const IGisProject * tar, QWidget * parent); virtual ~CSelectCopyAction(); enum result_e { eResultNone, eResultCopy, eResultSkip, eResultClone }; result_e getResult() { return result; } bool allOthersToo(); private slots: void slotSelectResult(); private: result_e result = eResultNone; }; #endif //CSELECTCOPYACTION_H qmapshack-1.10.0/src/helpers/CFileExt.h000644 001750 000144 00000003423 13216234142 020767 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILEEXT_H #define CFILEEXT_H #include #include class CFileExt : public QFile { public: CFileExt(const QString &filename) : QFile(filename) , mapped(nullptr) { cnt++; } ~CFileExt() { cnt--; } #ifndef Q_OS_WIN32 // data access function const char *data(qint64 offset, qint64 s) { mapped = map(offset, s); mappedSections << mapped; return (const char*)mapped; } void free() { for(uchar * p : mappedSections) { unmap(p); } mappedSections.clear(); } #else // data access function const char *data(qint64 offset, qint64 s) { uchar * p = map(offset,s); return (const char *)p; } #endif private: static int cnt; uchar *mapped; QSet mappedSections; }; #endif //CFILEEXT_H qmapshack-1.10.0/src/helpers/CDraw.h000644 001750 000144 00000007612 13216234261 020332 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CPAINTER_H #define CPAINTER_H #include #include #include #include "CMainWindow.h" inline void USE_ANTI_ALIASING(QPainter& p, bool useAntiAliasing) { p.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing|QPainter::SmoothPixmapTransform|QPainter::HighQualityAntialiasing, useAntiAliasing); } #define RECT_RADIUS 3 #define PAINT_ROUNDED_RECT(p,r) p.drawRoundedRect(r,RECT_RADIUS,RECT_RADIUS) class CDraw { public: static QPen penBorderBlue; static QPen penBorderGray; static QPen penBorderBlack; static QPen penBorderRed; static QBrush brushBackWhite; static QBrush brushBackYellow; /** @brief Draw arrows along a line An arrow is drawn if all the following requirements are met: * the position the new arrow would have been drawn is within viewport OR `viewport.height() == 0` * the two points have a distance of at least `minPointDist` * the (potential) position of the new arrow has at least a distance of `minArrowDist` from the previous arrow @param line The line to draw the arrows along @param viewport Restrict drawing of arrows to this viewport (no limitation is applied if `viewport.height() == 0`) @param minPointDist The minimum distance of two points (in px) @param minArrowDist The minimum distance of two consecutive arrows (in px) */ static void arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale); static void text(const QString& str, QPainter &p, const QPoint ¢er, const QColor &color, const QFont &font = CMainWindow::self().getMapFont()); static void text(const QString& str, QPainter &p, const QRect &r, const QColor &color); /** @brief Draw a cartoon bubble `pointerBasePos` denotes the position of the pointer's base, where 0 is `at the very left of the content`, and 1 is `at the very right`. Be careful with small values (near 0) or large values (near 1) for pointerBasePos, this might lead to incorrect drawing, especially if pointerBaseWidth is large. If is larger than 1, a value in pixels is assumed. @param p An active QPainter @param contentRect The area the actual content will be in @param pointerPos The position of the pointer's head @param pointerBaseWidth The width of the pointer @param pointerBasePos The (relative) location of the pointer (in percent / pixels) */ static QPoint bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth = 20, float pointerBasePos = .5f, const QPen& pen = penBorderGray); private: /** @brief Creates a new arrow using the brush specified @return A QImage containing the arrow */ static QImage createBasicArrow(const QBrush &brush, qreal scale); }; #endif // CPAINTER_H qmapshack-1.10.0/src/helpers/CProgressDialog.h000644 001750 000144 00000003605 13216234142 022355 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPROGRESSDIALOG_H #define CPROGRESSDIALOG_H #include "ui_IProgressDialog.h" #include #include #include class QTimer; #define PROGRESS_SETUP(lbl, min, max, parent) \ CProgressDialog progress(lbl, min, max, parent); #define PROGRESS(x, cmd) \ progress.setValue(x); \ if (progress.wasCanceled()) { cmd; } \ class CProgressDialog : public QDialog, private Ui::IProgressDialog { Q_OBJECT public: CProgressDialog(const QString text, int min, int max, QWidget * parent); virtual ~CProgressDialog(); static CProgressDialog * self(); static void setAllVisible(bool yes); void setValue(int val); bool wasCanceled(); void enableCancel(bool yes); public slots: void reject() override; protected: void showEvent(QShowEvent *) override; private: void pause(); void goOn(); static QStack stackSelf; QTime time; QTimer * timer; qint32 timeElapsed = 0; }; #endif //CPROGRESSDIALOG_H qmapshack-1.10.0/src/helpers/CValue.h000644 001750 000144 00000003652 13216234142 020507 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CVALUE_H #define CVALUE_H #include #include #include using fMarkChanged = std::function; using fValueOnChange = std::function; class CValue { public: CValue(const QString& cfgTag, const QVariant& initDefault, fMarkChanged markChanged, fValueOnChange onChange = nullptr); virtual ~CValue(); enum mode_e { eModeSys , eModeUser }; void setMode(mode_e m); mode_e getMode() const { return mode; } QVariant val() const; const QVariant& operator=(const QVariant& v); private: friend QDataStream& operator<<(QDataStream& stream, const CValue& v); friend QDataStream& operator>>(QDataStream& stream, CValue& v); void updateSys(const QString &tag, const QVariant& val); mode_e mode = eModeSys; QString cfgTag; QVariant initDefault; QVariant valUser; fValueOnChange funcOnChange; fMarkChanged funcMarkChanged; static QSet allValues; }; #endif //CVALUE_H qmapshack-1.10.0/src/helpers/CElevationDialog.cpp000644 001750 000144 00000005075 13216234137 023041 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CElevationDialog.h" #include "units/IUnit.h" #include #include CElevationDialog::CElevationDialog(QWidget * parent, QVariant &val, const QVariant &reset, const QPointF &pos) : QDialog(parent) , val(val) , reset(reset) , pos(pos) { setupUi(this); QPushButton * pushReset = buttonBox->addButton(QDialogButtonBox::Reset); connect(pushReset, &QPushButton::clicked, this, &CElevationDialog::slotReset); connect(toolGetEle, &QToolButton::clicked, this, &CElevationDialog::slotGetEle); QString str, unit; IUnit::self().meter2elevation(100, str, unit); labelUnit->setText(unit); if(val != NOINT) { IUnit::self().meter2elevation(val.toDouble(), str, unit); lineValue->setText(str); } } CElevationDialog::~CElevationDialog() { } void CElevationDialog::accept() { if(lineValue->text().isEmpty()) { val = reset; } else { val.setValue(lineValue->text().toDouble() / IUnit::self().basefactor); } QDialog::accept(); } void CElevationDialog::slotReset() { if(reset == NOINT) { lineValue->clear(); } else { QString str, unit; IUnit::self().meter2elevation(val.toDouble(), str, unit); lineValue->setText(str); } } void CElevationDialog::slotGetEle() { QVariant ele = CMainWindow::self().getElevationAt(pos * DEG_TO_RAD); if(ele != NOFLOAT) { QString str, unit; IUnit::self().meter2elevation(ele.toDouble(), str, unit); lineValue->setText(str); } else { labelMessage->setText(tr("No DEM data found for that point.")); } } qmapshack-1.10.0/src/helpers/IProgressDialog.ui000644 001750 000144 00000003551 12560352624 022560 0ustar00oeichlerxusers000000 000000 IProgressDialog 0 0 400 107 Please wait... TextLabel TextLabel 24 Qt::Horizontal QDialogButtonBox::Cancel buttonBox accepted() IProgressDialog accept() 248 254 157 274 buttonBox rejected() IProgressDialog reject() 316 260 286 274 qmapshack-1.10.0/src/helpers/Signals.h000644 001750 000144 00000002573 13216234142 020731 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef SIGNALS_H #define SIGNALS_H #include #include inline void X______________BlockAllSignals______________X(QObject * parent) { for(QObject * obj : parent->findChildren(QRegExp(".*"))) { obj->blockSignals(true); } } inline void X_____________UnBlockAllSignals_____________X(QObject * parent) { for(QObject * obj : parent->findChildren(QRegExp(".*"))) { obj->blockSignals(false); } } #endif //SIGNALS_H qmapshack-1.10.0/src/helpers/CPositionDialog.h000644 001750 000144 00000002621 13216234142 022352 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPOSITIONDIALOG_H #define CPOSITIONDIALOG_H #include "ui_IPositionDialog.h" #include class QPointF; class CPositionDialog : public QDialog, private Ui::IPositionDialog { Q_OBJECT public: CPositionDialog(QWidget * parent, QPointF &pos); virtual ~CPositionDialog(); static bool getPosition(QPointF& pt, const QString &str); public slots: void accept() override; private slots: void slotEdit(const QString& str); private: QPointF& pos; }; #endif //CPOSITIONDIALOG_H qmapshack-1.10.0/src/helpers/CWptIconDialog.h000644 001750 000144 00000003071 13216234142 022131 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CWPTICONDIALOG_H #define CWPTICONDIALOG_H #include "ui_IWptIconDialog.h" #include class QToolButton; class QAction; class QListWidgetItem; class CMainWindow; class CWptIconDialog : public QDialog, private Ui::IWptIconDialog { Q_OBJECT public: CWptIconDialog(QToolButton * parent); CWptIconDialog(QAction * parent); CWptIconDialog(CMainWindow * parent); virtual ~CWptIconDialog(); private slots: void slotItemClicked(QListWidgetItem * item); void slotSetupPath(); private: void setupList(QObject *obj); void setupSignals(); QToolButton * button = nullptr; QAction * action = nullptr; }; #endif //CWPTICONDIALOG_H qmapshack-1.10.0/src/helpers/CInputDialog.h000644 001750 000144 00000002532 13216234142 021646 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CINPUTDIALOG_H #define CINPUTDIALOG_H #include "ui_IInputDialog.h" #include class CInputDialog : public QDialog, private Ui::IInputDialog { Q_OBJECT public: CInputDialog(QWidget * parent, const QString &text, QVariant &val, const QVariant &reset); virtual ~CInputDialog(); public slots: void accept() override; private slots: void slotReset(); private: QVariant& val; QVariant reset; }; #endif //CINPUTDIALOG_H qmapshack-1.10.0/src/helpers/IPositionDialog.ui000644 001750 000144 00000004411 12374350216 022552 0ustar00oeichlerxusers000000 000000 IPositionDialog 0 0 400 189 Position ... Enter new position Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" true Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IPositionDialog accept() 248 254 157 274 buttonBox rejected() IPositionDialog reject() 316 260 286 274 qmapshack-1.10.0/src/helpers/CLimit.h000644 001750 000144 00000005015 13216234142 020504 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLIMIT_H #define CLIMIT_H #include #include #include #include #include #include "units/IUnit.h" using fGetLimit = std::function; using fGetUnit = std::function; using fMarkChanged = std::function; class CLimit : public QObject { Q_OBJECT public: CLimit(const QString& cfgPath, fGetLimit getMin, fGetLimit getMax, fGetLimit getMinAuto, fGetLimit getMaxAuto, fGetUnit getUnit, fMarkChanged markChanged); virtual ~CLimit(); enum mode_e { eModeSys , eModeUser , eModeAuto }; void setMode(mode_e m); void setSource(const QString& src); const QString& getSource() const { return source; } mode_e getMode() const { return mode; } qreal getMin() const; qreal getMax() const; QString getUnit() const; public slots: void setMin(const qreal& val); void setMax(const qreal& val); signals: void sigChanged(); private: friend class CGisItemTrk; friend QDataStream& operator<<(QDataStream& stream, const CLimit& l); friend QDataStream& operator>>(QDataStream& stream, CLimit& l); void updateSys(); void updateSys(const QString& src); mode_e mode = eModeAuto; QString cfgPath; qreal minUser = NOFLOAT; qreal maxUser = NOFLOAT; fGetLimit funcGetMin; fGetLimit funcGetMax; fGetLimit funcGetMinAuto; fGetLimit funcGetMaxAuto; fGetUnit funcGetUnit; fMarkChanged funcMarkChanged; QString source; static QSet allLimits; }; #endif //CLIMIT_H qmapshack-1.10.0/src/helpers/IWptIconDialog.ui000644 001750 000144 00000005145 13135614453 022340 0ustar00oeichlerxusers000000 000000 IWptIconDialog 0 0 400 300 Icons... 3 3 3 3 3 22 22 3 0 0 0 0 0 0 External Icons: - ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png All custom icons have to be *.bmp or *.png format. qmapshack-1.10.0/src/helpers/CToolBarConfig.cpp000644 001750 000144 00000006332 13216234137 022460 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #include "CSettings.h" #include "helpers/CToolBarConfig.h" #include #include CToolBarConfig::CToolBarConfig(QObject * const & parent, QToolBar * const & toolBar, const QList & availableActions, const QList & defaultActions) : QObject(parent), toolBar(toolBar), available(availableActions), defaultActions(defaultActions) { } CToolBarConfig::~CToolBarConfig() { } void CToolBarConfig::loadSettings() { SETTINGS; QStringList actions = cfg.value("ToolBar/actions").toStringList(); if (actions.isEmpty()) { setDefaultConfiguredActions(); } else { setConfiguredActionsByName(actions); } fullscreen = cfg.value("ToolBar/fullscreen",false).toBool(); } void CToolBarConfig::saveSettings() const { SETTINGS; QStringList configuredNames; for (QAction * const & action : configuredActions()) { configuredNames << action->objectName(); } cfg.setValue("ToolBar/actions",configuredNames); cfg.setValue("ToolBar/fullscreen",fullscreen); } const QList & CToolBarConfig::availableActions() const { return available; } const QList & CToolBarConfig::configuredActions() const { return configured; } void CToolBarConfig::setConfiguredActionsByName(const QStringList & names) { QList actions; for (const QString & name : names) { for (QAction * const & action : available) { if (action->objectName() == name) { if (action->isSeparator()) { QAction * separator = new QAction(this); separator->setObjectName("separator"); separator->setSeparator(true); actions << separator; } else { actions << action; } break; } } } setConfiguredActions(actions); } void CToolBarConfig::setDefaultConfiguredActions() { setConfiguredActions(defaultActions); } void CToolBarConfig::setConfiguredActions(const QList & actions) { configured.clear(); configured << actions; toolBar->clear(); toolBar->addActions(actions); } qmapshack-1.10.0/src/helpers/CToolBarSetupDialog.h000644 001750 000144 00000004337 13216234142 023137 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #ifndef CTOOLBARSETUPDIALOG_H #define CTOOLBARSETUPDIALOG_H #include "ui_IToolBarSetupDialog.h" class CToolBarConfig; class CToolBarSetupDialog : public QDialog, private Ui::IToolBarSetupDialog { Q_OBJECT public: CToolBarSetupDialog(QWidget * const &parent, CToolBarConfig * const &config); virtual ~CToolBarSetupDialog(); public slots: void accept() override; void slotButtonClicked(QAbstractButton * button) const; private: class CDialogItem : public QListWidgetItem { public: CDialogItem(QIcon icon, QString text, QString name) : QListWidgetItem(icon, text, nullptr, QListWidgetItem::UserType), actionName(name) {} ~CDialogItem() override {} QListWidgetItem * clone() const override { return new CDialogItem(this->icon(),this->text(),this->actionName); } private: const QString actionName; friend class CToolBarSetupDialog; }; class CItemFilter : public QObject, public CSelectDoubleListWidget::IItemFilter { public: CItemFilter(QObject *parent) : QObject(parent) {} ~CItemFilter() override {} bool shouldBeMoved(QListWidgetItem *item) override; }; void configure() const; CToolBarConfig * config; }; #endif //CTOOLBARSETUPDIALOG_H qmapshack-1.10.0/src/helpers/CLinksDialog.cpp000644 001750 000144 00000005134 13216234137 022167 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CLinksDialog.h" #include CLinksDialog::CLinksDialog(QList &links, QWidget *parent) : QDialog(parent) , links(links) { setupUi(this); connect(toolAdd, &QToolButton::clicked, this, &CLinksDialog::slotAddLink); connect(toolDelete, &QToolButton::clicked, this, &CLinksDialog::slotDelLink); connect(treeWidget, &QTreeWidget::itemSelectionChanged, this, &CLinksDialog::slotItemSelectionChanged); for(const IGisItem::link_t& link : links) { QTreeWidgetItem * item = new QTreeWidgetItem(treeWidget); item->setText(0, link.type); item->setText(1, link.text); item->setText(2, link.uri.toString()); item->setFlags(item->flags()|Qt::ItemIsEditable); } } CLinksDialog::~CLinksDialog() { } void CLinksDialog::slotItemSelectionChanged() { QList items = treeWidget->selectedItems(); toolDelete->setEnabled(!items.isEmpty()); } void CLinksDialog::slotAddLink() { QTreeWidgetItem * item = new QTreeWidgetItem(treeWidget); item->setText(0, ""); item->setText(1, "enter a text"); item->setText(2, "enter a link"); item->setFlags(item->flags()|Qt::ItemIsEditable); } void CLinksDialog::slotDelLink() { QList items = treeWidget->selectedItems(); qDeleteAll(items); } void CLinksDialog::accept() { links.clear(); for(int i = 0; i < treeWidget->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWidget->topLevelItem(i); IGisItem::link_t link; link.type = item->text(0); link.text = item->text(1); link.uri = item->text(2); links << link; } QDialog::accept(); } qmapshack-1.10.0/src/helpers/CSelectProjectDialog.cpp000644 001750 000144 00000013115 13216234137 023653 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisListWks.h" #include "helpers/CSelectProjectDialog.h" #include "helpers/CSettings.h" #include QString CSelectProjectDialog::lastkey; CSelectProjectDialog::CSelectProjectDialog(QString &key, QString &name, IGisProject::type_e &type, QTreeWidget * parent) : QDialog(CMainWindow::getBestWidgetForParent()) , key(key) , name(name) , type(type) { setupUi(this); QListWidgetItem *lastSelectedItem = nullptr; if(parent) { for(int i = 0; i < parent->topLevelItemCount(); i++) { IGisProject * project = dynamic_cast(parent->topLevelItem(i)); if(nullptr == project) { continue; } QListWidgetItem * item = new QListWidgetItem(project->icon(CGisListWks::eColumnIcon), project->text(CGisListWks::eColumnName),listWidget); item->setData(Qt::UserRole+0, project->getKey()); item->setData(Qt::UserRole+1, project->getType()); item->setData(Qt::UserRole+2, project->getName()); if(project->getKey() == lastkey) { lastSelectedItem = item; type = project->getType(); } } } else { listWidget->hide(); label1->hide(); } frameType->setEnabled(listWidget->count() == 0); if(nullptr == lastSelectedItem) { SETTINGS; QString filter = cfg.value("Paths/lastGisFilter", "GPS Exchange Format (*.qms)").toString(); if(filter.contains("gpx")) { type = IGisProject::eTypeGpx; } else { type = IGisProject::eTypeQms; } buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } else { slotItemClicked(lastSelectedItem); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } setType(type); connect(listWidget, &QListWidget::itemClicked, this, &CSelectProjectDialog::slotItemClicked); connect(listWidget, &QListWidget::itemDoubleClicked, this, &CSelectProjectDialog::slotItemDoubleClicked); connect(lineEdit, &QLineEdit::textChanged, this, &CSelectProjectDialog::slotProjectChanged); connect(lineEdit, &QLineEdit::textEdited, this, &CSelectProjectDialog::slotProjectEdited); connect(radioQms, &QRadioButton::clicked, this, &CSelectProjectDialog::slotTypeChanged); connect(radioGpx, &QRadioButton::clicked, this, &CSelectProjectDialog::slotTypeChanged); connect(radioDatabase, &QRadioButton::toggled, this, &CSelectProjectDialog::slotTypeChanged); lineEdit->setFocus(); adjustSize(); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelectProjectDialog"); } CSelectProjectDialog::~CSelectProjectDialog() { CCanvas::restoreOverrideCursor("~CSelectProjectDialog"); } void CSelectProjectDialog::accept() { lastkey = key; QDialog::accept(); } void CSelectProjectDialog::reject() { key.clear(); name.clear(); QDialog::reject(); } void CSelectProjectDialog::slotItemClicked(QListWidgetItem * item) { lineEdit->setText(item->data(Qt::UserRole+2).toString()); key = item->data(Qt::UserRole).toString(); type = IGisProject::type_e(item->data(Qt::UserRole+1).toInt()); setType(type); frameType->setEnabled(false); } void CSelectProjectDialog::slotItemDoubleClicked(QListWidgetItem * item) { lineEdit->setText(item->data(Qt::UserRole+2).toString()); key = item->data(Qt::UserRole).toString(); type = IGisProject::type_e(item->data(Qt::UserRole+1).toInt()); QDialog::accept(); } void CSelectProjectDialog::slotProjectChanged(const QString& text) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); name = text; } void CSelectProjectDialog::slotProjectEdited(const QString& text) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); key.clear(); name = text; frameType->setEnabled(true); } void CSelectProjectDialog::slotTypeChanged() { if(radioQms->isChecked()) { type = IGisProject::eTypeQms; } else if(radioGpx->isChecked()) { type = IGisProject::eTypeGpx; } else if(radioDatabase->isChecked()) { type = IGisProject::eTypeDb; } } void CSelectProjectDialog::setType(IGisProject::type_e& t) { switch(type) { case IGisProject::eTypeGpx: radioGpx->setChecked(true); break; case IGisProject::eTypeDb: radioDatabase->setChecked(true); break; default: radioQms->setChecked(true); t = IGisProject::eTypeQms; break; } } qmapshack-1.10.0/src/helpers/CSelectProjectDialog.h000644 001750 000144 00000003443 13216234142 023317 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELECTPROJECTDIALOG_H #define CSELECTPROJECTDIALOG_H #include "gis/prj/IGisProject.h" #include "ui_ISelectProjectDialog.h" #include class QTreeWidget; class CSelectProjectDialog : public QDialog, private Ui::ISelectProjectDialog { Q_OBJECT public: CSelectProjectDialog(QString& key, QString& name, IGisProject::type_e& type, QTreeWidget *parent); virtual ~CSelectProjectDialog(); public slots: void accept() override; void reject() override; private slots: void slotItemClicked(QListWidgetItem * item); void slotItemDoubleClicked(QListWidgetItem * item); void slotProjectChanged(const QString& text); void slotProjectEdited(const QString& text); void slotTypeChanged(); private: void setType(IGisProject::type_e& t); static QString lastkey; QString& key; QString& name; IGisProject::type_e& type; }; #endif //CSELECTPROJECTDIALOG_H qmapshack-1.10.0/src/helpers/CToolBarSetupDialog.cpp000644 001750 000144 00000007240 13216234137 023472 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #include "helpers/CToolBarConfig.h" #include "helpers/CToolBarSetupDialog.h" bool CToolBarSetupDialog::CItemFilter::shouldBeMoved(QListWidgetItem *item) { CDialogItem * dialogItem = dynamic_cast(item); if (dialogItem != nullptr) { return dialogItem->actionName != "separator"; } return true; } CToolBarSetupDialog::CToolBarSetupDialog(QWidget * const & parent, CToolBarConfig * const & config) : QDialog(parent), config(config) { setupUi(this); selectActionsWidget->setFilter(new CItemFilter(this)); connect(buttonBox, &QDialogButtonBox::clicked, this, &CToolBarSetupDialog::slotButtonClicked); configure(); selectActionsWidget->setLabelAvailable(tr("Available Actions")); selectActionsWidget->setLabelSelected(tr("Selected Actions")); } CToolBarSetupDialog::~CToolBarSetupDialog() { selectActionsWidget->clear(); } void CToolBarSetupDialog::accept() { QStringList actionNames; for (const QListWidgetItem * const selectedItem : selectActionsWidget->selected()) { const CDialogItem * const setupDialogItem = dynamic_cast(selectedItem); if (setupDialogItem != nullptr) { actionNames << setupDialogItem->actionName; } } config->setConfiguredActionsByName(actionNames); config->setVisibleInFullscreen(checkFullscreen->isChecked()); QDialog::accept(); } void CToolBarSetupDialog::slotButtonClicked(QAbstractButton *button) const { if(buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { config->setDefaultConfiguredActions(); configure(); } } void CToolBarSetupDialog::configure() const { QList availableItems; QList selectedItems; for(QAction * const & action : config->availableActions()) { availableItems << new CDialogItem(action->icon(),action->iconText(),action->objectName()); } for(QAction * const & action : config->configuredActions()) { if (action->isSeparator()) { selectedItems << new CDialogItem(action->icon(),"---------------",action->objectName()); } else { QString configuredName = action->objectName(); for(QListWidgetItem * const & item : availableItems) { if(configuredName == dynamic_cast(item)->actionName) { selectedItems << item; break; } } } } selectActionsWidget->setSelected(selectedItems); selectActionsWidget->setAvailable(availableItems); checkFullscreen->setChecked(config->visibleInFullscreen()); } qmapshack-1.10.0/src/helpers/CProgressDialog.cpp000644 001750 000144 00000006752 13216234137 022722 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "helpers/CProgressDialog.h" #include "units/IUnit.h" #include QStack CProgressDialog::stackSelf; #define DELAY 1000 CProgressDialog::CProgressDialog(const QString text, int min, int max, QWidget *parent) : QDialog(parent) { if(!stackSelf.isEmpty()) { stackSelf.top()->pause(); } stackSelf.push(this); setupUi(this); setWindowModality(Qt::WindowModal); label->setText(text); progressBar->setMinimum(min); progressBar->setMaximum(max); progressBar->setValue(0); time.start(); labelTime->setText(tr("Elapsed time: %1").arg(time.elapsed()/1000)); if(max == NOINT) { progressBar->hide(); // add a timer to update the elapsed time QTimer * t = new QTimer(this); t->start(DELAY); connect(t, &QTimer::timeout, this, [this] {setValue(0); }); } QDialog::hide(); timer = new QTimer(this); timer->setSingleShot(true); connect(timer, &QTimer::timeout, this, [this] {show(); }); timer->start(DELAY); } CProgressDialog * CProgressDialog::self() { if(stackSelf.isEmpty()) { return nullptr; } return stackSelf.top(); } CProgressDialog::~CProgressDialog() { stackSelf.pop(); if(!stackSelf.isEmpty()) { stackSelf.top()->goOn(); } } void CProgressDialog::pause() { hide(); timer->stop(); timeElapsed = time.elapsed(); } void CProgressDialog::goOn() { if(timeElapsed <= DELAY) { timer->start(DELAY - timeElapsed); } else { show(); } } void CProgressDialog::setAllVisible(bool yes) { if(stackSelf.isEmpty()) { return; } yes ? stackSelf.top()->goOn() : stackSelf.top()->pause(); } void CProgressDialog::enableCancel(bool yes) { buttonBox->setEnabled(yes); } void CProgressDialog::reject() { setResult(QMessageBox::Abort); emit rejected(); } void CProgressDialog::setValue(int val) { if(time.elapsed() > DELAY) { QApplication::processEvents(); } progressBar->setValue(val); labelTime->setText(tr("Elapsed time: %1 seconds.").arg(time.elapsed()/1000.0, 0,'f',0)); } bool CProgressDialog::wasCanceled() { return result() == QMessageBox::Abort; } void CProgressDialog::showEvent(QShowEvent *) { // that is a workaround for canvas loosing mousetracking caused by CProgressDialog being modal: CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if (canvas != nullptr) { canvas->mouseTrackingLost(); } } qmapshack-1.10.0/src/helpers/CLinksDialog.h000644 001750 000144 00000002626 13216234142 021633 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLINKSDIALOG_H #define CLINKSDIALOG_H #include "gis/IGisItem.h" #include "ui_ILinksDialog.h" #include class CLinksDialog : public QDialog, private Ui::ILinksDialog { Q_OBJECT public: CLinksDialog(QList& links, QWidget * parent); virtual ~CLinksDialog(); public slots: void accept() override; private slots: void slotAddLink(); void slotDelLink(); void slotItemSelectionChanged(); private: QList& links; }; #endif //CLINKSDIALOG_H qmapshack-1.10.0/src/helpers/CLimit.cpp000644 001750 000144 00000010014 13216234137 021036 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2016 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CLimit.h" #include "helpers/CSettings.h" QSet CLimit::allLimits; CLimit::CLimit(const QString &cfgPath, fGetLimit getMin, fGetLimit getMax, fGetLimit getMinAuto, fGetLimit getMaxAuto, fGetUnit getUnit, fMarkChanged markChanged) : cfgPath(cfgPath) , funcGetMin(getMin) , funcGetMax(getMax) , funcGetMinAuto(getMinAuto) , funcGetMaxAuto(getMaxAuto) , funcGetUnit(getUnit) , funcMarkChanged(markChanged) { allLimits << this; } CLimit::~CLimit() { allLimits.remove(this); } void CLimit::setMode(mode_e m) { bool markAsChanged = mode != m; mode = m; if(markAsChanged) { funcMarkChanged(); } emit sigChanged(); } void CLimit::setSource(const QString& src) { bool isInitial = source.isEmpty(); if(source != src) { source = src; minUser = funcGetMin(source); maxUser = funcGetMax(source); if(!isInitial) { funcMarkChanged(); } } } qreal CLimit::getMin() const { SETTINGS; qreal val = NOFLOAT; switch(mode) { case eModeUser: val = minUser; break; case eModeAuto: val = funcGetMinAuto(source); break; case eModeSys: cfg.beginGroup(cfgPath); val = cfg.value(source + "/min", funcGetMin(source)).toReal(); cfg.endGroup(); break; } return val; } qreal CLimit::getMax() const { SETTINGS; qreal val = NOFLOAT; switch(mode) { case eModeUser: val = maxUser; break; case eModeAuto: val = funcGetMaxAuto(source); break; case eModeSys: cfg.beginGroup(cfgPath); val = cfg.value(source + "/max", funcGetMax(source)).toReal(); cfg.endGroup(); break; } return val; } void CLimit::setMin(const qreal &val) { SETTINGS; switch(mode) { case eModeUser: { bool markAsChanged = (minUser != NOFLOAT) && (minUser != val); minUser = val; if(markAsChanged) { funcMarkChanged(); } break; } case eModeSys: { cfg.beginGroup(cfgPath); cfg.setValue(source + "/min", val); cfg.endGroup(); updateSys(); break; } } emit sigChanged(); } void CLimit::setMax(const qreal &val) { SETTINGS; switch(mode) { case eModeUser: { bool markAsChanged = (maxUser == NOFLOAT) && (maxUser != val); maxUser = val; if(markAsChanged) { funcMarkChanged(); } break; } case eModeSys: { cfg.beginGroup(cfgPath); cfg.setValue(source + "/max", val); cfg.endGroup(); updateSys(); break; } } emit sigChanged(); } QString CLimit::getUnit() const { return funcGetUnit(source); } void CLimit::updateSys() { for(CLimit * limit : allLimits) { if(limit != this) { limit->updateSys(source); } } } void CLimit::updateSys(const QString& src) { if((mode == eModeSys) && (source == src)) { emit sigChanged(); } } qmapshack-1.10.0/src/helpers/ISelectCopyAction.ui000644 001750 000144 00000010577 12705713523 023052 0ustar00oeichlerxusers000000 000000 ISelectCopyAction 0 0 471 251 Copy item... QFormLayout::ExpandingFieldsGrow 0 0 Replace existing item TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Horizontal 0 0 Do not copy item TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Horizontal 0 0 Create a clone Replace with: Keep item: The clone's name will be appended with '_Clone' true Qt::Horizontal And for all other items, too. qmapshack-1.10.0/src/helpers/CToolBarConfig.h000644 001750 000144 00000004007 13216234142 022116 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #ifndef CTOOLBARCONFIG_H #define CTOOLBARCONFIG_H #include class T; template <> class QList; class QAction; class QToolBar; class CToolBarConfig : public QObject { Q_OBJECT public: CToolBarConfig(QObject * const & parent, QToolBar * const & toolBar, const QList & availableActions, const QList & defaultActions); virtual ~CToolBarConfig(); void loadSettings(); void saveSettings() const; const QList & availableActions() const; const QList & configuredActions() const; void setConfiguredActionsByName(const QStringList & actions); void setConfiguredActions(const QList & actions); void setDefaultConfiguredActions(); void setVisibleInFullscreen(bool visible) { fullscreen = visible; } bool visibleInFullscreen() { return fullscreen; } private: QToolBar * const toolBar; const QList available; const QList defaultActions; QList configured; bool fullscreen = false; }; #endif //CTOOLBARCONFIG_H qmapshack-1.10.0/src/helpers/IInputDialog.ui000644 001750 000144 00000003571 12374350216 022053 0ustar00oeichlerxusers000000 000000 IInputDialog 0 0 294 100 Edit... TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IInputDialog accept() 248 254 157 274 buttonBox rejected() IInputDialog reject() 316 260 286 274 qmapshack-1.10.0/src/CMakeLists.txt000644 001750 000144 00000062173 13216421072 020260 0ustar00oeichlerxusers000000 000000 # Prevent custom commands/targets outputs to be deleted by make clean # We need this to prevent .ts files from being deleted with make clean, when # UPDATE_TRANSLATIONS=ON # WARNING: Only works with Makefile generator. # See: https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=15c454fe set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE) # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) option(BUILD_FOR_LOCAL_SYSTEM "Build for local system ONLY (resulting binary might not work on other systems!)" OFF) if(BUILD_FOR_LOCAL_SYSTEM) set(flag "-march=native") CHECK_CXX_COMPILER_FLAG(${flag} Flag:${flag}) if(Flag:${flag}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) message(WARNING [=[ BUILDING FOR LOCAL SYSTEM ONLY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Specifying -DBUILD_FOR_LOCAL_SYSTEM=ON will pass -march=native to the compiler. The generated binary will exhibit higher performance, but will not be portable (e.g., might not work on other CPUs)]=]) else(Flag:${flag}) message(WARNING [=[ Your compiler does not support -march=native. Ignoring -DBUILD_FOR_LOCAL_SYSTEM=ON!]=]) endif(Flag:${flag}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif(BUILD_FOR_LOCAL_SYSTEM) # Find the QtWidgets library find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) find_package(Qt5Xml REQUIRED) find_package(Qt5Script REQUIRED) find_package(Qt5Sql REQUIRED) find_package(Qt5WebKitWidgets REQUIRED) find_package(Qt5LinguistTools REQUIRED) find_package(Qt5PrintSupport REQUIRED) find_package(Qt5UiTools REQUIRED) find_package(GDAL REQUIRED) find_package(PROJ REQUIRED) find_package(ROUTINO REQUIRED) find_package(QuaZip REQUIRED) if(USE_QT5DBus) find_package(Qt5DBus REQUIRED) if(Qt5DBus_FOUND) add_definitions(-DHAVE_DBUS) endif(Qt5DBus_FOUND) endif(USE_QT5DBus) if(${Qt5Widgets_VERSION} MATCHES "5\\.[0-2]{1}\\..*") message( SEND_ERROR "You need at least Qt5.3 or newer.") endif() function(cxx_add_flag_if_supported flag) CHECK_CXX_COMPILER_FLAG(${flag} Flag:${flag}) if(Flag:${flag}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) endif(Flag:${flag}) endfunction(cxx_add_flag_if_supported) if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lstdc++ -lm") endif(UNIX) if (APPLE) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -framework Foundation -framework DiskArbitration") SET(LINK_FLAGS "${LINK_FLAGS} -framework Foundation -framework DiskArbitration") endif(APPLE) if(APPLE) FIND_LIBRARY(DiskArbitration_LIBRARY DiskArbitration) FIND_LIBRARY(Foundation_LIBRARY Foundation) endif(APPLE) set( SRCS CAbout.cpp CMainWindow.cpp CSingleInstanceProxy.cpp GeoMath.cpp canvas/CCanvas.cpp canvas/CCanvasSetup.cpp canvas/IDrawContext.cpp canvas/IDrawObject.cpp dem/CDemDraw.cpp dem/CDemItem.cpp dem/CDemList.cpp dem/CDemPathSetup.cpp dem/CDemPropSetup.cpp dem/CDemVRT.cpp dem/IDem.cpp dem/IDemProp.cpp device/CDeviceGarmin.cpp device/CDeviceGarminArchive.cpp device/CDeviceTwoNav.cpp device/IDevice.cpp device/IDeviceWatcher.cpp gis/CGisDatabase.cpp gis/CGisDraw.cpp gis/CGisListDB.cpp gis/CGisListWks.cpp gis/CGisWorkspace.cpp gis/CSelDevices.cpp gis/CSetupFilter.cpp gis/IGisItem.cpp gis/IGisLine.cpp gis/WptIcons.cpp gis/db/CDBFolderGroup.cpp gis/db/CDBFolderLostFound.cpp gis/db/CDBFolderMysql.cpp gis/db/CDBFolderOther.cpp gis/db/CDBFolderProject.cpp gis/db/CDBFolderSqlite.cpp gis/db/CDBItem.cpp gis/db/CDBProject.cpp gis/db/CExportDatabase.cpp gis/db/CExportDatabaseThread.cpp gis/db/CLostFoundProject.cpp gis/db/CSearchDatabase.cpp gis/db/CSelectDBFolder.cpp gis/db/CSelectSaveAction.cpp gis/db/CSetupDatabase.cpp gis/db/CSetupFolder.cpp gis/db/CSetupWorkspace.cpp gis/db/IDB.cpp gis/db/IDBFolder.cpp gis/db/IDBFolderSql.cpp gis/db/IDBMysql.cpp gis/db/IDBSqlite.cpp gis/fit/CFitProject.cpp gis/fit/CFitStream.cpp gis/fit/decoder/CFitByteDataTransformer.cpp gis/fit/decoder/CFitCrcState.cpp gis/fit/decoder/CFitDecoder.cpp gis/fit/decoder/CFitDefinitionMessage.cpp gis/fit/decoder/CFitDevFieldDefinition.cpp gis/fit/decoder/CFitDevFieldDefinitionState.cpp gis/fit/decoder/CFitField.cpp gis/fit/decoder/CFitFieldBuilder.cpp gis/fit/decoder/CFitFieldDataState.cpp gis/fit/decoder/CFitFieldDefinition.cpp gis/fit/decoder/CFitFieldDefinitionState.cpp gis/fit/decoder/CFitHeaderState.cpp gis/fit/decoder/CFitMessage.cpp gis/fit/decoder/CFitRecordContentState.cpp gis/fit/decoder/CFitRecordHeaderState.cpp gis/fit/decoder/IFitDecoderState.cpp gis/fit/defs/CFitBaseType.cpp gis/fit/defs/CFitFieldProfile.cpp gis/fit/defs/CFitProfile.cpp gis/fit/defs/CFitProfileLookup.cpp gis/fit/serialization.cpp gis/gpx/CGpxProject.cpp gis/gpx/serialization.cpp gis/ovl/CDetailsOvlArea.cpp gis/ovl/CGisItemOvlArea.cpp gis/ovl/CScrOptOvlArea.cpp gis/prj/CDetailsPrj.cpp gis/prj/IGisProject.cpp gis/qlb/CQlbProject.cpp gis/qms/CQmsProject.cpp gis/qms/serialization.cpp gis/rte/CCreateRouteFromWpt.cpp gis/rte/CDetailsRte.cpp gis/rte/CGisItemRte.cpp gis/rte/CScrOptRte.cpp gis/rte/router/CRouterBRouter.cpp gis/rte/router/CRouterMapQuest.cpp gis/rte/router/CRouterRoutino.cpp gis/rte/router/CRouterSetup.cpp gis/rte/router/IRouter.cpp gis/rte/router/brouter/CRouterBRouterInfo.cpp gis/rte/router/brouter/CRouterBRouterSetup.cpp gis/rte/router/brouter/CRouterBRouterSetupPage.cpp gis/rte/router/brouter/CRouterBRouterSetupWizard.cpp gis/rte/router/brouter/CRouterBRouterTilesPage.cpp gis/rte/router/brouter/CRouterBRouterTilesSelect.cpp gis/rte/router/brouter/CRouterBRouterTilesSelectArea.cpp gis/rte/router/brouter/CRouterBRouterToolShell.cpp gis/rte/router/routino/CRouterRoutinoPathSetup.cpp gis/search/CSearchGoogle.cpp gis/slf/CSlfProject.cpp gis/slf/CSlfReader.cpp gis/suunto/CLogProject.cpp gis/suunto/CSmlProject.cpp gis/suunto/ISuuntoProject.cpp gis/tcx/CTcxProject.cpp gis/tcx/serialization.cpp gis/tnv/CTwoNavProject.cpp gis/tnv/serialization.cpp gis/trk/CActivityTrk.cpp gis/trk/CCombineTrk.cpp gis/trk/CCutTrk.cpp gis/trk/CDetailsTrk.cpp gis/trk/CGisItemTrk.cpp gis/trk/CKnownExtension.cpp gis/trk/CPropertyTrk.cpp gis/trk/CScrOptTrk.cpp gis/trk/CSelectActivityColor.cpp gis/trk/CTableTrk.cpp gis/trk/CTrackData.cpp gis/trk/filter/CFilterDelete.cpp gis/trk/filter/CFilterDeleteExtension.cpp gis/trk/filter/CFilterDouglasPeuker.cpp gis/trk/filter/CFilterInterpolateElevation.cpp gis/trk/filter/CFilterInvalid.cpp gis/trk/filter/CFilterMedian.cpp gis/trk/filter/CFilterNewDate.cpp gis/trk/filter/CFilterObscureDate.cpp gis/trk/filter/CFilterOffsetElevation.cpp gis/trk/filter/CFilterReplaceElevation.cpp gis/trk/filter/CFilterReset.cpp gis/trk/filter/CFilterSpeed.cpp gis/trk/filter/CFilterSplitSegment.cpp gis/trk/filter/CFilterSubPt2Pt.cpp gis/trk/filter/CFilterTerrainSlope.cpp gis/trk/filter/filter.cpp gis/wpt/CDetailsGeoCache.cpp gis/wpt/CDetailsWpt.cpp gis/wpt/CGisItemWpt.cpp gis/wpt/CProjWpt.cpp gis/wpt/CScrOptWpt.cpp gis/wpt/CScrOptWptRadius.cpp gis/wpt/CSetupNewWpt.cpp grid/CGrid.cpp grid/CGridSetup.cpp grid/CProjWizard.cpp grid/mitab.cpp helpers/CDraw.cpp helpers/CElevationDialog.cpp helpers/CInputDialog.cpp helpers/CLimit.cpp helpers/CLinksDialog.cpp helpers/CPhotoViewer.cpp helpers/CPositionDialog.cpp helpers/CProgressDialog.cpp helpers/CSelectCopyAction.cpp helpers/CSelectProjectDialog.cpp helpers/CToolBarConfig.cpp helpers/CToolBarSetupDialog.cpp helpers/CValue.cpp helpers/CWptIconDialog.cpp main.cpp map/CMapDraw.cpp map/CMapGEMF.cpp map/CMapIMG.cpp map/CMapItem.cpp map/CMapJNX.cpp map/CMapList.cpp map/CMapMAP.cpp map/CMapPathSetup.cpp map/CMapPropSetup.cpp map/CMapRMAP.cpp map/CMapTMS.cpp map/CMapVRT.cpp map/CMapWMTS.cpp map/IMap.cpp map/IMapOnline.cpp map/IMapProp.cpp map/cache/CDiskCache.cpp map/garmin/CGarminPoint.cpp map/garmin/CGarminPolygon.cpp map/garmin/CGarminStrTbl6.cpp map/garmin/CGarminStrTbl8.cpp map/garmin/CGarminStrTblUtf8.cpp map/garmin/CGarminTyp.cpp map/garmin/IGarminStrTbl.cpp map/mapsforge/types.cpp mouse/CMouseDummy.cpp mouse/CMouseEditArea.cpp mouse/CMouseEditRte.cpp mouse/CMouseEditTrk.cpp mouse/CMouseMoveWpt.cpp mouse/CMouseNormal.cpp mouse/CMousePrint.cpp mouse/CMouseRadiusWpt.cpp mouse/CMouseRangeTrk.cpp mouse/CMouseSelect.cpp mouse/CMouseWptBubble.cpp mouse/CScrOptPrint.cpp mouse/CScrOptRangeTrk.cpp mouse/CScrOptSelect.cpp mouse/CScrOptUnclutter.cpp mouse/IMouse.cpp mouse/IMouseSelect.cpp mouse/IScrOpt.cpp mouse/line/CLineOpAddPoint.cpp mouse/line/CLineOpDeletePoint.cpp mouse/line/CLineOpMovePoint.cpp mouse/line/CLineOpSelectRange.cpp mouse/line/CScrOptEditLine.cpp mouse/line/CScrOptRangeLine.cpp mouse/line/ILineOp.cpp mouse/line/IMouseEditLine.cpp plot/CPlot.cpp plot/CPlotAxis.cpp plot/CPlotAxisTime.cpp plot/CPlotData.cpp plot/CPlotProfile.cpp plot/CPlotTrack.cpp plot/IPlot.cpp plot/ITrack.cpp print/CPrintDialog.cpp qlgt/CQlb.cpp qlgt/CQlgtDb.cpp qlgt/CQlgtDiary.cpp qlgt/CQlgtFolder.cpp qlgt/CQlgtRoute.cpp qlgt/CQlgtTrack.cpp qlgt/CQlgtWpt.cpp qlgt/CQmsDb.cpp qlgt/IItem.cpp qlgt/IQlgtOverlay.cpp qlgt/converter.cpp setup/CAppSetupLinux.cpp setup/CAppSetupMac.cpp setup/CAppSetupWin.cpp setup/CCommandProcessor.cpp setup/CLogHandler.cpp setup/IAppSetup.cpp tool/CImportDatabase.cpp tool/CMapVrtBuilder.cpp tool/CRoutinoDatabaseBuilder.cpp tool/IToolShell.cpp units/CCoordFormatSetup.cpp units/CTimeZoneSetup.cpp units/CUnitImperial.cpp units/CUnitMetric.cpp units/CUnitNautic.cpp units/CUnitsSetup.cpp units/IUnit.cpp widgets/CColorChooser.cpp widgets/CColorLegend.cpp widgets/CDoubleSpinBox.cpp widgets/CFadingIcon.cpp widgets/CHistoryListWidget.cpp widgets/CLineEdit.cpp widgets/CPhotoAlbum.cpp widgets/CSelectDoubleListWidget.cpp widgets/CTemplateWidget.cpp widgets/CTextEdit.cpp widgets/CTextEditWidget.cpp widgets/CTextEditWidgetSelMenu.cpp widgets/CTinySpinBox.cpp ) if(Qt5DBus_FOUND) set( SRCS ${SRCS} device/CDeviceWatcherLinux.cpp ) endif(Qt5DBus_FOUND) if (APPLE) set( SRCS ${SRCS} device/CDeviceWatcherMac.cpp ) endif(APPLE) if(WIN32) set( SRCS ${SRCS} device/CDeviceWatcherWindows.cpp ) endif(WIN32) set( HDRS CAbout.h CMainWindow.h CSingleInstanceProxy.h GeoMath.h canvas/CCanvas.h canvas/CCanvasSetup.h canvas/IDrawContext.h canvas/IDrawObject.h dem/CDemDraw.h dem/CDemItem.h dem/CDemList.h dem/CDemPathSetup.h dem/CDemPropSetup.h dem/CDemVRT.h dem/IDem.h dem/IDemProp.h device/CDeviceGarmin.h device/CDeviceGarminArchive.h device/CDeviceTwoNav.h device/IDevice.h device/IDeviceWatcher.h gis/CGisDatabase.h gis/CGisDraw.h gis/CGisListDB.h gis/CGisListWks.h gis/CGisWorkspace.h gis/CSelDevices.h gis/CSetupFilter.h gis/IGisItem.h gis/IGisLine.h gis/Poi.h gis/WptIcons.h gis/db/CDBFolderGroup.h gis/db/CDBFolderLostFound.h gis/db/CDBFolderMysql.h gis/db/CDBFolderOther.h gis/db/CDBFolderProject.h gis/db/CDBFolderSqlite.h gis/db/CDBItem.h gis/db/CDBProject.h gis/db/CExportDatabase.h gis/db/CExportDatabaseThread.h gis/db/CLostFoundProject.h gis/db/CSearchDatabase.h gis/db/CSelectDBFolder.h gis/db/CSelectSaveAction.h gis/db/CSetupDatabase.h gis/db/CSetupFolder.h gis/db/CSetupWorkspace.h gis/db/IDB.h gis/db/IDBFolder.h gis/db/IDBFolderSql.h gis/db/IDBMysql.h gis/db/IDBSqlite.h gis/db/macros.h gis/fit/CFitProject.h gis/fit/CFitStream.h gis/fit/decoder/CFitByteDataTransformer.h gis/fit/decoder/CFitCrcState.h gis/fit/decoder/CFitDecoder.h gis/fit/decoder/CFitDefinitionMessage.h gis/fit/decoder/CFitDevFieldDefinition.h gis/fit/decoder/CFitDevFieldDefinitionState.h gis/fit/decoder/CFitField.h gis/fit/decoder/CFitFieldBuilder.h gis/fit/decoder/CFitFieldDataState.h gis/fit/decoder/CFitFieldDefinition.h gis/fit/decoder/CFitFieldDefinitionState.h gis/fit/decoder/CFitHeaderState.h gis/fit/decoder/CFitMessage.h gis/fit/decoder/CFitRecordContentState.h gis/fit/decoder/CFitRecordHeaderState.h gis/fit/decoder/IFitDecoderState.h gis/fit/defs/CFitBaseType.h gis/fit/defs/CFitFieldProfile.h gis/fit/defs/CFitProfile.h gis/fit/defs/CFitProfileLookup.h gis/fit/defs/fit_const.h gis/fit/defs/fit_enums.h gis/fit/defs/fit_fields.h gis/gpx/CGpxProject.h gis/ovl/CDetailsOvlArea.h gis/ovl/CGisItemOvlArea.h gis/ovl/CScrOptOvlArea.h gis/prj/CDetailsPrj.h gis/prj/IGisProject.h gis/qlb/CQlbProject.h gis/qms/CQmsProject.h gis/rte/CCreateRouteFromWpt.h gis/rte/CDetailsRte.h gis/rte/CGisItemRte.h gis/rte/CScrOptRte.h gis/rte/router/CRouterBRouter.h gis/rte/router/CRouterMapQuest.h gis/rte/router/CRouterRoutino.h gis/rte/router/CRouterSetup.h gis/rte/router/IRouter.h gis/rte/router/brouter/CRouterBRouterInfo.h gis/rte/router/brouter/CRouterBRouterSetup.h gis/rte/router/brouter/CRouterBRouterSetupPage.h gis/rte/router/brouter/CRouterBRouterSetupWizard.h gis/rte/router/brouter/CRouterBRouterTilesPage.h gis/rte/router/brouter/CRouterBRouterTilesSelect.h gis/rte/router/brouter/CRouterBRouterTilesSelectArea.h gis/rte/router/brouter/CRouterBRouterTilesSelectLayout.h gis/rte/router/brouter/CRouterBRouterTilesStatus.h gis/rte/router/brouter/CRouterBRouterToolShell.h gis/rte/router/routino/CRouterRoutinoPathSetup.h gis/search/CSearchGoogle.h gis/slf/CSlfProject.h gis/slf/CSlfReader.h gis/suunto/CLogProject.h gis/suunto/CSmlProject.h gis/suunto/ISuuntoProject.h gis/tcx/CTcxProject.h gis/tnv/CTwoNavProject.h gis/trk/CActivityTrk.h gis/trk/CCombineTrk.h gis/trk/CCutTrk.h gis/trk/CDetailsTrk.h gis/trk/CGisItemTrk.h gis/trk/CKnownExtension.h gis/trk/CPropertyTrk.h gis/trk/CScrOptTrk.h gis/trk/CSelectActivityColor.h gis/trk/CTableTrk.h gis/trk/CTrackData.h gis/trk/filter/CFilterDelete.h gis/trk/filter/CFilterDeleteExtension.h gis/trk/filter/CFilterDouglasPeuker.h gis/trk/filter/CFilterInterpolateElevation.h gis/trk/filter/CFilterInvalid.h gis/trk/filter/CFilterMedian.h gis/trk/filter/CFilterNewDate.h gis/trk/filter/CFilterObscureDate.h gis/trk/filter/CFilterOffsetElevation.h gis/trk/filter/CFilterReplaceElevation.h gis/trk/filter/CFilterReset.h gis/trk/filter/CFilterSpeed.h gis/trk/filter/CFilterSplitSegment.h gis/trk/filter/CFilterSubPt2Pt.h gis/trk/filter/CFilterTerrainSlope.h gis/wpt/CDetailsGeoCache.h gis/wpt/CDetailsWpt.h gis/wpt/CGisItemWpt.h gis/wpt/CProjWpt.h gis/wpt/CScrOptWpt.h gis/wpt/CScrOptWptRadius.h gis/wpt/CSetupNewWpt.h grid/CGrid.h grid/CGridSetup.h grid/CProjWizard.h grid/mitab.h helpers/CDraw.h helpers/CElevationDialog.h helpers/CFileExt.h helpers/CInputDialog.h helpers/CLimit.h helpers/CLinksDialog.h helpers/CPhotoViewer.h helpers/CPositionDialog.h helpers/CProgressDialog.h helpers/CSelectCopyAction.h helpers/CSelectProjectDialog.h helpers/CSettings.h helpers/CToolBarConfig.h helpers/CToolBarSetupDialog.h helpers/CValue.h helpers/CWptIconDialog.h helpers/Platform.h helpers/Signals.h map/CMapDraw.h map/CMapGEMF.h map/CMapIMG.h map/CMapItem.h map/CMapJNX.h map/CMapList.h map/CMapMAP.h map/CMapPathSetup.h map/CMapPropSetup.h map/CMapRMAP.h map/CMapTMS.h map/CMapVRT.h map/CMapWMTS.h map/IMap.h map/IMapOnline.h map/IMapProp.h map/cache/CDiskCache.h map/garmin/CGarminPoint.h map/garmin/CGarminPolygon.h map/garmin/CGarminStrTbl6.h map/garmin/CGarminStrTbl8.h map/garmin/CGarminStrTblUtf8.h map/garmin/CGarminTyp.h map/garmin/Garmin.h map/garmin/IGarminStrTbl.h map/mapsforge/types.h mouse/CMouseDummy.h mouse/CMouseEditArea.h mouse/CMouseEditRte.h mouse/CMouseEditTrk.h mouse/CMouseMoveWpt.h mouse/CMouseNormal.h mouse/CMousePrint.h mouse/CMouseRadiusWpt.h mouse/CMouseRangeTrk.h mouse/CMouseSelect.h mouse/CMouseWptBubble.h mouse/CScrOptPrint.h mouse/CScrOptRangeTrk.h mouse/CScrOptSelect.h mouse/CScrOptUnclutter.h mouse/IMouse.h mouse/IMouseSelect.h mouse/IScrOpt.h mouse/line/CLineOpAddPoint.h mouse/line/CLineOpDeletePoint.h mouse/line/CLineOpMovePoint.h mouse/line/CLineOpSelectRange.h mouse/line/CScrOptEditLine.h mouse/line/CScrOptRangeLine.h mouse/line/ILineOp.h mouse/line/IMouseEditLine.h plot/CPlot.h plot/CPlotAxis.h plot/CPlotAxisTime.h plot/CPlotData.h plot/CPlotProfile.h plot/CPlotTrack.h plot/IPlot.h plot/ITrack.h print/CPrintDialog.h qlgt/CQlb.h qlgt/CQlgtDb.h qlgt/CQlgtDiary.h qlgt/CQlgtFolder.h qlgt/CQlgtRoute.h qlgt/CQlgtTrack.h qlgt/CQlgtWpt.h qlgt/CQmsDb.h qlgt/IItem.h qlgt/IQlgtOverlay.h setup/CAppOpts.h setup/CAppSetupLinux.h setup/CAppSetupMac.h setup/CAppSetupWin.h setup/CCommandProcessor.h setup/CLogHandler.h setup/IAppSetup.h tool/CImportDatabase.h tool/CMapVrtBuilder.h tool/CRoutinoDatabaseBuilder.h tool/IToolShell.h units/CCoordFormatSetup.h units/CTimeZoneSetup.h units/CUnitImperial.h units/CUnitMetric.h units/CUnitNautic.h units/CUnitsSetup.h units/IUnit.h version.h widgets/CColorChooser.h widgets/CColorLegend.h widgets/CDoubleSpinBox.h widgets/CFadingIcon.h widgets/CHistoryListWidget.h widgets/CLineEdit.h widgets/CPhotoAlbum.h widgets/CSelectDoubleListWidget.h widgets/CTemplateWidget.h widgets/CTextEdit.h widgets/CTextEditWidget.h widgets/CTextEditWidgetSelMenu.h widgets/CTinySpinBox.h ) if(Qt5DBus_FOUND) set( HDRS ${HDRS} device/CDeviceWatcherLinux.h ) endif(Qt5DBus_FOUND) if(APPLE) set( HDRS ${HDRS} device/CDeviceWatcherMac.h ) endif(APPLE) if(WIN32) set( HDRS ${HDRS} device/CDeviceWatcherWindows.h ) endif(WIN32) set( UIS IAbout.ui IMainWindow.ui canvas/ICanvasSetup.ui dem/IDemList.ui dem/IDemPathSetup.ui dem/IDemPropSetup.ui gis/IGisDatabase.ui gis/IGisWorkspace.ui gis/ISelDevices.ui gis/ISetupFilter.ui gis/db/IExportDatabase.ui gis/db/ISearchDatabase.ui gis/db/ISelectDBFolder.ui gis/db/ISelectSaveAction.ui gis/db/ISetupDatabase.ui gis/db/ISetupFolder.ui gis/db/ISetupWorkspace.ui gis/ovl/IDetailsOvlArea.ui gis/ovl/IScrOptOvlArea.ui gis/prj/IDetailsPrj.ui gis/rte/ICreateRouteFromWpt.ui gis/rte/IDetailsRte.ui gis/rte/IScrOptRte.ui gis/rte/router/IRouterBRouter.ui gis/rte/router/IRouterMapQuest.ui gis/rte/router/IRouterRoutino.ui gis/rte/router/IRouterSetup.ui gis/rte/router/brouter/IRouterBRouterInfo.ui gis/rte/router/brouter/IRouterBRouterSetupWizard.ui gis/rte/router/routino/IRouterRoutinoPathSetup.ui gis/trk/ICombineTrk.ui gis/trk/ICutTrk.ui gis/trk/IDetailsTrk.ui gis/trk/IScrOptTrk.ui gis/trk/ISelectActivityColor.ui gis/trk/filter/IFilterDelete.ui gis/trk/filter/IFilterDeleteExtension.ui gis/trk/filter/IFilterDouglasPeuker.ui gis/trk/filter/IFilterInterpolateElevation.ui gis/trk/filter/IFilterInvalid.ui gis/trk/filter/IFilterMedian.ui gis/trk/filter/IFilterNewDate.ui gis/trk/filter/IFilterObscureDate.ui gis/trk/filter/IFilterOffsetElevation.ui gis/trk/filter/IFilterReplaceElevation.ui gis/trk/filter/IFilterReset.ui gis/trk/filter/IFilterSpeed.ui gis/trk/filter/IFilterSplitSegment.ui gis/trk/filter/IFilterSubPt2Pt.ui gis/trk/filter/IFilterTerrainSlope.ui gis/wpt/IDetailsGeoCache.ui gis/wpt/IDetailsWpt.ui gis/wpt/IProjWpt.ui gis/wpt/IScrOptWpt.ui gis/wpt/IScrOptWptRadius.ui gis/wpt/ISetupNewWpt.ui grid/IGridSetup.ui grid/IProjWizard.ui helpers/IElevationDialog.ui helpers/IInputDialog.ui helpers/ILinksDialog.ui helpers/IPositionDialog.ui helpers/IProgressDialog.ui helpers/ISelectCopyAction.ui helpers/ISelectProjectDialog.ui helpers/IToolBarSetupDialog.ui helpers/IWptIconDialog.ui map/IMapList.ui map/IMapPathSetup.ui map/IMapPropSetup.ui mouse/IScrOptPrint.ui mouse/IScrOptRangeTrk.ui mouse/IScrOptSelect.ui mouse/line/IScrOptEditLine.ui mouse/line/IScrOptRangeLine.ui print/IPrintDialog.ui templates/Hiking_Tour_Summary.ui tool/IImportDatabase.ui tool/IMapVrtBuilder.ui tool/IRoutinoDatabaseBuilder.ui units/ICoordFormatSetup.ui units/ITimeZoneSetup.ui units/IUnitsSetup.ui widgets/IColorChooser.ui widgets/IPhotoAlbum.ui widgets/ISelectDoubleListWidget.ui widgets/ITemplateWidget.ui widgets/ITextEditWidget.ui widgets/ITextEditWidgetSelMenu.ui ) set( RCS resources.qrc ) qt5_wrap_ui(UI_HDRS ${UIS}) qt5_add_resources(RC_SRCS ${RCS}) # try to figure out which compiler flags are supported (and add them) cxx_add_flag_if_supported(-Wsuggest-override) cxx_add_flag_if_supported(-Woverloaded-virtual) if(UNIX) add_definitions(-Wall -Wpedantic -Wno-switch -Wno-strict-aliasing) endif(UNIX) if(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif(WIN32) add_definitions(-DROUTINO_XML_PATH=${ROUTINO_XML_PATH}) translate_ts(${APPLICATION_NAME}_QM_FILES UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} UPDATE_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}" "-no-obsolete" SOURCES ${SRCS} ${HDRS} ${UIS} TEMPLATE ${APPLICATION_NAME} TRANSLATION_DIR "locale" ) if (UNIX AND NOT WIN32 AND NOT APPLE) translate_desktop(${APPLICATION_NAME}_DESKTOP_FILES TRANSLATION_DIR "locale" SOURCES "${PROJECT_SOURCE_DIR}/qmapshack.desktop.in" ) endif() set(MAININP ${SRCS} ${HDRS} ${UI_HDRS} ${RC_SRCS} ${${APPLICATION_NAME}_QM_FILES} ${${APPLICATION_NAME}_DESKTOP_FILES} ) include_directories( ${CMAKE_BINARY_DIR} ) include_directories( SYSTEM # this prevents warnings from non-QMS headers ${GDAL_INCLUDE_DIRS} ${PROJ_INCLUDE_DIRS} ${ROUTINO_INCLUDE_DIRS} ${ALGLIB_INCLUDE_DIRS} ${QUAZIP_INCLUDE_DIRS} ) if(APPLE) INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework) INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework) endif(APPLE) add_executable(${APPLICATION_NAME} WIN32 ${MAININP}) if(Qt5DBus_FOUND) set(DBUS_LIB Qt5::DBus) else(Qt5DBus_FOUND) set(DBUS_LIB) endif(Qt5DBus_FOUND) target_link_libraries(${APPLICATION_NAME} Qt5::Widgets Qt5::Xml Qt5::Script Qt5::Sql Qt5::WebKitWidgets Qt5::PrintSupport Qt5::UiTools ${DBUS_LIB} ${GDAL_LIBRARIES} ${PROJ_LIBRARIES} ${ROUTINO_LIBRARIES} ${ALGLIB_LIBRARIES} ${QUAZIP_LIBRARIES} ) if(APPLE) target_link_libraries(${APPLICATION_NAME} ${Foundation_LIBRARY} ${DiskArbitration_LIBRARY} ) endif(APPLE) install( TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR} ) if (UNIX AND NOT WIN32 AND NOT APPLE) install( FILES ${${APPLICATION_NAME}_QM_FILES} DESTINATION ${DATA_INSTALL_PREFIX}/${APPLICATION_NAME}/translations) install( FILES ${${APPLICATION_NAME}_DESKTOP_FILES} DESTINATION ${XDG_APPS_DIR} ) endif (UNIX AND NOT WIN32 AND NOT APPLE) qmapshack-1.10.0/src/widgets/000755 001750 000144 00000000000 13216664445 017172 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/widgets/CTinySpinBox.cpp000644 001750 000144 00000004567 13216234137 022232 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "widgets/CTinySpinBox.h" #include void CTinySpinBox::initialize() { initialized = true; paletteEdit = QPalette(palette()); paletteRO = QPalette(palette()); paletteRW = QPalette(palette()); paletteRW.setColor(QPalette::Text, QColor(0, 0, 255)); fontNoUnderline = QFont(font()); fontUnderline = QFont(font()); fontUnderline.setUnderline(true); } void CTinySpinBox::updateStyle() { if(!initialized) { initialize(); } if(isReadOnly()) { setPalette(paletteRO); setFont(fontNoUnderline); } else if(hasFocus()) { setPalette(paletteEdit); setFont(fontNoUnderline); } else { setPalette(paletteRW); setFont(fontUnderline); } } CTinySpinBox::CTinySpinBox(QWidget * parent) : QSpinBox(parent) { // initialization has to be done deferred, // as the correct palette is set after construction initialized = false; } void CTinySpinBox::stepBy(int steps) { QSpinBox::stepBy(steps); emit valueChangedByStep(value()); } void CTinySpinBox::setReadOnly(bool r) { QSpinBox::setReadOnly(r); updateStyle(); } void CTinySpinBox::focusInEvent(QFocusEvent *event) { updateStyle(); if(!isReadOnly()) { QTimer::singleShot(0, this, SLOT(slotSelectAll())); } QSpinBox::focusInEvent(event); } void CTinySpinBox::focusOutEvent(QFocusEvent *event) { updateStyle(); QSpinBox::focusOutEvent(event); } qmapshack-1.10.0/src/widgets/CColorLegend.cpp000644 001750 000144 00000013703 13216234137 022171 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "CMainWindow.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "helpers/CDraw.h" #include "widgets/CColorLegend.h" #include CColorLegend::CColorLegend(QWidget *parent, CGisItemTrk *trk) : QWidget(parent) , INotifyTrk(CGisItemTrk::eVisualColorLegend) , trk(trk) { colorRect = QRect(0, 0, colorWidth, colorHeight); colorRect.moveCenter(QPoint(xOffset + colorWidth / 2, height() / 2)); if(nullptr != trk) { background = true; xOffset = 5; trk->registerVisual(this); // read data from trk updateData(); } } CColorLegend::~CColorLegend() { if(trk) { trk->unregisterVisual(this); } } void CColorLegend::setMouseFocus(const CTrackData::trkpt_t * pt) { if(nullptr == pt) { val = NOFLOAT; return; } QString colorSource = trk->getColorizeSource(); auto valueFunc = CKnownExtension::get(colorSource).valueFunc; const qreal factor = CKnownExtension::get(colorSource).factor; val = factor * valueFunc(*pt); val = qMin(val, maximum); val = qMax(val, minimum); } void CColorLegend::updateData() { if(!trk->getColorizeSource().isEmpty() && (trk->getColorizeSource() != "activity")) { unit = trk->getColorizeUnit(); minimum = trk->getColorizeLimitLow(); maximum = trk->getColorizeLimitHigh(); update(); show(); } else { hide(); } } void CColorLegend::setMinimum(qreal min) { minimum = min; update(); } void CColorLegend::setMaximum(qreal max) { maximum = max; update(); } void CColorLegend::setUnit(const QString &unit) { this->unit = unit; update(); } int CColorLegend::paintLabel(QPainter &p, qreal value) { const int fontHeight = QFontMetrics(p.font()).ascent() + 1; const qreal relativePos = (value - minimum) / (maximum - minimum); const int posY = colorRect.bottom() + fontHeight / 2 - (2 + colorRect.height()) * relativePos + 1; int posX = xOffset + colorWidth + 3; p.setPen( QPen(QBrush(Qt::black), 2.) ); p.drawLine(posX, posY - fontHeight / 2 + 1, posX + 2, posY - fontHeight / 2 + 1); if(value == minimum || value == maximum || (posY > colorRect.top() + 3*fontHeight / 2 && posY < colorRect.bottom() - fontHeight / 2)) { posX += 5; const QString &labelText = QString("%1%2").arg(value).arg(unit); p.drawText(posX, posY, labelText); posX += QFontMetrics(p.font()).width(labelText); } return posX; } void CColorLegend::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); colorRect.setHeight(height() - 20); colorRect.moveCenter(QPoint(xOffset + colorWidth / 2, height() / 2)); updateGeometry(); } static qreal legendRound(qreal value, int powOffset) { int l10 = (int) (value > 0) ? log10(value) : log10(-value); qreal div = pow(10, l10 + powOffset); return ceil(value / div) * div; } void CColorLegend::paintEvent(QPaintEvent *event) { const QFont &font = CMainWindow::self().getMapFont(); if(isEnabled()) { QPainter p(this); p.setFont(font); if(background) { p.setRenderHint(QPainter::Antialiasing); p.setOpacity(0.6); p.setPen( QPen(QBrush(Qt::darkGray), 2.) ); p.setBrush(Qt::white); p.drawRoundedRect(1, 1, width() - 2, height() - 2, RECT_RADIUS, RECT_RADIUS); p.setOpacity(1.f); p.setRenderHint(QPainter::Antialiasing, false); } // draw the black frame QRect borderRect(colorRect); borderRect += QMargins(1, 1, 1, 1); p.setPen( QPen(QBrush(Qt::SolidPattern), 2., Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) ); p.drawRect(borderRect); // draw the gradient QLinearGradient grad(colorRect.topLeft(), colorRect.bottomLeft()); grad.setColorAt(1.00, QColor( 0, 0, 255)); // blue grad.setColorAt(0.60, QColor( 0, 255, 0)); // green grad.setColorAt(0.40, QColor(255, 255, 0)); // yellow grad.setColorAt(0.00, QColor(255, 0, 0)); // red p.fillRect(colorRect, grad); int reqWidth = paintLabel(p, minimum); reqWidth = qMax(paintLabel(p, maximum), reqWidth); // draw values inbetween min/max const qreal delta = maximum - minimum; qreal step = legendRound(delta / 8, 0); qreal roundedMinimum = legendRound(minimum, delta > 60 ? -1 : 0); for(qreal v = roundedMinimum; v < maximum; v+= step) { reqWidth = qMax(paintLabel(p, v), reqWidth); } if(reqWidth + 5 != width()) { setMinimumWidth(reqWidth + 5); resize(reqWidth + 5, height()); } if(val != NOFLOAT) { qreal y = qFloor(colorRect.bottom() - (val - minimum) * (colorRect.height()-1)/(maximum - minimum)); p.setPen(QPen(Qt::darkGray, 2)); p.drawLine(colorRect.left() + 2, y, colorRect.right() - 2, y); } p.end(); } } qmapshack-1.10.0/src/widgets/ITextEditWidgetSelMenu.ui000644 001750 000144 00000006644 12741120171 024024 0ustar00oeichlerxusers000000 000000 ITextEditWidgetSelMenu 0 0 474 285 0 1 78 51 QFrame::StyledPanel QFrame::Raised 1 0 0 0 0 0 1 B 16 16 I 16 16 U 16 16 0 Cut 16 16 Copy 16 16 Paste 16 16 qmapshack-1.10.0/src/widgets/ISelectDoubleListWidget.ui000644 001750 000144 00000007540 13126360004 024202 0ustar00oeichlerxusers000000 000000 ISelectDoubleListWidget 0 0 400 300 Form Available QAbstractItemView::NoEditTriggers QAbstractItemView::ExtendedSelection QAbstractItemView::SelectItems Add to selected items ... :/icons/32x32/Right.png:/icons/32x32/Right.png Remove from selected items ... :/icons/32x32/Left.png:/icons/32x32/Left.png Selected QAbstractItemView::NoEditTriggers QAbstractItemView::ExtendedSelection QAbstractItemView::SelectItems Move selected items up ... :/icons/32x32/Up.png:/icons/32x32/Up.png Move selected items down ... :/icons/32x32/Down.png:/icons/32x32/Down.png qmapshack-1.10.0/src/widgets/CTextEditWidgetSelMenu.h000644 001750 000144 00000002760 13216234142 023625 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CTEXTEDITWIDGETCONTEXTMENU_H #define CTEXTEDITWIDGETCONTEXTMENU_H #include "ui_ITextEditWidgetSelMenu.h" #include class CTextEditWidgetSelMenu : public QWidget, private Ui::ITextEditWidgetSelMenu { Q_OBJECT public: CTextEditWidgetSelMenu(QWidget *parent, QAction *actionTextBold, QAction *actionTextItalic, QAction *actionTextUnderline, QAction *actionCut, QAction *actionCopy, QAction *actionPaste ); virtual ~CTextEditWidgetSelMenu() {} }; #endif // CTEXTEDITWIDGETCONTEXTMENU_H qmapshack-1.10.0/src/widgets/CSelectDoubleListWidget.cpp000644 001750 000144 00000017031 13216234137 024344 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #include "CSelectDoubleListWidget.h" #include CSelectDoubleListWidget::CSelectDoubleListWidget(QWidget * parent, IItemFilter *filter) : QWidget(parent), filter(filter) { setupUi(this); connect(listSelected, &QListView::clicked, this, &CSelectDoubleListWidget::slotSelectedClicked); connect(listAvailable, &QListView::clicked, this, &CSelectDoubleListWidget::slotAvailableClicked); connect(toolAdd, &QToolButton::clicked, this, &CSelectDoubleListWidget::slotAdd); connect(toolRemove, &QToolButton::clicked, this, &CSelectDoubleListWidget::slotRemove); connect(toolUp, &QToolButton::clicked, this, &CSelectDoubleListWidget::slotUp); connect(toolDown, &QToolButton::clicked, this, &CSelectDoubleListWidget::slotDown); } CSelectDoubleListWidget::~CSelectDoubleListWidget() { } void CSelectDoubleListWidget::setAvailable(const QList & available) { this->available.clear(); this->available << available; listAvailable->clear(); for (QListWidgetItem * const & item : available) { int index = listSelected->row(item); if (index < 0) { listAvailable->addItem(item); } else if(filter != nullptr && !filter->shouldBeMoved(item)) { listSelected->takeItem(index); listSelected->insertItem(index,item->clone()); listAvailable->addItem(item); } } updateButtons(); } void CSelectDoubleListWidget::setSelected(const QList & selected) const { listSelected->clear(); for (QListWidgetItem * const & item : selected) { int index = listAvailable->row(item); if (index < 0) { listSelected->addItem(item); } else { if(filter == nullptr || filter->shouldBeMoved(item)) { listAvailable->takeItem(index); listSelected->addItem(item); } else { listSelected->addItem(item->clone()); } } } updateButtons(); } void CSelectDoubleListWidget::setFilter(IItemFilter * const & filter) { this->filter = filter; } void CSelectDoubleListWidget::setLabelAvailable(const QString & label) const { labelAvailable->setText(label); } void CSelectDoubleListWidget::setLabelSelected(const QString & label) const { labelSelected->setText(label); } const QList CSelectDoubleListWidget::selected() const { QList selected; for (int i=0; i < listSelected->count(); i++) { selected << listSelected->item(i); } return selected; } void CSelectDoubleListWidget::clear() { this->available.clear(); listAvailable->clear(); listSelected->clear(); } void CSelectDoubleListWidget::slotSelectedClicked(const QModelIndex & index) const { listAvailable->clearSelection(); updateButtons(); } void CSelectDoubleListWidget::slotAvailableClicked(const QModelIndex & index) const { listSelected->clearSelection(); updateButtons(); } void CSelectDoubleListWidget::slotAdd() const { for (QListWidgetItem * const & item : listAvailable->selectedItems()) { if (filter == nullptr || filter->shouldBeMoved(item)) { listAvailable->takeItem(listAvailable->row(item)); listSelected->addItem(item); } else { listSelected->addItem(item->clone()); } } updateButtons(); } void CSelectDoubleListWidget::slotRemove() const { for (QListWidgetItem * const & item : listSelected->selectedItems()) { if (filter == nullptr || filter->shouldBeMoved(item)) { int index = -1; for (int i = available.indexOf(item)-1; i>=0; i--) { index = listAvailable->row(available.at(i)); if (index >= 0) { break; } } index++; listSelected->takeItem(listSelected->row(item)); listAvailable->insertItem(index,item); } else { delete listSelected->takeItem(listSelected->row(item)); } } updateButtons(); } void CSelectDoubleListWidget::slotUp() const { QList indices; for (const QModelIndex & modelIndex : listSelected->selectionModel()->selectedIndexes()) { indices << modelIndex.row(); } std::sort(indices.begin(),indices.end()); int i=0; for (int index : indices) { if (index > i) { listSelected->insertItem(index-1,listSelected->takeItem(index)); listSelected->setCurrentRow(index-1,QItemSelectionModel::Select); } i++; } updateButtons(); } void CSelectDoubleListWidget::slotDown() const { QList indices; for (const QModelIndex & modelIndex : listSelected->selectionModel()->selectedIndexes()) { indices << modelIndex.row(); } std::sort(indices.begin(), indices.end(), [] (int a, int b) { return a > b; }); int i=listSelected->count()-1; for (int index : indices) { if (index < i) { listSelected->insertItem(index+1,listSelected->takeItem(index)); listSelected->setCurrentRow(index+1,QItemSelectionModel::Select); } i--; } updateButtons(); } void CSelectDoubleListWidget::updateButtons() const { toolAdd->setEnabled(listAvailable->selectionModel()->hasSelection()); const QItemSelectionModel * const & selectedSelectionModel = listSelected->selectionModel(); if (selectedSelectionModel->hasSelection()) { toolRemove->setEnabled(true); int minSelected = listSelected->count(); int maxSelected = -1; int minUnselected = minSelected; int maxUnselected = -1; for (int i = 0; i < listSelected->count(); i++) { if (selectedSelectionModel->isRowSelected(i, QModelIndex())) { if (i < minSelected) { minSelected = i; } maxSelected = i; } else { if (i < minUnselected) { minUnselected = i; } maxUnselected = i; } } toolUp->setEnabled(minUnselected < maxSelected); toolDown->setEnabled(maxUnselected > minSelected); } else { toolRemove->setEnabled(false); toolUp->setEnabled(false); toolDown->setEnabled(false); } } qmapshack-1.10.0/src/widgets/CTinySpinBox.h000644 001750 000144 00000004047 13216234142 021664 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ /** @brief A QWidget derived from QSpinBox, aiming to be tiny with regard to spaced consumed on screen. By default, a readonly CTinySpinBox looks like an ordinary label, whereas a non-readonly CTinySpinBox contains blue, underlined text. As soon as the non-readonly widget receives the focus, the color is changed to black, the underline disappears and the modifiable text is selected. */ #ifndef CTINYSPINBOX_H #define CTINYSPINBOX_H #include #include #include class CTinySpinBox : public QSpinBox { Q_OBJECT private: bool initialized; QPalette paletteEdit; QPalette paletteRO; QPalette paletteRW; QFont fontNoUnderline; QFont fontUnderline; void initialize(); void updateStyle(); public slots: void slotSelectAll() { selectAll(); } signals: void valueChangedByStep(int val); public: CTinySpinBox(QWidget * parent = nullptr); void setReadOnly(bool r); void stepBy(int steps) override; protected: void focusInEvent(QFocusEvent *event) override; void focusOutEvent(QFocusEvent *event) override; }; #endif // CTINYSPINBOX_H qmapshack-1.10.0/src/widgets/CPhotoAlbum.h000644 001750 000144 00000003305 13216234142 021504 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPHOTOALBUM_H #define CPHOTOALBUM_H #include "ui_IPhotoAlbum.h" #include #include "gis/wpt/CGisItemWpt.h" class CPhotoAlbum : public QWidget, private Ui::IPhotoAlbum { Q_OBJECT public: CPhotoAlbum(QWidget * parent); virtual ~CPhotoAlbum(); void reload(const QList& imgs); signals: void sigChanged(const QList& imgs); public slots: void slotAddImage(); void slotDelImage(); protected: void resizeEvent(QResizeEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; private slots: void slotRight(); void slotLeft(); private: void updateView(); QList images; QList rects; qint32 idx1stVisible = 0; qint32 idxSelected = 0; }; #endif //CPHOTOALBUM_H qmapshack-1.10.0/src/widgets/CPhotoAlbum.cpp000644 001750 000144 00000012062 13216234137 022043 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CPhotoViewer.h" #include "helpers/CSettings.h" #include "widgets/CPhotoAlbum.h" #include CPhotoAlbum::CPhotoAlbum(QWidget *parent) : QWidget(parent) { setupUi(this); setFocusPolicy(Qt::WheelFocus); connect(toolLeft, &QToolButton::clicked, this, &CPhotoAlbum::slotLeft); connect(toolRight, &QToolButton::clicked, this, &CPhotoAlbum::slotRight); } CPhotoAlbum::~CPhotoAlbum() { } void CPhotoAlbum::resizeEvent(QResizeEvent * e) { QWidget::resizeEvent(e); updateView(); } void CPhotoAlbum::mouseReleaseEvent(QMouseEvent * e) { CPhotoViewer dlg(images, 0, this); dlg.exec(); e->accept(); } void CPhotoAlbum::reload(const QList& imgs) { images = imgs; if(idxSelected >= images.size()) { idx1stVisible = 0; idxSelected = 0; } updateView(); } void CPhotoAlbum::slotAddImage() { SETTINGS; QString path = cfg.value("Paths/lastWptImagePath", QDir::homePath()).toString(); QString filters = "All Files (*);; All Images (*.png *.jpg);; PNG Image (*.png);; JPEG Image (*.jpg)"; QString defaultFilter = "All Images (*.png *.jpg)"; QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Select images..."), path, filters, &defaultFilter); if(filenames.isEmpty()) { return; } for(const QString &filename : filenames) { CGisItemWpt::image_t image; image.fileName = filename; if(image.pixmap.load(filename)) { int w = image.pixmap.width(); int h = image.pixmap.height(); if(w < h) { h *= 400.0 / w; w = 400; } else { h *= 600.0 / w; w = 600; } image.pixmap = image.pixmap.scaled(w,h,Qt::KeepAspectRatio, Qt::SmoothTransformation); images << image; } else { qDebug() << "Cannot load image from file " << filename; } } QFileInfo fi(filenames.first()); path = fi.absolutePath(); cfg.setValue("Paths/lastWptImagePath", path); emit sigChanged(images); } void CPhotoAlbum::slotDelImage() { images.removeAt(idxSelected); emit sigChanged(images); } void CPhotoAlbum::slotRight() { idxSelected++; QRect r1 = rects[idxSelected]; QRect r2 = label->rect(); while(!r2.contains(r1)) { int w = rects[idx1stVisible].width(); r1.moveLeft(r1.left() - w); idx1stVisible++; } updateView(); } void CPhotoAlbum::slotLeft() { idxSelected--; QRect r1 = rects[idxSelected]; QRect r2 = label->rect(); while(!r2.contains(r1)) { idx1stVisible--; int w = rects[idx1stVisible].width(); r1.moveLeft(r1.left() + w); } updateView(); } void CPhotoAlbum::updateView() { toolLeft->setEnabled(idxSelected != 0); toolRight->setEnabled(idxSelected != (images.size() - 1)); if(images.isEmpty()) { hide(); return; } setEnabled(true); show(); QPixmap img(label->size()); img.fill(Qt::black); QPainter p(&img); int xoff = 0; for(int i = 0; i < rects.size() && i < idx1stVisible; i++) { xoff -= rects[i].width(); } rects.clear(); for(int i = 0; i < images.size(); i++) { CGisItemWpt::image_t& image = images[i]; QImage tmp = image.pixmap.scaledToHeight(label->height(), Qt::SmoothTransformation); if(tmp.width() > label->width()) { tmp = image.pixmap.scaledToWidth(label->width(), Qt::SmoothTransformation); } QRect r = tmp.rect(); int yoff = (height()- r.height()) / 2; p.save(); p.translate(xoff,yoff); p.drawImage(0,0,tmp); p.setPen(QPen(Qt::black, 3)); p.setBrush(Qt::NoBrush); p.drawRect(r); p.restore(); r.moveTopLeft(QPoint(xoff, yoff)); rects << r; xoff += tmp.width(); } if(idxSelected < rects.size()) { p.setPen(QPen(Qt::yellow, 5)); p.drawRect(rects[idxSelected]); } label->setPixmap(img); } qmapshack-1.10.0/src/widgets/CLineEdit.cpp000644 001750 000144 00000004365 13216234137 021475 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "widgets/CLineEdit.h" #include void CLineEdit::initialize() { initialized = true; paletteEdit = QPalette(palette()); paletteRO = QPalette(palette()); paletteRW = QPalette(palette()); paletteRW.setColor(QPalette::Text, QColor(0, 0, 255)); fontNoUnderline = QFont(font()); fontUnderline = QFont(font()); fontUnderline.setUnderline(true); } void CLineEdit::updateStyle() { if(!initialized) { initialize(); } if(isReadOnly()) { setPalette(paletteRO); setFont(fontNoUnderline); } else if(hasFocus()) { setPalette(paletteEdit); setFont(fontNoUnderline); } else { setPalette(paletteRW); setFont(fontUnderline); } } CLineEdit::CLineEdit(QWidget *parent) : QLineEdit(parent) { // initialization has to be done deferred, // as the correct palette is set after construction initialized = false; } void CLineEdit::setReadOnly(bool r) { QLineEdit::setReadOnly(r); updateStyle(); } void CLineEdit::focusInEvent(QFocusEvent *event) { QLineEdit::focusInEvent(event); updateStyle(); if(!isReadOnly()) { QTimer::singleShot(0, this, SLOT(slotSelectAll())); } } void CLineEdit::focusOutEvent(QFocusEvent *event) { QLineEdit::focusOutEvent(event); updateStyle(); } qmapshack-1.10.0/src/widgets/CTextEdit.h000644 001750 000144 00000002363 13216234142 021167 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CTEXTEDIT_H #define CTEXTEDIT_H #include class CTextEdit : public QTextEdit { Q_OBJECT public slots: void paste(); public: CTextEdit(QWidget *parent = nullptr); void setPastePlain(bool plain); protected: void keyPressEvent(QKeyEvent *event) override; private: bool pastePlain; }; #endif // CTEXTEDIT_H qmapshack-1.10.0/src/widgets/CSelectDoubleListWidget.h000644 001750 000144 00000004226 13216234142 024007 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #ifndef CSELECTDOUBLELISTWIDGET_H #define CSELECTDOUBLELISTWIDGET_H #include "ui_ISelectDoubleListWidget.h" class CSelectDoubleListWidget : public QWidget, private Ui::ISelectDoubleListWidget { Q_OBJECT public: class IItemFilter { public: virtual bool shouldBeMoved(QListWidgetItem * item) = 0; }; CSelectDoubleListWidget(QWidget *parent, IItemFilter *filter = nullptr); virtual ~CSelectDoubleListWidget(); void setAvailable(const QList &available); void setSelected(const QList &selected) const; void setLabelAvailable(const QString & label) const; void setLabelSelected(const QString & label) const; void setFilter(IItemFilter * const &filter); const QList selected() const; void clear(); private slots: void slotSelectedClicked(const QModelIndex & index) const; void slotAvailableClicked(const QModelIndex & index) const; void slotAdd() const; void slotRemove() const; void slotUp() const; void slotDown() const; private: void updateButtons() const; QList available; IItemFilter * filter; }; #endif //CSELECTDOUBLELISTWIDGET_H qmapshack-1.10.0/src/widgets/CHistoryListWidget.h000644 001750 000144 00000003032 13216234142 023070 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CHISTORYLISTWIDGET_H #define CHISTORYLISTWIDGET_H #include "gis/IGisItem.h" #include class CHistoryListWidget : public QListWidget { Q_OBJECT public: CHistoryListWidget(QWidget * parent); virtual ~CHistoryListWidget(); void setupHistory(IGisItem &gisItem); signals: void sigChanged(); private slots: void slotSelectionChanged(); void slotContextMenu(const QPoint& point); void slotCutHistoryAfter(); void slotCutHistoryBefore(); private: IGisItem::key_t key; QMenu * menu; QAction * actionCutHistoryAfter; QAction * actionCutHistoryBefore; }; #endif //CHISTORYLISTWIDGET_H qmapshack-1.10.0/src/widgets/CColorChooser.cpp000644 001750 000144 00000004253 13216234137 022375 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/IGisItem.h" #include "widgets/CColorChooser.h" #include #include using std::bind; CColorChooser::CColorChooser(QToolButton *parent) : QDialog(parent) , parentButton(parent) { setupUi(this); setWindowFlags(Qt::ToolTip); for(quint32 i = 0; i < IGisItem::colorMapSize; i++) { QPixmap pixmap(16,16); pixmap.fill(IGisItem::colorMap[i].color); QToolButton * button = new QToolButton(this); button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setAutoRaise(true); button->setIcon(QIcon(pixmap)); button->setProperty("color", IGisItem::colorMap[i].color.name()); horizontalLayout->addWidget(button); auto selectFunc = bind(&CColorChooser::slotSelect, this, button); connect(button, &QToolButton::clicked, this, selectFunc); } QToolButton * butEsc = new QToolButton(this); butEsc->setText(tr("Esc.")); butEsc->setAutoRaise(true); horizontalLayout->addWidget(butEsc); connect(butEsc, &QToolButton::clicked, this, &CColorChooser::reject); adjustSize(); } void CColorChooser::slotSelect(QToolButton * button) { parentButton->setIcon(button->icon()); parentButton->setProperty("color", button->property("color")); accept(); } qmapshack-1.10.0/src/widgets/CDoubleSpinBox.cpp000644 001750 000144 00000002530 13216234137 022505 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "widgets/CDoubleSpinBox.h" #include CDoubleSpinBox::CDoubleSpinBox(QWidget * parent) : QDoubleSpinBox(parent) { } void CDoubleSpinBox::stepBy(int steps) { QDoubleSpinBox::stepBy(steps); emit valueChangedByStep(value()); } void CDoubleSpinBox::focusInEvent(QFocusEvent *event) { if(!isReadOnly()) { QTimer::singleShot(0, this, SLOT(slotSelectAll())); } QDoubleSpinBox::focusInEvent(event); } qmapshack-1.10.0/src/widgets/CTextEdit.cpp000644 001750 000144 00000002762 13216234137 021531 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "widgets/CTextEdit.h" #include CTextEdit::CTextEdit(QWidget *parent) : QTextEdit(parent) { } void CTextEdit::keyPressEvent(QKeyEvent *event) { if(event->matches(QKeySequence::Paste)) { event->ignore(); paste(); } else { QTextEdit::keyPressEvent(event); } } void CTextEdit::paste() { if(pastePlain) { QClipboard *clip = QApplication::clipboard(); insertPlainText( clip->text() ); } else { QTextEdit::paste(); } } void CTextEdit::setPastePlain(bool plain) { pastePlain = plain; } qmapshack-1.10.0/src/widgets/CFadingIcon.cpp000644 001750 000144 00000003252 13216234137 021773 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CFadingIcon.h" #include CFadingIcon::CFadingIcon(const QPoint& pt, const QString &resource, QWidget *parent) : QLabel(parent) , icon(resource) { setPixmap(icon); QTimer * timer = new QTimer(this); timer->setSingleShot(false); timer->setInterval(100); timer->start(); connect(timer, &QTimer::timeout, this, &CFadingIcon::slotTimeout); move(pt.x() - icon.width()/2, pt.y() - icon.height()/2); show(); } CFadingIcon::~CFadingIcon() { } void CFadingIcon::slotTimeout() { o -= 0.1; if(o <= 0) { deleteLater(); } else { QPixmap tmp(icon.size()); tmp.fill(Qt::transparent); QPainter p(&tmp); p.setOpacity(o); p.drawPixmap(0,0,icon); setPixmap(tmp); } } qmapshack-1.10.0/src/widgets/CTextEditWidget.cpp000644 001750 000144 00000037612 13216234137 022677 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). Contact: http://www.qt-project.org/legal 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, version 3 of the License. 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 "CTextEditWidget.h" #include "helpers/CSettings.h" #include "helpers/Signals.h" #include "widgets/CTemplateWidget.h" #include "widgets/CTextEditWidgetSelMenu.h" #include CTextEditWidget::CTextEditWidget(const QString &html, QWidget * parent) : QDialog(parent) { SETTINGS; bool pastePlain = cfg.value("TextEditWidget/pastePlain", false).toBool(); setupUi(this); selectionWindow = new CTextEditWidgetSelMenu(this, /* font style actions */ actionTextBold, actionTextItalic, actionTextUnderline, /* copy/paste actions */ actionCut, actionCopy, actionPaste ); QScrollBar *vbar = textEdit->verticalScrollBar(); connect(vbar, &QAbstractSlider::valueChanged, this, &CTextEditWidget::textEditScrolled); toolBold->setDefaultAction (actionTextBold); toolItalic->setDefaultAction(actionTextItalic); toolUnder->setDefaultAction (actionTextUnderline); connect(actionTextBold, &QAction::triggered, this, &CTextEditWidget::textBold); connect(actionTextItalic, &QAction::triggered, this, &CTextEditWidget::textItalic); connect(actionTextUnderline, &QAction::triggered, this, &CTextEditWidget::textUnderline); QActionGroup *grp = new QActionGroup(this); grp->addAction(actionAlignLeft); grp->addAction(actionAlignRight); grp->addAction(actionAlignCenter); grp->addAction(actionAlignJustify); connect(grp, &QActionGroup::triggered, this, &CTextEditWidget::textAlign); toolLeft->setDefaultAction(actionAlignLeft); toolCenter->setDefaultAction(actionAlignCenter); toolRight->setDefaultAction(actionAlignRight); toolBlock->setDefaultAction(actionAlignJustify); defaultFont = textEdit->font(); QPixmap pix(24, 24); pix.fill(Qt::black); actionTextColor = new QAction(pix, tr("&Color..."), this); connect(actionTextColor, &QAction::triggered, this, &CTextEditWidget::textColor); toolColor->setDefaultAction(actionTextColor); connect(comboStyle, static_cast(&QComboBox::activated), this, &CTextEditWidget::textStyle); connect(comboFont, &QFontComboBox::currentFontChanged, textEdit, &QTextEdit::setCurrentFont); connect(spinFontSize, static_cast(&QSpinBox::valueChanged), textEdit, &QTextEdit::setFontPointSize); connect(textEdit, &QTextEdit::currentCharFormatChanged, this, &CTextEditWidget::currentCharFormatChanged); connect(textEdit, &QTextEdit::cursorPositionChanged, this, &CTextEditWidget::cursorPositionChanged); connect(textEdit, &QTextEdit::textChanged, this, &CTextEditWidget::cursorPositionChanged); connect(textEdit, &QTextEdit::selectionChanged, this, &CTextEditWidget::selectionChanged); textEdit->setHtml(html); textEdit->setFocus(); fontChanged(textEdit->font()); colorChanged(textEdit->textColor()); alignmentChanged(textEdit->alignment()); toolInsertFromTemplate->setDefaultAction(actionInsertFromTemplate); toolUndo->setDefaultAction(actionUndo); toolRedo->setDefaultAction(actionRedo); toolCut->setDefaultAction(actionCut); toolCopy->setDefaultAction(actionCopy); toolPaste->setDefaultAction(actionPaste); QMenu *menu = new QMenu(this); menu->addAction(actionPastePlain); menu->addAction(actionPasteNormal); toolPaste->setMenu(menu); /* Setup contextmenu for textEdit */ menuTextEdit = new QMenu(this); menuTextEdit->addAction(actionInsertFromTemplate); menuTextEdit->addSeparator(); menuTextEdit->addAction(actionUndo); menuTextEdit->addAction(actionRedo); menuTextEdit->addSeparator(); menuTextEdit->addAction(actionCut); menuTextEdit->addAction(actionCopy); menuTextEdit->addAction(actionPaste); menuTextEdit->addAction(actionDelete); menuTextEdit->addSeparator(); removeFormat = new QMenu(tr("Reset format"), this); { menuTextEdit->addMenu(removeFormat); removeFormat->addAction(actionResetFont); removeFormat->addAction(actionResetLayout); } connect(actionResetFont, &QAction::triggered, this, &CTextEditWidget::resetFont); connect(actionResetLayout, &QAction::triggered, this, &CTextEditWidget::resetLayout); menuTextEdit->addAction(actionSelectAll); actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty()); actionPastePlain->setEnabled(!QApplication::clipboard()->text().isEmpty()); actionUndo->setEnabled(textEdit->document()->isUndoAvailable()); actionRedo->setEnabled(textEdit->document()->isRedoAvailable()); connect(textEdit->document(), &QTextDocument::undoAvailable, actionUndo, &QAction::setEnabled); connect(textEdit->document(), &QTextDocument::redoAvailable, actionRedo, &QAction::setEnabled); connect(actionInsertFromTemplate, &QAction::triggered, this, &CTextEditWidget::insertFromTemplate); connect(actionUndo, &QAction::triggered, textEdit, &QTextEdit::undo); connect(actionRedo, &QAction::triggered, textEdit, &QTextEdit::redo); actionCut->setEnabled(false); actionCopy->setEnabled(false); QActionGroup *pasteGroup = new QActionGroup(this); actionPastePlain->setChecked(pastePlain); actionPasteNormal->setChecked(!pastePlain); pasteGroup->addAction(actionPastePlain); pasteGroup->addAction(actionPasteNormal); connect(pasteGroup, &QActionGroup::triggered, this, &CTextEditWidget::pasteMode); pasteMode(pastePlain ? actionPastePlain : actionPasteNormal); connect(actionCut, &QAction::triggered, textEdit, &QTextEdit::cut); connect(actionCopy, &QAction::triggered, textEdit, &QTextEdit::copy); connect(actionSelectAll, &QAction::triggered, textEdit, &QTextEdit::selectAll); connect(actionPaste, &QAction::triggered, textEdit, &CTextEdit::paste); connect(actionDelete, &QAction::triggered, this, &CTextEditWidget::deleteSelected); connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextEditWidget::customContextMenuRequested); connect(textEdit, &QTextEdit::copyAvailable, actionCut, &QAction::setEnabled); connect(textEdit, &QTextEdit::copyAvailable, actionCopy, &QAction::setEnabled); connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &CTextEditWidget::clipboardDataChanged); } CTextEditWidget::~CTextEditWidget() { SETTINGS; cfg.setValue("TextEditWidget/pastePlain", actionPastePlain->isChecked()); } QString CTextEditWidget::getHtml() { QString str = textEdit->toHtml(); QRegExp re(".*(\\).*"); if(re.exactMatch(str)) { str = re.cap(1); QRegExp re1(""); re1.setMinimal(true); str = str.replace("body>","div>").replace(re1,"
"); } return str; } void CTextEditWidget::textBold() { QTextCharFormat fmt; fmt.setFontWeight(actionTextBold->isChecked() ? QFont::Bold : QFont::Normal); mergeFormatOnWordOrSelection(fmt); } void CTextEditWidget::textUnderline() { QTextCharFormat fmt; fmt.setFontUnderline(actionTextUnderline->isChecked()); mergeFormatOnWordOrSelection(fmt); } void CTextEditWidget::textItalic() { QTextCharFormat fmt; fmt.setFontItalic(actionTextItalic->isChecked()); mergeFormatOnWordOrSelection(fmt); } void CTextEditWidget::textAlign(QAction *a) { if (a == actionAlignLeft) { textEdit->setAlignment(Qt::AlignLeft); } else if (a == actionAlignCenter) { textEdit->setAlignment(Qt::AlignHCenter); } else if (a == actionAlignRight) { textEdit->setAlignment(Qt::AlignRight); } else if (a == actionAlignJustify) { textEdit->setAlignment(Qt::AlignJustify); } } void CTextEditWidget::textStyle(int styleIndex) { if (styleIndex > 0) { QTextCursor cursor = textEdit->textCursor(); QTextListFormat::Style style = QTextListFormat::ListDisc; static QTextListFormat::Style indexToFormat[] = { QTextListFormat::ListDisc, QTextListFormat::ListCircle, QTextListFormat::ListSquare, QTextListFormat::ListDecimal, QTextListFormat::ListLowerAlpha, QTextListFormat::ListUpperAlpha, QTextListFormat::ListLowerRoman, QTextListFormat::ListUpperRoman }; if( (unsigned) styleIndex <= sizeof(indexToFormat)/sizeof(QTextListFormat::Style)) { style = indexToFormat[styleIndex - 1]; } cursor.beginEditBlock(); QTextBlockFormat blockFmt = cursor.blockFormat(); QTextListFormat listFmt; if (cursor.currentList()) { listFmt = cursor.currentList()->format(); } else { listFmt.setIndent(blockFmt.indent() + 1); blockFmt.setIndent(0); cursor.setBlockFormat(blockFmt); } listFmt.setStyle(style); cursor.createList(listFmt); cursor.endEditBlock(); } else { resetLayout(); } } void CTextEditWidget::resetLayout() { textEdit->textCursor().setBlockFormat(QTextBlockFormat()); } void CTextEditWidget::resetFont() { QTextCharFormat fmt; fmt.setFontUnderline(false); fmt.setFontWeight(QFont::Normal); fmt.setFontItalic(false); fmt.setForeground(QColor()); fmt.setFont(defaultFont); fmt.setFontPointSize(defaultFont.pointSizeF()); QTextCursor cursor = textEdit->textCursor(); if (!cursor.hasSelection()) { cursor.select(QTextCursor::WordUnderCursor); } cursor.setCharFormat(fmt); fontChanged(defaultFont); colorChanged(QColor()); } void CTextEditWidget::textColor() { QColor col = QColorDialog::getColor(textEdit->textColor(), this); if (!col.isValid()) { return; } QTextCharFormat fmt; fmt.setForeground(col); mergeFormatOnWordOrSelection(fmt); colorChanged(col); } void CTextEditWidget::mergeFormatOnWordOrSelection(const QTextCharFormat &format) { QTextCursor cursor = textEdit->textCursor(); if (!cursor.hasSelection()) { cursor.select(QTextCursor::WordUnderCursor); } cursor.mergeCharFormat(format); textEdit->mergeCurrentCharFormat(format); } void CTextEditWidget::fontChanged(const QFont &f) { actionTextBold->setChecked(f.bold()); actionTextItalic->setChecked(f.italic()); actionTextUnderline->setChecked(f.underline()); } void CTextEditWidget::colorChanged(const QColor &c) { QPixmap pix(16, 16); pix.fill(c); actionTextColor->setIcon(pix); } void CTextEditWidget::alignmentChanged(Qt::Alignment a) { if (a & Qt::AlignLeft) { actionAlignLeft->setChecked(true); } else if (a & Qt::AlignHCenter) { actionAlignCenter->setChecked(true); } else if (a & Qt::AlignRight) { actionAlignRight->setChecked(true); } else if (a & Qt::AlignJustify) { actionAlignJustify->setChecked(true); } } void CTextEditWidget::currentCharFormatChanged(const QTextCharFormat &format) { fontChanged(format.font()); colorChanged(format.foreground().color()); } void CTextEditWidget::cursorPositionChanged() { static QHash styleToIndex({ std::make_pair(QTextListFormat::ListDisc, 1), std::make_pair(QTextListFormat::ListCircle, 2), std::make_pair(QTextListFormat::ListSquare, 3), std::make_pair(QTextListFormat::ListDecimal, 4), std::make_pair(QTextListFormat::ListLowerAlpha, 5), std::make_pair(QTextListFormat::ListUpperAlpha, 6), std::make_pair(QTextListFormat::ListLowerRoman, 7), std::make_pair(QTextListFormat::ListUpperRoman, 8) }); alignmentChanged(textEdit->alignment()); int listStyleIndex = 0; QTextCursor cursor = textEdit->textCursor(); if(cursor.currentList()) { QTextListFormat::Style style = cursor.currentList()->format().style(); if(styleToIndex.contains(style)) { listStyleIndex = styleToIndex[ cursor.currentList()->format().style() ]; } } X______________BlockAllSignals______________X(this); comboStyle->setCurrentIndex(listStyleIndex); const QFont &font = cursor.charFormat().font(); comboFont->setCurrentFont(font); int pointSize = font.pointSize(); if(-1 == pointSize) { // some texts (if pasted from px. a browser) have their font size // specified in pixels instead of points, so we need to convert that QFontInfo info(font); pointSize = info.pointSize(); } spinFontSize->setValue(pointSize); X_____________UnBlockAllSignals_____________X(this); } void CTextEditWidget::clipboardDataChanged() { actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty()); actionPastePlain->setEnabled(!QApplication::clipboard()->text().isEmpty()); } void CTextEditWidget::selectionChanged() { bool hasSel = textEdit->textCursor().hasSelection(); actionDelete->setEnabled (hasSel); removeFormat->setEnabled (hasSel); actionResetFont->setEnabled (hasSel); actionResetLayout->setEnabled(hasSel); updateSelectionWindow(); } void CTextEditWidget::customContextMenuRequested() { menuTextEdit->exec(QCursor::pos()); } void CTextEditWidget::deleteSelected() { textEdit->insertPlainText(QString()); } void CTextEditWidget::textEditScrolled() { updateSelectionWindow(); } void CTextEditWidget::moveEvent(QMoveEvent *event) { updateSelectionWindow(); } void CTextEditWidget::pasteMode(QAction *action) { textEdit->setPastePlain( action == actionPastePlain ); actionPaste->setIcon(action->icon()); } bool CTextEditWidget::event(QEvent *event) { if(event->type() == QEvent::WindowActivate) { updateSelectionWindow(); } else if(event->type() == QEvent::WindowDeactivate) { selectionWindow->hide(); } return QDialog::event(event); } void CTextEditWidget::updateSelectionWindow() { const QTextCursor &cursor = textEdit->textCursor(); const QRect &rect = textEdit->cursorRect(); // don't show the selctionWindow, if there is no selection or // the cursor is not visible if(cursor.hasSelection() && rect.y() >= 0 && rect.y() <= textEdit->height()) { int dy = cursor.anchor() < cursor.position() ? ( 6 + rect.height() ) : ( -6 - selectionWindow->height() ); int dx = -selectionWindow->width() / 2; selectionWindow->move(textEdit->mapToGlobal(QPoint(rect.x(), rect.y())) + QPoint(dx, dy)); selectionWindow->show(); } else { selectionWindow->hide(); } } void CTextEditWidget::insertFromTemplate() { CTemplateWidget dlg(this); if(dlg.exec() == QDialog::Accepted) { textEdit->insertHtml(dlg.text()); } } qmapshack-1.10.0/src/widgets/ITemplateWidget.ui000644 001750 000144 00000007233 13142547572 022565 0ustar00oeichlerxusers000000 000000 ITemplateWidget 0 0 400 300 Insert Template... :/icons/32x32/Template.png:/icons/32x32/Template.png 0 0 Templates Select a path with your own templates. ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png Qt::Vertical 20 40 Preview Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ITemplateWidget accept() 248 254 157 274 buttonBox rejected() ITemplateWidget reject() 316 260 286 274 qmapshack-1.10.0/src/widgets/CTemplateWidget.h000644 001750 000144 00000002734 13216234142 022356 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CTEMPLATEWIDGET_H #define CTEMPLATEWIDGET_H #include #include #include "ui_ITemplateWidget.h" class QGroupBox; class CTemplateWidget : public QDialog, private Ui::ITemplateWidget { Q_OBJECT public: CTemplateWidget(QWidget * parent); virtual ~CTemplateWidget() = default; QString text(); private slots: void slotTemplateActivated(int idx); void slotPreview(); void slotSetPath(); private: void listTemplates(); QString resolveGroup(const QGroupBox * group); QPointer widget; }; #endif //CTEMPLATEWIDGET_H qmapshack-1.10.0/src/widgets/ITextEditWidget.ui000644 001750 000144 00000037415 13142547572 022551 0ustar00oeichlerxusers000000 000000 ITextEditWidget 0 0 504 341 Edit text... 2 Templ. 24 24 Qt::Vertical Undo 24 24 Redo 24 24 Cut 24 24 Copy 24 24 Paste 24 24 QToolButton::MenuButtonPopup Qt::Vertical A:L 24 24 A:C 24 24 A:R 24 24 A:B 24 24 Qt::Horizontal 40 20 2 B 24 24 I 24 24 U 24 24 Qt::Vertical C 24 24 0 0 80 0 80 16777215 1 200 Standard Bullet List (Disc) Bullet List (Circle) Bullet List (Square) Ordered List (Decimal) Ordered List (Alpha lower) Ordered List (Alpha upper) Ordered List (Roman lower) Ordered List (Roman upper) Qt::CustomContextMenu QDialogButtonBox::Cancel|QDialogButtonBox::Ok :/icons/32x32/Undo.png:/icons/32x32/Undo.png Undo Ctrl+Z :/icons/32x32/Redo.png:/icons/32x32/Redo.png Redo Ctrl+Shift+Z :/icons/32x32/Cut.png:/icons/32x32/Cut.png Cut Ctrl+X :/icons/32x32/Copy.png:/icons/32x32/Copy.png Copy Ctrl+C Paste Ctrl+V true :/icons/32x32/TextLeft.png:/icons/32x32/TextLeft.png Align Left Ctrl+L true :/icons/32x32/TextRight.png:/icons/32x32/TextRight.png Align Right Ctrl+R true :/icons/32x32/TextCenter.png:/icons/32x32/TextCenter.png Align Center Ctrl+E true :/icons/32x32/TextJustified.png:/icons/32x32/TextJustified.png Align Block Ctrl+J true :/icons/32x32/TextUnderlined.png:/icons/32x32/TextUnderlined.png Underline Ctrl+U true :/icons/32x32/TextBold.png:/icons/32x32/TextBold.png Bold Ctrl+B true :/icons/32x32/TextItalic.png:/icons/32x32/TextItalic.png Italic Ctrl+I true :/icons/32x32/PastePlain.png:/icons/32x32/PastePlain.png Plain Reset the text's format before pasting Select All Select All Ctrl+A Delete Delete Reset Font Reset Font Reset Layout Reset Layout true :/icons/32x32/PasteNormal.png:/icons/32x32/PasteNormal.png Normal Paste without resetting the text's format :/icons/32x32/Template.png:/icons/32x32/Template.png Insert From Template Create text from template. CTextEdit QTextEdit
widgets/CTextEdit.h
buttonBox accepted() ITextEditWidget accept() 417 331 454 250 buttonBox rejected() ITextEditWidget reject() 417 331 454 250
qmapshack-1.10.0/src/widgets/CDoubleSpinBox.h000644 001750 000144 00000002517 13216234142 022153 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CDOUBLESPINBOX_H #define CDOUBLESPINBOX_H #include class CDoubleSpinBox : public QDoubleSpinBox { Q_OBJECT public slots: void slotSelectAll() { selectAll(); } signals: void valueChangedByStep(double val); public: CDoubleSpinBox(QWidget * parent = nullptr); void stepBy(int steps) override; protected: void focusInEvent(QFocusEvent *event) override; }; #endif // CDOUBLESPINBOX_H qmapshack-1.10.0/src/widgets/CTextEditWidget.h000644 001750 000144 00000004520 13216234142 022330 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). Contact: http://www.qt-project.org/legal 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, version 3 of the License. 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 . **********************************************************************************************/ #ifndef CTEXTEDITWIDGET_H #define CTEXTEDITWIDGET_H #include "ui_ITextEditWidget.h" #include #include #include class CTextEditWidget : public QDialog, private Ui::ITextEditWidget { Q_OBJECT public: CTextEditWidget(const QString &html, QWidget * parent); virtual ~CTextEditWidget(); QString getHtml(); protected: void moveEvent(QMoveEvent *event) override; bool event(QEvent *event) override; private slots: void textBold(); void textUnderline(); void textItalic(); void textStyle(int styleIndex); void textColor(); void textAlign(QAction *a); void resetFont(); void resetLayout(); void currentCharFormatChanged(const QTextCharFormat &format); void cursorPositionChanged(); void selectionChanged(); void clipboardDataChanged(); void customContextMenuRequested(); void pasteMode(QAction *action); void deleteSelected(); void textEditScrolled(); void insertFromTemplate(); private: void mergeFormatOnWordOrSelection(const QTextCharFormat &format); void fontChanged(const QFont &f); void colorChanged(const QColor &c); void alignmentChanged(Qt::Alignment a); void updateSelectionWindow(); QAction *actionTextColor; QMenu *menuTextEdit; QWidget *selectionWindow; QMenu *removeFormat; QFont defaultFont; }; #endif // CTEXTEDITWIDGET_H qmapshack-1.10.0/src/widgets/CFadingIcon.h000644 001750 000144 00000002364 13216234142 021437 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFADINGICON_H #define CFADINGICON_H #include #include class CFadingIcon : public QLabel { Q_OBJECT public: CFadingIcon(const QPoint &pt, const QString& resource, QWidget * parent); virtual ~CFadingIcon(); private slots: void slotTimeout(); private: qreal o = 1.0; QPixmap icon; }; #endif //CFADINGICON_H qmapshack-1.10.0/src/widgets/CColorChooser.h000644 001750 000144 00000002454 13216234142 022037 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCOLORCHOOSER_H #define CCOLORCHOOSER_H #include "ui_IColorChooser.h" #include class QToolButton; class CColorChooser : public QDialog, private Ui::IColorChooser { Q_OBJECT public: CColorChooser(QToolButton * parent); virtual ~CColorChooser() = default; private slots: void slotSelect(QToolButton * button); private: QToolButton* parentButton; }; #endif //CCOLORCHOOSER_H qmapshack-1.10.0/src/widgets/CHistoryListWidget.cpp000644 001750 000144 00000011523 13216234137 023433 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisWorkspace.h" #include "gis/prj/IGisProject.h" #include "widgets/CHistoryListWidget.h" #include "CMainWindow.h" #include CHistoryListWidget::CHistoryListWidget(QWidget *parent) : QListWidget(parent) { setIconSize(QSize(32,32)); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &CHistoryListWidget::itemSelectionChanged, this, &CHistoryListWidget::slotSelectionChanged); connect(this, &CHistoryListWidget::customContextMenuRequested, this, &CHistoryListWidget::slotContextMenu); menu = new QMenu(this); actionCutHistoryBefore = menu->addAction(QIcon("://icons/32x32/CutHistoryBefore.png"), tr("Cut history before"), this, SLOT(slotCutHistoryBefore())); actionCutHistoryAfter = menu->addAction(QIcon("://icons/32x32/CutHistoryAfter.png"), tr("Cut history after"), this, SLOT(slotCutHistoryAfter())); } CHistoryListWidget::~CHistoryListWidget() { } void CHistoryListWidget::setupHistory(IGisItem& gisItem) { blockSignals(true); clear(); key = gisItem.getKey(); const IGisItem::history_t& history = gisItem.getHistory(); //for(const IGisItem::history_event_t& event : history.events) for(int i = 0; i < history.events.size(); i++) { const IGisItem::history_event_t& event = history.events[i]; QString str; QListWidgetItem * item = new QListWidgetItem(this); str = event.time.toString(); if(!event.who.isEmpty()) { str += tr(" by %1").arg(event.who); } str += "\n"; str += event.comment; item->setText(str); item->setIcon(QIcon(event.icon)); if(event.data.isEmpty()) { item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } } if(history.histIdxCurrent < count()) { setCurrentItem(item(history.histIdxCurrent)); } blockSignals(false); } void CHistoryListWidget::slotSelectionChanged() { IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { return; } item->loadHistory(currentRow()); item->updateDecoration(IGisItem::eMarkChanged, IGisItem::eMarkNone); emit sigChanged(); } void CHistoryListWidget::slotContextMenu(const QPoint& point) { if ((count() == 0) || (count() == 1)) // nothing can be done if there is 0 (should not happen) or 1 event in history { return; } actionCutHistoryBefore->setEnabled(currentRow() > 0); actionCutHistoryAfter->setEnabled(currentRow() < count() - 1); QPoint p = mapToGlobal(point); menu->exec(p); } void CHistoryListWidget::slotCutHistoryAfter() { if(currentRow() == (count() - 1)) { return; } IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { return; } item->cutHistoryAfter(); item->updateDecoration(IGisItem::eMarkChanged, IGisItem::eMarkNone); IGisProject * project = dynamic_cast(item->parent()); if(project) { project->setChanged(); } emit sigChanged(); } void CHistoryListWidget::slotCutHistoryBefore() { if (currentRow() == 0) { return; } IGisItem * item = CGisWorkspace::self().getItemByKey(key); if (nullptr == item) { return; } int res = QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("History removal") , tr("The removal is permanent and cannot be undone. " "Do you really want to delete history before this step?") , QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (res == QMessageBox::No) { return; } item->cutHistoryBefore(); item->updateDecoration(IGisItem::eMarkChanged, IGisItem::eMarkNone); IGisProject * project = dynamic_cast(item->parent()); if (project) { project->setChanged(); } emit sigChanged(); } qmapshack-1.10.0/src/widgets/IPhotoAlbum.ui000644 001750 000144 00000004513 12627613666 021723 0ustar00oeichlerxusers000000 000000 IPhotoAlbum 0 0 400 150 0 0 Form 0 0 0 0 0 false 0 0 ... :/icons/32x32/Left.png:/icons/32x32/Left.png false 0 0 ... :/icons/32x32/Right.png:/icons/32x32/Right.png qmapshack-1.10.0/src/widgets/CColorLegend.h000644 001750 000144 00000004006 13216234142 021626 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CCOLORLEGEND_H #define CCOLORLEGEND_H #include #include "gis/trk/CGisItemTrk.h" class CColorLegend : public QWidget, public INotifyTrk { Q_OBJECT public: CColorLegend(QWidget *parent, CGisItemTrk *trk = nullptr); ~CColorLegend(); void setMinimum(qreal min); void setMaximum(qreal max); void setUnit(const QString &unit); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t *pt) override; void setMouseRangeFocus(const CTrackData::trkpt_t *pt1, const CTrackData::trkpt_t *pt2) override {} void setMouseClickFocus(const CTrackData::trkpt_t *pt) override {} protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: int paintLabel(QPainter &p, qreal value); const int colorWidth = 18; const int colorHeight = 256; QRect colorRect; QString unit; qreal minimum = 0; qreal maximum = 0; bool background = false; int xOffset = 1; CGisItemTrk *trk = nullptr; qreal val = NOFLOAT; }; #endif // CCOLORLEGEND_H qmapshack-1.10.0/src/widgets/CTextEditWidgetSelMenu.cpp000644 001750 000144 00000003526 13216234137 024165 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "CTextEditWidgetSelMenu.h" #include "helpers/Signals.h" #include CTextEditWidgetSelMenu::CTextEditWidgetSelMenu(QWidget *parent, QAction *actionTextBold, QAction *actionTextItalic, QAction *actionTextUnderline, QAction *actionCut, QAction *actionCopy, QAction *actionPaste ) : QWidget(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint) { setupUi(this); toolBold->setDefaultAction(actionTextBold); toolItalic->setDefaultAction(actionTextItalic); toolUnder->setDefaultAction(actionTextUnderline); toolCut->setDefaultAction(actionCut); toolCopy->setDefaultAction(actionCopy); toolPaste->setDefaultAction(actionPaste); QRect geo = childrenRect(); geo.adjust(0, 0, 0, 1); setGeometry(geo); } qmapshack-1.10.0/src/widgets/CLineEdit.h000644 001750 000144 00000003663 13216234143 021137 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ /** @brief A QWidget derived from QLineEdit, aiming to provide a simple-to-use wrapper around QLineEdit By default, a readonly CLineEdit looks like an ordinary label, whereas a non-readonly CLineEdit contains blue, underlined text. As soon as the non-readonly widget receives the focus, the color is changed to black, the underline disappears and the modifiable text is selected. */ #ifndef CLINEEDIT_H #define CLINEEDIT_H #include #include #include class CLineEdit : public QLineEdit { Q_OBJECT private: bool initialized; QPalette paletteEdit; QPalette paletteRO; QPalette paletteRW; QFont fontNoUnderline; QFont fontUnderline; void initialize(); void updateStyle(); public slots: void slotSelectAll() { selectAll(); } public: CLineEdit(QWidget *parent = nullptr); void setReadOnly(bool r); protected: void focusInEvent(QFocusEvent *event) override; void focusOutEvent(QFocusEvent *event) override; }; #endif // CLINEEDIT_H qmapshack-1.10.0/src/widgets/IColorChooser.ui000644 001750 000144 00000001712 12705713524 022237 0ustar00oeichlerxusers000000 000000 IColorChooser 0 0 67 16 Dialog 0 0 0 0 0 0 qmapshack-1.10.0/src/widgets/CTemplateWidget.cpp000644 001750 000144 00000017127 13216234137 022717 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CSettings.h" #include "widgets/CTemplateWidget.h" #include #include CTemplateWidget::CTemplateWidget(QWidget *parent) : QDialog(parent) { setupUi(this); connect(comboTemplates, static_cast(&QComboBox::currentIndexChanged), this, &CTemplateWidget::slotTemplateActivated); connect(pushPreview, &QPushButton::pressed, this, &CTemplateWidget::slotPreview); connect(toolPathTemplates, &QToolButton::pressed, this, &CTemplateWidget::slotSetPath); listTemplates(); } void CTemplateWidget::listTemplates() { comboTemplates->clear(); comboTemplates->addItem(tr("choose one...")); comboTemplates->addItem(tr("Hiking Tour Summary (built-in)"), "://templates/Hiking_Tour_Summary.ui"); SETTINGS; const QString& path = cfg.value("TextEditWidget/templatePath", "").toString(); if(!path.isEmpty()) { QDir dir(path); QStringList files = dir.entryList(QStringList("*.ui"), QDir::Files); for(const QString& file : files) { QString name = QFileInfo(file).completeBaseName().replace("_", " "); comboTemplates->addItem(name, dir.absoluteFilePath(file)); } } const QString& data = cfg.value("TextEditWidget/template", "").toString(); const int idx = comboTemplates->findData(data); if(idx != -1) { comboTemplates->setCurrentIndex(idx); } } QString CTemplateWidget::text() { if(widget.isNull()) { return ""; } QString str; QList groups = widget->findChildren(QRegExp("group.*"), Qt::FindDirectChildrenOnly); qSort(groups.begin(), groups.end(), [](const QGroupBox * g1, const QGroupBox * g2){return g1->objectName() < g2->objectName(); }); for(const QGroupBox * group : groups) { str += QString("

%1: ").arg(group->title()); str += resolveGroup(group); str += "

"; } return str; } QString CTemplateWidget::resolveGroup(const QGroupBox * group) { QString str; QList widgets = group->findChildren(QRegExp(".*"), Qt::FindDirectChildrenOnly); qSort(widgets.begin(), widgets.end(), [](const QWidget * w1, const QWidget * w2){return w1->property("order") < w2->property("order"); }); for(const QWidget * w : widgets) { const QString pre(str.isEmpty() ? "" : ", "); { const QCheckBox * obj = dynamic_cast(w); if(obj != nullptr) { if(obj->isChecked()) { str += pre + obj->text().replace("&",""); } continue; } } { const QRadioButton * obj = dynamic_cast(w); if(obj != nullptr) { if(obj->isChecked()) { str += pre + obj->text().replace("&",""); } continue; } } { const QComboBox * obj = dynamic_cast(w); if(obj != nullptr) { if(!obj->currentText().isEmpty()) { str += pre + obj->currentText(); } continue; } } { const QLineEdit * obj = dynamic_cast(w); if(obj != nullptr) { if(!obj->text().simplified().isEmpty()) { str += pre + obj->text(); } continue; } } { const QTextEdit * obj = dynamic_cast(w); if(obj != nullptr) { if(!obj->toPlainText().simplified().isEmpty()) { str += pre + obj->toHtml(); } continue; } } } if(str.isEmpty()) { str += tr("-"); } return str; } void CTemplateWidget::slotSetPath() { SETTINGS; QString path = cfg.value("TextEditWidget/templatePath", QDir::homePath()).toString(); path = QFileDialog::getExistingDirectory(this, tr("Template path..."), path); if(path.isEmpty()) { return; } cfg.setValue("TextEditWidget/templatePath", path); listTemplates(); } void CTemplateWidget::slotTemplateActivated(int idx) { delete widget; if(idx < 1) { pushPreview->setEnabled(false); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); return; } bool success = false; const QString& filename = comboTemplates->itemData(idx).toString(); QFile file(filename); if(!file.open(QFile::ReadOnly)) { widget = new QLabel(tr("Failed to read template file %1.").arg(filename)); } else { QUiLoader loader; widget = loader.load(&file, this); file.close(); if(widget.isNull()) { widget = new QLabel(loader.errorString()); } else { // convert focus chain into a sortable property. quint32 cnt = 0; QWidget * first = nextInFocusChain(); QWidget * next = first; do { if( (dynamic_cast(next) != nullptr) || (dynamic_cast(next) != nullptr) || (dynamic_cast(next) != nullptr) || (dynamic_cast(next) != nullptr) || (dynamic_cast(next) != nullptr) ) { next->setProperty("order", cnt++); } next = next->nextInFocusChain(); } while(next != first); success = true; } } layoutWidget->insertWidget(0,widget); pushPreview->setEnabled(success); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(success); SETTINGS; cfg.setValue("TextEditWidget/template", filename); } void CTemplateWidget::slotPreview() { QTextBrowser * preview = new QTextBrowser(); preview->setAttribute(Qt::WA_DeleteOnClose, true); preview->setWindowModality(Qt::ApplicationModal); preview->setReadOnly(true); preview->setHtml(text()); preview->setWindowTitle(tr("Preview...")); preview->setMinimumWidth(600); preview->move(QApplication::desktop()->screen()->rect().center() - preview->rect().center()); preview->show(); preview->raise(); QAction * action = new QAction(preview); action->setShortcut(Qt::Key_Escape); preview->addAction(action); connect(action, &QAction::triggered, preview, &QTextBrowser::close); } qmapshack-1.10.0/src/CSingleInstanceProxy.cpp000644 001750 000144 00000006451 13216234137 022300 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "CSingleInstanceProxy.h" #include CSingleInstanceProxy::CSingleInstanceProxy(const QStringList filenames) { serverName = CMainWindow::self().getUser(); if(serverName != "QMapShack") { serverName = "QMapShack-" + serverName; } QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(1000)) { // if the connection is successful another instance // is already running. In that case the list of files to // open is sent to the primary instance. And this instance // will be closed imediately. QDataStream stream(&socket); stream << filenames; socket.waitForBytesWritten(3000); // wait for confirmation socket.waitForReadyRead(3000); bool ok; stream >> ok; qDebug() << "Sent parameters to primary instance. Result" << ok; qDebug() << "There can only be one. Exit."; exit(0); } // Looks like we are the first instance. // Create a server socket and wait for other instances to connect. server = new QLocalServer(this); connect(server, &QLocalServer::newConnection, this, &CSingleInstanceProxy::slotNewConnection); server->removeServer(serverName); if(!server->listen(serverName)) { qDebug() << "CSingleInstanceProxy: Failed to start single instance server socket."; } else { qDebug() << "CSingleInstanceProxy: Single instance server socket listening to" << server->fullServerName(); } } CSingleInstanceProxy::~CSingleInstanceProxy() { qDebug() << "CSingleInstanceProxy::~CSingleInstanceProxy()"; } void CSingleInstanceProxy::slotNewConnection() { QLocalSocket * socket = server->nextPendingConnection(); if(socket == nullptr) { return; } // Each secondary instance will send a QStringList with files to open // The list can be empty. if(socket->waitForReadyRead(3000)) { QStringList filenames; QDataStream stream(socket); stream >> filenames; CMainWindow& w = CMainWindow::self(); w.loadGISData(filenames); // confirm that files are loaded stream << true; socket->waitForBytesWritten(3000); // raise the application window to top of desktop w.raise(); QApplication::setActiveWindow(&w); } socket->close(); delete socket; } qmapshack-1.10.0/src/gis/000755 001750 000144 00000000000 13216664445 016306 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/ovl/000755 001750 000144 00000000000 13216664445 017106 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/ovl/CScrOptOvlArea.h000644 001750 000144 00000002754 13216234143 022042 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTOVLAREA_H #define CSCROPTOVLAREA_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptOvlArea.h" class CGisItemOvlArea; class IMouse; class CScrOptOvlArea : public IScrOpt, private Ui::IScrOptOvlArea { Q_OBJECT public: CScrOptOvlArea(CGisItemOvlArea * area, const QPoint &point, IMouse *parent); virtual ~CScrOptOvlArea(); void draw(QPainter& p) override; private slots: void slotEditDetails(); void slotCopy(); void slotDelete(); void slotEdit(); private: IGisItem::key_t key; QPointF anchor; }; #endif //CSCROPTOVLAREA_H qmapshack-1.10.0/src/gis/ovl/CDetailsOvlArea.cpp000644 001750 000144 00000015510 13216234137 022545 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/ovl/CDetailsOvlArea.h" #include "gis/ovl/CGisItemOvlArea.h" #include "helpers/CLinksDialog.h" #include "widgets/CTextEditWidget.h" #include CDetailsOvlArea::CDetailsOvlArea(CGisItemOvlArea &area, QWidget * parent) : QDialog(parent) , area(area) { setupUi(this); QPixmap icon(64,24); for(size_t i = 0; i < CGisItemOvlArea::colorMapSize; ++i) { icon.fill(CGisItemOvlArea::colorMap[i].color); comboColor->addItem(icon,"", CGisItemOvlArea::colorMap[i].color); } for(int i = 0; i < OVL_N_STYLES; ++i) { icon.fill(Qt::white); QPainter p(&icon); p.setPen(Qt::black); p.setBrush(CGisItemOvlArea::brushStyles[i]); p.drawRect(icon.rect()); comboStyle->addItem(icon,"",(int)CGisItemOvlArea::brushStyles[i]); } for(int i = 0; i < OVL_N_WIDTHS; ++i) { comboBorderWidth->addItem(CGisItemOvlArea::lineWidths[i].string, CGisItemOvlArea::lineWidths[i].width); } setupGui(); if(area.isOnDevice()) { toolLock->setDisabled(true); } connect(comboColor, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsOvlArea::slotSetColor); connect(comboBorderWidth, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsOvlArea::slotSetWidth); connect(comboStyle, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsOvlArea::slotSetStyle); connect(checkOpacity, &QCheckBox::toggled, this, &CDetailsOvlArea::slotOpyacity); connect(toolLock, &QToolButton::toggled, this, &CDetailsOvlArea::slotChangeReadOnlyMode); connect(textCmtDesc, &QTextBrowser::anchorClicked, this, static_cast(&CDetailsOvlArea::slotLinkActivated)); connect(lineName, &CLineEdit::textEdited, this, &CDetailsOvlArea::slotNameChanged); connect(lineName, &CLineEdit::editingFinished, this, &CDetailsOvlArea::slotNameChangeFinished); connect(listHistory, &CHistoryListWidget::sigChanged, this, &CDetailsOvlArea::setupGui); } CDetailsOvlArea::~CDetailsOvlArea() { } void CDetailsOvlArea::slotSetColor(int idx) { if(area.isReadOnly() || originator) { return; } area.setColor(idx); setupGui(); } void CDetailsOvlArea::slotSetWidth(int idx) { if(area.isReadOnly() || originator) { return; } area.setWidth(CGisItemOvlArea::lineWidths[idx].width); setupGui(); } void CDetailsOvlArea::slotSetStyle(int idx) { if(area.isReadOnly() || originator) { return; } area.setStyle(CGisItemOvlArea::brushStyles[idx]); setupGui(); } void CDetailsOvlArea::slotOpyacity(bool yes) { if(area.isReadOnly() || originator) { return; } area.setOpacity(yes); setupGui(); } void CDetailsOvlArea::slotChangeReadOnlyMode(bool on) { area.setReadOnlyMode(on); setupGui(); } void CDetailsOvlArea::slotNameChanged(const QString &name) { const QString shownName = name.isEmpty() ? IGisItem::noName : QString(name).replace('&', "&&"); setWindowTitle(shownName); } void CDetailsOvlArea::slotNameChangeFinished() { lineName->clearFocus(); const QString& name = lineName->text(); slotNameChanged(name); if(name != area.getName()) { area.setName(name); setupGui(); } } void CDetailsOvlArea::slotLinkActivated(const QUrl& url) { if(url.toString() == "comment") { CTextEditWidget dlg(area.getComment(), nullptr); if(dlg.exec() == QDialog::Accepted) { area.setComment(dlg.getHtml()); } setupGui(); } else if(url.toString() == "description") { CTextEditWidget dlg(area.getDescription(), nullptr); if(dlg.exec() == QDialog::Accepted) { area.setDescription(dlg.getHtml()); } setupGui(); } else if(url.toString() == "links") { QList links = area.getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { area.setLinks(links); } setupGui(); } else { QDesktopServices::openUrl(url); } } void CDetailsOvlArea::setupGui() { if(originator) { return; } originator = true; bool isReadOnly = area.isReadOnly(); setWindowTitle(area.getName()); labelTainted->setVisible(area.isTainted()); lineName->setText(area.getName()); lineName->setReadOnly(isReadOnly); comboColor->setCurrentIndex (area.getColorIdx()); comboBorderWidth->setCurrentIndex(comboBorderWidth->findData(area.getWidth())); comboStyle->setCurrentIndex (comboStyle->findData (area.getStyle())); comboColor->setEnabled (!isReadOnly); comboBorderWidth->setEnabled(!isReadOnly); comboStyle->setEnabled (!isReadOnly); checkOpacity->setEnabled (!isReadOnly); checkOpacity->setChecked(area.getOpacity()); textCmtDesc->document()->clear(); textCmtDesc->append(IGisItem::createText(isReadOnly, area.getComment(), area.getDescription(), area.getLinks())); textCmtDesc->moveCursor (QTextCursor::Start); textCmtDesc->ensureCursorVisible(); int idx = 0; QList items; const CGisItemOvlArea::area_t& a = area.getAreaData(); for(const CGisItemOvlArea::pt_t& pt : a.pts) { QTreeWidgetItem * item = new QTreeWidgetItem(); item->setText(eColNum,QString::number(idx++)); // position QString str; IUnit::degToStr(pt.lon, pt.lat, str); item->setText(eColPosition,str); items << item; } treeWidget->clear(); treeWidget->addTopLevelItems(items); treeWidget->header()->resizeSections(QHeaderView::ResizeToContents); toolLock->setChecked(isReadOnly); listHistory->setupHistory(area); originator = false; } qmapshack-1.10.0/src/gis/ovl/IScrOptOvlArea.ui000644 001750 000144 00000007301 12541017640 022230 0ustar00oeichlerxusers000000 000000 IScrOptOvlArea 0 0 171 69 Form 3 3 3 3 3 3 View details and edit. ... :/icons/32x32/EditDetails.png:/icons/32x32/EditDetails.png Copy area into another project. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png Delete area from project. ... :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png Qt::Vertical Edit shape of the area. ... :/icons/32x32/AreaMove.png:/icons/32x32/AreaMove.png Qt::Horizontal QSizePolicy::Expanding 1 20 TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse qmapshack-1.10.0/src/gis/ovl/CScrOptOvlArea.cpp000644 001750 000144 00000005717 13216234137 022402 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisWorkspace.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/ovl/CScrOptOvlArea.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" CScrOptOvlArea::CScrOptOvlArea(CGisItemOvlArea *area, const QPoint &point, IMouse *parent) : IScrOpt(parent) , key(area->getKey()) { setupUi(this); setOrigin(point); label->setFont(CMainWindow::self().getMapFont()); label->setText(area->getInfo(IGisItem::eFeatureShowName)); adjustSize(); anchor = area->getPointCloseBy(point); if((anchor - point).manhattanLength() > 50) { anchor = point; } move(anchor.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptOvlArea::hide); connect(toolDelete, &QToolButton::clicked, this, &CScrOptOvlArea::hide); connect(toolCopy, &QToolButton::clicked, this, &CScrOptOvlArea::hide); connect(toolEdit, &QToolButton::clicked, this, &CScrOptOvlArea::hide); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptOvlArea::slotEditDetails); connect(toolDelete, &QToolButton::clicked, this, &CScrOptOvlArea::slotDelete); connect(toolCopy, &QToolButton::clicked, this, &CScrOptOvlArea::slotCopy); connect(toolEdit, &QToolButton::clicked, this, &CScrOptOvlArea::slotEdit); } CScrOptOvlArea::~CScrOptOvlArea() { } void CScrOptOvlArea::slotEditDetails() { CGisWorkspace::self().editItemByKey(key); deleteLater(); } void CScrOptOvlArea::slotCopy() { CGisWorkspace::self().copyItemByKey(key); deleteLater(); } void CScrOptOvlArea::slotDelete() { CGisWorkspace::self().delItemByKey(key); deleteLater(); } void CScrOptOvlArea::slotEdit() { CGisWorkspace::self().editAreaByKey(key); deleteLater(); } void CScrOptOvlArea::draw(QPainter& p) { IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { QWidget::deleteLater(); return; } item->drawHighlight(p); CDraw::bubble(p, geometry(), anchor.toPoint()); } qmapshack-1.10.0/src/gis/ovl/IDetailsOvlArea.ui000644 001750 000144 00000023550 13035437343 022414 0ustar00oeichlerxusers000000 000000 IDetailsOvlArea 0 0 400 400 Dialog 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 true false 0 0 0 0 25 25 The area was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. :/icons/32x32/Tainted.png true Toggle read only mode. You have to open the lock to edit the item. ... :/icons/32x32/UnLock.png :/icons/32x32/Lock.png:/icons/32x32/UnLock.png 22 22 true true Color 64 24 Border width Style 64 24 Opacity 1 Info 0 0 0 0 0 false Points 0 0 0 0 0 # Position Hist. 0 0 0 0 0 CHistoryListWidget QListWidget
widgets/CHistoryListWidget.h
CLineEdit QLineEdit
widgets/CLineEdit.h
toolLock lineName tabWidget comboColor comboBorderWidth comboStyle checkOpacity textCmtDesc treeWidget listHistory
qmapshack-1.10.0/src/gis/ovl/CDetailsOvlArea.h000644 001750 000144 00000003317 13216234143 022211 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSOVLAREA_H #define CDETAILSOVLAREA_H #include "ui_IDetailsOvlArea.h" #include class CGisItemOvlArea; class CDetailsOvlArea : public QDialog, private Ui::IDetailsOvlArea { Q_OBJECT public: CDetailsOvlArea(CGisItemOvlArea &area, QWidget * parent); virtual ~CDetailsOvlArea(); private slots: void slotSetColor(int idx); void slotNameChanged(const QString &name); void slotNameChangeFinished(); void slotSetWidth(int idx); void slotSetStyle(int idx); void slotOpyacity(bool yes); void slotChangeReadOnlyMode(bool on); void slotLinkActivated(const QUrl& url); void setupGui(); private: enum columns_t { eColNum ,eColPosition ,eColMax }; CGisItemOvlArea& area; bool originator = false; }; #endif //CDETAILSOVLAREA_H qmapshack-1.10.0/src/gis/ovl/CGisItemOvlArea.h000644 001750 000144 00000012516 13216234261 022167 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGISITEMOVLAREA_H #define CGISITEMOVLAREA_H #include "gis/IGisItem.h" #include "gis/IGisLine.h" #include #include class IGisProject; class CScrOptOvlArea; class IQlgtOverlay; #define OVL_N_WIDTHS 4 #define OVL_N_STYLES 8 class CGisItemOvlArea : public IGisItem, public IGisLine { Q_DECLARE_TR_FUNCTIONS(CGisItemOvlArea) public: CGisItemOvlArea(const SGisLine& line, const QString &name, IGisProject * project, int idx); CGisItemOvlArea(const CGisItemOvlArea &parentArea, IGisProject * project, int idx, bool clone); CGisItemOvlArea(const QDomNode &xml, IGisProject *project); CGisItemOvlArea(const history_t& hist, const QString& dbHash, IGisProject * project); CGisItemOvlArea(quint64 id, QSqlDatabase& db, IGisProject * project); CGisItemOvlArea(const IQlgtOverlay& ovl, IGisProject *project = nullptr); virtual ~CGisItemOvlArea(); IGisItem * createClone() override; QDataStream& operator<<(QDataStream& stream) override; QDataStream& operator>>(QDataStream& stream) const override; const QString& getName() const override { return area.name.isEmpty() ? noName : area.name; } int getColorIdx() const { return colorIdx; } QString getInfo(quint32 feature) const override; void getPolylineFromData(SGisLine& l) override; const QString& getComment() const override { return area.cmt; } const QString& getDescription() const override { return area.desc; } const QList& getLinks() const override { return area.links; } qint32 getWidth() const { return area.width; } qint32 getStyle() const { return area.style; } bool getOpacity() const { return area.opacity; } QDateTime getTimestamp() const override { return QDateTime(); } void setName(const QString& str); void setColor(size_t idx); void setDataFromPolyline(const SGisLine& l) override; void setWidth(qint32 w); void setStyle(qint32 s); void setOpacity(bool yes); void setComment(const QString& str) override; void setDescription(const QString& str) override; void setLinks(const QList& links) override; void save(QDomNode& gpx, bool strictGpx11) override; void edit() override; using IGisItem::drawItem; void drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) override; void drawLabel(QPainter& p, const QPolygonF& viewport,QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) override; void drawHighlight(QPainter& p) override; IScrOpt * getScreenOptions(const QPoint &origin, IMouse * mouse) override; QPointF getPointCloseBy(const QPoint& screenPos) override; bool isCloseTo(const QPointF& pos) override; bool isWithin(const QRectF& area, selflags_t flags) override; void gainUserFocus(bool yes) override; struct width_t { int width; QString string; }; static const width_t lineWidths[OVL_N_WIDTHS]; static const Qt::BrushStyle brushStyles[OVL_N_STYLES]; protected: void setSymbol() override; public: struct pt_t : public wpt_t { }; struct area_t { // -- all gpx tags - start QString name; QString cmt; QString desc; QString src; QList links; quint64 number = 0; QString type; QVector pts; QString color; qint32 width = 5; qint32 style = Qt::BDiagPattern; bool opacity = false; // secondary data; qreal area; }; const area_t& getAreaData() const { return area; } private: void readArea(const QDomNode& xml, area_t& area); void setColor(const QColor& c); void setIcon(const QString& c); void readAreaDataFromGisLine(const SGisLine &line); void deriveSecondaryData(); QPointF getPolygonCentroid(const QPolygonF& polygon); area_t area; static key_t keyUserFocus; QPen penForeground {Qt::blue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; QPen penBackground {Qt::white, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; /// the track line color QColor color; /// the trackpoint bullet icon QPixmap bullet; /// the track line color by index unsigned colorIdx = 0; QPolygonF polygonArea; QPointer scrOpt; }; #endif //CGISITEMOVLAREA_H qmapshack-1.10.0/src/gis/ovl/CGisItemOvlArea.cpp000644 001750 000144 00000031355 13216234137 022526 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "GeoMath.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/ovl/CDetailsOvlArea.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/ovl/CScrOptOvlArea.h" #include "gis/prj/IGisProject.h" #include "helpers/CDraw.h" #include #include #define DEFAULT_COLOR 4 #define MIN_DIST_CLOSE_TO 10 const CGisItemOvlArea::width_t CGisItemOvlArea::lineWidths[OVL_N_WIDTHS] = { {3, tr("thin")} ,{5, tr("normal")} ,{9, tr("wide")} ,{13, tr("strong")} }; const Qt::BrushStyle CGisItemOvlArea::brushStyles[OVL_N_STYLES] = { Qt::NoBrush , Qt::HorPattern , Qt::VerPattern , Qt::CrossPattern , Qt::BDiagPattern , Qt::FDiagPattern , Qt::DiagCrossPattern , Qt::SolidPattern }; IGisItem::key_t CGisItemOvlArea::keyUserFocus; CGisItemOvlArea::CGisItemOvlArea(const SGisLine &line, const QString &name, IGisProject * project, int idx) : IGisItem(project, eTypeOvl, idx) { area.name = name; readAreaDataFromGisLine(line); flags |= eFlagCreatedInQms|eFlagWriteAllowed; setColor(str2color("")); setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemOvlArea::CGisItemOvlArea(const CGisItemOvlArea& parentArea, IGisProject * project, int idx, bool clone) : IGisItem(project, eTypeOvl, idx) { history = parentArea.history; loadHistory(history.histIdxCurrent); if(clone) { area.name += tr("_Clone"); key.clear(); history.events.clear(); setupHistory(); } if(parentArea.isOnDevice() || !parentArea.isReadOnly()) { flags |= eFlagWriteAllowed; } else { flags &= ~eFlagWriteAllowed; } deriveSecondaryData(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemOvlArea::CGisItemOvlArea(const QDomNode &xml, IGisProject *project) : IGisItem(project, eTypeOvl, project->childCount()) { // --- start read and process data ---- setColor(penForeground.color()); readArea(xml, area); // --- stop read and process data ---- setupHistory(); updateDecoration(eMarkNone, eMarkNone); } CGisItemOvlArea::CGisItemOvlArea(const history_t& hist, const QString &dbHash, IGisProject * project) : IGisItem(project, eTypeOvl, project->childCount()) { history = hist; loadHistory(hist.histIdxCurrent); if(!dbHash.isEmpty()) { lastDatabaseHash = dbHash; } } CGisItemOvlArea::CGisItemOvlArea(quint64 id, QSqlDatabase& db, IGisProject * project) : IGisItem(project, eTypeOvl, NOIDX) { loadFromDb(id, db); } CGisItemOvlArea::~CGisItemOvlArea() { // reset user focus if focused on this track if(key == keyUserFocus) { keyUserFocus.clear(); } } IGisItem * CGisItemOvlArea::createClone() { int idx = -1; IGisProject * project = getParentProject(); if(project) { idx = project->indexOfChild(this); } return new CGisItemOvlArea(*this, project, idx, true); } void CGisItemOvlArea::setSymbol() { setColor(str2color(area.color)); } bool CGisItemOvlArea::isCloseTo(const QPointF& pos) { QMutexLocker lock(&mutexItems); qreal dist = GPS_Math_DistPointPolyline(polygonArea, pos); return dist < 20; } bool CGisItemOvlArea::isWithin(const QRectF& area, selflags_t flags) { return (flags & eSelectionOvl) ? IGisItem::isWithin(area, flags, polygonArea) : false; } QPointF CGisItemOvlArea::getPointCloseBy(const QPoint& screenPos) { QMutexLocker lock(&mutexItems); qint32 i = 0; qint32 idx = NOIDX; qint32 d = NOINT; for(const QPointF &point : polygonArea) { int tmp = (screenPos - point).manhattanLength(); if(tmp < d) { idx = i; d = tmp; } i++; } return (idx < 0) ? NOPOINTF : polygonArea[idx]; } void CGisItemOvlArea::readAreaDataFromGisLine(const SGisLine &l) { QMutexLocker lock(&mutexItems); area.pts.clear(); for(int i = 0; i < l.size(); i++) { area.pts << pt_t(); pt_t& areapt = area.pts.last(); const point_t& pt = l[i]; areapt.lon = pt.coord.x() * RAD_TO_DEG; areapt.lat = pt.coord.y() * RAD_TO_DEG; for(int n = 0; n < pt.subpts.size(); n++) { area.pts << pt_t(); pt_t& areapt = area.pts.last(); const subpt_t& sub = pt.subpts[n]; areapt.lon = sub.coord.x() * RAD_TO_DEG; areapt.lat = sub.coord.y() * RAD_TO_DEG; } } deriveSecondaryData(); } void CGisItemOvlArea::edit() { CDetailsOvlArea dlg(*this, nullptr); dlg.exec(); deriveSecondaryData(); } void CGisItemOvlArea::deriveSecondaryData() { qreal north = -90; qreal east = -180; qreal south = 90; qreal west = 180; for(const pt_t &pt : area.pts) { if(pt.lon < west) { west = pt.lon; } if(pt.lon > east) { east = pt.lon; } if(pt.lat < south) { south = pt.lat; } if(pt.lat > north) { north = pt.lat; } } boundingRect = QRectF(QPointF(west * DEG_TO_RAD, north * DEG_TO_RAD), QPointF(east * DEG_TO_RAD,south * DEG_TO_RAD)); QPolygonF line(area.pts.size()); for(int i = 1; i < area.pts.size(); i++) { qreal a1, a2, d; const pt_t& pt11 = area.pts[i - 1]; const pt_t& pt12 = area.pts[i]; QPointF& pt21 = line[i - 1]; QPointF& pt22 = line[i]; d = GPS_Math_Distance(pt11.lon * DEG_TO_RAD, pt11.lat * DEG_TO_RAD, pt12.lon * DEG_TO_RAD, pt12.lat * DEG_TO_RAD, a1, a2); pt22.rx() = pt21.x() + qCos(a1 * DEG_TO_RAD) * d; pt22.ry() = pt21.y() + qSin(a1 * DEG_TO_RAD) * d; } area.area = 0; int j = line.size() - 1; for(int i = 0; i < line.size(); i++) { area.area += (line[j].x() + line[i].x())*(line[j].y() - line[i].y()); j = i; } area.area = qAbs(area.area/2); } void CGisItemOvlArea::drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) { QMutexLocker lock(&mutexItems); polygonArea.clear(); if(!isVisible(boundingRect, viewport, gis)) { return; } QPointF pt1; for(const pt_t &pt : area.pts) { pt1.setX(pt.lon); pt1.setY(pt.lat); pt1 *= DEG_TO_RAD; polygonArea << pt1; } gis->convertRad2Px(polygonArea); p.save(); p.setOpacity(area.opacity ? 0.3 : 1.0); penBackground.setWidth(area.width + 2); p.setBrush(Qt::NoBrush); p.setPen(penBackground); p.drawPolygon(polygonArea); penForeground.setColor(color); penForeground.setWidth(area.width); p.setBrush(QBrush(color, (Qt::BrushStyle)area.style)); p.setPen(penForeground); p.drawPolygon(polygonArea); p.restore(); } void CGisItemOvlArea::drawLabel(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) { QMutexLocker lock(&mutexItems); if(polygonArea.isEmpty()) { return; } QPointF pt = getPolygonCentroid(polygonArea); QRectF rect = fm.boundingRect(area.name); rect.adjust(-2,-2,2,2); rect.moveCenter(pt); CDraw::text(getName(), p, pt.toPoint(), Qt::darkBlue); blockedAreas << rect; } void CGisItemOvlArea::drawHighlight(QPainter& p) { QMutexLocker lock(&mutexItems); if(polygonArea.isEmpty() || key == keyUserFocus) { return; } p.setBrush(Qt::NoBrush); p.setPen(QPen(QColor(255,0,0,100),11,Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolygon(polygonArea); } void CGisItemOvlArea::gainUserFocus(bool yes) { keyUserFocus = yes ? key : key_t(); } QPointF CGisItemOvlArea::getPolygonCentroid(const QPolygonF& polygon) { qreal x = 0; qreal y = 0; int len = polygon.size(); for(int i = 0; i < len; i++) { x = x + polygon[i].x(); y = y + polygon[i].y(); } x = x / len; y = y / len; return QPointF(x,y); } IScrOpt * CGisItemOvlArea::getScreenOptions(const QPoint& origin, IMouse * mouse) { if(scrOpt.isNull()) { scrOpt = new CScrOptOvlArea(this, origin, mouse); } return scrOpt; } QString CGisItemOvlArea::getInfo(quint32 feature) const { QString unit, val; QString str = "
"; if(feature && eFeatureShowName) { str += "" + getName() + ""; } IUnit::self().meter2area(area.area, val, unit); str += "
\n" + tr("Area: %1%2").arg(val).arg(unit); QString desc = removeHtml(area.desc).simplified(); if(desc.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || (desc.count() < 300)) { str += desc; } else { str += desc.left(297) + "..."; } } QString cmt = removeHtml(area.cmt).simplified(); if((cmt != desc) && cmt.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || (cmt.count() < 300)) { str += cmt; } else { str += cmt.left(297) + "..."; } } return str + "
"; } void CGisItemOvlArea::getPolylineFromData(SGisLine &l) { QMutexLocker lock(&mutexItems); l.clear(); for(const pt_t &pt : area.pts) { l << point_t(QPointF(pt.lon * DEG_TO_RAD, pt.lat * DEG_TO_RAD)); } } void CGisItemOvlArea::setDataFromPolyline(const SGisLine& l) { QMutexLocker lock(&mutexItems); readAreaDataFromGisLine(l); flags |= eFlagTainted; changed(tr("Changed area shape."), "://icons/48x48/AreaMove.png"); updateDecoration(eMarkChanged, eMarkNone); } void CGisItemOvlArea::setName(const QString& str) { setText(CGisListWks::eColumnName, str); area.name = str; changed(tr("Changed name."), "://icons/48x48/EditText.png"); } void CGisItemOvlArea::setWidth(qint32 w) { area.width = w; changed(tr("Changed border width."), "://icons/48x48/TextBold.png"); } void CGisItemOvlArea::setStyle(qint32 s) { area.style = s; changed(tr("Changed fill pattern."), "://icons/48x48/Pattern.png"); } void CGisItemOvlArea::setOpacity(bool yes) { area.opacity = yes; changed(tr("Changed opacity."), "://icons/48x48/Opacity.png"); } void CGisItemOvlArea::setComment(const QString& str) { area.cmt = str; changed(tr("Changed comment."), "://icons/48x48/EditText.png"); } void CGisItemOvlArea::setDescription(const QString& str) { area.desc = str; changed(tr("Changed description."), "://icons/48x48/EditText.png"); } void CGisItemOvlArea::setLinks(const QList& links) { area.links = links; changed(tr("Changed links"), "://icons/48x48/Link.png"); } void CGisItemOvlArea::setColor(size_t idx) { if(idx >= colorMapSize) { return; } setColor(colorMap[idx].color); changed(tr("Changed color"), "://icons/48x48/SelectColor.png"); } void CGisItemOvlArea::setColor(const QColor& c) { size_t n; for(n = 0; n < colorMapSize; n++) { if(colorMap[n].color == c) { colorIdx = n; color = colorMap[n].color; bullet = QPixmap(colorMap[n].bullet); break; } } if(n == colorMapSize) { colorIdx = DEFAULT_COLOR; color = colorMap[DEFAULT_COLOR].color; bullet = QPixmap(colorMap[DEFAULT_COLOR].bullet); } setIcon(color.name()); } void CGisItemOvlArea::setIcon(const QString& c) { area.color = c; icon = QPixmap("://icons/48x48/Area.png"); QPixmap mask( icon.size() ); mask.fill( str2color(c) ); mask.setMask( icon.createMaskFromColor( Qt::transparent ) ); icon = mask.scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation); QTreeWidgetItem::setIcon(CGisListWks::eColumnIcon,icon); } qmapshack-1.10.0/src/gis/IGisLine.cpp000644 001750 000144 00000003766 13216234137 020460 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "dem/CDemDraw.h" #include "gis/CGisDraw.h" #include "gis/IGisLine.h" void IGisLine::point_t::resetElevation() { ele = NOINT; for(int i = 0; i < subpts.size(); i++) { subpts[i].ele = NOINT; } } void SGisLine::updateElevation(CDemDraw * dem) { for(int i = 0; i < size(); i++) { IGisLine::point_t& pt = (*this)[i]; qreal ele = dem->getElevationAt(pt.coord); pt.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); for(int n = 0; n < pt.subpts.size(); n++) { IGisLine::subpt_t& sub = pt.subpts[n]; qreal ele = dem->getElevationAt(sub.coord); sub.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); } } } void SGisLine::updatePixel(CGisDraw * gis) { for(int i = 0; i < size(); i++) { IGisLine::point_t& pt = (*this)[i]; pt.pixel = pt.coord; gis->convertRad2Px(pt.pixel); for(int n = 0; n < pt.subpts.size(); n++) { IGisLine::subpt_t& sub = pt.subpts[n]; sub.pixel = sub.coord; gis->convertRad2Px(sub.pixel); } } } qmapshack-1.10.0/src/gis/CSetupFilter.h000644 001750 000144 00000002434 13216234143 021017 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETUPFILTER_H #define CSETUPFILTER_H #include "ui_ISetupFilter.h" #include class CGisWorkspace; class CSetupFilter : public QWidget, private Ui::ISetupFilter { Q_OBJECT public: CSetupFilter(CGisWorkspace *parent); virtual ~CSetupFilter() = default; private slots: void slotSelect(); private: CGisWorkspace * widgetGisWorkspace; }; #endif //CSETUPFILTER_H qmapshack-1.10.0/src/gis/CGisWorkspace.cpp000644 001750 000144 00000072266 13216234261 021520 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "device/IDevice.h" #include "gis/CGisDatabase.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/CSetupFilter.h" #include "gis/IGisItem.h" #include "gis/db/CDBProject.h" #include "gis/db/CSelectDBFolder.h" #include "gis/db/CSetupFolder.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CCreateRouteFromWpt.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/IRouter.h" #include "gis/trk/CCombineTrk.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "gis/wpt/CProjWpt.h" #include "helpers/CProgressDialog.h" #include "helpers/CSelectCopyAction.h" #include "helpers/CSelectProjectDialog.h" #include "helpers/CSettings.h" #include #include CGisWorkspace * CGisWorkspace::pSelf = nullptr; CGisWorkspace::CGisWorkspace(QMenu *menuProject, QWidget *parent) : QWidget(parent) { pSelf = this; setupUi(this); lineFilter->addAction(actionClearFilter,QLineEdit::TrailingPosition); lineFilter->addAction(actionSetupFilter, QLineEdit::LeadingPosition); treeWks->setExternalMenu(menuProject); SETTINGS; treeWks->header()->restoreState(cfg.value("Workspace/treeWks/state", treeWks->header()->saveState()).toByteArray()); IGisProject::filterMode = IGisProject::filter_mode_e(cfg.value("Workspace/projects/filterMode", IGisProject::filterMode).toInt()); connect(treeWks, &CGisListWks::sigChanged, this, &CGisWorkspace::sigChanged); connect(sliderOpacity, &QSlider::valueChanged, this, &CGisWorkspace::slotSetGisLayerOpacity); connect(lineFilter, &QLineEdit::textChanged, this, &CGisWorkspace::slotFilter); connect(actionSetupFilter, &QAction::triggered, this, &CGisWorkspace::slotSetupFilter); connect(treeWks, &CGisListWks::itemPressed, this, &CGisWorkspace::slotWksItemPressed); connect(treeWks, &CGisListWks::itemSelectionChanged, this, &CGisWorkspace::slotWksItemSelectionChanged); connect(treeWks, &CGisListWks::sigItemDeleted, this, &CGisWorkspace::slotWksItemSelectionChanged); // [Issue #265] Delay the loading of the workspace to make sure the complete IUnit system // is up and running. QTimer::singleShot(500, treeWks, SLOT(slotLoadWorkspace())); } CGisWorkspace::~CGisWorkspace() { SETTINGS; cfg.setValue("Workspace/treeWks/state", treeWks->header()->saveState()); cfg.setValue("Workspace/projects/filterMode", IGisProject::filterMode); /* Explicitly delete workspace here, as database projects use CGisWorkspace upon destruction to signal the database their destruction. */ delete treeWks; } void CGisWorkspace::setOpacity(qreal val) { sliderOpacity->setValue(val * 100); } void CGisWorkspace::postEventForWks(QEvent * event) { QCoreApplication::postEvent(treeWks, event); } void CGisWorkspace::loadGisProject(const QString& filename) { // add project to workspace CCanvas::setOverrideCursor(Qt::WaitCursor, "loadGisProject"); treeWks->blockSignals(true); QMutexLocker lock(&IGisItem::mutexItems); IGisProject * item = IGisProject::create(filename, treeWks); // skip if project is already loaded if(item && treeWks->hasProject(item)) { QMessageBox::information(this, tr("Load project..."), tr("The project \"%1\" is already in the workspace.").arg(item->getName()), QMessageBox::Abort); delete item; item = nullptr; } treeWks->blockSignals(false); CCanvas::restoreOverrideCursor("loadGisProject"); emit sigChanged(); } void CGisWorkspace::slotSetGisLayerOpacity(int val) { CCanvas::gisLayerOpacity = qreal(val)/100; CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas != nullptr) { canvas->update(); } } void CGisWorkspace::applyFilter() { slotFilter(lineFilter->text()); } void CGisWorkspace::slotFilter(const QString& str) { actionClearFilter->setIcon(str.isEmpty() ? QIcon("://icons/32x32/Filter.png") : QIcon("://icons/32x32/Cancel.png")); CCanvas::setOverrideCursor(Qt::WaitCursor, "slotFilter"); QMutexLocker lock(&IGisItem::mutexItems); const int N = treeWks->topLevelItemCount(); for(int n = 0; n < N; n++) { IGisProject * item = dynamic_cast(treeWks->topLevelItem(n)); if(item == nullptr) { continue; } item->filter(str.toUpper()); item->setExpanded(!str.isEmpty()); } CCanvas::restoreOverrideCursor("slotFilter"); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } void CGisWorkspace::slotSetupFilter() { CSetupFilter * setupFilter = new CSetupFilter(this); setupFilter->adjustSize(); setupFilter->move(lineFilter->geometry().topLeft()); setupFilter->show(); } void CGisWorkspace::slotSaveAll() { CCanvas::setOverrideCursor(Qt::WaitCursor, "slotSaveAll"); QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { IGisProject * item = dynamic_cast(treeWks->topLevelItem(i)); if(nullptr == item) { continue; } if(item->canSave()) { item->save(); } else { item->saveAs(); } } CCanvas::restoreOverrideCursor("slotSaveAll"); } void CGisWorkspace::slotWksItemSelectionChanged() { slotWksItemPressed(treeWks->currentItem()); } void CGisWorkspace::slotWksItemPressed(QTreeWidgetItem * i) { IGisItem * item = dynamic_cast(i); if(item != nullptr) { keyWksSelection = item->getKey(); for(CCanvas * canvas : CMainWindow::self().getCanvas()) { canvas->reportStatus("WksSelection", tr("Item Selection: Item selected from workspace list. Click on the map to switch back to normal mouse selection behavior.")); } } else { slotWksItemSelectionReset(); } } void CGisWorkspace::slotWksItemSelectionReset() { keyWksSelection.clear(); for(CCanvas * canvas : CMainWindow::self().getCanvas()) { canvas->reportStatus("WksSelection", ""); } } IGisProject * CGisWorkspace::selectProject() { QString key, name; IGisProject::type_e type = IGisProject::eTypeQms; CSelectProjectDialog dlg(key, name, type, treeWks); if(dlg.exec() == QDialog::Rejected) { return nullptr; } IGisProject *project = nullptr; if(!key.isEmpty()) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { project = dynamic_cast(treeWks->topLevelItem(i)); if(nullptr == project) { continue; } if(key == project->getKey()) { break; } } } else if(type == IGisProject::eTypeDb) { quint64 idParent; QString db; QString host; IDBFolder::type_e type; CSelectDBFolder dlg1(idParent, db, host, this); if(dlg1.exec() == QDialog::Rejected) { return nullptr; } CSetupFolder dlg2(type, name, false, this); if(dlg2.exec() == QDialog::Rejected) { return nullptr; } QMutexLocker lock(&IGisItem::mutexItems); CEvtW2DCreate evt(name, type, idParent, db, host); CGisDatabase::self().sendEventForDb(&evt); if(evt.idChild) { CDBProject * p = nullptr; while(nullptr == p) { QApplication::processEvents(QEventLoop::WaitForMoreEvents|QEventLoop::ExcludeUserInputEvents, 100); p = dynamic_cast(treeWks->getProjectById(evt.idChild, db)); } /* Creating a project usually does initiate an info request. However as the project isn't in the workspace the moment we create it, the request will fail. That is why we send the info now. */ p->postStatus(false); project = p; } } else if(!name.isEmpty()) { QMutexLocker lock(&IGisItem::mutexItems); if(type == IGisProject::eTypeGpx) { project = new CGpxProject(name, treeWks); } else if (type == IGisProject::eTypeQms) { project = new CQmsProject(name, treeWks); } } return project; } void CGisWorkspace::getItemsByPos(const QPointF& pos, QList& items) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(project) { project->getItemsByPos(pos, items); continue; } IDevice * device = dynamic_cast(item); if(device) { device->getItemsByPos(pos, items); continue; } } /* If there is an item selected by the workspace limit the list of items to this item. But only if the item is part of the items close to position. */ if(!keyWksSelection.item.isEmpty() && !items.isEmpty()) { IGisItem * item = getItemByKey(keyWksSelection); if(item && items.contains(item)) { items.clear(); items << item; } else { items.clear(); } } } void CGisWorkspace::getItemsByKeys(const QList& keys, QList& items) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(project) { project->getItemsByKeys(keys, items); continue; } IDevice * device = dynamic_cast(item); if(device) { device->getItemsByKeys(keys, items); continue; } } } void CGisWorkspace::getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(project) { project->getItemsByArea(area, flags, items); continue; } IDevice * device = dynamic_cast(item); if(device) { device->getItemsByArea(area, flags, items); continue; } } } void CGisWorkspace::getNogoAreas(QVector &areas) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(project) { project->getNogoAreas(areas); continue; } IDevice * device = dynamic_cast(item); if(device) { device->getNogoAreas(areas); continue; } } } void CGisWorkspace::mouseMove(const QPointF& pos) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(project) { project->mouseMove(pos); continue; } } } IGisItem * CGisWorkspace::getItemByKey(const IGisItem::key_t& key) { IGisItem *item = nullptr; QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item1 = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item1); if(project) { if(project->getKey() != key.project) { continue; } item = project->getItemByKey(key); if(nullptr != item) { break; } continue; } IDevice * device = dynamic_cast(item1); if(device) { if(device->getKey() != key.device) { continue; } item = device->getItemByKey(key); if(nullptr != item) { break; } } } return item; } void CGisWorkspace::delItemByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); QMessageBox::StandardButtons last = QMessageBox::NoButton; for(int i = 0; i < treeWks->topLevelItemCount(); i++) { IGisProject * project = dynamic_cast(treeWks->topLevelItem(i)); if(nullptr == project) { continue; } if(project->delItemByKey(key, last)) { // update database tree if that is a database project CDBProject * dbp = dynamic_cast(project); if(dbp) { dbp->postStatus(true); } } if(last == QMessageBox::Cancel) { break; } } emit sigChanged(); } void CGisWorkspace::delItemsByKey(const QList &keys) { QMessageBox::StandardButtons last = QMessageBox::NoButton; QSet projects; QSet projectsAll; for(const IGisItem::key_t key : keys) { IGisItem * gisItem = getItemByKey(key); if(nullptr != gisItem) { bool yes = false; IGisProject *project = dynamic_cast(gisItem->parent()); if(nullptr != project) { project->blockUpdateItems(true); yes = project->delItemByKey(gisItem->getKey(), last); /* collect database projects to update their counterpart in the database view, after all operations are done. */ if(yes && project->getType() == IGisProject::eTypeDb) { projects << dynamic_cast(project); } /* Collect all projects to unblock update later on. */ projectsAll << project; } if(last == QMessageBox::Cancel) { break; } } } // make all database projects that are changed to post their new status // this will update the database view. for(CDBProject * project : projects) { project->postStatus(true); } // unblock update for all projects seen for(IGisProject * project : projectsAll) { project->blockUpdateItems(false); } CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } void CGisWorkspace::editItemByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem *item = treeWks->topLevelItem(i); IGisProject *project = dynamic_cast(item); if(nullptr != project) { project->editItemByKey(key); continue; } IDevice * device = dynamic_cast(item); if(nullptr != device) { device->editItemByKey(key); continue; } } emit sigChanged(); } void CGisWorkspace::copyItemByKey(const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); IGisItem *item = getItemByKey(key); if(nullptr == item) { return; } IGisProject *project = selectProject(); if(nullptr == project) { return; } int lastResult = CSelectCopyAction::eResultNone; project->insertCopyOfItem(item, NOIDX, lastResult); emit sigChanged(); } void CGisWorkspace::copyItemsByKey(const QList &keys) { QMutexLocker lock(&IGisItem::mutexItems); IGisProject * project = selectProject(); if(nullptr == project) { return; } int lastResult = CSelectCopyAction::eResultNone; project->blockUpdateItems(true); int cnt = 1; PROGRESS_SETUP(tr("Copy items..."), 0, keys.count(), this); for(const IGisItem::key_t& key : keys) { PROGRESS(cnt++, break); IGisItem * gisItem = getItemByKey(key); if(nullptr != gisItem) { project->insertCopyOfItem(gisItem, NOIDX, lastResult); } } project->blockUpdateItems(false); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } void CGisWorkspace::changeWptSymByKey(const QList& keys, const QString& sym) { QMutexLocker lock(&IGisItem::mutexItems); PROGRESS_SETUP(tr("Change waypoint symbols."), 0, keys.count(), this); int cnt = 0; for(const IGisItem::key_t& key : keys) { PROGRESS(cnt++, break); CGisItemWpt *wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { wpt->setIcon(sym); } } emit sigChanged(); } void CGisWorkspace::projWptByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt *wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { CProjWpt dlg(*wpt, 0); dlg.exec(); } emit sigChanged(); } void CGisWorkspace::moveWptByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt *wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { if(!wpt->setReadOnlyMode(false)) { return; } CCanvas *canvas = CMainWindow::self().getVisibleCanvas(); if(nullptr != canvas) { canvas->setMouseMoveWpt(*wpt); } } } void CGisWorkspace::toggleWptBubble(const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt * wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { wpt->toggleBubble(); } } void CGisWorkspace::deleteWptRadius(const IGisItem::key_t &key) { IGisItem * item = getItemByKey(key); if(nullptr != item) { CGisItemWpt * wpt = dynamic_cast(item); wpt->setProximity(NOFLOAT); } } void CGisWorkspace::toggleWptNogoArea(const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt * wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { wpt->toggleNogoArea(); } } void CGisWorkspace::editWptRadius(const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt *wpt = dynamic_cast(getItemByKey(key)); if(nullptr != wpt) { if(!wpt->setReadOnlyMode(false)) { return; } CCanvas *canvas = CMainWindow::self().getVisibleCanvas(); if(nullptr != canvas) { canvas->setMouseRadiusWpt(*wpt); } } } void CGisWorkspace::addWptByPos(QPointF pt, const QString& label, const QString& desc) const { QString name = label; QString icon; if(!CGisItemWpt::getNewWptData(pt, icon, name)) { return; } IGisProject * project = CGisWorkspace::self().selectProject(); if(nullptr == project) { return; } QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt * wpt = new CGisItemWpt(pt, name, icon, project); if(!desc.isEmpty()) { wpt->setDescription(desc); } wpt->edit(); } void CGisWorkspace::focusTrkByKey(bool yes, const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(nullptr != trk) { trk->gainUserFocus(yes); } emit sigChanged(); } void CGisWorkspace::focusRteByKey(bool yes, const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemRte * rte = dynamic_cast(getItemByKey(key)); if(nullptr != rte) { rte->gainUserFocus(yes); } emit sigChanged(); } void CGisWorkspace::convertRouteToTrack(const IGisItem::key_t &key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemRte * rte = dynamic_cast(getItemByKey(key)); if(nullptr != rte) { rte->toTrack(); } emit sigChanged(); } void CGisWorkspace::cutTrkByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(nullptr != trk && trk->cut()) { int res = QMessageBox::question(this, tr("Cut Track..."), tr("Do you want to delete the original track?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::Ok); if(res == QMessageBox::Ok) { delete trk; } } emit sigChanged(); } void CGisWorkspace::reverseTrkByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(nullptr != trk) { trk->reverse(); } emit sigChanged(); } void CGisWorkspace::combineTrkByKey(const IGisItem::key_t& keyTrk) { QMutexLocker lock(&IGisItem::mutexItems); QList keys; IGisItem * item = dynamic_cast(getItemByKey(keyTrk)); if(item == nullptr) { return; } keys << keyTrk; IGisProject * project = dynamic_cast(item->parent()); if(project == nullptr) { return; } const int N = project->childCount(); for(int i = 0; i < N; i++) { CGisItemTrk * trk = dynamic_cast(project->child(i)); if(trk != nullptr) { const IGisItem::key_t& key = trk->getKey(); if(key != keyTrk) { keys << key; } } } combineTrkByKey(keys, {keyTrk}); } void CGisWorkspace::combineTrkByKey(const QList& keys, const QList& keysPreSel) { if(keys.isEmpty()) { return; } QMutexLocker lock(&IGisItem::mutexItems); CCombineTrk dlg(keys, keysPreSel, this); dlg.exec(); emit sigChanged(); } void CGisWorkspace::activityTrkByKey(const QList& keys) { if(keys.isEmpty()) { return; } quint32 flags = CActivityTrk::selectActivity(this); if(0xFFFFFFFF != flags) { QMutexLocker lock(&IGisItem::mutexItems); for(const IGisItem::key_t& key : keys) { CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(trk != nullptr) { trk->setActivity(flags); } } } } void CGisWorkspace::editTrkByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(nullptr != trk) { if(!trk->setReadOnlyMode(false)) { return; } CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(nullptr != canvas) { canvas->setMouseEditTrk(*trk); } } } void CGisWorkspace::rangeTrkByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(getItemByKey(key)); if(nullptr != trk) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(nullptr != canvas) { canvas->setMouseRangeTrk(*trk); } } } void CGisWorkspace::copyTrkWithWptByKey(const IGisItem::key_t &key) { QList keys; CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr != trk) { keys << key; const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { if(trkpt.isHidden() || trkpt.keyWpt.item.isEmpty()) { continue; } keys << trkpt.keyWpt; } copyItemsByKey(keys); } } void CGisWorkspace::editRteByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemRte * rte = dynamic_cast(getItemByKey(key)); if(nullptr != rte) { if(!rte->setReadOnlyMode(false)) { return; } CCanvas *canvas = CMainWindow::self().getVisibleCanvas(); if(nullptr != canvas) { canvas->setMouseEditRte(*rte); } } } void CGisWorkspace::calcRteByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemRte * rte = dynamic_cast(getItemByKey(key)); if(nullptr != rte) { rte->calc(); } } void CGisWorkspace::resetRteByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemRte * rte = dynamic_cast(getItemByKey(key)); if(rte != nullptr) { rte->reset(); } } void CGisWorkspace::editAreaByKey(const IGisItem::key_t& key) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemOvlArea * area = dynamic_cast(getItemByKey(key)); if(area != nullptr) { if(!area->setReadOnlyMode(false)) { return; } CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas != nullptr) { canvas->setMouseEditArea(*area); } } } void CGisWorkspace::makeRteFromWpt(const QList& keys) { QMutexLocker lock(&IGisItem::mutexItems); CCreateRouteFromWpt dlg(keys, this); dlg.exec(); } void CGisWorkspace::draw(QPainter& p, const QPolygonF& viewport, CGisDraw * gis) { QFontMetricsF fm(CMainWindow::self().getMapFont()); QList blockedAreas; QMutexLocker lock(&IGisItem::mutexItems); // draw mandatory stuff first for(int i = 0; i < treeWks->topLevelItemCount(); i++) { if(gis->needsRedraw()) { break; } QTreeWidgetItem *item = treeWks->topLevelItem(i); IGisProject *project = dynamic_cast(item); if(nullptr != project) { project->drawItem(p, viewport, blockedAreas, gis); continue; } IDevice *device = dynamic_cast(item); if(nullptr != device) { device->drawItem(p, viewport, blockedAreas, gis); continue; } } // draw optional labels second for(int i = 0; i < treeWks->topLevelItemCount(); i++) { if(gis->needsRedraw()) { break; } QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(nullptr != project) { project->drawLabel(p, viewport, blockedAreas, fm, gis); continue; } IDevice * device = dynamic_cast(item); if(nullptr != device) { device->drawLabel(p, viewport, blockedAreas, fm, gis); continue; } } } void CGisWorkspace::fastDraw(QPainter& p, const QRectF& viewport, CGisDraw *gis) { /* Mutex locking will make map moving very slow if there are many GIS items visible. Remove it for now. But I am not sure if that is a good idea. */ //QMutexLocker lock(&IGisItem::mutexItems); for(int i = 0; i < treeWks->topLevelItemCount(); i++) { QTreeWidgetItem * item = treeWks->topLevelItem(i); IGisProject * project = dynamic_cast(item); if(nullptr != project) { project->drawItem(p, viewport, gis); continue; } IDevice * device = dynamic_cast(item); if(nullptr != device) { device->drawItem(p, viewport, gis); continue; } } IGisItem * item = getItemByKey(keyWksSelection); if(item != nullptr) { item->drawHighlight(p); } } qmapshack-1.10.0/src/gis/Poi.h000644 001750 000144 00000002116 13216234143 017172 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef POI_H #define POI_H #include "units/IUnit.h" struct poi_t { poi_t() : pos(NOPOINTF){} QString name; QString desc; QPointF pos; QSize symbolSize; }; #endif //POI_H qmapshack-1.10.0/src/gis/tnv/000755 001750 000144 00000000000 13216664445 017115 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/tnv/serialization.cpp000644 001750 000144 00000052427 13216234137 022477 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include struct twonav_icon_t { const char * twonav; const char * qlgt; }; static const twonav_icon_t TwoNavIcons[] = { {"City (Capitol)","City (Capitol)"} ,{"City (Large)","City (Large)"} ,{"City (Medium)","City (Medium)"} ,{"City (Small)","City (Small)"} ,{"City (Small)","Small City"} ,{"Closed Box","Geocache"} ,{"Open Box","Geocache Found"} ,{"Red Flag","Flag, Red"} ,{"Blue Flag","Flag, Blue"} ,{"Green Flag","Flag, Green"} ,{"Red Booble","Pin, Red"} ,{"Blue Booble","Pin, Blue"} ,{"Green Booble","Pin, Green"} ,{"Red Cube","Block, Red"} ,{"Blue Cube","Block, Blue"} ,{"Green Cube","Block, Green"} ,{"Blue Diamond","Blue Diamond"} ,{"Green Diamond","Green Diamond"} ,{"Red Diamond","Red Diamond"} ,{"Traditional Cache","Traditional Cache"} ,{"Multi-cache","Multi-cache"} ,{"Unknown Cache","Unknown Cache"} ,{"Wherigo","Wherigo Cache"} ,{"Event Cache","Event Cache"} ,{"Earthcache","Earthcache"} ,{"Letterbox","Letterbox Hybrid"} ,{"Virtual Cache","Virtual Cache"} ,{"Webcam Cache","Webcam Cache"} ,{0,0} }; static QStringList writeCompeTime( const QDateTime& t, bool isTrack) { QStringList result; QString dateFormat; if(!t.isValid()) { if(isTrack) { result << "01-Jan-1970" << "00:00:00.000"; } else { result << "01-Jan-1970" << "00:00:00"; } return result; } QDateTime timestamp = t.toTimeSpec(Qt::UTC); QString monthStrs[] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; QString monthStr = monthStrs[timestamp.date().month()]; if(isTrack) { dateFormat = QString("dd-'%1'-yy").arg(monthStr); } else { dateFormat = QString("dd-'%1'-yyyy").arg(monthStr); } result << timestamp.toString(dateFormat); if(isTrack) { result << timestamp.toString("hh:mm:ss.000"); } else { result << timestamp.toString("hh:mm:ss"); } return result; } static QDateTime readCompeTime(QString str, bool isTrack) { QDateTime timestamp; QRegExp re("([0-9]{2})-([A-Za-z]{3})-.*"); if(re.exactMatch(str)) { QString monthStr = re.cap(2); QHash monthStr2Num { {"JAN", "01"} ,{"FEB", "02"} ,{"MAR", "03"} ,{"APR", "04"} ,{"MAY", "05"} ,{"JUN", "06"} ,{"JUL", "07"} ,{"AUG", "08"} ,{"SEP", "09"} ,{"OCT", "10"} ,{"NOV", "11"} ,{"DEC", "12"} }; str.replace(monthStr, monthStr2Num.value(monthStr.toUpper())); if(isTrack) { timestamp = QDateTime::fromString(str, "dd-MM-yy hh:mm:ss.zzz"); if(timestamp.isValid()) { timestamp = timestamp.addYears(100); } } else { timestamp = QDateTime::fromString(str, "dd-MM-yyyy hh:mm:ss"); } } timestamp.setTimeSpec(Qt::UTC); return timestamp; } static QString iconTwoNav2QlGt(const QString& sym) { int i = 0; while(TwoNavIcons[i].qlgt) { if(sym == TwoNavIcons[i].twonav) { return TwoNavIcons[i].qlgt; } i++; } return sym; } static QString iconQlGt2TwoNav(const QString& sym) { int i = 0; while(TwoNavIcons[i].qlgt) { if(sym == TwoNavIcons[i].qlgt) { return TwoNavIcons[i].twonav; } i++; } return sym; } static QString makeUniqueName(const QString& name, const QDir& dir) { int cnt = 0; QFileInfo fi(name); QString tmp(name); while(dir.exists(tmp)) { tmp = QString("%1_%2.%3").arg(fi.baseName()).arg(cnt++).arg(fi.completeSuffix()); } return tmp; } bool CGisItemTrk::saveTwoNav(const QString &filename) { QFile file(filename); if(!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to open %1.").arg(filename), QMessageBox::Abort); return false; } QDir dir(QFileInfo(filename).absoluteDir()); IGisProject * project = getParentProject(); QTextStream out(&file); out.setCodec(QTextCodec::codecForName("UTF-8")); out << bom; out << "B UTF-8" << endl; out << "G WGS 84" << endl; out << "U 1" << endl; QString name = getName(); name = name.replace(" ","_"); QColor color = getColor(); QStringList list; list << "C"; list << QString::number(color.red()); list << QString::number(color.green()); list << QString::number(color.blue()); list << "5"; // ??? list << "1"; // ??? out << list.join(" ") << endl; out << "s " << name << endl; out << "y " << getKey().item << endl; for(const CTrackData::trkseg_t& seg : trk.segs) { for(const CTrackData::trkpt_t& trkpt : seg.pts) { list.clear(); list << "T"; list << "A"; list << (trkpt.lat > 0 ? QString("%1%2N") : QString("%1%2S")).arg(trkpt.lat,0,'f').arg(QChar(186)); list << (trkpt.lon > 0 ? QString("%1%2E") : QString("%1%2W")).arg(trkpt.lon,0,'f').arg(QChar(186)); list << writeCompeTime(trkpt.time, true); list << "s"; list << QString("%1").arg(trkpt.ele == NOINT ? 0 : trkpt.ele); list << "0.000000"; list << "0.000000"; list << "0.000000"; list << "0"; list << "-1000.000000"; list << "-1.000000"; list << "-1"; list << "-1.000000"; list << "-1"; list << "-1"; list << "-1"; list << "-1.000000"; out << list.join(" ") << endl; if(!trkpt.keyWpt.item.isEmpty() && project) { CGisItemWpt * wpt = dynamic_cast(project->getItemByKey(trkpt.keyWpt)); if(wpt) { QString iconName = wpt->getIconName(); QPixmap icon = wpt->getIcon(); icon = icon.scaledToWidth(15, Qt::SmoothTransformation); iconName = iconQlGt2TwoNav(iconName); iconName = iconName.replace(" ", "_"); icon.save(dir.absoluteFilePath(iconName + ".png")); list.clear(); list << (iconName + ".png"); list << "1"; list << "3"; list << "0"; list << wpt->getName(); out << "a " << list.join(",") << endl; for(const CGisItemWpt::image_t& img : wpt->getImages()) { QString fn = img.info; if(fn.isEmpty()) { fn = QString("picture.png"); } QFileInfo fi(fn); if(!(fi.completeSuffix() == "png")) { fn = fi.baseName() + ".png"; } fn = makeUniqueName(fn, dir); img.pixmap.save(dir.absoluteFilePath(fn)); list.clear(); list << fn; list << "1"; list << "8"; list << "0"; out << "a " << list.join(",") << endl; } QString comment = wpt->getComment(); if(!IGisItem::removeHtml(comment).isEmpty()) { QString filenameCmt = QString("QMS_CMT%1.html").arg(wpt->getKey().item); QFile fileCmt(dir.absoluteFilePath(filenameCmt)); fileCmt.open(QIODevice::WriteOnly); QTextStream stream(&fileCmt); stream << bom << comment; fileCmt.close(); out << "a .\\" << filenameCmt << ",0" << endl; } } } } } return true; } bool CGisItemTrk::readTwoNav(const QString& filename) { QString line("start"); QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to open %1.").arg(filename),QMessageBox::Abort,QMessageBox::Abort); return false; } QTextStream in(&file); in.setCodec(QTextCodec::codecForName("UTF-8")); CTrackData::trkseg_t seg; while(!line.isEmpty()) { line = in.readLine(); switch(line[0].toLatin1()) { case 'B': { QString name = line.mid(1).simplified(); QTextCodec * codec = QTextCodec::codecForName(name.toLatin1()); if(codec) { in.setCodec(codec); } break; } case 'G': { QString name = line.mid(1).simplified(); if(name != "WGS 84") { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Only support lon/lat WGS 84 format."),QMessageBox::Abort,QMessageBox::Abort); return false; } break; } case 'U': { QString name = line.mid(1).simplified(); if(name != "1") { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Only support lon/lat WGS 84 format."),QMessageBox::Abort,QMessageBox::Abort); return false; } break; } case 'C': { QStringList values = line.split(' ', QString::SkipEmptyParts); if(values.size() > 2) { QColor c(values[1].toInt(),values[2].toInt(),values[3].toInt()); setColor(c); } else { values = values[1].split(',',QString::SkipEmptyParts); if(values.size() >= 3) { QColor c(values[0].toInt(),values[1].toInt(),values[2].toInt()); setColor(c); } } break; } case 'T': { CTrackData::trkpt_t pt; QStringList values = line.split(' ', QString::SkipEmptyParts); if(values.size() < 8) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to read data."),QMessageBox::Abort,QMessageBox::Abort); return false; } QString lat = values[2].replace(QChar(186),"").replace(QChar(-3),""); QString lon = values[3].replace(QChar(186),"").replace(QChar(-3),""); IUnit::strToDeg(lat + " " + lon, pt.lon, pt.lat); pt.time = readCompeTime(values[4] + " " + values[5], true); pt.ele = values[7].toFloat(); seg.pts << pt; break; } case 's': { trk.name = line.mid(1).simplified(); trk.name = trk.name.replace("_", " "); break; } case 'y': { key.item = line.mid(1).simplified(); break; } } } file.close(); trk.segs << seg; if(trk.name.isEmpty()) { QFileInfo fi(filename); trk.name = fi.baseName(); } deriveSecondaryData(); return true; } void CGisItemWpt::saveTwoNav(QTextStream& out, const QDir& dir) { QString name = getName(); name = name.replace(" ","_"); QString description = getDescription(); description = removeHtml(description); QStringList list; list << "W"; list << name; list << "A"; list << (wpt.lat > 0 ? QString("%1%2N") : QString("%1%2S")).arg(wpt.lat,0,'f').arg(QChar(186)); list << (wpt.lon > 0 ? QString("%1%2E") : QString("%1%2W")).arg(wpt.lon,0,'f').arg(QChar(186)); list << writeCompeTime(wpt.time, false); list << QString("%1").arg(wpt.ele == NOINT ? 0 : wpt.ele); out << list.join(" ") << " "; out << description << endl; list.clear(); list << iconQlGt2TwoNav(getIconName()); list << "0"; //test position list << "-1.0"; list << "0"; list << QString("%1").arg(QColor(Qt::darkBlue).value()); list << "1"; list << "37"; // 1 Name 2 Beschreibung 4 Symbol 8 Hhe 16 URL 32 Radius list << ""; //wpt->link; list << QString("%1").arg(proximity == NOFLOAT ? 0 : proximity,0,'f'); list << getKey().item; out << "w "; out << list.join(","); out << endl; QString comment = getComment(); if(!IGisItem::removeHtml(comment).isEmpty()) { QString filenameCmt = QString("QMS_CMT%1.html").arg(getKey().item); QFile fileCmt(dir.absoluteFilePath(filenameCmt)); fileCmt.open(QIODevice::WriteOnly); QTextStream stream(&fileCmt); stream << bom << comment; fileCmt.close(); out << "a .\\" << filenameCmt << ",0" << endl; } for(const image_t &img : images) { QString fn = img.info; if(fn.isEmpty()) { fn = QString("picture.png"); } QFileInfo fi(fn); if(!(fi.completeSuffix().toLower() == "png")) { fn = fi.baseName() + ".png"; } fn = makeUniqueName(fn, dir); img.pixmap.save(dir.absoluteFilePath(fn)); out << "a .\\" << fn << endl; } if(isGeocache()) { // write geocache data QDomDocument doc; QDomElement gpxCache = doc.createElement("groundspeak:cache"); writeGcExt(gpxCache); doc.appendChild(gpxCache); out << "e" << endl; out << doc.toString(); out << "ee" << endl; } } bool CTwoNavProject::loadWpts(const QString& filename, const QDir& dir) { wpt_t wpt; QString line("start"); QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to open %1.").arg(filename),QMessageBox::Abort,QMessageBox::Abort); return false; } QTextStream in(&file); in.setCodec(QTextCodec::codecForName("UTF-8")); while(!line.isEmpty()) { line = in.readLine(); switch(line[0].toLatin1()) { case 'B': { QString name = line.mid(1).simplified(); QTextCodec * codec = QTextCodec::codecForName(name.toLatin1()); if(codec) { in.setCodec(codec); } break; } case 'G': { QString name = line.mid(1).simplified(); if(name != "WGS 84") { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Only support lon/lat WGS 84 format."),QMessageBox::Abort,QMessageBox::Abort); return false; } break; } case 'U': { QString name = line.mid(1).simplified(); if(name != "1") { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Only support lon/lat WGS 84 format."),QMessageBox::Abort,QMessageBox::Abort); return false; } break; } case 'W': { if(wpt.valid) { new CGisItemWpt(wpt, this); } wpt = wpt_t(); QStringList values = line.split(' ', QString::SkipEmptyParts); if(values.size() < 8) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to read data."),QMessageBox::Abort,QMessageBox::Abort); return false; } wpt.name = values[1]; QString lat = values[3].replace(QChar(186),"").replace(QChar(-3),""); QString lon = values[4].replace(QChar(186),"").replace(QChar(-3),""); IUnit::strToDeg(lat + " " + lon, wpt.lon, wpt.lat); wpt.time = readCompeTime(values[5] + " " + values[6], false); wpt.ele = values[7].toFloat(); if(values.size() > 7) { QStringList list = values.mid(8); wpt.description = list.join(" "); } break; } case 'w': { QStringList values = line.mid(1).simplified().split(',', QString::KeepEmptyParts); if(values.size() < 10) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to read data."),QMessageBox::Abort,QMessageBox::Abort); return false; } wpt.symbol = iconTwoNav2QlGt(values[0]); wpt.url = values[7]; wpt.prox = values[8].toFloat(); wpt.key = values[9]; if(wpt.prox == 0) { wpt.prox = NOFLOAT; } if(wpt.ele == 0) { wpt.ele = NOINT; } if(wpt.key == "0") { wpt.key.clear(); } wpt.name = wpt.name.replace("_", " "); if(!wpt.key.isEmpty()) { QString filenameCmt = QString("QMS_CMT%1.html").arg(wpt.key); if(QFile::exists(dir.absoluteFilePath(filenameCmt))) { QFile fileCmt(dir.absoluteFilePath(filenameCmt)); if(fileCmt.open(QIODevice::ReadOnly)) { wpt.comment = QTextStream(&fileCmt).readAll(); fileCmt.close(); } } } wpt.valid = true; break; } case 'e': { QString str; while(!in.atEnd()) { line = in.readLine(); if(line == "ee") { break; } str += line; } QString errorMsg; int errorLine = 0; int errorColumn = 0; wpt.gpx.setContent(str, &errorMsg, &errorLine, &errorColumn); break; } case 'a': { img_t img; QStringList values = line.mid(1).simplified().split(',', QString::KeepEmptyParts); if(values.size() < 1) { QMessageBox::information(CMainWindow::getBestWidgetForParent(),tr("Error..."), tr("Failed to read data."),QMessageBox::Abort,QMessageBox::Abort); return false; } QString fn = values[0].simplified(); #ifndef WIN32 fn = fn.replace("\\","/"); #endif QFileInfo fi(dir.absoluteFilePath(fn)); img.image.load(dir.absoluteFilePath(fn)); if(!img.image.isNull()) { img.filename = fi.fileName(); img.info = fi.baseName(); wpt.images << img; } break; } } } if(wpt.valid) { new CGisItemWpt(wpt, this); } return true; } void CGisItemWpt::readTwoNav(const CTwoNavProject::wpt_t &tnvWpt) { wpt.lon = tnvWpt.lon; wpt.lat = tnvWpt.lat; wpt.ele = tnvWpt.ele; proximity = tnvWpt.prox; wpt.time = tnvWpt.time; wpt.name = tnvWpt.name; wpt.cmt = tnvWpt.comment; wpt.desc = tnvWpt.description; wpt.sym = tnvWpt.symbol; key.item = tnvWpt.key; for(const CTwoNavProject::img_t& img : tnvWpt.images) { CGisItemWpt::image_t image; image.fileName = img.filename; image.info = img.info; image.pixmap = img.image; images << image; } const QDomNode& xmlCache = tnvWpt.gpx.namedItem("groundspeak:cache"); if(!xmlCache.isNull()) { readGcExt(xmlCache); } setIcon(); } qmapshack-1.10.0/src/gis/tnv/CTwoNavProject.cpp000644 001750 000144 00000016102 13216234137 022460 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/gpx/CGpxProject.h" #include "gis/qms/CQmsProject.h" #include "gis/tnv/CTwoNavProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CSelectCopyAction.h" #include "helpers/CSettings.h" #include #include CTwoNavProject::CTwoNavProject(const QString &filename, IDevice * parent) : IGisProject(eTypeTwoNav, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/2NavProject.png")); load(filename); sortItems(); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); setToolTip(CGisListWks::eColumnName, getInfo()); updateItems(); valid = true; } CTwoNavProject::CTwoNavProject(const QString &filename, const IGisProject * project, IDevice * parent) : IGisProject(eTypeTwoNav, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/2NavProject.png")); *(IGisProject*)this = *project; int res = CSelectCopyAction::eResultNone; const int N = project->childCount(); for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(project->child(n)); if(item) { insertCopyOfItem(item, NOIDX, res); } } sortItems(); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); setToolTip(CGisListWks::eColumnName, getInfo()); updateItems(); valid = true; } CTwoNavProject::~CTwoNavProject() { } bool CTwoNavProject::save() { bool res = true; mount(); QDir().mkpath(filename); QDir dir(filename); try { QFile fileKey(dir.absoluteFilePath(QString("%1.key").arg(getKey()))); if(!fileKey.open(QIODevice::WriteOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to open %1.").arg(fileKey.fileName()), QMessageBox::Abort); throw -1; } fileKey.close(); QList wpts; QList geocaches; const int N = childCount(); for(int n = 0; n < N; n++) { QTreeWidgetItem * item = child(n); CGisItemTrk * trk = dynamic_cast(item); if(trk) { QString fn = trk->getName(); fn = fn.remove(QRegExp("[^A-Za-z0-9_]")); fn = dir.absoluteFilePath(fn + ".trk"); if(!trk->saveTwoNav(fn)) { throw -1; } } CGisItemWpt * wpt = dynamic_cast(item); if(wpt) { if(wpt->isGeocache()) { geocaches << wpt; } else { wpts << wpt; } } } if(!wpts.isEmpty()) { if(!saveWpts(wpts, dir.absoluteFilePath("waypoints.wpt"), dir)) { throw -1; } } if(!geocaches.isEmpty()) { if(!saveWpts(geocaches, dir.absoluteFilePath("geocaches.wpt"), dir)) { throw -1; } } } catch(int) { res = false; } if(res) { markAsSaved(); } umount(); return res; } bool CTwoNavProject::saveAs() { SETTINGS; QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString(); QString filter = filedialogFilterGPX; QString fn = QFileDialog::getSaveFileName(CMainWindow::getBestWidgetForParent(), tr("Save GIS data to..."), path, filedialogSaveFilters, &filter); if(fn.isEmpty()) { return false; } bool res = false; if(filter == filedialogFilterGPX) { res = CGpxProject::saveAs(fn, *this, false); } else if(filter == filedialogFilterQMS) { res = CQmsProject::saveAs(fn, *this); } else { return false; } path = QFileInfo(fn).absolutePath(); cfg.setValue("Paths/lastGisPath", path); return res; } bool CTwoNavProject::saveWpts(QList& wpts, const QString& filename, const QDir& dir) { QFile file(filename); if(!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to open %1.").arg(filename), QMessageBox::Abort); return false; } QTextStream out(&file); out.setCodec(QTextCodec::codecForName("UTF-8")); qreal north = -90.0; qreal south = 90.0; qreal west = 180.0; qreal east = -180.0; for(CGisItemWpt * wpt : wpts) { QPointF pt = wpt->getPosition(); if(north < pt.y()) { north = pt.y(); } if(south > pt.y()) { south = pt.y(); } if(west > pt.x()) { west = pt.x(); } if(east < pt.x()) { east = pt.x(); } } out << bom; out << "B UTF-8" << endl; out << "G WGS 84" << endl; out << "U 1" << endl; out << "z " << west << ", " << south << ", " << east << ", " << north << endl; for(CGisItemWpt * wpt : wpts) { wpt->saveTwoNav(out, dir); } file.close(); return true; } bool CTwoNavProject::load(const QString& filename) { QDir dir(filename); QStringList entries = dir.entryList(QDir::NoDotAndDotDot|QDir::Dirs|QDir::Files); for(const QString &entry : entries) { QFileInfo fi(entry); if(fi.suffix().toLower() == "key") { key = fi.completeBaseName(); break; } } for(const QString &entry : entries) { QFileInfo fi(entry); if(fi.suffix().toLower() == "trk") { try { new CGisItemTrk(dir.absoluteFilePath(entry), this); } catch(int) { return false; } } else if(fi.suffix().toLower() == "wpt") { if(!loadWpts(dir.absoluteFilePath(entry), dir)) { return false; } } } return true; } qmapshack-1.10.0/src/gis/tnv/CTwoNavProject.h000644 001750 000144 00000004154 13216234143 022126 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CTWONAVPROJECT_H #define CTWONAVPROJECT_H #include "gis/prj/IGisProject.h" class IDevice; class CGisItemTrk; class CGisItemWpt; class QDir; class CTwoNavProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CTwoNavProject) public: CTwoNavProject(const QString &filename, const IGisProject * project, IDevice * parent); CTwoNavProject(const QString &filename, IDevice * parent); virtual ~CTwoNavProject(); struct img_t { QString filename; QString info; QImage image; }; struct wpt_t { wpt_t() : valid(false), lon(0), lat(0), ele(0), prox(0) { } bool valid; QDateTime time; QString name; QString comment; QString description; QString symbol; QString key; QString url; qreal lon; qreal lat; qreal ele; qreal prox; QDomDocument gpx; QList images; }; bool save() override; bool saveAs(); private: bool load(const QString& filename); bool loadWpts(const QString& filename, const QDir& dir); bool saveWpts(QList &wpts, const QString &filename, const QDir& dir); }; #endif //CTWONAVPROJECT_H qmapshack-1.10.0/src/gis/CGisDraw.cpp000644 001750 000144 00000004140 13216234137 020443 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "helpers/CDraw.h" #include CGisDraw::CGisDraw(CCanvas *parent) : IDrawContext("gis", CCanvas::eRedrawGis, parent) { connect(&CGisWorkspace::self(), &CGisWorkspace::sigChanged, this, &CGisDraw::emitSigCanvasUpdate); } CGisDraw::~CGisDraw() { } void CGisDraw::draw(QPainter& p, const QRect& rect) { CGisWorkspace::self().fastDraw(p, rect, this); } void CGisDraw::drawt(buffer_t& currentBuffer) { QPointF pt1 = currentBuffer.ref1; QPointF pt2 = currentBuffer.ref2; QPointF pt3 = currentBuffer.ref3; QPointF pt4 = currentBuffer.ref4; qreal left, right, top, bottom; left = (pt1.x() < pt4.x() ? pt1.x() : pt4.x()); right = (pt2.x() > pt3.x() ? pt2.x() : pt3.x()); top = (pt1.y() < pt2.y() ? pt1.y() : pt2.y()); bottom = (pt4.y() > pt3.y() ? pt4.y() : pt3.y()); QPointF pp = currentBuffer.ref1; convertRad2Px(pp); QRectF rect(QPointF(left,top), QPointF(right, bottom)); QPolygonF viewport; viewport << pt1 << pt2 << pt3 << pt4; QPainter p(¤tBuffer.image); USE_ANTI_ALIASING(p,true); p.translate(-pp); CGisWorkspace::self().draw(p,viewport, this); } qmapshack-1.10.0/src/gis/tcx/000755 001750 000144 00000000000 13216664445 017104 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/tcx/CTcxProject.h000644 001750 000144 00000003712 13216234143 021434 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CTCXPROJECT_H #define CTCXPROJECT_H #include "gis/prj/IGisProject.h" class CTcxProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CTcxProject) public: CTcxProject(const QString &filename, CGisListWks * parent); virtual ~CTcxProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterTCX; } const QString getFileExtension() const override { return "tcx"; } bool canSave() const override { return true; } static bool saveAs(const QString& fn, IGisProject& project); static void loadTcx(const QString &filename, CTcxProject *project); private: void loadTcx(const QString& filename); void loadActivity(const QDomNode& activityRootNode); void loadCourse(const QDomNode& courseRootNode); static void saveAuthor(QDomNode& nodeToAttachAuthor); enum trackType_e { eCourse , eActivity }; QMap trackTypes; //key = itemKey ; value = eCourse or eActivity }; #endif //CTCXPROJECT_H qmapshack-1.10.0/src/gis/tcx/serialization.cpp000644 001750 000144 00000025653 13216234137 022467 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include #include #include static std::initializer_list knownSymbols = { "1stCategory", "2ndCategory", "3rdCategory", "4thCategory", "Danger", "FirstAid", "Food", "HorsCategory", "Left", "Right", "Sprint", "Straight", "Summit", "Valley", "Water" }; void CGisItemWpt::saveTCX(QDomNode& courseNode, const QDateTime crsPtDateTimeToBeSaved) { QDomDocument doc = courseNode.ownerDocument(); QDomElement xmlCrsPt = doc.createElement("CoursePoint"); courseNode.appendChild(xmlCrsPt); xmlCrsPt.appendChild(doc.createElement("Name")); QString str = wpt.name; str.truncate(10); // course point name max size is 10 characters ; see http://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd xmlCrsPt.lastChild().appendChild(doc.createTextNode(str)); xmlCrsPt.appendChild(doc.createElement("Time")); xmlCrsPt.lastChild().appendChild(doc.createTextNode(crsPtDateTimeToBeSaved.toString("yyyy-MM-dd'T'hh:mm:ss'Z'"))); xmlCrsPt.appendChild(doc.createElement("Position")); xmlCrsPt.lastChild().appendChild(doc.createElement("LatitudeDegrees")); str.sprintf("%1.8f", wpt.lat); xmlCrsPt.lastChild().lastChild().appendChild(doc.createTextNode(str)); xmlCrsPt.lastChild().appendChild(doc.createElement("LongitudeDegrees")); str.sprintf("%1.8f", wpt.lon); xmlCrsPt.lastChild().lastChild().appendChild(doc.createTextNode(str)); if (wpt.ele != NOINT) { xmlCrsPt.appendChild(doc.createElement("AltitudeMeters")); xmlCrsPt.lastChild().appendChild(doc.createTextNode(QString::number(wpt.ele))); } QString pointTypeToBeWritten; if (!QSet(knownSymbols).contains(wpt.sym)) { pointTypeToBeWritten = "Generic"; } else { pointTypeToBeWritten = wpt.sym; } xmlCrsPt.appendChild(doc.createElement("PointType")); xmlCrsPt.lastChild().appendChild(doc.createTextNode(pointTypeToBeWritten)); } void CGisItemTrk::saveTCXcourse(QDomNode& coursesNode) { IGisProject * project = getParentProject(); if (nullptr == project) { return; } QDomDocument doc = coursesNode.ownerDocument(); QDomElement courseNode = doc.createElement("Course"); coursesNode.appendChild(courseNode); courseNode.appendChild(doc.createElement("Name")); QString str = this->getName(); str.truncate(15); // course name max size is 15 characters ; see http://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd courseNode.lastChild().appendChild(doc.createTextNode(str)); QDomElement lapElmt = doc.createElement("Lap"); courseNode.appendChild(lapElmt); lapElmt.appendChild(doc.createElement("TotalTimeSeconds")); lapElmt.lastChild().appendChild(doc.createTextNode(QString::number(this->getTotalElapsedSeconds()))); lapElmt.appendChild(doc.createElement("DistanceMeters")); lapElmt.lastChild().appendChild(doc.createTextNode(QString::number(this->getTotalDistance()))); lapElmt.appendChild(doc.createElement("Intensity")); lapElmt.lastChild().appendChild(doc.createTextNode("Active")); QDomElement xmlTrk = doc.createElement("Track"); courseNode.appendChild(xmlTrk); QList trkPtToOverwriteDateTimes; QList wptKeys; for (const CTrackData::trkpt_t& trkpt : trk) { QDomElement xmlTrkpt = doc.createElement("Trackpoint"); xmlTrk.appendChild(xmlTrkpt); xmlTrkpt.appendChild(doc.createElement("Time")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(trkpt.time.toString("yyyy-MM-dd'T'hh:mm:ss'Z'"))); xmlTrkpt.appendChild(doc.createElement("Position")); xmlTrkpt.lastChild().appendChild(doc.createElement("LatitudeDegrees")); QString str; str.sprintf("%1.8f", trkpt.lat); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(str)); xmlTrkpt.lastChild().appendChild(doc.createElement("LongitudeDegrees")); str.sprintf("%1.8f", trkpt.lon); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(str)); qint32 eleToBeWritten = NOINT; if (NOINT != trkpt.ele) // if this trackpoint has elevation { eleToBeWritten = trkpt.ele; // take elevation on the trackpoint } CGisItemWpt * wpt = dynamic_cast(project->getItemByKey(trkpt.keyWpt)); if (nullptr != wpt) // if trackpoint has an attached waypoint { wptKeys << trkpt.keyWpt; // store attached waypoint trkPtToOverwriteDateTimes << trkpt.time; // store trackpoint dateTime if (NOINT != wpt->getElevation()) // if waypoint has elevation { eleToBeWritten = wpt->getElevation(); // take elevation of the waypoint } } if (eleToBeWritten != NOINT) // if valid elevation has been found { xmlTrkpt.appendChild(doc.createElement("AltitudeMeters")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(QString::number(eleToBeWritten))); } xmlTrkpt.appendChild(doc.createElement("DistanceMeters")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(QString::number(trkpt.distance))); if (trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"].toString().size() != 0) { xmlTrkpt.appendChild(doc.createElement("HeartRateBpm")); xmlTrkpt.lastChild().appendChild(doc.createElement("Value")); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"].toString())); } if (trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"].toString().size() != 0) { xmlTrkpt.appendChild(doc.createElement("Cadence")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"].toString())); } } int i = 0; for (const IGisItem::key_t& wptKey : wptKeys) // browse course points { CGisItemWpt *wptItem = dynamic_cast(project->getItemByKey(wptKey)); wptItem->saveTCX(courseNode, trkPtToOverwriteDateTimes[i++]); } } void CGisItemTrk::saveTCXactivity(QDomNode& activitiesNode) { IGisProject * project = getParentProject(); if (nullptr == project) { return; } QDomDocument doc = activitiesNode.ownerDocument(); QDomElement activityNode = doc.createElement("Activity"); activitiesNode.appendChild(activityNode); activityNode.setAttribute("Sport", "Other"); activityNode.appendChild(doc.createElement("Id")); activityNode.lastChild().appendChild(doc.createTextNode(trk.segs[0].pts[0].time.toString("yyyy-MM-dd'T'hh:mm:ss'Z'"))); for (const CTrackData::trkseg_t &seg : trk.segs) { QDomElement lapElmt = doc.createElement("Lap"); activityNode.appendChild(lapElmt); lapElmt.setAttribute("StartTime", seg.pts[0].time.toString("yyyy-MM-dd'T'hh:mm:ss'Z'")); lapElmt.appendChild(doc.createElement("TotalTimeSeconds")); // "totalTime" means "time of this lap" lapElmt.lastChild().appendChild(doc.createTextNode(QString::number(seg.pts.first().time.secsTo(seg.pts.last().time)))); lapElmt.appendChild(doc.createElement("DistanceMeters")); lapElmt.lastChild().appendChild(doc.createTextNode(QString::number(seg.pts.last().distance - seg.pts.first().distance))); lapElmt.appendChild(doc.createElement("Calories")); lapElmt.lastChild().appendChild(doc.createTextNode("0")); // calories are unknown but a "calories" element is mandatory lapElmt.appendChild(doc.createElement("Intensity")); lapElmt.lastChild().appendChild(doc.createTextNode("Active")); lapElmt.appendChild(doc.createElement("TriggerMethod")); lapElmt.lastChild().appendChild(doc.createTextNode("Manual")); QDomElement xmlTrk = doc.createElement("Track"); lapElmt.appendChild(xmlTrk); for (const CTrackData::trkpt_t &trkpt : seg.pts) { QDomElement xmlTrkpt = doc.createElement("Trackpoint"); xmlTrk.appendChild(xmlTrkpt); xmlTrkpt.appendChild(doc.createElement("Time")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(trkpt.time.toString("yyyy-MM-dd'T'hh:mm:ss'Z'"))); xmlTrkpt.appendChild(doc.createElement("Position")); xmlTrkpt.lastChild().appendChild(doc.createElement("LatitudeDegrees")); QString str; str.sprintf("%1.8f", trkpt.lat); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(str)); xmlTrkpt.lastChild().appendChild(doc.createElement("LongitudeDegrees")); str.sprintf("%1.8f", trkpt.lon); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(str)); if (NOINT != trkpt.ele) // if this trackpoint has elevation { xmlTrkpt.appendChild(doc.createElement("AltitudeMeters")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(QString::number(trkpt.ele))); } xmlTrkpt.appendChild(doc.createElement("DistanceMeters")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(QString::number(trkpt.distance))); if (trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"].toString().size() != 0) { xmlTrkpt.appendChild(doc.createElement("HeartRateBpm")); xmlTrkpt.lastChild().appendChild(doc.createElement("Value")); xmlTrkpt.lastChild().lastChild().appendChild(doc.createTextNode(trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"].toString())); } if (trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"].toString().size() != 0) { xmlTrkpt.appendChild(doc.createElement("Cadence")); xmlTrkpt.lastChild().appendChild(doc.createTextNode(trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"].toString())); } } } } qmapshack-1.10.0/src/gis/tcx/CTcxProject.cpp000644 001750 000144 00000053216 13216234137 021776 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Michel Durand zero@cms123.fr 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/tcx/CTcxProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "version.h" #include CTcxProject::CTcxProject(const QString &filename, CGisListWks * parent) : IGisProject(eTypeTcx, filename, parent) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/TcxProject.png")); blockUpdateItems(true); loadTcx(filename); blockUpdateItems(false); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); } void CTcxProject::loadTcx(const QString& filename) { try { loadTcx(filename, this); } catch(QString &errormsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); valid = false; } } void CTcxProject::loadTcx(const QString &filename, CTcxProject *project) { QFile file(filename); // if the file does not exist, the file name is assumed to be a name for a new project if (!file.exists() || QFileInfo(filename).suffix().toLower() != "tcx") { project->filename.clear(); project->setupName(filename); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; return; } if (!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open %1").arg(filename); } QDomDocument xml; QString msg; int line; int column; if (!xml.setContent(&file, false, &msg, &line, &column)) { file.close(); throw tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg); } file.close(); QDomElement xmlTcx = xml.documentElement(); if (xmlTcx.tagName() != "TrainingCenterDatabase") { throw tr("Not a TCX file: %1").arg(filename); } const QDomNodeList& tcxActivities = xmlTcx.elementsByTagName("Activity"); const QDomNodeList& tcxCourses = xmlTcx.elementsByTagName("Course"); if (!tcxActivities.item(0).isElement() && !tcxCourses.item(0).isElement()) { if ( xmlTcx.elementsByTagName("Workout").item(0).isElement() ) { throw tr("This TCX file contains at least 1 workout, but neither an activity nor a course. " "As workouts do not contain position data, they can not be imported to QMapShack."); } else { throw tr("This TCX file does not contain any activity or course: %1").arg(filename); } } for (int i = 0; i < tcxActivities.count(); i++) { project->loadActivity(tcxActivities.item(i)); } for (int i = 0; i < tcxCourses.count(); i++) { project->loadCourse(tcxCourses.item(i)); } project->sortItems(); project->setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; } void CTcxProject::loadActivity(const QDomNode& activityRootNode) { if (activityRootNode.isElement()) { CTrackData trk; trk.name = activityRootNode.toElement().elementsByTagName("Id").item(0).firstChild().nodeValue(); // activities do not have a "Name" but an "Id" instead (containing start date-time) const QDomNodeList& tcxLaps = activityRootNode.toElement().elementsByTagName("Lap"); trk.segs.resize(tcxLaps.count()); for (int i = 0; i < tcxLaps.count(); i++) // browse laps { CTrackData::trkseg_t *seg = &(trk.segs[i]); const QDomNodeList& tcxLapTrackpts = tcxLaps.item(i).toElement().elementsByTagName("Trackpoint"); for (int j = 0; j < tcxLapTrackpts.count(); j++) // browse trackpoints { const QDomElement &positionElement = tcxLapTrackpts.item(j).toElement().elementsByTagName("Position").item(0).toElement(); if (positionElement.isElement()) // if this trackpoint contains position, i.e. GPSr was able to capture position { CTrackData::trkpt_t trkpt; IUnit::parseTimestamp(tcxLapTrackpts.item(j).toElement().elementsByTagName("Time").item(0).firstChild().nodeValue(), trkpt.time); trkpt.lat = positionElement.elementsByTagName("LatitudeDegrees").item(0).firstChild().nodeValue().toDouble(); trkpt.lon = positionElement.elementsByTagName("LongitudeDegrees").item(0).firstChild().nodeValue().toDouble(); trkpt.ele = tcxLapTrackpts.item(j).toElement().elementsByTagName("AltitudeMeters").item(0).firstChild().nodeValue().toDouble(); const QDomElement &HRElement = tcxLapTrackpts.item(j).toElement().elementsByTagName("HeartRateBpm").item(0).toElement(); if (HRElement.isElement()) // if this trackpoint contains heartrate data, i.e. heartrate sensor data has been captured { trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"] = HRElement.elementsByTagName("Value").item(0).firstChild().nodeValue().toDouble(); } const QDomElement &CADElement = tcxLapTrackpts.item(j).toElement().elementsByTagName("Cadence").item(0).toElement(); if (CADElement.isElement()) // if this trackpoint contains cadence data, i.e. cadence sensor data has been captured { trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"] = CADElement.firstChild().nodeValue().toDouble(); } seg->pts.append(trkpt); // 1 TCX lap gives 1 GPX track segment } } } CGisItemTrk *trkItem = new CGisItemTrk(trk, this); trackTypes.insert(trkItem->getKey().item, eActivity); // store the track type according to its key } } void CTcxProject::loadCourse(const QDomNode& courseRootNode) { if (courseRootNode.isElement()) { CTrackData trk; trk.name = courseRootNode.toElement().elementsByTagName("Name").item(0).firstChild().nodeValue(); trk.segs.resize(1); CTrackData::trkseg_t *seg = &(trk.segs[0]); const QDomNodeList& tcxTrackpts = courseRootNode.toElement().elementsByTagName("Trackpoint"); for (int i = 0; i < tcxTrackpts.count(); i++) // browse trackpoints { const QDomElement &positionElement = tcxTrackpts.item(i).toElement().elementsByTagName("Position").item(0).toElement(); if (positionElement.isElement()) // if this trackpoint contains position, i.e. GPSr was able to capture position { CTrackData::trkpt_t trkpt; IUnit::parseTimestamp(tcxTrackpts.item(i).toElement().elementsByTagName("Time").item(0).firstChild().nodeValue(), trkpt.time); trkpt.lat = positionElement.elementsByTagName("LatitudeDegrees").item(0).firstChild().nodeValue().toDouble(); trkpt.lon = positionElement.elementsByTagName("LongitudeDegrees").item(0).firstChild().nodeValue().toDouble(); trkpt.ele = tcxTrackpts.item(i).toElement().elementsByTagName("AltitudeMeters").item(0).firstChild().nodeValue().toDouble(); const QDomElement &HRElement = tcxTrackpts.item(i).toElement().elementsByTagName("HeartRateBpm").item(0).toElement(); if (HRElement.isElement()) // if this trackpoint contains heartrate data, i.e. heartrate sensor data has been captured { trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"] = HRElement.elementsByTagName("Value").item(0).firstChild().nodeValue().toDouble(); } const QDomElement &CADElement = tcxTrackpts.item(i).toElement().elementsByTagName("Cadence").item(0).toElement(); if (CADElement.isElement()) // if this trackpoint contains cadence data, i.e. cadence sensor data has been captured { trkpt.extensions["gpxtpx:TrackPointExtension|gpxtpx:cad"] = CADElement.firstChild().nodeValue().toDouble(); } seg->pts.append(trkpt); } } CGisItemTrk *trkItem = new CGisItemTrk(trk, this); trackTypes.insert(trkItem->getKey().item, eCourse); // store the track type according to its key const QDomNodeList& tcxCoursePts = courseRootNode.toElement().elementsByTagName("CoursePoint"); for (int i = 0; i < tcxCoursePts.count(); i++) // browse course points { QString name = tcxCoursePts.item(i).toElement().elementsByTagName("Name").item(0).firstChild().nodeValue(); qreal lat = tcxCoursePts.item(i).toElement().elementsByTagName("Position").item(0).toElement().elementsByTagName("LatitudeDegrees").item(0).firstChild().nodeValue().toDouble(); qreal lon = tcxCoursePts.item(i).toElement().elementsByTagName("Position").item(0).toElement().elementsByTagName("LongitudeDegrees").item(0).firstChild().nodeValue().toDouble(); qreal ele = tcxCoursePts.item(i).toElement().elementsByTagName("AltitudeMeters").item(0).firstChild().nodeValue().toDouble(); QString icon = tcxCoursePts.item(i).toElement().elementsByTagName("PointType").item(0).firstChild().nodeValue(); // there is no "icon" in course points ; "PointType" is used instead (can be "turn left", "turn right", etc... See list in http://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd) new CGisItemWpt(QPointF(lon, lat), ele, QDateTime::currentDateTime().toUTC(), name, icon, this); // 1 TCX course point gives 1 GPX waypoint } } } bool CTcxProject::saveAs(const QString& fn, IGisProject& project) { QString _fn_ = fn; QFileInfo fi(_fn_); if (fi.suffix().toLower() != "tcx") { _fn_ += ".tcx"; } project.mount(); // safety check for existing files QFile file(_fn_); if (file.exists()) { file.open(QIODevice::ReadOnly); bool createdByQMS = false; // load file content to xml document QDomDocument xmlTcx; if (xmlTcx.setContent(&file, false)) { const QDomNodeList& tcxAuthor = xmlTcx.elementsByTagName("Author"); if (tcxAuthor.item(0).isElement()) { const QDomNodeList& tcxAuthorName = tcxAuthor.item(0).toElement().elementsByTagName("Name"); createdByQMS = tcxAuthorName.item(0).firstChild().nodeValue() == "QMapShack"; } } if (!createdByQMS) { int res = QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("File exists ...") , tr("The file exists and it has not been created by QMapShack. " "If you press 'yes' all data in this file will be lost. " "Even if this file contains data and has been loaded by QMapShack, " "QMapShack might not be able to load and store all elements of this file. " "Those elements will be lost. I recommend to use another file. " "Do you really want to overwrite the file?") , QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (res == QMessageBox::No) { project.umount(); return false; } } file.close(); } // ---- start content of tcx QDomDocument doc; QDomElement tcx = doc.createElement("TrainingCenterDatabase"); doc.appendChild(tcx); tcx.setAttribute("xmlns", "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"); tcx.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); tcx.setAttribute("xsi:schemaLocation", "http://www.garmin.com/xmlschemas/ProfileExtension/v1 http://www.garmin.com/xmlschemas/UserProfilePowerExtensionv1.xsd http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd http://www.garmin.com/xmlschemas/UserProfile/v2 http://www.garmin.com/xmlschemas/UserProfileExtensionv2.xsd"); QList courseTrks, activityTrks; for (int i = 0; i < project.childCount(); i++) // browse tracks in selected project { CGisItemTrk *trkItem = dynamic_cast(project.child(i)); if (nullptr == trkItem) { continue; // not a track } else { if (!trkItem->isTrkTimeValid()) { int res = QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Track with invalid timestamps...") , tr("The track %1 you have selected contains trackpoints with " "invalid timestamps. " "Device might not accept the generated TCX course file if left as is. " "Do you want to apply a filter with constant speed (10 m/s) and continue?").arg(trkItem->getName()) , QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (res == QMessageBox::No) { project.blockUpdateItems(false); return false; } if (res == QMessageBox::Yes) { project.blockUpdateItems(true); // block is necessary as changing the start date will also change the track position in project when project sorting order is "by date" trkItem->filterSpeed(10); } } QMessageBox courseOrActivityMsgBox; courseOrActivityMsgBox.setWindowTitle(tr("Activity or course?")); courseOrActivityMsgBox.setText(tr("QMapShack does not know how track %1 should be saved. " "Do you want to save it as a course or as an activity? " "Remember that only waypoints close enough to the track will be saved when saving as a course. " "Waypoints will not be saved when saving as an activity.").arg(trkItem->getName())); QAbstractButton* pButtonCourse = courseOrActivityMsgBox.addButton(tr("Course"), QMessageBox::AcceptRole); QAbstractButton* pButtonActivity = courseOrActivityMsgBox.addButton(tr("Activity"), QMessageBox::AcceptRole); QAbstractButton* pButtonCancel = courseOrActivityMsgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); CTcxProject *CTcxProjectRef = dynamic_cast(&project); if (nullptr != CTcxProjectRef) // if a TCX project { if (!CTcxProjectRef->trackTypes.contains(trkItem->getKey().item)) // if this is an added track { courseOrActivityMsgBox.exec(); if (courseOrActivityMsgBox.clickedButton() == pButtonCourse) { courseTrks << trkItem; } if (courseOrActivityMsgBox.clickedButton() == pButtonActivity) { activityTrks << trkItem; } if (courseOrActivityMsgBox.clickedButton() == pButtonCancel) { project.blockUpdateItems(false); return false; } } else { if (CTcxProjectRef->trackTypes.value(trkItem->getKey().item) == eCourse) //if a course { courseTrks << trkItem; } if (CTcxProjectRef->trackTypes.value(trkItem->getKey().item) == eActivity) // if an activity { activityTrks << trkItem; } } } else // not a TCX project, then it is necessary to ask for each track { courseOrActivityMsgBox.exec(); if (courseOrActivityMsgBox.clickedButton() == pButtonCourse) { courseTrks << trkItem; } if (courseOrActivityMsgBox.clickedButton() == pButtonActivity) { activityTrks << trkItem; } if (courseOrActivityMsgBox.clickedButton() == pButtonCancel) { project.blockUpdateItems(false); return false; } } } } project.blockUpdateItems(false); QDomNode activitiesNode = doc.createElement("Activities"); if (activityTrks.size() != 0) { tcx.appendChild(activitiesNode); } for (CGisItemTrk *trkToBeSaved : activityTrks) { trkToBeSaved->saveTCXactivity(activitiesNode); } QDomNode coursesNode = doc.createElement("Courses"); if (courseTrks.size() != 0) { tcx.appendChild(coursesNode); } for (CGisItemTrk *trkToBeSaved : courseTrks) { trkToBeSaved->saveTCXcourse(coursesNode); } saveAuthor(tcx); bool res = true; QString msg; if (!file.open(QIODevice::WriteOnly)) { // copied-pasted from CGpxProject::saveAs : // "as saveAs() can be called from the thread that exports a database showing the // message box will crash the app. Therefore we test if the current thread is the // application's main thread. If not we forward the exception. // // Not sure if that is a good concept." msg = tr("Failed to create file '%1'").arg(_fn_); if (QThread::currentThread() == qApp->thread()) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Saving GIS data failed..."), msg, QMessageBox::Abort); } else { throw msg; } res = false; } QTextStream out(&file); out.setCodec("UTF-8"); out << "" << endl; out << doc.toString(); file.close(); if (file.error() != QFile::NoError) { if (QThread::currentThread() == qApp->thread()) { msg = tr("Failed to write file '%1'").arg(_fn_); QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Saving GIS data failed..."), msg, QMessageBox::Abort); } else { throw msg; } res = false; } project.umount(); return res; } void CTcxProject::saveAuthor(QDomNode& nodeToAttachAuthor) { QDomDocument doc = nodeToAttachAuthor.toElement().ownerDocument(); nodeToAttachAuthor.appendChild(doc.createElement("Author")); nodeToAttachAuthor.lastChild().toElement().setAttribute("xsi:type", "Application_t"); nodeToAttachAuthor.lastChild().appendChild(doc.createElement("Name")); nodeToAttachAuthor.lastChild().lastChild().appendChild(doc.createTextNode("QMapShack")); nodeToAttachAuthor.lastChild().appendChild(doc.createElement("Build")); nodeToAttachAuthor.lastChild().lastChild().appendChild(doc.createElement("Version")); nodeToAttachAuthor.lastChild().lastChild().lastChild().appendChild(doc.createElement("VersionMajor")); nodeToAttachAuthor.lastChild().lastChild().lastChild().lastChild().appendChild(doc.createTextNode(_MKSTR(VER_MAJOR))); nodeToAttachAuthor.lastChild().lastChild().lastChild().appendChild(doc.createElement("VersionMinor")); nodeToAttachAuthor.lastChild().lastChild().lastChild().lastChild().appendChild(doc.createTextNode(_MKSTR(VER_MINOR))); nodeToAttachAuthor.lastChild().lastChild().lastChild().appendChild(doc.createElement("BuildMajor")); nodeToAttachAuthor.lastChild().lastChild().lastChild().lastChild().appendChild(doc.createTextNode(_MKSTR(VER_STEP))); nodeToAttachAuthor.lastChild().lastChild().lastChild().appendChild(doc.createElement("BuildMinor")); nodeToAttachAuthor.lastChild().lastChild().lastChild().lastChild().appendChild(doc.createTextNode("0")); nodeToAttachAuthor.lastChild().lastChild().appendChild(doc.createElement("Type")); nodeToAttachAuthor.lastChild().lastChild().lastChild().appendChild(doc.createTextNode("Release")); nodeToAttachAuthor.lastChild().appendChild(doc.createElement("LangID")); nodeToAttachAuthor.lastChild().lastChild().appendChild(doc.createTextNode(QLocale().bcp47Name())); nodeToAttachAuthor.lastChild().appendChild(doc.createElement("PartNumber")); nodeToAttachAuthor.lastChild().lastChild().appendChild(doc.createTextNode("000-00000-00")); // dummy number } qmapshack-1.10.0/src/gis/ISelDevices.ui000644 001750 000144 00000002742 12506165467 021012 0ustar00oeichlerxusers000000 000000 ISelDevices 0 0 321 354 Select devices... Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISelDevices accept() 248 254 157 274 buttonBox rejected() ISelDevices reject() 316 260 286 274 qmapshack-1.10.0/src/gis/IGisDatabase.ui000644 001750 000144 00000006236 13204504054 021116 0ustar00oeichlerxusers000000 000000 IGisDatabase 0 0 345 297 Form 0 0 0 0 0 Qt::CustomContextMenu QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows 20 20 10 - Name Age QFrame::StyledPanel QFrame::Raised 0 0 :/icons/48x48/Help.png To add a database do a right click on the database list above. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true CGisListDB QTreeWidget
gis/CGisListDB.h
qmapshack-1.10.0/src/gis/qms/000755 001750 000144 00000000000 13216664445 017106 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/qms/CQmsProject.h000644 001750 000144 00000003007 13216234143 021435 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQMSPROJECT_H #define CQMSPROJECT_H #include "gis/prj/IGisProject.h" class CQmsProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CQmsProject) public: CQmsProject(const QString& filename, CGisListWks * parent); virtual ~CQmsProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterQMS; } const QString getFileExtension() const override { return "qms"; } bool canSave() const override { return true; } static bool saveAs(const QString& fn, IGisProject& project); }; #endif //CQMSPROJECT_H qmapshack-1.10.0/src/gis/qms/serialization.cpp000644 001750 000144 00000064044 13216234261 022464 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListWks.h" #include "gis/db/CDBProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CLimit.h" #include "helpers/CValue.h" #include #define VER_TRK quint8(5) #define VER_WPT quint8(2) #define VER_RTE quint8(3) #define VER_AREA quint8(1) #define VER_LINK quint8(1) #define VER_TRKSEG quint8(1) #define VER_TRKPT quint8(2) #define VER_RTEPT quint8(2) #define VER_RTESUBPT quint8(2) #define VER_WPT_T quint8(1) #define VER_GC_T quint8(1) #define VER_GCLOG_T quint8(1) #define VER_IMAGE quint8(1) #define VER_PROJECT quint8(5) #define VER_COPYRIGHT quint8(1) #define VER_PERSON quint8(1) #define VER_HIST quint8(1) #define VER_HIST_EVT quint8(3) #define VER_ITEM quint8(3) #define VER_CVALUE quint8(1) #define VER_CLIMIT quint8(1) #define MAGIC_SIZE 10 #define MAGIC_TRK "QMTrk " #define MAGIC_WPT "QMWpt " #define MAGIC_RTE "QMRte " #define MAGIC_AREA "QMArea " #define MAGIC_PROJ "QMProj " QDataStream& operator<<(QDataStream& stream, const IGisItem::link_t& link) { stream << VER_LINK << link.uri << link.text << link.type; return stream; } QDataStream& operator>>(QDataStream& stream, IGisItem::link_t& link) { quint8 version; stream >> version >> link.uri >> link.text >> link.type; return stream; } QDataStream& operator<<(QDataStream& stream, const IGisItem::wpt_t& wpt) { stream << VER_WPT_T; stream << wpt.lat; stream << wpt.lon; stream << wpt.ele; stream << wpt.time; stream << wpt.magvar; stream << wpt.geoidheight; stream << wpt.name; stream << wpt.cmt; stream << wpt.desc; stream << wpt.src; stream << wpt.links; stream << wpt.sym; stream << wpt.type; stream << wpt.fix; stream << wpt.sat; stream << wpt.hdop; stream << wpt.vdop; stream << wpt.pdop; stream << wpt.ageofdgpsdata; stream << wpt.dgpsid; return stream; } QDataStream& operator>>(QDataStream& stream, IGisItem::wpt_t& wpt) { quint8 version; stream >> version; stream >> wpt.lat; stream >> wpt.lon; stream >> wpt.ele; stream >> wpt.time; stream >> wpt.magvar; stream >> wpt.geoidheight; stream >> wpt.name; stream >> wpt.cmt; stream >> wpt.desc; stream >> wpt.src; stream >> wpt.links; stream >> wpt.sym; stream >> wpt.type; stream >> wpt.fix; stream >> wpt.sat; stream >> wpt.hdop; stream >> wpt.vdop; stream >> wpt.pdop; stream >> wpt.ageofdgpsdata; stream >> wpt.dgpsid; return stream; } QDataStream& operator<<(QDataStream& stream, const IGisItem::history_event_t& e) { stream << VER_HIST_EVT; stream << e.time; stream << e.icon; stream << e.comment; stream << e.data; stream << e.hash; stream << e.who; return stream; } QDataStream& operator>>(QDataStream& stream, IGisItem::history_event_t& e) { quint8 version; stream >> version; stream >> e.time; stream >> e.icon; stream >> e.comment; stream >> e.data; if(version > 1) { stream >> e.hash; } if(version > 2) { stream >> e.who; } return stream; } QDataStream& operator<<(QDataStream& stream, const IGisItem::history_t& h) { stream << VER_HIST; stream << h.histIdxInitial; stream << h.histIdxCurrent; stream << h.events; return stream; } QDataStream& operator>>(QDataStream& stream, IGisItem::history_t& h) { quint8 version; stream >> version; stream >> h.histIdxInitial; stream >> h.histIdxCurrent; stream >> h.events; if(h.histIdxCurrent >= h.events.size()) { h.histIdxCurrent = h.events.size() - 1; } if(h.histIdxInitial >= h.events.size()) { h.histIdxInitial = h.events.size() - 1; } if(h.histIdxCurrent < 0) { h.histIdxInitial = NOIDX; h.histIdxCurrent = NOIDX; h.events.clear(); } if(h.histIdxInitial < 0) { h.histIdxInitial = NOIDX; h.histIdxCurrent = NOIDX; h.events.clear(); } return stream; } QDataStream& operator<<(QDataStream& stream, const CGisItemWpt::geocachelog_t& log) { stream << VER_GCLOG_T; stream << log.id; stream << log.date; stream << log.type; stream << log.finderId; stream << log.finder; stream << quint8(log.textIsHtml); stream << log.text; return stream; } QDataStream& operator>>(QDataStream& stream, CGisItemWpt::geocachelog_t& log) { quint8 version, tmp8; stream >> version; stream >> log.id; stream >> log.date; stream >> log.type; stream >> log.finderId; stream >> log.finder; stream >> tmp8; log.textIsHtml = tmp8; stream >> log.text; return stream; } QDataStream& operator<<(QDataStream& stream, const CGisItemWpt::geocache_t& geocache) { stream << VER_GC_T; stream << quint8(geocache.hasData); if(geocache.hasData) { stream << geocache.id; stream << quint8(geocache.available); stream << quint8(geocache.archived); stream << geocache.difficulty; stream << geocache.terrain; stream << geocache.status; stream << geocache.name; stream << geocache.owner; stream << geocache.ownerId; stream << geocache.type; stream << geocache.container; stream << quint8(geocache.shortDescIsHtml); stream << geocache.shortDesc; stream << quint8(geocache.longDescIsHtml); stream << geocache.longDesc; stream << geocache.hint; stream << geocache.country; stream << geocache.state; stream << geocache.locale; stream << geocache.logs; } return stream; } QDataStream& operator>>(QDataStream& stream, CGisItemWpt::geocache_t& geocache) { quint8 version, tmp8; stream >> version; stream >> tmp8; geocache.hasData = tmp8; if(geocache.hasData) { stream >> geocache.id; stream >> tmp8; geocache.available = tmp8; stream >> tmp8; geocache.archived = tmp8; stream >> geocache.difficulty; stream >> geocache.terrain; stream >> geocache.status; stream >> geocache.name; stream >> geocache.owner; stream >> geocache.ownerId; stream >> geocache.type; stream >> geocache.container; stream >> tmp8; geocache.shortDescIsHtml = tmp8; stream >> geocache.shortDesc; stream >> tmp8; geocache.longDescIsHtml = tmp8; stream >> geocache.longDesc; stream >> geocache.hint; stream >> geocache.country; stream >> geocache.state; stream >> geocache.locale; stream >> geocache.logs; } return stream; } QDataStream& operator<<(QDataStream& stream, const CGisItemWpt::image_t& image) { QBuffer imgBuf; image.pixmap.save(&imgBuf,"JPEG"); stream << VER_IMAGE; stream << imgBuf.data(); stream << image.direction; stream << image.info; stream << image.filePath; stream << image.fileName; return stream; } QDataStream& operator>>(QDataStream& stream, CGisItemWpt::image_t& image) { quint8 version; QBuffer imgBuf; stream >> version; stream >> imgBuf.buffer(); stream >> image.direction; stream >> image.info; stream >> image.filePath; stream >> image.fileName; image.pixmap.load(&imgBuf,"JPEG"); return stream; } QDataStream& operator<<(QDataStream& stream, const CTrackData::trkseg_t& seg) { stream << VER_TRKSEG << seg.pts; return stream; } QDataStream& operator>>(QDataStream& stream, CTrackData::trkseg_t& seg) { quint8 version; stream >> version >> seg.pts; return stream; } QDataStream& operator<<(QDataStream& stream, const CTrackData::trkpt_t& pt) { stream << VER_TRKPT << pt.flags; stream << (const IGisItem::wpt_t&)pt; stream << pt.extensions; return stream; } QDataStream& operator>>(QDataStream& stream, CTrackData::trkpt_t& pt) { quint8 version; stream >> version >> pt.flags; stream >> (IGisItem::wpt_t&)pt; if(version > 1) { stream >> pt.extensions; } return stream; } QDataStream& operator<<(QDataStream& stream, const CGisItemRte::subpt_t& pt) { stream << VER_RTESUBPT; stream << pt.lon; stream << pt.lat; stream << pt.type; stream << pt.turn; stream << pt.bearing; stream << pt.streets; stream << pt.instruction; stream << pt.distance; stream << pt.time; stream << pt.ele; return stream; } QDataStream& operator>>(QDataStream& stream, CGisItemRte::subpt_t& pt) { quint8 version; stream >> version; stream >> pt.lon; stream >> pt.lat; stream >> pt.type; stream >> pt.turn; stream >> pt.bearing; stream >> pt.streets; stream >> pt.instruction; stream >> pt.distance; if(version < 2) { quint32 time; stream >> time; } else { stream >> pt.time; stream >> pt.ele; } return stream; } QDataStream& operator<<(QDataStream& stream, const CGisItemRte::rtept_t& pt) { stream << VER_RTEPT << pt.focus << pt.icon; stream << (const IGisItem::wpt_t&)pt; stream << pt.fakeSubpt; stream << pt.subpts; return stream; } QDataStream& operator>>(QDataStream& stream, CGisItemRte::rtept_t& pt) { quint8 version; stream >> version >> pt.focus >> pt.icon; stream >> (IGisItem::wpt_t&)pt; if(version > 1) { stream >> pt.fakeSubpt; stream >> pt.subpts; } return stream; } QDataStream& operator<<(QDataStream& stream, const IGisProject::copyright_t& c) { stream << VER_COPYRIGHT << c.author << c.year << c.license; return stream; } QDataStream& operator>>(QDataStream& stream, IGisProject::copyright_t& c) { quint8 version; stream >> version >> c.author >> c.year >> c.license; return stream; } QDataStream& operator<<(QDataStream& stream, const IGisProject::person_t& p) { stream << VER_PERSON << p.name << p.id << p.domain << p.link; return stream; } QDataStream& operator>>(QDataStream& stream, IGisProject::person_t& p) { quint8 version; stream >> version >> p.name >> p.id >> p.domain >> p.link; return stream; } QDataStream& operator<<(QDataStream& stream, const CValue& v) { stream << VER_CVALUE << quint8(v.mode) << v.valUser; return stream; } QDataStream& operator>>(QDataStream& stream, CValue& v) { quint8 version, mode; stream >> version >> mode >> v.valUser; // lame trick to update object on mode correctly without // triggering a changed mark v.mode = CValue::mode_e(mode); v.setMode(CValue::mode_e(mode)); return stream; } QDataStream& operator<<(QDataStream& stream, const CLimit& l) { stream << VER_CLIMIT << quint8(l.mode) << l.source << l.minUser << l.maxUser; return stream; } QDataStream& operator>>(QDataStream& stream, CLimit& l) { quint8 version, mode; stream >> version >> mode >> l.source >> l.minUser >> l.maxUser; l.mode = CLimit::mode_e(mode); return stream; } // ---------------- main objects --------------------------------- QDataStream& CGisItemTrk::operator>>(QDataStream& stream) const { QByteArray buffer; QDataStream out(&buffer, QIODevice::WriteOnly); out.setByteOrder(QDataStream::LittleEndian); out.setVersion(QDataStream::Qt_5_2); out << key.item; out << flags; out << trk.name; out << trk.cmt; out << trk.desc; out << trk.src; out << trk.links; out << trk.number; out << trk.type; out << trk.color; out << colorSourceLimit; out << lineScale; out << showArrows; out << limitsGraph1; out << limitsGraph2; out << limitsGraph3; out << trk.segs; stream.writeRawData(MAGIC_TRK, MAGIC_SIZE); stream << VER_TRK; stream << qCompress(buffer,9); return stream; } QDataStream& CGisItemTrk::operator<<(QDataStream& stream) { quint8 version; QByteArray buffer; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_TRK,MAGIC_SIZE)) { dev->seek(pos); return stream; } stream >> version; stream >> buffer; buffer = qUncompress(buffer); QDataStream in(&buffer, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in >> key.item; in >> flags; in >> trk.name; in >> trk.cmt; in >> trk.desc; in >> trk.src; in >> trk.links; in >> trk.number; in >> trk.type; in >> trk.color; if(version > 1 && version <= 4) { QString colorSource; in >> colorSource; qreal limitLow, limitHigh; in >> limitLow; in >> limitHigh; colorSourceLimit.source = colorSource; colorSourceLimit.mode = CLimit::eModeAuto; colorSourceLimit.minUser = limitLow; colorSourceLimit.maxUser = limitHigh; } else if(version > 4) { in >> colorSourceLimit; } if(version > 2) { in >> lineScale; in >> showArrows; } if(version > 3) { in >> limitsGraph1; in >> limitsGraph2; in >> limitsGraph3; } trk.segs.clear(); in >> trk.segs; deriveSecondaryData(); setColor(str2color(trk.color)); setText( CGisListWks::eColumnName, getName()); setToolTip(CGisListWks::eColumnName, getInfo(IGisItem::eFeatureShowName)); return stream; } QDataStream& CGisItemWpt::operator<<(QDataStream& stream) { quint8 version; QByteArray buffer; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_WPT,MAGIC_SIZE)) { dev->seek(pos); return stream; } stream >> version; stream >> buffer; buffer = qUncompress(buffer); QDataStream in(&buffer, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in >> key.item; in >> flags; in >> proximity; in >> wpt; in >> geocache; in >> images; if(version > 1) { in >> offsetBubble; in >> widthBubble; } setIcon(); setText (CGisListWks::eColumnName, getName()); setToolTip(CGisListWks::eColumnName, getInfo(IGisItem::eFeatureShowName)); detBoundingRect(); radius = NOFLOAT; return stream; } QDataStream& CGisItemWpt::operator>>(QDataStream& stream) const { QByteArray buffer; QDataStream out(&buffer, QIODevice::WriteOnly); out.setByteOrder(QDataStream::LittleEndian); out.setVersion(QDataStream::Qt_5_2); out << key.item; out << flags; out << proximity; out << wpt; out << geocache; out << images; out << offsetBubble; out << widthBubble; stream.writeRawData(MAGIC_WPT, MAGIC_SIZE); stream << VER_WPT; stream << qCompress(buffer,9); return stream; } QDataStream& CGisItemRte::operator<<(QDataStream& stream) { quint8 version; QByteArray buffer; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_RTE,MAGIC_SIZE)) { dev->seek(pos); return stream; } stream >> version; stream >> buffer; buffer = qUncompress(buffer); QDataStream in(&buffer, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in >> key.item; in >> flags; in >> rte.name; in >> rte.cmt; in >> rte.desc; in >> rte.src; in >> rte.links; in >> rte.number; in >> rte.type; in >> rte.pts; if(version > 1) { in >> rte.lastRoutedWith; in >> rte.lastRoutedTime; in >> rte.totalDistance; in >> rte.totalTime; } if(version > 2) { in >> rte.ascent; in >> rte.descent; } setSymbol(); deriveSecondaryData(); setText (CGisListWks::eColumnName, getName()); setToolTip(CGisListWks::eColumnName, getInfo(IGisItem::eFeatureShowName)); return stream; } QDataStream& CGisItemRte::operator>>(QDataStream& stream) const { QByteArray buffer; QDataStream out(&buffer, QIODevice::WriteOnly); out.setByteOrder(QDataStream::LittleEndian); out.setVersion(QDataStream::Qt_5_2); out << key.item; out << flags; out << rte.name; out << rte.cmt; out << rte.desc; out << rte.src; out << rte.links; out << rte.number; out << rte.type; out << rte.pts; out << rte.lastRoutedWith; out << rte.lastRoutedTime; out << rte.totalDistance; out << rte.totalTime; out << rte.ascent; out << rte.descent; stream.writeRawData(MAGIC_RTE, MAGIC_SIZE); stream << VER_RTE; stream << qCompress(buffer,9); return stream; } QDataStream& CGisItemOvlArea::operator<<(QDataStream& stream) { quint8 version, tmp8; QByteArray buffer; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_AREA,MAGIC_SIZE)) { dev->seek(pos); return stream; } stream >> version; stream >> buffer; buffer = qUncompress(buffer); QDataStream in(&buffer, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in >> key.item; in >> flags; in >> area.name; in >> area.cmt; in >> area.desc; in >> area.src; in >> area.links; in >> area.number; in >> area.type; in >> area.pts; in >> area.color; in >> area.width; in >> area.style; in >> tmp8; area.opacity = tmp8; deriveSecondaryData(); setColor(str2color(area.color)); setText (CGisListWks::eColumnName, getName()); setToolTip(CGisListWks::eColumnName, getInfo(IGisItem::eFeatureShowName)); return stream; } QDataStream& CGisItemOvlArea::operator>>(QDataStream& stream) const { QByteArray buffer; QDataStream out(&buffer, QIODevice::WriteOnly); out.setByteOrder(QDataStream::LittleEndian); out.setVersion(QDataStream::Qt_5_2); out << key.item; out << flags; out << area.name; out << area.cmt; out << area.desc; out << area.src; out << area.links; out << area.number; out << area.type; out << area.pts; out << area.color; out << area.width; out << area.style; out << quint8(area.opacity); stream.writeRawData(MAGIC_AREA, MAGIC_SIZE); stream << VER_AREA; stream << qCompress(buffer,9); return stream; } QDataStream& IGisProject::operator<<(QDataStream& stream) { quint8 version; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_PROJ,MAGIC_SIZE)) { dev->seek(pos); return stream; } blockUpdateItems(true); stream >> version; if(filename.isEmpty()) { stream >> filename; } else { QString tmp; stream >> tmp; } stream >> metadata.name; stream >> metadata.desc; stream >> metadata.author; stream >> metadata.copyright; stream >> metadata.links; stream >> metadata.time; stream >> metadata.keywords; stream >> metadata.bounds; if(version > 1) { stream >> key; } if(version > 2) { qint32 tmp; stream >> tmp; sortingRoadbook = (sorting_roadbook_e)tmp; } if(version > 3) { qint8 tmp; stream >> tmp; noCorrelation = (tmp & eFlagNoCorrelation) != 0; autoSave = (tmp & eFlagAutoSave) != 0; } if(version > 4) { qint32 tmp; stream >> tmp; sortingFolder = (sorting_folder_e)tmp; } while(!stream.atEnd()) { QString lastDatabaseHash; IGisItem::history_t history; quint8 changed = 0; quint8 version, type; stream >> version; stream >> type; stream >> history; if(version > 1) { stream >> changed; } if(version > 2) { stream >> lastDatabaseHash; } IGisItem *item = nullptr; switch(type) { case IGisItem::eTypeWpt: item = new CGisItemWpt(history, lastDatabaseHash, this); break; case IGisItem::eTypeTrk: item = new CGisItemTrk(history, lastDatabaseHash, this); break; case IGisItem::eTypeRte: item = new CGisItemRte(history, lastDatabaseHash, this); break; case IGisItem::eTypeOvl: item = new CGisItemOvlArea(history, lastDatabaseHash, this); break; default: ; } if(item && changed) { item->updateDecoration(IGisItem::eMarkChanged, IGisItem::eMarkNone); } } sortItems(); blockUpdateItems(false); return stream; } QDataStream& IGisProject::operator>>(QDataStream& stream) const { stream.writeRawData(MAGIC_PROJ, MAGIC_SIZE); stream << VER_PROJECT; stream << filename; stream << metadata.name; stream << metadata.desc; stream << metadata.author; stream << metadata.copyright; stream << metadata.links; stream << metadata.time; stream << metadata.keywords; stream << metadata.bounds; stream << key; stream << qint32(sortingRoadbook); stream << qint8((noCorrelation ? eFlagNoCorrelation : 0) | (autoSave ? eFlagAutoSave : 0)); // collect trivial flags in one field. stream << qint32(sortingFolder); for(int i = 0; i < childCount(); i++) { CGisItemTrk * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } stream << VER_ITEM; stream << quint8(item->type()); stream << item->getHistory(); stream << quint8(item->data(1,Qt::UserRole).toUInt() & IGisItem::eMarkChanged); stream << item->getLastDatabaseHash(); } for(int i = 0; i < childCount(); i++) { CGisItemRte * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } stream << VER_ITEM; stream << quint8(item->type()); stream << item->getHistory(); stream << quint8(item->data(1,Qt::UserRole).toUInt() & IGisItem::eMarkChanged); stream << item->getLastDatabaseHash(); } for(int i = 0; i < childCount(); i++) { CGisItemWpt * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } stream << VER_ITEM; stream << quint8(item->type()); stream << item->getHistory(); stream << quint8(item->data(1,Qt::UserRole).toUInt() & IGisItem::eMarkChanged); stream << item->getLastDatabaseHash(); } for(int i = 0; i < childCount(); i++) { CGisItemOvlArea * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } stream << VER_ITEM; stream << quint8(item->type()); stream << item->getHistory(); stream << quint8(item->data(1,Qt::UserRole).toUInt() & IGisItem::eMarkChanged); stream << item->getLastDatabaseHash(); } return stream; } QDataStream& CDBProject::operator<<(QDataStream& stream) { quint8 version; QIODevice * dev = stream.device(); qint64 pos = dev->pos(); char magic[10]; stream.readRawData(magic,MAGIC_SIZE); if(strncmp(magic,MAGIC_PROJ,MAGIC_SIZE)) { dev->seek(pos); return stream; } stream >> version; stream >> filename; stream >> metadata.name; stream >> metadata.desc; stream >> metadata.author; stream >> metadata.copyright; stream >> metadata.links; stream >> metadata.time; stream >> metadata.keywords; stream >> metadata.bounds; if(version > 1) { stream >> key; } if(version > 2) { qint32 tmp; stream >> tmp; sortingRoadbook = (sorting_roadbook_e)tmp; } if(version > 3) { qint8 tmp; stream >> tmp; noCorrelation = (tmp & eFlagNoCorrelation) != 0; autoSave = (tmp & eFlagAutoSave) != 0; } if(version > 4) { qint32 tmp; stream >> tmp; sortingFolder = (sorting_folder_e)tmp; } return stream; } QDataStream& CDBProject::operator>>(QDataStream& stream) const { stream.writeRawData(MAGIC_PROJ, MAGIC_SIZE); stream << VER_PROJECT; stream << filename; stream << metadata.name; stream << metadata.desc; stream << metadata.author; stream << metadata.copyright; stream << metadata.links; stream << metadata.time; stream << metadata.keywords; stream << metadata.bounds; stream << key; stream << qint32(sortingRoadbook); stream << qint8((noCorrelation ? eFlagNoCorrelation : 0) | (autoSave ? eFlagAutoSave : 0)); // collect trivial flags in one field. stream << qint32(sortingFolder); return stream; } qmapshack-1.10.0/src/gis/qms/CQmsProject.cpp000644 001750 000144 00000005670 13216234137 022003 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/gpx/CGpxProject.h" #include "gis/qms/CQmsProject.h" #include "helpers/CSettings.h" #include CQmsProject::CQmsProject(const QString &filename, CGisListWks *parent) : IGisProject(eTypeQms, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/QmsProject.png")); // create file instance QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if(!file.exists() || QFileInfo(filename).suffix().toLower() != "qms") { IGisProject::filename.clear(); setupName(filename); setToolTip(CGisListWks::eColumnName, getInfo()); valid = true; return; } if(!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to open..."), tr("Failed to open %1").arg(filename), QMessageBox::Abort); return; } QDataStream in(&file); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); *this << in; file.close(); markAsSaved(); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); setToolTip(CGisListWks::eColumnName, getInfo()); updateItems(); valid = true; } bool CQmsProject::saveAs(const QString& fn, IGisProject& project) { QString _fn_ = fn; QFileInfo fi(_fn_); if(fi.suffix().toLower() != "qms") { _fn_ += ".qms"; } // todo save qms QFile file(_fn_); if(!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to open..."), tr("Failed to open %1").arg(_fn_), QMessageBox::Abort); return false; } QDataStream out(&file); out.setByteOrder(QDataStream::LittleEndian); out.setVersion(QDataStream::Qt_5_2); QString tmp = project.getFilename(); project.setFilename(_fn_); project.IGisProject::operator>>(out); project.setFilename(tmp); file.close(); return true; } qmapshack-1.10.0/src/gis/CGisListDB.h000644 001750 000144 00000005614 13216234143 020340 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGISLISTDB_H #define CGISLISTDB_H #include #include #include struct action_t; class QMenu; class IDBFolderSql; class QUdpSocket; class CSearchDatabase; class CGisListDB : public QTreeWidget { Q_OBJECT public: CGisListDB(QWidget * parent); virtual ~CGisListDB(); enum column_e { eColumnCheckbox = 0 ,eColumnName = 1 ,eColumnTime = 2 }; bool hasDatabase(const QString& name); bool event(QEvent * e) override; signals: void sigChanged(); private slots: void slotContextMenu(const QPoint& point); void slotAddFolder(); void slotDelFolder(); void slotDelLostFound(); void slotDelLostFoundItem(); void slotItemExpanded(QTreeWidgetItem * item); void slotItemChanged(QTreeWidgetItem * item, int column); void slotAddDatabase(); void slotDelDatabase(); void slotDelItem(); void slotUpdateDatabase(); void slotSearchDatabase(); void slotRenameFolder(); void slotCopyFolder(); void slotMoveFolder(); void slotReadyRead(); void slotExportToGpx(); void slotImport(); private: friend class CGisListDBEditLock; IDBFolderSql *getDataBase(const QString& name, const QString& host); void saveDatabaseConfiguration(); int isInternalEdit = 0; QMenu * menuNone; QAction * actionAddDatabase; QMenu * menuFolder; QAction * actionAddFolder; QAction * actionRenameFolder; QAction * actionCopyFolder; QAction * actionMoveFolder; QAction * actionDelFolder; QAction * actionExportToGpx; QAction * actionImport; QMenu * menuDatabase; QAction * actionDelDatabase; QAction * actionUpdate; QAction * actionSearch; QMenu * menuItem; QAction * actionDelItem; QMenu * menuLostFound; QAction * actionDelLostFound; QMenu * menuLostFoundItem; QAction * actionDelLostFoundItem; QUdpSocket * socket; quint32 lastTan; QPointer dlgSearch; }; #endif //CGISLISTDB_H qmapshack-1.10.0/src/gis/CGisDraw.h000644 001750 000144 00000002360 13216234143 020107 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGISDRAW_H #define CGISDRAW_H #include "canvas/IDrawContext.h" class CCanvas; class CGisDraw : public IDrawContext { public: CGisDraw(CCanvas *parent); virtual ~CGisDraw(); using IDrawContext::draw; void draw(QPainter& p, const QRect& rect); protected: void drawt(buffer_t& currentBuffer) override; }; #endif //CGISDRAW_H qmapshack-1.10.0/src/gis/CGisDatabase.h000644 001750 000144 00000002625 13216234143 020722 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGISDATABASE_H #define CGISDATABASE_H #include "ui_IGisDatabase.h" class CGisDatabase : public QWidget, private Ui::IGisDatabase { Q_OBJECT public: static CGisDatabase& self() { return *pSelf; } virtual ~CGisDatabase(); void postEventForDb(QEvent * event); void sendEventForDb(QEvent * event); private slots: void slotHelpText(); private: friend class CMainWindow; CGisDatabase(QWidget * parent); static CGisDatabase * pSelf; }; #endif //CGISDATABASE_H qmapshack-1.10.0/src/gis/qlb/000755 001750 000144 00000000000 13216664445 017064 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/qlb/CQlbProject.h000644 001750 000144 00000003113 13216234261 021370 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CQLBPROJECT_H #define CQLBPROJECT_H #include "gis/prj/IGisProject.h" class CQlbProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CQlbProject) public: CQlbProject(const QString& filename, CGisListWks * parent); virtual ~CQlbProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterQLB; } const QString getFileExtension() const override { return "qlb"; } private: void load(const QString& filename); void loadWpts(QByteArray &array); void loadTrks(QByteArray &array); void loadRtes(QByteArray &array); void loadOvls(QByteArray &array); }; #endif //CQLBPROJECT_H qmapshack-1.10.0/src/gis/qlb/CQlbProject.cpp000644 001750 000144 00000010314 13216234261 021724 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/qlb/CQlbProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "qlgt/CQlb.h" #include "qlgt/CQlgtDiary.h" #include "qlgt/CQlgtRoute.h" #include "qlgt/CQlgtTrack.h" #include "qlgt/CQlgtWpt.h" #include "qlgt/IQlgtOverlay.h" #include CQlbProject::CQlbProject(const QString &filename, CGisListWks *parent) : IGisProject(eTypeQlb, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/QlbProject.png")); // create file instance QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if(!file.exists() || QFileInfo(filename).suffix().toLower() != "qlb") { IGisProject::filename.clear(); setupName(filename); setToolTip(CGisListWks::eColumnName, getInfo()); valid = true; return; } if(!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to open..."), tr("Failed to open %1").arg(filename), QMessageBox::Abort); return; } load(filename); markAsSaved(); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); setToolTip(CGisListWks::eColumnName, getInfo()); updateItems(); valid = true; } void CQlbProject::load(const QString& filename) { CQlb qlb(nullptr); qlb.load(filename); loadWpts(qlb.waypoints()); loadTrks(qlb.tracks()); loadRtes(qlb.routes()); loadOvls(qlb.overlays()); } void CQlbProject::loadWpts(QByteArray& array) { QDataStream stream(&array, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); while(!stream.atEnd()) { CQlgtWpt wpt(0, nullptr); stream >> wpt; new CGisItemWpt(wpt, this); } } void CQlbProject::loadTrks(QByteArray &array) { QDataStream stream(&array, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); while(!stream.atEnd()) { CQlgtTrack trk(0, nullptr); stream >> trk; new CGisItemTrk(trk, this); } } void CQlbProject::loadRtes(QByteArray &array) { QDataStream stream(&array, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); while(!stream.atEnd()) { CQlgtRoute rte(0, nullptr); stream >> rte; new CGisItemRte(rte, this); } } void CQlbProject::loadOvls(QByteArray &array) { QDataStream stream(&array, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_5); bool warningDone = false; while(!stream.atEnd()) { IQlgtOverlay ovl(0,nullptr); stream >> ovl; if(ovl.type == "Area") { new CGisItemOvlArea(ovl, this); } else if(ovl.type == "Distance") { new CGisItemTrk(ovl, this); } else if(!warningDone) { QMessageBox::warning(CMainWindow::self().getBestWidgetForParent(), tr("Could not convert...") , tr("The file contains overlays that can not be converted. This is because " "QMapShack does not support all overlay types of QLandkarte."), QMessageBox::Ok); warningDone = true; } } } qmapshack-1.10.0/src/gis/CGisDatabase.cpp000644 001750 000144 00000003467 13216234137 021265 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisDatabase.h" #include "helpers/CSettings.h" #include CGisDatabase * CGisDatabase::pSelf = nullptr; CGisDatabase::CGisDatabase(QWidget *parent) : QWidget(parent) { pSelf = this; setupUi(this); SETTINGS; treeDB->header()->restoreState(cfg.value("Database/treeDB/state", treeDB->header()->saveState()).toByteArray()); connect(treeDB, &CGisListDB::sigChanged, this, &CGisDatabase::slotHelpText); QTimer::singleShot(1, this, SLOT(slotHelpText())); } CGisDatabase::~CGisDatabase() { SETTINGS; cfg.setValue("Database/treeDB/state", treeDB->header()->saveState()); } void CGisDatabase::slotHelpText() { frameHelp->setVisible(treeDB->topLevelItemCount() == 0); } void CGisDatabase::postEventForDb(QEvent * event) { QCoreApplication::postEvent(treeDB, event); } void CGisDatabase::sendEventForDb(QEvent * event) { QCoreApplication::sendEvent(treeDB, event); } qmapshack-1.10.0/src/gis/wpt/000755 001750 000144 00000000000 13216664445 017120 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/wpt/IProjWpt.ui000644 001750 000144 00000007142 12444752216 021175 0ustar00oeichlerxusers000000 000000 IProjWpt 0 0 240 354 Waypoint Projection ... 22 22 true 15 75 true - Clone waypoint and move by: m ° :/pics/compass.png Qt::AlignCenter Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IProjWpt accept() 248 254 157 274 buttonBox rejected() IProjWpt reject() 316 260 286 274 qmapshack-1.10.0/src/gis/wpt/CScrOptWptRadius.cpp000644 001750 000144 00000005406 13216234261 022776 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/wpt/CGisItemWpt.h" #include "gis/wpt/CProjWpt.h" #include "gis/wpt/CScrOptWptRadius.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" #include CScrOptWptRadius::CScrOptWptRadius(CGisItemWpt *wpt, const QPoint& point, IMouse *parent) : IScrOpt(parent) , key(wpt->getKey()) { setupUi(this); setOrigin(point); label->setFont(CMainWindow::self().getMapFont()); qreal proximity = wpt->getProximity(); if(proximity == NOFLOAT) { proximity = 0.; } QString val, unit; IUnit::self().meter2distance(proximity, val, unit); label->setText(QString("%1%2").arg(val).arg(unit)); adjustSize(); toolNogoArea->setChecked(wpt->isNogoArea()); anchor = wpt->getPointCloseBy(point); move(anchor.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); connect(toolDelete, &QToolButton::clicked, this, &CScrOptWptRadius::slotDelete); connect(toolEdit, &QToolButton::clicked, this, &CScrOptWptRadius::slotEdit); connect(toolNogoArea, &QToolButton::clicked, this, &CScrOptWptRadius::slotNogoArea); adjustSize(); } CScrOptWptRadius::~CScrOptWptRadius() { } void CScrOptWptRadius::slotDelete() { CGisWorkspace::self().deleteWptRadius(key); deleteLater(); } void CScrOptWptRadius::slotNogoArea() { CGisWorkspace::self().toggleWptNogoArea(key); deleteLater(); } void CScrOptWptRadius::slotEdit() { CGisWorkspace::self().editWptRadius(key); deleteLater(); } void CScrOptWptRadius::draw(QPainter& p) { IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { deleteLater(); return; } item->drawHighlight(p); CDraw::bubble(p, geometry(), anchor.toPoint()); } qmapshack-1.10.0/src/gis/wpt/ISetupNewWpt.ui000644 001750 000144 00000005432 12516214125 022025 0ustar00oeichlerxusers000000 000000 ISetupNewWpt 0 0 400 196 New Waypoint... Symbol ... true Position Name Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISetupNewWpt accept() 248 254 157 274 buttonBox rejected() ISetupNewWpt reject() 316 260 286 274 qmapshack-1.10.0/src/gis/wpt/CDetailsGeoCache.h000644 001750 000144 00000003136 13216234143 022327 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSGEOCACHE_H #define CDETAILSGEOCACHE_H #include "ui_IDetailsGeoCache.h" #include class CGisItemWpt; class QNetworkAccessManager; class QTimer; class CDetailsGeoCache : public QDialog, private Ui::IDetailsGeoCache { Q_OBJECT public: CDetailsGeoCache(CGisItemWpt& wpt, QWidget * parent); virtual ~CDetailsGeoCache(); private slots: void slotHintChanged(bool on); void slotLinkClicked(const QUrl& url); void slotCollectSpoiler(); void slotRequestFinished(QNetworkReply * reply); void slotDownloadDone(); private: CGisItemWpt& wpt; QNetworkAccessManager * networkManager; int cntSpoiler = 0; QTimer * timerDownload; }; #endif //CDETAILSGEOCACHE_H qmapshack-1.10.0/src/gis/wpt/CSetupNewWpt.cpp000644 001750 000144 00000005143 13216234137 022166 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/WptIcons.h" #include "gis/wpt/CSetupNewWpt.h" #include "helpers/CPositionDialog.h" #include "helpers/CWptIconDialog.h" #include "units/IUnit.h" #include CSetupNewWpt::CSetupNewWpt(QPointF &pt, QString &icon, QString &name, QWidget *parent) : QDialog(parent) , pt(pt) , icon(icon) , name(name) { QPointF focus; setupUi(this); toolIcon->setObjectName(icon); toolIcon->setIcon(getWptIconByName(icon, focus)); QString pos; IUnit::degToStr(pt.x(), pt.y(), pos); linePosition->setText(pos); labelWarning->hide(); lineName->setText(name); connect(linePosition, &QLineEdit::textEdited, this, &CSetupNewWpt::slotEditPosition); connect(lineName, &QLineEdit::textEdited, this, &CSetupNewWpt::slotEditName); connect(toolIcon, &QToolButton::clicked, this, &CSetupNewWpt::slotChangeIcon); checkInput(); } CSetupNewWpt::~CSetupNewWpt() { } void CSetupNewWpt::accept() { if(CPositionDialog::getPosition(pt, linePosition->text())) { icon = toolIcon->objectName(); name = lineName->text(); QDialog::accept(); } } void CSetupNewWpt::reject() { pt = NOPOINTF; name.clear(); icon.clear(); QDialog::reject(); } void CSetupNewWpt::slotEditPosition(const QString& str) { labelWarning->setVisible(!IUnit::isValidCoordString(str)); checkInput(); } void CSetupNewWpt::slotEditName(const QString& str) { checkInput(); } void CSetupNewWpt::slotChangeIcon() { CWptIconDialog dlg(toolIcon); dlg.exec(); } void CSetupNewWpt::checkInput() { bool isEnabled = (labelWarning->isHidden() && !lineName->text().isEmpty()); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isEnabled); } qmapshack-1.10.0/src/gis/wpt/IDetailsWpt.ui000644 001750 000144 00000035134 13035437610 021645 0ustar00oeichlerxusers000000 000000 IDetailsWpt 0 0 550 454 Dialog :/icons/32x32/Map.png:/icons/32x32/Map.png 0 0 0 0 0 0 Info 0 0 0 0 0 3 0 0 Position: - 0 0 Ele. 0 0 - 0 0 Proximity: 0 0 - 0 0 QFrame::NoFrame false 0 150 16777215 150 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 true false 0 0 25 25 The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. :/icons/32x32/Tainted.png true Toggle read only mode. You have to open the lock to edit the item. ... :/icons/32x32/UnLock.png :/icons/32x32/Lock.png:/icons/32x32/UnLock.png 22 22 true true 0 0 Date/Time: - Add images. ... :/icons/32x32/AddImage.png:/icons/32x32/AddImage.png 22 22 Delete selected image. ... :/icons/32x32/DelImage.png:/icons/32x32/DelImage.png 22 22 Qt::Vertical 20 40 ... 22 22 true Hist. 0 0 0 0 0 CHistoryListWidget QListWidget
widgets/CHistoryListWidget.h
CLineEdit QLineEdit
widgets/CLineEdit.h
CPhotoAlbum QWidget
widgets/CPhotoAlbum.h
1
qmapshack-1.10.0/src/gis/wpt/CSetupNewWpt.h000644 001750 000144 00000002756 13216234143 021637 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETUPNEWWPT_H #define CSETUPNEWWPT_H #include "ui_ISetupNewWpt.h" #include class CSetupNewWpt : public QDialog, private Ui::ISetupNewWpt { Q_OBJECT public: CSetupNewWpt(QPointF& pt, QString& icon, QString& name, QWidget * parent); virtual ~CSetupNewWpt(); public slots: void accept() override; void reject() override; private slots: void slotEditPosition(const QString& str); void slotEditName(const QString& str); void slotChangeIcon(); private: void checkInput(); QPointF &pt; QString &icon; QString &name; }; #endif //CSETUPNEWWPT_H qmapshack-1.10.0/src/gis/wpt/CGisItemWpt.cpp000644 001750 000144 00000055765 13216234261 021772 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/WptIcons.h" #include "gis/prj/IGisProject.h" #include "gis/wpt/CDetailsGeoCache.h" #include "gis/wpt/CDetailsWpt.h" #include "gis/wpt/CGisItemWpt.h" #include "gis/wpt/CScrOptWpt.h" #include "gis/wpt/CScrOptWptRadius.h" #include "gis/wpt/CSetupNewWpt.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "mouse/IMouse.h" #include "units/IUnit.h" #include #include IGisItem::key_t CGisItemWpt::keyUserFocus; CGisItemWpt::CGisItemWpt(const QPointF &pos, qreal ele, const QDateTime &time, const QString &name, const QString &icon, IGisProject *project) : IGisItem(project, eTypeWpt, NOIDX) { wpt.name = name; wpt.sym = icon; wpt.lon = pos.x(); wpt.lat = pos.y(); wpt.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); wpt.time = time; detBoundingRect(); setupHistory(); updateDecoration(eMarkNone, eMarkNone); } /// used to add a new waypoint CGisItemWpt::CGisItemWpt(const QPointF& pos, const QString& name, const QString &icon, IGisProject *project) : CGisItemWpt(pos, NOFLOAT, QDateTime::currentDateTimeUtc(), name, icon, project) { flags = eFlagCreatedInQms|eFlagWriteAllowed; qreal ele = CMainWindow::self().getElevationAt(pos * DEG_TO_RAD); wpt.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); detBoundingRect(); setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } /// used to move a copy of waypoint CGisItemWpt::CGisItemWpt(const QPointF& pos, const CGisItemWpt& parentWpt, IGisProject *project) : IGisItem(project, eTypeWpt, NOIDX) { *this = parentWpt; wpt.lon = pos.x(); wpt.lat = pos.y(); wpt.time = QDateTime::currentDateTimeUtc(); key.clear(); history.events.clear(); flags = eFlagCreatedInQms|eFlagWriteAllowed; qreal ele = CMainWindow::self().getElevationAt(pos * DEG_TO_RAD); wpt.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); detBoundingRect(); setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } /// used to create a copy of waypoint with new parent CGisItemWpt::CGisItemWpt(const CGisItemWpt &parentWpt, IGisProject *project, int idx, bool clone) : IGisItem(project, eTypeWpt, idx) { history = parentWpt.history; loadHistory(history.histIdxCurrent); if(clone) { wpt.name += tr("_Clone"); key.clear(); history.events.clear(); setupHistory(); } if(parentWpt.isOnDevice() || !parentWpt.isReadOnly()) { flags |= eFlagWriteAllowed; } else { flags &= ~eFlagWriteAllowed; } detBoundingRect(); updateDecoration(eMarkChanged, eMarkNone); } /// used to create waypoint from GPX file CGisItemWpt::CGisItemWpt(const QDomNode &xml, IGisProject *project) : IGisItem(project, eTypeWpt, project->childCount()) { readGpx(xml); detBoundingRect(); genKey(); setupHistory(); updateDecoration(eMarkNone, eMarkNone); } CGisItemWpt::CGisItemWpt(const history_t& hist, const QString &dbHash, IGisProject * project) : IGisItem(project, eTypeWpt, project->childCount()) { history = hist; loadHistory(hist.histIdxCurrent); detBoundingRect(); if(!dbHash.isEmpty()) { lastDatabaseHash = dbHash; } } CGisItemWpt::CGisItemWpt(quint64 id, QSqlDatabase& db, IGisProject * project) : IGisItem(project, eTypeWpt, NOIDX) { loadFromDb(id, db); detBoundingRect(); } CGisItemWpt::CGisItemWpt(const CTwoNavProject::wpt_t &tnvWpt, IGisProject * project) : IGisItem(project, eTypeWpt, NOIDX) { readTwoNav(tnvWpt); detBoundingRect(); genKey(); setupHistory(); updateDecoration(eMarkNone, eMarkNone); } CGisItemWpt::CGisItemWpt(CFitStream& stream, IGisProject * project) : IGisItem(project, eTypeWpt, NOIDX) , proximity(NOFLOAT) , posScreen(NOPOINTF) { readWptFromFit(stream); detBoundingRect(); genKey(); setupHistory(); updateDecoration(eMarkNone, eMarkNone); } CGisItemWpt::~CGisItemWpt() { } IGisItem * CGisItemWpt::createClone() { int idx = -1; IGisProject * project = getParentProject(); if(project) { idx = project->indexOfChild(this); } return new CGisItemWpt(*this, project, idx, true); } void CGisItemWpt::setSymbol() { setIcon(); } bool CGisItemWpt::getNewWptData(QPointF& pt, QString& icon, QString& name) { SETTINGS; QString lastName = cfg.value("Waypoint/lastName", "wpt").toString(); QString lastIcon = cfg.value("Waypoint/lastIcon", "Waypoint").toString(); const int s = lastName.size(); if(s != 0) { int idx; for(idx = s; idx > 0; idx--) { if(!lastName[idx - 1].isDigit()) { break; } } if(idx == 0) { lastName = QString::number(lastName.toInt() + 1); } else if(idx < s) { lastName = lastName.left(idx) + QString::number(lastName.mid(idx).toInt() + 1); } } if(name.isEmpty()) { name = lastName; } icon = lastIcon; CSetupNewWpt dlg(pt, icon, name, CMainWindow::getBestWidgetForParent()); if(dlg.exec() != QDialog::Accepted) { return false; } cfg.setValue("Waypoint/lastName", name); cfg.setValue("Waypoint/lastIcon", icon); return true; } QString CGisItemWpt::getInfo(quint32 feature) const { QString str = "
"; if(feature & eFeatureShowName) { str = "" + getName() + "
\n"; } if(geocache.hasData) { str += QString(" %4 (%1, D %2, T %3)").arg(geocache.container).arg(geocache.difficulty, 0,'f',1).arg(geocache.terrain, 0,'f',1).arg(geocache.name); } if(wpt.time.isValid()) { if(!str.isEmpty()) { str += "
\n"; } str += IUnit::datetime2string(wpt.time, false, QPointF(wpt.lon*DEG_TO_RAD, wpt.lat*DEG_TO_RAD)); } if(wpt.ele != NOINT) { if(!str.isEmpty()) { str += "
\n"; } QString val, unit; IUnit::self().meter2elevation(wpt.ele, val, unit); str += tr("Elevation: %1%2").arg(val).arg(unit); // KKA } if(proximity != NOFLOAT) { if(!str.isEmpty()) { str += "
\n"; } QString val, unit; IUnit::self().meter2distance(proximity, val, unit); str += tr("Proximity: %1%2").arg(val).arg(unit); } QString desc = removeHtml(wpt.desc).simplified(); if(desc.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || (desc.count() < 300)) { str += desc; } else { str += desc.left(297) + "..."; } } QString cmt = removeHtml(wpt.cmt).simplified(); if((cmt != desc) && cmt.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || (cmt.count() < 300)) { str += cmt; } else { str += cmt.left(297) + "..."; } } return str + "
"; } IScrOpt * CGisItemWpt::getScreenOptions(const QPoint& origin, IMouse * mouse) { if (closeToRadius) { if(scrOptRadius.isNull()) { scrOptRadius = new CScrOptWptRadius(this, origin, mouse); } return scrOptRadius; } else { if(scrOptWpt.isNull()) { scrOptWpt = new CScrOptWpt(this, origin, mouse); } return scrOptWpt; } } QPointF CGisItemWpt::getPointCloseBy(const QPoint& point) { if (closeToRadius) { QPointF l = (QPointF(point) - posScreen); return posScreen + l * (radius / sqrt(QPointF::dotProduct(l,l))); } else { return posScreen; } } void CGisItemWpt::setIcon() { if(geocache.hasData) { icon = getWptIconByName(geocache.type, focus); } else { icon = getWptIconByName(wpt.sym, focus); } QTreeWidgetItem::setIcon(CGisListWks::eColumnIcon,icon); } void CGisItemWpt::setName(const QString& str) { SETTINGS; cfg.setValue("Waypoint/lastName", str); setText(CGisListWks::eColumnName, str); wpt.name = str; changed(tr("Changed name"),"://icons/48x48/EditText.png"); } void CGisItemWpt::setPosition(const QPointF& pos) { wpt.lon = pos.x(); wpt.lat = pos.y(); detBoundingRect(); changed(tr("Changed position"),"://icons/48x48/WptMove.png"); } void CGisItemWpt::setElevation(qint32 val) { wpt.ele = val; changed(tr("Changed elevation"),"://icons/48x48/SetEle.png"); } void CGisItemWpt::setProximity(qreal val) { proximity = val == NOFLOAT ? val : qRound(val); detBoundingRect(); radius = NOFLOAT; //radius is proximity in set on redraw if (proximity == NOFLOAT) { changed(tr("Removed proximity"),"://icons/48x48/WptDelProx.png"); } else { changed(tr("Changed proximity"),"://icons/48x48/WptEditProx.png"); } } void CGisItemWpt::setIcon(const QString& name) { SETTINGS; cfg.setValue("Waypoint/lastIcon", name); wpt.sym = name; QPointF focus; QString path; getWptIconByName(name, focus, &path); changed(tr("Changed icon"), path); } void CGisItemWpt::setComment(const QString& str) { wpt.cmt = str; changed(tr("Changed comment"), "://icons/48x48/EditText.png"); } void CGisItemWpt::setDescription(const QString& str) { wpt.desc = str; changed(tr("Changed description"), "://icons/48x48/EditText.png"); } void CGisItemWpt::setLinks(const QList& links) { wpt.links = links; changed(tr("Changed links"), "://icons/48x48/Link.png"); } void CGisItemWpt::setImages(const QList& imgs) { images = imgs; changed(tr("Changed images"), "://icons/48x48/Image.png"); } void CGisItemWpt::addImage(const image_t& img) { images.append(img); changed(tr("Add image"), "://icons/48x48/Image.png"); } bool CGisItemWpt::isCloseTo(const QPointF& pos) { closeToRadius = false; if(posScreen == NOPOINTF) { return false; } QPointF dist = (pos - posScreen); if(dist.manhattanLength() < 22) { return true; } if (radius == NOFLOAT) { return false; } closeToRadius = abs(QPointF::dotProduct(dist,dist)/radius - radius) < 22; return closeToRadius; } bool CGisItemWpt::isWithin(const QRectF& area, selflags_t flags) { return (flags & eSelectionWpt) ? area.contains(posScreen) : false; } void CGisItemWpt::gainUserFocus(bool yes) { keyUserFocus = yes ? key : key_t(); } void CGisItemWpt::edit() { if(geocache.hasData) { CDetailsGeoCache dlg(*this, CMainWindow::getBestWidgetForParent()); dlg.exec(); } else { CDetailsWpt dlg(*this, CMainWindow::getBestWidgetForParent()); dlg.exec(); } } void CGisItemWpt::drawItem(QPainter& p, const QPolygonF& viewport, QList &blockedAreas, CGisDraw *gis) { posScreen = QPointF(wpt.lon * DEG_TO_RAD, wpt.lat * DEG_TO_RAD); if (proximity == NOFLOAT || proximity == 0. ? !isVisible(posScreen, viewport, gis) : !isVisible(boundingRect, viewport, gis)) { rectBubble = QRect(); posScreen = NOPOINTF; return; } gis->convertRad2Px(posScreen); if(proximity == NOFLOAT) { radius = NOFLOAT; } else { //remember radius for isCloseTo-method radius = calcRadius(QPointF(wpt.lon * DEG_TO_RAD, wpt.lat * DEG_TO_RAD),posScreen,proximity,gis); drawCircle(p, posScreen, radius, !hideArea && isNogoArea(), false); } drawBubble(p); p.drawPixmap(posScreen - focus, icon); blockedAreas << QRectF(posScreen - focus, icon.size()); } void CGisItemWpt::drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { if(mouseIsOverBubble && !doBubbleMove && !doBubbleSize && rectBubble.isValid() && !isReadOnly()) { QPainterPath clip; clip.addRoundedRect(rectBubble, RECT_RADIUS, RECT_RADIUS); p.setClipPath(clip); QRect barTop(rectBubble.topLeft(), QSize(rectBubble.width(), 26)); QRect barBottom(barTop); barBottom.moveBottomLeft(rectBubble.bottomLeft()); barBottom.adjust(1,0,-1,-1); barTop.adjust(1,1,-1,0); p.setPen(Qt::NoPen); p.setBrush(QColor(200,200,255,150)); p.drawRect(barTop); p.drawRect(barBottom); p.setBrush(Qt::white); p.drawRoundedRect(rectBubbleMove.adjusted(-2,-2,2,2), RECT_RADIUS, RECT_RADIUS); p.drawRoundedRect(rectBubbleEdit.adjusted(-2,-2,2,2), RECT_RADIUS, RECT_RADIUS); p.drawRoundedRect(rectBubbleSize.adjusted(-2,-2,2,2), RECT_RADIUS, RECT_RADIUS); p.drawPixmap(rectBubbleMove, QPixmap("://icons/32x32/MoveArrow.png")); p.drawPixmap(rectBubbleEdit, QPixmap("://icons/32x32/EditDetails.png")); p.drawPixmap(rectBubbleSize, QPixmap("://icons/32x32/SizeArrow.png")); } } void CGisItemWpt::drawLabel(QPainter& p, const QPolygonF &viewport, QList &blockedAreas, const QFontMetricsF &fm, CGisDraw *gis) { if(posScreen == NOPOINTF) { return; } QPointF pt = posScreen - focus; QRectF rect = fm.boundingRect(wpt.name); rect.adjust(-2,-2,2,2); // place label on top rect.moveCenter(pt + QPointF(icon.width()/2, -fm.height())); if(isBlocked(rect, blockedAreas)) { // place label on bottom rect.moveCenter(pt + QPointF( icon.width()/2, +fm.height() + icon.height())); if(isBlocked(rect, blockedAreas)) { // place label on right rect.moveCenter(pt + QPointF( icon.width() + rect.width()/2, +fm.height())); if(isBlocked(rect, blockedAreas)) { // place label on left rect.moveCenter(pt + QPointF( -rect.width()/2, +fm.height())); if(isBlocked(rect, blockedAreas)) { // failed to place label anywhere return; } } } } CDraw::text(wpt.name,p,rect.toRect(), Qt::darkBlue); blockedAreas << rect; } void CGisItemWpt::drawHighlight(QPainter& p) { if(posScreen == NOPOINTF) { return; } if (closeToRadius) { drawCircle(p, posScreen, radius, isNogoArea(), true); } else { p.drawImage(posScreen - QPointF(31,31), QImage("://cursors/wptHighlightRed.png")); } } void CGisItemWpt::drawBubble(QPainter& p) { if(!(flags & eFlagWptBubble)) { return; } QString str = QString("%1").arg(getName()); if(!removeHtml(wpt.desc).simplified().isEmpty()) { str += QString("

%1

").arg(wpt.desc); } if(!removeHtml(wpt.cmt).simplified().isEmpty()) { str += QString("

%1

").arg(wpt.cmt); } QTextDocument doc; doc.setHtml(str); doc.setTextWidth(widthBubble); rectBubble.setWidth(widthBubble); rectBubble.setHeight(doc.size().height()); QPoint posBubble = posScreen.toPoint() + offsetBubble; rectBubble.moveTopLeft(posBubble); rectBubbleMove.moveTopLeft(rectBubble.topLeft() + QPoint(5,5)); rectBubbleEdit.moveTopLeft(rectBubbleMove.topRight() + QPoint(7,0)); rectBubbleSize.moveBottomRight(rectBubble.bottomRight() - QPoint(5,5)); QPolygonF frame = makePolyline(posScreen, rectBubble); p.setPen(CDraw::penBorderGray); p.setBrush(CDraw::brushBackWhite); p.drawPolygon(frame); p.save(); p.translate(posBubble); p.setPen(Qt::black); doc.drawContents(&p); p.restore(); } void CGisItemWpt::drawCircle(QPainter& p, const QPointF& pos, const qreal& r, const bool& filled, const bool& selected) { QRect circle(pos.x() - r - 1, pos.y() - r - 1, 2*r + 1, 2*r + 1); p.save(); p.setBrush(Qt::NoBrush); if (selected) { p.setPen(QPen(Qt::red,3)); } else { p.setPen(QPen(Qt::white,3)); p.drawEllipse(circle); p.setPen(QPen(Qt::red,1)); } if (filled) { p.setBrush(QBrush(Qt::red,Qt::DiagCrossPattern)); } p.drawEllipse(circle); p.restore(); } qreal CGisItemWpt::calcRadius(const QPointF& posRad, const QPointF& posPx, const qreal& radiusRad, CGisDraw *gis) { QPointF pt1 = posRad; pt1 = GPS_Math_Wpt_Projection(pt1, radiusRad, 90 * DEG_TO_RAD); gis->convertRad2Px(pt1); return pt1.x() - posPx.x(); } QPolygonF CGisItemWpt::makePolyline(const QPointF& anchor, const QRectF& r) { QPolygonF poly1, poly2; poly1 << r.topLeft() << r.topRight() << r.bottomRight() << r.bottomLeft(); if(!r.contains(anchor)) { qreal w = rectBubble.width()>>1; qreal h = rectBubble.height()>>1; if(w > 30) { w = 30; } if(h > 30) { h = 30; } w = h = qMin(w,h); if(anchor.x() < r.left()) { poly2 << anchor << (r.center() + QPoint(0,-h)) << (r.center() + QPoint(0,h)) << anchor; } else if(r.right() < anchor.x()) { poly2 << anchor << (r.center() + QPoint(0,-h)) << (r.center() + QPoint(0,h)) << anchor; } else if(anchor.y() < r.top()) { poly2 << anchor << (r.center() + QPoint(-w,0)) << (r.center() + QPoint(w,0)) << anchor; } else if(r.bottom() < anchor.y()) { poly2 << anchor << (r.center() + QPoint(-w,0)) << (r.center() + QPoint(w,0)) << anchor; } QPainterPath path1; path1.addRoundedRect(r, RECT_RADIUS, RECT_RADIUS); QPainterPath path2; path2.addPolygon(poly2); path1 = path1.united(path2); poly1 = path1.toFillPolygon(); } return poly1; } void CGisItemWpt::removeLinksByType(const QString& type) { QList::iterator link = wpt.links.begin(); while(link != wpt.links.end()) { if(link->type == type) { link = wpt.links.erase(link); continue; } ++link; } } void CGisItemWpt::mouseMove(const QPointF& pos) { if(!hasBubble() || isReadOnly()) { return; } if(!processMouseOverBubble(pos.toPoint())) { if(mouseIsOverBubble) { if(!rectBubble.contains(pos.toPoint())) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { doBubbleMove = doBubbleSize = false; canvas->resetMouse(); } mouseIsOverBubble = false; } } else { if(rectBubble.contains(pos.toPoint())) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { doBubbleMove = doBubbleSize = false; canvas->setMouseWptBubble(getKey()); } mouseIsOverBubble = true; } } } } void CGisItemWpt::mousePress(const QPointF& pos) { if(!mouseIsOverBubble) { return; } QPoint pos1 = pos.toPoint(); if(rectBubbleMove.contains(pos1)) { offsetMouse = pos1 - rectBubble.topLeft(); doBubbleMove = true; } else if(rectBubbleEdit.contains(pos1)) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { doBubbleMove = doBubbleSize = false; canvas->resetMouse(); } mouseIsOverBubble = false; edit(); } else if(rectBubbleSize.contains(pos1)) { offsetMouse = pos1 - rectBubble.bottomRight(); doBubbleSize = true; } } void CGisItemWpt::mouseRelease(const QPointF& pos) { if(!mouseIsOverBubble) { return; } updateHistory(); doBubbleMove = doBubbleSize = false; } void CGisItemWpt::toggleBubble() { if(flags & eFlagWptBubble) { flags &= ~eFlagWptBubble; } else { flags |= eFlagWptBubble; } updateHistory(); } void CGisItemWpt::toggleNogoArea() { if(flags & eFlagWptNogo) { flags &= ~eFlagWptNogo; changed(tr("Changed to proximity-radius"),"://icons/48x48/WptProx.png"); } else { flags |= eFlagWptNogo; changed(tr("Changed to nogo-area"),"://icons/48x48/WptAvoid.png"); } } bool CGisItemWpt::processMouseOverBubble(const QPoint &pos) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(!canvas || !mouseIsOverBubble) { return false; } if(doBubbleMove) { offsetBubble = pos - posScreen.toPoint(); offsetBubble -= offsetMouse; canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); return true; } else if(doBubbleSize) { qDebug() << offsetMouse; int width = pos.x() - rectBubble.left() - offsetMouse.x(); if(width > 50) { widthBubble = width; } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); return true; } else if(rectBubbleMove.contains(pos) || rectBubbleEdit.contains(pos) || rectBubbleSize.contains(pos)) { if(!doSpecialCursor) { CCanvas::setOverrideCursor(Qt::PointingHandCursor, "processMouseOverBubble"); doSpecialCursor = true; } } else { if(doSpecialCursor) { CCanvas::restoreOverrideCursor("processMouseOverBubble"); doSpecialCursor = false; } } return false; } void CGisItemWpt::detBoundingRect() { if(proximity == NOFLOAT) { boundingRect = QRectF(QPointF(wpt.lon,wpt.lat)*DEG_TO_RAD,QPointF(wpt.lon,wpt.lat)*DEG_TO_RAD); } else { qreal diag = proximity * 1.414213562; QPointF cent(wpt.lon * DEG_TO_RAD, wpt.lat * DEG_TO_RAD); QPointF pt1 = GPS_Math_Wpt_Projection(cent, diag, 225 * DEG_TO_RAD); QPointF pt2 = GPS_Math_Wpt_Projection(cent, diag, 45 * DEG_TO_RAD); boundingRect = QRectF(pt1,pt2); } } qmapshack-1.10.0/src/gis/wpt/CScrOptWpt.cpp000644 001750 000144 00000010605 13216234261 021623 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/wpt/CGisItemWpt.h" #include "gis/wpt/CProjWpt.h" #include "gis/wpt/CScrOptWpt.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" #include CScrOptWpt::CScrOptWpt(CGisItemWpt *wpt, const QPoint& point, IMouse *parent) : IScrOpt(parent) , key(wpt->getKey()) { setupUi(this); setOrigin(point); label->setFont(CMainWindow::self().getMapFont()); label->setText(wpt->getInfo(IGisItem::eFeatureShowName)); adjustSize(); toolProj->setDisabled(wpt->isGeocache() || wpt->isOnDevice()); toolMove->setDisabled(wpt->isGeocache() || wpt->isOnDevice()); photoAlbum->reload(wpt->getImages()); toolBubble->setChecked(wpt->hasBubble()); bool radius = wpt->hasRadius(); toolNogoArea->setEnabled(radius); toolNogoArea->setChecked(radius && wpt->isNogoArea()); toolDelRadius->setEnabled(radius); anchor = wpt->getPointCloseBy(point); move(anchor.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); connect(toolDelete, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolEdit, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolCopy, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolMove, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolProj, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolBubble, &QToolButton::clicked, this, &CScrOptWpt::hide); connect(toolDelete, &QToolButton::clicked, this, &CScrOptWpt::slotDelete); connect(toolEdit, &QToolButton::clicked, this, &CScrOptWpt::slotEdit); connect(toolCopy, &QToolButton::clicked, this, &CScrOptWpt::slotCopy); connect(toolMove, &QToolButton::clicked, this, &CScrOptWpt::slotMove); connect(toolProj, &QToolButton::clicked, this, &CScrOptWpt::slotProj); connect(toolBubble, &QToolButton::clicked, this, &CScrOptWpt::slotBubble); connect(toolDelRadius, &QToolButton::clicked, this, &CScrOptWpt::slotDeleteRadius); connect(toolNogoArea, &QToolButton::clicked, this, &CScrOptWpt::slotNogoArea); connect(toolEditRadius, &QToolButton::clicked, this, &CScrOptWpt::slotEditRadius); adjustSize(); } CScrOptWpt::~CScrOptWpt() { } void CScrOptWpt::slotDelete() { CGisWorkspace::self().delItemByKey(key); deleteLater(); } void CScrOptWpt::slotEdit() { CGisWorkspace::self().editItemByKey(key); deleteLater(); } void CScrOptWpt::slotCopy() { CGisWorkspace::self().copyItemByKey(key); deleteLater(); } void CScrOptWpt::slotMove() { CGisWorkspace::self().moveWptByKey(key); deleteLater(); } void CScrOptWpt::slotProj() { CGisWorkspace::self().projWptByKey(key); deleteLater(); } void CScrOptWpt::slotBubble() { CGisWorkspace::self().toggleWptBubble(key); deleteLater(); } void CScrOptWpt::slotDeleteRadius() { CGisWorkspace::self().deleteWptRadius(key); deleteLater(); } void CScrOptWpt::slotNogoArea() { CGisWorkspace::self().toggleWptNogoArea(key); deleteLater(); } void CScrOptWpt::slotEditRadius() { CGisWorkspace::self().editWptRadius(key); deleteLater(); } void CScrOptWpt::draw(QPainter& p) { IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { deleteLater(); return; } item->drawHighlight(p); CDraw::bubble(p, geometry(), anchor.toPoint()); } qmapshack-1.10.0/src/gis/wpt/CDetailsWpt.cpp000644 001750 000144 00000016434 13216234137 022006 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/wpt/CDetailsWpt.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CElevationDialog.h" #include "helpers/CInputDialog.h" #include "helpers/CLinksDialog.h" #include "helpers/CPositionDialog.h" #include "helpers/CWptIconDialog.h" #include "units/IUnit.h" #include "widgets/CTextEditWidget.h" #include #include CDetailsWpt::CDetailsWpt(CGisItemWpt &wpt, QWidget *parent) : QDialog(parent) , wpt(wpt) { setupUi(this); photoAlbum->hide(); setupGui(); toolLock->setDisabled(wpt.isOnDevice()); connect(labelPosition, &QLabel::linkActivated, this, static_cast(&CDetailsWpt::slotLinkActivated)); connect(labelElevation, &QLabel::linkActivated, this, static_cast(&CDetailsWpt::slotLinkActivated)); connect(labelProximity, &QLabel::linkActivated, this, static_cast(&CDetailsWpt::slotLinkActivated)); connect(textCmtDesc, &QTextBrowser::anchorClicked, this, static_cast(&CDetailsWpt::slotLinkActivated)); connect(lineName, &CLineEdit::textEdited, this, &CDetailsWpt::slotNameChanged); connect(lineName, &CLineEdit::editingFinished, this, &CDetailsWpt::slotNameChangeFinished); connect(toolIcon, &QToolButton::clicked, this, &CDetailsWpt::slotChangeIcon); connect(toolLock, &QToolButton::toggled, this, &CDetailsWpt::slotChangeReadOnlyMode); connect(listHistory, &CHistoryListWidget::sigChanged, this, &CDetailsWpt::setupGui); connect(toolAddImage, &QToolButton::clicked, photoAlbum, &CPhotoAlbum::slotAddImage); connect(toolDelImage, &QToolButton::clicked, photoAlbum, &CPhotoAlbum::slotDelImage); connect(photoAlbum, &CPhotoAlbum::sigChanged, this, &CDetailsWpt::slotChangedImages); } CDetailsWpt::~CDetailsWpt() { } void CDetailsWpt::setupGui() { if(originator) { return; } originator = true; setWindowTitle(wpt.getName()); QString val, unit; QString strPos; QPointF pos = wpt.getPosition(); IUnit::degToStr(pos.x(), pos.y(), strPos); bool isReadOnly = wpt.isReadOnly(); toolIcon->setEnabled(!isReadOnly); toolIcon->setIcon(wpt.getIcon()); toolIcon->setObjectName(wpt.getIconName()); lineName->setReadOnly(isReadOnly); lineName->setText(wpt.getName()); labelPosition->setText(IGisItem::toLink(isReadOnly, "position", strPos, "")); labelTainted->setVisible(wpt.isTainted()); QString elevationStr = "--"; if(wpt.getElevation() != NOINT) { IUnit::self().meter2elevation(wpt.getElevation(), val, unit); elevationStr = QString("%1 %2").arg(val).arg(unit); } labelElevation->setText(IGisItem::toLink(isReadOnly, "elevation", elevationStr, "")); QString proxStr = "--"; if(wpt.getProximity() != NOFLOAT) { IUnit::self().meter2elevation(wpt.getProximity(), val, unit); proxStr = QString("%1 %2").arg(val).arg(unit); } labelProximity->setText(IGisItem::toLink(isReadOnly, "proximity", proxStr, "")); if(wpt.getTime().isValid()) { labelTime->setText(IUnit::datetime2string(wpt.getTime(), false, QPointF(pos.x()*DEG_TO_RAD, pos.y()*DEG_TO_RAD))); } textCmtDesc->document()->clear(); textCmtDesc->append(IGisItem::createText(isReadOnly, wpt.getComment(), wpt.getDescription(), wpt.getLinks())); textCmtDesc->moveCursor (QTextCursor::Start); textCmtDesc->ensureCursorVisible(); toolLock->setChecked(isReadOnly); listHistory->setupHistory(wpt); const QList& images = wpt.getImages(); photoAlbum->reload(images); toolAddImage->setVisible(!isReadOnly); toolDelImage->setVisible(!isReadOnly && !images.isEmpty()); originator = false; } void CDetailsWpt::slotNameChanged(const QString &name) { setWindowTitle(name); } void CDetailsWpt::slotNameChangeFinished() { lineName->clearFocus(); const QString& name = lineName->text(); slotNameChanged(name); if(name != wpt.getName()) { wpt.setName(name); setupGui(); } } void CDetailsWpt::slotLinkActivated(const QString& link) { if(link == "elevation") { QVariant var(wpt.getElevation()); CElevationDialog dlg(this, var, QVariant(NOINT), wpt.getPosition()); if(dlg.exec() == QDialog::Accepted) { wpt.setElevation(var.toInt()); } } else if(link == "proximity") { QVariant var(wpt.getProximity()); CInputDialog dlg(this, tr("Enter new proximity range."), var, QVariant(NOFLOAT)); if(dlg.exec() == QDialog::Accepted) { wpt.setProximity(var.toDouble()); } } else if(link == "position") { QPointF pos = wpt.getPosition(); CPositionDialog dlg(this, pos); if(dlg.exec() == QDialog::Accepted) { wpt.setPosition(pos); } } setupGui(); } void CDetailsWpt::slotLinkActivated(const QUrl& url) { if(url.toString() == "comment") { CTextEditWidget dlg(wpt.getComment(), this); if(dlg.exec() == QDialog::Accepted) { wpt.setComment(dlg.getHtml()); } setupGui(); } else if(url.toString() == "description") { CTextEditWidget dlg(wpt.getDescription(), this); if(dlg.exec() == QDialog::Accepted) { wpt.setDescription(dlg.getHtml()); } setupGui(); } else if(url.toString() == "links") { QList links = wpt.getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { wpt.setLinks(links); } setupGui(); } else { QDesktopServices::openUrl(url); } } void CDetailsWpt::slotChangeIcon() { if(!wpt.isReadOnly()) { CWptIconDialog dlg(toolIcon); if(dlg.exec() == QDialog::Accepted) { wpt.setIcon(toolIcon->objectName()); setupGui(); } } } void CDetailsWpt::slotChangeReadOnlyMode(bool on) { wpt.setReadOnlyMode(on); setupGui(); } void CDetailsWpt::slotChangedImages(const QList& images) { wpt.setImages(images); setupGui(); } qmapshack-1.10.0/src/gis/wpt/CScrOptWptRadius.h000644 001750 000144 00000003065 13216234261 022442 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CSCROPTWPTRADIUS_H #define CSCROPTWPTRADIUS_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptWptRadius.h" #include class CGisItemWpt; class IMouse; class CScrOptWptRadius : public IScrOpt, private Ui::IScrOptWptRadius { Q_OBJECT public: CScrOptWptRadius(CGisItemWpt * wpt, const QPoint &point, IMouse *parent); virtual ~CScrOptWptRadius(); void draw(QPainter& p) override; private slots: void slotDelete(); void slotNogoArea(); void slotEdit(); private: IGisItem::key_t key; QPointF anchor; }; #endif //CSCROPTWPTRADIUS_H qmapshack-1.10.0/src/gis/wpt/CProjWpt.cpp000644 001750 000144 00000005507 13216234137 021332 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "gis/prj/IGisProject.h" #include "gis/wpt/CGisItemWpt.h" #include "gis/wpt/CProjWpt.h" #include "helpers/CWptIconDialog.h" #include "units/IUnit.h" #include #include CProjWpt::CProjWpt(CGisItemWpt& wpt, QWidget *parent) : QDialog(parent) , wpt(wpt) { setupUi(this); name = wpt.getName(); toolIcon->setIcon(wpt.getIcon()); toolIcon->setObjectName(wpt.getIconName()); labelName->setText(QString("%2").arg(name)); QString val, unit; IUnit::self().meter2distance(0,val,unit); labelDistUnit->setText(unit); connect(labelName, &QLabel::linkActivated, this, &CProjWpt::slotChangeName); connect(toolIcon, &QToolButton::clicked, this, &CProjWpt::slotChangeIcon); } CProjWpt::~CProjWpt() { } void CProjWpt::slotChangeIcon() { CWptIconDialog dlg(toolIcon); dlg.exec(); } void CProjWpt::slotChangeName() { QString n = QInputDialog::getText(this, tr("Edit name..."), tr("Enter new waypoint name."), QLineEdit::Normal, wpt.getName()); if(n.isEmpty()) { return; } name = n; labelName->setText(QString("%2").arg(name)); } void CProjWpt::accept() { qreal dist = lineDist->text().toDouble(); qreal bearing = lineBearing->text().toDouble(); if((dist <= 0) || (bearing > 180) || (bearing < -180)) { return; } IGisProject *project = dynamic_cast(wpt.parent()); if(nullptr == project) { return; } QPointF pos = wpt.getPosition() * DEG_TO_RAD; pos = GPS_Math_Wpt_Projection(pos, dist, bearing * DEG_TO_RAD) * RAD_TO_DEG; CGisItemWpt * newWpt = new CGisItemWpt(pos, wpt, project); if(name != newWpt->getName()) { newWpt->setName(name); } if(toolIcon->objectName() != newWpt->getIconName()) { newWpt->setIcon(toolIcon->objectName()); } QDialog::accept(); } qmapshack-1.10.0/src/gis/wpt/IScrOptWpt.ui000644 001750 000144 00000017202 13216234261 021464 0ustar00oeichlerxusers000000 000000 IScrOptWpt 0 0 500 157 0 0 Form 3 3 3 3 3 3 true View details and edit. ... :/icons/32x32/EditDetails.png:/icons/32x32/EditDetails.png Copy waypoint into another project. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png Delete waypoint from project. ... :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png Qt::Vertical Show content as static bubble. ... :/icons/32x32/Bubble.png:/icons/32x32/Bubble.png true Move waypoint to a new location. ... :/icons/32x32/WptMove.png:/icons/32x32/WptMove.png Clone waypoint and move clone a given distance and angle. ... :/icons/32x32/WptProj.png:/icons/32x32/WptProj.png Qt::Vertical edit radius of circular area ... :/icons/32x32/WptEditProx.png:/icons/32x32/WptEditProx.png false Switch between proximity and nogo-area ... :/icons/32x32/WptProx.png :/icons/32x32/WptAvoid.png:/icons/32x32/WptProx.png true Delete circle defined by waypoint :/icons/32x32/WptDelProx.png:/icons/32x32/WptDelProx.png Qt::Horizontal 40 20 0 0 300 0 500 16777215 TextLabel true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 100 CPhotoAlbum QWidget
widgets/CPhotoAlbum.h
1
qmapshack-1.10.0/src/gis/wpt/CProjWpt.h000644 001750 000144 00000002507 13216234143 020771 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPROJWPT_H #define CPROJWPT_H #include "ui_IProjWpt.h" #include class CGisItemWpt; class CProjWpt : public QDialog, private Ui::IProjWpt { Q_OBJECT public: CProjWpt(CGisItemWpt &wpt, QWidget * parent); virtual ~CProjWpt(); public slots: void accept() override; private slots: void slotChangeIcon(); void slotChangeName(); private: CGisItemWpt& wpt; QString name; }; #endif //CPROJWPT_H qmapshack-1.10.0/src/gis/wpt/IScrOptWptRadius.ui000644 001750 000144 00000007705 13216234261 022643 0ustar00oeichlerxusers000000 000000 IScrOptWptRadius 0 0 306 52 0 0 Form 3 3 3 3 3 3 QLayout::SetNoConstraint edit radius of circular area ... :/icons/32x32/WptEditProx.png:/icons/32x32/WptEditProx.png Switch between proximity and nogo-area ... :/icons/32x32/WptProx.png :/icons/32x32/WptAvoid.png:/icons/32x32/WptProx.png true Delete circle defined by waypoint ... :/icons/32x32/WptDelProx.png:/icons/32x32/WptDelProx.png Qt::Horizontal 0 20 0 0 0 0 500 16777215 TextLabel true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse qmapshack-1.10.0/src/gis/wpt/CDetailsGeoCache.cpp000644 001750 000144 00000022777 13216234137 022701 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/wpt/CDetailsGeoCache.h" #include "gis/wpt/CGisItemWpt.h" #include #include #include #define HTTP_ATTR_WHAT QNetworkRequest::Attribute(QNetworkRequest::User + 1) #define HTTP_ATTR_INFO QNetworkRequest::Attribute(QNetworkRequest::User + 2) CDetailsGeoCache::CDetailsGeoCache(CGisItemWpt &wpt, QWidget *parent) : QDialog(parent) , wpt(wpt) { setupUi(this); setWindowTitle(wpt.getName()); QString val, unit; QString strPos; QPointF pos = wpt.getPosition(); IUnit::degToStr(pos.x(), pos.y(), strPos); const CGisItemWpt::geocache_t& geocache = wpt.getGeoCache(); labelName->setText(geocache.name); labelPositon->setText(strPos); qreal d = geocache.difficulty; labelD1->setPixmap(QPixmap(d < 0.5 ? "://icons/cache/32x32/star_empty.png" : d < 1.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelD2->setPixmap(QPixmap(d < 1.5 ? "://icons/cache/32x32/star_empty.png" : d < 2.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelD3->setPixmap(QPixmap(d < 2.5 ? "://icons/cache/32x32/star_empty.png" : d < 3.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelD4->setPixmap(QPixmap(d < 3.5 ? "://icons/cache/32x32/star_empty.png" : d < 4.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelD5->setPixmap(QPixmap(d < 4.5 ? "://icons/cache/32x32/star_empty.png" : d < 5.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); qreal t = geocache.terrain; labelT1->setPixmap(QPixmap(t < 0.5 ? "://icons/cache/32x32/star_empty.png" : t < 1.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelT2->setPixmap(QPixmap(t < 1.5 ? "://icons/cache/32x32/star_empty.png" : t < 2.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelT3->setPixmap(QPixmap(t < 2.5 ? "://icons/cache/32x32/star_empty.png" : t < 3.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelT4->setPixmap(QPixmap(t < 3.5 ? "://icons/cache/32x32/star_empty.png" : t < 4.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); labelT5->setPixmap(QPixmap(t < 4.5 ? "://icons/cache/32x32/star_empty.png" : t < 5.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16,16,Qt::KeepAspectRatio, Qt::SmoothTransformation)); checkHint->setEnabled(!geocache.hint.isEmpty()); labelHint->setText(geocache.hint.isEmpty() ? tr("none") : tr("???")); toolIcon->setIcon(wpt.getIcon()); labelStatus->hide(); QString desc; if(geocache.shortDescIsHtml) { desc += geocache.shortDesc; } else { QString str = geocache.shortDesc; desc += "

" + str.replace("\n","
") + "

"; } if(geocache.longDescIsHtml) { desc += geocache.longDesc; } else { QString str = geocache.longDesc; desc += "

" + str.replace("\n","
") + "

"; } webDesc->setHtml(desc); webDesc->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); timerDownload = new QTimer(this); timerDownload->setSingleShot(true); connect(timerDownload, &QTimer::timeout, this, &CDetailsGeoCache::slotDownloadDone); connect(checkHint, &QCheckBox::toggled, this, &CDetailsGeoCache::slotHintChanged); connect(webDesc, &QWebView::linkClicked, this, &CDetailsGeoCache::slotLinkClicked); connect(toolUpdateSpoiler, &QToolButton::clicked, this, &CDetailsGeoCache::slotCollectSpoiler); networkManager = new QNetworkAccessManager(this); connect(networkManager, &QNetworkAccessManager::finished, this, &CDetailsGeoCache::slotRequestFinished); const QList& images = wpt.getImages(); photoAlbum->reload(images); if(images.isEmpty()) { slotCollectSpoiler(); toolUpdateSpoiler->setEnabled(false); } else { toolUpdateSpoiler->setEnabled(true); } if(wpt.isOnDevice()) { toolUpdateSpoiler->setEnabled(false); } listHistory->setEnabled(false); listHistory->setupHistory(wpt); } CDetailsGeoCache::~CDetailsGeoCache() { } void CDetailsGeoCache::slotHintChanged(bool on) { if(on) { labelHint->setText(wpt.getGeoCache().hint); } else { labelHint->setText(tr("???")); } } void CDetailsGeoCache::slotLinkClicked(const QUrl& url) { QDesktopServices::openUrl(url); } void CDetailsGeoCache::slotCollectSpoiler() { const QList& links = wpt.getLinks(); if(links.isEmpty()) { return; } wpt.loadHistory(0); photoAlbum->reload(wpt.getImages()); listHistory->setupHistory(wpt); QNetworkRequest request; request.setUrl(links.first().uri); networkManager->get(request); timerDownload->start(10000); labelStatus->show(); labelStatus->setText(tr("Searching for images...")); } void CDetailsGeoCache::slotRequestFinished(QNetworkReply * reply) { if(reply->error() != QNetworkReply::NoError) { qDebug() << reply->errorString(); reply->deleteLater(); return; } qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute); qDebug() << reply->attribute(QNetworkRequest::RedirectionTargetAttribute); qint32 httpStatusCodeAttribute = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if(reply->property("whatfor") == "image") { QString info = reply->property("info").toString(); if((httpStatusCodeAttribute == 301) || (httpStatusCodeAttribute == 302)) { QNetworkRequest request; request.setUrl(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()); QNetworkReply * reply = networkManager->get(request); reply->setProperty("whatfor", "image"); reply->setProperty("info", info); } else if(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) { CGisItemWpt::image_t image; image.info = info; image.pixmap.loadFromData(reply->readAll()); wpt.addImage(image); photoAlbum->reload(wpt.getImages()); listHistory->setupHistory(wpt); cntSpoiler--; if(cntSpoiler == 0) { slotDownloadDone(); } } } else { if((httpStatusCodeAttribute == 301) || (httpStatusCodeAttribute == 302)) { QNetworkRequest request; request.setUrl(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()); networkManager->get(request); } } QString asw = reply->readAll(); reply->deleteLater(); if(asw.isEmpty()) { return; } QRegExp re1(".*CachePageImages.*"); QRegExp re2("(https://.*\\.jpg).*>(.*)"); re2.setMinimal(true); bool watchOut = false; QStringList lines = asw.split("\n"); for(const QString &line : lines) { if(!watchOut && re1.exactMatch(line)) { watchOut = true; } else if(watchOut) { int pos = 0; while ((pos = re2.indexIn(line, pos)) != NOIDX) { QString url = re2.cap(1); QString info = re2.cap(2); QNetworkRequest request; request.setUrl(url); QNetworkReply * reply = networkManager->get(request); reply->setProperty("whatfor", "image"); reply->setProperty("info", info); cntSpoiler++; pos += re2.matchedLength(); } watchOut = false; } } } void CDetailsGeoCache::slotDownloadDone() { timerDownload->stop(); cntSpoiler = 0; if(wpt.getImages().isEmpty()) { labelStatus->setText(tr("No images found")); } else { labelStatus->hide(); } } qmapshack-1.10.0/src/gis/wpt/CGisItemWpt.h000644 001750 000144 00000027110 13216234261 021416 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CGISITEMWPT_H #define CGISITEMWPT_H #include "gis/IGisItem.h" #include "gis/tnv/CTwoNavProject.h" #include #include class IGisProject; class QDomNode; class CScrOptWpt; class CScrOptWptRadius; class QSqlDatabase; class CQlgtWpt; class QTextEdit; class QDir; class CFitStream; class CGisItemWpt : public IGisItem { Q_DECLARE_TR_FUNCTIONS(CGisItemWpt) public: enum geocacheservice_e {eGC, eOC, eTC}; struct geocachelog_t { quint32 id = 0; QDateTime date; QString type; QString finderId; QString finder; bool textIsHtml = false; QString text; }; struct geocache_t { geocacheservice_e service = eOC; bool hasData = false; quint32 id = 0; bool available = true; bool archived = false; qreal difficulty = 0; qreal terrain = 0; QString status; QString name; QString owner; QString ownerId; QString type; QString container; bool shortDescIsHtml = false; QString shortDesc; bool longDescIsHtml = false; QString longDesc; QString hint; QString country; QString state; QString locale; QList logs; }; struct image_t { QImage pixmap; qreal direction = 0; QString info; QString filePath; QString fileName; }; CGisItemWpt(const QPointF &pos, qreal ele, const QDateTime &time, const QString &name, const QString &icon, IGisProject *project); /** @brief Create a completely new waypoint @param pos the waypoint's position [°] @param name the waypoint's name @param icon the waypoint's icon @param project the project the waypoint is added to */ CGisItemWpt(const QPointF& pos, const QString& name, const QString& icon, IGisProject * project); /** @brief Create a copy of an existing waypoint with a new position @param pos the waypoint's new position [°] @param parentWpt the waypoint to copy @param project the project the waypoint is added to */ CGisItemWpt(const QPointF& pos, const CGisItemWpt &parentWpt, IGisProject *project); /** @brief Create a 1:1 copy of an existing waypoint (with new key) @param parentWpt the waypoint to copy @param project the project the waypoint is added to @param idx the index to insert the item. If -1 the item will be appended to it's group */ CGisItemWpt(const CGisItemWpt &parentWpt, IGisProject *project, int idx, bool clone); /** @brief Create item from GPX. @param xml the GPX section containing the item @param project the project to append with item */ CGisItemWpt(const QDomNode& xml, IGisProject * project); /** @brief Create item from list of changes @param hist the change history @param project the project to append with item */ CGisItemWpt(const history_t& hist, const QString& dbHash, IGisProject * project); /** @brief Read item from database by it's database ID @param id the item's ID in the database @param db the database itself @param project the project to append with item */ CGisItemWpt(quint64 id, QSqlDatabase& db, IGisProject * project); /** @brief Read item from text stream with TwoNav encoding @param tnvWpt @param project */ CGisItemWpt(const CTwoNavProject::wpt_t& tnvWpt, IGisProject * project); CGisItemWpt(const CQlgtWpt& wpt1, IGisProject *project = nullptr); CGisItemWpt(CFitStream& stream, IGisProject * project); virtual ~CGisItemWpt(); IGisItem * createClone() override; /** @brief Save waypoint to GPX tree @param gpx The node to append by the waypoint */ void save(QDomNode& gpx, bool strictGpx11) override; /** @brief Save waypoint to TwoNav waypoint file @param out the text stream to write to */ void saveTwoNav(QTextStream &out, const QDir &dir); /** @brief Save waypoint to TCX file @param courseNode The course node to append by the waypoint @param crsPtDateTimeToBeSaved course point dateTime to be saved (NOT the waypoint date and time !) */ void saveTCX(QDomNode& courseNode, const QDateTime crsPtDateTimeToBeSaved); /** @brief Read serialized waypoint from a binary data stream @param stream the data stream to read from @return A reference to the stream */ QDataStream& operator<<(QDataStream& stream) override; /** @brief Serialize waypoint into a binary data stream @param stream the data stream to write to. @return A reference to the stream */ QDataStream& operator>>(QDataStream& stream) const override; void setName(const QString& str); void setPosition(const QPointF& pos); void setElevation(qint32 val); void setProximity(qreal val); void setIcon(const QString& name); void setComment(const QString& str) override; void setDescription(const QString& str) override; void setLinks(const QList& links) override; void setImages(const QList& imgs); /** @brief Silently append list of links Devices uses links to reference multimedia content attached to the waypoint. These links have to be added to the list of normal links. See removeLinksByType() on how to remove these links again. @param links list of links. */ void appendLinks(const QList& links) { wpt.links = links + wpt.links; } /** @brief Silently append list of images This is used to restore images from a device. As these images where part of the waypoint object in the first place they have to be added to the waypoint again without creating a new history entry. @param imgs list of images */ void appendImages(const QList& imgs) { images += imgs; } /** @brief Append the list of images by a single image. @param img a single image */ void addImage(const image_t& img); const QString& getName() const override { return wpt.name.isEmpty() ? noName : wpt.name; } QString getInfo(quint32 feature) const override; QPointF getPosition() const { return QPointF(wpt.lon, wpt.lat); } qint32 getElevation() const { return wpt.ele; } qreal getProximity() const { return proximity; } const QDateTime& getTime() const { return wpt.time; } const QString& getIconName() const { return wpt.sym; } const QString& getComment() const override { return wpt.cmt; } const QString& getDescription() const override { return wpt.desc; } const geocache_t& getGeoCache() const { return geocache; } const QList& getLinks() const override { return wpt.links; } const QList& getImages() const { return images; } QDateTime getTimestamp() const override { return wpt.time; } IScrOpt* getScreenOptions(const QPoint &origin, IMouse * mouse) override; QPointF getPointCloseBy(const QPoint& point) override; void drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) override; void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) override; void drawLabel(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) override; void drawHighlight(QPainter& p) override; bool isCloseTo(const QPointF& pos) override; bool isWithin(const QRectF &area, selflags_t flags) override; void mouseMove(const QPointF& pos) override; void mousePress(const QPointF& pos); void mouseRelease(const QPointF& pos); bool isGeocache() { return geocache.hasData; } void toggleNogoArea(); bool isNogoArea() { return bool(flags & eFlagWptNogo); } bool hasRadius() { return proximity < NOFLOAT; } qreal getRadius() { return radius; } void gainUserFocus(bool yes) override; void edit() override; /** @brief Remove all links from the waypoint's link list with a given type This is used by devices that use links to attach multimedia items to a waypoint like images. These links only make sense on the device. Therefor the links have to be removed after the waypoint has been loaded from the device. @param type */ void removeLinksByType(const QString& type); void toggleBubble(); bool hasBubble() { return bool(flags & eFlagWptBubble); } void setHideArea(bool hide) { hideArea = hide; } static bool getNewWptData(QPointF& pt, QString& icon, QString& name); static void drawCircle(QPainter& p, const QPointF& pos, const qreal& r, const bool &avoid, const bool &selected); static qreal calcRadius(const QPointF& posRad, const QPointF& posPx, const qreal& radiusRad, CGisDraw *gis); private: void setIcon(); void setSymbol() override; void readGpx(const QDomNode& xml); void readTwoNav(const CTwoNavProject::wpt_t &tnvWpt); void readWptFromFit(CFitStream &stream); void readGcExt(const QDomNode& xmlCache); void writeGcExt(QDomNode& xmlCache); void drawBubble(QPainter& p); QPolygonF makePolyline(const QPointF& anchor, const QRectF& r); bool processMouseOverBubble(const QPoint &pos); void detBoundingRect(); static key_t keyUserFocus; // --- start all waypoint data ---- wpt_t wpt; qreal proximity = NOFLOAT; qreal radius = NOFLOAT; bool closeToRadius = false; bool hideArea = false; geocache_t geocache; QList images; QPointF focus; QPointF posScreen = NOPOINTF; // additional data, common to all IGisItems, is found in IItem // // --- stop all waypoint data ---- QPointer scrOptWpt; QPointer scrOptRadius; bool doBubble = false; bool doSpecialCursor = false; bool doBubbleMove = false; bool doBubbleSize = false; bool mouseIsOverBubble = false; QRect rectBubble; QRect rectBubbleMove {0,0,16,16}; QRect rectBubbleEdit {0,0,16,16}; QRect rectBubbleSize {0,0,16,16}; QPoint offsetMouse; QPoint offsetBubble {-320, -150}; quint32 widthBubble = 300; }; #endif // CGISITEMWPT_H qmapshack-1.10.0/src/gis/wpt/CDetailsWpt.h000644 001750 000144 00000003151 13216234143 021440 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSWPT_H #define CDETAILSWPT_H #include "ui_IDetailsWpt.h" #include #include "gis/wpt/CGisItemWpt.h" class CDetailsWpt : public QDialog, private Ui::IDetailsWpt { Q_OBJECT public: CDetailsWpt(CGisItemWpt& wpt, QWidget * parent); virtual ~CDetailsWpt(); private slots: void slotNameChanged(const QString &name); void slotNameChangeFinished(); void slotLinkActivated(const QString& link); void slotLinkActivated(const QUrl& url); void slotChangeIcon(); void slotChangeReadOnlyMode(bool on); void slotChangedImages(const QList& images); void setupGui(); private: CGisItemWpt& wpt; bool originator = false; }; #endif //CDETAILSWPT_H qmapshack-1.10.0/src/gis/wpt/IDetailsGeoCache.ui000644 001750 000144 00000024461 12627613666 022547 0ustar00oeichlerxusers000000 000000 IDetailsGeoCache 0 0 800 667 600 400 Dialog :/icons/32x32/Map.png:/icons/32x32/Map.png 0 0 Position: - 0 0 Difficulty 0 0 - 0 0 - 0 0 - 0 0 - 0 0 - 0 0 Terrain 0 0 - 0 0 - 0 0 - 0 0 - 0 0 - Update spoilers ... :/icons/32x32/ReloadImage.png:/icons/32x32/ReloadImage.png 22 22 Qt::Vertical 20 40 - Qt::Horizontal about:blank ... 22 22 true Hint: Qt::Horizontal 40 20 TextLabel 0 150 QWebView QWidget
QtWebKitWidgets/QWebView
CPhotoAlbum QWidget
widgets/CPhotoAlbum.h
1
CHistoryListWidget QListWidget
widgets/CHistoryListWidget.h
qmapshack-1.10.0/src/gis/wpt/CScrOptWpt.h000644 001750 000144 00000003223 13216234261 021266 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CSCROPTWPT_H #define CSCROPTWPT_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptWpt.h" #include class CGisItemWpt; class IMouse; class CScrOptWpt : public IScrOpt, private Ui::IScrOptWpt { Q_OBJECT public: CScrOptWpt(CGisItemWpt * wpt, const QPoint &point, IMouse *parent); virtual ~CScrOptWpt(); void draw(QPainter& p) override; private slots: void slotDelete(); void slotEdit(); void slotCopy(); void slotMove(); void slotProj(); void slotBubble(); void slotDeleteRadius(); void slotNogoArea(); void slotEditRadius(); private: IGisItem::key_t key; QPointF anchor; }; #endif //CSCROPTWPT_H qmapshack-1.10.0/src/gis/trk/000755 001750 000144 00000000000 13216664445 017106 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/trk/CKnownExtension.cpp000644 001750 000144 00000026203 13216234261 022676 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 "gis/trk/CKnownExtension.h" #include "units/IUnit.h" #include const QString CKnownExtension::internalSlope = "::ql:slope"; const QString CKnownExtension::internalSpeedDist = "::ql:speeddist"; const QString CKnownExtension::internalSpeedTime = "::ql:speedtime"; const QString CKnownExtension::internalEle = "::ql:ele"; const QString CKnownExtension::internalProgress = "::ql:progress"; const QString CKnownExtension::internalTerrainSlope = "::ql:terrainslope"; QHash CKnownExtension::knownExtensions; QSet CKnownExtension::registeredNS; static const int NOORDER = std::numeric_limits::max(); static fTrkPtGetVal getExtensionValueFunc(const QString ext) { return [ext](const CTrackData::trkpt_t &p) { bool ok; qreal val = p.extensions.value(ext).toReal(&ok); return ok ? val : NOFLOAT; }; } bool CKnownExtension::registerNS(const QString &ns) { if(!registeredNS.contains(ns)) { registeredNS.insert(ns); return true; } return false; } void CKnownExtension::initGarminTPXv1(const IUnit &units, const QString &ns) { if(!registerNS(ns)) { return; } // support for the Garmin TrackPointExtension v1 // https://www8.garmin.com/xmlschemas/TrackPointExtensionv1.xsd knownExtensions.insert(ns % ":TrackPointExtension|" % ns % ":atemp", { tr("Air Temp.", "extShortName"), tr("Air Temperature", "extLongName"), 0, -100., 100., 1., "°C", "://icons/32x32/CSrcATemp.png", true, false, getExtensionValueFunc(ns % ":TrackPointExtension|" % ns % ":atemp")}); knownExtensions.insert(ns % ":TrackPointExtension|" % ns % ":wtemp", { tr("Water Temp.", "extShortName"), tr("Water Temperature", "extLongName"), 1, -100., 100., 1., "°C", "://icons/32x32/CSrcWTemp.png", true, false, getExtensionValueFunc(ns % ":TrackPointExtension|" % ns % ":wtemp")}); knownExtensions.insert(ns % ":TrackPointExtension|" % ns % ":depth", { tr("Depth", "extShortName"), tr("Depth", "extLongName"), 2, 0., 12000., units.basefactor, units.baseunit, "://icons/32x32/CSrcDepth.png", true, false, getExtensionValueFunc(ns % ":TrackPointExtension|" % ns % ":depth")}); knownExtensions.insert(ns % ":TrackPointExtension|" % ns % ":hr", { tr("Heart R.", "extShortName"), tr("Heart Rate", "extLongName"), 3, 0., 300., 1., "bpm", "://icons/32x32/CSrcHR.png", true, false, getExtensionValueFunc(ns % ":TrackPointExtension|" % ns % ":hr")}); knownExtensions.insert(ns % ":TrackPointExtension|" % ns % ":cad", { tr("Cadence", "extShortName"), tr("Cadence", "extLongName"), 4, 0., 500., 1., "rpm", "://icons/32x32/CSrcCAD.png", true, false, getExtensionValueFunc(ns % ":TrackPointExtension|" % ns % ":cad")}); } void CKnownExtension::initMioTPX(const IUnit &units) { // support for extensions used by MIO Cyclo ver. 4.2 (who needs xml namespaces?!) knownExtensions.insert("heartrate", { tr("Heart R.", "extShortName"), tr("Heart Rate", "extLongName"), NOORDER, 0., 300., 1., "bpm", "://icons/32x32/CSrcHR.png", true, false, getExtensionValueFunc("heartrate")}); knownExtensions.insert("cadence", { tr("Cadence", "extShortName"), tr("Cadence", "extLongName"), NOORDER, 0., 500., 1., "rpm", "://icons/32x32/CSrcCAD.png", true, false, getExtensionValueFunc("cadence")}); knownExtensions.insert("speed", { tr("Speed", "extShortName"), tr("Speed", "extLongName"), NOORDER, 0., 600., units.speedfactor, units.speedunit, "://icons/32x32/CSrcSpeed.png", true, false, getExtensionValueFunc("speed")}); knownExtensions.insert("acceleration", { tr("Accel.", "extShortName"), tr("Acceleration", "extLongName"), NOORDER, std::numeric_limits::lowest(), std::numeric_limits::max(), units.basefactor, units.baseunit + "/s²", "://icons/32x32/CSrcAccel.png", true, false, getExtensionValueFunc("acceleration")}); knownExtensions.insert("course", { tr("Course", "extShortName"), tr("Course", "extLongName"), NOORDER, -3.2, 3.2, 1., "rad", "://icons/32x32/CSrcCourse.png", true, false, getExtensionValueFunc("course")}); } void CKnownExtension::initClueTrustTPXv1(const IUnit &units, const QString &ns) { knownExtensions.insert(ns % ":cadence", { tr("Cadence", "extShortName"), tr("Cadence", "extLongName"), 0, 0., 500., 1., "rpm", "://icons/32x32/CSrcCAD.png", true, false, getExtensionValueFunc(ns % ":cadence")}); knownExtensions.insert(ns % ":temp", { tr("Temp.", "extShortName"), tr("Temperature", "extLongName"), 1, -100., 100., 1., "°C", "://icons/32x32/CSrcATemp.png", true, false, getExtensionValueFunc(ns % ":temp")}); knownExtensions.insert(ns % ":distance", { tr("Dist.", "extShortName"), tr("Distance", "extLongName"), 2, 0., +100000000., units.basefactor, units.baseunit, "://icons/32x32/CSrcDistance.png", true, false, getExtensionValueFunc(ns % ":distance") }); knownExtensions.insert(ns % ":altitude", { tr("Ele.", "extShortName"), tr("Elevation", "extLongName"), 3, -1000., +10000., units.basefactor, units.baseunit, "://icons/32x32/CSrcElevation.png", true, false, getExtensionValueFunc(ns % ":altitude") }); knownExtensions.insert(ns % ":energy", { tr("Energy", "extShortName"), tr("Energy", "extLongName"), 4, 0., 10000., 1., "kcal/min", "://icons/32x32/CSrcEnergy.png", true, false, getExtensionValueFunc(ns % ":energy") }); knownExtensions.insert(ns % ":seaLevelPressure", { tr("Sea Lev. Pres.", "extShortName"), tr("Sea Level Pressure", "extLongName"), 5, 0., 1500., 1., "hPa", "://icons/32x32/CSrcSeaLevelPressure.png", true, false, getExtensionValueFunc(ns % ":seaLevelPressure") }); knownExtensions.insert(ns % ":speed", { tr("Speed", "extShortName"), tr("Speed", "extLongName"), 6, 0., 600., units.speedfactor, units.speedunit, "://icons/32x32/CSrcSpeed.png", true, false, getExtensionValueFunc(ns % ":speed")}); knownExtensions.insert(ns % ":verticalSpeed", { tr("v. Speed", "extShortName"), tr("Vertical Speed", "extLongName"), 7, 0., 50., units.speedfactor, units.speedunit, "://icons/32x32/CSrcVertSpeed.png", true, false, getExtensionValueFunc(ns % ":verticalSpeed")}); } void CKnownExtension::init(const IUnit &units) { knownExtensions = { {internalSlope, { tr("Slope", "extShortName"), tr("Slope*"), -1, -90., 90., 1., "°", "://icons/32x32/CSrcSlope.png", true, true, [](const CTrackData::trkpt_t &p) { return p.slope1; }} }, {internalSpeedDist, { tr("Speed", "extShortName"), tr("Speed over Distance*", "extLongName"), -1, 0., 600., units.speedfactor, units.speedunit, "://icons/32x32/CSrcSpeed.png", true, true, [](const CTrackData::trkpt_t &p) { return p.speed; }} }, {internalSpeedTime, { tr("Speed", "extShortName"), tr("Speed over Time*", "extLongName"), -1, 0., NOFLOAT, units.speedfactor, units.speedunit, "://icons/32x32/CSrcSpeed.png", true, true, [](const CTrackData::trkpt_t &p) { return p.speed; }} }, {internalEle, { tr("Ele.", "extShortName"), tr("Elevation*", "extLongName"), -1, 0., 100000., units.basefactor, units.baseunit, "://icons/32x32/CSrcElevation.png", true, true, [](const CTrackData::trkpt_t &p) { return (NOINT == p.ele) ? NOFLOAT : p.ele; }} }, {internalProgress, { tr("Progress", "extShortName"), tr("Progress*", "extLongName"), -1, 0., NOFLOAT, units.basefactor, units.baseunit, "://icons/32x32/Progress.png", true, true, [](const CTrackData::trkpt_t &p) { return p.distance; }} }, {internalTerrainSlope, { tr("Terr. Slope", "extShortName"), tr("Terrain Slope*", "extLongName"), -1, 0, 90., 1., "°", "://icons/32x32/CSrcSlope.png", true, false, getExtensionValueFunc(internalTerrainSlope)} } }; initGarminTPXv1(units, "gpxtpx"); initGarminTPXv1(units, "tp1"); initMioTPX(units); initClueTrustTPXv1(units, "gpxdata"); } const CKnownExtension CKnownExtension::get(const QString &key) { CKnownExtension def("", "", NOORDER, -100000., 100000., 1., "", "://icons/32x32/CSrcUnknown.png", false, true, getExtensionValueFunc(key) ); return knownExtensions.value(key, def); } bool CKnownExtension::isKnown(const QString &key) { return knownExtensions.contains(key); } QString CKnownExtension::getName(const QString& altName) const { bool hasNoName = nameShortText.isEmpty(); QString name = hasNoName ? altName : nameShortText; if(derivedQMS && !hasNoName) { name += "*"; } return name; } QString CKnownExtension::toString(qreal value, bool withName, const QString &key) const { QString str; if(key == CKnownExtension::internalProgress) { return str; } else if(key.contains("speed")) { QString v, u; IUnit::self().meter2speed(value, v, u); str = v + u; } else if(key == CKnownExtension::internalEle) { QString v, u; IUnit::self().meter2elevation(value, v, u); str = v + u; } else if(key == CKnownExtension::internalSlope) { QString v, u; IUnit::self().slope2string(value, v, u); str = v + u; } else { str = QString("%1%2").arg(value * factor).arg(unit); } if(withName) { str = getName(key) + " " + str; } return str; } qmapshack-1.10.0/src/gis/trk/CGisItemTrk.cpp000644 001750 000144 00000220257 13216234261 021734 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/prj/IGisProject.h" #include "gis/trk/CCutTrk.h" #include "gis/trk/CDetailsTrk.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/trk/CPropertyTrk.h" #include "gis/trk/CScrOptTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CDraw.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include #include #include #define DEFAULT_COLOR 4 #define MIN_DIST_CLOSE_TO 10 #define MIN_DIST_FOCUS 200 #define WPT_FOCUS_DIST_IN (50*50) #define WPT_FOCUS_DIST_OUT (200*200) struct trkwpt_t { QString name; qreal x = 0; qreal y = 0; IGisItem::key_t key; }; IGisItem::key_t CGisItemTrk::keyUserFocus; CGisItemTrk::CGisItemTrk(const QString &name, qint32 idx1, qint32 idx2, const CTrackData& srctrk, IGisProject * project) : IGisItem(project, eTypeTrk, NOIDX), trk(name, srctrk, idx1, idx2) { flags = eFlagCreatedInQms; deriveSecondaryData(); setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemTrk::CGisItemTrk(const CGisItemTrk& parentTrk, IGisProject *project, int idx, bool clone) : IGisItem(project, eTypeTrk, idx) { // copy track via history history = parentTrk.history; loadHistory(history.histIdxCurrent); // if track should be a clone clear history and key and // build new ones. if(clone) { trk.name += tr("_Clone"); key.clear(); history.events.clear(); setupHistory(); } if(parentTrk.isOnDevice() || !parentTrk.isReadOnly()) { flags |= eFlagWriteAllowed; } else { flags &= ~eFlagWriteAllowed; } deriveSecondaryData(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemTrk::CGisItemTrk(const SGisLine& l, const QString& name, IGisProject * project, int idx) : IGisItem(project, eTypeTrk, idx) { trk.name = name; readTrackDataFromGisLine(l); flags |= eFlagCreatedInQms | eFlagWriteAllowed; setColor(str2color("")); setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemTrk::CGisItemTrk(const QDomNode& xml, IGisProject *project) : IGisItem(project, eTypeTrk, project->childCount()) { // --- start read and process data ---- setColor(penForeground.color()); readTrk(xml, trk); // --- stop read and process data ---- setupHistory(); updateDecoration(eMarkNone, eMarkNone); if((cntInvalidPoints != 0) && (cntInvalidPoints < cntVisiblePoints)) { int res = QMessageBox::question(CMainWindow::self().getBestWidgetForParent(), tr("Invalid points...."), tr("The track '%1' has %2 invalid points out of %3 visible points. " "Do you want to hide invalid points now?").arg(getName()).arg(cntInvalidPoints).arg(cntVisiblePoints), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); if(res == QMessageBox::Yes) { filterRemoveInvalidPoints(); } } } CGisItemTrk::CGisItemTrk(const QString& filename, IGisProject * project) : IGisItem(project, eTypeTrk, project->childCount()) { // --- start read and process data ---- setColor(penForeground.color()); if(!readTwoNav(filename)) { throw -1; } // --- stop read and process data ---- setupHistory(); updateDecoration(eMarkNone, eMarkNone); } CGisItemTrk::CGisItemTrk(const history_t& hist, const QString &dbHash, IGisProject * project) : IGisItem(project, eTypeTrk, project->childCount()) { history = hist; loadHistory(hist.histIdxCurrent); if(!dbHash.isEmpty()) { lastDatabaseHash = dbHash; } } CGisItemTrk::CGisItemTrk(quint64 id, QSqlDatabase& db, IGisProject * project) : IGisItem(project, eTypeTrk, NOIDX) { loadFromDb(id, db); } CGisItemTrk::CGisItemTrk(CTrackData& trkdata, IGisProject *project) : IGisItem(project, eTypeTrk, NOIDX) , trk(std::move(trkdata)) { setupHistory(); deriveSecondaryData(); updateDecoration(eMarkNone, eMarkNone); } CGisItemTrk::CGisItemTrk(CFitStream& stream, IGisProject * project) : IGisItem(project, eTypeTrk, project->childCount()) { // --- start read and process data ---- setColor(penForeground.color()); readTrkFromFit(stream); // --- stop read and process data ---- setupHistory(); deriveSecondaryData(); updateDecoration(eMarkNone, eMarkNone); } CGisItemTrk::~CGisItemTrk() { // reset user focus if focused on this track if(key == keyUserFocus) { keyUserFocus.clear(); } /* Delete all registered INotifyTrk as they can't exist without the item. As the INotifyTrk objects will unregister via unregisterVisual() in their destructor things will get a bit complicated here. Better create a copy of the list before we start to delete. */ qDeleteAll(registeredVisuals.toList()); // now it is save to destroy the details dialog delete dlgDetails; // delete it after the detail dialog as it is used by the detail dialog delete propHandler; } template static inline bool isInRange(const T &val, const T &rangeStart, const T &rangeEnd) { return (rangeStart <= val) && (val <= rangeEnd); } IGisItem * CGisItemTrk::createClone() { int idx = -1; IGisProject * project = getParentProject(); if(project) { idx = project->indexOfChild(this); } return new CGisItemTrk(*this, project, idx, true); } void CGisItemTrk::updateFromDB(quint64 id, QSqlDatabase& db) { IGisItem::updateFromDB(id, db); /* as this will change the line significantly we better stop all focus operations and close the detail dialog. */ resetInternalData(); } void CGisItemTrk::setSymbol() { setColor(str2color(trk.color)); } void CGisItemTrk::setDataFromPolyline(const SGisLine &l) { QMutexLocker lock(&mutexItems); /* as this will change the line significantly we better stop all focus operations and close the detail dialog. */ resetInternalData(); readTrackDataFromGisLine(l); flags |= eFlagTainted; changed(tr("Changed trackpoints, sacrificed all previous data."), "://icons/48x48/LineMove.png"); } void CGisItemTrk::getPolylineFromData(QPolygonF &l) const { QMutexLocker lock(&mutexItems); trk.getPolyline(l); } void CGisItemTrk::getPolylineFromData(SGisLine &l) { QMutexLocker lock(&mutexItems); trk.getPolyline(l); } void CGisItemTrk::readTrackDataFromGisLine(const SGisLine &l) { QMutexLocker lock(&mutexItems); trk.readFrom(l); deriveSecondaryData(); } void CGisItemTrk::registerVisual(INotifyTrk * visual) { registeredVisuals << visual; } void CGisItemTrk::unregisterVisual(INotifyTrk * visual) { registeredVisuals.remove(visual); } static void addRowLimit(QString& str, const QString& name, const QString& min, const QString& max) { str += ""; str += "" + name + ""; str += "" + min + ""; str += "" + max + ""; str += ""; } static bool sortByName(const QString& item1, const QString& item2) { static QCollator collator; // this will set collator to natural sorting mode (instead of lexical) collator.setNumericMode(true); return collator.compare(item1, item2) < 0; } QString CGisItemTrk::getInfoLimits() const { QString str = ""; str += ""; QStringList keys = extrema.keys(); qSort(keys.begin(), keys.end(), sortByName); for(const QString& key : keys) { const CKnownExtension& ext = CKnownExtension::get(key); const limits_t& limit = extrema[key]; const QString& labelMin = ext.toString(limit.min, false, key); const QString& labelMax = ext.toString(limit.max, false, key); if(!labelMin.isEmpty() && !labelMax.isEmpty()) { addRowLimit(str, ext.getName(key), labelMin, labelMax); } } str += "
" + tr("min.") + "" + tr("max.") + "
"; return str; } QString CGisItemTrk::getInfo(quint32 feature) const { QString val1, unit1, val2, unit2; if(cntVisiblePoints == 0) { return feature ? QString("
%1
").arg(getName()) : QString("
"); } bool timeIsValid = (allValidFlags & CTrackData::trkpt_t::eInvalidTime) == 0; bool eleIsValid = (allValidFlags & CTrackData::trkpt_t::eInvalidEle) == 0; QString str = "
"; qint32 actCnt = activities.getActivityCount(); quint32 actFlags = activities.getAllFlags(); if(feature & eFeatureShowName) { if((actCnt == 1) && actFlags) { const CActivityTrk::desc_t& desc = activities.getDescriptor(actFlags); str += QString(" ").arg(desc.iconSmall); } str += "" + getName() + ""; } if((feature & eFeatureShowActivity) && (actCnt > 1)) { str += "
"; activities.printSummary(str); str += "
"; } else { str += "
"; IUnit::self().meter2distance(totalDistance, val1, unit1); str += tr("Length: %1%2").arg(val1).arg(unit1); if(eleIsValid && totalAscent != NOFLOAT && totalDescent != NOFLOAT) { IUnit::self().meter2elevation(totalAscent, val1, unit1); IUnit::self().meter2elevation(totalDescent, val2, unit2); str += tr(", %1%2%3, %4%5%6").arg(QChar(0x2197)).arg(val1).arg(unit1).arg(QChar(0x2198)).arg(val2).arg(unit2); } else { str += tr(", %1-, %2-").arg(QChar(0x2197)).arg(QChar(0x2198)); } str += "
"; if(timeIsValid && (totalElapsedSeconds != NOTIME)) { IUnit::self().seconds2time(totalElapsedSeconds, val1, unit1); IUnit::self().meter2speed(totalDistance / totalElapsedSeconds, val2, unit2); str += tr("Time: %1%2, Speed: %3%4").arg(val1).arg(unit1).arg(val2).arg(unit2); } else { str += tr("Time: -, Speed: -"); } str += "
"; if(timeIsValid && (totalElapsedSecondsMoving != NOTIME)) { IUnit::self().seconds2time(totalElapsedSecondsMoving, val1, unit1); IUnit::self().meter2speed(totalDistance / totalElapsedSecondsMoving, val2, unit2); str += tr("Moving: %1%2, Speed: %3%4").arg(val1).arg(unit1).arg(val2).arg(unit2); } else { str += tr("Moving: -, Speed: -"); } str += "
"; } str += "
"; if(timeIsValid && timeStart.isValid()) { str += tr("Start: %1").arg(IUnit::datetime2string(timeStart, false, boundingRect.center())); } else { str += tr("Start: -"); } str += "
"; if(timeIsValid && timeEnd.isValid()) { str += tr("End: %1").arg(IUnit::datetime2string(timeEnd, false, boundingRect.center())); } else { str += tr("End: -"); } str += "
"; str += tr("Points: %1 (%2)").arg(cntVisiblePoints).arg(cntTotalPoints) + "
"; if((allValidFlags & (CTrackData::trkpt_t::eValidEle|CTrackData::trkpt_t::eInvalidEle)) == (CTrackData::trkpt_t::eValidEle|CTrackData::trkpt_t::eInvalidEle)) { str += "" + tr("Invalid elevations!") + "
"; } if((allValidFlags & (CTrackData::trkpt_t::eValidTime|CTrackData::trkpt_t::eInvalidTime)) == (CTrackData::trkpt_t::eValidTime|CTrackData::trkpt_t::eInvalidTime)) { str += "" + tr("Invalid timestamps!") + "
"; } if((allValidFlags & (CTrackData::trkpt_t::eValidPos|CTrackData::trkpt_t::eInvalidPos)) == (CTrackData::trkpt_t::eValidPos|CTrackData::trkpt_t::eInvalidPos)) { str += "" + tr("Invalid positions!") + "
"; } if(feature & eFeatureShowFullText) { QStringList actNames; activities.getActivityNames(actNames); if(!actNames.isEmpty()) { str += "
" + tr("Activities: %1").arg(actNames.join(", ")); } QString desc = removeHtml(trk.desc).simplified(); if(desc.count()) { if(!str.isEmpty()) { str += "
\n"; } str += desc; } QString cmt = removeHtml(trk.cmt).simplified(); if((cmt != desc) && cmt.count()) { if(!str.isEmpty()) { str += "
\n"; } str += cmt; } } return str + "
"; } QString CGisItemTrk::getInfoRange() const { qreal tmp, slope1; QString str, val, unit; if((mouseRange1 == nullptr) || (mouseRange2 == nullptr) || (mouseRange1 == mouseRange2)) { return str; } const CTrackData::trkpt_t *pt1 = mouseRange1; const CTrackData::trkpt_t *pt2 = mouseRange2; if(mouseRange1->idxTotal >= mouseRange2->idxTotal) { pt1 = mouseRange2; pt2 = mouseRange1; } for(; pt1->isHidden() && (pt1->idxTotal < (cntTotalPoints - 1)); ++pt1) { } for(; pt2->isHidden() && (pt2->idxTotal > 0); --pt2) { } bool timeIsValid = pt1->time.isValid() && pt2->time.isValid(); qreal deltaTime = pt2->time.toTime_t() - pt1->time.toTime_t(); const qreal distance = pt2->distance - pt1->distance; IUnit::self().meter2distance(distance, val, unit); str += QString("%3 %1%2 ").arg(val).arg(unit).arg(QChar(0x21A6)); if(timeIsValid) { quint32 t = pt2->time.toTime_t() - pt1->time.toTime_t(); quint32 hh = t / 3600; quint32 mm = (t % 3600) / 60; quint32 ss = t % 60; str += QString("%4 %1:%2:%3").arg(hh, 2, 10, QChar('0')).arg(mm, 2, 10, QChar('0')).arg(ss, 2, 10, QChar('0')).arg(QChar(0x231a)); IUnit::self().meter2speed(distance/deltaTime, val, unit); str += QString(", %3 %1%2").arg(val).arg(unit).arg(QChar(0x21A3)); } str += "\n"; qreal deltaAscent = pt2->ascent - pt1->ascent; qreal deltaDescent = pt2->descent - pt1->descent; tmp = qAtan(deltaAscent / distance); slope1 = qAbs(tmp * 360.0 / (2 * M_PI)); QString val2, unit2; IUnit::self().slope2string(slope1, val2, unit2); IUnit::self().meter2elevation(deltaAscent, val, unit); str += QString("%3 %1%2 (%4%5)").arg(val).arg(unit).arg(QChar(0x2197)).arg(val2).arg(unit2); if(timeIsValid) { IUnit::self().meter2speed(deltaAscent/deltaTime, val, unit); str += QString(", %1%2").arg(val).arg(unit); } str += "\n"; tmp = qAtan(deltaDescent/distance); slope1 = qAbs(tmp * 360.0/(2 * M_PI)); IUnit::self().slope2string(slope1, val2, unit2); IUnit::self().meter2elevation(deltaDescent, val, unit); str += QString("%3 %1%2 (%4%5)").arg(val).arg(unit).arg(QChar(0x2198)).arg(val2).arg(unit2); if(timeIsValid) { IUnit::self().meter2speed(deltaDescent/deltaTime, val, unit); str += QString(", %1%2").arg(val).arg(unit); } return str + "\n"; } QString CGisItemTrk::getInfoTrkPt(const CTrackData::trkpt_t& pt) const { QString str, val1, unit1; if(pt.idxTotal == pt.idxVisible) { str += tr("Index: %1").arg(pt.idxVisible); } else { str += tr("Index: visible %1, total %2").arg(pt.idxVisible).arg(pt.idxTotal); } str += "\n"; if(totalElapsedSeconds != 0) { str += IUnit::datetime2string(pt.time, false, QPointF(pt.lon, pt.lat) * DEG_TO_RAD); str += "\n"; } IUnit::self().meter2elevation(pt.ele, val1, unit1); str += tr("Ele.: %1%2").arg(val1).arg(unit1); if(pt.slope1 != NOFLOAT) { IUnit::self().slope2string(pt.slope1, val1, unit1); str += tr(", Slope: %1%2").arg(val1).arg(unit1); } if(pt.speed != NOFLOAT) { IUnit::self().meter2speed(pt.speed, val1, unit1); str += tr(", Speed: %1%2").arg(val1).arg(unit1); } QStringList keys = pt.extensions.keys(); keys.sort(); qint32 more = keys.size() - 10; if(more > 0) { keys = keys.mid(0, 10); } for(const QString &key : keys) { const CKnownExtension &ext = CKnownExtension::get(key); if(ext.known) { str += "\n" + ext.nameLongText + ": " + QString("%1%2").arg(ext.valueFunc(pt)*ext.factor, 0, 'f', 1).arg(ext.unit); } else { QStringList tags = key.split("|"); str += "\n" + tags.last() + ": " + pt.extensions[key].toString(); } } if(more > 0) { str += "\n" + tr("... and %1 tags not displayed").arg(more); } return str; } QString CGisItemTrk::getInfoProgress(const CTrackData::trkpt_t& pt) const { QString val, unit; QString asc = tr("Ascent: - (-)"); QString dsc = tr("Descent: - (-)"); QString dst = tr("Distance: - (-)"); QString mov = tr("Moving: - (-)"); if(pt.ascent != NOFLOAT) { IUnit::self().meter2elevation(pt.ascent, val, unit); asc = tr("Ascent: %1%2 (%3%)").arg(val).arg(unit).arg(pt.ascent * 100/totalAscent, 2, 'f', 0); } if(pt.descent != NOFLOAT) { IUnit::self().meter2elevation(pt.descent, val, unit); dsc = tr(", Descent: %1%2 (%3%)").arg(val).arg(unit).arg(pt.descent * 100/totalDescent, 2, 'f', 0); } if(pt.distance != NOFLOAT) { IUnit::self().meter2distance(pt.distance, val, unit); dst = tr("Distance: %1%2 (%3%)").arg(val).arg(unit).arg(pt.distance * 100/totalDistance, 2, 'f', 0); } if(pt.elapsedSeconds != NOFLOAT) { IUnit::self().seconds2time(pt.elapsedSecondsMoving, val, unit); mov = tr(", Moving: %1%2 (%3%)").arg(val).arg(unit).arg(pt.elapsedSecondsMoving * 100/totalElapsedSecondsMoving, 2, 'f', 0); } return QString("%1%2\n%3%4").arg(asc).arg(dsc).arg(dst).arg(mov); } QString CGisItemTrk::getInfoRange(const CTrackData::trkpt_t& pt1, const CTrackData::trkpt_t& pt2) const { QString val, unit; qreal dt = NOFLOAT; if(pt1.time.isValid() && pt2.time.isValid()) { dt = pt2.time.toTime_t() - pt1.time.toTime_t(); } QString asc = tr("Ascent: -"); QString dsc = tr("Descent: -"); if((pt1.ascent != NOFLOAT) && (pt2.ascent != NOFLOAT)) { IUnit::self().meter2elevation(pt2.ascent - pt1.ascent, val, unit); asc = tr("Ascent: %1%2").arg(val).arg(unit); if(dt != NOFLOAT) { IUnit::self().meter2speed((pt2.ascent - pt1.ascent)/dt, val, unit); asc += tr(", %1%2").arg(val).arg(unit); } } if((pt1.descent != NOFLOAT) && (pt2.descent != NOFLOAT)) { IUnit::self().meter2elevation(pt2.descent - pt1.descent, val, unit); dsc = tr(", Descent: %1%2").arg(val).arg(unit); if(dt != NOFLOAT) { IUnit::self().meter2speed((pt2.descent - pt1.descent)/dt, val, unit); dsc += tr(", %1%2").arg(val).arg(unit); } } IUnit::self().meter2distance(pt2.distance - pt1.distance, val, unit); QString dsttme = tr("Distance: %1%2").arg(val).arg(unit); if(dt != NOFLOAT) { IUnit::self().seconds2time(dt, val, unit); dsttme += tr(", Time: %1%2").arg(val).arg(unit); } return QString("%1%2\n%3").arg(asc).arg(dsc).arg(dsttme); } qint32 CGisItemTrk::getElevation(qint32 idx) const { const CTrackData::trkpt_t *trkpt = trk.getTrkPtByTotalIndex(idx); return trkpt != nullptr ? trkpt->ele : NOINT; } IScrOpt * CGisItemTrk::getScreenOptions(const QPoint& origin, IMouse * mouse) { if(scrOpt.isNull()) { scrOpt = new CScrOptTrk(this, origin, mouse); } return scrOpt; } static qint32 getIdxPointCloseBy(const QPoint &pos, const QPolygonF &line) { qint32 idx = 0; qint32 bestIdx = NOIDX; qint32 bestDst = NOINT; for(const QPointF &pt : line) { int dst = (pos - pt).manhattanLength(); if(dst < bestDst) { bestIdx = idx; bestDst = dst; } ++idx; } return bestIdx; } QPointF CGisItemTrk::getPointCloseBy(const QPoint& screenPos) { QMutexLocker lock(&mutexItems); qint32 bestIdx = getIdxPointCloseBy(screenPos, lineSimple); return (NOIDX == bestIdx) ? NOPOINTF : lineSimple[bestIdx]; } bool CGisItemTrk::isRangeSelected() const { return mouseRange1 != mouseRange2; } static inline void updateExtrema(CGisItemTrk::limits_t &extrema, qreal val, const QPointF& pos) { if(NOFLOAT != val) { extrema.setMin(val, pos); extrema.setMax(val, pos); } } void CGisItemTrk::updateExtremaAndExtensions() { extrema = QHash(); limits_t extremaSpeed; limits_t extremaSlope; limits_t extremaEle; limits_t extremaProgress; existingExtensions = QSet(); QSet nonRealExtensions; for(const CTrackData::trkpt_t &pt : trk) { if(pt.isHidden()) { continue; } existingExtensions.unite(pt.extensions.keys().toSet()); const QPointF& pos = {pt.lon, pt.lat}; for(const QString &key : pt.extensions.keys()) { bool isReal = false; qreal val = pt.extensions.value(key).toReal(&isReal); if(isReal) { if(!extrema.contains(key)) { extrema[key] = limits_t(); } updateExtrema(extrema[key], val, pos); } else { nonRealExtensions << key; } } updateExtrema(extremaSpeed, pt.speed, pos); updateExtrema(extremaEle, pt.ele, pos); updateExtrema(extremaSlope, pt.slope1, pos); updateExtrema(extremaProgress, pt.distance, pos); } if(extremaEle.min < extremaEle.max) { existingExtensions << CKnownExtension::internalEle; extrema[CKnownExtension::internalEle] = extremaEle; } if(extremaSlope.min < extremaSlope.max) { existingExtensions << CKnownExtension::internalSlope; extrema[CKnownExtension::internalSlope] = extremaSlope; } if(numeric_limits::max() != extremaSpeed.min) { existingExtensions << CKnownExtension::internalSpeedDist; existingExtensions << CKnownExtension::internalSpeedTime; extrema[CKnownExtension::internalSpeedDist] = extremaSpeed; } if(numeric_limits::max() != extremaProgress.min) { existingExtensions << CKnownExtension::internalProgress; extrema[CKnownExtension::internalProgress] = extremaProgress; } existingExtensions.subtract(nonRealExtensions); } void CGisItemTrk::resetInternalData() { mouseClickFocus = nullptr; mouseMoveFocus = nullptr; resetMouseRange(); delete dlgDetails; } void CGisItemTrk::verifyTrkPt(CTrackData::trkpt_t*& last, CTrackData::trkpt_t& trkpt) { trkpt.valid = (trkpt.ele != NOINT) ? quint32(CTrackData::trkpt_t::eValidEle) : quint32(CTrackData::trkpt_t::eInvalidEle); trkpt.valid |= (trkpt.lat < -90) || (trkpt.lat > 90) || (trkpt.lon < -180) || (trkpt.lon > 180) ? quint32(CTrackData::trkpt_t::eInvalidPos) : quint32(CTrackData::trkpt_t::eValidPos); if(trkpt.time.isValid()) { if(last != nullptr) { trkpt.valid |= (trkpt.time.toMSecsSinceEpoch() - last->time.toMSecsSinceEpoch()) < 0 ? quint32(CTrackData::trkpt_t::eInvalidTime) : quint32(CTrackData::trkpt_t::eValidTime); } else { trkpt.valid |= CTrackData::trkpt_t::eValidTime; } last = &trkpt; } else { trkpt.valid |= CTrackData::trkpt_t::eInvalidTime; } } void CGisItemTrk::consolidatePoints() { for(CTrackData::trkseg_t &seg : trk.segs) { if(seg.pts.empty()) { continue; } seg.pts.first().unsetFlag(CTrackData::trkpt_t::eSubpt); seg.pts.last().unsetFlag(CTrackData::trkpt_t::eSubpt); } } void CGisItemTrk::deriveSecondaryData() { consolidatePoints(); qreal north = -90; qreal east = -180; qreal south = 90; qreal west = 180; // reset all secondary data allValidFlags = 0; cntInvalidPoints = 0; cntTotalPoints = 0; cntVisiblePoints = 0; timeStart = QDateTime(); timeEnd = QDateTime(); totalDistance = NOFLOAT; totalAscent = NOFLOAT; totalDescent = NOFLOAT; totalElapsedSeconds = NOTIME; totalElapsedSecondsMoving = NOTIME; trk.removeEmptySegments(); // no data -> nothing to do if(trk.isEmpty()) { return; } CTrackData::trkpt_t * lastValid = nullptr; CTrackData::trkpt_t * lastTrkpt = nullptr; qreal timestampStart = NOFLOAT; qint32 lastEle = NOINT; // linear list of pointers to visible track points QVector lintrk; for(CTrackData::trkpt_t& trkpt : trk) { // verify data of all points verifyTrkPt(lastValid, trkpt); trkpt.idxTotal = cntTotalPoints++; if(trkpt.isHidden()) { trkpt.reset(); continue; } // count only visible points to allValidFlags allValidFlags |= trkpt.valid; if((trkpt.valid & 0xFFFF0000) != 0) { cntInvalidPoints++; } trkpt.idxVisible = cntVisiblePoints++; lintrk << &trkpt; west = qMin(west, trkpt.lon); east = qMax(east, trkpt.lon); south = qMin(south, trkpt.lat); north = qMax(north, trkpt.lat); if(lastTrkpt != nullptr) { trkpt.deltaDistance = lastTrkpt->distanceTo(trkpt); trkpt.distance = lastTrkpt->distance + trkpt.deltaDistance; trkpt.elapsedSeconds = trkpt.time.toMSecsSinceEpoch()/1000.0 - timestampStart; // ascent descent if(lastEle != NOINT) { qint32 delta = trkpt.ele - lastEle; trkpt.ascent = lastTrkpt->ascent; trkpt.descent = lastTrkpt->descent; if(qAbs(delta) >= ASCENT_THRESHOLD) { const qint32 step = (delta/ASCENT_THRESHOLD)*ASCENT_THRESHOLD; if(delta > 0) { trkpt.ascent += step; } else { trkpt.descent -= step; } lastEle += step; } } // time moving trkpt.elapsedSecondsMoving = lastTrkpt->elapsedSecondsMoving; qreal dt = (trkpt.time.toMSecsSinceEpoch() - lastTrkpt->time.toMSecsSinceEpoch()) / 1000.0; if(dt > 0 && ((trkpt.deltaDistance / dt) > 0.2)) { trkpt.elapsedSecondsMoving += dt; } } else { timeStart = trkpt.time; timestampStart = timeStart.toMSecsSinceEpoch()/1000.0; lastEle = trkpt.ele; trkpt.deltaDistance = 0; trkpt.distance = 0; trkpt.ascent = 0; trkpt.descent = 0; trkpt.elapsedSeconds = 0; trkpt.elapsedSecondsMoving = 0; } lastTrkpt = &trkpt; } boundingRect = QRectF(QPointF(west * DEG_TO_RAD, north * DEG_TO_RAD), QPointF(east * DEG_TO_RAD,south * DEG_TO_RAD)); for(int p = 0; p < lintrk.size(); p++) { CTrackData::trkpt_t& trkpt = *lintrk[p]; qreal d1 = trkpt.distance; qreal e1 = trkpt.ele; qreal t1 = trkpt.time.toMSecsSinceEpoch() / 1000.0; for(int n = p; n > 0; --n) { CTrackData::trkpt_t & trkpt2 = *lintrk[n]; if(trkpt2.ele == NOINT) { continue; } if(trkpt.distance - trkpt2.distance >= 25) { d1 = trkpt2.distance; e1 = trkpt2.ele; t1 = trkpt2.time.toMSecsSinceEpoch()/1000.0; break; } } qreal d2 = trkpt.distance; qreal e2 = trkpt.ele; qreal t2 = trkpt.time.toMSecsSinceEpoch() / 1000.0; for(int n = p; n < lintrk.size(); ++n) { CTrackData::trkpt_t & trkpt2 = *lintrk[n]; if(trkpt2.ele == NOINT) { continue; } if(trkpt2.distance - trkpt.distance >= 25) { d2 = trkpt2.distance; e2 = trkpt2.ele; t2 = trkpt2.time.toMSecsSinceEpoch() / 1000.0; break; } } qreal a = qAtan((e2 - e1)/(d2 - d1)); trkpt.slope1 = a * 360.0/(2 * M_PI); trkpt.slope2 = qTan(trkpt.slope1 * DEG_TO_RAD) * 100; if((t2 - t1) > 0) { trkpt.speed = (d2 - d1) / (t2 - t1); } else { trkpt.speed = NOFLOAT; } } if(nullptr != lastTrkpt) { timeEnd = lastTrkpt->time; totalDistance = lastTrkpt->distance; totalAscent = lastTrkpt->ascent; totalDescent = lastTrkpt->descent; totalElapsedSeconds = lastTrkpt->elapsedSeconds; totalElapsedSecondsMoving = lastTrkpt->elapsedSecondsMoving; } activities.update(); updateExtremaAndExtensions(); // make sure we have a graph properties object by now if(propHandler == nullptr) { propHandler = new CPropertyTrk(*this); limitsGraph1.setSource(CKnownExtension::internalEle); } else { propHandler->setupData(); } setupInterpolation(interp.valid, interp.Q); updateVisuals(eVisualPlot|eVisualDetails|eVisualProject|eVisualColorAct|eVisualTrkTable, "deriveSecondaryData()"); // qDebug() << "--------------" << getName() << "------------------"; // qDebug() << "allValidFlags" << hex << allValidFlags; // qDebug() << "totalDistance" << totalDistance; // qDebug() << "totalAscent" << totalAscent; // qDebug() << "totalDescent" << totalDescent; // qDebug() << "totalElapsedSeconds" << totalElapsedSeconds; // qDebug() << "totalElapsedSecondsMoving" << totalElapsedSecondsMoving; } void CGisItemTrk::findWaypointsCloseBy(CProgressDialog& progress, quint32& current) { IGisProject * project = getParentProject(); if(nullptr == project) { return; } quint32 lastCurrent = current; bool withDoubles = project->getSortingRoadbook() != IGisProject::eSortRoadbookTrackWithoutDouble; QVector line; // combine all segments to a single line for(CTrackData::trkpt_t& pt : trk) { pt.keyWpt.clear(); if(pt.isHidden()) { continue; } pointDP dp(pt.lon * DEG_TO_RAD, pt.lat * DEG_TO_RAD, 0); dp.idx = pt.idxVisible; line << dp; } if(line.isEmpty()) { return; } // convert coordinates of all waypoints into meter coordinates relative to the first track point point3D pt0 = line[0]; QList trkwpts; for(int i=0; i < project->childCount(); i++) { CGisItemWpt * wpt = dynamic_cast(project->child(i)); if(wpt == nullptr) { continue; } if(!boundingRect.contains(wpt->getBoundingRect().topLeft())) { continue; } QPointF pos = wpt->getPosition(); qreal a1 = 0, a2 = 0; qreal d = GPS_Math_Distance(pt0.x, pt0.y, pos.x() * DEG_TO_RAD, pos.y() * DEG_TO_RAD, a1, a2); trkwpt_t trkwpt; trkwpt.x = qCos(a1 * DEG_TO_RAD) * d; trkwpt.y = qSin(a1 * DEG_TO_RAD) * d; trkwpt.name = wpt->getName(); trkwpt.key = wpt->getKey(); trkwpts << trkwpt; } // convert all coordinates into meter relative to the first track point. for(pointDP& pt1 : line) { qreal a1 = 0, a2 = 0; qreal d = GPS_Math_Distance(pt0.x, pt0.y, pt1.x, pt1.y, a1, a2); pt1.x = qCos(a1 * DEG_TO_RAD) * d; pt1.y = qSin(a1 * DEG_TO_RAD) * d; } numberOfAttachedWpt = 0; for(const trkwpt_t &trkwpt : trkwpts) { qreal minD = WPT_FOCUS_DIST_IN; qint32 index = NOIDX; for(const pointDP &pt : line) { ++current; qreal d = (trkwpt.x - pt.x)*(trkwpt.x - pt.x) + (trkwpt.y - pt.y)*(trkwpt.y - pt.y); if(d < WPT_FOCUS_DIST_IN) { if(d < minD) { index = pt.idx; minD = d; } } else if(withDoubles && (d > WPT_FOCUS_DIST_OUT)) { CTrackData::trkpt_t * trkpt = const_cast(trk.getTrkPtByVisibleIndex(index)); if(trkpt) { ++numberOfAttachedWpt; trkpt->keyWpt = trkwpt.key; } index = NOIDX; minD = WPT_FOCUS_DIST_IN; } if(current - lastCurrent > 100) { lastCurrent = current; PROGRESS(current, return ); } } if(index != NOIDX) { CTrackData::trkpt_t * trkpt = const_cast(trk.getTrkPtByVisibleIndex(index)); if(trkpt) { ++numberOfAttachedWpt; trkpt->keyWpt = trkwpt.key; } } } updateVisuals(eVisualDetails|eVisualPlot, "findWaypointsCloseBy()"); } bool CGisItemTrk::isCloseTo(const QPointF& pos) { QMutexLocker lock(&mutexItems); return GPS_Math_DistPointPolyline(lineSimple, pos) < 20; } bool CGisItemTrk::isWithin(const QRectF& area, selflags_t flags) { return (flags & eSelectionTrk) ? IGisItem::isWithin(area, flags, lineSimple) : false; } void CGisItemTrk::gainUserFocus(bool yes) { keyUserFocus = yes ? key : key_t(); widthInfoBox = MIN_WIDTH_INFO_BOX; } void CGisItemTrk::looseUserFocus() { if(keyUserFocus == key) { keyUserFocus.clear(); } } void CGisItemTrk::edit() { if(dlgDetails.isNull()) { dlgDetails = new CDetailsTrk(*this, nullptr); dlgDetails->setObjectName(getName()); } CMainWindow::self().addWidgetToTab(dlgDetails); } bool CGisItemTrk::cut() { if(nullptr == mouseClickFocus) { return false; } CCutTrk dlg(CMainWindow::getBestWidgetForParent()); if(dlg.exec() == QDialog::Rejected) { return false; } qint32 idxMouse = mouseClickFocus->idxTotal; CCutTrk::mode_e mode = dlg.getMode(); CCutTrk::cutmode_e cutMode = dlg.getCutMode(); // if the cut action results into cloning a track, the calling method should // ask if the original track should be removed. As a track can't delete itself // this has to be done from the outside of this method. bool askToDeleteOriginal = dlg.createClone() || (mode == CCutTrk::eModeKeepBoth); // askToDeleteOriginal = store result as clone if(askToDeleteOriginal) { // clone first part? if((mode & (CCutTrk::eModeKeepBoth|CCutTrk::eModeKeepFirst)) != 0) { int idx = cutMode == CCutTrk::eCutMode1 ? idxMouse - 1 : idxMouse; if(idx < 0) { idx = 0; } QString name = getName() + QString(" (%1 - %2)").arg(0).arg(idx); IGisProject *project = nullptr; if(!getNameAndProject(name, project, tr("track"))) { return false; } new CGisItemTrk(name, 0, idx, trk, project); } // clone second part? if((mode & (CCutTrk::eModeKeepBoth|CCutTrk::eModeKeepSecond)) != 0) { QString name = getName() + QString(" (%1 - %2)").arg(idxMouse).arg(cntTotalPoints-1); IGisProject *project = nullptr; if(!getNameAndProject(name, project, tr("track"))) { return false; } new CGisItemTrk(name, idxMouse, cntTotalPoints-1, trk, project); } } else { // if the result is not a clone, the track's list of segments and trackpoints // has to be reduced. This is done by copying points into a new trackpoint list // that replaces the original one. int removeStart = ((mode & CCutTrk::eModeKeepFirst) != 0) ? idxMouse + 1 : 0; int removeEnd = ((mode & CCutTrk::eModeKeepFirst) != 0) ? cntTotalPoints : idxMouse - 1; for(CTrackData::trkseg_t& seg : trk.segs) { if(seg.isEmpty()) { continue; } if(removeStart <= seg.pts.first().idxTotal && seg.pts.last().idxTotal <= removeEnd) { // remove all points for segments, that are completely in [removeStart; removeEnd] seg.pts.clear(); } else if( isInRange(removeStart, seg.pts.first().idxTotal, seg.pts.last().idxTotal) || isInRange(removeEnd, seg.pts.first().idxTotal, seg.pts.last().idxTotal) ) { QVector pts; for(const CTrackData::trkpt_t& pt : seg.pts) { if(!(removeStart <= pt.idxTotal && pt.idxTotal <= removeEnd) ) { pts << pt; } } seg.pts = pts; } // else: keep any segments, that are not in [removeStart; removeEnd] } deriveSecondaryData(); changed(tr("Permanently removed points %1..%2").arg(removeStart).arg(removeEnd), "://icons/48x48/TrkCut.png"); } return askToDeleteOriginal; } void CGisItemTrk::reverse() { QString name = getName() + "_rev"; IGisProject *project = nullptr; if(!getNameAndProject(name, project, tr("track"))) { return; } // start with a 1:1 copy of the first track CGisItemTrk * trk1 = new CGisItemTrk(*this, project, NOIDX, false); trk1->trk.name = name; /* clear track data, item key and history. To clear the history is important as the original track's history would restore the original key */ trk1->trk.segs.clear(); trk1->key.clear(); trk1->history.events.clear(); for(const CTrackData::trkseg_t &seg : trk.segs) { CTrackData::trkseg_t seg1; for(const CTrackData::trkpt_t &pt : seg.pts) { CTrackData::trkpt_t pt1 = pt; pt1.time = QDateTime(); seg1.pts.push_front(pt1); } trk1->trk.segs.push_front(seg1); } // restore secondary data and create a new history trk1->deriveSecondaryData(); trk1->setupHistory(); trk1->updateDecoration(eMarkChanged, eMarkNone); } void CGisItemTrk::combine(const QList& keys) { if(keys.isEmpty()) { return; } QString name = getName() + " & other"; IGisProject *projectNew = nullptr; if(!getNameAndProject(name, projectNew, tr("track"))) { return; } // start with a 1:1 copy of the first track CGisItemTrk * trk1 = new CGisItemTrk(*this, projectNew, NOIDX, false); // replace name trk1->trk.name = name; /* clear track data, item key and history. To clear the history is important as the original track's history would restore the original key */ trk1->trk.segs.clear(); trk1->key.clear(); trk1->history.events.clear(); // copy the segments of all tracks to new track CGisWorkspace& gis = CGisWorkspace::self(); for(const IGisItem::key_t &key : keys) { CGisItemTrk * trk2 = dynamic_cast(gis.getItemByKey(key)); if(nullptr == trk2) { continue; } trk1->trk.segs += trk2->trk.segs; } // restore secondary data and create a new history trk1->deriveSecondaryData(); trk1->setupHistory(); trk1->updateDecoration(eMarkChanged, eMarkNone); } void CGisItemTrk::hideSelectedPoints() { if(!setReadOnlyMode(false)) { return; } // read start/stop indices qint32 idx1, idx2; getMouseRange(idx1, idx2, true); if(NOIDX == idx1) { return; } // if first index is the first point adjust index to hide it, too if(trk.isTrkPtFirstVisible(idx1)) { idx1--; } // if second index is the last point adjust index to hide it, too if(trk.isTrkPtLastVisible(idx2)) { idx2++; } // abort if there is no point between idx1 and idx2 if(idx1 + 1 == idx2) { return; } // special case for a single point if(idx1 == idx2) { --idx1; ++idx2; } // iterate over all segments and delete points between idx1 and idx2 for(CTrackData::trkpt_t& trkpt : trk) { if((idx1 < trkpt.idxTotal) && (trkpt.idxTotal < idx2)) { trkpt.setFlag(CTrackData::trkpt_t::eHidden); } } resetMouseRange(); deriveSecondaryData(); if(idx1 + 1 == idx2 - 1) { changed(tr("Hide point %1.").arg(idx1 + 1), "://icons/48x48/PointHide.png"); } else { changed(tr("Hide points %1..%2.").arg(idx1 + 1).arg(idx2 - 1), "://icons/48x48/PointHide.png"); } } void CGisItemTrk::showSelectedPoints() { if(!setReadOnlyMode(false)) { return; } qint32 idx1, idx2; getMouseRange(idx1, idx2, true); if(NOIDX == idx1) { return; } for(CTrackData::trkpt_t& trkpt : trk) { if(isInRange(trkpt.idxTotal, idx1, idx2)) { trkpt.unsetFlag(CTrackData::trkpt_t::eHidden); } } resetMouseRange(); deriveSecondaryData(); changed(tr("Show points."), "://icons/48x48/PointShow.png"); } void CGisItemTrk::copySelectedPoints() const { qint32 idx1, idx2; getMouseRange(idx1, idx2, true); if(NOIDX == idx1) { return; } QString name = getName() + QString(" (%1 - %2)").arg(idx1).arg(idx2); IGisProject *project = nullptr; if(!getNameAndProject(name, project, tr("track"))) { return; } new CGisItemTrk(name, idx1, idx2, trk, project); } void CGisItemTrk::drawItem(QPainter& p, const QPolygonF& viewport, QList &blockedAreas, CGisDraw *gis) { QMutexLocker lock(&mutexItems); lineSimple.clear(); lineFull.clear(); if(!isVisible(boundingRect, viewport,gis)) { return; } if(trk.segs.isEmpty()) { return; } QPointF pt1; QPointF p1 = viewport[0]; QPointF p2 = viewport[2]; gis->convertRad2Px(p1); gis->convertRad2Px(p2); QRectF extViewport(p1,p2); if(mode == eModeNormal) { // in normal mode the trackline without points marked as deleted is drawn for(const CTrackData::trkpt_t &pt : trk) { if(pt.isHidden()) { continue; } pt1.setX(pt.lon); pt1.setY(pt.lat); pt1 *= DEG_TO_RAD; lineSimple << pt1; } } else { // in full mode the complete track including points marked as deleted // is drawn as gray line first. Then the track without points marked as // deleted is drawn with it's configured color for(const CTrackData::trkpt_t &pt : trk) { pt1.setX(pt.lon); pt1.setY(pt.lat); pt1 *= DEG_TO_RAD; lineFull << pt1; if(pt.isHidden()) { continue; } lineSimple << pt1; } } gis->convertRad2Px(lineSimple); gis->convertRad2Px(lineFull); // draw the full line first if(mode == eModeRange) { QList lines; splitLineToViewport(lineFull, extViewport, lines); p.setPen(QPen(Qt::lightGray, penWidthBg, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); for(const QPolygonF &l : lines) { p.drawPolyline(l); } QPixmap bullet("://icons/8x8/bullet_dark_gray.png"); for(const QPolygonF &l : lines) { for(const QPointF &pt : l) { p.drawPixmap(pt.x() - 3, pt.y() - 3, bullet); } } } // ------------------------- // draw the reduced track line QList lines; splitLineToViewport(lineSimple, extViewport, lines); if(key == keyUserFocus) { p.setPen(QPen(Qt::red, penWidthHi, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); for(const QPolygonF &l : lines) { p.drawPolyline(l); } } p.setBrush(color); p.setPen(penBackground); for(const QPolygonF &l : lines) { p.drawPolyline(l); if(showArrows.val().toBool()) { CDraw::arrows(l, extViewport, p, 10, 80, lineScale.val().toDouble()); } } if(getColorizeSource().isEmpty()) { // use the track's ordinary color penForeground.setColor(color); p.setPen(penForeground); for(const QPolygonF &l : lines) { p.drawPolyline(l); } } else if(getColorizeSource() == "activity") { drawColorizedByActivity(p); } else { drawColorized(p); } // ------------------------- // draw min/max labels if(CMainWindow::self().isMinMaxTrackValues()) { if(!keyUserFocus.item.isEmpty() && (key != keyUserFocus)) { return; } for(const QString& key : extrema.keys()) { if(key == CKnownExtension::internalProgress) { continue; } const limits_t& limit = extrema[key]; QPointF posMin = limit.posMin * DEG_TO_RAD; QPointF posMax = limit.posMax * DEG_TO_RAD; gis->convertRad2Px(posMin); gis->convertRad2Px(posMax); p.setPen(Qt::white); p.setBrush(Qt::darkGreen); p.drawEllipse(posMin, 5, 5); p.setBrush(Qt::darkRed); p.drawEllipse(posMax, 5, 5); } } } static bool doesOverlap(const QList& blockedAreas, const QRectF& rect) { for(const QRectF& r : blockedAreas) { if(r.intersects(rect)) { return true; } } return false; } void CGisItemTrk::drawLimitLabels(limit_type_e type, const QString& label, const QPointF& pos, QPainter& p, const QFontMetricsF& fm, QList& blockedAreas) { const QString& fullLabel = (type == eLimitTypeMin ? tr("min.") : tr("max.")) + " " + label; QRectF rect = fm.boundingRect(fullLabel); rect.moveBottomLeft(pos.toPoint() + QPoint(10,-10)); rect.adjust(-4,-2,4,2); qint32 baseWidth = 10; qint32 basePos = 10; if(doesOverlap(blockedAreas, rect)) { rect.moveBottomRight(pos.toPoint() + QPoint(-10,-10)); basePos = rect.width() - 10; if(doesOverlap(blockedAreas, rect)) { rect.moveTopLeft(pos.toPoint() + QPoint(10,10)); basePos = 10; if(doesOverlap(blockedAreas, rect)) { rect.moveTopRight(pos.toPoint() + QPoint(-10,10)); basePos = rect.width() - 10; if(doesOverlap(blockedAreas, rect)) { return; } } } } CDraw::bubble(p, rect.toRect(), pos.toPoint(), baseWidth, basePos, (key == keyUserFocus) ? CDraw::penBorderRed : CDraw::penBorderGray); CDraw::text(fullLabel, p, rect.toRect(), type == eLimitTypeMin ? Qt::darkGreen : Qt::darkRed); blockedAreas << rect; } void CGisItemTrk::setPen(QPainter& p, QPen& pen, quint32 flag) const { flag &= CTrackData::trkpt_t::eActMask; pen.setColor((flag == 0) ? color : CActivityTrk::getDescriptor(flag).color); p.setPen(pen); } void CGisItemTrk::drawColorizedByActivity(QPainter& p) const { QPen pen; pen.setWidth(penWidthFg); pen.setCapStyle(Qt::RoundCap); for(const CTrackData::trkseg_t &segment : trk.segs) { const CTrackData::trkpt_t *ptPrev = nullptr; for(const CTrackData::trkpt_t &pt : segment.pts) { if(pt.isHidden()) { continue; } if(nullptr == ptPrev) { setPen(p, pen, pt.flags); ptPrev = &pt; continue; } if((ptPrev->flags & CTrackData::trkpt_t::eActMask) != (pt.flags & CTrackData::trkpt_t::eActMask)) { setPen(p, pen, pt.flags); } p.drawLine(lineSimple[ptPrev->idxVisible], lineSimple[pt.idxVisible]); ptPrev = &pt; } } } void CGisItemTrk::drawColorized(QPainter &p) const { auto valueFunc = CKnownExtension::get(getColorizeSource()).valueFunc; QImage colors(1, 256, QImage::Format_RGB888); QPainter colorsPainter(&colors); QLinearGradient colorsGradient(colors.rect().topLeft(), colors.rect().bottomLeft()); colorsGradient.setColorAt(1.0, QColor( 0, 0, 255)); // blue colorsGradient.setColorAt(0.6, QColor( 0, 255, 0)); // green colorsGradient.setColorAt(0.4, QColor(255, 255, 0)); // yellow colorsGradient.setColorAt(0.0, QColor(255, 0, 0)); // red colorsPainter.fillRect(colors.rect(), colorsGradient); const qreal factor = CKnownExtension::get(getColorizeSource()).factor; for(const CTrackData::trkseg_t &segment : trk.segs) { const CTrackData::trkpt_t *ptPrev = nullptr; QColor colorStart; for(const CTrackData::trkpt_t &pt : segment.pts) { if(pt.isHidden()) { continue; } if(nullptr == ptPrev) { ptPrev = &pt; continue; } float colorAt = ( factor * valueFunc(pt) - getColorizeLimitLow() ) / (getColorizeLimitHigh() - getColorizeLimitLow()); colorAt = qMin(qMax(colorAt, 0.f), 1.f); const QColor &colorEnd = colors.pixel(0, ((1.f - colorAt) * 255.f)); if(!colorStart.isValid()) { colorStart = colorEnd; } QLinearGradient grad(lineSimple[ptPrev->idxVisible], lineSimple[pt.idxVisible]); grad.setColorAt(0.f, colorStart); grad.setColorAt(1.f, colorEnd); QPen pen; pen.setBrush(QBrush(grad)); pen.setWidth(penWidthFg); pen.setCapStyle(Qt::RoundCap); p.setPen(pen); p.drawLine(lineSimple[ptPrev->idxVisible], lineSimple[pt.idxVisible]); ptPrev = &pt; colorStart = colorEnd; } } } qreal CGisItemTrk::getMin(const QString& source) const { return extrema.value(source).min * CKnownExtension::get(source).factor; } qreal CGisItemTrk::getMax(const QString& source) const { return extrema.value(source).max * CKnownExtension::get(source).factor; } qreal CGisItemTrk::getMinProp(const QString& source) const { return propHandler == nullptr ? NOFLOAT : propHandler->propBySource(source).min; } qreal CGisItemTrk::getMaxProp(const QString& source) const { return propHandler == nullptr ? NOFLOAT : propHandler->propBySource(source).max; } QString CGisItemTrk::getUnitProp(const QString& source) const { return propHandler == nullptr ? QString() : propHandler->propBySource(source).unit; } QStringList CGisItemTrk::getExistingDataSources() const { QStringList known; QStringList unknown; for(const QString &key : existingExtensions) { if(CKnownExtension::isKnown(key)) { known << key; } else { unknown << key; } } auto stringSort = [] (const QString &s1, const QString &s2) { return s1.toLower() < s2.toLower(); }; qSort(known.begin(), known.end(), stringSort); qSort(unknown.begin(), unknown.end(), stringSort); return known + unknown; } void CGisItemTrk::setColorizeSource(QString src) { if(src != getColorizeSource()) { colorSourceLimit.setSource(src); updateHistory(eVisualColorLegend|eVisualDetails); } } void CGisItemTrk::setColorizeLimitLow(qreal limit) { colorSourceLimit.setMin(limit); updateHistory(eVisualColorLegend|eVisualDetails); } void CGisItemTrk::setColorizeLimitHigh(qreal limit) { colorSourceLimit.setMax(limit); updateHistory(eVisualColorLegend|eVisualDetails); } QString CGisItemTrk::getColorizeUnit() const { return CKnownExtension::get(getColorizeSource()).unit; } void CGisItemTrk::drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { QMutexLocker lock(&mutexItems); if(trk.segs.isEmpty()) { return; } if(hasUserFocus() && mouseMoveFocus && (mode != eModeRange)) { // derive anchor QPointF anchor(mouseMoveFocus->lon, mouseMoveFocus->lat); anchor *= DEG_TO_RAD; gis->convertRad2Px(anchor); // create trackpoint info text QString str = getInfoTrkPt(*mouseMoveFocus); // calculate bounding box of text QFont f = CMainWindow::self().getMapFont(); QFontMetrics fm(f); QRect rectText = fm.boundingRect(QRect(0, 0, 500, 0), Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, str); // The initial minimum size of the box will be MIN_WIDTH_INFO_BOX. // If a larger box is needed the minimum grows. By that the width // of the box will only grow but not jump between sizes if(rectText.width() < widthInfoBox) { rectText.setWidth(widthInfoBox); } else { widthInfoBox = rectText.width(); } // create info box int w = rectText.width() + 5 + 5; int h = rectText.height() + 5 + (fm.height() + 8); if(totalElapsedSeconds != 0) { h += 5 + fm.height() + 8; } p.setFont(f); // draw the bubble QRect box(0, 0, w, h); box.moveBottomLeft(anchor.toPoint() + QPoint(-50, -50)); CDraw::bubble(p, box, anchor.toPoint(), 18 /* px */, 21 /* px */); p.save(); p.translate(box.topLeft()); QColor pbarBlue(150, 150, 255); QColor pbarGreen(150, 255, 150); // draw progress bar distance p.translate(5, 5); QRect rectBar1(0, 0, rectText.width(), fm.height()); p.setPen(pbarBlue); p.setBrush(pbarBlue); p.drawRect(rectBar1); qreal d = mouseMoveFocus->distance * rectBar1.width() / totalDistance; p.setPen(pbarGreen); p.setBrush(pbarGreen); p.drawRect(0, 0, d, fm.height()); QString val1, unit1, val2, unit2; IUnit::self().meter2distance(mouseMoveFocus->distance, val1, unit1); IUnit::self().meter2distance(totalDistance - mouseMoveFocus->distance, val2, unit2); p.setPen(Qt::darkBlue); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignVCenter|Qt::AlignLeft, QString("%1%2").arg(val1).arg(unit1)); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignCenter, QString("%1%").arg(mouseMoveFocus->distance * 100 / totalDistance, 0, 'f', 0)); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignVCenter|Qt::AlignRight, QString("%1%2").arg(val2).arg(unit2)); // draw progress bar time if(totalElapsedSeconds != 0) { p.translate(0, fm.height() + 5); QRect rectBar2(0, 0, rectText.width(), fm.height()); p.setPen(pbarBlue); p.setBrush(pbarBlue); p.drawRect(rectBar2); qreal t = mouseMoveFocus->elapsedSecondsMoving * rectBar2.width() / totalElapsedSecondsMoving; p.setPen(pbarGreen); p.setBrush(pbarGreen); p.drawRect(0, 0, t, fm.height()); IUnit::self().seconds2time(mouseMoveFocus->elapsedSecondsMoving, val1, unit1); IUnit::self().seconds2time(totalElapsedSecondsMoving - mouseMoveFocus->elapsedSecondsMoving, val2, unit2); p.setPen(Qt::darkBlue); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignVCenter|Qt::AlignLeft, QString("%1%2").arg(val1).arg(unit1)); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignCenter, QString("%1%").arg(mouseMoveFocus->elapsedSecondsMoving * 100 / totalElapsedSecondsMoving, 0, 'f', 0)); p.drawText(QRect(0, 1, rectBar1.width(), fm.height()), Qt::AlignVCenter|Qt::AlignRight, QString("%1%2").arg(val2).arg(unit2)); } // draw text p.translate(0, fm.height() + 8); p.setPen(Qt::darkBlue); p.drawText(rectText, Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, str); p.restore(); } if(!scrOpt.isNull() && mouseClickFocus) { QPointF anchor(mouseClickFocus->lon, mouseClickFocus->lat); anchor *= DEG_TO_RAD; gis->convertRad2Px(anchor); p.drawPixmap(anchor - QPointF(4, 4), QPixmap(IGisItem::colorMap[colorIdx].bullet)); } drawRange(p); } void CGisItemTrk::drawLabel(QPainter& p, const QPolygonF&, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw* gis) { if(!keyUserFocus.item.isEmpty() && (key != keyUserFocus)) { return; } if(CMainWindow::self().isMinMaxTrackValues()) { for(const QString& key : extrema.keys()) { const CKnownExtension& ext = CKnownExtension::get(key); const limits_t& limit = extrema[key]; QPointF posMin = limit.posMin * DEG_TO_RAD; QPointF posMax = limit.posMax * DEG_TO_RAD; gis->convertRad2Px(posMin); gis->convertRad2Px(posMax); QString labelMin = ext.toString(limit.min, true, key); QString labelMax = ext.toString(limit.max, true, key); if(!labelMin.isEmpty()) { drawLimitLabels(eLimitTypeMin, labelMin, posMin, p, fm, blockedAreas); } if(!labelMax.isEmpty()) { drawLimitLabels(eLimitTypeMax, labelMax, posMax, p, fm, blockedAreas); } } } } void CGisItemTrk::drawHighlight(QPainter& p) { QMutexLocker lock(&mutexItems); if(lineSimple.isEmpty() || hasUserFocus()) { return; } // draw the reduced track line QList lines; splitLineToViewport(lineSimple, p.viewport(), lines); p.setPen(QPen(QColor(255,0,0,100), penWidthHi, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); for(const QPolygonF &line : lines) { p.drawPolyline(line); } } void CGisItemTrk::drawRange(QPainter& p) { QMutexLocker lock(&mutexItems); int idx1, idx2; getMouseRange(idx1, idx2, mode == eModeRange); if(NOIDX == idx1) { return; } const QPolygonF& line = (mode == eModeRange) ? lineFull : lineSimple; QPolygonF seg = line.mid(idx1, idx2 - idx1 + 1); p.setPen(QPen(Qt::darkGreen, penWidthHi, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(seg); p.setPen(QPen(Qt::green, penWidthFg, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(seg); } bool CGisItemTrk::setMode(mode_e m, const QString& owner) { if(!mouseFocusOwner.isEmpty() && owner != mouseFocusOwner) { return false; } mode = m; // always reset the range statemachine resetMouseRange(); mouseFocusOwner = (mode == eModeRange) ? owner : ""; CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); return true; } void CGisItemTrk::setName(const QString& str) { setText(CGisListWks::eColumnName, str); trk.name = str; changed(tr("Changed name"), "://icons/48x48/EditText.png"); } void CGisItemTrk::setComment(const QString& str) { trk.cmt = str; changed(tr("Changed comment"), "://icons/48x48/EditText.png"); } void CGisItemTrk::setDescription(const QString& str) { trk.desc = str; changed(tr("Changed description"), "://icons/48x48/EditText.png"); } void CGisItemTrk::setLinks(const QList& links) { trk.links = links; changed(tr("Changed links"), "://icons/48x48/Link.png"); } void CGisItemTrk::setElevation(qint32 idx, qint32 ele) { auto condition = [idx](const CTrackData::trkpt_t &pt) { return pt.idxTotal == idx; }; CTrackData::trkpt_t * trkpt = trk.getTrkPtByCondition(condition); if((trkpt != nullptr) && (trkpt->ele != ele)) { trkpt->ele = ele; deriveSecondaryData(); changed(tr("Changed elevation of point %1 to %2 %3").arg(idx).arg(ele).arg(IUnit::self().baseunit), "://icons/48x48/SetEle.png"); } } void CGisItemTrk::setColor(int idx) { if(idx < TRK_N_COLORS) { setColor(IGisItem::colorMap[idx].color); updateHistory(eVisualColorLegend|eVisualDetails); } } void CGisItemTrk::setActivity(quint32 flag) { for(CTrackData::trkpt_t& trkpt : trk) { trkpt.unsetFlag(CTrackData::trkpt_t::eActMask); trkpt.setFlag((enum CTrackData::trkpt_t::flag_e) flag); } deriveSecondaryData(); const CActivityTrk::desc_t &desc = CActivityTrk::getDescriptor(flag); changed(tr("Changed activity to '%1' for complete track.").arg(desc.name), desc.iconLarge); } void CGisItemTrk::setActivityRange(quint32 flags) { if(!setReadOnlyMode(false)) { return; } const CActivityTrk::desc_t &desc = CActivityTrk::getDescriptor(flags); // read start/stop indices qint32 idx1, idx2; getMouseRange(idx1, idx2, true); if(NOIDX == idx1) { return; } // special case for a single point if(idx1 == idx2) { --idx1; } // iterate over all segments and set activity flag for points between idx1 and idx2 for(CTrackData::trkpt_t& trkpt : trk) { if((idx1 <= trkpt.idxTotal) && (trkpt.idxTotal < idx2)) { trkpt.unsetFlag(CTrackData::trkpt_t::eActMask); trkpt.setFlag((enum CTrackData::trkpt_t::flag_e) flags); } } resetMouseRange(); deriveSecondaryData(); changed(tr("Changed activity to '%1' for range(%2..%3).").arg(desc.name).arg(idx1).arg(idx2), desc.iconLarge); } void CGisItemTrk::setColor(const QColor& c) { colorIdx = DEFAULT_COLOR; for(int n = 0; n < TRK_N_COLORS; n++) { if(c == IGisItem::colorMap[n].color) { colorIdx = n; break; } } color = IGisItem::colorMap[colorIdx].color; bullet = QPixmap(IGisItem::colorMap[colorIdx].bullet); setIcon(color2str(color)); } void CGisItemTrk::setIcon(const QString& iconColor) { trk.color = iconColor; icon = QPixmap("://icons/48x48/Track.png"); QPixmap mask( icon.size() ); mask.fill( str2color(iconColor) ); mask.setMask( icon.createMaskFromColor( Qt::transparent ) ); icon = mask.scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation); QTreeWidgetItem::setIcon(CGisListWks::eColumnIcon,icon); } bool CGisItemTrk::setMouseFocusByDistance(qreal dist, focusmode_e fmode, const QString &owner) { const CTrackData::trkpt_t * newPointOfFocus = nullptr; if(dist != NOFLOAT) { qreal delta = totalDistance; /// @todo: optimize search by single out segment and then do a binary search for(const CTrackData::trkpt_t &pt : trk) { if(pt.isHidden()) { continue; } qreal d = qAbs(pt.distance - dist); if(d <= delta) { newPointOfFocus = &pt; delta = d; } else { break; } } } return publishMouseFocus(newPointOfFocus, fmode, owner); } bool CGisItemTrk::setMouseFocusByTime(quint32 time, focusmode_e fmode, const QString &owner) { const CTrackData::trkpt_t * newPointOfFocus = nullptr; if(time != NOTIME) { /// @todo: optimize search by single out segment and then do a binary search qreal delta = totalElapsedSeconds; for(const CTrackData::trkpt_t &pt : trk) { if(pt.isHidden()) { continue; } qreal d = qAbs(qreal(pt.time.toTime_t()) - qreal(time)); if(d <= delta) { newPointOfFocus = &pt; delta = d; } else { break; } } } return publishMouseFocus(newPointOfFocus, fmode, owner); } QPointF CGisItemTrk::setMouseFocusByPoint(const QPoint& pt, focusmode_e fmode, const QString &owner) { QMutexLocker lock(&mutexItems); const CTrackData::trkpt_t * newPointOfFocus = nullptr; quint32 idx = 0; const QPolygonF& line = (mode == eModeRange) ? lineFull : lineSimple; if(pt != NOPOINT && GPS_Math_DistPointPolyline(line, pt) < MIN_DIST_FOCUS) { /* Iterate over the polyline used to draw the track as it contains screen coordinates. The polyline is a linear representation of the segments in the track. That is why the index into the polyline can't be used directly. In a second step we have to iterate over all segments and points of the CTrackData object until the index is reached. This is done by either getTrkPtByVisibleIndex(), or getTrkPtByTotalIndex(). Depending on the current mode. */ idx = getIdxPointCloseBy(pt, line); newPointOfFocus = (mode == eModeRange) ? trk.getTrkPtByTotalIndex(idx) : trk.getTrkPtByVisibleIndex(idx); } if(!publishMouseFocus(newPointOfFocus, fmode, owner)) { newPointOfFocus = nullptr; } /* Test for line size before applying index. This fixes random assertions because of an invalid index. The reason for this is unknown. */ return newPointOfFocus ? ((int)idx < line.size() ? line[idx] : NOPOINTF) : NOPOINTF; } bool CGisItemTrk::setMouseFocusByTotalIndex(qint32 idx, focusmode_e fmode, const QString &owner) { const CTrackData::trkpt_t *newPointOfFocus = trk.getTrkPtByTotalIndex(idx); if(nullptr != newPointOfFocus) { return publishMouseFocus(newPointOfFocus, fmode, owner); } return false; } void CGisItemTrk::resetMouseRange() { mouseRange1 = nullptr; mouseRange2 = nullptr; rangeState = eRangeStateIdle; } bool CGisItemTrk::publishMouseFocus(const CTrackData::trkpt_t * pt, focusmode_e fmode, const QString& owner) { if(mode == eModeRange) { if(mouseFocusOwner != owner) { return false; } publishMouseFocusRangeMode(pt, fmode); } else { publishMouseFocusNormalMode(pt, fmode); } return true; } void CGisItemTrk::publishMouseFocusRangeMode(const CTrackData::trkpt_t * pt, focusmode_e fmode) { switch(rangeState) { case eRangeStateIdle: { if((fmode == eFocusMouseClick) && (pt != nullptr)) { mouseRange1 = pt; rangeState = eRangeState1st; } break; } case eRangeState1st: { mouseRange2 = pt; if((fmode == eFocusMouseClick) && (pt != nullptr)) { rangeState = eRangeState2nd; } break; } case eRangeState2nd: { if(fmode == eFocusMouseClick) { resetMouseRange(); } break; } } setMouseFocusVisuals(pt); setMouseRangeFocusVisuals(mouseRange1, mouseRange2); } void CGisItemTrk::publishMouseFocusNormalMode(const CTrackData::trkpt_t * pt, focusmode_e fmode) { switch(fmode) { case eFocusMouseMove: if(pt != mouseMoveFocus) { mouseMoveFocus = pt; setMouseFocusVisuals(pt); setMouseRangeFocusVisuals(0, 0); } break; case eFocusMouseClick: if(pt != mouseClickFocus) { mouseClickFocus = pt; setMouseClickFocusVisuals(pt); } } } void CGisItemTrk::changed(const QString& what, const QString& icon) { IGisItem::changed(what, icon); updateVisuals(eVisualAll, "changed()"); } void CGisItemTrk::updateHistory(quint32 visuals) { IGisItem::updateHistory(); updateVisuals(visuals, "updateHistory()"); } void CGisItemTrk::updateVisuals(quint32 visuals, const QString& who) { qDebug() << "CGisItemTrk::updateVisuals()" << getName() << who; if(!dlgDetails.isNull() && (visuals & eVisualDetails)) { dlgDetails->updateData(); } for(INotifyTrk * visual : registeredVisuals) { if(visuals & visual->mask) { visual->updateData(); } } } void CGisItemTrk::setMouseFocusVisuals(const CTrackData::trkpt_t * pt) { if(!dlgDetails.isNull()) { dlgDetails->setMouseFocus(pt); } for(INotifyTrk * visual : registeredVisuals) { visual->setMouseFocus(pt); } } void CGisItemTrk::setMouseRangeFocusVisuals(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2) { if(!dlgDetails.isNull()) { dlgDetails->setMouseRangeFocus(pt1, pt2); } for(INotifyTrk * visual : registeredVisuals) { visual->setMouseRangeFocus(pt1, pt2); } } void CGisItemTrk::setMouseClickFocusVisuals(const CTrackData::trkpt_t * pt) { if(!dlgDetails.isNull()) { dlgDetails->setMouseClickFocus(pt); } for(INotifyTrk * visual : registeredVisuals) { visual->setMouseClickFocus(pt); } } void CGisItemTrk::setupInterpolation(bool on, qint32 q) { interp.valid = on; interp.Q = (quality_e)q; if(!on) { updateVisuals(eVisualPlot, "setupInterpolation()"); return; } const qint32 N = getNumberOfVisiblePoints(); alglib::real_1d_array x,y; x.setlength(N); y.setlength(N); qreal basefactor = IUnit::self().basefactor; for(const CTrackData::trkpt_t& trkpt : trk) { if(trkpt.isHidden()) { continue; } if(trkpt.ele == NOINT) { continue; } x[trkpt.idxVisible] = trkpt.distance; y[trkpt.idxVisible] = trkpt.ele * basefactor; } /// @todo find a better way to scale the algorithm interp.m = interp.Q*50; if(N < 400) { interp.m = N / (16/interp.Q); } interp.m &= 0xFFFFFFFE; try { alglib::spline1dfitcubic(x, y, interp.m, interp.info, interp.p, interp.rep); } catch(const alglib::ap_error& e) { qWarning() << "Error from alglib: " << e.msg.c_str(); } interp.valid = interp.info > 0; updateVisuals(eVisualPlot, "setupInterpolation()"); } qreal CGisItemTrk::getElevationInterpolated(qreal d) { try { return alglib::spline1dcalc(interp.p, d); } catch(const alglib::ap_error& e) { qWarning() << "Error from alglib: " << e.msg.c_str(); interp.valid = false; } return NOFLOAT; } void CGisItemTrk::getMouseRange(int &idx1, int &idx2, bool total) const { if(nullptr == mouseRange1 || nullptr == mouseRange2) { idx1 = NOIDX; idx2 = NOIDX; } else { idx1 = total ? mouseRange1->idxTotal : mouseRange1->idxVisible; idx2 = total ? mouseRange2->idxTotal : mouseRange2->idxVisible; if(idx1 > idx2) { qSwap(idx1, idx2); } } } qmapshack-1.10.0/src/gis/trk/ISelectActivityColor.ui000644 001750 000144 00000001730 12705713523 023504 0ustar00oeichlerxusers000000 000000 ISelectActivityColor 0 0 400 300 Form 0 0 0 0 0 0 qmapshack-1.10.0/src/gis/trk/CKnownExtension.h000644 001750 000144 00000011631 13216234261 022342 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CKNOWNEXTENSION_H #define CKNOWNEXTENSION_H #include #include "gis/trk/CGisItemTrk.h" class CKnownExtension { Q_DECLARE_TR_FUNCTIONS(CKnownExtension) public: /** @brief Initialize using the default list of known namespaces @param units The unit class currently used */ static void init(const IUnit &units); /** @brief Register the Garmin TPX v1 for namespace ns @param units The unit class currently used @param ns The namespace to be used for Garmin TPX v1 */ static void initGarminTPXv1(const IUnit &units, const QString &ns); static void initClueTrustTPXv1(const IUnit &units, const QString &ns); static const QString internalSlope; //< name of internally derived slope static const QString internalSpeedDist; //< name of internally derived speed over distance static const QString internalSpeedTime; //< name of internally derived speed over time static const QString internalEle; //< name of internally derived elevation (DEM) static const QString internalProgress; //< name of internally derived progress static const QString internalTerrainSlope; //< name of internally derived terrain slope /** @brief Get extension descriptor for name If there is no known descriptor for an extension with `name`, a valid dummy descriptor will be returned. The dummy descriptor contains valid entries, `valueFunc` can be used just as if the extension was known. @param name The name of the requested extension (incl. namespace) @return a valid extension descriptor (for both known and unknown extensions) */ static const CKnownExtension get(const QString &key); static bool isKnown(const QString &key); QString nameShortText; //< short text name to display in GUI (ex. "Heart R." in y-axis) QString nameLongText; //< long text name to display in GUI (ex. Heart Rate" in ComboBox) int order; //< the order used for exporting ("relative position") qreal minimum; //< hard (enforced) minimum, cannot go lower qreal maximum; //< hard (enforced) maximum, cannot go higher qreal factor; //< factor used to convert a value to match the users' units QString unit; //< the unit (to be displayed) QString icon; //< path to an icon bool known; //< true if extension is known, false otherwise bool derivedQMS; //< if set to true the value is derived by QMS (p.x. slope*) fTrkPtGetVal valueFunc; //< the function used to retrieve the value /** * @brief Convert a value to a string @param value the value to convert @param withName set true to prepend the value with the extension's name @param key the key used to retrieve the extension via CKnownExtension::get() @return A string. */ QString toString(qreal value, bool withName, const QString& key) const; /** @brief Get the short name of the extension @param altName alternative name if the extension does not have a short name @return A string. */ QString getName(const QString& altName) const; private: static bool registerNS(const QString &ns); static QHash knownExtensions; static QSet registeredNS; CKnownExtension(QString nameShortText, QString nameLongText, int order, qreal minimum, qreal maximum, qreal factor, QString unit, QString icon, bool known, bool derivedQMS, fTrkPtGetVal valueFunc ) : nameShortText(nameShortText), nameLongText(nameLongText), order(order), minimum(minimum), maximum(maximum), factor(factor), unit(unit), icon(icon), known(known), derivedQMS(derivedQMS), valueFunc(valueFunc) { } static void initMioTPX(const IUnit &units); }; #endif // CKNOWNEXTENSION_H qmapshack-1.10.0/src/gis/trk/CActivityTrk.cpp000644 001750 000144 00000041276 13216234137 022173 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CActivityTrk.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CSettings.h" #include "units/IUnit.h" QVector CActivityTrk::actDescriptor; const CActivityTrk::desc_t CActivityTrk::dummyDesc = { "-" , CTrackData::trkpt_t::eActNone , "-" , "://icons/48x48/ActNone.png" , "://icons/16x16/ActNone.png" , QColor() }; CActivityTrk::CActivityTrk(CGisItemTrk * trk) : trk(trk) , allFlags(0) { } void CActivityTrk::init() { actDescriptor = { { // 0 "Foot" , CTrackData::trkpt_t::eActFoot , tr("Foot") , "://icons/48x48/ActFoot.png" , "://icons/16x16/ActFoot.png" , IGisItem::colorMap[0].color }, { // 1 "Cycle" , CTrackData::trkpt_t::eActCycle , tr("Bicycle") , "://icons/48x48/ActCycle.png" , "://icons/16x16/ActCycle.png" , IGisItem::colorMap[1].color }, { // 2 "Bike" , CTrackData::trkpt_t::eActBike , tr("Motor Bike") , "://icons/48x48/ActBike.png" , "://icons/16x16/ActBike.png" , IGisItem::colorMap[2].color }, { // 3 "Car" , CTrackData::trkpt_t::eActCar , tr("Car") , "://icons/48x48/ActCar.png" , "://icons/16x16/ActCar.png" , IGisItem::colorMap[3].color }, { // 4 "Cable" , CTrackData::trkpt_t::eActCable , tr("Cable Car") , "://icons/48x48/ActCable.png" , "://icons/16x16/ActCable.png" , IGisItem::colorMap[4].color }, { // 5 "Swim" , CTrackData::trkpt_t::eActSwim , tr("Swim") , "://icons/48x48/ActSwim.png" , "://icons/16x16/ActSwim.png" , IGisItem::colorMap[5].color }, { // 6 "Ship" , CTrackData::trkpt_t::eActShip , tr("Ship") , "://icons/48x48/ActShip.png" , "://icons/16x16/ActShip.png" , IGisItem::colorMap[6].color }, { // 7 "Aeronautik" , CTrackData::trkpt_t::eActAero , tr("Aeronautics") , "://icons/48x48/ActAero.png" , "://icons/16x16/ActAero.png" , IGisItem::colorMap[7].color }, { // 8 "Ski/Winter" , CTrackData::trkpt_t::eActSki , tr("Ski/Winter") , "://icons/48x48/ActSki.png" , "://icons/16x16/ActSki.png" , IGisItem::colorMap[8].color }, { // 9 "Train" , CTrackData::trkpt_t::eActTrain , tr("Public Transport") , "://icons/48x48/ActTrain.png" , "://icons/16x16/ActTrain.png" , IGisItem::colorMap[9].color } }; SETTINGS; cfg.beginGroup("Activities"); int i = 0; for(desc_t &desc : actDescriptor) { desc.color = QColor(cfg.value(QString("color%1").arg(i), desc.color.name()).toString()); ++i; } cfg.endGroup(); // Activities } void CActivityTrk::release() { SETTINGS; cfg.beginGroup("Activities"); int i = 0; for(desc_t &desc : actDescriptor) { cfg.setValue(QString("color%1").arg(i), desc.color.name()); ++i; } cfg.endGroup(); // Activities } quint32 CActivityTrk::selectActivity(QWidget *parent) { QMenu menu(parent); QAction * act; act = menu.addAction(QIcon("://icons/32x32/ActNone.png"), tr("No Activity")); act->setData(QVariant(CTrackData::trkpt_t::eActNone)); for(const desc_t &desc : actDescriptor) { act = menu.addAction(QIcon(desc.iconLarge), desc.name); act->setData(QVariant(desc.flag)); } act = menu.exec(QCursor::pos()); if(nullptr != act) { return act->data().toUInt(nullptr); } return 0xFFFFFFFF; } void CActivityTrk::update() { allFlags = 0; activityRanges.clear(); activitySummary.clear(); const CTrackData& data = trk->getTrackData(); const CTrackData::trkpt_t *lastTrkpt = nullptr; const CTrackData::trkpt_t *startTrkpt = nullptr; quint32 lastFlag = 0xFFFFFFFF; for(const CTrackData::trkpt_t &pt : data) { allFlags |= pt.flags; if(pt.isHidden()) { continue; } lastTrkpt = &pt; if((pt.flags & CTrackData::trkpt_t::eActMask) != lastFlag) { if(startTrkpt != nullptr) { activity_summary_t& summary = activitySummary[lastFlag]; summary.distance += pt.distance - startTrkpt->distance; summary.ascent += pt.ascent - startTrkpt->ascent; summary.descent += pt.descent - startTrkpt->descent; summary.ellapsedSeconds += pt.elapsedSeconds - startTrkpt->elapsedSeconds; summary.ellapsedSecondsMoving += pt.elapsedSecondsMoving - startTrkpt->elapsedSecondsMoving; activityRanges << activity_range_t(); activity_range_t& activity = activityRanges.last(); activity.d1 = startTrkpt->distance; activity.d2 = pt.distance; activity.t1 = startTrkpt->time.toTime_t(); activity.t2 = pt.time.toTime_t(); const desc_t& desc = getDescriptor(lastFlag); activity.name = desc.name; activity.icon = desc.iconSmall; } startTrkpt = &pt; lastFlag = pt.flags & CTrackData::trkpt_t::eActMask; } } if(lastTrkpt == nullptr) { return; } activity_summary_t& summary = activitySummary[lastFlag]; summary.distance += lastTrkpt->distance - startTrkpt->distance; summary.ascent += lastTrkpt->ascent - startTrkpt->ascent; summary.descent += lastTrkpt->descent - startTrkpt->descent; summary.ellapsedSeconds += lastTrkpt->elapsedSeconds - startTrkpt->elapsedSeconds; summary.ellapsedSecondsMoving += lastTrkpt->elapsedSecondsMoving - startTrkpt->elapsedSecondsMoving; activityRanges << activity_range_t(); activity_range_t& activity = activityRanges.last(); activity.d1 = startTrkpt->distance; activity.d2 = lastTrkpt->distance; activity.t1 = startTrkpt->time.toTime_t(); activity.t2 = lastTrkpt->time.toTime_t(); const desc_t& desc = getDescriptor(lastFlag); activity.name = desc.name; activity.icon = desc.iconSmall; allFlags &= CTrackData::trkpt_t::eActMask; // for(int i = 0; i < 9; i++) // { // activity_summary_t& stat = summaries[i]; // qDebug() << "--------------" << i << "--------------"; // qDebug() << "stat.distance" << stat.distance; // qDebug() << "stat.ascent" << stat.ascent; // qDebug() << "stat.descent" << stat.descent; // qDebug() << "stat.timeMoving" << stat.ellapsedSecondsMoving; // qDebug() << "stat.timeTotal" << stat.ellapsedSeconds; // } } void CActivityTrk::printSummary(QString& str) const { printSummary(activitySummary, allFlags, str); } void CActivityTrk::printSummary(const QMap& summary, quint32 flags, QString& str) { QString val, unit; qreal total; qreal distance; bool printTotal = false; bool printNoAct = false; str += ""; // gather any used activities QVector descs; for(const desc_t &desc : actDescriptor) { if(flags & desc.flag) { descs << &desc; } } const activity_summary_t& sumActNone = summary[CTrackData::trkpt_t::eActNone]; if(sumActNone.distance != 0) { printNoAct = true; } if(descs.size() > 1 || (descs.size() == 1 && printNoAct)) { printTotal = true; } // ############### build header ############### str += ""; str += ""; for(const desc_t *desc : descs) { str += QString("").arg(desc->iconSmall); } if(printNoAct) { str += QString(""); } if(printTotal) { str += ""; } str += ""; // ############### build Distance row ############### str += ""; str += ""; distance = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().meter2distance(s.distance, val, unit); str += QString("").arg(val).arg(unit); distance += s.distance; } if(printNoAct) { IUnit::self().meter2distance(sumActNone.distance, val, unit); str += QString("").arg(val).arg(unit); distance += sumActNone.distance; } if(printTotal) { IUnit::self().meter2distance(distance, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Ascent row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().meter2elevation(s.ascent, val, unit); str += QString("").arg(val).arg(unit); total += s.ascent; } if(printNoAct) { IUnit::self().meter2elevation(sumActNone.ascent, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.ascent; } if(printTotal) { IUnit::self().meter2elevation(total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Descent row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().meter2elevation(s.descent, val, unit); str += QString("").arg(val).arg(unit); total += s.descent; } if(printNoAct) { IUnit::self().meter2elevation(sumActNone.descent, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.descent; } if(printTotal) { IUnit::self().meter2elevation(total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Speed Moving row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().meter2speed(s.distance/s.ellapsedSecondsMoving, val, unit); str += QString("").arg(val).arg(unit); total += s.ellapsedSecondsMoving; } if(printNoAct) { IUnit::self().meter2speed(sumActNone.distance/sumActNone.ellapsedSecondsMoving, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.ellapsedSecondsMoving; } if(printTotal) { IUnit::self().meter2speed(distance/total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Speed row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().meter2speed(s.distance/s.ellapsedSeconds, val, unit); str += QString("").arg(val).arg(unit); total += s.ellapsedSeconds; } if(printNoAct) { IUnit::self().meter2speed(sumActNone.distance/sumActNone.ellapsedSeconds, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.ellapsedSeconds; } if(printTotal) { IUnit::self().meter2speed(distance/total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Time Moving row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().seconds2time(s.ellapsedSecondsMoving, val, unit); str += QString("").arg(val).arg(unit); total += s.ellapsedSecondsMoving; } if(printNoAct) { IUnit::self().seconds2time(sumActNone.ellapsedSecondsMoving, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.ellapsedSecondsMoving; } if(printTotal) { IUnit::self().seconds2time(total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; // ############### build Time Moving row ############### str += ""; str += ""; total = 0; for(const desc_t *desc : descs) { const activity_summary_t& s = summary[desc->flag]; IUnit::self().seconds2time(s.ellapsedSeconds, val, unit); str += QString("").arg(val).arg(unit); total += s.ellapsedSeconds; } if(printNoAct) { IUnit::self().seconds2time(sumActNone.ellapsedSeconds, val, unit); str += QString("").arg(val).arg(unit); total += sumActNone.ellapsedSeconds; } if(printTotal) { IUnit::self().seconds2time(total, val, unit); str += QString("").arg(val).arg(unit); } str += ""; str += "
" + tr("Total") + "
" + tr("Distance:") + "  %1 %2  %1 %2  %1 %2
" + tr("Ascent:") + "  %1%2  %1%2  %1%2
" + tr("Descent:") + "  %1%2  %1%2  %1%2
" + tr("Speed Moving:") + "  %1%2  %1%2  %1%2
" + tr("Speed Total:") + "  %1%2  %1%2  %1%2
" + tr("Time Moving:") + "  %1%2  %1%2  %1%2
" + tr("Time Total:") + "  %1%2  %1%2  %1%2
"; } void CActivityTrk::sumUp(QMap &summary) const { for(quint32 flag : activitySummary.keys()) { const activity_summary_t &src = activitySummary[flag]; activity_summary_t &dst = summary[flag]; dst.distance += src.distance; dst.ascent += src.ascent; dst.descent += src.descent; dst.ellapsedSeconds += src.ellapsedSeconds; dst.ellapsedSecondsMoving += src.ellapsedSecondsMoving; } } const CActivityTrk::desc_t& CActivityTrk::getDescriptor(quint32 flag) { for(const desc_t &desc : actDescriptor) { if(desc.flag == flag) { return desc; } } return dummyDesc; } void CActivityTrk::setColor(quint32 flag, const QString& color) { for(desc_t &desc : actDescriptor) { if(desc.flag == flag) { desc.color = QColor(color); return; } } } void CActivityTrk::getActivityNames(QStringList& names) const { for(const desc_t &desc : actDescriptor) { if((allFlags & desc.flag) != 0) { names << desc.name; } } } qint32 CActivityTrk::getActivityCount() const { qint32 cnt = 0; for(const desc_t &desc : actDescriptor) { if((allFlags & desc.flag) != 0) { ++cnt; } } const activity_summary_t& sumActNone = activitySummary[CTrackData::trkpt_t::eActNone]; if(sumActNone.distance != 0) { cnt++; } return cnt; } qmapshack-1.10.0/src/gis/trk/IDetailsTrk.ui000644 001750 000144 00000163616 13145507557 021642 0ustar00oeichlerxusers000000 000000 IDetailsTrk 0 0 992 404 Form 3 3 3 3 3 Qt::Vertical 0 3 0 0 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Vertical 0 0 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Vertical 0 0 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Horizontal QSizePolicy::Expanding 40 20 3 QFrame::StyledPanel QFrame::Raised 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 true Qt::ClickFocus false 0 0 25 25 The track was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. :/icons/32x32/Tainted.png true 0 0 Toggle read only mode. You have to open the lock to edit the item. ... :/icons/32x32/UnLock.png :/icons/32x32/Lock.png:/icons/32x32/UnLock.png 22 22 true true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Qt::Vertical 20 40 0 0 0 Info 3 0 0 0 0 false Style 0 0 100 0 300 16777215 0 0 Source Width 0 Use/edit user defined visibility of arrows for this track ... :/icons/32x32/ArrowUser.png:/icons/32x32/ArrowUser.png 16 16 true true buttonGroupArrow Use/edit system's visibility of arrows for all tracks ... :/icons/32x32/ArrowDef.png:/icons/32x32/ArrowDef.png 16 16 true true true buttonGroupArrow Qt::Horizontal QSizePolicy::Maximum 25 20 1 -100.000000000000000 0 User defined limits for this track ... :/icons/32x32/LimitUsr.png:/icons/32x32/LimitUsr.png 16 16 true true Automatic limits ... :/icons/32x32/Limit.png:/icons/32x32/Limit.png 16 16 true true true User defined limits for all tracks ... :/icons/32x32/LimitSys.png:/icons/32x32/LimitSys.png 16 16 true true 0 0 Maximum with arrows x 1 1.000000000000000 4.000000000000000 0.500000000000000 1 -100.000000000000000 0 0 Use/edit user defined scale factor for this track ... :/icons/32x32/LineWidthUser.png:/icons/32x32/LineWidthUser.png 16 16 true true buttonGroupLineWidth Use/edit system's default factor for all tracks ... :/icons/32x32/LineWidthDef.png:/icons/32x32/LineWidthDef.png 16 16 true true true buttonGroupLineWidth Qt::Horizontal QSizePolicy::Maximum 25 20 0 0 Minimum Qt::Horizontal 0 0 Color Qt::Vertical 20 40 Qt::Horizontal 40 20 Graphs max. false -1000000.000000000000000 1000000.000000000000000 max. false -1000000.000000000000000 1000000.000000000000000 false -1000000.000000000000000 1000000.000000000000000 Qt::Horizontal 40 20 false -1000000.000000000000000 1000000.000000000000000 Qt::Vertical 20 40 max. false -1000000.000000000000000 1000000.000000000000000 false -1000000.000000000000000 1000000.000000000000000 min. min. Qt::Horizontal min. Qt::Horizontal Profile 0 User defined limits for this track ... :/icons/32x32/LimitUsr.png:/icons/32x32/LimitUsr.png 16 16 true true buttonGroupGraph1 Automatic limits ... :/icons/32x32/Limit.png:/icons/32x32/Limit.png 16 16 true true true buttonGroupGraph1 User defined limits for all tracks ... :/icons/32x32/LimitSys.png:/icons/32x32/LimitSys.png 16 16 true true buttonGroupGraph1 0 User defined limits for this track ... :/icons/32x32/LimitUsr.png:/icons/32x32/LimitUsr.png 16 16 true true buttonGroupGraph2 Automatic limits ... :/icons/32x32/Limit.png:/icons/32x32/Limit.png 16 16 true true true buttonGroupGraph2 User defined limits for all tracks ... :/icons/32x32/LimitSys.png:/icons/32x32/LimitSys.png 16 16 true true buttonGroupGraph2 0 User defined limits for this track ... :/icons/32x32/LimitUsr.png:/icons/32x32/LimitUsr.png 16 16 true true buttonGroupGraph3 Automatic limits ... :/icons/32x32/Limit.png:/icons/32x32/Limit.png 16 16 true true true buttonGroupGraph3 User defined limits for all tracks ... :/icons/32x32/LimitSys.png:/icons/32x32/LimitSys.png 16 16 true true buttonGroupGraph3 Activity 3 3 3 3 3 Set Track Activity :/icons/32x32/Activity.png:/icons/32x32/Activity.png Qt::Vertical 20 40 Qt::Vertical Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop To differentiate the track statistics select an activity from the list for the complete track. Or select a part of the track to assign an activity. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Horizontal 40 20 Points 0 0 0 0 0 0 0 true false false false 50 # Time Ele. Delta Dist. Speed Slope Ascent Descent Position Filter 0 0 0 0 0 QAbstractItemView::NoSelection false 1 Hist. 0 0 0 0 0 32 32 CHistoryListWidget QListWidget
widgets/CHistoryListWidget.h
CLineEdit QLineEdit
widgets/CLineEdit.h
CPlotTrack QWidget
plot/CPlotTrack.h
1
CDoubleSpinBox QDoubleSpinBox
widgets/CDoubleSpinBox.h
CColorLegend QWidget
widgets/CColorLegend.h
1
CSelectActivityColor QWidget
gis/trk/CSelectActivityColor.h
1
CTableTrk QTreeWidget
gis/trk/CTableTrk.h
qmapshack-1.10.0/src/gis/trk/ICutTrk.ui000644 001750 000144 00000012336 13044557066 020776 0ustar00oeichlerxusers000000 000000 ICutTrk 0 0 400 215 Cut Track Delete first part of the track and keep second one buttonGroup_2 Keep both parts of the track true buttonGroup_2 Keep first part of the track and delete second one buttonGroup_2 Cut Mode: :/icons/32x32/CutMode1.png:/icons/32x32/CutMode1.png 32 32 buttonGroup :/icons/32x32/CutMode2.png:/icons/32x32/CutMode2.png 32 32 true buttonGroup Qt::Horizontal 40 20 Qt::Vertical 20 40 false Check this to store the result into a new track. If you keep both parts of the track you have to create new ones. If you want to keep just one half you can simply remove the points, or check this to create a new track. Create a new track true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ICutTrk accept() 248 254 157 274 buttonBox rejected() ICutTrk reject() 316 260 286 274 qmapshack-1.10.0/src/gis/trk/CDetailsTrk.cpp000644 001750 000144 00000060457 13216234137 021766 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CDetailsTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/trk/CPropertyTrk.h" #include "gis/trk/filter/CFilterDelete.h" #include "gis/trk/filter/CFilterDeleteExtension.h" #include "gis/trk/filter/CFilterDouglasPeuker.h" #include "gis/trk/filter/CFilterInterpolateElevation.h" #include "gis/trk/filter/CFilterInvalid.h" #include "gis/trk/filter/CFilterMedian.h" #include "gis/trk/filter/CFilterNewDate.h" #include "gis/trk/filter/CFilterObscureDate.h" #include "gis/trk/filter/CFilterOffsetElevation.h" #include "gis/trk/filter/CFilterReplaceElevation.h" #include "gis/trk/filter/CFilterReset.h" #include "gis/trk/filter/CFilterSpeed.h" #include "gis/trk/filter/CFilterSplitSegment.h" #include "gis/trk/filter/CFilterSubPt2Pt.h" #include "gis/trk/filter/CFilterTerrainSlope.h" #include "helpers/CLinksDialog.h" #include "helpers/CSettings.h" #include "helpers/Signals.h" #include "plot/CPlot.h" #include "plot/CPlotProfile.h" #include "units/IUnit.h" #include "widgets/CTextEditWidget.h" #include #include #include using std::bind; /* base case: add the filter specified in template parameter */ template static void addFilters(QTreeWidgetItem *itemGroup, CGisItemTrk& trk) { QTreeWidgetItem *item = new QTreeWidgetItem(itemGroup); itemGroup->treeWidget()->setItemWidget(item, /* column = */ 0, new filter(trk, itemGroup->treeWidget())); } template static void addFilters(QTreeWidgetItem *itemGroup, CGisItemTrk& trk) { addFilters(itemGroup, trk); addFilters(itemGroup, trk); } template static void addFilterGroup(QTreeWidget *widget, CGisItemTrk& trk, const QString &groupText, const QString &groupIcon) { QTreeWidgetItem *itemGroup = new QTreeWidgetItem(widget); itemGroup->setIcon(/* column = */ 0, QIcon(groupIcon)); itemGroup->setText(/* column = */ 0, groupText); addFilters(itemGroup, trk); } CDetailsTrk::CDetailsTrk(CGisItemTrk& trk, QWidget *parent) : QWidget(parent) , INotifyTrk(CGisItemTrk::eVisualDetails) , trk(trk) { setupUi(this); QPixmap icon(14,14); for(int i=0; i < TRK_N_COLORS; ++i) { icon.fill(IGisItem::colorMap[i].color); comboColor->addItem(icon, IGisItem::colorMap[i].name, IGisItem::colorMap[i].color); } widgetColorLayout->setAlignment(Qt::AlignTop); widgetColorActivity->setTrack(&trk); updateData(); treeWidget->setTrack(&trk); plot1 = new CPlotProfile(&trk, trk.limitsGraph1, IPlot::eModeNormal, this); plot2 = new CPlot(&trk, trk.limitsGraph2, this); plot3 = new CPlot(&trk, trk.limitsGraph3, this); for(IPlot *plot : { static_cast(plot1), static_cast(plot2), static_cast(plot3) }) { plot->setMinimumSize(QSize(0, 100)); plot->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); plot->show(); layoutPlot->addWidget(plot); } if(trk.isOnDevice()) { toolLock->setDisabled(true); } SETTINGS; cfg.beginGroup("TrackDetails"); checkGraph1->setChecked(cfg.value("showGraph1", true).toBool()); checkGraph2->setChecked(cfg.value("showGraph2", true).toBool()); checkGraph3->setChecked(cfg.value("showGraph3", true).toBool()); splitter->restoreState (cfg.value("splitterSizes").toByteArray()); tabWidget->setCurrentIndex(cfg.value("visibleTab", 0).toInt()); cfg.endGroup(); connect(checkGraph1, &QCheckBox::clicked, this, &CDetailsTrk::slotShowPlots); connect(checkGraph2, &QCheckBox::clicked, this, &CDetailsTrk::slotShowPlots); connect(checkGraph3, &QCheckBox::clicked, this, &CDetailsTrk::slotShowPlots); connect(toolLock, &QToolButton::toggled, this, &CDetailsTrk::slotChangeReadOnlyMode); connect(textCmtDesc, &QTextBrowser::anchorClicked, this, &CDetailsTrk::slotLinkActivated); connect(pushSetActivities, &QPushButton::clicked, this, &CDetailsTrk::slotSetActivities); connect(lineName, &QLineEdit::textEdited, this, &CDetailsTrk::slotNameChanged); connect(lineName, &QLineEdit::editingFinished, this, &CDetailsTrk::slotNameChangeFinished); connect(plot1, &CPlot::sigMouseClickState, this, &CDetailsTrk::slotMouseClickState); connect(plot2, &CPlot::sigMouseClickState, this, &CDetailsTrk::slotMouseClickState); connect(plot3, &CPlot::sigMouseClickState, this, &CDetailsTrk::slotMouseClickState); connect(spinLineWidth, static_cast(&QDoubleSpinBox::valueChanged), this, &CDetailsTrk::slotLineWidth); connect(checkWithArrows, &QCheckBox::toggled, this, &CDetailsTrk::slotWithArrows); setupStyleLimits(trk.colorSourceLimit, toolLimitAutoStyle, toolLimitUsrStyle, toolLimitSysStyle, spinLimitLow, spinLimitHigh); connect(toolUserLineWith, &QToolButton::toggled, this, &CDetailsTrk::slotLineWidthMode); connect(toolUserArrow, &QToolButton::toggled, this, &CDetailsTrk::slotWithArrowsMode); connect(listHistory, &CHistoryListWidget::sigChanged, this, &CDetailsTrk::updateData); connect(comboColor, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsTrk::slotColorChanged); connect(comboColorSource, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsTrk::slotColorSourceChanged); connect(comboGraph2, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsTrk::slotSetupGraph); connect(comboGraph3, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsTrk::slotSetupGraph); setupGraphLimits(trk.limitsGraph1, toolLimitAutoGraph1, toolLimitUsrGraph1, toolLimitSysGraph1, spinMinGraph1, spinMaxGraph1); setupGraphLimits(trk.limitsGraph2, toolLimitAutoGraph2, toolLimitUsrGraph2, toolLimitSysGraph2, spinMinGraph2, spinMaxGraph2); setupGraphLimits(trk.limitsGraph3, toolLimitAutoGraph3, toolLimitUsrGraph3, toolLimitSysGraph3, spinMinGraph3, spinMaxGraph3); // setting up the graph properties will trigger the signals // this is good because the signals are connected at this point // invoking the slots loadGraphSource(comboGraph2, 2, CKnownExtension::internalSpeedDist); loadGraphSource(comboGraph3, 3, CKnownExtension::internalProgress); addFilterGroup (treeFilter, trk, tr("Reduce visible track points"), "://icons/48x48/PointHide.png"); addFilterGroup (treeFilter, trk, tr("Change elevation of track points"), "://icons/48x48/SetEle.png"); addFilterGroup (treeFilter, trk, tr("Change timestamp of track points"), "://icons/48x48/Time.png"); addFilterGroup (treeFilter, trk, tr("Miscellaneous"), "://icons/48x48/CSrcUnknown.png"); slotShowPlots(); } CDetailsTrk::~CDetailsTrk() { SETTINGS; cfg.beginGroup("TrackDetails"); cfg.setValue("showGraph1", checkGraph1->isChecked()); cfg.setValue("showGraph2", checkGraph2->isChecked()); cfg.setValue("showGraph3", checkGraph3->isChecked()); cfg.setValue("splitterSizes", splitter->saveState()); cfg.setValue("visibleTab", tabWidget->currentIndex()); cfg.endGroup(); saveGraphSource(comboGraph2, 2); saveGraphSource(comboGraph3, 3); } void CDetailsTrk::slotSetLimitModeStyle(CLimit::mode_e mode, bool on) { if(!on) { return; } CLimit &limit = trk.colorSourceLimit; limit.setMode(mode); widgetColorLabel->setMinimum(limit.getMin()); widgetColorLabel->setMaximum(limit.getMax()); trk.updateHistory(CGisItemTrk::eVisualColorLegend | CGisItemTrk::eVisualDetails); } void CDetailsTrk::setupGraphLimits(CLimit& limit, QToolButton * toolLimitAutoGraph, QToolButton * toolLimitUsrGraph, QToolButton * toolLimitSysGraph, QDoubleSpinBox * spinMinGraph, QDoubleSpinBox * spinMaxGraph) { bool isAutoMode = (limit.getMode() == CLimit::eModeAuto); spinMinGraph->setDisabled(isAutoMode); spinMinGraph->setSuffix(limit.getUnit()); spinMinGraph->setValue(limit.getMin()); spinMaxGraph->setDisabled(isAutoMode); spinMaxGraph->setSuffix(limit.getUnit()); spinMaxGraph->setValue(limit.getMax()); switch(limit.getMode()) { case CLimit::eModeUser: toolLimitUsrGraph->setChecked(true); break; case CLimit::eModeAuto: toolLimitAutoGraph->setChecked(true); break; case CLimit::eModeSys: toolLimitSysGraph->setChecked(true); break; } connect(toolLimitAutoGraph, &QToolButton::toggled, spinMinGraph, &QDoubleSpinBox::setDisabled); connect(toolLimitAutoGraph, &QToolButton::toggled, spinMaxGraph, &QDoubleSpinBox::setDisabled); /* creates "lambdas" which look like: * (bool on) { slotSetLimitModeGraph(CLimit::eModeAuto, &limit, spinMinGraph, spinMaxGraph, on); } */ auto limitAutoFunc = bind(&CDetailsTrk::slotSetLimitModeGraph, this, CLimit::eModeAuto, &limit, spinMinGraph, spinMaxGraph, std::placeholders::_1); auto limitUserFunc = bind(&CDetailsTrk::slotSetLimitModeGraph, this, CLimit::eModeUser, &limit, spinMinGraph, spinMaxGraph, std::placeholders::_1); auto limitSysFunc = bind(&CDetailsTrk::slotSetLimitModeGraph, this, CLimit::eModeSys, &limit, spinMinGraph, spinMaxGraph, std::placeholders::_1); connect(toolLimitAutoGraph, &QToolButton::toggled, this, limitAutoFunc); connect(toolLimitUsrGraph, &QToolButton::toggled, this, limitUserFunc); connect(toolLimitSysGraph, &QToolButton::toggled, this, limitSysFunc); connect(spinMinGraph, static_cast(&QDoubleSpinBox::valueChanged), &limit, &CLimit::setMin); connect(spinMaxGraph, static_cast(&QDoubleSpinBox::valueChanged), &limit, &CLimit::setMax); auto limitChangedFunc = bind(&CDetailsTrk::setupLimits, this, &limit, spinMinGraph, spinMaxGraph); connect(&limit, &CLimit::sigChanged, this, limitChangedFunc); } void CDetailsTrk::setupStyleLimits(CLimit& limit, QToolButton *toolLimitAuto, QToolButton *toolLimitUsr, QToolButton *toolLimitSys, CDoubleSpinBox *spinMin, CDoubleSpinBox *spinMax) { bool isAutoMode = (limit.getMode() == CLimit::eModeAuto); spinMin->setDisabled(isAutoMode); spinMin->setSuffix(limit.getUnit()); spinMin->setValue(limit.getMin()); spinMax->setDisabled(isAutoMode); spinMax->setSuffix(limit.getUnit()); spinMax->setValue(limit.getMax()); switch(limit.getMode()) { case CLimit::eModeUser: toolLimitUsr->setChecked(true); break; case CLimit::eModeAuto: toolLimitAuto->setChecked(true); break; case CLimit::eModeSys: toolLimitSys->setChecked(true); break; } connect(toolLimitAuto, &QToolButton::toggled, spinMax, &QDoubleSpinBox::setDisabled); connect(toolLimitAuto, &QToolButton::toggled, spinMin, &QDoubleSpinBox::setDisabled); connect(toolLimitAuto, &QToolButton::toggled, bind(&CDetailsTrk::slotSetLimitModeStyle, this, CLimit::eModeAuto, std::placeholders::_1)); connect(toolLimitUsr, &QToolButton::toggled, bind(&CDetailsTrk::slotSetLimitModeStyle, this, CLimit::eModeUser, std::placeholders::_1)); connect(toolLimitSys, &QToolButton::toggled, bind(&CDetailsTrk::slotSetLimitModeStyle, this, CLimit::eModeSys, std::placeholders::_1)); connect(spinMax, &CDoubleSpinBox::valueChangedByStep, this, &CDetailsTrk::slotColorLimitHighChanged); connect(spinMax, &CDoubleSpinBox::editingFinished, this, &CDetailsTrk::slotColorLimitHighChanged); connect(spinMin, &CDoubleSpinBox::valueChangedByStep, this, &CDetailsTrk::slotColorLimitLowChanged); connect(spinMin, &CDoubleSpinBox::editingFinished, this, &CDetailsTrk::slotColorLimitLowChanged); auto limitChangedFunc = bind(&CDetailsTrk::setupLimits, this, &limit, spinMin, spinMax); connect(&limit, &CLimit::sigChanged, this, limitChangedFunc); } void CDetailsTrk::loadGraphSource(QComboBox * comboBox, qint32 n, const QString cfgDefault) { const CPropertyTrk * p = trk.getPropertyHandler(); if(p == nullptr) { return; } comboBox->blockSignals(true); p->fillComboBox(comboBox); comboBox->blockSignals(false); // try to restore last graph setup // signals are unblocked by now changing the combobox will trigger a graph update SETTINGS; cfg.beginGroup("TrackDetails"); int i = comboBox->findData(cfg.value(QString("propGraph%1").arg(n),cfgDefault).toString()); if(i != NOIDX) { comboBox->setCurrentIndex(i); } cfg.endGroup(); } void CDetailsTrk::saveGraphSource(QComboBox * comboBox, qint32 n) { SETTINGS; cfg.beginGroup("TrackDetails"); if(comboBox->currentIndex() != 0) { cfg.setValue(QString("propGraph%1").arg(n), comboBox->currentData().toString()); } cfg.endGroup(); } void CDetailsTrk::updateData() { if(originator) { return; } CCanvas::setOverrideCursor(Qt::WaitCursor, "CDetailsTrk::updateData"); originator = true; bool isReadOnly = trk.isReadOnly(); tabWidget->widget(eTabFilter)->setEnabled(!isReadOnly); labelTainted->setVisible(trk.isTainted()); labelInfo->setText(trk.getInfo(IGisItem::eFeatureNone)); comboColor->setCurrentIndex(trk.getColorIdx()); toolLock->setChecked(isReadOnly); lineName->setText(trk.getName()); lineName->setReadOnly(isReadOnly); textCmtDesc->document()->clear(); textCmtDesc->append(IGisItem::createText(isReadOnly, trk.getComment(), trk.getDescription(), trk.getLinks())); textCmtDesc->moveCursor (QTextCursor::Start); textCmtDesc->ensureCursorVisible(); QString str; trk.getActivities().printSummary(str); labelActivityInfo->setText(str); quint32 flags = trk.getActivities().getAllFlags(); bool hasActivity = 0 != (flags & CTrackData::trkpt_t::eActMask); labelActivityHelp->setVisible(!hasActivity); labelActivityInfo->setVisible(hasActivity); pushSetActivities->setEnabled(!isReadOnly); plotTrack->setTrack(&trk); listHistory->setupHistory(trk); QTabWidget * tabWidget = dynamic_cast(parentWidget() ? parentWidget()->parentWidget() : nullptr); if(nullptr != tabWidget) { int idx = tabWidget->indexOf(this); if(idx != NOIDX) { setObjectName(trk.getName()); tabWidget->setTabText(idx, trk.getName()); } } X______________BlockAllSignals______________X(this); spinLineWidth->setValue(trk.lineScale.val().toDouble()); toolUserLineWith->setChecked(trk.lineScale.getMode() == CValue::eModeUser); checkWithArrows->setChecked(trk.showArrows.val().toBool()); toolUserArrow->setChecked(trk.showArrows.getMode() == CValue::eModeUser); comboColorSource->clear(); // the first entry `solid color`, it is always available comboColorSource->addItem(QIcon("://icons/32x32/CSrcSolid.png"), tr("Color")); comboColorSource->addItem(QIcon("://icons/32x32/Activity.png"), tr("Activity"), "activity"); for(const QString &key : trk.getExistingDataSources()) { const CKnownExtension &ext = CKnownExtension::get(key); QIcon icon(ext.icon); comboColorSource->addItem(icon, ext.known ? ext.nameLongText : key, key); } int currentIdx = comboColorSource->findData(trk.getColorizeSource()); if(-1 == currentIdx) { trk.setColorizeSource(QString()); currentIdx = 0; } comboColorSource->setCurrentIndex(currentIdx); QString source = comboColorSource->currentData().toString(); bool enabledColorize = !source.isEmpty() && (source != "activity"); bool enabledActivity = source == "activity"; comboColor->setVisible(!(enabledColorize||enabledActivity)); widgetColorLabel->setVisible(enabledColorize); widgetColorLabel->setEnabled(enabledColorize); toolLimitAutoStyle->setEnabled(enabledColorize); toolLimitUsrStyle->setEnabled(enabledColorize); toolLimitSysStyle->setEnabled(enabledColorize); if(enabledColorize) { const CKnownExtension &ext = CKnownExtension::get(comboColorSource->itemData(currentIdx).toString()); spinLimitLow->setMinimum(ext.minimum); spinLimitLow->setMaximum(ext.maximum); spinLimitLow->setSuffix (ext.unit); spinLimitLow->setValue (trk.getColorizeLimitLow()); spinLimitHigh->setMinimum(ext.minimum); spinLimitHigh->setMaximum(ext.maximum); spinLimitHigh->setSuffix (ext.unit); spinLimitHigh->setValue (trk.getColorizeLimitHigh()); widgetColorLabel->setMinimum(spinLimitLow->value()); widgetColorLabel->setMaximum(spinLimitHigh->value()); widgetColorLabel->setUnit(ext.unit); } widgetColorActivity->updateData(); widgetColorActivity->setVisible(enabledActivity); widgetColorActivity->setEnabled(enabledActivity); X_____________UnBlockAllSignals_____________X(this); // refill comboboxes to select track property to be displayed by graphs loadGraphSource(comboGraph2, 2, CKnownExtension::internalSpeedDist); loadGraphSource(comboGraph3, 3, CKnownExtension::internalProgress); CFilterDeleteExtension *filter = treeFilter->findChild(); if(nullptr != filter) { filter->update(); } originator = false; CCanvas::restoreOverrideCursor("CDetailsTrk::updateData"); } void CDetailsTrk::setMouseFocus(const CTrackData::trkpt_t * pt) { if(nullptr != pt) { plotTrack->setMouseFocus(pt->lon, pt->lat); labelInfoTrkPt->setText(trk.getInfoTrkPt(*pt)); labelInfoProgress->setText(trk.getInfoProgress(*pt)); } else { labelInfoTrkPt->setText("-\n-"); labelInfoProgress->setText("-\n-"); } } void CDetailsTrk::setMouseRangeFocus(const CTrackData::trkpt_t *pt1, const CTrackData::trkpt_t *pt2) { labelInfoRange->setText( (pt1 && pt2) ? trk.getInfoRange(*pt1, *pt2) : "-\n-" ); } void CDetailsTrk::setMouseClickFocus(const CTrackData::trkpt_t *pt) { if(nullptr != pt) { treeWidget->blockSignals(true); treeWidget->setCurrentItem(treeWidget->topLevelItem(pt->idxTotal)); treeWidget->blockSignals(false); } } void CDetailsTrk::slotMouseClickState(int s) { if(s == IPlot::eMouseClickIdle) { labelInfoRange->setText("-\n-"); plot3->setMouseRangeFocus(0, 0); plot1->setMouseRangeFocus(0, 0); plot2->setMouseRangeFocus(0, 0); } } void CDetailsTrk::slotNameChanged(const QString &name) { QTabWidget *tabWidget = dynamic_cast(parentWidget() ? parentWidget()->parentWidget() : nullptr); if(nullptr != tabWidget) { int idx = tabWidget->indexOf(this); if(idx != NOIDX) { const QString shownName = name.isEmpty() ? CGisItemTrk::noName : QString(name).replace('&', "&&"); setObjectName(shownName); tabWidget->setTabText(idx, shownName); } } } void CDetailsTrk::slotNameChangeFinished() { lineName->clearFocus(); const QString& name = lineName->text(); slotNameChanged(name); if(name != trk.getName()) { trk.setName(name); updateData(); } } void CDetailsTrk::slotShowPlots() { plot1->setVisible(checkGraph1->isChecked()); plot2->setVisible(checkGraph2->isChecked()); plot3->setVisible(checkGraph3->isChecked()); } void CDetailsTrk::slotColorChanged(int idx) { if(trk.getColorIdx() != idx) { trk.setColor(idx); } } void CDetailsTrk::slotColorSourceChanged(int idx) { trk.setColorizeSource(comboColorSource->itemData(idx).toString()); updateData(); } void CDetailsTrk::slotColorLimitHighChanged() { const double val = spinLimitHigh->value(); trk.setColorizeLimitHigh(val); widgetColorLabel->setMaximum(val); } void CDetailsTrk::slotColorLimitLowChanged() { const double val = spinLimitLow->value(); trk.setColorizeLimitLow(val); widgetColorLabel->setMinimum(val); } void CDetailsTrk::slotChangeReadOnlyMode(bool on) { trk.setReadOnlyMode(on); // as setReadOnlyMode() is a method of IGisItem it will bypass updateHistory() of the track // Therefore we have to call updateVisuals() explicitly. trk.updateVisuals(CGisItemTrk::eVisualProject, "CDetailsTrk::slotChangeReadOnlyMode()"); updateData(); } void CDetailsTrk::slotLinkActivated(const QUrl& url) { if(url.toString() == "comment") { CTextEditWidget dlg(trk.getComment(), this); if(dlg.exec() == QDialog::Accepted) { trk.setComment(dlg.getHtml()); } updateData(); } else if(url.toString() == "description") { CTextEditWidget dlg(trk.getDescription(), this); if(dlg.exec() == QDialog::Accepted) { trk.setDescription(dlg.getHtml()); } updateData(); } else if(url.toString() == "links") { QList links = trk.getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { trk.setLinks(links); } updateData(); } else { QDesktopServices::openUrl(url); } } void CDetailsTrk::slotSetActivities() { quint32 flags = CActivityTrk::selectActivity(this); if(0xFFFFFFFF != flags) { trk.setActivity(flags); } } void CDetailsTrk::setupGraph(CPlot * plot, const CLimit& limit, const QString& source, QDoubleSpinBox * spinMin, QDoubleSpinBox * spinMax) { trk.getPropertyHandler()->setupPlot(plot, source); spinMin->setSuffix(limit.getUnit()); spinMax->setSuffix(limit.getUnit()); spinMin->setValue(limit.getMin()); spinMax->setValue(limit.getMax()); } void CDetailsTrk::slotSetupGraph(int idx) { QObject *s = sender(); if(s == comboGraph2) { saveGraphSource(comboGraph2, 2); setupGraph(plot2, trk.limitsGraph2, comboGraph2->itemData(idx).toString(), spinMinGraph2, spinMaxGraph2); } else if(s == comboGraph3) { saveGraphSource(comboGraph3, 3); setupGraph(plot3, trk.limitsGraph3, comboGraph3->itemData(idx).toString(), spinMinGraph3, spinMaxGraph3); } } void CDetailsTrk::slotSetLimitModeGraph(CLimit::mode_e mode, CLimit *limit, QDoubleSpinBox *spinMin, QDoubleSpinBox *spinMax, bool on) { if(!on) { return; } limit->setMode(mode); spinMin->setValue(limit->getMin()); spinMax->setValue(limit->getMax()); } void CDetailsTrk::setupLimits(CLimit *limit, QDoubleSpinBox * spinMin, QDoubleSpinBox * spinMax) { spinMin->setValue(limit->getMin()); spinMax->setValue(limit->getMax()); } void CDetailsTrk::slotLineWidthMode(bool isUser) { trk.lineScale.setMode(isUser ? CValue::eModeUser : CValue::eModeSys); spinLineWidth->setValue(trk.lineScale.val().toDouble()); } void CDetailsTrk::slotLineWidth(qreal f) { trk.lineScale = f; } void CDetailsTrk::slotWithArrowsMode(bool isUser) { trk.showArrows.setMode(isUser ? CValue::eModeUser : CValue::eModeSys); checkWithArrows->setChecked(trk.showArrows.val().toBool()); } void CDetailsTrk::slotWithArrows(bool yes) { trk.showArrows = yes; } qmapshack-1.10.0/src/gis/trk/CTableTrk.h000644 001750 000144 00000003544 13216234143 021064 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CTABLETRK_H #define CTABLETRK_H #include #include class CTableTrk : public QTreeWidget, public INotifyTrk { Q_OBJECT public: CTableTrk(QWidget * parent); virtual ~CTableTrk(); void setTrack(CGisItemTrk * track); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t * pt) override {} void setMouseRangeFocus(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2) override {} void setMouseClickFocus(const CTrackData::trkpt_t * pt) override {} enum columns_t { eColNum ,eColTime ,eColEle ,eColDelta ,eColDist ,eColSpeed ,eColSlope ,eColAscent ,eColDescent ,eColPosition ,eColMax }; private slots: void slotItemSelectionChanged(); void slotItemDoubleClicked(QTreeWidgetItem * item, int column); private: CGisItemTrk * trk = nullptr; }; #endif //CTABLETRK_H qmapshack-1.10.0/src/gis/trk/CCutTrk.h000644 001750 000144 00000003323 13216234143 020563 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCUTTRK_H #define CCUTTRK_H #include "ui_ICutTrk.h" #include class CCutTrk : public QDialog, private Ui::ICutTrk { Q_OBJECT public: CCutTrk(QWidget * parent); virtual ~CCutTrk() = default; enum mode_e { eModeNone = 0 , eModeKeepFirst = 1 , eModeKeepBoth = 2 , eModeKeepSecond = 4 }; enum cutmode_e { eCutMode1 ,eCutMode2 }; mode_e getMode() const { return mode; } cutmode_e getCutMode() const { return cutMode; } bool createClone() { return checkCreateClone->isChecked(); } public slots: void accept() override; private slots: void slotClicked(); private: mode_e mode = eModeNone; cutmode_e cutMode = eCutMode2; }; #endif //CCUTTRK_H qmapshack-1.10.0/src/gis/trk/CSelectActivityColor.h000644 001750 000144 00000003505 13216234143 023304 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELECTACTIVITYCOLOR_H #define CSELECTACTIVITYCOLOR_H #include "gis/trk/CGisItemTrk.h" #include #include #include class QLabel; class QToolButton; class CSelectActivityColor : public QWidget, public INotifyTrk, private Ui::ISelectActivityColor { Q_OBJECT public: CSelectActivityColor(QWidget * parent); virtual ~CSelectActivityColor(); void setTrack(CGisItemTrk * p); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t * pt) override {} void setMouseRangeFocus(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2) override {} void setMouseClickFocus(const CTrackData::trkpt_t * pt) override {} private slots: void slotSetColor(QToolButton * button, quint32 activityFlag); private: CGisItemTrk * trk = nullptr; QList allActLabels; QList allActColors; }; #endif //CSELECTACTIVITYCOLOR_H qmapshack-1.10.0/src/gis/trk/CTrackData.cpp000644 001750 000144 00000007571 13216234137 021554 0ustar00oeichlerxusers000000 000000 #include "gis/IGisLine.h" #include "gis/trk/CTrackData.h" CTrackData::CTrackData(const QString &name, const CTrackData &other, qint32 rangeStart, qint32 rangeEnd) : name(name) { for(const trkseg_t &oseg : other.segs) { trkseg_t seg; for(const trkpt_t &opt : oseg.pts) { if(opt.idxTotal < rangeStart) { continue; } if(opt.idxTotal > rangeEnd) { break; } seg.pts << opt; } if(!seg.isEmpty()) { segs << seg; } } cmt = other.cmt; desc = other.desc; src = other.src; links = other.links; number = other.number; type = other.type; } void CTrackData::removeEmptySegments() { QVector::iterator it = segs.begin(); while(it != segs.end()) { if(it->pts.isEmpty()) { it = segs.erase(it); } else { ++it; } } } void CTrackData::readFrom(const SGisLine &l) { segs.clear(); segs.resize(1); trkseg_t& seg = segs.first(); for(int i = 0; i < l.size(); i++) { seg.pts << trkpt_t(); trkpt_t& trkpt = seg.pts.last(); const IGisLine::point_t& pt = l[i]; trkpt.lon = pt.coord.x() * RAD_TO_DEG; trkpt.lat = pt.coord.y() * RAD_TO_DEG; trkpt.ele = pt.ele; for(int n = 0; n < pt.subpts.size(); n++) { seg.pts << trkpt_t(); trkpt_t& trkpt = seg.pts.last(); const IGisLine::subpt_t& sub = pt.subpts[n]; trkpt.lon = sub.coord.x() * RAD_TO_DEG; trkpt.lat = sub.coord.y() * RAD_TO_DEG; trkpt.ele = sub.ele; trkpt.setFlag(trkpt_t::eSubpt); } } } void CTrackData::getPolyline(SGisLine &l) const { l.clear(); for(const trkpt_t &pt : *this) { if(!pt.isHidden()) { if(pt.hasFlag(trkpt_t::eSubpt)) { l.last().subpts << IGisLine::subpt_t(pt.radPoint()); } else { l << IGisLine::point_t(pt.radPoint()); } } } } void CTrackData::getPolyline(QPolygonF &l) const { l.clear(); for(const trkpt_t &pt : *this) { if(!pt.isHidden()) { l << pt.radPoint(); } } } bool CTrackData::isTrkPtFirstVisible(qint32 idxTotal) const { for(const trkpt_t &pt : *this) { if((pt.idxTotal < idxTotal)) { if(!pt.isHidden()) { return false; } } else { return true; } } return true; } const CTrackData::trkpt_t* CTrackData::getTrkPtByVisibleIndex(qint32 idx) const { if(idx == NOIDX) { return nullptr; } auto condition = [idx](const trkpt_t &pt) { return pt.idxVisible == idx; }; return getTrkPtByCondition(condition); } const CTrackData::trkpt_t* CTrackData::getTrkPtByTotalIndex(qint32 idx) const { auto condition = [idx](const trkpt_t &pt) { return pt.idxTotal == idx; }; return getTrkPtByCondition(condition); } bool CTrackData::isTrkPtLastVisible(qint32 idxTotal) const { auto condition = [idxTotal](const trkpt_t &pt) { return (pt.idxTotal > idxTotal) && !pt.isHidden(); }; return nullptr == getTrkPtByCondition(condition); } const CTrackData::trkpt_t* CTrackData::getTrkPtByCondition(std::function cond) const { for(const trkpt_t &pt : *this) { if(cond(pt)) { return &pt; } } return nullptr; } CTrackData::trkpt_t* CTrackData::getTrkPtByCondition(std::function cond) { for(trkpt_t &pt : *this) { if(cond(pt)) { return &pt; } } return nullptr; } qmapshack-1.10.0/src/gis/trk/CSelectActivityColor.cpp000644 001750 000144 00000007154 13216234137 023646 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CSelectActivityColor.h" #include "widgets/CColorChooser.h" #include #include using std::bind; CSelectActivityColor::CSelectActivityColor(QWidget *parent) : QWidget(parent) , INotifyTrk(CGisItemTrk::eVisualColorAct) { setupUi(this); } CSelectActivityColor::~CSelectActivityColor() { if(trk != nullptr) { trk->unregisterVisual(this); } } void CSelectActivityColor::setTrack(CGisItemTrk * p) { if(trk != nullptr) { trk->unregisterVisual(this); } trk = p; if(trk != nullptr) { trk->registerVisual(this); } updateData(); } void CSelectActivityColor::updateData() { qDeleteAll(allActLabels); qDeleteAll(allActColors); allActLabels.clear(); allActColors.clear(); if((trk == nullptr) || !isEnabled()) { return; } const CActivityTrk& act = trk->getActivities(); quint32 flags = act.getAllFlags(); quint32 mask = 0x80000000; qint32 cnt = 0; for(quint32 i = 0; i < CTrackData::trkpt_t::eActMaxNum; i++) { if((flags & mask) != 0) { const CActivityTrk::desc_t& desc = CActivityTrk::getDescriptor(mask); QLabel * label = new QLabel(this); label->setMinimumSize(16,16); label->setMaximumSize(16,16); label->setPixmap(desc.iconSmall); label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum); horizontalLayout->addWidget(label); allActLabels << label; QPixmap pixmap(16,16); pixmap.fill(desc.color); QToolButton * button = new QToolButton(this); button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setAutoRaise(true); button->setIcon(QIcon(pixmap)); button->setProperty("color", desc.color.name()); button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum); horizontalLayout->addWidget(button); auto setColorFunc = bind(&CSelectActivityColor::slotSetColor, this, button, mask); connect(button, &QToolButton::clicked, this, setColorFunc); allActColors << button; ++cnt; } mask >>= 1; } QSpacerItem * spacer = new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Minimum); horizontalLayout->addItem(spacer); } void CSelectActivityColor::slotSetColor(QToolButton * button, quint32 activityFlag) { CColorChooser dlg(button); dlg.move(button->parentWidget()->mapToGlobal(button->geometry().topRight())); if(dlg.exec() == QDialog::Accepted) { CActivityTrk::setColor(activityFlag, button->property("color").toString()); } } qmapshack-1.10.0/src/gis/trk/CTableTrk.cpp000644 001750 000144 00000014031 13216234137 021413 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CTableTrk.h" #include "helpers/CElevationDialog.h" #include "helpers/CSettings.h" #include "units/IUnit.h" #include #include CTableTrk::CTableTrk(QWidget *parent) : QTreeWidget(parent) , INotifyTrk(CGisItemTrk::eVisualTrkTable) { SETTINGS; cfg.beginGroup("TrackDetails"); header()->restoreState(cfg.value("trackPointListState").toByteArray()); cfg.endGroup(); connect(this, &CTableTrk::itemSelectionChanged, this, &CTableTrk::slotItemSelectionChanged); connect(this, &CTableTrk::itemDoubleClicked, this, &CTableTrk::slotItemDoubleClicked); } CTableTrk::~CTableTrk() { SETTINGS; cfg.beginGroup("TrackDetails"); cfg.setValue("trackPointListState", header()->saveState()); cfg.endGroup(); if(trk != nullptr) { trk->unregisterVisual(this); } } void CTableTrk::setTrack(CGisItemTrk * track) { if(trk != nullptr) { trk->unregisterVisual(this); } clear(); trk = track; if(trk != nullptr) { trk->registerVisual(this); updateData(); } } void CTableTrk::updateData() { if(trk == nullptr) { return; } // use all valid flags as invalid mask. By that only // invalid flags for properties with valid points count quint32 invalidMask = (trk->getAllValidFlags() & CTrackData::trkpt_t::eValidMask) << 16; QList items; const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { QString val, unit; QTreeWidgetItem * item = new QTreeWidgetItem(); item->setTextAlignment(eColNum, Qt::AlignLeft); item->setTextAlignment(eColEle, Qt::AlignRight); item->setTextAlignment(eColDelta, Qt::AlignRight); item->setTextAlignment(eColDist, Qt::AlignRight); item->setTextAlignment(eColAscent, Qt::AlignRight); item->setTextAlignment(eColDescent, Qt::AlignRight); item->setTextAlignment(eColSpeed, Qt::AlignRight); if(!trk->isReadOnly()) { item->setToolTip(eColEle, tr("Double click to edit elevation value")); } QBrush bg = item->background(0); if(trkpt.isInvalid(CTrackData::trkpt_t::invalid_e(invalidMask))) { bg = QColor(255, 100, 100); } QBrush fg( trkpt.isHidden() ? Qt::gray : Qt::black ); for(int i = 0; i < eColMax; i++) { item->setBackground(i, bg); item->setForeground(i, fg); } item->setText(eColNum,QString::number(trkpt.idxTotal)); item->setText(eColTime, trkpt.time.isValid() ? IUnit::self().datetime2string(trkpt.time, true, QPointF(trkpt.lon, trkpt.lat)*DEG_TO_RAD) : "-" ); if(trkpt.ele != NOINT) { IUnit::self().meter2elevation(trkpt.ele, val, unit); item->setText(eColEle, tr("%1%2").arg(val).arg(unit)); } else { item->setText(eColEle, "-"); } IUnit::self().meter2distance(trkpt.deltaDistance, val, unit); item->setText(eColDelta, tr("%1%2").arg(val).arg(unit)); IUnit::self().meter2distance(trkpt.distance, val, unit); item->setText(eColDist, tr("%1%2").arg(val).arg(unit)); if(trkpt.speed != NOFLOAT) { IUnit::self().meter2speed(trkpt.speed, val, unit); item->setText(eColSpeed, tr("%1%2").arg(val).arg(unit)); } else { item->setText(eColSpeed, "-"); } IUnit::self().slope2string(trkpt.slope1, val, unit); item->setText(eColSlope, (trkpt.slope1 != NOFLOAT) ? QString("%1%2").arg(val).arg(unit) : "-" ); IUnit::self().meter2elevation(trkpt.ascent, val, unit); item->setText(eColAscent, tr("%1%2").arg(val).arg(unit)); IUnit::self().meter2elevation(trkpt.descent, val, unit); item->setText(eColDescent, tr("%1%2").arg(val).arg(unit)); // position QString str; IUnit::degToStr(trkpt.lon, trkpt.lat, str); item->setText(eColPosition,str); items << item; } clear(); addTopLevelItems(items); header()->resizeSections(QHeaderView::ResizeToContents); } void CTableTrk::slotItemSelectionChanged() { QTreeWidgetItem * item = currentItem(); if(nullptr != item) { quint32 idx = item->text(eColNum).toUInt(); trk->setMouseFocusByTotalIndex(idx, CGisItemTrk::eFocusMouseMove, "CTableTrk"); } } void CTableTrk::slotItemDoubleClicked(QTreeWidgetItem * item, int column) { if(trk->isReadOnly()) { return; } qint32 idx = item->text(eColNum).toInt(); qint32 ele = trk->getElevation(idx); qreal lon, lat; IUnit::strToDeg(item->text(eColPosition), lon, lat); if((column == eColEle) && (lon != NOFLOAT) && (lat != NOFLOAT)) { QVariant var(ele); CElevationDialog dlg(this, var, QVariant(ele), QPointF(lon, lat)); if(dlg.exec() == QDialog::Accepted) { trk->setElevation(idx, var.toInt()); } } } qmapshack-1.10.0/src/gis/trk/CCutTrk.cpp000644 001750 000144 00000005551 13216234137 021126 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CCutTrk.h" #include "helpers/CSettings.h" #include CCutTrk::CCutTrk(QWidget *parent) : QDialog(parent) { setupUi(this); connect(radioKeepFirst, &QRadioButton::toggled, this, &CCutTrk::slotClicked); connect(radioKeepBoth, &QRadioButton::toggled, this, &CCutTrk::slotClicked); connect(radioKeepSecond, &QRadioButton::toggled, this, &CCutTrk::slotClicked); SETTINGS; cfg.beginGroup("TrackCut"); checkCreateClone->setChecked(cfg.value("checkCreateClone", true).toBool()); switch(cfg.value("mode", eModeKeepBoth).toInt()) { case eModeKeepFirst: radioKeepFirst->setChecked(true); break; case eModeKeepBoth: radioKeepBoth->setChecked(true); break; case eModeKeepSecond: radioKeepSecond->setChecked(true); break; } switch(cfg.value("cutMode", eCutMode2).toInt()) { case eCutMode1: radioCutMode1->setChecked(true); break; case eCutMode2: radioCutMode2->setChecked(true); break; } cfg.endGroup(); } void CCutTrk::accept() { SETTINGS; cfg.beginGroup("TrackCut"); cfg.setValue("checkCreateClone", checkCreateClone->isChecked()); cfg.setValue("mode", radioKeepFirst->isChecked() ? eModeKeepFirst : radioKeepBoth->isChecked() ? eModeKeepBoth : radioKeepSecond->isChecked() ? eModeKeepSecond : eModeNone); cfg.setValue("cutMode", radioCutMode1->isChecked() ? eCutMode1 : eCutMode2); cfg.endGroup(); if(radioKeepFirst->isChecked()) { mode = eModeKeepFirst; } else if(radioKeepBoth->isChecked()) { mode = eModeKeepBoth; } else if(radioKeepSecond->isChecked()) { mode = eModeKeepSecond; } if(radioCutMode1->isChecked()) { cutMode = eCutMode1; } else { cutMode = eCutMode2; } QDialog::accept(); } void CCutTrk::slotClicked() { checkCreateClone->setEnabled(!radioKeepBoth->isChecked()); } qmapshack-1.10.0/src/gis/trk/CTrackData.h000644 001750 000144 00000017074 13216234143 021215 0ustar00oeichlerxusers000000 000000 #ifndef TRACKDATA_H #define TRACKDATA_H #include "GeoMath.h" #include "gis/IGisItem.h" #include #include #include #include struct SGisLine; class CTrackData { public: struct trkpt_t : public IGisItem::wpt_t { trkpt_t() { reset(); } void reset() { deltaDistance = NOFLOAT; distance = NOFLOAT; ascent = NOFLOAT; descent = NOFLOAT; elapsedSeconds = NOFLOAT; elapsedSecondsMoving = NOFLOAT; slope1 = NOFLOAT; slope2 = NOFLOAT; speed = NOFLOAT; idxVisible = NOIDX; } enum flag_e { eHidden = 0x00000004 ///< mark point as deleted ,eSubpt = 0x00000008 // activity flags ,eActNone = 0x00000000 ,eActFoot = 0x80000000 ,eActCycle = 0x40000000 ,eActBike = 0x20000000 ,eActCar = 0x10000000 ,eActCable = 0x08000000 ,eActSwim = 0x04000000 ,eActShip = 0x02000000 ,eActAero = 0x01000000 ,eActSki = 0x00800000 ,eActTrain = 0x00400000 ,eActMask = 0xFFC00000 ///< mask for activity flags ,eActMaxNum = 10 ///< maximum number of activity flags. this is defined by the mask }; enum valid_e { eValidTime = 0x00000001 ,eValidEle = 0x00000002 ,eValidPos = 0x00000004 ,eValidMask = 0x0000FFFF }; enum invalid_e { eInvalidTime = eValidTime << 16 ,eInvalidEle = eValidEle << 16 ,eInvalidPos = eValidPos << 16 ,eInvalidMask = 0xFFFF0000 }; inline bool isHidden() const { return hasFlag(trkpt_t::eHidden); } inline bool hasFlag(enum flag_e flag) const { return flags & flag; } inline void setFlag(enum flag_e flag) { flags |= flag; } inline void unsetFlag(enum flag_e flag) { flags &= ~flag; } inline bool isValid(valid_e flag) const { return (valid & flag) != 0; } inline bool isInvalid(invalid_e flag) const { return (valid & flag) != 0; } inline QPointF radPoint() const { return QPointF(lon * DEG_TO_RAD, lat * DEG_TO_RAD); } inline qreal distanceTo(const trkpt_t &other) { return GPS_Math_Distance(lon * DEG_TO_RAD, lat * DEG_TO_RAD, other.lon * DEG_TO_RAD, other.lat * DEG_TO_RAD); } quint32 flags = 0; quint32 valid = 0; qint32 idxTotal = NOIDX; //< index within the complete track qint32 idxVisible; //< offset into lineSimple qreal deltaDistance; //< the distance to the last point qreal distance; //< the distance from the start of the track qreal ascent; //< the ascent from the start of the track qreal descent; //< the descent from the start of the track qreal slope1; //< the slope [°] over several points close by qreal slope2; //< the slope [%] over several points close by qreal speed; //< the speed over several points close by qreal elapsedSeconds; //< the seconds since the start of the track qreal elapsedSecondsMoving; //< the seconds since the start of the track with moving speed IGisItem::key_t keyWpt; //< the key of an attached waypoint QHash extensions; //< track point extensions }; struct trkseg_t { QVector pts; bool isEmpty() const { return pts.isEmpty(); } }; CTrackData() {} CTrackData(const QString &name, const CTrackData &other, qint32 rangeStart, qint32 rangeEnd); // -- all gpx tags - start QString name; QString cmt; QString desc; QString src; QList links; quint64 number = 0; QString type; QVector segs; // -- all gpx tags - stop QString color; void removeEmptySegments(); void readFrom(const SGisLine &l); void getPolyline(SGisLine &l) const; void getPolyline(QPolygonF &l) const; bool isEmpty() const { return segs.isEmpty(); } /** @brief Check if the track point at index it the first one visible @param idxTotal The point's index @return True if it is the first one visible */ bool isTrkPtFirstVisible(qint32 idxTotal) const; const trkpt_t* getTrkPtByCondition(std::function cond) const; trkpt_t* getTrkPtByCondition(std::function cond); /** @brief Try to get access Nth visible point matching the idx This will iterate over all segments and count the visible points. If the count matches idx a pointer to the track point is returned. @param idx The index into all visible points @return A null pointer of no point is found. */ const trkpt_t *getTrkPtByVisibleIndex(qint32 idx) const; /** @brief Try to get access Nth point This will iterate over all segments. If the index matches a pointer to the track point is returned. @param idx The index into all points @return A null pointer of no point is found. */ const trkpt_t *getTrkPtByTotalIndex(qint32 idx) const; /** @brief Check if the track point at index it the last one visible @param idxTotal The point's index @return True if it is the last one visible */ bool isTrkPtLastVisible(qint32 idxTotal) const; template class iterator : public std::iterator { T1 &trk; int seg = 0; int pt = 0; public: explicit iterator(T1 &trk, int seg, int pt) : trk(trk), seg(seg), pt(pt) {} iterator& operator++() { Q_ASSERT(seg < trk.segs.count()); ++pt; if(this->trk.segs[seg].pts.count() <= pt) { pt = 0; ++seg; } return *this; } iterator operator++(int) { iterator prev = *this; ++(*this); return prev; } bool operator==(iterator other) const { return (&trk == &other.trk) && (seg == other.seg) && (pt == other.pt); } bool operator!=(iterator other) const { return !(*this == other); } T2& operator*() { return this->trk.segs[seg].pts[pt]; } }; iterator begin() { return iterator(*this, 0, 0); } iterator end() { return iterator(*this, segs.count(), 0); } iterator begin() const { return iterator(*this, 0, 0); } iterator end() const { return iterator(*this, segs.count(), 0); } }; #endif /* TRACKDATA_H */ qmapshack-1.10.0/src/gis/trk/CPropertyTrk.cpp000644 001750 000144 00000007702 13216234137 022217 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/trk/CPropertyTrk.h" #include "plot/CPlot.h" #include "units/IUnit.h" #include CPropertyTrk::CPropertyTrk(CGisItemTrk& trk) : trk(trk) { setupData(); } void CPropertyTrk::setupData() { properties.clear(); property_t propNull { QString() , QString() , QString() , QIcon() , property_t::eAxisDistance , nullptr , QString() , QString() , 1.0 , nullptr }; properties << propNull; QStringList keys = trk.getExistingDataSources(); for(const QString &key : keys) { const CKnownExtension &ext = CKnownExtension::get(key); QString nameShortText = (ext.known ? ext.nameShortText : key); QString nameLongText = (ext.known ? ext.nameLongText : key); property_t property { key , nameShortText , nameLongText , QIcon(ext.icon) , property_t::eAxisDistance , [](const CTrackData::trkpt_t &p) { return p.distance; } , ext.unit , ext.known ? QString("%1 [%2]").arg(nameShortText).arg(ext.unit) : nameShortText , ext.factor , ext.valueFunc }; // lame hack for properties off the usual scheme if((key == CKnownExtension::internalProgress) || (key == CKnownExtension::internalSpeedTime)) { property.min = 0; property.axisType = property_t::eAxisTime; property.getX = [](const CTrackData::trkpt_t &p) {return p.time.isValid() ? p.time.toTime_t() : NOFLOAT; }; } if(key == CKnownExtension::internalSpeedDist) { property.min = 0; } if(key == CKnownExtension::internalSlope) { qreal val; QString unit; IUnit::self().slope2unit(0, val, unit); property.unit = unit; property.yLabel = QString("%1 [%2]").arg(nameShortText).arg(unit); property.getY = [](const CTrackData::trkpt_t &p) {qreal val; QString unit; IUnit::self().slope2unit(p.slope1, val, unit); return val; }; } properties << property; } } const CPropertyTrk::property_t& CPropertyTrk::propBySource(const QString& source) const { for(const property_t &prop : properties) { if(prop.key == source) { return prop; } } return properties[0]; } void CPropertyTrk::fillComboBox(QComboBox * box) const { box->clear(); for(const property_t &p : properties) { if(p.key == CKnownExtension::internalEle) { // skip it as there is a dedicated profile plot continue; } box->addItem(p.icon, p.nameLongText, p.key); } } void CPropertyTrk::setupPlot(CPlot * plot, const QString& source) const { const property_t& p = propBySource(source); if(p.nameLongText.isEmpty()) { plot->clear(); return; } plot->setup(p); } qmapshack-1.10.0/src/gis/trk/CCombineTrk.cpp000644 001750 000144 00000014627 13216234137 021753 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisWorkspace.h" #include "gis/trk/CCombineTrk.h" #include "gis/trk/CGisItemTrk.h" #include "plot/CPlotTrack.h" #include CCombineTrk::CCombineTrk(const QList &keys, const QList &keysPreSel, QWidget * parent) : QDialog(parent) { setupUi(this); CGisWorkspace& gis = CGisWorkspace::self(); for(const IGisItem::key_t& key : keys) { CGisItemTrk * trk = dynamic_cast(gis.getItemByKey(key)); if(nullptr == trk) { continue; } QListWidgetItem * item = new QListWidgetItem(keysPreSel.contains(key) ? listSelected : listAvailable); item->setText(trk->getName()); item->setIcon(trk->getIcon()); item->setData(Qt::UserRole + 1, key.item); item->setData(Qt::UserRole + 2, key.project); item->setData(Qt::UserRole + 3, key.device); } connect(listAvailable, &QListWidget::itemSelectionChanged, this, &CCombineTrk::slotSelectionChanged); connect(listSelected, &QListWidget::itemSelectionChanged, this, &CCombineTrk::slotSelectionChanged); connect(toolSelect, &QToolButton::clicked, this, &CCombineTrk::slotSelect); connect(toolRemove, &QToolButton::clicked, this, &CCombineTrk::slotRemove); connect(toolUp, &QToolButton::clicked, this, &CCombineTrk::slotUp); connect(toolDown, &QToolButton::clicked, this, &CCombineTrk::slotDown); listAvailable->setCurrentItem(nullptr); listSelected->setCurrentItem(nullptr); slotSelectionChanged(); updatePreview(); } CCombineTrk::~CCombineTrk() { } void CCombineTrk::accept() { CGisWorkspace& gis = CGisWorkspace::self(); // get name of first track in list IGisItem::key_t key; key.item = listSelected->item(0)->data(Qt::UserRole + 1).toString(); key.project = listSelected->item(0)->data(Qt::UserRole + 2).toString(); key.device = listSelected->item(0)->data(Qt::UserRole + 3).toString(); CGisItemTrk * trk = dynamic_cast(gis.getItemByKey(key)); if(nullptr == trk) { return; } QList keys; // copy the segments of all tracks to new track for(int i = 0; i < listSelected->count(); i++) { IGisItem::key_t key; key.item = listSelected->item(i)->data(Qt::UserRole + 1).toString(); key.project = listSelected->item(i)->data(Qt::UserRole + 2).toString(); key.device = listSelected->item(i)->data(Qt::UserRole + 3).toString(); keys << key; } trk->combine(keys); QDialog::accept(); } void CCombineTrk::slotSelectionChanged() { QListWidgetItem * item = listAvailable->currentItem(); toolSelect->setEnabled(item != nullptr); item = listSelected->currentItem(); toolRemove->setEnabled(item != nullptr); toolUp->setEnabled(item != nullptr); toolDown->setEnabled(item != nullptr); if(item) { if(listSelected->row(item) == 0) { toolUp->setEnabled(false); } if(listSelected->row(item) == (listSelected->count() - 1)) { toolDown->setEnabled(false); } } buttonBox->button(QDialogButtonBox::Ok)->setEnabled(listSelected->count() > 1); } void CCombineTrk::slotSelect() { QListWidgetItem *item = listAvailable->currentItem(); if(nullptr == item) { return; } listAvailable->takeItem(listAvailable->row(item)); listSelected->addItem(item); slotSelectionChanged(); updatePreview(); } void CCombineTrk::slotRemove() { QListWidgetItem *item = listSelected->currentItem(); if(nullptr == item) { return; } IGisItem::key_t key; key.item = item->data(Qt::UserRole + 1).toString(); key.project = item->data(Qt::UserRole + 2).toString(); key.device = item->data(Qt::UserRole + 3).toString(); listSelected->takeItem(listSelected->row(item)); listAvailable->addItem(item); slotSelectionChanged(); updatePreview(); } void CCombineTrk::slotUp() { QListWidgetItem * item = listSelected->currentItem(); if(item) { int row = listSelected->row(item); if(row == 0) { return; } listSelected->takeItem(row); row = row - 1; listSelected->insertItem(row,item); listSelected->setCurrentItem(item); } updatePreview(); } void CCombineTrk::slotDown() { QListWidgetItem * item = listSelected->currentItem(); if(item) { int row = listSelected->row(item); if(row == (listSelected->count() - 1)) { return; } listSelected->takeItem(row); row = row + 1; listSelected->insertItem(row,item); listSelected->setCurrentItem(item); } updatePreview(); } void CCombineTrk::updatePreview() { CGisWorkspace& gis = CGisWorkspace::self(); QPolygonF line; for(int i = 0; i < listSelected->count(); i++) { IGisItem::key_t key; key.item = listSelected->item(i)->data(Qt::UserRole + 1).toString(); key.project = listSelected->item(i)->data(Qt::UserRole + 2).toString(); key.device = listSelected->item(i)->data(Qt::UserRole + 3).toString(); CGisItemTrk *trk1 = dynamic_cast(gis.getItemByKey(key)); if(nullptr == trk1) { continue; } QPolygonF line1; trk1->getPolylineFromData(line1); line += line1; } plotTrack->setTrack(line); plotTrack->update(); } qmapshack-1.10.0/src/gis/trk/CGisItemTrk.h000644 001750 000144 00000072316 13216234261 021402 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGISITEMTRK_H #define CGISITEMTRK_H #include "gis/IGisItem.h" #include "gis/IGisLine.h" #include "gis/trk/CActivityTrk.h" #include "gis/trk/CTrackData.h" #include "helpers/CLimit.h" #include "helpers/CValue.h" #include #include #include #include #include using std::numeric_limits; class QDomNode; class IGisProject; class INotifyTrk; class CDetailsTrk; class CScrOptTrk; class QSqlDatabase; class CQlgtTrack; class IQlgtOverlay; class CProgressDialog; class CPropertyTrk; class CFitStream; #define TRK_N_COLORS 17 #define ASCENT_THRESHOLD 5 #define MIN_WIDTH_INFO_BOX 300 class CGisItemTrk : public IGisItem, public IGisLine { Q_DECLARE_TR_FUNCTIONS(CGisItemTrk) public: enum focusmode_e { eFocusMouseMove ,eFocusMouseClick }; enum mode_e { eModeNormal , eModeRange }; enum visual_e { eVisualNone = 0 , eVisualColorLegend = 0x01 , eVisualPlot = 0x02 , eVisualDetails = 0x04 , eVisualProject = 0x08 , eVisualColorAct = 0x10 , eVisualTrkTable = 0x20 , eVisualAll = -1 }; /** @brief Used to create a new track from a part of an existing track */ CGisItemTrk(const QString& name, qint32 idx1, qint32 idx2, const CTrackData &srctrk, IGisProject *project); /** @brief Used to create a copy of track with new parent */ CGisItemTrk(const CGisItemTrk& parentTrk, IGisProject * project, int idx, bool clone); /** @brief Used to restore a track from a line of coordinates */ CGisItemTrk(const SGisLine &l, const QString &name, IGisProject *project, int idx); /** @brief Used to create track from GPX file */ CGisItemTrk(const QDomNode &xml, IGisProject *project); /** @brief Used to restore track from history structure */ CGisItemTrk(const history_t& hist, const QString& dbHash, IGisProject * project); /** @brief Used to restore track from database */ CGisItemTrk(quint64 id, QSqlDatabase& db, IGisProject * project); /** @brief Clone QLandkarte GT track */ CGisItemTrk(const CQlgtTrack& trk1, IGisProject *project = nullptr); /** @brief Load track from file (e.g. TwoNav *trk) */ CGisItemTrk(const QString& filename, IGisProject * project); CGisItemTrk(const IQlgtOverlay& ovl, IGisProject *project = nullptr); /** @brief Creates a new track via provided trkdata @param trkdata The track's new data (will be moved, don't use your "copy" after construction! @param project The project this track belongs to */ CGisItemTrk(CTrackData& trkdata, IGisProject *project); CGisItemTrk(CFitStream& stream, IGisProject * project); virtual ~CGisItemTrk(); /** @brief Overide IGisItem::updateHistory() method same as changed(); */ void updateHistory(quint32 visuals); /** @brief Update all registered visuals via the INotifyTrk interface @param a bit field of visuals to be updated @param who a string for debug purposes */ void updateVisuals(quint32 visuals, const QString &who); /** @brief Create a cloned copy of this track @return The cloned item a pointer */ IGisItem * createClone() override; /** @brief Save track to GPX tree @param gpx The node to append by the track */ void save(QDomNode& gpx, bool strictGpx11) override; /** @brief Save track to TwoNav track file @param dir the path to store the file */ bool saveTwoNav(const QString& filename); /** @brief Save track as TCX course (including correlated course points) @param coursesNode The node to append by the course */ void saveTCXcourse(QDomNode& coursesNode); /** @brief Save track as TCX activity @param activitiesNode The node to append by the activity */ void saveTCXactivity(QDomNode& activitiesNode); /** @brief Read serialized track from a binary data stream @param stream the data stream to read from @return A reference to the stream */ QDataStream& operator<<(QDataStream& stream) override; /** @brief Serialize track into a binary data stream @param stream the data stream to write to. @return A reference to the stream */ QDataStream& operator>>(QDataStream& stream) const override; /// get name of track const QString& getName() const override { return trk.name.isEmpty() ? noName : trk.name; } /// returns "true" when trk has no time-related invalid points bool isTrkTimeValid() { return (allValidFlags & CTrackData::trkpt_t::eInvalidTime) == 0; } QDateTime getTimestamp() const override {return getTimeStart(); } /// get the track color as index into the Garmin color table int getColorIdx() const { return colorIdx; } /// get the track color a Qt color object const QColor& getColor() const { return color; } /** @brief get a summary of the track @param showName if true the track name is shown @return */ QString getInfo(quint32 feature) const override; /// get a summary of a selected range QString getInfoRange() const; /// get a summary of a selected range defined by two track points QString getInfoRange(const CTrackData::trkpt_t& pt1, const CTrackData::trkpt_t& pt2) const; /// get a summary for a track point QString getInfoTrkPt(const CTrackData::trkpt_t& pt) const; /// get a progress summary for a selected track point QString getInfoProgress(const CTrackData::trkpt_t& pt) const; QString getInfoLimits() const; quint32 getTotalElapsedSeconds() const { return totalElapsedSeconds; } quint32 getTotalElapsedSecondsMoving() const { return totalElapsedSecondsMoving; } qreal getTotalAscent() const { return totalAscent; } qreal getTotalDescent() const { return totalDescent; } qreal getTotalDistance() const { return totalDistance; } const QString& getComment() const override { return trk.cmt; } const QString& getDescription() const override { return trk.desc; } const QList& getLinks() const override { return trk.links; } qint32 getCntTotalPoints() const { return cntTotalPoints; } const QDateTime& getTimeStart() const { return timeStart; } qint32 getNumberOfVisiblePoints() const { return cntVisiblePoints; } const CActivityTrk& getActivities() const { return activities; } const CPropertyTrk * getPropertyHandler() const { return propHandler; } const CTrackData::trkpt_t * getMouseMoveFocusPoint() const { return mouseMoveFocus; } quint32 getAllValidFlags() const { return allValidFlags; } /// get the track as a simple coordinate polyline void getPolylineFromData(QPolygonF &l) const; /// get the track as polyline with elevation, pixel and GIS coordinates. void getPolylineFromData(SGisLine& l) override; /** @brief Get the elevation of a track point @param idx The total index of the point @return The elevation or NOINT if the index is invalid, or the track point has no elevation value. */ qint32 getElevation(qint32 idx) const; void getMouseRange(int &idx1, int &idx2, bool total) const; /** @defgroup ColorSource Stuff related to coloring tracks using data from different sources @{ */ public: static const struct ColorizeSource unknownColorizeSource; /** @brief Set the colorize source to the source specified. @param src The new source to use. */ void setColorizeSource(QString src); /** @brief Get the current colorize source. @return The new source to use. */ QString getColorizeSource() const { return colorSourceLimit.getSource(); } QStringList getExistingDataSources() const; void setColorizeLimitLow(qreal limit); qreal getColorizeLimitLow() const { return colorSourceLimit.getMin(); } void setColorizeLimitHigh(qreal limit); qreal getColorizeLimitHigh() const { return colorSourceLimit.getMax(); } QString getColorizeUnit() const; qreal getMin(const QString& source) const; qreal getMax(const QString& source) const; private: void drawColorized(QPainter &p) const; void drawColorizedByActivity(QPainter& p) const; void setPen(QPainter& p, QPen& pen, quint32 flag) const; /**@}*/ public: bool isRangeSelected() const; void setName(const QString& str); void setColor(int idx); /// set the width of the inner track line by factor bool setMode(mode_e m, const QString &owner); void setComment(const QString& str) override; void setDescription(const QString& str) override; void setLinks(const QList& links) override; void setDataFromPolyline(const SGisLine &l) override; quint32 getNumberOfAttachedWpt() { return numberOfAttachedWpt; } /** @brief Manually set the elevation value of a single track point @param idx the total index of the track point @param ele the new elevation value */ void setElevation(qint32 idx, qint32 ele); /** @brief display the track screen options @param origin the point on screen to anchor the options @param mouse the mouse object causing the request @return a pointer to the screen option widget */ IScrOpt * getScreenOptions(const QPoint &origin, IMouse * mouse) override; /** @brief Get a screen pixel of the track close to the given position on the screen @param screenPos Screen position as pixel coordinate @return The screen coordinates as pixel of a track point close by */ QPointF getPointCloseBy(const QPoint& screenPos) override; /** @brief isCloseTo @param pos Screen position as pixel coordinate @return True if point is considered close enough */ bool isCloseTo(const QPointF& pos) override; bool isWithin(const QRectF& area, selflags_t flags) override; void drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) override; void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) override; void drawLabel(QPainter&p, const QPolygonF&, QList&blockedAreas, const QFontMetricsF&fm, CGisDraw*gis) override; void drawHighlight(QPainter& p) override; void drawRange(QPainter& p); /** @brief Switch user focus on and off. If the focus is switched on any other track having the focus will loose it. @param yes set true to gain focus. */ void gainUserFocus(bool yes) override; /** @brief Make sure the track has lost focus. If the track has the focus, keyUserFocus will be reset. In all other cases nothing will be done. */ void looseUserFocus(); /** @brief Make sure a CDetailsTrk widget is registered with the main tab widget */ void edit() override; /** @brief Cut track at mouseClickFocus @return Return true on success. */ bool cut(); /** @brief Reverse the complete track @note All timestamps will be removed */ void reverse(); /** @brief Combine this track with several others. @param keysPreSel list of pre-selected track item keys Handle the complete process of selecting tracks, choosing the order and the final name with dialogs. */ void combine(const QList &keys); /** @brief Set the CTrackData::trkpt_t::eHidden flag The flag is set for all track points between mouseClickFocus and mouseMoveFocus, regardless of their previous state. */ void hideSelectedPoints(); /** @brief Reset the CTrackData::trkpt_t::eHidden flag The flag is reset for all track points between mouseClickFocus and mouseMoveFocus, regardless of their previous state. */ void showSelectedPoints(); /** @brief Set the activity flag for all track points @param flag one of CTrackData::trkpt_t::flag_e::eAct... */ void setActivity(quint32 flags); /** @brief Sets the activity flag for a selected range of track points The range has to be selected already. The activity will be selected by a dialog displayed in this method. */ void setActivityRange(quint32 flags); /** @brief Copy a section into a new track object The section is defined by mouseClickFocus and mouseMoveFocus, All points are copied, including the hidden (CTrackData::trkpt_t::eHidden) ones. */ void copySelectedPoints() const; /** @brief Check for user focus @return True if the track has user focus */ bool hasUserFocus() const override { return key == keyUserFocus; } /** @brief Get the key of the current track with user focus @return If no track has the focus an empty string is returned */ static const key_t& getKeyUserFocus() { return keyUserFocus; } /** @brief Each plot widget that operates on the track must register during it's construction see registeredPlots for a detailed discussion @param plot */ void registerVisual(INotifyTrk * visual); /** @brief Each plot widget that operates on the track must unregister during it's destruction see registeredPlots for a detailed discussion @param plot */ void unregisterVisual(INotifyTrk * visual); /** @brief Use point with the distance from start matching best the given distance. @param dist the distance in [m] */ bool setMouseFocusByDistance(qreal dist, focusmode_e fmode, const QString& owner); /** @brief Use point with time from start matching best the given time delta @param time a time delta in [s] relative to the start time */ bool setMouseFocusByTime(quint32 time, focusmode_e fmode, const QString& owner); /** @brief Use the point that is closest to the given point on the screen. @param pt a point on the screen in pixel. */ QPointF setMouseFocusByPoint(const QPoint& pt, focusmode_e fmode, const QString& owner); /** @brief Use point with given index counter @param idx */ bool setMouseFocusByTotalIndex(qint32 idx, focusmode_e fmode, const QString& owner); /** @defgroup Filter All filters implemented by CGisItemTrks. @note All filter implementations are found in src/gis/trk/filter/filter.cpp @{ */ /** @brief Reduce the amount of visible track points with the help of the Douglas Peuker algorithm @param dist the Douglas Peuker distance in meters */ void filterReducePoints(qreal dist); /** @brief Remove track points without valid location at the beginning of the track */ void filterRemoveInvalidPoints(); /** @param points size of Median filter */ void filterSmoothProfile(int points); /** @param offset elevation offset in meters */ void filterOffsetElevation(int offset); /** @param date new date for start of track */ void filterNewDate(const QDateTime& date); /** @param delta interval to increase timestamps in seconds a*/ void filterObscureDate(int delta); /** @param speed speed in meter per seconds */ void filterSpeed(qreal speed); void filterTerrainSlope(); void filterReplaceElevation(); void filterInterpolateElevation(); void filterReset(); void filterDelete(); void filterSplitSegment(); void filterDeleteExtension(const QString &ext); void filterSubPt2Pt(); /** @} */ /** @brief Correlate waypoints with the track points If a waypoint correlates with a trackpoint it's key is written to CTrackData::trkpt_t::keyWpt. @param progress a progress dialog as this operation can take quite some time @param current the current progress if the operation is done for several tracks */ void findWaypointsCloseBy(CProgressDialog &progress, quint32 ¤t); private: /// no don't really use it, use CGisItemTrk(quint32 visuals) instead void updateHistory() override { updateHistory(eVisualAll); } void setSymbol() override; /** @brief Read track data from section in GPX file @param xml The XML section @param trk The track structure to fill */ void readTrk(const QDomNode& xml, CTrackData& trk); /** @brief Restore track from TwoNav *trk file @param filename */ bool readTwoNav(const QString& filename); /** @brief Read serialized track data from a FIT file stream @param stream */ void readTrkFromFit(CFitStream &stream); /** @brief Consolidate points and subpoints */ void consolidatePoints(); /** @brief Derive secondary data from the track data This has to be called each time the track data is changed. */ void deriveSecondaryData(); /** * @brief Reset internal data like range selection and details dialog */ void resetInternalData(); void verifyTrkPt(CTrackData::trkpt_t *&last, CTrackData::trkpt_t& trkpt); /** @defgroup ExtremaExtensions Stuff related to calculation of extrema/extensions @{ */ public: struct limits_t { void setMin(qreal val, const QPointF& pos) { if(min > val) { min = val; posMin = pos; } } void setMax(qreal val, const QPointF& pos) { if(max < val) { max = val; posMax = pos; } } qreal min = numeric_limits::max(); QPointF posMin = NOPOINTF; qreal max = numeric_limits::lowest(); QPointF posMax = NOPOINTF; }; /**@}*/ private: QSet existingExtensions; QHash extrema; void updateExtremaAndExtensions(); enum limit_type_e { eLimitTypeMin , eLimitTypeMax }; void drawLimitLabels(limit_type_e type, const QString &label, const QPointF& pos, QPainter& p, const QFontMetricsF &fm, QList &blockedAreas); /** @brief Tell the point of focus to all plots and the detail dialog @param pt A pointer to the point itself @param fmode The reason for the focus @param owner A string to identify owner of the operation */ bool publishMouseFocus(const CTrackData::trkpt_t * pt, focusmode_e fmode, const QString &owner); void publishMouseFocusNormalMode(const CTrackData::trkpt_t * pt, focusmode_e fmode); void publishMouseFocusRangeMode(const CTrackData::trkpt_t * pt, focusmode_e fmode); void resetMouseRange(); /** @brief Replace all trackpoints by the coordinates stored in the polyline The DEM layer will be queried for elevation data. All other data is lost. @param l A polyline with coordinates [rad] */ void readTrackDataFromGisLine(const SGisLine &l); /** @brief Override IGisItem::changed() method As the CDetailsTrk is no modal dialog that blocks the GUI from any other input the track can be changed while the widget is visible. Therefore it needs some feedback to update the CDetailsTrk widget. Usually this would be a signal. However CGisItemTrk is a QTreeWidgetItem and therefor no QObject. Fortunately there the dlgDetails pointer. So CDetailsTrk::setupGui() can be called from changed() @param what The reason string @param icon An icon string */ void changed(const QString& what, const QString& icon) override; /// setup colorIdx, color, bullet and icon void setColor(const QColor& c); /// setup track icon by color void setIcon(const QString& iconColor); void setMouseFocusVisuals(const CTrackData::trkpt_t * pt); void setMouseRangeFocusVisuals(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2); void setMouseClickFocusVisuals(const CTrackData::trkpt_t * pt); public: /** @brief Read only access to the track data. @return */ const CTrackData& getTrackData() const { return trk; } void updateFromDB(quint64 id, QSqlDatabase& db) override; private: fGetLimit _getMin = [this](const QString& source) { return getMin(source); }; fGetLimit _getMax = [this](const QString& source) { return getMax(source); }; qreal getMinProp(const QString& source) const; qreal getMaxProp(const QString& source) const; QString getUnitProp(const QString& source) const; fGetLimit _getMinProp = [this](const QString& source) { return getMinProp(source); }; fGetLimit _getMaxProp = [this](const QString& source) { return getMaxProp(source); }; fGetUnit _getUnitProp = [this](const QString& source) { return getUnitProp(source); }; fMarkChanged _markChanged = [this]() { updateHistory(eVisualNone); }; public: CLimit limitsGraph1 {"TrackDetails/Graph1", _getMin, _getMax, _getMinProp, _getMaxProp, _getUnitProp, _markChanged}; CLimit limitsGraph2 {"TrackDetails/Graph2", _getMin, _getMax, _getMinProp, _getMaxProp, _getUnitProp, _markChanged}; CLimit limitsGraph3 {"TrackDetails/Graph3", _getMin, _getMax, _getMinProp, _getMaxProp, _getUnitProp, _markChanged}; CLimit colorSourceLimit {"TrackDetails/Style", _getMin, _getMax, _getMin, _getMax, _getUnitProp, _markChanged}; private: /// this is the GPX structure oriented data of the track CTrackData trk; /// the key of the track having the user focus. static key_t keyUserFocus; /// drawing and mouse interaction is dependent on the mode mode_e mode = eModeNormal; /** \defgroup TrackStatistics Some statistical values over the complete track */ /**@{*/ quint32 allValidFlags = 0; qint32 cntInvalidPoints = 0; qint32 cntTotalPoints = 0; qint32 cntVisiblePoints = 0; QDateTime timeStart; QDateTime timeEnd; qreal totalDistance = 0; qreal totalAscent = 0; qreal totalDescent = 0; qreal totalElapsedSeconds = 0; qreal totalElapsedSecondsMoving = 0; quint32 numberOfAttachedWpt = 0; /**@}*/ /** \defgroup DrawUtilies Objects used to draw the track */ /**@{*/ unsigned colorIdx = 4; //< the track line color by index QColor color; //< the track line color QPixmap bullet; //< the trackpoint bullet icon QPolygonF lineSimple; //< the current track line as screen pixel coordinates QPolygonF lineFull; //< visible and invisible points qint32 penWidthFg = 3; //< inner trackline width qint32 penWidthBg = 5; //< outer trackline width qint32 penWidthHi = 11; //< highlighted trackline width qint32 widthInfoBox = MIN_WIDTH_INFO_BOX; /// the pen with the actual track color QPen penForeground {Qt::blue, qreal(penWidthFg), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; /// background (border) color of all tracks QPen penBackground {Qt::white, qreal(penWidthBg), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; fValueOnChange onChange = [this](const QVariant& val) { int w = qRound(3.0 * val.toDouble()); penWidthFg = w; penWidthBg = w + 2; penWidthHi = w + 8; penForeground.setWidth(penWidthFg); penBackground.setWidth(penWidthBg); }; public: CValue lineScale {"TrackDetails/lineScale", 1.0, _markChanged, onChange}; CValue showArrows {"TrackDetails/showArrows", true, _markChanged}; private: /**@}*/ /** A list of INotifyTrk objects that need to get informed on any change in data. @note This is necessary because QTreeWidgetItem is not derived from QObject. Thus no signals and slots can be handled. Probably this is because the signal/slot system would be a huge overhead on treewidgets with a large amount of items. Anyway we need some kind of signaling between the track object and the INotifyTrk objects displaying the data. And we have to keep in mind that the track can be delete by the user at any time. That is why no other object is allowed to save a pointer to the track. It must store the key. But accessing the track via key is expensive. That is why we make an exception here. As the track will delete all registered INotifyTrk objects upon destruction, it should be ok to store the track object in the INotifyTrk object, too. By that INotifyTrk and track can easily communicate with each other. @note CDetailsTrk is an INotifyTrk, too. But it is a bit special as it has to be destroyed right after all other INotifyTrk have been destroyed. That is why it is not part of that set. */ QSet registeredVisuals; /** \defgroup FocusRange Variables to handle mouse focus and range selection */ /**@{*/ enum rangestate_e { eRangeStateIdle , eRangeState1st , eRangeState2nd }; /// state variable for range selection rangestate_e rangeState = eRangeStateIdle; /** @brief Identify source of current range selection Each range selection operation has to provide an owner string. If mouseFocusOwner is not empty and different to the passed owner string the operation must be rejected. */ QString mouseFocusOwner; const CTrackData::trkpt_t *mouseMoveFocus = nullptr; //< the current track point selected by mouse movement const CTrackData::trkpt_t *mouseClickFocus = nullptr; //< the last track point the user clicked on const CTrackData::trkpt_t *mouseRange1 = nullptr; //< the first point of a range selection const CTrackData::trkpt_t *mouseRange2 = nullptr; //< the second point of a range selection /**@}*/ QPointer dlgDetails; //< the track's details dialog if any QPointer scrOpt; //< the track's screen option if visible /// all function concerning track activities have been moved to CActivityTrk CActivityTrk activities = {this}; /// all functions and data concerning graphs CPropertyTrk * propHandler = nullptr; /** \defgroup Data and API related to track interpolation */ /**@{*/ public: enum quality_e { eQualityFine = 8 , eQualityMedium = 4 , eQualityCoarse = 2 }; void setupInterpolation(bool on, qint32 q); bool isInterpolationEnabled() const { return interp.valid; } qreal getElevationInterpolated(qreal d); private: struct interpolate_t { bool valid = false; quality_e Q = eQualityCoarse; alglib::ae_int_t info = -1; alglib::ae_int_t m = 0; alglib::spline1dinterpolant p; alglib::spline1dfitreport rep; }; interpolate_t interp; /**@}*/ }; class INotifyTrk { public: INotifyTrk(CGisItemTrk::visual_e mask) : mask(mask){} virtual ~INotifyTrk() = default; virtual void updateData() = 0; virtual void setMouseFocus(const CTrackData::trkpt_t * pt) = 0; virtual void setMouseRangeFocus(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2) = 0; virtual void setMouseClickFocus(const CTrackData::trkpt_t * pt) = 0; const CGisItemTrk::visual_e mask; }; using fTrkPtGetVal = std::function; #endif //CGISITEMTRK_H qmapshack-1.10.0/src/gis/trk/CPropertyTrk.h000644 001750 000144 00000006306 13216234143 021660 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPROPERTYTRK_H #define CPROPERTYTRK_H #include "gis/trk/CGisItemTrk.h" #include "plot/CPlotData.h" #include class QComboBox; class CPlot; class CLimit; class CPropertyTrk { Q_DECLARE_TR_FUNCTIONS(CPropertyTrk) public: virtual ~CPropertyTrk() = default; struct property_t { enum axistype_e { eAxisDistance ,eAxisTime }; property_t() = default; property_t(const QString& key, const QString& nameShortText, const QString& nameLongText, const QIcon& icon, axistype_e axisType, fTrkPtGetVal getX, const QString& unit, const QString& yLabel, qreal factor, fTrkPtGetVal getY) : key(key) , nameShortText(nameShortText) , nameLongText(nameLongText) , icon(icon) , axisType(axisType) , getX(getX) , unit(unit) , yLabel(yLabel) , factor(factor) , getY(getY) { } // key/extension source of the property QString key; // long and short name of the property QString nameShortText; QString nameLongText; // symbol representing the property QIcon icon; // the x-axis type to be used in plots axistype_e axisType = eAxisDistance; // access function to the x-values fTrkPtGetVal getX = nullptr; // the unit of the y-axis QString unit; // the y-axis label QString yLabel; // a scaling factor for the y-values (e.g. m/h -> km/h) qreal factor = 1.0; // access function to the y-values fTrkPtGetVal getY = nullptr; // lower limit of the y-axis qreal min = NOFLOAT; // upper limit of the y-axis qreal max = NOFLOAT; }; void fillComboBox(QComboBox * box) const; void setupData(); void setupPlot(CPlot * plot, const QString &source) const; const property_t &propBySource(const QString& source) const; private: friend class CGisItemTrk; CPropertyTrk(CGisItemTrk &trk); CGisItemTrk& trk; QList properties; }; #endif //CPROPERTYTRK_H qmapshack-1.10.0/src/gis/trk/IScrOptTrk.ui000644 001750 000144 00000016206 13147467735 021464 0ustar00oeichlerxusers000000 000000 IScrOptTrk 0 0 311 65 Form 3 3 3 3 3 3 View details and edit properties of track. ... :/icons/32x32/EditDetails.png:/icons/32x32/EditDetails.png Copy track into another project. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png Delete track from project. ... :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png Qt::Vertical Show on-screen profile and detailed information about points. ... :/icons/32x32/TrkProfile.png:/icons/32x32/TrkProfile.png true Select a range of points. ... :/icons/32x32/SelectRange.png:/icons/32x32/SelectRange.png Edit position of track points. ... :/icons/32x32/LineMove.png:/icons/32x32/LineMove.png Reverse track. ... :/icons/32x32/Reverse.png:/icons/32x32/Reverse.png Combine tracks. ... :/icons/32x32/Combine.png:/icons/32x32/Combine.png Cut track at selected point. You can use this to: * remove bad points at the start or end of the track * use the track parts to plan a new tour * cut a long track into stages ... :/icons/32x32/TrkCut.png:/icons/32x32/TrkCut.png Set an activity for the complete track. ... :/icons/32x32/Activity.png:/icons/32x32/Activity.png Copy track together with all attached waypoints into another project. ... :/icons/32x32/CopyTrkWithWpt.png:/icons/32x32/CopyTrkWithWpt.png Qt::Horizontal 40 20 TextLabel Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse qmapshack-1.10.0/src/gis/trk/CActivityTrk.h000644 001750 000144 00000007355 13216234143 021635 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CACTIVITYTRK_H #define CACTIVITYTRK_H #include #include #include #include #include #include class CGisItemTrk; class CActivityTrk { Q_DECLARE_TR_FUNCTIONS(CActivityTrk) public: virtual ~CActivityTrk() = default; static void init(); static void release(); struct activity_summary_t { activity_summary_t() : distance(0), ascent(0), descent(0), ellapsedSeconds(0), ellapsedSecondsMoving(0) { } void reset() { distance = 0; ascent = 0; descent = 0; ellapsedSeconds = 0; ellapsedSecondsMoving = 0; } qreal distance; qreal ascent; qreal descent; qreal ellapsedSeconds; qreal ellapsedSecondsMoving; }; struct activity_range_t { qreal d1; qreal d2; qreal t1; qreal t2; QString icon; QString name; }; struct desc_t { QString objName; quint32 flag; QString name; QString iconLarge; QString iconSmall; QColor color; }; /** @brief Update internal summary array */ void update(); /** @brief Get sum of all flags seen in the track @return A 32 bit field with all available activity flags set. */ quint32 getAllFlags() const { return allFlags; } qint32 getActivityCount() const; void getActivityNames(QStringList& names) const; static quint32 selectActivity(QWidget *parent); /** @brief Convert internal summary to HTML table @param str string to receive HTML */ void printSummary(QString& str) const; /** @brief Convert array of summaries to HTML table @param summary The array of summaries @param str string to receive HTML */ static void printSummary(const QMap &summary, quint32 flags, QString& str); /** @brief Add internal summary to given array of summaries @param summary an array of summaries to hold the sum */ void sumUp(QMap &summary) const; const QList& getActivityRanges() const { return activityRanges; } static const QVector& getActivityDescriptors() { return actDescriptor; } static const desc_t& getDescriptor(quint32 flag); static void setColor(quint32 flag, const QString& color); private: friend class CGisItemTrk; CActivityTrk(CGisItemTrk * trk); static QVector actDescriptor; static const desc_t dummyDesc; CGisItemTrk * trk; quint32 allFlags; QList activityRanges; QMap activitySummary; }; #endif //CACTIVITYTRK_H qmapshack-1.10.0/src/gis/trk/filter/000755 001750 000144 00000000000 13216664445 020373 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/trk/filter/CFilterSplitSegment.h000644 001750 000144 00000002620 13216234143 024417 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CFILTERSPLITSEGMENT_H #define CFILTERSPLITSEGMENT_H #include "ui_IFilterSplitSegment.h" #include class CGisItemTrk; class CFilterSplitSegment : public QWidget, private Ui::IFilterSplitSegment { Q_OBJECT public: CFilterSplitSegment(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterSplitSegment() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif // CFILTERSPLITSEGMENT_H qmapshack-1.10.0/src/gis/trk/filter/IFilterInvalid.ui000644 001750 000144 00000005427 12727447634 023614 0ustar00oeichlerxusers000000 000000 IFilterInvalid 0 0 787 82 Form 3 0 0 0 3 75 true Hide Invalid Points Qt::PlainText 3 Hide points with invalid data. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal 0 0 :/icons/48x48/PointHide.png qmapshack-1.10.0/src/gis/trk/filter/IFilterNewDate.ui000644 001750 000144 00000006053 12542262457 023542 0ustar00oeichlerxusers000000 000000 IFilterNewDate 0 0 896 58 Form 3 0 0 0 3 <b>Change Time</b> Change start of track to dd.MM.yy HH:mm:ss true - Qt::Horizontal 40 20 ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal :/icons/48x48/Time.png qmapshack-1.10.0/src/gis/trk/filter/CFilterTerrainSlope.cpp000644 001750 000144 00000002642 13216234137 024752 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterTerrainSlope.h" CFilterTerrainSlope::CFilterTerrainSlope(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterTerrainSlope::slotApply); } void CFilterTerrainSlope::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterTerrainSlope"); trk.filterTerrainSlope(); CCanvas::restoreOverrideCursor("CFilterTerrainSlope"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterDeleteExtension.cpp000644 001750 000144 00000004257 13216234137 025446 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/trk/filter/CFilterDeleteExtension.h" CFilterDeleteExtension::CFilterDeleteExtension(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); update(); connect(toolApply, &QToolButton::clicked, this, &CFilterDeleteExtension::slotApply); } void CFilterDeleteExtension::update() { comboExtensions->clear(); for(const QString &key : trk.getExistingDataSources()) { const CKnownExtension &ext = CKnownExtension::get(key); if(!ext.derivedQMS) { QIcon icon(ext.icon); comboExtensions->addItem(icon, ext.known ? ext.nameLongText : key, key); } } bool enabled = (0 != comboExtensions->count()); toolApply->setEnabled(enabled); comboExtensions->setEnabled(enabled); if(!enabled) { comboExtensions->addItem(tr("No extension available"), ""); } } void CFilterDeleteExtension::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterDeleteExtension"); int idx = comboExtensions->currentIndex(); trk.filterDeleteExtension(comboExtensions->itemData(idx).toString()); CCanvas::restoreOverrideCursor("CFilterDeleteExtension"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterDeleteExtension.h000644 001750 000144 00000002577 13216234143 025113 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CFILTERDELETEEXTENSION_H #define CFILTERDELETEEXTENSION_H #include "ui_IFilterDeleteExtension.h" #include class CGisItemTrk; class CFilterDeleteExtension : public QWidget, private Ui::IFilterDeleteExtension { Q_OBJECT public: CFilterDeleteExtension(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterDeleteExtension() = default; void update(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERDELETEEXTENSION_H qmapshack-1.10.0/src/gis/trk/filter/CFilterNewDate.h000644 001750 000144 00000002444 13216234143 023334 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERNEWDATE_H #define CFILTERNEWDATE_H #include "ui_IFilterNewDate.h" #include class CGisItemTrk; class CFilterNewDate : public QWidget, private Ui::IFilterNewDate { Q_OBJECT public: CFilterNewDate(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterNewDate() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERNEWDATE_H qmapshack-1.10.0/src/gis/trk/filter/IFilterDelete.ui000644 001750 000144 00000005123 12453154213 023401 0ustar00oeichlerxusers000000 000000 IFilterDelete 0 0 811 82 Form 3 0 0 0 3 0 0 :/icons/48x48/PointHide.png <b>Remove Track Points</b> 3 Remove all hidden track points permanently. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/IFilterMedian.ui000644 001750 000144 00000007052 12453154213 023377 0ustar00oeichlerxusers000000 000000 IFilterMedian 0 0 820 58 Form 3 0 0 0 3 0 0 :/icons/48x48/SetEle.png <b>Smooth Profile (Median Method)</b> 3 Smooth deviation of the track points elevation with a Median filter of size 0 0 points 5 9 2 Qt::Horizontal 40 20 ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/CFilterInvalid.h000644 001750 000144 00000002444 13216234143 023373 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERINVALID_H #define CFILTERINVALID_H #include "ui_IFilterInvalid.h" #include class CGisItemTrk; class CFilterInvalid : public QWidget, private Ui::IFilterInvalid { Q_OBJECT public: CFilterInvalid(CGisItemTrk& trk, QWidget *parent); virtual ~CFilterInvalid() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif // CFILTERINVALID_H qmapshack-1.10.0/src/gis/trk/filter/CFilterReplaceElevation.h000644 001750 000144 00000002554 13216234143 025231 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERREPLACEELEVATION_H #define CFILTERREPLACEELEVATION_H #include "ui_IFilterReplaceElevation.h" #include class CGisItemTrk; class CFilterReplaceElevation : public QWidget, private Ui::IFilterReplaceElevation { Q_OBJECT public: CFilterReplaceElevation(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterReplaceElevation() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERREPLACEELEVATION_H qmapshack-1.10.0/src/gis/trk/filter/CFilterDouglasPeuker.h000644 001750 000144 00000002511 13216234143 024552 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERDOUGLASPEUKER_H #define CFILTERDOUGLASPEUKER_H #include "ui_IFilterDouglasPeuker.h" #include class CGisItemTrk; class CFilterDouglasPeuker : public QWidget, private Ui::IFilterDouglasPeuker { Q_OBJECT public: CFilterDouglasPeuker(CGisItemTrk& trk, QWidget *parent); virtual ~CFilterDouglasPeuker(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERDOUGLASPEUKER_H qmapshack-1.10.0/src/gis/trk/filter/CFilterDelete.cpp000644 001750 000144 00000002562 13216234137 023546 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterDelete.h" CFilterDelete::CFilterDelete(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterDelete::slotApply); } void CFilterDelete::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterDelete"); trk.filterDelete(); CCanvas::restoreOverrideCursor("CFilterDelete"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterReset.cpp000644 001750 000144 00000002553 13216234137 023426 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterReset.h" CFilterReset::CFilterReset(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterReset::slotApply); } void CFilterReset::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterReset"); trk.filterReset(); CCanvas::restoreOverrideCursor("CFilterReset"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterMedian.h000644 001750 000144 00000002422 13216234143 023176 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERMEDIAN_H #define CFILTERMEDIAN_H #include "ui_IFilterMedian.h" #include class CGisItemTrk; class CFilterMedian : public QWidget, private Ui::IFilterMedian { Q_OBJECT public: CFilterMedian(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterMedian(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERMEDIAN_H qmapshack-1.10.0/src/gis/trk/filter/CFilterOffsetElevation.h000644 001750 000144 00000002532 13216234143 025100 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTEROFFSETELEVATION_H #define CFILTEROFFSETELEVATION_H #include "ui_IFilterOffsetElevation.h" #include class CGisItemTrk; class CFilterOffsetElevation : public QWidget, private Ui::IFilterOffsetElevation { Q_OBJECT public: CFilterOffsetElevation(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterOffsetElevation(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTEROFFSETELEVATION_H qmapshack-1.10.0/src/gis/trk/filter/CFilterSubPt2Pt.h000644 001750 000144 00000002455 13216234143 023432 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CFILTERSUBPT2PT #define CFILTERSUBPT2PT #include "ui_IFilterSubPt2Pt.h" #include class CGisItemTrk; class CFilterSubPt2Pt : public QWidget, private Ui::IFilterSubPt2Pt { Q_OBJECT public: CFilterSubPt2Pt(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterSubPt2Pt() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERSUBPT2PT qmapshack-1.10.0/src/gis/trk/filter/CFilterMedian.cpp000644 001750 000144 00000003235 13216234137 023537 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterMedian.h" #include "helpers/CSettings.h" #include "units/IUnit.h" CFilterMedian::CFilterMedian(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); SETTINGS; spinBox->setValue(cfg.value("TrackDetails/Filter/Median/points",5).toInt()); connect(toolApply, &QToolButton::clicked, this, &CFilterMedian::slotApply); } CFilterMedian::~CFilterMedian() { SETTINGS; cfg.setValue("TrackDetails/Filter/Median/points", spinBox->value()); } void CFilterMedian::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterMedian"); trk.filterSmoothProfile(spinBox->value()); CCanvas::restoreOverrideCursor("CFilterMedian"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterInterpolateElevation.h000644 001750 000144 00000002633 13216234143 026142 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERINTERPOLATEELEVATION_H #define CFILTERINTERPOLATEELEVATION_H #include "ui_IFilterInterpolateElevation.h" #include class CGisItemTrk; class CFilterInterpolateElevation : public QWidget, private Ui::IFilterInterpolateElevation { Q_OBJECT public: CFilterInterpolateElevation(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterInterpolateElevation(); private slots: void slotApply(); void slotPreview(); private: CGisItemTrk& trk; }; #endif //CFILTERINTERPOLATEELEVATION_H qmapshack-1.10.0/src/gis/trk/filter/IFilterSpeed.ui000644 001750 000144 00000006172 12453154213 023244 0ustar00oeichlerxusers000000 000000 IFilterSpeed 0 0 997 56 Form 3 0 0 0 3 <b>Change Speed</b> Set speed to km/h 1 0.100000000000000 Qt::Horizontal 40 20 Qt::Horizontal 0 0 :/icons/48x48/Time.png ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 qmapshack-1.10.0/src/gis/trk/filter/IFilterInterpolateElevation.ui000644 001750 000144 00000007432 13015033052 026331 0ustar00oeichlerxusers000000 000000 IFilterInterpolateElevation 0 0 842 58 Form 3 0 0 0 3 0 0 :/icons/48x48/SetEle.png <b>Interpolate Elevation Data</b> 3 0 0 Replace elevation of track points with interpolated data. Quality Qt::Horizontal 40 20 0 0 Preview ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/CFilterReplaceElevation.cpp000644 001750 000144 00000002702 13216234137 025562 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterReplaceElevation.h" CFilterReplaceElevation::CFilterReplaceElevation(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterReplaceElevation::slotApply); } void CFilterReplaceElevation::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterReplaceElevation"); trk.filterReplaceElevation(); CCanvas::restoreOverrideCursor("CFilterReplaceElevation"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterInvalid.cpp000644 001750 000144 00000002610 13216234137 023724 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterInvalid.h" CFilterInvalid::CFilterInvalid(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterInvalid::slotApply); } void CFilterInvalid::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor, "CFilterInvalid"); trk.filterRemoveInvalidPoints(); CCanvas::restoreOverrideCursor("CFilterInvalid"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterOffsetElevation.cpp000644 001750 000144 00000003514 13216234137 025437 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterOffsetElevation.h" #include "helpers/CSettings.h" #include "units/IUnit.h" CFilterOffsetElevation::CFilterOffsetElevation(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); spinBox->setSuffix(IUnit::self().baseunit); SETTINGS; spinBox->setValue(cfg.value("TrackDetails/Filter/OffsetElevation/offset",0).toInt()); connect(toolApply, &QToolButton::clicked, this, &CFilterOffsetElevation::slotApply); } CFilterOffsetElevation::~CFilterOffsetElevation() { SETTINGS; cfg.setValue("TrackDetails/Filter/OffsetElevation/offset", spinBox->value()); } void CFilterOffsetElevation::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterOffsetElevation"); trk.filterOffsetElevation(spinBox->value()/IUnit::self().basefactor); CCanvas::restoreOverrideCursor("CFilterOffsetElevation"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterDelete.h000644 001750 000144 00000002434 13216234143 023206 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERDELETE_H #define CFILTERDELETE_H #include "ui_IFilterDelete.h" #include class CGisItemTrk; class CFilterDelete : public QWidget, private Ui::IFilterDelete { Q_OBJECT public: CFilterDelete(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterDelete() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERDELETE_H qmapshack-1.10.0/src/gis/trk/filter/IFilterOffsetElevation.ui000644 001750 000144 00000007472 12453154213 025305 0ustar00oeichlerxusers000000 000000 IFilterOffsetElevation 0 0 690 82 Form 3 0 0 0 3 0 0 :/icons/48x48/SetEle.png <b>Offset Elevation</b> 3 0 0 Add offset of 0 0 m -8000 8000 to track points elevation. Qt::Horizontal 40 20 ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/CFilterObscureDate.h000644 001750 000144 00000002472 13216234143 024206 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTEROBSCUREDATE_H #define CFILTEROBSCUREDATE_H #include "ui_IFilterObscureDate.h" #include class CGisItemTrk; class CFilterObscureDate : public QWidget, private Ui::IFilterObscureDate { Q_OBJECT public: CFilterObscureDate(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterObscureDate(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTEROBSCUREDATE_H qmapshack-1.10.0/src/gis/trk/filter/IFilterSplitSegment.ui000644 001750 000144 00000005354 12705713523 024630 0ustar00oeichlerxusers000000 000000 IFilterSplitSegment 0 0 811 82 Form 3 0 0 0 3 0 0 :/icons/48x48/TrkCut.png <html><head/><body><p><span style=" font-weight:600;">Split Segments into Tracks</span></p></body></html> 3 Creates a new track for every segment within this track. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/filter.cpp000644 001750 000144 00000023174 13216234137 022362 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "CMainWindow.h" #include "GeoMath.h" #include "gis/CGisWorkspace.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/trk/CPropertyTrk.h" #include #include void CGisItemTrk::filterReducePoints(qreal dist) { QVector line; bool nothingDone = true; for(const CTrackData::trkpt_t &pt : trk) { pointDP dp(pt.lon * DEG_TO_RAD, pt.lat * DEG_TO_RAD, pt.ele); dp.used = !pt.isHidden(); line << dp; } if(line.size() < 3) { return; } point3D pt0 = line[0]; line[0].x = 0; line[0].y = 0; for(int i = 1; i < line.size(); i++) { pointDP& pt1 = line[i - 1]; pointDP& pt2 = line[i]; qreal a1, a2; qreal d = GPS_Math_Distance(pt0.x, pt0.y, pt2.x, pt2.y, a1, a2); pt0 = pt2; pt2.x = pt1.x + qCos(a1 * DEG_TO_RAD) * d; pt2.y = pt1.y + qSin(a1 * DEG_TO_RAD) * d; } GPS_Math_DouglasPeucker(line, dist); int cnt = 0; for(CTrackData::trkpt_t& pt : trk) { if(line[cnt].used) { pt.unsetFlag(CTrackData::trkpt_t::eHidden); } else { if(!pt.isHidden()) { nothingDone = false; pt.setFlag(CTrackData::trkpt_t::eHidden); } } cnt++; } if(nothingDone) { return; } deriveSecondaryData(); QString val, unit; IUnit::self().meter2distance(dist, val, unit); changed(tr("Hide points by Douglas Peuker algorithm (%1%2)").arg(val).arg(unit), "://icons/48x48/PointHide.png"); } void CGisItemTrk::filterRemoveInvalidPoints() { bool nothingDone = true; // use all valid flags as invalid mask. By that only // invalid flags for properties with valid points count quint32 invalidMask = (getAllValidFlags() & CTrackData::trkpt_t::eValidMask) << 16; for(CTrackData::trkpt_t& pt : trk) { if(pt.isInvalid(CTrackData::trkpt_t::invalid_e(invalidMask))) { pt.setFlag(CTrackData::trkpt_t::eHidden); nothingDone = false; } } if(nothingDone) { return; } deriveSecondaryData(); changed(tr("Hide points with invalid data."), "://icons/48x48/PointHide.png"); } void CGisItemTrk::filterReset() { for(CTrackData::trkpt_t& pt : trk) { pt.unsetFlag(CTrackData::trkpt_t::eHidden); } deriveSecondaryData(); changed(tr("Reset all hidden track points to visible"), "://icons/48x48/PointHide.png"); } void CGisItemTrk::filterDelete() { bool nothingDone = true; for(CTrackData::trkseg_t& seg : trk.segs) { QVector pts; for(const CTrackData::trkpt_t &pt : seg.pts) { if(pt.isHidden()) { nothingDone = false; continue; } pts << pt; } seg.pts = pts; } if(nothingDone) { return; } deriveSecondaryData(); changed(tr("Permanently removed all hidden track points"), "://icons/48x48/PointHide.png"); } void CGisItemTrk::filterSmoothProfile(int points) { QVector window(points, 0); QVector ele1, ele2; for(const CTrackData::trkpt_t &pt : trk) { ele1 << pt.ele; ele2 << pt.ele; } if(ele1.size() < (points + 1)) { return; } int d = points >> 1; for(int i = d; i < ele1.size() - d; i++) { for(int n = i - d, m = 0; m < points; n++, m++) { window[m] = ele1[n]; } qSort(window); ele2[i] = window[d]; } int cnt = 0; for(CTrackData::trkpt_t& pt : trk) { pt.ele = ele2[cnt++]; } deriveSecondaryData(); changed(tr("Smoothed profile with a Median filter of size %1").arg(points), "://icons/48x48/SetEle.png"); } void CGisItemTrk::filterTerrainSlope() { QPolygonF line; for(const CTrackData::trkpt_t &pt : trk) { line << pt.radPoint(); } QPolygonF slope(line.size()); CMainWindow::self().getSlopeAt(line, slope); int cnt = 0; for(CTrackData::trkpt_t& pt : trk) { pt.extensions[CKnownExtension::internalTerrainSlope] = slope[cnt].ry(); ++cnt; } deriveSecondaryData(); changed(tr("Added terrain slope from DEM file."), "://icons/48x48/CSrcSlope.png"); } void CGisItemTrk::filterReplaceElevation() { QPolygonF line; for(const CTrackData::trkpt_t &pt : trk) { line << pt.radPoint(); } QPolygonF ele(line.size()); CMainWindow::self().getElevationAt(line, ele); int cnt = 0; for(CTrackData::trkpt_t& pt : trk) { pt.ele = (ele[cnt].y() == NOFLOAT) ? NOINT : ele[cnt].y(); ++cnt; } deriveSecondaryData(); changed(tr("Replaced elevation data with data from DEM files."), "://icons/48x48/SetEle.png"); } void CGisItemTrk::filterInterpolateElevation() { if(!interp.valid) { return; } for(CTrackData::trkpt_t& pt : trk) { qreal ele = getElevationInterpolated(pt.distance); pt.ele = (ele == NOFLOAT) ? NOINT : qRound(ele); } interp.valid = false; deriveSecondaryData(); changed(tr("Replaced elevation data with interpolated values. (M=%1, RMSErr=%2)").arg(interp.m).arg(interp.rep.rmserror), "://icons/48x48/SetEle.png"); } void CGisItemTrk::filterOffsetElevation(int offset) { for(CTrackData::trkpt_t& pt : trk) { if(pt.ele != NOINT) { pt.ele += offset; } } QString val, unit; IUnit::self().meter2elevation(offset, val, unit); deriveSecondaryData(); changed(tr("Offset elevation data by %1%2.").arg(val).arg(unit), "://icons/48x48/SetEle.png"); } void CGisItemTrk::filterNewDate(const QDateTime& date) { qint64 delta = qint64(date.toTime_t()) - qint64(timeStart.toUTC().toTime_t()); for(CTrackData::trkpt_t& pt : trk) { pt.time = pt.time.addSecs(delta); } deriveSecondaryData(); changed(tr("Changed start of track to %1.").arg(date.toString()), "://icons/48x48/Time.png"); } void CGisItemTrk::filterObscureDate(int delta) { if(delta == 0) { for(CTrackData::trkpt_t& pt : trk) { pt.time = QDateTime(); } deriveSecondaryData(); changed(tr("Remove timestamps."), "://icons/48x48/Time.png"); } else { QDateTime timestamp = timeStart; if(!timestamp.isValid()) { timestamp = QDateTime::currentDateTime().toUTC(); } for(CTrackData::trkpt_t& pt : trk) { pt.time = timestamp; timestamp = timestamp.addSecs(delta); } deriveSecondaryData(); changed(tr("Set artificial timestamps with delta of %1 sec.").arg(delta), "://icons/48x48/Time.png"); } } void CGisItemTrk::filterSpeed(qreal speed) { QDateTime timestamp = timeStart; if(!timestamp.isValid()) { timestamp = QDateTime::currentDateTime().toUTC(); } for(CTrackData::trkpt_t& pt : trk) { if(pt.isHidden()) { continue; } timestamp = speed == 0 ? QDateTime() : timestamp.addMSecs(qRound(1000 * pt.deltaDistance/speed)); pt.time = timestamp; } deriveSecondaryData(); QString val, unit; IUnit::self().meter2speed(speed, val, unit); changed(tr("Changed speed to %1%2.").arg(val).arg(unit), "://icons/48x48/Time.png"); } void CGisItemTrk::filterSplitSegment() { IGisProject * project = CGisWorkspace::self().selectProject(); if(nullptr == project) { return; } int part = 0; for(const CTrackData::trkseg_t &seg : trk.segs) { if(0 < seg.pts.count()) { qint32 idx1 = seg.pts[ 0].idxTotal; qint32 idx2 = seg.pts[seg.pts.count() - 1].idxTotal; new CGisItemTrk(tr("%1 (Segment %2)").arg(trk.name).arg(part), idx1, idx2, trk, project); ++part; } } } void CGisItemTrk::filterDeleteExtension(const QString &extStr) { for(CTrackData::trkpt_t& pt : trk) { pt.extensions.remove(extStr); } extrema.remove(extStr); existingExtensions.remove(extStr); propHandler->setupData(); const CKnownExtension &ext = CKnownExtension::get(extStr); changed(tr("Removed extension %1 from all Track Points").arg(ext.nameLongText), "://icons/48x48/FilterModifyExtension.png"); } void CGisItemTrk::filterSubPt2Pt() { for(CTrackData::trkpt_t& pt : trk) { pt.unsetFlag(CTrackData::trkpt_t::eSubpt); } propHandler->setupData(); changed(tr("Converted subpoints from routing to track points"), "://icons/48x48/FilterSubPt2Pt.png"); } qmapshack-1.10.0/src/gis/trk/filter/IFilterDouglasPeuker.ui000644 001750 000144 00000006600 12453154213 024752 0ustar00oeichlerxusers000000 000000 IFilterDouglasPeuker 0 0 1001 82 Form 3 0 0 0 3 :/icons/48x48/PointHide.png <b>Hide Points (Douglas Peuker)</b> 3 Hide track points if the distance to a line between neighboring points is less than 0 0 m 1 Qt::Horizontal 40 20 Apply filter now. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal label_2 line label_3 qmapshack-1.10.0/src/gis/trk/filter/CFilterDouglasPeuker.cpp000644 001750 000144 00000003517 13216234137 025117 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterDouglasPeuker.h" #include "helpers/CSettings.h" #include "units/IUnit.h" #include CFilterDouglasPeuker::CFilterDouglasPeuker(CGisItemTrk &trk, QWidget * parent) : QWidget(parent) , trk(trk) { setupUi(this); spinBox->setSuffix(IUnit::self().baseunit); SETTINGS; spinBox->setValue(cfg.value("TrackDetails/Filter/DouglasPeuker/distance",5).toInt()); connect(toolApply, &QToolButton::clicked, this, &CFilterDouglasPeuker::slotApply); } CFilterDouglasPeuker::~CFilterDouglasPeuker() { SETTINGS; cfg.setValue("TrackDetails/Filter/DouglasPeuker/distance", spinBox->value()); } void CFilterDouglasPeuker::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor, "CFilterDouglasPeuker"); trk.filterReducePoints(spinBox->value()/IUnit::self().basefactor); CCanvas::restoreOverrideCursor("CFilterDouglasPeuker"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterNewDate.cpp000644 001750 000144 00000003111 13216234137 023662 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterNewDate.h" CFilterNewDate::CFilterNewDate(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); labelTimeZone->setText(QDateTime::currentDateTime().timeZone().abbreviation(QDateTime::currentDateTime())); dateTimeEdit->setDateTime(QDateTime::currentDateTime()); connect(toolApply, &QToolButton::clicked, this, &CFilterNewDate::slotApply); } void CFilterNewDate::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterNewDate"); trk.filterNewDate(dateTimeEdit->dateTime().toUTC()); CCanvas::restoreOverrideCursor("CFilterNewDate"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterSpeed.cpp000644 001750 000144 00000003361 13216234137 023402 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterSpeed.h" #include "helpers/CSettings.h" #include "units/IUnit.h" CFilterSpeed::CFilterSpeed(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); doubleSpinBox->setSuffix(IUnit::self().speedunit); SETTINGS; doubleSpinBox->setValue(cfg.value("TrackDetails/Filter/Speed/speed",1).toDouble()); connect(toolApply, &QToolButton::clicked, this, &CFilterSpeed::slotApply); } CFilterSpeed::~CFilterSpeed() { SETTINGS; cfg.setValue("TrackDetails/Filter/Speed/speed", doubleSpinBox->value()); } void CFilterSpeed::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor, "CFilterSpeed"); trk.filterSpeed(doubleSpinBox->value()/IUnit::self().speedfactor); CCanvas::restoreOverrideCursor("CFilterSpeed"); } qmapshack-1.10.0/src/gis/trk/filter/IFilterDeleteExtension.ui000644 001750 000144 00000006770 12705713523 025314 0ustar00oeichlerxusers000000 000000 IFilterDeleteExtension 0 0 811 82 Form 3 0 0 0 3 0 0 :/icons/48x48/FilterModifyExtension.png <b>Remove Extension from all Track Points</b> 3 Remove 0 0 QComboBox::AdjustToContents from all Track Points Qt::Horizontal 40 20 ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/CFilterTerrainSlope.h000644 001750 000144 00000002514 13216234143 024412 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERTERRAINSLOPE_H #define CFILTERTERRAINSLOPE_H #include "ui_IFilterTerrainSlope.h" #include class CGisItemTrk; class CFilterTerrainSlope : public QWidget, private Ui::IFilterTerrainSlope { Q_OBJECT public: CFilterTerrainSlope(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterTerrainSlope() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERTERRAINSLOPE_H qmapshack-1.10.0/src/gis/trk/filter/CFilterSubPt2Pt.cpp000644 001750 000144 00000002612 13216234137 023763 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Christian Eichler code@christian-eichler.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterSubPt2Pt.h" CFilterSubPt2Pt::CFilterSubPt2Pt(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterSubPt2Pt::slotApply); } void CFilterSubPt2Pt::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterSubPt2Pt"); trk.filterSubPt2Pt(); CCanvas::restoreOverrideCursor("CFilterSubPt2Pt"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterInterpolateElevation.cpp000644 001750 000144 00000005714 13216234137 026503 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterInterpolateElevation.h" #include "helpers/CSettings.h" CFilterInterpolateElevation::CFilterInterpolateElevation(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); comboQuality->addItem(tr("coarse"), CGisItemTrk::eQualityCoarse); comboQuality->addItem(tr("medium"), CGisItemTrk::eQualityMedium); comboQuality->addItem(tr("fine"), CGisItemTrk::eQualityFine); bool enabled = trk.isInterpolationEnabled(); checkPreview->setChecked(enabled); toolApply->setEnabled(enabled); SETTINGS; comboQuality->setCurrentIndex(comboQuality->findData(cfg.value("TrackDetails/Filter/Interp/quality", CGisItemTrk::eQualityCoarse))); connect(toolApply, &QToolButton::clicked, this, &CFilterInterpolateElevation::slotApply); connect(checkPreview, &QCheckBox::toggled, this, &CFilterInterpolateElevation::slotPreview); connect(comboQuality, static_cast(&QComboBox::currentIndexChanged), this, &CFilterInterpolateElevation::slotPreview); } CFilterInterpolateElevation::~CFilterInterpolateElevation() { SETTINGS; cfg.setValue("TrackDetails/Filter/Interp/quality",comboQuality->currentData()); trk.setupInterpolation(false, CGisItemTrk::eQualityCoarse); } void CFilterInterpolateElevation::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterInterpolateElevation"); trk.filterInterpolateElevation(); checkPreview->setChecked(trk.isInterpolationEnabled()); CCanvas::restoreOverrideCursor("CFilterInterpolateElevation"); } void CFilterInterpolateElevation::slotPreview() { CCanvas::setOverrideCursor(Qt::WaitCursor, "CFilterInterpolateElevation::slotPreview()"); bool yes = checkPreview->isChecked(); qint32 Q = comboQuality->currentData().toInt(); trk.setupInterpolation(yes, Q); yes = trk.isInterpolationEnabled(); checkPreview->setChecked(yes); toolApply->setEnabled(yes); CCanvas::restoreOverrideCursor("CFilterInterpolateElevation::slotPreview()"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterSplitSegment.cpp000644 001750 000144 00000002746 13216234137 024766 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterSplitSegment.h" CFilterSplitSegment::CFilterSplitSegment(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); connect(toolApply, &QToolButton::clicked, this, &CFilterSplitSegment::slotApply); } void CFilterSplitSegment::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor, "CFilterSplitSegment"); trk.filterSplitSegment(); CCanvas::restoreOverrideCursor("CFilterSplitSegment"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterObscureDate.cpp000644 001750 000144 00000003302 13216234137 024535 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/filter/CFilterObscureDate.h" #include "helpers/CSettings.h" CFilterObscureDate::CFilterObscureDate(CGisItemTrk &trk, QWidget *parent) : QWidget(parent) , trk(trk) { setupUi(this); SETTINGS; spinBox->setValue(cfg.value("TrackDetails/Filter/ObscureTimestamp/delta",0).toInt()); connect(toolApply, &QToolButton::clicked, this, &CFilterObscureDate::slotApply); } CFilterObscureDate::~CFilterObscureDate() { SETTINGS; cfg.setValue("TrackDetails/Filter/ObscureTimestamp/delta", spinBox->value()); } void CFilterObscureDate::slotApply() { CCanvas::setOverrideCursor(Qt::WaitCursor,"CFilterObscureDate"); trk.filterObscureDate(spinBox->value()); CCanvas::restoreOverrideCursor("CFilterObscureDate"); } qmapshack-1.10.0/src/gis/trk/filter/CFilterReset.h000644 001750 000144 00000002424 13216234143 023065 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERRESET_H #define CFILTERRESET_H #include "ui_IFilterReset.h" #include class CGisItemTrk; class CFilterReset : public QWidget, private Ui::IFilterReset { Q_OBJECT public: CFilterReset(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterReset() = default; private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERRESET_H qmapshack-1.10.0/src/gis/trk/filter/IFilterReplaceElevation.ui000644 001750 000144 00000005204 12627613666 025440 0ustar00oeichlerxusers000000 000000 IFilterReplaceElevation 0 0 996 69 Form 3 0 0 0 3 0 0 :/icons/48x48/SetEle.png <b>Replace Elevation Data</b> 3 Replace elevation of track points with the values from loaded DEM files. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/IFilterObscureDate.ui000644 001750 000144 00000005763 12453154213 024411 0ustar00oeichlerxusers000000 000000 IFilterObscureDate 0 0 812 58 Form 3 0 0 0 3 :/icons/48x48/Time.png <b>Obscure Timestamps</b> Increase timestamp by sec. with each track point. 0 sec. will remove timestamps. Qt::Horizontal 40 20 ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/IFilterTerrainSlope.ui000644 001750 000144 00000005161 13126360003 024602 0ustar00oeichlerxusers000000 000000 IFilterTerrainSlope 0 0 996 69 Form 3 0 0 0 3 0 0 :/icons/48x48/CSrcSlope.png <b>Calculate Terrain Slope</b> 3 Calculate slope of the terrain based on loaded DEM files. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal qmapshack-1.10.0/src/gis/trk/filter/IFilterSubPt2Pt.ui000644 001750 000144 00000005202 13022217652 023620 0ustar00oeichlerxusers000000 000000 IFilterSubPt2Pt 0 0 787 58 Form 3 0 0 0 3 <b>Convert track subpoints to points</b> 3 Convert subpoints obtained from routing to ordinary track points ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal 0 0 :/icons/48x48/FilterSubPt2Pt.png qmapshack-1.10.0/src/gis/trk/filter/IFilterReset.ui000644 001750 000144 00000005121 12454666535 023277 0ustar00oeichlerxusers000000 000000 IFilterReset 0 0 787 82 Form 3 0 0 0 3 <b>Reset Hidden Track Points</b> 3 Make all trackpoints visible again. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png 22 22 Qt::Horizontal 0 0 :/icons/48x48/PointHide.png qmapshack-1.10.0/src/gis/trk/filter/CFilterSpeed.h000644 001750 000144 00000002412 13216234143 023040 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CFILTERSPEED_H #define CFILTERSPEED_H #include "ui_IFilterSpeed.h" #include class CGisItemTrk; class CFilterSpeed : public QWidget, private Ui::IFilterSpeed { Q_OBJECT public: CFilterSpeed(CGisItemTrk& trk, QWidget * parent); virtual ~CFilterSpeed(); private slots: void slotApply(); private: CGisItemTrk& trk; }; #endif //CFILTERSPEED_H qmapshack-1.10.0/src/gis/trk/CScrOptTrk.cpp000644 001750 000144 00000012613 13216234137 021602 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisWorkspace.h" #include "gis/prj/IGisProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CScrOptTrk.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" CScrOptTrk::CScrOptTrk(CGisItemTrk * trk, const QPoint& point, IMouse *parent) : IScrOpt(parent) , key(trk->getKey()) { setupUi(this); setOrigin(point); label->setFont(CMainWindow::self().getMapFont()); label->setText(trk->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowActivity)); adjustSize(); toolProfile->setChecked(trk->hasUserFocus()); bool isOnDevice = trk->isOnDevice(); toolCut->setDisabled(isOnDevice); toolEdit->setDisabled(isOnDevice); toolReverse->setDisabled(isOnDevice); toolRange->setDisabled(isOnDevice); toolCopyWithWpt->setEnabled(trk->getNumberOfAttachedWpt() != 0); IGisProject * project = trk->getParentProject(); if(project != nullptr) { toolCombine->setEnabled(project->getItemCountByType(IGisItem::eTypeTrk) > 1); } anchor = trk->getPointCloseBy(point); if((anchor - point).manhattanLength() > 50) { anchor = point; toolCut->setEnabled(false); } move(anchor.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolDelete, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolCopy, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolProfile, &QToolButton::toggled, this, &CScrOptTrk::hide); connect(toolCut, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolEdit, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolReverse, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolCombine, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolRange, &QToolButton::clicked, this, &CScrOptTrk::hide); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptTrk::slotEditDetails); connect(toolDelete, &QToolButton::clicked, this, &CScrOptTrk::slotDelete); connect(toolCopy, &QToolButton::clicked, this, &CScrOptTrk::slotCopy); connect(toolProfile, &QToolButton::toggled, this, &CScrOptTrk::slotProfile); connect(toolCut, &QToolButton::clicked, this, &CScrOptTrk::slotCut); connect(toolEdit, &QToolButton::clicked, this, &CScrOptTrk::slotEdit); connect(toolReverse, &QToolButton::clicked, this, &CScrOptTrk::slotReverse); connect(toolCombine, &QToolButton::clicked, this, &CScrOptTrk::slotCombine); connect(toolRange, &QToolButton::clicked, this, &CScrOptTrk::slotRange); connect(toolActivity, &QToolButton::clicked, this, &CScrOptTrk::slotActivity); connect(toolCopyWithWpt, &QToolButton::clicked, this, &CScrOptTrk::slotCopyWithWpt); // reset user focus if the track has it trk->setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CScrOptTrk"); trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseClick, "CScrOptTrk"); } CScrOptTrk::~CScrOptTrk() { } void CScrOptTrk::slotDelete() { CGisWorkspace::self().delItemByKey(key); deleteLater(); } void CScrOptTrk::slotCopy() { CGisWorkspace::self().copyItemByKey(key); deleteLater(); } void CScrOptTrk::slotEditDetails() { CGisWorkspace::self().editItemByKey(key); deleteLater(); } void CScrOptTrk::slotProfile(bool on) { CGisWorkspace::self().focusTrkByKey(on, key); deleteLater(); } void CScrOptTrk::slotCut() { CGisWorkspace::self().cutTrkByKey(key); deleteLater(); } void CScrOptTrk::slotEdit() { CGisWorkspace::self().editTrkByKey(key); deleteLater(); } void CScrOptTrk::slotReverse() { CGisWorkspace::self().reverseTrkByKey(key); deleteLater(); } void CScrOptTrk::slotCombine() { CGisWorkspace::self().combineTrkByKey(key); deleteLater(); } void CScrOptTrk::slotRange() { CGisWorkspace::self().rangeTrkByKey(key); deleteLater(); } void CScrOptTrk::slotActivity() { QList keys; keys << key; CGisWorkspace::self().activityTrkByKey(keys); deleteLater(); } void CScrOptTrk::slotCopyWithWpt() { CGisWorkspace::self().copyTrkWithWptByKey(key); deleteLater(); } void CScrOptTrk::draw(QPainter& p) { IGisItem * item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { QWidget::deleteLater(); return; } item->drawHighlight(p); CDraw::bubble(p, geometry(), anchor.toPoint()); } qmapshack-1.10.0/src/gis/trk/ICombineTrk.ui000644 001750 000144 00000016744 13052513756 021623 0ustar00oeichlerxusers000000 000000 ICombineTrk 0 0 571 374 Combine Tracks... Available Tracks Qt::Vertical 20 40 false ... :/icons/32x32/Right.png:/icons/32x32/Right.png Qt::Vertical 20 40 false ... :/icons/32x32/Left.png:/icons/32x32/Left.png Qt::Vertical 20 40 Combined Tracks Qt::Vertical 20 40 false ... :/icons/32x32/Up.png:/icons/32x32/Up.png Qt::Vertical 20 40 false ... :/icons/32x32/Down.png:/icons/32x32/Down.png Qt::Vertical 20 40 Qt::Horizontal 40 20 150 150 Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok CPlotTrack QWidget
plot/CPlotTrack.h
1
buttonBox accepted() ICombineTrk accept() 248 254 157 274 buttonBox rejected() ICombineTrk reject() 316 260 286 274
qmapshack-1.10.0/src/gis/trk/CScrOptTrk.h000644 001750 000144 00000003162 13216234143 021243 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTTRK_H #define CSCROPTTRK_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptTrk.h" class CGisItemTrk; class IMouse; class CScrOptTrk : public IScrOpt, private Ui::IScrOptTrk { Q_OBJECT public: CScrOptTrk(CGisItemTrk * trk, const QPoint &point, IMouse *parent); virtual ~CScrOptTrk(); void draw(QPainter& p) override; private slots: void slotDelete(); void slotCopy(); void slotEditDetails(); void slotProfile(bool on); void slotCut(); void slotEdit(); void slotReverse(); void slotCombine(); void slotRange(); void slotActivity(); void slotCopyWithWpt(); private: IGisItem::key_t key; QPointF anchor; }; #endif //CSCROPTTRK_H qmapshack-1.10.0/src/gis/trk/CCombineTrk.h000644 001750 000144 00000002725 13216234143 021411 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCOMBINETRK_H #define CCOMBINETRK_H #include "gis/IGisItem.h" #include "ui_ICombineTrk.h" #include class CCombineTrk : public QDialog, private Ui::ICombineTrk { Q_OBJECT public: CCombineTrk(const QList &keys, const QList &keysPreSel, QWidget * parent); virtual ~CCombineTrk(); public slots: void accept() override; private slots: void slotSelectionChanged(); void slotSelect(); void slotRemove(); void slotUp(); void slotDown(); private: void updatePreview(); }; #endif //CCOMBINETRK_H qmapshack-1.10.0/src/gis/trk/CDetailsTrk.h000644 001750 000144 00000007070 13216234143 021420 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSTRK_H #define CDETAILSTRK_H #include "gis/trk/CGisItemTrk.h" #include "helpers/CLimit.h" #include "ui_IDetailsTrk.h" #include class CPlot; class CPlotProfile; class CDetailsTrk : public QWidget, public INotifyTrk, private Ui::IDetailsTrk { Q_OBJECT public: CDetailsTrk(CGisItemTrk &trk, QWidget * parent); virtual ~CDetailsTrk(); void setMouseFocus(const CTrackData::trkpt_t *pt) override; void setMouseRangeFocus(const CTrackData::trkpt_t *pt1, const CTrackData::trkpt_t *pt2) override; void setMouseClickFocus(const CTrackData::trkpt_t *pt) override; public slots: void updateData() override; private slots: void slotNameChanged(const QString &name); void slotNameChangeFinished(); void slotShowPlots(); void slotColorChanged(int idx); void slotChangeReadOnlyMode(bool on); void slotLinkActivated(const QUrl& url); void slotMouseClickState(int); void slotSetActivities(); void slotColorSourceChanged(int idx); void slotColorLimitHighChanged(); void slotColorLimitLowChanged(); void slotSetupGraph(int idx); void slotSetLimitModeGraph(CLimit::mode_e mode, CLimit *limit, QDoubleSpinBox *spinMin, QDoubleSpinBox *spinMax, bool on); void slotSetLimitModeStyle(CLimit::mode_e mode, bool on); void slotLineWidthMode(bool isUser); void slotLineWidth(qreal f); void slotWithArrowsMode(bool isUser); void slotWithArrows(bool yes); private: void loadGraphSource(QComboBox * comboBox, qint32 n, const QString cfgDefault); void saveGraphSource(QComboBox * comboBox, qint32 n); void setupGraphLimits(CLimit& limit, QToolButton * toolLimitAutoGraph, QToolButton * toolLimitUsrGraph, QToolButton * toolLimitSysGraph, QDoubleSpinBox * spinMinGraph, QDoubleSpinBox * spinMaxGraph); void setupStyleLimits(CLimit& limit, QToolButton *toolLimitAuto, QToolButton *toolLimitUsr, QToolButton *toolLimitSys, CDoubleSpinBox *spinMin, CDoubleSpinBox *spinMax); void setupGraph(CPlot * plot, const CLimit &limit, const QString& source, QDoubleSpinBox * spinMin, QDoubleSpinBox * spinMax); void setupLimits(CLimit *limit, QDoubleSpinBox * spinMin, QDoubleSpinBox * spinMax); enum tabs_t { eTabInfo ,eTabStyle ,eTabGraphs ,eTabActivity ,eTabPoints ,eTabFilter ,eTabHistory }; /** @brief Pointer to track item It is ok to store the pointer as this widget is created by the track item. The track item will destroy this object on it's own destruction. */ CGisItemTrk& trk; bool originator = false; CPlotProfile * plot1; CPlot * plot2; CPlot * plot3; }; #endif //CDETAILSTRK_H qmapshack-1.10.0/src/gis/slf/000755 001750 000144 00000000000 13216664445 017072 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/slf/CSlfProject.h000644 001750 000144 00000002734 13216234143 021413 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CSLFPROJECT_H #define CSLFPROJECT_H #include "gis/prj/IGisProject.h" class CSlfProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CSlfProject) public: CSlfProject(const QString &filename, bool readFile = true); virtual ~CSlfProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterSLF; } const QString getFileExtension() const override { return "slf"; } private: void loadSlf(const QString &filename); friend class CSlfReader; }; #endif // CSLFPROJECT_H qmapshack-1.10.0/src/gis/slf/CSlfReader.h000644 001750 000144 00000004457 13216234143 021213 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef CSLFREADER_H #define CSLFREADER_H #include #include #include #include "gis/prj/IGisProject.h" class CSlfProject; class CSlfReader { Q_DECLARE_TR_FUNCTIONS(CSlfReader) public: static void readFile(const QString &file, CSlfProject *proj); private: CSlfReader(const QString &filename, CSlfProject *proj); void readMarkers(const QDomNode& xml); void readEntries(const QDomNode& xml); void readMetadata(const QDomNode& xml, IGisProject::metadata_t& metadata); /** @brief Search for attributes that are not 0-only. Sigma Data Center even stores non-used values (as 0) within the .slf file. As we do not want to include those 0-only values as extensions, we need to search for used attributes first. @param xmlEntrs List of nodes @return Set of used attributes */ QSet findUsedAttributes(const QDomNodeList &xmlEntrs); static QDateTime parseTimestamp(const QString &ts); CSlfProject *proj = nullptr; //< the resulting project after construction QDateTime baseTime; //< the time all entries refer to QList offsetsTime; //< an additional offset, required to take breaks into account QList laps; //< the distances a new lap starts at (a lap is a .slf segment) static const QHash attrToExt; }; #endif // CSLFREADER_H qmapshack-1.10.0/src/gis/slf/CSlfReader.cpp000644 001750 000144 00000021744 13216234137 021547 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de 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 "gis/slf/CSlfReader.h" #include #include #include #include #include #include "gis/slf/CSlfProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" // .slf does not know extensions, but we are using them internally. // This makes saving as .gpx easy and conforms to the internal way of doing // things. const QHash CSlfReader::attrToExt = { {"temperature", "gpxtpx:TrackPointExtension|gpxtpx:atemp"}, {"heartrate", "gpxtpx:TrackPointExtension|gpxtpx:hr" }, {"cadence", "gpxtpx:TrackPointExtension|gpxtpx:cad" }, {"speed", "speed"} }; void CSlfReader::readFile(const QString &file, CSlfProject *proj) { CSlfReader reader(file, proj); } QDateTime CSlfReader::parseTimestamp(const QString &ts) { int posOfGMT = ts.indexOf("GMT"); int deltaGMT = 0; if(' ' != ts[posOfGMT + 3]) { QString deltaGMTStr = ts.mid(posOfGMT + 3); QTextStream(&deltaGMTStr) >> deltaGMT; } QString pts = ts.left(posOfGMT - 1) + ts.mid(posOfGMT + 8); QLocale locale(QLocale::C); const QDateTime &baseTime = locale.toDateTime(pts, "ddd MMM d HH:mm:ss yyyy"); if(!baseTime.isValid()) { throw tr("Failed to parse timestamp `%1`").arg(ts); } return baseTime.addSecs( (deltaGMT / 100) * 60 * 60 ); } CSlfReader::CSlfReader(const QString &filename, CSlfProject *proj) : proj(proj) { QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if(!file.exists()) { throw tr("%1 does not exist").arg(filename); } if(!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open %1").arg(filename); } // load file content to xml document QDomDocument xml; QString msg; int line; int column; if(!xml.setContent(&file, false, &msg, &line, &column)) { file.close(); throw tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg); } file.close(); QDomElement xmlAct = xml.documentElement(); if(xmlAct.tagName() != "Activity") { throw tr("Not a SLF file: %1").arg(filename); } // Ensure we only open files with the correct version (only revision 400 supported atm) const int revision = xmlAct.attributes().namedItem("revision").nodeValue().toInt(); if(400 != revision) { throw tr("Unsupported revision %1: %2").arg(revision).arg(filename); } // Parse the file's dateCode // This is a crucial step, as all the other timestamps are relative to this one const QString &dateCode = xmlAct.namedItem("Computer").attributes().namedItem("dateCode").nodeValue(); baseTime = parseTimestamp(dateCode); const QDomNode& xmlGI = xmlAct.namedItem("GeneralInformation"); if(xmlGI.isElement()) { readMetadata(xmlGI, proj->metadata); } // Read all the Markers // This needs to be done prior to reading the Entries, as they contain the // locations at which we need to split the track into segments readMarkers(xmlAct.namedItem("Markers")); // Now read the "Entries" // Entries are the actual waypoints, which make up the track(s) readEntries(xmlAct.namedItem("Entries")); } void CSlfReader::readMarkers(const QDomNode& xml) { const QDomNodeList& xmlMrks = xml.childNodes(); long markerTimeSum = 0; // iterate over all markers and add them to a QMap (this will sort them by timeAbsolute) QMap markers; for(int i = 0; i < xmlMrks.count(); i++) { const QDomNode &marker = xmlMrks.item(i); const QDomNamedNodeMap& attr = marker.attributes(); long time = attr.namedItem("timeAbsolute").nodeValue().toLong(); markers.insert(time, marker); } offsetsTime.append(0); for(const QDomNode &marker : markers) { const QDomNamedNodeMap& attr = marker.attributes(); bool ok; long markerTime = attr.namedItem("duration").nodeValue().toLong(&ok); if(ok) { markerTimeSum += markerTime; } // type="l" indicates a marker, which is used to separate two laps const QString &type = attr.namedItem("type").nodeValue(); if("l" == type || "p" == type) { // filter out duplicate (and invalid) laps long time = attr.namedItem("timeAbsolute").nodeValue().toLong(); if(laps.isEmpty() || (laps.last() < time)) { laps.append(time); offsetsTime.append(markerTimeSum); } } if("p" == type || "l" == type) { qreal lat = attr.namedItem("latitude" ).nodeValue().toDouble(); qreal lon = attr.namedItem("longitude").nodeValue().toDouble(); QString name = attr.namedItem("title").nodeValue(); if(name.isEmpty()) { if("p" == type) { name = tr("Break %1").arg(attr.namedItem("number").nodeValue()); } if("l" == type) { name = tr("Lap %1").arg(attr.namedItem("number").nodeValue()); } } qreal ele = attr.namedItem("altitude").nodeValue().toDouble() / 1000.; const QDateTime &time = baseTime.addSecs(attr.namedItem("timeAbsolute").nodeValue().toDouble() / 100.); new CGisItemWpt(QPointF(lon, lat), ele, time, name, "", proj); } } // the last lap ends at positive infinite laps.append(std::numeric_limits::max()); } QSet CSlfReader::findUsedAttributes(const QDomNodeList &xmlEntrs) { QSet usedAttr; for(int i = 0; i < xmlEntrs.count(); i++) { const QDomNamedNodeMap &attr = xmlEntrs.item(i).attributes(); for(const QString &key : attrToExt.keys()) { if(attr.contains(key) && ("0" != attr.namedItem(key).nodeValue())) { usedAttr.insert(key); } } } return usedAttr; } void CSlfReader::readEntries(const QDomNode& xml) { const QDomNodeList& xmlEntrs = xml.childNodes(); QSet usedAttr = findUsedAttributes(xmlEntrs); // Now generate the track / segments int lap = 0; CTrackData trk; trk.segs.resize(laps.count() + 1); CTrackData::trkseg_t *seg = &(trk.segs[0]); long breakTime = offsetsTime[0]; qreal prevLon = NOFLOAT; qreal prevLat = NOFLOAT; for(int i = 0; i < xmlEntrs.count(); i++) { CTrackData::trkpt_t trkpt; const QDomNamedNodeMap& attr = xmlEntrs.item(i).attributes(); trkpt.lat = attr.namedItem("latitude" ).nodeValue().toDouble(); trkpt.lon = attr.namedItem("longitude").nodeValue().toDouble(); if((0. == trkpt.lat && 0. == trkpt.lon) || (prevLat == trkpt.lat && prevLon == trkpt.lon)) { continue; } prevLat = trkpt.lat; prevLon = trkpt.lon; trkpt.ele = attr.namedItem("altitude" ).nodeValue().toDouble() / 1000.; for(const QString &key : usedAttr) { if(attr.contains(key) && attrToExt.contains(key)) { trkpt.extensions[attrToExt[key]] = attr.namedItem(key).nodeValue().toDouble(); } } const long trainingTime = attr.namedItem("trainingTimeAbsolute").nodeValue().toLong(); while(trainingTime > laps[lap]) { lap++; seg = &(trk.segs[lap]); breakTime = offsetsTime[lap]; } trkpt.time = baseTime.addSecs( (breakTime + trainingTime) / 100.); seg->pts.append(trkpt); } trk.name = proj->metadata.name; new CGisItemTrk(trk, proj); proj->updateItemCounters(); } void CSlfReader::readMetadata(const QDomNode& xml, IGisProject::metadata_t& metadata) { metadata.name = xml.namedItem("name" ).firstChild().nodeValue(); metadata.desc = xml.namedItem("description").firstChild().nodeValue(); metadata.keywords = xml.namedItem("sport" ).firstChild().nodeValue(); } qmapshack-1.10.0/src/gis/slf/CSlfProject.cpp000644 001750 000144 00000003515 13216234137 021747 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Christian Eichler code@christian-eichler.de 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/slf/CSlfProject.h" #include "gis/slf/CSlfReader.h" #include CSlfProject::CSlfProject(const QString &filename, bool readFile) : IGisProject(eTypeSlf, filename, (CGisListWks*)nullptr) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/SlfProject.png")); blockUpdateItems(true); valid = true; if(readFile) { try { CSlfReader::readFile(filename, this); } catch(QString &errormsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); valid = false; } } else { IGisProject::filename.clear(); } sortItems(); blockUpdateItems(false); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); } qmapshack-1.10.0/src/gis/prj/000755 001750 000144 00000000000 13216664445 017101 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/prj/IGisProject.cpp000644 001750 000144 00000071754 13216234261 021772 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "device/IDevice.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/CGisWorkspace.h" #include "gis/IGisItem.h" #include "gis/fit/CFitProject.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/CDetailsPrj.h" #include "gis/prj/IGisProject.h" #include "gis/qlb/CQlbProject.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/IRouter.h" #include "gis/slf/CSlfProject.h" #include "gis/suunto/CLogProject.h" #include "gis/suunto/CSmlProject.h" #include "gis/tcx/CTcxProject.h" #include "gis/tcx/CTcxProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include "helpers/CSelectCopyAction.h" #include "helpers/CSettings.h" #include const QString IGisProject::filedialogAllSupported = "All Supported (*.gpx *.GPX *.tcx *.TCX *.sml *.log *.qms *.qlb *.slf *.fit)"; const QString IGisProject::filedialogFilterGPX = "GPS Exchange Format (*.gpx *.GPX)"; const QString IGisProject::filedialogFilterTCX = "TCX Garmin Proprietary (*.tcx *.TCX)"; const QString IGisProject::filedialogFilterSML = "Suunto XML format (*.sml)"; const QString IGisProject::filedialogFilterLOG = "Openambit XML format (*.log)"; const QString IGisProject::filedialogFilterQLB = "QLandkarte Binary (*.qlb)"; const QString IGisProject::filedialogFilterQMS = "QMapShack Binary (*.qms)"; const QString IGisProject::filedialogFilterSLF = "Sigma Log Format (*.slf)"; const QString IGisProject::filedialogFilterFIT = "Garmin FIT Format (*.fit)"; const QString IGisProject::filedialogSaveFilters = filedialogFilterGPX + ";; " + filedialogFilterQLB + ";; " + filedialogFilterQMS + ";; " + filedialogFilterTCX; const QString IGisProject::filedialogLoadFilters = filedialogAllSupported + ";; " + filedialogFilterGPX + ";; " + filedialogFilterTCX + ";; " + filedialogFilterSML + ";; " + filedialogFilterLOG + ";; " + filedialogFilterQLB + ";; " + filedialogFilterQMS + ";; " + filedialogFilterSLF + ";; " + filedialogFilterFIT; IGisProject::filter_mode_e IGisProject::filterMode = IGisProject::eFilterModeName; IGisProject::IGisProject(type_e type, const QString &filename, CGisListWks *parent) : QTreeWidgetItem(parent) , type(type) , filename(filename) { memset(cntItemsByType, 0, sizeof(cntItemsByType)); setCheckState(CGisListWks::eColumnCheckBox, Qt::Checked); if(parent) { // move project up the list until there a re only projects, no devices int newIdx = NOIDX; const int myIdx = parent->topLevelItemCount() - 1; for(int i = myIdx - 1; i >= 0; i--) { IDevice * device = dynamic_cast(parent->topLevelItem(i)); if(device != nullptr) { newIdx = i; continue; } break; } if(newIdx != NOIDX) { parent->takeTopLevelItem(myIdx); parent->insertTopLevelItem(newIdx, this); } } } IGisProject::IGisProject(type_e type, const QString &filename, IDevice *parent) : QTreeWidgetItem(parent) , type(type) , filename(filename) { memset(cntItemsByType, 0, sizeof(cntItemsByType)); setCheckState(CGisListWks::eColumnCheckBox, Qt::Checked); nameSuffix = parent->getName(); } IGisProject::~IGisProject() { delete dlgDetails; } IGisProject * IGisProject::create(const QString filename, CGisListWks * parent) { IGisProject *item = nullptr; QString suffix = QFileInfo(filename).suffix().toLower(); if(suffix == "gpx") { item = new CGpxProject(filename, parent); } else if(suffix == "qms") { item = new CQmsProject(filename, parent); } else if(suffix == "slf") { item = new CSlfProject(filename); // the CSlfProject does not - as the other C*Project - register itself in the list // of currently opened projects. This is done manually here. if(parent) { parent->addProject(item); } } else if(suffix == "fit") { item = new CFitProject(filename, parent); } else if(suffix == "tcx") { item = new CTcxProject(filename, parent); } else if (suffix == "sml") { item = new CSmlProject(filename, parent); } else if (suffix == "log") { item = new CLogProject(filename, parent); } else if (suffix == "qlb") { item = new CQlbProject(filename, parent); } if(item && !item->isValid()) { delete item; item = nullptr; } return item; } QString IGisProject::html2Dev(const QString& str) { return isOnDevice() == IDevice::eTypeGarmin ? IGisItem::removeHtml(str) : str; } bool IGisProject::askBeforClose() { int res = QMessageBox::Ok; if(isChanged()) { CCanvas::setOverrideCursor(Qt::ArrowCursor, "askBeforClose"); res = QMessageBox::question(CMainWindow::getBestWidgetForParent(), tr("Save project?"), tr("

%1

The project was changed. Save before closing it?").arg(getName()), QMessageBox::Save|QMessageBox::No|QMessageBox::Abort, QMessageBox::No); CCanvas::restoreOverrideCursor("askBeforClose"); if(res == QMessageBox::Save) { // some project cannot be saved if(canSave()) { save(); } else { saveAs(); } } } return res == QMessageBox::Abort; } bool IGisProject::isVisible() const { return checkState(CGisListWks::eColumnCheckBox) == Qt::Checked; } void IGisProject::genKey() const { if(key.isEmpty()) { QByteArray buffer; QDataStream stream(&buffer, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this >> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(buffer); key = md5.result().toHex(); } } QString IGisProject::getDeviceKey() const { IDevice * device = dynamic_cast(parent()); if(device) { return device->getKey(); } return ""; } QPixmap IGisProject::getIcon() const { return icon(CGisListWks::eColumnIcon).pixmap(22,22); } qint32 IGisProject::isOnDevice() const { IDevice * device = dynamic_cast(parent()); return device != nullptr ? device->type() : IDevice::eTypeNone; } bool IGisProject::isChanged() const { return text(CGisListWks::eColumnDecoration) == "*"; } void IGisProject::edit() { if(dlgDetails.isNull()) { dlgDetails = new CDetailsPrj(*this, 0); dlgDetails->setObjectName(getName()); } CMainWindow::self().addWidgetToTab(dlgDetails); } void IGisProject::setName(const QString& str) { metadata.name = str; setText(CGisListWks::eColumnName, getNameEx()); setChanged(); } void IGisProject::setKeywords(const QString& str) { metadata.keywords = str; setChanged(); } void IGisProject::setDescription(const QString& str) { metadata.desc = str; setChanged(); } void IGisProject::setLinks(const QList& links) { metadata.links = links; setChanged(); } void IGisProject::setSortingRoadbook(sorting_roadbook_e s) { changedRoadbookMode = (s != sortingRoadbook); sortingRoadbook = s; if(changedRoadbookMode) { setChanged(); } } void IGisProject::setSortingFolder(sorting_folder_e s) { bool changed = (s != sortingFolder); sortingFolder = s; sortItems(); if(changed) { setChanged(); if(dlgDetails != nullptr) { dlgDetails->updateData(); } } } void IGisProject::setChanged() { if(autoSave) { setText(CGisListWks::eColumnDecoration,"A"); if(!autoSavePending) { autoSavePending = true; CGisWorkspace::self().postEventForWks(new CEvtA2WSave(getKey())); } } else { setText(CGisListWks::eColumnDecoration,"*"); } updateItems(); } void IGisProject::setAutoSave(bool on) { // make sure project is saved one more time to remove autoSave flag in storage if(!on && autoSave) { CGisWorkspace::self().postEventForWks(new CEvtA2WSave(getKey())); } autoSave = on; setChanged(); } void IGisProject::switchOnCorrelation() { noCorrelation = false; hashTrkWpt[0].clear(); hashTrkWpt[1].clear(); updateItems(); } void IGisProject::updateItems() { if(noUpdate) { return; } sortItems(); updateItemCounters(); if(noCorrelation) { return; } if(!changedRoadbookMode) { if((hashTrkWpt[0] == hashTrkWpt[1]) || (getItemCountByType(IGisItem::eTypeTrk) == 0)) { return; } } changedRoadbookMode = false; quint32 total = cntTrkPts * cntWpts; quint32 current = 0; PROGRESS_SETUP(tr("%1: Correlate tracks and waypoints.").arg(getName()), 0, total, CMainWindow::getBestWidgetForParent()); for(int i = 0; i < childCount(); i++) { CGisItemTrk * trk = dynamic_cast(child(i)); if(trk) { trk->findWaypointsCloseBy(progress, current); if(progress.wasCanceled()) { QString msg = tr("

%1

Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project in the future?").arg(getNameEx()); int res = QMessageBox::question(&progress, tr("Canceled correlation..."), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); noCorrelation = res == QMessageBox::Yes; break; } } } if(dlgDetails != nullptr) { dlgDetails->updateData(); } } bool IGisProject::save() { if(!canSave()) { qWarning() << "This should never be called!"; return false; } return saveAs(filename, getFileDialogFilter()); } bool IGisProject::saveAs(QString fn, QString filter) { SETTINGS; if(fn.isEmpty()) { QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString(); // guess the correct extension: // by default use the extension provided by the current format, // otherwise use gpx QString ext = getFileExtension(); filter = getFileDialogFilter(); if(ext.isEmpty() || !canSave()) { ext = "gpx"; filter = IGisProject::filedialogFilterGPX; } path += "/" + getName() + "." + ext; fn = QFileDialog::getSaveFileName(CMainWindow::getBestWidgetForParent(), tr("Save \"%1\" to...").arg(getName()), path, filedialogSaveFilters, &filter); if(fn.isEmpty()) { return false; } } bool res = false; if(filter == getFileDialogFilter()) { filename = fn; setupName(QFileInfo(fn).completeBaseName()); } if(filter == filedialogFilterGPX) { res = CGpxProject::saveAs(fn, *this, false); } else if(filter == filedialogFilterQMS) { res = CQmsProject::saveAs(fn, *this); } else if (filter == filedialogFilterTCX) { res = CTcxProject::saveAs(fn, *this); } else { return false; } if(res && filter == getFileDialogFilter()) { markAsSaved(); } QString path = QFileInfo(fn).absolutePath(); cfg.setValue("Paths/lastGisPath", path); return res; } bool IGisProject::saveAsStrictGpx11() { SETTINGS; QString fn; QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString(); // guess the correct extension: // by default use the extension provided by the current format, // otherwise use gpx QString ext = "gpx"; QString filter = IGisProject::filedialogFilterGPX; path += "/" + getName() + "." + ext; fn = QFileDialog::getSaveFileName(CMainWindow::getBestWidgetForParent(), tr("Save \"%1\" to...").arg(getName()), path, "Strict GPX V 1.1 (*.gpx *.GPX)", &filter); if(fn.isEmpty()) { return false; } bool res = CGpxProject::saveAs(fn, *this, true); path = QFileInfo(fn).absolutePath(); cfg.setValue("Paths/lastGisPath", path); return res; } void IGisProject::setupName(const QString &defaultName) { if(metadata.name.isEmpty()) { metadata.name = defaultName; } setText(CGisListWks::eColumnName, getName()); } void IGisProject::markAsSaved() { setText(CGisListWks::eColumnDecoration,autoSave ? "A" : ""); for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } item->updateDecoration(IGisItem::eMarkNone, IGisItem::eMarkChanged); } } QString IGisProject::getName() const { return metadata.name; } QString IGisProject::getNameEx() const { if(nameSuffix.isEmpty()) { return metadata.name; } else { return metadata.name + " @ " + nameSuffix; } } QString IGisProject::getInfo() const { QString str = metadata.name.isEmpty() ? text(CGisListWks::eColumnName) : metadata.name; str = "
" + str + "
"; if(metadata.time.isValid()) { str += "
\n"; str += IUnit::datetime2string(metadata.time, false); } QString desc = IGisItem::removeHtml(metadata.desc).simplified(); if(!desc.isEmpty()) { str += "
\n"; if(desc.count() < 100) { str += desc; } else { str += desc.left(97) + "..."; } } if(!filename.isEmpty()) { str += tr("
\nFilename: %1").arg(filename); } if(cntItemsByType[IGisItem::eTypeWpt]) { str += "
\n" + tr("Waypoints: %1").arg(cntItemsByType[IGisItem::eTypeWpt]); } if(cntItemsByType[IGisItem::eTypeTrk]) { str += "
\n" + tr("Tracks: %1").arg(cntItemsByType[IGisItem::eTypeTrk]); } if(cntItemsByType[IGisItem::eTypeRte]) { str += "
\n" + tr("Routes: %1").arg(cntItemsByType[IGisItem::eTypeRte]); } if(cntItemsByType[IGisItem::eTypeOvl]) { str += "
\n" + tr("Areas: %1").arg(cntItemsByType[IGisItem::eTypeOvl]); } return str; } IGisItem * IGisProject::getItemByKey(const IGisItem::key_t& key) { for(int i = 0; i < childCount(); i++) { IGisItem *item = dynamic_cast(child(i)); if(nullptr == item) { continue; } if(item->getKey() == key) { return item; } } return nullptr; } void IGisProject::getItemsByKeys(const QList& keys, QList& items) { for(int i = 0; i < childCount(); i++) { IGisItem *item = dynamic_cast(child(i)); if(nullptr == item) { continue; } if(keys.contains(item->getKey())) { items << item; } } } void IGisProject::getItemsByPos(const QPointF& pos, QList &items) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } if(item->isCloseTo(pos)) { items << item; } } } void IGisProject::getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } if(item->isWithin(area, flags)) { items << item; } } } void IGisProject::getNogoAreas(QVector &areas) const { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { CGisItemWpt * item = dynamic_cast(child(i)); if(nullptr != item && !item->isHidden() && item->isNogoArea()) { const qreal& rad = item->getProximity(); if (rad != NOFLOAT && rad > 0.) { const QPointF& pos = item->getPosition(); areas << IRouter::circle_t(pos.y(),pos.x(),rad); } } } } void IGisProject::mouseMove(const QPointF& pos) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } item->mouseMove(pos); } } bool IGisProject::delItemByKey(const IGisItem::key_t& key, QMessageBox::StandardButtons& last) { for(int i = childCount(); i > 0; i--) { IGisItem * item = dynamic_cast(child(i-1)); if(nullptr == item ) { continue; } if(item->getKey() == key) { if(last != QMessageBox::YesToAll) { QString msg = tr("Are you sure you want to delete '%1' from project '%2'?").arg(item->getName()).arg(text(CGisListWks::eColumnName)); last = QMessageBox::question(CMainWindow::getBestWidgetForParent(), tr("Delete..."), msg, QMessageBox::YesToAll|QMessageBox::Cancel|QMessageBox::Ok|QMessageBox::No, QMessageBox::Ok); if((last == QMessageBox::No) || (last == QMessageBox::Cancel)) { // as each item in the project has to be unique, we can stop searching. return false; } } delete item; /* Database projects are a bit different. Deleting an item does not really mean the project is changed as the item is still stored in the database. */ if(type != eTypeDb) { setChanged(); } // as each item in the project has to be unique, we can stop searching. return true; } } return false; } void IGisProject::editItemByKey(const IGisItem::key_t& key) { for(int i = childCount(); i > 0; i--) { IGisItem * item = dynamic_cast(child(i-1)); if(nullptr == item) { continue; } if(item->getKey() == key) { item->edit(); } } } void IGisProject::insertCopyOfItem(IGisItem * item, int off, int& lastResult) { bool clone = false; IGisItem::key_t key = item->getKey(); key.project = getKey(); key.device = getDeviceKey(); IGisItem * item2 = getItemByKey(key); if(item2 != nullptr) { int result = lastResult; if(lastResult == CSelectCopyAction::eResultNone) { CSelectCopyAction dlg(item, item2, CMainWindow::getBestWidgetForParent()); dlg.exec(); result = dlg.getResult(); if(dlg.allOthersToo()) { lastResult = result; } } if(result == CSelectCopyAction::eResultSkip) { return; } if(result == CSelectCopyAction::eResultNone) { return; } if(result == CSelectCopyAction::eResultClone) { clone = true; } else { // replace item2 with item if(item != item2) { delete item2; } else { // replacing an item with itself does not make sense return; } } } switch(item->type()) { case IGisItem::eTypeTrk: { CGisItemTrk * trk = dynamic_cast(item); if(trk != nullptr) { CGisItemTrk * newTrk = new CGisItemTrk(*trk, this, off, clone); // if the track is on a device, remove hidden trackpoints if(isOnDevice()) { newTrk->filterDelete(); } } break; } case IGisItem::eTypeWpt: { CGisItemWpt * wpt = dynamic_cast(item); if(wpt != nullptr) { new CGisItemWpt(*wpt, this, off, clone); } break; } case IGisItem::eTypeRte: { CGisItemRte * rte = dynamic_cast(item); if(rte != nullptr) { new CGisItemRte(*rte, this, off, clone); } break; } case IGisItem::eTypeOvl: { CGisItemOvlArea * area = dynamic_cast(item); if(area != nullptr) { new CGisItemOvlArea(*area, this, off, clone); } break; } } } void IGisProject::drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { if(gis->needsRedraw()) { break; } IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } item->drawItem(p, viewport, blockedAreas, gis); } } void IGisProject::drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } item->drawItem(p, viewport, gis); } } void IGisProject::drawLabel(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) { if(!isVisible()) { return; } for(int i = 0; i < childCount(); i++) { if(gis->needsRedraw()) { break; } IGisItem * item = dynamic_cast(child(i)); if(nullptr == item || item->isHidden()) { continue; } item->drawLabel(p, viewport, blockedAreas, fm, gis); } } void IGisProject::mount() { if(!isOnDevice()) { return; } IDevice * device = dynamic_cast(parent()); if(device) { device->mount(); } } void IGisProject::umount() { if(!isOnDevice()) { return; } IDevice * device = dynamic_cast(parent()); if(device) { device->umount(); } } bool IGisProject::remove() { mount(); /* Check if parent is a device and give it a chance to take care of data. e.g. Garmin devices remove images attached to the project. */ IDevice * device = dynamic_cast(parent()); if(device) { device->aboutToRemoveProject(this); } QFileInfo fi(filename); if(fi.isFile()) { QFile::remove(filename); } else if(fi.isDir()) { QDir(filename).removeRecursively(); } umount(); return true; } void IGisProject::updateItemCounters() { // count number of items by type memset(cntItemsByType, 0, sizeof(cntItemsByType)); cntTrkPts = 0; cntWpts = 0; totalDistance = 0; totalAscent = 0; totalDescent = 0; totalElapsedSeconds = 0; totalElapsedSecondsMoving = 0; QByteArray buffer; QDataStream stream(&buffer, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); for(int i = 0; i < childCount(); i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } cntItemsByType[item->type()]++; CGisItemTrk * trk = dynamic_cast(item); if(trk) { cntTrkPts += trk->getNumberOfVisiblePoints(); totalDistance += trk->getTotalDistance(); totalAscent += trk->getTotalAscent(); totalDescent += trk->getTotalDescent(); totalElapsedSeconds += trk->getTotalElapsedSeconds(); totalElapsedSecondsMoving += trk->getTotalElapsedSecondsMoving(); stream << trk->getHash(); } CGisItemWpt * wpt = dynamic_cast(item); if(wpt) { cntWpts++; stream << wpt->getHash(); } } QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(buffer); hashTrkWpt[1] = hashTrkWpt[0]; hashTrkWpt[0] = md5.result().toHex(); } void IGisProject::blockUpdateItems(bool yes) { noUpdate = yes; if(noUpdate == false) { updateItems(); } } void IGisProject::updateDecoration() { int N = childCount(); bool saved = true; for(int i = 0; i < N; i++) { IGisItem * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } if(item->isChanged()) { saved = false; break; } } setText(CGisListWks::eColumnDecoration, autoSave ? "A" : saved ? "" : "*"); } void IGisProject::sortItems() { QList trks; QList rtes; QList wpts; QList ovls; QList items = takeChildren(); for(QTreeWidgetItem* item : items) { CGisItemTrk * trk = dynamic_cast(item); if(trk != nullptr) { trks << trk; continue; } CGisItemRte * rte = dynamic_cast(item); if(rte != nullptr) { rtes << rte; continue; } CGisItemWpt * wpt = dynamic_cast(item); if(wpt != nullptr) { wpts << wpt; continue; } CGisItemOvlArea * ovl = dynamic_cast(item); if(ovl != nullptr) { ovls << ovl; continue; } } sortItems(trks); sortItems(rtes); sortItems(wpts); sortItems(ovls); items.clear(); for(IGisItem * item : trks) { items << item; } for(IGisItem * item : rtes) { items << item; } for(IGisItem * item : wpts) { items << item; } for(IGisItem * item : ovls) { items << item; } addChildren(items); } static bool sortByName(IGisItem * item1, IGisItem * item2) { static QCollator collator; // this will set collator to natural sorting mode (instead of lexical) collator.setNumericMode(true); return collator.compare(item1->getName(), item2->getName()) < 0; } static bool sortByTime(IGisItem * item1, IGisItem * item2) { const QDateTime& t1 = item1->getTimestamp(); const QDateTime& t2 = item2->getTimestamp(); // avoid jumping items due to invalid timestamps if(!t1.isValid() || !t2.isValid()) { return sortByName(item1, item2); } return t1 < t2; } void IGisProject::sortItems(QList &items) const { switch(sortingFolder) { case IGisProject::eSortFolderName: qSort(items.begin(), items.end(), &sortByName); break; case IGisProject::eSortFolderTime: qSort(items.begin(), items.end(), &sortByTime); break; } } void IGisProject::filter(const QString& str) { const int N = childCount(); if(str.isEmpty()) { for(int n = 0; n < N; n++) { child(n)->setHidden(false); } return; } for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(child(n)); if(item == nullptr) { continue; } switch(filterMode) { case eFilterModeName: item->setHidden(!item->getName().toUpper().contains(str)); break; case eFilterModeText: item->setHidden(!item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText).toUpper().contains(str)); break; } } } qmapshack-1.10.0/src/gis/prj/IGisProject.h000644 001750 000144 00000036264 13216234261 021434 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef IGISPROJECT_H #define IGISPROJECT_H #include "gis/IGisItem.h" #include "gis/rte/router/IRouter.h" #include #include #include #include class CGisListWks; class CGisDraw; class CGisItemWpt; class QDataStream; class CDetailsPrj; class IDevice; class IGisProject : public QTreeWidgetItem { Q_DECLARE_TR_FUNCTIONS(IGisProject) public: enum type_e { eTypeGoogle , eTypeQms , eTypeGpx , eTypeDb , eTypeLostFound , eTypeTwoNav , eTypeSlf // the Sigma Log Format , eTypeFit , eTypeTcx , eTypeSml , eTypeLog , eTypeQlb }; /// flags used to serialize trivial flags in qms file enum flags_e { eFlagNoCorrelation = 0x1 , eFlagAutoSave = 0x2 }; enum sorting_roadbook_e { eSortRoadbookNone , eSortRoadbookTrackWithDouble , eSortRoadbookTrackWithoutDouble }; enum sorting_folder_e { eSortFolderTime ,eSortFolderName ,eSortFolderSymbol }; enum filter_mode_e { eFilterModeName ,eFilterModeText }; struct person_t { QString name; QString id; QString domain; IGisItem::link_t link; }; struct copyright_t { QString author; QString year; QString license; }; struct metadata_t { metadata_t() : time(QDateTime::currentDateTimeUtc()) { } QString name; QString desc; person_t author; copyright_t copyright; QList links; QDateTime time; QString keywords; QRectF bounds; // -- all gpx tags - stop QMap extensions; }; static const QString filedialogAllSupported; static const QString filedialogFilterGPX; static const QString filedialogFilterTCX; static const QString filedialogFilterSML; static const QString filedialogFilterLOG; static const QString filedialogFilterQLB; static const QString filedialogFilterQMS; static const QString filedialogFilterSLF; static const QString filedialogFilterFIT; static const QString filedialogSaveFilters; static const QString filedialogLoadFilters; static filter_mode_e filterMode; IGisProject(type_e type, const QString &filename, CGisListWks *parent); IGisProject(type_e type, const QString &filename, IDevice *parent); virtual ~IGisProject(); static IGisProject * create(const QString filename, CGisListWks * parent); /** @brief Ask to save the project before it is closed. If the project is closed, the user is asked if the project should be saved and saved on user request. @return True if the operation is aborted. False on "save" and "no". */ bool askBeforClose(); IGisProject& operator=(const IGisProject& p) { key = p.key; metadata = p.metadata; return *this; } /** @brief Summon the project details dialog. */ void edit(); /** @brief Returns true if a project of given format can be saved, false if it cannot be saved (just as .slf atm) */ virtual bool canSave() const { return false; } virtual const QString getFileDialogFilter() const { return QString(); } virtual const QString getFileExtension() const { return QString(); } /** @brief Save the project using it's native format. */ virtual bool save(); /** @brief Save the project selecting one of the available formats. */ bool saveAs(QString fn = QString(), QString filter = QString()); /** @brief Save as strict GPX V 1.1 without any extensions and HTML @return True on success */ bool saveAsStrictGpx11(); virtual void setFilename(const QString& fn) { filename = fn; } virtual QString getFilename() const { return filename; } /** @brief Get the project type enumeration. @Note: usually dynamic_cast should be used to get a pointer of correct type. However if the project is serialized, a type id is needed. @return One of type_e */ type_e getType() const { return type; } /** @brief Get unique project key. @return A MD5 hash string */ const QString& getKey() const { genKey(); return key; } /** @brief Get the unique key of the device the project is attached to @return If the project is not attached to a device the string is empty */ QString getDeviceKey() const; QPixmap getIcon() const; /** @brief Get the project's name @return The name from metadata.name */ QString getName() const; /** @brief Get the project's name extended with the parent's name. @return The name from metadata.nam appended with either the device name or the database parent folder's name. */ QString getNameEx() const; const QDateTime& getTime() const { return metadata.time; } const QString& getKeywords() const { return metadata.keywords; } const QString& getDescription() const { return metadata.desc; } const QList& getLinks() const { return metadata.links; } const metadata_t& getMetadata() const { return metadata; } /** @brief Get the sorting mode @return One of sorting_e */ sorting_roadbook_e getSortingRoadbook() const { return sortingRoadbook; } sorting_folder_e getSortingFolder() const { return sortingFolder; } void setName(const QString& str); void setKeywords(const QString& str); void setDescription(const QString& str); void setLinks(const QList& links); /** @brief Set change mark */ void setChanged(); /** @brief Set the sorting mode for the roadbook in the details dialog This will mark the project as changed. @param s the mode */ void setSortingRoadbook(sorting_roadbook_e s); /** @brief Set the sorting mode for workspace folder This will mark the project as changed. @param s the mode */ void setSortingFolder(sorting_folder_e s); /** @brief Get a short metadata summary @return Informational string. */ virtual QString getInfo() const; /** @brief Get a temporary pointer to the item with matching key @param key @return If no item is found 0 is returned. */ IGisItem * getItemByKey(const IGisItem::key_t &key); void getItemsByKeys(const QList& keys, QList& items); /** @brief Get a list of items that are close to a given pixel coordinate of the screen @note: The returned pointers are just for temporary use. Best you use them to get the item's key. @param pos the coordinate on the screen in pixel @param items a list the item's pointer is stored to. */ void getItemsByPos(const QPointF& pos, QList& items); void getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items); void getNogoAreas(QVector &areas) const; int getItemCountByType(IGisItem::type_e type) const { return cntItemsByType[type]; } qreal getTotalDistance() const { return totalDistance; } qreal getTotalAscent() const { return totalAscent; } qreal getTotalDescent() const { return totalDescent; } qreal getTotalElapsedSeconds() const { return totalElapsedSeconds; } qreal getTotalElapsedSecondsMoving() const { return totalElapsedSecondsMoving; } bool doCorrelation() const { return !noCorrelation; } void switchOnCorrelation(); void setAutoSave(bool on); /** @brief Receive the current mouse position Iterate over all items and pass the position @param pos the mouse position on the screen in pixel */ virtual void mouseMove(const QPointF& pos); /** @brief Delete items with matching key @param key */ bool delItemByKey(const IGisItem::key_t &key, QMessageBox::StandardButtons &last); /** @brief Call IGisItem::edit() method for items with given key @param key a MD5 hash key */ void editItemByKey(const IGisItem::key_t &key); /** @brief Add a copy if the given item to the project Before the item is inserted the method will use it's key to find a duplicate item. If there is an item with the same item key a copy option dialog is shown. Depending the result the action is performed or aborted. The result will be copied into lastResult to repeat the same decision on subsequent items. @param item pointer to item @param off the offset into the tree widget, -1 for none @param lastResult a reference to hold the last result of the copy option dialog */ void insertCopyOfItem(IGisItem *item, int off, int &lastResult); /** @brief Check if the project was initialized correctly. For example a if a GPX file does not load correctly the project is invalid. @return True if project is valid */ bool isValid() const { return valid; } /** @brief Test if visibility check mark is set @return True if project is visible */ bool isVisible() const; bool isAutoSave() const { return autoSave; } /** @brief Test if this project is handled by a device @return The device type (IDevice::type_e). IDevice::eTypeNone if the project is not stored on a device. */ qint32 isOnDevice() const; /** @brief Test if project has been changed @return True if changed. */ bool isChanged() const; void drawItem(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, CGisDraw * gis); void drawLabel(QPainter& p, const QPolygonF &viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis); void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis); /** @brief Serialize object out of a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ virtual QDataStream& operator<<(QDataStream& stream); /** @brief Serialize object into a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ virtual QDataStream& operator>>(QDataStream& stream) const; /** @brief writeMetadata @param doc @return */ QDomNode writeMetadata(QDomDocument& doc, bool strictGpx11); /** @brief Mount volume the project's file is stored at This is only valid for projects located on GPS devices. For all other projects the method does nothing. */ void mount(); /** @brief Umount volume the project's file is stored at This is only valid for projects located on GPS devices. For all other projects the method does nothing. */ void umount(); /** @brief Removed the projects file from disk. This is only valid for projects located on GPS devices. For all other projects the method does nothing. */ bool remove(); /** @brief Block update of items. Use this to speed up actions with many items, e.g. copy actions. If the blocking is stopped (yes == false) updateItems() is called. @param yes set true to block updating items */ void blockUpdateItems(bool yes); /** @brief Return state of current update block @return True if updates are blocked. */ bool blockUpdateItems() const { return noUpdate; } void filter(const QString& str); void confirmPendingAutoSave() { autoSavePending = false; } protected: void genKey() const; virtual void setupName(const QString& defaultName); void markAsSaved(); void readMetadata(const QDomNode& xml, metadata_t& metadata); void updateItems(); void updateItemCounters(); void updateDecoration(); void sortItems(); void sortItems(QList& items) const; /** @brief Converts a string with HTML tags to a string without HTML depending on the device Some devices e.g. Garmin can not handle HTML. @param str a string @return A string with HTML removed depending on the device */ QString html2Dev(const QString& str); // Those are the URIs of the GPX extensions we support static const QString gpxx_ns; static const QString gpxtpx_ns; static const QString wptx1_ns; static const QString rmc_ns; static const QString ql_ns; static const QString gs_ns; static const QString tp1_ns; // Those are standard GPX/XML namespaces static const QString gpx_ns; static const QString xsi_ns; static const QString gpxdata_ns; QPointer dlgDetails; type_e type; mutable QString key; QString filename; bool valid = false; bool noUpdate = false; bool noCorrelation = false; bool changedRoadbookMode = false; bool autoSave = false; ///< flag to show if auto save is on or off bool autoSavePending = false; ///< flag to show if auto save event has been sent. will be reset by save() metadata_t metadata; QString nameSuffix; sorting_roadbook_e sortingRoadbook = eSortRoadbookNone; sorting_folder_e sortingFolder = eSortFolderTime; qint32 cntItemsByType[IGisItem::eTypeMax]; qint32 cntTrkPts = 0; qint32 cntWpts = 0; qreal totalDistance = 0; qreal totalAscent = 0; qreal totalDescent = 0; quint32 totalElapsedSeconds = 0; quint32 totalElapsedSecondsMoving = 0; QString hashTrkWpt[2]; }; #endif //IGISPROJECT_H qmapshack-1.10.0/src/gis/prj/CDetailsPrj.cpp000644 001750 000144 00000075721 13216234137 021754 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/IGisItem.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/CDetailsPrj.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CActivityTrk.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CLinksDialog.h" #include "helpers/CProgressDialog.h" #include "helpers/Signals.h" #include "plot/CPlotProfile.h" #include "plot/CPlotTrack.h" #include "widgets/CTextEditWidget.h" #include #include CDetailsPrj::CDetailsPrj(IGisProject &prj, QWidget *parent) : QWidget(parent) , INotifyTrk(CGisItemTrk::eVisualProject) , prj(prj) { setupUi(this); const int N = prj.childCount(); for(int i = 0; i < N; i++) { CGisItemTrk *trk = dynamic_cast(prj.child(i)); if(nullptr != trk) { trk->registerVisual(this); } } connect(labelKeywords, &QLabel::linkActivated, this, static_cast(&CDetailsPrj::slotLinkActivated)); connect(textDesc, &QTextBrowser::anchorClicked, this, static_cast(&CDetailsPrj::slotLinkActivated)); connect(toolPrint, &QToolButton::clicked, this, &CDetailsPrj::slotPrint); connect(toolReload, &QToolButton::clicked, this, &CDetailsPrj::slotSetupGui); connect(toolLock, &QToolButton::clicked, this, &CDetailsPrj::slotLock); connect(comboSort, static_cast(&QComboBox::currentIndexChanged), this, &CDetailsPrj::slotSortMode); timerUpdateTime = new QTimer(this); timerUpdateTime->setSingleShot(true); timerUpdateTime->setInterval(20); connect(timerUpdateTime, &QTimer::timeout, this, &CDetailsPrj::slotSetupGui); timerUpdateTime->start(); } CDetailsPrj::~CDetailsPrj() { const int N = prj.childCount(); for(int i = 0; i < N; i++) { CGisItemTrk *trk = dynamic_cast(prj.child(i)); if(nullptr != trk) { trk->unregisterVisual(this); } } } void CDetailsPrj::resizeEvent(QResizeEvent * e) { QWidget::resizeEvent(e); timerUpdateTime->start(); } void CDetailsPrj::getTrackProfile(CGisItemTrk * trk, QImage& image) { CPlotProfile plot(trk, trk->limitsGraph1, IPlot::eModeIcon, this); plot.setSolid(true); plot.save(image); } void CDetailsPrj::getTrackOverview(CGisItemTrk * trk, QImage& image) { CPlotTrack plot(trk, this); plot.save(image); } void CDetailsPrj::slotSetupGui() { if(!mutex.tryLock()) { /* What is this about? When drawing the diary a progress dialog is used. This dialog is operating the event loop. Consequently new events resulting into drawing the diary can be processed. But slotSetupGui() is not reentrant. That is why we have to block these calls with a mutex. However as something has changed the diary has to be redrawn again. That is why the timer is restarted. */ timerUpdateTime->start(1000); return; } X______________BlockAllSignals______________X(this); comboSort->setCurrentIndex(prj.getSortingRoadbook()); if((prj.getSortingRoadbook() > IGisProject::eSortRoadbookNone) && !prj.doCorrelation()) { X_____________UnBlockAllSignals_____________X(this); QString msg = tr("You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?"); int res = QMessageBox::question(this, tr("Correlation..."), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); if(res == QMessageBox::Yes) { prj.switchOnCorrelation(); } else { comboSort->setCurrentIndex(IGisProject::eSortRoadbookNone); } timerUpdateTime->start(); mutex.unlock(); return; } const int N = prj.childCount(); if(N == 0) { toolLock->setChecked(false); toolLock->setEnabled(false); } else { toolLock->setChecked(true); toolLock->setEnabled(true); for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(prj.child(n)); if(item && !item->isReadOnly()) { toolLock->setChecked(false); break; } } } X_____________UnBlockAllSignals_____________X(this); CCanvas::setOverrideCursor(Qt::WaitCursor, "CDetailsPrj::slotSetupGui()"); // Create a new document, fill it and attach it to the text browser. // This is much faster than to use the current one of the text browser. // According to the docs, the text browser's current document should be // deleted because the text browser is it's parent. QTextDocument * doc = new QTextDocument(); doc->setTextWidth(textDesc->size().width() - 20); draw(*doc, false); doc->setParent(textDesc); textDesc->setDocument(doc); QTabWidget * tabWidget = dynamic_cast(parentWidget() ? parentWidget()->parentWidget() : nullptr); if(tabWidget) { int idx = tabWidget->indexOf(this); if(idx != NOIDX) { setObjectName(prj.getName()); tabWidget->setTabText(idx, prj.getName().replace("&", "&&")); } } CCanvas::restoreOverrideCursor("CDetailsPrj::slotSetupGui()"); mutex.unlock(); } #define ROOT_FRAME_MARGIN 5 #define CHAR_PER_LINE 130 void CDetailsPrj::draw(QTextDocument& doc, bool printable) { int w = doc.textWidth(); int nItems = 0; QFontMetrics fm(QFont(font().family(),12)); int pointSize = ((10 * (w - 2 * ROOT_FRAME_MARGIN)) / (CHAR_PER_LINE * fm.width("X"))); pointSize = qMax(pointSize,CMainWindow::self().getMapFont().pointSize()); QFont f = textDesc->font(); f.setPointSize(pointSize); textDesc->setFont(f); fmtFrameStandard.setTopMargin(5); fmtFrameStandard.setBottomMargin(5); fmtFrameStandard.setWidth(w - 2 * ROOT_FRAME_MARGIN); fmtFrameTrackSummary.setBackground(Qt::white); fmtFrameTrackSummary.setBorder(1); fmtFrameTrackSummary.setPadding(10); fmtCharStandard.setFont(f); fmtBlockStandard.setTopMargin(10); fmtBlockStandard.setBottomMargin(10); fmtBlockStandard.setAlignment(Qt::AlignJustify); fmtFrameRoot.setTopMargin(0); fmtFrameRoot.setBottomMargin(ROOT_FRAME_MARGIN); fmtFrameRoot.setLeftMargin(ROOT_FRAME_MARGIN); fmtFrameRoot.setRightMargin(ROOT_FRAME_MARGIN); fmtTableStandard.setBorder(1); fmtTableStandard.setBorderBrush(Qt::black); fmtTableStandard.setCellPadding(4); fmtTableStandard.setCellSpacing(0); fmtTableStandard.setHeaderRowCount(1); fmtTableStandard.setTopMargin(10); fmtTableStandard.setBottomMargin(20); fmtTableStandard.setWidth(w - 4 * ROOT_FRAME_MARGIN); QVector constraints1; constraints1 << QTextLength(QTextLength::FixedLength, 32); constraints1 << QTextLength(QTextLength::VariableLength, 50); constraints1 << QTextLength(QTextLength::VariableLength, 100); fmtTableStandard.setColumnWidthConstraints(constraints1); fmtTableHidden.setBorder(0); fmtTableHidden.setCellPadding(4); fmtTableHidden.setCellSpacing(0); fmtTableHidden.setTopMargin(0); fmtTableHidden.setBottomMargin(0); QVector constraints2; constraints2 << QTextLength(QTextLength::PercentageLength, 50); constraints2 << QTextLength(QTextLength::PercentageLength, 50); fmtTableHidden.setColumnWidthConstraints(constraints2); fmtTableInfo.setBorder(0); fmtCharHeader.setFont(f); fmtCharHeader.setBackground(Qt::darkBlue); fmtCharHeader.setFontWeight(QFont::Bold); fmtCharHeader.setForeground(Qt::white); bool isReadOnly = printable || prj.isOnDevice() || toolLock->isChecked(); setWindowTitle(prj.getName()); labelTime->setText(IUnit::datetime2string(prj.getTime(), false)); QString keywords = prj.getKeywords(); if(keywords.isEmpty()) { keywords = tr("none"); } labelKeywords->setText(IGisItem::toLink(isReadOnly, "keywords", keywords, "")); scrollVal = textDesc->verticalScrollBar()->value(); doc.clear(); doc.rootFrame()->setFrameFormat(fmtFrameRoot); QTextCursor cursor = doc.rootFrame()->firstCursorPosition(); cursor.insertHtml(IGisItem::toLink(isReadOnly, "name", QString("

%1

").arg(prj.getNameEx()), "")); QList trks; QList rtes; QList wpts; QList areas; const int N = prj.childCount(); for(int i = 0; i < N; i++) { CGisItemTrk *trk = dynamic_cast(prj.child(i)); if(nullptr != trk && !trk->isHidden()) { trks << trk; nItems++; continue; } CGisItemRte *rte = dynamic_cast(prj.child(i)); if(nullptr != rte && !rte->isHidden()) { rtes << rte; nItems++; continue; } CGisItemWpt *wpt = dynamic_cast(prj.child(i)); if(nullptr != wpt && !wpt->isHidden()) { wpts << wpt; nItems++; continue; } CGisItemOvlArea *area = dynamic_cast(prj.child(i)); if(nullptr != area && !area->isHidden()) { areas << area; nItems++; continue; } } QTextFrame * diaryFrame = cursor.insertFrame(fmtFrameStandard); { QTextCursor cursor1(diaryFrame); cursor1.setCharFormat(fmtCharStandard); cursor1.setBlockFormat(fmtBlockStandard); QTextTable * table = cursor1.insertTable(1, 2, fmtTableHidden); QTextCursor cursor2 = table->cellAt(0,0).firstCursorPosition(); drawInfo(cursor2, isReadOnly); if(prj.getItemCountByType(IGisItem::eTypeTrk) != 0) { QTextCursor cursor3 = table->cellAt(0,1).firstCursorPosition(); drawTrackSummary(cursor3, trks, isReadOnly); } } int n=1; PROGRESS_SETUP(tr("Build diary..."), 0, nItems, this); if(comboSort->currentIndex() > IGisProject::eSortRoadbookNone) { drawByTrack(cursor, trks, wpts, progress, n, isReadOnly); } else { drawByGroup(cursor, trks, wpts, progress, n, isReadOnly); } drawRoute(cursor, rtes, progress, n, isReadOnly); drawArea(cursor, areas, progress, n, isReadOnly); QTimer::singleShot(1, this, SLOT(slotSetScrollbar())); } void CDetailsPrj::slotSetScrollbar() { textDesc->verticalScrollBar()->setValue(scrollVal); comboSort->setEnabled(true); } void CDetailsPrj::drawInfo(QTextCursor& cursor, bool isReadOnly) { QTextFrame * diaryFrame = cursor.insertFrame(fmtFrameStandard); QTextCursor cursor1(diaryFrame); cursor1.setCharFormat(fmtCharStandard); cursor1.setBlockFormat(fmtBlockStandard); cursor1.insertHtml(IGisItem::createText(isReadOnly, prj.getDescription(), prj.getLinks())); } void CDetailsPrj::drawTrackSummary(QTextCursor& cursor, const QList trks, bool isReadOnly) { quint32 flags = 0; QMap summaries; for(const CGisItemTrk* trk : trks) { const CActivityTrk& activities = trk->getActivities(); flags |= activities.getAllFlags(); activities.sumUp(summaries); } QTextFrame * diaryFrame = cursor.insertFrame(fmtFrameTrackSummary); QTextCursor cursor1(diaryFrame); cursor1.setCharFormat(fmtCharStandard); cursor1.setBlockFormat(fmtBlockStandard); QString str; str += tr("Summary over all tracks in project
"); CActivityTrk::printSummary(summaries, flags, str); cursor1.insertHtml(str); } void CDetailsPrj::addIcon(QTextTable * table, int col, int row, IGisItem * item, bool printable) { table->cellAt(row,col).firstCursorPosition().insertImage(item->getIcon().toImage().scaledToWidth(16, Qt::SmoothTransformation)); if(!(printable||item->isReadOnly())) { table->cellAt(row,col).lastCursorPosition().insertHtml(QString("

").arg(item->getKey().item)); } } void CDetailsPrj::drawByGroup(QTextCursor &cursor, QList& trks, QList& wpts, CProgressDialog& progress, int& n, bool printable) { int cnt, w = cursor.document()->textWidth(); if(!wpts.isEmpty()) { cursor.insertHtml(tr("

Waypoints

")); QTextTable * table = cursor.insertTable(wpts.count()+1, eMax1, fmtTableStandard); table->cellAt(0,eSym1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).setFormat(fmtCharHeader); table->cellAt(0,eComment1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).firstCursorPosition().insertText(tr("Info")); table->cellAt(0,eComment1).firstCursorPosition().insertText(tr("Comment")); cnt = 1; for(CGisItemWpt * wpt : wpts) { PROGRESS(n++, return ); addIcon(table, eSym1, cnt, wpt, printable); table->cellAt(cnt,eInfo1).firstCursorPosition().insertHtml(wpt->getInfo(IGisItem::eFeatureShowName)); table->cellAt(cnt,eComment1).firstCursorPosition().insertHtml(IGisItem::createText(wpt->isReadOnly()||printable, wpt->getComment(), wpt->getDescription(), wpt->getLinks(), wpt->getKey().item)); cnt++; } cursor.setPosition(table->lastPosition() + 1); } if(!trks.isEmpty()) { cursor.insertHtml(tr("

Tracks

")); QTextTable * table = cursor.insertTable(trks.count()+1, eMax1, fmtTableStandard); table->cellAt(0,eSym1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).setFormat(fmtCharHeader); table->cellAt(0,eComment1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).firstCursorPosition().insertText(tr("Info")); table->cellAt(0,eComment1).firstCursorPosition().insertText(tr("Comment")); cnt = 1; for(CGisItemTrk * trk : trks) { PROGRESS(n++, return ); addIcon(table, eSym1, cnt, trk, printable); int w1 = qRound(w/3.5 > 300 ? 300 : w/3.5); int h1 = qRound(w1/2.0); if(w1 < 300) { table->cellAt(cnt,eInfo1).firstCursorPosition().insertHtml(trk->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowActivity)); QTextTable * table1 = table->cellAt(cnt,eInfo1).lastCursorPosition().insertTable(1, 2, fmtTableInfo); QImage profile(w1,h1,QImage::Format_ARGB32); getTrackProfile(trk, profile); table1->cellAt(0,0).firstCursorPosition().insertImage(profile); QImage overview(h1,h1,QImage::Format_ARGB32); getTrackOverview(trk, overview); table1->cellAt(0,1).firstCursorPosition().insertImage(overview); } else { QTextTable * table1 = table->cellAt(cnt,eInfo1).firstCursorPosition().insertTable(1, 3, fmtTableInfo); table1->cellAt(0,0).firstCursorPosition().insertHtml(trk->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowActivity)); QImage profile(w1,h1,QImage::Format_ARGB32); getTrackProfile(trk, profile); table1->cellAt(0,1).firstCursorPosition().insertImage(profile); QImage overview(h1,h1,QImage::Format_ARGB32); getTrackOverview(trk, overview); table1->cellAt(0,2).firstCursorPosition().insertImage(overview); } table->cellAt(cnt,eComment1).firstCursorPosition().insertHtml(IGisItem::createText(trk->isReadOnly()||printable, trk->getComment(), trk->getDescription(), trk->getLinks(), trk->getKey().item)); cnt++; } cursor.setPosition(table->lastPosition() + 1); } } struct wpt_info_t { IGisItem::key_t key; qreal distance1 = NOFLOAT; qreal ascent1 = NOFLOAT; qreal descent1 = NOFLOAT; qreal distance2 = NOFLOAT; qreal ascent2 = NOFLOAT; qreal descent2 = NOFLOAT; qreal distance3 = NOFLOAT; qreal ascent3 = NOFLOAT; qreal descent3 = NOFLOAT; }; void CDetailsPrj::drawByTrack(QTextCursor& cursor, QList &trks, QList &wpts, CProgressDialog &progress, int &n, bool printable) { int cnt, w = cursor.document()->textWidth(); const qreal w1 = qRound(w/3.5 > 300 ? 300 : w/3.5); const qreal h1 = qRound(w1/2.0); for(CGisItemTrk * trk : trks) { const CTrackData::trkpt_t* lastTrkpt = nullptr; wpt_info_t * lastWptInfo = nullptr; QList wptInfo; const CTrackData& t = trk->getTrackData(); for(const CTrackData::trkpt_t& trkpt : t) { if(trkpt.isHidden() || trkpt.keyWpt.item.isEmpty()) { continue; } wptInfo << wpt_info_t(); wpt_info_t& info = wptInfo.last(); info.key = trkpt.keyWpt; info.distance1 = trkpt.distance; info.ascent1 = trkpt.ascent; info.descent1 = trkpt.descent; if(lastWptInfo != nullptr) { lastWptInfo->distance2 = trkpt.distance - lastTrkpt->distance; lastWptInfo->ascent2 = trkpt.ascent - lastTrkpt->ascent; lastWptInfo->descent2 = trkpt.descent - lastTrkpt->descent; } info.distance3 = trk->getTotalDistance() - trkpt.distance; info.ascent3 = trk->getTotalAscent() - trkpt.ascent; info.descent3 = trk->getTotalDescent() - trkpt.descent; lastTrkpt = &trkpt; lastWptInfo = &wptInfo.last(); } cursor.insertHtml(QString("

%1

").arg(trk->getName())); QTextTable * table = cursor.insertTable(wptInfo.count()+2, eMax2, fmtTableStandard); table->cellAt(0,eSym2).setFormat(fmtCharHeader); table->cellAt(0,eInfo2).setFormat(fmtCharHeader); table->cellAt(0,eData2).setFormat(fmtCharHeader); table->cellAt(0,eComment2).setFormat(fmtCharHeader); table->cellAt(0,eInfo2).firstCursorPosition().insertText(tr("Info")); table->cellAt(0,eComment2).firstCursorPosition().insertText(tr("Comment")); cnt = 1; for(const wpt_info_t &info : wptInfo) { PROGRESS(n++, return ); CGisItemWpt * wpt = dynamic_cast(prj.getItemByKey(info.key)); if(wpt != nullptr) { addIcon(table, eSym2, cnt, wpt, printable); table->cellAt(cnt,eInfo2).firstCursorPosition().insertHtml(wpt->getInfo(IGisItem::eFeatureShowName)); QTextTable * table1 = table->cellAt(cnt,eData2).lastCursorPosition().insertTable(1, 2, fmtTableInfo); QString text, val, unit; text += ""; text += ""; text += ""; text += ""; IUnit::self().meter2distance(info.distance1, val, unit); text += ""; IUnit::self().meter2distance(info.distance2, val, unit); text += ""; IUnit::self().meter2distance(info.distance3, val, unit); text += ""; text += ""; text += ""; text += ""; IUnit::self().meter2elevation(info.ascent1, val, unit); text += ""; IUnit::self().meter2elevation(info.ascent2, val, unit); text += ""; IUnit::self().meter2elevation(info.ascent3, val, unit); text += ""; text += ""; text += ""; text += ""; IUnit::self().meter2elevation(info.descent1, val, unit); text += ""; IUnit::self().meter2elevation(info.descent2, val, unit); text += ""; IUnit::self().meter2elevation(info.descent3, val, unit); text += ""; text += ""; text += "
 " + tr("From Start") + "  " + tr("To Next") + "  " + tr("To End") + " 
" + tr("Distance: ") + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + "
" + tr("Ascent: ") + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + "
" + tr("Descent: ") + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + ""+ QString("%1%2").arg(val).arg(unit) + "
"; table1->cellAt(0,0).firstCursorPosition().insertHtml(text); const QList& images = wpt->getImages(); if(!images.isEmpty()) { QImage image(images.first().pixmap); qDebug() << image.size(); int w = image.width(); int h = image.height(); if(w < h) { h *= 100.0 / w; w = 100; } else { h *= 200.0 / w; w = 200; } qDebug() << w << h; image = image.scaled(w,h,Qt::KeepAspectRatio, Qt::SmoothTransformation); table1->cellAt(0,1).firstCursorPosition().insertImage(image); } table->cellAt(cnt,eComment2).firstCursorPosition().insertHtml(IGisItem::createText(wpt->isReadOnly()||printable, wpt->getComment(), wpt->getDescription(), wpt->getLinks(), wpt->getKey().item)); } cnt++; } addIcon(table, eSym1, cnt, trk, printable); table->cellAt(cnt,eInfo2).firstCursorPosition().insertHtml(trk->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowActivity)); QTextTable * table1 = table->cellAt(cnt,eData2).lastCursorPosition().insertTable(1, 2, fmtTableInfo); QImage profile(w1,h1,QImage::Format_ARGB32); getTrackProfile(trk, profile); table1->cellAt(0,0).firstCursorPosition().insertImage(profile); QImage overview(h1,h1,QImage::Format_ARGB32); getTrackOverview(trk, overview); table1->cellAt(0,1).firstCursorPosition().insertImage(overview); table->cellAt(cnt,eComment2).firstCursorPosition().insertHtml(IGisItem::createText(trk->isReadOnly()||printable, trk->getComment(), trk->getDescription(), trk->getLinks(), trk->getKey().item)); cursor.setPosition(table->lastPosition() + 1); } } void CDetailsPrj::drawArea(QTextCursor& cursor, QList &areas, CProgressDialog &progress, int &n, bool printable) { if(areas.isEmpty()) { return; } cursor.insertHtml(tr("

Areas

")); QTextTable * table = cursor.insertTable(areas.count()+1, eMax1, fmtTableStandard); table->cellAt(0,eSym1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).setFormat(fmtCharHeader); table->cellAt(0,eComment1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).firstCursorPosition().insertText(tr("Info")); table->cellAt(0,eComment1).firstCursorPosition().insertText(tr("Comment")); int cnt = 1; for(CGisItemOvlArea * area : areas) { PROGRESS(n++, return ); addIcon(table, eSym1, cnt, area, printable); table->cellAt(cnt,eInfo1).firstCursorPosition().insertHtml(area->getInfo(IGisItem::eFeatureShowName)); table->cellAt(cnt,eComment1).firstCursorPosition().insertHtml(IGisItem::createText(area->isReadOnly()||printable, area->getComment(), area->getDescription(), area->getLinks(), area->getKey().item)); cnt++; } cursor.setPosition(table->lastPosition() + 1); } void CDetailsPrj::drawRoute(QTextCursor& cursor, QList &rtes, CProgressDialog &progress, int &n, bool printable) { if(rtes.isEmpty()) { return; } cursor.insertHtml(tr("

Routes

")); QTextTable * table = cursor.insertTable(rtes.count()+1, eMax1, fmtTableStandard); table->cellAt(0,eSym1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).setFormat(fmtCharHeader); table->cellAt(0,eComment1).setFormat(fmtCharHeader); table->cellAt(0,eInfo1).firstCursorPosition().insertText(tr("Info")); table->cellAt(0,eComment1).firstCursorPosition().insertText(tr("Comment")); int cnt = 1; for(CGisItemRte * rte : rtes) { PROGRESS(n++, return ); addIcon(table, eSym1, cnt, rte, printable); table->cellAt(cnt,eInfo1).firstCursorPosition().insertHtml(rte->getInfo(IGisItem::eFeatureShowName)); table->cellAt(cnt,eComment1).firstCursorPosition().insertHtml(IGisItem::createText(rte->isReadOnly()||printable, rte->getComment(), rte->getDescription(), rte->getLinks(), rte->getKey().item)); cnt++; } cursor.setPosition(table->lastPosition() + 1); } void CDetailsPrj::slotLinkActivated(const QString& link) { if(link == "name") { QString name = QInputDialog::getText(this, tr("Edit name..."), tr("Enter new project name."), QLineEdit::Normal, prj.getName()); if(name.isEmpty()) { return; } prj.setName(name); } else if(link == "keywords") { QString keywords = QInputDialog::getText(this, tr("Edit keywords..."), tr("Enter keywords."), QLineEdit::Normal, prj.getKeywords()); if(keywords.isEmpty()) { return; } if(keywords == tr("none")) { keywords.clear(); } prj.setKeywords(keywords); } slotSetupGui(); } void CDetailsPrj::slotLinkActivated(const QUrl& url) { if(url.path() == "name") { QString name = QInputDialog::getText(this, tr("Edit name..."), tr("Enter new project name."), QLineEdit::Normal, prj.getName()); if(!name.isEmpty()) { prj.setName(name); } } else if(url.path() == "description") { if(url.hasQuery()) { IGisItem::key_t key; key.project = prj.getKey(); QString query = url.query(); if(query.startsWith("key=")) { key.item = query.mid(4); } IGisItem * item = prj.getItemByKey(key); if(item) { CTextEditWidget dlg(item->getDescription(), this); if(dlg.exec() == QDialog::Accepted) { item->setDescription(dlg.getHtml()); } } } else { CTextEditWidget dlg(prj.getDescription(), nullptr); if(dlg.exec() == QDialog::Accepted) { prj.setDescription(dlg.getHtml()); } } } else if(url.path() == "comment") { if(url.hasQuery()) { IGisItem::key_t key; key.project = prj.getKey(); QString query = url.query(); if(query.startsWith("key=")) { key.item = query.mid(4); } IGisItem * item = prj.getItemByKey(key); if(item) { CTextEditWidget dlg(item->getComment(), this); if(dlg.exec() == QDialog::Accepted) { item->setComment(dlg.getHtml()); } } } } else if(url.path() == "links") { if(url.hasQuery()) { IGisItem::key_t key; key.project = prj.getKey(); QString query = url.query(); if(query.startsWith("key=")) { key.item = query.mid(4); } IGisItem * item = prj.getItemByKey(key); if(item) { QList links = item->getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { item->setLinks(links); } } } else { QList links = prj.getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { prj.setLinks(links); } } } else if(url.path() == "edit") { IGisItem::key_t key; key.project = prj.getKey(); QString query = url.query(); if(query.startsWith("key=")) { key.item = query.mid(4); } IGisItem * item = prj.getItemByKey(key); if(item) { item->edit(); } } else { QDesktopServices::openUrl(url); return; } slotSetupGui(); } void CDetailsPrj::slotPrint() { QPrinter printer; printer.setResolution(200); printer.setPageSize(QPrinter::A4); QPrintDialog dialog(&printer, this); dialog.setWindowTitle(tr("Print Diary")); if (dialog.exec() != QDialog::Accepted) { return; } QTextDocument doc; QSizeF pageSize = printer.pageRect(QPrinter::DevicePixel).size(); doc.setPageSize(pageSize); draw(doc, true); doc.print(&printer); slotSetupGui(); } void CDetailsPrj::slotLock(bool on) { prj.blockUpdateItems(true); const int N = prj.childCount(); for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(prj.child(n)); if(item && (item->isReadOnly() != on)) { item->setReadOnlyMode(on); } } prj.blockUpdateItems(false); slotSetupGui(); } void CDetailsPrj::slotSortMode(int idx) { comboSort->setEnabled(false); prj.setSortingRoadbook(IGisProject::sorting_roadbook_e(idx)); slotSetupGui(); } void CDetailsPrj::updateData() { if(!prj.blockUpdateItems()) { slotSetupGui(); } } qmapshack-1.10.0/src/gis/prj/IDetailsPrj.ui000644 001750 000144 00000010640 12745644236 021615 0ustar00oeichlerxusers000000 000000 IDetailsPrj 0 0 873 511 Form 3 3 3 3 3 0 0 Keywords: - - 0 0 Keep order of project Sort along track (multiple) Sort along track (single) ... :/icons/32x32/UnLock.png :/icons/32x32/Lock.png:/icons/32x32/UnLock.png 22 22 true Print diary ... :/icons/32x32/Print.png:/icons/32x32/Print.png 22 22 Rebuild diary. ... :/icons/32x32/Reset.png:/icons/32x32/Reset.png 22 22 Qt::ScrollBarAlwaysOn true false qmapshack-1.10.0/src/gis/prj/CDetailsPrj.h000644 001750 000144 00000006756 13216234143 021420 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSPRJ_H #define CDETAILSPRJ_H #include "gis/trk/CGisItemTrk.h" #include "ui_IDetailsPrj.h" #include #include #include class CDetailsPrj; class IGisProject; class CGisItemTrk; class CGisItemWpt; class CGisItemOvlArea; class CGisItemRte; class CProgressDialog; class QTimer; class CDetailsPrj : public QWidget, public INotifyTrk, private Ui::IDetailsPrj { Q_OBJECT public: CDetailsPrj(IGisProject& prj, QWidget * parent); virtual ~CDetailsPrj(); void updateData() override; void setMouseFocus(const CTrackData::trkpt_t * pt) override {} void setMouseRangeFocus(const CTrackData::trkpt_t * pt1, const CTrackData::trkpt_t * pt2) override {} void setMouseClickFocus(const CTrackData::trkpt_t * pt) override {} protected: void resizeEvent(QResizeEvent *e) override; private slots: void slotLinkActivated(const QString& link); void slotLinkActivated(const QUrl& url); void slotPrint(); void slotLock(bool on); void slotSortMode(int idx); void slotSetupGui(); void slotSetScrollbar(); private: void addIcon(QTextTable *table, int col, int row, IGisItem * item, bool printable); void getTrackProfile(CGisItemTrk * trk, QImage& image); void getTrackOverview(CGisItemTrk * trk, QImage& image); void draw(QTextDocument& doc, bool printable); void drawInfo(QTextCursor& cursor, bool isReadOnly); void drawTrackSummary(QTextCursor& cursor, const QList trks, bool isReadOnly); void drawByGroup(QTextCursor& cursor, QList &trks, QList &wpts, CProgressDialog &progress, int &n, bool printable); void drawByTrack(QTextCursor& cursor, QList &trks, QList &wpts, CProgressDialog &progress, int &n, bool printable); void drawArea(QTextCursor& cursor, QList &areas, CProgressDialog &progress, int &n, bool printable); void drawRoute(QTextCursor& cursor, QList &rtes, CProgressDialog &progress, int &n, bool printable); enum eTblCol1 {eSym1, eInfo1, eComment1, eMax1}; enum eTblCol2 {eSym2, eInfo2, eData2, eComment2, eMax2}; IGisProject& prj; QTextFrameFormat fmtFrameStandard; QTextFrameFormat fmtFrameTrackSummary; QTextCharFormat fmtCharStandard; QTextBlockFormat fmtBlockStandard; QTextFrameFormat fmtFrameRoot; QTextTableFormat fmtTableStandard; QTextTableFormat fmtTableHidden; QTextTableFormat fmtTableInfo; QTextCharFormat fmtCharHeader; int scrollVal = 0; QTimer * timerUpdateTime; QMutex mutex {QMutex::NonRecursive}; }; #endif //CDETAILSPRJ_H qmapshack-1.10.0/src/gis/suunto/000755 001750 000144 00000000000 13216664445 017643 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/suunto/CLogProject.h000644 001750 000144 00000003040 13216234143 022150 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 . **********************************************************************************************/ #ifndef CLOGPROJECT_H #define CLOGPROJECT_H #include "gis/prj/IGisProject.h" #include "gis/suunto/ISuuntoProject.h" class CLogProject : public ISuuntoProject { Q_DECLARE_TR_FUNCTIONS(CLogProject) public: CLogProject(const QString &filename, CGisListWks * parent); virtual ~CLogProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterLOG; } const QString getFileExtension() const override { return "log"; } static void loadLog(const QString &filename, CLogProject *project); private: void loadLog(const QString& filename); }; #endif //CLOGPROJECT_H qmapshack-1.10.0/src/gis/suunto/ISuuntoProject.cpp000644 001750 000144 00000013347 13216234137 023303 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/suunto/ISuuntoProject.h" #include "gis/trk/CGisItemTrk.h" ISuuntoProject::ISuuntoProject(type_e type, const QString &filename, CGisListWks *parent) : IGisProject(type, filename, parent) { } void ISuuntoProject::fillTrackPointsFromSamples(QList &samplesList, QList &lapsList, CTrackData &trk, QList extensions) { for (const extension_t& ext : extensions) { fillMissingData(ext.tag, samplesList); } deleteSamplesWithDuplicateTimestamps(samplesList, extensions); lapsList << samplesList.last().time.addSecs(1); // a last dummy lap button push is added with timestamp = 1 s later than the last sample timestamp trk.segs.resize(lapsList.size() ); // segments are created and each of them contains 1 lap int lap = 0; CTrackData::trkseg_t *seg = &(trk.segs[lap]); for(const sample_t& sample : samplesList) { if (sample.time > lapsList[lap]) { lap++; seg = &(trk.segs[lap]); } CTrackData::trkpt_t trkpt; trkpt.time = sample.time; for(const extension_t& ext : extensions) { if(sample.data.contains(ext.tag)) { ext.func(trkpt, sample[ext.tag]); } } seg->pts.append(trkpt); } } void ISuuntoProject::fillMissingData(const QString &dataField, QList &samplesList) { // Suunto samples contain lat/lon OR heart rate, elevation, etc.., each one with its own timestamp. // The purpose of the code below is to "spread" data among samples. // At the end each sample contains data, linearly interpolated from its neighbors according to timestamps. QList collect; QList result; sample_t previousSampleWithData; for(sample_t& sample : samplesList) { collect << sample; if (sample.data.contains(dataField)) { if (!previousSampleWithData.data.contains(dataField)) { // case where, at the beginning, first samples have no data for(sample_t& collectedSample : collect) { collectedSample[dataField] = sample[dataField]; } } else { // case where linear interpolation can be applied qreal dT = ((qreal)(collect.last().time.toMSecsSinceEpoch() - previousSampleWithData.time.toMSecsSinceEpoch())) / 1000.0; if (dT != 0) // dT == 0 when samples have the same timestamps ; this is managed later in deleteSamplesWithDuplicateTimestamps function { qreal dY = collect.last().data[dataField] - previousSampleWithData.data[dataField]; qreal slope = dY / dT; for(sample_t& collectedSample : collect) { // apply interpolation to collected samples collectedSample[dataField] = previousSampleWithData.data[dataField] + slope * ( (qreal)(collectedSample.time.toMSecsSinceEpoch() - previousSampleWithData.time.toMSecsSinceEpoch()) / 1000.0 ); } } } previousSampleWithData = sample; result << collect; collect.clear(); } } if (previousSampleWithData.data.contains(dataField)) { for(sample_t& collectedSample : collect) { // processing last remaining collected samples without data collectedSample[dataField] = previousSampleWithData[dataField]; } } result << collect; samplesList = result; } void ISuuntoProject::deleteSamplesWithDuplicateTimestamps(QList &samples, QList extensions) { QList result; QList collect; for(sample_t& sample : samples) { if(!collect.isEmpty()) { if(sample.time != collect.first().time) { result << mergeSamples(collect, extensions); collect.clear(); } } collect << sample; } result << mergeSamples(collect, extensions); samples = result; } ISuuntoProject::sample_t ISuuntoProject::mergeSamples(QList samples, QList extensions) { if(samples.count() == 1) { return samples.first(); } sample_t result; result.time = samples.first().time; for (const extension_t& ext : extensions) { qreal sum = 0; qint32 cnt = 0; for(const sample_t& sample : samples) { if(sample.data.contains(ext.tag)) { sum += sample[ext.tag]; cnt++; } } if(cnt != 0) { result[ext.tag] = sum/cnt; // averaged value is assigned to the merged sample } } return result; } qmapshack-1.10.0/src/gis/suunto/CLogProject.cpp000644 001750 000144 00000026020 13216234261 022507 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/suunto/CLogProject.h" #include "gis/suunto/ISuuntoProject.h" #include "gis/trk/CGisItemTrk.h" #include static const QList extensions = { {"Latitude", 0.0000001, 0.0, ASSIGN_VALUE(lat,NIL)} // unit [°] ,{"Longitude", 0.0000001, 0.0, ASSIGN_VALUE(lon,NIL)} // unit [°] ,{"Altitude", 1.0, 0.0, ASSIGN_VALUE(ele,NIL)} // unit [m] ,{"VerticalSpeed", 0.01, 0.0, ASSIGN_VALUE(extensions["gpxdata:verticalSpeed"],NIL)} // unit [m/h] ,{"HR", 1.0, 0.0, ASSIGN_VALUE(extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"],qRound)} // unit [bpm] ,{"Cadence", 1.0, 0.0, ASSIGN_VALUE(extensions["gpxdata:cadence"],NIL)} // unit [bpm] ,{"Temperature", 0.1, 0.0, ASSIGN_VALUE(extensions["gpxdata:temp"],NIL)} // unit [°C] ,{"SeaLevelPressure", 0.1, 0.0, ASSIGN_VALUE(extensions["gpxdata:seaLevelPressure"],NIL)} // unit [hPa] ,{"Speed", 0.01, 0.0, ASSIGN_VALUE(extensions["gpxdata:speed"],NIL)} // unit [m/s] ,{"EnergyConsumption", 0.1, 0.0, ASSIGN_VALUE(extensions["gpxdata:energy"],NIL)} // unit [kCal/min] }; CLogProject::CLogProject(const QString &filename, CGisListWks * parent) : ISuuntoProject(eTypeLog, filename, parent) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/LogProject.png")); blockUpdateItems(true); loadLog(filename); blockUpdateItems(false); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); } void CLogProject::loadLog(const QString& filename) { try { loadLog(filename, this); } catch(QString &errormsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); valid = false; } } void CLogProject::loadLog(const QString &filename, CLogProject *project) { QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if (!file.exists() || QFileInfo(filename).suffix().toLower() != "log") { project->filename.clear(); project->setupName(filename); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; return; } if (!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open %1").arg(filename); } // load file content to xml document QDomDocument xml; QString msg; int line; int column; if (!xml.setContent(&file, false, &msg, &line, &column)) { file.close(); throw tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg); } file.close(); QDomElement xmlOpenambitlog = xml.documentElement(); if (xmlOpenambitlog.tagName() != "openambitlog") { throw tr("Not an Openambit log file: %1").arg(filename); } CTrackData trk; if(xmlOpenambitlog.namedItem("DeviceInfo").isElement()) { const QDomNode& xmlDeviceInfo = xmlOpenambitlog.namedItem("DeviceInfo"); if(xmlDeviceInfo.namedItem("Name").isElement()) { trk.cmt = tr("Device: %1
").arg(xmlDeviceInfo.namedItem("Name").toElement().text()); } } if(xmlOpenambitlog.namedItem("Log").isElement()) { QDateTime time0; // start time of the track const QDomNode& xmlLog = xmlOpenambitlog.namedItem("Log"); if(xmlLog.namedItem("Header").isElement()) { const QDomNode& xmlHeader = xmlLog.namedItem("Header"); if(xmlHeader.namedItem("DateTime").isElement()) { QString dateTimeStr = xmlHeader.namedItem("DateTime").toElement().text(); trk.name = dateTimeStr; // date of beginning of recording is chosen as track name IUnit::parseTimestamp(dateTimeStr, time0); // as local time } if(xmlHeader.namedItem("Activity").isElement()) { trk.desc = xmlHeader.namedItem("Activity").toElement().text(); } if(xmlHeader.namedItem("RecoveryTime").isElement()) { trk.cmt += tr("Recovery time: %1 h
").arg(xmlHeader.namedItem("RecoveryTime").toElement().text().toInt() / 3600000); } if(xmlHeader.namedItem("PeakTrainingEffect").isElement()) { trk.cmt += tr("Peak Training Effect: %1
").arg(xmlHeader.namedItem("PeakTrainingEffect").toElement().text().toDouble()/10.0); } if(xmlHeader.namedItem("Energy").isElement()) { trk.cmt += tr("Energy: %1 kCal
").arg((int)xmlHeader.namedItem("Energy").toElement().text().toDouble() ); } } if(xmlLog.namedItem("Samples").isElement()) { const QDomNode& xmlSamples = xmlLog.namedItem("Samples"); const QDomNodeList& xmlSampleList = xmlSamples.toElement().elementsByTagName("Sample"); if (xmlSampleList.count() > 0) { bool UTCtimeFound = false; for (int i = 0; i < xmlSampleList.count(); i++) // browse XML samples { //look for samples with UTC timestamp const QDomNode& xmlSample = xmlSampleList.item(i); if (xmlSample.namedItem("UTCReference").isElement()) { QString timeStr = xmlSample.namedItem("UTCReference").toElement().text(); if(xmlSample.namedItem("Time").isElement()) { IUnit::parseTimestamp(timeStr, time0); time0 = time0.addMSecs(-xmlSample.namedItem("Time").toElement().text().toDouble() ); // substract current sample time to get start time UTCtimeFound = true; break; } } } if ( !UTCtimeFound) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Use of local time...") , tr("No UTC time has been found in file %1. " "Local computer time will be used. " "You can adjust time using a time filter if needed.").arg(filename) , QMessageBox::Ok); } bool sampleWithPositionFound = false; QList samplesList; QList lapsList; for (int i = 0; i < xmlSampleList.count(); i++) // browse XML samples { sample_t sample; const QDomNode& xmlSample = xmlSampleList.item(i); if(xmlSample.namedItem("Latitude").isElement()) { sampleWithPositionFound = true; } if(xmlSample.namedItem("Time").isElement()) { sample.time = time0.addMSecs(xmlSample.namedItem("Time").toElement().text().toDouble() ); } if(xmlSample.namedItem("Type").isElement()) { if ( xmlSample.namedItem("Type").toElement().text() == "lap-info" ) { if ( xmlSample.namedItem("Lap").isElement() ) { const QDomNode& xmlLap = xmlSample.namedItem("Lap"); if(xmlLap.namedItem("Type").isElement()) { if (xmlLap.namedItem("Type").toElement().text() == "Manual") { lapsList << sample.time; // stores timestamps of the samples where the the "Lap" button has been pressed } } } } else if (xmlSample.namedItem("Type").toElement().text() == "gps-small" || xmlSample.namedItem("Type").toElement().text() == "gps-base" || xmlSample.namedItem("Type").toElement().text() == "gps-tiny" || xmlSample.namedItem("Type").toElement().text() == "position" || xmlSample.namedItem("Type").toElement().text() == "periodic") { for (const extension_t& ext : extensions) { if (xmlSample.namedItem(ext.tag).isElement()) { const QDomNode& xmlSampleData = xmlSample.namedItem(ext.tag); sample[ext.tag] = xmlSampleData.toElement().text().toDouble() * ext.scale + ext.offset; } } samplesList << sample; } } } if (!sampleWithPositionFound) { throw tr("This LOG file does not contain any position data and can not be displayed by QMapShack: %1").arg(filename); } fillTrackPointsFromSamples(samplesList, lapsList, trk, extensions); new CGisItemTrk(trk, project); project->sortItems(); project->setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; } } } } qmapshack-1.10.0/src/gis/suunto/CSmlProject.cpp000644 001750 000144 00000026042 13216234261 022525 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/suunto/CSmlProject.h" #include "gis/suunto/ISuuntoProject.h" #include "gis/trk/CGisItemTrk.h" #include static const QList extensions = { {"Latitude", RAD_TO_DEG, 0.0, ASSIGN_VALUE(lat,NIL)} // unit [°] ,{"Longitude", RAD_TO_DEG, 0.0, ASSIGN_VALUE(lon,NIL)} // unit [°] ,{"Altitude", 1.0, 0.0, ASSIGN_VALUE(ele,NIL)} // unit [m] ,{"VerticalSpeed", 1.0, 0.0, ASSIGN_VALUE(extensions["gpxdata:verticalSpeed"],NIL)} // unit [m/h] ,{"HR", 60.0, 0.0, ASSIGN_VALUE(extensions["gpxtpx:TrackPointExtension|gpxtpx:hr"],qRound)} // unit [bpm] ,{"Cadence", 60.0, 0.0, ASSIGN_VALUE(extensions["gpxdata:cadence"],NIL)} // unit [bpm] ,{"Temperature", 1.0, -273.15, ASSIGN_VALUE(extensions["gpxdata:temp"],NIL)} // unit [°C] ,{"SeaLevelPressure", 0.01, 0.0, ASSIGN_VALUE(extensions["gpxdata:seaLevelPressure"],NIL)} // unit [hPa] ,{"Speed", 1.0, 0.0, ASSIGN_VALUE(extensions["gpxdata:speed"],NIL)} // unit [m/s] ,{"EnergyConsumption", 60.0 / 4184.0, 0.0, ASSIGN_VALUE(extensions["gpxdata:energy"],NIL)} // unit [kCal/min] }; CSmlProject::CSmlProject(const QString &filename, CGisListWks * parent) : ISuuntoProject(eTypeSml, filename, parent) { setIcon(CGisListWks::eColumnIcon, QIcon("://icons/32x32/SmlProject.png")); blockUpdateItems(true); loadSml(filename); blockUpdateItems(false); setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); } void CSmlProject::loadSml(const QString& filename) { try { loadSml(filename, this); } catch(QString &errormsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); valid = false; } } void CSmlProject::loadSml(const QString &filename, CSmlProject *project) { QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if (!file.exists() || QFileInfo(filename).suffix().toLower() != "sml") { project->filename.clear(); project->setupName(filename); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; return; } if (!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open %1").arg(filename); } // load file content to xml document QDomDocument xml; QString msg; int line; int column; if (!xml.setContent(&file, false, &msg, &line, &column)) { file.close(); throw tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg); } file.close(); QDomElement xmlSml = xml.documentElement(); if (xmlSml.tagName() != "sml") { throw tr("Not an sml file: %1").arg(filename); } if(xmlSml.namedItem("DeviceLog").isElement()) { CTrackData trk; QDateTime time0; // start time of the track const QDomNode& xmlDeviceLog = xmlSml.namedItem("DeviceLog"); if(xmlDeviceLog.namedItem("Header").isElement()) { const QDomNode& xmlHeader = xmlDeviceLog.namedItem("Header"); if(xmlHeader.namedItem("DateTime").isElement()) { QString dateTimeStr = xmlHeader.namedItem("DateTime").toElement().text(); trk.name = dateTimeStr; // date (in local time) of beginning of recording is chosen as track name IUnit::parseTimestamp(dateTimeStr, time0); // as local time } if(xmlHeader.namedItem("Activity").isElement()) { trk.desc = xmlHeader.namedItem("Activity").toElement().text(); } if(xmlHeader.namedItem("RecoveryTime").isElement()) { trk.cmt = tr("Recovery time: %1 h
").arg(xmlHeader.namedItem("RecoveryTime").toElement().text().toInt() / 3600); } if(xmlHeader.namedItem("PeakTrainingEffect").isElement()) { trk.cmt += tr("Peak Training Effect: %1
").arg(xmlHeader.namedItem("PeakTrainingEffect").toElement().text().toDouble()); } if(xmlHeader.namedItem("Energy").isElement()) { trk.cmt += tr("Energy: %1 kCal
").arg((int)xmlHeader.namedItem("Energy").toElement().text().toDouble() / 4184); } if(xmlHeader.namedItem("BatteryChargeAtStart").isElement() && xmlHeader.namedItem("BatteryCharge").isElement() && xmlHeader.namedItem("Duration").isElement() ) { trk.cmt += tr("Battery usage: %1 %/hour") .arg( 100*(xmlHeader.namedItem("BatteryChargeAtStart").toElement().text().toDouble() - xmlHeader.namedItem("BatteryCharge").toElement().text().toDouble()) / (xmlHeader.namedItem("Duration").toElement().text().toDouble() / 3600), 0, 'f', 1); } } if(xmlDeviceLog.namedItem("Device").isElement()) { const QDomNode& xmlDevice = xmlDeviceLog.namedItem("Device"); if(xmlDevice.namedItem("Name").isElement()) { trk.cmt = tr("Device: %1
").arg(xmlDevice.namedItem("Name").toElement().text()) + trk.cmt; } } if(xmlDeviceLog.namedItem("Samples").isElement()) { const QDomNode& xmlSamples = xmlDeviceLog.namedItem("Samples"); const QDomNodeList& xmlSampleList = xmlSamples.toElement().elementsByTagName("Sample"); if (xmlSampleList.count() > 0) { bool UTCtimeFound = false; for (int i = 0; i < xmlSampleList.count(); i++) // browse XML samples { //look for samples with UTC timestamp const QDomNode& xmlSample = xmlSampleList.item(i); if (xmlSample.namedItem("UTC").isElement()) { QString timeStr = xmlSample.namedItem("UTC").toElement().text(); if (timeStr.indexOf("Z") != NOIDX) // "Z" means "UTC timestamp" ; note the even this element is , this does not mean that time is expressed as UTC { if(xmlSample.namedItem("Time").isElement()) { IUnit::parseTimestamp(timeStr, time0); time0 = time0.addMSecs(-xmlSample.namedItem("Time").toElement().text().toDouble() * 1000.0 ); // substract current sample time to get start time UTCtimeFound = true; break; } } } } if ( !UTCtimeFound) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Use of local time...") , tr("No UTC time has been found in file %1. " "Local computer time will be used. " "You can adjust time using a time filter if needed.").arg(filename) , QMessageBox::Ok); } bool sampleWithPositionFound = false; QList samplesList; QList lapsList; for (int i = 0; i < xmlSampleList.count(); i++) // browse XML samples { sample_t sample; const QDomNode& xmlSample = xmlSampleList.item(i); if(xmlSample.namedItem("Latitude").isElement()) { sampleWithPositionFound = true; } if(xmlSample.namedItem("Time").isElement()) { sample.time = time0.addMSecs(xmlSample.namedItem("Time").toElement().text().toDouble() * 1000.0); } if(xmlSample.namedItem("Events").isElement()) { const QDomNode& xmlEvents = xmlSample.namedItem("Events"); if(xmlEvents.namedItem("Lap").isElement()) { lapsList << sample.time; // stores timestamps of the samples where the the "Lap" button has been pressed } } else // samples without "Events" are the ones containing position, heart rate, etc... that we want to store { for (const extension_t& ext : extensions) { if (xmlSample.namedItem(ext.tag).isElement()) { const QDomNode& xmlSampleData = xmlSample.namedItem(ext.tag); sample[ext.tag] = xmlSampleData.toElement().text().toDouble() * ext.scale + ext.offset; } } samplesList << sample; } } if (!sampleWithPositionFound) { throw tr("This SML file does not contain any position data and can not be displayed by QMapShack: %1").arg(filename); } fillTrackPointsFromSamples(samplesList, lapsList, trk, extensions); new CGisItemTrk(trk, project); project->sortItems(); project->setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; } } } } qmapshack-1.10.0/src/gis/suunto/CSmlProject.h000644 001750 000144 00000003040 13216234143 022162 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 . **********************************************************************************************/ #ifndef CSMLPROJECT_H #define CSMLPROJECT_H #include "gis/prj/IGisProject.h" #include "gis/suunto/ISuuntoProject.h" class CSmlProject : public ISuuntoProject { Q_DECLARE_TR_FUNCTIONS(CSmlProject) public: CSmlProject(const QString &filename, CGisListWks * parent); virtual ~CSmlProject() = default; const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterSML; } const QString getFileExtension() const override { return "sml"; } static void loadSml(const QString &filename, CSmlProject *project); private: void loadSml(const QString& filename); }; #endif //CSMLPROJECT_H qmapshack-1.10.0/src/gis/suunto/ISuuntoProject.h000644 001750 000144 00000005103 13216234143 022734 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Michel Durand zero@cms123.fr 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 . **********************************************************************************************/ #ifndef ISUUNTOPROJECT_H #define ISUUNTOPROJECT_H #include "gis/prj/IGisProject.h" #include "gis/trk/CGisItemTrk.h" #include using fTrkPtSetVal = std::function; #define NIL ///< this is to silence the MSVC compiler #define ASSIGN_VALUE(var, op) \ [](CTrackData::trkpt_t &pt, qreal val) \ { \ if(val != NOFLOAT) \ { \ pt.var = op(val); \ } \ } \ struct extension_t { /// the tag as used in the xml file QString tag; /// a scale factor to be applied to the value stored in the xml file qreal scale; /// an offset to be applied to the value stored in the xml file qreal offset; /// an assignment function that assigns a value to a member of a trkpt_t object fTrkPtSetVal func; }; class ISuuntoProject : public IGisProject { public: ISuuntoProject(type_e type, const QString &filename, CGisListWks *parent); struct sample_t { QDateTime time; // as UTC timestamp QMap data; qreal& operator[](const QString& key) { return data[key]; } qreal operator[](const QString& key) const { return data[key]; } }; static void fillMissingData(const QString &dataField, QList &samplesList); static sample_t mergeSamples(QList samples, QList extensions); static void deleteSamplesWithDuplicateTimestamps(QList &samples, QList extensions); static void fillTrackPointsFromSamples(QList &samplesList, QList &lapsList, CTrackData &trk, QList extensions); }; #endif //CSUUNTOPROJECT_H qmapshack-1.10.0/src/gis/IGisItem.h000644 001750 000144 00000043322 13216234261 020122 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IGISITEM_H #define IGISITEM_H #include #include #include #include #include #include #include #include #include #include #include #include "units/IUnit.h" class CGisDraw; class IScrOpt; class IMouse; class QSqlDatabase; class IGisProject; class IGisItem : public QTreeWidgetItem { Q_DECLARE_TR_FUNCTIONS(IGisItem) public: struct history_event_t { QDateTime time; QString hash; QString who = "QMapShack"; QString icon; QString comment; QByteArray data; }; struct history_t { history_t() : histIdxInitial(NOIDX), histIdxCurrent(NOIDX) { } void reset() { histIdxInitial = NOIDX; histIdxCurrent = NOIDX; events.clear(); } qint32 histIdxInitial; qint32 histIdxCurrent; QList events; }; struct link_t { QUrl uri; QString text; QString type; }; struct wpt_t { wpt_t() : lat(NOFLOAT), lon(NOFLOAT), ele(NOINT), magvar(NOINT), geoidheight(NOINT), sat(NOINT), hdop(NOINT), vdop(NOINT), pdop(NOINT), ageofdgpsdata(NOINT), dgpsid(NOINT) { } // -- all gpx tags - start qreal lat; qreal lon; qint32 ele; QDateTime time; qint32 magvar; qint32 geoidheight; QString name; QString cmt; QString desc; QString src; QList links; QString sym; QString type; QString fix; qint32 sat; qint32 hdop; qint32 vdop; qint32 pdop; qint32 ageofdgpsdata; qint32 dgpsid; // -- all gpx tags - stop QMap extensions; }; /// never ever change these numbers. it will break binary data files enum type_e { eTypeWpt = 1 , eTypeTrk = 2 , eTypeRte = 3 , eTypeOvl = 4 , eTypeMax = 5 }; enum mark_e { eMarkNone = 0 ,eMarkChanged = 0x00000001 ,eMarkNotPart = 0x00000002 ,eMarkNotInDB = 0x00000004 }; enum selection_e { eSelectionNone = 0 , eSelectionExact = 0x00000001 , eSelectionIntersect = 0x00000002 , eSelectionTrk = 0x80000000 , eSelectionWpt = 0x40000000 , eSelectionRte = 0x20000000 , eSelectionOvl = 0x10000000 }; using selflags_t = quint32; struct key_t { bool operator==(const key_t& k) const { return (item == k.item) && (project == k.project) && (device == k.device); } bool operator!=(const key_t& k) const { return (item != k.item) || (project != k.project) || (device != k.device); } void clear() { item.clear(); project.clear(); device.clear(); } QString item; QString project; QString device; }; IGisItem(IGisProject *parent, type_e typ, int idx); virtual ~IGisItem(); /// this mutex has to be locked when ever the item list is accessed. static QMutex mutexItems; /** @brief If the item is part of a database project it will update itself with the database content */ virtual void updateFromDB(quint64 id, QSqlDatabase& db); /** @brief Update the visual representation of the QTreeWidgetItem @param enable @param disable */ virtual void updateDecoration(quint32 enable, quint32 disable); /** @brief Save the item's data into a GPX structure @param gpx the files tag to attach the data to */ virtual void save(QDomNode& gpx, bool strictGpx11) = 0; /** @brief Get key string to identify object @return */ const key_t& getKey() const; /** @brief Get a hash over the items data. Every entry in the history has a hash over the item's serialized data. If the data changes a new history entry is created and a new hash calculated. Thus the has can be used to detect if an item has been changed between the last time the hash was read. @return The hash as a string reference. */ const QString& getHash(); /** @brief Get the hash stored in the database when the item was loaded @return The hash as a string */ const QString& getLastDatabaseHash(); /** @brief Read the hash stored in the database */ void setLastDatabaseHash(quint64 id, QSqlDatabase& db); /** @brief Get the icon attached to object @return */ virtual const QPixmap& getIcon() const { return icon; } /** @brief Get name of this item. @return A reference to the internal string object */ virtual const QString& getName() const = 0; /** @brief Get name of this item extended by the project name @return A string object. */ virtual QString getNameEx() const; enum features_e { eFeatureNone = 0 , eFeatureShowName = 0x00000001 , eFeatureShowFullText = 0x00000002 , eFeatureShowActivity = 0x00000004 }; /** @brief Get a short string with the items properties to be displayed in tool tips or similar @param showName set true if the first line should be the item's name @param features a combination of features_e types @return A string object. */ virtual QString getInfo(quint32 features) const = 0; virtual const QString& getComment() const = 0; virtual const QString& getDescription() const = 0; virtual const QList& getLinks() const = 0; virtual QDateTime getTimestamp() const = 0; virtual void setComment(const QString& str) = 0; virtual void setDescription(const QString& str) = 0; virtual void setLinks(const QList& links) = 0; /** @brief Edit content of item. This is quite dependent on the item. The default implementation does nothing. It has to be overwritten and the item has to generate what ever is needed to edit/view it's details. */ virtual void edit() { } /** @brief Get the dimension of the item All coordinates are in Rad. Items with no @return */ virtual const QRectF& getBoundingRect() const { return boundingRect; } /** @brief Get screen option object to display and handle actions for this item. @param mouse a pointer to the mouse object initiating the action @return A null pointer is returned if no screen option are available */ virtual IScrOpt* getScreenOptions(const QPoint& origin, IMouse * mouse) { return nullptr; } /** @brief Get a point of the item that is close by the given screen pixel coordinate @param point a point in screen pixels @return If no point is found NOPOINTF is returned. */ virtual QPointF getPointCloseBy(const QPoint& point) { return NOPOINTF; } /** @brief Test if the item is close to a given pixel coordinate of the screen @param pos the coordinate on the screen in pixel @return If no point can be found NOPOINTF is returned. */ virtual bool isCloseTo(const QPointF& pos) = 0; virtual bool isWithin(const QRectF& area, selflags_t mode) = 0; /** @brief Receive the current mouse position The default does nothing. Override if needed. @param pos the mouse position on the screen in pixel */ virtual void mouseMove(const QPointF& pos) { Q_UNUSED(pos); } void mousePress(const QPointF& pos) { Q_UNUSED(pos); } void mouseRelease(const QPointF& pos) { Q_UNUSED(pos); } /** @brief Query if this item is read only @return True if it is read only. */ bool isReadOnly() const; /** @brief Query if the item is imported and was changed @return True if content was changed. */ bool isTainted() const; /** @brief Check if item is on a GPS device @return The device type (IDevice::type_e). IDevice::eTypeNone if the item is not stored on a device. */ qint32 isOnDevice() const; /** @brief Check if there are any pending unsaved changes @return True if the are changes to be saved */ bool isChanged() const; /** @brief Set the read only mode. This is quite dependent on the item. The default implementation will display a message box with a warning and ask the user to confirm. @param readOnly set true to make item read only @return Return true if the mode change has been accepted. */ virtual bool setReadOnlyMode(bool readOnly); virtual void drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) = 0; virtual void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { } virtual void drawLabel(QPainter& p, const QPolygonF& viewport,QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) = 0; virtual void drawHighlight(QPainter& p) = 0; virtual void gainUserFocus(bool yes) = 0; /** @brief Check for user focus @return True if the item has user focus. The default implementation is always false. */ virtual bool hasUserFocus() const { return false; } /** @brief Serialize object out of a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ virtual QDataStream& operator<<(QDataStream& stream) = 0; /** @brief Serialize object into a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ virtual QDataStream& operator>>(QDataStream& stream) const = 0; /** @brief Get read access to history of changes @return A reference to the history structure. */ const history_t& getHistory() const { return history; } /** @brief Load a given state of change from the history @param idx */ void loadHistory(int idx); /** @brief Remove all history entries younger than the current selected one. */ void cutHistoryAfter(); /** @brief Remove all history entries older than the current selected one. */ void cutHistoryBefore(); /** @brief Create a clone of itself and pass back the pointer Add the cloned item to the project with the same index as the original @return The pointer of the cloned item */ virtual IGisItem * createClone() = 0; IGisProject * getParentProject() const; /** @brief Remove all HTML tags from a string @param str the string @return A string without HTML tags */ static QString removeHtml(const QString &str); /** @brief Create a HTML formatted text with comment, description and link section. Depending on the isReadOnly flag the section headers are links to trigger a function @param isReadOnly true if the text should have no active links @param cmt the comment string @param desc the description string @param links a list of links @param key some key to be sent with the header links @return The formatted text ready to be used. */ static QString createText(bool isReadOnly, const QString& cmt, const QString& desc, const QList& links, const QString& key = ""); /** @brief Create a HTML formatted text with description and link section. Depending on the isReadOnly flag the section headers are links to trigger a function @param isReadOnly true if the text should have no active links @param desc the description string @param links a list of links @param key some key to be sent with the header links @return The formatted text ready to be used. */ static QString createText(bool isReadOnly, const QString& desc, const QList& links, const QString& key = ""); /** @brief Create a HTML formatted text with a link. Depending on the isReadOnly flag the section headers are links to trigger a function @param isReadOnly true if the text should have no active links @param href the link address @param str the link's string @param key some key to be sent with the link @return The formated text ready to be used. */ static QString toLink(bool isReadOnly, const QString& href, const QString& str, const QString& key); /** @brief Unified handler to get a new item name and a pointer to the traget project @param name a reference to a string object with the default name and to receive the name @param project a reference to a IGisProject pointer. On success it will point to the project instance @param itemtype a string to be used for the item type in the dialogs @return Returns true on success. Otherwise false. */ static bool getNameAndProject(QString &name, IGisProject *&project, const QString &itemtype); static IGisItem * newGisItem(quint32 type, quint64 id, QSqlDatabase& db, IGisProject * project); /// a no key value that can be used to nullify references. const static QString noKey; const static QString noName; struct color_t { const char *name; const QColor color; const QString bullet; }; static const color_t colorMap[]; static const size_t colorMapSize; protected: /// set icon of QTreeWidgetItem virtual void setSymbol() = 0; /// read waypoint data from an XML snippet void readWpt(const QDomNode& xml, wpt_t &wpt); /// write waypoint data to an XML snippet void writeWpt(QDomElement &xml, const wpt_t &wpt, bool strictGpx11); /// generate a unique key from item's data virtual void genKey() const; /// setup the history structure right after the creation of the item void setupHistory(); /// update current history entry (e.g. to save the flags) virtual void updateHistory(); /// convert a color string from GPX to a QT color QColor str2color(const QString& name); /// convert a QT color to a string to be used in a GPX file QString color2str(const QColor &color); /// to optimize drawing of large polylines split the line into sections that are visible void splitLineToViewport(const QPolygonF& line, const QRectF& extViewport, QList& lines); /// call when ever you make a change to the item's data virtual void changed(const QString& what, const QString& icon); void loadFromDb(quint64 id, QSqlDatabase& db); bool isVisible(const QRectF& rect, const QPolygonF& viewport, CGisDraw * gis); bool isVisible(const QPointF& point, const QPolygonF& viewport, CGisDraw * gis); bool isWithin(const QRectF& area, selflags_t flags, const QPolygonF& points); /** @brief Converts a string with HTML tags to a string without HTML depending on the device Some devices e.g. Garmin can not handle HTML. @param str a string @return A string with HTML removed depending on the device */ QString html2Dev(const QString& str, bool strictGpx11); /// see flags_e for possible flags quint32 flags = 0; /// the item's unique key mutable key_t key; /// each item has an icon for the tree widget QPixmap icon; /// the dimensions of the item QRectF boundingRect; /// that's where the real data is. An item is completely defined by it's history history_t history; /// the hash in the database when the item was loaded/saved QString lastDatabaseHash; enum flags_e { eFlagCreatedInQms = 0x00000001 ,eFlagWriteAllowed = 0x00000002 ,eFlagTainted = 0x00000004 ,eFlagWptBubble = 0x00000100 ,eFlagWptNogo = 0x00000200 }; static inline bool isBlocked(const QRectF& rect, const QList &blockedAreas) { for(const QRectF &r : blockedAreas) { if(rect.intersects(r)) { return true; } } return false; } }; QDataStream& operator>>(QDataStream& stream, IGisItem::history_t& h); QDataStream& operator<<(QDataStream& stream, const IGisItem::history_t& h); #endif //IGISITEM_H qmapshack-1.10.0/src/gis/CSetupFilter.cpp000644 001750 000144 00000003313 13216234137 021352 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisWorkspace.h" #include "gis/CSetupFilter.h" #include "gis/prj/IGisProject.h" CSetupFilter::CSetupFilter(CGisWorkspace *parent) : QWidget(parent) , widgetGisWorkspace(parent) { setupUi(this); switch (IGisProject::filterMode) { case IGisProject::eFilterModeName: radioName->setChecked(true); break; case IGisProject::eFilterModeText: radioText->setChecked(true); break; } connect(radioName, &QRadioButton::clicked, this, &CSetupFilter::slotSelect); connect(radioText, &QRadioButton::clicked, this, &CSetupFilter::slotSelect); } void CSetupFilter::slotSelect() { IGisProject::filterMode = radioName->isChecked() ? IGisProject::eFilterModeName : IGisProject::eFilterModeText; widgetGisWorkspace->applyFilter(); deleteLater(); } qmapshack-1.10.0/src/gis/CGisListDB.cpp000644 001750 000144 00000076076 13216234137 020710 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "config.h" #include "gis/CGisListDB.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBFolderLostFound.h" #include "gis/db/CDBFolderMysql.h" #include "gis/db/CDBFolderSqlite.h" #include "gis/db/CDBItem.h" #include "gis/db/CDBProject.h" #include "gis/db/CSearchDatabase.h" #include "gis/db/CSelectDBFolder.h" #include "gis/db/CSetupDatabase.h" #include "gis/db/CSetupFolder.h" #include "gis/db/macros.h" #include "helpers/CSettings.h" #include #include #include class CGisListDBEditLock { public: CGisListDBEditLock(bool waitCursor, CGisListDB * widget, const QString& src) : widget(widget), waitCursor(waitCursor), src(src) { if(waitCursor) { CCanvas::setOverrideCursor(Qt::WaitCursor, "CGisListDBEditLock: " + src); } widget->isInternalEdit++; } ~CGisListDBEditLock() { if(waitCursor) { CCanvas::restoreOverrideCursor("~CGisListDBEditLock: " + src); } widget->isInternalEdit--; } private: CGisListDB * widget; bool waitCursor; QString src; }; CGisListDB::CGisListDB(QWidget *parent) : QTreeWidget(parent) , socket(nullptr) { SETTINGS; cfg.beginGroup("Database"); QString path = cfg.value("lastDatabasePath", QDir::homePath()).toString(); QStringList names = cfg.value("names").toStringList(); cfg.beginGroup("Entries"); for(const QString &name : names) { cfg.beginGroup(name); QString type = cfg.value("type", "SQLite").toString(); if(type == "SQLite") { QString filename = cfg.value("filename","").toString(); if(filename.isEmpty()) { QMessageBox::information(this, name, tr("Due to changes in the database system QMapShack forgot about the filename of your database '%1'. You have to select it again in the next step.").arg(name), QMessageBox::Ok); filename = QFileDialog::getOpenFileName(this, tr("Select database file."), path, "QMapShack Database (*.db)"); if(filename.isEmpty()) { cfg.endGroup(); // name; continue; } } CDBFolderSqlite *folder = new CDBFolderSqlite(filename, name, this); folder->setToolTip(eColumnName, folder->getDBInfo()); } if(type == "MySQL") { QString server = cfg.value("server", "").toString(); QString port = cfg.value("port", "").toString(); QString user = cfg.value("user", "").toString(); QString passwd = cfg.value("passwd", "").toString(); bool noPasswd = cfg.value("noPasswd", false).toBool(); if(server.isEmpty() || user.isEmpty()) { cfg.endGroup(); // name continue; } CDBFolderMysql *folder = new CDBFolderMysql(server, port, user, passwd, noPasswd, name, this); folder->setToolTip(eColumnName, folder->getDBInfo()); } cfg.endGroup(); // name } cfg.endGroup(); // Entries cfg.endGroup(); // Database menuNone = new QMenu(this); actionAddDatabase = menuNone->addAction(QIcon("://icons/32x32/Add.png"), tr("Add Database"), this, SLOT(slotAddDatabase())); menuFolder = new QMenu(this); actionAddFolder = menuFolder->addAction(QIcon("://icons/32x32/Add.png"), tr("Add Folder"), this, SLOT(slotAddFolder())); actionRenameFolder = menuFolder->addAction(QIcon("://icons/32x32/A.png"), tr("Rename Folder"), this, SLOT(slotRenameFolder())); actionCopyFolder = menuFolder->addAction(QIcon("://icons/32x32/Copy.png"), tr("Copy Folder"), this, SLOT(slotCopyFolder())); actionMoveFolder = menuFolder->addAction(QIcon("://icons/32x32/Move.png"), tr("Move Folder"), this, SLOT(slotMoveFolder())); actionDelFolder = menuFolder->addAction(QIcon("://icons/32x32/DeleteOne.png"), tr("Delete Folder"), this, SLOT(slotDelFolder())); menuFolder->addSeparator(); actionImport = menuFolder->addAction(QIcon("://icons/32x32/LoadGIS.png"), tr("Import from Files..."), this, SLOT(slotImport())); actionExportToGpx = menuFolder->addAction(QIcon("://icons/32x32/SaveGIS.png"), tr("Export to GPX..."), this, SLOT(slotExportToGpx())); menuItem = new QMenu(this); actionDelItem = menuItem->addAction(QIcon("://icons/32x32/DeleteOne.png"), tr("Delete Item"), this, SLOT(slotDelItem())); menuDatabase = new QMenu(this); menuDatabase->addAction(actionAddFolder); actionSearch = menuDatabase->addAction(QIcon("://icons/32x32/Zoom.png"), tr("Search Database"), this, SLOT(slotSearchDatabase())); actionUpdate = menuDatabase->addAction(QIcon("://icons/32x32/DatabaseSync.png"), tr("Sync. with Database"), this, SLOT(slotUpdateDatabase())); actionDelDatabase = menuDatabase->addAction(QIcon("://icons/32x32/DeleteOne.png"), tr("Remove Database"), this, SLOT(slotDelDatabase())); menuDatabase->addSeparator(); menuDatabase->addAction(actionImport); menuDatabase->addAction(actionExportToGpx); menuLostFound = new QMenu(this); actionDelLostFound = menuLostFound->addAction(QIcon("://icons/32x32/Empty.png"), tr("Empty"), this, SLOT(slotDelLostFound())); menuLostFoundItem = new QMenu(this); actionDelLostFoundItem = menuLostFoundItem->addAction(QIcon("://icons/32x32/DeleteOne.png"), tr("Delete Item"), this, SLOT(slotDelLostFoundItem())); connect(this, &CGisListDB::customContextMenuRequested, this, &CGisListDB::slotContextMenu); connect(this, &CGisListDB::itemExpanded, this, &CGisListDB::slotItemExpanded); connect(this, &CGisListDB::itemChanged, this, &CGisListDB::slotItemChanged); bool enabled = cfg.value("Database/listenUpdate", false).toBool(); if(enabled) { quint16 port = cfg.value("Database/port", UDP_PORT).toUInt(); socket = new QUdpSocket(this); if(!socket->bind(QHostAddress::Any, port, QUdpSocket::ShareAddress)) { qDebug() << socket->errorString(); } connect(socket, &QUdpSocket::readyRead, this, &CGisListDB::slotReadyRead); } } CGisListDB::~CGisListDB() { saveDatabaseConfiguration(); } void CGisListDB::saveDatabaseConfiguration() { QStringList names; SETTINGS; cfg.beginGroup("Database"); cfg.beginGroup("Entries"); cfg.remove(""); const int N = topLevelItemCount(); for(int n = 0; n < N; n++) { CDBFolderSqlite * sqlite = dynamic_cast(topLevelItem(n)); if(sqlite) { QString name = sqlite->text(CGisListDB::eColumnName); names << name; cfg.beginGroup(name); cfg.setValue("type", "SQLite"); cfg.setValue("filename", sqlite->getFilename()); cfg.endGroup(); // name } CDBFolderMysql * mysql = dynamic_cast(topLevelItem(n)); if(mysql) { QString name = mysql->text(CGisListDB::eColumnName); names << name; cfg.beginGroup(name); cfg.setValue("type", "MySQL"); cfg.setValue("server", mysql->getServer()); cfg.setValue("port", mysql->getPort()); cfg.setValue("user", mysql->getUser()); cfg.setValue("passwd", mysql->getPasswd()); cfg.setValue("noPasswd",mysql->hasNoPasswd()); cfg.endGroup(); // name } } cfg.endGroup(); // Entries cfg.setValue("names", names); cfg.endGroup(); // Database } IDBFolderSql * CGisListDB::getDataBase(const QString& name, const QString &host) { CGisListDBEditLock lock(true, this, "getDataBase"); const int N = topLevelItemCount(); for(int n = 0; n < N; n++) { IDBFolderSql * database = dynamic_cast(topLevelItem(n)); if(database && (database->getDBName() == name)) { if(!host.isEmpty()) { if(database->getDBHost() != host) { continue; } } return database; } } return nullptr; } bool CGisListDB::hasDatabase(const QString& name) { CGisListDBEditLock lock(true, this, "hasDatabase"); const int N = topLevelItemCount(); for(int i = 0; i < N; i++) { IDBFolderSql * folder = dynamic_cast(topLevelItem(i)); if(folder && (folder->text(CGisListDB::eColumnName) == name)) { return true; } } return false; } bool CGisListDB::event(QEvent * e) { if(!dlgSearch.isNull()) { dlgSearch->event(e); } switch(e->type()) { case eEvtW2DAckInfo: { CGisListDBEditLock lock(true, this, "event"); CEvtW2DAckInfo * evt = (CEvtW2DAckInfo*)e; IDBFolderSql * folder = getDataBase(evt->db, evt->host); if(folder) { folder->update(evt); if(evt->updateLostFound) { folder->updateLostFound(); folder->announceChange(); } } e->accept(); return true; } case eEvtW2DCreate: { CGisListDBEditLock lock(true, this, "event"); CEvtW2DCreate * evt = (CEvtW2DCreate*)e; IDBFolderSql * db = getDataBase(evt->db, evt->host); if(db) { quint64 idChild = 0; IDBFolder * folder = db->getFolder(evt->idParent); if(folder) { idChild = folder->addFolder(evt->type, evt->name); } else { idChild = IDBFolder::addFolderToDb(evt->type, evt->name, evt->idParent, db->getDb()); } if(idChild) { if(folder) { folder->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } evt->idChild = idChild; CEvtD2WShowFolder * evt1 = new CEvtD2WShowFolder(idChild, evt->db); CGisWorkspace::self().postEventForWks(evt1); } db->announceChange(); } e->accept(); return true; } } return QTreeWidget::event(e); } void CGisListDB::slotContextMenu(const QPoint& point) { QPoint p = mapToGlobal(point); if(selectedItems().isEmpty()) { menuNone->exec(p); return; } bool isSingleSelection = selectedItems().count() == 1; actionUpdate->setEnabled(true); actionAddFolder->setEnabled(isSingleSelection); actionExportToGpx->setEnabled(isSingleSelection); actionImport->setEnabled(isSingleSelection); IDBFolderSql * database = dynamic_cast(currentItem()); if(database) { bool enabled = database->getDb().isOpen(); actionUpdate->setEnabled(enabled); actionAddFolder->setEnabled(enabled); actionSearch->setEnabled(enabled); menuDatabase->exec(p); return; } CDBFolderLostFound * lostFound = dynamic_cast(currentItem()); if(lostFound) { menuLostFound->exec(p); return; } IDBFolder * folder = dynamic_cast(currentItem()); if(folder) { bool isGroupFolder = folder->type() == IDBFolder::eTypeGroup; actionRenameFolder->setVisible(isGroupFolder); menuFolder->exec(p); return; } CDBItem * item = dynamic_cast(currentItem()); if(item) { CDBFolderLostFound * lostFound = dynamic_cast(item->parent()); if(lostFound) { menuLostFoundItem->exec(p); } else { menuItem->exec(p); } return; } } void CGisListDB::slotAddDatabase() { CSetupDatabase dlg(*this); if(dlg.exec() != QDialog::Accepted) { return; } QString name = dlg.getName(); IDBFolder * folder = nullptr; bool isUsable = true; if(dlg.isSqlite()) { QString filename = dlg.getFilename(); CDBFolderSqlite *sfolder = new CDBFolderSqlite(filename, name, this); sfolder->setToolTip(eColumnName, sfolder->getDBInfo()); isUsable = sfolder->isUsable(); folder = sfolder; } else if(dlg.isMysql()) { QString server = dlg.getServer(); QString port = dlg.getPort(); QString user = dlg.getUser(); QString passwd = dlg.getPasswd(); bool noPasswd = dlg.noPasswd(); CDBFolderMysql *mfolder = new CDBFolderMysql(server, port, user, passwd, noPasswd, name, this); mfolder->setToolTip(eColumnName, mfolder->getDBInfo()); isUsable = mfolder->isUsable(); folder = mfolder; } else { return; } if(isUsable) { folder->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } emit sigChanged(); saveDatabaseConfiguration(); } void CGisListDB::slotDelDatabase() { IDBFolderSql *folder = dynamic_cast(currentItem()); if(nullptr == folder) { return; } int res = QMessageBox::question(this, tr("Remove database..."), tr("Do you really want to remove '%1' from the list?").arg(folder->text(CGisListDB::eColumnName)), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok); if(res != QMessageBox::Ok) { return; } delete folder; emit sigChanged(); saveDatabaseConfiguration(); } void CGisListDB::slotAddFolder() { CGisListDBEditLock lock(false, this, "slotAddFolder"); IDBFolder *folder = dynamic_cast(currentItem()); if(nullptr == folder) { return; } IDBFolder::type_e type = IDBFolder::eTypeProject; QString name; CSetupFolder dlg(type, name, true, this); if(dlg.exec() != QDialog::Accepted) { return; } if(folder->addFolder(type, name) == 0) { return; } if(!folder->isExpanded()) { folder->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); folder->setExpanded(true); } IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder) { dbfolder->announceChange(); } } void CGisListDB::slotDelFolder() { CGisListDBEditLock lock(false, this, "slotDelFolder"); IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder == nullptr) { return; } int res = QMessageBox::question(this, tr("Delete database folder..."), tr("Are you sure you want to delete selected folders and all subfolders from the database?"), QMessageBox::Ok|QMessageBox::No); if(res != QMessageBox::Ok) { return; } QList itemsToDelete; QList items = selectedItems(); for(QTreeWidgetItem * item : items) { // only pick the project/other folders to copy folder = dynamic_cast(item); if((folder == nullptr) || (folder->type() < IDBFolder::eTypeGroup)) { continue; } folder->remove(); // Because some items can be parent of other selected items // it's a bad idea to delete them asap. Better collect them first. itemsToDelete << folder; } // iterate over all items to be deleted. for(QTreeWidgetItem * item : itemsToDelete) { // Test if the item's parent is also in the list. // If it is skip it because it will be deleted together with its parent. if(itemsToDelete.contains(item->parent())) { continue; } delete item; } dbfolder->updateLostFound(); dbfolder->announceChange(); } void CGisListDB::slotCopyFolder() { CGisListDBEditLock lock(false, this, "slotCopyFolder"); // no way to continue if the current item is not a folder (we need the database it is attached to) IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } // get the database the folder is attached to IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder == nullptr) { return; } // next we need to get the target folder // NOTE: By pre-setting db and host, we limit the selection to the current database quint64 idTarget = 0; QString db = folder->getDBName(); QString host = folder->getDBHost(); CSelectDBFolder dlg(idTarget, db, host, this); if(dlg.exec() == QDialog::Rejected) { return; } // get a pointer to the parent folder for later use. IDBFolder * target = dbfolder->getFolder(idTarget); if(target == nullptr) { return; } // --- at this point we should have all data to perform the copy without interruption --- // now iterate over all selected items QList items = selectedItems(); for(QTreeWidgetItem * item : items) { // only pick the project/other folders to copy folder = dynamic_cast(item); if((folder == nullptr) || (folder->type() < IDBFolder::eTypeGroup)) { continue; } IDBFolder * parent = dynamic_cast(folder->parent()); if((parent == nullptr) || (parent->getId() == idTarget) || (folder->getId() == idTarget)) { // skip operation if the current parent is the same as the traget parent continue; } dbfolder->copyFolder(folder->getId(), idTarget); } // tell the parent folder to show all changes target->update(); // tell other clients to show changes dbfolder->announceChange(); } void CGisListDB::slotMoveFolder() { CGisListDBEditLock lock(false, this, "slotMoveFolder"); // no way to continue if the current item is not a folder (we need the database it is attached to) IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } // get the database the folder is attached to IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder == nullptr) { return; } // next we need to get the target folder // NOTE: By pre-setting db and host, we limit the selection to the current database quint64 idTarget = 0; QString db = folder->getDBName(); QString host = folder->getDBHost(); CSelectDBFolder dlg(idTarget, db, host, this); if(dlg.exec() == QDialog::Rejected) { return; } // get a pointer to the parent folder for later use. IDBFolder * target = dbfolder->getFolder(idTarget); if(target == nullptr) { return; } // --- at this point we should have all data to perform the copy without interruption --- // now iterate over all selected items QList foldersToDelete; QList items = selectedItems(); for(QTreeWidgetItem * item : items) { // only pick the project/other folders to copy folder = dynamic_cast(item); if((folder == nullptr) || (folder->type() < IDBFolder::eTypeGroup)) { continue; } IDBFolder * parent = dynamic_cast(folder->parent()); if((parent == nullptr) || (parent->getId() == idTarget)) { // skip operation if the current parent is the same as the target parent continue; } if(target->isSiblingFrom(folder)) { QMessageBox::warning(this, tr("Bad operation...."), tr("The target folder is a subfolder of the one to move. This will not work."), QMessageBox::Abort); continue; } // copy to new location dbfolder->copyFolder(folder->getId(), idTarget); // Because some items can be parent of other selected items // it's a bad idea to delete them asap. Better collect them first. foldersToDelete << folder; } // iterate over all items to be deleted. for(IDBFolder * folder : foldersToDelete) { // Test if the item's parent is also in the list. // If it is skip it because it will be deleted together with it's parent. if(foldersToDelete.contains(dynamic_cast(folder->parent()))) { continue; } folder->remove(); delete folder; } // tell the parent folder to show all changes target->update(); // tell other clients to show changes dbfolder->announceChange(); } void CGisListDB::slotRenameFolder() { CGisListDBEditLock lock(false, this, "slotRenameFolder"); IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } // get the database the folder is attached to IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder == nullptr) { return; } QList items = selectedItems(); for(QTreeWidgetItem * item : items) { folder = dynamic_cast(item); if((folder == nullptr) || (folder->type() != IDBFolder::eTypeGroup)) { continue; } QString name1 = folder->getName(); QString name2 = QInputDialog::getText(this, tr("Folder name..."), tr("Rename folder:"), QLineEdit::Normal, name1); if(!name2.isEmpty() && (name1 != name2)) { folder->setName(name2); } } // tell other clients to show changes dbfolder->announceChange(); } void CGisListDB::slotDelLostFound() { CGisListDBEditLock lock(false, this, "slotDelLostFound"); CDBFolderLostFound * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } int res = QMessageBox::question(this, tr("Remove items..."), tr("Are you sure you want to delete all items from Lost&Found? This will remove them permanently."), QMessageBox::Ok|QMessageBox::No); if(res != QMessageBox::Ok) { return; } CCanvas::setOverrideCursor(Qt::WaitCursor, "slotDelLostFound"); folder->clear(); CCanvas::restoreOverrideCursor("slotDelLostFound"); IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder) { dbfolder->announceChange(); } } void CGisListDB::slotDelLostFoundItem() { CGisListDBEditLock lock(false, this, "slotDelLostFoundItem"); int res = QMessageBox::question(this, tr("Remove items..."), tr("Are you sure you want to delete all selected items from Lost&Found? This will remove them permanently."), QMessageBox::Ok|QMessageBox::No); if(res != QMessageBox::Ok) { return; } CCanvas::setOverrideCursor(Qt::WaitCursor, "slotDelLostFoundItem"); QSet folders; QList delItems; QList items = selectedItems(); for(QTreeWidgetItem * item : items) { CDBItem * dbItem = dynamic_cast(item); if(dbItem == nullptr) { continue; } CDBFolderLostFound * folder = dynamic_cast(dbItem->parent()); if(folder == nullptr) { continue; } if(folder->delItem(dbItem)) { delItems << dbItem; folders << folder; } } qDeleteAll(delItems); for(CDBFolderLostFound* folder : folders) { folder->update(); IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder) { dbfolder->announceChange(); } } CCanvas::restoreOverrideCursor("slotDelLostFoundItem"); } void CGisListDB::slotItemExpanded(QTreeWidgetItem * item) { CGisListDBEditLock lock(true, this, "slotItemExpanded"); IDBFolder * folder = dynamic_cast(item); if(folder == nullptr) { return; } folder->expanding(); } void CGisListDB::slotDelItem() { CGisListDBEditLock lock(false, this, "slotDelItem"); int last = QMessageBox::NoButton; QSet folders; QList dbItems; QSet dbFolders; QList items = selectedItems(); for(QTreeWidgetItem * item : items) { CDBItem * dbItem = dynamic_cast(item); if(dbItem == nullptr) { continue; } IDBFolder * folder = dynamic_cast(dbItem->parent()); if(folder == nullptr) { continue; } if(last != QMessageBox::YesToAll) { QString msg = tr("Are you sure you want to delete '%1' from folder '%2'?").arg(dbItem->text(CGisListDB::eColumnName)).arg(folder->text(CGisListDB::eColumnName)); last = QMessageBox::question(CMainWindow::getBestWidgetForParent(), tr("Delete..."), msg, QMessageBox::YesToAll|QMessageBox::Cancel|QMessageBox::Ok|QMessageBox::No, QMessageBox::Ok); } if(last == QMessageBox::No) { continue; } if(last == QMessageBox::Cancel) { return; } dbItem->remove(); folders << folder; dbItems << dbItem; dbFolders << folder->getDBFolder(); } qDeleteAll(dbItems); for(IDBFolderSql * dbFolder : dbFolders) { dbFolder->updateLostFound(); dbFolder->announceChange(); } // tell all folders to update their statistics and waypoint/track correlations for(IDBFolder * folder : folders) { folder->updateItemsOnWks(); } } void CGisListDB::slotItemChanged(QTreeWidgetItem * item, int column) { if(isInternalEdit) { return; } CGisListDBEditLock lock(true, this, "slotItemChanged"); if(column == CGisListDB::eColumnCheckbox) { IDBFolder * folder = dynamic_cast(item); if(folder != nullptr) { folder->toggle(); // tell folder to update its statistics and waypoint/track correlations folder->updateItemsOnWks(); return; } CDBItem * dbItem = dynamic_cast(item); if(dbItem != nullptr) { dbItem->toggle(); // tell folder to update its statistics and waypoint/track correlations folder = dynamic_cast(dbItem->parent()); if(folder) { folder->updateItemsOnWks(); } return; } } } void CGisListDB::slotUpdateDatabase() { CGisListDBEditLock lock(true, this, "slotUpdateDatabase"); QList items = selectedItems(); for(QTreeWidgetItem* item : items) { IDBFolder * folder = dynamic_cast(item); if(folder == nullptr) { continue; } if(folder->type() == IDBFolder::eTypeDatabase) { folder->update(); CEvtD2WReload * evt = new CEvtD2WReload(folder->getDBName()); CGisWorkspace::self().postEventForWks(evt); } } } void CGisListDB::slotSearchDatabase() { CGisListDBEditLock lock(false, this, "slotSearchDatabase"); IDBFolder * db = dynamic_cast(currentItem()); if(db == nullptr) { return; } isInternalEdit--; dlgSearch = new CSearchDatabase(*db,this); connect(dlgSearch.data(), &CSearchDatabase::sigItemChanged, this, &CGisListDB::slotItemChanged); dlgSearch->exec(); delete dlgSearch; isInternalEdit++; } void CGisListDB::slotReadyRead() { CGisListDBEditLock lock(true, this, "slotReadyRead"); while(socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); QDataStream stream(&datagram, QIODevice::ReadOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); quint32 msgId; quint32 tan; qint32 id; QString driver; QString dbName; QString dbHost; stream >> msgId >> tan >> id >> driver >> dbName >> dbHost; if((lastTan == tan) || (msgId != 0)) { continue; } lastTan = tan; // check for our own message if(id == CMainWindow::self().id) { continue; } qDebug() << "Receive database update from:" << sender << senderPort; qDebug() << "with" << "tan:" << lastTan << "app ID:" << id << "driver:" << driver << "DB name:" << dbName << "DB host:" << dbHost; IDBFolderSql * folder = getDataBase(dbName, dbHost); if(folder) { folder->update(); CEvtD2WReload * evt = new CEvtD2WReload(folder->getDBName()); CGisWorkspace::self().postEventForWks(evt); } } } void CGisListDB::slotExportToGpx() { CGisListDBEditLock lock(false, this, "slotExportToGpx"); IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } folder->exportToGpx(); } void CGisListDB::slotImport() { CGisListDBEditLock lock(false, this, "slotImport"); IDBFolder * folder = dynamic_cast(currentItem()); if(folder == nullptr) { return; } SETTINGS; QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString(); QString filter = cfg.value("Paths/lastGisFilter", IGisProject::filedialogAllSupported).toString(); QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Import GIS Data..."), path, IGisProject::filedialogLoadFilters, &filter); if(filenames.isEmpty()) { return; } for(const QString& filename : filenames) { CDBProject * prjDb = new CDBProject(filename, folder, nullptr); if(prjDb->isValid()) { prjDb->save(); } delete prjDb; } IDBFolderSql * dbfolder = folder->getDBFolder(); if(dbfolder) { dbfolder->announceChange(); } path = QFileInfo(filenames.first()).absolutePath(); cfg.setValue("Paths/lastGisPath", path); cfg.setValue("Paths/lastGisFilter", filter); } qmapshack-1.10.0/src/gis/IGisWorkspace.ui000644 001750 000144 00000010533 13204504054 021343 0ustar00oeichlerxusers000000 000000 IGisWorkspace 0 0 402 500 Form 0 0 0 0 0 3 3 Opacity Change the opacity of all GIS Items on the map. 100 10 Qt::Horizontal Filter false Qt::Vertical Qt::CustomContextMenu true QAbstractItemView::InternalMove QAbstractItemView::ExtendedSelection 20 20 14 100 Name :/icons/32x32/Filter.png:/icons/32x32/Filter.png Clear Filter :/icons/32x32/Apply.png:/icons/32x32/Apply.png Setup Filter CGisListWks QTreeWidget
gis/CGisListWks.h
actionClearFilter triggered() lineFilter clear() -1 -1 228 34
qmapshack-1.10.0/src/gis/CGisWorkspace.h000644 001750 000144 00000027515 13216234261 021162 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CGISWORKSPACE_H #define CGISWORKSPACE_H #include "ui_IGisWorkspace.h" #include #include #include #include "db/IDBFolder.h" #include "gis/IGisItem.h" #include "gis/rte/router/IRouter.h" class CGisDraw; class IGisProject; enum event_types_e { eEvtD2WReqInfo = QEvent::User + 1 ,eEvtD2WShowFolder = QEvent::User + 2 ,eEvtD2WHideFolder = QEvent::User + 3 ,eEvtD2WShowItems = QEvent::User + 4 ,eEvtD2WHideItems = QEvent::User + 5 ,eEvtD2WUpdateLnF = QEvent::User + 6 ,eEvtD2WUpdateItems = QEvent::User + 7 ,eEvtD2WReload = QEvent::User + 8 ,eEvtW2DAckInfo = QEvent::User + 100 ,eEvtW2DCreate = QEvent::User + 101 ,eEvtA2WCutTrk = QEvent::User + 200 ,eEvtA2WSave = QEvent::User + 201 }; struct evt_item_t { evt_item_t(quint64 id, quint32 type) : id(id), type(type) { } quint64 id; quint32 type; }; class CEvtD2WReqInfo : public QEvent { public: CEvtD2WReqInfo(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WReqInfo)), id(id), db(db) { } quint64 id; QString db; }; class CEvtD2WShowFolder : public QEvent { public: CEvtD2WShowFolder(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WShowFolder)), id(id), db(db) { } quint64 id; QString db; }; class CEvtD2WHideFolder : public QEvent { public: CEvtD2WHideFolder(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WHideFolder)), id(id), db(db) { } quint64 id; QString db; }; class CEvtD2WShowItems : public QEvent { public: CEvtD2WShowItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WShowItems)), id(id), db(db) { } /// if true only the items in the list are loaded. Any other item loaded but not part of the list will be removed. bool addItemsExclusively = false; quint64 id; QString db; QList items; }; class CEvtD2WHideItems : public QEvent { public: CEvtD2WHideItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WHideItems)), id(id), db(db) { } quint64 id; QString db; QSet keys; }; class CEvtW2DAckInfo : public QEvent { public: CEvtW2DAckInfo(Qt::CheckState checkState, quint64 id, const QString& db, const QString& host) : QEvent(QEvent::Type(eEvtW2DAckInfo)) , checkState(checkState) , id(id) , db(db) , host(host) { } CEvtW2DAckInfo(quint64 id, const QString& db, const QString& host) : QEvent(QEvent::Type(eEvtW2DAckInfo)) , id(id) , db(db) , host(host) { } Qt::CheckState checkState = Qt::Unchecked; bool updateLostFound = false; quint64 id; QString db; QString host; QSet keysChildren; }; class CEvtD2WUpdateLnF : public QEvent { public: CEvtD2WUpdateLnF(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WUpdateLnF)), id(id), db(db) { } quint64 id; QString db; }; class CEvtW2DCreate : public QEvent { public: CEvtW2DCreate(const QString& name, IDBFolder::type_e type, quint64 id, const QString& db, const QString& host) : QEvent(QEvent::Type(eEvtW2DCreate)) , name(name) , type(type) , idParent(id) , db(db) , host(host) { } QString name; IDBFolder::type_e type; quint64 idParent; quint64 idChild = 0; QString db; QString host; }; class CEvtD2WUpdateItems : public QEvent { public: CEvtD2WUpdateItems(quint64 id, const QString& db) : QEvent(QEvent::Type(eEvtD2WUpdateItems)), id(id), db(db) { } quint64 id; QString db; }; class CEvtD2WReload : public QEvent { public: CEvtD2WReload(const QString& db) : QEvent(QEvent::Type(eEvtD2WReload)), db(db) { } QString db; }; class CEvtA2WCutTrk : public QEvent { public: CEvtA2WCutTrk(const IGisItem::key_t& key) : QEvent(QEvent::Type(eEvtA2WCutTrk)), key(key) { } const IGisItem::key_t key; }; class CEvtA2WSave : public QEvent { public: CEvtA2WSave(const QString& key) : QEvent(QEvent::Type(eEvtA2WSave)), key(key) { } const QString key; }; class CGisWorkspace : public QWidget, private Ui::IGisWorkspace { Q_OBJECT public: static CGisWorkspace& self() { return *pSelf; } virtual ~CGisWorkspace(); void loadGisProject(const QString& filename); /** @brief Draw all loaded data in the workspace that is visible This method is called from The CGisDraw thread. The thread has to make sure that everything is thread safe. @param p the painter to be used @param viewport the viewport in units of rad @param gis the draw context to be used */ void draw(QPainter& p, const QPolygonF &viewport, CGisDraw *gis); /** @brief Receive the current mouse position Iterate over all projects and pass the position @param pos the mouse position on the screen in pixel */ void mouseMove(const QPointF& pos); /** @brief Draw all data that is time variant and can't wait for a full update This method is called directly from the main thread's paintEvent() method. @param p the painter to be used @param viewport the viewport in units of rad @param gis the draw context to be used */ void fastDraw(QPainter& p, const QRectF& viewport, CGisDraw *gis); /** @brief Get items close to the given point Note: Do not store the pointers of items permanently as they can become invalid once you reach the main event loop again. Store the key instead. @param pos the position in pixel @param items an empty item list that will get filled with temporary pointers */ void getItemsByPos(const QPointF& pos, QList &items); /** @brief Get items matching the given area @param area a rectangle in screen pixel coordinates @param flags flag field with IGisItem::selection_e flags set @param items a list to receive the temporary pointers to the found items */ void getItemsByArea(const QRectF& area, IGisItem::selflags_t flags, QList &items); /** @brief Find first item with matching key @param key the item's key as it is returned from IGisItem::getKey() @return If no item is found 0 is returned. */ IGisItem * getItemByKey(const IGisItem::key_t &key); void getItemsByKeys(const QList& keys, QList& items); void getNogoAreas(QVector &areas); /** @brief Delete all items with matching key from workspace @param key the item's key as it is returned from IGisItem::getKey() */ void delItemByKey(const IGisItem::key_t &key); void delItemsByKey(const QList &keys); /** @brief Edit / view item details @param key the item's key as it is returned from IGisItem::getKey() */ void editItemByKey(const IGisItem::key_t &key); /** @brief Select a project and add a copy of the item to the project @param key the item's key as it is returned from IGisItem::getKey() */ void copyItemByKey(const IGisItem::key_t &key); /** @brief Select a project and add a copy of all items in the list @param keys a list of item keys to copy */ void copyItemsByKey(const QList &keys); /** @brief Clone waypoint and move clone @param key the item's key as it is returned from IGisItem::getKey() */ void projWptByKey(const IGisItem::key_t &key); /** @brief Move waypoint via mouse @param key the item's key as it is returned from IGisItem::getKey() */ void moveWptByKey(const IGisItem::key_t &key); /** @brief Add a new waypoint by Position @param pt the position in [?] */ void addWptByPos(QPointF pt, const QString& label = QString::Null(), const QString& desc = QString::Null()) const; void toggleWptBubble(const IGisItem::key_t &key); void deleteWptRadius(const IGisItem::key_t &key); void toggleWptNogoArea(const IGisItem::key_t &key); void editWptRadius(const IGisItem::key_t &key); /** @brief Set user focus to track @param yes true if focus is set @param key the item's key as it is returned from IGisItem::getKey() */ void focusTrkByKey(bool yes, const IGisItem::key_t &key); void focusRteByKey(bool yes, const IGisItem::key_t &key); void convertRouteToTrack(const IGisItem::key_t &key); void cutTrkByKey(const IGisItem::key_t &key); void editTrkByKey(const IGisItem::key_t &key); void reverseTrkByKey(const IGisItem::key_t &key); /** @brief Combine all tracks in a given track's project This will collect all tracks in a project and pass them to the track combine dialog. @param keyTrk the key of the first track */ void combineTrkByKey(const IGisItem::key_t &keyTrk); /** @brief Combine al tracks in the given list of keys. @param keys a list of GIS item keys */ void combineTrkByKey(const QList& keys, const QList &keysPreSel); void activityTrkByKey(const QList& keys); void rangeTrkByKey(const IGisItem::key_t &key); void copyTrkWithWptByKey(const IGisItem::key_t &key); void editRteByKey(const IGisItem::key_t& key); void calcRteByKey(const IGisItem::key_t& key); void resetRteByKey(const IGisItem::key_t& key); void editAreaByKey(const IGisItem::key_t &key); void makeRteFromWpt(const QList& keys); void changeWptSymByKey(const QList& keys, const QString& sym); /** @brief Select a project via dialog If a new project name is entered a new project is created. Else the pointer to an existing project is passed back. @return 0 if no project was selected. */ IGisProject * selectProject(); void postEventForWks(QEvent * event); void setOpacity(qreal val); void applyFilter(); signals: void sigChanged(); public slots: void slotSaveAll(); void slotWksItemSelectionReset(); private slots: void slotSetGisLayerOpacity(int val); void slotFilter(const QString& str); void slotSetupFilter(); void slotWksItemSelectionChanged(); void slotWksItemPressed(QTreeWidgetItem * item); private: friend class CMainWindow; CGisWorkspace(QMenu * menuProject, QWidget * parent); static CGisWorkspace * pSelf; /** The item key of last item pressed in the workspace list. The key will be reset by getItemsByPos() which is used by the mouse object to find items close by for highlight. */ IGisItem::key_t keyWksSelection; }; #endif //CGISWORKSPACE_H qmapshack-1.10.0/src/gis/ISetupFilter.ui000644 001750 000144 00000002530 13135304116 021206 0ustar00oeichlerxusers000000 000000 ISetupFilter 0 0 123 78 Form true 3 3 3 3 3 Apply filter to name only complete text qmapshack-1.10.0/src/gis/CGisListWks.h000644 001750 000144 00000012647 13216234261 020624 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CGISLISTWKS_H #define CGISLISTWKS_H #include "gis/prj/IGisProject.h" #include #include #include struct action_t; class QAction; class CSearchGoogle; class IGisProject; class CDBProject; class IDeviceWatcher; class QActionGroup; class CGisListWks : public QTreeWidget { Q_OBJECT public: CGisListWks(QWidget * parent); virtual ~CGisListWks(); enum column_e { eColumnIcon = 0 ,eColumnCheckBox = eColumnIcon ,eColumnDecoration = eColumnIcon ,eColumnName = 1 }; void setExternalMenu(QMenu * project); bool hasProject(IGisProject *project); IGisProject * getProjectByKey(const QString& key); CDBProject * getProjectById(quint64 id, const QString& db); bool event(QEvent * e) override; void addProject(IGisProject *proj); void removeDevice(const QString& key); public slots: void slotLoadWorkspace(); signals: void sigChanged(); void sigItemDeleted(); protected: void dragMoveEvent(QDragMoveEvent *e) override; void dropEvent(QDropEvent *e) override; private slots: void slotSaveWorkspace(); void slotContextMenu(const QPoint& point); void slotSaveProject(); void slotSaveAsProject(); void slotSaveAsStrictGpx11Project(); void slotEditPrj(); void slotCloseProject(); void slotDeleteProject(); void slotShowOnMap(); void slotHideFrMap(); void slotItemDoubleClicked(QTreeWidgetItem * item, int); void slotItemChanged(QTreeWidgetItem * item, int column); void slotEditItem(); void slotDeleteItem(); void slotBubbleWpt(); void slotNogoAreaWpt(); void slotDelRadiusWpt(); void slotEditRadiusWpt(); void slotProjWpt(); void slotMoveWpt(); void slotFocusTrk(bool on); void slotEditTrk(); void slotReverseTrk(); void slotCombineTrk(); void slotRangeTrk(); void slotActivityTrk(); void slotCopyTrkWithWpt(); void slotFocusRte(bool on); void slotCalcRte(); void slotResetRte(); void slotEditRte(); void slotRte2Trk(); void slotEditArea(); void slotAddEmptyProject(); void slotCloseAllProjects(); void slotSearchGoogle(bool on); void slotCopyItem(); void slotSyncWksDev(); void slotSyncDevWks(); void slotRteFromWpt(); void slotSyncDB(); void slotSetSortMode(IGisProject::sorting_folder_e mode, bool checked); void slotCopyProject(); void slotSymWpt(); void slotAutoSaveProject(bool on); private: void configDB(); void initDB(); void migrateDB(int version); void migrateDB1to2(); void migrateDB2to3(); void setVisibilityOnMap(bool visible); QAction * addSortAction(QMenu * menu, QActionGroup *actionGroup, const QString& icon, const QString& text, IGisProject::sorting_folder_e mode); QSqlDatabase db; QMenu * menuProjectWks; QAction * actionSave; QAction * actionSaveAs; QAction * actionSaveAsStrict; QAction * actionAutoSave; QAction * actionCopyPrj; QAction * actionEditPrj; QAction * actionCloseProj; QAction * actionShowOnMap; QAction * actionHideFrMap; QAction * actionSyncWksDev; QAction * actionSyncDB; QAction * actionSortByTime; QAction * actionSortByName; QActionGroup * actionGroup; QMenu * menuProjectDev; QAction * actionDelProj; QAction * actionSyncDevWks; QMenu * menuProjectTrash; QMenu * menuItem; QMenu * menuItemTrk; QMenu * menuItemWpt; QMenu * menuItemRte; QMenu * menuItemOvl; QAction * actionEditDetails; QAction * actionCopyItem; QAction * actionDelete; QAction * actionBubbleWpt; QAction * actionDelRadiusWpt; QAction * actionNogoAreaWpt; QAction * actionEditRadiusWpt; QAction * actionProjWpt; QAction * actionMoveWpt; QAction * actionFocusTrk; QAction * actionEditTrk; QAction * actionReverseTrk; QAction * actionCombineTrk; QAction * actionRangeTrk; QAction * actionActivityTrk; QAction * actionCopyTrkWithWpt; QAction * actionFocusRte; QAction * actionCalcRte; QAction * actionResetRte; QAction * actionEditRte; QAction * actionRte2Trk; QAction * actionEditArea; QAction * actionRteFromWpt; QAction * actionSymWpt; QMenu * menuNone = nullptr; QPointer searchGoogle; bool saveOnExit = true; qint32 saveEvery = 5; IDeviceWatcher * deviceWatcher = nullptr; bool blockSorting = false; }; #endif //CGISLISTWKS_H qmapshack-1.10.0/src/gis/search/000755 001750 000144 00000000000 13216664445 017553 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/search/CSearchGoogle.h000644 001750 000144 00000002725 13216234143 022363 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSEARCHGOOGLE_H #define CSEARCHGOOGLE_H #include "gis/prj/IGisProject.h" #include #include class CGisListWks; class QLineEdit; class CSearchGoogle : public QObject, public IGisProject { Q_OBJECT public: CSearchGoogle(CGisListWks * parent); virtual ~CSearchGoogle(); private slots: void slotChangeSymbol(); void slotStartSearch(); void slotRequestFinished(QNetworkReply* reply); private: QLineEdit * edit; QAction * actSymbol; QNetworkAccessManager networkAccessManager; }; #endif //CSEARCHGOOGLE_H qmapshack-1.10.0/src/gis/search/CSearchGoogle.cpp000644 001750 000144 00000011714 13216234137 022717 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisListWks.h" #include "gis/WptIcons.h" #include "gis/search/CSearchGoogle.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CSettings.h" #include "helpers/CWptIconDialog.h" #include #include #include CSearchGoogle::CSearchGoogle(CGisListWks * parent) : IGisProject(eTypeGoogle, "", parent) { QPointF focus; SETTINGS; QString symName = cfg.value("Search/symbol","Default").toString(); parent->takeTopLevelItem(parent->indexOfTopLevelItem(this)); parent->insertTopLevelItem(0, this); edit = new QLineEdit(parent); actSymbol = edit->addAction(getWptIconByName(symName, focus), QLineEdit::TrailingPosition); actSymbol->setObjectName(symName); connect(actSymbol, &QAction::triggered, this, &CSearchGoogle::slotChangeSymbol); parent->setItemWidget(this, CGisListWks::eColumnName, edit); connect(edit, &QLineEdit::returnPressed, this, &CSearchGoogle::slotStartSearch); connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &CSearchGoogle::slotRequestFinished); setIcon(CGisListWks::eColumnDecoration, QIcon("://icons/32x32/SearchGoogle.png")); } CSearchGoogle::~CSearchGoogle() { } void CSearchGoogle::slotChangeSymbol() { CWptIconDialog dlg(actSymbol); dlg.exec(); SETTINGS; cfg.setValue("Search/symbol", actSymbol->objectName()); } void CSearchGoogle::slotStartSearch() { qDeleteAll(takeChildren()); QString addr = edit->text(); QUrl url("http://maps.googleapis.com"); url.setPath("/maps/api/geocode/xml"); QUrlQuery urlQuery; urlQuery.addQueryItem("address",addr.replace(" ","+")); urlQuery.addQueryItem("sensor","false"); url.setQuery(urlQuery); QNetworkRequest request; request.setUrl(url); networkAccessManager.get(request); edit->setEnabled(false); } void CSearchGoogle::slotRequestFinished(QNetworkReply* reply) { edit->setEnabled(true); if(reply->error() != QNetworkReply::NoError) { reply->deleteLater(); return; } QByteArray data = reply->readAll(); reply->deleteLater(); if(data.isEmpty()) { return; } QString status; QDomDocument xml; xml.setContent(data); // qDebug() << xml.toString(); QDomElement root = xml.documentElement(); if(root.tagName() != "GeocodeResponse") { status = tr("Unknown response"); QTreeWidgetItem * item = new QTreeWidgetItem(this); item->setText(CGisListWks::eColumnName, status); item->setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/Error.png")); return; } status = root.namedItem("status").toElement().text(); if(status != "OK") { status = tr("Error: "); status += root.namedItem("error_message").toElement().text(); QTreeWidgetItem * item = new QTreeWidgetItem(this); item->setText(CGisListWks::eColumnName, status); item->setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/Error.png")); return; } { QDomNodeList xmlEntries = root.elementsByTagName("result"); const qint32 N = xmlEntries.size(); if(N) { for(int i = 0; i < N; i++) { QString address; QDomElement xmlEntry = xmlEntries.item(i).toElement(); QDomElement xmlAddress = xmlEntry.namedItem("formatted_address").toElement(); if(xmlAddress.isElement()) { address = xmlAddress.text(); } QDomNode xmlGeometry = xmlEntry.namedItem("geometry"); QDomNode xmlLocation = xmlGeometry.namedItem("location"); qreal lon = xmlLocation.namedItem("lng").toElement().text().toDouble(); qreal lat = xmlLocation.namedItem("lat").toElement().text().toDouble(); new CGisItemWpt(QPointF(lon,lat), address, actSymbol->objectName(), this); } } } setExpanded(true); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } qmapshack-1.10.0/src/gis/db/000755 001750 000144 00000000000 13216664445 016673 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/db/macros.h000644 001750 000144 00000002650 13216234143 020317 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef MACROS_H #define MACROS_H #define DB_VERSION 6 #define NO_CMD ((void)0) #define QUERY_EXEC(cmd) \ if(!query.exec()) \ { \ qWarning() << "Execution of SQL-Statement `" << query.lastQuery() << "` failed:"; \ qWarning() << query.lastError(); \ cmd; \ } #define QUERY_RUN(stmt, cmd) \ if(!query.exec(stmt)) \ { \ qWarning() << "Execution of SQL-Statement `" << query.lastQuery() << "` failed:"; \ qWarning() << query.lastError(); \ cmd; \ } #endif //MACROS_H qmapshack-1.10.0/src/gis/db/CDBItem.h000644 001750 000144 00000004121 13216234143 020235 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBITEM_H #define CDBITEM_H #include #include class IDBFolder; class QSqlDatabase; class CDBItem : public QTreeWidgetItem { Q_DECLARE_TR_FUNCTIONS(CDBItem) public: CDBItem(QSqlDatabase& db, quint64 id, IDBFolder * parent); virtual ~CDBItem() = default; /** @brief Get the database id @return The ID value used by the database */ quint64 getId() const { return id; } /** @brief Get the item key This is not the full blown QMapShack item key with project and device key. It's just the item key. @return The string with the item key */ const QString& getKey() const { return key; } /** @brief Send show/hide events to the workspace */ void toggle(); /** @brief Delete the folder/item relation in the database */ void remove(); /** @brief Update the time the item is in the lost & found folder */ void updateAge(); private: friend bool sortByTime(CDBItem * item1, CDBItem * item2); QSqlDatabase& db; quint64 id; int type = 0; QString key; QDateTime date; }; #endif //CDBITEM_H qmapshack-1.10.0/src/gis/db/CSearchDatabase.cpp000644 001750 000144 00000020221 13216234137 022320 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBFolderGroup.h" #include "gis/db/CDBFolderOther.h" #include "gis/db/CDBFolderProject.h" #include "gis/db/CDBItem.h" #include "gis/db/CSearchDatabase.h" #include "gis/db/IDBFolder.h" #include "gis/db/macros.h" #include #include CSearchDatabase::CSearchDatabase(IDBFolder &dbFolder, CGisListDB *parent) : QDialog(parent) , dbFolder(dbFolder) { setupUi(this); labelName->setText(tr("Search database '%1':").arg(dbFolder.getDBName())); connect(pushSearch, &QPushButton::clicked, this, &CSearchDatabase::slotSearch); connect(pushClose, &QPushButton::clicked, this, &CSearchDatabase::accept); connect(treeResult, &QTreeWidget::itemChanged, this, &CSearchDatabase::slotItemChanged); } void CSearchDatabase::slotItemChanged(QTreeWidgetItem * item, int column) { if((column != CGisListDB::eColumnCheckbox) || internalEdit) { return; } IDBFolder * folder = dynamic_cast(item); if(folder != nullptr) { Qt::CheckState checkState = item->checkState(column); const int N = folder->childCount(); for(int i = 0; i < N; i++) { IDBFolder * childFolder = dynamic_cast(folder->child(i)); if(childFolder != nullptr) { childFolder->setCheckState(CGisListDB::eColumnCheckbox, checkState); } CDBItem * childItem = dynamic_cast(folder->child(i)); if(childItem != nullptr) { childItem->setCheckState(CGisListDB::eColumnCheckbox, checkState); } } } else { emit sigItemChanged(item, column); } } void CSearchDatabase::slotSearch() { internalEdit = true; treeResult->clear(); QSqlDatabase& db = dbFolder.getDb(); QSqlQuery query(db); dbFolder.search(lineQuery->text(), query); QMap folders; while(query.next()) { quint64 itemId = query.value(0).toULongLong(); QSqlQuery query2(db); query2.prepare("SELECT t1.id, t1.type FROM folders AS t1 WHERE id=(SELECT parent FROM folder2item WHERE child=:id)"); query2.bindValue(":id", itemId); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); continue; } while(query2.next()) { quint64 folderId = query2.value(0).toULongLong(); quint32 type = query2.value(1).toUInt(); IDBFolder * folder = nullptr; if(!folders.contains(folderId)) { switch(type) { case IDBFolder::eTypeProject: folder = new CDBFolderProject(db, folderId, 0); break; case IDBFolder::eTypeOther: folder = new CDBFolderOther(db, folderId, 0); break; default: continue; } folders[folderId] = folder; addWithParentFolders(treeResult, folder, folders, db); } else { folder = folders[folderId]; } CDBItem * item = new CDBItem(db, itemId, folder); item->setCheckState(CGisListDB::eColumnCheckbox, Qt::Unchecked); } } treeResult->expandAll(); treeResult->header()->resizeSections(QHeaderView::ResizeToContents); internalEdit = false; } void CSearchDatabase::addWithParentFolders(QTreeWidget * result, IDBFolder * child, QMap& folders, QSqlDatabase& db) { QSqlQuery query(db); query.prepare("SELECT t1.id, t1.type FROM folders AS t1 WHERE id=(SELECT parent FROM folder2folder WHERE child=:id)"); query.bindValue(":id", child->getId()); QUERY_EXEC(return ); while(query.next()) { quint64 folderId = query.value(0).toULongLong(); quint32 type = query.value(1).toUInt(); if(!folders.contains(folderId)) { IDBFolder * folder = nullptr; switch(type) { case IDBFolder::eTypeProject: folder = new CDBFolderProject(db, folderId, 0); break; case IDBFolder::eTypeOther: folder = new CDBFolderOther(db, folderId, 0); break; case IDBFolder::eTypeGroup: folder = new CDBFolderGroup(db, folderId, 0); break; default: ; } if(folder != nullptr) { folders[folderId] = folder; folder->addChild(child); addWithParentFolders(result, folder, folders, db); } else { result->addTopLevelItem(child); } } else { folders[folderId]->addChild(child); } } } bool CSearchDatabase::event(QEvent * e) { switch(e->type()) { case eEvtW2DAckInfo: { CEvtW2DAckInfo * evt = (CEvtW2DAckInfo*)e; // check for matching database if(evt->db == dbFolder.getDBName()) { if(!evt->host.isEmpty()) { if(dbFolder.getDBHost() != evt->host) { break; } } } internalEdit = true; // iterate over all top level items and their children to check active items. const int N = treeResult->topLevelItemCount(); for(int i = 0; i < N; i++) { IDBFolder * folder = dynamic_cast(treeResult->topLevelItem(i)); if(folder) { updateFolder(folder, evt); } } internalEdit = false; break; } } return QDialog::event(e); } void CSearchDatabase::updateFolder(IDBFolder * folder, CEvtW2DAckInfo * evt) { const int N = folder->childCount(); for(int i = 0; i < N; i++) { IDBFolder * folder1 = dynamic_cast(folder->child(i)); if(folder1 != nullptr) { updateFolder(folder1, evt); continue; } } if(folder->getId() != evt->id) { return; } int nItems = 0; int nChecked = 0; for(int i = 0; i < N; i++) { CDBItem * item = dynamic_cast(folder->child(i)); if(item != nullptr) { nItems++; if(evt->keysChildren.contains(item->getKey())) { nChecked++; item->setCheckState(CGisListDB::eColumnCheckbox, Qt::Checked); } else { item->setCheckState(CGisListDB::eColumnCheckbox, Qt::Unchecked); } } } if(folder->type() > IDBFolder::eTypeGroup) { if(nChecked == nItems) { folder->setCheckState(CGisListDB::eColumnCheckbox, Qt::Checked); } else if(nChecked > 0) { folder->setCheckState(CGisListDB::eColumnCheckbox, Qt::PartiallyChecked); } else { folder->setCheckState(CGisListDB::eColumnCheckbox, Qt::Unchecked); } } } qmapshack-1.10.0/src/gis/db/CSetupFolder.h000644 001750 000144 00000002633 13216234143 021373 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETUPFOLDER_H #define CSETUPFOLDER_H #include "gis/db/IDBFolder.h" #include "ui_ISetupFolder.h" #include class CSetupFolder : public QDialog, private Ui::ISetupFolder { Q_OBJECT public: CSetupFolder(IDBFolder::type_e& type, QString& name, bool groupAllowed, QWidget * parent); virtual ~CSetupFolder(); public slots: void accept() override; private slots: void slotNameChanged(const QString& text); private: IDBFolder::type_e& type; QString& name; }; #endif //CSETUPFOLDER_H qmapshack-1.10.0/src/gis/db/CSelectDBFolder.cpp000644 001750 000144 00000006565 13216234137 022266 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/db/CDBFolderMysql.h" #include "gis/db/CDBFolderSqlite.h" #include "gis/db/CSelectDBFolder.h" #include "helpers/CSettings.h" #include CSelectDBFolder::CSelectDBFolder(quint64 &id, QString &db, QString &host, QWidget *parent) : QDialog(parent) , id(id) , db(db) , host(host) { setupUi(this); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); SETTINGS; cfg.beginGroup("Database"); QStringList names = cfg.value("names").toStringList(); cfg.beginGroup("Entries"); for(const QString &name : names) { if(!db.isEmpty() && (db != name)) { continue; } cfg.beginGroup(name); QString type = cfg.value("type", "SQLite").toString(); if(type == "SQLite") { QString filename = cfg.value("filename","").toString(); new CDBFolderSqlite(filename, name, treeWidget); } if(type == "MySQL") { QString server = cfg.value("server","").toString(); QString port = cfg.value("port","").toString(); QString user = cfg.value("user","").toString(); QString passwd = cfg.value("passwd","").toString(); bool noPasswd = cfg.value("noPasswd",false).toBool(); new CDBFolderMysql(server, port, user, passwd, noPasswd, name, treeWidget); } cfg.endGroup(); // name } cfg.endGroup(); // Database connect(treeWidget, &QTreeWidget::itemExpanded, this, &CSelectDBFolder::slotItemExpanded); connect(treeWidget, &QTreeWidget::itemSelectionChanged, this, &CSelectDBFolder::slotItemSelectionChanged); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelectDBFolder"); } CSelectDBFolder::~CSelectDBFolder() { CCanvas::restoreOverrideCursor("~CSelectDBFolder"); } void CSelectDBFolder::slotItemExpanded(QTreeWidgetItem * item) { IDBFolder * folder = dynamic_cast(item); if(nullptr != folder) { folder->expanding(); } } void CSelectDBFolder::slotItemSelectionChanged() { IDBFolder * folder = dynamic_cast(treeWidget->currentItem()); if(folder) { id = folder->getId(); db = folder->getDBName(); host = folder->getDBHost(); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } else { id = -1; db.clear(); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } } qmapshack-1.10.0/src/gis/db/CSetupDatabase.h000644 001750 000144 00000003544 13216234143 021666 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETUPDATABASE_H #define CSETUPDATABASE_H #include "ui_ISetupDatabase.h" #include class CGisListDB; class CSetupDatabase : public QDialog, private Ui::ISetupDatabase { Q_OBJECT public: CSetupDatabase(CGisListDB& parent); virtual ~CSetupDatabase(); bool isSqlite() const {return radioSqlite->isChecked(); } bool isMysql() const {return radioMysql->isChecked(); } bool noPasswd() const; QString getName() const {return lineName->text(); } QString getFilename() const {return labelFilename->text(); } QString getServer() const {return lineServer->text(); } QString getPort() const {return linePort->text(); } QString getUser() const {return lineUser->text(); } QString getPasswd() const {return linePasswd->text(); } public slots: void accept() override; private slots: void slotNewDB(); void slotOpenDB(); void slotUpdateButtonBox(); private: CGisListDB& list; }; #endif //CSETUPDATABASE_H qmapshack-1.10.0/src/gis/db/CDBFolderGroup.h000644 001750 000144 00000002232 13216234143 021570 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDERGROUP_H #define CDBFOLDERGROUP_H #include "gis/db/IDBFolder.h" class CDBFolderGroup : public IDBFolder { public: CDBFolderGroup(QSqlDatabase &db, quint64 key, QTreeWidgetItem * parent); virtual ~CDBFolderGroup(); }; #endif //CDBFOLDERGROUP_H qmapshack-1.10.0/src/gis/db/ISelectSaveAction.ui000644 001750 000144 00000011750 12705713523 022535 0ustar00oeichlerxusers000000 000000 ISelectSaveAction 0 0 471 340 0 0 Copy item... QFormLayout::ExpandingFieldsGrow 0 0 Replace existing item TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 0 0 Do not replace item TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 0 0 Add a clone 0 0 The clone's name will be appended with '_Clone' true 0 0 And for all other items, too. Use item: TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Horizontal Qt::Horizontal Qt::Horizontal Replace with: qmapshack-1.10.0/src/gis/db/CDBFolderProject.cpp000644 001750 000144 00000002361 13216234137 022443 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/db/CDBFolderProject.h" CDBFolderProject::CDBFolderProject(QSqlDatabase& db, quint64 key, QTreeWidgetItem * parent) : IDBFolder(true, db, eTypeProject, key, parent) { setIcon(CGisListDB::eColumnCheckbox,QIcon("://icons/32x32/PathGreen.png")); setupFromDB(); } CDBFolderProject::~CDBFolderProject() { } qmapshack-1.10.0/src/gis/db/CSearchDatabase.h000644 001750 000144 00000003343 13216234143 021770 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSEARCHDATABASE_H #define CSEARCHDATABASE_H #include "ui_ISearchDatabase.h" #include class CGisListDB; class IDBFolder; class QSqlDatabase; class CSearchDatabase : public QDialog, private Ui::ISearchDatabase { Q_OBJECT public: CSearchDatabase(IDBFolder& db, CGisListDB * parent); virtual ~CSearchDatabase() = default; bool event(QEvent * e) override; signals: void sigItemChanged(QTreeWidgetItem * item, int column); private slots: void slotSearch(); void slotItemChanged(QTreeWidgetItem * item, int column); private: void addWithParentFolders(QTreeWidget * result, IDBFolder * folder, QMap &folders, QSqlDatabase &sqlDB); void updateFolder(IDBFolder * folder, CEvtW2DAckInfo * evt); IDBFolder& dbFolder; bool internalEdit = false; }; #endif //CSEARCHDATABASE_H qmapshack-1.10.0/src/gis/db/CDBFolderGroup.cpp000644 001750 000144 00000002345 13216234137 022133 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/db/CDBFolderGroup.h" CDBFolderGroup::CDBFolderGroup(QSqlDatabase& db, quint64 key, QTreeWidgetItem * parent) : IDBFolder(false, db, eTypeGroup, key, parent) { setIcon(CGisListDB::eColumnCheckbox,QIcon("://icons/32x32/PathBlue.png")); setupFromDB(); } CDBFolderGroup::~CDBFolderGroup() { } qmapshack-1.10.0/src/gis/db/CDBProject.h000644 001750 000144 00000010541 13216234143 020750 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBPROJECT_H #define CDBPROJECT_H #include "gis/prj/IGisProject.h" #include class CEvtD2WShowItems; class CEvtD2WHideItems; class CQlgtFolder; class IDBFolder; class CDBProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CDBProject) public: CDBProject(CGisListWks * parent); CDBProject(const QString &dbName, quint64 id, CGisListWks * parent); CDBProject(const QString &filename, IDBFolder *parentFolder, CGisListWks *parent); CDBProject(CQlgtFolder& folder); virtual ~CDBProject(); /** @brief Restore database link after the project has been restored from binary storage. Typically this is done after the project has been restored in the workspace on application's startup. */ void restoreDBLink(); bool canSave() const override { return true; } bool save() override; quint64 getId() const { return id; } QString getDBName() const { return db.connectionName(); } QString getDBHost() const { return db.hostName(); } /** @brief Serialize object out of a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ QDataStream& operator<<(QDataStream& stream) override; /** @brief Serialize object into a QDataStream See CGisSerialization.cpp for implementation @param stream the binary data stream @return The stream object. */ QDataStream& operator>>(QDataStream& stream) const override; /** @brief Send a CEvtW2DAckInfo event to the database view */ void postStatus(bool updateLostFound); /** @brief Load items from the database into the project @param evt the event sent by the database view */ void showItems(CEvtD2WShowItems * evt); /** @brief Remove items from the project Note: This is not the same as for the other projects. The relation in the database is still valid. The item is just not selected to be shown. @param evt the event sent by the database view */ void hideItems(CEvtD2WHideItems * evt); void update(); protected: /** @brief Setup the items text with the name and suffix @param defaultName */ void setupName(const QString &defaultName) override; /** * @brief Save item's data into an existing database entry * * @param item the item itself * @param idItem the 64bit database key */ void updateItem(IGisItem *&item, quint64 idItem, QSqlQuery& query); int checkForAction1(IGisItem * item, quint64 &itemId, int &lastResult, QSqlQuery& query); int checkForAction2(IGisItem * item, quint64 &itemId, QString &hashItem, QSqlQuery& query); /** * @brief Add item to database * @param item the item itself * @return The new 64bit database key */ quint64 insertItem(IGisItem * item, QSqlQuery& query); QSqlDatabase db; quint64 id = 0; enum reasons_e { eReasonCancel = 0 , eReasonQueryFail = -1 , eReasonUnexpected = -2 , eReasonConflict = -3 }; enum action_e { eActionNone = 0x00 , eActionLink = 0x01 , eActionUpdate = 0x02 , eActionInsert = 0x04 , eActionClone = 0x08 , eActionReload = 0x10 }; Qt::CheckState checkState = Qt::Unchecked; }; #endif //CDBPROJECT_H qmapshack-1.10.0/src/gis/db/ISetupFolder.ui000644 001750 000144 00000005430 12516204664 021574 0ustar00oeichlerxusers000000 000000 ISetupFolder 0 0 400 170 Database Folder... Folder name Group :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png Project :/icons/32x32/PathGreen.png:/icons/32x32/PathGreen.png true Other :/icons/32x32/PathOrange.png:/icons/32x32/PathOrange.png Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISetupFolder accept() 248 254 157 274 buttonBox rejected() ISetupFolder reject() 316 260 286 274 qmapshack-1.10.0/src/gis/db/IDB.h000644 001750 000144 00000002766 13216234143 017441 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDB_H #define IDB_H #include #include #include class IDB { Q_DECLARE_TR_FUNCTIONS(IDB) public: IDB(); virtual ~IDB(); QSqlDatabase& getDb() { return db; } static quint64 getLastInsertID(QSqlDatabase& db, const QString& table); bool isUsable() const { return db.isOpen(); } protected: static QMap references; QSqlDatabase db; void setup(const QString& connectionName); bool setupDB(QString &error); virtual bool initDB() = 0; virtual bool migrateDB(int version) = 0; }; #endif //IDB_H qmapshack-1.10.0/src/gis/db/CDBFolderOther.h000644 001750 000144 00000002231 13216234143 021554 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDEROTHER_H #define CDBFOLDEROTHER_H #include "gis/db/IDBFolder.h" class CDBFolderOther : public IDBFolder { public: CDBFolderOther(QSqlDatabase &db, quint64 key, QTreeWidgetItem *parent); virtual ~CDBFolderOther(); }; #endif //CDBFOLDEROTHER_H qmapshack-1.10.0/src/gis/db/CDBFolderMysql.h000644 001750 000144 00000003635 13216234143 021611 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDERMYSQL_H #define CDBFOLDERMYSQL_H #include "gis/db/IDBFolderSql.h" #include "gis/db/IDBMysql.h" class CDBFolderMysql : public IDBFolderSql, public IDBMysql { Q_DECLARE_TR_FUNCTIONS(CDBFolderMysql) public: CDBFolderMysql(const QString &server, const QString &port, const QString &user, const QString &passwd, bool noPasswd, const QString &name, QTreeWidget *parent); virtual ~CDBFolderMysql() = default; const QString& getServer() const {return server; } const QString& getPort() const {return port; } const QString& getUser() const {return user; } const QString& getPasswd() const {return passwd; } bool hasNoPasswd() const { return noPasswd; } QString getDBInfo() const; bool search(const QString& str, QSqlQuery& query) override; void copyFolder(quint64 child, quint64 parent) override; private: const QString server; const QString port; const QString user; const QString passwd; const bool noPasswd; }; #endif //CDBFOLDERMYSQL_H qmapshack-1.10.0/src/gis/db/CDBProject.cpp000644 001750 000144 00000066222 13216234137 021315 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisDatabase.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBProject.h" #include "gis/db/CSelectSaveAction.h" #include "gis/db/IDB.h" #include "gis/db/macros.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/CDetailsPrj.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include #include CDBProject::CDBProject(CGisListWks * parent) : IGisProject(eTypeDb, "", parent) , id(0) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/DBProject.png")); } CDBProject::CDBProject(const QString& dbName, quint64 id, CGisListWks *parent) : IGisProject(eTypeDb, dbName, parent) , id(id) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/DBProject.png")); db = QSqlDatabase::database(dbName); QSqlQuery query(db); query.prepare("SELECT date, name, data FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); query.next(); QString date = query.value(0).toString(); QString name = query.value(1).toString(); QByteArray data = query.value(2).toByteArray(); if(data.isEmpty()) { // Make sure the key is reset key.clear(); metadata.name = name; // The time format can differ by database type if(date.contains('T')) { metadata.time = QDateTime::fromString(date,"yyyy-MM-ddThh:mm:ss"); } else { metadata.time = QDateTime::fromString(date,"yyyy-MM-dd hh:mm:ss"); } // Still no valid date? Bad as we need it to produce an unique key. if(!metadata.time.isValid()) { metadata.time = QDateTime::currentDateTimeUtc(); } query.prepare("UPDATE folders SET keyqms=:keyqms WHERE id=:id"); query.bindValue(":keyqms", getKey()); query.bindValue(":id", id); QUERY_EXEC(return ); } else { QDataStream in(&data, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); *this << in; filename = dbName; } setupName(name); setToolTip(CGisListWks::eColumnName, getInfo()); updateItems(); valid = true; } CDBProject::CDBProject(const QString& filename, IDBFolder * parentFolder, CGisListWks *parent) : IGisProject(eTypeDb, parentFolder->getDBName(), parent) , db(parentFolder->getDb()) { IGisProject * prjIn = IGisProject::create(filename, nullptr); if(prjIn == nullptr) { QMessageBox::information(CMainWindow::self().getBestWidgetForParent(), tr("Failed to load..."), tr("Can't load file \"%1\" . It will be skipped.").arg(QFileInfo(filename).completeBaseName()), QMessageBox::Ok); return; } // test if the project has been imported already QSqlQuery query(db); query.prepare("SELECT id FROM folders WHERE keyqms=:keyqms"); query.bindValue(":keyqms", prjIn->getKey()); QUERY_EXEC(return ); if(query.next()) { QMessageBox::information(CMainWindow::self().getBestWidgetForParent(), tr("Project already in database..."), tr("The project \"%1\" has already been imported into the database. It will be skipped.").arg(prjIn->getName()), QMessageBox::Ok); return; } // create a new folder in the database id = parentFolder->addFolder(IDBFolder::eTypeProject, prjIn->getName()); query.prepare("UPDATE folders SET keyqms=:keyqms WHERE id=:id"); query.bindValue(":keyqms", prjIn->getKey()); query.bindValue(":id", id); QUERY_EXEC(return ); // copy data key = prjIn->getKey(); metadata = prjIn->getMetadata(); QList items = prjIn->takeChildren(); addChildren(items); // set change indication else the item will not be saved for(QTreeWidgetItem * item : items) { IGisItem * gisItem = dynamic_cast(item); if(gisItem) { gisItem->updateDecoration(IGisItem::eMarkChanged, IGisItem::eMarkNone); } } valid = true; } CDBProject::~CDBProject() { CEvtW2DAckInfo * info = new CEvtW2DAckInfo(Qt::Unchecked, getId(), getDBName(), getDBHost()); CGisDatabase::self().postEventForDb(info); } void CDBProject::restoreDBLink() { db = QSqlDatabase::database(filename); QSqlQuery query(db); query.prepare("SELECT id FROM folders WHERE keyqms=:keyqms"); query.bindValue(":keyqms", getKey()); QUERY_EXEC(return ); if(query.next()) { id = query.value(0).toULongLong(); setupName("----"); valid = true; } } void CDBProject::setupName(const QString &defaultName) { IGisProject::setupName(defaultName); // look for a parent folder's name to be used as suffix QSqlQuery query(db); query.prepare("SELECT t1.name FROM folders AS t1 WHERE id=(SELECT parent FROM folder2folder WHERE child=:id) AND (t1.type=:type1 OR t1.type=:type2)"); query.bindValue(":id", id); query.bindValue(":type1", IDBFolder::eTypeGroup); query.bindValue(":type2", IDBFolder::eTypeProject); QUERY_EXEC(); if(query.next()) { nameSuffix = query.value(0).toString(); } setText(CGisListWks::eColumnName, getNameEx()); } void CDBProject::postStatus(bool updateLostFound) { // collect the keys of all child items and post them to the database view CEvtW2DAckInfo * info = new CEvtW2DAckInfo(getId(), getDBName(), getDBHost()); bool changedItems = false; const int N = childCount(); for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(child(n)); if(item) { info->keysChildren << item->getKey().item; changedItems |= item->isChanged(); } } // check if all items are loaded if(type != eTypeLostFound) { QSqlQuery query(db); query.prepare("SELECT COUNT(*) FROM folder2item WHERE parent=:parent"); query.bindValue(":parent", getId()); QUERY_EXEC(); query.next(); const int nChildrenAttached = query.value(0).toInt(); if((nChildrenAttached != 0) && (nChildrenAttached != info->keysChildren.count())) { checkState = Qt::PartiallyChecked; } else { checkState = Qt::Checked; } } else { checkState = Qt::Checked; } info->checkState = checkState; info->updateLostFound = updateLostFound; // update item counters and track/waypoint correlation // updateItems(); <--- don't! this is causing a crash if(!changedItems) { setText(CGisListWks::eColumnDecoration,autoSave ? "A" : ""); } CGisDatabase::self().postEventForDb(info); } int CDBProject::checkForAction2(IGisItem * item, quint64 &itemId, QString& hashItem, QSqlQuery &query) { int action = eActionNone; query.prepare("SELECT hash, last_user, last_change FROM items WHERE id=:id"); query.bindValue(":id", itemId); QUERY_EXEC(throw eReasonQueryFail); if(query.next()) { QString hash = query.value(0).toString(); QString user = query.value(1).toString(); QString date = query.value(2).toString(); if(hash == hashItem) { // there seems to be no difference return action; } hashItem = hash; QString msg = tr( "The item %1 has been changed by %2 (%3). \n\n" "To solve this conflict you can create and save a clone, force your version or drop " "your version and take the one from the database" ).arg(item->getNameEx()).arg(user).arg(date); QMessageBox msgBox(QMessageBox::Question, tr("Conflict with database..."), msg, QMessageBox::NoButton, CMainWindow::self().getBestWidgetForParent()); QAbstractButton* pButClone = msgBox.addButton(tr("Clone && Save"), QMessageBox::YesRole); QAbstractButton* pButForce = msgBox.addButton(tr("Force Save"), QMessageBox::ApplyRole); QAbstractButton* pButUpdate = msgBox.addButton(tr("Take remote"), QMessageBox::DestructiveRole); msgBox.addButton(QMessageBox::Abort); CProgressDialog::setAllVisible(false); msgBox.exec(); CProgressDialog::setAllVisible(true); if(msgBox.clickedButton() == pButClone) { action = eActionClone; } else if(msgBox.clickedButton() == pButForce) { action = eActionUpdate; } else if(msgBox.clickedButton() == pButUpdate) { action = eActionReload; } } else { // item has been removed. By throwing eReasonConflict // the save procedure is restarted for the item and // the item should be inserted into the database. throw eReasonConflict; } return action; } void CDBProject::updateItem(IGisItem *&item, quint64 idItem, QSqlQuery &query) { // serialize complete history of item QByteArray data; QDataStream in(&data, QIODevice::WriteOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in << item->getHistory(); // prepare icon to be saved QBuffer buffer; buffer.open(QIODevice::ReadWrite); QPixmap pixmap = item->getIcon(); pixmap.save(&buffer, "PNG"); buffer.seek(0); QString hashInDb = item->getLastDatabaseHash(); query.prepare("UPDATE items SET type=:type, keyqms=:keyqms, icon=:icon, name=:name, date=:date, comment=:comment, data=:data, hash=:hash WHERE id=:id AND hash=:oldhash"); query.bindValue(":type", item->type()); query.bindValue(":keyqms", item->getKey().item); query.bindValue(":icon", buffer.data()); query.bindValue(":name", item->getName()); query.bindValue(":date", item->getTimestamp()); query.bindValue(":comment", item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText)); query.bindValue(":data", data); query.bindValue(":hash", item->getHash()); query.bindValue(":id", idItem); query.bindValue(":oldhash", hashInDb); QUERY_EXEC(throw eReasonQueryFail); if(query.numRowsAffected()) { // the update has been successful. // set current hash as database hash. item->setLastDatabaseHash(idItem, db); } else { // there are two reasons why an update does not affect a row // 1) the hash is different because another user changed the item // 2) the id was not found because another user removed the item // 3) the items was completely identical, therefore no row was affected. int action = checkForAction2(item, idItem, hashInDb, query); switch(action) { case eActionClone: { IGisItem * item2 = item->createClone(); quint64 idItem = insertItem(item2, query); delete item; item = item2; query.prepare("INSERT INTO folder2item (parent, child) VALUES (:parent, :child)"); query.bindValue(":parent", id); query.bindValue(":child", idItem); QUERY_EXEC(throw eReasonQueryFail); break; } case eActionUpdate: { // hashInDb has been updated by checkForAction2() by the one stored in the database // therefore the update should succeed now. query.prepare("UPDATE items SET type=:type, keyqms=:keyqms, icon=:icon, name=:name, date=:date, comment=:comment, data=:data, hash=:hash WHERE id=:id AND hash=:oldhash"); query.bindValue(":type", item->type()); query.bindValue(":keyqms", item->getKey().item); query.bindValue(":icon", buffer.data()); query.bindValue(":name", item->getName()); query.bindValue(":date", item->getTimestamp()); query.bindValue(":comment", item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText)); query.bindValue(":data", data); query.bindValue(":hash", item->getHash()); query.bindValue(":id", idItem); query.bindValue(":oldhash", hashInDb); QUERY_EXEC(throw eReasonQueryFail); if(query.numRowsAffected()) { item->setLastDatabaseHash(idItem, db); } else { // in the case someone updated the item between calling // checkForAction2() and this update our update fails. // In this case we throw eReasonConflict to restart the // save procedure for this item. throw eReasonConflict; } break; } case eActionReload: item->updateFromDB(idItem, db); break; } } } quint64 CDBProject::insertItem(IGisItem * item, QSqlQuery &query) { quint64 idItem = 0; // serialize complete history of item QByteArray data; QDataStream in(&data, QIODevice::WriteOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in << item->getHistory(); // prepare icon to be saved QBuffer buffer; buffer.open(QIODevice::ReadWrite); QPixmap pixmap = item->getIcon(); pixmap.save(&buffer, "PNG"); buffer.seek(0); query.prepare("INSERT INTO items (type, keyqms, icon, name, date, comment, data, hash) VALUES (:type, :keyqms, :icon, :name, :date, :comment, :data, :hash)"); query.bindValue(":type", item->type()); query.bindValue(":keyqms", item->getKey().item); query.bindValue(":icon", buffer.data()); query.bindValue(":name", item->getName()); query.bindValue(":date", item->getTimestamp()); query.bindValue(":comment", item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText)); query.bindValue(":data", data); query.bindValue(":hash", item->getHash()); QUERY_EXEC(throw eReasonQueryFail); if(query.numRowsAffected()) { idItem = IDB::getLastInsertID(db, "items"); if(idItem == 0) { qDebug() << "childId equals 0. bad."; throw eReasonUnexpected; } item->setLastDatabaseHash(idItem, db); } else { throw eReasonConflict; } return idItem; } int CDBProject::checkForAction1(IGisItem * item, quint64& itemId, int& lastResult, QSqlQuery &query) { int action = eActionNone; // test if item exists in database quint32 itemType = 0; query.prepare("SELECT id, type FROM items WHERE keyqms=:keyqms"); query.bindValue(":keyqms", item->getKey().item); QUERY_EXEC(throw eReasonQueryFail); if(query.next()) { itemId = query.value(0).toULongLong(); itemType = query.value(1).toUInt(); // check if relation already exists. query.prepare("SELECT id FROM folder2item WHERE parent=:parent AND child=:child"); query.bindValue(":parent", id); query.bindValue(":child", itemId); QUERY_EXEC(throw eReasonQueryFail); if(!query.next()) { // item is already in database but folder relation does not exit int result = lastResult; if(lastResult == CSelectSaveAction::eResultNone) { // Build the dialog to ask for user action IGisItem * item1 = IGisItem::newGisItem(itemType, itemId, db, nullptr); if(nullptr == item1) { qDebug() << "no item to compare!?."; throw eReasonUnexpected; } CSelectSaveAction dlg(item, item1, CMainWindow::self().getBestWidgetForParent()); dlg.exec(); result = dlg.getResult(); if(dlg.allOthersToo()) { lastResult = result; } } if(result == CSelectSaveAction::eResultNone) { // no decision by user, cancel operation. // this is different to a skip as a skip will // just skip saving the data, but the item to folder // link will be still processed. return eActionNone; } // the item is in the database and has no relation to the folder -> update only if the user confirms. action = eActionLink; switch(result) { case CSelectSaveAction::eResultSave: action |= eActionUpdate; break; case CSelectSaveAction::eResultSkip: action |= eActionReload; break; case CSelectSaveAction::eResultClone: action |= eActionClone; break; } } else { // the item is in the database and has a relation to the folder -> simply update item action = eActionUpdate; } } else { action = eActionInsert|eActionLink; } return action; } bool CDBProject::save() { QSqlQuery query(db); bool stop = false; bool success = true; int lastResult = CSelectSaveAction::eResultNone; // check if project is still part of the database query.prepare("SELECT keyqms FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return false); if(!query.next()) { QMessageBox::critical(CMainWindow::self().getBestWidgetForParent() , tr("Missing folder...") , tr("Failed to save project. The folder has been deleted in the database.") , QMessageBox::Abort ); return false; } int N = childCount(); PROGRESS_SETUP(tr("Save ..."), 0, N, CMainWindow::getBestWidgetForParent()); for(int i = 0; (i < N) && !stop; i++) { try { PROGRESS(i, throw eReasonCancel); IGisItem * item = dynamic_cast(child(i)); if(nullptr == item) { continue; } // skip unchanged items if(!item->isChanged()) { continue; } quint64 idItem = 0; int action = checkForAction1(item, idItem, lastResult, query); if(action & eActionInsert) { idItem = insertItem(item, query); } if(action & eActionUpdate) { updateItem(item, idItem, query); } if(action & eActionReload) { item->updateFromDB(idItem, db); } if(action & eActionClone) { IGisItem * item2 = item->createClone(); idItem = insertItem(item2, query); delete item; item = item2; } if((action & eActionLink) && (idItem != 0)) { query.prepare("INSERT INTO folder2item (parent, child) VALUES (:parent, :child)"); query.bindValue(":parent", id); query.bindValue(":child", idItem); QUERY_EXEC(throw eReasonQueryFail); } item->updateDecoration(IGisItem::eMarkNone, IGisItem::eMarkChanged|IGisItem::eMarkNotPart|IGisItem::eMarkNotInDB); } catch(reasons_e reason) { CProgressDialog::setAllVisible(false); switch(reason) { case eReasonQueryFail: QMessageBox::critical(&progress, tr("Error"), tr("There was an unexpected database error:\n\n%1").arg(query.lastError().text()), QMessageBox::Abort); case eReasonCancel: case eReasonUnexpected: stop = true; success = false; break; case eReasonConflict: i--; break; } CProgressDialog::setAllVisible(true); } } // serialize metadata of project QByteArray data; QDataStream in(&data, QIODevice::WriteOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); *this >> in; // update folder entry in database query.prepare("UPDATE folders SET name=:name, comment=:comment, data=:data, sortmode=:sortmode WHERE id=:id"); query.bindValue(":name", getName()); query.bindValue(":comment", getInfo()); query.bindValue(":data", data); query.bindValue(":sortmode", getSortingFolder()); query.bindValue(":id", getId()); QUERY_EXEC(return false); postStatus(true); // update change flag updateDecoration(); return success; } void CDBProject::showItems(CEvtD2WShowItems * evt) { bool restoreDlgDetails = false; if(evt->addItemsExclusively) { restoreDlgDetails = !dlgDetails.isNull(); delete dlgDetails; qDeleteAll(takeChildren()); } for(const evt_item_t &item : evt->items) { IGisItem * gisItem = IGisItem::newGisItem(item.type, item.id, db, this); /* [Issue #72] Database/Workspace inconsistency in QMS 1.4.0 When an item with no key is loaded it is "healed". The healing will mark it as changed. To avoid this save all items that are marked as changed right after loading from the database. */ if(gisItem && gisItem->isChanged()) { bool success = true; try { QSqlQuery query(db); updateItem(gisItem, item.id, query); } catch(int) { success = false; } if(success) { gisItem->updateDecoration(IGisItem::eMarkNone, IGisItem::eMarkChanged); } } } sortItems(); postStatus(false); setToolTip(CGisListWks::eColumnName, getInfo()); if(restoreDlgDetails) { edit(); } } void CDBProject::hideItems(CEvtD2WHideItems * evt) { IGisItem::key_t key; key.project = getKey(); QMessageBox::StandardButtons last = QMessageBox::YesToAll; for(const QString &k : evt->keys) { key.item = k; delItemByKey(key, last); } postStatus(false); setToolTip(CGisListWks::eColumnName, getInfo()); } void CDBProject::update() { Qt::CheckState state = checkState; if(isChanged()) { QString msg = tr("The project '%1' is about to update itself from the database. However there are changes not saved.").arg(getName()); int res = QMessageBox::question(CMainWindow::self().getBestWidgetForParent(), tr("Save changes?"), msg, QMessageBox::Save|QMessageBox::Ignore|QMessageBox::Abort, QMessageBox::Save); if(res == QMessageBox::Abort) { return; } if(res == QMessageBox::Save) { if(!save()) { return; } } } // read project properties QSqlQuery query(db); query.prepare("SELECT date, name, data FROM folders WHERE id=:id"); query.bindValue(":id", getId()); QUERY_EXEC(return ); query.next(); QString name = query.value(1).toString(); QByteArray data = query.value(2).toByteArray(); if(!data.isEmpty()) { QDataStream in(&data, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); *this << in; filename = getDBName(); } setupName(name); setToolTip(CGisListWks::eColumnName, getInfo()); /* The further proceeding depends on the check state of the project. If the project is partially loaded we simply update all items. If it is completely loaded we reload it. */ if(state == Qt::Checked) { // get keys of all children attached to the project in the database query.prepare("SELECT id, type FROM items WHERE id IN (SELECT child FROM folder2item WHERE parent=:parent)"); query.bindValue(":parent", getId()); QUERY_EXEC(return ); CEvtD2WShowItems * evt = new CEvtD2WShowItems(getId(), getDBName()); evt->addItemsExclusively = true; while(query.next()) { evt->items << evt_item_t(query.value(0).toULongLong(), query.value(1).toUInt()); } CGisWorkspace::self().postEventForWks(evt); } else { // Iterate over all children and update const int N = childCount(); for(int i = 0; i < N; i++) { IGisItem * item = dynamic_cast(child(i)); if(item == nullptr) { continue; } const IGisItem::key_t& key = item->getKey(); // update item from database query.prepare("SELECT id FROM items WHERE keyqms=:keyqms"); query.bindValue(":keyqms", key.item); QUERY_EXEC(return ); if(query.next()) { // item is in the database quint64 idItem = query.value(0).toULongLong(); QSqlQuery query2(db); query2.prepare("SELECT id FROM folder2item WHERE parent=:parent AND child=:child"); query2.bindValue(":parent", getId()); query2.bindValue(":child", idItem); query2.exec(); if(query2.next()) { // item is connected to this project item->updateFromDB(idItem, db); item->updateDecoration(IGisItem::eMarkNone, IGisItem::eMarkChanged); } else { // item is not connected to this project item->updateFromDB(idItem, db); item->updateDecoration(IGisItem::eMarkNotPart|IGisItem::eMarkChanged, IGisItem::eMarkNone); } } else { // item is not in the database at all. item->updateDecoration(IGisItem::eMarkNotInDB|IGisItem::eMarkChanged, IGisItem::eMarkNone); } } postStatus(false); } updateDecoration(); } qmapshack-1.10.0/src/gis/db/CLostFoundProject.h000644 001750 000144 00000002477 13216234143 022411 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLOSTFOUNDPROJECT_H #define CLOSTFOUNDPROJECT_H #include "gis/db/CDBProject.h" #include class CLostFoundProject : public CDBProject { Q_DECLARE_TR_FUNCTIONS(CLostFoundProject) public: CLostFoundProject(const QString &dbName, CGisListWks * parent); virtual ~CLostFoundProject(); bool save() override { return false; } void updateFromDb(); }; #endif //CLOSTFOUNDPROJECT_H qmapshack-1.10.0/src/gis/db/CDBFolderProject.h000644 001750 000144 00000002245 13216234143 022106 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDERPROJECT_H #define CDBFOLDERPROJECT_H #include "gis/db/IDBFolder.h" class CDBFolderProject : public IDBFolder { public: CDBFolderProject(QSqlDatabase &db, quint64 key, QTreeWidgetItem *parent); virtual ~CDBFolderProject(); }; #endif //CDBFOLDERPROJECT_H qmapshack-1.10.0/src/gis/db/ISearchDatabase.ui000644 001750 000144 00000004446 12745644236 022207 0ustar00oeichlerxusers000000 000000 ISearchDatabase 0 0 545 492 Search... Qt::WheelFocus Type the word you want to search for and press the search button. If you enter 'word' a search with an exact match is done. If you enter 'word*', 'word' has to be at the beginning of a string. true Name Qt::Horizontal 40 20 Search Close qmapshack-1.10.0/src/gis/db/CSetupWorkspace.h000644 001750 000144 00000002342 13216234143 022113 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSETUPWORKSPACE_H #define CSETUPWORKSPACE_H #include "ui_ISetupWorkspace.h" #include class CSetupWorkspace : public QDialog, private Ui::ISetupWorkspace { Q_OBJECT public: CSetupWorkspace(QWidget * parent); virtual ~CSetupWorkspace(); public slots: void accept() override; }; #endif //CSETUPWORKSPACE_H qmapshack-1.10.0/src/gis/db/IExportDatabase.ui000644 001750 000144 00000006254 13022454561 022247 0ustar00oeichlerxusers000000 000000 IExportDatabase 0 0 600 400 Export database to GPX... ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png Export Path: 0 0 - GPX 1.1 without extensions Qt::Horizontal 40 20 false Start false Abort Close pushClose clicked() IExportDatabase reject() 349 366 199 194 qmapshack-1.10.0/src/gis/db/CDBFolderLostFound.h000644 001750 000144 00000002716 13216234143 022420 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDERLOSTFOUND_H #define CDBFOLDERLOSTFOUND_H #include "gis/db/IDBFolder.h" #include class CDBItem; class CDBFolderLostFound : public IDBFolder { Q_DECLARE_TR_FUNCTIONS(CDBFolderLostFound) public: CDBFolderLostFound(QSqlDatabase &db, QTreeWidgetItem *parent); virtual ~CDBFolderLostFound(); void update(CEvtW2DAckInfo * info) override; bool update() override; void expanding() override; void clear(); bool delItem(CDBItem * item); protected: void setupFromDB() override; }; #endif //CDBFOLDERLOSTFOUND_H qmapshack-1.10.0/src/gis/db/CDBFolderSqlite.cpp000644 001750 000144 00000005567 13216234137 022311 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/db/CDBFolderSqlite.h" #include "gis/db/macros.h" #include #include CDBFolderSqlite::CDBFolderSqlite(const QString& filename, const QString& name, QTreeWidget *parent) : IDBFolderSql(IDB::db, parent) , filename(filename) { setToolTip(CGisListDB::eColumnName, tr("All your data grouped by folders.")); setText(CGisListDB::eColumnName, name); if(setupDB(filename, name, error)) { setupFromDB(); setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/SQLite.png")); setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } else { IDB::db.close(); setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/SQLiteNoConn.png")); } } QString CDBFolderSqlite::getDBInfo() const { QString str = "
" + IDB::db.connectionName() + "

"; str += tr("SQLite Database") + "
"; QString path = IDB::db.databaseName(); #ifndef Q_OS_WIN if(path.startsWith(QDir::homePath())) { path = "~" + path.remove(0, QDir::homePath().length()); } #endif str += tr("File: ") + QString("%1").arg(path); if(!isUsable()) { str += "
" + tr("Error: ") + QString("%1").arg(error); } return str; } bool CDBFolderSqlite::search(const QString& str, QSqlQuery& query) { query.prepare("SELECT id FROM searchindex WHERE comment MATCH :str"); query.bindValue(":str", str); QUERY_EXEC(return false); return true; } void CDBFolderSqlite::copyFolder(quint64 child, quint64 parent) //override; { QSqlQuery query(IDB::db); query.prepare("INSERT INTO folder2folder (parent, child) SELECT :parent, :child WHERE NOT EXISTS (SELECT parent, child FROM folder2folder WHERE parent=:parent AND child=:child)"); query.bindValue(":parent", parent); query.bindValue(":child", child); QUERY_EXEC(return ); } qmapshack-1.10.0/src/gis/db/IDBFolder.cpp000644 001750 000144 00000044254 13216234137 021131 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListDB.h" #include "gis/CGisWorkspace.h" #include "gis/IGisItem.h" #include "gis/db/CDBFolderGroup.h" #include "gis/db/CDBFolderOther.h" #include "gis/db/CDBFolderProject.h" #include "gis/db/CDBItem.h" #include "gis/db/CExportDatabase.h" #include "gis/db/IDB.h" #include "gis/db/IDBFolder.h" #include "gis/db/IDBFolderSql.h" #include "gis/db/macros.h" #include IDBFolder::IDBFolder(bool isLoadable, QSqlDatabase& db, type_e type, quint64 id, QTreeWidgetItem *parent) : QTreeWidgetItem(parent, type) , db(db) , id(id) , isLoadable(isLoadable) { } IDBFolder::IDBFolder(bool isLoadable, QSqlDatabase& db, type_e type, quint64 id, QTreeWidget * parent) : QTreeWidgetItem(parent, type) , db(db) , id(id) , isLoadable(isLoadable) { } IDBFolder::~IDBFolder() { } bool IDBFolder::operator<(const QTreeWidgetItem &other) const { const IDBFolder * folder = dynamic_cast(&other); if(nullptr == folder) { return false; } return text(CGisListDB::eColumnName) < folder->text(CGisListDB::eColumnName); } IDBFolder * IDBFolder::createFolderByType(QSqlDatabase& db, int type, quint64 id, QTreeWidgetItem * parent) { switch(type) { case eTypeGroup: return new CDBFolderGroup(db, id, parent); case eTypeProject: return new CDBFolderProject(db, id, parent); case eTypeOther: return new CDBFolderOther(db, id, parent); default: return nullptr; } } QString IDBFolder::getDBName() const { return db.connectionName(); } QString IDBFolder::getDBHost() const { return db.hostName(); } QString IDBFolder::getName() const { return text(CGisListDB::eColumnName); } void IDBFolder::setName(const QString& name) { QSqlQuery query(db); query.prepare("UPDATE folders SET name=:name WHERE id=:id"); query.bindValue(":name", name); query.bindValue(":id", getId()); QUERY_EXEC(return ); setupFromDB(); } IDBFolderSql *IDBFolder::getDBFolder() { if(type() == eTypeDatabase) { return dynamic_cast(this); } IDBFolder * folder = dynamic_cast(parent()); if(nullptr != folder) { return folder->getDBFolder(); } return nullptr; } IDBFolder * IDBFolder::getFolder(quint64 idFolder) { if(id == idFolder) { return this; } const int N = childCount(); for(int n = 0; n < N; n++) { IDBFolder * folder1 = dynamic_cast(child(n)); if(nullptr == folder1) { return nullptr; } IDBFolder * folder2 = folder1->getFolder(idFolder); if(nullptr != folder2) { return folder2; } } return nullptr; } quint64 IDBFolder::addFolder(type_e type, const QString& name) { quint64 idChild = IDBFolder::addFolderToDb(type, name, id, db); if(idChild != 0) { createFolderByType(db, type, idChild, this); expanding(); } return idChild; } quint64 IDBFolder::addFolderToDb(type_e type, const QString& name, quint64 idParent, QSqlDatabase& db) { QSqlQuery query(db); query.prepare("INSERT INTO folders (name, type) VALUES (:name, :type)"); query.bindValue(":name", name); query.bindValue(":type", type); QUERY_EXEC(return 0); quint64 idChild = IDB::getLastInsertID(db, "folders"); if(idChild == 0) { qDebug() << "CGisListDB::slotAddFolder(): childId equals 0. bad."; return 0; } query.prepare("INSERT INTO folder2folder (parent, child) VALUES (:parent, :child)"); query.bindValue(":parent", idParent); query.bindValue(":child", idChild); QUERY_EXEC(return 0); return idChild; } void IDBFolder::expanding() { qDeleteAll(takeChildren()); addChildren(QSet(), false); CEvtD2WReqInfo * evt = new CEvtD2WReqInfo(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt); } void IDBFolder::update(CEvtW2DAckInfo * info) { if(info->id != id) { // forward call if not for local ID for(int i = 0; i < childCount(); i++) { IDBFolder * folder = dynamic_cast(child(i)); if(folder) { folder->update(info); } } return; } setCheckState(CGisListDB::eColumnCheckbox, info->checkState); QSqlQuery query(db); // update text and tooltip query.prepare("SELECT name, comment, sortmode FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); query.next(); setText(CGisListDB::eColumnName, query.value(0).toString()); setToolTip(CGisListDB::eColumnName, query.value(1).toString()); sortMode = query.value(2).toUInt(); setChildIndicator(); if(isExpanded()) { qDeleteAll(takeChildren()); addChildren(info->keysChildren, false); } } bool IDBFolder::update() { QSqlQuery query(db); // Step 0: check if folder is still in the database query.prepare("SELECT COUNT(*) FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return false); if(!query.next() || query.value(0).toInt() == 0) { qDebug() << text(CGisListDB::eColumnName) << query.value(0).toInt() << id; // return false to mark folder to be deleted return false; } // Step 1: get basic properties like name and key query.prepare("SELECT keyqms, name, comment, sortmode FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return false); query.next(); // update items look on the gui. key = query.value(0).toString(); setText(CGisListDB::eColumnName, query.value(1).toString()); setToolTip(CGisListDB::eColumnName, query.value(2).toString()); sortMode = query.value(3).toUInt(); // Step 2: Test for children. setChildIndicator(); // Nothing to do for folders not expanded if(!isExpanded()) { return true; } /* Step 3: Iterate over all child items. * * There might be new folders to add. This is done collecting all sub-folder IDs in * dbFoldersAdd. Remove every existing folder while iterating over all items. The * left overs are the folders to add. * * Update existing folders. If the update return s false the folder was removed from * the database or an error occurred. In both cases remove the folder item. * * Collect all items in dbItems. They will be removed and the item list is rebuilt * from scratch. */ QSet activeChildren; QList dbItems; QList dbFoldersDel; // get all folder IDs attached to this folder QList dbFoldersAdd; query.prepare("SELECT child FROM folder2folder WHERE parent=:parent"); query.bindValue(":parent", id); QUERY_EXEC(return false); while(query.next()) { dbFoldersAdd << query.value(0).toULongLong(); } const int N = childCount(); for(int i = 0; i < N; i++) { QTreeWidgetItem * item = child(i); // test for folder and update folder // remove the folder from the add list as it is already known // if the update returns false register it for removal IDBFolder * dbFolder = dynamic_cast(item); if(dbFolder != nullptr) { dbFoldersAdd.removeAll(dbFolder->getId()); if(dbFolder->update() == false) { dbFoldersDel << dbFolder; } continue; } CDBItem * dbItem = dynamic_cast(item); if(dbItem != nullptr) { if(dbItem->checkState(CGisListDB::eColumnCheckbox) == Qt::Checked) { activeChildren << dbItem->getKey(); } dbItems << dbItem; continue; } } // Step 4: Remove items and folders registered for removal. Add missing folders. Rebuild list of items. qDeleteAll(dbFoldersDel); qDeleteAll(dbItems); // add folders query.prepare("SELECT t1.child, t2.type FROM folder2folder AS t1, folders AS t2 WHERE t1.parent = :id AND t2.id = t1.child ORDER BY t2.id"); query.bindValue(":id", id); QUERY_EXEC(return false); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); quint32 typeChild = query.value(1).toInt(); if(dbFoldersAdd.contains(idChild)) { createFolderByType(db, typeChild, idChild, this); } } sortChildren(CGisListDB::eColumnName, Qt::AscendingOrder); // add children addChildren(activeChildren, true); return true; } void IDBFolder::toggle() { if(checkState(CGisListDB::eColumnCheckbox) == Qt::Checked) { CEvtD2WShowFolder * evt1 = new CEvtD2WShowFolder(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt1); QSqlQuery query(db); if(getId() == 0) { query.prepare("SELECT id, type FROM items AS t1 WHERE NOT EXISTS(SELECT * FROM folder2item WHERE child=t1.id) ORDER BY t1.type, t1.name"); } else { query.prepare("SELECT t1.child, t2.type FROM folder2item AS t1, items AS t2 WHERE t1.parent = :id AND t2.id = t1.child ORDER BY t2.id"); query.bindValue(":id", getId()); } QUERY_EXEC(return ); CEvtD2WShowItems * evt2 = new CEvtD2WShowItems(getId(), getDBName()); evt2->addItemsExclusively = true; while(query.next()) { evt2->items << evt_item_t(query.value(0).toULongLong(), query.value(1).toUInt()); } CGisWorkspace::self().postEventForWks(evt2); } else { CEvtD2WHideFolder * evt1 = new CEvtD2WHideFolder(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt1); } } void IDBFolder::remove() { IDBFolder * folder = dynamic_cast(parent()); if(nullptr == folder) { return; } remove(folder->getId(), getId()); CEvtD2WHideFolder * evt1 = new CEvtD2WHideFolder(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt1); } void IDBFolder::setupFromDB() { if(id == 0) { return; } QSqlQuery query(db); // get basic properties like name and key query.prepare("SELECT keyqms, name, comment, sortmode FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); query.next(); key = query.value(0).toString(); setText(CGisListDB::eColumnName, query.value(1).toString()); setToolTip(CGisListDB::eColumnName, query.value(2).toString()); sortMode = query.value(3).toUInt(); // check if folder has child folders (to set expand indicator) setChildIndicator(); // if the folder is loadable the checkbox has to be displayed and // an event to query the state has to be sent to the workspace if(isLoadable) { setCheckState(CGisListDB::eColumnCheckbox, Qt::Unchecked); CEvtD2WReqInfo * evt = new CEvtD2WReqInfo(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt); } } void IDBFolder::addChildren(const QSet& activeChildren, bool skipFolders) { QSqlQuery query(db); if(!skipFolders) { // folders 1st query.prepare("SELECT t1.child, t2.type FROM folder2folder AS t1, folders AS t2 WHERE t1.parent = :id AND t2.id = t1.child ORDER BY t2.id"); query.bindValue(":id", id); QUERY_EXEC(return ); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); quint32 typeChild = query.value(1).toInt(); createFolderByType(db, typeChild, idChild, this); } sortChildren(CGisListDB::eColumnName, Qt::AscendingOrder); } QList items; // tracks 2nd query.prepare("SELECT t1.child FROM folder2item AS t1, items AS t2 WHERE t1.parent = :id AND t2.id = t1.child AND t2.type=:type ORDER BY t2.id"); query.bindValue(":id", id); query.bindValue(":type", IGisItem::eTypeTrk); QUERY_EXEC(return ); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); CDBItem * item = new CDBItem(db, idChild, nullptr); item->setCheckState(CGisListDB::eColumnCheckbox, activeChildren.contains(item->getKey()) ? Qt::Checked : Qt::Unchecked); items << item; } addItemsSorted(items); // routes 3rd query.prepare("SELECT t1.child FROM folder2item AS t1, items AS t2 WHERE t1.parent = :id AND t2.id = t1.child AND t2.type=:type ORDER BY t2.id"); query.bindValue(":id", id); query.bindValue(":type", IGisItem::eTypeRte); QUERY_EXEC(return ); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); CDBItem * item = new CDBItem(db, idChild, nullptr); item->setCheckState(CGisListDB::eColumnCheckbox, activeChildren.contains(item->getKey()) ? Qt::Checked : Qt::Unchecked); items << item; } addItemsSorted(items); //waypoints 4th query.prepare("SELECT t1.child FROM folder2item AS t1, items AS t2 WHERE t1.parent = :id AND t2.id = t1.child AND t2.type=:type ORDER BY t2.id"); query.bindValue(":id", id); query.bindValue(":type", IGisItem::eTypeWpt); QUERY_EXEC(return ); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); CDBItem * item = new CDBItem(db, idChild, nullptr); item->setCheckState(CGisListDB::eColumnCheckbox, activeChildren.contains(item->getKey()) ? Qt::Checked : Qt::Unchecked); items << item; } addItemsSorted(items); // overlays 5th query.prepare("SELECT t1.child FROM folder2item AS t1, items AS t2 WHERE t1.parent = :id AND t2.id = t1.child AND t2.type=:type ORDER BY t2.id"); query.bindValue(":id", id); query.bindValue(":type", IGisItem::eTypeOvl); QUERY_EXEC(return ); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); CDBItem * item = new CDBItem(db, idChild, nullptr); item->setCheckState(CGisListDB::eColumnCheckbox, activeChildren.contains(item->getKey()) ? Qt::Checked : Qt::Unchecked); items << item; } addItemsSorted(items); } void IDBFolder::remove(quint64 idParent, quint64 idFolder) { QSqlQuery query(db); // delete this particular relation first query.prepare("DELETE FROM folder2folder WHERE parent=:parent AND child=:child"); query.bindValue(":parent", idParent); query.bindValue(":child", idFolder); QUERY_EXEC(); query.prepare("SELECT EXISTS(SELECT 1 FROM folder2folder WHERE child=:id LIMIT 1)"); query.bindValue(":id", idFolder); QUERY_EXEC(); // if there is no other relation delete the children, too. if(!query.next() || (query.value(0).toInt() == 0)) { query.prepare("SELECT child FROM folder2folder WHERE parent=:id"); query.bindValue(":id", idFolder); QUERY_EXEC(); while(query.next()) { remove(idFolder, query.value(0).toULongLong()); } // remove the child items relations query.prepare("DELETE FROM folder2item WHERE parent=:id"); query.bindValue(":id", idFolder); QUERY_EXEC(); // and remove the folder query.prepare("DELETE FROM folders WHERE id=:id"); query.bindValue(":id", idFolder); QUERY_EXEC() } } void IDBFolder::updateItemsOnWks() { CEvtD2WUpdateItems * evt = new CEvtD2WUpdateItems(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt); } void IDBFolder::setChildIndicator() { QSqlQuery query(db); // count folders linked to this folder query.prepare("SELECT COUNT(*) FROM folder2folder WHERE parent=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); query.next(); qint32 nFolders = query.value(0).toInt(); // count items linked to this folder query.prepare("SELECT COUNT(*) FROM folder2item WHERE parent=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); query.next(); qint32 nItems = query.value(0).toInt(); // set indicator according to items if(nFolders || nItems) { setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } else { setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); } } void IDBFolder::addItemsSorted(QList& items) { sortItems(items); for(CDBItem * item : items) { addChild(item); } items.clear(); } bool sortByName(CDBItem * item1, CDBItem * item2) { return item1->text(CGisListDB::eColumnName) < item2->text(CGisListDB::eColumnName); } bool sortByTime(CDBItem * item1, CDBItem * item2) { return item1->date < item2->date; } void IDBFolder::sortItems(QList& items) const { switch(sortMode) { case IGisProject::eSortFolderTime: qSort(items.begin(), items.end(), &sortByTime); break; case IGisProject::eSortFolderName: qSort(items.begin(), items.end(), &sortByName); break; } } bool IDBFolder::isSiblingFrom(IDBFolder * folder) const { if(folder->getId() == getId()) { return true; } IDBFolder * parentFolder = dynamic_cast(parent()); if(parentFolder != nullptr) { return parentFolder->isSiblingFrom(folder); } return false; } void IDBFolder::exportToGpx() { CExportDatabase dlg(getId(), getDb(), CMainWindow::self().getBestWidgetForParent()); dlg.exec(); } qmapshack-1.10.0/src/gis/db/CSetupWorkspace.cpp000644 001750 000144 00000004035 13216234137 022452 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "config.h" #include "gis/db/CSetupWorkspace.h" #include "helpers/CSettings.h" #include CSetupWorkspace::CSetupWorkspace(QWidget *parent) : QDialog(parent) { setupUi(this); SETTINGS; cfg.beginGroup("Database"); checkSaveOnExit->setChecked(cfg.value("saveOnExit", true).toBool()); spinSaveEvery->setValue(cfg.value("saveEvery",5).toInt()); checkDbUpdate->setChecked(cfg.value("listenUpdate", false).toBool()); linePort->setText(cfg.value("port", "34123").toString()); cfg.endGroup(); connect(checkSaveOnExit, &QCheckBox::toggled, spinSaveEvery, &QSpinBox::setEnabled); } CSetupWorkspace::~CSetupWorkspace() { } void CSetupWorkspace::accept() { SETTINGS; cfg.beginGroup("Database"); cfg.setValue("saveOnExit", checkSaveOnExit->isChecked()); cfg.setValue("saveEvery", spinSaveEvery->value()); cfg.setValue("listenUpdate", checkDbUpdate->isChecked()); cfg.setValue("port", linePort->text()); cfg.endGroup(); QMessageBox::information(this, tr("Setup database..."), tr("Changes will become active after an application's restart."), QMessageBox::Ok); QDialog::accept(); } qmapshack-1.10.0/src/gis/db/IDBFolderSql.cpp000644 001750 000144 00000011421 13216234137 021577 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListDB.h" #include "gis/db/CDBFolderLostFound.h" #include "gis/db/IDBFolderSql.h" #include "gis/db/macros.h" #include "helpers/CSettings.h" #include #include IDBFolderSql::IDBFolderSql(QSqlDatabase &db, QTreeWidget *parent) : IDBFolder(false, db, eTypeDatabase, 1, parent) { socket = new QUdpSocket(this); } void IDBFolderSql::expanding() { IDBFolder::expanding(); folderLostFound = new CDBFolderLostFound(db, nullptr); insertChild(0, folderLostFound); } void IDBFolderSql::updateLostFound() { if(folderLostFound) { folderLostFound->update(); } } bool IDBFolderSql::update() { QSqlQuery query(db); QList dbFoldersDel; /* Database folders are a bit special as there are no items. But a lost & found folder. * * As there can be folders removed from the database and new folders this is a bit tricky. * * dbFoldersAdd is filled with all folders IDs attached with the database folder. Now we * iterate over all existing items and remove their ID from dbFoldersAdd. Additionally * the folder item is updated. If the update returns false, the folders was removed from * the database or an error occurred. In both cases the item is registered for removal in * dbFoldersDel. * * When done with the iteration all folders registered for removal are deleted and the * new ones are created. Finally lost & found is updated. */ // get all folder IDs attached to this folder QList dbFoldersAdd; query.prepare("SELECT child FROM folder2folder WHERE parent=:parent"); query.bindValue(":parent", id); QUERY_EXEC(return false); while(query.next()) { dbFoldersAdd << query.value(0).toULongLong(); } const int N = childCount(); for(int i = 1; i < N; i++) { IDBFolder * folder = dynamic_cast(child(i)); if(folder) { dbFoldersAdd.removeAll(folder->getId()); if(!folder->update()) { dbFoldersDel << folder; } } } qDeleteAll(dbFoldersDel); // add folders query.prepare("SELECT t1.child, t2.type FROM folder2folder AS t1, folders AS t2 WHERE t1.parent = :id AND t2.id = t1.child ORDER BY t2.id"); query.bindValue(":id", id); QUERY_EXEC(return false); while(query.next()) { quint64 idChild = query.value(0).toULongLong(); quint32 typeChild = query.value(1).toInt(); if(dbFoldersAdd.contains(idChild)) { createFolderByType(db, typeChild, idChild, this); } } takeChild(0); sortChildren(CGisListDB::eColumnName, Qt::AscendingOrder); insertChild(0, folderLostFound); updateLostFound(); return true; } void IDBFolderSql::announceChange() const { SETTINGS; bool enabled = cfg.value("Database/listenUpdate", false).toBool(); if(!enabled) { return; } quint16 port = cfg.value("Database/port", UDP_PORT).toUInt(); QByteArray msg; QDataStream stream(&msg, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); quint32 tan = qrand(); stream << quint32(0); stream << tan; stream << CMainWindow::self().id; stream << db.driverName(); stream << getDBName(); stream << getDBHost(); QList netdevices = QNetworkInterface::allInterfaces(); for(const QNetworkInterface &netdevice : netdevices) { QList networks = netdevice.addressEntries(); for(const QNetworkAddressEntry &network : networks) { socket->writeDatagram(msg, network.broadcast(), port); socket->writeDatagram(msg, network.broadcast(), port); socket->writeDatagram(msg, network.broadcast(), port); } } } qmapshack-1.10.0/src/gis/db/CDBItem.cpp000644 001750 000144 00000011265 13216234137 020602 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBItem.h" #include "gis/db/IDBFolder.h" #include "gis/db/macros.h" #include CDBItem::CDBItem(QSqlDatabase &db, quint64 id, IDBFolder *parent) : QTreeWidgetItem(parent) , db(db) , id(id) { QSqlQuery query(db); query.prepare("SELECT type, keyqms, icon, name, date, comment FROM items WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(query.next()) { QPixmap pixmap; type = query.value(0).toInt(); key = query.value(1).toString(); pixmap.loadFromData(query.value(2).toByteArray(), "PNG"); setIcon(CGisListDB::eColumnCheckbox, pixmap); setText(CGisListDB::eColumnName, query.value(3).toString()); date = query.value(4).toDateTime(); // limit comment to 300 characters QString comment = query.value(5).toString(); if(comment.size() > 300) { comment = comment.left(297) + "..."; } setToolTip(CGisListDB::eColumnName, comment); } updateAge(); } void CDBItem::updateAge() { QSqlQuery query(db); query.prepare("SELECT trash FROM items WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(!query.next()) { return; } if((parent() != nullptr) && (parent()->type() == IDBFolder::eTypeLostFound)) { QString date = query.value(0).toString(); QDateTime timestamp; // The time format can differ by database type if(date.contains('T')) { timestamp = QDateTime::fromString(date,"yyyy-MM-ddThh:mm:ss"); } else { timestamp = QDateTime::fromString(date,"yyyy-MM-dd hh:mm:ss"); } if(timestamp.isValid()) { quint64 diff = QDateTime::currentDateTimeUtc().toTime_t() - timestamp.toTime_t(); if(diff < (60*60)) { setText(CGisListDB::eColumnTime, tr("%1 min.").arg(diff/60)); } else if(diff < (60*60*24)) { setText(CGisListDB::eColumnTime, tr("%1 h").arg(diff/(60*60))); } else { setText(CGisListDB::eColumnTime, tr("%1 days").arg(diff/(60*60*24))); } } } } void CDBItem::toggle() { IDBFolder * folder = dynamic_cast(parent()); if(nullptr == folder) { return; } if(checkState(CGisListDB::eColumnCheckbox) == Qt::Checked) { // make sure the project is shown on the workspace CEvtD2WShowFolder * evt1 = new CEvtD2WShowFolder(folder->getId(), folder->getDBName()); CGisWorkspace::self().postEventForWks(evt1); // tell the project to load the item from the database CEvtD2WShowItems * evt2 = new CEvtD2WShowItems(folder->getId(), folder->getDBName()); evt2->items << evt_item_t(id, type); CGisWorkspace::self().postEventForWks(evt2); } else { // tell the project to remove the item CEvtD2WHideItems * evt2 = new CEvtD2WHideItems(folder->getId(), folder->getDBName()); evt2->keys << key; CGisWorkspace::self().postEventForWks(evt2); } } void CDBItem::remove() { IDBFolder * folder = dynamic_cast(parent()); if(nullptr == folder) { return; } if(checkState(CGisListDB::eColumnCheckbox) == Qt::Checked) { CEvtD2WHideItems * evt = new CEvtD2WHideItems(folder->getId(), folder->getDBName()); evt->keys << key; CGisWorkspace::self().postEventForWks(evt); } QSqlQuery query(db); query.prepare("DELETE FROM folder2item WHERE parent=:parent AND child=:child"); query.bindValue(":parent", folder->getId()); query.bindValue(":child", id); QUERY_EXEC(); } qmapshack-1.10.0/src/gis/db/CExportDatabaseThread.cpp000644 001750 000144 00000012211 13216234137 023524 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBProject.h" #include "gis/db/CExportDatabaseThread.h" #include "gis/db/IDBFolder.h" #include "gis/db/macros.h" #include "gis/gpx/CGpxProject.h" #include CExportDatabaseThread::CExportDatabaseThread(quint64 id, QSqlDatabase &db, QObject *parent) : QThread(parent) , parentFolderId(id) , db(db) { } void CExportDatabaseThread::start(const QString& path, bool saveAsGpx11) { if(isRunning()) { return; } asGpx11 = saveAsGpx11; exportPath = path; QThread::start(); } QString CExportDatabaseThread::simplifyString(const QString& str) const { QString s = str; return s.replace(QRegExp("[^\\w\\d]"), "_"); } void CExportDatabaseThread::slotAbort() { QMutexLocker lock(&mutex); keepGoing = false; } bool CExportDatabaseThread::getKeepGoing() const { QMutexLocker lock(&mutex); return keepGoing; } void CExportDatabaseThread::run() { { QMutexLocker lock(&mutex); keepGoing = true; } try { QDir dir(exportPath); if(!dir.exists()) { emit sigOut(tr("Create %1").arg(dir.absoluteFilePath(exportPath))); if(!dir.mkpath(exportPath)) { throw tr("Failed to create %1").arg(dir.absoluteFilePath(exportPath)); } } dumpFolder(parentFolderId, "", exportPath); emit sigOut(tr("Done!")); } catch(const QString& msg) { emit sigErr(msg); } } void CExportDatabaseThread::dumpFolder(quint64 id, const QString& parentName, const QString& path) { if(!getKeepGoing()) { throw tr("Abort by user!"); } QDir dir(path); QSqlQuery query(db); query.prepare("SELECT type, name FROM folders WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(throw tr("Database Error: %1").arg(query.lastError().text())); query.next(); quint32 type = query.value(0).toUInt(); QString name = query.value(1).toString(); QString simplifiedName = simplifyString(name); if(type < IDBFolder::eTypeProject) { // if it is a group or database folder create a new subdirectory- if(!dir.exists(simplifiedName)) { emit sigOut(tr("Create %1").arg(dir.absoluteFilePath(simplifiedName))); if(!dir.mkpath(simplifiedName)) { throw tr("Failed to create %1").arg(simplifiedName); } } dir.cd(simplifiedName); } else { // if it is a project or other folder dump it to a GPX file const QString connectionName = db.connectionName(); CDBProject prj(connectionName, id, 0); CEvtD2WShowItems evt(id, connectionName); query.prepare("SELECT id, type FROM items WHERE id IN (SELECT child FROM folder2item WHERE parent=:parent)"); query.bindValue(":parent", id); QUERY_EXEC(throw tr("Database Error: %1").arg(query.lastError().text())); while(query.next()) { quint64 itemId = query.value(0).toULongLong(); quint32 itemType = query.value(1).toUInt(); evt.items << evt_item_t(itemId, itemType); } prj.showItems(&evt); QString simplifiedProjName = simplifyString(prj.getName()); // use simplified project name as filename. If the folder is of type "other" prepend it with the parent folder's name. QString filename = dir.absoluteFilePath((!parentName.isEmpty() && (type == IDBFolder::eTypeOther)) ? parentName + "_" + simplifiedProjName : simplifiedProjName) + ".gpx"; sigOut(tr("Save project as %1").arg(filename)); if(!CGpxProject::saveAs(filename, prj, asGpx11)) { throw tr("Failed!"); } } // query all child folders to this folder query.prepare("SELECT child FROM folder2folder WHERE parent=:parent"); query.prepare("SELECT id, name FROM folders WHERE id IN (SELECT child FROM folder2folder WHERE parent=:parent)"); query.bindValue(":parent", id); QUERY_EXEC(throw tr("Database Error: %1").arg(query.lastError().text())); while(query.next()) { quint64 childId = query.value(0).toULongLong(); dumpFolder(childId, simplifiedName, dir.absolutePath()); } } qmapshack-1.10.0/src/gis/db/CSelectSaveAction.h000644 001750 000144 00000003050 13216234143 022325 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELECTSAVEACTION_H #define CSELECTSAVEACTION_H #include "ui_ISelectSaveAction.h" #include class IGisItem; class CSelectSaveAction : public QDialog, private Ui::ISelectSaveAction { Q_OBJECT public: CSelectSaveAction(const IGisItem * src, const IGisItem * tar, QWidget * parent); virtual ~CSelectSaveAction(); enum result_e { eResultNone, eResultSave, eResultSkip, eResultClone, }; result_e getResult() { return result; } bool allOthersToo(); private slots: void slotSelectResult(); private: result_e result = eResultNone; }; #endif //CSELECTSAVEACTION_H qmapshack-1.10.0/src/gis/db/CSetupFolder.cpp000644 001750 000144 00000004411 13216234137 021725 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/db/CSetupFolder.h" #include CSetupFolder::CSetupFolder(IDBFolder::type_e& type, QString &name, bool groupAllowed, QWidget *parent) : QDialog(parent) , type(type) , name(name) { setupUi(this); connect(lineName, &QLineEdit::textChanged, this, &CSetupFolder::slotNameChanged); lineName->setText(name); switch(type) { case IDBFolder::eTypeGroup: radioGroup->setChecked(true); break; case IDBFolder::eTypeProject: radioProject->setChecked(true); break; case IDBFolder::eTypeOther: radioOther->setChecked(true); break; default: ; } radioGroup->setEnabled(groupAllowed); slotNameChanged(name); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSetupFolder"); } CSetupFolder::~CSetupFolder() { CCanvas::restoreOverrideCursor("~CSetupFolder"); } void CSetupFolder::accept() { name = lineName->text(); if(radioGroup->isChecked()) { type = IDBFolder::eTypeGroup; } else if(radioProject->isChecked()) { type = IDBFolder::eTypeProject; } else if(radioOther->isChecked()) { type = IDBFolder::eTypeOther; } QDialog::accept(); } void CSetupFolder::slotNameChanged(const QString& text) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); } qmapshack-1.10.0/src/gis/db/IDBMysql.cpp000644 001750 000144 00000023170 13216234137 021015 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/db/IDBMysql.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include #include IDBMysql::IDBMysql() { } bool IDBMysql::setupDB(const QString& server, const QString& port, const QString& user, const QString& passwd, bool noPasswd, const QString& name, const QString& connectionName) { // this is important! IDB::setup(connectionName); if(!QSqlDatabase::contains(connectionName)) { db = QSqlDatabase::addDatabase("QMYSQL", connectionName); db.setDatabaseName(name); db.setHostName(server); if(!port.isEmpty()) { quint16 port16 = port.toUInt(); db.setPort(port16); } db.setUserName(user); if(!noPasswd) { if(passwd.isEmpty()) { QString p = QInputDialog::getText(CMainWindow::self().getBestWidgetForParent(), tr("Password..."), tr("Password for database '%1':").arg(name), QLineEdit::Password, ""); db.setPassword(p); } else { db.setPassword(passwd); } } qDebug() << "open MySQL database" << name << "@" << server << ":" << port << "as user" << user; if(!db.open()) { qDebug() << "failed to open database" << db.lastError(); return false; } } else { db = QSqlDatabase::database(connectionName); } QString error; return setupDB(error); } bool IDBMysql::initDB() { QSqlQuery query(db); if(query.exec( "CREATE TABLE versioninfo ( version TEXT, type TEXT )")) { query.prepare( "INSERT INTO versioninfo (version, type) VALUES(:version, 'QMapShack')"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(return false); } QUERY_RUN( "CREATE TABLE folders (" "id INTEGER PRIMARY KEY AUTO_INCREMENT," "type INTEGER NOT NULL," "keyqms TEXT," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "name TEXT NOT NULL," "comment TEXT," "locked BOOLEAN DEFAULT FALSE," "data LONGBLOB," "sortmode INTEGER NOT NULL DEFAULT 0" ")", return false); QUERY_RUN( "CREATE TABLE items (" "id INTEGER PRIMARY KEY AUTO_INCREMENT," "type INTEGER," "keyqms VARCHAR(64) NOT NULL," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "icon BLOB NOT NULL," "name TEXT NOT NULL," "comment TEXT," "data LONGBLOB NOT NULL," "hash TEXT NOT NULL," "last_user TEXT DEFAULT NULL," "last_change DATETIME DEFAULT NOW() ON UPDATE NOW()," "trash DATETIME DEFAULT NULL," "FULLTEXT INDEX searchindex(comment)," "UNIQUE KEY (keyqms)" ")", return false); QUERY_RUN("CREATE TRIGGER items_insert_last_user " "BEFORE INSERT ON items " "FOR EACH ROW SET NEW.last_user = USER();" , return false); QUERY_RUN("CREATE TRIGGER items_update_last_user " "BEFORE UPDATE ON items " "FOR EACH ROW SET NEW.last_user = USER();" , return false); query.prepare("INSERT INTO folders (type, name, comment) VALUES (2, :name, '')"); query.bindValue(":name", db.connectionName()); QUERY_EXEC(return false); QUERY_RUN( "CREATE TABLE folder2folder (" "id INTEGER PRIMARY KEY AUTO_INCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES folders(id)" ")", return false); QUERY_RUN( "CREATE TABLE folder2item (" "id INTEGER PRIMARY KEY AUTO_INCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES items(id)" ")", return false); QUERY_RUN("CREATE TRIGGER folder2item_insert " "BEFORE INSERT ON folder2item " "FOR EACH ROW UPDATE items SET trash=NULL " "WHERE id=NEW.child;" , return false); QUERY_RUN("CREATE TRIGGER folder2item_delete " "AFTER DELETE ON folder2item " "FOR EACH ROW UPDATE items SET trash=CURRENT_TIMESTAMP " "WHERE id=OLD.child AND OLD.child NOT IN(SELECT child FROM folder2item);" , return false); return true; } bool IDBMysql::migrateDB(int version) { QSqlQuery query(db); try { if(version < 5) { if(!migrateDB4to5()) { throw -1; } } if(version < 6) { if(!migrateDB5to6()) { throw -1; } } } catch(int i) { if(i == -1) { return false; } } query.prepare( "UPDATE versioninfo set version=:version"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(return false); return true; } bool IDBMysql::migrateDB4to5() { QSqlQuery query(db); // id and comment to full text search index QUERY_RUN("ALTER TABLE items ADD FULLTEXT INDEX searchindex (comment)", return false); // get number of items in the database QUERY_RUN("SELECT Count(*) FROM items", return false); query.next(); quint32 N = query.value(0).toUInt(); // over all items QUERY_RUN("SELECT id, type FROM items", return false); PROGRESS_SETUP(tr("Update to database version 5. Migrate all GIS items."), 0, N, CMainWindow::self().getBestWidgetForParent()); progress.enableCancel(false); quint32 cnt = 0; while(query.next()) { PROGRESS(cnt++,; ); quint64 itemId = query.value(0).toULongLong(); quint32 itemType = query.value(1).toUInt(); IGisItem *item = IGisItem::newGisItem(itemType, itemId, db, nullptr); if(nullptr == item) { continue; } // get full size info text QString comment = item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText); // replace comment with full size info text in items table QSqlQuery query2(db); query2.prepare("UPDATE items SET comment=:comment WHERE id=:id"); query2.bindValue(":comment", comment); query2.bindValue(":id", itemId); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } delete item; } return true; } bool IDBMysql::migrateDB5to6() { QSqlQuery query(db); QUERY_RUN("ALTER TABLE folders ADD COLUMN sortmode INTEGER NOT NULL DEFAULT 0", return false); // get number of items in the database QUERY_RUN("SELECT Count(*) FROM items", return false); query.next(); quint32 N = query.value(0).toUInt(); // over all items QUERY_RUN("SELECT id, type FROM items", return false); PROGRESS_SETUP(("Update to database version 6. Migrate all GIS items."), 0, N, CMainWindow::self().getBestWidgetForParent()); progress.enableCancel(false); quint32 cnt = 0; while(query.next()) { PROGRESS(cnt++,; ); quint64 itemId = query.value(0).toULongLong(); quint32 itemType = query.value(1).toUInt(); IGisItem *item = IGisItem::newGisItem(itemType, itemId, db, nullptr); if(nullptr == item) { continue; } // get full size info text QString comment = item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText); QDateTime date = item->getTimestamp(); // replace comment with full size info text in items table QSqlQuery query2(db); query2.prepare("UPDATE items SET comment=:comment, date=:date WHERE id=:id"); query2.bindValue(":comment", comment); query2.bindValue(":date", date); query2.bindValue(":id", itemId); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } delete item; } return true; } qmapshack-1.10.0/src/gis/db/CSelectDBFolder.h000644 001750 000144 00000002606 13216234143 021720 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELECTDBFOLDER_H #define CSELECTDBFOLDER_H #include "ui_ISelectDBFolder.h" #include class CSelectDBFolder : public QDialog, private Ui::ISelectDBFolder { Q_OBJECT public: CSelectDBFolder(quint64& id, QString& db, QString& host, QWidget * parent); virtual ~CSelectDBFolder(); private slots: void slotItemExpanded(QTreeWidgetItem * item); void slotItemSelectionChanged(); private: quint64& id; QString& db; QString& host; }; #endif //CSELECTDBFOLDER_H qmapshack-1.10.0/src/gis/db/CLostFoundProject.cpp000644 001750 000144 00000004057 13216234137 022743 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListWks.h" #include "gis/db/CLostFoundProject.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include #include CLostFoundProject::CLostFoundProject(const QString &dbName, CGisListWks * parent) : CDBProject(parent) { type = eTypeLostFound; db = QSqlDatabase::database(dbName); setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/DeleteMultiple.png")); filename = dbName; metadata.name = tr("Lost & Found"); setupName(dbName); valid = true; } CLostFoundProject::~CLostFoundProject() { } void CLostFoundProject::updateFromDb() { qDeleteAll(takeChildren()); QSqlQuery query(db); QUERY_RUN("SELECT id, type FROM items AS t1 WHERE NOT EXISTS(SELECT * FROM folder2item WHERE child=t1.id) ORDER BY t1.type, t1.name", return ) while(query.next()) { quint64 id = query.value(0).toULongLong(); quint32 type = query.value(1).toUInt(); IGisItem::newGisItem(type, id, db, this); } setText(CGisListWks::eColumnDecoration,""); } qmapshack-1.10.0/src/gis/db/CExportDatabase.cpp000644 001750 000144 00000006675 13216234137 022415 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/db/CExportDatabase.h" #include "gis/db/CExportDatabaseThread.h" #include "helpers/CSettings.h" #include CExportDatabase::CExportDatabase(quint64 id, QSqlDatabase &db, QWidget *parent) : QDialog(parent) { setupUi(this); SETTINGS; cfg.beginGroup("ExportDB"); labelPath->setText(cfg.value("path","-").toString()); checkGpx11->setChecked(cfg.value("asGpx11", false).toBool()); cfg.endGroup(); QDir dir(labelPath->text()); pushStart->setEnabled(dir.exists()); connect(toolPath, &QToolButton::clicked, this, &CExportDatabase::slotSetPath); connect(pushStart, &QPushButton::clicked, this, &CExportDatabase::slotStart); thread = new CExportDatabaseThread(id, db, this); connect(pushAbort, &QPushButton::clicked, thread, &CExportDatabaseThread::slotAbort); connect(thread, &CExportDatabaseThread::started, this, &CExportDatabase::slotStarted); connect(thread, &CExportDatabaseThread::finished, this, &CExportDatabase::slotFinished); connect(thread, &CExportDatabaseThread::sigOut, this, &CExportDatabase::slotStdout); connect(thread, &CExportDatabaseThread::sigErr, this, &CExportDatabase::slotStderr); } CExportDatabase::~CExportDatabase() { SETTINGS; cfg.beginGroup("ExportDB"); cfg.setValue("path", labelPath->text()); cfg.setValue("asGpx11", checkGpx11->isChecked()); cfg.endGroup(); } void CExportDatabase::closeEvent(QCloseEvent * e) { if(thread->isRunning()) { e->ignore(); } else { e->accept(); } } void CExportDatabase::slotStdout(const QString& str) { textBrowser->setTextColor(Qt::black); textBrowser->append(str); } void CExportDatabase::slotStderr(const QString& str) { textBrowser->setTextColor(Qt::red); textBrowser->append(str); } void CExportDatabase::slotSetPath() { QString path = labelPath->text(); path = QFileDialog::getExistingDirectory(CMainWindow::self().getBestWidgetForParent(), tr("Select export path..."), path); if(!path.isEmpty()) { labelPath->setText(path); } QDir dir(labelPath->text()); pushStart->setEnabled(dir.exists()); } void CExportDatabase::slotStart() { textBrowser->clear(); thread->start(labelPath->text(), checkGpx11->isChecked()); } void CExportDatabase::slotStarted() { pushStart->setEnabled(false); pushAbort->setEnabled(true); pushClose->setEnabled(false); } void CExportDatabase::slotFinished() { pushStart->setEnabled(true); pushAbort->setEnabled(false); pushClose->setEnabled(true); } qmapshack-1.10.0/src/gis/db/ISelectDBFolder.ui000644 001750 000144 00000003313 12515735116 022117 0ustar00oeichlerxusers000000 000000 ISelectDBFolder 0 0 400 300 Select Parent Folder... Name Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISelectDBFolder accept() 248 254 157 274 buttonBox rejected() ISelectDBFolder reject() 316 260 286 274 qmapshack-1.10.0/src/gis/db/IDBSqlite.h000644 001750 000144 00000002664 13216234143 020620 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDBSQLITE_H #define IDBSQLITE_H #include "gis/db/IDB.h" class IDBSqlite : public IDB { Q_DECLARE_TR_FUNCTIONS(IDBSqlite) public: IDBSqlite(); virtual ~IDBSqlite() = default; protected: using IDB::setupDB; bool setupDB(const QString &filename, const QString &connectionName, QString &error); bool initDB() override; bool migrateDB(int version) override; bool migrateDB1to2(); bool migrateDB2to3(); bool migrateDB3to4(); bool migrateDB4to5(); bool migrateDB5to6(); }; #endif //IDBSQLITE_H qmapshack-1.10.0/src/gis/db/IDBFolderSql.h000644 001750 000144 00000003123 13216234143 021241 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDBFOLDERSQL_H #define IDBFOLDERSQL_H #include "gis/db/IDBFolder.h" class CDBFolderLostFound; class QUdpSocket; #define UDP_PORT 34123 class IDBFolderSql : public IDBFolder, public QObject { public: IDBFolderSql(QSqlDatabase& db, QTreeWidget * parent); virtual ~IDBFolderSql() = default; void expanding() override; void updateLostFound(); void update(CEvtW2DAckInfo * info) override { IDBFolder::update(info); } bool update() override; void announceChange() const; virtual void copyFolder(quint64 child, quint64 parent) = 0; protected: CDBFolderLostFound * folderLostFound = nullptr; QUdpSocket * socket; }; #endif //IDBFOLDERSQL_H qmapshack-1.10.0/src/gis/db/CDBFolderMysql.cpp000644 001750 000144 00000006273 13216234137 022150 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/db/CDBFolderMysql.h" #include "gis/db/macros.h" #include CDBFolderMysql::CDBFolderMysql(const QString &server, const QString &port, const QString &user, const QString & passwd, bool noPasswd, const QString &name, QTreeWidget *parent) : IDBFolderSql(IDB::db, parent) , server(server) , port(port) , user(user) , passwd(passwd) , noPasswd(noPasswd) { setToolTip(CGisListDB::eColumnName, tr("All your data grouped by folders.")); setText(CGisListDB::eColumnName, name); if(setupDB(server, port, user, passwd, noPasswd, name, name)) { setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/MySQL.png")); setupFromDB(); setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } else { setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/MySQLNoConn.png")); } } QString CDBFolderMysql::getDBInfo() const { QString str = "
" + IDB::db.connectionName() + "

"; str += tr("MySQL Database") + "
"; if(!port.isEmpty()) { str += tr("Server: ") + QString("%1:%2").arg(server).arg(port); } else { str += tr("Server: ") + QString("%1").arg(server); } if(noPasswd) { str += tr(" (No PW)"); } if(!isUsable()) { const QString &dbError = IDB::db.lastError().databaseText(); const QString &drError = IDB::db.lastError().driverText(); str += "
" + tr("Error: ") + QString("%1").arg(dbError.isEmpty() ? drError : dbError); } return str; } bool CDBFolderMysql::search(const QString& str, QSqlQuery &query) { query.prepare("SELECT id FROM items WHERE MATCH(comment) AGAINST (:str IN BOOLEAN MODE)"); query.bindValue(":str", str); QUERY_EXEC(return false); return true; } void CDBFolderMysql::copyFolder(quint64 child, quint64 parent) //override; { QSqlQuery query(IDB::db); query.prepare("INSERT INTO folder2folder (parent, child) SELECT :parent, :child FROM DUAL WHERE NOT EXISTS (SELECT id FROM folder2folder WHERE parent=:parent AND child=:child)"); query.bindValue(":parent", parent); query.bindValue(":child", child); QUERY_EXEC(return ); } qmapshack-1.10.0/src/gis/db/CSelectSaveAction.cpp000644 001750 000144 00000004425 13216234137 022672 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/IGisItem.h" #include "gis/db/CSelectSaveAction.h" #include "helpers/CProgressDialog.h" CSelectSaveAction::CSelectSaveAction(const IGisItem *src, const IGisItem *tar, QWidget *parent) : QDialog(parent) { setupUi(this); labelIcon1->setPixmap(src->getIcon()); labelInfo1->setText(src->getInfo(IGisItem::eFeatureShowName)); labelIcon2->setPixmap(tar->getIcon()); labelInfo2->setText(tar->getInfo(IGisItem::eFeatureShowName)); adjustSize(); connect(pushSave, &QPushButton::clicked, this, &CSelectSaveAction::slotSelectResult); connect(pushSkip, &QPushButton::clicked, this, &CSelectSaveAction::slotSelectResult); connect(pushClone, &QPushButton::clicked, this, &CSelectSaveAction::slotSelectResult); CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelectSaveAction"); CProgressDialog::setAllVisible(false); } CSelectSaveAction::~CSelectSaveAction() { CCanvas::restoreOverrideCursor("~CSelectSaveAction"); CProgressDialog::setAllVisible(true); } bool CSelectSaveAction::allOthersToo() { return checkAllOtherToo->isChecked(); } void CSelectSaveAction::slotSelectResult() { if(sender() == pushSave) { result = eResultSave; } else if(sender() == pushSkip) { result = eResultSkip; } else if(sender() == pushClone) { result = eResultClone; } accept(); } qmapshack-1.10.0/src/gis/db/CExportDatabaseThread.h000644 001750 000144 00000003421 13216234143 023171 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CEXPORTDATABASETHREAD_H #define CEXPORTDATABASETHREAD_H #include #include #include class CExportDatabaseThread : public QThread { Q_OBJECT public: CExportDatabaseThread(quint64 id, QSqlDatabase& db, QObject * parent); virtual ~CExportDatabaseThread() = default; void start(const QString& path, bool saveAsGpx11); public slots: void slotAbort(); signals: void sigOut(const QString& msg); void sigErr(const QString& msg); protected: void run() override; bool getKeepGoing() const; void dumpFolder(quint64 id, const QString &parentName, const QString& path); private: QString simplifyString(const QString &str) const; mutable QMutex mutex; bool keepGoing = false; quint64 parentFolderId; QSqlDatabase& db; QString exportPath; bool asGpx11 = false; }; #endif //CEXPORTDATABASETHREAD_H qmapshack-1.10.0/src/gis/db/CExportDatabase.h000644 001750 000144 00000003060 13216234143 022040 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CEXPORTDATABASE_H #define CEXPORTDATABASE_H #include #include #include class CExportDatabaseThread; class CExportDatabase : public QDialog, private Ui::IExportDatabase { Q_OBJECT public: CExportDatabase(quint64 id, QSqlDatabase& db, QWidget * parent); virtual ~CExportDatabase(); protected: void closeEvent(QCloseEvent * e) override; private slots: void slotStdout(const QString& str); void slotStderr(const QString& str); void slotSetPath(); void slotStart(); void slotStarted(); void slotFinished(); private: CExportDatabaseThread * thread; }; #endif //CEXPORTDATABASE_H qmapshack-1.10.0/src/gis/db/IDBSqlite.cpp000644 001750 000144 00000036666 13216234137 021167 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/db/IDBSqlite.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include #include IDBSqlite::IDBSqlite() { } bool IDBSqlite::setupDB(const QString& filename, const QString& connectionName, QString &error) { // this is important! IDB::setup(connectionName); if(!QSqlDatabase::contains(connectionName)) { db = QSqlDatabase::addDatabase("QSQLITE", connectionName); db.setDatabaseName(filename); if(!db.open()) { qDebug() << "failed to open database" << db.lastError(); } } else { db = QSqlDatabase::database(connectionName); } QSqlQuery query(db); QUERY_RUN("PRAGMA locking_mode=NORMAL", return false) QUERY_RUN("PRAGMA temp_store=MEMORY", return false) QUERY_RUN("PRAGMA default_cache_size=50", return false) QUERY_RUN("PRAGMA page_size=8192", return false) QUERY_RUN("PRAGMA synchronous=off", return false) // When migrating the database these tables are used. // Due to caching they can't be dropped right after the // migration. That is why we look for them on startup. // And delete them as a second chance. if(query.exec("select * from tmp_folders")) { QUERY_RUN("DROP TABLE tmp_folders;", NO_CMD) } if(query.exec("select * from tmp_items")) { QUERY_RUN("DROP TABLE tmp_items;", NO_CMD) } return setupDB(error); } bool IDBSqlite::initDB() { QSqlQuery query(db); QUERY_RUN("BEGIN TRANSACTION;", return false); try { if(query.exec( "CREATE TABLE versioninfo ( version TEXT, type TEXT )")) { query.prepare( "INSERT INTO versioninfo (version, type) VALUES(:version, 'QMapShack')"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(throw -1); } QUERY_RUN("CREATE TABLE folders (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," "keyqms TEXT," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "name TEXT NOT NULL," "comment TEXT," "locked BOOLEAN DEFAULT FALSE," "data BLOB," "sortmode INTEGER NOT NULL DEFAULT 0" ")", throw -1) QUERY_RUN("CREATE TABLE items (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER," "keyqms TEXT NOT NULL UNIQUE," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "icon BLOB NOT NULL," "name TEXT NOT NULL," "comment TEXT," "data BLOB NOT NULL," "hash TEXT NOT NULL," "last_user TEXT DEFAULT 'QMapShack'," "last_change DATETIME DEFAULT CURRENT_TIMESTAMP," "trash DATETIME DEFAULT NULL" ")", throw -1) QUERY_RUN("CREATE TRIGGER items_update_last_change " "AFTER UPDATE ON items BEGIN " "UPDATE items SET last_change=CURRENT_TIMESTAMP WHERE id=NEW.id; " "END;", throw -1) query.prepare("INSERT INTO folders (type, name, comment) VALUES (2, :name, '')"); query.bindValue(":name", db.connectionName()); QUERY_EXEC(return false); QUERY_RUN("CREATE TABLE folder2folder (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES folders(id)" ")", throw -1) QUERY_RUN("CREATE TABLE folder2item (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "parent INTEGER NOT NULL," "child INTEGER NOT NULL," "FOREIGN KEY(parent) REFERENCES folders(id)," "FOREIGN KEY(child) REFERENCES items(id)" ")", return false) QUERY_RUN("CREATE TRIGGER folder2item_insert " "BEFORE INSERT ON folder2item BEGIN " "UPDATE items SET trash=NULL " "WHERE id=NEW.child; " "END;", throw -1); QUERY_RUN("CREATE TRIGGER folder2item_delete " "AFTER DELETE ON folder2item BEGIN " "UPDATE items SET trash=CURRENT_TIMESTAMP " "WHERE id=OLD.child AND OLD.child NOT IN(SELECT child FROM folder2item); " "END;", throw -1); // create virtual table with search index QUERY_RUN("CREATE VIRTUAL TABLE searchindex USING fts4(id, comment)", throw -1); QUERY_RUN("CREATE TRIGGER searchindex_update " "AFTER UPDATE ON items BEGIN " "UPDATE searchindex SET comment=NEW.comment " "WHERE id=OLD.id; " "END;", throw -1); QUERY_RUN("CREATE TRIGGER searchindex_insert " "AFTER INSERT ON items BEGIN " "INSERT INTO searchindex(id, comment) VALUES(NEW.id, NEW.comment); " "END;", throw -1); QUERY_RUN("END TRANSACTION;", throw -1); } catch(int i) { if(i == -1) { QUERY_RUN("ROLLBACK;", return false); return false; } } return true; } bool IDBSqlite::migrateDB(int version) { QSqlQuery query(db); QUERY_RUN("BEGIN TRANSACTION;", return false); try { if(version < 2) { if(!migrateDB1to2()) { throw -1; } } if(version < 3) { if(!migrateDB2to3()) { throw -1; } } if(version < 4) { if(!migrateDB3to4()) { throw -1; } } if(version < 5) { if(!migrateDB4to5()) { throw -1; } } if(version < 6) { if(!migrateDB5to6()) { throw -1; } } QUERY_RUN("END TRANSACTION;", throw -1); } catch(int i) { if(i == -1) { QUERY_RUN("ROLLBACK;", return false); return false; } } query.prepare( "UPDATE versioninfo set version=:version"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(return false); return true; } bool IDBSqlite::migrateDB1to2() { QSqlQuery query(db); QUERY_RUN("ALTER TABLE folders RENAME TO tmp_folders;", return false) QUERY_RUN("CREATE TABLE folders (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," "keyqms TEXT," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "name TEXT NOT NULL," "comment TEXT," "locked BOOLEAN DEFAULT FALSE," "data BLOB" ");", return false); QUERY_RUN("INSERT INTO folders(id,type,keyqms,date,name,comment,locked,data) SELECT * FROM tmp_folders;", return false); QUERY_RUN("ALTER TABLE items RENAME TO tmp_items;", return false); QUERY_RUN("CREATE TABLE items (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER," "keyqms TEXT NOT NULL," "date DATETIME DEFAULT CURRENT_TIMESTAMP," "icon BLOB NOT NULL," "name TEXT NOT NULL," "comment TEXT," "data BLOB NOT NULL" ");", return false); QUERY_RUN("INSERT INTO items(id,type,keyqms,date,icon,name,comment,data) SELECT * FROM tmp_items;", return false); return true; } bool IDBSqlite::migrateDB2to3() { QSqlQuery query(db); QUERY_RUN("ALTER TABLE items ADD COLUMN hash TEXT NOT NULL DEFAULT '-'", return false); QUERY_RUN("ALTER TABLE items ADD COLUMN last_user TEXT NOT NULL DEFAULT 'QMapShack'", return false); QUERY_RUN("ALTER TABLE items ADD COLUMN last_change DATETIME NOT NULL DEFAULT '-'", return false); QUERY_RUN("CREATE TRIGGER items_update_last_change " "AFTER UPDATE ON items BEGIN " "UPDATE items SET last_change=datetime(CURRENT_TIMESTAMP, 'localtime') WHERE id=NEW.id; " "END;", return false); QUERY_RUN("SELECT Count(*) FROM items", return false); query.next(); quint32 N = query.value(0).toUInt(); QUERY_RUN("SELECT id, type FROM items WHERE hash='-'", return false); PROGRESS_SETUP(tr("Update to database version 3. Migrate all GIS items."), 0, N, CMainWindow::self().getBestWidgetForParent()); progress.enableCancel(false); quint32 cnt = 0; while(query.next()) { PROGRESS(cnt++,; ); quint64 idItem = query.value(0).toULongLong(); quint32 typeItem = query.value(1).toUInt(); IGisItem *item = IGisItem::newGisItem(typeItem, idItem, db, nullptr); if(nullptr == item) { continue; } QSqlQuery query2(db); query2.prepare("UPDATE items SET hash=:hash, last_user='QMapShack' WHERE id=:id"); query2.bindValue(":hash", item->getHash()); query2.bindValue(":id", idItem); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } delete item; } return true; } bool IDBSqlite::migrateDB3to4() { QSqlQuery query(db); QUERY_RUN("ALTER TABLE items ADD COLUMN trash DATETIME DEFAULT NULL", return false); QUERY_RUN("CREATE TRIGGER folder2item_insert " "BEFORE INSERT ON folder2item BEGIN " "UPDATE items SET trash=NULL " "WHERE id=NEW.child; " "END;", return false); QUERY_RUN("CREATE TRIGGER folder2item_delete " "AFTER DELETE ON folder2item BEGIN " "UPDATE items SET trash=CURRENT_TIMESTAMP " "WHERE id=OLD.child AND OLD.child NOT IN(SELECT child FROM folder2item); " "END;", return false); return true; } bool IDBSqlite::migrateDB4to5() { QSqlQuery query(db); // create virtual table with search index QUERY_RUN("CREATE VIRTUAL TABLE searchindex USING fts4(id, comment)", return false); // get number of items in the database QUERY_RUN("SELECT Count(*) FROM items", return false); query.next(); quint32 N = query.value(0).toUInt(); // over all items QUERY_RUN("SELECT id, type FROM items", return false); PROGRESS_SETUP(tr("Update to database version 5. Migrate all GIS items."), 0, N, CMainWindow::self().getBestWidgetForParent()); progress.enableCancel(false); quint32 cnt = 0; while(query.next()) { PROGRESS(cnt++,; ); quint64 idItem = query.value(0).toULongLong(); quint32 typeItem = query.value(1).toUInt(); IGisItem *item = IGisItem::newGisItem(typeItem, idItem, db, nullptr); if(nullptr == item) { continue; } // get full size info text QString comment = item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText); // replace comment with full size info text in items table QSqlQuery query2(db); query2.prepare("UPDATE items SET comment=:comment WHERE id=:id"); query2.bindValue(":comment", comment); query2.bindValue(":id", idItem); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } // add item id and full size info text to virtual table query2.prepare("INSERT INTO searchindex(id, comment) VALUES(:id, :comment)"); query2.bindValue(":id", idItem); query2.bindValue(":comment", comment); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } delete item; } QUERY_RUN("CREATE TRIGGER searchindex_update " "AFTER UPDATE ON items BEGIN " "UPDATE searchindex SET comment=NEW.comment " "WHERE id=OLD.id; " "END;", return false); QUERY_RUN("CREATE TRIGGER searchindex_insert " "AFTER INSERT ON items BEGIN " "INSERT INTO searchindex(id, comment) VALUES(NEW.id, NEW.comment); " "END;", return false); return true; } bool IDBSqlite::migrateDB5to6() { QSqlQuery query(db); QUERY_RUN("ALTER TABLE folders ADD COLUMN sortmode INTEGER NOT NULL DEFAULT 0", return false); // get number of items in the database QUERY_RUN("SELECT Count(*) FROM items", return false); query.next(); quint32 N = query.value(0).toUInt(); // over all items QUERY_RUN("SELECT id, type FROM items", return false); PROGRESS_SETUP(tr("Update to database version 6. Migrate all GIS items."), 0, N, CMainWindow::self().getBestWidgetForParent()); progress.enableCancel(false); quint32 cnt = 0; while(query.next()) { PROGRESS(cnt++,; ); quint64 idItem = query.value(0).toULongLong(); quint32 typeItem = query.value(1).toUInt(); IGisItem *item = IGisItem::newGisItem(typeItem, idItem, db, nullptr); if(nullptr == item) { continue; } // get full size info text QString comment = item->getInfo(IGisItem::eFeatureShowName|IGisItem::eFeatureShowFullText); QDateTime date = item->getTimestamp(); // replace comment with full size info text in items table QSqlQuery query2(db); query2.prepare("UPDATE items SET comment=:comment, date=:date WHERE id=:id"); query2.bindValue(":comment", comment); query2.bindValue(":date", date); query2.bindValue(":id", idItem); if(!query2.exec()) { qWarning() << query2.lastQuery(); qWarning() << query2.lastError(); } delete item; } return true; } qmapshack-1.10.0/src/gis/db/ISetupDatabase.ui000644 001750 000144 00000023774 12705713523 022077 0ustar00oeichlerxusers000000 000000 ISetupDatabase 0 0 500 412 Add database... Name Qt::Horizontal Qt::Horizontal QFrame::NoFrame QFrame::Plain 0 0 File: - Add new database. ... :/icons/32x32/Add.png:/icons/32x32/Add.png Open existing database. ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png QFrame::NoFrame QFrame::Plain MySQL true buttonGroup Qt::Vertical 20 40 QFrame::NoFrame QFrame::Plain SQLite true true buttonGroup QFrame::NoFrame QFrame::Plain Server Port 0 0 00000 User Password QLineEdit::Password Do not use a password. 0 0 <p align="justify"><span style=" font-weight:600;">Caution!</span> It is recommended to leave the password blank, as QMapShack will store it as plain text. If you don't give a password you will be asked for it on each startup.</p> true Qt::Vertical 20 40 <b>Port:</b> Leave the port field empty to use the default port. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISetupDatabase accept() 248 254 157 274 buttonBox rejected() ISetupDatabase reject() 316 260 286 274 qmapshack-1.10.0/src/gis/db/CDBFolderLostFound.cpp000644 001750 000144 00000007022 13216234137 022751 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/CGisWorkspace.h" #include "gis/db/CDBFolderLostFound.h" #include "gis/db/CDBItem.h" #include "gis/db/macros.h" #include CDBFolderLostFound::CDBFolderLostFound(QSqlDatabase& db, QTreeWidgetItem *parent) : IDBFolder(true, db, eTypeLostFound, 0, parent) { setToolTip(CGisListDB::eColumnName, tr("All your data grouped by folders.")); setupFromDB(); setCheckState(CGisListDB::eColumnCheckbox, Qt::Unchecked); CEvtD2WReqInfo * evt = new CEvtD2WReqInfo(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt); } CDBFolderLostFound::~CDBFolderLostFound() { } void CDBFolderLostFound::setupFromDB() { int cnt = 0; QSqlQuery query(db); qDeleteAll(takeChildren()); QUERY_RUN("SELECT id FROM items AS t1 WHERE NOT EXISTS(SELECT * FROM folder2item WHERE child=t1.id) ORDER BY t1.type, t1.name", return ); while(query.next()) { quint64 id = query.value(0).toULongLong(); new CDBItem(db, id, this); cnt++; } if(cnt) { setText(CGisListDB::eColumnName, tr("Lost & Found (%1)").arg(cnt)); setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/DeleteMultiple.png")); } else { setText(CGisListDB::eColumnName, tr("Lost & Found")); setIcon(CGisListDB::eColumnCheckbox, QIcon("://icons/32x32/Empty.png")); } CEvtD2WUpdateLnF * evt = new CEvtD2WUpdateLnF(getId(), getDBName()); CGisWorkspace::self().postEventForWks(evt); } void CDBFolderLostFound::update(CEvtW2DAckInfo * info) { if(info->id != 0) { return; } setCheckState(CGisListDB::eColumnCheckbox, info->checkState); } bool CDBFolderLostFound::update() { setupFromDB(); return true; } void CDBFolderLostFound::expanding() { const int N = childCount(); for(int i=0; i(child(i)); if(item) { item->updateAge(); } } } void CDBFolderLostFound::clear() { QSqlQuery query(db); QUERY_RUN("DELETE FROM items WHERE id NOT IN (SELECT child from folder2item)", return ) setupFromDB(); } bool CDBFolderLostFound::delItem(CDBItem * item) { QSqlQuery query(db); if(checkState(CGisListDB::eColumnCheckbox) == Qt::Checked) { CEvtD2WHideItems * evt = new CEvtD2WHideItems(getId(), getDBName()); evt->keys << item->getKey(); CGisWorkspace::self().postEventForWks(evt); } query.prepare("DELETE FROM items WHERE id=:id AND id NOT IN (SELECT child from folder2item)"); query.bindValue(":id", item->getId()); QUERY_EXEC(return false); return true; } qmapshack-1.10.0/src/gis/db/IDBMysql.h000644 001750 000144 00000002662 13216234143 020462 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDBMYSQL_H #define IDBMYSQL_H #include "gis/db/IDB.h" class IDBMysql : public IDB { Q_DECLARE_TR_FUNCTIONS(IDBMysql) public: IDBMysql(); virtual ~IDBMysql() = default; protected: using IDB::setupDB; bool setupDB(const QString &server, const QString &port, const QString &user, const QString &passwd, bool noPasswd, const QString &name, const QString &connectionName); bool initDB() override; bool migrateDB(int version) override; bool migrateDB4to5(); bool migrateDB5to6(); }; #endif //IDBMYSQL_H qmapshack-1.10.0/src/gis/db/ISetupWorkspace.ui000644 001750 000144 00000005460 12705713523 022321 0ustar00oeichlerxusers000000 000000 ISetupWorkspace 0 0 624 107 Setup workspace... 0 0 save workspace on exit, and every minutes listen for database changes from other instances of QMapShack. On port 00000 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ISetupWorkspace accept() 227 91 157 111 buttonBox rejected() ISetupWorkspace reject() 295 97 286 111 qmapshack-1.10.0/src/gis/db/CDBFolderSqlite.h000644 001750 000144 00000003053 13216234143 021737 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDBFOLDERSQLITE_H #define CDBFOLDERSQLITE_H #include "gis/db/IDBFolderSql.h" #include "gis/db/IDBSqlite.h" class CDBFolderSqlite : public IDBFolderSql, public IDBSqlite { Q_DECLARE_TR_FUNCTIONS(CDBFolderSqlite) public: CDBFolderSqlite(const QString &filename, const QString &name, QTreeWidget *parent); virtual ~CDBFolderSqlite() {} const QString& getFilename() { return filename; } QString getDBInfo() const; bool search(const QString& str, QSqlQuery &query) override; void copyFolder(quint64 child, quint64 parent) override; private: QString filename; QString error; }; #endif //CDBFOLDERSQLITE_H qmapshack-1.10.0/src/gis/db/CDBFolderOther.cpp000644 001750 000144 00000002346 13216234137 022121 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisListDB.h" #include "gis/db/CDBFolderOther.h" CDBFolderOther::CDBFolderOther(QSqlDatabase& db, quint64 key, QTreeWidgetItem * parent) : IDBFolder(true, db, eTypeOther, key, parent) { setIcon(CGisListDB::eColumnCheckbox,QIcon("://icons/32x32/PathOrange.png")); setupFromDB(); } CDBFolderOther::~CDBFolderOther() { } qmapshack-1.10.0/src/gis/db/IDB.cpp000644 001750 000144 00000010700 13216234137 017762 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/db/IDB.h" #include "gis/db/macros.h" #include #include QMap IDB::references; IDB::IDB() { } IDB::~IDB() { references[db.connectionName()]--; if(references[db.connectionName()] == 0 && db.isOpen()) { qDebug() << "close database" << db.connectionName(); db.close(); } } void IDB::setup(const QString &connectionName) { references[connectionName]++; } bool IDB::setupDB(QString &error) { QSqlQuery query(db); if(!query.exec("SELECT version FROM versioninfo")) { return initDB(); } else if(query.next()) { int version = query.value(0).toInt(); if(version < DB_VERSION) { QString msg = tr("The internal database format of '%1' has changed. QMapShack will migrate your database, now. " "After the migration the database won't be usable with older versions of QMapShack. " "It is recommended to backup the database first.").arg(db.connectionName()); int res = QMessageBox::warning(CMainWindow::self().getBestWidgetForParent(), tr("Migrate database..."), msg, QMessageBox::Ok|QMessageBox::Abort); if(res != QMessageBox::Ok) { error = tr("Migration aborted by user"); return false; } if(!migrateDB(version)) { QString msg = tr("Failed to migrate '%1'.").arg(db.connectionName()); QMessageBox::critical(CMainWindow::self().getBestWidgetForParent(), tr("Error..."), msg, QMessageBox::Abort); error = tr("Migration failed"); return false; } } else if(version > DB_VERSION) { QString msg = tr("The database version of '%1' is more advanced as the one understood by your " "QMapShack installation. This won't work.").arg(db.connectionName()); QMessageBox::critical(CMainWindow::self().getBestWidgetForParent(), tr("Wrong database version..."), msg, QMessageBox::Abort); error = tr("Database created by newer version of QMapShack"); return false; } } else { if(!initDB()) { QString msg = tr("Failed to initialize '%1'.").arg(db.connectionName()); QMessageBox::critical(CMainWindow::self().getBestWidgetForParent(), tr("Error..."), msg, QMessageBox::Abort); error = tr("Initialization failed"); return false; } } query.prepare("UPDATE folders SET name=:name WHERE id=1"); query.bindValue(":name", db.connectionName()); QUERY_EXEC(return false); return true; } quint64 IDB::getLastInsertID(QSqlDatabase& db, const QString& table) { QSqlQuery query(db); if(db.driverName() == "QSQLITE") { QUERY_RUN("SELECT last_insert_rowid() from " + table, return 0) } else if(db.driverName() == "QMYSQL") { QUERY_RUN("SELECT last_insert_id() from " + table, return 0) } query.next(); return query.value(0).toULongLong(); } qmapshack-1.10.0/src/gis/db/CSetupDatabase.cpp000644 001750 000144 00000012062 13216234137 022217 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisListDB.h" #include "gis/db/CSetupDatabase.h" #include "helpers/CSettings.h" #include CSetupDatabase::CSetupDatabase(CGisListDB &parent) : QDialog(&parent) , list(parent) { setupUi(this); lineUser->setText(CMainWindow::getUser()); connect(toolNewDB, &QToolButton::clicked, this, &CSetupDatabase::slotNewDB); connect(toolAddDB, &QToolButton::clicked, this, &CSetupDatabase::slotOpenDB); connect(lineName, &QLineEdit::textChanged, this, &CSetupDatabase::slotUpdateButtonBox); connect(lineServer, &QLineEdit::textChanged, this, &CSetupDatabase::slotUpdateButtonBox); connect(lineUser, &QLineEdit::textChanged, this, &CSetupDatabase::slotUpdateButtonBox); connect(radioSqlite, &QRadioButton::clicked, this, &CSetupDatabase::slotUpdateButtonBox); connect(radioMysql, &QRadioButton::clicked, this, &CSetupDatabase::slotUpdateButtonBox); connect(checkMySQLNoPasswd, &QCheckBox::clicked, linePasswd, &QLineEdit::setDisabled); if(!QSqlDatabase::isDriverAvailable("QMYSQL")) { gridLayout->removeWidget(frameMysql); QString errorTitle = tr("Missing Requirement"); QString errorText = tr("MySQL cannot be used at this point, because the corresponding driver (QMYSQL) is not available.
Please make sure you have installed the corresponding package.
If you don't know what to do now you should have a look at the wiki.").arg("https://bitbucket.org/maproom/qmapshack/wiki/DocGisDatabaseAddRemove#markdown-header-mysql-565"); QLabel *errorMissingMySQL = new QLabel(QString("%1

%2").arg(errorTitle).arg(errorText)); errorMissingMySQL->setOpenExternalLinks(true); errorMissingMySQL->setWordWrap(true); gridLayout->addWidget(errorMissingMySQL, 4, 1, Qt::AlignTop); radioSqlite->setChecked(true); radioMysql->setDisabled(true); } slotUpdateButtonBox(); } CSetupDatabase::~CSetupDatabase() { } void CSetupDatabase::slotUpdateButtonBox() { bool enable = !lineName->text().isEmpty(); if(radioSqlite->isChecked()) { if(labelFilename->text() == "-") { enable = false; } frameSqlite->setEnabled(true); frameMysql->setEnabled(false); } else if(radioMysql->isChecked()) { if(lineServer->text().isEmpty()) { enable = false; } if(lineUser->text().isEmpty()) { enable = false; } frameSqlite->setEnabled(false); frameMysql->setEnabled(true); } buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable); } void CSetupDatabase::accept() { QString name = lineName->text(); if(list.hasDatabase(name)) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("There is already a database with name '%1'").arg(name), QMessageBox::Abort); return; } QDialog::accept(); } void CSetupDatabase::slotNewDB() { SETTINGS; QString path = cfg.value("Database/lastDatabasePath", QDir::homePath()).toString(); QString filename = QFileDialog::getSaveFileName(this, tr("New database..."), path, "QMapShack Database (*.db)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); if(fi.suffix().toLower() != "db") { filename += ".db"; } cfg.setValue("Database/lastDatabasePath", fi.absolutePath()); labelFilename->setText(filename); slotUpdateButtonBox(); } void CSetupDatabase::slotOpenDB() { SETTINGS; QString path = cfg.value("Database/lastDatabasePath", QDir::homePath()).toString(); QString filename = QFileDialog::getOpenFileName(this, tr("Open database..."), path, "QMapShack Database (*.db)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); if(fi.suffix().toLower() != "db") { filename += ".db"; } cfg.setValue("Database/lastDatabasePath", fi.absolutePath()); labelFilename->setText(filename); slotUpdateButtonBox(); } bool CSetupDatabase::noPasswd() const { return radioMysql->isChecked() && checkMySQLNoPasswd->isChecked(); } qmapshack-1.10.0/src/gis/db/IDBFolder.h000644 001750 000144 00000014734 13216234143 020573 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IDBFOLDER_H #define IDBFOLDER_H #include "gis/prj/IGisProject.h" #include #include class QSqlDatabase; class CEvtW2DAckInfo; class IDBFolderSql; class CDBItem; /** * @brief Baseclass for all folders in the database view */ class IDBFolder : public QTreeWidgetItem { public: enum type_e { eTypeLostFound = 1 ,eTypeDatabase = 2 ,eTypeGroup = 3 ,eTypeProject = 4 ,eTypeOther = 5 }; IDBFolder(bool isLoadable, QSqlDatabase& db, type_e type, quint64 id, QTreeWidgetItem * parent); IDBFolder(bool isLoadable, QSqlDatabase& db, type_e type, quint64 id, QTreeWidget * parent); virtual ~IDBFolder(); /** * @brief Get the 64bit database key * @return */ quint64 getId() const { return id; } QString getDBName() const; QString getDBHost() const; QSqlDatabase& getDb(){return db; } QString getName() const; void setName(const QString& name); /** * @brief Get the database folder that folder is stored in * * @return On success a pointer to the item holding the database is returned. */ IDBFolderSql * getDBFolder(); /** * @brief Search and get access to a subfolder * @param idFolder the database key of the folder * @return On success a pointer to the item is returned. Else 0. */ IDBFolder * getFolder(quint64 idFolder); /** * @brief Add a new folder to the database and the treewidget. * * This will call addFolderToDb() and createFolderByType() * * @param type the type of the new folder * @param name the name of the new folder * @return The 64bit database key of the new folder. 0 on failure. */ virtual quint64 addFolder(type_e type, const QString &name); /** * @brief Add children from database */ virtual void expanding(); /** * @brief Update item all child items from database * * The event has a list of active items. The item list is created from * scratch and the check state is updated by that list * * @param info The event object posted by the workspace */ virtual void update(CEvtW2DAckInfo * info); /** * @brief Update from database * * The database might have been changed by other users. Update list of folders * and update each folder expanded. Rebuild list of items. */ virtual bool update(); /** * @brief Toggle check state of project and post event to workspace. */ virtual void toggle(); /** * @brief Remove folder from database and post event to workspace */ virtual void remove(); /** * @brief Create a new folder entry into the database table * * The folder will be attached to it's parent folder * * @param type the type of the new folder * @param name the name of the new folder * @param idParent the 64bit database key of the parent * @param db the database to work on * @return The 64bit database key of the new folder. 0 on failure. */ static quint64 addFolderToDb(type_e type, const QString& name, quint64 idParent, QSqlDatabase& db); /** * @brief Create a new treeWidgetItem from a folder in the database * * @param db the database the item belongs to * @param type the folder type to create * @param id the database key of the folder * @param parent the items parent item * @return A pointer to the new treewidgetitem. */ static IDBFolder * createFolderByType(QSqlDatabase &db, int type, quint64 id, QTreeWidgetItem *parent); bool operator<(const QTreeWidgetItem &other) const override; void updateItemsOnWks(); /** @brief Do a database search. This must be overridden by the database folder classes. As a result the query will contain a list of item IDs. @param str The string to search for @param query The sql query item to use */ virtual bool search(const QString& str, QSqlQuery& query) { return false; } bool isSiblingFrom(IDBFolder * folder) const; void exportToGpx(); protected: /** @brief Setup all item properties This will read the database to setup the name, key and tooltip. Additionally it will query for child elements (folders, gis items) and set the expand indicator accordingly. If the folder is loadable the checkbox has to be displayed and the workspace has to be queried for the folder. */ virtual void setupFromDB(); /** @brief Add child items like folders, tracks, routes, waypoints and overlays The checkbox of active items will be set checked. @param activeChildren a set of item keys that are active on the workspace */ virtual void addChildren(const QSet &activeChildren, bool skipFolders); /** @brief Remove a folder to folder relation If the folder has no other relation the folder's relation to it's children is removed, too. @param idParent the 64bit database key of the parent folder @param idFolder the 64bit database key of the child folder to be removed */ virtual void remove(quint64 idParent, quint64 idFolder); void setChildIndicator(); void addItemsSorted(QList &items); void sortItems(QList &items) const; QSqlDatabase& db; quint64 id; QString key; quint32 sortMode = IGisProject::eSortFolderTime; bool isLoadable; }; #endif //IDBFOLDER_H qmapshack-1.10.0/src/gis/rte/000755 001750 000144 00000000000 13216664445 017100 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/rte/CGisItemRte.cpp000644 001750 000144 00000101167 13216234140 021712 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/WptIcons.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CDetailsRte.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/CScrOptRte.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "units/IUnit.h" #include #include #include const QPen CGisItemRte::penBackground(Qt::white, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); IGisItem::key_t CGisItemRte::keyUserFocus; #define MIN_DIST_FOCUS 200 void CGisItemRte::rtept_t::updateIcon() { if(sym.isEmpty()) { icon = QPixmap(); focus = NOPOINTF; } else { icon = getWptIconByName(sym, focus); } } /// used to create a copy of route with new parent CGisItemRte::CGisItemRte(const CGisItemRte& parentRte, IGisProject * project, int idx, bool clone) : IGisItem(project, eTypeRte, idx) { history = parentRte.history; loadHistory(history.histIdxCurrent); if(clone) { rte.name += tr("_Clone"); key.clear(); history.events.clear(); } if(parentRte.isOnDevice()) { flags |= eFlagWriteAllowed; } else if(!parentRte.isReadOnly()) { flags |= eFlagWriteAllowed; } else { flags &= ~eFlagWriteAllowed; } setupHistory(); deriveSecondaryData(); updateDecoration(eMarkChanged, eMarkNone); } /// used to create route from GPX file CGisItemRte::CGisItemRte(const QDomNode& xml, IGisProject *parent) : IGisItem(parent, eTypeRte, parent->childCount()) { // --- start read and process data ---- readRte(xml, rte); // --- stop read and process data ---- setupHistory(); deriveSecondaryData(); updateDecoration(eMarkNone, eMarkNone); } CGisItemRte::CGisItemRte(const history_t& hist, const QString &dbHash, IGisProject * project) : IGisItem(project, eTypeRte, project->childCount()) { history = hist; loadHistory(hist.histIdxCurrent); deriveSecondaryData(); if(!dbHash.isEmpty()) { lastDatabaseHash = dbHash; } } CGisItemRte::CGisItemRte(quint64 id, QSqlDatabase& db, IGisProject * project) : IGisItem(project, eTypeRte, NOIDX) { loadFromDb(id, db); } CGisItemRte::CGisItemRte(const SGisLine &l, const QString &name, IGisProject *project, int idx) : IGisItem(project, eTypeRte, idx) { rte.name = name; readRouteDataFromGisLine(l); flags |= eFlagCreatedInQms|eFlagWriteAllowed; setupHistory(); updateDecoration(eMarkChanged, eMarkNone); } CGisItemRte::CGisItemRte(CFitStream& stream, IGisProject * project) : IGisItem(project, eTypeRte, project->childCount()) { // --- start read and process data ---- readRteFromFit(stream); // --- stop read and process data ---- setupHistory(); deriveSecondaryData(); updateDecoration(eMarkNone, eMarkNone); } CGisItemRte::~CGisItemRte() { // reset user focus if focused on this track if(key == keyUserFocus) { keyUserFocus.clear(); } } IGisItem * CGisItemRte::createClone() { int idx = -1; IGisProject * project = getParentProject(); if(project) { idx = project->indexOfChild(this); } return new CGisItemRte(*this, project, idx, true); } bool CGisItemRte::isCalculated() { bool yes = true; for(const rtept_t &pt : rte.pts) { if((pt.fakeSubpt.lat == NOFLOAT) || (pt.fakeSubpt.lon == NOFLOAT)) { yes = false; } } return yes; } void CGisItemRte::setElevation(qreal ele, subpt_t& subpt, qreal& lastEle) { if(ele == NOFLOAT) { subpt.ele = NOINT; return; } subpt.ele = qRound(ele); if(lastEle != NOFLOAT) { qreal delta = subpt.ele - lastEle; if(qAbs(delta) > ASCENT_THRESHOLD) { if(delta > 0) { rte.ascent += delta; } else { rte.descent -= delta; } lastEle = subpt.ele; } } else { lastEle = subpt.ele; } } void CGisItemRte::deriveSecondaryData() { QPolygonF pos; QPolygonF ele; qreal north = -90; qreal east = -180; qreal south = 90; qreal west = 180; for(rtept_t &rtept : rte.pts) { west = qMin(west, rtept.lon); east = qMax(east, rtept.lon); south = qMin(south, rtept.lat); north = qMax(north, rtept.lat); pos << (QPointF(rtept.lon, rtept.lat) * DEG_TO_RAD); rtept.ele = NOINT; rtept.fakeSubpt.ele = NOINT; for(subpt_t &subpt : rtept.subpts) { west = qMin(west, subpt.lon); east = qMax(east, subpt.lon); south = qMin(south, subpt.lat); north = qMax(north, subpt.lat); pos << (QPointF(subpt.lon, subpt.lat) * DEG_TO_RAD); subpt.ele = NOINT; } rtept.updateIcon(); } ele.resize(pos.size()); ele.fill(NOPOINTF); CMainWindow::self().getElevationAt(pos, ele); if(!ele.isEmpty()) { qreal lastEle = NOFLOAT; int i = 0; rte.descent = 0; rte.ascent = 0; for(rtept_t &rtept : rte.pts) { setElevation(ele[i++].y(), rtept.fakeSubpt, lastEle); rtept.ele = rtept.fakeSubpt.ele; for(subpt_t &subpt : rtept.subpts) { setElevation(ele[i++].y(), subpt, lastEle); } } } boundingRect = QRectF(QPointF(west * DEG_TO_RAD, north * DEG_TO_RAD), QPointF(east * DEG_TO_RAD,south * DEG_TO_RAD)); } void CGisItemRte::edit() { CDetailsRte dlg(*this, CMainWindow::getBestWidgetForParent()); dlg.exec(); } void CGisItemRte::toTrack() { QString name; IGisProject * project; if(!getNameAndProject(name, project, tr("track"))) { return; } SGisLine line; getPolylineFromData(line); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->getElevationAt(line); } new CGisItemTrk(line, name, project, -1); } void CGisItemRte::setSymbol() { icon = QPixmap("://icons/32x32/Route.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation); setIcon(CGisListWks::eColumnIcon, icon); } void CGisItemRte::setName(const QString& str) { setText(CGisListWks::eColumnName, str); rte.name = str; changed(tr("Changed name."), "://icons/48x48/EditText.png"); } void CGisItemRte::setComment(const QString& str) { rte.cmt = str; changed(tr("Changed comment"), "://icons/48x48/EditText.png"); } void CGisItemRte::setDescription(const QString& str) { rte.desc = str; changed(tr("Changed description"), "://icons/48x48/EditText.png"); } void CGisItemRte::setLinks(const QList& links) { rte.links = links; changed(tr("Changed links"), "://icons/48x48/Link.png"); } QString CGisItemRte::getInfo(quint32 feature) const { QString val1, unit1; QString str = "
"; if(feature & eFeatureShowName) { str += "" + getName() + "
"; } if(rte.totalDistance != NOFLOAT) { IUnit::self().meter2distance(rte.totalDistance, val1, unit1); str += tr("Length: %1%2").arg(val1).arg(unit1); } else { str += tr("Length: -"); } str += "
\n"; if(rte.totalTime != 0) { IUnit::self().seconds2time(rte.totalTime, val1, unit1); str += tr("Time: %1%2").arg(val1).arg(unit1); } else { str += tr("Time: -"); } if((rte.ascent != NOFLOAT) && (rte.descent != NOFLOAT)) { str += "
\n"; QString val1, val2, unit1, unit2; IUnit::self().meter2elevation(rte.ascent, val1, unit1); IUnit::self().meter2elevation(rte.descent, val2, unit2); str += tr("%1%2 %3, %4%5 %6").arg(QChar(0x2197)).arg(val1).arg(unit1).arg(QChar(0x2198)).arg(val2).arg(unit2); } if(!rte.lastRoutedWith.isEmpty()) { str += "
\n"; str += tr("Last time routed:
%1").arg(IUnit::datetime2string(rte.lastRoutedTime, false, boundingRect.center())); str += "
\n"; str += tr("with %1").arg(rte.lastRoutedWith); } QString desc = removeHtml(rte.desc).simplified(); if(desc.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || (desc.count() < 300)) { str += desc; } else { str += desc.left(297) + "..."; } } QString cmt = removeHtml(rte.cmt).simplified(); if((cmt != desc) && cmt.count()) { if(!str.isEmpty()) { str += "
\n"; } if((feature & eFeatureShowFullText) || cmt.count() < 300) { str += cmt; } else { str += cmt.left(297) + "..."; } } return str + "
"; } IScrOpt * CGisItemRte::getScreenOptions(const QPoint& origin, IMouse * mouse) { if(scrOpt.isNull()) { scrOpt = new CScrOptRte(this, origin, mouse); } return scrOpt; } QPointF CGisItemRte::getPointCloseBy(const QPoint& screenPos) { QMutexLocker lock(&mutexItems); qint32 d = NOINT; QPointF pt = NOPOINTF; for(const QPointF &point : line) { int tmp = (screenPos - point).manhattanLength(); if(tmp < d) { pt = point; d = tmp; } } return pt; } bool CGisItemRte::isCloseTo(const QPointF& pos) { QMutexLocker lock(&mutexItems); qreal dist = GPS_Math_DistPointPolyline(line, pos); return dist < 20; } bool CGisItemRte::isWithin(const QRectF& area, selflags_t flags) { return (flags & eSelectionRte) ? IGisItem::isWithin(area, flags, line) : false; } void CGisItemRte::gainUserFocus(bool yes) { keyUserFocus = yes ? key : key_t(); } void CGisItemRte::looseUserFocus() { if(keyUserFocus == key) { keyUserFocus.clear(); } } void CGisItemRte::drawItem(QPainter& p, const QPolygonF& viewport, QList &blockedAreas, CGisDraw *gis) { QMutexLocker lock(&mutexItems); line.clear(); if(!isVisible(boundingRect, viewport, gis)) { return; } QPointF p1 = viewport[0]; QPointF p2 = viewport[2]; gis->convertRad2Px(p1); gis->convertRad2Px(p2); QRectF extViewport(p1,p2); QVector points; QVector icons; QVector focus; for(const rtept_t &rtept : rte.pts) { QPointF pt(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD); gis->convertRad2Px(pt); line << pt; points << 1; icons << rtept.icon; focus << rtept.focus; blockedAreas << QRectF(pt - rtept.focus, rtept.icon.size()); for(const subpt_t &subpt : rtept.subpts) { QPointF pt(subpt.lon * DEG_TO_RAD, subpt.lat * DEG_TO_RAD); gis->convertRad2Px(pt); line << pt; if(subpt.type != subpt_t::eTypeNone) { points << 2; } else { points << 0; } } } p.setPen(penBackground); p.drawPolyline(line); p.setPen(Qt::NoPen); p.setBrush(Qt::white); for(int i = 0; i < line.size(); i++) { switch(points[i]) { case 1: p.drawEllipse(line[i],7,7); break; case 2: p.drawEllipse(line[i],5,5); break; } } p.setPen(hasUserFocus() ? penForegroundFocus : penForeground); p.setBrush(hasUserFocus() ? penForegroundFocus.color() : penForeground.color()); CDraw::arrows(line, extViewport, p, 10, 80, 1.0); p.drawPolyline(line); p.setPen(Qt::NoPen); for(int i = 0, n = 0; i < line.size(); i++) { switch(points[i]) { case 1: p.setBrush(Qt::red); p.drawEllipse(line[i],5,5); if(focus[n] != NOPOINTF) { p.drawPixmap(line[i] - focus[n], icons[n]); } n++; break; case 2: p.setBrush(Qt::cyan); p.drawEllipse(line[i],3,3); break; } } } void CGisItemRte::drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) { QMutexLocker lock(&mutexItems); if(rte.pts.isEmpty()) { return; } QDateTime startTime = rte.pts.first().fakeSubpt.time; if(!startTime.isValid() && !rte.pts.isEmpty() && !rte.pts.first().subpts.isEmpty()) { startTime = rte.pts.first().subpts.first().time; } if(hasUserFocus() && mouseMoveFocus && mouseMoveFocus->lon != NOFLOAT && mouseMoveFocus->lat != NOFLOAT) { QPointF anchor(mouseMoveFocus->lon, mouseMoveFocus->lat); anchor *= DEG_TO_RAD; gis->convertRad2Px(anchor); p.drawEllipse(anchor, 5, 5); QString str, val, unit; IUnit::self().seconds2time((mouseMoveFocus->time.toTime_t() - startTime.toTime_t()), val, unit); str += tr("Time: %1%2").arg(val).arg(unit) + " "; IUnit::self().meter2distance(mouseMoveFocus->distance, val, unit); str += tr("Distance: %1%2").arg(val).arg(unit); str += "\n" + mouseMoveFocus->instruction; // calculate bounding box of text QFont f = CMainWindow::self().getMapFont(); QFontMetrics fm(f); QRect rectText = fm.boundingRect(QRect(0,0,500,0), Qt::AlignLeft|Qt::AlignTop|Qt::TextWordWrap, str); rectText.adjust(-5, -5, 5, 5); rectText.moveBottomLeft(anchor.toPoint() + QPoint(-50,-50)); p.setFont(f); CDraw::bubble(p, rectText, anchor.toPoint(), 18 /* px */, 21 /* px */); p.save(); p.translate(5,5); p.setPen(Qt::darkBlue); p.drawText(rectText, str); p.restore(); } } void CGisItemRte::drawLabel(QPainter& p, const QPolygonF& viewport, QList &blockedAreas, const QFontMetricsF &fm, CGisDraw *gis) { QMutexLocker lock(&mutexItems); if(!isVisible(boundingRect, viewport, gis)) { return; } for(const rtept_t &rtept : rte.pts) { QPointF pt(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD); gis->convertRad2Px(pt); //pt = pt - rtept.focus; //p.drawPixmap(pt, rtept.icon); QRectF rect = fm.boundingRect(rtept.name); rect.adjust(-2,-2,2,2); // place label on top rect.moveCenter(pt + QPointF(rtept.icon.width()/2, -fm.height())); if(isBlocked(rect, blockedAreas)) { // place label on bottom rect.moveCenter(pt + QPointF( rtept.icon.width()/2, +fm.height() + rtept.icon.height())); if(isBlocked(rect, blockedAreas)) { // place label on right rect.moveCenter(pt + QPointF( rtept.icon.width() + rect.width()/2, +fm.height())); if(isBlocked(rect, blockedAreas)) { // place label on left rect.moveCenter(pt + QPointF( -rect.width()/2, +fm.height())); if(isBlocked(rect, blockedAreas)) { // failed to place label anywhere return; } } } } CDraw::text(rtept.name, p, rect.toRect(), Qt::darkBlue); blockedAreas << rect; } } void CGisItemRte::drawHighlight(QPainter& p) { QMutexLocker lock(&mutexItems); if(line.isEmpty() || hasUserFocus()) { return; } p.setPen(QPen(QColor(255,0,0,100),11,Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(line); } void CGisItemRte::readRouteDataFromGisLine(const SGisLine &l) { bool doAutoRouting = !l.first().subpts.isEmpty(); rte.pts.clear(); for(int i = 0; i < l.size(); i++) { rte.pts << rtept_t(); rtept_t& rtept = rte.pts.last(); const point_t& pt = l[i]; rtept.lon = pt.coord.x() * RAD_TO_DEG; rtept.lat = pt.coord.y() * RAD_TO_DEG; rtept.ele = pt.ele; rtept.name = pt.name; } if(doAutoRouting) { calc(); } deriveSecondaryData(); } void CGisItemRte::setDataFromPolyline(const SGisLine &l) { QMutexLocker lock(&mutexItems); mouseMoveFocus = nullptr; readRouteDataFromGisLine(l); flags |= eFlagTainted; changed(tr("Changed route points."), "://icons/48x48/LineMove.png"); } void CGisItemRte::getPolylineFromData(SGisLine& l) { QMutexLocker lock(&mutexItems); l.clear(); for(const rtept_t &rtept : rte.pts) { l << point_t(QPointF(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD)); point_t& pt = l.last(); pt.subpts.clear(); for(const subpt_t &subpt : rtept.subpts) { pt.subpts << IGisLine::subpt_t(QPointF(subpt.lon * DEG_TO_RAD, subpt.lat * DEG_TO_RAD)); } } } void CGisItemRte::calc() { QMutexLocker lock(&mutexItems); mouseMoveFocus = nullptr; for(int i = 0; i < rte.pts.size(); i++) { rte.pts[i].subpts.clear(); } CRouterSetup::self().calcRoute(getKey()); } void CGisItemRte::reset() { QMutexLocker lock(&mutexItems); for(int i = 0; i < rte.pts.size(); i++) { rtept_t& pt = rte.pts[i]; pt.subpts.clear(); pt.fakeSubpt = subpt_t(); } mouseMoveFocus = nullptr; rte.totalDistance = NOFLOAT; rte.totalTime = 0; rte.lastRoutedTime = QDateTime(); rte.lastRoutedWith = ""; deriveSecondaryData(); updateHistory(); if(key == keyUserFocus) { gainUserFocus(false); } } QPointF CGisItemRte::setMouseFocusByPoint(const QPoint& pt, focusmode_e fmode, const QString &owner) { QMutexLocker lock(&mutexItems); const subpt_t * newPointOfFocus = nullptr; quint32 idx = 0; if(pt != NOPOINT && GPS_Math_DistPointPolyline(line, pt) < MIN_DIST_FOCUS) { quint32 i = 0; qint32 d1 = NOINT; for(const QPointF &point : line) { int tmp = (pt - point).manhattanLength(); if(tmp <= d1) { idx = i; d1 = tmp; } i++; } newPointOfFocus = getSubPtByIndex(idx); } if(newPointOfFocus && (newPointOfFocus->type == subpt_t::eTypeNone)) { newPointOfFocus = nullptr; } mouseMoveFocus = newPointOfFocus; return newPointOfFocus ? ((int)idx < line.size() ? line[idx] : NOPOINTF) : NOPOINTF; } const CGisItemRte::subpt_t * CGisItemRte::getSubPtByIndex(quint32 idx) { quint32 cnt = 0; for(const rtept_t &rtept : rte.pts) { if(cnt == idx) { return &rtept.fakeSubpt; } for(const subpt_t &subpt : rtept.subpts) { cnt++; if(cnt == idx) { return &subpt; } } cnt++; } return nullptr; } void CGisItemRte::setResult(Routino_Output * route, const QString& options) { QMutexLocker lock(&mutexItems); qint32 idxRtept = -1; rtept_t * rtept = nullptr; QDateTime time = QDateTime::currentDateTimeUtc(); Routino_Output * next = route; while(next) { if(next->type == ROUTINO_POINT_WAYPOINT) { idxRtept++; rtept = &rte.pts[idxRtept]; rtept->subpts.clear(); rtept->fakeSubpt.lon = next->lon * RAD_TO_DEG; rtept->fakeSubpt.lat = next->lat * RAD_TO_DEG; rtept->fakeSubpt.turn = next->turn; rtept->fakeSubpt.bearing = next->bearing; rtept->fakeSubpt.distance = next->dist * 1000; rtept->fakeSubpt.time = time.addSecs(next->time * 60); rtept->fakeSubpt.type = subpt_t::eTypeWpt; rtept->fakeSubpt.instruction = QString(next->desc1) + ".\n" + QString(next->desc2) + "."; rte.totalDistance = rtept->fakeSubpt.distance; rte.totalTime = rtept->fakeSubpt.time.toTime_t() - time.toTime_t(); } else if(rtept != nullptr) { rtept->subpts << subpt_t(); subpt_t& subpt = rtept->subpts.last(); subpt.lon = next->lon * RAD_TO_DEG; subpt.lat = next->lat * RAD_TO_DEG; subpt.turn = next->turn; subpt.bearing = next->bearing; subpt.distance = next->dist * 1000; subpt.time = time.addSecs(next->time * 60); if(next->name != 0) { subpt.streets << next->name; } if(next->type > ROUTINO_POINT_CHANGE) { subpt.type = subpt_t::eTypeJunct; } else { subpt.type = subpt_t::eTypeNone; } rte.totalDistance = subpt.distance; rte.totalTime = subpt.time.toTime_t() - time.toTime_t(); subpt.instruction = QString(next->desc1) + ".\n" + QString(next->desc2) + "."; } next = next->next; } rte.lastRoutedTime = QDateTime::currentDateTimeUtc(); rte.lastRoutedWith = "Routino, " + options; deriveSecondaryData(); updateHistory(); } struct maneuver_t { QStringList streets; QString instruction; quint32 time; qreal dist; qint32 bearing; qint32 turn; }; static const qint32 idx2bearing[] = { NOINT , 0 , -45 , 45 , 180 , 135 , -135 , -90 , 90 }; void CGisItemRte::setResult(const QDomDocument& xml, const QString &options) { QMutexLocker lock(&mutexItems); QDateTime localtime = QDateTime::currentDateTimeUtc(); QDomElement response = xml.firstChildElement("response"); QDomElement route = response.firstChildElement("route"); // get time of travel QDomElement xmlTime = route.firstChildElement("time"); rte.totalTime = xmlTime.text().toUInt(); // build list of maneuvers QDomNodeList xmlLegs = route.firstChildElement("legs").elementsByTagName("leg"); const qint32 L = xmlLegs.size(); QList maneuvers; for(int l = 0; l < L; l++) { QDomNode xmlLeg = xmlLegs.item(l); QDomNodeList xmlManeuvers = xmlLeg.firstChildElement("maneuvers").elementsByTagName("maneuver"); const qint32 M = xmlManeuvers.size(); for(int m = 0; m < M; m++) { maneuvers << maneuver_t(); maneuver_t& maneuver = maneuvers.last(); QDomNode xmlManeuver = xmlManeuvers.item(m); maneuver.instruction = xmlManeuver.firstChildElement("narrative").text(); maneuver.time = xmlManeuver.firstChildElement("time").text().toUInt(); maneuver.dist = xmlManeuver.firstChildElement("distance").text().toFloat(); maneuver.bearing = idx2bearing[xmlManeuver.firstChildElement("direction").text().toUInt()]; maneuver.turn = xmlManeuver.firstChildElement("turnType").text().toInt(); QDomNodeList xmlStreets = xmlManeuver.toElement().elementsByTagName("streets"); const int S = xmlStreets.size(); for(int s = 0; s < S; s++) { QDomNode xmlStreet = xmlStreets.item(s); maneuver.streets << xmlStreet.toElement().text(); } } } QVector shape; // read the shape QDomElement xmlShape = route.firstChildElement("shape"); QDomElement xmlShapePoints = xmlShape.firstChildElement("shapePoints"); QDomNodeList xmlLatLng = xmlShapePoints.elementsByTagName("latLng"); const qint32 N = xmlLatLng.size(); for(int n = 0; n < N; n++) { QDomNode elem = xmlLatLng.item(n); QDomElement lat = elem.firstChildElement("lat"); QDomElement lng = elem.firstChildElement("lng"); shape << subpt_t(); subpt_t& subpt = shape.last(); subpt.lon = lng.text().toFloat(); subpt.lat = lat.text().toFloat(); } QVector idxLegs; QDomElement xmlLegIndexes = xmlShape.firstChildElement("legIndexes"); QDomNodeList xmlIndex = xmlLegIndexes.elementsByTagName("index"); const qint32 I = xmlIndex.size(); for(int i = 0; i < I; i++) { QDomNode elem = xmlIndex.item(i); idxLegs << elem.toElement().text().toUInt(); } quint32 time = 0; quint32 dist = 0; QDomElement xmlManeuverIndexes = xmlShape.firstChildElement("maneuverIndexes"); xmlIndex = xmlManeuverIndexes.elementsByTagName("index"); qint32 M = xmlIndex.size(); for(int m = 0; m < M; m++) { QDomNode elem = xmlIndex.item(m); quint32 idx = elem.toElement().text().toUInt(); subpt_t& subpt = shape[idx]; maneuver_t& maneuver = maneuvers[m]; subpt.type = subpt_t::eTypeJunct; subpt.instruction = maneuver.instruction; subpt.time = localtime.addSecs(time); time += maneuver.time; subpt.distance = dist; dist += maneuver.dist * 1000; subpt.bearing = maneuver.bearing; subpt.turn = maneuver.turn; subpt.streets = maneuver.streets; } for(int i = 0; i < rte.pts.size() - 1; i++ ) { quint32 idx1 = idxLegs[i]; quint32 idx2 = idxLegs[i+1]; rtept_t& rtept = rte.pts[i]; rtept.subpts = shape.mid(idx1, idx2 - idx1 + 1); rtept.fakeSubpt.lon = rtept.lon; rtept.fakeSubpt.lat = rtept.lat; } rtept_t& rtept = rte.pts.last(); rtept.fakeSubpt.lon = rtept.lon; rtept.fakeSubpt.lat = rtept.lat; rte.totalDistance = dist; rte.lastRoutedTime = QDateTime::currentDateTimeUtc(); rte.lastRoutedWith = "MapQuest" + options; deriveSecondaryData(); updateHistory(); } void CGisItemRte::setResultFromBRouter(const QDomDocument &xml, const QString &options) { QMutexLocker lock(&mutexItems); QVector shape; const QDomElement &gpx = xml.documentElement(); // read the shape const QDomElement &xmlShape = gpx.firstChildElement("trk"); const QDomElement &xmlShapePoints = xmlShape.firstChildElement("trkseg"); const QDomNodeList &xmlLatLng = xmlShapePoints.elementsByTagName("trkpt"); const qint32 N = xmlLatLng.size(); for(int n = 0; n < N; n++) { const QDomElement &elem = xmlLatLng.item(n).toElement(); shape << subpt_t(); subpt_t& subpt = shape.last(); subpt.lon = elem.attribute("lon").toFloat(); subpt.lat = elem.attribute("lat").toFloat(); subpt.ele = elem.firstChildElement("ele").text().toFloat(); } // build list of maneuvers const QDomElement &xmlLeg = gpx.firstChildElement("rte"); if (!xmlLeg.isNull()) { const QDomNodeList &xmlManeuvers = xmlLeg.elementsByTagName("rtept"); const qint32 M = xmlManeuvers.size(); for(int m = 0; m < M; m++) { const QDomNode &xmlManeuver = xmlManeuvers.item(m); /* right TR 45.655945 76 */ quint32 idx = xmlManeuver.firstChildElement("extensions").firstChildElement("offset").text().toUInt(); subpt_t& subpt = shape[idx]; subpt.type = subpt_t::eTypeJunct; subpt.instruction = xmlManeuver.firstChildElement("desc").text(); const QString &command = xmlManeuver.firstChildElement("extensions").firstChildElement("turn").text(); // command if(command=="TU") // u-turn { subpt.bearing = 180; } else if(command=="TSHL") // turn sharp left { subpt.bearing = -135; } else if(command=="TL") // turn left { subpt.bearing = -90; } else if(command=="TSLL") // turn slight left { subpt.bearing = -45; } else if(command=="KL") // keep left { subpt.bearing = 0; } else if(command=="C") // straight { subpt.bearing = 0; } else if(command=="KR") // keep right { subpt.bearing = 0; } else if(command=="TSLR") // turn slight right { subpt.bearing = 45; } else if(command=="TR") // turn right { subpt.bearing = 90; } else if(command=="TSHR") // turn sharp right { subpt.bearing = 135; } else if(command=="TRU") // u-turn { subpt.bearing = 180; } else if(command.startsWith("RNDB")) // take roundabout exit nr { subpt.bearing = 0; } else if(command.startsWith("RNLB")) // take roundabout exit nr. (to the left) { subpt.bearing = 0; } subpt.turn = xmlManeuver.firstChildElement("extensions").firstChildElement("turn-angle").text().toUInt(); // turn angle (degree) } } // match routepoints to shape qint32 startIdx = 0; qint32 minDistIdx = 0; for(qint32 rtIdx = 0; rtIdx < rte.pts.size() - 1; rtIdx++) { rtept_t &routePoint = rte.pts[rtIdx]; const rtept_t &nextRoutePoint = rte.pts[rtIdx+1]; qreal minDist = std::pow(nextRoutePoint.lon - shape[minDistIdx].lon, 2) + std::pow(nextRoutePoint.lat - shape[minDistIdx].lat, 2); for (qint32 idx = startIdx+1; idx < shape.size(); idx++) { qreal dist = std::pow(nextRoutePoint.lon - shape[idx].lon, 2) + std::pow(nextRoutePoint.lat - shape[idx].lat, 2); if (dist < minDist) { minDist = dist; minDistIdx = idx; } } routePoint.ele = shape[startIdx].ele; routePoint.subpts = shape.mid(startIdx,minDistIdx-startIdx); routePoint.fakeSubpt.lon = routePoint.lon; routePoint.fakeSubpt.lat = routePoint.lat; routePoint.fakeSubpt.ele = routePoint.ele; startIdx = minDistIdx; } rtept_t &rtept = rte.pts.last(); rtept.ele = shape[minDistIdx].ele; rtept.fakeSubpt.lon = rtept.lon; rtept.fakeSubpt.lat = rtept.lat; rtept.fakeSubpt.ele = rtept.ele; rte.lastRoutedTime = QDateTime::currentDateTimeUtc(); rte.lastRoutedWith = QString("BRouter %1").arg(options); // const QDomNodeList &nodes = xml.childNodes(); for (int i = 0; i < nodes.count(); i++) { const QDomNode &node = nodes.at(i); if (node.isComment()) { const QString &commentTxt = node.toComment().data(); // ' track-length = 180864 filtered ascend = 428 plain-ascend = -172 cost=270249 ' const QRegExp rxAscDes("(\\s*track-length\\s*=\\s*)(-?\\d+)(\\s*)(filtered ascend\\s*=\\s*-?\\d+)(\\s*)(plain-ascend\\s*=\\s*-?\\d+)(\\s*)(cost\\s*=\\s*-?\\d+)(\\s*)"); int pos = rxAscDes.indexIn(commentTxt); if (pos > -1) { rte.totalDistance = rxAscDes.cap(2).toFloat(); rte.cmt = QString("%1, %2, %3").arg(rxAscDes.cap(4)).arg(rxAscDes.cap(6)).arg(rxAscDes.cap(8)); } break; } } deriveSecondaryData(); updateHistory(); } qmapshack-1.10.0/src/gis/rte/CCreateRouteFromWpt.h000644 001750 000144 00000002637 13216234143 023111 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CCREATEROUTEFROMWPT_H #define CCREATEROUTEFROMWPT_H #include "gis/IGisItem.h" #include "ui_ICreateRouteFromWpt.h" #include class CCreateRouteFromWpt : public QDialog, private Ui::ICreateRouteFromWpt { Q_OBJECT public: CCreateRouteFromWpt(const QList& keys, QWidget * parent); virtual ~CCreateRouteFromWpt(); public slots: void accept() override; private slots: void slotSelectionChanged(); void slotUp(); void slotDown(); }; #endif //CCREATEROUTEFROMWPT_H qmapshack-1.10.0/src/gis/rte/CGisItemRte.h000644 001750 000144 00000015446 13216234261 021367 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CGISITEMRTE_H #define CGISITEMRTE_H #include "gis/IGisItem.h" #include "gis/IGisLine.h" #include #include "gis/fit/CFitStream.h" #include #include class QDomNode; class IGisProject; class CQlgtRoute; class CScrOptRte; class CGisItemRte : public IGisItem, public IGisLine { Q_DECLARE_TR_FUNCTIONS(CGisItemRte) public: enum focusmode_e { eFocusMouseMove ,eFocusMouseClick }; struct subpt_t { enum type_e { eTypeNone , eTypeWpt , eTypeJunct }; qreal lon = NOFLOAT; qreal lat = NOFLOAT; quint8 type = eTypeNone; qreal turn = NOFLOAT; qreal bearing = NOFLOAT; QStringList streets; QString instruction; qreal distance = 0; QDateTime time; qint32 ele = NOINT; }; struct rtept_t : public wpt_t { rtept_t() { fakeSubpt.type = subpt_t::eTypeWpt; } void updateIcon(); QPixmap icon; QPointF focus; subpt_t fakeSubpt; QVector subpts; }; struct rte_t { // -- all gpx tags - start QString name; QString cmt; QString desc; QString src; QList links; quint64 number = 0; QString type; QVector pts; // -- all gpx tags - stop QString lastRoutedWith; QDateTime lastRoutedTime; qreal totalDistance = NOFLOAT; quint32 totalTime = 0; qreal ascent = NOFLOAT; qreal descent = NOFLOAT; }; CGisItemRte(const QDomNode &xml, IGisProject *parent); CGisItemRte(const CGisItemRte& parentRte, IGisProject *project, int idx, bool clone); CGisItemRte(const history_t& hist, const QString& dbHash, IGisProject * project); CGisItemRte(quint64 id, QSqlDatabase& db, IGisProject * project); CGisItemRte(const CQlgtRoute& rte1, IGisProject *project = nullptr); CGisItemRte(const SGisLine& l, const QString &name, IGisProject *project, int idx); CGisItemRte(CFitStream& stream, IGisProject * project); virtual ~CGisItemRte(); IGisItem * createClone() override; QDataStream& operator<<(QDataStream& stream) override; QDataStream& operator>>(QDataStream& stream) const override; const QString& getName() const override { return rte.name.isEmpty() ? noName : rte.name; } QString getInfo(quint32 feature) const override; IScrOpt * getScreenOptions(const QPoint &origin, IMouse * mouse) override; QPointF getPointCloseBy(const QPoint& screenPos) override; void drawItem(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, CGisDraw * gis) override; void drawItem(QPainter& p, const QRectF& viewport, CGisDraw * gis) override; void drawLabel(QPainter& p, const QPolygonF& viewport, QList& blockedAreas, const QFontMetricsF& fm, CGisDraw * gis) override; void drawHighlight(QPainter& p) override; void save(QDomNode& gpx, bool strictGpx11) override; bool isCloseTo(const QPointF& pos) override; bool isWithin(const QRectF& area, selflags_t flags) override; /** @brief Switch user focus on and off. If the focus is switched on any other route having the focus will loose it. @param yes set true to gain focus. */ void gainUserFocus(bool yes) override; /** @brief Make sure the route has lost focus. If the route has the focus, keyUserFocus will be reset. In all other cases nothing will be done. */ void looseUserFocus(); /** @brief Check for user focus @return True if the route has user focus */ bool hasUserFocus() const override { return key == keyUserFocus; } /** @brief Get the key of the current track with user focus @return If no route has the focus an empty string is returned */ static const key_t& getKeyUserFocus() { return keyUserFocus; } void setDataFromPolyline(const SGisLine& l) override; void getPolylineFromData(SGisLine &l) override; const QString& getComment() const override { return rte.cmt; } const QString& getDescription() const override { return rte.desc; } const QList& getLinks() const override { return rte.links; } const rte_t& getRoute() const { return rte; } QDateTime getTimestamp() const override { return QDateTime(); } void setName(const QString& str); void setComment(const QString& str) override; void setDescription(const QString& str) override; void setLinks(const QList& links) override; void calc(); void reset(); void edit() override; void toTrack(); QPointF setMouseFocusByPoint(const QPoint& pt, focusmode_e fmode, const QString &owner); void setResult(Routino_Output * route, const QString &options); void setResult(const QDomDocument& xml, const QString &options); void setResultFromBRouter(const QDomDocument& xml, const QString &options); bool isCalculated(); private: void deriveSecondaryData(); void setElevation(qreal ele, subpt_t &subpt, qreal &lastEle); void setSymbol() override; void readRte(const QDomNode& xml, rte_t& rte); void readRteFromFit(CFitStream &stream); void readRouteDataFromGisLine(const SGisLine &l); const subpt_t * getSubPtByIndex(quint32 idx); static key_t keyUserFocus; static const QPen penBackground; QPen penForeground {Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; QPen penForegroundFocus {Qt::magenta, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin}; rte_t rte; QPolygonF line; const subpt_t * mouseMoveFocus = nullptr; QPointer scrOpt; }; #endif //CGISITEMRTE_H qmapshack-1.10.0/src/gis/rte/CScrOptRte.h000644 001750 000144 00000003074 13216234143 021231 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTRTE_H #define CSCROPTRTE_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptRte.h" #include class CGisItemRte; class IMouse; class CScrOptRte : public IScrOpt, private Ui::IScrOptRte { Q_OBJECT public: CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent); virtual ~CScrOptRte(); void draw(QPainter& p) override; private slots: void slotEditDetails(); void slotDelete(); void slotCopy(); void slotCalc(); void slotReset(); void slotEdit(); void slotInstruction(bool on); void slotToTrack(); private: IGisItem::key_t key; QPointF anchor; }; #endif //CSCROPTRTE_H qmapshack-1.10.0/src/gis/rte/ICreateRouteFromWpt.ui000644 001750 000144 00000006452 12542715222 023307 0ustar00oeichlerxusers000000 000000 ICreateRouteFromWpt 0 0 400 300 Create Route from Waypoints false ... :/icons/32x32/Up.png:/icons/32x32/Up.png 22 22 false ... :/icons/32x32/Down.png:/icons/32x32/Down.png 22 22 Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ICreateRouteFromWpt accept() 248 254 157 274 buttonBox rejected() ICreateRouteFromWpt reject() 316 260 286 274 qmapshack-1.10.0/src/gis/rte/router/000755 001750 000144 00000000000 13216664445 020420 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/rte/router/IRouter.h000644 001750 000144 00000003351 13216234261 022151 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IROUTER_H #define IROUTER_H #include "gis/IGisItem.h" #include class IRouter : public QWidget { Q_OBJECT public: struct circle_t { circle_t() : lon(NOFLOAT), lat(NOFLOAT), rad(NOINT) { } circle_t(const qreal& lat, const qreal& lon, const qreal& rad) : lon(lon), lat(lat), rad(rad) { } qreal lon; qreal lat; quint32 rad; }; IRouter(bool fastRouting, QWidget * parent); virtual ~IRouter(); virtual void calcRoute(const IGisItem::key_t& key) = 0; virtual int calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) = 0; virtual bool hasFastRouting() { return fastRouting; } virtual QString getOptions() = 0; private: bool fastRouting; }; #endif //IROUTER_H qmapshack-1.10.0/src/gis/rte/router/IRouterSetup.ui000644 001750 000144 00000002131 12551744506 023364 0ustar00oeichlerxusers000000 000000 IRouterSetup 0 0 302 382 Form 3 3 3 3 3 Qt::Horizontal qmapshack-1.10.0/src/gis/rte/router/CRouterRoutino.h000644 001750 000144 00000003376 13216234143 023531 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CROUTERROUTINO_H #define CROUTERROUTINO_H #include "gis/rte/router/IRouter.h" #include "ui_IRouterRoutino.h" #include #include class CProgressDialog; class CRouterRoutino : public IRouter, private Ui::IRouterRoutino { Q_OBJECT public: CRouterRoutino(QWidget * parent); virtual ~CRouterRoutino(); void calcRoute(const IGisItem::key_t& key) override; int calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) override; bool hasFastRouting() override; QString getOptions() override; static QPointer progress; private slots: void slotSetupPaths(); private: void buildDatabaseList(); void freeDatabaseList(); void updateHelpText(); QString xlateRoutinoError(int err); QStringList dbPaths; QMutex mutex {QMutex::NonRecursive}; }; #endif //CROUTERROUTINO_H qmapshack-1.10.0/src/gis/rte/router/IRouterMapQuest.ui000644 001750 000144 00000006217 12553110242 024016 0ustar00oeichlerxusers000000 000000 IRouterMapQuest 0 0 400 300 Form Highways Seasonal Language Country Border Profile Avoid: Ferry Toll Road Unpaved Qt::Vertical 20 123 <p>Directions Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> </p> true qmapshack-1.10.0/src/gis/rte/router/CRouterBRouter.h000644 001750 000144 00000006614 13216234261 023453 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTER_H #define CROUTERBROUTER_H #include "gis/rte/router/IRouter.h" #include "ui_IRouterBRouter.h" #include #include #include class CRouterBRouterSetup; class CRouterBRouterSetupWizard; class CRouterBRouterInfo; class CRouterBRouterToolShell; class CRouterSetup; class CProgressDialog; class CRouterBRouter : public IRouter, private Ui::IRouterBRouter { Q_OBJECT public: CRouterBRouter(QWidget * parent); virtual ~CRouterBRouter(); void calcRoute(const IGisItem::key_t& key) override; int calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) override; bool hasFastRouting() override; QString getOptions() override; private slots: void slotToolSetupClicked(); void slotRequestFinished(QNetworkReply* reply); void slotCloseStatusMsg() const; void slotToolProfileInfoClicked() const; void slotDisplayError(const QString &error, const QString &details) const; void slotDisplayProfileInfo(const QString &profile, const QString &content); void slotBRouterStateChanged(const QProcess::ProcessState newState); void slotBRouterError(const QProcess::ProcessError error, const QString &errorString); void slotToggleBRouter() const; void slotToggleConsole() const; private: struct wpt_t { wpt_t() : lat(NOFLOAT), lon(NOFLOAT) { } wpt_t(const qreal& lat, const qreal& lon) : lat(lat), lon(lon) { } qreal lat; qreal lon; }; void updateDialog() const; void startBRouter() const; void stopBRouter() const; void updateLocalBRouterStatus() const; QNetworkRequest getRequest(const QVector& routePoints, const QVector &areas) const; QUrl getServiceUrl() const; void clearError(); QNetworkAccessManager * networkAccessManager; QTimer * timerCloseStatusMsg; bool synchronous = false; QMutex mutex {QMutex::NonRecursive}; CRouterBRouterSetup * setup; CRouterSetup * routerSetup; CRouterBRouterInfo * info; CRouterBRouterToolShell * brouterShell {nullptr}; QProcess::ProcessState brouterState { QProcess::NotRunning }; QProcess::ProcessError brouterError { QProcess::UnknownError }; CProgressDialog * progress; bool isError { false }; QString error; QString errorDetails; bool isShutdown { false }; }; #endif //CROUTERBROUTER_H qmapshack-1.10.0/src/gis/rte/router/CRouterRoutino.cpp000644 001750 000144 00000033622 13216234140 024056 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/CRouterRoutino.h" #include "gis/rte/router/routino/CRouterRoutinoPathSetup.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include "setup/IAppSetup.h" #include #include #include QPointer CRouterRoutino::progress; int ProgressFunc(double complete) { if(CRouterRoutino::progress.isNull()) { return true; } CRouterRoutino::progress->setValue(complete*100); return !CRouterRoutino::progress->wasCanceled(); } CRouterRoutino::CRouterRoutino(QWidget *parent) : IRouter(true, parent) { setupUi(this); if(Routino_CheckAPIVersion() != ROUTINO_ERROR_NONE) { QMessageBox::warning(this, tr("Warning..."), tr("Found Routino with a wrong version. Expected %1 found %2").arg(ROUTINO_API_VERSION).arg(Routino_APIVersion), QMessageBox::Ok); return; } comboMode->addItem(tr("Shortest")); comboMode->addItem(tr("Quickest")); int res = 0; IAppSetup *setup = IAppSetup::getPlatformInstance(); res = Routino_ParseXMLProfiles(setup->routinoPath("profiles.xml").toUtf8()); if(res) { QMessageBox::critical(this, "Routino...", xlateRoutinoError(Routino_errno), QMessageBox::Abort); return; } res = Routino_ParseXMLTranslations(setup->routinoPath("translations.xml").toUtf8()); if(res) { QMessageBox::critical(this, "Routino...", xlateRoutinoError(Routino_errno), QMessageBox::Abort); return; } comboProfile->addItem(tr("Foot"), "foot"); comboProfile->addItem(tr("Horse"), "horse"); comboProfile->addItem(tr("Wheelchair"), "wheelchair"); comboProfile->addItem(tr("Bicycle"), "bicycle"); comboProfile->addItem(tr("Moped"), "moped"); comboProfile->addItem(tr("Motorcycle"), "motorcycle"); comboProfile->addItem(tr("Motorcar"), "motorcar"); comboProfile->addItem(tr("Goods"), "goods"); comboLanguage->addItem(tr("English"), "en"); comboLanguage->addItem(tr("German"), "de"); comboLanguage->addItem(tr("French"), "fr"); comboLanguage->addItem(tr("Hungarian"), "hu"); comboLanguage->addItem(tr("Dutch"), "nl"); comboLanguage->addItem(tr("Russian"), "ru"); comboLanguage->addItem(tr("Polish"), "pl"); connect(toolSetupPaths, &QToolButton::clicked, this, &CRouterRoutino::slotSetupPaths); SETTINGS; dbPaths = cfg.value("Route/routino/paths", dbPaths).toStringList(); buildDatabaseList(); comboProfile->setCurrentIndex(cfg.value("Route/routino/profile",0).toInt()); comboLanguage->setCurrentIndex(cfg.value("Route/routino/language",0).toInt()); comboMode->setCurrentIndex(cfg.value("Route/routino/mode",0).toInt()); comboDatabase->setCurrentIndex(cfg.value("Route/routino/database",0).toInt()); updateHelpText(); } CRouterRoutino::~CRouterRoutino() { SETTINGS; cfg.setValue("Route/routino/paths", dbPaths); cfg.setValue("Route/routino/profile", comboProfile->currentIndex()); cfg.setValue("Route/routino/language", comboLanguage->currentIndex()); cfg.setValue("Route/routino/mode", comboMode->currentIndex()); cfg.setValue("Route/routino/database", comboDatabase->currentIndex()); freeDatabaseList(); Routino_FreeXMLProfiles(); Routino_FreeXMLTranslations(); } QString CRouterRoutino::xlateRoutinoError(int err) { switch(err) { case ROUTINO_ERROR_NO_DATABASE: return tr("A function was called without the database variable set."); case ROUTINO_ERROR_NO_PROFILE: return tr("A function was called without the profile variable set."); case ROUTINO_ERROR_NO_TRANSLATION: return tr("A function was called without the translation variable set."); case ROUTINO_ERROR_NO_DATABASE_FILES: return tr("The specified database to load did not exist."); case ROUTINO_ERROR_BAD_DATABASE_FILES: return tr("The specified database could not be loaded."); case ROUTINO_ERROR_NO_PROFILES_XML: return tr("The specified profiles XML file did not exist."); case ROUTINO_ERROR_BAD_PROFILES_XML: return tr("The specified profiles XML file could not be loaded."); case ROUTINO_ERROR_NO_TRANSLATIONS_XML: return tr("The specified translations XML file did not exist."); case ROUTINO_ERROR_BAD_TRANSLATIONS_XML: return tr("The specified translations XML file could not be loaded."); case ROUTINO_ERROR_NO_SUCH_PROFILE: return tr("The requested profile name does not exist in the loaded XML file."); case ROUTINO_ERROR_NO_SUCH_TRANSLATION: return tr("The requested translation language does not exist in the loaded XML file."); case ROUTINO_ERROR_NO_NEARBY_HIGHWAY: return tr("In the routing database there is no highway near the coordinates to place a waypoint."); case ROUTINO_ERROR_PROFILE_DATABASE_ERR: return tr("The profile and database do not work together."); case ROUTINO_ERROR_NOTVALID_PROFILE: return tr("The profile being used has not been validated."); case ROUTINO_ERROR_BAD_USER_PROFILE: return tr("The user specified profile contained invalid data."); case ROUTINO_ERROR_BAD_OPTIONS: return tr("The routing options specified are not consistent with each other."); case ROUTINO_ERROR_WRONG_API_VERSION: return tr("There is a mismatch between the library and caller API version."); case ROUTINO_ERROR_PROGRESS_ABORTED: return tr("Route calculation was aborted by user."); } if(ROUTINO_ERROR_NO_ROUTE_1 <= err) { int n = err - 1000; return tr("A route could not be found to waypoint %1.").arg(n); } return tr("Unknown error: %1").arg(err); } bool CRouterRoutino::hasFastRouting() { return IRouter::hasFastRouting() && (comboDatabase->count() != 0); } QString CRouterRoutino::getOptions() { QString str; str = tr("profile \"%1\"").arg(comboProfile->currentText()); str += tr(", mode \"%1\"").arg(comboMode->currentText()); return str; } void CRouterRoutino::slotSetupPaths() { CRouterRoutinoPathSetup dlg(dbPaths); dlg.exec(); buildDatabaseList(); updateHelpText(); } void CRouterRoutino::buildDatabaseList() { QRegExp re("(.*)-segments.mem"); freeDatabaseList(); for(const QString &path : dbPaths) { QDir dir(path); for(const QString &filename : dir.entryList(QStringList("*segments.mem"), QDir::Files|QDir::Readable, QDir::Name)) { QString prefix; if(re.exactMatch(filename)) { prefix = re.cap(1); } else { continue; } #ifdef Q_OS_WIN Routino_Database * data = Routino_LoadDatabase(dir.absolutePath().toLocal8Bit(), prefix.toLocal8Bit()); #else Routino_Database * data = Routino_LoadDatabase(dir.absolutePath().toUtf8(), prefix.toUtf8()); #endif if(data) { comboDatabase->addItem(prefix.replace("_", " "), quint64(data)); } else { QMessageBox::critical(this, "Routino...", xlateRoutinoError(Routino_errno), QMessageBox::Abort); } } } } void CRouterRoutino::freeDatabaseList() { for(int i = 0; i < comboDatabase->count(); i++) { Routino_Database * data = (Routino_Database*)comboDatabase->itemData(i, Qt::UserRole).toULongLong(); Routino_UnloadDatabase(data); } comboDatabase->clear(); } void CRouterRoutino::updateHelpText() { bool haveDB = (comboDatabase->count() != 0); frameHelp->setVisible(!haveDB); comboDatabase->setEnabled(haveDB); } void CRouterRoutino::calcRoute(const IGisItem::key_t& key) { if(!mutex.tryLock()) { return; } try { QTime time; time.start(); CGisItemRte * rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr == rte) { throw QString(); } Routino_Database * data = (Routino_Database*)comboDatabase->currentData(Qt::UserRole).toULongLong(); if(nullptr == data) { throw QString(); } rte->reset(); QString strProfile = comboProfile->currentData(Qt::UserRole).toString(); QString strLanguage = comboLanguage->currentData(Qt::UserRole).toString(); Routino_Profile *profile = Routino_GetProfile(strProfile.toUtf8()); Routino_Translation *translation = Routino_GetTranslation(strLanguage.toUtf8()); int res = Routino_ValidateProfile(data,profile); if(res != 0) { throw xlateRoutinoError(Routino_errno); } int options = ROUTINO_ROUTE_LIST_HTML_ALL; if(comboMode->currentIndex() == 0) { options |= ROUTINO_ROUTE_SHORTEST; } if(comboMode->currentIndex() == 1) { options |= ROUTINO_ROUTE_QUICKEST; } SGisLine line; rte->getPolylineFromData(line); int idx = 0; QVector waypoints(line.size(), nullptr); for(const IGisLine::point_t &pt : line) { waypoints[idx] = Routino_FindWaypoint(data, profile, pt.coord.y()*RAD_TO_DEG, pt.coord.x()*RAD_TO_DEG); if(waypoints[idx] == nullptr) { throw xlateRoutinoError(Routino_errno); } idx++; } progress = new CProgressDialog(tr("Calculate route with %1").arg(getOptions()), 0, NOINT, this); Routino_Output * route = Routino_CalculateRoute(data,profile,translation,waypoints.data(),waypoints.size(),options, ProgressFunc); delete progress; if(nullptr != route) { rte->setResult(route, getOptions() + tr("
Calculation time: %1s").arg(time.elapsed()/1000.0, 0,'f',2)); Routino_DeleteRoute(route); } else { if(Routino_errno != ROUTINO_ERROR_PROGRESS_ABORTED) { throw xlateRoutinoError(Routino_errno); } } } catch(const QString& msg) { if(!msg.isEmpty()) { QMessageBox::critical(this, "Routino...", msg, QMessageBox::Abort); } } mutex.unlock(); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } int CRouterRoutino::calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) { if(!mutex.tryLock()) { return -1; } try { Routino_Database * data = (Routino_Database*)comboDatabase->currentData(Qt::UserRole).toULongLong(); if(nullptr == data) { throw QString(); } QString strProfile = comboProfile->currentData(Qt::UserRole).toString(); QString strLanguage = comboLanguage->currentData(Qt::UserRole).toString(); Routino_Profile *profile = Routino_GetProfile(strProfile.toUtf8()); Routino_Translation *translation = Routino_GetTranslation(strLanguage.toUtf8()); int res = Routino_ValidateProfile(data,profile); if(res != 0) { throw xlateRoutinoError(Routino_errno); } int options = ROUTINO_ROUTE_LIST_HTML_ALL; if(comboMode->currentIndex() == 0) { options |= ROUTINO_ROUTE_SHORTEST; } if(comboMode->currentIndex() == 1) { options |= ROUTINO_ROUTE_QUICKEST; } Routino_Waypoint* waypoints[2] = {0}; waypoints[0] = Routino_FindWaypoint(data, profile, p1.y()*RAD_TO_DEG, p1.x()*RAD_TO_DEG); if(waypoints[0] == nullptr) { throw xlateRoutinoError(Routino_errno); } waypoints[1] = Routino_FindWaypoint(data, profile, p2.y()*RAD_TO_DEG, p2.x()*RAD_TO_DEG); if(waypoints[1] == nullptr) { throw xlateRoutinoError(Routino_errno); } progress = new CProgressDialog(tr("Calculate route with %1").arg(getOptions()), 0, NOINT, this); Routino_Output * route = Routino_CalculateRoute(data,profile,translation,waypoints,2,options, ProgressFunc); delete progress; if(route != nullptr) { Routino_Output * next = route; while(next) { if(next->type != ROUTINO_POINT_WAYPOINT) { coords << QPointF(next->lon, next->lat); } next = next->next; } Routino_DeleteRoute(route); } else { if(Routino_errno != ROUTINO_ERROR_PROGRESS_ABORTED) { throw xlateRoutinoError(Routino_errno); } else { throw QString(); } } } catch(const QString& msg) { coords.clear(); if(!msg.isEmpty()) { mutex.unlock(); throw msg; } } mutex.unlock(); return coords.size(); } qmapshack-1.10.0/src/gis/rte/router/CRouterSetup.h000644 001750 000144 00000003211 13216234143 023156 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CROUTERSETUP_H #define CROUTERSETUP_H #include "gis/IGisItem.h" #include "ui_IRouterSetup.h" #include class CRouterSetup : public QWidget, private Ui::IRouterSetup { Q_OBJECT public: static CRouterSetup& self() { return *pSelf; } virtual ~CRouterSetup(); void calcRoute(const IGisItem::key_t &key); int calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords); bool hasFastRouting(); enum router_e {RouterRoutino, RouterMapquest, RouterBRouter}; void setRouterTitle(router_e, QString title); private slots: void slotSelectRouter(int i); private: friend class Ui_IMainWindow; CRouterSetup(QWidget * parent); static CRouterSetup * pSelf; }; #endif //CROUTERSETUP_H qmapshack-1.10.0/src/gis/rte/router/CRouterMapQuest.cpp000644 001750 000144 00000027407 13216234140 024162 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/CRouterMapQuest.h" #include "helpers/CSettings.h" #include #include #include const QByteArray CRouterMapQuest::keyMapQuest = "Fmjtd%7Cluu2n16t2h%2Crw%3Do5-haya0"; CRouterMapQuest::CRouterMapQuest(QWidget *parent) : IRouter(false, parent) { setupUi(this); comboMQPreference->addItem(tr("Fastest"), "fastest"); comboMQPreference->addItem(tr("Shortest"), "shortest"); comboMQPreference->addItem(tr("Bicycle"), "bicycle"); comboMQPreference->addItem(tr("Pedestrian"), "pedestrian"); comboMQLanguage->addItem(tr("US English"), "en_US"); comboMQLanguage->addItem(tr("British English"), "en_GB"); comboMQLanguage->addItem(tr("Danish"), "da_DK"); comboMQLanguage->addItem(tr("Dutch"), "nl_NL"); comboMQLanguage->addItem(tr("French"), "fr_FR"); comboMQLanguage->addItem(tr("German"), "de_DE"); comboMQLanguage->addItem(tr("Italian"), "it_IT"); comboMQLanguage->addItem(tr("Norwegian"), "no_NO"); comboMQLanguage->addItem(tr("Spanish"), "es_ES"); comboMQLanguage->addItem(tr("Swedish"), "sv_SE"); SETTINGS; int langIdx; QString locale = QLocale::system().name(); cfg.beginGroup("Route/mapquest"); langIdx = comboMQLanguage->findData(locale); comboMQPreference->setCurrentIndex(cfg.value("preference", 0).toInt()); checkMQAvoidLimAccess->setChecked(cfg.value("avoidLimAccess", false).toBool()); checkMQAvoidTollRoads->setChecked(cfg.value("avoidTollRoads", false).toBool()); checkMQAvoidSeasonal->setChecked(cfg.value("avoidSeasonal", false).toBool()); checkMQAvoidUnpaved->setChecked(cfg.value("avoidUnpaved", false).toBool()); checkMQAvoidFerry->setChecked(cfg.value("avoidFerry", false).toBool()); checkMQAvoidCountryBorder->setChecked(cfg.value("avoidCountryBorder", false).toBool()); comboMQLanguage->setCurrentIndex(cfg.value("language", langIdx).toInt()); cfg.endGroup(); networkAccessManager = new QNetworkAccessManager(this); connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CRouterMapQuest::slotRequestFinished); timerCloseStatusMsg = new QTimer(this); timerCloseStatusMsg->setSingleShot(true); timerCloseStatusMsg->setInterval(5000); connect(timerCloseStatusMsg, &QTimer::timeout, this, &CRouterMapQuest::slotCloseStatusMsg); } CRouterMapQuest::~CRouterMapQuest() { SETTINGS; cfg.beginGroup("Route/mapquest"); cfg.setValue("preference", comboMQPreference->currentIndex()); cfg.setValue("avoidLimAccess", checkMQAvoidLimAccess->isChecked()); cfg.setValue("avoidTollRoads", checkMQAvoidTollRoads->isChecked()); cfg.setValue("avoidSeasonal", checkMQAvoidSeasonal->isChecked()); cfg.setValue("avoidUnpaved", checkMQAvoidUnpaved->isChecked()); cfg.setValue("avoidFerry", checkMQAvoidFerry->isChecked()); cfg.setValue("avoidCountryBorder", checkMQAvoidCountryBorder->isChecked()); cfg.setValue("language", comboMQLanguage->currentIndex()); cfg.endGroup(); } void CRouterMapQuest::slotCloseStatusMsg() { timerCloseStatusMsg->stop(); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); canvas->reportStatus("MapQuest", ""); } } QString CRouterMapQuest::getOptions() { QString str; int times = 1; str += ", " + tr("mode \"%1\"").arg(comboMQPreference->currentText()); if(checkMQAvoidLimAccess->isChecked()) { str += ", " + tr("no highways"); } if(str.size() > 40 * times) { str += "
"; times++; } if(checkMQAvoidTollRoads->isChecked()) { str += ", " + tr("no toll roads"); } if(str.size() > 40 * times) { str += "
"; times++; } if(checkMQAvoidSeasonal->isChecked()) { str += ", " + tr("no seasonal"); } if(str.size() > 40 * times) { str += "
"; times++; } if(checkMQAvoidUnpaved->isChecked()) { str += ", " + tr("no unpaved"); } if(str.size() > 40 * times) { str += "
"; times++; } if(checkMQAvoidFerry->isChecked()) { str += ", " + tr("no ferry"); } if(str.size() > 40 * times) { str += "
"; times++; } if(checkMQAvoidCountryBorder->isChecked()) { str += ", " + tr("no crossing of country borders"); } return str; } void CRouterMapQuest::addMapQuestLocations(QDomDocument& xml, QDomElement& locations, CGisItemRte &rte) { SGisLine line; rte.getPolylineFromData(line); for(const IGisLine::point_t &pt : line) { QDomElement location = xml.createElement("location"); location.appendChild(xml.createTextNode(QString("%1,%2").arg(pt.coord.y()*RAD_TO_DEG).arg(pt.coord.x()*RAD_TO_DEG))); locations.appendChild(location); } } void CRouterMapQuest::calcRoute(const IGisItem::key_t& key) { CGisItemRte *rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr == rte) { return; } rte->reset(); slotCloseStatusMsg(); QDomDocument xml; QDomElement route = xml.createElement("route"); xml.appendChild(route); QDomElement locations = xml.createElement("locations"); route.appendChild(locations); addMapQuestLocations(xml, locations, *rte); QDomElement options = xml.createElement("options"); route.appendChild(options); QDomElement shapeFormat = xml.createElement("shapeFormat"); shapeFormat.appendChild(xml.createTextNode("raw")); options.appendChild(shapeFormat); QDomElement generalize = xml.createElement("generalize"); generalize.appendChild(xml.createTextNode("0")); options.appendChild(generalize); QDomElement unit = xml.createElement("unit"); unit.appendChild(xml.createTextNode("k")); options.appendChild(unit); QDomElement routeType = xml.createElement("routeType"); routeType.appendChild(xml.createTextNode(comboMQPreference->itemData(comboMQPreference->currentIndex()).toString())); options.appendChild(routeType); QDomElement locale = xml.createElement("locale"); locale.appendChild(xml.createTextNode(comboMQLanguage->itemData(comboMQLanguage->currentIndex()).toString())); options.appendChild(locale); QDomElement avoids = xml.createElement("avoids"); if(checkMQAvoidLimAccess->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Limited Access")); avoids.appendChild(avoid); } if(checkMQAvoidTollRoads->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Toll road")); avoids.appendChild(avoid); } if(checkMQAvoidSeasonal->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Approximate Seasonal Closure")); avoids.appendChild(avoid); } if(checkMQAvoidUnpaved->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Unpaved")); avoids.appendChild(avoid); } if(checkMQAvoidFerry->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Ferry")); avoids.appendChild(avoid); } if(checkMQAvoidCountryBorder->isChecked()) { QDomElement avoid = xml.createElement("avoid"); avoid.appendChild(xml.createTextNode("Country border crossing")); avoids.appendChild(avoid); } options.appendChild(avoids); QString xmlstr = xml.toString(0); qDebug() << xmlstr; xmlstr = xmlstr.replace("\n",""); QUrl url("http://open.mapquestapi.com"); url.setPath("/directions/v2/route"); QUrlQuery urlQuery; urlQuery.addQueryItem("key", keyMapQuest); urlQuery.addQueryItem("ambiguities", "ignore"); urlQuery.addQueryItem("inFormat", "xml"); urlQuery.addQueryItem("outFormat", "xml"); urlQuery.addQueryItem("xml", QUrl::toPercentEncoding(xmlstr)); url.setQuery(urlQuery); QNetworkRequest request; request.setUrl(url); QNetworkReply* reply = networkAccessManager->get(request); reply->setProperty("key.item", key.item); reply->setProperty("key.project", key.project); reply->setProperty("key.device", key.device); reply->setProperty("options", getOptions()); reply->setProperty("time", QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); canvas->reportStatus("MapQuest", tr("MapQuest
Routing request sent to server. Please wait...")); } } void CRouterMapQuest::slotRequestFinished(QNetworkReply* reply) { if(reply->error() != QNetworkReply::NoError) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->reportStatus("MapQuest", tr("MapQuest
Bad response from server:
%1").arg(reply->errorString())); timerCloseStatusMsg->start(); } reply->deleteLater(); return; } QByteArray res = reply->readAll(); reply->deleteLater(); if(res.isEmpty()) { return; } QDomDocument xml; xml.setContent(res); // QFile f("test.xml"); // f.open(QIODevice::WriteOnly); // f.write(xml.toString().toUtf8()); // f.close(); QDomElement response = xml.firstChildElement("response"); QDomElement info = response.firstChildElement("info"); QDomElement statusCode = info.firstChildElement("statusCode"); if(statusCode.isNull() || statusCode.text().toInt() != 0) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { QDomElement messages = info.firstChildElement("messages"); QDomElement message = messages.firstChildElement("message"); canvas->reportStatus("MapQuest", tr("MapQuest
Bad response from server:
%1").arg(message.text())); timerCloseStatusMsg->start(); } return; } IGisItem::key_t key; key.item = reply->property("key.item").toString(); key.project = reply->property("key.project").toString(); key.device = reply->property("key.device").toString(); qint64 time = reply->property("time").toLongLong(); time = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() - time; CGisItemRte * rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(rte != nullptr) { rte->setResult(xml, reply->property("options").toString() + tr("
Calculation time: %1s").arg(time/1000.0, 0,'f',2)); } slotCloseStatusMsg(); } qmapshack-1.10.0/src/gis/rte/router/IRouterRoutino.ui000644 001750 000144 00000010023 13205475067 023722 0ustar00oeichlerxusers000000 000000 IRouterRoutino 0 0 400 300 Form Profile Mode Database Add paths with Routino database. ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png Language Qt::Vertical 20 40 QFrame::NoFrame QFrame::Plain 0 0 :/icons/48x48/Help.png To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path. You can create your own routing data with <b>Tool->Create Routino Database</b>. Qt::AlignJustify|Qt::AlignTop true qmapshack-1.10.0/src/gis/rte/router/IRouterBRouter.ui000644 001750 000144 00000017015 13216416563 023653 0ustar00oeichlerxusers000000 000000 IRouterBRouter 0 0 400 388 0 0 Form Profile Alternative 0 0 0 0 display selected routing profile ... :/icons/32x32/Help.png:/icons/32x32/Help.png true on-the-fly routing Qt::Horizontal 40 20 BRouter: not running start/stop BRouter ... :/icons/32x32/Off.png:/icons/32x32/Off.png show BRouter console ... :/icons/32x32/TextLeft.png:/icons/32x32/TextLeft.png Qt::Horizontal 40 20 0 0 Setup Caution! BRouter is listening on all ports for connections. true 0 0 Qt::Vertical 20 40 <p><a href="http://brouter.de/brouter/" target="_blank">BRouter</a> © <a href="https://github.com/abrensch/brouter/blob/master/LICENSE" target="_blank">ABrensch, Licence GPLv3</a></p> true true <p>Directions Courtesy of <a href="http://brouter.de/brouter-web/" target="_blank">BRouter-web</a> </p> true true <p>Routing data <a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors</p> true true qmapshack-1.10.0/src/gis/rte/router/CRouterBRouter.cpp000644 001750 000144 00000050730 13216234261 024004 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/CRouterBRouter.h" #include "gis/rte/router/brouter/CRouterBRouterInfo.h" #include "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "gis/rte/router/brouter/CRouterBRouterSetupWizard.h" #include "gis/rte/router/brouter/CRouterBRouterToolShell.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include "helpers/CSettings.h" #include #include CRouterBRouter::CRouterBRouter(QWidget *parent) : IRouter(false, parent) { setupUi(this); labelBRouterWarning->hide(); setup = new CRouterBRouterSetup(this); setup->load(); connect(toolSetup, &QToolButton::clicked, this, &CRouterBRouter::slotToolSetupClicked); connect(toolProfileInfo, &QToolButton::clicked, this, &CRouterBRouter::slotToolProfileInfoClicked); connect(setup, &CRouterBRouterSetup::sigDisplayOnlineProfileFinished, this, &CRouterBRouter::slotDisplayProfileInfo); connect(setup, &CRouterBRouterSetup::sigError, this, &CRouterBRouter::slotDisplayError); comboAlternative->addItem(tr("original"), "0"); comboAlternative->addItem(tr("first alternative"), "1"); comboAlternative->addItem(tr("second alternative"), "2"); comboAlternative->addItem(tr("third alternative"), "3"); networkAccessManager = new QNetworkAccessManager(this); connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CRouterBRouter::slotRequestFinished); timerCloseStatusMsg = new QTimer(this); timerCloseStatusMsg->setSingleShot(true); timerCloseStatusMsg->setInterval(5000); connect(timerCloseStatusMsg, &QTimer::timeout, this, &CRouterBRouter::slotCloseStatusMsg); routerSetup = dynamic_cast(parent); connect(toolConsole, &QToolButton::clicked, this, &CRouterBRouter::slotToggleConsole); connect(toolToggleBRouter, &QToolButton::clicked, this, &CRouterBRouter::slotToggleBRouter); textBRouterOutput->setVisible(false); textBRouterError->setVisible(false); //set textBRouterOutput as parent of ToolShell to ensure Toolshell is destroyed before text brouterShell = new CRouterBRouterToolShell(textBRouterOutput,textBRouterOutput); connect(brouterShell, &CRouterBRouterToolShell::sigProcessStateChanged, this, &CRouterBRouter::slotBRouterStateChanged); connect(brouterShell, &CRouterBRouterToolShell::sigProcessError, this, &CRouterBRouter::slotBRouterError); updateDialog(); SETTINGS; cfg.beginGroup("Route/brouter"); comboProfile->setCurrentIndex(cfg.value("profile", 0).toInt()); checkFastRecalc->setChecked(cfg.value("fastRecalc", false).toBool() && (setup->installMode == CRouterBRouterSetup::eModeLocal)); comboAlternative->setCurrentIndex(cfg.value("alternative", 0).toInt()); cfg.endGroup(); } CRouterBRouter::~CRouterBRouter() { isShutdown = true; if (brouterState != QProcess::NotRunning) { stopBRouter(); } SETTINGS; cfg.beginGroup("Route/brouter"); cfg.setValue("profile", comboProfile->currentIndex()); cfg.setValue("alternative", comboAlternative->currentIndex()); cfg.setValue("fastRecalc", checkFastRecalc->isChecked()); cfg.endGroup(); } void CRouterBRouter::slotToolSetupClicked() { stopBRouter(); CRouterBRouterSetupWizard setupWizard; setupWizard.exec(); clearError(); setup->load(); updateDialog(); } void CRouterBRouter::slotToolProfileInfoClicked() const { const int index = comboProfile->currentIndex(); if (index > -1) { setup->displayProfileAsync(setup->getProfiles().at(index)); } } void CRouterBRouter::slotDisplayError(const QString &error, const QString &details) const { textBRouterError->setText(error + ": " + details); textBRouterError->setVisible(true); QTimer::singleShot(5000,this,&CRouterBRouter::clearError); } void CRouterBRouter::clearError() { textBRouterError->clear(); textBRouterError->setVisible(false); brouterError = QProcess::UnknownError; } void CRouterBRouter::slotDisplayProfileInfo(const QString &profile, const QString &content) { clearError(); CRouterBRouterInfo info; info.setLabel(profile); info.setInfo(content); info.exec(); } void CRouterBRouter::updateDialog() const { if (setup->installMode == CRouterBRouterSetup::eModeLocal) { routerSetup->setRouterTitle(CRouterSetup::RouterBRouter,tr("BRouter (offline)")); labelCopyrightBRouter->setVisible(true); labelCopyrightBRouterWeb->setVisible(false); } else { Q_ASSERT(setup->installMode == CRouterBRouterSetup::eModeOnline); routerSetup->setRouterTitle(CRouterSetup::RouterBRouter,tr("BRouter (online)")); labelCopyrightBRouter->setVisible(false); labelCopyrightBRouterWeb->setVisible(true); } comboProfile->clear(); bool hasItems = false; for(const QString& profile : setup->getProfiles()) { comboProfile->addItem(profile,profile); hasItems = true; } comboProfile->setEnabled(hasItems); toolProfileInfo->setEnabled(hasItems); comboAlternative->setEnabled(hasItems); updateLocalBRouterStatus(); } void CRouterBRouter::slotCloseStatusMsg() const { timerCloseStatusMsg->stop(); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); canvas->reportStatus("BRouter", ""); } } QString CRouterBRouter::getOptions() { return QString(tr("profile: %1, alternative: %2") .arg(comboProfile->currentData().toString()) .arg(comboAlternative->currentData().toInt()+1)); } bool CRouterBRouter::hasFastRouting() { return setup->installMode == CRouterBRouterSetup::eModeLocal && checkFastRecalc->isChecked(); } QNetworkRequest CRouterBRouter::getRequest(const QVector& routePoints, const QVector& areas) const { QString lonLats; bool isNext = false; for(const wpt_t &pt : routePoints) { if (isNext) { lonLats.append(QString("|%1,%2").arg(pt.lon).arg(pt.lat)); } else { lonLats = QString("%1,%2").arg(pt.lon).arg(pt.lat); isNext = true; } } QString nogos; isNext = false; for(const IRouter::circle_t &pt : areas) { if (isNext) { nogos.append(QString("|%1,%2,%3").arg(pt.lon).arg(pt.lat).arg(pt.rad)); } else { nogos = QString("%1,%2,%3").arg(pt.lon).arg(pt.lat).arg(pt.rad); isNext = true; } } QUrlQuery urlQuery; urlQuery.addQueryItem("lonlats",lonLats.toLatin1()); urlQuery.addQueryItem("nogos", nogos.toLatin1()); urlQuery.addQueryItem("profile", comboProfile->currentData().toString()); urlQuery.addQueryItem("alternativeidx", comboAlternative->currentData().toString()); urlQuery.addQueryItem("format", "gpx"); QUrl url = getServiceUrl(); url.setPath("/brouter"); url.setQuery(urlQuery); return QNetworkRequest(url); } int CRouterBRouter::calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) { if(!hasFastRouting() || !mutex.tryLock()) { return -1; } if (setup->installMode == CRouterBRouterSetup::eModeLocal && brouterState == QProcess::NotRunning) { startBRouter(); } QVector points; points << wpt_t(p1.y()*RAD_TO_DEG,p1.x()*RAD_TO_DEG); points << wpt_t(p2.y()*RAD_TO_DEG,p2.x()*RAD_TO_DEG); QVector areas; CGisWorkspace::self().getNogoAreas(areas); synchronous = true; QNetworkReply * reply = networkAccessManager->get(getRequest(points,areas)); try { reply->setProperty("options", getOptions()); reply->setProperty("time", QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()); progress = new CProgressDialog(tr("Calculate route with %1").arg(getOptions()), 0, NOINT, this); QEventLoop eventLoop; connect(progress, &CProgressDialog::rejected, reply, &QNetworkReply::abort); connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); //Processing userinputevents in local eventloop would cause a SEGV when clicking 'abort' of calling LineOp eventLoop.exec(QEventLoop::ExcludeUserInputEvents); delete progress; const QNetworkReply::NetworkError& netErr = reply->error(); if (netErr == QNetworkReply::RemoteHostClosedError && areas.size() > 1) { throw tr("BRouter does not support more then 1 nogo-area in this version, consider to upgrade"); } else if(netErr != QNetworkReply::NoError) { throw reply->errorString(); } else { clearError(); const QByteArray &res = reply->readAll(); if(res.isEmpty()) { throw tr("response is empty"); } else { QDomDocument xml; xml.setContent(res); const QDomElement &xmlGpx = xml.documentElement(); if(xmlGpx.isNull() || xmlGpx.tagName() != "gpx") { throw QString(res); } else { // read the shape const QDomNodeList &xmlLatLng = xmlGpx.firstChildElement("trk") .firstChildElement("trkseg") .elementsByTagName("trkpt"); for(int n = 0; n < xmlLatLng.size(); n++) { const QDomElement &elem = xmlLatLng.item(n).toElement(); coords << QPointF(); QPointF &point = coords.last(); point.setX(elem.attribute("lon").toFloat()*DEG_TO_RAD); point.setY(elem.attribute("lat").toFloat()*DEG_TO_RAD); } } } } } catch(const QString& msg) { coords.clear(); if(!msg.isEmpty()) { reply->deleteLater(); mutex.unlock(); throw tr("Bad response from server: %1").arg(msg); } } reply->deleteLater(); slotCloseStatusMsg(); mutex.unlock(); return coords.size(); } void CRouterBRouter::calcRoute(const IGisItem::key_t& key) { mutex.lock(); if (setup->installMode == CRouterBRouterSetup::eModeLocal && brouterState == QProcess::NotRunning) { startBRouter(); } CGisItemRte *rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr == rte) { mutex.unlock(); return; } QVector areas; CGisWorkspace::self().getNogoAreas(areas); rte->reset(); slotCloseStatusMsg(); QVector points; for(const CGisItemRte::rtept_t &pt : rte->getRoute().pts) { points << wpt_t(pt.lat,pt.lon); } synchronous = false; QNetworkReply * reply = networkAccessManager->get(getRequest(points,areas)); reply->setProperty("key.item", key.item); reply->setProperty("key.project", key.project); reply->setProperty("key.device", key.device); reply->setProperty("options", getOptions()); reply->setProperty("time", QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()); reply->setProperty("nogos", areas.size()); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); canvas->reportStatus("BRouter", tr("BRouter
Routing request sent to server. Please wait...")); } progress = new CProgressDialog(tr("Calculate route with %1").arg(getOptions()), 0, NOINT, this); connect(progress, &CProgressDialog::rejected, reply, &QNetworkReply::abort); } void CRouterBRouter::slotRequestFinished(QNetworkReply* reply) { if (synchronous) { return; } delete progress; try { const QNetworkReply::NetworkError& netErr = reply->error(); if (netErr == QNetworkReply::RemoteHostClosedError && reply->property("nogos").toInt() > 1) { throw tr("BRouter does not support more then 1 nogo-area in this version, consider to upgrade"); } else if(netErr != QNetworkReply::NoError) { throw reply->errorString(); } const QByteArray &res = reply->readAll(); reply->deleteLater(); if(res.isEmpty()) { throw tr("response is empty"); } clearError(); QDomDocument xml; xml.setContent(res); const QDomElement &xmlGpx = xml.documentElement(); if(xmlGpx.isNull() || xmlGpx.tagName() != "gpx") { throw QString(res); } IGisItem::key_t key; key.item = reply->property("key.item").toString(); key.project = reply->property("key.project").toString(); key.device = reply->property("key.device").toString(); qint64 time = reply->property("time").toLongLong(); time = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() - time; CGisItemRte * rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(rte != nullptr) { rte->setResultFromBRouter(xml, reply->property("options").toString() + tr("
Calculation time: %1s").arg(time/1000.0, 0,'f',2)); } } catch(const QString& msg) { if(!msg.isEmpty()) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->reportStatus("BRouter", tr("BRouter
Bad response from server:
%1").arg(msg)); } timerCloseStatusMsg->start(); reply->deleteLater(); mutex.unlock(); return; } } slotCloseStatusMsg(); mutex.unlock(); } QUrl CRouterBRouter::getServiceUrl() const { if (setup->installMode == CRouterBRouterSetup::eModeLocal) { QUrl url(QString("http://")); url.setHost(setup->localHost); url.setPort(setup->localPort.toInt()); return url; } else { Q_ASSERT(setup->installMode == CRouterBRouterSetup::eModeOnline); return QUrl(setup->onlineServiceUrl); } } void CRouterBRouter::slotToggleConsole() const { textBRouterOutput->setVisible(!textBRouterOutput->isVisible()); textBRouterError->setVisible(brouterError != QProcess::UnknownError && !textBRouterOutput->isVisible()); } void CRouterBRouter::slotToggleBRouter() const { if (brouterState == QProcess::NotRunning) { startBRouter(); } else { stopBRouter(); } } void CRouterBRouter::startBRouter() const { if (setup->isLocalBRouterInstalled()) { textBRouterOutput->clear(); //# BRouter standalone server //# java -cp brouter.jar btools.brouter.RouteServer //# maxRunningTime is the request timeout in seconds, set to 0 to disable timeout// JAVA_OPTS= // CLASSPATH=../brouter.jar // java $JAVA_OPTS -cp $CLASSPATH btools.server.RouteServer ../segments4 ../profiles2 ../customprofiles 17777 1 if (brouterState == QProcess::NotRunning) { QStringList args; args << setup->localJavaOpts.split(QRegExp("\\s+")); args << QString("-DmaxRunningTime=%1").arg(setup->localMaxRunningTime); args << "-cp"; args << "brouter.jar"; args << "btools.server.RouteServer"; args << setup->localSegmentsDir; args << setup->localProfileDir; args << setup->localCustomProfileDir; args << setup->localPort; args << setup->localNumberThreads; brouterShell->start(setup->localDir, setup->localJavaExecutable, args); } } } void CRouterBRouter::stopBRouter() const { if (brouterState != QProcess::NotRunning) { brouterShell->stop(); } textBRouterOutput->setVisible(false); } void CRouterBRouter::slotBRouterStateChanged(const QProcess::ProcessState newState) { brouterState = newState; updateLocalBRouterStatus(); } void CRouterBRouter::slotBRouterError(const QProcess::ProcessError error, const QString &errorString) { brouterError = error; slotDisplayError(tr("Error"),errorString); updateLocalBRouterStatus(); } void CRouterBRouter::updateLocalBRouterStatus() const { static const QString msgBRouterWarning = tr( "QMapShack communicates with BRouter via a network connection. Usually this is done on a special " "address that can't be reached from outside your device. However BRouter listens for connections " "on all available interfaces. If you are in your own private network with an active firewall, this " "is not much of a problem. If you are in a public network every open port is a risk as it can be " "used by someone else to compromise your system. We do not recommend to use the local BRouter service " "in this case." ); if (isShutdown) { return; } labelBRouterWarning->hide(); if (setup->installMode == CRouterBRouterSetup::eModeLocal) { if (setup->isLocalBRouterInstalled()) { switch(brouterState) { case QProcess::Starting: { SETTINGS; if(cfg.value("Route/brouter/local/showWarning", true).toBool()) { QMessageBox mbox; mbox.setWindowTitle(tr("Warning...")); mbox.setIcon(QMessageBox::Warning); mbox.setStandardButtons(QMessageBox::Ok); mbox.setText(msgBRouterWarning); QCheckBox * checkAgree = new QCheckBox(tr("I understand the risk. Don't tell me again."), &mbox); mbox.setCheckBox(checkAgree); mbox.exec(); cfg.setValue("Route/brouter/local/showWarning", !checkAgree->isChecked()); } labelStatus->setText(tr("starting")); toolConsole->setVisible(true); break; } case QProcess::Running: { labelBRouterWarning->show(); labelStatus->setText(tr("running")); toolConsole->setVisible(true); break; } case QProcess::NotRunning: { labelStatus->setText(tr("stopped")); toolConsole->setVisible(brouterError != QProcess::UnknownError); break; } } checkFastRecalc->setEnabled(true); toolToggleBRouter->setEnabled(true); } else { labelStatus->setText(tr("not installed")); toolConsole->setVisible(false); toolToggleBRouter->setEnabled(false); checkFastRecalc->setEnabled(false); } toolToggleBRouter->setVisible(true); checkFastRecalc->setVisible(true); } else { Q_ASSERT(setup->installMode == CRouterBRouterSetup::eModeOnline); labelStatus->setText(tr("online")); toolConsole->setVisible(false); toolToggleBRouter->setVisible(false); checkFastRecalc->setVisible(false); textBRouterOutput->clear(); textBRouterOutput->setVisible(false); } } qmapshack-1.10.0/src/gis/rte/router/routino/000755 001750 000144 00000000000 13216664445 022117 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/rte/router/routino/IRouterRoutinoPathSetup.ui000644 001750 000144 00000010300 13063701351 027243 0ustar00oeichlerxusers000000 000000 IRouterRoutinoPathSetup 0 0 450 200 Setup Routino database... ... :/icons/32x32/Add.png:/icons/32x32/Add.png 22 22 false ... :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png 22 22 Qt::Vertical 20 40 0 0 :/icons/48x48/Help.png - Qt::AlignJustify|Qt::AlignTop true Qt::Vertical QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IRouterRoutinoPathSetup accept() 248 254 157 274 buttonBox rejected() IRouterRoutinoPathSetup reject() 316 260 286 274 qmapshack-1.10.0/src/gis/rte/router/routino/CRouterRoutinoPathSetup.h000644 001750 000144 00000002660 13216234143 027061 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CROUTERROUTINOPATHSETUP_H #define CROUTERROUTINOPATHSETUP_H #include "ui_IRouterRoutinoPathSetup.h" #include class CRouterRoutinoPathSetup : public QDialog, private Ui::IRouterRoutinoPathSetup { Q_OBJECT public: CRouterRoutinoPathSetup(QStringList& paths); virtual ~CRouterRoutinoPathSetup(); public slots: void accept() override; private slots: void slotAddPath(); void slotDelPath(); void slotItemSelectionChanged(); private: QStringList& paths; }; #endif //CROUTERROUTINOPATHSETUP_H qmapshack-1.10.0/src/gis/rte/router/routino/CRouterRoutinoPathSetup.cpp000644 001750 000144 00000005224 13216234140 027410 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/rte/router/routino/CRouterRoutinoPathSetup.h" #include CRouterRoutinoPathSetup::CRouterRoutinoPathSetup(QStringList &paths) : QDialog(CMainWindow::getBestWidgetForParent()) , paths(paths) { setupUi(this); connect(toolAdd, &QToolButton::clicked, this, &CRouterRoutinoPathSetup::slotAddPath); connect(toolDelete, &QToolButton::clicked, this, &CRouterRoutinoPathSetup::slotDelPath); connect(listWidget, &QListWidget::itemSelectionChanged, this, &CRouterRoutinoPathSetup::slotItemSelectionChanged); for(const QString &path : paths) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } labelHelp->setText(tr("Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed.")); } CRouterRoutinoPathSetup::~CRouterRoutinoPathSetup() { } void CRouterRoutinoPathSetup::slotItemSelectionChanged() { QList items = listWidget->selectedItems(); toolDelete->setEnabled(!items.isEmpty()); } void CRouterRoutinoPathSetup::slotAddPath() { QString path = QFileDialog::getExistingDirectory(this, tr("Select routing data file path..."), QDir::homePath(), 0); if(!path.isEmpty()) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } } void CRouterRoutinoPathSetup::slotDelPath() { QList items = listWidget->selectedItems(); qDeleteAll(items); } void CRouterRoutinoPathSetup::accept() { paths.clear(); for(int i = 0; i < listWidget->count(); i++) { QListWidgetItem *item = listWidget->item(i); paths << item->text(); } QDialog::accept(); } qmapshack-1.10.0/src/gis/rte/router/brouter/000755 001750 000144 00000000000 13216664445 022102 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetupWizard.cpp000644 001750 000144 00000067256 13216234140 027677 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "gis/rte/router/brouter/CRouterBRouterSetupWizard.h" #include "setup/IAppSetup.h" #include #include #include #include #include #include CRouterBRouterSetupWizard::CRouterBRouterSetupWizard() : QWizard(CMainWindow::getBestWidgetForParent()) { setupUi(this); setup = new CRouterBRouterSetup(this); setButtonText(QWizard::CustomButton1, tr("Restore Default Values")); connect(this, &CRouterBRouterSetupWizard::currentIdChanged, this, &CRouterBRouterSetupWizard::slotCurrentIdChanged); connect(this, &CRouterBRouterSetupWizard::customButtonClicked, this, &CRouterBRouterSetupWizard::slotCustomButtonClicked); connect(radioLocal, &QRadioButton::clicked, this, &CRouterBRouterSetupWizard::slotRadioLocalClicked); connect(radioOnline, &QRadioButton::clicked, this, &CRouterBRouterSetupWizard::slotRadioOnlineClicked); connect(checkExpert, &QCheckBox::clicked, this, &CRouterBRouterSetupWizard::slotCheckExpertClicked); connect(lineLocalProfilesUrl, &QLineEdit::cursorPositionChanged, this, &CRouterBRouterSetupWizard::slotLocalProfilesUrlCursorPositionChanged); connect(lineLocalProfilesUrl, &QLineEdit::editingFinished, this, &CRouterBRouterSetupWizard::slotLocalProfilesUrlCursorPositionChanged); connect(toolLocalDir, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotLocalToolSelectDirectory); connect(toolJavaExecutable, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotLocalToolSelectJava); connect(pushLocalFindJava, &QPushButton::clicked, this, &CRouterBRouterSetupWizard::slotLocalPushFindJava); connect(lineLocalDir, &QLineEdit::cursorPositionChanged, this, &CRouterBRouterSetupWizard::slotLocalDirectoryCursonPositionChanged); connect(lineJavaExecutable, &QLineEdit::cursorPositionChanged, this, &CRouterBRouterSetupWizard::slotLocalJavaExecutableCursorPositionChanged); connect(pushCreateOrUpdateLocalInstall, &QPushButton::clicked, this, &CRouterBRouterSetupWizard::slotCreateOrUpdateLocalInstallClicked); connect(pushLocalInstall, &QPushButton::clicked, this, &CRouterBRouterSetupWizard::slotLocalDownloadButtonClicked); connect(listProfiles, &QListView::clicked, this, &CRouterBRouterSetupWizard::slotProfileClicked); connect(listAvailableProfiles, &QListView::clicked, this, &CRouterBRouterSetupWizard::slotAvailableProfileClicked); connect(toolAddProfile, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotAddProfileClicked); connect(toolDeleteProfile, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotDelProfileClicked); connect(toolProfileUp, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotProfileUpClicked); connect(toolProfileDown, &QToolButton::clicked, this, &CRouterBRouterSetupWizard::slotProfileDownClicked); connect(lineOnlineUrl, &QLineEdit::cursorPositionChanged, this, &CRouterBRouterSetupWizard::slotOnlineUrlCursorPositionChanged); connect(lineOnlineUrl, &QLineEdit::editingFinished, this, &CRouterBRouterSetupWizard::slotOnlineUrlCursorPositionChanged); connect(setup, &CRouterBRouterSetup::sigOnlineConfigLoaded, this, &CRouterBRouterSetupWizard::slotOnlineConfigLoaded); connect(setup, &CRouterBRouterSetup::sigDisplayOnlineProfileFinished, this, &CRouterBRouterSetupWizard::slotDisplayProfile); connect(setup, &CRouterBRouterSetup::sigProfilesChanged, this, &CRouterBRouterSetupWizard::slotOnlineProfilesLoaded); connect(setup, &CRouterBRouterSetup::sigError, this, &CRouterBRouterSetupWizard::slotSetupError); QStringListModel *profilesModel = new QStringListModel(); listProfiles->setModel(profilesModel); QStringListModel *availableProfiles = new QStringListModel(); listAvailableProfiles->setModel(availableProfiles); networkAccessManager = new QNetworkAccessManager(this); connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CRouterBRouterSetupWizard::slotLocalDownloadButtonFinished); setup->load(); } CRouterBRouterSetupWizard::~CRouterBRouterSetupWizard() { } int CRouterBRouterSetupWizard::nextId() const { switch(currentId()) { case ePageChooseMode: { if (setup->installMode == CRouterBRouterSetup::eModeLocal) { return ePageLocalDirectory; } if (setup->expertMode) //ModeOnline { return ePageOnlineUrl; } return ePageProfiles; } case ePageLocalDirectory: { if (setup->expertMode) { return ePageOnlineUrl; } if (doLocalInstall) { return ePageLocalInstallation; } return ePageProfiles; } case ePageLocalInstallation: { if (setup->expertMode) { return ePageLocalDetails; } return ePageProfiles; } case ePageProfiles: { if (setup->installMode == CRouterBRouterSetup::eModeLocal) { return ePageLocalTiles; } break; } case ePageLocalTiles: { break; } case ePageOnlineDetails: { return ePageProfiles; } case ePageOnlineUrl: { if (setup->installMode == CRouterBRouterSetup::eModeLocal) { if (doLocalInstall) { return ePageLocalInstallation; } if (setup->expertMode) { return ePageLocalDetails; } return ePageProfiles; } else if (setup->installMode == CRouterBRouterSetup::eModeOnline) { return ePageOnlineDetails; } break; } case ePageLocalDetails: { return ePageProfiles; } } return -1; } void CRouterBRouterSetupWizard::initializePage(const int id) { switch(id) { case ePageLocalDirectory: { initLocalDirectory(); break; } case ePageLocalInstallation: { initLocalInstall(); break; } case ePageLocalTiles: { initLocalTiles(); break; } } } bool CRouterBRouterSetupWizard::validateCurrentPage() { switch(currentId()) { case ePageOnlineDetails: { return validateOnlineDetails(); } case ePageLocalDetails: { return validateLocalDetails(); } } return true; } void CRouterBRouterSetupWizard::slotCurrentIdChanged(const int id) { switch(id) { case ePageChooseMode: { beginChooseMode(); break; } case ePageLocalDirectory: { beginLocalDirectory(); break; } case ePageLocalInstallation: { beginLocalInstall(); break; } case ePageProfiles: { beginProfiles(); break; } case ePageLocalTiles: { beginLocalTiles(); break; } case ePageOnlineDetails: { beginOnlineDetails(); break; } case ePageOnlineUrl: { beginOnlineUrl(); break; } case ePageLocalDetails: { beginLocalDetails(); break; } } } void CRouterBRouterSetupWizard::slotCustomButtonClicked(const int id) { if (id == QWizard::CustomButton1) { const int page = currentId(); switch (page) { case ePageOnlineDetails: { resetOnlineDetails(); break; } case ePageOnlineUrl: { resetOnlineUrl(); break; } case ePageLocalDetails: { resetLocalDetails(); break; } } } } void CRouterBRouterSetupWizard::accept() { setup->save(); QDialog::accept(); } void CRouterBRouterSetupWizard::reject() { if (!pageLocalTiles->isComplete()) { if (pageLocalTiles->raiseWarning()) { return; } } QDialog::reject(); } void CRouterBRouterSetupWizard::beginChooseMode() { switch(setup->installMode) { case CRouterBRouterSetup::eModeLocal: { radioLocal->setChecked(true); radioOnline->setChecked(false); break; } case CRouterBRouterSetup::eModeOnline: { radioLocal->setChecked(false); radioOnline->setChecked(true); break; } } checkExpert->setChecked(setup->expertMode); setOption(QWizard::HaveCustomButton1, false); } void CRouterBRouterSetupWizard::slotRadioLocalClicked() const { setup->installMode = CRouterBRouterSetup::eModeLocal; } void CRouterBRouterSetupWizard::slotRadioOnlineClicked() const { setup->installMode = CRouterBRouterSetup::eModeOnline; } void CRouterBRouterSetupWizard::slotCheckExpertClicked() const { setup->expertMode = checkExpert->isChecked(); } void CRouterBRouterSetupWizard::initLocalDirectory() { pageLocalDirectory->setSetup(setup); } void CRouterBRouterSetupWizard::beginLocalDirectory() { updateLocalDirectory(); doLocalInstall = false; setOption(QWizard::HaveCustomButton1, false); } void CRouterBRouterSetupWizard::slotLocalToolSelectDirectory() { setup->localDir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),"", QFileDialog::ShowDirsOnly); updateLocalDirectory(); } void CRouterBRouterSetupWizard::slotLocalToolSelectJava() { QFileDialog dialog(this, tr("select Java Executable"), QFileInfo(setup->localJavaExecutable).absolutePath(), "Java Executable (java*)"); dialog.setFileMode(QFileDialog::ExistingFile); if (dialog.exec()) { setup->localJavaExecutable = dialog.selectedFiles().first(); updateLocalDirectory(); } } void CRouterBRouterSetupWizard::slotLocalPushFindJava() const { setup->localJavaExecutable = setup->findJava(); updateLocalDirectory(); } void CRouterBRouterSetupWizard::slotLocalDirectoryCursonPositionChanged() const { setup->localDir = lineLocalDir->text(); updateLocalDirectory(); } void CRouterBRouterSetupWizard::slotLocalJavaExecutableCursorPositionChanged() const { setup->localJavaExecutable = lineJavaExecutable->text(); updateLocalDirectory(); } void CRouterBRouterSetupWizard::updateLocalDirectory() const { textLocalDirectory->setVisible(false); lineLocalDir->setText(setup->localDir); lineJavaExecutable->setText(setup->localJavaExecutable); if (setup->localDir.isEmpty()) { labelLocalDirResult->setText(tr("please select BRouter installation directory")); pushCreateOrUpdateLocalInstall->setVisible(false); } else if(!QDir(setup->localDir).exists()) { labelLocalDirResult->setText(tr("selected directory does not exist")); pushCreateOrUpdateLocalInstall->setText(tr("create directory and install BRouter there")); pushCreateOrUpdateLocalInstall->setVisible(true); } else { if (setup->isLocalBRouterInstalled()) { labelLocalDirResult->setText(tr("existing BRouter installation")); pushCreateOrUpdateLocalInstall->setText(tr("update existing BRouter installation")); pushCreateOrUpdateLocalInstall->setVisible(true); } else { labelLocalDirResult->setText(tr("empty directory, create new BRouter installation here")); pushCreateOrUpdateLocalInstall->setText(tr("create new BRouter installation")); pushCreateOrUpdateLocalInstall->setVisible(true); } } if (QFile(setup->localJavaExecutable).exists()) { if (QFileInfo(setup->localJavaExecutable).baseName().startsWith("java")) { labelLocalJavaResult->setText(tr("seems to be a valid Java-executable")); } else { labelLocalJavaResult->setText(tr("doesn't seem to be a valid Java-executable")); } } else { labelLocalJavaResult->setText(tr("Java Executable not found")); labelLocalJavaResult->setVisible(true); } pageLocalDirectory->emitCompleteChanged(); } void CRouterBRouterSetupWizard::slotCreateOrUpdateLocalInstallClicked() { QDir outDir(setup->localDir); try { if(!outDir.exists()) { if (!outDir.mkpath(outDir.absolutePath())) { throw tr("Error creating directory %1").arg(outDir.absolutePath()); } } doLocalInstall = true; next(); } catch (const QString &msg) { textLocalDirectory->setVisible(true); textLocalDirectory->setTextColor(Qt::red); textLocalDirectory->append(msg); } } void CRouterBRouterSetupWizard::initLocalInstall() { pageLocalInstallation->setSetup(setup); connect(webLocalBRouterVersions, &QWebView::loadFinished, this, &CRouterBRouterSetupWizard::slotWebLocalBRouterVersionsLoadFinished); webLocalBRouterVersions->load(QUrl(setup->binariesUrl)); QWebPage *localVersionsPage = webLocalBRouterVersions->page(); localVersionsPage->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); connect(localVersionsPage, &QWebPage::linkClicked, this, &CRouterBRouterSetupWizard::slotLocalDownloadLinkClicked); } void CRouterBRouterSetupWizard::slotWebLocalBRouterVersionsLoadFinished(bool ok) { if (!ok) { textLocalInstall->setVisible(true); textLocalInstall->setTextColor(Qt::red); textLocalInstall->append(tr("Error loading installation-page at %1").arg(setup->binariesUrl)); } } void CRouterBRouterSetupWizard::beginLocalInstall() { doLocalInstall = false; textLocalInstall->setVisible(false); textLocalInstall->clear(); labelLocalInstallLink->setText(tr("no brouter-version to install selected")); pushLocalInstall->setEnabled(false); setOption(QWizard::HaveCustomButton1, false); } void CRouterBRouterSetupWizard::slotLocalDownloadLinkClicked(const QUrl &url) { downloadUrl = url; labelLocalInstallLink->setText(QString(tr("selected %1 for download and installation")).arg(url.fileName())); pushLocalInstall->setEnabled(true); } void CRouterBRouterSetupWizard::slotLocalDownloadButtonClicked() { const QString& strUrl = downloadUrl.toString(); if(!strUrl.startsWith("https")) { QMessageBox mbox; mbox.setWindowTitle(tr("Warning...")); mbox.setIcon(QMessageBox::Warning); mbox.setStandardButtons(QMessageBox::Ok|QMessageBox::Abort); mbox.setDefaultButton(QMessageBox::Abort); QString msg = tr("Download: %1
" "
" "This will download and install a zip file from a download location that is not secured " "by any standard at all, using plain HTTP. Usually this should be HTTPS. The risk is " "someone redirecting the request and sending you a replacement zip with malware. There " "is no way for QMapShack to detect this.
" "If you do not understand this or if you are in doubt, do not proceed and abort. " "Use the Web version of BRouter instead." ).arg(strUrl); mbox.setText(msg); QCheckBox * checkAgree = new QCheckBox(tr("I understand the risk and wish to proceed."), &mbox); mbox.setCheckBox(checkAgree); connect(checkAgree, &QCheckBox::clicked, mbox.button(QMessageBox::Ok), &QPushButton::setEnabled); mbox.button(QMessageBox::Ok)->setDisabled(true); if(mbox.exec() != QMessageBox::Ok) { return; } } textLocalInstall->setVisible(true); textLocalInstall->setTextColor(Qt::darkGreen); textLocalInstall->append(tr("download %1 started").arg(downloadUrl.toString())); QNetworkReply * reply = networkAccessManager->get(QNetworkRequest(downloadUrl)); reply->setProperty("fileName",downloadUrl.fileName()); } void CRouterBRouterSetupWizard::slotLocalDownloadButtonFinished(QNetworkReply * reply) { reply->deleteLater(); try { if (reply->error() != QNetworkReply::NoError) { throw tr("Network Error: %1").arg(reply->errorString()); } const QString &fileName = reply->property("fileName").toString(); QDir outDir(setup->localDir); if (!outDir.exists()) { throw tr("Error directory %1 does not exist").arg(outDir.absolutePath()); } QFile outfile(outDir.absoluteFilePath(fileName)); try { if (!outfile.open(QIODevice::WriteOnly)) { throw tr("Error creating file %1").arg(outfile.fileName()); } if (outfile.write(reply->readAll()) < 0) { throw tr("Error writing to file %1").arg(outfile.fileName()); } outfile.close(); textLocalInstall->setTextColor(Qt::darkGreen); textLocalInstall->append(tr("download %1 finished").arg(outfile.fileName())); const QStringList &unzippedNames = JlCompress::extractDir(outfile.fileName(),setup->localDir); textLocalInstall->append(tr("unzipping:")); for (const QString unzipped : unzippedNames) { textLocalInstall->append(unzipped); } textLocalInstall->append(tr("ready.")); pageLocalInstallation->emitCompleteChanged(); setup->readLocalProfiles(); } catch (const QString &msg) { if (outfile.isOpen()) { outfile.close(); } if (outfile.exists()) { outfile.remove(); } throw msg; } } catch (const QString &msg) { textLocalInstall->setTextColor(Qt::red); textLocalInstall->append(tr("download of brouter failed: %1").arg(msg)); } } void CRouterBRouterSetupWizard::beginProfiles() { isError = false; updateProfiles(); if (setup->installMode == CRouterBRouterSetup::eModeLocal) { textProfileContent->setText(tr("retrieving available profiles from %1").arg(setup->onlineProfilesUrl)); setup->loadLocalOnlineProfiles(); setup->readLocalProfiles(); } else { Q_ASSERT(setup->installMode == CRouterBRouterSetup::eModeOnline); textProfileContent->setText(tr("retrieving available profiles from %1").arg(setup->onlineWebUrl)); setup->loadOnlineConfig(); } setOption(QWizard::HaveCustomButton1, false); } void CRouterBRouterSetupWizard::slotProfileClicked(const QModelIndex & index) const { const QString &profile = listProfiles->model()->data(index).toString(); listAvailableProfiles->clearSelection(); updateProfiles(); setup->displayProfileAsync(profile); } void CRouterBRouterSetupWizard::slotAvailableProfileClicked(const QModelIndex & index) const { const QString &profile = listAvailableProfiles->model()->data(index).toString(); listProfiles->clearSelection(); updateProfiles(); setup->displayOnlineProfileAsync(profile); } void CRouterBRouterSetupWizard::slotDisplayProfile(const QString &profile, const QString content) { labelProfileContent->setText(tr("content of profile")); textProfileContent->setText(content); } void CRouterBRouterSetupWizard::slotAddProfileClicked() const { for (const QString &profile : selectedProfiles(listAvailableProfiles)) { setup->addProfile(profile); } } void CRouterBRouterSetupWizard::slotDelProfileClicked() const { for (const QString &profile : selectedProfiles(listProfiles)) { setup->deleteProfile(profile); } } void CRouterBRouterSetupWizard::slotProfileUpClicked() const { for (const QString &profile : selectedProfiles(listProfiles)) { setup->profileUp(profile); } } void CRouterBRouterSetupWizard::slotProfileDownClicked() const { for (const QString &profile : selectedProfiles(listProfiles)) { setup->profileDown(profile); } } void CRouterBRouterSetupWizard::slotOnlineProfilesLoaded() { isError = false; switch(currentId()) { case ePageProfiles: { updateProfiles(); break; } case ePageLocalDetails: { updateLocalDetails(); break; } } } void CRouterBRouterSetupWizard::updateProfiles() const { const QStringList &profiles = setup->getProfiles(); QStringList available; for(const QString &profile:setup->onlineProfilesAvailable) { if (!profiles.contains(profile)) { available << profile; } } QList selected = updateProfileView(listProfiles, profiles); qSort(selected.begin(),selected.end()); toolDeleteProfile->setEnabled(!selected.isEmpty()); toolProfileUp->setEnabled(!selected.isEmpty() && selected.first() > 0); toolProfileDown->setEnabled(!selected.isEmpty() && selected.last() < profiles.size()-1); if (isError) { toolAddProfile->setEnabled(false); labelProfileContent->setText(tr("Error:")); textProfileContent->setText(error + ": "+ errorDetails); } else { toolAddProfile->setEnabled(!updateProfileView(listAvailableProfiles, available).isEmpty()); listAvailableProfiles->setVisible(true); labelProfileContent->setText(tr("content of profile")); textProfileContent->clear(); } pageProfiles->emitCompleteChanged(); } QStringList CRouterBRouterSetupWizard::selectedProfiles(const QListView * listView) const { const QItemSelectionModel * selectModel = listView->selectionModel(); const QModelIndexList &selected = selectModel->selectedIndexes(); const QAbstractItemModel * model = listView->model(); QStringList selectedList; for (int i = 0; i < selected.size(); i++) { selectedList << model->data(selected.at(i)).toString(); } return selectedList; } QList CRouterBRouterSetupWizard::updateProfileView(QListView * listView, const QStringList &values) const { QList selected; const QStringList &selectedValues = selectedProfiles(listView); QStringListModel * listModel = (dynamic_cast(listView->model())); QItemSelectionModel * selectModel = listView->selectionModel(); listModel->setStringList(values); for (const QString &value : selectedValues) { if (values.contains(value)) { int index = values.indexOf(value); selectModel->select(listModel->index(index), QItemSelectionModel::Select); selected << index; } } return selected; } void CRouterBRouterSetupWizard::initLocalTiles() const { pageLocalTiles->setSetup(setup); } void CRouterBRouterSetupWizard::beginLocalTiles() { pageLocalTiles->beginPage(); setOption(QWizard::HaveCustomButton1, false); } void CRouterBRouterSetupWizard::beginOnlineDetails() { setOption(QWizard::HaveCustomButton1, true); updateOnlineDetails(); } void CRouterBRouterSetupWizard::updateOnlineDetails() const { lineOnlineProfileUrl->setText(setup->onlineProfilesUrl); lineOnlineService->setText(setup->onlineServiceUrl); } bool CRouterBRouterSetupWizard::validateOnlineDetails() const { setup->onlineProfilesUrl = lineOnlineProfileUrl->text(); setup->onlineServiceUrl = lineOnlineService->text(); return true; } void CRouterBRouterSetupWizard::resetOnlineDetails() const { setup->resetOnlineProfilesUrl(); setup->resetOnlineServiceUrl(); updateOnlineDetails(); } void CRouterBRouterSetupWizard::beginOnlineUrl() { setOption(QWizard::HaveCustomButton1, true); isError = false; setup->loadOnlineConfig(); } void CRouterBRouterSetupWizard::slotOnlineUrlCursorPositionChanged() { setup->onlineWebUrl = lineOnlineUrl->text(); isError = false; setup->loadOnlineConfig(); } void CRouterBRouterSetupWizard::updateOnlineUrl() { lineOnlineUrl->setText(setup->onlineWebUrl); textOnlineUrl->setVisible(isError); if (isError) { textOnlineUrl->setText(error + ": "+ errorDetails); } } void CRouterBRouterSetupWizard::resetOnlineUrl() { setup->resetOnlineWebUrl(); beginOnlineUrl(); } void CRouterBRouterSetupWizard::updateLocalDetails() const { lineLocalProfilesUrl->setText(setup->onlineProfilesUrl); lineLocalHost->setText(setup->localHost); lineLocalPort->setText(setup->localPort); lineLocalProfiles->setText(setup->localProfileDir); lineLocalSegments->setText(setup->localSegmentsDir); lineLocalCustomProfiles->setText(setup->localCustomProfileDir); lineLocalMaxRuntime->setText(setup->localMaxRunningTime); lineLocalNumberThreads->setText(setup->localNumberThreads); lineLocalJavaOpts->setText(setup->localJavaOpts); textLocalDetails->setVisible(isError); if (isError) { textLocalDetails->setText(error + ": " + errorDetails); } } void CRouterBRouterSetupWizard::beginLocalDetails() { setOption(QWizard::HaveCustomButton1, true); isError = false; setup->loadLocalOnlineProfiles(); } void CRouterBRouterSetupWizard::slotLocalProfilesUrlCursorPositionChanged() { setup->onlineProfilesUrl = lineLocalProfilesUrl->text(); isError = false; setup->loadLocalOnlineProfiles(); } bool CRouterBRouterSetupWizard::validateLocalDetails() const { setup->localHost = lineLocalHost->text(); setup->localPort = lineLocalPort->text(); setup->localProfileDir = lineLocalProfiles->text(); setup->localSegmentsDir = lineLocalSegments->text(); setup->localCustomProfileDir = lineLocalCustomProfiles->text(); setup->localMaxRunningTime = lineLocalMaxRuntime->text(); setup->localNumberThreads = lineLocalNumberThreads->text(); setup->localJavaOpts = lineLocalJavaOpts->text(); return true; } void CRouterBRouterSetupWizard::resetLocalDetails() const { setup->resetOnlineProfilesUrl(); setup->resetLocalHost(); setup->resetLocalPort(); setup->resetLocalProfileDir(); setup->resetLocalSegmentsDir(); setup->resetLocalCustomProfileDir(); setup->resetLocalMaxRunningTime(); setup->resetLocalNumberThreads(); setup->resetLocalJavaOpts(); updateLocalDetails(); } void CRouterBRouterSetupWizard::slotOnlineConfigLoaded() { isError = false; switch(currentId()) { case ePageOnlineUrl: { updateOnlineUrl(); break; } case ePageOnlineDetails: { updateOnlineDetails(); break; } case ePageLocalDetails: { updateLocalDetails(); break; } } } void CRouterBRouterSetupWizard::slotSetupError(const QString &error, const QString &details) { isError = true; this->error = error; this->errorDetails = details; switch(currentId()) { case ePageOnlineUrl: { updateOnlineUrl(); break; } case ePageLocalDetails: { updateLocalDetails(); break; } case ePageProfiles: { updateProfiles(); break; } } } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesSelectLayout.h000644 001750 000144 00000004014 13216234143 030463 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTILESSELECTLAYOUT_H #define CROUTERBROUTERTILESSELECTLAYOUT_H #include #include /* * This layout class seems trivial. What it does is, it enforces the exact * same geometry on its contained QLayoutItems. It's been used to overlay * multiple widgets so they appear as a single unit. Standard Layout-classes * arrange the items in non-overlapping manner. */ class CRouterBRouterTilesSelectLayout : public QLayout { public: CRouterBRouterTilesSelectLayout(QWidget * parent) : QLayout(parent) {} virtual ~CRouterBRouterTilesSelectLayout() {} void addItem(QLayoutItem * item) override { items.append(item); } QSize sizeHint() const override { return QSize(200,200); } void setGeometry(const QRect & r) override { for (QLayoutItem *item : items) { item->setGeometry(r); }} QLayoutItem * itemAt(int index) const override { return items.at(index); } QLayoutItem * takeAt(int index) override { return items.takeAt(index); } int count() const override { return items.size(); } private: QList items; }; #endif //CROUTERBROUTERTILESSELECTLAYOUT_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesSelect.h000644 001750 000144 00000006676 13216234143 027305 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTILESSELECT_H #define CROUTERBROUTERTILESSELECT_H #include #include #include #include #include #include #include #include class CRouterBRouterTilesSelectArea; class CRouterBRouterTilesStatus; class CRouterBRouterSetup; class CRouterBRouterTilesSelect : public QWidget { Q_OBJECT public: CRouterBRouterTilesSelect(QWidget * parent); virtual ~CRouterBRouterTilesSelect(); void setSetup(CRouterBRouterSetup * setup); void initialize(); void cancelDownload() const; static QString formatSize(const qint64 size); static QPoint tileFromFileName(const QString &fileName); static QString fileNameFromTile(const QPoint tile); bool isInitialized() const { return initialized; } bool isDownloading() const { return downloading; } bool isDownloadSelected() const { return downloadSelected; } static const QPoint noTile; static const int minTileLat; static const int maxTileLat; static const int minTileLon; static const int maxTileLon; static const int tileSize; signals: void sigCompleteChanged() const; private slots: void slotTileClicked(const QPoint & tile); void slotTileToolTipChanged(const QPoint & tile) const; void slotClearSelection(); void slotDeleteSelected(); void slotSelectOutdated(); void slotDownload(); void slotLoadOnlineTilesRequestFinished(bool ok); void slotDownloadFinished(QNetworkReply* reply); void slotDownloadReadReady(); private: QDir segmentsDir() const; void update(); void updateStatus(); void updateButtons() const; void updateTiles() const; void error(const QString &error) const; void clearError() const; CRouterBRouterTilesStatus * getTileStatus(QPoint tile) const; CRouterBRouterSetup * setup; QVBoxLayout * outerLayout; QWidget * widgetSelect; QLabel * statusLabel; QProgressBar * statusProgress; QLabel * errorLabel; QPushButton * pushSelectOutdated; QPushButton * pushClearSelection; QPushButton * pushDeleteSelection; QPushButton * pushDownload; CRouterBRouterTilesSelectArea * selectArea; QWebPage * tilesWebPage; QNetworkAccessManager * tilesDownloadManager; QVector tilesDownloadManagerReplies; QHash tilesDownloadStatus; bool downloading { false }; bool downloadSelected { false }; bool initialized { false }; }; #endif //CROUTERBROUTERTILESSELECT_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetupPage.cpp000644 001750 000144 00000004451 13216234140 027277 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "gis/rte/router/brouter/CRouterBRouterSetupPage.h" #include "gis/rte/router/brouter/CRouterBRouterSetupWizard.h" CRouterBRouterSetupPage::CRouterBRouterSetupPage() : QWizardPage() { } CRouterBRouterSetupPage::~CRouterBRouterSetupPage() { } bool CRouterBRouterSetupPage::isComplete() const { switch(wizard()->currentId()) { case CRouterBRouterSetupWizard::ePageLocalDirectory: { return setup != nullptr && setup->isLocalBRouterInstalled() && QFile(setup->localJavaExecutable).exists() && QFileInfo(setup->localJavaExecutable).baseName().startsWith("java"); } case CRouterBRouterSetupWizard::ePageLocalInstallation: { return setup != nullptr && setup->isLocalBRouterInstalled(); } case CRouterBRouterSetupWizard::ePageProfiles: { const QListView *profilesListView = findChild("listProfiles"); Q_ASSERT(profilesListView != nullptr); return profilesListView->model()->rowCount() > 0; } default: { return false; } } } void CRouterBRouterSetupPage::setComplete(bool newComplete) { if (newComplete != complete) { complete = newComplete; emit completeChanged(); } } void CRouterBRouterSetupPage::emitCompleteChanged() { emit completeChanged(); } qmapshack-1.10.0/src/gis/rte/router/brouter/IRouterBRouterInfo.ui000644 001750 000144 00000003202 13063701351 026132 0ustar00oeichlerxusers000000 000000 IRouterBRouterInfo 0 0 615 300 BRouter Profile TextLabel Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() IRouterBRouterInfo accept() 248 254 157 274 buttonBox rejected() IRouterBRouterInfo reject() 316 260 286 274 qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesStatus.h000644 001750 000144 00000003340 13216234143 027332 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTILESSTATUS_H #define CROUTERBROUTERTILESSTATUS_H #include #include #include class CRouterBRouterTilesStatus : public QObject { Q_OBJECT public: CRouterBRouterTilesStatus(QObject *parent) : QObject(parent) {} virtual ~CRouterBRouterTilesStatus() {} public slots: void slotUpdateProgress(qint64 received, qint64 total) { progressMax = total; progressVal = received; } private: qint64 progressMax; qint64 progressVal; qint64 remoteSize; qint64 localSize; QDateTime remoteDate; QDateTime localDate; bool isLocal {false}; bool isRemote {false}; bool isSelected {false}; bool isOutdated {false}; QFile * file {nullptr}; friend class CRouterBRouterTilesSelect; }; #endif //CROUTERBROUTERTILESSTATUS_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesPage.cpp000644 001750 000144 00000006414 13216234140 027260 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "gis/rte/router/brouter/CRouterBRouterTilesPage.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelect.h" #include #include CRouterBRouterTilesPage::CRouterBRouterTilesPage() : QWizardPage() { layout = new QVBoxLayout(this); widgetLocalTilesSelect = new CRouterBRouterTilesSelect(this); widgetLocalTilesSelect->setObjectName("widgetLocalTilesSelect"); QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(widgetLocalTilesSelect->sizePolicy().hasHeightForWidth()); widgetLocalTilesSelect->setSizePolicy(sizePolicy); layout->addWidget(widgetLocalTilesSelect); connect(widgetLocalTilesSelect, &CRouterBRouterTilesSelect::sigCompleteChanged, this, &CRouterBRouterTilesPage::slotTileDownloadStatusChanged); } CRouterBRouterTilesPage::~CRouterBRouterTilesPage() { } bool CRouterBRouterTilesPage::isComplete() const { return widgetLocalTilesSelect->isInitialized() && !(widgetLocalTilesSelect->isDownloading() || widgetLocalTilesSelect->isDownloadSelected()); } void CRouterBRouterTilesPage::slotTileDownloadStatusChanged() { emit completeChanged(); } void CRouterBRouterTilesPage::beginPage() const { widgetLocalTilesSelect->initialize(); } void CRouterBRouterTilesPage::setSetup(CRouterBRouterSetup * setup) const { widgetLocalTilesSelect->setSetup(setup); } bool CRouterBRouterTilesPage::raiseWarning() const { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); if (widgetLocalTilesSelect->isDownloading()) { msgBox.setText("Download of routing data is in progress."); } else if (widgetLocalTilesSelect->isDownloadSelected()) { msgBox.setText("You did not yet download the selected routing data."); } else { return false; } msgBox.setInformativeText("Do you want to cancel or continue with setup"); msgBox.setStandardButtons(QMessageBox::Cancel); QPushButton *continueButton = msgBox.addButton(tr("Continue with Setup"), QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == continueButton) { return true; } else { widgetLocalTilesSelect->cancelDownload(); return false; } } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetup.cpp000644 001750 000144 00000044741 13216234140 026510 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "helpers/CSettings.h" #include "setup/IAppSetup.h" #include #include #include #include #include CRouterBRouterSetup::CRouterBRouterSetup(QObject *parent) : QObject(parent) { networkAccessManager = new QNetworkAccessManager(this); profilesWebPage = new QWebPage(this); connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CRouterBRouterSetup::slotOnlineRequestFinished); connect(profilesWebPage, &QWebPage::loadFinished, this, &CRouterBRouterSetup::slotLoadOnlineProfilesRequestFinished); } CRouterBRouterSetup::~CRouterBRouterSetup() { } void CRouterBRouterSetup::load() { SETTINGS; cfg.beginGroup("Route/brouter"); installMode = modeFromString(cfg.value("installMode",stringFromMode(defaultInstallMode)).toString()); expertMode = cfg.value("expertMode",defaultExpertMode).toBool(); onlineWebUrl = cfg.value("onlineWebUrl", defaultOnlineWebUrl).toString(); onlineServiceUrl = cfg.value("onlineServiceUrl", defaultOnlineServiceUrl).toString(); onlineProfilesUrl = cfg.value("onlineProfilesUrl", defaultOnlineProfilesUrl).toString(); localDir = cfg.value("localDir", defaultLocalDir).toString(); localJavaExecutable = cfg.value("localJava",findJava()).toString(); localProfileDir = cfg.value("localProfileDir", defaultLocalProfileDir).toString(); localCustomProfileDir = cfg.value("localCustomProfileDir", defaultLocalCustomProfileDir).toString(); localSegmentsDir = cfg.value("localSegmentsDir", defaultLocalSegmentsDir).toString(); localHost = cfg.value("localHost", defaultLocalHost).toString(); localPort = cfg.value("localPort", defaultLocalPort).toString(); localNumberThreads = cfg.value("localNumberThreads", defaultLocalNumberThreads).toString(); localMaxRunningTime = cfg.value("localMaxRunningTime", defaultLocalMaxRunningTime).toString(); localJavaOpts = cfg.value("localJavaOpts", defaultLocalJavaOpts).toString(); binariesUrl = cfg.value("binariesUrl",defaultBinariesUrl).toString(); segmentsUrl = cfg.value("segmentsUrl",defaultSegmentsUrl).toString(); onlineProfiles.clear(); int size = cfg.beginReadArray("online"); for (int i=0; i < size; i++) { cfg.setArrayIndex(i); onlineProfiles << cfg.value("profile").toString(); } cfg.endArray(); localProfiles.clear(); size = cfg.beginReadArray("local"); for (int i=0; i < size; i++) { cfg.setArrayIndex(i); localProfiles << cfg.value("profile").toString(); } cfg.endArray(); cfg.endGroup(); if (installMode == eModeLocal) { readLocalProfiles(); } else if (installMode == eModeOnline) { loadOnlineConfig(); } else { onInvalidSetup(); } } void CRouterBRouterSetup::save() { SETTINGS; cfg.beginGroup("Route/brouter"); cfg.setValue("expertMode",expertMode); cfg.setValue("installMode", stringFromMode(installMode)); cfg.setValue("onlineWebUrl", onlineWebUrl); cfg.setValue("onlineServiceUrl", onlineServiceUrl); cfg.setValue("onlineProfilesUrl", onlineProfilesUrl); cfg.setValue("localDir", localDir); cfg.setValue("localJava", localJavaExecutable); cfg.setValue("localProfileDir", localProfileDir); cfg.setValue("localCustomProfileDir", localCustomProfileDir); cfg.setValue("localSegmentsDir", localSegmentsDir); cfg.setValue("localHost", localHost); cfg.setValue("localPort", localPort); cfg.setValue("localNumberThreads", localNumberThreads); cfg.setValue("localMaxRunningTime", localMaxRunningTime); cfg.setValue("localJavaOpts", localJavaOpts); cfg.setValue("binariesUrl", binariesUrl); cfg.setValue("segmentsUrl", segmentsUrl); cfg.beginWriteArray("online"); for (int i=0; i < onlineProfiles.size(); i++) { cfg.setArrayIndex(i); cfg.setValue("profile", onlineProfiles.at(i)); } cfg.endArray(); cfg.beginWriteArray("local"); for (int i=0; i < localProfiles.size(); i++) { cfg.setArrayIndex(i); cfg.setValue("profile",localProfiles.at(i)); } cfg.endArray(); cfg.endGroup(); } void CRouterBRouterSetup::resetAll() { resetInstallMode(); resetOnlineWebUrl(); resetOnlineServiceUrl(); resetOnlineProfilesUrl(); resetLocalProfileDir(); resetLocalCustomProfileDir(); resetLocalSegmentsDir(); resetLocalHost(); resetLocalPort(); resetLocalNumberThreads(); resetLocalMaxRunningTime(); resetLocalJavaOpts(); resetBinariesUrl(); resetSegmentsUrl(); } CRouterBRouterSetup::mode_e CRouterBRouterSetup::modeFromString(const QString& mode) const { if (mode == "online") { return eModeOnline; } else if (mode == "local") { return eModeLocal; } else { return eModeIllegal; } } QString CRouterBRouterSetup::stringFromMode(const mode_e mode) const { if (mode == eModeLocal) { return "local"; } else { Q_ASSERT(mode == eModeOnline); return "online"; } } void CRouterBRouterSetup::addProfile(const QString &profile) { if (installMode == eModeLocal) { loadOnlineProfileAsync(profile, eProfileInstall); } else { Q_ASSERT(installMode == eModeOnline); if (!onlineProfiles.contains(profile)) { onlineProfiles << profile; emit sigProfilesChanged(); } } } void CRouterBRouterSetup::deleteProfile(const QString &profile) { if (installMode == eModeLocal) { const QString &filename = getProfileDir(eModeLocal).absoluteFilePath(profile + ".brf"); QFile file(filename); if (file.exists()) { file.remove(); } if (localProfiles.contains(profile)) { localProfiles.removeAt(localProfiles.indexOf(profile)); emit sigProfilesChanged(); } } else { Q_ASSERT(installMode == eModeOnline); onlineProfiles.removeAt(onlineProfiles.indexOf(profile)); emit sigProfilesChanged(); } } void CRouterBRouterSetup::profileUp(const QString &profile) { if (installMode == eModeLocal) { int index = localProfiles.indexOf(profile); if (index > 0) { localProfiles.removeAt(index); localProfiles.insert(index-1,profile); emit sigProfilesChanged(); } } else { Q_ASSERT(installMode == eModeOnline); int index = onlineProfiles.indexOf(profile); if (index > 0) { onlineProfiles.removeAt(index); onlineProfiles.insert(index-1,profile); emit sigProfilesChanged(); } } } void CRouterBRouterSetup::profileDown(const QString &profile) { if (installMode == eModeLocal) { int index = localProfiles.indexOf(profile); if (index > -1 && index < localProfiles.size()-1) { localProfiles.removeAt(index); localProfiles.insert(index+1,profile); emit sigProfilesChanged(); } } else { Q_ASSERT(installMode == eModeOnline); int index = onlineProfiles.indexOf(profile); if (index > -1 && index < onlineProfiles.size()-1) { onlineProfiles.removeAt(index); onlineProfiles.insert(index+1,profile); emit sigProfilesChanged(); } } } void CRouterBRouterSetup::readLocalProfiles() { bool changed(false); const QDir& dir = getProfileDir(eModeLocal); QStringList installedProfiles; if (dir.exists()) { for(const QString &profile : dir.entryList()) { if (profile.endsWith(".brf")) { installedProfiles << profile.left(profile.length()-4); } } } const QStringList localProfilesTmp(localProfiles); for (const QString &profile : localProfilesTmp) { if (!installedProfiles.contains(profile)) { localProfiles.removeAt(localProfiles.indexOf(profile)); changed = true; } } for (const QString &profile : installedProfiles) { if (!localProfiles.contains(profile)) { localProfiles << profile; changed = true; } } if (changed) { emit sigProfilesChanged(); } } QDir CRouterBRouterSetup::getProfileDir(const mode_e mode) const { if (mode == eModeLocal) { return QDir(QDir(localDir).absoluteFilePath(localProfileDir)); } else { Q_ASSERT(mode == eModeOnline); QDir brouterDir(QDir(IAppSetup::getPlatformInstance()->defaultCachePath()).absoluteFilePath(onlineCacheDir)); if (!brouterDir.exists()) { brouterDir.mkpath(brouterDir.absolutePath()); } return brouterDir; } } QStringList CRouterBRouterSetup::getProfiles() const { if (installMode == eModeLocal) { return localProfiles; } else { Q_ASSERT(installMode == eModeOnline); return onlineProfiles; } } void CRouterBRouterSetup::loadLocalOnlineProfiles() const { profilesWebPage->mainFrame()->load(QUrl(onlineProfilesUrl)); } void CRouterBRouterSetup::loadOnlineConfig() const { const QUrl configUrl(onlineWebUrl + "config.js"); const QString &configHost = configUrl.host(); QNetworkReply * reply = networkAccessManager->get(QNetworkRequest(configUrl)); reply->setProperty("configHost",configHost); reply->setProperty("type",eTypeConfig); } void CRouterBRouterSetup::slotOnlineRequestFinished(QNetworkReply *reply) { const request_e type = request_e(reply->property("type").toInt()); if (type == eTypeConfig) { loadOnlineConfigFinished(reply); } else { Q_ASSERT(type == eTypeProfile); loadOnlineProfileFinished(reply); } } void CRouterBRouterSetup::loadOnlineConfigFinished(QNetworkReply *reply) { reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { emitNetworkError(reply->errorString()); return; } else { QString configHost = reply->property("configHost").toString(); const QString jsConfig(reply->readAll()); QScriptEngine engine; const QString &jsSetup = QString( \ "(function(){\ window = {};\ window.location = {};\ window.location.hostname = '%1';\ window.location.search = {};\ window.location.search.slice = function() {};\ URLSearchParams = function() {};\ BR = {};\ })();").arg(configHost); engine.evaluate(jsSetup).toString(); engine.evaluate(jsConfig).toString(); if (engine.hasUncaughtException()) { emitOnlineConfigScriptError(engine.uncaughtException()); return; } const QScriptValue &br = engine.globalObject().property("BR"); if (!br.isValid() || br.isError()) { emitOnlineConfigScriptError(br); return; } const QScriptValue &conf = br.property("conf"); if (!conf.isValid() || conf.isError()) { emitOnlineConfigScriptError(conf); return; } const QScriptValue &host = conf.property("host").toString(); if (!host.isValid() || host.isError()) { emitOnlineConfigScriptError(host); return; } if (onlineServiceUrl != host.toString()) { onlineServiceUrl = host.toString(); } const QScriptValue &url = conf.property("profilesUrl").toString(); if (!url.isValid() || url.isError()) { emitOnlineConfigScriptError(url); return; } if (onlineProfilesUrl != url.toString()) { onlineProfilesUrl = url.toString(); } const QScriptValue &profiles = conf.property("profiles"); if (!profiles.isValid() || profiles.isError()) { emitOnlineConfigScriptError(profiles); return; } const qint32 len = profiles.property("length").toInt32(); QStringList onlineProfilesLoaded; for(qint32 i=0; imainFrame()->documentElement(); const QWebElementCollection &anchorElements = htmlElement.findAll("table tr td a"); if (anchorElements.count() == 0) { emitNetworkError(tr("%1 invalid result").arg(onlineProfilesUrl)); return; } const QRegExp rxProfileName("(\\S+)\\.brf"); QStringList onlineProfilesLoaded; for (const QWebElement &anchorElement : anchorElements) { const QString &profileName = anchorElement.toPlainText(); //only anchors matching the desired pattern if (rxProfileName.indexIn(profileName) > -1) { onlineProfilesLoaded << rxProfileName.cap(1); } } mergeOnlineProfiles(onlineProfilesLoaded); emit sigProfilesChanged(); } } void CRouterBRouterSetup::mergeOnlineProfiles(const QStringList &onlineProfilesLoaded) { const QStringList onlineProfilesAvailableTmp(onlineProfilesAvailable); for (const QString &profile : onlineProfilesAvailableTmp) { if (!onlineProfilesLoaded.contains(profile)) { onlineProfilesAvailable.removeAt(onlineProfilesAvailable.indexOf(profile)); } } for (const QString &profile : onlineProfilesLoaded) { if (!onlineProfilesAvailable.contains(profile)) { onlineProfilesAvailable << profile; } } } void CRouterBRouterSetup::emitOnlineConfigScriptError(const QScriptValue &error) const { emit sigError(tr("Error parsing online-config:"),error.toString()); } void CRouterBRouterSetup::emitNetworkError(QString error) const { emit sigError(tr("Network error:"),error); } void CRouterBRouterSetup::displayProfileAsync(const QString &profile) const { if (installMode == eModeLocal) { QFile file(getProfileDir(eModeLocal).absoluteFilePath(profile + ".brf")); if (file.exists()) { file.open(QIODevice::ReadOnly); const QByteArray &content = file.readAll(); file.close(); emit sigDisplayOnlineProfileFinished(profile, QString(content)); } } else { Q_ASSERT(installMode == eModeOnline); loadOnlineProfileAsync(profile, eProfileDisplay); } } void CRouterBRouterSetup::displayOnlineProfileAsync(const QString &profile) const { loadOnlineProfileAsync(profile, eProfileDisplay); } void CRouterBRouterSetup::loadOnlineProfileAsync(const QString &profile, const profileRequest_e mode) const { QNetworkReply * reply = networkAccessManager->get(QNetworkRequest(QUrl(onlineProfilesUrl + profile +".brf"))); reply->setProperty("type",eTypeProfile); reply->setProperty("profile", profile); reply->setProperty("request", mode); } void CRouterBRouterSetup::loadOnlineProfileFinished(QNetworkReply * reply) { reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { emitNetworkError(reply->errorString()); } else { const QString &profile = reply->property("profile").toString(); const profileRequest_e mode = profileRequest_e(reply->property("request").toInt()); const QByteArray &content = reply->readAll(); if (mode == eProfileInstall) { const QDir dir = getProfileDir(eModeLocal); const QString filename = dir.absoluteFilePath(profile + ".brf"); QFile file(filename); file.open(QIODevice::WriteOnly); file.write(content); file.close(); readLocalProfiles(); } else { Q_ASSERT(mode == eProfileDisplay); emit sigDisplayOnlineProfileFinished(profile, QString(content)); } } } bool CRouterBRouterSetup::isLocalBRouterInstalled() const { const QDir dir(localDir); return QFile(dir.absoluteFilePath("brouter.jar")).exists() && QDir(dir.absoluteFilePath(localProfileDir)).exists(); } QString CRouterBRouterSetup::findJava() const { return IAppSetup::getPlatformInstance()->findExecutable("java"); } void CRouterBRouterSetup::onInvalidSetup() { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText("BRouter config is inconsistent!"); msgBox.setInformativeText("Resetting to default values"); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); resetAll(); } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesSelectArea.cpp000644 001750 000144 00000014563 13216234140 030420 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "canvas/CCanvas.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelect.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelectArea.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelectLayout.h" #include "gis/rte/router/brouter/CRouterBRouterTilesStatus.h" #include const QPen CRouterBRouterTilesSelectArea::gridPen = QPen(Qt::magenta); const QPen CRouterBRouterTilesSelectArea::outdatedTilesPen = QPen(Qt::gray); const QPen CRouterBRouterTilesSelectArea::currentTilesPen = QPen(Qt::darkGreen); const QPen CRouterBRouterTilesSelectArea::selectedTilesPen = QPen(Qt::blue); const QPen CRouterBRouterTilesSelectArea::outstandingTilesPen = QPen(Qt::yellow); const QPen CRouterBRouterTilesSelectArea::invalidTilesPen = QPen(Qt::gray); const QBrush CRouterBRouterTilesSelectArea::outdatedTilesBrush = QBrush(Qt::gray, Qt::Dense5Pattern); const QBrush CRouterBRouterTilesSelectArea::currentTilesBrush = QBrush(Qt::darkGreen,Qt::Dense3Pattern); const QBrush CRouterBRouterTilesSelectArea::selectedTilesBrush = QBrush(Qt::blue, Qt::Dense3Pattern); const QBrush CRouterBRouterTilesSelectArea::outstandingTilesBrush = QBrush(Qt::yellow, Qt::Dense3Pattern); const QBrush CRouterBRouterTilesSelectArea::invalidTilesBrush = QBrush(Qt::gray, Qt::DiagCrossPattern); CRouterBRouterTilesSelectArea::CRouterBRouterTilesSelectArea(QWidget * parent, CCanvas * canvas) : QWidget(parent) { this->canvas = canvas; setMouseTracking(true); } CRouterBRouterTilesSelectArea::~CRouterBRouterTilesSelectArea() { } bool CRouterBRouterTilesSelectArea::event(QEvent * event) { if (event->type() == QEvent::ToolTip) { QHelpEvent *helpEvent = static_cast(event); const QPoint &tile = tileUnderMouse(helpEvent->pos()); if (currentTile != tile) { emit sigTileToolTipChanged(tile); currentTile = tile; } QToolTip::showText(helpEvent->globalPos(), tileToolTip); return true; } return QWidget::event(event); } void CRouterBRouterTilesSelectArea::paintEvent(QPaintEvent *event) { drawGrid(); drawTiles(invalidTilesPen, invalidTilesBrush, invalidTiles); drawTiles(outdatedTilesPen, outdatedTilesBrush, outdatedTiles); drawTiles(currentTilesPen, currentTilesBrush, currentTiles); drawTiles(selectedTilesPen, selectedTilesBrush, selectedTiles); drawTiles(outstandingTilesPen, outstandingTilesBrush, outstandingTiles); } void CRouterBRouterTilesSelectArea::mouseMoveEvent(QMouseEvent * event) { if (event->buttons() == Qt::LeftButton) { canvas->moveMap(QPointF(event->pos()-mousePos)); mousePos = event->pos(); } } void CRouterBRouterTilesSelectArea::mousePressEvent(QMouseEvent * event) { if (event->buttons() == Qt::LeftButton) { startPos = mousePos = event->pos(); } button = event->buttons(); } void CRouterBRouterTilesSelectArea::mouseReleaseEvent(QMouseEvent * event) { if (button == Qt::LeftButton) { const QPoint &pos = event->pos(); canvas->moveMap(QPointF(pos-mousePos)); if (pos == startPos) { emit sigTileClicked(tileUnderMouse(pos)); } } } void CRouterBRouterTilesSelectArea::drawGrid() { QPainter painter(this); painter.setPen(gridPen); for(const QPoint &tile : gridTiles) { painter.drawPolyline(gridPolygon(tile)); } } void CRouterBRouterTilesSelectArea::drawTiles(const QPen &pen, const QBrush & brush, const QVector & tiles) { QPainter painter(this); painter.setPen(pen); painter.setBrush(brush); for(const QPoint &tile : tiles) { painter.drawPolygon(tilePolygon(tile)); } } QPoint CRouterBRouterTilesSelectArea::tileUnderMouse(const QPointF & mousePos) const { QPointF pos(mousePos); canvas->convertPx2Rad(pos); QPointF posDegF = pos * RAD_TO_DEG; QPoint tile(posDegF.x() > 0 ? posDegF.x()/CRouterBRouterTilesSelect::tileSize : posDegF.x()/CRouterBRouterTilesSelect::tileSize - 1 ,posDegF.y() > 0 ? posDegF.y()/CRouterBRouterTilesSelect::tileSize : posDegF.y()/CRouterBRouterTilesSelect::tileSize - 1); return tile * CRouterBRouterTilesSelect::tileSize; } QPolygonF CRouterBRouterTilesSelectArea::tilePolygon(const QPoint & tile) const { QPointF p0(tile.x(),tile.y()); QPointF p1(tile.x()+CRouterBRouterTilesSelect::tileSize,tile.y()); QPointF p2(tile.x()+CRouterBRouterTilesSelect::tileSize,tile.y()+CRouterBRouterTilesSelect::tileSize); QPointF p3(tile.x(),tile.y()+CRouterBRouterTilesSelect::tileSize); p0 *= DEG_TO_RAD; p1 *= DEG_TO_RAD; p2 *= DEG_TO_RAD; p3 *= DEG_TO_RAD; canvas->convertRad2Px(p0); canvas->convertRad2Px(p1); canvas->convertRad2Px(p2); canvas->convertRad2Px(p3); QPolygonF polygon; polygon << p0; polygon << p1; polygon << p2; polygon << p3; return polygon; } QPolygonF CRouterBRouterTilesSelectArea::gridPolygon(const QPoint & tile) const { QPointF p0(tile.x(),tile.y()); QPointF p1(tile.x()+CRouterBRouterTilesSelect::tileSize,tile.y()); QPointF p2(tile.x()+CRouterBRouterTilesSelect::tileSize,tile.y()+CRouterBRouterTilesSelect::tileSize); p0 *= DEG_TO_RAD; p1 *= DEG_TO_RAD; p2 *= DEG_TO_RAD; canvas->convertRad2Px(p0); canvas->convertRad2Px(p1); canvas->convertRad2Px(p2); QPolygonF polygon; polygon << p0; polygon << p1; polygon << p2; return polygon; } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterToolShell.h000644 001750 000144 00000003505 13216234143 026756 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsessr norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTOOLSHELL_H #define CROUTERBROUTERTOOLSHELL_H #include "tool/IToolShell.h" #if defined (Q_OS_WIN32) #define USE_KILL_FOR_SHUTDOWN #endif class CRouterBRouterToolShell : public IToolShell { Q_OBJECT public: CRouterBRouterToolShell(QTextBrowser *textBrowser, QWidget * parent); virtual ~CRouterBRouterToolShell(); void start(const QString &dir, const QString &command, const QStringList &args); void stop(); signals: void sigProcessStateChanged(const QProcess::ProcessState newState) const; void sigProcessError(const QProcess::ProcessError error, const QString &errorString) const; private slots: void slotStateChanged(const QProcess::ProcessState newState) const; void slotError(const QProcess::ProcessError error) const; private: void finished(int exitCode, QProcess::ExitStatus status) override; bool isBeingKilled { false }; }; #endif //CROUTERBROUTERTOOLSHELL_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterInfo.h000644 001750 000144 00000002402 13216234143 025737 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERINFO_H #define CROUTERBROUTERINFO_H #include "ui_IRouterBRouterInfo.h" class CRouterBRouterInfo : public QDialog, private Ui::IRouterBRouterInfo { Q_OBJECT public: CRouterBRouterInfo(); virtual ~CRouterBRouterInfo(); void setLabel(const QString &infoLabel) const; void setInfo(const QString &infoText) const; }; #endif qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesPage.h000644 001750 000144 00000003057 13216234143 026730 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTILESPAGE_H #define CROUTERBROUTERTILESPAGE_H #include #include class CRouterBRouterTilesSelect; class CRouterBRouterSetup; class CRouterBRouterTilesPage : public QWizardPage { Q_OBJECT public: CRouterBRouterTilesPage(); virtual ~CRouterBRouterTilesPage(); bool isComplete() const override; void setSetup(CRouterBRouterSetup * setup) const; void beginPage() const; bool raiseWarning() const; private slots: void slotTileDownloadStatusChanged(); private: QVBoxLayout * layout; CRouterBRouterTilesSelect * widgetLocalTilesSelect; }; #endif //CROUTERBROUTERTILESPAGE_H qmapshack-1.10.0/src/gis/rte/router/brouter/IRouterBRouterSetupWizard.ui000644 001750 000144 00000047176 13077315473 027555 0ustar00oeichlerxusers000000 000000 IRouterBRouterSetupWizard true 0 0 700 500 0 0 BRouter Setup QWizard::CancelButtonOnLeft|QWizard::HaveCustomButton1 0 0 0 0 0 choose which BRouter to use BRouter-Web (online) local Installation Expert Mode 0 0 1 local BRouter Installation directory: select installation directory ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png labelLocalDirResult create or update installation Qt::Horizontal 40 20 Java Executable ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png labelLocalJavaResult search for installed java Qt::Horizontal 40 20 Qt::Vertical 20 269 0 0 2 Download and install BRouter Version 0 0 about:blank File to install Download and Install Qt::Horizontal 40 20 0 0 0 0 3 available Profiles QAbstractItemView::NoEditTriggers install profile ... :/icons/32x32/Right.png:/icons/32x32/Right.png remove profile ... :/icons/32x32/Left.png:/icons/32x32/Left.png installed Profiles QAbstractItemView::NoEditTriggers ... :/icons/32x32/Up.png:/icons/32x32/Up.png ... :/icons/32x32/Down.png:/icons/32x32/Down.png content of profile 0 0 4 0 0 5 BRouter-Web URL: Qt::Vertical 20 40 true 1 1 6 QLayout::SetNoConstraint Service-URL Profile-URL Qt::Vertical 20 40 0 0 7 Profiles Url Hostname Port Profile directory Segments directory Custom Profiles dir Max Runtime Number Threads Java Options Qt::Vertical 20 40 QWebView QWidget
QtWebKitWidgets/QWebView
CRouterBRouterTilesPage QWizardPage
gis/rte/router/brouter/CRouterBRouterTilesPage.h
1
CRouterBRouterSetupPage QWizardPage
gis/rte/router/brouter/CRouterBRouterSetupPage.h
1
qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterToolShell.cpp000644 001750 000144 00000005133 13216234140 027305 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "CRouterBRouterToolShell.h" #include CRouterBRouterToolShell::CRouterBRouterToolShell(QTextBrowser *textBrowser, QWidget * parent) : IToolShell(parent) { setTextBrowser(textBrowser); connect(&cmd, &QProcess::stateChanged, this, &CRouterBRouterToolShell::slotStateChanged); connect(&cmd, static_cast(&QProcess::error), this, &CRouterBRouterToolShell::slotError); } CRouterBRouterToolShell::~CRouterBRouterToolShell() { } void CRouterBRouterToolShell::start(const QString &dir, const QString &command, const QStringList &args) { isBeingKilled = false; stdOut("cd " + dir); stdOut(command+" " + args.join(" ") + "\n"); cmd.setWorkingDirectory(dir); cmd.start(command,args); cmd.waitForStarted(); } void CRouterBRouterToolShell::stop() { if (cmd.state() != QProcess::NotRunning) { #ifdef USE_KILL_FOR_SHUTDOWN isBeingKilled = true; cmd.kill(); #else cmd.terminate(); #endif } } void CRouterBRouterToolShell::slotStateChanged(const QProcess::ProcessState newState) const { emit sigProcessStateChanged(newState); } void CRouterBRouterToolShell::slotError(const QProcess::ProcessError error) const { if (isBeingKilled) { return; } emit sigProcessError(error, cmd.errorString()); } void CRouterBRouterToolShell::finished(const int exitCode, const QProcess::ExitStatus status) { if (status == QProcess::ExitStatus::NormalExit) { text->setTextColor(Qt::darkGreen); text->append(tr("!!! done !!!\n")); } else { text->setTextColor(Qt::darkRed); text->append(tr("!!! failed !!!\n")); } } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesSelectArea.h000644 001750 000144 00000006523 13216234143 030065 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERTILESSELECTAREA_H #define CROUTERBROUTERTILESSELECTAREA_H #include #include #include class CCanvas; class CRouterBRouterTilesSelect; class CRouterBRouterTilesSelectArea : public QWidget { Q_OBJECT public: CRouterBRouterTilesSelectArea(QWidget * parent, CCanvas * canvas); virtual ~CRouterBRouterTilesSelectArea(); void paintEvent(QPaintEvent *event) override; void setGridTiles(const QVector & tiles) { gridTiles = tiles; } void setInvalidTiles(const QVector & tiles) { invalidTiles = tiles; } void setOutdatedTiles(const QVector & tiles) { outdatedTiles = tiles; } void setCurrentTiles(const QVector & tiles) { currentTiles = tiles; } void setOutstandingTiles(const QVector & tiles) { outstandingTiles = tiles; } void setSelectedTiles(const QVector & tiles) { selectedTiles = tiles; } void setTileToolTip(const QString &toolTip) { tileToolTip = toolTip; } static const QPen gridPen; static const QPen currentTilesPen; static const QPen outdatedTilesPen; static const QPen selectedTilesPen; static const QPen outstandingTilesPen; static const QPen invalidTilesPen; static const QBrush currentTilesBrush; static const QBrush outdatedTilesBrush; static const QBrush selectedTilesBrush; static const QBrush outstandingTilesBrush; static const QBrush invalidTilesBrush; signals: void sigTileClicked(const QPoint & tile); void sigTileToolTipChanged(const QPoint & tile); protected: void mouseMoveEvent(QMouseEvent * event) override; void mousePressEvent(QMouseEvent * event) override; void mouseReleaseEvent(QMouseEvent * event) override; bool event(QEvent * event) override; private slots: private: void drawGrid(); void drawTiles(const QPen &pen, const QBrush &brush, const QVector & tiles); QPoint tileUnderMouse(const QPointF & mousePos) const; QPolygonF gridPolygon(const QPoint & tile) const; QPolygonF tilePolygon(const QPoint & tile) const; CCanvas * canvas; QPoint mousePos; QPoint startPos; Qt::MouseButtons button; QPoint currentTile; QString tileToolTip; QVector gridTiles; QVector invalidTiles; QVector outdatedTiles; QVector currentTiles; QVector outstandingTiles; QVector selectedTiles; }; #endif //CROUTERBROUTERTILESSELECTAREA_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterInfo.cpp000644 001750 000144 00000002527 13216234140 026277 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "gis/rte/router/brouter/CRouterBRouterInfo.h" CRouterBRouterInfo::CRouterBRouterInfo() : QDialog(CMainWindow::getBestWidgetForParent()) { setupUi(this); } CRouterBRouterInfo::~CRouterBRouterInfo() { } void CRouterBRouterInfo::setLabel(const QString &infoLabel) const { label->setText(infoLabel); } void CRouterBRouterInfo::setInfo(const QString &infoText) const { textBrowser->setText(infoText); } qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetupPage.h000644 001750 000144 00000002725 13216234143 026751 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERSETUPPAGE_H #define CROUTERBROUTERSETUPPAGE_H #include class CRouterBRouterSetup; class CRouterBRouterSetupPage : public QWizardPage { Q_OBJECT public: CRouterBRouterSetupPage(); virtual ~CRouterBRouterSetupPage(); bool isComplete() const override; void setSetup(CRouterBRouterSetup * newSetup) { setup = newSetup; } void setComplete(bool newComplete); void emitCompleteChanged(); private: CRouterBRouterSetup * setup { nullptr }; bool complete { false }; }; #endif //CROUTERBROUTERTILESPAGE_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetup.h000644 001750 000144 00000013400 13216234143 026144 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERSETUP_H #define CROUTERBROUTERSETUP_H #include #include #include class CRouterBRouterSetup : public QObject { Q_OBJECT public: CRouterBRouterSetup(QObject * parent); ~CRouterBRouterSetup(); enum mode_e { eModeLocal, eModeOnline, eModeIllegal }; struct tile_t { QPoint tile; QDateTime date; qreal size; }; void load(); void save(); void resetAll(); void resetInstallMode() { installMode = defaultInstallMode; } void resetOnlineWebUrl() { onlineWebUrl = defaultOnlineWebUrl; } void resetOnlineServiceUrl() { onlineServiceUrl = defaultOnlineServiceUrl; } void resetOnlineProfilesUrl() { onlineProfilesUrl = defaultOnlineProfilesUrl; } void resetLocalProfileDir() { localProfileDir = defaultLocalProfileDir; } void resetLocalCustomProfileDir() { localCustomProfileDir = defaultLocalCustomProfileDir; } void resetLocalSegmentsDir() { localSegmentsDir = defaultLocalSegmentsDir; } void resetLocalHost() { localHost = defaultLocalHost; } void resetLocalPort() { localPort = defaultLocalPort; } void resetLocalNumberThreads() { localNumberThreads = defaultLocalNumberThreads; } void resetLocalMaxRunningTime() { localMaxRunningTime = defaultLocalMaxRunningTime; } void resetLocalJavaOpts() { localJavaOpts = defaultLocalJavaOpts; } void resetBinariesUrl() { binariesUrl = defaultBinariesUrl; } void resetSegmentsUrl() { segmentsUrl = defaultSegmentsUrl; } QStringList getProfiles() const; void addProfile(const QString &profile); void deleteProfile(const QString &profile); void profileUp(const QString &profile); void profileDown(const QString &profile); void readLocalProfiles(); void loadOnlineConfig() const; void loadLocalOnlineProfiles() const; void displayProfileAsync(const QString &profile) const; void displayOnlineProfileAsync(const QString &profile) const; QString findJava() const; bool isLocalBRouterInstalled() const; void onInvalidSetup(); signals: void sigOnlineConfigLoaded() const; void sigProfilesChanged() const; void sigDisplayOnlineProfileFinished(const QString profile, const QString content) const; void sigError(const QString error, const QString details) const; private slots: void slotOnlineRequestFinished(QNetworkReply *reply); void slotLoadOnlineProfilesRequestFinished(bool ok); private: enum request_e { eTypeConfig, eTypeProfile }; enum profileRequest_e { eProfileInstall, eProfileDisplay }; QDir getProfileDir(const mode_e mode) const; void loadOnlineProfileAsync(const QString &profile, const profileRequest_e mode) const; void loadOnlineConfigFinished(QNetworkReply* reply); void loadOnlineProfileFinished(QNetworkReply * reply); void mergeOnlineProfiles(const QStringList &profilesLoaded); void emitOnlineConfigScriptError(const QScriptValue &error) const; void emitNetworkError(QString error) const; mode_e modeFromString(const QString &mode) const; QString stringFromMode(const mode_e mode) const; QStringList onlineProfiles; QStringList localProfiles; QNetworkAccessManager * networkAccessManager; QWebPage * profilesWebPage; bool expertMode; mode_e installMode; QString onlineWebUrl; QString onlineServiceUrl; QString onlineProfilesUrl; QStringList onlineProfilesAvailable; QString localDir; QString localJavaExecutable; QString localProfileDir; QString localCustomProfileDir; QString localSegmentsDir; QString localHost; QString localPort; QString localNumberThreads; QString localMaxRunningTime; QString localJavaOpts; QString binariesUrl; QString segmentsUrl; const bool defaultExpertMode = false; const mode_e defaultInstallMode = eModeOnline; const QString defaultOnlineWebUrl = "http://brouter.de/brouter-web/"; const QString defaultOnlineServiceUrl = "http://h2096617.stratoserver.net:443"; const QString defaultOnlineProfilesUrl = "http://brouter.de/brouter/profiles2/"; const QString defaultLocalDir = "."; const QString defaultLocalProfileDir = "profiles2"; const QString defaultLocalCustomProfileDir = "customprofiles"; const QString defaultLocalSegmentsDir = "segments4"; const QString defaultLocalHost = "127.0.0.1"; const QString defaultLocalPort = "17777"; const QString defaultLocalNumberThreads = "1"; const QString defaultLocalMaxRunningTime = "300"; const QString defaultLocalJavaOpts = "-Xmx128M -Xms128M -Xmn8M"; const QString defaultBinariesUrl = "http://brouter.de/brouter_bin/"; const QString defaultSegmentsUrl = "http://brouter.de/brouter/segments4/"; const QString onlineCacheDir = "BRouter"; friend class CRouterBRouter; friend class CRouterBRouterSetupPage; friend class CRouterBRouterSetupWizard; friend class CRouterBRouterTilesSelect; }; #endif qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterSetupWizard.h000644 001750 000144 00000010016 13216234143 027325 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CROUTERBROUTERSETUPWIZARD_H #define CROUTERBROUTERSETUPWIZARD_H #include "ui_IRouterBRouterSetupWizard.h" class CCanvas; class CRouterBRouterSetup; class CRouterBRouterTilesSelect; class CRouterBRouterSetupWizard : public QWizard, private Ui::IRouterBRouterSetupWizard { Q_OBJECT public: CRouterBRouterSetupWizard(); virtual ~CRouterBRouterSetupWizard(); int nextId() const override; void initializePage(int id) override; bool validateCurrentPage() override; enum { ePageChooseMode, ePageLocalDirectory, ePageLocalInstallation, ePageProfiles, ePageLocalTiles, ePageOnlineUrl, ePageOnlineDetails, ePageLocalDetails }; public slots: void accept() override; void reject() override; private slots: void slotCurrentIdChanged(const int id); void slotCustomButtonClicked(int id); void slotRadioLocalClicked() const; void slotRadioOnlineClicked() const; void slotCheckExpertClicked() const; void slotLocalToolSelectDirectory(); void slotLocalToolSelectJava(); void slotLocalPushFindJava() const; void slotCreateOrUpdateLocalInstallClicked(); void slotLocalDirectoryCursonPositionChanged() const; void slotLocalJavaExecutableCursorPositionChanged() const; void slotLocalProfilesUrlCursorPositionChanged(); void slotOnlineUrlCursorPositionChanged(); void slotWebLocalBRouterVersionsLoadFinished(bool ok); void slotLocalDownloadLinkClicked(const QUrl & url); void slotLocalDownloadButtonClicked(); void slotLocalDownloadButtonFinished(QNetworkReply * reply); void slotProfileClicked(const QModelIndex & index) const; void slotAvailableProfileClicked(const QModelIndex & index) const; void slotDisplayProfile(const QString &profile, const QString content); void slotAddProfileClicked() const; void slotDelProfileClicked() const; void slotProfileUpClicked() const; void slotProfileDownClicked() const; void slotOnlineConfigLoaded(); void slotSetupError(const QString &error, const QString &details); void slotOnlineProfilesLoaded(); private: void beginChooseMode(); void initLocalDirectory(); void beginLocalDirectory(); void updateLocalDirectory() const; void initLocalInstall(); void beginLocalInstall(); void beginProfiles(); void updateProfiles() const; QStringList selectedProfiles(const QListView * listView) const; QList updateProfileView(QListView * listView, const QStringList &values) const; void initLocalTiles() const; void beginLocalTiles(); void beginLocalDetails(); void updateLocalDetails() const; bool validateLocalDetails() const; void resetLocalDetails() const; void beginOnlineDetails(); void updateOnlineDetails() const; bool validateOnlineDetails() const; void resetOnlineDetails() const; void beginOnlineUrl(); void updateOnlineUrl(); void resetOnlineUrl(); CRouterBRouterSetup * setup; bool doLocalInstall; QUrl downloadUrl; QNetworkAccessManager * networkAccessManager; bool isError { false }; QString error; QString errorDetails; }; #endif //CROUTERBROUTERSETUPWIZARD_H qmapshack-1.10.0/src/gis/rte/router/brouter/CRouterBRouterTilesSelect.cpp000644 001750 000144 00000067047 13216234140 027634 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/rte/router/brouter/CRouterBRouterSetup.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelect.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelectArea.h" #include "gis/rte/router/brouter/CRouterBRouterTilesSelectLayout.h" #include "gis/rte/router/brouter/CRouterBRouterTilesStatus.h" #include #include #include #include const QPoint CRouterBRouterTilesSelect::noTile = QPoint(INT_MIN, INT_MIN); const int CRouterBRouterTilesSelect::minTileLat = -180; const int CRouterBRouterTilesSelect::maxTileLat = 180; const int CRouterBRouterTilesSelect::minTileLon = -85; const int CRouterBRouterTilesSelect::maxTileLon = 85; const int CRouterBRouterTilesSelect::tileSize = 5; CRouterBRouterTilesSelect::CRouterBRouterTilesSelect(QWidget *parent) : QWidget(parent) { for (int x = minTileLat; x < maxTileLat; x += tileSize) { for (int y = minTileLon; y < maxTileLon; y += tileSize) { CRouterBRouterTilesStatus * status = new CRouterBRouterTilesStatus(this); tilesDownloadStatus.insert(fileNameFromTile(QPoint(x,y)),status); } } outerLayout = new QVBoxLayout(this); outerLayout->setContentsMargins(0,0,0,0); widgetSelect = new QWidget(this); widgetSelect->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); outerLayout->addWidget(widgetSelect); widgetSelect->show(); QTemporaryFile temp; temp.open(); temp.close(); QSettings view(temp.fileName(), QSettings::IniFormat); view.clear(); CCanvas * source = CMainWindow::self().getVisibleCanvas(); if(source) { source->saveConfig(view); } view.setValue("map/zoomIndex",16); view.setValue("scales",1); view.setValue("proj","+proj=merc"); view.setValue("grid/proj","+proj=longlat +datum=WGS84 +no_defs"); CCanvas * canvas = new CCanvas(widgetSelect,"BRouterTileDownload"); // clone canvas by a temporary configuration file canvas->loadConfig(view); selectArea = new CRouterBRouterTilesSelectArea(widgetSelect,canvas); QLayout * selectLayout = new CRouterBRouterTilesSelectLayout(widgetSelect); selectLayout->addWidget(canvas); selectLayout->addWidget(selectArea); canvas->lower(); canvas->show(); selectArea->show(); QHBoxLayout * statusLayout = new QHBoxLayout(); outerLayout->addLayout(statusLayout); statusLabel = new QLabel(this); statusProgress = new QProgressBar(this); statusLayout->addWidget(statusLabel); statusLayout->addWidget(statusProgress); statusLabel->setText(tr("available routing-data is being determined.")); statusProgress->setVisible(false); errorLabel = new QLabel(this); outerLayout->addWidget(errorLabel); errorLabel->setVisible(false); QHBoxLayout * buttonsLayout = new QHBoxLayout(); outerLayout->addLayout(buttonsLayout); pushSelectOutdated = new QPushButton(tr("Select outdated"), this); pushClearSelection = new QPushButton(tr("Clear Selection"), this); pushDeleteSelection = new QPushButton(tr("Delete selection"), this); pushDownload = new QPushButton(tr("Download"), this); buttonsLayout->addWidget(pushSelectOutdated); buttonsLayout->addWidget(pushClearSelection); buttonsLayout->addWidget(pushDeleteSelection); buttonsLayout->addWidget(pushDownload); tilesDownloadManager = new QNetworkAccessManager(this); tilesWebPage = new QWebPage(this); connect(pushClearSelection, &QPushButton::clicked, this, &CRouterBRouterTilesSelect::slotClearSelection); connect(pushDeleteSelection, &QPushButton::clicked, this, &CRouterBRouterTilesSelect::slotDeleteSelected); connect(pushSelectOutdated, &QPushButton::clicked, this, &CRouterBRouterTilesSelect::slotSelectOutdated); connect(pushDownload, &QPushButton::clicked, this, &CRouterBRouterTilesSelect::slotDownload); connect(selectArea, &CRouterBRouterTilesSelectArea::sigTileClicked, this, &CRouterBRouterTilesSelect::slotTileClicked); connect(selectArea, &CRouterBRouterTilesSelectArea::sigTileToolTipChanged, this, &CRouterBRouterTilesSelect::slotTileToolTipChanged); connect(tilesWebPage, &QWebPage::loadFinished, this, &CRouterBRouterTilesSelect::slotLoadOnlineTilesRequestFinished); connect(tilesDownloadManager, &QNetworkAccessManager::finished, this, &CRouterBRouterTilesSelect::slotDownloadFinished); } CRouterBRouterTilesSelect::~CRouterBRouterTilesSelect() { } void CRouterBRouterTilesSelect::setSetup(CRouterBRouterSetup * setup) { this->setup = setup; } void CRouterBRouterTilesSelect::slotTileClicked(const QPoint &tile) { CRouterBRouterTilesStatus * status = getTileStatus(tile); if (status->isLocal || status->isRemote) { status->isSelected = !status->isSelected; update(); } } void CRouterBRouterTilesSelect::slotSelectOutdated() { bool changed(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); if (!status->isSelected && status->isOutdated) { changed = true; status->isSelected = true; } } if (changed) { update(); } } void CRouterBRouterTilesSelect::slotDeleteSelected() { bool changed(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); if (status->isSelected) { status->isSelected = false; changed = true; if (status->isLocal) { QFile segment(segmentsDir().absoluteFilePath(it.key())); if (!segment.remove()) { error(tr("Error removing %1: %2") .arg(segment.fileName()) .arg(segment.errorString())); break; } status->isLocal = false; } } } if (changed) { update(); } } void CRouterBRouterTilesSelect::slotClearSelection() { bool changed(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); if (status->isSelected) { changed = true; status->isSelected = false; } } if (changed) { update(); } } void CRouterBRouterTilesSelect::updateButtons() const { bool hasSelected(false); bool hasLocalSelected(false); bool hasUnselectedOutdated(false); bool hasSelectedForDownload(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); if (status->isSelected) { hasSelected = true; if (status->isLocal) { hasLocalSelected = true; } if (status->isOutdated || !status->isLocal) { hasSelectedForDownload = true; } } else if (status->isOutdated) { hasUnselectedOutdated = true; } } pushClearSelection->setEnabled(hasSelected); pushDeleteSelection->setEnabled(hasLocalSelected); pushSelectOutdated->setEnabled(hasUnselectedOutdated); pushDownload->setEnabled(hasSelectedForDownload); } void CRouterBRouterTilesSelect::initialize() { try { for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); status->isLocal = false; status->isRemote = false; status->isOutdated = false; } const QDir &dir = segmentsDir(); if (!dir.exists()) { if (!QDir(setup->localDir).mkpath(setup->localSegmentsDir)) { throw tr("Error creating segments directory %1").arg(dir.path()); } } const QStringList &segments = dir.entryList(); const QRegExp rxTileName("([EW])(\\d{1,3})_([NS])(\\d{1,3})\\.rd5$"); for (const QString &segment : segments) { if (rxTileName.indexIn(segment) > -1) { const QPoint& tile = tileFromFileName(segment); if (tile != noTile) { CRouterBRouterTilesStatus * status = getTileStatus(tile); const QFileInfo &info = QFileInfo(dir,segment); status->localDate = info.created(); status->localSize = info.size(); status->isLocal = true; } } } clearError(); initialized = true; tilesWebPage->mainFrame()->load(QUrl(setup->segmentsUrl)); } catch (const QString &msg) { error(msg); } update(); emit sigCompleteChanged(); } void CRouterBRouterTilesSelect::slotLoadOnlineTilesRequestFinished(bool ok) { try { if (!ok) { throw tr("Network Error"); } else { const QWebElement &htmlElement = tilesWebPage->mainFrame()->documentElement(); const QWebElementCollection &anchorElements = htmlElement.findAll("table tr td a"); if (anchorElements.count() == 0) { throw tr("invalid result, no files found"); } // 'E10_N20.rd5' const QRegExp rxTileName("([EW])(\\d{1,3})_([NS])(\\d{1,3})\\.rd5"); // '16-Feb-2017 20:48 ' // const QString dateFormat = "d-MMM-yyyy H:mm"; // QDateFormat conversion depends on user-locale, doesn't work here const QRegExp rxDate("(\\d{1,2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\\d{4}) (\\d{1,2}):(\\d{2})"); // 8.2M 271K 9.3K const QRegExp rxSize(" {0,2}(\\d{1,3}|\\d\\.\\d)([KMG])"); for (const QWebElement &anchorElement : anchorElements) { const QString &tileName = anchorElement.toPlainText(); //only anchors matching the desired pattern if (rxTileName.indexIn(tileName) > -1) { const QWebElement &dateElement = anchorElement.parent().nextSibling(); const QWebElement &sizeElement = dateElement.nextSibling(); const QPoint &tile = tileFromFileName(tileName); if (tile != noTile) { CRouterBRouterTilesStatus * status = getTileStatus(tile); if (status != nullptr) { status->isRemote = true; const QString &date = dateElement.toPlainText(); if (rxDate.indexIn(date) < 0) { throw tr("cannot parse: %1 is not a date").arg(date); } int day = rxDate.cap(1).toInt(); const QString &monthStr = rxDate.cap(2); int month = monthStr == "Jan" ? 1 : monthStr == "Feb" ? 2 : monthStr == "Mar" ? 3 : monthStr == "Apr" ? 4 : monthStr == "May" ? 5 : monthStr == "Jun" ? 6 : monthStr == "Jul" ? 7 : monthStr == "Aug" ? 8 : monthStr == "Sep" ? 9 : monthStr == "Oct" ? 10 : monthStr == "Nov" ? 11 : 12; int year = rxDate.cap(3).toInt(); int hour = rxDate.cap(4).toInt(); int min = rxDate.cap(5).toInt(); status->remoteDate = QDateTime(QDate(year,month,day),QTime(hour,min,0)); const QString &size = sizeElement.toPlainText(); if (rxSize.indexIn(size) < 0) { throw tr("cannot parse: %1 is not a valid size").arg(size); } status->remoteSize = rxSize.cap(1).toFloat() * (rxSize.cap(2) == "M" ? 1048576 : rxSize.cap(2) == "G" ? 1073741824 : rxSize.cap(2) == "K" ? 1024 : 1); if (status->isLocal && status->remoteDate > status->localDate) { status->isOutdated = true; } } } } } } clearError(); } catch (const QString &msg) { error(tr("Error retrieving available routing data from %1: %2").arg(setup->segmentsUrl).arg(msg)); } update(); } QString CRouterBRouterTilesSelect::formatSize(const qint64 size) { if (size >= 2147483648) { return QString("%1G").arg(size/1073741824); } else if (size >= 1073741824) { return QString("%1G").arg(qreal(size/107374182)/10); } else if (size >= 2097152) { return QString("%1M").arg(size/1048576); } else if (size >= 1048576) { return QString("%1M").arg(qreal(size/104858)/10); } else if (size >= 2048) { return QString("%1K").arg(size/1024); } else if (size >= 1000) { return QString("%1K").arg(qreal(size/102)/10); } else { return QString("%1").arg(size); } } QPoint CRouterBRouterTilesSelect::tileFromFileName(const QString &fileName) { // 'E10_N20.rd5' const QRegExp rxTileName("([EW])(\\d{1,3})_([NS])(\\d{1,3})\\.rd5"); if (rxTileName.indexIn(fileName) > -1) { return QPoint(rxTileName.cap(2).toInt() * (rxTileName.cap(1) == "E" ? 1 : -1) ,rxTileName.cap(4).toInt() * (rxTileName.cap(3) == "N" ? 1 : -1)); } else { return noTile; } } QString CRouterBRouterTilesSelect::fileNameFromTile(const QPoint tile) { return QString("%1%2_%3%4.rd5").arg(tile.x()<0 ? "W" : "E") .arg(abs(tile.x())) .arg(tile.y()<0 ? "S" : "N") .arg(abs(tile.y())); } QDir CRouterBRouterTilesSelect::segmentsDir() const { return QDir(QDir(setup->localDir).absoluteFilePath(setup->localSegmentsDir)); } void CRouterBRouterTilesSelect::slotDownload() { bool changed(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { CRouterBRouterTilesStatus * status = it.value(); if (status->isSelected && (status->isOutdated || !status->isLocal) && status->file == nullptr) { const QString &fileName = it.key(); const QDir &dir = segmentsDir(); if (!dir.exists()) { error(tr("segments directory does not exist: ").arg(dir.path())); break; } status->isSelected = false; changed = true; status->file = new QFile(dir.absoluteFilePath(fileName+".tmp")); if (!status->file->open(QIODevice::WriteOnly)) { const QString tmpName = status->file->fileName(); const QString tmpError = status->file->errorString(); delete status->file; status->file = nullptr; error(tr("error creating file %1: %2").arg(tmpName).arg(tmpError)); break; } QNetworkReply* reply = tilesDownloadManager->get(QNetworkRequest(QUrl(setup->segmentsUrl + fileName))); reply->setProperty("tile", fileName); tilesDownloadManagerReplies << reply; connect(reply, &QNetworkReply::downloadProgress, status, &CRouterBRouterTilesStatus::slotUpdateProgress); connect(reply, &QNetworkReply::readyRead, this, &CRouterBRouterTilesSelect::slotDownloadReadReady); } } if (changed) { update(); } } void CRouterBRouterTilesSelect::slotDownloadReadReady() { for (QNetworkReply * reply : tilesDownloadManagerReplies) { if (reply->bytesAvailable() > 0) { try { const QString &fileName = reply->property("tile").toString(); QHash::const_iterator it = tilesDownloadStatus.constFind(fileName); if (it == tilesDownloadStatus.constEnd()) { throw tr("no valid request for filename %1").arg(fileName); } CRouterBRouterTilesStatus * status = it.value(); if (status->file == nullptr) { throw tr("no open file assigned to request for %1").arg(fileName); } if (status->file->write(reply->readAll()) < 0) { QString tmpName = status->file->fileName(); QString msg = status->file->errorString(); status->file->close(); status->file->remove(); delete status->file; status->file = nullptr; throw tr("error writing to file %1: %2").arg(tmpName).arg(msg); } } catch (const QString &msg) { reply->abort(); error(msg); } } } updateStatus(); } void CRouterBRouterTilesSelect::slotDownloadFinished(QNetworkReply* reply) { if (tilesDownloadManagerReplies.contains(reply)) { tilesDownloadManagerReplies.remove(tilesDownloadManagerReplies.indexOf(reply)); } reply->deleteLater(); const QString &fileName = reply->property("tile").toString(); QHash::const_iterator it = tilesDownloadStatus.constFind(fileName); if (it == tilesDownloadStatus.constEnd()) { error(tr("no valid request for filename %1").arg(fileName)); } else { CRouterBRouterTilesStatus * status = it.value(); status->isLocal = false; if (status->file == nullptr) { error(tr("no open file assigned to request for %1").arg(fileName)); } else { if(reply->error() != QNetworkReply::NoError) { error(fileName + ": "+reply->errorString()); } else if (status->file->write(reply->readAll()) < 0) { error(tr("error writing to file %1: %2") .arg(status->file->fileName()) .arg(status->file->errorString())); status->file->close(); status->file->remove(); } else { const QString &finalName = segmentsDir().absoluteFilePath(it.key()); QFile oldFile(finalName); if (oldFile.exists()) { oldFile.remove(); } if (status->file->rename(finalName)) { status->isLocal = true; status->isOutdated = false; status->file->close(); QFileInfo info(*status->file); status->localDate = info.created(); status->localSize = info.size(); clearError(); } else { error(tr("error renaming file %1 to %2: %3") .arg(status->file->fileName()) .arg(finalName) .arg(status->file->errorString())); status->file->close(); status->file->remove(); } } delete status->file; status->file = nullptr; } } update(); } void CRouterBRouterTilesSelect::cancelDownload() const { for (QNetworkReply * reply : tilesDownloadManagerReplies) { reply->abort(); } } void CRouterBRouterTilesSelect::update() { updateButtons(); updateStatus(); updateTiles(); } void CRouterBRouterTilesSelect::updateStatus() { int numCurrent(0); int sizeCurrent(0); int numOutdated(0); int sizeOutdated(0); int numOutstanding(0); int sizeDownloadMax(0); int sizeOutstanding(0); int sizeDownloaded(0); bool downloading(false); for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { const CRouterBRouterTilesStatus * status = it.value(); if (status->file != nullptr && status->progressMax > 0) { numOutstanding++; sizeDownloadMax += status->progressMax; sizeOutstanding += status->progressMax - status->progressVal; sizeDownloaded += status->progressVal; downloading = true; } else if (status->isSelected && status->isRemote && (!status->isLocal || status->isOutdated)) { numOutstanding++; sizeOutstanding += status->remoteSize; } if (status->isOutdated) { numOutdated++; sizeOutdated += status->localSize; } else if (status->isLocal) { numCurrent++; sizeCurrent += status->localSize; } } statusLabel->setText(QString(tr("up-to-date: %1 (%2), outdated: %3 (%4), to be downloaded: %5 (%6)")) .arg(numCurrent).arg(formatSize(sizeCurrent)) .arg(numOutdated).arg(formatSize(sizeOutdated)) .arg(numOutstanding).arg(formatSize(sizeOutstanding))); statusProgress->setVisible(downloading); statusProgress->setRange(0,sizeDownloadMax); statusProgress->setValue(sizeDownloaded); if (this->downloading != downloading || (numOutstanding > 0) != downloadSelected) { this->downloading = downloading; downloadSelected = numOutstanding > 0; emit sigCompleteChanged(); } } void CRouterBRouterTilesSelect::error(const QString &error) const { errorLabel->setText(error); errorLabel->setVisible(true); } void CRouterBRouterTilesSelect::clearError() const { errorLabel->setVisible(false); } CRouterBRouterTilesStatus * CRouterBRouterTilesSelect::getTileStatus(QPoint tile) const { QHash::const_iterator it = tilesDownloadStatus.constFind(fileNameFromTile(tile)); if (it != tilesDownloadStatus.constEnd()) { return it.value(); } return nullptr; } void CRouterBRouterTilesSelect::updateTiles() const { QVector gridTiles; QVector invalidTiles; QVector outdatedTiles; QVector currentTiles; QVector outstandingTiles; QVector selectedTiles; for (QHash::const_iterator it = tilesDownloadStatus.constBegin(); it != tilesDownloadStatus.constEnd(); ++it) { const QPoint& tile = tileFromFileName(it.key()); Q_ASSERT(tile != noTile); const CRouterBRouterTilesStatus * status = it.value(); if (status->file != nullptr) { outstandingTiles << tile; } else if (status->isSelected) { selectedTiles << tile; } else if (status->isLocal) { if (status->isOutdated) { outdatedTiles << tile; } else { currentTiles << tile; } } else if (status->isRemote) { gridTiles << tile; } else { invalidTiles << tile; } } selectArea->setGridTiles(gridTiles); selectArea->setInvalidTiles(invalidTiles); selectArea->setOutdatedTiles(outdatedTiles); selectArea->setCurrentTiles(currentTiles); selectArea->setOutstandingTiles(outstandingTiles); selectArea->setSelectedTiles(selectedTiles); selectArea->update(); } void CRouterBRouterTilesSelect::slotTileToolTipChanged(const QPoint &tile) const { const CRouterBRouterTilesStatus * status = getTileStatus(tile); if (status->file != nullptr) { selectArea->setTileToolTip(QString(tr("being downloaded: %1 of %2")) .arg(formatSize(status->progressVal)) .arg(formatSize(status->progressMax))); } else if (status->isOutdated) { selectArea->setTileToolTip(QString(tr("local data outdated (%1, %2 - remote %3, %4)")) .arg(formatSize(status->localSize)) .arg(status->localDate.toString(Qt::DefaultLocaleShortDate)) .arg(formatSize(status->remoteSize)) .arg(status->remoteDate.toString(Qt::DefaultLocaleShortDate))); } else if (status->isLocal) { selectArea->setTileToolTip(QString(tr("local data up to date (%1, %2)")) .arg(formatSize(status->localSize)) .arg(status->localDate.toString(Qt::DefaultLocaleShortDate))); } else if (status->isRemote) { selectArea->setTileToolTip(QString(tr("no local data, online available: %1 (%2)")) .arg(formatSize(status->remoteSize)) .arg(status->remoteDate.toString(Qt::DefaultLocaleShortDate))); } else { selectArea->setTileToolTip(tr("no routing-data available")); } } qmapshack-1.10.0/src/gis/rte/router/CRouterSetup.cpp000644 001750 000144 00000005630 13216234140 023515 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/router/CRouterBRouter.h" #include "gis/rte/router/CRouterMapQuest.h" #include "gis/rte/router/CRouterRoutino.h" #include "gis/rte/router/CRouterSetup.h" #include "helpers/CSettings.h" #include CRouterSetup * CRouterSetup::pSelf = nullptr; CRouterSetup::CRouterSetup(QWidget * parent) : QWidget(parent) { setupUi(this); pSelf = this; comboRouter->addItem(tr("Routino (offline)")); comboRouter->addItem(tr("MapQuest (online)")); comboRouter->addItem(tr("BRouter (online)")); stackedWidget->addWidget(new CRouterRoutino(this)); stackedWidget->addWidget(new CRouterMapQuest(this)); stackedWidget->addWidget(new CRouterBRouter(this)); connect(comboRouter, static_cast(&QComboBox::currentIndexChanged), this, &CRouterSetup::slotSelectRouter); SETTINGS; comboRouter->setCurrentIndex(cfg.value("Route/current",0).toInt()); } CRouterSetup::~CRouterSetup() { SETTINGS; cfg.setValue("Route/current", comboRouter->currentIndex()); } bool CRouterSetup::hasFastRouting() { IRouter * router = dynamic_cast(stackedWidget->currentWidget()); if(router) { return router->hasFastRouting(); } return false; } void CRouterSetup::slotSelectRouter(int i) { stackedWidget->setCurrentIndex(i); } void CRouterSetup::calcRoute(const IGisItem::key_t& key) { IRouter * router = dynamic_cast(stackedWidget->currentWidget()); if(router) { router->calcRoute(key); } } int CRouterSetup::calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) { IRouter * router = dynamic_cast(stackedWidget->currentWidget()); if(router) { return router->calcRoute(p1, p2, coords); } return false; } void CRouterSetup::setRouterTitle(const router_e router, const QString title) { comboRouter->setItemText(router,title); } qmapshack-1.10.0/src/gis/rte/router/CRouterMapQuest.h000644 001750 000144 00000003465 13216234143 023630 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CROUTERMAPQUEST_H #define CROUTERMAPQUEST_H #include "gis/rte/router/IRouter.h" #include "ui_IRouterMapQuest.h" class QNetworkAccessManager; class CGisItemRte; class QNetworkReply; class QTimer; class CRouterMapQuest : public IRouter, private Ui::IRouterMapQuest { Q_OBJECT public: CRouterMapQuest(QWidget * parent); virtual ~CRouterMapQuest(); void calcRoute(const IGisItem::key_t& key) override; int calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) override { return -1; } QString getOptions() override; private slots: void slotRequestFinished(QNetworkReply* reply); void slotCloseStatusMsg(); private: void addMapQuestLocations(QDomDocument& xml, QDomElement& locations, CGisItemRte& rte); static const QByteArray keyMapQuest; QNetworkAccessManager * networkAccessManager; QTimer * timerCloseStatusMsg; }; #endif //CROUTERMAPQUEST_H qmapshack-1.10.0/src/gis/rte/router/IRouter.cpp000644 001750 000144 00000002067 13216234140 022503 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/rte/router/IRouter.h" IRouter::IRouter(bool fastRouting, QWidget *parent) : QWidget(parent) , fastRouting(fastRouting) { } IRouter::~IRouter() { } qmapshack-1.10.0/src/gis/rte/CCreateRouteFromWpt.cpp000644 001750 000144 00000007457 13216234140 023446 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/CGisWorkspace.h" #include "gis/CGisWorkspace.h" #include "gis/IGisLine.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CCreateRouteFromWpt.h" #include "gis/rte/CGisItemRte.h" #include "gis/wpt/CGisItemWpt.h" #include #include CCreateRouteFromWpt::CCreateRouteFromWpt(const QList &keys, QWidget *parent) : QDialog(parent) { setupUi(this); for(const IGisItem::key_t& key : keys) { CGisItemWpt *wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr == wpt) { continue; } QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(wpt->getName()); item->setIcon(wpt->getIcon()); item->setToolTip(wpt->getInfo(IGisItem::eFeatureShowName)); item->setData(Qt::UserRole + 0, QPointF(wpt->getPosition()*DEG_TO_RAD)); } connect(listWidget, &QListWidget::itemSelectionChanged, this, &CCreateRouteFromWpt::slotSelectionChanged); connect(toolUp, &QToolButton::clicked, this, &CCreateRouteFromWpt::slotUp); connect(toolDown, &QToolButton::clicked, this, &CCreateRouteFromWpt::slotDown); } CCreateRouteFromWpt::~CCreateRouteFromWpt() { } void CCreateRouteFromWpt::accept() { QDialog::accept(); QString name; IGisProject *project = nullptr; if(!IGisItem::getNameAndProject(name, project, tr("route"))) { return; } SGisLine points; for(int i = 0; i < listWidget->count(); i++) { QListWidgetItem * item = listWidget->item(i); points << IGisLine::point_t(item->data(Qt::UserRole + 0).toPointF(),item->text()); } CGisItemRte* rte = new CGisItemRte(points,name, project, NOIDX); rte->calc(); } void CCreateRouteFromWpt::slotSelectionChanged() { QListWidgetItem * item = listWidget->currentItem(); if(item != nullptr) { int row = listWidget->row(item); toolUp->setEnabled(row != 0); toolDown->setEnabled(row != (listWidget->count() - 1)); } else { toolUp->setEnabled(false); toolDown->setEnabled(false); } } void CCreateRouteFromWpt::slotUp() { QListWidgetItem * item = listWidget->currentItem(); if(item) { int row = listWidget->row(item); if(row == 0) { return; } listWidget->takeItem(row); row = row - 1; listWidget->insertItem(row,item); listWidget->setCurrentItem(item); } } void CCreateRouteFromWpt::slotDown() { QListWidgetItem * item = listWidget->currentItem(); if(item) { int row = listWidget->row(item); if(row == (listWidget->count() - 1)) { return; } listWidget->takeItem(row); row = row + 1; listWidget->insertItem(row,item); listWidget->setCurrentItem(item); } } qmapshack-1.10.0/src/gis/rte/IDetailsRte.ui000644 001750 000144 00000020014 13035437317 021600 0ustar00oeichlerxusers000000 000000 IDetailsRte 0 0 400 400 3 3 3 3 3 0 Info 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 true false 0 0 0 0 25 25 The route was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. :/icons/32x32/Tainted.png true Toggle read only mode. You have to open the lock to edit the item. ... :/icons/32x32/UnLock.png :/icons/32x32/Lock.png:/icons/32x32/UnLock.png 22 22 true true 0 0 - Qt::AlignJustify|Qt::AlignTop 0 0 false Hist. 0 0 0 0 0 CHistoryListWidget QListWidget
widgets/CHistoryListWidget.h
CLineEdit QLineEdit
widgets/CLineEdit.h
qmapshack-1.10.0/src/gis/rte/CScrOptRte.cpp000644 001750 000144 00000010202 13216234140 021550 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "gis/rte/CScrOptRte.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" CScrOptRte::CScrOptRte(CGisItemRte *rte, const QPoint& point, IMouse *parent) : IScrOpt(parent) , key(rte->getKey()) { setupUi(this); setOrigin(point); label->setFont(CMainWindow::self().getMapFont()); label->setText(rte->getInfo(IGisItem::eFeatureShowName)); adjustSize(); toolInstruction->setEnabled(rte->isCalculated()); toolInstruction->setChecked(rte->hasUserFocus()); bool isOnDevice = rte->isOnDevice(); toolEdit->setDisabled(isOnDevice); anchor = rte->getPointCloseBy(point); if((anchor - point).manhattanLength() > 50) { anchor = point; } move(anchor.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolDelete, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolCopy, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolCalc, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolReset, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolEdit, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolInstruction, &QToolButton::toggled, this, &CScrOptRte::hide); connect(toolToTrack, &QToolButton::clicked, this, &CScrOptRte::hide); connect(toolEditDetails, &QToolButton::clicked, this, &CScrOptRte::slotEditDetails); connect(toolDelete, &QToolButton::clicked, this, &CScrOptRte::slotDelete); connect(toolCopy, &QToolButton::clicked, this, &CScrOptRte::slotCopy); connect(toolCalc, &QToolButton::clicked, this, &CScrOptRte::slotCalc); connect(toolReset, &QToolButton::clicked, this, &CScrOptRte::slotReset); connect(toolEdit, &QToolButton::clicked, this, &CScrOptRte::slotEdit); connect(toolInstruction, &QToolButton::toggled, this, &CScrOptRte::slotInstruction); connect(toolToTrack, &QToolButton::clicked, this, &CScrOptRte::slotToTrack); } CScrOptRte::~CScrOptRte() { } void CScrOptRte::slotEditDetails() { CGisWorkspace::self().editItemByKey(key); deleteLater(); } void CScrOptRte::slotDelete() { CGisWorkspace::self().delItemByKey(key); deleteLater(); } void CScrOptRte::slotCopy() { CGisWorkspace::self().copyItemByKey(key); deleteLater(); } void CScrOptRte::slotCalc() { CGisWorkspace::self().calcRteByKey(key); deleteLater(); } void CScrOptRte::slotReset() { CGisWorkspace::self().resetRteByKey(key); deleteLater(); } void CScrOptRte::slotEdit() { CGisWorkspace::self().editRteByKey(key); deleteLater(); } void CScrOptRte::slotInstruction(bool on) { CGisWorkspace::self().focusRteByKey(on, key); deleteLater(); } void CScrOptRte::slotToTrack() { CGisWorkspace::self().convertRouteToTrack(key); deleteLater(); } void CScrOptRte::draw(QPainter& p) { IGisItem *item = CGisWorkspace::self().getItemByKey(key); if(nullptr == item) { QWidget::deleteLater(); return; } item->drawHighlight(p); CDraw::bubble(p, geometry(), anchor.toPoint()); } qmapshack-1.10.0/src/gis/rte/IScrOptRte.ui000644 001750 000144 00000012706 12727447634 021450 0ustar00oeichlerxusers000000 000000 IScrOptRte 0 0 400 69 Form 3 3 3 3 3 3 View details and edit. ... :/icons/32x32/EditDetails.png:/icons/32x32/EditDetails.png Copy route into another project. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png Delete route from project. ... :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png Qt::Vertical ... :/icons/32x32/RteInstr.png:/icons/32x32/RteInstr.png true Calculate route. ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png Reset route calculation. ... :/icons/32x32/Reset.png:/icons/32x32/Reset.png Move route points. ... :/icons/32x32/LineMove.png:/icons/32x32/LineMove.png Convert route to track ... :/icons/32x32/Track.png:/icons/32x32/Track.png Qt::Horizontal 40 20 TextLabel Qt::AutoText Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse qmapshack-1.10.0/src/gis/rte/CDetailsRte.h000644 001750 000144 00000002715 13216234143 021405 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDETAILSRTE_H #define CDETAILSRTE_H #include "ui_IDetailsRte.h" #include class CGisItemRte; class CDetailsRte : public QDialog, private Ui::IDetailsRte { Q_OBJECT public: CDetailsRte(CGisItemRte& rte, QWidget * parent); virtual ~CDetailsRte(); private slots: void slotNameChanged(const QString &name); void slotNameChangeFinished(); void slotChangeReadOnlyMode(bool on); void slotLinkActivated(const QUrl& url); void setupGui(); private: CGisItemRte& rte; bool originator = false; }; #endif //CDETAILSRTE_H qmapshack-1.10.0/src/gis/rte/CDetailsRte.cpp000644 001750 000144 00000011113 13216234140 021725 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/rte/CDetailsRte.h" #include "gis/rte/CGisItemRte.h" #include "helpers/CLinksDialog.h" #include "units/IUnit.h" #include "widgets/CTextEditWidget.h" #include CDetailsRte::CDetailsRte(CGisItemRte& rte, QWidget *parent) : QDialog(parent) , rte(rte) { setupUi(this); setupGui(); if(rte.isOnDevice()) { toolLock->setDisabled(true); } connect(lineName, &CLineEdit::textEdited, this, &CDetailsRte::slotNameChanged); connect(lineName, &CLineEdit::editingFinished, this, &CDetailsRte::slotNameChangeFinished); connect(toolLock, &QToolButton::toggled, this, &CDetailsRte::slotChangeReadOnlyMode); connect(textCmtDesc, &QTextBrowser::anchorClicked, this, static_cast(&CDetailsRte::slotLinkActivated)); connect(listHistory, &CHistoryListWidget::sigChanged, this, &CDetailsRte::setupGui); } CDetailsRte::~CDetailsRte() { } void CDetailsRte::setupGui() { if(originator) { return; } originator = true; bool isReadOnly = rte.isReadOnly(); setWindowTitle(rte.getName()); labelTainted->setVisible(rte.isTainted()); lineName->setText(rte.getName()); lineName->setReadOnly(isReadOnly); labelInfo->setText(rte.getInfo(IGisItem::eFeatureNone)); textCmtDesc->document()->clear(); textCmtDesc->append(IGisItem::createText(isReadOnly, rte.getComment(), rte.getDescription(), rte.getLinks())); textCmtDesc->moveCursor (QTextCursor::Start); textCmtDesc->ensureCursorVisible(); // treeWidget->clear(); // QString val, unit; // for(const CGisItemRte::rtept_t& rtept : rte.getRoute().pts) // { // QTreeWidgetItem * item = new QTreeWidgetItem(treeWidget); // item->setText(0, tr("Route waypoint")); // for(const CGisItemRte::subpt_t& subpt : rtept.subpts) // { // if(subpt.type != CGisItemRte::subpt_t::eTypeJunct) // { // continue; // } // QTreeWidgetItem * item = new QTreeWidgetItem(treeWidget); // IUnit::self().meter2distance(subpt.distance, val, unit); // QString str = QString("Time: %1 Dist.: %2 %3").arg(subpt.time.toString()).arg(val).arg(unit); // str += "\n" + subpt.instruction; // item->setText(0,str); // } // } toolLock->setChecked(isReadOnly); listHistory->setupHistory(rte); originator = false; } void CDetailsRte::slotChangeReadOnlyMode(bool on) { rte.setReadOnlyMode(on); setupGui(); } void CDetailsRte::slotNameChanged(const QString &name) { setWindowTitle(name); } void CDetailsRte::slotNameChangeFinished() { lineName->clearFocus(); const QString& name = lineName->text(); slotNameChanged(name); if(name != rte.getName()) { rte.setName(name); setupGui(); } } void CDetailsRte::slotLinkActivated(const QUrl& url) { if(url.toString() == "comment") { CTextEditWidget dlg(rte.getComment(), nullptr); if(dlg.exec() == QDialog::Accepted) { rte.setComment(dlg.getHtml()); } setupGui(); } else if(url.toString() == "description") { CTextEditWidget dlg(rte.getDescription(), nullptr); if(dlg.exec() == QDialog::Accepted) { rte.setDescription(dlg.getHtml()); } setupGui(); } else if(url.toString() == "links") { QList links = rte.getLinks(); CLinksDialog dlg(links, this); if(dlg.exec() == QDialog::Accepted) { rte.setLinks(links); } setupGui(); } else { QDesktopServices::openUrl(url); } } qmapshack-1.10.0/src/gis/IGisLine.h000644 001750 000144 00000003737 13216234143 020120 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IGISLINE_H #define IGISLINE_H #include "units/IUnit.h" #include #include class QPolygonF; class CGisDraw; class CDemDraw; struct SGisLine; class IGisLine { public: IGisLine() = default; virtual ~IGisLine() = default; struct subpt_t { subpt_t() = default; subpt_t(const QPointF& pt) : coord(pt) {} subpt_t(const QPointF& pt, const QString &name) : coord(pt), name(name) {} QPointF coord; QPointF pixel; QString name; qint32 ele = NOINT; }; struct point_t : public subpt_t { point_t() = default; point_t(const QPointF &pt) : subpt_t(pt) {} point_t(const QPointF &pt, const QString &name) : subpt_t(pt, name) {} void resetElevation(); QVector subpts; }; virtual void setDataFromPolyline(const SGisLine& line) = 0; virtual void getPolylineFromData(SGisLine& line) = 0; }; struct SGisLine : public QVector { void updateElevation(CDemDraw * dem); void updatePixel(CGisDraw * gis); }; #endif //IGISLINE_H qmapshack-1.10.0/src/gis/gpx/000755 001750 000144 00000000000 13216664445 017104 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/gpx/serialization.cpp000644 001750 000144 00000111351 13216234140 022450 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "device/CDeviceGarmin.h" #include "gis/WptIcons.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/wpt/CGisItemWpt.h" #include "version.h" #include #include const QString IGisProject::gpx_ns = "http://www.topografix.com/GPX/1/1"; const QString IGisProject::xsi_ns = "http://www.w3.org/2001/XMLSchema-instance"; const QString IGisProject::gpxx_ns = "http://www.garmin.com/xmlschemas/GpxExtensions/v3"; const QString IGisProject::gpxtpx_ns = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1"; const QString IGisProject::wptx1_ns = "http://www.garmin.com/xmlschemas/WaypointExtension/v1"; const QString IGisProject::rmc_ns = "urn:net:trekbuddy:1.0:nmea:rmc"; const QString IGisProject::ql_ns = "http://www.qlandkarte.org/xmlschemas/v1.1"; const QString IGisProject::gs_ns = "http://www.groundspeak.com/cache/1/0"; const QString IGisProject::tp1_ns = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1"; const QString IGisProject::gpxdata_ns= "http://www.cluetrust.com/XML/GPXDATA/1/0"; static void readXml(const QDomNode& xml, const QString& tag, qint32& value) { if(xml.namedItem(tag).isElement()) { bool ok = false; qint32 tmp = xml.namedItem(tag).toElement().text().toInt(&ok); if(!ok) { tmp = qRound(xml.namedItem(tag).toElement().text().toDouble(&ok)); } if(ok) { value = tmp; } } } template static void readXml(const QDomNode& xml, const QString& tag, T& value) { if(xml.namedItem(tag).isElement()) { bool ok = false; T tmp; if(std::is_same::value) { tmp = xml.namedItem(tag).toElement().text().toUInt(&ok); } else if(std::is_same::value) { tmp = xml.namedItem(tag).toElement().text().toULongLong(&ok); } else if(std::is_same::value) { tmp = xml.namedItem(tag).toElement().text().toDouble(&ok); } else if(std::is_same::value) { tmp = xml.namedItem(tag).toElement().text().toInt(&ok); } if(ok) { value = tmp; } } } static void readXml(const QDomNode& xml, const QString& tag, QString& value) { if(xml.namedItem(tag).isElement()) { value = xml.namedItem(tag).toElement().text(); } } static void readXml(const QDomNode& xml, const QString& tag, QString& value, bool& isHtml) { if(xml.namedItem(tag).isElement()) { const QDomNamedNodeMap& attr = xml.namedItem(tag).toElement().attributes(); isHtml = (attr.namedItem("html").nodeValue().toLocal8Bit().toLower() == "true"); value = xml.namedItem(tag).toElement().text(); } } static void readXml(const QDomNode& xml, const QString& tag, QDateTime& value) { if(xml.namedItem(tag).isElement()) { QString time = xml.namedItem(tag).toElement().text(); IUnit::parseTimestamp(time, value); } } static void readXml(const QDomNode& xml, const QString& tag, QList& l) { if(xml.namedItem(tag).isElement()) { const QDomNodeList& links = xml.toElement().elementsByTagName(tag); int N = links.count(); for(int n = 0; n < N; ++n) { const QDomNode& link = links.item(n); IGisItem::link_t tmp; tmp.uri.setUrl(link.attributes().namedItem("href").nodeValue()); readXml(link, "text", tmp.text); readXml(link, "type", tmp.type); l << tmp; } } } static void readXml(const QDomNode& xml, IGisItem::history_t& history) { if(xml.namedItem("ql:history").isElement()) { const QDomElement& xmlHistory = xml.namedItem("ql:history").toElement(); const QDomNodeList& xmlEntries = xmlHistory.elementsByTagName("ql:event"); for(int n = 0; n < xmlEntries.count(); ++n) { const QDomNode& xmlEntry = xmlEntries.item(n); IGisItem::history_event_t entry; readXml(xmlEntry, "ql:icon", entry.icon); readXml(xmlEntry, "ql:time", entry.time); readXml(xmlEntry, "ql:comment", entry.comment); history.events << entry; } history.histIdxInitial = history.events.size() - 1; history.histIdxCurrent = history.histIdxInitial; } } static void readXml(const QDomNode& xml, const QString& tag, QPoint& offsetBubble, quint32& widthBubble) { if(xml.namedItem(tag).isElement()) { const QDomElement& xmlBubble = xml.namedItem(tag).toElement(); int x = xmlBubble.attributes().namedItem("xoff").nodeValue().toInt(); int y = xmlBubble.attributes().namedItem("yoff").nodeValue().toInt(); offsetBubble = QPoint(x,y); widthBubble = xmlBubble.attributes().namedItem("width").nodeValue().toInt(); } } static void writeXml(QDomNode& xml, const QString& tag, qint32 val) { if(val != NOINT) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(QString::number(val)); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, quint32 val) { if(val != NOINT) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(QString::number(val)); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, quint64 val) { if(val != 0) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(QString::number(val)); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, const QString& val) { if(!val.isEmpty()) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(val); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, qreal val) { if(val != NOFLOAT) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(QString("%1").arg(val,0,'f',8)); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, const QString& val, bool isHtml) { if(!val.isEmpty()) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createCDATASection(val); elem.appendChild(text); elem.setAttribute("html", isHtml ? "True" : "False"); } } static void writeXml(QDomNode& xml, const QString& tag, const QDateTime& time) { if(time.isValid()) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); QDomText text = xml.ownerDocument().createTextNode(time.toString("yyyy-MM-dd'T'hh:mm:ss.zzz'Z'")); elem.appendChild(text); } } static void writeXml(QDomNode& xml, const QString& tag, const QList& links) { if(!links.isEmpty()) { for(const IGisItem::link_t& link : links) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); elem.setAttribute("href", link.uri.toString()); writeXml(elem, "text", link.text); writeXml(elem, "type", link.type); } } } static void writeXml(QDomNode& xml, const IGisItem::history_t& history) { if(history.events.size() > 1) { QDomElement xmlHistory = xml.ownerDocument().createElement("ql:history"); xml.appendChild(xmlHistory); for(int i = 0; i <= history.histIdxCurrent; i++) { const IGisItem::history_event_t& event = history.events[i]; QDomElement xmlEvent = xml.ownerDocument().createElement("ql:event"); xmlHistory.appendChild(xmlEvent); writeXml(xmlEvent,"ql:icon", event.icon); writeXml(xmlEvent,"ql:time", event.time); writeXml(xmlEvent,"ql:comment", event.comment); } } } static void writeXml(QDomNode& xml, const QString& tag, const QPoint& offsetBubble, quint32 widthBubble) { QDomElement elem = xml.ownerDocument().createElement(tag); xml.appendChild(elem); elem.setAttribute("xoff", offsetBubble.x()); elem.setAttribute("yoff", offsetBubble.y()); elem.setAttribute("width", widthBubble); } static void readXml(const QDomNode& node, const QString& parentTags, QHash& extensions) { QString tag = node.nodeName(); if(tag.left(8) == "ql:flags") { return; } QString tags = parentTags.isEmpty() ? tag : parentTags + "|" + tag; const QDomNode& next = node.firstChild(); if(next.isText()) { extensions[tags] = node.toElement().text(); } else { const QDomNodeList& list = node.childNodes(); for(int i = 0; i < list.size(); i++) { readXml(list.at(i), tags, extensions); } } } static void readXml(const QDomNode& ext, QHash& extensions) { const QDomNodeList& list = ext.childNodes(); for(int i = 0; i < list.size(); i++) { readXml(list.at(i), "", extensions); } extensions.squeeze(); } static void writeXml(QDomNode& ext, const QHash& extensions) { if(extensions.isEmpty()) { return; } QDomDocument doc = ext.ownerDocument(); QStringList keys = extensions.keys(); qSort(keys.begin(), keys.end(), [] (const QString &k1, const QString &k2) { return CKnownExtension::get(k1).order < CKnownExtension::get(k2).order; }); for(const QString &key : keys) { QStringList tags = key.split('|', QString::SkipEmptyParts); if(tags.size() == 1) { QDomElement elem = doc.createElement(tags.first()); ext.appendChild(elem); QDomText text = doc.createTextNode(extensions[key].toString()); elem.appendChild(text); } else { QDomNode node = ext; QString lastTag = tags.last(); tags.pop_back(); for(const QString &tag : tags) { QDomNode child = node.firstChildElement(tag); if(child.isNull()) { QDomElement elem = doc.createElement(tags.first()); node.appendChild(elem); node = elem; } else { node = child; } } QDomElement elem = doc.createElement(lastTag); node.appendChild(elem); QDomText text = doc.createTextNode(extensions[key].toString()); elem.appendChild(text); } } } void IGisProject::readMetadata(const QDomNode& xml, metadata_t& metadata) { readXml(xml,"name", metadata.name); readXml(xml,"desc", metadata.desc); const QDomNode& xmlAuthor = xml.namedItem("author"); if(xmlAuthor.isElement()) { readXml(xml,"name", metadata.author.name); const QDomNode& xmlEmail = xmlAuthor.namedItem("email"); if(xmlEmail.isElement()) { const QDomNamedNodeMap& attr = xmlEmail.attributes(); metadata.author.id = attr.namedItem("id").nodeValue(); metadata.author.domain = attr.namedItem("domain").nodeValue(); } const QDomNode& xmlLink = xmlAuthor.namedItem("link"); if(xmlLink.isElement()) { metadata.author.link.uri.setUrl(xmlLink.attributes().namedItem("href").nodeValue()); readXml(xmlLink, "text", metadata.author.link.text); readXml(xmlLink, "type", metadata.author.link.type); } } const QDomNode& xmlCopyright = xml.namedItem("copyright"); if(xmlCopyright.isElement()) { metadata.copyright.author = xmlCopyright.attributes().namedItem("author").nodeValue(); readXml(xmlCopyright, "year", metadata.copyright.year); readXml(xmlCopyright, "license", metadata.copyright.license); } readXml(xml,"link", metadata.links); readXml(xml,"time", metadata.time); readXml(xml,"keywords", metadata.keywords); const QDomNode& xmlBounds = xml.namedItem("bounds"); if(xmlBounds.isElement()) { const QDomNamedNodeMap& attr = xmlBounds.attributes(); metadata.bounds.setLeft( attr.namedItem("minlon").nodeValue().toDouble()); metadata.bounds.setTop( attr.namedItem("maxlat").nodeValue().toDouble()); metadata.bounds.setRight( attr.namedItem("maxlon").nodeValue().toDouble()); metadata.bounds.setBottom(attr.namedItem("minlat").nodeValue().toDouble()); } } QDomNode IGisProject::writeMetadata(QDomDocument& doc, bool strictGpx11) { QDomElement gpx = doc.createElement("gpx"); doc.appendChild(gpx); gpx.setAttribute("version","1.1"); gpx.setAttribute("creator","QMapShack " VER_STR " http://www.qlandkarte.org/"); gpx.setAttribute("xmlns", gpx_ns); gpx.setAttribute("xmlns:xsi", xsi_ns); QString schemaLocation; if(!strictGpx11) { gpx.setAttribute("xmlns:gpxx", gpxx_ns); gpx.setAttribute("xmlns:gpxtpx", gpxtpx_ns); gpx.setAttribute("xmlns:wptx1", wptx1_ns); gpx.setAttribute("xmlns:rmc", rmc_ns); gpx.setAttribute("xmlns:ql", ql_ns); gpx.setAttribute("xmlns:tp1", tp1_ns); gpx.setAttribute("xmlns:gpxdata",gpxdata_ns); schemaLocation = QString() + gpx_ns + " http://www.topografix.com/GPX/1/1/gpx.xsd " + gpxx_ns + " http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd " + gpxtpx_ns + " http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd " + wptx1_ns + " http://www.garmin.com/xmlschemas/WaypointExtensionv1.xsd " + ql_ns + " http://www.qlandkarte.org/xmlschemas/v1.1/ql-extensions.xsd " + gpxdata_ns+ " http://www.cluetrust.com/Schemas/gpxdata10.xsd"; } else { schemaLocation = QString() + gpx_ns + " http://www.topografix.com/GPX/1/1/gpx.xsd "; } gpx.setAttribute("xsi:schemaLocation", schemaLocation); QDomElement xmlMetadata = doc.createElement("metadata"); gpx.appendChild(xmlMetadata); writeXml(xmlMetadata,"name", metadata.name); writeXml(xmlMetadata,"desc", html2Dev(metadata.desc)); if(!metadata.author.name.isEmpty()) { QDomElement xmlAuthor = doc.createElement("author"); xmlMetadata.appendChild(xmlAuthor); writeXml(xmlAuthor,"name", metadata.author.name); if(!metadata.author.id.isEmpty() && !metadata.author.domain.isEmpty()) { QDomElement xmlEmail = doc.createElement("email"); xmlAuthor.appendChild(xmlEmail); xmlEmail.setAttribute("id", metadata.author.id); xmlEmail.setAttribute("domain", metadata.author.domain); } if(metadata.author.link.uri.isValid()) { QDomElement xmlLink = doc.createElement("link"); xmlAuthor.appendChild(xmlLink); xmlLink.setAttribute("href", metadata.author.link.uri.toString()); writeXml(xmlLink, "text", metadata.author.link.text); writeXml(xmlLink, "type", metadata.author.link.type); } } if(!metadata.copyright.author.isEmpty()) { QDomElement xmlCopyright = doc.createElement("copyright"); xmlMetadata.appendChild(xmlCopyright); xmlCopyright.setAttribute("author", metadata.copyright.author); writeXml(xmlCopyright, "year", metadata.copyright.year); writeXml(xmlCopyright, "license", metadata.copyright.license); } writeXml(xmlMetadata, "link", metadata.links); writeXml(xmlMetadata, "time", metadata.time); writeXml(xmlMetadata, "keywords", metadata.keywords); if(metadata.bounds.isValid()) { QDomElement xmlBounds = doc.createElement("bounds"); xmlMetadata.appendChild(xmlBounds); xmlBounds.setAttribute("minlat", metadata.bounds.bottom()); xmlBounds.setAttribute("minlon", metadata.bounds.left()); xmlBounds.setAttribute("maxlat", metadata.bounds.top()); xmlBounds.setAttribute("maxlon", metadata.bounds.right()); } return gpx; } void CGisItemWpt::readGpx(const QDomNode& xml) { readWpt(xml, wpt); // decode some well known extensions if(xml.namedItem("extensions").isElement()) { const QDomNode& ext = xml.namedItem("extensions"); readXml(ext, "ql:key", key.item); readXml(ext, "ql:flags", flags); readXml(ext, "ql:bubble", offsetBubble, widthBubble); readXml(ext, history); const QDomNode& wptx1 = ext.namedItem("wptx1:WaypointExtension"); readXml(wptx1, "wptx1:Proximity", proximity); const QDomNode& xmlCache = ext.namedItem("cache"); if(!xmlCache.isNull()) { // read OC cache extensions } } const QDomNode& xmlCache = xml.namedItem("groundspeak:cache"); if(!xmlCache.isNull() && !geocache.hasData) { readGcExt(xmlCache); } } void CGisItemWpt::save(QDomNode& gpx, bool strictGpx11) { QDomDocument doc = gpx.ownerDocument(); QDomElement xmlWpt = doc.createElement("wpt"); gpx.appendChild(xmlWpt); writeWpt(xmlWpt, wpt, strictGpx11); if(!strictGpx11) { // write the key as extension tag QDomElement xmlExt = doc.createElement("extensions"); xmlWpt.appendChild(xmlExt); writeXml(xmlExt, "ql:key", key.item); writeXml(xmlExt, "ql:flags", flags); writeXml(xmlExt, "ql:bubble", offsetBubble, widthBubble); writeXml(xmlExt, history); // write other well known extensions QDomElement wptx1 = doc.createElement("wptx1:WaypointExtension"); xmlExt.appendChild(wptx1); writeXml(wptx1, "wptx1:Proximity", proximity); if(geocache.hasData /*&& geocache.service == eGC*/) { QDomElement xmlCache = doc.createElement("groundspeak:cache"); writeGcExt(xmlCache); xmlWpt.appendChild(xmlCache); } } } void CGisItemWpt::readGcExt(const QDomNode& xmlCache) { geocache.service = eGC; const QDomNamedNodeMap& attr = xmlCache.attributes(); geocache.id = attr.namedItem("id").nodeValue().toInt(); geocache.archived = attr.namedItem("archived").nodeValue().toLocal8Bit() == "True"; geocache.available = attr.namedItem("available").nodeValue().toLocal8Bit() == "True"; if(geocache.archived) { geocache.status = tr("Archived"); } else if(geocache.available) { geocache.status = tr("Available"); } else { geocache.status = tr("Not Available"); } readXml(xmlCache, "groundspeak:name", geocache.name); readXml(xmlCache, "groundspeak:placed_by", geocache.owner); readXml(xmlCache, "groundspeak:type", geocache.type); readXml(xmlCache, "groundspeak:container", geocache.container); readXml(xmlCache, "groundspeak:difficulty", geocache.difficulty); readXml(xmlCache, "groundspeak:terrain", geocache.terrain); readXml(xmlCache, "groundspeak:short_description", geocache.shortDesc, geocache.shortDescIsHtml); readXml(xmlCache, "groundspeak:long_description", geocache.longDesc, geocache.longDescIsHtml); readXml(xmlCache, "groundspeak:encoded_hints", geocache.hint); readXml(xmlCache, "groundspeak:country", geocache.country); readXml(xmlCache, "groundspeak:state", geocache.state); const QDomNodeList& logs = xmlCache.toElement().elementsByTagName("groundspeak:log"); uint N = logs.count(); for(uint n = 0; n < N; ++n) { const QDomNode& xmlLog = logs.item(n); const QDomNamedNodeMap& attr = xmlLog.attributes(); geocachelog_t log; log.id = attr.namedItem("id").nodeValue().toUInt(); readXml(xmlLog, "groundspeak:date", log.date); readXml(xmlLog, "groundspeak:type", log.type); if(xmlLog.namedItem("groundspeak:finder").isElement()) { const QDomNamedNodeMap& attr = xmlLog.namedItem("groundspeak:finder").attributes(); log.finderId = attr.namedItem("id").nodeValue(); } readXml(xmlLog, "groundspeak:finder", log.finder); readXml(xmlLog, "groundspeak:text", log.text, log.textIsHtml); geocache.logs << log; } geocache.hasData = true; } void CGisItemWpt::writeGcExt(QDomNode& xmlCache) { QString str; xmlCache.toElement().setAttribute("xmlns:groundspeak", "http://www.groundspeak.com/cache/1/0"); xmlCache.toElement().setAttribute("id", geocache.id); xmlCache.toElement().setAttribute("archived", geocache.archived ? "True" : "False"); xmlCache.toElement().setAttribute("available", geocache.available ? "True" : "False"); writeXml(xmlCache, "groundspeak:name", geocache.name); writeXml(xmlCache, "groundspeak:placed_by", geocache.owner); writeXml(xmlCache, "groundspeak:type", geocache.type); writeXml(xmlCache, "groundspeak:container", geocache.container); if(geocache.difficulty == int(geocache.difficulty)) { str.sprintf("%1.0f", geocache.difficulty); } else { str.sprintf("%1.1f", geocache.difficulty); } writeXml(xmlCache, "groundspeak:difficulty", str); if(geocache.terrain == int(geocache.terrain)) { str.sprintf("%1.0f", geocache.terrain); } else { str.sprintf("%1.1f", geocache.terrain); } writeXml(xmlCache, "groundspeak:terrain", str); writeXml(xmlCache, "groundspeak:short_description", geocache.shortDesc, geocache.shortDescIsHtml); writeXml(xmlCache, "groundspeak:long_description", geocache.longDesc, geocache.longDescIsHtml); writeXml(xmlCache, "groundspeak:encoded_hints", geocache.hint); if(!geocache.logs.isEmpty()) { QDomElement xmlLogs = xmlCache.ownerDocument().createElement("groundspeak:logs"); xmlCache.appendChild(xmlLogs); for(const geocachelog_t &log : geocache.logs) { QDomElement xmlLog = xmlCache.ownerDocument().createElement("groundspeak:log"); xmlLogs.appendChild(xmlLog); xmlLog.setAttribute("id", log.id); writeXml(xmlLog, "groundspeak:date", log.date); writeXml(xmlLog, "groundspeak:type", log.type); QDomElement xmlFinder = xmlCache.ownerDocument().createElement("groundspeak:finder"); xmlLog.appendChild(xmlFinder); QDomText _finder_ = xmlCache.ownerDocument().createCDATASection(log.finder); xmlFinder.appendChild(_finder_); xmlFinder.setAttribute("id", log.finderId); writeXml(xmlLog, "groundspeak:text", log.text, log.textIsHtml); } } } void CGisItemTrk::readTrk(const QDomNode& xml, CTrackData& trk) { readXml(xml, "name", trk.name); readXml(xml, "cmt", trk.cmt); readXml(xml, "desc", trk.desc); readXml(xml, "src", trk.src); readXml(xml, "link", trk.links); readXml(xml, "number", trk.number); readXml(xml, "type", trk.type); const QDomNodeList& trksegs = xml.toElement().elementsByTagName("trkseg"); int N = trksegs.count(); trk.segs.resize(N); for(int n = 0; n < N; ++n) { const QDomNode& trkseg = trksegs.item(n); CTrackData::trkseg_t& seg = trk.segs[n]; const QDomNodeList& xmlTrkpts = trkseg.toElement().elementsByTagName("trkpt"); int M = xmlTrkpts.count(); seg.pts.resize(M); for(int m = 0; m < M; ++m) { CTrackData::trkpt_t& trkpt = seg.pts[m]; const QDomNode& xmlTrkpt = xmlTrkpts.item(m); readWpt(xmlTrkpt, trkpt); const QDomNode& ext = xmlTrkpt.namedItem("extensions"); if(ext.isElement()) { readXml(ext, "ql:flags", trkpt.flags); readXml(ext, trkpt.extensions); } } } // decode some well known extensions const QDomNode& ext = xml.namedItem("extensions"); if(ext.isElement()) { readXml(ext, "ql:key", key.item); readXml(ext, "ql:flags", flags); readXml(ext, history); const QDomNode& gpxx = ext.namedItem("gpxx:TrackExtension"); readXml(gpxx, "gpxx:DisplayColor", trk.color); setColor(str2color(trk.color)); } deriveSecondaryData(); } void CGisItemTrk::save(QDomNode& gpx, bool strictGpx11) { QDomDocument doc = gpx.ownerDocument(); QDomElement xmlTrk = doc.createElement("trk"); gpx.appendChild(xmlTrk); writeXml(xmlTrk, "name", trk.name); writeXml(xmlTrk, "cmt", html2Dev(trk.cmt, strictGpx11)); writeXml(xmlTrk, "desc", html2Dev(trk.desc, strictGpx11)); writeXml(xmlTrk, "src", trk.src); writeXml(xmlTrk, "link", trk.links); writeXml(xmlTrk, "number", trk.number); writeXml(xmlTrk, "type", trk.type); if(!strictGpx11) { // write the key as extension tag QDomElement xmlExt = doc.createElement("extensions"); xmlTrk.appendChild(xmlExt); writeXml(xmlExt, "ql:key", key.item); writeXml(xmlExt, "ql:flags", flags); writeXml(xmlExt, history); // write other well known extensions QDomElement gpxx = doc.createElement("gpxx:TrackExtension"); xmlExt.appendChild(gpxx); writeXml(gpxx, "gpxx:DisplayColor", trk.color); } for(const CTrackData::trkseg_t &seg : trk.segs) { QDomElement xmlTrkseg = doc.createElement("trkseg"); xmlTrk.appendChild(xmlTrkseg); for(const CTrackData::trkpt_t &pt : seg.pts) { QDomElement xmlTrkpt = doc.createElement("trkpt"); xmlTrkseg.appendChild(xmlTrkpt); writeWpt(xmlTrkpt, pt, strictGpx11); if(!strictGpx11) { QDomElement xmlExt = doc.createElement("extensions"); xmlTrkpt.appendChild(xmlExt); writeXml(xmlExt, "ql:flags", pt.flags); writeXml(xmlExt, pt.extensions); } } } } void CGisItemRte::readRte(const QDomNode& xml, rte_t& rte) { readXml(xml, "name", rte.name); readXml(xml, "cmt", rte.cmt); readXml(xml, "desc", rte.desc); readXml(xml, "src", rte.src); readXml(xml, "link", rte.links); readXml(xml, "number", rte.number); readXml(xml, "type", rte.type); const QDomNodeList& xmlRtepts = xml.toElement().elementsByTagName("rtept"); int M = xmlRtepts.count(); rte.pts.resize(M); for(int m = 0; m < M; ++m) { rtept_t& rtept = rte.pts[m]; const QDomNode& xmlRtept = xmlRtepts.item(m); readWpt(xmlRtept, rtept); rtept.icon = getWptIconByName(rtept.sym, rtept.focus); } // decode some well known extensions if(xml.namedItem("extensions").isElement()) { const QDomNode& ext = xml.namedItem("extensions"); readXml(ext, "ql:key", key.item); } } void CGisItemRte::save(QDomNode& gpx, bool strictGpx11) { QDomDocument doc = gpx.ownerDocument(); QDomElement xmlRte = doc.createElement("rte"); gpx.appendChild(xmlRte); writeXml(xmlRte, "name", rte.name); writeXml(xmlRte, "cmt", html2Dev(rte.cmt, strictGpx11)); writeXml(xmlRte, "desc", html2Dev(rte.desc, strictGpx11)); writeXml(xmlRte, "src", rte.src); writeXml(xmlRte, "link", rte.links); writeXml(xmlRte, "number", rte.number); writeXml(xmlRte, "type", rte.type); if(!strictGpx11) { // write the key as extension tag QDomElement xmlExt = doc.createElement("extensions"); xmlRte.appendChild(xmlExt); writeXml(xmlExt, "ql:key", key.item); } for(const rtept_t &pt : rte.pts) { QDomElement xmlRtept = doc.createElement("rtept"); xmlRte.appendChild(xmlRtept); writeWpt(xmlRtept, pt, strictGpx11); } } void CGisItemOvlArea::readArea(const QDomNode& xml, area_t& area) { readXml(xml, "ql:name", area.name); readXml(xml, "ql:cmt", area.cmt); readXml(xml, "ql:desc", area.desc); readXml(xml, "ql:src", area.src); readXml(xml, "ql:link", area.links); readXml(xml, "ql:number", area.number); readXml(xml, "ql:type", area.type); readXml(xml, "ql:color", area.color); readXml(xml, "ql:width", area.width); readXml(xml, "ql:style", area.style); readXml(xml, "ql:opacity", area.opacity); readXml(xml, "ql:key", key.item); readXml(xml, "ql:flags", flags); readXml(xml, history); const QDomNodeList& xmlPts = xml.toElement().elementsByTagName("ql:point"); int M = xmlPts.count(); area.pts.resize(M); for(int m = 0; m < M; ++m) { pt_t& pt = area.pts[m]; const QDomNode& xmlPt = xmlPts.item(m); readWpt(xmlPt, pt); } setColor(str2color(area.color)); deriveSecondaryData(); } void CGisItemOvlArea::save(QDomNode& gpx, bool strictGpx11) { QDomDocument doc = gpx.ownerDocument(); QDomElement xmlArea = doc.createElement("ql:area"); gpx.appendChild(xmlArea); writeXml(xmlArea, "ql:name", area.name); writeXml(xmlArea, "ql:cmt", area.cmt); writeXml(xmlArea, "ql:desc", area.desc); writeXml(xmlArea, "ql:src", area.src); writeXml(xmlArea, "ql:link", area.links); writeXml(xmlArea, "ql:number", area.number); writeXml(xmlArea, "ql:type", area.type); writeXml(xmlArea, "ql:color", area.color); writeXml(xmlArea, "ql:width", area.width); writeXml(xmlArea, "ql:style", area.style); writeXml(xmlArea, "ql:opacity", area.opacity); writeXml(xmlArea, "ql:key", key.item); writeXml(xmlArea, "ql:flags", flags); writeXml(xmlArea, history); for(const pt_t &pt : area.pts) { QDomElement xmlPt = doc.createElement("ql:point"); xmlArea.appendChild(xmlPt); writeWpt(xmlPt, pt, strictGpx11); } } void IGisItem::readWpt(const QDomNode& xml, wpt_t& wpt) { const QDomNamedNodeMap& attr = xml.attributes(); wpt.lat = attr.namedItem("lat").nodeValue().toDouble(); wpt.lon = attr.namedItem("lon").nodeValue().toDouble(); readXml(xml, "ele", wpt.ele); readXml(xml, "time", wpt.time); readXml(xml, "magvar", wpt.magvar); readXml(xml, "geoidheight", wpt.geoidheight); readXml(xml, "name", wpt.name); readXml(xml, "cmt", wpt.cmt); readXml(xml, "desc", wpt.desc); readXml(xml, "src", wpt.src); readXml(xml, "link", wpt.links); readXml(xml, "sym", wpt.sym); readXml(xml, "type", wpt.type); readXml(xml, "fix", wpt.fix); readXml(xml, "sat", wpt.sat); readXml(xml, "hdop", wpt.hdop); readXml(xml, "vdop", wpt.vdop); readXml(xml, "pdop", wpt.pdop); readXml(xml, "ageofdgpsdata", wpt.ageofdgpsdata); readXml(xml, "dgpsid", wpt.dgpsid); // some GPX 1.0 backward compatibility QString url; readXml(xml, "url", url); if(!url.isEmpty()) { link_t link; link.uri.setUrl(url); readXml(xml, "urlname", link.text); wpt.links << link; } } void IGisItem::writeWpt(QDomElement& xml, const wpt_t& wpt, bool strictGpx11) { QString str; str.sprintf("%1.8f", wpt.lat); xml.setAttribute("lat", str); str.sprintf("%1.8f", wpt.lon); xml.setAttribute("lon", str); writeXml(xml, "ele", wpt.ele); writeXml(xml, "time", wpt.time); writeXml(xml, "magvar", wpt.magvar); writeXml(xml, "geoidheight", wpt.geoidheight); writeXml(xml, "name", wpt.name); writeXml(xml, "cmt", html2Dev(wpt.cmt, strictGpx11)); writeXml(xml, "desc", html2Dev(wpt.desc, strictGpx11)); writeXml(xml, "src", wpt.src); writeXml(xml, "link", wpt.links); writeXml(xml, "sym", wpt.sym); writeXml(xml, "type", wpt.type); writeXml(xml, "fix", wpt.fix); writeXml(xml, "sat", wpt.sat); writeXml(xml, "hdop", wpt.hdop); writeXml(xml, "vdop", wpt.vdop); writeXml(xml, "pdop", wpt.pdop); writeXml(xml, "ageofdgpsdata", wpt.ageofdgpsdata); writeXml(xml, "dgpsid", wpt.dgpsid); } void CDeviceGarmin::createAdventureFromProject(IGisProject * project, const QString& gpxFilename) { if(pathAdventures.isEmpty()) { return; } QDomDocument doc; QDomElement adventure = doc.createElement("Adventure"); doc.appendChild(adventure); adventure.setAttribute("xmlns","http://www.garmin.com/xmlschemas/GarminAdventure/v1"); writeXml(adventure, "GlobalId", project->getKey()); writeXml(adventure, "Name", project->getName()); QDomElement item = doc.createElement("Item"); adventure.appendChild(item); writeXml(item, "DataType", "GPSData"); writeXml(item, "Location", gpxFilename); writeXml(adventure, "Description", IGisItem::removeHtml(project->getDescription())); const int N = project->childCount(); for(int i = 0; i < N; i++) { CGisItemTrk * track = dynamic_cast(project->child(i)); if(track != nullptr) { const CTrackData& trk = track->getTrackData(); if(trk.segs.isEmpty()) { continue; } if(trk.segs.first().pts.isEmpty()) { continue; } const CTrackData::trkpt_t& origin = trk.segs.first().pts.first(); QDomElement startPosition = doc.createElement("StartPosition"); adventure.appendChild(startPosition); writeXml(startPosition, "Lat", origin.lat); writeXml(startPosition, "Lon", origin.lon); writeXml(adventure, "Activity", tr("Unknown")); writeXml(adventure, "Distance", track->getTotalDistance()); writeXml(adventure, "Duration", track->getTotalElapsedSecondsMoving()); writeXml(adventure, "Ascent", track->getTotalAscent()); writeXml(adventure, "Descent", track->getTotalDescent()); writeXml(adventure, "Difficulty", 1); writeXml(adventure, "NumRatings", 0); writeXml(adventure, "MainTrackId", track->getName()); QDomElement waypointOrder = doc.createElement("WaypointOrder"); adventure.appendChild(waypointOrder); for(const CTrackData::trkpt_t& trkpt : trk) { if(trkpt.keyWpt.item.isEmpty()) { continue; } const CGisItemWpt * wpt = dynamic_cast(project->getItemByKey(trkpt.keyWpt)); if(wpt == nullptr) { continue; } QDomElement waypoints = doc.createElement("Waypoints"); waypointOrder.appendChild(waypoints); writeXml(waypoints, "ID", wpt->getName()); writeXml(waypoints, "DistanceFromOrigin", trkpt.distance); } break; } } const QDir dirAdventures(dir.absoluteFilePath(pathAdventures)); QString filename = dirAdventures.absoluteFilePath(project->getKey() + ".adv"); QFile file(filename); mount(); file.open(QIODevice::WriteOnly); QTextStream out(&file); out.setCodec("UTF-8"); out << "" << endl; out << doc.toString(); file.close(); umount(); } qmapshack-1.10.0/src/gis/gpx/CGpxProject.cpp000644 001750 000144 00000032543 13216234140 021770 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "device/CDeviceGarmin.h" #include "device/IDevice.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/trk/CKnownExtension.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CSelectCopyAction.h" #include "helpers/CSettings.h" #include CGpxProject::CGpxProject(const QString &filename, CGisListWks *parent) : IGisProject(eTypeGpx, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png")); blockUpdateItems(true); loadGpx(filename); blockUpdateItems(false); } CGpxProject::CGpxProject(const QString &filename, IDevice * parent) : IGisProject(eTypeGpx, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png")); blockUpdateItems(true); loadGpx(filename); blockUpdateItems(false); } CGpxProject::CGpxProject(const QString &filename, const IGisProject * project, IDevice * parent) : IGisProject(eTypeGpx, filename, parent) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png")); *(IGisProject*)this = *project; blockUpdateItems(project->blockUpdateItems()); int res = CSelectCopyAction::eResultNone; const int N = project->childCount(); for(int n = 0; n < N; n++) { IGisItem * item = dynamic_cast(project->child(n)); if(item) { insertCopyOfItem(item, NOIDX, res); } } setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); blockUpdateItems(false); setToolTip(CGisListWks::eColumnName, getInfo()); valid = true; } CGpxProject::~CGpxProject() { } void CGpxProject::loadGpx(const QString& filename) { try { loadGpx(filename, this); } catch(QString &errormsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); valid = false; } } void CGpxProject::loadGpx(const QString &filename, CGpxProject *project) { // create file instance QFile file(filename); // if the file does not exist, the filename is assumed to be a name for a new project if(!file.exists() || QFileInfo(filename).suffix().toLower() != "gpx") { project->filename.clear(); project->setupName(filename); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; return; } if(!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open %1").arg(filename); } // load file content to xml document QDomDocument xml; QString msg; int line; int column; if(!xml.setContent(&file, false, &msg, &line, &column)) { file.close(); throw tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg); } file.close(); int N; QDomElement xmlGpx = xml.documentElement(); if(xmlGpx.tagName() != "gpx") { throw tr("Not a GPX file: %1").arg(filename); } // Read all attributes and find any registrations for actually known extensions. // This is used to properly detect valid .gpx files using uncommon namespaces. QDomNamedNodeMap attributes = xmlGpx.attributes(); for(int i = 0; i < attributes.size(); ++i) { const QString xmlns("xmlns"); QDomAttr att = attributes.item(i).toAttr(); if(att.name().startsWith(xmlns + ":")) { QString ns = att.name().mid(xmlns.length() + 1); if(att.value() == gpxtpx_ns) { CKnownExtension::initGarminTPXv1(IUnit::self(), ns); } else if(att.value() == gpxdata_ns) { CKnownExtension::initClueTrustTPXv1(IUnit::self(), ns); } } } const QDomElement& xmlExtension = xmlGpx.namedItem("extensions").toElement(); if(xmlExtension.namedItem("ql:key").isElement()) { project->key = xmlExtension.namedItem("ql:key").toElement().text(); } if(xmlExtension.namedItem("ql:sortingRoadbook").isElement()) { project->sortingRoadbook = sorting_roadbook_e(xmlExtension.namedItem("ql:sortingRoadbook").toElement().text().toInt()); } if(xmlExtension.namedItem("ql:sortingFolder").isElement()) { project->sortingFolder = sorting_folder_e(xmlExtension.namedItem("ql:sortingFolder").toElement().text().toInt()); } if(xmlExtension.namedItem("ql:correlation").isElement()) { project->noCorrelation = bool(xmlExtension.namedItem("ql:correlation").toElement().text().toInt() == 0); } const QDomNode& xmlMetadata = xmlGpx.namedItem("metadata"); if(xmlMetadata.isElement()) { project->readMetadata(xmlMetadata, project->metadata); } /** @note If you change the order of the item types read you have to take care of the order enforced in IGisItem(). */ const QDomNodeList& xmlTrks = xmlGpx.elementsByTagName("trk"); N = xmlTrks.count(); for(int n = 0; n < N; ++n) { const QDomNode& xmlTrk = xmlTrks.item(n); new CGisItemTrk(xmlTrk, project); } const QDomNodeList& xmlRtes = xmlGpx.elementsByTagName("rte"); N = xmlRtes.count(); for(int n = 0; n < N; ++n) { const QDomNode& xmlRte = xmlRtes.item(n); new CGisItemRte(xmlRte, project); } const QDomNodeList& xmlWpts = xmlGpx.elementsByTagName("wpt"); N = xmlWpts.count(); for(int n = 0; n < N; ++n) { const QDomNode& xmlWpt = xmlWpts.item(n); CGisItemWpt * wpt = new CGisItemWpt(xmlWpt, project); /* Special care for waypoints stored on Garmin devices. Images attached to the waypoint are stored in the file system of the device and written as links to the waypoint. Let the device object take care of this. */ IDevice * device = dynamic_cast(project->parent()); if(device) { device->loadImages(*wpt); } } const QDomNodeList& xmlAreas = xmlExtension.elementsByTagName("ql:area"); N = xmlAreas.count(); for(int n = 0; n < N; ++n) { const QDomNode& xmlArea = xmlAreas.item(n); new CGisItemOvlArea(xmlArea, project); } project->sortItems(); project->setupName(QFileInfo(filename).completeBaseName().replace("_", " ")); project->setToolTip(CGisListWks::eColumnName, project->getInfo()); project->valid = true; } bool CGpxProject::saveAs(const QString& fn, IGisProject& project, bool strictGpx11) { QString _fn_ = fn; QFileInfo fi(_fn_); if(fi.suffix().toLower() != "gpx") { _fn_ += ".gpx"; } project.mount(); // safety check for existing files QFile file(_fn_); if(file.exists()) { file.open(QIODevice::ReadOnly); bool createdByQMS = false; // load file content to xml document QDomDocument xml; if(xml.setContent(&file, false)) { const QDomElement& docElem = xml.documentElement(); const QDomNamedNodeMap& attr = docElem.attributes(); createdByQMS = attr.namedItem("creator").nodeValue().startsWith("QMapShack"); } if(!createdByQMS) { int res = QMessageBox::warning(CMainWindow::getBestWidgetForParent(),tr("File exists ...") ,tr("The file exists and it has not been created by QMapShack. " "If you press 'yes' all data in this file will be lost. " "Even if this file contains GPX data and has been loaded by QMapShack, " "QMapShack might not be able to load and store all elements of this file. " "Those elements will be lost. I recommend to use another file. " "Do you really want to overwrite the file?") ,QMessageBox::Yes|QMessageBox::No,QMessageBox::No); if(res == QMessageBox::No) { project.umount(); return false; } } file.close(); } // ---- start content of gpx QDomDocument doc; QDomNode gpx = project.writeMetadata(doc, strictGpx11); IDevice * device = dynamic_cast(project.parent()); if(device) { device->startSavingProject(&project); } for(int i = 0; i < project.childCount(); i++) { CGisItemWpt *item = dynamic_cast(project.child(i)); if(nullptr == item) { continue; } /* Special care for waypoints stored on Garmin devices. Images attached to the waypoint are stored in the file system of the device and written as links to the waypoint. Let the device object take care of this. */ if(device) { device->saveImages(*item); } item->save(gpx, strictGpx11); } for(int i = 0; i < project.childCount(); i++) { CGisItemRte *item = dynamic_cast(project.child(i)); if(nullptr == item) { continue; } item->save(gpx, strictGpx11); } for(int i = 0; i < project.childCount(); i++) { CGisItemTrk *item = dynamic_cast(project.child(i)); if(nullptr == item) { continue; } item->save(gpx, strictGpx11); } if(!strictGpx11) { QDomElement xmlExt = doc.createElement("extensions"); gpx.appendChild(xmlExt); for(int i = 0; i < project.childCount(); i++) { CGisItemOvlArea * item = dynamic_cast(project.child(i)); if(nullptr == item) { continue; } item->save(xmlExt,strictGpx11); } if(!project.getKey().isEmpty()) { QDomElement elem = xmlExt.ownerDocument().createElement("ql:key"); xmlExt.appendChild(elem); QDomText text = xmlExt.ownerDocument().createTextNode(project.getKey()); elem.appendChild(text); } { QDomElement elem = xmlExt.ownerDocument().createElement("ql:sortingRoadbook"); xmlExt.appendChild(elem); QDomText text = xmlExt.ownerDocument().createTextNode(QString::number(project.getSortingRoadbook())); elem.appendChild(text); } { QDomElement elem = xmlExt.ownerDocument().createElement("ql:sortingFolder"); xmlExt.appendChild(elem); QDomText text = xmlExt.ownerDocument().createTextNode(QString::number(project.getSortingFolder())); elem.appendChild(text); } { QDomElement elem = xmlExt.ownerDocument().createElement("ql:correlation"); xmlExt.appendChild(elem); QDomText text = xmlExt.ownerDocument().createTextNode(QString::number(project.doCorrelation())); elem.appendChild(text); } } // ---- stop content of gpx bool res = true; try { if(!file.open(QIODevice::WriteOnly)) { throw tr("Failed to create file '%1'").arg(_fn_); } QTextStream out(&file); out.setCodec("UTF-8"); out << "" << endl; out << doc.toString(); file.close(); if(file.error() != QFile::NoError) { throw tr("Failed to write file '%1'").arg(_fn_); } } catch(const QString& msg) { // as saveAs() can be called from the thread that exports a database showing the // message box will crash the app. Therefore we test if the current thread is the // application's main thread. If not we forward the exception. // // Not sure if that is a good concept. if(QThread::currentThread() == qApp->thread()) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Saving GIS data failed..."), msg, QMessageBox::Abort); } else { throw msg; } res = false; } project.umount(); return res; } qmapshack-1.10.0/src/gis/gpx/CGpxProject.h000644 001750 000144 00000003506 13216234143 021435 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGPXPROJECT_H #define CGPXPROJECT_H #include "gis/prj/IGisProject.h" class CGisListWks; class CGisDraw; class CGpxProject : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CGpxProject) public: CGpxProject(const QString &filename, CGisListWks * parent); CGpxProject(const QString &filename, IDevice * parent); CGpxProject(const QString &filename, const IGisProject * project, IDevice * parent); virtual ~CGpxProject(); const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterGPX; } const QString getFileExtension() const override { return "gpx"; } bool canSave() const override { return true; } static bool saveAs(const QString& fn, IGisProject& project, bool strictGpx11); static void loadGpx(const QString &filename, CGpxProject *project); private: void loadGpx(const QString& filename); }; #endif //CGPXPROJECT_H qmapshack-1.10.0/src/gis/WptIcons.cpp000644 001750 000144 00000021135 13216234140 020543 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "WptIcons.h" #include "helpers/CSettings.h" #include "setup/IAppSetup.h" #include static const char * wptDefault = "://icons/waypoints/32x32/Default.png"; static QMap wptIcons; void initWptIcons() { wptIcons.clear(); wptIcons["Default"] = icon_t(wptDefault, 16, 16); wptIcons["City (Capitol)"] = icon_t("://icons/waypoints/32x32/CityCapitol.png", 16, 16); wptIcons["City (Large)"] = icon_t("://icons/waypoints/32x32/CityLarge.png", 16, 16); wptIcons["City (Medium)"] = icon_t("://icons/waypoints/32x32/CityMedium.png", 16, 16); wptIcons["City (Small)"] = icon_t("://icons/waypoints/32x32/CitySmall.png", 16, 16); // wptIcons["Small City"] = ":/icons/wpt/small_city15x15.png"; // wptIcons["Geocache"] = ":/icons/wpt/geocache15x15.png"; // wptIcons["Geocache Found"] = ":/icons/wpt/geocache_fnd15x15.png"; wptIcons["Residence"] = icon_t("://icons/waypoints/32x32/Residence.png", 16, 16); wptIcons["Flag, Red"] = icon_t("://icons/waypoints/32x32/FlagRed.png", 0, 32); wptIcons["Flag, Blue"] = icon_t("://icons/waypoints/32x32/FlagBlue.png", 0, 32); wptIcons["Flag, Green"] = icon_t("://icons/waypoints/32x32/FlagGreen.png", 0, 32); wptIcons["Pin, Red"] = icon_t("://icons/waypoints/32x32/PinRed.png", 0, 32); wptIcons["Pin, Blue"] = icon_t("://icons/waypoints/32x32/PinBlue.png", 0, 32); wptIcons["Pin, Green"] = icon_t("://icons/waypoints/32x32/PinGreen.png", 0, 32); wptIcons["Block, Red"] = icon_t("://icons/waypoints/32x32/BoxRed.png", 16, 16); wptIcons["Block, Blue"] = icon_t("://icons/waypoints/32x32/BoxBlue.png", 16, 16); wptIcons["Block, Green"] = icon_t("://icons/waypoints/32x32/BoxGreen.png", 16, 16); wptIcons["Blue Diamond"] = icon_t("://icons/waypoints/32x32/DiamondBlue.png", 16, 16); wptIcons["Green Diamond"] = icon_t("://icons/waypoints/32x32/DiamondGreen.png", 16, 16); wptIcons["Red Diamond"] = icon_t("://icons/waypoints/32x32/DiamondRed.png", 16, 16); wptIcons["Parking Area"] = icon_t("://icons/cache/32x32/parking.png", 16, 16); wptIcons["Trailhead"] = icon_t("://icons/cache/32x32/trailhead.png", 16, 16); wptIcons["Waypoint"] = icon_t("://icons/waypoints/32x32/Waypoint.png", 16, 16); wptIcons["1stCategory"] = icon_t("://icons/waypoints/32x32/1stCategory.png", 16, 16); wptIcons["2ndCategory"] = icon_t("://icons/waypoints/32x32/2ndCategory.png", 16, 16); wptIcons["3rdCategory"] = icon_t("://icons/waypoints/32x32/3rdCategory.png", 16, 16); wptIcons["4thCategory"] = icon_t("://icons/waypoints/32x32/4thCategory.png", 16, 16); wptIcons["Danger"] = icon_t("://icons/waypoints/32x32/Danger.png", 16, 16); wptIcons["FirstAid"] = icon_t("://icons/waypoints/32x32/FirstAid.png", 16, 16); wptIcons["Food"] = icon_t("://icons/waypoints/32x32/Food.png", 16, 16); wptIcons["Generic"] = icon_t("://icons/waypoints/32x32/Generic.png", 16, 16); wptIcons["HorsCategory"] = icon_t("://icons/waypoints/32x32/HorsCategory.png", 16, 16); wptIcons["Left"] = icon_t("://icons/waypoints/32x32/Left.png", 16, 16); wptIcons["Right"] = icon_t("://icons/waypoints/32x32/Right.png", 16, 16); wptIcons["Sprint"] = icon_t("://icons/waypoints/32x32/Sprint.png", 16, 16); wptIcons["Straight"] = icon_t("://icons/waypoints/32x32/Straight.png", 16, 16); wptIcons["Summit"] = icon_t("://icons/waypoints/32x32/Summit.png", 16, 16); wptIcons["Valley"] = icon_t("://icons/waypoints/32x32/Valley.png", 16, 16); wptIcons["Water"] = icon_t("://icons/waypoints/32x32/Water.png", 16, 16); wptIcons["LeftFork"] = icon_t("://icons/waypoints/32x32/LeftFork.png", 16, 16); wptIcons["RightFork"] = icon_t("://icons/waypoints/32x32/RightFork.png", 16, 16); wptIcons["MiddleFork"] = icon_t("://icons/waypoints/32x32/MiddleFork.png", 16, 16); wptIcons["SlightLeft"] = icon_t("://icons/waypoints/32x32/SlightLeft.png", 16, 16); wptIcons["SharpLeft"] = icon_t("://icons/waypoints/32x32/SharpLeft.png", 16, 16); wptIcons["SlightRight"] = icon_t("://icons/waypoints/32x32/SlightRight.png", 16, 16); wptIcons["SharpRight"] = icon_t("://icons/waypoints/32x32/SharpRight.png", 16, 16); wptIcons["UTurn"] = icon_t("://icons/waypoints/32x32/UTurn.png", 16, 16); wptIcons["Start"] = icon_t("://icons/waypoints/32x32/Start.png", 16, 16); wptIcons["End"] = icon_t("://icons/waypoints/32x32/End.png", 16, 16); setWptIconByName("Traditional Cache", "://icons/cache/32x32/traditional.png"); setWptIconByName("Multi-cache", "://icons/cache/32x32/multi.png"); setWptIconByName("Unknown Cache", "://icons/cache/32x32/unknown.png"); setWptIconByName("Wherigo Cache", "://icons/cache/32x32/wherigo.png"); setWptIconByName("Event Cache", "://icons/cache/32x32/event.png"); setWptIconByName("Earthcache", "://icons/cache/32x32/earth.png"); setWptIconByName("Letterbox Hybrid", "://icons/cache/32x32/letterbox.png"); setWptIconByName("Virtual Cache", "://icons/cache/32x32/virtual.png"); setWptIconByName("Webcam Cache", "://icons/cache/32x32/webcam.png"); SETTINGS; QDir dirIcon(cfg.value("Paths/externalWptIcons", IAppSetup::getPlatformInstance()->userDataPath("WaypointIcons")).toString()); QStringList filenames = dirIcon.entryList(QString("*.bmp *.png").split(" "), QDir::Files); for(const QString &filename : filenames) { QFileInfo fi(filename); QString name = fi.completeBaseName(); setWptIconByName(name, dirIcon.filePath(filename)); } } const QMap& getWptIcons() { return wptIcons; } void setWptIconByName(const QString& name, const QString& filename) { QPixmap icon(filename); wptIcons[name] = icon_t(filename, icon.width()>>1, icon.height()>>1); } void setWptIconByName(const QString& name, const QPixmap& icon) { SETTINGS; QDir dirIcon(cfg.value("Paths/externalWptIcons", IAppSetup::getPlatformInstance()->userDataPath("WaypointIcons")).toString()); QString filename = dirIcon.filePath(name + ".png"); icon.save(filename); wptIcons[name] = icon_t(filename, icon.width()>>1, icon.height()>>1); } QPixmap loadIcon(const QString& path) { QFileInfo finfo(path); if(finfo.completeSuffix() != "bmp") { return QPixmap(path); } else { QImage img = QPixmap(path).toImage().convertToFormat(QImage::Format_Indexed8); img.setColor(0,qRgba(0,0,0,0)); return QPixmap::fromImage(img); } } QPixmap getWptIconByName(const QString& name, QPointF &focus, QString * src) { QPixmap icon; QString path; if(wptIcons.contains(name)) { focus = wptIcons[name].focus; path = wptIcons[name].path; } else { focus = wptIcons["Default"].focus; path = wptIcons["Default"].path; } if(path.isEmpty()) { path = wptDefault; } if(src) { *src = path; } icon = loadIcon(path); // Limit icon size to 22 pixel max. if(icon.width() > 22 || icon.height() > 22) { qreal s; if(icon.width() > icon.height()) { s = 22.0/icon.width(); } else { s = 22.0/icon.height(); } focus = focus * s; icon = icon.scaled(icon.size()*s,Qt::KeepAspectRatio,Qt::SmoothTransformation); } return icon; } qmapshack-1.10.0/src/gis/fit/000755 001750 000144 00000000000 13216664445 017070 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/fit/CFitStream.h000644 001750 000144 00000004563 13216234143 021236 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITSTREAM_H #define CFITSTREAM_H #include "gis/fit/decoder/CFitDecoder.h" #include class CFitMessage; /* Encapsulates the access to the FIT messages. Looping over the read FIT messages can be done using the methods nextMesg() and hasMoreMesg() (Iterator pattern). */ class CFitStream final { public: CFitStream(QFile& dev) : file(dev) { } /** decodes fit file provided in constructor throws: QString in case of a decoding failure */ void decodeFile(); /** sets the stream at the beginning (first position). */ void reset(); /** Get the next FIT message throws: fit::RuntimeException */ const CFitMessage& nextMesg(); /** return: the last read message again */ const CFitMessage& lastMesg() const; /** return: true if there a further FIT message is available */ bool hasMoreMesg() const; /** return: the next message of the given message type (xx_MESG_NUM) beginning reading at the current position */ const CFitMessage& nextMesgOf(quint16 mesgNum); /** return: gets the first message of the given type (xx_MESG_NUM) beginning reading at start of stream. Sets the stream to the beginning again. */ const CFitMessage& firstMesgOf(quint16 mesgNum); int countMesgOf(quint16 mesgNr); QString getFileName() const { return file.fileName(); } private: QFile& file; CFitDecoder decode; int readPos = 0; }; #endif //CFITSTREAM_H qmapshack-1.10.0/src/gis/fit/defs/000755 001750 000144 00000000000 13216664445 020011 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/fit/defs/fit_enums.h000644 001750 000144 00000173744 13216234143 022157 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef FIT_PROFILE_H #define FIT_PROFILE_H typedef enum { eLocationName = 0, eLocationPositionLat = 1, eLocationPositionLong = 2, eLocationSymbol = 3, eLocationAltitude = 4, eLocation5 = 5, eLocationComment = 6, eLocationTimestamp = 253, eLocationMessageIndex = 254 } message_location_e; typedef enum { eMesgNumLocation = 29 } ext_mesg_num_e; typedef enum { eFileLocation = 8 } ext_file_e; // ----------- start generated code ----------- typedef enum { eFileDevice = 1, eFileSettings = 2, eFileSport = 3, eFileActivity = 4, eFileWorkout = 5, eFileCourse = 6, eFileSchedules = 7, eFileWeight = 9, eFileTotals = 10, eFileGoals = 11, eFileBloodPressure = 14, eFileMonitoringA = 15, eFileActivitySummary = 20, eFileMonitoringDaily = 28, eFileMonitoringB = 32, eFileSegment = 34, eFileSegmentList = 35, eFileExdConfiguration = 40, eFileMfgRangeMin = 0xF7, eFileMfgRangeMax = 0xFE } file_e; typedef enum { eMesgNumFileId = 0, eMesgNumCapabilities = 1, eMesgNumDeviceSettings = 2, eMesgNumUserProfile = 3, eMesgNumHrmProfile = 4, eMesgNumSdmProfile = 5, eMesgNumBikeProfile = 6, eMesgNumZonesTarget = 7, eMesgNumHrZone = 8, eMesgNumPowerZone = 9, eMesgNumMetZone = 10, eMesgNumSport = 12, eMesgNumGoal = 15, eMesgNumSession = 18, eMesgNumLap = 19, eMesgNumRecord = 20, eMesgNumEvent = 21, eMesgNumDeviceInfo = 23, eMesgNumWorkout = 26, eMesgNumWorkoutStep = 27, eMesgNumSchedule = 28, eMesgNumWeightScale = 30, eMesgNumCourse = 31, eMesgNumCoursePoint = 32, eMesgNumTotals = 33, eMesgNumActivity = 34, eMesgNumSoftware = 35, eMesgNumFileCapabilities = 37, eMesgNumMesgCapabilities = 38, eMesgNumFieldCapabilities = 39, eMesgNumFileCreator = 49, eMesgNumBloodPressure = 51, eMesgNumSpeedZone = 53, eMesgNumMonitoring = 55, eMesgNumTrainingFile = 72, eMesgNumHrv = 78, eMesgNumAntRx = 80, eMesgNumAntTx = 81, eMesgNumAntChannelId = 82, eMesgNumLength = 101, eMesgNumMonitoringInfo = 103, eMesgNumPad = 105, eMesgNumSlaveDevice = 106, eMesgNumConnectivity = 127, eMesgNumWeatherConditions = 128, eMesgNumWeatherAlert = 129, eMesgNumCadenceZone = 131, eMesgNumHr = 132, eMesgNumSegmentLap = 142, eMesgNumMemoGlob = 145, eMesgNumSegmentId = 148, eMesgNumSegmentLeaderboardEntry = 149, eMesgNumSegmentPoint = 150, eMesgNumSegmentFile = 151, eMesgNumWatchfaceSettings = 159, eMesgNumGpsMetadata = 160, eMesgNumCameraEvent = 161, eMesgNumTimestampCorrelation = 162, eMesgNumGyroscopeData = 164, eMesgNumAccelerometerData = 165, eMesgNumThreeDSensorCalibration = 167, eMesgNumVideoFrame = 169, eMesgNumObdiiData = 174, eMesgNumNmeaSentence = 177, eMesgNumAviationAttitude = 178, eMesgNumVideo = 184, eMesgNumVideoTitle = 185, eMesgNumVideoDescription = 186, eMesgNumVideoClip = 187, eMesgNumOhrSettings = 188, eMesgNumExdScreenConfiguration = 200, eMesgNumExdDataFieldConfiguration = 201, eMesgNumExdDataConceptConfiguration = 202, eMesgNumFieldDescription = 206, eMesgNumDeveloperDataId = 207, eMesgNumMagnetometerData = 208, eMesgNumMfgRangeMin = 0xFF00, eMesgNumMfgRangeMax = 0xFFFE } mesg_num_e; typedef enum { eChecksumClear = 0, eChecksumOk = 1 } checksum_e; typedef enum { eFileFlagsRead = 0x02, eFileFlagsWrite = 0x04, eFileFlagsErase = 0x08 } file_flags_e; typedef enum { eMesgCountNumPerFile = 0, eMesgCountMaxPerFile = 1, eMesgCountMaxPerFileType = 2 } mesg_count_e; typedef enum { eDateTimeMin = 0x10000000 } date_time_e; typedef enum { eLocalDateTimeMin = 0x10000000 } local_date_time_e; typedef enum { eMessageIndexSelected = 0x8000, eMessageIndexReserved = 0x7000, eMessageIndexMask = 0x0FFF } message_index_e; typedef enum { eDeviceIndexCreator = 0 } device_index_e; typedef enum { eGenderFemale = 0, eGenderMale = 1 } gender_e; typedef enum { eLanguageEnglish = 0, eLanguageFrench = 1, eLanguageItalian = 2, eLanguageGerman = 3, eLanguageSpanish = 4, eLanguageCroatian = 5, eLanguageCzech = 6, eLanguageDanish = 7, eLanguageDutch = 8, eLanguageFinnish = 9, eLanguageGreek = 10, eLanguageHungarian = 11, eLanguageNorwegian = 12, eLanguagePolish = 13, eLanguagePortuguese = 14, eLanguageSlovakian = 15, eLanguageSlovenian = 16, eLanguageSwedish = 17, eLanguageRussian = 18, eLanguageTurkish = 19, eLanguageLatvian = 20, eLanguageUkrainian = 21, eLanguageArabic = 22, eLanguageFarsi = 23, eLanguageBulgarian = 24, eLanguageRomanian = 25, eLanguageChinese = 26, eLanguageJapanese = 27, eLanguageKorean = 28, eLanguageTaiwanese = 29, eLanguageThai = 30, eLanguageHebrew = 31, eLanguageBrazilianPortuguese = 32, eLanguageIndonesian = 33, eLanguageMalaysian = 34, eLanguageVietnamese = 35, eLanguageBurmese = 36, eLanguageMongolian = 37, eLanguageCustom = 254 } language_e; typedef enum { eLanguageBits0English = 0x01, eLanguageBits0French = 0x02, eLanguageBits0Italian = 0x04, eLanguageBits0German = 0x08, eLanguageBits0Spanish = 0x10, eLanguageBits0Croatian = 0x20, eLanguageBits0Czech = 0x40, eLanguageBits0Danish = 0x80 } language_bits_0_e; typedef enum { eLanguageBits1Dutch = 0x01, eLanguageBits1Finnish = 0x02, eLanguageBits1Greek = 0x04, eLanguageBits1Hungarian = 0x08, eLanguageBits1Norwegian = 0x10, eLanguageBits1Polish = 0x20, eLanguageBits1Portuguese = 0x40, eLanguageBits1Slovakian = 0x80 } language_bits_1_e; typedef enum { eLanguageBits2Slovenian = 0x01, eLanguageBits2Swedish = 0x02, eLanguageBits2Russian = 0x04, eLanguageBits2Turkish = 0x08, eLanguageBits2Latvian = 0x10, eLanguageBits2Ukrainian = 0x20, eLanguageBits2Arabic = 0x40, eLanguageBits2Farsi = 0x80 } language_bits_2_e; typedef enum { eLanguageBits3Bulgarian = 0x01, eLanguageBits3Romanian = 0x02, eLanguageBits3Chinese = 0x04, eLanguageBits3Japanese = 0x08, eLanguageBits3Korean = 0x10, eLanguageBits3Taiwanese = 0x20, eLanguageBits3Thai = 0x40, eLanguageBits3Hebrew = 0x80 } language_bits_3_e; typedef enum { eLanguageBits4BrazilianPortuguese = 0x01, eLanguageBits4Indonesian = 0x02, eLanguageBits4Malaysian = 0x04, eLanguageBits4Vietnamese = 0x08, eLanguageBits4Burmese = 0x10, eLanguageBits4Mongolian = 0x20 } language_bits_4_e; typedef enum { eTimeZoneAlmaty = 0, eTimeZoneBangkok = 1, eTimeZoneBombay = 2, eTimeZoneBrasilia = 3, eTimeZoneCairo = 4, eTimeZoneCapeVerdeIs = 5, eTimeZoneDarwin = 6, eTimeZoneEniwetok = 7, eTimeZoneFiji = 8, eTimeZoneHongKong = 9, eTimeZoneIslamabad = 10, eTimeZoneKabul = 11, eTimeZoneMagadan = 12, eTimeZoneMidAtlantic = 13, eTimeZoneMoscow = 14, eTimeZoneMuscat = 15, eTimeZoneNewfoundland = 16, eTimeZoneSamoa = 17, eTimeZoneSydney = 18, eTimeZoneTehran = 19, eTimeZoneTokyo = 20, eTimeZoneUsAlaska = 21, eTimeZoneUsAtlantic = 22, eTimeZoneUsCentral = 23, eTimeZoneUsEastern = 24, eTimeZoneUsHawaii = 25, eTimeZoneUsMountain = 26, eTimeZoneUsPacific = 27, eTimeZoneOther = 28, eTimeZoneAuckland = 29, eTimeZoneKathmandu = 30, eTimeZoneEuropeWesternWet = 31, eTimeZoneEuropeCentralCet = 32, eTimeZoneEuropeEasternEet = 33, eTimeZoneJakarta = 34, eTimeZonePerth = 35, eTimeZoneAdelaide = 36, eTimeZoneBrisbane = 37, eTimeZoneTasmania = 38, eTimeZoneIceland = 39, eTimeZoneAmsterdam = 40, eTimeZoneAthens = 41, eTimeZoneBarcelona = 42, eTimeZoneBerlin = 43, eTimeZoneBrussels = 44, eTimeZoneBudapest = 45, eTimeZoneCopenhagen = 46, eTimeZoneDublin = 47, eTimeZoneHelsinki = 48, eTimeZoneLisbon = 49, eTimeZoneLondon = 50, eTimeZoneMadrid = 51, eTimeZoneMunich = 52, eTimeZoneOslo = 53, eTimeZoneParis = 54, eTimeZonePrague = 55, eTimeZoneReykjavik = 56, eTimeZoneRome = 57, eTimeZoneStockholm = 58, eTimeZoneVienna = 59, eTimeZoneWarsaw = 60, eTimeZoneZurich = 61, eTimeZoneQuebec = 62, eTimeZoneOntario = 63, eTimeZoneManitoba = 64, eTimeZoneSaskatchewan = 65, eTimeZoneAlberta = 66, eTimeZoneBritishColumbia = 67, eTimeZoneBoise = 68, eTimeZoneBoston = 69, eTimeZoneChicago = 70, eTimeZoneDallas = 71, eTimeZoneDenver = 72, eTimeZoneKansasCity = 73, eTimeZoneLasVegas = 74, eTimeZoneLosAngeles = 75, eTimeZoneMiami = 76, eTimeZoneMinneapolis = 77, eTimeZoneNewYork = 78, eTimeZoneNewOrleans = 79, eTimeZonePhoenix = 80, eTimeZoneSantaFe = 81, eTimeZoneSeattle = 82, eTimeZoneWashingtonDc = 83, eTimeZoneUsArizona = 84, eTimeZoneChita = 85, eTimeZoneEkaterinburg = 86, eTimeZoneIrkutsk = 87, eTimeZoneKaliningrad = 88, eTimeZoneKrasnoyarsk = 89, eTimeZoneNovosibirsk = 90, eTimeZonePetropavlovskKamchatskiy = 91, eTimeZoneSamara = 92, eTimeZoneVladivostok = 93, eTimeZoneMexicoCentral = 94, eTimeZoneMexicoMountain = 95, eTimeZoneMexicoPacific = 96, eTimeZoneCapeTown = 97, eTimeZoneWinkhoek = 98, eTimeZoneLagos = 99, eTimeZoneRiyahd = 100, eTimeZoneVenezuela = 101, eTimeZoneAustraliaLh = 102, eTimeZoneSantiago = 103, eTimeZoneManual = 253, eTimeZoneAutomatic = 254 } time_zone_e; typedef enum { eDisplayMeasureMetric = 0, eDisplayMeasureStatute = 1, eDisplayMeasureNautical = 2 } display_measure_e; typedef enum { eDisplayHeartBpm = 0, eDisplayHeartMax = 1, eDisplayHeartReserve = 2 } display_heart_e; typedef enum { eDisplayPowerWatts = 0, eDisplayPowerPercentFtp = 1 } display_power_e; typedef enum { eDisplayPositionDegree = 0, eDisplayPositionDegreeMinute = 1, eDisplayPositionDegreeMinuteSecond = 2, eDisplayPositionAustrianGrid = 3, eDisplayPositionBritishGrid = 4, eDisplayPositionDutchGrid = 5, eDisplayPositionHungarianGrid = 6, eDisplayPositionFinnishGrid = 7, eDisplayPositionGermanGrid = 8, eDisplayPositionIcelandicGrid = 9, eDisplayPositionIndonesianEquatorial = 10, eDisplayPositionIndonesianIrian = 11, eDisplayPositionIndonesianSouthern = 12, eDisplayPositionIndiaZone0 = 13, eDisplayPositionIndiaZoneIa = 14, eDisplayPositionIndiaZoneIb = 15, eDisplayPositionIndiaZoneIia = 16, eDisplayPositionIndiaZoneIib = 17, eDisplayPositionIndiaZoneIiia = 18, eDisplayPositionIndiaZoneIiib = 19, eDisplayPositionIndiaZoneIva = 20, eDisplayPositionIndiaZoneIvb = 21, eDisplayPositionIrishTransverse = 22, eDisplayPositionIrishGrid = 23, eDisplayPositionLoran = 24, eDisplayPositionMaidenheadGrid = 25, eDisplayPositionMgrsGrid = 26, eDisplayPositionNewZealandGrid = 27, eDisplayPositionNewZealandTransverse = 28, eDisplayPositionQatarGrid = 29, eDisplayPositionModifiedSwedishGrid = 30, eDisplayPositionSwedishGrid = 31, eDisplayPositionSouthAfricanGrid = 32, eDisplayPositionSwissGrid = 33, eDisplayPositionTaiwanGrid = 34, eDisplayPositionUnitedStatesGrid = 35, eDisplayPositionUtmUpsGrid = 36, eDisplayPositionWestMalayan = 37, eDisplayPositionBorneoRso = 38, eDisplayPositionEstonianGrid = 39, eDisplayPositionLatvianGrid = 40, eDisplayPositionSwedishRef99Grid = 41 } display_position_e; typedef enum { eSwitchOff = 0, eSwitchOn = 1, eSwitchAuto = 2 } switch_e; typedef enum { eSportGeneric = 0, eSportRunning = 1, eSportCycling = 2, eSportTransition = 3, eSportFitnessEquipment = 4, eSportSwimming = 5, eSportBasketball = 6, eSportSoccer = 7, eSportTennis = 8, eSportAmericanFootball = 9, eSportTraining = 10, eSportWalking = 11, eSportCrossCountrySkiing = 12, eSportAlpineSkiing = 13, eSportSnowboarding = 14, eSportRowing = 15, eSportMountaineering = 16, eSportHiking = 17, eSportMultisport = 18, eSportPaddling = 19, eSportFlying = 20, eSportEBiking = 21, eSportMotorcycling = 22, eSportBoating = 23, eSportDriving = 24, eSportGolf = 25, eSportHangGliding = 26, eSportHorsebackRiding = 27, eSportHunting = 28, eSportFishing = 29, eSportInlineSkating = 30, eSportRockClimbing = 31, eSportSailing = 32, eSportIceSkating = 33, eSportSkyDiving = 34, eSportSnowshoeing = 35, eSportSnowmobiling = 36, eSportStandUpPaddleboarding = 37, eSportSurfing = 38, eSportWakeboarding = 39, eSportWaterSkiing = 40, eSportKayaking = 41, eSportRafting = 42, eSportWindsurfing = 43, eSportKitesurfing = 44, eSportTactical = 45, eSportJumpmaster = 46, eSportBoxing = 47, eSportFloorClimbing = 48, eSportAll = 254 } sport_e; typedef enum { eSportBits0Generic = 0x01, eSportBits0Running = 0x02, eSportBits0Cycling = 0x04, eSportBits0Transition = 0x08, eSportBits0FitnessEquipment = 0x10, eSportBits0Swimming = 0x20, eSportBits0Basketball = 0x40, eSportBits0Soccer = 0x80 } sport_bits_0_e; typedef enum { eSportBits1Tennis = 0x01, eSportBits1AmericanFootball = 0x02, eSportBits1Training = 0x04, eSportBits1Walking = 0x08, eSportBits1CrossCountrySkiing = 0x10, eSportBits1AlpineSkiing = 0x20, eSportBits1Snowboarding = 0x40, eSportBits1Rowing = 0x80 } sport_bits_1_e; typedef enum { eSportBits2Mountaineering = 0x01, eSportBits2Hiking = 0x02, eSportBits2Multisport = 0x04, eSportBits2Paddling = 0x08, eSportBits2Flying = 0x10, eSportBits2EBiking = 0x20, eSportBits2Motorcycling = 0x40, eSportBits2Boating = 0x80 } sport_bits_2_e; typedef enum { eSportBits3Driving = 0x01, eSportBits3Golf = 0x02, eSportBits3HangGliding = 0x04, eSportBits3HorsebackRiding = 0x08, eSportBits3Hunting = 0x10, eSportBits3Fishing = 0x20, eSportBits3InlineSkating = 0x40, eSportBits3RockClimbing = 0x80 } sport_bits_3_e; typedef enum { eSportBits4Sailing = 0x01, eSportBits4IceSkating = 0x02, eSportBits4SkyDiving = 0x04, eSportBits4Snowshoeing = 0x08, eSportBits4Snowmobiling = 0x10, eSportBits4StandUpPaddleboarding = 0x20, eSportBits4Surfing = 0x40, eSportBits4Wakeboarding = 0x80 } sport_bits_4_e; typedef enum { eSportBits5WaterSkiing = 0x01, eSportBits5Kayaking = 0x02, eSportBits5Rafting = 0x04, eSportBits5Windsurfing = 0x08, eSportBits5Kitesurfing = 0x10, eSportBits5Tactical = 0x20, eSportBits5Jumpmaster = 0x40, eSportBits5Boxing = 0x80 } sport_bits_5_e; typedef enum { eSportBits6FloorClimbing = 0x01 } sport_bits_6_e; typedef enum { eSubSportGeneric = 0, eSubSportTreadmill = 1, eSubSportStreet = 2, eSubSportTrail = 3, eSubSportTrack = 4, eSubSportSpin = 5, eSubSportIndoorCycling = 6, eSubSportRoad = 7, eSubSportMountain = 8, eSubSportDownhill = 9, eSubSportRecumbent = 10, eSubSportCyclocross = 11, eSubSportHandCycling = 12, eSubSportTrackCycling = 13, eSubSportIndoorRowing = 14, eSubSportElliptical = 15, eSubSportStairClimbing = 16, eSubSportLapSwimming = 17, eSubSportOpenWater = 18, eSubSportFlexibilityTraining = 19, eSubSportStrengthTraining = 20, eSubSportWarmUp = 21, eSubSportMatch = 22, eSubSportExercise = 23, eSubSportChallenge = 24, eSubSportIndoorSkiing = 25, eSubSportCardioTraining = 26, eSubSportIndoorWalking = 27, eSubSportEBikeFitness = 28, eSubSportBmx = 29, eSubSportCasualWalking = 30, eSubSportSpeedWalking = 31, eSubSportBikeToRunTransition = 32, eSubSportRunToBikeTransition = 33, eSubSportSwimToBikeTransition = 34, eSubSportAtv = 35, eSubSportMotocross = 36, eSubSportBackcountry = 37, eSubSportResort = 38, eSubSportRcDrone = 39, eSubSportWingsuit = 40, eSubSportWhitewater = 41, eSubSportSkateSkiing = 42, eSubSportYoga = 43, eSubSportPilates = 44, eSubSportIndoorRunning = 45, eSubSportGravelCycling = 46, eSubSportEBikeMountain = 47, eSubSportCommuting = 48, eSubSportMixedSurface = 49, eSubSportNavigate = 50, eSubSportTrackMe = 51, eSubSportMap = 52, eSubSportAll = 254 } sub_sport_e; typedef enum { eSportEventUncategorized = 0, eSportEventGeocaching = 1, eSportEventFitness = 2, eSportEventRecreation = 3, eSportEventRace = 4, eSportEventSpecialEvent = 5, eSportEventTraining = 6, eSportEventTransportation = 7, eSportEventTouring = 8 } sport_event_e; typedef enum { eActivityManual = 0, eActivityAutoMultiSport = 1 } activity_e; typedef enum { eIntensityActive = 0, eIntensityRest = 1, eIntensityWarmup = 2, eIntensityCooldown = 3 } intensity_e; typedef enum { eSessionTriggerActivityEnd = 0, eSessionTriggerManual = 1, eSessionTriggerAutoMultiSport = 2, eSessionTriggerFitnessEquipment = 3 } session_trigger_e; typedef enum { eAutolapTriggerTime = 0, eAutolapTriggerDistance = 1, eAutolapTriggerPositionStart = 2, eAutolapTriggerPositionLap = 3, eAutolapTriggerPositionWaypoint = 4, eAutolapTriggerPositionMarked = 5, eAutolapTriggerOff = 6 } autolap_trigger_e; typedef enum { eLapTriggerManual = 0, eLapTriggerTime = 1, eLapTriggerDistance = 2, eLapTriggerPositionStart = 3, eLapTriggerPositionLap = 4, eLapTriggerPositionWaypoint = 5, eLapTriggerPositionMarked = 6, eLapTriggerSessionEnd = 7, eLapTriggerFitnessEquipment = 8 } lap_trigger_e; typedef enum { eTimeModeHour12 = 0, eTimeModeHour24 = 1, eTimeModeMilitary = 2, eTimeModeHour12WithSeconds = 3, eTimeModeHour24WithSeconds = 4, eTimeModeUtc = 5 } time_mode_e; typedef enum { eBacklightModeOff = 0, eBacklightModeManual = 1, eBacklightModeKeyAndMessages = 2, eBacklightModeAutoBrightness = 3, eBacklightModeSmartNotifications = 4, eBacklightModeKeyAndMessagesNight = 5, eBacklightModeKeyAndMessagesAndSmartNotifications = 6 } backlight_mode_e; typedef enum { eDateModeDayMonth = 0, eDateModeMonthDay = 1 } date_mode_e; typedef enum { eEventTimer = 0, eEventWorkout = 3, eEventWorkoutStep = 4, eEventPowerDown = 5, eEventPowerUp = 6, eEventOffCourse = 7, eEventSession = 8, eEventLap = 9, eEventCoursePoint = 10, eEventBattery = 11, eEventVirtualPartnerPace = 12, eEventHrHighAlert = 13, eEventHrLowAlert = 14, eEventSpeedHighAlert = 15, eEventSpeedLowAlert = 16, eEventCadHighAlert = 17, eEventCadLowAlert = 18, eEventPowerHighAlert = 19, eEventPowerLowAlert = 20, eEventRecoveryHr = 21, eEventBatteryLow = 22, eEventTimeDurationAlert = 23, eEventDistanceDurationAlert = 24, eEventCalorieDurationAlert = 25, eEventActivity = 26, eEventFitnessEquipment = 27, eEventLength = 28, eEventUserMarker = 32, eEventSportPoint = 33, eEventCalibration = 36, eEventFrontGearChange = 42, eEventRearGearChange = 43, eEventRiderPositionChange = 44, eEventElevHighAlert = 45, eEventElevLowAlert = 46, eEventCommTimeout = 47 } event_e; typedef enum { eEventTypeStart = 0, eEventTypeStop = 1, eEventTypeConsecutiveDepreciated = 2, eEventTypeMarker = 3, eEventTypeStopAll = 4, eEventTypeBeginDepreciated = 5, eEventTypeEndDepreciated = 6, eEventTypeEndAllDepreciated = 7, eEventTypeStopDisable = 8, eEventTypeStopDisableAll = 9 } event_type_e; typedef enum { eTimerTriggerManual = 0, eTimerTriggerAuto = 1, eTimerTriggerFitnessEquipment = 2 } timer_trigger_e; typedef enum { eFitnessEquipmentStateReady = 0, eFitnessEquipmentStateInUse = 1, eFitnessEquipmentStatePaused = 2, eFitnessEquipmentStateUnknown = 3 } fitness_equipment_state_e; typedef enum { eAutoscrollNone = 0, eAutoscrollSlow = 1, eAutoscrollMedium = 2, eAutoscrollFast = 3 } autoscroll_e; typedef enum { eActivityClassLevel = 0x7F, eActivityClassLevelMax = 100, eActivityClassAthlete = 0x80 } activity_class_e; typedef enum { eHrZoneCalcCustom = 0, eHrZoneCalcPercentMaxHr = 1, eHrZoneCalcPercentHrr = 2 } hr_zone_calc_e; typedef enum { ePwrZoneCalcCustom = 0, ePwrZoneCalcPercentFtp = 1 } pwr_zone_calc_e; typedef enum { eWktStepDurationTime = 0, eWktStepDurationDistance = 1, eWktStepDurationHrLessThan = 2, eWktStepDurationHrGreaterThan = 3, eWktStepDurationCalories = 4, eWktStepDurationOpen = 5, eWktStepDurationRepeatUntilStepsCmplt = 6, eWktStepDurationRepeatUntilTime = 7, eWktStepDurationRepeatUntilDistance = 8, eWktStepDurationRepeatUntilCalories = 9, eWktStepDurationRepeatUntilHrLessThan = 10, eWktStepDurationRepeatUntilHrGreaterThan = 11, eWktStepDurationRepeatUntilPowerLessThan = 12, eWktStepDurationRepeatUntilPowerGreaterThan = 13, eWktStepDurationPowerLessThan = 14, eWktStepDurationPowerGreaterThan = 15, eWktStepDurationTrainingPeaksTss = 16, eWktStepDurationRepeatUntilPowerLastLapLessThan = 17, eWktStepDurationRepeatUntilMaxPowerLastLapLessThan = 18, eWktStepDurationPower3SLessThan = 19, eWktStepDurationPower10SLessThan = 20, eWktStepDurationPower30SLessThan = 21, eWktStepDurationPower3SGreaterThan = 22, eWktStepDurationPower10SGreaterThan = 23, eWktStepDurationPower30SGreaterThan = 24, eWktStepDurationPowerLapLessThan = 25, eWktStepDurationPowerLapGreaterThan = 26, eWktStepDurationRepeatUntilTrainingPeaksTss = 27, eWktStepDurationRepetitionTime = 28 } wkt_step_duration_e; typedef enum { eWktStepTargetSpeed = 0, eWktStepTargetHeartRate = 1, eWktStepTargetOpen = 2, eWktStepTargetCadence = 3, eWktStepTargetPower = 4, eWktStepTargetGrade = 5, eWktStepTargetResistance = 6, eWktStepTargetPower3S = 7, eWktStepTargetPower10S = 8, eWktStepTargetPower30S = 9, eWktStepTargetPowerLap = 10, eWktStepTargetSpeedLap = 12, eWktStepTargetHeartRateLap = 13 } wkt_step_target_e; typedef enum { eGoalTime = 0, eGoalDistance = 1, eGoalCalories = 2, eGoalFrequency = 3, eGoalSteps = 4, eGoalAscent = 5, eGoalActiveMinutes = 6 } goal_e; typedef enum { eGoalRecurrenceOff = 0, eGoalRecurrenceDaily = 1, eGoalRecurrenceWeekly = 2, eGoalRecurrenceMonthly = 3, eGoalRecurrenceYearly = 4, eGoalRecurrenceCustom = 5 } goal_recurrence_e; typedef enum { eGoalSourceAuto = 0, eGoalSourceCommunity = 1, eGoalSourceUser = 2 } goal_source_e; typedef enum { eScheduleWorkout = 0, eScheduleCourse = 1 } schedule_e; typedef enum { eCoursePointGeneric = 0, eCoursePointSummit = 1, eCoursePointValley = 2, eCoursePointWater = 3, eCoursePointFood = 4, eCoursePointDanger = 5, eCoursePointLeft = 6, eCoursePointRight = 7, eCoursePointStraight = 8, eCoursePointFirstAid = 9, eCoursePointFourthCategory = 10, eCoursePointThirdCategory = 11, eCoursePointSecondCategory = 12, eCoursePointFirstCategory = 13, eCoursePointHorsCategory = 14, eCoursePointSprint = 15, eCoursePointLeftFork = 16, eCoursePointRightFork = 17, eCoursePointMiddleFork = 18, eCoursePointSlightLeft = 19, eCoursePointSharpLeft = 20, eCoursePointSlightRight = 21, eCoursePointSharpRight = 22, eCoursePointUTurn = 23, eCoursePointSegmentStart = 24, eCoursePointSegmentEnd = 25 } course_point_e; typedef enum { eManufacturerGarmin = 1, eManufacturerGarminFr405Antfs = 2, eManufacturerZephyr = 3, eManufacturerDayton = 4, eManufacturerIdt = 5, eManufacturerSrm = 6, eManufacturerQuarq = 7, eManufacturerIbike = 8, eManufacturerSaris = 9, eManufacturerSparkHk = 10, eManufacturerTanita = 11, eManufacturerEchowell = 12, eManufacturerDynastreamOem = 13, eManufacturerNautilus = 14, eManufacturerDynastream = 15, eManufacturerTimex = 16, eManufacturerMetrigear = 17, eManufacturerXelic = 18, eManufacturerBeurer = 19, eManufacturerCardiosport = 20, eManufacturerAAndD = 21, eManufacturerHmm = 22, eManufacturerSuunto = 23, eManufacturerThitaElektronik = 24, eManufacturerGpulse = 25, eManufacturerCleanMobile = 26, eManufacturerPedalBrain = 27, eManufacturerPeaksware = 28, eManufacturerSaxonar = 29, eManufacturerLemondFitness = 30, eManufacturerDexcom = 31, eManufacturerWahooFitness = 32, eManufacturerOctaneFitness = 33, eManufacturerArchinoetics = 34, eManufacturerTheHurtBox = 35, eManufacturerCitizenSystems = 36, eManufacturerMagellan = 37, eManufacturerOsynce = 38, eManufacturerHolux = 39, eManufacturerConcept2 = 40, eManufacturerOneGiantLeap = 42, eManufacturerAceSensor = 43, eManufacturerBrimBrothers = 44, eManufacturerXplova = 45, eManufacturerPerceptionDigital = 46, eManufacturerBf1Systems = 47, eManufacturerPioneer = 48, eManufacturerSpantec = 49, eManufacturerMetalogics = 50, eManufacturer4Iiiis = 51, eManufacturerSeikoEpson = 52, eManufacturerSeikoEpsonOem = 53, eManufacturerIforPowell = 54, eManufacturerMaxwellGuider = 55, eManufacturerStarTrac = 56, eManufacturerBreakaway = 57, eManufacturerAlatechTechnologyLtd = 58, eManufacturerMioTechnologyEurope = 59, eManufacturerRotor = 60, eManufacturerGeonaute = 61, eManufacturerIdBike = 62, eManufacturerSpecialized = 63, eManufacturerWtek = 64, eManufacturerPhysicalEnterprises = 65, eManufacturerNorthPoleEngineering = 66, eManufacturerBkool = 67, eManufacturerCateye = 68, eManufacturerStagesCycling = 69, eManufacturerSigmasport = 70, eManufacturerTomtom = 71, eManufacturerPeripedal = 72, eManufacturerWattbike = 73, eManufacturerMoxy = 76, eManufacturerCiclosport = 77, eManufacturerPowerbahn = 78, eManufacturerAcornProjectsAps = 79, eManufacturerLifebeam = 80, eManufacturerBontrager = 81, eManufacturerWellgo = 82, eManufacturerScosche = 83, eManufacturerMagura = 84, eManufacturerWoodway = 85, eManufacturerElite = 86, eManufacturerNielsenKellerman = 87, eManufacturerDkCity = 88, eManufacturerTacx = 89, eManufacturerDirectionTechnology = 90, eManufacturerMagtonic = 91, eManufacturer1Partcarbon = 92, eManufacturerInsideRideTechnologies = 93, eManufacturerSoundOfMotion = 94, eManufacturerStryd = 95, eManufacturerIcg = 96, eManufacturerMipulse = 97, eManufacturerBsxAthletics = 98, eManufacturerLook = 99, eManufacturerCampagnoloSrl = 100, eManufacturerBodyBikeSmart = 101, eManufacturerPraxisworks = 102, eManufacturerLimitsTechnology = 103, eManufacturerTopactionTechnology = 104, eManufacturerCosinuss = 105, eManufacturerFitcare = 106, eManufacturerMagene = 107, eManufacturerGiantManufacturingCo = 108, eManufacturerTigrasport = 109, eManufacturerSalutron = 110, eManufacturerDevelopment = 255, eManufacturerHealthandlife = 257, eManufacturerLezyne = 258, eManufacturerScribeLabs = 259, eManufacturerZwift = 260, eManufacturerWatteam = 261, eManufacturerRecon = 262, eManufacturerFaveroElectronics = 263, eManufacturerDynovelo = 264, eManufacturerStrava = 265, eManufacturerPrecor = 266, eManufacturerBryton = 267, eManufacturerSram = 268, eManufacturerNavman = 269, eManufacturerCobi = 270, eManufacturerSpivi = 271, eManufacturerMioMagellan = 272, eManufacturerEvesports = 273, eManufacturerSensitivusGauge = 274, eManufacturerPodoon = 275, eManufacturerLifeTimeFitness = 276, eManufacturerFalcoEMotors = 277, eManufacturerActigraphcorp = 5759 } manufacturer_e; typedef enum { eGarminProductHrm1 = 1, eGarminProductAxh01 = 2, eGarminProductAxb01 = 3, eGarminProductAxb02 = 4, eGarminProductHrm2Ss = 5, eGarminProductDsiAlf02 = 6, eGarminProductHrm3Ss = 7, eGarminProductHrmRunSingleByteProductId = 8, eGarminProductBsm = 9, eGarminProductBcm = 10, eGarminProductAxs01 = 11, eGarminProductHrmTriSingleByteProductId = 12, eGarminProductFr225SingleByteProductId = 14, eGarminProductFr301China = 473, eGarminProductFr301Japan = 474, eGarminProductFr301Korea = 475, eGarminProductFr301Taiwan = 494, eGarminProductFr405 = 717, eGarminProductFr50 = 782, eGarminProductFr405Japan = 987, eGarminProductFr60 = 988, eGarminProductDsiAlf01 = 1011, eGarminProductFr310Xt = 1018, eGarminProductEdge500 = 1036, eGarminProductFr110 = 1124, eGarminProductEdge800 = 1169, eGarminProductEdge500Taiwan = 1199, eGarminProductEdge500Japan = 1213, eGarminProductChirp = 1253, eGarminProductFr110Japan = 1274, eGarminProductEdge200 = 1325, eGarminProductFr910Xt = 1328, eGarminProductEdge800Taiwan = 1333, eGarminProductEdge800Japan = 1334, eGarminProductAlf04 = 1341, eGarminProductFr610 = 1345, eGarminProductFr210Japan = 1360, eGarminProductVectorSs = 1380, eGarminProductVectorCp = 1381, eGarminProductEdge800China = 1386, eGarminProductEdge500China = 1387, eGarminProductFr610Japan = 1410, eGarminProductEdge500Korea = 1422, eGarminProductFr70 = 1436, eGarminProductFr310Xt4T = 1446, eGarminProductAmx = 1461, eGarminProductFr10 = 1482, eGarminProductEdge800Korea = 1497, eGarminProductSwim = 1499, eGarminProductFr910XtChina = 1537, eGarminProductFenix = 1551, eGarminProductEdge200Taiwan = 1555, eGarminProductEdge510 = 1561, eGarminProductEdge810 = 1567, eGarminProductTempe = 1570, eGarminProductFr910XtJapan = 1600, eGarminProductFr620 = 1623, eGarminProductFr220 = 1632, eGarminProductFr910XtKorea = 1664, eGarminProductFr10Japan = 1688, eGarminProductEdge810Japan = 1721, eGarminProductVirbElite = 1735, eGarminProductEdgeTouring = 1736, eGarminProductEdge510Japan = 1742, eGarminProductHrmTri = 1743, eGarminProductHrmRun = 1752, eGarminProductFr920Xt = 1765, eGarminProductEdge510Asia = 1821, eGarminProductEdge810China = 1822, eGarminProductEdge810Taiwan = 1823, eGarminProductEdge1000 = 1836, eGarminProductVivoFit = 1837, eGarminProductVirbRemote = 1853, eGarminProductVivoKi = 1885, eGarminProductFr15 = 1903, eGarminProductVivoActive = 1907, eGarminProductEdge510Korea = 1918, eGarminProductFr620Japan = 1928, eGarminProductFr620China = 1929, eGarminProductFr220Japan = 1930, eGarminProductFr220China = 1931, eGarminProductApproachS6 = 1936, eGarminProductVivoSmart = 1956, eGarminProductFenix2 = 1967, eGarminProductEpix = 1988, eGarminProductFenix3 = 2050, eGarminProductEdge1000Taiwan = 2052, eGarminProductEdge1000Japan = 2053, eGarminProductFr15Japan = 2061, eGarminProductEdge520 = 2067, eGarminProductEdge1000China = 2070, eGarminProductFr620Russia = 2072, eGarminProductFr220Russia = 2073, eGarminProductVectorS = 2079, eGarminProductEdge1000Korea = 2100, eGarminProductFr920XtTaiwan = 2130, eGarminProductFr920XtChina = 2131, eGarminProductFr920XtJapan = 2132, eGarminProductVirbx = 2134, eGarminProductVivoSmartApac = 2135, eGarminProductEtrexTouch = 2140, eGarminProductEdge25 = 2147, eGarminProductFr25 = 2148, eGarminProductVivoFit2 = 2150, eGarminProductFr225 = 2153, eGarminProductFr630 = 2156, eGarminProductFr230 = 2157, eGarminProductVivoActiveApac = 2160, eGarminProductVector2 = 2161, eGarminProductVector2S = 2162, eGarminProductVirbxe = 2172, eGarminProductFr620Taiwan = 2173, eGarminProductFr220Taiwan = 2174, eGarminProductTruswing = 2175, eGarminProductFenix3China = 2188, eGarminProductFenix3Twn = 2189, eGarminProductVariaHeadlight = 2192, eGarminProductVariaTaillightOld = 2193, eGarminProductEdgeExplore1000 = 2204, eGarminProductFr225Asia = 2219, eGarminProductVariaRadarTaillight = 2225, eGarminProductVariaRadarDisplay = 2226, eGarminProductEdge20 = 2238, eGarminProductD2Bravo = 2262, eGarminProductApproachS20 = 2266, eGarminProductVariaRemote = 2276, eGarminProductHrm4Run = 2327, eGarminProductVivoActiveHr = 2337, eGarminProductVivoSmartGpsHr = 2347, eGarminProductVivoSmartHr = 2348, eGarminProductVivoMove = 2368, eGarminProductVariaVision = 2398, eGarminProductVivoFit3 = 2406, eGarminProductFenix3Hr = 2413, eGarminProductIndexSmartScale = 2429, eGarminProductFr235 = 2431, eGarminProductOregon7Xx = 2441, eGarminProductRino7Xx = 2444, eGarminProductNautix = 2496, eGarminProductEdge820 = 2530, eGarminProductEdgeExplore820 = 2531, eGarminProductSdm4 = 10007, eGarminProductEdgeRemote = 10014, eGarminProductTrainingCenter = 20119, eGarminProductConnectiqSimulator = 65531, eGarminProductAndroidAntplusPlugin = 65532, eGarminProductConnect = 65534 } garmin_product_e; typedef enum { eAntplusDeviceTypeAntfs = 1, eAntplusDeviceTypeBikePower = 11, eAntplusDeviceTypeEnvironmentSensorLegacy = 12, eAntplusDeviceTypeMultiSportSpeedDistance = 15, eAntplusDeviceTypeControl = 16, eAntplusDeviceTypeFitnessEquipment = 17, eAntplusDeviceTypeBloodPressure = 18, eAntplusDeviceTypeGeocacheNode = 19, eAntplusDeviceTypeLightElectricVehicle = 20, eAntplusDeviceTypeEnvSensor = 25, eAntplusDeviceTypeRacquet = 26, eAntplusDeviceTypeControlHub = 27, eAntplusDeviceTypeMuscleOxygen = 31, eAntplusDeviceTypeBikeLightMain = 35, eAntplusDeviceTypeBikeLightShared = 36, eAntplusDeviceTypeExd = 38, eAntplusDeviceTypeBikeRadar = 40, eAntplusDeviceTypeWeightScale = 119, eAntplusDeviceTypeHeartRate = 120, eAntplusDeviceTypeBikeSpeedCadence = 121, eAntplusDeviceTypeBikeCadence = 122, eAntplusDeviceTypeBikeSpeed = 123, eAntplusDeviceTypeStrideSpeedDistance = 124 } antplus_device_type_e; typedef enum { eAntNetworkPublic = 0, eAntNetworkAntplus = 1, eAntNetworkAntfs = 2, eAntNetworkPrivate = 3 } ant_network_e; typedef enum { eWorkoutCapabilitiesInterval = 0x00000001, eWorkoutCapabilitiesCustom = 0x00000002, eWorkoutCapabilitiesFitnessEquipment = 0x00000004, eWorkoutCapabilitiesFirstbeat = 0x00000008, eWorkoutCapabilitiesNewLeaf = 0x00000010, eWorkoutCapabilitiesTcx = 0x00000020, eWorkoutCapabilitiesSpeed = 0x00000080, eWorkoutCapabilitiesHeartRate = 0x00000100, eWorkoutCapabilitiesDistance = 0x00000200, eWorkoutCapabilitiesCadence = 0x00000400, eWorkoutCapabilitiesPower = 0x00000800, eWorkoutCapabilitiesGrade = 0x00001000, eWorkoutCapabilitiesResistance = 0x00002000, eWorkoutCapabilitiesProtected = 0x00004000 } workout_capabilities_e; typedef enum { eBatteryStatusNew = 1, eBatteryStatusGood = 2, eBatteryStatusOk = 3, eBatteryStatusLow = 4, eBatteryStatusCritical = 5, eBatteryStatusCharging = 6, eBatteryStatusUnknown = 7 } battery_status_e; typedef enum { eHrTypeNormal = 0, eHrTypeIrregular = 1 } hr_type_e; typedef enum { eCourseCapabilitiesProcessed = 0x00000001, eCourseCapabilitiesValid = 0x00000002, eCourseCapabilitiesTime = 0x00000004, eCourseCapabilitiesDistance = 0x00000008, eCourseCapabilitiesPosition = 0x00000010, eCourseCapabilitiesHeartRate = 0x00000020, eCourseCapabilitiesPower = 0x00000040, eCourseCapabilitiesCadence = 0x00000080, eCourseCapabilitiesTraining = 0x00000100, eCourseCapabilitiesNavigation = 0x00000200, eCourseCapabilitiesBikeway = 0x00000400 } course_capabilities_e; typedef enum { eWeightCalculating = 0xFFFE } weight_e; typedef enum { eWorkoutHrBpmOffset = 100 } workout_hr_e; typedef enum { eWorkoutPowerWattsOffset = 1000 } workout_power_e; typedef enum { eBpStatusNoError = 0, eBpStatusErrorIncompleteData = 1, eBpStatusErrorNoMeasurement = 2, eBpStatusErrorDataOutOfRange = 3, eBpStatusErrorIrregularHeartRate = 4 } bp_status_e; typedef enum { eUserLocalIdLocalMin = 0x0000, eUserLocalIdLocalMax = 0x000F, eUserLocalIdStationaryMin = 0x0010, eUserLocalIdStationaryMax = 0x00FF, eUserLocalIdPortableMin = 0x0100, eUserLocalIdPortableMax = 0xFFFE } user_local_id_e; typedef enum { eSwimStrokeFreestyle = 0, eSwimStrokeBackstroke = 1, eSwimStrokeBreaststroke = 2, eSwimStrokeButterfly = 3, eSwimStrokeDrill = 4, eSwimStrokeMixed = 5, eSwimStrokeIm = 6 } swim_stroke_e; typedef enum { eActivityTypeGeneric = 0, eActivityTypeRunning = 1, eActivityTypeCycling = 2, eActivityTypeTransition = 3, eActivityTypeFitnessEquipment = 4, eActivityTypeSwimming = 5, eActivityTypeWalking = 6, eActivityTypeSedentary = 8, eActivityTypeAll = 254 } activity_type_e; typedef enum { eActivitySubtypeGeneric = 0, eActivitySubtypeTreadmill = 1, eActivitySubtypeStreet = 2, eActivitySubtypeTrail = 3, eActivitySubtypeTrack = 4, eActivitySubtypeSpin = 5, eActivitySubtypeIndoorCycling = 6, eActivitySubtypeRoad = 7, eActivitySubtypeMountain = 8, eActivitySubtypeDownhill = 9, eActivitySubtypeRecumbent = 10, eActivitySubtypeCyclocross = 11, eActivitySubtypeHandCycling = 12, eActivitySubtypeTrackCycling = 13, eActivitySubtypeIndoorRowing = 14, eActivitySubtypeElliptical = 15, eActivitySubtypeStairClimbing = 16, eActivitySubtypeLapSwimming = 17, eActivitySubtypeOpenWater = 18, eActivitySubtypeAll = 254 } activity_subtype_e; typedef enum { eActivityLevelLow = 0, eActivityLevelMedium = 1, eActivityLevelHigh = 2 } activity_level_e; typedef enum { eSideRight = 0, eSideLeft = 1 } side_e; typedef enum { eLeftRightBalanceMask = 0x7F, eLeftRightBalanceRight = 0x80 } left_right_balance_e; typedef enum { eLeftRightBalance100Mask = 0x3FFF, eLeftRightBalance100Right = 0x8000 } left_right_balance_100_e; typedef enum { eLengthTypeIdle = 0, eLengthTypeActive = 1 } length_type_e; typedef enum { eDayOfWeekSunday = 0, eDayOfWeekMonday = 1, eDayOfWeekTuesday = 2, eDayOfWeekWednesday = 3, eDayOfWeekThursday = 4, eDayOfWeekFriday = 5, eDayOfWeekSaturday = 6 } day_of_week_e; typedef enum { eConnectivityCapabilitiesBluetooth = 0x00000001, eConnectivityCapabilitiesBluetoothLe = 0x00000002, eConnectivityCapabilitiesAnt = 0x00000004, eConnectivityCapabilitiesActivityUpload = 0x00000008, eConnectivityCapabilitiesCourseDownload = 0x00000010, eConnectivityCapabilitiesWorkoutDownload = 0x00000020, eConnectivityCapabilitiesLiveTrack = 0x00000040, eConnectivityCapabilitiesWeatherConditions = 0x00000080, eConnectivityCapabilitiesWeatherAlerts = 0x00000100, eConnectivityCapabilitiesGpsEphemerisDownload = 0x00000200, eConnectivityCapabilitiesExplicitArchive = 0x00000400, eConnectivityCapabilitiesSetupIncomplete = 0x00000800, eConnectivityCapabilitiesContinueSyncAfterSoftwareUpdate = 0x00001000, eConnectivityCapabilitiesConnectIqAppDownload = 0x00002000, eConnectivityCapabilitiesGolfCourseDownload = 0x00004000, eConnectivityCapabilitiesDeviceInitiatesSync = 0x00008000, eConnectivityCapabilitiesConnectIqWatchAppDownload = 0x00010000, eConnectivityCapabilitiesConnectIqWidgetDownload = 0x00020000, eConnectivityCapabilitiesConnectIqWatchFaceDownload = 0x00040000, eConnectivityCapabilitiesConnectIqDataFieldDownload = 0x00080000, eConnectivityCapabilitiesConnectIqAppManagment = 0x00100000, eConnectivityCapabilitiesSwingSensor = 0x00200000, eConnectivityCapabilitiesSwingSensorRemote = 0x00400000, eConnectivityCapabilitiesIncidentDetection = 0x00800000, eConnectivityCapabilitiesAudioPrompts = 0x01000000, eConnectivityCapabilitiesWifiVerification = 0x02000000, eConnectivityCapabilitiesTrueUp = 0x04000000, eConnectivityCapabilitiesFindMyWatch = 0x08000000, eConnectivityCapabilitiesRemoteManualSync = 0x10000000, eConnectivityCapabilitiesLiveTrackAutoStart = 0x20000000, eConnectivityCapabilitiesLiveTrackMessaging = 0x40000000, eConnectivityCapabilitiesInstantInput = 0x80000000 } connectivity_capabilities_e; typedef enum { eWeatherReportCurrent = 0, eWeatherReportForecast = 1, eWeatherReportHourlyForecast = 1, eWeatherReportDailyForecast = 2 } weather_report_e; typedef enum { eWeatherStatusClear = 0, eWeatherStatusPartlyCloudy = 1, eWeatherStatusMostlyCloudy = 2, eWeatherStatusRain = 3, eWeatherStatusSnow = 4, eWeatherStatusWindy = 5, eWeatherStatusThunderstorms = 6, eWeatherStatusWintryMix = 7, eWeatherStatusFog = 8, eWeatherStatusHazy = 11, eWeatherStatusHail = 12, eWeatherStatusScatteredShowers = 13, eWeatherStatusScatteredThunderstorms = 14, eWeatherStatusUnknownPrecipitation = 15, eWeatherStatusLightRain = 16, eWeatherStatusHeavyRain = 17, eWeatherStatusLightSnow = 18, eWeatherStatusHeavySnow = 19, eWeatherStatusLightRainSnow = 20, eWeatherStatusHeavyRainSnow = 21, eWeatherStatusCloudy = 22 } weather_status_e; typedef enum { eWeatherSeverityUnknown = 0, eWeatherSeverityWarning = 1, eWeatherSeverityWatch = 2, eWeatherSeverityAdvisory = 3, eWeatherSeverityStatement = 4 } weather_severity_e; typedef enum { eWeatherSevereTypeUnspecified = 0, eWeatherSevereTypeTornado = 1, eWeatherSevereTypeTsunami = 2, eWeatherSevereTypeHurricane = 3, eWeatherSevereTypeExtremeWind = 4, eWeatherSevereTypeTyphoon = 5, eWeatherSevereTypeInlandHurricane = 6, eWeatherSevereTypeHurricaneForceWind = 7, eWeatherSevereTypeWaterspout = 8, eWeatherSevereTypeSevereThunderstorm = 9, eWeatherSevereTypeWreckhouseWinds = 10, eWeatherSevereTypeLesSuetesWind = 11, eWeatherSevereTypeAvalanche = 12, eWeatherSevereTypeFlashFlood = 13, eWeatherSevereTypeTropicalStorm = 14, eWeatherSevereTypeInlandTropicalStorm = 15, eWeatherSevereTypeBlizzard = 16, eWeatherSevereTypeIceStorm = 17, eWeatherSevereTypeFreezingRain = 18, eWeatherSevereTypeDebrisFlow = 19, eWeatherSevereTypeFlashFreeze = 20, eWeatherSevereTypeDustStorm = 21, eWeatherSevereTypeHighWind = 22, eWeatherSevereTypeWinterStorm = 23, eWeatherSevereTypeHeavyFreezingSpray = 24, eWeatherSevereTypeExtremeCold = 25, eWeatherSevereTypeWindChill = 26, eWeatherSevereTypeColdWave = 27, eWeatherSevereTypeHeavySnowAlert = 28, eWeatherSevereTypeLakeEffectBlowingSnow = 29, eWeatherSevereTypeSnowSquall = 30, eWeatherSevereTypeLakeEffectSnow = 31, eWeatherSevereTypeWinterWeather = 32, eWeatherSevereTypeSleet = 33, eWeatherSevereTypeSnowfall = 34, eWeatherSevereTypeSnowAndBlowingSnow = 35, eWeatherSevereTypeBlowingSnow = 36, eWeatherSevereTypeSnowAlert = 37, eWeatherSevereTypeArcticOutflow = 38, eWeatherSevereTypeFreezingDrizzle = 39, eWeatherSevereTypeStorm = 40, eWeatherSevereTypeStormSurge = 41, eWeatherSevereTypeRainfall = 42, eWeatherSevereTypeArealFlood = 43, eWeatherSevereTypeCoastalFlood = 44, eWeatherSevereTypeLakeshoreFlood = 45, eWeatherSevereTypeExcessiveHeat = 46, eWeatherSevereTypeHeat = 47, eWeatherSevereTypeWeather = 48, eWeatherSevereTypeHighHeatAndHumidity = 49, eWeatherSevereTypeHumidexAndHealth = 50, eWeatherSevereTypeHumidex = 51, eWeatherSevereTypeGale = 52, eWeatherSevereTypeFreezingSpray = 53, eWeatherSevereTypeSpecialMarine = 54, eWeatherSevereTypeSquall = 55, eWeatherSevereTypeStrongWind = 56, eWeatherSevereTypeLakeWind = 57, eWeatherSevereTypeMarineWeather = 58, eWeatherSevereTypeWind = 59, eWeatherSevereTypeSmallCraftHazardousSeas = 60, eWeatherSevereTypeHazardousSeas = 61, eWeatherSevereTypeSmallCraft = 62, eWeatherSevereTypeSmallCraftWinds = 63, eWeatherSevereTypeSmallCraftRoughBar = 64, eWeatherSevereTypeHighWaterLevel = 65, eWeatherSevereTypeAshfall = 66, eWeatherSevereTypeFreezingFog = 67, eWeatherSevereTypeDenseFog = 68, eWeatherSevereTypeDenseSmoke = 69, eWeatherSevereTypeBlowingDust = 70, eWeatherSevereTypeHardFreeze = 71, eWeatherSevereTypeFreeze = 72, eWeatherSevereTypeFrost = 73, eWeatherSevereTypeFireWeather = 74, eWeatherSevereTypeFlood = 75, eWeatherSevereTypeRipTide = 76, eWeatherSevereTypeHighSurf = 77, eWeatherSevereTypeSmog = 78, eWeatherSevereTypeAirQuality = 79, eWeatherSevereTypeBriskWind = 80, eWeatherSevereTypeAirStagnation = 81, eWeatherSevereTypeLowWater = 82, eWeatherSevereTypeHydrological = 83, eWeatherSevereTypeSpecialWeather = 84 } weather_severe_type_e; typedef enum { eStrokeTypeNoEvent = 0, eStrokeTypeOther = 1, eStrokeTypeServe = 2, eStrokeTypeForehand = 3, eStrokeTypeBackhand = 4, eStrokeTypeSmash = 5 } stroke_type_e; typedef enum { eBodyLocationLeftLeg = 0, eBodyLocationLeftCalf = 1, eBodyLocationLeftShin = 2, eBodyLocationLeftHamstring = 3, eBodyLocationLeftQuad = 4, eBodyLocationLeftGlute = 5, eBodyLocationRightLeg = 6, eBodyLocationRightCalf = 7, eBodyLocationRightShin = 8, eBodyLocationRightHamstring = 9, eBodyLocationRightQuad = 10, eBodyLocationRightGlute = 11, eBodyLocationTorsoBack = 12, eBodyLocationLeftLowerBack = 13, eBodyLocationLeftUpperBack = 14, eBodyLocationRightLowerBack = 15, eBodyLocationRightUpperBack = 16, eBodyLocationTorsoFront = 17, eBodyLocationLeftAbdomen = 18, eBodyLocationLeftChest = 19, eBodyLocationRightAbdomen = 20, eBodyLocationRightChest = 21, eBodyLocationLeftArm = 22, eBodyLocationLeftShoulder = 23, eBodyLocationLeftBicep = 24, eBodyLocationLeftTricep = 25, eBodyLocationLeftBrachioradialis = 26, eBodyLocationLeftForearmExtensors = 27, eBodyLocationRightArm = 28, eBodyLocationRightShoulder = 29, eBodyLocationRightBicep = 30, eBodyLocationRightTricep = 31, eBodyLocationRightBrachioradialis = 32, eBodyLocationRightForearmExtensors = 33, eBodyLocationNeck = 34, eBodyLocationThroat = 35, eBodyLocationWaistMidBack = 36, eBodyLocationWaistFront = 37, eBodyLocationWaistLeft = 38, eBodyLocationWaistRight = 39 } body_location_e; typedef enum { eSegmentLapStatusEnd = 0, eSegmentLapStatusFail = 1 } segment_lap_status_e; typedef enum { eSegmentLeaderboardTypeOverall = 0, eSegmentLeaderboardTypePersonalBest = 1, eSegmentLeaderboardTypeConnections = 2, eSegmentLeaderboardTypeGroup = 3, eSegmentLeaderboardTypeChallenger = 4, eSegmentLeaderboardTypeKom = 5, eSegmentLeaderboardTypeQom = 6, eSegmentLeaderboardTypePr = 7, eSegmentLeaderboardTypeGoal = 8, eSegmentLeaderboardTypeRival = 9, eSegmentLeaderboardTypeClubLeader = 10 } segment_leaderboard_type_e; typedef enum { eSegmentDeleteStatusDoNotDelete = 0, eSegmentDeleteStatusDeleteOne = 1, eSegmentDeleteStatusDeleteAll = 2 } segment_delete_status_e; typedef enum { eSegmentSelectionTypeStarred = 0, eSegmentSelectionTypeSuggested = 1 } segment_selection_type_e; typedef enum { eSourceTypeAnt = 0, eSourceTypeAntplus = 1, eSourceTypeBluetooth = 2, eSourceTypeBluetoothLowEnergy = 3, eSourceTypeWifi = 4, eSourceTypeLocal = 5 } source_type_e; typedef enum { eDisplayOrientationAuto = 0, eDisplayOrientationPortrait = 1, eDisplayOrientationLandscape = 2, eDisplayOrientationPortraitFlipped = 3, eDisplayOrientationLandscapeFlipped = 4 } display_orientation_e; typedef enum { eWatchfaceModeDigital = 0, eWatchfaceModeAnalog = 1, eWatchfaceModeConnectIq = 2 } watchface_mode_e; typedef enum { eDigitalWatchfaceLayoutTraditional = 0, eDigitalWatchfaceLayoutModern = 1, eDigitalWatchfaceLayoutBold = 2 } digital_watchface_layout_e; typedef enum { eAnalogWatchfaceLayoutMinimal = 0, eAnalogWatchfaceLayoutTraditional = 1, eAnalogWatchfaceLayoutModern = 2 } analog_watchface_layout_e; typedef enum { eRiderPositionTypeSeated = 0, eRiderPositionTypeStanding = 1 } rider_position_type_e; typedef enum { ePowerPhaseTypePowerPhaseStartAngle = 0, ePowerPhaseTypePowerPhaseEndAngle = 1, ePowerPhaseTypePowerPhaseArcLength = 2, ePowerPhaseTypePowerPhaseCenter = 3 } power_phase_type_e; typedef enum { eCameraEventTypeVideoStart = 0, eCameraEventTypeVideoSplit = 1, eCameraEventTypeVideoEnd = 2, eCameraEventTypePhotoTaken = 3, eCameraEventTypeVideoSecondStreamStart = 4, eCameraEventTypeVideoSecondStreamSplit = 5, eCameraEventTypeVideoSecondStreamEnd = 6, eCameraEventTypeVideoSplitStart = 7, eCameraEventTypeVideoSecondStreamSplitStart = 8, eCameraEventTypeVideoPause = 11, eCameraEventTypeVideoSecondStreamPause = 12, eCameraEventTypeVideoResume = 13, eCameraEventTypeVideoSecondStreamResume = 14 } camera_event_type_e; typedef enum { eSensorTypeAccelerometer = 0, eSensorTypeGyroscope = 1, eSensorTypeCompass = 2 } sensor_type_e; typedef enum { eBikeLightNetworkConfigTypeAuto = 0, eBikeLightNetworkConfigTypeIndividual = 4, eBikeLightNetworkConfigTypeHighVisibility = 5, eBikeLightNetworkConfigTypeTrail = 6 } bike_light_network_config_type_e; typedef enum { eCommTimeoutTypeWildcardPairingTimeout = 0, eCommTimeoutTypePairingTimeout = 1, eCommTimeoutTypeConnectionLost = 2, eCommTimeoutTypeConnectionTimeout = 3 } comm_timeout_type_e; typedef enum { eCameraOrientationTypeCameraOrientation0 = 0, eCameraOrientationTypeCameraOrientation90 = 1, eCameraOrientationTypeCameraOrientation180 = 2, eCameraOrientationTypeCameraOrientation270 = 3 } camera_orientation_type_e; typedef enum { eAttitudeStageFailed = 0, eAttitudeStageAligning = 1, eAttitudeStageDegraded = 2, eAttitudeStageValid = 3 } attitude_stage_e; typedef enum { eAttitudeValidityTrackAngleHeadingValid = 0x0001, eAttitudeValidityPitchValid = 0x0002, eAttitudeValidityRollValid = 0x0004, eAttitudeValidityLateralBodyAccelValid = 0x0008, eAttitudeValidityNormalBodyAccelValid = 0x0010, eAttitudeValidityTurnRateValid = 0x0020, eAttitudeValidityHwFail = 0x0040, eAttitudeValidityMagInvalid = 0x0080, eAttitudeValidityNoGps = 0x0100, eAttitudeValidityGpsInvalid = 0x0200, eAttitudeValiditySolutionCoasting = 0x0400, eAttitudeValidityTrueTrackAngle = 0x0800, eAttitudeValidityMagneticHeading = 0x1000 } attitude_validity_e; typedef enum { eAutoSyncFrequencyNever = 0, eAutoSyncFrequencyOccasionally = 1, eAutoSyncFrequencyFrequent = 2, eAutoSyncFrequencyOnceADay = 3 } auto_sync_frequency_e; typedef enum { eExdLayoutFullScreen = 0, eExdLayoutHalfVertical = 1, eExdLayoutHalfHorizontal = 2, eExdLayoutHalfVerticalRightSplit = 3, eExdLayoutHalfHorizontalBottomSplit = 4, eExdLayoutFullQuarterSplit = 5, eExdLayoutHalfVerticalLeftSplit = 6, eExdLayoutHalfHorizontalTopSplit = 7 } exd_layout_e; typedef enum { eExdDisplayTypeNumerical = 0, eExdDisplayTypeSimple = 1, eExdDisplayTypeGraph = 2, eExdDisplayTypeBar = 3, eExdDisplayTypeCircleGraph = 4, eExdDisplayTypeVirtualPartner = 5, eExdDisplayTypeBalance = 6, eExdDisplayTypeStringList = 7, eExdDisplayTypeString = 8, eExdDisplayTypeSimpleDynamicIcon = 9, eExdDisplayTypeGauge = 10 } exd_display_type_e; typedef enum { eExdDataUnitsNoUnits = 0, eExdDataUnitsLaps = 1, eExdDataUnitsMilesPerHour = 2, eExdDataUnitsKilometersPerHour = 3, eExdDataUnitsFeetPerHour = 4, eExdDataUnitsMetersPerHour = 5, eExdDataUnitsDegreesCelsius = 6, eExdDataUnitsDegreesFarenheit = 7, eExdDataUnitsZone = 8, eExdDataUnitsGear = 9, eExdDataUnitsRpm = 10, eExdDataUnitsBpm = 11, eExdDataUnitsDegrees = 12, eExdDataUnitsMillimeters = 13, eExdDataUnitsMeters = 14, eExdDataUnitsKilometers = 15, eExdDataUnitsFeet = 16, eExdDataUnitsYards = 17, eExdDataUnitsKilofeet = 18, eExdDataUnitsMiles = 19, eExdDataUnitsTime = 20, eExdDataUnitsEnumTurnType = 21, eExdDataUnitsPercent = 22, eExdDataUnitsWatts = 23, eExdDataUnitsWattsPerKilogram = 24, eExdDataUnitsEnumBatteryStatus = 25, eExdDataUnitsEnumBikeLightBeamAngleMode = 26, eExdDataUnitsEnumBikeLightBatteryStatus = 27, eExdDataUnitsEnumBikeLightNetworkConfigType = 28, eExdDataUnitsLights = 29, eExdDataUnitsSeconds = 30, eExdDataUnitsMinutes = 31, eExdDataUnitsHours = 32, eExdDataUnitsCalories = 33, eExdDataUnitsKilojoules = 34, eExdDataUnitsMilliseconds = 35, eExdDataUnitsSecondPerMile = 36, eExdDataUnitsSecondPerKilometer = 37, eExdDataUnitsCentimeter = 38, eExdDataUnitsEnumCoursePoint = 39, eExdDataUnitsBradians = 40, eExdDataUnitsEnumSport = 41, eExdDataUnitsInchesHg = 42, eExdDataUnitsMmHg = 43, eExdDataUnitsMbars = 44, eExdDataUnitsHectoPascals = 45, eExdDataUnitsFeetPerMin = 46, eExdDataUnitsMetersPerMin = 47, eExdDataUnitsMetersPerSec = 48, eExdDataUnitsEightCardinal = 49 } exd_data_units_e; typedef enum { eExdQualifiersNoQualifier = 0, eExdQualifiersInstantaneous = 1, eExdQualifiersAverage = 2, eExdQualifiersLap = 3, eExdQualifiersMaximum = 4, eExdQualifiersMaximumAverage = 5, eExdQualifiersMaximumLap = 6, eExdQualifiersLastLap = 7, eExdQualifiersAverageLap = 8, eExdQualifiersToDestination = 9, eExdQualifiersToGo = 10, eExdQualifiersToNext = 11, eExdQualifiersNextCoursePoint = 12, eExdQualifiersTotal = 13, eExdQualifiersThreeSecondAverage = 14, eExdQualifiersTenSecondAverage = 15, eExdQualifiersThirtySecondAverage = 16, eExdQualifiersPercentMaximum = 17, eExdQualifiersPercentMaximumAverage = 18, eExdQualifiersLapPercentMaximum = 19, eExdQualifiersElapsed = 20, eExdQualifiersSunrise = 21, eExdQualifiersSunset = 22, eExdQualifiersComparedToVirtualPartner = 23, eExdQualifiersMaximum24H = 24, eExdQualifiersMinimum24H = 25, eExdQualifiersMinimum = 26, eExdQualifiersFirst = 27, eExdQualifiersSecond = 28, eExdQualifiersThird = 29, eExdQualifiersShifter = 30, eExdQualifiersLastSport = 31, eExdQualifiersMoving = 32, eExdQualifiersStopped = 33, eExdQualifiersZone9 = 242, eExdQualifiersZone8 = 243, eExdQualifiersZone7 = 244, eExdQualifiersZone6 = 245, eExdQualifiersZone5 = 246, eExdQualifiersZone4 = 247, eExdQualifiersZone3 = 248, eExdQualifiersZone2 = 249, eExdQualifiersZone1 = 250 } exd_qualifiers_e; typedef enum { eExdDescriptorsBikeLightBatteryStatus = 0, eExdDescriptorsBeamAngleStatus = 1, eExdDescriptorsBateryLevel = 2, eExdDescriptorsLightNetworkMode = 3, eExdDescriptorsNumberLightsConnected = 4, eExdDescriptorsCadence = 5, eExdDescriptorsDistance = 6, eExdDescriptorsEstimatedTimeOfArrival = 7, eExdDescriptorsHeading = 8, eExdDescriptorsTime = 9, eExdDescriptorsBatteryLevel = 10, eExdDescriptorsTrainerResistance = 11, eExdDescriptorsTrainerTargetPower = 12, eExdDescriptorsTimeSeated = 13, eExdDescriptorsTimeStanding = 14, eExdDescriptorsElevation = 15, eExdDescriptorsGrade = 16, eExdDescriptorsAscent = 17, eExdDescriptorsDescent = 18, eExdDescriptorsVerticalSpeed = 19, eExdDescriptorsDi2BatteryLevel = 20, eExdDescriptorsFrontGear = 21, eExdDescriptorsRearGear = 22, eExdDescriptorsGearRatio = 23, eExdDescriptorsHeartRate = 24, eExdDescriptorsHeartRateZone = 25, eExdDescriptorsTimeInHeartRateZone = 26, eExdDescriptorsHeartRateReserve = 27, eExdDescriptorsCalories = 28, eExdDescriptorsGpsAccuracy = 29, eExdDescriptorsGpsSignalStrength = 30, eExdDescriptorsTemperature = 31, eExdDescriptorsTimeOfDay = 32, eExdDescriptorsBalance = 33, eExdDescriptorsPedalSmoothness = 34, eExdDescriptorsPower = 35, eExdDescriptorsFunctionalThresholdPower = 36, eExdDescriptorsIntensityFactor = 37, eExdDescriptorsWork = 38, eExdDescriptorsPowerRatio = 39, eExdDescriptorsNormalizedPower = 40, eExdDescriptorsTrainingStressScore = 41, eExdDescriptorsTimeOnZone = 42, eExdDescriptorsSpeed = 43, eExdDescriptorsLaps = 44, eExdDescriptorsReps = 45, eExdDescriptorsWorkoutStep = 46, eExdDescriptorsCourseDistance = 47, eExdDescriptorsNavigationDistance = 48, eExdDescriptorsCourseEstimatedTimeOfArrival = 49, eExdDescriptorsNavigationEstimatedTimeOfArrival = 50, eExdDescriptorsCourseTime = 51, eExdDescriptorsNavigationTime = 52, eExdDescriptorsCourseHeading = 53, eExdDescriptorsNavigationHeading = 54, eExdDescriptorsPowerZone = 55, eExdDescriptorsTorqueEffectiveness = 56, eExdDescriptorsTimerTime = 57, eExdDescriptorsPowerWeightRatio = 58, eExdDescriptorsLeftPlatformCenterOffset = 59, eExdDescriptorsRightPlatformCenterOffset = 60, eExdDescriptorsLeftPowerPhaseStartAngle = 61, eExdDescriptorsRightPowerPhaseStartAngle = 62, eExdDescriptorsLeftPowerPhaseFinishAngle = 63, eExdDescriptorsRightPowerPhaseFinishAngle = 64, eExdDescriptorsGears = 65, eExdDescriptorsPace = 66, eExdDescriptorsTrainingEffect = 67, eExdDescriptorsVerticalOscillation = 68, eExdDescriptorsVerticalRatio = 69, eExdDescriptorsGroundContactTime = 70, eExdDescriptorsLeftGroundContactTimeBalance = 71, eExdDescriptorsRightGroundContactTimeBalance = 72, eExdDescriptorsStrideLength = 73, eExdDescriptorsRunningCadence = 74, eExdDescriptorsPerformanceCondition = 75, eExdDescriptorsCourseType = 76, eExdDescriptorsTimeInPowerZone = 77, eExdDescriptorsNavigationTurn = 78, eExdDescriptorsCourseLocation = 79, eExdDescriptorsNavigationLocation = 80, eExdDescriptorsCompass = 81, eExdDescriptorsGearCombo = 82, eExdDescriptorsMuscleOxygen = 83, eExdDescriptorsIcon = 84, eExdDescriptorsCompassHeading = 85, eExdDescriptorsGpsHeading = 86, eExdDescriptorsGpsElevation = 87, eExdDescriptorsAnaerobicTrainingEffect = 88, eExdDescriptorsCourse = 89, eExdDescriptorsOffCourse = 90, eExdDescriptorsGlideRatio = 91, eExdDescriptorsVerticalDistance = 92, eExdDescriptorsVmg = 93, eExdDescriptorsAmbientPressure = 94, eExdDescriptorsPressure = 95 } exd_descriptors_e; typedef enum { eAutoActivityDetectNone = 0x00000000, eAutoActivityDetectRunning = 0x00000001, eAutoActivityDetectCycling = 0x00000002, eAutoActivityDetectSwimming = 0x00000004, eAutoActivityDetectWalking = 0x00000008, eAutoActivityDetectElliptical = 0x00000020, eAutoActivityDetectSedentary = 0x00000400 } auto_activity_detect_e; typedef enum { eSupportedExdScreenLayoutsFullScreen = 0x00000001, eSupportedExdScreenLayoutsHalfVertical = 0x00000002, eSupportedExdScreenLayoutsHalfHorizontal = 0x00000004, eSupportedExdScreenLayoutsHalfVerticalRightSplit = 0x00000008, eSupportedExdScreenLayoutsHalfHorizontalBottomSplit = 0x00000010, eSupportedExdScreenLayoutsFullQuarterSplit = 0x00000020, eSupportedExdScreenLayoutsHalfVerticalLeftSplit = 0x00000040, eSupportedExdScreenLayoutsHalfHorizontalTopSplit = 0x00000080 } supported_exd_screen_layouts_e; typedef enum { eFitBaseTypeEnum = 0, eFitBaseTypeSint8 = 1, eFitBaseTypeUint8 = 2, eFitBaseTypeSint16 = 131, eFitBaseTypeUint16 = 132, eFitBaseTypeSint32 = 133, eFitBaseTypeUint32 = 134, eFitBaseTypeString = 7, eFitBaseTypeFloat32 = 136, eFitBaseTypeFloat64 = 137, eFitBaseTypeUint8Z = 10, eFitBaseTypeUint16Z = 139, eFitBaseTypeUint32Z = 140, eFitBaseTypeByte = 13, eFitBaseTypeSint64 = 142, eFitBaseTypeUint64 = 143, eFitBaseTypeUint64Z = 144 } fit_base_type_e; typedef enum { eTurnTypeArrivingIdx = 0, eTurnTypeArrivingLeftIdx = 1, eTurnTypeArrivingRightIdx = 2, eTurnTypeArrivingViaIdx = 3, eTurnTypeArrivingViaLeftIdx = 4, eTurnTypeArrivingViaRightIdx = 5, eTurnTypeBearKeepLeftIdx = 6, eTurnTypeBearKeepRightIdx = 7, eTurnTypeContinueIdx = 8, eTurnTypeExitLeftIdx = 9, eTurnTypeExitRightIdx = 10, eTurnTypeFerryIdx = 11, eTurnTypeRoundabout45Idx = 12, eTurnTypeRoundabout90Idx = 13, eTurnTypeRoundabout135Idx = 14, eTurnTypeRoundabout180Idx = 15, eTurnTypeRoundabout225Idx = 16, eTurnTypeRoundabout270Idx = 17, eTurnTypeRoundabout315Idx = 18, eTurnTypeRoundabout360Idx = 19, eTurnTypeRoundaboutNeg45Idx = 20, eTurnTypeRoundaboutNeg90Idx = 21, eTurnTypeRoundaboutNeg135Idx = 22, eTurnTypeRoundaboutNeg180Idx = 23, eTurnTypeRoundaboutNeg225Idx = 24, eTurnTypeRoundaboutNeg270Idx = 25, eTurnTypeRoundaboutNeg315Idx = 26, eTurnTypeRoundaboutNeg360Idx = 27, eTurnTypeRoundaboutGenericIdx = 28, eTurnTypeRoundaboutNegGenericIdx = 29, eTurnTypeSharpTurnLeftIdx = 30, eTurnTypeSharpTurnRightIdx = 31, eTurnTypeTurnLeftIdx = 32, eTurnTypeTurnRightIdx = 33, eTurnTypeUturnLeftIdx = 34, eTurnTypeUturnRightIdx = 35, eTurnTypeIconInvIdx = 36, eTurnTypeIconIdxCnt = 37 } turn_type_e; typedef enum { eBikeLightBeamAngleModeManual = 0, eBikeLightBeamAngleModeAuto = 1 } bike_light_beam_angle_mode_e; typedef enum { eFitBaseUnitOther = 0, eFitBaseUnitKilogram = 1, eFitBaseUnitPound = 2 } fit_base_unit_e; // ----------- end generated code ----------- #endif // FIT_PROFILE_H qmapshack-1.10.0/src/gis/fit/defs/CFitProfile.h000644 001750 000144 00000004140 13216234143 022313 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITPROFILE_H #define CFITPROFILE_H #include class CFitFieldProfile; class CFitBaseType; class CFitProfile final { public: CFitProfile(); CFitProfile(const CFitProfile& copy); CFitProfile(QString name, quint16 globalMesgNr); virtual ~CFitProfile(); void addField(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units); void addSubfield(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, quint16 offset, QString units, quint8 subRefFieldDefNr, quint8 subRefFieldValue); void addComponent(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits); void addComponent(int subfieldIndex, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits); const CFitFieldProfile* getField(quint8 fieldDefNr) const; QString getName() const { return name; } quint16 getGlobalMesgNr() const { return globalMesgNr; } private: QString name; quint16 globalMesgNr; QMap fields; }; #endif // CFITPROFILE_H qmapshack-1.10.0/src/gis/fit/defs/CFitBaseType.cpp000644 001750 000144 00000010413 13216234140 022757 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/defs/CFitBaseType.h" CFitBaseType::CFitBaseType() : CFitBaseType(eBaseTypeNrInvalid, "invalid", 0, { 0 }) { } CFitBaseType::CFitBaseType(fit_base_type_nr_e baseTypeNr, QString name, quint8 size, std::initializer_list invalid) : typeSize(size), baseTypeNr(baseTypeNr), namestr(name) { quint8 i = (quint8) (size - 1); for(quint8 bit : invalid) { invalidBytes[i--] = bit; } } quint8 CFitBaseType::size() const { return typeSize; } bool CFitBaseType::isSizeUndefined() const { return typeSize == 0; } fit_base_type_nr_e CFitBaseType::nr() const { return baseTypeNr; } quint8 CFitBaseType::baseTypeField() const { if(typeSize > 1) { return (quint8) (0x80 | baseTypeNr); } return baseTypeNr; } const quint8* CFitBaseType::invalidValueBytes() const { return invalidBytes; } bool CFitBaseType::isInteger() const { return isSignedInt() || isUnsignedInt(); } bool CFitBaseType::isSignedInt() const { return baseTypeNr == eBaseTypeNrSint8 || baseTypeNr == eBaseTypeNrSint16 || baseTypeNr == eBaseTypeNrSint32 || baseTypeNr == eBaseTypeNrSint64; } bool CFitBaseType::isUnsignedInt() const { return baseTypeNr == eBaseTypeNrUint8 || baseTypeNr == eBaseTypeNrUint8z || baseTypeNr == eBaseTypeNrUint16 || baseTypeNr == eBaseTypeNrUint16z || baseTypeNr == eBaseTypeNrUint32 || baseTypeNr == eBaseTypeNrUint32z || baseTypeNr == eBaseTypeNrUint64 || baseTypeNr == eBaseTypeNrUint64z || baseTypeNr == eBaseTypeNrEnum; } bool CFitBaseType::isFloat() const { return baseTypeNr == eBaseTypeNrFloat32 || baseTypeNr == eBaseTypeNrFloat64; } bool CFitBaseType::isNumber() const { return isInteger() ||isFloat(); } bool CFitBaseType::isString() const { return baseTypeNr == eBaseTypeNrString; } bool CFitBaseType::isByte() const { return baseTypeNr == eBaseTypeNrByte; } QString CFitBaseType::name() const { return namestr; } void CFitBaseTypeMap::initialize(QMap& baseTypesMap) { baseTypesMap.insert(fitEnumType.nr(), fitEnumType); baseTypesMap.insert(fitSint8Type.nr(), fitSint8Type); baseTypesMap.insert(fitUint8Type.nr(), fitUint8Type); baseTypesMap.insert(fitSint16Type.nr(), fitSint16Type); baseTypesMap.insert(fitUint16Type.nr(), fitUint16Type); baseTypesMap.insert(fitSint32Type.nr(), fitSint32Type); baseTypesMap.insert(fitUint32Type.nr(), fitUint32Type); baseTypesMap.insert(fitSint64Type.nr(), fitSint64Type); baseTypesMap.insert(fitUint64Type.nr(), fitUint64Type); baseTypesMap.insert(fitStringType.nr(), fitStringType); baseTypesMap.insert(fitFloat32Type.nr(), fitFloat32Type); baseTypesMap.insert(fitFloat64Type.nr(), fitFloat64Type); baseTypesMap.insert(fitUint8zType.nr(), fitUint8zType); baseTypesMap.insert(fitUint16zType.nr(), fitUint16zType); baseTypesMap.insert(fitUint32zType.nr(), fitUint32zType); baseTypesMap.insert(fitUint64zType.nr(), fitUint64zType); baseTypesMap.insert(fitByteType.nr(), fitByteType); } CFitBaseType* CFitBaseTypeMap::get(quint8 nr) { static bool initialized = false; static QMap baseTypes; if(!initialized) { initialize(baseTypes); initialized = true; } if (baseTypes.contains(nr & fitBaseTypeNumMask)) { return &baseTypes[nr & fitBaseTypeNumMask]; } return &baseTypes[eBaseTypeNrInvalid]; } qmapshack-1.10.0/src/gis/fit/defs/profiles.py000644 001750 000144 00000025223 13070640000 022165 0ustar00oeichlerxusers000000 000000 #!/usr/bin/env python # vim:fileencoding=utf-8 from __future__ import print_function import csv type_csv_filename = './Profile_Types.csv' messages_csv_filename = './Profile_Messages.csv' enum_filename = 'gen-fit_enums.h' enum_profiles_filename = 'gen-fit_fields.h' profile_code_filename = 'gen-CFitProfileLockup.cpp' profile_init_filename = 'gen-CFitProfileLockup-call.cpp' def titlecase(s): s = s.replace('_', ' ') s = s.title() s = s.replace(' ', '') return s def zero_if_null(s, i = None): return default_if_null('0', s, i) def empty_if_none(s, i = None): return default_if_null('', s, i) def default_if_null(default, s, i = None): if i is not None: if len(s) > i: s = s[i] else: s = '' if not s: return default return s def write_enum_type(enum_file, enum_list, type_name): if len(enum_list) > 0 and type_name: count = 0 print("typedef enum {", file=enum_file) for e in enum_list: if count + 1 < len(enum_list): print(' ' + e + ',', file=enum_file) else: print(' ' + e, file=enum_file) count = count + 1 print('} ' + type_name + '_e;', file=enum_file) print(' ', file=enum_file) def write_enum_file(): # field enums count = 0 last_type_name = '' enum_list = [] with open(type_csv_filename, 'r') as csvfile: typereader = csv.reader(csvfile, delimiter=';', quotechar='"') with open(enum_filename, 'w') as enum_file: for row in typereader: type_name = row[0] base_type = row[1] value_name = row[2] value = row[3] comment = row[4] if count > 0: if type_name: write_enum_type(enum_file, enum_list, last_type_name) enum_list = [] last_type_name = type_name if value_name and value: enum_list.append('e' + titlecase(last_type_name) + titlecase(value_name) + ' = ' + value) count = count + 1 write_enum_type(enum_file, enum_list, last_type_name) def write_message_enums(): count = 0 last_type_name = '' enum_list = [] with open(messages_csv_filename, 'r') as csvfile: typereader = csv.reader(csvfile, delimiter=';', quotechar='"') with open(enum_profiles_filename, 'w') as enum_file: for row in typereader: message_name = row[0] field_def_nr = row[1] field_name = row[2] if count > 0: if message_name: # '} message_' + + '_e;' write_enum_type(enum_file, enum_list, 'message_' + last_type_name) enum_list = [] last_type_name = message_name if field_name and field_def_nr: enum_list.append('e' + titlecase(last_type_name) + titlecase(field_name) + ' = ' + field_def_nr) count = count + 1 write_enum_type(enum_file, enum_list, 'message_' + last_type_name) def write_profile_type(profile_file, field_list, msg_name): if len(field_list) > 0 and msg_name: print('void init' + titlecase(msg_name) + '(QMap& profiles)', file=profile_file) print('{', file=profile_file) print(' CFitProfile* f = new CFitProfile("' + msg_name + '", eMesgNum' + titlecase(msg_name) + ');', file=profile_file) for f in field_list: print(' f->' + f + ';', file=profile_file) print(' profiles.insert(eMesgNum' + titlecase(msg_name) + ', f);', file=profile_file) print('}', file=profile_file) print(' ', file=profile_file) def write_profile_init(profile_file, msg_name): if msg_name: print(' init' + titlecase(msg_name) + '(allProfiles);', file=profile_file) base_type_map = { 'uint8' : 'fitUint8Type', 'uint16': 'fitUint16Type', 'uint32':'fitUint32Type', 'uint64':'fitUint64Type', 'sint8':'fitSint8Type', 'sint16':'fitSint16Type', 'sint32': 'fitSint32Type', 'sint64':'fitSint64Type', 'uint8z':'fitUint8zType', 'uint16z':'fitUint16zType', 'uint32z':'fitUint32zType', 'uint64z':'fitUint64zType', 'float32':'fitFloat32Type', 'float64':'fitFloat64Type', 'string':'fitStringType', 'byte':'fitByteType', 'bool':'fitEnumType', '':'fitEnumType'} def base_type(type): if type in base_type_map: return base_type_map[type] return 'fitEnumType' def write_profiles(): count = 0 subcount = 0 last_msg_name = '' field_names = {} add_list = [] profile_file = open(profile_code_filename, 'w') profile_init_file = open(profile_init_filename, 'w') with open(messages_csv_filename, 'r') as csvfile: typereader = csv.reader(csvfile, delimiter=';', quotechar='"') for row in typereader: message_name = row[0] field_def_nr = row[1] field_name = row[2] field_type = row[3] array = row[4] components = row[5] scale = row[6] offset = row[7] units = row[8] bits = row[9] accumulate = row[10] ref_field_name = row[11] ref_field_value = row[12] if count > 0: if message_name: # new message write_profile_type(profile_file, add_list, last_msg_name) write_profile_init(profile_init_file, last_msg_name) add_list = [] last_msg_name = message_name elif field_name: type_name = base_type(field_type) field_names[field_name] = field_type if field_def_nr and not components: # normal type scale = zero_if_null(scale) offset = zero_if_null(offset) last_field_def_nr = 'e' + titlecase(last_msg_name) + titlecase(field_name) add_list.append('addField("' + field_name + '", ' + type_name + ', ' + last_field_def_nr + ', ' + scale + ', ' + offset + ', "' + units + '")') subcount = 0 # end normal type else: # sub type or component type # ref field name is for all elements the same, so take the first one ref_field_name = empty_if_none(ref_field_name.split(','), 0) ref_field_value_list = ref_field_value.split(',') components_list = components.split(',') scale_list = scale.split(',') offset_list = offset.split(',') units_list = units.split(',') bits_list = bits.split(',') if not field_def_nr: # sub type enum_field = 'e' + titlecase(last_msg_name) + titlecase(ref_field_name) # case it has components (scale, offset and units are undefined) scale = '0' offset = '0' units = '' i = 0 for a in ref_field_value_list: if not components: scale = zero_if_null(scale_list, i) offset = zero_if_null(offset_list, i) units = empty_if_none(units_list, i) if ref_field_name not in field_names or not field_names[ref_field_name]: enum_field_value = 'e' + titlecase(ref_field_name) + titlecase(ref_field_value_list[i]) else: enum_field_value = 'e' +titlecase(field_names[ref_field_name]) + titlecase(ref_field_value_list[i]) add_list.append('addSubfield("' + field_name + '", ' + type_name + ', ' + last_field_def_nr + ', ' + scale + ', ' + offset + ', "' + units + '", ' + enum_field + ', ' + enum_field_value+')') i = i + 1 subcount = subcount + 1 # end sub type if components: # component type if field_def_nr: # a component needs always a parent field. add one last_field_def_nr = 'e' + titlecase(last_msg_name) + titlecase(field_name) add_list.append('addField("' + field_name + '", ' + type_name + ', ' + last_field_def_nr + ', 0, 0, "")') subaccess_field = '' else: # parent field for component is sub field subaccess_field = str(subcount - 1) + ', ' i = 0 for a in components_list: scale = zero_if_null(scale_list, i) if not scale: scale = zero_if_null(scale_list, 0) offset = zero_if_null(offset_list, i) units = empty_if_none(units_list, i) if not units: units = empty_if_none(units_list, 0) bits = zero_if_null(bits_list, i) if not bits: bits = zero_if_null(bits_list, 0) enum_component = 'e' + titlecase(last_msg_name) + titlecase(components_list[i]) add_list.append('addComponent('+ subaccess_field + '"' + field_name + '", ' + type_name + ', ' + last_field_def_nr + ', ' + scale + ', ' + offset + ', "' + units + '", ' + enum_component + ', ' + bits + ')') i = i + 1 # end component type count = count + 1 write_profile_type(profile_file, add_list, last_msg_name) write_profile_init(profile_init_file, last_msg_name) write_enum_file() write_message_enums() write_profiles()qmapshack-1.10.0/src/gis/fit/defs/fit_fields.h000644 001750 000144 00000105740 13216234143 022265 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef FIT_FIELDS_H #define FIT_FIELDS_H // ----------- start generated code ----------- typedef enum { eFileIdType = 0, eFileIdManufacturer = 1, eFileIdProduct = 2, eFileIdSerialNumber = 3, eFileIdTimeCreated = 4, eFileIdNumber = 5, eFileIdProductName = 8 } message_file_id_e; typedef enum { eFileCreatorSoftwareVersion = 0, eFileCreatorHardwareVersion = 1 } message_file_creator_e; typedef enum { eTimestampCorrelationTimestamp = 253, eTimestampCorrelationFractionalTimestamp = 0, eTimestampCorrelationSystemTimestamp = 1, eTimestampCorrelationFractionalSystemTimestamp = 2, eTimestampCorrelationLocalTimestamp = 3, eTimestampCorrelationTimestampMs = 4, eTimestampCorrelationSystemTimestampMs = 5 } message_timestamp_correlation_e; typedef enum { eSoftwareMessageIndex = 254, eSoftwareVersion = 3, eSoftwarePartNumber = 5 } message_software_e; typedef enum { eSlaveDeviceManufacturer = 0, eSlaveDeviceProduct = 1 } message_slave_device_e; typedef enum { eCapabilitiesLanguages = 0, eCapabilitiesSports = 1, eCapabilitiesWorkoutsSupported = 21, eCapabilitiesConnectivitySupported = 23 } message_capabilities_e; typedef enum { eFileCapabilitiesMessageIndex = 254, eFileCapabilitiesType = 0, eFileCapabilitiesFlags = 1, eFileCapabilitiesDirectory = 2, eFileCapabilitiesMaxCount = 3, eFileCapabilitiesMaxSize = 4 } message_file_capabilities_e; typedef enum { eMesgCapabilitiesMessageIndex = 254, eMesgCapabilitiesFile = 0, eMesgCapabilitiesMesgNum = 1, eMesgCapabilitiesCountType = 2, eMesgCapabilitiesCount = 3 } message_mesg_capabilities_e; typedef enum { eFieldCapabilitiesMessageIndex = 254, eFieldCapabilitiesFile = 0, eFieldCapabilitiesMesgNum = 1, eFieldCapabilitiesFieldNum = 2, eFieldCapabilitiesCount = 3 } message_field_capabilities_e; typedef enum { eDeviceSettingsActiveTimeZone = 0, eDeviceSettingsUtcOffset = 1, eDeviceSettingsTimeOffset = 2, eDeviceSettingsTimeMode = 4, eDeviceSettingsTimeZoneOffset = 5, eDeviceSettingsBacklightMode = 12, eDeviceSettingsActivityTrackerEnabled = 36, eDeviceSettingsClockTime = 39, eDeviceSettingsPagesEnabled = 40, eDeviceSettingsMoveAlertEnabled = 46, eDeviceSettingsDateMode = 47, eDeviceSettingsDisplayOrientation = 55, eDeviceSettingsMountingSide = 56, eDeviceSettingsDefaultPage = 57, eDeviceSettingsAutosyncMinSteps = 58, eDeviceSettingsAutosyncMinTime = 59, eDeviceSettingsLactateThresholdAutodetectEnabled = 80, eDeviceSettingsBleAutoUploadEnabled = 86, eDeviceSettingsAutoSyncFrequency = 89, eDeviceSettingsAutoActivityDetect = 90, eDeviceSettingsNumberOfScreens = 94, eDeviceSettingsSmartNotificationDisplayOrientation = 95 } message_device_settings_e; typedef enum { eUserProfileMessageIndex = 254, eUserProfileFriendlyName = 0, eUserProfileGender = 1, eUserProfileAge = 2, eUserProfileHeight = 3, eUserProfileWeight = 4, eUserProfileLanguage = 5, eUserProfileElevSetting = 6, eUserProfileWeightSetting = 7, eUserProfileRestingHeartRate = 8, eUserProfileDefaultMaxRunningHeartRate = 9, eUserProfileDefaultMaxBikingHeartRate = 10, eUserProfileDefaultMaxHeartRate = 11, eUserProfileHrSetting = 12, eUserProfileSpeedSetting = 13, eUserProfileDistSetting = 14, eUserProfilePowerSetting = 16, eUserProfileActivityClass = 17, eUserProfilePositionSetting = 18, eUserProfileTemperatureSetting = 21, eUserProfileLocalId = 22, eUserProfileGlobalId = 23, eUserProfileWakeTime = 28, eUserProfileSleepTime = 29, eUserProfileHeightSetting = 30, eUserProfileUserRunningStepLength = 31, eUserProfileUserWalkingStepLength = 32 } message_user_profile_e; typedef enum { eHrmProfileMessageIndex = 254, eHrmProfileEnabled = 0, eHrmProfileHrmAntId = 1, eHrmProfileLogHrv = 2, eHrmProfileHrmAntIdTransType = 3 } message_hrm_profile_e; typedef enum { eSdmProfileMessageIndex = 254, eSdmProfileEnabled = 0, eSdmProfileSdmAntId = 1, eSdmProfileSdmCalFactor = 2, eSdmProfileOdometer = 3, eSdmProfileSpeedSource = 4, eSdmProfileSdmAntIdTransType = 5, eSdmProfileOdometerRollover = 7 } message_sdm_profile_e; typedef enum { eBikeProfileMessageIndex = 254, eBikeProfileName = 0, eBikeProfileSport = 1, eBikeProfileSubSport = 2, eBikeProfileOdometer = 3, eBikeProfileBikeSpdAntId = 4, eBikeProfileBikeCadAntId = 5, eBikeProfileBikeSpdcadAntId = 6, eBikeProfileBikePowerAntId = 7, eBikeProfileCustomWheelsize = 8, eBikeProfileAutoWheelsize = 9, eBikeProfileBikeWeight = 10, eBikeProfilePowerCalFactor = 11, eBikeProfileAutoWheelCal = 12, eBikeProfileAutoPowerZero = 13, eBikeProfileId = 14, eBikeProfileSpdEnabled = 15, eBikeProfileCadEnabled = 16, eBikeProfileSpdcadEnabled = 17, eBikeProfilePowerEnabled = 18, eBikeProfileCrankLength = 19, eBikeProfileEnabled = 20, eBikeProfileBikeSpdAntIdTransType = 21, eBikeProfileBikeCadAntIdTransType = 22, eBikeProfileBikeSpdcadAntIdTransType = 23, eBikeProfileBikePowerAntIdTransType = 24, eBikeProfileOdometerRollover = 37, eBikeProfileFrontGearNum = 38, eBikeProfileFrontGear = 39, eBikeProfileRearGearNum = 40, eBikeProfileRearGear = 41, eBikeProfileShimanoDi2Enabled = 44 } message_bike_profile_e; typedef enum { eConnectivityBluetoothEnabled = 0, eConnectivityBluetoothLeEnabled = 1, eConnectivityAntEnabled = 2, eConnectivityName = 3, eConnectivityLiveTrackingEnabled = 4, eConnectivityWeatherConditionsEnabled = 5, eConnectivityWeatherAlertsEnabled = 6, eConnectivityAutoActivityUploadEnabled = 7, eConnectivityCourseDownloadEnabled = 8, eConnectivityWorkoutDownloadEnabled = 9, eConnectivityGpsEphemerisDownloadEnabled = 10, eConnectivityIncidentDetectionEnabled = 11, eConnectivityGrouptrackEnabled = 12 } message_connectivity_e; typedef enum { eWatchfaceSettingsMessageIndex = 254, eWatchfaceSettingsMode = 0, eWatchfaceSettingsLayout = 1 } message_watchface_settings_e; typedef enum { eOhrSettingsEnabled = 0 } message_ohr_settings_e; typedef enum { eZonesTargetMaxHeartRate = 1, eZonesTargetThresholdHeartRate = 2, eZonesTargetFunctionalThresholdPower = 3, eZonesTargetHrCalcType = 5, eZonesTargetPwrCalcType = 7 } message_zones_target_e; typedef enum { eSportSport = 0, eSportSubSport = 1, eSportName = 3 } message_sport_e; typedef enum { eHrZoneMessageIndex = 254, eHrZoneHighBpm = 1, eHrZoneName = 2 } message_hr_zone_e; typedef enum { eSpeedZoneMessageIndex = 254, eSpeedZoneHighValue = 0, eSpeedZoneName = 1 } message_speed_zone_e; typedef enum { eCadenceZoneMessageIndex = 254, eCadenceZoneHighValue = 0, eCadenceZoneName = 1 } message_cadence_zone_e; typedef enum { ePowerZoneMessageIndex = 254, ePowerZoneHighValue = 1, ePowerZoneName = 2 } message_power_zone_e; typedef enum { eMetZoneMessageIndex = 254, eMetZoneHighBpm = 1, eMetZoneCalories = 2, eMetZoneFatCalories = 3 } message_met_zone_e; typedef enum { eGoalMessageIndex = 254, eGoalSport = 0, eGoalSubSport = 1, eGoalStartDate = 2, eGoalEndDate = 3, eGoalType = 4, eGoalValue = 5, eGoalRepeat = 6, eGoalTargetValue = 7, eGoalRecurrence = 8, eGoalRecurrenceValue = 9, eGoalEnabled = 10, eGoalSource = 11 } message_goal_e; typedef enum { eActivityTimestamp = 253, eActivityTotalTimerTime = 0, eActivityNumSessions = 1, eActivityType = 2, eActivityEvent = 3, eActivityEventType = 4, eActivityLocalTimestamp = 5, eActivityEventGroup = 6 } message_activity_e; typedef enum { eSessionMessageIndex = 254, eSessionTimestamp = 253, eSessionEvent = 0, eSessionEventType = 1, eSessionStartTime = 2, eSessionStartPositionLat = 3, eSessionStartPositionLong = 4, eSessionSport = 5, eSessionSubSport = 6, eSessionTotalElapsedTime = 7, eSessionTotalTimerTime = 8, eSessionTotalDistance = 9, eSessionTotalCycles = 10, eSessionTotalCalories = 11, eSessionTotalFatCalories = 13, eSessionAvgSpeed = 14, eSessionMaxSpeed = 15, eSessionAvgHeartRate = 16, eSessionMaxHeartRate = 17, eSessionAvgCadence = 18, eSessionMaxCadence = 19, eSessionAvgPower = 20, eSessionMaxPower = 21, eSessionTotalAscent = 22, eSessionTotalDescent = 23, eSessionTotalTrainingEffect = 24, eSessionFirstLapIndex = 25, eSessionNumLaps = 26, eSessionEventGroup = 27, eSessionTrigger = 28, eSessionNecLat = 29, eSessionNecLong = 30, eSessionSwcLat = 31, eSessionSwcLong = 32, eSessionNormalizedPower = 34, eSessionTrainingStressScore = 35, eSessionIntensityFactor = 36, eSessionLeftRightBalance = 37, eSessionAvgStrokeCount = 41, eSessionAvgStrokeDistance = 42, eSessionSwimStroke = 43, eSessionPoolLength = 44, eSessionThresholdPower = 45, eSessionPoolLengthUnit = 46, eSessionNumActiveLengths = 47, eSessionTotalWork = 48, eSessionAvgAltitude = 49, eSessionMaxAltitude = 50, eSessionGpsAccuracy = 51, eSessionAvgGrade = 52, eSessionAvgPosGrade = 53, eSessionAvgNegGrade = 54, eSessionMaxPosGrade = 55, eSessionMaxNegGrade = 56, eSessionAvgTemperature = 57, eSessionMaxTemperature = 58, eSessionTotalMovingTime = 59, eSessionAvgPosVerticalSpeed = 60, eSessionAvgNegVerticalSpeed = 61, eSessionMaxPosVerticalSpeed = 62, eSessionMaxNegVerticalSpeed = 63, eSessionMinHeartRate = 64, eSessionTimeInHrZone = 65, eSessionTimeInSpeedZone = 66, eSessionTimeInCadenceZone = 67, eSessionTimeInPowerZone = 68, eSessionAvgLapTime = 69, eSessionBestLapIndex = 70, eSessionMinAltitude = 71, eSessionPlayerScore = 82, eSessionOpponentScore = 83, eSessionOpponentName = 84, eSessionStrokeCount = 85, eSessionZoneCount = 86, eSessionMaxBallSpeed = 87, eSessionAvgBallSpeed = 88, eSessionAvgVerticalOscillation = 89, eSessionAvgStanceTimePercent = 90, eSessionAvgStanceTime = 91, eSessionAvgFractionalCadence = 92, eSessionMaxFractionalCadence = 93, eSessionTotalFractionalCycles = 94, eSessionAvgTotalHemoglobinConc = 95, eSessionMinTotalHemoglobinConc = 96, eSessionMaxTotalHemoglobinConc = 97, eSessionAvgSaturatedHemoglobinPercent = 98, eSessionMinSaturatedHemoglobinPercent = 99, eSessionMaxSaturatedHemoglobinPercent = 100, eSessionAvgLeftTorqueEffectiveness = 101, eSessionAvgRightTorqueEffectiveness = 102, eSessionAvgLeftPedalSmoothness = 103, eSessionAvgRightPedalSmoothness = 104, eSessionAvgCombinedPedalSmoothness = 105, eSessionSportIndex = 111, eSessionTimeStanding = 112, eSessionStandCount = 113, eSessionAvgLeftPco = 114, eSessionAvgRightPco = 115, eSessionAvgLeftPowerPhase = 116, eSessionAvgLeftPowerPhasePeak = 117, eSessionAvgRightPowerPhase = 118, eSessionAvgRightPowerPhasePeak = 119, eSessionAvgPowerPosition = 120, eSessionMaxPowerPosition = 121, eSessionAvgCadencePosition = 122, eSessionMaxCadencePosition = 123, eSessionEnhancedAvgSpeed = 124, eSessionEnhancedMaxSpeed = 125, eSessionEnhancedAvgAltitude = 126, eSessionEnhancedMinAltitude = 127, eSessionEnhancedMaxAltitude = 128, eSessionAvgLevMotorPower = 129, eSessionMaxLevMotorPower = 130, eSessionLevBatteryConsumption = 131, eSessionAvgVerticalRatio = 132, eSessionAvgStanceTimeBalance = 133, eSessionAvgStepLength = 134, eSessionTotalAnaerobicTrainingEffect = 137, eSessionAvgVam = 139 } message_session_e; typedef enum { eLapMessageIndex = 254, eLapTimestamp = 253, eLapEvent = 0, eLapEventType = 1, eLapStartTime = 2, eLapStartPositionLat = 3, eLapStartPositionLong = 4, eLapEndPositionLat = 5, eLapEndPositionLong = 6, eLapTotalElapsedTime = 7, eLapTotalTimerTime = 8, eLapTotalDistance = 9, eLapTotalCycles = 10, eLapTotalCalories = 11, eLapTotalFatCalories = 12, eLapAvgSpeed = 13, eLapMaxSpeed = 14, eLapAvgHeartRate = 15, eLapMaxHeartRate = 16, eLapAvgCadence = 17, eLapMaxCadence = 18, eLapAvgPower = 19, eLapMaxPower = 20, eLapTotalAscent = 21, eLapTotalDescent = 22, eLapIntensity = 23, eLapLapTrigger = 24, eLapSport = 25, eLapEventGroup = 26, eLapNumLengths = 32, eLapNormalizedPower = 33, eLapLeftRightBalance = 34, eLapFirstLengthIndex = 35, eLapAvgStrokeDistance = 37, eLapSwimStroke = 38, eLapSubSport = 39, eLapNumActiveLengths = 40, eLapTotalWork = 41, eLapAvgAltitude = 42, eLapMaxAltitude = 43, eLapGpsAccuracy = 44, eLapAvgGrade = 45, eLapAvgPosGrade = 46, eLapAvgNegGrade = 47, eLapMaxPosGrade = 48, eLapMaxNegGrade = 49, eLapAvgTemperature = 50, eLapMaxTemperature = 51, eLapTotalMovingTime = 52, eLapAvgPosVerticalSpeed = 53, eLapAvgNegVerticalSpeed = 54, eLapMaxPosVerticalSpeed = 55, eLapMaxNegVerticalSpeed = 56, eLapTimeInHrZone = 57, eLapTimeInSpeedZone = 58, eLapTimeInCadenceZone = 59, eLapTimeInPowerZone = 60, eLapRepetitionNum = 61, eLapMinAltitude = 62, eLapMinHeartRate = 63, eLapWktStepIndex = 71, eLapOpponentScore = 74, eLapStrokeCount = 75, eLapZoneCount = 76, eLapAvgVerticalOscillation = 77, eLapAvgStanceTimePercent = 78, eLapAvgStanceTime = 79, eLapAvgFractionalCadence = 80, eLapMaxFractionalCadence = 81, eLapTotalFractionalCycles = 82, eLapPlayerScore = 83, eLapAvgTotalHemoglobinConc = 84, eLapMinTotalHemoglobinConc = 85, eLapMaxTotalHemoglobinConc = 86, eLapAvgSaturatedHemoglobinPercent = 87, eLapMinSaturatedHemoglobinPercent = 88, eLapMaxSaturatedHemoglobinPercent = 89, eLapAvgLeftTorqueEffectiveness = 91, eLapAvgRightTorqueEffectiveness = 92, eLapAvgLeftPedalSmoothness = 93, eLapAvgRightPedalSmoothness = 94, eLapAvgCombinedPedalSmoothness = 95, eLapTimeStanding = 98, eLapStandCount = 99, eLapAvgLeftPco = 100, eLapAvgRightPco = 101, eLapAvgLeftPowerPhase = 102, eLapAvgLeftPowerPhasePeak = 103, eLapAvgRightPowerPhase = 104, eLapAvgRightPowerPhasePeak = 105, eLapAvgPowerPosition = 106, eLapMaxPowerPosition = 107, eLapAvgCadencePosition = 108, eLapMaxCadencePosition = 109, eLapEnhancedAvgSpeed = 110, eLapEnhancedMaxSpeed = 111, eLapEnhancedAvgAltitude = 112, eLapEnhancedMinAltitude = 113, eLapEnhancedMaxAltitude = 114, eLapAvgLevMotorPower = 115, eLapMaxLevMotorPower = 116, eLapLevBatteryConsumption = 117, eLapAvgVerticalRatio = 118, eLapAvgStanceTimeBalance = 119, eLapAvgStepLength = 120, eLapAvgVam = 121 } message_lap_e; typedef enum { eLengthMessageIndex = 254, eLengthTimestamp = 253, eLengthEvent = 0, eLengthEventType = 1, eLengthStartTime = 2, eLengthTotalElapsedTime = 3, eLengthTotalTimerTime = 4, eLengthTotalStrokes = 5, eLengthAvgSpeed = 6, eLengthSwimStroke = 7, eLengthAvgSwimmingCadence = 9, eLengthEventGroup = 10, eLengthTotalCalories = 11, eLengthLengthType = 12, eLengthPlayerScore = 18, eLengthOpponentScore = 19, eLengthStrokeCount = 20, eLengthZoneCount = 21 } message_length_e; typedef enum { eRecordTimestamp = 253, eRecordPositionLat = 0, eRecordPositionLong = 1, eRecordAltitude = 2, eRecordHeartRate = 3, eRecordCadence = 4, eRecordDistance = 5, eRecordSpeed = 6, eRecordPower = 7, eRecordCompressedSpeedDistance = 8, eRecordGrade = 9, eRecordResistance = 10, eRecordTimeFromCourse = 11, eRecordCycleLength = 12, eRecordTemperature = 13, eRecordSpeed1S = 17, eRecordCycles = 18, eRecordTotalCycles = 19, eRecordCompressedAccumulatedPower = 28, eRecordAccumulatedPower = 29, eRecordLeftRightBalance = 30, eRecordGpsAccuracy = 31, eRecordVerticalSpeed = 32, eRecordCalories = 33, eRecordVerticalOscillation = 39, eRecordStanceTimePercent = 40, eRecordStanceTime = 41, eRecordActivityType = 42, eRecordLeftTorqueEffectiveness = 43, eRecordRightTorqueEffectiveness = 44, eRecordLeftPedalSmoothness = 45, eRecordRightPedalSmoothness = 46, eRecordCombinedPedalSmoothness = 47, eRecordTime128 = 48, eRecordStrokeType = 49, eRecordZone = 50, eRecordBallSpeed = 51, eRecordCadence256 = 52, eRecordFractionalCadence = 53, eRecordTotalHemoglobinConc = 54, eRecordTotalHemoglobinConcMin = 55, eRecordTotalHemoglobinConcMax = 56, eRecordSaturatedHemoglobinPercent = 57, eRecordSaturatedHemoglobinPercentMin = 58, eRecordSaturatedHemoglobinPercentMax = 59, eRecordDeviceIndex = 62, eRecordLeftPco = 67, eRecordRightPco = 68, eRecordLeftPowerPhase = 69, eRecordLeftPowerPhasePeak = 70, eRecordRightPowerPhase = 71, eRecordRightPowerPhasePeak = 72, eRecordEnhancedSpeed = 73, eRecordEnhancedAltitude = 78, eRecordBatterySoc = 81, eRecordMotorPower = 82, eRecordVerticalRatio = 83, eRecordStanceTimeBalance = 84, eRecordStepLength = 85 } message_record_e; typedef enum { eEventTimestamp = 253, eEventEvent = 0, eEventEventType = 1, eEventData16 = 2, eEventData = 3, eEventEventGroup = 4, eEventScore = 7, eEventOpponentScore = 8, eEventFrontGearNum = 9, eEventFrontGear = 10, eEventRearGearNum = 11, eEventRearGear = 12, eEventDeviceIndex = 13 } message_event_e; typedef enum { eDeviceInfoTimestamp = 253, eDeviceInfoDeviceIndex = 0, eDeviceInfoDeviceType = 1, eDeviceInfoManufacturer = 2, eDeviceInfoSerialNumber = 3, eDeviceInfoProduct = 4, eDeviceInfoSoftwareVersion = 5, eDeviceInfoHardwareVersion = 6, eDeviceInfoCumOperatingTime = 7, eDeviceInfoBatteryVoltage = 10, eDeviceInfoBatteryStatus = 11, eDeviceInfoSensorPosition = 18, eDeviceInfoDescriptor = 19, eDeviceInfoAntTransmissionType = 20, eDeviceInfoAntDeviceNumber = 21, eDeviceInfoAntNetwork = 22, eDeviceInfoSourceType = 25, eDeviceInfoProductName = 27 } message_device_info_e; typedef enum { eTrainingFileTimestamp = 253, eTrainingFileType = 0, eTrainingFileManufacturer = 1, eTrainingFileProduct = 2, eTrainingFileSerialNumber = 3, eTrainingFileTimeCreated = 4 } message_training_file_e; typedef enum { eHrvTime = 0 } message_hrv_e; typedef enum { eWeatherConditionsTimestamp = 253, eWeatherConditionsWeatherReport = 0, eWeatherConditionsTemperature = 1, eWeatherConditionsCondition = 2, eWeatherConditionsWindDirection = 3, eWeatherConditionsWindSpeed = 4, eWeatherConditionsPrecipitationProbability = 5, eWeatherConditionsTemperatureFeelsLike = 6, eWeatherConditionsRelativeHumidity = 7, eWeatherConditionsLocation = 8, eWeatherConditionsObservedAtTime = 9, eWeatherConditionsObservedLocationLat = 10, eWeatherConditionsObservedLocationLong = 11, eWeatherConditionsDayOfWeek = 12, eWeatherConditionsHighTemperature = 13, eWeatherConditionsLowTemperature = 14 } message_weather_conditions_e; typedef enum { eWeatherAlertTimestamp = 253, eWeatherAlertReportId = 0, eWeatherAlertIssueTime = 1, eWeatherAlertExpireTime = 2, eWeatherAlertSeverity = 3, eWeatherAlertType = 4 } message_weather_alert_e; typedef enum { eGpsMetadataTimestamp = 253, eGpsMetadataTimestampMs = 0, eGpsMetadataPositionLat = 1, eGpsMetadataPositionLong = 2, eGpsMetadataEnhancedAltitude = 3, eGpsMetadataEnhancedSpeed = 4, eGpsMetadataHeading = 5, eGpsMetadataUtcTimestamp = 6, eGpsMetadataVelocity = 7 } message_gps_metadata_e; typedef enum { eCameraEventTimestamp = 253, eCameraEventTimestampMs = 0, eCameraEventCameraEventType = 1, eCameraEventCameraFileUuid = 2, eCameraEventCameraOrientation = 3 } message_camera_event_e; typedef enum { eGyroscopeDataTimestamp = 253, eGyroscopeDataTimestampMs = 0, eGyroscopeDataSampleTimeOffset = 1, eGyroscopeDataGyroX = 2, eGyroscopeDataGyroY = 3, eGyroscopeDataGyroZ = 4, eGyroscopeDataCalibratedGyroX = 5, eGyroscopeDataCalibratedGyroY = 6, eGyroscopeDataCalibratedGyroZ = 7 } message_gyroscope_data_e; typedef enum { eAccelerometerDataTimestamp = 253, eAccelerometerDataTimestampMs = 0, eAccelerometerDataSampleTimeOffset = 1, eAccelerometerDataAccelX = 2, eAccelerometerDataAccelY = 3, eAccelerometerDataAccelZ = 4, eAccelerometerDataCalibratedAccelX = 5, eAccelerometerDataCalibratedAccelY = 6, eAccelerometerDataCalibratedAccelZ = 7, eAccelerometerDataCompressedCalibratedAccelX = 8, eAccelerometerDataCompressedCalibratedAccelY = 9, eAccelerometerDataCompressedCalibratedAccelZ = 10 } message_accelerometer_data_e; typedef enum { eMagnetometerDataTimestamp = 253, eMagnetometerDataTimestampMs = 0, eMagnetometerDataSampleTimeOffset = 1, eMagnetometerDataMagX = 2, eMagnetometerDataMagY = 3, eMagnetometerDataMagZ = 4, eMagnetometerDataCalibratedMagX = 5, eMagnetometerDataCalibratedMagY = 6, eMagnetometerDataCalibratedMagZ = 7 } message_magnetometer_data_e; typedef enum { eThreeDSensorCalibrationTimestamp = 253, eThreeDSensorCalibrationSensorType = 0, eThreeDSensorCalibrationCalibrationFactor = 1, eThreeDSensorCalibrationCalibrationDivisor = 2, eThreeDSensorCalibrationLevelShift = 3, eThreeDSensorCalibrationOffsetCal = 4, eThreeDSensorCalibrationOrientationMatrix = 5 } message_three_d_sensor_calibration_e; typedef enum { eVideoFrameTimestamp = 253, eVideoFrameTimestampMs = 0, eVideoFrameFrameNumber = 1 } message_video_frame_e; typedef enum { eObdiiDataTimestamp = 253, eObdiiDataTimestampMs = 0, eObdiiDataTimeOffset = 1, eObdiiDataPid = 2, eObdiiDataRawData = 3, eObdiiDataPidDataSize = 4, eObdiiDataSystemTime = 5, eObdiiDataStartTimestamp = 6, eObdiiDataStartTimestampMs = 7 } message_obdii_data_e; typedef enum { eNmeaSentenceTimestamp = 253, eNmeaSentenceTimestampMs = 0, eNmeaSentenceSentence = 1 } message_nmea_sentence_e; typedef enum { eAviationAttitudeTimestamp = 253, eAviationAttitudeTimestampMs = 0, eAviationAttitudeSystemTime = 1, eAviationAttitudePitch = 2, eAviationAttitudeRoll = 3, eAviationAttitudeAccelLateral = 4, eAviationAttitudeAccelNormal = 5, eAviationAttitudeTurnRate = 6, eAviationAttitudeStage = 7, eAviationAttitudeAttitudeStageComplete = 8, eAviationAttitudeTrack = 9, eAviationAttitudeValidity = 10 } message_aviation_attitude_e; typedef enum { eVideoUrl = 0, eVideoHostingProvider = 1, eVideoDuration = 2 } message_video_e; typedef enum { eVideoTitleMessageIndex = 254, eVideoTitleMessageCount = 0, eVideoTitleText = 1 } message_video_title_e; typedef enum { eVideoDescriptionMessageIndex = 254, eVideoDescriptionMessageCount = 0, eVideoDescriptionText = 1 } message_video_description_e; typedef enum { eVideoClipClipNumber = 0, eVideoClipStartTimestamp = 1, eVideoClipStartTimestampMs = 2, eVideoClipEndTimestamp = 3, eVideoClipEndTimestampMs = 4, eVideoClipClipStart = 6, eVideoClipClipEnd = 7 } message_video_clip_e; typedef enum { eCourseSport = 4, eCourseName = 5, eCourseCapabilities = 6, eCourseSubSport = 7 } message_course_e; typedef enum { eCoursePointMessageIndex = 254, eCoursePointTimestamp = 1, eCoursePointPositionLat = 2, eCoursePointPositionLong = 3, eCoursePointDistance = 4, eCoursePointType = 5, eCoursePointName = 6, eCoursePointFavorite = 8 } message_course_point_e; typedef enum { eSegmentIdName = 0, eSegmentIdUuid = 1, eSegmentIdSport = 2, eSegmentIdEnabled = 3, eSegmentIdUserProfilePrimaryKey = 4, eSegmentIdDeviceId = 5, eSegmentIdDefaultRaceLeader = 6, eSegmentIdDeleteStatus = 7, eSegmentIdSelectionType = 8 } message_segment_id_e; typedef enum { eSegmentLeaderboardEntryMessageIndex = 254, eSegmentLeaderboardEntryName = 0, eSegmentLeaderboardEntryType = 1, eSegmentLeaderboardEntryGroupPrimaryKey = 2, eSegmentLeaderboardEntryActivityId = 3, eSegmentLeaderboardEntrySegmentTime = 4, eSegmentLeaderboardEntryActivityIdString = 5 } message_segment_leaderboard_entry_e; typedef enum { eSegmentPointMessageIndex = 254, eSegmentPointPositionLat = 1, eSegmentPointPositionLong = 2, eSegmentPointDistance = 3, eSegmentPointAltitude = 4, eSegmentPointLeaderTime = 5 } message_segment_point_e; typedef enum { eSegmentLapMessageIndex = 254, eSegmentLapTimestamp = 253, eSegmentLapEvent = 0, eSegmentLapEventType = 1, eSegmentLapStartTime = 2, eSegmentLapStartPositionLat = 3, eSegmentLapStartPositionLong = 4, eSegmentLapEndPositionLat = 5, eSegmentLapEndPositionLong = 6, eSegmentLapTotalElapsedTime = 7, eSegmentLapTotalTimerTime = 8, eSegmentLapTotalDistance = 9, eSegmentLapTotalCycles = 10, eSegmentLapTotalCalories = 11, eSegmentLapTotalFatCalories = 12, eSegmentLapAvgSpeed = 13, eSegmentLapMaxSpeed = 14, eSegmentLapAvgHeartRate = 15, eSegmentLapMaxHeartRate = 16, eSegmentLapAvgCadence = 17, eSegmentLapMaxCadence = 18, eSegmentLapAvgPower = 19, eSegmentLapMaxPower = 20, eSegmentLapTotalAscent = 21, eSegmentLapTotalDescent = 22, eSegmentLapSport = 23, eSegmentLapEventGroup = 24, eSegmentLapNecLat = 25, eSegmentLapNecLong = 26, eSegmentLapSwcLat = 27, eSegmentLapSwcLong = 28, eSegmentLapName = 29, eSegmentLapNormalizedPower = 30, eSegmentLapLeftRightBalance = 31, eSegmentLapSubSport = 32, eSegmentLapTotalWork = 33, eSegmentLapAvgAltitude = 34, eSegmentLapMaxAltitude = 35, eSegmentLapGpsAccuracy = 36, eSegmentLapAvgGrade = 37, eSegmentLapAvgPosGrade = 38, eSegmentLapAvgNegGrade = 39, eSegmentLapMaxPosGrade = 40, eSegmentLapMaxNegGrade = 41, eSegmentLapAvgTemperature = 42, eSegmentLapMaxTemperature = 43, eSegmentLapTotalMovingTime = 44, eSegmentLapAvgPosVerticalSpeed = 45, eSegmentLapAvgNegVerticalSpeed = 46, eSegmentLapMaxPosVerticalSpeed = 47, eSegmentLapMaxNegVerticalSpeed = 48, eSegmentLapTimeInHrZone = 49, eSegmentLapTimeInSpeedZone = 50, eSegmentLapTimeInCadenceZone = 51, eSegmentLapTimeInPowerZone = 52, eSegmentLapRepetitionNum = 53, eSegmentLapMinAltitude = 54, eSegmentLapMinHeartRate = 55, eSegmentLapActiveTime = 56, eSegmentLapWktStepIndex = 57, eSegmentLapSportEvent = 58, eSegmentLapAvgLeftTorqueEffectiveness = 59, eSegmentLapAvgRightTorqueEffectiveness = 60, eSegmentLapAvgLeftPedalSmoothness = 61, eSegmentLapAvgRightPedalSmoothness = 62, eSegmentLapAvgCombinedPedalSmoothness = 63, eSegmentLapStatus = 64, eSegmentLapUuid = 65, eSegmentLapAvgFractionalCadence = 66, eSegmentLapMaxFractionalCadence = 67, eSegmentLapTotalFractionalCycles = 68, eSegmentLapFrontGearShiftCount = 69, eSegmentLapRearGearShiftCount = 70, eSegmentLapTimeStanding = 71, eSegmentLapStandCount = 72, eSegmentLapAvgLeftPco = 73, eSegmentLapAvgRightPco = 74, eSegmentLapAvgLeftPowerPhase = 75, eSegmentLapAvgLeftPowerPhasePeak = 76, eSegmentLapAvgRightPowerPhase = 77, eSegmentLapAvgRightPowerPhasePeak = 78, eSegmentLapAvgPowerPosition = 79, eSegmentLapMaxPowerPosition = 80, eSegmentLapAvgCadencePosition = 81, eSegmentLapMaxCadencePosition = 82, eSegmentLapManufacturer = 83 } message_segment_lap_e; typedef enum { eSegmentFileMessageIndex = 254, eSegmentFileFileUuid = 1, eSegmentFileEnabled = 3, eSegmentFileUserProfilePrimaryKey = 4, eSegmentFileLeaderType = 7, eSegmentFileLeaderGroupPrimaryKey = 8, eSegmentFileLeaderActivityId = 9, eSegmentFileLeaderActivityIdString = 10, eSegmentFileDefaultRaceLeader = 11 } message_segment_file_e; typedef enum { eWorkoutSport = 4, eWorkoutCapabilities = 5, eWorkoutNumValidSteps = 6, eWorkoutWktName = 8 } message_workout_e; typedef enum { eWorkoutStepMessageIndex = 254, eWorkoutStepWktStepName = 0, eWorkoutStepDurationType = 1, eWorkoutStepDurationValue = 2, eWorkoutStepTargetType = 3, eWorkoutStepTargetValue = 4, eWorkoutStepCustomTargetValueLow = 5, eWorkoutStepCustomTargetValueHigh = 6, eWorkoutStepIntensity = 7, eWorkoutStepNotes = 8 } message_workout_step_e; typedef enum { eScheduleManufacturer = 0, eScheduleProduct = 1, eScheduleSerialNumber = 2, eScheduleTimeCreated = 3, eScheduleCompleted = 4, eScheduleType = 5, eScheduleScheduledTime = 6 } message_schedule_e; typedef enum { eTotalsMessageIndex = 254, eTotalsTimestamp = 253, eTotalsTimerTime = 0, eTotalsDistance = 1, eTotalsCalories = 2, eTotalsSport = 3, eTotalsElapsedTime = 4, eTotalsSessions = 5, eTotalsActiveTime = 6, eTotalsSportIndex = 9 } message_totals_e; typedef enum { eWeightScaleTimestamp = 253, eWeightScaleWeight = 0, eWeightScalePercentFat = 1, eWeightScalePercentHydration = 2, eWeightScaleVisceralFatMass = 3, eWeightScaleBoneMass = 4, eWeightScaleMuscleMass = 5, eWeightScaleBasalMet = 7, eWeightScalePhysiqueRating = 8, eWeightScaleActiveMet = 9, eWeightScaleMetabolicAge = 10, eWeightScaleVisceralFatRating = 11, eWeightScaleUserProfileIndex = 12 } message_weight_scale_e; typedef enum { eBloodPressureTimestamp = 253, eBloodPressureSystolicPressure = 0, eBloodPressureDiastolicPressure = 1, eBloodPressureMeanArterialPressure = 2, eBloodPressureMap3SampleMean = 3, eBloodPressureMapMorningValues = 4, eBloodPressureMapEveningValues = 5, eBloodPressureHeartRate = 6, eBloodPressureHeartRateType = 7, eBloodPressureStatus = 8, eBloodPressureUserProfileIndex = 9 } message_blood_pressure_e; typedef enum { eMonitoringInfoTimestamp = 253, eMonitoringInfoLocalTimestamp = 0, eMonitoringInfoActivityType = 1, eMonitoringInfoCyclesToDistance = 3, eMonitoringInfoCyclesToCalories = 4, eMonitoringInfoRestingMetabolicRate = 5 } message_monitoring_info_e; typedef enum { eMonitoringTimestamp = 253, eMonitoringDeviceIndex = 0, eMonitoringCalories = 1, eMonitoringDistance = 2, eMonitoringCycles = 3, eMonitoringActiveTime = 4, eMonitoringActivityType = 5, eMonitoringActivitySubtype = 6, eMonitoringActivityLevel = 7, eMonitoringDistance16 = 8, eMonitoringCycles16 = 9, eMonitoringActiveTime16 = 10, eMonitoringLocalTimestamp = 11, eMonitoringTemperature = 12, eMonitoringTemperatureMin = 14, eMonitoringTemperatureMax = 15, eMonitoringActivityTime = 16, eMonitoringActiveCalories = 19, eMonitoringCurrentActivityTypeIntensity = 24, eMonitoringTimestampMin8 = 25, eMonitoringTimestamp16 = 26, eMonitoringHeartRate = 27, eMonitoringIntensity = 28, eMonitoringDurationMin = 29, eMonitoringDuration = 30, eMonitoringAscent = 31, eMonitoringDescent = 32, eMonitoringModerateActivityMinutes = 33, eMonitoringVigorousActivityMinutes = 34 } message_monitoring_e; typedef enum { eHrTimestamp = 253, eHrFractionalTimestamp = 0, eHrTime256 = 1, eHrFilteredBpm = 6, eHrEventTimestamp = 9, eHrEventTimestamp12 = 10 } message_hr_e; typedef enum { eMemoGlobPartIndex = 250, eMemoGlobMemo = 0, eMemoGlobMessageNumber = 1, eMemoGlobMessageIndex = 2 } message_memo_glob_e; typedef enum { eAntChannelIdChannelNumber = 0, eAntChannelIdDeviceType = 1, eAntChannelIdDeviceNumber = 2, eAntChannelIdTransmissionType = 3, eAntChannelIdDeviceIndex = 4 } message_ant_channel_id_e; typedef enum { eAntRxTimestamp = 253, eAntRxFractionalTimestamp = 0, eAntRxMesgId = 1, eAntRxMesgData = 2, eAntRxChannelNumber = 3, eAntRxData = 4 } message_ant_rx_e; typedef enum { eAntTxTimestamp = 253, eAntTxFractionalTimestamp = 0, eAntTxMesgId = 1, eAntTxMesgData = 2, eAntTxChannelNumber = 3, eAntTxData = 4 } message_ant_tx_e; typedef enum { eExdScreenConfigurationScreenIndex = 0, eExdScreenConfigurationFieldCount = 1, eExdScreenConfigurationLayout = 2, eExdScreenConfigurationScreenEnabled = 3 } message_exd_screen_configuration_e; typedef enum { eExdDataFieldConfigurationScreenIndex = 0, eExdDataFieldConfigurationConceptField = 1, eExdDataFieldConfigurationFieldId = 2, eExdDataFieldConfigurationConceptCount = 3, eExdDataFieldConfigurationDisplayType = 4, eExdDataFieldConfigurationTitle = 5 } message_exd_data_field_configuration_e; typedef enum { eExdDataConceptConfigurationScreenIndex = 0, eExdDataConceptConfigurationConceptField = 1, eExdDataConceptConfigurationFieldId = 2, eExdDataConceptConfigurationConceptIndex = 3, eExdDataConceptConfigurationDataPage = 4, eExdDataConceptConfigurationConceptKey = 5, eExdDataConceptConfigurationScaling = 6, eExdDataConceptConfigurationDataUnits = 8, eExdDataConceptConfigurationQualifier = 9, eExdDataConceptConfigurationDescriptor = 10, eExdDataConceptConfigurationIsSigned = 11 } message_exd_data_concept_configuration_e; typedef enum { eFieldDescriptionDeveloperDataIndex = 0, eFieldDescriptionFieldDefinitionNumber = 1, eFieldDescriptionFitBaseTypeId = 2, eFieldDescriptionFieldName = 3, eFieldDescriptionArray = 4, eFieldDescriptionComponents = 5, eFieldDescriptionScale = 6, eFieldDescriptionOffset = 7, eFieldDescriptionUnits = 8, eFieldDescriptionBits = 9, eFieldDescriptionAccumulate = 10, eFieldDescriptionFitBaseUnitId = 13, eFieldDescriptionNativeMesgNum = 14, eFieldDescriptionNativeFieldNum = 15 } message_field_description_e; typedef enum { eDeveloperDataIdDeveloperId = 0, eDeveloperDataIdApplicationId = 1, eDeveloperDataIdManufacturerId = 2, eDeveloperDataIdDeveloperDataIndex = 3, eDeveloperDataIdApplicationVersion = 4 } message_developer_data_id_e; // ----------- end generated code ----------- #endif // FIT_FIELDS_H qmapshack-1.10.0/src/gis/fit/defs/CFitBaseType.h000644 001750 000144 00000011362 13216234143 022433 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITBASETYPE_H #define CFITBASETYPE_H #include typedef enum { eBaseTypeNrEnum = 0, eBaseTypeNrSint8 = 1, eBaseTypeNrUint8 = 2, eBaseTypeNrSint16 = 3, eBaseTypeNrUint16 = 4, eBaseTypeNrSint32 = 5, eBaseTypeNrUint32 = 6, eBaseTypeNrString = 7, eBaseTypeNrFloat32 = 8, eBaseTypeNrFloat64 = 9, eBaseTypeNrUint8z = 10, eBaseTypeNrUint16z = 11, eBaseTypeNrUint32z = 12, eBaseTypeNrByte = 13, eBaseTypeNrSint64 = 14, eBaseTypeNrUint64 = 15, eBaseTypeNrUint64z = 16, eBaseTypeNrInvalid = 0xff } fit_base_type_nr_e; class CFitBaseType final { public: CFitBaseType(); CFitBaseType(fit_base_type_nr_e baseTypeNr, QString name, quint8 size, std::initializer_list invalid); quint8 size() const; fit_base_type_nr_e nr() const; quint8 baseTypeField() const; const quint8* invalidValueBytes() const; bool isSizeUndefined() const; bool isInteger() const; bool isSignedInt() const; bool isUnsignedInt() const; bool isFloat() const; bool isNumber() const; bool isString() const; bool isByte() const; QString name() const; private: // fixed size to 8, which is enough for float64 quint8 invalidBytes[8]; quint8 typeSize; fit_base_type_nr_e baseTypeNr; QString namestr; }; static const CFitBaseType fitEnumType = CFitBaseType(eBaseTypeNrEnum, "Enum", sizeof(quint8), {0xFF}); static const CFitBaseType fitSint8Type = CFitBaseType(eBaseTypeNrSint8, "Sint8", sizeof(qint8), {0x7F}); static const CFitBaseType fitUint8Type = CFitBaseType(eBaseTypeNrUint8, "Uint8", sizeof(quint8), {0xFF}); static const CFitBaseType fitSint16Type = CFitBaseType(eBaseTypeNrSint16, "Sint16", sizeof(qint16), {0x7F, 0xFF}); static const CFitBaseType fitUint16Type = CFitBaseType(eBaseTypeNrUint16, "Uint16", sizeof(quint16), {0xFF, 0xFF}); static const CFitBaseType fitSint32Type = CFitBaseType(eBaseTypeNrSint32, "Sint32", sizeof(qint32), {0x7F, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitUint32Type = CFitBaseType(eBaseTypeNrUint32, "Uint32", sizeof(quint32), {0xFF, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitSint64Type = CFitBaseType(eBaseTypeNrSint64, "Sint64", sizeof(qint64), {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitUint64Type = CFitBaseType(eBaseTypeNrUint64, "Uint64", sizeof(quint64), {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitStringType = CFitBaseType(eBaseTypeNrString, "String", 0, {0x00}); // Field is invalid if all bytes are invalid. static const CFitBaseType fitFloat32Type = CFitBaseType(eBaseTypeNrFloat32, "Float32", sizeof(float), {0xFF, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitFloat64Type = CFitBaseType(eBaseTypeNrFloat64, "Float64", sizeof(double), {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}); static const CFitBaseType fitUint8zType = CFitBaseType(eBaseTypeNrUint8z, "Uint8z", sizeof(quint8), {0x00}); static const CFitBaseType fitUint16zType = CFitBaseType(eBaseTypeNrUint16z, "Uint16z", sizeof(quint16), {0x00, 0x00}); static const CFitBaseType fitUint32zType = CFitBaseType(eBaseTypeNrUint32z, "Uint32z", sizeof(quint32), {0x00, 0x00, 0x00, 0x00}); static const CFitBaseType fitUint64zType = CFitBaseType(eBaseTypeNrUint64z, "Uint64z", sizeof(quint64), {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); static const CFitBaseType fitByteType = CFitBaseType(eBaseTypeNrByte, "Byte", 0, {0xFF}); // Field is invalid if all bytes are invalid. static const CFitBaseType fitInvalidType = CFitBaseType(eBaseTypeNrInvalid, "Invalid", 0, {0}); class CFitBaseTypeMap { public: static const quint8 fitBaseTypeNumMask =0x1F; // 0000 0000 0001 1111 /** * param nr: either the "real" base type number (0 -13) or the masked base type byte. */ static CFitBaseType* get(quint8 nr); private: static void initialize(QMap& baseTypesMap); }; #endif //CFITBASETYPE_H qmapshack-1.10.0/src/gis/fit/defs/CFitProfileLookup.h000644 001750 000144 00000002565 13216234143 023516 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITPROFILELOOKUP_H #define CFITPROFILELOOKUP_H #include class CFitProfile; class CFitFieldProfile; class CFitProfileLookup : public QObject { Q_OBJECT public: static const CFitProfile* getProfile(quint16 globalMesgNr); static const CFitFieldProfile* getFieldForProfile(quint16 globalMesgNr, quint8 fieldDefNr); private: CFitProfileLookup(); ~CFitProfileLookup(); QMap allProfiles; private slots: void slotCleanup(); }; #endif // CFITPROFILELOOKUP_H qmapshack-1.10.0/src/gis/fit/defs/CFitFieldProfile.cpp000644 001750 000144 00000013320 13216234140 023607 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/fit_const.h" CFitFieldProfile::CFitFieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, field_type_e fieldType ) : name(name), fieldDefNr(fieldDefNr), scale(scale), offset(offset), units(units), fieldType(fieldType), baseType(&baseType), profile(parent), subfields(), components() { } CFitFieldProfile::CFitFieldProfile() : CFitFieldProfile(nullptr, "unknown", fitInvalidType, fitFieldDefNrInvalid, 0, 0, "") { } CFitFieldProfile::CFitFieldProfile(const CFitFieldProfile& copy) : name(copy.name), fieldDefNr(copy.fieldDefNr), scale(copy.scale), offset(copy.offset), units(copy.units), fieldType(copy.fieldType), baseType(copy.baseType), profile(copy.profile), subfields(copy.subfields), components(copy.components) { } CFitFieldProfile::~CFitFieldProfile() { qDeleteAll(subfields); qDeleteAll(components); } void CFitFieldProfile::addSubfield(CFitSubfieldProfile* subfield) { subfields.append(subfield); } void CFitFieldProfile::addComponent(CFitComponentfieldProfile* component) { components.append(component); } void CFitFieldProfile::addComponent(int subfieldIndex, CFitComponentfieldProfile* field) { subfields[subfieldIndex]->addComponent(field); } bool CFitFieldProfile::hasSubfields() const { return subfields.size() > 0; } bool CFitFieldProfile::hasComponents() const { return components.size() > 0; } QString CFitFieldProfile::getName() const { return name; } quint8 CFitFieldProfile::getFieldDefNum() const { return fieldDefNr; } qreal CFitFieldProfile::getScale() const { if (scale == 0) { return 1; } return scale; } qint16 CFitFieldProfile::getOffset() const { return offset; } bool CFitFieldProfile::hasScaleAndOffset() const { return scale != 0 || offset != 0; } QString CFitFieldProfile::getUnits() const { return units; } const CFitBaseType& CFitFieldProfile::getBaseType() const { return *baseType; } const CFitProfile* CFitFieldProfile::getProfile() const { return profile; } const QList CFitFieldProfile::getSubfields() const { return subfields; } QList CFitFieldProfile::getComponents() const { return components; } QString CFitFieldProfile::fieldProfileInfo() { QString str = QString("%1 %2 (%3): %4 %5") .arg(QString("field profile")) .arg(getName()) .arg(getFieldDefNum()) .arg(getUnits()) .arg(getBaseType().name()); if(getBaseType().isNumber()) { str += QString(" (%1-%2)") .arg(getScale()) .arg(getOffset()); } return str; } CFitSubfieldProfile::CFitSubfieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 subRefFieldDefNr, quint8 subRefFieldValue) : CFitFieldProfile(parent, name, baseType, fieldDefNr, scale, offset, units), refFieldDefNr(subRefFieldDefNr), refFieldValue(subRefFieldValue) { } CFitSubfieldProfile::CFitSubfieldProfile(const CFitSubfieldProfile& copy) : CFitFieldProfile(copy), refFieldDefNr(copy.refFieldDefNr), refFieldValue(copy.refFieldValue) { } quint8 CFitSubfieldProfile::getReferencedFieldDefNr() const { return refFieldDefNr; } quint8 CFitSubfieldProfile::getReferencedFieldValue() const { return refFieldValue; } CFitComponentfieldProfile::CFitComponentfieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits) : CFitFieldProfile(parent, name, baseType, fieldDefNr, scale, offset, units), nrOfBits(bits), componentFieldDefNr(componentFieldDefNr) { } CFitComponentfieldProfile::CFitComponentfieldProfile(const CFitComponentfieldProfile& copy) : CFitFieldProfile(copy), nrOfBits(copy.nrOfBits), componentFieldDefNr(copy.componentFieldDefNr) { } QString CFitComponentfieldProfile::getName() const { return getProfile()->getField(componentFieldDefNr)->getName(); } quint8 CFitComponentfieldProfile::getFieldDefNum() const { return getProfile()->getField(componentFieldDefNr)->getFieldDefNum(); } const CFitBaseType& CFitComponentfieldProfile::getBaseType() const { return getProfile()->getField(componentFieldDefNr)->getBaseType(); } quint32 CFitComponentfieldProfile::getBits() const { return nrOfBits; } quint32 CFitComponentfieldProfile::getBitmask() const { quint32 bitmask = 0; for (quint32 i = 0; i < nrOfBits; i++) { bitmask |= (1 << i); } return bitmask; }qmapshack-1.10.0/src/gis/fit/defs/CFitProfile.cpp000644 001750 000144 00000006054 13216234140 022651 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/fit_const.h" CFitProfile::CFitProfile(QString name, quint16 globalMesgNr) : name(name), globalMesgNr(globalMesgNr), fields() { } CFitProfile::CFitProfile() : CFitProfile("unknown", fitGlobalMesgNrInvalid) { } CFitProfile::CFitProfile(const CFitProfile& copy) : name(copy.name), globalMesgNr(copy.globalMesgNr), fields(copy.fields) { } CFitProfile::~CFitProfile() { qDeleteAll(fields); } const CFitFieldProfile* CFitProfile::getField(quint8 fieldDefNr) const { if (fields.contains(fieldDefNr)) { return fields[fieldDefNr]; } static CFitFieldProfile dummyFieldProfile {}; return &dummyFieldProfile; } void CFitProfile::addField(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units) { CFitFieldProfile* field= new CFitFieldProfile(this, name, baseType, fieldDefNr, scale, offset, units); fields.insert(fieldDefNr, field); } void CFitProfile::addSubfield(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, quint16 offset, QString units, quint8 subRefFieldDefNr, quint8 subRefFieldValue) { CFitSubfieldProfile* field = new CFitSubfieldProfile(this, name, baseType, fieldDefNr, scale, offset, units, subRefFieldDefNr, subRefFieldValue); fields[fieldDefNr]->addSubfield(field); } void CFitProfile::addComponent(QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits) { CFitComponentfieldProfile* field = new CFitComponentfieldProfile(this, name, baseType, fieldDefNr, scale, offset, units, componentFieldDefNr, bits); fields[fieldDefNr]->addComponent(field); } void CFitProfile::addComponent(int subfieldIndex, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits) { CFitComponentfieldProfile* field = new CFitComponentfieldProfile(this, name, baseType, fieldDefNr, scale, offset, units, componentFieldDefNr, bits); fields[fieldDefNr]->addComponent(subfieldIndex, field); } qmapshack-1.10.0/src/gis/fit/defs/HowToFitGenerator.txt000644 001750 000144 00000002723 13070640000 024103 0ustar00oeichlerxusers000000 000000 How To Generate FIT Master Data ------------------------------- The source code for the fit decoder has several places with the comments: // ----------- start generated code ----------- // ----------- end generated code ----------- The code in between these comments is generated. The files with generated code are: - /src/gis/fit/defs/CFitProfileLookup.cpp contains the fit profiles (message and field) - /src/gis/fit/defs/fit_enums.h contains the global message numbers plus enumerations for field values - /src/gis/fit/defs/fit_fields.h contains all field def numbers The input for the generator are two CSV files (beware the line ending must be line ending unix): - Profile_Messages.csv - Profile_Types.csv These csv files are the export from the Excel "Profiles.xlsx" within the FIT SDK (Current Version 20.27). The generator "profiles.py" is a python script and needs python 2.7. The generator creates separate files. The code must be placed at the corresponding source code manually (in between the above mentioned comments). The generator creates files with the same name as the files mentioned above plus a prefix "gen-" in the same directory as it has been executed: - e.g. gen-fit_enums.h is the source for the file fit_enums.h The generator is not part of the build, so it must be executed manually. These files should be deleted after copying the code into the corresponding source files. Do not add these generated files to the repository. qmapshack-1.10.0/src/gis/fit/defs/fit_const.h000644 001750 000144 00000002741 13216234143 022142 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef FIT_CONST_H #define FIT_CONST_H #include /* * 0: does not print any decoded fit messages and definitions * 1: prints fit messages and definitions after finishing decoding * 2: 1 + prints fit messages and definitions during decoding (just after finishing one) */ #define FITDEBUGLVL 1 #define FITDEBUG(level, cmd) if(FITDEBUGLVL >= level) { cmd; } static const quint8 fitLocalMesgNrInvalid = 255; static const quint16 fitGlobalMesgNrInvalid = 0xffff; static const quint8 fitFieldDefNrInvalid = 255; typedef enum { eFitArchEndianLittle = 0, eFitArchEndianBig = 1 }fit_arch_e; #endif // FIT_CONST_H qmapshack-1.10.0/src/gis/fit/defs/Profile_Messages.csv000644 001750 000144 00001031173 12705713524 023756 0ustar00oeichlerxusers000000 000000 Message Name;Field Def #;Field Name;Field Type;Array;Components;Scale;Offset;Units;Bits;Accumulate;Ref Field Name;Ref Field Value;Comment;Products:;EXAMPLE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;COMMON MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; file_id;;;;;;;;;;;;;Must be first message in file.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;type;file;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;manufacturer;manufacturer;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;product;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;garmin_product;garmin_product;;;;;;;;"manufacturer,manufacturer,manufacturer";"garmin,dynastream,dynastream_oem";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;serial_number;uint32z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;time_created;date_time;;;;;;;;;;Only set for files that are can be created/erased.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;number;uint16;;;;;;;;;;Only set for files that are not created/erased.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;product_name;string;;;;;;;;;;Optional free form string to indicate the devices name or model;;20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; file_creator;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;software_version;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;hardware_version;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; timestamp_correlation;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of UTC timestamp at the time the system timestamp was recorded.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;fractional_timestamp;uint16;;;32768;;s;;;;;Fractional part of the UTC timestamp at the time the system timestamp was recorded.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;system_timestamp;date_time;;;;;s;;;;;Whole second part of the system timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;fractional_system_timestamp;uint16;;;32768;;s;;;;;Fractional part of the system timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;local_timestamp;local_date_time;;;;;s;;;;;timestamp epoch expressed in local time used to convert timestamps to local time ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the UTC timestamp at the time the system timestamp was recorded.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;system_timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the system timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;DEVICE FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; software;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;version;uint16;;;100;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;part_number;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; slave_device;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;manufacturer;manufacturer;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;product;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;garmin_product;garmin_product;;;;;;;;"manufacturer,manufacturer,manufacturer";"garmin,dynastream,dynastream_oem";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; capabilities;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;languages;uint8z;[N];;;;;;;;;Use language_bits_x types where x is index of array.;;4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sports;sport_bits_0;[N];;;;;;;;;Use sport_bits_x types where x is index of array.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;workouts_supported;workout_capabilities;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;connectivity_supported;connectivity_capabilities;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; file_capabilities;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;type;file;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;flags;file_flags;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;directory;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;max_count;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;max_size;uint32;;;;;bytes;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mesg_capabilities;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;file;file;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;mesg_num;mesg_num;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;count_type;mesg_count;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;count;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;num_per_file;uint16;;;;;;;;count_type;num_per_file;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;max_per_file;uint16;;;;;;;;count_type;max_per_file;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;max_per_file_type;uint16;;;;;;;;count_type;max_per_file_type;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; field_capabilities;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;file;file;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;mesg_num;mesg_num;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;field_num;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;count;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;SETTINGS FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; device_settings;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;active_time_zone;uint8;;;;;;;;;;Index into time zone arrays.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;utc_offset;uint32;;;;;;;;;;Offset from system time. Required to convert timestamp from system time to UTC.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;time_zone_offset;sint8;[N];;4;;hr;;;;;timezone offset in 1/4 hour increments;;2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; user_profile;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;friendly_name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;gender;gender;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;age;uint8;;;;;years;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;height;uint8;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;weight;uint16;;;10;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;language;language;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;elev_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;weight_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;resting_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;default_max_running_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;default_max_biking_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;default_max_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;hr_setting;display_heart;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;speed_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;dist_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;power_setting;display_power;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;activity_class;activity_class;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;position_setting;display_position;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;temperature_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;local_id;user_local_id;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;global_id;byte;[6];;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;30;height_setting;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hrm_profile;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;hrm_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;log_hrv;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;hrm_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sdm_profile;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sdm_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;sdm_cal_factor;uint16;;;10;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;odometer;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;speed_source;bool;;;;;;;;;;Use footpod for speed source instead of GPS;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;sdm_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;odometer_rollover;uint8;;;;;;;;;;Rollover counter that can be used to extend the odometer;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bike_profile;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;odometer;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;bike_spd_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;bike_cad_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;bike_spdcad_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;bike_power_ant_id;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;custom_wheelsize;uint16;;;1000;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;auto_wheelsize;uint16;;;1000;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;bike_weight;uint16;;;10;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;power_cal_factor;uint16;;;10;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;auto_wheel_cal;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;auto_power_zero;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;id;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;15;spd_enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;cad_enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;spdcad_enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;power_enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;crank_length;uint8;;;2;-110;mm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;bike_spd_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;bike_cad_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;bike_spdcad_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;24;bike_power_ant_id_trans_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;37;odometer_rollover;uint8;;;;;;;;;;Rollover counter that can be used to extend the odometer;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;38;front_gear_num;uint8z;;;;;;;;;;Number of front gears;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;39;front_gear;uint8z;[N];;;;;;;;;Number of teeth on each gear 0 is innermost;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;40;rear_gear_num;uint8z;;;;;;;;;;Number of rear gears;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;41;rear_gear;uint8z;[N];;;;;;;;;Number of teeth on each gear 0 is innermost;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;44;shimano_di2_enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;SPORT SETTINGS FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; zones_target;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;max_heart_rate;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;threshold_heart_rate;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;functional_threshold_power;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;hr_calc_type;hr_zone_calc;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;pwr_calc_type;pwr_zone_calc;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sport;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hr_zone;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;high_bpm;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; speed_zone;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;high_value;uint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cadence_zone;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;high_value;uint8;;;;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; power_zone;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;high_value;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; met_zone;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;high_bpm;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;calories;uint16;;;10;;kcal / min;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;fat_calories;uint8;;;10;;kcal / min;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;GOALS FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; goal;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_date;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;end_date;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;type;goal;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;value;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;repeat;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;target_value;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;recurrence;goal_recurrence;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;recurrence_value;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;enabled;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;ACTIVITY FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; activity;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;total_timer_time;uint32;;;1000;;s;;;;;Exclude pauses;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;num_sessions;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;type;activity;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;event;event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;event_type;event_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;local_timestamp;local_date_time;;;;;;;;;;timestamp epoch expressed in local time, used to convert activity timestamps to local time ;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; session;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;Selected bit is set for the current session.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Sesson end time.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;event;event;;;;;;;;;;session;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;event_type;event_type;;;;;;;;;;stop;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_time;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;start_position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;start_position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;total_elapsed_time;uint32;;;1000;;s;;;;;Time (includes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;total_timer_time;uint32;;;1000;;s;;;;;Timer Time (excludes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;total_distance;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;total_cycles;uint32;;;;;cycles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;total_strides;uint32;;;;;strides;;;"sport,sport";"running,walking";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;total_calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;total_fat_calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;avg_speed;uint16;;enhanced_avg_speed;1000;;m/s;16;;;;total_distance / total_timer_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;15;max_speed;uint16;;enhanced_max_speed;1000;;m/s;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;avg_heart_rate;uint8;;;;;bpm;;;;;average heart rate (excludes pause time);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;max_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;avg_cadence;uint8;;;;;rpm;;;;;total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;avg_running_cadence;uint8;;;;;strides/min;;;sport;running;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;max_cadence;uint8;;;;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;max_running_cadence;uint8;;;;;strides/min;;;sport;running;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;avg_power;uint16;;;;;watts;;;;;total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;max_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;total_ascent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;total_descent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;24;total_training_effect;uint8;;;10;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;25;first_lap_index;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;26;num_laps;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;27;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;28;trigger;session_trigger;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;29;nec_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;30;nec_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;31;swc_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;32;swc_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;34;normalized_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;35;training_stress_score;uint16;;;10;;tss;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;36;intensity_factor;uint16;;;1000;;if;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;37;left_right_balance;left_right_balance_100;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;41;avg_stroke_count;uint32;;;10;;strokes/lap;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;42;avg_stroke_distance;uint16;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;43;swim_stroke;swim_stroke;;;;;swim_stroke;;;sport;swimming;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;44;pool_length;uint16;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;45;threshold_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;46;pool_length_unit;display_measure;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;47;num_active_lengths;uint16;;;;;lengths;;;;;# of active lengths of swim pool;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;48;total_work;uint32;;;;;J;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;49;avg_altitude;uint16;;enhanced_avg_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;50;max_altitude;uint16;;enhanced_max_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;51;gps_accuracy;uint8;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;52;avg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;53;avg_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;54;avg_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;55;max_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;56;max_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;57;avg_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;58;max_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;59;total_moving_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;60;avg_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;61;avg_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;62;max_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;63;max_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;64;min_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;65;time_in_hr_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;66;time_in_speed_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;67;time_in_cadence_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;68;time_in_power_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;69;avg_lap_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;70;best_lap_index;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;71;min_altitude;uint16;;enhanced_min_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;82;player_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;83;opponent_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;84;opponent_name;string;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;85;stroke_count;uint16;[N];;;;counts;;;;;stroke_type enum used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;86;zone_count;uint16;[N];;;;counts;;;;;zone number used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;87;max_ball_speed;uint16;;;100;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;88;avg_ball_speed;uint16;;;100;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;89;avg_vertical_oscillation;uint16;;;10;;mm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;90;avg_stance_time_percent;uint16;;;100;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;91;avg_stance_time;uint16;;;10;;ms;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;92;avg_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the avg_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;93;max_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the max_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;94;total_fractional_cycles;uint8;;;128;;cycles;;;;;fractional part of the total_cycles;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;95;avg_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Avg saturated and unsaturated hemoglobin;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;96;min_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Min saturated and unsaturated hemoglobin;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;97;max_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Max saturated and unsaturated hemoglobin;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;98;avg_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Avg percentage of hemoglobin saturated with oxygen;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;99;min_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Min percentage of hemoglobin saturated with oxygen;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;100;max_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Max percentage of hemoglobin saturated with oxygen;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;101;avg_left_torque_effectiveness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;102;avg_right_torque_effectiveness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;103;avg_left_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;104;avg_right_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;105;avg_combined_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;111;sport_index;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;112;time_standing;uint32;;;1000;;s;;;;;Total time spend in the standing position;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;113;stand_count;uint16;;;;;;;;;;Number of transitions to the standing state;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;114;avg_left_pco;sint8;;;;;mm;;;;;Average platform center offset Left;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;115;avg_right_pco;sint8;;;;;mm;;;;;Average platform center offset Right;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;116;avg_left_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase angles. Indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;117;avg_left_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;118;avg_right_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;119;avg_right_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase peak angles data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;120;avg_power_position;uint16;[N];;;;watts;;;;;Average power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;121;max_power_position;uint16;[N];;;;watts;;;;;Maximum power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;122;avg_cadence_position;uint8;[N];;;;rpm;;;;;Average cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;123;max_cadence_position;uint8;[N];;;;rpm;;;;;Maximum cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;124;enhanced_avg_speed;uint32;;;1000;;m/s;;;;;total_distance / total_timer_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;125;enhanced_max_speed;uint32;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;126;enhanced_avg_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;127;enhanced_min_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;128;enhanced_max_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;129;avg_lev_motor_power;uint16;;;;;watts;;;;;lev average motor power during session;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;130;max_lev_motor_power;uint16;;;;;watts;;;;;lev maximum motor power during session;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;131;lev_battery_consumption;uint8;;;2;;percent;;;;;lev battery consumption during session;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; lap;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Lap end time.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;event;event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;event_type;event_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_time;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;start_position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;start_position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;end_position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;end_position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;total_elapsed_time;uint32;;;1000;;s;;;;;Time (includes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;total_timer_time;uint32;;;1000;;s;;;;;Timer Time (excludes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;total_distance;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;total_cycles;uint32;;;;;cycles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;total_strides;uint32;;;;;strides;;;"sport,sport";"running,walking";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;total_calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;total_fat_calories;uint16;;;;;kcal;;;;;If New Leaf;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;avg_speed;uint16;;enhanced_avg_speed;1000;;m/s;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;max_speed;uint16;;enhanced_max_speed;1000;;m/s;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;15;avg_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;max_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;avg_cadence;uint8;;;;;rpm;;;;;total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;avg_running_cadence;uint8;;;;;strides/min;;;sport;running;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;max_cadence;uint8;;;;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;max_running_cadence;uint8;;;;;strides/min;;;sport;running;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;avg_power;uint16;;;;;watts;;;;;total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;max_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;total_ascent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;total_descent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;intensity;intensity;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;24;lap_trigger;lap_trigger;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;25;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;26;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;32;num_lengths;uint16;;;;;lengths;;;;;# of lengths of swim pool;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;33;normalized_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;34;left_right_balance;left_right_balance_100;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;35;first_length_index;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;37;avg_stroke_distance;uint16;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;38;swim_stroke;swim_stroke;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;39;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;40;num_active_lengths;uint16;;;;;lengths;;;;;# of active lengths of swim pool;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;41;total_work;uint32;;;;;J;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;42;avg_altitude;uint16;;enhanced_avg_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;43;max_altitude;uint16;;enhanced_max_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;44;gps_accuracy;uint8;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;45;avg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;46;avg_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;47;avg_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;48;max_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;49;max_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;50;avg_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;51;max_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;52;total_moving_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;53;avg_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;54;avg_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;55;max_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;56;max_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;57;time_in_hr_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;58;time_in_speed_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;59;time_in_cadence_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;60;time_in_power_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;61;repetition_num;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;62;min_altitude;uint16;;enhanced_min_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;63;min_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;71;wkt_step_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;74;opponent_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;75;stroke_count;uint16;[N];;;;counts;;;;;stroke_type enum used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;76;zone_count;uint16;[N];;;;counts;;;;;zone number used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;77;avg_vertical_oscillation;uint16;;;10;;mm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;78;avg_stance_time_percent;uint16;;;100;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;79;avg_stance_time;uint16;;;10;;ms;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;80;avg_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the avg_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;81;max_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the max_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;82;total_fractional_cycles;uint8;;;128;;cycles;;;;;fractional part of the total_cycles;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;83;player_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;84;avg_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Avg saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;85;min_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Min saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;86;max_total_hemoglobin_conc;uint16;[N];;100;;g/dL;;;;;Max saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;87;avg_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Avg percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;88;min_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Min percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;89;max_saturated_hemoglobin_percent;uint16;[N];;10;;%;;;;;Max percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;91;avg_left_torque_effectiveness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;92;avg_right_torque_effectiveness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;93;avg_left_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;94;avg_right_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;95;avg_combined_pedal_smoothness;uint8;;;2;;percent;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;98;time_standing;uint32;;;1000;;s;;;;;Total time spent in the standing position;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;99;stand_count;uint16;;;;;;;;;;Number of transitions to the standing state;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;100;avg_left_pco;sint8;;;;;mm;;;;;Average left platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;101;avg_right_pco;sint8;;;;;mm;;;;;Average right platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;102;avg_left_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;103;avg_left_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;104;avg_right_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;105;avg_right_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;106;avg_power_position;uint16;[N];;;;watts;;;;;Average power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;107;max_power_position;uint16;[N];;;;watts;;;;;Maximum power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;108;avg_cadence_position;uint8;[N];;;;rpm;;;;;Average cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;109;max_cadence_position;uint8;[N];;;;rpm;;;;;Maximum cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;110;enhanced_avg_speed;uint32;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;111;enhanced_max_speed;uint32;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;112;enhanced_avg_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;113;enhanced_min_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;114;enhanced_max_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;115;avg_lev_motor_power;uint16;;;;;watts;;;;;lev average motor power during lap;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;116;max_lev_motor_power;uint16;;;;;watts;;;;;lev maximum motor power during lap;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;117;lev_battery_consumption;uint8;;;2;;percent;;;;;lev battery consumption during lap;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; length;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;event;event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;event_type;event_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_time;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;total_elapsed_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;total_timer_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;total_strokes;uint16;;;;;strokes;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;avg_speed;uint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;swim_stroke;swim_stroke;;;;;swim_stroke;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;avg_swimming_cadence;uint8;;;;;strokes/min;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;total_calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;length_type;length_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;player_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;opponent_score;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;stroke_count;uint16;[N];;;;counts;;;;;stroke_type enum used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;zone_count;uint16;[N];;;;counts;;;;;zone number used as the index;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; record;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;altitude;uint16;;enhanced_altitude;5;500;m;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;cadence;uint8;;;;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;distance;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;speed;uint16;;enhanced_speed;1000;;m/s;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;compressed_speed_distance;byte;[3];"speed,distance";"100,16";;"m/s,m";"12,12";"0,1";;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;resistance;uint8;;;;;;;;;;Relative. 0 is none 254 is Max.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;time_from_course;sint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;cycle_length;uint8;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;speed_1s;uint8;[N];;16;;m/s;;;;;Speed at 1s intervals. Timestamp field indicates time of last array element.;;5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;cycles;uint8;;total_cycles;;;cycles;8;1;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;total_cycles;uint32;;;;;cycles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;28;compressed_accumulated_power;uint16;;accumulated_power;;;watts;16;1;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;29;accumulated_power;uint32;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;30;left_right_balance;left_right_balance;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;31;gps_accuracy;uint8;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;32;vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;33;calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;39;vertical_oscillation;uint16;;;10;;mm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;40;stance_time_percent;uint16;;;100;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;41;stance_time;uint16;;;10;;ms;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;42;activity_type;activity_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;43;left_torque_effectiveness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;44;right_torque_effectiveness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;45;left_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;46;right_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;47;combined_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;48;time128;uint8;;;128;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;49;stroke_type;stroke_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;50;zone;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;51;ball_speed;uint16;;;100;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;52;cadence256;uint16;;;256;;rpm;;;;;Log cadence and fractional cadence for backwards compatability;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;53;fractional_cadence;uint8;;;128;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;54;total_hemoglobin_conc;uint16;;;100;;g/dL;;;;;Total saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;55;total_hemoglobin_conc_min;uint16;;;100;;g/dL;;;;;Min saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;56;total_hemoglobin_conc_max;uint16;;;100;;g/dL;;;;;Max saturated and unsaturated hemoglobin;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;57;saturated_hemoglobin_percent;uint16;;;10;;%;;;;;Percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;58;saturated_hemoglobin_percent_min;uint16;;;10;;%;;;;;Min percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;59;saturated_hemoglobin_percent_max;uint16;;;10;;%;;;;;Max percentage of hemoglobin saturated with oxygen;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;62;device_index;device_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;67;left_pco;sint8;;;;;mm;;;;;Left platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;68;right_pco;sint8;;;;;mm;;;;;Right platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;69;left_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Left power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;70;left_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Left power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;71;right_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Right power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;72;right_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Right power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;73;enhanced_speed;uint32;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;78;enhanced_altitude;uint32;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;81;battery_soc;uint8;;;2;;percent;;;;;lev battery state of charge;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;82;motor_power;uint16;;;;;watts;;;;;lev motor power;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; event;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;event;event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;event_type;event_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;data16;uint16;;data;;;;16;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;data;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;timer_trigger;timer_trigger;;;;;;;;event;timer;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;course_point_index;message_index;;;;;;;;event;course_point;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;battery_level;uint16;;;1000;;V;;;event;battery;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;virtual_partner_speed;uint16;;;1000;;m/s;;;event;virtual_partner_pace;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;hr_high_alert;uint8;;;;;bpm;;;event;hr_high_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;hr_low_alert;uint8;;;;;bpm;;;event;hr_low_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;speed_high_alert;uint32;;;1000;;m/s;;;event;speed_high_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;speed_low_alert;uint32;;;1000;;m/s;;;event;speed_low_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;cad_high_alert;uint16;;;;;rpm;;;event;cad_high_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;cad_low_alert;uint16;;;;;rpm;;;event;cad_low_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;power_high_alert;uint16;;;;;watts;;;event;power_high_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;power_low_alert;uint16;;;;;watts;;;event;power_low_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;time_duration_alert;uint32;;;1000;;s;;;event;time_duration_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;distance_duration_alert;uint32;;;100;;m;;;event;distance_duration_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;calorie_duration_alert;uint32;;;;;calories;;;event;calorie_duration_alert;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;fitness_equipment_state;fitness_equipment_state;;;;;;;;event;fitness_equipment;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;sport_point;uint32;;score,opponent_score;1,1;;;16,16;;event;sport_point;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;gear_change_data;uint32;;"rear_gear_num,rear_gear,front_gear_num,front_gear";1,1,1,1;;;"8,8,8,8";;"event,event";"front_gear_change,rear_gear_change";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;rider_position;rider_position_type;;;;;;;;event;rider_position_change;Indicates the rider position value.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;comm_timeout;comm_timeout_type;;;;;;;;event;comm_timeout;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;score;uint16;;;;;;;;;;Do not populate directly. Autogenerated by decoder for sport_point subfield components;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;opponent_score;uint16;;;;;;;;;;Do not populate directly. Autogenerated by decoder for sport_point subfield components;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;front_gear_num;uint8z;;;;;;;;;;Do not populate directly. Autogenerated by decoder for gear_change subfield components. Front gear number. 1 is innermost.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;front_gear;uint8z;;;;;;;;;;Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of front teeth.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;rear_gear_num;uint8z;;;;;;;;;;Do not populate directly. Autogenerated by decoder for gear_change subfield components. Rear gear number. 1 is innermost.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;rear_gear;uint8z;;;;;;;;;;Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of rear teeth.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;device_index;device_index;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; device_info;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;device_index;device_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;device_type;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;antplus_device_type;antplus_device_type;;;;;;;;source_type;antplus;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;ant_device_type;uint8;;;;;;;;source_type;ant;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;manufacturer;manufacturer;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;serial_number;uint32z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;product;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;garmin_product;garmin_product;;;;;;;;"manufacturer,manufacturer,manufacturer";"garmin,dynastream,dynastream_oem";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;software_version;uint16;;;100;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;hardware_version;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;cum_operating_time;uint32;;;;;s;;;;;Reset by new battery or charge.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;battery_voltage;uint16;;;256;;V;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;battery_status;battery_status;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;sensor_position;body_location;;;;;;;;;;Indicates the location of the sensor;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;descriptor;string;;;;;;;;;;Used to describe the sensor or location;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;ant_transmission_type;uint8z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;ant_device_number;uint16z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;ant_network;ant_network;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;25;source_type;source_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;27;product_name;string;;;;;;;;;;Optional free form string to indicate the devices name or model;;20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; training_file;;;;;;;;;;;;;Corresponds to file_id of workout or course.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;type;file;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;manufacturer;manufacturer;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;product;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;garmin_product;garmin_product;;;;;;;;"manufacturer,manufacturer,manufacturer";"garmin,dynastream,dynastream_oem";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;serial_number;uint32z;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;time_created;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hrv;;;;;;;;;;;;;Heart rate variability;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;time;uint16;[N];;1000;;s;;;;;Time between beats;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; camera_event;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of the timestamp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the timestamp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;camera_event_type;camera_event_type;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;camera_file_uuid;string;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;camera_orientation;camera_orientation_type;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gyroscope_data;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of the timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the timestamp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sample_time_offset;uint16;[N];;;;ms;;;;;Each time in the array describes the time at which the gyro sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;gyro_x;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;gyro_y;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;gyro_z;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;calibrated_gyro_x;float32;[N];;;;deg/s;;;;;Calibrated gyro reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;calibrated_gyro_y;float32;[N];;;;deg/s;;;;;Calibrated gyro reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;calibrated_gyro_z;float32;[N];;;;deg/s;;;;;Calibrated gyro reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; accelerometer_data;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of the timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the timestamp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sample_time_offset;uint16;[N];;;;ms;;;;;Each time in the array describes the time at which the accelerometer sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;accel_x;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;accel_y;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;accel_z;uint16;[N];;;;counts;;;;;These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;calibrated_accel_x;float32;[N];;;;g;;;;;Calibrated accel reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;calibrated_accel_y;float32;[N];;;;g;;;;;Calibrated accel reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;calibrated_accel_z;float32;[N];;;;g;;;;;Calibrated accel reading;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; three_d_sensor_calibration;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of the timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;sensor_type;sensor_type;;;;;;;;;;Indicates which sensor the calibration is for;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;calibration_factor;uint32;;;;;;;;;;Calibration factor used to convert from raw ADC value to degrees, g, etc.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;accel_cal_factor;uint32;;;;;g;;;sensor_type;accelerometer;Accelerometer calibration factor;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;gyro_cal_factor;uint32;;;;;deg/s;;;sensor_type;gyroscope;Gyro calibration factor;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;calibration_divisor;uint32;;;;;counts;;;;;Calibration factor divisor;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;level_shift;uint32;;;;;;;;;;Level shift value used to shift the ADC value back into range;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;offset_cal;sint32;[3];;;;;;;;;Internal calibration factors, one for each: xy, yx, zx;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;orientation_matrix;sint32;[9];;65535;;;;;;;3 x 3 rotation matrix (row major);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; video_frame;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Whole second part of the timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Millisecond part of the timestamp.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;frame_number;uint32;;;;;;;;;;Number of the frame that the timestamp and timestamp_ms correlate to;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; obdii_data;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Timestamp message was output;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Fractional part of timestamp, added to timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;time_offset;uint16;[N];;;;ms;;;;;Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span accross seconds.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;pid;byte;;;;;;;;;;Parameter ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;raw_data;byte;[N];;;;;;;;;Raw parameter data;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;pid_data_size;uint8;[N];;;;;;;;;Optional, data size of PID[i]. If not specified refer to SAE J1979.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;system_time;uint32;[N];;;;;;;;;System time associated with sample expressed in ms, can be used instead of time_offset. There will be a system_time value for each raw_data element. For multibyte pids the system_time is repeated.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;start_timestamp;date_time;;;;;;;;;;Timestamp of first sample recorded in the message. Used with time_offset to generate time of each sample;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;start_timestamp_ms;uint16;;;;;ms;;;;;Fractional part of start_timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; nmea_sentence;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Timestamp message was output;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Fractional part of timestamp, added to timestamp;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;sentence;string;;;;;;;;;;NMEA sentence;;83;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; aviation_attitude;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Timestamp message was output;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timestamp_ms;uint16;;;;;ms;;;;;Fractional part of timestamp, added to timestamp;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;system_time;uint32;[N];;;;ms;;;;;System time associated with sample expressed in ms.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;pitch;sint16;[N];;10430.38;;radians;;;;;Range -PI/2 to +PI/2;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;roll;sint16;[N];;10430.38;;radians;;;;;Range -PI to +PI;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;accel_lateral;sint16;[N];;100;;m/s^2;;;;;Range -78.4 to +78.4 (-8 Gs to 8 Gs);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;accel_normal;sint16;[N];;100;;m/s^2;;;;;Range -78.4 to +78.4 (-8 Gs to 8 Gs);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;turn_rate;sint16;[N];;1024;;radians/second;;;;;Range -8.727 to +8.727 (-500 degs/sec to +500 degs/sec);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;stage;attitude_stage;[N];;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;attitude_stage_complete;uint8;[N];;;;%;;;;;The percent complete of the current attitude stage. Set to 0 for attitude stages 0, 1 and 2 and to 100 for attitude stage 3 by AHRS modules that do not support it. Range - 100;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;track;uint16;[N];;10430.38;;radians;;;;;Track Angle/Heading Range 0 - 2pi;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;validity;attitude_validity;[N];;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; video;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;url;string;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;hosting_provider;string;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;duration;uint32;;;;;ms;;;;;Playback time of video;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; video_title;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;Long titles will be split into multiple parts;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;message_count;uint16;;;;;;;;;;Total number of title parts;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;text;string;;;;;;;;;;;;80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; video_description;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;Long descriptions will be split into multiple parts;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;message_count;uint16;;;;;;;;;;Total number of description parts;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;text;string;;;;;;;;;;;;250;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; video_clip;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;clip_number;uint16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;start_timestamp;date_time;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_timestamp_ms;uint16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;end_timestamp;date_time;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;end_timestamp_ms;uint16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;clip_start;uint32;;;;;ms;;;;;Start of clip in video time;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;clip_end;uint32;;;;;ms;;;;;End of clip in video time;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;COURSE FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; course;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;capabilities;course_capabilities;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; course_point;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;timestamp;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;distance;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;type;course_point;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;favorite;bool;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;SEGMENT FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; segment_id;;;;;;;;;;;;;Unique Identification data for a segment file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;name;string;;;;;;;;;;Friendly name assigned to segment;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;uuid;string;;;;;;;;;;UUID of the segment;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;sport;sport;;;;;;;;;;Sport associated with the segment;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;enabled;bool;;;;;;;;;;Segment enabled for evaluation;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;user_profile_primary_key;uint32;;;;;;;;;;Primary key of the user that created the segment ;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;device_id;uint32;;;;;;;;;;ID of the device that created the segment;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;default_race_leader;uint8;;;;;;;;;;Index for the Leader Board entry selected as the default race participant;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;delete_status;segment_delete_status;;;;;;;;;;Indicates if any segments should be deleted;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;selection_type;segment_selection_type;;;;;;;;;;Indicates how the segment was selected to be sent to the device;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; segment_leaderboard_entry;;;;;;;;;;;;;Unique Identification data for an individual segment leader within a segment file;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;name;string;;;;;;;;;;Friendly name assigned to leader;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;type;segment_leaderboard_type;;;;;;;;;;Leader classification;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;group_primary_key;uint32;;;;;;;;;;Primary user ID of this leader;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;activity_id;uint32;;;;;;;;;;ID of the activity associated with this leader time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;segment_time;uint32;;;1000;;s;;;;;Segment Time (includes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;activity_id_string;string;;;;;;;;;;String version of the activity_id. 21 characters long, express in decimal;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; segment_point;;;;;;;;;;;;;Navigation and race evaluation point for a segment decribing a point along the segment path and time it took each segment leader to reach that point ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;distance;uint32;;;100;;m;;;;;Accumulated distance along the segment at the described point;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;altitude;uint16;;;5;500;m;;;;;Accumulated altitude along the segment at the described point;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;leader_time;uint32;[N];;1000;;s;;;;;Accumualted time each leader board member required to reach the described point. This value is zero for all leader board members at the starting point of the segment. ;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; segment_lap;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Lap end time.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;event;event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;event_type;event_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;start_time;date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;start_position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;start_position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;end_position_lat;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;end_position_long;sint32;;;;;semicircles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;total_elapsed_time;uint32;;;1000;;s;;;;;Time (includes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;total_timer_time;uint32;;;1000;;s;;;;;Timer Time (excludes pauses);;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;total_distance;uint32;;;100;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;total_cycles;uint32;;;;;cycles;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;total_strokes;uint32;;;;;strokes;;;sport;cycling;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;total_calories;uint16;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;total_fat_calories;uint16;;;;;kcal;;;;;If New Leaf;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;13;avg_speed;uint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;max_speed;uint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;15;avg_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;max_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;17;avg_cadence;uint8;;;;;rpm;;;;;total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;18;max_cadence;uint8;;;;;rpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;avg_power;uint16;;;;;watts;;;;;total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;20;max_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;21;total_ascent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;22;total_descent;uint16;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;23;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;24;event_group;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;25;nec_lat;sint32;;;;;semicircles;;;;;North east corner latitude.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;26;nec_long;sint32;;;;;semicircles;;;;;North east corner longitude.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;27;swc_lat;sint32;;;;;semicircles;;;;;South west corner latitude.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;28;swc_long;sint32;;;;;semicircles;;;;;South west corner latitude.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;29;name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;30;normalized_power;uint16;;;;;watts;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;31;left_right_balance;left_right_balance_100;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;32;sub_sport;sub_sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;33;total_work;uint32;;;;;J;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;34;avg_altitude;uint16;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;35;max_altitude;uint16;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;36;gps_accuracy;uint8;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;37;avg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;38;avg_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;39;avg_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;40;max_pos_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;41;max_neg_grade;sint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;42;avg_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;43;max_temperature;sint8;;;;;C;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;44;total_moving_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;45;avg_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;46;avg_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;47;max_pos_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;48;max_neg_vertical_speed;sint16;;;1000;;m/s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;49;time_in_hr_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;50;time_in_speed_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;51;time_in_cadence_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;52;time_in_power_zone;uint32;[N];;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;53;repetition_num;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;54;min_altitude;uint16;;;5;500;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;55;min_heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;56;active_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;57;wkt_step_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;58;sport_event;sport_event;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;59;avg_left_torque_effectiveness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;60;avg_right_torque_effectiveness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;61;avg_left_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;62;avg_right_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;63;avg_combined_pedal_smoothness;uint8;;;2;;percent;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;64;status;segment_lap_status;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;65;uuid;string;;;;;;;;;;;;33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;66;avg_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the avg_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;67;max_fractional_cadence;uint8;;;128;;rpm;;;;;fractional part of the max_cadence;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;68;total_fractional_cycles;uint8;;;128;;cycles;;;;;fractional part of the total_cycles;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;69;front_gear_shift_count;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;70;rear_gear_shift_count;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;71;time_standing;uint32;;;1000;;s;;;;;Total time spent in the standing position;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;72;stand_count;uint16;;;;;;;;;;Number of transitions to the standing state;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;73;avg_left_pco;sint8;;;;;mm;;;;;Average left platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;74;avg_right_pco;sint8;;;;;mm;;;;;Average right platform center offset;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;75;avg_left_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;76;avg_left_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average left power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;77;avg_right_power_phase;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;78;avg_right_power_phase_peak;uint8;[N];;0.7111111;;degrees;;;;;Average right power phase peak angles. Data value indexes defined by power_phase_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;79;avg_power_position;uint16;[N];;;;watts;;;;;Average power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;80;max_power_position;uint16;[N];;;;watts;;;;;Maximum power by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;81;avg_cadence_position;uint8;[N];;;;rpm;;;;;Average cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;82;max_cadence_position;uint8;[N];;;;rpm;;;;;Maximum cadence by position. Data value indexes defined by rider_position_type.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;SEGMENT LIST FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; segment_file;;;;;;;;;;;;;Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;file_uuid;string;;;;;;;;;;UUID of the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;enabled;bool;;;;;;;;;;Enabled state of the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;user_profile_primary_key;uint32;;;;;;;;;;Primary key of the user that created the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;leader_type;segment_leaderboard_type;[N];;;;;;;;;Leader type of each leader in the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;leader_group_primary_key;uint32;[N];;;;;;;;;Group primary key of each leader in the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;leader_activity_id;uint32;[N];;;;;;;;;Activity ID of each leader in the segment file;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;leader_activity_id_string;string;[N];;;;;;;;;String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;WORKOUT FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; workout;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;capabilities;workout_capabilities;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;num_valid_steps;uint16;;;;;;;;;;number of valid steps;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;wkt_name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; workout_step;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;wkt_step_name;string;;;;;;;;;;;;16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;duration_type;wkt_step_duration;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;duration_value;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_time;uint32;;;1000;;s;;;duration_type,duration_type;time,repetition_time;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_distance;uint32;;;100;;m;;;duration_type;distance;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_hr;workout_hr;;;;;% or bpm;;;duration_type,duration_type;hr_less_than,hr_greater_than;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_calories;uint32;;;;;calories;;;duration_type;calories;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_step;uint32;;;;;;;;duration_type,duration_type,duration_type,duration_type,duration_type,duration_type,duration_type,duration_type;repeat_until_steps_cmplt,repeat_until_time,repeat_until_distance,repeat_until_calories,repeat_until_hr_less_than,repeat_until_hr_greater_than,repeat_until_power_less_than,repeat_until_power_greater_than;message_index of step to loop back to. Steps are assumed to be in the order by message_index. custom_name and intensity members are undefined for this duration type.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;duration_power;workout_power;;;;;% or watts;;;duration_type,duration_type;power_less_than,power_greater_than;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;target_type;wkt_step_target;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;target_value;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;target_hr_zone;uint32;;;;;;;;target_type;heart_rate;"hr zone (1-5);Custom =0;";;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;target_power_zone;uint32;;;;;;;;target_type;power;"Power Zone ( 1-7); Custom = 0;";;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_steps;uint32;;;;;;;;duration_type;repeat_until_steps_cmplt;# of repetitions;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_time;uint32;;;1000;;s;;;duration_type;repeat_until_time;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_distance;uint32;;;100;;m;;;duration_type;repeat_until_distance;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_calories;uint32;;;;;calories;;;duration_type;repeat_until_calories;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_hr;workout_hr;;;;;% or bpm;;;"duration_type,duration_type";"repeat_until_hr_less_than,repeat_until_hr_greater_than";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;repeat_power;workout_power;;;;;% or watts;;;"duration_type,duration_type";"repeat_until_power_less_than,repeat_until_power_greater_than";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;custom_target_value_low;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_speed_low;uint32;;;1000;;m/s;;;target_type;speed;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_heart_rate_low;workout_hr;;;;;% or bpm;;;target_type;heart_rate;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_cadence_low;uint32;;;;;rpm;;;target_type;cadence;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_power_low;workout_power;;;;;% or watts;;;target_type;power;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;custom_target_value_high;uint32;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_speed_high;uint32;;;1000;;m/s;;;target_type;speed;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_heart_rate_high;workout_hr;;;;;% or bpm;;;target_type;heart_rate;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_cadence_high;uint32;;;;;rpm;;;target_type;cadence;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;custom_target_power_high;workout_power;;;;;% or watts;;;target_type;power;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;intensity;intensity;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;SCHEDULE FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; schedule;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;manufacturer;manufacturer;;;;;;;;;;Corresponds to file_id of scheduled workout / course.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;product;uint16;;;;;;;;;;Corresponds to file_id of scheduled workout / course.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;garmin_product;garmin_product;;;;;;;;"manufacturer,manufacturer,manufacturer";"garmin,dynastream,dynastream_oem";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;serial_number;uint32z;;;;;;;;;;Corresponds to file_id of scheduled workout / course.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;time_created;date_time;;;;;;;;;;Corresponds to file_id of scheduled workout / course.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;completed;bool;;;;;;;;;;TRUE if this activity has been started;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;type;schedule;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;scheduled_time;local_date_time;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;TOTALS FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; totals;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;254;message_index;message_index;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;timer_time;uint32;;;;;s;;;;;Excludes pauses;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;distance;uint32;;;;;m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;calories;uint32;;;;;kcal;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;sport;sport;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;elapsed_time;uint32;;;;;s;;;;;Includes pauses;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;sessions;uint16;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;active_time;uint32;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;sport_index;uint8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;WEIGHT SCALE FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; weight_scale;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;weight;weight;;;100;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;percent_fat;uint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;percent_hydration;uint16;;;100;;%;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;visceral_fat_mass;uint16;;;100;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;bone_mass;uint16;;;100;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;muscle_mass;uint16;;;100;;kg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;basal_met;uint16;;;4;;kcal/day;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;physique_rating;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;active_met;uint16;;;4;;kcal/day;;;;;~4kJ per kcal, 0.25 allows max 16384 kcal;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;metabolic_age;uint8;;;;;years;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;visceral_fat_rating;uint8;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;user_profile_index;message_index;;;;;;;;;;Associates this weight scale message to a user. This corresponds to the index of the user profile message in the weight scale file.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;BLOOD PRESSURE FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; blood_pressure;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;systolic_pressure;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;diastolic_pressure;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;mean_arterial_pressure;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;map_3_sample_mean;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;map_morning_values;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;map_evening_values;uint16;;;;;mmHg;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;heart_rate;uint8;;;;;bpm;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;heart_rate_type;hr_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;status;bp_status;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;user_profile_index;message_index;;;;;;;;;;Associates this blood pressure message to a user. This corresponds to the index of the user profile message in the blood pressure file.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;MONITORING FILE MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; monitoring_info;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;local_timestamp;local_date_time;;;;;s;;;;;Use to convert activity timestamps to local time if device does not support time zone and daylight savings time correction.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;activity_type;activity_type;[N];;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;cycles_to_distance;uint16;[N];;5000;;m/cycle;;;;;Indexed by activity_type;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;cycles_to_calories;uint16;[N];;5000;;kcal/cycle;;;;;Indexed by activity_type;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;resting_metabolic_rate;uint16;;;;;kcal / day;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; monitoring;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;253;timestamp;date_time;;;;;s;;;;;Must align to logging interval, for example, time must be 00:00:00 for daily log.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;device_index;device_index;;;;;;;;;;Associates this data to device_info message. Not required for file with single device (sensor).;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;calories;uint16;;;;;kcal;;;;;Accumulated total calories. Maintained by MonitoringReader for each activity_type. See SDK documentation;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;distance;uint32;;;100;;m;;;;;Accumulated distance. Maintained by MonitoringReader for each activity_type. See SDK documentation.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;3;cycles;uint32;;;2;;cycles;;;;;Accumulated cycles. Maintained by MonitoringReader for each activity_type. See SDK documentation.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;steps;uint32;;;1;;steps;;;"activity_type,activity_type";"walking,running";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;strokes;uint32;;;2;;strokes;;;"activity_type,activity_type";"cycling,swimming";;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;4;active_time;uint32;;;1000;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;5;activity_type;activity_type;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;6;activity_subtype;activity_subtype;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;7;activity_level;activity_level;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;8;distance_16;uint16;;;;;100 * m;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;9;cycles_16;uint16;;;;;2 * cycles (steps);;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;10;active_time_16;uint16;;;;;s;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;11;local_timestamp;local_date_time;;;;;;;;;;Must align to logging interval, for example, time must be 00:00:00 for daily log.;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;12;temperature;sint16;;;100;;C;;;;;Avg temperature during the logging interval ended at timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;14;temperature_min;sint16;;;100;;C;;;;;Min temperature during the logging interval ended at timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;15;temperature_max;sint16;;;100;;C;;;;;Max temperature during the logging interval ended at timestamp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;16;activity_time;uint16;[8];;;;minutes;;;;;Indexed using minute_activity_level enum;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;19;active_calories;uint16;;;;;kcal;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;24;current_activity_type_intensity;byte;;activity_type,intensity;;;;5,3;;;;Indicates single type / intensity for duration since last monitoring message.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;25;timestamp_min_8;uint8;;;;;min;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;26;timestamp_16;uint16;;;;;s;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;27;heart_rate;uint8;;;;;bpm;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;28;intensity;uint8;;;10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;29;duration_min;uint16;;;;;min;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;30;duration;uint32;;;;;s;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;OTHER MESSAGES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; memo_glob;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;250;part_index;uint32;;;;;;;;;;Sequence number of memo blocks;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;0;memo;byte;[N];;;;;;;;;Block of utf8 bytes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;1;message_number;uint16;;;;;;;;;;Allows relating glob to another mesg If used only required for first part of each memo_glob;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;2;message_index;message_index;;;;;;;;;;Index of external mesg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qmapshack-1.10.0/src/gis/fit/defs/CFitProfileLookup.cpp000644 001750 000144 00000352072 13216234140 024047 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "CFitProfileLookup.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/fit_const.h" #include "gis/fit/defs/fit_enums.h" #include "gis/fit/defs/fit_fields.h" #include // ----------- start generated code ----------- void initFileId(QMap& profiles) { CFitProfile* f = new CFitProfile("file_id", eMesgNumFileId); f->addField("type", fitEnumType, eFileIdType, 0, 0, ""); f->addField("manufacturer", fitEnumType, eFileIdManufacturer, 0, 0, ""); f->addField("product", fitUint16Type, eFileIdProduct, 0, 0, ""); f->addSubfield("garmin_product", fitEnumType, eFileIdProduct, 0, 0, "", eFileIdManufacturer, eManufacturerGarmin); f->addSubfield("garmin_product", fitEnumType, eFileIdProduct, 0, 0, "", eFileIdManufacturer, eManufacturerDynastream); f->addSubfield("garmin_product", fitEnumType, eFileIdProduct, 0, 0, "", eFileIdManufacturer, eManufacturerDynastreamOem); f->addField("serial_number", fitUint32zType, eFileIdSerialNumber, 0, 0, ""); f->addField("time_created", fitEnumType, eFileIdTimeCreated, 0, 0, ""); f->addField("number", fitUint16Type, eFileIdNumber, 0, 0, ""); f->addField("product_name", fitStringType, eFileIdProductName, 0, 0, ""); profiles.insert(eMesgNumFileId, f); } void initFileCreator(QMap& profiles) { CFitProfile* f = new CFitProfile("file_creator", eMesgNumFileCreator); f->addField("software_version", fitUint16Type, eFileCreatorSoftwareVersion, 0, 0, ""); f->addField("hardware_version", fitUint8Type, eFileCreatorHardwareVersion, 0, 0, ""); profiles.insert(eMesgNumFileCreator, f); } void initTimestampCorrelation(QMap& profiles) { CFitProfile* f = new CFitProfile("timestamp_correlation", eMesgNumTimestampCorrelation); f->addField("timestamp", fitEnumType, eTimestampCorrelationTimestamp, 0, 0, "s"); f->addField("fractional_timestamp", fitUint16Type, eTimestampCorrelationFractionalTimestamp, 32768, 0, "s"); f->addField("system_timestamp", fitEnumType, eTimestampCorrelationSystemTimestamp, 0, 0, "s"); f->addField("fractional_system_timestamp", fitUint16Type, eTimestampCorrelationFractionalSystemTimestamp, 32768, 0, "s"); f->addField("local_timestamp", fitEnumType, eTimestampCorrelationLocalTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eTimestampCorrelationTimestampMs, 0, 0, "ms"); f->addField("system_timestamp_ms", fitUint16Type, eTimestampCorrelationSystemTimestampMs, 0, 0, "ms"); profiles.insert(eMesgNumTimestampCorrelation, f); } void initSoftware(QMap& profiles) { CFitProfile* f = new CFitProfile("software", eMesgNumSoftware); f->addField("message_index", fitEnumType, eSoftwareMessageIndex, 0, 0, ""); f->addField("version", fitUint16Type, eSoftwareVersion, 100, 0, ""); f->addField("part_number", fitStringType, eSoftwarePartNumber, 0, 0, ""); profiles.insert(eMesgNumSoftware, f); } void initSlaveDevice(QMap& profiles) { CFitProfile* f = new CFitProfile("slave_device", eMesgNumSlaveDevice); f->addField("manufacturer", fitEnumType, eSlaveDeviceManufacturer, 0, 0, ""); f->addField("product", fitUint16Type, eSlaveDeviceProduct, 0, 0, ""); f->addSubfield("garmin_product", fitEnumType, eSlaveDeviceProduct, 0, 0, "", eSlaveDeviceManufacturer, eManufacturerGarmin); f->addSubfield("garmin_product", fitEnumType, eSlaveDeviceProduct, 0, 0, "", eSlaveDeviceManufacturer, eManufacturerDynastream); f->addSubfield("garmin_product", fitEnumType, eSlaveDeviceProduct, 0, 0, "", eSlaveDeviceManufacturer, eManufacturerDynastreamOem); profiles.insert(eMesgNumSlaveDevice, f); } void initCapabilities(QMap& profiles) { CFitProfile* f = new CFitProfile("capabilities", eMesgNumCapabilities); f->addField("languages", fitUint8zType, eCapabilitiesLanguages, 0, 0, ""); f->addField("sports", fitEnumType, eCapabilitiesSports, 0, 0, ""); f->addField("workouts_supported", fitEnumType, eCapabilitiesWorkoutsSupported, 0, 0, ""); f->addField("connectivity_supported", fitEnumType, eCapabilitiesConnectivitySupported, 0, 0, ""); profiles.insert(eMesgNumCapabilities, f); } void initFileCapabilities(QMap& profiles) { CFitProfile* f = new CFitProfile("file_capabilities", eMesgNumFileCapabilities); f->addField("message_index", fitEnumType, eFileCapabilitiesMessageIndex, 0, 0, ""); f->addField("type", fitEnumType, eFileCapabilitiesType, 0, 0, ""); f->addField("flags", fitEnumType, eFileCapabilitiesFlags, 0, 0, ""); f->addField("directory", fitStringType, eFileCapabilitiesDirectory, 0, 0, ""); f->addField("max_count", fitUint16Type, eFileCapabilitiesMaxCount, 0, 0, ""); f->addField("max_size", fitUint32Type, eFileCapabilitiesMaxSize, 0, 0, "bytes"); profiles.insert(eMesgNumFileCapabilities, f); } void initMesgCapabilities(QMap& profiles) { CFitProfile* f = new CFitProfile("mesg_capabilities", eMesgNumMesgCapabilities); f->addField("message_index", fitEnumType, eMesgCapabilitiesMessageIndex, 0, 0, ""); f->addField("file", fitEnumType, eMesgCapabilitiesFile, 0, 0, ""); f->addField("mesg_num", fitEnumType, eMesgCapabilitiesMesgNum, 0, 0, ""); f->addField("count_type", fitEnumType, eMesgCapabilitiesCountType, 0, 0, ""); f->addField("count", fitUint16Type, eMesgCapabilitiesCount, 0, 0, ""); f->addSubfield("num_per_file", fitUint16Type, eMesgCapabilitiesCount, 0, 0, "", eMesgCapabilitiesCountType, eMesgCountNumPerFile); f->addSubfield("max_per_file", fitUint16Type, eMesgCapabilitiesCount, 0, 0, "", eMesgCapabilitiesCountType, eMesgCountMaxPerFile); f->addSubfield("max_per_file_type", fitUint16Type, eMesgCapabilitiesCount, 0, 0, "", eMesgCapabilitiesCountType, eMesgCountMaxPerFileType); profiles.insert(eMesgNumMesgCapabilities, f); } void initFieldCapabilities(QMap& profiles) { CFitProfile* f = new CFitProfile("field_capabilities", eMesgNumFieldCapabilities); f->addField("message_index", fitEnumType, eFieldCapabilitiesMessageIndex, 0, 0, ""); f->addField("file", fitEnumType, eFieldCapabilitiesFile, 0, 0, ""); f->addField("mesg_num", fitEnumType, eFieldCapabilitiesMesgNum, 0, 0, ""); f->addField("field_num", fitUint8Type, eFieldCapabilitiesFieldNum, 0, 0, ""); f->addField("count", fitUint16Type, eFieldCapabilitiesCount, 0, 0, ""); profiles.insert(eMesgNumFieldCapabilities, f); } void initDeviceSettings(QMap& profiles) { CFitProfile* f = new CFitProfile("device_settings", eMesgNumDeviceSettings); f->addField("active_time_zone", fitUint8Type, eDeviceSettingsActiveTimeZone, 0, 0, ""); f->addField("utc_offset", fitUint32Type, eDeviceSettingsUtcOffset, 0, 0, ""); f->addField("time_offset", fitUint32Type, eDeviceSettingsTimeOffset, 0, 0, "s"); f->addField("time_mode", fitEnumType, eDeviceSettingsTimeMode, 0, 0, ""); f->addField("time_zone_offset", fitSint8Type, eDeviceSettingsTimeZoneOffset, 4, 0, "hr"); f->addField("backlight_mode", fitEnumType, eDeviceSettingsBacklightMode, 0, 0, ""); f->addField("activity_tracker_enabled", fitEnumType, eDeviceSettingsActivityTrackerEnabled, 0, 0, ""); f->addField("clock_time", fitEnumType, eDeviceSettingsClockTime, 0, 0, ""); f->addField("pages_enabled", fitUint16Type, eDeviceSettingsPagesEnabled, 0, 0, ""); f->addField("move_alert_enabled", fitEnumType, eDeviceSettingsMoveAlertEnabled, 0, 0, ""); f->addField("date_mode", fitEnumType, eDeviceSettingsDateMode, 0, 0, ""); f->addField("display_orientation", fitEnumType, eDeviceSettingsDisplayOrientation, 0, 0, ""); f->addField("mounting_side", fitEnumType, eDeviceSettingsMountingSide, 0, 0, ""); f->addField("default_page", fitUint16Type, eDeviceSettingsDefaultPage, 0, 0, ""); f->addField("autosync_min_steps", fitUint16Type, eDeviceSettingsAutosyncMinSteps, 0, 0, "steps"); f->addField("autosync_min_time", fitUint16Type, eDeviceSettingsAutosyncMinTime, 0, 0, "minutes"); f->addField("lactate_threshold_autodetect_enabled", fitEnumType, eDeviceSettingsLactateThresholdAutodetectEnabled, 0, 0, ""); f->addField("ble_auto_upload_enabled", fitEnumType, eDeviceSettingsBleAutoUploadEnabled, 0, 0, ""); f->addField("auto_sync_frequency", fitEnumType, eDeviceSettingsAutoSyncFrequency, 0, 0, ""); f->addField("auto_activity_detect", fitEnumType, eDeviceSettingsAutoActivityDetect, 0, 0, ""); f->addField("number_of_screens", fitUint8Type, eDeviceSettingsNumberOfScreens, 0, 0, ""); f->addField("smart_notification_display_orientation", fitEnumType, eDeviceSettingsSmartNotificationDisplayOrientation, 0, 0, ""); profiles.insert(eMesgNumDeviceSettings, f); } void initUserProfile(QMap& profiles) { CFitProfile* f = new CFitProfile("user_profile", eMesgNumUserProfile); f->addField("message_index", fitEnumType, eUserProfileMessageIndex, 0, 0, ""); f->addField("friendly_name", fitStringType, eUserProfileFriendlyName, 0, 0, ""); f->addField("gender", fitEnumType, eUserProfileGender, 0, 0, ""); f->addField("age", fitUint8Type, eUserProfileAge, 0, 0, "years"); f->addField("height", fitUint8Type, eUserProfileHeight, 100, 0, "m"); f->addField("weight", fitUint16Type, eUserProfileWeight, 10, 0, "kg"); f->addField("language", fitEnumType, eUserProfileLanguage, 0, 0, ""); f->addField("elev_setting", fitEnumType, eUserProfileElevSetting, 0, 0, ""); f->addField("weight_setting", fitEnumType, eUserProfileWeightSetting, 0, 0, ""); f->addField("resting_heart_rate", fitUint8Type, eUserProfileRestingHeartRate, 0, 0, "bpm"); f->addField("default_max_running_heart_rate", fitUint8Type, eUserProfileDefaultMaxRunningHeartRate, 0, 0, "bpm"); f->addField("default_max_biking_heart_rate", fitUint8Type, eUserProfileDefaultMaxBikingHeartRate, 0, 0, "bpm"); f->addField("default_max_heart_rate", fitUint8Type, eUserProfileDefaultMaxHeartRate, 0, 0, "bpm"); f->addField("hr_setting", fitEnumType, eUserProfileHrSetting, 0, 0, ""); f->addField("speed_setting", fitEnumType, eUserProfileSpeedSetting, 0, 0, ""); f->addField("dist_setting", fitEnumType, eUserProfileDistSetting, 0, 0, ""); f->addField("power_setting", fitEnumType, eUserProfilePowerSetting, 0, 0, ""); f->addField("activity_class", fitEnumType, eUserProfileActivityClass, 0, 0, ""); f->addField("position_setting", fitEnumType, eUserProfilePositionSetting, 0, 0, ""); f->addField("temperature_setting", fitEnumType, eUserProfileTemperatureSetting, 0, 0, ""); f->addField("local_id", fitEnumType, eUserProfileLocalId, 0, 0, ""); f->addField("global_id", fitByteType, eUserProfileGlobalId, 0, 0, ""); f->addField("wake_time", fitEnumType, eUserProfileWakeTime, 0, 0, ""); f->addField("sleep_time", fitEnumType, eUserProfileSleepTime, 0, 0, ""); f->addField("height_setting", fitEnumType, eUserProfileHeightSetting, 0, 0, ""); f->addField("user_running_step_length", fitUint16Type, eUserProfileUserRunningStepLength, 1000, 0, "m"); f->addField("user_walking_step_length", fitUint16Type, eUserProfileUserWalkingStepLength, 1000, 0, "m"); profiles.insert(eMesgNumUserProfile, f); } void initHrmProfile(QMap& profiles) { CFitProfile* f = new CFitProfile("hrm_profile", eMesgNumHrmProfile); f->addField("message_index", fitEnumType, eHrmProfileMessageIndex, 0, 0, ""); f->addField("enabled", fitEnumType, eHrmProfileEnabled, 0, 0, ""); f->addField("hrm_ant_id", fitUint16zType, eHrmProfileHrmAntId, 0, 0, ""); f->addField("log_hrv", fitEnumType, eHrmProfileLogHrv, 0, 0, ""); f->addField("hrm_ant_id_trans_type", fitUint8zType, eHrmProfileHrmAntIdTransType, 0, 0, ""); profiles.insert(eMesgNumHrmProfile, f); } void initSdmProfile(QMap& profiles) { CFitProfile* f = new CFitProfile("sdm_profile", eMesgNumSdmProfile); f->addField("message_index", fitEnumType, eSdmProfileMessageIndex, 0, 0, ""); f->addField("enabled", fitEnumType, eSdmProfileEnabled, 0, 0, ""); f->addField("sdm_ant_id", fitUint16zType, eSdmProfileSdmAntId, 0, 0, ""); f->addField("sdm_cal_factor", fitUint16Type, eSdmProfileSdmCalFactor, 10, 0, "%"); f->addField("odometer", fitUint32Type, eSdmProfileOdometer, 100, 0, "m"); f->addField("speed_source", fitEnumType, eSdmProfileSpeedSource, 0, 0, ""); f->addField("sdm_ant_id_trans_type", fitUint8zType, eSdmProfileSdmAntIdTransType, 0, 0, ""); f->addField("odometer_rollover", fitUint8Type, eSdmProfileOdometerRollover, 0, 0, ""); profiles.insert(eMesgNumSdmProfile, f); } void initBikeProfile(QMap& profiles) { CFitProfile* f = new CFitProfile("bike_profile", eMesgNumBikeProfile); f->addField("message_index", fitEnumType, eBikeProfileMessageIndex, 0, 0, ""); f->addField("name", fitStringType, eBikeProfileName, 0, 0, ""); f->addField("sport", fitEnumType, eBikeProfileSport, 0, 0, ""); f->addField("sub_sport", fitEnumType, eBikeProfileSubSport, 0, 0, ""); f->addField("odometer", fitUint32Type, eBikeProfileOdometer, 100, 0, "m"); f->addField("bike_spd_ant_id", fitUint16zType, eBikeProfileBikeSpdAntId, 0, 0, ""); f->addField("bike_cad_ant_id", fitUint16zType, eBikeProfileBikeCadAntId, 0, 0, ""); f->addField("bike_spdcad_ant_id", fitUint16zType, eBikeProfileBikeSpdcadAntId, 0, 0, ""); f->addField("bike_power_ant_id", fitUint16zType, eBikeProfileBikePowerAntId, 0, 0, ""); f->addField("custom_wheelsize", fitUint16Type, eBikeProfileCustomWheelsize, 1000, 0, "m"); f->addField("auto_wheelsize", fitUint16Type, eBikeProfileAutoWheelsize, 1000, 0, "m"); f->addField("bike_weight", fitUint16Type, eBikeProfileBikeWeight, 10, 0, "kg"); f->addField("power_cal_factor", fitUint16Type, eBikeProfilePowerCalFactor, 10, 0, "%"); f->addField("auto_wheel_cal", fitEnumType, eBikeProfileAutoWheelCal, 0, 0, ""); f->addField("auto_power_zero", fitEnumType, eBikeProfileAutoPowerZero, 0, 0, ""); f->addField("id", fitUint8Type, eBikeProfileId, 0, 0, ""); f->addField("spd_enabled", fitEnumType, eBikeProfileSpdEnabled, 0, 0, ""); f->addField("cad_enabled", fitEnumType, eBikeProfileCadEnabled, 0, 0, ""); f->addField("spdcad_enabled", fitEnumType, eBikeProfileSpdcadEnabled, 0, 0, ""); f->addField("power_enabled", fitEnumType, eBikeProfilePowerEnabled, 0, 0, ""); f->addField("crank_length", fitUint8Type, eBikeProfileCrankLength, 2, -110, "mm"); f->addField("enabled", fitEnumType, eBikeProfileEnabled, 0, 0, ""); f->addField("bike_spd_ant_id_trans_type", fitUint8zType, eBikeProfileBikeSpdAntIdTransType, 0, 0, ""); f->addField("bike_cad_ant_id_trans_type", fitUint8zType, eBikeProfileBikeCadAntIdTransType, 0, 0, ""); f->addField("bike_spdcad_ant_id_trans_type", fitUint8zType, eBikeProfileBikeSpdcadAntIdTransType, 0, 0, ""); f->addField("bike_power_ant_id_trans_type", fitUint8zType, eBikeProfileBikePowerAntIdTransType, 0, 0, ""); f->addField("odometer_rollover", fitUint8Type, eBikeProfileOdometerRollover, 0, 0, ""); f->addField("front_gear_num", fitUint8zType, eBikeProfileFrontGearNum, 0, 0, ""); f->addField("front_gear", fitUint8zType, eBikeProfileFrontGear, 0, 0, ""); f->addField("rear_gear_num", fitUint8zType, eBikeProfileRearGearNum, 0, 0, ""); f->addField("rear_gear", fitUint8zType, eBikeProfileRearGear, 0, 0, ""); f->addField("shimano_di2_enabled", fitEnumType, eBikeProfileShimanoDi2Enabled, 0, 0, ""); profiles.insert(eMesgNumBikeProfile, f); } void initConnectivity(QMap& profiles) { CFitProfile* f = new CFitProfile("connectivity", eMesgNumConnectivity); f->addField("bluetooth_enabled", fitEnumType, eConnectivityBluetoothEnabled, 0, 0, ""); f->addField("bluetooth_le_enabled", fitEnumType, eConnectivityBluetoothLeEnabled, 0, 0, ""); f->addField("ant_enabled", fitEnumType, eConnectivityAntEnabled, 0, 0, ""); f->addField("name", fitStringType, eConnectivityName, 0, 0, ""); f->addField("live_tracking_enabled", fitEnumType, eConnectivityLiveTrackingEnabled, 0, 0, ""); f->addField("weather_conditions_enabled", fitEnumType, eConnectivityWeatherConditionsEnabled, 0, 0, ""); f->addField("weather_alerts_enabled", fitEnumType, eConnectivityWeatherAlertsEnabled, 0, 0, ""); f->addField("auto_activity_upload_enabled", fitEnumType, eConnectivityAutoActivityUploadEnabled, 0, 0, ""); f->addField("course_download_enabled", fitEnumType, eConnectivityCourseDownloadEnabled, 0, 0, ""); f->addField("workout_download_enabled", fitEnumType, eConnectivityWorkoutDownloadEnabled, 0, 0, ""); f->addField("gps_ephemeris_download_enabled", fitEnumType, eConnectivityGpsEphemerisDownloadEnabled, 0, 0, ""); f->addField("incident_detection_enabled", fitEnumType, eConnectivityIncidentDetectionEnabled, 0, 0, ""); f->addField("grouptrack_enabled", fitEnumType, eConnectivityGrouptrackEnabled, 0, 0, ""); profiles.insert(eMesgNumConnectivity, f); } void initWatchfaceSettings(QMap& profiles) { CFitProfile* f = new CFitProfile("watchface_settings", eMesgNumWatchfaceSettings); f->addField("message_index", fitEnumType, eWatchfaceSettingsMessageIndex, 0, 0, ""); f->addField("mode", fitEnumType, eWatchfaceSettingsMode, 0, 0, ""); f->addField("layout", fitByteType, eWatchfaceSettingsLayout, 0, 0, ""); f->addSubfield("digital_layout", fitEnumType, eWatchfaceSettingsLayout, 0, 0, "", eWatchfaceSettingsMode, eWatchfaceModeDigital); f->addSubfield("analog_layout", fitEnumType, eWatchfaceSettingsLayout, 0, 0, "", eWatchfaceSettingsMode, eWatchfaceModeAnalog); profiles.insert(eMesgNumWatchfaceSettings, f); } void initOhrSettings(QMap& profiles) { CFitProfile* f = new CFitProfile("ohr_settings", eMesgNumOhrSettings); f->addField("enabled", fitEnumType, eOhrSettingsEnabled, 0, 0, ""); profiles.insert(eMesgNumOhrSettings, f); } void initZonesTarget(QMap& profiles) { CFitProfile* f = new CFitProfile("zones_target", eMesgNumZonesTarget); f->addField("max_heart_rate", fitUint8Type, eZonesTargetMaxHeartRate, 0, 0, ""); f->addField("threshold_heart_rate", fitUint8Type, eZonesTargetThresholdHeartRate, 0, 0, ""); f->addField("functional_threshold_power", fitUint16Type, eZonesTargetFunctionalThresholdPower, 0, 0, ""); f->addField("hr_calc_type", fitEnumType, eZonesTargetHrCalcType, 0, 0, ""); f->addField("pwr_calc_type", fitEnumType, eZonesTargetPwrCalcType, 0, 0, ""); profiles.insert(eMesgNumZonesTarget, f); } void initSport(QMap& profiles) { CFitProfile* f = new CFitProfile("sport", eMesgNumSport); f->addField("sport", fitEnumType, eSportSport, 0, 0, ""); f->addField("sub_sport", fitEnumType, eSportSubSport, 0, 0, ""); f->addField("name", fitStringType, eSportName, 0, 0, ""); profiles.insert(eMesgNumSport, f); } void initHrZone(QMap& profiles) { CFitProfile* f = new CFitProfile("hr_zone", eMesgNumHrZone); f->addField("message_index", fitEnumType, eHrZoneMessageIndex, 0, 0, ""); f->addField("high_bpm", fitUint8Type, eHrZoneHighBpm, 0, 0, "bpm"); f->addField("name", fitStringType, eHrZoneName, 0, 0, ""); profiles.insert(eMesgNumHrZone, f); } void initSpeedZone(QMap& profiles) { CFitProfile* f = new CFitProfile("speed_zone", eMesgNumSpeedZone); f->addField("message_index", fitEnumType, eSpeedZoneMessageIndex, 0, 0, ""); f->addField("high_value", fitUint16Type, eSpeedZoneHighValue, 1000, 0, "m/s"); f->addField("name", fitStringType, eSpeedZoneName, 0, 0, ""); profiles.insert(eMesgNumSpeedZone, f); } void initCadenceZone(QMap& profiles) { CFitProfile* f = new CFitProfile("cadence_zone", eMesgNumCadenceZone); f->addField("message_index", fitEnumType, eCadenceZoneMessageIndex, 0, 0, ""); f->addField("high_value", fitUint8Type, eCadenceZoneHighValue, 0, 0, "rpm"); f->addField("name", fitStringType, eCadenceZoneName, 0, 0, ""); profiles.insert(eMesgNumCadenceZone, f); } void initPowerZone(QMap& profiles) { CFitProfile* f = new CFitProfile("power_zone", eMesgNumPowerZone); f->addField("message_index", fitEnumType, ePowerZoneMessageIndex, 0, 0, ""); f->addField("high_value", fitUint16Type, ePowerZoneHighValue, 0, 0, "watts"); f->addField("name", fitStringType, ePowerZoneName, 0, 0, ""); profiles.insert(eMesgNumPowerZone, f); } void initMetZone(QMap& profiles) { CFitProfile* f = new CFitProfile("met_zone", eMesgNumMetZone); f->addField("message_index", fitEnumType, eMetZoneMessageIndex, 0, 0, ""); f->addField("high_bpm", fitUint8Type, eMetZoneHighBpm, 0, 0, ""); f->addField("calories", fitUint16Type, eMetZoneCalories, 10, 0, "kcal / min"); f->addField("fat_calories", fitUint8Type, eMetZoneFatCalories, 10, 0, "kcal / min"); profiles.insert(eMesgNumMetZone, f); } void initGoal(QMap& profiles) { CFitProfile* f = new CFitProfile("goal", eMesgNumGoal); f->addField("message_index", fitEnumType, eGoalMessageIndex, 0, 0, ""); f->addField("sport", fitEnumType, eGoalSport, 0, 0, ""); f->addField("sub_sport", fitEnumType, eGoalSubSport, 0, 0, ""); f->addField("start_date", fitEnumType, eGoalStartDate, 0, 0, ""); f->addField("end_date", fitEnumType, eGoalEndDate, 0, 0, ""); f->addField("type", fitEnumType, eGoalType, 0, 0, ""); f->addField("value", fitUint32Type, eGoalValue, 0, 0, ""); f->addField("repeat", fitEnumType, eGoalRepeat, 0, 0, ""); f->addField("target_value", fitUint32Type, eGoalTargetValue, 0, 0, ""); f->addField("recurrence", fitEnumType, eGoalRecurrence, 0, 0, ""); f->addField("recurrence_value", fitUint16Type, eGoalRecurrenceValue, 0, 0, ""); f->addField("enabled", fitEnumType, eGoalEnabled, 0, 0, ""); f->addField("source", fitEnumType, eGoalSource, 0, 0, ""); profiles.insert(eMesgNumGoal, f); } void initActivity(QMap& profiles) { CFitProfile* f = new CFitProfile("activity", eMesgNumActivity); f->addField("timestamp", fitEnumType, eActivityTimestamp, 0, 0, ""); f->addField("total_timer_time", fitUint32Type, eActivityTotalTimerTime, 1000, 0, "s"); f->addField("num_sessions", fitUint16Type, eActivityNumSessions, 0, 0, ""); f->addField("type", fitEnumType, eActivityType, 0, 0, ""); f->addField("event", fitEnumType, eActivityEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eActivityEventType, 0, 0, ""); f->addField("local_timestamp", fitEnumType, eActivityLocalTimestamp, 0, 0, ""); f->addField("event_group", fitUint8Type, eActivityEventGroup, 0, 0, ""); profiles.insert(eMesgNumActivity, f); } void initSession(QMap& profiles) { CFitProfile* f = new CFitProfile("session", eMesgNumSession); f->addField("message_index", fitEnumType, eSessionMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eSessionTimestamp, 0, 0, "s"); f->addField("event", fitEnumType, eSessionEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eSessionEventType, 0, 0, ""); f->addField("start_time", fitEnumType, eSessionStartTime, 0, 0, ""); f->addField("start_position_lat", fitSint32Type, eSessionStartPositionLat, 0, 0, "semicircles"); f->addField("start_position_long", fitSint32Type, eSessionStartPositionLong, 0, 0, "semicircles"); f->addField("sport", fitEnumType, eSessionSport, 0, 0, ""); f->addField("sub_sport", fitEnumType, eSessionSubSport, 0, 0, ""); f->addField("total_elapsed_time", fitUint32Type, eSessionTotalElapsedTime, 1000, 0, "s"); f->addField("total_timer_time", fitUint32Type, eSessionTotalTimerTime, 1000, 0, "s"); f->addField("total_distance", fitUint32Type, eSessionTotalDistance, 100, 0, "m"); f->addField("total_cycles", fitUint32Type, eSessionTotalCycles, 0, 0, "cycles"); f->addField("total_calories", fitUint16Type, eSessionTotalCalories, 0, 0, "kcal"); f->addField("total_fat_calories", fitUint16Type, eSessionTotalFatCalories, 0, 0, "kcal"); f->addField("avg_speed", fitUint16Type, eSessionAvgSpeed, 0, 0, ""); f->addComponent("avg_speed", fitUint16Type, eSessionAvgSpeed, 1000, 0, "m/s", eSessionEnhancedAvgSpeed, 16); f->addField("max_speed", fitUint16Type, eSessionMaxSpeed, 0, 0, ""); f->addComponent("max_speed", fitUint16Type, eSessionMaxSpeed, 1000, 0, "m/s", eSessionEnhancedMaxSpeed, 16); f->addField("avg_heart_rate", fitUint8Type, eSessionAvgHeartRate, 0, 0, "bpm"); f->addField("max_heart_rate", fitUint8Type, eSessionMaxHeartRate, 0, 0, "bpm"); f->addField("avg_cadence", fitUint8Type, eSessionAvgCadence, 0, 0, "rpm"); f->addSubfield("avg_running_cadence", fitUint8Type, eSessionAvgCadence, 0, 0, "strides/min", eSessionSport, eSportRunning); f->addField("max_cadence", fitUint8Type, eSessionMaxCadence, 0, 0, "rpm"); f->addSubfield("max_running_cadence", fitUint8Type, eSessionMaxCadence, 0, 0, "strides/min", eSessionSport, eSportRunning); f->addField("avg_power", fitUint16Type, eSessionAvgPower, 0, 0, "watts"); f->addField("max_power", fitUint16Type, eSessionMaxPower, 0, 0, "watts"); f->addField("total_ascent", fitUint16Type, eSessionTotalAscent, 0, 0, "m"); f->addField("total_descent", fitUint16Type, eSessionTotalDescent, 0, 0, "m"); f->addField("total_training_effect", fitUint8Type, eSessionTotalTrainingEffect, 10, 0, ""); f->addField("first_lap_index", fitUint16Type, eSessionFirstLapIndex, 0, 0, ""); f->addField("num_laps", fitUint16Type, eSessionNumLaps, 0, 0, ""); f->addField("event_group", fitUint8Type, eSessionEventGroup, 0, 0, ""); f->addField("trigger", fitEnumType, eSessionTrigger, 0, 0, ""); f->addField("nec_lat", fitSint32Type, eSessionNecLat, 0, 0, "semicircles"); f->addField("nec_long", fitSint32Type, eSessionNecLong, 0, 0, "semicircles"); f->addField("swc_lat", fitSint32Type, eSessionSwcLat, 0, 0, "semicircles"); f->addField("swc_long", fitSint32Type, eSessionSwcLong, 0, 0, "semicircles"); f->addField("normalized_power", fitUint16Type, eSessionNormalizedPower, 0, 0, "watts"); f->addField("training_stress_score", fitUint16Type, eSessionTrainingStressScore, 10, 0, "tss"); f->addField("intensity_factor", fitUint16Type, eSessionIntensityFactor, 1000, 0, "if"); f->addField("left_right_balance", fitEnumType, eSessionLeftRightBalance, 0, 0, ""); f->addField("avg_stroke_count", fitUint32Type, eSessionAvgStrokeCount, 10, 0, "strokes/lap"); f->addField("avg_stroke_distance", fitUint16Type, eSessionAvgStrokeDistance, 100, 0, "m"); f->addField("swim_stroke", fitEnumType, eSessionSwimStroke, 0, 0, "swim_stroke"); f->addField("pool_length", fitUint16Type, eSessionPoolLength, 100, 0, "m"); f->addField("threshold_power", fitUint16Type, eSessionThresholdPower, 0, 0, "watts"); f->addField("pool_length_unit", fitEnumType, eSessionPoolLengthUnit, 0, 0, ""); f->addField("num_active_lengths", fitUint16Type, eSessionNumActiveLengths, 0, 0, "lengths"); f->addField("total_work", fitUint32Type, eSessionTotalWork, 0, 0, "J"); f->addField("avg_altitude", fitUint16Type, eSessionAvgAltitude, 0, 0, ""); f->addComponent("avg_altitude", fitUint16Type, eSessionAvgAltitude, 5, 500, "m", eSessionEnhancedAvgAltitude, 16); f->addField("max_altitude", fitUint16Type, eSessionMaxAltitude, 0, 0, ""); f->addComponent("max_altitude", fitUint16Type, eSessionMaxAltitude, 5, 500, "m", eSessionEnhancedMaxAltitude, 16); f->addField("gps_accuracy", fitUint8Type, eSessionGpsAccuracy, 0, 0, "m"); f->addField("avg_grade", fitSint16Type, eSessionAvgGrade, 100, 0, "%"); f->addField("avg_pos_grade", fitSint16Type, eSessionAvgPosGrade, 100, 0, "%"); f->addField("avg_neg_grade", fitSint16Type, eSessionAvgNegGrade, 100, 0, "%"); f->addField("max_pos_grade", fitSint16Type, eSessionMaxPosGrade, 100, 0, "%"); f->addField("max_neg_grade", fitSint16Type, eSessionMaxNegGrade, 100, 0, "%"); f->addField("avg_temperature", fitSint8Type, eSessionAvgTemperature, 0, 0, "C"); f->addField("max_temperature", fitSint8Type, eSessionMaxTemperature, 0, 0, "C"); f->addField("total_moving_time", fitUint32Type, eSessionTotalMovingTime, 1000, 0, "s"); f->addField("avg_pos_vertical_speed", fitSint16Type, eSessionAvgPosVerticalSpeed, 1000, 0, "m/s"); f->addField("avg_neg_vertical_speed", fitSint16Type, eSessionAvgNegVerticalSpeed, 1000, 0, "m/s"); f->addField("max_pos_vertical_speed", fitSint16Type, eSessionMaxPosVerticalSpeed, 1000, 0, "m/s"); f->addField("max_neg_vertical_speed", fitSint16Type, eSessionMaxNegVerticalSpeed, 1000, 0, "m/s"); f->addField("min_heart_rate", fitUint8Type, eSessionMinHeartRate, 0, 0, "bpm"); f->addField("time_in_hr_zone", fitUint32Type, eSessionTimeInHrZone, 1000, 0, "s"); f->addField("time_in_speed_zone", fitUint32Type, eSessionTimeInSpeedZone, 1000, 0, "s"); f->addField("time_in_cadence_zone", fitUint32Type, eSessionTimeInCadenceZone, 1000, 0, "s"); f->addField("time_in_power_zone", fitUint32Type, eSessionTimeInPowerZone, 1000, 0, "s"); f->addField("avg_lap_time", fitUint32Type, eSessionAvgLapTime, 1000, 0, "s"); f->addField("best_lap_index", fitUint16Type, eSessionBestLapIndex, 0, 0, ""); f->addField("min_altitude", fitUint16Type, eSessionMinAltitude, 0, 0, ""); f->addComponent("min_altitude", fitUint16Type, eSessionMinAltitude, 5, 500, "m", eSessionEnhancedMinAltitude, 16); f->addField("player_score", fitUint16Type, eSessionPlayerScore, 0, 0, ""); f->addField("opponent_score", fitUint16Type, eSessionOpponentScore, 0, 0, ""); f->addField("opponent_name", fitStringType, eSessionOpponentName, 0, 0, ""); f->addField("stroke_count", fitUint16Type, eSessionStrokeCount, 0, 0, "counts"); f->addField("zone_count", fitUint16Type, eSessionZoneCount, 0, 0, "counts"); f->addField("max_ball_speed", fitUint16Type, eSessionMaxBallSpeed, 100, 0, "m/s"); f->addField("avg_ball_speed", fitUint16Type, eSessionAvgBallSpeed, 100, 0, "m/s"); f->addField("avg_vertical_oscillation", fitUint16Type, eSessionAvgVerticalOscillation, 10, 0, "mm"); f->addField("avg_stance_time_percent", fitUint16Type, eSessionAvgStanceTimePercent, 100, 0, "percent"); f->addField("avg_stance_time", fitUint16Type, eSessionAvgStanceTime, 10, 0, "ms"); f->addField("avg_fractional_cadence", fitUint8Type, eSessionAvgFractionalCadence, 128, 0, "rpm"); f->addField("max_fractional_cadence", fitUint8Type, eSessionMaxFractionalCadence, 128, 0, "rpm"); f->addField("total_fractional_cycles", fitUint8Type, eSessionTotalFractionalCycles, 128, 0, "cycles"); f->addField("avg_total_hemoglobin_conc", fitUint16Type, eSessionAvgTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("min_total_hemoglobin_conc", fitUint16Type, eSessionMinTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("max_total_hemoglobin_conc", fitUint16Type, eSessionMaxTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("avg_saturated_hemoglobin_percent", fitUint16Type, eSessionAvgSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("min_saturated_hemoglobin_percent", fitUint16Type, eSessionMinSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("max_saturated_hemoglobin_percent", fitUint16Type, eSessionMaxSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("avg_left_torque_effectiveness", fitUint8Type, eSessionAvgLeftTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_right_torque_effectiveness", fitUint8Type, eSessionAvgRightTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_left_pedal_smoothness", fitUint8Type, eSessionAvgLeftPedalSmoothness, 2, 0, "percent"); f->addField("avg_right_pedal_smoothness", fitUint8Type, eSessionAvgRightPedalSmoothness, 2, 0, "percent"); f->addField("avg_combined_pedal_smoothness", fitUint8Type, eSessionAvgCombinedPedalSmoothness, 2, 0, "percent"); f->addField("sport_index", fitUint8Type, eSessionSportIndex, 0, 0, ""); f->addField("time_standing", fitUint32Type, eSessionTimeStanding, 1000, 0, "s"); f->addField("stand_count", fitUint16Type, eSessionStandCount, 0, 0, ""); f->addField("avg_left_pco", fitSint8Type, eSessionAvgLeftPco, 0, 0, "mm"); f->addField("avg_right_pco", fitSint8Type, eSessionAvgRightPco, 0, 0, "mm"); f->addField("avg_left_power_phase", fitUint8Type, eSessionAvgLeftPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_left_power_phase_peak", fitUint8Type, eSessionAvgLeftPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase", fitUint8Type, eSessionAvgRightPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase_peak", fitUint8Type, eSessionAvgRightPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_power_position", fitUint16Type, eSessionAvgPowerPosition, 0, 0, "watts"); f->addField("max_power_position", fitUint16Type, eSessionMaxPowerPosition, 0, 0, "watts"); f->addField("avg_cadence_position", fitUint8Type, eSessionAvgCadencePosition, 0, 0, "rpm"); f->addField("max_cadence_position", fitUint8Type, eSessionMaxCadencePosition, 0, 0, "rpm"); f->addField("enhanced_avg_speed", fitUint32Type, eSessionEnhancedAvgSpeed, 1000, 0, "m/s"); f->addField("enhanced_max_speed", fitUint32Type, eSessionEnhancedMaxSpeed, 1000, 0, "m/s"); f->addField("enhanced_avg_altitude", fitUint32Type, eSessionEnhancedAvgAltitude, 5, 500, "m"); f->addField("enhanced_min_altitude", fitUint32Type, eSessionEnhancedMinAltitude, 5, 500, "m"); f->addField("enhanced_max_altitude", fitUint32Type, eSessionEnhancedMaxAltitude, 5, 500, "m"); f->addField("avg_lev_motor_power", fitUint16Type, eSessionAvgLevMotorPower, 0, 0, "watts"); f->addField("max_lev_motor_power", fitUint16Type, eSessionMaxLevMotorPower, 0, 0, "watts"); f->addField("lev_battery_consumption", fitUint8Type, eSessionLevBatteryConsumption, 2, 0, "percent"); f->addField("avg_vertical_ratio", fitUint16Type, eSessionAvgVerticalRatio, 100, 0, "percent"); f->addField("avg_stance_time_balance", fitUint16Type, eSessionAvgStanceTimeBalance, 100, 0, "percent"); f->addField("avg_step_length", fitUint16Type, eSessionAvgStepLength, 10, 0, "mm"); f->addField("total_anaerobic_training_effect", fitUint8Type, eSessionTotalAnaerobicTrainingEffect, 10, 0, ""); f->addField("avg_vam", fitUint16Type, eSessionAvgVam, 1000, 0, "m/s"); profiles.insert(eMesgNumSession, f); } void initLap(QMap& profiles) { CFitProfile* f = new CFitProfile("lap", eMesgNumLap); f->addField("message_index", fitEnumType, eLapMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eLapTimestamp, 0, 0, "s"); f->addField("event", fitEnumType, eLapEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eLapEventType, 0, 0, ""); f->addField("start_time", fitEnumType, eLapStartTime, 0, 0, ""); f->addField("start_position_lat", fitSint32Type, eLapStartPositionLat, 0, 0, "semicircles"); f->addField("start_position_long", fitSint32Type, eLapStartPositionLong, 0, 0, "semicircles"); f->addField("end_position_lat", fitSint32Type, eLapEndPositionLat, 0, 0, "semicircles"); f->addField("end_position_long", fitSint32Type, eLapEndPositionLong, 0, 0, "semicircles"); f->addField("total_elapsed_time", fitUint32Type, eLapTotalElapsedTime, 1000, 0, "s"); f->addField("total_timer_time", fitUint32Type, eLapTotalTimerTime, 1000, 0, "s"); f->addField("total_distance", fitUint32Type, eLapTotalDistance, 100, 0, "m"); f->addField("total_cycles", fitUint32Type, eLapTotalCycles, 0, 0, "cycles"); f->addField("total_calories", fitUint16Type, eLapTotalCalories, 0, 0, "kcal"); f->addField("total_fat_calories", fitUint16Type, eLapTotalFatCalories, 0, 0, "kcal"); f->addField("avg_speed", fitUint16Type, eLapAvgSpeed, 0, 0, ""); f->addComponent("avg_speed", fitUint16Type, eLapAvgSpeed, 1000, 0, "m/s", eLapEnhancedAvgSpeed, 16); f->addField("max_speed", fitUint16Type, eLapMaxSpeed, 0, 0, ""); f->addComponent("max_speed", fitUint16Type, eLapMaxSpeed, 1000, 0, "m/s", eLapEnhancedMaxSpeed, 16); f->addField("avg_heart_rate", fitUint8Type, eLapAvgHeartRate, 0, 0, "bpm"); f->addField("max_heart_rate", fitUint8Type, eLapMaxHeartRate, 0, 0, "bpm"); f->addField("avg_cadence", fitUint8Type, eLapAvgCadence, 0, 0, "rpm"); f->addSubfield("avg_running_cadence", fitUint8Type, eLapAvgCadence, 0, 0, "strides/min", eLapSport, eSportRunning); f->addField("max_cadence", fitUint8Type, eLapMaxCadence, 0, 0, "rpm"); f->addSubfield("max_running_cadence", fitUint8Type, eLapMaxCadence, 0, 0, "strides/min", eLapSport, eSportRunning); f->addField("avg_power", fitUint16Type, eLapAvgPower, 0, 0, "watts"); f->addField("max_power", fitUint16Type, eLapMaxPower, 0, 0, "watts"); f->addField("total_ascent", fitUint16Type, eLapTotalAscent, 0, 0, "m"); f->addField("total_descent", fitUint16Type, eLapTotalDescent, 0, 0, "m"); f->addField("intensity", fitEnumType, eLapIntensity, 0, 0, ""); f->addField("lap_trigger", fitEnumType, eLapLapTrigger, 0, 0, ""); f->addField("sport", fitEnumType, eLapSport, 0, 0, ""); f->addField("event_group", fitUint8Type, eLapEventGroup, 0, 0, ""); f->addField("num_lengths", fitUint16Type, eLapNumLengths, 0, 0, "lengths"); f->addField("normalized_power", fitUint16Type, eLapNormalizedPower, 0, 0, "watts"); f->addField("left_right_balance", fitEnumType, eLapLeftRightBalance, 0, 0, ""); f->addField("first_length_index", fitUint16Type, eLapFirstLengthIndex, 0, 0, ""); f->addField("avg_stroke_distance", fitUint16Type, eLapAvgStrokeDistance, 100, 0, "m"); f->addField("swim_stroke", fitEnumType, eLapSwimStroke, 0, 0, ""); f->addField("sub_sport", fitEnumType, eLapSubSport, 0, 0, ""); f->addField("num_active_lengths", fitUint16Type, eLapNumActiveLengths, 0, 0, "lengths"); f->addField("total_work", fitUint32Type, eLapTotalWork, 0, 0, "J"); f->addField("avg_altitude", fitUint16Type, eLapAvgAltitude, 0, 0, ""); f->addComponent("avg_altitude", fitUint16Type, eLapAvgAltitude, 5, 500, "m", eLapEnhancedAvgAltitude, 16); f->addField("max_altitude", fitUint16Type, eLapMaxAltitude, 0, 0, ""); f->addComponent("max_altitude", fitUint16Type, eLapMaxAltitude, 5, 500, "m", eLapEnhancedMaxAltitude, 16); f->addField("gps_accuracy", fitUint8Type, eLapGpsAccuracy, 0, 0, "m"); f->addField("avg_grade", fitSint16Type, eLapAvgGrade, 100, 0, "%"); f->addField("avg_pos_grade", fitSint16Type, eLapAvgPosGrade, 100, 0, "%"); f->addField("avg_neg_grade", fitSint16Type, eLapAvgNegGrade, 100, 0, "%"); f->addField("max_pos_grade", fitSint16Type, eLapMaxPosGrade, 100, 0, "%"); f->addField("max_neg_grade", fitSint16Type, eLapMaxNegGrade, 100, 0, "%"); f->addField("avg_temperature", fitSint8Type, eLapAvgTemperature, 0, 0, "C"); f->addField("max_temperature", fitSint8Type, eLapMaxTemperature, 0, 0, "C"); f->addField("total_moving_time", fitUint32Type, eLapTotalMovingTime, 1000, 0, "s"); f->addField("avg_pos_vertical_speed", fitSint16Type, eLapAvgPosVerticalSpeed, 1000, 0, "m/s"); f->addField("avg_neg_vertical_speed", fitSint16Type, eLapAvgNegVerticalSpeed, 1000, 0, "m/s"); f->addField("max_pos_vertical_speed", fitSint16Type, eLapMaxPosVerticalSpeed, 1000, 0, "m/s"); f->addField("max_neg_vertical_speed", fitSint16Type, eLapMaxNegVerticalSpeed, 1000, 0, "m/s"); f->addField("time_in_hr_zone", fitUint32Type, eLapTimeInHrZone, 1000, 0, "s"); f->addField("time_in_speed_zone", fitUint32Type, eLapTimeInSpeedZone, 1000, 0, "s"); f->addField("time_in_cadence_zone", fitUint32Type, eLapTimeInCadenceZone, 1000, 0, "s"); f->addField("time_in_power_zone", fitUint32Type, eLapTimeInPowerZone, 1000, 0, "s"); f->addField("repetition_num", fitUint16Type, eLapRepetitionNum, 0, 0, ""); f->addField("min_altitude", fitUint16Type, eLapMinAltitude, 0, 0, ""); f->addComponent("min_altitude", fitUint16Type, eLapMinAltitude, 5, 500, "m", eLapEnhancedMinAltitude, 16); f->addField("min_heart_rate", fitUint8Type, eLapMinHeartRate, 0, 0, "bpm"); f->addField("wkt_step_index", fitEnumType, eLapWktStepIndex, 0, 0, ""); f->addField("opponent_score", fitUint16Type, eLapOpponentScore, 0, 0, ""); f->addField("stroke_count", fitUint16Type, eLapStrokeCount, 0, 0, "counts"); f->addField("zone_count", fitUint16Type, eLapZoneCount, 0, 0, "counts"); f->addField("avg_vertical_oscillation", fitUint16Type, eLapAvgVerticalOscillation, 10, 0, "mm"); f->addField("avg_stance_time_percent", fitUint16Type, eLapAvgStanceTimePercent, 100, 0, "percent"); f->addField("avg_stance_time", fitUint16Type, eLapAvgStanceTime, 10, 0, "ms"); f->addField("avg_fractional_cadence", fitUint8Type, eLapAvgFractionalCadence, 128, 0, "rpm"); f->addField("max_fractional_cadence", fitUint8Type, eLapMaxFractionalCadence, 128, 0, "rpm"); f->addField("total_fractional_cycles", fitUint8Type, eLapTotalFractionalCycles, 128, 0, "cycles"); f->addField("player_score", fitUint16Type, eLapPlayerScore, 0, 0, ""); f->addField("avg_total_hemoglobin_conc", fitUint16Type, eLapAvgTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("min_total_hemoglobin_conc", fitUint16Type, eLapMinTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("max_total_hemoglobin_conc", fitUint16Type, eLapMaxTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("avg_saturated_hemoglobin_percent", fitUint16Type, eLapAvgSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("min_saturated_hemoglobin_percent", fitUint16Type, eLapMinSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("max_saturated_hemoglobin_percent", fitUint16Type, eLapMaxSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("avg_left_torque_effectiveness", fitUint8Type, eLapAvgLeftTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_right_torque_effectiveness", fitUint8Type, eLapAvgRightTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_left_pedal_smoothness", fitUint8Type, eLapAvgLeftPedalSmoothness, 2, 0, "percent"); f->addField("avg_right_pedal_smoothness", fitUint8Type, eLapAvgRightPedalSmoothness, 2, 0, "percent"); f->addField("avg_combined_pedal_smoothness", fitUint8Type, eLapAvgCombinedPedalSmoothness, 2, 0, "percent"); f->addField("time_standing", fitUint32Type, eLapTimeStanding, 1000, 0, "s"); f->addField("stand_count", fitUint16Type, eLapStandCount, 0, 0, ""); f->addField("avg_left_pco", fitSint8Type, eLapAvgLeftPco, 0, 0, "mm"); f->addField("avg_right_pco", fitSint8Type, eLapAvgRightPco, 0, 0, "mm"); f->addField("avg_left_power_phase", fitUint8Type, eLapAvgLeftPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_left_power_phase_peak", fitUint8Type, eLapAvgLeftPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase", fitUint8Type, eLapAvgRightPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase_peak", fitUint8Type, eLapAvgRightPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_power_position", fitUint16Type, eLapAvgPowerPosition, 0, 0, "watts"); f->addField("max_power_position", fitUint16Type, eLapMaxPowerPosition, 0, 0, "watts"); f->addField("avg_cadence_position", fitUint8Type, eLapAvgCadencePosition, 0, 0, "rpm"); f->addField("max_cadence_position", fitUint8Type, eLapMaxCadencePosition, 0, 0, "rpm"); f->addField("enhanced_avg_speed", fitUint32Type, eLapEnhancedAvgSpeed, 1000, 0, "m/s"); f->addField("enhanced_max_speed", fitUint32Type, eLapEnhancedMaxSpeed, 1000, 0, "m/s"); f->addField("enhanced_avg_altitude", fitUint32Type, eLapEnhancedAvgAltitude, 5, 500, "m"); f->addField("enhanced_min_altitude", fitUint32Type, eLapEnhancedMinAltitude, 5, 500, "m"); f->addField("enhanced_max_altitude", fitUint32Type, eLapEnhancedMaxAltitude, 5, 500, "m"); f->addField("avg_lev_motor_power", fitUint16Type, eLapAvgLevMotorPower, 0, 0, "watts"); f->addField("max_lev_motor_power", fitUint16Type, eLapMaxLevMotorPower, 0, 0, "watts"); f->addField("lev_battery_consumption", fitUint8Type, eLapLevBatteryConsumption, 2, 0, "percent"); f->addField("avg_vertical_ratio", fitUint16Type, eLapAvgVerticalRatio, 100, 0, "percent"); f->addField("avg_stance_time_balance", fitUint16Type, eLapAvgStanceTimeBalance, 100, 0, "percent"); f->addField("avg_step_length", fitUint16Type, eLapAvgStepLength, 10, 0, "mm"); f->addField("avg_vam", fitUint16Type, eLapAvgVam, 1000, 0, "m/s"); profiles.insert(eMesgNumLap, f); } void initLength(QMap& profiles) { CFitProfile* f = new CFitProfile("length", eMesgNumLength); f->addField("message_index", fitEnumType, eLengthMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eLengthTimestamp, 0, 0, ""); f->addField("event", fitEnumType, eLengthEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eLengthEventType, 0, 0, ""); f->addField("start_time", fitEnumType, eLengthStartTime, 0, 0, ""); f->addField("total_elapsed_time", fitUint32Type, eLengthTotalElapsedTime, 1000, 0, "s"); f->addField("total_timer_time", fitUint32Type, eLengthTotalTimerTime, 1000, 0, "s"); f->addField("total_strokes", fitUint16Type, eLengthTotalStrokes, 0, 0, "strokes"); f->addField("avg_speed", fitUint16Type, eLengthAvgSpeed, 1000, 0, "m/s"); f->addField("swim_stroke", fitEnumType, eLengthSwimStroke, 0, 0, "swim_stroke"); f->addField("avg_swimming_cadence", fitUint8Type, eLengthAvgSwimmingCadence, 0, 0, "strokes/min"); f->addField("event_group", fitUint8Type, eLengthEventGroup, 0, 0, ""); f->addField("total_calories", fitUint16Type, eLengthTotalCalories, 0, 0, "kcal"); f->addField("length_type", fitEnumType, eLengthLengthType, 0, 0, ""); f->addField("player_score", fitUint16Type, eLengthPlayerScore, 0, 0, ""); f->addField("opponent_score", fitUint16Type, eLengthOpponentScore, 0, 0, ""); f->addField("stroke_count", fitUint16Type, eLengthStrokeCount, 0, 0, "counts"); f->addField("zone_count", fitUint16Type, eLengthZoneCount, 0, 0, "counts"); profiles.insert(eMesgNumLength, f); } void initRecord(QMap& profiles) { CFitProfile* f = new CFitProfile("record", eMesgNumRecord); f->addField("timestamp", fitEnumType, eRecordTimestamp, 0, 0, "s"); f->addField("position_lat", fitSint32Type, eRecordPositionLat, 0, 0, "semicircles"); f->addField("position_long", fitSint32Type, eRecordPositionLong, 0, 0, "semicircles"); f->addField("altitude", fitUint16Type, eRecordAltitude, 0, 0, ""); f->addComponent("altitude", fitUint16Type, eRecordAltitude, 5, 500, "m", eRecordEnhancedAltitude, 16); f->addField("heart_rate", fitUint8Type, eRecordHeartRate, 0, 0, "bpm"); f->addField("cadence", fitUint8Type, eRecordCadence, 0, 0, "rpm"); f->addField("distance", fitUint32Type, eRecordDistance, 100, 0, "m"); f->addField("speed", fitUint16Type, eRecordSpeed, 0, 0, ""); f->addComponent("speed", fitUint16Type, eRecordSpeed, 1000, 0, "m/s", eRecordEnhancedSpeed, 16); f->addField("power", fitUint16Type, eRecordPower, 0, 0, "watts"); f->addField("compressed_speed_distance", fitByteType, eRecordCompressedSpeedDistance, 0, 0, ""); f->addComponent("compressed_speed_distance", fitByteType, eRecordCompressedSpeedDistance, 100, 0, "m/s", eRecordSpeed, 12); f->addComponent("compressed_speed_distance", fitByteType, eRecordCompressedSpeedDistance, 16, 0, "m", eRecordDistance, 12); f->addField("grade", fitSint16Type, eRecordGrade, 100, 0, "%"); f->addField("resistance", fitUint8Type, eRecordResistance, 0, 0, ""); f->addField("time_from_course", fitSint32Type, eRecordTimeFromCourse, 1000, 0, "s"); f->addField("cycle_length", fitUint8Type, eRecordCycleLength, 100, 0, "m"); f->addField("temperature", fitSint8Type, eRecordTemperature, 0, 0, "C"); f->addField("speed_1s", fitUint8Type, eRecordSpeed1S, 16, 0, "m/s"); f->addField("cycles", fitUint8Type, eRecordCycles, 0, 0, ""); f->addComponent("cycles", fitUint8Type, eRecordCycles, 0, 0, "cycles", eRecordTotalCycles, 8); f->addField("total_cycles", fitUint32Type, eRecordTotalCycles, 0, 0, "cycles"); f->addField("compressed_accumulated_power", fitUint16Type, eRecordCompressedAccumulatedPower, 0, 0, ""); f->addComponent("compressed_accumulated_power", fitUint16Type, eRecordCompressedAccumulatedPower, 0, 0, "watts", eRecordAccumulatedPower, 16); f->addField("accumulated_power", fitUint32Type, eRecordAccumulatedPower, 0, 0, "watts"); f->addField("left_right_balance", fitEnumType, eRecordLeftRightBalance, 0, 0, ""); f->addField("gps_accuracy", fitUint8Type, eRecordGpsAccuracy, 0, 0, "m"); f->addField("vertical_speed", fitSint16Type, eRecordVerticalSpeed, 1000, 0, "m/s"); f->addField("calories", fitUint16Type, eRecordCalories, 0, 0, "kcal"); f->addField("vertical_oscillation", fitUint16Type, eRecordVerticalOscillation, 10, 0, "mm"); f->addField("stance_time_percent", fitUint16Type, eRecordStanceTimePercent, 100, 0, "percent"); f->addField("stance_time", fitUint16Type, eRecordStanceTime, 10, 0, "ms"); f->addField("activity_type", fitEnumType, eRecordActivityType, 0, 0, ""); f->addField("left_torque_effectiveness", fitUint8Type, eRecordLeftTorqueEffectiveness, 2, 0, "percent"); f->addField("right_torque_effectiveness", fitUint8Type, eRecordRightTorqueEffectiveness, 2, 0, "percent"); f->addField("left_pedal_smoothness", fitUint8Type, eRecordLeftPedalSmoothness, 2, 0, "percent"); f->addField("right_pedal_smoothness", fitUint8Type, eRecordRightPedalSmoothness, 2, 0, "percent"); f->addField("combined_pedal_smoothness", fitUint8Type, eRecordCombinedPedalSmoothness, 2, 0, "percent"); f->addField("time128", fitUint8Type, eRecordTime128, 128, 0, "s"); f->addField("stroke_type", fitEnumType, eRecordStrokeType, 0, 0, ""); f->addField("zone", fitUint8Type, eRecordZone, 0, 0, ""); f->addField("ball_speed", fitUint16Type, eRecordBallSpeed, 100, 0, "m/s"); f->addField("cadence256", fitUint16Type, eRecordCadence256, 256, 0, "rpm"); f->addField("fractional_cadence", fitUint8Type, eRecordFractionalCadence, 128, 0, "rpm"); f->addField("total_hemoglobin_conc", fitUint16Type, eRecordTotalHemoglobinConc, 100, 0, "g/dL"); f->addField("total_hemoglobin_conc_min", fitUint16Type, eRecordTotalHemoglobinConcMin, 100, 0, "g/dL"); f->addField("total_hemoglobin_conc_max", fitUint16Type, eRecordTotalHemoglobinConcMax, 100, 0, "g/dL"); f->addField("saturated_hemoglobin_percent", fitUint16Type, eRecordSaturatedHemoglobinPercent, 10, 0, "%"); f->addField("saturated_hemoglobin_percent_min", fitUint16Type, eRecordSaturatedHemoglobinPercentMin, 10, 0, "%"); f->addField("saturated_hemoglobin_percent_max", fitUint16Type, eRecordSaturatedHemoglobinPercentMax, 10, 0, "%"); f->addField("device_index", fitEnumType, eRecordDeviceIndex, 0, 0, ""); f->addField("left_pco", fitSint8Type, eRecordLeftPco, 0, 0, "mm"); f->addField("right_pco", fitSint8Type, eRecordRightPco, 0, 0, "mm"); f->addField("left_power_phase", fitUint8Type, eRecordLeftPowerPhase, 0.7111111, 0, "degrees"); f->addField("left_power_phase_peak", fitUint8Type, eRecordLeftPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("right_power_phase", fitUint8Type, eRecordRightPowerPhase, 0.7111111, 0, "degrees"); f->addField("right_power_phase_peak", fitUint8Type, eRecordRightPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("enhanced_speed", fitUint32Type, eRecordEnhancedSpeed, 1000, 0, "m/s"); f->addField("enhanced_altitude", fitUint32Type, eRecordEnhancedAltitude, 5, 500, "m"); f->addField("battery_soc", fitUint8Type, eRecordBatterySoc, 2, 0, "percent"); f->addField("motor_power", fitUint16Type, eRecordMotorPower, 0, 0, "watts"); f->addField("vertical_ratio", fitUint16Type, eRecordVerticalRatio, 100, 0, "percent"); f->addField("stance_time_balance", fitUint16Type, eRecordStanceTimeBalance, 100, 0, "percent"); f->addField("step_length", fitUint16Type, eRecordStepLength, 10, 0, "mm"); profiles.insert(eMesgNumRecord, f); } void initEvent(QMap& profiles) { CFitProfile* f = new CFitProfile("event", eMesgNumEvent); f->addField("timestamp", fitEnumType, eEventTimestamp, 0, 0, "s"); f->addField("event", fitEnumType, eEventEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eEventEventType, 0, 0, ""); f->addField("data16", fitUint16Type, eEventData16, 0, 0, ""); f->addComponent("data16", fitUint16Type, eEventData16, 0, 0, "", eEventData, 16); f->addField("data", fitUint32Type, eEventData, 0, 0, ""); f->addSubfield("timer_trigger", fitEnumType, eEventData, 0, 0, "", eEventEvent, eEventTimer); f->addSubfield("course_point_index", fitEnumType, eEventData, 0, 0, "", eEventEvent, eEventCoursePoint); f->addSubfield("battery_level", fitUint16Type, eEventData, 1000, 0, "V", eEventEvent, eEventBattery); f->addSubfield("virtual_partner_speed", fitUint16Type, eEventData, 1000, 0, "m/s", eEventEvent, eEventVirtualPartnerPace); f->addSubfield("hr_high_alert", fitUint8Type, eEventData, 0, 0, "bpm", eEventEvent, eEventHrHighAlert); f->addSubfield("hr_low_alert", fitUint8Type, eEventData, 0, 0, "bpm", eEventEvent, eEventHrLowAlert); f->addSubfield("speed_high_alert", fitUint32Type, eEventData, 1000, 0, "m/s", eEventEvent, eEventSpeedHighAlert); f->addSubfield("speed_low_alert", fitUint32Type, eEventData, 1000, 0, "m/s", eEventEvent, eEventSpeedLowAlert); f->addSubfield("cad_high_alert", fitUint16Type, eEventData, 0, 0, "rpm", eEventEvent, eEventCadHighAlert); f->addSubfield("cad_low_alert", fitUint16Type, eEventData, 0, 0, "rpm", eEventEvent, eEventCadLowAlert); f->addSubfield("power_high_alert", fitUint16Type, eEventData, 0, 0, "watts", eEventEvent, eEventPowerHighAlert); f->addSubfield("power_low_alert", fitUint16Type, eEventData, 0, 0, "watts", eEventEvent, eEventPowerLowAlert); f->addSubfield("time_duration_alert", fitUint32Type, eEventData, 1000, 0, "s", eEventEvent, eEventTimeDurationAlert); f->addSubfield("distance_duration_alert", fitUint32Type, eEventData, 100, 0, "m", eEventEvent, eEventDistanceDurationAlert); f->addSubfield("calorie_duration_alert", fitUint32Type, eEventData, 0, 0, "calories", eEventEvent, eEventCalorieDurationAlert); f->addSubfield("fitness_equipment_state", fitEnumType, eEventData, 0, 0, "", eEventEvent, eEventFitnessEquipment); f->addSubfield("sport_point", fitUint32Type, eEventData, 0, 0, "", eEventEvent, eEventSportPoint); f->addComponent(16, "sport_point", fitUint32Type, eEventData, 11, 0, "", eEventScore, 1616); f->addComponent(16, "sport_point", fitUint32Type, eEventData, 0, 0, "", eEventOpponentScore, 0); f->addSubfield("gear_change_data", fitUint32Type, eEventData, 0, 0, "", eEventEvent, eEventFrontGearChange); f->addSubfield("gear_change_data", fitUint32Type, eEventData, 0, 0, "", eEventEvent, eEventRearGearChange); f->addComponent(18, "gear_change_data", fitUint32Type, eEventData, 1111, 0, "", eEventRearGearNum, 8); f->addComponent(18, "gear_change_data", fitUint32Type, eEventData, 0, 0, "", eEventRearGear, 8); f->addComponent(18, "gear_change_data", fitUint32Type, eEventData, 0, 0, "", eEventFrontGearNum, 8); f->addComponent(18, "gear_change_data", fitUint32Type, eEventData, 0, 0, "", eEventFrontGear, 8); f->addSubfield("rider_position", fitEnumType, eEventData, 0, 0, "", eEventEvent, eEventRiderPositionChange); f->addSubfield("comm_timeout", fitEnumType, eEventData, 0, 0, "", eEventEvent, eEventCommTimeout); f->addField("event_group", fitUint8Type, eEventEventGroup, 0, 0, ""); f->addField("score", fitUint16Type, eEventScore, 0, 0, ""); f->addField("opponent_score", fitUint16Type, eEventOpponentScore, 0, 0, ""); f->addField("front_gear_num", fitUint8zType, eEventFrontGearNum, 0, 0, ""); f->addField("front_gear", fitUint8zType, eEventFrontGear, 0, 0, ""); f->addField("rear_gear_num", fitUint8zType, eEventRearGearNum, 0, 0, ""); f->addField("rear_gear", fitUint8zType, eEventRearGear, 0, 0, ""); f->addField("device_index", fitEnumType, eEventDeviceIndex, 0, 0, ""); profiles.insert(eMesgNumEvent, f); } void initDeviceInfo(QMap& profiles) { CFitProfile* f = new CFitProfile("device_info", eMesgNumDeviceInfo); f->addField("timestamp", fitEnumType, eDeviceInfoTimestamp, 0, 0, "s"); f->addField("device_index", fitEnumType, eDeviceInfoDeviceIndex, 0, 0, ""); f->addField("device_type", fitUint8Type, eDeviceInfoDeviceType, 0, 0, ""); f->addSubfield("antplus_device_type", fitEnumType, eDeviceInfoDeviceType, 0, 0, "", eDeviceInfoSourceType, eSourceTypeAntplus); f->addSubfield("ant_device_type", fitUint8Type, eDeviceInfoDeviceType, 0, 0, "", eDeviceInfoSourceType, eSourceTypeAnt); f->addField("manufacturer", fitEnumType, eDeviceInfoManufacturer, 0, 0, ""); f->addField("serial_number", fitUint32zType, eDeviceInfoSerialNumber, 0, 0, ""); f->addField("product", fitUint16Type, eDeviceInfoProduct, 0, 0, ""); f->addSubfield("garmin_product", fitEnumType, eDeviceInfoProduct, 0, 0, "", eDeviceInfoManufacturer, eManufacturerGarmin); f->addSubfield("garmin_product", fitEnumType, eDeviceInfoProduct, 0, 0, "", eDeviceInfoManufacturer, eManufacturerDynastream); f->addSubfield("garmin_product", fitEnumType, eDeviceInfoProduct, 0, 0, "", eDeviceInfoManufacturer, eManufacturerDynastreamOem); f->addField("software_version", fitUint16Type, eDeviceInfoSoftwareVersion, 100, 0, ""); f->addField("hardware_version", fitUint8Type, eDeviceInfoHardwareVersion, 0, 0, ""); f->addField("cum_operating_time", fitUint32Type, eDeviceInfoCumOperatingTime, 0, 0, "s"); f->addField("battery_voltage", fitUint16Type, eDeviceInfoBatteryVoltage, 256, 0, "V"); f->addField("battery_status", fitEnumType, eDeviceInfoBatteryStatus, 0, 0, ""); f->addField("sensor_position", fitEnumType, eDeviceInfoSensorPosition, 0, 0, ""); f->addField("descriptor", fitStringType, eDeviceInfoDescriptor, 0, 0, ""); f->addField("ant_transmission_type", fitUint8zType, eDeviceInfoAntTransmissionType, 0, 0, ""); f->addField("ant_device_number", fitUint16zType, eDeviceInfoAntDeviceNumber, 0, 0, ""); f->addField("ant_network", fitEnumType, eDeviceInfoAntNetwork, 0, 0, ""); f->addField("source_type", fitEnumType, eDeviceInfoSourceType, 0, 0, ""); f->addField("product_name", fitStringType, eDeviceInfoProductName, 0, 0, ""); profiles.insert(eMesgNumDeviceInfo, f); } void initTrainingFile(QMap& profiles) { CFitProfile* f = new CFitProfile("training_file", eMesgNumTrainingFile); f->addField("timestamp", fitEnumType, eTrainingFileTimestamp, 0, 0, ""); f->addField("type", fitEnumType, eTrainingFileType, 0, 0, ""); f->addField("manufacturer", fitEnumType, eTrainingFileManufacturer, 0, 0, ""); f->addField("product", fitUint16Type, eTrainingFileProduct, 0, 0, ""); f->addSubfield("garmin_product", fitEnumType, eTrainingFileProduct, 0, 0, "", eTrainingFileManufacturer, eManufacturerGarmin); f->addSubfield("garmin_product", fitEnumType, eTrainingFileProduct, 0, 0, "", eTrainingFileManufacturer, eManufacturerDynastream); f->addSubfield("garmin_product", fitEnumType, eTrainingFileProduct, 0, 0, "", eTrainingFileManufacturer, eManufacturerDynastreamOem); f->addField("serial_number", fitUint32zType, eTrainingFileSerialNumber, 0, 0, ""); f->addField("time_created", fitEnumType, eTrainingFileTimeCreated, 0, 0, ""); profiles.insert(eMesgNumTrainingFile, f); } void initHrv(QMap& profiles) { CFitProfile* f = new CFitProfile("hrv", eMesgNumHrv); f->addField("time", fitUint16Type, eHrvTime, 1000, 0, "s"); profiles.insert(eMesgNumHrv, f); } void initWeatherConditions(QMap& profiles) { CFitProfile* f = new CFitProfile("weather_conditions", eMesgNumWeatherConditions); f->addField("timestamp", fitEnumType, eWeatherConditionsTimestamp, 0, 0, ""); f->addField("weather_report", fitEnumType, eWeatherConditionsWeatherReport, 0, 0, ""); f->addField("temperature", fitSint8Type, eWeatherConditionsTemperature, 0, 0, "C"); f->addField("condition", fitEnumType, eWeatherConditionsCondition, 0, 0, ""); f->addField("wind_direction", fitUint16Type, eWeatherConditionsWindDirection, 0, 0, "degrees"); f->addField("wind_speed", fitUint16Type, eWeatherConditionsWindSpeed, 1000, 0, "m/s"); f->addField("precipitation_probability", fitUint8Type, eWeatherConditionsPrecipitationProbability, 0, 0, ""); f->addField("temperature_feels_like", fitSint8Type, eWeatherConditionsTemperatureFeelsLike, 0, 0, "C"); f->addField("relative_humidity", fitUint8Type, eWeatherConditionsRelativeHumidity, 0, 0, ""); f->addField("location", fitStringType, eWeatherConditionsLocation, 0, 0, ""); f->addField("observed_at_time", fitEnumType, eWeatherConditionsObservedAtTime, 0, 0, ""); f->addField("observed_location_lat", fitSint32Type, eWeatherConditionsObservedLocationLat, 0, 0, "semicircles"); f->addField("observed_location_long", fitSint32Type, eWeatherConditionsObservedLocationLong, 0, 0, "semicircles"); f->addField("day_of_week", fitEnumType, eWeatherConditionsDayOfWeek, 0, 0, ""); f->addField("high_temperature", fitSint8Type, eWeatherConditionsHighTemperature, 0, 0, "C"); f->addField("low_temperature", fitSint8Type, eWeatherConditionsLowTemperature, 0, 0, "C"); profiles.insert(eMesgNumWeatherConditions, f); } void initWeatherAlert(QMap& profiles) { CFitProfile* f = new CFitProfile("weather_alert", eMesgNumWeatherAlert); f->addField("timestamp", fitEnumType, eWeatherAlertTimestamp, 0, 0, ""); f->addField("report_id", fitStringType, eWeatherAlertReportId, 0, 0, ""); f->addField("issue_time", fitEnumType, eWeatherAlertIssueTime, 0, 0, ""); f->addField("expire_time", fitEnumType, eWeatherAlertExpireTime, 0, 0, ""); f->addField("severity", fitEnumType, eWeatherAlertSeverity, 0, 0, ""); f->addField("type", fitEnumType, eWeatherAlertType, 0, 0, ""); profiles.insert(eMesgNumWeatherAlert, f); } void initGpsMetadata(QMap& profiles) { CFitProfile* f = new CFitProfile("gps_metadata", eMesgNumGpsMetadata); f->addField("timestamp", fitEnumType, eGpsMetadataTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eGpsMetadataTimestampMs, 0, 0, "ms"); f->addField("position_lat", fitSint32Type, eGpsMetadataPositionLat, 0, 0, "semicircles"); f->addField("position_long", fitSint32Type, eGpsMetadataPositionLong, 0, 0, "semicircles"); f->addField("enhanced_altitude", fitUint32Type, eGpsMetadataEnhancedAltitude, 5, 500, "m"); f->addField("enhanced_speed", fitUint32Type, eGpsMetadataEnhancedSpeed, 1000, 0, "m/s"); f->addField("heading", fitUint16Type, eGpsMetadataHeading, 100, 0, "degrees"); f->addField("utc_timestamp", fitEnumType, eGpsMetadataUtcTimestamp, 0, 0, "s"); f->addField("velocity", fitSint16Type, eGpsMetadataVelocity, 100, 0, "m/s"); profiles.insert(eMesgNumGpsMetadata, f); } void initCameraEvent(QMap& profiles) { CFitProfile* f = new CFitProfile("camera_event", eMesgNumCameraEvent); f->addField("timestamp", fitEnumType, eCameraEventTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eCameraEventTimestampMs, 0, 0, "ms"); f->addField("camera_event_type", fitEnumType, eCameraEventCameraEventType, 0, 0, ""); f->addField("camera_file_uuid", fitStringType, eCameraEventCameraFileUuid, 0, 0, ""); f->addField("camera_orientation", fitEnumType, eCameraEventCameraOrientation, 0, 0, ""); profiles.insert(eMesgNumCameraEvent, f); } void initGyroscopeData(QMap& profiles) { CFitProfile* f = new CFitProfile("gyroscope_data", eMesgNumGyroscopeData); f->addField("timestamp", fitEnumType, eGyroscopeDataTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eGyroscopeDataTimestampMs, 0, 0, "ms"); f->addField("sample_time_offset", fitUint16Type, eGyroscopeDataSampleTimeOffset, 0, 0, "ms"); f->addField("gyro_x", fitUint16Type, eGyroscopeDataGyroX, 0, 0, "counts"); f->addField("gyro_y", fitUint16Type, eGyroscopeDataGyroY, 0, 0, "counts"); f->addField("gyro_z", fitUint16Type, eGyroscopeDataGyroZ, 0, 0, "counts"); f->addField("calibrated_gyro_x", fitFloat32Type, eGyroscopeDataCalibratedGyroX, 0, 0, "deg/s"); f->addField("calibrated_gyro_y", fitFloat32Type, eGyroscopeDataCalibratedGyroY, 0, 0, "deg/s"); f->addField("calibrated_gyro_z", fitFloat32Type, eGyroscopeDataCalibratedGyroZ, 0, 0, "deg/s"); profiles.insert(eMesgNumGyroscopeData, f); } void initAccelerometerData(QMap& profiles) { CFitProfile* f = new CFitProfile("accelerometer_data", eMesgNumAccelerometerData); f->addField("timestamp", fitEnumType, eAccelerometerDataTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eAccelerometerDataTimestampMs, 0, 0, "ms"); f->addField("sample_time_offset", fitUint16Type, eAccelerometerDataSampleTimeOffset, 0, 0, "ms"); f->addField("accel_x", fitUint16Type, eAccelerometerDataAccelX, 0, 0, "counts"); f->addField("accel_y", fitUint16Type, eAccelerometerDataAccelY, 0, 0, "counts"); f->addField("accel_z", fitUint16Type, eAccelerometerDataAccelZ, 0, 0, "counts"); f->addField("calibrated_accel_x", fitFloat32Type, eAccelerometerDataCalibratedAccelX, 0, 0, "g"); f->addField("calibrated_accel_y", fitFloat32Type, eAccelerometerDataCalibratedAccelY, 0, 0, "g"); f->addField("calibrated_accel_z", fitFloat32Type, eAccelerometerDataCalibratedAccelZ, 0, 0, "g"); f->addField("compressed_calibrated_accel_x", fitSint16Type, eAccelerometerDataCompressedCalibratedAccelX, 0, 0, "mG"); f->addField("compressed_calibrated_accel_y", fitSint16Type, eAccelerometerDataCompressedCalibratedAccelY, 0, 0, "mG"); f->addField("compressed_calibrated_accel_z", fitSint16Type, eAccelerometerDataCompressedCalibratedAccelZ, 0, 0, "mG"); profiles.insert(eMesgNumAccelerometerData, f); } void initMagnetometerData(QMap& profiles) { CFitProfile* f = new CFitProfile("magnetometer_data", eMesgNumMagnetometerData); f->addField("timestamp", fitEnumType, eMagnetometerDataTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eMagnetometerDataTimestampMs, 0, 0, "ms"); f->addField("sample_time_offset", fitUint16Type, eMagnetometerDataSampleTimeOffset, 0, 0, "ms"); f->addField("mag_x", fitUint16Type, eMagnetometerDataMagX, 0, 0, "counts"); f->addField("mag_y", fitUint16Type, eMagnetometerDataMagY, 0, 0, "counts"); f->addField("mag_z", fitUint16Type, eMagnetometerDataMagZ, 0, 0, "counts"); f->addField("calibrated_mag_x", fitFloat32Type, eMagnetometerDataCalibratedMagX, 0, 0, "G"); f->addField("calibrated_mag_y", fitFloat32Type, eMagnetometerDataCalibratedMagY, 0, 0, "G"); f->addField("calibrated_mag_z", fitFloat32Type, eMagnetometerDataCalibratedMagZ, 0, 0, "G"); profiles.insert(eMesgNumMagnetometerData, f); } void initThreeDSensorCalibration(QMap& profiles) { CFitProfile* f = new CFitProfile("three_d_sensor_calibration", eMesgNumThreeDSensorCalibration); f->addField("timestamp", fitEnumType, eThreeDSensorCalibrationTimestamp, 0, 0, "s"); f->addField("sensor_type", fitEnumType, eThreeDSensorCalibrationSensorType, 0, 0, ""); f->addField("calibration_factor", fitUint32Type, eThreeDSensorCalibrationCalibrationFactor, 0, 0, ""); f->addSubfield("accel_cal_factor", fitUint32Type, eThreeDSensorCalibrationCalibrationFactor, 0, 0, "g", eThreeDSensorCalibrationSensorType, eSensorTypeAccelerometer); f->addSubfield("gyro_cal_factor", fitUint32Type, eThreeDSensorCalibrationCalibrationFactor, 0, 0, "deg/s", eThreeDSensorCalibrationSensorType, eSensorTypeGyroscope); f->addField("calibration_divisor", fitUint32Type, eThreeDSensorCalibrationCalibrationDivisor, 0, 0, "counts"); f->addField("level_shift", fitUint32Type, eThreeDSensorCalibrationLevelShift, 0, 0, ""); f->addField("offset_cal", fitSint32Type, eThreeDSensorCalibrationOffsetCal, 0, 0, ""); f->addField("orientation_matrix", fitSint32Type, eThreeDSensorCalibrationOrientationMatrix, 65535, 0, ""); profiles.insert(eMesgNumThreeDSensorCalibration, f); } void initVideoFrame(QMap& profiles) { CFitProfile* f = new CFitProfile("video_frame", eMesgNumVideoFrame); f->addField("timestamp", fitEnumType, eVideoFrameTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eVideoFrameTimestampMs, 0, 0, "ms"); f->addField("frame_number", fitUint32Type, eVideoFrameFrameNumber, 0, 0, ""); profiles.insert(eMesgNumVideoFrame, f); } void initObdiiData(QMap& profiles) { CFitProfile* f = new CFitProfile("obdii_data", eMesgNumObdiiData); f->addField("timestamp", fitEnumType, eObdiiDataTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eObdiiDataTimestampMs, 0, 0, "ms"); f->addField("time_offset", fitUint16Type, eObdiiDataTimeOffset, 0, 0, "ms"); f->addField("pid", fitByteType, eObdiiDataPid, 0, 0, ""); f->addField("raw_data", fitByteType, eObdiiDataRawData, 0, 0, ""); f->addField("pid_data_size", fitUint8Type, eObdiiDataPidDataSize, 0, 0, ""); f->addField("system_time", fitUint32Type, eObdiiDataSystemTime, 0, 0, ""); f->addField("start_timestamp", fitEnumType, eObdiiDataStartTimestamp, 0, 0, ""); f->addField("start_timestamp_ms", fitUint16Type, eObdiiDataStartTimestampMs, 0, 0, "ms"); profiles.insert(eMesgNumObdiiData, f); } void initNmeaSentence(QMap& profiles) { CFitProfile* f = new CFitProfile("nmea_sentence", eMesgNumNmeaSentence); f->addField("timestamp", fitEnumType, eNmeaSentenceTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eNmeaSentenceTimestampMs, 0, 0, "ms"); f->addField("sentence", fitStringType, eNmeaSentenceSentence, 0, 0, ""); profiles.insert(eMesgNumNmeaSentence, f); } void initAviationAttitude(QMap& profiles) { CFitProfile* f = new CFitProfile("aviation_attitude", eMesgNumAviationAttitude); f->addField("timestamp", fitEnumType, eAviationAttitudeTimestamp, 0, 0, "s"); f->addField("timestamp_ms", fitUint16Type, eAviationAttitudeTimestampMs, 0, 0, "ms"); f->addField("system_time", fitUint32Type, eAviationAttitudeSystemTime, 0, 0, "ms"); f->addField("pitch", fitSint16Type, eAviationAttitudePitch, 10430.38, 0, "radians"); f->addField("roll", fitSint16Type, eAviationAttitudeRoll, 10430.38, 0, "radians"); f->addField("accel_lateral", fitSint16Type, eAviationAttitudeAccelLateral, 100, 0, "m/s^2"); f->addField("accel_normal", fitSint16Type, eAviationAttitudeAccelNormal, 100, 0, "m/s^2"); f->addField("turn_rate", fitSint16Type, eAviationAttitudeTurnRate, 1024, 0, "radians/second"); f->addField("stage", fitEnumType, eAviationAttitudeStage, 0, 0, ""); f->addField("attitude_stage_complete", fitUint8Type, eAviationAttitudeAttitudeStageComplete, 0, 0, "%"); f->addField("track", fitUint16Type, eAviationAttitudeTrack, 10430.38, 0, "radians"); f->addField("validity", fitEnumType, eAviationAttitudeValidity, 0, 0, ""); profiles.insert(eMesgNumAviationAttitude, f); } void initVideo(QMap& profiles) { CFitProfile* f = new CFitProfile("video", eMesgNumVideo); f->addField("url", fitStringType, eVideoUrl, 0, 0, ""); f->addField("hosting_provider", fitStringType, eVideoHostingProvider, 0, 0, ""); f->addField("duration", fitUint32Type, eVideoDuration, 0, 0, "ms"); profiles.insert(eMesgNumVideo, f); } void initVideoTitle(QMap& profiles) { CFitProfile* f = new CFitProfile("video_title", eMesgNumVideoTitle); f->addField("message_index", fitEnumType, eVideoTitleMessageIndex, 0, 0, ""); f->addField("message_count", fitUint16Type, eVideoTitleMessageCount, 0, 0, ""); f->addField("text", fitStringType, eVideoTitleText, 0, 0, ""); profiles.insert(eMesgNumVideoTitle, f); } void initVideoDescription(QMap& profiles) { CFitProfile* f = new CFitProfile("video_description", eMesgNumVideoDescription); f->addField("message_index", fitEnumType, eVideoDescriptionMessageIndex, 0, 0, ""); f->addField("message_count", fitUint16Type, eVideoDescriptionMessageCount, 0, 0, ""); f->addField("text", fitStringType, eVideoDescriptionText, 0, 0, ""); profiles.insert(eMesgNumVideoDescription, f); } void initVideoClip(QMap& profiles) { CFitProfile* f = new CFitProfile("video_clip", eMesgNumVideoClip); f->addField("clip_number", fitUint16Type, eVideoClipClipNumber, 0, 0, ""); f->addField("start_timestamp", fitEnumType, eVideoClipStartTimestamp, 0, 0, ""); f->addField("start_timestamp_ms", fitUint16Type, eVideoClipStartTimestampMs, 0, 0, ""); f->addField("end_timestamp", fitEnumType, eVideoClipEndTimestamp, 0, 0, ""); f->addField("end_timestamp_ms", fitUint16Type, eVideoClipEndTimestampMs, 0, 0, ""); f->addField("clip_start", fitUint32Type, eVideoClipClipStart, 0, 0, "ms"); f->addField("clip_end", fitUint32Type, eVideoClipClipEnd, 0, 0, "ms"); profiles.insert(eMesgNumVideoClip, f); } void initCourse(QMap& profiles) { CFitProfile* f = new CFitProfile("course", eMesgNumCourse); f->addField("sport", fitEnumType, eCourseSport, 0, 0, ""); f->addField("name", fitStringType, eCourseName, 0, 0, ""); f->addField("capabilities", fitEnumType, eCourseCapabilities, 0, 0, ""); f->addField("sub_sport", fitEnumType, eCourseSubSport, 0, 0, ""); profiles.insert(eMesgNumCourse, f); } void initCoursePoint(QMap& profiles) { CFitProfile* f = new CFitProfile("course_point", eMesgNumCoursePoint); f->addField("message_index", fitEnumType, eCoursePointMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eCoursePointTimestamp, 0, 0, ""); f->addField("position_lat", fitSint32Type, eCoursePointPositionLat, 0, 0, "semicircles"); f->addField("position_long", fitSint32Type, eCoursePointPositionLong, 0, 0, "semicircles"); f->addField("distance", fitUint32Type, eCoursePointDistance, 100, 0, "m"); f->addField("type", fitEnumType, eCoursePointType, 0, 0, ""); f->addField("name", fitStringType, eCoursePointName, 0, 0, ""); f->addField("favorite", fitEnumType, eCoursePointFavorite, 0, 0, ""); profiles.insert(eMesgNumCoursePoint, f); } void initSegmentId(QMap& profiles) { CFitProfile* f = new CFitProfile("segment_id", eMesgNumSegmentId); f->addField("name", fitStringType, eSegmentIdName, 0, 0, ""); f->addField("uuid", fitStringType, eSegmentIdUuid, 0, 0, ""); f->addField("sport", fitEnumType, eSegmentIdSport, 0, 0, ""); f->addField("enabled", fitEnumType, eSegmentIdEnabled, 0, 0, ""); f->addField("user_profile_primary_key", fitUint32Type, eSegmentIdUserProfilePrimaryKey, 0, 0, ""); f->addField("device_id", fitUint32Type, eSegmentIdDeviceId, 0, 0, ""); f->addField("default_race_leader", fitUint8Type, eSegmentIdDefaultRaceLeader, 0, 0, ""); f->addField("delete_status", fitEnumType, eSegmentIdDeleteStatus, 0, 0, ""); f->addField("selection_type", fitEnumType, eSegmentIdSelectionType, 0, 0, ""); profiles.insert(eMesgNumSegmentId, f); } void initSegmentLeaderboardEntry(QMap& profiles) { CFitProfile* f = new CFitProfile("segment_leaderboard_entry", eMesgNumSegmentLeaderboardEntry); f->addField("message_index", fitEnumType, eSegmentLeaderboardEntryMessageIndex, 0, 0, ""); f->addField("name", fitStringType, eSegmentLeaderboardEntryName, 0, 0, ""); f->addField("type", fitEnumType, eSegmentLeaderboardEntryType, 0, 0, ""); f->addField("group_primary_key", fitUint32Type, eSegmentLeaderboardEntryGroupPrimaryKey, 0, 0, ""); f->addField("activity_id", fitUint32Type, eSegmentLeaderboardEntryActivityId, 0, 0, ""); f->addField("segment_time", fitUint32Type, eSegmentLeaderboardEntrySegmentTime, 1000, 0, "s"); f->addField("activity_id_string", fitStringType, eSegmentLeaderboardEntryActivityIdString, 0, 0, ""); profiles.insert(eMesgNumSegmentLeaderboardEntry, f); } void initSegmentPoint(QMap& profiles) { CFitProfile* f = new CFitProfile("segment_point", eMesgNumSegmentPoint); f->addField("message_index", fitEnumType, eSegmentPointMessageIndex, 0, 0, ""); f->addField("position_lat", fitSint32Type, eSegmentPointPositionLat, 0, 0, "semicircles"); f->addField("position_long", fitSint32Type, eSegmentPointPositionLong, 0, 0, "semicircles"); f->addField("distance", fitUint32Type, eSegmentPointDistance, 100, 0, "m"); f->addField("altitude", fitUint16Type, eSegmentPointAltitude, 5, 500, "m"); f->addField("leader_time", fitUint32Type, eSegmentPointLeaderTime, 1000, 0, "s"); profiles.insert(eMesgNumSegmentPoint, f); } void initSegmentLap(QMap& profiles) { CFitProfile* f = new CFitProfile("segment_lap", eMesgNumSegmentLap); f->addField("message_index", fitEnumType, eSegmentLapMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eSegmentLapTimestamp, 0, 0, "s"); f->addField("event", fitEnumType, eSegmentLapEvent, 0, 0, ""); f->addField("event_type", fitEnumType, eSegmentLapEventType, 0, 0, ""); f->addField("start_time", fitEnumType, eSegmentLapStartTime, 0, 0, ""); f->addField("start_position_lat", fitSint32Type, eSegmentLapStartPositionLat, 0, 0, "semicircles"); f->addField("start_position_long", fitSint32Type, eSegmentLapStartPositionLong, 0, 0, "semicircles"); f->addField("end_position_lat", fitSint32Type, eSegmentLapEndPositionLat, 0, 0, "semicircles"); f->addField("end_position_long", fitSint32Type, eSegmentLapEndPositionLong, 0, 0, "semicircles"); f->addField("total_elapsed_time", fitUint32Type, eSegmentLapTotalElapsedTime, 1000, 0, "s"); f->addField("total_timer_time", fitUint32Type, eSegmentLapTotalTimerTime, 1000, 0, "s"); f->addField("total_distance", fitUint32Type, eSegmentLapTotalDistance, 100, 0, "m"); f->addField("total_cycles", fitUint32Type, eSegmentLapTotalCycles, 0, 0, "cycles"); f->addSubfield("total_strokes", fitUint32Type, eSegmentLapTotalCycles, 0, 0, "strokes", eSegmentLapSport, eSportCycling); f->addField("total_calories", fitUint16Type, eSegmentLapTotalCalories, 0, 0, "kcal"); f->addField("total_fat_calories", fitUint16Type, eSegmentLapTotalFatCalories, 0, 0, "kcal"); f->addField("avg_speed", fitUint16Type, eSegmentLapAvgSpeed, 1000, 0, "m/s"); f->addField("max_speed", fitUint16Type, eSegmentLapMaxSpeed, 1000, 0, "m/s"); f->addField("avg_heart_rate", fitUint8Type, eSegmentLapAvgHeartRate, 0, 0, "bpm"); f->addField("max_heart_rate", fitUint8Type, eSegmentLapMaxHeartRate, 0, 0, "bpm"); f->addField("avg_cadence", fitUint8Type, eSegmentLapAvgCadence, 0, 0, "rpm"); f->addField("max_cadence", fitUint8Type, eSegmentLapMaxCadence, 0, 0, "rpm"); f->addField("avg_power", fitUint16Type, eSegmentLapAvgPower, 0, 0, "watts"); f->addField("max_power", fitUint16Type, eSegmentLapMaxPower, 0, 0, "watts"); f->addField("total_ascent", fitUint16Type, eSegmentLapTotalAscent, 0, 0, "m"); f->addField("total_descent", fitUint16Type, eSegmentLapTotalDescent, 0, 0, "m"); f->addField("sport", fitEnumType, eSegmentLapSport, 0, 0, ""); f->addField("event_group", fitUint8Type, eSegmentLapEventGroup, 0, 0, ""); f->addField("nec_lat", fitSint32Type, eSegmentLapNecLat, 0, 0, "semicircles"); f->addField("nec_long", fitSint32Type, eSegmentLapNecLong, 0, 0, "semicircles"); f->addField("swc_lat", fitSint32Type, eSegmentLapSwcLat, 0, 0, "semicircles"); f->addField("swc_long", fitSint32Type, eSegmentLapSwcLong, 0, 0, "semicircles"); f->addField("name", fitStringType, eSegmentLapName, 0, 0, ""); f->addField("normalized_power", fitUint16Type, eSegmentLapNormalizedPower, 0, 0, "watts"); f->addField("left_right_balance", fitEnumType, eSegmentLapLeftRightBalance, 0, 0, ""); f->addField("sub_sport", fitEnumType, eSegmentLapSubSport, 0, 0, ""); f->addField("total_work", fitUint32Type, eSegmentLapTotalWork, 0, 0, "J"); f->addField("avg_altitude", fitUint16Type, eSegmentLapAvgAltitude, 5, 500, "m"); f->addField("max_altitude", fitUint16Type, eSegmentLapMaxAltitude, 5, 500, "m"); f->addField("gps_accuracy", fitUint8Type, eSegmentLapGpsAccuracy, 0, 0, "m"); f->addField("avg_grade", fitSint16Type, eSegmentLapAvgGrade, 100, 0, "%"); f->addField("avg_pos_grade", fitSint16Type, eSegmentLapAvgPosGrade, 100, 0, "%"); f->addField("avg_neg_grade", fitSint16Type, eSegmentLapAvgNegGrade, 100, 0, "%"); f->addField("max_pos_grade", fitSint16Type, eSegmentLapMaxPosGrade, 100, 0, "%"); f->addField("max_neg_grade", fitSint16Type, eSegmentLapMaxNegGrade, 100, 0, "%"); f->addField("avg_temperature", fitSint8Type, eSegmentLapAvgTemperature, 0, 0, "C"); f->addField("max_temperature", fitSint8Type, eSegmentLapMaxTemperature, 0, 0, "C"); f->addField("total_moving_time", fitUint32Type, eSegmentLapTotalMovingTime, 1000, 0, "s"); f->addField("avg_pos_vertical_speed", fitSint16Type, eSegmentLapAvgPosVerticalSpeed, 1000, 0, "m/s"); f->addField("avg_neg_vertical_speed", fitSint16Type, eSegmentLapAvgNegVerticalSpeed, 1000, 0, "m/s"); f->addField("max_pos_vertical_speed", fitSint16Type, eSegmentLapMaxPosVerticalSpeed, 1000, 0, "m/s"); f->addField("max_neg_vertical_speed", fitSint16Type, eSegmentLapMaxNegVerticalSpeed, 1000, 0, "m/s"); f->addField("time_in_hr_zone", fitUint32Type, eSegmentLapTimeInHrZone, 1000, 0, "s"); f->addField("time_in_speed_zone", fitUint32Type, eSegmentLapTimeInSpeedZone, 1000, 0, "s"); f->addField("time_in_cadence_zone", fitUint32Type, eSegmentLapTimeInCadenceZone, 1000, 0, "s"); f->addField("time_in_power_zone", fitUint32Type, eSegmentLapTimeInPowerZone, 1000, 0, "s"); f->addField("repetition_num", fitUint16Type, eSegmentLapRepetitionNum, 0, 0, ""); f->addField("min_altitude", fitUint16Type, eSegmentLapMinAltitude, 5, 500, "m"); f->addField("min_heart_rate", fitUint8Type, eSegmentLapMinHeartRate, 0, 0, "bpm"); f->addField("active_time", fitUint32Type, eSegmentLapActiveTime, 1000, 0, "s"); f->addField("wkt_step_index", fitEnumType, eSegmentLapWktStepIndex, 0, 0, ""); f->addField("sport_event", fitEnumType, eSegmentLapSportEvent, 0, 0, ""); f->addField("avg_left_torque_effectiveness", fitUint8Type, eSegmentLapAvgLeftTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_right_torque_effectiveness", fitUint8Type, eSegmentLapAvgRightTorqueEffectiveness, 2, 0, "percent"); f->addField("avg_left_pedal_smoothness", fitUint8Type, eSegmentLapAvgLeftPedalSmoothness, 2, 0, "percent"); f->addField("avg_right_pedal_smoothness", fitUint8Type, eSegmentLapAvgRightPedalSmoothness, 2, 0, "percent"); f->addField("avg_combined_pedal_smoothness", fitUint8Type, eSegmentLapAvgCombinedPedalSmoothness, 2, 0, "percent"); f->addField("status", fitEnumType, eSegmentLapStatus, 0, 0, ""); f->addField("uuid", fitStringType, eSegmentLapUuid, 0, 0, ""); f->addField("avg_fractional_cadence", fitUint8Type, eSegmentLapAvgFractionalCadence, 128, 0, "rpm"); f->addField("max_fractional_cadence", fitUint8Type, eSegmentLapMaxFractionalCadence, 128, 0, "rpm"); f->addField("total_fractional_cycles", fitUint8Type, eSegmentLapTotalFractionalCycles, 128, 0, "cycles"); f->addField("front_gear_shift_count", fitUint16Type, eSegmentLapFrontGearShiftCount, 0, 0, ""); f->addField("rear_gear_shift_count", fitUint16Type, eSegmentLapRearGearShiftCount, 0, 0, ""); f->addField("time_standing", fitUint32Type, eSegmentLapTimeStanding, 1000, 0, "s"); f->addField("stand_count", fitUint16Type, eSegmentLapStandCount, 0, 0, ""); f->addField("avg_left_pco", fitSint8Type, eSegmentLapAvgLeftPco, 0, 0, "mm"); f->addField("avg_right_pco", fitSint8Type, eSegmentLapAvgRightPco, 0, 0, "mm"); f->addField("avg_left_power_phase", fitUint8Type, eSegmentLapAvgLeftPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_left_power_phase_peak", fitUint8Type, eSegmentLapAvgLeftPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase", fitUint8Type, eSegmentLapAvgRightPowerPhase, 0.7111111, 0, "degrees"); f->addField("avg_right_power_phase_peak", fitUint8Type, eSegmentLapAvgRightPowerPhasePeak, 0.7111111, 0, "degrees"); f->addField("avg_power_position", fitUint16Type, eSegmentLapAvgPowerPosition, 0, 0, "watts"); f->addField("max_power_position", fitUint16Type, eSegmentLapMaxPowerPosition, 0, 0, "watts"); f->addField("avg_cadence_position", fitUint8Type, eSegmentLapAvgCadencePosition, 0, 0, "rpm"); f->addField("max_cadence_position", fitUint8Type, eSegmentLapMaxCadencePosition, 0, 0, "rpm"); f->addField("manufacturer", fitEnumType, eSegmentLapManufacturer, 0, 0, ""); profiles.insert(eMesgNumSegmentLap, f); } void initSegmentFile(QMap& profiles) { CFitProfile* f = new CFitProfile("segment_file", eMesgNumSegmentFile); f->addField("message_index", fitEnumType, eSegmentFileMessageIndex, 0, 0, ""); f->addField("file_uuid", fitStringType, eSegmentFileFileUuid, 0, 0, ""); f->addField("enabled", fitEnumType, eSegmentFileEnabled, 0, 0, ""); f->addField("user_profile_primary_key", fitUint32Type, eSegmentFileUserProfilePrimaryKey, 0, 0, ""); f->addField("leader_type", fitEnumType, eSegmentFileLeaderType, 0, 0, ""); f->addField("leader_group_primary_key", fitUint32Type, eSegmentFileLeaderGroupPrimaryKey, 0, 0, ""); f->addField("leader_activity_id", fitUint32Type, eSegmentFileLeaderActivityId, 0, 0, ""); f->addField("leader_activity_id_string", fitStringType, eSegmentFileLeaderActivityIdString, 0, 0, ""); f->addField("default_race_leader", fitUint8Type, eSegmentFileDefaultRaceLeader, 0, 0, ""); profiles.insert(eMesgNumSegmentFile, f); } void initWorkout(QMap& profiles) { CFitProfile* f = new CFitProfile("workout", eMesgNumWorkout); f->addField("sport", fitEnumType, eWorkoutSport, 0, 0, ""); f->addField("capabilities", fitEnumType, eWorkoutCapabilities, 0, 0, ""); f->addField("num_valid_steps", fitUint16Type, eWorkoutNumValidSteps, 0, 0, ""); f->addField("wkt_name", fitStringType, eWorkoutWktName, 0, 0, ""); profiles.insert(eMesgNumWorkout, f); } void initWorkoutStep(QMap& profiles) { CFitProfile* f = new CFitProfile("workout_step", eMesgNumWorkoutStep); f->addField("message_index", fitEnumType, eWorkoutStepMessageIndex, 0, 0, ""); f->addField("wkt_step_name", fitStringType, eWorkoutStepWktStepName, 0, 0, ""); f->addField("duration_type", fitEnumType, eWorkoutStepDurationType, 0, 0, ""); f->addField("duration_value", fitUint32Type, eWorkoutStepDurationValue, 0, 0, ""); f->addSubfield("duration_time", fitUint32Type, eWorkoutStepDurationValue, 1000, 0, "s", eWorkoutStepDurationType, eWktStepDurationTime); f->addSubfield("duration_time", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepetitionTime); f->addSubfield("duration_distance", fitUint32Type, eWorkoutStepDurationValue, 100, 0, "m", eWorkoutStepDurationType, eWktStepDurationDistance); f->addSubfield("duration_hr", fitEnumType, eWorkoutStepDurationValue, 0, 0, "% or bpm", eWorkoutStepDurationType, eWktStepDurationHrLessThan); f->addSubfield("duration_hr", fitEnumType, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationHrGreaterThan); f->addSubfield("duration_calories", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "calories", eWorkoutStepDurationType, eWktStepDurationCalories); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilStepsCmplt); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilTime); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilDistance); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilCalories); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilHrLessThan); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilHrGreaterThan); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilPowerLessThan); f->addSubfield("duration_step", fitUint32Type, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilPowerGreaterThan); f->addSubfield("duration_power", fitEnumType, eWorkoutStepDurationValue, 0, 0, "% or watts", eWorkoutStepDurationType, eWktStepDurationPowerLessThan); f->addSubfield("duration_power", fitEnumType, eWorkoutStepDurationValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationPowerGreaterThan); f->addField("target_type", fitEnumType, eWorkoutStepTargetType, 0, 0, ""); f->addField("target_value", fitUint32Type, eWorkoutStepTargetValue, 0, 0, ""); f->addSubfield("target_speed_zone", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepTargetType, eWktStepTargetSpeed); f->addSubfield("target_hr_zone", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepTargetType, eWktStepTargetHeartRate); f->addSubfield("target_cadence_zone", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepTargetType, eWktStepTargetCadence); f->addSubfield("target_power_zone", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepTargetType, eWktStepTargetPower); f->addSubfield("repeat_steps", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilStepsCmplt); f->addSubfield("repeat_time", fitUint32Type, eWorkoutStepTargetValue, 1000, 0, "s", eWorkoutStepDurationType, eWktStepDurationRepeatUntilTime); f->addSubfield("repeat_distance", fitUint32Type, eWorkoutStepTargetValue, 100, 0, "m", eWorkoutStepDurationType, eWktStepDurationRepeatUntilDistance); f->addSubfield("repeat_calories", fitUint32Type, eWorkoutStepTargetValue, 0, 0, "calories", eWorkoutStepDurationType, eWktStepDurationRepeatUntilCalories); f->addSubfield("repeat_hr", fitEnumType, eWorkoutStepTargetValue, 0, 0, "% or bpm", eWorkoutStepDurationType, eWktStepDurationRepeatUntilHrLessThan); f->addSubfield("repeat_hr", fitEnumType, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilHrGreaterThan); f->addSubfield("repeat_power", fitEnumType, eWorkoutStepTargetValue, 0, 0, "% or watts", eWorkoutStepDurationType, eWktStepDurationRepeatUntilPowerLessThan); f->addSubfield("repeat_power", fitEnumType, eWorkoutStepTargetValue, 0, 0, "", eWorkoutStepDurationType, eWktStepDurationRepeatUntilPowerGreaterThan); f->addField("custom_target_value_low", fitUint32Type, eWorkoutStepCustomTargetValueLow, 0, 0, ""); f->addSubfield("custom_target_speed_low", fitUint32Type, eWorkoutStepCustomTargetValueLow, 1000, 0, "m/s", eWorkoutStepTargetType, eWktStepTargetSpeed); f->addSubfield("custom_target_heart_rate_low", fitEnumType, eWorkoutStepCustomTargetValueLow, 0, 0, "% or bpm", eWorkoutStepTargetType, eWktStepTargetHeartRate); f->addSubfield("custom_target_cadence_low", fitUint32Type, eWorkoutStepCustomTargetValueLow, 0, 0, "rpm", eWorkoutStepTargetType, eWktStepTargetCadence); f->addSubfield("custom_target_power_low", fitEnumType, eWorkoutStepCustomTargetValueLow, 0, 0, "% or watts", eWorkoutStepTargetType, eWktStepTargetPower); f->addField("custom_target_value_high", fitUint32Type, eWorkoutStepCustomTargetValueHigh, 0, 0, ""); f->addSubfield("custom_target_speed_high", fitUint32Type, eWorkoutStepCustomTargetValueHigh, 1000, 0, "m/s", eWorkoutStepTargetType, eWktStepTargetSpeed); f->addSubfield("custom_target_heart_rate_high", fitEnumType, eWorkoutStepCustomTargetValueHigh, 0, 0, "% or bpm", eWorkoutStepTargetType, eWktStepTargetHeartRate); f->addSubfield("custom_target_cadence_high", fitUint32Type, eWorkoutStepCustomTargetValueHigh, 0, 0, "rpm", eWorkoutStepTargetType, eWktStepTargetCadence); f->addSubfield("custom_target_power_high", fitEnumType, eWorkoutStepCustomTargetValueHigh, 0, 0, "% or watts", eWorkoutStepTargetType, eWktStepTargetPower); f->addField("intensity", fitEnumType, eWorkoutStepIntensity, 0, 0, ""); f->addField("notes", fitStringType, eWorkoutStepNotes, 0, 0, ""); profiles.insert(eMesgNumWorkoutStep, f); } void initSchedule(QMap& profiles) { CFitProfile* f = new CFitProfile("schedule", eMesgNumSchedule); f->addField("manufacturer", fitEnumType, eScheduleManufacturer, 0, 0, ""); f->addField("product", fitUint16Type, eScheduleProduct, 0, 0, ""); f->addSubfield("garmin_product", fitEnumType, eScheduleProduct, 0, 0, "", eScheduleManufacturer, eManufacturerGarmin); f->addSubfield("garmin_product", fitEnumType, eScheduleProduct, 0, 0, "", eScheduleManufacturer, eManufacturerDynastream); f->addSubfield("garmin_product", fitEnumType, eScheduleProduct, 0, 0, "", eScheduleManufacturer, eManufacturerDynastreamOem); f->addField("serial_number", fitUint32zType, eScheduleSerialNumber, 0, 0, ""); f->addField("time_created", fitEnumType, eScheduleTimeCreated, 0, 0, ""); f->addField("completed", fitEnumType, eScheduleCompleted, 0, 0, ""); f->addField("type", fitEnumType, eScheduleType, 0, 0, ""); f->addField("scheduled_time", fitEnumType, eScheduleScheduledTime, 0, 0, ""); profiles.insert(eMesgNumSchedule, f); } void initTotals(QMap& profiles) { CFitProfile* f = new CFitProfile("totals", eMesgNumTotals); f->addField("message_index", fitEnumType, eTotalsMessageIndex, 0, 0, ""); f->addField("timestamp", fitEnumType, eTotalsTimestamp, 0, 0, "s"); f->addField("timer_time", fitUint32Type, eTotalsTimerTime, 0, 0, "s"); f->addField("distance", fitUint32Type, eTotalsDistance, 0, 0, "m"); f->addField("calories", fitUint32Type, eTotalsCalories, 0, 0, "kcal"); f->addField("sport", fitEnumType, eTotalsSport, 0, 0, ""); f->addField("elapsed_time", fitUint32Type, eTotalsElapsedTime, 0, 0, "s"); f->addField("sessions", fitUint16Type, eTotalsSessions, 0, 0, ""); f->addField("active_time", fitUint32Type, eTotalsActiveTime, 0, 0, "s"); f->addField("sport_index", fitUint8Type, eTotalsSportIndex, 0, 0, ""); profiles.insert(eMesgNumTotals, f); } void initWeightScale(QMap& profiles) { CFitProfile* f = new CFitProfile("weight_scale", eMesgNumWeightScale); f->addField("timestamp", fitEnumType, eWeightScaleTimestamp, 0, 0, "s"); f->addField("weight", fitEnumType, eWeightScaleWeight, 100, 0, "kg"); f->addField("percent_fat", fitUint16Type, eWeightScalePercentFat, 100, 0, "%"); f->addField("percent_hydration", fitUint16Type, eWeightScalePercentHydration, 100, 0, "%"); f->addField("visceral_fat_mass", fitUint16Type, eWeightScaleVisceralFatMass, 100, 0, "kg"); f->addField("bone_mass", fitUint16Type, eWeightScaleBoneMass, 100, 0, "kg"); f->addField("muscle_mass", fitUint16Type, eWeightScaleMuscleMass, 100, 0, "kg"); f->addField("basal_met", fitUint16Type, eWeightScaleBasalMet, 4, 0, "kcal/day"); f->addField("physique_rating", fitUint8Type, eWeightScalePhysiqueRating, 0, 0, ""); f->addField("active_met", fitUint16Type, eWeightScaleActiveMet, 4, 0, "kcal/day"); f->addField("metabolic_age", fitUint8Type, eWeightScaleMetabolicAge, 0, 0, "years"); f->addField("visceral_fat_rating", fitUint8Type, eWeightScaleVisceralFatRating, 0, 0, ""); f->addField("user_profile_index", fitEnumType, eWeightScaleUserProfileIndex, 0, 0, ""); profiles.insert(eMesgNumWeightScale, f); } void initBloodPressure(QMap& profiles) { CFitProfile* f = new CFitProfile("blood_pressure", eMesgNumBloodPressure); f->addField("timestamp", fitEnumType, eBloodPressureTimestamp, 0, 0, "s"); f->addField("systolic_pressure", fitUint16Type, eBloodPressureSystolicPressure, 0, 0, "mmHg"); f->addField("diastolic_pressure", fitUint16Type, eBloodPressureDiastolicPressure, 0, 0, "mmHg"); f->addField("mean_arterial_pressure", fitUint16Type, eBloodPressureMeanArterialPressure, 0, 0, "mmHg"); f->addField("map_3_sample_mean", fitUint16Type, eBloodPressureMap3SampleMean, 0, 0, "mmHg"); f->addField("map_morning_values", fitUint16Type, eBloodPressureMapMorningValues, 0, 0, "mmHg"); f->addField("map_evening_values", fitUint16Type, eBloodPressureMapEveningValues, 0, 0, "mmHg"); f->addField("heart_rate", fitUint8Type, eBloodPressureHeartRate, 0, 0, "bpm"); f->addField("heart_rate_type", fitEnumType, eBloodPressureHeartRateType, 0, 0, ""); f->addField("status", fitEnumType, eBloodPressureStatus, 0, 0, ""); f->addField("user_profile_index", fitEnumType, eBloodPressureUserProfileIndex, 0, 0, ""); profiles.insert(eMesgNumBloodPressure, f); } void initMonitoringInfo(QMap& profiles) { CFitProfile* f = new CFitProfile("monitoring_info", eMesgNumMonitoringInfo); f->addField("timestamp", fitEnumType, eMonitoringInfoTimestamp, 0, 0, "s"); f->addField("local_timestamp", fitEnumType, eMonitoringInfoLocalTimestamp, 0, 0, "s"); f->addField("activity_type", fitEnumType, eMonitoringInfoActivityType, 0, 0, ""); f->addField("cycles_to_distance", fitUint16Type, eMonitoringInfoCyclesToDistance, 5000, 0, "m/cycle"); f->addField("cycles_to_calories", fitUint16Type, eMonitoringInfoCyclesToCalories, 5000, 0, "kcal/cycle"); f->addField("resting_metabolic_rate", fitUint16Type, eMonitoringInfoRestingMetabolicRate, 0, 0, "kcal / day"); profiles.insert(eMesgNumMonitoringInfo, f); } void initMonitoring(QMap& profiles) { CFitProfile* f = new CFitProfile("monitoring", eMesgNumMonitoring); f->addField("timestamp", fitEnumType, eMonitoringTimestamp, 0, 0, "s"); f->addField("device_index", fitEnumType, eMonitoringDeviceIndex, 0, 0, ""); f->addField("calories", fitUint16Type, eMonitoringCalories, 0, 0, "kcal"); f->addField("distance", fitUint32Type, eMonitoringDistance, 100, 0, "m"); f->addField("cycles", fitUint32Type, eMonitoringCycles, 2, 0, "cycles"); f->addSubfield("steps", fitUint32Type, eMonitoringCycles, 1, 0, "steps", eMonitoringActivityType, eActivityTypeWalking); f->addSubfield("steps", fitUint32Type, eMonitoringCycles, 0, 0, "", eMonitoringActivityType, eActivityTypeRunning); f->addSubfield("strokes", fitUint32Type, eMonitoringCycles, 2, 0, "strokes", eMonitoringActivityType, eActivityTypeCycling); f->addSubfield("strokes", fitUint32Type, eMonitoringCycles, 0, 0, "", eMonitoringActivityType, eActivityTypeSwimming); f->addField("active_time", fitUint32Type, eMonitoringActiveTime, 1000, 0, "s"); f->addField("activity_type", fitEnumType, eMonitoringActivityType, 0, 0, ""); f->addField("activity_subtype", fitEnumType, eMonitoringActivitySubtype, 0, 0, ""); f->addField("activity_level", fitEnumType, eMonitoringActivityLevel, 0, 0, ""); f->addField("distance_16", fitUint16Type, eMonitoringDistance16, 0, 0, "100 * m"); f->addField("cycles_16", fitUint16Type, eMonitoringCycles16, 0, 0, "2 * cycles (steps)"); f->addField("active_time_16", fitUint16Type, eMonitoringActiveTime16, 0, 0, "s"); f->addField("local_timestamp", fitEnumType, eMonitoringLocalTimestamp, 0, 0, ""); f->addField("temperature", fitSint16Type, eMonitoringTemperature, 100, 0, "C"); f->addField("temperature_min", fitSint16Type, eMonitoringTemperatureMin, 100, 0, "C"); f->addField("temperature_max", fitSint16Type, eMonitoringTemperatureMax, 100, 0, "C"); f->addField("activity_time", fitUint16Type, eMonitoringActivityTime, 0, 0, "minutes"); f->addField("active_calories", fitUint16Type, eMonitoringActiveCalories, 0, 0, "kcal"); f->addField("current_activity_type_intensity", fitByteType, eMonitoringCurrentActivityTypeIntensity, 0, 0, ""); f->addComponent("current_activity_type_intensity", fitByteType, eMonitoringCurrentActivityTypeIntensity, 0, 0, "", eMonitoringActivityType, 53); f->addComponent("current_activity_type_intensity", fitByteType, eMonitoringCurrentActivityTypeIntensity, 0, 0, "", eMonitoringIntensity, 0); f->addField("timestamp_min_8", fitUint8Type, eMonitoringTimestampMin8, 0, 0, "min"); f->addField("timestamp_16", fitUint16Type, eMonitoringTimestamp16, 0, 0, "s"); f->addField("heart_rate", fitUint8Type, eMonitoringHeartRate, 0, 0, "bpm"); f->addField("intensity", fitUint8Type, eMonitoringIntensity, 10, 0, ""); f->addField("duration_min", fitUint16Type, eMonitoringDurationMin, 0, 0, "min"); f->addField("duration", fitUint32Type, eMonitoringDuration, 0, 0, "s"); f->addField("ascent", fitUint32Type, eMonitoringAscent, 1000, 0, "m"); f->addField("descent", fitUint32Type, eMonitoringDescent, 1000, 0, "m"); f->addField("moderate_activity_minutes", fitUint16Type, eMonitoringModerateActivityMinutes, 0, 0, "minutes"); f->addField("vigorous_activity_minutes", fitUint16Type, eMonitoringVigorousActivityMinutes, 0, 0, "minutes"); profiles.insert(eMesgNumMonitoring, f); } void initHr(QMap& profiles) { CFitProfile* f = new CFitProfile("hr", eMesgNumHr); f->addField("timestamp", fitEnumType, eHrTimestamp, 0, 0, ""); f->addField("fractional_timestamp", fitUint16Type, eHrFractionalTimestamp, 32768, 0, "s"); f->addField("time256", fitUint8Type, eHrTime256, 0, 0, ""); f->addComponent("time256", fitUint8Type, eHrTime256, 256, 0, "s", eHrFractionalTimestamp, 8); f->addField("filtered_bpm", fitUint8Type, eHrFilteredBpm, 0, 0, "bpm"); f->addField("event_timestamp", fitUint32Type, eHrEventTimestamp, 1024, 0, "s"); f->addField("event_timestamp_12", fitByteType, eHrEventTimestamp12, 0, 0, ""); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); f->addComponent("event_timestamp_12", fitByteType, eHrEventTimestamp12, 1024, 0, "s", eHrEventTimestamp, 12); profiles.insert(eMesgNumHr, f); } void initMemoGlob(QMap& profiles) { CFitProfile* f = new CFitProfile("memo_glob", eMesgNumMemoGlob); f->addField("part_index", fitUint32Type, eMemoGlobPartIndex, 0, 0, ""); f->addField("memo", fitByteType, eMemoGlobMemo, 0, 0, ""); f->addField("message_number", fitUint16Type, eMemoGlobMessageNumber, 0, 0, ""); f->addField("message_index", fitEnumType, eMemoGlobMessageIndex, 0, 0, ""); profiles.insert(eMesgNumMemoGlob, f); } void initAntChannelId(QMap& profiles) { CFitProfile* f = new CFitProfile("ant_channel_id", eMesgNumAntChannelId); f->addField("channel_number", fitUint8Type, eAntChannelIdChannelNumber, 0, 0, ""); f->addField("device_type", fitUint8zType, eAntChannelIdDeviceType, 0, 0, ""); f->addField("device_number", fitUint16zType, eAntChannelIdDeviceNumber, 0, 0, ""); f->addField("transmission_type", fitUint8zType, eAntChannelIdTransmissionType, 0, 0, ""); f->addField("device_index", fitEnumType, eAntChannelIdDeviceIndex, 0, 0, ""); profiles.insert(eMesgNumAntChannelId, f); } void initAntRx(QMap& profiles) { CFitProfile* f = new CFitProfile("ant_rx", eMesgNumAntRx); f->addField("timestamp", fitEnumType, eAntRxTimestamp, 0, 0, "s"); f->addField("fractional_timestamp", fitUint16Type, eAntRxFractionalTimestamp, 32768, 0, "s"); f->addField("mesg_id", fitByteType, eAntRxMesgId, 0, 0, ""); f->addField("mesg_data", fitByteType, eAntRxMesgData, 0, 0, ""); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxChannelNumber, 888888888); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addComponent("mesg_data", fitByteType, eAntRxMesgData, 0, 0, "", eAntRxData, 0); f->addField("channel_number", fitUint8Type, eAntRxChannelNumber, 0, 0, ""); f->addField("data", fitByteType, eAntRxData, 0, 0, ""); profiles.insert(eMesgNumAntRx, f); } void initAntTx(QMap& profiles) { CFitProfile* f = new CFitProfile("ant_tx", eMesgNumAntTx); f->addField("timestamp", fitEnumType, eAntTxTimestamp, 0, 0, "s"); f->addField("fractional_timestamp", fitUint16Type, eAntTxFractionalTimestamp, 32768, 0, "s"); f->addField("mesg_id", fitByteType, eAntTxMesgId, 0, 0, ""); f->addField("mesg_data", fitByteType, eAntTxMesgData, 0, 0, ""); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxChannelNumber, 888888888); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addComponent("mesg_data", fitByteType, eAntTxMesgData, 0, 0, "", eAntTxData, 0); f->addField("channel_number", fitUint8Type, eAntTxChannelNumber, 0, 0, ""); f->addField("data", fitByteType, eAntTxData, 0, 0, ""); profiles.insert(eMesgNumAntTx, f); } void initExdScreenConfiguration(QMap& profiles) { CFitProfile* f = new CFitProfile("exd_screen_configuration", eMesgNumExdScreenConfiguration); f->addField("screen_index", fitUint8Type, eExdScreenConfigurationScreenIndex, 0, 0, ""); f->addField("field_count", fitUint8Type, eExdScreenConfigurationFieldCount, 0, 0, ""); f->addField("layout", fitEnumType, eExdScreenConfigurationLayout, 0, 0, ""); f->addField("screen_enabled", fitEnumType, eExdScreenConfigurationScreenEnabled, 0, 0, ""); profiles.insert(eMesgNumExdScreenConfiguration, f); } void initExdDataFieldConfiguration(QMap& profiles) { CFitProfile* f = new CFitProfile("exd_data_field_configuration", eMesgNumExdDataFieldConfiguration); f->addField("screen_index", fitUint8Type, eExdDataFieldConfigurationScreenIndex, 0, 0, ""); f->addField("concept_field", fitByteType, eExdDataFieldConfigurationConceptField, 0, 0, ""); f->addComponent("concept_field", fitByteType, eExdDataFieldConfigurationConceptField, 0, 0, "", eExdDataFieldConfigurationFieldId, 44); f->addComponent("concept_field", fitByteType, eExdDataFieldConfigurationConceptField, 0, 0, "", eExdDataFieldConfigurationConceptCount, 0); f->addField("field_id", fitUint8Type, eExdDataFieldConfigurationFieldId, 0, 0, ""); f->addField("concept_count", fitUint8Type, eExdDataFieldConfigurationConceptCount, 0, 0, ""); f->addField("display_type", fitEnumType, eExdDataFieldConfigurationDisplayType, 0, 0, ""); f->addField("title", fitStringType, eExdDataFieldConfigurationTitle, 0, 0, ""); profiles.insert(eMesgNumExdDataFieldConfiguration, f); } void initExdDataConceptConfiguration(QMap& profiles) { CFitProfile* f = new CFitProfile("exd_data_concept_configuration", eMesgNumExdDataConceptConfiguration); f->addField("screen_index", fitUint8Type, eExdDataConceptConfigurationScreenIndex, 0, 0, ""); f->addField("concept_field", fitByteType, eExdDataConceptConfigurationConceptField, 0, 0, ""); f->addComponent("concept_field", fitByteType, eExdDataConceptConfigurationConceptField, 0, 0, "", eExdDataConceptConfigurationFieldId, 44); f->addComponent("concept_field", fitByteType, eExdDataConceptConfigurationConceptField, 0, 0, "", eExdDataConceptConfigurationConceptIndex, 0); f->addField("field_id", fitUint8Type, eExdDataConceptConfigurationFieldId, 0, 0, ""); f->addField("concept_index", fitUint8Type, eExdDataConceptConfigurationConceptIndex, 0, 0, ""); f->addField("data_page", fitUint8Type, eExdDataConceptConfigurationDataPage, 0, 0, ""); f->addField("concept_key", fitUint8Type, eExdDataConceptConfigurationConceptKey, 0, 0, ""); f->addField("scaling", fitUint8Type, eExdDataConceptConfigurationScaling, 0, 0, ""); f->addField("data_units", fitEnumType, eExdDataConceptConfigurationDataUnits, 0, 0, ""); f->addField("qualifier", fitEnumType, eExdDataConceptConfigurationQualifier, 0, 0, ""); f->addField("descriptor", fitEnumType, eExdDataConceptConfigurationDescriptor, 0, 0, ""); f->addField("is_signed", fitEnumType, eExdDataConceptConfigurationIsSigned, 0, 0, ""); profiles.insert(eMesgNumExdDataConceptConfiguration, f); } void initFieldDescription(QMap& profiles) { CFitProfile* f = new CFitProfile("field_description", eMesgNumFieldDescription); f->addField("developer_data_index", fitUint8Type, eFieldDescriptionDeveloperDataIndex, 0, 0, ""); f->addField("field_definition_number", fitUint8Type, eFieldDescriptionFieldDefinitionNumber, 0, 0, ""); f->addField("fit_base_type_id", fitEnumType, eFieldDescriptionFitBaseTypeId, 0, 0, ""); f->addField("field_name", fitStringType, eFieldDescriptionFieldName, 0, 0, ""); f->addField("array", fitUint8Type, eFieldDescriptionArray, 0, 0, ""); f->addField("components", fitStringType, eFieldDescriptionComponents, 0, 0, ""); f->addField("scale", fitUint8Type, eFieldDescriptionScale, 0, 0, ""); f->addField("offset", fitSint8Type, eFieldDescriptionOffset, 0, 0, ""); f->addField("units", fitStringType, eFieldDescriptionUnits, 0, 0, ""); f->addField("bits", fitStringType, eFieldDescriptionBits, 0, 0, ""); f->addField("accumulate", fitStringType, eFieldDescriptionAccumulate, 0, 0, ""); f->addField("fit_base_unit_id", fitEnumType, eFieldDescriptionFitBaseUnitId, 0, 0, ""); f->addField("native_mesg_num", fitEnumType, eFieldDescriptionNativeMesgNum, 0, 0, ""); f->addField("native_field_num", fitUint8Type, eFieldDescriptionNativeFieldNum, 0, 0, ""); profiles.insert(eMesgNumFieldDescription, f); } void initDeveloperDataId(QMap& profiles) { CFitProfile* f = new CFitProfile("developer_data_id", eMesgNumDeveloperDataId); f->addField("developer_id", fitByteType, eDeveloperDataIdDeveloperId, 0, 0, ""); f->addField("application_id", fitByteType, eDeveloperDataIdApplicationId, 0, 0, ""); f->addField("manufacturer_id", fitEnumType, eDeveloperDataIdManufacturerId, 0, 0, ""); f->addField("developer_data_index", fitUint8Type, eDeveloperDataIdDeveloperDataIndex, 0, 0, ""); f->addField("application_version", fitUint32Type, eDeveloperDataIdApplicationVersion, 0, 0, ""); profiles.insert(eMesgNumDeveloperDataId, f); } // ----------- end generated code ----------- void initExtProfiles(QMap& profiles) { CFitProfile* f = new CFitProfile("location", eMesgNumLocation); f->addField("name", fitStringType, eLocationName, 0, 0, ""); f->addField("timestamp", fitUint32Type, eLocationTimestamp, 0, 0, "s"); f->addField("index", fitUint16Type, eLocationMessageIndex, 0, 0, ""); f->addField("position_lat", fitSint32Type, eLocationPositionLat, 0, 0, "semicircles"); f->addField("position_long", fitSint32Type, eLocationPositionLong, 0, 0, "semicircles"); f->addField("symbol", fitUint32Type, eLocationSymbol, 0, 0, ""); f->addField("altitude", fitUint16Type, eLocationAltitude, 5, 500, "m"); f->addField("???", fitUint16Type, eLocation5, 0, 0, ""); f->addField("comment", fitStringType, eLocationComment, 0, 0, ""); profiles.insert(eMesgNumLocation, f); } void initProfiles(QMap& allProfiles) { initFileId(allProfiles); initFileCreator(allProfiles); initTimestampCorrelation(allProfiles); initSoftware(allProfiles); initSlaveDevice(allProfiles); initCapabilities(allProfiles); initFileCapabilities(allProfiles); initMesgCapabilities(allProfiles); initFieldCapabilities(allProfiles); initDeviceSettings(allProfiles); initUserProfile(allProfiles); initHrmProfile(allProfiles); initSdmProfile(allProfiles); initBikeProfile(allProfiles); initConnectivity(allProfiles); initWatchfaceSettings(allProfiles); initOhrSettings(allProfiles); initZonesTarget(allProfiles); initSport(allProfiles); initHrZone(allProfiles); initSpeedZone(allProfiles); initCadenceZone(allProfiles); initPowerZone(allProfiles); initMetZone(allProfiles); initGoal(allProfiles); initActivity(allProfiles); initSession(allProfiles); initLap(allProfiles); initLength(allProfiles); initRecord(allProfiles); initEvent(allProfiles); initDeviceInfo(allProfiles); initTrainingFile(allProfiles); initHrv(allProfiles); initWeatherConditions(allProfiles); initWeatherAlert(allProfiles); initGpsMetadata(allProfiles); initCameraEvent(allProfiles); initGyroscopeData(allProfiles); initAccelerometerData(allProfiles); initMagnetometerData(allProfiles); initThreeDSensorCalibration(allProfiles); initVideoFrame(allProfiles); initObdiiData(allProfiles); initNmeaSentence(allProfiles); initAviationAttitude(allProfiles); initVideo(allProfiles); initVideoTitle(allProfiles); initVideoDescription(allProfiles); initVideoClip(allProfiles); initCourse(allProfiles); initCoursePoint(allProfiles); initSegmentId(allProfiles); initSegmentLeaderboardEntry(allProfiles); initSegmentPoint(allProfiles); initSegmentLap(allProfiles); initSegmentFile(allProfiles); initWorkout(allProfiles); initWorkoutStep(allProfiles); initSchedule(allProfiles); initTotals(allProfiles); initWeightScale(allProfiles); initBloodPressure(allProfiles); initMonitoringInfo(allProfiles); initMonitoring(allProfiles); initHr(allProfiles); initMemoGlob(allProfiles); initAntChannelId(allProfiles); initAntRx(allProfiles); initAntTx(allProfiles); initExdScreenConfiguration(allProfiles); initExdDataFieldConfiguration(allProfiles); initExdDataConceptConfiguration(allProfiles); initFieldDescription(allProfiles); initDeveloperDataId(allProfiles); initExtProfiles(allProfiles); // invalid profile allProfiles.insert(fitGlobalMesgNrInvalid, new CFitProfile()); } CFitProfileLookup * fitLookupInstance = nullptr; CFitProfileLookup::CFitProfileLookup() { initProfiles(allProfiles); connect(qApp, &QApplication::aboutToQuit, this, &CFitProfileLookup::slotCleanup); } CFitProfileLookup::~CFitProfileLookup() { qDeleteAll(allProfiles); } void CFitProfileLookup::slotCleanup() { fitLookupInstance = nullptr; delete this; } const CFitProfile*CFitProfileLookup::getProfile(quint16 globalMesgNr) { if(fitLookupInstance == nullptr) { fitLookupInstance = new CFitProfileLookup(); } if (fitLookupInstance->allProfiles.contains(globalMesgNr)) { return fitLookupInstance->allProfiles[globalMesgNr]; } return fitLookupInstance->allProfiles[fitGlobalMesgNrInvalid]; } const CFitFieldProfile*CFitProfileLookup::getFieldForProfile(quint16 globalMesgNr, quint8 fieldDefNr) { if(fitLookupInstance == nullptr) { fitLookupInstance = new CFitProfileLookup(); } if (fitLookupInstance->allProfiles.contains(globalMesgNr)) { return fitLookupInstance->allProfiles[globalMesgNr]->getField(fieldDefNr); } return fitLookupInstance->allProfiles[fitGlobalMesgNrInvalid]->getField(fitFieldDefNrInvalid); }qmapshack-1.10.0/src/gis/fit/defs/Profile_Types.csv000644 001750 000144 00000071263 12705713524 023316 0ustar00oeichlerxusers000000 000000 Type Name;Base Type;Value Name;Value;Comment; file;enum;;;; ;;device;1;Read only, single file. Must be in root directory.; ;;settings;2;Read/write, single file. Directory=Settings; ;;sport;3;Read/write, multiple files, file number = sport type. Directory=Sports; ;;activity;4;Read/erase, multiple files. Directory=Activities; ;;workout;5;Read/write/erase, multiple files. Directory=Workouts; ;;course;6;Read/write/erase, multiple files. Directory=Courses; ;;schedules;7;Read/write, single file. Directory=Schedules; ;;weight;9;Read only, single file. Circular buffer. All message definitions at start of file. Directory=Weight; ;;totals;10;Read only, single file. Directory=Totals; ;;goals;11;Read/write, single file. Directory=Goals; ;;blood_pressure;14;Read only. Directory=Blood Pressure; ;;monitoring_a;15;Read only. Directory=Monitoring. File number=sub type.; ;;activity_summary;20;Read/erase, multiple files. Directory=Activities; ;;monitoring_daily;28;; ;;monitoring_b;32;Read only. Directory=Monitoring. File number=identifier; ;;segment;34;Read/write/erase. Multiple Files. Directory=Segments; ;;segment_list;35;Read/write/erase. Single File. Directory=Segments; ;;mfg_range_min;0xF7;0xF7 - 0xFE reserved for manufacturer specific file types; ;;mfg_range_max;0xFE;0xF7 - 0xFE reserved for manufacturer specific file types; ;;;;; mesg_num;uint16;;;; ;;file_id;0;; ;;capabilities;1;; ;;device_settings;2;; ;;user_profile;3;; ;;hrm_profile;4;; ;;sdm_profile;5;; ;;bike_profile;6;; ;;zones_target;7;; ;;hr_zone;8;; ;;power_zone;9;; ;;met_zone;10;; ;;sport;12;; ;;goal;15;; ;;session;18;; ;;lap;19;; ;;record;20;; ;;event;21;; ;;device_info;23;; ;;workout;26;; ;;workout_step;27;; ;;schedule;28;; ;;weight_scale;30;; ;;course;31;; ;;course_point;32;; ;;totals;33;; ;;activity;34;; ;;software;35;; ;;file_capabilities;37;; ;;mesg_capabilities;38;; ;;field_capabilities;39;; ;;file_creator;49;; ;;blood_pressure;51;; ;;speed_zone;53;; ;;monitoring;55;; ;;training_file;72;; ;;hrv;78;; ;;length;101;; ;;monitoring_info;103;; ;;pad;105;; ;;slave_device;106;; ;;cadence_zone;131;; ;;segment_lap;142;; ;;memo_glob;145;; ;;segment_id;148;; ;;segment_leaderboard_entry;149;; ;;segment_point;150;; ;;segment_file;151;; ;;gps_metadata;160;; ;;camera_event;161;; ;;timestamp_correlation;162;; ;;gyroscope_data;164;; ;;accelerometer_data;165;; ;;three_d_sensor_calibration;167;; ;;video_frame;169;; ;;obdii_data;174;; ;;nmea_sentence;177;; ;;aviation_attitude;178;; ;;video;184;; ;;video_title;185;; ;;video_description;186;; ;;video_clip;187;; ;;mfg_range_min;0xFF00;0xFF00 - 0xFFFE reserved for manufacturer specific messages; ;;mfg_range_max;0xFFFE;0xFF00 - 0xFFFE reserved for manufacturer specific messages; ;;;;; checksum;uint8;;;; ;;clear;0;Allows clear of checksum for flash memory where can only write 1 to 0 without erasing sector.; ;;ok;1;Set to mark checksum as valid if computes to invalid values 0 or 0xFF. Checksum can also be set to ok to save encoding computation time.; ;;;;; file_flags;uint8z;;;; ;;read;0x02;; ;;write;0x04;; ;;erase;0x08;; ;;;;; mesg_count;enum;;;; ;;num_per_file;0;; ;;max_per_file;1;; ;;max_per_file_type;2;; ;;;;; date_time;uint32;;;seconds since UTC 00:00 Dec 31 1989; ;;min;0x10000000;if date_time is < 0x10000000 then it is system time (seconds from device power on); ;;;;; local_date_time;uint32;;;seconds since 00:00 Dec 31 1989 in local time zone; ;;min;0x10000000;if date_time is < 0x10000000 then it is system time (seconds from device power on); ;;;;; message_index;uint16;;;; ;;selected;0x8000;message is selected if set; ;;reserved;0x7000;reserved (default 0); ;;mask;0x0FFF;index; ;;;;; device_index;uint8;;;; ;;creator;0;Creator of the file is always device index 0.; ;;;;; gender;enum;;;; ;;female;0;; ;;male;1;; ;;;;; language;enum;;;; ;;english;0;; ;;french;1;; ;;italian;2;; ;;german;3;; ;;spanish;4;; ;;croatian;5;; ;;czech;6;; ;;danish;7;; ;;dutch;8;; ;;finnish;9;; ;;greek;10;; ;;hungarian;11;; ;;norwegian;12;; ;;polish;13;; ;;portuguese;14;; ;;slovakian;15;; ;;slovenian;16;; ;;swedish;17;; ;;russian;18;; ;;turkish;19;; ;;latvian;20;; ;;ukrainian;21;; ;;arabic;22;; ;;farsi;23;; ;;bulgarian;24;; ;;romanian;25;; ;;custom;254;; ;;;;; time_zone;enum;;;; ;;almaty;0;; ;;bangkok;1;; ;;bombay;2;; ;;brasilia;3;; ;;cairo;4;; ;;cape_verde_is;5;; ;;darwin;6;; ;;eniwetok;7;; ;;fiji;8;; ;;hong_kong;9;; ;;islamabad;10;; ;;kabul;11;; ;;magadan;12;; ;;mid_atlantic;13;; ;;moscow;14;; ;;muscat;15;; ;;newfoundland;16;; ;;samoa;17;; ;;sydney;18;; ;;tehran;19;; ;;tokyo;20;; ;;us_alaska;21;; ;;us_atlantic;22;; ;;us_central;23;; ;;us_eastern;24;; ;;us_hawaii;25;; ;;us_mountain;26;; ;;us_pacific;27;; ;;other;28;; ;;auckland;29;; ;;kathmandu;30;; ;;europe_western_wet;31;; ;;europe_central_cet;32;; ;;europe_eastern_eet;33;; ;;jakarta;34;; ;;perth;35;; ;;adelaide;36;; ;;brisbane;37;; ;;tasmania;38;; ;;iceland;39;; ;;amsterdam;40;; ;;athens;41;; ;;barcelona;42;; ;;berlin;43;; ;;brussels;44;; ;;budapest;45;; ;;copenhagen;46;; ;;dublin;47;; ;;helsinki;48;; ;;lisbon;49;; ;;london;50;; ;;madrid;51;; ;;munich;52;; ;;oslo;53;; ;;paris;54;; ;;prague;55;; ;;reykjavik;56;; ;;rome;57;; ;;stockholm;58;; ;;vienna;59;; ;;warsaw;60;; ;;zurich;61;; ;;quebec;62;; ;;ontario;63;; ;;manitoba;64;; ;;saskatchewan;65;; ;;alberta;66;; ;;british_columbia;67;; ;;boise;68;; ;;boston;69;; ;;chicago;70;; ;;dallas;71;; ;;denver;72;; ;;kansas_city;73;; ;;las_vegas;74;; ;;los_angeles;75;; ;;miami;76;; ;;minneapolis;77;; ;;new_york;78;; ;;new_orleans;79;; ;;phoenix;80;; ;;santa_fe;81;; ;;seattle;82;; ;;washington_dc;83;; ;;us_arizona;84;; ;;chita;85;; ;;ekaterinburg;86;; ;;irkutsk;87;; ;;kaliningrad;88;; ;;krasnoyarsk;89;; ;;novosibirsk;90;; ;;petropavlovsk_kamchatskiy;91;; ;;samara;92;; ;;vladivostok;93;; ;;mexico_central;94;; ;;mexico_mountain;95;; ;;mexico_pacific;96;; ;;cape_town;97;; ;;winkhoek;98;; ;;lagos;99;; ;;riyahd;100;; ;;venezuela;101;; ;;australia_lh;102;; ;;santiago;103;; ;;manual;253;; ;;automatic;254;; ;;;;; display_measure;enum;;;; ;;metric;0;; ;;statute;1;; ;;;;; display_heart;enum;;;; ;;bpm;0;; ;;max;1;; ;;reserve;2;; ;;;;; display_power;enum;;;; ;;watts;0;; ;;percent_ftp;1;; ;;;;; display_position;enum;;;; ;;degree;0;dd.dddddd ; ;;degree_minute;1;dddmm.mmm ; ;;degree_minute_second;2;dddmmss ; ;;austrian_grid;3;Austrian Grid (BMN) ; ;;british_grid;4;British National Grid ; ;;dutch_grid;5;Dutch grid system ; ;;hungarian_grid;6;Hungarian grid system ; ;;finnish_grid;7;Finnish grid system Zone3 KKJ27 ; ;;german_grid;8;Gausss Krueger (German) ; ;;icelandic_grid;9;Icelandic Grid ; ;;indonesian_equatorial;10;Indonesian Equatorial LCO ; ;;indonesian_irian;11;Indonesian Irian LCO ; ;;indonesian_southern;12;Indonesian Southern LCO ; ;;india_zone_0;13;India zone 0 ; ;;india_zone_IA;14;India zone IA ; ;;india_zone_IB;15;India zone IB ; ;;india_zone_IIA;16;India zone IIA ; ;;india_zone_IIB;17;India zone IIB ; ;;india_zone_IIIA;18;India zone IIIA ; ;;india_zone_IIIB;19;India zone IIIB ; ;;india_zone_IVA;20;India zone IVA ; ;;india_zone_IVB;21;India zone IVB ; ;;irish_transverse;22;Irish Transverse Mercator ; ;;irish_grid;23;Irish Grid ; ;;loran;24;Loran TD ; ;;maidenhead_grid;25;Maidenhead grid system ; ;;mgrs_grid;26;MGRS grid system ; ;;new_zealand_grid;27;New Zealand grid system ; ;;new_zealand_transverse;28;New Zealand Transverse Mercator ; ;;qatar_grid;29;Qatar National Grid ; ;;modified_swedish_grid;30;Modified RT-90 (Sweden) ; ;;swedish_grid;31;RT-90 (Sweden) ; ;;south_african_grid;32;South African Grid ; ;;swiss_grid;33;Swiss CH-1903 grid ; ;;taiwan_grid;34;Taiwan Grid ; ;;united_states_grid;35;United States National Grid ; ;;utm_ups_grid;36;UTM/UPS grid system ; ;;west_malayan;37;West Malayan RSO ; ;;borneo_rso;38;Borneo RSO; ;;estonian_grid;39;Estonian grid system; ;;latvian_grid;40;Latvian Transverse Mercator; ;;swedish_ref_99_grid;41;Reference Grid 99 TM (Swedish); ;;;;; sport;enum;;;; ;;generic;0;; ;;running;1;; ;;cycling;2;; ;;transition;3;Mulitsport transition; ;;fitness_equipment;4;; ;;swimming;5;; ;;basketball;6;; ;;soccer;7;; ;;tennis;8;; ;;american_football;9;; ;;training;10;; ;;walking;11;; ;;cross_country_skiing;12;; ;;alpine_skiing;13;; ;;snowboarding;14;; ;;rowing;15;; ;;mountaineering;16;; ;;hiking;17;; ;;multisport;18;; ;;paddling;19;; ;;flying;20;; ;;e_biking;21;; ;;motorcycling;22;; ;;boating;23;; ;;driving;24;; ;;golf;25;; ;;hang_gliding;26;; ;;horseback_riding;27;; ;;hunting;28;; ;;fishing;29;; ;;inline_skating;30;; ;;rock_climbing;31;; ;;sailing;32;; ;;ice_skating;33;; ;;sky_diving;34;; ;;snowshoeing;35;; ;;snowmobiling;36;; ;;stand_up_paddleboarding;37;; ;;surfing;38;; ;;wakeboarding;39;; ;;water_skiing;40;; ;;kayaking;41;; ;;rafting;42;; ;;windsurfing;43;; ;;kitesurfing;44;; ;;all;254;All is for goals only to include all sports.; ;;;;; sport_bits_0;uint8z;;;Bit field corresponding to sport enum type (1 << sport).; ;;generic;0x01;; ;;running;0x02;; ;;cycling;0x04;; ;;transition;0x08;Mulitsport transition; ;;fitness_equipment;0x10;; ;;swimming;0x20;; ;;basketball;0x40;; ;;soccer;0x80;; ;;;;; sport_bits_1;uint8z;;;Bit field corresponding to sport enum type (1 << (sport-8)).; ;;tennis;0x01;; ;;american_football;0x02;; ;;training;0x04;; ;;walking;0x08;; ;;cross_country_skiing;0x10;; ;;alpine_skiing;0x20;; ;;snowboarding;0x40;; ;;rowing;0x80;; ;;;;; sport_bits_2;uint8z;;;Bit field corresponding to sport enum type (1 << (sport-16)).; ;;mountaineering;0x01;; ;;hiking;0x02;; ;;multisport;0x04;; ;;paddling;0x08;; ;;flying;0x10;; ;;e_biking;0x20;; ;;motorcycling;0x40;; ;;boating;0x80;; ;;;;; sport_bits_3;uint8z;;;Bit field corresponding to sport enum type (1 << (sport-24)).; ;;driving;0x01;; ;;golf;0x02;; ;;hang_gliding;0x04;; ;;horseback_riding;0x08;; ;;hunting;0x10;; ;;fishing;0x20;; ;;inline_skating;0x40;; ;;rock_climbing;0x80;; ;;;;; sport_bits_4;uint8z;;;Bit field corresponding to sport enum type (1 << (sport-32)).; ;;sailing;0x01;; ;;ice_skating;0x02;; ;;sky_diving;0x04;; ;;snowshoeing;0x08;; ;;snowmobiling;0x10;; ;;stand_up_paddleboarding;0x20;; ;;surfing;0x40;; ;;wakeboarding;0x80;; ;;;;; sport_bits_5;uint8z;;;Bit field corresponding to sport enum type (1 << (sport-40)).; ;;water_skiing;0x01;; ;;kayaking;0x02;; ;;rafting;0x04;; ;;windsurfing;0x08;; ;;kitesurfing;0x10;; ;;;;; sub_sport;enum;;;; ;;generic;0;; ;;treadmill;1;Run/Fitness Equipment; ;;street;2;Run; ;;trail;3;Run; ;;track;4;Run; ;;spin;5;Cycling; ;;indoor_cycling;6;Cycling/Fitness Equipment; ;;road;7;Cycling; ;;mountain;8;Cycling; ;;downhill;9;Cycling; ;;recumbent;10;Cycling; ;;cyclocross;11;Cycling; ;;hand_cycling;12;Cycling; ;;track_cycling;13;Cycling; ;;indoor_rowing;14;Fitness Equipment; ;;elliptical;15;Fitness Equipment; ;;stair_climbing;16;Fitness Equipment; ;;lap_swimming;17;Swimming; ;;open_water;18;Swimming; ;;flexibility_training;19;Training; ;;strength_training;20;Training; ;;warm_up;21;Tennis; ;;match;22;Tennis; ;;exercise;23;Tennis; ;;challenge;24;Tennis; ;;indoor_skiing;25;Fitness Equipment; ;;cardio_training;26;Training; ;;indoor_walking;27;Walking/Fitness Equipment; ;;e_bike_fitness;28;E-Biking; ;;bmx;29;Cycling ; ;;casual_walking;30;Walking; ;;speed_walking;31;Walking; ;;bike_to_run_transition;32;Transition; ;;run_to_bike_transition;33;Transition; ;;swim_to_bike_transition;34;Transition; ;;atv;35;Motorcycling; ;;motocross;36;Motorcycling; ;;backcountry;37;Alpine Skiing/Snowboarding; ;;resort;38;Alpine Skiing/Snowboarding; ;;rc_drone;39;Flying; ;;wingsuit;40;Flying; ;;whitewater;41;Kayaking/Rafting; ;;all;254;; ;;;;; sport_event;enum;;;; ;;uncategorized;0;; ;;geocaching;1;; ;;fitness;2;; ;;recreation;3;; ;;race;4;; ;;special_event;5;; ;;training;6;; ;;transportation;7;; ;;touring;8;; ;;;;; activity;enum;;;; ;;manual;0;; ;;auto_multi_sport;1;; ;;;;; intensity;enum;;;; ;;active;0;; ;;rest;1;; ;;warmup;2;; ;;cooldown;3;; ;;;;; session_trigger;enum;;;; ;;activity_end;0;; ;;manual;1;User changed sport.; ;;auto_multi_sport;2;Auto multi-sport feature is enabled and user pressed lap button to advance session.; ;;fitness_equipment;3;Auto sport change caused by user linking to fitness equipment.; ;;;;; autolap_trigger;enum;;;; ;;time;0;; ;;distance;1;; ;;position_start;2;; ;;position_lap;3;; ;;position_waypoint;4;; ;;position_marked;5;; ;;off;6;; ;;;;; lap_trigger;enum;;;; ;;manual;0;; ;;time;1;; ;;distance;2;; ;;position_start;3;; ;;position_lap;4;; ;;position_waypoint;5;; ;;position_marked;6;; ;;session_end;7;; ;;fitness_equipment;8;; ;;;;; event;enum;;;; ;;timer;0;Group 0. Start / stop_all; ;;workout;3;start / stop; ;;workout_step;4;Start at beginning of workout. Stop at end of each step.; ;;power_down;5;stop_all group 0; ;;power_up;6;stop_all group 0; ;;off_course;7;start / stop group 0; ;;session;8;Stop at end of each session.; ;;lap;9;Stop at end of each lap.; ;;course_point;10;marker; ;;battery;11;marker; ;;virtual_partner_pace;12;Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled.; ;;hr_high_alert;13;Group 0. Start / stop when in alert condition.; ;;hr_low_alert;14;Group 0. Start / stop when in alert condition.; ;;speed_high_alert;15;Group 0. Start / stop when in alert condition.; ;;speed_low_alert;16;Group 0. Start / stop when in alert condition.; ;;cad_high_alert;17;Group 0. Start / stop when in alert condition.; ;;cad_low_alert;18;Group 0. Start / stop when in alert condition.; ;;power_high_alert;19;Group 0. Start / stop when in alert condition.; ;;power_low_alert;20;Group 0. Start / stop when in alert condition.; ;;recovery_hr;21;marker; ;;battery_low;22;marker; ;;time_duration_alert;23;Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.; ;;distance_duration_alert;24;Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.; ;;calorie_duration_alert;25;Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.; ;;activity;26;Group 1.. Stop at end of activity.; ;;fitness_equipment;27;marker; ;;length;28;Stop at end of each length.; ;;user_marker;32;marker; ;;sport_point;33;marker; ;;calibration;36;start/stop/marker; ;;front_gear_change;42;marker; ;;rear_gear_change;43;marker; ;;rider_position_change;44;marker; ;;elev_high_alert;45;Group 0. Start / stop when in alert condition.; ;;elev_low_alert;46;Group 0. Start / stop when in alert condition.; ;;comm_timeout;47;marker; ;;;;; event_type;enum;;;; ;;start;0;; ;;stop;1;; ;;consecutive_depreciated;2;; ;;marker;3;; ;;stop_all;4;; ;;begin_depreciated;5;; ;;end_depreciated;6;; ;;end_all_depreciated;7;; ;;stop_disable;8;; ;;stop_disable_all;9;; ;;;;; timer_trigger;enum;;;timer event data; ;;manual;0;; ;;auto;1;; ;;fitness_equipment;2;; ;;;;; fitness_equipment_state;enum;;;fitness equipment event data; ;;ready;0;; ;;in_use;1;; ;;paused;2;; ;;unknown;3;lost connection to fitness equipment; ;;;;; activity_class;enum;;;; ;;level;0x7F;0 to 100; ;;level_max;100;; ;;athlete;0x80;; ;;;;; hr_zone_calc;enum;;;; ;;custom;0;; ;;percent_max_hr;1;; ;;percent_hrr;2;; ;;;;; pwr_zone_calc;enum;;;; ;;custom;0;; ;;percent_ftp;1;; ;;;;; wkt_step_duration;enum;;;; ;;time;0;; ;;distance;1;; ;;hr_less_than;2;; ;;hr_greater_than;3;; ;;calories;4;; ;;open;5;; ;;repeat_until_steps_cmplt;6;; ;;repeat_until_time;7;; ;;repeat_until_distance;8;; ;;repeat_until_calories;9;; ;;repeat_until_hr_less_than;10;; ;;repeat_until_hr_greater_than;11;; ;;repeat_until_power_less_than;12;; ;;repeat_until_power_greater_than;13;; ;;power_less_than;14;; ;;power_greater_than;15;; ;;repetition_time;28;; ;;;;; wkt_step_target;enum;;;; ;;speed;0;; ;;heart_rate;1;; ;;open;2;; ;;cadence;3;; ;;power;4;; ;;grade;5;; ;;resistance;6;; ;;;;; goal;enum;;;; ;;time;0;; ;;distance;1;; ;;calories;2;; ;;frequency;3;; ;;steps;4;; ;;;;; goal_recurrence;enum;;;; ;;off;0;; ;;daily;1;; ;;weekly;2;; ;;monthly;3;; ;;yearly;4;; ;;custom;5;; ;;;;; schedule;enum;;;; ;;workout;0;; ;;course;1;; ;;;;; course_point;enum;;;; ;;generic;0;; ;;summit;1;; ;;valley;2;; ;;water;3;; ;;food;4;; ;;danger;5;; ;;left;6;; ;;right;7;; ;;straight;8;; ;;first_aid;9;; ;;fourth_category;10;; ;;third_category;11;; ;;second_category;12;; ;;first_category;13;; ;;hors_category;14;; ;;sprint;15;; ;;left_fork;16;; ;;right_fork;17;; ;;middle_fork;18;; ;;slight_left;19;; ;;sharp_left;20;; ;;slight_right;21;; ;;sharp_right;22;; ;;u_turn;23;; ;;;;; manufacturer;uint16;;;; ;;garmin;1;; ;;garmin_fr405_antfs;2;Do not use. Used by FR405 for ANTFS man id.; ;;zephyr;3;; ;;dayton;4;; ;;idt;5;; ;;srm;6;; ;;quarq;7;; ;;ibike;8;; ;;saris;9;; ;;spark_hk;10;; ;;tanita;11;; ;;echowell;12;; ;;dynastream_oem;13;; ;;nautilus;14;; ;;dynastream;15;; ;;timex;16;; ;;metrigear;17;; ;;xelic;18;; ;;beurer;19;; ;;cardiosport;20;; ;;a_and_d;21;; ;;hmm;22;; ;;suunto;23;; ;;thita_elektronik;24;; ;;gpulse;25;; ;;clean_mobile;26;; ;;pedal_brain;27;; ;;peaksware;28;; ;;saxonar;29;; ;;lemond_fitness;30;; ;;dexcom;31;; ;;wahoo_fitness;32;; ;;octane_fitness;33;; ;;archinoetics;34;; ;;the_hurt_box;35;; ;;citizen_systems;36;; ;;magellan;37;; ;;osynce;38;; ;;holux;39;; ;;concept2;40;; ;;one_giant_leap;42;; ;;ace_sensor;43;; ;;brim_brothers;44;; ;;xplova;45;; ;;perception_digital;46;; ;;bf1systems;47;; ;;pioneer;48;; ;;spantec;49;; ;;metalogics;50;; ;;4iiiis;51;; ;;seiko_epson;52;; ;;seiko_epson_oem;53;; ;;ifor_powell;54;; ;;maxwell_guider;55;; ;;star_trac;56;; ;;breakaway;57;; ;;alatech_technology_ltd;58;; ;;mio_technology_europe;59;; ;;rotor;60;; ;;geonaute;61;; ;;id_bike;62;; ;;specialized;63;; ;;wtek;64;; ;;physical_enterprises;65;; ;;north_pole_engineering;66;; ;;bkool;67;; ;;cateye;68;; ;;stages_cycling;69;; ;;sigmasport;70;; ;;tomtom;71;; ;;peripedal;72;; ;;wattbike;73;; ;;moxy;76;; ;;ciclosport;77;; ;;powerbahn;78;; ;;acorn_projects_aps;79;; ;;lifebeam;80;; ;;bontrager;81;; ;;wellgo;82;; ;;scosche;83;; ;;magura;84;; ;;woodway;85;; ;;elite;86;; ;;nielsen_kellerman;87;; ;;dk_city;88;; ;;tacx;89;; ;;direction_technology;90;; ;;magtonic;91;; ;;1partcarbon;92;; ;;inside_ride_technologies;93;; ;;sound_of_motion;94;; ;;stryd;95;; ;;icg;96;Indoorcycling Group; ;;mi_pulse;97;; ;;bsx_athletics;98;; ;;look;99;; ;;development;255;; ;;healthandlife;257;; ;;lezyne;258;; ;;scribe_labs;259;; ;;zwift;260;; ;;watteam;261;; ;;recon;262;; ;;favero_electronics;263;; ;;dynovelo;264;; ;;strava;265;; ;;actigraphcorp;5759;; ;;;;; garmin_product;uint16;;;; ;;hrm1;1;; ;;axh01;2;AXH01 HRM chipset; ;;axb01;3;; ;;axb02;4;; ;;hrm2ss;5;; ;;dsi_alf02;6;; ;;hrm3ss;7;; ;;hrm_run_single_byte_product_id;8;hrm_run model for HRM ANT+ messaging; ;;bsm;9;BSM model for ANT+ messaging; ;;bcm;10;BCM model for ANT+ messaging; ;;axs01;11;AXS01 HRM Bike Chipset model for ANT+ messaging; ;;hrm_tri_single_byte_product_id;12;hrm_tri model for HRM ANT+ messaging; ;;fr225_single_byte_product_id;14;fr225 model for HRM ANT+ messaging; ;;fr301_china;473;; ;;fr301_japan;474;; ;;fr301_korea;475;; ;;fr301_taiwan;494;; ;;fr405;717;Forerunner 405; ;;fr50;782;Forerunner 50; ;;fr405_japan;987;; ;;fr60;988;Forerunner 60; ;;dsi_alf01;1011;; ;;fr310xt;1018;Forerunner 310; ;;edge500;1036;; ;;fr110;1124;Forerunner 110; ;;edge800;1169;; ;;edge500_taiwan;1199;; ;;edge500_japan;1213;; ;;chirp;1253;; ;;fr110_japan;1274;; ;;edge200;1325;; ;;fr910xt;1328;; ;;edge800_taiwan;1333;; ;;edge800_japan;1334;; ;;alf04;1341;; ;;fr610;1345;; ;;fr210_japan;1360;; ;;vector_ss;1380;; ;;vector_cp;1381;; ;;edge800_china;1386;; ;;edge500_china;1387;; ;;fr610_japan;1410;; ;;edge500_korea;1422;; ;;fr70;1436;; ;;fr310xt_4t;1446;; ;;amx;1461;; ;;fr10;1482;; ;;edge800_korea;1497;; ;;swim;1499;; ;;fr910xt_china;1537;; ;;fenix;1551;; ;;edge200_taiwan;1555;; ;;edge510;1561;; ;;edge810;1567;; ;;tempe;1570;; ;;fr910xt_japan;1600;; ;;fr620;1623;; ;;fr220;1632;; ;;fr910xt_korea;1664;; ;;fr10_japan;1688;; ;;edge810_japan;1721;; ;;virb_elite;1735;; ;;edge_touring;1736;Also Edge Touring Plus; ;;edge510_japan;1742;; ;;hrm_tri;1743;; ;;hrm_run;1752;; ;;fr920xt;1765;; ;;edge510_asia;1821;; ;;edge810_china;1822;; ;;edge810_taiwan;1823;; ;;edge1000;1836;; ;;vivo_fit;1837;; ;;virb_remote;1853;; ;;vivo_ki;1885;; ;;fr15;1903;; ;;vivo_active;1907;; ;;edge510_korea;1918;; ;;fr620_japan;1928;; ;;fr620_china;1929;; ;;fr220_japan;1930;; ;;fr220_china;1931;; ;;approach_s6;1936;; ;;vivo_smart;1956;; ;;fenix2;1967;; ;;epix;1988;; ;;fenix3;2050;; ;;edge1000_taiwan;2052;; ;;edge1000_japan;2053;; ;;fr15_japan;2061;; ;;edge520;2067;; ;;edge1000_china;2070;; ;;fr620_russia;2072;; ;;fr220_russia;2073;; ;;vector_s;2079;; ;;edge1000_korea;2100;; ;;fr920xt_taiwan;2130;; ;;fr920xt_china;2131;; ;;fr920xt_japan;2132;; ;;virbx;2134;; ;;vivo_smart_apac;2135;; ;;etrex_touch;2140;; ;;edge25;2147;; ;;vivo_fit2;2150;; ;;fr225;2153;; ;;vivo_active_apac;2160;; ;;vector_2;2161;; ;;vector_2s;2162;; ;;virbxe;2172;; ;;fr620_taiwan;2173;; ;;fr220_taiwan;2174;; ;;fenix3_china;2188;; ;;fenix3_twn;2189;; ;;varia_headlight;2192;; ;;varia_taillight_old;2193;; ;;fr225_asia;2219;; ;;varia_radar_taillight;2225;; ;;varia_radar_display;2226;; ;;edge20;2238;; ;;d2_bravo;2262;; ;;varia_remote;2276;; ;;sdm4;10007;SDM4 footpod; ;;edge_remote;10014;; ;;training_center;20119;; ;;android_antplus_plugin;65532;; ;;connect;65534;Garmin Connect website; ;;;;; antplus_device_type;uint8;;;; ;;antfs;1;; ;;bike_power;11;; ;;environment_sensor_legacy;12;; ;;multi_sport_speed_distance;15;; ;;control;16;; ;;fitness_equipment;17;; ;;blood_pressure;18;; ;;geocache_node;19;; ;;light_electric_vehicle;20;; ;;env_sensor;25;; ;;racquet;26;; ;;weight_scale;119;; ;;heart_rate;120;; ;;bike_speed_cadence;121;; ;;bike_cadence;122;; ;;bike_speed;123;; ;;stride_speed_distance;124;; ;;;;; ant_network;enum;;;; ;;public;0;; ;;antplus;1;; ;;antfs;2;; ;;private;3;; ;;;;; workout_capabilities;uint32z;;;; ;;interval;0x00000001;; ;;custom;0x00000002;; ;;fitness_equipment;0x00000004;; ;;firstbeat;0x00000008;; ;;new_leaf;0x00000010;; ;;tcx;0x00000020;For backwards compatibility. Watch should add missing id fields then clear flag.; ;;speed;0x00000080;Speed source required for workout step.; ;;heart_rate;0x00000100;Heart rate source required for workout step.; ;;distance;0x00000200;Distance source required for workout step.; ;;cadence;0x00000400;Cadence source required for workout step.; ;;power;0x00000800;Power source required for workout step.; ;;grade;0x00001000;Grade source required for workout step.; ;;resistance;0x00002000;Resistance source required for workout step.; ;;protected;0x00004000;; ;;;;; battery_status;uint8;;;; ;;new;1;; ;;good;2;; ;;ok;3;; ;;low;4;; ;;critical;5;; ;;unknown;7;; ;;;;; hr_type;enum;;;; ;;normal;0;; ;;irregular;1;; ;;;;; course_capabilities;uint32z;;;; ;;processed;0x00000001;; ;;valid;0x00000002;; ;;time;0x00000004;; ;;distance;0x00000008;; ;;position;0x00000010;; ;;heart_rate;0x00000020;; ;;power;0x00000040;; ;;cadence;0x00000080;; ;;training;0x00000100;; ;;navigation;0x00000200;; ;;bikeway;0x00000400;; ;;;;; weight;uint16;;;; ;;calculating;0xFFFE;; ;;;;; workout_hr;uint32;;;"0 - 100 indicates% of maz hr; >100 indicates bpm (255 max) plus 100"; ;;bpm_offset;100;; ;;;;; workout_power;uint32;;;"0 - 1000 indicates % of functional threshold power; >1000 indicates watts plus 1000."; ;;watts_offset;1000;; ;;;;; bp_status;enum;;;; ;;no_error;0;; ;;error_incomplete_data;1;; ;;error_no_measurement;2;; ;;error_data_out_of_range;3;; ;;error_irregular_heart_rate;4;; ;;;;; user_local_id;uint16;;;; ;;local_min;0x0000;; ;;local_max;0x000F;; ;;stationary_min;0x0010;; ;;stationary_max;0x00FF;; ;;portable_min;0x0100;; ;;portable_max;0xFFFE;; ;;;;; swim_stroke;enum;;;; ;;freestyle;0;; ;;backstroke;1;; ;;breaststroke;2;; ;;butterfly;3;; ;;drill;4;; ;;mixed;5;; ;;im;6;IM is a mixed interval containing the same number of lengths for each of: Butterfly, Backstroke, Breaststroke, Freestyle, swam in that order.; ;;;;; activity_type;enum;;;; ;;generic;0;; ;;running;1;; ;;cycling;2;; ;;transition;3;Mulitsport transition; ;;fitness_equipment;4;; ;;swimming;5;; ;;walking;6;; ;;all;254;All is for goals only to include all sports.; ;;;;; activity_subtype;enum;;;; ;;generic;0;; ;;treadmill;1;Run; ;;street;2;Run; ;;trail;3;Run; ;;track;4;Run; ;;spin;5;Cycling; ;;indoor_cycling;6;Cycling; ;;road;7;Cycling; ;;mountain;8;Cycling; ;;downhill;9;Cycling; ;;recumbent;10;Cycling; ;;cyclocross;11;Cycling; ;;hand_cycling;12;Cycling; ;;track_cycling;13;Cycling; ;;indoor_rowing;14;Fitness Equipment; ;;elliptical;15;Fitness Equipment; ;;stair_climbing;16;Fitness Equipment; ;;lap_swimming;17;Swimming; ;;open_water;18;Swimming; ;;all;254;; ;;;;; activity_level;enum;;;; ;;low;0;; ;;medium;1;; ;;high;2;; ;;;;; left_right_balance;uint8;;;; ;;mask;0x7F;% contribution; ;;right;0x80;data corresponds to right if set, otherwise unknown; ;;;;; left_right_balance_100;uint16;;;; ;;mask;0x3FFF;% contribution scaled by 100; ;;right;0x8000;data corresponds to right if set, otherwise unknown; ;;;;; length_type;enum;;;; ;;idle;0;Rest period. Length with no strokes; ;;active;1;Length with strokes.; ;;;;; connectivity_capabilities;uint32z;;;; ;;bluetooth;0x00000001;; ;;bluetooth_le;0x00000002;; ;;ant;0x00000004;; ;;activity_upload;0x00000008;; ;;course_download;0x00000010;; ;;workout_download;0x00000020;; ;;live_track;0x00000040;; ;;weather_conditions;0x00000080;; ;;weather_alerts;0x00000100;; ;;gps_ephemeris_download;0x00000200;; ;;explicit_archive;0x00000400;; ;;setup_incomplete;0x00000800;; ;;continue_sync_after_software_update;0x00001000;; ;;connect_iq_app_download;0x00002000;; ;;;;; stroke_type;enum;;;; ;;no_event;0;; ;;other;1;stroke was detected but cannot be identified; ;;serve;2;; ;;forehand;3;; ;;backhand;4;; ;;smash;5;; ;;;;; body_location;enum;;;; ;;left_leg;0;; ;;left_calf;1;; ;;left_shin;2;; ;;left_hamstring;3;; ;;left_quad;4;; ;;left_glute;5;; ;;right_leg;6;; ;;right_calf;7;; ;;right_shin;8;; ;;right_hamstring;9;; ;;right_quad;10;; ;;right_glute;11;; ;;torso_back;12;; ;;left_lower_back;13;; ;;left_upper_back;14;; ;;right_lower_back;15;; ;;right_upper_back;16;; ;;torso_front;17;; ;;left_abdomen;18;; ;;left_chest;19;; ;;right_abdomen;20;; ;;right_chest;21;; ;;left_arm;22;; ;;left_shoulder;23;; ;;left_bicep;24;; ;;left_tricep;25;; ;;left_brachioradialis;26;Left anterior forearm; ;;left_forearm_extensors;27;Left posterior forearm; ;;right_arm;28;; ;;right_shoulder;29;; ;;right_bicep;30;; ;;right_tricep;31;; ;;right_brachioradialis;32;Right anterior forearm; ;;right_forearm_extensors;33;Right posterior forearm; ;;neck;34;; ;;throat;35;; ;;;;; segment_lap_status;enum;;;; ;;end;0;; ;;fail;1;; ;;;;; segment_leaderboard_type;enum;;;; ;;overall;0;; ;;personal_best;1;; ;;connections;2;; ;;group;3;; ;;challenger;4;; ;;kom;5;; ;;qom;6;; ;;pr;7;; ;;goal;8;; ;;rival;9;; ;;club_leader;10;; ;;;;; segment_delete_status;enum;;;; ;;do_not_delete;0;; ;;delete_one;1;; ;;delete_all;2;; ;;;;; segment_selection_type;enum;;;; ;;starred;0;; ;;suggested;1;; ;;;;; source_type;enum;;;; ;;ant;0;External device connected with ANT; ;;antplus;1;External device connected with ANT+; ;;bluetooth;2;External device connected with BT; ;;bluetooth_low_energy;3;External device connected with BLE; ;;wifi;4;External device connected with Wifi; ;;local;5;Onboard device; ;;;;; rider_position_type;enum;;;; ;;seated;0;; ;;standing;1;; ;;;;; power_phase_type;enum;;;; ;;power_phase_start_angle;0;; ;;power_phase_end_angle;1;; ;;power_phase_arc_length;2;; ;;power_phase_center;3;; ;;;;; camera_event_type;enum;;;; ;;video_start;0;Start of video recording; ;;video_split;1;Mark of video file split (end of one file, beginning of the other); ;;video_end;2;End of video recording; ;;photo_taken;3;Still photo taken; ;;video_second_stream_start;4;; ;;video_second_stream_split;5;; ;;video_second_stream_end;6;; ;;video_split_start;7;Mark of video file split start; ;;video_second_stream_split_start;8;; ;;;;; sensor_type;enum;;;; ;;accelerometer;0;; ;;gyroscope;1;; ;;compass;2;; ;;;;; comm_timeout_type;uint16;;;; ;;wildcard_pairing_timeout;0;Timeout pairing to any device; ;;pairing_timeout;1;Timeout pairing to previously paired device; ;;connection_lost;2;Temporary loss of communications; ;;connection_timeout;3;Connection closed due to extended bad communications; camera_orientation_type;enum;;;; ;;camera_orientation_0;0;; ;;camera_orientation_90;1;; ;;camera_orientation_180;2;; ;;camera_orientation_270;3;; ;;;;; attitude_stage;enum;;;; ;;failed;0;; ;;aligning;1;; ;;degraded;2;; ;;valid;3;; ;;;;; attitude_validity;uint16;;;; ;;track_angle_heading_valid;0x0001;; ;;pitch_valid;0x0002;; ;;roll_valid;0x0004;; ;;lateral_body_accel_valid;0x0008;; ;;normal_body_accel_valid;0x0010;; ;;turn_rate_valid;0x0020;; ;;hw_fail;0x0040;; ;;mag_invalid;0x0080;; ;;no_gps;0x0100;; ;;gps_invalid;0x0200;; ;;solution_coasting;0x0400;; ;;true_track_angle;0x0800;; ;;magnetic_heading;0x1000;; ;;;;;qmapshack-1.10.0/src/gis/fit/defs/CFitFieldProfile.h000644 001750 000144 00000010055 13216234143 023261 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELDPROFILE_H #define CFITFIELDPROFILE_H #include class CFitProfile; class CFitSubfieldProfile; class CFitComponentfieldProfile; class CFitBaseType; typedef enum { eFieldTypeFit = 0, eFieldTypeDevelopment = 1, } field_type_e; class CFitFieldProfile { public: CFitFieldProfile(); CFitFieldProfile(const CFitFieldProfile& copy); CFitFieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, field_type_e fieldType = eFieldTypeFit); virtual ~CFitFieldProfile(); void addSubfield(CFitSubfieldProfile* subfield); void addComponent(CFitComponentfieldProfile* component); void addComponent(int subfieldIndex, CFitComponentfieldProfile* field); bool hasSubfields() const; bool hasComponents() const; virtual QString getName() const; virtual quint8 getFieldDefNum() const; virtual qreal getScale() const; virtual qint16 getOffset() const; virtual bool hasScaleAndOffset() const; virtual QString getUnits() const; virtual const CFitBaseType& getBaseType() const; virtual QString getTyp() const { return "field"; } const QList getSubfields() const; QList getComponents() const; const CFitProfile* getProfile() const; field_type_e getFieldType() const { return fieldType; } QString fieldProfileInfo(); private: QString name; quint8 fieldDefNr; qreal scale; qint16 offset; QString units; field_type_e fieldType; const CFitBaseType* baseType; CFitProfile* profile; QList subfields; QList components; }; class CFitSubfieldProfile final : public CFitFieldProfile { public: CFitSubfieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 subRefFieldDefNr, quint8 subRefFieldValue); CFitSubfieldProfile(const CFitSubfieldProfile& copy); CFitSubfieldProfile() : CFitFieldProfile(), refFieldDefNr(0), refFieldValue(0) {} virtual ~CFitSubfieldProfile() {} QString getTyp() const override { return "dynamic"; } quint8 getReferencedFieldDefNr() const; quint8 getReferencedFieldValue() const; private: quint8 refFieldDefNr; quint8 refFieldValue; }; class CFitComponentfieldProfile final : public CFitFieldProfile { public: CFitComponentfieldProfile(CFitProfile* parent, QString name, const CFitBaseType& baseType, quint8 fieldDefNr, qreal scale, qint16 offset, QString units, quint8 componentFieldDefNr, quint32 bits); CFitComponentfieldProfile(const CFitComponentfieldProfile& copy); CFitComponentfieldProfile() : CFitFieldProfile(), nrOfBits(0), componentFieldDefNr(0) {} virtual ~CFitComponentfieldProfile() {} QString getName() const override; quint8 getFieldDefNum() const override; const CFitBaseType& getBaseType() const override; QString getTyp() const override { return "component"; } quint32 getBits() const; quint32 getBitmask() const; private: quint32 nrOfBits; quint8 componentFieldDefNr; }; #endif //CFITFIELDPROFILE_H qmapshack-1.10.0/src/gis/fit/serialization.cpp000644 001750 000144 00000025517 13216234140 022444 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/defs/fit_enums.h" #include "gis/fit/defs/fit_fields.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" static const qreal degrees = 180.0; static const qreal twoPow31 = qPow(2, 31); static const uint sec1970to1990 = QDateTime(QDate(1989, 12, 31), QTime(0, 0, 0),Qt::UTC).toTime_t(); /** * converts the semicircle to the WGS-84 geoids (Degrees Decimal Minutes (DDD MM.MMM)). * North latitude +, South latitude - * East longitude +, West longitude - * return: the given semicircle value converted to degree. */ static qreal toDegree(qint32 semicircles) { return semicircles * (degrees / twoPow31); } /** timestamp: seconds since UTC 00:00 Dec 31 1989 */ static QDateTime toDateTime(quint32 timestamp) { QDateTime dateTime; dateTime.setTime_t(sec1970to1990 + timestamp); return dateTime; } static QString dateTimeAsString(quint32 timestamp) { QDateTime dateTime = toDateTime(timestamp); return IUnit::datetime2string(dateTime, true); } template static void readKnownExtensions(T &exts, const CFitMessage &mesg) { // see gis/trk/CKnownExtension for the keys of the extensions if(mesg.isFieldValueValid(eRecordHeartRate)) { exts["gpxtpx:TrackPointExtension|gpxtpx:hr"] = mesg.getFieldValue(eRecordHeartRate); } if(mesg.isFieldValueValid(eRecordTemperature)) { exts["gpxtpx:TrackPointExtension|gpxtpx:atemp"] = mesg.getFieldValue(eRecordTemperature); } if(mesg.isFieldValueValid(eRecordCadence)) { exts["gpxtpx:TrackPointExtension|gpxtpx:cad"] = mesg.getFieldValue(eRecordCadence); } if(mesg.isFieldValueValid(eRecordSpeed)) { const QVariant &speed = mesg.getFieldValue(eRecordSpeed); exts["speed"] = speed.toDouble() / 1000.; } } static bool readFitRecord(const CFitMessage &mesg, IGisItem::wpt_t &pt) { if(mesg.isFieldValueValid(eRecordPositionLong) && mesg.isFieldValueValid(eRecordPositionLat)) { pt.lon = toDegree(mesg.getFieldValue(eRecordPositionLong).toInt()); pt.lat = toDegree(mesg.getFieldValue(eRecordPositionLat).toInt()); // QVariant.toInt() does not convert double to int but return 0. pt.ele = (int) mesg.getFieldValue(eRecordEnhancedAltitude).toDouble(); pt.time = toDateTime(mesg.getFieldValue(eRecordTimestamp).toUInt()); readKnownExtensions(pt.extensions, mesg); return true; } return false; } static bool readFitRecord(const CFitMessage &mesg, CTrackData::trkpt_t &pt) { if(readFitRecord(mesg, (IGisItem::wpt_t &)pt)) { pt.speed = mesg.getFieldValue(eRecordSpeed).toDouble(); readKnownExtensions(pt.extensions, mesg); pt.extensions.squeeze(); return true; } return false; } static void readFitLocation(const CFitMessage &mesg, IGisItem::wpt_t &wpt) { if(mesg.isFieldValueValid(eLocationName)) { wpt.name = mesg.getFieldValue(eLocationName).toString(); } if(mesg.isFieldValueValid(eLocationTimestamp)) { wpt.time = toDateTime(mesg.getFieldValue(eLocationTimestamp).toUInt()); } if(mesg.isFieldValueValid(eLocationPositionLong) && mesg.isFieldValueValid(eLocationPositionLat)) { wpt.lon = toDegree(mesg.getFieldValue(eLocationPositionLong).toInt()); wpt.lat = toDegree(mesg.getFieldValue(eLocationPositionLat).toInt()); } if(mesg.isFieldValueValid(eLocationAltitude)) { wpt.ele = mesg.getFieldValue(eLocationAltitude).toInt(); } if(mesg.isFieldValueValid(eLocationComment)) { wpt.desc = mesg.getFieldValue(eLocationComment).toString(); } wpt.sym = "Default"; } QString wptIconNames[26] { "Default", "Summit", "Valley", "Water", "Food", "Danger", "Left", "Right", "Straight", "FirstAid", "4thCategory", "3rdCategory", "2ndCategory", "1stCategory", "HorsCategory", "Sprint" , "LeftFork", "RightFork", "MiddleFork", "SlightLeft", "SharpLeft", "SlightRight", "SharpRight", "UTurn", "Start", "End" }; static void readFitCoursePoint(const CFitMessage &mesg, IGisItem::wpt_t &wpt) { if(mesg.isFieldValueValid(eCoursePointName)) { wpt.name = mesg.getFieldValue(eCoursePointName).toString(); } if(mesg.isFieldValueValid(eCoursePointTimestamp)) { wpt.time = toDateTime(mesg.getFieldValue(eCoursePointTimestamp).toUInt()); } if(mesg.isFieldValueValid(eCoursePointPositionLong) && mesg.isFieldValueValid(eCoursePointPositionLat)) { wpt.lon = toDegree(mesg.getFieldValue(eCoursePointPositionLong).toInt()); wpt.lat = toDegree(mesg.getFieldValue(eCoursePointPositionLat).toInt()); } if (mesg.isFieldValueValid(eCoursePointType)) { wpt.sym = wptIconNames[mesg.getFieldValue(eCoursePointType).toInt()]; } } static bool readFitSegmentPoint(const CFitMessage &mesg, CTrackData::trkpt_t &pt, quint32 timeCreated) { if(mesg.isFieldValueValid(eSegmentPointPositionLong) && mesg.isFieldValueValid(eSegmentPointPositionLat)) { pt.lon = toDegree(mesg.getFieldValue(eSegmentPointPositionLong).toInt()); pt.lat = toDegree(mesg.getFieldValue(eSegmentPointPositionLat).toInt()); pt.ele = (int) mesg.getFieldValue(eSegmentPointAltitude).toDouble(); // sum with file_id time_created pt.time = toDateTime(timeCreated + mesg.getFieldValue(eSegmentPointLeaderTime).toUInt()); return true; } return false; } static QString evaluateTrkName(CFitStream &stream) { const CFitMessage& segmentIdMesg = stream.firstMesgOf(eMesgNumSegmentId); if(segmentIdMesg.isFieldValueValid(eSegmentIdName)) { return segmentIdMesg.getFieldValue(eSegmentIdName).toString(); } const CFitMessage& courseMesg = stream.firstMesgOf(eMesgNumCourse); if(courseMesg.isFieldValueValid(eCourseName)) { // first place: take the course name // course files can have a name but activities don't. return courseMesg.getFieldValue(eCourseName).toString(); } const CFitMessage& sessionMesg = stream.firstMesgOf(eMesgNumSession); if(sessionMesg.isFieldValueValid(eSessionStartTime)) { // second place: take the session start time return dateTimeAsString(sessionMesg.getFieldValue(eSessionStartTime).toUInt()); } const CFitMessage& fileidMesg = stream.firstMesgOf(eMesgNumFileId); if(fileidMesg.isFieldValueValid(eFileIdTimeCreated)) { // third place: take the file created timestamp // (is typically the same as the start time with a offset of several seconds) return dateTimeAsString(fileidMesg.getFieldValue(eFileIdTimeCreated).toUInt()); } // fourth place: take the filename of the fit file return QFileInfo(stream.getFileName()).completeBaseName().replace("_", " "); } void CGisItemTrk::readTrkFromFit(CFitStream &stream) { trk.name = evaluateTrkName(stream); quint32 timeCreated = 0; const CFitMessage& fileIdMesg = stream.firstMesgOf(eMesgNumFileId); if(fileIdMesg.isFieldValueValid(eFileIdTimeCreated)) { timeCreated = fileIdMesg.getFieldValue(eFileIdTimeCreated).toUInt(); } stream.reset(); // note to the FIT specification: the specification allows different ordering of the messages. // Record messages can either be at the beginning or in chronological order within the record // messages. Garmin devices uses the chronological ordering. We only consider the chronological // order, otherwise timestamps (of records and events) must be compared to each other. CTrackData::trkseg_t seg; do { const CFitMessage& mesg = stream.nextMesg(); if(mesg.getGlobalMesgNr() == eMesgNumRecord) { // for documentation: MesgNumActivity, MesgNumSession, MesgNumLap, MesgNumLength could also contain data CTrackData::trkpt_t pt; if(readFitRecord(mesg, pt)) { seg.pts.append(std::move(pt)); } } else if(mesg.getGlobalMesgNr() == eMesgNumEvent) { if(mesg.getFieldValue(eEventEvent).toUInt() == eEventTimer) { uint event = mesg.getFieldValue(eEventEventType).toUInt(); if(event == eEventTypeStop || event == eEventTypeStopAll || event == eEventTypeStopDisableAll) { if(!seg.pts.isEmpty()) { trk.segs.append(seg); seg = CTrackData::trkseg_t(); } } } } else if(mesg.getGlobalMesgNr() == eMesgNumSegmentPoint) { CTrackData::trkpt_t pt; if(readFitSegmentPoint(mesg, pt, timeCreated)) { seg.pts.append(std::move(pt)); } } } while (stream.hasMoreMesg()); // append last segment if it is not empty. // navigation course files do not have to have start / stop event, so add the segment now. // and some records do not have a stop event if(!seg.pts.isEmpty()) { trk.segs.append(seg); } if(trk.segs.isEmpty()) { throw tr("FIT file %1 contains no GPS data.").arg(stream.getFileName()); } } void CGisItemWpt::readWptFromFit(CFitStream &stream) { const CFitMessage& mesg = stream.lastMesg(); if (mesg.getGlobalMesgNr() == eMesgNumLocation) { readFitLocation(mesg, wpt); } else { readFitCoursePoint(mesg, wpt); } } void CGisItemRte::readRteFromFit(CFitStream &stream) { // a course file could be considered as a route... rte.name = evaluateTrkName(stream); stream.reset(); do { const CFitMessage& mesg = stream.nextMesg(); if(mesg.getGlobalMesgNr() == eMesgNumRecord) { rtept_t pt; if(readFitRecord(mesg, pt)) { rte.pts.append(std::move(pt)); } } } while (stream.hasMoreMesg()); } qmapshack-1.10.0/src/gis/fit/CFitProject.cpp000644 001750 000144 00000011273 13216234140 021735 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "CMainWindow.h" #include "gis/CGisListWks.h" #include "gis/fit/CFitProject.h" #include "gis/fit/CFitStream.h" #include "gis/fit/defs/fit_enums.h" #include "gis/fit/defs/fit_fields.h" #include "gis/gpx/CGpxProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include CFitProject::CFitProject(const QString &filename, CGisListWks *parent) : IGisProject(eTypeFit, filename, parent) { loadFitFromFile(filename, true); } CFitProject::CFitProject(const QString &filename, IDevice *parent) : IGisProject(eTypeFit, filename, parent) { // this constructor is used when opening files from the garmin device. // this means several files are opened at the same time. For that case we do not show an error message if a file // can not be opened. loadFitFromFile(filename, false); } void CFitProject::loadFitFromFile(const QString &filename, bool showErrorMsg) { setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/FitProject.png")); blockUpdateItems(true); try { tryOpeningFitFile(filename); } catch(QString &errormsg) { if(showErrorMsg) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed to load file %1...").arg(filename), errormsg, QMessageBox::Abort); } else { qWarning() << "Failed to load FIT file:" << errormsg; } valid = false; } sortItems(); blockUpdateItems(false); } void CFitProject::tryOpeningFitFile(const QString &filename) { // create file instance QFile file(filename); qDebug() << "reading FIT file" << filename; // if the file does not exist, the filename is assumed to be a name for a new project if(!file.exists()) { IGisProject::filename.clear(); setupName(filename); setToolTip(CGisListWks::eColumnName, getInfo()); valid = true; return; } if(!file.open(QIODevice::ReadOnly)) { throw tr("Failed to open FIT file %1.").arg(filename); } try { createGisItems(file); } catch(QString& errormsg) { file.close(); throw errormsg; } file.close(); markAsSaved(); setToolTip(CGisListWks::eColumnName, getInfo()); valid = true; } void CFitProject::createGisItems(QFile& file) { CFitStream in(file); in.decodeFile(); QString name = ""; // remark: we consider activity and course files types. trk is for both types. There is one trk per fit file const CFitMessage& mesg = in.firstMesgOf(eMesgNumFileId); if(mesg.getFieldValue(eFileIdType).toUInt() == eFileActivity || mesg.getFieldValue(eFileIdType).toUInt() == eFileCourse || mesg.getFieldValue(eFileIdType).toUInt() == eFileSegment) { CGisItemTrk* trk = new CGisItemTrk(in, this); name = trk->getName(); } // fit does not have routes // new CGisItemRte(in, this); // Locations file containing waypoints if (mesg.getFieldValue(eFileIdType).toUInt() == eFileLocation) { while(in.nextMesgOf(eMesgNumLocation).isValid()) { new CGisItemWpt(in, this); } } in.reset(); // course point is a message of a course file. Thus, wpt is only for a course file. There might be n wpt per fit file while(in.nextMesgOf(eMesgNumCoursePoint).isValid()) { CGisItemWpt* wpt = new CGisItemWpt(in, this); if (name.length() == 0) { name = wpt->getName(); } } // ql:area is not directly available in FIT (could be calculated) QString tmp = QFileInfo(filename).completeBaseName().replace("_", " "); if(!name.isEmpty()) { tmp += QString("(%1)").arg(name); } setupName(tmp); } CFitProject::~CFitProject() { } qmapshack-1.10.0/src/gis/fit/decoder/000755 001750 000144 00000000000 13216664445 020475 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDefinitionState.h000644 001750 000144 00000002577 13216234143 025450 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELDDEFINITIONSTATE_H #define CFITFIELDDEFINITIONSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitFieldDefinitionState final : public IFitDecoderState { public: CFitFieldDefinitionState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitFieldDefinitionState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; private: quint8 offset; quint8 defNr; quint8 type; quint8 size; }; #endif //CFITFIELDDEFINITIONSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitCrcState.h000644 001750 000144 00000002416 13216234143 023113 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITCRCSTATE_H #define CFITCRCSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitCrcState final : public IFitDecoderState { Q_DECLARE_TR_FUNCTIONS(CFitCrcState) public: CFitCrcState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitCrcState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; }; #endif //CFITCRCSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitHeaderState.h000644 001750 000144 00000002557 13216234143 023602 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITHEADERSTATE_H #define CFITHEADERSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitHeaderState final : public IFitDecoderState { Q_DECLARE_TR_FUNCTIONS(CFitHeaderState) public: CFitHeaderState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitHeaderState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; private: quint8 offset; quint8 headerLength; quint32 dataSize; }; #endif //CFITHEADERSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDataState.h000644 001750 000144 00000003173 13216234143 024222 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELDDATASTATE_H #define CFITFIELDDATASTATE_H #include "gis/fit/decoder/IFitDecoderState.h" static const int fitMaxFieldSize =255; class CFitFieldDataState final : public IFitDecoderState { Q_DECLARE_TR_FUNCTIONS(CFitFieldDataState) public: CFitFieldDataState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitFieldDataState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; private: bool handleFitField(); bool handleDevField(); void devProfile(CFitMessage& mesg); CFitFieldProfile buildDevFieldProfile(CFitMessage& mesg); quint8 fieldIndex; quint8 devFieldIndex; quint8 fieldDataIndex; quint8 fieldData[fitMaxFieldSize]; }; #endif // CFITFIELDDATASTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitDecoder.h000644 001750 000144 00000003043 13216234143 022745 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITDECODER_H #define CFITDECODER_H #include "gis/fit/decoder/IFitDecoderState.h" #include class CFitMessage; class CFitDecoder final { Q_DECLARE_TR_FUNCTIONS(CFitDecoder) public: CFitDecoder(); ~CFitDecoder(); void decode(QFile& file); const QList& getMessages() const; private: void resetSharedData(); void printDebugInfo(); // map containing all states for the decoder. Needs to be pointer because decoder state is abstract class QMap stateMap; // shared data passed along the decoder state instances. IFitDecoderState::shared_state_data_t data; }; #endif // CFITDECODER_H qmapshack-1.10.0/src/gis/fit/decoder/CFitByteDataTransformer.cpp000644 001750 000144 00000014061 13216234140 025652 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitByteDataTransformer.h" #include "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/fit_const.h" quint64 CFitByteDataTransformer::getUIntValue(const CFitBaseType& baseType, quint8* rawData) { switch(baseType.nr()) { case eBaseTypeNrUint8: case eBaseTypeNrUint8z: case eBaseTypeNrEnum: return getUint8(rawData); case eBaseTypeNrUint16: case eBaseTypeNrUint16z: return getUint16(rawData); case eBaseTypeNrUint32: case eBaseTypeNrUint32z: return getUint32(rawData); case eBaseTypeNrUint64: case eBaseTypeNrUint64z: return getUint64(rawData); default: return 0; } } qint64 CFitByteDataTransformer::getSIntValue(const CFitBaseType& baseType, quint8 *rawData) { switch(baseType.nr()) { case eBaseTypeNrSint8: return getSint8(rawData); case eBaseTypeNrSint16: return getSint16(rawData); case eBaseTypeNrSint32: return getSint32(rawData); case eBaseTypeNrSint64: return getSint64(rawData); default: return 0; } } qreal CFitByteDataTransformer::getFloatValue(const CFitBaseType& baseType, quint8* rawData) { switch(baseType.nr()) { case eBaseTypeNrFloat32: return getFloat32(rawData); case eBaseTypeNrFloat64: return getFloat64(rawData); default: return 0; } } quint8 CFitByteDataTransformer::getUint8(quint8* rawData) { return (quint8) rawData[0]; } quint16 CFitByteDataTransformer::getUint16(quint8* rawData) { return ((quint16)rawData[1] << 8) | (quint16)rawData[0]; } quint32 CFitByteDataTransformer::getUint32(quint8* rawData) { return ((quint32)rawData[3] << 24) | ((quint32)rawData[2] << 16) | ((quint32)rawData[1] << 8) | (quint32)rawData[0]; } quint64 CFitByteDataTransformer::getUint64(quint8* rawData) { return ((quint64) rawData[7] << 56) | ((quint64) rawData[6] << 48) | ((quint64) rawData[5] << 40) | ((quint64) rawData[4] << 32) | ((quint64) rawData[3] << 24) | ((quint64) rawData[2] << 16) | ((quint64) rawData[1] << 8) | rawData[0]; } qint8 CFitByteDataTransformer::getSint8(quint8* rawData) { return (qint8) rawData[0]; } qint16 CFitByteDataTransformer::getSint16(quint8* rawData) { return ((qint16)rawData[1] << 8) | (qint16)rawData[0]; } qint32 CFitByteDataTransformer::getSint32(quint8* rawData) { return ((qint32)rawData[3] << 24) | ((qint32)rawData[2] << 16) | ((qint32)rawData[1] << 8) | (qint32)rawData[0]; } qint64 CFitByteDataTransformer::getSint64(quint8* rawData) { return ((qint64) rawData[7] << 56) | ((qint64) rawData[6] << 48) | ((qint64) rawData[5] << 40) | ((qint64) rawData[4] << 32) | ((qint64) rawData[3] << 24) | ((qint64) rawData[2] << 16) | ((qint64) rawData[1] << 8) | rawData[0]; } qreal CFitByteDataTransformer::getFloat32(quint8* rawData) { qint32 fValue = (qint32) (((qint32)rawData[3] << 24) | ((qint32)rawData[2] << 16) | ((qint32)rawData[1] << 8) | rawData[0]); // comment: qreal is a double type (on almost all systems). Here we need to go through a 32 bit floating type. float tmp; memcpy(&tmp, &fValue, sizeof(tmp)); qreal value = tmp; return value; } qreal CFitByteDataTransformer::getFloat64(quint8* rawData) { unsigned long long dValue = ((unsigned long long) rawData[7] << 56) | ((unsigned long long) rawData[6] << 48) | ((unsigned long long) rawData[5] << 40) | ((unsigned long long) rawData[4] << 32) | ((unsigned long long) rawData[3] << 24) | ((unsigned long long) rawData[2] << 16) | ((unsigned long long) rawData[1] << 8) | rawData[0]; // comment: qreal is a double type (on almost all systems). Here we need to go through a 64 bit floating type. double tmp; memcpy(&tmp, &dValue, sizeof(tmp)); qreal value = tmp; return value; } QString CFitByteDataTransformer::getString(quint8* rawData, quint8 length) { // find the 0 termination quint8 i = 0; while(rawData[i] != 0 ) { i++; // no 0 termination found, but length exceeded if(i > length) { break; } } return QString::fromUtf8((const char*)rawData, i); } QByteArray CFitByteDataTransformer::getBytes(quint8* rawData, quint8 length) { return QByteArray((const char*)rawData, length); } void CFitByteDataTransformer::swapFieldData(const CFitFieldDefinition& fieldDef, quint8* fieldData) { if (fieldDef.getEndianAbilityFlag() && (fieldDef.parent().getArchitectureBit() != eFitArchEndianLittle)) { // Swap the bytes for each element. int typeSize = fieldDef.getBaseType().size(); int elements = fieldDef.getSize() / typeSize; for (int element = 0; element < elements; element++) { for (int i = 0; i < (typeSize / 2); i++) { quint8 tmp = (quint8)fieldData[element * typeSize + i]; fieldData[element * typeSize + i] = fieldData[element * typeSize + typeSize - i - 1]; fieldData[element * typeSize + typeSize - i - 1] = tmp; } } } } qmapshack-1.10.0/src/gis/fit/decoder/CFitDevFieldDefinitionState.cpp000644 001750 000144 00000004216 13216234140 026427 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDevFieldDefinitionState.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/fit_const.h" /** * byte * 0: field number * 1: size in bytes of field data * 2: developer data index (maps to developer data id message) */ void CFitDevFieldDefinitionState::reset() { offset = 0; } decode_state_e CFitDevFieldDefinitionState::process(quint8 &dataByte) { switch (offset++) { case 0: // field number fieldNr = dataByte; break; case 1: // field data size size = dataByte; break; case 2: // field developer data index devDataIndex = dataByte; // get the previously (in RecordHeaderState) added definition message CFitDefinitionMessage* def = latestDefinition(); CFitFieldProfile* profile = devFieldProfile(fieldNr); // add the new field definition def->addDevField(CFitFieldDefinition(def, profile, fieldNr, size, profile->getBaseType().baseTypeField())); reset(); if (def->getDevFields().size() >= def->getNrOfDevFields()) { FITDEBUG(2, qDebug() << latestDefinition()->messageInfo()) endDefinition(); return eDecoderStateRecord; } } return eDecoderStateDevFieldDef; } qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDefinition.h000644 001750 000144 00000003663 13216234143 024444 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELDDEFINITION_H #define CFITFIELDDEFINITION_H #include class CFitDefinitionMessage; class CFitBaseType; class CFitFieldProfile; class CFitFieldDefinition final { public: CFitFieldDefinition(CFitDefinitionMessage* parent, CFitFieldProfile* fieldProfile, quint8 defNr, quint8 size, quint8 type); CFitFieldDefinition(CFitDefinitionMessage* parent, quint8 defNr, quint8 size, quint8 type); CFitFieldDefinition(); QString fieldInfo() const; quint8 getDefNr() const; quint8 getSize() const; quint8 getType() const; const CFitBaseType& getBaseType() const; bool getEndianAbilityFlag() const; const CFitDefinitionMessage& parent() const { return *parentDefintion; } const CFitFieldProfile& profile() const { return *fieldProfile; } void setParent(CFitDefinitionMessage* parent) { parentDefintion = parent; } private: quint8 defNr; quint8 size; quint8 type; CFitBaseType* baseType; const CFitDefinitionMessage* parentDefintion; const CFitFieldProfile* fieldProfile; }; #endif // CFITFIELDDEFINITION_H qmapshack-1.10.0/src/gis/fit/decoder/CFitRecordContentState.cpp000644 001750 000144 00000006607 13216234140 025513 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitRecordContentState.h" #include "gis/fit/defs/fit_const.h" /** * record content (without field definitions) * 0: reserved * 1: architecture (0 little, 1 big endian) * 2: global message number * 3: global message number * * 4: number of fields in the data message * 5 - 7: field definitions * if developer flag set * 8: number of developer fields in the data message * 9 - 11: developer field definitions */ void CFitRecordContentState::reset() { offset = 0; } decode_state_e CFitRecordContentState::process(quint8 &dataByte) { CFitDefinitionMessage* def = latestDefinition(); switch (offset++) { case 0: // reserved break; case 1: // architecture architecture = dataByte; def->setArchiteture(architecture); break; case 2: // global message number globalMesgNr = dataByte; break; case 3: // global message number globalMesgNr = globalMesgNr | ((quint16) dataByte << 8); if (architecture == eFitArchEndianBig) { globalMesgNr = (globalMesgNr >> 8) | ((globalMesgNr & 0xFF) << 8); } else if (architecture != eFitArchEndianLittle) { throw tr("FIT decoding error: architecture %1 not supported.").arg(architecture); } def->setGlobalMesgNr(globalMesgNr); break; case 4: // number of fields nrOfFields = dataByte; def->setNrOfFields(nrOfFields); // only reset if developer flag not set, else developer fields follow if(!def->developerFlag()) { reset(); } if (nrOfFields == 0) { // no fields, records may follow (either for a data message or definition message) return eDecoderStateRecord; } // the fields definitions follows return eDecoderStateFieldDef; break; case 5: // number of development fields nrOfFields = dataByte; def->setNrOfDevFields(nrOfFields); reset(); if (nrOfFields == 0) { // no fields, records may follow (either for a data message or definition message) return eDecoderStateRecord; } // the fields definitions follows return eDecoderStateDevFieldDef; break; default: throw tr("FIT decoding error: invalid offset %1 for state 'record content'").arg(offset); } // still more bytes for the record content return eDecoderStateRecordContent; } qmapshack-1.10.0/src/gis/fit/decoder/CFitDevFieldDefinitionState.h000644 001750 000144 00000002653 13216234143 026102 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITDEVFIELDDEFINITIONSTATE_H #define CFITDEVFIELDDEFINITIONSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitDevFieldDefinitionState final : public IFitDecoderState { public: CFitDevFieldDefinitionState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitDevFieldDefinitionState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; private: quint8 offset = 0; quint8 fieldNr = 0; quint8 size = 0; quint8 devDataIndex = 0; }; #endif //CFITDEVFIELDDEFINITIONSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitMessage.h000644 001750 000144 00000003701 13216234143 022765 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITMESSAGE_H #define CFITMESSAGE_H #include "gis/fit/decoder/CFitField.h" #include class CFitDefinitionMessage; class CFitProfile; class CFitFieldProfile; class CFitMessage final { public: CFitMessage(const CFitDefinitionMessage& def); CFitMessage(); bool isValid() const; quint16 getGlobalMesgNr() const { return globalMesgNr; } quint8 getLocalMesgNr() const { return localMesgNr; } bool hasField(const quint8 fieldDefNum) const; bool isFieldValueValid(const quint8 fieldDefNum) const; const QVariant getFieldValue(const quint8 fieldDefNum) const; void addField(CFitField & field); const CFitProfile& profile() const { return *messageProfile; } QStringList messageInfo() const; const QList getFields() const { return fields.values(); } void updateFieldProfile(quint8 fieldDefNr, const CFitFieldProfile* fieldProfile); private: QMap fields; QMap devFields; quint16 globalMesgNr; quint8 localMesgNr; const CFitProfile* messageProfile; }; #endif //CFITMESSAGE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitDecoder.cpp000644 001750 000144 00000010372 13216234140 023300 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitCrcState.h" #include "gis/fit/decoder/CFitDecoder.h" #include "gis/fit/decoder/CFitDevFieldDefinitionState.h" #include "gis/fit/decoder/CFitFieldDataState.h" #include "gis/fit/decoder/CFitFieldDefinitionState.h" #include "gis/fit/decoder/CFitHeaderState.h" #include "gis/fit/decoder/CFitRecordContentState.h" #include "gis/fit/decoder/CFitRecordHeaderState.h" #include "gis/fit/defs/fit_const.h" CFitDecoder::CFitDecoder() { stateMap[eDecoderStateFileHeader] = new CFitHeaderState(data); stateMap[eDecoderStateRecord] = new CFitRecordHeaderState(data); stateMap[eDecoderStateRecordContent] = new CFitRecordContentState(data); stateMap[eDecoderStateFieldDef] = new CFitFieldDefinitionState(data); stateMap[eDecoderStateDevFieldDef] = new CFitDevFieldDefinitionState(data); stateMap[eDecoderStateFieldData] = new CFitFieldDataState(data); stateMap[eDecoderStateFileCrc] = new CFitCrcState(data); } CFitDecoder::~CFitDecoder() { qDeleteAll(stateMap); stateMap.clear(); data.messages.clear(); } void CFitDecoder::resetSharedData() { data.definitions = QMap(); data.definitionHistory = QList(); data.messages = QList(); data.devFieldProfiles = QList(); data.lastDefinition = nullptr; data.lastMessage = nullptr; data.timestamp = 0; data.lastTimeOffset = 0; data.fileBytesRead = 0; data.fileLength = 0; data.crc = 0; } void printDefinitions(const QList& defs) { for(int i = 0; i < defs.size(); i++) { for(QString& s: defs[i].messageInfo()) { qDebug() << s; } } } void printMessages(const QList& messages) { for(int i = 0; i < messages.size(); i++) { for(QString& s: messages[i].messageInfo()) { qDebug() << s; } } } void CFitDecoder::printDebugInfo() { FITDEBUG(1, printDefinitions(data.definitionHistory)) FITDEBUG(1, printMessages(data.messages)) } QList decoderStateNames = {"File Header", "Record", "Record Content", "Field Definition", "Development Field Definition", "Field Data", "CRC", "End"}; void printByte(QFile& file, decode_state_e state, quint8 dataByte) { FITDEBUG(3, qDebug() << QString("decoding byte %1 - %2 - %3") .arg(file.pos(), 6, 10, QLatin1Char(' ')) .arg(dataByte, 8, 2, QLatin1Char('0')) .arg(decoderStateNames.at(state))); } void CFitDecoder::decode(QFile &file) { resetSharedData(); file.seek(0); quint8 dataByte; decode_state_e state = eDecoderStateFileHeader; while (!file.atEnd()) { file.getChar((char *) &dataByte); try { printByte(file, state, dataByte); state = stateMap[state]->processByte(dataByte); if (state == eDecoderStateEnd) { // end of file, everything ok printDebugInfo(); return; } } catch(QString& errormsg) { printDebugInfo(); throw errormsg; } } // unexpected end of file printDebugInfo(); throw tr("FIT decoding error: unexpected end of file %1.").arg(file.fileName()); } const QList& CFitDecoder::getMessages() const { return data.messages; } qmapshack-1.10.0/src/gis/fit/decoder/CFitRecordHeaderState.h000644 001750 000144 00000002436 13216234143 024735 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITRECORDHEADERSTATE_H #define CFITRECORDHEADERSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitRecordHeaderState final : public IFitDecoderState { public: CFitRecordHeaderState(shared_state_data_t & data) : IFitDecoderState(data) { reset(); } virtual ~CFitRecordHeaderState() {} decode_state_e process(quint8 &dataByte) override; void reset() override {} }; #endif //CFITRECORDHEADERSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/IFitDecoderState.h000644 001750 000144 00000006023 13216234143 023755 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITSTATE_H #define CFITSTATE_H #include "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/decoder/CFitMessage.h" #include "gis/fit/defs/CFitFieldProfile.h" #include typedef enum { eDecoderStateFileHeader, eDecoderStateRecord, eDecoderStateRecordContent, eDecoderStateFieldDef, eDecoderStateDevFieldDef, eDecoderStateFieldData, eDecoderStateFileCrc, eDecoderStateEnd } decode_state_e; class IFitDecoderState { Q_DECLARE_TR_FUNCTIONS(IFitDecoderState) public: struct shared_state_data_t { quint16 crc; quint32 fileLength; quint32 fileBytesRead; quint8 lastTimeOffset; quint32 timestamp; CFitDefinitionMessage* lastDefinition; CFitMessage* lastMessage; QMap definitions; QList definitionHistory; QList messages; QList devFieldProfiles; }; IFitDecoderState(shared_state_data_t &data) : data(data) { } virtual ~IFitDecoderState() {} virtual void reset() = 0; decode_state_e processByte(quint8 &dataByte); protected: virtual decode_state_e process(quint8 &dataByte) = 0; CFitMessage* latestMessage() const { return data.lastMessage; } void addMessage(const CFitDefinitionMessage& definition); void setFileLength(quint32 fileLength); void resetFileBytesRead(); void incFileBytesRead(); quint32 bytesLeftToRead(); CFitDefinitionMessage* latestDefinition() const { return data.lastDefinition; } CFitDefinitionMessage* definition(quint32 localMessageType); void addDefinition(const CFitDefinitionMessage &definition); void endDefinition(); void setTimestamp(quint32 fullTimestamp); void setTimestampOffset(quint32 offsetTimestamp); quint32 getTimestamp() const { return data.timestamp; } quint16 getCrc() const { return data.crc; } void addDevFieldProfile(const CFitFieldProfile &fieldProfile); CFitFieldProfile* devFieldProfile(quint32 fieldNr); void clearDevFieldProfiles(); private: void buildCrc(quint8 byte); shared_state_data_t &data; }; #endif // CFITSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldBuilder.cpp000644 001750 000144 00000013246 13216234140 024270 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitByteDataTransformer.h" #include "gis/fit/decoder/CFitField.h" #include "gis/fit/decoder/CFitFieldBuilder.h" #include "gis/fit/decoder/CFitFieldDefinition.h" #include "gis/fit/decoder/CFitMessage.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" void CFitFieldBuilder::evaluateSubfieldsAndExpandComponents(CFitMessage& mesg) { for (const CFitField & field : mesg.getFields()) { CFitFieldBuilder::evaluateFieldProfile(mesg, field); } for (const CFitField & field : mesg.getFields()) { CFitFieldBuilder::expandComponents(mesg, field); } } CFitField CFitFieldBuilder::buildField(const CFitFieldDefinition& def, quint8* fieldData, const CFitMessage& message) { const CFitFieldProfile* fieldProfile = CFitProfileLookup::getFieldForProfile(message.getGlobalMesgNr(), def.getDefNr()); return buildField(*fieldProfile, def, fieldData, message); } CFitField CFitFieldBuilder::buildField(const CFitFieldProfile &fieldProfile, const CFitFieldDefinition &def, quint8 *fieldData, const CFitMessage& message) { CFitByteDataTransformer::swapFieldData(def, fieldData); const CFitBaseType& baseType = def.getBaseType(); QVariant value; if (baseType.isSignedInt()) { value = QVariant(CFitByteDataTransformer::getSIntValue(baseType, fieldData)); } else if (baseType.isUnsignedInt()) { value = QVariant(CFitByteDataTransformer::getUIntValue(baseType, fieldData)); } else if (baseType.isFloat()) { value = QVariant(CFitByteDataTransformer::getFloatValue(baseType, fieldData)); } else if (baseType.isString()) { value = QVariant(CFitByteDataTransformer::getString(fieldData, def.getSize())); } else if (baseType.isByte()) { value = QVariant(CFitByteDataTransformer::getBytes(fieldData, def.getSize())); } else { // should not be possible throw tr("FIT decoding error: unknown base type %1.").arg(baseType.nr()); } bool valid = isValueValid(def, fieldData); return CFitField(def, &fieldProfile, value, valid); } bool CFitFieldBuilder::isValueValid(const CFitFieldDefinition &def, quint8 *fieldData) { const CFitBaseType &baseType = def.getBaseType(); const quint8 *invalidBytes = baseType.invalidValueBytes(); quint8 invalidCount = 0; if(!baseType.isSizeUndefined() && def.getSize() != baseType.size()) { return false; } for (quint8 i = 0; i < def.getSize(); i++) { quint8 b = baseType.isSizeUndefined() ? invalidBytes[0] : invalidBytes[i]; if (fieldData[i] == b) { invalidCount++; } } return invalidCount < def.getSize(); } void CFitFieldBuilder::evaluateFieldProfile(CFitMessage& mesg, const CFitField & field) { const CFitFieldProfile& fieldProfile = field.profile(); // case subfield if (fieldProfile.hasSubfields()) { for (const CFitSubfieldProfile* subfieldProfile : fieldProfile.getSubfields()) { // the referenced field is for all subfields the same for (const CFitField & referencedField : mesg.getFields()) { if (referencedField.getFieldDefNr() == subfieldProfile->getReferencedFieldDefNr() && referencedField.getValue().toUInt() == subfieldProfile->getReferencedFieldValue()) { // the value of the referenced field matches with the field profile reference-value mesg.updateFieldProfile(field.getFieldDefNr(), subfieldProfile); } } } } } void CFitFieldBuilder::expandComponents(CFitMessage& mesg, const CFitField & field) { // TODO accumulated fields are not implemented (no need so far) const CFitFieldProfile& fieldProfile = field.profile(); // case component if (fieldProfile.hasComponents()) { int offset = 0; for (const CFitComponentfieldProfile* compProfile : fieldProfile.getComponents()) { if (field.getBaseType().isSignedInt()) { qint32 value = (field.getValue().toInt() >> offset) & compProfile->getBitmask(); CFitField compField = CFitField(field.getGlobalMesgNr(), compProfile->getFieldDefNum(), compProfile, QVariant(value), true); mesg.addField(compField); } else { quint32 value = (field.getValue().toUInt() >> offset) & compProfile->getBitmask(); CFitField compField = CFitField(field.getGlobalMesgNr(), compProfile->getFieldDefNum(), compProfile, QVariant(value), true); mesg.addField(compField); } offset += compProfile->getBits(); } } } qmapshack-1.10.0/src/gis/fit/decoder/CFitDevFieldDefinition.h000644 001750 000144 00000002613 13216234143 025075 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITDEVFIELDDEFINITION_H #define CFITDEVFIELDDEFINITION_H #include // content of the field description messages class CFitDevFieldDefinition final { public: CFitDevFieldDefinition(quint8 fieldNr, quint8 size, quint8 devDataIndex); CFitDevFieldDefinition() = default; QString fieldInfo() const; quint8 getFieldNr() const; quint8 getSize() const; quint8 getDevDataIndex() const; private: quint8 fieldNr = 0; quint8 size = 0; quint8 devDataIndex = 0; }; #endif // CFITDEVFIELDDEFINITION_H qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDefinition.cpp000644 001750 000144 00000005532 13216234140 024771 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/decoder/CFitFieldDefinition.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" static const quint8 fitEndianFlagMask = 0x80; CFitFieldDefinition::CFitFieldDefinition(CFitDefinitionMessage* parent, CFitFieldProfile* fieldProfile, quint8 defNr, quint8 size, quint8 type) : defNr(defNr), size(size), type(type), baseType(CFitBaseTypeMap::get(type)), parentDefintion(parent), fieldProfile(fieldProfile) { } CFitFieldDefinition::CFitFieldDefinition(CFitDefinitionMessage* parent, quint8 defNr, quint8 size, quint8 type) : CFitFieldDefinition(parent, nullptr, defNr, size, type) { fieldProfile = CFitProfileLookup::getFieldForProfile(parentDefintion ? parentDefintion->getGlobalMesgNr() : fitGlobalMesgNrInvalid, defNr); } CFitFieldDefinition::CFitFieldDefinition() : CFitFieldDefinition(nullptr, fitLocalMesgNrInvalid, 0, eBaseTypeNrInvalid) { } QString CFitFieldDefinition::fieldInfo() const { QString fstr = QString("%1 %2 %3 (%4): %5, type %6, size %7, endian %8") .arg(profile().hasSubfields() ? "dynamic" : profile().hasComponents() ? "component" : "field") .arg(profile().getName()) .arg(profile().getFieldType() == eFieldTypeDevelopment ? " DEV" : "") .arg(getDefNr()) .arg(getBaseType().name()) .arg(getType()) .arg(getSize()) .arg(getEndianAbilityFlag()); return fstr; } quint8 CFitFieldDefinition::getDefNr() const { return defNr; } quint8 CFitFieldDefinition::getSize() const { return size; } quint8 CFitFieldDefinition::getType() const { return type; } bool CFitFieldDefinition::getEndianAbilityFlag() const { return (type & fitEndianFlagMask) != 0; } const CFitBaseType& CFitFieldDefinition::getBaseType() const { return *baseType; }qmapshack-1.10.0/src/gis/fit/decoder/IFitDecoderState.cpp000644 001750 000144 00000011314 13216234140 024304 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/IFitDecoderState.h" decode_state_e IFitDecoderState::processByte(quint8 &dataByte) { incFileBytesRead(); buildCrc(dataByte); decode_state_e state = process(dataByte); if (bytesLeftToRead() == 2) { if (state != eDecoderStateRecord) { // we come from a wrong state... throw tr("FIT decoding error: Decoder not in correct state %1 after last data byte in file.").arg(state); } // end of file, 2 bytes left, this is the crc return eDecoderStateFileCrc; } return state; } void IFitDecoderState::buildCrc(quint8 byte) { static const quint16 crc_table[16] = { 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 }; quint16 tmp; quint16 crc = data.crc; // compute checksum of lower four bits of byte tmp = crc_table[crc & 0xF]; crc = (crc >> 4) & 0x0FFF; crc = crc ^ tmp ^ crc_table[byte & 0xF]; // now compute checksum of upper four bits of byte tmp = crc_table[crc & 0xF]; crc = (crc >> 4) & 0x0FFF; crc = crc ^ tmp ^ crc_table[(byte >> 4) & 0xF]; data.crc = crc; } static const quint8 fitRecordHeaderTimeOffsetMask = 0x1F; // bit 0-4: 0001 1111 void IFitDecoderState::setTimestamp(quint32 fullTimestamp) { data.timestamp = fullTimestamp; data.lastTimeOffset = (quint8) (data.timestamp & fitRecordHeaderTimeOffsetMask); } void IFitDecoderState::setTimestampOffset(quint32 offsetTimestamp) { quint8 timeOffset = offsetTimestamp & fitRecordHeaderTimeOffsetMask; data.timestamp += (timeOffset - data.lastTimeOffset) & fitRecordHeaderTimeOffsetMask; data.lastTimeOffset = timeOffset; } void IFitDecoderState::addMessage(const CFitDefinitionMessage& definition) { data.messages.append(CFitMessage(definition)); data.lastMessage = &data.messages.last(); } void IFitDecoderState::addDefinition(const CFitDefinitionMessage &definition) { data.definitions[definition.getLocalMesgNr()] = definition; data.lastDefinition = &data.definitions[definition.getLocalMesgNr()]; } void IFitDecoderState::endDefinition() { data.definitionHistory.append(*data.lastDefinition); } CFitDefinitionMessage*IFitDecoderState::definition(quint32 localMessageType) { return &(data.definitions[localMessageType]); } void IFitDecoderState::setFileLength(quint32 fileLength) { data.fileLength = fileLength; } quint32 IFitDecoderState::bytesLeftToRead() { return data.fileLength - data.fileBytesRead; } void IFitDecoderState::resetFileBytesRead() { data.fileBytesRead = 0; } void IFitDecoderState::incFileBytesRead() { data.fileBytesRead++; } void IFitDecoderState::addDevFieldProfile(const CFitFieldProfile &fieldProfile) { // for documentation: a development field definition is linked to an developer data ID. Only the tuple developer data index // and field definition number must be unique. So far no fit file with more than one developer data ID has been created. if(devFieldProfile(fieldProfile.getFieldDefNum())->getFieldDefNum() == fieldProfile.getFieldDefNum()) { throw tr("FIT decoding error: a development field with the field_definition_number %1 already exists.") .arg(fieldProfile.getFieldDefNum()); } data.devFieldProfiles.append(fieldProfile); } CFitFieldProfile* IFitDecoderState::devFieldProfile(quint32 fieldNr) { for (int i=0; i < data.devFieldProfiles.size(); i++) { if (fieldNr == data.devFieldProfiles[i].getFieldDefNum()) { return &data.devFieldProfiles[i]; } } // dummy field for unknown field nr. static CFitFieldProfile dummyFieldProfile; return &dummyFieldProfile; //return data.devFieldProfiles[fieldNr]; } void IFitDecoderState::clearDevFieldProfiles() { data.devFieldProfiles.clear(); } qmapshack-1.10.0/src/gis/fit/decoder/CFitMessage.cpp000644 001750 000144 00000006520 13216234140 023317 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/decoder/CFitMessage.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" CFitMessage::CFitMessage(const CFitDefinitionMessage& def) : fields(), devFields(), globalMesgNr(def.getGlobalMesgNr()), localMesgNr(def.getLocalMesgNr()), messageProfile(CFitProfileLookup::getProfile(globalMesgNr)) { } CFitMessage::CFitMessage() : fields(), devFields(), globalMesgNr(fitGlobalMesgNrInvalid), localMesgNr(fitLocalMesgNrInvalid), messageProfile(CFitProfileLookup::getProfile(fitGlobalMesgNrInvalid)) { } bool CFitMessage::isValid() const { return getGlobalMesgNr() != fitGlobalMesgNrInvalid; } void CFitMessage::updateFieldProfile(quint8 fieldDefNr, const CFitFieldProfile* fieldProfile) { if (fieldProfile->getFieldType() == eFieldTypeFit) { fields[fieldDefNr].setProfile(fieldProfile); } if (fieldProfile->getFieldType() == eFieldTypeDevelopment) { devFields[fieldDefNr].setProfile(fieldProfile); } } QStringList CFitMessage::messageInfo() const { QStringList list; list << QString("Message %1 (%3) %4 [loc]") .arg(profile().getName()) .arg(getGlobalMesgNr()) .arg(getLocalMesgNr()); for(const CFitField &field : fields) { list << field.fieldInfo(); } for(const CFitField &field : devFields) { list << field.fieldInfo(); } return list; } bool CFitMessage::hasField(const quint8 fieldDefNum) const { return fields.contains(fieldDefNum); } void CFitMessage::addField(CFitField & field) { if (field.profile().getFieldType() == eFieldTypeFit) { if(fields.contains(field.getFieldDefNr())) { qCritical("fit field %d already added to map.", (int) field.getFieldDefNr()); } fields.insert(field.getFieldDefNr(), field); } if (field.profile().getFieldType() == eFieldTypeDevelopment) { if(devFields.contains(field.getFieldDefNr())) { qCritical("fit dev field %d already added to map.", (int) field.getFieldDefNr()); } devFields.insert(field.getFieldDefNr(), field); } } bool CFitMessage::isFieldValueValid(const quint8 fieldDefNum) const { return fields[fieldDefNum].isValidValue(); } const QVariant CFitMessage::getFieldValue(const quint8 fieldDefNum) const { return fields[fieldDefNum].getValue(); } qmapshack-1.10.0/src/gis/fit/decoder/CFitDefinitionMessage.h000644 001750 000144 00000005317 13216234143 025003 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITMESSAGEDEFINTION_H #define CFITMESSAGEDEFINTION_H #include "gis/fit/decoder/CFitDevFieldDefinition.h" #include "gis/fit/decoder/CFitFieldDefinition.h" #include class CFitBaseType; class CFitProfile; class CFitDefinitionMessage final { public: CFitDefinitionMessage(quint8 localMesgNr, bool devFlag); CFitDefinitionMessage(); CFitDefinitionMessage(const CFitDefinitionMessage& copy); void setArchiteture(quint8 arch); void setGlobalMesgNr(quint16 globalMesgNr); void setNrOfFields(quint8 nrOfFields); void setNrOfDevFields(quint8 nrOfDevFields); quint8 getArchitectureBit() const; quint16 getGlobalMesgNr() const { return globalMesgNr; } quint8 getNrOfFields() const { return nrOfFields; } quint8 getNrOfDevFields() const { return nrOfDevFields; } quint8 getLocalMesgNr() const { return localMesgNr; } bool developerFlag() const { return devFlag; } const CFitProfile& profile() const { return *messageProfile; } const QList& getFields() const { return fields; } const QList& getDevFields() const { return devFields; } void addField(CFitFieldDefinition field); void addDevField(CFitFieldDefinition field); bool hasField(const quint8 fieldNum) const; const CFitFieldDefinition& getField(const quint8 fieldNum) const; const CFitFieldDefinition& getFieldByIndex(const quint16 index) const; const CFitFieldDefinition& getDevFieldByIndex(const quint16 index) const; QStringList messageInfo() const; private: quint16 globalMesgNr; quint8 architecture; quint8 nrOfFields; quint8 nrOfDevFields; quint8 localMesgNr; bool devFlag; QList fields; QList devFields; const CFitProfile* messageProfile; }; #endif // CFITMESSAGEDEFINTION_H qmapshack-1.10.0/src/gis/fit/decoder/CFitByteDataTransformer.h000644 001750 000144 00000004113 13216234143 025317 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITBYTEDATATRANSFORMER_H #define CFITBYTEDATATRANSFORMER_H #include class CFitBaseType; class CFitFieldDefinition; class CFitByteDataTransformer { public: CFitByteDataTransformer() = delete; static quint64 getUIntValue(const CFitBaseType& baseType, quint8* rawData); static qint64 getSIntValue(const CFitBaseType &baseType, quint8 *rawData); static qreal getFloatValue(const CFitBaseType& baseType, quint8* rawData); /* * param rawData: the fit utf-8 string, 0 terminated. */ static QString getString(quint8* rawData, quint8 length); static QByteArray getBytes(quint8* rawData, quint8 length); static void swapFieldData(const CFitFieldDefinition& fieldDef, quint8* fieldData); private: static quint8 getUint8(quint8* rawData); static quint16 getUint16(quint8* rawData); static quint32 getUint32(quint8* rawData); static quint64 getUint64(quint8* rawData); static qint8 getSint8(quint8* rawData); static qint16 getSint16(quint8* rawData); static qint32 getSint32(quint8* rawData); static qint64 getSint64(quint8* rawData); static qreal getFloat32(quint8* rawData); static qreal getFloat64(quint8* rawData); }; #endif //CFITBYTEDATATRANSFORMER_H qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDefinitionState.cpp000644 001750 000144 00000004055 13216234140 025771 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitFieldDefinitionState.h" #include "gis/fit/defs/fit_const.h" /** * byte * 0: field definition number * 1: size in bytes of field data * 2: base type */ void CFitFieldDefinitionState::reset() { offset = 0; } decode_state_e CFitFieldDefinitionState::process(quint8 &dataByte) { switch (offset++) { case 0: // field definition number defNr = dataByte; break; case 1: // field data size size = dataByte; break; case 2: // field base type type = dataByte; // get the previously (in RecordHeaderState) added definition message CFitDefinitionMessage* def = latestDefinition(); // add the new field definition def->addField(CFitFieldDefinition(def, defNr, size, type)); reset(); if (def->getFields().size() >= def->getNrOfFields()) { if(def->developerFlag()) { return eDecoderStateRecordContent; } FITDEBUG(2, qDebug() << latestDefinition()->messageInfo()) endDefinition(); return eDecoderStateRecord; } } return eDecoderStateFieldDef; } qmapshack-1.10.0/src/gis/fit/decoder/CFitRecordContentState.h000644 001750 000144 00000002674 13216234143 025163 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITRECORDCONTENTSTATE_H #define CFITRECORDCONTENTSTATE_H #include "gis/fit/decoder/IFitDecoderState.h" class CFitRecordContentState final : public IFitDecoderState { Q_DECLARE_TR_FUNCTIONS(CFitRecordContentState) public: CFitRecordContentState(shared_state_data_t &data) : IFitDecoderState(data) { reset(); } virtual ~CFitRecordContentState() {} void reset() override; decode_state_e process(quint8 &dataByte) override; private: quint8 offset; quint8 architecture; quint32 globalMesgNr; quint8 nrOfFields; }; #endif //CFITRECORDCONTENTSTATE_H qmapshack-1.10.0/src/gis/fit/decoder/CFitRecordHeaderState.cpp000644 001750 000144 00000007537 13216234140 025274 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitRecordHeaderState.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/fit_fields.h" /* * normal header * bit: value description * 7: 0 normal Header * 6: 0/1 data message / definition message * 5: 0/1 developer data flag * 4: - reserved * 3: 0/1 local message type (0-15 -> 0000 - 1111) * 2: local message type * 1: local message type * 0: local message type */ static const quint8 fitRecordHeaderDefBit = ((quint8) 0x40); // bit 6: 0100 0000 static const quint8 fitRecordHeaderDevBit = ((quint8) 0x20); // bit 5: 0010 0000 static const quint8 fitRecordHeaderMesgMask = ((quint8) 0x0F); // bit 0-3: 0000 1111 /* * compressed timestamp header * bit: value description * 7: 1 compressed timestamp header * 6: 0/1 local message type * 5: local message type * 4: 0/1 time offset (seconds) (0-31 -> 0 0000-1 1111) * 3: time offset * 2: time offset * 1: time offset * 0: time offset */ static const quint8 fitRecordHeaderTypeBit = ((quint8) 0x80); // bit 7: 1000 0000 static const quint8 fitRecordHeaderTimeMesgMask = ((quint8) 0x60); // bit 5-6: 0110 0000 static const quint8 fitRecordHeaderTimeMesgShift = 5; decode_state_e CFitRecordHeaderState::process(quint8 &dataByte) { if ((dataByte & fitRecordHeaderTypeBit) != 0) { // this is a compressed timestamp header quint8 localMessageType = (dataByte & fitRecordHeaderTimeMesgMask) >> fitRecordHeaderTimeMesgShift; CFitDefinitionMessage* def = definition(localMessageType); if (!def->hasField(eRecordTimestamp)) { // create dummy definition field for timestamp // later on passed timestamp is a uint32, therefore a 4 byte type is created. // remark on enum for timestamp (RecordTimestamp): // the timestamp field has for all message types the same number (253) therefore it does not matter which // enum is taken here. def->addField(CFitFieldDefinition(def, eRecordTimestamp, sizeof(quint32), eBaseTypeNrUint8)); } setTimestampOffset(dataByte); addMessage(*def); const CFitFieldDefinition& fieldDef = def->getField(eRecordTimestamp); CFitField timeField = CFitField(fieldDef, &fieldDef.profile(), QVariant(getTimestamp()), true); latestMessage()->addField(timeField); return eDecoderStateFieldData; } else { quint8 localMessageType = dataByte & fitRecordHeaderMesgMask; if ((dataByte & fitRecordHeaderDefBit) != 0) { // this is a definition message bool developerDataFlag = dataByte & fitRecordHeaderDevBit; addDefinition(CFitDefinitionMessage(localMessageType, developerDataFlag)); return eDecoderStateRecordContent; } else { // this is a data message addMessage(*definition(localMessageType)); // go to eDecoderStateFieldData return eDecoderStateFieldData; } } } qmapshack-1.10.0/src/gis/fit/decoder/CFitHeaderState.cpp000644 001750 000144 00000006217 13216234140 024127 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitHeaderState.h" /** * byte * 0: the header size without crc (12 for the current version) * 1: protocol version * 2: profil version LSB * 3: profil version MSB * 4: data size LSB * 5: data size * 6: data size * 7: data size * 8: "." * 9: "F" * 10: "I" * 11: "T" * 12: CRC LSB * 13: CRC MSB */ static const quint8 fitProtocolVersionMajor = 2; static const quint8 fitProtocolMajorVersionShift = 4; static const quint8 fitProtocolMajorVersionMask = 0x0F << fitProtocolMajorVersionShift; void CFitHeaderState::reset() { setFileLength(3); // Header byte + CRC. offset = 0; setTimestamp(0); resetFileBytesRead(); } decode_state_e CFitHeaderState::process(quint8 &dataByte) { bool invalid = false; switch (offset++) { case 0: // header length headerLength = dataByte; setFileLength(headerLength + 2); break; case 1: // protocol version if ((dataByte & fitProtocolMajorVersionMask) > (fitProtocolVersionMajor << fitProtocolMajorVersionShift)) { throw tr("FIT decoding error: protocol %1 version not supported.").arg(dataByte & fitProtocolMajorVersionMask); } break; case 4: // data size dataSize = (quint32) (dataByte & 0xFF); break; case 5: // data size dataSize |= (quint32) (dataByte & 0xFF) << 8; break; case 6: // data size dataSize |= (quint32) (dataByte & 0xFF) << 16; break; case 7: // data size dataSize |= (quint32) (dataByte & 0xFF) << 24; setFileLength(dataSize + headerLength + 2); // include crc break; case 8: // "." invalid = (dataByte != '.'); break; case 9: // "F" invalid = (dataByte != 'F'); break; case 10: // "I" invalid = (dataByte != 'I'); break; case 11: // "T" invalid = (dataByte != 'T'); break; default: break; } if (invalid) { throw tr("FIT decoding error: file header signature mismatch. File is not FIT."); } if (offset == headerLength) { // end of header return eDecoderStateRecord; } return eDecoderStateFileHeader; } qmapshack-1.10.0/src/gis/fit/decoder/CFitField.h000644 001750 000144 00000004131 13216234143 022422 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELD_H #define CFITFIELD_H #include class CFitFieldDefinition; class CFitFieldProfile; class CFitBaseType; class CFitField final { public: CFitField(const CFitFieldDefinition& fieldDefinition, const CFitFieldProfile* profile, QVariant value, bool valid); CFitField(quint16 globalMesgNr, quint8 fieldDefNr, const CFitFieldProfile* profile, QVariant value, bool valid); CFitField(const CFitField & copy); CFitField(); virtual ~CFitField() { /* nothing to do here, profile and base type are global and not to delete */ } void setProfile(const CFitFieldProfile* profile); QString fieldInfo() const; const CFitBaseType& getBaseType() const { return *baseType; } quint16 getGlobalMesgNr() const { return globalMesgNr; } quint8 getFieldDefNr() const { return fieldDefNr; } const CFitFieldProfile& profile() const { return *fieldProfile; } bool isValidValue() const { return valid; } const QVariant& getValue() const { return value; } private: void applyScaleAndOffset(); const CFitFieldProfile* fieldProfile; quint16 globalMesgNr; quint8 fieldDefNr; const CFitBaseType* baseType; bool valid; QVariant value; QVariant rawValue; }; #endif // CFITFIELD_H qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldDataState.cpp000644 001750 000144 00000021506 13216234140 024552 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitFieldBuilder.h" #include "gis/fit/decoder/CFitFieldDataState.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" #include "gis/fit/defs/fit_enums.h" #include "gis/fit/defs/fit_fields.h" void CFitFieldDataState::reset() { fieldDataIndex = 0; fieldIndex = 0; devFieldIndex = 0; } decode_state_e CFitFieldDataState::process(quint8 &dataByte) { CFitMessage& mesg = *latestMessage(); CFitDefinitionMessage* defMesg = definition(mesg.getLocalMesgNr()); // add the read byte to the data array fieldData[fieldDataIndex++] = dataByte; handleFitField(); bool allFieldRead = fieldIndex >= defMesg->getNrOfFields(); if(allFieldRead) { handleDevField(); } bool allDevFielRead = devFieldIndex >= defMesg->getNrOfDevFields(); if (allFieldRead && allDevFielRead) { // Now that the entire message is decoded we may evaluate subfields and expand components CFitFieldBuilder::evaluateSubfieldsAndExpandComponents(mesg); devProfile(mesg); reset(); FITDEBUG(2, qDebug() << mesg.messageInfo()) // after all fields read, go to next record header return eDecoderStateRecord; } // there are more fields to read for the current message return eDecoderStateFieldData; } bool CFitFieldDataState::handleFitField() { CFitMessage& mesg = *latestMessage(); CFitDefinitionMessage* defMesg = definition(mesg.getLocalMesgNr()); if (fieldIndex < defMesg->getNrOfFields()) { const CFitFieldDefinition& fieldDef = defMesg->getFieldByIndex(fieldIndex); if (fieldDataIndex >= fieldDef.getSize()) { // all bytes are read for current field // new field with data CFitField f = CFitFieldBuilder::buildField(fieldDef, fieldData, mesg); mesg.addField(f); // The special case time record. // timestamp has always the same value for all enums. it does not matter against which we're comparing. if (fieldDef.getDefNr() == eRecordTimestamp) { setTimestamp(f.getValue().toUInt()); } // new field follows, reset fieldDataIndex = 0; fieldIndex++; } } return fieldIndex >= defMesg->getNrOfFields(); } bool CFitFieldDataState::handleDevField() { CFitMessage& mesg = *latestMessage(); CFitDefinitionMessage* defMesg = definition(mesg.getLocalMesgNr()); if (devFieldIndex < defMesg->getNrOfDevFields()) { const CFitFieldDefinition& fieldDef = defMesg->getDevFieldByIndex(devFieldIndex); if (fieldDataIndex >= fieldDef.getSize()) { // handling developer data for mapping the field data to its definitions: // part 2, reading field data and attach dynamic profile CFitFieldProfile* fieldProfile = devFieldProfile(fieldDef.getDefNr()); if (fieldProfile->getBaseType().nr() == eBaseTypeNrInvalid) { // test if profile exists throw tr("Missing field definition for development field."); } CFitField f = CFitFieldBuilder::buildField(*fieldProfile, fieldDef, fieldData, mesg); mesg.addField(f); // new field follows, reset fieldDataIndex = 0; devFieldIndex++; } } return devFieldIndex >= defMesg->getNrOfDevFields(); } void CFitFieldDataState::devProfile(CFitMessage& mesg) { // handling developer data for mapping the field data to its definitions: // part 1, dynamic profiles creation if (mesg.getGlobalMesgNr() == eMesgNumDeveloperDataId) { clearDevFieldProfiles(); } if (mesg.getGlobalMesgNr() == eMesgNumFieldDescription) { CFitFieldProfile devFieldProfile = buildDevFieldProfile(mesg); FITDEBUG(2, qDebug() << devFieldProfile.fieldProfileInfo()); addDevFieldProfile(devFieldProfile); } } CFitFieldProfile CFitFieldDataState::buildDevFieldProfile(CFitMessage& mesg) { QString fieldName; quint8 fieldDefNr = 0; quint8 devDataIdx = 0; quint8 baseType = eBaseTypeNrInvalid; qreal scale = 0; quint8 array = 0; QString components; qint16 offset = 0; QString units; QString bits; QString accumulate; quint8 baseUnitId = 0; quint8 natvieMesgNum = 0; quint8 nativeFieldNum = 0; for (const CFitField field : mesg.getFields()) { if (field.isValidValue()) { switch (field.getFieldDefNr()) { case eFieldDescriptionDeveloperDataIndex: devDataIdx = (quint8) field.getValue().toUInt(); break; case eFieldDescriptionFieldDefinitionNumber: fieldDefNr = (quint8) field.getValue().toUInt(); break; case eFieldDescriptionFitBaseTypeId: baseType = (quint8) field.getValue().toUInt(); // enum break; case eFieldDescriptionFieldName: fieldName = field.getValue().toString(); break; case eFieldDescriptionArray: array = (quint8) field.getValue().toUInt(); break; case eFieldDescriptionComponents: components = field.getValue().toString(); break; case eFieldDescriptionScale: scale = (qreal) field.getValue().toDouble(); break; case eFieldDescriptionOffset: offset = (qint16) field.getValue().toInt(); break; case eFieldDescriptionUnits: units = field.getValue().toString(); break; case eFieldDescriptionBits: bits = field.getValue().toString(); break; case eFieldDescriptionAccumulate: accumulate = field.getValue().toString(); break; case eFieldDescriptionFitBaseUnitId: baseUnitId = (quint8) field.getValue().toUInt(); // enum break; case eFieldDescriptionNativeMesgNum: natvieMesgNum = (quint8) field.getValue().toUInt(); // enum break; case eFieldDescriptionNativeFieldNum: nativeFieldNum = (quint8) field.getValue().toUInt(); break; default: throw tr("FIT decoding error: invalid field def nr %1 while creating dev field profile.") .arg(field.getFieldDefNr()); break; } } } Q_UNUSED(devDataIdx) Q_UNUSED(array) Q_UNUSED(baseUnitId) if (natvieMesgNum && nativeFieldNum) { const CFitFieldProfile* nativeFieldProfile = CFitProfileLookup::getFieldForProfile(natvieMesgNum, nativeFieldNum); if (nativeFieldProfile->getBaseType().nr() == eBaseTypeNrInvalid) { qWarning() << "DEV field"<< fieldName <<" field profile for mesg num"<< natvieMesgNum << "and field num" << nativeFieldNum << "does not exist."; } if (nativeFieldProfile->getUnits() != units) { qWarning() << "DEV field" << fieldName << "units" << units <<" do not match existing profile units" << nativeFieldProfile->getUnits(); } // scale and offset not allowed if a fit field is overwritten. scale = 0; offset = 0; } CFitFieldProfile devFieldProfile = CFitFieldProfile(nullptr, fieldName, *CFitBaseTypeMap::get(baseType), fieldDefNr, scale, offset, units, eFieldTypeDevelopment); // for documentation: the development field profile may contain more fields in the future as can be adumbrated by // the description field enumeration. According to the FIT specification Rev 2.3 table 4-9 - Field Description Messages // those fields are not yet used. return devFieldProfile; }qmapshack-1.10.0/src/gis/fit/decoder/CFitCrcState.cpp000644 001750 000144 00000002374 13216234140 023446 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitCrcState.h" void CFitCrcState::reset() { } decode_state_e CFitCrcState::process(quint8 &dataByte) { if (bytesLeftToRead() == 0) { // last CRC byte. if (getCrc() != 0) { throw tr("FIT decoding error : invalid CRC."); } return eDecoderStateEnd; } // 2nd crc byte left return eDecoderStateFileCrc; } qmapshack-1.10.0/src/gis/fit/decoder/CFitField.cpp000644 001750 000144 00000007137 13216234140 022763 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/decoder/CFitField.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" CFitField::CFitField(const CFitFieldDefinition& fieldDefinition, const CFitFieldProfile* profile, QVariant value, bool valid) : fieldProfile(profile), globalMesgNr(fieldDefinition.parent().getGlobalMesgNr()), fieldDefNr(fieldDefinition.getDefNr()), baseType(&fieldDefinition.getBaseType()), valid(valid), value(value), rawValue(value) { applyScaleAndOffset(); } CFitField::CFitField(quint16 globalMesgNr, quint8 fieldDefNr, const CFitFieldProfile* profile, QVariant value, bool valid) : fieldProfile(profile), globalMesgNr(globalMesgNr), fieldDefNr(fieldDefNr), baseType(&profile->getBaseType()), valid(valid), value(value), rawValue(value) { applyScaleAndOffset(); } CFitField::CFitField(const CFitField & copy) : fieldProfile(copy.fieldProfile), globalMesgNr(copy.globalMesgNr), fieldDefNr(copy.fieldDefNr), baseType(copy.baseType), valid(copy.valid), value(copy.value), rawValue(copy.rawValue) { } CFitField::CFitField() : fieldProfile(CFitProfileLookup::getFieldForProfile(fitGlobalMesgNrInvalid, fitFieldDefNrInvalid)), globalMesgNr(fitGlobalMesgNrInvalid), fieldDefNr(fitFieldDefNrInvalid), baseType(&fitInvalidType), valid(false), value(), rawValue() { } void CFitField::applyScaleAndOffset() { if(fieldProfile->hasScaleAndOffset()) { // scale and offset is only for int / sint types if(baseType->isUnsignedInt()) { value = QVariant(rawValue.toUInt()/ profile().getScale() - profile().getOffset()); } if(baseType->isSignedInt()) { value = QVariant(rawValue.toInt()/ profile().getScale() - profile().getOffset()); } } else { value = rawValue; } } void CFitField::setProfile(const CFitFieldProfile* profile) { fieldProfile = profile; applyScaleAndOffset(); } QString CFitField::fieldInfo() const { QString str = QString("%1 %2%3 (%4): %5 %6 %7 %8") .arg(profile().getTyp()) .arg(profile().getName()) .arg(profile().getFieldType() == eFieldTypeDevelopment ? " DEV" : "") .arg(getFieldDefNr()) .arg(value.toString()) .arg(profile().getUnits()) .arg(getBaseType().name()) .arg(valid ? "" : ""); if(getBaseType().isNumber()) { str += QString(" (%1/%2-%3)") .arg(rawValue.toString()) .arg(profile().getScale()) .arg( profile().getOffset()); } return str; } qmapshack-1.10.0/src/gis/fit/decoder/CFitFieldBuilder.h000644 001750 000144 00000003345 13216234143 023737 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITFIELDBUILDER_H #define CFITFIELDBUILDER_H #include class CFitField; class CFitMessage; class CFitFieldDefinition; class CFitFieldProfile; class CFitFieldBuilder { Q_DECLARE_TR_FUNCTIONS(CFitFieldBuilder) public: CFitFieldBuilder() = delete; static void evaluateSubfieldsAndExpandComponents(CFitMessage& mesg); static CFitField buildField(const CFitFieldDefinition& def, quint8* fieldData, const CFitMessage& message); static CFitField buildField(const CFitFieldProfile &fieldProfile, const CFitFieldDefinition& def, quint8* fieldData, const CFitMessage& message); private: static bool isValueValid(const CFitFieldDefinition &def, quint8 *fieldData); static void evaluateFieldProfile(CFitMessage& mesg, const CFitField & field); static void expandComponents(CFitMessage& mesg, const CFitField & field); }; #endif //CFITFIELDBUILDER_H qmapshack-1.10.0/src/gis/fit/decoder/CFitDefinitionMessage.cpp000644 001750 000144 00000011036 13216234140 025326 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/defs/CFitProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" static const quint8 fitArchitecureEndianMask = 0x01; CFitDefinitionMessage::CFitDefinitionMessage() : CFitDefinitionMessage(fitLocalMesgNrInvalid, false) { } CFitDefinitionMessage::CFitDefinitionMessage(const CFitDefinitionMessage& copy) : globalMesgNr(copy.globalMesgNr), architecture(copy.architecture), nrOfFields(copy.nrOfFields), nrOfDevFields(copy.nrOfDevFields), localMesgNr(copy.localMesgNr), devFlag(copy.devFlag), fields(copy.fields), devFields(copy.devFields), messageProfile(CFitProfileLookup::getProfile(globalMesgNr)) { for(CFitFieldDefinition& field : fields) { field.setParent(this); } } CFitDefinitionMessage::CFitDefinitionMessage(quint8 localMesgNr, bool devFlag) : globalMesgNr(fitGlobalMesgNrInvalid), architecture(0), nrOfFields(0), nrOfDevFields(0), localMesgNr(localMesgNr), devFlag(devFlag), fields(), devFields(), messageProfile(CFitProfileLookup::getProfile(fitGlobalMesgNrInvalid)) { } void CFitDefinitionMessage::setArchiteture(quint8 arch) { architecture = arch; } void CFitDefinitionMessage::setGlobalMesgNr(quint16 globalMesgNr) { this->globalMesgNr = globalMesgNr; messageProfile = CFitProfileLookup::getProfile(globalMesgNr); } void CFitDefinitionMessage::setNrOfFields(quint8 nrOfFields) { this->nrOfFields = nrOfFields; } void CFitDefinitionMessage::setNrOfDevFields(quint8 nrOfDevFields) { this->nrOfDevFields = nrOfDevFields; } quint8 CFitDefinitionMessage::getArchitectureBit() const { return architecture & fitArchitecureEndianMask; } void CFitDefinitionMessage::addField(CFitFieldDefinition fieldDef) { fields.append(fieldDef); } void CFitDefinitionMessage::addDevField(CFitFieldDefinition fieldDef) { devFields.append(fieldDef); } bool CFitDefinitionMessage::hasField(const quint8 fieldNum) const { for (int i=0; i< fields.size(); i++) { if (fieldNum == fields[i].getDefNr()) { return true; } } return false; } const CFitFieldDefinition& CFitDefinitionMessage::getField(const quint8 fieldNum) const { for (int i=0; i< fields.size(); i++) { if (fieldNum == fields[i].getDefNr()) { return fields[i]; } } // dummy field for unknown field nr. static const CFitFieldDefinition dummyDefinitionField; return dummyDefinitionField; } const CFitFieldDefinition& CFitDefinitionMessage::getFieldByIndex(const quint16 index) const { if (index < fields.size()) { return fields[index]; } // dummy field for unknown field nr. static const CFitFieldDefinition dummyDefinitionField; return dummyDefinitionField; } const CFitFieldDefinition& CFitDefinitionMessage::getDevFieldByIndex(const quint16 index) const { if (index < devFields.size()) { return devFields[index]; } // dummy field for unknown field nr. static const CFitFieldDefinition dummyDefinitionDevField; return dummyDefinitionDevField; } QStringList CFitDefinitionMessage::messageInfo() const { QStringList list; list << QString("Definition %1 (%2) local nr %3, arch %4, # fields %5, # dev fields %6") .arg(profile().getName()) .arg(getGlobalMesgNr()) .arg(getLocalMesgNr()) .arg(getArchitectureBit()) .arg(getNrOfFields()) .arg(getNrOfDevFields()); for(const CFitFieldDefinition& field: fields) { list << field.fieldInfo(); } for(const CFitFieldDefinition& devField: devFields) { list << devField.fieldInfo(); } return list; } qmapshack-1.10.0/src/gis/fit/decoder/CFitDevFieldDefinition.cpp000644 001750 000144 00000003370 13216234140 025426 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/decoder/CFitDevFieldDefinition.h" #include "gis/fit/decoder/CFitDefinitionMessage.h" #include "gis/fit/defs/CFitBaseType.h" #include "gis/fit/defs/CFitFieldProfile.h" #include "gis/fit/defs/CFitProfileLookup.h" #include "gis/fit/defs/fit_const.h" CFitDevFieldDefinition::CFitDevFieldDefinition(quint8 fieldNr, quint8 size, quint8 devDataIndex) : fieldNr(fieldNr), size(size), devDataIndex(devDataIndex) { } QString CFitDevFieldDefinition::fieldInfo() const { QString fstr = QString("DEV FIELD %1: type %3, size %3") .arg(getFieldNr()) .arg(getSize()) .arg(getDevDataIndex()); return fstr; } quint8 CFitDevFieldDefinition::getFieldNr() const { return fieldNr; } quint8 CFitDevFieldDefinition::getSize() const { return size; } quint8 CFitDevFieldDefinition::getDevDataIndex() const { return devDataIndex; }qmapshack-1.10.0/src/gis/fit/CFitStream.cpp000644 001750 000144 00000004033 13216234140 021556 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 "gis/fit/CFitStream.h" #include "gis/fit/defs/fit_const.h" void CFitStream::decodeFile() { decode.decode(file); } void CFitStream::reset() { readPos = 0; } const CFitMessage& CFitStream::nextMesg() { return decode.getMessages().at(readPos++); } const CFitMessage& CFitStream::lastMesg() const { int pos = readPos-1; if(pos < 0) { pos = 0; } return decode.getMessages().at(pos); } bool CFitStream::hasMoreMesg() const { return readPos < decode.getMessages().size(); } const CFitMessage& CFitStream::nextMesgOf(quint16 mesgNum) { while(hasMoreMesg()) { const CFitMessage& mesg = nextMesg(); if (mesg.getGlobalMesgNr() == mesgNum) { return mesg; } } static const CFitMessage dummyMessage; return dummyMessage; } const CFitMessage& CFitStream::firstMesgOf(quint16 mesgNum) { reset(); const CFitMessage& mesg = nextMesgOf(mesgNum); reset(); return mesg; } int CFitStream::countMesgOf(quint16 mesgNr) { reset(); int c = 0; while(nextMesgOf(mesgNr).getGlobalMesgNr() != fitGlobalMesgNrInvalid) { c++; } reset(); return c; } qmapshack-1.10.0/src/gis/fit/CFitProject.h000644 001750 000144 00000003273 13216234143 021406 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2015 Ivo Kronenberg 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 . **********************************************************************************************/ #ifndef CFITPROJECT_H #define CFITPROJECT_H #include "gis/prj/IGisProject.h" #include class CFitStream; class CFitProject final : public IGisProject { Q_DECLARE_TR_FUNCTIONS(CFitProject) public: CFitProject(const QString& filename, CGisListWks * parent); CFitProject(const QString& filename, IDevice * parent); virtual ~CFitProject(); const QString getFileDialogFilter() const override { return IGisProject::filedialogFilterFIT; } const QString getFileExtension() const override { return "fit"; } bool canSave() const override { return false; } private: void loadFitFromFile(const QString &filename, bool showErrorMsg); void tryOpeningFitFile(const QString &filename); void createGisItems(QFile& file); }; #endif //CFITPROJECT_H qmapshack-1.10.0/src/gis/WptIcons.h000644 001750 000144 00000002751 13216234143 020216 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef WPTICONS_H #define WPTICONS_H #include #include struct icon_t { icon_t() : focus(16,16) { } icon_t(const QString& path, int x, int y) : path(path), focus(x,y) { } QString path; QPoint focus; }; void initWptIcons(); const QMap &getWptIcons(); QPixmap getWptIconByName(const QString& name, QPointF &focus, QString * src = nullptr); void setWptIconByName(const QString& name, const QString& filename); void setWptIconByName(const QString& name, const QPixmap& icon); QPixmap loadIcon(const QString& path); #endif //WPTICONS_H qmapshack-1.10.0/src/gis/CSelDevices.h000644 001750 000144 00000002406 13216234143 020576 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSELDEVICES_H #define CSELDEVICES_H #include "ui_ISelDevices.h" #include class QTreeWidget; class IGisProject; class CSelDevices : public QDialog, private Ui::ISelDevices { Q_OBJECT public: CSelDevices(IGisProject *project, QTreeWidget * wks); virtual ~CSelDevices(); void getSlectedDevices(QSet& keys); }; #endif //CSELDEVICES_H qmapshack-1.10.0/src/gis/CGisListWks.cpp000644 001750 000144 00000176372 13216234261 021165 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) #include "device/CDeviceWatcherLinux.h" #endif #ifdef Q_OS_WIN #include "device/CDeviceWatcherWindows.h" #endif #ifdef Q_OS_MAC #include "device/CDeviceWatcherMac.h" #endif #include "device/IDevice.h" #include "gis/CGisDatabase.h" #include "gis/CGisListWks.h" #include "gis/CGisWorkspace.h" #include "gis/CSelDevices.h" #include "gis/IGisItem.h" #include "gis/db/CDBProject.h" #include "gis/db/CLostFoundProject.h" #include "gis/db/CSelectDBFolder.h" #include "gis/db/CSetupFolder.h" #include "gis/db/macros.h" #include "gis/fit/CFitProject.h" #include "gis/gpx/CGpxProject.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/qlb/CQlbProject.h" #include "gis/qms/CQmsProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/search/CSearchGoogle.h" #include "gis/slf/CSlfProject.h" #include "gis/suunto/CLogProject.h" #include "gis/suunto/CSmlProject.h" #include "gis/tcx/CTcxProject.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CProgressDialog.h" #include "helpers/CSelectCopyAction.h" #include "helpers/CSelectProjectDialog.h" #include "helpers/CSettings.h" #include "helpers/CWptIconDialog.h" #include "setup/IAppSetup.h" #include #include #include using std::bind; #undef DB_VERSION #define DB_VERSION 3 class CGisListWksEditLock { public: CGisListWksEditLock(bool waitCursor, QMutex& mutex) : mutex(mutex), waitCursor(waitCursor) { if(waitCursor) { CCanvas::setOverrideCursor(Qt::WaitCursor, "CGisListWksEditLock"); } mutex.lock(); } ~CGisListWksEditLock() { if(waitCursor) { CCanvas::restoreOverrideCursor("~CGisListWksEditLock"); } mutex.unlock(); } private: QMutex& mutex; bool waitCursor; }; CGisListWks::CGisListWks(QWidget *parent) : QTreeWidget(parent) { db = QSqlDatabase::addDatabase("QSQLITE","Workspace1"); QString config = QDir(IAppSetup::getPlatformInstance()->userDataPath()).filePath("workspace.db"); db.setDatabaseName(config); db.open(); configDB(); menuProjectWks = new QMenu(this); actionEditPrj = menuProjectWks->addAction(QIcon("://icons/32x32/EditDetails.png"), tr("Edit.." ), this, SLOT(slotEditPrj())); actionCopyPrj = menuProjectWks->addAction(QIcon("://icons/32x32/Copy.png" ), tr("Copy to..." ), this, SLOT(slotCopyProject())); actionShowOnMap = menuProjectWks->addAction(QIcon("://icons/32x32/ShowAll.png" ), tr("Show on Map" ), this, SLOT(slotShowOnMap())); actionHideFrMap = menuProjectWks->addAction(QIcon("://icons/32x32/ShowNone.png" ), tr("Hide from Map" ), this, SLOT(slotHideFrMap())); menuProjectWks->addSeparator(); actionGroup = new QActionGroup(menuProjectWks); actionGroup->setExclusive(true); actionSortByTime = addSortAction(menuProjectWks, actionGroup, "://icons/32x32/Time.png", tr("Sort by Time"), IGisProject::eSortFolderTime); actionSortByName = addSortAction(menuProjectWks, actionGroup, "://icons/32x32/SortName.png", tr("Sort by Name"), IGisProject::eSortFolderName); menuProjectWks->addSeparator(); actionAutoSave = menuProjectWks->addAction(QIcon("://icons/32x32/AutoSave.png"), tr("Autom. Save")); actionAutoSave->setCheckable(true); menuProjectWks->addSeparator(); actionSave = menuProjectWks->addAction(QIcon("://icons/32x32/SaveGIS.png" ), tr("Save" ), this, SLOT(slotSaveProject())); actionSaveAs = menuProjectWks->addAction(QIcon("://icons/32x32/SaveGISAs.png" ), tr("Save as..." ), this, SLOT(slotSaveAsProject())); actionSaveAsStrict = menuProjectWks->addAction(QIcon("://icons/32x32/SaveGISAsGpx11.png"), tr("Save as GPX 1.1 w/o ext..."), this, SLOT(slotSaveAsStrictGpx11Project())); menuProjectWks->addSeparator(); actionSyncWksDev = menuProjectWks->addAction(QIcon("://icons/32x32/Device.png" ), tr("Send to Devices"), this, SLOT(slotSyncWksDev())); actionSyncDB = menuProjectWks->addAction(QIcon("://icons/32x32/DatabaseSync.png" ), tr("Sync. with Database"), this, SLOT(slotSyncDB())); menuProjectWks->addSeparator(); actionCloseProj = menuProjectWks->addAction(QIcon("://icons/32x32/Close.png" ), tr("Close" ), this, SLOT(slotCloseProject())); menuProjectDev = new QMenu(this); menuProjectDev->addAction(actionEditPrj); menuProjectDev->addAction(actionCopyPrj); menuProjectDev->addAction(actionShowOnMap); menuProjectDev->addAction(actionHideFrMap); menuProjectDev->addSeparator(); menuProjectDev->addSeparator(); actionSyncDevWks= menuProjectDev->addAction(QIcon("://icons/32x32/Device.png"),tr("Update Project on Device"), this, SLOT(slotSyncDevWks())); menuProjectDev->addSeparator(); actionDelProj = menuProjectDev->addAction(QIcon("://icons/32x32/DeleteOne.png"),tr("Delete"), this, SLOT(slotDeleteProject())); menuProjectTrash= new QMenu(this); menuProjectTrash->addAction(actionSaveAs); menuProjectTrash->addAction(actionSaveAsStrict); menuProjectTrash->addAction(actionCloseProj); connect(this, &CGisListWks::customContextMenuRequested, this, &CGisListWks::slotContextMenu); connect(this, &CGisListWks::itemDoubleClicked, this, &CGisListWks::slotItemDoubleClicked); connect(this, &CGisListWks::itemChanged, this, &CGisListWks::slotItemChanged); menuItemTrk = new QMenu(this); actionEditDetails = menuItemTrk->addAction(QIcon("://icons/32x32/EditDetails.png"),tr("Edit..."), this, SLOT(slotEditItem())); actionCopyItem = menuItemTrk->addAction(QIcon("://icons/32x32/Copy.png"),tr("Copy to..."), this, SLOT(slotCopyItem())); menuItemTrk->addSeparator(); actionFocusTrk = menuItemTrk->addAction(QIcon("://icons/32x32/TrkProfile.png"),tr("Track Profile")); actionFocusTrk->setCheckable(true); actionRangeTrk = menuItemTrk->addAction(QIcon("://icons/32x32/SelectRange.png"), tr("Select Range" ), this, SLOT(slotRangeTrk())); actionEditTrk = menuItemTrk->addAction(QIcon("://icons/32x32/LineMove.png"), tr("Edit Track Points" ), this, SLOT(slotEditTrk())); actionReverseTrk = menuItemTrk->addAction(QIcon("://icons/32x32/Reverse.png"), tr("Reverse Track" ), this, SLOT(slotReverseTrk())); actionCombineTrk = menuItemTrk->addAction(QIcon("://icons/32x32/Combine.png"), tr("Combine Tracks" ), this, SLOT(slotCombineTrk())); actionActivityTrk= menuItemTrk->addAction(QIcon("://icons/32x32/Activity.png"), tr("Set Track Activity"), this, SLOT(slotActivityTrk())); actionCopyTrkWithWpt = menuItemTrk->addAction(QIcon("://icons/32x32/CopyTrkWithWpt.png"), tr("Copy Track with Waypoints"), this, SLOT(slotCopyTrkWithWpt())); menuItemTrk->addSeparator(); actionDelete = menuItemTrk->addAction(QIcon("://icons/32x32/DeleteOne.png"),tr("Delete"), this, SLOT(slotDeleteItem())); connect(menuItemTrk, &QMenu::triggered, &CGisWorkspace::self(), &CGisWorkspace::slotWksItemSelectionReset); menuItemWpt = new QMenu(this); menuItemWpt->addAction(actionEditDetails); menuItemWpt->addAction(actionCopyItem); menuItemWpt->addSeparator(); actionBubbleWpt = menuItemWpt->addAction(QIcon("://icons/32x32/Bubble.png"), tr("Show Bubble"), this, SLOT(slotBubbleWpt())); actionBubbleWpt->setCheckable(true); actionMoveWpt = menuItemWpt->addAction(QIcon("://icons/32x32/WptMove.png"), tr("Move Waypoint"), this, SLOT(slotMoveWpt())); actionProjWpt = menuItemWpt->addAction(QIcon("://icons/32x32/WptProj.png"), tr("Proj. Waypoint..."), this, SLOT(slotProjWpt())); actionEditRadiusWpt = menuItemWpt->addAction(QIcon("://icons/32x32/WptEditProx.png"), tr("Change Radius"), this, SLOT(slotEditRadiusWpt())); actionNogoAreaWpt = menuItemWpt->addAction(QIcon("://icons/32x32/WptAvoid.png"), tr("Toggle Nogo-Area"), this, SLOT(slotNogoAreaWpt())); actionNogoAreaWpt->setCheckable(true); actionDelRadiusWpt = menuItemWpt->addAction(QIcon("://icons/32x32/WptDelProx.png"), tr("Delete Radius"), this, SLOT(slotDelRadiusWpt())); menuItemWpt->addSeparator(); menuItemWpt->addAction(actionDelete); connect(menuItemWpt, &QMenu::triggered, &CGisWorkspace::self(), &CGisWorkspace::slotWksItemSelectionReset); menuItemRte = new QMenu(this); menuItemRte->addAction(actionEditDetails); menuItemRte->addAction(actionCopyItem); menuItemRte->addSeparator(); actionFocusRte = menuItemRte->addAction(QIcon("://icons/32x32/RteInstr.png"), tr("Route Instructions")); actionFocusRte->setCheckable(true); actionCalcRte = menuItemRte->addAction(QIcon("://icons/32x32/Apply.png"), tr("Calculate Route"), this, SLOT(slotCalcRte())); actionResetRte = menuItemRte->addAction(QIcon("://icons/32x32/Reset.png"), tr("Reset Route"), this, SLOT(slotResetRte())); actionEditRte = menuItemRte->addAction(QIcon("://icons/32x32/LineMove.png"), tr("Edit Route"), this, SLOT(slotEditRte())); actionRte2Trk = menuItemRte->addAction(QIcon("://icons/32x32/Track.png"), tr("Convert to Track"),this, SLOT(slotRte2Trk())); menuItemRte->addSeparator(); menuItemRte->addAction(actionDelete); connect(menuItemRte, &QMenu::triggered, &CGisWorkspace::self(), &CGisWorkspace::slotWksItemSelectionReset); menuItemOvl = new QMenu(this); menuItemOvl->addAction(actionEditDetails); menuItemOvl->addAction(actionCopyItem); menuItemOvl->addSeparator(); actionEditArea = menuItemOvl->addAction(QIcon("://icons/32x32/AreaMove.png"),tr("Edit Area Points"), this, SLOT(slotEditArea())); menuItemOvl->addSeparator(); menuItemOvl->addAction(actionDelete); connect(menuItemOvl, &QMenu::triggered, &CGisWorkspace::self(), &CGisWorkspace::slotWksItemSelectionReset); menuItem = new QMenu(this); menuItem->addAction(actionCopyItem); actionRteFromWpt = menuItem->addAction(QIcon("://icons/32x32/Route.png"), tr("Create Route"), this, SLOT(slotRteFromWpt())); actionSymWpt = menuItem->addAction(QIcon("://icons/waypoints/32x32/PinBlue.png"), tr("Change Icon (sel. waypt. only)"), this, SLOT(slotSymWpt())); menuItem->addAction(actionCombineTrk); menuItem->addAction(actionActivityTrk); menuItem->addAction(actionDelete); connect(menuItem, &QMenu::triggered, &CGisWorkspace::self(), &CGisWorkspace::slotWksItemSelectionReset); connect(actionFocusTrk, &QAction::triggered, this, &CGisListWks::slotFocusTrk); connect(actionFocusRte, &QAction::triggered, this, &CGisListWks::slotFocusRte); connect(actionAutoSave, &QAction::triggered, this, &CGisListWks::slotAutoSaveProject); connect(qApp, &QApplication::aboutToQuit, this, &CGisListWks::slotSaveWorkspace); SETTINGS; saveOnExit = cfg.value("Database/saveOnExit", saveOnExit).toBool(); saveEvery = cfg.value("Database/saveEvery", saveEvery).toInt(); if(saveOnExit && (saveEvery > 0)) { QTimer::singleShot(saveEvery * 60000, this, SLOT(slotSaveWorkspace())); } #ifdef Q_OS_MAC deviceWatcher = new CDeviceWatcherMac(this); connect(deviceWatcher, &CDeviceWatcherMac::sigChanged, this, &CGisListWks::sigChanged); #else #ifdef Q_OS_WIN deviceWatcher = new CDeviceWatcherWindows(this); connect(deviceWatcher, &CDeviceWatcherWindows::sigChanged, this, &CGisListWks::sigChanged); #else #ifdef HAVE_DBUS deviceWatcher = new CDeviceWatcherLinux(this); connect(deviceWatcher, &CDeviceWatcherLinux::sigChanged, this, &CGisListWks::sigChanged); #endif // HAVE_DBUS #endif // Q_OS_WIN #endif // Q_OS_MAC } CGisListWks::~CGisListWks() { } void CGisListWks::configDB() { QSqlQuery query(db); QUERY_RUN("PRAGMA locking_mode=EXCLUSIVE", return ) QUERY_RUN("PRAGMA synchronous=OFF", return ) QUERY_RUN("PRAGMA temp_store=MEMORY", return ) QUERY_RUN("PRAGMA default_cache_size=50", return ) QUERY_RUN("PRAGMA page_size=8192", return ) // When migrating the database these tables are used. // Due to caching they can't be dropped right after the // migration. That is why we look for them on startup. // And delete them as a second chance. if(query.exec("select * from tmp_workspace")) { QUERY_RUN("DROP TABLE tmp_workspace;", return ); } if(!query.exec("SELECT version FROM versioninfo")) { initDB(); } else if(query.next()) { int version = query.value(0).toInt(); if(version != DB_VERSION) { migrateDB(version); } } else { initDB(); } } void CGisListWks::initDB() { QSqlQuery query(db); if(query.exec( "CREATE TABLE versioninfo ( version TEXT )")) { query.prepare( "INSERT INTO versioninfo (version) VALUES(:version)"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(); } QUERY_RUN("CREATE TABLE workspace (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," "name TEXT NOT NULL," "keyqms TEXT NOT NULL," "changed BOOLEAN DEFAULT FALSE," "visible BOOLEAN DEFAULT TRUE," "data BLOB NOT NULL" ")", NO_CMD) } void CGisListWks::migrateDB(int version) { qDebug() << "workspace.db has version " << version << ", migration to version " << DB_VERSION << " required"; // try to migrate between the database versions step by step (as soon as applicable) if(version < 2) { migrateDB1to2(); } if(version < 3) { migrateDB2to3(); } // save the new version to the database QSqlQuery query(db); query.prepare( "UPDATE versioninfo set version=:version"); query.bindValue(":version", DB_VERSION); QUERY_EXEC(); } void CGisListWks::migrateDB1to2() { qDebug() << "migrating workspace.db from version 1 to version 2"; // add a new column `visible` to the database // the default value is `true`, as - by default in older versions of QMS - all saved projects // have been loaded and shown on the map directly after starting QSqlQuery query(db); QUERY_RUN("ALTER TABLE workspace ADD COLUMN visible BOOLEAN DEFAULT TRUE;", NO_CMD) } void CGisListWks::migrateDB2to3() { QSqlQuery query(db); QUERY_RUN("BEGIN TRANSACTION;", return ) QUERY_RUN("ALTER TABLE workspace RENAME TO tmp_workspace;", return ) QUERY_RUN("CREATE TABLE workspace (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," "name TEXT NOT NULL," "keyqms TEXT NOT NULL," "changed BOOLEAN DEFAULT FALSE," "visible BOOLEAN DEFAULT TRUE," "data BLOB NOT NULL" ")", return ); QUERY_RUN("INSERT INTO workspace(id,type,name,keyqms,changed,visible,data) SELECT * FROM tmp_workspace;", return ) QUERY_RUN("COMMIT;", return ) QUERY_RUN("DROP TABLE tmp_workspace;", return ) } void CGisListWks::setExternalMenu(QMenu * project) { menuNone = project; connect(CMainWindow::self().findChild("actionAddEmptyProject"), &QAction::triggered, this, &CGisListWks::slotAddEmptyProject); connect(CMainWindow::self().findChild("actionCloseAllProjects"), &QAction::triggered, this, &CGisListWks::slotCloseAllProjects); connect(CMainWindow::self().findChild("actionSearchGoogle"), &QAction::triggered, this, &CGisListWks::slotSearchGoogle); } QAction * CGisListWks::addSortAction(QMenu * menu, QActionGroup * actionGroup, const QString& icon, const QString& text, IGisProject::sorting_folder_e mode) { QAction * action = menu->addAction(QIcon(icon), text); action->setCheckable(true); auto func = std::bind(&CGisListWks::slotSetSortMode, this, mode, std::placeholders::_1); connect(action, &QAction::toggled, this, func); actionGroup->addAction(action); return action; } void CGisListWks::dragMoveEvent(QDragMoveEvent * e ) { CGisListWksEditLock lock(true, IGisItem::mutexItems); QTreeWidgetItem * item1 = currentItem(); QTreeWidgetItem * item2 = itemAt(e->pos()); // changing the item order is only valid for single selected items if(selectedItems().count() == 1) { /* What's happening here? 1) Cast current item and item under cursor to GIS item type 2) If type matches for both test for common parent 2.1) common parent-> move 2.1) different parent -> copy 3) go on with dragMoveEvent(); */ CGisItemTrk * trk1 = dynamic_cast(item1); CGisItemTrk * trk2 = dynamic_cast(item2); if(trk1 && trk2) { e->setDropAction( trk1->parent() == trk2->parent() ? Qt::MoveAction : Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } CGisItemWpt * wpt1 = dynamic_cast(item1); CGisItemWpt * wpt2 = dynamic_cast(item2); if(wpt1 && wpt2) { e->setDropAction( wpt1->parent() == wpt2->parent() ? Qt::MoveAction : Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } CGisItemRte * rte1 = dynamic_cast(item1); CGisItemRte * rte2 = dynamic_cast(item2); if(rte1 && rte2) { e->setDropAction( rte1->parent() == rte2->parent() ? Qt::MoveAction : Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } CGisItemOvlArea * area1 = dynamic_cast(item1); CGisItemOvlArea * area2 = dynamic_cast(item2); if(area1 && area2) { e->setDropAction( area1->parent() == area2->parent() ? Qt::MoveAction : Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } /* Never move/copy projects on devices. Data has to be removed or changed to store a project and it's items on a device. Moving it back to the workspace would conflict with the original project. To much hassle to resolve this properly. */ IGisProject * proj1 = dynamic_cast(item1); if(proj1 && proj1->isOnDevice()) { e->setDropAction(Qt::IgnoreAction); QTreeWidget::dragMoveEvent(e); return; } } /* Test for other project, to change project order. But if other project is on a device block the request. A project has to be copied to the device via it's device item. */ IGisProject * proj2 = dynamic_cast(item2); if(proj2) { IGisProject * proj1 = dynamic_cast(item1); if(proj1) { e->setDropAction(proj2->isOnDevice() ? Qt::IgnoreAction : Qt::MoveAction); QTreeWidget::dragMoveEvent(e); return; } IGisItem * gisItem1 = dynamic_cast(item1); if(gisItem1) { e->setDropAction(Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } } /* Test for device as drop target. A device will copy the project into it's own supported format. */ IDevice * device = dynamic_cast(item2); if(device) { IGisProject * proj1 = dynamic_cast(item1); if(proj1 && !proj1->isOnDevice()) { e->setDropAction(Qt::CopyAction); QTreeWidget::dragMoveEvent(e); return; } } e->setDropAction(Qt::IgnoreAction); QTreeWidget::dragMoveEvent(e); } void CGisListWks::dropEvent( QDropEvent * e ) { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList items = selectedItems(); if(items.isEmpty()) { return; } int lastResult = CSelectCopyAction::eResultNone; // go on with item insertion /* What's happening here? for single selected items do: 1) Test if item will be inserted above ore below item under cursor. 2) Cast current item and item under cursor to GIS item type 3) If type matches for both test for common parent 3.1) common parent-> go on with default drop event 3.1) different parent -> create a copy and insert it index 4) signal change of project for single and multiple selected items, do: 5) Test if item under cursor is a project 6) If project and project is not item's project create a copy */ if(items.size() == 1) { // calc. index offset (below/above item) QRect r = visualItemRect(itemAt(e->pos())); int y1 = r.top() + r.height()/2; int y2 = e->pos().y(); int off = y2 > y1 ? 1 : 0; IGisProject * prj1 = dynamic_cast(currentItem()); IGisProject * prj2 = dynamic_cast(itemAt(e->pos())); if(prj1 && prj2) { prj2->setFlags(prj2->flags() & ~Qt::ItemIsDropEnabled); QTreeWidget::dropEvent(e); prj2->setFlags(prj2->flags() | Qt::ItemIsDropEnabled); emit sigChanged(); return; } CGisItemWpt * wpt1 = dynamic_cast(currentItem()); CGisItemWpt * wpt2 = dynamic_cast(itemAt(e->pos())); if(wpt1 && wpt2) { if(wpt1->parent() == wpt2->parent()) { QTreeWidget::dropEvent(e); } else { IGisProject * project = dynamic_cast(wpt2->parent()); if(project) { project->insertCopyOfItem(wpt1, off, lastResult); } } emit sigChanged(); return; } CGisItemTrk * trk1 = dynamic_cast(currentItem()); CGisItemTrk * trk2 = dynamic_cast(itemAt(e->pos())); if(trk1 && trk2) { if(trk1->parent() == trk2->parent()) { QTreeWidget::dropEvent(e); } else { IGisProject * project = dynamic_cast(trk2->parent()); if(project) { project->insertCopyOfItem(trk1, off, lastResult); } } emit sigChanged(); return; } CGisItemRte * rte1 = dynamic_cast(currentItem()); CGisItemRte * rte2 = dynamic_cast(itemAt(e->pos())); if(rte1 && rte2) { if(rte1->parent() == rte2->parent()) { QTreeWidget::dropEvent(e); } else { IGisProject * project = dynamic_cast(rte2->parent()); if(project) { project->insertCopyOfItem(rte1, off, lastResult); } } emit sigChanged(); return; } CGisItemOvlArea * area1 = dynamic_cast(currentItem()); CGisItemOvlArea * area2 = dynamic_cast(itemAt(e->pos())); if(area1 && area2) { if(area1->parent() == area2->parent()) { QTreeWidget::dropEvent(e); } else { IGisProject * project = dynamic_cast(area2->parent()); if(project) { project->insertCopyOfItem(area1, off, lastResult); } } emit sigChanged(); return; } } // check if item at position is a project and insert a copy of all selected items IGisProject * project = dynamic_cast(itemAt(e->pos())); if(project) { project->blockUpdateItems(true); int cnt = 1; int N = items.size(); PROGRESS_SETUP(tr("Drop items..."), 0, N, this); for(QTreeWidgetItem * item : items) { PROGRESS(cnt++, break); IGisItem * gisItem = dynamic_cast(item); if(gisItem) { project->insertCopyOfItem(gisItem, NOIDX, lastResult); } } project->blockUpdateItems(false); } IDevice * device = dynamic_cast(itemAt(e->pos())); if(device) { IGisProject * project = dynamic_cast(currentItem()); if(project) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->reportStatus("device", tr("Update devices

Update %1
Please wait...

").arg(device->text(CGisListWks::eColumnName))); canvas->update(); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } int lastResult = CSelectCopyAction::eResultNone; device->insertCopyOfProject(project, lastResult); if(canvas) { canvas->reportStatus("device", ""); } } } emit sigChanged(); } void CGisListWks::addProject(IGisProject *proj) { if(!proj->isValid()) { return; } addTopLevelItem(proj); // move project up the list until there a re only projects, no devices int newIdx = NOIDX; const int myIdx = topLevelItemCount() - 1; for(int i = myIdx - 1; i >= 0; i--) { IDevice * device = dynamic_cast(topLevelItem(i)); if(nullptr == device) { break; } newIdx = i; } if(newIdx != NOIDX) { takeTopLevelItem(myIdx); insertTopLevelItem(newIdx, proj); } } void CGisListWks::removeDevice(const QString& key) { CGisListWksEditLock lock(true, IGisItem::mutexItems); for(int i = 0; i < topLevelItemCount(); i++) { IDevice * device = dynamic_cast(topLevelItem(i)); if(device && device->getKey() == key) { delete device; emit sigChanged(); return; } } } bool CGisListWks::hasProject(IGisProject * project) { CGisListWksEditLock lock(true, IGisItem::mutexItems); QString key = project->getKey(); for(int i = 0; i < topLevelItemCount(); i++) { IGisProject * item = dynamic_cast(topLevelItem(i)); if(item && item->getKey() == key && item != project) { return true; } } return false; } IGisProject * CGisListWks::getProjectByKey(const QString& key) { CGisListWksEditLock lock(true, IGisItem::mutexItems); for(int i = 0; i < topLevelItemCount(); i++) { IGisProject * item = dynamic_cast(topLevelItem(i)); if(item && item->getKey() == key) { return item; } } return nullptr; } CDBProject * CGisListWks::getProjectById(quint64 id, const QString& db) { CGisListWksEditLock lock(true, IGisItem::mutexItems); for(int i = 0; i < topLevelItemCount(); i++) { CDBProject * item = dynamic_cast(topLevelItem(i)); if(item && item->getId() == id && item->getDBName() == db) { return item; } } return nullptr; } void CGisListWks::slotSaveWorkspace() { CGisListWksEditLock lock(true,IGisItem::mutexItems); if(!saveOnExit) { return; } QSqlQuery query(db); QUERY_RUN("DELETE FROM workspace", return ) qDebug() << "slotSaveWorkspace()"; const int total = topLevelItemCount(); PROGRESS_SETUP(tr("Saving workspace. Please wait."), 0, total, this); for(int i = 0; i < total; i++) { PROGRESS(i, return ); IGisProject * project = dynamic_cast(topLevelItem(i)); if(nullptr == project) { continue; } QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_5_2); stream.setByteOrder(QDataStream::LittleEndian); project->IGisProject::operator>>(stream); query.prepare("INSERT INTO workspace (type, keyqms, name, changed, visible, data) VALUES (:type, :keyqms, :name, :changed, :visible, :data)"); query.bindValue(":type", project->getType()); query.bindValue(":keyqms", project->getKey()); query.bindValue(":name", project->getName()); query.bindValue(":changed", project->isChanged()); bool visible = (project->checkState(CGisListDB::eColumnCheckbox) == Qt::Checked); query.bindValue(":visible", visible); query.bindValue(":data", data); QUERY_EXEC(continue); } if(saveEvery) { QTimer::singleShot(saveEvery * 60000, this, SLOT(slotSaveWorkspace())); } } void CGisListWks::slotLoadWorkspace() { CGisListWksEditLock lock(true,IGisItem::mutexItems); QSqlQuery query(db); QUERY_RUN("SELECT type, keyqms, name, changed, visible, data FROM workspace", return ) const int total = query.size(); PROGRESS_SETUP(tr("Loading workspace. Please wait."), 0, total, this); quint32 progCnt = 0; while(query.next()) { PROGRESS(progCnt++, return ); int type = query.value(0).toInt(); QString name = query.value(2).toString(); bool changed = query.value(3).toBool(); Qt::CheckState visible = query.value(4).toBool() ? Qt::Checked : Qt::Unchecked; QByteArray data = query.value(5).toByteArray(); QDataStream stream(&data, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_5_2); stream.setByteOrder(QDataStream::LittleEndian); IGisProject *project = nullptr; switch(type) { case IGisProject::eTypeQms: { project = new CQmsProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); // (1a) *project << stream; break; } case IGisProject::eTypeQlb: { project = new CQlbProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); // (1a) *project << stream; break; } case IGisProject::eTypeGpx: { project = new CGpxProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); // (1b) *project << stream; break; } case IGisProject::eTypeDb: { CDBProject * dbProject; project = dbProject = new CDBProject(this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); // (1c) project->IGisProject::operator<<(stream); dbProject->restoreDBLink(); if(!project->isValid()) { delete project; project = nullptr; } else { dbProject->postStatus(false); } break; } case IGisProject::eTypeSlf: { project = new CSlfProject(name, false); project->setCheckState(CGisListDB::eColumnCheckbox, visible); // (1d) *project << stream; // the CSlfProject does not - as the other C*Project - register itself in the list // of currently opened projects. This is done manually here. addProject(project); break; } case IGisProject::eTypeFit: { project = new CFitProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); *project << stream; break; } case IGisProject::eTypeTcx: { project = new CTcxProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); *project << stream; break; } case IGisProject::eTypeSml: { project = new CSmlProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); *project << stream; break; } case IGisProject::eTypeLog: { project = new CSmlProject(name, this); project->setCheckState(CGisListDB::eColumnCheckbox, visible); *project << stream; break; } } if(nullptr != project) { // Hiding the individual projects from the map (1a, 1b, 1c) could be done here within a single statement, // but this results in a visible `the checkbox is being unchecked`, especially in case the project // is large and takes some time to load. // When done directly after construction there is no `blinking` of the check mark project->setToolTip(eColumnName,project->getInfo()); if(changed) { project->setChanged(); } } } emit sigChanged(); } void CGisListWks::slotContextMenu(const QPoint& point) { QPoint p = mapToGlobal(point); if(selectedItems().isEmpty() && menuNone) { menuNone->exec(p); return; } // check whether all projects are checked or unchecked... bool allChecked = true; bool allUnchecked = true; bool allCantSave = true; for(QTreeWidgetItem *item : selectedItems()) { IGisProject *project = dynamic_cast(item); if(nullptr != project) { // as soon as we find an unchecked element, not all elements are checked (and vice versa) if(project->checkState(CGisListDB::eColumnCheckbox) == Qt::Unchecked) { allChecked = false; } else { allUnchecked = false; } if(project->canSave()) { allCantSave = false; } } } // ...and disable entries without any effect actionShowOnMap->setEnabled(!allChecked); actionHideFrMap->setEnabled(!allUnchecked); actionSave->setEnabled(!allCantSave); if(selectedItems().count() > 1) { IGisProject *project = dynamic_cast(currentItem()); if(nullptr != project) { if(project->isOnDevice()) { menuProjectDev->exec(p); } else { actionGroup->setEnabled(false); actionSyncWksDev->setEnabled(IDevice::count()); actionSyncDB->setEnabled(project->getType() == IGisProject::eTypeDb); actionAutoSave->setVisible(false); menuProjectWks->exec(p); } return; } IGisItem *gisItem = dynamic_cast(currentItem()); if(nullptr != gisItem) { bool hasWpts = false; bool onlyWpts = true; bool onlyTrks = true; for(QTreeWidgetItem *item : selectedItems()) { if(item->type() != IGisItem::eTypeWpt) { onlyWpts = false; } else { hasWpts = true; } if(item->type() != IGisItem::eTypeTrk) { onlyTrks = false; } if(!onlyTrks && !onlyWpts) { break; } } actionRteFromWpt->setEnabled(onlyWpts); actionCombineTrk->setEnabled(onlyTrks); actionActivityTrk->setEnabled(onlyTrks); actionSymWpt->setEnabled(hasWpts); menuItem->exec(p); return; } return; } if(selectedItems().count() == 1) { IGisProject *project = dynamic_cast(currentItem()); if(nullptr != project) { if(project->getType() == IGisProject::eTypeLostFound) { menuProjectTrash->exec(p); } else { if(project->isOnDevice()) { menuProjectDev->exec(p); } else { actionGroup->setEnabled(true); actionSyncWksDev->setEnabled(IDevice::count()); actionSyncDB->setEnabled(project->getType() == IGisProject::eTypeDb); blockSorting = true; switch(project->getSortingFolder()) { case IGisProject::eSortFolderName: actionSortByName->setChecked(true); break; case IGisProject::eSortFolderTime: actionSortByTime->setChecked(true); break; } blockSorting = false; actionAutoSave->setVisible(true); actionAutoSave->setEnabled(project->canSave()); actionAutoSave->setChecked(project->isAutoSave()); menuProjectWks->exec(p); } } return; } IGisItem *gisItem = dynamic_cast(currentItem()); if(nullptr != gisItem) { bool isOnDevice = gisItem->isOnDevice(); switch(gisItem->type()) { case IGisItem::eTypeTrk: { CGisItemTrk * trk = dynamic_cast(gisItem); IGisProject * project = gisItem->getParentProject(); if(project != nullptr) { actionCombineTrk->setEnabled(project->getItemCountByType(IGisItem::eTypeTrk) > 1); } else { actionCombineTrk->setEnabled(false); } actionRangeTrk->setDisabled(isOnDevice); actionReverseTrk->setDisabled(isOnDevice); actionEditTrk->setDisabled(isOnDevice); actionCopyTrkWithWpt->setEnabled(trk->getNumberOfAttachedWpt() != 0); actionFocusTrk->setChecked(gisItem->hasUserFocus()); menuItemTrk->exec(p); break; } case IGisItem::eTypeWpt: { CGisItemWpt * wpt = dynamic_cast(gisItem); actionBubbleWpt->setChecked(wpt->hasBubble()); bool radius = wpt->hasRadius(); actionDelRadiusWpt->setEnabled(radius); actionNogoAreaWpt->setEnabled(radius); actionNogoAreaWpt->setChecked(radius && wpt->isNogoArea()); actionMoveWpt->setDisabled(isOnDevice); actionProjWpt->setDisabled(isOnDevice); menuItemWpt->exec(p); break; } case IGisItem::eTypeRte: actionFocusRte->setChecked(gisItem->hasUserFocus()); menuItemRte->exec(p); break; case IGisItem::eTypeOvl: actionEditArea->setDisabled(isOnDevice); menuItemOvl->exec(p); break; } return; } } } void CGisListWks::setVisibilityOnMap(bool visible) { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem *item : items) { IGisProject *project = dynamic_cast(item); if(nullptr != project) { project->setCheckState(CGisListDB::eColumnCheckbox, visible ? Qt::Checked : Qt::Unchecked); } } emit sigChanged(); } void CGisListWks::slotShowOnMap() { setVisibilityOnMap(true); } void CGisListWks::slotHideFrMap() { setVisibilityOnMap(false); } static void closeProjects(const QList &items) { for(QTreeWidgetItem * item : items) { IGisProject *project = dynamic_cast(item); if(nullptr != project) { if(project->askBeforClose()) { break; } if(IGisProject::eTypeGoogle == project->getType()) { CMainWindow::self().findChild("actionSearchGoogle")->setChecked(false); } delete project; } } } void CGisListWks::slotCloseProject() { CGisListWksEditLock lock(true, IGisItem::mutexItems); closeProjects(selectedItems()); emit sigChanged(); } void CGisListWks::slotCloseAllProjects() { int res = QMessageBox::question(this, tr("Close all projects..."), tr("This will remove all projects from the workspace."), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok); if(res != QMessageBox::Ok) { return; } CGisListWksEditLock lock(true, IGisItem::mutexItems); closeProjects(findItems("*", Qt::MatchWildcard)); CGisWorkspace::self().slotWksItemSelectionReset(); emit sigChanged(); } void CGisListWks::slotDeleteProject() { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem * item : items) { IGisProject * project = dynamic_cast(item); if(nullptr != project) { CCanvas::setOverrideCursor(Qt::ArrowCursor, "slotDeleteProject"); int res = QMessageBox::question(CMainWindow::getBestWidgetForParent(), tr("Delete project..."), tr("Do you really want to delete %1?").arg(project->getFilename()), QMessageBox::Ok|QMessageBox::No,QMessageBox::Ok); CCanvas::restoreOverrideCursor("slotDeleteProject"); if(res != QMessageBox::Ok) { continue; } if(project->remove()) { delete project; } } } emit sigChanged(); } void CGisListWks::slotSaveProject() { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem * item : items) { IGisProject * project = dynamic_cast(item); if(nullptr != project) { if(project->canSave()) { project->save(); } else { project->saveAs(); } } } } void CGisListWks::slotSaveAsProject() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem * item : items) { IGisProject * project = dynamic_cast(item); if(nullptr != project) { project->saveAs(); } } } void CGisListWks::slotSaveAsStrictGpx11Project() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem * item : items) { IGisProject * project = dynamic_cast(item); if(nullptr != project) { project->saveAsStrictGpx11(); } } } void CGisListWks::slotAutoSaveProject(bool on) { CGisListWksEditLock lock(false, IGisItem::mutexItems); IGisProject * project = dynamic_cast(currentItem()); if(project != nullptr) { project->setAutoSave(on); } } void CGisListWks::slotEditPrj() { CGisListWksEditLock lock(false, IGisItem::mutexItems); IGisProject * project = dynamic_cast(currentItem()); if(project != nullptr) { project->edit(); } } void CGisListWks::slotItemDoubleClicked(QTreeWidgetItem * item, int ) { CGisListWksEditLock lock(true, IGisItem::mutexItems); IGisItem * gisItem = dynamic_cast(item); if(gisItem != nullptr) { CGisWorkspace::self().slotWksItemSelectionReset(); CMainWindow::self().zoomCanvasTo(gisItem->getBoundingRect()); CGisWorkspace::self().focusTrkByKey(true, gisItem->getKey()); } } void CGisListWks::slotItemChanged(QTreeWidgetItem * item, int column) { CGisListWksEditLock lock(true, IGisItem::mutexItems); if(column == eColumnCheckBox) { emit sigChanged(); } } void CGisListWks::slotEditItem() { CGisListWksEditLock lock(false, IGisItem::mutexItems); IGisItem * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().editItemByKey(gisItem->getKey()); } } void CGisListWks::slotDeleteItem() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QList items = selectedItems(); QList keys; for(QTreeWidgetItem * item : items) { IGisItem * gisItem = dynamic_cast(item); if(gisItem != nullptr) { keys << gisItem->getKey(); } } CGisWorkspace::self().delItemsByKey(keys); } void CGisListWks::slotCopyItem() { CGisListWksEditLock lock(true, IGisItem::mutexItems); /* * Item selection is reset when the target project is a new database * project. Additionally the list of selected items pointers seems * to get invalid, causing a segfault when used. * * As a fix the keys of the selected items are stored temporarily and * later used to retrieve the item on the workspace via CGisWorkspace::getItemByKey() * again. This is always safe. */ QList items = selectedItems(); QList keys; for(QTreeWidgetItem * item : items) { IGisItem * gisItem = dynamic_cast(item); if(gisItem != nullptr) { keys << gisItem->getKey(); } } CGisWorkspace::self().copyItemsByKey(keys); } void CGisListWks::slotProjWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().projWptByKey(gisItem->getKey()); } } void CGisListWks::slotBubbleWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().toggleWptBubble(gisItem->getKey()); } } void CGisListWks::slotNogoAreaWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().toggleWptNogoArea(gisItem->getKey()); } } void CGisListWks::slotDelRadiusWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().deleteWptRadius(gisItem->getKey()); } } void CGisListWks::slotEditRadiusWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().editWptRadius(gisItem->getKey()); } } void CGisListWks::slotMoveWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemWpt * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().moveWptByKey(gisItem->getKey()); } } void CGisListWks::slotFocusTrk(bool on) { CGisListWksEditLock lock(true, IGisItem::mutexItems); CGisItemTrk * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().focusTrkByKey(on, gisItem->getKey()); } } void CGisListWks::slotEditTrk() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemTrk * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().editTrkByKey(gisItem->getKey()); } } void CGisListWks::slotReverseTrk() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemTrk * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().reverseTrkByKey(gisItem->getKey()); } } void CGisListWks::slotCombineTrk() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QList keys; QList items = selectedItems(); for(QTreeWidgetItem * item : items) { CGisItemTrk * gisItem = dynamic_cast(item); if(gisItem) { keys << gisItem->getKey(); } } if(!keys.isEmpty()) { if(keys.size() == 1) { CGisWorkspace::self().combineTrkByKey(keys.first()); } else { CGisWorkspace::self().combineTrkByKey(keys, keys); } } } void CGisListWks::slotActivityTrk() { quint32 flags = CActivityTrk::selectActivity(this); if(0xFFFFFFFF != flags) { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList items = selectedItems(); for(QTreeWidgetItem * item : items) { CGisItemTrk * trk = dynamic_cast(item); if(trk) { trk->setActivity(flags); } } } } void CGisListWks::slotRangeTrk() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemTrk * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().rangeTrkByKey(gisItem->getKey()); } } void CGisListWks::slotCopyTrkWithWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemTrk * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().copyTrkWithWptByKey(gisItem->getKey()); } } void CGisListWks::slotFocusRte(bool on) { CGisListWksEditLock lock(true, IGisItem::mutexItems); CGisItemRte * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().focusRteByKey(on, gisItem->getKey()); } } void CGisListWks::slotCalcRte() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemRte * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().calcRteByKey(gisItem->getKey()); } } void CGisListWks::slotResetRte() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemRte * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().resetRteByKey(gisItem->getKey()); } } void CGisListWks::slotEditRte() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemRte * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().editRteByKey(gisItem->getKey()); } } void CGisListWks::slotRte2Trk() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemRte * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().convertRouteToTrack(gisItem->getKey()); } } void CGisListWks::slotEditArea() { CGisListWksEditLock lock(false, IGisItem::mutexItems); CGisItemOvlArea * gisItem = dynamic_cast(currentItem()); if(gisItem != nullptr) { CGisWorkspace::self().editAreaByKey(gisItem->getKey()); } } void CGisListWks::slotAddEmptyProject() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QString key, name; IGisProject::type_e type; CSelectProjectDialog dlg(key, name, type, nullptr); if(dlg.exec() == QDialog::Rejected) { return; } if(name.isEmpty() && (type != IGisProject::eTypeDb)) { return; } if(type == IGisProject::eTypeGpx) { new CGpxProject(name, this); } else if(type == IGisProject::eTypeQms) { new CQmsProject(name, this); } else if(type == IGisProject::eTypeDb) { quint64 idParent; QString db; QString host; IDBFolder::type_e type; CSelectDBFolder dlg1(idParent, db, host, this); if(dlg1.exec() == QDialog::Rejected) { return; } CSetupFolder dlg2(type, name, false, this); if(dlg2.exec() == QDialog::Rejected) { return; } CEvtW2DCreate * evt = new CEvtW2DCreate(name, type, idParent, db, host); CGisDatabase::self().postEventForDb(evt); } } void CGisListWks::slotSearchGoogle(bool on) { CGisListWksEditLock lock(true, IGisItem::mutexItems); delete searchGoogle; if(on) { searchGoogle = new CSearchGoogle(this); } CCanvas::triggerCompleteUpdate(CCanvas::eRedrawGis); } void CGisListWks::slotSyncWksDev() { CGisListWksEditLock lock(true, IGisItem::mutexItems); if(IDevice::count() == 0) { return; } IGisProject * project = dynamic_cast(currentItem()); if(nullptr == project) { return; } const int N = topLevelItemCount(); QSet keys; if(IDevice::count() > 1) { CSelDevices dlg(project, this); if(dlg.exec() != QDialog::Accepted) { return; } dlg.getSlectedDevices(keys); } else { for(int n = 0; n < N; n++) { IDevice *device = dynamic_cast(topLevelItem(n)); if(nullptr != device) { keys << device->getKey(); break; } } } CCanvas *canvas = CMainWindow::self().getVisibleCanvas(); for(int n = 0; n < N; n++) { IDevice * device = dynamic_cast(topLevelItem(n)); if(nullptr == device || keys.isEmpty() || !keys.contains(device->getKey())) { continue; } if(canvas) { canvas->reportStatus("device", tr("Update devices

Update %1
Please wait...

").arg(device->text(CGisListWks::eColumnName))); canvas->update(); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } device->updateProject(project); } if(canvas) { canvas->reportStatus("device", ""); } emit sigChanged(); } void CGisListWks::slotSyncDevWks() { CGisListWksEditLock lock(true, IGisItem::mutexItems); IGisProject * project = dynamic_cast(currentItem()); if(nullptr == project) { return; } IDevice * device = dynamic_cast(project->parent()); if(nullptr == device) { return; } QString key = project->getKey(); project = getProjectByKey(key); if(project) { CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->reportStatus("device", tr("Update devices

Update %1
Please wait...

").arg(device->text(CGisListWks::eColumnName))); canvas->update(); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } device->updateProject(project); if(canvas) { canvas->reportStatus("device", ""); } emit sigChanged(); } } bool CGisListWks::event(QEvent * e) { if(e->type() > QEvent::User) { const bool doWaitCursoer = (eEvtA2WCutTrk != event_types_e(e->type())); CGisListWksEditLock lock(doWaitCursoer, IGisItem::mutexItems); switch(e->type()) { case eEvtD2WReqInfo: { CEvtD2WReqInfo * evt = (CEvtD2WReqInfo*)e; CDBProject * project = getProjectById(evt->id, evt->db); if(nullptr != project) { project->postStatus(false); } e->accept(); emit sigChanged(); return true; } case eEvtD2WShowFolder: { CEvtD2WShowFolder * evt = (CEvtD2WShowFolder*)e; CDBProject * project = getProjectById(evt->id, evt->db); if(nullptr == project) { if(evt->id == 0) { project = new CLostFoundProject(evt->db, this); } else { project = new CDBProject(evt->db, evt->id, this); } if(!project->isValid()) { delete project; } } e->accept(); emit sigChanged(); return true; } case eEvtD2WHideFolder: { CEvtD2WHideFolder * evt = (CEvtD2WHideFolder*)e; CDBProject * project = getProjectById(evt->id, evt->db); if(project && project->askBeforClose()) { /* Tell the DB view that we aborted to hide the folder by posting it's current status. */ project->postStatus(false); return false; } delete project; e->accept(); emit sigChanged(); emit sigItemDeleted(); return true; } case eEvtD2WShowItems: { CEvtD2WShowItems * evt = (CEvtD2WShowItems*)e; CDBProject * project = getProjectById(evt->id, evt->db); if(project) { project->showItems(evt); } e->accept(); emit sigChanged(); return true; } case eEvtD2WHideItems: { CEvtD2WHideItems * evt = (CEvtD2WHideItems*)e; CDBProject * project = getProjectById(evt->id, evt->db); if(project) { project->hideItems(evt); } e->accept(); emit sigChanged(); emit sigItemDeleted(); return true; } case eEvtD2WUpdateLnF: { CEvtD2WUpdateLnF * evt = (CEvtD2WUpdateLnF*)e; CLostFoundProject * project = dynamic_cast(getProjectById(evt->id, evt->db)); if(project) { project->updateFromDb(); } e->accept(); emit sigChanged(); return true; } case eEvtD2WUpdateItems: { CEvtD2WUpdateItems * evt = (CEvtD2WUpdateItems*)e; IGisProject * project = dynamic_cast(getProjectById(evt->id, evt->db)); if(project) { project->blockUpdateItems(false); } e->accept(); emit sigChanged(); return true; } case eEvtD2WReload: { CEvtD2WReload * evt = (CEvtD2WReload*)e; QList projects; const int N = topLevelItemCount(); for(int i = 0; i < N; i++) { CDBProject * project = dynamic_cast(topLevelItem(i)); if(project && (project->getDBName() == evt->db)) { project->update(); projects << project; } } for(CDBProject * project : projects) { project->blockUpdateItems(false); } e->accept(); return true; } case eEvtA2WCutTrk: { CEvtA2WCutTrk * evt = (CEvtA2WCutTrk*)e; CGisWorkspace::self().cutTrkByKey(evt->key); e->accept(); return true; } case eEvtA2WSave: { CEvtA2WSave * evt = (CEvtA2WSave*)e; IGisProject * project = getProjectByKey(evt->key); if(project) { project->save(); project->confirmPendingAutoSave(); } e->accept(); return true; } } } return QTreeWidget::event(e); } void CGisListWks::slotRteFromWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QList keys; for(QTreeWidgetItem * item : selectedItems()) { CGisItemWpt * wpt = dynamic_cast(item); if(nullptr != wpt) { keys << wpt->getKey(); } } if(!keys.isEmpty()) { CGisWorkspace::self().makeRteFromWpt(keys); } } void CGisListWks::slotSyncDB() { CGisListWksEditLock lock(true, IGisItem::mutexItems); for(QTreeWidgetItem * item : selectedItems()) { CDBProject * project = dynamic_cast(item); if(project == nullptr) { continue; } project->update(); } } void CGisListWks::slotSetSortMode(IGisProject::sorting_folder_e mode, bool checked) { if(!checked || blockSorting) { return; } IGisProject * project = dynamic_cast(currentItem()); if(project != nullptr) { project->setSortingFolder(mode); } } void CGisListWks::slotCopyProject() { CGisListWksEditLock lock(true, IGisItem::mutexItems); QList keys; for(QTreeWidgetItem * item : selectedItems()) { IGisProject * project = dynamic_cast(item); if(project == nullptr) { continue; } const int N = project->childCount(); for(int i = 0; i < N; i++) { IGisItem * item = dynamic_cast(project->child(i)); if(item != nullptr) { keys << item->getKey(); } } } CGisWorkspace::self().copyItemsByKey(keys); } void CGisListWks::slotSymWpt() { CGisListWksEditLock lock(false, IGisItem::mutexItems); QToolButton tb; CWptIconDialog dlg(&tb); if(dlg.exec() == QDialog::Rejected) { return; } QList keys; for(QTreeWidgetItem * item : selectedItems()) { CGisItemWpt * wpt = dynamic_cast(item); if(wpt == nullptr) { continue; } keys << wpt->getKey(); } CGisWorkspace::self().changeWptSymByKey(keys, tb.objectName()); } qmapshack-1.10.0/src/gis/CSelDevices.cpp000644 001750 000144 00000004355 13216234140 021133 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "device/IDevice.h" #include "gis/CGisListWks.h" #include "gis/CSelDevices.h" #include "gis/prj/IGisProject.h" #include CSelDevices::CSelDevices(IGisProject * project, QTreeWidget *wks) : QDialog(wks) { setupUi(this); const int N = wks->topLevelItemCount(); for(int n = 0; n < N; n++) { IDevice *device = dynamic_cast(wks->topLevelItem(n)); if(nullptr == device) { continue; } QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(device->getName()); item->setData(Qt::UserRole, device->getKey()); item->setIcon(device->icon(CGisListWks::eColumnIcon)); IGisProject *proj = device->getProjectByKey(project->getKey()); item->setCheckState(nullptr == proj ? Qt::Unchecked : Qt::Checked); } CCanvas::setOverrideCursor(Qt::ArrowCursor, "CSelDevices"); } CSelDevices::~CSelDevices() { CCanvas::restoreOverrideCursor("~CSelDevices"); } void CSelDevices::getSlectedDevices(QSet& keys) { keys.clear(); const int N = listWidget->count(); for(int n = 0; n < N; n++) { QListWidgetItem * item = listWidget->item(n); if(item->checkState() == Qt::Checked) { keys << item->data(Qt::UserRole).toString(); } } } qmapshack-1.10.0/src/gis/IGisItem.cpp000644 001750 000144 00000057375 13216234261 020472 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "device/IDevice.h" #include "gis/CGisDraw.h" #include "gis/CGisListWks.h" #include "gis/CGisWorkspace.h" #include "gis/IGisItem.h" #include "gis/db/macros.h" #include "gis/ovl/CGisItemOvlArea.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "units/IUnit.h" #include #include #include QMutex IGisItem::mutexItems(QMutex::Recursive); const QString IGisItem::noKey; const QString IGisItem::noName = IGisItem::tr("[no name]"); const IGisItem::color_t IGisItem::colorMap[] = { {"Black", QColor(Qt::black), QString("://icons/8x8/bullet_black.png")} ,{"DarkRed", QColor(Qt::darkRed), QString("://icons/8x8/bullet_dark_red.png")} ,{"DarkGreen", QColor(Qt::darkGreen), QString("://icons/8x8/bullet_dark_green.png")} ,{"DarkYellow", QColor(Qt::darkYellow), QString("://icons/8x8/bullet_dark_yellow.png")} ,{"DarkBlue", QColor(Qt::darkBlue), QString("://icons/8x8/bullet_dark_blue.png")} ,{"DarkMagenta", QColor(Qt::darkMagenta), QString("://icons/8x8/bullet_dark_magenta.png")} ,{"DarkCyan", QColor(Qt::darkCyan), QString("://icons/8x8/bullet_dark_cyan.png")} ,{"LightGray", QColor(Qt::lightGray), QString("://icons/8x8/bullet_gray.png")} ,{"DarkGray", QColor(Qt::darkGray), QString("://icons/8x8/bullet_dark_gray.png")} ,{"Red", QColor(Qt::red), QString("://icons/8x8/bullet_red.png")} ,{"Green", QColor(Qt::green), QString("://icons/8x8/bullet_green.png")} ,{"Yellow", QColor(Qt::yellow), QString("://icons/8x8/bullet_yellow.png")} ,{"Blue", QColor(Qt::blue), QString("://icons/8x8/bullet_blue.png")} ,{"Magenta", QColor(Qt::magenta), QString("://icons/8x8/bullet_magenta.png")} ,{"Cyan", QColor(Qt::cyan), QString("://icons/8x8/bullet_cyan.png")} ,{"White", QColor(Qt::white), QString("://icons/8x8/bullet_white.png")} ,{"Transparent", QColor(Qt::transparent), QString()} }; const size_t IGisItem::colorMapSize = sizeof(colorMap) / sizeof(color_t); IGisItem::IGisItem(IGisProject *parent, type_e typ, int idx) : QTreeWidgetItem(parent, typ) { int n = -1; setFlags(QTreeWidgetItem::flags() & ~Qt::ItemIsDropEnabled); if(nullptr == parent) { return; } key.project = parent->getKey(); key.device = parent->getDeviceKey(); if(idx >= 0) { parent->removeChild(this); parent->insertChild(idx, this); } else { if(type() == eTypeTrk) { for(n = parent->childCount() - 2; n >= 0; n--) { /** @note The order of item types to test is given by the order items read from the GPX file in the CGpxProject constructor. */ int childType = parent->child(n)->type(); if(childType == eTypeTrk) { parent->removeChild(this); parent->insertChild(n+1, this); break; } } } else if(type() == eTypeRte) { for(n = parent->childCount() - 2; n >= 0; n--) { /** @note The order of item types to test is given by the order items read from the GPX file in the CGpxProject constructor. */ int childType = parent->child(n)->type(); if( childType == eTypeRte || childType == eTypeTrk) { parent->removeChild(this); parent->insertChild(n+1, this); break; } } } else if(type() == eTypeWpt) { for(n = parent->childCount() - 2; n >= 0; n--) { /** @note The order of item types to test is given by the order items read from the GPX file in the CGpxProject constructor. */ int childType = parent->child(n)->type(); if(childType == eTypeWpt || childType == eTypeRte || childType == eTypeTrk) { parent->removeChild(this); parent->insertChild(n+1, this); break; } } } else if(type() == eTypeOvl) { for(n = parent->childCount() - 2; n >= 0; n--) { /** @note The order of item types to test is given by the order items read from the GPX file in the CGpxProject constructor. */ int childType = parent->child(n)->type(); if(childType == eTypeOvl || childType == eTypeWpt || childType == eTypeRte || childType == eTypeTrk) { parent->removeChild(this); parent->insertChild(n+1, this); break; } } } if(n < 0) { parent->removeChild(this); parent->insertChild(0, this); } } } IGisItem::~IGisItem() { } IGisProject * IGisItem::getParentProject() const { return dynamic_cast(parent()); } void IGisItem::genKey() const { if(key.item.isEmpty()) { QByteArray buffer; QDataStream stream(&buffer, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this >> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(buffer); key.item = md5.result().toHex(); } if(key.project.isEmpty()) { IGisProject * project = getParentProject(); if(project) { key.project = project->getKey(); } } } void IGisItem::loadFromDb(quint64 id, QSqlDatabase& db) { QSqlQuery query(db); query.prepare("SELECT data, keyqms, hash FROM items WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); if(query.next()) { QByteArray data(query.value(0).toByteArray()); QDataStream in(&data, QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in.setVersion(QDataStream::Qt_5_2); in >> history; loadHistory(history.histIdxCurrent); if(key.item.isEmpty()) { QString keyFromDB = query.value(1).toString(); /*[Issue #72] Database/Workspace inconsistency in QMS 1.4.0 The root cause is a missing key in the serialized data. This is fixed by calling getKey() in setupHistory(). As the database has a valid key the complete history data has to be fixed with that key. */ const int N = history.events.size(); for(int i = 0; i < N; i++) { loadHistory(i); key.item = keyFromDB; updateHistory(); } } lastDatabaseHash = query.value(2).toString(); } } void IGisItem::updateFromDB(quint64 id, QSqlDatabase& db) { QSqlQuery query(db); query.prepare("SELECT hash FROM items WHERE id=:id"); query.bindValue(":id", id); QUERY_EXEC(return ); /* Test on the hash stored in the database. If the hash is equal to the one stored in this item the item is up-to-date */ if(query.next()) { if(query.value(0).toString() == lastDatabaseHash) { return; } } else { // no hash? better leave... return; } // reset history and load item again history.reset(); loadFromDb(id, db); } QString IGisItem::getNameEx() const { QString str = getName(); IGisProject * project = getParentProject(); if(project) { str += " @ " + project->getName(); } IDevice * device = dynamic_cast(parent()->parent()); if(device) { str += " @ " + device->getName(); } return str; } void IGisItem::updateDecoration(quint32 enable, quint32 disable) { // update text and icon setToolTip(CGisListWks::eColumnName,getInfo(IGisItem::eFeatureShowName)); setText(CGisListWks::eColumnName, getName()); setSymbol(); // update project if necessary IGisProject * project = getParentProject(); if(project && (enable & (eMarkChanged|eMarkNotPart|eMarkNotInDB))) { project->setChanged(); } // test for lost & found folder if(project && project->getType() == IGisProject::eTypeLostFound) { setText(CGisListWks::eColumnDecoration, QString()); setToolTip(CGisListWks::eColumnDecoration, QString()); return; } // set marks in column 1 quint32 mask = data(1,Qt::UserRole).toUInt(); mask |= enable; mask &= ~disable; setData(1, Qt::UserRole, mask); QString tt; QString str; if(mask & eMarkNotPart) { tt += tt.isEmpty() ? "" : "\n"; tt += tr("The item is not part of the project in the database."); tt += tr("\nIt is either a new item or it has been deleted in the database by someone else."); str += "?"; } if(mask & eMarkNotInDB) { tt += tt.isEmpty() ? "" : "\n"; tt += tr("The item is not in the database."); str += "X"; } if(mask & eMarkChanged) { tt += tt.isEmpty() ? "" : "\n"; tt += tr("The item might need to be saved"); str += "*"; } setText(CGisListWks::eColumnDecoration, str); setToolTip(CGisListWks::eColumnDecoration, tt); } void IGisItem::changed(const QString &what, const QString &icon) { /* If item gets changed but if it's origin is not QMapShack then it is assumed to be tainted, as imported data should never be changed without notice. */ if(!(flags & eFlagCreatedInQms)) { flags |= eFlagTainted; } // forget all history entries after the current entry for(int i = history.events.size() - 1; i > history.histIdxCurrent; i--) { history.events.pop_back(); } // append history by new entry history.events << history_event_t(); history_event_t& event = history.events.last(); event.time = QDateTime::currentDateTimeUtc(); event.comment = what; event.icon = icon; event.who = CMainWindow::getUser(); QDataStream stream(&event.data, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this >> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(event.data); event.hash = md5.result().toHex(); history.histIdxCurrent = history.events.size() - 1; updateDecoration(eMarkChanged, eMarkNone); } void IGisItem::updateHistory() { if(history.histIdxCurrent == NOIDX) { return; } history_event_t& event = history.events[history.histIdxCurrent]; event.data.clear(); QDataStream stream(&event.data, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this >> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(event.data); event.hash = md5.result().toHex(); updateDecoration(eMarkChanged, eMarkNone); } void IGisItem::setupHistory() { getKey(); history.histIdxInitial = NOIDX; history.histIdxCurrent = NOIDX; // if history is empty setup an initial item if(history.events.isEmpty()) { history.events << history_event_t(); history_event_t& event = history.events.last(); event.time = QDateTime::currentDateTimeUtc(); event.comment = tr("Initial version."); event.icon = "://icons/48x48/Start.png"; } // search for the first item with data for(int i = 0; i < history.events.size(); i++) { if(!history.events[i].data.isEmpty()) { history.histIdxInitial = i; break; } } // if no initial item can be found fill the last item with data // and make it the initial item if(history.histIdxInitial == NOIDX) { history_event_t& event = history.events.last(); QDataStream stream(&event.data, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this >> stream; QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(event.data); event.hash = md5.result().toHex(); history.histIdxInitial = history.events.size() - 1; } history.histIdxCurrent = history.events.size() - 1; } void IGisItem::loadHistory(int idx) { // test for bad index if((idx >= history.events.size()) || (idx < 0)) { return; } history_event_t& event = history.events[idx]; // test for no data if(event.data.isEmpty()) { return; } // restore item from history entry QDataStream stream(&event.data, QIODevice::ReadOnly); stream.setByteOrder(QDataStream::LittleEndian); stream.setVersion(QDataStream::Qt_5_2); *this << stream; history.histIdxCurrent = idx; } void IGisItem::cutHistoryAfter() { while(history.events.size() > (history.histIdxCurrent + 1)) { history.events.pop_back(); } } void IGisItem::cutHistoryBefore() { for (int i = 0; i < history.histIdxCurrent; i++) { history.events[i].data.clear(); } } bool IGisItem::isReadOnly() const { return !(flags & eFlagWriteAllowed) || isOnDevice(); } bool IGisItem::isTainted() const { return flags & eFlagTainted; } qint32 IGisItem::isOnDevice() const { IGisProject * project = getParentProject(); if(nullptr == project) { return false; } return project->isOnDevice(); } bool IGisItem::setReadOnlyMode(bool readOnly) { // if the item is on a device no change is allowed if(isOnDevice()) { return false; } // test if it is a change at all if(isReadOnly() == readOnly) { return true; } // warn if item is external and read only if(!(flags & (eFlagCreatedInQms|eFlagTainted))) { SETTINGS; bool doNotAsk = cfg.value("Dialog/Items/ReadOnly/doNotAsk", false).toBool(); if(isReadOnly() && !readOnly && !doNotAsk) { CCanvas::setOverrideCursor(Qt::ArrowCursor, "setReadOnlyMode"); QCheckBox * checkBox = new QCheckBox(tr("Never ask again."), 0); QString msg = tr("

%1

This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press 'Ok'.").arg(getName()); QMessageBox box(QMessageBox::Warning, tr("Read Only Mode..."), msg, QMessageBox::Ok|QMessageBox::Abort, CMainWindow::getBestWidgetForParent()); box.setDefaultButton(QMessageBox::Ok); box.setCheckBox(checkBox); int res = box.exec(); CCanvas::restoreOverrideCursor("setReadOnlyMode"); if(res != QMessageBox::Ok) { return false; } cfg.setValue("Dialog/Items/ReadOnly/doNotAsk", checkBox->isChecked()); } } // finally change flag if(readOnly) { flags &= ~eFlagWriteAllowed; } else { flags |= eFlagWriteAllowed; } updateHistory(); return true; } const IGisItem::key_t &IGisItem::getKey() const { if(key.item.isEmpty() || key.project.isEmpty()) { genKey(); } return key; } const QString& IGisItem::getHash() { if(history.histIdxCurrent == NOIDX) { return noKey; } return history.events[history.histIdxCurrent].hash; } const QString& IGisItem::getLastDatabaseHash() { if(lastDatabaseHash.isEmpty()) { lastDatabaseHash = getHash(); } return lastDatabaseHash; } void IGisItem::setLastDatabaseHash(quint64 id, QSqlDatabase& db) { lastDatabaseHash = getHash(); } QColor IGisItem::str2color(const QString& name) { for(size_t i = 0; i < colorMapSize; i++) { if(QString(colorMap[i].name).toUpper() == name.toUpper()) { return colorMap[i].color; } } return QColor(name); } QString IGisItem::color2str(const QColor& color) { for(size_t i = 0; i < colorMapSize; i++) { if(colorMap[i].color == color) { return colorMap[i].name; } } return ""; } void IGisItem::splitLineToViewport(const QPolygonF& line, const QRectF& extViewport, QList& lines) { if(line.isEmpty()) { return; } QPointF ptt; QPointF pt = line[0]; QPolygonF subline; subline << pt; const int size = line.size(); for(int i = 1; i < size; i++) { QPointF pt1 = line[i]; if(!GPS_Math_LineCrossesRect(pt, pt1, extViewport)) { pt = pt1; if(subline.size() > 1) { lines << subline; } subline.clear(); subline << pt; continue; } ptt = pt1 - pt; if(ptt.manhattanLength() >= 5) { subline << pt1; pt = pt1; } } if(subline.size() > 1) { lines << subline; } } QString IGisItem::removeHtml(const QString &str) { QTextDocument html; html.setHtml(str); return html.toPlainText(); } QString IGisItem::html2Dev(const QString& str, bool strictGpx11) { // device or not, an empty text should never be enclosed in HTML tags if(removeHtml(str).simplified().isEmpty()) { return ""; } return (isOnDevice() == IDevice::eTypeGarmin) || strictGpx11 ? removeHtml(str) : str; } QString IGisItem::toLink(bool isReadOnly, const QString& href, const QString& str, const QString &key) { if(isReadOnly) { return QString("%1").arg(str); } if(key.isEmpty()) { return QString("%2").arg(href).arg(str); } else { return QString("%2").arg(href).arg(str).arg(key); } } QString IGisItem::createText(bool isReadOnly, const QString& cmt, const QString& desc, const QList& links, const QString &key) { QString str; bool isEmpty; isEmpty = removeHtml(desc).simplified().isEmpty(); if(!isReadOnly || !isEmpty) { str += toLink(isReadOnly, "description", tr("

Description:

"), key); if(removeHtml(desc).simplified().isEmpty()) { str += tr("

--- no description ---

"); } else { str += desc; } } isEmpty = removeHtml(cmt).simplified().isEmpty(); if(!isReadOnly || !isEmpty) { str += toLink(isReadOnly, "comment", tr("

Comment:

"), key); if(isEmpty) { str += tr("

--- no comment ---

"); } else { str += cmt; } } isEmpty = links.isEmpty(); if(!isReadOnly || !isEmpty) { str += toLink(isReadOnly, "links", tr("

Links:

"), key); if(isEmpty) { str += tr("

--- no links ---

"); } else { for(const link_t &link : links) { str += QString("

%2

").arg(link.uri.toString()) .arg(link.text.isEmpty() ? link.uri.toString() : link.text); } } } return str; } QString IGisItem::createText(bool isReadOnly, const QString& desc, const QList& links, const QString& key) { QString str; bool isEmpty; isEmpty = removeHtml(desc).simplified().isEmpty(); if(!isReadOnly || !isEmpty) { str += toLink(isReadOnly, "description", tr("

Description:

"), key); if(removeHtml(desc).simplified().isEmpty()) { str += tr("

--- no description ---

"); } else { str += desc; } } isEmpty = links.isEmpty(); if(!isReadOnly || !isEmpty) { str += toLink(isReadOnly, "links", tr("

Links:

"), key); if(isEmpty) { str += tr("

--- no links ---

"); } else { for(const link_t &link : links) { str += QString("

%2

").arg(link.uri.toString()) .arg(link.text.isEmpty() ? link.uri.toString() : link.text); } } } return str; } bool IGisItem::isVisible(const QRectF &rect, const QPolygonF& viewport, CGisDraw *gis) { QPolygonF tmp1; tmp1 << rect.topLeft(); tmp1 << rect.topRight(); tmp1 << rect.bottomRight(); tmp1 << rect.bottomLeft(); gis->convertRad2Px(tmp1); QPolygonF tmp2 = viewport; gis->convertRad2Px(tmp2); return tmp2.boundingRect().intersects(tmp1.boundingRect()); } bool IGisItem::isVisible(const QPointF& point, const QPolygonF& viewport, CGisDraw * gis) { QPolygonF tmp2 = viewport; gis->convertRad2Px(tmp2); QPointF pt = point; gis->convertRad2Px(pt); return tmp2.boundingRect().contains(pt); } bool IGisItem::isChanged() const { return text(CGisListWks::eColumnDecoration).contains('*'); } bool IGisItem::isWithin(const QRectF& area, selflags_t flags, const QPolygonF& points) { if(points.isEmpty()) { return false; } if(flags & eSelectionExact) { for(const QPointF &point : points) { if(!area.contains(point)) { return false; } } return true; } else if(flags & eSelectionIntersect) { for(const QPointF &point : points) { if(area.contains(point)) { return true; } } return false; } return false; } bool IGisItem::getNameAndProject(QString &name, IGisProject *&project, const QString& itemtype) { name = QInputDialog::getText(CMainWindow::getBestWidgetForParent(), tr("Edit name..."), tr("Enter new %1 name.").arg(itemtype), QLineEdit::Normal, name); if(name.isEmpty()) { return false; } project = CGisWorkspace::self().selectProject(); return nullptr != project; } IGisItem * IGisItem::newGisItem(quint32 type, quint64 id, QSqlDatabase& db, IGisProject * project) { IGisItem *item = nullptr; // load item from database switch(type) { case IGisItem::eTypeWpt: item = new CGisItemWpt(id, db, project); break; case IGisItem::eTypeTrk: item = new CGisItemTrk(id, db, project); break; case IGisItem::eTypeRte: item = new CGisItemRte(id, db, project); break; case IGisItem::eTypeOvl: item = new CGisItemOvlArea(id, db, project); break; default: ; } return item; } qmapshack-1.10.0/src/GeoMath.cpp000644 001750 000144 00000036630 13216234140 017545 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #include "GeoMath.h" #include "canvas/IDrawContext.h" #include "units/IUnit.h" #include #include #include #include #define PI M_PI #define TWOPI (2*PI) pointDP::pointDP() : used(true), idx(NOIDX) { } pointDP::pointDP(const qreal &x, const qreal &y, const qreal &z) : point3D(x, y, z), used(true), idx(NOIDX) { } segment_t::segment_t() : idx11(NOIDX), idx12(NOIDX), idx21(NOIDX) { } static inline qreal distance(const QPointF &pa, const QPointF &pb) { const qreal &dx = pa.x() - pb.x(); const qreal &dy = pa.y() - pb.y(); return qSqrt(dx * dx + dy * dy); } void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal °) { deg = qAbs(d) + qreal(m) / 60.0 + s / 3600; if(sign) { deg = -deg; } } bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min) { *deg = qAbs(v); *min = (qAbs(v) - *deg) * 60.0; return v < 0; } void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg) { deg = qAbs(d) + m / 60.0; if(sign) { deg = -deg; } } // from http://www.movable-type.co.uk/scripts/LatLongVincenty.html qreal GPS_Math_Distance(const qreal u1, const qreal v1, const qreal u2, const qreal v2, qreal& a1, qreal& a2) { qreal cosSigma = 0.0; qreal sigma = 0.0; qreal sinAlpha = 0.0; qreal cosSqAlpha = 0.0; qreal cos2SigmaM = 0.0; qreal sinSigma = 0.0; qreal sinLambda = 0.0; qreal cosLambda = 0.0; qreal a = 6378137.0, b = 6356752.3142, f = 1.0/298.257223563; // WGS-84 ellipsiod qreal L = u2 - u1; qreal U1 = qAtan((1-f) * qTan(v1)); qreal U2 = qAtan((1-f) * qTan(v2)); qreal sinU1 = qSin(U1), cosU1 = qCos(U1); qreal sinU2 = qSin(U2), cosU2 = qCos(U2); qreal lambda = L, lambdaP = 2*PI; unsigned iterLimit = 20; while ((qAbs(lambda - lambdaP) > 1e-12) && (--iterLimit > 0)) { sinLambda = qSin(lambda); cosLambda = qCos(lambda); sinSigma = qSqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); if (sinSigma==0) { return 0; // co-incident points } cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = qAtan2(sinSigma, cosSigma); sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (qIsNaN(cos2SigmaM)) { cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) } qreal C = f/16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } if (iterLimit==0) { return FP_NAN; // formula failed to converge } qreal uSq = cosSqAlpha * (a*a - b*b) / (b*b); qreal A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); qreal B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); qreal deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); qreal s = b*A*(sigma-deltaSigma); a1 = qAtan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * 360 / TWOPI; a2 = qAtan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda) * 360 / TWOPI; return s; } qreal GPS_Math_Distance(const qreal u1, const qreal v1, const qreal u2, const qreal v2) { qreal cosSigma = 0.0; qreal sigma = 0.0; qreal sinAlpha = 0.0; qreal cosSqAlpha = 0.0; qreal cos2SigmaM = 0.0; qreal sinSigma = 0.0; qreal sinLambda = 0.0; qreal cosLambda = 0.0; qreal a = 6378137.0, b = 6356752.3142, f = 1.0/298.257223563; // WGS-84 ellipsiod qreal L = u2 - u1; qreal U1 = qAtan((1-f) * qTan(v1)); qreal U2 = qAtan((1-f) * qTan(v2)); qreal sinU1 = qSin(U1), cosU1 = qCos(U1); qreal sinU2 = qSin(U2), cosU2 = qCos(U2); qreal lambda = L, lambdaP = 2*PI; unsigned iterLimit = 20; while ((qAbs(lambda - lambdaP) > 1e-12) && (--iterLimit > 0)) { sinLambda = qSin(lambda); cosLambda = qCos(lambda); sinSigma = qSqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); if (sinSigma==0) { return 0; // co-incident points } cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = qAtan2(sinSigma, cosSigma); sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (qIsNaN(cos2SigmaM)) { cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) } qreal C = f/16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } if (iterLimit==0) { return FP_NAN; // formula failed to converge } qreal uSq = cosSqAlpha * (a*a - b*b) / (b*b); qreal A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); qreal B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); qreal deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); qreal s = b*A*(sigma-deltaSigma); return s; } qreal GPS_Math_DistanceQuick(const qreal u1, const qreal v1, const qreal u2, const qreal v2) { qreal dU = u2 - u1; // lambda qreal dV = v2 - v1; // roh qreal d = 2*qAsin(qSqrt(qSin(dV/2) * qSin(dV/2) + qCos(v1) * qCos(v2) * qSin(dU/2) * qSin(dU/2))); return 6371010 * d; } void GPS_Math_Wpt_Projection(const qreal lon1, const qreal lat1, const qreal distance, const qreal bearing, qreal& lon2, qreal& lat2) { qreal d = distance / 6378130.0; lat2 = qAsin(qSin(lat1) * qCos(d) + qCos(lat1) * qSin(d) * qCos(-bearing)); lon2 = qCos(lat1) == 0 ? lon1 : fmod(lon1 - qAsin(qSin(-bearing) * qSin(d) / qCos(lat1)) + PI, TWOPI) - PI; } static qreal GPS_Math_distPointLine3D(const point3D &x1, const point3D &x2, const point3D &x0) { point3D v1, v2, v3, v1x2; // (x0 - x1) v1.x = x0.x - x1.x; v1.y = x0.y - x1.y; v1.z = x0.z - x1.z; // (x0 - x2) v2.x = x0.x - x2.x; v2.y = x0.y - x2.y; v2.z = x0.z - x2.z; // (x2 - x1) v3.x = x2.x - x1.x; v3.y = x2.y - x1.y; v3.z = x2.z - x1.z; // (x0 - x1)x(x0 - x2) v1x2.x = v1.y * v2.z - v1.z * v2.y; v1x2.y = v1.z * v2.x - v1.x * v2.z; v1x2.z = v1.x * v2.y - v1.y * v2.x; // |(x0 - x1)x(x0 - x2)| qreal a1x2 = v1x2.x*v1x2.x + v1x2.y*v1x2.y + v1x2.z*v1x2.z; // |(x2 - x1)| qreal a3 = v3.x*v3.x + v3.y*v3.y + v3.z*v3.z; return qSqrt(a1x2/a3); } static inline qreal sqr(qreal a) { return a*a; } static inline qreal sqrlen(const QPointF &a) { return sqr(a.x()) + sqr(a.y()); } qreal GPS_Math_DistPointPolyline(const QPolygonF &points, const QPointF &q) { const qint32 count = points.size(); if(count == 0) { return NOFLOAT; } QPointF b = points[0]; QPointF dbq = b - q; qreal dist = sqrlen(dbq); for (qint32 i = 1; i1. { current_dist = sqrlen(dbq); } if (current_dist &line, qreal d) { if(line.count() < 3) { return; } QStack stack; stack << segment(0, line.size() - 1); while(!stack.isEmpty()) { qint32 idx = NOIDX; segment seg = stack.pop(); pointDP& x1 = line[seg.idx1]; pointDP& x2 = line[seg.idx2]; qreal dmax = d; for(qint32 i = seg.idx1 + 1; i < seg.idx2; i++) { qreal distance = GPS_Math_distPointLine3D(x1, x2, line[i]); if(distance > dmax) { idx = i; dmax = distance; } } if(idx > 0) { stack << segment(seg.idx1, idx); stack << segment(idx, seg.idx2); } else { for(qint32 i = seg.idx1 + 1; i < seg.idx2; i++) { line[i].used = false; } } } } QPointF GPS_Math_Wpt_Projection(const QPointF& pt1, qreal distance, qreal bearing) { QPointF pt2; qreal d = distance / 6378130.0; qreal lon1 = pt1.x(); qreal lat1 = pt1.y(); qreal lat2 = qAsin(qSin(lat1) * qCos(d) + qCos(lat1) * qSin(d) * qCos(-bearing)); qreal lon2 = qCos(lat1) == 0 ? lon1 : fmod(lon1 - qAsin(qSin(-bearing) * qSin(d) / qCos(lat1)) + M_PI, (2*M_PI)) - M_PI; pt2.rx() = lon2; pt2.ry() = lat2; return pt2; } bool GPS_Math_LineCrossesRect(const QPointF &p1, const QPointF &p2, const QRectF &rect) { // the trivial case if(rect.contains(p1) || rect.contains(p2)) { return true; } qreal slope = qreal(p2.y() - p1.y()) / (p2.x() - p1.x()); qreal offset = p1.y() - slope * p1.x(); qreal y1 = offset + slope * rect.left(); qreal y2 = offset + slope * rect.right(); if((y1 < rect.top()) && (y2 < rect.top())) { return false; } else if((y1 > rect.bottom()) && (y2 > rect.bottom())) { return false; } return true; } void GPS_Math_SubPolyline(const QPointF& pt1, const QPointF& pt2, qint32 threshold, const QPolygonF& pixel, segment_t &result) { projXY p1, p2; qreal dx,dy; // delta x and y defined by p1 and p2 qreal d_p1_p2; // distance between p1 and p2 qreal x,y; // coord. (x,y) of the point on line defined by [p1,p2] close to pt qreal shortest1 = threshold; qreal shortest2 = threshold; qint32 idx11 = NOIDX, idx21 = NOIDX, idx12 = NOIDX; QPointF pt11; QPointF pt21; // find points on line closest to pt1 and pt2 const qint32 len = pixel.size(); for(qint32 i = 1; i < len; ++i) { p1.u = pixel[i - 1].x(); p1.v = pixel[i - 1].y(); p2.u = pixel[i].x(); p2.v = pixel[i].y(); dx = p2.u - p1.u; dy = p2.v - p1.v; d_p1_p2 = qSqrt(dx * dx + dy * dy); // find point on line closest to pt1 // ratio u the tangent point will divide d_p1_p2 qreal u = ((pt1.x() - p1.u) * dx + (pt1.y() - p1.v) * dy) / (d_p1_p2 * d_p1_p2); if(u >= 0.0 && u <= 1.0) { x = p1.u + u * dx; y = p1.v + u * dy; qreal distance = qSqrt((x - pt1.x())*(x - pt1.x()) + (y - pt1.y())*(y - pt1.y())); if(distance < shortest1) { idx11 = i - 1; idx12 = i; pt11.setX(x); pt11.setY(y); shortest1 = distance; } } // find point on line closest to pt2 // ratio u the tangent point will divide d_p1_p2 u = ((pt2.x() - p1.u) * dx + (pt2.y() - p1.v) * dy) / (d_p1_p2 * d_p1_p2); if(u >= 0.0 && u <= 1.0) { x = p1.u + u * dx; y = p1.v + u * dy; qreal distance = qSqrt((x - pt2.x())*(x - pt2.x()) + (y - pt2.y())*(y - pt2.y())); if(distance < shortest2) { idx21 = i - 1; pt21.setX(x); pt21.setY(y); shortest2 = distance; } } } // if 1st point can't be found test for distance to both ends if(idx11 == NOIDX) { QPointF px = pixel.first(); qreal dist = distance(px, pt1); if(dist < (threshold << 1)) { idx11 = 0; idx12 = 1; pt11 = px; } else { px = pixel.last(); qreal dist = distance(px, pt1); if(dist < (threshold << 1)) { idx11 = pixel.size() - 2; idx12 = pixel.size() - 1; pt11 = px; } } } // if 2nd point can't be found test for distance to both ends if(idx21 == NOIDX) { QPointF px = pixel.first(); qreal dist = distance(px, pt2); if(dist < (threshold<<1)) { idx21 = 0; pt21 = px; } else { px = pixel.last(); qreal dist = distance(px, pt2); if(dist < (threshold<<1)) { idx21 = pixel.size() - 2; pt21 = px; } } } // qDebug() << pixel.size() << idx11 << idx12 << idx21 << pt1 << pt2 << pt11 << pt21; result.idx11 = idx11; result.idx12 = idx12; result.idx21 = idx21; result.px1 = pt11; result.px2 = pt21; } void segment_t::apply(const QPolygonF& coords, const QPolygonF& pixel, QPolygonF& segCoord, QPolygonF& segPixel, IDrawContext * context) { QPointF pt1 = px1; QPointF pt2 = px2; context->convertPx2Rad(pt1); context->convertPx2Rad(pt2); if(idx11 != NOIDX && idx21 != NOIDX) { if(idx12 == idx21) { segPixel.push_back(pixel[idx12]); segCoord.push_back(coords[idx12]); } else if(idx11 < idx21) { for(int i = idx12; i <= idx21; i++) { segPixel.push_back(pixel[i]); segCoord.push_back(coords[i]); } } else if(idx11 > idx21) { for(int i = idx11; i > idx21; i--) { segPixel.push_back(pixel[i]); segCoord.push_back(coords[i]); } } } } qmapshack-1.10.0/src/GeoMath.h000644 001750 000144 00000005660 13216234143 017214 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********************************************************************************************/ #ifndef GEOMATH_H #define GEOMATH_H #include #include #include #include class QPolygonF; class IDrawContext; struct point3D { point3D() {} point3D(const qreal &x, const qreal &y, const qreal &z) : x(x), y(y), z(z) {} qreal x = 0; qreal y = 0; qreal z = 0; }; struct pointDP : public point3D { pointDP(); pointDP(const qreal &x, const qreal &y, const qreal &z); bool used; qint32 idx; }; struct segment_t { segment_t(); void apply(const QPolygonF& coords, const QPolygonF& pixel, QPolygonF& segCoord, QPolygonF& segPixel, IDrawContext * context); qint32 idx11; qint32 idx12; qint32 idx21; QPointF px1; QPointF px2; }; void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg); void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal& deg); bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min); /// use for long distances qreal GPS_Math_Distance(const qreal u1, const qreal v1, const qreal u2, const qreal v2, qreal& a1, qreal& a2); qreal GPS_Math_Distance(const qreal u1, const qreal v1, const qreal u2, const qreal v2); /// use for short distances, much quicker processing qreal GPS_Math_DistanceQuick(const qreal u1, const qreal v1, const qreal u2, const qreal v2); void GPS_Math_Wpt_Projection(const qreal lon1, const qreal lat1, const qreal distance, const qreal bearing, qreal& lon2, qreal& lat2); void GPS_Math_DouglasPeucker(QVector& line, qreal d); QPointF GPS_Math_Wpt_Projection(const QPointF& pt1, qreal distance, qreal bearing); bool GPS_Math_LineCrossesRect(const QPointF& p1, const QPointF& p2, const QRectF& rect); void GPS_Math_SubPolyline(const QPointF& pt1, const QPointF& pt2, qint32 threshold, const QPolygonF& pixel, segment_t& result); qreal GPS_Math_DistPointPolyline(const QPolygonF &points, const QPointF &q); #endif //GEOMATH_H qmapshack-1.10.0/src/map/000755 001750 000144 00000000000 13216664445 016301 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/map/CMapDraw.h000644 001750 000144 00000013204 13216234143 020074 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPDRAW_H #define CMAPDRAW_H #include "canvas/IDrawContext.h" #include class QPainter; class CCanvas; class CMapList; class QSettings; class CMapItem; struct poi_t; class CMapDraw : public IDrawContext { Q_OBJECT public: CMapDraw(CCanvas * parent); virtual ~CMapDraw(); void saveConfig(QSettings& cfg); void loadConfig(QSettings& cfg); /** @brief This is called most likely from the item itself to call it's loadConfig() method. As the setup of a map is stored in the context of the view the correct groups have to be set prior to call the item's loadConfig() method. However the item does not know all that stuff. That is why it has to ask it's CMapDraw object to prepare the QSettings object and to call loadConfig(); @param item the item to call it's loadConfig() method */ void loadConfigForMapItem(CMapItem * item); /** @brief Get a full detailed info text about objects close to the given point This method will call getInfo() of all items in mapList. @param px the point on the screen in pixel @param str a string object to receive all information */ void getInfo(const QPoint& px, QString& str); /** @brief Get an info text fit for a tool tip This method will call getToolTip() of all items in mapList. @param px the point on the screen in pixel @param str a string object to receive all information */ void getToolTip(const QPoint& px, QString& str); poi_t findPOICloseBy(const QPoint& px) const; /** @brief Set projection of this draw context @param proj a proj4 string */ void setProjection(const QString& proj) override; static const QStringList& getMapPaths() { return mapPaths; } static void setupMapPath(); static void setupMapPath(const QString &path); static void setupMapPath(const QStringList &paths); static void saveMapPath(QSettings &cfg); static void loadMapPath(QSettings &cfg); static const QStringList& getSupportedFormats() { return supportedFormats; } static const QString& getCacheRoot() { return cachePath; } /** @brief Forward messages to CCanvas::reportStatus() Messages from various sources will be collected in a list and displayed in the top left corner of the widget. @note The object reporting has to take care to remove the message by reporting an empty string. @param key the key to identify the reporting object @param msg the message to report */ void reportStatusToCanvas(const QString& key, const QString& msg); /** @brief Find a matching street polyline The polyline must be close enough in terms of pixel to point 1 and 2. "Close enough" is defined by the threshold. The returned polyline uses lon/lat as coordinates. @param pt1 first point in [rad] @param pt2 second point in [rad] @param threshold the "close enough" threshold in [pixel] @param polyline the resulting polyline, if any, in [rad] @return Return true if a line has been found. */ bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline); protected: void drawt(buffer_t& currentBuffer) override; private: /** @brief Search in paths found in mapPaths for files with supported extensions and add them to mapList. */ void buildMapList(); /** @brief Save list of active maps to configuration file The group context will be appended by the map's key @param keys the stored map's MD5 keys will be written to keys @param cfg configuration file with correct group context set. */ void saveActiveMapsList(QStringList &keys, QSettings &cfg); /** @brief Open configuration before saving list @param keys the stored map's MD5 keys will be written to keys */ void saveActiveMapsList(QStringList &keys); /** @brief Restore list of active maps from configuration file @param keys MD5 hash keys to identify the maps */ void restoreActiveMapsList(const QStringList &keys); void restoreActiveMapsList(const QStringList& keys, QSettings& cfg); /// the treewidget holding all active and inactive map items CMapList * mapList; /// the group label used in QSettings QString cfgGroup; /// the list of paths to search maps static QStringList mapPaths; static QString cachePath; /// all existing CMapDraw instances static QList maps; /// a list of supported map formats static QStringList supportedFormats; }; #endif //CMAPDRAW_H qmapshack-1.10.0/src/map/IMapOnline.h000644 001750 000144 00000004354 13216234143 020437 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Christian Eichler code@christian-eichler.de 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 . **********************************************************************************************/ #ifndef IMAPONLINE_H #define IMAPONLINE_H #include "map/IMap.h" #include #include #include class CDiskCache; class QNetworkAccessManager; class QNetworkReply; class IMapOnline : public IMap { Q_OBJECT struct rawHeaderItem_t { QString name; QString value; }; QList rawHeaderItems; signals: void sigQueueChanged(); protected: /// Mutex to control access to url queue QMutex mutex {QMutex::Recursive}; /// a queue with all tile urls to request QQueue urlQueue; /// the tile cache CDiskCache * diskCache = nullptr; /// access manager to request tiles QNetworkAccessManager * accessManager = nullptr; QList urlPending; bool lastRequest = false; QTime timeLastUpdate; QString name; static bool httpsCheck(const QString &url); void registerHeaderItem(const QString &name, const QString &value) { struct rawHeaderItem_t item; item.name = name; item.value = value; rawHeaderItems << item; } void configureCache() override; public: void slotQueueChanged(); void slotRequestFinished(QNetworkReply* reply); IMapOnline(CMapDraw * parent); virtual ~IMapOnline() {} }; #endif //IMAPONLINE_H qmapshack-1.10.0/src/map/OpenCycleMap.tms000644 001750 000144 00000000504 12513131604 021325 0ustar00oeichlerxusers000000 000000 Opencyclemap 1 1024 http://a.tile.thunderforest.com/cycle/%1/%2/%3.png Map data: (c) OpenStreetMap contributors, ODbL | Rendering: (c) OpenCycleMap , CC-BY-SA qmapshack-1.10.0/src/map/IMapOnline.cpp000644 001750 000144 00000010712 13216234140 020762 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Christian Eichler code@christian-eichler.de 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 "CMainWindow.h" #include "map/CMapDraw.h" #include "map/IMapOnline.h" #include "map/cache/CDiskCache.h" #include #include IMapOnline::IMapOnline(CMapDraw * parent) : IMap(eFeatVisibility | eFeatTileCache, parent) { accessManager = new QNetworkAccessManager(parent->thread()); connect(accessManager, &QNetworkAccessManager::finished, this, &IMapOnline::slotRequestFinished); connect(this, &IMapOnline::sigQueueChanged, this, &IMapOnline::slotQueueChanged); } bool IMapOnline::httpsCheck(const QString &url) { if(url.toLower().startsWith("https") && !QSslSocket::supportsSsl()) { QString msg = tr( "This map requires OpenSSL support. However due to legal restrictions in some countries " "OpenSSL is not packaged with QMapShack. You can have a look at the " "OpenSSL Homepage " "for binaries. You have to copy libeay32.dll and ssleay32.dll into the QMapShack program directory." ); QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), msg, QMessageBox::Abort); return false; } return true; } void IMapOnline::slotQueueChanged() { QMutexLocker lock(&mutex); if(!urlQueue.isEmpty() && urlPending.size() < 6) { // request up to 6 pending request for(int i = 0; i < (6 - urlPending.size()); i++) { QString url = urlQueue.dequeue(); lastRequest = urlQueue.isEmpty(); QNetworkRequest request; request.setUrl(url); for(const rawHeaderItem_t &item : rawHeaderItems) { request.setRawHeader(item.name.toLatin1(), item.value.toLatin1()); } accessManager->get(request); urlPending << url; if(lastRequest) { break; } } } else if(lastRequest && urlPending.isEmpty()) { lastRequest = false; // if all tiles are received the map layer can be redrawn with all tiles from cache map->emitSigCanvasUpdate(); } if(timeLastUpdate.elapsed() > 2000) { timeLastUpdate.start(); map->emitSigCanvasUpdate(); } // report status of pending tiles int pending = urlQueue.size() + urlPending.size(); if(pending) { map->reportStatusToCanvas(name, tr("%1: %2 tiles pending
").arg(name).arg(pending)); } else { map->reportStatusToCanvas(name, ""); } } void IMapOnline::slotRequestFinished(QNetworkReply* reply) { QMutexLocker lock(&mutex); QString url = reply->url().toString(); if(urlPending.contains(url)) { QImage img; // only take good responses if(!reply->error()) { // read image data img.loadFromData(reply->readAll()); } // always store image to cache, the cache will take care of NULL images diskCache->store(url, img); urlPending.removeAll(url); } // debug output any error if(reply->error()) { qDebug() << "Request to" << url << "failed:" << reply->errorString(); } // delete reply object reply->deleteLater(); // check for more items to be queued slotQueueChanged(); } void IMapOnline::configureCache() { QMutexLocker lock(&mutex); delete diskCache; diskCache = new CDiskCache(getCachePath(), getCacheSize(), getCacheExpiration(), this); } qmapshack-1.10.0/src/map/IMap.cpp000644 001750 000144 00000006251 13216234140 017620 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "map/CMapDraw.h" #include "map/CMapPropSetup.h" #include "map/IMap.h" #include "units/IUnit.h" #include IMap::IMap(quint32 features, CMapDraw *parent) : IDrawObject(parent) , map(parent) , flagsFeature(features) { pjtar = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); } IMap::~IMap() { pj_free(pjtar); pj_free(pjsrc); delete setup; } void IMap::saveConfig(QSettings& cfg) /* override */ { IDrawObject::saveConfig(cfg); if(hasFeatureVectorItems()) { cfg.setValue("showPolygons", getShowPolygons()); cfg.setValue("showPolylines", getShowPolylines()); cfg.setValue("showPOIs", getShowPOIs()); cfg.setValue("adjustDetailLevel", getAdjustDetailLevel()); } if(hasFeatureTileCache()) { cfg.setValue("cacheSizeMB", cacheSizeMB); cfg.setValue("cacheExpiration", cacheExpiration); } if(hasFeatureTypFile()) { cfg.setValue("typeFile", typeFile); } } void IMap::loadConfig(QSettings& cfg) /* override */ { IDrawObject::loadConfig(cfg); slotSetShowPolygons(cfg.value("showPolygons", getShowPolygons()).toBool()); slotSetShowPolylines(cfg.value("showPolylines", getShowPolylines()).toBool()); slotSetShowPOIs(cfg.value("showPOIs", getShowPOIs()).toBool()); slotSetAdjustDetailLevel(cfg.value("adjustDetailLevel", getAdjustDetailLevel()).toInt()); slotSetCacheSize(cfg.value("cacheSizeMB", getCacheSize()).toInt()); slotSetCacheExpiration(cfg.value("cacheExpiration", getCacheExpiration()).toInt()); slotSetTypeFile(cfg.value("typeFile", getTypeFile()).toString()); } IMapProp *IMap::getSetup() { if(setup.isNull()) { setup = new CMapPropSetup(this, map); } return setup; } void IMap::convertRad2M(QPointF &p) const { if(pjsrc == nullptr) { return; } pj_transform(pjtar,pjsrc,1,0,&p.rx(),&p.ry(),0); } void IMap::convertM2Rad(QPointF &p) const { if(pjsrc == nullptr) { return; } pj_transform(pjsrc,pjtar,1,0,&p.rx(),&p.ry(),0); } bool IMap::findPolylineCloseBy(const QPointF&, const QPointF&, qint32, QPolygonF&) { return false; } void IMap::drawTile(const QImage& img, QPolygonF& l, QPainter& p) { drawTileLQ(img, l, p, *map, pjsrc, pjtar); } qmapshack-1.10.0/src/map/IMap.h000644 001750 000144 00000015634 13216234143 017275 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IMAP_H #define IMAP_H #include "canvas/IDrawContext.h" #include "canvas/IDrawObject.h" #include #include #include #include class CMapDraw; class IMapProp; struct poi_t; class IMap : public IDrawObject { Q_OBJECT public: IMap(quint32 features, CMapDraw * parent); virtual ~IMap(); void saveConfig(QSettings& cfg) override; void loadConfig(QSettings& cfg) override; enum features_e { eFeatVisibility = 0x00000001 ,eFeatVectorItems = 0x00000002 ,eFeatTileCache = 0x00000004 ,eFeatLayers = 0x00000008 ,eFeatTypFile = 0x00000010 }; virtual void draw(IDrawContext::buffer_t& buf) = 0; /** @brief Test if map has been loaded successfully @return Return false if map is not loaded */ bool activated() const { return isActivated; } /** @brief Get the map's setup widget. As default an instance of CMapPropSetup is used. For other setups you have to override this method. @return A pointer to the widget. Use a smart pointer to store as the widget can be destroyed at any time */ virtual IMapProp *getSetup(); virtual void getInfo(const QPoint&, QString&) {} virtual void getToolTip(const QPoint&, QString&) const {} virtual void findPOICloseBy(const QPoint&, poi_t&) const {} /** @brief Return copyright notice if any @return If no copyright notice has been decoded the string will be empty */ const QString& getCopyright() const { return copyright; } bool hasFeatureVisibility() const { return flagsFeature & eFeatVisibility; } bool hasFeatureVectorItems() const { return flagsFeature & eFeatVectorItems; } bool hasFeatureTileCache() const { return flagsFeature & eFeatTileCache; } bool hasFeatureLayers() const { return flagsFeature & eFeatLayers; } bool hasFeatureTypFile() const { return flagsFeature & eFeatTypFile; } bool getShowPolygons() const { return showPolygons; } bool getShowPolylines() const { return showPolylines; } bool getShowPOIs() const { return showPOIs; } const QString& getCachePath() const { return cachePath; } qint32 getCacheSize() const { return cacheSizeMB; } qint32 getCacheExpiration() const { return cacheExpiration; } qint32 getAdjustDetailLevel() const { return adjustDetailLevel; } const QString& getTypeFile() const { return typeFile; } /** @brief Find a matching street polyline The polyline must be close enough in terms of pixel to point 1 and 2. "Close enough" is defined by the threshold. The returned polyline uses lon/lat as coordinates. @param pt1 first point in [rad] @param pt2 second point in [rad] @param threshold the "close enough" threshold in [pixel] @param polyline the resulting polyline, if any, in [rad] @return Return true if a line has been found. */ virtual bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline); public slots: void slotSetShowPolygons(bool yes) { showPolygons = yes; } void slotSetShowPolylines(bool yes) { showPolylines = yes; } void slotSetShowPOIs(bool yes) { showPOIs = yes; } void slotSetCachePath(const QString& path) { cachePath = path; configureCache(); } void slotSetCacheSize(qint32 size) { cacheSizeMB = size; configureCache(); } void slotSetCacheExpiration(qint32 days) { cacheExpiration = days; configureCache(); } void slotSetAdjustDetailLevel(qint32 level) { adjustDetailLevel = level; } virtual void slotSetTypeFile(const QString& filename) { typeFile = filename; } protected: void convertRad2M(QPointF &p) const; void convertM2Rad(QPointF &p) const; /** @brief Detect what reprojection is needed and select the correct handler This has to be called prior to the loop that calls drawTile(); */ void detectTileDrawMode(const IDrawContext::buffer_t &buf); /** @brief Reproject (translate, rotate, scale) tile before drawing it. @param img the tile as QImage @param l a 4 point polygon to fit the tile in @param p the QPainter used to paint the tile */ void drawTile(const QImage& img, QPolygonF& l, QPainter& p); protected: /// the drawcontext this map belongs to CMapDraw * map; /** Source projection of the current map file Has to be set by subclass. Destruction has to be handled by subclass. */ projPJ pjsrc = nullptr; /** target projection Is set by IMap() to WGS84. Will be freed by ~IMap() */ projPJ pjtar = nullptr; /** @brief True if map was loaded successfully */ bool isActivated = false; /// the setup dialog. Use getSetup() for access QPointer setup; /// flag field for features defined in features_e quint32 flagsFeature; bool showPolygons = true; //< vector maps only: hide/show polygons bool showPolylines = true; //< vector maps only: hide/show polylines bool showPOIs = true; //< vector maps only: hide/show point of interest qint32 adjustDetailLevel = 0; //< vector maps only: alter threshold to show details. QString cachePath; //< streaming map only: path to cached tiles qint32 cacheSizeMB = 100; //< streaming map only: maximum size of all tiles in cache [MByte] qint32 cacheExpiration = 8; //< streaming map only: maximum age of tiles in cache [days] QString copyright; //< a copyright string to be displayed as tool tip QString typeFile; }; #endif //IMAP_H qmapshack-1.10.0/src/map/CMapItem.h000644 001750 000144 00000005537 13216234143 020107 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPITEM_H #define CMAPITEM_H #include #include #include class IMap; class CMapDraw; class CMapPropSetup; class QSettings; class CMapItem : public QTreeWidgetItem { public: CMapItem(QTreeWidget * parent, CMapDraw *map); virtual ~CMapItem(); void saveConfig(QSettings& cfg) const; void loadConfig(QSettings& cfg); /** @brief As the drawing thread is using the list widget to iterate of all maps to draw, all access has to be synchronized. */ static QMutex mutexActiveMaps; /** @brief Query if map objects are loaded @return True if the internal list of map objects is not empty. */ bool isActivated(); /** @brief Either loads or destroys internal map objects @return True if the internal list of maps is not empty after the operation. */ bool toggleActivate(); /** * @brief Load all internal map objects * @return Return true on success. */ bool activate(); /** @brief Delete all internal map objects */ void deactivate(); /** @brief Move item to top of list widget */ void moveToTop(); /** @brief Move item to bottom of active maps list */ void moveToBottom(); /** @brief Set item's icon according to map type and state */ void updateIcon(); /** @brief Show or hide child treewidget items @param yes set true to add children, false will remove all children and delete the attached widgets */ void showChildren(bool yes); private: friend class CMapDraw; CMapDraw * map; /** @brief A MD5 hash over the first 1024 bytes of the map file, to identify the map */ QString key; /** @brief List of map files forming that particular map */ QString filename; /** @brief List of loaded map objects when map is activated. */ QPointer mapfile; }; #endif //CMAPITEM_H qmapshack-1.10.0/src/map/IMapProp.cpp000644 001750 000144 00000002234 13216234140 020456 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMapDraw.h" #include "IMap.h" #include "IMapProp.h" IMapProp::IMapProp(IMap *mapfile, CMapDraw *map) : mapfile(mapfile) , map(map) { connect(mapfile, &IMap::sigPropertiesChanged, this, &IMapProp::slotPropertiesChanged); } IMapProp::~IMapProp() { } qmapshack-1.10.0/src/map/CMapMAP.h000644 001750 000144 00000005407 13216234143 017622 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPMAP_H #define CMAPMAP_H #include "map/IMap.h" #include "map/mapsforge/types.h" #include class CMapDraw; class CMapMAP : public IMap { Q_DECLARE_TR_FUNCTIONS(CMapMAP) public: CMapMAP(const QString& filename, CMapDraw *parent); virtual ~CMapMAP(); void draw(IDrawContext::buffer_t& buf) override; private: enum exce_e {eErrOpen, eErrAccess, errFormat, errAbort}; struct exce_t { exce_t(exce_e err, const QString& msg) : err(err), msg(msg) { } exce_e err; QString msg; }; struct layer_t { quint8 baseZoom; quint8 minZoom; quint8 maxZoom; quint64 offsetSubFile; quint64 sizeSubFile; }; enum header_flags_e { eHeaderFlagDebugInfo = 0x80 ,eHeaderFlagStartPosition = 0x40 ,eHeaderFlagStartZoomLevel = 0x20 ,eHeaderFlagLanguage = 0x10 ,eHeaderFlagComment = 0x08 ,eHeaderFlagCreator = 0x04 }; struct header_t { header_t() : latStart(0), lonStart(0), zoomStart(0) { } char signature[20]; quint32 sizeHeader = 0; quint32 version = 0; quint64 sizeFile = 0; quint64 timestamp = 0; qint32 minLat = 0; qint32 minLon = 0; qint32 maxLat = 0; qint32 maxLon = 0; quint16 sizeTile = 0; utf8 projection; quint8 flags = 0; // optional fields qint32 latStart; qint32 lonStart; quint8 zoomStart; utf8 language; utf8 comment; utf8 creator; QStringList tagsPOIs; QStringList tagsWays; }; QList layers; void readBasics(); QString filename; header_t header; /// top left point of the map QPointF ref1; /// bottom right point of the map QPointF ref2; }; #endif //CMAPMAP_H qmapshack-1.10.0/src/map/CMapGEMF.cpp000644 001750 000144 00000020502 13216234140 020244 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Peter Schumann peter.schumann@jeepxj.de 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 . **********************************************************************************************/ /* * Map Driver Implementation for GEMF Maps * SPECs --> http://www.cgtk.co.uk/gemf */ #include "CMainWindow.h" #include "helpers/CDraw.h" #include "map/CMapDraw.h" #include "map/CMapGEMF.h" #include "units/IUnit.h" #include #include #include #define NAMEBUFLEN 1024 inline int lon2tile(double lon, int z) { return (int)(qRound(256*(lon + 180.0) / 360.0 * qPow(2.0, z))); } inline int lat2tile(double lat, int z) { return (int)(qRound(256*(1.0 - log( qTan(lat * M_PI/180.0) + 1.0 / qCos(lat * M_PI/180.0)) / M_PI) / 2.0 * qPow(2.0, z))); } inline double tile2lon(int x, int z) { return x / qPow(2.0, z) * 360.0 - 180; } inline double tile2lat(int y, int z) { double n = M_PI - 2.0 * M_PI * y / qPow(2.0, z); return 180.0 / M_PI * qAtan(0.5 * (exp(n) - exp(-n))); } CMapGEMF::CMapGEMF(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility,parent) , filename(filename) { qDebug() << "CMapGEMF: try to open " << filename; pjsrc = pj_init_plus("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"); qDebug() << "CMapGEMF:" << "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"; QFile file(filename); file.open(QIODevice::ReadOnly); QDataStream stream(&file); stream.setByteOrder(QDataStream::BigEndian); stream >> version; stream >> tileSize; stream >> sourceNr; for(quint32 i = 0; i < sourceNr; i++) { source_t source; quint32 len; QByteArray name(NAMEBUFLEN, 0); stream >> source.index; stream >> len; if(len > NAMEBUFLEN) { qDebug() << "CMapGEMF: Name longer than " << NAMEBUFLEN << " byte"; len = NAMEBUFLEN; } stream.readRawData(name.data(),len); source.name = QString().fromLocal8Bit(name,len); sources << source; qDebug() << "CMapGEMF: Read Source " << i << " " << source.name; } stream >> rangeNum; QList ranges; quint64 tiles=0; for (quint32 i=0; i> range.zoomlevel; stream >> range.minX; stream >> range.maxX; stream >> range.minY; stream >> range.maxY; stream >> range.sourceIdx; stream >> range.offset; ranges << range; tiles += (range.maxX + 1 - range.minX)*(range.maxY + 1 - range.minY); } qDebug() << "CMapGEMF: Read " << rangeNum << "Ranges with " << tiles << " Tiles"; minZoom = MAX_ZOOM_LEVEL; maxZoom = MIN_ZOOM_LEVEL; for(quint32 i=0; i<=MAX_ZOOM_LEVEL; i++) { QList rangeZoom; for(const range_t &range : ranges) { if(range.zoomlevel == i) { rangeZoom << range; minZoom = qMin(i, minZoom); maxZoom = qMax(i, maxZoom); } } if(!rangeZoom.empty()) { rangesByZoom[i] = rangeZoom; qDebug() << "CMapGEMF: Found " << rangeZoom.length() << " ranges for zoomlevel " << i; } } QString partfile = filename; QFile f(partfile); f.open(QIODevice::ReadOnly); quint32 i=1; do { gemffile_t gf; gf.filename= partfile; gf.size = f.size(); f.close(); files << gf; partfile = filename + "-" + QString::number(i); i++; f.setFileName(partfile); } while( f.open(QIODevice::ReadOnly) ); isActivated = true; } void CMapGEMF::draw(IDrawContext::buffer_t &buf) { if(map->needsRedraw()) { return; } QPointF bufferScale = buf.scale * buf.zoomFactor; if(isOutOfScale(bufferScale)) { return; } QPointF pp = buf.ref1; map->convertRad2Px(pp); // start to draw the map QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); qreal x1 = qMin(buf.ref1.x(), buf.ref4.x()); qreal y1 = qMax(buf.ref1.y(), buf.ref2.y()); qreal x2 = qMax(buf.ref2.x(), buf.ref3.x()); qreal y2 = qMin(buf.ref3.y(), buf.ref4.y()); if(x1 < -180.0*DEG_TO_RAD) { x1 = -180*DEG_TO_RAD; } if(x2 > 180.0*DEG_TO_RAD) { x2 = 180*DEG_TO_RAD; } QPointF s1 = buf.scale * buf.zoomFactor; qreal d = NOFLOAT; quint32 z = MAX_ZOOM_LEVEL; for(quint32 i = 0; i < MAX_ZOOM_LEVEL; i++) { qreal s2 = 0.055 * (1< ranges = rangesByZoom[z]; for(const range_t &range : ranges) { if(row >= range.minX && row <= range.maxX && col >= range.minY && col <= range.maxY) { const quint32 Xidx = row - range.minX; const quint32 Yidx = col - range.minY; const quint32 nrYVals = range.maxY + 1 - range.minY; const quint32 TileIdx = Xidx * nrYVals + Yidx; const quint64 offsetRange = TileIdx * 12; // 4 + 8 quint64 offsetGEMF = offsetRange + range.offset; QString splitfile; offsetGEMF = getFilenameFromAddress(offsetGEMF, splitfile); QFile file(splitfile); file.open(QIODevice::ReadOnly); QDataStream dataFile(&file); dataFile.skipRawData(offsetGEMF); quint64 imageDataAddress; dataFile >> imageDataAddress; quint32 size; dataFile >> size; file.close(); quint64 imageDataOffset = getFilenameFromAddress(imageDataAddress, splitfile); QFile imageFile(splitfile); imageFile.open(QIODevice::ReadOnly); imageFile.seek(imageDataOffset); QByteArray imageData(size,0); imageFile.read(imageData.data(),size); return QImage::fromData((uchar *)imageData.data(),size,0); } } return QImage(); } qmapshack-1.10.0/src/map/CMapPropSetup.h000644 001750 000144 00000003075 13216234143 021145 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPPROPSETUP_H #define CMAPPROPSETUP_H #include "IMapProp.h" #include "ui_IMapPropSetup.h" class CMapPropSetup : public IMapProp, private Ui::IMapPropSetup { Q_OBJECT public: CMapPropSetup(IMap * mapfile, CMapDraw * map); virtual ~CMapPropSetup(); protected slots: void slotPropertiesChanged() override; protected: void resizeEvent(QResizeEvent * e) override; private slots: void slotScaleChanged(const QPointF& s); void slotSetMinScale(bool checked); void slotSetMaxScale(bool checked); void slotLoadTypeFile(); void slotClearTypeFile(); private: void updateScaleLabel(); static QPointF scale; }; #endif //CMAPPROPSETUP_H qmapshack-1.10.0/src/map/CMapList.cpp000644 001750 000144 00000015601 13216234140 020445 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "map/CMapDraw.h" #include "map/CMapItem.h" #include "map/CMapList.h" #include void CMapTreeWidget::dragEnterEvent(QDragEnterEvent * e) { collapseAll(); QTreeWidget::dragEnterEvent(e); } void CMapTreeWidget::dragMoveEvent(QDragMoveEvent * e) { CMapItem * item = dynamic_cast(itemAt(e->pos())); if(item && item->isActivated()) { e->setDropAction(Qt::MoveAction); QTreeWidget::dragMoveEvent(e); } else { e->setDropAction(Qt::IgnoreAction); } } void CMapTreeWidget::dropEvent(QDropEvent * e) { CMapItem * item = dynamic_cast(currentItem()); if(item) { item->showChildren(false); } QTreeWidget::dropEvent(e); if(item) { item->showChildren(true); } emit sigChanged(); } CMapList::CMapList(QWidget *parent) : QWidget(parent) { setupUi(this); connect(treeWidget, &CMapTreeWidget::customContextMenuRequested, this, &CMapList::slotContextMenu); connect(treeWidget, &CMapTreeWidget::sigChanged, this, &CMapList::sigChanged); connect(actionActivate, &QAction::triggered, this, &CMapList::slotActivate); connect(actionMoveUp, &QAction::triggered, this, &CMapList::slotMoveUp); connect(actionMoveDown, &QAction::triggered, this, &CMapList::slotMoveDown); connect(actionReloadMaps, &QAction::triggered, this, &CMapList::slotReloadMaps); connect(pushMapHonk, &QPushButton::clicked, this, &CMapList::slotMapHonk); connect(labelHelpFillMapList, &QLabel::linkActivated, this, &CMapList::slotLinkActivated); menu = new QMenu(this); menu->addAction(actionActivate); menu->addAction(actionMoveUp); menu->addAction(actionMoveDown); menu->addSeparator(); menu->addAction(actionReloadMaps); menu->addAction(CMainWindow::self().getMapSetupAction()); } CMapList::~CMapList() { } void CMapList::clear() { treeWidget->clear(); } int CMapList::count() { return treeWidget->topLevelItemCount(); } CMapItem * CMapList::item(int i) { return dynamic_cast(treeWidget->topLevelItem(i)); } void CMapList::updateHelpText() { bool haveMaps = (treeWidget->topLevelItemCount() > 0); pushMapHonk->setVisible(!haveMaps); labelHelpFillMapList->setVisible(!haveMaps); if(!haveMaps) { labelIcon->show(); labelHelpActivateMap->hide(); } else { CMapItem * item = dynamic_cast(treeWidget->topLevelItem(0)); bool showHelp = !(item && item->isActivated()); labelIcon->setVisible(showHelp); labelHelpActivateMap->setVisible(showHelp); } } void CMapList::slotActivate() { CMapItem * item = dynamic_cast(treeWidget->currentItem()); if(nullptr == item) { return; } bool activated = item->toggleActivate(); if(!activated) { treeWidget->setCurrentItem(0); } updateHelpText(); } void CMapList::slotMoveUp() { CMapItem * item = dynamic_cast(treeWidget->currentItem()); if(item == nullptr) { return; } int index = treeWidget->indexOfTopLevelItem(item); if(index == NOIDX) { return; } item->showChildren(false); treeWidget->takeTopLevelItem(index); treeWidget->insertTopLevelItem(index-1, item); item->showChildren(true); treeWidget->setCurrentItem(0); emit treeWidget->sigChanged(); } void CMapList::slotMoveDown() { CMapItem * item = dynamic_cast(treeWidget->currentItem()); if(item == nullptr) { return; } int index = treeWidget->indexOfTopLevelItem(item); if(index == NOIDX) { return; } item->showChildren(false); treeWidget->takeTopLevelItem(index); treeWidget->insertTopLevelItem(index+1, item); item->showChildren(true); treeWidget->setCurrentItem(0); emit treeWidget->sigChanged(); } void CMapList::slotContextMenu(const QPoint& point) { CMapItem * item = dynamic_cast(treeWidget->currentItem()); bool itemIsSelected = nullptr != item; bool itemIsActivated = item ? item->isActivated() : false; actionActivate->setEnabled(itemIsSelected); actionMoveUp->setEnabled(itemIsSelected); actionMoveDown->setEnabled(itemIsSelected); actionActivate->setChecked(itemIsActivated); actionActivate->setText(itemIsActivated ? tr("Deactivate") : tr("Activate")); if(itemIsSelected) { CMapItem * item1 = dynamic_cast(treeWidget->itemBelow(item)); actionMoveUp->setEnabled(itemIsActivated && (treeWidget->itemAbove(item) != 0)); actionMoveDown->setEnabled(itemIsActivated && item1 && item1->isActivated()); } QPoint p = treeWidget->mapToGlobal(point); menu->exec(p); } void saveResource(const QString& name, QDir& dir) { QFile resource1(QString("://map/%1").arg(name)); resource1.open(QIODevice::ReadOnly); QFile file(dir.absoluteFilePath(name)); file.open(QIODevice::WriteOnly); file.write(resource1.readAll()); file.close(); } void CMapList::slotMapHonk() { QString path = QFileDialog::getExistingDirectory(CMainWindow::getBestWidgetForParent(), tr("Where do you want to store maps?"), QDir::homePath()); if(path.isEmpty()) { return; } QDir dir(path); saveResource("WorldSat.wmts", dir); saveResource("WorldTopo.wmts", dir); saveResource("OpenStreetMap.tms", dir); saveResource("OSM_Topo.tms", dir); saveResource("OpenCycleMap.tms", dir); CMapDraw::setupMapPath(path); CCanvas * canvas = CMainWindow::self().getVisibleCanvas(); if(canvas) { canvas->setScales(CCanvas::eScalesSquare); } } void CMapList::slotReloadMaps() { CMapDraw::setupMapPath(CMapDraw::getMapPaths()); } void CMapList::slotLinkActivated(const QString& link) { if(link == "setup") { emit sigSetupMapPath(); } } qmapshack-1.10.0/src/map/CMapIMG.h000644 001750 000144 00000046454 13216234143 017630 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPIMG_H #define CMAPIMG_H #include "map/IMap.h" #include "map/garmin/CGarminPoint.h" #include "map/garmin/CGarminPolygon.h" #include "map/garmin/CGarminTyp.h" #include "map/garmin/Garmin.h" #include class CMapDraw; class CFileExt; class IGarminStrTbl; typedef QVector polytype_t; typedef QVector pointtype_t; class CMapIMG : public IMap { Q_OBJECT public: struct maplevel_t { bool inherited; quint8 level; quint8 bits; }; /// subfile part (TRE, RGN, ...) location information struct subfile_part_t { quint32 offset = 0; //< file offset of subfile part quint32 size = 0; //< size of the subfile part }; /// subdivision information struct subdiv_desc_t { quint32 n; quint16 next; //< section of next level bool terminate; //< end of section group quint32 rgn_start; //< offset into the subfile's RGN part quint32 rgn_end; //< end of section in RGN part (last offset = rgn_end - 1) bool hasPoints; //< there are points stored in the RGN subsection bool hasIdxPoints; //< there are index points stored in the RGN subsection bool hasPolylines; //< there are polylines stored in the RGN subsection bool hasPolygons; //< there are polygons stored in the RGN subsection qint32 iCenterLng; //< the center longitude of the area covered by this subdivision qint32 iCenterLat; //< the center latitude of the area covered by this subdivision qreal north; //< north boundary of area covered by this subsection [] qreal east; //< east boundary of area covered by this subsection [] qreal south; //< south boundary of area covered by this subsection [] qreal west; //< west boundary of area covered by this subsection [] /// area in meter coordinates covered by this subdivision [] QRectF area; /// number of left shifts for RGN data quint32 shift; /// map level this subdivision is shown quint32 level; quint32 offsetPoints2; qint32 lengthPoints2; quint32 offsetPolylines2; qint32 lengthPolylines2; quint32 offsetPolygons2; qint32 lengthPolygons2; }; struct subfile_desc_t { /// the name of the subfile (not really needed) QString name; /// location information of all parts QMap parts; qreal north = 0.0; //< north boundary of area covered by this subfile [rad] qreal east = 0.0; //< east boundary of area covered by this subfile [rad] qreal south = 0.0; //< south boundary of area covered by this subfile [rad] qreal west = 0.0; //< west boundary of area covered by this subfile [rad] /// area in [] covered by this subfile QRectF area; /// list of subdivisions QVector subdivs; /// used maplevels QVector maplevels; /// bit 1 of POI_flags (TRE header @ 0x3F) bool isTransparent = false; /// object to manage the string tables IGarminStrTbl * strtbl = nullptr; }; CMapIMG(const QString &filename, CMapDraw *parent); virtual ~CMapIMG() = default; void loadConfig(QSettings& cfg) override; void draw(IDrawContext::buffer_t& buf) override; void getToolTip(const QPoint& px, QString& infotext) const override; void findPOICloseBy(const QPoint&, poi_t& poi) const override; /** @brief Find a matching street polyline The polyline must be close enough in terms of pixel to point 1 and 2. "Close enough" is defined by the threshold. The returned polyline uses lon/lat as coordinates. @param pt1 first point in [rad] @param pt2 second point in [rad] @param threshold the "close enough" threshold in [pixel] @param polyline the resulting polyline, if any, in [rad] @return Return true if a line has been found. */ bool findPolylineCloseBy(const QPointF &pt1, const QPointF &pt2, qint32 threshold, QPolygonF& polyline) override; public slots: void slotSetTypeFile(const QString& filename) override; private: enum exce_e {eErrOpen, eErrAccess, errFormat, errLock, errAbort}; struct exce_t { exce_t(exce_e err, const QString& msg) : err(err), msg(msg) { } exce_e err; QString msg; }; struct strlbl_t { QPoint pt; QRect rect; QString str; CGarminTyp::label_type_e type = CGarminTyp::eStandard; }; quint8 scale2bits(const QPointF &scale); void setupTyp(); void readBasics(); void readSubfileBasics(subfile_desc_t& subfile, CFileExt &file); void processPrimaryMapData(); void readFile(CFileExt& file, quint32 offset, quint32 size, QByteArray& data); void loadVisibleData(bool fast, polytype_t& polygons, polytype_t& polylines, pointtype_t& points, pointtype_t& pois, unsigned level, const QRectF& viewport,QPainter& p); void loadSubDiv(CFileExt &file, const subdiv_desc_t& subdiv, IGarminStrTbl * strtbl, const QByteArray& rgndata, bool fast, const QRectF& viewport, polytype_t& polylines, polytype_t& polygons, pointtype_t& points, pointtype_t& pois); bool intersectsWithExistingLabel(const QRect &rect) const; void addLabel(const CGarminPoint &pt, const QRect &rect, CGarminTyp::label_type_e type); void drawPolygons(QPainter& p, polytype_t& lines); void drawPolylines(QPainter& p, polytype_t& lines, const QPointF &scale); void drawPoints(QPainter& p, pointtype_t& pts, QVector &rectPois); void drawPois(QPainter& p, pointtype_t& pts, QVector& rectPois); void drawLabels(QPainter& p, const QVector &lbls); void drawText(QPainter& p); void drawLine(QPainter& p, CGarminPolygon& l, const CGarminTyp::polyline_property& property, const QFontMetricsF& metrics, const QFont& font, const QPointF& scale); void drawLine(QPainter& p, const CGarminPolygon& l); void collectText(const CGarminPolygon& item, const QPolygonF& line, const QFont& font, const QFontMetricsF& metrics, qint32 lineWidth); void getInfoPoints(const pointtype_t &points, const QPoint& pt, QMultiMap& dict) const; void getInfoPolylines(const QPoint& pt, QMultiMap& dict) const; void getInfoPolygons(const QPoint& pt, QMultiMap& dict) const; #pragma pack(1) // Garmin IMG file header structure, to the start of the FAT blocks struct hdr_img_t { quint8 xorByte; ///< 0x00000000 quint8 byte0x00000001_0x0000000F[15]; char signature[7]; ///< 0x00000010 .. 0x00000016 quint8 byte0x00000017_0x00000040[42]; ///< 0x00000041 .. 0x00000047 char identifier[7]; quint8 byte0x00000048; char desc1[20]; ///< 0x00000049 .. 0x0000005C quint8 byte0x0000005D_0x00000060[4]; quint8 e1; ///< 0x00000061 quint8 e2; ///< 0x00000062 quint8 byte0x00000063_0x00000064[2]; char desc2[31]; ///< 0x00000065 .. 0x00000083 quint8 byte0x00000084_0x0000040B[904]; quint32 dataoffset; ///< 0x0000040C .. 0x0000040F quint8 byte0x00000410_0x0000041F[16]; quint16 blocks[240]; ///< 0x00000420 .. 0x000005FF quint32 blocksize() { return 1 << (e1 + e2); } }; struct FATblock_t { quint8 flag; ///< 0x00000000 char name[8]; ///< 0x00000001 .. 0x00000008 char type[3]; ///< 0x00000009 .. 0x0000000B quint32 size; ///< 0x0000000C .. 0x0000000F quint16 part; ///< 0x00000010 .. 0x00000011 quint8 byte0x00000012_0x0000001F[14]; quint16 blocks[240]; ///< 0x00000020 .. 0x000001FF }; // common header of the RGN, TRE, LBL, NET, ... parts of the IMG file struct hdr_subfile_part_t { quint16 length; ///< 0x00000000 .. 0x00000001 char type[10]; ///< 0x00000002 .. 0x0000000B quint8 byte0x0000000C; quint8 flag; ///< 0x0000000D quint8 byte0x0000000E_0x00000014[7]; }; // TRE part header, to 0xB7 struct hdr_tre_t : public hdr_subfile_part_t { quint24 northbound; ///< 0x00000015 .. 0x00000017 quint24 eastbound; ///< 0x00000018 .. 0x0000001A quint24 southbound; ///< 0x0000001B .. 0x0000001D quint24 westbound; ///< 0x0000001E .. 0x00000020 quint32 tre1_offset; ///< 0x00000021 .. 0x00000024 quint32 tre1_size; ///< 0x00000025 .. 0x00000028 quint32 tre2_offset; ///< 0x00000029 .. 0x0000002C quint32 tre2_size; ///< 0x0000002D .. 0x00000030 quint32 tre3_offset; ///< 0x00000031 .. 0x00000034 quint32 tre3_size; ///< 0x00000035 .. 0x00000038 ///< 0x00000039 .. 0x0000003A quint16 tre3_rec_size; quint8 byte0x0000003B_0x0000003E[4]; quint8 POI_flags; ///< 0x0000003F quint8 byte0x00000040_0x00000049[10]; quint32 tre4_offset; ///< 0x0000004A .. 0x0000004D quint32 tre4_size; ///< 0x0000004E .. 0x00000051 ///< 0x00000052 .. 0x00000053 quint16 tre4_rec_size; quint8 byte0x00000054_0x00000057[4]; quint32 tre5_offset; ///< 0x00000058 .. 0x0000005B quint32 tre5_size; ///< 0x0000005C .. 0x0000005F ///< 0x00000060 .. 0x00000061 quint16 tre5_rec_size; quint8 byte0x00000062_0x00000065[4]; quint32 tre6_offset; ///< 0x00000066 .. 0x00000069 quint32 tre6_size; ///< 0x0000006A .. 0x0000006D ///< 0x0000006E .. 0x0000006F quint16 tre6_rec_size; quint8 byte0x00000070_0x00000073[4]; /*-----------------------------------------------------*/ quint8 byte0x00000074_0x0000007B[8]; // Object groups V2 (CTreGroup2). quint32 tre7_offset; ///< 0x0000007C .. 0x0000007F //Groups2Offset quint32 tre7_size; ///< 0x00000080 .. 0x00000083 //dwGroups2Length ///< 0x00000084 .. 0x00000085 //wGroup2RecSize quint16 tre7_rec_size; quint8 byte0x00000086_0x00000089[4]; // Order: polyline, polygon, POI; each sorted by type (1 type 1 levels 1 subtype) quint32 tre8_offset; ///< 0x0000008A .. 0x0000008D quint32 tre8_size; ///< 0x0000008E .. 0x00000091 ///< 0x00000092 .. 0x00000093 quint16 tre8_rec_size; ///< 0x00000094 .. 0x00000095 quint16 polyl2_types_num; ///< 0x00000096 .. 0x00000097 quint16 polyg2_types_num; ///< 0x00000098 .. 0x00000099 quint16 poi2_types_num; /*-----------------------------------------------------*/ quint8 key[20]; ///< 0x0000009A .. 0x000000AD quint32 tre9_offset; ///< 0x000000AE .. 0x000000B1 quint32 tre9_size; ///< 0x000000B2 .. 0x000000B5 ///< 0x000000B6 .. 0x000000B7 quint16 tre9_rec_size; }; // RGN part header struct hdr_rgn_t : public hdr_subfile_part_t { quint32 offset; ///< 0x00000015 .. 0x00000018 quint32 length; ///< 0x00000019 .. 0x0000001C ///< 0x0000001D .. 0x00000020 quint32 offset_polyg2; ///< 0x00000021 .. 0x00000024 quint32 length_polyg2; quint8 byte0x00000025_0x00000038[20]; ///< 0x00000039 .. 0x0000003C quint32 offset_polyl2; ///< 0x0000003D .. 0x00000040 quint32 length_polyl2; quint8 byte0x00000041_0x00000054[20]; ///< 0x00000055 .. 0x00000058 quint32 offset_point2; ///< 0x00000059 .. 0x0000005C quint32 length_point2; }; // LBL part header struct hdr_lbl_t : public hdr_subfile_part_t { quint32 lbl1_offset; ///< 0x00000015 .. 0x00000018 quint32 lbl1_length; ///< 0x00000019 .. 0x0000001C quint8 addr_shift; ///< 0x0000001D quint8 coding; ///< 0x0000001E quint32 lbl2_offset; ///< 0x0000001F .. 0x00000022 quint32 lbl2_length; ///< 0x00000023 .. 0x00000026 ///< 0x00000027 .. 0x00000028 quint16 lbl2_rec_size; quint8 byte0x00000029_0x0000002C[4]; quint32 lbl3_offset; ///< 0x0000002D .. 0x00000030 quint32 lbl3_length; ///< 0x00000031 .. 0x00000034 ///< 0x00000035 .. 0x00000036 quint16 lbl3_rec_size; quint8 byte0x00000037_0x0000003A[4]; quint32 lbl4_offset; ///< 0x0000003B .. 0x0000003E quint32 lbl4_length; ///< 0x0000003F .. 0x00000042 ///< 0x00000043 .. 0x00000044 quint16 lbl4_rec_size; quint8 byte0x00000045_0x00000048[4]; quint32 lbl5_offset; ///< 0x00000049 .. 0x0000004C quint32 lbl5_length; ///< 0x0000004D .. 0x00000050 ///< 0x00000051 .. 0x00000052 quint16 lbl5_rec_size; quint8 byte0x00000053_0x00000056[4]; quint32 lbl6_offset; ///< 0x00000057 .. 0x0000005A quint32 lbl6_length; ///< 0x0000005B .. 0x0000005E ///< 0x0000005F quint8 lbl6_addr_shift; ///< 0x00000060 quint8 lbl6_glob_mask; quint8 byte0x00000061_0x00000063[3]; quint32 lbl7_offset; ///< 0x00000064 .. 0x00000067 quint32 lbl7_length; ///< 0x00000068 .. 0x0000006B ///< 0x0000006C .. 0x0000006D quint16 lbl7_rec_size; quint8 byte0x0000006E_0x00000071[4]; quint32 lbl8_offset; ///< 0x00000072 .. 0x00000075 quint32 lbl8_length; ///< 0x00000076 .. 0x00000079 ///< 0x0000007A .. 0x0000007B quint16 lbl8_rec_size; quint8 byte0x0000007C_0x0000007F[4]; quint32 lbl9_offset; ///< 0x00000080 .. 0x00000083 quint32 lbl9_length; ///< 0x00000084 .. 0x00000087 ///< 0x00000088 .. 0x00000089 quint16 lbl9_rec_size; quint8 byte0x0000008A_0x0000008D[4]; quint32 lbl10_offset; ///< 0x0000008E .. 0x00000091 quint32 lbl10_length; ///< 0x00000092 .. 0x00000095 ///< 0x00000096 .. 0x00000097 quint16 lbl10_rec_size; quint8 byte0x00000098_0x0000009B[4]; quint32 lbl11_offset; ///< 0x0000009C .. 0x0000009F quint32 lbl11_length; ///< 0x000000A0 .. 0x000000A3 ///< 0x000000A4 .. 0x000000A5 quint16 lbl11_rec_size; quint8 byte0x000000A6_0x000000A9[4]; quint16 codepage; ///< 0x000000AA .. 0x000000AB optional check length }; // NET part header struct hdr_net_t : public hdr_subfile_part_t { quint32 net1_offset; ///< 0x00000015 .. 0x00000018 quint32 net1_length; ///< 0x00000019 .. 0x0000001C ///< 0x0000001D quint8 net1_addr_shift; quint32 net2_offset; ///< 0x0000001E .. 0x00000021 quint32 net2_length; ///< 0x00000022 .. 0x00000025 ///< 0x00000026 quint8 net2_addr_shift; quint32 net3_offset; ///< 0x00000027 .. 0x0000002A quint32 net3_length; ///< 0x0000002B .. 0x0000002E }; #define TRE_MAP_LEVEL(r) ((r)->zoom & 0x0f) #define TRE_MAP_INHER(r) (((r)->zoom & 0x80) != 0) // map level definition struct tre_map_level_t { quint8 zoom; quint8 bits; quint16 nsubdiv; }; // map subdivision definition, without pointer to the lower level subparts struct tre_subdiv_t { quint24 rgn_offset; quint8 elements; quint24 center_lng; quint24 center_lat; quint16 width_trm; #define TRE_SUBDIV_WIDTH(r) (gar_load(uint16_t, (r)->width_trm) & 0x7FFF) #define TRE_SUBDIV_TERM(r) ((gar_load(uint16_t, (r)->width_trm) & 0x8000) != 0) quint16 height; }; // pointer to the lower level subparts struct tre_subdiv_next_t : public tre_subdiv_t { quint16 next; }; struct tre_subdiv2_t { quint32 offsetPolygons; quint32 offsetPolyline; quint32 offsetPoints; quint8 btObjects; }; #ifdef WIN32 #pragma pack() #else #pragma pack(0) #endif struct map_level_t { quint8 bits; quint8 level; bool useBaseMap; bool operator==(const map_level_t &ml) const { if (ml.bits != bits || ml.level != level || ml.useBaseMap != useBaseMap) { return false; } else { return true; } } static bool GreaterThan(const map_level_t &ml1, const map_level_t &ml2) { return ml1.bits < ml2.bits; } }; QString filename; quint8 mask; quint32 mask32; quint64 mask64; QString mapdesc; /// hold all subfile descriptors /** In a normal *.img file there is only one subfile. However gmapsupp.img files can hold several subfiles each with it's own subfile parts. */ QMap subfiles; /// relay the transparent flags from the subfiles bool transparent = false; QRectF maparea; QFontMetrics fm; /// combined maplevels of all tiles QVector maplevels; QMap polylineProperties; QMap polygonProperties; QList polygonDrawOrder; QMap pointProperties; QMap languages; polytype_t polygons; polytype_t polylines; pointtype_t points; pointtype_t pois; QVector labels; struct textpath_t { // QPainterPath path; QPolygonF polyline; QString text; QFont font; QVector lengths; qint32 lineWidth; }; QVector textpaths; qint8 selectedLanguage; QSet copyrights; }; #endif //CMAPIMG_H qmapshack-1.10.0/src/map/IMapPropSetup.h000644 001750 000144 00000002414 13216234143 021147 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IMAPPROPSETUP_H #define IMAPPROPSETUP_H #include class IMap; class CMapDraw; class IMapPropSetup : public QWidget { Q_OBJECT public: IMapPropSetup(IMap * mapfile, CMapDraw * map); virtual ~IMapPropSetup(); protected slots: virtual void slotPropertiesChanged()= 0; protected: IMap * mapfile; CMapDraw * map; }; #endif //IMAPPROPSETUP_H qmapshack-1.10.0/src/map/WorldTopo.wmts000644 001750 000144 00000037414 12511746047 021153 0ustar00oeichlerxusers000000 000000 World_Topo_Map OGC WMTS 1.0.0 RESTful KVP RESTful KVP World_Topo_Map World_Topo_Map -2.0037507067161843E7 -1.9971868880408604E7 2.0037507067161843E7 1.997186888040863E7 -179.9999885408441 -85.00000000000003 179.9999885408441 85.00000000000006 image/jpg default028mm GoogleMapsCompatible TileMatrix using 0.28mm The tile matrix set that has scale values calculated based on the dpi defined by OGC specification (dpi assumes 0.28mm as the physical distance of a pixel). default028mm urn:ogc:def:crs:EPSG::3857 0 5.590822640285016E8 -2.0037508342787E7 2.0037508342787E7 256 256 1 1 1 2.7954113201425034E8 -2.0037508342787E7 2.0037508342787E7 256 256 2 2 2 1.3977056600712562E8 -2.0037508342787E7 2.0037508342787E7 256 256 4 4 3 6.988528300356235E7 -2.0037508342787E7 2.0037508342787E7 256 256 8 8 4 3.494264150178117E7 -2.0037508342787E7 2.0037508342787E7 256 256 16 16 5 1.7471320750890587E7 -2.0037508342787E7 2.0037508342787E7 256 256 32 32 6 8735660.375445293 -2.0037508342787E7 2.0037508342787E7 256 256 64 64 7 4367830.187722647 -2.0037508342787E7 2.0037508342787E7 256 256 128 128 8 2183915.0938617955 -2.0037508342787E7 2.0037508342787E7 256 256 256 256 9 1091957.5469304253 -2.0037508342787E7 2.0037508342787E7 256 256 512 512 10 545978.7734656851 -2.0037508342787E7 2.0037508342787E7 256 256 1024 1023 11 272989.38673237007 -2.0037508342787E7 2.0037508342787E7 256 256 2048 2045 12 136494.69336618503 -2.0037508342787E7 2.0037508342787E7 256 256 4096 4090 13 68247.34668309252 -2.0037508342787E7 2.0037508342787E7 256 256 8192 8179 14 34123.67334154626 -2.0037508342787E7 2.0037508342787E7 256 256 16384 16358 15 17061.836671245605 -2.0037508342787E7 2.0037508342787E7 256 256 32768 32715 16 8530.918335622802 -2.0037508342787E7 2.0037508342787E7 256 256 65536 65429 17 4265.459167338929 -2.0037508342787E7 2.0037508342787E7 256 256 131072 130858 18 2132.729584141936 -2.0037508342787E7 2.0037508342787E7 256 256 262144 261715 19 1066.3647915984968 -2.0037508342787E7 2.0037508342787E7 256 256 524288 523430 GoogleMapsCompatible the wellknown 'GoogleMapsCompatible' tile matrix set defined by OGC WMTS specification GoogleMapsCompatible urn:ogc:def:crs:EPSG:6.18.3:3857 urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible 0 559082264.0287178 -20037508.34278925 20037508.34278925 256 256 1 1 1 279541132.0143589 -20037508.34278925 20037508.34278925 256 256 2 2 2 139770566.0071794 -20037508.34278925 20037508.34278925 256 256 4 4 3 69885283.00358972 -20037508.34278925 20037508.34278925 256 256 8 8 4 34942641.50179486 -20037508.34278925 20037508.34278925 256 256 16 16 5 17471320.75089743 -20037508.34278925 20037508.34278925 256 256 32 32 6 8735660.375448715 -20037508.34278925 20037508.34278925 256 256 64 64 7 4367830.187724357 -20037508.34278925 20037508.34278925 256 256 128 128 8 2183915.093862179 -20037508.34278925 20037508.34278925 256 256 256 256 9 1091957.546931089 -20037508.34278925 20037508.34278925 256 256 512 512 10 545978.7734655447 -20037508.34278925 20037508.34278925 256 256 1024 1024 11 272989.3867327723 -20037508.34278925 20037508.34278925 256 256 2048 2048 12 136494.6933663862 -20037508.34278925 20037508.34278925 256 256 4096 4096 13 68247.34668319309 -20037508.34278925 20037508.34278925 256 256 8192 8192 14 34123.67334159654 -20037508.34278925 20037508.34278925 256 256 16384 16384 15 17061.83667079827 -20037508.34278925 20037508.34278925 256 256 32768 32768 16 8530.918335399136 -20037508.34278925 20037508.34278925 256 256 65536 65536 17 4265.459167699568 -20037508.34278925 20037508.34278925 256 256 131072 131072 18 2132.729583849784 -20037508.34278925 20037508.34278925 256 256 262144 262144 qmapshack-1.10.0/src/map/CMapPathSetup.h000644 001750 000144 00000002676 13216234143 021127 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPPATHSETUP_H #define CMAPPATHSETUP_H #include "ui_IMapPathSetup.h" #include class CMapPathSetup : public QDialog, private Ui::IMapPathSetup { Q_OBJECT public: CMapPathSetup(QStringList& paths, QString &pathCache); virtual ~CMapPathSetup(); public slots: void accept() override; private slots: void slotAddPath(); void slotDelPath(); void slotItemSelectionChanged(); void slotChangeCachePath(); void slotMapHonk(); private: QStringList& paths; QString& pathCache; }; #endif //CMAPPATHSETUP_H qmapshack-1.10.0/src/map/OSM_Topo.tms000644 001750 000144 00000001311 13015033052 020436 0ustar00oeichlerxusers000000 000000 OSM D-Land TK 50 3 18 Open Topo Map https://opentopomap.org/%1/%2/%3.png 3 11 Trails https://tile.waymarkedtrails.org/hiking/%1/%2/%3.png 3 9 Whatever Map data: (c) OpenStreetMap contributors, ODbL | Rendering: (c) OpenTopoMap, CC-BY-SA | Trails by tile.waymarkedtrails.org qmapshack-1.10.0/src/map/CMapVRT.h000644 001750 000144 00000003500 13216234143 017650 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPVRT_H #define CMAPVRT_H #include "map/IMap.h" class CMapDraw; class GDALDataset; class CMapVRT : public IMap { Q_OBJECT public: CMapVRT(const QString& filename, CMapDraw *parent); virtual ~CMapVRT(); void draw(IDrawContext::buffer_t& buf) override; private: QString filename; /// instance of GDAL dataset GDALDataset * dataset; /// number of color bands used by the *vrt int rasterBandCount = 0; /// QT representation of the vrt's color table QVector colortable; /// width in number of px quint32 xsize_px = 0; /// height in number of px quint32 ysize_px = 0; /// scale [px/m] qreal xscale = 0; /// scale [px/m] qreal yscale = 0; qreal xrot = 0; qreal yrot = 0; QPointF ref1; QPointF ref2; QPointF ref3; QPointF ref4; QTransform trFwd; QTransform trInv; bool hasOverviews = false; }; #endif //CMAPVRT_H qmapshack-1.10.0/src/map/CMapDraw.cpp000644 001750 000144 00000031041 13216234140 020423 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/Poi.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "map/CMapDraw.h" #include "map/CMapItem.h" #include "map/CMapList.h" #include "map/CMapPathSetup.h" #include "map/IMap.h" #include "map/cache/CDiskCache.h" #include "setup/IAppSetup.h" #include #include QList CMapDraw::maps; QString CMapDraw::cachePath = ""; QStringList CMapDraw::mapPaths; QStringList CMapDraw::supportedFormats = QString("*.vrt|*.jnx|*.img|*.rmap|*.wmts|*.tms|*.gemf").split('|'); CMapDraw::CMapDraw(CCanvas *parent) : IDrawContext("map", CCanvas::eRedrawMap, parent) { mapList = new CMapList(canvas); CMainWindow::self().addMapList(mapList, canvas->objectName()); connect(canvas, &CCanvas::destroyed, mapList, &CMapList::deleteLater); connect(mapList, &CMapList::sigChanged, this, &CMapDraw::emitSigCanvasUpdate); buildMapList(); maps << this; } CMapDraw::~CMapDraw() { maps.removeOne(this); } void CMapDraw::setProjection(const QString& proj) /* override */ { // --- save the active maps QStringList keys; saveActiveMapsList(keys); // --- now set the new projection IDrawContext::setProjection(proj); // --- now build the map list from scratch. This will deactivate -> activate all maps // By that everything is restored with the new projection buildMapList(); restoreActiveMapsList(keys); } void CMapDraw::setupMapPath() { QStringList paths = mapPaths; if(cachePath.isEmpty()) { cachePath = IAppSetup::getPlatformInstance()->defaultCachePath(); } CMapPathSetup dlg(paths, cachePath); if(dlg.exec() != QDialog::Accepted) { return; } setupMapPath(paths); } void CMapDraw::setupMapPath(const QString &path) { if(mapPaths.contains(path)) { return; } QStringList paths(mapPaths); paths << path; setupMapPath(paths); } void CMapDraw::setupMapPath(const QStringList& paths) { mapPaths = paths; for(CMapDraw * map : maps) { QStringList keys; map->saveActiveMapsList(keys); map->buildMapList(); map->restoreActiveMapsList(keys); } } void CMapDraw::saveMapPath(QSettings& cfg) { cfg.setValue("mapPath", mapPaths); cfg.setValue("cachePath", cachePath); } void CMapDraw::loadMapPath(QSettings& cfg) { mapPaths = cfg.value("mapPath", mapPaths).toStringList(); cachePath = cfg.value("cachePath", cachePath).toString(); if(cachePath.isEmpty()) { cachePath = IAppSetup::getPlatformInstance()->defaultCachePath(); } } void CMapDraw::getInfo(const QPoint& px, QString& str) { if(isRunning()) { return; } CMapItem::mutexActiveMaps.lock(); if(mapList) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(!item || item->mapfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } item->mapfile->getInfo(px, str); } } CMapItem::mutexActiveMaps.unlock(); } void CMapDraw::getToolTip(const QPoint& px, QString& str) { if(isRunning()) { return; } CMapItem::mutexActiveMaps.lock(); if(mapList) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(!item || item->mapfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } item->mapfile->getToolTip(px, str); } } CMapItem::mutexActiveMaps.unlock(); } poi_t CMapDraw::findPOICloseBy(const QPoint& px) const { poi_t poi; if(isRunning()) { return poi; } CMapItem::mutexActiveMaps.lock(); if(mapList) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(!item || item->mapfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } item->mapfile->findPOICloseBy(px, poi); if(poi.pos != NOPOINTF) { // stop at the 1st one found break; } } } CMapItem::mutexActiveMaps.unlock(); return poi; } bool CMapDraw::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline) { if(isRunning()) { return false; } bool res = false; CMapItem::mutexActiveMaps.lock(); if(mapList) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(!item || item->mapfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } res = item->mapfile->findPolylineCloseBy(pt1, pt2, threshold, polyline); if(res) { break; } } } CMapItem::mutexActiveMaps.unlock(); return res; } void CMapDraw::saveConfig(QSettings& cfg) /* override */ { // store group context for later use cfgGroup = cfg.group(); // ------------------- QStringList keys; cfg.beginGroup("map"); saveActiveMapsList(keys, cfg); cfg.setValue("active", keys); cfg.setValue("zoomIndex", zoomIndex); cfg.endGroup(); } void CMapDraw::loadConfig(QSettings& cfg) /* override */ { // store group context for later use cfgGroup = cfg.group(); // ------------------- cfg.beginGroup("map"); if(cfgGroup.isEmpty()) { restoreActiveMapsList(cfg.value("active", "").toStringList(), cfg); } else { restoreActiveMapsList(cfg.value("active", "").toStringList()); } int idx = cfg.value("zoomIndex",zoomIndex).toInt(); cfg.endGroup(); zoom(idx); } void CMapDraw::buildMapList() { QCryptographicHash md5(QCryptographicHash::Md5); QMutexLocker lock(&CMapItem::mutexActiveMaps); mapList->clear(); QSet maps; for(const QString &path : mapPaths) { QDir dir(path); // find available maps for(const QString &filename : dir.entryList(supportedFormats, QDir::Files|QDir::Readable, QDir::Name)) { QFileInfo fi(filename); CMapItem * item = new CMapItem(*mapList, this); maps.insert(fi.completeBaseName()); item->setText(0, fi.completeBaseName().replace("_", " ")); item->filename = dir.absoluteFilePath(filename); item->updateIcon(); // calculate MD5 hash from the file's first 1024 bytes QFile f(dir.absoluteFilePath(filename)); f.open(QIODevice::ReadOnly); md5.reset(); md5.addData(f.read(1024)); item->key = md5.result().toHex(); f.close(); } } CDiskCache::cleanupRemovedMaps(maps); mapList->updateHelpText(); } void CMapDraw::saveActiveMapsList(QStringList& keys) { SETTINGS; cfg.beginGroup(cfgGroup); cfg.beginGroup("map"); saveActiveMapsList(keys, cfg); cfg.endGroup(); cfg.endGroup(); } void CMapDraw::saveActiveMapsList(QStringList& keys, QSettings& cfg) { QMutexLocker lock(&CMapItem::mutexActiveMaps); for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(item && !item->mapfile.isNull()) { item->saveConfig(cfg); keys << item->key; } } } void CMapDraw::loadConfigForMapItem(CMapItem * item) { if(cfgGroup.isEmpty()) { return; } SETTINGS; cfg.beginGroup(cfgGroup); cfg.beginGroup("map"); item->loadConfig(cfg); cfg.endGroup(); cfg.endGroup(); } void CMapDraw::restoreActiveMapsList(const QStringList& keys) { QMutexLocker lock(&CMapItem::mutexActiveMaps); for(const QString &key : keys) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(item && item->key == key) { /** @Note the item will load it's configuration upon successful activation by calling loadConfigForMapItem(). */ item->activate(); break; } } } mapList->updateHelpText(); } void CMapDraw::restoreActiveMapsList(const QStringList& keys, QSettings& cfg) { QMutexLocker lock(&CMapItem::mutexActiveMaps); for(const QString &key : keys) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(item && item->key == key) { if(item->activate()) { item->loadConfig(cfg); } break; } } } mapList->updateHelpText(); } void CMapDraw::reportStatusToCanvas(const QString& key, const QString& msg) { canvas->reportStatus(key, msg); } void CMapDraw::drawt(IDrawContext::buffer_t& currentBuffer) /* override */ { // iterate over all active maps and call the draw method CMapItem::mutexActiveMaps.lock(); if(mapList && (mapList->count() != 0)) { for(int i = 0; i < mapList->count(); i++) { CMapItem * item = mapList->item(i); if(!item || item->mapfile.isNull()) { // as all active maps have to be at the top of the list // it is ok to break as soon as the first map with no // active files is hit. break; } item->mapfile->draw(currentBuffer); } } else { const int offMargin = currentBuffer.image.size().width()*0.1; const int offTop = currentBuffer.image.size().height()/3; QPainter p(¤tBuffer.image); p.setPen(Qt::black); p.translate(offMargin,offTop); QString msg = tr( "There are no maps right now. " "QMapShack is no fun without maps. " "You can install maps by pressing the 'Help! I want maps!' button in the 'Maps' dock window. " "Or you can press the F1 key to open the online documentation that tells you how to use QMapShack. " "\n\n" "If it's no fun, why don't you provide maps? Well to host maps ready for download and installation " "requires a good server. And this is not a free service. The project lacks the money. Additionally " "map and DEM data has a copyright. Therefore the copyright holder has to be asked prior to package " "the data. This is not that easy as it might sound and for some data you have to pay royalties. " "The project simply lacks resources to do this. And we think installing the stuff yourself is not " "that much to ask from you. After all the software is distributed without a fee." ); QTextDocument doc; doc.setPlainText(msg); doc.setTextWidth(currentBuffer.image.width() - offMargin*2); doc.drawContents(&p); } CMapItem::mutexActiveMaps.unlock(); } qmapshack-1.10.0/src/map/CMapWMTS.cpp000644 001750 000144 00000044476 13216234140 020340 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CDraw.h" #include "map/CMapDraw.h" #include "map/CMapWMTS.h" #include "map/cache/CDiskCache.h" #include "units/IUnit.h" #include #include #include #include CMapWMTS::CMapWMTS(const QString &filename, CMapDraw *parent) : IMapOnline(parent) { qDebug() << "------------------------------"; qDebug() << "WMTS: try to open" << filename; QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to open %1").arg(filename), QMessageBox::Abort, QMessageBox::Abort); return; } QString msg; int line, column; QDomDocument dom; if(!dom.setContent(&file, true, &msg, &line, &column)) { file.close(); QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg), QMessageBox::Abort, QMessageBox::Abort); return; } file.close(); // start to decode XML // validate content as WMTS capability sheet const QDomElement& xmlCapabilities = dom.documentElement(); if(xmlCapabilities.tagName() != "Capabilities") { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read: %1\nUnknown structure.").arg(filename), QMessageBox::Abort, QMessageBox::Abort); return; } const QDomNode& xmlServiceIdentification = xmlCapabilities.namedItem("ServiceIdentification"); QString ServiceType = xmlServiceIdentification.firstChildElement("ServiceType").text(); QString ServiceTypeVersion = xmlServiceIdentification.firstChildElement("ServiceTypeVersion").text(); if(!ServiceType.contains("WMTS", Qt::CaseInsensitive) || ServiceTypeVersion != "1.0.0") { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Unexpected service. '* WMTS 1.0.0' is expected. '%1 %2' is read.").arg(ServiceType).arg(ServiceTypeVersion), QMessageBox::Abort, QMessageBox::Abort); return; } // read setup of all layers const QDomNode& xmlContents = xmlCapabilities.namedItem("Contents"); const QDomNodeList& xmlLayers = xmlContents.toElement().elementsByTagName("Layer"); const int N = xmlLayers.count(); for(int n = 0; n < N; n++) { QString str; QStringList values; const QDomNode& xmlLayer = xmlLayers.at(n); layer_t layer; layer.title = xmlLayer.firstChildElement("Title").text(); // read bounding box const QDomNode& xmlBoundingBox = xmlLayer.firstChildElement("WGS84BoundingBox"); str = xmlBoundingBox.namedItem("LowerCorner").toElement().text(); values = str.split(" "); QPointF bottomLeft(values[0].toDouble(), values[1].toDouble()); str = xmlBoundingBox.namedItem("UpperCorner").toElement().text(); values = str.split(" "); QPointF topRight(values[0].toDouble(), values[1].toDouble()); layer.boundingBox.setBottomLeft(bottomLeft); layer.boundingBox.setTopRight(topRight); const QDomNode& xmlStyle = xmlLayer.firstChildElement("Style"); layer.styles << xmlStyle.namedItem("Identifier").toElement().text(); const QDomNode& xmlTileMatrixSetLink = xmlLayer.firstChildElement("TileMatrixSetLink"); layer.tileMatrixSet = xmlTileMatrixSetLink.namedItem("TileMatrixSet").toElement().text(); // read limits if any const QDomNode& xmlTileMatrixSetLimits = xmlTileMatrixSetLink.firstChildElement("TileMatrixSetLimits"); if(xmlTileMatrixSetLimits.isElement()) { const QDomNodeList& xmlTileMatrixLimits = xmlTileMatrixSetLimits.toElement().elementsByTagName("TileMatrixLimits"); const int L = xmlTileMatrixLimits.count(); for(int l = 0; l < L; l++) { const QDomNode& xmlTileMatrixLimit = xmlTileMatrixLimits.at(l); QString Identifier = xmlTileMatrixLimit.namedItem("TileMatrix").toElement().text(); layer.limits[Identifier] = limit_t(); limit_t& limit = layer.limits[Identifier]; limit.minTileRow = xmlTileMatrixLimit.namedItem("MinTileRow").toElement().text().toInt(); limit.maxTileRow = xmlTileMatrixLimit.namedItem("MaxTileRow").toElement().text().toInt(); limit.minTileCol = xmlTileMatrixLimit.namedItem("MinTileCol").toElement().text().toInt(); limit.maxTileCol = xmlTileMatrixLimit.namedItem("MaxTileCol").toElement().text().toInt(); } } // read resource URL of layer and replace placeholders by information that is already available const QDomNode& xmlResourceURL = xmlLayer.firstChildElement("ResourceURL"); const QDomNamedNodeMap& attr = xmlResourceURL.attributes(); layer.resourceURL = attr.namedItem("template").nodeValue(); layer.resourceURL = layer.resourceURL.replace("{style}",layer.styles[0], Qt::CaseInsensitive); layer.resourceURL = layer.resourceURL.replace("{TileMatrixSet}",layer.tileMatrixSet, Qt::CaseInsensitive); // read and replace dimensions in url string by default value const QDomNodeList& xmlDimensions = xmlLayer.toElement().elementsByTagName("Dimension"); const int D = xmlDimensions.count(); for(int d = 0; d < D; d++) { const QDomNode& xmlDimension = xmlDimensions.at(d); QString Identifier = xmlDimension.namedItem("Identifier").toElement().text(); QString Default = xmlDimension.namedItem("Default").toElement().text(); layer.resourceURL = layer.resourceURL.replace("{" + Identifier + "}", Default, Qt::CaseInsensitive); } if(!httpsCheck(layer.resourceURL)) { return; } // enable layer by default layer.enabled = true; layers << layer; } // if there is more than one layer the layer list in the properties widget has to be enabled. if(layers.size() > 1) { flagsFeature |= eFeatLayers; } // read setup of all tile matrices const QDomNodeList& xmlTileMatrixSets = xmlContents.childNodes(); const int M = xmlTileMatrixSets.count(); for(int m = 0; m < M; m++) { const QDomNode& xmlTileMatrixSet = xmlTileMatrixSets.at(m); if(xmlTileMatrixSet.nodeName() != "TileMatrixSet") { continue; } QString Identifier = xmlTileMatrixSet.namedItem("Identifier").toElement().text(); tilesets[Identifier] = tileset_t(); tileset_t& tileset = tilesets[Identifier]; // read projection string QString str = xmlTileMatrixSet.namedItem("SupportedCRS").toElement().text(); char * ptr1 = (char*)malloc(str.toLatin1().size() + 1); char * ptr2 = nullptr; strncpy(ptr1,str.toLatin1().data(), str.toLatin1().size() + 1); OGRSpatialReference oSRS; if(str.startsWith("EPSG")) { QStringList tokens = str.split(":"); oSRS.importFromEPSG(tokens.last().toInt()); } else { oSRS.importFromURN(ptr1); } oSRS.exportToProj4(&ptr2); qDebug() << ptr1 << ptr2; tileset.pjsrc = pj_init_plus(ptr2); free(ptr1); free(ptr2); if(tileset.pjsrc == nullptr) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("No georeference information found.")); return; } // read information about all matrix levels const QDomNodeList& xmlTileMatrixN = xmlTileMatrixSet.toElement().elementsByTagName("TileMatrix"); const int N = xmlTileMatrixN.count(); for(int n = 0; n < N; n++) { QString str; QStringList values; const QDomNode& xmlTileMatrix = xmlTileMatrixN.at(n); QString Identifier = xmlTileMatrix.namedItem("Identifier").toElement().text(); tileset.tilematrix[Identifier] = tilematrix_t(); tilematrix_t& matrix = tileset.tilematrix[Identifier]; str = xmlTileMatrix.namedItem("TopLeftCorner").toElement().text(); values = str.split(" "); matrix.topLeft = QPointF(values[0].toDouble(), values[1].toDouble()); matrix.scale = xmlTileMatrix.namedItem("ScaleDenominator").toElement().text().toDouble(); matrix.tileWidth = xmlTileMatrix.namedItem("TileWidth").toElement().text().toInt(); matrix.tileHeight = xmlTileMatrix.namedItem("TileHeight").toElement().text().toInt(); matrix.matrixWidth = xmlTileMatrix.namedItem("MatrixWidth").toElement().text().toInt(); matrix.matrixHeight = xmlTileMatrix.namedItem("MatrixHeight").toElement().text().toInt(); } } // ---- done reading XML file // create default cache path from filename QFileInfo fi(filename); slotSetCachePath(QDir(CMapDraw::getCacheRoot()).absoluteFilePath(fi.completeBaseName())); name = fi.completeBaseName().replace("_", " "); isActivated = true; } void CMapWMTS::getLayers(QListWidget& list) { QMutexLocker lock(&mutex); list.clear(); if(layers.size() < 2) { return; } int i = 0; for(const layer_t &layer : layers) { QListWidgetItem * item = new QListWidgetItem(layer.title, &list); item->setCheckState(layer.enabled ? Qt::Checked : Qt::Unchecked); item->setData(Qt::UserRole, i++); } connect(&list, &QListWidget::itemChanged, this, &CMapWMTS::slotLayersChanged); } void CMapWMTS::saveConfig(QSettings& cfg) /* override */ { QMutexLocker lock(&mutex); IMapOnline::saveConfig(cfg); if(layers.size() < 2) { return; } // save indices of enabled layers QStringList enabled; for(int i = 0; i< layers.size(); i++) { if(layers[i].enabled) { enabled << QString::number(i); } } cfg.setValue("enabledLayers", enabled); } void CMapWMTS::loadConfig(QSettings& cfg) /* override */ { QMutexLocker lock(&mutex); IMapOnline::loadConfig(cfg); if(layers.size() < 2) { return; } QStringList enabled; // set all layers to disabled first for(int i = 0; i< layers.size(); i++) { layers[i].enabled = false; enabled << QString::number(i); } // enable layers stored in configuration enabled = cfg.value("enabledLayers", enabled).toStringList(); for(const QString &str : enabled) { int idx = str.toInt(); if(idx < layers.size()) { layers[idx].enabled = true; } } } void CMapWMTS::slotLayersChanged(QListWidgetItem * item) { QMutexLocker lock(&mutex); bool isChecked = (item->checkState() == Qt::Checked); int idx = item->data(Qt::UserRole).toInt(); if(idx < 0) { QListWidget * list = item->listWidget(); list->blockSignals(true); for(int i = 0; i < layers.size(); i++) { list->item(i + 1)->setCheckState(isChecked ? Qt::Checked : Qt::Unchecked); layers[i].enabled = isChecked; } list->blockSignals(false); } else { layers[idx].enabled = isChecked; } map->emitSigCanvasUpdate(); } void CMapWMTS::draw(IDrawContext::buffer_t& buf) /* override */ { QMutexLocker lock(&mutex); timeLastUpdate.start(); urlQueue.clear(); if(map->needsRedraw()) { return; } QPointF bufferScale = buf.scale * buf.zoomFactor; if(isOutOfScale(bufferScale)) { return; } // get pixel offset of top left buffer corner QPointF pp = buf.ref1; map->convertRad2Px(pp); // start to draw the map QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); // calculate maximum viewport qreal x1 = buf.ref1.x() < buf.ref4.x() ? buf.ref1.x() : buf.ref4.x(); qreal y1 = buf.ref1.y() > buf.ref2.y() ? buf.ref1.y() : buf.ref2.y(); qreal x2 = buf.ref2.x() > buf.ref3.x() ? buf.ref2.x() : buf.ref3.x(); qreal y2 = buf.ref3.y() < buf.ref4.y() ? buf.ref3.y() : buf.ref4.y(); if(x1 < -180.0*DEG_TO_RAD) { x1 = -180*DEG_TO_RAD; } if(x2 > 180.0*DEG_TO_RAD) { x2 = 180*DEG_TO_RAD; } QRectF viewport(QPointF(x1,y1) * RAD_TO_DEG, QPointF(x2,y2) * RAD_TO_DEG); // draw layers for(const layer_t &layer : layers) { if(!layer.boundingBox.intersects(viewport) || !layer.enabled) { continue; } const tileset_t& tileset = tilesets[layer.tileMatrixSet]; const QMap& limits = layer.limits; // convert viewport to layer's coordinate system QPointF pt1(x1,y1); QPointF pt2(x2,y2); pj_transform(pjtar, tileset.pjsrc, 1, 0, &pt1.rx(), &pt1.ry(), 0); pj_transform(pjtar, tileset.pjsrc, 1, 0, &pt2.rx(), &pt2.ry(), 0); if(pj_is_latlong(tileset.pjsrc)) { pt1 *= RAD_TO_DEG; pt2 *= RAD_TO_DEG; } // search matrix ID of tile level with best matching scale QString tileMatrixId; QPointF s1 = (pt2 - pt1)/QPointF(buf.image.width(), buf.image.height()); qreal d = NOFLOAT; for(const QString &key : tileset.tilematrix.keys()) { const tilematrix_t& tilematrix = tileset.tilematrix[key]; qreal s2 = tilematrix.scale * 0.28e-3; if(qAbs(s2 - s1.x()) < d) { tileMatrixId = key; d = qAbs(s2 - s1.x()); } } // get min/max col/row values for that level qint32 minRow, maxRow, minCol, maxCol; const tilematrix_t& tilematrix = tileset.tilematrix[tileMatrixId]; if(!limits.isEmpty()) { if(limits.contains(tileMatrixId)) { const limit_t& limit = limits[tileMatrixId]; minCol = limit.minTileCol; maxCol = limit.maxTileCol; minRow = limit.minTileRow; maxRow = limit.maxTileRow; } else { // layer has limits but not for the selected tileMatrixId -> skip layer continue; } } else { minCol = 0; maxCol = tilematrix.matrixWidth; minRow = 0; maxRow = tilematrix.matrixHeight; } // derive range of col/row to request tiles qreal xscale = tilematrix.scale * 0.28e-3; qreal yscale = -tilematrix.scale * 0.28e-3; qint32 col1 = qFloor((pt1.x() - tilematrix.topLeft.x()) / ( xscale * tilematrix.tileWidth)); qint32 row1 = qFloor((pt1.y() - tilematrix.topLeft.y()) / ( yscale * tilematrix.tileHeight)); qint32 col2 = qFloor((pt2.x() - tilematrix.topLeft.x()) / ( xscale * tilematrix.tileWidth)); qint32 row2 = qFloor((pt2.y() - tilematrix.topLeft.y()) / ( yscale * tilematrix.tileHeight)); if(col1 < minCol) { col1 = minCol; } if(col1 > maxCol) { col1 = maxCol; } if(row1 < minRow) { row1 = minRow; } if(row1 > maxRow) { row1 = maxRow; } if(col2 < minCol) { col2 = minCol; } if(col2 > maxCol) { col2 = maxCol; } if(row2 < minRow) { row2 = minRow; } if(row2 > maxRow) { row2 = maxRow; } // start to request tiles. draw tiles in cache, queue urls of tile yet to be requested for(qint32 row = row1; row <= row2; row++) { for(qint32 col = col1; col <= col2; col++) { QString url = layer.resourceURL; url = url.replace("{TileMatrix}",tileMatrixId, Qt::CaseInsensitive); url = url.replace("{TileRow}",QString::number(row), Qt::CaseInsensitive); url = url.replace("{TileCol}",QString::number(col), Qt::CaseInsensitive); if(diskCache->contains(url)) { QImage img; diskCache->restore(url, img); QPolygonF l; qreal xx1 = col * (xscale * tilematrix.tileWidth) + tilematrix.topLeft.x(); qreal yy1 = row * (yscale * tilematrix.tileHeight) + tilematrix.topLeft.y(); qreal xx2 = (col + 1) * (xscale * tilematrix.tileWidth) + tilematrix.topLeft.x(); qreal yy2 = (row + 1) * (yscale * tilematrix.tileHeight) + tilematrix.topLeft.y(); l << QPointF(xx1, yy1) << QPointF(xx2, yy1) << QPointF(xx2, yy2) << QPointF(xx1, yy2); pj_transform(tileset.pjsrc,pjtar, 1, 0, &l[0].rx(), &l[0].ry(), 0); pj_transform(tileset.pjsrc,pjtar, 1, 0, &l[1].rx(), &l[1].ry(), 0); pj_transform(tileset.pjsrc,pjtar, 1, 0, &l[2].rx(), &l[2].ry(), 0); pj_transform(tileset.pjsrc,pjtar, 1, 0, &l[3].rx(), &l[3].ry(), 0); drawTile(img, l, p); } else { urlQueue << url; } } } emit sigQueueChanged(); } } qmapshack-1.10.0/src/map/CMapWMTS.h000644 001750 000144 00000004626 13216234143 020001 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPWMTS_H #define CMAPWMTS_H #include "map/IMapOnline.h" #include class CMapDraw; class CDiskCache; class QNetworkAccessManager; class QNetworkReply; class QListWidgetItem; class CMapWMTS : public IMapOnline { Q_OBJECT public: CMapWMTS(const QString& filename, CMapDraw *parent); virtual ~CMapWMTS() {} void draw(IDrawContext::buffer_t& buf) override; void getLayers(QListWidget& list) override; void saveConfig(QSettings& cfg) override; void loadConfig(QSettings& cfg) override; private slots: void slotLayersChanged(QListWidgetItem * item); private: struct limit_t { qint32 minTileRow; qint32 maxTileRow; qint32 minTileCol; qint32 maxTileCol; }; struct layer_t { bool enabled; QString title; QStringList styles; QString tileMatrixSet; QRectF boundingBox; QString resourceURL; QMap limits; }; QList layers; struct tilematrix_t { QPointF topLeft; qreal scale; qint32 tileWidth; qint32 tileHeight; qint32 matrixWidth; qint32 matrixHeight; }; struct tileset_t { tileset_t() : pjsrc(0) { } ~tileset_t() { if(pjsrc) { pj_free(pjsrc); } } projPJ pjsrc; QMap tilematrix; }; QMap tilesets; }; #endif //CMAPWMTS_H qmapshack-1.10.0/src/map/CMapRMAP.h000644 001750 000144 00000004706 13216234143 017745 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPRMAP_H #define CMAPRMAP_H #include "IMap.h" class CMapDraw; class CMapRMAP : public IMap { Q_OBJECT public: CMapRMAP(const QString& filename, CMapDraw *parent); void draw(IDrawContext::buffer_t& buf) override; private: struct level_t { level_t() : offsetLevel(0), width(0), height(0), xTiles(0), yTiles(0), xscale(0), yscale(0) { } quint64 offsetLevel; qint32 width; qint32 height; qint32 xTiles; qint32 yTiles; QVector offsetJpegs; quint64 getOffsetJpeg(quint32 x, quint32 y) { qint32 idx = y * xTiles + x; return idx < offsetJpegs.size() ? offsetJpegs[idx] : 0; } qreal xscale; qreal yscale; }; bool setProjection(const QString& projection, const QString& datum); level_t& findBestLevel(const QPointF &s); QString filename; /// total width in number of px qint32 xsize_px = 0; /// total height in number of px qint32 ysize_px = 0; /// width of a tile in number of px quint32 tileSizeX = 0; /// height of a tile in number of px quint32 tileSizeY = 0; /// all pre-scaled levels QList levels; /// reference point [m] or [°] (left hand side of map) qreal xref1 = 0; /// reference point [m] or [°] (top of map) qreal yref1 = 0; /// reference point [m] or [°] (right hand side of map) qreal xref2 = 0; /// reference point [m] or [°] (bottom of map) qreal yref2 = 0; QPointF scale; }; #endif // CMAPRMAP_H qmapshack-1.10.0/src/map/cache/000755 001750 000144 00000000000 13216664445 017344 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/map/cache/CDiskCache.h000644 001750 000144 00000003654 13216234143 021432 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CDISKCACHE_H #define CDISKCACHE_H #include #include #include #include class QTimer; class CDiskCache : public QObject { Q_OBJECT public: CDiskCache(const QString& path, qint32 size, qint32 days, QObject *parent); virtual ~CDiskCache() = default; void store(const QString& key, QImage& img); void restore(const QString& key, QImage& img); bool contains(const QString& key) const; static void cleanupRemovedMaps(const QSet &maps); private slots: void slotCleanup(); private: void removeCacheFile(const QFileInfo &fileinfo); QDir dir; const qint32 maxSizeMB; //< maximum cache size in MB const qint32 expirationDays; //< expiration time in days /// hash table to cache images as files on disc QHash table; /// hash table to cache loaded images in memory QHash cache; QTimer * timer; QImage dummy {256, 256, QImage::Format_ARGB32}; mutable QMutex mutex; }; #endif //CDISKCACHE_H qmapshack-1.10.0/src/map/cache/CDiskCache.cpp000644 001750 000144 00000013065 13216234140 021757 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CDiskCache.h" #include "map/CMapDraw.h" #include "version.h" #include CDiskCache::CDiskCache(const QString &path, qint32 maxSizeMB, qint32 expirationDays, QObject * parent) : QObject(parent) , dir(path) , maxSizeMB(maxSizeMB) , expirationDays(expirationDays) { dummy.fill(Qt::transparent); dir.mkpath(dir.path()); QFile IDfile(dir.absoluteFilePath("QMS_cache")); if(!IDfile.exists()) { if(IDfile.open(QIODevice::ReadWrite)) { QTextStream(&IDfile) << "QMapShack " << VER_STR; } } QFileInfoList files = dir.entryInfoList(QStringList("*.png"), QDir::Files); for(const QFileInfo &fileinfo : files) { QString hash = fileinfo.baseName(); table[hash] = fileinfo.fileName(); } timer = new QTimer(this); timer->setSingleShot(false); timer->start(20000); connect(timer, &QTimer::timeout, this, &CDiskCache::slotCleanup); } void CDiskCache::store(const QString& key, QImage& img) { QMutexLocker lock(&mutex); QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(key.toLatin1()); QString hash = md5.result().toHex(); QString filename = QString("%1.png").arg(hash); if(!img.isNull()) { img.save(dir.absoluteFilePath(filename)); table[hash] = filename; cache[hash] = img; } else { cache[hash] = dummy; } } void CDiskCache::restore(const QString& key, QImage& img) { QMutexLocker lock(&mutex); QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(key.toLatin1()); QString hash = md5.result().toHex(); if(cache.contains(hash)) { img = cache[hash]; } else if(table.contains(hash)) { img.load(dir.absoluteFilePath(table[hash])); if(!cache.contains(hash)) { cache[hash] = img; } } else { img = QImage(); } } bool CDiskCache::contains(const QString& key) const { QMutexLocker lock(&mutex); QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(key.toLatin1()); QString hash = md5.result().toHex(); return table.contains(hash) || cache.contains(hash); } void CDiskCache::removeCacheFile(const QFileInfo &fileinfo) { QString hash = fileinfo.baseName(); table.remove(hash); cache.remove(hash); QFile::remove(fileinfo.absoluteFilePath()); } void CDiskCache::slotCleanup() { QMutexLocker lock(&mutex); QFileInfoList files = dir.entryInfoList(QStringList("*.png"), QDir::Files); QDateTime now = QDateTime::currentDateTime(); qint32 maxSizeBytes = maxSizeMB * 1024 * 1024; qint32 tmpSize = 0; // expire old files and calculate cache size for(const QFileInfo &fileinfo : files) { if(fileinfo.lastModified().daysTo(now) > expirationDays) { removeCacheFile(fileinfo); qDebug() << "remove tile" << fileinfo.lastModified() << fileinfo.absoluteFilePath() << "(reason: expired)"; } else { tmpSize += fileinfo.size(); } } if(tmpSize > maxSizeBytes) { files = dir.entryInfoList(QStringList("*.png"), QDir::Files, QDir::Time|QDir::Reversed); // if cache is still too large remove oldest files for(const QFileInfo &fileinfo : files) { removeCacheFile(fileinfo); qDebug() << "remove tile" << fileinfo.lastModified() << fileinfo.absoluteFilePath() << "(reason: cache size limit)"; tmpSize -= fileinfo.size(); if(tmpSize < maxSizeBytes) { break; } } } } void CDiskCache::cleanupRemovedMaps(const QSet &maps) { QString cacheRoot = CMapDraw::getCacheRoot(); if(cacheRoot.isEmpty()) { qWarning() << "cacheRoot is empty, that should not happen at all"; return; } const QStringList &dirs = QDir(cacheRoot).entryList(QStringList("*"), QDir::Dirs | QDir::NoDotAndDotDot); for(const QString &dir : dirs) { QDir qdir(cacheRoot + "/" + dir); if(!maps.contains(dir)) { QDir qdir(cacheRoot + "/" + dir); if(QFile(qdir.absoluteFilePath("QMS_cache")).exists()) { qDebug() << "remove cache directory" << dir << "(reason: map no longer exists)"; for(const QString &file : qdir.entryList(QDir::Files)) { qdir.remove(file); } qdir.cdUp(); qdir.rmdir(dir); } else { qDebug() << "ignoring " << dir << " (reason: no QMS cache)"; } } } } qmapshack-1.10.0/src/map/CMapTMS.cpp000644 001750 000144 00000027466 13216234140 020211 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CDraw.h" #include "map/CMapDraw.h" #include "map/CMapTMS.h" #include "map/cache/CDiskCache.h" #include "units/IUnit.h" #include #include #include #include #include #include inline int lon2tile(double lon, int z) { return (int)(qRound(256*(lon + 180.0) / 360.0 * qPow(2.0, z))); } inline int lat2tile(double lat, int z) { return (int)(qRound(256*(1.0 - log( qTan(lat * M_PI/180.0) + 1.0 / qCos(lat * M_PI/180.0)) / M_PI) / 2.0 * qPow(2.0, z))); } inline double tile2lon(int x, int z) { return x / qPow(2.0, z) * 360.0 - 180; } inline double tile2lat(int y, int z) { double n = M_PI - 2.0 * M_PI * y / qPow(2.0, z); return 180.0 / M_PI * qAtan(0.5 * (exp(n) - exp(-n))); } CMapTMS::CMapTMS(const QString &filename, CMapDraw *parent) : IMapOnline(parent) { qDebug() << "------------------------------"; qDebug() << "TMS: try to open" << filename; pjsrc = pj_init_plus("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"); qDebug() << "tms:" << "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"; QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to open %1").arg(filename), QMessageBox::Abort, QMessageBox::Abort); return; } QString msg; int line, column; QDomDocument dom; if(!dom.setContent(&file, true, &msg, &line, &column)) { file.close(); QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read: %1\nline %2, column %3:\n %4").arg(filename).arg(line).arg(column).arg(msg), QMessageBox::Abort, QMessageBox::Abort); return; } file.close(); const QDomElement& xmlTms = dom.firstChildElement("TMS"); name = xmlTms.firstChildElement("Title").text(); copyright = xmlTms.firstChildElement("Copyright").text(); if(xmlTms.firstChildElement("MaxZoomLevel").isElement()) { maxZoomLevel = xmlTms.firstChildElement("MaxZoomLevel").text().toInt(); } if(xmlTms.firstChildElement("MinZoomLevel").isElement()) { minZoomLevel = xmlTms.firstChildElement("MinZoomLevel").text().toInt(); } const QDomNodeList& xmlLayers = xmlTms.elementsByTagName("Layer"); qint32 N = xmlLayers.count(); layers.resize(N); for(qint32 n = 0; n < N; ++n) { const QDomNode& xmlLayer = xmlLayers.item(n); int idx = xmlLayer.attributes().namedItem("idx").nodeValue().toInt(); layers[idx].strUrl = xmlLayer.namedItem("ServerUrl").toElement().text(); layers[idx].script = xmlLayer.namedItem("Script").toElement().text(); layers[idx].minZoomLevel = minZoomLevel; layers[idx].maxZoomLevel = maxZoomLevel; if(xmlLayer.namedItem("Title").isElement()) { layers[idx].title = xmlLayer.namedItem("Title").toElement().text(); } else { layers[idx].title = tr("Layer %1").arg(idx + 1); } if(xmlLayer.firstChildElement("MinZoomLevel").isElement()) { layers[idx].minZoomLevel = xmlLayer.firstChildElement("MinZoomLevel").text().toInt(); } if(xmlLayer.firstChildElement("MaxZoomLevel").isElement()) { layers[idx].maxZoomLevel = xmlLayer.firstChildElement("MaxZoomLevel").text().toInt(); } if(!httpsCheck(layers[idx].strUrl)) { return; } } const QDomElement& xmlRawHeader = xmlTms.firstChildElement("RawHeader"); const QDomNodeList& xmlValues = xmlRawHeader.elementsByTagName("Value"); N = xmlValues.count(); for(qint32 n = 0; n < N; ++n) { const QDomNode& xmlValue = xmlValues.item(n); registerHeaderItem( xmlValue.attributes().namedItem("name").nodeValue(), xmlValue.toElement().text() ); } // if there is more than one layer the layer list in the properties widget has to be enabled. if(layers.size() > 1) { flagsFeature |= eFeatLayers; } // create default cache path from filename QFileInfo fi(filename); slotSetCachePath(QDir(CMapDraw::getCacheRoot()).absoluteFilePath(fi.completeBaseName())); name = fi.completeBaseName().replace("_", " "); isActivated = true; } void CMapTMS::getLayers(QListWidget& list) /* override */ { QMutexLocker lock(&mutex); list.clear(); if(layers.size() < 2) { return; } int i = 0; for(const layer_t &layer : layers) { QListWidgetItem * item = new QListWidgetItem(layer.title, &list); item->setCheckState(layer.enabled ? Qt::Checked : Qt::Unchecked); item->setData(Qt::UserRole, i++); } connect(&list, &QListWidget::itemChanged, this, &CMapTMS::slotLayersChanged); } void CMapTMS::saveConfig(QSettings& cfg) /* override */ { QMutexLocker lock(&mutex); IMapOnline::saveConfig(cfg); if(layers.size() < 2) { return; } // save indices of enabled layers QStringList enabled; for(int i = 0; i< layers.size(); i++) { if(layers[i].enabled) { enabled << QString::number(i); } } cfg.setValue("enabledLayers", enabled); } void CMapTMS::loadConfig(QSettings& cfg) { QMutexLocker lock(&mutex); IMapOnline::loadConfig(cfg); if(layers.size() < 2) { return; } QStringList enabled; // set all layers to disabled first for(int i = 0; i< layers.size(); i++) { layers[i].enabled = false; enabled << QString::number(i); } // enable layers stored in configuration enabled = cfg.value("enabledLayers", enabled).toStringList(); for(const QString &str : enabled) { int idx = str.toInt(); if(idx < layers.size()) { layers[idx].enabled = true; } } } void CMapTMS::slotLayersChanged(QListWidgetItem * item) { QMutexLocker lock(&mutex); bool isChecked = (item->checkState() == Qt::Checked); int idx = item->data(Qt::UserRole).toInt(); if(idx < 0) { QListWidget * list = item->listWidget(); list->blockSignals(true); for(int i = 0; i < layers.size(); i++) { list->item(i + 1)->setCheckState(isChecked ? Qt::Checked : Qt::Unchecked); layers[i].enabled = isChecked; } list->blockSignals(false); } else { layers[idx].enabled = isChecked; } map->emitSigCanvasUpdate(); } QString CMapTMS::createUrl(const layer_t& layer, int x, int y, int z) { QMutexLocker lock(&mutex); if(layer.strUrl.startsWith("script")) { QString filename = layer.strUrl.mid(9); QFile scriptFile(filename); if (!scriptFile.open(QIODevice::ReadOnly)) { return ""; } QTextStream stream(&scriptFile); QString contents = stream.readAll(); scriptFile.close(); QScriptEngine engine; QScriptValue fun = engine.evaluate(contents, filename); if(engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "uncaught exception at line" << line << ":" << fun.toString(); } QScriptValueList args; args << z << x << y; QScriptValue res = fun.call(QScriptValue(), args); return res.toString(); } else if(!layer.script.isEmpty()) { QScriptEngine engine; QScriptValue fun = engine.evaluate(layer.script); QScriptValueList args; args << z << x << y; QScriptValue res = fun.call(QScriptValue(), args); return res.toString(); } return layer.strUrl.arg(z).arg(x).arg(y); } void CMapTMS::draw(IDrawContext::buffer_t& buf) /* override */ { QMutexLocker lock(&mutex); timeLastUpdate.start(); urlQueue.clear(); if(map->needsRedraw()) { return; } QPointF bufferScale = buf.scale * buf.zoomFactor; if(isOutOfScale(bufferScale)) { return; } // get pixel offset of top left buffer corner QPointF pp = buf.ref1; map->convertRad2Px(pp); // start to draw the map QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); // calculate maximum viewport qreal x1 = buf.ref1.x() < buf.ref4.x() ? buf.ref1.x() : buf.ref4.x(); qreal y1 = buf.ref1.y() > buf.ref2.y() ? buf.ref1.y() : buf.ref2.y(); qreal x2 = buf.ref2.x() > buf.ref3.x() ? buf.ref2.x() : buf.ref3.x(); qreal y2 = buf.ref3.y() < buf.ref4.y() ? buf.ref3.y() : buf.ref4.y(); if(x1 < -180.0*DEG_TO_RAD) { x1 = -180*DEG_TO_RAD; } if(x2 > 180.0*DEG_TO_RAD) { x2 = 180*DEG_TO_RAD; } // draw layers for(const layer_t &layer : layers) { if(!layer.enabled) { continue; } qint32 z = 20; QPointF s1 = buf.scale * buf.zoomFactor; qreal d = NOFLOAT; for(qint32 i = layer.minZoomLevel; i < 21; i++) { qreal s2 = 0.055 * (1< layer.maxZoomLevel) { continue; } z = 21 - z; qint32 row1, row2, col1, col2; col1 = lon2tile(x1 * RAD_TO_DEG, z) / 256; col2 = lon2tile(x2 * RAD_TO_DEG, z) / 256; row1 = lat2tile(y1 * RAD_TO_DEG, z) / 256; row2 = lat2tile(y2 * RAD_TO_DEG, z) / 256; // qDebug() << col1 << col2 << row1 << row2 << (col2 - col1) << (row2 - row1) << ((col2 - col1) * (row2 - row1)); // start to request tiles. draw tiles in cache, queue urls of tile yet to be requested for(qint32 row = row1; row <= row2; row++) { for(qint32 col = col1; col <= col2; col++) { QString url = createUrl(layer, col, row, z); // qDebug() << url; if(diskCache->contains(url)) { QImage img; diskCache->restore(url, img); QPolygonF l; qreal xx1 = tile2lon(col, z) * DEG_TO_RAD; qreal yy1 = tile2lat(row, z) * DEG_TO_RAD; qreal xx2 = tile2lon(col + 1, z) * DEG_TO_RAD; qreal yy2 = tile2lat(row + 1, z) * DEG_TO_RAD; l << QPointF(xx1, yy1) << QPointF(xx2, yy1) << QPointF(xx2, yy2) << QPointF(xx1, yy2); drawTile(img, l, p); } else { urlQueue << url; } } } emit sigQueueChanged(); } } qmapshack-1.10.0/src/map/IMapPropSetup.cpp000644 001750 000144 00000002272 13216234140 021501 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMapDraw.h" #include "IMap.h" #include "IMapPropSetup.h" IMapPropSetup::IMapPropSetup(IMap *mapfile, CMapDraw *map) : mapfile(mapfile) , map(map) { connect(mapfile, &IMap::sigPropertiesChanged, this, &IMapPropSetup::slotPropertiesChanged); } IMapPropSetup::~IMapPropSetup() { } qmapshack-1.10.0/src/map/CMapItem.cpp000644 001750 000144 00000014527 13216234140 020436 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "map/CMapDraw.h" #include "map/CMapGEMF.h" #include "map/CMapIMG.h" #include "map/CMapItem.h" #include "map/CMapJNX.h" #include "map/CMapMAP.h" #include "map/CMapRMAP.h" #include "map/CMapTMS.h" #include "map/CMapVRT.h" #include "map/CMapWMTS.h" #include "map/IMapProp.h" #include QMutex CMapItem::mutexActiveMaps(QMutex::Recursive); CMapItem::CMapItem(QTreeWidget *parent, CMapDraw * map) : QTreeWidgetItem(parent) , map(map) { // it's everything but not drag-n-drop until it gets activated setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); } CMapItem::~CMapItem() { } void CMapItem::saveConfig(QSettings& cfg) const { if(mapfile.isNull()) { return; } cfg.beginGroup(key); mapfile->saveConfig(cfg); cfg.endGroup(); } void CMapItem::loadConfig(QSettings& cfg) { if(mapfile.isNull()) { return; } cfg.beginGroup(key); mapfile->loadConfig(cfg); cfg.endGroup(); } void CMapItem::showChildren(bool yes) { if(yes && !mapfile.isNull()) { QTreeWidget * tw = treeWidget(); QTreeWidgetItem * item = new QTreeWidgetItem(this); item->setFlags(Qt::ItemIsEnabled); tw->setItemWidget(item, 0, mapfile->getSetup()); } else { QList items = takeChildren(); qDeleteAll(items); delete mapfile->getSetup(); } } void CMapItem::updateIcon() { if(filename.isEmpty()) { return; } static QHash icons { {"rmap", "://icons/32x32/MimeRMAP.png"} , {"jnx", "://icons/32x32/MimeJNX.png"} , {"vrt", "://icons/32x32/MimeVRT.png"} , {"img", "://icons/32x32/MimeIMG.png"} , {"map", "://icons/32x32/MimeMAP.png"} , {"wmts", "://icons/32x32/MimeWMTS.png"} , {"tms", "://icons/32x32/MimeTMS.png"} , {"gemf", "://icons/32x32/MimeGEMF.png"} }; const QString &suffix = QFileInfo(filename).suffix().toLower(); QPixmap img( icons.contains(suffix) ? icons[suffix] : "://icons/32x32/Map.png" ); setIcon(/* col */ 0, QIcon(img)); } bool CMapItem::isActivated() { QMutexLocker lock(&mutexActiveMaps); return !mapfile.isNull(); } bool CMapItem::toggleActivate() { QMutexLocker lock(&mutexActiveMaps); if(mapfile.isNull()) { return activate(); } else { deactivate(); return false; } } void CMapItem::deactivate() { QMutexLocker lock(&mutexActiveMaps); // remove mapfile setup dialog as child of this item showChildren(false); // remove mapfile object delete mapfile; // maybe used to reflect changes in the icon updateIcon(); // move to bottom of the active map list moveToBottom(); // deny drag-n-drop again setFlags(flags() & ~Qt::ItemIsDragEnabled); map->reportStatusToCanvas(text(0), ""); } bool CMapItem::activate() { QMutexLocker lock(&mutexActiveMaps); delete mapfile; // load map by suffix QFileInfo fi(filename); if(fi.suffix().toLower() == "rmap") { mapfile = new CMapRMAP(filename, map); } else if(fi.suffix().toLower() == "jnx") { mapfile = new CMapJNX(filename, map); } else if(fi.suffix().toLower() == "img") { mapfile = new CMapIMG(filename, map); } else if(fi.suffix().toLower() == "vrt") { mapfile = new CMapVRT(filename, map); } else if(fi.suffix().toLower() == "map") { mapfile = new CMapMAP(filename, map); } else if(fi.suffix().toLower() == "wmts") { mapfile = new CMapWMTS(filename, map); } else if(fi.suffix().toLower() == "tms") { mapfile = new CMapTMS(filename, map); } else if(fi.suffix().toLower() == "gemf") { mapfile = new CMapGEMF(filename, map); } updateIcon(); // no mapfiles loaded? Bad. if(mapfile.isNull()) { return false; } // if map is activated successfully add to the list of map files // else delete all previous loaded maps and abort if(!mapfile->activated()) { delete mapfile; return false; } setToolTip(0, mapfile->getCopyright()); // append list of active map files moveToBottom(); // an active map is subject to drag-n-drop setFlags(flags() | Qt::ItemIsDragEnabled); /* As the map file setup is stored in the context of the CMapDraw object the configuration has to be loaded via the CMapDraw object to select the correct group context in the QSetting object. This call will result into a call of loadConfig() of this CMapItem object. */ map->loadConfigForMapItem(this); // Add the mapfile setup dialog as child of this item showChildren(true); return true; } void CMapItem::moveToTop() { QTreeWidget * w = treeWidget(); QMutexLocker lock(&mutexActiveMaps); w->takeTopLevelItem(w->indexOfTopLevelItem(this)); w->insertTopLevelItem(0, this); map->emitSigCanvasUpdate(); } void CMapItem::moveToBottom() { int row; QTreeWidget * w = treeWidget(); QMutexLocker lock(&mutexActiveMaps); w->takeTopLevelItem(w->indexOfTopLevelItem(this)); for(row = 0; row < w->topLevelItemCount(); row++) { CMapItem * item = dynamic_cast(w->topLevelItem(row)); if(item && item->mapfile.isNull()) { break; } } w->insertTopLevelItem(row, this); map->emitSigCanvasUpdate(); } qmapshack-1.10.0/src/map/IMapPathSetup.ui000644 001750 000144 00000013772 12540525371 021327 0ustar00oeichlerxusers000000 000000 IMapPathSetup 0 0 450 277 Setup map paths Root path of tile cache for online maps: - ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png 22 22 Qt::Horizontal QAbstractItemView::ExtendedSelection ... :/icons/32x32/Add.png:/icons/32x32/Add.png 22 22 false ... :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png 22 22 Qt::Vertical 20 40 64 16777215 :/icons/48x48/Help.png Qt::AlignCenter 0 0 - Qt::AlignJustify|Qt::AlignVCenter true 0 0 Qt::Vertical QDialogButtonBox::Cancel|QDialogButtonBox::Ok Help! I want maps! I don't want to read the documentation! buttonBox accepted() IMapPathSetup accept() 248 254 157 274 buttonBox rejected() IMapPathSetup reject() 316 260 286 274 qmapshack-1.10.0/src/map/CMapPathSetup.cpp000644 001750 000144 00000006503 13216234140 021450 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "map/CMapDraw.h" #include "map/CMapList.h" #include "map/CMapPathSetup.h" #include CMapPathSetup::CMapPathSetup(QStringList &paths, QString& pathCache) : QDialog(CMainWindow::getBestWidgetForParent()) , paths(paths) , pathCache(pathCache) { setupUi(this); connect(toolAdd, &QToolButton::clicked, this, &CMapPathSetup::slotAddPath); connect(toolDelete, &QToolButton::clicked, this, &CMapPathSetup::slotDelPath); connect(listWidget, &QListWidget::itemSelectionChanged, this, &CMapPathSetup::slotItemSelectionChanged); connect(pushMapHonk, &QPushButton::clicked, this, &CMapPathSetup::slotMapHonk); for(const QString &path : paths) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } labelCacheRoot->setText(pathCache); connect(toolCacheRoot, &QToolButton::clicked, this, &CMapPathSetup::slotChangeCachePath); labelHelp->setText(tr("Add or remove paths containing maps. There can be multiple maps in a path but no sub-path is parsed. Supported formats are: %1").arg(CMapDraw::getSupportedFormats().join(", "))); } CMapPathSetup::~CMapPathSetup() { } void CMapPathSetup::slotItemSelectionChanged() { QList items = listWidget->selectedItems(); toolDelete->setEnabled(!items.isEmpty()); } void CMapPathSetup::slotAddPath() { QString path = QFileDialog::getExistingDirectory(this, tr("Select map path..."), QDir::homePath(), 0); if(!path.isEmpty()) { if(!paths.contains(path)) { QListWidgetItem * item = new QListWidgetItem(listWidget); item->setText(path); } } } void CMapPathSetup::slotDelPath() { QList items = listWidget->selectedItems(); qDeleteAll(items); } void CMapPathSetup::slotChangeCachePath() { QString path = QFileDialog::getExistingDirectory(this, tr("Select root path..."), labelCacheRoot->text()); if(path.isEmpty()) { return; } labelCacheRoot->setText(path); } void CMapPathSetup::slotMapHonk() { CMapList::slotMapHonk(); close(); } void CMapPathSetup::accept() { paths.clear(); for(int i = 0; i < listWidget->count(); i++) { QListWidgetItem *item = listWidget->item(i); paths << item->text(); } pathCache = QDir(labelCacheRoot->text()).absolutePath(); QDialog::accept(); } qmapshack-1.10.0/src/map/CMapRMAP.cpp000644 001750 000144 00000035155 13216234140 020277 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CDraw.h" #include "map/CMapDraw.h" #include "map/CMapRMAP.h" #include "units/IUnit.h" #include #include CMapRMAP::CMapRMAP(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility,parent) , filename(filename) { qDebug() << "------------------------------"; qDebug() << "RMAP: try to open" << filename; QFile file(filename); file.open(QIODevice::ReadOnly); // qDebug() << file.errorString(); QDataStream stream(&file); stream.setByteOrder(QDataStream::LittleEndian); QByteArray charbuf(20,0); stream.readRawData(charbuf.data(), 19); if("CompeGPSRasterImage" != QString(charbuf)) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("This is not a TwoNav RMAP file."), QMessageBox::Abort, QMessageBox::Abort); return; } quint32 tag1, tag2, tmp32; stream >> tag1 >> tag2 >> tmp32; if(tag1 != 10 || tag2 != 7) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Unknown sub-format."), QMessageBox::Abort, QMessageBox::Abort); return; } stream >> xsize_px >> ysize_px; stream >> tmp32 >> tmp32; stream >> tileSizeX >> tileSizeY; ysize_px = -ysize_px; quint64 mapDataOffset; stream >> mapDataOffset; stream >> tmp32; qint32 nZoomLevels; stream >> nZoomLevels; for(int i=0; i < nZoomLevels; i++) { level_t level; stream >> level.offsetLevel; levels << level; } for(int i=0; i> level.width; stream >> level.height; stream >> level.xTiles; stream >> level.yTiles; for(int j=0; j<(level.xTiles * level.yTiles); j++) { quint64 offset; stream >> offset; level.offsetJpegs << offset; } } file.seek(mapDataOffset); stream >> tmp32 >> tmp32; charbuf.resize(tmp32 + 1); charbuf.fill(0); stream.readRawData(charbuf.data(), tmp32); QPoint p0; QPoint p1; QPoint p2; QPoint p3; projXY c0 = {0,0}; projXY c1 = {0,0}; projXY c2 = {0,0}; projXY c3 = {0,0}; bool pointsAreLongLat = true; QString projection; QString datum; QStringList lines = QString(charbuf).split("\r\n"); for(const QString &line : lines) { // qDebug() << line; if(line.startsWith("Version=")) { if(line.split("=")[1] != "2") { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Unknown version."), QMessageBox::Abort, QMessageBox::Abort); return; } } else if(line.startsWith("Projection=")) { projection = line.split("=")[1]; } else if(line.startsWith("Datum=")) { datum = line.split("=")[1]; } else if(line.startsWith("P0=")) { QStringList vals = line.split("=")[1].split(","); if(vals.size() < 5) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read reference point."), QMessageBox::Abort, QMessageBox::Abort); return; } p0 = QPoint(vals[0].toInt(), vals[1].toInt()); if(vals[2] == "A") { c0.u = vals[3].toDouble() * DEG_TO_RAD; c0.v = vals[4].toDouble() * DEG_TO_RAD; } else { c0.u = vals[3].toDouble(); c0.v = vals[4].toDouble(); } } else if(line.startsWith("P1=")) { QStringList vals = line.split("=")[1].split(","); if(vals.size() < 5) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read reference point."), QMessageBox::Abort, QMessageBox::Abort); return; } p1 = QPoint(vals[0].toInt(), vals[1].toInt()); if(vals[2] == "A") { c1.u = vals[3].toDouble() * DEG_TO_RAD; c1.v = vals[4].toDouble() * DEG_TO_RAD; } else { pointsAreLongLat = false; c1.u = vals[3].toDouble(); c1.v = vals[4].toDouble(); } } else if(line.startsWith("P2=")) { QStringList vals = line.split("=")[1].split(","); if(vals.size() < 5) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read reference point."), QMessageBox::Abort, QMessageBox::Abort); return; } p2 = QPoint(vals[0].toInt(), vals[1].toInt()); if(vals[2] == "A") { c2.u = vals[3].toDouble() * DEG_TO_RAD; c2.v = vals[4].toDouble() * DEG_TO_RAD; } else { pointsAreLongLat = false; c2.u = vals[3].toDouble(); c2.v = vals[4].toDouble(); } } else if(line.startsWith("P3=")) { QStringList vals = line.split("=")[1].split(","); if(vals.size() < 5) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to read reference point."), QMessageBox::Abort, QMessageBox::Abort); return; } p3 = QPoint(vals[0].toInt(), vals[1].toInt()); if(vals[2] == "A") { c3.u = vals[3].toDouble() * DEG_TO_RAD; c3.v = vals[4].toDouble() * DEG_TO_RAD; } else { pointsAreLongLat = false; c3.u = vals[3].toDouble(); c3.v = vals[4].toDouble(); } } else { // qDebug() << line; } //qDebug() << line; } if(!projection.isEmpty() && !datum.isEmpty()) { if(!setProjection(projection, datum)) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Unknown projection and datum (%1%2).").arg(projection).arg(datum), QMessageBox::Abort, QMessageBox::Abort); return; } } if(!pj_is_latlong(pjsrc)) { if(pointsAreLongLat) { pj_transform(pjtar, pjsrc, 1, 0, &c0.u, &c0.v, 0); pj_transform(pjtar, pjsrc, 1, 0, &c1.u, &c1.v, 0); pj_transform(pjtar, pjsrc, 1, 0, &c2.u, &c2.v, 0); pj_transform(pjtar, pjsrc, 1, 0, &c3.u, &c3.v, 0); } // qDebug() << c0.u << c0.v; // qDebug() << c1.u << c1.v; // qDebug() << c2.u << c2.v; // qDebug() << c3.u << c3.v; xref1 = NOFLOAT; yref1 = -NOFLOAT; xref2 = -NOFLOAT; yref2 = NOFLOAT; } else { xref1 = 180 * DEG_TO_RAD; yref1 = -90 * DEG_TO_RAD; xref2 = -180 * DEG_TO_RAD; yref2 = 90 * DEG_TO_RAD; } if(c0.u < xref1) { xref1 = c0.u; } if(c0.u > xref2) { xref2 = c0.u; } if(c1.u < xref1) { xref1 = c1.u; } if(c1.u > xref2) { xref2 = c1.u; } if(c2.u < xref1) { xref1 = c2.u; } if(c2.u > xref2) { xref2 = c2.u; } if(c0.v > yref1) { yref1 = c0.v; } if(c0.v < yref2) { yref2 = c0.v; } if(c1.v > yref1) { yref1 = c1.v; } if(c1.v < yref2) { yref2 = c1.v; } if(c2.v > yref1) { yref1 = c2.v; } if(c2.v < yref2) { yref2 = c2.v; } scale.rx() = (xref2 - xref1) / xsize_px; scale.ry() = (yref2 - yref1) / ysize_px; qreal widthL0 = levels[0].width; qreal heightL0 = levels[0].height; for(int i=0; i levels[i].xscale) { return levels[i]; } int j = 0; qreal dsx = NOFLOAT; for(; j < levels.size(); j++) { level_t& level = levels[j]; if(qAbs(level.xscale - s.x()) < dsx) { i = j; dsx = qAbs(level.xscale - s.x()); } } return levels[i]; } void CMapRMAP::draw(IDrawContext::buffer_t& buf) /* override */ { if(map->needsRedraw()) { return; } // convert top left buffer corner // into buffer's coordinate system QPointF pp = buf.ref1; map->convertRad2Px(pp); // find best level for buffer's scale factor derived from base scale and zoom factor QPointF bufferScale = buf.scale * buf.zoomFactor; if(isOutOfScale(bufferScale)) { return; } level_t& level = findBestLevel(bufferScale); // convert top left and bottom right point of buffer to local coord. system QPointF p1 = buf.ref1; QPointF p2 = buf.ref3; convertRad2M(p1); convertRad2M(p2); // find indices into tile buffer int idxx1 = qFloor((p1.x() - xref1) / (level.xscale * tileSizeX)); int idxy1 = qFloor((p1.y() - yref1) / (level.yscale * tileSizeY)); int idxx2 = qCeil((p2.x() - xref1) / (level.xscale * tileSizeX)); int idxy2 = qCeil((p2.y() - yref1) / (level.yscale * tileSizeY)); if(idxx1 < 0) { idxx1 = 0; } if(idxx1 >= level.xTiles) { idxx1 = level.xTiles; } if(idxx2 < 0) { idxx2 = 0; } if(idxx2 >= level.xTiles) { idxx2 = level.xTiles; } if(idxy1 < 0) { idxy1 = 0; } if(idxy1 >= level.yTiles) { idxy1 = level.yTiles; } if(idxy2 < 0) { idxy2 = 0; } if(idxy2 >= level.yTiles) { idxy2 = level.yTiles; } // ----- start drawing ----- QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); QFile file(filename); file.open(QIODevice::ReadOnly); QDataStream stream(&file); stream.setByteOrder(QDataStream::LittleEndian); for(int idxy = idxy1; idxy < idxy2; idxy++) { if(map->needsRedraw()) { break; } for(int idxx = idxx1; idxx < idxx2; idxx++) { if(map->needsRedraw()) { break; } quint32 tag; quint32 len; quint64 offset = level.getOffsetJpeg(idxx, idxy); file.seek(offset); stream >> tag >> len; QImage img; img.load(&file,"JPG"); if(img.isNull()) { continue; } qreal imgw = img.width(); qreal imgh = img.height(); // derive tile's corner coordinate QPolygonF l(4); l[0].rx() = xref1 + idxx * tileSizeX * level.xscale; l[0].ry() = yref1 + idxy * tileSizeY * level.yscale; l[1].rx() = xref1 + (idxx * tileSizeX + imgw) * level.xscale; l[1].ry() = yref1 + idxy * tileSizeY * level.yscale; l[2].rx() = xref1 + (idxx * tileSizeX + imgw) * level.xscale; l[2].ry() = yref1 + (idxy * tileSizeY + imgh) * level.yscale; l[3].rx() = xref1 + idxx * tileSizeX * level.xscale; l[3].ry() = yref1 + (idxy * tileSizeY + imgh) * level.yscale; pj_transform(pjsrc,pjtar, 1, 0, &l[0].rx(), &l[0].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[1].rx(), &l[1].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[2].rx(), &l[2].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[3].rx(), &l[3].ry(), 0); drawTile(img, l, p); } } } qmapshack-1.10.0/src/map/IMapPropSetup.ui000644 001750 000144 00000027316 13135614453 021353 0ustar00oeichlerxusers000000 000000 IMapPropSetup 0 0 403 330 Form 0 3 3 3 3 <html><head/><body><p>Change opacity of map</p></body></html> Qt::Horizontal 3 <html><head/><body><p>Click to use current scale as minimum scale to display the map.</p></body></html> ... :/icons/8x8/bullet_green.png :/icons/8x8/bullet_red.png:/icons/8x8/bullet_green.png 8 8 true <html><head/><body><p>Control the range of scale the map is displayed. Use the two buttons left and right to define the actual scale as either minimum or maximum scale.</p></body></html> true <html><head/><body><p>Click to use current scale as maximum scale to display the map.</p></body></html> ... :/icons/8x8/bullet_green.png :/icons/8x8/bullet_red.png:/icons/8x8/bullet_green.png 8 8 true QFrame::NoFrame QFrame::Plain 3 0 0 0 0 Areas Lines Points 0 0 Details -5 5 QFrame::NoFrame QFrame::Raised 3 0 0 0 0 QFormLayout::AllNonFixedFieldsGrow 3 3 Cache Size (MB) 100 1000 100 Expiration (Days) 1 14 - Cache Path QFrame::NoFrame QFrame::Raised 3 0 0 0 0 0 0 QFrame::StyledPanel QFrame::NoFrame QFrame::Plain 3 0 0 0 0 0 0 Type File: Forget external type file and use internal types. ... :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png Load an external type file. ... :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png qmapshack-1.10.0/src/map/CMapPropSetup.cpp000644 001750 000144 00000016332 13216234140 021475 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CSettings.h" #include "helpers/Signals.h" #include "map/CMapDraw.h" #include "map/CMapPropSetup.h" #include "map/IMap.h" #include "units/IUnit.h" #include QPointF CMapPropSetup::scale; CMapPropSetup::CMapPropSetup(IMap * mapfile, CMapDraw *map) : IMapProp(mapfile, map) { setupUi(this); slotPropertiesChanged(); connect(sliderOpacity, &QSlider::valueChanged, mapfile, &IMap::slotSetOpacity); connect(sliderOpacity, &QSlider::valueChanged, map, &CMapDraw::emitSigCanvasUpdate); connect(map, &CMapDraw::sigScaleChanged, this, &CMapPropSetup::slotScaleChanged); connect(toolSetMinScale, &QToolButton::toggled, this, &CMapPropSetup::slotSetMinScale); connect(toolSetMaxScale, &QToolButton::toggled, this, &CMapPropSetup::slotSetMaxScale); connect(checkPolygons, &QCheckBox::toggled, mapfile, &IMap::slotSetShowPolygons); connect(checkPolylines, &QCheckBox::toggled, mapfile, &IMap::slotSetShowPolylines); connect(checkPoints, &QCheckBox::toggled, mapfile, &IMap::slotSetShowPOIs); connect(spinAdjustDetails, static_cast(&QSpinBox::valueChanged), mapfile, &IMap::slotSetAdjustDetailLevel); connect(checkPolygons, &QCheckBox::clicked, map, &CMapDraw::emitSigCanvasUpdate); connect(checkPolylines, &QCheckBox::clicked, map, &CMapDraw::emitSigCanvasUpdate); connect(checkPoints, &QCheckBox::clicked, map, &CMapDraw::emitSigCanvasUpdate); connect(spinAdjustDetails, static_cast(&QSpinBox::valueChanged), map, &CMapDraw::emitSigCanvasUpdate); connect(spinCacheSize, static_cast(&QSpinBox::valueChanged), mapfile, &IMap::slotSetCacheSize); connect(spinCacheExpiration, static_cast(&QSpinBox::valueChanged), mapfile, &IMap::slotSetCacheExpiration); connect(toolOpenTypFile, &QToolButton::pressed, this, &CMapPropSetup::slotLoadTypeFile); connect(toolClearTypFile, &QToolButton::pressed, this, &CMapPropSetup::slotClearTypeFile); frameVectorItems->setVisible( mapfile->hasFeatureVectorItems() ); frameTileCache->setVisible( mapfile->hasFeatureTileCache() ); if(mapfile->hasFeatureLayers()) { frameLayers->show(); mapfile->getLayers(*listLayers); } else { frameLayers->hide(); } frameTypFile->setVisible(mapfile->hasFeatureTypFile()); } CMapPropSetup::~CMapPropSetup() { } void CMapPropSetup::resizeEvent(QResizeEvent * e) /* override */ { IMapProp::resizeEvent(e); updateScaleLabel(); } void CMapPropSetup::slotPropertiesChanged() /* override */ { X______________BlockAllSignals______________X(this); // block all signals to avoid retrigger // opacity and visibility settings sliderOpacity->setValue(mapfile->getOpacity()); qreal minScale = mapfile->getMinScale(); toolSetMinScale->setChecked(minScale != NOFLOAT); qreal maxScale = mapfile->getMaxScale(); toolSetMaxScale->setChecked(maxScale != NOFLOAT); updateScaleLabel(); // vector maps properties checkPolygons->setChecked(mapfile->getShowPolygons()); checkPolylines->setChecked(mapfile->getShowPolylines()); checkPoints->setChecked(mapfile->getShowPOIs()); spinAdjustDetails->setValue(mapfile->getAdjustDetailLevel()); // streaming map properties QString lbl = mapfile->getCachePath(); labelCachePath->setText(lbl); labelCachePath->setToolTip(lbl); spinCacheSize->setValue(mapfile->getCacheSize()); spinCacheExpiration->setValue(mapfile->getCacheExpiration()); // type file QFileInfo fi(mapfile->getTypeFile()); labelTypeFile->setText(fi.completeBaseName()); labelTypeFile->setToolTip(fi.absoluteFilePath()); toolClearTypFile->setEnabled(!labelTypeFile->text().isEmpty()); // unblock all signals X_____________UnBlockAllSignals_____________X(this); } void CMapPropSetup::slotScaleChanged(const QPointF& s) { scale = s; slotPropertiesChanged(); } void CMapPropSetup::slotSetMinScale(bool checked) { mapfile->setMinScale(checked ? scale.x() : NOFLOAT); slotPropertiesChanged(); } void CMapPropSetup::slotSetMaxScale(bool checked) { mapfile->setMaxScale(checked ? scale.x() : NOFLOAT); slotPropertiesChanged(); } #define BAR_HEIGHT 6 #define HOR_MARGIN 3 void CMapPropSetup::updateScaleLabel() { int w = labelScale->width(); int h = labelScale->height(); QPixmap pix(w,h); if(pix.isNull()) { return; } pix.fill(Qt::transparent); QPainter p(&pix); // draw bar background int xBar = HOR_MARGIN; int yBar = (h - BAR_HEIGHT) / 2; QRect bar(xBar, yBar, w-2*HOR_MARGIN, BAR_HEIGHT); p.setPen(Qt::darkBlue); p.setBrush(Qt::white); p.drawRect(bar); // draw current scale range qreal minScale = mapfile->getMinScale(); qreal maxScale = mapfile->getMaxScale(); if((minScale != NOFLOAT) || (maxScale != NOFLOAT)) { int x1Range = minScale != NOFLOAT ? HOR_MARGIN + qRound(bar.width() * (1 + log10(minScale)) / 5) : bar.left(); int x2Range = maxScale != NOFLOAT ? HOR_MARGIN + qRound(bar.width() * (1 + log10(maxScale)) / 5) : bar.right(); int yRange = yBar; QRect range(x1Range, yRange, x2Range - x1Range, BAR_HEIGHT); p.setPen(Qt::NoPen); p.setBrush(Qt::darkGreen); p.drawRect(range); } // draw scale indicator int xInd = HOR_MARGIN + qRound(bar.width() * (1 + log10(scale.x())) / 5) - 3; int yInd = yBar - 1; QRect ind(xInd, yInd, 5, BAR_HEIGHT + 2); p.setPen(Qt::darkBlue); p.setBrush(Qt::NoBrush); p.drawRect(ind); labelScale->setPixmap(pix); } void CMapPropSetup::slotLoadTypeFile() { SETTINGS; QString path = cfg.value("Paths/lastTypePath",QDir::homePath()).toString(); QString filename = QFileDialog::getOpenFileName(this, tr("Select type file..."), path, "Garmin type file (*.typ)"); if(filename.isEmpty()) { return; } QFileInfo fi(filename); cfg.setValue("Paths/lastTypePath", fi.absolutePath()); mapfile->slotSetTypeFile(filename); slotPropertiesChanged(); } void CMapPropSetup::slotClearTypeFile() { mapfile->slotSetTypeFile(""); slotPropertiesChanged(); } qmapshack-1.10.0/src/map/CMapTMS.h000644 001750 000144 00000003636 13216234143 017652 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPTMS_H #define CMAPTMS_H #include "map/IMapOnline.h" class CDiskCache; class QListWidgetItem; class QNetworkAccessManager; class QNetworkReply; class CMapTMS : public IMapOnline { Q_OBJECT public: CMapTMS(const QString& filename, CMapDraw *parent); virtual ~CMapTMS() {} void draw(IDrawContext::buffer_t& buf) override; void getLayers(QListWidget& list) override; void saveConfig(QSettings& cfg) override; void loadConfig(QSettings& cfg) override; private slots: void slotLayersChanged(QListWidgetItem * item); private: struct layer_t; QString createUrl(const layer_t& layer, int x, int y, int z); struct layer_t { layer_t() : enabled(true), minZoomLevel(0), maxZoomLevel(0) { } bool enabled; qint32 minZoomLevel; qint32 maxZoomLevel; QString title; QString strUrl; QString script; }; QVector layers; qint32 minZoomLevel = 1; qint32 maxZoomLevel = 21; }; #endif //CMAPTMS_H qmapshack-1.10.0/src/map/IMapList.ui000644 001750 000144 00000013115 13205474743 020321 0ustar00oeichlerxusers000000 000000 IMapList 0 0 400 443 Form 0 0 0 0 0 Qt::CustomContextMenu QAbstractItemView::InternalMove 32 32 QAbstractItemView::ScrollPerPixel false 1 3 3 3 3 3 0 0 :/icons/48x48/Help.png Qt::AlignHCenter|Qt::AlignTop 8 To add maps use <b>File->Setup Map Paths</b>. Or click <a href='setup'><b>here</b></a> Qt::AlignJustify|Qt::AlignVCenter true Use the context menu (right mouse button click on entry) to activate a map. Use drag-n-drop to move the activated map in the draw order. Qt::AlignJustify|Qt::AlignVCenter true Help! I want maps! I don't want to read the documentation! true :/icons/32x32/Check.png :/icons/32x32/Cancel.png:/icons/32x32/Check.png Activate :/icons/32x32/Up.png:/icons/32x32/Up.png Move Up Hide map behind previous map :/icons/32x32/Down.png:/icons/32x32/Down.png Move down Show map on top of next map :/icons/32x32/Reset.png:/icons/32x32/Reset.png Reload Maps CMapTreeWidget QTreeWidget
map/CMapList.h
qmapshack-1.10.0/src/map/CMapList.h000644 001750 000144 00000004003 13216234143 020107 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPLIST_H #define CMAPLIST_H #include #include class CMapItem; class QMenu; class CMapTreeWidget : public QTreeWidget { Q_OBJECT public: CMapTreeWidget(QWidget * parent) : QTreeWidget(parent) { } signals: void sigChanged(); protected: void dragEnterEvent(QDragEnterEvent *e) override; void dragMoveEvent(QDragMoveEvent *e) override; void dropEvent(QDropEvent *e) override; }; #include "ui_IMapList.h" class CMapList : public QWidget, private Ui::IMapList { Q_OBJECT public: CMapList(QWidget * parent); virtual ~CMapList(); void clear(); int count(); CMapItem * item(int i); operator QTreeWidget*() { return treeWidget; } void updateHelpText(); signals: void sigChanged(); void sigSetupMapPath(); public slots: static void slotMapHonk(); private slots: void slotActivate(); void slotMoveUp(); void slotMoveDown(); void slotReloadMaps(); void slotContextMenu(const QPoint &point); void slotLinkActivated(const QString& link); private: QMenu * menu; }; #endif //CMAPLIST_H qmapshack-1.10.0/src/map/CMapJNX.h000644 001750 000144 00000005504 13216234143 017642 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMAPJNX_H #define CMAPJNX_H #include "map/IMap.h" class CMapDraw; class CMapJNX : public IMap { public: CMapJNX(const QString& filename, CMapDraw *parent); void draw(IDrawContext::buffer_t& buf) override; private: QString filename; #pragma pack(1) struct hdr_t { quint32 version; // byte 00000000..00000003 quint32 devid; // byte 00000004..00000007 qint32 lat1; // byte 00000010..00000013 qint32 lon2; // byte 00000014..00000017 qint32 lat2; // byte 00000008..0000000B qint32 lon1; // byte 0000000C..0000000F quint32 details; // byte 00000018..0000001B quint32 expire; // byte 0000001C..0000001F qint32 productId; // byte 00000020..00000023 quint32 crc; // byte 00000024..00000027 quint32 signature; // byte 00000028..0000002B // byte 0000002C..0000002F quint32 signature_offset; qint32 zorder; // byte 00000030..00000033 }; #ifdef WIN32 #pragma pack() #else #pragma pack(0) #endif struct tile_t { QRectF area; quint16 width; quint16 height; quint32 size; quint32 offset; }; struct level_t { quint32 nTiles; quint32 offset; quint32 scale; QString copyright1; quint32 level; QString name1; QString name2; QString copyright2; QVector tiles; }; struct file_t { qreal lon1; qreal lat1; qreal lon2; qreal lat2; QRectF bbox; QString filename; QVector levels; }; void readFile(const QString& fn, qint32& productId); qint32 scale2level(qreal s, const file_t& file); QList files; qreal lon1 = 180.0; qreal lat1 = -90; qreal lon2 = -180; qreal lat2 = 90; }; #endif // CMAPJNX_H qmapshack-1.10.0/src/map/OpenStreetMap.tms000644 001750 000144 00000000631 12727720143 021546 0ustar00oeichlerxusers000000 000000 OpenStreetMap 2 19 http://c.tile.openstreetmap.org/%1/%2/%3.png Agent Smith Map data: (c) OpenStreetMap contributors, ODbL | Rendering: (c) OpenStreetMap , CC-BY-SA qmapshack-1.10.0/src/map/CMapVRT.cpp000644 001750 000144 00000031100 13216234140 020175 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CDraw.h" #include "map/CMapDraw.h" #include "map/CMapVRT.h" #include "units/IUnit.h" #include #include #include #define TILELIMIT 2500 #define TILESIZEX 64 #define TILESIZEY 64 CMapVRT::CMapVRT(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility,parent) , filename(filename) { qDebug() << "------------------------------"; qDebug() << "VRT: try to open" << filename; dataset = (GDALDataset*)GDALOpen(filename.toUtf8(),GA_ReadOnly); if(nullptr == dataset) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to load file: %1").arg(filename)); return; } // ------- setup color table --------- rasterBandCount = dataset->GetRasterCount(); if(rasterBandCount == 1) { GDALRasterBand *pBand = dataset->GetRasterBand(1); if(nullptr == pBand) { GDALClose(dataset); dataset = nullptr; QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("Failed to load file: %1").arg(filename)); return; } if(pBand->GetColorInterpretation() == GCI_PaletteIndex ) { GDALColorTable * pct = pBand->GetColorTable(); for(int i=0; i < pct->GetColorEntryCount(); ++i) { const GDALColorEntry& e = *pct->GetColorEntry(i); colortable << qRgba(e.c1, e.c2, e.c3, e.c4); } } else if(pBand->GetColorInterpretation() == GCI_GrayIndex ) { for(int i=0; i < 256; ++i) { colortable << qRgba(i, i, i, 255); } } else { GDALClose(dataset); dataset = nullptr; QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("File must be 8 bit palette or gray indexed.")); return; } int success = 0; qreal idx = pBand->GetNoDataValue(&success); if(success) { if((idx > 0) && (idx < colortable.size())) { QColor tmp(colortable[idx]); tmp.setAlpha(0); colortable[idx] = tmp.rgba(); } else { qDebug() << "Index for no data value is out of bound"; return; } } } if(dataset->GetRasterCount() > 0) { hasOverviews = dataset->GetRasterBand(1)->GetOverviewCount() != 0; } qDebug() << "has overviews" << hasOverviews; // ------- setup projection --------------- char str[1025] = {0}; if(dataset->GetProjectionRef()) { strncpy(str, dataset->GetProjectionRef(), sizeof(str) - 1); } OGRSpatialReference oSRS; char *wkt = str; oSRS.importFromWkt(&wkt); char *proj4 = nullptr; oSRS.exportToProj4(&proj4); pjsrc = pj_init_plus(proj4); free(proj4); if(pjsrc == 0) { delete dataset; dataset = nullptr; QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."), tr("No georeference information found.")); return; } xsize_px = dataset->GetRasterXSize(); ysize_px = dataset->GetRasterYSize(); qreal adfGeoTransform[6]; dataset->GetGeoTransform( adfGeoTransform ); xscale = adfGeoTransform[1]; yscale = adfGeoTransform[5]; xrot = adfGeoTransform[4]; yrot = adfGeoTransform[2]; trFwd.translate(adfGeoTransform[0], adfGeoTransform[3]); trFwd.scale(adfGeoTransform[1],adfGeoTransform[5]); if(adfGeoTransform[4] != 0.0) { trFwd.rotate(qAtan(adfGeoTransform[2]/adfGeoTransform[4])); } if(pj_is_latlong(pjsrc)) { // convert to RAD to match internal notations trFwd = trFwd * DEG_TO_RAD; } trInv = trFwd.inverted(); ref1 = trFwd.map(QPointF(0,0)); ref2 = trFwd.map(QPointF(xsize_px,0)); ref3 = trFwd.map(QPointF(xsize_px,ysize_px)); ref4 = trFwd.map(QPointF(0,ysize_px)); qDebug() << "FF" << trFwd; qDebug() << "RR" << trInv; isActivated = true; } CMapVRT::~CMapVRT() { GDALClose(dataset); } void CMapVRT::draw(IDrawContext::buffer_t& buf) /* override */ { if(map->needsRedraw()) { return; } QPointF bufferScale = buf.scale * buf.zoomFactor; // calculate bounding box; QPointF pt1 = ref1; QPointF pt2 = ref2; QPointF pt3 = ref3; QPointF pt4 = ref4; pj_transform(pjsrc,pjtar, 1, 0, &pt1.rx(), &pt1.ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &pt2.rx(), &pt2.ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &pt3.rx(), &pt3.ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &pt4.rx(), &pt4.ry(), 0); QPolygonF boundingBox; boundingBox << pt1 << pt2 << pt3 << pt4; map->convertRad2Px(boundingBox); // get pixel offset of top left buffer corner QPointF pp = buf.ref1; map->convertRad2Px(pp); // calculate area to read from file pt1 = buf.ref1; pt2 = buf.ref2; pt3 = buf.ref3; pt4 = buf.ref4; pj_transform(pjtar,pjsrc, 1, 0, &pt1.rx(), &pt1.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt2.rx(), &pt2.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt3.rx(), &pt3.ry(), 0); pj_transform(pjtar,pjsrc, 1, 0, &pt4.rx(), &pt4.ry(), 0); pt1 = trInv.map(pt1); pt2 = trInv.map(pt2); pt3 = trInv.map(pt3); pt4 = trInv.map(pt4); qreal left, right, top, bottom; left = pt1.x() < pt4.x() ? pt1.x() : pt4.x(); right = pt2.x() > pt3.x() ? pt2.x() : pt3.x(); top = pt1.y() < pt2.y() ? pt1.y() : pt2.y(); bottom = pt4.y() > pt3.y() ? pt4.y() : pt3.y(); if(left < 0) { left = 0; } if(left > xsize_px) { left = xsize_px; } if(top < 0) { top = 0; } if(top > ysize_px) { top = ysize_px; } if(right > xsize_px) { right = xsize_px; } if(right < 0) { right = 0; } if(bottom > ysize_px) { bottom = ysize_px; } if(bottom < 0) { bottom = 0; } qreal imgw = TILESIZEX; qreal imgh = TILESIZEY; qreal dx = imgw; qreal dy = imgh; // estimate number of tiles and use it as a limit if no // user defined limit is given qreal nTiles = ((right - left) * (bottom - top) / (dx*dy)); if(hasOverviews) { // if there are overviews tiles can be reduced by reading // with a scale factor from file. Increase amount of pixel // read until tile limit is met. while(nTiles > TILELIMIT) { dx *= 2; dy *= 2; nTiles /= 4; } } else { nTiles = getMaxScale() == NOFLOAT ? nTiles : 0; } // start to draw the map QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); // qDebug() << imgw << dx << nTiles; // limit number of tiles to keep performance if(!isOutOfScale(bufferScale) && (nTiles < TILELIMIT)) { for(qreal y = top; y < bottom; y += dy) { if(map->needsRedraw()) { break; } for(qreal x = left; x < right; x += dx) { if(map->needsRedraw()) { break; } // read tile from file CPLErr err = CE_Failure; // reduce tile size at the border of the file qreal dx_used = dx; qreal dy_used = dy; qreal imgw_used = imgw; qreal imgh_used = imgh; if((x + dx) > xsize_px) { dx_used = xsize_px - x; imgw_used = qRound(imgw * dx_used / dx) & 0xFFFFFFFC; } if((y + dy) > ysize_px) { dy_used = ysize_px - y; imgh_used = imgh * dy_used / dy; } x = qRound(x); y = qRound(y); dx_used = qFloor(dx_used); dy_used = qFloor(dy_used); imgw_used = qRound(imgw_used); imgh_used = qRound(imgh_used); if(imgw_used < 1 || imgh_used < 1) { continue; } QImage img; if(rasterBandCount == 1) { GDALRasterBand * pBand; pBand = dataset->GetRasterBand(1); img = QImage(QSize(imgw_used,imgh_used),QImage::Format_Indexed8); img.setColorTable(colortable); err = pBand->RasterIO(GF_Read ,x,y ,dx_used,dy_used ,img.bits() ,imgw_used,imgh_used ,GDT_Byte,0,0); } else { img = QImage(imgw_used,imgh_used, QImage::Format_ARGB32); img.fill(qRgba(255,255,255,255)); QVector buffer(imgw_used * imgh_used); QRgb testPix = qRgba(GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand); for(int b = 1; b <= rasterBandCount; ++b) { GDALRasterBand * pBand; pBand = dataset->GetRasterBand(b); err = pBand->RasterIO(GF_Read , x, y , dx_used, dy_used , buffer.data() , imgw_used, imgh_used , GDT_Byte, 0, 0); if(!err) { int pbandColour = pBand->GetColorInterpretation(); unsigned int offset; for (offset = 0; offset < sizeof(testPix) && *(((quint8 *)&testPix) + offset) != pbandColour; offset++) { } if(offset < sizeof(testPix)) { quint8 * pTar = img.bits() + offset; quint8 * pSrc = buffer.data(); const int size = buffer.size(); for(int i = 0; i < size; ++i) { *pTar = *pSrc; pTar += sizeof(testPix); pSrc += 1; } } } } } if(err) { continue; } QPolygonF l; l << QPointF(x,y) << QPointF(x+dx_used,y) << QPointF(x+dx_used,y+dy_used) << QPointF(x,y+dy_used); l = trFwd.map(l); pj_transform(pjsrc,pjtar, 1, 0, &l[0].rx(), &l[0].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[1].rx(), &l[1].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[2].rx(), &l[2].ry(), 0); pj_transform(pjsrc,pjtar, 1, 0, &l[3].rx(), &l[3].ry(), 0); drawTile(img, l, p); } } } p.setPen(Qt::black); p.setBrush(Qt::NoBrush); p.drawPolygon(boundingBox); } qmapshack-1.10.0/src/map/CMapGEMF.h000644 001750 000144 00000003741 13216234143 017722 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Peter Schumann peter.schumann@jeepxj.de 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 . **********************************************************************************************/ #ifndef CMAPGEMF_H #define CMAPGEMF_H #include "IMap.h" class CMapGEMF : public IMap { Q_OBJECT public: CMapGEMF(const QString& filename, CMapDraw *parent); void draw(IDrawContext::buffer_t& buf) override; private: const quint32 MAX_ZOOM_LEVEL = 21; const quint32 MIN_ZOOM_LEVEL = 0; QImage getTile(const quint32 col, const quint32 row,const quint32 z); quint64 getFilenameFromAddress(const quint64 offset, QString &filename ); struct source_t { quint32 index; QString name; }; struct gemffile_t { QString filename; quint64 size; }; struct range_t { quint32 zoomlevel; quint32 minX; quint32 maxX; quint32 minY; quint32 maxY; quint32 sourceIdx; quint64 offset; }; QString filename; quint32 version; quint32 tileSize; quint32 sourceNr; quint32 rangeNum; quint32 minZoom; quint32 maxZoom; QList< source_t> sources; QList files; QHash > rangesByZoom; }; #endif // CMAPGEMF_H qmapshack-1.10.0/src/map/IMapProp.h000644 001750 000144 00000002357 13216234143 020134 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IMAPPROP_H #define IMAPPROP_H #include class IMap; class CMapDraw; class IMapProp : public QWidget { Q_OBJECT public: IMapProp(IMap * mapfile, CMapDraw * map); virtual ~IMapProp(); protected slots: virtual void slotPropertiesChanged() = 0; protected: IMap * mapfile; CMapDraw * map; }; #endif //IMAPPROP_H qmapshack-1.10.0/src/map/CMapMAP.cpp000644 001750 000144 00000007650 13216234140 020154 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "helpers/CFileExt.h" #include "map/CMapDraw.h" #include "map/CMapMAP.h" #include #include #define INT_TO_DEG(x) (qreal(x)/1e6) #define INT_TO_RAD(x) (qreal(x)/(1e6*RAD_TO_DEG)) CMapMAP::CMapMAP(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility|eFeatVectorItems, parent) , filename(filename) { qDebug() << "------------------------------"; qDebug() << "MAP: try to open" << filename; try { readBasics(); } catch(const exce_t& e) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed ..."), e.msg, QMessageBox::Abort); return; } isActivated = true; } CMapMAP::~CMapMAP() { } void CMapMAP::readBasics() { CFileExt file(filename); if(!file.open(QIODevice::ReadOnly)) { throw exce_t(eErrOpen, tr("Failed to open: ") + filename); } QDataStream stream(&file); stream.setByteOrder(QDataStream::BigEndian); // ---------- start file header ---------------------- stream.readRawData(header.signature,sizeof(header.signature)); if(strncmp(header.signature, "mapsforge binary OSM", sizeof(header.signature)) != 0) { throw exce_t(errFormat,tr("Bad file format: ") + filename); } stream >> header.sizeHeader; stream >> header.version; stream >> header.sizeFile; stream >> header.timestamp; stream >> header.minLat; stream >> header.minLon; stream >> header.maxLat; stream >> header.maxLon; qDebug() << INT_TO_DEG(header.minLat) << INT_TO_DEG(header.minLon) << INT_TO_DEG(header.maxLat) << INT_TO_DEG(header.maxLon); ref1 = QPointF(INT_TO_RAD(header.minLon), INT_TO_RAD(header.maxLat)); ref2 = QPointF(INT_TO_RAD(header.maxLon), INT_TO_RAD(header.minLat)); stream >> header.sizeTile; stream >> header.projection; stream >> header.flags; if(header.flags & eHeaderFlagStartPosition) { stream >> header.latStart >> header.lonStart; } if(header.flags & eHeaderFlagStartZoomLevel) { stream >> header.zoomStart; } if(header.flags & eHeaderFlagLanguage) { stream >> header.language; } if(header.flags & eHeaderFlagComment) { stream >> header.comment; } if(header.flags & eHeaderFlagCreator) { stream >> header.creator; } quint16 size; utf8 tag; stream >> size; for(int i = 0; i < size; i++) { stream >> tag; header.tagsPOIs << tag; } stream >> size; for(int i = 0; i < size; i++) { stream >> tag; header.tagsWays << tag; } quint8 N; stream >> N; for(int i = 0; i < N; i++) { layer_t layer; stream >> layer.baseZoom; stream >> layer.minZoom; stream >> layer.maxZoom; stream >> layer.offsetSubFile; stream >> layer.sizeSubFile; layers << layer; } // ---------- end file header ---------------------- } void CMapMAP::draw(IDrawContext::buffer_t& buf) /* override */ { } qmapshack-1.10.0/src/map/WorldSat.wmts000644 001750 000144 00000037365 12511746042 020761 0ustar00oeichlerxusers000000 000000 World_Imagery OGC WMTS 1.0.0 RESTful KVP RESTful KVP World_Imagery World_Imagery -2.003750722959434E7 -1.997186888040859E7 2.003750722959434E7 1.9971868880408563E7 -179.99999000000003 -85.00000000000003 179.99999000000003 85.0 image/jpg default028mm GoogleMapsCompatible TileMatrix using 0.28mm The tile matrix set that has scale values calculated based on the dpi defined by OGC specification (dpi assumes 0.28mm as the physical distance of a pixel). default028mm urn:ogc:def:crs:EPSG::3857 0 5.590822640285016E8 -2.0037508342787E7 2.0037508342787E7 256 256 1 1 1 2.7954113201425034E8 -2.0037508342787E7 2.0037508342787E7 256 256 2 2 2 1.3977056600712562E8 -2.0037508342787E7 2.0037508342787E7 256 256 4 4 3 6.988528300356235E7 -2.0037508342787E7 2.0037508342787E7 256 256 8 8 4 3.494264150178117E7 -2.0037508342787E7 2.0037508342787E7 256 256 16 16 5 1.7471320750890587E7 -2.0037508342787E7 2.0037508342787E7 256 256 32 32 6 8735660.375445293 -2.0037508342787E7 2.0037508342787E7 256 256 64 64 7 4367830.187722647 -2.0037508342787E7 2.0037508342787E7 256 256 128 128 8 2183915.0938617955 -2.0037508342787E7 2.0037508342787E7 256 256 256 256 9 1091957.5469304253 -2.0037508342787E7 2.0037508342787E7 256 256 512 512 10 545978.7734656851 -2.0037508342787E7 2.0037508342787E7 256 256 1024 1023 11 272989.38673237007 -2.0037508342787E7 2.0037508342787E7 256 256 2048 2045 12 136494.69336618503 -2.0037508342787E7 2.0037508342787E7 256 256 4096 4090 13 68247.34668309252 -2.0037508342787E7 2.0037508342787E7 256 256 8192 8179 14 34123.67334154626 -2.0037508342787E7 2.0037508342787E7 256 256 16384 16358 15 17061.836671245605 -2.0037508342787E7 2.0037508342787E7 256 256 32768 32715 16 8530.918335622802 -2.0037508342787E7 2.0037508342787E7 256 256 65536 65429 17 4265.459167338929 -2.0037508342787E7 2.0037508342787E7 256 256 131072 130858 18 2132.729584141936 -2.0037508342787E7 2.0037508342787E7 256 256 262144 261715 19 1066.3647915984968 -2.0037508342787E7 2.0037508342787E7 256 256 524288 523430 GoogleMapsCompatible the wellknown 'GoogleMapsCompatible' tile matrix set defined by OGC WMTS specification GoogleMapsCompatible urn:ogc:def:crs:EPSG:6.18.3:3857 urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible 0 559082264.0287178 -20037508.34278925 20037508.34278925 256 256 1 1 1 279541132.0143589 -20037508.34278925 20037508.34278925 256 256 2 2 2 139770566.0071794 -20037508.34278925 20037508.34278925 256 256 4 4 3 69885283.00358972 -20037508.34278925 20037508.34278925 256 256 8 8 4 34942641.50179486 -20037508.34278925 20037508.34278925 256 256 16 16 5 17471320.75089743 -20037508.34278925 20037508.34278925 256 256 32 32 6 8735660.375448715 -20037508.34278925 20037508.34278925 256 256 64 64 7 4367830.187724357 -20037508.34278925 20037508.34278925 256 256 128 128 8 2183915.093862179 -20037508.34278925 20037508.34278925 256 256 256 256 9 1091957.546931089 -20037508.34278925 20037508.34278925 256 256 512 512 10 545978.7734655447 -20037508.34278925 20037508.34278925 256 256 1024 1024 11 272989.3867327723 -20037508.34278925 20037508.34278925 256 256 2048 2048 12 136494.6933663862 -20037508.34278925 20037508.34278925 256 256 4096 4096 13 68247.34668319309 -20037508.34278925 20037508.34278925 256 256 8192 8192 14 34123.67334159654 -20037508.34278925 20037508.34278925 256 256 16384 16384 15 17061.83667079827 -20037508.34278925 20037508.34278925 256 256 32768 32768 16 8530.918335399136 -20037508.34278925 20037508.34278925 256 256 65536 65536 17 4265.459167699568 -20037508.34278925 20037508.34278925 256 256 131072 131072 18 2132.729583849784 -20037508.34278925 20037508.34278925 256 256 262144 262144 qmapshack-1.10.0/src/map/garmin/000755 001750 000144 00000000000 13216664445 017556 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/map/garmin/IGarminStrTbl.cpp000644 001750 000144 00000007450 13216234140 022732 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 "IGarminStrTbl.h" #include "helpers/CFileExt.h" #include "helpers/Platform.h" #include IGarminStrTbl::IGarminStrTbl(const quint16 codepage, const quint8 mask, QObject * parent) : QObject(parent) , codepage(codepage) , mask(mask) { if(codepage != 0) { if(1250 <= codepage && codepage <= 1258) { char strcp[64]; sprintf(strcp,"Windows-%i",codepage); codec = QTextCodec::codecForName(strcp); } else if(codepage == 950) { codec = QTextCodec::codecForName("Big5"); } else if(codepage == 850) { codec = QTextCodec::codecForName("IBM 850"); } else if(codepage == 65001) { codec = QTextCodec::codecForName("UTF-8"); } else { qDebug() << "unknown codepage:" << codepage << "0x" << hex << codepage; codec = QTextCodec::codecForName("Latin1"); } } mask32 = mask; mask32 <<= 8; mask32 |= mask; mask32 <<= 8; mask32 |= mask; mask32 <<= 8; mask32 |= mask; mask64 = mask32; mask64 <<= 32; mask64 |= mask32; } IGarminStrTbl::~IGarminStrTbl() { } void IGarminStrTbl::readFile(CFileExt &file, quint32 offset, quint32 size, QByteArray& data) { if(offset + size > file.size()) { // throw exce_t(eErrOpen, tr("Failed to read: ") + file.filename()); return; } data = QByteArray::fromRawData(file.data(offset,size), size); // wenn mask == 0 ist kein xor noetig if(mask == 0) { return; } #ifdef HOST_IS_64_BIT quint64 * p64 = (quint64*)data.data(); for(quint32 i = 0; i < size/8; ++i) { *p64++ ^= mask64; } quint32 rest = size % 8; quint8 * p = (quint8*)p64; #else quint32 * p32 = (quint32*)data.data(); for(quint32 i = 0; i < size/4; ++i) { *p32++ ^= mask32; } quint32 rest = size % 4; quint8 * p = (quint8*)p32; #endif for(quint32 i = 0; i < rest; ++i) { *p++ ^= mask; } } quint32 IGarminStrTbl::calcOffset(CFileExt& file, const quint32 offset, type_e t) { quint32 newOffset = offset; if(t == poi) { QByteArray buffer; readFile(file, offsetLBL6 + offset, sizeof(quint32), buffer); newOffset = gar_ptr_load(quint32, buffer.data()); newOffset = (newOffset & 0x003FFFFF); } else if(t == net) { if(offsetNET1 == 0) { return 0xFFFFFFFF; } QByteArray data; readFile(file, offsetNET1 + (offset << addrshift2), sizeof(quint32), data); newOffset = gar_ptr_load(quint32, data.data()); if(newOffset & 0x00400000) { return 0xFFFFFFFF; } newOffset = (newOffset & 0x003FFFFF); } newOffset <<= addrshift1; // qDebug() << hex << newOffset; return newOffset; } qmapshack-1.10.0/src/map/garmin/CGarminStrTbl8.h000644 001750 000144 00000002414 13216234143 022457 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGARMINSTRTBL8_H #define CGARMINSTRTBL8_H #include "IGarminStrTbl.h" class CGarminStrTbl8 : public IGarminStrTbl { public: CGarminStrTbl8(const quint16 codepage, const quint8 mask, QObject * parent); virtual ~CGarminStrTbl8(); void get(CFileExt& file, quint32 offset, type_e t, QStringList& info) override; }; #endif //CGARMINSTRTBL8_H qmapshack-1.10.0/src/map/garmin/CGarminPoint.cpp000644 001750 000144 00000007623 13216234140 022605 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2006, 2007 Oliver Eichler oliver.eichler@gmx.de 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 . Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries. This source is based on John Mechalas documentation "Garmin IMG File Format" found at sourceforge. The missing bits and error were rectified by the source code of Konstantin Galichsky (kg@geopainting.com), http://www.geopainting.com **********************************************************************************************/ #include "CGarminPoint.h" #include "Garmin.h" #include "helpers/Platform.h" #include "units/IUnit.h" #include quint32 CGarminPoint::decode(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, const quint8 * pData) { type = (quint16)(*pData) << 8; ++pData; lbl_ptr = gar_ptr_load(uint24_t, pData); hasSubType = lbl_ptr & 0x00800000; isLbl6 = lbl_ptr & 0x00400000; lbl_ptr = lbl_ptr & 0x003FFFFF; pData += 3; qint16 dLng = gar_ptr_load(int16_t, pData); pData += 2; qint16 dLat = gar_ptr_load(int16_t, pData); pData += 2; qint32 x1 = ((qint32)dLng << shift) + iCenterLon; qint32 y1 = ((qint32)dLat << shift) + iCenterLat; pos = QPointF(GARMIN_RAD(x1),GARMIN_RAD(y1)); #ifdef DEBUG_SHOW_POINTS qDebug() << x1 << y1 << point.u << point.v; #endif if(hasSubType) { type |= *pData; return 9; } return 8; } quint32 CGarminPoint::decode2(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, const quint8 * pData, const quint8 * pEnd) { quint32 byte_size = 6; quint8 subtype; type = (quint16)(*pData) << 8; ++pData; subtype = (quint16)(*pData); ++pData; type = 0x10000 + type + (subtype & 0x1F); if(subtype & 0x80) { byte_size += 1; } qint16 dLng = gar_ptr_load(int16_t, pData); pData += 2; qint16 dLat = gar_ptr_load(int16_t, pData); pData += 2; qint32 x1,y1; x1 = ((qint32)dLng << shift) + iCenterLon; y1 = ((qint32)dLat << shift) + iCenterLat; pos = QPointF(GARMIN_RAD(x1),GARMIN_RAD(y1)); if(subtype & 0x20) { byte_size += 3; lbl_ptr = gar_ptr_load(uint24_t, pData); isLbl6 = lbl_ptr & 0x00400000; lbl_ptr &= 0x003FFFFF; } return byte_size; } QString CGarminPoint::getLabelText() const { QString str; if(!labels.isEmpty()) { if((type == 0x6200) || (type == 0x6300)) { QString unit; QString val = labels[0]; IUnit::self().meter2elevation(val.toFloat() / 3.28084f, val, unit); str = QString("%1 %2").arg(val).arg(unit); } else if(type == 0x6616) //669 DAV { if(labels.size() > 1) { QString unit; QString val = labels[1]; IUnit::self().meter2elevation(val.toFloat() / 3.28084f, val, unit); str = QString("%1 %2 %3").arg(labels[0]).arg(val).arg(unit); } else { str = labels[0]; } } else { str = labels.join(" "); } } return str; } qmapshack-1.10.0/src/map/garmin/CGarminPoint.h000644 001750 000144 00000003774 13216234143 022260 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2006, 2007 Oliver Eichler oliver.eichler@gmx.de 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 . Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries. This source is based on John Mechalas documentation "Garmin IMG File Format" found at sourceforge. The missing bits and error were rectified by the source code of Konstantin Galichsky (kg@geopainting.com), http://www.geopainting.com **********************************************************************************************/ #ifndef CGARMINPOINT_H #define CGARMINPOINT_H #include #include #include class CGarminTile; class CGarminPoint { public: CGarminPoint() = default; virtual ~CGarminPoint() = default; quint32 decode(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, const quint8 * pData); quint32 decode2(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, const quint8 * pData, const quint8 * pEnd); QString getLabelText() const; bool hasLabel() const { return !labels.isEmpty(); } quint32 type = 0; bool isLbl6 = false; bool hasSubType = false; //QString label; QPointF pos; QStringList labels; quint32 lbl_ptr = 0xFFFFFFFF; }; #endif //CGARMINPOINT_H qmapshack-1.10.0/src/map/garmin/CGarminStrTblUtf8.cpp000644 001750 000144 00000004645 13216234140 023476 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 "CGarminStrTblUtf8.h" #include CGarminStrTblUtf8::CGarminStrTblUtf8(const quint16 codepage, const quint8 mask, QObject * parent) : IGarminStrTbl(codepage, mask, parent) { } CGarminStrTblUtf8::~CGarminStrTblUtf8() { } void CGarminStrTblUtf8::get(CFileExt& file, quint32 offset, type_e t, QStringList& labels) { labels.clear(); offset = calcOffset(file, offset, t); if(offset == 0xFFFFFFFF) { return; } if(offset > (quint32)sizeLBL1) { //qWarning() << "Index into string table to large" << hex << offset << dataLBL.size() << hdrLbl->addr_shift << hdrNet->net1_addr_shift; return; } QByteArray data; quint32 size = (sizeLBL1 - offset) < 200 ? (sizeLBL1 - offset) : 200; readFile(file, offsetLBL1 + offset, size, data); char * lbl = data.data(); char * pBuffer = buffer; *pBuffer = 0; while(*lbl != 0) { if((unsigned)*lbl >= 0x1B && (unsigned)*lbl <= 0x1F) { *pBuffer = 0; if(strlen(buffer)) { labels << codec->toUnicode(buffer); pBuffer = buffer; *pBuffer = 0; } ++lbl; continue; } else if((unsigned)*lbl < 0x07) { ++lbl; continue; } else { *pBuffer++ = *lbl++; } } *pBuffer = 0; if(strlen(buffer)) { // qDebug() << QString(buffer); labels << codec->toUnicode(buffer); } } qmapshack-1.10.0/src/map/garmin/CGarminTyp.h000644 001750 000144 00000016275 13216234143 021743 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGARMINTYP_H #define CGARMINTYP_H #include class CGarminTyp { Q_DECLARE_TR_FUNCTIONS(CGarminTyp) public: CGarminTyp() = default; virtual ~CGarminTyp() = default; enum label_type_e { eStandard = 0 ,eNone = 1 ,eSmall = 2 ,eNormal = 3 ,eLarge = 4 }; struct polyline_property { polyline_property() : type(0) , penLineDay(Qt::magenta,3) , penLineNight(Qt::magenta,3) , hasBorder(false) , penBorderDay(Qt::NoPen) , penBorderNight(Qt::NoPen) , hasPixmap(false) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(false) { } polyline_property(quint16 type, const QPen& penLineDay, const QPen& penLineNight, const QPen& penBorderDay, const QPen& penBorderNight) : type(type) , penLineDay(penLineDay) , penLineNight(penLineNight) , hasBorder(true) , penBorderDay(penBorderDay) , penBorderNight(penBorderNight) , hasPixmap(false) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(true) { } polyline_property(quint16 type, const QColor& color, int width, Qt::PenStyle style) : type(type) , penLineDay(QPen(color, width, style)) , penLineNight(penLineDay) , hasBorder(false) , penBorderDay(Qt::NoPen) , penBorderNight(Qt::NoPen) , hasPixmap(false) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(true) { } quint16 type; QPen penLineDay; QPen penLineNight; bool hasBorder; QPen penBorderDay; QPen penBorderNight; bool hasPixmap; QImage imgDay; QImage imgNight; QMap strings; label_type_e labelType; QColor colorLabelDay; QColor colorLabelNight; bool known; }; struct polygon_property { polygon_property() : type(0) , pen(Qt::magenta) , brushDay(Qt::magenta, Qt::BDiagPattern) , brushNight(Qt::magenta, Qt::BDiagPattern) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(false) { } polygon_property(quint16 type, const Qt::PenStyle pensty, const QColor& brushColor, Qt::BrushStyle pattern) : type(type) , pen(pensty) , brushDay(brushColor, pattern) , brushNight(brushColor.darker(150), pattern) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(true) { pen.setWidth(1); } polygon_property(quint16 type, const QColor& penColor, const QColor& brushColor, Qt::BrushStyle pattern) : type(type) , pen(penColor,1) , brushDay(brushColor, pattern) , brushNight(brushColor.darker(150), pattern) , labelType(eStandard) , colorLabelDay(Qt::black) , colorLabelNight(Qt::black) , known(true) { } quint16 type; QPen pen; QBrush brushDay; QBrush brushNight; QMap strings; label_type_e labelType; QColor colorLabelDay; QColor colorLabelNight; bool known; }; struct point_property { point_property() : labelType(eStandard) { } QImage imgDay; QImage imgNight; QMap strings; label_type_e labelType; QColor colorLabelDay; QColor colorLabelNight; }; /// decode typ file /** This pure virtual function has to be implemented in every subclass. It should be the only public function needed. The typ file is read and it's content is stored in the passed map/list objects. @param in input data stream @param polygons reference to polygon properties map @param polylines reference to polyline properties map @param drawOrder reference to list of polygon draw orders @param points reference to point properties map */ bool decode(const QByteArray& array, QMap& polygons, QMap& polylines, QList& drawOrder, QMap& points); QSet getLanguages() { return languages; } quint16 getFid() { return fid; } quint16 getPid() { return pid; } protected: virtual bool parseHeader(QDataStream& in); virtual bool parseDrawOrder(QDataStream& in, QList& drawOrder); virtual bool parsePolygon(QDataStream& in, QMap& polygons); virtual bool parsePolyline(QDataStream& in, QMap& polylines); virtual bool parsePoint(QDataStream& in, QMap& points); QTextCodec * getCodec(quint16 codepage); void decodeBitmap(QDataStream &in, QImage &img, int w, int h, int bpp); bool decodeBppAndBytes(int ncolors, int w, int flags, int& bpp, int& bytes); bool decodeColorTable(QDataStream& in, QImage& img, int ncolors, int maxcolor, bool hasAlpha); struct typ_section_t { typ_section_t() : dataOffset(0), dataLength(0), arrayOffset(0), arrayModulo(0), arraySize(0) { } quint32 dataOffset; quint32 dataLength; quint32 arrayOffset; quint16 arrayModulo; quint32 arraySize; }; quint16 version = 0; quint16 codepage = 0; quint16 year = 0; quint8 month = 0; quint8 day = 0; quint8 hour = 0; quint8 minutes = 0; quint8 seconds = 0; quint16 fid = 0; quint16 pid = 0; typ_section_t sectPoints; typ_section_t sectPolylines; typ_section_t sectPolygons; typ_section_t sectOrder; QSet languages; }; #endif //CGARMINTYP_H qmapshack-1.10.0/src/map/garmin/CGarminStrTblUtf8.h000644 001750 000144 00000002403 13216234143 023134 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGARMINSTRTBLUTF8_H #define CGARMINSTRTBLUTF8_H #include "IGarminStrTbl.h" class CGarminStrTblUtf8 : public IGarminStrTbl { public: CGarminStrTblUtf8(const quint16 codepage, const quint8 mask, QObject * parent); virtual ~CGarminStrTblUtf8(); void get(CFileExt& file, quint32 offset, type_e t, QStringList& info) override; }; #endif //CGARMINSTRTBLUTF8_H qmapshack-1.10.0/src/map/garmin/CGarminPolygon.h000644 001750 000144 00000007531 13216234143 022611 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2006, 2007 Oliver Eichler oliver.eichler@gmx.de 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 . Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries. This source is based on John Mechalas documentation "Garmin IMG File Format" found at sourceforge. The missing bits and error were rectified by the source code of Konstantin Galichsky (kg@geopainting.com), http://www.geopainting.com **********************************************************************************************/ #ifndef CGARMINPOLYGON_H #define CGARMINPOLYGON_H #include #ifdef __MINGW32__ #undef LP #endif #include #include struct subdiv_desc_t; struct sign_info_t; class CGarminPolygon { public: CGarminPolygon() = default; virtual ~CGarminPolygon() = default; quint32 decode(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, bool line, const quint8 * pData, const quint8 * pEnd); quint32 decode2(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, bool line, const quint8 * pData, const quint8 * pEnd); QString getLabelText() const; bool hasLabel() const { return !labels.isEmpty(); } quint32 type = 0; /// direction of line (polyline, only) bool direction = false; /// the label offset quint32 lbl_info = 0; /// true if label offset has to be used in NET section bool lbl_in_NET = false; /// bool hasV2Label = false; /// delta longitude from subdivision center qint16 dLng = 0; /// delta latitude from subdivision center qint16 dLat = 0; /** @brief the actual polyline points as [pixel] @note After decode() or decode2() the content will be the same as coords. It is up to the render object to convert it into pixel coordinates */ QPolygonF pixel; /// the actual polyline points as longitude / latitude [rad] QPolygonF coords; quint32 id = 0; QStringList labels; static quint32 cnt; static qint32 maxVecSize; private: void bits_per_coord(quint8 base, quint8 bfirst, quint32& bx, quint32& by, sign_info_t& signinfo, bool isVer2); int bits_per_coord(quint8 base, bool is_signed); }; class CShiftReg { public: CShiftReg(const quint8* pData, quint32 n, quint32 bx, quint32 by, bool extra_bit, sign_info_t& si); bool get(qint32& x, qint32& y); private: void fill(quint32 bits); /// the register to work on quint64 reg; /// the data stream to get data from const quint8 * pData; quint32 bytes; //< bytes left in stream quint32 xmask; //< bitmask x coord. quint32 ymask; //< bitmask y coord. qint32 xsign; //< sign bit for x value qint32 ysign; //< sign bit for y value qint32 xsign2; //< sign bit * 2 for x value qint32 ysign2; //< sign bit * 2 for y value quint8 bits; //< total bits in register quint8 bits_per_x; //< bits per x coord. quint8 bits_per_y; //< bits per y coord. quint8 bits_per_coord; //< bits per coord. sign_info_t& sinfo; bool extraBit; }; #endif //CGARMINPOLYGON_H qmapshack-1.10.0/src/map/garmin/IGarminStrTbl.h000644 001750 000144 00000004546 13216234143 022405 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IGARMINSTRTBL_H #define IGARMINSTRTBL_H #include class CFileExt; class QByteArray; class QStringList; class IGarminStrTbl : public QObject { public: IGarminStrTbl(const quint16 codepage, const quint8 mask, QObject * parent); virtual ~IGarminStrTbl(); enum type_e {norm,poi,net}; void registerLBL1(const quint32 offset, const quint32 size, const quint8 shift) { offsetLBL1 = offset; sizeLBL1 = size; addrshift1 = shift; } void registerLBL6(const quint32 offset, const quint32 size) { offsetLBL6 = offset; sizeLBL6 = size; } void registerNET1(const quint32 offset, const quint32 size, const quint8 shift) { offsetNET1 = offset; sizeNET1 = size; addrshift2 = shift; } virtual void get(CFileExt& file, quint32 offset, type_e t, QStringList& info) = 0; protected: void readFile(CFileExt &file, quint32 offset, quint32 size, QByteArray& data); quint32 calcOffset(CFileExt& file, const quint32 offset, type_e t); quint32 offsetLBL1 = 0; quint32 sizeLBL1 = 0; quint32 offsetLBL6 = 0; quint32 sizeLBL6 = 0; quint32 offsetNET1 = 0; quint32 sizeNET1 = 0; quint8 addrshift1 = 0; quint8 addrshift2 = 0; // conversion of strings quint16 codepage; QTextCodec * codec = nullptr; const quint8 mask; quint32 mask32; quint64 mask64; char buffer[1025]; }; #endif //IGARMINSTRTBL_H qmapshack-1.10.0/src/map/garmin/CGarminStrTbl6.cpp000644 001750 000144 00000010213 13216234140 023001 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 "CGarminStrTbl6.h" #include const char CGarminStrTbl6::str6tbl1[] = { ' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ,0,0,0,0,0 ,'0','1','2','3','4','5','6','7','8','9' ,0,0,0,0,0,0 }; const char CGarminStrTbl6::str6tbl2[] = { //@ ! " # $ % & ' ( ) * + , - . / '@','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/' ,0,0,0,0,0,0,0,0,0,0 //: ; < = > ? ,':',';','<','=','>','?' ,0,0,0,0,0,0,0,0,0,0,0 //[ \ ] ^ _ ,'[','\\',']','^','_' }; const char CGarminStrTbl6::str6tbl3[] = { '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' }; CGarminStrTbl6::CGarminStrTbl6(const quint16 codepage, const quint8 mask, QObject * parent) : IGarminStrTbl(codepage, mask, parent) { } CGarminStrTbl6::~CGarminStrTbl6() { } void CGarminStrTbl6::fill() { quint32 tmp; if(bits < 6) { tmp = *p++; reg |= tmp << (24 - bits); bits += 8; } } void CGarminStrTbl6::get(CFileExt& file, quint32 offset, type_e t, QStringList& labels) { labels.clear(); offset = calcOffset(file, offset,t); if(offset == 0xFFFFFFFF) { return; } if(offset > (quint32)sizeLBL1) { // qWarning() << "Index into string table to large" << hex << offset << dataLBL.size() << hdrLbl->addr_shift << hdrNet->net1_addr_shift; return; } quint8 c1 = 0; quint8 c2 = 0; quint32 idx = 0; reg = 0; bits = 0; QByteArray data; quint32 size = (sizeLBL1 - offset) < 200 ? (sizeLBL1 - offset) : 200; readFile(file, offsetLBL1 + offset, size, data); p = (quint8*)data.data(); fill(); while(idx < (sizeof(buffer) - 1)) { c1 = reg >> 26; reg <<= 6; bits -= 6; fill(); //terminator if(c1 > 0x2F) { break; } c2 = str6tbl1[c1]; if(c2 == 0) { if(c1 == 0x1C) { c1 = reg >> 26; reg <<= 6; bits -= 6; fill(); buffer[idx++] = str6tbl2[c1]; } else if(c1 == 0x1B) { c1 = reg >> 26; reg <<= 6; bits -= 6; fill(); buffer[idx++] = str6tbl3[c1]; } else if(c1 > 0x1C && c1 < 0x20) { buffer[idx] = 0; if(strlen(buffer)) { if (codepage != 0) { labels << codec->toUnicode(buffer); } else { labels << buffer; } } idx = 0; buffer[0] = 0; } } else { buffer[idx++] = str6tbl1[c1]; } } buffer[idx] = 0; if(strlen(buffer)) { if (codepage != 0) { labels << codec->toUnicode(buffer); } else { labels << buffer; } } } qmapshack-1.10.0/src/map/garmin/Garmin.h000644 001750 000144 00000002450 13216234143 021131 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef GARMIN_H #define GARMIN_H #include #ifdef __MINGW32__ #undef LP #endif #define GARMIN_DEG(x) ((x) < 0x800000 ? (qreal)(x) * 360.0 / 16777216.0 : (qreal)((x) - 0x1000000) * 360.0 / 16777216.0) #define GARMIN_RAD(x) ((x) < 0x800000 ? (qreal)(x) * (2*M_PI) / 16777216.0 : (qreal)((x) - 0x1000000) * (2*M_PI) / 16777216.0) typedef quint8 quint24[3]; #endif //GARMIN_H qmapshack-1.10.0/src/map/garmin/CGarminStrTbl8.cpp000644 001750 000144 00000005164 13216234140 023014 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 "CGarminStrTbl8.h" #include CGarminStrTbl8::CGarminStrTbl8(const quint16 codepage, const quint8 mask, QObject * parent) : IGarminStrTbl(codepage, mask, parent) { } CGarminStrTbl8::~CGarminStrTbl8() { } void CGarminStrTbl8::get(CFileExt& file, quint32 offset, type_e t, QStringList& info) { info.clear(); offset = calcOffset(file, offset, t); if(offset == 0xFFFFFFFF) { return; } if(offset > (quint32)sizeLBL1) { //qWarning() << "Index into string table to large" << hex << offset << dataLBL.size() << hdrLbl->addr_shift << hdrNet->net1_addr_shift; return; } QByteArray data; quint32 size = (sizeLBL1 - offset) < 200 ? (sizeLBL1 - offset) : 200; readFile(file, offsetLBL1 + offset, size, data); char * lbl = data.data(); char * pBuffer = buffer; *pBuffer = 0; while(*lbl != 0) { if((unsigned)*lbl >= 0x1B && (unsigned)*lbl <= 0x1F) { *pBuffer = 0; if(strlen(buffer)) { if (codepage != 0) { info << codec->toUnicode(buffer); } else { info << buffer; } pBuffer = buffer; *pBuffer = 0; } ++lbl; continue; } else if((unsigned)*lbl < 0x07) { ++lbl; continue; } else { *pBuffer++ = *lbl++; } } *pBuffer = 0; if(strlen(buffer)) { if (codepage != 0) { info << codec->toUnicode(buffer); } else { info << buffer; } } } qmapshack-1.10.0/src/map/garmin/CGarminTyp.cpp000644 001750 000144 00000113457 13216234140 022273 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de 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 . NOTE: this code is based on the opensource typ file generator at http://ati.land.cz/gps/typdecomp/editor.cgi **********************************************************************************************/ #include "CMainWindow.h" #include "map/garmin/CGarminTyp.h" #include "units/IUnit.h" #include #include #include #include #undef DBG bool CGarminTyp::decode(const QByteArray& array, QMap& polygons, QMap& polylines, QList& drawOrder, QMap& points) { QDataStream in(array); in.setVersion(QDataStream::Qt_4_5); in.setByteOrder( QDataStream::LittleEndian); /* Read typ file descriptor */ quint16 descriptor; in >> descriptor; qDebug() << "descriptor" << hex << descriptor; if(!parseHeader(in)) { return false; } if(!parseDrawOrder(in, drawOrder)) { return false; } if(!parsePolygon(in, polygons)) { return false; } if(!parsePolyline(in, polylines)) { return false; } if(!parsePoint(in, points)) { return false; } return true; } QTextCodec * CGarminTyp::getCodec(quint16 codepage) { QTextCodec * codec = QTextCodec::codecForName(QString("CP%1").arg(codepage).toLatin1()); if(codepage == 65001) { codec = QTextCodec::codecForName("UTF-8"); } return codec; } bool CGarminTyp::parseHeader(QDataStream& in) { int i; QString garmintyp; quint8 byte; for(i = 0; i < 10; ++i) { in >> byte; garmintyp.append(byte); } garmintyp.append(0); if(garmintyp != "GARMIN TYP") { qDebug() << "CMapTDB::readTYP() not a known typ file"; return false; } /* reading typ creation date string */ in.device()->seek(0x0c); in >> version >> year >> month >> day >> hour >> minutes >> seconds >> codepage; month -= 1; /* Month are like Microsoft starting 0 ? */ year += 1900; /* Reading points / lines / polygons struct */ in >> sectPoints.dataOffset >> sectPoints.dataLength; in >> sectPolylines.dataOffset >> sectPolylines.dataLength; in >> sectPolygons.dataOffset >> sectPolygons.dataLength; in >> pid >> fid; /* Read Array datas */ in >> sectPoints.arrayOffset >> sectPoints.arrayModulo >> sectPoints.arraySize; in >> sectPolylines.arrayOffset >> sectPolylines.arrayModulo >> sectPolylines.arraySize; in >> sectPolygons.arrayOffset >> sectPolygons.arrayModulo >> sectPolygons.arraySize; in >> sectOrder.arrayOffset >> sectOrder.arrayModulo >> sectOrder.arraySize; #ifdef DBG qDebug() << "Version:" << version << "Codepage:" << codepage; qDebug() << "PID" << hex << pid << "FID" << hex << fid; qDebug() << "Points doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPoints.dataOffset << "\t" << sectPoints.dataLength << "\t" << sectPoints.arrayOffset << "\t" << sectPoints.arrayModulo << "\t" << sectPoints.arrayOffset; qDebug() << "Polylines doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPolylines.dataOffset << "\t" << sectPolylines.dataLength << "\t" << sectPolylines.arrayOffset << "\t" << sectPolylines.arrayModulo << "\t" << sectPolylines.arrayOffset; qDebug() << "Polygons doff/dlen/aoff/amod/asize:" << hex << "\t" << sectPolygons.dataOffset << "\t" << sectPolygons.dataLength << "\t" << sectPolygons.arrayOffset << "\t" << sectPolygons.arrayModulo << "\t" << sectPolygons.arrayOffset; qDebug() << "Order doff/dlen/aoff/amod/asize:" << hex << "\t" << sectOrder.dataOffset << "\t" << sectOrder.dataLength << "\t" << sectOrder.arrayOffset << "\t" << sectOrder.arrayModulo << "\t" << sectOrder.arrayOffset; #endif return true; } bool CGarminTyp::parseDrawOrder(QDataStream& in, QList& drawOrder) { if(sectOrder.arrayModulo != 5) { return false; } if((sectOrder.arraySize % sectOrder.arrayModulo) != 0) { return true; } in.device()->seek(sectOrder.arrayOffset); int i,n; quint8 typ; quint32 subtyp; int count=1; const int N = sectOrder.arraySize / sectOrder.arrayModulo; for (i = 0; i < N; i++) { in >> typ >> subtyp; // qDebug() << hex << typ << subtyp; if (typ == 0) { count++; } else if(subtyp == 0) { #ifdef DBG qDebug() << QString("Type 0x%1 is priority %2").arg(typ,0,16).arg(count); #endif int idx = drawOrder.indexOf(typ); if(idx != NOIDX) { drawOrder.move(idx,0); } } else { quint32 exttyp = 0x010000 | (typ << 8); quint32 mask = 0x1; for(n=0; n < 0x20; ++n) { if(subtyp & mask) { drawOrder.push_front(exttyp|n); #ifdef DBG qDebug() << QString("Type 0x%1 is priority %2").arg(exttyp|n,0,16).arg(count); #endif } mask = mask << 1; } } } #ifdef DBG for(unsigned i = 0; i < drawOrder.size(); ++i) { if(i && i%16 == 0) { printf(" \n"); } printf("%06X ", drawOrder[i]); } printf(" \n"); #endif return true; } bool CGarminTyp::parsePolygon(QDataStream& in, QMap& polygons) { bool tainted = false; if(!sectPolygons.arrayModulo || ((sectPolygons.arraySize % sectPolygons.arrayModulo) != 0)) { return true; } QTextCodec * codec = getCodec(codepage); const int N = sectPolygons.arraySize / sectPolygons.arrayModulo; for (int element = 0; element < N; element++) { quint16 t16_1 = 0, t16_2, subtyp; quint8 t8; quint32 typ, offset=0; bool hasLocalization = false; bool hasTextColor = false; quint8 ctyp; QImage xpmDay(32,32, QImage::Format_Indexed8); QImage xpmNight(32,32, QImage::Format_Indexed8); quint8 r,g,b; quint8 langcode; in.device()->seek( sectPolygons.arrayOffset + (sectPolygons.arrayModulo * element ) ); if (sectPolygons.arrayModulo == 5) { in >> t16_1 >> t16_2 >> t8; offset = t16_2|(t8<<16); } else if (sectPolygons.arrayModulo == 4) { in >> t16_1 >> t16_2; offset = t16_2; } else if (sectPolygons.arrayModulo == 3) { in >> t16_1 >> t8; offset = t8; } t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11); typ = t16_2 & 0x7F; subtyp = t16_1 & 0x1F; if(t16_1 & 0x2000) { typ = 0x10000|(typ << 8)|subtyp; } in.device()->seek(sectPolygons.dataOffset + offset); in >> t8; hasLocalization = t8 & 0x10; hasTextColor = t8 & 0x20; ctyp = t8 & 0x0F; #ifdef DBG qDebug() << "Polygon typ:" << hex << typ << "ctype:" << ctyp << "offset:" << (sectPolygons.dataOffset + offset) << "orig data:" << t16_1; #endif polygon_property& property = polygons[typ]; switch(ctyp) { case 0x01: { // day & night single color in >> b >> g >> r; property.brushDay = QBrush(qRgb(r,g,b)); in >> b >> g >> r; property.brushNight = QBrush(qRgb(r,g,b)); // night and day color for line? in >> b >> g >> r; property.pen = QPen(QBrush(qRgb(r,g,b)),2); in >> b >> g >> r; property.known = true; break; } case 0x06: { // day & night single color in >> b >> g >> r; property.brushDay = QBrush(qRgb(r,g,b)); property.brushNight = QBrush(qRgb(r,g,b)); property.pen = Qt::NoPen; property.known = true; break; } case 0x07: { // day single color & night single color in >> b >> g >> r; property.brushDay = QBrush(qRgb(r,g,b)); in >> b >> g >> r; property.brushNight = QBrush(qRgb(r,g,b)); property.pen = Qt::NoPen; property.known = true; break; } case 0x08: { // day & night two color xpmDay.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpmDay.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpmDay, 32, 32, 1); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmDay); property.pen = Qt::NoPen; property.known = true; break; } case 0x09: { //day two color & night two color xpmDay.setColorCount(2); xpmNight.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpmDay.setColor(0, qRgb(r,g,b) ); in >> b >> g >> r; xpmNight.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpmNight.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpmDay, 32, 32, 1); memcpy(xpmNight.bits(), xpmDay.bits(), (32*32)); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmNight); property.pen = Qt::NoPen; property.known = true; break; } case 0x0B: { // day one color, transparent & night two color xpmDay.setColorCount(2); xpmNight.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); xpmDay.setColor(0, qRgba(255,255,255,0) ); in >> b >> g >> r; xpmNight.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpmNight.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpmDay, 32, 32, 1); memcpy(xpmNight.bits(), xpmDay.bits(), (32*32)); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmNight); property.pen = Qt::NoPen; property.known = true; break; } case 0x0D: { // day two color & night one color, transparent xpmDay.setColorCount(2); xpmNight.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpmDay.setColor(0, qRgb(r,g,b) ); in >> b >> g >> r; xpmNight.setColor(1, qRgb(r,g,b) ); xpmNight.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpmDay, 32, 32, 1); memcpy(xpmNight.bits(), xpmDay.bits(), (32*32)); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmNight); property.pen = Qt::NoPen; property.known = true; break; } case 0x0E: { // day & night one color, transparent xpmDay.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); xpmDay.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpmDay, 32, 32, 1); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmDay); property.pen = Qt::NoPen; property.known = true; break; } case 0x0F: { // day one color, transparent & night one color, transparent xpmDay.setColorCount(2); xpmNight.setColorCount(2); in >> b >> g >> r; xpmDay.setColor(1, qRgb(r,g,b) ); xpmDay.setColor(0, qRgba(255,255,255,0) ); in >> b >> g >> r; xpmNight.setColor(1, qRgb(r,g,b) ); xpmNight.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpmDay, 32, 32, 1); memcpy(xpmNight.bits(), xpmDay.bits(), (32*32)); property.brushDay.setTextureImage(xpmDay); property.brushNight.setTextureImage(xpmNight); property.pen = Qt::NoPen; property.known = true; break; } default: if(!tainted) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Warning..."), tr("This is a typ file with unknown polygon encoding. Please report!"), QMessageBox::Abort, QMessageBox::Abort); tainted = true; } qDebug() << "Failed polygon:" << typ << subtyp << hex << typ << subtyp << ctyp; } if(hasLocalization) { qint16 len; quint8 n = 1; in >> t8; len = t8; if(!(t8 & 0x01)) { n = 2; in >> t8; len |= t8 << 8; } len -= n; while(len > 0) { QByteArray str; in >> langcode; languages << langcode; len -= 2*n; while(len > 0) { in >> t8; len -= 2*n; if(t8 == 0) { break; } str += t8; } property.strings[langcode] = codec->toUnicode(str); #ifdef DBG qDebug() << len << langcode << property.strings[langcode]; #endif } } if(hasTextColor) { in >> t8; property.labelType = (label_type_e)(t8 & 0x07); if(t8 & 0x08) { in >> r >> g >> b; property.colorLabelDay = qRgb(r,g,b); } if(t8 & 0x10) { in >> r >> g >> b; property.colorLabelNight = qRgb(r,g,b); } #ifdef DBG qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight; #endif } } return true; } bool CGarminTyp::parsePolyline(QDataStream& in, QMap& polylines) { bool tainted = false; if(!sectPolylines.arrayModulo || ((sectPolylines.arraySize % sectPolylines.arrayModulo) != 0)) { return true; } QTextCodec * codec = getCodec(codepage); const int N = sectPolylines.arraySize / sectPolylines.arrayModulo; for (int element = 0; element < N; element++) { quint16 t16_1 = 0, t16_2, subtyp; quint8 t8_1, t8_2; quint32 typ, offset=0; bool hasLocalization = false; bool hasTextColor = false; //bool renderMode = false; quint8 ctyp, rows; quint8 r,g,b; quint8 langcode; in.device()->seek( sectPolylines.arrayOffset + (sectPolylines.arrayModulo * element ) ); if (sectPolylines.arrayModulo == 5) { in >> t16_1 >> t16_2 >> t8_1; offset = t16_2|(t8_1<<16); } else if (sectPolylines.arrayModulo == 4) { in >> t16_1 >> t16_2; offset = t16_2; } else if (sectPolylines.arrayModulo == 3) { in >> t16_1 >> t8_1; offset = t8_1; } t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11); typ = t16_2 & 0x7F; subtyp = t16_1 & 0x1F; if(t16_1 & 0x2000) { typ = 0x10000|(typ << 8)|subtyp; } in.device()->seek(sectPolylines.dataOffset + offset); in >> t8_1 >> t8_2; ctyp = t8_1 & 0x07; rows = t8_1 >> 3; hasLocalization = t8_2 & 0x01; //renderMode = t8_2 & 0x02; hasTextColor = t8_2 & 0x04; #ifdef DBG qDebug() << "Polyline typ:" << hex << typ << "ctyp:" << ctyp << "offset:" << (sectPolylines.dataOffset + offset) << "orig data:" << t16_1; #endif polyline_property& property = polylines[typ]; #ifdef DBG qDebug() << "rows" << rows << "t8_2" << hex << t8_2; #endif switch(ctyp) { case 0x00: { if(rows) { QImage xpm(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpm.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpm, 32, rows, 1); property.imgDay = xpm; property.imgNight = xpm; property.hasPixmap = true; property.known = true; } else { quint8 w1, w2; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penBorderDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> w1 >> w2; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.penBorderDay.setWidth(w2); property.penBorderNight.setWidth(w2); property.hasBorder = w2 > w1; property.hasPixmap = false; property.known = true; } break; } case 0x01: { if(rows) { QImage xpm1(32, rows, QImage::Format_Indexed8 ); QImage xpm2(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm1.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpm1.setColor(0, qRgb(r,g,b) ); in >> b >> g >> r; xpm2.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpm2.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpm1, 32, rows, 1); memcpy(xpm2.bits(), xpm1.bits(), (32*rows)); property.imgDay = xpm1; property.imgNight = xpm2; property.hasPixmap = true; property.known = true; } else { quint8 w1, w2; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penBorderDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penBorderNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> w1 >> w2; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.penBorderDay.setWidth(w2); property.penBorderNight.setWidth(w2); property.hasBorder = w2 > w1; property.hasPixmap = false; property.known = true; } break; } case 0x03: { if(rows) { QImage xpm1(32, rows, QImage::Format_Indexed8 ); QImage xpm2(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm1.setColor(1, qRgb(r,g,b) ); xpm1.setColor(0, qRgba(255,255,255,0) ); in >> b >> g >> r; xpm2.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpm2.setColor(0, qRgb(r,g,b) ); decodeBitmap(in, xpm1, 32, rows, 1); memcpy(xpm2.bits(), xpm1.bits(), (32*rows)); property.imgDay = xpm1; property.imgNight = xpm2; property.hasPixmap = true; property.known = true; } else { quint8 w1, w2; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderDay = QPen(Qt::NoPen); in >> b >> g >> r; property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penBorderNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> w1 >> w2; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.penBorderDay.setWidth(w2); property.penBorderNight.setWidth(w2); property.hasBorder = w2 > w1; property.hasPixmap = false; property.known = true; } break; } case 0x05: { if(rows) { QImage xpm1(32, rows, QImage::Format_Indexed8 ); QImage xpm2(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm1.setColor(1, qRgb(r,g,b) ); in >> b >> g >> r; xpm1.setColor(0, qRgb(r,g,b) ); in >> b >> g >> r; xpm2.setColor(1, qRgb(r,g,b) ); xpm2.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpm1, 32, rows, 1); memcpy(xpm2.bits(), xpm1.bits(), (32*rows)); property.imgDay = xpm1; property.imgNight = xpm2; property.hasPixmap = true; property.known = true; } else { quint8 w1; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penBorderDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); in >> b >> g >> r; property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderNight = QPen(Qt::NoPen); in >> w1; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.hasBorder = false; property.hasPixmap = false; property.known = true; } break; } case 0x06: { if(rows) { QImage xpm(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm.setColor(1, qRgb(r,g,b) ); xpm.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpm, 32, rows, 1); property.imgDay = xpm; property.imgNight = xpm; property.hasPixmap = true; property.known = true; } else { quint8 w1; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderDay = QPen(Qt::NoPen); property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderNight = QPen(Qt::NoPen); in >> w1; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.hasBorder = false; property.hasPixmap = false; property.known = true; } break; } case 0x07: { if(rows) { QImage xpm1(32, rows, QImage::Format_Indexed8 ); QImage xpm2(32, rows, QImage::Format_Indexed8 ); in >> b >> g >> r; xpm1.setColor(1, qRgb(r,g,b) ); xpm1.setColor(0, qRgba(255,255,255,0) ); in >> b >> g >> r; xpm2.setColor(1, qRgb(r,g,b) ); xpm2.setColor(0, qRgba(255,255,255,0) ); decodeBitmap(in, xpm1, 32, rows, 1); memcpy(xpm2.bits(), xpm1.bits(), (32*rows)); property.imgDay = xpm1; property.imgNight = xpm2; property.hasPixmap = true; property.known = true; } else { quint8 w1; in >> b >> g >> r; property.penLineDay = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderDay = QPen(Qt::NoPen); in >> b >> g >> r; property.penLineNight = QPen(QBrush(qRgb(r,g,b)), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); property.penBorderNight = QPen(Qt::NoPen); in >> w1; property.penLineDay.setWidth(w1); property.penLineNight.setWidth(w1); property.hasBorder = false; property.hasPixmap = false; property.known = true; } break; } default: if(!tainted) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Warning..."), tr("This is a typ file with unknown polyline encoding. Please report!"), QMessageBox::Abort, QMessageBox::Abort); tainted = true; } qDebug() << "Failed polyline" << hex << ":" << typ << ctyp << rows; continue; } property.imgDay = property.imgDay.convertToFormat(QImage::Format_ARGB32_Premultiplied); property.imgNight = property.imgNight.convertToFormat(QImage::Format_ARGB32_Premultiplied); if(hasLocalization) { qint16 len; quint8 n = 1; in >> t8_1; len = t8_1; if(!(t8_1 & 0x01)) { n = 2; in >> t8_1; len |= t8_1 << 8; } len -= n; while(len > 0) { QByteArray str; in >> langcode; languages << langcode; len -= 2*n; while(len > 0) { in >> t8_1; len -= 2*n; if(t8_1 == 0) { break; } str += t8_1; } property.strings[langcode] = codec->toUnicode(str); #ifdef DBG qDebug() << len << langcode << property.strings[langcode]; #endif } } if(hasTextColor) { in >> t8_1; property.labelType = (label_type_e)(t8_1 & 0x07); if(t8_1 & 0x08) { in >> r >> g >> b; property.colorLabelDay = qRgb(r,g,b); } if(t8_1 & 0x10) { in >> r >> g >> b; property.colorLabelNight = qRgb(r,g,b); } #ifdef DBG qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight; #endif } if(property.hasPixmap) { property.imgDay = property.imgDay.mirrored(false,true); property.imgNight = property.imgNight.mirrored(false,true); } } return true; } bool CGarminTyp::decodeBppAndBytes(int ncolors, int w, int flags, int& bpp, int& bytes) { switch(flags) { case 0x00: { if(ncolors < 3) { bpp = ncolors; } else if(ncolors == 3) { bpp = 2; } else if(ncolors < 16) { bpp = 4; } else if(ncolors < 256) { bpp = 8; } else { return false; } break; } case 0x10: { if(ncolors == 0) { bpp = 1; } else if(ncolors < 3) { bpp = 2; } else if(ncolors < 15) { bpp = 4; } else if(ncolors < 256) { bpp = 8; } else { return false; } break; } case 0x20: { if(ncolors == 0) { bpp = 16; } else if(ncolors < 3) { bpp = ncolors; } else if(ncolors < 4) { bpp = 2; } else if(ncolors < 16) { bpp = 4; } else if(ncolors < 256) { bpp = 8; } else { return false; } break; } default: return false; } bytes = (w * bpp) / 8; if( (w * bpp) & 0x07 ) { ++bytes; } return true; } bool CGarminTyp::decodeColorTable(QDataStream& in, QImage& img, int ncolors, int maxcolor, bool hasAlpha) { img.setColorCount(ncolors); if(hasAlpha) { int i; quint8 byte; quint32 bits = 0; quint32 reg = 0; quint32 mask = 0x000000FF; for (i = 0; i < ncolors; i++) { while(bits < 28) { in >> byte; mask = 0x000000FF << bits; reg = reg & (~mask); reg = reg | (byte << bits); bits += 8; } img.setColor(i, qRgba((reg >> 16) & 0x0FF, (reg >> 8) & 0x0FF, reg & 0x0FF, ~((reg >> 24) & 0x0F) << 4)); reg = reg >> 28; bits -= 28; } for(; i < maxcolor; ++i) { img.setColor(i,qRgba(0,0,0,0)); } } else { int i; quint8 r,g,b; for(i = 0; i < ncolors; ++i) { in >> b >> g >> r; img.setColor(i, qRgb(r,g,b)); } for(; i < maxcolor; ++i) { img.setColor(i,qRgba(0,0,0,0)); } } return true; } void CGarminTyp::decodeBitmap(QDataStream &in, QImage &img, int w, int h, int bpp) { int x = 0,j = 0; quint8 color; if(bpp == 0) { return; } for (int y = 0; y < h; y++) { while ( x < w ) { in >> color; for ( int i = 0; (i < (8 / bpp)) && (x < w); i++ ) { int value; if ( i > 0 ) { value = (color >>= bpp); } else { value = color; } if ( bpp == 4) { value = value & 0xf; } if ( bpp == 2) { value = value & 0x3; } if ( bpp == 1) { value = value & 0x1; } img.setPixel(x,y,value); // qDebug() << QString("value(%4) pixel at (%1,%2) is 0x%3 j is %5").arg(x).arg(y).arg(value,0,16).arg(color).arg(j); x += 1; } j += 1; } x = 0; } } bool CGarminTyp::parsePoint(QDataStream& in, QMap& points) { // bool tainted = false; if(!sectPoints.arrayModulo || ((sectPoints.arraySize % sectPoints.arrayModulo) != 0)) { return true; } QTextCodec * codec = getCodec(codepage); const int N = sectPoints.arraySize / sectPoints.arrayModulo; for (int element=0; element < N; element++) { quint16 t16_1 = 0, t16_2, subtyp; quint8 t8_1; quint32 typ, offset=0; bool hasLocalization = false; bool hasTextColor = false; quint8 langcode; quint8 r,g,b; in.device()->seek( sectPoints.arrayOffset + (sectPoints.arrayModulo * element ) ); if (sectPoints.arrayModulo == 5) { in >> t16_1 >> t16_2 >> t8_1; offset = t16_2|(t8_1<<16); } else if (sectPoints.arrayModulo == 4) { in >> t16_1 >> t16_2; offset = t16_2; } else if (sectPoints.arrayModulo == 3) { in >> t16_1 >> t8_1; offset = t8_1; } t16_2 = (t16_1 >> 5) | (( t16_1 & 0x1f) << 11); typ = t16_2 & 0x7FF; subtyp = t16_1 & 0x01F; if(t16_1 & 0x2000) { typ = 0x10000|(typ << 8)|subtyp; } else { typ = (typ << 8) + subtyp; } in.device()->seek( sectPoints.dataOffset + offset ); int bpp = 0, wbytes = 0; quint8 w, h, ncolors, ctyp; in >> t8_1 >> w >> h >> ncolors >> ctyp; hasLocalization = t8_1 & 0x04; hasTextColor = t8_1 & 0x08; t8_1 = t8_1 & 0x03; #ifdef DBG qDebug() << "Point typ:" << hex << typ << "ctyp:" << ctyp <<"offset:" << (sectPoints.dataOffset + offset) << "orig data:" << t16_1; #endif if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes)) { continue; } #ifdef DBG qDebug() << " " << dec << "w" << w << "h" << h << "ncolors" << ncolors << "bpp" << bpp << "wbytes" << wbytes; #endif if(ctyp == 0x20 || ctyp == 0x00) { if((ncolors == 0) && (bpp >= 16)) { ncolors = w*h; } } point_property& property = points[typ]; QImage imgDay(w,h, QImage::Format_Indexed8 ); QImage imgNight(w,h, QImage::Format_Indexed8 ); if(!decodeColorTable(in, imgDay, ncolors, 1 << bpp, ctyp == 0x20)) { continue; } if(bpp >= 16) { continue; } else { decodeBitmap(in, imgDay, w, h, bpp); property.imgDay = imgDay; } if(t8_1 == 0x03) { in >> ncolors >> ctyp; if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes)) { continue; } if(!decodeColorTable(in, imgNight, ncolors, 1 << bpp, ctyp == 0x20)) { continue; } decodeBitmap(in, imgNight, w, h, bpp); points[typ].imgNight = imgNight; } else if(t8_1 == 0x02) { in >> ncolors >> ctyp; if(!decodeBppAndBytes(ncolors, w, ctyp, bpp, wbytes)) { continue; } if(!decodeColorTable(in, imgDay, ncolors, 1 << bpp, ctyp == 0x20)) { continue; } property.imgNight = imgDay; } else { property.imgNight = imgDay; } if(hasLocalization) { qint16 len; quint8 n = 1; in >> t8_1; len = t8_1; if(!(t8_1 & 0x01)) { n = 2; in >> t8_1; len |= t8_1 << 8; } len -= n; while(len > 0) { QByteArray str; in >> langcode; languages << langcode; len -= 2*n; while(len > 0) { in >> t8_1; len -= 2*n; if(t8_1 == 0) { break; } str += t8_1; } property.strings[langcode] = codec->toUnicode(str); #ifdef DBG qDebug() << len << langcode << property.strings[langcode]; #endif } } if(hasTextColor) { in >> t8_1; property.labelType = (label_type_e)(t8_1 & 0x07); if(t8_1 & 0x08) { in >> r >> g >> b; property.colorLabelDay = qRgb(r,g,b); } if(t8_1 & 0x10) { in >> r >> g >> b; property.colorLabelNight = qRgb(r,g,b); } #ifdef DBG qDebug() << "ext. label: type" << property.labelType << "day" << property.colorLabelDay << "night" << property.colorLabelNight; #endif } } return true; } qmapshack-1.10.0/src/map/garmin/CGarminPolygon.cpp000644 001750 000144 00000033052 13216234140 023136 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2006, 2007 Oliver Eichler oliver.eichler@gmx.de 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 . Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries. This source is based on John Mechalas documentation "Garmin IMG File Format" found at sourceforge. The missing bits and error were rectified by the source code of Konstantin Galichsky (kg@geopainting.com), http://www.geopainting.com **********************************************************************************************/ #include "CGarminPolygon.h" #include "Garmin.h" #include "helpers/Platform.h" #include "units/IUnit.h" #include #undef DEBUG_SHOW_POLY_DATA #undef DEBUG_SHOW_POLY2_DATA #undef DEBUG_SHOW_POLY_PTS struct sign_info_t { quint32 sign_info_bits = 2; bool x_has_sign = true; bool nx = false; bool y_has_sign = true; bool ny = false; }; quint32 CGarminPolygon::cnt = 0; qint32 CGarminPolygon::maxVecSize = 0; quint32 CGarminPolygon::decode(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, bool line, const quint8 * pData, const quint8 * pEnd) { quint32 bytes_total = 10; // bitstream has a two byte length bool two_byte_len; // coordinates use extra bit - ??? have never seen it bool extra_bit; // bitstream length quint16 bs_len = 0; // base bit size info for coordinates quint8 bs_info; // bits per x coord. quint32 bx; // bits per y coord. quint32 by; const quint8 * const pStart = pData; labels.clear(); coords.resize(0); coords.reserve(maxVecSize); /* poly_type for polylines: bit 0..5 type bit 6 direction for polygons: bit 0..6 type bit 7 bitstream_len is two bytes (true) */ type = *pData++; two_byte_len = type & 0x80; if(line) { direction = (type & 0x40); type &= 0x3F; } else { type &= 0x7F; } /* label info bit 0..21 off set into LBL section bit 22 use extra bit for coordinates bit 23 use label data of NET section */ lbl_info = gar_ptr_load(uint24_t, pData); lbl_in_NET = lbl_info & 0x800000; extra_bit = lbl_info & 0x400000; lbl_info = lbl_info & 0x3FFFFF; pData += 3; // qDebug() << hex << lbl_in_NET << extra_bit << lbl_info; // delta longitude and latitude dLng = gar_ptr_load(uint16_t, pData); pData += 2; dLat = gar_ptr_load(uint16_t, pData); pData += 2; // bitstream length if(two_byte_len) { bs_len = gar_ptr_load(uint16_t, pData); pData += 2; bytes_total += bs_len + 1; } else { #if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) (quint8&)bs_len = *pData++; #else bs_len = *pData++; #endif bytes_total += bs_len; } if(pEnd && ((pStart + bytes_total) > pEnd)) { return bytes_total; } /* bitstream info bit 0..3 base bits longitude bit 4..7 base bits latitude */ bs_info = *pData++; //if(extra_bit) qWarning("extrabit"); #ifdef DEBUG_SHOW_POLY_DATA qDebug() << "type: " << type << hex << tmpType; qDebug() << "two byte: " << two_byte_len; qDebug() << "extra bit: " << extra_bit; qDebug() << "dLng: " << dLng; qDebug() << "dLat: " << dLat; qDebug() << "len: " << bs_len; qDebug() << "info: " << hex << bs_info; qDebug() << "1st byte: " << hex << *pData; qDebug() << "bytes total" << bytes_total; #endif // DEBUG_SHOW_POLY_DATA sign_info_t signinfo; bits_per_coord(bs_info,*pData,bx,by,signinfo, false); CShiftReg sr(pData,bs_len,bx,by,extra_bit,signinfo); qint32 x1,y1,x = 0,y = 0; bool isNegative = (iCenterLon >= 0x800000); // first point x1 = ((qint32)dLng << shift) + iCenterLon; y1 = ((qint32)dLat << shift) + iCenterLat; if(x1 >= 0x800000 && !isNegative) { x1 = 0x7fffff; } coords << QPointF(GARMIN_RAD(x1), GARMIN_RAD(y1)); // next points while(sr.get(x,y)) { x1 += (x << shift); y1 += (y << shift); if(x1 >= 0x800000 && !isNegative) { x1 = 0x7fffff; } coords << QPointF(GARMIN_RAD(x1), GARMIN_RAD(y1)); } id = cnt++; // qDebug() << "<<<" << id; if(maxVecSize < coords.size()) { maxVecSize = coords.size(); } if(coords.size() * 1.2 < maxVecSize) { coords.squeeze(); } pixel = coords; return bytes_total; } quint32 CGarminPolygon::decode2(qint32 iCenterLon, qint32 iCenterLat, quint32 shift, bool line, const quint8 * pData, const quint8 * pEnd) { quint32 bytes_total = 6; // bitstream length quint16 bs_len = 0; // type and subtype quint32 subtype; // base bit size info for coordinates quint8 bs_info; // bits per x coord. quint32 bx; // bits per y coord. quint32 by; const quint8 * const pStart = pData; labels.clear(); coords.resize(0); coords.reserve(maxVecSize); type = *pData++; subtype = *pData++; type = 0x10000 + (quint16(type) << 8) + (subtype & 0x1f); hasV2Label = subtype & 0x20; // delta longitude and latitude dLng = gar_ptr_load(uint16_t, pData); pData += 2; dLat = gar_ptr_load(uint16_t, pData); pData += 2; if((*pData & 0x1) == 0) { bs_len = gar_ptr_load(uint16_t, pData); bs_len = (bs_len >> 2) - 1; pData += 2; bytes_total += 2; } else { bs_len = ((*pData) >> 1) - 1; pData += 1; bytes_total += 1; } bs_info = *pData++; bytes_total += bs_len + 1; #ifdef DEBUG_SHOW_POLY2_DATA qDebug() << "type: " << type << hex << type; qDebug() << "dLng: " << dLng; qDebug() << "dLat: " << dLat; qDebug() << "len: " << bs_len; qDebug() << "info: " << hex << bs_info; qDebug() << "1st byte: " << hex << *pData; qDebug() << "bytes total" << bytes_total; #endif // DEBUG_SHOW_POLY_DATA sign_info_t signinfo; bits_per_coord(bs_info,*pData,bx,by,signinfo, true); // qDebug() << ">>" << bs_len << bytes_total << (pEnd - pStart); // assert((pEnd - pStart) >= bytes_total); if(((quint32)(pEnd - pStart)) < bytes_total) { return pEnd - pStart; } CShiftReg sr(pData,bs_len,bx,by,false,signinfo); qint32 x1,y1,x = 0,y = 0; bool isNegative = (iCenterLon >= 0x800000); // first point x1 = ((qint32)dLng << shift) + iCenterLon; y1 = ((qint32)dLat << shift) + iCenterLat; if(x1 >= 0x800000 && !isNegative) { x1 = 0x7fffff; } coords << QPointF(GARMIN_RAD(x1), GARMIN_RAD(y1)); // next points while(sr.get(x,y)) { x1 += (x << shift); y1 += (y << shift); if(x1 >= 0x800000 && !isNegative) { x1 = 0x7fffff; } // xy.u = GARMIN_RAD(x1); // xy.v = GARMIN_RAD(y1); // if(qAbs(xy.v) > 2*M_PI || qAbs(xy.u) > 2*M_PI) // { // qDebug() << "bam"; // qDebug() << xy.u << xy.v << pStart << pEnd << (pEnd - pStart) << (cnt + 1) << line; // //assert(0); // } //#ifdef DEBUG_SHOW_POLY_PTS // qDebug() << xy.u << xy.v << (RAD_TO_DEG * xy.u) << (RAD_TO_DEG * xy.v); //#endif coords << QPointF(GARMIN_RAD(x1), GARMIN_RAD(y1)); } if(hasV2Label) { quint32 offset = gar_ptr_load(uint24_t, pData + bs_len); bytes_total += 3; lbl_info = offset & 0x3FFFFF; } else { lbl_info = 0; } id = cnt++; // qDebug() << "<<<" << id; if(maxVecSize < coords.size()) { maxVecSize = coords.size(); } if(coords.size() * 1.2 < maxVecSize) { coords.squeeze(); } pixel = coords; return bytes_total; } void CGarminPolygon::bits_per_coord(quint8 base, quint8 bfirst, quint32& bx, quint32& by, sign_info_t& signinfo, bool isVer2) { bool x_sign_same, y_sign_same; quint8 mask = 0x1; // x_sign_same = bfirst & 0x1; x_sign_same = bfirst & mask; mask <<= 1; if(x_sign_same) { signinfo.x_has_sign = false; // signinfo.nx = bfirst & 0x2; signinfo.nx = bfirst & mask; mask <<= 1; ++signinfo.sign_info_bits; } else { signinfo.x_has_sign = true; } bx = bits_per_coord(base & 0x0F, signinfo.x_has_sign); // y_sign_same = x_sign_same ? (bfirst & 0x04) : (bfirst & 0x02); y_sign_same = bfirst & mask; mask <<= 1; if(y_sign_same) { signinfo.y_has_sign = false; // signinfo.ny = x_sign_same ? bfirst & 0x08 : bfirst & 0x04; signinfo.ny = bfirst & mask; mask <<= 1; ++signinfo.sign_info_bits; } else { signinfo.y_has_sign = true; } by = bits_per_coord((base>>4) & 0x0F, signinfo.y_has_sign); // Determine extra bits. if(isVer2) { ++signinfo.sign_info_bits; if(bfirst & mask) { // qDebug() << "V2"; ++bx; ++by; } } } QString CGarminPolygon::getLabelText() const { QString str; switch(type) { case 0x23: //< "Minor depth contour" case 0x20: //< "Minor land contour" case 0x24: //< "Intermediate depth contour" case 0x21: //< "Intermediate land contour" case 0x25: //< "Major depth contour" case 0x22: //< "Major land contour" { QString unit; QString val = labels[0]; IUnit::self().meter2elevation(val.toFloat() / 3.28084f, val, unit); str = QString("%1 %2").arg(val).arg(unit); } break; default: str = labels.join(" ").simplified(); } return str; } // extract bits per coordinate int CGarminPolygon::bits_per_coord(quint8 base, bool is_signed) { int n = 2; if ( base <= 9 ) { n+= base; } else { n+= (2*base-9); } if ( is_signed ) { ++n; } return n; } CShiftReg::CShiftReg(const quint8* pData, quint32 n, quint32 bx, quint32 by, bool extra_bit, sign_info_t& si) : reg(0) , pData(pData) , bytes(n) , xmask(0xFFFFFFFF) , ymask(0xFFFFFFFF) , xsign(1) , ysign(1) , xsign2(2) , ysign2(2) , bits(0) , bits_per_x(bx) , bits_per_y(by) , bits_per_coord(bx + by + (extra_bit ? 1 : 0)) , sinfo(si) , extraBit(extra_bit) { // create bit masks xmask = (xmask << (32-bx)) >> (32-bx); ymask = (ymask << (32-by)) >> (32-by); xsign <<= (bits_per_x - 1); ysign <<= (bits_per_y - 1); xsign2 = xsign<<1; ysign2 = ysign<<1; // add sufficient bytes for the first coord. pair fill(bits_per_coord + si.sign_info_bits); // get rid of sign setup bytes reg >>= si.sign_info_bits; bits -= si.sign_info_bits; } bool CShiftReg::get(qint32& x, qint32& y) { x = y = 0; if(bits < (bits_per_coord)) { return false; } // don't know what to do with it -> skip extra bit if(extraBit) { reg >>= 1; bits -= 1; } if(sinfo.x_has_sign) { qint32 tmp = 0; while(1) { tmp = reg & xmask; if(tmp != xsign) { break; } x += tmp - 1; reg >>= bits_per_x; bits -= bits_per_x; fill(bits_per_y + bits_per_x); } if(tmp < xsign) { x += tmp; } else { x = tmp - (xsign2) - x; } } else { x = reg & xmask; if(sinfo.nx) { x = -x; } } reg >>= bits_per_x; bits -= bits_per_x; // take y coord., add sign if necessary, shift register by bits per y coord. if(sinfo.y_has_sign) { qint32 tmp = 0; while(1) { tmp = reg & ymask; if(tmp != ysign) { break; } y += tmp - 1; reg >>= bits_per_y; bits -= bits_per_y; fill(bits_per_y); } if(tmp < ysign) { y += tmp; } else { y = tmp - (ysign2) - y; } } else { y = reg & ymask; if(sinfo.ny) { y = -y; } } reg >>= bits_per_y; bits -= bits_per_y; // fill register until it has enough bits for one coord. pair again fill(bits_per_coord); return true; } void CShiftReg::fill(quint32 b) { quint64 tmp = 0; while((bits < b) && bytes) { #if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) (quint8&)tmp = *pData++; #else tmp = *pData++; #endif --bytes; reg |= tmp << bits; bits += 8; } } qmapshack-1.10.0/src/map/garmin/CGarminStrTbl6.h000644 001750 000144 00000003056 13216234143 022460 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGARMINSTRTBL6_H #define CGARMINSTRTBL6_H #include "IGarminStrTbl.h" class CGarminStrTbl6 : public IGarminStrTbl { public: CGarminStrTbl6(const quint16 codepage, const quint8 mask, QObject * parent); virtual ~CGarminStrTbl6(); void get(CFileExt& file, quint32 offset, type_e t, QStringList& info) override; private: static const char str6tbl1[]; static const char str6tbl2[]; static const char str6tbl3[]; void fill(); /// temp shift reg buffer quint32 reg = 0; /// bits in buffer quint32 bits = 0; /// pointer to current data; const quint8 * p = nullptr; }; #endif //CGARMINSTRTBL6_H qmapshack-1.10.0/src/map/mapsforge/000755 001750 000144 00000000000 13216664445 020264 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/map/mapsforge/types.h000644 001750 000144 00000002714 13216234143 021571 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef TYPES_H #define TYPES_H #include struct uintX { uintX() : val(0) { } operator quint64() { return val; } quint64 val; }; struct intX { intX() : val(0) { } operator qint64() { return val; } qint64 val; }; struct utf8 { operator QString() { return val; } QString val; }; extern QDataStream& operator>>(QDataStream& s, uintX& v); extern QDataStream& operator>>(QDataStream& s, intX& v); extern QDataStream& operator>>(QDataStream& s, utf8& v); #endif //TYPES_H qmapshack-1.10.0/src/map/mapsforge/types.cpp000644 001750 000144 00000003340 13216234140 022115 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "types.h" QDataStream& operator>>(QDataStream& s, uintX& v) { quint8 tmp; int shift = 0; v.val = 0; s >> tmp; while(tmp & 0x80) { v.val |= (tmp & 0x7F)<> tmp; } v.val |= quint64(tmp) << shift; return s; } QDataStream& operator>>(QDataStream& s, intX& v) { quint8 tmp; int shift = 0; v.val = 0; s >> tmp; while(tmp & 0x80) { v.val |= (tmp & 0x7F)<> tmp; } if(tmp & 0x40) { v.val = -(v.val | ((tmp & 0x3f) << shift)); } else { v.val |= quint64(tmp) << shift; } return s; } QDataStream& operator>>(QDataStream& s, utf8& v) { uintX l; s >> l; v.val = QString::fromUtf8(s.device()->read(l)); return s; } qmapshack-1.10.0/src/map/CMapIMG.cpp000644 001750 000144 00000263425 13216234140 020157 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/Poi.h" #include "helpers/CDraw.h" #include "helpers/CFileExt.h" #include "helpers/CProgressDialog.h" #include "helpers/Platform.h" #include "map/CMapDraw.h" #include "map/CMapIMG.h" #include "map/garmin/CGarminStrTbl6.h" #include "map/garmin/CGarminStrTbl8.h" #include "map/garmin/CGarminStrTblUtf8.h" #include "map/garmin/CGarminTyp.h" #include "units/IUnit.h" #include #undef DEBUG_SHOW_SECT_DESC #undef DEBUG_SHOW_TRE_DATA #undef DEBUG_SHOW_SUBDIV_DATA #undef DEBUG_SHOW_MAPLEVELS #undef DEBUG_SHOW_SECTION_BORDERS #undef DEBUG_SHOW_SUBDIV_BORDERS #define STREETNAME_THRESHOLD 5.0 int CFileExt::cnt = 0; static inline bool isCompletlyOutside(const QPolygonF& poly, const QRectF &viewport) { qreal north = -90.0 * DEG_TO_RAD; qreal south = 90.0 * DEG_TO_RAD; qreal west = 180.0 * DEG_TO_RAD; qreal east = -180.0 * DEG_TO_RAD; for(const QPointF &pt : poly) { if(north < pt.y()) { north = pt.y(); } if(south > pt.y()) { south = pt.y(); } if(west > pt.x()) { west = pt.x(); } if(east < pt.x()) { east = pt.x(); } } QRectF ref(west, north, east - west, south - north); if(ref.width() == 0) { ref.setWidth(0.00001); } if(ref.height() == 0) { ref.setHeight(0.00001); } return !viewport.intersects(ref); } static inline QImage img2line(const QImage &img, int width) { Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied); QImage newImage(width, img.height(), QImage::Format_ARGB32_Premultiplied); const int bpl_src = img.bytesPerLine(); const int bpl_dst = newImage.bytesPerLine(); const uchar *_srcBits = img.bits(); uchar *_dstBits = newImage.bits(); for(int i = 0; i < img.height(); i++) { const uchar *srcBits = _srcBits + bpl_src * i; uchar *dstBits = _dstBits + bpl_dst * i; int bytesToCopy = bpl_dst; while(bytesToCopy > 0) { memcpy(dstBits, srcBits, qMin(bytesToCopy, bpl_src)); dstBits += bpl_src; bytesToCopy -= bpl_src; } } return newImage; } static inline bool isCluttered(QVector& rectPois, const QRectF& rect) { for(const QRectF &rectPoi : rectPois) { if(rect.intersects(rectPoi)) { return true; } } rectPois << rect; return false; } CMapIMG::CMapIMG(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility|eFeatVectorItems|eFeatTypFile,parent) , filename(filename) , fm(CMainWindow::self().getMapFont()) , selectedLanguage(NOIDX) { qDebug() << "------------------------------"; qDebug() << "IMG: try to open" << filename; try { readBasics(); processPrimaryMapData(); setupTyp(); } catch(const exce_t& e) { QMessageBox::critical(CMainWindow::getBestWidgetForParent(), tr("Failed ..."), e.msg, QMessageBox::Abort); return; } isActivated = true; } void CMapIMG::loadConfig(QSettings& cfg) { IMap::loadConfig(cfg); if(!typeFile.isEmpty()) { setupTyp(); } } void CMapIMG::slotSetTypeFile(const QString& filename) { IMap::slotSetTypeFile(filename); setupTyp(); CCanvas::triggerCompleteUpdate(CCanvas::eRedrawMap); } void CMapIMG::setupTyp() { languages.clear(); languages[0x00] = tr("Unspecified"); languages[0x01] = tr("French"); languages[0x02] = tr("German"); languages[0x03] = tr("Dutch"); languages[0x04] = tr("English"); languages[0x05] = tr("Italian"); languages[0x06] = tr("Finnish"); languages[0x07] = tr("Swedish"); languages[0x08] = tr("Spanish"); languages[0x09] = tr("Basque"); languages[0x0a] = tr("Catalan"); languages[0x0b] = tr("Galician"); languages[0x0c] = tr("Welsh"); languages[0x0d] = tr("Gaelic"); languages[0x0e] = tr("Danish"); languages[0x0f] = tr("Norwegian"); languages[0x10] = tr("Portuguese"); languages[0x11] = tr("Slovak"); languages[0x12] = tr("Czech"); languages[0x13] = tr("Croatian"); languages[0x14] = tr("Hungarian"); languages[0x15] = tr("Polish"); languages[0x16] = tr("Turkish"); languages[0x17] = tr("Greek"); languages[0x18] = tr("Slovenian"); languages[0x19] = tr("Russian"); languages[0x1a] = tr("Estonian"); languages[0x1b] = tr("Latvian"); languages[0x1c] = tr("Romanian"); languages[0x1d] = tr("Albanian"); languages[0x1e] = tr("Bosnian"); languages[0x1f] = tr("Lithuanian"); languages[0x20] = tr("Serbian"); languages[0x21] = tr("Macedonian"); languages[0x22] = tr("Bulgarian"); polylineProperties.clear(); polylineProperties[0x01] = CGarminTyp::polyline_property(0x01, Qt::blue, 6, Qt::SolidLine ); polylineProperties[0x01].penBorderDay = QPen(Qt::black, 8, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x01].penBorderNight = QPen(Qt::lightGray, 8, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x01].hasBorder = true; polylineProperties[0x02] = CGarminTyp::polyline_property(0x02, "#cc9900", 4, Qt::SolidLine ); polylineProperties[0x02].penBorderDay = QPen(Qt::black, 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x02].penBorderNight = QPen(Qt::lightGray, 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x02].hasBorder = true; polylineProperties[0x03] = CGarminTyp::polyline_property(0x03, Qt::yellow, 3, Qt::SolidLine ); polylineProperties[0x03].penBorderDay = QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x03].penBorderNight = QPen(Qt::lightGray, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x03].hasBorder = true; polylineProperties[0x04] = CGarminTyp::polyline_property(0x04, "#ffff00", 3, Qt::SolidLine ); polylineProperties[0x04].penBorderDay = QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x04].penBorderNight = QPen(Qt::lightGray, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x04].hasBorder = true; polylineProperties[0x05] = CGarminTyp::polyline_property(0x05, "#dc7c5a", 2, Qt::SolidLine ); polylineProperties[0x06] = CGarminTyp::polyline_property(0x06, Qt::gray, 2, Qt::SolidLine ); polylineProperties[0x06].penBorderDay = QPen(Qt::black, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x06].penBorderNight = QPen(QColor("#f0f0f0"), 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x06].hasBorder = true; polylineProperties[0x07] = CGarminTyp::polyline_property(0x07, "#c46442", 1, Qt::SolidLine ); polylineProperties[0x08] = CGarminTyp::polyline_property(0x08, "#e88866", 2, Qt::SolidLine ); polylineProperties[0x09] = CGarminTyp::polyline_property(0x09, "#e88866", 2, Qt::SolidLine ); polylineProperties[0x0A] = CGarminTyp::polyline_property(0x0A, "#808080", 2, Qt::SolidLine ); polylineProperties[0x0B] = CGarminTyp::polyline_property(0x0B, "#c46442", 2, Qt::SolidLine ); polylineProperties[0x0C] = CGarminTyp::polyline_property(0x0C, "#000000", 2, Qt::SolidLine ); polylineProperties[0x14] = CGarminTyp::polyline_property(0x14, Qt::white, 2, Qt::DotLine ); polylineProperties[0x14].penBorderDay = QPen(Qt::black, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x14].penBorderNight = QPen(Qt::lightGray, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); polylineProperties[0x14].hasBorder = true; polylineProperties[0x15] = CGarminTyp::polyline_property(0x15, "#000080", 2, Qt::SolidLine ); polylineProperties[0x16] = CGarminTyp::polyline_property(0x16, "#E0E0E0", 1, Qt::SolidLine ); polylineProperties[0x18] = CGarminTyp::polyline_property(0x18, "#0000ff", 2, Qt::SolidLine ); polylineProperties[0x19] = CGarminTyp::polyline_property(0x19, "#00ff00", 2, Qt::SolidLine ); polylineProperties[0x1A] = CGarminTyp::polyline_property(0x1A, "#000000", 2, Qt::SolidLine ); polylineProperties[0x1B] = CGarminTyp::polyline_property(0x1B, "#000000", 2, Qt::SolidLine ); polylineProperties[0x1C] = CGarminTyp::polyline_property(0x1C, "#00c864", 2, Qt::DotLine ); polylineProperties[0x1D] = CGarminTyp::polyline_property(0x1D, "#00c864", 2, Qt::DotLine ); polylineProperties[0x1E] = CGarminTyp::polyline_property(0x1E, "#00c864", 2, Qt::DotLine ); polylineProperties[0x1F] = CGarminTyp::polyline_property(0x1F, "#0000ff", 2, Qt::SolidLine ); polylineProperties[0x20] = CGarminTyp::polyline_property(0x20, "#b67824", 1, Qt::SolidLine ); polylineProperties[0x21] = CGarminTyp::polyline_property(0x21, "#b67824", 2, Qt::SolidLine ); polylineProperties[0x22] = CGarminTyp::polyline_property(0x22, "#b67824", 3, Qt::SolidLine ); polylineProperties[0x23] = CGarminTyp::polyline_property(0x23, "#b67824", 1, Qt::SolidLine ); polylineProperties[0x24] = CGarminTyp::polyline_property(0x24, "#b67824", 2, Qt::SolidLine ); polylineProperties[0x25] = CGarminTyp::polyline_property(0x25, "#b67824", 3, Qt::SolidLine ); polylineProperties[0x26] = CGarminTyp::polyline_property(0x26, "#0000ff", 2, Qt::DotLine ); polylineProperties[0x27] = CGarminTyp::polyline_property(0x27, "#c46442", 4, Qt::SolidLine ); polylineProperties[0x28] = CGarminTyp::polyline_property(0x28, "#aa0000", 2, Qt::SolidLine ); polylineProperties[0x29] = CGarminTyp::polyline_property(0x29, "#ff0000", 2, Qt::SolidLine ); polylineProperties[0x2A] = CGarminTyp::polyline_property(0x2A, "#000000", 2, Qt::SolidLine ); polylineProperties[0x2B] = CGarminTyp::polyline_property(0x2B, "#000000", 2, Qt::SolidLine ); polylineProperties[0x01].strings[0x00] = tr("Major highway"); polylineProperties[0x02].strings[0x00] = tr("Principal highway"); polylineProperties[0x03].strings[0x00] = tr("Other highway"); polylineProperties[0x04].strings[0x00] = tr("Arterial road"); polylineProperties[0x05].strings[0x00] = tr("Collector road"); polylineProperties[0x06].strings[0x00] = tr("Residential street"); polylineProperties[0x07].strings[0x00] = tr("Alley/Private road"); polylineProperties[0x08].strings[0x00] = tr("Highway ramp, low speed"); polylineProperties[0x09].strings[0x00] = tr("Highway ramp, high speed"); polylineProperties[0x0a].strings[0x00] = tr("Unpaved road"); polylineProperties[0x0b].strings[0x00] = tr("Major highway connector"); polylineProperties[0x0c].strings[0x00] = tr("Roundabout"); polylineProperties[0x14].strings[0x00] = tr("Railroad"); polylineProperties[0x15].strings[0x00] = tr("Shoreline"); polylineProperties[0x16].strings[0x00] = tr("Trail"); polylineProperties[0x18].strings[0x00] = tr("Stream"); polylineProperties[0x19].strings[0x00] = tr("Time zone"); polylineProperties[0x1a].strings[0x00] = tr("Ferry"); polylineProperties[0x1b].strings[0x00] = tr("Ferry"); polylineProperties[0x1c].strings[0x00] = tr("State/province border"); polylineProperties[0x1d].strings[0x00] = tr("County/parish border"); polylineProperties[0x1e].strings[0x00] = tr("International border"); polylineProperties[0x1f].strings[0x00] = tr("River"); polylineProperties[0x20].strings[0x00] = tr("Minor land contour"); polylineProperties[0x21].strings[0x00] = tr("Intermediate land contour"); polylineProperties[0x22].strings[0x00] = tr("Major land contour"); polylineProperties[0x23].strings[0x00] = tr("Minor depth contour"); polylineProperties[0x24].strings[0x00] = tr("Intermediate depth contour"); polylineProperties[0x25].strings[0x00] = tr("Major depth contour"); polylineProperties[0x26].strings[0x00] = tr("Intermittent stream"); polylineProperties[0x27].strings[0x00] = tr("Airport runway"); polylineProperties[0x28].strings[0x00] = tr("Pipeline"); polylineProperties[0x29].strings[0x00] = tr("Powerline"); polylineProperties[0x2a].strings[0x00] = tr("Marine boundary"); polylineProperties[0x2b].strings[0x00] = tr("Hazard boundary"); polygonProperties.clear(); polygonProperties[0x01] = CGarminTyp::polygon_property(0x01, Qt::NoPen, "#d2c0c0", Qt::SolidPattern); polygonProperties[0x02] = CGarminTyp::polygon_property(0x02, Qt::NoPen, "#fbeab7", Qt::SolidPattern); polygonProperties[0x03] = CGarminTyp::polygon_property(0x03, Qt::NoPen, "#a4b094", Qt::SolidPattern); polygonProperties[0x04] = CGarminTyp::polygon_property(0x04, Qt::NoPen, "#808080", Qt::SolidPattern); polygonProperties[0x05] = CGarminTyp::polygon_property(0x05, Qt::NoPen, "#f0f0f0", Qt::SolidPattern); polygonProperties[0x06] = CGarminTyp::polygon_property(0x06, Qt::NoPen, "#cacaca", Qt::SolidPattern); polygonProperties[0x07] = CGarminTyp::polygon_property(0x07, Qt::NoPen, "#feebcf", Qt::SolidPattern); polygonProperties[0x08] = CGarminTyp::polygon_property(0x08, Qt::NoPen, "#fde8d5", Qt::SolidPattern); polygonProperties[0x09] = CGarminTyp::polygon_property(0x09, Qt::NoPen, "#fee8b8", Qt::SolidPattern); polygonProperties[0x0a] = CGarminTyp::polygon_property(0x0a, Qt::NoPen, "#fdeac6", Qt::SolidPattern); polygonProperties[0x0b] = CGarminTyp::polygon_property(0x0b, Qt::NoPen, "#fddfbd", Qt::SolidPattern); polygonProperties[0x0c] = CGarminTyp::polygon_property(0x0c, Qt::NoPen, "#ebeada", Qt::SolidPattern); polygonProperties[0x0d] = CGarminTyp::polygon_property(0x0d, Qt::NoPen, "#f8e3be", Qt::SolidPattern); polygonProperties[0x0e] = CGarminTyp::polygon_property(0x0e, Qt::NoPen, "#e0e0e0", Qt::SolidPattern); polygonProperties[0x13] = CGarminTyp::polygon_property(0x13, Qt::NoPen, "#cc9900", Qt::SolidPattern); polygonProperties[0x14] = CGarminTyp::polygon_property(0x14, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x15] = CGarminTyp::polygon_property(0x15, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x16] = CGarminTyp::polygon_property(0x16, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x17] = CGarminTyp::polygon_property(0x17, Qt::NoPen, "#90be00", Qt::SolidPattern); polygonProperties[0x18] = CGarminTyp::polygon_property(0x18, Qt::NoPen, "#00ff00", Qt::SolidPattern); polygonProperties[0x19] = CGarminTyp::polygon_property(0x19, Qt::NoPen, "#f8e3be", Qt::SolidPattern); polygonProperties[0x1a] = CGarminTyp::polygon_property(0x1a, Qt::NoPen, "#d3f5a5", Qt::SolidPattern); polygonProperties[0x1e] = CGarminTyp::polygon_property(0x1e, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x1f] = CGarminTyp::polygon_property(0x1f, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x20] = CGarminTyp::polygon_property(0x20, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x28] = CGarminTyp::polygon_property(0x28, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x29] = CGarminTyp::polygon_property(0x29, Qt::NoPen, "#0000ff", Qt::SolidPattern); polygonProperties[0x32] = CGarminTyp::polygon_property(0x32, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x3b] = CGarminTyp::polygon_property(0x3b, Qt::NoPen, "#0000ff", Qt::SolidPattern); polygonProperties[0x3c] = CGarminTyp::polygon_property(0x3c, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x3d] = CGarminTyp::polygon_property(0x3d, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x3e] = CGarminTyp::polygon_property(0x3e, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x3f] = CGarminTyp::polygon_property(0x3f, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x40] = CGarminTyp::polygon_property(0x40, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x41] = CGarminTyp::polygon_property(0x41, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x42] = CGarminTyp::polygon_property(0x42, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x43] = CGarminTyp::polygon_property(0x43, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x44] = CGarminTyp::polygon_property(0x44, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x45] = CGarminTyp::polygon_property(0x45, Qt::NoPen, "#0000ff", Qt::SolidPattern); polygonProperties[0x46] = CGarminTyp::polygon_property(0x46, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x47] = CGarminTyp::polygon_property(0x47, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x48] = CGarminTyp::polygon_property(0x48, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x49] = CGarminTyp::polygon_property(0x49, Qt::NoPen, "#0080ff", Qt::SolidPattern); #ifdef WIN32 polygonProperties[0x4a] = CGarminTyp::polygon_property(0x4a, "#000000", qRgba(255,255,255,0), Qt::SolidPattern); polygonProperties[0x4b] = CGarminTyp::polygon_property(0x4b, "#000000", qRgba(255,255,255,0), Qt::SolidPattern); #else polygonProperties[0x4a] = CGarminTyp::polygon_property(0x4a, "#000000", Qt::transparent, Qt::NoBrush); polygonProperties[0x4b] = CGarminTyp::polygon_property(0x4b, "#000000", Qt::transparent, Qt::NoBrush); #endif polygonProperties[0x4c] = CGarminTyp::polygon_property(0x4c, Qt::NoPen, "#f0e68c", Qt::SolidPattern); polygonProperties[0x4d] = CGarminTyp::polygon_property(0x4d, Qt::NoPen, "#00ffff", Qt::SolidPattern); polygonProperties[0x4e] = CGarminTyp::polygon_property(0x4e, Qt::NoPen, "#d3f5a5", Qt::SolidPattern); polygonProperties[0x4f] = CGarminTyp::polygon_property(0x4f, Qt::NoPen, "#d3f5a5", Qt::SolidPattern); polygonProperties[0x50] = CGarminTyp::polygon_property(0x50, Qt::NoPen, "#b7e999", Qt::SolidPattern); polygonProperties[0x51] = CGarminTyp::polygon_property(0x51, Qt::NoPen, "#0000ff", Qt::DiagCrossPattern); polygonProperties[0x52] = CGarminTyp::polygon_property(0x52, Qt::NoPen, "#4aca4a", Qt::SolidPattern); polygonProperties[0x53] = CGarminTyp::polygon_property(0x53, Qt::NoPen, "#bcedfa", Qt::SolidPattern); polygonProperties[0x54] = CGarminTyp::polygon_property(0x54, Qt::NoPen, "#fde8d5", Qt::SolidPattern); polygonProperties[0x59] = CGarminTyp::polygon_property(0x59, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x69] = CGarminTyp::polygon_property(0x69, Qt::NoPen, "#0080ff", Qt::SolidPattern); polygonProperties[0x01].strings[0x00] = tr("Large urban area (>200K)"); polygonProperties[0x02].strings[0x00] = tr("Small urban area (<200K)"); polygonProperties[0x03].strings[0x00] = tr("Rural housing area"); polygonProperties[0x04].strings[0x00] = tr("Military base"); polygonProperties[0x05].strings[0x00] = tr("Parking lot"); polygonProperties[0x06].strings[0x00] = tr("Parking garage"); polygonProperties[0x07].strings[0x00] = tr("Airport"); polygonProperties[0x08].strings[0x00] = tr("Shopping center"); polygonProperties[0x09].strings[0x00] = tr("Marina"); polygonProperties[0x0a].strings[0x00] = tr("University/College"); polygonProperties[0x0b].strings[0x00] = tr("Hospital"); polygonProperties[0x0c].strings[0x00] = tr("Industrial complex"); polygonProperties[0x0d].strings[0x00] = tr("Reservation"); polygonProperties[0x0e].strings[0x00] = tr("Airport runway"); polygonProperties[0x13].strings[0x00] = tr("Man-made area"); polygonProperties[0x19].strings[0x00] = tr("Sports complex"); polygonProperties[0x18].strings[0x00] = tr("Golf course"); polygonProperties[0x1a].strings[0x00] = tr("Cemetery"); polygonProperties[0x14].strings[0x00] = tr("National park"); polygonProperties[0x15].strings[0x00] = tr("National park"); polygonProperties[0x16].strings[0x00] = tr("National park"); polygonProperties[0x17].strings[0x00] = tr("City park"); polygonProperties[0x1e].strings[0x00] = tr("State park"); polygonProperties[0x1f].strings[0x00] = tr("State park"); polygonProperties[0x20].strings[0x00] = tr("State park"); polygonProperties[0x50].strings[0x00] = tr("Forest"); polygonProperties[0x28].strings[0x00] = tr("Ocean"); polygonProperties[0x29].strings[0x00] = tr("Blue (unknown)"); polygonProperties[0x32].strings[0x00] = tr("Sea"); polygonProperties[0x3b].strings[0x00] = tr("Blue (unknown)"); polygonProperties[0x3c].strings[0x00] = tr("Large lake"); polygonProperties[0x3d].strings[0x00] = tr("Large lake"); polygonProperties[0x3e].strings[0x00] = tr("Medium lake"); polygonProperties[0x3f].strings[0x00] = tr("Medium lake"); polygonProperties[0x40].strings[0x00] = tr("Small lake"); polygonProperties[0x41].strings[0x00] = tr("Small lake"); polygonProperties[0x42].strings[0x00] = tr("Major lake"); polygonProperties[0x43].strings[0x00] = tr("Major lake"); polygonProperties[0x44].strings[0x00] = tr("Large lake"); polygonProperties[0x46].strings[0x00] = tr("Blue (unknown)"); polygonProperties[0x46].strings[0x00] = tr("Major River"); polygonProperties[0x47].strings[0x00] = tr("Large River"); polygonProperties[0x48].strings[0x00] = tr("Medium River"); polygonProperties[0x49].strings[0x00] = tr("Small River"); // polygonProperties[0x4a].strings[0x00] = tr("Definition area"); // polygonProperties[0x4b].strings[0x00] = tr("Background"); polygonProperties[0x4c].strings[0x00] = tr("Intermittent water"); polygonProperties[0x51].strings[0x00] = tr("Wetland/Swamp"); polygonProperties[0x4d].strings[0x00] = tr("Glacier"); polygonProperties[0x4e].strings[0x00] = tr("Orchard/Plantation"); polygonProperties[0x4f].strings[0x00] = tr("Scrub"); polygonProperties[0x52].strings[0x00] = tr("Tundra"); polygonProperties[0x53].strings[0x00] = tr("Flat"); polygonProperties[0x54].strings[0x00] = tr("???"); polygonDrawOrder.clear(); for(int i = 0; i < 0x80; i++) { polygonDrawOrder << (0x7F - i); } pointProperties.clear(); if(!typeFile.isEmpty()) { QFile file(typeFile); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(CMainWindow::self().getBestWidgetForParent(), tr("Read external type file..."), tr("Failed to read type file: %1\nFall back to internal types.").arg(typeFile), QMessageBox::Ok); typeFile.clear(); setupTyp(); return; } QByteArray array = file.readAll(); CGarminTyp typ; typ.decode(array, polygonProperties, polylineProperties, polygonDrawOrder, pointProperties); file.close(); } else { QMap::iterator subfile = subfiles.begin(); while(subfile != subfiles.end()) { if(!(*subfile).parts.contains("TYP")) { ++subfile; continue; } CFileExt file(filename); file.open(QIODevice::ReadOnly); QByteArray array; readFile(file, (*subfile).parts["TYP"].offset, (*subfile).parts["TYP"].size, array); CGarminTyp typ; typ.decode(array, polygonProperties, polylineProperties, polygonDrawOrder, pointProperties); file.close(); break; } } } void CMapIMG::readFile(CFileExt& file, quint32 offset, quint32 size, QByteArray& data) { if(offset + size > file.size()) { throw exce_t(eErrOpen, tr("Failed to read: ") + filename); } data = QByteArray::fromRawData(file.data(offset, size), size); // wenn mask == 0 ist kein xor noetig if(mask == 0) { return; } #ifdef HOST_IS_64_BIT quint64 * p64 = (quint64*)data.data(); for(quint32 i = 0; i < size/8; ++i) { *p64++ ^= mask64; } quint32 rest = size % 8; quint8 * p = (quint8*)p64; #else quint32 * p32 = (quint32*)data.data(); for(quint32 i = 0; i < size/4; ++i) { *p32++ ^= mask32; } quint32 rest = size % 4; quint8 * p = (quint8*)p32; #endif for(quint32 i = 0; i < rest; ++i) { *p++ ^= mask; } } void CMapIMG::readBasics() { char tmpstr[64]; qint64 fsize = QFileInfo(filename).size(); CFileExt file(filename); if(!file.open(QIODevice::ReadOnly)) { throw exce_t(eErrOpen, tr("Failed to open: ") + filename); } mask = (quint8)*file.data(0,1); mask32 = mask; mask32 <<= 8; mask32 |= mask; mask32 <<= 8; mask32 |= mask; mask32 <<= 8; mask32 |= mask; mask64 = mask32; mask64 <<= 32; mask64 |= mask32; // read hdr_img_t QByteArray imghdr; readFile(file, 0, sizeof(hdr_img_t), imghdr); hdr_img_t * pImgHdr = (hdr_img_t*)imghdr.data(); if(strncmp(pImgHdr->signature,"DSKIMG",7) != 0) { throw exce_t(errFormat,tr("Bad file format: ") + filename); } if(strncmp(pImgHdr->identifier,"GARMIN",7) != 0) { throw exce_t(errFormat,tr("Bad file format: ") + filename); } mapdesc = QByteArray((const char*)pImgHdr->desc1,20); mapdesc += pImgHdr->desc2; qDebug() << mapdesc; size_t blocksize = pImgHdr->blocksize(); // 1st read FAT QByteArray FATblock; readFile(file, sizeof(hdr_img_t), sizeof(FATblock_t), FATblock); const FATblock_t * pFATBlock = (const FATblock_t * )FATblock.data(); size_t dataoffset = sizeof(hdr_img_t); // skip dummy blocks at the beginning while(dataoffset < (size_t)fsize) { if(pFATBlock->flag != 0x00) { break; } dataoffset += sizeof(FATblock_t); readFile(file, quint32(dataoffset), quint32(sizeof(FATblock_t)), FATblock); pFATBlock = (const FATblock_t * )FATblock.data(); } // start of new subfile part /* It is taken for granted that the single subfile parts are not fragmented within the file. Thus it is not really necessary to store and handle all block sequence numbers. Just the first one will give us the offset. This also implies that it is not necessary to care about FAT blocks with a non-zero part number. 2007-03-31: Garmin's world base map seems to be coded different. The part field seems to be rather a bit field than a part number. As the total subfile size is given for the first part only (for all others it's zero) I use it to identify the 1st part of a subfile 2007-05-26: Gmapsupp images by Sendmap code quite some bull shit, too. The size is stored in every part and they do have a part number. I introduced a set of subfile names storing the subfile's name and type. The first part with a size info and it's name / type not stored in the set is used to get the location information. */ QSet subfileNames; while(dataoffset < (size_t)fsize) { if(pFATBlock->flag != 0x01) { break; } memcpy(tmpstr,pFATBlock->name,sizeof(pFATBlock->name) + sizeof(pFATBlock->type)); tmpstr[sizeof(pFATBlock->name) + sizeof(pFATBlock->type)] = 0; if(gar_load(quint32, pFATBlock->size) != 0 && !subfileNames.contains(tmpstr) && tmpstr[0] != 0x20) { subfileNames << tmpstr; memcpy(tmpstr,pFATBlock->name,sizeof(pFATBlock->name)); tmpstr[sizeof(pFATBlock->name)] = 0; // skip MAPSORC.MPS section if(strcmp(tmpstr,"MAPSOURC") && strcmp(tmpstr,"SENDMAP2")) { subfile_desc_t& subfile = subfiles[tmpstr]; subfile.name = tmpstr; memcpy(tmpstr,pFATBlock->type,sizeof(pFATBlock->type)); tmpstr[sizeof(pFATBlock->type)] = 0; subfile_part_t& part = subfile.parts[tmpstr]; part.size = gar_load(quint32, pFATBlock->size); part.offset = quint32(gar_load(uint16_t, pFATBlock->blocks[0]) * blocksize); } } dataoffset += sizeof(FATblock_t); readFile(file, quint32(dataoffset), quint32(sizeof(FATblock_t)), FATblock); pFATBlock = (const FATblock_t * )FATblock.data(); } if((dataoffset == sizeof(hdr_img_t)) || (dataoffset >= (size_t)fsize)) { throw exce_t(errFormat,tr("Failed to read file structure: ") + filename); } // gmapsupp.img files do not have a data offset field if(gar_load(quint32, pImgHdr->dataoffset) == 0) { pImgHdr->dataoffset = gar_load(quint32, dataoffset); } // sometimes there are dummy blocks at the end of the FAT if(gar_load(quint32, pImgHdr->dataoffset) != dataoffset) { dataoffset = gar_load(quint32, pImgHdr->dataoffset); } #ifdef DEBUG_SHOW_SECT_DESC { QMap::const_iterator subfile = subfiles.begin(); while(subfile != subfiles.end()) { qDebug() << "--- subfile" << subfile->name << "---"; QMap::const_iterator part = subfile->parts.begin(); while(part != subfile->parts.end()) { qDebug() << part.key() << hex << part->offset << part->size; ++part; } ++subfile; } } #endif //DEBUG_SHOW_SECT_DESC int cnt = 1; int tot = subfiles.count(); PROGRESS_SETUP(tr("Loading %1").arg(QFileInfo(filename).fileName()), 0, tot, CMainWindow::getBestWidgetForParent()); maparea = QRectF(); QMap::iterator subfile = subfiles.begin(); while(subfile != subfiles.end()) { PROGRESS(cnt++, throw exce_t(errAbort,tr("User abort: ") + filename)); if((*subfile).parts.contains("GMP")) { throw exce_t(errFormat,tr("File is NT format. QMapShack is unable to read map files with NT format: ") + filename); } readSubfileBasics(*subfile, file); ++subfile; } // combine copyright sections copyright.clear(); for(const QString &str : copyrights) { if(!copyright.isEmpty()) { copyright += "\n"; } copyright += str; } qDebug() << "dimensions:\t" << "N" << (maparea.bottom()*RAD_TO_DEG) << "E" << (maparea.right()*RAD_TO_DEG) << "S" << (maparea.top()*RAD_TO_DEG) << "W" << (maparea.left()*RAD_TO_DEG); } void CMapIMG::readSubfileBasics(subfile_desc_t& subfile, CFileExt &file) { // test for mandatory subfile parts if(!(subfile.parts.contains("TRE") && subfile.parts.contains("RGN"))) { return; } QByteArray trehdr; readFile(file, subfile.parts["TRE"].offset, sizeof(hdr_tre_t), trehdr); hdr_tre_t * pTreHdr = (hdr_tre_t * )trehdr.data(); subfile.isTransparent = pTreHdr->POI_flags & 0x02; transparent = subfile.isTransparent ? true : transparent; #ifdef DEBUG_SHOW_TRE_DATA qDebug() << "+++" << subfile.name << "+++"; qDebug() << "TRE header length :" << gar_load(uint16_t, pTreHdr->length); qDebug() << "TRE1 offset :" << hex << gar_load(quint32, pTreHdr->tre1_offset); qDebug() << "TRE1 size :" << dec << gar_load(quint32, pTreHdr->tre1_size); qDebug() << "TRE2 offset :" << hex << gar_load(quint32, pTreHdr->tre2_offset); qDebug() << "TRE2 size :" << dec << gar_load(quint32, pTreHdr->tre2_size); #endif // DEBUG_SHOW_TRE_DATA copyrights << QString(file.data(subfile.parts["TRE"].offset + gar_load(uint16_t, pTreHdr->length),0x7FFF)); // read map boundaries from header qint32 i32; i32 = gar_ptr_load(int24_t, &pTreHdr->northbound); subfile.north = GARMIN_RAD(i32); i32 = gar_ptr_load(int24_t, &pTreHdr->eastbound); subfile.east = GARMIN_RAD(i32); i32 = gar_ptr_load(int24_t, &pTreHdr->southbound); subfile.south = GARMIN_RAD(i32); i32 = gar_ptr_load(int24_t, &pTreHdr->westbound); subfile.west = GARMIN_RAD(i32); if(subfile.east == subfile.west) { subfile.east = -subfile.east; } if(subfile.west > 0 && subfile.east < 0) { subfile.east = -subfile.east; } subfile.area = QRectF(QPointF(subfile.west, subfile.north), QPointF(subfile.east, subfile.south)); if(maparea.isNull()) { maparea = subfile.area; } else { maparea = maparea.united(subfile.area); } #ifdef DEBUG_SHOW_TRE_DATA qDebug() << "bounding area (\260)" << (subfile.north*RAD_TO_DEG) << (subfile.east*RAD_TO_DEG) << (subfile.south*RAD_TO_DEG) << (subfile.west*RAD_TO_DEG); qDebug() << "bounding area (rad)" << subfile.area; #endif // DEBUG_SHOW_TRE_DATA QByteArray maplevel; readFile(file, subfile.parts["TRE"].offset + gar_load(quint32, pTreHdr->tre1_offset), gar_load(quint32, pTreHdr->tre1_size), maplevel); const tre_map_level_t * pMapLevel = (const tre_map_level_t * )maplevel.data(); if(pTreHdr->flag & 0x80) { throw exce_t(errLock,tr("File contains locked / encrypted data. Garmin does not " "want you to use this file with any other software than " "the one supplied by Garmin.")); } quint32 nlevels = gar_load(quint32, pTreHdr->tre1_size) / sizeof(tre_map_level_t); quint32 nsubdivs = 0; quint32 nsubdivs_last = 0; // count subsections for(quint32 i=0; ibits; subfile.maplevels << ml; nsubdivs += gar_load(uint16_t, pMapLevel->nsubdiv); nsubdivs_last = gar_load(uint16_t, pMapLevel->nsubdiv); #ifdef DEBUG_SHOW_MAPLEVEL_DATA qDebug() << "level" << TRE_MAP_LEVEL(pMapLevel) << "inherited" << TRE_MAP_INHER(pMapLevel) << "bits" << pMapLevel->bits << "#subdivs" << gar_load(uint16_t, pMapLevel->nsubdiv); #endif // DEBUG_SHOW_MAPLEVEL_DATA ++pMapLevel; } quint32 nsubdivs_next = nsubdivs - nsubdivs_last; ////////////////////////////////// // read subdivision information ////////////////////////////////// // point to first map level definition pMapLevel = (const tre_map_level_t * )maplevel.data(); // number of subdivisions per map level quint32 nsubdiv = gar_load(uint16_t, pMapLevel->nsubdiv); // point to first 16 byte subdivision definition entry QByteArray subdiv_n; readFile(file, subfile.parts["TRE"].offset + gar_load(quint32, pTreHdr->tre2_offset), gar_load(quint32, pTreHdr->tre2_size), subdiv_n); tre_subdiv_next_t * pSubDivN = (tre_subdiv_next_t*)subdiv_n.data(); QVector subdivs; subdivs.resize(nsubdivs); QVector::iterator subdiv = subdivs.begin(); QVector::iterator subdiv_prev = subdivs.end(); // absolute offset of RGN data QByteArray rgnhdr; readFile(file, subfile.parts["RGN"].offset, sizeof(hdr_rgn_t), rgnhdr); hdr_rgn_t * pRgnHdr = (hdr_rgn_t*)rgnhdr.data(); quint32 rgnoff = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->offset); quint32 rgnOffPolyg2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->offset_polyg2); quint32 rgnOffPolyl2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->offset_polyl2); quint32 rgnOffPoint2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->offset_point2); quint32 rgnLenPolyg2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->length_polyg2); quint32 rgnLenPolyl2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->length_polyl2); quint32 rgnLenPoint2 = /*subfile.parts["RGN"].offset +*/ gar_load(quint32, pRgnHdr->length_point2); // qDebug() << "***" << hex << subfile.parts["RGN"].offset << (subfile.parts["RGN"].offset + subfile.parts["RGN"].size); // qDebug() << "+++" << hex << rgnOffPolyg2 << (rgnOffPolyg2 + rgnLenPolyg2); // qDebug() << "+++" << hex << rgnOffPolyl2 << (rgnOffPolyl2 + rgnLenPolyl2); // qDebug() << "+++" << hex << rgnOffPoint2 << (rgnOffPoint2 + rgnLenPoint2); // parse all 16 byte subdivision entries quint32 i; for(i=0; in = i; subdiv->next = gar_load(uint16_t, pSubDivN->next); subdiv->terminate = TRE_SUBDIV_TERM(pSubDivN); subdiv->rgn_start = gar_ptr_load(uint24_t, &pSubDivN->rgn_offset); subdiv->rgn_start += rgnoff; // skip if this is the first entry if(subdiv_prev != subdivs.end()) { subdiv_prev->rgn_end = subdiv->rgn_start; } subdiv->hasPoints = pSubDivN->elements & 0x10; subdiv->hasIdxPoints = pSubDivN->elements & 0x20; subdiv->hasPolylines = pSubDivN->elements & 0x40; subdiv->hasPolygons = pSubDivN->elements & 0x80; // if all subdivisions of this level have been parsed, switch to the next one if(nsubdiv == 0) { ++pMapLevel; nsubdiv = gar_load(uint16_t, pMapLevel->nsubdiv); } subdiv->level = TRE_MAP_LEVEL(pMapLevel); subdiv->shift = 24 - pMapLevel->bits; qint32 cx = gar_ptr_load(uint24_t, &pSubDivN->center_lng); subdiv->iCenterLng = cx; qint32 cy = gar_ptr_load(uint24_t, &pSubDivN->center_lat); subdiv->iCenterLat = cy; qint32 width = TRE_SUBDIV_WIDTH(pSubDivN) << subdiv->shift; qint32 height = gar_load(uint16_t, pSubDivN->height) << subdiv->shift; subdiv->north = GARMIN_RAD(cy + height + 1); subdiv->south = GARMIN_RAD(cy - height); subdiv->east = GARMIN_RAD(cx + width + 1); subdiv->west = GARMIN_RAD(cx - width); subdiv->area = QRectF(QPointF(subdiv->west, subdiv->north), QPointF(subdiv->east, subdiv->south)); subdiv->offsetPoints2 = 0; subdiv->lengthPoints2 = 0; subdiv->offsetPolylines2 = 0; subdiv->lengthPolylines2 = 0; subdiv->offsetPolygons2 = 0; subdiv->lengthPolygons2 = 0; subdiv_prev = subdiv; ++pSubDivN; ++subdiv; } // switch to last map level ++pMapLevel; // witch pointer to 14 byte subdivision sections tre_subdiv_t* pSubDivL = pSubDivN; // parse all 14 byte subdivision entries of last map level for(; in = i; subdiv->next = 0; subdiv->terminate = TRE_SUBDIV_TERM(pSubDivL); subdiv->rgn_start = gar_ptr_load(uint24_t, &pSubDivL->rgn_offset); subdiv->rgn_start += rgnoff; subdiv_prev->rgn_end = subdiv->rgn_start; subdiv->hasPoints = pSubDivL->elements & 0x10; subdiv->hasIdxPoints = pSubDivL->elements & 0x20; subdiv->hasPolylines = pSubDivL->elements & 0x40; subdiv->hasPolygons = pSubDivL->elements & 0x80; subdiv->level = TRE_MAP_LEVEL(pMapLevel); subdiv->shift = 24 - pMapLevel->bits; qint32 cx = gar_ptr_load(uint24_t, &pSubDivL->center_lng); subdiv->iCenterLng = cx; qint32 cy = gar_ptr_load(uint24_t, &pSubDivL->center_lat); subdiv->iCenterLat = cy; qint32 width = TRE_SUBDIV_WIDTH(pSubDivL) << subdiv->shift; qint32 height = gar_load(uint16_t, pSubDivL->height) << subdiv->shift; subdiv->north = GARMIN_RAD(cy + height + 1); subdiv->south = GARMIN_RAD(cy - height); subdiv->east = GARMIN_RAD(cx + width + 1); subdiv->west = GARMIN_RAD(cx - width); subdiv->area = QRectF(QPointF(subdiv->west, subdiv->north), QPointF(subdiv->east, subdiv->south)); subdiv->offsetPoints2 = 0; subdiv->lengthPoints2 = 0; subdiv->offsetPolylines2 = 0; subdiv->lengthPolylines2 = 0; subdiv->offsetPolygons2 = 0; subdiv->lengthPolygons2 = 0; subdiv_prev = subdiv; ++pSubDivL; ++subdiv; } subdivs.last().rgn_end = gar_load(quint32, pRgnHdr->hdr_rgn_t::offset) + gar_load(quint32, pRgnHdr->hdr_rgn_t::length); // read extended NT elements if((gar_load(uint16_t, pTreHdr->hdr_subfile_part_t::length) >= 0x9A) && pTreHdr->tre7_size && (gar_load(uint16_t, pTreHdr->tre7_rec_size) >= sizeof(tre_subdiv2_t))) { //rgnoff = subfile.parts["RGN"].offset; // qDebug() << subdivs.count() << (pTreHdr->tre7_size / pTreHdr->tre7_rec_size) << pTreHdr->tre7_rec_size; QByteArray subdiv2; readFile(file, subfile.parts["TRE"].offset + gar_load(quint32, pTreHdr->tre7_offset), gar_load(quint32, pTreHdr->tre7_size), subdiv2); tre_subdiv2_t * pSubDiv2 = (tre_subdiv2_t*)subdiv2.data(); // const quint32 entries1 = gar_load(quint32, pTreHdr->tre7_size) / gar_load(quint32, pTreHdr->tre7_rec_size); // const quint32 entries2 = subdivs.size(); bool skipPois = ( gar_load(uint16_t, pTreHdr->tre7_rec_size) != sizeof(tre_subdiv2_t) ); // for(int i = 0; i < pTreHdr->tre7_rec_size; ++i){ // if(i%4 == 0) fprintf(stderr,"\n"); // fprintf(stderr,"%02X ", ((quint8*)pSubDiv2)[i]); // } // fprintf(stderr,"\n"); subdiv = subdivs.begin(); subdiv_prev = subdivs.begin(); subdiv->offsetPolygons2 = gar_load(quint32, pSubDiv2->offsetPolygons) + rgnOffPolyg2; subdiv->offsetPolylines2 = gar_load(quint32, pSubDiv2->offsetPolyline) + rgnOffPolyl2; subdiv->offsetPoints2 = skipPois ? 0 : gar_load(quint32, pSubDiv2->offsetPoints) + rgnOffPoint2; ++subdiv; pSubDiv2 = reinterpret_cast((quint8*)pSubDiv2 + gar_endian(uint16_t, pTreHdr->tre7_rec_size)); while(subdiv != subdivs.end()) { // for(int i = 0; i < pTreHdr->tre7_rec_size; ++i){ // if(i%4 == 0) fprintf(stderr,"\n"); // fprintf(stderr,"%02X ", ((quint8*)pSubDiv2)[i]); // } // fprintf(stderr,"\n"); subdiv->offsetPolygons2 = gar_load(quint32, pSubDiv2->offsetPolygons) + rgnOffPolyg2; subdiv->offsetPolylines2 = gar_load(quint32, pSubDiv2->offsetPolyline) + rgnOffPolyl2; subdiv->offsetPoints2 = skipPois ? 0 : gar_load(quint32, pSubDiv2->offsetPoints) + rgnOffPoint2; subdiv_prev->lengthPolygons2 = subdiv->offsetPolygons2 - subdiv_prev->offsetPolygons2; subdiv_prev->lengthPolylines2 = subdiv->offsetPolylines2 - subdiv_prev->offsetPolylines2; subdiv_prev->lengthPoints2 = skipPois ? 0 : subdiv->offsetPoints2 - subdiv_prev->offsetPoints2; subdiv_prev = subdiv; ++subdiv; pSubDiv2 = reinterpret_cast((quint8*)pSubDiv2 + gar_endian(uint16_t, pTreHdr->tre7_rec_size)); } subdiv_prev->lengthPolygons2 = rgnOffPolyg2 + rgnLenPolyg2 - subdiv_prev->offsetPolygons2; subdiv_prev->lengthPolylines2 = rgnOffPolyl2 + rgnLenPolyl2 - subdiv_prev->offsetPolylines2; subdiv_prev->lengthPoints2 = skipPois ? 0 : rgnOffPoint2 + rgnLenPoint2 - subdiv_prev->offsetPoints2; } subfile.subdivs = subdivs; #ifdef DEBUG_SHOW_SUBDIV_DATA { QVector::iterator subdiv = subfile.subdivs.begin(); while(subdiv != subfile.subdivs.end()) { qDebug() << "--- subdiv" << subdiv->n << "---"; qDebug() << "RGN start " << hex << subdiv->rgn_start; qDebug() << "RGN end " << hex << subdiv->rgn_end; qDebug() << "center lng " << GARMIN_DEG(subdiv->iCenterLng); qDebug() << "center lat " << GARMIN_DEG(subdiv->iCenterLat); qDebug() << "has points " << subdiv->hasPoints; qDebug() << "has indexed points " << subdiv->hasIdxPoints; qDebug() << "has polylines " << subdiv->hasPolylines; qDebug() << "has polygons " << subdiv->hasPolygons; qDebug() << "bounding area (m) " << subdiv->area.topLeft() << subdiv->area.bottomRight(); qDebug() << "map level " << subdiv->level; qDebug() << "left shifts " << subdiv->shift; qDebug() << "polyg off. " << hex << subdiv->offsetPolygons2; qDebug() << "polyg len. " << hex << subdiv->lengthPolygons2; qDebug() << "polyl off. " << hex << subdiv->offsetPolylines2; qDebug() << "polyl len. " << hex << subdiv->lengthPolylines2; qDebug() << "point off. " << hex << subdiv->offsetPoints2; qDebug() << "point len. " << hex << subdiv->lengthPoints2; ++subdiv; } } #endif // DEBUG_SHOW_SUBDIV_DATA // qDebug() << "***" << hex << subfile.parts["RGN"].offset << (subfile.parts["RGN"].offset + subfile.parts["RGN"].size); // qDebug() << "+++" << hex << rgnOffPolyg2 << (rgnOffPolyg2 + pRgnHdr->length_polyg2); // qDebug() << "+++" << hex << rgnOffPolyl2 << (rgnOffPolyl2 + pRgnHdr->length_polyl2); // qDebug() << "+++" << hex << rgnOffPoint2 << (rgnOffPoint2 + pRgnHdr->length_point2); if(subfile.parts.contains("LBL")) { QByteArray lblhdr; readFile(file, subfile.parts["LBL"].offset, sizeof(hdr_lbl_t), lblhdr); hdr_lbl_t * pLblHdr = (hdr_lbl_t*)lblhdr.data(); quint32 offsetLbl1 = subfile.parts["LBL"].offset + gar_load(quint32, pLblHdr->lbl1_offset); quint32 offsetLbl6 = subfile.parts["LBL"].offset + gar_load(quint32, pLblHdr->lbl6_offset); QByteArray nethdr; quint32 offsetNet1 = 0; hdr_net_t * pNetHdr = nullptr; if(subfile.parts.contains("NET")) { readFile(file, subfile.parts["NET"].offset, sizeof(hdr_net_t), nethdr); pNetHdr = (hdr_net_t*)nethdr.data(); offsetNet1 = subfile.parts["NET"].offset + gar_load(quint32, pNetHdr->net1_offset); } quint16 codepage = 0; if(gar_load(uint16_t, pLblHdr->length) > 0xAA) { codepage = gar_load(uint16_t, pLblHdr->codepage); } // qDebug() << file.fileName() << hex << offsetLbl1 << offsetLbl6 << offsetNet1; switch(pLblHdr->coding) { case 0x06: subfile.strtbl = new CGarminStrTbl6(codepage, mask, this); break; case 0x09: subfile.strtbl = new CGarminStrTbl8(codepage, mask, this); break; case 0x0A: subfile.strtbl = new CGarminStrTblUtf8(codepage, mask, this); break; default: qWarning() << "Unknown label coding" << hex << pLblHdr->coding; } if(nullptr != subfile.strtbl) { subfile.strtbl->registerLBL1(offsetLbl1, gar_load(quint32, pLblHdr->lbl1_length), pLblHdr->addr_shift); subfile.strtbl->registerLBL6(offsetLbl6, gar_load(quint32, pLblHdr->lbl6_length)); if(nullptr != pNetHdr) { subfile.strtbl->registerNET1(offsetNet1, gar_load(quint32, pNetHdr->net1_length), pNetHdr->net1_addr_shift); } } } } void CMapIMG::processPrimaryMapData() { /* * Query all subfiles for possible maplevels. * Exclude basemap to avoid pollution. */ for(const subfile_desc_t &subfile : subfiles) { for(const maplevel_t &maplevel : subfile.maplevels) { if(!maplevel.inherited) { map_level_t ml; ml.bits = maplevel.bits; ml.level = maplevel.level; ml.useBaseMap = false; maplevels << ml; } } } /* Sort all entries, note that stable sort should insure that basemap is preferred when available. */ qStableSort(maplevels.begin(), maplevels.end(), map_level_t::GreaterThan); /* Delete any duplicates for obvious performance reasons. */ auto where = std::unique(maplevels.begin(), maplevels.end()); maplevels.erase(where, maplevels.end()); #ifdef DEBUG_SHOW_MAPLEVELS for(int i=0; i < maplevels.count(); ++i) { map_level_t& ml = maplevels[i]; qDebug() << ml.bits << ml.level << ml.useBaseMap; } #endif } quint8 CMapIMG::scale2bits(const QPointF& scale) { qint32 bits = 24; if(scale.x() >= 70000.0) { bits = 2; } else if(scale.x() >= 50000.0) { bits = 3; } else if(scale.x() >= 30000.0) { bits = 4; } else if(scale.x() >= 20000.0) { bits = 5; } else if(scale.x() >= 15000.0) { bits = 6; } else if(scale.x() >= 10000.0) { bits = 7; } else if(scale.x() >= 7000.0) { bits = 8; } else if(scale.x() >= 5000.0) { bits = 9; } else if(scale.x() >= 3000.0) { bits = 10; } else if(scale.x() >= 2000.0) { bits = 11; } else if(scale.x() >= 1500.0) { bits = 12; } else if(scale.x() >= 1000.0) { bits = 13; } else if(scale.x() >= 700.0) { bits = 14; } else if(scale.x() >= 500.0) { bits = 15; } else if(scale.x() >= 300.0) { bits = 16; } else if(scale.x() >= 200.0) { bits = 17; } else if(scale.x() >= 100.0) { bits = 18; } else if(scale.x() >= 70.0) { bits = 19; } else if(scale.x() >= 30.0) { bits = 20; } else if(scale.x() >= 15.0) { bits = 21; } else if(scale.x() >= 7.0) { bits = 22; } else if(scale.x() >= 3.0) { bits = 23; } return qMax(2, qMin(24, bits + getAdjustDetailLevel())); } void CMapIMG::draw(IDrawContext::buffer_t& buf) /* override */ { if(map->needsRedraw()) { return; } QPointF bufferScale = buf.scale * buf.zoomFactor; if(isOutOfScale(bufferScale)) { return; } QPainter p(&buf.image); p.setOpacity(getOpacity()/100.0); USE_ANTI_ALIASING(p,true); QFont f = CMainWindow::self().getMapFont(); fm = QFontMetrics(f); p.setFont(f); p.setPen(Qt::black); p.setBrush(Qt::NoBrush); quint8 bits = scale2bits(bufferScale); QVector::const_iterator maplevel = maplevels.constEnd(); do { --maplevel; if(bits >= maplevel->bits) { break; } } while(maplevel != maplevels.constBegin()); qreal u1 = qMin(buf.ref1.x(), buf.ref4.x()); qreal u2 = qMax(buf.ref2.x(), buf.ref3.x()); qreal v1 = qMax(buf.ref1.y(), buf.ref2.y()); qreal v2 = qMin(buf.ref4.y(), buf.ref3.y()); QRectF viewport(u1,v1, u2 - u1, v2 - v1); QVector rectPois; polygons.clear(); polylines.clear(); pois.clear(); points.clear(); labels.clear(); /** convertRad2Px() converts positions into screen coordinates. However the painter devices paints into the buffer which is a little bit larger than the screen. Thus we need the offset of the buffer's top left corner to the top left corner of the screen to adjust all drawings. */ QPointF pp = buf.ref1; map->convertRad2Px(pp); p.save(); p.translate(-pp); if(map->needsRedraw()) { p.restore(); return; } try { loadVisibleData(false, polygons, polylines, points, pois, maplevel->level, viewport, p); } catch(std::bad_alloc) { qWarning() << "GarminIMG: Allocation error. Abort map rendering."; p.restore(); return; } if(map->needsRedraw()) { p.restore(); return; } drawPolygons(p, polygons); if(map->needsRedraw()) { p.restore(); return; } drawPolylines(p, polylines, bufferScale); if(map->needsRedraw()) { p.restore(); return; } drawPoints(p, points, rectPois); if(map->needsRedraw()) { p.restore(); return; } drawPois(p, pois, rectPois); if(map->needsRedraw()) { p.restore(); return; } drawText(p); if(map->needsRedraw()) { p.restore(); return; } drawLabels(p, labels); p.restore(); } void CMapIMG::loadVisibleData(bool fast, polytype_t& polygons, polytype_t& polylines, pointtype_t& points, pointtype_t& pois, unsigned level, const QRectF& viewport, QPainter& p) { #ifndef Q_OS_WIN32 CFileExt file(filename); if(!file.open(QIODevice::ReadOnly)) { return; } #endif for(const subfile_desc_t &subfile : subfiles) { // qDebug() << "-------"; // qDebug() << (viewport.topLeft() * RAD_TO_DEG) << (viewport.bottomRight() * RAD_TO_DEG); // qDebug() << (subfile.area.topLeft() * RAD_TO_DEG) << (subfile.area.bottomRight() * RAD_TO_DEG); // qDebug() << subfile.area.intersects(viewport); if(!subfile.area.intersects(viewport)) { continue; } if(map->needsRedraw()) { break; } #ifdef Q_OS_WIN32 CFileExt file(filename); if(!file.open(QIODevice::ReadOnly)) { return; } #endif QByteArray rgndata; readFile(file, subfile.parts["RGN"].offset, subfile.parts["RGN"].size, rgndata); // qDebug() << "rgn range" << hex << subfile.parts["RGN"].offset << (subfile.parts["RGN"].offset + subfile.parts["RGN"].size); const QVector& subdivs = subfile.subdivs; // collect polylines for(const subdiv_desc_t &subdiv : subdivs) { // if(subdiv.level == level) qDebug() << "subdiv:" << subdiv.level << level << subdiv.area << viewport << subdiv.area.intersects(viewport); if(subdiv.level != level || !subdiv.area.intersects(viewport)) { continue; } if(map->needsRedraw()) { break; } loadSubDiv(file, subdiv, subfile.strtbl, rgndata, fast, viewport, polylines, polygons, points, pois); #ifdef DEBUG_SHOW_SECTION_BORDERS const QRectF& a = subdiv.area; qreal u[2] = {a.left(), a.right()}; qreal v[2] = {a.top(), a.bottom()}; QPolygonF poly; poly << a.bottomLeft() << a.bottomRight() << a.topRight() << a.topLeft(); map->convertRad2Px(poly); p.setPen(QPen(Qt::magenta,2)); p.setBrush(Qt::NoBrush); p.drawPolygon(poly); #endif // DEBUG_SHOW_SECTION_BORDERS } #ifdef DEBUG_SHOW_SUBDIV_BORDERS QPointF p1 = subfile.area.bottomLeft(); QPointF p2 = subfile.area.bottomRight(); QPointF p3 = subfile.area.topRight(); QPointF p4 = subfile.area.topLeft(); map->convertRad2Px(p1); map->convertRad2Px(p2); map->convertRad2Px(p3); map->convertRad2Px(p4); QPolygonF poly; poly << p1 << p2 << p3 << p4; p.setPen(Qt::black); p.drawPolygon(poly); #endif // DEBUG_SHOW_SUBDIV_BORDERS #ifdef Q_OS_WIN32 file.close(); #else file.free(); #endif } #ifndef Q_OS_WIN32 file.close(); #endif } void CMapIMG::loadSubDiv(CFileExt &file, const subdiv_desc_t& subdiv, IGarminStrTbl * strtbl, const QByteArray& rgndata, bool fast, const QRectF& viewport, polytype_t& polylines, polytype_t& polygons, pointtype_t& points, pointtype_t& pois) { if(subdiv.rgn_start == subdiv.rgn_end && !subdiv.lengthPolygons2 && !subdiv.lengthPolylines2 && !subdiv.lengthPoints2) { return; } //fprintf(stderr, "loadSubDiv\n"); // qDebug() << "---------" << file.fileName() << "---------"; const quint8 * pRawData = (quint8*)rgndata.data(); quint32 opnt = 0, oidx = 0, opline = 0, opgon = 0; quint32 objCnt = subdiv.hasIdxPoints + subdiv.hasPoints + subdiv.hasPolylines + subdiv.hasPolygons; quint16 * pOffset = (quint16*)(pRawData + subdiv.rgn_start); // test for points if(subdiv.hasPoints) { opnt = (objCnt - 1) * sizeof(quint16) + subdiv.rgn_start; } // test for indexed points if(subdiv.hasIdxPoints) { if(opnt) { oidx = gar_load(uint16_t, *pOffset); oidx += subdiv.rgn_start; ++pOffset; } else { oidx = (objCnt - 1) * sizeof(quint16) + subdiv.rgn_start; } } // test for polylines if(subdiv.hasPolylines) { if(opnt || oidx) { opline = gar_load(uint16_t, *pOffset); opline += subdiv.rgn_start; ++pOffset; } else { opline = (objCnt - 1) * sizeof(quint16) + subdiv.rgn_start; } } // test for polygons if(subdiv.hasPolygons) { if(opnt || oidx || opline) { opgon = gar_load(uint16_t, *pOffset); opgon += subdiv.rgn_start; ++pOffset; } else { opgon = (objCnt - 1) * sizeof(quint16) + subdiv.rgn_start; } } #ifdef DEBUG_SHOW_POLY_DATA qDebug() << "--- Subdivision" << subdiv.n << "---"; qDebug() << "address:" << hex << subdiv.rgn_start << "- " << subdiv.rgn_end; qDebug() << "points: " << hex << opnt; qDebug() << "indexed points: " << hex << oidx; qDebug() << "polylines: " << hex << opline; qDebug() << "polygons: " << hex << opgon; #endif // DEBUG_SHOW_POLY_DATA CGarminPolygon p; // decode points if(subdiv.hasPoints && !fast && getShowPOIs()) { const quint8 *pData = pRawData + opnt; const quint8 *pEnd = pRawData + (oidx ? oidx : opline ? opline : opgon ? opgon : subdiv.rgn_end); while(pData < pEnd) { CGarminPoint p; pData += p.decode(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, pData); // skip points outside our current viewport if(!viewport.contains(p.pos)) { continue; } if(strtbl) { p.isLbl6 ? strtbl->get(file, p.lbl_ptr, IGarminStrTbl::poi, p.labels) : strtbl->get(file, p.lbl_ptr, IGarminStrTbl::norm, p.labels); } points.push_back(p); } } // decode indexed points if(subdiv.hasIdxPoints && !fast && getShowPOIs()) { const quint8 *pData = pRawData + oidx; const quint8 *pEnd = pRawData + (opline ? opline : opgon ? opgon : subdiv.rgn_end); while(pData < pEnd) { CGarminPoint p; pData += p.decode(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, pData); // skip points outside our current viewport if(!viewport.contains(p.pos)) { continue; } if(strtbl) { p.isLbl6 ? strtbl->get(file, p.lbl_ptr, IGarminStrTbl::poi, p.labels) : strtbl->get(file, p.lbl_ptr, IGarminStrTbl::norm, p.labels); } pois.push_back(p); } } // decode polylines if(subdiv.hasPolylines && !fast && getShowPolylines()) { CGarminPolygon::cnt = 0; const quint8 *pData = pRawData + opline; const quint8 *pEnd = pRawData + (opgon ? opgon : subdiv.rgn_end); while(pData < pEnd) { pData += p.decode(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, true, pData, pEnd); // skip points outside our current viewport if(isCompletlyOutside(p.pixel, viewport)) { continue; } if(strtbl && !p.lbl_in_NET && p.lbl_info) { strtbl->get(file, p.lbl_info,IGarminStrTbl::norm, p.labels); } else if(strtbl && p.lbl_in_NET && p.lbl_info) { strtbl->get(file, p.lbl_info,IGarminStrTbl::net, p.labels); } polylines.push_back(p); } } // decode polygons if(subdiv.hasPolygons && getShowPolygons()) { CGarminPolygon::cnt = 0; const quint8 *pData = pRawData + opgon; const quint8 *pEnd = pRawData + subdiv.rgn_end; while(pData < pEnd) { pData += p.decode(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, false, pData, pEnd); // skip points outside our current viewport if(isCompletlyOutside(p.pixel, viewport)) { continue; } if(strtbl && !p.lbl_in_NET && p.lbl_info && !fast) { strtbl->get(file, p.lbl_info,IGarminStrTbl::norm, p.labels); } else if(strtbl && p.lbl_in_NET && p.lbl_info && !fast) { strtbl->get(file, p.lbl_info,IGarminStrTbl::net, p.labels); } polygons.push_back(p); } } // qDebug() << "--- Subdivision" << subdiv.n << "---"; // qDebug() << "adress:" << hex << subdiv.rgn_start << "- " << subdiv.rgn_end; // qDebug() << "polyg off: " << hex << subdiv.offsetPolygons2; // qDebug() << "polyg len: " << hex << subdiv.lengthPolygons2 << dec << subdiv.lengthPolygons2; // qDebug() << "polyg end: " << hex << subdiv.lengthPolygons2 + subdiv.offsetPolygons2; // qDebug() << "polyl off: " << hex << subdiv.offsetPolylines2; // qDebug() << "polyl len: " << hex << subdiv.lengthPolylines2 << dec << subdiv.lengthPolylines2; // qDebug() << "polyl end: " << hex << subdiv.lengthPolylines2 + subdiv.offsetPolylines2; // qDebug() << "point off: " << hex << subdiv.offsetPoints2; // qDebug() << "point len: " << hex << subdiv.lengthPoints2 << dec << subdiv.lengthPoints2; // qDebug() << "point end: " << hex << subdiv.lengthPoints2 + subdiv.offsetPoints2; if(subdiv.lengthPolygons2 && getShowPolygons()) { const quint8 *pData = pRawData + subdiv.offsetPolygons2; const quint8 *pEnd = pData + subdiv.lengthPolygons2; while(pData < pEnd) { // qDebug() << "rgn offset:" << hex << (rgnoff + (pData - pRawData)); pData += p.decode2(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, false, pData, pEnd); // skip points outside our current viewport if(isCompletlyOutside(p.pixel, viewport)) { continue; } if(strtbl && !p.lbl_in_NET && p.lbl_info && !fast) { strtbl->get(file, p.lbl_info,IGarminStrTbl::norm, p.labels); } polygons.push_back(p); } } if(subdiv.lengthPolylines2 && !fast && getShowPolylines()) { const quint8 *pData = pRawData + subdiv.offsetPolylines2; const quint8 *pEnd = pData + subdiv.lengthPolylines2; while(pData < pEnd) { // qDebug() << "rgn offset:" << hex << (rgnoff + (pData - pRawData)); pData += p.decode2(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, true, pData, pEnd); // skip points outside our current viewport if(isCompletlyOutside(p.pixel, viewport)) { continue; } if(strtbl && !p.lbl_in_NET && p.lbl_info) { strtbl->get(file, p.lbl_info,IGarminStrTbl::norm, p.labels); } polylines.push_back(p); } } if(subdiv.lengthPoints2 && !fast && getShowPOIs()) { const quint8 *pData = pRawData + subdiv.offsetPoints2; const quint8 *pEnd = pData + subdiv.lengthPoints2; while(pData < pEnd) { CGarminPoint p; // qDebug() << "rgn offset:" << hex << (rgnoff + (pData - pRawData)); pData += p.decode2(subdiv.iCenterLng, subdiv.iCenterLat, subdiv.shift, pData, pEnd); // skip points outside our current viewport if(!viewport.contains(p.pos)) { continue; } if(strtbl) { p.isLbl6 ? strtbl->get(file, p.lbl_ptr, IGarminStrTbl::poi, p.labels) : strtbl->get(file, p.lbl_ptr, IGarminStrTbl::norm, p.labels); } pois.push_back(p); } } } void CMapIMG::drawPolygons(QPainter& p, polytype_t& lines) { const int N = polygonDrawOrder.size(); for(int n = 0; n < N; ++n) { quint32 type = polygonDrawOrder[(N-1) - n]; p.setPen(polygonProperties[type].pen); p.setBrush(CMainWindow::self().isNight() ? polygonProperties[type].brushNight : polygonProperties[type].brushDay); for(CGarminPolygon &line : lines) { if(line.type != type) { continue; } QPolygonF &poly = line.pixel; map->convertRad2Px(poly); // simplifyPolyline(line); p.drawPolygon(poly); if(!polygonProperties[type].known) { qDebug() << "unknown polygon" << hex << type; } } } } void CMapIMG::drawPolylines(QPainter& p, polytype_t& lines, const QPointF& scale) { textpaths.clear(); QFont font = CMainWindow::self().getMapFont(); font.setPixelSize(12); font.setBold(false); QFontMetricsF metrics(font); QVector lengths; lengths.reserve(100); /* int pixmapCount = 0; int borderCount = 0; int normalCount = 0; int imageCount = 0; int deletedCount = 0; */ QHash > dict; for(int i = 0; i < lines.count(); ++i) { dict[lines[i].type].push_back(i); } QMap::iterator props = polylineProperties.begin(); QMap::iterator end = polylineProperties.end(); for(; props != end; ++props) { const quint32 &type = props.key(); const CGarminTyp::polyline_property& property = props.value(); if(dict[type].isEmpty()) { continue; } if(property.hasPixmap) { const QImage &pixmap = CMainWindow::self().isNight() ? property.imgNight : property.imgDay; const qreal h = pixmap.height(); QList::const_iterator it = dict[type].constBegin(); for(; it != dict[type].constEnd(); ++it) { CGarminPolygon &item = lines[*it]; { //pixmapCount++; QPolygonF& poly = item.pixel; int size = poly.size(); if(size < 2) { continue; } map->convertRad2Px(poly); lengths.resize(0); // deletedCount += line.size(); // simplifyPolyline(line); // deletedCount -= line.size(); // size = line.size(); lengths.reserve(size); QPainterPath path; qreal totalLength = 0; qreal u1 = poly[0].x(); qreal v1 = poly[0].y(); for(int i = 1; i < size; ++i) { qreal u2 = poly[i].x(); qreal v2 = poly[i].y(); qreal segLength = qSqrt((u2 - u1) * (u2 - u1) + (v2 - v1) * (v2 - v1)); totalLength += segLength; lengths << segLength; u1 = u2; v1 = v2; } if (scale.x() < STREETNAME_THRESHOLD && property.labelType != CGarminTyp::eNone) { collectText(item, poly, font, metrics, h); } path.addPolygon(poly); const int nLength = lengths.count(); qreal curLength = 0; QPointF p2 = path.pointAtPercent(curLength / totalLength); for(int i = 0; i < nLength; ++i) { qreal segLength = lengths.at(i); // qDebug() << curLength << totalLength << curLength / totalLength; QPointF p1 = p2; p2 = path.pointAtPercent((curLength + segLength) / totalLength); qreal angle = qAtan((p2.y() - p1.y()) / (p2.x() - p1.x())) * 180 / M_PI; if(p2.x() - p1.x() < 0) { angle += 180; } p.save(); p.translate(p1); p.rotate(angle); p.drawImage(0,-h/2, img2line(pixmap, segLength)); //imageCount++; p.restore(); curLength += segLength; } } } } else { if(property.hasBorder) { // draw background line 1st p.setPen(CMainWindow::self().isNight() ? property.penBorderNight : property.penBorderDay); QList::const_iterator it = dict[type].constBegin(); for(; it != dict[type].constEnd(); ++it) { //borderCount++; drawLine(p, lines[*it], property, metrics, font, scale); } // draw foreground line in a second run for nicer borders } else { p.setPen(CMainWindow::self().isNight() ? property.penLineNight : property.penLineDay); QList::const_iterator it = dict[type].constBegin(); for(; it != dict[type].constEnd(); ++it) { //normalCount++; drawLine(p, lines[*it], property, metrics, font, scale); } } } } // 2nd run to draw foreground lines. props = polylineProperties.begin(); for(; props != end; ++props) { const quint32 &type = props.key(); const CGarminTyp::polyline_property& property = props.value(); if(dict[type].isEmpty()) { continue; } if(property.hasBorder && !property.hasPixmap) { // draw foreground line 2nd p.setPen(CMainWindow::self().isNight() ? property.penLineNight : property.penLineDay); QList::const_iterator it = dict[type].constBegin(); for(; it != dict[type].constEnd(); ++it) { drawLine(p, lines[*it]); } } } // qDebug() << "pixmapCount:" << pixmapCount // << "borderCount:" << borderCount // << "normalCount:" << normalCount // << "imageCount:" << imageCount // << "deletedCount:" << deletedCount; } void CMapIMG::drawLine(QPainter& p, CGarminPolygon& l, const CGarminTyp::polyline_property& property, const QFontMetricsF& metrics, const QFont& font, const QPointF& scale) { QPolygonF& poly = l.pixel; const int size = poly.size(); const int lineWidth = p.pen().width(); if(size < 2) { return; } map->convertRad2Px(poly); // simplifyPolyline(line); if (scale.x() < STREETNAME_THRESHOLD && property.labelType != CGarminTyp::eNone) { collectText(l, poly, font, metrics, lineWidth); } p.drawPolyline(poly); } void CMapIMG::drawLine(QPainter& p, const CGarminPolygon& l) { const QPolygonF& poly = l.pixel; const int size = poly.size(); if(size < 2) { return; } // simplifyPolyline(poly); p.drawPolyline(poly); } void CMapIMG::collectText(const CGarminPolygon& item, const QPolygonF& line, const QFont& font, const QFontMetricsF& metrics, qint32 lineWidth) { QString str; if(item.hasLabel()) { str = item.getLabelText(); } if(str.isEmpty()) { return; } textpath_t tp; tp.polyline = line; tp.font = font; tp.text = str; tp.lineWidth = lineWidth; const int size = line.size(); for(int i = 1; i < size; ++i) { const QPointF &p1 = line[i-1]; const QPointF &p2 = line[i]; qreal dx = p2.x() - p1.x(); qreal dy = p2.y() - p1.y(); tp.lengths << qSqrt(dx * dx + dy * dy); } textpaths << tp; } bool CMapIMG::intersectsWithExistingLabel(const QRect &rect) const { for(const strlbl_t &label : labels) { if(label.rect.intersects(rect)) { return true; } } return false; } void CMapIMG::addLabel(const CGarminPoint &pt, const QRect &rect, CGarminTyp::label_type_e type) { QString str; if(pt.hasLabel()) { str = pt.getLabelText(); } labels.push_back(strlbl_t()); strlbl_t& strlbl = labels.last(); strlbl.pt = pt.pos.toPoint(); strlbl.str = str; strlbl.rect = rect; strlbl.type = type; } void CMapIMG::drawPoints(QPainter& p, pointtype_t& pts, QVector& rectPois) { pointtype_t::iterator pt = pts.begin(); while(pt != pts.end()) { // if((pt->type > 0x1600) && (zoomFactor > CResources::self().getZoomLevelThresholdPois())) // { // ++pt; // continue; // }; map->convertRad2Px(pt->pos); const QImage& icon = CMainWindow::self().isNight() ? pointProperties[pt->type].imgNight : pointProperties[pt->type].imgDay; const QSizeF& size = icon.size(); if(isCluttered(rectPois, QRectF(pt->pos, size))) { if(size.width() <= 8 && size.height() <= 8) { p.drawImage(pt->pos.x() - (size.width()/2), pt->pos.y() - (size.height()/2), icon); } else { p.drawPixmap(pt->pos.x() - 4, pt->pos.y() - 4, QPixmap(":/icons/8x8/bullet_blue.png")); } ++pt; continue; } bool showLabel = true; if(pointProperties.contains(pt->type)) { p.drawImage(pt->pos.x() - (size.width()/2), pt->pos.y() - (size.height()/2), icon); showLabel = pointProperties[pt->type].labelType != CGarminTyp::eNone; } else { p.drawPixmap(pt->pos.x() - 4, pt->pos.y() - 4, QPixmap(":/icons/8x8/bullet_blue.png")); } if(CMainWindow::self().isPOIText() && showLabel) { // calculate bounding rectangle with a border of 2 px QRect rect = fm.boundingRect(pt->labels.join(" ")); rect.adjust(0,0,4,4); rect.moveCenter(pt->pos.toPoint()); // if no intersection was found, add label to list if(!intersectsWithExistingLabel(rect)) { addLabel(*pt, rect, CGarminTyp::eStandard); } } ++pt; } } void CMapIMG::drawPois(QPainter& p, pointtype_t& pts, QVector &rectPois) { CGarminTyp::label_type_e labelType = CGarminTyp::eStandard; for(CGarminPoint &pt : pts) { map->convertRad2Px(pt.pos); const QImage& icon = CMainWindow::self().isNight() ? pointProperties[pt.type].imgNight : pointProperties[pt.type].imgDay; const QSizeF& size = icon.size(); if(isCluttered(rectPois, QRectF(pt.pos, size))) { if(size.width() <= 8 && size.height() <= 8) { p.drawImage(pt.pos.x() - (size.width()/2), pt.pos.y() - (size.height()/2), icon); } else { p.drawPixmap(pt.pos.x() - 4, pt.pos.y() - 4, QPixmap(":/icons/8x8/bullet_blue.png")); } continue; } labelType = CGarminTyp::eStandard; if(pointProperties.contains(pt.type)) { p.drawImage(pt.pos.x() - (size.width()/2), pt.pos.y() - (size.height()/2), icon); labelType = pointProperties[pt.type].labelType; } else { p.drawPixmap(pt.pos.x() - 4, pt.pos.y() - 4, QPixmap(":/icons/8x8/bullet_red.png")); } if(CMainWindow::self().isPOIText()) { // calculate bounding rectangle with a border of 2 px QRect rect = fm.boundingRect(pt.labels.join(" ")); rect.adjust(0,0,4,4); rect.moveCenter(pt.pos.toPoint()); // if no intersection was found, add label to list if(!intersectsWithExistingLabel(rect)) { addLabel(pt, rect, labelType); } } } } void CMapIMG::drawLabels(QPainter& p, const QVector &lbls) { QFont f = CMainWindow::self().getMapFont(); QVector fonts(8, f); fonts[CGarminTyp::eSmall].setPointSize(f.pointSize() - 2); fonts[CGarminTyp::eLarge].setPointSize(f.pointSize() + 2); for(const strlbl_t &lbl : lbls) { CDraw::text(lbl.str, p, lbl.pt, Qt::black, fonts[lbl.type]); } } void CMapIMG::drawText(QPainter& p) { p.setPen(Qt::black); for(const textpath_t &textpath : textpaths) { QPainterPath path; QFont font = textpath.font; QFontMetricsF fm(font); path.addPolygon(textpath.polyline); // get path length and string length qreal length = qAbs(path.length()); qreal width = fm.width(textpath.text); // adjust font size until string fits into polyline while(width > (length * 0.7)) { font.setPixelSize(font.pixelSize() - 1); fm = QFontMetricsF(font); width = fm.width(textpath.text); if((font.pixelSize() < 8)) { break; } } // no way to draw a readable string - skip if((font.pixelSize() < 8)) { continue; } fm = QFontMetricsF(font); p.setFont(font); // adjust exact offset to first half of segment const QVector& lengths = textpath.lengths; const qreal ref = (length - width) / 2; qreal offset = 0; for(int i = 0; i < lengths.size(); ++i) { const qreal d = lengths[i]; if((offset + d/2) >= ref) { offset = ref; break; } if((offset + d) >= ref) { offset += d/2; break; } offset += d; } // get starting angle of first two letters const QString& text = textpath.text; qreal percent1 = offset / length; qreal percent2 = (offset + fm.width(text.left(2))) / length; QPointF point1 = path.pointAtPercent(percent1); QPointF point2 = path.pointAtPercent(percent2); qreal angle; // = qAtan((point2.y() - point1.y()) / (point2.x() - point1.x())) * 180 / M_PI; // flip path if string start is E->W direction // this helps, sometimes, in 50 % of the cases :) if(point2.x() - point1.x() < 0) { path = path.toReversed(); } // draw string letter by letter and adjust angle const int size = text.size(); percent2 = offset / length; point2 = path.pointAtPercent(percent2); for(int i = 0; i < size; ++i) { //percent1 = percent2; percent2 = (offset + fm.width(text[i])) / length; point1 = point2; point2 = path.pointAtPercent(percent2); angle = qAtan((point2.y() - point1.y()) / (point2.x() - point1.x())) * 180 / M_PI; if(point2.x() - point1.x() < 0) { angle += 180; } p.save(); p.translate(point1); p.rotate(angle); p.translate(0, -(textpath.lineWidth + 2)); QString str = text.mid(i,1); p.setPen(Qt::white); p.drawText(-1,-1,str); p.drawText( 0,-1,str); p.drawText(+1,-1,str); p.drawText(-1, 0,str); p.drawText(+1, 0,str); p.drawText(-1,+1,str); p.drawText( 0,+1,str); p.drawText(+1,+1,str); p.setPen(Qt::black); p.drawText( 0, 0,str); p.restore(); offset += fm.width(text[i]); } } } void CMapIMG::getToolTip(const QPoint& px, QString& infotext) const /* override */ { QString str; QMultiMap dict; getInfoPoints(points, px, dict); getInfoPoints(pois, px, dict); getInfoPolylines(px, dict); for(const QString &value : dict.values()) { if(value == "-") { continue; } if(!str.isEmpty()) { str += "\n"; } str += value; } if(str.isEmpty()) { dict.clear(); getInfoPolygons(px, dict); for(const QString &value : dict.values()) { if(value == "-") { continue; } if(!str.isEmpty()) { str += "\n"; } str += value; } } if(!infotext.isEmpty() && !str.isEmpty()) { infotext += "\n" + str; } else { infotext += str; } } void CMapIMG::findPOICloseBy(const QPoint& pt, poi_t& poi) const /*override;*/ { for(auto &list : {points, pois}) { for(const CGarminPoint &point : list) { QPoint x = pt - QPoint(point.pos.x(), point.pos.y()); if(x.manhattanLength() < 10) { poi.pos = point.pos; if(!point.labels.isEmpty()) { poi.name = point.labels.first(); poi.desc = point.getLabelText(); } else { if(pointProperties.contains(point.type)) { poi.name = pointProperties[point.type].strings[selectedLanguage != NOIDX ? selectedLanguage : 0]; } else { poi.name = QString(" (%1)").arg(point.type, 2, 16, QChar('0')); } } if(pointProperties.contains(point.type)) { poi.symbolSize = pointProperties[point.type].imgDay.size(); } else { poi.symbolSize = QSize(16,16); } return; } } } } void CMapIMG::getInfoPoints(const pointtype_t &points, const QPoint& pt, QMultiMap& dict) const { for(const CGarminPoint &point : points) { QPoint x = pt - QPoint(point.pos.x(), point.pos.y()); if(x.manhattanLength() < 10) { if(point.hasLabel()) { dict.insert(tr("Point of Interest"), point.getLabelText()); } else { if(pointProperties.contains(point.type)) { dict.insert(tr("Point of Interest"),pointProperties[point.type].strings[selectedLanguage != NOIDX ? selectedLanguage : 0]); } else { dict.insert(tr("Point of Interest"), QString(" (%1)").arg(point.type, 2, 16, QChar('0'))); } } } } } void CMapIMG::getInfoPolylines(const QPoint &pt, QMultiMap& dict) const { projXY p1, p2; // the two points of the polyline close to pt qreal u; // ratio u the tangent point will divide d_p1_p2 qreal shortest = 20; // shortest distance so far QPointF resPt = pt; QString key, value; quint32 type = 0; bool found = false; for(const CGarminPolygon &line : polylines) { int len = line.pixel.size(); // need at least 2 points if(len < 2) { continue; } // see http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ for(int i=1; i 1.0) { continue; } // coord. (x,y) of the point on line defined by [p1,p2] close to pt qreal x = p1.u + u * dx; qreal y = p1.v + u * dy; qreal distance = qSqrt((x - pt.x())*(x - pt.x()) + (y - pt.y())*(y - pt.y())); if(distance < shortest) { type = line.type; value = line.hasLabel() ? line.getLabelText() : "-"; resPt.setX(x); resPt.setY(y); shortest = distance; found = true; } } } if(!found) { return; } if(selectedLanguage != NOIDX) { key = polylineProperties[type].strings[selectedLanguage]; } if(!key.isEmpty()) { dict.insert(key + QString("(%1)").arg(type,2,16,QChar('0')),value); } else { if(polylineProperties[type].strings.isEmpty()) { dict.insert(tr("Unknown") + QString("(%1)").arg(type,2,16,QChar('0')),value); } else { dict.insert(polylineProperties[type].strings[0] + QString("(%1)").arg(type,2,16,QChar('0')),value); } } // pt = resPt.toPoint(); } void CMapIMG::getInfoPolygons(const QPoint& pt, QMultiMap& dict) const { projXY p1, p2; // the two points of the polyline close to pt const qreal x = pt.x(); const qreal y = pt.y(); for(const CGarminPolygon &line : polygons) { int npol = line.pixel.size(); if(npol > 2) { bool c = false; // see http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/ for (int i = 0, j = npol-1; i < npol; j = i++) { p1.u = line.pixel[j].x(); p1.v = line.pixel[j].y(); p2.u = line.pixel[i].x(); p2.v = line.pixel[i].y(); if ((((p2.v <= y) && (y < p1.v)) || ((p1.v <= y) && (y < p2.v))) && (x < (p1.u - p2.u) * (y - p2.v) / (p1.v - p2.v) + p2.u)) { c = !c; } } if(c) { if(line.labels.size()) { dict.insert(tr("Area"), line.labels.join(" ").simplified()); } else { if(selectedLanguage != NOIDX) { if(polygonProperties[line.type].strings[selectedLanguage].size()) { dict.insert(tr("Area"), polygonProperties[line.type].strings[selectedLanguage]); } } else { if(polygonProperties[line.type].strings[0].size()) { dict.insert(tr("Area"), polygonProperties[line.type].strings[0]); } } } } } } } static qreal getDistance(const QPolygonF& line, const QPointF& pt, qreal threshold) { qreal d = threshold + 1; const int len = line.size(); // see http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ for(int i=1; i 1.0) { continue; } // coord. (x,y) of the point on line defined by [p1,p2] close to pt qreal x = p1.x() + u * dx; qreal y = p1.y() + u * dy; qreal distance = qSqrt((x - pt.x())*(x - pt.x()) + (y - pt.y())*(y - pt.y())); if(distance < threshold) { d = threshold = distance; } } return d; } bool CMapIMG::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline) /* override */ { for(const CGarminPolygon &line : polylines) { if(line.pixel.size() < 2) { continue; } if(0x20 <= line.type && line.type <= 0x25) { continue; } qreal dist1 = ::getDistance(line.pixel, pt1, threshold); qreal dist2 = ::getDistance(line.pixel, pt2, threshold); if(dist1 < threshold && dist2 < threshold) { polyline = line.coords; threshold = qMin(dist1, dist2); } } return !polyline.isEmpty(); } qmapshack-1.10.0/src/map/CMapJNX.cpp000644 001750 000144 00000026165 13216234140 020200 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CDraw.h" #include "inttypes.h" #include "map/CMapDraw.h" #include "map/CMapJNX.h" #include "units/IUnit.h" #include static void readCString(QDataStream& stream, QByteArray& ba) { quint8 byte; ba.clear(); stream >> byte; while(byte != 0) { ba += byte; stream >> byte; } } static quint32 scale2jnx(qreal scale) { /* Ok, I've made some calculations, and got the following formula to calculate the JNX scale (S) depending on the map's meters/pixel ratio (R): S(R) = qRound( 76437 * exp( ln(2.000032708011) * qRound( ln(R * 130.2084 / 76437) / ln(2.000032708011) ) ) ) where qRound - is a function which returns the closest integer from floating point value, [unfortunately its defined in C99 but not standard C++] exp - exponent, ln - natural logarithm. Magic number 130.2084 - is an average value for (JNX scale) / (maps meters per pixel) ratio among all zoom levels in metric system. Magic number 2.000032708011 is a ratio on which our standard scale table is built. It is (76437 / 4777) ^ (1/4). */ return (quint32)qFloor(0.5 + 76437 * exp(log(2.000032708011) * qFloor(0.5 + log(scale * 10 * 130.2084 / 76437) / log(2.000032708011) ) ) ); } CMapJNX::CMapJNX(const QString &filename, CMapDraw *parent) : IMap(eFeatVisibility,parent) , filename(filename) { qDebug() << "------------------------------"; qDebug() << "JNX: try to open" << filename; qint32 productId = -1; readFile(filename, productId); pjsrc = pj_init_plus("+proj=merc +ellps=WGS84 +datum=WGS84 +units=m +no_defs +towgs84=0,0,0"); isActivated = true; } void CMapJNX::readFile(const QString& fn, qint32& productId) { hdr_t hdr; qDebug() << fn; QFile file(fn); file.open(QIODevice::ReadOnly); QDataStream stream(&file); stream.setByteOrder(QDataStream::LittleEndian); stream >> hdr.version; // byte 00000000..00000003 stream >> hdr.devid; // byte 00000004..00000007 stream >> hdr.lat1; // byte 00000008..0000000B stream >> hdr.lon2; // byte 0000000C..0000000F stream >> hdr.lat2; // byte 00000010..00000013 stream >> hdr.lon1; // byte 00000014..00000017 stream >> hdr.details; // byte 00000018..0000001B stream >> hdr.expire; // byte 0000001C..0000001F stream >> hdr.productId; // byte 00000020..00000023 stream >> hdr.crc; // byte 00000024..00000027 stream >> hdr.signature; // byte 00000028..0000002B // byte 0000002C..0000002F stream >> hdr.signature_offset; if(hdr.version > 3) { stream >> hdr.zorder; } else { hdr.zorder = -1; } if(productId != -1 && hdr.productId != productId) { return; } productId = hdr.productId; files.append(file_t()); file_t& mapFile = files.last(); mapFile.filename = fn; mapFile.lat1 = hdr.lat1 * 180.0 / 0x7FFFFFFF; mapFile.lat2 = hdr.lat2 * 180.0 / 0x7FFFFFFF; mapFile.lon1 = hdr.lon1 * 180.0 / 0x7FFFFFFF; mapFile.lon2 = hdr.lon2 * 180.0 / 0x7FFFFFFF; mapFile.bbox = QRectF(QPointF(mapFile.lon1, mapFile.lat1), QPointF(mapFile.lon2, mapFile.lat2)); qDebug() << hex << "Version:" << hdr.version << "DevId" << hdr.devid; qDebug() << mapFile.lon1 << mapFile.lat1 << mapFile.lon2 << mapFile.lat2; qDebug() << hex << hdr.lon1 << hdr.lat1 << hdr.lon2 << hdr.lat2; qDebug() << hex << "Details:" << hdr.details << "Expire:" << hdr.expire << "CRC:" << hdr.crc; qDebug() << hex << "Signature:" << hdr.signature << "Offset:" << hdr.signature_offset; QString strTopLeft, strBottomRight; IUnit::degToStr(mapFile.lon1, mapFile.lat1, strTopLeft); IUnit::degToStr(mapFile.lon2, mapFile.lat2, strBottomRight); qDebug() << "Levels:"; mapFile.levels.resize(hdr.details); for(quint32 i = 0; i < hdr.details; i++) { level_t& level = mapFile.levels[i]; stream >> level.nTiles >> level.offset >> level.scale; if(hdr.version > 3) { quint32 dummy; QTextCodec * codec = QTextCodec::codecForName("utf-8"); QByteArray ba; stream >> dummy; readCString(stream, ba); level.copyright1 = codec->toUnicode(ba); copyright += level.copyright1 + "\n"; } qDebug() << i << hex << level.nTiles << level.offset << level.scale; } quint32 infoBlockVersion; stream >> infoBlockVersion; if(infoBlockVersion == 0x9) { QTextCodec * codec = QTextCodec::codecForName("utf-8"); QByteArray ba; quint8 dummy; QString groupId; QString groupName; QString groupTitle; readCString(stream, ba); groupId = codec->toUnicode(ba); readCString(stream, ba); groupName = codec->toUnicode(ba); stream >> dummy >> dummy >> dummy; readCString(stream, ba); groupTitle = codec->toUnicode(ba); qDebug() << groupId << groupName << groupTitle; for(quint32 i = 0; i < hdr.details; i++) { level_t& level = mapFile.levels[i]; stream >> level.level; readCString(stream, ba); level.name1 = codec->toUnicode(ba); readCString(stream, ba); level.name2 = codec->toUnicode(ba); readCString(stream, ba); level.copyright2 = codec->toUnicode(ba); copyright += level.copyright2 + "\n"; } } for(quint32 i = 0; i < hdr.details; i++) { level_t& level = mapFile.levels[i]; const quint32 M = level.nTiles; file.seek(level.offset); level.tiles.resize(M); for(quint32 m = 0; m < M; m++) { qint32 top, right, bottom, left; tile_t& tile = level.tiles[m]; stream >> top >> right >> bottom >> left; stream >> tile.width >> tile.height >> tile.size >> tile.offset; tile.area.setTop(top * 180.0 / 0x7FFFFFFF); tile.area.setRight(right * 180.0 / 0x7FFFFFFF); tile.area.setBottom(bottom * 180.0 / 0x7FFFFFFF); tile.area.setLeft(left * 180.0 / 0x7FFFFFFF); } } if(mapFile.lon1 < lon1) { lon1 = mapFile.lon1; } if(mapFile.lat1 > lat1) { lat1 = mapFile.lat1; } if(mapFile.lon2 > lon2) { lon2 = mapFile.lon2; } if(mapFile.lat2 < lat2) { lat2 = mapFile.lat2; } } qint32 CMapJNX::scale2level(qreal s, const file_t& file) { qint32 idxLvl = NOIDX; quint32 actScale = scale2jnx(s); for(int i = 0; i < file.levels.size(); i++) { const level_t& level = file.levels[i]; if(actScale <= level.scale) { idxLvl = i; } } return idxLvl; } void CMapJNX::draw(IDrawContext::buffer_t& buf) /* override */ { if(map->needsRedraw()) { return; } // convert top left buffer corner // into buffer's coordinate system QPointF pp = buf.ref1; map->convertRad2Px(pp); QPointF bufferScale = buf.scale * buf.zoomFactor; qreal u1 = buf.ref1.x() * RAD_TO_DEG; qreal v1 = buf.ref1.y() * RAD_TO_DEG; qreal u2 = buf.ref3.x() * RAD_TO_DEG; qreal v2 = buf.ref3.y() * RAD_TO_DEG; QRectF viewport; viewport.setTop(v2); viewport.setRight(u2); viewport.setBottom(v1); viewport.setLeft(u1); // ----- start drawing ----- QPainter p(&buf.image); USE_ANTI_ALIASING(p,true); p.setOpacity(getOpacity()/100.0); p.translate(-pp); for(const file_t &mapFile : files) { if(!viewport.intersects(mapFile.bbox)) { continue; } if(map->needsRedraw()) { break; } qint32 level = scale2level(bufferScale.x()/5, mapFile); // no scalable level found, draw bounding box of map // derive maps corner coordinate QPolygonF l(4); l[0].rx() = mapFile.lon1 * DEG_TO_RAD; l[0].ry() = mapFile.lat1 * DEG_TO_RAD; l[1].rx() = mapFile.lon2 * DEG_TO_RAD; l[1].ry() = mapFile.lat1 * DEG_TO_RAD; l[2].rx() = mapFile.lon2 * DEG_TO_RAD; l[2].ry() = mapFile.lat2 * DEG_TO_RAD; l[3].rx() = mapFile.lon1 * DEG_TO_RAD; l[3].ry() = mapFile.lat2 * DEG_TO_RAD; map->convertRad2Px(l); // finally scale, rotate and draw tile p.setPen(Qt::black); p.setBrush(Qt::NoBrush); p.drawPolygon(l); if(level < 0) { continue; } if(isOutOfScale(bufferScale)) { continue; } QByteArray data(1024*1024*4,0); //(char) typecast needed to avoid MSVC compiler warning //in MSVC, char is a signed type. //Maybe the QByteArray declaration should be fixed ;-) data[0] = (char) 0xFF; data[1] = (char) 0xD8; char * pData = data.data() + 2; QFile file(mapFile.filename); file.open(QIODevice::ReadOnly); const QVector& tiles = mapFile.levels[level].tiles; const quint32 M = tiles.size(); for(quint32 m = 0; m < M; m++) { if(map->needsRedraw()) { break; } const tile_t& tile = tiles[m]; if(viewport.intersects(tile.area)) { QImage img; file.seek(tile.offset); file.read(pData, tile.size); img.loadFromData(data); QPolygonF l(4); l[0].rx() = tile.area.left() * DEG_TO_RAD; l[0].ry() = tile.area.top() * DEG_TO_RAD; l[1].rx() = tile.area.right() * DEG_TO_RAD; l[1].ry() = tile.area.top() * DEG_TO_RAD; l[2].rx() = tile.area.right() * DEG_TO_RAD; l[2].ry() = tile.area.bottom() * DEG_TO_RAD; l[3].rx() = tile.area.left() * DEG_TO_RAD; l[3].ry() = tile.area.bottom() * DEG_TO_RAD; drawTile(img, l, p); } } } } qmapshack-1.10.0/src/grid/000755 001750 000144 00000000000 13216664445 016451 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/grid/CProjWizard.cpp000644 001750 000144 00000016217 13216234140 021343 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "CProjWizard.h" #include "grid/mitab.h" #include #include struct mitab_entry_t { QString name; int idx; }; static bool mitabLessThan(const mitab_entry_t &s1, const mitab_entry_t &s2) { return s1.name < s2.name; } CProjWizard::CProjWizard(QLineEdit &line) : QDialog(CMainWindow::getBestWidgetForParent()) , line(line) { setupUi(this); QList list; int idx = 0; const MapInfoDatumInfo * di = asDatumInfoListQL; while(di->nMapInfoDatumID != -1) { mitab_entry_t entry; entry.name = di->pszOGCDatumName; entry.idx = idx; list << entry; ++di; ++idx; } qSort(list.begin(), list.end(), mitabLessThan); for(const mitab_entry_t &entry : list) { comboDatum->addItem(entry.name, entry.idx); } comboHemisphere->addItem(tr("north"), ""); comboHemisphere->addItem(tr("south"), "+south"); connect(radioMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(radioWorldMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(radioUPSNorth, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(radioUPSSouth, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(radioUTM, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(radioUserDef, &QRadioButton::clicked, this, &CProjWizard::slotChange); connect(lineUserDef, &QLineEdit::textChanged, this, &CProjWizard::slotChange); connect(spinUTMZone, static_cast(&QSpinBox::valueChanged), this, &CProjWizard::slotChange); connect(comboDatum, static_cast(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange); connect(comboHemisphere, static_cast(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange); QString projstr = line.text(); QRegExp re2("\\s*\\+proj=merc \\+a=6378137 \\+b=6378137 \\+lat_ts=0.001 \\+lon_0=0.0 \\+x_0=0.0 \\+y_0=0 \\+k=1.0 \\+units=m \\+nadgrids=@null \\+no_defs"); QRegExp re3("\\s*\\+proj=merc\\s(.*)"); QRegExp re4("\\s*\\+proj=utm \\+zone=([0-9]+)\\s(.*)"); if(re2.exactMatch(projstr)) { radioWorldMercator->setChecked(true); } else if(re3.exactMatch(projstr)) { radioMercator->setChecked(true); findDatum(re3.cap(1)); } else if(re4.exactMatch(projstr)) { radioUTM->setChecked(true); spinUTMZone->setValue(re4.cap(1).toInt()); QString datum = re4.cap(2); if(datum.startsWith("+south ")) { datum = datum.mid(7); comboHemisphere->setCurrentIndex(1); } findDatum(datum); } slotChange(); } CProjWizard::~CProjWizard() { } void CProjWizard::findDatum(const QString& str) { QString cmp; int idx = 0; const MapInfoDatumInfo * di = asDatumInfoListQL; while(di->nMapInfoDatumID != -1) { cmp.clear(); if(di->pszOGCDatumName != QString()) { const MapInfoSpheroidInfo * si = asSpheroidInfoList; while(si->nMapInfoId != -1) { if(si->nMapInfoId == di->nEllipsoid) { break; } ++si; } cmp += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4); cmp += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di->dfShiftX).arg(di->dfShiftY).arg(di->dfShiftZ).arg(di->dfDatumParm0).arg(di->dfDatumParm1).arg(di->dfDatumParm2).arg(di->dfDatumParm3).arg(di->dfDatumParm4); cmp += "+units=m +no_defs"; } if(cmp == str) { comboDatum->setCurrentIndex(comboDatum->findText(di->pszOGCDatumName)); break; } ++di; ++idx; } } void CProjWizard::slotChange() { QString str; if(radioMercator->isChecked()) { str += "+proj=merc "; } else if(radioWorldMercator->isChecked()) { str += "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.001 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"; labelResult->setText(str); return; } else if(radioUPSNorth->isChecked()) { str += "+init=epsg:32661"; } else if(radioUPSSouth->isChecked()) { str += "+init=epsg:32761"; } else if(radioUTM->isChecked()) { str += QString("+proj=utm +zone=%1 %2 ").arg(spinUTMZone->value()).arg(comboHemisphere->itemData(comboHemisphere->currentIndex()).toString()); } else if(radioUserDef->isChecked()) { str += lineUserDef->text() + " "; } int idx = comboDatum->itemData(comboDatum->currentIndex()).toInt(); const MapInfoDatumInfo di = asDatumInfoListQL[idx]; if(di.pszOGCDatumName != QString()) { const MapInfoSpheroidInfo * si = asSpheroidInfoList; while(si->nMapInfoId != -1) { if(si->nMapInfoId == di.nEllipsoid) { break; } ++si; } str += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4); str += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di.dfShiftX).arg(di.dfShiftY).arg(di.dfShiftZ).arg(di.dfDatumParm0).arg(di.dfDatumParm1).arg(di.dfDatumParm2).arg(di.dfDatumParm3).arg(di.dfDatumParm4); str += "+units=m +no_defs"; } labelResult->setText(str); } void CProjWizard::accept() { if (CProjWizard::validProjStr(labelResult->text())) { line.setText(labelResult->text()); line.setCursorPosition(0); QDialog::accept(); } } bool CProjWizard::validProjStr(const QString projStr) { projPJ projCheck = pj_init_plus(projStr.toUtf8().data()); if (!projCheck) { QMessageBox::warning(CMainWindow::getBestWidgetForParent(), tr("Error..."),tr("The value\n'%1'\nis not a valid coordinate system definition:\n%2").arg(projStr).arg(pj_strerrno(pj_errno)),QMessageBox::Abort,QMessageBox::Abort); return false; } else { pj_free(projCheck); return true; } } qmapshack-1.10.0/src/grid/CGrid.h000644 001750 000144 00000003474 13216234143 017606 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGRID_H #define CGRID_H #include #include #include class QPainter; class QSettings; class CMapDraw; class CGrid : public QObject { Q_OBJECT public: CGrid(CMapDraw * map); virtual ~CGrid(); void saveConfig(QSettings& cfg); void loadConfig(QSettings& cfg); void draw(QPainter& p, const QRect &rect); void setProjAndColor(const QString& proj, const QColor& c); void convertPos2Str(const QPointF& pos, QString& info, bool simple); private: friend class CGridSetup; void findGridSpace(qreal min, qreal max, qreal& xSpace, qreal& ySpace); bool calcIntersection(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4, qreal& x, qreal& y); CMapDraw * map; projPJ pjWGS84 = nullptr; projPJ pjGrid = nullptr; QString projstr = "+proj=longlat +datum=WGS84 +no_defs"; QColor color = Qt::magenta; }; #endif //CGRID_H qmapshack-1.10.0/src/grid/CGridSetup.h000644 001750 000144 00000002630 13216234143 020620 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CGRIDSETUP_H #define CGRIDSETUP_H #include "ui_IGridSetup.h" #include class CGrid; class CMapDraw; class CGridSetup : public QDialog, private Ui::IGridSetup { Q_OBJECT public: CGridSetup(CGrid * grid, CMapDraw *map); virtual ~CGridSetup(); public slots: void accept() override; private slots: void slotProjWizard(); void slotSelectGridColor(); void slotRestoreDefault(); void slotProjFromMap(); private: CGrid * grid; CMapDraw * map; }; #endif //CGRIDSETUP_H qmapshack-1.10.0/src/grid/CGridSetup.cpp000644 001750 000144 00000005533 13216234140 021155 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "grid/CGrid.h" #include "grid/CGridSetup.h" #include "grid/CProjWizard.h" #include "map/CMapDraw.h" #include CGridSetup::CGridSetup(CGrid *grid, CMapDraw * map) : QDialog(CMainWindow::getBestWidgetForParent()) , grid(grid) , map(map) { setupUi(this); lineProjection->setText(grid->projstr); lineProjection->setCursorPosition(0); QPalette palette = labelGridColor->palette(); palette.setColor(labelGridColor->foregroundRole(), grid->color); labelGridColor->setPalette(palette); connect(toolRestoreDefault, &QToolButton::clicked, this, &CGridSetup::slotRestoreDefault); connect(toolFromMap, &QToolButton::clicked, this, &CGridSetup::slotProjFromMap); connect(toolProjWizzard, &QToolButton::clicked, this, &CGridSetup::slotProjWizard); connect(toolGridColor, &QToolButton::clicked, this, &CGridSetup::slotSelectGridColor); } CGridSetup::~CGridSetup() { } void CGridSetup::accept() { if (CProjWizard::validProjStr(lineProjection->text())) { QPalette palette = labelGridColor->palette(); grid->setProjAndColor(lineProjection->text(), palette.color(labelGridColor->foregroundRole())); QDialog::accept(); } } void CGridSetup::slotProjWizard() { CProjWizard dlg(*lineProjection); dlg.exec(); } void CGridSetup::slotSelectGridColor() { QPalette palette = labelGridColor->palette(); QColor color = palette.color(labelGridColor->foregroundRole()); color = QColorDialog::getColor(color, this); if(color.isValid()) { palette.setColor(labelGridColor->foregroundRole(), color); labelGridColor->setPalette(palette); } } void CGridSetup::slotRestoreDefault() { lineProjection->setText("+proj=longlat +datum=WGS84 +no_defs"); lineProjection->setCursorPosition(0); } void CGridSetup::slotProjFromMap() { lineProjection->setText(map->getProjection()); lineProjection->setCursorPosition(0); } qmapshack-1.10.0/src/grid/IGridSetup.ui000644 001750 000144 00000014156 12374350216 021026 0ustar00oeichlerxusers000000 000000 IGridSetup 0 0 446 140 Setup Grid... Projection 32 32 restore default ... :/icons/32x32/Reset.png:/icons/32x32/Reset.png 22 22 32 32 Get projection from current map. ... :/icons/32x32/FromMap.png:/icons/32x32/FromMap.png 22 22 32 32 projection wizzard ... :/icons/32x32/GridWizzard.png:/icons/32x32/GridWizzard.png 22 22 Qt::Horizontal 40 20 75 true Grid color 32 32 setup grid color ... :/icons/32x32/SelectColor.png:/icons/32x32/SelectColor.png 22 22 Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IGridSetup accept() 248 254 157 274 buttonBox rejected() IGridSetup reject() 316 260 286 274 qmapshack-1.10.0/src/grid/CProjWizard.h000644 001750 000144 00000002524 13216234143 021007 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CPROJWIZARD_H #define CPROJWIZARD_H #include "ui_IProjWizard.h" #include class CProjWizard : public QDialog, private Ui::IProjWizard { Q_OBJECT public: CProjWizard(QLineEdit& line); virtual ~CProjWizard(); static bool validProjStr(const QString projStr); public slots: void accept() override; void slotChange(); private: void findDatum(const QString& str); QLineEdit& line; }; #endif //CPROJWIZARD_H qmapshack-1.10.0/src/grid/IProjWizard.ui000644 001750 000144 00000012555 12705713523 021216 0ustar00oeichlerxusers000000 000000 IProjWizard 0 0 440 280 Proj4 Wizzard QFrame::StyledPanel QFrame::Raised Mercator UTM zone 1 60 Qt::Horizontal 40 20 user defined Datum World Mercator (OSM) Qt::Vertical 20 40 Result: UPS North (North Pole) UPS South (South Pole) Projection Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() IProjWizard accept() 248 254 157 274 buttonBox rejected() IProjWizard reject() 316 260 286 274 qmapshack-1.10.0/src/grid/mitab.h000644 001750 000144 00000003252 13216234143 017704 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef MITAB_H #define MITAB_H struct MapInfoDatumInfo { int nMapInfoDatumID; const char *pszOGCDatumName; int nEllipsoid; double dfShiftX; double dfShiftY; double dfShiftZ; double dfDatumParm0; /* RotX */ double dfDatumParm1; /* RotY */ double dfDatumParm2; /* RotZ */ double dfDatumParm3; /* Scale Factor */ double dfDatumParm4; /* Prime Meridian */ }; struct MapInfoSpheroidInfo { int nMapInfoId; const char *pszMapinfoName; double dfA; /* semi major axis in meters */ double dfInvFlattening; /* Inverse flattening */ }; extern const MapInfoDatumInfo asDatumInfoListQL[]; extern const MapInfoSpheroidInfo asSpheroidInfoList[]; #endif //MITAB_H qmapshack-1.10.0/src/grid/CGrid.cpp000644 001750 000144 00000026677 13216234140 020150 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "grid/CGrid.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "map/CMapDraw.h" #include CGrid::CGrid(CMapDraw *map) : QObject(map) , map(map) { pjWGS84 = pj_init_plus("+proj=longlat +datum=WGS84 +no_defs"); setProjAndColor(projstr, color); } CGrid::~CGrid() { pj_free(pjWGS84); pj_free(pjGrid); } void CGrid::convertPos2Str(const QPointF& pos, QString& info, bool simple) { if(pjGrid == nullptr) { return; } QPointF pt = pos * DEG_TO_RAD; pj_transform(pjWGS84, pjGrid, 1, 0, &pt.rx(), &pt.ry(), 0); if(pj_is_latlong(pjGrid)) { QString lat,lng; pt *= RAD_TO_DEG; lat = pt.y() < 0 ? "S" : "N"; lng = pt.x() < 0 ? "W" : "E"; if(simple) { info += tr("%1 %2 ").arg(pt.y(), 0, 'f', 6).arg(pt.x(), 0, 'f', 6); } else { info += tr("%1%2%5 %3%4%5 ").arg(lat).arg(qAbs(pt.y()), 0, 'f', 6).arg(lng).arg(qAbs(pt.x()), 0, 'f', 6).arg(QChar('\260')); } } else { if(simple) { info += tr("%1m, %2m ").arg(pt.y(),0,'f',0).arg(pt.x(),0,'f',0); } else { info += tr("N %1m, E %2m ").arg(pt.y(),0,'f',0).arg(pt.x(),0,'f',0); } } } void CGrid::saveConfig(QSettings& cfg) { cfg.setValue("grid/color", color.name()); cfg.setValue("grid/proj", projstr); } void CGrid::loadConfig(QSettings& cfg) { color = QColor(cfg.value("grid/color", color.name()).toString()); projstr = cfg.value("grid/proj", projstr).toString(); setProjAndColor(projstr, color); } void CGrid::setProjAndColor(const QString& proj, const QColor& c) { projstr = proj; color = c; if(nullptr != pjGrid) { pj_free(pjGrid); } pjGrid = pj_init_plus(projstr.toLatin1()); } void CGrid::findGridSpace(qreal min, qreal max, qreal& xSpace, qreal& ySpace) { qreal dX = qAbs(min - max) / 10; if(dX < M_PI/180000) { xSpace = 5*M_PI/1800000; ySpace = 5*M_PI/1800000; } else if(dX < M_PI/18000) { xSpace = 5*M_PI/180000; ySpace = 5*M_PI/180000; } else if(dX < M_PI/1800) { xSpace = 5*M_PI/18000; ySpace = 5*M_PI/18000; } else if(dX < M_PI/180) { xSpace = 5*M_PI/1800; ySpace = 5*M_PI/1800; } else if(dX < M_PI/18) { xSpace = 5*M_PI/180; ySpace = 5*M_PI/180; } else if(dX < M_PI/1.8) { xSpace = 5*M_PI/180; ySpace = 5*M_PI/180; } else if(dX < 3000) { xSpace = 1000; ySpace = 1000; } else if(dX < 7000) { xSpace = 5000; ySpace = 5000; } else if(dX < 30000) { xSpace = 10000; ySpace = 10000; } else if(dX < 70000) { xSpace = 50000; ySpace = 50000; } else if(dX < 300000) { xSpace = 100000; ySpace = 100000; } else if(dX < 700000) { xSpace = 500000; ySpace = 500000; } else if(dX < 3000000) { xSpace = 1000000; ySpace = 1000000; } else if(dX < 7000000) { xSpace = 5000000; ySpace = 5000000; } else if(dX < 30000000) { xSpace = 10000000; ySpace = 10000000; } else if(dX < 70000000) { xSpace = 50000000; ySpace = 50000000; } } bool CGrid::calcIntersection(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4, qreal& x, qreal& y) { qreal ua = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3))/((y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1)); x = x1 + ua * (x2 - x1); y = y1 + ua * (y2 - y1); qreal d12 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); qreal d1x = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y); qreal d2x = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); qreal d34 = (x4 - x3) * (x4 - x3) + (y4 - y3) * (y4 - y3); qreal d3x = (x3 - x) * (x3 - x) + (y3 - y) * (y3 - y); qreal d4x = (x4 - x) * (x4 - x) + (y4 - y) * (y4 - y); return (d12 >= d1x) && (d12 >= d2x) && (d34 >= d3x) && (d34 >= d4x); } struct val_t { val_t(qint32 pos, qreal val) : pos(pos), val(val) { } qint32 pos; qreal val; }; void CGrid::draw(QPainter& p, const QRect& rect) { if(pjWGS84 == nullptr || pjGrid == nullptr || !CMainWindow::self().isGridVisible()) { return; } QPointF topLeft = rect.topLeft(); QPointF topRight = rect.topRight(); QPointF btmLeft = rect.bottomLeft(); QPointF btmRight = rect.bottomRight(); map->convertPx2Rad(topLeft); map->convertPx2Rad(topRight); map->convertPx2Rad(btmLeft); map->convertPx2Rad(btmRight); pj_transform(pjWGS84, pjGrid, 1, 0, &topLeft.rx(), &topLeft.ry(), 0); pj_transform(pjWGS84, pjGrid, 1, 0, &topRight.rx(), &topRight.ry(), 0); pj_transform(pjWGS84, pjGrid, 1, 0, &btmLeft.rx(), &btmLeft.ry(), 0); pj_transform(pjWGS84, pjGrid, 1, 0, &btmRight.rx(), &btmRight.ry(), 0); // qDebug() << "---"; // qDebug() << "topLeft " << topLeft.u << topLeft.v; // qDebug() << "topRight" << topRight.u << topRight.v; // qDebug() << "btmLeft " << btmLeft.u << btmLeft.v; // qDebug() << "btmRight" << btmRight.u << btmRight.v; // qDebug() << topLeft.u - topRight.u; // qDebug() << btmLeft.u - btmRight.u; // qDebug() << topLeft.v - btmLeft.v; // qDebug() << topRight.v - btmRight.v; qreal topMax = qMax(topLeft.y(), topRight.y()); qreal btmMin = qMin(btmLeft.y(), btmRight.y()); qreal leftMin = qMin(topLeft.x(), btmLeft.x()); qreal rightMax = qMax(topRight.x(), btmRight.x()); qreal xGridSpace = 1000; qreal yGridSpace = 1000; findGridSpace(leftMin, rightMax, xGridSpace, yGridSpace); qreal xStart = qFloor(leftMin / xGridSpace) * xGridSpace; qreal yStart = qCeil(topMax / yGridSpace) * yGridSpace; qreal x = xStart - xGridSpace; qreal y = yStart + yGridSpace; if(pj_is_latlong(pjGrid)) { if(y > (85*DEG_TO_RAD)) { y = (85*DEG_TO_RAD); } if(btmMin < -(85*DEG_TO_RAD - yGridSpace)) { btmMin = -(85*DEG_TO_RAD - yGridSpace); } if(x > rightMax) { if(qAbs(x) > qAbs(rightMax)) { xStart = x = -180 * DEG_TO_RAD; } if(qAbs(x) < qAbs(rightMax)) { rightMax = 180 * DEG_TO_RAD; } } } QList< val_t > horzTopTicks; QList< val_t > horzBtmTicks; QList< val_t > vertLftTicks; QList< val_t > vertRgtTicks; p.save(); p.setBrush(Qt::NoBrush); p.setPen(QPen(color,1)); USE_ANTI_ALIASING(p,false); qreal h = rect.height(); qreal w = rect.width(); while(y > btmMin) { while(x < rightMax) { QPointF p1(x, y); QPointF p2(x + xGridSpace, y); QPointF p3(x + xGridSpace, y - yGridSpace); QPointF p4(x, y - yGridSpace); qreal xVal = p1.x(); qreal yVal = p1.y(); pj_transform(pjGrid, pjWGS84, 1, 0, &p1.rx(), &p1.ry(), 0); pj_transform(pjGrid, pjWGS84, 1, 0, &p2.rx(), &p2.ry(), 0); pj_transform(pjGrid, pjWGS84, 1, 0, &p3.rx(), &p3.ry(), 0); pj_transform(pjGrid, pjWGS84, 1, 0, &p4.rx(), &p4.ry(), 0); // qDebug() << (p1 * RAD_TO_DEG) << (p2 * RAD_TO_DEG) << (p3 * RAD_TO_DEG) << (p4 * RAD_TO_DEG); map->convertRad2Px(p1); map->convertRad2Px(p2); map->convertRad2Px(p3); map->convertRad2Px(p4); qreal xx,yy; if(calcIntersection(0,0,w,0, p1.x(), p1.y(), p4.x(), p4.y(), xx, yy)) { horzTopTicks << val_t(xx, xVal); } if(calcIntersection(0,h,w,h, p1.x(), p1.y(), p4.x(), p4.y(), xx, yy)) { horzBtmTicks << val_t(xx, xVal); } if(calcIntersection(0,0,0,h, p1.x(), p1.y(), p2.x(), p2.y(), xx, yy)) { vertLftTicks << val_t(yy, yVal); } if(calcIntersection(w,0,w,h, p1.x(), p1.y(), p2.x(), p2.y(), xx, yy)) { vertRgtTicks << val_t(yy, yVal); } p.drawLine(p1, p2); p.drawLine(p2, p3); p.drawLine(p3, p4); p.drawLine(p4, p1); x += xGridSpace; } x = xStart; y -= yGridSpace; } USE_ANTI_ALIASING(p,true); p.restore(); QColor textColor; textColor.setHsv(color.hslHue(), color.hsvSaturation(), (color.value()>128 ? color.value()-128 : 0)); if(pj_is_latlong(pjGrid)) { QFontMetrics fm(CMainWindow::self().getMapFont()); int yoff = fm.height() + fm.ascent(); int xoff = fm.width("XX.XXXX")>>1; for(const val_t &val : horzTopTicks) { CDraw::text(qAbs(val.val)<1.e-5 ? "0" : QString("%1%2").arg(val.val * RAD_TO_DEG).arg(QChar(0260)), p, QPoint(val.pos, yoff), textColor); } for(const val_t &val : horzBtmTicks) { CDraw::text(qAbs(val.val)<1.e-5 ? "0" : QString("%1%2").arg(val.val * RAD_TO_DEG).arg(QChar(0260)), p, QPoint(val.pos, h), textColor); } for(const val_t &val : vertLftTicks) { CDraw::text(qAbs(val.val)<1.e-5 ? "0" : QString("%1%2").arg(val.val * RAD_TO_DEG).arg(QChar(0260)), p, QPoint(xoff, val.pos), textColor); } for(const val_t &val : vertRgtTicks) { CDraw::text(qAbs(val.val)<1.e-5 ? "0" : QString("%1%2").arg(val.val * RAD_TO_DEG).arg(QChar(0260)), p, QPoint(w - xoff, val.pos), textColor); } } else { QFontMetrics fm(CMainWindow::self().getMapFont()); int yoff = fm.height() + fm.ascent(); int xoff = fm.width("XXXX")>>1; for(const val_t &val : horzTopTicks) { CDraw::text(QString("%1").arg(qint32(val.val/1000)), p, QPoint(val.pos, yoff), textColor); } for(const val_t &val : horzBtmTicks) { CDraw::text(QString("%1").arg(qint32(val.val/1000)), p, QPoint(val.pos, h), textColor); } for(const val_t &val : vertLftTicks) { CDraw::text(QString("%1").arg(qint32(val.val/1000)), p, QPoint(xoff, val.pos), textColor); } for(const val_t &val : vertRgtTicks) { CDraw::text(QString("%1").arg(qint32(val.val/1000)), p, QPoint(w - xoff, val.pos), textColor); } } } qmapshack-1.10.0/src/grid/mitab.cpp000644 001750 000144 00000045134 13216234140 020241 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de 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 "mitab.h" const MapInfoDatumInfo asDatumInfoListQL[] = { { // Datum ignore 0, "", 29, 0, 0, 0, 0, 0, 0, 0, 0 }, {74, "North_American_Datum_1983", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, "Adindan", 6, -162, -12, 206, 0, 0, 0, 0, 0}, {2, "Afgooye", 3, -43, -163, 45, 0, 0, 0, 0, 0}, {3, "Ain_el_Abd_1970", 4, -150, -251, -2, 0, 0, 0, 0, 0}, {4, "Anna_1_Astro_1965", 2, -491, -22, 435, 0, 0, 0, 0, 0}, {5, "Arc_1950", 15,-143, -90, -294,0, 0, 0, 0, 0}, {6, "Arc_1960", 6, -160, -8, -300,0, 0, 0, 0, 0}, {7, "Ascension_Islands", 4, -207, 107, 52, 0, 0, 0, 0, 0}, {8, "Astro_Beacon_E", 4, 145, 75, -272,0, 0, 0, 0, 0}, {9, "Astro_B4_Sorol_Atoll", 4, 114, -116, -333,0, 0, 0, 0, 0}, {10, "Astro_Dos_71_4", 4, -320, 550, -494,0, 0, 0, 0, 0}, {11, "Astronomic_Station_1952", 4, 124, -234, -25, 0, 0, 0, 0, 0}, {12, "Australian_Geodetic_Datum_66",2, -133, -48, 148, 0, 0, 0, 0, 0}, {13, "Australian_Geodetic_Datum_84",2, -134, -48, 149, 0, 0, 0, 0, 0}, {14, "Bellevue_Ign", 4, -127, -769, 472, 0, 0, 0, 0, 0}, {15, "Bermuda_1957", 7, -73, 213, 296, 0, 0, 0, 0, 0}, {16, "Bogota", 4, 307, 304, -318,0, 0, 0, 0, 0}, {17, "Campo_Inchauspe", 4, -148, 136, 90, 0, 0, 0, 0, 0}, {18, "Canton_Astro_1966", 4, 298, -304, -375,0, 0, 0, 0, 0}, {19, "Cape", 6, -136, -108, -292,0, 0, 0, 0, 0}, {20, "Cape_Canaveral", 7, -2, 150, 181, 0, 0, 0, 0, 0}, {21, "Carthage", 6, -263, 6, 431, 0, 0, 0, 0, 0}, {22, "Chatham_1971", 4, 175, -38, 113, 0, 0, 0, 0, 0}, {23, "Chua", 4, -134, 229, -29, 0, 0, 0, 0, 0}, {24, "Corrego_Alegre", 4, -206, 172, -6, 0, 0, 0, 0, 0}, {25, "Batavia", 10,-377,681, -50, 0, 0, 0, 0, 0}, {26, "Dos_1968", 4, 230, -199, -752,0, 0, 0, 0, 0}, {27, "Easter_Island_1967", 4, 211, 147, 111, 0, 0, 0, 0, 0}, {28, "European_Datum_1950", 4, -87, -98, -121,0, 0, 0, 0, 0}, {29, "European_Datum_1979", 4, -86, -98, -119,0, 0, 0, 0, 0}, {30, "Gandajika_1970", 4, -133, -321, 50, 0, 0, 0, 0, 0}, {31, "New_Zealand_GD49", 4, 84, -22, 209, 0, 0, 0, 0, 0}, {32, "GRS_67", 21,0, 0, 0, 0, 0, 0, 0, 0}, {33, "GRS_80", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {34, "Guam_1963", 7, -100, -248, 259, 0, 0, 0, 0, 0}, {35, "Gux_1_Astro", 4, 252, -209, -751,0, 0, 0, 0, 0}, {36, "Hito_XVIII_1963", 4, 16, 196, 93, 0, 0, 0, 0, 0}, {37, "Hjorsey_1955", 4, -73, 46, -86, 0, 0, 0, 0, 0}, {38, "Hong_Kong_1963", 4, -156, -271, -189,0, 0, 0, 0, 0}, {39, "Hu_Tzu_Shan", 4, -634, -549, -201,0, 0, 0, 0, 0}, {40, "Indian_Thailand_Vietnam", 11,214, 836, 303, 0, 0, 0, 0, 0}, {41, "Indian_Bangladesh", 11,289, 734, 257, 0, 0, 0, 0, 0}, {42, "Ireland_1965", 13,506, -122, 611, 0, 0, 0, 0, 0}, {43, "ISTS_073_Astro_1969", 4, 208, -435, -229,0, 0, 0, 0, 0}, {44, "Johnston_Island_1961", 4, 191, -77, -204,0, 0, 0, 0, 0}, {45, "Kandawala", 11,-97, 787, 86, 0, 0, 0, 0, 0}, {46, "Kerguyelen_Island", 4, 145, -187, 103, 0, 0, 0, 0, 0}, {47, "Kertau", 17,-11, 851, 5, 0, 0, 0, 0, 0}, {48, "L_C_5_Astro", 7, 42, 124, 147, 0, 0, 0, 0, 0}, {49, "Liberia_1964", 6, -90, 40, 88, 0, 0, 0, 0, 0}, {50, "Luzon_Phillippines", 7, -133, -77, -51, 0, 0, 0, 0, 0}, {51, "Luzon_Mindanao_Island", 7, -133, -79, -72, 0, 0, 0, 0, 0}, {52, "Mahe_1971", 6, 41, -220, -134,0, 0, 0, 0, 0}, {53, "Marco_Astro", 4, -289, -124, 60, 0, 0, 0, 0, 0}, {54, "Massawa", 10,639, 405, 60, 0, 0, 0, 0, 0}, {55, "Merchich", 16,31, 146, 47, 0, 0, 0, 0, 0}, {56, "Midway_Astro_1961", 4, 912, -58, 1227,0, 0, 0, 0, 0}, {57, "Minna", 6, -92, -93, 122, 0, 0, 0, 0, 0}, {58, "Nahrwan_Masirah_Island", 6, -247, -148, 369, 0, 0, 0, 0, 0}, {59, "Nahrwan_Un_Arab_Emirates", 6, -249, -156, 381, 0, 0, 0, 0, 0}, {60, "Nahrwan_Saudi_Arabia", 6, -231, -196, 482, 0, 0, 0, 0, 0}, {61, "Naparima_1972", 4, -2, 374, 172, 0, 0, 0, 0, 0}, {62, "NAD_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0}, {62, "North_American_Datum_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0}, {63, "NAD_27_Alaska", 7, -5, 135, 172, 0, 0, 0, 0, 0}, {64, "NAD_27_Bahamas", 7, -4, 154, 178, 0, 0, 0, 0, 0}, {65, "NAD_27_San_Salvador", 7, 1, 140, 165, 0, 0, 0, 0, 0}, {66, "NAD_27_Canada", 7, -10, 158, 187, 0, 0, 0, 0, 0}, {67, "NAD_27_Canal_Zone", 7, 0, 125, 201, 0, 0, 0, 0, 0}, {68, "NAD_27_Caribbean", 7, -7, 152, 178, 0, 0, 0, 0, 0}, {69, "NAD_27_Central_America", 7, 0, 125, 194, 0, 0, 0, 0, 0}, {70, "NAD_27_Cuba", 7, -9, 152, 178, 0, 0, 0, 0, 0}, {71, "NAD_27_Greenland", 7, 11, 114, 195, 0, 0, 0, 0, 0}, {72, "NAD_27_Mexico", 7, -12, 130, 190, 0, 0, 0, 0, 0}, {73, "NAD_27_Michigan", 8, -8, 160, 176, 0, 0, 0, 0, 0}, {75, "Observatorio_1966", 4, -425, -169, 81, 0, 0, 0, 0, 0}, {76, "Old_Egyptian", 22,-130, 110, -13, 0, 0, 0, 0, 0}, {77, "Old_Hawaiian", 7, 61, -285, -181,0, 0, 0, 0, 0}, {78, "Oman", 6, -346, -1, 224, 0, 0, 0, 0, 0}, {79, "OSGB_1936", 9, 375, -111, 431, 0, 0, 0, 0, 0}, {80, "Pico_De_Las_Nieves", 4, -307, -92, 127, 0, 0, 0, 0, 0}, {81, "Pitcairn_Astro_1967", 4, 185, 165, 42, 0, 0, 0, 0, 0}, {82, "Provisional_South_American", 4, -288, 175, -376,0, 0, 0, 0, 0}, {83, "Puerto_Rico", 7, 11, 72, -101,0, 0, 0, 0, 0}, {84, "Qatar_National", 4, -128, -283, 22, 0, 0, 0, 0, 0}, {85, "Qornoq", 4, 164, 138, -189, 0, 0, 0, 0, 0}, {86, "Reunion", 4, 94, -948,-1262,0, 0, 0, 0, 0}, {87, "Monte_Mario", 4, -225, -65, 9, 0, 0, 0, 0, 0}, {88, "Santo_Dos", 4, 170, 42, 84, 0, 0, 0, 0, 0}, {89, "Sao_Braz", 4, -203, 141, 53, 0, 0, 0, 0, 0}, {90, "Sapper_Hill_1943", 4, -355, 16, 74, 0, 0, 0, 0, 0}, {91, "Schwarzeck", 14,616, 97, -251, 0, 0, 0, 0, 0}, {92, "South_American_Datum_1969", 24,-57, 1, -41, 0, 0, 0, 0, 0}, {93, "South_Asia", 19,7, -10, -26, 0, 0, 0, 0, 0}, {94, "Southeast_Base", 4, -499, -249,314, 0, 0, 0, 0, 0}, {95, "Southwest_Base", 4, -104, 167, -38, 0, 0, 0, 0, 0}, {96, "Timbalai_1948", 11,-689, 691, -46, 0, 0, 0, 0, 0}, {97, "Tokyo", 10,-128, 481, 664, 0, 0, 0, 0, 0}, {98, "Tristan_Astro_1968", 4, -632, 438, -609, 0, 0, 0, 0, 0}, {99, "Viti_Levu_1916", 6, 51, 391, -36, 0, 0, 0, 0, 0}, {100, "Wake_Entiwetok_1960", 23,101, 52, -39, 0, 0, 0, 0, 0}, {101, "WGS_60", 26,0, 0, 0, 0, 0, 0, 0, 0}, {102, "WGS_66", 27,0, 0, 0, 0, 0, 0, 0, 0}, {103, "WGS_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0}, {104, "WGS_1984", 28,0, 0, 0, 0, 0, 0, 0, 0}, {105, "Yacare", 4, -155, 171, 37, 0, 0, 0, 0, 0}, {106, "Zanderij", 4, -265, 120, -358, 0, 0, 0, 0, 0}, {107, "NTF", 30,-168, -60, 320, 0, 0, 0, 0, 0}, {108, "European_Datum_1987", 4, -83, -96, -113, 0, 0, 0, 0, 0}, {109, "Netherlands_Bessel", 10,593, 26, 478, 0, 0, 0, 0, 0}, {110, "Belgium_Hayford", 4, 81, 120, 129, 0, 0, 0, 0, 0}, {111, "NWGL_10", 1, -1, 15, 1, 0, 0, 0, 0, 0}, {112, "Rikets_koordinatsystem_1990",10,498, -36, 568, 0, 0, 0, 0, 0}, {113, "Lisboa_DLX", 4, -303, -62, 105, 0, 0, 0, 0, 0}, {114, "Melrica_1973_D73", 4, -223, 110, 37, 0, 0, 0, 0, 0}, {115, "Euref_98", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {116, "GDA94", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {117, "NZGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {118, "America_Samoa", 7, -115, 118, 426, 0, 0, 0, 0, 0}, {119, "Antigua_Astro_1965", 6, -270, 13, 62, 0, 0, 0, 0, 0}, {120, "Ayabelle_Lighthouse", 6, -79, -129, 145, 0, 0, 0, 0, 0}, {121, "Bukit_Rimpah", 10,-384, 664, -48, 0, 0, 0, 0, 0}, {122, "Estonia_1937", 10,374, 150, 588, 0, 0, 0, 0, 0}, {123, "Dabola", 6, -83, 37, 124, 0, 0, 0, 0, 0}, {124, "Deception_Island", 6, 260, 12, -147, 0, 0, 0, 0, 0}, {125, "Fort_Thomas_1955", 6, -7, 215, 225, 0, 0, 0, 0, 0}, {126, "Graciosa_base_1948", 4, -104, 167, -38, 0, 0, 0, 0, 0}, {127, "Herat_North", 4, -333, -222,114, 0, 0, 0, 0, 0}, {128, "Hermanns_Kogel", 10,682, -203, 480, 0, 0, 0, 0, 0}, {129, "Indian", 50,283, 682, 231, 0, 0, 0, 0, 0}, {130, "Indian_1954", 11,217, 823, 299, 0, 0, 0, 0, 0}, {131, "Indian_1960", 11,198, 881, 317, 0, 0, 0, 0, 0}, {132, "Indian_1975", 11,210, 814, 289, 0, 0, 0, 0, 0}, {133, "Indonesian_Datum_1974", 4, -24, -15, 5, 0, 0, 0, 0, 0}, {134, "ISTS061_Astro_1968", 4, -794, 119, -298, 0, 0, 0, 0, 0}, {135, "Kusaie_Astro_1951", 4, 647, 1777, -1124,0, 0, 0, 0, 0}, {136, "Leigon", 6, -130, 29, 364, 0, 0, 0, 0, 0}, {137, "Montserrat_Astro_1958", 6, 174, 359, 365, 0, 0, 0, 0, 0}, {138, "Mporaloko", 6, -74, -130, 42, 0, 0, 0, 0, 0}, {139, "North_Sahara_1959", 6, -186, -93, 310, 0, 0, 0, 0, 0}, {140, "Observatorio_Met_1939", 4, -425, -169,81, 0, 0, 0, 0, 0}, {141, "Point_58", 6, -106, -129,165, 0, 0, 0, 0, 0}, {142, "Pointe_Noire", 6, -148, 51, -291, 0, 0, 0, 0, 0}, {143, "Porto_Santo_1936", 4, -499, -249,314, 0, 0, 0, 0, 0}, {144, "Selvagem_Grande_1938", 4, -289, -124,60, 0, 0, 0, 0, 0}, {145, "Sierra_Leone_1960", 6, -88, 4, 101, 0, 0, 0, 0, 0}, {146, "S_JTSK_Ferro", 10, 589, 76, 480, 0, 0, 0, 0, 0}, {147, "Tananarive_1925", 4, -189, -242,-91, 0, 0, 0, 0, 0}, {148, "Voirol_1874", 6, -73, -247,227, 0, 0, 0, 0, 0}, {149, "Virol_1960", 6, -123, -206,219, 0, 0, 0, 0, 0}, {150, "Hartebeesthoek94", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {151, "ATS77", 51, 0, 0, 0, 0, 0, 0, 0, 0}, {152, "JGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1000,"DHDN_Potsdam_Rauenberg", 10,582, 105, 414, -1.04, -0.35, 3.08, 8.3, 0}, {1001,"Pulkovo_1942", 3, 24, -123, -94, -0.02, 0.25, 0.13, 1.1, 0}, {1002,"NTF_Paris_Meridian", 30,-168, -60, 320, 0, 0, 0, 0, 2.337229166667}, {1003,"Switzerland_CH_1903", 10,660.077,13.551, 369.344, 0.804816, 0.577692, 0.952236, 5.66,0}, {1004,"Hungarian_Datum_1972", 21,-56, 75.77, 15.31, -0.37, -0.2, -0.21, -1.01, 0}, {1005,"Cape_7_Parameter", 28,-134.73,-110.92, -292.66, 0, 0, 0, 1, 0}, {1006,"AGD84_7_Param_Aust", 2, -117.763,-51.51, 139.061, -0.292, -0.443, -0.277, -0.191, 0}, {1007,"AGD66_7_Param_ACT", 2, -129.193,-41.212, 130.73, -0.246, -0.374, -0.329, -2.955, 0}, {1008,"AGD66_7_Param_TAS", 2, -120.271,-64.543, 161.632, -0.2175, 0.0672, 0.1291, 2.4985, 0}, {1009,"AGD66_7_Param_VIC_NSW", 2, -119.353,-48.301, 139.484, -0.415, -0.26, -0.437, -0.613, 0}, {1010,"NZGD_7_Param_49", 4, 59.47, -5.04, 187.44, -0.47, 0.1, -1.024, -4.5993, 0}, {1011,"Rikets_Tri_7_Param_1990", 10,419.3836, 99.3335, 591.3451, -0.850389, -1.817277, 7.862238, -0.99496, 0}, {1012,"Russia_PZ90", 52, -1.08,-0.27,-0.9,0, 0, -0.16,-0.12, 0}, {1013,"Russia_SK42", 52, 23.92,-141.27,-80.9, 0, -0.35,-0.82, -0.12, 0}, {1014,"Russia_SK95", 52, 24.82,-131.21,-82.66,0,0,-0.16,-0.12, 0}, {1015,"Tokyo", 10, -146.414, 507.337, 680.507,0,0,0,0,0}, {1016,"Finnish_KKJ", 4, -96.062, -82.428, -121.754, -4.801, -0.345, 1.376, 1.496, 0}, {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; /* -------------------------------------------------------------------- */ /* This table was hand entered from Appendix I of the mapinfo 6 */ /* manuals. */ /* -------------------------------------------------------------------- */ const MapInfoSpheroidInfo asSpheroidInfoList[] = { { 9,"Airy 1930", 6377563.396, 299.3249646}, {13,"Airy 1930 (modified for Ireland 1965", 6377340.189, 299.3249646}, {51,"ATS77 (Average Terrestrial System 1977)", 6378135, 298.257}, { 2,"Australian", 6378160.0, 298.25}, {10,"Bessel 1841", 6377397.155, 299.1528128}, {35,"Bessel 1841 (modified for NGO 1948)", 6377492.0176, 299.15281}, {14,"Bessel 1841 (modified for Schwarzeck)", 6377483.865, 299.1528128}, {36,"Clarke 1858", 6378293.639, 294.26068}, { 7,"Clarke 1866", 6378206.4, 294.9786982}, { 8,"Clarke 1866 (modified for Michigan)", 6378450.047484481,294.9786982}, { 6,"Clarke 1880", 6378249.145, 293.465}, {15,"Clarke 1880 (modified for Arc 1950)", 6378249.145326, 293.4663076}, {30,"Clarke 1880 (modified for IGN)", 6378249.2, 293.4660213}, {37,"Clarke 1880 (modified for Jamaica)", 6378249.136, 293.46631}, {16,"Clarke 1880 (modified for Merchich)", 6378249.2, 293.46598}, {38,"Clarke 1880 (modified for Palestine)", 6378300.79, 293.46623}, {39,"Everest (Brunei and East Malaysia)", 6377298.556, 300.8017}, {11,"Everest (India 1830)", 6377276.345, 300.8017}, {40,"Everest (India 1956)", 6377301.243, 300.80174}, {50,"Everest (Pakistan)", 6377309.613, 300.8017}, {17,"Everest (W. Malaysia and Singapore 1948)", 6377304.063, 300.8017}, {48,"Everest (West Malaysia 1969)", 6377304.063, 300.8017}, {18,"Fischer 1960", 6378166.0, 298.3}, {19,"Fischer 1960 (modified for South Asia)", 6378155.0, 298.3}, {20,"Fischer 1968", 6378150.0, 298.3}, {21,"GRS 67", 6378160.0, 298.247167427}, { 0,"GRS 80", 6378137.0, 298.257222101}, { 5,"Hayford", 6378388.0, 297.0}, {22,"Helmert 1906", 6378200.0, 298.3}, {23,"Hough", 6378270.0, 297.0}, {31,"IAG 75", 6378140.0, 298.257222}, {41,"Indonesian", 6378160.0, 298.247}, { 4,"International 1924", 6378388.0, 297.0}, {49,"Irish (WOFO)", 6377542.178, 299.325}, { 3,"Krassovsky", 6378245.0, 298.3}, {32,"MERIT 83", 6378137.0, 298.257}, {33,"New International 1967", 6378157.5, 298.25}, {42,"NWL 9D", 6378145.0, 298.25}, {43,"NWL 10D", 6378135.0, 298.26}, {44,"OSU86F", 6378136.2, 298.25722}, {45,"OSU91A", 6378136.3, 298.25722}, {46,"Plessis 1817", 6376523.0, 308.64}, {52,"PZ90", 6378136.0, 298.257839303}, {24,"South American", 6378160.0, 298.25}, {12,"Sphere", 6370997.0, 0.0}, {47,"Struve 1860", 6378297.0, 294.73}, {34,"Walbeck", 6376896.0, 302.78}, {25,"War Office", 6378300.583, 296.0}, {26,"WGS 60", 6378165.0, 298.3}, {27,"WGS 66", 6378145.0, 298.25}, { 1,"WGS 72", 6378135.0, 298.26}, {28,"WGS 84", 6378137.0, 298.257223563}, {29,"WGS 84 (MAPINFO Datum 0)", 6378137.01, 298.257223563}, {-1,0, 0.0, 0.0} }; qmapshack-1.10.0/src/pics/000755 001750 000144 00000000000 13216664445 016462 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/pics/about.png000644 001750 000144 00000455543 12627613666 020326 0ustar00oeichlerxusers000000 000000 PNG  IHDRwsBITO pHYs& S IDATx\}Q%;E%yK^L[>eUf I$ lKM <`C6a0@2L1 l۠& p A1sdW,ٰIB #ʷ&$A!0@ۤ@#R0Oi3whmل!:~(ڠ< ڼBh`W MÄ@߯+!1W4 x7a1 Mqh A$Eq6eY p@p`0B޲ٽH`<{A4)"F RfVWy%ط/8 i9<(Iʣt]}`NmavKh7{{$ޛ(*n/{w.Oh6d1Q%w83m15%¼1wway$CwW.(1 v$;}ι$i)/x{'F?3x՟x 7FzȁqTB.`fƴ}o .VuǠEn0`<=})s8"0؝ggd{jfȳw$'LiH{U3?"=K>%gaK^xx}ob]аhQIs@> R@+a5Min.lԼ?4[^(-È { zyUh̡!Y 6oS>[i{dMj5bNޛmEdd'B>-6I}I o' 2w$鞀8ͧ#"Br䇅)YT:AWm(3'R9YM-c%GP@y],=I&0I.l%s|l,ach&H 6lhlq4SF@.~;̲ " MO$"7;#{R4=UMMȫe a#@[.l||Q6uaMԗMV9/oLP%PڄLpʁHḧ"3lQ!N^Q6|bKfȚL PзP?i4O?|A03ÂHWp_V+qq~p#3@  9H>,-li#$f6U٤?|ѐ񂅍I2' !f1'ߩUFTv 6oQK2~_Iy(Kl&1hޱQb |灣NԷC{DhBh?%<ݍۣDL{,4($"h_!e$P̠Ś<$IiL;Y5x9&fYp%(y ^$Ǟ AS |V?aOofǘ;i8pJx)b w#</$f)?SB1,iA ĐxOC}ɜ*ZwBC\؍7<%⹬+<Z4} I>k^7R@%<ɳ̉X40O9pa*g0R" xX aް?xcrf>',WV4EH,*4Xg)1u~:Ox.8=6(nDNZ'9 -",dcNM^sx;&|*!) 3a99`e0)B{Ƅ¦m h')*~kH"?  OĚ1=͞׈V1o67N8-dWBÁO¨bݰ#z i0q|&:$qW^Vd̫O3Ys猫Z]2QNѤ_#\[RG'{S398Uw ĀAQ[0yb3rf"`o>asM>'0+\xICV\Hj7,gVEPB3 cWOpldT(nmx,K]1mEG0| ա<n|m?]ۤCM/='ۧ*-,FoFJXP_Dm"aL3=KaB6Zs Hb'c QhJ_ʮƞ9][,Uy>\"T"P{h$,:6f@V9$$pR("D>_ w:}60Vr]$76 (oNt7/oBs%,brP(h AS"hQ0GBe$vV,kRm QC$":' }8η4r¥iԜ9Kn~XMxxyhj߲L_>oL *Ҝ6Jr|u~;EmeO)TGQds3_f c1'|fXUCnߩSB҂f~VjyB*"f٭jɆz^!otB)o0J@Zk:O N֔DŽI$ѫg@co/xi25|@ϲe4NV67 l3 B6R..nzޔ.ZbAjeC% Eje\=;Tc,7݄0̈I) XW856仂 ŝԴfY>'c*jT~(s ۻ8u}i=I,P!uAH*Q M!aE\8X-$DxR4t0I% /}<잪&ZK# ,f3Gfsb@uޜHlMcp%# WBPKnV $N;B./ٖ,Y# syqtaBRLtky' |$s87I|d\+%p;SHaSԼY?d.P NRekP̃6tD $r<4gJ0@cO>&xLk ͷZZȣI;&)iV6!:ΚiKhfd4_σC'HlΎR =-g`E#TDNr![>YK^j}-=~z=~P,p.'US\Ӕ8*Z!F g$C0dp4Qf ƯdbB~xpiڕ49-93x8b'JI?'ر|U:bE'nyiӰNtWt39UlMp}Xr5O_\vf|4[c xXolI9 {XqxX`vqt]SSﳰ|7XJê 7k]AZw34qeEpcӢas'J':CrNf >y}~_ I&/\~@*b.(Ě!Ħ9 \Aʼ u,Z>(}xYEXDT7]X ZRl'K)iW SFD0W0SV6*bƞD-K4m45ԍqT+(|=#b@#>c~| ]x6EeF2vԤ[l]:"הV}/q+pkS z[l V<AϝJ!?$265BY# !xoH6>>IR=&+Fd͢n=uǃùljx O#ecAk3pB&`k,ZrG 4J6VCL/لȈ,B\H3+{Gl5鵴#cHְ"ȗV [ m4qNRS Z^sZJ ;`L wi}~ F߁R!樚\TǗc9B&Kم?-3N|ٷ_B`|@x4Ji.:A姎q$Q =qp]斀u5@zl_RٵnzTa73hS_g;"[bhutV>jo)ScQHiTiI)rd;(dvÏd;a S#e]|S]T++֑Q#ZT|?3 j +9)b0 y%\ X'8`VcšowWy8 %{hdww PٸR)<^,` B igf9S 9%U+oZ]ÍmK0\t33%H-2q'0Ƕho|7@u8E r;BW2ÞLlI+wpȻF % ~N*|*N +Ls̋s׸hq9f]] &0ܴ+ a#vKbIV * HAl<`mpU"1 g_pb嘵x1T{+x!.H(@u'1?sڦ>?*ΓD9t>ymR}e:yΎq4݅$vhQL"9jd^A~cF;(=K5դO+L1?B?-{'%'f8ŘOI?xwzRQvWAW +}(+ؖ.S2 7и&Zy`-W4 pn\`msy&zZiί٠pyr4J~1uX\VemmK8j*fLrIRpn]ADb)熻A4)&Wz7G 'i0ӞhCV`n LwJPC`7hukuSCjKCВ5w~TW4к=g0REs{+[xU^Wa,046~|~KSZ뼝Š~=}ȞwL?5aܣN,m[:]eBkhrSǭB6a@..sc*ܩ|Xp->\Qo ݖ !.*ʉ+%:&Ȑdf#(>+`T:H3lG9oylQ7O/X2m̥=qƔH;Pƺ]8k`čődJ6N=`9L^:l>ǤV2l =89U~mB X ;nkT[A$2I߁M OGއp>98eRHJ qG"3n'Xt]$M>"G [T>xfLsko3|ڶ_9o3 kã+kN4s(U +Rwi:EozYRpIȏHG;*2;saҬ\Ԉ~) ܺס?9=$7.y/ٻӶp@$ݪ. >+\smIeP5ilI)Jj&Wro]h䙌dMC9l$W6"|[ KX`9,`c:փ%<ۥY L#IɈdž|< x›!#€[¤ (˽av@ƌ({sm5 m @؂- bnoEfXuF*sNɾ*Z+d0B~ ݓ(W8+>mz΂㯳-dU2N +ộ=u/3)IH%-T)9>[ D$wQViI+yύ{ >#ʤ#  w2+T YU A*ьU$ClM Ty3W?j;b-B]pJ7FwA~&>ՍaN9_ Ϛpƀq;jd3Wu߿c L)hF;@^bKm5ˁxax~D(tbD /QJ%gՀS,mZMf+mOF , ОC,jC!5EnS7{t%"Z֌Jd4ĉMS >Xv(U*&b|iDcNa~F UpK@f|/n%>g'ܺs3?OKGIBkG%UҳxZH;"Kh2M9 `Ahf @[&h*HrT%S ʱv|2|i4u󬲠J1bQ2w۽pm)7(rD'㤄m3G s)i]0ðnh^GG C;39X+^ԟ 8L-r#rpUq]Hb$LGn=Z9 ӁS}6b,Pd+qRU6@TW0I:˚E# {NF#1TNAji/ZҝӶ:H]OwU(_ŪzY'v{q_?Y{2g+i}r!@n?svS0Uh_ 8ě@001%72MAڐݯkXI+&HǑciC}B*7#ׅpd.zf>Z|rILe"$91s҂@.g!5t ffY2ry~ Pwڙ\ݛQߚc|HtD:WAuB_OY)m@ *CO& "߄?G'8e ݅܏2ڶmOU'AQ^sgWoUǀFCNA>d&Oy%Xy6m`h2q o-?8ӿƽDUrZL[c2'HJ8W`f&yAǾT&<~6E3DCT.Pm2LuħPq&زpCH5Fـj[>'BJ#-rG^zN2ǜ^kL'%q'1D2+g:Խ yˇ8zD_jvP-%~ٲm s%#*P(Fm$ۮ"NVL6ʺb3/.3sH'I%] E> dFbcZǻe(OFtA?ZsPoYOPeAg)F L[+mpU&K}PJ.Y1zynI;w$gw="oO\H~~Or[I% Ԩ耙+dz3(T"+1d+[O0L pnpD*g,`rR||KBv@(NjJBoVbY6XBDFL{'42KA'O#A )I*z)_ޓ/ҝ o7QJ{鵍| Yhp:<2"]dӛ`cZ6mmr}aW4& >}AφR|3$ݍm<Υ cR\O2GiG']tSѡyX!t͙;є+3R4k˯ `lTʜ)伿<lBX9. ȬWP hc#Is$?<WYr>CGm8;qZ֧{Y>f{027sAA7u|73Q)<+#sG2؆N/i2e[/!`KOOlmC{'3πU2Q{cnTwS$ U}3`džמRZ+|gz>a*EqsHl]\]Qѩ ΦoetU5/ u\qv-`SH ți39y~|~R.:^ӂQPQA,hֵ(az5X?B('TȠm#A˩6; 1bkm\-8@k۠k[LlR8p/17TV%s`΅y>i-f`o#r ˢ2ѮNM^1MfɔzHrd 51I%R*vҽAvv2"fS^W:j:xf@\NKud疠vعm E\[v ,J-s &>6~UXLOto Ag9#[o~VoC%H>/ В{GI9Vӯ:?\x+6ԥ,e 7.MC@ (`F]a"خXI-x/1"sP*8r˦az%YwD-aj \V`+0=r7Q +%hq\!t .`ଁOgEZ'6@^PJ0G|ѿ4Jj@L{.G(#1}V=+pjcd Q \u^^L$0TQR> WҼ)wPkў6lj}rI"꯵Al~mDd_\ T %&fVo:}2[fFmt Rn{z tX]o<'2p8 -N !4%FsafI)kZ(L F+] H17(6ƬYٲͫ "nY1'pd BM>,LAQ7E}#$Lcks,z̴ge>s7h1اɥ@@ИK<WViV>%a>{uzОn4}/9z~rOdBR33s}gl |ֻhX^{7e yed#|Û!zIZ|u!P uE//]ܚ:i&Ndw~rpNG+; *mzF>)ے尳Xo/]xBp#zfKYL`#Z8[]0X±sx6жk{J,)F7_i1%Ć= y`VE; OEpyٲ(Ձm9NzfpK[,rNA;88qGă1yÄ1L#Jӣ8QF))(Kg)DžG1Iya<=0>i"} 6O<@tk4Ku@ 2"Ԅgo FNSs ܎d=zpH"};3u%Agh3;:9i~0/X/UzaÖkWI# e&GnNȴ}JCOEN1@u 'fJoi?\89=XH[EN]Yndvc#Yn]BC~wJammbSm4$K:n2WE$j : vB5B$eHݠQ-ͤg;" s36^ƚٯ8mr-JK\Om"Z/>beB~: pJbׇ}9OoXg GX+̔^Y.fiE98iQ =}aCsu#b#V;SLk$WlwoB1fR77x)NqpAS$<131` ; ܍[XxAi] &?7ݹi&rnPeE'Op_b;wJmWs)/( ӒC^@a5>rUFj"OvI{:w{Vɏ];s;9;xrɯn:ٓdݩMR]ewVR#)~*q[4wr)M WFۚtUm'(R3ȡԽɱaZ9in֑DONoR4 +׬sE+垘l lTjd> *sq - ]y`eܩQfI/ R.ksm@SU`f\v,}7uțHm5flSr.{6E巫As2.[b<'wURN?xBҫ#]241}3zs% K=v%$r8I$#߻.Xǹoӡ]٣LI^b{ K/3~;w58kL͘&_1-? ˣua =l=&10&ա۪]!6Wc,'{<}^ asȘ{F8mǃf>^tvWlalk 76JߜN:&wD*nӠ}On~2[nz IDATws [6AĤXoF*N dyAR{$T1ON?. uQmnIP8vI[odl3C69O={! #73d&Rz3O3V jxCDۛUG`?N$2o>C'},ͥ.5T1qΠ̞=c7CN rH1XAΑ"y/kO&لmrAdA3$w e/vp:/ k 6|hsþ_mZ, :)2-W IgPh21q!G7Yzn_WNVKU]d8?.ns;0EM4tB'? $ `.d: 0PJ똈< 1Oit1nxAU8YXl9ONaugж秹v.f]@jCĂ9I_(!@o%Xl<ȣd|%_L16D<W%0g8!&p(Vc&'ƿ9meǺ-G6؃$Kq EόvYdI`Qas^Гwreg$sqyaΈc{Կ3-vwpm HoL79>D9+f&Iдu;K*,ۮwd@m!Tc[so9qvr^G_) VA-tMU3a p238ʱU  ' rze-俘5@Tes4 +2s#6W+[sB*q\4BF/Zg!P@eM`W:'7Z%qzdK2=Rzjn9=35U7O Hx l'}]Q0 ,=2K]:`w}J 2D6+sJf66w m"BFId;^L%V߆V$X1;<ԂvC:9Z pMBvn!sy_+fa}vƐH#{K@b LWHA2dW3c;nq| |n &BG3?7ֈo BIx~%,cnUNweKpG"nP~fm֘J͞1UFU_񘭘MXú0\׾&8U +(WWǘ=k~ZZ嘰HT5ź; |1 3rw ,˴D<$=A(.$~i":}X2ZYy_lKQOV:g7ۃLFRrh*>%-w+c-Sћꈬjډ&Z9 cT݌,l QW"OplJ,:-i=sByCc9ߏɀ %.׹^=6rNP$|- bz@/^zxt0א#Vxf<{ݾD-zrYP#a}oLZ!%+i]P!F3pz[">Wn?J45,5s!l6Dl~k%>>GK{u~qcy4t\iZ) y}T)lLJNJ.APӦ0z Xo7Ac;r U ukjګ4$Ȑ+xS{| i;98X?=lD aնn9$ҿbz`zF$b||LvOhSfkA5 +y[J^f>{EO/Lvz$fӬ$n U8ׇ!लgc JF${kr4Ӑ۶DPnOkqDZ.&'@KxTǺ.Y[ƅ&.)Ƌ*̆#jO"2`&I?,iDZFf-AK$7< ['j>JQK/fTH%'\&D={WԷ >ϼ/Gu倿ˍTi[ xLrжG`J E*<^t;-j#d]w6k" nKB'?=€:y^ph`8t0KZ<&:߁I[}4Ĉ y toR6:XII b1ePdo:&upv=ܝgGa)z=PM!eU! wl]b&6m|w8+?}I\T7'&5kX *PlDyo3+D>"& ]2 p=Y v߭8)YlP#;|():+cdYh`wPٶ"\utʹǓDV1P[Zp&0Y|qVQE|Qg9w7587a܃-̆m] bx)/dMɫ00 [h(}3ѕ1CPEacvvFz4ʃd6%mPj3P04jxLW̛aQµJ# XNfͻt*T7>4d2JCͷO|<a|խc0B\{5v5QIhi>RggH P8Fw3@A-(D/p뇁M#VyA3붉Ǣ.ͤNqX"P.p Ib~1i%z86y6 ${>w\7ş\~s&nOؚ*D}SkVI֚O.)?Bzb-XsP^Foz{s8>j<5Q_O}-q0l@o/̀:Ms#צ| \u{viҍjm'[a+OWTXs9Ji ǻ{Ox)gE?#k2ѐx?7D 1 #u4Ar @MCRMCvg \uϽr2hGeL,'4xV3M*]*zV^Ϝ-'اgLOdt&[~5&ZOX{D-0p3/V4b;s{]*]ovdMvjǺɇ3K Z:~{7 &u/T=!yA n~_[I %J=xs2ʻgv'd~&몗]&>|SzZ^urJP[>dPǔR85D{:\~Kt9`Id!qo|A״錁ʈaL ҉.В썪I^YCa]Y;#2MzR&|kz|L@K6uk$,鰩 XBf!Yȫُ!}:s?IWQ낈͢=Z|M7FcweGiV]ºԚc6HiWUnRl9؇N O<^|>_z_A_&_\bAA^qQ8DxaQv12ͥ]j \ֿa1 )5?J Y@*<ļ`ԅՙ4IeҴr%Tnzs@{'oƜQH._5E@9Wux .HS5+Y:-10Q6!d_>Hx8H/ڥ!*=64'\%)A7i PlbpAF"QJqs{G}VOgc/T>]<[/mч'CDeYǷv `F !>7=/;ES1@M"` )?~]\ǣ7ᣍƹ~6VuB rb]M"BtU52g^E& ҚXScrOh΁yrbyMfB:FR > RJ+/,4ډfюTe0ܛFm9ywpEUrÊ8|MWdL{|IP$Lq־yH2lK9yޗٶsy muZ%9e _zY5tD|˗87Xշ>D+*iwS]o[^J@ ލK{y679r-XA*^6hK<1ak?zIzy0P|o'>q^y}N2 sʦj;jt%k9'4Ui(,De-QG47T;ܔH Ws/nz3`75J|y\ARnLTK2rIϖ('ɱjFntcO`9TZ*AϤq;SoGXMB |p,,$-# AȌg vˑ"ғ4 IۋPYyy- 2C5~p1;8 HvPGJ6|r:\eECgL@ˠ4@L6.fcy.䲅0̺89/R{ kBTw,~^&C1'Pn1Cn7\k OײO.Xy߈I,^t'b~ \Z +?SY/'Ap(ir05*tkg  ]_tr8HiqYl4 N'HهYǾ@*ؗC /lM xHoB:_;\\.JWuZzMeդW9C͉:Y'Ky&1¿/u+PׁZ "ǙPؽt ;R_fؕ-Jv۝_+HȭK\7}vjM1( 07CЦ`_a3~^t-IC[RmK}N\"lckx241.nb7̷l.4G#ij7RZ:7ƜE61AxA,^ 8}q;+0ʠ7 ;8n ׮Ggh}6NqvvKh)a.?ڑpaskEgrlֳ{@]NrTD&./Gkf@NJ/\Tskl]}/^QV8ej` E+tUGRwӑÓ1.G2SD>*n.*t]ۜMp':M!]6_-͢A{0M/ II;%[~`\Cg.ѹT1Wy!",X2k-gM^+f;4O*#6aCTq'} x#>H0dwcy IDATe"KcgyvDt-lOӆ!v f$Gݬ m*mH~D"AݻnZ'?(87?ةhUQGP)m%@&N0EѻV$B3 kUbiUz|-Iv_pܸfr̕o^p(>_'MFC_w&~'gi `eV?lՒjOmbk kNd"ҋ!ܩÁNldm]|LyBݐT-nhlVF kV뫌ϋ7$` ؈xNb@Wiv'{C DZa\1q5pȰfBb0?܁+`txv p.iqkh~2/s*M ڧmA.`b_wT}CӖs{^Wo+F~BWH egJvFTlDWTt8;l Q(mcLkDk|/}y~yқ'0opM:uz8n1%y"N~\ҿ`zC[ _ڽ<LjHGϳRbo `bQ=Y[CLo,&τXnwi qꖂL0%?g"R\8鐵L! eu@>zuI= I#O\v(1:O>xٳ{|}E;;7VQ ,|}fGIO}Щ] e 5hA>X1Q{eaDfBE;cb+\R&FbQxyJ⿄i5UMY 3~{EQ]-ԊG >%]דsK,rXfvRrfL4_x! r)N;>r+*iL ; _O/w/B 0p~0* f.\i M1\7M1m;STQW-Nu{(7 zִmd# u-;I8#Jw~P#MQP$dU%AM3hWaBj %j)[=|yt{pȘOD}}RzwOE/M͛Z'Иo W NC`өm~0b?_`..u +[߉s61n6ۛm}iśפRUh;rs B@fRE'Uע*/Nڀ<9]|,/u3?2 9RtM_]W4?9ޕ*ǔ~H_"ͰpW% l$,V_ GY[Ml4TMA=9)McUC,\NU2HBje=f|DR Jz)O3e/Wx$+ /=VO)0*C…ATP_?CZf\xGr!՞Н]y5:k]Go6^:ܗSHs:Jf7B灿#< 6y qi<@*zb'XE!X!)u18冝G`ޚ}}l>A,w'cbcy,lSf b̋^@3a\Ѩ/摤=VKEmXAf]՗'w:<L.4 80% Pz5 C_݂?GC%ZB%.=CO밽_1%-`XӒ+uz돥rl?;uˁ&gjr:$BX՛0PJ)~$*`:^Hq'G|&&Aٟ%i jIC@M`/;.U+UoU\H]fHxR2AɎa!8O>7@0Nz/ےv: ,b 8+*Jp[}Ǘ3:4! +GlZIlfbvm Mwԯ3GcMozbKꀥA[UцjPͪG77T@V rtx$g"`G8AA7{!1[eo#PEPHո8"lHdy}!Qbo:."݆xx ^[org t5Юh+cNQ/ zJR؛dJ :CG@HV!Җ"fftJ(ZIg3k!2͵nE3Tܥiظ&NIlTT-'jIkCc{a˽T3#Հm 6+ hv8xM*cbabeWL7 ++4 *D$lmCp  yF+%?syEV.,r=|L}c9Cvq+֙9XA[%^q7_TE( HC Ig!kPNo3Wĸ}WvW0NiUd%'̴ ߫H7I3a͒,xf8"@!Z3弴'iN^y@RqB\˅z౗TȌB3 `rj-74WUWT@(V4asG]Q#rq퟼>xkN_V82FNdrN0KID'}CPL /6+} }]DٔyE/~ *nÄ 6LY~]:KӼ"X``YtFzDfP{B (K>pIdhp$8Tt_fI ʌqOr׺Ԍ-6:NIp;Z8og: 8J ]y qzw@ ND˔Q(>G@6-22[6p.4R,:Xh=KR*˔7=êEiWsl,,l$ҎN+h6cG[@msh:R$A:ȥ65$5 jQ /q`si9o<]"?ϤͽDHzTi)‹% Mn(21Z>@7@/)&CF_txpwpgg#7pi:c8rSqli|cv$݅5;J i0KPZ6#("V"빁jyQCyA(Wrߕ|3$9'ϥyZuRF& Sh߮4R 7]{I~'1G8I:@0l&]є +3G+!"_},v`3!kNSx޶6eкM8H0 /KW} `5"l_ 2(K 0Cp<=uכ ozS d {#:m[~+9|,qhIzl L)8yXō}k-!QQիb$^QCQL'1iIǞ>C<:dZEF<$V  $Z3[eX+8KyvuvIx"ƗPDᗀhZ*lZ4S j)qíDH0iD6;i43&!%aёc6:8nr]Ǽʜ~ ( Vj"ű[ߕn:N-Ջ*AׯAX 4 I`B e@r7MaUiLJ8m,ȤH@J:P?ny9:#m$;@p-=7W(:Din V3A0PYFJm῀FrE̎ R4o{[^Sn`- zS bhvXE47.hD^u%{A؏7y`[bQ&0\@i_"i# gxG$7 !`,HKbvR xcpUIH&HN8^F{j [Җ"-aF" C/7t)oE>^*ׂXG=B򠘷a;$z໰r].3._m;;fBi&4nK;ɞ$nymg /d/8tW,IދGk08X#ؒhq1<3% !7Ϋac9'UDjg䦆 =@ e!y&ލP/xZs;!ڳGC+$)@Xiq"K*)@ކl,ȷM>p?e JY"S{Iq~~liq}+eAbnFlrU`,9̭ ֹBQê8Yqe$,HSe=w~1>%8+|}τ a ~x9} 5gj\6 t@jӸB\3c 0E䵽IglJ z&{vTx%9X1ʯ^R7_]4CD(?cvt 0~ar4o$Ph~MS u`xixa-瘢||5|{|^)ym2à; -zhʏHd8;Ryw4 IDAT xnNh% {n}#3:b&943suK2Gu|d&tcA'L"i)ͺ1r NK.t BJ \tis@wp/x`Zal=*B PՃ=5.ƍ "Βu@^~]eպV&s6J޷F[@`H_pIi~w|l~F 21z&(ԕsYճGGY _a|9~OM$e1NyMw) prvwyR?6 %|\$Tejbq 5sAλ{CXXg43>U2-vNAlK^y uo'_J/f=H۫.}}wÖz=^K~)`i_KRrJ )+xgrK`TS z"~Xٖ 饾xX7,)w'8ֲ47K5>ΰ_h !QT'/[_?{[J$ⴼV/ƂpؘB;{П䈅A;+ج џb %w4ڼJJ⦩%NqX:䄉EJEX2!m.-Ј mnU+w6ɼ(u! tmMrӤ1+ m{$SXrwD.˷ӧ! 0)ؙp"aDiU); ̛=*g D'H&SHӰsAP!&; `ry&#%rGpYm2^Ҟ!q,s}elgLhDu3D G & E6U4DpdU']Ns!'Ϗ;ٽ*vIn~ޡXJp>mri2V`4t_+Uԓu^=/ypf؝Lb3Զ~|kl ĥ6տ=9lf'JoGC@Q }vbIP?G:ѝirf£g5lY^ujG8fD\}JiS/"bUA^~v%gXR.Zp6ۦ#;fQX-Hg 8Cd$ժ Y,bO󃷏-Yiˊ|4QKPe@di=Eedߪ p5R  we*b ӛꡳlh<:FEpK[4O%̊ꛤ;b+mP@Ǒ}q@k:ゎ8zW?dx #iPlӪr]e!MJ>wE)'d? O\!F !!8pی M;4pB/sfQ/x<7q>iec$'W誛3F/YyzpbTy,@Ϩ&[P k^qZj.q: fv`a-QqaGd6LRȐWm\1LB4Ra _uZ\Ts_o=ŎS,0{Z/ `*^_#kH\XK0ϝ'I?q p^x8Ei^"sAfSoWlsi# ֨}8%%x>K?孩^ȈhO--.Y,᪐wI$_iZᩑ$Lf0]O9r0`6˾7m*hnfG,[+7FG-)&OG5xW)M¬Hs2#6(*n_G鋑%#>K\) ~xDq^&$&ضZ ŅRI D%z[pO%rS3JF?.ys: T{`Gj-p2nPRْ  `r񌡆 Ic ׯ/ ˶rcw`u{ɻ&XܫtқL < s'YԸԞ{}$Qb!}V1a7(o?p2- sRIQН͟sbsgM-qhNn+hD/n@W $oe_"kyl n$&IB)2;1m-*MTm p`5a­Os"PM(0P+Y4Q hf=Ð=K >  }}9RL٧4?B.|CLHq3Q`V j= X)A}Op_#)2v-d \DbjF!pSN{5;RX!fT'6_Vl% `MDN< mod8#w)afF[28pUaZVs8W+_ Ή8-μ\&7"L@7yޔh5''1TZ"HZ$+\Mz=ABiuI*za#~EmNmSi8R \!u13L +5y[nE]Kf9. 56%ךDzS}&'k\lDW}L֐uQrt|5n5M WIdbQ+B7(l /]";ϸP#)mxS9X'3x˽brp;#]{%w #K4^'1d6 {yMX>;=2Fwxb}7N^h *Bo*Ē0hZUSR r^|J`NbOp7_~>xҏR. 8๿ˑGP u+O d@9}^]u#\_( йF"|@KA mѾ&JhJ壊Szy[MS+㗋7R6)YUp> qv2\cIekPO0`n)*jp*reSꬊ!w:Bl/ ,ߞmzҎi/VYc}m3=6f apOgaoզ)d)hI,ywd!y^]4ofܠbp҂MQ')~-ͯ}:2r@0)' Z,a"Q2]gn93/u?Xkϖ4ST(e-2M'{z5m5-u&Aڬ7o) El3" ZJv6 9Cn7xatĩdݏY| R}ZQ(9 kXM}Z_ǞL}8| i W54ͮ^JSZS_[J{&nɑ|/|[lp/Wlcl6^ILi7˙^6noO^JZhG51YZKݕ8Z&!%QJ8Զ\k ,죿jzg%inK혩* lFZ/9D`oYb5Plh3g_ F7_Nc\t1 \2 (G"C{y춱GXj-[@u&^n,nY$/ie\L h6&$q?=WaRzMc"r>P&3`?JD8b kX(i/lOU` X /4W#~:Fl\ "B;vwŠ ο5zT옡Nb|hv9Z_t\vU𣿡Y=|\ԝ(ur"btpTk轟nGG ӳvdDzԳ1[ا6h!QaY?rf |8EA}N:vQHt˽ߨE^MJ-Af%}`:GϴTrY=|/Ҋ=Zr׫ۈ:^xK8\\ D1S/l832Mt[ kR%Av55/XM@̰#I͎(\  Ќf cn>Nj4UJ7DZgz&#u2 4w  9c{=I·':6_;ZU3:#uE&Q|cu=.{K4BLo  I{@y67uBخoYڢnU_1Zqp ( S,4e 2#c_ֽ/av$֨&K&YDK.P hgWlQCר.zP# : yBuy<>!LU ag-&ѦAHYGjJ7z@D\Z[ HC¶j#Ga=j 34ej*K0yJ~ Ӎ;*+eV 4VWbI_:_ Dx8%qVͥ6CzyB!{Hu8c:/E+XD:uH#LQjF8Jt_Eš_juV{`cCe{h:׮( qT'6\!R,) wxDŷBcgդ }}Ԩ2CZhEu+ߤwOy SXPwz~M&F[;QT,cMHwv!%=><.eW ]K*Ca:0TC8q=^c\DԠ° ,mjȱץ{D p4w =X:q8*E3F%)>0*ڊgyR*-epgrw)PgGUJ!+pFs.&m BXiTAGˇWKFJNˮmωo}?vem@+㻷׏~ǧyKN26Fw4 *H:II ' {~YSGDc~>*fWlBQQeN,(N? k@vdy5G$!H9tUuL%&MD|h`h'.j;dNtqo5^$ǰq^p{W_>$Ͽx{~ѳ\-Ͼovy]>h~gnVX-8ߜO|A=ï^ޏq"OA}#r)gڇϞ(d]m#.> 0]묂u7jCyzp0](IdM5ӭZ*so{!- 6m&j/g=O"̕ 塡>.p#:!9fj?kpo.#e 1"[J+W1G}5S%W|.-ik0sb|۳w>ۻsEpr&-CUg jL 0Я5?_=eP-dj!RaW;plp3UGe*GȌ EfJ ?0بԂ׀j vfXIC-U02ю=?Pؓf>m̉Xi+%ݵw]p*0/sÀR%+R˕H2Z(  +)CTYұ I*5=j E0˾%< IDATw gog([gD8W<5Q^0mW eKPT.Ηy4,gp)=ɉ8RP#v5\yԡj3ebq~G+2 G (:T&zk(-FFn{dQZb3N ߌ CĶ2Ks`B֘:G:mAb rFr*# `ۖsjC_~W?>~p;Qr*rgiJ V ݗNus]Ov}O̵EPVk_'ɔso}?tp$ч/wCUs3^\6Aa+nӞJ%UCaR6U.Gp4;sD; S%=9RݲDJuUPh>v#KĆq!YPjl@'#j1c)$1Ā!3jF2֚52+tElőZ\J) 4X,)bOd dbu" d Eo{Fy8 ZXp], 7ZrYBQȊDn>~‹ꦊuD 7.J9%1LYBAPo&T1DCͺ8jXGYѿ4៙Z [ C^jRXX?^e*ܐH2!+2J|+qBg_\_o|z5f햿GL2F+Ɠ'U(Lh^oYݩbKiT-4H.'|HռUb \ʫmf ^M q##9v$,b/HQhi`myٹ6Zn,gb Fpt0LBr@1q ΐ6Gd$VFy&Vz\ka[/LJ1ʨ&|7ʻzr?b[v7a23 rS )٭-yG X} |9b72'$*>/n0xĐI,e@!OeL!UZ>ZV/]`vS@zlG@r%'1C"0($cTPJ Z,֡f9س:+`P2W8V`2s=nIe.̕^_P쨎E%v=[!]RuVQTaxzxMW@Seڍ&Y+x`҃]9}]v,ZT/ 7Ċ]MZu$-஻vE4I,(͡)CjgІT.ք#8/`tL$ ,l'ёQ;6)Jݝ"vQf2`,Cf]]ut_kЯX.qD;l"c<]s_iNDU?,/|mx /go$ M@ei%)rXdDhL==Yc Z>eQ^$.++ 7#2u)\ߗox~O)I`zHV]_:\aNmyJ<.ZcYzru%=`V(Cī>(j(ÊY 5+^Ջ п`CQ_GKA& L4/\\K1V clD(k ( dbH{OFj5QAb}߀mks {8qs^g/>~ɷ?yR>e͏תE5tŹ*Ӽe'94BJZS_U_F\w@: 8[]t3i UWb%n0-@9yfU0dfPeUaH\ꠤW!8:ӣa.85BZ+wuZ8 PDzDP#ݵ/NfoM-λxHexA.3OC{.u^]{<z?dIu; LFUXTDة(VG!ױ^9{;:f^cFh'!V!`yQe ]ФO=^lM`$|vzL4oJq~23yT*&Ҝ$Z^{9T+9V͑(L S]Jkm'Jf$MQؒLD.jPM0%=.ywyop>i*YÆYʴ@7DK!6D͚R#Oi! 9PPu?cnz1X170pحv()աJ%g?EhT ප?;5%Q"Z˧Mnt4.H3DHieyPrC#y(yڬZ^hH+n/ٲn+ G#cY-h0cƐ^zp+Li?"*Qsz©MCY/FWf u{8O?D:=؇.IR;TŤ9?F 82seba%$D_DBhk]skCtN#@LGYF~r[) DfXlUDYG cٟZzظ; # / ]\9ebi"iMH@ 61\vRž1<ꚺjlƎT@2R3WZ*A 醟F2vĠZ5D(Y 3b14C0w(q+tf=J#ieϾfTCxqd9P Nm`%*r,P#<˼!躯~)"Buu HD ,_]HZgB4aUVEpJXd eo9Q2ƳbZAg# Nr-Xn81,BfNYk&cDzmBb-.{Ist̔F"a j4XERY}3ǠVD_x~Ͼw> ӓOUtjE P{$@`xX?C,Q3e.0L0G r.Ԗk=b 2ŞB YA9o#r͟ݻe":X/#-#Ou~=ߣ] [73KmG.iaKr_ʅTEWTX#HŊ#u]jNwDCɁOdfbyss>͑e//yn\ڀRwFDyjbɖtu>{ȝ" 6f8ڍ=ШH=7o\{s47y}*,OG39؁́?3#1r.(HP<ߜ/Y(;dF%CE#1  K3H]k`_!d_Ғg&2'xB;1ի۩b*A@bQ;U(JVT]~w}Ɋ,~J]wHeyUIvKNpɏE^9h|V=G\S[ux w`v:sIQqg-3/%'8eXA82u n {d"=P\ONh([pHXIh+*sذ"-j8ڶ\]7'OT[tw==`(;`o61";b`Dq>M'<psM""Aq &bRbSBǑ/`E ;FgdK碦"O2嫵%&CLlIsޫ) AZތtо=.B$cp 1EO ĵ$ja\w&Ԃ4tnRm[Ea'qOƔ0zВRaص+!#\+4UW_V 5ʣ;% \I"/6:RQ` {En]:6Y{9Ԫ@`DM6Xub6OqyG5zhw6SD'&+#53c,,4 ΁LdjX\^(1iӶf!%ր">3yZgr'7c~X1}FYBJ2&jxٯLJ/?uM 8,h^m\WW7^PU ,o5NIBSe*] >jVwӜ'P6u\O8Ξ#e<>+˽}Tmi-?4TiH @4$k*=5Y#>P`{Vsg>^n"%=Cd\rT e 3#Oο3{<["$-4%¾ ]ʸ@c*m ɂm aHi=sdҪrEOه+aK<msTlPw4_  P F9bßPKi )#Ǐ+M32d]YwJ73TKc01 -$ ̕TFɊ8j1:V_ +)ډy9өM4un(nh8;ftS3\:G ׵ľy WյFfav><dbEAD?? Dԇi{4r9?4QTDn,s2c@ '`'"9oEBȵs@DZ`h Im yT aLBC[K\;7Wc6YC2EWƮ?Erϛso>8}kn'nەt*:°:;vv-ĜBuwMV2>.JK &H&L5:DLJȂ얳ʳɨQoKP&Tɧy]뢛!ț4. H)Eb #K!oNX 3ٜ>`:E)?JzdjA&K YȔ8\-7({mN'ԫWoo~?Q*e OpKe^ȩcRZAREe)*3y+Z}XhzVewu;*ZeoUf|Vo3DZcN5`0F䂽EϧTP\݂ʡ:#C>7'QxWb1fK6y1sRMT#\0AU ,JO.@k嶔ÎϿzsy|Q{^5\D8Raލy.JI eK5\})IWs q39nΓ}1Cm[Z۲=>K2EzI}G]j( #&<Z Kܒ+`z.FAӐ! %\4an' (2D9$r 27?Lu2U@s~|D[w9\r:qsL 8{Ic Ԩ\F$+QI 5PeFώ@JPnQ~O=3s>kOBEc"w\v,2F Ԏ,h0P99s}ڵƘ3aRk)zP©mk8_y"&%ݿ{Ƿr!ӧ7D3.ә2Pv($jbWcr Yz jzԐ94'"1f+uLJn@rȃf"(.%8 3qq)M=%fB?w$ 'F%vǍJ$ŠA,25(s0!V]d04xR),8`hf oU9s珏a=\.۸lS<ǿӕО+ MӴXΉqCG()ؑcT5L3ʨZIRÞckO#F<>^Rt<Sf N 0QwP}ۺuXs` ˛@BESgw?v/(L"pvtE'Cr ˨_u`4 /t\_EE~M~ 9PnmP1l54#C5-Faj"0_e^?>8keEz{w#(|z8qAv "T~jð+!3 JچcA쐤}ItQ)zR '(0M∫lCG\d#] 짥}P387MT`fAoge,])C{$$D O+u險6e6~wo=\/{JmTz䞸d^.+뷏޽+欠9@/vj"&ݡ0 DN.a(%$Mγ ACVg|:/q ]~a1^$RkeZLHUU2-*B_}?ݝ#u)kb1] Yʈ< dNN I "Z%,+;rU~R\}a_!1'&1Qߟ5}}!ŝ[>lkx SCz{St- cix#\z xBpƉP,ݡg\.Ge1(1i>ۥ/ϹQ= RnCHFu*_|ͷŷ>|LghtRQ%kNŢ1(Ԝd @dbo5՞2YQBۓW&;QF5zxՇ%rGsw,:9Xi&@$ '[0}x X4b@=Ѯ/q8A;YHɴ D$ %G͛ yCJJ5>*@Z8e_Q/\iC*Jhc8QT/tobƗ_=;}rd [7L,#Q@ fP ^D ńR15[2P0U Qi7vN5@I?ݟ#y:qH$G@Z`ܶ"N76j0䘌 #nnd%DB>WJ+d8&SB{nLLYWUThI" J5 @Fڵ(Dd PX#TZ;YwMk/ݏ>xv_~ͳgs Q/yS;cS%#eEQ`4!V }S 5wrya͙}1& 1F,NϲuHFy 1%Av>[xFw*?*TxE2Dyg$'%-be).󕗗I ߰$ݫ?c4- K 3EPy4cLw ޗ*E}XK6C0ůӓW/^ޞ'Op<m Uc?Jե짿_sơ&Z0T0,,=%#7pyҘT5;눞Kv24=%2!2' 2y俪U?="a݈y8Xo.P'OcHh Kj2!h>NBqr31#lJI|#a_,Jx_D"Wu==={ve1gwġ@py>L}t W; QwBǎ^%&%h۪>~P,}6 Po d0~~r: -ND<1r " +[Vb0K>⋄A[qDчD=Gpl"yLaFSkrjdw#%b HaKr#Csna0W2K[zOOǠŨ?o| J\3Wܣ P?i9z9j^ ,`κ o O'cho}$L"_Rf2!)Wyc<{;ɛ' m̓嫯>{"Ur$@1%IZNaJ̾yx{ޚAVxڋ69:]f#b@)2= Rb*ח'7s Xum?Yz6  B\wçUQoZq۩^Yr*d5j[j_1%d%\kg_-$گ|x΅UsΘ#޽MU~ً_}__r>t1Xe3=9Ua rف,"i9v}CEp5=S::8Y  `;0y3kT D|L//f*afa9Du [1 )_x՛#ng5ei}Fs+FZxHRkϮ?-Ga[mAd-73yL&%!׮_{a]ƾ#5pחm߶mw߼~A)ƻ7c^|} or/|/z|9Fx3N3M3j5X\i8SmEDZ?f.IӈQR@~NWf, c5) SL{!7/Ͼc[^[ow7H 5Hŋi/_͇E nWo:b6 yl"8۫Y9m%Rܤ=y{27,^>z~ЌIre[$ag8.݀0\=-HyțF}i$,Re} }W⬵k[9ۇx9޾ݻׯ}g͚mI+{8ܩKHd`$FZ/M#UO&6ТL$Mb"APӝ=;3#ܗ<^ַ= 8r JQS4`5smXlS8Ypl:’F(k 꾖DV[PǺ2&ח{ųv3qͩQdȧſz=!k=phw7>qljK, )뫷Ӌ_n,a*N|y}z=G!wGMw6@$NjDd+}g ='Uf+XY^"cZN :Q@㼴vwZw;sxm W~XOyTB_]+Pq/f ggp-r~>yWDO JZ;h=$MvaV~>7ٛc?|t5pѩмɿzۏTZVJ |$]wy$sjff*%ߛa U;`w(^E5":<x[s{g=b7/8ohTJ|ˍQ]nEM&`t0uy'0w+3QiKU>?e"HwErLŒƀTY,x@DM%%+y]>~pYkN | 1QIsG@#YQSfG4ijvK#@C~^o3ľ+Hׯhcs矺@0բb,)sňDΗBHUѲ:"2Ltȫ)wϗbGGl1a;-tixsiipvۓ#ZBJ0kx(]AefL`4X:1Q'#)*NA#[KnZe[:x B F2.uws "oEPULΦR=9ufP0"C.vΠC$F :N嘛 <-8+ O`v"}Ut$w\0 &RT̾D57Xd֜*Y@%}u#5(i HFIxScPؕfμgJU_BWw=a"̂(HB -DפZ=^ؕlkoq7-m`нMn瘜q<~I{rYoNbBDpx?PuWdOAd &TTwcHR#U"PHuuE1T,2d $}Dyss{honNo|ێ#X 7\m{ivc'd @tn}0zt.קO3'r:P$: P#8uܜ@ ȵ1/)r8cRaLaw}ƚ "Q I 5*ڗCDB{&W"'Պ×9 ƢnnNG 1 rGUCd.-!kC52`@&N. !k%֒WfH@Ĝ=q)R NBynq:\lN #@)eiOWT*%CAuI, V ^%Gxٜo=ŗ̂X5ú<zއ>>.~\mǿxP5.3o?1/6|0ۖ|jGf13@n0֢#N]b Tm2K/?o"g2x;2[?Q=iRR̙!su1P.a@tY A<(}^ J,.Z IܗX}dxh(Z @Sɶp _}T.iu@@ubMξ\ f`!*}"/w7lO>~r?ޝ!V fsB5]y^RgཝmL|ϯg ~!jZ*l.9- p{PcU/.qPX 6A5gxp{z¥! JVK5)~v'_/$eUo+FȨB¡YO#4z~ }d eenPKHAXS`er+0{2lL I 9X,תD)Keɖ2Jzd5Xى"TC<˫8}-ǻqItٰqEѼO :lg;T-%DK]G/NO>|do߼:;&NʀGoi@Z8w6eHƀVܞ ;;TO~N]l [LIJt1t `pBPbU*c#Jz*tgò}+?GĔjT!eaE <͡N@u|vshxahGL$(guS-'dXvXk&Ţ*wn{?}ӷSLwRl:RXRFOTV/kq]-jp'XX٣8OAZ-k*г+V?*<%mE@uqV~gfl2\zzo~[_<޻=}?}>*,0#|GstjMKФTUQ ;Dw@tIBA% Gf"MC4SR#~Wٟ_O1Lp:Q-q 13@1G8ٛ3Z z%J%Q"|AD)+ʙP%TeJf/.uڨH-b@BI'><,]Tp}|`""Ee1RLWS5`W P ~~>xvWonSwQajoZ(R˦T5.*4ۅ2~t駯xZL2߽l܌I,6]TEZTUکw'3 p|ӫ/K歹6/Bj>ZwKDHoc/?LMnN81M/ ;PJ.N 󶝩p)9_]($X#0pn!BPsn" qEV+@_$ օ5aW|^dͲI3'(. !E}xEů^]wRTq2-JCoDžۻփaME}@IYݎ*ӟ6CɓO_=ͧyeG+M\a}qe|8&\Z/§>M苈,?`6-$R eAmevQc־U$Ӏ (H$ HI6L„VRT2ؒn`v, Tk&SL=]71% ̔WL{xRu܏L9uSuMG0: Ur:.uHm>1f`ԍ)Aу[>|՗_^[Qsn b֡u(Z@lw1lA쎥Zgxk*uea=ˬ]֝RAĴ0؝*<M!}cL ފA5 _HŊ(qj絬PSWSXN!b&?\v,fӤ 22Ta`P3MFa&v;;AbLQl.vl*Z1Z]PU ǰje@]Uۻ2b1Ze(X?z10)bhT5+Vk6㾎[XqB?oNK,fF-nj0a;h 0UWŴUMҊS|0[}YzdCUsfk̽hӽ{Lm@",˼DwOB%}bo{c})@=nsDCнl]Q/+X|W殙H+\T[5"@  -EMtZ]JsZuP]~Ujt 춧S&VBEűm RFy㋷sQ">X7Jg.o>~ynm,V6T,v1bO#"1z&FxbbL}ͺ@SVj`0Pfx3 "f[} jU TսO2Xz 4lTBARxp/˺mW WS{&Xj.]ח*W s. gtV [Sjec&2w 2J8>5!ҝw@l^h)2"0^&U1jyPh)u^fB2$u"ePkj2>z|q;{a`uID@)v(2h)A";zoscVx=cY1ϱ6f;# VlyTHH|MEfMV; v;t]iN0$LX6Bxtwedh.pҧ}i, RP)}7%Q[fp'_T E1#S*PxCE()@DAp^uvqs{J]lKw.SCEr]lM<3pƩ{xW2ZpaXĖc.ͩDz6m WWnҰ, yi1{p!sWJ&;HǏEՑJҧv?+ Gxwo4} h)=@< A TRJV+b XzGw(k<(E77'ƈKwRH82VuY4n)*t祻#`iJ&{d8 +uA+C^֖fZt;ytj=xtᓻnZJO2ue,jezoZYJDn.rb5oӼ iYJTn{ӱj-9녈#e"jw?=yXE;T]^x;9[@P/ [[SO~$r(cND8h 2fLb!U%<`"9`q;8kUZ*e-Վq7`CJf+[/ *)o~ﻇm'(}uWAono *jlf6njU|o~k:~|Q-:륁SDf`v01UO/:{%cu}(ows?S˯;͌6-}>qxiYVv'ǿ>;\QFHbbqcJh,֮pjdCes[6{o]m3śI o (uz뽵$ ڦ9ϟ/͊D!AO_gɯ{ii.o_FT\B d];\ ӲuH>ejE\@—Vb<(O]/w?͗ Թfn !Kj9tGkM)N 6;TpiI6-MuKB &O/yZ<|_;(̓"?5@PRu(:&! "(D0LT uhq,)iAivF)%TDiX𵇩1ΒT R7L>ğ.4}lE~wU)`o_>_ӏn!*??}sGwoI|60^/o,KjVaspowo lw1kKtj1#ЧAңC]{@wv1 0 q:4Z ]>_o-JR>[Ϸ'!;Os;UHhy ,k$7@L"fCӓm*SH3*80&"I<i^=8[s Fq#2 fm (s~媟 1qkqO~hlj}mwoJ)"f}?yrQBUO࣡[iwj^/:A6纻uEI!BRXfѲ̳+5w\z!"uSn.~j3)P4<3ya\[սe%*0jtO~?޼=EH&h-a]w沂L@2Բ=:P) H(XD(ZȢ:RYx$j`dU $Vi<Q"BC<^i⳷͠$Wqn}z4i99ԘVUnؠg`@7_!e.al\#4k8>Wd3D4>ڍf31\m>6=@&,3s&L- FFxJ2,^\ ծs(&"( g*Ql1]{$P !%K v I] 8lwf8aj@4y/æ!T)c- hnV$Ufl.jE"lR,39I>$:VkJ*R)BN>o)wIϞ~uɿz}-}ZNwP,NX_R, T˫ ?ő$k"ݨ{ !V"U&oE:CMWkߜkֳkIx.sK 6"CTcia&Qpk1STP@ڇQC{e@s0HG3R`k$ T=/(dm{J[ aXsԴVmTHM |>.Zfԛ7qfPTNT!H7jr{ZZ;'b9Mw}2O 8M˅b^z̠mskRCqnp Q 3z ȋj=/ʖ1 䛬Vq؜aED(YQ$?v7-K[@JYԒ+:! b.Ժh#{EGvN˴Ě2TjBQ h]f:l@dA=^F=/#Z~=i'Ϫj$zk3}︀en{s}C9mvSIKn/a ūi!TrOS_ܙA;3q;t$ 醅4I9cD;st+Zz,'W"$ ٕejl (Tԛ%I$Kb"=>7_ @  `f+3LE^p7E2ᬡk:U+)&n`պ:z3o$hhTbA (׌.:# ##L]TD+h<}VabA"gF/@D_~5& ۼ ĸ VW=Lr\*0q΋76?Z/ n1lT$37F4o8ɜq))`} {N X@FF0 ZiN9#dtqvBuH~|3_^Us|?_׳j19 5欅:.!av&-,8&UW!@= | yuEq1%kUT3{eyc 3t iL`¿SXJ5GE##n8əcȑ1R$󏏟7"e8mKP_b)P(#o1o#T5Ϝ ;#Zh{ n n}]^Uuuj-s^c_A:G+JHw^;s?nsm|#1Pߗ2":eJOĈѫU*!퉉-4Nvn cFv?!I ќ z8oΌ%PU1x]/3U|UeIpouϧXMz:BzߋPIξ]]h#BT A@R]1nCqǘ:f6M-ЄڼCJ]jMu*0sB_f1zU s1,% 3x[q[v/|UmֵH]+>>f]"rts1uUv)~}]13:#l|&2U& W?5Sk^yURFud׳ $sjI$T30dI:%ϑ׉1"u_zz~~1FUaT;U =跌!"&תB6-(Ev.GJp $ȫy˜y}_,P;sdoG*imBeibXC^u5n#UCΫzUN th.!q1r8u׫xܪ6883-o9tCHF b+im'z^FK:PU*g7ƑH~=m 3Uzy:UL֒ncUAm{҂tV]5Hٕ7d[aޫHV6M1F̑36.Һ뵘9:O:{ɒm\I#<ȃ;k篗[*3cW8uqFhViR7s#9 ʄIOW%~y%vXV-;U6so…ML t[ob5"w>@ߧꤪx>Ks@ j 20ȵyj鰭 ő<EB<]o^cz~]RuB3Z17 N#38:Wʞc ukL^_-)2wp pB#=꾾^9n__w,O* ck vXzz ۟wɂl@S Bw$2cU]I\5$+Md1jԵS] rRBnvv@( %Z߲L)q\cyBvԪqt]F/xcxtqX6ՐzIfteǶZKBd *WWJ5bvU.oԊZ>.zE#g`qy#c d x-PC@459R˪+RǑX?Wʅ@rңAB#.{HXg_զ"91Kh{o@c#EuI;pQvā$6׿Ы}F^Ίi*;gH5fFXFZ:_keP,sJ3Zד<[^/ #bJoSI.[:pM?}#!I}6qj[F*BEQ X%U ##-:cbTcox^UAȴS3/xu2U}i0(ֺb;tʵTƸ P'@D WW}>H6|}-ux zCSSȪrV`4Bi{fPdғޓ-i?jI8O'm򖉯_ڣ@}D@dHdQq]Dyjm]֎Q2R0>@WmdE\f\@^v:1rkNҕ-%n9Reu5Zjl Ps#<_5#e㴵bZ^!oz9޷)ՌpK~13_G_Wzc-OṈuz5",%jxD٭k9>81bp?yk]@13ccD W#u)!ʂFG%ЮI*y%3?'H{[W(qj#M+2K)Ί*5 li~+2]ҵVFwfTjZZ98bsԷb2 2ݙպ߯'eU]cmC"֩K1Ƹݎ@/>~l`vF =_{y{hFG!|]~9sis [63H[r [vR2<t QQ{(NϙA[̈ :, #VAPo{#Ӂj3+-\sEly~ 2^SE~3g7͒ǾK%>Ȳ=l7c^l.YU i_=)^=- .#70X&V`D*2})@[4㷙=;hkHuc^ի6Yj;Xs&u'h Ġte_s#s֫@, e' r >n:ϑsa IDAT~\݁VPq@i [hHklmzҜ>=Ԧ> kJ/rUFF$U[`wab@`a{&m9v1:D6 ^]'\4{j`Zx}ED #??/+s<0}<I&zyD~^S7?19~!%/64HjᏏ?~}ui\OkXlAiVHiE߳3q?n9BhcsW]/h5I'yBdchҮ"jq빭AFf >\g1U兢 P8`]9#᭻91$"9"!} ->-o2xՅx0if턙Ey:@^K $;%t;1NYrn v7B\>A""c Ƙ7!`tG묥jjF)k [/z6g9VJ`ВFq(aŽwE ֳr^*\l!=Ӟuasn>f=D5N X8< dȺ3^KT[@F U ܟ2fŞGeX(@Z;^+NzV=jZ?>"om[E&P-@`cyO nDt%0qG?Kmi K2v7~˜59viBA$72Atuo,;nl6Lvka2LP񽷘ێ h16[fz=Wu(^*zf2 #10Dk0Z}h 9 w$PXk^uDYFp}Ǒ~.!ߓv1 n=[?$Hzn6 P4bu2H z\sL9&-&{3;MFHlVh &S[a ԚB ~ Cȍ"kV)>wht5'Zb( aXhH@>B0־Nn7 ;?b0j$p4Hc7]=Oŷ[XVB8PPt;M`A0bWPmt=>lm)*[.fZ8rI:9A=nstVQ`dȆʥ_Fa05 ^LZŐ-Hq4$D!uRTͲv(혶B ?%c$ͭ8E 0P ȿ偲(K` ~VJ19'P ]Sf.0nuώ8]BܡsTmb @ج; ˧)н_+""8H*b/VĒ$"lsʐPilѸj<{=m-oRﱊopOI2LU B-ao=K z\Q8F=DZo˚bvl/%kݦZ< طyeYrjƄ2sx@nyⅆ46P #!7Sj4w8`3V8fú@pHuv7jC6Jc/АHH Ւu,\O.LBWe(JB3Bm]!l a3:v ŀpUʄ??>v ( +T$4-R9)=ZY x{HЭrnv Y JZ}!>Mه3D] Ab#_N)ɪ )'<~:A1ӟY̾16'S Y$ޫ_`J9d6ű6_{kB@㚰}L6 h/)\&>۬)Pƫ_o@qK!^d Û^.qÕԊ0W/n8PyoJВ`O#9'˲}pm cPخ|{,.uu46!"4.nXz[z,D=vB)tVWU$b8 {M_&'Iti)zc1MT 0EnI+Qn<3nG 2np"]9ŦMv"L˔ ѫ O#`RќiS3mHo[;(>hloGpnw=s"oo{#\ Cȳ(GG1qUvieHi-q`i Fo{y[7 C#z`CW4zº @`'@dSC rnF9JEZ&"*拾DDtCڤy*.iǻK3cYZVAZ[?jb6jy@a<h0>?.z{ /!m 0 ]^5:H]pl&*TQ>btn(Mnn7A*)X'(tR@3#ԋD1V1}Reв6F~QBZ؏ȇrw@ÜL& GY$Bݛ78X۱:Ķ-ɪn4kωdNtcBM<.5SLДύ.IhB2 45 %I]a ,?M9kvdFh2m4~ze,rHh隫F,{+7no_*F#VmCZܓ3 Nr61Q5lx#S)6_b/ (%T-#]r]=B6'a/mJ1.41lWl0n~j`MM!>Dh0r7hm2 ./m 4({^Ђ;Be8՝K ͊K.ϿϺ^#MݕH4nGVcY6p+˥ v)o,0˂fD)HA߸s'wm9~ڬ:;#:vQP%s6B^Fj.OP c(nL5uCJ}niFw(@폷Y ~۟}k8-+WKظ+Kػ{uOޏ^{+`6p 1q$[)-A?_u07ҋ~_ u ]{ۿG21kJ"@1Rrv eJ)pl%[j6fIa"H[=hSIa/:lGn, =&R3hދl;O  6&i7 oJ)۴X6Om6ҎF%>n"ǽwjc_24$qP|kߌKe7']gc ow¤5z` ~զQP]}E͝ СF- ,gZBcC]Cˀr(?d`AI4=o]w>U 9DoXwݾޜL!=` Qfe~zfeP{B&F،TP^^p`2#[>4όMvQ~$ٰ!g*s?g>'UnwMz{Mv)VMNs{.xC{\JE>IUuc;c>4@/-t#;T#lq=xV=ys0IcܶЮ;[`r_݆;ګ:1=skFyIh/Nچ>8H#,؄?85xt !(i zXo} v Z }%)riieEKKFstI+-"1ӮoԶ2x+FĄM+B0`'f1GE?c*F0ƹTB&zkv^̚!ri(P~ DX== 2_obQ /]QnN;v`+  50t`bX7j1egԮL Ž !rEd߾6/h[B<^T嫡tN C b{h`\#B+\Rf0&ɖr?w37|e&%BfcI7o r*^_g8nH ݚ807Bw- 9M{+:`8>![k{];n/}{,ln87Dt>>ƯE~ D# W N!+j1B]vuֻ滾[@e~~|:뀱ͅmKp!1+um YM&=U)u`a7܄s\_uZҏ?~m9ίt ֍2ç]9Qm6݈ߌ[$;r`.261cO$,V^~&Ø~^LN)g)WVW\p !bz V7BhSOwuf]*B֖Zv@DT#(U3L''&&r}pc*Fb`zw6cnC"r{?{h[{X̭L6*1o~}R>7Ɔ,JOINH`qp_lKށl760!>1_a@\=mpA(3*k`z(TFy cxKB#7;*1ܢ}{s @ <^Me 0*-7SDɼiSvw,U[fvd~&;[WU8Y".رt?F{t|fܐc CBVܗ$Hhm~Q. Q&5jX$y=X #Y$ZRn |>nM\$b`lL*>@h:~nfLYr9v@w+g8 9$gFv0dAS(ٟ'"Aɒ5$gntc{VUd?h}A".:KoKWRP2*"o!+յU9g~&(Gˎ lppɀ}a循1:l mi#f#68)d:WTF}0ǃ \#ILVFf:G!(02KHD=Z`B+S!犼ZEPAppՂuR[ʂKbl |`:o1cT+;^նآ/!Bv>U,PMQ=(P]7`"!Po^1fӀ cT,& \`DsƶҁnT(<~qu`* GB4jR*hۉ5[#z '_E7/G-(rDC*(,55Uv<ևnL s}7ny-mP(F` C?? {+9*$ߺkC3(8yTε"Y_̛q; 2do7/.V_>= &dTD!+PEabS"b^=+5Vn]@  P&T!a@}!ⷂzXBmو`b= 8W{ Ⴣ^Kbҽ[1g_J.WnWЮ1b? D|"3Y-j5'vF[$aջm&Ùz3"f L(Q#¢Õ1iF'R`'qй}oԐ:p]3LzQ e*F q guݨ1#T̳^9+03"?ѐHD#kG<`C'!V Ҷe2l!<#gvo!-Vu,P{p j1^;/κijɔ0-̦ͦvgBv__e33$̶֕&w/1Y$OXT _^6G_`Z [}YTjb"m88AL("1YV~3&2 ª+>&>EǢMjB MfD16*DRd%ǜE6v99rcaݐYF cVWB:ߨ@Hj%(G&4UF5 u/j7z*!G# 1]`vؐ _dѩU\"@wmHW3U8TD7@&$ru'VlK["6k9 ,$u\? 2c-Î G-WUl @ xݣCC%ѨD5 '_M[ ĊZ vI휼`?CW ]ۙk5Wm1o$DmjCb;MXD0Eg,v ߼9}q''7\>&-Pe'q( j(!N'nV5 2[wH7Du!uI!V6D2G BvwZ֬f\䡌Q46[N֠hqv"sU6Q15x;$۷v/O>E&K(1*gEE&YXXeRe{~T Uz{ [cN/{!^q~{IU $2`0V P2d_cPuT%dD4 n_g'E~URiiL/6z BX'^c0~9Hu]u=_\M`SrOA͌mF#?|+3l`16M6$bh քL̍RHU&|2@ _0ު+ǁ6Qe OR440vњTxw*fFP2qe9Q%AML* }-nu LĞU)(nU0Eq+'j-t D@z(vCb=Q6T=%'v4OTzya/?~7#M !um@B6 =VsZ1e״  +Q hJA+yJ[*9Q@l 2"%3TL땋47땚d4W )$B?IK@] )u깁Pj4bMObHmr|uyfy>혥?fEt6ڵ"wcF`JLMZA9ME5%S F$qȠ*6X`h7[rNm۪U~,x`'b]V<uDu"75`9`P dըBN-^TަlGq8(] j(ʤ,%}k>;b7d``O]u6&i>?g/qo_6]w |Q0MxRy8@DS2cjmYwFT+z5nBƸ)cٌZ4 #.1h VPA$1H*x4ik8dHL;8m@)6޴kӶTOLb~!ZmbdZc 8 G#Y9Xp'ץe1Ej́|"JmW%B M"12S"[6E *h"Bތ&9R6ҽ ȦċNjtDdn~TlnLf|` HwMBQ]%V*f~"Wث׭iՂuK=MTa˝buVj N#cR"VM !1aSTv!@l޸=bm[kjMr`6EcKQ!Kcbf /d±m EKd+eMq&8eJM5"AdD"ȪlbR-X}*VDG`(f| a1SȌS7ou;7 qWfwvKFxp}?ojZaL9^b%kD)^Cs;﷞ >JȸUzjg[?`%6URS0jV)H`! W[`&RP@MJc0&6brVQ&]%ޙ) pcf[&A PrF/MڮÊY#y 2ٜyS2r9Dj^i)V͐#i" Q"$4UAd+BQ@+2#d &;0lF4k 4 jXR4*]K)*7"yl}|=yɳk7;QG70BJئ4B3'1d&vlYN+rԉD&4b/{ %R R_˫ 1ad p/V,*CȺU mN;mѲ ^%(0 "g Ör$Lt8F`s!6Q#X"aYUM&I *{Ve }pwFm"Y ,Ahvx,"@0FSC@ b!8 y.WU~]f(cU9"w#B"<9a\MܴQ UĊ&="Ø˨ӝp;_^ 0 14)ӺBEc1˗vlu9ϻ|k{)Џf jmKݿNi!wv.We)..\>TARC$f:{7i+`Oғ^:A_mfH*`Ek%*ͻp}7W!#BE5 }?Z)-؄O"DC6(嵖|xc.NwM1bJDbM R2"Z3!1;PdQ^ XhmȇaaΥ+B6uo0-ys!|t!jeX۳vl!cl˜GhRCB L^>=??ѳ?"_?9Lm"Sb\O?}3mgjX~'/9䓯N^, rY.mJԦx |aț5&!/";;w&):.;nZe=GoF3W|[LD٣EwݸKжq2iLlڥJY-/A1t !*3vxd>4TZ Ԋ@) K5k=Œ[?t޸\m WCbS pe^qDF̜a"2&a)bE-HCo`/yҦn›1_uo7I-}IphnjHĄ>Ƨ Dܪ* iAfRRA ] EsΨL=AbJR'(! bEJf079PըAa ׮ay?\l8D~{o`֜.|x_OY`b(g&4|y~դ4Opp򏬓YxT |lϿ woY(ĒQ{ztfHE! Ղ4юv׏&{c6JQ3S0Pwg bJ0"2 qwnwj1S@Ƒ]NLl(cs-H1` [-EV_?G;G`!_\,V;vM;faR~D\v c_ռYeɆbDkv€ňc RclZrDD%K)Ȋ]].GgWe~Njgf4@0Avgε-|p/ŭ^F >x;TMJ)j(+_=>;[{wwvw|V/B!(Db6U?hPfx=}8i yi Ri7 6hgm#EsMM6Xf@G:P>0#1&!"R2*%&UK4r>_^y]9;xڵӽb:D,"Qб [hx;Kr|5]TDBPFS8j`FH󦨈o|R"TbL+LsuXr  2"S eN!#,npVYuμMN JF}8e L']{f ތ(㚕mO~r~>l+f"_VÇn|qyymX5fyUaH\,z#/. ?63`˥ʤ(x`A Kt26^e"ݩ۸"@REVèm[ 9X^Et1ix<uR4_bSDAbR^FR>w-_›❃)*PKpEqr6;! 6^k2%®\~~C @d@`D(9s!2J)t~>bXA,޺sѣӳH 0yO@/hfhvzz55O'W:y/}_ch`dj9jf Ngϟq8zٝ}!/h#mr\]ke(i4PB&83!16)fAQ5S%&b"Lm;{m:a D1FOC9= FC4SOlb "#HE- UXL!"1ܿ67"02ۍ7//^{^ācK*CM1UYŊi͏97 nZT%T#!#fE J?~3}^7(JnCAQDF` Ҥ 2 _z3`&4g/O?~rܤ0oiJRTn]yy~~|1 ܟ.k1D( YO]!p#f48b{$0AL 0w'-٩&q 61Eu4svﰛ71L"L΍[ EY!`Q59tM4ws6o0ΐA607w"[7@SG+@JeEl(68.zDVeF+9.2\CV4 ԬG~Rj1,D+ʁLZFZ>|z,n(&@R)FD 0Bl[nUE 1v7G%,*A؆3ֱ)8 訉^ONV罨MOrWCo}W~_ߟw/^\ݿ=w\\1nYƾcHBQ^k/^^^\1Pk"?΍}(g{݉d+1)`&"ZM"vMZdtӾ~w6&ФH"PQJ)9K˽il#2Lh*&e,r.9`C1qY" IDAT5j9 xk`jYTQ(rȋH,}t񻏞M.2RA@+)4d=u֞,`av4Pk c bF%gf$g(R4DrHm( v#Y,5G7;ylӣJt>{Z=>Ys QuP _qC^>>y~o~;NϛI49єblR{k܌h>}|Γg;qS?~vH/rh^a/80JBh!sLju `ɢnRJp!\W÷4 hou`,UWbPw[kD5b5XB 0{엟Y-.cjoߘ~KQuЈo|l=d3@gi7Lo 8o܏_}gOyu)%RO_.OWX3~lLm2&DgL @F-v-18N~8Y%Kd(F>ɳs1Zln\?DY{JcIGbRTYCFq|tb Cv \:BZN%;?מ$8G@_JQ& Y P,wSбY߽vkJ* yU=FD0@S6o矼=kVƗ{aX/ nκ>xb_{|ҋ(p vz>2@)E!۝YoXy6o~օJAA>|Ub.%D qjWCH}dϮ6Uvrx;wڽCJl޾x^^"G˽&@ˡ"GS A6a 1a`Wjl4UGwxZ;RB}Qi,M^eaV})9ZN .Ei q4Dzy~yu`fLmA%JL&v};x̘27rȈ8횝iXn'B@)5"B <=Ӽ~ ?dœ3`V⯞/o%8YŤZjTDɖ!b)2o't;=Xٛo|ųzN?j3g!@VB͆! QuG<%,S>;Yp7C'7~~.ϯz-fu|>ϛ߹um5E h! ,¤S=CI6)HF*C1"dwf*6jMIaE(^Mjt˕TD^^Wy\y5 bdEk645D2EB12GqK@@)2<1S3iC #"l<zlؔ˕\^,E413E#"Ė"͛N.WbhX"x"@`Ej[2bkypkI4H.dE?4̚/t9*Y@H>@L<dØsK)Y״h*e1Z8m>|7&~b4ls$M#'SѻG eYr)9|=z(Hp78ƔW`Џxyo8rɗ>Owogvsm~8!4:U/{U@SSj1Ʀi1PH>)(QTݪ 1!q f<FEce!П(׏ajjTs0 J4`$&<5qtq~9Kiܔb >e/}qrhwu;M?Ν_Mr@!O &5o6p11M) Ѐ|ۋAhF)^vcaȊ{gM7<|vݳ')y׽8z :"\]O_n ʃvې^^ϮA5)x;D*"m0cj"34ml(}!"Z!jn&g MiiC)(ؐkǏ$?4ͺ۷o.;O6.<-P@޼\,+@;HRȈu2f0-@YM̐"7)A32})H8q30OԛhZrη[gefU]n{xc]7넦;231so%&jb%`_ Wqol8<]NjqY$ȼ Aڙ;uAA"C/_<([բk B${6ec SAseTWˣqZVŴC@`S۩ ;@v ^]M\m3s8d61׷Fżٳ߻r\ЄDjm2;[#&.˼QD2>9ߟLfH$hڣڳ'' jU;asGNjgG|9=>>XTv6/O^=+| y%`F0jy9>]GS#_)E@@d+ʨFhєy+3KxJDƬ7 ;fT%,sZ{EEEњ rhQ-8&tg/oٿOow}vp~zmp<떳n%0c4bP6*bW""dpNkvY]~vѨ1gr@fhH5**rjcm e16z۷X4#yb .: 1/Ndz٢Ey%l:_%?Dl fKy4~os&{gKmmm011+hʦ;;pmF(uD_dQ M87=O뭫n\YfeT\nNo~'"$2bܽ2 b`U=sfw?Ȍ 2daAiFUSQakDTmY!)*!)99ׯ_̪4LT}"GϞs{v1?:M|q9_;ۣg!/Użs]Tey[YI#{ewtٝVMr]`wx4^M}AE%ؕX} Qu!P4 <*/߽=~v 푵.C$"cfEn3( v>&VC blVN%NjyjYzŬ8>{v*Eu}?pz6ڎi6 B()t?9X,Kd%~.env6O?\45x<*bmY`qְ@L\+E@i`Eo 2Qj DЮ14TY 1 ^ p CLD{_Ժv棧I6\>O/y;G6/iE#3c>v~/ړw_8]h1U8\veM(_}珏"3J4BnOj1 +AR9|vtZ  VK?w><딣13Qog۷oO?:ؽ'8*H7O LF!5t b6g`;9M͓G{ڇ>Vt?Aa&>~4L 67Lu{ÅE=ֈ9*v<^\:2gSCxw{_Lj̴=Nbd`QPݹxVwMRk x`1׭2!Ld;7 $$ ʍh;mRGrftom 'ABv?FˉA|89$FSB`(`G=1\D$h&`KiF %u:9O h NUgbd߼"*Bh*:DtbҴ 6*N6?z1z5y>qeaEшc"QYîhH쳳ß~~x2[^L'"J+xDx;@#JEƤYGfLa4# $uR ) ݻ׮7/&< A_Vn"ۆ|7{0ltEՖ\(֢!1zQ/o`2S C~9m\-Z3S,L6FS2(hɊݿ}/Qho:v}7_9:ͽ~ϟOd6,OT0lֶV./&O^B|vyyEhCwg'67{;aT}ck6KD"a6'K<:U0UŻ7Ǝܠ 0Q$SFq@` "+"j lh/sB#$B4Q5 EO_|jcP;o/z=p{w{_{ݿ 4,em=Қ)3ECDb +F 3|}GcӄY-Ѽ'@2 0v#lo2qGz1[W}taAZb# m8R TA//ڢN'NpOώqd|>^UfãSCL'狦vtޑ!YAlPk;e3`Z5G@"+܋Ĉ?쀇n+]{j_zp{9:MJ 2`#_Lb HD$GŰNGG;_77_O/Mb0fKԡ^?xsT^ΗQΐ_{RͶd_qc'm}lRp8o{7wQwv T`biT>:Fc`6fngvZ[@A`޶©Ѕw 3;֐C#fV aWM%ȃk[k>7b@@ֵrm+__~L4t- 5Otli1آ-{lNԠd<,UuǏgae闿xɣgle|tP#!2"2ʓg/vFShF/IѪmH(Zg"޽7/e'jWConWUM(IMȄDέ|GC̝[g8e/_տY{ܽ{jϛ9GgϞ~>zvƠ|,qApڬng/7=?EE"Cd.vDLB9+1ϳnGb^F/C^M&63`0OhKjQe1Ut-w_~xv;[Eg6oώk+W<ǟ<id\.P d$2o|G/;oNZL (tZ1m]5e<;zq>qA4/f/+3_.:'Gg;׷mfu7FA@&,j$rɣӠhkt>mCܱcfPSZvEN%{PjY"K+<-kisJ?O^pQNyS˓O͆Coy?_|{sgp3&E7O/ӝa2֝"w~h8W"L;bFx4SW]cL Hjh jLXY L6͢杹iemiz*E?۽ݵ.1"*aN*A_~rxV#̾g,/TLA{lQ""b\s_|xpV\żkW;#!LA@M |aLIaX/^1Fye}1,{`^r^wn=*NgOyB䍫 IDATv"67-ۮ:::zmo].Vhk"TEQ U5!1ٕE4a2(E%I̔R'3j-1Z^p]袞΍?UX(`*<qvp4<{G@y]q2:EUw`$#sѳ\ƳʕYnN%Ph! 5 FF% B<9Jl޸2TB Hx:51EDV{Fb6 3C< :0$e p~9 J.}5xx_zM+WbQb<ca2bؖɥ Fjι[;rɱb—#5SѠV29C[#}mnݼwn/orѨ(&cʍkleG~/b@cLxdU"{4PCӕ(QVj`1E\Y@ M?~|Y6˶n$z_yϞ_uŷ{g<u@p`5/y[Qie˺Pq5r;Vw?`mR&ƨ?Y4F\]@X`$Fb]P |!P|d&@ʼ̳6`B9S C ʎP6V.!("r¡i F0/l:2hXܽ64`Tto/7p~_~2F^_9v}Fy9ŻLJ Yp$Vi[KYEGfHQZI@51Y0s]XLg wGev*ީ|[nկ.QF$;cgT͗2(n?Gռ--Y,b3_/{x1kE#r oުg͠4t“(fgYJg\7h>&Xw\7D#{O?;U$Sa.4+Uu Q8 be&&(%y$N{J  2^eѐ ڮ3 \yo׊|ϋ~eum|?gr0?){ET gx:;{_k;9j$bɊC2I'D%r~H4A{xR-u"EBȐ=XEkI Y˾o'ӌh \*vt*H"z9^¨^_=g ѺSAݻ+_'O [x^_o3vvCgw+_>r &JϾF,/@捭?yNȔِP{6G!;Re`rR+"(&9|I!4zZ].hEN^6om 7rkü/?ha/?uy`,.F4# ,׈.+bL/:*QgӋٻvJ~{9,$j1ld "&QM 9pk}֢jBn<"r;ss^2gc'vwm-.QFa:ĨѢX I{R:;QVӮ ']gO.[ (2(E>ٴ u֯m3@Ԣ ihV+Hn}^i^:b @"am?[t5 0ouVA6@$FT5NI<^7`Yc&'?:>g/z~rbNb/2dGDCNZQ3й)!Wu|vmm4b2fR2Q۶3Aj|Ld7Vt5F PI%h:e]?xx8M8:@|ݝiX(>{^XHï1g^<9Tiܿ.VKlEW6tk}pYO ]LfnM 37/6>mO'Ħu F]jjIh*(bPеߚ;$ՠ֩;x`Y2?:vAgDILU<3tF& 9nj8[tǧÓY |VPޣYvҼN1JI4Tbе(땮|b>[ ] YE&;=9FHYleTB54e04K/XҔKʀ~=&<*a[͖@T=qQ)]/7:?~GϿ'Owpogo,Oև|Q{Q%ƗsT%$PbnыJAM"bh%Y3`o]?x{~>m[UbdqbAb4nà l5]#+ Dy+ouvzѶR5fF#c+];d욺EGQ޹9l[Y.rj'A4DYѬ ڈDM>X37mXTzi:XL1r:%c $9&8%"qVrzyp1o2Cm1i_yً۷oNgM̀N "":Ue0Jo!)arz #`ms?^KDE[4 N =<;?8/շl^7u[w]5[|v|^Ř\5XY`—Efb.FI!|啝?~4,I hBi&% Vhz5JWʧ>C ưG'Z(`cl2 ?~2WwbKvDd?1#!0Dw+1at^uP0S ]؄& > TuE|)RrYƎ[A0 |ǃ+{~vAY4Vb*Ι"#%+-K] Pd'3 s"hCLGϹ<|zE;]vh?9,~䏾3޿ÙON1%W i&S3uQm Qhhc* "JlZLt(2`PfsbҒYeރPO`/gVͪdg>΅(Lȿ"ro1z>,g#lUaBBN* 9T`Ҩ]* D@ԢXlitRIC&L>0&B!FU:$HlXxgLB椭C!\]euJdb$ Qp5Ie%UEvHȄ1糶^:@ФEFf7v=Grtg,"BQOY!ZQ U(ZE4Bk:Dڸq0a*@P.X2""0 36B4ԍ6d,3_"!w7v!LjqVn/Z&EZ!8\H),9窶z)9Y6u/i# c lDneM"6 ڵ(4TW|V|Q6d߼?F1*x2:g^QUCgiĀg}αJAKw gg:CQQ&@˶`>oo}h 0)20!$c"eb*bbș*b Vϧm7GVnL!)F`$C" 2XixDH0 ~IWw߾ч;2DdS3wwJ&;JU$CwKRMc"i )N0U3f&$eձ0Z]bc'ލM 8QBߦbp'M]_L(ɑH@awïȐl5^Fu MXvPHbhSt5,'NQ0Rh {Nb. /?xh5]14"b"3!0$ wfUL<(oڨdFFLu;݉ꪞ4dwzلG{ ^c&Tbo5힝/G][]Jϐ@SUrv2+7z(83J-u0pHD=CӒ.qQw!*$ɐ83:՛+rx@8]QF[k~+Co; QEpQg/&'/| k}+r#fuVHE AUT-՜MU MbP Ћ:,*)X0,teK aV$QTl1B@R 9m"g@rPaP8L#L ` !F&Rg"F4c7/]cX2ASU/&vk{T0 gsuU\隮K7^/9#kB/d:׊"cPBcBhJ)05!.j Sڐi f% !Pɀ/9,Gqꝭ1 #thtww7noorfdP/ ..PAELM54Mc')dFMUEM L@͐ 3BjAZ$wC]-4BJR5"M+-LĄ`QU#:Ec/<`llQ/jVCR6l\(+w"U;g{Q7o727~ o֨ػBЮQAB脚J%M"&z$02jTĠ6U L΀)aP([]HyI)&F qYw[Cdi"<|ኲ7(J/fۯxۋi=,UgTMH^A!, URcd66KDD4Cuu$4+|;83398y[7kD LE "@PgrH#(&ŹP牾'S(JFHt6фeFbkŲd̀ e)=ƵQ?Ϯ_{ _яݽ+ΘDi|Rv@%"Kzd &rwU$$Z1% %aR2IYc%b` hPӋtYٲ~m"x䬞-,(2X7lEARlljHh1=R@@>s"da:#SYU-,~W\$9hwn?|vBfTum"( J}޳2b+)'aމU{b4sHU GmFR LjYD0UV٫&9 `qab>ϼsK:4 | bqCʰau4,0_JNdyګhD"E0f̲41LD@AɈYԐ MtTLFr/O #DTHT#2 3ICPb0bB"hH.7ֲ;.Ԍw*3<@|s[;G Rd;#Q^  N)C@Dl';,rM4VWES3b;[Zlg*!}l_gd"P ƨVN)*ݡU  ]JPSHS%E2*˜ Uιkx\ Psq{r>/j:Ͽۿme;:_zne@ A1mᕽѢn\qvyrq~\|o$0d,uyŀD8([]]TjJvzW j6]%*h D+r⼥ےWwD$@j&Ȉ[0c FE *ʌB׌/ݸXt]D6Q:>YLNON.ZzB 2eA3bN #Z]P XhZD{RAFb6[  NOИ^UX̚.jR͂ Ѫ^sVQ@eeɫO&ʬQ Pb & >i ȀVT`AM 3DrH3":Б1r̗"J"4mpt:y>nDpts}w~7!NfKG8kBW/AǀMDdОkbgAiWTR `u4PpiU7 M%vcRXzc\B-^xZFyN.飣꓏!~[o ''.* |1tF`*b i&G@1CC0VBA&Az1F~ZZW0 Q M "JjYbk *PJ#,ȌQ[ lfB1)ٙ]wTA h mU3SyEmaJ//F?^ŲBSvzwmQ- fl;P, J l%pZE'C!]Ht262Aj+F@*JX`Us&D%#6iS]]۴-xt, 1 0䙋w9SWe6ټQp] G$R( jH@5L?Q#rPM"b^f͢K=tm iĔyhPE/$N'X^`uF()C f.U)94DCU'?˲ 1Yh>g]"Y`fJB.h.' [^={VOguDٓfuݷs9geUj4fhiRB$EJ HQ4A r/_/|Hq hjTWUVw8gs~@t22g~kmɰNGX!Dt!zƠ,8Gw|v (~ѯ}&Է9`$=X 3~b>q_ n8Na*06BEQGWs*%*"N\X0zN 1fb}^v<ةܺ7˨n7Q {;?s`Wg/Φ iQT 4"}y‰Mn gUU -1v"K@e f҅^LC, IDAT_"0h…րM:P7N"  Ӄ{LE&D7.DJxt-UKGr;['[yab&*LE]}u|1*oZQchCl8a_FQ0@D.#*Qn囊`Df*'WD{vK &,YW&i"Cd2VU9i[duuܘd_̓~txdYm\f{ u%v9=Br`ѐ3X->MA٤ʗ똾/!bC$S3ś %ŔQcxd3) of]4IwrP43Cbc#h JI,e!h`Qe.= D0wgΪ;ӳ97~lyzv*)هN6v6Wmb\yeH.D b:(?<2W//U-B 4c@0`FG&v>hT 0("1yν{tup;.2 omoΗ^ ug.tmbԻU @?&:}d mL+j t8HR%ur'g"A@WP0)]xsK c |ӵ4DT$#`.晢 AQ M;IpM/g8:DEH^'O քNU(0_vWVLҚe뺉N+?z5 Eݝ)C,g2TlR3Ppj751DL+ dLZ ,ES0%%@M@5SDG |1y>3OVTjIU }~}]DU/.=*'|vV*&>bPPs@Bb/[@`uEIee6haL40&|7 .sC#Y_-k DcL!"$UE5r`@G TYMlV%DHc;XE "``jj4)7Ŭ^]|m}aP-XI|ѝ-Jz_S"%1  (qrPj Hp%VR.! (S}"YHmCtwAv &rc:3*|O??=>~ 'NgJgmvUzAzOX#q?p[/O}sSKuhZ]k ֭?9#QfÞؤ^!h46QUA!JسFr]@L)5F/Kef%"DDaՄպS#$ bW3C ƿ/lu*ap{;yj~Z ,)jޓ!EՓf6k>杭:!Ĕ&SM Q*b4/3H4r EDf7Z" iB$9  ǟgǯ.ׯOfO|P10a鵒5=Nn=xqt:ۜ(]ݘ@?K'])M1: jVunĠL@!aR=%iԢH=Œ =W@>3GHԒK7rR&it!FŨ1j+g͂w@ӓƝtzulmvbk3 `Ýq> ;t JtWO7 +$G8B`7E=>w(Y4"`O?EسVd,'CP^D cb QЌ K3#QH@ʘ00U 'LVm#(d<:U`1L( 2Ϝ1'bM"44=fӴ'9eEVI_$MD ]{1}8C-#8{ǷܿjgQ *߿/ݹ{w{<Бwcbn>R|" K9r3#JRRr8DA7)QY\z͐1=i `&390I""hHiEtOVY+39" Tc}$0`ts\&`h}0 ؕ[@AE6OY 9]Jp:.tUs9J Qb\,w[VVQ5[4ʥWWpX /_%) qOI#)-CFE0SJ[b X",+fb~:@BjH9J2ș 2p VI0ʌa 8)7PQ%2y VDTE$]2[7O:9_Jϰ=*j@%G&P8΋|*I6)Ҏ}bi @O{O J# c8wd{p4Gװ\8ꖋjuX99<>XkT<fjɢazI$iRya zSwҀD+iY`쁦Jyƪb*Β}S܄ lZU;[Y1{Й$&͘@SbḦٷ~W $)٠(mn׋zcsSE_:0eAYf "LVb{h$ a&@8H6u:@Ӏ")ʼn=q0Ȑ w7loͱK?_p?x<|MknϞyV<Ɲ'ףo  Mb #R$x 6x}!XL]? 8h$Ą[HQzU$F6 u$){UIu#$ʨreW:=U~F$UTFjD_ƌD5)vqށZ<繙Eta6_K?wi"H fʧlEɕFSu6O*uXnflHBm6DrG2&1wÃ7oߚMFng2kvo?~zfk[E\#Z;lvEse7yiTLW$-QHf!0QYJz视D>R27i2!Bd =ACvӴ {S sr'&so.b٪Q" ݐӸGhݘ9;#3]Fa1Uvwl8,]5RQ$"6WndlM$DpXFCt)\uMBysLW5}HS e ALP8ڗ~n'ϼᳫ:*EӾ@:6˵̛/A׻;j0S$yӄ弸Xs/~e'fq4F~'G @{j,Q4RRXWH/"t|&!gS,Z A>E$fTC%܈b]B]W}ΓA~gg/O?zX' g;Mu-d`H 7AVn:)@TDD$0pPĝqb541+:-z30AKP"z(I`ȨF[te{?s*2ѓ-gg}ټm "@4 F6jQÝ^;sk瓧y1(_muų?`'rld1tn0ĝ'?>l d^~rU1u$AI?~tolg/_'fUB7FUnubQETKt=y1!"6ZprXNtư;yw}ٓot$i(QQxtk_|{ʇw~;UYytALz,˨2Tj%"A3sTgO I"#p^ݿLUY0R… QTAA4 MwnLFO0*koWǟ_GG2H@N'A\ҥ(s:dSe 19 #Lu)).ay-*v0=~~pk A=F[~ge^t<\.8]QC4vphA4#'`IJKs$q FdHu2"2cF]l&RҒ$xu@.)&#:Xg񽟜,p=xB2g݃A{;-g+Ijhh6bvvm ]&"88wg#Tvdڼb8,ϘCPYZ2ia1$ʗ羰Q_}*u)G5T骊v6*2lFDUJ44AC^aLENѼ~ϏdPU1q׆m {Ue$R% 顧G@$Ң`ps28?oATTR $EPLR Pi:~ EeD&"1C""ZxKtOϚy AooOFƺ "\.CZNQGE5.x>rQ8Inzu݁bbpD{ʋ}&!j2ݻSUAׅ29LPξ/߬^| :TUAUDAOu+0jQTCl(}LbiUNMfs#2eBxbk: xe__|/֮=ݙoOC KL4k LlL@wFd]%C@&k8_ **qRJ{;C36IJUF ɒfhL8W&+?9_1Xz+؀pX{㯾ypk 6 ʻ Ք,h5ޕY!B\fĢ*ԴȊ683˺=Z挣AT% A0ZF()s1/X/_]_ϚAiI_ A #@Y"8#4öدf(]^3 -W뫋j_i'Ҵruv|[}|^/vnޢjώƽۃ,όۺQwLDH.U2 ltiRD2gU^JA݄^0 HɃ'!B؈eCW8JM9mt`jy&@ a^(<|3+;ohlOKҢj;ߡTh2y%DSw̰A4\FrPY f*P@fB% 3aBOrŔ]jJBl:E&u@"*@HESЈw7HhN#b\/Ymӭhum-Qm6K|Q;y9FŊ]f?yqqyquk_l 2 ذixTUPIRD&X4"Bb@i"w*!JH/ AL!P߷hˇ": %KoՋlQSM8#GyYTE9ݚϽswsDuwx;{l|&Qa8̬)&&=B9,{b"T5Lλ Qz)ELCn< D=zqzqR붶&1Ʋ([/gUr1 zC]THUh<wMGeӳwךU|k1l0;[]<=y͖h<*3ߵ-E'Z!!sdYETS}SꨪFIyB24@LZD)2 1ꭗ$ g"!9?pg6@ƑYY +v7qo~* %_hC٬Ʊ8;ǎ٥<41fg;ɰ"Fm IDATG}B׶)+jk\fwTCƠ\']F Fq~Q`i  1@fX*}2##ic<X #Z.g(Eb0ޜTQ޾s|sZ>~vdk:g1b},\4=X^\~[?Q$(|/ /$H޶z6m#*8,9ƔQPE3b%L}J ]gb ĈQZg3E*ϳ*oV?d3ÏD2Tiuyy37<;o$DI !"C8gzH Q !>5$9ngw3#DUU)g˲%t xrBȊ3nͯf{d6ukrvElMVUz5}0I .^QTo&B@n$P2H]C@`u @&ovpr937D$N=j Jd 40j heF u w~t||%Kr( ݭ(4>}q~|Yrwu״]g!3"I !h&ؙyy1("#iĈLbf D@O;[ӝX .l:$Q }{E.h0rφv$f1j$>KLjT4 vAn[T#dж!#ddUloT[ڄSc@ !/j<&@B"Lޝp=on]IԀ{umZ?=aq(PӗA9onH !@OӄTQbGu$sԾ 9Ò`Tw<_x>^Z!dfUmx<ًu{ܳѪiOW?+?e8sD` fXjH=1SVѠ2R;<3yhXh(27M3J9 )6f(#S){ ̘8;0b!Uޫ  5t(pck"1kTUH"RUmֳjV`w1F%լiՂgx\,f+S6pڌ)USd3C&6B36WDF>n @>[R*$ gr[a¢<ʃǗAAtPdY.3pT ~e=+o<;,|_iP7 @;ώ;Q(&( y *F/rDJ m\e^DwӳyU]ȹTըdf!.H]mT1#VI*vJ35-T"Mj06cjյ^6:Ե!m4>uve^i|to{{sdA"cEv~㣋˹E޶mu\^dAݪnmHRM9!"a)u& XSc .G p7"*fYVE^v6۶ "Z1b(6]1W3$*_/ge}r6;zv fs}v1gMh[[Ct:p.uh׳*3a% "FdKlzlb]޻()*ȩ"C| A!gdݍ2?ENGcwno'WOuQ>?׫|q>~2;YFٜ?% 뺋!8VȱwGu۵m QNfzsB*y5ۦ Պцef!QF9*e[(BȘ*MFEN H*0' #&+a")iMTMVU\ PRjNFxLDʈ zg9syQG\,հLi6\\-fp Ͼƽ?zYqDegȌ(sWa{{ыyhoMWD}4UM RmyM+QUb& ޓcJYüeΡ1З5Aj>VGwݺ,^(O>}ZT/3w\[XPmB$&pU F|Zu?dZ?w..uH8ln<9徬 cjlpǓLJe[DK<[ʗ_߹\t/O *0-G\%h0J>.he@hLňRL(F%bF.FW*0@w}}> e~0&|Άf*Kΐ`j1~//㽿ܿϿ_CQ {gM?yrVo[?8[@EOY$nQzR7`a{ǼyJA9!0Zɐ~4߿?2'1(дqcsUyj~`s|~}}?3ʼ:Ow'W9+K6?7MhtM\F~ίVz%`!t ] 8snXmiU$mwl.g嫳[[[Ӧ.̤*J(B 4t6Q4DVM}vvmnmqȀ|~v:_,Uw7ǣj?}oVd)pXTeLB%3f\*elfGyF& @h䫂3)ȵA(|L1HʂFĺNZ`'ĊܕUpg{;;OO.fg˳umg1n4(;ݝa]GiZe-YMyyFb^r-eEA9_~~:ˇoXFVbt]ztk9g" ϒaޛO}}ܙ;9l]X`IMY i]rRIO.\eYEIdeAE܈l};pKwy=^=ӟfI Z h(V0L POC:O@* 0 &5%'@ 1BO]@!2@%:IQVr1J`8j[7è5[^"!$`b96f "FԏlNȔA@`DA aLI~-9i7Jg.~K0J R+<I*@F17Fܿw?RX#5g|!$ڶYѳ:(.VRAb^k^DF! 2B\*z MC&8D@ u`ڌQ0 G 00Xؖe92k ;'O,%(ʔ ۡ)9f$ XF(LT+  ʏ0o!@)|`҉C&Pr XsFʈ23 fMRAc  K%s2@lJ,;9eHNzrQR($.h`"sϬ,V}?1zET,ؘU+FM`@=~3G_8:8[yoWxV!hses3) @Bg\Jm ;{ѧ+@mTF͍QJAkLE[,2[/kzcD<_"Oq*6@׿e2L)rTLR1*@3j`TX'faQykRюb3ʴa˖VI5B i"4H+BBjPp$~`lI0WrL~@:ѓnV25(v %0Bdh :oT &Rh%aL)(Fv1Iȥil6K%j%J%b8tPLIIU+i(c%=֮+}׾x;_e{rڞqkVO8̢ M,˲42 LH-Rim2J)Í{]!LZJ-Z+eqa&DiqIS@F{ 0]:ӚmSD!+ope@_2YR`4s` Y5S@ F+),s,#6o+8N\ +ՊmQ1 B,R!ъ<4Rb` \2 VJ !x( ʋ\1!63P,ݴG{XM JԎW|nw{4&FT:K"D1` 2cLONʤM"+J=Y~*2Ã!Dd*͔J4%PH D*[j^y/ܼшkt2*%hmB aT,˲!]4UR810I*4,k۞++ME)1-z#E(4$:QPeM K(q DdHtWW(3ҹ J'QFs@C gʂЌ`<<<<<ވF?sӟl?Ieffs3% Za!2fK)A6!\ٞ8ũYc4 3SjAdeD*SxId՗CQodB\I"Hu,t p.WJL4IʓLEqY'qqsxf)FliKL,1BhΥ2X ywǖ\B&8M44 fQ!* Shr '_{~߬,8Όz2ʣ q9"ZBN2 Lt8+OJ 'i%sf; cnz@!LV0ON# g|kpL\)R5$S80B 8A@׿rje8\^H!&4#1I 1&׆OMo(^jmF0@1B6Ka3|N0 HʪE϶0ay)9Ovw&B hz h >>q=Q2$t?8Xټ$O"PH x:_AA'k #sKLΫtJ=@%1qRE̱Ea?8J*Ƕ*9SVJkӅFjTv:?@j7sMa`9M~å aDȀcLuJѣKO>1ԷHh r3ӻvkVp#re @hc@)QJ"1J_zM¨E 8SOȊc\0BZv PZJB$x.%iZp]`ƈ#\%Bāo!2WՇc?h0lzOS ?Ttm!1Ţ )DFr16R֧WI7 Zq@Y9rڙ /N !(6Hd+49 F~_ [zOB `MDZSr HY7Jd$QS_{R1?LFYF eN|[ " ň֚ PRk2YQ$q 8M0e7׷+Kfs`Yi+1f8( }?8?cA&(V{g۟'[w `:1ZQrCҗ.=SoϮYo+>}$j#evx3[_nxcekgg<:Jx2n>^w=?Ier)$a0#42K ٕVwp0"Pkb{иEo4 ΞZRnolc`ȅt}d RBBrcB 1R/ X`iٙYʧAd 6˅ YC  ³p@ CBŐbvmZ.y40|[7/|W%uav{P 24pq#ZkE΁~sB8KAs(FA%4N^X# 0TJ(΄c` WZB0Nwe9WiT*I;sKR~M/?ï}W_y~5{0a cHM?Zzܻuu8*3=7/rzu!L0(a}F=Wt<޾}+ G$oyLXb}~eeB{!TCD?u=\#;RUCJhv1{{QLcF/s }2f6c̖O eeνh{tN48~鵯!!c۔mf48ł(RJ0+b2 %Ѱ4Ә7*P*BV\GJ̀X(ئ՚ۭY˶1Ǣ0(e,ס/OVPg"D]5aUG*`Љ )Rrye007n=^>"aY&0FTkS*?<ҐQB FX/ۧf7P q Ҍ3B4* pĬ4 f0ɤmYe%u&"4 0DPʴkpf0^ O7T/ߪ-4ʯ?d?CbBӬR"Pa4JKcěpnvlIAK)x:Oi0Fk'WӌSlł(5˃X>̹N^7m$wz ?*Bs>c~{[{DpQk6B;;y|{fKՖDkQ-zq& ( fJ'z37 Nz7㷿'?=;ۘ8ʢ LP+P'Y M83RƧfD1aԟ]uڋ ĩ2%GI*x5O΋gNt: i^a x:=y]w^$><g,6: m[\]tgoxF:h#"H)={|hCF T( p;YH!bb3*xN] "3D4H#MPD oPD~5c1\hQJ6U0NDO' LKRYƟ,z*+D AS)!% B3T`J(J!K%5_!@,|kW>x{s'FޢUG¸!*F۞,oHA&͙zRX[[r#ǓYϳݽ1>xNR#.Si[LI $?@8򹋮k+-ZMcd4&ƓIb W5H.7 7o>l;ju(BYc"ei"r6vŢWK̲Tp: `ko\'i^#nPX]o%: |Zl4{thWȲ 2p FR)Ly4L*c3ϵ1Bxo:V^gI(T '8-77nNN#8n}kyasFOn]~FT.&~d'OjF^_I vJh!B (c`T={mhF2TLv _+w~bZa@Id G'jv8ByB#ʤPHbLj7;`Fo(TYw]Bbe7ݍdaqqmeXlx{wYEkeƮb{@ @&!yM^XT)14RTVZśLO9fX)%˽?v mvӫ9 ӳ_~b ʬ2gJ$"8 ZVk4{L9 bBpR!~{y,^@LS5NToVtwa`O/<; ]~~? ͺ;St Ҳ?=tG(m͵Ox"0O?|_k}aV/YA&Ra)nT6?G˗+8V\2 ^o|GンCHW>{ᅋŎ/"`;֜P_)PFc!EE%<`h0J%DQآpldHCB)h%C * rpHΞ]a P`•J~1rkF#qq/#-= H |9MͻdN%V0rT(LY%Q;&?O~pkWZhB٤X,$3JAs][)PZQB: XD+IY)QiTzx|HsFAGh<ϯ{ BP`Y'ZV*?_7?jcS5(>_/{W.\;S̈́}w; (I=ucGn},dbۢ5_H%h6 pyL"qm њkӟ$BAe:vT\"J׽X&٧WO{#]r L4JkVz8ML֡bYsal|Jic (ԡP72SOj@2D~?t?G,_aTj/:\-xgWVX`͙cW-Rij &q=Cqڎa6 -@TU%x`!K2:}0nQL>:q8.Yzѽ$ǩGdQ{s8'fj;k!F7玵S܇}0 &P˶r~HW_:^\g_ܼ}6Z);(ٽB{fv6 0|V)]^7.^xZ⑕7&"_hi7.jW)eڵZ= 'GRuν~,T8Wal@/RًksΕgj`F>) ,L*uHc҄qU[h]pȵwK&B#Ũa`KAϴy2zrL4Wn*_ԉ|vk(Fo|嗞{Pu-hkb`ld1hjEk2$OGa4 xU:}v#<`R1foml~޾iP8z+_l..כMida~iMg>#DQpgc˵?RMp{ÝTK"aXnqo#r&Ӈ;>|K_7{ڃ;J>Gtk_mp|6؞Sڝ61Arq' GVa:?Q05E|啣2F/k S{>N?ȢLw84Zp1( 2:D,FQdL ť( ?HG1j1H 腙5SJD .01JdR֊8J*ߴFG7ή\e;V`6kszSϿ`(87jQ A3S%I˭M5hzճ7P*hMJ*cM|` IHLzR(% x7;@fmPJ}08[t- å, " ;ca !LOz@d342/,/#ͷ=TpA-KK+9Bl"VloLF]FivǙ|G]x$h7߽Ok FU-s/(,A&S< n|˟s)GQI F D 51% H- 6 +x3!;>w>~N;o-Ϝ9_=O{"pjT.xB3%dfLҕJ9"rK?hgJk'ZNvj {4m2׀L 0&Pd!OJgc3rf`{h AȍV' Ё}?L$YF!͖C?EZMljiYڠ$lioqV)BrN$G]J̱D"}J!,9iwrM^v럼4E @ $!B]_D+q΍Lc$5 &_]T-~`8^\^<~z(bݸͽP yW>'4Iyfb4IV oֽ[QGz<Ccğ,= Li1ĵFNMF+?x DF*eQA( -\ # lYAZ(I%B~ G@7se~_}ig;wfM4|dh0J}j*zE'%b Pl;_?nKY2sܹu1͹eL{sp)fY ˜iNܰfn#_hDrLEJ`4R@s"`80Ԃ+ TPH?4JiAZt4J2t 4kT/I1q x*7?ztwR-(vv; ۲y>*F#4F'Ϭ=un1R?#:氻4J2F0&rj͙A*NmzN&zdhkcBqpa'/YmcBe{EZqGZR-;sS+?ڝۏ7ַ;řG/sL+Tomn '2OrcB Ę8nzrs\¹p○^^}G#Mt,C';wnܿ3[-Ɲ`53G{Qt8 ե6g+E.ZqqW,ٮ;KWgN1`,E4_F LbRL0)%s, +XFiA R,`bQ&KӢ(HV*&7m? JH~s]o_l52꽃d«/2}[?2JDzpkKƽbv}t- S)>?~+]h *˘EfRH|=ckc7Su=}6X t1F\ٿ|Q=3n QΛB2B)Čbd{maBO ХE EdB'YR{`ˮxy?{jһq^Ql/p3gff_<{CIgq֍7umoĉ5`L/5/=xg˳BZjM-fO裧Y~䀘A(0"0[SEŦ o5Z➇?ޚFiL9aIJ$tL(N-!x+I1YaKYnuuƕ_/~͍$}N"Ra~ҍٹ$VB3VU$ ߹rN^Nͭ^Ϋ/=sw\[^];{ Ψ(}H(!PIDiEom&S৒j5 B}Q\q冓ҳWZ֊}?!:37{csp0vqVXyG7\~k3սw$?-⹦'?(]ɫ;sLZ#ogi3'?T*|8q"BK@!`Iu=ym;QȤlhV0>'|EB#=?c?3+?\;M"jw[Ͻ3 'p3{'s?_L4t2tuݹ? G,Þ$m/,OFSǛG{̛?B󮻏<7_cV>O4hws=X"*EJ t#cK$6-a9vhzۭV"r Go60YJB ))=;BRR )(uH @罩nwg[g^{‹>>Dc JS!m0B$yk^)'ʹKvt?ac⫗jvqɣ:@ }>ģ:zp2D `Y  J`+ulpczPoOR3ߤn[3HVbE<J;8Nrk\>t?3X ixc}‹όIe\]}3o?-틻Z9ҽ8w!65~&I47vO|;7SE3U@+HR,-Fqe^},h=; y1 sov+&ÉtHCiXG̯ꯑ;O?~ϿTGWOyVYzýAoܥ[{ᨪ:pIL!٪4u8G!' =Lyx F2לI-`0aJ..!@EtfZ:$1.*DH( ;w<8Z`Y=%J&xa""?o/K*A#Y-}ӟ_oXjyɥcG]sWk_U bMIF|V;3xA6.Fƻ{??O+(LmT/0YoqhodUYql4ZCGcLk~a+Fo]YHQ7w6 EaC$$KC0!7+gO8z[êm`O,PTsC(*b$$)_rNȞ )*~=jǓ`Aolp`^S{S՛'iڍLB<]HӨ"{?_?rs+`Po8,Lw}skOͳWYT3WjTv8,*7/)%5cQ6 Z-#lWЃݳqřvh5UĴʅ6PfLXFQw~n~qKyjd|37/4U5uZƓ6sp(@ǃSyJǤ"pﲵG9u 8\uon sc<$T %TTI|ޛs-]kA)TWsʰ JpS@$6\@H8v+} ,$S~ߦ y ǹB) ;spEI)u )RH-꼯 lxw^x^r+>ÏO}vmwwj$s w>GCܷ8էm/-_t݉L3tgNwR`eb2Zq|sowua~W~{t" q֜=!aZ\]IU^zͭ~g buy;)|E*G?O]|sgsww{J*$URPG/xHRp u$J!Iyn1ֆx߬ <%(wf=Ǧ?)$i6c$ T2BO5߁t L?L3_ч/ᗿ~_şΝw_°7,&F`jai1͒ob,20"$Y~IEUx\|\"lWY#4fŰsf! )8" $5]IylM>XA*Tۇ`~H "B!js*A H,V!T*03޻zrQh괳fC &Qd4IH,2BZ{"z~2˺L^{W;+/Gċcw|>[hr6O[I9/>_Xq RL򡣇[NW^Iq!iI1|7J˺'h_;w`x;u䛻o9u/.v<G;>Ͽ4A(Nn#K?GS7_PRY('$K%)XJ\]{$" 6T=@Jm]kV$~=9ֺNHJ;")HZ"!3HiOUa=3!0@eMm]l҄rw7n|%PJ9xc֍,Q,@j`:;$fb{H+Rb‚[qcۯM,'G wf*#)_ij6b\L@P'tjɇ>EIRHv\2F.՚f53R6׮\qƵ0{S':ѝmE$!F4 ;NV3%F^^'^lwq'}A FqB!HD $t"S4e{+#DR PM]tZ~J'FD0*RrB+bID D)!%1UU{,4V#˲4p{ԁNRDBOc A @*6@‹J`;k@F08gʪ+ 3 THJ! &ZKyhePNl:cy} [Bc?_P:񵵛7n"V9/_ݸC*_{ZoXH94Z)(Z"-{\=̶[F1ˢ0'OiEn$I+`{w;@x7_d@$B`3 BJ"DJp@S嵩ӈ`DA :B2虧'^JAB 9`l !I0 }0(pǷ!p~:)a RIL&R0C&Q:Q@I!Dbp*Z˫*k/t~Ʒ/.[/JWg> B>x~\%d4iy!ʡyL@ȦEYX.Q륬޶vŝN{]\\R`8qnO5byE;mg+7, lw;7o.MC7A A2$dRHuUc{zr* qSo4F=h Gsw ߆Yq=qD:R$YLZ IEU*c:o bnmޡՕV)I/OYj[嫷.]bMeJ7S@ \Ͼ>O}slud#U; @)Id6X{DiѠٞNxXGѵΥ[^߸a[Lit[4i6DGɤ'v|xuvh<{;ho\ڙ;{@22R@^E APs>bSaWi4tDd%fS @!0*e0i|Z֡kXomiFu gY(*F (*?s܅+˛|Y8N"pŅFDi'F52@71e@9Ӥ8ؕS"`)NrYAi`Pل{kk/!ܺykKvG5{8$:zrӪk0jUU޺gwGL@Z Ib ( @6$ĆR∄:) H%@` Ĉ=i\ޕ1MM@(S(jYK4k-Eg4pԁ IDATpCej@ DK%M68 S >L*Z)`Rʼ/؝I5DHZKkd8RlUJ[ J.-]E wǑwt!`2lmm>i*Ouwa2gsf"$it2x8043XьV'rʥ W68yxfnplr_t~lőw.>w$/9DJ(D;!єw)Rl4Gq^5@Y'DfTL;R)5>u$<$\6H4KUYr`BB)akOF(T0)qi8RUeB$H%IYS!K,ɔ{F뼱-#$1 5R7*a Bl0a<.TSyPR8ql 4Z*U9XTMrβ勯w!>@B<~ 珟ҍk4a^ĩ& 1"N#I<R$gUb'I3+JЇ?lv͍S9rfRRjKkو17?h{apC9ضwnx;;ۦ?NZ:1<3$BJ, "1\-B©5"#"2p{ oG3Ω?\B%I()#ϯw/;| B4 ű(0ÔQL{a|O~3g/g?=@RS$Leho-.*dGY @`>Pd!3Àa*yM EhcE􍧾2ݴf>21 8E]֖#0 p0c DD5T߄HLWK(`Lffa6 >$P"NqS&x @lΌR(!u xOIHсҷ$09!9YTDZ:Ra`TE"tmhX:>x"3ȩ"Na~U;B 1,o?3OAY`a" *0/8&^Jo;y1I 9?uf plVdJ`$)[=c F8.b$fr'SHjMQ0 )[c&08Z~;D(40UE$@b ʒ"0l:VR(x8T?2)#B)rI$|6*ih+V$`  3! I` 19u$P9[K%qY͔$)dmq!( $Ɍ*QEQL* BH i Nm{NZ76zÍv_:1"r5(u# 8ORL7V(9w ʪMmlg[h=qG'N&Ͻ| @R r 0A(@l>'3((P`طu!0{[X֙bf5ּ?FFFd PhB<+%I!O}Ĵ&X1  vބ I"YS$,I >HycuR9É.ɔ7X?XED B1Z';Ktum5Z8I@AlZȦZJޙ"+$ D!$"Jdvڗ\H9:ˢleGL8rk]!ʨᝃP !%*^^;ʙ׎9904t*oܼ&*zovѩ#| 7nl3({}W=@! oh"UhmBe`d dakaJ>~tN;"$d=TUZSP”uXSvz69DxgA":[5yǂB$ @8PSv8Hb$: P:uh7h\8YSIĝtV3N&{yY6x~17߹oy:ߑeo|;o2b xwp?鹙 k's7Y#œl5 ݏ;Vko|sj"KKD!X$Gn^Ӈi 4x2CBn7;`nB'•o{=>xo߯@GoKk˾}Gf/+w0b\)oaAU=p0ފ#8/q (O??7^, Щ$hۚm5Vַn^p3N\]X*}J =SӴAH\~_\^>z!qt\?SJ˧ysk6vFQ { tILe> Ƭ Q六 k*cJןnGx.j4΋:ֱc@H[B~?E?M'HEiY9q_oD2uz8dD^ybl¬;ٙV4;0י[Zrc=N=ʹn#K$ jg Hhx{+Ew¸AQTV3nCPr4KM1"$q0F0P{-@6SHtX[W~8܆.G[k:ηrܻ^wI"|"/,t{umϮ=|w,9P2/j$ɸÕk;Ǐ>} V^IHr~~Z7d$[+m)uYPqWq#ɒ3yko޸ `l&eT{)"#"]@l _zڍpl\T;f"`ys7,gC(|Njwxo ow`3뭣߿3۞)-TyjqqnN ,-F㢨lN/6)j phiӦ$NʢW|+OЧ$A=  ^@ObX``fF4V+^yZ>.vF噫u6UƂ]@aoP>r< hbp=Xaݞs74aؾK+8Hօܺo}RiEɁ'|So-#<8U]}Fe#ķJ$؋WođP tyqu8͛E1YXbt43J3Hfsgt !rb54sP*$0 NT dd%H`{l ['w+t7 H?4=Xr;@~^[3)j|@aT0@k Tz Ĵ H(>SR?1on-w4N4Q@KU׵)`Q`]^Y^s3ܺ5֎X3sۘɵ9n/5R҅v"{l G{ftA<'h|$iVg3N$$/*hC\]^iU( P0mf"?~xve -]tk޷+n_6x+Gwy80CҁGQ "jl@!RZ~OF7_Abu[;0aoI2ҴN@@|`$ =0 PJ ؉(HB,|Z\ %:"%'oUuN̼Cn;,dwЙsWY139|]cƉN7;yb!K~7YUإ̋JiS32$d*QcVg{}i B*BJ%,-M]*!4IKTB !"jn+{_4I}Z:vxU?(Bfi R7edMY*j6ݵM;GFNYNll cï~!˚Q:ŕ~/_9EL6om~lqyׯ}kOcz.i[{N3k4c33VkJ X10FًY#m43IT2VO,kW.o`sseDZƥP! ,-6VY#U6{{ F^fF0LLm7XmZ~l,۟ $( s4.˲/iJG!%+Sԡ;e|RF}O DPR h4BXLi֯mYԚEH~yƍ.^9,@bMg{kv1FNk/xZhO}Wǥ >#gۮt46 =rtu@ژX'qaL) EJ'鴾9,BifI\N"T.$s8BßyDavWV LO;S?|̟|[qƧ>v]ճWSJÝvFݯ={՛UQk>}g߸0 O,nnvkR4QwWR Ǒ@d%R6Vk޹.I5s(I90rI)ec qm ȚJo6[IABk-!pe:@);gQf"Hk$t;$=oVY#gi#GQmYXյu;fg:Ȧ۝&Yk4-"D[ )RZ~6ЙiuljJ !`t$D*.04E1K8CR` ̵PE(%Y)0fs@BDQٻ${;[pl;q+"@\Vj}; vo'_Zʜ GYc@w~GK~Ksl#I$QJEB2rp$\`HI1eJrA%k}3T0`!n$$x#% -*^7lyi%H,k"0cWB$M4ͅCsD!B]UQ  k8HǣqR@(B+-@DB@|VH |UJkkňӭEYslqsa Lw"%RC!K w2PHH^N4{OU6.QCʵGz?<ݍ?p\8H68DZTY1tqFu4`]e<ĉzm%d67O) #)ЙrN`Z.>C}y]m]>"Y.{|w^WUWw nu+ Sw!qZ-iaFD_nCa]Zek1P]p=|?ͽʈ1FU}615_U??1cx8YqS:3e8|^nӔrιGu|⍛j%";1Nwkjx$bP:{e]kScuȴm5?'2Mko0BqW(q[3J8/R`m‘cb@gDUmRDd9z;JD޶y]b&r*kij9Ewae+mZ~̉E2M7[frSf.Ub Z&>şXD8Dm|ZVS;oNò.1uwS-岠0\t1sl܍CFmeáS8x:2_/)u6! =0sݘf̄KH8$Jwzx۷u5Ma?NFscN@U9=.w]Mc˴(j*/?Gx:a!DRp9>TR x|9@0}H*h7m)0b[̱21"z[ʶ a|Y7`Sj^&DH)ezSmڐ\ !0y-u<̝nMR"s(l-wY]Eͬ?_1r 1cr8m 9A"1-[o?|wLT(t?aJ2@ϫ<}z ~pZ7k AjUŵRvݮJCtĶeB䘻á_|;t %U4a8T~V\s`[Gޡ L e!˜"Q7~[2mcl+U YMm3ܽk֞ε"ޟBc@7FRE3|]ݭ1Ɣʺ;!r7].IDATz[1u]`]e >Nc=0^^?>/bL$۶F x)!0 6um-́v@-@ R*bE +#MEm}:"!#=z4Svyf84BD҄9H"fT|<Lv{.v9]g}|Oc]?).Vj )"TZ)́om^3vݠM޼\cLmm^x)8V|C!ϗo|Iupj)1ˋ%0Rd{=x.apGPN# <1Қ"lb|Է0Dǻe9wf^8Z2~^ ILr*>j.1DbϹDr(K1%}0<9w9BBphMBmT"0ZQUUdl1[:ߖ'p3VB01$04 ̵RkΑT t-u"`́z;|Ƅ1wSU"&f& 9!81L5w$b7R!TеVwue^ơ_y<o)g.zu->]4Z[!o"njV1!Zjm_3tw8uLđE<ByO@{ ??=SKﳨ˲f*:p^}?0l)0"qH]*[ 13w{~B~.}.2D\4$f&}n&L̄mCp/~4%t)k CP"8Pk-!Hr`f&i&M/~'\U9Am[|+˲ ]^EM9uGQwG$Ak*;1XeD*Z%ܪp Qj]`$(Ҷ]j{x- Bdrmn*Mb8!3[aAUD=cn#g]͉9ήM6"P&3[H=rd&ZJUwf!V*!939u]Dk)q)lW_.ǘup8Mfukѵus(L[ (ݞ>9":1#!#t : !:3=(B0uBJAT/"!x? D-fM-1YJ]|' !ZTm9nuUO*TC1)1Gr[n7 cLI}[VBvj[7 xMbBS$,HfRj""ϩƱqf6&͈[1jXbU ̦Ъ@d}EBGUb9e\篾|gS 4lB@ߓsFmn׹S)zpdi.8˺)FwG"զˮf)ηHZ2R+E v[۶B~ܤ)'mvuxrd0hU83gbLbJ@:/b7V ##`Jazy^ðC@Hm]IAiB1j&!8K'UO#!ܮ4]4.]3syRΦȢZ-RDr8(K 9@b=MTJYe;W{H9Df1m)SJ~0^{YaKmmw9)r|Z}7fD rxwDwm%u=":??]ci׭4R8[-4͇AմU5cb R+S?ݽ5mZT+V>~lz;QZ:f}!2m]Bu;9b&)wy[7uYYZrPm]y2oޚ*$MPJT3ߊۇcQjDLbb4~"a QXQdUcbw+ƁRNR#mYϟ?|%[69! Pͥ TUMJ*ֶ-HCƎ|~:mwפ1q !Rr*ȁLEL*b] ]ߩ;uF`Tmp |"Q@ZZiXoאxVdbӟ~ȵ*rĭRtcbDDĝvfH.F|qiϗ~6Çb˶V7m!$ơBD8dۺqѹ*9ϏG"wDT8(u\W@`BwS؟{8]kMC׶.K: &K9BDU ۼ;2K61@aUZ+%t!bD Ӻ=>Rce;*kk]ʺ~ߧ BtK ͠m[PWpZ1䜖ǘ>nPeODn{ EMsLiՐyozwbTU 7055'G H4p DkYw?-Dˍ^>=\&u>M[JMMD*BJnZJi8i)go_~94y\ŠR Ā> }1M_~-c7FĄ?ļW;DETS``"V+1w?2fZsܙy[WpxL)uݩJYqeYB`Zk.=}|WÛ7ЕrH[iRH "S\Dm[kJrS:; pTwԪK`nuʶC0p jkM)63Eݶu;6 4/F@n753̀4sS! h\ C dZk,1]o0#N.m`..!>vDڱMT HFUC`h;r޾hßɛ CwmCnHT._ n#mlHAj꒻.:mJ)+p 4_g eOw>qD SJ? :q1ZV3)+ޟ/_hGG b0SD4V"xS]9t'Ҥ*hƁEDZE[ᰕ:9cJ"F&nR*r[3!"su"FM݉)ZVkȩ5pC̑w ֐AZS3Q !,RaR]Ŕ0ӈ,jsLdꢵjN5 ].k Bv2*""X7s1Wn88P)>yH53Q75t*(D@D(l[1w%sGD6mρz[s?=5C!%0}֤61"95Q1E./~h}RJ]2u "슿b t֎cʶֵeb1m9z2Aw(Ɯ8"4f{goaUZJ!w.%yGI ڥԊ"Zsq$ofrt`"i#R"R8Ǻ՜"Hk:?/Ӻ eZ[{GߟRqF93t9{+Ƶi:jJ}c_=.bΌem!E0"ӣNNkSkm۬k5|~ݮNr:B"m 5JC 't5LĵTU%v׶*;nշ3ǧ粮no"]HZe Lĭ)EM1R9*@~p82MЯks7]u+8 ppg2??_ t8&U1wjW)gLwl8"kOO?/)a5}6/4LHxets r;Ůsd@UG$0ܥ{К-k]ia|xx`nVU$DTnm+ @~ܳA^bČFHsVKBL6e<@]!A۶#<}H.g&Tc$D6 ft~\/p}*NxSGX-crw;L!N P_n3 b<~t}euf*jVc<`bulUvWZ6@ߡ_9em9>s`$vsU*s$&pPw03@47BvS{6>~Þ&Hj@!EB|=qݐ;\o}1W?Rb]TQ`WR fbiOFpAxZ3%f8mB!$MƎGDN q<@Td_ e)xB,>ҷ,F̉Usw)ΪDtS"F@vŎV|"R̉)l< !=۶-)QE :մs hjjh*#;J j29hԥmGDĠn+ Ĕbʲ0uPU/?ebXe-߿] j]Db@tu<,[Hॴj]s",[!R%`RHDvcD$Ûmջ.zښη2y\1RR{ޚ@NM|.Kr7&4 =#][qͻ&⪈epΟ/O)Zǟmk__>H[uY@ i>= (r3 S6UĽ$EbQEc fiYʿ/rocﳻڶV饖tReM/0!Đr2SN[-c@vyǮ]_}~Ķȯa7w-!:V-@{i L\bDwmbn#l Q@'m]8žku)Zqp$$"w7w4$W-[ -sUCiBLCHC `RH--phZi8_~O|{pGD҄e8|~݁w`ǡ_WyTfMp<0uz!>Mo8iZ8x!#P$IENDB`qmapshack-1.10.0/src/pics/compass.svg000644 001750 000144 00000032134 12374350216 020643 0ustar00oeichlerxusers000000 000000 image/svg+xml N S O W 0..180° 0..-180° qmapshack-1.10.0/src/pics/splash.png000644 001750 000144 00001337601 12374350216 020465 0ustar00oeichlerxusers000000 000000 PNG  IHDRXr5sBIT|d pHYs tEXtSoftwarewww.inkscape.org< IDATx|K-I-<^y 1"DA!¥QU}T~ͬy \\࿁pQ[@qp\>p i6P-<[*\"z\zlVT]T f;}ZCܭ…hj&(-nQjUeΛ|D~)@pи FU4o|;{fBr់^L6(t-3> n~[FJyƃΙ^ˎ~s-v܌]ocۆG ujx-#=mvF\3.h{kZ[Ykz^?qzpִ[d+_X+FY[52[ˈzY!L_jTI}y8K9e, *3+zG>F>W͸GB\'YnEuz57MZ7qeWÞ)E"u˿y`{yt~IA:R&.QaM;gdV1iy_8,~o]kju:]׃π^R~~MM쬺P8ug-4 Ia(1 ?(9$k/Œx Fw )`jp(Ys}B v@b* .^ ~*Sϒ-+,X"FzA@ *U>.H(}}mw+=LQ &7%pdIdE2|MYРr+ci:fĊ"DPb_!.Bs^O)32A%B`40>K5iѣ4~~nã |l{Rh*B]guҌAwq8>=n5bCIM':_4R p}i|mLǖŋcCco 7h,hqq7 qAxe zh!#V^Db9 ec1K^(@sXRuȉYjl_Z5]Fw. OuI@uB'dB/!}l+i31Uc>`-$<8FG6RD@?#w "2Pr*!(t Pj;ub rWόe4%*%g8Qx=i]:Byb1bjO קC#jS  (bcF9^DYO;O^탮Q4]oYBiYba  loEѽzb%BI.C]F4CK##_t͔KיQݏ! l#;<ˬOfi&GA(téqm/ .o"֠0 cTKе~(/6V{2HSecd=ɥTk}`V2Ru3 .^:wd[LTR@)NC L pNԣ(( fEo )GUtPHڊ))b"=. *b#AoFwl ͍/0>^6P{s9y0C~i50S Om5)N^/q ;I*TF)Ew$e?~85$ԡtwlI+@QZgalӷ+:QxIϥl*F20f`ǓB.;䥒v_r.oX QEietƳcc$l941:IN/}a)Rŕ$3 8Kv$vD#K6p. JXHԈI6\d< ˃h( ̚uqÉ'BRhcׅ ]51rti\d$%g̝,^'4xWhe:D36CTI!I²r&ww'N\xP}0q /.vLf@k)am"ܧ[& F '|JuO ܇0*~jef?֚GoO5Uํ1z<#~w1Uy<FQo,( /Է0SZ;9(ծmϤ.Yv'x‹YgCqq `vʭuEqH?^3[>.qV2+Ic*/p-#oxatj{JբyLGJ@ H\˃Gn+8@(2+`%:ȡӺSWGI;}u`ykUiVuZ%'bc |*nxѺQm'0ЉGϗAQH?  `䠎hU;EINLY7Jv9P6XZXi ɉe1jbT`#]45V-ܬM5yjD>HGGLYZPq:rDvAi( SgM(bM\Ȕiޔ[$;!%# ]#&N<'Dh(9Z,+O#ۗs_-+B£KtL.S7~Fo:`kP5D~T)A>Yg(MܚB1(: xya$\0 Lep?$ ;KYDc/SFJ.;Yʫjқat#3B@+ p(NZA 8=0-(6BA͔C!:ȁŤMY:["romsKwнh0ᨀ VhՂi,21PV;υ5"SNǿ5UߩeBצA;ZG4ʳi#Iߝ?Pnc)]?f_WZlEu:6Rh8t Xѽ]y,=qd]΍Y&7~&f$(hQJ,ue)r?8d|+ŐXQ!f/=kt{CE,2( Τ8ٓד4f| i/'?VZ¼;yf\\ eU"6c IJBVa ídې p) 姮-F|j,RL +2VRzV: 7G!!Lg~ݱ)AM;hb[~?+Q̨4]ol'bG3ﻔs(9o*P22&{82OJLQ=fx$YX] uF(N[\HI`Zd}цhL[ijؑIy(˙8gCLV|+,옶#5)Ж47(1t) hKwM;IKgS<҅CD35_ck{>ky|_H~R[2\'—`uM9l(h2DG9 %;mt@C)oPB花 Y `@Z޲.nlaťDw{F;+k#O qbp s~З|X[[hT mhkL 6wrԳ w:zn J-#6ϳf9% SQt 0(rlE3I *RUVL$%$3d?-0RU!؀tS{jKU]3~g 3|4I i2g(-Ftۤi׼l0Sz\oj=h&1jmg'١Vn=Lѫ o?q/Ow( J3:<HKlO,pv@yvYqe]GiȉLҎH-~{2*AGYJS`Z>v̤x敩C8Q5 f]MhXw7*X‡-Ԧ{K3y}QvM]Zmlr+zRP2xż g|fU68at,h qޔY b$8;L]~lxTUއϱ0apo^ĭ?50y0SzykQ0&~Z缣0ᨴKS`O<X Z9Ł]#d6wҐe%Q{O,%}<,U Exdīr JPF}Rg% )*C S*isA|^yv37R,kֳ1Yh++8fۑ}R|ܢ=@LHi=ҏ;RVQAw__"C5d'^ԙ槧14Ș~g)TB-Bv0o_Ŭgy-{4O7\kDzimasi1?y^vq׊6)0c$-Em,HM}̩3X"&j9&CΟ o<# :?3ӱaE*`l4ߦa% -K!3x|0R4ɹ'exgQp?#,p&vl- J=;kcDe؅('{M2_yëtъd59λE娗-1 6~0-: 3mƒWϷ2:j#Vd ȐD,l*rV^Ƈ =JoM1'2JI3Ғ6[sq)c<.JC.C|讀;V@*E!vp2OuosQ O髙+?VC᫋47.gt\P~yټ@Ay{'(~7G6C F8ULs|4#P'بl !b҂-#I؉vqUsjk*S8O0Lh- ׵EY@1ecdH#tNF4M/BﯡI[aXyS]Ձ|yk.S1uKkSBƢ کH/Ȁp5R$Px-`VfE'zdbr  a2r*uR 4vrgSRrG`[u|\7Pn-F t/ dwTVIG٥Xw;>닶G \̺ <5{ -FL}(ȻAݪ)pf(*2G33E;^6 GQbُ|ٲmVT<J60%ra2 |#ɵ[\jL=jБ-Na g%5Nь:o5/d+_YaD">F"ڃO$f[B]?;LI\9vvKQל䮘4/ p7ùc0`E8whEXݏ IEq>Ph{G{82|R>veVPgVZ#(/ĉGЖ=Y)&5nEHtMYj`l-Eס,OTHXw*)nu=t w)䁘&08S?zJʭf~h}j ]2,3EI9.]UF#> ъH [+i&0GO k"*:roF'̋ V֏5wȮE?OKQZTv+J9QY%2S)'Ѱ$"?8Xc\?.{ڼ!G?;ܧQ{n#eȱ6_I5|k\g4I*-ZXaP|a18 8o:,%^fl!߿O"Z BE!rqwԂZI4 S+U/TւdT Ӈ)QE补%7Ţ{K|x_uANI9`J?R6.o9ْ҆*J/5_w)s@E;"j=yiVۖ)$ʡ `c0%]6PaOO;(8 L)#<&1Z)8 2֥gQFz2smPC .s_:0DR(rޑ*)r n#f._J_ $\8NkRd^6RdM,1@g ]_$k|ZmcL? Ф>!rNq?аq%yN;;h]IhQ':]+8"R\;uF /f> ,981E؇}iwtl@OgZ#*QLDm{=ϑ2(^iSYIfy(yVVZ3q/sIXc9X0cS|zƃ:K:;]';ҥ#TP3MtGeRT:PS*nnfwJ#q'HӤ\QWsiZls,uqghqP0@aSJycvsyAW2p^WTcoEiPZb ~i! ,/QkŁ׭ …7i\'g\-u?}6Xbn'Z0f">i)ge\<|+S;=eF,y=dxxEBLFNx{@ 3OOXU ^x*тwX,zJ+t{?Eb?C:ecx|uVڍhNd;'.+*' `[Ig,CV_ ~L a< k{Qnk2t IW`^\6+Ԙ_}&zp T>a1vCbQw8MZ6WxߍV{;]D'2cKG+Ϩ em@6%..P2۱@ZGi:ƎC\Ok`ԩh$v~rשU=[Evn9EtƎLl,^qvTfO}@.mFkLɄjZt}_oWBOU[ye}KNu D#-mrkgiq9Q[CNVEpZ7GPi7lN2D Z c⋔ |4f2iG lfjhXm#nG7,Q(CWϝă3Ib`\<5@eI\4;oE;5&腣i3}􁉒{xTtڌ\t=`qU5FpQ?ghjKW %rQ k;YMhűN z}cC`T=~.Bq9+f$.=\;O,^xʹ׻3+1N>~s+Jc!q(sCCKnpWNhqk w3H'&.|gV(Xi)#pa^24K"Ec.PVVچcS@6sQHjǪiQauUr"@+`!%P-Q+ϭ 6 m F%6e>o=Ez ;]*1TA!93brE6pt&+,!FMiZ* pAG lXD:?Gyэ`yL?O(hbQD0J?6@XʹPʅk|0Mjm LuRM}d(}ib@g v7^E|]PRaE~'[}8(΀_]ڴ$Z&a|Em5azE5ˣ5ړ7Ϫ 6KK4U:ҷor*hPph>4zVA׊ pt>@$Ņb<+,ņzu9:?yԤ7 zQ\JEi^f{xXzBiPT͒[Σ}:A]-B+ #k`Sއ^dʵv$Cr(yfnvv m.ͨG<@] 9ue|)J#FF?Z+"ZVYXOy,d[VZ L]YN0h6'*`VQ#{ ZJ8cg~z%.=OC(.EQ0՚NHJ\XdCLOu[}:F]㒄+.;ǿIsTtDABYDeϸm EUʱ[;'0Q[xӳ V! b '*66QT{a*|P}FaDs{ڿ0(ԵŨj'|&w?H) X.v鑟1]~{4i(2WP\fِcY-e c}Нvn(P"Xa'@(fDi6%" lt)2z5p{uy2S#>sw^ z q.Gy<p u}>Ixj qMƟ~ &׊=D@):bR#9/>i^ZQL hajUR3s|N%#XKR2ШAFl5#[Hym6{AOtG1B>ɞ'S96sq5A1TӢ>üOU`E;F~.?CE@)I+`āg1:SҦމ n ,!vywZRAo@;)H8o`^kW*x]~?qePpWF0ަI gЬu ۠8^CT"h'a+)sG22N4Y<Ŵ S*4b%+TetZ\ҾzХu5bp'\4(U" XQ{,h.ɭו86auCl薶DJoD2AawҁRUAOFwOgd* ^qs4=—A\ JJ֪CѩMe.r̭%  ~,ovMKF>v1Og6 <բ)\Y3WL&#`gb zb;Q^}B\dN FeX?R 9L(# BԷ؃|C3sĨ;H5o- -7+9P aM[2?ѵ/ӗ?w!zcuA=682g{Zo,"ȩAkqjC rݿSr8}^] תhUo~KCX!R}Oc? Bm̶c=K\ BlaaQ(GH(pʍ-Q 7s_QSy?5oqCFͥCuwn,4 ۸gϳzV( !I.EyDfkY*o[G R5ET㣂I1 o|(kCULBÄ &vSLɶ2Jl :tgZ@) o7%T' K٠aҖ2bWl^i 2lQV1χjL|* y'H^yka3OVheb y9P@wD1Y` ʥ]!|SF6AI[fE!rwx JIBqMk{kf;.tFx~$E^'q*&%}g|99EnN,_Fa:S5{ϜUT}m2z=g[g a'%0pm]O׻PKPN2sr8LXA-MT9PT<}r񵇾iQp( TL1۵q9k@P,ퟎ\L#4y{kD/qT눛I̔HVnd1mZ1XzwRn4NZH^8SOsA?K J< u#K5DdvT̈́tEJ@ks䒑x*UviF|иuLԲR@R,-Q.MF4.t%[918ӳm1\+d0JsܫW+) [;Nrj'RF8t&md1]kBaٍ]<49eM ?rV%ۢRkռRKןyl7}#n66z^ĵ_v'ZctR:W󳔔@֋Qnh ]g74.JΧy>qx;2.^{xo_XPgs~Pt&_=@W*Μgy4Sx`#\45LJM:*y!hOsYdws<#Ck;AjlM5RqW{比H StT$ fn>dܩ6@a H ej GP9Ő%2$H>'!I'(ei!2BE;aX>Y2g.X ZV;qKE~w\-5ƔZS(fW#/SgywK:&z2HFp5㤰.OƘn3ymC#O0r)bz pj~Pͥ.=MJ(dNOa;)oď#P1,\TsV2Fm}"f={IvE~]DUV:^G4I~NqjY<ء}咇*CFhhU/|wY龎 {FL4j}1T&lG(MƘ2ӭ|HSdg׎尪xC}4~CW`Q$.ow;YzӮFG*pmZ t|u?ɷKB6ݵSsg>`fZUhjR+FErY`O4>t=gt(Ec.g![؋d#gw3!gtV2A(Q Qh¬hrM:a=kѤUG;Zx֫~36,i(#6}u3%Dp%gRhQJ ea^<6 IDATFtR?:VEFUp *%є}3' kQDbGCfR3o!9mßԥv)*NA˔VNdZ4җƝUĝ"?xAM(dvM~yte!A?6ަo|(]s;D$//9unlWO6~4Egb zյs \x sV*rć] ;'C0̏E*theN{ź/ ˳Æȳ5.IQe63B"[!Zd$JY_g%ȊQ  qz-3OхEO-Du׹ٲ*MbZ"U'm$R1ٰiG&}]rR/¡M!^[4UUPm UtG84Ͱk7" fPۀ@k\Z%ϵ"`sEԢv&䛿jqP'%r=/ڦZ*uٽc.Z-`I\ UAV#Q2 A9!cJ0F'p_ˆpjRIk^vy8I&[kdZ78B]mMZ__/VQjYF]1I:kTBA#r>B/Y;aUS'2}|m,tsklYLƕ QG;9?bs|zj' %o!&Ԓۃ1 |ɡ=*9 yh->\'>Vb>?s&AQep0Aڂ D o<^r9XGߗ>5ԻÀ 3w(LȚN7~zqe1G~|oƁhYPzc+"WH5'|AqƬBBE=c2UJ?R ҮVvJ1˫?jՊ((rUѤmq 5Gܕ򚿇<B`D Nڳ\,7!#,Ch#lQPz+jޅTƿN z.޻&ͭV=/9Fa~͸%? UWqC1;ReJJ|hS6WAi*H?^6kO[6e%"ңʩ`v3: dMP{m;x4!ztE7cm̩eigeu"-v#`p1֫=L'wx_:j Irܸ~v-nTMLPaпs36h)wB1'wWNrfQd*R Yy{*4^n|+GgÜ?h6\8 euB|zxNRYتrq 2miE<,O%x?ic8A`L6C?{Ѡ0*x>+ oenF]D f8,hy}:nPԹ1u4 Õ`%d=GƓq6`'3&EfCC'AnfmŸ2qXo3_jsՋlQm꧀7JfUߪgbE&b8gmfljoU1_Fϛݼ>Hgh(vXΗJϔS pL,Ct;hj&{w_/'5Fړ3~b \Su\ymq'eE1tIFOI\[%᧴'ѨڞS7\:QqTs&_ZGĶѤ\_:oR779;U)ݜypC[ &qxBa^2>c_tCLz#Sgi/0D<g邱v 푧S';h _|o JAMsPgp,Wό $0[x294X Gi 񡺧9QJ_ҢU2X~94$ď }#=/w$g k@'I s:?`(o~kh5\sPZ# XG"y58)rۃ`xDm+YM00}jk%a JzNɁJueS{4=PMHGF ݋]@;ehiu% M$L|?$L"p^^hްaSR !=tGN"e.yp ee Ȓ2hPdbT t-||:h0ksvǐG.VTu(a5x)D_qͳvp\!&aTJ8[UGZ,*Gq46IzPj}b?+]mRh5l,XbT4 FK ?#^{-fQR m#̛rh ǁlE!LEɄȍ8ckv j`N.9 Ox :g9R:sBMP^=EKPa,ඔ_]/IwN 4XQByojh(vl͏[ZM$XIv*ĭr_!b(5`H#)׻ʗizU[VNeubH S `n*.q]*n? |S/jJ?6Bf1^)c5o0;*}0]u.=xeuɳfV+KeyG9SKQ kC#Y kiM-^tZQ:@\8dp &xI~6QRYKp=4P3ܘ`>Rko?ŰRFa w"<*g]3 uv0P纪%a8,_}UϽeDtWJcUeh,ݤ.WV}*^k$I-^S{ysngHD8s2ex+M'3sdJ|h5QI"7?|(#0v~xQmQ x&ovN4䄓wiѪQ:!9%}jtϋ+OЛ|1wmIP={vy SHP<˭) T*Z@ w5NHF>7P&j_ГD$io֮d/ƒRג'Pq/>_C=#XK;G/|822?Xp'}O.ӊ]u Б<HS.4!jW;TWYR03#%a<[H(q_`,0⥠Xa;RW+Mamȱ8MaJE.F5fB]hBҙƥ$,m%h\*\?͸~ENcI}=n`ygqHlV> 0Sj:h-,T/oYx쥷NyO-3;UM_^ j`sHme3׌ĸ[|vi|JiY]bAv+g.r=R~B!䧌;jS2PܝDtG!@^j{-c<爀#uk|/SZOb"}_l~ kaC;0|?ZW~jlQ|l! EYtֵPQy܋d;Qe7Ľ(gh~X୕ Kh6򖋠5Nrז 5mn7b1̪ ]-#Wmnx #+ 0Mw;u(WvX}sgN^բn=5Wigpxӈ%c?"3,܉40}WU <"q,KxNS`i3OBj7Lg `Ԭ J|~ꛊk!uF;n:}$%vHOH'B<(RxQ1laPRP{U=$2 {;u%*^^VWkͥrҭ2 kwQ~_XHid*iUҢawA* WjC3}Pc)2~nƪ;Krd 0#6嚾QyTRU7DM':]G3>qb`6usI(my 1u0楈!Jkb㊀Ppszظ0Mgeyz54:nFӾsN5Sx[֫:S/ߔtMjG_2l#t2z*#߿ O)8ƠVYHAdj,1G~WUQ jp>?^UN`Cp ͪt{dPcgrYW;B9躳2tF?8&96w]l`Qlgw+H,S4F! oCԤ08PS1t]40$07u{αچB@!ᄋ7S+PTf|7ii4TӰ%%ݑ0O}`'^04~ ">?QftGV|$P2->½P)HA6.{RYK Bުr?Dj`)ŝRCm:.zmths@_2Q>3i1<\ZKlV+`a# |Sᥤ<]f=#]1 ""3uõ2ȕ}~a— K-g(]xxdҳ%ُ}$x8Bܱf qlG AZߙ64rMePqNFkF/vϕs=X= »pHkMBZ-0w53ܳ-iY{qÖ,  uH3w:o\Xr*Q-O'toә?g 8[qS W @M=*Z׹?wii$yRv8g-Ly]v\#1lt{_]gCAq+=(Fgz=6w eXdx/4t&%f%rB צfhn mc֞?@ƿ؟:R|CnG"l13Rwؗ}@cJi>'s_ዦ#iSTT,.wpu>k1qEe) >QLqb?okr`dhHiAעzjП*G|o#2 kLx 5dt8\/53Y$Ebn_se4=9L! .;D /Qk-{,狯J}mi _-iqmے* V.!DvX^h{3Ni`Q,3c?<61& :w^P9Pwk JL$$ن.ެE:5{ZH6mV:@ק@)go}~;4/*S:yW_gI+\oC_l/e%E며~.^oO;-PCTDg¦?ծ$;4c5.&~b͌lg?鼗`;=t m9SܛI|&^% I~pM J(5$kxKw󾢘j73*MsVd[C]=7)_ .gH8iS6r(*63>Ϻ?n| ֤N5%R[1mOPtJi U:@"yZ/xXD'ͬq: hM1z2M.G;~-."f>3i"A4Nk9;(NߪJtbs'K5K)"rgCsQl ;/n$ˆ$iiC p:ԿZOg9'T8ޭG[g+P_fk_:MoܹDYV0y t5s1`gżȓi7%76k#W#\x#,TF0,N-:=н Egr[R@[e~l|+T6FzV5c䅗k>Nڿ4]o9q9^i#UZ'Ϲi6ڸsKFHI1_Sе_*–rQi C4ORHokQ2 F'nB&'q)o]Qlz >ZdlAJ|}^J:qr{|y}Iu.ՓKb;nwjz] nihYz|YR69b= R @/hEd d>R@DLX/oq ~'"@II)T ,-A9{{w|ݵnt뽳-:ٖdh%R%QL"  0!9~yCIn~ymh#"53)Q7;AO]To 90bs*1gJp2CuBfި9j,<.لvV`Py)&c&bTm!Ğ#h IDAT вط:%% ZQ $~zJ~E^mYgCihɧ}N_`@j&T# TApʘ#P1Xz!h!)2~(!T ~`ͼi-]!Qצ-0marֆfX Xpzf^2XZKmmF䪓Wy=iary@proR$AvӘ w:MG(9q<'zMv8blUrk $KFihsnQր$ѨN酏+F}9^;!lGHLGGOd_q|P۵:tx@$bJ|6sE9KWm0W6Q޻)ψqΡ[3J1$B?-_^?tf&F#LNǻ5mn_pE$6u.9Zq2%!hHA/ghE/T#]b9a@2I?yˑch$\eRھ$O }@ja'XS%Bn9ڟ5R'A =[ c};I:mBABjMvLtI3JZ eEa7G=PG6Q.,n{S]2= NU$]tiS٘tөJC*HK6wt{=O:xz0q=B*Lٲҿ M Xyymvj{bTZAv5U q2~ (zr0^=k3NzYV6mm 2oߣz9e::OtYa{ TVQҖpI8 .>Jxo[V?Ae4ۨ{ž*wz ^> Ggi޺I:.6?Yofn۰u@tz6SŲPi#dl۷f.(ImAYɼ (*/rQ'f 25%dMm47-F} 3Վt2P čE@,P25-E$֌gi-/ႮPɨJS] N;Ā5$@"}b#F1R, 3=*@N ݃Jt9y\D}hzELH(4kAL+ /h -[[5lb,ɼ:~;XD`J&Y庹᫴j*z(t$QJ˷u[G:PQ\T,} ;DQ%2k4;}Dgk1Nz AQYtX J8 d[_tyIm$FnYFBuo5B=[`J<2C t1Z[v 6$q{".]$zDZ = YR1_ZɈްexl7-Rx kM:Gphm<}2h)WZx27JYي)SN՚.b=z1gToXK6 /-ͪ~j4ۘ0`U ǝ<9c!u<73i1$(R%2O(s%::~ciBO`<_n6e>R+=8z.0r((wʘxy{ n(afJZT<}eR'mX﯎rK54v'ylCV.B1^( 2%=J?\='^Tы%}V;0?3FøHq/|S^=1PP^ʢtJ'47#5"=XĒ2e`@흆~9E($i8{ĆqL ,5[D*7^yJLԄDr4% F Аnw]6=Ra.vv9& JtY+9e.abk2j{A߉RLٿ-yⶎ(˚nE g*ŷ'JL߮Zphz뉊ry;cg#'aPrb`FJ&0$kGj@L?){کr{^ڍZ7o ScnE0}_* 8K]KAH1]AO{%#IclƨK}ە:rkQx'î/VoKM~ٱ@6-^Np*80%3>fڤF2Rsp $P*;=3NvP- fX eK XRc]  )6'Uv"ey" ]zx 8 V- w})ʊ+.|2T  LJ8+e"Oll7K9A]{{„oSns$(a/WDl}~;]NycP1U6᎗U*|a sM+$!$e7t&J.\EzM;aIyyćlu^0Fr5 vҳ;1[- Y5)S7& q4*a2q-$>cd 6alԗ mO1 ~Gcx"PO,̢)Q;"@4rJih55A f&ODDu#MfΖVQefiH!u`n,#/}2׎ʈ*xYX<2w8%"?KH{% {>o6y}$ec}BU5A[@Va?d]5OMCVD 6W\}!'^aίK~UA>S )bɘD冬ڡWaAlSsS?NGIùǢak/i lZP_?c>RlY0} lg4r<9E>+a$$?öĖ"7wy7($\t}^N}[ϭۼ6g#&U׺fѓx˻7كe&D%,SB@) {ޗzvb5pkIC=wD@Ӡ$W4xd}{LtxQ*<'7E"UheQnsZMQe#K:WL@ TL^Ǿ$WCx ̐Zх_qF[vZ#A0>!6V țt{{'CG$.TƦ&165;x^ >\"u5mVS~&EBDfG&w}*xazlKY^q=_sʷuLT)~FA =~d.xdmfd3g-ÛbyYe@ˡ˞9u߽_z :}lz c#ptp?aâvz\r]u6,Zj#D $>ciܸ X!'.?<Os+A%cUdzN2v`m1'=iL2}(}*3G0s !ռs=Q,(vѿ.4=Y h Z⩒9ue )蕷 kዾE;SDR;A 敞+ԃM9/Z{|w3A6{kX+ϞAڮd<3GyG'8 |vJ1ETpkv1}P[ѫpzMQÄ+ ~$QOTF`&5$d2>|Gfޏ_?} x15c/]dg+f=L >Cϫ}xč 9OȲ>M6Qrz@і dFhO-'?tDUI}%Fu;+Pef0O6y&J39gNO=ԇ;~׹ tc L5J㭴'^=p%@=^P /$H * TNr**%v$L)M9%RVzeZo^z2!'uT-_JL\?'dج* j dA FJ#ĠD-s$|8ZS@q8 o."F/@ _yAF'B\o2"<`s1"ë]y$.O@CvO4N~kNf gϼ˱8Q7ZW'4IcQ R"Ic6(ҕX[3*P[mh7a:Rv\Q=d=31wpAgO >ă/ 6,\;X)DOy-K3>{;yVAmGSǞWbjjuORPxʜ\:U i2>}^\:C1y-tR&tp#"8~c׉#=z.iZXx~x%)zh7^xlփ=ГlI"h#7TVfDΧ0٨cO$|+R!06݅V )SX)G5\R![~HMہ1em$ !:(K Luf7.2)b;昅)VmӶ̈ϔ$fAn!jip.0`=jӲ(TUto+؋fM):BqA$M5/KI9 # \$7O{,rj N1FSw͚;Vb=ǎm >A5"T挫zԪ(zHD:}/O:_?C{[MO=^'dcy3O=>%[u3I$#O<Ao΁ Z la9~ދZ6PQ +˔탲dT_3o[q!&`%SZ$ѩ)gW\TumVc/V=}RƧ`VЋZ >i댟!*0jA[t RGz~pS)[uz]H`PSTwW95Tވۘ737 IDAT=q jJdOR o읁a#,m;:ڒ} m ʾtr5|2#?(܀bDh=?w*qM=P@ aR?62~o$qY#yTE6-rN䂛J+ "x9̙256T&EN<y_0;rvbOw-. 5j(x3؁8ãgO=k@Ƒ-?Gj #ҚQ9$a6N9A+v uܝ䱏pU~3 VNe <}Zkby ȇ\' Rr9GJ<_ mDZ6^6`&*$jAdn`3!zTJ.)0@Ti"[hL3 *:9CȜ :0,CM˳>6icS@_0g̩N8֐-*zĮ;:(%ף_ynnD5ẇв;lw-o>tH(U XJlS.SjMtR8'zrbӕy该TEmi"&T%J\h⿒ [zOs զ~|oGA\"7dJIǧ'W- @V's91 $vȏA wUY_%FْIg םݿ>v`_.] Ka0 8Ny<}8&/XGl\iܡx ;%՝AX4 N{+z*,F&$6AMž~f@`MLV" 3`i9Q(xK>N'-4$!-YhP6nxˀmƘ9 ȀVom$B]wH:* !0J=fNݰ@AՉ5_"r!β wDyZ3և瀤ɀ썿ހ'I9B״ Ic\c7@Z?1h<+^C !1Ď;Jd{(Pwhi#E.RΗv(ٴ v=ZV%_ɓ'lN]rrz rA>4uI?mkhC~|Y= lElR&gܳ=^-KWWހ[7\}_c,w=s?<Ź!bK^RLu"aeZn.R溑Qn*bc.bߙVm+Vuچl,T/9_iډWmkt*Mj%AW0Q.5&P?MxAx- }QN7by(C4O1&FnuSp+`4J 0yHS\ɝV`@1~|PmO8g9t 25" ·Uq=5XZ/c?u e\黅 :!Y~5P^ASڶ3 !'aDޠs=ʶBV" @1O1>ȑg rQG-{n}#n\QGLgӷ.]zx+o~GFuc}O&ذYXo7+-` >sT+k֣Q [O6/ 1W9W{F!Qou X\ׄ^SK9YqʲkS{3 ғ ?3˖=P(%qɒxÖ+14qNܱw\ d&Il6Mݬ5 _Q]_>`N炆k6Qy;BA1+f-Tÿ C 3("QZX*C/I /P|fT5/|h4WYP 8VBb5wX!+hguP Y4#J-̪'E*S3YےaۍHВYVYgE ?<{Ϣ* X7y*UT' 9(hOJ`2PPH&mx4?uioᑎ3)xX^s6f[W\VDZ)`Vf$3薕MrhlB 2e`(1vf"#{& u}2vۏʕk$MyWy.sʵ?oQG;G/{澓L5 >{~ẗk}s}ݢsl^j6ny=}gN܍y$Ƨ&14Nbx>,[˖ƥVa^_ Ee/ϟ#Gq|sU7x[c)$اv?EC+^w^qGs\6?qٴ5U݊h-[.c?}Hv?8zppx`ҕ/7X!w)".,g~ ;cqty2ׇ[_o7^}dj-gGZ||' =z_~q=?g ǭඍᆵ/p_B X>a4 {x~Oc<|wY:4_`%|FְWRpYNg9.[K" h'y[l6Cj,&n MDυTQ 6 mhLE1p"PFvOW.S@i%HbQ@CጵdpA-0`H^Jt PMi\-!FYJp4^Pr Fqy+ݏӱ(?k{gqͪux_N񪍗k{'wmɵՋdh3:16ݍWoV$Rzk9|[ /ꏱԋW;ө.edr{1|5\`@}WA߹w7{8 _<|7ܳcV\!޹87~H2BGFt J@!.E8?9wO=='W݈_jT@z'9$b߱ (l©,L| *7_r%t被J@_p|w莈D仹P@'>\c~O:Geq:%wJt 'Ʀdd9ʉ?<'p>z/rvlm ^X?B;'C3;!Oԑqѯ3wʞ'o@,iWƔ$w, E_~>NGp~R+6b i$'c3 RNHI/Dɑ;mP㣸 ၞg<ņRG0 mf]am#ʅk_M C-7䢗%ݓɖjNh{ ێ6ry%K(24ǞR ^g7ޤx\q8u-[r`eW(rz| Տcٓe .tkcNw;XmฃR̡re$x$LB(W?>uc>jXE(=PG|ޯr׃Jnק;f[1`m2E=nÝbTZSXL;['۶zȰ$>3+{6aâi){r|~Tcڻ̣֫$?w垯~?HĩQ_D^YVr.Kh%B7O5;p%SF%KYw^e6] D̅G|Ϝ>>7z&g| eް-SMh P)!y蒅K6fRLY{x~#rZa|?ĆU2ly>#dXPIe-!iw0e%N1(C壠BN 3Y\FIeW!\; 8`Qjg<2oqT=oq5tSkueVvڍ[iO;Q-,dɓ%f+ЏV`큞A ޠJ#3?ܓ3L 0׽P ~㏽,I/RI5j5$qgD-_<ʯ%}dt %31V~R, NLρsgv-[Ro|^<~+okgPv5X00?96O=zrEKq5|jl[W,_A{vݯ*w-g'œu);ƮGpfk֊<~,, Y`drGqf| Gv{wvby!"Lj`Δ߿iwy͵ݎꅫ7O_$]g)j4F.@DZmԐ, /[@ٔ/*DT)s6]Sc"Ξ.?km EY],UV ȣjʪΙdG񁵥Œ;Cl%SYyh"*fBfD*=.Y$]B74&fVEz8 '$Vdkhw]NFc'&JlGײuʪv &SSNu-'Fl|Jzή%X88oܽ34>^ۏ fظxnZwGm9^6</[ 7ۄmWc%~DB? Ξ—y۵ Emۮ`w;L ,ޫm.lͩdOQ=rx/79P}퍞`EK׾޴ sNcشdEA@9p+6\w |%O?gƦw_ 1Ys~/Ƨ|{ʌ `y0aX><ݴ oB>RtȢ5>ԣbXdM2pCo:$]^M=Ҙ?S&΋$AVa,[j}hA@޿Xaɚ;e !@Rc0Iޱ4Ůvc* O>T]b}$_[4*Z&QhUފZ Txi`@㠤 fz2_TN@ky%WO^f,WYAXO`ż$Wh"֍͑n> {85>ʺZ<m*pN_] ९02~sWة'O]<'>mzE7^im;DAAm+nzu'9OjWai==!UoǒyJAbz3K᧯[/*C(e"\c~ҫ_DbgՅL$2L; /0*g$փ+Kl|e[bʉ,dG^M.RDXܑUn.d{!,lgU; f[rB ǡ]~8=4p}I^Hm*x:Dxšή%O*Lq_{( dɂWId9ϊ*62{NMy8ڧ+Jxs N z2ҷvZ? )"Z;G)۶-9`I3҇Xy`ۮr׎ %W` uU>N H=Ǟz0]Uqe,_];,sj4[O [w%Zz zA&>or՜҂̵L5 >{;~GAĬILyٺ;woNuNMuLZe4E'OێZ9uŊ5 G}uG{Wm]W4V2*7 篹cxԗMUdZ{;_{/8JDˊHKj cЉ  KpEJ(%5h+K1@Z{4r<\%@E)Ѡt-(ToTˤ$S cu=5=w浳m5dhD⭲sjXp9 @U/d'{PƊK<-H59^#7`BcyDzVF\4prµt& ڦ1[x'@HSc* Dhz:A]LFUJ4*w(B.f|YR3mu=V| ?_ j@NɻSqA?u2tGG-rnP^sV@+>z_\v m>z#E! ڛ[^)GF_ةo+'%{^e"b/Zl cg)&[Dt I9m)B8?59G8V_8+M'i]:Cp=6׏_RPnbBxPʺvNKތekiɔqiW+!,GVX!/:~(zW|<ϲ^ew3ZL%CÝF&?㡯ݸw®'Zs1T  5%e7>w]MU91{P9o 8')=..o|B%n9Х\b-_wEV_ZɱUPEVSq=x ;sϞ™Kx|?fC]^i ǻM:?_;Rgg9~"ů۽]Ҹk*X|J"8״Rj 6e2xhM:r+mD`${2a,>, 9z!.Q+SdȀsX{|T;n;85ōw R}d4 44 (^ O|Ife|ic-V ^:@uSQx7G_`\)(DlN@Zm,4EtI 2]?G)>Jf"<,@LI`p|!"@B̮oxW/gYN@}umP5|zacl896}ҳw Rؽɉ "?'mX~W9tWAenx~庛wsOĮGg+GGO<3/zd\Y4i>׏.i^]1>SuoϷgf= ;y*rFQ6^[i2pkW^Eٸ _DZrH&`ի I(e)1/2qC(Ffnmv UFa4JП9:gr, *oեTO{Gfy| kcAr4B6x>AZ3!G8IՏ8iYqe19K_*X8]Ao@7tʆʔ[n_-N"qK1ze7r۟PEbU@c#XpW@,LN`k0R6/\G͗SOμ 8Sٰh)^aek3dӦaG_nAR%ϩ{HDX`A<\!k̾ǃ/X40w\~=q816ÃcԩsJЫ|3WO{ƶ{]˚ uJ;&) |o|-]Ƨ'Tf;_moVj߂C ])b=N,)=/{nx¦A s/d$ŃjHd@"Y!'1".n5}2Ίpz qOӐRDX|>ׯ)qwr\1oO1\At3 (KwdVZSw"K"j υOIr1@ QI;.4(/:Nf>wH ~K{{!@м6666EE]I§,^+N1dIe2^oڒn,x1_`8$$S_w+O>PoY@S0(OBJvXovf7'x 뱌?|q`?RmbF=T,dj@jIvQ vV>dϜW z ,6S1`ZgP#;O=W|Wbgs` ePd' _#,AEu8i\ a]rLmXފ._?]ʮS[ܸAiCE2W'fNY˖D7&m.=PNʸt pz|fEFӑLVImL?<0.E8ݪ+& (aܰz~qfbzǽxNtCGÕWkre.Vzp!;Pu=RWY׊([8tgd3m gD5koIY@];]/፛/w c7iGo r9MBp22OH~yO*HDCb31Iݒ6,1!'L҈zVQ]%#hJ%89 rЕI[|6:3e--i^*^6che;[L95, Cg)&nҖC$e!rWM-Ahgu?6&}Hp>G䴨(i[ausTqڙsA垃W} GZ4CA rӻ?ӹ]HTX"O*/nNM[! [] 'Ht KUJa<}}3M@ɵbx>V[zJNXz~.GFΙnp`qc͢AtֈBbYo}nhLﮛ:X447]z%^r;ɎcuZmT,{~pENDShbzz2ߏ ||,o䇎>7㧩jiv!mBNbg{zуVpϰm#]8>y:g)M2R~he͂DhŦtlR΃T tmn$YV3=.Kf5*[BqSsn#Fbd5;JBX"l' kjne@OϩrB xVɉ=51qxUJG2ber!քx$'&ˏ{t ߝȬTc5(!zo|6)@J a^.)]-\#)?1~_zve:$q? slJ{ۢc#qoApuzJa xrl q|,ovzQ5\uХ=Kv7%ݝOZ޲~~qڍVC ^t6W?NHsNM8 mB¡cpАBnVs={LEc_%@_J7 ɓuv|mNªk15v/ : F=s@u'x^a3))M^=bS֗l$4{üN1ΟoZtn,8%)Z=s._hrƻE.i_>M4z3"tioXL 30 "bSS"he$]M)$+:})qu / 4Ԙ#gH28`[Z3F2xoe9[{i2A9$\B3?$Pc@<,wب1( A&-= R֔Kݔjx{19NI_BdJ"\0y]>ĎMq ˙xr"#C?9 ї[b+)%ѭ/7^t3ڃYi(5J|m}yݦ0nh#/l\ʟ휞@C]԰K9rt)j䎌tXˆAPr FOO\+[y׮^׉> Q,?_6'%`_&nr5Gq ( 4Cpl|:-i}©q&qߋa/N2_4-ˢMkbV7^$dfgB |]ƍVɲj.1rgaH\  &ϒ]M3mlcVڀ"1@Iw21>*Ԓd/3$9KhI^8{ U r4&O* ?YRJ\Sb2j8.9FlBNoRROn9=fVB%Y/v@R*3J^f.kGjl[!Imor9<0=ԛqkk4qluSvn)p8)XC [/Sw\~?t `3)3w7_J65+%G'4f ݒh?O2 tNn[:xIzr&~랻 bŽaKU73Qݑ$Ɏ.R٫QIsݞUX<{D텷WP{ȁ 8{W%[+v{w%՗A a?tD]W0g?|04o~S@$/Q%"9oS 4ʺlyu+hY>PcSEF5#Cd ]A'PKuw|OR~u'3hVc ;. ߱Zz,27/a".F&;mNMÐ Th>s̸tϝ{T#TǺy7M?h s`/~KůG'QL; dR~NP\ b嫇z5A_+ˊI!lLBb{B&Sxpc&riD#p憐4v\Lr[?VPZiUVI4JCn[o| pq ώūO>8mގ*"Upp m@M+8= W-]'Nc Ovִ2Q=:oy ݖT _x#gnE!`C?Gxep`31*aG{}Loëo9ulm.v'S,{v'w|.;N7/E .MqږʘߦnuԱ]c$b*/1̥cv<+RxM'=u˿x_UxͷY- >|G X㝞q78 fc[^*쯖?}h_O[TjH&Ыrhd3rR lް.?8{~ &B >¸Wu.ۘ"I,f tٖAzRNK,WՈ;AXX'`HUkZXKpe-0/@ \1 Ą[؝=LvҰZU8ϳzC>.h הlZM8ոQe:.]9¹ W#F2U-Ѳbc`&`h)w(00TF3'q.d}.x-ˠO@ݰZ8yJѺ2+?*4Q`қ { ׽ WW~tTo~'n;f Mx@M `?%KLX+$iFKV}Խƻ;K_x^|;n\Ÿ]<>ȱ浒x7  '~cb=<}p;0_Yqǯo=x2)K)]Bsܥu3~5ww,e?o}+[;N≃ go'Tn\fɆ3=/|~es?'q.wNN1z/x*cB[,O$φ_&Bѝ`9?>_OxͷH/%r6jL;KZ&~Z S%&TOʕZ-6J4#QN >ӺnmoyR䐦߆fJeGbMyᡯr/\,+ J^*tJ؞vy\fɇ;֦BeOD$̭rRq*f?Ǫ1 ippr CPXwb{*z]D p`r-lMUЍ/-KZUSaDZ(ú[2=!<Ɗc[`7n5t7=>|olxQwyArtF5(mK67mor[0eΊ_z%~S7cu"L8r㩃8xڷy2ywg7 ce/9pnM+^O~XQC'|}?7`2ˊ_ Kٱ@ MFdWdd׾ W ßnKU~[`٭/ zN>xX)@&!el.| Cʱ(UDLf5FC5ɭI%yxԊֲhŹ9U҈Q+c>[Ǟ>Cg/`6êu* \ {a@?T ?$j;~#~O`Ԥ<9ƸVWPWp}-p4_aW\x! K 0$ClsS3Ep,ʆͲS)elRk1$M~9U? Ѐ~4͊4 XFy:"Y}ȣOpvzXR0PuնbY+f'<|}2@O*iZN-̾L#H@U}_\"P+a(WRT( {fh@FφX @~_} ~b 6+3m &ݼHsRChQ'55U!%nv˪505^M>_Ox:|iIa#HU65c4]SFYoBBLuV/7~]Bͯx#/S|X7rjGi@|{^z[a\yOpϩ3-￑cs)f]deU}k›n۞uBΐ\Қ4W'oO;;|{H)O^^Xʤ"g0~?&هO_nf9򎑷Q-I0fCDY*YҸeOj@%ر&)'0U @0@,o&Tv#dW~WR c2TQݢXz<<,Zu=9UL(;o/CVO .rjP@͉õi̇<{Oau`˗qUVrd#*$h (Y&]DF&ғOtx/`>[4 2*1۴ T:ɁOۯ.퍊TsT$m4P4VZ"YKI}}[׿]NmmN{LhU6]mD@1=?hMPS)oVRL G z~)5k}lzI/E{_H/qДnׁRyrr;~k~K)F+y㥯­_~>7}/MXEqsDZ3n1iYnGW/G|'ٌbIr} A`'_I9X832}"&f-6i:[طi{? x˳fn K`R$v+qJ0k4e-H۵kEќTA@LA`Xa0z*ЃXD--Y\Z4XfO]cOjtynV&Üyh-G)|,֤ټ#:3: =.]oxrh~wSHMby@_(` ϱL@kOU K؊$dk* Cw.Щ*Sr,'H], Ϟ);`ZtG+<}<˅(t2$Wk'a)NLSAB zfK,KDdrtUEyٲǩ-8tWfCN*~(f 7Bb}PJ @aam"ڇLjn%eгz$/+jHEp(PÊ24oc/Η j|Dz 6l{=gZc&}|OƳGǾSW}|G#Ωc$d7HUˉVĤW]ǃ*97 B{tĆS7KI83nÏԹg?xJuw܍wR|5_H W q]>@(jѫ ׿0~푇k' w݋/n7 hFi1,.y8Xg=/\'+8U.S7e܆Wz'qKq[Bb 8W3V*wisb|ý/{'mELqۚpݛ߅U_{O=pxŭw]co/Y?` *.uQ$y"#o߱w^=>SxT[xљ[kn o>jx6Ac}Ÿ{3[;),4O]/xor wS'Hj,vJ3c`=wߊ8xk_%Jݘ{Bn| 2Cё\r"t ;8qrgrH"T R„T4&`5tݖE+WAc NġX-{ ` ̯BCD"vb©;>f}%4lDV_O29^ӎ@N֑Ma]|,e3Àˋ./_.Kiz?5/}ڎpcU kQ!@B bۏsV(9Ƭr9<,!⫴SLn̝+>.g85ƭ'p:w Rx,F^&g~⺖r;~=wU ƪ8wtsG "ܾw+l);ߑ,Z9̈́y>Zri1jG:`d7CxZ_FܜpZXV})hmf3CS+J5mɭva>r n=[w0)cL^Ii.8s@B)k1`@?0渺tZau馸c$nt&`ϱȿ`0 7h % ټR#'t-5MbnB DŽ_|Y<{p OUlwêd{'="3Uڳ0݈Kdc籿(BAesWV2R ICUuw[z h1,ו S\W渰?*@P㔺JKKQ@ m N&W ˞M@&Kfs "BWBa0*3 tKFj2m5N&&H1 JXlZiXQXVt$`CQ DMw{2wZq~'[ j)J!ڤHf'ZqZcj ٱhs{-rvn{P0 ,JE!@{ Yg>y,f3Xgå( ,/>$^]7BW[; jf"#Yj傣g(R=P*z@W`3M[',n/}&9%*s8|\Ո s\p]G8ybyãVHP$8tPCKXI"U9"t]܀*(JvW{5 i,)]G(Ez ՀaPDepI $z3Wd 8yb |;[>ߍgX*<,MhNru J4+Tɶ2Dn+֫Z WFI}qDw?_ħ_;2}xλ1gc*lzd'>\I4oЂPsbWtO)`3}n1{,i#'x!iv&s0@w)g$9WCtnz&x]K֑[vcu&P&J⸒:BM]w.W$ME `6ɖ%|q4T;,`BV*R=1NjLJ#}07 IDAT:>he(U6 G4znhnX[`f80N"*p;1YQVCųO_ĕKWpiUR &:g.c@ Xg.΃8sSк* + úD 櫄C_Kٹʪ01&(]bq1-2 ;]rXp hCX%k.\rBg p ^9*Q n7xQS-WƀJWP&v. uCq3_l5X-Ksu#\=ZUv)lmQVtj3nX⑯ׇdG(3 Wh`8sM$&{b`N&o|<zyc*~]߁tKRBXSY!󞧱Zh$9o UJ zXcV 8 fZv.O#&w خ _}d +=6,:yrj9J slGM02\v  _M]CN8Wp0F@lcae4P XvKAmȉ#Rԥu8l&sD21mk }5S꽰3 c 2‚i~)O>lC ˭*Rf`Hi)Wf it.\&w?Z4\/&ØmˋC5#Dʅʙ7sp:b̄~(x3_K5ƚv\? %ZAh]p8#PTXy65d bC+A,[ۻSI5eZ+%V*PM)6}u"dL,-pef_xŢōpR'͛Eu2rGDA+ЫNվbX1Qj_QWu,JP%N ,I):`2!L#ͬ0Pʧ1 X:etKgnQ 19eh8 eꜱj1<]Ь;y[yCc2bXvl48}'/31K|FJa0ji i-y]O Ud4.s+XyqR⌇5Vzq v٦}L.9 5+0ΟXɆ'FxjѮhL3_0Ijb,IMyŌ1 $0Sgxx:/2c.d C\cഈ PPWc"eWxU<'1pEG^p):Y2]IAfMg&LêXUw#n"̺R)+~ bƊAG$jXR ,ZI#utM20F? W[2(AeP/p4Pwb,*OLO; XT3K1-cPUv` d01ne T&³lD*H`ȽU3On֛Ocwg;\;G9V 1g1L!a% 9dž 4c!Z=n?Gi+}x>#of|79O=r"U߇I}f7`ݭivcG(-y8-U0*v*ϿI6Nx"(șDƕ>$cߎURN OMN&K |o5S|`D@N `_)ςVk+Y#]v6zZ@rMB h%/J%LnŌjޢ&V>~`ÕOVlo3pzvm0HA"jn'ŇVtQq)=t̨;PŤgjAЬ8wnx3c>G0h'OrVc1"VBAI` =a'2uNwb!#,;ZFB]$dNSsۙ W$-``{sgsFPs Kt͚:L!V?<<آ u 0ĊU1.[q'xyJqG83gv (p݂vCo+V(' 2@UŹŽ}2׺)k5 p($ JeM8X @{oy#Et\¯aůH‰BQ4vcPcTe%b1Bm ]_ER/6J=Y h'KFzG3CϜWٷBy̸s(Z,tLDSh<ҵaX)u1[ANer=ZT?jֶ74ۖ?Ar>d%yM:yFgETB纲I`R:tZ9  NV~3?x >mϒ#\ۗXAr]Q 4F/UF 2fh(ã9jMn1f *MB@-諲Lǘ N'r.J[0yb1Ge`M1NQR5%hmfa%U)@ʑ`D̒rPT*Bz&\98+"tjJ~app|I*L*+ vmwL|*M1b`]B,aH,.ju7_$T"-u? -(e"LB#}PcV WXX(085C~ M}(M*bAM'la!0(R-4VRUQKҬir'iu,Op|t{ w DRSC6!.c̮MlZ,ĹĆe,hK^F2ov<X 軭05 G%bZw(s֘I;\ ºUZ9f8ߡ<567lƒG`lkrɂ&bRwUyb"'_'Mh=f_g5iV uju ؘSK}blIYɴbԳp̖#耢a.b;7H{+֕z28U)pGO(! CC8hā,$u S82 45^ cL 䂷]_㰇HNr/-گjOgHzػ)!2cKsDå[5Vt686A\AHS# kJv^3@$ߋǼb\7o1HYƊQ) wcJ OecR~(6i5hK sZ|7Л4O|< N[ex{$qk5ˀq"#Sɦ~'E %`%cSyH Y0.Br.x樕Q& ^|EB`u8aƷmh8XT  ޮѹ-5nx,?@X >/etӉ'a".8֫t*Ҥdgif[PjRY]nF Fߥl0z,i|]7WB]Z+\lW 8y5ف6HKjY"Žڥ΀$6*ozG_:T/sjVL *֪idRn@WjՎ J 7+Ή}HS8L(5RwCڪwvԗNPڷj5к!a~2{q.<\``BFaNgUL1'!]%:Ip뎙?Ao=6ꌹd]\ {GFcF͆$ܾyN1Lmn^Ž RE,OL03ӓyR?Z$IMJjų-TA˜4UFͺ9f)ØlkЃJtUN {p/>4"KЋn*\"mT"ZlmuB`r]ų.Lvd3JU E |gqP*BG5r@f[E.A1dmXH-ciGms)V b+\} 2kF'OcF"'ҀQ%3 ǵOޑJYBE~)ԻԴ1iAZ G8-MXXJ1T;FGEɴ^3ނĸ!cq=^YB9RbZ=oQBZZ|iNiV|ZQL7֜|xH,sZs$&,Uh/ al)_-؍F)chmK]k9vO?sG>8.5V~'`!dF0NX-P'z5Ū+0#spwL" Bl+̌Q ~[QLwzL: @~])Pg'8GQf# ;`nF8+("KpY$Hܕ H|_=jœf-r(:m% 5CJ'"YSZ| դ0;e=(z:JS`qH $=N`Ǚ1E,Ѻa0_i6 l/ie&-rEdMȓ 2pNz_mךK 0TZYXrLm-#0_wRq$ B(]Qċz-Z7B)rkZ+W T3Yi rRҬeyӖve&+•dqIDKW!A8\Шl8jcuبn5:-FCkS4"ve,k2k]Oi$X+z@l!n Ϛ, FqM[1g4j*氦afgVw`[HWW{E75Ѳ#ABTPT-7DH,Ξ> \W0Яc2}:t :^4id$P'pɴ:q챵U3{ȓ]x=$i'y PRU&[@W0z Àa7Ƶ\eѹuH]kg4QFhy3Jٵˆxk6eĬcvEC>_Q@8\~d28.m-*..}iEw{i&5gB>  P(Y!2Aamn!xSCvIώ$EMmͥs S+21ɊNқ B'S',gFOy F:v6!y fZ7t4ɀil')wpS \R IDAT]{.Yl!efjI[)ĂULJ.B&fѬc_<+ " qE-\ {]0R \){*^y`HvaW)}/ ϢzW+ c3ydwU=EC=K ftӂ2)g(,9]JL.Ra\$IPAjՓO2^fh*5=A%r]I#BEx#C,SLr5`ǀsTn:@2, PX-YYl=Ysoդ(mdT;=5<XjEӵnL~(j=󅽦\_y_ˡMpo߃ ,36=Xw bV\6|]D-Q4pÅroOmeoߥ[=fa '}%߉( d1MJ>ݹqMҌm |]*`G._IGOwma6"u&MqA@$,Ju׺lGmHxp>щdJhMȋ$5F k `/r{&MHȺM'T"p—W(BCŕ4WUơ{%)x;y :ڟ E*@~W2qTp(H*VMb>7;VDMu*n/U`0>8~a=~p0 һ` K6a=ƒOj:X,I&"%"@t`M1,MaGbB D__ v4yU}eU$B V=UtRd>0̏ eqX*c0LIIRpלHQX9<&x@ cVb%?zɓ)[˱I3ptS;̍F;7Y# '~iT[T7LG}$bf=.P^x'05"wgF$zN1d wEl&D2m]D5Z!֏NrMB^yހV(vDbv=aqm!3)7@0b-^H9M ޶N P=IEs.읾ZZFk!)`6 o 5Ma^h5EuF4BXM [N qm퐣}TJu2_//XGc2 fcQaJ*%U+Xӏ$˃>Y<")xȀe*i$#IsXv\KӁ5v=sK8}`t?9xP@Wc`Q"PVro"W"X *Wl1JYCbtLjVf0oRB2Rkf$i \*)UӚȈNÔ5yaWSsट/0LvDtZ|Uf C^F*8=qf!Lѱт,r|' IC [[lmBp. Mgpp8DžKG`V #9¾ rr&].Cp3'>9,:eصbX3*mt%ACaǡZLahŦ1i%YKnE` p0[ !8*;<͵$7.dIU:Uߣ1&vvOYWUeQ58 VT#Tɚ+EiHe>9Eѧ0 zʷ$1޲i*ey{qU6LVJ _#,(Wtd~u? A BAкbhXO:Ȯ\ZDX( 5bnjIXjg@Te ]ۺSؚn lCP)jcI?c ;+Xneȟ9RmQMƘzBGqiqtf-ז_Ny7xr=4&Ν:np+$ڗ,l7iX DiM۵F#`V@ Q7LJ:@fza%+$G&{PQOM8&Sit)ʤð\E r(eg`lm,hkPt4P}Mj6$ *-p+%`W:c5 `V%Q}hNY݈ړV:9nĘ)M$VU9 O,PI'Uar>G)DQ .Lّ)Z+V⤔\+HLȼhA؂g=v-ť.t+"l?8,dvfKɈKjʉ5/XJL'dmC *ÉYlalE d7î"ۺa䛌Xdp|¬eGbZR3Ie LgQM[nqC+#V|MₔMOhc2Q!$( b~=z<~CCԼv h+fBhwKJXq$ݖv}FrFx4e\1>YGk:87[SlgKSkR% e"Zbc;i@xx/J7^-ͪ_`+gbuq_rֱ+`b+K,+ni:~m}X]ᗮ:05 bLȂ-Lj Cr13"w)vVH-Z]p2 k$B-TP4(|:Unր|DvǠt,EብFz1ht Ʃ$14F~P&0ݚcm P&HVْ>&FG? , `p!`[v'^ԉL&ֺizgA2Xcv/ 個Wf8< {,mM Y۝Lmcf̌Ųb6[3A)e#i)&KR:8+8c!kGy, 8wCAZ,![I9=gNBnj|άҜ҈ova+n=5MX/BRz7>{h3B };dkܒZ/6RlY|FrHFcsС+xo; VXk74/ؚˆ]x}d N=aYԱu"/R[_CR )H:K4*:0eg%2V%&$ HJt+ TĺSZS%M]Zuݭ-VZ*=r!1=-+ʤsR7af(臡8| UHj)&iU 6B計Y92M(Wݴ}WT[3t~7+-cGrL'J؈P &ܡ֪BkT*NqOV(?`P*+S\r%9 q% ^͓%Bpѣ^<²Лi!*Jtb|޶(#'Prd7G bew/l3-ZUbˍ[D8snc{g"B@N5@7fh܅C̗ʧ% `h>9NS;L?Y?ܴ&:$ޤ,݌wLs4],3#7Ô;B@zh}RE'hQ=,}BB.Aڴ]-shs~ݞz3I__ȡ ͶDR [`L hۻ;ZQ*A\PjS6*Y;.,AcR| 1r)`*ʤ`RD8HZY.B:c&uE/iAapE[H !HVvJ@n,']a:j0􃺼lz)[ldU+ [mLSqw=*]>MŎ*Q)t"[f%ζv g2+F۪,L/lf; Ȯt1GLVٮJYν ASY`d=1:-@NO(`kge>*ܬ3g%\R斡Aepz%Ir\MH93G=Z[C&id:[UeF~BxdΦuWeEG* ~y/'=91]< +ۇng%߾=qq.5//;^J>{ruW/w*l+`jc`00Ͽ=+>~rTU0&o9|XV5:zٳ^ (E.5'%bha]5j?uDM7=szCy.s}SF<*Pmozc: #cJ\ L~x:pc//Gb"FRc%)k\8PP;D+;˞$0g}q._qÏo\[\<ܐy/BX$l-(OWQ,ZpgmU9p:C~Dg:e]2-h4WhI72V SphZ <J%Uc9kDOߟE{|b ~9Wz{ _It||uuL ~b])˚?kW.)$S a? `H*iD ƋI%|ʠ p3W2e 7f`HM8-(qAJz " x Ye7}?02:%@mdMae uOfvPCRc۬'1'vLs2=JO!G"TTxw݊>Yp0H@@c!|OAU!Tmb[Z!y(NSϪ+ܑgp5@ϯLȰ#΁Jie5.9̽]˳n^r jx58nC?Hyrwh_uAدk̜W{ݛD ӭF9&hDLV v1XElWbL,1~8+co.xK lsRb`52XBo-WS;/@@f[q_nRHv:luEROw-332RZ5D9b8f`8L3ՙm 4~<[ vÜ,sZZMYƴ84V 3nnn+N LkEu 7p_!D]FRQk `oS7UfK=' &d3! %?+~#nBiSB^dT";_*>Gu ~|O _ 8"-,8gm96 [:brrE:ܥH8Sط5 =;&MmI.u5"Nԟ|#UڅrVd 2)DYZ^XM%Ktҿz, &W+fY>DgÛPilo] zӛwUڿcD-s[ك'q$;K !,FXtX*-]{gY~#`6+5{mmu9&i'[ %.FX #KuZcSpB'Pas?b6$/Agq(PӉfnr',wN|km|3Nhݸm4j°\Wf5L^ZdX2].h W-ai-DEqء"cb\A#T-3/@-9_3wJ5| 1n[/;&Bqن:mJ1gy/ehqmxޞrJ[.En+?^\b']^sJ8vb`ۚY1;~chU3݀zR&H*@# `[  S1[icMN6ڍ 3"Fl- \H-&R#t&OYQ;(<5No,A  +lO~g*I+SVg՞|=p7+xr"ל+޴Fm:V̢ȅh۱tב s(}rz'މ~f0ЩƂ\t8j|Yϭ я򯧍gkҙϳRy1r''z ȷ<Mvi:O] cLtK{pp;,v",cGdrD1w afuq`6bl;$"`jā{==or*i%=/fy*<.BxPZ0JbqNx)rw-9c5n dNs'1 21e}Mnl9' Yq@: ?oZh[3 J=+.2tφ 'ٳ YR4އ@R֑OV"rgSρߝFEX]^o Q/?pçOW m~]X?Ff*VvzMYy}ʚHM6x~v 0j-iHd?&(S-P& Qc G|rZgy}vXe4 vb)?|~|Ϫ o}VZ6[~0A(X,SÜBۗ&ɟ΄L Yn +!nl%5ReafwUc_hf!i>):@a,oi5[x^h}JG< l)sBov/m42J{jL ;Df"o8IvXℸgؔxa:H\i"RI_!ȫ/m QV xBjk^Lk[ȞB?+ĢXZOOHʬo 7swV߾Iy;X*e*Z8bՒ2Q#aN̮Y?4!Jk+,eXJ.u}(t4pSvz}iyZW2Հvkɘ85:6].&),X[WLPEk4r4abH58YD|ДZV8QeȘ1&#nW*q82R2I1v늻_oHӊ@qK">zs0@Bx]0` E8Xt7F`s/*Ǣaa G7dL nۅp.ɘgg`Lsj(R`e5F AK4nT9YiD(w j% %rQIHj1woUU{G4/?^8&/,ה!}?p?X\֓́ku:(%}z\]VUPY]UAGcHyWN6RfKSs9 `Tw ̲F}"%ytzzl%t{nx8eRXTnLS)b鉮ϼ"=Yk޳\ Kq/ߝf;/ux,Uźur.ݬ:ڝerD4xAOWQ4DQ"7SĊ>p]jK(~!q%#ȕfEufqURafm~92ăƭ9Q>3csj蛥=y,L qsfql`mGl2n}^vža1L08ØѺ Nќ`&tnmCߚPs߱w(YPz2=[|92M DoxrkqQ՞8LE5-CW*^2+NۘbpceS)%V-K'Ͽ1ỏ/$OK+|UC+ec~6-,Jnkf qmr÷q`&4M}l !!8)yu:3=Q"=sZ֢e^'DV#s R푌c< K><~O?}JG.A7tӧSy*O:VQ5+~XgXt9<0 iȼ+{txd,Vn|<\]a9,߶];YB5ewg b O@ tyytjH A׿qC#r9 J>d/4g<]jOG<@`QKXD ؘ]<7dLd9ڄza"jyj5(#5SFYcdNl\n <)Zmu8]A&\>`n Z7{zoZsbqI>0S}3ApP!2sh(Z77%jōHW_ xi ]Aрh8U80'f#Lȹ.pj]X`e. &r(Aur&|Ŋ7*._gl&2 PE͙9!f]1ly:vA ˎ b=&>=>~ۘ _wcei"!D{ґӚeL*uIpXUZmVS 48 j Q<Sc7- huY֚\|"Ns]U).ٸ]Rx<6 *׿'$ps?wt><J=~v U}9\&-<;fDΝ+Uޫ%Ί8ޛ>b7/CNY{iMJBZƷ; q]s[ψ❦Nğ}ωmxyZg`6|x0I>tihJ}z-3:kY{ttX\S@8¶66'5f?7@-K X(cDbniʔ3O,4:bun|&Yi֏YbLT[Yl1 Zd(8DoLZC 9nbAA#mۼFJHZqHGYTM,gK߰m1q\qː5\ݒ2[VOnAQ@`eU,f_2(1|SJXRXtH#"؏!SqHaQSSdl,;UFGH\\lPKJ:xwGzx +|$`EYJFЩD@#VLe!A1݋H@#.g,h )6lHV5]G93q1 Zɂ%Tc-_|O?ܰ]=I*w䀞ve}^VOWWsE#UbKZ%E o;q鑒%$P{c ~h7 @dl%<}Ms %7| \ !` Qqwq!Y|4TZU`L tj(@sNr2+^G|x͆zG!rۤax/k=m\$䩑C,R*=}_Uw@ؓ'׀\ "D[`!_9lԡO^-eq?;f|Hy⍓Ki}^pDTF]d@ߙT>B(DT*xWla+e ]rhȑS'H=  o }u I:yy4d ,Q&JylQj23!^H4h,{,'?ԜOlHvw^(_Vb꠰˭Y'orηN}zT^ x4'-{6;.X 5&,>x~MB=@Hcj[w`x&[={`iLRǡ[PΠ1m\@,1FF`j<vˑsF$&% ocbeefY@UV֥jn q0E&_PX@`V![YnDp. ڈ+pĮ$l-Sfaqbv!jT-*)2"yî}h1T'Ґ@RX@t !H~K%LQ<8"wY*VHBEl 5羘*y$<TJqd`.}V,!8Y?`jDǘPӪgs?~3kK6nCqI8ǍౚW?"IATZUi-K60Pҕ3AP0@y?++0fOk*A1VA~cS ]vNFek;a H֊'V ?gOq+k fX-ז׃'w1#~S=պ(ɹ}soK-!@O;}_= ;k 潑\ ^[+Uded/>RGQ* :vbirƲ{I>R@ 2ex\90%Hm։@|NdeP.h"#sAUJX6S(f֥3\Bb,)K>*mit#PsyK@ B`AXcEi) 0(MeO(b5p1N*+REWYTZn``|ĺT)}f~[ē#!nF3>m@#Օs,wK\k#-T_;(jx勘7"t`M)P=6Œ\3:+_^:?;|e.@xV:qrZKS)9e=!W=i@F>Qi.&AJB˖rX|WZ͕BՕrSAVJ<5EbHysiDU*,p@`b(=#uZt;'ZsWCf&sۓug`_;s_ei,;Mp(eoq^늈Nc:I.  jɃ\γ ؘlJhnz fTchT:cٛʰJS$31ֿLRX IDAToX5hr8.)'EMf!dJd$6;bKޞPZP?ښ@$_(x]!S:X"p4mjM~%9eN{., ͒D|^ 8@/a I15wJ:xH'Q$DO> % !F"XTQ/(D<ezL\@*Q||-']VJ1V&]e㖲 I)}7'rE$a(Eԣjໆ4c'A2 btņ!{uY?5(ZA8A~ǟ?s" eR4R"dcUÅ. :媝4w쵘#;]pBd^6%u^<ȥo@7hƛZ6' $,*.%K5)P0՚* Yf4[,<X~MJcEksCĹ,U*%,/Ao5dE.Nt'5G>Xs S@$b1eW枔B;C@Kl?x~lP EIԓu/fWMݐ;em*9.P,!=5',77Fdi%~Dy3( eUPaä?3/%s!d`i|/h=c1-R'Ruי{r("30PLw}2$'a])8NPQrs] SS"FXaE,jT-P~o]6uBE>QMCrTSr> J#b9ᗒzv]@H\^pQXJ TWRv@L1 q^_K}8:$/À+EUjVZs[f$^fqc %rJS!>/JXO@ z嗢>TN`~)zu߾3g!QUFQax fJ#'?@UTX!KvB&ӥWxUqN0E(\e 'wohݞq`gmfB@ф92r7.ƞ1}T!h8 qy'V)m 'I[* yLL2 ==VbZ$'8$2+E$@V3sOâ֟tl 15Y{T R{)sh0 ϿY?o ۥ'+tZta۰%*@4XV FcLM.23(L@`L@:zTqoE9B/,=(Xj:RBĠ-m7ǁp "c /,f4!#%F52@J0ۜ-/swvvks&S0zyi`p bcLΘA<-;J2E Ȑf*tymn7BZ1trL^C@ tx RȻSgcEVr3k\?[ash?I}ax< VS $Zpo* d إ(՟ YH|~>ֻj[sgE񭤾qkK8)Sn.:mB72V&^YmW@%A@/?ӻo[x3;9KCA2{"q_L9jk% Σ셐SLV/^P)-q:;M1  Pv/a. ̩lv9pmfc `J[ڮFD5X)i  tL7\s`&lCN͒9? 0>6KI;H m:T,$ j^1@oqXF(bB Ȯ3N0Bm.7.L= GG* %n+h[;s avr1lrst 7*Йpup7KʱkyLRR\-n`*>u)< ;=5R9uŨȍ'" Ö dPvm 8ꖢu^JI۩@Y FPa|.9JfRr~ͩWIkF`h31,fR1Ye e[S"lؔ,jB΂Ti%T7 A}]5EUNAȪDVQxEEKiw_iR1H%d8 LTpr^|+2*MX8H4bLۊ0xcLe~̂U D-Du~3'R&@tX%tvB偦Svv-LM0w~LW%|К)vbv.`)cBOǴk?Лnpp0krS(zx; êjrZ%R܊345= ԻՑM* "1㘘1u<47jo\63]0pub%Tƨupove4)xS/Rdrmj2K"&6b2\ x`c]qh)[RtML5N-jt60Jq W\@Y0bbmh̠f(iMfj](4pKɑZtM(P"ETo8hX#BJOmzy֒ZtܮueBG338e8ogBMb.Xc!xNAJ2dS/!9IK0⇹aXQO>:@Enᐁ}DYFFu)[+.#<*62 7;UiFzj''d$f]-Ayq*1ct1 t(h({씂ni,b| dbz r`>n /;hsm|vv$VMN@/ĀDy-bztF~/~ԥlqiD'CqL5|4L b6洄0!"n5ĢV; L ӪgMq4KDzKgg*i"-5QS]C.|?`.qu/ C0$ 2CnI%Dy \*Dw}L#.:OEdKx:j(ɧZd,lPpk.RwP:PLxA3,WUmhz"[.7^ MEѤ8qT S 5!NV@˔NSOz7)CҎRxnb_꥝dXdvU{QH]Dp<ܳ PLXY dյB1\:e(tі;(S)jj.Hs(-T uC(^? q̾_Ȯ3W)<\~va݆A2@dոx fɊyq  ZApjV utfntgIln eWBӬ|Seŵ%Al,2f~ULK&jgq8,kJ̏;J5o+o;~a րfK%pS=Nԓmdu!;͠/ ?bBCm"r MY4^:;Y{O:t:5ޘZJlFx'KyMfu=7`!Z@sbI !J=,q ߥjQZC[9iUHFkd ֋9ss:S/iIwm<%kecՏ-z? Ѵ7\(_NWhģ|8ƪc] vTXrANZV8^<4j6µ>t_;>EHvc&Cy64eSjQ),Urd5CFCkX}n5aHe$@C02'֮q|P}+DaZAְuWstg`nܮP0Xf NpFv?p@EMcv7Mh#s"C7j P4^:o_Pֱ 2&_x‹чGzo`UҩPbbJs!u!ׁKgw}EB11恩V؏ 4+7I9oB {P8l@F2m )Q1Ro@ 浳5n܌5|h] ̭>`4k1P,g`KB`F,~vSL #Yn8eV+s3 ,ntɍ3P4drcAJ5D X{ya溆kfԬ_@}c?6m$hI#0 Vw+n`} N] ì^ rRKn$$b> SgSͶ\ig|.EPnryYKW;}Y1c-/x-Vk;- @aiŠ6DAˍ ݿU=?8"`a\߅3tAе0?gRK\ԛAṠʍ'сTKX\Oyv2eR d(~Į~ya=`*6({F^|ucq2uಉA1QNF} n44Xud fgCJf R2AhF%c[Q@&OA@ôq77 {m(0-;a2ˆnh#n,V" `Yv|

@&<C1zl/?~`@EHSÐL { 1؇]̴6D^IQˮEaڽhDݒ25 -.uR:'{ ,̌rag:0:i\VЅqĭM@#Hϐt#qKb I>۪I8t".SJ[0@ ^wq7ФYG¿CX}m|5Ag~ӧIsnU0ݵkͱ RFr%xJa#Ym[>#܍Dơ+zä13]==)RȬ`bLFķJV 9JA~ ;BXBW ڵDƪ!,~3.tM)*ȓ #@&0|ş~+b ҥKf͢m-f*^{uzX $h*g`*Lh>Uoa ]mpUŠS:Iw} :LZiRUyCm3$3 Q4 p(EUo{tdZ`'ح=@OkǓA!ۻT9h^%bjt.C 7D@>SV)Sz |]UϿ~Øﮌ%ێƘcǿ,&[e#|;[|O7_Ge*FwXaWɾi7{[ sB*Abؓ;cY/\5udp?A 䁿4=c@f8./FfG.H112.f9`.sfZ."3[t8/W䲘a4̩x,H|9 UWD@k7po 4$X{\'fꤦZ#g__]7kDZ,5\zCKwW,߾z#xuZy6R,>P`<0Օ8K[OیR6`ۀM!  IDAT0k, c-0xߍ*pnV|LB:oЏ񓽈T{wzͿQ 59⚿cKAS-Vaugo:{8ٚ6,pdM(C2%eIiBB D!kZ Rkv 7Fp ZHkq\}#τv(ۿ}Ͽ??_ &+bCp E ' r~4 ,-!ePO :3ΣK[sr2P2 rE1Hbq?n0{ήb7X奰uW݊cGOuQ|ަi%+}"ji[6x5`}`L~rÇ 6 xLŧ_udZ~];d ^^W|;֭!Z,B(MaNm %[vÈ"bY >\@8]gxZa #)ulSK \o`r+3C\hְ]fOS<_aЕaHt(az&I!F{gZI[;tmC~cYПWY(c cn*ْ͓R7f~Cc8K)c &(q> lf ~hL!dqiȅCvm@`x7lm]YcjJ/YuNK@Λ{gUVH=(Uد LX6b@XM {J@,jP0 ygT-'bƴDĊegn/JԶ;<~k9) )B[sx~>0J("K<'d艥lN"Bv`2;~+_ͣ떦^hj]̓fTdžif1lY,Kn#2Lwb($QO֒zR55L9DG^2ת w776 Fu7׸M 5[/8ʐwT!n+nj >s)oIFϩ+{ tqoE ػj^=}(k~Ol Mqk'Yb[r4sD28du5[&t. ƚdކWi-<^+ 9p'pʟ?_\ KY1up4qT4c>Qr^T=sܱ k ӄ&LWJڱ%][̮5!8/'jkN&oƒ|);ujsPJZ\M<ӉHm -Cu6@SduwAKoqϔ$q`;_)q\<BD:Bchs.$)v "I)ٵt엫 bF˯k $iS2²fkct)J iz-T|]3e{~!%/.5tꈙ?zFX%H!;H<^ _{bcA0y͔AOVBY3rK#t%nN FyGL+J^=SFC Δj1K4@vԍѮreu77#~Xb6'%dvnٸ!iNEѨCLHl1lz̩쳤{vw]~vUK~3݀n2I] pk }u_Wf2Gb!;<_Ȃ$:>s{!w[9dts_-!s-S>ʺfy|g$'Ϲ-o@)wQ2(N+ m74+H\,~xvUH󙄽*]w7*Taƻ8Vw󕟿6 RgI>]6PTO[ "u2 рso8el<=Wx|p&ׇIȚ#g8-w\D q'WEqSgq%9"^MTo7'{ S2eye]OBkmjiy]X) ^(4p>/4vu , Grn&烞&3)S2`aF7uUlDc99!kcNc*%%K5 NH.nR!ӟ1:H"Y>VS -# VZmS祙 M:<'oBqj6m7$z̛wo$* ;o>(\C$4szOuw0őwdܡy4M%oh "77gj3u`kp8 0j}\ =LR\ 9-w@vyb);Xկ~Bɾ[ &?Eܘ8 MH9p<~Za]wp'n)1JkX7TF؎,8V!DUv萋pd ,X_c s?(Щw7/}tPz~ux@+qӸWd^l8p`D_ / ͺ (bfc>þ'.s_+swnXvdBMu@/r4 w ׽edP7`p)}{TG>9:/$틋'[zl%SN;|ym|*ܟƧ;Gf- ̒{w}ĻBZ;<|zTu>qW*t\w6Heڔ^wY|B_7ʗƧǨa4dV14XvY!gnAϰpP!VF'" tm:pP haJqDdǽɣLmAVrAL=c/&x'\kԽnt"MS(6 5fW7)s^[ǒ]238w8ϻc;&?\#"^Bʶ5^bQ^ Lo͵Hsճʲ^e?jzZ21BDCpލ+E\JJ.KWVf%#/7rNᙚgov^ [$˚]^؆wCĀđ *_$,^n]XJ*_}i,d2ge.Rorl LAhLAڲHZ2yzܸTSJB4ȝSLjh3>hU }DPJ rNvMia`@,_LOBI G8:aBO$;rR)rQ^3$O, T80ܔk͉Fi-HJEܱTw+ sΧEH)A8߿~ ᄧOoKoӚ2꿿>pL%2/s Faذk"#6Tl8 _(!9Am81:(KJm! V27whﴽQkr>@wzj%Χ7oΜN*P뷡u-N5a;R9km#=Rw ƾU)%Bx- U+:V >W2ay8ÄK274pLP4wY('%J 1F7\~(kj9b$c9$f\XDZ2rgDnumfԳ9rg1`_#/[?<ܯ\nF9&%0L+ 8:)2A) x nӿ@q|ܪ٩ƫyc1d8nRuYj>~?ĦqFr|Z`7{r||d Pނ㔸sx&Q(uh8TO; F^͚/eog[nBw'fH..oRPmnBQ_0S^!L^| rN2utmF{B"[!C' 1O;2YcH5q ,fϾ噲]=R$Q.v5$$rreb(>Jܦ7\@yHGֈ϶ڐXrϭ^0 k1ȌTH,9q>HI wg0\7N\]j\C M(6UT`F_xЋrƞRsH=k1&L@ĐلLݣ\(q=ۮ1߲7Zݱ^Yrᴬܕ] ͳDϚK!xʚg:ݼ7eYjlS^$3xÇk,Xv8S575!7f{fw#Wj'u;ktWΤC8MyWfig ~w{S|I;'OBE Jd-nl\oL Gc3IrA.yKcBH;+^NR+L$x`vV|jH*~N;:)LN4鴠n._O@Y:IRq)9Ʊr(eI170~rks4dFS("4֒ڱYOBN̞ļK7$_$P]%ޟ9Z'2 Cxޝ-A&GN9glZ8ٜ\pż,+YY弐SF$p8Q.ՠּ[bZw}'LZ bݳNs{ciG+%3NꊰKCx5zB;=6Z9+3oU{8Lucfީ 6$L&^㒖Ltp}~ȡMhf|&U钎$%i-|o> !zH+ R3<Q,$2 l8ᰳnȧw']Rh7՛%qZ\:cw@cN!jZ`aPS!k[9zJqΛUKafS3I@#A $?Y)QBKc< &87pztь2.`E㬌k  ħ#쇇na@G q23[#l 9ZNpcB I)o>Q'0fMcG|a/&[= nDm.5?o\lʜ7$.єoC ^m!_aûܖ ͲRܿ|Jxm/{_^k _(JR%#4$3?2}F^ @$r:ol)@UgL@N@=}ҁT(RεȾ's" 2C!~sw~a fQ EVK$Ily9[QD7;'RlZ5wN9JHR;^SpMYZ3`f޿KmRruRpU &>W3<ea9)S7rҩcc)-8&)ӄ'=x;2l uek D(kA{3l(v\>\S Ldvu.Iҝw#sV7Ak޽rJGP;V5iD렱R4P:tZHڱ{͂@{}|陇w߾f̭KG|M—\<}3,T赹InrDx:Oϟ9-䥰 qG^N [^w%pBgt?ѣ46uovqӒ3>!]v+/t8}z1;yzujDD^ߛbkb{ji@@C;y5I4@Ju͈SoRہ}Mppx&*0s_k%o0ݩt3z~oN=X?IV1JZ |E@(?.DZl @)~刏r(o;[far1u,Xy=RYJy05SA8hr@J2MčĘ/2˜Q6>267)7'fԮ<_{S}O§+?}|'.BЂ~չS; Xz}]iIxv>=W~asqd"IeNUoOKaoʗkO|w.GSŎM,55{/-#3+ Ēh{gS1WkDՐ+Bkͫ sUeI\7GjЛKD$;[gZ{Q7ldW~!.0YE{"@0AXdt>+j,tI=!>wrdiԐ" k9EZ#{P̩6OD|v [=bvԠ$5JNG /1!OYCh17 s=з| ,a7P*晎c]I0k8R%#mozjnζWgzT~RLn(4b jvAK uWjG{a7h(kb.Rr5lvR+yKҍ@%%w%GJەZw6 r6j ŭ(y6Gk)_Wt ?}~-|{}xGZC\XKb)9+(d IDATm)R}]&Oe/50~uW|O{#R//<ܝ_'❭f&&q},h,@=_9prDGwI#RN/ Nbĵ}??ztpI";mi04[?7݇{ΏЌ2h:@vU7b DF,3b\f.L9&I?11TtYQ:+vmn~~>g;ߏZͰ7?}"qL,] ܖzM)@rݕ~2S:0}z>7>?kډvd=,SF3j$v3.f7nAqTޜs-}ڢ9aM|<]] DDz9߂XJSpA3~5ݛf-^ !7>9]rrm<-.V<1WbNJ"KDFÜAWYANO51B%Sl|H橷:琔a]fIiq啤ԍ˥h6EꇾWPm_1kR鞁')@ӻ+;((q E"CDf}Zoe/3z^}m|QoM=EIEHKLc3^+{iE2992zlD∬ٝSLfJvz٦@u `Эg3G6}w<)퍾7eV1BA}ƗϏdIܽ}OXڢ`aЇ<&$ [W'~+~,+9iSoI;Tatxytr;uiQ3ǻ̸>n||ڐI[dB ww"GF2#OOpD[ `'zw<w kɴ'[!vYpƑ=9(\?+}wwf{"4<3r4JjY(QF?d-/6eGdeF;2fFoȜB &Q ;4gZ-beع_I#0wBm[-st}d0cs%(DʫES쉁veSNܝ|}i\we*,trJJ3{^եUޝKK|DݟX aא0sbE]KUݡF§/;mo|oޜX l{rۻj-ys`sN Z?TNDv:@ctdt٫ y5o/S#uC$#洅d>O'\vJѥkkeN t1kG4.S+'Ht'ڝ Kl: ډ:G9kՈ CaƑ;-=0)j:"b7uN761rWɑ B›Jv]sc0HzDw@G27G=u۸\Q:eq>)eNw+`Ӷ}.!@3eޔ#2x9v1k-3dfxz3ubs:D:daC3 Eo>Kmނ$ݍڒ.X.Ӷalm7Iнj,\V$4s18mtyʮ呧[`F(!#º'86bڜ)'Dm47 H1j'#kX.`"eW~`#w͇88f7ϒ[ "ɱfFTfIKedK>M[=>ߢ?3dXv"08@-u`;r ng~A$VIs42cߚl--Eeoϟ7<̻?|}NKKg<~21p:)Wekzs חS kw9A*aGnta, 1dZO|~6vz_^: wݹ|]*_vjuN!XDW_b>2Gqe "Wt"\~Ryx{Ҳb%!f4-m!X*`Ԝt1vT$qc%w!M|_p\WakdT^k1''/[ġP.r`Ha/?Oosx&Y3k=R׸V\-u-^%sg*gSft@Ź^\"/Î?D6~T@DPf7{F$fB,nspFh̿@`zdɮ ^+$"s% %q*wwa}mkX9 %sZS߼++N 96b̞+&o>]Tթ:f9땧|. ww )5x/%vguک}2ҕ1{⼴?S ƏP01zB}j6J%5M3^1R苰Fv_ M..z $, v&E3x]5%aє- 9%./W+{^S06DXO%KJ0Zwkʞ_s#EXl[dC'GYƁXrn)I-#0}'4@eEM煡䠪dzH)ЅMSlˣ x)zQebR,rVd~n6v\V^#m~DnGT?ܖed+~4"Paø43Z]dqf #%#r* .o : 52φeݹ䍻sPwyg_Kw6k-ʲݙtk~D?D4/Tm#ke/S)JϮGzks9K)y|PWA6eXRaܳ`GH1zeΓtM5#ƻoᴼu'lFѪ ?30& u$9s6K/"i.IHGϲ9zN: N ^wLҮaxOx 'oޟI'p>&J`< d6FfE{UJ& 2J e"pSZuo'8 И?\yRx7=풾|篜27;hnunykcWynl&oJrjW݇qyy'.C{ɧR&f>+χ\LX9Ӷ+ZGiY:#/ aAĞ|.G3֜8ӕ|awп1VNPTݔ0-\@a|x%\J_Bt0LDcFMʯձ[{r}{*28H UP:έ q%yT^A|QS $2'ZlΓcMyyylĹx5gCJNuh0xC&^\(Ւׅ%o3($VIO9biJ@Y7uۧHݳEP6BĻ*ne&8PR:X\E~ ºfR\w<7$eJڵWytfGJ*V'Kbˊ ~r´˝vfQNgھRX8 7k\J)$1ӎmWΰ;s&X/&""4BGFy܎ڌ3e={Y|{T2%(A]I1BÇ*jŰܚJy28%qZFW#|܋tAd =# @dc@B\tރC㍐]sVB)6x.v8=]w$`۵w^{3$ƊO UzCJixb,,\LFwc*KhZ7<}׽?_h R;_= S꣉,<VCU>Ie`^rlwcbHr|)HSb6/%8q\w&N7tڑK>lJ1xREq 튗{g, I)걎#4uZQ$G0wPld#xr-zI@9&vMKϏH?xsr>e"+?$8 ~d>?ǵ{f3O `5̋Mଌxqp{=ߑS[=MH`#ǻH%i 5py*ϗ_vj0*5>,qVKe  ]1E"`dHJ\2% F5ѧ{S*٣%&[JQrUj2NK!)̚T #j7\mS̩;u1_e=#[^77F x,g2Ir$P0~D]|<)NӍ7"x#à!QzeFkuD9#tHHD)I*r"- kY))COZثtTXʾIO|jb{itG؝=0BWޜN%teY._qyٜ '^c i){΅uY<%_]_,g7~˺,5UVԨ}gѕiRRD >,\MSqP%^k UϞͫP[?5I'S.ɍHrbaity H+`N 7e ݞ>{IkYRhU8F=RD\>$\,CDXRYLLE]F=9N;ZT?j 0K|ùGMr0F6M(N}3g{ӏޞ oN 5s;E6P9dN}| #6~gt1=`:掉4Q?5L\^ 2 4.{)e D?w%Jx|e(;o!q, NJ%QV6"9)筷r\' N8tף;o]M`cV`NzFIg/ :ϣ/17 ok:ڛ$.q3yh"QUmww2^Cը,.з6m\$?m]KW/9H,Dְ #KrdI+S7,+Ŕ֫0 Ӂ6D[7P }38/Pm➉K$-} ;qJDpdƢ8"r&%B^/ -%J[-mLfP4"Ag$v\-b|kއ^IC.#ƨȲ #UI7`& Tyƣ߿jPTrpf|vᅠj-xRkn@ɸo/@IM:-s=~gCys=ǽqs]fNFc2?1q -z窝 c 6JpOO|.r1F,8٥o-|o|_8- EKӗ?wOù~!%㧍?}36m͌/W\yTs(sS: _/K Bw$! [@ 9J#5%knu۹\gKrvM M$Je$2Ȫtu4=$ޝuEID\9BFӘ ]*m[ne]5ʚx|޽׌ӕݽ/[WMzHuAjxy~a=J Y iQ. }aʤ(82ESнLARbV IDATvkیHj헷nDy Gvϸijŏ^֔.FHpT1m=Ehx%Nޝ&%a}/uv4:I[\wN)foN\6W&Ȓh9hВJɤHQ$pm?G4h,k&%EpLWh-Qb>nA%ӷF.{:QS3s}!`1iszZ>04d)5යO% a$| G5᯦JWX*L"PrdL K݊ קD` 2A-CRz@V)Q[ΧJ朤ñOwBf"td-oJz8Ⱥ-ŁqW탣9 R:~|֥ gC"0A-u ^u9 ^k/W?/{eP"h`d>ae_W_rS z(f|x[#M|BW8W^şo72^bY;t |n&_h1H@ӗ_9ǝ: $[D?o_ umԭ ?_/OX cw T]DܶIʥ6T;.gĘ)\;0q ]G =2SXƟ(/[nqwتe< Kn7``xFГ9^+1JPYU-!Kko(QqQ",%,|\4ѻBnTFgs;Gf(9Ⱦ͸42Wq-+3I1k ʩ!!Wpf0/Q|w7{|R9 zԽ2tZ2r^i.F9%3K4ei{ugk¯=샷"0H.T l7x*^-[ Y5,)1mTmI}Pr .WVR$e=ei!auÕG܀ 8WN$"Dz#A@&"ѐ0wgiݎn7`j!;~mLR I2"o2 lʒ)$2!6ԝdF^W̔u%O3~Қ+W O5#bRwnTh8WvbX(!}ht/ZX'8Lr8h#33rxu/ n͵5U҂4݇A=١5))26RC'2\Dctq3ϸ5N9i%J(Rh`H -R4\/~#x<A=@3"GkuWR.ߛe1h7;k[ǫAU7sr0[^ ryb#d!GaƽɿQ]219Iq G,|f~oxûBzQU{WjSZ%X}$io ˅//yJIXl0"Qz6\3jablA7$+Dc`#E&Kd _fuYN.&oPT J1} Z؍aϸLEGZtZh J+l]py2bWc`=y)Zk3>#zFdvu*- ^z0X4Zݝ?QJjzciAmP,#Bjr%^]2gD( Mn]X$wDy,K̘_I{9jE33f2_dqmw' >,t\ ,P;*Fq,xX^#xkdtm6Ul l,aNdV ieQ I{=ҽX>2bk^[|2;-E9_O l$ɑ{]r)TU{z8!OWE 䰧 4jˬ[D*G%FrfG=3u֣┸IˌD[7ۂ6$ŶJ FJԍalfC0nX&K So^Q *eWY7;90;lEt#ں7hE2Dܒ]90pWO,+"XƘ[+HA\ǞIA(3\z[)̉*'HM;μE%ݸOė>l x=0jks$E J +rv,&L=4/_ut\h |bYoG{]F64⯱٧0n 8lshH4@X88 D!ڒdUM=|v)+ZRNAdD`l^~?~Ż[^-l[Avɔipa| ?@ yKF >4>69v)Edv?="6쒋qͮ߁!ىx'wg_ {g\10 >Ěx@,9 %B5Xl?'nL8a64yoJ݌lӺ뿺*yJ|w M+yhïxj|.)?>7.U9dvdmrFH3nwUcRc#oŠvܘPkNS\ -ƴR؃}7|:Hf(fr,ӛKyZh4| zOq}kT#Qd-5GeS %S$Q"$P[Kh15˙^`BburDSr8_6veA݄6NsLH1کpJ |6_cT2_yuSNLW [-k>ɼ۬Z;W^P3?+,с5\/SFgBKî_2摮Z@=\2d=\_87H Gqն[zo|h]tsCDIS Pנ.JN9V%/BF'G譣ސgUu,RLBatLɧJe79cɓo#Vf'ЄLΉi餦L_ndu>7֢D)#ڣ]=4*lCWxFRkqR[=_+ϩBoc 5wɓpۖd{s#=a;6l)EAWMB9)^\UKxm꺾оmTڶѫ6xӿ*\jsV S27͵Q(UBJK( ?aavZYARks )8{$ QxZT4<ﰵ4Ϥ\bP"rKZi AvT4hqcg0͇-IDiBx:X< v-Z% #<ي Y㮻0&swdlqK^IHL#R{͏/ȏgx} MӅyz~py5MmVgEUR+y%>Y%|[|Q:!>ò@M;*v=˾jcOA=É_wר>LQxuL,EAN\o{iqϝco`znpXS1D3aݔY8miwt7NOu㳛Sc@wb{[%H`E^}z7̰˅8.\.`_,od"гЛ8Ccځ| 㱪޿)Gtmע(@ɿ-8؟vNcVɐSej_RV.S}:+[*{l+Oğ}qcr66 m6W7]d WR8S3fUkϪ9i"6nTF<)nP2ǹ`1$]{[^PC%S8j A'\>iJi7mh]*>tDKh [p%36oi766?zPIG|_![6J|%uƞOٟIE#)z½4"]1*n٧}tf6O\6pdo*Hn"d51A:ڎ@^%q1bUxH=CgwOctJ[ę`NfFᏏ|?-_}qOSv>Ogn,<]:DޙwΦOغ8 jxJp)sʇKicc7e*ǃK5Q{GN!g CjYY{? PO8 #Ď<Ց1Ou 9e;SZC'%_e-_=Oy|+)oyɼu5C!4`ku>]FaO5#_IX%@͍͗Il(y&)x E̯?9:HByr ]0[ zo'^$}Xq4HuEq$<*筻^ >>b23rb=IHSM6F^ńt), P A|iX x*%Olѣ=*4k,q9yUSsx i"OMYSHkO/V.ԠE i^EkJݓ+牲LX<5\Y YBP29`B\K^]!n{nՉqĚd{(8H^ H ɧjT%6"Tdap{'.ZU!K#pg$?;8.ՑW M{L Be.,UW6ʒU%k;xZzhM#e\*>M9r.H.:+prIL2Uֺ9'Mibq}GՠnrxL%_ZR(WV*⭬ո-3SΘWk 2;=:yI)ͽUz0(#F2"tz˜D],Zv^m `^<~@(>9 r}oX}ocS6a*T@[fl)[k1[<=3pT{xqo㎵kJĴa檀9)3Nl=c֪p:9c5uɠFP} cXXZ'gr[rx{?+tjиʼnf?[*9ZuS3a\]*aL62qKms&IзӋq\f)Aͥya`Rfwljۙ(o_}yǔmve5jzE/Skg*np坳Ki"2 .O SZ֣soyt϶]͂&HuB bK敒iD$L@V0]ȬV>"@$h ߗ<50o_ GWoc坅Kv|k6?dܱQnbV3Y -CCSZiEq.,sF&R B7oC5DAeޮ8%?5 162yzs ^lx#)ՅEF,f`iжv"v6b*AXmz"*?W]?##&q [\6I] $ӆe Am@ IDAT o5jw3SSzs N!c[ceӈQ^_c:_~oє(RvZytәŸϝBĥUP큯>ܭ[޾UO +p{)q>5.62`ՂA jXxH Ez+> Uş/a$9+/^ 1_PpR&ʔ97>?1kiᘡ \ 2=zM<uZ}vg44%5:؈N*݂mi@A[ SS WX RRyC4oԟWP׍zɠD!u$.p=eL )ō$:_V,GB gRWjkѾ1{6 G^ᬗ\P͇d0O g೶LxfHh^F),,S&>Wc2vmKH-s]aiє;ڏ縭 7H ?{o}J:BT{Ď1W|󺃃4v6|H,pl$+B.ZuX78Ck oQS+eũzUˍj{L?7` qnaه"kZ8~ܹɼ0A>VݎѭVg3*|p _<=V6u5iJ.0;̅*U oLod9{I)8//?c+yyudX4.Er)٢HIJruj}H$~r7 Vakⳤ)9q9m||\}rn,)Ro;s/y[n}Bpg/pͱ[IE2vB m8{'-nN)0 W5w:Q8aC>5qJwul_kFTg)IɌm$I͛qa4w)Tӝ&UoӭaڙKa9.T@S\z퍶6#vdM J^y2(m=é̈́thC["WM*%6ܥ:m[hUx2 MIނ)h-Z$Iz$իK0>>^9ěb,bF}5Y} #JCﭙ M%p8#ک;o%˟E캙ÔX7%&lނ_`)aɱ4yO\Ps/ex@TsMT)i2n54r~bn][zs91ܽsVtT Bc"ef3KAty ֌G'>W+ of*2gJ)qHSnһyL)¿+lqbe{W.NkHb2yT֜7}8u"Δ)I?wK\o>\x9m8z}x4faOQ\#GedB)KSKM%v|/erD,ݛwR8p72hXD>L65.EFg CNM4ht˙i*k w 9[!\t=׶F*~iH.8Ku3Fk:]CH?/~q!h&әqgkRPRWRN73h6oO7.9L}J|@hX"g ofo۟1%rW|kM8ܢ$j8 NltԔs՝ RWsW1 wČL9dE?f>{+{3"ӪK|ITrh͟SI¯:͏NkWKéV'~|C槯QUy:m9]`?y!M(CFjb2gL;e''z9vl5I: OYz,z&,l3BS VW|2)BXL-4,δh򩺔}[() _Q )iׂX\cd5z`1%\I%%tr`k0mD\j9xPfY%=Tc!xE+a &N J U0O]{DMp3R:cZAا %5$^K4WV* 6Ej#O,j=O &T77LB Y/jѲoVQ3qQd'5UJkJ]B3m=JbFZbĂlZsMBG_z=NXǩg+״Th[T6ch%gxXn^a)DZ[aƝ޵TxG]⌕%+,9bH#Ojc'߅K{i{ FsL-C(F$jޓ3kO4@)}>|8X텀EQ7;1.{:hZa R͓œw/o5OT2Y~'~k~k7~Lax>SoӔO%8cMagdr1:1`Jۺwq ƺn0҅۠sE^ܱysᆒK<+?>]xّ9Kcvֲ 3AGH頮ݚ0ϐkRk0~p2rL0B6?c7+oV"Gp-I I2al:̉iNnUq1#)i 6aki]o6,B*>*=a$` ނ? q0t& F%oS M|:U}ck>00Wœs^᩟ Jzu=u.4mLp{P ˛&ٺ'ea,R4%Ew/1 `1X376X?d] 0XvZi[\9CN]#@ Wtޖ[L2zož;%a<8Ά 4ܷ̈́=hIJG)4-ڱ8sG/;8Ž'7>2W,P~AՇa$c a mJ2S]nb)(|ᑿȇ>4 -nWS*>s3g|Dm<=mԮL7kcIxoQ7F U^z y4Λrn|߼8:|t1(,HįBM~\C0^QOO<~$ dVSRRߞ_NSzuOJv{bq$gt廿~?Ӫ"@')x;%󪼬گ>0WxjbJ>x<F=ضxaB,ə>_ަw Xz"vT28ez{D/TjsXOdNmm2e.['QMvС s:@}ױ!割6-w4,,exH 'X&eIgw#}ceksZ;b1zG|1DMaj%]UbY)/++%jGX`=]g})ZZH!Cc k-@YrSⅧ,,e=ѪߒvzXQ83[OOg>LJ+]\Is{>_#/ep>piFoT{<ٸiڡرjSS?yu`ɝG>|x?c㴺#7nW||O|] h I&WhHWKJ)Q[J1U`Kc(e ?S[maABj eNw#8k:]]pF7-a~hѵ&c[xiuӺ_.-`l)C$1l$Ėa!? 1TcHz?]2bhv%`k{wSX5d#h,ʺ3{;$H% b8 \,ra1elx|~A~xBrw, mukZyUGyX w̟zF8/|8l5bO||zfpPO?mNQHurDAR_QRlPׅTNΟy90Hr^Ʋn?dJƫcPe7A\H*m}xd~Wo(O߾ת EQėqƺ6߇+٨uEj!z ИJ^8S&tZ8,%rxfDκv-cԌ)I w4 l"߯N1=k뾺zKp&4Kj$ zqʻW3"|rY=g6H`mwO+ǙT͙D ˀhͿ%ns j,4݇D9}l;k\*"w >~I ,RZeZ%g昆sd$ضnTLhkQOW8pXr33ۙi*TS ❓>& e"lXDž%& $j#qDFvAe-Ssɧ2(KIy6TrMAI㔵:0?;0Fַ'AP'D2erʺ5ueʉeb\!D"SR"O2z08?-3O Rkg$(KA\vFO;$q'2Ȏl{k͊`Ғ9t{a_$t{)G5ڋ:%(ƻ ]ߥH@FdLF0~\[z3U6:M"Ε]$qQS@o= q#w}QRsv=Wdaj /;L1=H'y E+|Fm, fWm|h"`\+sw}*udcgI%~:gxs6 IDATwk|>r,˂vrn^8}J8%4PIFdO_?s>9/^3xfx:%ڜSiU݄Bu$ӮaKE,E`^|0XUνǯX7n_6*[1[3HB=o,Q$ AS_QŹ^#$x!dY|Nl8qT-V.Ƚvn߼AQ3Qk sd @f 1$PqH"{rSUjh8r@$3'n I!-np,O>>b'cf6%Kƿ~ȟy5Ver(D3>/+{odՈ#Ƨ)%$( 덾5 7aKc;2yvkC90ΔiFrW/\ &@'j> BRam)֙'s)sY ŗdoQm&Xs1홦D!!fV}_xAW}'CUbS8)j}u"aι6R v[^iFؕ]3i]!+NB [(I, >F p^;u4b+{| 9刓ޭ϶-a/Xa>Ly#3cFL8>&%Vkm!FAKEϥpK-%,lD\ARn0~N`זJٓiPʞ ]9 _ -/ |.~14H߸xD]+`%I:MBNHSr H~2WO %zG68)'e\lnfmt]gZW޾T't(Hm^E AwYe'JQ]n*B-kC'~=LRgV [J|_ߙn4B4O hJN#ZQ~̇;R PAUr2ɑjTC4ZKZJ5@2D! T30XZ dx.JnjXHTc{(%ƫ,niǧ o>`2ޏswg`2oNp?]r:?|?~VuNARb3͑hgџ|wdnke9ff?zhyq/Va͋N7y,~Gdfe  8-#2I;V+mLlM 4@U9Dw'-s_UUUf?9M߭B`gA?|t2TtI FLGպ[|zu"/ G/#nΒ Lg+Kkrٸ6VyYX9Α>{o_Rxo e*֊5g0]%!ZȵAsor\0lļb cpV 9ey@P#.e~ݩ/8#/g~c .[rjo5j0) GndŰwE3[5ε@0j>$a)Hew0?(y`SďZ'g_͕]˜_ŨeЬ*Izd!*{/4j}t$Yl|FYHf~~ՆxKB*J,4F YmĦT"aFm 2euc{jY:tq/#ݪ@ɨ_W4w<@2}~xCr ϏXO)Kj6mW?EW| gmBt\E^1EuJ!Pk%-圡vpM}um*141bk\84N@`GX V[#zJRg!=*f1>jHaI>M;Fy]Fu0O`8c!>ML 8 7;#qZlxKc&0w6gsy➫tLME}ɢъx!s^{hyA1=1 !($y?!z(Fk)`:T:%]EJzwsePgA?@*V2bנFp2jb͛Gn@uY'Q#hXBn1>̏?ySR ~[v`0b^XmW>\!ۧfi1>`MBR w kSwGqrL ?#jQK[;jm_2EtjZ0|ŧ\n|ӥpݕ]Xg_c:)@39/9%O?<*+C(yd"|-HF+)-؊U\Wl~n(̼AJaP.A4 . mvSƾWԘ+X}w?OiUV/ g}vsN_1SCVa4v͝VncdvPܿ]h2o.~K?O }7L"f:?C]@~ t7t{ՔC1q u0NI E]Nw FZ0 ~Hvr"ިo&'IAYFRAF3B8Pu;L>4ȸ)H@V6hhR&,'LKKsixtn6 {4Si> nu1kUI5˃Q\@qov&c GN \6J5eG.1-,oG4K8 a9PB%&K#'Z)}@!̛zAHI_Pz5_ l| ޏ E12K8h!gbJ\j*paD@;cxCP97j x?f*HFDB(ӻ0tpQ}(!Fb7U9΂ coAU PqqdvN>Ю9$Y%AkWXg1ELkOs1>$! -__ӟoLΜ~Tf~Pn F⭴\Cw| e#wP }ڹyl#t ̺"ێ͹)4r#|g]O{wy]׶1ʶ]Gi:iK"ߝ)Ӫg0rr2#_yFBYW([Z7%m[UTa9 _[rFiP ޡ 6WvHy,C5&s/[߿}V"b⣫qtCc&pDl)?SJZlrߪSTr054J~ HLJZR VzK\'pwp k9ĚB@AkBSИ봈S% .E9pN*rn犵VԳËOfЕ챕l=l3L'_xM)NuCLT^a8\.iUBvZN LN؉ƃ,x6F<'‴xKԾ[sPtHy[5nU,A^f=,r9}`iH&UZGu)hFZT!v30x8G8bԣ`Z-(I6ʶɅ)?1P Q-)@+{pa^\bkfYjmRDaX\H#怂EFO) 9)Uܑ`$GI̾9:bt^~%2&L#$c='BBY{jy\?G9gdk>?;T8{e/ۦ-3[0%;D^$pja`aQ<[(Jq2*tR%ak ڮQdvmP湯KIB:ɋLM*ț9u3u̿G,=rql$g<^zk#!APu wTrB M/0Pգ[ 4>HKd 7;kJK%-u+XԍAyF+y=c1#eBMUk盇˶Qe6_7*)χ}׾6#鴲1ߝH9bwTJъbb⛷Oܝ2KX$s}wGk*6j" &0A?B@Sx{@/;OvIȗ M_cŁ18&IYFBk$fd+qi5 !R` ~6Orcp:/nBݻCc]>q.'i]U}rrƸKOg/xtWP[?3qȓ0Ĥpu9X֓Fq~֓ Ԣ)ִl@ܰ!/Qʍofڐ-{bz92{`ס!6( 4 @sA Z!x=R,gN5gbPM*@q`M,!|Kz.|qfrџn FՋOMҏQlޱ1T y/>r$MTMMo[i\6d]D[,d@?䎏_.iiJ7n&Vaۇ|8>o}W'~?%o6G|5=E߰gFCgRuQduq^X8ݨwo>Re:Ln4<" O;*!<9xa4T.'̐ڥkaSӍlϙӋE R9gG"ek;3TYtb Lw9RxĎ뗫 yjEƣZfJDD: cQ݈1A݅46A(MPJ⨎:%eJlB"d#m97Cn7/VR`Xઊ8E~_kL$Y0Jc KN4^i8+>ELaևrA)oxy6K q4&3%'']ݖP ;I|~0xɺRC-h58dmi۾˧Y䐽YJG"xfn%)3L#ރD윋mof 3`C1L&ǛY(8x76eBPoMES#Fr9rˆĨ(uڶ*1*Cg]Hܝ).]ǣI%r>)S7}x[Zny Bʋ~{>zϯo TYdXRfN7/g4RǽR8^+]cR8Ucx,](ZRc3gN uCpO N%GN}<^v FWs2qmC|yIBۣX'L'E۟SbY9mͻeˎgu; {8]%HB uȢcx짟p{lcxݥPːcNBܭO>^ _~uU3Х Cػգio^EsۍHbnU=~/"X1uSSd49ݘApprAOJZe`MA`l {R1'ʾ2Tw,)IK4$zK,NQ) FA|=C#4j=Ntxig2Ñ ޅoPj ၽc-32)<88F6N #Ơ ܓ3FVhO߹8|6#Rut SMY^.\(^Fdw{C6zmN,~۞CAť%w94Nf00,C݊|hzU欫NA;£5~Ǥ).VvZDE5mbJs@ws10qiR𴉝}pp->2'.uea)WC ֻΡ6g) p"otBiBnу $? &qj֋뭰7% }[ZTRQ IDAT/3$P_WeW2UE |wcߥ~"s٪d!Gs\#όVoY֩B-;U^򒱔>*VRUT)SJh/ tsU6BʂJBRvKfYWMdy6 e[-2طΈznXCBp,f\§Og/+[i,1@4JԲXMAb(%XutRk_EZsr)4[heͤ 3!JR.ZN>Uv0#erݖr.j<ɍ!zRU|PFH^3)'ʭk~{ɟ_ ~tOiw X}զ1Н֪pB}/\?^E#ule跽E׳S͋SRD 5?neŻk}(O1HovCDgƨfzL_;Gh胴 v?fqb$%/˜+`)D.o1En'󏜗D:e'x|RMC ZãLĐ ު6R֘wGJ kFꑴиmR D`:0V&3(0'aVxΕ[1GӉ3UnۮE㑳ô@ۚ`tߌ\) zwY 3ŭ-XLd gHBZ췝3,ڨ^(&i<,c= s:[C}ZqhHX{[@ucb1VMHPÕv%M*OPk<l3"36Hox-M,ݺą.Ќ<<#3 v#N~ru>cp``H1Qۣs+B :Opc@qT9~˴H.'xk΍e`5!,Sd?_DNiݟ.%]6f[uzز-(VEgw!>KcX$/~DR<"b͙Z<=kZv (w9ۥJ*DUWlhCcθ@b7^R$ #݉<0ۆjkm\/7rӕC 7!짜?5AZDG*NZL EmS!++#;L qx/š1Pט8b$UhhD"yM(Eَ}^lZw΀i$e{髐L^ *֘ 51'Q\9!-MjrdHZc4]ֈ 9AMs^y"4~Ad`J m/ԢgRLNMgzj0p"0  "Μ>kTVeњ|/Af1T>pxR 64MOhTs2pL߿ԎFy{RZs0Hy9Z֦ZϜp͹2zi 2.wW=5h@8Ƅ%KTh ɫ 1% nA"~Ap<*ĎͰu%,j:Z{!EҺi *soFv >R!Kk>m,1t'?_{>TJFEB9/Ӫ")Vǯ_=-!^N<xه<Ѻ̷\˺N_ Ē\ƈ)uW?D+Q6K(aĜ ! ^,x l[췝۶Ip``¶z6Z5&/6eG(+sp׺XVz8g)4[- s^pe':]i I;_XBgWH~rjYs$#wt8 wP(4Ǩ3cc&{/wϑOyyTz뜖H2Ru.ɽ,-P[e0Rw^2'g̥`Wf֜RA2Qqj/O^~ZotXO*s0,kMN,YiiT$b]ÒPG[}zIa 8.u^1UXe{g?Kܤwj iؒp Ws%:J}8b$OӂѱV{Q_a[2 )1pJ'n{'~-`USGd8li :s8-8}up;P yb0#J),tb0*o^(ͣ'3p!V$`eDbBl͆)\: Эh]1{VXvWu͈-ы22gc~=+A0 ELWT^)/N繓^iof"JMc>!J,l΍G ݻ2rtyO%a"$ p0{ܻ"OZk1 0 iEYdv'|#v]5@_w'ƕ??築N{~߼y?kR4^zgHN^CY />_OXb|}/ρ_%/ׅϿś _=ܸl;a. 9*Qn7FO '?W_kU8r^<ы/{ڸޔj~!Rd\}!-Fޯ,,i"XTFbe[h~^ iy>U*lS\Qc^avRph>QDsݧ[Աs:y9}{ɋJJ9gHyQa`T *b;V5r+o*εI0M6==O=ܬkeCA)>̇/N|ᄒPO}6I9n{!>fcM;KENlC/_$P>XԨS}RB t{3>t֛2Ve?_/߿g/ G'twb*j>1 'vkpnڪȄKAIf!C/7sw+ە`tcU[dSAR\[E,9*K`&B".x^h;CbXWuR`V SEsv3[9g cʾWqh"򴰑Lp2`2jmA"x4&K$.f,w(FYc1ZdN,J{ŢԚ锈tAޭcs Hhph@mB;Myc !pҶ_ su4|! ᪾\yJCE?]HAC$G1oWBZ{12>临 /p0[%f{^S.A(,%R)򌺤RJN')4/=qXRdOO|}b~Of5'oo(m8LkWRL|p%u[ >DE-U|YQ’wG_W!`4Gy]0hM:wk$ =!jMcl[Y#;1޽Ku[?xတ+&1űQv胘M-KFЙ;5^NARd򎘌O?~M;_WO8l3tA^SN+k7՛`&A_-U{9N0V뺪*73ʊYs"YbFJBٟ?n  q{l[w/8z_#Ap~Gwer <^ Uhs @X *IZ=fcr1.D8i5ݑϻsfF|UO{Œ9zVyu\W!s1jzT.$["W_'_5o/ >f DFFF G-!=z4lDR2YHcPE/HQasua9鰈Di^ r",Uh 6c͛pLAJ|pZx/Rz+{gyq}}C5ѴLy2$ē=h8:S=b֗<t\íG_Νd9$ χ rhp3s9OVj/lH|ǺtҚ_@ .eiI*9 =^G4>jJZb=RF+!֤3jbT1h)Ȝ'~bG8obJ"/E,T: 'F߯gvn0**|LO /f;'L!!/g2%,JJme:c4XҕFxG e#$A50z"1K jŨbn0ia9L0֪LUf8$WqQ慀L5'D+Jv︢CZ"q]({3ّ7c)hb IDATԢ19Өȼ8Š8; &sYҚz&伐R"xPUe\l!/E߶EgѤ Ρi}d"ċxyJ|3?7zݨ[j]-(`7ʫD4}㗙;߽ek%pYukӶv[ |LoÀ8XNftcfZG`,*v ënٱ!۾GϯC+vttyoK&A{h(MÑL(EXRmÖrn2BN:;->ZFcqZu.+(I)&r$Hk [J!H^RĘTtfxTFkν*E ^uqCȤiTEC #p5sZ²,iޙđϑ/NDNW-,ޡ>~hRv>wW>[ծ%'<톞m^$_ s_]L# bӰ*u KWW7>zuBn͎V|ܳ,xiM9B〩zo+᫫iM%L4!Th5 **$ @o/>lH) ͞RvS7`K{BcmУ[8eDaBU (X'&R$ 4NKVpNģA ɹi!E?Ar@IJd`=w qL!NI1Rܞ{-5$.) 5Nā;2q2RRAe디t!}Ex31D eujDv릏lx7HdLrn V+ Iqݹ'y`nHQu٥CRrޥ n$̈(U4٩Fuw*~IFXW܆@`0}ZSȴ+^:xǛ #E5/;k5&?|sSI:uR6I+2ќȞ+:>c~)^ Ʀ/Vxo)GYʴA/aYEmC-3XGJ}G9Uͭ.a ƑU}XS<\x{KbY4nJ ^/Bt^vU0F{4BশfF.c$9z(&0(33@+1*C)*&]tMܶPn;s\N75N1?w)DK-XP:9'ypUNKJzo}+ܝ3^f8*O+[={7e&U|nlMB gW7 YkQcO Q ]E7 r['T a˵Ё}<]:KԽͻ+?S2Ji7u-zk |px介ɄN/G2}p惻ĺ.\gU#ŅV+{,50}"OLCG[` ys Wy$v5Y^H u5U 8Ao'k3S0zBl"[2q&Keוw{=oNUde2JVS5o;!44ՠ&Q&" `w~ikJ,?<ܯZRODIUsLe-B)ybX>:vFE]JS_|`9/&).}gSEEC+zoQIΡ͑)4&\I|]dJA2tU^;=ZwfrBw(L]tʾDKVj*(R Xgߺ7T )KPJDJ\si#ݻޚ;@|l ȣn;W-W@B7%_̍)jJ)#@FRE'D畆98Dyb pm*Cfƨ\Wm]>@ءֺ8nDLs3%43}os\Z(uXb}znxN K!~R*?ٛ,co4NK)i6%XH9Rr"ƨB~x6C 7*!ch'(vmH&41CE0~ m6AD.ڒA o߳]eGP;結Jmĩ}Ʒ?n<*¾~6'w׊7EU%6;\ɷE,^A߫s`8Cx ʒH?n.՘uGv@O7yp_"6 ) xׅ>?= 924NTXfrHR!ם~Y.o)=+̃O=TDKj e91QU'l)5{*.$\E]c9ky]^ogKЩUؾX6*)IܩR3rgl ~|DX#Ug(1Ld<'Oo؀:Ln|*7"8`z^&%՟y<󭉼RrgVB= 7H`-ZoЇS MDRVj`%0d0fuwC@Vn$wo3&>;x 7AuЪPDJ_3PqGAѳmxshfo[Α56d< 'X!GRLYRl_7dRJ^z!ER}ԗpUFӸ8«7'+0mapݰJ13 ad z﴾ob6'^MۀmmyA?)HH0h>lgZ,6d[?/ެ*n,EZ;c3>HXYK|<I, "-ƻ ̴ޫOE'>" n]_KZ$uicYm$r l͸;%&(EO kWX /ՌSg'@Ӎ^Kޮp{|.bZ0hָ=:%}Z ɚF'υsm ""-+ravMDѴ/V>d|+d_bqL^MF`@e{`8nyAdaPdG50xN!U&BPD甖LΙތ6I[\2T0񠦘4zqF+qS@cޤP&ONf0m"J<+E˸`6ugw}u!hÝ :љ? FU]٭IRt"杓$}TW7 g_oJHZ]aҚ;$V&k-F\<)mMʚT Ol_d(guU!h P݉ I2 ) shU|_9,?=`ی}p%!Z%dc4 snO4cq} &{Z7IQ'ʂ<T^y2!Qh#}z_/7nM)Dޮ25SS+KcSn[w*' _]9-K4sz%[֎m~>C'DYO;˅(OzݰwZ ˉ|YfT7 &2TcHƼA cV3;x+>gf(tFA%FzbX?Fl`ϮyDM*x$4_Vo!͈%k"q8g78kG#<7AxR~VJ,3s9ti=~T8-|IO9%.UTa@Fy1.yxGkuXhxzxz8T0\)Z5f@ʰ&^Қ!$GHnBs\{22 v*|=/p})g`L;09<֝mF#˭ y$\1QzHQs*V0Kݗą:)!89i檝@o?eT]r 3 r,:`^ވPbLEZ`sыsZIR1jQnh7c4b7ѿ#v[_(* iDa-MQTKNNTfGrOZEb ."YΑu͔(q|;Iu(JUPk\)cFB\:߯ܝ"o;|م*A̰^LJm6x;߽{^?5]}i3EWg_2vP]/,rnU:k/ɤ輽K֍:\e&J$j C#51F%.Ɂk_Qx،LJ Wŏ,H^N||~;'J,)rmo?O}`_~K:_0uZKmÓ 3Rft=o#q卣Q$k;_6 ;~*xk9^0pp0# ̢qrJw{9+ȣCW?ЗgWnmg`]?(f"iKL#a)qTYԯq{Y2)h"qф=H-BbYWb{80ҰX41?̅}~\(G(GHގX^8 /Ų>W3Y88pD!'bwt'!N;sszZ,RD]yYYc:!9TwtRycu"J1i٠%*CZS=xk\dWmL  Α$>'1Ȭ@oX(Nc1Fc]=䀏L˻k]DͨlTBɶ@k5-}Ha6R:jRA W"q:7?B4R,IBgh Bд`? zCMZ|zC/c35sӲ e±{Ɔ#])37lĮgYi|}*c=r"ڛXP92wG?A6p^N%kS"+iQNm#U{c+ XTJZŲd m<>t7>m}ٙӚ]!ƪf=>];7!_RJOçRq6uB;az|<:M6%W'~zG;,9yu.|x)0 vyjӣ~v@mУ6;g^k:HקLJuck͐,N%z]_>8o7|ŵ="d9ׯ+כ~+?b.M&U0Uij FJJ:Qi~+ZV\9OdX1 cck@sW|Dd0 4%p,-ufJ< I:)l8L7Y@h6K P/Zd'8ܜ0]]T#S]:z29riߓA/q Rus'/7;-:ϰ1;rd'w6Ҏ"7p ‹?kۜΒ m>9*:L?tT1Ǹ@s8>$,gh1;/hyCOa IDATQܸd72Fe-iX^63m߹m; o 4|F%IF CmC$U*8| '!$T &}D?Y=d8i)MAg:,HV~62X`>j!i ˼;Nttf7&hM:p Fx}1yJEv@$UhAnakk 6[7B,rZI!FG['&o4%kFw B&dMj@X¨Rlr,s>|<)iS*әrZ8犮QÛ8X/jLẼ7y;Fg\?>5` Q|*56EcUmI)GJ vŞ*s~Ir1 b*כ5s3^/>8-Rpޗ,IrI,Po\+9h 1#*qQ:r &c n4Q?1dב$}1iۺU.nF)D!Y. +.F<$0ɹ:FGA^&1\/ncƁ@3dPqg1`f׫#sw`ns/!Ab6*FឯȠ'Ii#>:Bcq ;YM^1\=83,Ȫ!Y(qf&2zMйS6Uy=sҾ(+ gQ< hFB-T콉<hrv? XQ?hmn]ͻdslZ%%T#BZDJ8̰{8k$J91Ƃx/9 w)u7p teL;(E؂#~Utd5T)1Lp9VdY/>WөE^G1ɗj t>L3ښeE*ao)B{h=j0%jض06GwPN7i`0jfҊ/Ch.n"9 8W&ʱPU(w[/0_(1,פtLt j-6>zc\>.M*/Wş/^^9eIjnןw?y5yUrмɘMWDiS&'x [j0>Dy2N%ȟ­OvkW9ȲI6?G9d޾= OKt.|zVys 9ۘK<"%%X DxmK)鵱?@X2!d,.Uƾ]δG]7;;o Dg6ҁH{’5N;uSD<./b?wϼg׬P| a۽E/*0_4f!9Ù;Oخ?> ] fGM< v<Ϝ(ٹɎ?{c>[DV7T:^ܞMī[ynJcPv=֏_I89hB#4]yP:I|^{s3${ԘV!G^>/#/?'pwc=Iz<+(sUcLzѺ.Uc;ճvr &9ӓ.s er@댶;\hNB~4Uf+jby][ !Q15BlcFM/O8vghB`p4К'!LJO\ <¤H93>.wq3\o84G#"'jskfG=2~hb /Ͱ!/'dCj(~X4ܪ!iKue;"@AvCEk YfU ZVRV8sB{k]7Ș_nWtk©$zDrnЙB4IR!Rf\ˉTd;ցP3KN>aV E{Ctw&,U.jr2}:(wO))޶Sɪ:>q?w?/~vi ڵGv]2{?Zi#rEӇV@+xغ/V R :'6Ēi#u:/%>87O'^_?sGƒo tx`كwdZy.ʎ7kI6^Ʒ%/<^sXԧ;P5j!pK. 7WVtn}L5; 1ˏ6yÅ 1h"dQiъ/&J YY< /p}k5 9VH^O |DRas gC 7X  A`vcW)||AY0^KvNlj`y3tWZ{^4)ιF=^aX"AY#i]ó u 0j%;zlukӣdLeՈ(X\<Y`)Bvk?Qp Ѵųs.TȠ2!ljbp*;.{u 1EEX݈ XB ².`Jfٷ+RZ&<ԡw-rukfzϟQNĹ~)gOz#eoSQkv[O˒h> }H7ZtW9 jN*{ݶmDvmu_jSH.4b2J˱u0͂bE2B3M]W~Zs &Xj)T)r^(2/<&9[e\>/k Ai[ow~v5q9'.s}gXo>ѻtn۶০ S{'&8/˒#糱,)~H)B{SΛ7_xE;c(5ӋT&**4.6(dSP^ݭBwZD^x5%띔o}̹DƘL *@Y3?'j} EkT [D'aUڰu憢qvLwL\#Tnݗ ȜHyw1 ~계)9-̻< 6DoZ4}bhy]xMh9 WFZRH a3~aG{] RN,;OcC1漝0GOs܆Hd,B BԨǦyܲp51^{}HZVxLk5IG7 $i zJ޶O"3,Qt^2{!?n")Gܮ70(g\XK?I!SzJ(]֚Z(%RR<]CHGĂ+1ei1Z:zW-4ڲٮm+*SRZ1 E{ 'v31Cj]T/^%x'ۏZo+eIT<>gޞ wƷlYR}S:xu.|zdZbo|x޾ZX5)o7EuMS&7<7Ź5C Ē]+N볯OҨKʇOs@;>˙Z1F{o3c}m!2QZ-R] Fp2<fGp=<3ӞAEi8-8!i\' !! Uv$33e4GP8Q);τO8ijEsGĕDOe'eZuT5fHQw|0VbϰLUeD, <61qnGnە\r@Xs3aufZM֩aaКLΒ1$oG#F\o7Zf.Ӊ.M=+(E{A,ϗ,jkXˉ^s n8#,N1=Y7x&h>sSh5VjehDi20zu#‹{J3yAp^ ^[Be+9}I7ʪ5ȺjYd4ھӣ$*"9= i{6߻̗*LDBAlЧ$> 3"uAbdQ䗒Yו`>VwZ+B8AV&Z4"/nÉRVfs?(ԅ.Fpc|:*ˊJZ{g>Ɋ*O>j_" (&ztޅ&-iLv')@HU)ڲB<8!o&=T0S.s,kgc9`h{FZ8#t&L3\=G'N0) O7Ӎ_c {&JԫQwplU`kO;~_XTu%s=M>xte^82:7x5`Aɝe0K8lI|~]D>]+[WB€g~~U㲂@m "4  F^]&'oº~x3t>~zb=Vuaܘ3mȉutR裸?'oK+~$EUG@tt= LA 0yh+DK$L %.?^!.KyWyM#H[“J81TtqJuUӪFn3K^(iOb-c91i}WX'YJ\J펞jRTw^tJ"KRۡQf@XM=i "/(;;Ȋ -) u1.C#bdd 83*3ۮ h7&)PЙ0E/7f}IfY_ܕl[5u"䍕rb=eفdXĶ+Al׫| /FnmЫ9%Q~CX1:6wDBΌѹ]oz(>H=Kg*ÀgYIgY3iu"n^T9Eq]Iwqc*3B}gAhRŤ_Lz?cTe!=J8*R@TH[HcZf$B%gdL<^9?!`Q=dCxTՈ7Ô|)ЬӆmL1zÊS:S(PJ* F-UueY/u6GSY.+DRLA`n&ՔҀɥ=@lϾ ZJm'ڛ/:(rN*OEe뒸5#Q}57w;>=>n SQ.z tVe?"G0Tx}wrLw ֍s<Ӷ?[o?#hi EAoo?_wFr #F4\yRŨU8R D_]K9HhK * > Za'$3zD\1Ȍ9;(xxN%׼ zN> ɢCAqq?IAZV F—zW?e/ GWL*R͑[7Rd:OG.z?ͫ$[53Hڑ';W섔uh[}1ڠ#N^.q3(cG5L|=LcJLCtRmuĬ3Zhb!s NR#ghV#%1ʷW,BILnGmc] cvi\L^H%c":9G!z, !gSpFD0 wۂ5} uV!8b>JHwow/4.NN?x/݆8t&;s-cY~EILN64}#(KtwrhLQGԽ2DFugI4 >֝QۜQ&?z :|H:kƾbS߉F*jryr#@>n~ no\tI1zxƼjlB }UV=C DYºgGtr~'/(y !zyMrDP.Ϧ9~^L(! {ZL>G؇ bֹ?,~W+>J!?V{ڠ)1ڸV}"[Jd>?S|;򞯾8S|v>xsMt(F0Aچxt9DX3,K兏vҸmEGbjv_8ߞ$yzeɉiOTn뵲 tŅ}mWߪtz$-4w T%W'Z׿u ?JvrR0&A㣂1c/ϣ"0-!a'ZtA?<((%$jp#8/&xs)r0ݯc8Pj7Ogl" W =>xn&|9f~cP_'x"{kNwR"hrN1J`&~wJq vØ};VjSeK)(6eBOa s⅄|f2(*[LL̉z}bX褙 '+ A_C"ւ&)vl׸f]XbݪGD%o"HMVa靜 @%=7g]"Xu1cEIp21_u~|?71du]Z;u4JRYuGlN}n37dȳ^I*BAi CS ܫj?>R0G:G|4J%cnU)Fr&O u($0O:!o.\۶kPH6<}R~6e=N[`ZtZxQخ]WZ{p !9l`` IDATW̺.y oMalS!DM}ۍ ܒwi]3GSDH%F^Jsrc\+9 5 WzqZImȵ)޽h@g|oǩmgFqJ%'员"K\VY||\ wYgm|=)EnS5ȅHI!q_"$uttﱲGxuo|]Z+=gW)~lkͫK|: ?~⛯_,n{u{uu9 ^_jx ޿#3)bYIK֘Dq&Yo^͛;G/Wip<%<( WA:[ 7|dR=}QpyP5Gv&sDxh6)\8|Ag&,㷨#щJņzI]I8| E]"7( V~Aw0!RƗJ&EϼVډc"/ Vdkt{]7rШͺS&PbZSb6,IXf;:KҨ*D;PQvJwD: zW p,Po;iWZs~Ĕt=;Q*8sE:iJ)\[cR 4,uP>we)*Q߆U.SS4ϳ?39 &^(W3闺й?=wSйNEElrAFi1p LY,39\\^0R2) "'J)i%r|bHDw/2rb=YN ihtN:Ib~IE|s4č/9m rnPJ۴x,k=x;Gy~AZM!MHֹ`:Fb05'ϫ`nFY q.є`aV̂#|*lGz"8ݢ, ˅7Rz_AБ$sJA|`0x;yd*aK "y=Y#Le03ˆ #"=έv֕Nvj_/ެ:1nh5º ~Ji߇O?{$̧qnoNާruS#~ xe dZ2U^OVxU~pz3B]#?;Χ T`wOےiFCЍo};e>{'o{~kzTINY9p>xA++?}Sw8_3Jc;+kI11m(Oe]񰈄9y>~q"#A&", l(nC0U> ϔ:7񣘽AnVYy_5QtĜ}{sxړJ$LOu^?f6Cj31F JJ,KAޱe~G{JjFNc”ҡZOU@'wdBة- Xr@"t}Y,PV#\3)`wwm hx._Ie>b7дc郔 H\2Ð^8P*!\& &aTDv9‹e!'Nk&cMt9AMy!fgմmC YVS'HRiz1J{LYMQԢ\"musϖ"uCKp{ޞܾvE?r",dNfaD=EG^M:ܷMaAƜ{ %s^Y |4+1xEzk,IK먄8'Rv}h&WQMIV{#&8 )si~'T6\l c!{gn>eF@ t$^ A~r!fӍ\uɍ>Z zotU† 7iU>t/vv e!׍vb)e,}RѝpѼ\?Yo,[i}ntƻ>+  &0JDxFL R%fPѤfv2Pյ.ϵcm5kW4sX&ݝek](CeU-9&7V>U|EF8s:}YG6،JNʘՆ'q:s?MO&)7|ю_~qC?&&g:{j&N͙ۛ+ },^p{0cxz9p8& pu1P?~`,=8tLKGW{n.n6<}rӛ+./vg_'xsy9"4uhRsmy~aEWɉbP/=ʻW'nv.=W<4Uņ|9mX܎y0tų~l9͛6 K/d|W/oQg_wT;fkՉ₅29n <+H=ˌqG#@&J4s;RV{ĠUmJ{c?jR|l3ـTW vp#O,WnF tOF5oX.&6:ڲ?n&r"rF6cHr. 5A?#lSŀxv!+TӴX1 15]*^VXe=Qf h "޼`m]gK1m`kAõV } Ibٶl@lٽ}uuב>wZU 4zsBdV? F%) }I&(4dٵ~`!#x رL4#ө, 5pc)wXq^o$F"'Zi岉0l7>FˣZ v)G(߫-_O .V.HS;c86hj-L{ zst j"-D3Ll^;L EOުw=Bgz@ B6}ojK-ReL8ԬFgNdh2"eNhg2/ 'P>~AZV7fB)#-uɁ ''/R[*e#w}F{Ng'^H6t Dcy6!xLֳwGQ$":c0trge:I>SX>AbTk|(Us֬%ȰJ)AUP1 Ю2)j@9K|áT;/m95*m]ɉ F 6~ 4ZDn]VnMM9EczA }R|sys$e\9΅׏3{~xtDU>٧2_qR~߽ɋ >~:rwݫ||}Gv.ґń~76]EOVe34_?( 9'1}niݑyXTkhc/Ч-,Q/xU%g?7:c1:G;v\Хqa4vfîuC`ͷ5 2a}?1SO/H_=o9f g~w<<a^۷߃VRvR3Ѧbkn?yDZE(ԴZjB}AhKVZk3 `3|dʬ z"Rg\#qrֲZU4`>bv4$@!P5ZZп#A5+A!-WfDD3Sx34{uzi-#*g)#:Ia1+A&0%iC=w Stbfv\[VUDz@5D`܎g:yq V)+#xYN.&8nFcge!TlQΙfKU8hYVÎI$t}OW í̲n4r`/zW߁e^8T]ȹ+< =Sd +_β֪bC[ճ$nO]dA`2O$Uz1='rG?dEHMŬrXURsou5Rl_º:\lVtěp}S1d\(5UWP2ǙԳC9'rLbʝ8oDfXêVkHg(.f0OGAqU%0rgZc][ڳ$עX)Fp\䙖Qqf˚=]f7RZ^H 7(gZJݫ8>dqXoMa VT,󰳝tfUƬl;׼?o]C+Wf$m,]~e~wo=lL2]Εf䳏 QLfӖ1snmgo׈S,bBd\Z }F ~yO-/~v`1XM ~v߾=Icar_|~/>M^Q+3f<ϑh-?ǻiv%OW||W |Z\7|<2k3ۋ|Pj-,{{+>p%bT>{q/9+oeyܻQ-η,®Ff:w2j&H:z(I| R `E^~ ֗ . |$RE ъh3h"wH[>dݢRP״t|ϸk@Y󮂇YnS\+o&N>\MA.iD\֧>$~훁#[LeִȪ)@`[`r1 t>6?c-}M|L,RwI[k6CjY0tFDT%qy,}յw: f I OjਕHKYi>M =ԁfd."))9AfF9Iq$ͩ5tɲ~MgkX+[49W8h_AE۾KI%q٤E @dݍVě`F6+:,nFT~v Ϋ<lazj]ftKB^^T%*0vg-ld:DڱL3 .ʚ%Mkma=ڂJpVxv~'(t95{i.0&N)  eމ6 ~f_fLP(cRn/:6񂯿~{6}g⪞J)#y(y |BY?YB+ ÁϞoV,Z]Դ9M-a'W*v؝]_n ɢ=2.:n6d>6k/~oav|z2cHm˯&xW?~ ߽z7/+\Y0+{ttwO+W9,'r}I8\t{\۠b_JPcJAgfP ?5_y`_NO.iO׍q$;8ZqMuD]"iGYIŘn-:􋜄ɸT#()_~$3Qۤt~D['M#c=6<p13P_,-R(+eIq# aOn6/6G׼x~ŗ˿)ZhCoÿkE# Ų9u^") 8~WVPqFE^AImzO{t/t LFrљ*ZVB*h5ʕIֽ'>2ƈεf2d{ s.=`}73D*E,xMki^T#;ݺlVbÓ7Ҫl74':\Z .x{]9u"K5"cxsɲOw9ݎTNN:"u+4sвMVx;kA`ũR 6~I` IDAT.jTX .$b~x&r|CjFUX& d'R*9 RE ];ݾRldҸ0 YI*`-Yt܎tf%X|?߷{ȆvU,X6@m=Z@9^S+!N1_luvL?_߱׭睶+$r^ wBߏzӛ˪WKa:ˢp?YYy[wn6Řrx*~ IVnH#W.w|W{ \nz.6͔mz^yqΝHvT8]jak޼?pw,=N'g/DI(T{6_)ko}n?QVmMhrDPEH%Mը>DPxwo.sM.wG-S>Tzi1ҺbulLC>Gzz587aZۯ!Xaj,E?&1WղI"URyBk@N6uA3){Z`Y$SW2:hIJ"QNe4ndV Ts%gjem;%*gv7 ?gYӵֵ#8vha࿲\}S.n7%>ycv0;vqf`2WXVPcQ'v\\O]fфH^ 6Pi1JUNK4W:Sg:.!Yn6CϨD]tVP q,O ߽z~lW6L$Y޲Φ:)VYиeMg)j?208U_쏬6}rR#OlL']Ϯ/*VHc]6ê<::&\Zpe4`|, WҤzv?Xf@ڸE%i)f$k+/%d Cb@m  QھZ}g(.ӏ2-y3Cΰ,,>shoO29gI^q$Ӊ4;6<mV!Ņ)H}k9+wȺ{~0n-j5I3ҥyeY5q-ՂD\mCrQ`g^-dGQLu.HCæe-<֧lqm}Y¬ &٫@UpkTH4d}&J ߢ)?:W+`LdsdVЙmϟnϗ8-d$6zN w\a8gޝLW{>姟zc_bgVMߪLiZfN=o/nw:牻<닞a4O9O Ǚ_zd_` F2,2+L6ٽ8v  RNG^к_zų _Hj)3ŗŀQ*>t}OJpv\-"Ac:~ (FReY*2:$#ԑϣJ}fVfx->iq_u9Y)C $ )[WsT&(D'Lj4JHm.\윟Y{( ձ]Y̊8;^g曾/?kG\V`Ϫ96D"6b lO_\w;̖VtUvpn7p,ƥ`T`+w=ۋ_9}gqNԚ-˿}I:O?e7&7 tӴpx{}oޟtÉo^>d`ūh",wcbttȥE`:M-nI-r]GR9}6|mFyT:5Bm7Mh`9QXH%`iK{mTJ KR9,Sa 0?0.{{@|+(ʰ١y@V_1= : {&@T ZdvYͮ,LPӮ|HwMh]Z5Reղ:Cq;o}؍Z܂$E? wD@mC-&3&QdmC &~y4 Hd{)9jlVLZ.^""M&UH9vsgxT|$"HױRL2g@N:r70P#ud_JU&sQŜA|p4XF!P>\7;ܮz=u;'g]aʻvl$J:qVfYY@+id1ninh`0$fsSp4 cuS+H%u 4ekmk lc=l/ꙭ{yaGQcEi<ed-'> jp$MKЊaRe+x5aH{6wDcI|?pӏn:?x~{_x{*W_=͆O6<{gxܟ(}x _8VXH9fz˜ILYB!CmU5^L*f0g_JxwG:squӔmN~O|«#$aNN}1֎~:UϯyaXrrxPT Lk:d~̶TjD^B9lcǛ{Dr2Q4 YywhygY~ymtiP]X\>"ٸ6,hMW0 ZT7t\W_ӀB; T_eO~K%{M~u6TTˋ>1ȹ͈Y&vFpFԫ1[96R=ZmޚW_NiY t<)bx ikH" 8jߠP3Aiꆻj;w3:3$Q4sV@U"aZ6ų֖!Νsg6WݳB`zD&xmPwV7Ay$ awSo<)縡&>'p n5~; Dʉnzji_ / {S1"vƹWq3@%}AdՂarbwSc48vbeϫW_ ZuCr~F!ĊMz!8bhl%1|kgM ~Of=fk[)tuSW2޹./-rTeimvay|톥urf2R YU,;/p Inw<c'|{gŬHTe^zI-e.w\zypHBrO2/ wAg}˿[Ϟ_O͛=_9/`f?Uw{|MXCaY+,dH٦8vGoBjVm!Y<%–]wPv9qJ6O?e>GtہON.GO.vJ:#Áݓ[F9RHtC9.ɖ2X` uߜxn)L3[޿0l><0wڌ[[C;[ebkdmǝG%q)`1'&A@v![:o8g:4hQѳK'_qF5Cg$^Vߟ!39mϟ䆟w'qf|6D*\nmբ5VyH8ʖEt ;0"}O%CfX 1QT=_|x7>y 0"B]Ιo]Z7N JsĂEeʙAh\#9פJ j!QV@:=Y N+H6!si&0LrߣATjTlpL* ՑV^[Xp`|a!G҉kG̒r*ENt>dFU[S \qښ&V΋?{qj4ƐJ'9u []Ĝ}b\h. -/NT$&Va*,jVr=+~g[ z8[?e^;6Oyx8.ܝ Ky>q:ƞI;Owd7t 3aTig;_mx5)~ʰ)sg±=]K[xy5B8 .g3XwfY̓ۧO3aϸk$w #>s^:q0\>x)@idfr8<߽bG72)D8f=myx v^.ef|"[ꮫ R܈ظ֮a%>cш2JGtH Y::xcAze[WY9CE!Ρjeh /K57X|,sj3n9ΕӴgm3tRZLT50v.*a7{sTfۓ,~,HXZ$p aRD8Z,{g]DiT3N0e%QeQ Ffk|v*^vI}vb朝o< =5RXZP)A|YEM+$T8ZZ+:PikFe>u;wơ%]&1gٟ[Flw@3]yERц΃Bbhz}xH# Srs4A&GFIx}㣜LAqI{&5ǏDK8z0Yɿ ؋n7oU llg8pLA c9\gH!rOF0vt~{"?ek?V*|q$ZU%$7.=w?^ѕa]3b|.Ý%<ç dig/Nfd9\V5yV쟖9s<BG[ IDATb=+R!X;Vrz=ܠeri||KD 7PΎyk4 x4+~Rg#F܏ϫpgDMװJQΏxVNQk&π1L:F_%ߵ9R.vR)'+EjZ|&Q mD{%d[mׯF覧O6[Ȉd+^g]9f^nĻ~b*~*jbIcm`z'ñ2e.fj9&TEb]'r ]o; 9q5f5qz~?Ԝ;˜fi ŹO(ye! BT3Ls̅~ :qNgtc:sOI=If?n+A̶|* ƮmE+(/fS]h@y1.yԓeS* x ZD=`Z0<躧K8lA(2MԘ^L:o5n%4MҌrKK:סŕ9]?Ǹ$- knyc:MUFIϒ;YYNNuϺq^~f[ ֶ0aFƣr;BI9hX?Ϟ$ !tH\AemZm~FB8Ouݑ =.2sΚ$WV[J+`MeA(Xw YO'iWxvϴS&f:v]WY!H9NY8TvNÚi#],l_IT9 P gj,W &qSҺslU Gw=AĦ ,s%?'q7r%3mG>{=PG*V:bp[gdyz6Ɇlɺm'?|Jevx}?ZGsddՂJa29m \lb:*ZMq ?{ t$]Fj]D蹽»7eN'\k<{ C;V1*WZHǻRp2`~$up)bݻ-2 }4oG 7`zw0o;:ydLJ{!;A:.2ݿԙpԅ~ܰdPu6 <}?~rfԥa󬂛ۨFvf|;\u32gurV睵֓ՙ>K5+7dTꟻbۮ'fՅӜȒF!,wHʦ)):Bp$ULjCŢ(sf?\(U7+pJ+7*x8D /a}"vC( !iDoo3]@5.GM!tފ;6} #x8fCZJ{m460qH+﫝|;4}}J[o= IhVXvEiT(0HRUͳXlk{]ΕA(JJ[3M!M2}Jt MGsjx<砮{@z8K27 8ţlm*z2O)=V~]WJZ,}2>Q &'Aҩ,SjrzgOF~O^79prQZh)>#Ϫ.L3nZ*KqGΨ3q=yx+_~ua:(\ 7[^?,saq\SSXܖ#JF)g@ߝbO޿"閜M4S4)\;ƭ+rJ,B7 O1 E񸇲PwEFgs%7۞y*t,l"~$%-Ǒ"=_~oS{~n_v~uU8zTifJw٬O-YS7FQokWUEJKXՐ 6z#9LQe騵rL(4j-Ne}2),VjrM dkwSۚ5:3ϕ޹1hkݝ6UX6pҒԶԾc؊xC(* ($D<7vVe0܎lڲC=XiDƞ8ǚ2h`fccc}+M ->)J XȢeC~a9UˇJPnٶ6|e=x8˕ڬe6Ü6o5v x-ܮ9IšA F)cvpP RC/lQEy?]m0A[&׳TRY-@DY羽xUQPϲz.ﺮ-,),t]쭻FVo qH/C+s. r8->}C~㉫As氘 d&7+ޅRTJ%'aȐ{fdL]N]-]ʼO͞oWKVExsdǢРlrJPB )Y :f$^P|+7:%_"UigIMʐ sARYb䙽3J\A✦Se&pRLRsEeIC$UOZy%TWs|5*R^b{eS*2}׹DL kDR>Z)|~*DB9%,t(Y2&, 2qFVb7*LJW` ֒ZеYjg.f㮒TVUU;LG+x8-HT#D>R)8F%%\S@MhgY#LE͖MگFn9.U8ZX%(yr^qqmqϽΤTDU#1%|pNKh1o{&Ec3Pc9K y!̑-s1M@1&ʔUbDh|ML%(ϐwB4JZ?#X7lN[~#~@iji.8=ұZ-˸fLR=0yNAX,;@x hl~ף }t$^ubVahcM =LG~ٲ)_-'?|/|aʕyYN@c0嘲3!۠t ̽P*sH3-APTv/vQ? G)y2o4,S“+Ӌ52| /nَ4D~i/UEx)y] լZ3H{z)~9}rM??D31$TLEQSʊ=AM4sCJt%a F G..΢T_S-iY*ϔlAesjTGEg $C뤆M9X0'hTz^BTƤ{84H)@=O tA#ooGáPFtڎ)GGCecӄPrHJ^)i&ֻu+&f1RJ8 f A|ŕ)%x̷k8 j_ik93GnX#9(J3H KY ^q$eTeiMT3s3ߤzJ TR9JG˘#A^BYފDN#vHf@NFܥ(GLuĺLq bOe_󲏻KeNJYQ417=KA↪KNqVozC'g<:_Ep<N]su4JٸF1M#^ IA}ǑnȘ4 ᯊG׋'w#V]Pݡr?T(~d|SR-iB "(G.m ׬S*=NGL"hkFn~dGkY,F:mKTA<[i%[ŪmƜrnCP)a{g!j5\5ˢ]}ȩFHfd}O#'<`/?|rn!*vi/Fhw ڼ )K/}mIm琔xY3gL'z1{ %fVN k!~Qg\0J@ib4݁g%f"VaL>0@bK>|v4auxY'O/{&5?jd@qA*īI57UQ7DɆƓ[\UAMo+g4=y^YᖨUMyd&g/˲ y_v3T ک|_REVDFlL=R&JBy"ϨJv(gNeNʺ!% k+NeiV#*gRB^W-I)pVxXM7)وH4dRI*!2"MxzanO:z0Yw|w>QVaN|_Cҗ* hLֳ&Ͳ0eTy޼aE!V,iؠri7;dNbb2GRȆRϨ%`3Q옧%9Sp( -#C"O$%ܷ"gJ#&7)rUJ#Ri YvZɵɀBC,["*},~Z鈎K}+:(ɑ&kj`|?:VyD^&p8Dqhcd ±Ԏo_xFk syɒ4%bW*:Èa?xi[â)ۍY+NZZTY45uZ,?yL. _Fba1jZxaAk+L ΝǬעCc{vw DF%h)aS6 V (ʑ$JO{sOPnYgl$JaKbovl~9rs+ۡ$+cSx3ՊO;>y=Ruͫ;!jA:QI;n@{L*F_MեOU)*'+0=*O[*]"Z5g \-pV|bE7)*JC`ـV+ IsAZqeъrV'ifyIG,"qVѵk_=_߼侗 DEA^tٿy-JdP^?yU&=[棅s+G((s+!1sͳ)F9bЫ!MLN;Ï:xޏ$"4 A5FͩD"3m^dp39WD:PA)WH nPsDQ ceر71?>ҐתrT gqX67{E63 )Re'"`A(ytu[|&V0iD"f":ފ`.V>=ա${3wȾjj8Y`>"29*>^Z"a N5o]r%54J)%SI!l -$_x]65E'ixdSGP1w4xZ*c9F]C D"`,֮ JӼsxisf ht҅9Iqk3LcOӶ gBL(Y8N#ubjw4!$Kc5 t 18yF+%=_~|υmhβ{0Hy80޹<8k>q /#Gpst]VraU1UoQESw2 e хkR 3S>i O4VZ6%JqO煢Tf>R9 >xTS|JsTR:RgC"S0'1 Z J"UVS̻옖Vy|;AgQP ^ 2 #)(toJM7/qij\x}FVa|)%%8S42RqY):s !Eėfל$`Y5M?ppdZdb0'8]5~djd _6\Z~([fN VN#|-y"2[GUQ'Ʋ˵Y~lE?@V&X-ZE0F"E\=咮]rwG x=hcjEid'+dݶ$RX#l&b|{u\i]K#|d:ANK'cDš_7|5?;@4l6*|fa/Da.~9G/PB>Tdr3.q1 mR]Tp\%:,l#קugIq׈71P4pi1GI2|@ٶeX%Z>sR00xtӠ$A7Rf#2rGA[Nfa8aNpKlNy_ԑrLJj(F"WzQ(?(i[ATl**gI=/[2X3%n7r4ߒ@i͢ 5 COV㬑EZcuIdY1LlSi hrl'rp}IH6G53tkr4{|jW#vr16*#HO f}6dݬ `˷R΂:%)F hJ˪M^3gesʳ!/.77j-_89%8S ٢Tx]T[ g5 # Lx8:ͤ1ƒ"٪ W ᳕Tw%{_d4e99z1q'B,Zz|:|a eGU${QVrg[8]j_9[K)c4Bu0HᘜA80mXn͎F>G#J?Jf;`N4" {{g2#A AFUƴ-cLXx|CaΡE+L_77ٲn7| hIar)G]-O8⮟x{1xF4~ +qu4]:Nϯ!%%Vmq¨{(O V+5lo_PazR!& XdO4+ZQ2Q%{H~Ghg1ΠcOoa7[տglNNqMC6ƉjVmi0r7L۲}{Vg]K봄cOO ~V3JHJ2uj/v?:ق)|%fR>"V+6dݲY2:&RMtvZf6?MC@!ӳcZ5%֑aL(9 1”0ƕIYĀHд={~;ZC޺4[?2> (9rNr/Fv"GZJ4⬳ @CyMZ|Fo]:Is9E̊VX~8k좕>5I92f:2V3HhL:2LsU< dekH"O=q2vHLΏH]ю{爜BϦȭ| )*BkUsp2>DIϦj$u${%tOyw;Y$\ *3(j9䂆V4 I k$S6X!JW5yhև*߿Ⱦ:J , {$ϔD^S-=|%gud3s8f.T*𕽔uYU.:_UU4V\W\rq,e DLZ-{ꥄ RArX>&H1u-èz_1$Xvi8eÇW }~x A"(uYCq՝bX`lCDVAYVsO! ǐ>n jdjŧRBrc0YW#Q[cr1隻Ge2 t]KBẖHfZJ%Dӵ6 drYBuWieYbeGq 8lh\C׭xߡE[Q5W:󡐛cYmPZ@2iMfZoMòkGxڰ> <{7_dm=W@AFnD חkN< 7T<]]UNGl$x4 2#kҤљQeNl HɅ1_dQ28FRcu Zg҄PQ[Zдta)qJD<]2^GK C%&1t)6yNk~wƲuU-{/}b׳WHHB* *BqArUU9g'oyj5c0e#8*p|Ok"&1#)aG$2M}df}a'r!zpjb؜MTRLLa\SoA]N7$|buze,;V(H=FޓS6kn#41[8 g#|;nxwxz҆qg| 1qzzn#3Kb:5 g|w=MiM7+(5DrGUER)HYPcL҃9ͺkpڈ ՑHb(ޒs?Ȑ&qv9~cLD:J~חkV>KII<PHvSaH|-57=7ӇX#')&gGЎ> W^:GJkT9__<أ9%.ϕ@E+<ϑ2GR\v[% L*[=iUO!f^E&!ʹT$AW hllP)6,2Ru"bRv-{^NS 5m^#$mrwf.Sx/B/ I\&ХC`sH6Mg7~ s*o^QS9dɠKEgw壬ìFny V"L2&(LLC'%di BeT9ډҦ(Iͥf_#cr &!XX ?߂/ySSl*/Mɘf#b"Ai+HIL~Mbow\p a4|)C=]ѳS KZ ֱ^ݾa Dp#JuZ+<,DM O[vϾX\MAsϿ_rNsy՚i8pv}`mC?C9䐞A"|N v )V=C<  DQ2 2Gt2Ր:YK%DgْR7ӥŇ"S"i؜,I:1%c,-kR!֢ l_ߡ:˩!CS -y%ԛ"^Pf$yJqP˹q&"#S(1puLXox3M#Hi"?Kn8==|愮i 6YGY&Tc厗=_~c;rc,QTOOtf)Ԙ:nCAi+Gӈ!HHijqJ5i\bj,F)9YIH1:f%)|*MК4ΓgCƘ<D\ !U`4?~rBHWV<,ۗIY+H mSb /&idLz xKK%Gy|5W D625SNs%IM"Jl\THkYOb\d)P)RJ-UVI6o8=edq@UV.Xm>Rtg~r||s#h;+ِy\1.xrvzTG'(ƜF],q%02/Ÿ+$[6ъA*J]p%N0JejuS"yZ`E6OysE׆H,[{B,΃*Z3JQRdf%$| e0}3u\gU֬q%U1]2Zq2-.Q (+:$ev&gK3}i$Nh38@ ;mqz" Tђ1$Y8NZ܍>K\K|g7hQzxvxΊǾq1#]W|}b&)Q4 >y~ο<0'fD&Z˨=c F%[ۉo^<>2DHzE4T%Ţ?_ёh">&&Ģ5tˎ]D 'R׶)@ZB(K4GG!yY%Bcm{Q~i!خc^X$\G [Ha7K {bͮde&'?eq8HQ;K =!)z#n3N2pDDF_w+OIX)0N'Rv9!R-(=ig0 ܀%ݷ''FfyU3f4J933Z:ydM\)Iuy0R.F[j|<ҒCyBRurxmx " ` `9UGUP ̥ƃ[[ ~QLyq^J?$Z?Įt # =HM #$Rq(y/J\BQR;X Vk]ubg-?VVHk4F:ft\vrԇr*bM堘AGg 8͟=5mcwe 蚆U$R [3%2[x(i{O@ [SePeVȁ̬C"1HP8YRágMp86$G2XgLLѮ?=Z{#ϔӧQjF(jB^:r+a5GnU;Fj5u>9:Zi`SVnюAW)|ea.k?d=rpD$ ju ͲˍN ?S~ן޳ ?z ~{BLDG$my^jYɦAxDH-J&KN جg 1ɊxRX%i,Z.\LPY ϺZ[>zg"k$d|^IE!HVRMf *cXnZK%"2;Rthh)S4V:\ uM!T.Jg g+nCfJ* P'&E 9U2e];yt:OUG^*`Ditvĥ/+8GʼұŊR^JG !Ā֔{y'ΰs d덕ˠ(+(YOMT @sc|bI3 HcAX =]sjXv>?cx $Q(+LͲh>4N+6lSq"  .Qe U,3˯IZ_l\,/l$'!{Btq6_T{5:ޘ2QAcReL2(]uvRcy/L#%xy4`볖vݎ7{~xȋW Qg0diZ{ϟGO+6b %Kw{NOWG5ȷVuǪuQQ]oZ%jtbcyzAceq{?aǫ7wz}yw7 }~U7߿_aղMH&Ok~ Wk |#w4)r'l0yEz}s%/)pj)$ )}\F(&ZKx,D=c9bq i5i:GZJoI#BL"::c,G%"*zG[KX-w{pMCZ>8kdKՒ>dx;|\Z>~Ekľ|-_ĿŊ _}1GbHŵM%\3q1wHL L%pn8,F;NI>4*OfH׀ IDATD\ 1aJNSO,iÇOVxe7|mb&]j) zm 8R٣[-JϪjtJ#Wf?W"VNOv|p Tyney#LR!d$ޚfnȭ4գ%6gʷtH]p2g$`@gr-Q,)B/ૼ*6X|Və^3X"Wm:]C4jx#w +T^G# 89l Se[fSޣ]&<,H)2W*8h,˸.0HUpjDrBϛQC!Y֭#+!!Q3hŤ"e r}2SmEsTkNGPsDOb)*H9^#|\G$ N҂ًwcdIu]XRΫp~决õcFۜU_WҔ;~uNvW*}o=If~ކK|)%"k[7߾xJZt~cZ7 Ŗ!SP8#8mq# ivX QL'DH,59ю憻nw^9R2KKYGtY,+І5.!1m؅#񎘢c嵑4Iɥr e a'a""Sq؍IipvuE\bƁ~q":M.{dE=~7{&y#߼z74pvZRn6&.Z^?D \]1|?}B{zpzڲ\u| 7Os`p0uΠ(maqB'O&Vˆ9'>jxdɳ>`ohR L@R|7Wx\^Ᾱ0 h-id'');)'?~ÞsKHYr9u{޲Z8b`HTf%~xワ3(UQ,xr37w;^'ͪ$%)(cu&=GrH^ᯍqcIimM$Ud=oGR6!b&jY*/(EU3i&)W<*꼞.V!Tbbbٲyʽ8I)ڗFz Hʷj|6LZͯTJ@(>(yW Ť R"1AF^QiY2M*oH;ZEtf1&uǽ1,>x#QNNp=10߿dZb5'W<v7b[+Ư/6lV-۞i )ҏ#!X7;H%eC7?d`|-C|=mG1:o_Oc#s/ٍejś=DO(q?D=ْ݁_%Wе1X$bm {~*}\:];<`w8?;eXg$`jVYL-Ҕ@;p9%'~cZx:IVa:`}jvsrYЭN15Ƶ "Dc V-k~K^n $B 7mUQG|KLK rW-u[aȀ!@ 8![IYbL&w7Sjn̵wKq>{c9г߬y֛a.krEDΎ ]nzI+:gA(1F~DPI2 Nu='?"3\,sN R4vEQȜ2pDRCv4L+ΗrO>dqQ2IHL.FDc@^Z^jm8-ZBQ܁bӏ`cl5dGmO[3F(`ނN+5aS0{8ܟj5tkp4NO_J3]áDs#YE;D' G˹a9+hͶMYƠODQLC\J#z<OW˃HOz63&iHN- is7dHOkMgσ9)  Z?}')!PZKNDEr!D6-/߭ ,yt6sCUhbx{ࢀݾw/cV[~ۯq.py~ Db2( $W1,* ެh:ѲOXֆvӓ4ofKUG9Eƫf=w-дw_}wjGkSժ?bYdQspb%U!IL*&AO'՛k6k'i!zyn9]ʢ8Yn65כ;qYw݁1YBjΙ1'3i0)նtp6iyNY.zP}`H$]fduմQk:+2A+})~ Za<̐S ۸.8F#tBL^1JKp,O)4)H_GsJqղ*nC䧗KٳIN**u!Fz÷\a*慩8= +ZC@Y `b.%edY)FES$dz$Lt0 fZصAbҵ-tbS M-ca-de~81% q\>03?Id4:tNO=ܴT/Tr QFQ5slV3;BShÏN?ut9a۾c߉c@e_++qy~&:Gry6(eݲ.7{6{Ѣ٣ G˙m8;Ň=8F+M5=ŒEM ȴ(X&Q>W/WRm;\FˤC$en']"A;5r6'X`w M=Z[#ˣ#y65>Fяb.-\ďPy*j11mTLQ9ج$y]ac3ikEo;Lx;D_s=~w(iz~/?b PVmdAzY8jtgk1VQ9EsYM^hvI6&xptH]hg'KNTE<> Q+20,:cY/2. _R2S_UXDiC) $l%?CZ)䅴"84J[1(NQELvZM-Q'MOe1Vc:# cu**n6-0=h`JRYC(쇁c>l{^^Yx+@^Ӧs`WFTNuLpd?X+qAƨI]W9BpPԢ&JYxrYbs7=`%]*>!DE/34u ˤ]ϮuTe&sҹc9:XCaM}5a7v4xzO7xc$ JMvϢ4|gynsKUe9GۉIt8^Vݮہ__S嚾Xt{ʲ`-''*i4CM (RW97]O]<9СxǜeFYX6=]2w!DRfWܬ:5'G5EQA󜺐d{}%/-׷{yȥ,1FdEiX.,jah5sg>9(R_@;OnH O)<)N.mD 7EŜM+-r-Ȃ Hqf!ZEfݷh )eYq[9nb@ݲ۬;: }K>rHhR[d AA Ɏ XmP"C۱(r ͞n(-mR4&*'B d&R٬FiMzH"Ff ddQ]fԕe^gU<||Qh^ȆbiC)( m`,j2IDp}P:Zɺa$y9M:ȍؐTJFhY.mTz$E#0mnqp*\p}Z H@z?P'abP&@>/PIbDE?!c:Gbs`0)CJn䪴@6|5rSh L)iTbH'D"Ǜ)/F`W~LR4&a)+*E^h\s;Ewv?[YJ)6 (6]6OGQJ|ШhHa鑵K7e\?@9òrӿHIHƈ:e,Ow^:RXk1T;M4HEI9!s\Vggsa@.MX' 04:e \ZnL)ne 8Ě>X e`5%]~wGr|z$6.r󋚏3ҵ=ЋU9mͫkr9;+18;]Ǜ-՞7vΰ6H:޾_qnYk֫oݣ0uŽ@YU'nU]Yw,%O.3W(fW߰mH78: !B5ww m8B@^FY][|j9;-ح\KL}4YάsrR}/1L:%hd4S H6 rdIi]+ %Ej--ZX  ̤ZbzhD~Kl{b0lw[Nkӎ8"/JŖsxeD >B(f%Hr̸1(.2@ag?P:ͫ7<9q~qJUO,Ym{~{a$ArB R7d&)yfyo!v51*Aw`X%XΏJ~t),OL꽈Anp@.r2k7=:LD kD3%e$n乢(eTB(`l:˒~$Ѓ65EnpIftdbOU}zf? Sx89HQ#'%pRVMuUz ^3DQo#@k󐱒-SAՔ+Ȅ  mV3#:]7:u "9T7P:BY&viDrFNi:CwȺȿW"}ČMP6y(2ĐO":tJAnR1YhjYlZS(JK5Q1,i\LĸEPXPG=~VF$f*}*#?#HO@9w!Fs̘ ~E#DqaFR_/Md:`e]3,@Щ!b]XE:F%wG=zrTIR4^imҔe5HkN kXt`LBD'ԏ[Mڃ2 Ӂ?qu1XCOOg<=ss x+"uidܖa IDATv슈:-hcyTSf9]l~qͷ=Er.|zOKcł8,uV_ \/{6'9?[Pd9dŠ:?j~~x ym"7U, (hG86t'4\T4;Lum?`s4MF׿EyAil1_0-q JK;HǤK+JRV(bNYNQځ#tN4\ٌFa<ݾziz0.]Sd-I#A8EA-ϐeRVʂ㣒0Sׁ87&"t訓 Bf>xdWXEK/^'Ѵ} .!p-эRSfW䚢XcS⤦"@,3y؏(IK!CHN. eM()kE.T;NTzbF0D2YJ9HyR4q F,h!YJbN:FKi; y] 8"N{1R!@{` 'B1=Q 8>ds2O{Jt!JS"*W)xk ,#^J&&1xbIjrKt<|Q ܁1POͦ0ȚJtV2B74C/FqqA<6 1:8W%ON Bf8 4FqCCtRոuL+:%+#6N S~sQ&ӓ]JN05( w=nsZ:mqٳ ],ɕs Σy #->apދϙr:ΣB==MŬ`9/p>Y b9+["3.yC)EjR}rN-Z6hQb8( oVXkC.i b0g?DLȥnQӴALJF㲤gT. T|pK h .`AQыh85tju23).Q䕴[c)났d3E ̊X;xVũzl>tC47QN?xv:q;'G3<9$9%3L(S&o1" 5複JA6 ҁgI^8SgXQ1x !ki)N:/5X*, ũ>29XBrJOІ91 jRdԒ)y Njg}70eVf|GR5l(X'pRynÛg|35ei4r+\LZ#]mH)kZBJONMYH N4F$NN G]*٫0o~(򸯽+ o&zOl$R!01(JV8*(ˌ{Ʊm<7G-|O?:YBs0,+Mfܻ0oE)OP<*ҐtHc$S8>Úhjn}ҳAtD9~@T*Mcc2MV9Ȋ \{?ӑ0\.rض,<>WJN}QKK݈i&Awđ T'SJ0pDzI햞;&x3/'M?pׂS.D2=/߭|!BmEn5oo-:tY"EV 5= 9<77w=/o]ﹻ7"Ո"+眝|5gKʲizfQ-7};w[;#tT(&3t 9?.yv*-g'5Ϟ3Wl |*3ӫS>z~JtM eQ<~l%Dke YŹ@]W,s_#ܼͮg%!F/.8 t6t-!!D6ӘwIgW8)9Ԍ=$SqCP "l6 !?G⇞n;44wc trI:1ZJtG&1iJFj'Ύkr3'_M]XSJ+G#UCXגĄM#SIg|&.x9cbcM䑡<@Yw?N,R7FQgLn*i ! NmOůA 8vc0IFX1a )yQXq7֢2 ZphkѩkjpÀrc0lO/bj5.f.Jiţ'ueȌfY#y#.#nFi|^q=QMS'U8IDl0GQ&T ?A{ >X!aB)3τAL" დ)(cUj1ԥib&6F0eIU Gt/e6˄1%Mb댒E{p6)=!@l>qo=%Q5'nJB/t zä0c0b"µf Ew(G|7A@mshuk׊.xȂYƣ3BWq(yz1<|xƢRap!J5<:FźgԁIaZ3jjrv4@8ƀ`ȅ33u9+ ȫS9v&+~=XY!FN\RY6bJ)>L9YI]@x|$.i1 N-$yҰ8{/BrȸkBd= *љjw3Svn:u-˚ke85Ktp$FaJڈe=jT㣒64COYSnp X5D?B$+153Vj:,.{wݰޑYjz֚9/OXV9/^nfg%\In-2#/ iJ}` |Wg|O͹ShC^H ׋"Ϧ(EU#D|bɴt n;/_5˿b?sXՆe={bJk{s*cAP z?vxMA|̫PR28 Q:t@EFwێK ԅmZUM<}{q+%5odqi1WTRH>UNmy[>yfw Qcs>m\ffKDpN'Լ#0]MVD$<꼤,O]|;w Q١٢`(5k%edNC֋ a/l.ک\̪٢( <]?@@@Q*"1EƓOpfǾ`KU.p^s41_ی0bY*#:O ,Oèu RhQRhIQgEQeV_~~K#pD 8:csy}8 :̦C=҈bIzYǑQ:a,өd?Jou Xs~ȢY*1)|3*yPb['~Γm,Akxԡ3TEDYV!FO E%{9/Nhhgڲ+GG6<GϏ%=M;-]7pvzf)Zw>FZyZJ3OקTU_ }@V9>˳Ve/A)\D>e,@ euY1Ŭd]wg/2inJÃ,ȬdPJf <pV Cqaxf9o t5?dqQ#b;GMjK^`,OJ甹hfo:z'Vo?mz| <:^};ƉYLGDDHIxDUYGg|&7_츽oJۀ 32$, 7dbT;χ#/ϸ7='%힗;W^||ݍ0)K&_/c]@+KĉT 4OB> ?鏯 Ek%zȣMMZ}9;rW|7<.*k_ ͯKf0qW߼'ҸR% YYgAWΈ`6 S\/BAI=H;W+泒((! ](ALHUjvm L;΢*j|t#+,Hoq}O=/mFvw'sI*"x.ëׄي(߿ݞmӦt"o?XoZp=Q\\rt|LtCU Dͪ* 93e:g5γK-=+š㒳JdꆮI &5X@I6l^/z<|ɂ9G'5<˰P9yvyQZ|ܭ6آƖsq!Pɋ e3@ynZYhdXxHV+xQۓJ>l*?[J48d}rʦoh4&u`槃6Le= #ǰXp0wczGJi(N\RʌXH升YRJ(J>YJ%ں8 332mcPAX~ $VƲ]1T[A50n(/b ǵ=3ٌ"(eƂvӅJe%`4(cw"9/ɲH]fnɌ>?c*È2ٌu#7&rvd`tmާq9i݊[ynJ)͢<;/yrVҼmxa϶q8?0i|&6+љ(rM!II~kW5͈TD2mE =eYdz:/ Le Kb!Nq|NHF˕pNy2SWWAq4rrfZ'vwbGt&WFCZr[9 L=Eulqbc<T6p-i2&F$4aQgl{^k9=5ݾg97 } @~9A@sK\5q2ϣ㚡~?0JC01`rgVEb.HL,2>M3zbFԚm2fU yyvnh@mŶbkhjOYY:F:p', K" Zs(GmZe֔eNk mĐ4#j1|2KR3t]8OY+KBT|vvS!ϐcS|U1lR),V"|`;*xP#IC*3RcD 1Ā:c'(^L*I_nJ,@;(H3ePҴRhc$hED gc$"pLe+xzVsyz77zAe"![sKF)i|HQo ]"nYsq^ltTE9ٛ%gO}0鯜K%yaٳ9=]P@`^;>l:DgRc1N%QT`z}d$G Y @0aW &{<ѳKuZvɜRUiM wk4&2"cFfȞl*P vijӋrOqO#1Ӿd(d=ƔCv1Uq’-iKq@4dJQW`HZ/1e16<9wi899˒GK6ۆ%.Ndo^ԅaQv͵iMtvk̲(M#Afג6.ȴnK ͮk{./yl3N5uSWjG7R|fl;\n IDAT]R[XzOUd*5m<ٲ 8OUgpbitz2wh_]^ZWdyN{O+߽b?.flytRqu<''Wtw,kX+Lu*64r٨æ!W8APx 4 CV4M=m)4:ij,>x0%Zm4-Gsm:7(aK 9s"7x%Neحp}6; S⍊"4ikԝ9`ҩJ.o YxAG>x(koh>л-C|)j\ Y.klChY?GKo|ݽt:Dh{}"prT2s^]ٓ%B֑ӹJ2q/>L #W^K/VrhZG?yzZ[f9E kK(s+ɀdiǮcY<{tʫ7/_}`^Ǐbp5XU 8%3nQllv.RS #آʘ0$ˠQR2 ᬶ\.r1l;f`:)M9Q o4dVa頁G3>~4o_/^T7sȖ"g?zt2nY;FFt?Ӛ>g||^s^ٜ%_~MsuyA߿-!U*m- A601#k`%YMߺh-\S1C+1`tNK b$6r)S59o/90NAv)i]7WV6(It<?í9YA"2r/Q`q#S:錮pdKޛT"ĔG=>0$/*t4zJ只5_qbO~ǽgQ߇-]NYdfi'Q;+slm3тen7#׷5,̛a`>yF'1ZH0G'3ίܬ>2Bmъco&F!h~EդY QLe"s]+uXyͪ4IӅ!%}=*ϏUji-֬w G".4ՎI)ryfZ^YUq.qJUi^%ʰe3uxj[c駀Ur(|`X^<]h٠2vg;_؎Pn|ե):ʰh+felыjo;vtDPgD{Yf<>h1"1eJ:hR4 5hZm؍h+CّB+KMf+|,a npǟ?x9=?F?HGOcR|&EU's捦if/߬qO~~j3`-=;VplpFt,k5|-Su;(R}/8dO_ÆW,g?Ipdv?pU%i'OX,Mӗb9k+ytѵE(QHd`A[ucWPlZ{ R <&=4 l}׃Ҭ[fD6ГL̕nq ƝO( D c-i o bkI c?rqbbJtL:IF("k!A$Hk4?xˣoOWڲ"nf7ҏк"Nų9?x;.V=ދI>޼ R̜ a`?U91xSYBgav+EVjtFob@A契aΑHB<r*Tiږ 443TV6Udg!G *$U&h]Hѳ躎aVc SZͧ~ \޲V /~ 30i3?jYجGGs.ήy~|ǟ`s,f' D FtZI\$`%phyu>p+v? _Vd,̰?q,kU1fBA.fCz8r0I3v 7 xF|x{2o,)$T--/vlܦG3i8٫ylR^[^\ ~!F/(Z 1$jk؟W<9l*sOdNX#Q74)xƑsjf-*g+nnXu.臞0竤#]%~4Sm-M/j:?G[EׯS ̘MK_拚\I+ 4N[tSV~ G<3>Gnw, ]TT@&yŶpqqt֒HM4UV~!3N㚖zM#|hZ1@[0b=$D!3ٲAkH"g~8 1V)JSLYL4BNCA)Vir 8eƭCҹ Z5Yڕa(1Im8.<F&袧`Vg*'Um*Ag6]j#+dxٌRt8zfᜃ9]Ƕ"1z6m'Q!1IH9%ΒJubaH*50\Ȓ\3ߥ;b&~|}ǯz;|uЋŶld)cz.2$ʔ ){.l3pz/uh @J!"{%l1K22$RR#j ^%Xr^dlsS ɩʶ1P6`29<cz r)fyu!''jN1^/9h[4&H}f0ڠMr8pquק+vC$|}˓qXcpFc5<>^~lwo/TƇ4Mh,yR>ޣÚMEXb4\NY _% P (*@#T5Opauf 5)+<0&?۠''{rڦD}LT6VaS)ܩ*+W|0 (q9305jINi^xvؠ˦e Bߛ;Z.hVkYjnWkz?lÔ ixψr&q)2t?WW_Ce@dA\_^l8ڛRv__xŜټ-Eŏ_2oޯϟd_|3n9=Y#9DIF,'OOI!|b6]MRնs$¥H3s, Mf3x)Hh(Tl)ƇTx mG-!tEc OJ2L95O!%riu]7F抔0N X9ٲ<\bs ucd<|j &B"\tS"y娚=M3iRZYv}̴p&'0%r1`4T* m 5YTr̙)FpQZ ŠLLN19+}+*[Y6-V $n{Kp5@hږXڶb69kc ϟjvݦU5Ϗ[v[imzFΊٰ]Mjjk*>T}HA*Mv&ӴT2t0ḒYnQJ<(m1aa"@pr0z8MD=8*15>0J^^SZcEӓC U}0CkgJL==fs/k^|tnf;&ArvzNNǏ||o6l:njxÂsR!GYB[1K>},FED h^s4<7]f  VWKR a=gT,IU柀Iem,|5VK90'b$* (X7U\:eO?端O龹 f `64a)t=g9_Mlj9kSĩ=$KGx6#aL!q˷ ?gTe&ף=K.IifVL|x![@? TQCU38iz -qCe5W{ 1kEug4m/jinF~$a FM yȡ €5νZhu\an"Ā#;jшSD;T)]"Wz$3II*J0'%P*= ['X.I! PcN]s~q~QkO3[PYwgߛyU'ޞuL~ćEz&f1pv~I笮hOysvjqF>{U;Lc ~3KU/o_5Oɢ2C՗9Xo'G29'oޑkdΚ5*+a~i&0*n%dc!Hh#م^[LcPNZ[r KZi*[C'׶T>5u 2 ˬWnh+GXk99>DY+9GL]j:cnYX3۞D1ƩHs1PäM0hv(UbJHf#kJ<{v5|{K]V|#!ͨӬljx1zG4%F,) ݜryܘ1<5߷rY%xH~DAJR"Hi91b,V>ybH)hg34#0Na:)-4s|Bb8-/T oRđqΑ0sW6X[7,+>3\U3fي"Ϟ\8Բܔ-*a~wfGiE)bU3oٔ!b4$? ҢKJQ!*b.A)ɰlŬu7= ͹Җymka; A,"1?ZiI*Y9yZ ֢f{(߽jCGʠA'kC ׼>妏䨸xrp!D JT LvED EjM8LV?/T(d|9FA"?u4MVќ0jyuwKcaf99GMm->J9_G<89^T"Ѿ@Q“k,*͓G5PVžB%G3n:V Ϻ.2YE &Om,)GvSJY4تf2ǘS"J%nW=kǑƵ|$lUVCă5(k!1)7ÖL!E)7FT"ƔJa$Ychik")%*e*mP7lH &7fff 8ɻ ?L2dޓGS.xy]V,hIYQUӿQXYDpO&xMb77oxa=gvӑT|rd䋧8_g}u >EkpձND򑳛ϯR2q`Fy}oѶᣗ?o^Í]{ԗ|8 GHV0%ZA2FHR *WWFQf8XqL4i'-2y h婔Baɀm[r6+neӲxI"vǬK+f0^$= .?\f 9Vg#fGG ꖾ {n @ V͈Bdb'&R+|8 9f-JD_&ͪȅ͐U&f@.yrX喠u&T)V R𩊧E~6J9 R[E?&톃eͼ1 /WWt>KYE]2t#96?< IDAT5}?:RJc]+rH<Hʊ^|2UE[񒣃=v;P@V8H1b<VCTTVRc%ŢeooI?L6H A&nm/JJCPKI$ Xp:)lY*zϮ#Ni=%CG tݑx--~~D "/sqsK7|dOxwvxAHd?ځ0z!5V:/EtCbwwH6`fadzQ׼XV"QjmPJ`RabQJ]7 ~HꚪmJ03c?ȳPI ŔeCl2(ge%绋 13s݀-72hn:|cd<3mݰݍr3".+&}=\+<߽E1#Fk9+ɴ΢eWM7)Rו H>IKšXl k-ovl&3 smEpQ1wH6â2OlHP93WTTʹ\RhED^ߢ361!g4ǯ_҇@vXmHf8DSf$y| r1;9k-޽/7_q~71Fc&%!ti*R-!hd Ng#Kq l"ˍ ɠm+8@U5иH7N^@ֆ~`jk20]uېx̲blon lm1M3Em uΪv_d'|()>{'v9<N-ZE>h|00e:P 7Y r$fLHF L \L ,*d(' kK>hUF (/ʂ1 !i0l F҆cdcߑc jsz~)S#~~[yuͷo/41#mM<, Yu^O=ݚ߰8։ecitcħ}bNdR !ٌ58ѶxoV5~O#n`ż*p$}J)1#?MԵaor+֑DZK٣%]߰uQ^ J(E&hj9RLTd)vUXzŏ~~Ϝ_rg3N>'[77wVk98Ok>;ⰱ|nE?$|/j"}~G>pZtͯ9yO~ e+zR!N'y&CIyyb?*0z>K9-M7w|{O&K=R&(eNpB+2dl 80$ҘTh!BtH?ʀpX0I٫s#_''d`^)>ctEOL!x7dHVţ%)z}?Kۅ\jEg%0{mCqX[+Ґbnaokg׆}xx n=gAʴCiS -PHx43D_OV}*p?Kuە 0El%i9˜-XTDOgp#1O0{<)d:SZf56•R}/ļmבdB 5uʅI6\(6e0q2_˷[Sd.x@713TCȃǸ,mF%MTX+JAZIc9RXkqJ(SʨT.{brjMl" E5I>&&6!BwRcg47]r2NW‶-[~|_[Sg= e.8pĬhH.j )%B  8+QgįGT҆RvұYA,hBЂ Qrq- g!L(j 'KEFc\4gw,H8Wa]t@0b9ww f˖#wKISmeA02SPԭlYEZHIJYLQi6ct¨L@n^(j#Dv$.!ˇHy$Sq xEk1-b,5(aǎfGݐ| .X nd7yִmk6\w\nHSG33]fwدZ{3c9wBdoپYyp* Azv[7o1\ΙjjWѶ-MSIK} n8=_ͷxx g|9'foy\_x?W_Sǀ<~rQ1#sT<~t̟B!x>|8, "z;ruw;z7?+nvL! ()xbu҉wZcJ>AGATv3R.{ԁ3fuF8I#sjKҒ|H4r@ NJ1#bmkjk5/,hZw֜]*X;~gRO#\ hk8XX~GEQ˜LA6S;Mrʤ0=6ZQׁ͋o_\Vxn nH܍Tb qǑu?qvvHOpN1Fx6 ۞ff)$eDG u[ Y^ xyG* ly=1HS))ۆG'3s10N=ďYJޣL9 Cf0|uFNR;OTS ¹F}*[@,wk X2QV"^1!M3TV`̢mPF%nمȘP\c( ]PY` ? ,e!r-7۱lkJGxoƓ1_1j2|ƧY]+Hx)*3*0fBYV!&[Z|$(=eQF-G_|?!=o~tr8aFBc:nv'Plv/!*jDODD೦Ƚ$"!$kM[W rΧr/ b'uGVhmƹې6riF,c3[ F *Qw=9Pqdsyq4dRh\c+B,+X8ED:PP7c7R0ۍiv]O;β-t#mc"G"xM$ r B":\I:K~TCaÍV1hm QL)წ%ե ͗r+W ?OHݘҊP(,5)2')zV[䃛5gJ?S!O9G_NWlwQ६;iͺ\*>zq“gϰYIY#deehm7^Cf3OrEONh9v@$Dmj'u#(KLGT&!>D?F}XoOYwLc`w[S~QEϸapyݳ&׼x}0g=Mug⏥3`89Z\Tv3_Jn)%)H1L\_7ק)C==r9Slw#، m~S~ f5ތ|}2CTy[cv80 F1`)]b텾TT]d|f)A"7H1 )MP59Ej;U+Xx??jqή;R,/34mME B w->K_7$>bBXER Tu6Y-P߹W,.)?Ȼ*f@ԬೄJ|la0&9*᭩PF A6:E_4TRP[dW+Wa\?۟-caL#*!1N,,Rm51y'{sr\{R4yC<'hhFI(#V?NCOt ?R?DƋB Jn 'f"X%M!2LBxWhUue&^-(PZd!$ bk4(7Z+3B((@%:r{DLLSf }J:0سmW1,>=K4'RGO(6D"72-m=Wk^7v`bU Vgga->]?2N16UZk!' !aicP h#,*G7\lS9Hchrȏf3pza;LO׫ׯcrn1qrVM|zނ6$麞qP\d01 D\_)Z3>9A)NH ϟ[Fm'3G -{sX ' =^r? ]?r&IJeF;@i)KN>Q$0!`΢X{yv}hֲ9 Q HZ$Ępώӟ>e15]w\:bXίw,ۆYI(~)VgVj55JԽ !xyG9ЍA:n:)͚8Iߛ-o.¶Ħ[cbEaL!G145_~{N]9=F'lw#nctW[*yd-Wk/V(ϸ"g2_Fi #Dpߠ*$Kʙ4a^LShbVt]v\Ӎ8]m>J(˓%Ĭ@?b$}&IVC!g):dD0 /*Q9K(VKT#p X^ldm-VAp" TYp)+&򧵖ża7ΗN9T.8rmET/8pt>{³MW{Z+ ˬ_ ,Bb'_Gr @ݔ"wnnu#c?THuȮKo,/ZO<+CDaq h7l4v[^}wo\y)s7Fn@Ί'K15c?*tۑn$Q|n,.RRݥ}OtZ-t`tf&"[ E"{km 5YT9b @"adn F VT C%=vH0Neji"Cҭ7XBTU+S1o5[Uq)N[(¸ge㒬eZ7L{1GrmCH$Fv+Ib)$I`D*Ո6bpi9YmdǝF̆bh1eRfZ3Jcdye#ЯեE y$T`$}߼ 6YhKo\3Đa34jbTJâYe`l{1? c0M#Z}tǟYlf7?+.n،#]V\;g?dIvw}I$"R$%$iPIS=As4LVFIFUEH Fxxxwi,o7"܏7k}ϟ1ɬ'tUqyyFP N\-'LSvs[vO^!k *@kYXaW1 I~_<|7/C"O\8 傳(@eNYTZy6khyo^/eMcX6\lyucEB,c ^]1 !aFt8 }7pv2#ww2YG)%8HQ1D2)jd1rj$J\q7[}䶛pƕHr&JNRfBIGØ7͞|"^Slثe(1CUNVŚ36%4191%nڝW~7?+r/g|i]sESZ6쏢sz9o~+SU$I3o*z}"#M41I࣬`! t wLQ&Z'i,_膡`F4ǣghpbwA~g!&&sS7Iѣ,0J*\ %LK2$gcX ?$`D$YŽC+cmYw*EqzWc@Eh-c/kO8@swl*"rO1.aU( ̖v}7+Q-n6#gmĹtMG͎4H>0rr޼Ѻg@;IE>4mx8T=@%TYK%.4)GqR$91EŝX}p^ yԴ5TBGб:)cfJUV2z4VjU U僐zPؓ?.Q& ƈ(R#Te7"C>!oj~ԙ8 U޽bP%jI_.̬+Pg]Cdwp*jg@B]wn>~Sf%Hz@F\X@P Cy-O.=4|'(~/'$sY"(P,NNͻ5O''315);?yDe-Fiai&;*kif-nź{Q >rjX#njG?Q ?z~)>Yy[3kjjW c̓+5ee3Ͼ'cQJJ=L=5P34bNGh 6ܮ+~nG@{yUK[Y IDAT qZ(otaMmIMf׉2,ix~r1ë7%P I'}i2wa/8+&ٌ ݔI$L%:\\Y;V*b!iE7 lդT'"@P sx՚g:¯_O?bPZb\hBjeU~,܂=)3v0k6nfSo[fh5UܱM'/:ǛDVhm S=8 UeYgU#ie T]U1 \b> Id,.DS7psCa<>>G^ȰD"r>d '3GTN횿:dOmn$&’"qwEK>=+IM^> J,80E ^WDuyMҊ8q"HJt*'jHZhG +Jƶ5c֌S"fCH2I>|&!ΠE}fUV(r l#z `(t'XP'XjR\而2D #8tmAT 7Wъ(M49l1` XA?+h >y!3loh3"ݑ{fRz :HsqPbaFH`:S(*\WRi43cY6XvsS Oj4g:?*KS[j# iB$rD7/Ey)*ݕ5bwy)|Zl/xIWA>ZFTP@3F7F|lb!4gJkR# n;޿o9gNj*?~ĕ7k*֌sJB߿ŊˋK%OΙ-|ҢLş+j8e&1/őqd;;a3Y jn?pR3C")TY|>sf4QiBj+^}2tIg,&X|=E/k0C&apu?grI&!Gqv)xd9G-mGZ*ͬY1l6[7_=/Oh5E՝تu/IΠՉtv0y;ΙaJ|{8L|\qlшDȘEf ]ns!1tYkOo8!e?;%NQVwY\O_~tO>=g㧎D@Yq]yMi020y}\'Z%llL%_/x hO$n dZn=o>@c*fU˓an70,1ч)p>⏾\LE*Hayأuf-U-\A4F)B[K7mDϱ9Xqqf͎Uc !L )M͖n$he(&$-zX4LXnV}-˅D͵&$+wLYȺ^yPT\'g-1'}8ʄi6sJZXZ%om8tMyC [ y1Vq>keG~k&u?/=7CfL'~)J5Rln2Ev!Er/ޯ.fHwnYᧈBVØ=H6%)"S(0FYjm >v71Mq7rohUJ.Re>x1ĂR&'>,˽/hz$Z6FǐVI9Tat4ބ ٘Udk#T.RI85HP\@MI s9cmՆGԫC%8G|Pܭ7,g e֖qTvšа\] 鈎[&XB5 }$)r VTPF\!X!+z bPL}DH7Cʉ!!AD i5CJbVVɋP"{AdTTFƠPY4[Z˃/EiPP\#_$\QKdB]aF+ 2 RHy?%!$6(9=0$;}g.3[6-S//@N~ny?qVRdY#k V?zp :->'{OVdkYQY)qU;JD("e5ŊTdYV̖vۻY%E`c؏ivp_{>zJI*)$8YQ$jy~l#ʢtpdseMkֿȿ/ӧ,gլ֌x]TI4L~H>=8#iL!8kn(Uthqɠ4Z'LӋ9/?fϛu')a0"g-dqUVcUfF~xD]r/^ G5䜰&8QjrV }$%n)4ѪtfIWeRCir*@RԳGifO(irՆ>g|ݚӳk |jjӼyNjgOp"wݑ`pVSE]69gxe4u/*rNlzۉ9 )yOQIQ*5'3.Dn'tcrE"ȝp/ad6uaN +Tόdcf M1kFҘb'ae')\4 Ä6nsPso)r^ጢF'?/-zQUx)o:y{&f7~57#&|R[.k=Ylgs s>ℶV]o崩GcO ي!+kpDLYA_eՉ̅O(h*u2I6a+5q- U~2m mNAFd#U25ZAw9VhmBvd P9 04U $ЅGQ) W(x/fVKs'$s/ŁJ|B;E0Gɱk,R\ N<@Hԍd J.}``ћY)+ /ISfAKRJEkKeiV!HwTlLIb SSFK Q^-q ɧ‐]gqJG HI m#P/3`|fUJ!h*YOYrP˪4p}YuN  Ʊ9epsW/ܮy1>=NVpN5(˛#-Cn?QiwoA))j\m1(k"T$6Mh[ gC+bVW֝ј"uZ"M[q2Yg8+v S@[LcGT"M4YaxYG캞}wd6TMufp`6P87Yew;fǴZ4, {Ht]vW7w!)]C?rq~h[K?RdgH^"(y9TJ0 ;|x~[A-U+d>D".V%.N/\Ԏy%tbl6| htXx {a#~4ƈ@zV%LIlT΢U-] [MRƈGF>Z=*dVɆ Y׆Kw(ϛC,Aјe `ϨJT d"KEeBt !)[o!"$ݱ-z)Dv1ӳ$BTSɮXnxYI$"t83 QzD\}jrd%U$*pj܍tQ>kMqw[>'/X%upbmE#8tġ[B&%m0L>TSt(JazX9]*BVLn4B7߾~U1fw/?p%\Ø I$T΁ Yv(87|lɇ۞~OT A.T2nj]-ahTr3S՚dq֜,+2;5Q0mJ3Fl>UmS\0#J6mP|3@o 5%TKm&4B&91@#}7pzhf0L-g'g60 :]ZΖs95'ˆ͑wb "U1H"Gj.i 8duA%(hDCT;YUjRWN&ZYMtT.c}3$E'穛ʔ*sODSYjc7 D[7W{OBEa']_7 ޽!?[CĤ;C4*W3q@%|i!w $'t}|(XaT&@m- ̓LZ&R_HT-)/x`vIDt1Fa!K: 2A>TVlA߬% $I|@sy|*#!*-J3&'Te0SF -!NI, T0N$B9 af9_IHȜ-yKW}¦@e%c5j J\~lNIV)Z >~U[Ø=싵,L5UĊp¥r2V4DNAe$/G"t\+-Y Z!L$ZE];lUU+kg^D% J"B6T69OIzo#ZYeщ1U\~~p$)Fv?&RRIxXXnFQ+yqV h$+gR"U*"l6{| mcb=abݚ/oyS>obD*"՘ǻ)jqUcCfMU3. !dB>d '[xKJݕ3R; *8YU6[6!:Yж5MekK#痧pb}e:H|L&3zA){4Db(% e-0a}wI)"*."HHn7F`I$MX-STCbJ4mY58Q,(lTp]$vBX@b|MϾ8ݮRh5K;ϟÎo?n>_}?ӁƎ)enF%xrB_@>y~6[q%A|iǮCY*-:l@N2TZaʪ8xoZGcϘْ?C!JalX8~<[Y.n>˚D&1$1L4ReE8ҘJaT[fL$HLY-E3V)@rn$oedECe'0%t V:|}hT,7V/RؐK'jʈ>j]bikKee0nv=! [KTVjbTnjd-H q^d^Ie%!\iɿS(䅰lSJYz0$$H=tZ"RN'H3EhS_9"$EjW2AHWzS u}??ps4%q4K+Ec%c0~%W5?~۫o6k_ϙ/OXftg 3J(`(b V1p,BxHWT@ G8pX&0Pi^úS;B!tQXw=4YjT8vh[X`Jq8aM1+Bzym:/SnQ4ydBbzkTp}ø]J9VJJne*<Ȼ /vgv_nۛ})SVEt C"1BDb8IIYqD 0-VNbb`{bR$)Z) q ~B%#F!hgcY)z3g30e|Ղ\e%#BlWݏ!rENΖ|>o82C7Oi*3/Ámb^ C](56ϟ8"o #g'oq{8@ִe[P$9i : H6J]FuN/._UErhkHI12W` D㥁*& Cb e[s0#&H`+1i_&ީ<Њc?2lw/n*6?Sْhp͛ ]|_Aﺜ$Xe9URX98rQْS/% :üC*3$R˰!B~H][puu˷6|Nfxr 1rvJWGFRNTN12RgQOY+"N/^z.-mc9:b L8i%WF"ni([FP3ێaPiON&KAU IDAT2  *T9+*އʙVT֖=L~I!0XbNƿ&"r''5))l$p-<c"4۲6FR!B2w("*b1IX΂RYWMD(n1NiӓSVDmr凜 O"0 vXq{]Bm2Met)re$ .8e(lBYoznՌ*^ygL-8"޴CJ?hP"3fK*ՌO.XfݙgBHE!,$S{xV"TJmeX5'iAT?qi-$Q=%!EF x'.T¨I塸)q8 NMMN4E,/K|%>LYuk- VY1ɡ#~,2CG'N3K00})my6ҚH N >0=]Gܿ)gnww<{Oe{Vpt?c0zڦ'ggm,;L@o<k򱰀-%A3 Sxj@Y>G XL| #ƗYpnD#>rOJ\v||Y])1z7]`4~%6('ihK1e8'>}~¿g-l'6w{a'hDr8躑f)|y0],y~9q~m#5LEf!r`-}pw6sQWJEBbŝs$v}?Pt(8 e$;">EQtΰ=N|zÇ}Il-O=JCSiB#()ʨ}Z:+}Ȥ$nLݙ\ZıEq .()mKl \%%V}HY٠dԅQ:`9eU+BW!1YX7J'>~4O; 0bqF1p:cf>~rμ5sLC丆$|~qO^BANmjΖ-OW-3I/>=dUtf7k]⋏/l;d /hG^6~J44ka_DcK@ b4 Uq2Ub zI\.\CڍhWhYLIFnSR`9-~(|˝-I JJ\UqG%`O) #O T:)y:HJh_Tj8yqPYפMJ4FN> г1}!"~V#CTau$jQLIQbA9C7<΀Qc U LvL g9:w3@2FW뢿jVmm0D n 2 G)R7 FlH!c d19'nnsdww ȋ珉)p4bpчĶIGOYNVsVU]af90fQ8MS S$#W@2L^dDi+2qtƷێ; /tvr(Y)pcι=Lv_L:~cr8EϾK6]/op8mF8)G*_}邿wGtffA?!K3![~w%n8e*fn` $zd TPsi.pIq~z41FqabU)燛'/C]fg81)Jմ ՊC7Q  ~E6I%3!KQRrtE+a TsXRO>(u]~dXt: D eDU,TgѪ(-{Vz)ycLH@! Km k%Ho 2*ZA#vhx#+Y+=X+# OJbΒJ!ze!?[%K 9"fP֞e.TkAYʘz& 0Yh,}71Y`b WYAY12gmE֊Ձo~uUsP(ql)uD)M8k[)hJ2|fg ZrHS,a\SW[֪A$Hha )NTbTfU"t>OxDOE \J%/캎tͨ*ˬqxz{+eMK0!tK;g];hpe݃:3*2v`Ѷ<=k9vw6Ye9m<4/x_}nw-5mꟾ?ry O~ݖ~è ykxʓӆ~dWDƪ|@95f/M0xi53ԕeJVehjK2eU\b ^=/eX'V1&vkwgOϖ|V<[5$WH)jv}UgS)*F 3 cz2'Mbu8h܌qp8OL'39 [jr˳˚ib!3&w/?jbHohT1,y2A >h`}B9~TdJP=(pX̓&G:J5|+@~r[ o_~`Qr93ݑ!Z$-fǘ)g UOr`S4eBT9 >!Ս0CNrhx!Al:}}QH⨬'_ as`9s4Fszz£c䷯n&i{sv*3Lp9LypqZqrZQGݞq9=Yr-*'TUe[1 Z4 goN| Ñ;Ǽzsz'竆>pX8_s O!;}dۃ5ۆvdw{+tJQ@{!}A"F!I6W !D)EYw ɓK=]'C `[D`%rUaYQ SberdK(R$+\H1qu˿>]{+Y:w7mɼh/IrAc%`Z-1Ifv=mh^G=;shgfPgѯ~t\$*͆3U ufE@v:FyQYR> 2!9M bklQ rٱ4$ !w|֠~BUd;Ҥ!TRbZ7<}9N*֫n`}Rꞧ&C.*NXZ{8Knw^ :lF`1YL̦֛=)x́1Fxqq:P;:/|syiYӢ&HSX*c8YNyxQ9.W~ &S:'ͷϯu7[-?F'' e:=A>0@`2:ta%9)& -"CB黅aϡm1ƠF}("xl u%ޣ\*iXe]QBWD\^F>(|F*gĐo))Cld i#ț:NBwp s#Lz5k$$BR!`HQ܏fz`N$G+1=礍rlJѥ *L6X-;)jUQabn٦ ֣1HJ\?YT=9혞 JIJS5(Xzѣ~bRGI2݁zo)m9[|} rQ(8A+VPZ.ž]REB1RTɤ.K6ԽІJ񹶂1,H>SGL -ڌ-YG{ƞs&DЉ⤖[jMa qT5Ǭ=R #C1(iioJbLٵw>&ٌtG<:L1wpXmzc EwjJ[A ٢”5!q`Ct Z)Y:Admj84D~ *IAd!+++h`9EYC$&ǐ4>Ha| B[jK&) %{Eц5%h^rô,)'vv1C:BK2DBJ>tGyG ZV#iC]rC—]Hh ^{{Q>ЏD be~.qm{0 wM]RU I֦5yee[|}dp~&m1@R_,Z^oy 82_,7>^ [(\G#SI"x'qC'r(kT i&jH%#)i\?3bim) Mh(*+χ0NL=(~Gcjo}8>[ptWoS>x4a>-ݪexO"0hJ:1qKt[ :^^Rه8#G' uaxh|8=oP7LS^_\n)%Îv_[hypzJ lV+t] 1Z cKY'% ?PJC"w[|t&T%ղݍ8PZ~HY"61|jvi4ZBQ21*R}[ Qc' ,HcL^,UlyZa)iryjJ( e]ntѣ HcCI?PH2 A Wrn` E?II9& - EZT  %?kTFWhh"ڜl+ }R{@NŬ$z_Fѿq9E )9tf΍kba M 30*Vۖk,m}O{G H%1Js6!|biQj0)-C 1R rq]Q1p~~JUUJ1)4(y]'?"sTuMUj{9UA(Ju%snƘE:KڧY6IayB*z'FI1$"0:mtJ²Oyb a0Z#b+1B׏wϗRa^MF3&u\2 UKGu6e#:$~ o%3K)d&sNB*s>uim%ː.;{0,jCp bjP'˓:clgoVFtgn)-fnO(P)2Rj0D"%]ϋͽ,$t2g?%*T⤩__gm5f| >E>-.\QjvA@e"9&ub1˯-w'9t,L8fӧ֗9NSF<MHTEduuGY$0 a9qkԚ.(th|+MEPBuu+1 -n{`IC3BPQ> scVSFa-QL(L C*EWQUQPC@zˎK1t3BRGXVaJ,* [l}?KIܖqܡ"% IK=)*D<8G[ma6_}H)i"6]ͩPR䪶Is(-uT "C A1ӂnOpc>t(RzJbFǐ%hF;|aҼa6ہyRkɤIlZ2g eiH1qTLsn߱ 1J\% ]P75Uuʳo4WTe 1UEAR@+ytNJ>A]Ȋ!o°8?)_~?|ox$t! ZKi y}f2]kdCSJ~FL9R+Ie8_4HXёpgێ+ϗLsF7+5g%ntݞGS{|Ƣ3iα(,HJ.]QR*Ł [\?DZj+)֡2U*~SLSYA;$V2* IDATQϿŬb=<[N]\,@[AB0+K4 $ڶG[CSX۶c(5#II]X֛vMSqvrńחk2Y6ޓcu@)Ӊvu#\82ͧTp7$ȷfi*Bb$$m98eUILv-,ggs^f OeLQdȲmUՊs rR$g׻Cϕ;G$ *9cX6\?˟ֲ{9 "P/ wva Rki[Yg<8=2<8QwyvƑ1FbaIk\] 1[&܏ [01;0$?jJ;ѥf 0 K%G_895<<8G^ꩠ]7PJ&MģȢQ6D?2lBYIӡkssceI6M*NF!iFn|۳`KQF,.cM+0̈́Q@n1bLF:c ( j1g1JNSńώ٥I2X,NQ $qǔA\Kr UW-P7Kna}cSw$b̓T 'G:PYITTN =s<}Cϡ'5MOzj$D$g9l* &m۰k[6a`6P&g:5֖LŔٜIG0kӆl|>AW|15pw6mOkN<>w|/wQI]7zHd/ ݮ|r*&|2PV *!'. MU4rFgŊݺ/88Gͮgeag4GF<",,GLxsvc{P\mz- 8?aVDIbQ~f2<>a?|'\p0#Ӧd"b,v()v:jlMSY>7fݡB DFR&:UX)?בwDPNA1? IES }_&E>%6mn RUX~gnZOQ*~)'૯dƛ+=Zr~q'^n9=Ol-\Q"brQʰ?+ڈ(k"*],-!X'gXPګƓTA?w]-VN4A\$Gkzڭkk#:&eVhFI$: DQjLj*="Ŝcgb[録n(Ք8MeÏԲSK,'U@<]F;)H'aH@Z ~|ɬFfiKVSZt]E.>\) v̧jb*˹!l.E&eL'jg(KK2B +4CJ9$U7&~saTTFW<}ˋ;ֲl nOSow\]y??] 74nDX7||ζl~݆|DB(֚JR5%V~tlZOO=O>l9e5kͤ8=xv`6|饱Tv{nʎ!g>cqx7$}uM-b" HP޳ĤL(뒲e%YDZ~o}΋OMFs r ]bi0 בɔ;>Zx>'H6"P q{:S*l3p_x-K"V4;4MY|PVŒ߱ٷ,kƍtJr*:o3UbW[,#IThl˳t\ٻ@m$aݍhMk2ġib$Ą6o{f;0x5|?)uSя!&;W)W7u{<*Wlwe3 =g u$8@u|zK5!J"e]fp#:$85l?IyNZ H#RJ{8/D".ouFN' e|.U.Zo-Li)ưmG~ i]rh8[9[Ny|>m!\NhQ D]$Q+ycגJڽF}xuaPDrv[㳉2j^w[bLAi^3\zOC|kS̖5VLKEUϸhw#/^nGŔG'5qQ8a4脲.y-F+{DdZH&1zq>ӘRDz6 T$$ 4& kzd֊#`Z)j(y$!x؏"b+ >YS?#$|(oV6O:.8zbUTcL{QiɍRb=L#މu,%E=Jr+#: S`!x)*l,՚XbFߋC+MYLtl#JaݐeE4)E댂!mh!%)XrK+4@ ZnX^rhBH1jw?ѻ1ټD@pC#ᙫQrʌ>h\c@kI(q@{b7=EQRZW_>ǟ>?'mvRmZ䳘K\,ym +tQẌh=7+N0xGw0HIaK~/xJ:p>9n7OX,f2|΁ Zr2(1$h] <^#=yb]{ ]˹~G2q"gKZ4ߣfI)4{9_ |QBIcF꺤n$m>=7wnZ^_hL nwVS RD(]Pސp`D:tR<80 7(>ssĈ&*#.#b# p-*:{4)q3z}`Lެ%0Q籍%XN+Jy _^jΗ ;&tBߵaE0z$AUb87ES|jü.]?/EFI1GӹƁ资jv<{9m/Ew@@5Ê>x_v<׫˯]IEItŏ,?^;d1(-VRv試 ]#TUE]IOvc`/xׯ Q1FI'%RjL2!IaFΙC oȯb:҅rG$D%́SIw=wxؒ#~gyzʁC4$InV+0+ 5/.rqD#c&%ci7-׷;"#aH mC>aK)KK׋:g4ԇu}B@.H=#%dzqPl( Ap#VVR'H0"KXjB%ƱN0`$)ْ4X5-H=I0V Bs)QQy%XdxKreQy qIP"!p#$/(fL"N|NU1* IIY=z:ȕB q&ߍ惏GaoI)4uS\6:/'̦ }Wh,>]5.hTɤiCǑ9~4 QlA jVbn펇TR}nPMC嶯tBw8?9=[ro4d|IGƠfq<ݍmD9̦if7p%2 y)%Bm*kټfhö㮋eE5ͺs1jBY󳭲K\"#ET@p ԃf(5ߐ8׸$z$n)YOG,ȯ-&LȇesQDxC1#>^LGD]cݳ,O=?kbܭ665t΋uAQ4rUIax{Ó5ٴ]^a=P|'9u̧Vh쒙QdIЭ>{TdžSٛ Q.: jH{Rߵ\̸[mXPE$OΙLJ mb/OJyK,bzq>H#ѿP( H "s.|6!Ӑ1GZ~>E=ţ7r6tcuP$؈5#V{? Ám۱t7L]q-ugZ8#ZYs'8!,S˂e`"UaYN+lێնg:1s e Iy|>[iu 8{sIw/1x]?FݗҼzs>yrŲaEՋ\:}77LzWyFQ&I. qx4Z64c6hӆn55cﹻ]JX)zH)`5Jp`m.M1ӎ[#bt7\OƤ 1@ie86D GڭBBw 8̩8pm#f7 >k/RR"XI>?&Ab#Kn͈dw56Io% MTԳxGRLХmxP~$ Z 1(>7+%#"e BcT`qcF ^PBR"_LJ9I C,%+*T U>ޖv e jALdшoPLQ)ܮϿ3qyO/.q'??ᇄٷ[yu Վٳ;~`<<ѧO>bOr N3z7 Ww=W#`,[ơ^.ٷ#$ɒTAe ED++42nv%%Φ.a$>|:{2RֆG5(͡%x(D.Gd 2y' JPYB'k#QQc )&;W yB٪94J'3@JB z $L V{O|Sb,__:ܠ =IIXi99]\$g$#pD027 E]%(FwQ;:?9nwxmW_/psg{Ji 9-ƔP2]lN!c;Lj ׫eMlbV~`Db T8~h{3m%KCyJ =jm:^~?R|1TN^϶z.e1Jlo7&n\luYMhw-]L\^|Wѕ}BǤH?zi܈t~$YLlghŴ.`p|wuEc!HMFau|f{##MLK=ͪ*f ̓SN3nzv`t-^n|t_4k,#ͪozM>ҹ1WdQr@L$Bg1hTaezr{>2,ݑR@G{,dPڣcgyz$n 2XK"ا F0B")xS;D{-Foy?"U`Bzиc7߾YIuS l?80*Pe* EHYQ*^]|%M3=TUn+z8Zn(vq.ciQ&S!ZG ҕw1m*RBL䣇<>[b@a&s\@YsA]V> ޳uwTcbERX#.\XFHؑs*. J88֔V\pVG>~а=7.|H,ڗ4E1(rϚBd>"69%E>OJK3 ׭T&g<:pNϿ{o|f_TjϺw Za󃔹'źa$,Cޱ#¯imhm}FEB#(2Z9L8|ȡmuHvB$D?,[%ޱGO_~G="DY$]7),i&Sm9}C߳wt~wG] u.Ő5nRikpN2TF. ]rWFD/#ʜH0@MLvE#n޺0F1 Ogz8gV1|.i-!,<:s}ɃSwϺYP)Rnv\??|Kj..rNJ 췬霫ac2얺Ґ\:)Vn秧T՜[٭wl /h36$PrgOab@==l!FLW10hWȱ IDATȢJ6cDmdY)% 2 U (Y/ }o/C9=Tgyah|Zn3E.R\W*OcY) m)Ṡ8b1b(CöZ0UMp %1z62/IH.k/}I18ߓ*\yUbt- 5ZAmB2,\@k]BS$$X1"MFgXYLJܠl .pv`1C!D-*S6иak.d\wD[?ܳh^2kj)Q#I AߗB& Z,^/8[IJ \mZT2<9xV]ݍGAzAQțc` 0Gfg*BBtG#nG)Ѩ,$M dx@P*(ױ|N,lcjKkcr28TȔ\xzq#c"%'2\)U07wk^ONJ6|Ͽ⻫˭'%-JG*RIt)hK``vv 1V.;ςeXQ֘٦w#3F&gQ=Sǟmȭ!TEIa5  F[ͦ[~ َ ~ƛ7k\H-8<:v/R{\SVr231 #w=ypCYhJq> _c.zӧ N57g;^]o:G4UQP*9g磊tٙ泏FǛ=' 'pw<ͤwknlgy~}豅4,oߖ *yF6o^dzhP-Hfz(mL.OPryݷUI4H\tCB;TjҒJDrg&PVe7l=ǝ"؄*!*'Sh@UK7DiP&QP&i9p4xĂ= %6DfcH JE!T8 5ɀRDŽMJ#*-!:R @#VESmHiqE%US, P=`%ѕM50t!Ff@1$oU(%IIƪ%8H T2̖Vsh\kSVFnO?BU̦ʲf7Ͽxr6 Vw>mH``pcĔ ZPYɄ*h[ Z+>D/:>=?z,!)Cqz2g1z_,)"2H C !H(izBh@+ {$u87lT\Wјs$,KVܽ1c̊s8tt}9dbUT}H%abLCO/N8]-x8&v$YOfږىvVg/׆GBǽV$At#c82I KQb~ # RY$ho9رXmYERSݖb5>s˳9#dHQfTް9 Aph* Є{Aoqc{BNǖR*:+M_(S0d\6i0/^ق2ͻ Lz0Wֈl5 kMxD㗂¬uTU(̄酅Ђ1hy ^aFMsr˓CO7$N3>Xr}|'|s>Ϯ@I;~d77~o3s!b)s~:EHXbIbdPJ`pəc]irIR-XуFvRA HP 5 nПX\@4~izrAsSWDxI-Q@gEYy %w|)g"mϋDyg7\˾pqb^1*04Ye7⚆{%]Kf+E4RQahN5h, gmCJMr,!o^qyҲ\Dok?և@3Stƫmgs$>_[0k~v_y]ǮD^ҽw(ѰXTCF"k&'?e|'6f'-MGqsczG r MC;0qTd`oсY2HqJ H<1F6eet*EPL&c!; =(`JPҷ,9CHo&pTq%d呧%K\*18!]Q*ǎP2ZĉBu]% İvtÁ6xr3 ^_ 1KbߍʳX-B?쉩0kg5⌬VnY8.iygpU"j"ugS(AYNk<+qU0k<"g1*$z`^h%A،Gw\?bƛufۋ{a@*`"8R35cy)uD7izw9ƒpde͙YPUwCrɒ%K6=w[6;ElZ$gaT3c!eK0F }ptØ%V0p}}JTq7br >t\-sՋo) TN.!Y#lE :>2?EYXq oLMTFVU{`Y߬yze\8Hr7|ޭ:Y?yϿ|>(+a* rje D)L#?sș !1?Ϩ'Cɑ!|˯?oAb2eʂ).Rdb`kzf""@R8\,*)v|$=P4d w9I8QuFӼv<=s9Y6ٟ|yӟCw%5}F],agL֜ԞjX,[nlH=N@3;p#݁ݚ7{և ug0bX-x~W+WCY:w^>*6]b{80dͯ^pF$mAhe[sҏHNQc_A*x4,$L֑'SFT2XO 9UTπhDpڦŝ U%d@C"b8A/RZ.tJu' mT@^Jl{F-[pM^6M ;d0W2@tVͰe):9h'lVJV]@c%U$mh >2Mwa"Pb؏ HFqPVRw=c78ɕkkpz1cb@e)\<א2~6/J gC%z`+7eLSe%>m fmK6ªYKzg>SC_ŚE^xi)9H 6T:؇Wo}ٓU|Y.g;fe5ohJbI a߱kedOTՌa`my۱\N3NO9#[nwtDH"Ó id,ڠ1s,sNfXxzǰ"on5<;'8FQFtC"NO[t<-ANT C*2v2RLr%ɏ.f ͈{bB̈2]}q~Uqv\Dc¦D/^m|trn\KnwqwT(DG,=C'ᘴ,$-(*r.O'dAҍ2 F .W 1@MĹP2ԼQ so*6J6X6j/zٳcQ_$ƥDW;FEǐ07R)ܯ{ `^M8ld^>yr3.Nd^.EDwc)oݲ46nnwۑ!Z(5h0Zk!*A@w"~ zmnTǥ-) +\LVͪ9WfjP&UcG[^p}lYϑ/?ܲĕKԎ1AlYdk onפRxy\26g@;[~!vlk,dN5m]zױm_rFrf$۰?j;q Do bm~W58G8 e^ڰϊ FUͬ6|}?_ϟWF 8 T+dr`{@Q&Kxr,՜wZ`J)+ @6BVZWuɽ2EYr)Jo[ܰBV5ރޙkDZUEWMYcdN뉅 {v a߼{#FB A쎛UN9 3yr+VYRlYqv9D!1 YWc$cs籏 a\! Ylh9uJd-fL>3,M$+ٜv1vXm*mckX9eŚ<̢piXkMR55rH>V5||ndęUHfG e|D̰3~3 13)ᝥ+ںaȬwr:ȇY(K+nd @0%\^rqvs%C"-=Dhj0GZNW V' bJ7{>p7<ܮyvudIp!7n1{US>-~i7Ҕ˦8C٠`ergZkf6'5c[icb=1y}r\ɇWN*\阯:.XD0r$wk,xfVyJ$-,1YL`:-K/8_4gGnny{t@ #9b_~Ə]&ds4MDuƛU>0G-lSB̤fgP xmMZYTyjMkTF}bI1-ram˽$VVY8[8_.78FYEpг>2`Dxghw;ϸqU߼gİ2-Wg3kadT/wru>XͰdں 䃵a lG p9 $bD];+52{SU ͖~#g<>?_ gܾ^>a8"^2CȈ٬dE=!~0|^ 5rb^]f`Rl5;zcꖓɂo! ŬnM7!Ke7I.(rRd.x#·^[BImsv LXIZ":Y? XdQJRidL.œbz_ 'stwIʰH~, ϊaʣ*"ֶǘ3PUN}etԎR3KH!D"C!c!0G~Y^o>p~௞\8n7` p~H<\Rf6k+Ͼn]麞痎y[$zbL`ԩHK@ %ʡp.amr!Qil k a}BҳĚklXdD ظP( NfY Q>x=_Yy'w4N_ HK+%߻a׼|"/rt6'(jb=)VbjcJYnOWauA#1˝(1;0Y"c9,?vĪ)P&z'*2OEm1mC Ţ1V4״øgf&Bg sRw=@w?@,})CI ~X45rzvSj>13Bam-n;]';ǡ&+Iԕ#qʱƊ{w+>'?~}gׯp|y`7flY-Sv_|}{W眭b)la -?\_B \.;W/On=|b #2:S˚g 6'L7/`' $spdA3Yc{agƮg)iH^%EֲέPL8ɏZ CSI˘"?aJ애{~ҢH.čh[#TwQ(>E* ",ՇՖQ)A,Uq< $S,Drij1Qf,3FOIsY8묡254NhŅ{O;oBR!8&R 8V^/ =͹".E@`chxzl'l@E,5c,K9G4mꆴD&$NU>ԫ2|Rd/k ֲw&ܔ&,m)WhjI@ 1*I囁n7Zv}a$gC*oYU~?x5"TΰZX. zax cvCI_T,f5M0żd!@7bHX-]2k)%Bу#79? rj1ʤ-bf،z[}_ƤbRWgz{OV<{vgj/]_+n`vr˜ 狊gOqK rj8guL".sneԤS2k2ĜnFD)gM`;JlG97Z 墝XmU$.( HUg#(\sU%;1 0 1ui)l7Cf .=xXXvϳ'紵_.yc7^-b rEuo2=28MӱU }O`t畅R?u|6! ?%}3,ZreۏBfgcXKN.g3k]?pqug+\bd׏8]0#cߐيfNw$ !f#q %58=л9fټa1tytZ]WN#hjXyM1q^~v1 \9[- /pbb7&!1 ;>ëSlհRW;iͩM%LL\+p/Q^/Sk;B,|2&Ήn #.!̩)Fװd EX10r$=念]hp2He+6,NG=O =2,#ʘBUW+bteb(:m145ԕԋYC/0>j3~O-~KF9;m9J_sh4 0|%ni(Gn<0{p?DGw=)G R"E9.srq ,V>?lNe=uD,LS?&R5uݖLXCfmGR1dr-^y];5\_4k~g{@hZN5Y͘ĩEq__nK2l gDtWK~o IPmw'k罋9çx+orIZ J1Xo`WS*؏.%)ĝAQ i.ZJL#m,MF84{MhcUSfЈFrI"Ze#IaupsJPsFض%*Dl^.HAKuET/"VyJWZlJB7R }V~,5D Lz_تr(mšh=ӭ7]몉)1JnU,O޿*ʪɈ0v ۶ehs%I."od9H~aUWBKAzcԶp~2!\8Dq,Q^@KC:R񦢹8;6fr@81]z3Rrfh(H?a 8G?f^x{Ǖ,@2dA]ע#L#xx* 2 #rb1o8Y-xrqF4tc`98[apH7DBHB۟͘50%4$ ;mj}&&#-K5ݠ\c2wS!r*8QZG(-|wacJ:zzpsNX<[yx:(H3 {X#쬑>ѳ*=:ji6Ǣ&91ҢB!+ %[j*JI)\fI:XԌ;$*-$c. )3dF؏:Y"S@RR^6!pn# ;Q-fq wUlk.NT{F}9IGFdsw@]e9 ʎ|}WoIB}mYH(nN銫C#rmgKn;~:@ ^X!H!XiM"ہru7w{1 `EbqRLalXrԕgSLonvQ g-EKL*qƻ1I+v"1laHI?͛Q9 ." ű\hrnϯpЩ JگSD/z0 cQ*y⭧A4%C car\-G-P)xD[VYVlFxِPIN帑*Sh<8pgESUU8#4 %f+xOr)39&qR%tCQTwE%=V8JqiұVXM*HfQS-8+HEhRID+?= e%pVh*C2EH)3d,7o^d8?]#cH #w؜oq{ R4lҖhquVAJ?9snz^bQ@Z 7'%S;&m;Ok-tQ1o^8R+OITh 'eq"w'h0JܾO)Tں5B邓h_{cbS(iGa$HVm5żkæ; .f<\tc0RIK7>d4(@˓K|EQ>|M;ZdM}fN"T`%z"-ސ=B"yR狆?db'WOhw۞#w>~_{çgx+3aJ3qzj^4m#9VߓN#FH&L<|-擬#gܽ*/gԩYY. 3c42uuǠ#1F*at3Ĝ`Ebٰh 1oj^&r+6n]t Cdx ,,uQ٥Ŕ砼jո Xj2Nf5uevhˊ.R#$GC%SF cÑL vEx=WxWS 㛛;0ItO3iҹ@GBȔpP׎0&QfdH*\8hC# (ԕZiDžYRXYJϛR`"Öw7w__j* 4v5g63_,U-ZckP-w\& H Sj=ȽXmES~v|9w0\$eFNX %E[oI1zeR)>koi*KU  CX岥3^ANrbc 8dqD]4|%e >CmZ|]aGi.[Жr25iþg޳ڶb>oc~gNO朜cC8]"w[a di% &ZK#J *)^&1_LM,:N-3O+>~3󖏟_yW7,}1yg?$mEE/#i6BNՄsQtZ7ERvΠ+Vϡ̙ѽjr6Kh1C{(LᚓKN8t*abE3Xx;i2$Ķ 샴cʄ,FaPߴ5T^]zѵ.Yaֈ;iSXgkOij8d(1M]㬕8 ʔgT imc`/h%`,hٴ`ݖoJnSfT̼c hsrU-bci#U幺\q)'>;D- 11SWzz -:Z9+ C1솑ݡgl,CG]N2j(O^tF՝m-ݵ>r48`U 풌s*J9GȣVSTѤϔaZ{sYd(V45<=m8i a1S2JD8B>swǜ`"ܭaVˇ@.QuZ$hzBUu V\2H\EYkehC[I AicKF^rm1 n 44F}zJDN7y]9Ko<9]`A@.eDT~ [s{)˳%+uP= S }?@̚ `Y[VSxupF$Mvw qrraV-aױ]oltC,UUcĈ(SVD=$'I1g!1$t3݀0o MFC˒DZT\\.=Iٚܳ -u0naĔjrDOX+8G𶋼7+sՄg5'sјe2ۦf6G5AGnoR8LL`LtQdfuf5S&8gج:r9rXIU5WKW|t}rƢlr~.NDv-c2eaI-s7Mj)Q"9eQ$+/Boc H$4N"P) ^Huo6,͘&ɀDkIg sXH7ģ{+GVjѮO>f9wbdF4aVWG+F".zo1>j88t?CdI\ J ! YCfm=?Nȥp DȺCRd9G-"}!ł5iz+~Ya*N5W'?xj?}7ErnVsӅKJ ud,I=ؘIQ]ٌ"n6^S1+Ӡ |Z裐D2)K =rD^ۄY+ e0GP4Iݘ*Dp_TJO=0ń(: 1E631{0s@$F `Dl13䔱RJCKO){c0#E9Vqa #eev`tYXqg=ם6J2 +ɚ#A_aAkʱZԬNW4g8;-ޓ Y/UtHzt<@c 1&Uii)FSxu.r'.82q {pqԵ#+T$3%$ .Ydi=(X뙵f#ټwO BSRS ]bFoB?{jIm ~􄻇f2K,ܻ=?KΟO7v 鑼)ћ ry+r)(a#GGIyhGbf:Ma曷x[O:.Nf-0o~O'Jٌ'|Rń`}"D[i^m4iaEFc&;dkG+K)MIhxǸ/Mֈr233V. )Rxz٨x’#”i)߯'ѨTk,˶œ3~S~g ߾W}v^v2?QFQ)̍LxZeX=yNPy>Ң5"f~f\ oH.HANdU^f.k_8;j펫L)}}-uY y{C;MIBAagκM.[e9 )C.6gMLQ:-"[˱ `4LXUb;ǙD9-MS30QiѲGϏIӁGK.'nds?_^۫{)@奛E!L /RN }sNg'du3M`ēE 6ZRt;RJ٤&BĪ>ȁ$;<+91%ܺ"I $]/۶afxc"MD )i۩m!枳LatIhcNg}AeńXJ1RyW]?#Do=SXcTl2qUΪO$`;[cI$!)(%$ݠYٿqq"խʤ&6*O=*6ԨbfF'Xij*WTlARYǒtbkmqhV@NmBL]Wښk{KabxaI )P{f3{+B>r&BL:XT :J  d8FlƝwA0F/[oyU]w'+NΎۋNinUySm8=Ŋ.d^̝BfYEmI"HaH^ hEDKZD[]*w|2Tޱ>Z9C?.Ox%L)r"SHb0hkţ,-6 3VZr!Op&3 2* gr?t]6v$!LQ,9 2R" E1S%#j0aRшa#m-8a?O>sq~o_nL gtt^s: "S6ՃɨIKBz^ 6~.Ň,ExX'-\,9?Yb 5y[O!z3p pT>sw7Ֆo_Ֆov쇤q[ꨭ4l:$XOZDf}>&5<(SF8S$)z č Qܗz Z(~9Xxd^՞%3nv"(w%Atau=2>Dr JJev0aZ)S$IӪFX$ bg!3I'}ƪYxm1N,&]Xk5ozVqYJRX8(Dz2n\". 0y*[sFLT*RM q!D5d 8k'|䴚N13~H\V®8+x)w6VU׽QT%(3jQQ-eAZҲyD'-2:-ﮀ9WJД),G 1Bh-$\ SZV떲 ۊUkDogdstakÔdJtdOpئ L͚qֲ\G*먝1ߔ8M!o>z näђU]K 6ejg!g$mRǷ u-,]TLY-By+Gr>&W4. ݤJkjχa g2my= ..Y6EӐaIrLڅJ-&V쀙 f?6m~nmd>L7 A2J)r[S)@d wy&`AFޝTTe Ѐ0f⚇)b]StIR+I @$břbK!Y5 Wŏ7!'+GL+~kK~yFQ@C,f)>I r)D)@#DaO.Yw?A7J+`bb}1\gGX['uv=˶.g\To^׷t!sqS=ˀEIbHtGi^7xo7__q  RkӧLd N3UpIL?' 04^U'%XC$gK XaV*=f{ȢӈwSV"F`SYhR@-T\!Qs!YYhHZ>;gg5(~`ܪRXk}: /x@IarbQhɗ3 ]+"ڜrd\b]~&H$-W'8ߡzCDtW5V2!@2M舆:tcC 8KJ8 ibyBݬ!yBT_5?M*hQ>jטH$BL%[3/;Ώ\|Xp7ŘY}&Ockhu⼴ [Ԏ)6\mih~,g-?\V<{Tʳ@`fqo6n'k,U-T04u cLގXxIuMee xS [نprWݳ=)?'lS~s`zǫUv86ca62Z [8ugX95)l~$ai %rlIbӸKON<M#;![&dl\y0D\ml,m|nFmq+$)Ei%)2%و"fpbYZ(MΙ!L'&X*6 _8Ҏ%RZVl! ;Zh2L :)e{RO11Fw$ʔLCF '_Ɣ\77?7BaՆD+#IE˥;1&\(,4MYt$⬱A*a!!IRՑlJǶpzT3899:=;s.k1L>&胡&Uka\.a3}˝kKd#3ݐ9J`alwEq[X0Zt*=`&7TG+9ᭀgӫc/9#aNlbw1)%b Y4nz{08>^S?9þ^v.1wx-) MAE|RwaBTf#fiY';WߥBN4pyŢ{4MtN&a )WUd89>bʆ0q=;;n=]3&dgUޥ,n ^i&<Pzi벶5EZ |90rvmbuFM[XS!B0KlN*G1=B"VRvZH/,[(Xng8;68|jn†97l:`U޲h4ˆ-.@(=$]8Be Box'8`gȹ/҄hm#̐d1”8j2JK%ʐe1!;0hZ|SK+YzFv .DGئp0BF?n{eX*kF~?Jp2Y+H?=lw<숛[ݲhjk,|͡ aHuY-}! lnG.Ώyh͕o:L@Uy*kXxǓ.FQ Y2NI[F JHdE'Oh;lez.킄amahcNY-[{tSL6/~S;9Ds )Pt(N]hJ>}ΙSX>Jqͦ(rA H-8'I6F>cʙHcuXY/kN-.rp.SDԝc*. L6RCp6|ӓۛ=g'?'nng-MU :8av[dT~19dQ=y/9t'K|;2/VK@WIEˑ&\ Js2s|9rq7Yn6|}ͫ?Uѓjڥѭ+|򞅇G+='?1Ϗ|ͷ/oxFYxuM,+NiMȺ4RϐH:72`isG|Цr9e}RzxL?l8)OIӑ6a%(+gg&cdp46:ŹT]z(A{_<=y/ 'K޾abvs`Fķow\q2 puEVW36 $E=0K9*0 U+!knQJc9Yi8t֑rb-1F*9e-qhś-NDK~2L wpcB˷s1Zw|sY굋nyV&dE,YDo'#Ԝ0:V*Ɗ駳DSr0/x#8eÁo'w7&M? ڳh HQKh`n&/ (Ԭ3 +-!%,(+rlTLuE^i~PaRsS*C4 Sʼ#Lk'Q75FY.hZŻI/ _['R>$(2Wʳ0B?', 9% tWd$0E.tHw䥇BCBNVW}w_O4KBX]meLfZ>{9c Xr=\~% ׷ h*V s Zl^u C` h1Oa $dI[֎O߿Xx IDAT)joYK{o}?~oG2qy&ëC du/׌_W'<82uR"'˖ݳGAsL@u?F -iQ]ZM>i/b!fp(!M6^% *1JYiҵ0#Lo-\a3)h"kv @DUY?Ï~O?}ơ;pė_^3mnjөuX쨫XzazXŒ*}U3F{fƽF r)ݲ7[3*(zB*:XAmX̽h K~ Sn眓xQ]l}u$D92$VYcF?e}?َ̗L :d KkY;݌,gLrx6ࣗЎFWE <.Nq2l0 A)9C".N8c Rook3bX*|qL @-;B?qe1rNHm6U!Ӊû++^1 ~9ɴˆIn? tmw ״̦vӷթQ-+.N W[noD)`0"EYH$:J[Ja͉]rgG4ְh,X1F] ZUk@C;*xRRWlˢF*1EH/+穓iclN ^VgO9=_sjQ,4PUp}qrvB^QU]bswwޒr☣heȠrգTNٝz&e)z,= ԕhE<~c~cmE>e)kԆ%i t3h 6q}͞_\) /^c.iӆ?z/Kv++L.iW)ϢMQcX88+19Q[M:byi,V&V[*8Ud]/\9ޱ+q[]g?{9s{u \g/?=waSz2LU~{{nv=}4Ge+%PImVT63bN큡YW7enR`ryS3:@T6 FFK^ɑR$zc\ {lv\o7[8Zd_jUyvN෇]3F {S-lY-rJT>J;JviD;#ht,$wf4~Ue O֔b"Y9rm+`A_Mƻ!_oHBw'{9ApRӳ3޾ym1S$Y(Tg`+w, '%NڂaxqRYD.${bHJ:˃Pam#.H; zQ-E]LIjh7'Rwښؗrѣȫ Iںd4$ Z?[szR"хKX%VA4mbJϲ>" sىkj+v dMO:YC+r͞GkEsD֢%mfyzlMw&4-}6p~VsYp臢͑#%-3e֔e۪E{G?y!kڼe7;p'6vR,9V'g-Y=28fDkdU\w/ȣc ~7,]?WBKIg(Y.vl)[ac;Bqy㟽d]Mf9ps3ۋc˖ngcfx{H>Ѧ*qV,H[pXZl<(R^00H\LIiIq6%噗w.:aQ0G) %d%FVʖq0KT~#H]9)Mb; 0Dj 1J[K}V 3Y%4ݽ0Ni!d[wc8PnȒbJW'p ={`hb )6,9 L)8N ;-mw^꣬UEyޑ)fp.hrH{ c,[ֳP+,C JcW,IR{e= F5Y+I||mO6՛Ģ1b` j`2M_ML6y~'g/oIXl d񵪭aִzr 㤀ʀS&ct:яDۮ0RMCN8 o =Aʮd5+G c$ɯ2=`SJD}>72֑|kt8%FnU۰^. ,qi`Z,{κo $US3@F xBpDT&j)sӏn9?i9Z5lw;5}+~?!|w-} ^lS,8u Krd0VҵגejwrR沃Mg2e]-j.CF+a 4vf2%LJ,*K]9^w}zПQ6yXZZi<>'G,La";nw`2_~svs|zD[y wIW'?!v p$e'deFOcD3Rk)(2 |2ZʟSl 0X̜c+ "'BbsPP] @"Id,$DX0ZDي0<Ä Ef.&X)'CxF4Q}Y,w1r^5/qVV,stҏ{WuEVLO-$Krw؋ؘHޒC eG΋^Yo :EgnnP jo [Nz\XbN$l_{2JFcPR:/[ ⮊!qeP<}OY[xy)HhYrHb6P w8%Q'%Kʥ%z}$2(g%rWk,h> :88X51$IZ @ mjiE( :k89^`9Ɗ[=Iۂ'Tްl,1mUq=&Z||s5:(1W\u|}8 />n=DFfv%H$`CӋ59 g,ݔyu}Od&=he!5MB)fexmX)Äu50¤z0 ae)8HRvhezhK*#9 L (Ay++|u[qZRUdw#m[Qb,ȶyue=L-M'4EUy3{qqqj!hkVZ*t01r_>O{.jad;Fز.<'$9L=DS7Xc\pybM=7w=)|ΣS?}f?_zū=j- 9!h3u e Eyvb _6= NḿQVP:Y-nLyD }/oOn)úm9O/Oȫ=rT[Oxdr8NncF:^>՞0OI%{a_|\qqfힷ7;v%8M}WZqFd!%ά 1~=&V I[r,%9Y%a,D&btê ig-zo{I S?YxV5U6$.N|9myus~9mmI!Sk|FV=ktt2,}3Ľg r1"j֋+q2=.,ʃMbUX.Bd.1Š'䇡#f<wXT (rR`e)XaLI&f@8)ֵ _jJYPGەh$gLQ 7uASVS=oZض5yOWrbUWar2)Ŋ_wwMG<[m@f')m5@2_/jIq$pf|>EyXFkDs4q _䵏$Fk#V]I.UA3/eZJF<( U#`lYC l21zأT2P$A8+5N< 4$QXZ  eFȈoE ŁdXԲOZ9=9],)TVEbBQ˴L1#Y% l Q]q9Q[KmFL;+MU-?V}t@e9$t̪zX1ְX,Sv-8rkͬ'1ݦ8ezj;etV[3P/K>|qzwK 5۫}@ٴNVTeѩ;jgm5(eJSFGJUAsZh 猯,uI) P$Dz8>ZR՞~x}uam4 )1Nq]!qQd!n?pjNIBDc&im4W<09!$*=d] (~rqb:l9n)Þv8tS0 xcp>{b7onzy{0$w|d͟9m빾3Lg]5r2yhN}I6j?A J[IR f!x'l 7y?߽F l3CnG-鐞V,Lh=] )#66D5rS\:?5v>aKFN;S|& PGVJA1dq )Er9+e*"'R5?aʙ8ep黕2sfN` Ǵ[^Gp;汵6i c: IDAT/gX/u`Gi3hjTVd,}ȓb|ݷ:d}oSʩъx"ÑT2]W׀匆cZp8^S %9$+jJ{OY "v^ zRDR}=hU".C@Ciu]LPSq B;ILD%+ZRRژ )h赑N,#D2N"5"UG|)m˰?P/VTsBcE[#ƞ9#$붣*TA=DyF9MN0JT)Y2E NǬ1[Lܳ$@Iݡ]QԮQb"Ka3̺ ;MćGϕ{p$̫wG^_y_ُϟo #VgX3Ɋ7m@N{xGxyIsB?hhUa2QK~JW'e*nl"N#ƫ`ԇl**椟'b^y$ 8!rooWKakݠS̔.!V\/n?{w%&n0]?[ˆs>8aw 1χ ޛc*vZ*>!.sEuzt9EZ`RkVbkMI}a/&SJ'm.t8{ u`XijNW >~v妡xn<}zSV%cK׏#o;{~{^.pg ^'oΌ)~8{JJJ߱L%RR%SeZ-ZfV%=bITc/4a)(t)Ydt@rD`A/VK~xpqZecSSdjO=y(!l.%5O*ʡuLT)OAbנfAQ4b">*%hJl.ѧpueݎA"Tc:=DdZ.!T^WثpQMmu]mj$J6t ' fZ>CÑPEE|y~CCy\;~-EM|wGg<3ͺR+ = % ~~#o޳XT\^Y2 8 xX,8lX,cvui"ub Aybk;2UfuvSEodv}ݢX4PI:xu!c9j)nSӳ 8۬ 8r{O~c |nۻq`{n]sط1R" a*Ι^Y#j!MTr(!9>h 6z1#b{M0!:;}?R{xx3Q\ 8Vii73Ɠ SѨ/(A+PHfWݷl!VnXcO LS&1T4fF)ڱ}O)a`R8 ԫqnGqoݿktKTDH%+2hd`fh*$KّNݎDX%?=>%FYL3&#$U咉ɛ2#xJwsŒFqI}yI12Քm2RCoXwX':db4se4}HuA_rgSئ^4^82:].وI&9Dhpzמ{ơX.j&L쎔e}1bvԑ9uEΙ~1۬[4YPBZ;dиU pmS %Bp1[H,ELmwޱXU*T^x|Yžhc麖\2cxz›竞Ǐty8 5|wwatqF,pxd(E v E8!1Y-X.jnԍJ"> ,I!dHTBY5M{ݓ~t'2XPQ,矝SLXE&BQԶvO>~ӧyw;8rzk6r&0^ʶkr"Hf1 04B#=Dj/T^cBR!Sѵݞyd\ڎ8j>gr3qHWlN֜nV|Gx{#ԛzEy-߼~G ޢ[R(B+c(o'X8uN#K~rq|ǘZݛUMS5 W[.NN6Ku[PsvGolH"T1GK" ܶG}FNM' +(04&B +QKD󙧆=Ŧ"QkA所i)9sV+pMnRMEv݀z\ʜ,qc8K9 (?ZZXM(^4|(R:b;s4Jwtcj>7]CE ˩ڄM+=Hv`P&*^Xm]G8vۖU9 {beXa{g_hUEDS $H^Ky)dA x-y4ZQSF-j5Ĕ2Ϧ)zÜ-/ Nd)^ppBNgPK;%1N6e(`Hz@W˚f!Z" ߑB>dXJf"G*yW xx; Pq+q4M6o i(qri#} `$GnoIm5Z ^ MI*1"V'suYR =daXCDvg(:OŞ̏I<REYraNq.g\SI` zX6DKkGF\xǛ-w9+O,=8p~vƢYF@%bT;w, N<.b )]zp ͘xR%|mHhB]AcT" OzQwp_WHp^y8njUTuWLb2R"B e\TT'5E #J^7Y=NjGT]@Ct)iYqfLا̐yyTt]n6*YTԋaǑu=lFA:W؎\iϜ)-7\8lG޽gQ89N,OW9tӧdN4K1;bc$pۣ= FQ$(N0BPl|X7)wY{ܿuMB=ƜCjUYV,+d=oqNGO1v?:p{.SˡoHքcjsŃĪX e" }Ƒ&4k.gx!mr)'\l(N+/( PQlԦ{r`FG7P't*{F$e?5LG3EQ7 "F$5mk郬MKQ?ٱh/瘞{5__=P27۫=C-'2֎vèYrVb3ȺڥW66{^I};0:#sT"4hGsfʣ3#:ޜ'ŋس+ a"G!DU eC*qP&6~v-%#NMIc8#?ٙy0ꍋЂ#f&Nje:^lY-EU)o8ZPt7+ JFNt4!i@R!ArA }2O{*|qzrR+sBdlvRxqyw5/_s;RK-]{!4eƨ61&R4uzPWUfiê Zh8)XTT@Sx8ȍ >;]#}?Pr*TH)3ƨcIalF 3.'!8:ɉ~Sr5KmΎ>r\\G#)P+쿝*ZCZ=cdK;RRwJ<c?0;JI$5GK.N u]℔/߲w80DkMM@eдWIqH$[AJVcE]@-l5MVy):B^&*IH-3 xçOWOjjp9?]?Opun#m?nwtH11>M&`̌~LC#2m5Pc Sv:~XMaL蒘[|BOE em*>rAޔ^w yyE^yKdGbD^<;t(9jĈ4a3;MTXWk{ =$aA|f(<"b ;&>Ȧg2$P Ndq 3!u8~SB=ɚ]^rjᬢWDGu^ _*jo{b}1L݌s_7LqI?Ȕjbo0cG):RGZ/ 6mB1KR R%3&Ƥy<-XXVJCVxQJ>уlP)%E[\])F!.<2{@bm|HdL$f2:|R#ˊrI7- ` LO0f7;͚i/ӵrՒ rpwKߏS8=[نᄏ?x\j $.eAcuM*5O %MA.5w j=H3}w)!5|#lv;g ͉uEwc'^]w?yOzndsrZT׏)%ڱn='+?zdٓzkȦIf.VdG)ZhxrL1j.ս9sAQeSsvQrM*aoiGv=%B O.*~wۖ:[q1 g H|zK;Fn=ۣSF^س&_R&C:g1wq6>XSGffճPh&: CG\к/dOP Y%I'¿%d;)yK6t Icɠ420{}]=ZiEӌYY!7SI14bBGA ( KP"/_\ͣ88Q^jvNi1hFϞӹ٣3>i? =XXo֝B18Te\5- 9*J/hQdY *dQwzFٵs*Uvf/D?,vwqeU!# l$0-T# 82w4u=0(,k"ר5;%*j_ 䨵\pqVP,rʼn@ -C[q$E5IIb:3 NU9ZUNrXpdAGƣXw}i,%ib6±뗋P9-Kj'+!{ꐨ*wGUb3HB̵!kcD|M]_x"B/?O@EuthGvo֓e՞:'42W;vg'ԋU+J IDATv?p<Csq(0&! Yժ>͍J.fmG5"T2 !3q`HĤ| x|HpvvqÞ\ ǘy?|w͟}_|5c1l*9Cnٷ:&uNdW(biJ'ȫ7w(YՍW>{\,06Og."9n&s=^{Z/؁BhRj%>,ޱZ-XmVmCyƽzݴ6(EFq*b05Y(t}W\/Y=mə9y#c6kEw0:U*Ji*O{+[QԼ 1AXtw[rZt<2={gkc5)G6*ۄvR3 A+%l~: {LΌz MԶx DAE$jHwTfC3$Q 'Yldù0x\UѬO(v9g>ABxfvXG sy"_|x!UC+J8Ǒb\ :mP &pQ%?_2M&w!;a4D2o޾ڎP8tAZ;t|œ5kǑ}kfڹ=yzAS;l]?v2 ȡ'ȓVDqZ΅E(tpstӊa"'xW gk.rh%.sg~wovןO-mxRG9Q{O'摒5V/??59G ?6(ɢӆ4D]Ӡ{HT0:L%Y:SP=롴\ZcfR29TN6$4j x9/x{s?xGgt݀œ5i А% ON캞m)r=F\XZW`4 \kExzy9|==W/8ٵ!4Wu.VkvWG޽zH;DOϟrs׿Gh@}ʙۖ4z;V ܽLhD27uy0nVq6<7 i$չ@8ƄPbHdsSU0q *PUٌ:! t+7BSgJǢgQQO._(yFr3JLU:ij>1L{>r](j*iL:qx.02.ii>5Κ;§+\a .e~Ƕ3q C;2)L=I3{3Mc؏[]Rp@5~#xFKnе(aPYf`pR<yEz'H(&Q-<$Qc\T 0f nX,TG-șk(:VD\YL2 p%h=zHŇJ9]d )*'2͛iLSqlhVkہc;X`sd1WRp޼|-)(LѓӹnT8)Dc1֢FLUiu`Ț(ƹG&$-}cQ3GkW]UPiGFY+!R.VE JiV gKw=gm]PD׊epkyuzQ38d5n i>`Oiͻ-exG3GNּ븾븺X;*wƞRcsl{1DLAwgKN3kJ>3]aœ4>wDHE8lN6cdGv=n|3֧'^|fQϹ<ױ"w;n||λw<~|b@~58q|[Ƙt"[;YylDZS0[W/d$Kkʼ3 '{V5W jKI!/0;uj?S޽ꖳ@}dAEıO8 f#߿e߶4kQPlN㝢߁G'~|g{OUNMU[i3j0{Ca%P 5W*䘸@iJf]bT)قw*J*Yf*l<.]?z,4(GdlvJ`=ism蜁Qӝ&-|okB b:Wb$CL?_2+|/ 1 uQpqhV]^] ǁ!ai*-)"A YEMC㨅FTk3)e&Gv${SE\v0B‰(f8QDBB oظi!v^t: #' nm}r8t}4f^!x]YyXWZjreJͭH0#S6&@@@Q6Ly^8=]e&W8̅s&m#c.&+ZtN%FLh] %F^:Py[1)- =Kcęe%DΌqn~ ߂sԜ6ĐUu5X81s 1Ӎ"ɊAEdܪғ4hWWhoNS)zY/+ˊ@n#yd(7BuP.I:Y#.+rin%ἰl*]^rzӏquߪ;e2C˗oGԍ|A»9%>qr䓏\-lG^!1͐~#.8q>SRdFbdqt$=C&wxӏ.EY4m*ֻJ!rPCsqrS9Ϟ?W[0tG~kS>{c5ó5?*&PsnԢ( hGF)'N81K@#;sл:Q+V@cB[鬨dPL${&O0j *LL7 %SG$4c(:iH1StV)9K1$!YPFHao.̆B)D(F!Zg~w`#cԕlS" ., ޔWFY,/Cqw{4$uѽ}YFkk$fAg,VO#gّBRB~rn\? EÔm"h8m+RkVmSƫ z㚺HGU$PY?0`R'#*qc<^ź JR=`SxNfXXNI.HEݰ\/iGVbVu8bĢ]m10(VprvVlYe%Oi BUլ]f+Yu\T2{}g?fϟ\ռ|snءM/lN/li@zryH~gl}tɶ|~G4`:rвyrqdx_pZZD?ԁ.RG+Arv{;칸'>{񘦪~ɟꟿv%3_4-`oŨ8)'MIOs\5iq pTTt6b0CmZxpFvޑKFZl َPsDdyrjgnZC{FE\Q'V93+3(͘yUqޚ}N{S"LJVt'X,8^I7WKL &0+9v c7qOJƬimK1=/fDTA4;Ixy>WqX*hZ/-'INJv'B6 {xyiLH0fjQ\yi~6NOԄdR{݊>-hnI ;#b~%aHa\X45'3N..899rCXSN -|ʈQ;L1HSՁ*}׾IQ%E*WC@ qQ(YSwTu#OZoNX6Ĕcgb'8,e=ᖧMHΫ)`7F<$9bqN7@ 71AQ2=S)EG^axC(,,kF˚j`*g*_HxT4oƶo۵ʙBeY.V%j *1FI|:8{9aHjAXqЍ1f_ݑcsr.lz#W^GTutk ~_8'O61qi{-4^Ba D9S*yyԕPy}fɊ{eMǗgus*:EMJ*Hx縼8%8=N2=?eZrAא̠KȎ:NkqUGJ˿w8\NwT}d{V(i?Ag} K}&ۗ 2AԀ1CC-wqQƶCO*#=O{/?W|t -~Ǘѵ{ Oߵnrv-1tC?2ZlŬ}w{8&rRﶜ9p<ݷ=cK Q{ղ&AJق5?1*TABlO Sغb|x3P0"r bW Bwy*P/jjC~$D]N ^H)c&G F"1enʍ5jG+$ OL ŔM^WT 3!e$'lP&{#H'L:ʘ'f8٫tkj ;Z>`{Ox֭oK6z:x}a-}g{o/\^U`lHż&32R>=beEKh{F%ix o>]dOHqD X9z[5^?yWٿ|`W\.W匣[o2{|9# 6,Yt FiJ$ c m`3V#a|ِ%G71?ͦg1P9Rin '9luϫrm[v<*gg 6Rl].5y+NX4FmTSx.) 4IҰOD%aw[NpJi.f!(#$8:7=sV ȌM*!z%*^0\m@{IA\&Iźźf64pp$)ΘM+ _Skz;!I(nF{Bumӱ4[ǫ-/O_ś099C7HǯďnO_[:lirm h}ۣAş=woqք,JǼt,jŵ/ܚ򕷏}+_|׏h{9h ڍўQq !$W% ,dZҠ21b.5,մmzM;b̭(G==a15cA#q6q 58흱UD?徐n9f "q>x5)"z{h4\"8&`Rq΍D&z8>Nl6Re!1hbm"5ưRy .% )X?QʋIZ"r|n 1O0t"J/74Ђx.ă\8Obu.F=$pO11 :3Nh3-̄ÐLE1dʓdFEd`2]POgdE# }?Rq񚸐"m-}37NnH4qU%UG/-O)*!SNf%q,I hA@]LYPR4(*f0$-YjtD,dl1]IJJ%x.ёO1.iB!},TQayy@GtI㜥\6w`92D¡ۓi8;Ysz^M&,]E^Վ&I:*yhzvmD8adhQn Η44Cۣ9vtbl2dXzj4XhiLL:7霨W}DS)U`ceeDD#>p\n;,fj#΂ >prz,,r>gܸq@j!Qr8_m_Ff,&GQ=/>?>w8 -~Tt]g?1kXx/!JyTMљ{J A#68`m{ʪ(KIv[YBk*R5޸}- g?C)C]i7)}sai,!I2;^1|yOO_+t&"7M㳎$/HLP:n!n0]l99pvp~tWX8 \0a$·9=5t" )un9>],W84z6-(TVH:D3ecim3FJfu%$j,F;ABEgF&!( q#zrt8# '\\,ٮ|ւ ?b0s2e6n~j>M{I k'sk! o -7!X|3,Q(P8bV3(Gr J˘GkM?pnAI(,ْ빶 8GÃuwdz[SLrHѵ yŴ(d(c&!s"Eg̙T9u<v] 4CJ)XV8"+cDCYOa/ܤ*J>9f^iF^Zձ@B+>E@lgL 8tJd,'M3YB*Pg< NJT"'Yړ=z3bS#I\v]$exh!)?n`rz9Ɗ/q\QWR.d|>U&*\6pj49u1j1+6J!bQ⭨UBsqw+J-$-IBJnjh l~Ew CouyFSpr󡮢NZa\|nݤ)x \Gxw$]$ˊuj4$I||| qSB7+rq*`ŏm{m "DnJ}C97۶h1>ʎ$GaQsxQiHL*&E' މf2=> 5iZ*dzZzk;XfCl !8GYad6u<yĽ5*Co|[ELyz٧<'<'#Odq*}yG>JlIdw`oR4 xV>gVIB]ggS\.[|\;2N!R;"a8#/HAsء*xs o$N恽yoƍUHplV5ey4cRfĐ%2KV9Ӫ89OGKf\^i^s)"w/MR,#1 [G%=LP|%m#6n+N7hAv"ڮFMYb8'&!I4()Pi a%~@k۱APLB=i^O^DϽ RAEnGEVRUvll"E}n%cH0 ̮U!Ҭ$\wjձ2SLF1lظzwf:T˜)RdZ ǚb 6DvH\[/(vEbx.NMCZhL:H:BxF/(ߍc0$]Xŀ$z`Y$ :|4<ApB‰Et ]:Ewq BSnt6VR;c)F$uYas(I|6Ek-^nvс*q\a{1c+ꊬ (*Xh[ wde:C+L.f dkLeG{TUfMjbxͦCBzIBg cw4ێ yځ)DyR2vNLN \rݸ8h,vxgA91҂4/iBb{-[ʺ&$V\'ѐ*EYh}#~g|W$&ew(JDaXz~$S 0 ԋT:~+;&q2O0XRRI]Xw<:7Xk4#뜘91 O`1/q^hV|}'q,IIM US;+z23B$[]o8[{=lNa\a;"JL:ہ|ɳT^/SEQk_W+9Ey>E$喳ۿ>W?cNN n[pS=S<5߾A%t]O{~_? @=6}w oxⳏy<}Ҭ:7>`$[$&c&Ϟq||19{ >\@Ѵ=g+ak-EEc^l1IxE?!M4W/_%{{L ]:0 . ? r/n,ދ_at뤴= ZL?yN׵6׎{;г *8T EVp/yꔏsrhہ7[\.7UN$4NJ4M]b֭C7ڷ w^%b#D J_A%[JrB2N$KwA5I*K$8 h{1/Dl$X sUOnTѶ *tE}HދLc$vΪwT~c\#Bk8s!ԁĦc D?g#A^ԁ\9 8K(/?BШ8((VNǺ&Z.\s`T%X;S)*sf!YGw(WY"Fg  x'{b (7* rAǙi9.q#AD8$s+HVj t^L("Ng҉֞1AH\Ԇ,O1&rҬ놝&K )ٜdRn!@ݮX/YmW\V7kx Kʲ 5 wqi!r![)v*Ҳ)S9ʺ0y yQdF"40N&dUEwKȮaR"mzfqFRF|B6f7&Zn{IX/ȊB\ +D׬͖z9mעbV4K%XK`VX\£/k޻ͷ[+/w~`yí{}okw8l6v pB–D9ν;|A9=dn8;=Ӈ|3x+o>z'ӂ|2Hyvqɓ/98g^ub98>JhClW[õk ^?zmnLy.ioɲ+Wwק=oe%Nfy=|k_<7nssiQA/,%LDύghCs^mGጬ\O"go,h^lA5ݯcQ -"LF *ik6NqP:~X"t{A _#*<QWql!oTzivv5{W+@bp"ҤTF9]k.hq Pnf*R+54)Hу6R$)|Ju=R'yt"ynHI@g(hC%c. K3fYbQ+FsQ<($ .0mߡnJy͘D7h eK՚oI$I1F1=(a{ BHɼFazvenZҼh:!˅w$M釆zq4#+%b, Fa(|/YYH,RgU'mZaR-6mZ>29/W=Hrg,)ƈE{ν7nWX_2AYUh(+1fDvBL2-HQcF(Xa  ։U)-]Y Y?i,bP:vû~3eF¿W-s;)ͲYZf)Im]= V>/V6~tI?җ/żJi7w䓧l/]y׏&SBFՖý ѧ}_7&[?{x m~G|o~xe8??g^l/'þ%SoYnI\Mz6%Zil#9klct[B1:U-ELꜽOϝSmsǴ(EUC*RcІkL PNg8j˛e=2Duq]n7uzkIfES'`gΙ9Es|fplM)yϘNJ2:d>}䣇'\?z˧a7|?? ͖=ܿWt{f`y 'gj&93l iVo* @^&t%8gr BEKd%ѱXs !G.G o`wAPr#:Vxp~`u;դ)`{wEXyCYBB%8N.iF+N_hj IDATL詴" դfh-:1gIܠHs\e7I C4MY5 h- aUURlkjE/ ُmRd~V]CvB^ͳ"S&5E^?WY/ݚ~uAiF}0#ISUCj|U]5ՒnFaQhtRpl>xs?yEEy[iPC;83S%>*>f@G!x$j;mN}%4$k;ůy;!f;zfzDSZ,Nj0[drefhr "dY$:Yѵ[k{u>||,yM2tVl K4Es|=ٳ%ܼǴ.sȨ${Kf*K!C+H3^iEX YUK޸ub1OGhqptDg~[o%|:_y睷y7YQd٬Vx/̓VAkVu努gb';vݛ|;ο]h+N^s~qI^'_ph7gO\ϝ׹q ^a]Hilvv$(}Sbx?Xf˦xyᓗܺ4ߛQxCNgSRLC`G.M]%ܽϫbuBi-ϖ>Ă$ygX6$0\~yIӬם$-CX7 ~I4=zKxIOk5+n^?bI=gYǿ}n:&UƳY-\)m; '/ gg3-bq0'_>?wz>씟}K^(1:ar>z VFb$Lq4uB&,E9rC0|ϫ µH^g,*{< 5Ur)2ˏJqZDq2 KB5xi-1wE(Dݓ.DPGyF\*%KbH=ұWE|nB*ZY/ezҐQëKQ.S('Қ\ށ~B Y,z4ГE*|\ GFG 6LRT_7j&~*MFW1iʳn[}/څ, ɰF{mj2ƀɢfS͚9] YJQ0y&tPah*D߮u6RdIpYc ѱ,ͅݮ2A#AۤdyFVdUJ4U=n:J=XSʲD'r+PJRhFr Ql7gW(f$.gfDa(Vq4BZ:ᢒ,Cm0ITS ]fa:9,۬O1*0W[V[xxL]__ Nږ$aL2@%,8x􂛇5j(A&uB ?&L_<ނ TyYo6h2LJQEjEdA44>Q?@1Piɤ.PZs|lPMjHWZEUs(30e fCY.;>w޼sfe9/Űd^XRT !c[9:c2- ::n丛p^H4gO?OO/?(!f7[.^>Ŀ^pu_zT=ێ|r9YV9.88\p?c 7W~Kz>gO>{MolV4~xq~8~׎x pu6}GG\p^q _;^0%Ւ(C/VDɋׄ?7;_`?ڵlzô.f:u1 'EU:Y6+l,/N&x?DTC^(Lc@B:nH|4MlzHsC lG-\^n҄9?{uƫWǴ,jng>_p ^҂żb |=}߼ ^o.٬[ u+ _:KzrraY<~i گ1jލ}~"e=.["rUӃr1Z%B!Sz,ł8rT X7(?K_ eAedcy[%BvհTn 4gn")'əۍdfip.fpBXWA`h-mR1O?PTEPڡq|rW\!A;=4R##$M.&UR,NPF%łr2^mFY\o&>v2΍]6;Zb,x< 8+ 4KeeCQp`oq}{KNY/{ { ٜ(Pfk7xr IhYeZ|4y]>PV7QL&4X譧tZF~3QT%tJslY2GkC IQ)Qn`}TEQ2!g;iC9?;, z^a( T3+εEŤLs4ydŪAsWlC\|v+tRazeH$I&!˝Wъ]szrB N"2PH:l6l-YN?XviZy.H cP8 ]vqLbB?E' =Ӻ Kej\C8A_V_A;h^JllȲ,qT3$Zm\&|w1S6@Y|~lއ?_1|q3M8؛8*y\ߛ7 >pZ8g{t>av'!v舞`)߸Ub:,S'~-)׋D[98ضd6s"eRgeJ 9nÃ}x >~-IVKLRM&$Ji3J/ :IȊ9.^ڶšfZgU7>i;|4xm??~O\?ڣ*軎<{}I+w{3۾\R=k}O@aҜP-=ݟgK%o/0ۦ"1A Oj4Jŵ?Dh~8S-#=|xQ ZN쉈JY>b( PkUJ*1U'X4w5{S*Sѭ%v&*BpAJ]Y y)MQwqS: 9cYqX*#rQ&,imYBOⅈ~v!YNƥ?`ɬ; MMRI@#?ĉR NExDi$N X8 MQ8=EYPVzl +R) <`=K0@mXs/%\Y'm(DhѺb4S !>6ghУhCߓ&%iY݀zBLpwֲ\XoEPAA'ꮕԶV _AyڡGGߜѪk:4(hf9ɔ&?;g)Bg&K%nB7٬2;h6B-DαYoIթ|QOv=ˤ03 Hl^RCJ P4CHjqCiE%f޾MoMFo8hzbٓG?QEJŔ}/_ t@U i<Z(1 ư4dR|zV1\VWh1b.E⹸˾^G(˂YϞe G$8~ lP,[CHu?9UC}4%ޟ>ٚ7/sPn[`>}Mr0X;)evxbQR'890 ż|͟=iVń*V???ԛ4[vgzZk}L$H@`OJ$Ֆ\9r3oph`eWUrT%; =ͼ=nWM@$2o{>{y$ ~Fjł1w8™j2TFT]*Yu|\tÝ +ݽG3mo(Otk OjqBʜ}'Cg$~fVLij\}5 `;AYVʜ0bWNCQ"y= T/c}}6,)xGf6_2[yN'?+)˚ Ko.^mM}6Z+66>f _WX_[m@l`:qn޼΅-0=b]fFTe:/(D9O swK'~L%6x\'GZ()HJzg[C>x Dʓ3Y;)D)L0q*rAT*DJTwԫ)W@m:ŪF4KZQ5UHJ$u8yKd4e=X-*'V.Q5'4#Melnѱa>]TUV<{h:diFU7p2;qxG։Tm U^;Q#VFqm`}QAVmm|6'xEX=ڪ%zR 8=ѱ!`m]ږ;-~c0׊ kCPچ1!Eaۆд4bn- ںi(|rG|͆hGKFW_5?.kںjmY. ^N &Y4Rb_8eW4 Gl YѽCNW<{: CX(TH*8TmR4hpvmnz)uUP5USP>)Vx:Y/&FsW]JWѺt*].i#Xqn-g7OX _=`Z-t=r?ã)1;;NNy n;v rOƏ~s.|$…9h߹&_(:qRvykQgssqQc ~ǟ|yE6F}.]goQ/ɧw9:"t[ %LtZF!ˆWZ>Rg$ӣt[-J/8XEuJ1wiMazVCr]`OɳF%=P^( D[㌴/TM%eYFiyn m5\To P9l0q_i#7: tT2!ILy84xi5Zm#CM7QVaU(1.ώOaW1-!Zaui"2G@st8 I?isN.Z۽u SLZ:;kPYUT ŴĆ(IYJh-uX ծ!H)Di-mS]Г)*xzkCE SBךa(QQLkSNYp, IDATbP삘UGt õEo-ih9>8*v`8Լ]? |oya׷H` {lom5dww=U-ˢ&6g 's~/¶\@NgZ ,Eg%բPAۈ1hp hEgcN*Zk)vMC ax,<<)2h$霣XL&%'GW^8OfFg3oB(eCYu^:Р֫;|˯w)'l|k_ś7!}z7[/_}+/p[F9vx:RWsXMIׯ_s7y7quP _⠤i/Tق_᭷d}sW.238flsE E[3 ~hKVcu8˹x"Q$@ǜ.<>8xFI7qOQ!pɢ֐^8tɌ %v֩1!NɇC:sxk99QՎe)֢)j4efCkLZ}ck-YO("9<>dVbI@ᒄyxzx$y%id*R<1@ !m#4V.xy+ ,Ei)ʂ&/gwr1]T,+ˣS޼uKlmo)0(mRUN33ZS9e(:t71gm#=tȢ ̗ ,LTMKj&ӂ@wg M6Drj NDcCSl28EuyV'QGRKaZ [k!jE[ 1g>~ʅs GdH*u71fh|r!xp<ߢx~o  F\|=e D-DX%e45Gԕek0r ^ӧ?k'xyx>w(fzr¯? N^xy/gw'S Oߧ o~Ws|z]OOZ,Skƶ 9UUG2,t:w`.^WosqktV'𓻜w.w{#jrŵkxjQG}拖N-Q[oė2ӊ}{S%uբl&("B+4LW_%DmA{YTxOlxYZɄ#ay@(cx̟DqLd Жvx_98hݾ'O[o꫷ran\u*Ό Ġچ{N" KCa##s3o5z<>9<ctFoXQ8Q%kqN*&#JIϬSŖv{h/>gI@pJq+& 6ByE uMg .ϐϬ:@4ZE]Pu%ğ38-1cӪ~Ff*\w?w *DP@Ƽ @("* Q|҉((mD 5"!#*( q~׆oGdylg6@iM,ia?cc}"Zm -Yu|vS!ZT<=ºjݬ*ĉ$B'/m*0Q@iLi&%oz=Mh[O&, ZSt5fETZV/ !H{9*$& h#7!8 $S! \>Hj0JZ'nr̅TwU0 b'*9,?\A'Ҕ$KYE+4"Mb8D)IH>LŘTZ,߄p^1ڐd (Twyб\tLX:MKSئµ +,#icH"%L3B^WH'w%w.R%JqU.nweyFζ~Nf=67FlF]Иz\dV3_ܸFq<.k_捋|{»=d.?oŶr$M8HMjJa4Y?a~Bט~Cc_C[ ayA/[ek12^doDyG1Fw.39|ѓ<|P҅* uyWX+_KHLh%TDPJ ,ˊ'Lgs@Q.\9m>>ni͝{,%'Gn?>{{/koN|v6}w;Ԗbx{d7^ֈ]`LQY9) ƤDqRrdky)چO.}ts z|ͯ ܾsLf ŜxktjhO?oί>b,@[;JRVMw@XkL2՗re)|IcYKB[zQg5HGa7(Ξ#^EHo?+*/ٵ pf: \z2_an:m6h8 3[OpA]Ǩ2Z;N|tvi!A-!V8r#?_a+LT|T J ΢?c5ķ- bf>[⛆h08>8`Y,Hk[$O<弁DA/#lܹ@Z[ᐺ(q9R%*f(7đFvCGX.$z*t8e2okIG<(H+ϖ0Y0̫7D)D>e-iZ'뼭`֞>Ee=CU9LlnWѤa9;#n?{̿{6G9TN3לp7^Û-q$rt-?S-vLB$Nb40V-&l1MېRkkLk zi=ʱ,IzyBXP367,4:OdA7_ɉT5ʶ;=^:TSrnsqgV?fv|lA;\8K#hOXڦMj\dRN'%MYQ   궡b 1i3sSaMeފyYJɵҭWsjCݴYa$qe+juZ 0@8,5hl +W{"@ya4 J:gwy_elrdZ}n2y~Ix)uUe\sMф# 'GNKj)dN/|_W% m[q4+9S9mqn{͍ł}.唋*h8'rĐf$5g@z1#c4#WE1Iji[K[[ˊ٬)?>Kd`''K07F>.\`}c''SNOU6G~nNv%v6<}d!/xsv(xК}549,9:¹ /]t̝G{(6x/bdWxw4`{Yq=m Uh[bu]1 8>^pz2GK9q)Oykw~ƢE@+9Te-i@/e)f~Y ֱ,Kـ͍>XX7^[FY8CTQgL3 KJiIJhl 4i[9(1hhj2Y?'O"810 Uk8o-:fgw hk^/\@sxp7_agk$I}g~rKr*ühZnmېD;;ԭ?O>{ȅ+bX"xILzxtֹ>c7.fܽM$4\qs4UO=P'iF? M2rmJ d,,}4%z5>Xݴrt<==N'}G}^%F-<ǘ0y7yln uǿ -x:G=J% e>>_}5{" p5e/Kn]px2a2ʢ2Cv99>nZ>'*(h*X(ײXVS6 [o_o>侤uJ5)rsXR%Өsg,ଽy辜ƮQf%yJG(;o Ȝxo 8 !tNPPAT^{HKPLYBW7i+%oJQ/48geU"4)qJ4I/VTDM"ʢ+Q}$w`!J3)a%M$90t&w:ZG0!&ˆ̋bk TcI!INД2d0xdgqXMGu*b-]42tPRIhõ TgʻǶ%M3g y.:4>Dr tÙ QhHMNRݠ.VR]&Z>< O9LR(m+5I\.uEh-M#|ZP0tD5~nSmӰ`׬=I( UuJٮ\wEKUgvöM"'IXIi!@pwf׏ IDAT(Z{>?;x޸O<l02\94xqw?+d2WEIk$&݉LDS5,e QaJQ\6}-@H^NoCQ<Ͽix^ d4`MgJ ۣvië@8*OY,&3ʲŵ2iƚu\K]̗%F+%1 <8"ō!:eAQ>8_cLUp=.\a}V TSyW^ū_7_" wqy_pQ|Qk╋u;O$6p/Cʲaf6+`q>1?;hYf2s%_?O< Mk/3ܿ>: HZ҄$ˈ,KU].lvid4q+阦ђG:.YLFe\֗o$坏w>arx c賻DqlQ-$j"24Z5' ܳ#3m+GY4XkzyxYXT`">}x =Ōr1#OS41{3/mɬh(ZQcmxxZp8"YɼbmKO /O6Ӷ%r@mg&Tx h@~ $^ve,g]G&|-mk)n?Mxy޼uA_p44 ebL`"VgU\  "l\Ept8/+:)=~eRZ!vBERŠҮcR m[ JՂ5Za$%0BqwbZFhv7f gt2q*roO?ijQw8k(5 [amOHSC2H*#2ypVE ڝ͈;frFs5lE;XIB Q1\['OR|\&FxM7(ΰMgjNjuU+R >(Dk"pMs9l|:X. 3 ۣZj|ە]*M~gŔ@pc *B(i]KPNV 4.˦u̗US'M#HSLilH`&Ph%0gI%5iVeYsX̦,kQZ"6GҽkwhjG1M֐4ə/" s OQ*,^F۴,q%iBst8(*zy.#?VI񦴶 \K7$9Ƶ Lg3BQ/b{Gh:DO փ(jrR(ꪢu5(LD&'$RJ9YG$X穪[h[bܒ_>% Ofd_>_ӢރCk[|_Xgl8NQXlvy=6wtms=>}ӣb-~z{3[,A>/iᐼe1?p){{O( X"IR6,KN'sfjjđέ]2qlHYFGh꒣&'34e00yt׿ k:f1[wtý<{ʢ\bۿ`29bʭxWxѼx^2Hcbm^ /=t2DQA6 msK4E exxV,ƣ!"[0Khʒ Uk,essHpu%E`Y8!3泊ppt*ȗR8.l|z) heŬ$pJ{Q[Nxz8Sʺfmq%6G%'45s`8,*dDX(Z9<2[ D{ڦ-}OW6Yɣq֋ض|/^/^bQMqZwc:⊟FD&p܀a.jZdI. V&Qd0J(MG$IQiEek)b\ aZ%^1yvSur9'C )$òXm,׆/|iem0Lx!,aș!''t'שJHQ2NSU{/@>ϳ,l/S)#u rjdEYd'Yߥu-H~Zs3h|BqC{ʪ( ltRROK-r.m D8d09P\d:f[oТ?(ZU4MC5;{eMh!AUW;ESJXVK)c1 B,85ZDƪ S4XmsQ cR%;{L3H ,9;=aGOSD/Pn3d$oPmp2Q#_lZ ҇p:t)%{i߯ʂhbabjƏr'/7\J"vdv9C.YE/PJmM^ϢpHQYY 'FOyVa\Hd.(h$8e2!4eKמ{OT|B;h;k oq^սpOS/f:xttsb~nŲGkC7&6+'k T.@SwJ9Bcl&Wk|c(kJ[lD-P:&z=4+ ^%kw C0xVH\>;K|?wwxq9vKſ+]կ}|h>kWP𑗟#/bZ7,>/>\l6w?3ti( ׾5"O|)=J0F…( +ReqCV6^vvwŨzC]ueG?vT. :ʴ<%1(JKYVTՄm7tmGU\z@e5s?7^`yŢS6}j1v1G;V۵4UU.޻dt#{wrLNlNohҔ$=1<3y<{:'ˎNji wXu@Y-P֢`LY/ל/6l!dN@'GS*Jvr)QG!!Ƅ.qB^Qy62pК]tBB&j+DFy"N_ra1/N p)4UBU):a QlʦXٙ6V5/Wܾ~d t|yu)Dke udRzxīxl˟8ѲRJJgP?DY"8-9:]ۏ c"r}1fɵ[CFaayCEDMľ_2M)[yyճSy)0JGç^'_z{Yvާ[/E?ӟ|ISз=C?"T4Mpu'k>?I!w<Nɻodp'i%W/֖cP,-Ԋ)& D:_;2ݾ/__Ww_ڷW_nsB6-n?5Դ,Oy'QO"ƀeقhmfTUъɴ◿2?sO~/}/bZNNBV"/ 't5{ɄźͰu C1pI4)M]68Y:BSdgVzlÝǒcv!R A1Dͽܹ &uM]OJe!L88N-4^bH$qLJjt:GK+kц(!%bΥR U"{{eBRb6#4%L*CY(c( J)w:.5|zi6˞~W .q]Gf]RSS|˗.|TuOuݠ+I^lw^;8YpشRW!IAGwX*1Z _*0\TnX6CdE\Ҹpx|DB-g"aR{F]s*HZȈ EbM䉱'Ljb|袠0oEv3)Dр1 E3rLUd;D'jr'wΤxdXd@KA:-"b\Xϖ4]ٔnx;8B c@@)&)ƑɴζeJa(q8ײMZaheRB֠D=+ma@ç#cFӵi2Vb2첪L&; KL~F"vpLyS &"EֲYn)k%: c C3t *у Db|Lm(cb9TX|7OKD Dyf$F2 ׎0 .崐E9YH|'Q U^ D786LF.ٝMIѳZuBj5S]hR^i%9{>gO(eS3POApAtl6떳uǵ W. M c*-źdͣ5 K;Fl{GU sպ|⍷ޢ4w߻K%(('cdSdL2b @E6goN_?û?D'o֋# ks\@aSPD^&-}eg7173ILkMKla>vL%Z90տ(fLWأc]֯U7](ˊYw|;<|=~3c2OS.Of!ǏFNW(SǼxݻ]<:|)RIESH9g{EU5Z}S?h9u:2Bm>`GXek2dBT(qc=ZIS;L # qouf]ֳ3W~9r~87r|wU~:/4nG oOxuBGCo2+O̭o}UrTIr[=P`tč>sU )xWGvf57r.'G:G>)G ~}3U.0:H`ˆi]qi6eo3nδ)WgJҠuryegw)KK3k Aqr,zm|SO\tdD)IK!)\́#(UgVbĔXs$ ZYrSRHm<9gg' A᜗ౕ*s"): 2qk@[KRYVd-F+b "5UR-[F_!3NBq &D-E5IEBށƘy0T^=|2t(lL$Lł4h*J#\yL CULt)u]f|ELUI0kANLG`?غ@| "bj@˞4m瓑%@RO{w݃} uYRbh{vf {آ$*ӌDs0û=pKp)45%}̦D9-'UvV$1O1eU tHIF+oZ\w34.)Ul-Tor Mra 9fe֊aN(ʊI3ŸY$MU  IDATih^8#[Joޝo/Hs%Љhf![3h;9nÇ|[p.o/><=Eˣ#+iµ7)u[l0Dp>^wxx <>Zq|zVSC T& ɒb ,06bʮG_䋿Oɾv{ȷ(5_Vnt][k%H#m;ݒg*sI0GH90fG> *r~by̾]nݾׯ] ^xc<[|_7o{m7DSy%>S?|-yݴ\zwqmA, ?ۜѩ-U MK"QvcJ (.p|f;ƠQ(S].x9xN>YbAYE2f|M+~t~rrM=DtvD)CUm)R)-ŏuO afIKtnKVc^b`1|kM9Y,6vhc|"(NnAS7>bl Ϥ1:*(mGl`lG5EQ|{'C5U]HGggF'J mBL l~`0!MEDȎ 1Ia)bl#Ǽʦ6+S(uN&䩮ʫY 0߫K뎡KT"EW/ES2x74%~Đheyۈgp5nsF P9eaHRNJuEĐBu=1 d LF IBe}GJ1Jъh/gD Qd&u|ExE~f^nEL!L'5)D'\1մ8hߠҷ-I<O_A|㷨߸ú(ˊM7^zNNij854 V{'o*5Vir4uIUr ޏ8:?0xn@GKU:]K ;P*"\Pk|ѫ?;o‹xꩧۻL@Qa%#)9*k0ƍ'N*^7.Ta%x71yx;zo_ [a~iz:!o3N8[,C%9EQ剨EQS»[ÀF`QV Ie X+7Rz7ym@#su}Ǧ;'ƁMdtLMV/8Y,zR7f n) SXtQs|v Xiíó=Nj/wO~MH# U찳w-.ӳs]P0U%JC+VzoGo?d7N*;b򴚔؝U(m8]\LhaGDOR1'&E=Q 1DУD,)Ei Ӫ*.! *oٛ\z?:|js}}c cO楢*`ҌˊI٪c:kEz2  Him.J&5* |dzMɼ2tCVOeK)1zwc,ںZ\(#@$1Xx<{\ qE[\ъgPB%ʢ}= @9cH)k:OLjr]UO2sGٮP:ahxeWrg (|n.Z #)2`d|BEz:=Y3r^ QDaFƐ(' !BD6IJ gc)|GpJY1BՑK;0thRi 1EAPZ8q$),%mʵk5d!nt9 XKg 9͇3)+t$.7e(f3sʦ Qi"հQ4M0sLPs·=}KJ[EHg6)FQ7 $/0]$T!؁lTA͆:*WF.CV-k]ȷm@:[cKh;5Cp,[BEf hEyG! If* J΋g\eK!ud1!rzq]$(gVCMKqiC ƶCX|;ݷg7?~KמFaٝ֔"BC4e`ZEԞ*#h ?Yw<~|')6Sb>/ e]Ud~`7'oy sgz @;LU{pʚ̻C^x?UO'n=wڵ}^dgJZ~urNw+' ԢPԍ6ͿZw>UQVZ*h)a"ZH] -.Hr ? ??thW?&t<:h*)z]e.DU+p1zǸYyMz}~9?s?+zhk?~G'w&TEd:7_K/sQ5 ~K ]h1}v}w&n$f1)f!*FEšPt} #ʖJ&<1x~LƖŚ{gnD[K@1%̘ o;AʹwzƕADnĕ9'+'hźj4.DIN7ctSHFo=Iiہ;Gx*=y~ج{v;[ eҢLvv(D8>_Kiٛ|W~jv@k>JCr W'ԥe mXp앟#l?3RQSCPO "!%4ryQÄ!Zzn8c(6rqlzGQ|;ywyFٟy5w}GŇ7@ k|pȞ/V0JK0 LJ6_jP)4[ UBuI[Q6Z{f506D8b>UxnHtCcX._1k8Obh[Bjʪ–)0^N{Gy7"޽v8ڭؽ4gxOf;\DnߺM]Ti lQ ߾ɼ(8>(jdţH8-cn:qHYkpnCHⴡM72m > H>c,QD9/jiv.r0kؙہǏqH31.7u34ZQ%QYHr&0C^'%׽R8d\l0yKtqz_:gV2`QrFi2~psjb2tv)!+%7"{YF~?3VzdLeƑ.J[Mm `%Vk,N.覮8=?0\Bb)FEa%Ęg>!@Y%57cj~[Ghl-4$&I0JÊ7!G fR*Cr)y*RLkuBFTL*.18L) 4@ʒn#>tF\21IQO'l+nJ:ↁ.QuG* IZ <'y+[ kB|Q┲ޅ\ WD䐨ȼ %xaY7FRΡ!J}O{H) .&D$ OSL,Oќ|R6zgrWֿdQQT" Gk 1R`\1? QFZI5pOҍ[ضxtx;w&*FLgS1Q˓{r`7>6nF_~GLꚦ(ܺ4IJن#BbMbWQت qyeX\ޛR/Qh /{81o_6]K3ݙ35U5/7(m ﻰ7CGa3%F#7h0V+tKҁ(?Z S⪴U)iႲ#8Nr?(-Q#g-+{ @7 L[}IG>V99gް.,.%KrUQU eYqv 'y]G۶Ҝ9t5ⳟi~>B=?[1*J9EO䌶mT hMYXUO_ -HC&CbS>@ H\T»,JB׭K]XwCXƁ;(D!ADŽ0P8OKՊ;NN6W^aoj2,ƈ%Y`23rNp5ZSEp1{'|l97ٝ7cdkC]FŌAnHs[ (IPIڎK~J] y|'89?{?#ꄓ.SD-F(Xm}*׿ T4)@Gry^:E$vat4rb7&k4)Ɗ =@11k͕rU4~YSQ8΋^i[f* 0 ՊV2њ)=:8[4֣B* *al5)H6 SHib1m:Cd=gT"HeW#ѲJV.`t6vI{;:R"y!ڂՒ&O]ĂMĵ=DOQWTu3R}f)ptIlߥޱ"*WjIg&꒢[F;wBn5](L?8)C@a) CQZN8* q")14f3vdZJ~sBѢy"=\'%є&i+rE2⃘xɀVIk|-#0T/t1VZ]@WR%/TAgfGE?+"rRt k.Q'O}|(ckz8o&& 9UXѝX-oIޏ]8]/9r ~?Y +{#o33obbԂB-ٽ,;Ú=^{>?~mRӷx?EYV];) 4L0Q5%)|gիWϦptr|w+kW/3Zӷ?oY/@ʪBQ\ti0V2)(t黎F)  $E :FjCH9'"iS1 -0a<#CAfZhmp1cQUr[u V!iapg;wve:M hꦡ*زT=cODvplJ;xG sm C}z?)K.Eaxen^AG~XEMCPQ t 1a\4!)*%GN)b$D\fz3 0Tւ9V{PcU$Oņy G5! ˁŦɂ">9j(XޝDeW#]'+:㕒)!UXIIn2mezw!  $x4UQ3!ێ §>iٜnJuwzO/W9>p|8HsB@,0d3 Z"dէH{燯Ѯ!E]Kw~#l){[ nя|"1-Ǐ٬7-؜̶xM- sL'Sz-z- R[W4("2R͖e}oNoDRI߸ɟE.[XHf}I;HVK=ֳ̹?^ь}9`ox{yϸ{VT!|g\\\0[Hz (MBގ/m >CJ|K}{EgjBNڒEytwżxsI1#E7QhLe4Ĝ=fn|wǟ巿yU% fh LYʁXeޣ@*I6Ga IDATV 1bs$6 _Q'_qL]솀N2BN|'/ !pxp˳K~dHsĞ!(!EbTĐ(|7M{ F>ɭszAs"BkM@L; f>M&^& FFiL5&Q C&02.M3Ç=U[ ڠg3\v] ,fXgxa1Q5 *-<(C%S5ҥKS}$б'Ę||Ya|hZKBq'ԫ9s8leQ5PDSD^*isYQSZ mY[YtxKU5na[%%05pJݴ meKʒ^Wk]SEl/F| "~c5 5F p%eރbo}F"zOH: mk+|ybwKƾUZb)`+fuHA\2U,Np͌}׋{aIr'@e:ۣZ̘c Sq{B~u;]ӷW;' ݻ' aG?)i*&VyvŪ*cRd*^ePNIrUl7([;kѮfQ*spptkEiL :| 7_o#...M̕LLSU,! e2 n1o<~=pp  GO9uʝxzBLuŝ{HqdyrX,"f8o^|~''%J'Mƾg8J<ȯR.nŐtL _Ee ZA |+ ~U77sϽ毺/U2 ][kzAh5nhڦԢy"!'Oy3'jIfߏ<,ϾHJGB?{HW%_4h錶v<{bS (. CY#jGԵ`>7TFӗC c4,j;89YP<-!frIrlbw(P$ +c300x*`q|9(T1XyCdD4sz¢yF@1%Rl`\Y#:*wZ0 s"GJ4XpPI#I1IigOazJpV1OIf -$HpT"דÊJ2;Ų$˜'y*mid&{'nĘdr1=˚Y@M:\# Bas9GF\ʰ;1MCȑHfN ,K129.A52Mw=8Bd0BstHQA |?k*vަΊsJ))&a$EomUĞ=1D|腴RILV9Im-nǁt,UbW2 }s.&JZ`CkeM$pM)OV)3uD˥d1a^2L0 Ze\N^c,zkGcHKz(lbfʚRu@L6Tt_G5 ߏ JІQƁO*lʆ@ ~k#)0l@UUl !=JOx7.0v,"*46S;A|iWQҌ0<&A2-YfryȢX6 ?JEblQ_?og`a25hIRV vF5~+tIT"*V$696/?嫧z;—{1Z\>rt|Ľwif =ݎ'~‡|̛7WѮF kq" :s"k+Ƙv2}/.K*P[̨*+h*ìvP&Iw,3d7%/Ŷ>ۜ"sr|JK93xʢ#}EW'6JqzXQY JnX^cp]7.lWߞSx]V*1[NZ)1q458Fh4' 6G+fx/~?GwxCǟ0x1|þaiDkW($]O4c ݞqkSӹ|Y+W)" 0T~ DM$eYËrtk20@r %Y8S` un]jb>GJtb%$ 1_]2 med2>fF˚vQ-!%v}Ͼ1hRҧ"D7f$TqDu].9{[5:8!#'#uUrWUܽ=wEd>Opqq#_wd5r|0I&( ?B^υ2yKD5iBfsdE .੍'+îB( YP7aV;= ϟ$eiB S\G9t]C"@-9 (BJ҄o֞nǮ뱕 cgiTNE*ٌbq)e%&s./7I3TQB) C10fdCgr&A}ڧ9X:zrFhݤW}*c[-BA3/xez3O:j CFs/{AO7 M:j&Vµ:ڑ\HB'(E/FBhmK:3bv8ߒQ8 G1M*YVYFDE],HA=_^s +XP-9mGΑQƐ"=<&+=aUUc]E]52|kyKuyVPih>~"XU9LT7(V=H6%BK*ϬT- Z1E|?265ޏتƸeĐs TZ\;1#̸C`״!LjN fϮhJlֲPf\~-q f<9y^υЂƩ(? 1^_R/fdϴfLHF1cCA[9OGǤ\",疺4mF꺥YX.Z^?PdH9ˆSȚ!DL/Ǟ~1AcZ\-%[ G^|21lN*#qE)t܈D3)3F)u7eZjSxPD&4mY=Y2 jh(%1 rl% DŜbK{/1F!W^) kZ_v>``#]KU]v>P)d9e{۷Oxc?T./Z;=mWWOO>{O OX1 RC32 m`[ d嬹uPq|qvѕ?MDqi2uc8\-qrK"D! !ٳW<O _~0:@`Cfva$'0CU"y(Q2*5SӴ̕4+m9N1 !12;xZC;k0];50È Պމ,XqD7m}10;8`:,=a|O75*E۷6jaO3)3nG>qq9 _|A9GG2\}M|?p{gKrsXM&CA54N[?>kq@&S7v(HJrHHWwOx.XmC6]9C = A%~@V!!/ӎ3T3gl=1J1E#]=1Q*Ϟ><}c%q A |NN5͚ǟm)8?G_ѽ#?+ě ZoW k9cs[,V y;we1j$AeYSVؖZ6?!h-vS2|O^_j"Ƚw}`y{U7tQX'I6i'59>W{Tj$*@R' ?lt.'_9S@r5~]jޭsk~ş، s]W߻K7'dٳ6ԻA92擳K (ŔNZА)F1Iȴ&&d[(I1XR74)kJ*Ey3, kg%rճ[F96n. UklQi-НOIӺf^8%Z*q ȔM? &*D_n`%hSJ%r @n**Ŗp 4b'IxE~7$)4~ gZA# " )ǣ@5q H"zO ]$f%v1tlH9!:lܜ "MgJXnʜ$1OS+$X Ucߟ3AeRzP}*5;Be*XHVJD\iufG_[ŌجHn8sĔ @zl{ϛ .&(mjLҬ}8*ޕAg uZa”DF剚-Duu9)b.3RJNjZZ(8:J F+j}]Mi; b6!2SX¸2% QWY6nZh+XWUAn$xV%AX_zicPFZ Xgx)W?}'?~[_S&vj'3Y0c!9^vxul>j߳<gw&KYTt/{|JbaTʂad6/jˬH׏d,ߕsV! nhR:;>nqc7QBzC̜ov Wo.xufӁxx!IܻU%zbx$hJmN <(F,L:*jj4a ( )W0ZfZ>"BNnA[ 4YKn TT,*L)tdW heQu=tYm4Iev(+o<=K'E2"jDfJl ?7ub`(KLլ1|L hJI4~4)KGx!1.6{]"fhIbQN @ &(麗HT'XiĈ _6& YF\ f /]29&$+Kz#'"%\Ş>:vFնRYCE 10t^4.3_P{n&dɑPe`q\*KhRnK;/ۉ$G&,fKZRe@ޝ)-A>̓8brPq[M>&/kcUPU9&1q"̠C`eA7%ATD<)ny|ͩM+A~` =Iu|;ʉ_X`^)9:}c9wOx _o}]8$ HSN>ki*ftY {B+M=;b=JBn UUӏՎ~wQ! 4<1K pedQ`Y+Y}l\!֢ݫZ6{Ba|{ϯ2ZdrIiqJI3okokuΙ7/_o^qSKĂEk'Zl2/qmɭCrt=ubJV/Wx ? "-Й. b:J W[ 6R]G:#J-Zk65PHLmҚßG-ہyc"и/ 33u19 XF0[Ma^״FnX Z0.ZBabKc1ohBLʛGM]9*cY9kŮie>=Bw"*]A՚<]}-GIFIIۆ$l@D?#pN3lw hb dl"3Me }!mJQY*iKG3͎aΈ*0QГh'|V杘Aε׎I5ӟe鶒>%IĒp}$G.T,;^JInRʉCyX3ET*r򚶭9.*Y}!irȒSb.bLמ(Q-gL ,$JX-~ifg ጇ_M}㏱J[>3V[+">4RW9n5~Oܾ}Oy5)ݼ,ٜ֮x5/^EkM,mmX-jwK[LJ-bZ|%8{RWJ/mm)ζw{'S9S?~84ƮL^+ x~!~8"17/˟۸a"rŲɅ@_ghk ^(Rb_B'>sS߹bcr~yQr_~>0:6ww>DxEm5~qv!1'_|'NycV|<~/;yGoU| -<Fm'yfK'bȜ.Zg,4v?5Si<}&%M4tj vĵ[ܹ}OF%~R,+hF3o+#=1 W[? {pɇ]1(kw$G+EӶ|+qJhtYGLƙ\" XEVe?H":Y$dr1.]HHq #b\Hwٕ1I^ D($J (*-S1R:IJĵ>))ʴ#Ei2Zit+.(E S:}C+M%S k{}F5wq,(T\v2Vw#,Z9J&QbdVeux %C :՜a64sքAn$kKɖ $'JhgQ֒Ծ/Hee!nnj4>*651xjE~KfJ\U1vj hg3f9 cD7 JN;P8R|!]H R2b MhPT(<*maӪT(U&v&/Q M[CVlA6儊:ErsNB4e I9-'yj_2P*Z]ksue, cct^*QqQ-j/п=4}ɒ&r6-SV4j+ڲܹ}|3zNn~'B35^5ܽ{ld hQ+Vdn_jXjW*M GB:S9b^GśjOqSpfdz~X8ؓ]Te4C\ |=Ȯ|Dwg^ka5H~`~,tJӹmI?'Oۏ'x{v+bj1f<=*a6ϛ={ѻF=%GGGֲjoڪgٚ#fI8dtR4I%I RF$.yrjI12@me 6E]7-@.;Ao@m U :U !i>zzۋ-_CۂiJjbamw:͙ ʲo'!į309)vf1|*!X5UAZ%,Keu^5Wt0=ex#QCFB(DseU,ٖ>ĦL\IeF#yQ 1iiI.`DJ@3M͘3J!9([Ь ]{[D;AcF^vS̪}dwl0)=$26(n;r2!S/>QQەgHa JaXBhc9iVN(~$@ȑ4FhpY*TXz]sbVSWa̅<,_vurZ$DA3o88d`KknQH2}%*)+M =J- rce[} JIɄ\gE\\8UV ߣsBf@Ӏ7"C D TnkSN7sqM[h )9Z%^ eb̥@%ɢhT.nD*"X6N%N5<1ﷱaQht<{WyNp>'|{%8>f|/ytm8D~@)b9#%o5Nf'xR-Fe:aVG]LGNn\c/NʪHP| x0] )FpPu"gab>N꜄Z69 $zSJ\3YTRiUI,fl87SY+&*EJ"Rs'4ku|JgZ:4xa:P 9yD _ I$*o$!7g"#(rوRI~IMDR,A2 dJ%YN!/Q(in.Rk"]J cE[a\Mq .;3Ӵ3sJyz4jVǀ$M 1^oIW[X&]CU/猽'Q2T6"Lum$HsMU^3YQ+_Z$ ُ=͆Cqh+ c.V[ԮftoZ'3aѭ/$޴+BI[5m Q}Y@NR #@n \jK1BELD ,9@f){YB 1')e)E9=p@kQ= \-I>UB2Ev%ۡQ"ժ ESтC:埉p")IMYB$(aT2[h#VM%sՄ(SB:#!IHXe! A}lfjKu\]]G?yJvYo\S8h}9' fVͧԵDysŦxtw;9:8`V\79Y^DdCjO?m5o߾Ѷہ/u'K3 )RkEӔr0\=}޽#f\pt}Zj+|ȿ*΢^GßT7]QZR~ܻ̚wbV _V6Oӧwxtw}zȼMxvrѲrޡj4ϯP+*gY.T7#vG=_#mSq)x n#r?!;jqý k ޜm2XP)2hːu˺. VHVH2axL x#: ( ݖĊVfAv#&f˶]}osiR%V$9We /JʅJʉ$K)IvwrDT*V<k9[U^+Q$%^@2\ګAᕓA λv >?$P4t?yNk> 0$((+- SaNN>eɩt:-*gTt-TM$UFREi BK{$EJ))Ǡ61-Nـ)ҤQG$S^4ު絖dh(A¾ӒHa(c!8\i Ir&@'ǖіh=εJ|JZH rsm.y(u ޷1de+FDa`{Y,,V"3)G}[{:^"W!ڈ^I!_Ih85 bkÙFjZ_1V ku4C\7EX}{|_w '7ޑRŢ#L;Ág|W]b$KʾdmP?~OfIxqo>₟S>9;ݞ~i[YBZD0b0JZ8OD2ȝA{?pi5ij}+7>[s%~Ow9_GZr^5yć?kD?GÄ5z`SmG|{~5ah+T)39攰JZE!AUHfaǥ1Z0duNA}{蒘&E@nJKvE/}-]j P0GƢkBt+]j1 LMKf00 ᔨJP]X9|㜘"yJ$4(.:aF+ 9bU&%0W~TJ0uX\=YljdGڥc$(qcjEXw@;~ÁBfWL} )ŷkTJcЂ$a%$E5gd֙Վ{tK<]^/^s#juQ#Tx5P= ,{rW>!j8GvkBڲ^Ym_,g8閞;B,q5^> ^JɍbF)ժi!&|ӲZ]Ck9'\YX]a͒펻kJYb&L N>| O~G6(ضk=9]wջ|5E{h!'ͺe&nnn_Z3M1F)) Y mY# чflFsxse{p=!DL|8{!Pb[Ղ g̷_{?^4PiPshx6[$Jt]=瘙FQyv7́/b~wO?~6  IDATy˟쫗#XMdqJFl %sB8դWm~rS` uJlE~:"bd(R:)Teo)K'pr}PByZ \D丄pܦ JTX~ Fq%%ZЉ`~ 03̑C"vj0F1a(i`uDFq6rwnB%DLA\p!`3!3GiZĖ6k2Y `02큣]+hG kRGǓ6o?)(%٩db0* t{sM T]༠X:Zc)uG<kiy&ňk3mY3HT4ӌ^Vn_ R\De+cv!yJ2@m0J6\RMTc~ɗ"ۚA]K W g_{_Vˆi1VSi08)x1~KֱX#B|ۿ?w7/*)10ƠwJ1(R޿aిc*ؿz͎kW+̣K.6l_ް;$aa,)0޼zՅp:ˆ31bq+R9RL Ter~"<){!zǗϯ9 /[o~'? xqbՑSd:铧l{t%]}W\^iZC*0g^=W?{sK]\9,iCxpٱZ(&=?︺\"0" R`8 /`5t]w yf")v{sX,d8=։ h%.fow0V+/6&Xig7Q Zs[CTCʄ0t )д{JzJsį6XqN* Lb.*9װWC",NoR!R2 CH:r{bZgɲ\x..6 O\]mXZ-UĢcO@ g3гX4\b&8!g5aΌsfMcxxb,)E~0α4?\KN H񔂤G]k}J$̭g5-pղe,kh 1a?C1 wO~vͫW{o;a`'{?7$=cly|n"PI}8 H UJLI-.leB\4*%YpuJrj)IzUJIVD:+J&&k4 @H j2<ܢ9hnH1Pp PRZ%P"Ӯ햨We8 6c|ZCκEY2db@VX@ Cu1Y2HJ߮VK..pw~ۓ(+]vv.C+ )m-YYCʙ9[UB-i XK a% sL㐠T i-YBBZ\ VmZ/#)E)<48''FZfrbȃ_uAQȹc^ K$[]6gc8+Mt]2:ȧ3臚՚e>5=cj 改|HW77;1?;.(q瑲|?▘_Տ@{Lr#Y#\*, =$ĉyi ^p0 #~?+\?K/~&ϫ,ZpƯcP!\<;{{JMݎhODy]Ku(H8 8=VJ!.0FaZP8n{G [$9#ZƳlRrDiCa/0Kw`Zc-8RJ":G-eyo8JPT!c,U-qǔ|d۟M9G\F~+ZT$rB( ZTmk(!R7R+-_~uMyK֫ ya/^^3M3]жНh|>r< /^O/?_deJ"CV6FJW͛"K`9ң{d[|f*s\ ReڵGh+? ,ـ.$JFIM!nZ)@\!)9/ţ1ͺŻ"%dLh43 4g./V^qj=(.aGEz.. @ ߴXxzq O<$ě-?yh?P$%mm:,N adq jJ8 3a˳M))٧/ݳx.ZrMHO>^7glys^ٲ#%abggX/=s(m  Y(2a8q$&4VX48{]Z SԆc-}=eKA411Jkq&GPqX:] 2Tt!{·c-1ֲTH)-vae*Grs.i33;zp͎8G<}HheA}ߓR@pΡgRu3 3:µVVӹh81O^:!YD4EPEhmcc=Ղkjצ\2~dg-Z%^)s;5 D3Luot6R( 4C[.P0c ͚iexҘ1ϳTMd{0q8X#niQ!FWX+;U@Ï9LU`a:gL10Vӧ2cS |K å&EH30@ "hZҊ+no|OZvfQY7{XB glytm0Srf\\"AL ~(l'> g| oo#_d3qF$K!gLCg YcDQե(:J EuS9etB'Z*DP 4!˅BhEYM#@HÃ?P 5hL(!X)DkcB +ё# P&V%Lɱb k}6NzUv"{UD+sUEոVp㜫Нc%adHa[ͪkl61q'@ʥ5 J ~?Э:֛ndw/?k82(6F׃O(i\p^Y*Eh6LP*@I.2JPIMӰYQ\s2)qu M-觓 n@eeXJSXi^?-dyߏ%S2%ʹM;1BD6 Z6]K޳Zt|wl\d..8;[ /Z./=(qi4h4r2gC 5\-qL*DwuEJ)%ݐ!U+!kڮP6jy@W(_S 㲥ќi 8kJf!H\\@H)嘬AQF8 /M[(l 9?γ"5,mwj״+OHXzwcZV>bE۵8#X9.\N)3Abf ZA6rj#e1q斜 c N)%|H¾shkBH|589$[n8{Z, uL!2NA(:N8`ÄknQrCڬm+BERqL0 䜘 -zTkEҚ\`"0⽡k=F)-"&I_,mG2+%z7@3A9j762 Z+=HB"ƚf]sX$cРE6%o 5U#,hh1kE!YvR9B5t4a+:|npV+}P'oa,g\םPk9V kY2%9Fi5"R ÎK.^|!94&R., mpkZA #/_ي)ጢqF,:hk-0f1bnVKS"e% vnwg?SG?-!GHp@щi.e!}"[SQDA$S 3:1e!e#wYQ% Ն Dq F#.?M@3QaΩmD2k)sTJ^Q9j28$i-N88[-%ivh6D”O_mˆNJ}T }i:qѠVQt]܂iqی4i&L I͎)_YeI Tiö' r\L*NJqȄR!Nҝ-%Kk+Sb"(o00\i;H)hN 1oYM<7sP4ZYq$ժ(̲|K>I1W eyrе-KN kc%[E5jz,jL>EVGq+ǠN+VV-zl0 iLPGh#^ *JaU6QS*'1oȂ`TdĘ9D,8q{yR65t P]iF20fE[a zr~[,m՜ǔNRhK΋'n]Ҵ䢧ȑg$FʧQŢ(=M u{jU"RU$Y}9^1E&q^a#R0{ag8 ZHte$Ըc8τ9❥lE}$\u˩u6y&'y@\^S|oۢl =ҍ8Q|}w{{.h㰜:OӴRc&5sddY@IϢkX.]E@.qCMde5bBdڨ"@ӈ-LV5MVMy]ם*^IK'1חjR`2W2)hTNl JSn?:TgqqC叨gHH(B ǜ,mFKv8]}?,]-6%U~GT=%9gBufT]nn_[VaZ*,E+CkDrz4m`r=S41)L\g˟s;^a?bf"4Jt1b*OU9:S6K$!ڥϋ=9Annme{UJQе Be,YJcCPGE(SJ$H+e $1V0H8DQmHif5]Yg)r'yި,O[鯕j0Hԑ&jmqռrЭd혧DGJj}A&#| X# PVҶc(kHs5yxs{,$e xRF)E#Mݸ@  PIfyIBޘrS Hm\D#Ѯ[VY'߭8:s :ϣ<:cixp3+wjM#Y>>+(BOYg1 3*9~Rg`(U1bar(V{PJh#_c .|8@g W($U76s cic!'%918"Q¿Q9t6ޟc%:pdR 9+(28﫸RASPR!Dq2]Riq 1~H)\m=a8}(U/#BgYq)Uєzi&XQJL%ݶk01d_yYoX|QpgOMr~>iEk-~i}f<9ǫL՚C3zQD"Za|1$+E4YJQIuhR"IP0(EJ;:,'*YbU)$:j9{ARvJmNAaFbSA ue:lNP JQQJJfŢu(r]__1]ײ\.NZ㯜 A q1J;0L xrg-cQ*K3ө~M(.#Bzu)w_g˨$CchM-sb8a,""hTV:&:u*%DZ.н꤬sa(r8D6KJ&4 4Q4)GRJĂr4qL"j6ܚs9mLǎA,-quar ;mX.Zr:}:n UJ1.]~-1SG)JtKJh>} rJvSyJ'E*0cKSp!Qk+oa:\W.r]2xY4윫s>}9ȫ}x%M+ɦel3\pJg~JTF0ahEH֒V9Ū ;dqhmB;r1,NKMMhWY(T}tC#=zd05֨sFkYnYP"S` ouBó=^˯EWq$Eyٮi{M1Bb{r4m#}Fyw+k- 1 te2<γTRww=uz}CJ" <|fT vByBߕw63'-Qߏ~}K8Z" iH9.mu^έJw{c,-)<]Z-aE{7HY=MԦ<wYA2Vfۻ=0T4U"/xJEM:qM3,wm1m8;_0S-nAAgVx/4GaZ*b1:ysc(G7HZueC'(:ZSj IDATSfKuui7QZ|ēB >U$XRWϳS ":giZC%fu*U}1F9:>)f+V)$$gew圑o9Z6p:kqhfk=9|e9P꘣hG;}_>qs}`zvacGqؑ0h l~^oN9xG|b0(^_'W/ļǚQ8n%)D8J"Eb#%IZN̈́(\dAzѲDQR&Dy:W r,ĐY.{@ ~9A$)&rmNJc.p>QF9qK(Xkh,XiW yABIt9RJd& ;J[ջܫTRk sJ&Ǫת[ҵ+H0Ns=4EZD4,%k./θ<{) UsƈQT;Y^sg%XuI=Xlš~uVc5s!y:k1UXwg\ՒŢ:RңtL*@`sYBc4ա3=Ct>BiTSF dFWͅb#m%Z,Wں/*%ç+VQr1Sp QZLdO"ltlת^21a5!I`2UaH_4XIEڠд aJ^P'"n0 XcX-t%m1ƊH-Ց*u/l1 P<,P7hc4ݎ0.׬ дbIQЎ3/_ Vk>x g+)wyEhll#v Rݲm~G)keM4 :NVJx9JihZk|qixIdh^4S@1DR}JUr=/39Rww[{rͲrqG뎔2XRy)Dƹw|+R=~~`j"qHE'J%4ꈓj3qTNF n冚^Zg7t]SPScJU7UN˙ Gɪ#,M'K5G4N^0U'o(\I<`Ni<Ŋ]( 7 WEK(oI<:a?2 #MY,[(Iƕ@'>0źqsmmP4Kz览b1s"58~a8Vn=@7+VzMʊ>{E,yǃ@ȉ5FZV̩H决i10Ge?/~3+iOX& d/ib-n{`F:hCZ40EAl )-nDRKL^yhdYr&mhbEӴ1jI3e^ACEt, W̳8Ҵly@FEޓ|oHy˅ۙ}/Iu咮;"ꝣxRc#<4mS hrJӦ"ǗYScMFyf͛8r$9|@¾Zk>{ :nF^:BbjaYvNЧ"Rn9l]nXn6U/OnTSƹt6ey&Tk+ VSJTM u1\H$ˁU)D93=]֚rPH`BKPAr״[)1x`TM<5R3ݠYDֈQuNi }Zb];HZɹRTt$LqiZO:q\DsYkF(S}9++Hb#aA.0SU !EklV!#^RXSi 8c !F~"R3ju).7P ՊB;*+mޓs)h*r4|^o{T:U\43`Ҵ MbTyõnE h#<%ьs晾Ai˥P9L ֈ>+TQ4˥\h+$`VtgfTzmֹkԸ3ZqEC)鲜+-CgJ B\ªF4b,xi{ԘR{8I]d%BQŊF0TX^Lj)xki1WUlkz!EVD9GƱ\zYj8nׯ︽-x|#JNgmc6"VYе&2V\99bRt HԆ܄6.+LX(Ftxr$Z O# /i/s$.24"DZ^Ogĸb/#k%ʹx{@)\(j!㺾CH5D8HSH UV=NDu]c,r &.<#޷o୅UoDajC(Xeu$ʖ=px~Q_ǩi):t]h6Jµ&b6ğEŪhl߯w3seٕEGxCGo:|P3,Xu+2-XU)8  Η]czT_1 N ^^-üLqB#}ahQ@Ϯ/cʞmkp,()ZceXc{< ֈ[p9_3qo4Nわ?\p8V:yNu2"ORh@`(7m#rt1CSxS2ea0K(g9 .3Ro w/ %O_G?R3uBk;sr\eNScYpдwa@Q`LuqE* C bv?{Xa"EN (M0G4"PQ@tO ՒaBR,$ȂZtWk6N&}e<(N2˄/HbA}O*$'bD 휲)[eFLEu1.i>z)4 󊶵hvۃ\IL_Y9(1%d:m% R j6@WtNxIgSHȝ Fb;KFQF_ʕԟ cJqAL9r2Yɦ`gB)Ơ,3eAJΒ ,6b*<2иD#p9$2̋|&ri8Q!I+JVxxn? G MZ HzD<'pbedfoJQtG A`R+ ~%fMNf(hp˙tTF˚ \5?B+r ЖE4Ą#9i)enL{mÊo`O)\TE\\))GڦPjtK#CB(/O__bb 7hVDc ϯ$E11FX؊6Um‚ N~~GH%Ca| Xt} MUN+ E]3WPT 4V|g]icB"o%4* &%( 5R꧕"V9,КHk"_΂I UMFD70BrIh8*Q3.Al#WD?Ѷ-ҘYՀꦙa)rfe1`PT"ӄ,޵?oť`$k:"hh8xf!t+arGu|G-B*#=Zr/#Ԙ 㷿߶}6:D2]XUJaqc>q v,$R۷X;YgtNf9{,G#5d2! rE).EbSI9%, cmkXdhEd9']ފ?<>wPB|<3XWVF3me_P #(IDATnuӸ!B-\cEWfjYb#nZ1%\#R8;Aԕ3 7,M膞WKM:r gۦ)dfXY3$N]3Q*Aq$ߚN{8W &1F JSQb{坮 =;|R{T[q|=Z~ŘuE+ڮǰ!ĄyZལ$"FaQd`?YGc_ ܠo[噓G Q)(Pfh epő(QHS>Gż$Lӈ0Y)fCa1 ů/G9%A l8cP8:=:e˲;Tf1O3Rb!|D=`-LY,KB c*E$[4RH4Jw&S//'#Pe\4rdac4D˒Tn Og3^Jq*N󄔀1 @mzds/!Xq(LIC&f P$M<:,8G( C%x57ہ,Yd!;zzޮyi=x] M}4xo+h1f!7#$fcM8V1tMw*//A xߡ(׌?".3MX5/3)W募W5MT,@ ,Oo V$9xsX9\u_ <㳦mMrS(![A.Xׄ3oVҖ$Y(YKDccڸxTBιjR A YJKFQY%ӻ,VIRoj纚R*穵(@1T 5[uF։4=N)f(LӂI-" UrKکb[#|E"XmD!rR1ೈJLU]-:Ce@D8G5DϜ,˂~~7:~ 4F)[uWDOqz< j #5fY _"m:W f *Z@%DL@.aK6ڝGQA8RRf JFFbQJe)YS$1-୆/#_=7/,jGaCנ9ڐHsZ3Kąߛ؊,Mk04i`[ BvF)Qhm\ %Λw쒵 'hS&htCOgrrCނ,"lq~_>+GrpUvxpz=awCɟuǜWM" Kdhp,#.-J\Gة.DȴأCXW9tt =-f0heպ9kW=w݂ ~kXѵ_}ݞZGpAR3Zop*Q=8Nӫrt \Lq_KKW~ĈrR9d/o䜩7=J-+:"@԰BO)`LQ&#,eA[Љ;Ƙ@-3Xd8"ȝ;"YQZ7H_ypHi!"(MJVbQ 8~ד 2Ń"sPmY\88Mc iW9r?EXKW :s[Ew1O+~Wּy6Jل۷px,4t0O}~(q pi3U<+^OgL㊇bP6F3ʰ0 K8o.+v} 8*CFBw01ϸ˂d'hn ڟPp9O(9eXotLWt!љ/F״q"JVhZK-fV;"/Mo~A)yHbV'`.#\bZfv臖u!U2W)wX \)^y7XUr G%t4OOh[_r?BAkyDۜsdjB)#9gR0G(C:OX#i~ߡ("m,]%u:-(EF?|zr.q\e?Pukh砵4÷?`:.3 :{GJ 45=6HkAB)lJ+5j96P^٫"%9-Bq]`u \{SQ# zpa,˼q.rpF::,9f㨨V qNOj-x>Nu}ڮcJ}8<ƢZq)MGӇv ϯq0t mM7R /h[a?M>mU~/OGhpWB׷$7NȌtQ՞ ,­70dtc IKR:!UH9Jڸ$\}4áKTp95z8)4)ѿrִD"J? =EC?t-tSH]VD o"@*QձۢE|[}p~_|#F!SQ "\ƔBB$Zl5iYf@DSM.969e'M>~x?\cflH\} ,:7Qk$pO-V@Y*]+i4c> A<PR"8w[-@4P W+.fsFQ,kt4mR"ĈG5q:] ; Tcx^cAJ+RC|gB w-E'ж rL,@mb&jP1e"yl~{x4H9`a0X14m'هjCQqfQNegRl|RBXREZÐE1 >F;N=Jaiaw,JzkZ >EߒC6)AյwmMx‘uT1:a#rJ74!ma%rJ8]$Y?FɸZP/3Iw&IZ#e^ţo1[Ij/EGT2 eo81/U`7^f7JʥZQ K ٹ\V<<34c:^4t'?;#rQSnGb4#]cqwNi;< ddۘ_>-@tmW阗a&Bxt#9S ch;%cYΙ d]Vۈ9$:LB8hN..9AR{s=e&e$6rCZs A.HZƻRF[}ElȉE 2&TYg`A.K@;,44M/%&ex܏vx u7}bhӒL <wПT5BXk qsMl2Η 1D8H6M5&7$ِܟ䕟wԟv"ZO:?sբsO~ jauoISw'N'<[<>>^@ċZ ?9e rWļ ?KM~WJYg<0aGp4bP#ſ|7 Lq:o>E1Hje8\99Deaa/jQ+bxmA[L#hDD`P+Umq~?rn`f@1 R7sֱLJ:f x|/*9\$PK@A"=fd$\j4! e1\ǍerΊRȻ,TSL3ljy OL,(onB柕XjBun ,,?W)sxy>r~0Z*&pZ@ΔXF05-a^VX֌9dK_kCOPiNZJ7~_.ΐcSb6Xy~3~=22iE ݎy9 i`R( l~Q~<+ĸ_zq^NRJYBXI솞A*Y{@=WA<(t%Q󐫊C;(OIf )FI4tVv -41pa=|Q( TN2dY#i:.4%x}vJ, ? FU"(`Ś2.)'8)zH9߀S:R;g<ǥd3.첺r㞖q$ O3b\e-4{3|NRj~ 8c4֋5hXLf98^_/88 8zAA7tF6ߔ#`& i~v}|C7_ׯYjQdJ~+6 2Tӟt0qŇ_Srlܸ` Ӵq},nX׈u<8[4G} JD$Eyhf?Ԃ$XP- +:BɈƒPn9/h2`^!F(# ͇}zz Et0Y1Lcua gڌX]3/'\ Qc$ C2D|1Q|*93OU% o%sRF4%`gLc Z 焦ҀVbjZgnn?*Ρi+7jioF${*4M; xZZG2+aUHc?IENDB`qmapshack-1.10.0/src/pics/compass.png000644 001750 000144 00000023262 12374350216 020632 0ustar00oeichlerxusers000000 000000 PNG  IHDRYtsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxyTյ] CTD` |$1jPB NqN53qpAQǨ & S H cjNW:5穧SUu~j^[T27m_}[:55=c#"1aoCgZU {<~% cu lo[uf>aQn1-RM9+0-x-ʥMLI ZD(,4`ŻP ;"?TuK ڊO_i[H`p&0+FܯKB"RnÈxnӶL#"{c}8,ŽOrAQ ƟA` 0 xZU7jX=1C?\rIQ ZDc.0 lUcD|@(NL'Ε& ӻ0wn=iZ@Lv>;OvZ#l;w@yGT^{h93l1pL!ىB~ے,;?{5[~PE> ~ oCEpD1JUlZ+Cۿ@%0HČ~ o[R^!k^"o-k9i%ý~8o`\cy(!ƟNxU]INPuq@DC⻠Xg03C.Uӗvo13iƪc} 9DPj<#!jX͠oU~ّ+v9o/k ZD.tVg!lݺĉ;] oqyZDNF`֭+++~ےMTm <+"չ<N= ]Jbؾ}{~ۑ =8^3A|ny'kjj-^S 9\qֹlok!?tm;6YT>)˱%۫ESmE}sk}"}uAH ._&`,'6\D""X "Edc~ZD:/ w9?IG{,:`$&eݘeoȻ"2Ʊ<DAm}lЏdDsxK2'Z8 j$d<mwOjB&]1"`#;Of#Nm <|YDDbWZ戝|;0c*3؆ ޿UUNNra{bZb~kRwtmLd'"Uul|3tfTe%"'xtFtqAU%O̗eUtUboq8JՌ^8-1J^t%߹OtGX lsص$id dhPaGaBo.v<x=o۪1Yɘ#&b.v֖+`B2\rhMM!3, -k}x~oa&ۆbҁc05Bn4#Y0?3bL$sv97S̈1UuTu E?nNÔ1X&L#5I|Omn\U(OibKGhc~cW|0{Ej1u?P0UdkKk5KȬVNJޤw0τQń8}3}u>7ȩlˑ氈Lx;gb[#dtxj"-Aȱd RĴj655Ĩ$8j*eRz?N6eeSCGa5Tr=tFkIT!"1AɞDZAAe\3AUOC߀xTr@LAr0{LzR)aς0ݔw'gZi"f ]d{YЉ8jx{ekWf2,Z&Vkb O4 *㍸XU z$CQLDM8Ls &$E②L+9ԝwBI +z7jcf Cr[%W"?~ţ0H+g:QHɘ$Г gR*M$E$@fMG}tVyC|=7 F%VPjҥK+K.$[AwqBG/Z,Z|MW llܸqݢEԜS{ %r}#G8p`!Bm*h鋙q\w-_|ZMM͜ykԩSd@DjDd'S(ڕsf灃F[CUcPU/;wn˗k׮SLaO9hllZ!"K]GݻPl/$jT}>F Wϝ;weVc``03!DoTVVf%ak15f̘={܎Yox8m>XE> lE/`, o)e  :eʔq!D2;/vl;vS̋1㈋%h):7F>y 5::, x9f)^:i*c>1m\]>x]Uw,`D=4ZԘ5V zɦ WJk Fq"5Z}]OK 0o޼K.5w=x2L3_,1jآRЃ1#J z8 u.bS) mʗ`{yرGTB 'b XAHf]}2o5"rjSSӒ QR${7;3ǽGD3oBKSPy8jC֪65^r`C,Y*j<S$i[[['+㽱ļjjv-Z.UrꣴNY,XOotʔ)Fߺu!WFD6vinbE1:2.ᔸ-ѡqVՇ*++yO\>McǎGnWn*P; % Ɔl ,X`X4J:t0 ٘@P5_˂O Q C@ MMKaTWWGļ>d5>{K{pAU#"7|(۷sTWWS]]sά\|;ڵaÆm޽{<1/-|=]l2>&"gai"Ǐ**dʖ-[ز"Bmڴ@ЫԩP5%p3Uէ}6(o=Ed@SSSsClrJΝ+*eҥ̟??}E:PYYe`;R:p!"?x蒋'Nث?0μ\蠪Y*sOlUUk9i5{s ݝ"ED.袞***755 @ULPgo߉$"ki-gߞKCz`mc RܨV՜6L2W8/"T[dIYBx7H%o o`q}D3Z_l+we wQ/kc )+"! 3mI&LPވ6y(x(Yf,"buy}Kcsnk.W'WaזE!dҤI+**Kڥr|WZ+v R,TD.t${ F,n=rz :IDz1#SNk׮޶(D"t<#F0fu"0=:^Ǹ[Ucvؿ\gep}AԩЎ;k׮UUU>6n696H8nmۦ:tHX!)H6mv566~ G=١O>k۶'՟u F{ P36;v{,]^wDDmcX.](" ycZ).T99DŲFZ{UP(tfmXv{,XAĨUO|,GxnCTWW[ lӗ `_T)+$6>JWDںdYoӋdC>C'Š}.CVE p-Ey\b/ "meINipN$E0qm^8kodj,bh"G{ŞI6"XLxI CD&ORa<+ o!%/:N\|GNbw ,vwi}`LDp"&kr.Jksȱ6(AbB\ t;U䋴vZL,gžZ"=[Lע&ZyGk޽uuu|j`Scc#uuuxV%(xvx#"`01[755Q__O]]lذaGCC)="چ}Dl"{uk^UcVr*azk"lL>SLʨ tB.]hhh[om?~|6mٲe NQQYY[-c=G}4ӦM#'9TU+R|E9Vx$Ph!.:/`Gq<0Y+zF蜚7Y[+GJi(oݼU QBc4F͸ T)"6ԸZ-1rBB*aGRXo=[GDݭ[:=xV_P`0&Ԩts#p0\US$IC7zXo-"ƍsCV͸M-F`#^drg @(Z\D]Gp,0.@0\%FzN 9R͌4 CzI{Iy8\֑l%h; ɅU"j444lty0XUoO+;ɩvb6ir|)]Ͷnc՝x(V垛b)<\U3VL.muP(t0\D>t:TDcu.h(pĭT(a[n0cƌWX Y 1$ -tbܸqGuc a5yFp~_t0c˖-̜9ss8~iZDF7SnȘl/GX"^(6ljΜ9_ڵ,{e'^È:UݐUKP(uW^ <Ѧ+ ODPO2nV5jԠ+Vlضm9r^7k9P(lĉ͛wpΝ)l݃0t%xyrCmmGs,fCAGx>C:thtc*p뙨o1y;rטiVX^Cf8SO.ψ^D*&v>\9ӊDC=tsxa^v !^Z&8 m#3K7Nr 3c$# ,{c-M[Bl[b.U:MJ [A%GE > 3(?o.䝇vb:`L._݀!"k0< y!`|M\\BHW"Zs`ADNdAWBQD~Ok;wfߕ&%E /0]`\+"}6+.CUS1)iob MPP՝+`0X%"׋HMk#"^Ϋ–"EDnj3 V_0t⛌i8v6։l,]2w7\U'c*. .]22sTcmqW lLOžOaV5M1-ZT ")GIDPܽjg`fT-OUdS!G,Tui|*"1v,B,DdB ZnY>|w](f(RAGP&U}QUxa.jQDw٧hv5Ӽ@D{@5=ȍ1w`>U=~-wj݀ocz䇻0! ab=|wkCîiv[7k#m?A~~܊2NXDwJU̱}gb8 jӳ70^^ Y.TJ^Nll}8ppZ-,2 #&C;ElcdQûű %"\:MFD:,-b`[sK: ;s.uMUUݜ%t I Z=z٢,(032b:0_UɦHaRv׫~ؔBq "m17='E:JFGH[U}(}Se IENDB`qmapshack-1.10.0/src/pics/timezones.png000644 001750 000144 00000243106 12374350216 021203 0ustar00oeichlerxusers000000 000000 PNG  IHDRe.sRGB pHYs   IDATx-t95m/3Ka4젼,4gQl(gQh4 Ai'a3h;lzYeu}*I%룫H}#B@Y<(@ P A@(@ P A@(@ P A@(@ P A@(;l8|u%_a3@|#yy}%Wy~8I0h~l8>^]]-$^ 4@: `|}1[ۇ_?j ItB@RWo+J Ëj4I` /7;Я 6xgR<{#]E)~m˂d! =մ٢ڈ@a)Ɗ $k~+c~mbqe=r@_3kRsm_@4 1bh\g5lWWcvuB~*Yשr~h1W4 V6br2'N^yM K 6| HbHmh Ii%!ևT"w__dw7mn0z8;oRϚwG *IISH tPP AC07Gϳ^$ApO)do kw ƙ23!  (A5@@JM_~hNuiҨzr 30}gdkү$1s{0AxwvGo )Pi^ɗ,}( 4:=~NN$_ PËUg4 ,!/s\i.r03ķ@'G0,` P*8A$" tH'K}HQd?w vsֿW)l `Z|,ij 2Y ?@hi֪sޱ!}@0wB ?O ~O0Pnl2W;l:0:yиEH0-~}xπLSʉ ޫ0W6Qeѕa*9&R׬&R}A~t 1(*u;?@TO%/Ww>i%vJ x\Щ ; F[3> 'wp/_Ỿ5 /d_ "> “Q Is!#4 IcO?p r:~5t@BS!ͻ``)w24|A Ԩol/aXQ _1a#rsp` 4WRA@'sOOm< }*Ձ~!UKA60-I V ?f00!8yq(x}o{1#==Z 0TVuE$H">$!e@gjtՉSȏG ~oރXwlc q{7C'%|x/7 #t@8W@_{+@(@˳tS/zaˏ[= ;Ȩ&@%݁%0~23ۀ n]j,~BIC)q ߆R5E dmm{˘"D&66w`,HcJMnl \m ʦ-_[r`0hO^-Wwp6`?pnu),*`\}1 >ue} Vn/=f.BALa_~?т~3)hzA~z9c*?>^Uމ?@: }l^e Irq<)ơtÕ!2$ը(BDf4`~e%x#O* `J߶9q_=Z D$u?Y?L=Jg.}lfL*A` xd \5gYar!:eƂ?6S@LHa RH'S8-w# @ƠWH- 1@O {gm{lߵ]2a"=exAF"dW @Cps8h@@v젃(Ow^&зYboϼM(z,RX|Ϟtz4^S"_BJʯN4(֎Sx_Yi~*jLˋAQ;D-Ud_A \PW+U!*@x=keD>fB[πP<p A*If4թguu|%(/|[/,Jx\z#Y؏`9@4!1H,dx:o~6H @) gU!>hh߆?Q( ͷe kN4vA+cT*R޽ˀz~ndmn 8i&JrѣK̑zP!v+q1` 9֏ @.;5.ŻZQGV=Tb²@@F >ׇ L%W;m~"'`H"AI g@!@G6ч!/adi|+5 AP pQ@@RT2}L@?e;D2O佬$`R ~ ({'p-H2@Rc}yD!H0HGnxokU`Au }@57*-WDA\]-̜,8(?:k--dv$/nR!/ _mcN\p⯣' \ +HEԳ{ O ?v3vO+'^7ʮ- v3u ؏@dLe 仮t'Xek); O  8$PIwiK"gt[0M0,H0KAs +4@h>.ZgwQ@_WB. /vW#lЕ]KoW H~~鳡;lHL5?jNZBoapwٚ6}Sj8g $B"m Ax|~Lی?,[~o>6Mǂ6P+LzLA Hɻ/,@ˆy:m|@(g[C@tտJ]~`ٯP=7u? u =&@#e"" 6*b7R86x*W QAwp0hƋaw6u\4v AxQ@DN{:x¥wOVM~ZT"~NOsf hRfz6L~`?J 7e ' 0 ]FIEn@/:F0җX#;$[` #/` EyE@CSקm<\vQ 8WC  J[Ж/?b^in0a'r&*x{l  BD_LUHܗtW(0`8(_@ ٪_x@4p8]@=* yD?0SO[ G@xI~@ ֜A 8(@<&S^dxVngŋONЖ!j w6cAX)$t:e+3,Ny}=8@%17,wG 0kb (  wg&ļB Zqؤw0 Ff[ 1|gcR{YJ)o[!qЄL0"rt/ i8x|zh5P0'tؤ}`A7깽{ c-g _;nk.xb$8գ 89qiRgi)i.[{!ӁIݢ^|ZM_jdG{[5ϡs&x1@ ]^X@ 0ep| f%QO]oyqS,Ego-PS:<Jȯ~iq)8~/>YM>dž{C]YA3H !Gp0W#1GԱIUv?|)eZ@/ # #T #i.bؐ>oӂ42I7!.~%+hx J~O+T4W> rD0@m넱~ށ24< @?M` 5x[d\]u/fxQ<- !ו@8|rAyLp9x.k8YM'+0P_Wz ,]:r؇1ķ96H!w.azL@6Gݕ%2^Cv}!E 0S$1%@b} lB?N7PyPsm=ԮGmen3q/D@#йzN @t<*o^|Zuڒ}yCv'ю>cA?IuS&@?wV#_OJ߈}X?N P@}zwS1Bzi˶ިP2"LBծ:B1M@m'  QIgHDVJMƻ7OWLF2ͷ2: e "yϔ}Kƈ?P%\װh2sE-2F L rȑŁg hϾrf{к 'nGuaDo>'L%fo_ )~%ʷq(&H͋|s|O3O+Q+s{Ry-; X."FyRBcUw Pqj1 `# emB|9}eL(0!;S a|a0(Rܜ:K!Ϟ&m_wL[6緟8 `0mtu~Qj}]K 95g^eyf5P( }Wέgg~Xs%*DP*6T@XI۶mK}{!?yJD{d$6iMzo?dVHGLȄHU;zӫY=~J?g=O~wL48 ,PYE{DĀMhԦWbwYeL"K4aK!vMHΜ@!u] IDAT6&\XXOT ={LrJ;N-@\]py].H|f? AY寝`nju Pdo# rAϾ,.=.bHi~,[HH1z21OT~G\HL@grتq)Zo?CܟOݟTjZo.0%}9^?6T@ao|@[xXk[x2,֐C4~rMI5J(d.#oM@!B<EK/ݯAEQ4J?qP⅀ QW̧%Gk7BxR>tVn7WޕQQsz/b _Zh@Qؿ2;Fd ?dA>M]ۓҾvjv 0=9v\_UޫI:דz{ _DiȘ/|85۠f( 2@8ŎR~:bT[r@㊁@*@*2 /8iSmmł}W zLsB =\ÍUp{\Z &  &Ϫ C&`tzW18^iu5 n+^oƹՋ?np?L_ʼn v[+{I5ζГnvK1O˅J#bр ,E@prLM?L=[ A# ׿Z+a}}Ă#g +ܿ%.O<=?/ bV ې>M d;0 |,c􋻫 UiNhk n`6k1{&QLv@ pD3[Vձ1Gxr!R @oˀ k59>^9@U)CaHVCK'~i@^q;@E4OJeO2># ȱ@2 eHdxQ^ AQб)Zth[@?pS2Q هig_43 R p{? \yT"B);!/@F?.w%AWnVDV] ̸ܹ%cDgȨ=P! Brwݕ(z`ިd/MEnE.Xm`?@s, $B#cҁICHRks?=tk%CzTwM&&Nqӯ+ԨTiKH.(1μ.h #;MhlѠHzdx6~-F"~E@X ,m@V~9tM:@~ghh UlpS_>GAHW70w-p0es Ï{\`-} )߁T@ ʈ% ?q @ CK^  ϛ1nλgB%,(@= cn#7D?yA?P:)hlK _ͬ(KaB_c(%1Q^H6"Ñ$L@X^/6)4AP2-)p #00m榪RtH r~Llu8lF@x"wN~@'S6hh4* l κ@pxl_qjGե5 Fْq ܀QH&_[~|q8d&`urjczE':}Xgey\Ž _أPkT-q W꧒m.H@'IV+˱c"ubu&ztL‡۟J5Jf󌱎h_ $ﹼũe0"ѿ$]1pH=ĿuxMgƅ?s#<Dö! EzzdJ&Ј ٧P1c]ۀ_BW04mnmB!Gl@w)tPX·͟XS0"OWCזDFza{cb)5k@#|XEo_>,SO})D都CLOBwQN'Or S%U{CMsk}ȝd|d3 2oӗ єĨ%IpH@81_b;hqÝIvga.=D2`,Y'I Hj Z?^QH<),>-T3s91  8.h>,m+HvU~`'Ǐ C"!p-(W;M*+=M kT0-[u?7Kg`/P:vǪ=gS.mIǂ?#ܢt$RB7)&+{Sw~6ȗ|.$7ٷ}Xlؖ$י (/Bny|Ec{'_@F@DY' GN-Gp@@ @@> cݾm3()[+XȂX"@{o 1!Owy-.g͎7zHSHe֯ yA b( ,HBEL<{ __*oS;; bh&ٟ$.gčߒ>ZFo95@@v&HG$)0q=O@W/fZlY O D^_]|Yg >m9` '(J(x-fτByOPR dWaz0TLYJC4@=ۿP & #fe%zJ~D@d =9mQGۛ,ڲJVHl4@`mjUA0^81(i J/ D0YqDs10_Gq+1%ljAY|ON\[29n5߿2Qٻ!]!!B_/ }ƜiLE b y[쑲4@Ij/66zPB@d$dW'u6p:G!{t+$,e@%ėɾz_i&*փKA@oX?qB˴NR nbd%jX`@"~Y F1*p){F;eh W-ˇE9h=LacO`O|@*?w_C?V{:^J| K̎8̖H Ic-#r%ubJmx"^j sgƊĭEY o_fh_ȣ HY@b +C"Wg:?DZWl8& OKA< o}$:89e_Rww\<\?*vaO+8Õz9q3o+paQh`ʫWԉMng8SĀiI+qLmd(zh +֯h7@h#S@_۔1mz 0)h3ȒmK@O "ӫT:d0@g>\-~Q j4 =w[@K` :Bu_ ϶1HclL@ KAp\R=[:ܢ4NW AC?^KaD3X%Q Uꁁ~z,7CzdHXgze @ % 8rϟ`3FTV>K4A@/V!OWl_ݰ R6D/: 5?,A} 1 N88h*?x$/z|Vb߇>@]b?e@%Bo!1~u h\ 82WfY-}F `_eP]xVX9 E~W27`cZO\Y1A KcIS@`Ci9F=h?sǒm xN7W !c}=0sf%Hp@5ggwB/kS* Yy1 `j r7%clVK? @?)%Ѩ"@?MhȀOlIإpaoBpWx*f'>@; \kS@4" 0P w "!֟3Ȓm5*8u QMջŔջ$?p"6Kܾ6bHRg&h$U)@?5hzx?S@bJ9rNw! _q|<'\B!CyF/+!ēp'poyǣ idPcB\V'Cp}%Dor+IChI&BWCpNBuc%<  di}:;7 1s?=L+mB/{/.s&}@ERz%Dzzi,fk!s@O,1s/8 XHi?V2ѿ㯽;gtvz>|*l$( KynweA+ r8UO%{tjM^zG=8I @]nPz 725uP/-JY#'o7Bqu!-pr8 H$|dyC1`^!W8!o[B 3֗[+/Ă_g{/~2sH;w/{`N١W@w˨K;#_/ !{+BGpNwַ"?4>a>OK'"_})b\' Fur6*]p)w4NV+lC]0,?d_V*9`92: Zē/ n3 C }LխL{Hr wjG#@Gc.=3Zns$f/ѿ3xdC]m&k#w‡\[&yyp2 Ip&OOZ=uw@x P 8`9n@*'m_A7l&o7m` K#nјK a<xպ_*_/tmI'Y5Qkg1d̥O-?޿w @R#X-vޒw%ϾY4Y=^ !<yC[l@0#!>4I4f69$܏_&ӿ>wH OF^8=ϫbxxw%> ,_2B9BJ,n>>$p8@@ ~#oq}4+O- W6+IWgva_sdu_--+)# N}h~/wW 0m}Yv'ItoܠG}(&7gmƹ>Y&#/v~7/>7={GQdo߮uzq"{+zJ/:g_".z)?_m}_9}Шx/o^`}6/nEH !{ }2˵K|9<ʵo~{WP/0f ZOVP JE=ۣs?~mTFR@M[wy3-/c87^Lcml$xcBkN76, [ӔAQ F0`/)D4KH &oeH ')=Ur .f{x`i~o @d 'سM[FG5!Ҏ5J+T@}Wf@ +"mM0Τd{<C=&r]}/CZW@aԛySp`.(yqHa;9cwkAi52|kLg !?BD'yt pz, ;ڪۤ"= 9IP' w۹Xljy)۝NorP7:@!WfE`Lzos=&B=`6Qo4J{6_ 2j8|_HRH\5H9 Lp{0sN7[؆noaw;U:p9qN\&K0&Ci_L[ SpJuaL`Vbl,}c7߶e얶 IDATtv?7EgM[ˀ9'V{6.'Z]l&N^Cf\-Wc#&o/oaOew, $6OqQ~cR_I gA6eWW =WJb; Gh?VwOe%*q]6Cߝ7BGBt7pc`LL%DH4>/wWRo&2+YYc l_ !vZԜS-6[53!^kfφ-w s? -N|oL[f4wKqpf!Zzz2?Z@tpMyaB@飺lMV $pt]=\ at_Hj FAʀpO^/  7@d^JS/PR~W@X>|7tpJ+ѿz4\$&:6= G$28f̓[Z8>W^W7~7\VZ>``,jګQzۧY[9gg*\GdPth=פ^,N Cs0Fv'eWa`)Gw/c>=X(j%N=&eC8JBgBu3|﯇~O(&4' 2鬧/v7]/\݀ 0~^?^Kó `dP6M| l+T f*u|#p{q͛ϟwPITx|9exaZ__ڤYO19&眦yf5t;:3`X_/+_/~YuÛtп.'{eM{9\5W2 @Do Q~4~@c_l'п!n9'`uv_o0o sV4@}5 @} ĂFw64P:IGrJ^(tCڨϿYo|*{yU](SP`].s/)^Z63mfۑOPA~ו?<H}<%zꝌģ|9 =EzK7pMa#\?Uwm.!sð!kn`kKztyYߙϺvV&1Oq`4d0yQ{dІ!}!~ddV#,Ӿ HJR\GvqJs*b77*(rErκzq)or}y沷Ol{eA; zef1ͦקwD&w8A:ѿ&@wNHSY/; /D>`z?&2l~9:!?.rw%NDqz#,vֵ79sNh IIn? qױ:eo_G}}=EWr!w; 5唝Ӕ]H!(@]m~%7O>Y8@le@RR!Jym]-~:^\/`d'Dtj<خ15M6ߧx_w &`gs;ʂ ]s3~Wy&!&_7B,2c}[_豾ԧz4dt(/Z g2*~?{}!i`x,@S 03YN{ @G#Kw@=zl$@ PT$#q_5x\c2Aۛ/z~"îSƠR h+kd[΅HClU\ron3[B%ŲKg!^ !~RnvS|x3fdaJ P ꟍF 6>qv_0@P,] p0~ͺP4kyjJJ`h+low P+eonH@j0/Bᑿ HΏM! ^'TOI.aTQQ|؀Gjgyf+T5@ M/EؤӻP& s^wnI9n s*t()d$f.1%K}?{DrI/\t0*@é4ls_6AeN+;Rg=V;l",>AІB\LZGsO[p 5y-6qKd-=Q8e022ٿ>ޛyT_t9#Ӕ@R&+H7 AЃL%XfJ6d>2#ľ 0 x%{uZr]. x,kiz~Bݛ%t~];{fĔ ɀi:M -֟=rfp (4 h5F?@ule 4|৖vAy*tIcr׉nϒ=Bcߌ/rA(v'f^7Z0L;= ϸMR A]d2F-Pe8bd g`JCgP%8L&⸝%rz鈁 _s ? gB120 儮 İ*р/Z+=},>~b0kkI@|pl9ziN? zV}Sk5qI|:a]t-Zg"迢: dJHEcal/[ _O)Jdө4n%dJ ?:+-AES/!8|TN'SFp+@_Ni[~H5@Wbţm/SYrfbs!` !s_3r6oi֧C@PFD4@,;sq}Rd/_lԉYx{s䍊E-~ `9.E\)^?Ma`ŃW>3ok_ H=ol$nfB݌VȕzTbBˑG l4$hbtn>py ^ 0>9] qַ<whz4D "_VΚξ3!j  |;7lKBhhcA7{oX^z:hyk_?~~[J"+ ^\` ۅ(.Em&FAx{wo`=ߗ"7GI6 ma{d[`K~-R2`o4@бF *@B89qo&(5s췥zu0 oTk`t?l V[]9wH-ɑG-?"iyw 9IwOaöl8oNnE=ԗF #} RG0qۑK(@$N7ϡ)Lm@xnȏ_m8 i|_m5.z"@} {jw$%Ǯ! _ ? +ZznWN#DI"K<-gPr|< i+K&5hM"x !8Bq)6MqzGQLp-ӤWc ʻ{?/^8eS؄9͛>e^_  uMhi]~͋O@{sS81d4`%+.] oVr 1/-wM~/B3o]E4lwޏOmz-Y/EDU ?߿Fi%ߑ/9rcq!}o'hwCk1&@)f@C/IE/lM049=mad.Y !> ;/ޑ/F zѿUN>; .8{ˑ|dz.QH^hz-Mf>5׻U: ].ͷ+d!p P\qQ H 'E TA[9WQ@! N3ֳtd=X@O\{ljڮ4m$x8]NnoH潘=y w#04qŀȆQa[|BG[weg/&+>>_`p*O_\ ѿ$w (_lHS@|ZL!|Y<Т|_ W8jzsܿGH< h'S{&:M%sR☀ټkw;&6`~mx^~) MLY`/6>rjlae/;88/pq[ ^_^U8hhWJrz8=ïse}ut^Ŀ¼{Q5bukK?ok`) M*@·،3<WzJ88r-s' S_v d !͋n.wO'{!aea7|uu}>e 8о`) &!Dz/;\l(5b/r @Bw'Bq} F g[TM"zK0 "}`?/̍?LPBlߋGV@ x];EvZ둾P@?zQău"&ȋi:Yۄn#N[ѿ ~fG8Bq"-@sC@pB%MBN7kg0dL`{T}) 6c~7;s,K)=tw `C |2+6%.S {Vwt4NOWl7N[Tܘ d;OR{#l^uS1|qFI4؂G={z(߷ڳ+?'>`H!6o_d{47vVb@g` 'ɗ/{Vz󠫩~a|ZMQyG~Y_~GwnϯTB =y 5}BXB4*p. d.+#g0קr)_& ~:7ubzwA@(fSuFwc>*F; #HP fu 6*ʬg|339ѢoIZ{;xrq>̏}/Iv{[7<]M)P! S牃zOJd %弜Rt9,>t?8p$FucnYRv8@$4,BF0 l=ˎ'%k.,gm 6h'ݰB r>w& ?գr*>AG ]`d}:OC~cVjJd s9[Z>H+Oq*p009fpYXz47pa}9q)q]ooSz?PZwy9|~I'=$׳ۼz&6BݽE}J޽k!4 CzoF> 467\ڭ$N9Ex' `i}*|vRЩB}]@7@}Xy.X Q+#F3A0g  H!t%xf^0p850 @.]!E7:/_W.AЃH>3q0A#jv d̍;ޛ@3Ag_xmܤ?1kyVci@X _? g߾8vV'mJwAkH/D?=rZu2W O`dN^;Y)HwoO|rծN>~`iTnWB(UfbP/hAlN.=ޯZE*=d׽qwxuA4rT^Vs18'N @j;:u<<]YȆe%@W{:)Og&`L@:͊wFYJu {-\;?~MxM{S@P%,ѿe/ÔSs೯}/xr#<6nP@k"?"6䯯~Wrֿ/FB4Ox@}[ EckJgue-`'q湌I>@_<[ GfHO@P-sj_D` ?FxmQFL8&udjH} 91?2l~be4"P6zr$/u pw*UOdW8?>7E^o;N @2U??8M\4U !H2l)J[/Rd T'g׃L[Y=%#GU @sπe-<LD.6!{+/tC@ ?iq^!%GSK.+חN(F[jB!֦J:Jo>v[by"nvz]e@ $a9p2L'8+"q7kf~&'>: /-~kUMc5n'<&jVy"0\lwv[\:7&$_jtZ{$g˭(Q_1v Bs&Go c `7s=nߖS;>>';C0\OngW_ª+z_# 22pfG;cVyquT?Iҝ lw?#0:GNjb?gAo#?W r'S0[$@:!!]CDuh4@Q`AǻCdgVE%E \0  .`4,^` ̈)Fw1d/'N_^x_MS_b@jzt˛8&wao\]w|{.O3sKB@gFTL(`UGۯPt*A nK)a4@=įABZYР.5,\ R~ U*ȏz@YM1tB/8{$6sտf,~a(ȉ`yG][ \&s%=&Pջp޳o\?{vŰmWkE@1z)> P,/d<>Q!T*Gs;ڻ7֛q"AaOt(o4Fd?E@: (mpq|^w0Ȁa/-1Zxyt@j2+~ƙ5^w@*T~x7.(-2 >(`2`* `c#] v,-=C"(왭K[a|Kz.]WMOo+OD˹0i8jBq_ DŽB@CFVfrcಿ͒g (Z܃Ж}֍+Ba:v=R(/PyA-ݞo倲kh`߁ 1PSGvҿŻe5pkU?yt6LQl?o~x/k(P ~JIXU-t8cotb}nb@_^oy<6|G@:eB1^ѯoX'leK !!\0#w1+utŹIlV%*_N$y~KsAhKA|W\Nbɩ`Ij)Jv)cwnɈ`!0n)^2gEe$4%5~@{ :`'m$RW+*quT~gg{qXҿ i<_ v>Wn_꾞FANQ%?M?$NG)&m^5¥]cRo⍋mn.9%@}ߞd ҿA d7/Nի)?׫I߂})dRY؉A*Uؒȿ6KV'yp(ۨ8؏I?eu ޶vMP\LswFMfxK6r?x]2f.U[W/N^U:{7}ǟ5QMo>@@|I usO*8@_e/DE_"ul݁  B_=Md! #6Ԣ%bCHͷ0C%mw)>C0^2М>߼z=VoU.'I._S' @1`rs73} Qs'NUB^\PN@l E?V1I2_'*@4 97gK7Iߓzjl{CB\ !Ӫ39UkͬGGIҗc7}t:9X` zJ@%4 !Rzۼf+ن`P/ [hƩ֌?eDp2 <.]b*`嫯*F2d q$Ƞ~6⦝/;@TTNJū?`1apYxFTfaWOC1 0~|=DI_QjTh~>  `BI3p(xfQPY*P*uptl95_6Tzr>d(ZdE<qYJv\UV>T$2nOx8Bu[J @' áf:@dnb_|jBz H5^v5@.thܜFGYX6D04['ousDmCX|ˇ$N%#y`óP'O?'"&UB/{U}}C~{`OkAf3?U\>9N~Z+ IDAT o= y l>$"*1"xD W~@*}?rOC 9s'hӨIZIӥ?S/ vhqPǘf]g'=:S2*OnnObFb&`"hy&༟*@q /ꥪ~>Ir)L ̃6et@puZ~n(l f%!nZV~Ӳ?ZEJm'=ZpfOh3L#rSg3tIؗi/Vͷz=A~/ d- ,ˠ8?I}ѺV7Ul~d1rXR37Z6K~@-NˍW4 ZHKn&2r~rGD0`@H[̦J_z2`퉸O ^ڷN-5r+!p#&5y=uiMXzo0Ƅ<[Ol{,vy2x_Ox@l`CE_v-st_GM@)5A% >Vu(~g6p'DPkרj `qEY_3'}](k ge_Tc`]9ĖgnҸpt7DPaUN@i' bߏn<ȪYɾbYw349]9֙-$NU9 r.D !3GNWH@zwS)ٯTsmj*Ήylnډm` @R_PofE1Cb"N0~!ƍnK؇a^Dom{fR/Ka'۪A*:~/枔kP׵uJAJo% :݀CY=YtJ G򟊜"\j\Hm`ɛ޺,2;2N- a/ؿ` bUa/D  0nr(5ݏba9zsDR a/.[Z (N:~?ɩ-mLy"?MmwOdh@h C@_U @ !xRWO'vTf!(яo4 }oiCfu~ʈ J+EKN(+ꢚJ}9uxQ3WZ@ s!7:d~ZdDKpY`8PjUZPࠤO?? %[4XPiW,&K묑* Q׷r哹؈m*^d}Sv-`bF@-tv%?>f `1GA>do4#V"%9__yta+Sf+}v[ҿe@96M F L Aq?c1@jb'˷邽^os`xL]wgalk`? %AXTe RxFG?nC(5su~Ԝ4QZX"++3?3k<;267nG`.=w C]<( b&/bo,|d$ϛ+B[KV$!泠6wb-r}'$y?|1sƴAT??X!IaLejs?&%KXB`TQBb !Tjz 84ZZwҚ?$0w͕oZQA42~4RvS{1_=stC a %G31 m̈́<4 @%0dL__hSrwa/$HE t%~ͥ!d@+4U %r=^ɓPC"ZV=M׌Ru' j5U  ua'&d @p2~pRrq`LlUpo8h:^$,IyE_zǨFy+Lo!`pH_>P1F?! XL'0|ZF\qu"uWחϪJ^Ǡf0W ( M`m<H?@xmK/H8S7IؿJ &)g+ nF~רK|08zokv-U @)qHFׯU3EK'ot) ,%t7lg7g@dtS6t^%øD` )4UuE!<@QJh?`rb( V. ϦCeO<޾Y5'_m}*֣>x3SDz5.ؿZ<&k< gPCU BC=S2:.B~`Cc]=5 PUQ$s+Ԩ5[Pe0 %@c oAP MqiB*f|+__mW[Xx LaO0zC.M&uYF#CXPL. it$ѹTX=8WJWǔ g1e) 뼰fI*@_dcy<J^n,%P@O<bvNd F8ܛa Jqeh6wU&l0zTuGY%Ek_X hc@ z ҿ*BQ }b\3áņޢO@]c_>@CosFYf#ۘm=1Zx7] #M@^[;_ܨ 2!|4TR:{J_\5-ΗfNV}~%LKk}v @`@sh=0zѯAE z@8FWG~fiűM 53?D@dR |%ЀvI=/?*/|R)]jf)btxȺ#Vf0}/ fCŌ="ٛxQN*LȲ2!@q?b: g# PJ 4rXM'F/Ytf[xyj& @cohƤ O4R!&?Вzෝ /ZIwݪ9ZSRPR-0&D#OPUz9ny,d2`ͧ-74YS)q2#d;‚ XQ~`)i!x^QT:}W<_'?@)Yerԃ-iQ (pO*--#M> >_bB) D,K߃__ N% Lb1`:]$[U*Mx~bo8'7HNs^z~*(C 'A_ пKFFswݝmgw@|tpxQ^\jos`^6lN&Lp԰b-D??M+UjI1H5y5uyA.[dLBSș1`|#ow'?RAGx"`9)w!+@Bd=)(u{TQT%P/ol턠~7bKj^b{[wM@gҿd~L*_>1?HηH~+{ 0'yRZ lu >ޤт PIB_KR/ :ǿJsxn1QSUܰb>X"4lt*ɀ'7K̍Zۖk ēBLʦ7_m~ƹƿ #g#I>@]GwRoo}@_w-6_Am )]I"6{ݾuI7NV][(X#34ߦAKSPB+mI]3ߙN׷kX2Z@<F?Ѹ29xMd3$`xBHӺbsp@~RjASAo S/۽>FbijJ-&"-|d]\O.Ll XHd]txt}ZkgXyd=]+Ȧ@[(_*jʽ%{w;*O?U0v%j^zwxў/#f) M<M@wT?m) do>O;+ =MonizA)~I-lhYOQ ilVKw%߮(Pеa@. 'O- K^s2im `#?HȘl~NoԷ?!IO](9Mu14`7U?6qyeIN? K@ -*gu-qyi CfQ1R JNM!%\wf#9"꿸!(şNJVⷝ}k_/, ?PUG/;-Gc.N\"/*I-h3z ,&'xU8w3cQP}שU!PZ 4]h|39bc^ q&_tm]wI2q`7>Vx9SXpy ^Ңۤ Eft\YeGQ7ziRR88K0.õE}oN&t_}`,6s`374XT{cl_,4= 1 ^?ȩwW$<#='(&b<]z& @6$~t`"'@S?a&{@kqOn3US ".S7B%?').%h .z"p[TsX-#.9N;g!hKI>8Cbp_nA"}8Xt )k ?{eNNdʽ9-#vSPIMrR#*" pIj?8 66ҏ{A 6B+%9cBWs_( )!17)#݃X^pMM*|^Ps]zk @Z >j@p' 'cۛgxht#ݟ,fGow1$fy A2Õ |Wp#tLa>~X0tDv2o p^m'P|eBGGC3Ӷ0@R_x*ݎ4+GE<G%=HV?m0@PUzФ?9HȂ +U~I"$6H?kR;O^xxd 1bAI^n1_%aAc )$o_$<#W*N@CJm@~~G]wZ~]tB'23]'!s۹`Pg<4@"$!l$IKvY6R_.PSWƿmQ  IDAT@?sc/[ДFC=R%KBH)' >B@P0N:<;HKE[k#h.prN&ғ}Į}7l7 {m.npT/@P͒$M.B!{:3p6J?j&/ŹoBp͓l >k8TQOl(i\Z퇽}N @7?BWgPi jzS!"i [hfXU lw97J!Хwd6]9( 8@wB=+zF [@XKqirpiG+ ڐQi S[\aX:bq\0:ObhZ@b`NZ%+e4=M9r^pftT (j {S@C~?j9$?E!f DZ0[6s-S`oSX'/j8_Uzz!W_"K`eI !p+ƭFWk?am! !R[C-2N8޾~~8NxS9̀I|AC'R"=S*@xu 4Qkf~dE+a&B=!CS;kՁN!ǀ_I>BŬA7 y!Ğ)'R߿J<0dYZ|Z;k42 qץݽ2E?h^o,:.j7S+fuy xY__4lp {BY0\ō/+t,B@c=HISCNיٙ 7!U͛?uc.1BECx;=vҭae(i7}_A}K  7*fe4h(q-т=1MBLbƍTO91k_E!گd jh>W_ U %`(wOVR_Oi 2 YqEyk,8QhTJ]Fl#kFnÛ+ov0֧BqnP"$  u `k\%{bSBMֱ3 VՂ4;jJ31ٓ_ѦXMB _ӠС-zDbYd/r ``q>H;q"KѿJWK_=y##W_D 0̓Uj. .8$N ?<pKEoS0T`õͭ|\ 8jk^ʉ} c]"?7lӛ5Mo/|OBτlzp|'ٿ=݄0 1=H2 4d L}Ӿ{Ts ha<|:Jc}'3"l\̣փ?7\FrbpK`;$UUJ@cN$ Y0@QTdV܂lfmܟ=|n |O_R~j @5 UQIT feύmjk31P )6?MmNS/ ='Fs!|!c@y g7Z pF |5J" InJ K YC=^6dU@%Ϣ/K{@#}_gORwui &V6 K_*S_@H_ o.2Y2n7tnĵEitX]ڜFq?Z߽JOC)bT `4$UsT 팄vHOo N3-!`i(nشpO9uTׇx@T9 n,yC;; Ђ$j|1q&㽨)6@?w_| ' 7lɨy;v̕@?,p-*qo@=_;"%NX޷bO_tP=$t*_# %cu92!v,}Kp | !2^@`xmK@(J FОz0@@d^ лxټ Y/œΞۯ `JyO33/nߟ&rj.ONx;&(S)Et?KiК܏폥^a^ZH tW@|xiy!6 7geVbVzmo Ce5!S!D@C@ߡ x@-!\A! *@G?'2 6җ;Hq)wR<:zDgBTQ|~,Qg*"F_H?; !? NW wV9$gS!N?=<%C_2Tm/ y!z^Xf9ks97 BhP7Xuٟ-J5P?"_ (?t@C"'߆Ŕ3p#%] '@ vE.嘀X[oM3[hݫ4QBx4ܧXӢx m̨8<%}H"Q BQs>rӰ+ޖ?I_;#!7RUz$h` 20}@VlgC B!Ğ }pg]"J]rVũ=J#+7+) B`TA{`ЦIyj`X% Jo(0\ :04dypc)h: 6@s-_,#_UK_?ҸS}>5`8a] PD`ߞ ̶bb @yT}NLSER6GJ [m̹vR֯ߥ[!q##ׅvqZpr$I=(_>gy/'= -d-j`)!pFZj~3| 5J޼I3P 8XB/ڿgvK{UjߞnrR~V/eYpi3&f|\qdZȴ=KB4@I 0AoA(ɩ>Jbx;:zWZ՛Ixv_ @#T?>w|x8PsxI"W?% H2_qQ cjAy9_K$_D%T;Tm->cDwPhIpIW?qg `J9k6g8%K_V"@y!:YQ M~{| !n/TjW򰱚c dZ@?CLB'\`kQ9'@z+SR0!Xq) !oӚ_8ܿM~}q_E1`g| @q 6Q|\`,U=ԃ~U*U{~-m ~%/b[|OM,r'pXLC` !>%>]9U p E ِ IH$M?o!ٖ>["+"&.Rqa2_?>Os2 A$PUFv$9JA%r?I<3_+bB=Ii kek[WI}?Y"^2n7R3^o]%R̿vem7xR(nݿ&^/]v;0p0J׉_i6&±Mr@O>1Qeэ \їprȷHQ__\ı/ ˲(}T6SKzd,B|fۡĭ'꿅1q8%נ<2Tp{`~Z x>WGqC`1^xb<9KvԷTc%hT>JsiJI79r݀%@@=7x!%9J /mp}k5A*'<펈#.$mRy!d+[t )g<xA(?$Q-wdW@Kݿ@zj`%Pp HzM3[B{~t\jW`)?G1޿\̆qP' tp0 ͯzoz4.+n-} A0Ay^R`%@xg0ZSc U<$*@S»4@<+^vgR |HUN"-! h[f͢6=?'GKJ6 a&?BCV#CVp"_ ޿`zLPՁSӥ5\n񞘿越`Z{ 3+)r|:txY~ѲP!{T d ֌T*@UB@F +IS?IFŤ|0Ϭ\9 z=? ݃ԸwrtW={YxɝDJNW9}FnCu"ǯk{O;\zǃT`H=HEQk_H!`Rr"!Dl_43V~3 ܲ2#C;vԇsfj(W@g;IF@{` iHz7r?I!p,y`O/&t(+ @wDxGBdLz2f 0&eVX!櫗FzbA!= dj! hjLn ܴN}1?b> 1+ V'R9U e?3)х IDAT*4{7ε$2'~UG{ߦBOAPTE%O98$`7?LIC=W*`ߚ6БW%t0p"+AV/.h 9'B6?RRPsmWnA*؟~A:;Ƞ#JMx"p ,X?B!(QOr$,@T:en4llEe}<Ϲ#(hP.B 3nTrTw&Q}f?H#"Pմɪ2FB̝Y猐5<:alw3EybɃ"XOwё/o,<&/C>'m`h{s==@ڽZ0P_{co9?7=Jg拽kM0޻|a ovovK~_}H̾ĸM:}OzR+ݛE)@PA h^QXL Y?8T]$ͨ~b6LJ5|T %m / GdNR~! R9_3g{.oZ!c8՚?qI Мyӛ/14GJ 4}1q!0t& g2Q )W+UH5`w=O=O,d@3|vԿ(xKe_՟V"j;^0< !;N7=HB-U 1jOθߝvV=_#嫥JSZ,?e) ڠ_ ^wtXߴzOwY'-Ryf[d~w }lkM~dFBc|='G jAmeǯ}.?lmWi $>+D.B.E:1 =!^^qmNR%P {B< _~a?o^d1~a'ULY7# ډE!eݴF'B?jWJw<.egD (F753ڳQk<h#S_SG?? wq.5)ӴO#`tg+`m0-mX=/ L' ~#q9 bR;_Тoxv h 7RW9K:l~q; i..OBL,_N\{}troxͼ·(W} `PJ;r@OWO1^~QoJ>YP QaP{T `6)Ԋy,Rƿx9<oVR@ _= JWggw{_ CKcdCB6z>[d@`C;7@(% Ђ86S`Nʅq>@wFi%ST23./UG Q76nu +ԫq~MU$E^s)|P\ hWI$ }IȵNo]ODTDԦ/Nd7+foD|݀3;}~\/.BMDO:3;Ȩ޿E`d0g5vB|ʟ{^|+R9Jd ùXIPK{6Vd~@%n3F! hWHz .;]ҿ+I^0RH ~_ ϾEKl{xUW'\_I%T'ox^Zn᧝&?ҏ;{W4^י[?s&?!"]tgҬU^+,:TSȏf?=R۳=O0b>JԣWͦ{ʩg ZIGjD3`&Ĭ嶹gK_Q=2?g :*o '+l.uIcy埓;ϗY|<P»A*h.V= XYH*o?'U/f - t"#7|Kq*@t.;[Z׆orO쓯stE&7ZFr׬~55|~8J5) UmѬoQEQJ5礜@|:MCRAgyy`DM"ޟ$z,Qh 2?>_?<߈@/}@q!cvj?RG`mS_\SZ P.zf-*2 xE/!2=+gj`;NQ& fq/~Q⏠^(me\lk,95{%~`9 OI16@F2LmBGڞsC󻒜X~R(=bY*͎}tEOS3 e~1? DZ텬|~|~ 3$~~Bw0g6mDI}x[?E8.!ݷMƇ !drohObI.G6L|tcm$r6>7`H <!#A'-į9&|ful\j> p{nuq_%@ {5xb'"607sKTq*@?~N.NZ@=Hw-\%.𐢑Pe96㵜ʉ(%$ 荜|_,S_`KÎ"Uf?.6OV!i7aES z?UJTM&W[/o'#;F6֩l؋;EQBɽ6_ x~U, 4hb+Mt2JH'^o;껤JgJ&RJZvE͖ks`*m~Q-03-{MC*@9TQ tnhڎ\\Y`fx&H_%?3U*o$ ޿?~?amg~W˞ ]Vzf G\1m&lBiiKM?VT?[89Jv-fB1/;+:=Y[K?^-֣1`_S~MQs#K8:LPx˧~_RTAд yyđT'OdZtHitpwL(b=A?&rb(qt~l!|ar}Kr}O9"tQ<,4Fy]2>r==Kf! S-wR9g 5zubh'ߨ.+'[5j,.8 =Ȫ>'zeB)aQJE~"]B0=OU9 ^M dI?aK;}y3f3?s($!ZG1eH( K oy|L*4XTv@dݻ,+<@ݜOC= 7N ͏]a4 Z^Z*X*Tl `5Bd<t}iL]lU@4x-JK:?xϮR) lYL)vION^BT n=Ix@|I|Q]BE @"CߦA:zѹ`%@)*QuTO{8lק3('^Il?yS! fmȢmn!"d@<Уps;i87nqR8j󾏻Zf6c+uf;ىAj .ڔ@{{Ͽ{2+1i'KS M43dHwbfƋUr@N֯t6뛊}UZWͿ)+o p 5X)> 3b,.pjl/MĨ{) o6o69Y[VОXt^GߌRzQQEx>C +(\'Ӗ35[;`|уdP^H#{o|$dKY,\˵B:o@~ xARu*yIf>_h d@<{=S+5.STw0:#{ * 2f7?8r7DRAT/$r2$젟"!$qy ߃z|0O:y(IV'+p6Ob  K:EwTէ6A6lջ`P1S_0:o 0x{,DLzQaEtٰשt 8!Ҡ@061abDx TfV 1ϮҗwRVeԦP>+cvgNj Wj{7V͘Z1L'+<|V:e`}(vޞU~KݵY *ACPzfŹ&@-{v70lWXe0?2z,C@kٙzk 0Nik<쮥wL!߈pr96%z-!V5X0pH+K̿1]8\1=Z@+G#ЙUǁz# b@4=q7PjȠKg[=:q tT1@`׬o+Xfy?' `blj^U_O@3Ȑ? {deQ MԲUԄ\Ǯõ}_U/?@/PO=_y#ˋ[}&.'3+2Fِyi3ԃ; Dc_#-=$џUG[c@xx^g}S\^Tg+g+\S߇BC;f`=:Gc !'_j]HڿR͖9IOar?|Fn*@B?XU̡O>|B {ˊC}xtoIѐ$ИFWFkR>IPfc"'"z]?8yT2ng.MG7zjJ٥݄̒wv\E M 0Nb㶵53JVvX_El@ת:bU6owT?SgE苪 -Jdи+)j)ACځf,-K6 2$'oٯ֜[W>,5S;Im^xںpIrFZv+wIs ( 8;Hտ@܉F5LGUy9;7tWC)ٶy&`-߼:MEY5R@OM߸m |˿*FPZJN/ Յ*${(@ km3^I  M>?MΟ;B։pQo 7*83r_*t6@ 4![GķHFJ`ό IDAT 9{;&ﺨ1:4-Ci HGMs;tX~K=ujL,z 2ڟK]*@a3Qw|L^oB oB2+T p^YxѰpMωN>] 0PعJ#n,/cpM7 T'柞O.sabOT .Rg ;BP {04)*^ Pb7&9/ h@i兏z}_F!_o%o *}jά1 O>'O_$U0 ޝE~lP<4F_$Bv4P%X- {#3)_>݀K(k Y~ nb1"c^%NQJ=rUŋ > {[- D`o/U'Q|3[Rj@R[6E0e3M%:VT 0?@|t,cUw[R{emU_3sVoJsA8{cL(+K*y*|:I4@9&t,Hr1}~,o6?@D*o hѬc$@E45Rv`)(3ɁTQԀ={[UAvnmhbp 4Nn*@ͿrYA$gW"@JuRWl*5:꿞 F~AaMJ x}q{~J+faVYbluBrd.)FvQdE^n~Jȣhf4so7=Vb%ه>o61Z#l>|dl}PV>(mK%OFKKMg{v'=]LqIV] r٣$- dcD`U nb^@]bC '΃F |||'] fh5G/x!W0bкy`?^x{{z Z5QDZ=?{x"Yhgl@KwAql`@J uE_J?pEai?Ͻx٦? ]qXҁ\T?zҬpbzJm}^B:qp-mzlVp~hpط0up02~ m2LN N? {װ2c{@]Jw@;,o7W;^~ t8Qw*| j(Yrrۣ &;\~`.]zImMJЯ5[m0r}^kS:xIW](9Zp֋Kn`$yzV  ?'*gBjT8#vWha^G}ŏCIL'|?P>˘5ʧ^ :۠5^zw, (\-"L+ dյӳB4 u}.3¦w cj`]i\fyM?Op'ܿloxH3ۯ6?^n u@j-_ `v@/Ķ Ω?FtUVkF@~.@Jw]z)P}֕Ⱦ˺閂A"Yn_ P]v uwq:8DKYXm@/pp{UD4sw߮mvG mwTͅ}p8+S;vtiSY>.V]&c@'vZ?&lJPSaW~@Te+>BKoT'mo `J; itKC<26?Oä3X4c@@?f I"qw+َv(WN,Y~~|l@7@氺t>tBʿ>]hqBv;$&6OX(? ,] Z i.@t(wz3QmB-[zQŃR߾=7-n+1 c;l)\ !ßB!Zf"O.vhǭ?<]^O #eTg-`[,=X^οc5{FRg@]8+G{ڙ1\B(1.>/|p|F%Y1Z0`ϛɛMހmۢV ǖ空9eLPOoOp;E԰Q~׿jSҔ?(9<9^/AYKK%`@/v_]{i/o&_v麻H,#_̮O#zAI?K]}Z䇟{u;B^'/tKOӳx9J 1~MX:Wvpq/\[T.k՟6jkwIQ9.O7Y~./}(%2w]l62@*P>dS--"/I˿>h! s ??My5o#M+9ul*=[u[w.KG{.??]WO27C{Ö8[IYFQIRhlK'O?'_ɽN5^ ُ{iD-T 8؊Q7B w,V5 a+p^hg?׌~OB'b a5Uu\Rq{~jMHC4Y_?W}i= KwE}T3.:ܟPP!!0B / ~Z_HSo`P D$@ٿ.0W&vi?5a&0,as@:Yu?,5~NO 0D8>Oe_Ӹqc]Oo&7 `l_F 5`OJ&k"3{](,~W(&s;,.bŽi6‰ou΀7@_ic,0>vvh_]7꩹v?ZXjҔt*@$96h< ]HwT8rs/^~>Ǿ?wKο^GkPˍ~8 j]L},Q Dk@- 쯺>;>-ˌ<s @*@2p`5\w'/O{ptمs.{~__N/O;XN˸ kuF"k,oMfjQx'9cKg_{_ӿ|5-~}x_;B ^G>9 >+rMxMp~^??rQ@mڑ}- 4Z_8s'Kk d?=gj ߓ;@䍀*糒{,\< ! Uf:kx]i'.@mWa?0;;=pJ Ԭ.ԟ+^_'2>opvßBJoQhNj_Xmi;7ŀ~)03R5| ^XLRFVxvsFTJ@E Řߚߞ)}$Z2j!ӯPszp{Us@]hZN`%JϿ}: jpsr''y@{zc Ïpp$(@# ^xHEJki:AB ݜl_Tܵ? ru*2@!=^Izq5B h ID7dη/իWH֮pQS9֯:UJk)N?近0T/5ҋPN_-: Pٝ$p{ŇiTՉz;sy7 T>h$?LUhCc(k'iM<_Ch^hX[U>6E` &̢PyvMɳ~~nj{y'?~z2ǫ^80I8a%@`@Qj?u.'rHhןG;6%y7.@M2)OM[hB Wp5羟9nփC fδ} 79to{!_gѷ S kCn% - +/V"* : WَS{!jCa@>b:|ČZ0 aB/?]j.C:|>5WV `|:-&d|:ujWȂKN?dCkj!_f @Vue ,<>ɲH^@JAW(Cg85O} x#5mW  C_C ! RxBߌt F.lG9>0SR6uJ4-.SH Qb#ٝd|_%s+i7\K= !? >Â5 ,|EWE^E!})-9m S@XWk/Bx5SO%}^Q1z̟,_E?ݸܸ1q-f2O7Cɇkכ.[g_$\/lҏ/o&GK.d{Tv `;.~}=\9r{)0MC/l7d;"9yG!mb[{LPu' !(L}b+0m u"=a\puo @gk#C/ïI}~ŗc.q%K2j3  h^ W/0to?/2@{j@~5QH$^D XC9.ǯ.`OyfF@5b `U pBs -. UGU]-ӣy} εDZx._!(8g)竹ʢ ,˿$_ݱ2dZk.Gq.._|m1š_ W?-9kq#;p?yٯٯ-hR'?'G?BY($.z_ٌW#Yp= ֝z [ =WG_S+Oy>ҝSÇ_M3U;U e~O7Qx4@lOT>g7v\0 H@)/{z+"n]}/pOO|?ۯ6cNHWy%ZX }:Pg@ך-[z_{X~OB_}ꏅNJ#{^2%x㧡psϛkFc9;EҴ?] p NCYDOt27YZ$Te~ {ӅD@#}^kMc7W@Ə{ϏvkrҰ2g ׆—T~.~nKs^wW6YNXt+f׺;\V 0GW>8)__sn[(`0xQuHvg ,S,Xt- ]�&{F`?ў*t#F^{ yk1%|n>-Hah8=S'ٵ @a/&2d/]w%g<WV٨/y7?6;G&W9A+?%釻`#'Ӥu+N_7ONBM;lz6WbjC[_bF0Y 6@DQZ7so^SҽB8|^?`%vܿ23580G_+o0s `Q@Xt`W=q/y("OKILgfy]rnUR/.y.I?<~rT}!k)_uB''X&=lUv5qwIo П7\%4TiG9CW  Z] |uuV翥54YR%` ۓ2*} 6|᠊hYkޒg],h됥 χ_K>'?Ojim{~[^V="N?_/ ;r`ղ*i?ਨ&]濝/p-&ȇk @MlOZ^\ȮPOק@jgW=kcC\G`>?4YLH=̧y?P_: @/8 w Bz/8W麻 Htuu&aw:tooluLk:7Z|KBnP()_l3b^&`/!X0`b?SLm?xf}e`dC+7Xxs}vǮ |~ln?p3;c PU+4^JZ9~]ƻ.˻! (,>\XPG/f7>ܤ_I,F~(|T$lML?5E ^`a^aB^x᛽C=k4?wWGͲy׿6 VHp<[q0@_}9g&eM^@&WKg<3\/n pB px VC0˭y-J?bN ˲wd<>#Y/o*}@?ɩ=3QNl5\^i c]T"`rO?Oҏ퀞|' 6߅i_H ~\^8g֩N(@2@o ir.ϧ{eFŀj3_Ŕ_F*V_;55g?\m?B_C tթ/<,i;Fט߃)ƛ(1_$' *>O?O WlkO~@C'yܚ 5 Hϵ_U%`! hQl+ykPTVSZ8|.C_q ]]`0 Ar=(D~- "V( _:5¦Cq`֖ҍwɴ̻oڎX0tgX _mkU_o6?M4K%}0e. Ϛ]@nޜP!js, ?F`1k@ Y/RIK;'f_͟JwS$hq^}[8.Kk i7yP%5V|jpb bs>Tۿ(uP0ߦ Sg&aU6TMZ?> yz]讓՗,Ugj6 VWj =bj?޿M3j]6&;[=Mn?G>D̬P@^} ~B>tk ?y' _J/)eT3(캈l195Ád( e߄[ H5|/ydpGWsp0.̋1{}`P$GO~p J;&ٷCn&_@oHfQ|jUg;BZ?h n{byw눮Z*";5m@tv?oS?>g afMAt:=Mґ]ukr} !vF -{o:N4d?"]M-KQ\T5B_R&=˟—1ٝ$p[&Zdb}60XWZ"Q|pw p럖ςH`3~zM/OjHl }_K ?mf޸{uw*@$^\zy:fee.h5D5Wtk&#k!8vafw 0;\妹El>@.{܊_|kإ?@/JWɻɻ_FH2/IwPMB&]GT'هn՞puO uGH?UJ~3ꏳ|]k8Y~Y_O{"5\Pru[:N },GOdl}Oh9 hL?g)ܜk<>YHB_w(=OS@@ܿ{m&8X?CTl /I kS4z}J(Ơ660rHM??vw[RG\'1;O+X `l`{:J Phg3:xvz.~P;n~ᮈ^/X>/lHuF&OOV UZhewM!_Pܗk1[&j?| =;&po% P1n@jY۾~vJ Ћ;x~_{+t+}|/g8j l4LÀ_`(&N~a iXL[vyzB@5mT>? 燫8LνPK?y $adyS >g-qˢ+5B8*s{3n!H xfso.|f;:pgo3''>M!{K;=eN !!ʯ6,, SQsw'D?LDdp/`=|,fT `>F4pt[p|1\K8rP0o6X϶].Va[@_MY1рeژ` 0`F?5P `*xXQ-G`8''2b(l=6{?NTvz&εB| f~ ,"}`ofp%[ /4_dL<C,҇zqms#-&l~Gtu{Y[<"r` 6ot?o8֕@|h 0cB]ޛ MG<]oS^F/0''_oN07Kg4g@M]p'!y=֫Yx&lG=ܛ7ʇg-;h̗{WBWfD HVbgg_b[Pa~Vh`y!Oycx{? /0/~QzI驧+AzoKB{x.;T?UМGz3 7?y%_@@06g,ԧbKs-qK{H0?@lz]-/O'ױPHH,2('qp;f7hvsQw 0 ~<|6/@?v$a] ] uyW~u@p>li %l IDAT`vRש'O7ٌ{^9lX;G kWy<ϧ-Žf5?Ds4=+TZ!A 01xqm 4=\HAIh6GmػiX0ZKF͵g~_Wp;ÉBc2[\̴ `6]_S$1@< LU ڗrG>9s7b('-` rCw3"`|ԺO&m 5PkE2X :@lBI?|ˠ~R'ѼOYRhf@]u2x,m,L]wzLgH ŵFǷۍ`a]dZ|B,?o6K$i? jWX a s]R>Sg1$zݤ PC8NJ9J8Iߋ =;+Lיh5ݧ /N u?#{ז D'9գr:*$vq[f?y;TtiY^ hx^(M^@> Ћ>jΜs 9$#:X?nBn#u_o(`*|ޅE"KO?CNRP4{8Vܼ? k+,&lp-ǦGmTuyWχ5{REl@!ONAٚ>xkG-v4w8>o@ G nw{ l7@(VDuX?+ -5LR0IT? dWoHo#iLO `TYXT"רH`@rZ*;YKU:"xwᓣQor'nJkP˳+φ9s'Q`rjݿPjl9g,Į?p(nԂPQ ,&`yK[ێv;pQٛ?A *);P\@ s.dT5+t-tqT\ m @PAld hHmG'n{lE5g-B 0}˷k I>.i4XɓKu^6({=DK`0@UQ Ы׹e*>\`f0urv+>> 'G~]3v(9v7J 'Uk!xo!4oYLGuX[?H7fҳo!>ދkKI8%}if"_Sn@vGp>O _+Z!p]Z#m xDt]滍5e|t~fZG-fLbg@>ʯ@<R+4@> >y_!⯈w|VH,2JfR3ϗD}ؗCŵ,"T?f3`aFK_!1JY@=o7GkEsp^~K5z{Bx7}3z@?Wԙy@'gIoJ@P jfG3Kr({uY*O~OlF- EyH(~ 7xx{$pw׮Bt~n~?r>]^&B8 |MϘ*K3.k!x|l 7`^v/MKϬ~L8ڛ_o>R$[ϒ[ZPHe|%/F2o7- OB/Xk"ӯ ЏW`;8L4ؒ HX?u` +4tm/.p1(y; a5o,at(hWG׏>7ˎ! NO`wP \ kSm7nEV$0-屜vbNCB`ն[ӧ,[I j`+h㉯`eOQ2?Z?!?lSi,bɂZ$5mj0lX-Ɣ?Y\B;XFkǏ:ueФ@SۛS?@[)w%`Q S Vu6hbV#417ڤm`=?(@>qPe+wx, GPP.)@MkcٻH.%f=:}>*=&c?zmŋk:] лk!u Z@pq5?0>(jOi]@4|_Kb+5&twɋkO%kN<2+^Ҭ 3u?)<7hyrzvd;`ص̿?C6,o W@U(k_} X `^\th@̓Q.?o$3/~q̉py2PXa@7SXJ2Rw%/m-V@~MB?D'?ux98-`l2Wt Z+O'?=z{N_@v0se5`,43愀4K>KG)Pq;34eλŵMziK Yog[c-[ D躻mO<.U3f,T`;`RR.f X ;`` 1X j`^u 3``'mX ;````>q vsKq`BX8eVHH t`*v]mgF~ῠ"ВbfP,B,ߔ2̔@@y/YSMoW֟")2UAK &۱~zJ 5P%^_w ?E!bv-o`!h~;7Kf 3~Nv!gQ!ߛ~,J)r YQĿ#?̋?0; 0?LM/ -gX}d,\!>%[ o_J 8TvX Pwį\wAS(C5jי(}zs+ai^9:"IbՏrp#8U/~m#{/s^IϽEԡ].rCǖz_FQ4Cn.K~DU/Wj/!ZpOj 07`④+G|xN貨hUsׂػ*v.;3VTΩD^Ǒ0K]`<Ӕ /pX=~u #F`<ӂFA=m9ޘ"x;>Ӻ 7ux^<O=`wzM (3?~,Z(@o o1⥖8# I`]t$CɌ|.r_d vQU2\ڢٚt CiͧC1@@ӧFObgV /-Vw(zڻ.d6Q6MYv<5<ͶxtFV@oܱi;IPz #nwcm"9P&t~M(:`1/rs5!ޯȦ"; ;5;Ljlw _~%2摌JWKU5zhv~E+8/LuŃ `ͯ2[ŎCu|m*qo#xD [G>q:pUxpWY\)- ~90EXv8Cr70#.:`/-Fon{:コK/Ϝ wyxRh{e?,u=@XF3qޠ;$?qmՏz5Cנj Nśý (:r<?5D!V(o=7 c&mj*⟅z3#S`G1S`]j.TjmqR߸4 p2Ќ(woǭ@@J:H巃ܖEC,e]ǦpQb,.x 0'{ w.ōJG=lg|sF+%m v1C8(`ZM>ȳ=p Sm _eJl3u@l%[03s3C]~8xQ`f 2!5}+gh6 *X7(Ӛ6vo<6mgV+`O՞*m{}v+hs`'KB_NO/3/l$U4x[?;5zV|o/;\>wy?-˱QxͿ}%k旴kSU1C=1'׫UO,*t+YDX]z/egWRNk{ 6h J5*yˬMtg7eRb?Vz)9gbw ;GUh O`_8NUQZ +O-kY1>p4`9%Ns]֐,o9H_꯼`ZxΣl<RiG2ss7a:$ H32k W%M#W|acrW~b  ȯ4|A:}Ժ8޶7ps gv!y;ML9uۜ_ G }8O{:x<2p߾=LSX@ #nN N-x'!p}f7p^|X#VcKYk ^3X`%`%H@`9; yWٞ 1R4ZgQ!,2SO#:m'0*?ҡvsIDATO>H+ ع?eRџv}w(HNs4`{\跺ĥ,;g04vOs9ma Z`]7 ^43R'+2bVn7 <`T3/6z~-zޙ`z@J0cn>[>0&7Q4<=R'n1@eor17Rax(r?:hL>TmT<(|Yn^X+{D2 Ɔͪ@z؃3rr8o/#{2I'NzO _h8>z <bK :h{7X6ɭb7>n5˅ W$˅6 uQ( IO7oX^}񆙵\*G q*Dg5 Xq\ ;CVJ`q Q5 @*V5 $w$V@]>*R}`+IoC奄bDc/B-OEzgt& %S  F.? SʛWW7_֎")BIܢ4hC rPI`;XE 88%b8”bP|,E\84`́ 1'2T7,56XB LQC@&VH#H6~$ZRy"I`L6?Eݶ$zdhJ-~Q04"Ph+@cOw@ OQBr=I91 åorw <`-cjxv ?~z @e HI 4큆 { &E+Jಟ:ۢs+6t  H4 H4 H4 H4 H4 H4 ٳAIENDB`qmapshack-1.10.0/src/pics/noMap256x256.png000644 001750 000144 00000046666 12406046130 021127 0ustar00oeichlerxusers000000 000000 PNG  IHDR\rfsRGBbKGD pHYs  tIME 8-+riTXtCommentCreated with GIMPd.e IDATxw]Wy]kS4QŶ-ɖ+`B  $1!&!@K` ئ[euYm$iz;}>gd>9u?{zׂ0_A4_o! DH2uG4( p ~]/ K"prF s벫, ˎBЄO(tG!)H@PA< ]F!0rFEh8 1niYXKjfT0+A}C(V}! .3:gp M_o tu22E|P \ )(Mѩ=כ .G2V!C22g~-k5l,܅5Dc.ѸB>OvP Zec G8~9|TK` Z<,?ȑޣhࢍ/1,"9\yoX¥ T:H Pv86D7 É|ǐiRy!)Qbyj:b'҅P8VT&˒z!ÁQ ·v@)MKe\_5d$\C]pd8O'H{П,e`0 :P !R'OS<9>M"\ߓc4#+C *G$XZӯkqskؼ} s\<Rp&@s4%!*I&!P>J+tJ ?a(J X/F> +V$#08# "NB[ʠr50`@6*E9\ko]oM7,$! %*XX~Gbh<@!-)JxA!$BH,a!F#E!&d( P_6̩*4{^bsءkyd8Q{#qaUHwnۖ m$lXK.ZuhB 䱥CĎ!\45rp,!$Z.ĤS#BXQU@i-mlicaxN nh Uʋ/vϝDYLc!E!AF>s5w_+^XB00β1 VςU PB#"}hḘg|8e}!$;k4^+y? $UH,I&pzosBR ?}`/A[?=ƙ2_/,V-B:|$wm=ܫx}3}yX7-E5>Jg{B Bͧ174A:t9 ~ƒvdrXxA@yҟ(ʓ}4--h18iZi]=o^%Ǐ d=pUg|CFEK*g}+gȍ/&W!ja>4% ,9/%mn-RN0?cE hn_"&1f8ӏ|bnH d| ]q@s8aZQno\'$dKan1Rc_AZcfQEF:69hu`;o|: ma}Nn^%e .KÉ~ XP EĎNE$"SH+oܵ|hH"G6?9f5s ?W9FraPeO@0B3\&Ѱ}n| X/g+Ir(͸J񡋒ޱ\bN Y ¶p!`]Jd  *( 4J,ʰ^3'pjD1 })[uC=nK DDpgkvwRD>":Kֵ}-km E~׵ҋR#uQPxA x+J(@|BL?#١pg*2̎gXZ/8Е1>\,u[zj!p]Ad^l{Ѥ R+%| w<7n8=nk~G#/T1HdG "--3(u`h4 R^P[²:ش)Iyk* L4`F'yaׁ \{J~>ΰ>7eE]/@J%X |@ϒ.:QSe&bYT= I1Ӱx73.v&(C/w3;EZǾx'фIqm4:/BR+tT@P:EKM Y/K̼Oib͒1? k\SR#ؾm=yN %G:[>lb^3V=Bu7.S}Ѹ>64f˼z`5dXbNY?] ǎ2rp [TǪגrfGA:KZ+<Pm`]s=?:GDyΣ˜@tJdO%`eDB:<\§: yxGsf== V1~ zjꩍS.QO}hcw}%F!(PWkW2,ln>HT[:Ꮨ!7x> j߽yKu zpAw-'v}h @mx$AĎS*Z+DY.Fs#a]/K#䩏7y&GOUkImV̑[=]!ٌ< f"PD>{XwlA>Ej~>tۻ8^L|Pԋq-X&ĨSk&^?aHQ'`f<2ykZX2k9ܟ19J5U ,Sϴ<6XD$#;=L!_*/ 'n7p']?{j9?wA3|H#,n-H8vtܨaaϹeJ #4|&15$sCs%b%b3| U<^sj,*<ϐiaUǟ: 4D,1E0oEHηm-#pxN?w}M+zR_,&f׮&тv8}ɬp4|cg^cY/!HդB^lR~1~eqeЋm1+`}> V `ּz>; ,3cO[Wn7n 2,JS>JV|jWQ\mE9Q']]!P"'z @MrK.:GIXTTH@[̫]ώP//^eұ4B̏3iEkAn@iDB81RQ6n$%2gbRl|ҙ!|򚍸Cǟ ?~`@71t!]/p<׬](zSg ``&Qk=ڲT@K_#?x9[9dFxw!k#ؖ;4LDe/"H=&l *1!"@4$l T@V5R ?(pct%/5D~ϼph'0 O3tnc6>7v}3{vCAxko!R%]h\p ;8y_fohj^ͮ?yWWQ6xgJ dR c[6 Κ BF{jF>@.7 ah囉^/*%K|GuT$[8xr[ޥ9b \r>͋rb'7p>‚%Wz#_϶?nI`΃+6i = pGQ*@Jח)oP @JY4zQf2%_Sg!ρ8ZcC8-=p> F`3AJ;޲[Y̾.8˞} mrg9 O sZcM@]b1F A}4yAfڀ tDz``GTX\ŌE(6*9x8_~ؙؼaӭD i5X=B BeЛ Nj`nn1ˈcjlZy'/dY_]~&~4eia8!me~"F݌ _5ōrd_we% ='Ĕ!tA#n\D*fҏm} d> Uu-SKxɸeѨ{0̯UP xqN!XrG&P/N ,,)cDUO) lr߿<} nlf~""cM+7U,ͷ(4n!٤*@zvYJ'V!lٍ%5PrSԀL&T2 4q]G8A,jꪫI$N$.n*(VV}¶\AIexlFp,kM3S[tzP! 4R^'(](D˖#vm@E0pA&4 q.c$65l%36 ]R%=8PNS. %e4smm{hsb,Q%DRF +E6#SS*F9EXg,DZa_آu=D.;ĺ[vO?|g9Y,=^yhi.@oY+* r F5JB ^̝o޴cl[2kZNGO9J(X=XiM&\EWQH&XzN%DR+L>hzC=f$b,!PZ!$)t,, _>qC E6ǦW|=۰lgc BJH!ZM󼊰zõo: Ɏ:M=!.8qYRn~RT]$G>FZ608G~p16D=PL †,PUS͂%8~I~,)hu1X1e )mR̞FKG (Jsi\U[eޒDI]uш` ]$eq8V2r8%8ì8<];uyAY٠rX,nEmCXso$n,8ؑn4i; O>^~8A,[(QeT1XAiɷ+ޞB˼5k!PicXp" P9}LiK./Ka88D-G~v;|XLIӹ˵A(cx_{hj^AEf 3g)-k5`W fQ%u1FG9a`Y i'@+^g~=VMH"ш,34rL/< njmq\ H%&7`0W ,8v|]}3ϲڏ֠ɮ@(~B+RRޠmMT]R,YF6m`XBPx |m?v]ʇTҖH[RcR3i#3Cbl8GrV K+u~YNO?ʦmNn*&fq^3p}'Re;. 4 7q"\H9k8Fs𛀏>Z(o,߇d#_K0*@U!R P"*`KHĪhIG4we_v?k /\kW*zʅ 5ap`bӁB穭_u[׉UhH!|oy}8{ѓC4R7n|wH m[83p@i0p|?`?mA<Ķ<_#~uۍb2Tu_qM<굿K"^EO~iX_Gn~xv֮7C*is8͈ŀf{9l`?Q dju؎ +GgpVzTTy_a鰘9wDPXc A5,+:lˎc^~'iշ1ƺfjƱ&L, <\Xё\ec|k ˆO12 B %~EKJm eSȠ<([F^pͣifw߱{o*VWa%pv3(a`@&$o(C /(3=#yH͜?3YV-=Y^|_L3OOQ K;l2Cf&|m|_wrm ([N;,7*,Y+Kt+͡qAhX.?cM}I[r2MWhx {ZM0_t8`q}0ٴGu˜E3go%h6K M_֌PsAa2z֮=goI"uyAT eh476~n6TcC #6VQQ^HRBOS,0 cVKF:ܰh4 RaYoydy,&:2YTcLyl:/3H@*4+o{^D$?/54-aʷG$!t' ID Dvυ Q (g(KAZy曛װXLn)g?Hěi].zuQ g~1U 嗥t+V kM&;3?ki[:@CMW=$yd ǓDZc!Ūh=XǺ^ p:l~BYFD=D=hű}rign t<-gf^7PlC?kĒdpֱzg54oqleⷱq9z;<97fSU2~,TQ(e%(i䫏}r<ٴ#$#y(H .1AKw!Z㥎_uF#5>k/lK%Wzz\syqYDKNV Lw(QSO}ڪܴ|PK}aqh,Ʋm4a;`U{=6 &u\jd|ޑY7ٸg-[LT\ҊX$۰Ȩbɔ7._!ũ#}Ųaij&;ozL D;7~Xuqa#O.2Wk[0RzCL?E]1mDuai?G}2v+V#7_YdÒƞ˚rua}NOrt&e,/*$!Vŷ agwoZ`Yp@#op!fgFS,idԹ :9ַq*B#6|U{JJJ72&\3ܳ ҡ{x*Bth- 7Q, s[:h1CܹK6~Soqym |Gf7.p~E9Z/>~g;ōw-j @:ūM B*_Lg]!Փ8iUC:BY7IuVy0K,_N(z$끨|f>aY i n W_ɫ?fOSĜJ+ǎp<~l] stɯ/?TP$ç (;Xvw|?DM))Qn[_|g>A0. G3?Os M6@c<]Fۈ;! 8ٮ$*S4ӹN~ZaEi1uNOyy*ݚJRpXOKS,Y2 VZy7>lK-si ʩ`n7Na'{@<4ﱒ?50ݖRH,awLaI}TC/gam1YxÚ`WQ)"ng:$ 3q`vctݪ`S^Ǟb>v:±*s8T/Rꐶ{e\{<@S:CǚYk _U (*3Pt+\t R,=t^7zO=ɞ83z5Xp,-eQ BeʛS Sw Y䢸eWUan\S/<ֹ7.Ú.@ ^T`JrcgJO0M墀E2:[}JpmfQkfm$j'T2|*MTTnF?v1SpvC=_ƅp-^fѺ__y@SbD00ЪPϏaRGkw^Mg ~eůЗk#C/rhyϻ7.\ lWbj?d}pU_c; 1g;@ʜfPrzp+Q;zΙ?쾰Ze !’a Əss_L,7CW,: ōˣ/ŏw҉fšPo1Ԅ҃0A_v|d@~DQ\&P*mԎq283AL ;yJ5,azsbG#E 4̭ c8*+V/2!R<{YDRbmJ#"xð.,չSZ 3Hx׆ H4(7'FGG#9>rUaeCE!@ V@'iTx #$8[Yw\ʺ08X&g.4џ/4E41`l?@^cߖ$V%{N ~w~&?:OM l% *X@@ L~E(4Z|QZma0&2Uع*)-80e7n VvS@|+Ҁe#/(` ſRF@"Q(|[mh`fH ؕGw+_Y?;û>r#nZXŵpC"p$tfzsW?ޙuwwHM$XdYey'͊&Ccip 0/mZ(ZijZ)NI$A8jX2I,[ lŋdBj g̽arp2~{}W-|eT`ޟV,X[XdSYB¥ˀP^7Kx k5.s–[,o#.5X 6ޗ)a{*ʳ t3C> y4:qM˂LG__J&rՏ311kXNCPP .q^>+CܐC,W}xw'tڠys;gnc]{6sӧٙ4s;ly5T0J&eKoXKZqPQhB,G2,mVnMn(SS'8ssz0;@I ӚE*5)?hT)( l; ))YY q@G@ o_t p8<&~(}[egdwU᠟)&ƂA&«L,K&ݔNblwm:= &oFc}"ǎ]EϔL=pa/jrL,@1N'' vvlgEnzTy>(8_BmwH&P7.ߎг}wˮ.na-m4g@^\ gq,hi@sgMl6yh\uJyqN.qyp +'] ó\w1&/ИB= %pw7X T<=!y6vʥ=ÖJGw3[hj&MќMiJ`yڹeA>Wd#9L3<4LQ a*J\TL_n鼕+8" k^s q&A=D6@HA@$RX(:إ) Ι>$umlr  5R.oC,fzҞgtM(8OWNe x,FJDINo(O:BJGKW.omcw$[-RnDQX M.~$\08ဥ@4!Eq@S)T]W3῾_}-cZN)i4pk W` l@ ,!6Np[-쌅pyF5zFiaMiP**V|-smqj7?q'.c&7 -bˋ:o\,0~Ȱz@"_|;v8B)? fB$rbc{jT{-_:_@hQsoڙɍ'^?u}tw*Brq2'C/`Y|0%+@Pµf V ̰{7Tv9eU$ArGph ݐ`-#Y4<@^E S )Д P\|&=E`|(SfYQs]PgcQ8pgc}V E<0Q}9@_L 2`@44$-L'TjHvOud.L_&Q|e3LLj7br_` vt`=&I# ntcm5\k\G [C޷n7W5^RczdJ䢼֣ LSsLOs%I'yW]npeUTԷNrPL n`D/#EN#Ozdp1u꼾fgA;e|1<QiƢPwoiT|머=JR^b\S5|6#s5ja c+{]z_i4@^Un'hQ:+Pnvb:iW*WcԺVCg#ԇR6MmPƌOFC ?o!D"٘r \^?jr21b3/ D1t4ަ陶v"r$z1' D1"tg_x# ^^aG]潵0BytNبM=;'g>Pl!S6wmz[uHߢ|x6d! t@`}LL@\pZ؋"P_Qj 3VkL]&E8ʎRIJiǩ2S5 'e ,dD͌wP)["%/QٌjM(oI^. **********************************************************************************************/ #ifndef CMAINWINDOW_H #define CMAINWINDOW_H #include "ui_IMainWindow.h" #include class CMapList; class CDemList; class QLabel; class CGisWorkspace; class CGisDatabase; class CCanvas; class CToolBarConfig; struct SGisLine; class CMainWindow : public QMainWindow, private Ui::IMainWindow { Q_OBJECT public: static CMainWindow& self() { return *pSelf; } static QWidget * getBestWidgetForParent(); static QString getUser(); virtual ~CMainWindow(); void addMapList(CMapList *list, const QString& name); void addDemList(CDemList *list, const QString& name); void addWidgetToTab(QWidget * w); bool isScaleVisible() const; bool isGridVisible() const; bool isNight() const; bool isPOIText() const; bool isMapToolTip() const; bool isMinMaxTrackValues() const; bool flipMouseWheel() const; bool profileIsWindow() const; const QFont& getMapFont() const { return mapFont; } void zoomCanvasTo(const QRectF rect); /** @brief Read the elevation from DEM data attached to the currently visible canvas for a given location @param pos a position in units of [rad] @return If no elevation value can be found for the position NOFLOAT is returned. */ qreal getElevationAt(const QPointF &pos) const; void getElevationAt(const QPolygonF& pos, QPolygonF &ele) const; void getElevationAt(SGisLine &line) const; qreal getSlopeAt(const QPointF &pos) const; void getSlopeAt(const QPolygonF &pos, QPolygonF& slope) const; /** @brief Get pointer to the currently visible canvas object. @return If the currently visible tab does not contain a CCanvas object 0 is returned. */ CCanvas* getVisibleCanvas() const; QList getCanvas() const; QAction * getMapSetupAction() { return actionSetupMapPaths; } QAction * getDemSetupAction() { return actionSetupDEMPaths; } void loadGISData(const QStringList& filenames); const qint32 id; protected: #ifdef WIN32 bool CMainWindow::nativeEvent(const QByteArray & eventType, void * message, long * result); #endif // WIN32 void dragEnterEvent(QDragEnterEvent *event) override; void dropEvent(QDropEvent *event) override; private slots: void slotAbout(); void slotHelp(); void slotQuickstart(); void slotAddCanvas(); void slotCloneCanvas(); void slotTabCloseRequest(int i); void slotCurrentTabCanvas(int i); void slotCurrentTabMaps(int i); void slotCurrentTabDem(int i); void slotMousePosition(const QPointF& pos, qreal ele, qreal slope); void slotUpdateCurrentWidget(); void slotSetupMapFont(); void slotSetupMapBackground(); void slotSetupGrid(); void slotSetupMapPath(); void slotSetupDemPath(); void slotSetupMapView(); void slotSetupTimeZone(); void slotSetupUnits(); void slotSetupWorkspace(); void slotSetupCoordFormat(); void slotSetupToolbar(); void slotImportDatabase(); void slotLoadGISData(); void slotBuildVrt(); void slotStoreView(); void slotLoadView(); void slotSetProfileMode(bool on); void slotCreateRoutinoDatabase(); void slotPrintMap(); void slotSetupWptIcons(); void slotLinkActivated(const QString& link); void slotSanityTest(); void slotCloseTab(); void slotToggleDocks(); void slotDockVisibilityChanged(bool visible); void slotFullScreen(); private: friend int main(int argc, char ** argv); CMainWindow(); void prepareMenuForMac(); void testForNoView(); bool docksVisible() const; void showDocks() const; void hideDocks(); void displayRegular(); void displayFullscreen(); CCanvas * addView(const QString &name); static CMainWindow * pSelf; /// status bar label QLabel * lblPosWGS84; QLabel * lblElevation; QLabel * lblSlope; QLabel * lblPosGrid; QFont mapFont; CGisWorkspace * widgetGisWorkspace; CGisDatabase * widgetGisDatabase; CToolBarConfig * toolBarConfig; QList docks; QList activeDocks; Qt::WindowStates displayMode = Qt::WindowMaximized; QByteArray dockStates; bool menuVisible = false; static QMutex mutex; }; #endif //CMAINWINDOW_H qmapshack-1.10.0/src/main.cpp000644 001750 000144 00000005032 13216234140 017135 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "CSingleInstanceProxy.h" #include "setup/IAppSetup.h" #include "version.h" #include #include #include int main(int argc, char ** argv) { QApplication app(argc, argv); QCoreApplication::setApplicationName("QMapShack"); QCoreApplication::setOrganizationName("QLandkarte"); QCoreApplication::setOrganizationDomain("qlandkarte.org"); IAppSetup* env = IAppSetup::getPlatformInstance(); env->processArguments(); env->initLogHandler(); env->initQMapShack(); // setup random number generator. currently used for an // unique instance ID. uint seed = QDateTime::currentDateTime().toTime_t(); qsrand(seed); // setup default proxy QNetworkProxyFactory::setUseSystemConfiguration(true); // make sure this is the one and only instance on the system CSingleInstanceProxy s(qlOpts->arguments); QSplashScreen *splash = nullptr; if (!qlOpts->nosplash) { QPixmap pic(":/pics/splash.png"); QPainter p(&pic); QFont f = p.font(); f.setBold(true); p.setPen(Qt::black); p.setFont(f); p.drawText(400,395,"V " VER_STR); splash = new QSplashScreen(pic); #ifdef Q_OS_MAC // remove the splash screen flag on OS-X as workaround for the reported bug // https://bugreports.qt.io/browse/QTBUG-49576 splash->setWindowFlags(splash->windowFlags() & (~Qt::SplashScreen)); #endif splash->show(); } CMainWindow w; w.show(); if(nullptr != splash) { splash->finish(&w); delete splash; } return app.exec(); } qmapshack-1.10.0/src/CAbout.h000644 001750 000144 00000002204 13216234143 017034 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CABOUT_H #define CABOUT_H #include "ui_IAbout.h" #include class CAbout : public QDialog, private Ui::IAbout { Q_DECLARE_TR_FUNCTIONS(CAbout) public: CAbout(QWidget * parent); virtual ~CAbout(); }; #endif //CABOUT_H qmapshack-1.10.0/src/version.h000644 001750 000144 00000002264 13216234143 017352 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef VERSION_H #define VERSION_H #ifndef _MKSTR_1 #define _MKSTR_1(x) #x #define _MKSTR(x) _MKSTR_1(x) #endif #define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR (VER_MINOR) "." _MKSTR (VER_STEP) #define WHAT_STR _MKSTR(APPLICATION_NAME) ", Version " VER_STR #endif //VERSION_H qmapshack-1.10.0/src/IAbout.ui000644 001750 000144 00000034325 13063701351 017241 0ustar00oeichlerxusers000000 000000 IAbout 0 0 700 600 About.... 150 0 150 580 :/pics/about.png true 0 0 <b>QMapShack</b>, Version TextLabel 0 0 :/icons/48x48/QMapShack.png Qt::Horizontal QFormLayout::AllNonFixedFieldsGrow Qt TextLabel GDAL TextLabel Proj4 TextLabel Routino TextLabel Qt::Horizontal 0 0 Czech: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Pavel Fric 0 0 German: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Oliver Eichler 0 0 Dutch: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Harrie Klomp 0 0 French: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Rainer Unseld Jose Luis Domingo Lopez 0 0 Spanish: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter <b>Translation:</b> Russian: Wolfgang Thämelt Qt::Horizontal 0 0 Win64: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 0 OS X: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Helmut Schmidt Ivo Kronenberg <b>Binaries:</b> ...and thanks to all Linux binary maintainers for doing a great job. Special thanks to Dan Horák and Bas Couwenberg for showing presence on the mailing list to discuss distribution related topics. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true Qt::Horizontal <b>Contributors:</b> Christian Eichler (qms@christian-eichler.de) Ivo Kronenberg Norbert Truchsess (norbert.truchsess@t-online.de) true Qt::Horizontal This software is licensed under GPL3 or any later version © 2017 Oliver Eichler (oliver.eichler@gmx.de) Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() IAbout accept() 248 254 157 274 buttonBox rejected() IAbout reject() 316 260 286 274 qmapshack-1.10.0/src/mouse/000755 001750 000144 00000000000 13216664445 016654 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/mouse/IMouse.h000644 001750 000144 00000005020 13216234261 020210 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef IMOUSE_H #define IMOUSE_H #include "canvas/CCanvas.h" #include #include #include class QMouseEvent; class QPinchGesture; class QWheelEvent; class QTimer; class CGisDraw; class IMouse : public QObject { Q_OBJECT public: IMouse(CGisDraw * gis, CCanvas * canvas); virtual ~IMouse(); virtual void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) = 0; virtual void mousePressEvent(QMouseEvent *e) = 0; virtual void mouseMoveEvent(QMouseEvent *e) = 0; virtual void mouseReleaseEvent(QMouseEvent *e) = 0; virtual void mouseDoubleClickEvent(QMouseEvent *e) { } virtual void wheelEvent(QWheelEvent *e) { } virtual void keyPressEvent(QKeyEvent *e) { } virtual void pinchGestureEvent(QPinchGesture *e) { } virtual void afterMouseLostEvent(QMouseEvent *e) { } /// the current mouse cursor /** Each mouse function is represented by a special cursor. The main widget uses this method to query the current cursor. */ operator const QCursor&() const { return cursor; } CCanvas * getCanvas() const { return canvas; } virtual void setMouseTracking(bool enabled); const static int longButtonPressTimeout = 400; const static int minimalMouseMovingDistance = 4; protected: /// the functions mouse icon QCursor cursor; QPointer gis; QPointer canvas; // the current point reported by the mouse events QPoint point; }; #endif //IMOUSE_H qmapshack-1.10.0/src/mouse/CMouseRadiusWpt.cpp000644 001750 000144 00000010011 13216234261 022374 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/WptIcons.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CDraw.h" #include "mouse/CMouseRadiusWpt.h" #include "units/IUnit.h" #include #include #include CMouseRadiusWpt::CMouseRadiusWpt(CGisItemWpt &wpt, CGisDraw * gis, CCanvas * parent) : IMouse(gis, parent), key(wpt.getKey()), wptPosition(wpt.getPosition() * DEG_TO_RAD), avoid(wpt.isNogoArea()), start(true) { QPointF pos = GPS_Math_Wpt_Projection(wptPosition,wpt.getProximity(),90 * DEG_TO_RAD); gis->convertRad2Px(pos); point = QPoint(pos.rx(),pos.ry()); cursor = QCursor(QPixmap(":/cursors/cursorRadiusWpt.png"), 0, 0); wpt.setHideArea(true); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } CMouseRadiusWpt::~CMouseRadiusWpt() { } void CMouseRadiusWpt::draw(QPainter& p, CCanvas::redraw_e, const QRect&) { QPointF pos = point; gis->convertPx2Rad(pos); dist = GPS_Math_Distance(pos.rx(),pos.ry(),wptPosition.x(),wptPosition.y()); QPointF screenPos = wptPosition; gis->convertRad2Px(screenPos); qreal radius = CGisItemWpt::calcRadius(wptPosition,screenPos,dist,gis); CGisItemWpt::drawCircle(p,screenPos,radius,avoid,start); } void CMouseRadiusWpt::mousePressEvent(QMouseEvent * e) { point = e->pos(); if(e->button() == Qt::RightButton) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt != nullptr) { wpt->setHideArea(false); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } else if(e->button() == Qt::LeftButton) { mapMove = true; lastPoint = point; } start = false; } void CMouseRadiusWpt::mouseMoveEvent(QMouseEvent * e) { point = e->pos(); if(mapMove) { if(point != lastPoint) { QPoint delta = point - lastPoint; canvas->moveMap(delta); mapDidMove = true; } } lastPoint = point; canvas->update(); start = false; } void CMouseRadiusWpt::mouseReleaseEvent(QMouseEvent *e) { point = e->pos(); if(!mapDidMove && e->button()==Qt::LeftButton) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt != nullptr) { wpt->setProximity(dist); wpt->setHideArea(false); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } mapMove = false; mapDidMove = false; start = false; } void CMouseRadiusWpt::wheelEvent(QWheelEvent*) { canvas->update(); } void CMouseRadiusWpt::afterMouseLostEvent(QMouseEvent *e) { if (e->type() == QEvent::MouseMove) { lastPoint = e->pos(); } mapMove = e->buttons() & Qt::LeftButton; mapDidMove = true; } qmapshack-1.10.0/src/mouse/CScrOptRangeTrk.h000644 001750 000144 00000002620 13216234143 021764 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTRANGETRK_H #define CSCROPTRANGETRK_H #include "mouse/IScrOpt.h" #include "ui_IScrOptRangeTrk.h" class CGisItemTrk; class CScrOptRangeTrk : public IScrOpt, public Ui::IScrOptRangeTrk { Q_OBJECT public: CScrOptRangeTrk(const QPointF& point, CGisItemTrk *trk, IMouse *mouse, QWidget *parent = nullptr); virtual ~CScrOptRangeTrk(); void draw(QPainter& p) override; signals: void activitySelected(quint32 flag); private: void selectActivity(); }; #endif //CSCROPTRANGETRK_H qmapshack-1.10.0/src/mouse/CMouseNormal.h000644 001750 000144 00000006617 13216234261 021370 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CMOUSENORMAL_H #define CMOUSENORMAL_H #include "gis/Poi.h" #include "mouse/IMouse.h" #include #include #include #include class CCanvas; class IScrOpt; class CScrOptUnclutter; class QMenu; class CMouseNormal : public IMouse { Q_OBJECT public: CMouseNormal(CGisDraw * gis, CCanvas *canvas); virtual ~CMouseNormal(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseDoubleClickEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent * e) override; void keyPressEvent(QKeyEvent * e) override; void afterMouseLostEvent(QMouseEvent *e) override; private slots: void slotAddPoi() const; void slotAddWpt() const; void slotAddTrk() const; void slotAddRte() const; void slotAddArea() const; void slotSelectArea() const; void slotCopyPosition() const; void slotCopyPositionGrid() const; private: bool setScreenOption(const QPoint& pt, IGisItem * item); void scrollToItem(IGisItem * item); protected: void stopTracking() const; void resetState(); /// the flag is true if the map moving is in progress bool mapMove = false; /// the flag is true if the map has been moved actually bool mapDidMove = false; /// always the last seen mouse cursor position QPoint lastPos; /// the last mouse press event position QPoint firstPos; enum item_selection_states_e { eStateIdle = 0 , eStateHooverSingle = 1 //< there is only a single item close to the cursor , eStateHooverMultiple = 2 //< there are multiple items close to the cursor , eStateNoMapMovePossible = 3 //< not a real state, but at this value and above no map move is allowed to take place , eStateUnclutterMultiple = 3 //< the user clicked on multiple cluttered items and gets now an uncluttered representation , eStateShowItemOptions = 4 //< the user has selected a single item, show options how to proceed }; item_selection_states_e stateItemSel = eStateIdle; CScrOptUnclutter * screenUnclutter; QPointer screenItemOption; QMenu * menu; QAction * actionPoiAsWpt; poi_t curPOI; }; #endif //CMOUSENORMAL_H qmapshack-1.10.0/src/mouse/line/000755 001750 000144 00000000000 13216664445 017603 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/src/mouse/line/CScrOptRangeLine.h000644 001750 000144 00000002424 13216234143 023044 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTRANGELINE_H #define CSCROPTRANGELINE_H #include "mouse/IScrOpt.h" #include "ui_IScrOptRangeLine.h" class CScrOptRangeLine : public IScrOpt, public Ui::IScrOptRangeLine { Q_OBJECT public: CScrOptRangeLine(const QPointF &point, IMouse *mouse, QWidget *parent); virtual ~CScrOptRangeLine(); void draw(QPainter& p) override; }; #endif //CSCROPTRANGELINE_H qmapshack-1.10.0/src/mouse/line/IMouseEditLine.h000644 001750 000144 00000010774 13216234143 022570 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IMOUSEEDITLINE_H #define IMOUSEEDITLINE_H #include "gis/IGisItem.h" #include "gis/IGisLine.h" #include "mouse/IMouse.h" #include #include #include class CGisDraw; class CCanvas; class IGisLine; class CScrOptEditLine; class ILineOp; class IMouseEditLine : public IMouse { Q_OBJECT public: enum features_e { eFeatureSnapToLines = 0x01 , eFeatureRouting = 0x02 }; /** @brief Start to create a new track with given point as first track point @param point the starting point @param gis the draw context to use @param parent the canvas to use */ IMouseEditLine(const IGisItem::key_t& key, const QPointF& point, bool enableStatus, const QString& type, CGisDraw * gis, CCanvas * parent); /** @brief Edit an existing track @param trk the track to edit @param gis the draw context to use @param parent the canvas to use */ IMouseEditLine(const IGisItem::key_t &key, IGisLine &src, bool enableStatus, const QString& type, CGisDraw * gis, CCanvas * parent); virtual ~IMouseEditLine(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; void keyPressEvent(QKeyEvent *e) override; void pinchGestureEvent(QPinchGesture *e) override; void afterMouseLostEvent(QMouseEvent *e) override; void abortStep(); bool useAutoRouting() const; bool useVectorRouting() const; void storeToHistory(const SGisLine& line); void restoreFromHistory(SGisLine& line); virtual void updateStatus(); protected slots: /** @brief Delete the selected point */ void slotDeletePoint(); /** @brief Start to select a range of points */ void slotSelectRange(); /** @brief Move selected point */ void slotMovePoint(); /** @brief Add points in direction start of track (eStateAddPointBwd) */ void slotAddPoint(); void slotNoRouting(); void slotAutoRouting(); void slotVectorRouting(); virtual void slotAbort() = 0; void slotAbortEx(bool showMB); virtual void slotCopyToOrig(); virtual void slotCopyToNew() = 0; void slotUndo(); void slotRedo(); protected: virtual void drawLine(const QPolygonF& l, const QColor color, int width, QPainter& p); /** @brief Get access to the IGisLine object a subclass of IMouseEditLine is handling. @return A valid pointer or 0. */ virtual IGisLine * getGisLine() const = 0; virtual void startNewLine(const QPointF &point); /// shadow cursor needed to restore cursor after some actions providing their own cursor. QCursor cursor1; /// the abstract line object to edit SGisLine points; /// undo/redo history QList history; qint32 idxHistory = NOIDX; /// the on screen buttons CScrOptEditLine * scrOptEditLine; /// the key of the GIS item to edit IGisItem::key_t key; QString docPanning = tr("
Move the map
If you keep the left mouse button pressed and move the mouse, you will move the map.

"); private: void commonSetup(); void changeCursor(); QPolygonF pixelLine; QPolygonF pixelPts; QPolygonF pixelSubs; /// the current active line operation (move, add, delete...) ILineOp * lineOp = nullptr; bool enableStatus; QString type; }; #endif //IMOUSEEDITLINE_H qmapshack-1.10.0/src/mouse/line/CLineOpDeletePoint.h000644 001750 000144 00000002632 13216234143 023371 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLINEOPDELETEPOINT_H #define CLINEOPDELETEPOINT_H #include "mouse/line/ILineOp.h" class CLineOpDeletePoint : public ILineOp { public: CLineOpDeletePoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent); virtual ~CLineOpDeletePoint(); void mousePressEventEx(QMouseEvent*) override { } void mouseMoveEventEx(QMouseEvent *e) override; void mouseReleaseEventEx(QMouseEvent *e) override; void drawFg(QPainter& p) override; }; #endif //CLINEOPDELETEPOINT_H qmapshack-1.10.0/src/mouse/line/IMouseEditLine.cpp000644 001750 000144 00000035274 13216234140 023122 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/IGisLine.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "helpers/CSettings.h" #include "mouse/line/CLineOpAddPoint.h" #include "mouse/line/CLineOpDeletePoint.h" #include "mouse/line/CLineOpMovePoint.h" #include "mouse/line/CLineOpSelectRange.h" #include "mouse/line/CScrOptEditLine.h" #include "mouse/line/IMouseEditLine.h" #include "units/IUnit.h" #include IMouseEditLine::IMouseEditLine(const IGisItem::key_t &key, const QPointF& point, bool enableStatus, const QString &type, CGisDraw * gis, CCanvas * parent) : IMouse(gis, parent) , key(key) , enableStatus(enableStatus) , type(type) { commonSetup(); scrOptEditLine->pushSaveOrig->hide(); // hide as there is no original points << IGisLine::point_t(point); points.updatePixel(gis); storeToHistory(points); } IMouseEditLine::IMouseEditLine(const IGisItem::key_t &key, IGisLine &src, bool enableStatus, const QString &type, CGisDraw *gis, CCanvas *parent) : IMouse(gis, parent) , key(key) , enableStatus(enableStatus) , type(type) { commonSetup(); src.getPolylineFromData(points); points.updatePixel(gis); storeToHistory(points); } IMouseEditLine::~IMouseEditLine() { canvas->reportStatus("IMouseEditLine",""); canvas->reportStatus(key.item,""); int mode = 0; if(scrOptEditLine->toolNoRoute->isChecked()) { mode = 0; } else if(scrOptEditLine->toolAutoRoute->isChecked()) { mode = 1; } else if(scrOptEditLine->toolVectorRoute->isChecked()) { mode = 2; } SETTINGS; cfg.setValue("Route/drawMode", mode); delete scrOptEditLine; } void IMouseEditLine::commonSetup() { // create permanent line edit on screen options scrOptEditLine = new CScrOptEditLine(this); connect(scrOptEditLine->pushSaveOrig, &QPushButton::clicked, this, &IMouseEditLine::slotCopyToOrig ); connect(scrOptEditLine->pushSaveNew, &QPushButton::clicked, this, &IMouseEditLine::slotCopyToNew ); connect(scrOptEditLine->pushAbort, &QPushButton::clicked, this, &IMouseEditLine::slotAbort ); connect(scrOptEditLine->toolMovePoint, &QPushButton::clicked, this, &IMouseEditLine::slotMovePoint ); connect(scrOptEditLine->toolSelectRange, &QPushButton::clicked, this, &IMouseEditLine::slotSelectRange ); connect(scrOptEditLine->toolAddPoint, &QPushButton::clicked, this, &IMouseEditLine::slotAddPoint ); connect(scrOptEditLine->toolDeletePoint, &QPushButton::clicked, this, &IMouseEditLine::slotDeletePoint ); connect(scrOptEditLine->toolNoRoute, &QPushButton::clicked, this, &IMouseEditLine::slotNoRouting ); connect(scrOptEditLine->toolAutoRoute, &QPushButton::clicked, this, &IMouseEditLine::slotAutoRouting ); connect(scrOptEditLine->toolVectorRoute, &QPushButton::clicked, this, &IMouseEditLine::slotVectorRouting); connect(scrOptEditLine->toolUndo, &QPushButton::clicked, this, &IMouseEditLine::slotUndo ); connect(scrOptEditLine->toolRedo, &QPushButton::clicked, this, &IMouseEditLine::slotRedo ); SETTINGS; int mode = cfg.value("Route/drawMode",0).toInt(); switch(mode) { case 0: scrOptEditLine->toolNoRoute->setChecked(true); break; case 1: scrOptEditLine->toolAutoRoute->setChecked(true); break; case 2: scrOptEditLine->toolVectorRoute->setChecked(true); break; } slotMovePoint(); } void IMouseEditLine::abortStep() { // at first try to abort a step within the current operation (px. stop adding a new waypoint) if(!lineOp->abortStep()) { // if within operation nothing can be aborted, then abort the whole operation // this equals clicking the `abort` button slotAbortEx(true); } } bool IMouseEditLine::useAutoRouting() const { return scrOptEditLine->toolAutoRoute->isChecked(); } bool IMouseEditLine::useVectorRouting() const { return scrOptEditLine->toolVectorRoute->isChecked(); } void IMouseEditLine::drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p) { p.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(l); } void IMouseEditLine::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) { if(needsRedraw & (CCanvas::eRedrawMouse | CCanvas::eRedrawGis)) { points.updatePixel(gis); pixelLine.clear(); pixelPts.clear(); pixelSubs.clear(); for(const IGisLine::point_t &pt : points) { pixelLine << pt.pixel; pixelPts << pt.pixel; for(const IGisLine::subpt_t &sub : pt.subpts) { pixelLine << sub.pixel; pixelSubs << sub.pixel; } } } if(pixelPts.isEmpty()) { return; } lineOp->drawBg(p); drawLine(pixelLine, Qt::white, 7, p); // draw magenta arrows (with white background) p.setBrush(Qt::magenta); CDraw::arrows(pixelLine, QRectF(), p, 10, 80, 1.0); p.setPen(Qt::NoPen); p.setBrush(Qt::white); QRect r1(0,0,9,9); for(const QPointF &pt : pixelPts) { r1.moveCenter(pt.toPoint()); p.drawRect(r1); } drawLine(pixelLine, Qt::magenta, 5, p); p.setPen(Qt::NoPen); p.setBrush(Qt::black); QRect r2(0,0,7,7); for(const QPointF &pt : pixelPts) { r2.moveCenter(pt.toPoint()); p.drawRect(r2); } for(const QPointF &pt : pixelSubs) { p.drawEllipse(pt, 2, 2); } QRect r3(0,0,9,9); p.setBrush(Qt::NoBrush); p.setPen(QPen(Qt::yellow,2)); r3.moveCenter(pixelPts.first().toPoint()); p.drawRect(r3); p.setPen(QPen(Qt::green,2)); r3.moveCenter(pixelPts.last().toPoint()); p.drawRect(r3); lineOp->drawFg(p); } void IMouseEditLine::startNewLine(const QPointF& point) { scrOptEditLine->toolAddPoint->setChecked(true); slotAddPoint(); CLineOpAddPoint * lineOpAddPoint = dynamic_cast(lineOp); if(lineOpAddPoint) { lineOpAddPoint->append(); } canvas->reportStatus(key.item, tr("New Line
Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.
") + docPanning); } void IMouseEditLine::mousePressEvent(QMouseEvent * e) { point = e->pos(); lineOp->mousePressEvent(e); } void IMouseEditLine::mouseMoveEvent(QMouseEvent * e) { point = e->pos(); lineOp->mouseMoveEvent(e); canvas->displayInfo(point); canvas->update(); } void IMouseEditLine::mouseReleaseEvent(QMouseEvent *e) { point = e->pos(); lineOp->mouseReleaseEvent(e); } void IMouseEditLine::wheelEvent(QWheelEvent * e) { canvas->update(); lineOp->wheelEvent(e); } void IMouseEditLine::keyPressEvent(QKeyEvent * e) { canvas->update(); lineOp->keyPressEvent(e); } void IMouseEditLine::pinchGestureEvent(QPinchGesture *e) { lineOp->pinchGestureEvent(e); } void IMouseEditLine::afterMouseLostEvent(QMouseEvent *e) { point = e->pos(); lineOp->afterMouseLostEvent(e); } void IMouseEditLine::slotDeletePoint() { canvas->reportStatus(key.item, tr("Delete Point
Move the mouse close to a point and press the left button to delete it.
") + docPanning); delete lineOp; lineOp = new CLineOpDeletePoint(points, gis, canvas, this); changeCursor(); } void IMouseEditLine::slotSelectRange() { canvas->reportStatus(key.item, tr("Select Range of Points
Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.
") + docPanning); delete lineOp; lineOp = new CLineOpSelectRange(points, gis, canvas, this); changeCursor(); } void IMouseEditLine::slotMovePoint() { canvas->reportStatus(key.item, tr("Move Point
Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.
") + docPanning); delete lineOp; lineOp = new CLineOpMovePoint(points, gis, canvas, this); changeCursor(); } void IMouseEditLine::slotAddPoint() { canvas->reportStatus(key.item, tr("Add Point
Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it. Drop the point by a left click. Use the right mouse button to cancel.
") + docPanning); delete lineOp; lineOp = new CLineOpAddPoint(points, gis, canvas, this); changeCursor(); } void IMouseEditLine::slotNoRouting() { canvas->reportStatus(key.item, tr("No Routing
All points will be connected with a straight line.
")); canvas->reportStatus("Routino", QString()); } void IMouseEditLine::slotAutoRouting() { canvas->reportStatus(key.item, tr("Auto Routing
The current router setup is used to derive a route between points. Note: The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.
")); } void IMouseEditLine::slotVectorRouting() { canvas->reportStatus(key.item, tr("Vector Routing
Connect points with a line from a loaded vector map if possible.
")); canvas->reportStatus("Routino", QString()); } void IMouseEditLine::changeCursor() { cursor = lineOp->getCursor(); if(QApplication::overrideCursor() != 0) { CCanvas::changeOverrideCursor(cursor,"IMouseEditLine::changeCursor"); } } void IMouseEditLine::slotAbortEx(bool showMB) { // ask if the current operation should be aborted (only in case there are things to be saved) bool doAbort = ( idxHistory == 0 ) || !showMB; if(!doAbort) { doAbort = (QMessageBox::Yes == QMessageBox::question(nullptr, "Abort", "Do you really want to abort?\nAny modifications done will be discarded.", QMessageBox::Yes | QMessageBox::No)); } if(doAbort) { canvas->resetMouse(); canvas->update(); } } void IMouseEditLine::slotCopyToOrig() { QMutexLocker lock(&IGisItem::mutexItems); IGisLine * line = getGisLine(); if(line != nullptr) { CMainWindow::self().getElevationAt(points); line->setDataFromPolyline(points); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void IMouseEditLine::restoreFromHistory(SGisLine& line) { line = history[idxHistory]; canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); updateStatus(); } void IMouseEditLine::storeToHistory(const SGisLine& line) { // crop history if necessary if(idxHistory != NOIDX) { while(history.size() > (idxHistory + 1)) { history.pop_back(); } } history << line; idxHistory = history.size() - 1; scrOptEditLine->toolRedo->setEnabled(false); scrOptEditLine->toolUndo->setEnabled(idxHistory > 0); updateStatus(); } void IMouseEditLine::slotUndo() { if(lineOp != nullptr) { lineOp->abortStep(); } if(idxHistory > 0) { idxHistory--; } points = history[idxHistory]; scrOptEditLine->toolRedo->setEnabled(true); scrOptEditLine->toolUndo->setEnabled(idxHistory > 0); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void IMouseEditLine::slotRedo() { // abort operation if(lineOp != nullptr) { lineOp->abortStep(); } if(idxHistory < (history.size() - 1)) { idxHistory++; } points = history[idxHistory]; scrOptEditLine->toolRedo->setEnabled(idxHistory < (history.size() - 1)); scrOptEditLine->toolUndo->setEnabled(true); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void IMouseEditLine::updateStatus() { if(!enableStatus || points.isEmpty()) { canvas->reportStatus("IMouseEditLine", QString()); return; } canvas->getElevationAt(points); qreal asc = 0; qreal dsc = 0; qreal dist = 0; qreal lastEle = points[0].ele; QPointF lastPos = points[0].coord; for(const IGisLine::point_t &pt1 : points) { qreal delta = pt1.ele - lastEle; if(qAbs(delta) > ASCENT_THRESHOLD) { if(delta > 0) { asc += delta; } if(delta < 0) { dsc -= delta; } lastEle = pt1.ele; } dist += GPS_Math_Distance(lastPos.x(), lastPos.y(), pt1.coord.x(), pt1.coord.y()); lastPos = pt1.coord; for(const IGisLine::subpt_t& pt : pt1.subpts) { delta = pt.ele - lastEle; if(qAbs(delta) > ASCENT_THRESHOLD) { if(delta > 0) { asc += delta; } if(delta < 0) { dsc -= delta; } lastEle = pt.ele; } dist += GPS_Math_Distance(lastPos.x(), lastPos.y(), pt.coord.x(), pt.coord.y()); lastPos = pt.coord; } } QString msg, val, unit; msg += tr("%1 Metrics").arg(type); msg += ""; IUnit::self().meter2distance(dist, val, unit); msg += ""; IUnit::self().meter2elevation(asc, val, unit); msg += ""; IUnit::self().meter2elevation(dsc, val, unit); msg += ""; msg += "
" + tr("Distance:") + "" + QString(" %1 %2").arg(val).arg(unit) + "
" + tr("Ascent:") + "" + QString(" %1 %2").arg(val).arg(unit) + "
" + tr("Descent:") + "" + QString(" %1 %2").arg(val).arg(unit) + "
"; canvas->reportStatus("IMouseEditLine",msg); } qmapshack-1.10.0/src/mouse/line/CLineOpAddPoint.cpp000644 001750 000144 00000015732 13216234140 023214 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "mouse/line/CLineOpAddPoint.h" #include "mouse/line/IMouseEditLine.h" #include CLineOpAddPoint::CLineOpAddPoint(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent) : ILineOp(points, gis, canvas, parent) { cursor = QCursor(QPixmap(":/cursors/cursorPointAdd.png"), 0, 0); } CLineOpAddPoint::~CLineOpAddPoint() { } void CLineOpAddPoint::append() { // this is called on construction when creating a complete new line // A new point is appended to what ever line already exists, // and add point mode is entered immediately. idxFocus = points.size(); points.insert(idxFocus, IGisLine::point_t(points.last())); addPoint = true; isPoint = true; // make sure that when starting the line-edit on-the-fly-routing will // not trigger before the mouse has been moved a bit away from last point of line startMouseMove(points.last().pixel); } void CLineOpAddPoint::mouseReleaseEventEx(QMouseEvent * e) { if(e->button() == Qt::LeftButton) { if(addPoint) { // drop the new point at current position // update subpoints of previous and this point slotTimeoutRouting(); // if isPoint is true the line has been appended/prepended // in this case go on with adding another point if(isPoint) { if(idxFocus == (points.size() - 1)) { idxFocus++; } // store current state of line to undo/redo history parentHandler->storeToHistory(points); QPointF coord = e->pos(); gis->convertPx2Rad(coord); points.insert(idxFocus, IGisLine::point_t(coord)); } else { // store current state of line to undo/redo history parentHandler->storeToHistory(points); // terminate operation if the new point was inbetween a line segment. addPoint = false; idxFocus = NOIDX; } } else if(isPoint) { // as isPoint is set, add a new point either at the start or end of the line if(idxFocus == (points.size() - 1)) { idxFocus++; } QPointF coord = e->pos(); gis->convertPx2Rad(coord); points.insert(idxFocus, IGisLine::point_t(coord)); addPoint = true; } else if(idxFocus != NOIDX) { // clear current line segment points[idxFocus].subpts.clear(); // add a new point to line segment QPointF coord = e->pos(); gis->convertPx2Rad(coord); idxFocus++; points.insert(idxFocus, IGisLine::point_t(coord)); addPoint = true; } } else if(e->button() == Qt::RightButton) { abortStep(); idxFocus = NOIDX; } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } bool CLineOpAddPoint::abortStep() { if(addPoint) { // cancel action and restore last state of line cancelDelayedRouting(); parentHandler->restoreFromHistory(points); addPoint = false; idxFocus = NOIDX; canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); return true; } return false; } void CLineOpAddPoint::mouseMoveEventEx(QMouseEvent * e) { if(addPoint) { QPointF coord = e->pos(); gis->convertPx2Rad(coord); IGisLine::point_t& pt = points[idxFocus]; // update position of point pt.coord = coord; // clear subpoints, as they have to be recalculated // by the routing, if any pt.subpts.clear(); if(idxFocus > 0) { points[idxFocus - 1].subpts.clear(); } // retrigger delayed routing startDelayedRouting(); } else { isPoint = false; // find line segment close to cursor idxFocus = isCloseToLine(e->pos()); // if none is found try to find point if(idxFocus == NOIDX) { // if no line segment is found but a point // it is either first or the last point in the line idxFocus = isCloseTo(e->pos()); if((idxFocus == 0) || (idxFocus == (points.size() - 1))) { isPoint = true; } } } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpAddPoint::drawFg(QPainter& p) { if(idxFocus == NOIDX) { return; } if(addPoint) { const IGisLine::point_t& pt = points[idxFocus]; drawSinglePointSmall(pt.pixel, p); } else if(isPoint) { const IGisLine::point_t& pt = points[idxFocus]; drawSinglePointLarge(pt.pixel, p); } else if(idxFocus < (points.size() - 1)) { QPolygonF line; const IGisLine::point_t& pt1 = points[idxFocus]; const IGisLine::point_t& pt2 = points[idxFocus + 1]; if(pt1.subpts.isEmpty()) { line << pt1.pixel << pt2.pixel; } else { line << pt1.pixel; for(const IGisLine::subpt_t& pt : pt1.subpts) { line << pt.pixel; } line << pt2.pixel; } p.setPen(penBgPoint); p.setBrush(brushBgPoint); rectPoint.moveCenter(pt1.pixel.toPoint()); p.drawRect(rectPoint); rectPoint.moveCenter(pt2.pixel.toPoint()); p.drawRect(rectPoint); p.setPen(QPen(Qt::white, 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(line); p.setPen(penFgPoint); p.setBrush(brushFgPoint); rectPoint.moveCenter(pt1.pixel.toPoint()); p.drawRect(rectPoint); rectPoint.moveCenter(pt2.pixel.toPoint()); p.drawRect(rectPoint); p.setPen(QPen(Qt::red, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(line); } } qmapshack-1.10.0/src/mouse/line/ILineOp.cpp000644 001750 000144 00000025355 13216234140 021601 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "CMainWindow.h" #include "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/rte/router/CRouterSetup.h" #include "mouse/line/ILineOp.h" #include "mouse/line/IMouseEditLine.h" #include ILineOp::ILineOp(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent) : QObject(parent) , parentHandler(parent) , points(points) , canvas(canvas) , gis(gis) { timerRouting = new QTimer(this); timerRouting->setSingleShot(true); timerRouting->setInterval(400); connect(timerRouting, &QTimer::timeout, this, &ILineOp::slotTimeoutRouting); } ILineOp::~ILineOp() { canvas->reportStatus("Routino", QString()); } void ILineOp::cancelDelayedRouting() { timerRouting->stop(); } void ILineOp::startDelayedRouting() { if(parentHandler->useAutoRouting()) { timerRouting->start(); } else if(parentHandler->useVectorRouting()) { slotTimeoutRouting(); } } void ILineOp::slotTimeoutRouting() { timerRouting->stop(); finalizeOperation(idxFocus); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void ILineOp::drawBg(QPainter& p) { drawLeadLine(leadLinePixel1,p); drawLeadLine(leadLinePixel2,p); } void ILineOp::drawSinglePointSmall(const QPointF& pt, QPainter& p) { QRect r(0,0,3,3); r.moveCenter(pt.toPoint()); p.setPen(QPen(Qt::white, 2)); p.setBrush(Qt::white); p.drawRect(r); p.setPen(Qt::black); p.setBrush(Qt::black); p.drawRect(r); } void ILineOp::drawSinglePointLarge(const QPointF &pt, QPainter& p) { rectPoint.moveCenter(pt.toPoint()); p.setPen(penBgPoint); p.setBrush(brushBgPoint); p.drawRect(rectPoint); p.setPen(penFgPoint); p.setBrush(brushFgPoint); p.drawRect(rectPoint); } void ILineOp::drawLeadLine(const QPolygonF& line, QPainter& p) const { p.setPen(QPen(Qt::yellow, 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(line); } void ILineOp::mousePressEvent(QMouseEvent * e) { if(idxFocus != NOIDX) { mousePressEventEx(e); } if(e->button() == Qt::LeftButton) { lastPos = e->pos(); mapMove = true; } // make sure that on-the-fly-routing will // not trigger before the mouse has been moved a bit startMouseMove(e->pos()); // make sure a click is actually shorter than longButtonPressTimeout buttonPressTime.start(); ignoreClick = false; showRoutingErrorMessage(QString()); } void ILineOp::mouseMoveEvent(QMouseEvent * e) { const QPoint& pos = e->pos(); // do not take the mouse as moving unless it has been moved // by significant distance away from starting point. // this helps doing clicks with the finger on a touchscreen // and suppresses routing triggered by very small movements. if (!mouseDidMove && (pos - firstPos).manhattanLength() >= IMouse::minimalMouseMovingDistance) { mouseDidMove = true; } if (mouseDidMove) { if(mapMove) { QPoint delta = pos - lastPos; canvas->moveMap(delta); } else { updateLeadLines(idxFocus); mouseMoveEventEx(e); } } lastPos = pos; } void ILineOp::mouseReleaseEvent(QMouseEvent *e) { // suppress map-movement, long-clicks and button-release after zooming or display of CProgressDialog if(!(mouseDidMove && mapMove) && !ignoreClick && (buttonPressTime.elapsed() < IMouse::longButtonPressTimeout)) { mouseReleaseEventEx(e); } mapMove = false; mouseDidMove = false; } void ILineOp::wheelEvent(QWheelEvent *e) { // suppress little mouse-movements that are likely to happen when scrolling the mousewheel. startMouseMove(e->pos()); if (e->buttons() != Qt::NoButton) { // no shortclick by releasing button right after scrolling the wheel ignoreClick = true; } } void ILineOp::pinchGestureEvent(QPinchGesture *e) { // consider finger being down (equivalent to button pressed) during pinch mapMove = true; // no shortclick by lifting the finger right after a pinch ignoreClick = true; // no on-the-fly-routing during pinch timerRouting->stop(); } void ILineOp::afterMouseLostEvent(QMouseEvent *e) { // pinch or modal dialog interrupt tracking of mouse. As result the mouse // is at an arbitrary position. if (e->type() == QEvent::MouseMove) { // suppress jump of map when touching screen right afterwards lastPos = e->pos(); // consider the move starting at this position startMouseMove(e->pos()); } mapMove = e->buttons() & Qt::LeftButton; } void ILineOp::startMouseMove(const QPointF& pos) { // the mouse is not considered as moving // as long it has not been moved away from firstPos // by at least a few pixels. firstPos = pos.toPoint(); mouseDidMove = false; // as long the mouse is not taken as moving // to not trigger on-the-fly-routing timerRouting->stop(); } void ILineOp::updateLeadLines(qint32 idx) { leadLinePixel1.clear(); leadLinePixel2.clear(); subLinePixel1.clear(); subLinePixel2.clear(); if(parentHandler->useVectorRouting() && (idx != NOIDX)) { leadLineCoord1.clear(); leadLineCoord2.clear(); subLineCoord1.clear(); subLineCoord2.clear(); if(idx > 0) { const IGisLine::point_t& pt1 = points[idx - 1]; const IGisLine::point_t& pt2 = points[idx]; if(canvas->findPolylineCloseBy(pt2.pixel, pt2.pixel, 10, leadLineCoord1)) { leadLinePixel1 = leadLineCoord1; gis->convertRad2Px(leadLinePixel1); segment_t result; GPS_Math_SubPolyline(pt1.pixel, pt2.pixel, 10, leadLinePixel1, result); result.apply(leadLineCoord1, leadLinePixel1, subLineCoord1, subLinePixel1, gis); } } if(idx < points.size() - 1) { const IGisLine::point_t& pt1 = points[idx]; const IGisLine::point_t& pt2 = points[idx + 1]; if(canvas->findPolylineCloseBy(pt1.pixel, pt1.pixel, 10, leadLineCoord2)) { leadLinePixel2 = leadLineCoord2; gis->convertRad2Px(leadLinePixel2); segment_t result; GPS_Math_SubPolyline(pt1.pixel, pt2.pixel, 10, leadLinePixel2, result); result.apply(leadLineCoord2, leadLinePixel2, subLineCoord2, subLinePixel2, gis); } } } } void ILineOp::showRoutingErrorMessage(const QString &msg) const { if(msg.isEmpty()) { canvas->reportStatus("Routino", QString()); } else { canvas->reportStatus("Routino", QString("%1
%2
").arg(tr("Routing")).arg(msg)); } } void ILineOp::tryRouting(IGisLine::point_t& pt1, IGisLine::point_t& pt2) const { QPolygonF subs; try { if(CRouterSetup::self().calcRoute(pt1.coord, pt2.coord, subs) >= 0) { pt1.subpts.clear(); for(const QPointF &sub : subs) { pt1.subpts << IGisLine::subpt_t(sub); } } showRoutingErrorMessage(QString()); } catch(const QString &msg) { showRoutingErrorMessage(msg); } // that is a workaround for canvas loosing mousetracking caused by CProgressDialog being modal: canvas->setMouseTracking(true); } void ILineOp::finalizeOperation(qint32 idx) { if(idx == NOIDX) { return; } if(parentHandler->useAutoRouting()) { CCanvas::setOverrideCursor(Qt::WaitCursor,"ILineOp::finalizeOperation"); if(idx > 0) { tryRouting(points[idx - 1], points[idx]); } if(idx < (points.size() - 1)) { tryRouting(points[idx], points[idx + 1]); } CCanvas::restoreOverrideCursor("ILineOp::finalizeOperation"); } else if(parentHandler->useVectorRouting()) { if(idx > 0) { IGisLine::point_t& pt1 = points[idx - 1]; pt1.subpts.clear(); for(const QPointF &pt : subLineCoord1) { pt1.subpts << IGisLine::subpt_t(pt); } } if(idx < (points.size() - 1)) { IGisLine::point_t& pt1 = points[idx]; pt1.subpts.clear(); for(const QPointF &pt : subLineCoord2) { pt1.subpts << IGisLine::subpt_t(pt); } } } // need to move the mouse away by some pixels to trigger next routing event startMouseMove(points[idx].pixel); parentHandler->updateStatus(); } qint32 ILineOp::isCloseTo(const QPoint& pos) const { qint32 min = 30; qint32 idx = NOIDX; const int N = points.size(); for(int i = 0; i < N; i++) { const IGisLine::point_t& pt = points[i]; qint32 d = (pos - pt.pixel).manhattanLength(); if(d < min) { min = d; idx = i; } } return idx; } qint32 ILineOp::isCloseToLine(const QPoint& pos) const { qint32 idx = NOIDX; qreal dist = 60; for(int i = 0; i < points.size() - 1; i++) { QPolygonF line; const IGisLine::point_t& pt1 = points[i]; const IGisLine::point_t& pt2 = points[i + 1]; if(pt1.subpts.isEmpty()) { line << pt1.pixel << pt2.pixel; } else { line << pt1.pixel; for(const IGisLine::subpt_t& pt : pt1.subpts) { line << pt.pixel; } line << pt2.pixel; } qreal d = GPS_Math_DistPointPolyline(line, pos); if(d < dist) { dist = d; idx = i; } } return idx; } qmapshack-1.10.0/src/mouse/line/CScrOptEditLine.h000644 001750 000144 00000002353 13216234143 022676 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTEDITLINE_H #define CSCROPTEDITLINE_H #include "mouse/IScrOpt.h" #include "ui_IScrOptEditLine.h" class CScrOptEditLine : public IScrOpt, public Ui::IScrOptEditLine { Q_OBJECT public: CScrOptEditLine(IMouse *mouse); virtual ~CScrOptEditLine(); void draw(QPainter& p) override { } }; #endif //CSCROPTEDITLINE_H qmapshack-1.10.0/src/mouse/line/CLineOpMovePoint.cpp000644 001750 000144 00000007514 13216234140 023431 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "mouse/line/CLineOpMovePoint.h" #include "mouse/line/IMouseEditLine.h" #include "units/IUnit.h" #include CLineOpMovePoint::CLineOpMovePoint(SGisLine &points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine *parent) : ILineOp(points, gis, canvas, parent) { cursor = QCursor(QPixmap(":/cursors/cursorPointMove.png"),0,0); } CLineOpMovePoint::~CLineOpMovePoint() { } void CLineOpMovePoint::mouseReleaseEventEx(QMouseEvent * e) { if(e->button() == Qt::LeftButton) { if(movePoint) { // update subpoints by triggering the routing, if any. slotTimeoutRouting(); // terminate moving the point movePoint = false; // store new state of line to undo/redo history parentHandler->storeToHistory(points); } else if(idxFocus != NOIDX) { QPointF coord = e->pos(); gis->convertPx2Rad(coord); // start moving the point IGisLine::point_t& pt = points[idxFocus]; pt.coord = coord; // clear the subpoints from this point to the next pt.subpts.clear(); // clear the subpoints from the previous point to this point if(idxFocus != 0) { points[idxFocus - 1].subpts.clear(); } movePoint = true; } } else if(e->button() == Qt::RightButton) { abortStep(); } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } bool CLineOpMovePoint::abortStep() { if(movePoint) { // cancel action and restore last state of line cancelDelayedRouting(); parentHandler->restoreFromHistory(points); movePoint = false; idxFocus = NOIDX; canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); return true; } return false; } void CLineOpMovePoint::mouseMoveEventEx(QMouseEvent * e) { if(movePoint) { QPointF coord = e->pos(); gis->convertPx2Rad(coord); IGisLine::point_t& pt = points[idxFocus]; // update position of point pt.coord = coord; // clear subpoints, as they have to be recalculated // by the routing, if any pt.subpts.clear(); if(idxFocus > 0) { points[idxFocus - 1].subpts.clear(); } // retrigger delayed routing startDelayedRouting(); } else { // no point selected yet, find point to highlight idxFocus = isCloseTo(e->pos()); } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpMovePoint::drawFg(QPainter& p) { if(idxFocus == NOIDX) { return; } const IGisLine::point_t& pt = points[idxFocus]; if(movePoint) { drawSinglePointSmall(pt.pixel, p); } else { drawSinglePointLarge(pt.pixel, p); } } qmapshack-1.10.0/src/mouse/line/IScrOptEditLine.ui000644 001750 000144 00000024347 13136570070 023104 0ustar00oeichlerxusers000000 000000 IScrOptEditLine 0 0 653 46 0 0 0 0 16777215 100 Form Save to original Save as new Abort Qt::Vertical QFrame::NoFrame QFrame::Raised 0 0 0 0 Move points. (Ctrl+M) ... :/icons/32x32/PointMove.png:/icons/32x32/PointMove.png Ctrl+M true true true Add new points. (Ctrl++) ... :/icons/32x32/PointAdd.png:/icons/32x32/PointAdd.png Ctrl++ true true Select a range of points. (Ctrl+R) ... :/icons/32x32/SelectRange.png:/icons/32x32/SelectRange.png Ctrl+R true true Delete a point. (Ctrl+-) ... :/icons/32x32/PointDel.png:/icons/32x32/PointDel.png Ctrl+- true true Qt::Vertical QFrame::NoFrame QFrame::Raised 0 0 0 0 No auto-routing or line snapping (Ctrl+O) 0 :/icons/32x32/O.png:/icons/32x32/O.png Ctrl+O true true Use auto-routing to between points. (Ctrl+A) A :/icons/32x32/A.png:/icons/32x32/A.png Ctrl+A true true Snap line along lines of a vector map. (Ctrl+V) V :/icons/32x32/V.png:/icons/32x32/V.png Ctrl+V true true Qt::Vertical false Undo last change ... :/icons/32x32/Undo.png:/icons/32x32/Undo.png false Redo last change ... :/icons/32x32/Redo.png:/icons/32x32/Redo.png Qt::Horizontal 40 20 qmapshack-1.10.0/src/mouse/line/CLineOpSelectRange.cpp000644 001750 000144 00000014412 13216234140 023700 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "mouse/line/CLineOpSelectRange.h" #include "mouse/line/CScrOptRangeLine.h" #include "mouse/line/IMouseEditLine.h" #include CLineOpSelectRange::CLineOpSelectRange(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent) : ILineOp(points, gis, canvas, parent) { cursor = QCursor(QPixmap(":/cursors/cursorSelectRange.png"),0,0); } CLineOpSelectRange::~CLineOpSelectRange() { delete scrOptRangeLine; } void CLineOpSelectRange::mouseReleaseEventEx(QMouseEvent * e) { if(e->button() == Qt::LeftButton) { switch(state) { case eStateIdle: { if(idxFocus != NOIDX) { state = eState1st; } break; } case eState1st: { if(idx2nd < 0 || points.size() <= idx2nd) { break; } qint32 d = qAbs(idxFocus - idx2nd); if(d < 1) { resetState(); return; } scrOptRangeLine = new CScrOptRangeLine(points[idx2nd].pixel, parentHandler, canvas); connect(scrOptRangeLine->toolDelete, &QToolButton::clicked, this, &CLineOpSelectRange::slotDelete); connect(scrOptRangeLine->toolCalcRoute, &QToolButton::clicked, this, &CLineOpSelectRange::slotCalc); connect(scrOptRangeLine->toolDelete, &QToolButton::clicked, scrOptRangeLine.data(), &CScrOptRangeLine::hide); connect(scrOptRangeLine->toolCalcRoute, &QToolButton::clicked, scrOptRangeLine.data(), &CScrOptRangeLine::hide); if(d < 2) { scrOptRangeLine->toolDelete->setEnabled(false); } state = eState2nd; break; } } } else if(e->button() == Qt::RightButton) { resetState(); } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } bool CLineOpSelectRange::abortStep() { if(state != eStateIdle) { resetState(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); return true; } return false; } void CLineOpSelectRange::mouseMoveEventEx(QMouseEvent * e) { switch(state) { case eStateIdle: { // no point selected yet, find point to highlight idxFocus = isCloseTo(e->pos()); break; } case eState1st: { idx2nd = isCloseTo(e->pos()); if(idx2nd == NOIDX) { idx2nd = isCloseToLine(e->pos()); if((idx2nd != NOIDX) && ((idx2nd + 1) < points.size())) { idx2nd++; } } break; } } canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpSelectRange::wheelEvent(QWheelEvent * e) { if(state == eState2nd) { resetState(); } } void CLineOpSelectRange::keyPressEvent(QKeyEvent * e) { if(state == eState2nd) { resetState(); } } void CLineOpSelectRange::drawFg(QPainter& p) { if(idxFocus == NOIDX) { return; } switch(state) { case eStateIdle: { const IGisLine::point_t& pt = points[idxFocus]; drawSinglePointLarge(pt.pixel, p); break; } case eState1st: case eState2nd: { if(idx2nd != NOIDX) { qint32 idx1 = qMin(idxFocus, idx2nd); qint32 idx2 = qMax(idxFocus, idx2nd); QPolygonF seg; for(int i = idx1; i < idx2; i++) { const IGisLine::point_t& point = points[i]; seg << point.pixel; for(const IGisLine::subpt_t& subpt : point.subpts) { seg << subpt.pixel; } } seg << points[idx2].pixel; p.setPen(QPen(Qt::darkGreen, 11, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(seg); p.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.drawPolyline(seg); p.setPen(QPen(Qt::NoPen)); p.setBrush(Qt::black); QRectF r(0, 0, 8, 8); for(int i = idx1; i <= idx2; i++) { r.moveCenter(points[i].pixel); p.drawRect(r); for(const IGisLine::subpt_t& subpt : points[i].subpts) { p.drawEllipse(subpt.pixel, 2, 2); } } } if(!scrOptRangeLine.isNull() && eState2nd == state) { scrOptRangeLine->draw(p); } break; } } } void CLineOpSelectRange::resetState() { if(!scrOptRangeLine.isNull()) { scrOptRangeLine->deleteLater(); } idxFocus = NOIDX; idx2nd = NOIDX; state = eStateIdle; } void CLineOpSelectRange::slotDelete() { qint32 idx = qMin(idxFocus, idx2nd); qint32 N = qAbs(idxFocus - idx2nd) - 1; points[idx].subpts.clear(); points.remove(idx + 1, N); parentHandler->storeToHistory(points); resetState(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpSelectRange::slotCalc() { qint32 idx = qMin(idxFocus, idx2nd); qint32 N = qAbs(idxFocus - idx2nd) - 1; points.remove(idx + 1, N); finalizeOperation(idx); parentHandler->storeToHistory(points); resetState(); } qmapshack-1.10.0/src/mouse/line/CLineOpDeletePoint.cpp000644 001750 000144 00000004134 13216234140 023720 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "mouse/line/CLineOpDeletePoint.h" #include "mouse/line/IMouseEditLine.h" #include "units/IUnit.h" #include CLineOpDeletePoint::CLineOpDeletePoint(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent) : ILineOp(points, gis, canvas, parent) { cursor = QCursor(QPixmap(":/cursors/cursorPointDel.png"), 0, 0); } CLineOpDeletePoint::~CLineOpDeletePoint() { } void CLineOpDeletePoint::mouseMoveEventEx(QMouseEvent * e) { idxFocus = isCloseTo(e->pos()); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpDeletePoint::mouseReleaseEventEx(QMouseEvent *e) { if(idxFocus != NOIDX) { if(idxFocus > 0) { points[idxFocus - 1].subpts.clear(); } points.remove(idxFocus--); updateLeadLines(idxFocus); slotTimeoutRouting(); // store to undo/redo history parentHandler->storeToHistory(points); } idxFocus = NOIDX; canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } void CLineOpDeletePoint::drawFg(QPainter& p) { if(idxFocus == NOIDX) { return; } drawSinglePointLarge(points[idxFocus].pixel, p); } qmapshack-1.10.0/src/mouse/line/ILineOp.h000644 001750 000144 00000007664 13216234143 021254 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef ILINEOP_H #define ILINEOP_H #include "gis/IGisLine.h" #include #include #include #include #include class QMouseEvent; class QPinchGesture; class CCanvas; class QPainter; class IMouseEditLine; class ILineOp : public QObject { Q_OBJECT public: ILineOp(SGisLine &points, CGisDraw * gis, CCanvas * canvas, IMouseEditLine * parent); virtual ~ILineOp(); virtual void mousePressEvent(QMouseEvent * e); virtual void mouseMoveEvent(QMouseEvent * e); virtual void mouseReleaseEvent(QMouseEvent *e); virtual void mousePressEventEx(QMouseEvent * e) = 0; virtual void mouseMoveEventEx(QMouseEvent * e) = 0; virtual void mouseReleaseEventEx(QMouseEvent *e) = 0; virtual void wheelEvent(QWheelEvent*); virtual void keyPressEvent(QKeyEvent*) { } virtual void pinchGestureEvent(QPinchGesture *e); virtual void afterMouseLostEvent(QMouseEvent *e); virtual void drawFg(QPainter& p) = 0; virtual void drawBg(QPainter& p); const QCursor& getCursor() const { return cursor; } /** @brief (try to) abort a step in the current operation Method called, if a step in the current operation should be aborted, such as adding or moving a(n already) selected waypoint. This dummy implementation does not do anything and therefore always returns `false`. @return `true` if a step in the current operation was successfully, `false` otherwise */ virtual bool abortStep() { return false; } void updateStatus(); protected slots: void slotTimeoutRouting(); protected: virtual void cancelDelayedRouting(); virtual void startDelayedRouting(); virtual void finalizeOperation(qint32 idx); qint32 isCloseTo(const QPoint& pos) const; qint32 isCloseToLine(const QPoint& pos) const; void drawSinglePointSmall(const QPointF& pt, QPainter& p); void drawSinglePointLarge(const QPointF &pt, QPainter& p); void drawLeadLine(const QPolygonF& line, QPainter& p) const; void updateLeadLines(qint32 idx); void startMouseMove(const QPointF &pos); IMouseEditLine * parentHandler; SGisLine& points; CCanvas * canvas; CGisDraw * gis; QCursor cursor; qint32 idxFocus = NOIDX; QPoint lastPos; QPoint firstPos; QRect rectPoint {0,0,9,9}; const QPen penBgPoint {Qt::white, 4}; const QPen penFgPoint {Qt::red, 2}; const QBrush brushBgPoint {Qt::white}; const QBrush brushFgPoint {Qt::red}; QPolygonF leadLineCoord1; QPolygonF leadLineCoord2; QPolygonF leadLinePixel1; QPolygonF leadLinePixel2; QPolygonF subLineCoord1; QPolygonF subLineCoord2; QPolygonF subLinePixel1; QPolygonF subLinePixel2; private: void showRoutingErrorMessage(const QString &msg) const; void tryRouting(IGisLine::point_t& pt1, IGisLine::point_t& pt2) const; QTimer * timerRouting; QTime buttonPressTime; bool ignoreClick = false; bool mapMove = false; bool mouseDidMove = false; }; #endif //ILINEOP_H qmapshack-1.10.0/src/mouse/line/CScrOptEditLine.cpp000644 001750 000144 00000002176 13216234140 023231 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "mouse/line/CScrOptEditLine.h" #include CScrOptEditLine::CScrOptEditLine(IMouse *mouse) : IScrOpt(mouse) { setupUi(this); move(0,0); adjustSize(); show(); } CScrOptEditLine::~CScrOptEditLine() { } qmapshack-1.10.0/src/mouse/line/IScrOptRangeLine.ui000644 001750 000144 00000003447 13034634055 023252 0ustar00oeichlerxusers000000 000000 IScrOptRangeLine 0 0 92 43 Form 3 3 3 3 Delete all points between the first and last one. ... :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png <html><head/><body><p>Calculate a route between the first and last selected point.</p></body></html> ... :/icons/32x32/Apply.png:/icons/32x32/Apply.png qmapshack-1.10.0/src/mouse/line/CLineOpAddPoint.h000644 001750 000144 00000002775 13216234143 022667 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLINEOPADDPOINT_H #define CLINEOPADDPOINT_H #include "mouse/line/ILineOp.h" class CLineOpAddPoint : public ILineOp { public: CLineOpAddPoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent); virtual ~CLineOpAddPoint(); void mousePressEventEx(QMouseEvent *e) override { } void mouseMoveEventEx(QMouseEvent *e) override; void mouseReleaseEventEx(QMouseEvent *e) override; void drawFg(QPainter& p) override; void append(); bool abortStep() override; private: bool addPoint = false; bool isPoint = false; }; #endif //CLINEOPADDPOINT_H qmapshack-1.10.0/src/mouse/line/CScrOptRangeLine.cpp000644 001750 000144 00000003002 13216234140 023365 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "helpers/CDraw.h" #include "mouse/line/CScrOptRangeLine.h" CScrOptRangeLine::CScrOptRangeLine(const QPointF &point, IMouse *mouse, QWidget * parent) : IScrOpt(mouse) { if(parent != nullptr) { setParent(parent); } setupUi(this); // label->setFont(CMainWindow::self().getMapFont()); // label->setText(trk->getInfoRange()); adjustSize(); setOrigin(point.toPoint()); move(point.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); } CScrOptRangeLine::~CScrOptRangeLine() { } void CScrOptRangeLine::draw(QPainter& p) { CDraw::bubble(p, geometry(), origin); } qmapshack-1.10.0/src/mouse/line/CLineOpMovePoint.h000644 001750 000144 00000002731 13216234143 023075 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLINEOPMOVEPOINT_H #define CLINEOPMOVEPOINT_H #include "mouse/line/ILineOp.h" class CLineOpMovePoint : public ILineOp { public: CLineOpMovePoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent); virtual ~CLineOpMovePoint(); void mousePressEventEx(QMouseEvent * e) override { } void mouseMoveEventEx(QMouseEvent * e) override; void mouseReleaseEventEx(QMouseEvent * e) override; void drawFg(QPainter& p) override; bool abortStep() override; private: bool movePoint = false; }; #endif //CLINEOPMOVEPOINT_H qmapshack-1.10.0/src/mouse/line/CLineOpSelectRange.h000644 001750 000144 00000003574 13216234143 023357 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLINEOPSELECTRANGE_H #define CLINEOPSELECTRANGE_H #include "mouse/line/ILineOp.h" #include class CScrOptRangeLine; class CLineOpSelectRange : public ILineOp { Q_OBJECT public: CLineOpSelectRange(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent); virtual ~CLineOpSelectRange(); void mousePressEventEx(QMouseEvent *e) override { } void mouseMoveEventEx(QMouseEvent *e) override; void mouseReleaseEventEx(QMouseEvent *e) override; void wheelEvent(QWheelEvent * e) override; void keyPressEvent(QKeyEvent * e) override; void drawFg(QPainter& p) override; bool abortStep() override; private slots: void slotDelete(); void slotCalc(); private: void resetState(); enum state_e { eStateIdle , eState1st , eState2nd }; state_e state = eStateIdle; qint32 idx2nd = NOIDX; QPointer scrOptRangeLine; }; #endif //CLINEOPSELECTRANGE_H qmapshack-1.10.0/src/mouse/IMouseSelect.cpp000644 001750 000144 00000015105 13216234140 021704 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisDraw.h" #include "mouse/IMouseSelect.h" #include "mouse/IScrOpt.h" #include IMouseSelect::IMouseSelect(CGisDraw *gis, CCanvas *canvas) : IMouse(gis, canvas) { } IMouseSelect::~IMouseSelect() { canvas->reportStatus("IMouseSelect", ""); delete scrOpt; } void IMouseSelect::rectRad2Px(const QRectF& rectSrc, QRectF& rectTar) const { QPointF pt1 = rectSrc.topLeft(); QPointF pt2 = rectSrc.bottomRight(); gis->convertRad2Px(pt1); gis->convertRad2Px(pt2); rectTar = QRectF(pt1,pt2); } void IMouseSelect::placeScrOpt() { if(scrOpt.isNull()) { return; } if((state == eStateMap) || (state == eStateMapMoving)) { QRectF rectSel; rectRad2Px(rectSelection, rectSel); scrOpt->move(rectSel.topRight().toPoint()); scrOpt->show(); } else { scrOpt->hide(); } } void IMouseSelect::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) { if(rectSelection.isNull()) { return; } QRectF rectSel; rectRad2Px(rectSelection, rectSel); QRectF rectScr = canvas->rect(); rectTopLeft.moveTopLeft(rectSel.topLeft()); rectTopRight.moveTopRight(rectSel.topRight()); rectBottomLeft.moveBottomLeft(rectSel.bottomLeft()); rectBottomRight.moveBottomRight(rectSel.bottomRight()); QPainterPath path; path.addRect(rectScr); path.addRect(rectSel); p.setPen(Qt::black); p.setBrush(QColor(0,0,0,128)); p.drawPath(path); p.setBrush(Qt::lightGray); p.drawRect(rectTopLeft); p.drawRect(rectTopRight); p.drawRect(rectBottomLeft); p.drawRect(rectBottomRight); p.setBrush(Qt::red); switch(corner) { case eCornerTopLeft: p.drawRect(rectTopLeft); break; case eCornerTopRight: p.drawRect(rectTopRight); break; case eCornerBottomLeft: p.drawRect(rectBottomLeft); break; case eCornerBottomRight: p.drawRect(rectBottomRight); break; } placeScrOpt(); } void IMouseSelect::mousePressEvent(QMouseEvent * e) { e->accept(); canvas->reportStatus("IMouseSelect", ""); if(e->button() == Qt::RightButton) { canvas->resetMouse(); canvas->update(); } else if(e->button() == Qt::LeftButton) { switch(state) { case eStateIdle: { QPointF pos = e->pos(); gis->convertPx2Rad(pos); rectSelection.setTopLeft(pos); rectSelection.setBottomRight(pos); posInitial = pos; state = eStateInitial; break; } case eStateMap: { if(corner != eCornerNone) { state = eStateResize; } else { lastPos = e->pos(); state = eStateMapMoving; } break; } } } } void IMouseSelect::mouseMoveEvent(QMouseEvent * e) { e->accept(); switch(state) { case eStateInitial: { QPointF pos = e->pos(); gis->convertPx2Rad(pos); if(pos.x() < posInitial.x()) { rectSelection.setLeft(pos.x()); } else { rectSelection.setRight(pos.x()); } if(pos.y() < posInitial.y()) { rectSelection.setBottom(pos.y()); } else { rectSelection.setTop(pos.y()); } canvas->update(); break; } case eStateMap: { corner_e _corner = corner; QPoint pos = e->pos(); if(rectTopLeft.contains(pos)) { offset = pos - rectTopLeft.topLeft(); corner = eCornerTopLeft; } else if(rectTopRight.contains(pos)) { offset = pos - rectTopRight.topRight(); corner = eCornerTopRight; } else if(rectBottomLeft.contains(pos)) { offset = pos - rectBottomLeft.bottomLeft(); corner = eCornerBottomLeft; } else if(rectBottomRight.contains(pos)) { offset = pos - rectBottomRight.bottomRight(); corner = eCornerBottomRight; } else { corner = eCornerNone; } if(corner != _corner) { canvas->update(); } break; } case eStateMapMoving: { QPoint pos = e->pos(); if(pos != lastPos) { QPoint delta = pos - lastPos; canvas->moveMap(delta); lastPos = pos; } break; } case eStateResize: { QPointF pos = e->pos() - offset; gis->convertPx2Rad(pos); switch(corner) { case eCornerTopLeft: rectSelection.setTopLeft(pos); break; case eCornerTopRight: rectSelection.setTopRight(pos); break; case eCornerBottomLeft: rectSelection.setBottomLeft(pos); break; case eCornerBottomRight: rectSelection.setBottomRight(pos); break; } canvas->update(); break; } } } void IMouseSelect::mouseReleaseEvent(QMouseEvent *e) { e->accept(); if(!rectSelection.isNull()) { QPointF pt1 = rectSelection.topLeft(); QPointF pt2 = rectSelection.bottomRight(); gis->convertRad2Px(pt1); gis->convertRad2Px(pt2); QRectF rectSel(pt1,pt2); if(rectSel.width() < 40 || rectSel.height() < 40) { rectSelection = QRectF(); } } state = rectSelection.isNull() ? eStateIdle : eStateMap; canvas->update(); } qmapshack-1.10.0/src/mouse/CMouseRangeTrk.cpp000644 001750 000144 00000020561 13216234140 022176 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/trk/CGisItemTrk.h" #include "mouse/CMouseRangeTrk.h" #include "mouse/CScrOptRangeTrk.h" #include CMouseRangeTrk::CMouseRangeTrk(CGisItemTrk &trk, CGisDraw *gis, CCanvas *parent) : IMouse(gis, parent) { cursor = QCursor(QPixmap("://cursors/cursorSelectRange.png"),0,0); key = trk.getKey(); // switch to full mode to show deleted (hidden) track points, too trk.setMode(CGisItemTrk::eModeRange, "CMouseRangeTrk"); resetState(); } CMouseRangeTrk::~CMouseRangeTrk() { canvas->reportStatus(key.item, ""); CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk) { trk->setMode(CGisItemTrk::eModeNormal, "CMouseRangeTrk"); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } delete scrOptRange; } void CMouseRangeTrk::draw(QPainter& p, CCanvas::redraw_e, const QRect &) { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk) { trk->drawRange(p); if(!mapDidMove && (anchor != NOPOINTF)) { p.setPen(Qt::darkBlue); p.setBrush(QColor(255,255,255,200)); p.drawEllipse(anchor, 6, 6); QPixmap bullet("://icons/8x8/bullet_magenta.png"); p.drawPixmap(anchor.x() - 3, anchor.y() - 3, bullet); } } if(!scrOptRange.isNull()) { scrOptRange->draw(p); } } void CMouseRangeTrk::mousePressEvent(QMouseEvent * e) { canvas->reportStatus(key.item, ""); point = e->pos(); if(e->button() == Qt::RightButton) { canvas->resetMouse(); canvas->update(); } else if(e->button() == Qt::LeftButton) { mapMove = true; firstPoint = point; } } void CMouseRangeTrk::mouseMoveEvent(QMouseEvent * e) { point = e->pos(); if(mapMove) { if((point - firstPoint).manhattanLength() >= 4) { QPoint delta = point - lastPoint; canvas->moveMap(delta); mapDidMove = true; } } else { switch(state) { case eStateIdle: { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { anchor = trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseMove, "CMouseRangeTrk"); canvas->update(); } break; } case eStateSelectRange: { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { anchor = trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseMove, "CMouseRangeTrk"); canvas->update(); } break; } default: ; } } lastPoint = point; } void CMouseRangeTrk::mouseReleaseEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) { if(!mapDidMove) { switch(state) { case eStateIdle: { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr && anchor != NOPOINTF) { anchor = trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseClick, "CMouseRangeTrk"); state = eStateSelectRange; canvas->update(); } break; } case eStateSelectRange: { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr && anchor != NOPOINTF) { QPointF pt = trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseClick, "CMouseRangeTrk"); scrOptRange = new CScrOptRangeTrk(pt, trk, this); connect(scrOptRange->toolHidePoints, &QToolButton::clicked, this, &CMouseRangeTrk::slotHidePoints); connect(scrOptRange->toolShowPoints, &QToolButton::clicked, this, &CMouseRangeTrk::slotShowPoints); connect(scrOptRange.data(), &CScrOptRangeTrk::activitySelected, this, &CMouseRangeTrk::slotActivity); connect(scrOptRange->toolCopy, &QToolButton::clicked, this, &CMouseRangeTrk::slotCopy); state = eStateRangeSelected; canvas->update(); } break; } case eStateRangeSelected: { resetState(); break; } } } mapDidMove = false; mapMove = false; } } void CMouseRangeTrk::wheelEvent(QWheelEvent * e) { if(state == eStateRangeSelected) { resetState(); } } void CMouseRangeTrk::keyPressEvent(QKeyEvent * e) { if(state == eStateRangeSelected) { resetState(); } } void CMouseRangeTrk::afterMouseLostEvent(QMouseEvent *e) { if(state == eStateRangeSelected) { resetState(); } if (e->type() == QEvent::MouseMove) { firstPoint = e->pos(); } mapMove = e->buttons() & Qt::LeftButton; mapDidMove = true; } void CMouseRangeTrk::resetState() { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { trk->setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CMouseRangeTrk"); trk->setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseClick, "CMouseRangeTrk"); } if(!scrOptRange.isNull()) { scrOptRange->deleteLater(); } state = eStateIdle; anchor = NOPOINTF; canvas->reportStatus(key.item, tr("Select Range
Select first track point with left mouse button. And then a second one. Leave range selection with a click of the right mouse button.
")); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseRangeTrk::slotHidePoints() { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { trk->hideSelectedPoints(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } resetState(); } void CMouseRangeTrk::slotShowPoints() { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { trk->showSelectedPoints(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } resetState(); } void CMouseRangeTrk::slotActivity(quint32 flags) { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(nullptr != trk) { trk->setActivityRange(flags); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } scrOptRange->deleteLater(); canvas->resetMouse(); } void CMouseRangeTrk::slotCopy() { QMutexLocker lock(&IGisItem::mutexItems); CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { trk->copySelectedPoints(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } scrOptRange->deleteLater(); canvas->resetMouse(); } qmapshack-1.10.0/src/mouse/CMouseEditRte.cpp000644 001750 000144 00000006547 13216234140 022031 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/rte/CGisItemRte.h" #include "mouse/CMouseEditRte.h" #include "mouse/line/CScrOptEditLine.h" #include CMouseEditRte::CMouseEditRte(const QPointF &point, CGisDraw *gis, CCanvas *parent) : IMouseEditLine(IGisItem::key_t(), point, true, tr("Route"), gis, parent) { startNewLine(point); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditRte::CMouseEditRte(CGisItemRte &rte, CGisDraw * gis, CCanvas * parent) : IMouseEditLine(rte.getKey(), rte, true, tr("Route"), gis, parent) { canvas->reportStatus(key.item, tr("Edit Route Points
Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.
") + docPanning); if(!points.first().subpts.isEmpty()) { scrOptEditLine->toolAutoRoute->setChecked(true); } else { scrOptEditLine->toolNoRoute->setChecked(true); } /* trigger complete update of GIS components to make sure all changes to the originating object are reflected on the canvas */ canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditRte::~CMouseEditRte() { } void CMouseEditRte::mousePressEvent(QMouseEvent * e) { canvas->reportStatus(key.item, ""); IMouseEditLine::mousePressEvent(e); } IGisLine * CMouseEditRte::getGisLine() const { return dynamic_cast(CGisWorkspace::self().getItemByKey(key)); } void CMouseEditRte::slotAbort() { canvas->reportStatus(key.item,""); IMouseEditLine::slotAbortEx(false); } void CMouseEditRte::slotCopyToOrig() { canvas->reportStatus(key.item,""); IMouseEditLine::slotCopyToOrig(); } void CMouseEditRte::slotCopyToNew() { canvas->reportStatus(key.item,""); if(points.size() < 2) { return; } IGisProject * project = nullptr; QString name; CGisItemRte * rte = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(rte != nullptr) { name = rte->getName(); } if(!IGisItem::getNameAndProject(name, project, tr("route"))) { return; } { QMutexLocker lock(&IGisItem::mutexItems); new CGisItemRte(points,name, project, NOIDX); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } qmapshack-1.10.0/src/mouse/CMouseSelect.h000644 001750 000144 00000004022 13216234143 021342 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSESELECT_H #define CMOUSESELECT_H #include "canvas/CCanvas.h" #include "gis/IGisItem.h" #include "mouse/IMouseSelect.h" class CGisDraw; class CCanvas; class CScrOptSelect; class CMouseSelect : public IMouseSelect { Q_OBJECT public: CMouseSelect(CGisDraw * gis, CCanvas * parent); virtual ~CMouseSelect(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; private slots: void slotCopy() const; void slotRoute() const; void slotSymWpt() const; void slotCombineTrk() const; void slotActivityTrk() const; void slotDelete() const; private: /** @brief Get a temporary list of all items @Note: The list of items is only temporary and must not be used outside the calling method. @param items a temporary list to collect all item pointers */ void findItems(QList &items); QList itemKeys; IGisItem::selflags_t modeLastSel = IGisItem::eSelectionNone; QRectF rectLastSel; quint32 cntWpt = 0; quint32 cntTrk = 0; quint32 cntRte = 0; quint32 cntOvl = 0; }; #endif //CMOUSESELECT_H qmapshack-1.10.0/src/mouse/CMouseDummy.cpp000644 001750 000144 00000002112 13216234140 021544 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "CMouseDummy.h" CMouseDummy::CMouseDummy() : IMouse(nullptr, nullptr) { cursor = QCursor(QPixmap(":/cursors/cursorArrow.png"),0,0); } CMouseDummy::~CMouseDummy() { } qmapshack-1.10.0/src/mouse/IScrOptSelect.ui000644 001750 000144 00000027652 13147467777 021726 0ustar00oeichlerxusers000000 000000 IScrOptSelect 0 0 27 294 Form 3 3 0 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 0 Copy all selected items to a project. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png 16 16 Create a route from selected waypoints. ... :/icons/32x32/Route.png:/icons/32x32/Route.png 16 16 Change the icon of all selected waypoints. ... :/icons/waypoints/32x32/PinBlue.png:/icons/waypoints/32x32/PinBlue.png 16 16 Combine all selected tracks to a new one. ... :/icons/32x32/Combine.png:/icons/32x32/Combine.png 16 16 Set an activity for all selected tracks. ... :/icons/32x32/Activity.png:/icons/32x32/Activity.png Delete all selected items. ... :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png 16 16 Qt::Horizontal QFrame::NoFrame QFrame::Plain 0 0 0 0 0 Select all items that intersect the selected area. ... :/icons/32x32/SelectIntersectArea.png:/icons/32x32/SelectIntersectArea.png 16 16 true true true Select all items that are completely inside the selected area. ... :/icons/32x32/SelectExactArea.png:/icons/32x32/SelectExactArea.png 16 16 true true Qt::Horizontal QFrame::NoFrame QFrame::Plain 0 0 0 0 0 Add tracks to selection. ... :/icons/32x32/Track.png :/icons/32x32/TrackOn.png:/icons/32x32/Track.png 16 16 true true Add waypoints to selection. ... :/icons/waypoints/32x32/FlagBlue.png :/icons/32x32/WaypointOn.png:/icons/waypoints/32x32/FlagBlue.png 16 16 true true Add routes to selection. ... :/icons/32x32/Route.png :/icons/32x32/RouteOn.png:/icons/32x32/Route.png 16 16 true true Add areas to selection. ... :/icons/32x32/Area.png :/icons/32x32/AreaOn.png:/icons/32x32/Area.png 16 16 true true qmapshack-1.10.0/src/mouse/CScrOptPrint.h000644 001750 000144 00000002320 13216234143 021340 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTPRINT_H #define CSCROPTPRINT_H #include "mouse/IScrOpt.h" #include "ui_IScrOptPrint.h" class CScrOptPrint : public IScrOpt, public Ui::IScrOptPrint { public: CScrOptPrint(IMouse *mouse); virtual ~CScrOptPrint() = default; void draw(QPainter& p) override { } }; #endif //CSCROPTPRINT_H qmapshack-1.10.0/src/mouse/CScrOptRangeTrk.cpp000644 001750 000144 00000004446 13216234140 022324 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "mouse/CScrOptRangeTrk.h" #include CScrOptRangeTrk::CScrOptRangeTrk(const QPointF &point, CGisItemTrk * trk, IMouse *mouse, QWidget *parent) : IScrOpt(mouse) { if(parent != nullptr) { setParent(parent); } setupUi(this); bool noRange = !trk->isRangeSelected(); label->setFont(CMainWindow::self().getMapFont()); label->setText(noRange ? tr("No range selected") : trk->getInfoRange()); adjustSize(); setOrigin(point.toPoint()); move(point.toPoint() + QPoint(-width()/2,SCR_OPT_OFFSET)); show(); toolCopy->setDisabled(noRange); toolActivity->setDisabled(noRange); connect(toolHidePoints, &QToolButton::clicked, this, &CScrOptRangeTrk::hide); connect(toolShowPoints, &QToolButton::clicked, this, &CScrOptRangeTrk::hide); connect(toolCopy, &QToolButton::clicked, this, &CScrOptRangeTrk::hide); connect(toolActivity, &QToolButton::clicked, this, &CScrOptRangeTrk::selectActivity); } CScrOptRangeTrk::~CScrOptRangeTrk() { } void CScrOptRangeTrk::draw(QPainter& p) { if(isVisible()) { CDraw::bubble(p, geometry(), origin); } } void CScrOptRangeTrk::selectActivity() { quint32 flags = CActivityTrk::selectActivity(this); if(0xFFFFFFFF != flags) { emit activitySelected(flags); } hide(); } qmapshack-1.10.0/src/mouse/IScrOpt.h000644 001750 000144 00000003075 13216234143 020341 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef ISCROPT_H #define ISCROPT_H #include #include #include #include class QMouseEvent; class IMouse; #define SCR_OPT_OFFSET 15 class IScrOpt : public QWidget { public: IScrOpt(IMouse *mouse); virtual ~IScrOpt(); void setOrigin(const QPoint& pos) { origin = pos; } const QPoint& getOrigin() const { return origin; } virtual void draw(QPainter& p) = 0; void mouseMoveEvent(QMouseEvent *) override; protected: void enterEvent(QEvent *e) override; void leaveEvent(QEvent *e) override; QPoint origin; QPoint mousePos; QPointer mouse; }; #endif //ISCROPT_H qmapshack-1.10.0/src/mouse/CMouseRadiusWpt.h000644 001750 000144 00000003537 13216234261 022060 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 . **********************************************************************************************/ #ifndef CMOUSERADIUSWPT_H #define CMOUSERADIUSWPT_H #include "gis/IGisItem.h" #include "mouse/IMouse.h" class CGisItemWpt; class CGisDraw; class CCanvas; class CMouseRadiusWpt : public IMouse { Q_OBJECT public: CMouseRadiusWpt(CGisItemWpt& wpt, CGisDraw * gis, CCanvas * parent); virtual ~CMouseRadiusWpt(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; void afterMouseLostEvent(QMouseEvent *e) override; private: const IGisItem::key_t key; const QPointF wptPosition; const bool avoid; bool start; qreal dist; bool mapMove = false; bool mapDidMove = false; QPoint lastPoint; }; #endif //CMOUSERADIUSWPT_H qmapshack-1.10.0/src/mouse/CMouseEditArea.cpp000644 001750 000144 00000006454 13216234140 022144 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/ovl/CGisItemOvlArea.h" #include "mouse/CMouseEditArea.h" #include CMouseEditArea::CMouseEditArea(const QPointF& point, CGisDraw * gis, CCanvas * parent) : IMouseEditLine(IGisItem::key_t(), point, false, tr("Area"), gis, parent) { startNewLine(point); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditArea::CMouseEditArea(CGisItemOvlArea &area, CGisDraw * gis, CCanvas * parent) : IMouseEditLine(area.getKey(), area, false, tr("Area"), gis, parent) { canvas->reportStatus(key.item, tr("Edit Area
Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.
") + docPanning); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditArea::~CMouseEditArea() { canvas->reportStatus(key.item, ""); } void CMouseEditArea::mousePressEvent(QMouseEvent * e) { canvas->reportStatus(key.item, ""); IMouseEditLine::mousePressEvent(e); } void CMouseEditArea::drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p) { p.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); p.setBrush(QBrush(Qt::magenta, Qt::BDiagPattern)); p.drawPolygon(l); } IGisLine * CMouseEditArea::getGisLine() const { return dynamic_cast(CGisWorkspace::self().getItemByKey(key)); } void CMouseEditArea::slotAbort() { canvas->reportStatus(key.item,""); IMouseEditLine::slotAbortEx(false); } void CMouseEditArea::slotCopyToOrig() { canvas->reportStatus(key.item,""); IMouseEditLine::slotCopyToOrig(); } void CMouseEditArea::slotCopyToNew() { canvas->reportStatus(key.item,""); if(points.size() < 3) { return; } IGisProject * project = nullptr; QString name; CGisItemOvlArea * area = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(area != nullptr) { name = area->getName(); } if(!IGisItem::getNameAndProject(name, project, tr("area"))) { return; } { QMutexLocker lock(&IGisItem::mutexItems); new CGisItemOvlArea(points, name, project, NOIDX); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } qmapshack-1.10.0/src/mouse/CMouseSelect.cpp000644 001750 000144 00000013037 13216234140 021700 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "helpers/CWptIconDialog.h" #include "mouse/CMouseSelect.h" #include "mouse/CScrOptSelect.h" #include CMouseSelect::CMouseSelect(CGisDraw *gis, CCanvas *parent) : IMouseSelect(gis, parent) { cursor = QCursor(QPixmap("://cursors/cursorSelectArea.png"),0,0); canvas->reportStatus("IMouseSelect", tr("Select Items On Map
Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners.")); CScrOptSelect * scrOptSelect; scrOpt = scrOptSelect = new CScrOptSelect(this); connect(scrOptSelect->toolCopy, &QToolButton::clicked, this, &CMouseSelect::slotCopy); connect(scrOptSelect->toolRoute, &QToolButton::clicked, this, &CMouseSelect::slotRoute); connect(scrOptSelect->toolSymWpt, &QToolButton::clicked, this, &CMouseSelect::slotSymWpt); connect(scrOptSelect->toolCombineTrk, &QToolButton::clicked, this, &CMouseSelect::slotCombineTrk); connect(scrOptSelect->toolActivityTrk, &QToolButton::clicked, this, &CMouseSelect::slotActivityTrk); connect(scrOptSelect->toolDelete, &QToolButton::clicked, this, &CMouseSelect::slotDelete); } CMouseSelect::~CMouseSelect() { canvas->reportStatus("CMouseSelect::Stat", ""); } void CMouseSelect::findItems(QList& items) { CScrOptSelect * scrOptSelect = dynamic_cast((IScrOpt*)scrOpt); IGisItem::selflags_t modeSelection = scrOptSelect->getModeSelection(); if((rectSelection == rectLastSel) && (modeSelection == modeLastSel)) { if(!itemKeys.isEmpty()) { CGisWorkspace::self().getItemsByKeys(itemKeys, items); } } else { itemKeys.clear(); QRectF area; rectRad2Px(rectSelection, area); CGisWorkspace::self().getItemsByArea(area, modeSelection, items); cntWpt = 0; cntTrk = 0; cntRte = 0; cntOvl = 0; for(IGisItem * item : items) { itemKeys << item->getKey(); switch(item->type()) { case IGisItem::eTypeWpt: cntWpt++; break; case IGisItem::eTypeTrk: cntTrk++; break; case IGisItem::eTypeRte: cntRte++; break; case IGisItem::eTypeOvl: cntOvl++; break; } } QString msg = tr("Selected:
"); if(scrOptSelect->toolItemTrk->isChecked()) { msg += tr("%1 tracks
").arg(cntTrk); } if(scrOptSelect->toolItemWpt->isChecked()) { msg += tr("%1 waypoints
").arg(cntWpt); } if(scrOptSelect->toolItemRte->isChecked()) { msg += tr("%1 routes
").arg(cntRte); } if(scrOptSelect->toolItemOvl->isChecked()) { msg += tr("%1 areas
").arg(cntOvl); } canvas->reportStatus("CMouseSelect::Stat",msg); rectLastSel = rectSelection; modeLastSel = modeSelection; } scrOptSelect->frameFunction->setDisabled(items.isEmpty()); scrOptSelect->toolSymWpt->setEnabled(cntWpt); scrOptSelect->toolRoute->setEnabled(cntWpt > 1); scrOptSelect->toolCombineTrk->setEnabled(cntTrk > 1); scrOptSelect->toolActivityTrk->setEnabled(cntTrk > 0); } void CMouseSelect::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) { if(rectSelection.isNull()) { return; } QList items; findItems(items); for(IGisItem * item : items) { item->drawHighlight(p); } IMouseSelect::draw(p, needsRedraw, rect); } void CMouseSelect::slotCopy() const { CGisWorkspace::self().copyItemsByKey(itemKeys); canvas->resetMouse(); } void CMouseSelect::slotDelete() const { CGisWorkspace::self().delItemsByKey(itemKeys); canvas->resetMouse(); } void CMouseSelect::slotRoute() const { CGisWorkspace::self().makeRteFromWpt(itemKeys); canvas->resetMouse(); } void CMouseSelect::slotCombineTrk() const { CGisWorkspace::self().combineTrkByKey(itemKeys, itemKeys); canvas->resetMouse(); } void CMouseSelect::slotActivityTrk() const { CGisWorkspace::self().activityTrkByKey(itemKeys); canvas->resetMouse(); } void CMouseSelect::slotSymWpt() const { QToolButton tb; CWptIconDialog dlg(&tb); if(dlg.exec() == QDialog::Rejected) { return; } CGisWorkspace::self().changeWptSymByKey(itemKeys, tb.objectName()); canvas->resetMouse(); } qmapshack-1.10.0/src/mouse/CScrOptSelect.h000644 001750 000144 00000003003 13216234143 021462 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTSELECT_H #define CSCROPTSELECT_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" #include "ui_IScrOptSelect.h" class IMouse; class CScrOptSelect : public IScrOpt, public Ui::IScrOptSelect { Q_OBJECT public: CScrOptSelect(IMouse *mouse); virtual ~CScrOptSelect(); void draw(QPainter& p) override { } IGisItem::selflags_t getModeSelection() const { return modeSelection; } private slots: void slotModeSwitch(IGisItem::selection_e mode, bool checked); private: IGisItem::selflags_t modeSelection = IGisItem::eSelectionNone; }; #endif //CSCROPTSELECT_H qmapshack-1.10.0/src/mouse/CMouseWptBubble.cpp000644 001750 000144 00000004520 13216234140 022344 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/wpt/CGisItemWpt.h" #include "mouse/CMouseWptBubble.h" #include CMouseWptBubble::CMouseWptBubble(const IGisItem::key_t &key, CGisDraw * gis, CCanvas * parent) : IMouse(gis, parent) , key(key) { cursor = QCursor(QPixmap("://cursors/cursorArrow.png"), 0, 0); } CMouseWptBubble::~CMouseWptBubble() { } void CMouseWptBubble::draw(QPainter&, CCanvas::redraw_e, const QRect&) { } void CMouseWptBubble::mousePressEvent(QMouseEvent * e) { QMutexLocker lock(&IGisItem::mutexItems); QPointF pos = e->pos(); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt) { wpt->mousePress(pos); } else { canvas->resetMouse(); } } void CMouseWptBubble::mouseMoveEvent(QMouseEvent * e) { QMutexLocker lock(&IGisItem::mutexItems); QPointF pos = e->pos(); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt) { wpt->mouseMove(pos); } else { canvas->resetMouse(); } } void CMouseWptBubble::mouseReleaseEvent(QMouseEvent *e) { QMutexLocker lock(&IGisItem::mutexItems); QPointF pos = e->pos(); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt) { wpt->mouseRelease(pos); } else { canvas->resetMouse(); } } qmapshack-1.10.0/src/mouse/CScrOptPrint.cpp000644 001750 000144 00000002045 13216234140 021674 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "CScrOptPrint.h" #include CScrOptPrint::CScrOptPrint(IMouse *mouse) : IScrOpt(mouse) { setupUi(this); adjustSize(); } qmapshack-1.10.0/src/mouse/CMouseMoveWpt.cpp000644 001750 000144 00000011626 13216234261 022070 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "GeoMath.h" #include "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/WptIcons.h" #include "gis/wpt/CGisItemWpt.h" #include "helpers/CDraw.h" #include "mouse/CMouseMoveWpt.h" #include "units/IUnit.h" #include #include CMouseMoveWpt::CMouseMoveWpt(CGisItemWpt &wpt, CGisDraw * gis, CCanvas *parent) : IMouse(gis, parent), key(wpt.getKey()), origPos(wpt.getPosition()*DEG_TO_RAD), radius(wpt.getProximity()), avoid(wpt.isNogoArea()) { cursor = QCursor(QPixmap(":/cursors/cursorMoveWpt.png"), 0, 0); icon = getWptIconByName(wpt.getIconName(), focus); newPos = origPos; wpt.setHideArea(true); canvas->triggerCompleteUpdate(CCanvas::eRedrawGis); } CMouseMoveWpt::~CMouseMoveWpt() { } void CMouseMoveWpt::draw(QPainter& p, CCanvas::redraw_e, const QRect&) { QString val, unit; qreal a1 = 0, a2 = 0; QPointF p1 = origPos; QPointF p2 = newPos; qreal d = GPS_Math_Distance(p1.x(), p1.y(), p2.x(), p2.y(), a1, a2); IUnit::self().meter2distance(d, val, unit); const QString &str = QString("%1 %2, %3%4").arg(val).arg(unit).arg(a2, 0, 'f', 1).arg(QChar(0260)); gis->convertRad2Px(p1); gis->convertRad2Px(p2); qreal r = CGisItemWpt::calcRadius(newPos,p2,radius,gis); CGisItemWpt::drawCircle(p,p2,r,avoid,false); QPointF p11 = p1 + QPoint(17 * qCos((a1 - 90) * DEG_TO_RAD), 17 * qSin((a1 - 90) * DEG_TO_RAD)); QPointF p22 = p2 + QPoint(21 * qCos((a2 + 90) * DEG_TO_RAD), 21 * qSin((a2 + 90) * DEG_TO_RAD)); QPen pen(Qt::darkBlue, 3); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::MiterJoin); p.setPen(pen); p.setBrush(Qt::NoBrush); p.drawEllipse(p1, 16, 16); p.drawEllipse(p2, 16, 16); p.drawLine(p11, p22); p.save(); p.translate(p22); p.rotate(a2 + 180); QPolygonF arrow; arrow << QPointF(0, 0) << QPointF(5, -20) << QPointF(0, -10) << QPointF(-5, -20); p.setBrush(Qt::NoBrush); p.drawPolygon(arrow); p.restore(); CDraw::text(str, p, (p2 + QPoint(0, -30)).toPoint(), Qt::darkBlue); p.drawPixmap(p1 - focus, icon); p.drawPixmap(p2 - focus, icon); } void CMouseMoveWpt::mousePressEvent(QMouseEvent * e) { point = e->pos(); if(e->button() == Qt::RightButton) { CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt != nullptr) { wpt->setHideArea(false); } canvas->resetMouse(); canvas->triggerCompleteUpdate(CCanvas::eRedrawGis); } else if(e->button() == Qt::LeftButton) { mapMove = true; lastPoint = point; } } void CMouseMoveWpt::mouseMoveEvent(QMouseEvent * e) { point = e->pos(); if(mapMove) { if(point != lastPoint) { QPoint delta = point - lastPoint; canvas->moveMap(delta); mapDidMove = true; } } else { newPos = point; gis->convertPx2Rad(newPos); } lastPoint = point; canvas->update(); } void CMouseMoveWpt::mouseReleaseEvent(QMouseEvent *e) { point = e->pos(); if(!mapDidMove && (e->button() == Qt::LeftButton)) { QMutexLocker lock(&IGisItem::mutexItems); QPointF pos = e->pos(); gis->convertPx2Rad(pos); CGisItemWpt * wpt = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(wpt != nullptr) { wpt->setPosition(pos * RAD_TO_DEG); wpt->setHideArea(false); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } mapMove = false; mapDidMove = false; } void CMouseMoveWpt::wheelEvent(QWheelEvent*) { canvas->update(); } void CMouseMoveWpt::afterMouseLostEvent(QMouseEvent *e) { if (e->type() == QEvent::MouseMove) { lastPoint = e->pos(); } mapMove = e->buttons() & Qt::LeftButton; mapDidMove = true; } qmapshack-1.10.0/src/mouse/CMouseMoveWpt.h000644 001750 000144 00000003501 13216234261 021526 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEMOVEWPT_H #define CMOUSEMOVEWPT_H #include "gis/IGisItem.h" #include "mouse/IMouse.h" #include class CCanvas; class CGisItemWpt; class CGisDraw; class CMouseMoveWpt : public IMouse { public: CMouseMoveWpt(CGisItemWpt& wpt, CGisDraw * gis, CCanvas * parent); virtual ~CMouseMoveWpt(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; void afterMouseLostEvent(QMouseEvent *e) override; private: const IGisItem::key_t key; const QPointF origPos; const qreal radius; const bool avoid; QPointF newPos; QPointF focus; QPixmap icon; bool mapMove = false; bool mapDidMove = false; QPoint lastPoint; }; #endif //CMOUSEMOVEWPT_H qmapshack-1.10.0/src/mouse/CMouseRangeTrk.h000644 001750 000144 00000004205 13216234143 021643 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSERANGETRK_H #define CMOUSERANGETRK_H #include "gis/IGisItem.h" #include "mouse/IMouse.h" #include class CGisItemTrk; class CGisDraw; class CCanvas; class CScrOptRangeTrk; class CMouseRangeTrk : public IMouse { Q_OBJECT public: CMouseRangeTrk(CGisItemTrk& trk, CGisDraw * gis, CCanvas * parent); virtual ~CMouseRangeTrk(); void draw(QPainter& p, CCanvas::redraw_e, const QRect &) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; void keyPressEvent(QKeyEvent *e) override; void afterMouseLostEvent(QMouseEvent *e) override; private slots: void slotHidePoints(); void slotShowPoints(); void slotActivity(quint32 flags); void slotCopy(); private: void resetState(); IGisItem::key_t key; enum state_e { eStateIdle ,eStateSelectRange ,eStateRangeSelected }; bool mapMove = false; bool mapDidMove = false; state_e state = eStateIdle; QPointF anchor = NOPOINTF; QPoint lastPoint; QPoint firstPoint; QPointer scrOptRange; }; #endif //CMOUSERANGETRK_H qmapshack-1.10.0/src/mouse/IScrOptRangeTrk.ui000644 001750 000144 00000007153 13147467760 022206 0ustar00oeichlerxusers000000 000000 IScrOptRangeTrk 0 0 116 100 Form 3 3 3 3 3 3 Hide all points. ... :/icons/32x32/PointHide.png:/icons/32x32/PointHide.png Show all points. ... :/icons/32x32/PointShow.png:/icons/32x32/PointShow.png Set an activity for the selected range. ... :/icons/32x32/Activity.png:/icons/32x32/Activity.png Copy track points as new track. ... :/icons/32x32/Copy.png:/icons/32x32/Copy.png Qt::Horizontal 40 20 0 0 TextLabel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop qmapshack-1.10.0/src/mouse/CMousePrint.cpp000644 001750 000144 00000004262 13216234140 021555 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisDraw.h" #include "mouse/CMousePrint.h" #include "mouse/CScrOptPrint.h" #include "print/CPrintDialog.h" #include CMousePrint::CMousePrint(CGisDraw *gis, CCanvas *parent) : IMouseSelect(gis, parent) { cursor = QCursor(QPixmap("://cursors/cursorSave.png"),0,0); canvas->reportStatus("IMouseSelect", tr("Save(Print) Map
Select a rectangular area on the map. Use the left mouse button and move the mouse. Abort with a right click. Adjust the selection by point-click-move on the corners.")); CScrOptPrint * scrOptPrint; scrOpt = scrOptPrint = new CScrOptPrint(this); connect(scrOptPrint->toolSave, &QToolButton::clicked, this, &CMousePrint::slotSave); connect(scrOptPrint->toolPrint, &QToolButton::clicked, this, &CMousePrint::slotPrint); } CMousePrint::~CMousePrint() { } void CMousePrint::slotSave() { CPrintDialog dlg(CPrintDialog::eTypeImage, rectSelection, canvas); dlg.exec(); canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); canvas->resetMouse(); } void CMousePrint::slotPrint() { CPrintDialog dlg(CPrintDialog::eTypePrint, rectSelection, canvas); dlg.exec(); canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); canvas->resetMouse(); } qmapshack-1.10.0/src/mouse/IMouse.cpp000644 001750 000144 00000002320 13216234140 020537 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "mouse/IMouse.h" #include IMouse::IMouse(CGisDraw *gis, CCanvas *canvas) : QObject(canvas) , gis(gis) , canvas(canvas) { } IMouse::~IMouse() { } void IMouse::setMouseTracking(bool enabled) { canvas->setMouseTracking(enabled); } qmapshack-1.10.0/src/mouse/CMouseEditTrk.cpp000644 001750 000144 00000007536 13216234140 022036 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/CGisWorkspace.h" #include "gis/trk/CGisItemTrk.h" #include "mouse/CMouseEditTrk.h" #include CMouseEditTrk::CMouseEditTrk(const QPointF& point, CGisDraw * gis, CCanvas * parent) : IMouseEditLine(IGisItem::key_t(), point, true, tr("Track"), gis, parent) { startNewLine(point); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditTrk::CMouseEditTrk(CGisItemTrk &trk, CGisDraw * gis, CCanvas * parent) : IMouseEditLine(trk.getKey(), trk, true, tr("Track"), gis, parent) , isNewLine(false) { canvas->reportStatus(key.item, tr("Edit Track Points
Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.
") + docPanning); // reset any focus the track might have. trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CMouseEditTrk"); trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseClick, "CMouseEditTrk"); trk.looseUserFocus(); /* trigger complete update of GIS components to make sure all changes to the originating object are reflected on the canvas */ canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse); } CMouseEditTrk::~CMouseEditTrk() { // canvas->reportStatus(key,""); } void CMouseEditTrk::mousePressEvent(QMouseEvent * e) { canvas->reportStatus(key.item, ""); IMouseEditLine::mousePressEvent(e); } IGisLine * CMouseEditTrk::getGisLine() const { return dynamic_cast(CGisWorkspace::self().getItemByKey(key)); } void CMouseEditTrk::slotAbort() { canvas->reportStatus(key.item, ""); IMouseEditLine::slotAbortEx(false); } void CMouseEditTrk::slotCopyToOrig() { canvas->reportStatus(key.item, ""); if(!isNewLine) { QMessageBox::StandardButton button = QMessageBox::warning(canvas, tr("Warning!"), tr("This will replace all data of the original by a simple line of coordinates. All other data will be lost permanently."), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok); if(button != QMessageBox::Ok) { return; } } IMouseEditLine::slotCopyToOrig(); } void CMouseEditTrk::slotCopyToNew() { canvas->reportStatus(key.item,""); if(points.size() < 2) { return; } IGisProject * project = nullptr; QString name; CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { name = trk->getName(); } if(!IGisItem::getNameAndProject(name, project, tr("track"))) { return; } CMainWindow::self().getElevationAt(points); { QMutexLocker lock(&IGisItem::mutexItems); new CGisItemTrk(points, name, project, NOIDX); } canvas->resetMouse(); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } qmapshack-1.10.0/src/mouse/CMouseWptBubble.h000644 001750 000144 00000003024 13216234143 022012 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEWPTBUBBLE_H #define CMOUSEWPTBUBBLE_H #include "gis/IGisItem.h" #include "mouse/IMouse.h" class CGisItemWpt; class CGisDraw; class CCanvas; class CMouseWptBubble : public IMouse { Q_OBJECT public: CMouseWptBubble(const IGisItem::key_t& key, CGisDraw * gis, CCanvas * parent); virtual ~CMouseWptBubble(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; private: const IGisItem::key_t& key; }; #endif //CMOUSEWPTBUBBLE_H qmapshack-1.10.0/src/mouse/CScrOptUnclutter.h000644 001750 000144 00000003400 13216234143 022231 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CSCROPTUNCLUTTER_H #define CSCROPTUNCLUTTER_H #include "gis/IGisItem.h" #include "mouse/IScrOpt.h" class CScrOptUnclutter : public IScrOpt { public: CScrOptUnclutter(IMouse *mouse); virtual ~CScrOptUnclutter(); struct item_t { bool hasUserFocus; QString name; IGisItem::key_t key; QPixmap icon; QRect area; QRect text; QRect active; }; virtual void clear(); virtual int size() { return items.size(); } void addItem(IGisItem * gisItem); IGisItem::key_t getItemKey(int index = 0); const item_t *selectItem(const QPoint& point); void draw(QPainter& p) override; void mouseMoveEvent(QMouseEvent * e) override; private: static const QPoint positions[9][8]; QList items; bool doSpecialCursor = false; }; #endif //CSCROPTUNCLUTTER_H qmapshack-1.10.0/src/mouse/CScrOptSelect.cpp000644 001750 000144 00000014175 13216234140 022026 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 "canvas/CCanvas.h" #include "helpers/CSettings.h" #include "mouse/CScrOptSelect.h" #include "mouse/IMouse.h" #include #include using std::bind; CScrOptSelect::CScrOptSelect(IMouse *mouse) : IScrOpt(mouse) { setupUi(this); adjustSize(); SETTINGS; cfg.beginGroup("Selection"); toolModeExact->setChecked(cfg.value("modeExact", toolModeExact->isChecked()).toBool()); toolModeIntersect->setChecked(cfg.value("modeIntersect", toolModeIntersect->isChecked()).toBool()); toolItemTrk->setChecked(cfg.value("itemTrk", toolItemTrk->isChecked()).toBool()); toolItemWpt->setChecked(cfg.value("itemWpt", toolItemWpt->isChecked()).toBool()); toolItemRte->setChecked(cfg.value("itemRte", toolItemRte->isChecked()).toBool()); toolItemOvl->setChecked(cfg.value("itemOvl", toolItemOvl->isChecked()).toBool()); cfg.endGroup(); //Selection modeSelection |= toolModeExact->isChecked() ? IGisItem::eSelectionExact : 0; modeSelection |= toolModeIntersect->isChecked() ? IGisItem::eSelectionIntersect : 0; modeSelection |= toolItemTrk->isChecked() ? IGisItem::eSelectionTrk : 0; modeSelection |= toolItemWpt->isChecked() ? IGisItem::eSelectionWpt : 0; modeSelection |= toolItemRte->isChecked() ? IGisItem::eSelectionRte : 0; modeSelection |= toolItemOvl->isChecked() ? IGisItem::eSelectionOvl : 0; auto slotModeExact = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionExact, std::placeholders::_1); auto slotModeIntersect = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionIntersect, std::placeholders::_1); auto slotModeTrk = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionTrk, std::placeholders::_1); auto slotModeWpt = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionWpt, std::placeholders::_1); auto slotModeRte = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionRte, std::placeholders::_1); auto slotModeOvl = bind(&CScrOptSelect::slotModeSwitch, this, IGisItem::eSelectionOvl, std::placeholders::_1); connect(toolModeExact, &QToolButton::toggled, this, slotModeExact); connect(toolModeIntersect, &QToolButton::toggled, this, slotModeIntersect); connect(toolItemTrk, &QToolButton::toggled, this, slotModeTrk); connect(toolItemWpt, &QToolButton::toggled, this, slotModeWpt); connect(toolItemRte, &QToolButton::toggled, this, slotModeRte); connect(toolItemOvl, &QToolButton::toggled, this, slotModeOvl); } CScrOptSelect::~CScrOptSelect() { SETTINGS; cfg.beginGroup("Selection"); cfg.setValue("modeExact", toolModeExact->isChecked()); cfg.setValue("modeIntersect", toolModeIntersect->isChecked()); cfg.setValue("itemTrk", toolItemTrk->isChecked()); cfg.setValue("itemWpt", toolItemWpt->isChecked()); cfg.setValue("itemRte", toolItemRte->isChecked()); cfg.setValue("itemOvl", toolItemOvl->isChecked()); cfg.endGroup(); //Selection mouse->getCanvas()->reportStatus("CScrOptSelect",""); } void CScrOptSelect::slotModeSwitch(IGisItem::selection_e mode, bool checked) { CCanvas * canvas = mouse->getCanvas(); if(checked) { modeSelection |= mode; switch(mode) { case IGisItem::eSelectionExact: canvas->reportStatus("CScrOptSelect", tr("Exact Mode
All selected items have to be completely inside the selected area.
")); break; case IGisItem::eSelectionIntersect: canvas->reportStatus("CScrOptSelect", tr("Intersecting Mode
All selected items have to be inside or at least intersect the selected area.
")); break; case IGisItem::eSelectionTrk: canvas->reportStatus("CScrOptSelect", tr("Add Tracks
Add tracks to list of selected items
")); break; case IGisItem::eSelectionWpt: canvas->reportStatus("CScrOptSelect", tr("Add Waypoints
Add waypoints to list of selected items
")); break; case IGisItem::eSelectionRte: canvas->reportStatus("CScrOptSelect", tr("Add Routes
Add routes to list of selected items
")); break; case IGisItem::eSelectionOvl: canvas->reportStatus("CScrOptSelect", tr("Add Areas
Add areas to list of selected items
")); break; } } else { modeSelection &= ~mode; switch(mode) { case IGisItem::eSelectionTrk: canvas->reportStatus("CScrOptSelect", tr("Ignore Tracks
Ignore tracks in list of selected items
")); break; case IGisItem::eSelectionWpt: canvas->reportStatus("CScrOptSelect", tr("Ignore Waypoints
Ignore waypoints in list of selected items
")); break; case IGisItem::eSelectionRte: canvas->reportStatus("CScrOptSelect", tr("Ignore Routes
Ignore routes in list of selected items
")); break; case IGisItem::eSelectionOvl: canvas->reportStatus("CScrOptSelect", tr("Ignore Areas
Ignore areas in list of selected items
")); break; } } canvas->update(); } qmapshack-1.10.0/src/mouse/IMouseSelect.h000644 001750 000144 00000004313 13216234143 021353 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2016 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef IMOUSESELECT_H #define IMOUSESELECT_H #include "canvas/CCanvas.h" #include "mouse/IMouse.h" class CGisDraw; class IMouseSelect : public IMouse { Q_OBJECT public: IMouseSelect(CGisDraw * gis, CCanvas * canvas); virtual ~IMouseSelect(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override; void mousePressEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent *e) override; protected: void rectRad2Px(const QRectF& rectSrc, QRectF& rectTar) const; void placeScrOpt(); QPoint lastPos; QPointF offset; QPointF posInitial; QRectF rectSelection; QRectF rectTopLeft {0, 0, 20, 20}; QRectF rectTopRight {0, 0, 20, 20}; QRectF rectBottomLeft {0, 0, 20, 20}; QRectF rectBottomRight {0, 0, 20, 20}; enum state_e { eStateIdle ,eStateInitial ,eStateMap ,eStateMapMoving ,eStateResize }; state_e state = eStateIdle; enum corner_e { eCornerNone , eCornerTopLeft , eCornerTopRight , eCornerBottomLeft , eCornerBottomRight , eCornerPrint , eCornerImage }; corner_e corner = eCornerNone; QPointer scrOpt; }; #endif //IMOUSESELECT_H qmapshack-1.10.0/src/mouse/CMouseEditTrk.h000644 001750 000144 00000003017 13216234143 021474 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEEDITTRK_H #define CMOUSEEDITTRK_H #include "mouse/line/IMouseEditLine.h" class CGisItemTrk; class CMouseEditTrk : public IMouseEditLine { Q_OBJECT public: CMouseEditTrk(const QPointF& point, CGisDraw * gis, CCanvas * parent); CMouseEditTrk(CGisItemTrk &trk, CGisDraw * gis, CCanvas * parent); virtual ~CMouseEditTrk(); void mousePressEvent(QMouseEvent * e) override; protected slots: void slotAbort() override; void slotCopyToNew() override; void slotCopyToOrig() override; protected: IGisLine* getGisLine() const override; bool isNewLine = true; }; #endif //CMOUSEEDITTRK_H qmapshack-1.10.0/src/mouse/IScrOpt.cpp000644 001750 000144 00000003343 13216234140 020667 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "gis/CGisWorkspace.h" #include "helpers/CDraw.h" #include "mouse/IMouse.h" #include "mouse/IScrOpt.h" #include "units/IUnit.h" #include IScrOpt::IScrOpt(IMouse *mouse) : QWidget(mouse->getCanvas()) , mouse(mouse) { setFocusPolicy(Qt::WheelFocus); } IScrOpt::~IScrOpt() { if(hasFocus() && !mouse.isNull()) { CCanvas::setOverrideCursor(*mouse,"IScrOpt::~IScrOpt"); } CGisWorkspace::self().slotWksItemSelectionReset(); } void IScrOpt::mouseMoveEvent(QMouseEvent * e) { mousePos = e->pos(); } void IScrOpt::enterEvent(QEvent * e) { QWidget::enterEvent(e); CCanvas::restoreOverrideCursor("IScrOpt::enterEvent"); } void IScrOpt::leaveEvent(QEvent * e) { QWidget::leaveEvent(e); if(!mouse.isNull()) { CCanvas::setOverrideCursor(*mouse,"IScrOpt::leaveEvent"); } } qmapshack-1.10.0/src/mouse/CMouseDummy.h000644 001750 000144 00000002560 13216234143 021223 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEDUMMY_H #define CMOUSEDUMMY_H #include "mouse/IMouse.h" class CMouseDummy : public IMouse { public: CMouseDummy(); virtual ~CMouseDummy(); void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) override { } void mousePressEvent(QMouseEvent * e) override { } void mouseMoveEvent(QMouseEvent * e) override { } void mouseReleaseEvent(QMouseEvent *e) override { } }; #endif //CMOUSEDUMMY_H qmapshack-1.10.0/src/mouse/CMousePrint.h000644 001750 000144 00000002343 13216234143 021223 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEPRINT_H #define CMOUSEPRINT_H #include "mouse/IMouseSelect.h" class CGisDraw; class CCanvas; class CMousePrint : public IMouseSelect { Q_OBJECT public: CMousePrint(CGisDraw * gis, CCanvas * parent); virtual ~CMousePrint(); private slots: void slotSave(); void slotPrint(); }; #endif //CMOUSEPRINT_H qmapshack-1.10.0/src/mouse/CMouseEditArea.h000644 001750 000144 00000003173 13216234143 021607 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEEDITAREA_H #define CMOUSEEDITAREA_H #include "gis/IGisItem.h" #include "mouse/line/IMouseEditLine.h" class CGisItemOvlArea; class CMouseEditArea : public IMouseEditLine { Q_OBJECT public: CMouseEditArea(const QPointF& point, CGisDraw * gis, CCanvas * parent); CMouseEditArea(CGisItemOvlArea &area, CGisDraw * gis, CCanvas * parent); virtual ~CMouseEditArea(); void mousePressEvent(QMouseEvent * e) override; protected slots: void slotAbort() override; void slotCopyToNew() override; void slotCopyToOrig() override; protected: void drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p) override; IGisLine * getGisLine() const override; }; #endif //CMOUSEEDITAREA_H qmapshack-1.10.0/src/mouse/CMouseEditRte.h000644 001750 000144 00000003022 13216234143 021462 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CMOUSEEDITRTE_H #define CMOUSEEDITRTE_H #include "gis/IGisItem.h" #include "mouse/line/IMouseEditLine.h" class CGisItemRte; class CMouseEditRte : public IMouseEditLine { Q_OBJECT public: CMouseEditRte(const QPointF& point, CGisDraw * gis, CCanvas * parent); CMouseEditRte(CGisItemRte &rte, CGisDraw * gis, CCanvas * parent); virtual ~CMouseEditRte(); void mousePressEvent(QMouseEvent * e) override; protected slots: void slotAbort() override; void slotCopyToNew() override; void slotCopyToOrig() override; protected: IGisLine* getGisLine() const override; }; #endif //CMOUSEEDITRTE_H qmapshack-1.10.0/src/mouse/CScrOptUnclutter.cpp000644 001750 000144 00000012276 13216234140 022574 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de 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 "CMainWindow.h" #include "canvas/CCanvas.h" #include "gis/IGisItem.h" #include "gis/trk/CGisItemTrk.h" #include "helpers/CDraw.h" #include "mouse/CScrOptUnclutter.h" #include const QPoint CScrOptUnclutter::positions[9][8] = { { }, { QPoint(-50,-23) }, { QPoint(-30,0) , QPoint( 30,0) }, { QPoint( 0,-30) , QPoint( 30, 30) , QPoint(-30, 30) }, { QPoint(-30,-30) , QPoint( 30,-30) , QPoint(-30, 30) , QPoint( 30, 30) }, { QPoint(-25, 40) , QPoint( 25, 40) , QPoint(-40, -5) , QPoint( 40, -5) , QPoint( 0,-40) }, { QPoint(-40,-22) , QPoint( 40,-22) , QPoint(-40, 22) , QPoint( 40, 22) , QPoint( 0,-55) , QPoint( 0, 55) }, { QPoint(-50,-23) , QPoint( 50,-23) , QPoint(-45, 21) , QPoint( 45, 21) , QPoint(-22,-55) , QPoint( 22,-55) , QPoint( 0, 50) }, { QPoint(-50,-23) , QPoint( 50,-23) , QPoint(-50, 23) , QPoint( 50, 23) , QPoint(-22,-55) , QPoint( 22,-55) , QPoint(-22, 55) , QPoint( 22, 55) } }; CScrOptUnclutter::CScrOptUnclutter(IMouse *mouse) : IScrOpt(mouse) { } CScrOptUnclutter::~CScrOptUnclutter() { } void CScrOptUnclutter::clear() { if(doSpecialCursor) { CCanvas::restoreOverrideCursor("CScrOptUnclutter::clear()"); doSpecialCursor = false; } items.clear(); } void CScrOptUnclutter::mouseMoveEvent(QMouseEvent * e) { IScrOpt::mouseMoveEvent(e); for(const item_t &item : items) { if(item.active.contains(mousePos) || item.text.contains(mousePos)) { if(!doSpecialCursor) { CCanvas::setOverrideCursor(Qt::PointingHandCursor,"CScrOptUnclutter::mouseMoveEvent"); doSpecialCursor = true; } return; } } if(doSpecialCursor) { CCanvas::restoreOverrideCursor("CScrOptUnclutter::mouseMoveEvent"); doSpecialCursor = false; return; } } void CScrOptUnclutter::addItem(IGisItem * gisItem) { items << item_t(); item_t& item = items.last(); item.hasUserFocus = gisItem->hasUserFocus(); item.name = gisItem->getNameEx(); item.key = gisItem->getKey(); item.icon = gisItem->getIcon(); item.area = item.icon.rect(); item.active = item.area.adjusted(-10,-10,10,10); } IGisItem::key_t CScrOptUnclutter::getItemKey(int index) { if(index < items.size()) { return items[index].key; } return IGisItem::key_t(); } const CScrOptUnclutter::item_t * CScrOptUnclutter::selectItem(const QPoint& point) { for(const item_t &item : items) { if(item.active.contains(point) || item.text.contains(point)) { return &item; } } return nullptr; } void CScrOptUnclutter::draw(QPainter& p) { const int N = items.size(); QFontMetrics fm(CMainWindow::self().getMapFont()); for(int cnt = 0; cnt < N; cnt++) { item_t& item = items[cnt]; if(item.text.isNull()) { item.area.moveCenter(origin + positions[N][cnt]); item.active.moveCenter(item.area.center()); item.text = fm.boundingRect(item.name); if(cnt & 0x01) { item.text.moveTopLeft(item.area.topRight() + QPoint( 17, fm.height()/2)); } else { item.text.moveTopRight(item.area.topLeft() + QPoint(-17, fm.height()/2)); } item.text.adjust(-4, -3, 4, 3); } } for(const item_t &item : items) { p.setPen(Qt::NoPen); p.setBrush(QColor(255,255,255,255)); p.drawEllipse(item.area.center(), 20,20); p.drawRoundedRect(item.text, RECT_RADIUS, RECT_RADIUS); p.setPen(QPen(item.hasUserFocus ? Qt::red : Qt::lightGray,2)); p.setBrush(Qt::NoBrush); p.drawRoundedRect(item.text, RECT_RADIUS, RECT_RADIUS); p.drawEllipse(item.area.center(), 18,18); p.drawPixmap(item.area, item.icon); CDraw::text(item.name, p, item.text, Qt::darkBlue); } } qmapshack-1.10.0/src/mouse/IScrOptPrint.ui000644 001750 000144 00000003656 12705713524 021560 0ustar00oeichlerxusers000000 000000 IScrOptPrint 0 0 24 49 Form 3 3 0 0 0 Save selected area as image. ... :/icons/32x32/Save.png:/icons/32x32/Save.png 16 16 Print selected area. ... :/icons/32x32/Print.png:/icons/32x32/Print.png 16 16 qmapshack-1.10.0/src/mouse/CMouseNormal.cpp000644 001750 000144 00000032232 13216234261 021713 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2017 Norbert Truchsess norbert.truchsess@t-online.de 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 "canvas/CCanvas.h" #include "gis/CGisDraw.h" #include "gis/CGisWorkspace.h" #include "gis/prj/IGisProject.h" #include "gis/rte/CGisItemRte.h" #include "gis/trk/CGisItemTrk.h" #include "gis/wpt/CGisItemWpt.h" #include "mouse/CMouseNormal.h" #include "mouse/CScrOptUnclutter.h" #include "widgets/CFadingIcon.h" #include CMouseNormal::CMouseNormal(CGisDraw *gis, CCanvas *canvas) : IMouse(gis, canvas) { cursor = QCursor(QPixmap(":/cursors/cursorMoveMap.png"),0,0); screenUnclutter = new CScrOptUnclutter(this); menu = new QMenu(canvas); actionPoiAsWpt = menu->addAction(QIcon("://icons/32x32/AddWpt.png"), tr("Add POI as Waypoint"), this, SLOT(slotAddPoi())); menu->addAction(QIcon("://icons/32x32/AddWpt.png"), tr("Add Waypoint"), this, SLOT(slotAddWpt())); menu->addAction(QIcon("://icons/32x32/AddTrk.png"), tr("Add Track"), this, SLOT(slotAddTrk())); menu->addAction(QIcon("://icons/32x32/AddRte.png"), tr("Add Route"), this, SLOT(slotAddRte())); menu->addAction(QIcon("://icons/32x32/AddArea.png"), tr("Add Area"), this, SLOT(slotAddArea())); menu->addSeparator(); menu->addAction(QIcon("://icons/32x32/SelectArea.png"), tr("Select Items On Map"), this, SLOT(slotSelectArea())); menu->addSeparator(); menu->addAction(QIcon("://icons/32x32/Copy.png"), tr("Copy position"), this, SLOT(slotCopyPosition())); menu->addAction(QIcon("://icons/32x32/Copy.png"), tr("Copy position (Grid)"), this, SLOT(slotCopyPositionGrid())); } CMouseNormal::~CMouseNormal() { } void CMouseNormal::stopTracking() const { const IGisItem::key_t& key = CGisItemTrk::getKeyUserFocus(); if(!key.item.isEmpty()) { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(key)); if(trk != nullptr) { trk->setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CMouseNormal"); } } } void CMouseNormal::mousePressEvent(QMouseEvent * e) { point = e->pos(); if(e->button() == Qt::LeftButton) { lastPos = e->pos(); firstPos = lastPos; // start to block map moving when a previous click // has triggered a selection of any kind mapMove = (stateItemSel < eStateNoMapMovePossible); mapDidMove = false; } else if(e->button() == Qt::RightButton) { QPoint p = canvas->mapToGlobal(point); actionPoiAsWpt->setEnabled(curPOI.pos != NOPOINTF); menu->exec(p); } } void CMouseNormal::mouseMoveEvent(QMouseEvent * e) { screenUnclutter->mouseMoveEvent(e); if(!screenItemOption.isNull()) { screenItemOption->mouseMoveEvent(e); } point = e->pos(); if(mapMove) { if((point - firstPos).manhattanLength() >= 4) { QPoint delta = point - lastPos; canvas->moveMap(delta); lastPos = point; mapDidMove = true; } } else { switch(stateItemSel) { case eStateIdle: CGisWorkspace::self().mouseMove(point); //break; skip break intentionally case eStateHooverSingle: case eStateHooverMultiple: { const IGisItem::key_t& keyTrk = CGisItemTrk::getKeyUserFocus(); if(!keyTrk.item.isEmpty()) { CGisItemTrk * trk = dynamic_cast(CGisWorkspace::self().getItemByKey(keyTrk)); if(trk != nullptr) { trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseMove, "CMouseNormal"); } } const IGisItem::key_t& keyRte = CGisItemRte::getKeyUserFocus(); if(!keyRte.item.isEmpty()) { CGisItemRte * rte = dynamic_cast(CGisWorkspace::self().getItemByKey(keyRte)); if(rte != nullptr) { rte->setMouseFocusByPoint(point, CGisItemRte::eFocusMouseMove, "CMouseNormal"); } } break; } default: ; } curPOI = canvas->findPOICloseBy(point); canvas->displayInfo(point); canvas->update(); } } void CMouseNormal::mouseReleaseEvent(QMouseEvent *e) { point = e->pos(); if(e->button() == Qt::LeftButton) { if(!mapDidMove) { switch(stateItemSel) { case eStateIdle: { CGisWorkspace::self().slotWksItemSelectionReset(); break; } case eStateHooverSingle: { stateItemSel = eStateIdle; IGisItem * item = CGisWorkspace::self().getItemByKey(screenUnclutter->getItemKey()); if(nullptr != item) { scrollToItem(item); if(setScreenOption(point, item)) { stateItemSel = eStateShowItemOptions; } stopTracking(); } break; } case eStateHooverMultiple: { screenUnclutter->setOrigin(e->pos()); stateItemSel = eStateUnclutterMultiple; stopTracking(); break; } case eStateUnclutterMultiple: { const CScrOptUnclutter::item_t * scrOpt = screenUnclutter->selectItem(point); if(scrOpt != nullptr) { IGisItem * item = CGisWorkspace::self().getItemByKey(scrOpt->key); screenUnclutter->clear(); // CAUTION!! this will delete the object scrOpt is pointing to. scrOpt = nullptr; if(item) { scrollToItem(item); if(setScreenOption(screenUnclutter->getOrigin(), item)) { stateItemSel = eStateShowItemOptions; break; } } } resetState(); CGisWorkspace::self().slotWksItemSelectionReset(); break; } case eStateShowItemOptions: { resetState(); CGisWorkspace::self().slotWksItemSelectionReset(); break; } } canvas->update(); } mapMove = false; mapDidMove = false; } } void CMouseNormal::mouseDoubleClickEvent(QMouseEvent *e) { if(stateItemSel == eStateIdle) { const IGisItem::key_t& keyTrk = CGisItemTrk::getKeyUserFocus(); CGisWorkspace::self().focusTrkByKey(false, keyTrk); const IGisItem::key_t& keyRte = CGisItemRte::getKeyUserFocus(); CGisWorkspace::self().focusRteByKey(false, keyRte); } } void CMouseNormal::wheelEvent(QWheelEvent * e) { resetState(); } void CMouseNormal::keyPressEvent(QKeyEvent * e) { resetState(); } void CMouseNormal::afterMouseLostEvent(QMouseEvent *e) { resetState(); if (e->type() == QEvent::MouseMove) { lastPos = e->pos(); firstPos = lastPos; } mapMove = e->buttons() & Qt::LeftButton; mapDidMove = true; } void CMouseNormal::resetState() { screenUnclutter->clear(); if(!screenItemOption.isNull()) { screenItemOption->deleteLater(); } stateItemSel = eStateIdle; } void CMouseNormal::scrollToItem(IGisItem * item) { QTreeWidget * treeWidget = item->treeWidget(); // block signals as this is an internal // change and no user interaction with // the tree widget treeWidget->blockSignals(true); treeWidget->collapseAll(); treeWidget->setCurrentItem(item); treeWidget->scrollToItem(item, QAbstractItemView::PositionAtCenter); treeWidget->blockSignals(false); } bool CMouseNormal::setScreenOption(const QPoint& pt, IGisItem * item) { CGisItemTrk * trk = dynamic_cast(item); if(trk && trk->setMouseFocusByPoint(pt, CGisItemTrk::eFocusMouseClick, "CMouseNormal") == NOPOINTF) { new CFadingIcon(pt, "://icons/48x48/NoGo.png", canvas); return false; } delete screenItemOption; screenItemOption = item->getScreenOptions(pt, this); return !screenItemOption.isNull(); } void CMouseNormal::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) { // no mouse interaction while gis thread is running if(gis->isRunning()) { return; } switch(stateItemSel) { case eStateIdle: case eStateHooverSingle: case eStateHooverMultiple: { if(curPOI.pos != NOPOINTF) { const QSize s = curPOI.symbolSize; const qint32 x = (qMax(qMax(s.width(), s.height()), 7)<<1) & 0xFFFFFFFE; p.drawImage(curPOI.pos - QPointF(x,x), QImage("://cursors/wptHighlightBlue.png").scaled(x<<1, x<<1, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } /* Collect and draw items close to the last mouse position in the draw method. This might be a bit odd but there are two reasons: 1) Multiple update events are combined by the event loop. Thus multiple mouse move events are reduced to a single paint event. As getItemsByPos() is quite cycle intense this seems like a good idea. 2) The list of items passed back by getItemsByPos() must not be stored. That is why the list has to be generated within the draw handler to access the item's drawHighlight() method. */ screenUnclutter->clear(); QList items; CGisWorkspace::self().getItemsByPos(point, items); if(items.empty() || items.size() > 8) { stateItemSel = eStateIdle; break; } for(IGisItem * item : items) { item->drawHighlight(p); screenUnclutter->addItem(item); } stateItemSel = (screenUnclutter->size() == 1) ? eStateHooverSingle : eStateHooverMultiple; break; } case eStateUnclutterMultiple: { screenUnclutter->draw(p); break; } case eStateShowItemOptions: { if(screenItemOption.isNull()) { stateItemSel = eStateIdle; break; } // the screen option might not be destroyed yet, but already hidden if(screenItemOption->isVisible()) { screenItemOption->draw(p); } break; } default: ; } } void CMouseNormal::slotAddPoi() const { QPointF pt = curPOI.pos; gis->convertPx2Rad(pt); pt *= RAD_TO_DEG; CGisWorkspace::self().addWptByPos(pt, curPOI.name, curPOI.desc); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseNormal::slotAddWpt() const { QPointF pt = point; gis->convertPx2Rad(pt); pt *= RAD_TO_DEG; CGisWorkspace::self().addWptByPos(pt); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseNormal::slotAddTrk() const { QPointF pt = point; gis->convertPx2Rad(pt); canvas->setMouseEditTrk(pt); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseNormal::slotAddRte() const { QPointF pt = point; gis->convertPx2Rad(pt); canvas->setMouseEditRte(pt); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseNormal::slotAddArea() const { QPointF pt = point; gis->convertPx2Rad(pt); canvas->setMouseEditArea(pt); canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis); } void CMouseNormal::slotCopyPosition() const { QPointF pt = point; gis->convertPx2Rad(pt); QString position; IUnit::degToStr(pt.x() * RAD_TO_DEG, pt.y() * RAD_TO_DEG, position); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(position); } void CMouseNormal::slotCopyPositionGrid() const { QString position; QPointF pt = point; gis->convertPx2Rad(pt); canvas->convertGridPos2Str(pt * RAD_TO_DEG, position, true); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(position); } void CMouseNormal::slotSelectArea() const { canvas->setMouseSelect(); } qmapshack-1.10.0/call_Uncrustify.sh000754 001750 000144 00000001706 12611120137 020424 0ustar00oeichlerxusers000000 000000 #!/bin/sh if [ ! -n "$1" ]; then echo "Syntax is: recurse.sh dirname filesuffix" echo "Syntax is: recurse.sh filename" echo "Example: recurse.sh temp cpp" exit 1 fi if [ -d "$1" ]; then #echo "Dir ${1} exists" if [ -n "$2" ]; then filesuffix=$2 else filesuffix="*" fi #echo "Filtering files using suffix ${filesuffix}" file_list=`find ${1} -name "*.${filesuffix}" -type f` for file2indent in $file_list do echo "Indenting file $file2indent" #!/bin/bash uncrustify -f "$file2indent" -c "./call_Uncrustify.cfg" -o indentoutput.tmp mv indentoutput.tmp "$file2indent" done else if [ -f "$1" ]; then echo "Indenting one file $1" #!/bin/bash uncrustify -f "$1" -c "./call_Uncrustify.cfg" -o indentoutput.tmp mv indentoutput.tmp "$1" else echo "ERROR: As parameter given directory or file does not exist!" echo "Syntax is: call_Uncrustify.sh dirname filesuffix" echo "Syntax is: call_Uncrustify.sh filename" echo "Example: call_Uncrustify.sh temp cpp" exit 1 fi fi qmapshack-1.10.0/qmapshack.desktop.in000644 001750 000144 00000000517 12705713524 020703 0ustar00oeichlerxusers000000 000000 [Desktop Entry] Version=1.0 Name=QMapShack Exec=qmapshack %F Icon=QMapShack Terminal=false Type=Application X-MultipleArgs=false Categories=Qt;Geoscience;Geography;Science; GenericName=GPS device mapping utility Keywords=map;GPS;geocaching;waypoints;tracks; MimeType=application/x-gpx; StartupNotify=true #TRANSLATIONS_DIR=src/locale qmapshack-1.10.0/msvc_64/000755 001750 000144 00000000000 13216664445 016216 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/msvc_64/qt.conf000644 001750 000144 00000000061 13025704317 017475 0ustar00oeichlerxusers000000 000000 [Paths] Plugins=. Translations=translations qmapshack-1.10.0/msvc_64/QMapShack_Installer.nsi000644 001750 000144 00000025534 13064423104 022551 0ustar00oeichlerxusers000000 000000 ;NSIS Installer Script for https://bitbucket.org/maproom/qmapshack/wiki/Home ;NSIS References/Documentation ;http://nsis.sourceforge.net/Docs/Modern%20UI%202/Readme.html ;http://nsis.sourceforge.net/Docs/Modern%20UI/Readme.html ;http://nsis.sourceforge.net/Docs/Chapter4.html ;http://nsis.sourceforge.net/Many_Icons_Many_shortcuts ;Deployment issues ;Deploying Qt5 for Windows: ; http://qt-project.org/doc/qt-5/windows-deployment.html ;Deploying MSVC runtime libraries ; http://msdn.microsoft.com/en-us/library/dd293574.aspx ==> Central Deployment is preferred: by using a redistributable package enables automatic updating by Microsoft. ; http://msdn.microsoft.com/en-us/library/8kche8ah.aspx ==> Distribute msvcr120.dll and msvcp120.dll ; http://www.microsoft.com/en-us/download/details.aspx?id=40784 ==> Download the vcredist_x64.exe from here !!! ; http://msdn.microsoft.com/en-us/vstudio/dn501987.aspx ==> Legal stuff ;Revision Log ; 03-Aug-2014 First version of QMapShack installer based on the existing QLandkarteGT installer ;=================== BEGIN SCRIPT ==================== ; Include for nice Setup UI, see http://nsis.sourceforge.net/Docs/Modern%20UI%202/Readme.html !include MUI2.nsh ;------------------------------------------------------------------------ ; Modern UI2 definition - ;------------------------------------------------------------------------ ; Description Name "QMapShack" ;Default installation folder InstallDir "$PROGRAMFILES64\QMapShack" ;Get installation folder from registry if available InstallDirRegKey HKCU "Software\QMapShack" "" ;Request application privileges for Windows Vista RequestExecutionLevel admin ; The file to write OutFile "QMapShack_Install.exe" ;------------------------------------------------------------------------ ; Modern UI definition - ;------------------------------------------------------------------------ ;!define MUI_COMPONENTSPAGE_SMALLDESC ;No value !define MUI_INSTFILESPAGE_COLORS "FFFFFF 000000" ;Two colors !define MUI_ICON "QMapShack.ico" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "MUI_HEADERIMAGE.bmp" !define MUI_WELCOMEFINISHPAGE_BITMAP "MUI_WELCOMEFINISHPAGE.bmp" ; Page welcome description !define MUI_WELCOMEPAGE_TITLE "QMapShack" !define MUI_WELCOMEPAGE_TITLE_3LINES !define MUI_WELCOMEPAGE_TEXT "QMapShack is a consumer grade software to work with data acquired by GPS devices. The data can be displayed on a variety of maps and stored in a database. Additionally new data can be created to plan tours." !define MUI_LICENSEPAGE_CHECKBOX ;------------------------------------------------------------------------ ; Pages definition order - ;------------------------------------------------------------------------ !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "..\LICENSE" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY Var StartMenuFolder !insertmacro MUI_PAGE_STARTMENU "Application" $StartMenuFolder !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH ;------------------------------------------------------------------------ ;------------------------------------------------------------------------ ;Uninstaller - ;------------------------------------------------------------------------ !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ; Language settings !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "German" ;------------------------------------------------------------------------ ; Component add - ;------------------------------------------------------------------------ ;Components description Section "MSVC++ 2013 SP1 Runtime" MSVC SetOutPath $INSTDIR File Files\vcredist_x64.exe ExecWait '"$INSTDIR\vcredist_x64.exe"' Delete "$INSTDIR\vcredist_x64.exe" SectionEnd LangString DESC_MSVC ${LANG_ENGLISH} "Microsoft Visual C++ 2013 SP1 Runtime Libraries. Typically already installed on your PC. You only need to install them if it doesn't work without ;-)." LangString DESC_MSVC ${LANG_GERMAN} "Microsoft Visual C++ 2013 SP1 Laufzeitbibliotheken. Diese sind meist bereits auf dem Rechner installiert. Versuchen Sie die Installation zunchst einmal ohne dies." Section "QMapShack" QMapShack ;Install for all users SetShellVarContext all ;BEGIN QMapShack Files SetOutPath $INSTDIR File Files\qmapshack.exe File Files\*.ico ;File Files\*.png SetOutPath "$INSTDIR\translations" File Files\translations\qmapshack_*.qm ;END QMapShack Files ;BEGIN Qt Files SetOutPath $INSTDIR File Files\Qt5Core.dll File Files\Qt5Gui.dll File Files\Qt5Multimedia.dll File Files\Qt5MultimediaWidgets.dll File Files\Qt5Network.dll File Files\Qt5OpenGL.dll File Files\Qt5Positioning.dll File Files\Qt5PrintSupport.dll File Files\Qt5Qml.dll File Files\Qt5Quick.dll File Files\Qt5Script.dll File Files\Qt5Sensors.dll File Files\Qt5Sql.dll File Files\Qt5Svg.dll File Files\Qt5WebChannel.dll File Files\Qt5WebKit.dll File Files\Qt5Widgets.dll File Files\Qt5WebKitWidgets.dll File Files\Qt5Xml.dll File Files\icudt54.dll File Files\icuin54.dll File Files\icuuc54.dll File Files\libEGL.dll File Files\libGLESv2.dll SetOutPath "$INSTDIR\imageformats\" File Files\imageformats\qgif.dll File Files\imageformats\qjpeg.dll File Files\imageformats\qmng.dll File Files\imageformats\qsvg.dll File Files\imageformats\qtiff.dll File Files\imageformats\qico.dll File Files\imageformats\qtga.dll SetOutPath "$INSTDIR\sqldrivers\" File Files\sqldrivers\qsqlite.dll File Files\sqldrivers\qsqlmysql.dll File Files\sqldrivers\qsqlodbc.dll File Files\sqldrivers\qsqlpsql.dll SetOutPath "$INSTDIR\platforms\" File Files\platforms\qwindows.dll SetOutPath "$INSTDIR\printsupport\" File Files\printsupport\windowsprintersupport.dll SetOutPath "$INSTDIR\translations" File Files\translations\qt*.qm ;END Qt Files ;BEGIN GDAL and PROJ.4 Files SetOutPath $INSTDIR File Files\gdal*.dll File Files\gdal*.exe File Files\nearblack.exe File Files\ogr*.exe File Files\testepsg.exe SetOutPath "$INSTDIR\data\" File /r Files\data\*.* ;END GDAL and PROJ.4 Files ;BEGIN PROJ.4 Files SetOutPath $INSTDIR File Files\proj*.dll File Files\proj*.exe SetOutPath "$INSTDIR\share\" File /r Files\share\*.* ;END PROJ.4 Files ;BEGIN QuaZip Files SetOutPath $INSTDIR File Files\quazip5.dll ;END QuaZip Files ;BEGIN Routino Files SetOutPath $INSTDIR File Files\routino.dll File Files\planetsplitter.exe File Files\libwinpthread-1.dll File Files\libz-1.dll SetOutPath "$INSTDIR\routino-xml\" File /r Files\routino-xml\*.* ;END Routino Files ;BEGIN additional Files SetOutPath $INSTDIR File Files\libmysql.dll File Files\3rdparty.txt File Files\qt.conf ;File Files\libexif-12.dll ;END additional Files ;the last "SetOutPath" will be the default directory SetOutPath $INSTDIR WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd LangString DESC_QMapShack ${LANG_ENGLISH} "View Raster, Garmin and Online Maps combined with elevation data. Work with GIS data. Synchronize your GPS device." LangString DESC_QMapShack ${LANG_GERMAN} "Raster-, Garmin- und Online Karten mit Hheninformation anzeigen. GIS Daten bearbeiten. GPS Gerte synchronisieren" Section "StartMenue" StartMenue ;create batch file for a GDAL shell fileOpen $0 "$INSTDIR\gdal_shell.bat" w fileWrite $0 "@cd /D %USERPROFILE%$\r$\n" fileWrite $0 "@SET PATH=$INSTDIR;%PATH%$\r$\n" fileWrite $0 "@SET GDAL_DATA=$INSTDIR\data$\r$\n" fileWrite $0 "@SET PROJ_LIB=$INSTDIR\share$\r$\n" fileClose $0 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts CreateDirectory "$SMPROGRAMS\$StartMenuFolder" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\QMapShack.lnk" "$INSTDIR\qmapshack.exe" "" "$INSTDIR\QMapShack.ico" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\qmapshack.org.lnk" "https://bitbucket.org/maproom/qmapshack/wiki/Home" "" "$INSTDIR\kfm_home.ico" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Help.lnk" "https://bitbucket.org/maproom/qmapshack/wiki/DocMain" "" "$INSTDIR\Help.ico" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\gdal.org.lnk" "http://www.gdal.org/" "" "$INSTDIR\gdalicon.ico" CreateShortCut "$SMPROGRAMS\$StartMenuFolder\GDAL shell.lnk" %COMSPEC% "/k $\"$INSTDIR\gdal_shell.bat$\"" "" "" "" "" "GDAL shell" !insertmacro MUI_STARTMENU_WRITE_END ;Create registry entries WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\QMapShack" "DisplayName" "QMapShack (remove only)" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\QMapShack" "UninstallString" "$INSTDIR\Uninstall.exe" SectionEnd LangString DESC_StartMenue ${LANG_ENGLISH} "Create Start Menu (deselect if you want install QMapShack as portable app)" LangString DESC_StartMenue ${LANG_GERMAN} "Erzeuge Start Men (weglassen, wenn QMapShack als portable app installiert werden soll)" !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${QMapShack} $(DESC_QMapShack) !insertmacro MUI_DESCRIPTION_TEXT ${StartMenue} $(DESC_StartMenue) !insertmacro MUI_DESCRIPTION_TEXT ${MSVC} $(DESC_MSVC) !insertmacro MUI_FUNCTION_DESCRIPTION_END ;------------------------------------------------------------------------ ;Uninstaller Sections - ;------------------------------------------------------------------------ Section "Uninstall" ;Install for all users SetShellVarContext all Delete "$INSTDIR\Uninstall.exe" SetOutPath $TEMP RMDir /r $INSTDIR !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\QMapShack.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\qmapshack.org.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\Help.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\gdal.org.lnk" Delete "$SMPROGRAMS\$StartMenuFolder\GDAL shell.lnk" RMDir "$SMPROGRAMS\$StartMenuFolder" DeleteRegKey /ifempty HKCU "Software\QMapShack" DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\QMapShack" SectionEnd Function .onInit # set section 'MSVC' as unselected #SectionSetFlags ${MSVC} 0 FunctionEnd qmapshack-1.10.0/msvc_64/kfm_home.ico000644 001750 000144 00000035356 12705713524 020506 0ustar00oeichlerxusers000000 000000   6 h00 %F( @ ,8+ " X3XA"hC':${V!:nn4Gh; `># Q;hIfa7? 5(:1@10@(9.3A2!3/@-*:(:($':jbg''EJDHM2`.-/;"9%0+:1*3%9/)3 6&1*92&/#2'[,hd]x%$+gBC4./$01D 1*4-B!.0=%9)0@!2%.(=**5#1 yNeef]@44-B-5'29A!0,50;,0=&3#.2:!/(2.:*19 fffa_u'' %(XNN+:!,6B#0*44?02?(5(5@.".-:!.9```_[i((:>3E)7$50?#1(8)<3(8%2#3)8-$5.<'X*\\\\]W vKJL[.=.=.A,:-=.?)<-?+:%3'9'4%5#5%0 w R`````_^P~~yzzzy u u t u to6d(  34  .h!34 :%&?kP[%Iz1.- @Ma}4e{Wc#,\%J s pm|OՉXiFlyvqOІ)OpJ} qp{Fˊ@S̲˩*l ;}ppI [PʥVf ;g`vw\UVXdc P)Vpnzd&D,[!Y^inN =uE_bg:S!$)#'#')/-6-:05 G s .eSVF&/&9%7%8#6#4"3$2CW }#=D.A'4'7&6%4%4$4&6&!Z]F E3j,1*6*6(6(3'3'4'1 U WTb7D/?,;,>)<)8'8):EWVU)-&$""-(0` % %! :Wq|saN:' +IAgcG/x_I4"  7[4].VwW{$@cB*qZE1 (FwCs{+SKd+wU<& lU@, 6U/W=~uT btAj=MlN6gP<+ .r:h&a^- Yi>\j-4 }hG1X T8c'ZdDM9+ Xi>Ys$0yeP 8g'L *QB/ Sc6}Pz{@eJr!-RE2M^-w }A eEl ,UG3r`S1La(clj ~"C eDk )VJ7to5I^$A{|ʼn+ais` ~"C eCk%-WO;#CVJy*X؈2theVVgV ~"C dBk%-YR>- BVOsGoֹ޹HRM ~"C cAj$+\UA0 AWPteFilWDC }"E c?j'-_\G3;QRqwE}GcB~S:9%F b?i'.O7 c;NSl!)~vAd'$Kv01%F a>h|~0)p DvB_uNa7[m?aP3 Bo+1%F a=hvz^MbvnjfvyotxrXwvd>\cR%@k*1%F aB>DFL?F=I4K5<4544./dbg { '<`XZ\]`bcefmY"DF)4@ ?I'2= 7B$0; 5?#0:0:&2:$AG%2=E&0SV%%P3d9q99 TSUWX[\^`cd'@954AJS$2>5@HP(-:7BJQ(*74?FM%$36ADK'.1<@H$)00YQce.. SOPRSVWY[b4f+('7-!3+"5&$5'&8)#4%%6&'7&/=&(7$(8 ,6 79i'vi_((!!BRKMNQRTYF $>E)4C'=K'5D &;I).= 9G '-= !;H),< !7E+2> 5<?'bh66 'MIGILMPP1D@AJKU %1?AIJR '*;BIGP)+AF3"$ 3@'.<2<$*1k*}e_00 4?<=:MI AJMWLW9BISKU 5?GRHR4=GPHR#-7AKDO#&1DK:A }B(a0h22 )9;U>;*9(6#-)1)6!0%/#+#0,%4 ."0*(1$*6(*3()5$.6 ) K6 ]d55I*+1RW(3>;F&4>AJ'3A$?I$-8 ?G&,8 ;D#,7"%YV\%%ybdFRT[>HBMQX5?AJKU 2@=GKR 3=)aA-bA0xS;bOzkiZqgrɾxͿ˵azU|W{XuTsPtRvPuOvT}]yXwPuPc@kDrNvRnImIf@yan|dzfmUkLyV^~ɻheDqQmLpRway_¾;Ŀı̿hMa>w]eEfH{hvjN}gr\{sźxtcHiRkUjUV7]?_B^Ab@kWmE(_>]>V9{S7oG-Z>[=Y8V4wK-vO3rP6_B.\@/_D4^@1]>+gH4cD4fK;_>(gJ9}`Trbq^~{jxƺóȾ}XxOvR~\ySxSzVyUySxTwRxRxSwRwQpKvQvQxVjEoHvRvRtOrNkFhkLrM~\~j}ZsNeɹzV{VxU[{nQiHoMiJ~gɶpbqr{W~ZjurkQjKeHoT{g{s[yfeIkRrϾjPpYn[_I^EiSU-vQ5wP8\<^?\<_@\:Z:]=U6}T9pK1\=+X=([@-]B3cD3y^QrkbPvf|lvdȾxtM{T{V{VzU{U{TyUyTxTyRySyRyTySvRtPxQuQsQtPwRySvPxQtQvRrOnGmIuQnHȻƸuyR~WzU}Y{U|W|W{V|WvShJqPmKiFxYlȹijǹȹƶƷwzR}X{VzT}W{WxSvQ~^gw\}`pVc@cDź˻y\lLpQnlxboRpToXbKQ+jG-aC_=[ZiG7z}q}i~fl}Y|UyTxQ|X{XzW{X¿ǺȻ®ò͸vN|W{VzVzUzTyTyTzQxRyQwQwQxRyQySxTySzRzRvQpLvQyTyTzRyTySxUxUyTyT{U{V{U{X{T`c{T{V|V|V{V{X|V|TzW{X{VzUyY{X{XxV|W|X|Y~Y}X^|X{Y|X{W|V{UzW{XzVyV|WzV{WvTfƥȷɹ˻ÿftzd}^nƯ}xmfgmvo\oF(tL1{V;[<T5cHcFW>oL4d@&uO4gLgK}V:_8$ʷxc{`zVyUxQzQzSzUzSyUzU{XzVsfý}V{S|U{VzW{TyTyTyRxOwPwOwQxRxRyQxTxRxQxSwSuOjDsNxRwRxRySySxSxSxRyTyTzT{S{T|U{V|W}X|W|U{U|U|V{V{UzUzVyTzTzVzTyVzW{W{X{V|V{WztzV}X|Y|Y|W|V{VzV{WyWxV{X|X}X|Z|YwTʹȲɶɺŴycc~``gfrjhlooàf|Q2|V;iKZ<{R5_BaF\?oL4sP8^B[C`HeLwer~YvR|XzRzUyUzVySyRxRySzU{SzUzV{UxPôȽ~Z~XdehxRsJzS{UzU{W{WyUyUyRwQvQuQvPwPxRxSxRwQwSxSxRwSwRvRwQvRvQwRxRwQyRwUwTxRyUzVzTzS{U{VzT{U{V|V|T{VzUzXzVyTyVyUzT|W{W{V{T{W{W{X{XzWkvyT|X|X|W|V{W{VzVzVzUyX{X}Z}Z}[^~^tįȺrecees|prymnmjkihvN0~Y>aFtO5zS:~Y=`BcFYA[@lG-sQ8\BuT`uOyQ{TzU{UyTyTzRxRwRwTyUzU{VzWzT{W{ViȾö{TzSxQvRvOvPyRzTzUzV{TzTyTzTxSuRtPvQwQxSxSwRwSuSxSxUySyRwSwTwSxSxUyRyTySySyUyTwRxRzTzUzUyUyVzUzVzX{W{V{UyUyVzUySzU{WzXyWyVzV{V|V|X{XyXyX\t`{W|W{X|Y{Y{W{WzWyUxUxU}W}X}Y~\^~^jvedokhn{y›mlkjklg{U6`BhPcH]@iL^AdGW9tO5rO7eIvQxRvQzW{U{TzU{VzRxSxQwRxRxTzSzSzWzV{U{X|ZzW¸vN{SrOpPwSuQuNxPzVzVyTxSyRyPuOhChEkGnJrMsNvRyWxUwPuQsOmHrMwUtQlHnLrMtQvQzVzWyVxUwRzSzTxTzSzSzV{T{W{W{V{XyWzV{VyUzW|X{WzWwTyTvUuW{Z|YzWzW{WzW|W{W|W|Y{Y{Z|W{UzVyUyUxRzS|V}[_]_cıu~kptmŽɶɱƿƭojmlhefˍ^@vcwlTfQaCeEcCgQfLrV|WxRyV{UzUzUzTzSyTySwQwRxRyQyUzVzVzV{UzVzWzVzTcctOjHgCgCeBjJtPwQ{TzSzRySxPqKeCb@eCa?`=c>dCgFoKrMkJkIdBdAjFqQjGdBc@c?dCb@hDmLqOyVwSzU{VzV{V|T{UyVzVzWzVxWzX{X|YzVzW|YyVqQtTnJiJlMwW|[yWzWy[}\|Z|Z}[|Z|Y|X|W|X}XzWzXzUzW|X}Z_^`axrppqygj}ȯjTtI-~|rXo\vdiKhEa[wRwPxSyV{W{UvTwSzQyRwQwRxRxQxRyTyVzV{T{TzUzW{T{VzQuPyRmGcAdBeBfBfCiGwSzUzRzQsMfCc@cBlJgDdCeCiHpNlJlKjJiGvRsPwSyTqMiEhEe@bAb@b>c?c?eBiHsOsRlGjJpPwTzWyUyVyVxUwUzW{XzXxTxTzWrRcGhHeDdHeHkLpRuRuSoPvU}[|[}]{Y|\{Z{WzW|\|[|Y|Z}[|[}Z~^^afkp}ȱĭɸ»ƿҿμģǪkT_<"^JhNcDsKySvNvOxRyUxUzUzUzTySwRvNwPwQxSxUvSxQyTyTyTzUzTyUzU{SzSpLuRySqLqPpNjIiHfDoMzRySyUqLgD`?`>lIkIjIhHhFjGnLnLmLpNwSxUzVxUwSmIdCc@b?b@b>dAgFfEkIgDeCdC^<]hKuQvRsMsOvSxTyTyWzWzVzVyUySxVuPtMyTzV{XxUwTsQwQwVxSyRxUyUyUyTwPzTxUzWtSrPtRoMmKuRvOuQ{VyU{UyUvT}Y|XwSwU}YzVwUzX|UzVyW|XzVvTwStOqMtPtQqOoMrPtRsRtSvUuVuSpNjI_=aAa?bCpTpPtXmLeFbBdEeHdBb>cAgFdBhGiKfHaAgGfHbDcCeEdDeEnMsPvVvWpPsVqUoQuV|\sTsStXvYyYtYt[sZqU¥кɨȣʡɡʦɤɤɥͫʤбӼӻӻ˞{dwVwUyUvQvRzW{X{X{XzWzVvRrNnKpNeCcBkJqQsRqPmLhFgHvVuSvQxTzTyUlKhGjHgGfDeFeFkIuSoLjHeCeDsRrPqLsOpMtRqNgHjIpLoMkIhFpNkKiHiIiKlMkJhIeFfEgFlKpNsSyWuSyXtStSpNoKyY}cjIc=lO|uQrOgDeDlIfDdCfDfEfGaBcDdFgIcDbAdAhGiJ{`wYoOsSsVlLiLjInNuYvYtUrRsUrSnPtYpVmUw`ĿùŻ÷¶̬ɡȠɤȣȟǟɤʤж˧ήӷջ˿˯gwQxWwRzV}\rQtRsQnNyVwUkJfEdCcCdEeFeDfEkJxXuRkIjHkMjHkKyTxQjHdFhHfCcCdDfHhJpNlJb@dEdBeBhIkIiFeBdBbAa@dCdCeCeDaAa@hFeBc>c>cEhMmOlPhJkMiMfHfFqOyWyV|Z{YwTqPsSxV~c~z_rvSrOj~dgEoMvTtQmMjJjJkIgJmLrQw[}fu]}anQkLfGjIqRoRlMkNoTmRrTmQkKlMsUtXnTjQn¹ҽ¶ҹѮά˫̫̬ϲέɥɥɥͫΰʨ̬˨ˣʢɠtˠoJzUsOmLoOqSfGjHtTkKlHmJhGjIfFeDgEhGhEc@cClKiEiIiHjKlOnLvNrOiInJlIkHkIqNpOoKnMe@c@gJeFdDdCpNlJrOjIgHfGeCfCeEgEc@dCgEdBc>gEiKiNoRmTkOjOnQlMkNmSlMnLmJmLuUxUrOxY~`|_ay[{`zZ|X^xYkHqUnOkImNzZvVwVyXwSxPqOmMnPw\hm~buXoRlPkOlNvYuXyXuWrTtVsViGiJlOjLmQlTùöѸ˨ʥ˭ΰͭʥ̥̥ɤŞȣΨʤɥxˢtQrPaAaBeFlKiHcDpQxYjFeBhGfDeDdBd?gEeDdAcBfDoNoNkLhKqRlIqMtRvSuRvSvUvTlMlMpMlFc?fEnPhIdCeGpNsMpNhFgHgHdCfBfDhEdBdBeBdCeBiKgIiMmSmRkMmNmPlOlOmTkLeCdBdBeDiJiHiKkPkQwZ}`rvloT|bdvYz^{^zXrOqPuUlLxY{\yWuUpQfIotmlvVkKnRjLfHgIoPsTsTnPqSlOgFpPsWpThMżѷӳ־Ǽ׾ҳ˨γӻѷ̬̥̥ɣĝʣͦʢʢˤq˛mJiIcBdCgDlHhGeFeDuSgC_e?hEiLiIgDjIkHxQqOiEfEeDeAdCdDeCdAcAfDfDeEgGeFjOnQpVmQnPnRlRlQiNgFeAeAdCdAbCb@gHmTlkhipÝ|txYeh~`~[xpqQiq~awYvXnOlֽ̮ţͲqr~f|akpSiHmMqRmPrSmNgKqTjO~fּǿҶϯѯЯѸҵϱϱϬΦˤǞʣΧʢͧѨУhː`jJuUpkhehgktÙsqooeš}ͱӳڿؽŭ;DzƮì۾Ʊ˵īru˷ӽʤIJտǽϯʣȠşơǡʥΧͣˣˡkˎ_6hFjIdBgEgFuUyXhIeEpMlIfEvVvTiIeDgFeDgFkJhJgFgGlKoPjGiGfChHjLhIjHiGhGnLfFdCfAgAkGjHiFkHlJhBgCtPxUtPqNmKpOmJpN}[{YuSjIgGhIhGiKgJkOoUoSpTmPeCfEnLxXx[vXf_hnlhfekikoosj{δͽȳϪѬϬͬиȢͥѭټɽӷͪ˨ʪȢɡƠǠɢΧˤ̣ˤ̡nˏ]7eDlMiGmLdCqP~^sSfBqKuPrRyXuRvTkKfFfEjHjKhGhFjIxUwVpHlHcCfDhHlKqOyYtRiHfEcAhDrLpLkGhGoMlIkGkJnKxTrNkHuP|X~ZuUrTjOiKeCeDfFgDhGgFhGmRnToTlOiHhIyZjijmqnmkkeillmnthƦίʠʥʨͪӶЬͭʨͩΨͩϩΪ̦ͧոӽʣʢȡɣɢ̢ˤΩ̧ΣlˌZ5`AmPjKjJkKjHoQxWeBfBmKwSzV|Z~\{XiIfDiGgGgIgHjGnJpOuPuMjInMpMmMnMkJhHeBgDeCiHlJmIkHiGpMmKmInMwVmKiGjG}XyWnRmTmQjNpTfdtTnOiIfEc@hIjRgKiKgGcDvTfejjjmnpkgikmnpnĤ³Ծ˦̥ӶѺѵӲ׾Ҷɣʦ˦ϯίҷеΫѵѴЭͨѲֻɢʣȡȡɡ̣Ψά̢̣gˆV/`@jLiGhJhLbCcCqOhDa?cCuS|Z|[~]{XnNiJhFhGiJhHhAd>eDiHsOuPxTsRqPgDcAeDfGfDgDoPyXwVoLnJiGfFjKajd{ZsQnNgHgKiMjNjNgơşyrrj|\kLjNsQwU][`jkhjoommgglooml̰ķ׽ջտбϪˤʧʦʤͩźջѲӳϪͩΫΨ̧ʣ˦Ǣɣʤ̢Φɠ˟ˤfˇV3bBiJnNdFeEeKfGeBcAgEiHmLmOuVxYqPpOlKhHjJkJiIiFgCkGoLqNoMsOyWvRfBiGrQnLkIkIvXz]uTsQiJfGmNeljhie~`~`~]{_it{wssu|~tovoideijikorpggln˜spmͲǼЮͧͪΫջŷ׾վӹбҰӮЫɢ̦ɥ̧̤̩̬͢˥ΨeˈV4dClLiKeFdDgLeHgFcAeEnMiFjJlMmMvUwTiFhGiIiHjHiGfErOrNlIjGnJpLpLjGkIrQsQyVnLnQkMhHnLkJqQdnmnhgjotuz{zuuuqszux{ÚytnfbgjjkkkppgjonnuҺȺʻ̽ŶƷǸ°ϬέΩΨͨöյ~cˈV4cAfGdEdCdBfIfKeFbAdBfAjGjJkLjIoNsRnNgEiHoNkJdDeCiEfDhFhFnMsRpNjJpLrNpPsRpO{]uUqRoMtSkkkmojjjvzruÙyuvtšztrvwtwvsneegkjjikmjflktгʺ;Ŵijŵֻұؼ׾fˋ\;hGeJfJgHhFiLiNgJdDjJqMqMsQsUqQmMqPuVkKlItQhGfFkImLgDiFwT{VrPqPpOrOtQ{Z\esljbfpnopqqonvuxÝ~ywysstØtuytvttnhijmpmlmpnonzð̼ʹêڱ{~}~z}¢~vx~}}ɬαίϯѯбΰͱβϰβαвϰѳҶѶϳҶչӵҵѵҴѴҵҴҵггвѱѰϱͱͱϰбѲѳҲб̷ּݿ¥¦¥¤åεҷӶӵӵԷպӹԹպӸҸԸӸԸվӺԻպպּ׼ӸӹԸԸռԺջԷԶշԷӷԶշոԹԸԸɸǰܺťƩβѴѵҴѵҶչҶҷռԹҷԷֺʹƳӷ׽ԺպֹպҷӸչӹպչֺӷԷԷӶԸԸԷӷҵؾƮݵĦħŧɫϳѳгѳдѴҴҶҷҷӷӷҵʺƳҶӸԺӸҵҶҷԹԶԸԸԷԵӵӷԸҶӶŲŬݴ¥¦Ȯ˰гѴѳҳвгҵѵӷԷԹҷҶ­ԷͼξųƴȷؾӸԷ׼®ֻıһݳìӸԸѵϴгϴвбѳѵҵгƳƵҴԺ˱ɸ§ɯոӷегϳϲϰвѴҴвԼ˰ĬæγѳдҶдгѴβϰѲҴҵαȷջĪʯ¥̰ħдӶҳҵѱҳѵѴбЯвѴѲѵˤɡAyzHɰп±ͳոвʭвѴѳҴҵӵԷոշбааϲвʸ(rtR8st@ȸԿǶεȭƬμѴӷϲѱҴѴֹ׺ػնϱбҵˤƙ8tvMЯΩ׽ϫΪ‘ŘͨѰ9suFȝֻˤӐʡԸͨѴ׿ͪϮˤϭаּ̨Ȟřպа̨ջջΪʣսǵʳϻκӷϱбϰӶշӵвո̺Ż||rtwy~~Bּxym̧{|ɾ˥xyqt!Iz{7uv79psxy Ò^xzsutv|}ˣNuw0¸zyz ҵZ{|uwwxLvwhʾyzsuqt vx]ͫyz+ֽ˹Ų®ʸѾؽٿDzʵ̹xxyyzU>vx$ջvxkɠԷ˥z{ɽCuvƼ_~~ؿ4{||}1lxy׼*|}7SD vx&Ktv.·yxy ּЮ}~{|H'~~yzdř}}xz#qg6սsvhtw&ռֺ{{%v~~wyfԷvxhnsu5ˤz{ɾ5vx4Vvw׾6wx~~z{ɽȼЮqyzͨJtv-·xxyֽȡ}}}} wxcJwyҴvxM2rt"պʽ||z{·wxz(չvxk|}}}̦ϭz{ɽuuwxy9{|׽7sv=ұ xymչƚ2~~̨Jtv.vxy Ҵ$ru .4 wxc2uw3}~{|#Ժkyz}~Ĕ9xyؿֺuwuřxyxzTЯz{ʽĔK++||ּ6uw.ͧyz¶x˾6||yzuw3Jvxtwx ѱּk9'(xyd:wx |} z{"ҵky{}}Ò8xyպuwrHuwɼ yzʽҴǚCuw,6}}vչF||~ɠsxywywxSԹIz{{|UϬ4z{ջǛЯƙwxƹ~rvx\Ӵάķyջuw]Tpsά׿˾||z{oؿyz'Ե {|B^uwExzɽ˦uw}~ uwz{Ȼ3oq wyvxuwT)yz"ǹ}ʡ׾ٿIvxsuxzsvPTnr yztv&ֽ@wytv}~yz|} Ըtv_Bpt ֽո{|ұk~xybҲ ~ xzp̥z{ʼֺpI69RŖĸyO˽̦H>HHRR֭Ν##HHooooذ00߾ǏrrbbSS,,>>88$$͛oooooooooooooooouuoooo!!ooooooooCCСGGoooo׮˖ Ҥ^^==~~``oooo͚@@͚ss oooomm…]]Рܸ//oooo&&==<<DDȐooooǏ22ѣoooo ŋ ܹooooڴXX ܹΜooooС޼66))WWoooo##ƍĈӧ44ĉooooӦyyݻoooossĉÇر}}^^IIooooĉXXժ޼11mmVVLLŋԨoooo ҥrr „uu]]oooo͛GGܹŊLL>>oooozzFFii99ooooҤܹϟŋΝoooo~~KK߾jjpp  <lN?˘wsphz}{w}w]Xg_Ҷe_c^ϱrnkda[ǪԶԴЫ~wpg]Vb[i]vnfup^[RN\Y̭ԺέŧkeSLwHAzLCVHyOGrJ@vL@wN@rKlK?pPEnNBoN@qQCpO@rUG|aUuVIkN@mK?mN>mP@lM?źķ೔}zxr}ŬĽîsmcZ]Tmh}|rQJvTGjFhGqL=qKnM?nIoPBmN@mO@fJkH>kGnN?mJmJ:lI:lJ9mH:nI:ȵnlzRKuMFuMExYWnjvo~\WqQJpPGmKAnJ@sSGx_SrUMlMBpQDrQErQEmL?iHuVGcYnREiK9hJ7jL>jM?jM@jK=hKlMAmLBkI@w\V|c^dYq^yZKvZMy[Lnf}qaN]H^FwN;rH9uP@|ZGuP>mJ7lL7nM:mK:oO?qSCpPAlKnF4nF4mE5mD7oJmK>nJnGpJnH:mH:lJ:kH:mG7mI8mL;mE8nG5nL8lJ;kI;lM=kK;mL8rQ;pO9rN9ܷqlsWRnQHpQImMG}dZiJkI;kJ;jK;kK:hJ;gI7hK:hNlJ=mGoSApS?mJnL<~iemK;oO?rQ@pJ8oF4oF5nJ:oI;lG9kInM@pP@mODv_]}xxkaOjScM`JbIdK`L^KYDxN=pL;nH6kC2qM:zQkH:jG9mMlG5jG3iI4iH7hE7iJ;kMlKnJjF7iE7jI9mM:mI7lH5jE3jG7iC7jG:kM;kM=mK;lI9nM?pRBnL>mL>mL=lKlLqPBpQK‘pggWiWdPcPeOcLaIaI_KsO;kI5jF4iE2hD3iE4oH3rI4lE5jD6jE3kK8mL9nG4oI2pK5oI6mK7mI9nI9pMhL>jK@lOAnN@kInJ;uT@vTClF6jH7jI7kI7kH7lI7lD5kG5jF7hH;jJ=lI;kJ=kL?jH:rXRqRGmI;mI9mK8kL;mL;xS>|T?qN=mH;hA7xrmhiI9hJ8oSDlO@jM;lL;kL;lM=jG7jD3lJ6sQ;wQ?xQmM@pTIoOAjE5rYP}fcnPCnM;kI9|c]om{c\xYPcVpdl^dNgPeNcLcM`K^JXE|UByV@mJ4jC0iE3jH6gG7hE5mJ6kH2jC0kH4mM;lI8lC3nI3nJ6kF4iG6lI:nJ9mH8lInK=vYJjG8jE5jF4kJ7jI6iG6jH5iG7hF9jI;kL;nI9kF8mO@jK=x[SmgrRImK;mL9lJ9mK;vQ?xV@nL8mH8hB5rlrlkI9kG6iB1jJ7kM:kL;mM:oP{P?zP=xShG:hG9iJ:kK:nN?nN?nK>eD9pglbdA/qP?dYuUHlJ|WBqK8kC2iE6kF4jE3iB2jC2kF3kD/mF2oO;oK8kD4pO=uQ?nK8jF5kF4pN8lK8mL>{XFpL;hE6oO?jG7kH7jE4iE5iI8iF7hE8gH9iJ:iH8kM9mM:jG6uVHvVNjazb\lH7nL9nK9pP=sS?{\JoP?vTCiC9rmeC4kG8kF4lJ6mJ8kF9nK;qQ?nMzS@yR@xP>vR>vV>wS=zQ>zP=xPmK=nM=hI=zd_sYQiB/pN=hb{]SkH9f@0oUJqggL=fH7gF7lK:iI8iH7fG;v`XiL@jI;kG:jH9fE:zskfD6lH9iF;jI=rR?lJ9kF3jE4qPArQCgA7lkqXRkG:qSL{kdLeOlTjOiOeNcMbMaL^H{XDrN>yS@{WEoJ;mF6lG6lG5mF6lD6mE2nF0lC-kE0pN;oK7lG6qO?{XDuPsN?vR@yS?zS@{SA{P?yQ>wR=uS=wT>{Q;{P;{Q;yP=yRxS?Ƶ»x|WGmK>mL?oOBmG:oJ=f_ealPCjL?jL>iH:gD4iH6hH7iH8mK=pP>qP>iF:lhyc`iB3oL>mhhahF:g@2nSExbTeF7fE7gE6kH9iH8hG7gJ@urhKBiIlH6lH5hC5|\NrRAhD;rn|{hJFrdjTgMfMfMfNhNdMcLbK^H|VAuM;oJ;vUC}aJnK:nH7pK8vPyR=vQ;wT=xR=zN:{O:yO=yQxQ>DZk`bNxQ@sQ@mI:kI>rUJmHqO>eA6yuzd\jE3kJ=zjceC6iG3fD3dB0hG6hF7jI9kJqJ:oD8wUIg[uQIielFyS=wT=xP;zN<{Q=yPpUClK9kL>|hcxd_{fbnhzaWgH:fH9fI:fH9gH7hJ6hL8cD4sZMxZHnK;gD9ws{g_fC0mO?|f\pVKgG6hD1jE2hG6hF6jI8jH:lLBpUJbC8mk~hJAiG=jI>mL?~UDYGsQAjG8lG7oM@[MrO@iH:kI:jI6sVCnK=lK=ng{zù[VxdOhPjMfMeMbLgReMbJ]I|TDmF8nE6lD9qSDx\FrP=qO:rP;uR>vP?oJ:rM:mK7jH2jF4lK8nI5nG5yTByZNrmz^VoQAkK:gG7hLnN>nI;nF:rR@oK;oF;z\RofqTOzwkI:y[KoN=vWCmM:lK8kH6jH6kI9lM;kJ9mI5lH4rP9wR:xQ6yQ7xS:zT;zT=|T={P;{O;|P:{O:zQmO;lM>xc\ysw[RkL=iKrlqkjL@jL?hI?uRC^E[D}WFmK>lI;|ZMzXHjG6kJ:jK=eI;|g\nPBlH8rQGrpi`o^eMhNhNdMbMbMgSdMaI^I~SBlE5mD3mH:sSCzZEuR=qP;pL:nLlL=mJ=nJ;pQ?mK;oK>y\Tqjjh҉wsmK?wXIkI9lM:kH7jG4iJ6jJ7kM;nN@nM:mK7pO=wSkJgI:kL:eG9{e^mK?qTGpUFpO@nM@kJ?{YD`F[CVCpK?oNC}^RjF5hG4iK:iI:jLAmgpOCmJ9oL@Ο~pc}naMeNgPeOdNdNaNeNbK_H^G}TBlG7lH5lH8rSDz\MyUBsN;qI9nH:oN:nL6qP;nM9kI7lMxT>vS>xS|bXwqhJAjI=hE:|cWsiPDeE4hG4gH9mQAnSCkL@lLAkODlTMmPEgB4cXuWLiH9rSErRCvXFqQCqQCvUCvP@[CZDoK@qPCrRCkH5jH4jK8gK:kPG|xnTIjG9za[xprbm_bNiPgOcM\GZH_K_J]E}U?XA{U@mH6lF4kH4sUEeZyVErK9qH6oH4nI5nJ5qR>oTCv[Oz_VuYLnN>iF4uRB`UuTLy\PkK:hG5hG7hE5gH6hG8gH:jK=jHrQ@xTDnJ|Q?{P?|R?|P:{Q;yQ:zS8zQ7{R:zU=yU?xS?vS:xR;vVQoMAnMAkI>iI;hF8hA5hE8jK;jF4jC2hH5iH6gF6fC6eD8dI?pXMjIjG8nM=oM=wYHpPBuTEmI;oK;]H]FsPCpODpPAjG7iE4kK:fJ?~}kUMhH@vum]o\iWeQfOfNbKzM9|Q@_K^H{T?kI4uQ;Y?nI6lB4mJ7xWI`SsL;qH6nG5mE2nF2lD3jF4kL:~bVe^|_VlF6kE3qP?}^Ry]RoQ@fF6iH8hG8hF7iH8hJ9kK;iI;kI=pN?uRCuVKlb|_TlL@h[~vqQElK;rSGyvŝeElK8kK8kK9mN:lK6jJ5mM9uP>wQ>zTA\E~U@zQzU>zS;|T9|R7}T:Y@}W@{R>{S?zT>|S>|Q;{Q;xS;yT:{Q9|P9ySjG9jF7hJ:x`ZiRJiPLuiWlYjUfPgPfNbKzO>{R@]I\FqM8kB/qL6}YAsN;kD6nJ<`R]OrL;pI5mF2lE2lD1mF3lE3jF8uYPpmd[lG6lD4mJ9oM@nJ;mJ8hI8iG8hD4hF6jL9jK8jL;mN?pM>rPAwSFxWLul{]VnJ?sl{vWIqSCg]vnujwXKmF7oK{T{Q<}R>~x}\YlPCmOBhE:gF7fG7dA6jN@hJlehF8lG5kF4hD6nL=nL9iH6iI8hE5hF6iF7hG8kN;\HYD{VD{WG{XIwkwXLoKAxmsTEpR@qQ@hG3c@/kH5oJ7mI7kK9kK9iJ7lL:uSAuQ@yU={S<{Q;{R<|T<[?W=|T?{T={V=zS<{R<{S<}V<}U=|S=~YA}Y@zTzQ>{S>{Q<|Q:{T;xTofgHeQ\GqN;jI7kI8kN@lM=oQDg[qUK~gRK~ovddSjUiUePdMbKYDpL8}YB_GZDsL5nG1pJ6ZCZDrK:{R@_M\JnL=rP:mI3hD2jB0kF3kM8s\R~~i_hF8jF5nPAw^QjK:iF3jJ8iI9hE7jG8jI8gG8sTDlYZE[E~XEbVympNB}_XsYNnN?mK9iH5kK8jJ9mL9lI7mJ8pOzS=}U<|U;|S<}Z>~[?{Q;\E^G{V>}U;}S:~T<~V=~W?dKeI~Z@zVgJzYImX[E[HrL9lE0uO<[FzO;sJ7\Jl`aPpN;iB/kI4hF2iB1iF5gMBx[Q|`OjH6jD2lK:nN|S>lWfSYBW@}S<}S=~T?\DnRgHcD_D~X@zV?}V@}S>|R=|R=|Q<|T=|V>|V>|T=lD9lIpS@gF2gG5iH7mK?xWIsKA}XJ~YG~UE]NeO]HzTDpLD}\UpQClK8gD3yov[VdaxssN>yV@wS@}\E{W?sK9~\IlRIoO?gE6jJ;bD5unhLJqrk]iViTfTgSdNcNcO\GjI6wYHbNYE^JwP=nJ4vS@sM:oE1rJ5`Nunj]rSAiA1lJ7iH7kE4iF7pWQȾ–~z~[KvXChI5jH6iD4jH5iI6hG5jI6jJ8iK;jJ:mJ9lJ;yYLzWJnD4[HwN@|qgsN>qP@hG6jI5lK8nM~T>}S<S>VAfR_I^G\F~W@~T?~R=\DiOaH`DdH]F}U@~U>~T?}T>|S<{Q<|T?}W>~V>~V@pM@mK>kHjM>hH;jG:iIjF7nI=cWpMBwmsi\L]MZJxSCuQBrOAwUHmM@jG7hF7aVnLF`YyO?sL:rM8ZBzR=oH7~_QsqhnL@fC3iD5kH9_C;mVSkXhThRmWnYeQbMaKyQ=iF5sQ?XE\HbH|VBsO>sP=mG1nF0pK7`MxpcXlL=kD4mJ8kF8nE6kG8yZQxqrQ@pQ=jF5jF7iI:jM:jH6hD4jH6nN>oRAkK:mJ9mI:zWLzUHqJ:[JqL=g^uRHhD2iD1jJ8kK9rOuP@YB~WBoebW~YG\H[DV?YAZA\B^FU@VBiScObL`IWBT>R<^FnR]DV?_G`HbQhV~U@V@T?|S>|S>^GZDWDpO@mM@lJ?kK?hJ=hJ=iJ;kK>vTJe`vVNrSH{_YbWhXj^z[NiB5oIjH8iH4kL8nP?pR@nM;oLoK6zY@yVAyT@~WB[Ei[sj^IaK^GXBWA]CaEfK_I`KyclWeNcMYEU@~Q?bKkQYC}R=[F^KshshZCW?W>V?|S=dQbP[GlL@mPDlK?jI?jNBjM@jN@lL?vUJmfzXOlJC{pcRykeWsP@yR@[FuQAuSCcSxVGrQDyUIlH:`WfHBumogjK;gE:ZNwRBoK4pL7|_N{`TeA3kH8iG6{`TsXIeC2iI6hI9xWLĺnOKcTphXiQgTq`n\gS]H~ZDvU@qN;yVFkZ\I|U?yS={W@qN9lI4mI3jB/|b[|e^uYPiI=lK;kE1mI5lK6rN=uN>lB3kG5kJ7jD4jF6lJ8lI8iI7jK8iL7oS@~bUnN>nM@|_VzZMpJ:oF3pH3lF3mJ7lI6jH5lI6uQ;{S=|S>|U@}VAxO9{W>}W?~V?~T@\EaKdOfNaK]H]GeKcI^HaKeM~kmZeLdL\FXBV@\DhPYD|Q=WC\Isem\aL\DU?XDW@lXhU]GkI>pSEnQCpRCv\OoVInQEmOEwYRxrf`nICzwl{WH]JcO}ZI}WD[FxTCsL>sM?z[PmdzZNoNBf[lF:cXibmN@fH=Ź\P{TBrO8pO8uT@sUBhI5hF5hD4pUGmP@fD4jJ8lM<}[Py[VmYq]hWgPdNjsbaN^G|XBxTBqJlS@hH6{_SysUGnJ;z^PoM?nK=lE5mF3lH3lJ7kJ7lK8rN;{T>|U?}S>~U?~W@|S?|U=|W@}U@|T@ZD\KeThSdRZJ`JbLaJ]J^IiOpePfJfK_J_J[DXAhTYD}Q=T@[BiSfPfMeMXD`JbM~km[dWlJ>uSGaR_RocqZOpSGoPFfZ~xrNEl_pewUI~^MsUFkJ<|YF^H~XFpE=~[Riawrx\SmL@qVHiE8~d_~jblM?fE?úzq~WG[HvR>pK6qQ>sWBgI3iH5kG7iH:jH9jJ9iJ:lNoM:pL:lH:sXPsqmm}fbeF}T=}T>|S?~T>T?T?~U?~V@}U@~VBXC^T\MfPfQ^LaMcMdNbK`IhOqY_FcHaH]H`J\FZHgS}WE}Q@T?X?aHbMcLfLbLiNjRw]hRh\pOB[Mk_uovVMoNApM@mK@bSo|zSEdSp`xUIyVIlK=iG7|ZIbN[IqK@i\{[PbZqQElL?qUElOE~~qPFlH?qkrj}ZIyU?qP:mH3v\LqXFhG5kJ7kI:lL?nP@jL>jM>fJ>niiWjS}q}}eQbL|T@qM:xUBvR@{UBzVAuQ@}`R{pfhD8kG8pL;\FyXCpO=pK=jC9}b^zc_z]ShJ;jJ:kF7kD6iH6iG5kF3jJ5iK7hI5iI7hE7hE6lO@oS@jM~S=~U>~U=~S<U>V@~S?S?T?}V?ZDXBYC]Pz~WFo]^J]JdPiT_I\E_GaGeIbG[BZC[EaH[GVC^GXC~R@T@V@`GdLdJdJeLfNjPkNgN`PvTG\NneuQJnJ;nJ=qK@bQnY{gcPgShY~ZPgZpO@kF:gSgQZIoI@hcmQGqPBoK=oN?nRCr]W~fapOGrkrpdrQ@kJ3jG1lD0mLjJ9iJ:kKrRHeA8mOGlI;lK:lK;jF8iF5iI5jH5iF4kL7mO?mPBiK;jF7jJ;}cYkOEeKDz_TlH7mK8kH7mK8lK7qP:zU?|U?T?~T?~T>~S>}U>U?U?S?~S?~U@~X@]GVAYE\NpdYHsc~ZEXB]J_JZCYA_E_F_G_CY@X@]EaG[DUAZCYCS@T@T@_GeIeLbKZH_JhOkRfPaOjXgTvgz\VqM@nJ>xQBjUmYubgRhQfQeVk[sO@nH>m\cOuOBhI@rPFpOCoNoJ:xUFgWnN@zvgC;mghbgD6kK;kJ9hF8hG5hG4iH6kK6kI8y[LsXJjKqnuy¹e_pNCnL=mJ~U@~W@V?T?T?S@~U@W@U?S?V@[H~n`N~YDbM~W@U?W@XAXBX@[B\B[CZBXBYBZB\C[BU@\B\CT@T>VA^GdHcIcJ]HbIgMgMhObKp^o_yj~c[zZOzXJ]NeSfU|o~UHfQfQ~XIj\uPDrK?`PxUFlLDeE>miqllL=jK>»vYRiHFzrh[x]TjJ8nP=hG6jJ8gJDus{gblJEva`ȇvrkLBpml]\Iy|dPdQuPC^Q~\OuQBpMmI8lO@jJ;hF6gI6hI5iI6jI8qREi[x[NoQ@yWDqVLо]WrLAyVGsOBqL?vT@yVAzUA|VB|VA|W@|W@|W@~V?T?~U@X@~U@T?V@~R>~S=~U@T@~T=V>XC_I\EYA~ZA|U>T=}VA~XBV@V@X@Z?Y@XAV@XBZDV@V@V?]@Y@W@X?WA`HcJfJeK^FcIfNeLcL`JkXo_vjmkz\Tm\hWYJ\IjZyLAZJ|XGvPAwh~\NxTGwnsUMlLAhSPjM?kN@ùjhvuғ{wxUG}\MvVFjI9mQ@iH8fG@vb`srlKCc]j[]JxugRhT[Oxj`aRvUDjE4aTyWLrO>eV}]OnJ<|ZL~YKmG9rP@lI;iG9kF6lJ;iK>iI:iJ9jJ8lK7lK:bRr^cPrPBjarLCoJ@}YK|XE}XD{VA}ZBZCUB~VD}WE|VA{W?}W>~X>~T@}S@W@}W@~V@XA~U>~U?~U?T>U>W?[B\FYD~W@W?~V=X>X?X>~V@TAU@X?Z@ZAUAVAXAV@U@U@U@U@X?Z?V@]EaIaIcK_EcJfM`I]C_FnZqaxjzusigW{YH]IiTxPC{WH{WErRDxl~[O{^SoSMeICbKI¿kI:mO@pRHuXL|^QrRCkJ:mN;gG9~ieƼ{WSƾrSJf_n_eSsi|qhTfPcTc[fYpPBkE7dW}x|sz[NyZPyZQvSEmJ>|\TwVJkD6mH8mJ9jF6iE6hF6jK:iI9gF5kI6iF6kM?cWykye[xQAwQ@vQC~ZI}WDWB~VA|XDWBWBXC}VC}UC{V@~Y?X@V@U@V@WAXAXA~T?~T?V?V=U>W@ZC]EYAV@V?W>W?V@U>T?VA}W@XAZ@YAVAWAUAU@V@W@X@W@ZC~[C~XA\FZEWB\D_GcJeI\DW@_Bl\ynwj~b]z\OzYH{YFvdcUuRCyVGvUGeSyVGwUHrcoK>mRMſrWTmgiI?pRIſæz]TlL?lTI}g^rQBnLXC~U@|S@~XA~YBW@W@~VBUBVCWD~VD}VC}VF}XA~XAT@X@Y@~V?~V@XAV@~T?V@U?U?V@ZE`G[CUA~V@W@~UA~U@T?S@V@W@XAYBV@U@~X@~YA~V@~UAW@YB~X@[C~]E|YA]F[DU@YCXD\EeK\FV@]Dxo{YTvUHxUFxUDi[n^kE9yr|b\h]wUFpL:{ZGlG:jfrnjfuWMoP@~\Mۙz`VnQEnPBlMArXPrULmL?fGW>W?~X@WAVBVAVBXDVCUCVCVAVBVAZA~[AW@~TA~V@~Y@XA~XAX@U?V@YDbI]EXCV@~W@~WCU@U@~TAT?V@WAYBW@V@X@~Y@}U?~W@\D[E~YC`H|\D}YA]D_FWAYBXD\EdK^HVC]Gzuc[|\N{ZL]NnezfE=y`^rp}_WnJ{X@uR?vU@|YA~W@XAT>T>W@X@XAWBYDUBTAUAUBVBXDUBUBXA~XA~XA~Z@}X@XAW@V@XA[BV@W@\DaI]EWA~WA}WAYAV@V@WAW@XAX@XAXBWA~XA~[B}V>W@]EZF[IaK}YA~Y@]A]BXAZDWC\EbI_HYE]GzYUslg^_Ph]volMD}v[XuqjD;rO@hEfW|wwZQeU]S“sUNrSBlM9kK9jI8iI:gG9hJ8pQ?vTBzYEzUDpO=mO;lN;oM~YB~WA}W@|X@{W@}ZA~YAXBWBU@U?W@XAXCXBXBW@~V@TAVAU@XBXAYB~[D~XD}YA}\A}[@~[@Y@W@YA[E~WCY@\B]B\DXA~WAYAXAVAV@WC~WAXAYCYCZCXA~ZC}ZC}X@}W>[CZFYI]HZAYA^DYBU@ZAX@\DjQ\EWC[Ez}usPI~q_Yg`x[Uy]SrkwZUiF@sSEjG={rlzrul[KsK@rOC|rqUKoQCmMAqQDx[MpZT{wqPF^Syqzl`sd]nYRwukeoF=nC9vL@yqzwjdv[VɫhJ>nN9jK9lN9iJ9jL;iK:nP=zWA}XA~XD}WBzUAsR@zW@}XB~WAWAV@~W@~W@V@}XA|WAXDXDVBVAWBXDWDWD~WA~YAX@V@~YBV@W@ZA~ZB~[D~YD}YD}YC~Y@[?Y@X@W@XDYEYCVAW@X@[BZ@~ZAXBXCW@XCXC~XCXCXBXBYA~YA}X@W@Y@[BZDVCYCYCXA]CXATBWCX@\EhQ[CVAWAoH?c\g_u~wWSvSK~{lhf_zYSvWQlOHvVHy\U|wpj{kesO?nK=z_RxjnODqQBoMAvZNs[Qs]YǿżùsVO}^Y|TLripLCoG:xPByڠyWMnN?lM:kN;kM7kL:kP@kO?vV@|ZB|YC}XBWAWA~XAX@YCWBWAXB~WA~V@~U@~XBXBWAYCWCUCUCXDXCXA~X@|[@~[?~Y>X@V@WBXBXC~YFZFYEZC}YA~Y@X@W@V@ZFZEYBVAUAV@Y@[B~[A~ZC~ZC~ZCXB~XB~WC~WCXCVBYCZEYCXAXBXCZEXDXCXBXAWAWAVAUB~U@~YC`I[BX@Z@rSIqzzqoOKvXRwqwUOmLJǿ®nMEzVK{q}~qloOAnM@zcZjdoMCpOAoLBmYR~zxǿ·{ba|ulyKAcTq`wdwsPFoH8sNvUAxWC|YB}ZD}[F}YC~X@Y@ZC~XBV@V@U@U@V@WBVAV@Y@Y@XAYDVDVCWBZD~XAY@~\@~\?~X=Y>W?V@YAYCZF[HXFWDYB~X@V?Y@YB]GZDWBWB~XBW@W@~ZC~X@~XA}ZBZA~[B~YBWCYE[EXBYC[D[DXBYAXA~XDYEWDXCYBXBWEXCWC~XC]HcNYCZB[CcU}n~uv\Y|^[ĽuodaľqPHod~x¸újKAmNBzwoRFoMCfPMĽ·qm_zOEfWo^{gvxVLnH:mG:c[Ǵv}WLsPC|YJ}YE|XCyXCzXB}[C|YA\A\BYC[E~\F[FXBYBZDYDWAWAV@XCYDZFWBW@X?~Y@~W@~ZC~YCXCXA~YAY@}YA~[BY@V>W>X>V?~ZAZBZD[GZF[GZEX@YAXAZBYDXCXBYB~YB~X@XAWAX@~XAX@YA~YA}X@}WA[D\DXBWCZCYCYB[AYB~YD~ZI`O[EYCWAWA~YC~YC~WD\I`JZBYBYByjjYwǕspŻ{[YԨogd^~˼㳨gdoMBmPEydbgIAn][ûĸù´~owhxiugmpsr~rULsTCkPCɬlb[K[J`OZIZFZE\E~\D}^C}^B\CZAZBZEZFWEYFWDYB}\G\GZA[BXBXEXFZDYBYA[?~\@|\@|ZA~ZAXAWBXAXC~YDZBZ@~X>Y@Y>X?Y@XAYDZEZD[FYEYBXBXA~YC~VCVC~XCZB}ZBX@YAXAYB[DXA~YAXCXB~YD\E\DXAYB\D^D\AY?Z@YB[H`LYDYCXCWCXBYC}WC]F\EXBW@XBsghT{lyržρffqqĽ̛~浮ywmMGlSOrfkv{n~nqn{k{lyokdiI;sUHudcS}WF[G_LbM^LYJZHZF\E\C]D\DZB[CZDYE\FYFYGZE[FZGZEZBZBYBWCWCYBYDYA\A\A}YA~XAWBZCYEZFYE~XF~ZC[B~\@Y=X?Z@ZAWAWCXDWCYFYEXBYCYBXB~XB}XB~WAXB|YD}YCYB~XBZBYB~YBWAXDVCWCYBYA[CZB\C]BYAW@XAWA[D\GVDWDWFXFXDXBXBZCZEXAW@WAogfWzrki{ppøjhuu׹z[VuVN|kkz{sxo{§`VoMAbPePcQiU_M^K`K_JaI_G[C[C\F[D[DZCZC[DZF[G[H[H[H]FZE[EZCZCZCXDXCZDZFYDXDWAWCXBYBYCXBZE[FYDYD}[E}]D[@YBYBXBYCWAXBVBYCXEYEZFZEWDXA~XA~YC~YCYB~ZBYCZDZBZD}ZD~[CXBUAVAXAZ@[@ZA[AZAW@XAYAW@YBZEWCVEWEXDZDYBXAX@YBW@WAWAxk`Uedqmþ䘆|c_spĿ{ikkWYǵױéxheVcUxj`RaNkWcSfTseaR^K`McMdJ`H\E]F\F[F[D\DYB\E]G\HZF\H]H\E\DYBZD[D[EZEYC[DZDYGYEXBXBXEXDXBYDYCYEYE[D\G~]D}\D[FXDXCYCYCXAXBZCYBZDZD[DYCZB}[B|[C~YEZD}YC~ZBZBZB~ZD~ZC~[D~ZCYDYBXAYAY@[BYBXAZCZCYCYBYCXCWAYDYEYEYEYDYCYAXAXCYCWCyvQJf`ji·ޑqVLv\W⺟i_wUMiKFlMD{VKh\{rѽҸq_UvRDcSp\s^oWp[bPeRhWcQhVl\^N_NePhUeP_L]G_G]F]G[D]E]F[E]G[IXH\I\GZF[DZCYD\E\D[DZBYB[DYCYCYDYCYDXEWEYEZC[EYDZBZD[D[CYEXGXFZFYDXAWAZCXBWDXCZBZB~[B}[B|YC~ZF[E[C[DZDZBYBZD~ZDYDYDZDXAXCWAXBZBZC[F[EYDYDXB[DZCZC[BXB~XC[EZCZBXB~YDZAWBf\uMBwSMuu斅dLHe`qMBzYJaQvVMzXN_M`M`L]I\K_SdYpdvssfk]dTXH^IgSlVoXlWlUgPhPrZgRcOkWodqecS[L_MePhTfQ_I\H_I^I[G]G]F]G[H\J\H\G\HZFZFZD\E[E]G[E\D[CZA[AYB[AYB[D[BZEYEYF[HZEZCYCXAYBZDXEXFXEXEYCZCYCYCYDYDXBZCZA~ZB\C~ZD[F[DZDZFZDZDZE[EZEYEZD[BZBYAV@WBZC\CYCXC[EYEXB[E[D[D[C[AYCZEYCZCZBZBYBXExYTsI@{_\úŻجÓplrNDuQFxTG`MbK]MZL]K^K`JbJbJbMaO]J|ZD|XB|XD{XC{XA|ZC_I`L^K]J_KdOiRkUfQhPkTfNoWnWkTjWeY^LaMfRlZfScN^JaL_J^H]G[E]G]I^G]H[G[D[E\E[D\D[D\G^GZCZC[C[BZAZAXBWBYCZDXEXHZJ[E]E\G[EZC\DZEZGYF[EZDXCYDZB\D\CYAZBZAYB[E[FZD[C\CZEZC\EZEYFYFZGXDZCZDYCYBYCYDZEXAZBYDYEZGYFZC[CZDZBZCYBZB\D[DZDYBWCxscFCüɾǹƷż~\UvOA|XIvSFzWGaI_H^I\J[I[H]F_F]F^J]I^H_I_J`I`I_H]G^J^KYFYEYF]F^GbL`JhPlR`IfQnVnSlSll_cNdNjVo^yll^]KgQ`JbK]I]I]GcMaJ[F[E\D[D\F\F[D\D\F\DZB[EZB[B\C[DXCWDXDYCXGXGZG[F\CYBZCZB[EYF[F[E[EZDYCXCZC\D\DXAXAZBYB[EZDZD\E[D[C\C]D\E[EYFYGZFZF[G]F]D[C]F^HY@[CYF[D_JZFZDZC[E[EXAXBZCYD[FZEYDYD½ȿƹij´¾c[uRC{WE\K|XH\G^F\F\F\H[HYE[F[E\D_G^H]I^I^H]F^G^H[H[FXDYE[EZE\F]HbJaJhPhQ`JgQnVlTmUmVgY{pfWgSgUk]wpd\HjRfMeM_H^F]FcLcJ]G\G\E[E]H[E[D[D\D[DZD\F\F^E\EZEZFXEYDYCYDYEZEYG[DZBZ@^C\E[E[D[DZE[H[F\D[B[C[DYCXB\C\C[CYDZFZH[F[D[DZC\D[DYEZD[C[E[F[D[D[E^G_G~ZA[D\E]FbJ^EXBZAYCYCYCXBYDZFZF[CZCZCĽú¸ȹj]~]K{ZI{YF`K]H]E_G]F[D[G]I\G[E\G]D]E]F^F\E^H_I[F]H]H[EYC\D^E^E]F]G^G]GgNmR`LgPoSoVnVoXkXzovffVn_xll]_LnWgNeM^J^H_GbJaI]H\G[D\F\H]F^F\G\F\C[D\G[G]F_D_E\FZEZEZD\D[CZCZE[DZCZB[A]C\D[C[EZG[G]G\DZD[DYBXCWC\E\C[CYEZGYFZF~[E[EYCZDZEZC[C[CYBZCZC\EZD[D]F~\E\E\F\E^G\DYAYAYCZC[CZCYDYCYC\E[CYCûظfWaJcL^K^I_H]H]F\E\EZC\F^G]H[E]E]E]F]E^F`H`I_I\G]F]F\F\E^D_E_F\E\D]F^HdJmPeNfOeMhQmVnXmZlZsap^dPq^lZcNcLhQ_JaK^I\E_FcKaJ[I\G\E^E\G\H]H[E\D^E\C\D^F]E\C]E[D[E\E[C\C]D\D\EYDYCYAY@[A\C\D\EZFZE\G[E[F[F[DWCXC[E[C]F\E[EZEZD[D[EXEWFZF[D\F^EZCXBZC\E[E[E[EXC[E\FYD[E\DZ@X@XB[C]D[E[CZB[C]FYBWBɺ}`MbJdL`L_K_H_H^G^G]E]F[F\E[C\F\F]F[E]D^E_HaIaJaK^G]F\D]E^F]E\F^G]J[F\E^FbGiLfNfP`KaKkTnXnXnVgRaQaOl]{lgUfPfQ\JaNaL\FbHfJcL]J]H_G^H]G]H[H\D_F^E\D\D]D\DYCYB\E]G\G[G\E\F]H\DZDZC[BZBZA]D\E\D[FZF[G[G\F[D^GZEZDYDXE]E\G[EYC[C[D\E[FZEZHXF\H]IZD[CZA[C[D[C[CYB[DZC[EZD\EZCXBYB[DZDYC[C[A[C\E[GZFŮǵҺī{ocdP_HeLaJ_I^J`I^I^G_F_F_D^F]G[EZC[D^F\F[E\C\C\F]GaL`J^H^H]F_G]G]F_F\G]I]F[D\C_EcKbLgPeNaLhQmUoUnVgRbRdPlZ}rcm_o]_IbO`M^HeJkLhM]H_G^I^K]F_H]FaJeM^E\EZDZDZE[E\E]F\HYG[H\GZFZI[GZDZCZB[DYB\E]HZE[E[EZG[G[EZC_E\D[C[CZC\D[C]D\E[C\D]F[DYEZHXEYD[H[E\D\D\D[DZDXCYB[B[BZBZCYBYAXB[DZDXCXDXCZB\B]EZFZE}l^aPbNdNgUhXjXj[i\k^gXdTaP]K^L]K_JdMbKaI`H^G^G^J^I^G]F]F\E]E]F\F]E\D\E]F]E[G[FZBZC[F]J\H\H]I]G^G^F^F`H]G^G`F`F]E]F^H^J_HfOdMbLkTpVnXeSbPgQgRwe}nuiwgcObP`N_JfIjMfN`H_G_G_I]H^F`FaI`F^D\FZD]G[E[E[E[FZGZG]I[G[HYG[F[E[E]E\DYBZC[D[D]EZDYDZEZD\DaF[D[D]E\D]C\D]F\FZD[C^E]B\C[FYFYFZG\E]E\E[DZF\HYD[C\C\AZ@YBXAXAYBYC[DZDYC~[E}[CZC[FZGZFbSbOgPgTdQgOhMfNfNfOcObObObPeOdO`N`NcPbM_J^H_I_I^I^H]F]E^G[E]F]E\E_H]F\D\F]E]E\H[G[F[E\E]I\K\I\G]G\E^G^G`J^IaI_G]F\E\E\D[EYF_K`J_JgPoUqVjTiTkTfPq]qo\iWbO`MdO_KdKcKbJaIaIbJdLaK_I`GaH^F\F\G\H^H\G\F[D[F\G\G\I\I\JZG[F[E\E]F]E]E[B]D^E\E[FYG\GZD[C^D\D^C`E^E\D\FZEZD[D\D^E\C^D\EZEZDZD\D]EYB\F\G]I[HZE\F]C]B[BZCZBXBXBZCYDXE[E[D\F\FZD[EfTeSeQcPbMcKcLcLcNcObOaM`M`MaMaL]J\I_K`K]I]H]G_I^H]G^F]F^F]E]E]F[D_F^F\D\D\D[DZG\F^F\E^F^H\H^H`H_G\E\E^G_H_H\H[F]F^G^F\E[DYE\H^I[G_IjSlSnVoWmVfQnW{elXgQaKaLgO`LbNbNdMaIaIbJgL`J`IcJaI_H^G_H]I`J^H]G\D\E^G]GZH\I[F[D\E[D[F\F\E]G\C]B^D]D[F[F\E^E]C]E`EgEbE_F[DZD\C[BZDZD\E]D\E[FZDZBZCZBZC[E]H]I]H[G[D]E]D]D\A\B[D[D[DYBZE[FYDZE\G^HZF\FcPdPdNcM`KbJbLaLaK`L`KaJ_J_K_HaIaJ^H_IaJ^H]G^G^I^I^I_H]G]F^F\E]E\F_F]E\E\E\EZF\H\F]G\F]FaF]E_GcH]D]D\H\G^G_G]I^I_F]F\G_G[DZE]H]G\G]EiQmUoWoWoVfSmXmWiScMaJ_J`JdLaLcMiPeMbIbHdI`JbLdJaJ`H`I_JcNaL]F]F\E\F\DZCYF\G[D[D\D[C^F^F]E]G[F[C~]D[C[D[E\D]E^D]D`FcH]F^G[GZF[DYCYCZCZE]E\EZEZC\B\C\B]D]F\H[H\H\G[E\D\D\EZD[C[B\E\EZDYCYC[E\E[D]F\FZDfQcPcNbMbMdNdObNbL_I`IaI`HaKaIaI`IaJbIaI^G_HaH^J^I`J^G^F]G^G\E\D]E_F\E\D\E\E\F\I\G\E[E]DcG]E^F`H]E[E[H]G`H_H_J^I\G]F_G_G^G^H_H[H]G`GkOlQkTpXpWiRlWlXkWcOaJ_H^HdLcOaMkRgOcIdIbI_JaJbLbL_J^J`LdQ_J^I`J^F]F]D[C\E_G^F\E\C\C^F_F^G[F[F[F^G\DYD\E\D]D\C\D_F^GZH[I[HYF\E]C[CZD[F[GZEZF[E\D\D]C\C[E[I[IYEZE[G[G[D[E[D\C]D]EZC\D\D[DZD]F]E]FZDZEhScNbNcNdPdMdMbLbKcLcLbJcJaKaLbK`H`I`HbI`I^GaI`I`H_I^G_I^H\E\E\D]E_F]F\F]F^H`H\F\E]G]G[E`G_G_F_G]F[HZH\H^G_H^H\F^I_H_F]H^I^F^G]H]E_HeNlQmQmUoVmTnToWmWgQcL`IePq^fPdLmTeNgOlQcK^H^Im[n\aNbOeReQdLaL`K]H[F\G]G]G]G\E\C^C`D^F\G]I[G[G^G]D\CZC\D^E]D]D\E\G_I\I\H]G]F\D_C]D[E[FZE[EZF]G_G\F[DYB[EZE[GZGZE^G]G[F\E\F]E^E]E^F^F]E^F\E[D\D[D[D[FhTdOcOcMbNbNcMbKbKbKdLcKbI`J_LaL`K^J_I_H`J^I]I]G^G^G_G^G]E]E_E]E]D_F^F\F`H_H]J\F[E\F]F\G\F^GbJbIaI`L\J\I]H^H]G\D^G^G^G[G\F_H^H]G[G]GaGjNjMlQnTnRpTnSmUlThO`GhOs^cNdNjUeSmWqWdM`I_JhVxegUeS{ik\hWeRbL^J^K]J]H^G]F]D]C_E^F\F]G\IZGYF_H^F\D[C\E_E]D]D\DZE_L\I]H_H^F]D^DZD[E[EZEYEZG[G\FZDZDZD[DZE\G\G[F]I^F\H[G]F]F]F_G^I[F[G]H\H[D[D\D[C]DlVfReRdPbOcObMcLbJbLbLbKbKaL_K`K`LbLaI_H_I`J`I]G]F_G_G^D]C_D_E_D^D^E^F\F^H^J]H]G_G^E^E^F]EaIhNeLbIbH[I\G]G]G\F_H`G[E]E\D`I^H_I]G\G]H`GeHfKiMnQoRnPmQnUlRiObMeLjNfPcNiUjXmXkTeObIaJgT|mn``Pl\i[n`eSeO`L`L^J^J]H]F]F^F]F]F]G\F[F[H\F^E_G^F\D^G`E_D[D[C\E_H]H]I_I^F[EZD[DZC[I^J[FZGZG\H\G[EZDYCZC[E]GZG\D^EZEZC\C]D^E]F[FZFXF[IZG[E[D]C]D\D{elYgSfSdPeQePdNcLcM`N_NaNbN`MaL_K`KbJcJ_HaJaJ^H]G^F^E^E^D^E_FaF]G\G]F^J^I^J^J_H_G^E^E_G`JbJgNaI`HdL_I^H]E\E\E`H]F]E]D\E]F^G^G]F^G\F^GbHgKkPmRjPhNiPjRjOcK_KbMfLcJbKfPfSmZnXdNdMeQhUpxhdPhVm\yhiYeR_N]K_K]L]H]H[F]F^F\F]H\H\G^G[D[E]G]F\G]G]F^F[C[D]EaIaJ[I[G]F\FZE\D]C\FbJ]FZF[G\H]I\H[HZD\DYC[EZE\B\C[CYC\F[D\D[F[F\FZFYEZF\F]E]F^F]Gy|klYiUcPeQfSjSfOcP_P`ObPaLaMbN_L_LaJaJ`IaIaJ_G`HaFbG`F_G^D^CaC_F]H\F\I]I_K]J`HaG^D^F`JgNgM`H\EaHeMaG\F\E\D^E^F\C^E]D]D\D^H`I\E\D]F^H_HeLiOkQfPdMeMfNhMbJ]F_I`H_G^GaIdNfPiSdNdOo\kWkXfVv_r`revesgTaK_K_K_K^I]H]G^F]H\E]I]I]G^G\E^F^H_K^J[F]F\E]C]B^EbI`I\E\E[DZFZE\E\E^F^F[E[G\F[E\G^H\IYF\DZB[D]F]D[B]D[D\G]H\E]E]EZDYD]E]G^F`H^G\EZFywgr]mXeRgUpYlTcPbQbPcPbMcLbMaN`M^H_G`G`GaH`G`F`H^G^F^F^C^B]B_B]B[D[H\H\G]H`HbI_F\E`JkPhN`I]GcJdJ_H_H`H]G^H]H\D^F^C_C\E^G`I]F[E\F[F\FcLgNgMdLeMcMfMeLaL[F\FbJbI`H`IaIfNhPbK_MkYjYgVdUq^vk]vhgUcLeLcK`K^K\J^J]F]G`G_H^G]G^G_E_F_G^J^H\F]F]F\E\F^FaH^F\EZE[E\F]G[E\F_F[DZEZG[F[D\E_I_HZEZC\D\E]E]C[D[C[C\D]E\D^F]D\E\F_F^G[F[F]G\E\ExuugveqbfTjVhTfSeRaObNcMcLcM`M`L`I`G_E_F`HaH`D`F^H^F_F_E`E`D_E]E^F^G^G]E^F^F_G_I]G`JeNcM`J^HcJeHaJ]H]G\H_I^H\E]E^D`E_I^F`G]F\F]G]F]DdIfLcK`I_I`KcO`J`H]E]EaI`J_J^G[HcMeMdMcOgReRkZl]eVq^r_h[m\dNaKbLaK`M_L_K^I]F`H`H`G^G\E\E]F]G^F[F[G\F_G_G\E]F_G^G\E]E[E\E^E]F\F_G]E[DZG]I\H\G^E^G_G^F[D]D^F[D\D^E[C\D]E[C[D\E[F]E[D[E\E\FZF\F\E^F|}szmohUfReQgRgOgPcObLcNbN_JaI`H_H^H^H`G`F_F`GaG^F^F`EaF`F^F_F`G`G_G^F^G^E_H]H_J^J^J^H^FcGbI]H]G^G_I\F]G^F_D]EaG^G\F`I^G\G\G^H`H`JaIbI`F^E_F_J]H_G_D_EaH`J_K]G\HaLcKeMgPmUgQhXk[m\o]jWiYbPaMbKaJ`IdNaMaL_J_I_G`G`G`F\E]F]E]E^G]H[I\H^G^G^F_F_G_I]F_F\F\F\F\F^F^F[DZDZF\F\G]H^G_G`F_G]G^F^H\I\H]H^G^G`J^F\F[E]H^J[F[D]E]F\F]F]E\Dx|wiVbMgSiViUgRdOdPbOaL`GbI_H`IaK_H`H_G`G_G[E_E_E^F]G^G_F^D^E]G\H]H^J]I^G_I_H^I^G`EbF]GZH^JbK_I]G]G^I^E_E_E_F]F^G]F]I]H]G_I^I^I`H^E`F`G`G_H^F_FaHbIbK`I_G]F_HcKfOcOlVpXnZgTqco[fS`ObLbJ`JbMaLaM`L`J_GaIdK_G^G]F\E^F]F\H[I]I\G]H^I^G_G`I]G_F^H\G[E]E^E]D[CYD^G[EZE\G]G_HbF`FaH`I\I[H\HZF]F^G^G\G]H]G[F\G]E\E_I`H^E_G]I\F»yool\dSdShXsudeRcOcPbLaIbJaJbLaL`J_I_H`H`I]H^I_H^I^J_J^H]I[I\I^H]J^L\H`H_G^F^H^J_H_E]F[H\KdOaJ_H\F\E_F_F^E^F]F]F`H^J]I\H\H^G^G_H`G_G_H`H_G\E^GbIbJ`H_I`I_H`IcLcN_Nwc{excmYjSnZjSaNbM_IaKcMaL]J`K`J_GaIbJaJ`J^G^H^F]F]G[H\H\G\G]H]G_H]F[G_H_G^F\D[D]EaH\FZE\G[FZE\G]H`I`F`FeIbK\H\G_E\DZD^G\F\I]H]G]G\H^G_H_H_H^E_H]G[Gž½sci[j]eV}j}jp\jVeQcLcLcLbKaMaN`K_I_H_H_F_H`IaK^J]JaK_L^J\I^I`J_L\H\F^F`F_G^H]F\G^F^G\G\HeKcK_I`H^E`F`F`G]F^F^FaI_H_H^G_GaFbG^H_I^H]G_H_H]F]FaJ^H`G_I]G^G^I`J`J_Lq_q]mWnYjS|kkXuabNdOaM^IcLaL_KbJ`I`I`J`I`KaM_I`I_H_G^I\J\H]G]G\E\E^G_F]F_F^E^E_E\F_EdH]G\F\H^H[G[F\F^H_G_GcIeJ]I\F_D^E]D\D[D[E\F[E\E\G]H^H]G[E^F_F\EZEýüvjvmp]ybyb}ep[dNeNdNcLaLeP`K`J`J_H_I`HaI`J^H`J`K_K^J]K]K_IaH_G_F`G^G_H]I]F]F^F^G]G]GcKfNbL`I`I`H`H`G`F^E^GaIaHaHaGaG\F`F`H_I]H]I^H^I^IaJcL]I`J]I[H^H^H^JbM`Mscp]jUmYs^}k{meUn\cRfRaN_KdMaK`L`JaJ`I^H_GaH`I`J_I_JaL^I^J`I]F]E^F]F]F_F`G_H]E^F`F^F^G`I`I^H_H`I\G\F[G\G]F\FaIfJ`H]E\B`C]D\C^H\G\G\G\F]F^G\E\E\E^E]E]F^G¸pa}g{ew`s^gSbLdMdMbKdLbKaJ`I`JaN`H`IaJ^H_J`K_K`K^I^H]GaHaH_GaJ\H`J^H^I]G\E]G]F_HcKhOcL^I]H_H_HaI_H\F\F`GbG^H^G`F]G^H_J^K]H_L_L_L^J`KcL`KbM^J^I^H`I_JaMaMyhxgwgmXr]uas`fUiVeSjScMbKdLaM`M_I_IaI^G^H`J_J`KaMaK`M_IaI`G^G]E]D^F_G_F`F_H_F^G_I_H]E]F^H^I`H`I]G]H[F\E^F\FaHfJ`E]D]C]C]C^D]F]F\F\G[F\F]F\FYD[F_G[D]E`FŽxy|mwchSeNeMbLcLaM_K`LaKaLaJ`H`H^H]I_H`HbJ`HbG`G`HbIbHbH^H_H_F`I_H_GaJ^H^GbJfMeLbL_J_I_I_I_I]G[F^H^G]H^GcIaI]G\I]I^H`LaO_L\J^LaMaMcOaJ^F^G_J^LaMbNqazk{kfQr\p[yejXeTgTkTdKdLeMbKaK`L_J`G`G]J^K_J^KbNaNaK`L`JaIbK^H^E`G`G_F`G_F`I`I_J^F]E\F]G_IaI`H^F]F\D^B`E`EcIdH_E\C_E]E\D]E`D_E]D[E\F]E]D_G]F\E`G]G\E_FĺǺwjvhuchPdMdMdPaNbMaNbN`LaK`I^G]F^IaJaIaGaGbH^G_HaH_I_K^H_F_H]EcFcF_E\G`LbKcKfMaJ`I_H_H_I_I]H\I^J\G]F^H]H\G\G]G\G^JbO_N_K_K`MbMfMbJ_G^H^I_IaJaMq`l\rbgUlWnW|gkXcRgTjScJfOeOcMdNaK`JaJaG_I_K^J_IbK_JaL`K_I`IaI`H^F_G_G]G]G]E_H^I^H_F]F^G]G\I_HbHbH_F_D^B_CaGbGaF\E]C_D]D[E]F_F^D^F\F^G_G\E\D^D^F_G_F_F_HſȿŻʱ~ǿyopfOlUiSdPcPcNcOdMaKaKbL_J^J_IbIbH_FaI`I^G]G_G`H^H^G]G^H]F`EbF^E]G^H\FbIfLbKaJ_IaI`I^H^I]H^K]F\E\G[F^G\F^G]F^HaL_M_KaLbNbLeJaI^G^I`K_JaKfQ{gkZxm]lYnWoXkTgSfSiRbMhQgScOcNfN`L`JbJbJdKaIbKaK^H`JaLbKbKaJaJ_H_H^G^I\I]F]E\F\F^G^H]H]H^H_G]F`G^E]E_E`EbKbI]F^G]D\C_D^F\E\E_H`H^HZH\F]F\C`B_FaI`H]F]FǿijspºŽĻylvffQo\iVdNbNdOeNcNcNaLaJ_J_L`JbIbI_G\E]G^G]H^H`H]F]I`I`I^H_H_E`G^G`H_HcKgM`J`I^G`HaI_H_H`I]I\E\E^F_D^F^G^G^G_J`J\H^IbKbLbMcLaJ_G_G`H`JaJcLzehX}ip^r_o[lVlVgShTiScOjVl[fReOiTfQ`JdKhMeKbJeMdM`KbMbOdOcMaKaKaK`J`I^H\J_J_I]E]F^I^H^I^G_G^GZE^G_G]E^GaHcIbJ\F\F\E\C_B_E[E\FcKcL]H[K[H\D^C`C^EaH_H^I_JyñǕ~ɻxkvfWeRiTiUfRcOdPcNbLdMbM`L`M`M`MaM`KaK_J^I_H^G^G^H_I_J`HbJ^F]F^E`GaHbK_IaJdMbJ_G^D^E^FaGaGaJ^J^F^D^E_F`H_H_G^F_H^H^GaHcJaJcMeM_HaJaH`GbI`GaIdMePgScQygm^q]lXgUfReQaOl\{mdSeSiUhS_LgMiNeMcLjWgVaNn\jXcOhQaMiVhT_LaK_J_J_I^H_G]F]F^F_E`H^H]G]F]G\E[D\FaJ`H^G\F\E]F^E^B\C[D]FaJeM\HYIZGZC_D_E_EdKaM]L]MfTv÷ԯȿ¹ºskqim]q^hRfRfOeNcMaJcJdMcNaNaOaN`M`LaKbKaI_H_G_H]H_K`L_H`I^H]F`G`G_I`I_I_KcLcK`I_I]H^FbGbH_G^F_F`F_F_H`G^G]G^H^G^F`FbHaHaIbJeM`IaH`G^GaGaGaHcMdNgQdRo\iWp[gWeTcRdQaNm`|cUhXo_gS`NcMiOgObKo\|odSqczlfSs_cSkYjXbN`L_J_K`I_H^F]F]E^D`D_F^G]F^F]F\F\G`JcK^G^F\E]F\D_E^E]F]G]G`HcJ`H[I[F[D\E]D]EdKeO^LZLfQlWqYw`u¼ȹ}zvyp_eReOcKbI`HcJdJcKbLaNaMbLaKbKbKaKaIaH]H^I^I_LbJ`H]F_G^F`E`H^H_I_KbKaIbJaK_IaIaGaH`J_G^G^F]G^H^H]G]G`J_I`HbH`G_EaGbIcKcKaIbJ]FbGcJ`JcLcMdQdRbRgUxeh\fWgUfSbPk^dXy}siaQePhPfObLkUxcgVvgxifTiWbQ`P`ReQcN`NaNcM`J_I_I^F_FaG^F]F]E]F]F\GZI^IbI_H_H^F^E^F\F[D^G^H^GbJeLbK_I]G]F]F]F]IaJcL^K]JgSePgWhViRzc½°ѴphUfOdKbI_GaIbJcKcKaL`KcKcLbJcLbLaKaK^H_I`K`JbI`H_F^G^F`E_H^G^G`I_K]I]H_H^EaG`I^G_G_G`G^F\F]GaI_H^H`H_I^H`G^G^FaHaH`HbKbMbM\H_IaJbKcKcLdPhWo`iXp]p^kZgWk[eWg]ricRfRlVgPeOkWiVfVkXiVeRdR`Mykypl[`NaPbMbK`K`G`H^G]E]F]G^H^H_G]F[G]H`I^G^F]F_F_H\F[E\F\FbJhMeL`I_H_H_HaJ_H`KaK`J_J^IeSePfQePgSjTeR|ws¸ոɺnbeNfNeNcKcKdLcKcKcLbKdLcKbJcLcKaLaMaJ_J_I`HaH`I`G`HaG`I^G]H_I`K^J_I^H^H^GaI^H]F`H_G_H_I]H\F`G`J`J_I^I_I^H_I_HaJaI^H`JbLbM_J_HaIbJdJcJdOgUyih[shvfjZm\zkk^n`|w}s|iYfTjXjUgS{nl]eVo\kUcNcN`KwfqbaLcO`LdLaJaLaK^I^H_H^H]H^G_G_I]I]H]G_H^G]G_G`H`H^HZD[CbIfMdLcJ`I_IcLcL_JdMbK]GaHaGiQgQgPdQePlShUvi{ofַʿɩcOgPcObNaMbLcKbKcLcLeMdMbJbKbKbMbLbLaJaJaI_H^G`IaGaG`H_H_H_I_H_G_G^G^H`J`J^G^F_G_G_I^I^H_H`I^H]G_H`H_I`IcL`K_I_I]G^IcMfPaM_K`JcIeHgMfOeNwdukvkuuisfo`n`ysdscrgzsejYsem[hUxuhjZp\eQeMeMaKk[vn^cPdPeNcLcMaMaM_K_L_K_I^I_I_I]E`I]H_I^G]E_G^F^F_G_G^GZC\CaEdJdLdK_HbLgPbLdLiLbJ]FbGfKnXgSfPePeQiRgTcTl\p{kubm̹jZgPdOcObMbLcKdKcLaJeLbM_JbMdOkUcNaL`K`I`IaJ^G`HaHaGcHaI_H`J_I`H_I_HbI`I_I^H_G_G_I`J_G^H]G_G^G_G_GaIaJaKaK`K_L^G_H^HdLjQeN`K^IaIcIcLcLcMj{mxr{xykk^|px{mdxobhUzjvim^eRdRfOeMdKv]qZeNfNfObKbLeN`L`K_J`K_J^I_I`H^F]E_H_H_H^F]D^E_E`F`G^F\E\D]E`E`FdKeM^KePiOhOeMeL`I`IbHfKrahTdNeOgRhSfSgTgTfRlXyboZm\ƺnbs^eRgPbM`KcLdMcLcLeNbN^LbMdOlWbK`K`KaJbJdKcJ`HcKcIcKaI^HaJbJaI^FaH`I_H_J`J^G^F`I`J]F`H`I^G`HbJaH`I`K_K`I`J_I_H_I^HbKgOeOaKaIbKaJcKbJdMkSfRxqksirɽ|xsikZsem_wehTeQdObKeLmNlMgNfOcNaJbMePbO_MaLaLaM_J`I`H^G]E^G\G^E_F_E_E`G_G^F^G^F]E^F_F^EaHbI^KcObLeNfOaO^KaHaHfK|imZePePgSiTgSeShRfRgSiSp[s`suù̻wop]hUgRcNbKcKdMbLbLeMeMcLbLfPgPcLaLaKcLdJdJdJbJbJaH`HaH`H`JaJbK`H`G`H`JaL_H`I`I_I_I`IaJ`I`IbI`H_F_G`I`JaJ`H^G`G_G`HcJbKbKbKbLaLaJdMdKeMgPePrayw~j[ſœvopdpadSiUhTfRfOdMeMlMmMhMfNbMaMaNdPcNaM`MaK_J`IbIbHaH`H`I^G]F^G]E_E]E^G^G^H]G]E^F]G\DaIcK^MiUcLbMgOcLcOeNaJjQn]kWeQgShTjViTfSgSiThSgQmUq[nYs`m]xmɹſȹujiSkScObMcKcLbLdNgNfMdLcMhSgPcNcLaIbHaGaHcJcKaJaI`JaK`JbL`LbMbL`I_J`J_I^H_H_I^J`J_IaLaJaK`I_HaJbKaK`I`G`E`G_H^H`GbIaI^J`K_K^KaKaLhOgNgPdNhWhYwĹŹ|vkvdfTfUhUhSgNcJhMkMgMfOcLbKaMdMcNbMcP`LaKaIaI`HaIbI_J_I`I]G^G_G^E^G_H^F^F_F_G`J^FaJcMaNmXdMbKfMgPgQgOeQpYhVhUeRhShThUhUeReRhQgQgPgPmVlVoZo]jXo^ƾÿÛhUgRcPcMaKeLhQeNhOfLcJcMhPfOdNhOcIaFbGbJdMeMaJaKbLbKaJcJbJaJcKaIbKaL`K_L`KaK_JcKaJaJaIaI`I_GbIcK_IaJ_F_E`EcH`H^GaG`G_IbM`K`KaKaJhNeMfNfOjXxygq`ruf[~syoujjZp`gQaHbLfNcMfOdM`KbMbLcNdOdPbOcNcL`JbKbIaHbK`K`IaI`I`I`H_H^G`H`H`H_H^I_IbLbMeRlYfObIbKeOdNbMdQlTgTfSdRhSjTjThTeRhRgOgPiShRgRgQpZmZhShTkXyȰj]eTeSdPaLaLcNcNfOfLcKdOfOfQbNmSjOcJcLbKfNfNaIcJcHbIcLcKcJcLbMaL`J`LaMbKaKbLbJbIaIaHaHaIbJ`IbKbI^G`I`H^G_H`FaF`FaH^I`LcN`O`N^K_JgPcKdLcMdOvdn]iTmZrbi]Ǽ{u{}iUgQeP`NfPdLbMgOePfRcOdPdObLdNaKcJbI`JaKaJ_IaJ`I_I`KaK`G^F_HaH_H]J_IcMdPhYrffPaJaLcOdO`M_KhNhSnViSgSkShQfPfPgQfQiQhQgQgRgPhRePeQgQhVl[l^Ҹ{pk]cTbPaMbNaNfSiReNbKeNhOdP`NjPlOeJcLbNdNeMbJbIaFbGbIcKeJfKcLaLaLaMaKbMaMbKaJbJbH_G_HaHaJbMdMbJ^H^HaJ`K`J_I_G`G`J^KaN`M`OaN`M`KiPfMaKbLdMuf|omYfPmYn_oaùºبĻǼذwphTfPcOiQiOfNhRjUjVfOfPfPcMaMfPeM`I_JaL`K^H`H`J_IaKcM`J^H]G`I_H`J`LcQj^zq~iXeNcLcNeM`K^KiQjWu\jSiTmTjQfOdOiRhRgQhPfQhSgPgOfNeMfOfSm[wck\szlm_la`LdQdPnVkQeOcMjQoUhQbNfMjOdKbJaLbMdMaKbJbHaHdKdKeKfLbJbLbLbLdMaLbLdKcLcJbHaHaIbIaIaKdKcJ`KaJaL`NaKaK`J`J`LbLbM_M`Km[gUaNgNeM`KdLdMpcymqb`Nzeqn^{Źרĵ}xǶud|qo^iTpZgPlPiOdMiTlZiUgPgPcNdPdPdQcPaKdMbO_N_J]G^H`I`IbM`M^L]JaL_I`J`NsgxqbbP`LbLdN_KaLcPlXpZhSlVlViQgReRhRhRjUjShQfOgOhPfOfNfNhRlXjXmXlUn[sbr`m[xn`NePfShQeOePcKkRx^iRaMdMhOcKbKcKbLeNbKbIcLbJcLbMaKbK`KcMcMdMdMbMdMdMeMdKbIaJbLaMaLaJbJcLbLaLaK`KcKcKbLaN_McNePbOcPhUfPaKuel^_IcMcLiVp`iXiUvaor`m^ǵxozhq_q`s_r]lZ}lnZhRhUjUhPiPeMbLgSmYgRpXpYfPfQlZeRbOePgSeSaOcNaJ`IcK_I`N_M_MbOaL_KaLcLgSzoem_aPaLhQbMcRylp`ufSkVjTjUiTiRgQhSqm[gPfPhPhPeRgQgOiQlUlViSiUiWhThSfQq`m^cNeOkTfRbMeNbLjRs[fPbJcKeLaJaLbMbNfMdJeLdLcKbLcMaJ`H_IcLfLfMdNkWePfOiMfLeKdLcN`LaLbKbLdMaK`LaNcLdLeLbKaMbMbNeOiUmZ`MbN`Jm\k\^KdOfMnXubhVq]}isdsbq`p_zjzqao]wfwdzaoYkUmXhTeSeQePfOdMcMdMeNmVlVxas\pWhQn[fUeU|kn\eQcQaNcLdLaJaJbN`NbObObNbOgShQaNzlsk}ndiWeRbLfNeNdT{sdhWgTfSp_lVhPiRlWq^lWhReQfOgPeQfRgQhRiRjRgSdSdTfUeRdQePePcNdOfPkWq\eNfLiPnThPcKbKdKeMcKaJaLgLdJeJdKbKcMdLbK`I`JcMeMdNdNnYfQfNiNhNcNdNePcNbLdMdNbLbNaNaNbKcJdLdMcNdMdOaKmYk]eVeR`KcMcObPdQfPq_xdr_cOwdviylsejY|jyqrazgl|gwapWv[q\gVhWfTlTgPcLeMeKfNnUo[xin\lUrdxm^hWxpcdPcPbOcLfMcJaJcNcNdOaMcMjQkVfQdRvdresibSdRaNbLcMcKfSxxdfXgThUuao[lVlVjUoZn]fSgQgQfOgQgSfSiUiRfPfRgSdScRdRdSeRcPbOcNeNnY|fdNdMiOlPgMcKcJcKgLdJaKdLhLcIcIbI`K`LdLeLbIbIaKbLdMdNcNdNfNgMeM`LbOcNdOdNcNfNdMbOaO_NaLaKbLdNcMbNdOm_vpm^kZaOyehTeRdQcOn[rbvbePl[ymm_v{k{oyk}ro[va|udjViXlYfQfOeMfLfNoVrb{ocNymbl]wmbNdOcPcMgNfNbLcOdNcObNcLhP|kiYcQj[z{cVhWbObMdM`IjWsjXzkk`iVjUr_ud~mnZfSqdj]iShQhPhPkThSjTgReOdQeQdPdSeRhThSdPcNdMdNiSpYbNeOiOhKeLbKcJdJdKcKcKbNeKdJdKcJ`J_JeLiLdJcJeLbLbLfNfNbKeKeKgNcNdOeMcMbLbOdPeNbNbObOcNdNbLdNcMgOaN֕{o`gUiUn[aPcMeSwmwp|leRhX{~vg{uq]maykzudrdyieQiRiPhMgMjTyjŸ{pbNzng]repffSgSgQdMiQkTfQcOaMbLbM`MgOuam\iWnbxkqeiScK^IhSverbzgVkVoYvbkXn_~ug_ɼ{vfUkSkRgPjRjTiW}klXeQdPePfRfRiRkTiSeOdNeNfNeNdMdMfMeKdKbMbKaHbJcLcKaKdLeLeLeLaJaIfMdMcKdKaMbNbNcMeMdLaLaLhRhQfOfP`KaKdNcNdMcOcPcPcOeNeMeNcNfSaOȟ{hWq^fSdVse\~}nxhgUi[}oqn`}qyxzin^wsscxykzl|ozjdQjVjQiOhPdNuexfhVylmdvksijWp]kTeOdPjUjScNaN`NbLaNePfOcPhXk]k^|n~u|vl[aLaNdS~u}kekWlVn[fTwoeZǻľkajUiRhQiRiTjYrragUfQePfPfRhTiRjRhOeNeLfNeOcNdNfLeLcLcNcKbJbKbLcMaKaKbLbLaI`JbKdLbMcLaK`KdMdMdLbMbNaLaKbKdLfNdNbLaLcNdNbLbMbNbPcNdMeNeNdMdPcPiX{i[}liUjZlfôzmsek\k^ub}ip_r_n|lzgdYrkǻr~g[xfxhuisvffShXiTfRfQdNkZ}jn\shy{hTkVhRfQfTkZhSbNaQ`PaO`NbPdPbOdSl\iZm^pc~iWgUk\īvo~sxjvngZΕ~ykYkTjSiSiTjWr_sbhWgRfPePeReSgQhQhPfMeLfNeMeNeOeLdLdLdMcKbKcLePbMaLcOdNbLbJaJcLeMdMfOcLbMcOePfNdKdLcMaKaIaIaJbMdLdMeMdMbKcMcNdNdMdMeMfMeMeMcNiUvdvgymgVq^gReS}}}rk_j^zwp_}ikWu_mra|pgsi{o}wji`zwln_cTvhrfdSfSgZylsdsmȽ­ſ{siWnXp]n]gUfScRdRcN`ObPbNcOeRl[pacSk\wugjXlZiUp]j\תگwrûk^mVjSiUiViUjXl[iUhQhPgPgSgTgPgOfNhOiOfPhPfPdPfNeMcKcKdLbNbNePcNaMbPfQcMbKbKeMdMcMeNcNbMaKfMeLcLfMdLbMbKaJaK`LbKcKbKbNbNbMdMcLbMdMeMcLcMeNeNeQdPgTgUeRjTgPeS{r{vwok\kYjWr\~l{l_k[yjzg}kyzobxihXwirecVfWvqvkrd}wɷۮhXlZ}jsbm\p^iTeRjZuajXcSbQdSp`o`eVfWxekWfPgRcPfScT½ŹĽýĸƭmdrdkTmWlVjUhUiUhShPhQgRhRhPfPeOgPmTiRkUhRfReOfNfLeKdLbMcObMbNbMdNiSbLbKcKeLdMbL`KbLaLbKgLdIfMiQfOcPbLbKaKbKcJaJaKdNcMbLcMaKaMdNeMdMfNfMcOdQdQfRePeQlYq_jZ~sx|umk^o^mYvboypbl_vcr`m[{j¶ĺpe|nqek]obuhcZvyqʖ{yqdsfzsqewm[eRwh}pbwa_NymgVhVeUmZjWdQdQdPeTdRα{ufiUlXkUkViUhPhPhOgPjQgReOfPmUmVmWiTgSfRfOeMeMcLbMcLdMdPcPdPfOeLbLbLiOhMdJcKdLcLdMgKfKgNiQhQcNbLcMcMdLdLbLbKeLeMdMcNcK`LbNbLeMdLcLbOcOcPdQdQeQiUp^p\r^}}xsgn`yjm[l]papfshp`o^jXziwflWr_z|~ujl^ue|mqyjZuewk{yyivim~pwvvnjXiTmZ}sweYhThVfVuegWbPeQdPeSfTǾǿʶupm`lXkUkViVhSiPhQiRgQdPdRfTkVlTnYmYgQfQfOdNcMdLdLeNdNdNdOdNeMeLcKjPiMgKdLcKdMeMfKgNdMgPjUcMdNeLdLfLgKbKdLdLcMeOdNeNcM`KaKcKaJbMdLbMdOdPdPfQhPePhRfRrvqezopfngmck\m\gVjXgUjWs_ps|uvqbkZn]mauf{lykzuk^kZhVnXlUiVlZxfrm_sdl]}km]mgfTkXeXuj\aPfRfTlZiUriyҬŸ׽uqmal[kZgUgUiTiRiShSfSfUjSjRrZr[gRfQfPeQePeMgMfNbMdNfQcObKeKgKeNeMgMcL`IeLeLfKgLeMfQiTbPiRgOcKfLeMbKeMfNbLbMdMeKdKdKcJbLcLgMdLdMdMbNdOePdQeQePfQiWiXx~v|Ƨy~yuøyuzniXiXgVdTiVub|v®ίwlo]ub|kv~qξjYjTlVgTfPfQcOfPeOkXwdmbʿwowqŻdRiX}mqpafUiWgV}uj~sud¸Ь׾|~mgj\jZhXjWgRhRiShTgTiShTiUmWjTiQgQfQiQhQiOfJeKdMfNeMaLeMdNcNcNfNcLaIgMcLdKeKaKfOfOcNgNgNcKdLeOcLgOhOdLcJeLdLbIcIcJdKgNfKcKcMcNcMdLdNcPcOdOeOfScSmYykvyn{}ž|xsggS}mschRkWj\}~vsa~gsji¹ylZmXlVhQgQfRdOdOdOdNiXsipfqhiWsanrgpbkYznhl^{jvҝpnlak[k[jWhThThVhUgQgQiUnYfRhQgReRhShPgMfKeNdMeNfOcMdOcPcNcOcNbLeMmTdMcJeKdKfKeMcLdMcMbMdMdMdLgNhPgNfOeMcKbJdJcIdJeJbKbKbOdPeLcJcMdNcObNfNePdPeSgUhYkZpc{lzl}sui}nbwij[ja{ww|sym~v|qxdj}gyc{dza}cj}hrs`p[pZjUgRjReNdNeOeMeQq_q|jiZvjzj|iwdiXhXf[ùeYyfzjߵÿǾǦd[g\k\kXjUjTjUhRhQhSgRfPhRfRdRkVkShPgOfPeNfPfPeMeOcOdQdRcOcMeNiPeNcLeMfMeKhLdMcObOePhQbLcLeLhPfNeLdMbKaJdIcHcJeKdM`OdNhNdKcKdJcLdPfOeMeNdNeRdRdUhWjUgPp]|jr_{l{uf]ؿǹukmybn\p_zf|fzdze}f|fyf}ewuav^ybq\xbo[bPdPfPfNfMcKcNhSeQovfygxd|gp^jZn`xyyhjVziucӳļϽǜi_kXkUkUjSiShShTgQgSeRjRkRhOhOhPgPePgPdMdNePdPcQfSePbNdQePeOdMeLeKeLeLbMbMcNcPdObMcMcLfNfNeLdLbLbMdMdKcKeMfOeOfNhMcKdLfNcMdMfMdMsbfUcOeRcRpak\cOkViWiWm\o^}{xxɸrybq[u^u_gXm\ze{gwaq^krqv^y`x`{bgp\bReQiQgOfMfNdNcMdPaLeOiSiQmWp[gVp_vgvm^iWnVmUqygueʍyxự|xn`kVjSlXiTgRhShTgQmV{hr`fPmUmVhQiPeOdPfQeNdPdNdNeQdQcQdQdOgNiLfJfLdObObOdRcQbMcLbKfNgNcMaLcKeMdLdKdLgNdNdPeMhNdMdOePcMeOeNdMlZfSdNcQbQm]gWcPfRgTdRfUm\l\{kzvkĿûvp`s^q]m]ub{gunu^wz||hj}ew`s\w]y^{_v[mTeSgSfPeNfOdNeOdQdQeOdNePfRePgSo\q`}nrl\pUlSwrfż½ۛû»ƿÙqjk_iWkXjUlWhShQgQsbxekVv`rZkQhNfPePhSiPeOdNeNfReRgRcQbOePeOfMiMeNcObOdPeRdOdM`KeNhObL_MbKeLfLgMdMcNdMbLdPjUcMcNdObMbNdQdNcLdNcMcObOxgk\aOcQfTfSgUmZhSfQkXm\k[|n|pʽvzg}nxg}gqn}e~fr`r_q^v_v\s[kTqYwZw[u\pYgRnXnXiUkWeQdQfTdQeQdRbQcPdRgRgQhSm\~noenVkT~k^¸ԿզüĹέnckXlWlWiRiQeOhUnXu]w_mTjSiQgQjShPfMfLgNgPfRgRcQdPePaPeMeLbLcLdLaMcOdMdOaLfPiTdNaPaMdMdNeNdMbOcNaLeSq_cOcMdMcMdOdOePfPcObMdNbN~uugbOeSfRcNfOjVfQhTjVfViYm[udym~Ÿĸ~nvdn\ycx`|b}b{azc|j}mo~hrWgQiRnTrXrWnUfPoXr\kWkWkWjTiTeNhPhTbPbQcOdOdOePcNygugpYo[{hyeq`zü޻خӴǽ½ķΙxrulgWkUiTiTgUgVo\{cmUlViSiRkSjRgNiPgNfOgQfQeQeRdSbQeNdLdLfNeMcNcNdNdPcMeOiTfOdOcLdNcNdNcNcNaMaMbMeObNcNeOcOeOdMdOdNcMbNdNcNp`lZbNfPgQdNgOhRfPfQfTwo`kWkWjWlXo]u~vj{|ygn\uaxc}g~d}chrzizi~goXhQlRhPqXuXmRgPoVp[gSiSnVmVhReNlToZhTgTcPfNfOfPcQhUjUr]mYq_p]vj~nnöʺݸع⼶ſ˽objViUlWiXhWjWkVlUiRjQpViQfPlUjSgQfQfRfSeRdQbOdPeMdKcNdNcMfPeQgQcObNgPfPeNhPfPcPiShRfPdObMbLbLcLbMeNdMcMcMbNcNdPdOgPeNgNfNgRjUhQfOfMiRiTeMeQwhkVkWhSgSlXn]|jwhu}nr{jsam\ygk{gzlir_p]v`fWiRmThQqXwYrUhQnUqZfShTmVkSgOfNlShSs`pZgPdPfPiQdPcPdPpZlXwinb|xfྐྵھɿƻüۛ{vl\nXkXhWhUiSiRkRoUmThRnVlTgQhRhQhRhQdPdReSdMdMbMcNfPdOcMfNfPhUlWeRfQlTkUbRqm^vcfScLdMdNdOcOcMfOcNcNcPcQeQcPbOeNlRhPp]mYdMhQeMlVyhcNgQq`kXiUjThUeRgThVhWhYq`vezncvcxfo]{kyiuvcq^r^q_fVhShPoTrVoUsXmUjTmVjVhRlSiQhPgNiQgSkWs_zemWgQkUeQcPcOnYl[slɋldֵÿܽύupqaoZkWkVjUiViTkTjSoXs\hSdOkQhOfPgPfQeSfReOeNcMcMeOdNdMdLfNgPjUePePiRnWdUqewffVcQcNbLcOaMcLeOeOdMbNaOcOdPeQfNhNfLhOhPgNhOjRfPnYgRcPp`seTfTjVhSgVgUgTgViV|fh|qcx}qr}u{n~ygr`vcpbkWmXlWvWsWpYrZhSfRlWs^mYmTjRkTfQgQjUePwepkUjSgTdOcPcPq\l]Љha̸ɾḱsjjYk^gXiYjWhRfQfRoXqYhQfQmTgPgQfOgPhPiPkQfNcMdNdNdOcMeMfNdMcMdNdPfRgSiYujxjiZdOePeQbP_McOcOcOeOeOdOaNdPoWfLeJfJfKfMdLlXwdfPjSkT_NwgysaPzfk\cTeTeSfRoXmXrn}zqamXw[w[s[nXeQjWlYre~sjUmYsafQhSdSmdmam\hWhUhVfSoXn^}}ja߽ƾüƿ䩟½}hWlYhSgQgQiQiRkTu]kSiRfQgPiOlPnQiQgRgQgPdNeMgNfNeMeNcOfQiUcMfSsdkZ~liXePePfScOcPeObPaRcOcPdPcOfPkQfLcJeLhNfNbKo\xdlWgReRbNs]{hxj_PrkZbPeSfTeTfQgRnj]wżŶxl}iz|vu_u_rZu`j_cUl[wmzmylkdw}i\obl]jWkW{jn`h_ſƿº˾軴ǻk^n]mZjThQgPfSgSs_lWgQfOeNgPjQjQfOiQgPhOfNiQiOfNfOfPfPiUo[dNfOgMhOfQfPeQbPgQcOjRiQeRdNaObObMdNgOjPgNdMbNhPhOePfSfQhRdQbPcNgOgQgSmWdTsckWcPdQfRfRfQePrbzaQ}oȸz~nvjvv|j|gq^p`zlfh[˼̕xowfvwv~|r|jaxjlWoY{f}jiXf]¼毞̌kcp\p]jWiUiUfRgSiRhSgSeOeMgNkOnTjRjRfOgOgSpYmSeNfReOfOjSoYgQfOjRfNfOgOfOcOcNeNgPcOeQdNeNgPbNbNiPlSeNdNdPeOdOeRbPdQhTdQcOcLcLeOiShUdSkVgRcQdOcPeSdQeRgTfRfTiVp\o`wisezȿÜzox{ylߓvql]rm_n{vgp\wug{mqgykulufqZq[lWmVwdxfk^߸ǿޥk]o]jXjXiVrem_hSiTgOgPeNdNgPmVnWlTiPgOgRlUmUgQfQdQhRgRrYlShSiThOhPjPhPdOcMgQfQeOeMcKfMiOfOdMjSjTdMdOfPdMaNbNaOeUkZfTdQdNeMePgTdQcOkWfQdPePdPeRfRgSeQhTfSgTgSgSlTnXp^zukʿǾyhs~ul]hYwil[rbq~o~oq_sdi[uk{|pvh|nrqvd}jvckUnUnVpYj\¶뺭k`m\jZgWgVxi[n\jXgReNfOeQiTjVlTkSjTjWhUmUkSjRePeOeOgQgQgSgSgRhPhNfOeOgNfPgPhPeNeMfLeNfObLv`o\cOePdMbLcMcOlYlXuaeQdNcNdNeRgTragWp_gWdQfQgRfRhRjSgQgRfSfTfUgShQgQgPgShWiYiYnancg^piphjXhSiUmZi[|ohgYrd{{rwo~mg}r|q{n|npanyglTnUnVpZmbҫuen_l[iYn[rdpfucpa{ksaeMfPfPgSfTgSnWnZhRxau]mTfOgPfOdMcOhSlViUgPjQjReNgPiSiRgNfOgPfOeNfPaNvrd`NdPeMcLdMcPkXjUnZePeOcOdPeRiSpZgTfTeSdPdQgQgOhRfRcOfQeOfQgSgSfRgReNp[{jkZq]iWfVnbvouijXlXp\}k~oưžuz{ry}oymmVnWnUnToWoYui˽Է̟qbn[kYlZp\ocriubp[zfwdhPjSq^hYdSfTgShSgPnXoXjQfNhRgQeOePiRmWiSePlUmUgQjTqYqYgNgMhPeNdNePcP}ml\bPcPePdNbLcPdPhRfSePePbNdPeQeSeRgQbMbOcNcNfPeOeQfRdOdOeNiQfPfPgPiQfMjQlVjSlVlXfU|n~omWhTiUl}is˰zryo}rqc{noVnUmUoVqZu^xjĶĺrgq\oYlZnZrfƹ|kZr]oXqYnWlk_iVnZkViWgRePfQgQhRhShRfPiRmWnXiTkVjUiUmUuYqYiRjRjRiRgSfQfRiSeReRbObMfNgPeQdPiUiTbMdMcLeMeMcMdOgOdMcNcNdNgPcNcOgOfPcOdMgPfQfPgOhOeKgLgOgNhNgPgQw`lu^nVfRkTv[r]l~dnZmZs~q~}|qcqe~rviyjl\nWmVlUnXu`zf|nƿϖyqr]r\r]mZxjטzubr\pYnYrZ|xm}pnziYfOdNeOeQjV{jiVlUmYpZpYiVjVnVqXrXmTjTnWoXiSeOiQoUgQePdNbMdMilXbOiVn\dOcMdPdPcLcLfMhNeNfOeMgPhQeNeNiOfNbMcOdNhQiShPkSeNfNlRhOeMeNgRnVsYuXrXiTnVpWmTsZ|aw_mWp[q^o_kYiVm]rn[kXwcygl]l\ram[nVmUnWlVonp`ƽȘ{rsexcwcq^kzһj[pZmWs^r\vf|l}gl]hRgQfSeRfU}mjYhSs^pq\gQjTkUoZp[nVjRlTlSjRfOiQoVgQfPgPdLeNs]jWeQgUp`fSePdOdQdNeLdMhNgOePgOiPgOdNeNiPgOeNdNeMlUoWnToUgOiPmUlTiThVkWlWw^z^oVmWlUgOjRrZ{ar[mXxau`s`pZkTfSkWiTeRp\r^hUhTkXnZpYpXnWnV{bybs^Ļհynrar[z`uɿǻn_mVmXq]q^ncjXvau`q[vbyhiTgRfVeUdQiRhRr[ljVfOiQiT{nZiR{fmWgPgQoZpYkThRr\eOdNlWhSgRePiUmYePePiQgPeMdMdMdOcNfNiOiPeNeMhOkQkPeNgOmWnWrVuWjQfPhRp[r^p[sZpXw_v\iUpYlUbMiQpYs\s\r[zbyayapZlVkTkTgPfPmXu_fRfQgTeSqZpZnYoWnVw^s^趪~pmWw`pǿm]kTmXo\p`}gWq^p^s_wf|}vk[kWhUhSgRfQjTjSiPgPfOfPl{ggRdP}r^bLkXranTiVhXdNo[r^hTeOiWylkWgOkRfPcMfNeOdQcNgOiQiPfOgOfNhOiOeLeNlWoYnVoVhRiSiUkUs[u[x^u]w_mWlTrYjSdNgQoWnWu^u_{c|d{dpYnVoWnUfOfOfPoWfQdQdRfRs\q[x^rYo\k|jĶžĿúúݵxnVn|folXmTlXlVmZ}nsfveymucp_k_ļrmqdnYlUgTgQhSkTjQhQfPeOeMgOeNePgQePdPgTzhjUfMhQ}khSfOlUxdhVdOqfiVmRpWeMeMmYn\eQcNlZq]iNfPhOfNfNhMfMeQlXlWiWlWnZu^p]dOjSpXya|d{dq[gOmTmVjRjToYkTqZ{c}gjzgmWmUrZmUhPfNfNgOgPePdOdOv^sZy]pYp\|ixŸùŹƿŮ~usqZvr]qYu[v]nRnRnVlTkRr\kjTşpbj`ݪpbmWjWhSiRkSkShReOdNePgPfOdPePdOdReQeMePdNeKdJgNiQgQePdRcNn^sePgOkRdMdN|l~ro^eSk]sfhQhPkQjRdLfNo\jWmYqYmXlYs]|e}ieQjSrZ|dmszdiQlVw^rZmUkUjShTr]}gi{fkVlUu\oXoXgPjRgOgMgNdNcNoYpZq\o[oZvõǾǼΰzmo^o^nWnWnTlQlRmUkTkRlTpYfQszi]ޞhZnXlTkTkSkSkTq^kWhSeQgQfPnZo\ePiTkTgOfNeMgOhPgQgRiTfTdPeOdJeMbLdLeNdMmYrap]cRwkfQgPhQjSfOdNs`zgjWoWrZp\mZgUnVjQro`p\xbv^lVs^lWiSmWyc}g~fnYgTkUrZv_iUlUkTgOhOdMdNq\r\o\oYp^Ļúлû}sl}qiRmUlTkSmSoTlRkQkSkViXomk\mӜiYmWlTiSiQyfrur_ePjVnXzcwbiTlTjSgOiPgOhOlTlVeQzeu`eNeQfQfPdNbMdOgReOdMdOeQgSlYhScMras_dPcQxer_eOgQoZscaRr]lWeRzkol\m[r_valXyevxoergvb}eqZjUu]v^u_nYs]nXfPeNdNbMw_q]m[o\sežƻĸʼɿɾȻɿӪƙ|rkTpVmUkSnVv]nVlSkTlWlYq{fpj^q_̍qemWkVkThQ~m}lq`p`hSkVw^|cwaoXpWjSjQoXpYkSmVr[jVyvhUqbk\fSeOgSgRgQgPgRgShRePePfOePgQhQfReSgReNeNgNiXvqo]nZdS{xjjYgViVjVkUhTpcϙyyfsm]v`yaq[lXo\kXgQfQfPeN}r`p\qcƾȾ·ǿѱzmSoVnUnVu\u`kTkSmVnXn[xbr^qfȽ{wi[ޚkVnWmVkVlWjVkWlYjUiUoXkqvcrXnTnWv^x`oXmV{bp\vwvc~mmnZoXx]v^jSdO{jwfhSkTiSgQfRgRjRjSfRfQePfPhOiWȷj\{kaVuljVr_ncqgo^fUmeȼþj]~mwgwelWoYwaqmZeShSjSiRqfpa{ƿǾļƫn]oVmUmWq_ygs^gQjToXq[~jq]jW}uj[}mĸ֯hUoYlXkXlXiVkWlUmVkVjRyd||o]p[zazaqZnX~fp[r~k{hkm|cw_v]oWjSeSxvkVlUiSjSgTfSkToUiRfRdQfQjSjRn[m[xjrgzi|f\ŵӝulaɛiY}h[gVqczieRiW|in`eUhUgSfR{yɿɿǻǾŽԵxlmWnWo\|lmVjUnUnWso]jXlsak\s_¯pcs`k[hWjWiViUiTlUlTjRoXr\oramX{bx^lUo[qudq}~oybi|by]pZiTjUjV{kwo[nWiUpXq[kVoWu_o[o\jXp]pZiQnVqZgTfTfUeTjZyjȴogfZĆofdTk[udgUm\wp`iWjYjYiUeQȯĶʿÿǿɿǾ˜upk]mZrbrwbnVmVoWs^u`mXz`s]n\o^ĸÜ{~mmZiVkVkUkUiSoVpViQlQnTnWkV|flWoZpZiSvb}oakr{h{eg}cz`lUiRjTkVu`wcnZnYn[o\r\nXxdyeqaxi{i|gx`oXv\~a}dn`k`mahXhVrjg\fTlZl^rb}j\ðſsewx|piVlWkXgSɿǼʾʿɿʽĻϳh[rc~omVkWmVq\wdww`w\z^x^oYjYü~w{jq_kWlVmTmViUpWpVkPjQkRjRp]kmZjWkWiTuaygjzdxblVjSjTlWw_x_oXpYr\xdxepa{luƹx}q{kq_s]w^nolĽl]r\p^jZl\hWr]qXjY÷˼xrǽگlgeYkahYʿɿǽǼɿȽȿɾʞ~{m^|kZiXoZgs`v_x_w^y\w]lUiTpý¹}oq\oZkUlTmUmUlTlUmUrYlSkSlSqa~n_lXiWjVn]uzfvaxapZlTiTnWu_s`p]v_~ly|svwoyqŹpfo[r_ľ̓wnw`{em]o`zuxbqfҹ}xóϪ̚ƽ¾½ȿɿɾȼʽ˿ŷ´ĸաqdzop\jWv_~es^r\w^oYpYrZmUkTr_Ž{or]lTnWnZjTmTlTmUlTr^lWqZs^nbjYjWkV{nzrxdv]ybp\kVkUoZwusj{w~s|koauxgȹ׿П̛k[|ukɪumޫun|uūǾȿȿɽƾƻȿȿǾ˾ɺʷƳȻȾɺɼǼŹȾƽǽǹö÷ǽҥwnyinZkXq\v_s\u[v]nYpZq[nVjSsaĻumr^lWq[s]lUqXkUjTkTkSkVs_q^pdnbuefW|ѹwj}l~hrZs]uq`p[n^{躷|jWu`pave{Ś|ѱh\{wժᤙbRiZg[l`zoɿȿȽĸĸǼɾƼƽʽʿɷƴðïƷ˾ʼɹĴ÷ĸŹȾƺ¬ĮŵƼɿίxsjYmZkXkVmUnVmXmXu]v^s\lWs`ymp[oWrZ{fr[mViRjTr`o_o\wfxlĵ¶lb{Н~kXm[oZoZx|jn\odʺmfæk^wakVmZoZ~ip_}pw{ʰrj{~wװp_ul\lWp\ɿƼƻôĶƿ¿ɾɾǽɾɼɻɽ˾ƶñƱĮŵij¬sĿǻʿƵwpoqmjóȾİøndmZnZkViUiSjSjTwau^nXp\zdqŹq\lSq[zfpVmUlSm]}fXl^sڻ޶i[p_n[nVmXkWn[k[qhijqlðžǽsgk]m\nYlTlVlVmWiYwsb|kyoǼɽyqxg~kƺ۴}op`wgs]o\ŹĶĸƽʿɾɾɾȼɻ˽ʽɾǽɿĶ~{vmmɼŷȼǷplligghhjil|zИ|wkYp\kVlUkTjTjTlWlVjQmUs^{fǿźlXjRpYxamTmUkU}qПfW|iucvdѨh_qbn\lXkXmYm[kZvnȝۛxnyh~osbmZrbnYlVmXk\xhq^lp_ʾvreqd·¶Ե೥yjnZrv`oZöɽɾɿɾɼʾǼƺƸǶulkklmlkjjmnkklkhhhigfijijlovyvv̹ȻskpbsflXlUlUkUkTlSlSlWnWrZy÷ƺhUiSkUgu_iWkWqc˯fTgTykn\ܚngukqen[o\p^rh୤uhdVk]r_na{luko_mVmWo]wixdolYl\³i]ǽŪkWw~mpZp[ǻʿȿƼƽǼǽƿƿɿǻƹƵƳǰikkllkjijjjryslllkijiffghgeehjjijiijmki¨{p`r\lWmVmVkUiUlVq[wekVjUlWzcvap\lYlY~qjWeSǹ~siY||uݭiXp]{hzg~k_qfxjygrf{l_pclZxjoak\lYiY|woZxar_k]ůg]кǷ°ızm]yuclVmXȿĸúþĺƽǾǽƽƼƼźŶųĮĩ{ljijjkkiihgghijihjihhhgfhhefgghhjijiiijj|n´vgzcjWq\p\kSjToVy\z~jw`lWlUmWr\r]s\n[nYu\sYmYmWw`xe~m]wm࿻䰣|jnYoXzc~hwcue}n}wcmaygn^lXoXrYmXkZkXkXyg|kkaϱkbɹĸºο~v{k{s`mVkWɽȼĹ÷ȾǼȾȿɾƻŽŽǼƽŻƺĶųînjhilijjhggfghggffiheffgggfffghhhiiiggfhi~jobu{n~jqXnVnVwZm}mjoYjVhUnXoXr[pYkSrYrZkUkUqYlW|sjypĻþr[oWmWr\xdwczf~z~lmcv|lo\rZw\oYmZjW}l]zgxisið{ucƿ}ñv~porq~lxe~ku]s^l[ŷŷµŻŹŹǼƸóƻŹƸƷŶijñij|nljhhjghihhhghjiffgggeeghigfeggghhhfffdfhggiv}scyhĴ{r]pWnUv\u}kjp\lViWjWlVu]pWjSnWuZnYnZpZjTwhĿϾϿ~ioVnWpZqZu`yd~gvpmmxkvgqzhpY|au^r^nZy}osvsi¿ùuqrbn]i{dwdvdzgku]{hqaŸĵŹŻöŸ±ƺźŵŸŶ±nikigffhijijiijjihfhhhgeehghffedehggddddegfgjijvdp_~i|joYmVxavz~ilqp]kVjUmWv]pWlSkTqXu[w]rZkVyeʮ}hrm|cpYmVjmn\gf|grnmmnsmwgzlxgoZyakqyg}xžпĹyop[q]o{f{gxcn}kq\}e{e´µŶijĵ´±ƻǻ°ljjighhhhjjjiiiijjjjfefdfgfigeeeghgg~fddgefgijgj{gvdhf}q_o\q\ijjghxiUlVq[qZqXlTlUkUnWu\nWoY{fȺx`fg}eqYmWxbxdubfyaxcq}gh{filnpuxfo\pa|uwl{ú׹Ĵug{foXybvs`waq_r~o_p]waï°Ŷƺ¬rkkjigggeefihfggghiijfefdegihhfedffeeffhgfghhiihk{gik~hp^~l\ljhgfh[u]u^pYqZmSkSq[p]nZ|lrdl\zƼz`e~drZqZmXu`~e|c}ev\s\h{dxar\|dkprg}v¿{v®ϭzrgxexcv^{fs]wbn\}k|ramXp\ĶŹŸ}wjkjiigfggfhhhfeehhhhfdffdehjiihffghfeeeggffghjjih~g{dhiq]npdzolfd~p}i{dxaw]lQlSnWnYm[}ݵffs^n[o\jYzwx`nw^mVkgs_p^xϐuoŶ򵪫۹zzػö}|uhvf~ju^ydwa{fr`~lx}mp[nWŹƺõõnklkjighhhghhgghiihghhfefdghghhhffeffefffhfeefhih~ggz`|bgzbvbwg|qrmhewzhyaix^mTpVuZmYq`|ƽvav]oZs_yap{yfwwcusùҟ⽷ƹº»z­{wfpzgm|gxb|d{f|iqubr^źķ±Ȼŷillihggjihhigfghghfgghggedhfehhggffghffhhhgggghee~ddeezbvas_m\}uȹhfzr_u]~f|cs[rZw`zdvayƼĺ|l]q^q\|gp¨{~pŸҾĹѼżۭ»ܺ}~qj}gh~f}ivsbq¸ú·óƸ°qhikighhhhiigfgghhgeffgggffeddhhghgffhhhhhffhhffededd}fu`r]mWlYueƶ~ggusr^zcxa|d|cycxcwqhȾzsbr`}nw{gug̤ĽŽ¿Ǿïózkpqmmo÷µö³´°lkkjjkjiihhhhfdeghigfgffgffggffgegigffghjihffhhedcdeef}ezb{bpZr\ycq_{o»loqlzbsan[r[r\s_}cwd¸ƼǺŷ}pa}vf|ˮ⿷ȺϺʿǾϼźnjrqun}õsiiijkkjihiiigecdgghhgfedfhgfggggeefgggghhhgghggffcegfhhggxaybg}gzf~ohh~e{dlWoYmYn[xeĻͱy~xl껵ɨyuݺᾷżŰŹɯĻ}kq`xfzg}xw°Żùpjjjjjkjhiijjhgeghggffeeghfefgedfeeefggghhggggggdfdcfhiihf}f}egeeyzemWndop_o[o]n[zlƶľ}~uqezxгƽųżö篠~jvgsd~k|{~pñ±okjiijihhiijkihgiihheedehfedeeddegffeghgggfffffecggffhhijhfff{_~ahr_oZr~exjmYp]u`qƹ~෰ŽóŶǻİŻzl۰ryui{kƴmmkihghihghijhgiijhgeddefeefggeddeddfgeefffhgeedejjhhffhjhf}ed}a~a|^pYmVvr|e}¾iXo]n\zg|zu{Ķɞξ´~­δvhט{w}wzªxmkjghhhigfiiihihghgfebddeedgigfhedddggghfeghhecfhikghhgghg}e}efhgeqZjTjxonY|iufwk\wxȽĽ̿ʺռ±}ĮµљzyĸŸvrkkjggghhgefggfgeeghedddcdhgghggheedcfhggefgggedfkjigghihhhg~ffgh{coVnXjVmYu^o[p_|zz}ĵÿɿ˿˾ʽʽıvy¨ʻʽ¿ӽǾҿzliihihihgfffffgffggecegedfggegggfeedefhgffeeybffhhhjkgggfiihg~h~ggix`sZxawas^o[werźӭ~ǿȽȾɿɿɼʼʽ̾{xxxv˻ȿŻ־¹νөskĴ{ihhhjjihfeeghihggigefffdecdgeegddeeceeefeedcfgfhiikjfffgihfge~fgg|d|d}efxas`ygŷĺ־Ư¿ȽȽȾǽȼǻȻȻȼ­{xxxyzxǺ~ĽȾü̾ќ~ʺhhghiljgeefijjigghhfdeefecddggde~gfdddfffgefdd~aefhjjiifcegfffedeff~e|d|d}gwevanȷ̽ǻķ̾ɿʿʽŷǸɼȺȺƹǹȷƶƸź¯}zxxxxy{ȹ~ļԽǮjiijkkiggeegiiiiffigfeeeecbdggfhfffdfeefgededz]~aghjiiigddeeffggghg}c{b|e}fuaoXnY~|ճ}ij´ȽȼǺȻɻɺȺȺȸƷǶǵǷŹƼ|}zyywv{|}ŷ|üö°íwjil~ioqyjkjjihhhhefhghhggghgfecedddceefdcegdffgedeegfediggjihgedhfffeeeefw`ya~fe{dqYmVr\|jѽľμκϽĴȻɼȻǺƷȹȺȹǹƸŶƶǶǸƺȿ||{yy|{|z³{ǽznklmsvnnrjkkjihgffgfgghfefhhgfecdegeeddeeccdefhfgedegffggghhjheehhhffhfeed~e}fff~gw_s\{cilopqɴ˾˿ʽɼƹŷŷƹȻȻƸŶŷƷǹǼǽô{}|yyz{z·źrw}nkkmnxilnkjkiiigeghjhghfedegghgeeeefgeefdcdeh~highgefedfhffgijheffehgeeededfjggi}e~ejhjnoomr˿ʿɽɾʽƻƹǷƶŶŶƹȺǸŵųƵŷŸȻ{~zz}~zx{|xȸĽzrqqxuikmpq{pfhz|ihgijgggghiigghhfgeghgeefeeeffffccdfgiihihhgeefg|eqYyahigfddghgfffddddeeegghghikmmnm˷ʺʾȼǼȻǹĵƶƶŴŵǸǺŷĴųƵŶƷƺ±}zyz~{x{||zĿ|opvvvo}iknppzzj~gj}qohhffihhhfghhhhghgigiggfgeddefddfffffghihgghfggfg}emVr[eeefedghigggdfdddddfhffhhjlmmmsw̾ʾɽƺǺǸƵƳƱƳijĴƸƸƸõôĵöĶȽµ{xzz~}|}|~y¯xosvwuuwnmquwysqihuxlkihgghfeefgfgihhhhjijhgggfeedefeeefefhgffgfgfffehhs_xceffgeegh~hhhgffefgffgihhhgjklopqqq̹ɼǺŸƷƵƳdzưİıijŷƸĶöööŷȽʾŸȾµ||||~}|ĭêx}ipvwwwuvuorsuxuhhjqplliijhggfeegghhhfgghiiihgghgfefhgegfdefffggggffgehhh~gfggigeffgggggefgffhhihiiikklnnoppʻɼǶŷŵųųűŰïïİųĶĵŴó³õĵƺȾɿƻµķǻ{{{}}}lirvvxywwvpnqvvme~ehnzzolkjijkghihggiihhggfgiihifgggfgffeeffeeddegeefegggggihgiiiffgggfhhgfffggijhijiijkllmmonsŶŴƶij±ðïĮðİįİij°ŰİóöŶŻƻ÷ɿ{}|{Ź}jirvvvvvuuvqwvwm~f~e~ervj~hpljjkhghhhghggghihhgfffgfeedggeeegfffffcbbfeefefff~fff~ggghihhhhihiihghhiiijiiikllkmnnnnmmðijñİð®­îįïðįĮůijöĶǸŸ´Ƿokpvssuvsoooq{~og~fhj}kismiiiihhgffffgffikiihhecfedddgfgffheddeefgeefgedehg~f}e~dghhgfgihfhjjjhhhiijhhjjijkkkmmonnmlİï®îïîïóõijĴñüĺɿîvporsropromoor{qfghkh~fkxyqmjghfghgghffeffhgghhhgddegedeeeeeddeccegeeeddecdfgg~f~feggggghgggjkkihighiihikjkjhjjmnnnnmĬ¬¬¬¯­ððİݶ̿пyspruqppnqlijjlqn}hijoignsywmmliighheeffddffgfehighcbfgeddeddfbdceeggedefffeddeghhgggfhgeeffjjihhhghhhhkkkkkjjkmomnpm|®­Ʒxuvppurmpspnkimnkhs{mnujlvwvvjljjhgggfdeecfggggfeeffddggfggggffcdedegggfffggcccdggf~ggffhghhfgijiigggigijjkmkklkllnlmpmw³ǿȾ~zwsvrsolnpnkimsvqhvkjlvwwkw¯mkiifedfehiggggfgfefhgdeggihh~hgghhggedefgggffgddcceh~g}ghgghhjjiijiiihghiijkkjkjkllkllmnposǼzswuwxppppqonkjmrwr}gz|hjp}}ko|kjihhhedefhgigggfgihgggfghgffhhiihfefdggghgfffdccdfhgfgeegijjiiggiijiiiijjkjkkklmmmnmnnorĸʸukossvvspoopporrqqqnqowrvywyxzƮijz©ojjihiheeefhgffggfhggihhggiifeghhghfeeeeefgfefecb~deffeggdeghiihihhifhhijklljjkkkllllonmmpoijxmrswxyyyyxvzzuwrusxwzwvyz~ȴhjml}igijjihggggigfddfghfhiiifhhgefffffeggfdeeefffgeed}d~eff~ccgeefffhhhgfgeghghjkkjjlllmmlkkllnpp~{vwxsvxsw~|y}wuvvz{xx{|{{xghhnhjlhffhkihhffdghgedfghiiiggihggfefffedfdddghggf~eddcegg}e}ffdddegefhhghfhhfiiikjjlljkklmllllmnpqxij{z~yuqjmxrqopzyxvxxwvxx||z{yyyyhffjmijjggfefihghfehhhegghhhiihfhhhhffhfeeeefeegghhfgeddcc~d~f}e}d~eeeddeeehhggggihgikkjjkjkjjmmllllooppszs|z~uhh~gj~i}hlsuxyywux|zz{z}{xwxz{gffhihhhhgffegggeeeefgfhhhiijighihhiffhhheceeffgghgf~eedbbc~d~e~e~b~ddd~deddefffehffhjjkijlkklllklmlmnmnnmsǹ~rswyvs~xwɹx|rf~f~fkpsyxxzx|{zyyzxxy||~gghhihhihgffggggffffeghihijjihhhiiijhhhhfeceefgffgf~e~edccbdf~e}dd}c}c}d~bcbeffgfefffhjjjjjijkkmkkkmmnpnmnno³ǻyvupu~vx}}zxpppqwqnqy{|{{®|zxyyxyxz||fefhihgjighefggffeffeffffhiihgghhihiiggffdddefgfgffddc~ecbcd~ed~f~db}`~`{addddfddeffhkjjlklmllkjkloonnonnnmijxz{lmxzu|{zzxvxyz{zyz}|~~ɽ{y{|z{edeihhghjiffffgggefefggefjihhghigighhhigecccfihefhfdd~dfffdeg~e}dbbb}`~_ccceedefefhikmlmppnkiijjlnllmonlm{~~~|sv~m{|}~xxy{zxxyyy{||}®ȼ˾|}|ǻתggggjiiiiihhhgeefihfhhhhfhhgggghhihggghgebacehfeddeeghf~ghefhfcbceba~cdcdegeefiiimnlmonmkggiklmmmmnollv´~|~ws}r~~|{ywyywxxz{z}{y{ȹĽ໪}}óѫi}g~i~kjjjhhhhghgggggijilihhghhggghihhiiihgedcedffdddgfgg~gfee~fgeddcecbcdccdffhiijkkkmmmllliilllmmmmnooor´Ÿzxzy|p~q|xxxywvwyzzy{{ĺm~lmnljhhhihhghihffgillkihhghggihhhhhiihhgdeefgecddfgffff~fggfddcccdcde~eeefghhhijklmllllkikkmmlkmmproppȻƹ}~|yvwxyyyyxuw~̾lopnmkghjjhiiiijhhiiiigggghigfffjigggggggeeeggeeegiffffghhhfegfefggffhgghfihgiijklkmmkillklmmmnnnpoprȽx|yxyvvwwwy|Ͽ­ľǿ欄lnomnighjihiikjghiijiihhjiijifefiigeeeeeffghhjjjhjgfddgjihhgefgggfggghghihggfgfhlklmlllmmllmmnonlnprsĵwuz|wz{|zzzwxzϹÿ̾ijȺ̾Ⱥ|exdkkzdg~dkkkggjjihhijihiihkihjkggghgfffcdeeghiijkljiigddgijjhhfee~ffggfhhghijihfefgjklmmllmlkmmmnnnnoprrµxvqpvx}|}|}}yzzy}{~ɺô˼Ʒʿɾxav`zcjhs]u^kkjiijiiijjjijkhiiihkjjkhihfffdfgfggiijjkjlhffeghhhhhhff~f}fggfhghijjigefeilkkmmmlljkklnooopqqsr{}|xuv~~px|}{|~|Į¿ǟxaw`s]}dg{biklljhhgikkjjjjkhhghehkkjhiigegfhiggfhg~gze|ekljjhhgghhhggghhhigigfgikjihfggilllmlmkkklmonnnoopssqrsvu}~ouq}nu{~|||dz±Ǹw^s\v_|cu^hkjjiiiihiklllkjkkhhi}fya~fkjhkkhghihigfehffglkkkkjijhhhhhfhhgikiiihijiihjjiijkjllllklllmnmmnqqprqpsrqõ~pyx}~|}´ìȾǺ˾¿ܠx`v_}cu^u`|g|ejjhhhhhillkkolkjjjghhjlmmliijiiiifdeedffjnmklkihhhighhhiiijjiijjijhikkljkjkmllllklljnmnqopqqpqu}g{g|s~Ÿ~ɶɾʿþƱưī}fi{aw^~b{a|eihgggihiijkjkjjjjhhilmmkkjhijihiigedcb~c~e~f}gze|fljjijihgfgiihhhikikkljijijkkjkkklmmmlmlnonpussrrvuvzcyaxŸŽx~xz~ɼʼʽ®Ⱦ̽ʸ˸̽ʻɻĴƷ­ƫ}czbs_{_}a}ehhhffdfhgfzeiiiki{fvcub{djknnokiihkjjhgfeddbbeizevcxd}iklk|f{eihhghiihjjljjkjikihikjjiiklnnmljllmopsrqmsrqzy~nñ̹ǰ̻ëx}}||ɸλĦƫưȴêűűybxay`}`fhiiifecehg}eu`fehh{cs_waqauaydxb{dwa~elljhijhgfeeeedbcfkjknkkk~f~gggihg}hnjklnlilli}ghjiijjjkmnmonmkkmnmoqrqmrqswx}zxwy~||{̾ǸνɽɺȶǷƸƺuaq_r_{az`|cjjhddd~egii~e|d{gwdn\o]s_wbsaxbxau]s[s\x_~fjkjjjhggiihhdv]x`dgloqmmliiikiihjlmllnmllkwdyelljkkgmmhhnqpolnpnnqqsr~jmo~j|hziyi}m~|zŶ˻ɵĬ̷}~ñۜr\s^p]u_xdihgefed}e|fhjhxcj}hwdv`v_p^n^r_var]q^u^v]w_ikllkikii~f~df|czbybzdikmlloommijiiikkmmlnnlji|e~holjlijmmm~inppnmnonoponn|fycydq`{jnzïzϾƮŮħŦũƪ£ũ~ħɵƶƵíî˼֦b}ahkqlfede~d~d}d}d}eih}e|dgi}g}eydsaq_ubwas_waybzdklmlllkkfu\ya~eef~f|digzf|g|f~gjjjiihjiik~gmnnnmkiijknmkklnopqpoonqnpooonmkigln{mصýþƿű­ƭåɱŪ¤ĨàĤŦĤŧť~|ɷɻêþ֣|ew_imggedef~e~d|c|cgi}ff{excgghig}ehjhlkhkonommmmj~d|dihgffhg|g|hxbubuayczd}ehiigi}f{dlqpoomkmnonpolnpmounpsprpoponlkjjinrqzlĽľʹƱǯįȸéĥʵŨʸë~ŤƥŦ¡éʽǻĵ̾þĦɷþРu`u`|fnigfeff|e~e}d|egg}fg{c|c~dg{e|f~f}ef~fj~hiikljkh~g|fydzb{`}djjieedf}fweyd{d|e{e{fzcgi|d{czcxb|djrrppnjkoooqnmnjyeudwf|i|jluvpmlnnljigg~hn~lyjư¦ æȵ£¥áŪ˻}žǥäʶŵŵŴ˽ìο˿»½ƣv`gpheee}e~ee}e|f|e|dfhjhwcxb|c~ezeudsau^v^y`{e}fhxdsdwbwav`{c|dv^pZr\q\u^w_zaf}d~efgjmkikmplkigfffgoohln~gxa{agklpze}izds_s^r[v`zgweudllnmmomkkj}ehlzk}n|mŸġŸÞɮĥġĤ ǯƳȵ~ȴʼ̻˼̽ë˵ȳưϾǬʳοİŭĩλ~eeev^y_|`r]{fhg~e|h{h{b{cfijm{eyafegze}effzflxdo_n]p]q^o]u^y`w_u]r]p]q^q[nXu]ybv_yafjppllpnmkihghhhlnnlkg|gycw`vas_s^r_u_r]q\pZqZs`vcxe|i~lpsppnnoljhijziqzàŪŤáŬèƭ  ̽Ͽ««ǸȽɻ®æĨϿпǮũϸȳ˼¼˿žɺħǩ˶a}`w_v\{]z^oZwf~igb}e|e{a|afhmjygxc|f~f~e}deg{f~ikwds`w_wbv`xczex`y`ybwav`s]sYr[rZq[u^zbjkmnmnqnkjihghgfhnsnjjji}i|iyfzfxdzfzfzcu]q[r_zdmrrqsqrqpnlkkihjwhzǮžƬ䝡ã¨à̽μ̽кʶ˺ĭģã̸ȳã¦Ǭƪʵ¹ɺ˽dzƨƤƥȫz]x]rXuYz\w\q]{fxdyb}b|b|`}`}a~bgjkj|gydvaycza|dgh}ip^p]n\r]xb}hl{gwa{digieza~e~fybzd|ekkknmlnmmjgjihggilqoljklrvurprlmkzdxckqrnkyfkpsqmkkljhkwjʰæßç£äʹпǰª¤¡Ʈ˴ħĦä£̶¦ġĤƬƨǦȯɷǴdzĨĥƦƥȪx^oWmVuXvYqYs]|fzfs^s]~c{_|_|^z]}_ejkkj|g~e~fzfwck}fxdwbq^xbzdw`vaqasdvdgghe|dzdiki}hgljihmnl}i}h~hiighf~dgm~jhilnnpnhj~gzcfgzcyd|h}g{eyhsdxe{gweormk}i~i|g|g~iviŭDZɴĬ̿ȬǧŸßäȭťĥ¡ģġɭǩɪǫ̺ǮƭƦťà ɯs]oZnXvYsYjVo[s]p[nZqZ}az`}^}\{^|a}fhj|h~hiiihjk|d{c{g~hlniikolikif{`|a{cwc}j|h}f}fkiyb}gnn{h}ghhhgge}cdybze|gziojzc{c}eyaji{cx`u_s`wesdqcuauaucygxeygmoljj~h}i}j~kxiŰ©«˼îŴŸºêĠƣǥĥĥããžãŸǥȧƤɯʴŤǨĥĥιrZp[p[sZmViUyby`s\s\r[s[z_~_z`zazazdgigilhf~efzbs]u]v_}hkhhkmklkkiiegnonihilnlmpomjiihge}c|dzc|fze}h}jnj~ghmnlffv^oZr]sbuc|j|kudwchzfvg~kpplj~i~h~jwg~Ʈʶ¬©ƥšȨŪǫŸŸàţȩȫȮƧȧƤƣÞŤºrZpXpZjUkTqYy_w^zau]s\u[w^y_y`zazazc~ehhgzd~ggwbs`s]p[xaxar\r]s^zekwep`vck~gggekkliihghhimqlkljhhigyb{e{gkvbucnjhlmpokkjf{bzbs`wd}kwfscrawczf{jopol|g{f}g}kxhϼȹɸijDZªʷŪūȫŸǩğĨǰæážÚßťåǫ˶¤ţšƤçǭĨ˳oYrZs\kUkTqZs\o[q[q[s[u[q[u]{_|`{cybwb|fh|dzdeixdu`w_y^|au^s^}d}ejirdpe{k{gu`ubr`wa~gvauau^|c~f{f}g{eyazbye}hjlihhhg~f|f|gj{fubrbvc}ekijlyg{fi~e}dv_s_sczhzixg|inusqurkk}j{i|lzkƫºðʶϾ̺˸̻ÿȽǨŧŦ˰ɮ˱äĤǦŤǮºġÝĠğğàŦèϸ£áåğÝŦȯàååpYs[mXiSlTu[r[q]r\s\w]rZr\z^{^|a|ezcwa{eyexbf}dfycu`wa{by`u]v]d~fze~gnoxfr^r`qauazdyaxcvav_u_ybkli|g~gilg}eycv`{e~dd|d}d~ejrqmmopnoppnnlh~g|h~msvorwoyg{hzf}ikj}i|k}lzlťĬνůɺϽ̺̺˷˸οȾƱƩƧŠģȬȯѽŧǧãĠȤǡȩɭƤĞğŠšƧī˸ʰġţäáàŧȪžģťäqZpZmWiUoWqWs[v_v`w`zcw^x^{_{_~b}czc|c}b}egzbil|gydhgv_s^r\p\u_u_vbkorar_u_r`r`var^s`u`w_x`ya|djijlliw_w^r_o^s_v_r^xav`xbxb{fuvnk}impmkmnqnmnvvozg~jnxixfwdscs`xd{fu`zexhymĦçŨů˶λϻɴʳýɾȵƨǪƩåƪƬʴɰàŞǠƣǣɡǡơşěƞŠţġƪʮŠơťäƩǩšĞĤġţŤmWnXnVpXpWqWu]s^zf{ejjy^|a}d~ce~c~de}dgiomkji|g}g~fv]q[q]p\xdnjs_v_x`x`xazbr]q^r^q^ubuczgiihjkybs\v^v^u_r`wbx`|c|dxbq]p\{ixgq^s^r\x`|f{du_v_xa~immkyhvfucwayd{fyfyfvdvdvbw`u_u^x_xeqŦãǰνȫ˴ǯɷȸǰǧǦƦĤĬʽǸǰƪœĝơšƠǠǡƣġŞššƤßšţƣġŤĥǬãĞšţģġu\qZqYrZs\v^w^v^zc|fi|eoZx`e|d{dc~d}e}c|dh~hxcliwau_hl{dzeikxdyfyb|d|cw`w`|a}bx`v`waydjikjjkmk}gxbv_xavbr`vayadd}dyezewas_v`u^y`v]w^{czcu]q\q^ubsaqbuescs`xaxbucyhvgsfveygzfv`v_v`vdy¤ȶʳǦɯȰǪȩȧʭ˰ʴ̽ɽȴƪģĤĥġĞơߞĠĠģĤŤÞĞġġž¡ʭĤÞÞĞğťĠr\pXs^w`v_sZoXpZs]w`z`s\y`w^v]}e{d}g}ew\y^}cfxbxd|hxcs\qYy_v]q\s`wa|fq_n[o[w]y`w^~ee~cs_waxc{elnpnnonlj{g~h~g}fzc|c}d~eff}h|iyeucvbq_w`w]v]x`x`u]s`uaubxdkvdwcvavbxcxfwgudwhyivdscs`ye}kvfDZĩ̼ʵǩŦ¡ãťȨʬʬȫǬƦƥƥţƥģŸÝÝŝĝŞğޞ¤ ßĤáŸĥãŸàġĠߊƟnXpZu^waxb{g|insizbxajwbo[mYx`g}g|e{b~dfxbyf|hu_v]rYz_sZmXn\q\w^q^p\nYoZrZrZyaya}def|dycze}hlpssonqmilmkje~ddd~f~g}gzexfudwdvbs]u^r]s_q^uasdwc|f|hucu_wbye|hzivfzizkyhudrbzjqvj˽ȶɷνȴ˷̽ȳǯǰʱȯƩǧǨǦȧ žĠĝĚĞááãŞšáƧäãģĤĦäßĝÞu_xbw`wd}lxi~dgkmlix_u_{d}g}f}gf~f{fxgzfydr\u[uZpYr[r^o]u^r\o[mWnWoYoYp[p]u^}a}dgj}ilomo{iuax`}fjjllkji{e|d}d|f~fffhlp}iw`u]s^u_ydwfudxds^zcmyexexeqdsgyjzjl{h|hnwh~owmȶ̿þʽɼ˾¼ɸŪǦǧŤŸáŠĝğĠġĠŤģȭéģĤģŤ ŸÝŝŞv`r]r]|iqyxyg~n{gxb}ghya}cgu^s\w`}e~ezd|f}g}ghwcu_q[r[pYqZq]q^q_qau`q[lUnWpYq]r\s\s\q\q\wa}h~l{iuauaq^q^s_u_u^vazci}fvavap_o]o]q^zd|f|d}fmnj{cw_w`r\}g~lzgydzcvbrmwdrcufug~nom|fzf}jwh}m|qŴνοîºоϿƬǩŤģšŠơǡƠşƠĝŸáģģťáƫƬŤŤŤŤžœġğĜv_pZzfrrrs`o[qZs[p[o[r[oWnXpZv_v^zcxd|h}g~gi}hu_q[pXoYo[wa{cv_{d}hr\pXs]q[p\q]u^s\o[n[vcygucwbubq^r`r`v^v^s\s[r^r`r`q\o[mYq\yd|f}fwdwd|g}e~fx_y_|c{dorrnsuvksbp`raudygucsbwcygxhufwhypο¾¾νϽûƿоȱȮǫƭƯɴɴǯǮȭɮɮ˰ϳɮťŨɱùξǯǩǩǨȥţğşŞŞƧȪĤĥȫħƭŨƤţƣšĤàĠß¡~iq`kur}}hr[q[p[q[q\rYuZoXkXlVmUmToTpXs\rZsZ|cjhzdycr^q_s_u`wav`v_{av^r[u\u_u_q^q]o\q_ubsbse|gwcoar`u_v^w^s\s]q_sauas`s]q\w_|c}egvbp^u^u]s\q[s\q]vaqzpzg}ixx|is`r`qbsdqar`s_uawewgvgrdxʽ̽̽¾˵˷ʷ̶ʴʳǮɬȬȩȩǫɭȫǪʬʬɫɬʫɩɨȨɩȪģģħĪȯ̷ɰǬȰʳǯDZȱƫáģƦģŤɫ̷ƫǪƦǤƣơŠŦťáä¥xmo~|f{_xap[q[r\u]q\sZv\v]lXmWlVmUlTmVkTmToSv]zcyb{f{gygk{dr_xdq^q\sZs\v]r\u]u_u`zer`sbybydwfkjxcwbxahjhixcvbzezdw`s]u\sZsZx^s]q]q\s^u]u]s]q]r^muydr_wbk}mzev_uaububraucs`q_vcxgxhqe¾λϽüɷǮʭɭʭ˳ʶɵʶʹȷȱǭūȫɭɬɫʫ˪˪ʩȩɩȩǪħƥǥģßġƦǨɩǬȯʷϼʶ˵ǯƬƬϼȯƤȤȥǧšƠǨŤà£ƫufyivb{gp~fq_wbzcr_p]p^v_x_r[u\x`m[w_nWnUmUlUkUlUmSqXy`q[va~k~kkj}fxbo]r^}fwbr\v^u]w`{fxdwd|g~h|e{f~jyf{ezbxb}fjjk{dzeyeuaq_p[oYpYpWnVoYu^v`s`q\s[r[u^w_k|gq^s`vaxcsar^v_v`r`ucyg|l}lscxgyg{jvg˹λ˹ʴɳɱʱɳɸɽƾ˻˱ɮɬʪʪ˫ʪʪʪɩǨũũƩƣġũɪʫȬƩŨŨȮ˱Ȭȳ˵ʷɱǧƥǦƟǡƧţßĥǬvfqcsbwczcybu^r_zbq^n`qbsbxbv`yar\p]q[nYnWmUlWlVnVu\w^r[oYo[wakk{dzcvaq^p^zfkzeycyczb|er_s`}f~k|fuauczeydvaw`v`ycyfsbzfzf}f~g{hq_nZqZpXoXpYpXs[w^x^s[r]wdmis`s^v_s`vbsbr_v`vavc|k|kyj}kwevfxg|ioc½½нϺ¿üʾʹʹɺ̺˱ɬʪʫ˫˫˫ȨȨƧŧƪũƥ¤˴ȰǬƫƫƪȩƪǫǩĤãŪθпʸīĨĪŦšƣũǭ~pyj{g|gnjx^qZy^{c{g|j{izfhhq^uavan[q\v`wauaua}ewalZnZu_v]{b~fycxbvao^o^~hmpo{is_v_w`r_uaxczfwdrbudrava|dvas`yfjhrb{ekk|gs]u\sYrYpXpXqZs\qYs\ls|gwar^s]u^s_s`q`uas`r`vbyiyhxfvfsdzhzire¾˽̾¿̾ιɱ˵̷̹ʱʭ˫˫ʫʫǧǧǨŦŦŧƩǩǩƪǪǪƪƪƫǬǫƧ  ơğĠũ˵пǨǫƨŤrrwnxnxbs[|cj|f~iyf~hkgs`~gydvbhk{g~j|gs`q`q]q]u]ejhh|gwcyflwcr_ubxdsbq^vavbyb~fgkygrascsbvcyfu`zdl~g|fxeqazf}hjg}dv]rYoWpXr\xcs]yd|g~jubq_q_v`{cy`war`s`uaq_ucxiwgwfxh|ks|luiξ¿¾пλ̺κϽϿϼ̸˵ʮʩʪʬȫǩʭǭǬȬǪȪɫǫƫƩĥƩǩáãťƤšťǩĥ ©˷ûεǬŧäģ|vrponnik~hvcvbxfzfzbu_uaual}knjzdu`s`raq^u_s\qZybjmqyizgku`n\m]n\q^wczd~hkhj}h{dzdudxdhedfyar`wdvdvd}i}f{bx`{bgy`pXpWuZs\r^u_v`yesaq]q]s`wa}d}cs]u^s_ua|hwewf{k|lqp{lvjý¾ϾοξнλʷǯȯDZȱ̴μɹɵɳɱɮɬƩƩĤţŦƦţƥƧŦŤŦƥġŨũŧħƪŧĤŦĤvoxv~jxcxcyfwbvcsau^s\v^s_ucrbyf{gs`v`u`r_s_vbu`q[nZs^zfqr}j~iw`u_u_}gihkkikjw`qZs^xfijhc{]{azezhop}hq\oZqZqYv]v]s[p[s^u_r\pZu^yds`p\q\q\r]u^|d|ds]r]q^wbwg}lnzrxmqi|v̿ξϻικ̼˻˻̻̽ýÿμ˺˹̶ȯȰDZŪƤƦƦƧŨǧǦƥţŦħĦĥƧŨĤŤƥĦw~jnopxfq^p]r`ubs`q^nZoYq^q^o\r_q`q_s_q^r^r^s_s^p\o\o\q_ycloi}gikkjjijjjl~hp[w`{glkybx_u[w_}ipklwclWo[s[rYnVoWoWu]s\q[pYpZu^q^q_r_r^q]q[r]wa|gwcu`r]rbyh|jzky}pzrϿƶ˶˵ʱɱ˶̸ȮǩȫʴƽŪȤǤƥƧƨƦǥǦǥƦæåäǨƧţġũɴzk~jlsrqrq{es_u_ybw`o[o[r^r]oYnYs^r]q]q\pYpZpZs_s_o\n]q`u`r\wamkrqikkkljjkkmhhlmxdu]s\s\s]zcoom~fqZoYpYoWmUpWoXpXu\v^s[y_|cr_o]s_s_r^r]s_u_xbvawcuarasdvfwipzn¸˻ɶʱɯȭȭˬ̬ˬɪƩǫ϶úѼǮǨɧǥŦĦäŦƧǧǩƨƨĦĤåèƮ˹ڰwsqsqurppmkhij{bp[nZs`u^r]s_u^s^p[qZqZpZqZs`s`q]p]xcxbr]q\x`ya~gk}hkihh{cw`ydzeybu`{c~f|fr_q[nYq\}el|gj}dr]oYoYu[x^pXoWpXnWqZy_~dix`q]q^s^xbxcr_r_s`ycwauauas`rayhzi~rξιʱɮʭ˫̫˫˫ˬʪʪɪɱüϹ̶˴мо̺˴ɪʫɫɩȩŧĤáǪƪŨǬǫħǯ˸nprvrpooomjjjkhzcs_s`ubvau^s^pZpYpZs]u\r[s`u_r[p\s_vaq_q^u_q]s]v]u\s]wazfyb|cycr^r_q]pZp\r`u`u_oYr[xbzbycxcs_s_o]nYpZu\v]pXpVrYu]q[mXw_j|f~i~hhiwbr]r_ucubs`s`r_uavdxhwn¾¼»̾κ˶ȯɬʬʬʳʰ˭̯̱˱ɳɱɴʵϷϼλʳǪɩǧƧȧȪɬ˪ʪɪǨƧäģģƫǫĦèëȵſɵũĦoprssoqppmj}ehijli~i|ivemYnVqXpZpZpZr\u^v_s\q[oYo[q_r^q^s_r^q\rZoYoZp]q_s`yaik{er^s]q\s^s]r\v]w_zc{dh|fxdwbp]oZoYoXqYnUoUs[v_u^r\s^}hkm|jl~i~hx`r^rbqarbubu`vbvesgǺý¼нмϻ̸λξ̼̹λ̹˴˱ʯ̴̱̳϶Ϻѽп̹˴ϵϴϴ̱ɭ˭ʫɫʫʩʪʬɪɩǦťţàĤũŤ¡ƮûɴũǧɪŨopq~plpqqkxbv^x_x^y`fhhkvgp_mYoXpYr[s\r\s[rZr[q[r^p\o]r^w`u^q]q]p\q\o]q^v_r]|bhzdybs_r^sajycr^wbs`vb{d}g{fu`zeoZoXoXlVpZv^xazbv_w_~gjwdscrcqcze}ezbucueudwdxcwc}j½üľ¾оϽμ˷˸˹˷θκϻιηδ̰ʭɬʮʰɱȫȩɪˬˬ˭˰̰˭ˮɫɨɧɣȥŧĦģĥĦȱƳëǰλʴɮǪšƣǧƦǧʼ|qqkw`v_w^v^v]v]y`ijum\lWqZr\q^q\s[s[p\q]r^q^o]vair^o\o]o[q^r]s]r[r\w_~dhfwa~ipo^q_r`n]q^ydydw`wbvdv`w_v\w^xa|c|cwauaubvb}in{i}kzh{ezcloxgqcvfvep©ɴƾľϿϿþо̼̺̹̺κ̷ʱʭʪɪɪɫ̬ʬʫʪʬʮϳα̭˪ɨɨȦȨƦŨƧŧȱ̼˽ҿɮƨǩȩɫɫȥŠƣƤƦȵŬDZøĸ~nih{cu^u]w^v]waycxby`dsvhmWmYsZv[v]r]r`|g}guawbxcq_n]r\uZsYsZrYpXr[u]x`gh~f|evan\r`u`r^u_v`|d{d{ehhfy_|ewbr\r_q_r_sb}hsp~hjjyc|gpzirbscwh{kɬǪǫƪǭο̼̽˹˷ɱɭʬ˫ʫɭʬɬɫʫʬ˯αή˫ȫʮɬǧȩȫȮѾ˭ȩǫǫǫȫɪɨƥġƥƦƦƧȦǧħ¦Ʈҿ˹y{i{gj}fyc{fxcwbucvdvdye}g}zwdwaubyh|kze}hzfxdvar^pZv[uYuXuZs[oYrZu_r_v_}d~dc}eydycwawav^s^v`x`v`hhg}ds]q[o\p_q^r`saxe|dx`u`vaubwd{g}iziverbzjoɪȫȮʮɭɱüοξ˼˶ɰɯʰɮɬɫɭɫ˫˫˫ήϴϷзɫɪʰʰ̶ÿʴȫʨ˫ɭȫȪƪǧɨȧȧǩʯɫƧȦȦǩƧƫηռԻԽӾȶvrppoqnmk~ls{{pbl[q^zc~fx_u[v[sZs[s\p[qZq[q\q[rZrZz]ef}e~eu^p[o\s]v]s]~eze|dzas]q[r]q]p_q`ucubs_vavbwavbzg|h{gyexeraxeläˮɭɮɭɮʭϽýϼη˵̶ζδʱɯǯʮ˭̯ϱεϹ˰ʧ̪˰ιľȮǧʩ˩˫ɬǬɪƨǨɫȫɬε˳ƩɯƧƦǨƩɰӽӼӼӻӹսõÿ̽ɷȷ~oquwurpszȹĵ~nh~eyav]u]r]r_q\pXpYrZsZpXqYrZ{a}dxaw_|cgv_v_w`u\u^u]s]p[u\u\r\s_p_q_s`sasauau_w_u`xdzfyfvcvaycilƩʮʮȭɬɭί˶Ŀ¾Ͻомлι˷̶δεδ˰ʭʪʪɪɮûưǩʪɧɧʨɪȪǩŪƭɶμ¾̼пƪǫĦǪһӽҽӼԻԼһӼѼѼԾƶʾs~krvvunlqϽxkhg}e{eydzeybv^r\s\u]r\qXqYv`{de~cw`xb{d{d{c}c|ee~du_q[pYpYr^r_r`u_vas`r^u_s^u`xdzfwfxf{g|gl̴˵Ϻ̶ɭɬ̰α˴Ͼÿÿ¾поϿμ̹εˮʭȩȩǨηϽƫƧȩƩȩʪɫȫǪȰ̹ÿǭȮŪŪ˴ӻӽӼԻպԼѾҾԾӾҼӻҹз̶лнǷǶyvwzzwpmzbzfuqlijighjlkjkjjzdz`{cgih~d{bzbhnolkjikzjm`n^n[p^u`u`zbw_s^s_ydzf{ixgygyhykѼѻѽϿ˵ʭʮʬ̫˫ʫɮĹľ̸̻˵̴ηϸκľ˶ƦġƥȪɬ˰ιιϺ̸ǪҽϼżӺԼԼһӺԼԽҾӾӽҼҼӼԾԿҺкм˼ιzw|zzyql~ejrnjjijiijjjmmlkkkjiikkigmonmkijsŭŽyorcvcpknh{cwbygxgvg~oѽлѻϸ̵ɴ̹̺ʭˬ̮̮ʮɮϹſϿ̹˴̯ʱž̳ƧŦĤƤɪɭζϻϺѽϿ»½˴ŨĴɾ»ԽռԼӼӼԽҿӽԼԻӻԽӿ÷ϼýӻrqsqng~fosojjlklkjkknplikjgdilljiijklmnmmvʴľynxdzdzewdrqxűмθ̷ϸϸθ̻λ˹ȰˬˮɮɭʮȮѼϿ¸ÿýϽξοϼɳȱѽ»ʮƧƦƦŨȫǨɰ̷̷ϵΰϵʶƫǩ÷ź¶žƿӿԾӽҽӽҾѼԼռӻԼԾķѿýŷujlsvro~imoll|jih~g|g{fyeggignokjijihlkmnoomųɽʾȾx{qѾѾϾϿοϽλ̸ʶʳʴ˶˴ʴ̷λεɩȫǪʰɶžϿžǭǪȪȪȫǪɮ̸пʷη϶̰ʱ̻ǩǩźԿӾҿѽҽϽԾպּּҼƵſŰ{qpnn}j{ixg{jzi{h{fwa{excyb}chfopmkmljijkkikosor|Ǻȱķ¿ϿϾ̽̾¿þ½˶ŨħŦšƣǦзƼʴĥǨȪǮϸʯǧɬϿι̻Ʊ̵ζʰɪǨƿƿźֺԿĽɹʽij|xqpmj~h}h~gegyd}ee{azbprpopljhfhi|exelk}jv{xwɰáŤơǡǦʪʫ˭лʻ­ƫɮǧƧϻϾγǪ˵ľϾ̸ξûʰ˭ʪɫȫǨžѻѱȹɻ˾ɺĪ{{r}iprnnni}jmv}Ʒ³ļĬţäţƣǥƤȩ˫ɩƪ̻¼ȶǭ˸˸ϸϺмθ˵¼çǪũǩǩɧȱ£ξĻɽůǬɯ̴зԸѻѿ̵˺dzŵƵŶı£ĦĤġťťƦʪɬʬɨʰ̼Ͻ̺λüѿɱƬǭȮƱϾιħƧŦƨǪȨɴſǯƣƦȧǧȥȦȦɭйȩɧȧȨˮȮȮɭƭμʻǷɹ̹Ͽʹĥ¤ġãţţƥɩˬ˪ʨȨȪ̶½ſ˷ǬȫɭȫɭȭƪǩȩŨŨƩȧƥ̻ãȦȩɪɩȨȧȦɧʩȨŤƟşơššġũ˹ſϽϾ¼ѽĦå¡ãšǥƥƥɩɫʪ˫˩ɧɧϱĺнɱǫȪɫɭȭǬȭǭȭȭƧ̳ϻƮááȻĦǥǧȩǧƤơơɧʩɨǦǣǣǤǦƦȥŤŦʳ»нѽ˷åŦ¤¤äţǦȧǣǣȥǨɪʩ˪˫ɨɥȧʫ̰˸ĿƾʮɪˬȬɫɫȬȫǬǪȫȫǫŧƩƮĩ¤äŪťǥƥǥťŤƣɧȧǦȦƤƦɨȨǨƥƥǤĥǰþѽнκȬˬɬθ˾¤£äĥƣǥɩȨǦǦǤȦɨɫˬ˪˪˪˪ʩʩȨȫλ̺ɬʩʫʫɫȩɩɪǪǬȫǩƧǦƧũũ¤åĦȵãǦơƠƣƣȥɨǧƥƥǥɫɬƦȨŧŦŤťĥƪö¼¹˶δʫ˭ʬϾå¥ŤŦťƥɧʩʫʩɧǦȦɥʨʫ˫̫˪̫ˬ̬Ю̭ϹϾǰŨǪȫɩʪɫɬɫɫɩɪɪɫɪɫȪƨƩŪȬƪƪååũƥƣǡƤǣǤȦǧȦǤŤɫθ˶ŨƩŦƥƤƥƦǦȬþþλɮ̮ʮϺŽDZʮǫǪȬ˱ħĤģŦƦƥɧʩʩʩȨɨɨɨȪ˫ʫ˭̫̪ά˫˫ʬʬȪȪɫʫʪʨʩɫȪȫʪʩɪɫȬȫɭʮǬưȱ˷ο˻ĩĥɶġȤȤţǤȠȡǤǣơŤţŦɰĩƨŤŦƥǦȨɨɨȪǫ̶Ͼ̻μþ̺Ȱȭɩ˨ʨʩƦʳūũȯĪƪȬŧãĤťƧǤȥɧȧɩɩȩȪʫɪɬɬʫ˪̪̫˫ʫɫɪȩȦǥɧȦɧȧȪȩɩʩʪɫȪǩʪ˭˴ȴʷϿýʹȭƧħǤǥţƥȦǣǡơšƣƤġàƦƧĥŧƦǧȩɩʨɫȫǦǧʱҾþ˻ɰȭˬ˭ʮˬ˪˪ȨŦŦħãäĦĥħģġĤǥɦʧɨǥȦɨȨƦɪɩ˪ɫʫʫɪʪ˫˫ɫɪȬ˪ȦƥƥƧǨǥȧȪʩʩʪʪʮɰɫʬɶϼξξλ˵ʮʮŨŭǣǤǡȡȤǡƠƠĠƣƤģŤŤƧƩŨĥƨȪɪȧȧƥȩɫɮǪŨȰιǴƬɬʬ˱̳ɪʪʫʪɪȩŦǩǪǪŧåŧŨĤţţƥȦʩ˨ǣƣǦȩǨȨȩɪȪȪʫɧɩˬȫȫɬȩɦǥǦƧƨǨǥǦȨɩʨʩ˭̷ϿϿýпϺ̶˰ʯȦưŤȦƤǣȩʰġţšŤŤġšţƠǥʳ˼ȱĪǬȫǪƨũǫȭȭȮȪǩǨǦʫѽ̸ʵɮʳ˸Ļ̻ȩʨɧʩɩȩȪɫǨǩɰŪçƦƣŧŧǧ˭ȧɧȧƤƤŦǪȥȨǨȧǧȧɪ˫ʫɬ˴ɯɩɧȧǨƪƩǩȩȩɨɧʧʧϸϻ˳ƦɶãƥǦäʷĥţƥƥšţţŠơȪ˵Ӿиȭɫɬɫƨǫɫʭʭʬʬ˭̮̬ʪǫɮɱ̸оº̹ʳȭƣƤǨçȰ˹νϾDZƦȧȥɧɨɧɨȬѺϽ̼ŬãŤŤƦʰƩʱʳʭȨƥĤƦɩǧǨƧȥƣƥȩ˫˪ʮɳɬʨʩɩǫȬǪǪɩɪɩɨɨɧʭθàѿĤƣƦ¤κìãŤŤƥţţƣƣŤǦɧ˫еѼʳȭɫǪǮɱɭʫ˫˫˫̭˭̭Ϯ̭άˬȬǫǰ̶϶ʫǦȦŤĥáæåġĤƥơǡȦɪʨɩǩ̬ѶվƩŤĦĦǫκʵ˶ʵŨƪĨħɬȪǥǤȥȨȩɩʨ˫ȮɰɬȪɩɧǧȩɨɧʨȩȪȩɪȨ˰ƿѺϷ˶˶оιƯ¡äƥť¤˺¥ţţţƤŤƧťƤǦʪή̱ʰмϾ̺ɱɴϾɳɪ̫̪̪̬̭δϵϱ̰˰˳ɱμкǪǨǦǦƥţŤĤťťťƣǡǥǩɩɩȧɨƦƥȪϷʰȮɮɫŦ˱ϽĩƭéȬδǧơȤȦʬʰʬʨʱ˻˷ǬɫʨɧɧǧǦɦʩɪȨǦȦɨǬɭȩɪʪȫǩȪεê äϾīģƤƤȩȨɫǨƤȨ̯˯ϴ̱ɯп̾Ͻ̼ȳɰʯɭ˫ɪ̰϶ϵ̰ʮ̳̺кȬɦǥǥǧĦåƧǨǦǥƥƥƥĥŨǪǧƤŤťǥƦƩȮѼѼʭɪ˱ʷ̷ǰη˵ƧƧȧɨ˳̸Ȭ˱ξɱ˵ʭʫ˰ϵ˭ȤʨɪɩǥƤơƣƦȪȫʬά˭̮̮̬ʫ˯ηδŤ̼¸ſкáǦǦɪʩʪȩȧȧɪʮѺϿпɰм˼ü¼̻θɮˬ̭ˬ̭˩Ϸ˺˵˫ȥȦǤŤťţǧǩȨǧŧĦåŤƦŦŦƥĦŦƤȨǩƥũп˷ɱɭɰϻĽѼīĦǨɨɨϸɱʵ¸µȳι̸ȮɯϸʯȩɪɪǦŤťƣšťǩȬʬάʪɩ˪ˬϯϭ˭ɬŤťǤȧʪ̬ʪɩɧɦɨʫˮϸƾɴ˺̿ý̻нη̰ȪȨʫҿüɵʮ̩ȥǥƣŤƣƠƥũƧťĥĦ¤ĤţġĥĦĦƦƤƦƨŦŤĥϹκʮʬɯѿϼ̷˳ȫʬʭɯûλǭɫ̰˴˳ɬɩʫȪʮ̱ȧȦǧƧƧƦƦǥǧȨ˨ɦȥǤɦɧɩȫǪŤʵɫƧ̮̬ʫ˭ʨ˩˫ʪʪе̶оõȶʻϿι˳˱ζѼкϼŽʱɩ˫˩ɦȥƤťģġƤƧŦŦĦĥåĦšţŤĦƧƨƦŦĨŧťǤǥʰѻζȮɯȫȳпзˮαǫлϻǫȭʬɫɪʫ̫˩ɨʨʫʮ˱ɫȨȪǪƩǪǧǦȧɥǦǥǣƣŤǥŤŧŦʱбΰ̮˱̵ɫɪ˯ʮʭз˴̺ºμʺ̶Ȭʯ̶ϸʮȪʬɬʪȤǤƥƤšģãƨŨħĦƦĥťƤƦŦŦƧƧǨǨƦƧǧǧǥŦɵ˹ɱ̮Ȫκʵ϶ʯηϻƫȬɭɭ˭Ʃ϶̮̪ɫʪɨťɫɫȦɧɫɭʮɫɬɫȧɩɪȨƥǧǥƥƧť̸пк˷и˯˰϶̹̱αºýƩʬɪǦɥʧʩʫɧȣǤťĥĤťħũŦŦŦƥƦƥƥǤƥǦǧǦȩɩȧǧɨĥʵλѿɰ˵нмϽпкɯ˭ʬɫʫɬѽӼάέ̬̭ȧǥƥɨɩʨʭʫʬɬʬɬ˫ˬʮʬȩȨȩƧƥģѾѿϻк¸ηѾ̰̱ɳȬʫʩǩɨȧȩǦǦƧťƤƦƦƥƧƦǥƧǧȧǦǦǦǦȨȧǧȧʧȧɨǪɱ¾ϼʰʰйзˮˬ˫ˬ̪ʫθ̰ʪˬʭɫǦǥǦȨɫɫɬȫɬˮ̭ˬ˭˫ˬʬʬɬɭȫǨģü̻ѹʫ̵˺ŧǥɧȨɮɫǦǦǥǤƣƤťƥƦƦƧǪǪƧȨȩɩʩʩȨɪʫʪɨɯýʹ̶йĹйζ˯̭̫ʫ˯̳˱˭ɬƨǪƩƥƦŦȧʫȮɫʭˬ̭̪Ϋ̮ˬΫˬ˭ˬȫɬɬƤ¹нϼʵĥǦʫɫƦƦȧƦƥƥȧǧǦȥƥŪƫƩǩǩȫɪʪʭʮʭʮл̺ɫ̭ѶҺкϷγ̮̳α˭ϹѾ̸īƩȩǦƧŨƧȨɫʪ˫̬̬ΫΪέ̮̬ˬ̮̭ʫɪʫǥϽʳƨɩȨǧȧǧɨȧʩʪȨȧȥǧƩŨǪȪʬʭɬʭ̴Ϻſļȫ˪ɬɫɮɭ˱ʮ˭ȩ̰ȿ̹åƥǨȨǩɪ˫˫̫˫̬έϫΫ̮˭̬ˮ̬̩ʪʪǥҽǪȩʩȦȦɧʧɬȭɩɪʬɬƦǨǨʨ˫ɬȱѿĹĹûļпϽʷθɩťƭϼ̸ƦƤʫ̭˭̫̫˫̬έά̭˭̭̬ʭ̬Ϊʪ˭ȧüоǫ˪̪ʩ˪ʨȬȭʭ˫ˮҼ̴Ȫʩ˩ɪɴǼûʹĬưпǭɮ̳αʭɨ̫ή̯̬̭̬˫̬ˮ̬ˬˮǫ¹ɯȪʩȩǫȱɴǬʪʩɫ˯̰̭ʭѿʻο»пνȶǭ˪˩̬̬Ϋ˫ˬ̪ʫɬŪ̸Ȱʷ»Ҿ̶ҹҺηҾùĽ̻ʰ˱˰ʯ˰ζ̶˴̷кν˸̿˿ξ̿̿̿˿˿ɿɿο˾˿̿̿˾̿̿ʿʿʾʾɿʾʾ˿ɿʿʿɾɿɿɿɿʿ̿̾ο̾˿˿ʾ˿̿˿˿ʿ˿˿ʾʽʿʿʿɿɿʿʿɾɿɿʾʾξο̿˿̿˿̾̿˿̿̿˾˾̿˿˿̿˿ʿʾʿɿʿʿʾʿʿʾʿʾʾʿɿʿʿʿ̿̾̾̾˾̿˿˿˾˿˾˿ʿ˿˿˿̿ʿ̿˿ʿ˿˾˿̿˿ʿɿɿ˿ʿ˿ʿʾʿʿɿʽɿɾʽʽʾʾʿʿʾʽʾ̾̿˿̾̿˿̾˿̿ο˿̿˿˿˾˽˾ʿ˾˿˾˿ɿʿ˿̿˿̿˿ʿ˾˾ɿʿ˿ɿʿ˿ɿʽʿʿʾʾɿ˿˾˾ʿ˿˿ʿɿʿʿɿʿɿɽɾʾɿʼʾʾʾɾʿʽʽʽʿȿ˾˾̾̿̿˿˾˾˿̽ʾ˾ʿʿ˿ʿ˾˾ʿɾ˾˿ʾ˿̿ʽʽ˿ʾ˿ʿ˿̿˿˿˾˾ɿʾʽ˾ʿʿʾ˿˿ɿʿʿʿʿʿʿʾʿɾɾʽɿʿʽʾɿʽ˾ʾɾɾ˼ʾɿʿɽɾɾɽ˾˾˾˿̿˿˿˿˾˽˾˿˾̾˿̾˿ʿ˾˾ʿ˿˿˿˾ʿɿʽʾɿ̿˿ʿʿ˿ʾʿʿ˾ʾʿʿʿʾʿʾʿ˿˾ʾʿʿɿȿʿ˿ʽʽʾ˿˽ʿʿʿɽɾʿɾʿȿɾʿɿʾʿʿɿʾʽɼɽɾ˾ʿɾɾʻ˽ʼʽ˿˿˿ʿʿ˿ʿ̿̽˿˿˿ʿ˿˾ɿʾ˽̿˿̿˽̾ʿʾ˿˾˿˿˿˾˽˽˽ʿʿ˿ʿʽ˾˿˾˽˽ʾʾ˾ʿʿ˿ɿɿʾʾ˿̿̿ʿʿ˾ʾ˿˿ʿʿʽɾʾʾʿʿʾʿʿʿɿɾʾʿɿʿɿʿʾʿɿʿʽʾ˿ʽʾ˾ʾɿʾʾʾʾʿɿȾȾȿɿɽʿʿɽʼɼɼɼ̾˾ʾɾʽʽʼɽ˾˿ʾ˿ʾʾʿ˾˾ʾ˽˾ʽ˼˾˿ʿʿ˿˽̾˿˾˿ʿ˾˾ʽʽ˽ʽʾ˽˽˽˿ʽʽʾɿɿʽ˾˿̿ʾɿʿʿʾ˾˾˽˾ʿʿɿʿʾʽʾ˿ʿ˾ʽʽ˽ʽʿʽʾʽ˼ʽʿʿʿʿʾʽʾʾɽʾʾɽʼʿʾɾɿɾɽʿ˾˾ɾɿɾʾʾʽɽʽʿȿɾʾʿʾʽɾʾʽɽɾȿȿɿɿɿɿɾȿɿɿʾʼʽɾɽʽɿɾʽɼ˼˾˿˽˽˾ʽ˾˾˼˽˾˾ʽʾ˿˿˿˿ʾʿʿ˾ʿ˾ʽʾ˿ʾʿʿʾ˽ʽʽʽ˿˽ʿʿʽʽʽʽɾɿʽʽʽ˿˾ʾʽ˽ʾɿʿʽʿʿʿʽ˾̿˾ʿ˾˾˼˼˽˾ʾ˽ʽ˾˾ʽɼʽʾɾɾ˾˿̽˾ʿ˾ʿ˽ʽʾʾʿɾʾʾʾʿɾɽ˽ɿɾɽɼʾɾɾɾɾɽʽɼʻʻ˾ɿɾɿȿ˿ɾȾɾɾɼʼʽʽʽɿɾʿʾɿɿȿʼɼɿɽɼʽɾȾȾ˾˿ʿ˿ʼʾʽʽʾʾ˽ʾɽʽ˿ʿʾʾʽ˽˾ʿɿɿʿʿʿʿʿʽʾʽʽʾʽʿʿʽ˾ʽʿɿɾɾʿʽɿɾʾʽʽ˼˽ʽʼʽʾʾɿʼʽʿʿʾ˽˽ɿȿɿɿʾʼ˼˽ʿʿɽʽʽʽʿɾʻʽɽʽʾ˿ʽ˼ʾʽʽɾɾɿɿɽʽʽɽʼɼɽɾɾʿʾʼɽɾɼʽʾɿȾɽ˻˻ɽɾɿɾɾɽʽʾʽʼɽɽɽʼ˼ɼɾȾȾȿȿɾɽɽȽɼɽʼʼɼɽɾȾ˿ʿʾʿʽ˾ʾʽʽ˿ɾ˾ɿʽʽʽʽɾɿʿʽʽɾʾʿɿ˽ʽɽ˾ʽ˽ʼʽʾʾʼ˾ʽʼɽȿɽ˾ʾʽʽʽʾʼʾʾʼ˼˽ɿʾɾʼɾʾʾʽʽʿɿʿ˿ɾʼʽɿʽʽ˼˼ɾɿɿɾʽʽʽʽɾʿʾʿʽʽʾ˿˽˼˼ʾʽʾ˼ʽɿɿɿʾʾʾȼʻʼʽ˽ʼʽʾʽɽɾɼʼɽɽɽɽɾʽʽȾɾɼʼʽʽ˻ʼʽɼɽɽʼʼɽɽʿȾȼʼʽɼɼɼɼʻɼɽʽɼɼqmapshack-1.10.0/msvc_64/Help.ico000644 001750 000144 00000022676 12705713523 017611 0ustar00oeichlerxusers000000 000000 00 %(0` % PP ^):GUbbUG:)^  7_~~_7  iUUi L~~L 8&yy&8]< ccOO<]]S--պ S]8SS8<׿<&))&i yѱy i LȜYYL ~ʢxx~U7711U^  ^77 __ P~JJΪΪΪΪΪuu~P)hhˣ):\\ӵ:GDDGU̦Ubɟȝbb!!׾bUGG((UGEE11G:44:)չ)P~==~P _<<Ȝ_ 77^ Ҵ ^UIIU~))KK~ LֻwwJJ44GGȝL i yKKy i&rrԸ&<Ӷ!!<8S[[Է!!S8]S88ѲSSS]]< PPddwwqq``??<]8&yy&8 L~~L iUUi  7_~~_7  ^):GUbbUG:)^ PP qmapshack-1.10.0/msvc_64/3rdparty.txt000644 001750 000144 00000004325 12727447634 020540 0ustar00oeichlerxusers000000 000000 ############################################################# # QMapShack for Windows dependencies # ############################################################# This installation of QMapShack for Windows (short: QMS) has been build with Visual Studio 2013 as 64bit application. If you want to build QMS on your own, have a look at https://bitbucket.org/maproom/qmapshack/wiki/BuildWindowsVisualStudio Dependencies ============ QMS depends on the 3rd party software listed below: 1.) Microsoft Visual C++ 2013 Redistributable Package The installer vcredist_x64.exe (ca 7MB size) as downloaded from http://www.microsoft.com/en-us/download/details.aspx?id=40784 is already contained in the QMS Installer package and will be executed if selected by the user. Note: Those runtime libraries may already be contained in Windows 7 or Windows 8 installations. 2.) Qt5 runtime libraries The Qt DLL's are deployed in the QMS installation directory. They are part of Qt which you can download here: http://qt-project.org/downloads 3.) The GDAL library, http://www.gdal.org/ 4.) The PROJ library http://trac.osgeo.org/proj/ 5.) Icons for the Windows Start Menu ==> We should get rid of them and use own icons kfm_home.ico has been created from the Nuvola 1.0 icon set (http://www.icon-king.com/projects/nuvola/) gdalicon.ico has been converted from gdalicon.png from the GDAL package 6.) The routino library Source code is available http://www.routino.org/ This QMapShack installation uses a routino library which is precompiled with mingw64 to reduce porting efforts 7.) MinGW64, http://mingw-w64.org The mingw64 compiler is used to compile the routino library. This resulting library depends from mingw64 runtime libraries such as libwinpthread-1.dll, libz-1.dll which are also included in this installation 8.) MariaDB, https://mariadb.com/ For MySql/MariaDB support, the Qt mysql plugin needs libmysql.dll. This DLL can be downloaded as part of the precompiled MariaDB binaries at https://downloads.mariadb.org/mariadb/+releases/ For the current QMS binary distribution, libmysql.dll is taken from mariadb version 10.1.11: https://downloads.mariadb.org/mariadb/10.1.11/ --> mariadb-10.1.11-winx64.zip qmapshack-1.10.0/msvc_64/build_routino.bat000644 001750 000144 00000003476 12705713524 021571 0ustar00oeichlerxusers000000 000000 rem Batch file to compile routino for Windows using mingw64 rem Please adapt environment variables in section 1) to your system rem Routino source download: see http://www.routino.org/software/ rem Prerequisite: mingw64 toolchain installation rem http://mingw-w64.org/doku.php ==> http://mingw-w64.org/doku.php/download/win-builds rem Download msys as described in http://sourceforge.net/p/mingw-w64/wiki2/MSYS/ rem from http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29/ rem Unzip to C:\msys rem Download from http://win-builds.org/doku.php/download_and_installation_from_windows rem http://win-builds.org/1.5.0/win-builds-1.5.0.exe rem Section 1.) Environment variables rem ROUT_SRC_PATH: location of the routino sources (svn or extracted from archive) set ROUT_SRC_PATH="M:\src\routino" rem ROUT_PKG_PATH: directory where to store deplyment artifacts rem such as compiled binaries, header files, xml configuration files set ROUT_PKG_PATH="M:\src\routino_pkg" rem add mingw64 toolchain to PATH set PATH=C:\msys\bin;%PATH% set PATH=C:\msys\opt\windows_64\bin;%PATH% rem Section 2.) Compile routino cd /d %ROUT_SRC_PATH% make clean make rem Section 2.) Deploy routino del /s/q %ROUT_PKG_PATH% mkdir %ROUT_PKG_PATH% cd /d %ROUT_PKG_PATH% mkdir bin copy %ROUT_SRC_PATH%\src\*.exe bin mkdir doc xcopy %ROUT_SRC_PATH%\doc doc /s /i mkdir lib copy %ROUT_SRC_PATH%\src\routino.dll lib copy %ROUT_SRC_PATH%\src\routino.lib lib mkdir include copy %ROUT_SRC_PATH%\src\routino.h include mkdir xml copy %ROUT_SRC_PATH%\xml\tagging*.xml xml copy %ROUT_SRC_PATH%\xml\routino-profiles.xml xml\profiles.xml copy %ROUT_SRC_PATH%\xml\routino-tagging.xml xml\tagging.xml copy %ROUT_SRC_PATH%\xml\routino-translations.xml xml\translations.xml pause qmapshack-1.10.0/msvc_64/copyfiles.bat000644 001750 000144 00000010316 13063701351 020670 0ustar00oeichlerxusers000000 000000 rem Batch file to copy the necessary files for the Windows Installer rem Please adapt environment variables in section 1) to your system rem useful links rem http://technet.microsoft.com/en-us/library/bb491035.aspx rem http://vlaurie.com/computers2/Articles/environment.htm rem Section 1.) Define path to Qt, MSVC, .... installations set QMSI_QT_PATH="C:\Qt5\5.5\msvc2013_64" rem get the VC redistributable installer from http://www.microsoft.com/en-us/download/details.aspx?id=40784 set QMSI_VCREDIST_PATH="M:\deploy" rem set QLGTI_LIBEXIF_PATH="D:\qlgt\tools\libexif" set QMSI_GDAL_PATH="M:\lib\gdal" set QMSI_PROJ_PATH="M:\lib\PROJ" set QMSI_ROUT_PATH="M:\src\routino_pkg" set QMSI_QUAZIP_PATH="M:\lib\quazip" rem runtime libraries from mingw/msys - in my installation originally at C:\msys\opt\windows_64\bin set QMSI_MGW6_PATH="M:\lib\mingw64" rem runtime libraries from mysql/mariadb rem ToDo: describe from where to get - could this be optional? set QMSI_MSQL_PATH="M:\lib\mysql" rem And finally of courss the path to your build directory! set QMSI_BUILD_PATH="..\..\build\" rem Section 2.) Copy Files del /s/q Files mkdir Files cd Files rem Section 2.1) Copy Qt files copy %QMSI_QT_PATH%\bin\Qt5Core.dll copy %QMSI_QT_PATH%\bin\Qt5Gui.dll copy %QMSI_QT_PATH%\bin\Qt5Multimedia.dll copy %QMSI_QT_PATH%\bin\Qt5MultimediaWidgets.dll copy %QMSI_QT_PATH%\bin\Qt5Network.dll copy %QMSI_QT_PATH%\bin\Qt5OpenGL.dll copy %QMSI_QT_PATH%\bin\Qt5Positioning.dll copy %QMSI_QT_PATH%\bin\Qt5PrintSupport.dll copy %QMSI_QT_PATH%\bin\Qt5Qml.dll copy %QMSI_QT_PATH%\bin\Qt5Quick.dll copy %QMSI_QT_PATH%\bin\Qt5Script.dll copy %QMSI_QT_PATH%\bin\Qt5Sensors.dll copy %QMSI_QT_PATH%\bin\Qt5Sql.dll copy %QMSI_QT_PATH%\bin\Qt5Svg.dll copy %QMSI_QT_PATH%\bin\Qt5WebChannel.dll copy %QMSI_QT_PATH%\bin\Qt5WebKit.dll copy %QMSI_QT_PATH%\bin\Qt5WebKitWidgets.dll copy %QMSI_QT_PATH%\bin\Qt5Widgets.dll copy %QMSI_QT_PATH%\bin\Qt5Xml.dll copy %QMSI_QT_PATH%\bin\icudt54.dll copy %QMSI_QT_PATH%\bin\icuin54.dll copy %QMSI_QT_PATH%\bin\icuuc54.dll copy %QMSI_QT_PATH%\bin\libEGL.dll copy %QMSI_QT_PATH%\bin\libGLESv2.dll mkdir imageformats cd imageformats copy %QMSI_QT_PATH%\plugins\imageformats\qgif.dll copy %QMSI_QT_PATH%\plugins\imageformats\qjpeg.dll copy %QMSI_QT_PATH%\plugins\imageformats\qmng.dll copy %QMSI_QT_PATH%\plugins\imageformats\qsvg.dll copy %QMSI_QT_PATH%\plugins\imageformats\qtiff.dll copy %QMSI_QT_PATH%\plugins\imageformats\qico.dll copy %QMSI_QT_PATH%\plugins\imageformats\qtga.dll cd .. mkdir sqldrivers cd sqldrivers copy %QMSI_QT_PATH%\plugins\sqldrivers\qsqlite.dll copy %QMSI_QT_PATH%\plugins\sqldrivers\qsqlmysql.dll copy %QMSI_QT_PATH%\plugins\sqldrivers\qsqlodbc.dll copy %QMSI_QT_PATH%\plugins\sqldrivers\qsqlpsql.dll cd .. mkdir platforms cd platforms copy %QMSI_QT_PATH%\plugins\platforms\qwindows.dll cd .. mkdir printsupport cd printsupport copy %QMSI_QT_PATH%\plugins\printsupport\windowsprintersupport.dll cd .. rem Qt translations rem Qt5: see http://doc.qt.io/qt-5/linguist-programmers.html mkdir translations copy %QMSI_QT_PATH%\translations\qtbase_??.qm translations rem section 2.2) Copy GDAL and PROJ.4 Files rem put them in the same directory as the .exe for better testing rem section 2.2.1) GDAL xcopy %QMSI_GDAL_PATH%\data data /s /i copy %QMSI_GDAL_PATH%\bin\*.dll copy %QMSI_GDAL_PATH%\bin\*.exe rem section 2.2.4) PROJ.4 xcopy %QMSI_PROJ_PATH%\share share /s /i copy %QMSI_PROJ_PATH%\bin\*.dll copy %QMSI_PROJ_PATH%\bin\proj.exe rem section 2.2.5) Routino copy %QMSI_ROUT_PATH%\lib\routino.dll copy %QMSI_ROUT_PATH%\bin\planetsplitter.exe copy %QMSI_MGW6_PATH%\libwinpthread-1.dll copy %QMSI_MGW6_PATH%\libz-1.dll xcopy %QMSI_ROUT_PATH%\xml routino-xml /s /i rem section 2.2.6) MySql/MariaDB copy %QMSI_MSQL_PATH%\libmysql.dll rem section 2.2.7) QuaZip copy %QMSI_QUAZIP_PATH%\lib\quazip5.dll rem section 2.3) Copy MSVC Redist Files copy %QMSI_VCREDIST_PATH%\vcredist_x64.exe rem section 2.4) Copy QMapShack Files copy %QMSI_BUILD_PATH%\bin\Release\qmapshack.exe copy %QMSI_BUILD_PATH%\src\*.qm translations copy ..\*.ico rem section 2.5) 3rd party SW description copy ..\3rdparty.txt rem section 2.6) qt.conf copy ..\qt.conf pause qmapshack-1.10.0/CMakeLists.txt.user000644 001750 000144 00000041375 13216663405 020457 0ustar00oeichlerxusers000000 000000 EnvironmentId {866bca39-16eb-4541-961c-07f20b41e42e} ProjectExplorer.Project.ActiveTarget 0 ProjectExplorer.Project.EditorSettings true false true Cpp CppGlobal QmlJS QmlJSGlobal 2 UTF-8 false 4 false 80 true true 1 true false 0 true true 0 8 true 1 true true true false ProjectExplorer.Project.PluginSettings ProjectExplorer.Project.Target.0 Qt 5.6.2 (qt5) Qt 5.6.2 (qt5) {8715122a-3e83-46ae-83d4-72f9a7d29e4c} 0 0 0 BUILD_FOR_LOCAL_SYSTEM:BOOL=ON CMAKE_BUILD_TYPE:STRING=Debug CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-7 CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-7 CMAKE_INSTALL_PREFIX:PATH=/usr CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} UPDATE_TRANSLATIONS:BOOL=OFF /home/oeichler/Code/cpp/build_QMapShack -j8 all true CMake Build CMakeProjectManager.MakeStep 1 Build ProjectExplorer.BuildSteps.Build clean true CMake Build CMakeProjectManager.MakeStep 1 Bereinigen ProjectExplorer.BuildSteps.Clean 2 false Vorgabe Vorgabe CMakeProjectManager.CMakeBuildConfiguration 1 0 Deployment ProjectExplorer.BuildSteps.Deploy 1 Lokales Deployment ProjectExplorer.DefaultDeployConfiguration 1 false false 1000 true false false false false true 0.01 10 true 1 25 1 true false true valgrind 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 qmapshack /home/oeichlerx/Code/cpp/build_QMapShack/bin 2 qmapshack CMakeProjectManager.CMakeRunConfiguration.qmapshack 3768 false true false false true false false 1000 true false false false false true 0.01 10 true 1 25 1 true false true valgrind 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 qmaptool /home/oeichlerx/Code/cpp/build_QMapShack/bin -1 qmaptool (deaktiviert) CMakeProjectManager.CMakeRunConfiguration.qmaptool 3768 false true false false true 2 ProjectExplorer.Project.TargetCount 1 ProjectExplorer.Project.Updater.FileVersion 18 Version 18 qmapshack-1.10.0/LICENSE000644 001750 000144 00000104513 12374350216 015736 0ustar00oeichlerxusers000000 000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qmapshack-1.10.0/CPackConfig.cmake000644 001750 000144 00000001665 12765457042 020057 0ustar00oeichlerxusers000000 000000 include(InstallRequiredSystemLibraries) # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings string(TOLOWER ${APPLICATION_NAME} CPACK_PACKAGE_NAME) set(CPACK_PACKAGE_VENDOR "QLandkarte") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GPS Map, Route, Waypoint and Tracking Tool") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") ### versions set(CPACK_PACKAGE_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") set(CPACK_GENERATOR "TGZ") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") ### source package settings set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;[.]hg/;[.]hgsub;[.]hgsubstate;.gitignore;/build/;tags;cscope.*;[.]rej$;[.]orig$;svn-commit[.]") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") include(CPack) qmapshack-1.10.0/templates/000755 001750 000144 00000000000 13216664445 016733 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/templates/header.h000644 001750 000144 00000002051 13051551750 020321 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 . **********************************************************************************************/ #ifndef CLASSNAME_H #define CLASSNAME_H class CLASSNAME { public: CLASSNAME(); virtual ~CLASSNAME() = default; }; #endif //CLASSNAME_H qmapshack-1.10.0/templates/source.c000644 001750 000144 00000001643 13051551741 020372 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "CLASSNAME.h" qmapshack-1.10.0/templates/source.cpp000644 001750 000144 00000001701 13051551725 020727 0ustar00oeichlerxusers000000 000000 /********************************************************************************************** Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de 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 "CLASSNAME.h" CLASSNAME::CLASSNAME() { } qmapshack-1.10.0/config.h.cmake000644 001750 000144 00000001547 12374350216 017431 0ustar00oeichlerxusers000000 000000 #cmakedefine PACKAGE ${APPLICATION_NAME} #cmakedefine VERSION ${APPLICATION_VERSION} #cmakedefine LOCALEDIR ${LOCALE_INSTALL_DIR} #cmakedefine DATADIR ${SHARE_INSTALL_PREFIX} #cmakedefine LIBDIR ${LIB_INSTALL_DIR} #cmakedefine PLUGINDIR ${PLUGINDIR} #cmakedefine SYSCONFDIR ${SYSCONFDIR} #cmakedefine BINARYDIR ${BINARYDIR} #cmakedefine SOURCEDIR ${SOURCEDIR} /* always quote the config dir, as it *will* contain spaces on Mac OS X */ #cmakedefine CONFIGDIR "${CONFIGDIR}" #cmakedefine SHARED_LIB_EXT ${SHARED_LIB_EXT} #cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_INTTYPES_H 1 #cmakedefine HAVE_BYTESWAP_H 1 #cmakedefine HAVE_BIGENDIAN 1 #cmakedefine HAVE_ARC4RANDOM 1 /* build with native file dialogs */ #define FILE_DIALOG_FLAGS ${FILEDIALOGFLAGS} /* TODO add a check */ #define CAN_UNALIGNED 1 /* are we on a 64 bit system? */ #cmakedefine HOST_IS_64_BIT 1 qmapshack-1.10.0/README.md000644 001750 000144 00000002117 13200036556 016202 0ustar00oeichlerxusers000000 000000 You need a working mercurial, g++, cmake and QT5 (at least 5.4) installation to compile QMapShack on your computer. Clone and compile the code base by: hg clone https://bitbucket.org/maproom/qmapshack QMapShack mkdir build_QMapShack cd build_QMapShack ccmake ../QMapShack make To update the code to the cutting edge do in QMapShack: hg pull hg update And change back to build_QMapShack: make As everything is better with a GUI you might want to have a look at [TortoiseHg](https://tortoisehg.bitbucket.io/). Dependencies Next to QT5 you will need the development packages of: * [Qt5](https://www.qt.io/) (at least 5.4) * [GDAL](http://www.gdal.org/) * [Proj4](https://github.com/OSGeo/proj.4/wiki) * [Routino](http://www.routino.org/) (at least 3.0) * [QuaZip](http://quazip.sourceforge.net/index.html) * CMake/Make * a C++ compiler (supporting C++11) If you want to compile QMapShack for Windows have a look [at the wiki](https://bitbucket.org/maproom/qmapshack/wiki/BuildWindowsVisualStudio). qmapshack-1.10.0/changelog.txt000644 001750 000144 00000052461 13216663241 017426 0ustar00oeichlerxusers000000 000000 V 1.10.0 * Fine tune code for screen gestures. [Issue #253] Tracksorting in Datawindow somehow random- should be alphabetical [Issue #254] Selection in Datawindow does not highligt track on map [Issue #257] Diagram - Zoom: Center of zoom should be the mouse position [Issue #276] No-go areas in BRouter [Issue #279] Suunto SML/LOG : wrong start time [Issue #285] Do not add auto-increment number to waypoint names that have no number as last character [Issue #284] Read *.qlb from QLandkarte [Issue #277] Show position of min/max values for track properties like elevation, speed, etc [Issue #275] Some Suunto sml files do not have in first [Issue #274] Make visibility of database a toggle option in the menu [Issue #256] Option to show inclination in % instead of ° [Issue #272] Skip message box when changing an imported item [Issue #271] Drag'n drop missing - Openambit files [Issue #263] Reduce size of y label strings in graphs to avoid unintended truncation [Issue #270] Ask to hide invalid points when loading a GPX file with invalid points. [Issue #265] Inconsistent timestamp formats? V 1.9.1 Add: Fullscreen mode Add: Templates for project documentation Add: FIT: added support for location file (containing waypoints). Add: Trk: Add action to set activity for a group of tracks Add: VRT Builder: Add advanced options (-a_srs -srcndata -vrtndata) Add: Optional auto save for projects Add: Trk: Add activity summary to screen option dialog Add: Prj: Show activity summary for tracks in project details dialog Fix: VRT: Test for overviews on multi-band maps, too Fix: FIT: Fixing missing last segment for records that miss the stop event. Fix: Progress dialog hides other dialogs in certain window managers Fix: Workaround CCanvas loss of mousetracking due to modal CProgressDialog Fix: Jump after pinch gesture [Issue #245] QMS hangs when entering new track name and window sizing in parallel [Issue #243] Incosistent behavior of "copy to ..." dialog [Issue #216] "No activity" statistics column missing in diary [Issue #248] Regularscreen.png vs. RegularScreen.png V 1.9.0 Add: Garmin Maps: Allow external TYP files Add: Filter items on workspace by string Add: GPX: Support for Cluetrust extensions Add: Trk: Add filter to add terrain slope as extension Fix: Issue with time zone in fit files (Zulu instead of local time zone) Fix: GeoCaches: Fix regex to find attached images [Issue #84] Have a floating toolbar with common tools [Issue #232] Zoom on touchscreen using two fingers is very jumpy [Issue #226] Display slope under cursor in status bar [Issue #230] New layout of edit toolbar and POI highlighting [Issue #229] Failure to add point to track V 1.8.1 Fix: Various glitches introduced by the new FIT format Fix: Visual tile artefacts in the DEM layer [Issue #224] Support pinch-gesture [Issue #162] Add "keep last version only" function to objects (tracks, etc...) [Issue #221] Offline BRouter & network access [Issue #225] BRouter: Renaming tiles fails when updating tiles [Issue #215] BRouter (offline) issues (Windows) V 1.8.0 Add: Links to quickstart help Add: Russian translation Add: TCX file read and write support Add: Different cut modes for track cut function Add: Option for optimized build for local system architecture Add: Support for BRouter (online/offline) Add: Enhance reprojection between projections like merc/utm/lcc [Issue #152] Garmin maps: Alter scale to detail level table [Issue #189] Fix drawing of range selection in trkptedit mode [Issue #189] Draw bubble after line to prevent drawing over bubble [Issue #195] Copy errors in message (file)? [Issue #198] Logfile encoding [Issue #201] Provide 'Import GIS data' in database menu [Issue #204] Option to allow only one QMS instance at one time [Issue #211] Desired feature: change symbol for multiple selected waypoints [Issue #213] Adding a Garmin POI as waypoint [Issue #214] Crash when creating Routino database [Issue #217] BRouter setup window - not translated string [Issue #218] CSingleInstanceProxy & Multiuser V 1.7.2 * Add: Export to GPX V1.1 without extensions * Add: Copy a track with all attached waypoints. * Add: Interpolate elevation filter for tracks * Add: Ctrl+W to close tabs that are not a map view * Add: Plot: X&Y zoom and drag graph by left mouse button * Add: Implement filter `Convert SubPoint to Point` * Add: Database: Export database to folders and GPX files * Fix: Trk/Prj: Fixed missing update when changing roadbook mode. Disable copy with waypoints when no waypoints attached. * Fix: Prj: Fix update of project summary when changing the sorting mode * Fix: Trk: Fix nodata values for elevations applied by filter * Fix: Garmin: Fix path for devices that use "GARMIN" instead of "Garmin" in their path * [Issue #168] Invalid GPX 1.1 header? * [Issue #170] No new project when copying track with waypoints * [Issue #52] Track/path features in vector maps hidden by track line * [Issue #171] QMS crashes on "no or bad data" * [Issue #173] Crash with interpolation preview * [Issue #175] Invalid timestamps with MapQuest routing? * [Issue #176] Inconsistent states of diagrams * [Issue #179] Missing activity color selection * [Issue #181] Spelling: ascent vs. ascend, descent vs. descend * [Issue #177] High zoom level when double clicking on waypoint * [Issue #182] Missing project sorting? * [Issue #83] Only zoom every 15deg of mousewheel rotation * [Issue #163] Allow filenames with several '.' * [Issue #184] Track/Route Edit Mode: Move map with left mouse pressed * [Issue #117] Implement storing and loading of subpts as subpts V 1.7.1 * Fix: Compile issue for GCC4 V 1.7.0 * Add: Function to search the database * Add: Sort items in projects by time or name * Add: "Copy To..." for projects * Add: Include waypoint name when creating of a route from waypoints * Add: Database: Add menu item to copy projects from one folder to another * Add: Database: Add menu item to move projects from one folder to another * Fix: No HTML tags for empty strings * Fix: Checkmark for new folders to prevent deleting data by chance. * Clean up code for track activities for futur improvements * [Issue #154]Font size for project description * [Issue #157] Issue when "Save as" a project from Garmin device * [Issue #159] File-/Projectnames with dots get truncated * [Issue #158] QMS incompabilities on different platforms * [Issue #160] Update of diary after adding a waypoint takes very long time * [Issue #102] Allow renaming of Groups, Projects, ... V 1.6.3 * Add FreeBSD support * Enhance editor for descriptions and comments. * [Issue #147] Fix bug preventing list formats to be removed * [Issue #148] Text editor: format of pasted text * [Issue #149] Properly initialize cachePath for systems without QMS configuration (new installations) V 1.6.2 * Add support kFreeBSD ports, treat like Linux. * Add support for GNU/Hurd, treat like Linux. * Trk: Range Selection: Fix bad pointers if point 1 equals point 2 * Trk: Derive valid/invalid flags for elevation and time * Trk: Change filter to remove invalid trackpoints due to flags. * Trk: Optimize waypoint correlation * Trk: Add visible and total index to trackpoint info * Wpt: Allow png as custom symbol * Rte: Add ascend/descend info to routes * Maps: Implement automatic removal of caches for no longer existing maps * Maps: VRT Builder: Set file extension in file dialog for target file * Improve 1st time experience for new users * DB: Properly handle unusable SQLite databases * DB: Don't close application if database can not be migrated * [Issue #128] Show map info on cursor while routing * [Issue #132] GPX file exported from QMS not accepted by Basecamp, Strava and JOSM * [Issue #131] Strange behaviour of filters "Change Speed" and "Hide Invalid Points" in extreme situations * [Issue #134] Possibility to manually edit elevation data of track points (preferably in the table of points) * [Issue #115] Read namespaces for known extensions from .gpx * [Issue #48] No http map access behind proxy * [Issue #30] Create Track of Route * [Issue #141] Additional information for WP in roadbook * [Issue #143] %5 3%4%5 {1 m?} is added to some data in points table * [Issue #144] Crash - reproduceable when viewing track profiles * [Issue #148] Implement "Paste Plain" for CTextEditWidget V 1.6.1 * GUI improvements * Improve render perfomance of DEM layer * Fix: Geocache image download * Fix: OS X: Add planetsplitter * Fix: Bad elevation data if track is created without DEM data loaded * Add: item selection via selection rectangle in the map view * Add: Make combine tracks work over several projects * Add: Add a waypoint by context menu in plots * Add: Read FIT segments and other fixes of reading FIT format * [Issue #109] Implement choosing canvas background color * [Issue #125] Graph issue : previous graph remain displayed when [nothing] is selected * [Issue #121] Distance Values Choose Km/m Miles/feet * [Issue #126] No Printing on Windows V 1.6.0 * Fix: Toggle key focus of on-screen profile * Fix: Printing correct unit in a plot's xLabel instead of `distance [%1]` * Fix: CPlot: Replace hardcoded check for TotalElapsedSeconds() with proper values from the source actually used * Fix: Avoid div-by-zero in case the distance between two points is 0 * Fix: Precision of plot scale for small values * Fix: Implemented linear interpolation for drawing zoomed plots correctly * Fix: Avoid drawing tics outside the plotting area * Add: Additional extensions created by `MIO Cyclo ver. 4.2` * Add: Map/DEM: Add move up/move down to context menu as alternative to drag-n-drop * Add: Support for .slf (Sigma Log Format) files * Add: Support for .fit (Garmin Fitness Format) files * Add: (Trk) Filter to split a single track containing several segments into several tracks * Add: (Trk) Filter to remove extension values * Add: Support for MySQL database * Add: Support for accessing the database from multiple instances at the same time * Add: User info to item history * Add: (Trk) Setup for line width and arrows * Add: (Trk) line coloring: local, global, automatic setup of limits * Add: (Trk) plot limits: local, global, automatic setup of limits * Add: (Trk) colorize track by activity * Add: Adventures to Garmin devices. Projects are stored as adventure. * Add: "Archive" folder for Garmin devices. * Add: Show/hide action for projects on devices. * Add: Support GEMF raster maps * Add: Make custom waypoint symbols path configurable * Add: Reflect partially loaded projects in the checkbox state * [Issue #80] Selected segment by select tool diseappears when zoom +- or pan * [Issue #86] Updating map path when adding new maps * [Issue #91] undo last change crashes qmapshack when drawing a track or a route * [Issue #89] *.GPX files are not recognized * [Issue #100] Show file/server when hovering a database * [Issue #106 ] Profil with no or bad data does not open trackdetails * [Issue #107] Patches for 'original' & 'debugging' typos * [Issue #108] Use the correct order of extensions for Garmin TPX1 * [Issue #112] correct display of menu entries on OS-X for all languages. * A lot of lttle GUI fixes bug fixes and other improvements * Converted code closer to c++11 V 1.5.1 Line edit: Fix broken abort button V 1.5.0 * Add track filter to remove track points with invalid position * Add options to "cut track" function (keep only first or second, keep both) * Add Dutch translation (not finished yet) * Add selection of track properties as source for graphs * Add colorize track by track point properties * [Issue #68] Bubbles not moving when moving the map * [Issue #67] "Save Map Screenshot" does not save grid correctly * [Issue #69] "light gray" colored tracks are displayed in "dark blue" when imported from GPX file * [Issue #72] Database/Workspace inconsisteny in QMS 1.4.0 * [Issue #70] Removed maximumSize for comboGrades * [Issue #19] Map-drag resizes or moves window with KDE 5 * Many little bugfixes, some of them causing random crashes V 1.4.0 * Export selected map area to image or printer * Add activity to trackpoints to differentiate track statistic * Add dialog to setup coord. format * Add option to send console debug output to a logfile * Add `Show on/Hide from Map` in context menu of one or more projects * Add closing the `Track Profile` view via keypress ESC * Add stepwise aborting of current operation in `Add Track/Route/Area` (similar to using right mouse / button `Abort`) * Fix: Qt5 internal translations for Linux * Fix: Line Edit usage hint is not removed on abort * Fix: OS X, various path issues. (icon path, workspace not saved) * Map: Fix race conditions in WMTS/TMS map handler * Map: Add hint for missing SSL library when using WMTS/TMS maps * Map: Slowdown automatic map panning * Trk: Fix Douglas-Peuker filter * Trk: Read & write 3rd party track point extensions * Trk: extend track point info by extension values * [Issue #57] Trk: Fix color table for green and gray * [Issue #59] Not possible to change names of empty projects * [Issue #60] Tab label is not updated when track name is changed * [Issue #54] In tracks editor, mouse cursor does not change according to selected tool with keyboard shortcut * [Issue #64] Install QMapShack icon in hicolor theme too. * [Issue #65] loading routino XML files fixed (added to bundle and support for OS-X specific directory structure). * [Issue #61] Add average speed to selected area statistics popup * [Issue #32] Add arrows to indicate edited track direction V 1.3.1 * Add OS X support. * Moved to libRoutiono provided by the offcial Routino release * Add MapQuest as online routing service * Add edit details dialog for routes * Display instructions on highlighted routes. * Speed up projects with many tracks and waypoints * Add all tracks summary to project details * Insert new projects on top of device entries in the workspace * Fix random crashes due to multi threaded data access * Add device name to extended item name. * Add "City" waypoint icons * Fix race condition when creating new items * Optimize creating new waypoints in a row * Add a new progress dialog and fix many problems with displaying progress * Add routes to project details (diary) * Avoid crash in project details page when switching the sort mode to fast * Fix random crash when restoring the workspace * Fix some crashes due to lack of thread serialization * Project details: Fix crash on resize and other reentrant problems. * Fix crash when route on-the-fly * Waypoint details: Move history to tab * Track profile: Fix DEM line for units other than metric * History: Add sanity checks when restored from database. * Plot: Add zoom for x axis * Replaced CGetOpts with Qt QCommandLineParser * [Issue #33] Add a summary table (distance, ascent, descent) when editing tracks * [Issue #34] First point of edited track does not behave as next ones * [Issue #35] Routing using Routino : crash when route is too long * [Issue #37] "Select" tool issue when editing tracks * [Issue #39] Not possible to change names of objects with no name * [Issue #31] Add hotkeys for track editor buttons * [Issue #49] Hide screen option when buttons are pressed. * And many other small fixes... V 1.3.0 * Cluttered items select: make text sensitive, too * TwoNav: Fix problems with decoding records created with old firmware. * [Issue #20] Add command "Duplicate View" * Ask for saving chnages when closing db project via db folder check box * Rework user interface to edit line items (tracks, routes, areas) * Add Routino as offline auto-router * Add GUI tool to create Routino database files * Rte: Create route from selected waypoints * Complete lines via router in line edit mode * View: Fix bad scaling on startup when using square scale * [Issue #25] Saved tracks get wrong timestamps * [Issue #23] Update French translation and fix missleading translation * Trk/Wpt: Make track/waypoint correlation an option if it takes too long. * Workspace: Add warning when loading a project twice * Speed up project file loading * Trk: Allow combining tracks for tracks on devices. * Trk: Allow pre-selection of several tracks for combining tracks * Many GUI fixes and code cleanup. V 1.2.2 * TwoNav: Find wpt files created from device in the TwoNavData folder * Wpt: Display waypoint description/comment as bubble * Add option to choose between long and short date/time format * Proj/Trk: Add new sort mode to attach waypoints only once to a track V 1.2.1 * Add drag-n-drop of gpx and qms files to QMapShack * Fix wait cursor when asking to save project * [Issue #15] Using Garmin IMG files crashes on machines with small memory * [Issue #16] In Title-bar no Shutdown (Close QMapShack) entry * QlgtDB: Convert distance overlays to tracks * Fix several issues with range selection * Unlock items automatically on edit functions * Database projects: Append name with name of parent database folder or device name * Set write flag for items copied from devices. * Database: Ask before updating items in database * Add project to database directly from workspace * Wpt: Simplyfy adding new waypoints V 1.2.0 * TwoNav: prepend HTML file for waypoint comment with QMS_CMT * Devices: Warn if there is a file/path with the same name, but different key * TwoNav: Link comment file to roadbook waypoints. * Track: Enhance range selection * Track: Add range selection to plots * Canvas: Add option to choose between logarithmic and square scale. * Add button to add a selection online maps * Fix: Some waypoints do not snap on track * [Issue #14] Issue a warning when closing an unsaved project V 1.1.0 * Garmin Mpas: fix line breaks of tooltips * Project summary: Add roadbook mode * TwoNav: export tracks and waypoints as roadbook * Grid: Fixed swaped numbers for northing and easting * Tracks: Toggle between small OSD profile and extended profile * Tracks: Several fixes for range selection * Tracks: Show waypoints along track in profile plot V 1.0.1 * [Issue #11]Exclude items not visible from highlighting * Fix track edit hangup for tracks with corrupted timestamps * GPX: fix bad loading of trak colors from GPX * Add menu to track graphs to save graph to PNG * [Issue #7] Store/restore list of active maps into/from a file * Disable lock button for items on devices V 1.0.0 * Update Czech, French, German and Spanish translation * Fix dialogs hiding behind main window * Fix various application crashes * Fix tile cache growing too large * Fix cliff polylines in Garmin maps * Add device support on Windows * Various little GUI optimizations V 1.0.beta1 * Add support for TwoNav units * Load/Restore images attached to waypoints on devices * Add spoiler download to geocaches. * Add group update for projects on devices. * GUI cleanup and little fixes V 0.12.0 * Fix: Workspace is not saved on Windows. * Fix: Bad track color names * Add device watcher for Linux * Add basic device support for newer Garmin units. V 0.11.0 * Auto-switch projection for pole caps in track plot * Fix several issues with elements derived from existing ones still having the same key. * Add project diary (project details) * Add track filter to reset hidden track points to visible * Save only changed items to database (speed up) * Add photo album and viewer to waypoint details V 0.10.0 * Fix crash when saving a DB project before the database tree has been opened * Add track filters to hide trackpoints * Add track filters to change elevation * Add track filters to change timestamp * Add DEM layer to colorize the slope * Fix issue with duplicate key when reversing a track * Add project selection for all track operations V 0.9.1 * Complete function of 'Lost & Found' folder * Add copy function to all items including dialog to select copy action. * Workspace: move status column to column 0 V 0.9.0 * Fix sign of area calculation * Mark item with user focus in item unclutter screen * Add support for multiple databases * Add converter for QLandkarte GT to QMapShack database V 0.8.2 * Calculate area covered by area overlays * Change coordinate format for long/lat grid from dd mm.mm to dd.dddddd * Add edit widget for project details * Add drag-n-drop for multiple GIS items * Enhance delete of multiple items V 0.8.1 * Handle "no data" values in DEM files * Garmin maps: read copyright information * Save/Restore workspace on exit/start V 0.8.0 * Add unit setup (metric, imperial, nautical) * Add data serialization for track, waypoint, route and area * Add binary *.qms format to store projects without any loss of data * Enhance item history to perform full undo and redo * Many little fixes and enhancements V 0.7.0 * Add Google GIS search * Add support for TMS maps * Snap to line for track and area edit V 0.6.0 * Reverse tracks * Add dialog to combine tracks * Add range select to tracks * Add function to hide/show track points * Add function to copy selected track points as new track V 0.5.0 * Add support for WMTS maps * Edit/create tracks * Edit/create area overlays * Add contrast factor to hillshading V 0.4.0 * Add position dialog to "add waypoint" * Beautify waypoint edit dialog * Add on-screen information and detail dialog for tracks * Add drag-n-drop to workspace list to move items (draw order & copy between projects) V 0.3.1 * another favour for Debian release * Added "Add Waypoint" to mouse context menu V 0.3.0.bureaucratic * Add copyright notice to GpxExamples to satisfy bureaucrats @ debian V 0.3.0 * A lot of little fixes to prevent crashes and glitches due to multithreading * Take special care of the +-180 degree problem * Add RGB support to raster maps * Add a lot of cursor stuff to select items and to display on-screen-options * Add timezone support * Add dialog to view/edit waypoint data * Add 'moving waypoint' and 'project waypoint' as functions to on-screen-options qmapshack-1.10.0/CMakeLists.txt000644 001750 000144 00000007135 13216661201 017466 0ustar00oeichlerxusers000000 000000 cmake_minimum_required(VERSION 3.0.0) project(QMapShack) option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) if(WIN32) option(USE_QT5DBus "Enable device detection via DBus" OFF) else(WIN32) option(USE_QT5DBus "Enable device detection via DBus" ON) endif(WIN32) # Needed to properly handle extract translations strings when using the Ninja # generator. if (COMMAND CMAKE_POLICY) if (POLICY CMP0058) cmake_policy(SET CMP0058 NEW) endif() endif() if(WIN32) set(QT_DEV_PATH "C:\\Qt5\\5.5\\msvc2013_64" CACHE PATH "Path to directory containing Qt5 include and lib, e.g. C:\\Qt5\\5.5\\msvc2013_64") set(GDAL_DEV_PATH "C:\\GDAL" CACHE PATH "Path to directory containing GDAL include and lib, e.g. M:\\lib\\gdal") set(PROJ_DEV_PATH "C:\\PROJ" CACHE PATH "Path to directory containing PROJ.4 include and lib, e.g. M:\\lib\\PROJ") set(ROUTINO_DEV_PATH "C:\\routino" CACHE PATH "Path to directory containing routino include and lib, e.g. M:\\lib\\routino") set(QUAZIP_DEV_PATH "C:\\quazip" CACHE PATH "Path to directory containing quazip include and lib, e.g. M:\\lib\\quazip5") set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_DEV_PATH}) endif(WIN32) set(APPLICATION_NAME qmapshack) set(APPLICATION_VERSION_MAJOR "1") set(APPLICATION_VERSION_MINOR "10") set(APPLICATION_VERSION_PATCH "0") add_definitions(-DVER_MAJOR=${APPLICATION_VERSION_MAJOR} -DVER_MINOR=${APPLICATION_VERSION_MINOR} -DVER_STEP=${APPLICATION_VERSION_PATCH} -DAPPLICATION_NAME=${PROJECT_NAME}) if (APPLE) set(PROGNAME "QMapShack") set(CONFIGDIR "Library/Application Support/${PROGNAME}/") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_INIT} -Wall -std=c++11 -stdlib=libc++") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.7") else(APPLE) set(PROGNAME qmapshack) set(CONFIGDIR ".config/QLandkarte/") endif(APPLE) if(MSVC) # Add link-time code generation to improve performance set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") endif(MSVC) # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules ) # Bring translation support in include(TranslateTs) include(TranslateDesktop) # add definitions include(DefineCMakeDefaults) include(DefineCompilerFlags) include(DefineInstallationPaths) include(CPackConfig.cmake) include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) find_package(ALGLIB) if(NOT ALGLIB_FOUND) set(ALGLIB_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/alglib/src) set(ALGLIB_LIBRARIES alg) add_subdirectory(3rdparty/alglib) endif(NOT ALGLIB_FOUND) add_subdirectory(src) if (UNIX AND NOT WIN32 AND NOT APPLE) install( FILES src/icons/48x48/QMapShack.png DESTINATION ${DATA_INSTALL_PREFIX}/pixmaps ) install( DIRECTORY src/icons/hicolor DESTINATION ${ICON_INSTALL_DIR} ) install( FILES qmapshack.1 DESTINATION ${MAN_INSTALL_DIR}/man1 ) endif (UNIX AND NOT WIN32 AND NOT APPLE) CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") qmapshack-1.10.0/MacOSX/000755 001750 000144 00000000000 13216664445 016027 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/bundle.sh000755 001750 000144 00000025652 13064675145 017651 0ustar00oeichlerxusers000000 000000 #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $DIR/env-path.sh APP_VERSION=0 BUILD_TIME=$(date +"%y-%m-%dT%H:%M:%S") BUILD_HASH_KEY=0 function buildIcon { rm -rf $BUILD_BIN_DIR/$APP_NAME.iconset mkdir $BUILD_BIN_DIR/$APP_NAME.iconset sips -z 16 16 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_16x16.png sips -z 32 32 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_16x16@2x.png sips -z 32 32 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_32x32.png sips -z 64 64 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_32x32@2x.png sips -z 128 128 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_128x128.png sips -z 256 256 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_128x128@2x.png sips -z 256 256 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_256x256.png sips -z 512 512 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_256x256@2x.png sips -z 512 512 $SRC_RESOURCES_DIR/$APP_NAME.png --out $BUILD_BIN_DIR/$APP_NAME.iconset/icon_512x512.png cp -v $SRC_RESOURCES_DIR/$APP_NAME.png $BUILD_BIN_DIR/$APP_NAME.iconset/icon_512x512@2x.png iconutil -c icns -o $BUILD_BIN_DIR/$APP_NAME.icns $BUILD_BIN_DIR/$APP_NAME.iconset # rm -r $BUILD_BIN_DIR/$APP_NAME.iconset } function buildAppStructure { # structure bundle # QmapShack.app/ # Contents/ # Info.plist # MacOS/ # QMapShack # Resources/ # QMapShack.icns # Frameworks/ # # PlugIns # rm -rf $BUILD_BUNDLE_DIR mkdir $BUILD_BUNDLE_DIR # predefined data cp -v -R $SRC_RESOURCES_DIR/Contents $BUILD_BUNDLE_DIR # new icon, if one has been created (otherwise the one from predefined data if [ -f "$BUILD_BIN_DIR/$APP_NAME.icns" ]; then cp -v $BUILD_BIN_DIR/$APP_NAME.icns $BUILD_BUNDLE_RES_DIR/ fi # binary mkdir $BUILD_BUNDLE_APP_DIR cp -v $BUILD_BIN_DIR/qmapshack $BUILD_BUNDLE_APP_DIR/$APP_NAME mkdir $BUILD_BUNDLE_RES_QM_DIR mkdir $BUILD_BUNDLE_RES_GDAL_DIR mkdir $BUILD_BUNDLE_RES_PROJ_DIR mkdir $BUILD_BUNDLE_RES_ROUTINO_DIR mkdir $BUILD_BUNDLE_RES_BIN_DIR cp -v $BUILD_BIN_DIR/*.qm $BUILD_BUNDLE_RES_QM_DIR } function qtDeploy { # -no-strip $QT_DIR/bin/macdeployqt $BUILD_BUNDLE_DIR -always-overwrite -verbose=3 } function printLinkingApp { printLinking $BUILD_BUNDLE_APP_FILE for F in `find $BUILD_BUNDLE_FRW_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do printLinking $F done for F in `find $BUILD_BUNDLE_FRW_DIR/Qt*.framework/Versions/5 -type f -maxdepth 1` do printLinking $F done for F in `find $BUILD_BUNDLE_PLUGIN_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do printLinking $F done checkLibraries $BUILD_BUNDLE_APP_FILE for F in `find $BUILD_BUNDLE_FRW_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do checkLibraries $F done for F in `find $BUILD_BUNDLE_FRW_DIR/Qt*.framework/Versions/5 -type f -maxdepth 1` do checkLibraries $F done for F in `find $BUILD_BUNDLE_PLUGIN_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do checkLibraries $F done } function adjustLinking { for F in `find $BUILD_BUNDLE_PLUGIN_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do adjustLinkQt $F "libq" done for F in `find $BUILD_BUNDLE_FRW_DIR/Qt*.framework/Versions/5 -type f -maxdepth 1` do adjustLinkQt $F "Qt" adjustLinkQt $F "libdbus" done for F in `find $BUILD_BUNDLE_FRW_DIR -type f -type f \( -iname "*.dylib" -o -iname "*.so" \)` do adjustLinkQt $F "Qt" adjustLinkQt $F "libroutino" adjustLinkQt $F "libdbus" done adjustLinkQt $BUILD_BUNDLE_APP_FILE "Qt" adjustLinkQt $BUILD_BUNDLE_APP_FILE "libroutino" } function adjustLinkQt { F=$1 # file L=$2 # search condition FREL=${F##*/} for P in `otool -L $F | awk '{print $1}'` do # replace double slashes if [[ "$P" == *//* ]]; then PSLASH=$(echo $P | sed 's,//,/,g') sudo install_name_tool -change $P $PSLASH $F fi LIB=${P##*/} LIB=${LIB%%:} PREL="@executable_path/../Frameworks/$LIB" if [[ "$P" == *".framework"* ]]; then LIB_VERSION=Versions/5 LIB=$LIB.framework/$LIB_VERSION/$LIB PREL="@executable_path/../Frameworks/$LIB" elif [[ "$P" == *"plugins"* ]]; then # subdirectory for PlugIns LIB=${P##*plugins/} # remove prepart PREL="@executable_path/../PlugIns/$LIB" fi #echo "F = $F" #echo "P = $P" #echo "LIB = $LIB" #echo "FREL = $FREL" #echo "PREL = $PREL" #echo "L = $L" #echo "-----" if [[ "$LIB" == *"$FREL" ]]; then echo "name_tool: $FREL >> $PREL ($P)" sudo install_name_tool -id $PREL $F elif [[ "$P" == *$L* ]]; then echo "name_tool: $FREL > $PREL ($P)" sudo install_name_tool -change $P $PREL $F fi done } function checkLibraries { F=$1 # file DIR=${BUILD_BUNDLE_APP_FILE%/*} for P in `otool -L $F | awk '{print $1}'` do if [[ "$P" == "@executable_path"* ]]; then FREL=${P##@executable_path} LIB=${DIR}${FREL} #echo "LIB = $LIB" if [ ! -e $LIB ]; then echo "referenced library not bundled: $P" fi fi if [[ "$P" == "/"* && "$P" != "/System/Library/"* && "$P" != "/usr/lib/"* && "$P" != *":" ]]; then echo "external library: $P" fi done } function copyAdditionalLibraries { cp -v $ROUTINO_LIB_LIB_DIR/libroutino.so $BUILD_BUNDLE_FRW_DIR cp -v $QUAZIP_LIB_LIB_DIR/libquazip.1.dylib $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtSensors.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtPositioning.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtMultimediaWidgets.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtMultimedia.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtWebKitWidgets.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtOpenGL.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtQuick.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtQml.framework $BUILD_BUNDLE_FRW_DIR cp -v -R $QT_DIR/lib/QtWebChannel.framework $BUILD_BUNDLE_FRW_DIR # TODO remove QT Bus, is only for linux needed #cp -v -R $QT_DIR/lib/QtDBus.framework $BUILD_BUNDLE_FRW_DIR } function copyExternalFiles { cp -v $QT_DIR/translations/*_cs.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $QT_DIR/translations/*_de.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $QT_DIR/translations/*_en.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $QT_DIR/translations/*_es.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $QT_DIR/translations/*_fr.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $QT_DIR/translations/*_nl.qm $BUILD_BUNDLE_RES_QM_DIR cp -v $GDAL_DIR/share/gdal/* $BUILD_BUNDLE_RES_GDAL_DIR cp -v $PROJ_DIR/share/proj/* $BUILD_BUNDLE_RES_PROJ_DIR cp -v $ROUTINO_LIB_XML_DIR/profiles.xml $BUILD_BUNDLE_RES_ROUTINO_DIR cp -v $ROUTINO_LIB_XML_DIR/translations.xml $BUILD_BUNDLE_RES_ROUTINO_DIR cp -v $ROUTINO_LIB_XML_DIR/tagging.xml $BUILD_BUNDLE_RES_ROUTINO_DIR } function adjustLinkingExtTools { for F in `find $BUILD_BUNDLE_RES_BIN_DIR -type f ! \( -name "*.py" \)` do adjustLinkQt $F "/usr/local/opt/" adjustLinkQt $F "/usr/local/Cellar/" adjustLinkQt $F "/usr/local/lib/" done } function printLinkingExtTools { for F in `find $BUILD_BUNDLE_RES_BIN_DIR -type f ! \( -name "*.py" \)` do printLinking $F done } function copyExtTools { # at least gdalbuildvrt is used cp -v $GDAL_DIR/bin/* $BUILD_BUNDLE_RES_BIN_DIR cp -v $PROJ_DIR/bin/proj $BUILD_BUNDLE_RES_BIN_DIR cp -v $ROUTINO_LIB_LIB_DIR/planetsplitter $BUILD_BUNDLE_RES_BIN_DIR } function printLinking { echo "--------------------" echo "otool $1" otool -L $1 echo "--------------------" } function archiveBundle { ARCHIVE=$(printf "%s/%s-MacOSX_%s.tar.gz" "$BUILD_RELEASE_DIR" "$APP_NAME" "$APP_VERSION") echo $ARCHIVE rm $ARCHIVE cd $BUILD_RELEASE_DIR tar -zcvf $ARCHIVE $APP_BUNDLE cd .. } function extractVersion { # Version CMakeList.txt # set(APPLICATION_VERSION_MAJOR "1") # set(APPLICATION_VERSION_MINOR "3") # set(APPLICATION_VERSION_PATCH "0.libroutino") MAJOR_VERSION=$(sed -n 's/.*APPLICATION_VERSION_MAJOR.*\"\(.*\)\".*/\1/p' $QMS_SRC_DIR/CMakeLists.txt) MINOR_VERSION=$(sed -n 's/.*APPLICATION_VERSION_MINOR.*\"\(.*\)\".*/\1/p' $QMS_SRC_DIR/CMakeLists.txt) PATCH_VERSION=$(sed -n 's/.*APPLICATION_VERSION_PATCH.*\"\(.*\)\".*/\1/p' $QMS_SRC_DIR/CMakeLists.txt) echo "$MAJOR_VERSION $MINOR_VERSION $PATCH_VERSION" APP_VERSION="$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION" } function readRevisionHash { cd $QMS_SRC_DIR BUILD_HASH_KEY=$(hg --debug id -i) if [[ "$BUILD_HASH_KEY" == *"+"* ]]; then read -p "BEWARE - There are uncommited chagnes..." fi } function updateInfoPlist { /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $APP_VERSION" "$BUILD_BUNDLE_CONTENTS_DIR/Info.plist" /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $APP_VERSION" "$BUILD_BUNDLE_CONTENTS_DIR/Info.plist" /usr/libexec/PlistBuddy -c "Set :BuildHashKey $BUILD_HASH_KEY" "$BUILD_BUNDLE_CONTENTS_DIR/Info.plist" /usr/libexec/PlistBuddy -c "Set :BuildTime $BUILD_TIME" "$BUILD_BUNDLE_CONTENTS_DIR/Info.plist" } if [[ "$1" == "icon" ]]; then buildIcon fi if [[ "$1" == "bundle" ]]; then echo "---extract version -----------------" extractVersion readRevisionHash echo "---build bundle --------------------" buildAppStructure echo "---replace version string ----------" updateInfoPlist echo "---qt deploy tool ------------------" qtDeploy echo "---copy libraries ------------------" copyAdditionalLibraries echo "---copy external files -------------" copyExternalFiles echo "---adjust linking ------------------" adjustLinking echo "---external tools ------------------" copyExtTools adjustLinkingExtTools printLinkingExtTools echo "------------------------------------" # chmod a+x $BUILD_BUNDLE_DIR/Contents/Frameworks/* fi if [[ "$1" == "info" ]]; then printLinkingApp fi if [[ "$1" == "info-before" ]]; then printLinking $BUILD_RELEASE_DIR/$APP_NAME printLinking $LIB_ROUTINO_LIB_DIR/libroutino.so fi if [[ "$1" == "archive" ]]; then extractVersion archiveBundle fi qmapshack-1.10.0/MacOSX/HowtoBuildOSX.txt000644 001750 000144 00000015307 13064675145 021250 0ustar00oeichlerxusers000000 000000 Howto Building QMapShack on OS-X ******************************** This document describes how to build QMapShack on OS-X. All commands listed in this how to are executed in a terminal. Bash version 3 and above must be installed to execute the scripts. Additional Software & Installation ********************************** To be able to build QMapShack there are several software packages and libraries required: - proj4 library (version 4.9.x) - gdal library (version 2.1.x) - qt5 framework (version 5.5.x) - routino library (version 3.1.x) - quazip library (version 0.7.x) - qmapshack - cmake (version 3.x and above) - svn command line tool (for routino) - mercurial (hg) command line tool The best way is to install most of the required packages is by using brew. Download the brew package manager if you not already have: ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" After istalling brew use it to install most of the required packages: brew install proj4 brew install gdal (unfortunately not the newest version is prvided with brew) brew install cmake brew install qt5 --with-d-bus, --with-mysql brew install svn brew install hg The qt5 package needs some patience if you have selected the options "--with-d-bus" and "--with-mysql". But you will need this to successfully build QMapShack. You may also considering to install the qt5 additions "--with-docs --with-examples --with-developer" The routino library source must be downloaded from the SVN repository "http://routino.org/svn/trunk/" built manually. To checkout routino create a new directory where the source should be stored, cd into the directory and checkout routino with the command: svn checkout http://routino.org/svn/trunk/ To make the build easier, there is the bash script "build-routino.sh" in the same directory as this how to. To run the script, you need to set two environment variables in advanced: ROUTINO_LIB_DIR=... (absolute path to directory where the build library and other files will be stored) ROUTINO_SRC_DIR=... (absolute path to directory where the source code will be checked out) Script call: ./build-routino.sh routino-build For building the Quazip library there is the bash script "build-quazip.sh" in the MacOSX subdirectory. The Quazip source has to be downloaded manually from "https://sourceforge.net/projects/quazip/". To run the script, you need to set three environment variables in advanced: QUAZIP_LIB_DIR=.. (absolute path to directory where the build library and other files will be stored) QUAZIP_SRC_DIR=.. (absolute path to directory where the extracted source code has been saved to) QT_DIR=.. (absolute path to directory where QT has been installed to. If done with brew, it is like /usr/local/Cellar/qt5/5.5..) Script call: ./build-quazip.sh quazip-build Building and Bundling QMapShack ******************************* To get the source of QMapShack: hg clone https://bitbucket.org/maproom/qmapshack In the same directory as this how to is the bash script "bundle.sh". The script does all steps for packaging the application but not building the binary. So you need to build the binary first with the command: mkdir build_QMapShack cd build_QMapShack cmake ../QMapShack -DCMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5... -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 -DROUTINO_DEV_PATH=... -DQUAZIP_DEV_PATH=... -DCMAKE_BUILD_TYPE=Release make "QMapShack" is the relative path to where you have checked out QMapShack. The four passed parameter are more or less self describing: CMAKE_PREFIX_PATH path to used libraries by QMapShack, QT5 needs to be set by default. CMAKE_OSX_DEPLOYMENT_TARGET the target system of the build (10.11 is the El Capitan OS-X, see https://en.wikipedia.org/wiki/OS_X#Versions for a full list) ROUTINO_DEV_PATH The path to the routino library (is the same as you set previously with ROUTINO_LIB_DIR) QUAZIP_DEV_PATH The path to the quazip library (is the same as you set previously with QUAZIP_LIB_DIR) CMAKE_BUILD_TYPE "Debug" or "Release" depending what you want. If the build was successful, you can run the packaging with several environment variables set: QT_DIR=... (absolute path to the qt5 library base package, same as in CMAKE_PREFIX_PATH) GDAL_DIR=... (absolute path to the gdal library base package) PROJ_DIR=... (absolute path to the proj4 library base package) ROUTINO_LIB_DIR=.. (absolute path to the routino library base package, same as ROUTINO_LIB_DIR / ROUTINO_DEV_PATH) QUAZIP_LIB_DIR=.. (absolute path to the Quazip library base package) BUILD_DIR=.. (absolute path to the QMapShack build directory, the created directory "build_QMapShack" for the cmake build) QMS_SRC_DIR=... (absolute path to the QMapShack source, the directory "QMapShack" used by cmake) BUILD_BIN_DIR=... (absolute path to the directory with the qmapshack binary, typically build_QMapShack/bin for cmake build; depends on IDE) BUILD_RELEASE_DIR=... (absolute path to the directory where the application bundle should be placed) ./bundle.sh bundle If everything is ok, you will get the package "QMapShack.app" in the directory "BUILD_RELEASE_DIR". Double-click on the package and have fun with QMapShack. Debugging QMapShack ******************* The best way to debug QMapShack is using your IDE. To open QMapShack do for... * Create Xcode project from source: mkdir build_xcode cmake ../QMapShack -G Xcode -D.... The same command as described in the build with cmake, except of the additional option "-G Xcode". * JetBrains CLion: Nothing to be done, just open the Project folder in CLion. You need to set "CMake options" under "Preferences > Build, Execution, Development > CMake". -DCMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5... -DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 -DROUTINO_DEV_PATH=... -DQUAZIP_DEV_PATH=... The list is the same as described for the cmake build above. A note about directory structure in QMapShack ******************************************** QMapShack relies on the directory structure of a OS-X application bundle. This means that you can not run QMapShack correctly if you just make a build (binary) and run this. You need many different files placed with the correct relative path to the binary. If you don't have this, you will get already at the startup of QMapShack an error message (which you can click away at your own risk). The easiest way to have a fully working version from within your IDE of QMapShack: - Create a bundle as described above in "Building and Bundling QMapShack" - Open the bundle QMapShack.app and copy the subdirectory Contents/Resources - Paste the copied directory Resources relative one directory up to the binary qmapshack directory (../Resources) When starting qmapshack now, there shouldn't be an error message anymore. qmapshack-1.10.0/MacOSX/env-path.sh000644 001750 000144 00000003136 13064675145 020110 0ustar00oeichlerxusers000000 000000 #!/bin/bash if [[ "$QT_DIR" == "" ]]; then echo "QT_DIR not set" fi if [[ "$GDAL_DIR" == "" ]]; then echo "GDAL_DIR not set" fi if [[ "$PROJ_DIR" == "" ]]; then echo "PROJ_DIR not set" fi if [[ "$ROUTINO_LIB_DIR" == "" ]]; then echo "ROUTINO_LIB_DIR not set" fi if [[ "$QUAZIP_LIB_DIR" == "" ]]; then echo "QUAZIP_LIB_DIR not set" fi if [[ "$BUILD_DIR" == "" ]]; then echo "BUILD_DIR not set" fi if [[ "$QMS_SRC_DIR" == "" ]]; then echo "QMS_SRC_DIR not set" fi if [[ "$BUILD_BIN_DIR" == "" ]]; then echo "BUILD_BIN_DIR not set" fi if [[ "$BUILD_RELEASE_DIR" == "" ]]; then echo "BUILD_RELEASE_DIR not set" fi set -a APP_NAME=QMapShack APP_BUNDLE=$APP_NAME.app SRC_OSX_DIR=$QMS_SRC_DIR/MacOSX SRC_RESOURCES_DIR=$SRC_OSX_DIR/resources BUILD_BUNDLE_DIR=$BUILD_RELEASE_DIR/$APP_BUNDLE BUILD_BUNDLE_CONTENTS_DIR=$BUILD_BUNDLE_DIR/Contents BUILD_BUNDLE_APP_DIR=$BUILD_BUNDLE_DIR/Contents/MacOS BUILD_BUNDLE_RES_DIR=$BUILD_BUNDLE_DIR/Contents/Resources BUILD_BUNDLE_FRW_DIR=$BUILD_BUNDLE_DIR/Contents/Frameworks BUILD_BUNDLE_PLUGIN_DIR=$BUILD_BUNDLE_DIR/Contents/PlugIns BUILD_BUNDLE_APP_FILE=$BUILD_BUNDLE_APP_DIR/$APP_NAME BUILD_BUNDLE_RES_QM_DIR=$BUILD_BUNDLE_RES_DIR/translations BUILD_BUNDLE_RES_GDAL_DIR=$BUILD_BUNDLE_RES_DIR/gdal BUILD_BUNDLE_RES_PROJ_DIR=$BUILD_BUNDLE_RES_DIR/proj BUILD_BUNDLE_RES_ROUTINO_DIR=$BUILD_BUNDLE_RES_DIR/routino BUILD_BUNDLE_RES_BIN_DIR=$BUILD_BUNDLE_CONTENTS_DIR/Tools ROUTINO_LIB_LIB_DIR=$ROUTINO_LIB_DIR/lib ROUTINO_LIB_H_DIR=$ROUTINO_LIB_DIR/include ROUTINO_LIB_XML_DIR=$ROUTINO_LIB_DIR/xml QUAZIP_LIB_LIB_DIR=$QUAZIP_LIB_DIR/lib QUAZIP_LIB_H_DIR=$QUAZIP_LIB_DIR/include set +a qmapshack-1.10.0/MacOSX/build-quazip.sh000755 001750 000144 00000002566 13064675145 021005 0ustar00oeichlerxusers000000 000000 #!/bin/bash if [[ "$QUAZIP_LIB_DIR" == "" ]]; then echo "QUAZIP_LIB_DIR not set" fi if [[ "$QUAZIP_SRC_DIR" == "" ]]; then echo "QUAZIP_SRC_DIR not set" fi if [[ "$QT_DIR" == "" ]]; then echo "QT_DIR not set" fi if [[ "$QUAZIP_BUILD_DIR" == "" ]]; then QUAZIP_BUILD_DIR=$QUAZIP_SRC_DIR/../build_quazip fi QUAZIP_LIB_LIB_DIR=$QUAZIP_LIB_DIR/lib QUAZIP_LIB_H_DIR=$QUAZIP_LIB_DIR/include # build function buildQuazipLib { rm -R $QUAZIP_BUILD_DIR/* mkdir $QUAZIP_BUILD_DIR cd $QUAZIP_BUILD_DIR PATH=$PATH:$QT_DIR/bin qmake $QUAZIP_SRC_DIR -config release LIBS+=-lz make } # copy function copyQuazipFiles { rm -R $QUAZIP_LIB_DIR mkdir $QUAZIP_LIB_DIR mkdir $QUAZIP_LIB_LIB_DIR mkdir $QUAZIP_LIB_H_DIR cp $QUAZIP_SRC_DIR/quazip/*.h $QUAZIP_LIB_H_DIR cp $QUAZIP_BUILD_DIR/quazip/libquazip.1.0.0.dylib $QUAZIP_LIB_LIB_DIR cp $QUAZIP_BUILD_DIR/quazip/libquazip.1.0.0.dylib $QUAZIP_LIB_LIB_DIR/libquazip.1.dylib cp $QUAZIP_BUILD_DIR/quazip/libquazip.1.0.0.dylib $QUAZIP_LIB_LIB_DIR/libquazip5.dylib chmod a+rx $QUAZIP_LIB_LIB_DIR/* chmod a+r $QUAZIP_LIB_H_DIR/* cp $QUAZIP_LIB_LIB_DIR/libquazip.1.0.0.dylib /usr/local/lib/libquazip.1.dylib } function adjustLinking { sudo install_name_tool -id $QUAZIP_LIB_LIB_DIR/libquazip.1.dylib $QUAZIP_LIB_LIB_DIR/libquazip.1.dylib } if [[ "$1" == "quazip-build" ]]; then buildQuazipLib copyQuazipFiles adjustLinking fiqmapshack-1.10.0/MacOSX/resources/000755 001750 000144 00000000000 13216664445 020041 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/000755 001750 000144 00000000000 13216664445 021636 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/000755 001750 000144 00000000000 13216664445 023610 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/qms-style.qss000644 001750 000144 00000001037 13146470074 026272 0ustar00oeichlerxusers000000 000000 QToolBar { padding-left: 5px; spacing: 2px; background: #ececec; border: none } QToolBar > QToolButton { border-radius: 5px; padding: 0px; background-color: #ececec; border: none; width: 24px; height: 24px; } QToolBar > QToolButton:checked { border: 1px solid #cdcdcd; background-color: #d7d7d7; } QToolBar > QToolButton:pressed { border: 1px solid #cdcdcd; background-color: #d7d7d7; } QToolBar > QToolButton:hover { border: 1px solid #cdcdcd; background-color: #d7d7d7; } qmapshack-1.10.0/MacOSX/resources/Contents/Resources/fr.lproj/000755 001750 000144 00000000000 13216664445 025344 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/fr.lproj/locversion.plist000644 001750 000144 00000000644 13146470074 030603 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale fr LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/nl.lproj/000755 001750 000144 00000000000 13216664445 025346 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/nl.lproj/locversion.plist000644 001750 000144 00000000644 13146470074 030605 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale nl LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/es.lproj/000755 001750 000144 00000000000 13216664445 025344 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/es.lproj/locversion.plist000644 001750 000144 00000000644 12572255134 030603 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale es LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/QMapShack.icns000644 001750 000144 00001064720 12572255134 026303 0ustar00oeichlerxusers000000 000000 icnsiic07&PNG  IHDR>asRGB pHYs  &IDATx]xTU>3 A ҥ(Q\QuQۊbY+]Q M.MwB230yfn;|dGRHfmS#FUvWfފ76մie5fL7ճg}jG;KqÂ_tKܼtȆ+6z^4c6{>&'5zQRGHߪf̸Ww8ѕ_Rsl*=s{~ƙN~IfUC>!M/r/`WoS5k xeZzg+iڵ~ [Ip|< 3rႵ$e_s.:lݻ̮pM{w>"u. wnG2e6" tk)G6~gTbb)Uvy)8{:}ϞS&RRTW^xrsjҤ b1_~٧/ߧK믯zj23Ϫ)S6;O#GgՉ9*;:>OiJD:ZvkʔrxxQlRjr'lnLo>p:u ;eΥ˷S9E>ܹ\|f"1TlXIo_D蕋۷)?~*eQK;չs]5`u<6T*_>QuPӹ M>1M\J9رl`nyQ7[0뗓lYKݰыTٲԠAU͚ K 99VsjϞL)TI*WTQ կ_AY+~  p5U.\[[wX \LY[T8r\IIꪫ*COV.+XcBlCZnB DyV}~;ᧄP#׬yݺ_dV͛WQ;ւyzjg;sdvb h4AAС?:Uj6ϞIrQOuu<%&jݺjb Xtþ}֭GUI J7onۃD`oB[Iv0ʼy;[o-PXo_u 4qNvVV֯e2B'OS7\yPSnPG؁\2yF}K5P'OGeҿ~ ;w&4ɓͫdS"azej„8 ˨=UÆ%DZ_բE[^ݻ׫oX-T.uTF)e3g:x0[CvyL@&0!86\u8>;۞@G`-R1Gԍ76" $9=>GPp3^j&vޫWhb3ոq+UnY p|Z (du&TO&Ԑ!q2Ynq1bOcwY5^~7RylԨ>8eƫ'bzG瞛/Rqz #N k:# D ϼd%eG~P_g`*b ,mzꫯ~W ASh'}1<G>bSUjWWYڥ:Ƨu/r+">>y᧞מI"J22Y.@~[ { aI._8ҳ}fӧoW?8P osю]? a}14Cxrݜ6eZMiSM䤤8oэWr~9sOp_k#a|{睍$< ^jÆ#{cU2 =6m:E@d6þoE={Cf&NE>EYe_~gGB܌}h7+$I,KP΅ҟ.]^ ,vIj89!hB(k_<(>۵*`ڱ#SM {V VX(HV,TQ &?\f;sW:v2dIr/ĦڶM8y}DAvQW ^0yOppܓIX>JJaE9ې"1t4k $}|m;I"ԥhÇR]>׽LQsOS3!b!4Yw&yq

Wxhp[~a+%Y?5ûDŽ5PJa`Wk7QuWBQdl"<{qٲWFj˕PrPvmhK R>J ;k8]XG 17w.`AgU ez^ڹdz啮 =7&,_({L P +{3n B!?q(0]L<|\@ͭmo9sblA|vP$we _Na *ʔ; L;]R#G΂؀m~{ĉ J dNNhߺv#oVuq[hva(9u`bJnVUp}SRԄ:;x؛aEؠqA$hD= ;5BY1cMuʔ6 zÇ#b޸8h" BhUHتU y4\;˗W|F8^Y~=S{o3thB k|`UTSS8n܍UEm(UҞ='?Ym 8p:Rv \V +Fv'a0I Oq5)MӹW;&~}}jI @3hD,(4ovx>Swu5k 1MM%i9B,jJ0b߉*j^|K'm!Jv *H_F`ʤRѠA ]0eiaW):E_PIBLnm!fƎU.y_o/t T[+: ӹ\7ܱ#y%f *t[EZW!S#]'o|/hg L[D l\Au~X@l!вeȸSrJZ@P$6Æl`yPY g`!e;lL ӥy0i,ni=A~;‚~h' J R1.it wkd̸R4;d׉0 {lOW;  В{;@Z+S_D ˍ?N_'?~UAH2@݃C U%0KQŃR}h8@ m+j^[G' K oRoW$вȑNzA/GP]~b)z }Y^#fXфݵY=6SV5,#<ɹ^kmudGV܍:ET߾ .08)bȥZ$QQq4h*ymA2ۋsJMMF_c!,"`@0:>8 iGw>{ F^8.)v 15~: "Tb4̧O ڄR0o޽k[߳䏂3 AWv(jef_R ZTcAʘl(!?E})|o0b#;">fAIRg|E__sENp&Jo#IJ*]ԫ )@r)3a1ƌm\Sq%pat)-OlIR<= Uf(PAAԊF'D}Tru\9O5z;@k^P뱝Yqj!"q5iV&E"P5Ϸsk6CLu\UPԩsرs4*GFZ/Z pRJw:VW ë|M{\i` ni5?z'=pRQKK6*x.sO>u b y/QGJh糠EjW =EO؁USvLWzz=*қ1IGb$c)C,I; GE~ ƒfDVZ >)UP\j5Op]=KDE(jDjLn|?%^o`)pU-By&zӁ,7J>hصx@`CSw>`>璏?ӪU~+_{޽끦z0"} >LN[qVJ jH֎&'̹Fbر mpŽ"<&}/Ʌ.a8dpItfY; -ҲeZ(w;"FO q^t{)73sj"B'UWb7A_^>:W:nXP? $xj\PF-h-Sbh=Cm 7G.GM\1y)ks*DRl'cY a>81hϼ^H =/}b|['={y 虷Q0z'۷kQ,_@G &1"=_e:[|) U{SNu0IWM"gΗAN^0)@v4oFWTw|e45#ˌd}Ȑo !\^P-ElaO-( !ZP,\W=_/]["qOhjHlƨ?> Y",cD5f50]yLAkzk S/adzA<E "ٳ0ԘX}ND`5D D7H=:2ꉧ͚J qEMD6(&,~iidOuJt~Uqfg׭; !7"sF)}}(*$i3#HG&\1Wh'%I-akӘ=u~#ԩ}nެ$Hͼx@l g@:ܭ-Җ_EZ([mLjC5w 6*F`9^}};r`gNu-ȡg tqB> Ѿ#YΥ(N5fL-*Y*!zU׸FIQd+qs">aEĈ@%1ޱ%ZP&|#[(P6Unץ<@CFD],q±øp#PB~}[(n"F8ho0j.5='V P| cx 'c͟ _Z02{Bg!Cq́jxG>B!6ЂUkN"F{|2YR@3qd"#"Co^xxj¬-M[SXF4D2j@`G) P8'RiH ?uk -[fscǺp0m68f%{S'W7"s68nJ2|Ll.b`6y{L6|^mHԍ[byhӦmX7 =[^.6|A@CE⢹ b`C 0Qؓ'ϻՃ%jIQ!0 Eĉ$mf%( 3%&~݁&F#P\Qk)4i#|݆e}z0Xn~WK>MWئDgz:##KeP  ,W ۴ieӡEd y͚h؀dKӷ]2IxL^ݺ48Ѐ/#j|xaTiBŎ0sqDNg6q=N#ՋƌYϳ;+ >k0n+ F9ͮ9*>9NdhN$m4l QAԱg"'5'.矟L8`+ykBX |Z$AV `0KCec MYs2}~9ﳭZ{w3yr0ў-9 \r!w+[!2YsPalYe Jy?ď.̝_ b4VkӷX}E|%7^yuQAݲcQ"DyժYZeFWڏPRH\}^]TIՏl"W?1mb,;/D!K@KHYv@RW$XaLT;D%Nl.h U0m|r-{XA'i@?{x^\HњGE}h?hPs1W$D誑I!zVu=/SCU23FdΫ߽CU23FdΫ߽CU23FdΫ߽CU23zD(uzԊvKobZI6֛ ^fUsiBծ60µ%9*$g.$)sz: G $yIyܸ^:m\Ըq=gt5lX[`(&=xzq9+YfmS#FE#%.i~S<={֗,db~$1IENDB`ic08YMPNG  IHDR\rfsRGB pHYs  @IDATx]TE iCCYA@ADYPTDŰ]]˚eAA9gtx_t}{oxԩM6$v8&f^/^}ؼޘު  ƂM4jTQw_ѯ_3Sѥ&ſ=OL;vYPP0"YTPRQB@!N긂@P |  ;u C@!ajP0,0ԩ+‡AAPS: >B@!N긂@P |  ;u C@!ajP0,0ԩ+‡AAPS: >B@!N긂@P | vatԩysȑ3p|V:tN>|u ZvܡCMqe Evv)u B@!'һ_f(l۷~DȥKgV99AdxckQLF((e"R= 4S=8'{\8XLY#znU2=v,6Jk9 HZLoXUTZNt^HA!@Ð+!2Xe*RSM;C|YZ,l SL&U}w C!-XClt H+3.^Kvta!Aj EGff:$| _)QFU͚UF>YuFd w>OӱAVe K2dl/b9ACNSk-rւI/%MV ~l'āPzM)w> %#N[xoz5E~NZ5`ns[#/eSȶ)ïH3+}~%*U*%a)ZMg'0@뼄s7EJ [KWqyyQ1ijHu5-t+v ~LE`XS"%꛴l9 i 7mȭݵ n6QT:J1r&47W矿 ZtŜ9Qaz)]JW^9QVEy-gG_$O%KH޹sR?ņ9Uk1cHB#_] ت':9_6Dj ՋK.Us^6o'^|qxbɒ+>{NV 6X% N+, |kc]|$:v) \gpSQK_6ln'3A)W9rV^#ۋo"ekG)n}nWa@8nC'ڋmrΨ4dpxEq å^VTZ xN)@))rMzu( #M@rL}Q8F@zb>.v3Pe^YBnvJ]s[o!~iSagW\zGROoyB*x]e'.ȃr[GVlmP9l,2{LR2̙kPy2Uci fU=6>]{1{$1N*^)cXwԓ!)ܳd`L:'Ϛ6y15jgmqH;BEr.05rM4UMYHȓ޾I̢7~..ݍOX1P΄zYGQԐ=䵉&x093F#4F|o+GhѢ26z"f:ki.\RēO5b, n*HNҶ_o̘!CZ?=>@ݠһmWE%2u\IY3uq}rVС׷,歬'P>fX^"w? \b޼@[cNX~8-ڃ=k?J xȸ#|?ȼ{G2XeY)7/|| qyJq'q [auѧOCVt ;U{R/({s)O1_Eq;A #s%gޱd&̓ /«=fJɅJ|:?lovbK0& *W.*D^ tۀ9";2Kqp ;VX, _dqRMI¶bx,:2!U*Ex h2̢SRǻT w?_qC MMR=\~J}ubw@{iHl`6{7ET&{oVm HUf[~&̮)? Jy]Mʩ|S{Q"4 #2RJH2.M:Hy2A 6?AӁ\%<»ݒ;3#6+΀G^1F)PZquNJD^z}DfaϞ޽'!ۮ5Oj·-zg$ Ҁ]І]{v\w#8k{ 1hԣJk 5kKDݹwqTHNR)U4v:}:_RS!O=Hb\*]g>ykSe.j4)zxkҠE^1uj`5)y^)7dv 0aI$$7& HifPvQ }.%u 7< Ds@<†<"Y΃};n M 9\#ْ)]3!QLgDHYcI\U}ݲYp䔶xh'?k0pC hNi 34'6A#ߙDSm a(sew.ߩE )8O: &`#,Vt8-zXő'IF9/j, }?*)@{9m_Ы؃dV~ɜlr,Xp+()Гv_~̘KĠATF:G2%2%[Iɕ&=B] [adS $ҤSc9 zdnIb^ṞoHBAbv}NZ37"0ءDS^/RDp8E YoĈvd U|/u9M^9}v>\'};#]f_>oux$,С yuq93Cx? pa4Fjei٧w.j`Q'u||-П륓|b3њ1ux%Sdԧb)ya?֐y.`rX`& %,Hz_AFf Ő}&ڲJ r9jƤ?SRRB a=L͚UBDhn SX|M/y3JGȌuN`/[q/{{`wj wI;-5`UIJvS$ׯl@@R"+ 1C,dj) Pϓd6i竝ɓ@' 6Mj' VlTv@[޹sikMo#MLV: ҅45j]Lş&S4KHH5W3Fl=.E+En4fIH' k>dm>C4CF:;Rpz*Gꪭ;hvt : 5B{%_{)zEkT%ڽl髯Y+y ;Ò.m h L&M'Çϐ' eH|&֓"O\79-+-Yi_PVo5Gsq{M{t(hTCs=7P#7i$"N0v <FN*'c畀*f7mN^}`vJeWX//DI ygLDF߾c/AH2pAo2 z7ԈLViE.(0ëQ3lZHX]X .{ػv}b}Il, } tdRGs1zf Po}Ff{ J_f=yL{\  @N&͸Bn TtJH8P )Bx;MSu:!%/BS dŸ %G~_~KTuA&?h(pV}ֱY,34iPCH0P`ln:nf]cXuO5Ev; Njt2dsl KpW]/ZfЙFilm3fJ9s6?n\B0i׃̕2+5gǯH}A`qƭyK>J>?x58gy3KTbεWQA0ޢR}V`٪pY:OH+ ǃkwbAd*N>Pu]`1/Ŧ2e1V 1p` oKׯ)) iosd㳕]P# W3ͥVOfv:#OoM6|sl֬PRTA(7zXsQ (b},})^uU#PM oRT]< %"؉ʳʘ\[q7ҽ,JFOvyo?k${Ձof"F|bIY] W駖"%woE\a^[PX_Gu 6bTu hdhf1w-Ӷo?dg:wI3ӽ2hd{^B+t/ZN2tLց^G5PD.>WK/,z5c'{sI,w2KEL۶S&Rt1Fwb"W_dީ>),]z˸}5A3E+_F^y(08 | b*N3pUZ'N\{{構n]ε]]6}g6.b'g }n~{9~gu)I[Pf-;ꄤSTn9;IMarNj#:v+N@"w͡@DD8f&*Ce \ $ErҞ<CHD OZȻ0V##7B M81fj2O 5S+7D~Cr'>+V\;g@G*:2Td[G*Y,f8] cͅ|>h.8csnu Sn_/djc/X3 J8fܸE0^D'a9pG.`d|:2ZGxw I~d>suj OziӦ z_L{RҢ!nty]/.4Ԑë9#Zxq@)9I W:}; 3pmE31A57Z=iNM'E)ܶ0'q^w4}ċ*s:Ih:4(#sW:Ӑ71Į=]&QSyS~q4UFS܈?2~b`^cHf7iǺu,Ϧ%D-=ADE! 80p@Be] IV7yOTOE1DnxZ0@{"׏xD>tF3ţH(C/7{p@gpLB!8ƺo Un@ ٦@lG'HWF6cjP߁>Qƺ7;&^ Pd <7?5Fͯ戻b`3p.ÿFP%oz+^p}Vn(DXq7o^IuWX5H!X:*qC"LI^xa!iQ}ة9ؿPߤs37@KZ뜏)Ǧ`;wM95Oݯڏ@°aeM k`Zxn塆]<J; pH1zdgk04_~Q֐Ɔ GޜlToD( bȦ7OK}4ɖm<=Ԫ78Pn>"k.`_v-AL0?.F@L5  *$!Mڵׯ_TX/|DSeAa`qݡ"0T)}S6M!4;nw]p&Q4%!nh.Mz ^."]̓IvH&ɓ t-z& J T؅ZB6i`:Jt{.x>{+ʨmˍk`0@pQ:xMJU"y[K53ge2N7سn|Tw:_MTd;%q}gm1bx*v>^i)yͫQdh׮{"~cբhrs;o~:GJCW^ER {&4|/{nM5'a3I7 @sԋ/ jr9TVP G86ibi^R QX[V(((|I-IAW) jOgf1 uPL D?o sjP6o]ŧ`4SWJO@O7 0w~n5:^7@*Nc5_:YD^CBwObr0o,"yɄ~z}EdLō#߉0T )]ѓ3K-v!, EG=Gpr $?'ypevK׋g[xVSG7оQwYHR eF,xvA׵Mc3 )M;/c_=_8 :g!,zs ;YN'"|\" D O 1e_{Tj n޽ mkwO>nv*Spt0Mz0Yfy2XLn:d7J jp社dzBQ2fL ;39Ɩ?zٹF$k.4'nڴ*P3bwv_I3 9r&5owXp'ĂEI4LpݚQC@~2-~.x:DzVK`ma7X@3v 5 p16#{swQ315nLL0{8Ƒ7ʈ6l֮= :msihaHWVUJmYw|ޘd J= UH7dzXO\w] *r2#D> _N$ڵ3*ٮ3 *,g˭sޢs4ؒ?h7$Xѓ5z"-!'+ݩ -8)%p\,^~/aӯW^NBSH7!f,Ѣ!Cm3y ǘ'D lP"zQAfZl3twM:ߖ>x`&ҥw@d>i2 ̟ \ :*54ܙ|tW!F"n+l97HhngzxmXr331=z}Ⱦ ƾum6 |%LτEtU{]'Nt|d':gK c5G4JUުUv #N:na {+>ZDվ6ws=}-v3%"M$yMhj68T^X̬SN)͸~oi7:iUZzjlb?6 7_%ΨJneI縉ᶓH#66Z^VT[F=yNFIx^ggѸ pEAIZ{޼mns<7k&5i,bܸ>%~Etz2U$q0L1 G!A 6"Ɇ!{&ʹG&tHe6׿4 Y ={[X"tonftolYHO>3#NnQcD„+9y07Mm9D4I#;`]2[Fiz8t!W&šT(݂ELG _FqE +2OAz|H:$F[]^o7=\tZ3 IM&d4MEBX}߉Ȩ 9\_$yU# +B5GҭU׳l,Җ-Gb+Ģ0<`dڈ>|ZrXF$!^};v^pЊaN'rb A= 6%a$ð#- cX|OE.KgBi ϒ% ?W^YJQ/C'Ýk  Fe7tqMm3Kdg]sԸq%A㉒A(]0y,Q"H _/{yلf j%ᛯ AU)8Ǩ Ko=IB n8e$:aݔjqjb~f/Zx`9GtO5kf?J߆GT)QPI ^zixe9X^`z<ʢRRr7iګc[_~9W@Mw?46)HnBy٧Q[X)-_cPP[={rvǿtR"hf~+K#3O?J*1SI=r$?&Cv}.z9?Lg#9~>}%nBQ -ZCW}~]qۗ 2?Hoа%=l~C u͒?y@X ʳI@" >`NE¨cwfO nOOj•ȓhH=BkXܾ5"h>g1rH2M?eIxdu>Բk bDzOawqlfW᝾Ut(bdXkIdDjRľ}ǁD¸ճip߰w)/@ԩS IС@TCa"dO>Cw~j$zk;\oNykYDG%CvFⵑ?4,XtugXI= z_&j"x{kU$ S̢{A V^emxmrM`ԁxVx%/z\]+/"}krn m6&8/=i YQ{\^x7x GQX_:6xIqU01KrSaH hr i3E2ޥ. 2e ĮdOD:Gzұ6[d:/ >?غͿg)"-L>RRe߾ lg1L?b`ڈn^:SL.O  S+-T`҅Vt28$@G{ 4$yK#]ibٲ$44o9HD6xKkzV4W;T`Zq/f`M3|Կ/VEn q=H\we)渾E ٲ%I<ﻯqԨQ6B^ ŵտ$z|KٌH#\{tn삎T'͊7l8{IbѢ<*a ɝ{9nmbCͪ ;诽v%QtsT4%< a^}(D:cQEfUEB'Dҍ'&<7S0>ƛTM@pɫICo6*ږМP30ZntD 0 M`u*1oa`"s`< Hl߿Qg&bW5Vp~"1ܵ( 89%ҵm[M*x;ɝGn{EЏp:RݑG4n@qHYY`U?x7[48&`Oh`h\E.L^j!Wǰvrp 3lWnfte *ٽ6o.=ҖK= )n=L۶DIZg-R*(o: ;S?0%Cg @A{Zr/oޭ8Մ=UW#;6SC^GڨɁ&>w٠H%yi+W $5h82"fΈ*Uk4O+hMElp\QZL>7͜xbi~dtz4(UY^GƯСĪUŮ]'Ĝ9[ZTj=ನ__ Bjl=;FA_=Tlٲ\F4pyS,B M7rTՀHɒ7E1}IQ:tQDgh&)w߽&)~q~ܹ'H1͟ CYJ@$DA1~&= 8]$ۏ6T Z%~J-y/ "٩bn)d @< !C<u?2q+#zgЏelR+W MC |V'u ʦv&0^K6mG.(*h7@eAZkXNj+!@42_܏Z(+CuɇK{C* hWfcJ! *Q njtλs!ZNY P\ P,Y'rp~o|-=ߙ2E˖U+nh%4D^OBaҹwOEOۂz_XpxvYˉ̈4qPqu)m~Bl~TL;ޥ |cǚ:~kΜM⭷ŋ']{мs{c],v:s,~mvW_]@dL"'Ky5FcT (_fАi<~+.d3NrĢE.I[,V9wRᩙȍ5;ggHҚ$2yvKI>X6?Xj'W6 vJ:2I,TJTP7İamn\ܯp(cS.5*f&|aa֭ŁF:q"O|yu  1px O7e(^/MDDDq fQ^%q-}ꦒgA+:VC;WtzPgf;\ q`SqchQ.nL8dR1kĔ.m;Ӝ'&tLO|oX5;AYW"`XS0dqgl"-[KwcI{@*}=zNm]yj7-Yp:6:Htpf3qڗU7 .._J"1rdH %)Nw1s]ޏ#f]pC=c9snm8)b"ԾNkӇO? |v,~lѧOCu93g/@ZIuop@"{֬ w H.u{(hC80Kܬ<}&Q,zǶ$Snbߠ(UZ!ܹ6aj3\YxUqOQfŧ XA׽KXX]R_ĿTAf1 S[tWfo@y) Fs5@s7!"kL"2)#q}E];Qc 8TT^DA.)V--@_w]sy U Gdf}\97$*GsYn=GDzb>qR;z3V 33hy: 0?8@6⿸:v<|G_ !@V1雜]o|1 ϥu̸C ng߄+`hFP?W`;.o#d꿋yvH -*P#n^[->,' j3bO}WC8C˖& x'R~3})sZbbfP(3ElB )ؑ'zSšp#W}W l`J0+@lzVQ#Kw;/p2eMxQYȰJ @ o˿TeТ>-@d!tLdajS(6PL'z Pl @j5PO( DA@@!b3j P&ꉂ@Bf@TzmHoR".uwյꮮW׵W\XPQQ{eiI=w.dn$d&)0ؙA@h!(l@X1UrKoCT*:-l|PM`k  -ܰA;\jԇش頺j=D/}  Ppt>Jռy͓w߲T A@n3{A'(zdyg5m&@v&@_A@HlHO=9XhMu D" $ :̙׫n(-x9 2A@A:~  $ )o~T9صA~N$4e"  S36q?+ᬈ! @"Pιsc~B&A@ojʹsQ. $/`PP >{ef @qbW9" $?bXf( C@bA@A  PA@(0  @# @c  P aA"A@G@2CA@AD ɏ0e @1(A@Nх" '?)1dܪM:w#bswA@@sPkxc#)0xpKKf A@X"p߂؃.cĦBEˇIA@HbM#c$m  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnH+A@,9( $7$  ` A@aA@KE  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnH+A@,9( $7$  ` A@aA@KE  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnR{z2;Adx 4866ccb zm>*3"@#he1E`ӦCWs9_iS]uVk|Z*ş}vz N?qRNY$f3ZaZ[WS[|4iE߷`'bªǛmQ Ѕm 9>1ܸzj.~}]@ @܄x^>)jLitMJUdr8oF.jժ_?)ʿI꣏$, |>pȲdaP ʘ%82FK@# @߼ho]-O+evkU-9]Q^*TȀu=𿅪R%=P=z% 3a;)EHQ>8l9sz챟T΍O #@J  Sp,ZO^;w䎛wtȑkmPď0+P~Z`6Bgۧ![hQ[5.{D>՚5aH Q2(A0W2^MjTctPURW\1x1tvi]6Q#F 5BNi˖?}{$&KB6U\jZVdd>S_LY(c{A@#C80KM~5k+RTNuUVV5o iJj۶#A7 ^XS#^u\)^㢗yxa{S%0$+geUѯ^kԨ3aF'/ϭ\.7v/R|E2tLU]/1rar"hN] },uYe˚Rt!yoV$=K*̇*!CZ ;>bYN%3QAl9&LX^|q6"_v2VP'. Fld*F㙩RSTfuՙgn8p# @-0<\`_D1XB91UI1H)I@D9*= ` իW#նm1 R4hgKn{l{E3gnֆS^Sxp×`8zsJڀ\' aJaڽA8Uo3]tQGgaОz* c8y<OnUNcjnոq5XYUc@: mT "bɚع(WdO;@$vVpz睅x1331`<R-Ə]:Za*A@p*a]FeP{ -:䁱f|6W^ .h_2X{_oS:|8ǘ)|'MZT{̆;){WUkWV- p |Sj2L'O ^;O߸Mꭷ΋HOd`Xj? Jǐǩ6l8 MVhOb@($N0:6N7ժkT "13F*㐳abpׯ1iH$;č:4l9t_ԻEFK#&=9Tݺ`ҝ)Z;mk3Llz .cQ G@<լYLØ0azyFhR;;}JR̿a1~'hfv23`(R׏>}ZA:/[.dĹٿA 40XCO|bP R>2}wG~TKpa%^{tp i喾 #6?_ F=Q 5D#A"Ի&axpQʃ$-BvjC˗Q!vJfQ:֋Y즢 7f6gb"ҸXԀos O0Wjbe5|ogDJ_Pe"RY_"GD(+S2.HRu'8x45J֮ݯS]j0)y:8W*2ٺu-խ[=' uL- -x-+p$sq\-E02.C/;.b|s ^_or?Ag;[o-+Ǹ>샄C =c@mu}gt+R+O,ZoF~Vb48t(Gu*q3zl 钪}čaj.{J}*\g5dE0,4C)ȈC{o?<v"v5{Vu\3 Dݺy#0^MaTrJPQR %э`%x!gh]`p&  R`L>ߥKwC}v42 1zm۷8;eZ=A>}(6@b 'V#7k?`'Pײ\lvo!J,mS/P,srnf&- sY̙0Tذ!u}uO2 jW3ƇyDo̭eZ㩥ʅq1H:a`11>|۝;c=HKKiJ-05ҩ Cœv TQ24rݺJ@GIYb5[KpP <VQCTժ&DUTUt+xј&ʦM3L F %D4R@X["0imQB^P`J_ڨQ`;[ԎԿ=B]uU7gz2ZuW݀(xxfwM]q ǐE)x?L,fNdB/ߍ@4~7"h[WW=z4C VO87UZw_Hvjv o&`Ix53 uw\;o89!^6ߊ0vM͛N;5QzԇmˆC$80Cm:m'&0"w 4IW *5bSuΖ\'-eaV|1a u\tKaBF㵜m7o^Ciժj޼&^]%M \*Ě蚵k-@'uM|QW^i}WS Y`L/T |NhާR:(C`)+vIt1Mfn(X$9@ʤI+_VK0?ADF:^gjdsNkԞ }C@FHԷobngw" Fn5yy;.|vAت^ziNt kA,\K{/6W @ڜ8q9 w(BȇȞ9wFpڍ XW*62fn~+VʕպuPAA ،G >*8W&tuu\J"*ȝ7UFpcp}Zޕ3!NIp) b- ֋/<0 P}.E?\\.]m6l8aY1:rH꫕P5l1>Q(q`;d>w]|6FF%vSױcnԨڊW1˾}9Wgi&{d4-LTkq|,n _ ܖIWtFBLwjtߚY u j?gYx7>a1[  A~eń>R%Kv/X>h {>tNwi5;Iʪm[(UѠ.SReذV{e0Lw]J}Ύ J,_xyyΡF[`P@UZ}F`%ޡQ 7&15?‡r>FB@ed=>A :% #G~6`0@yd-W#Gr֨_ cXc;Cgׁ]=dܻZ[TA={4xne^yUԎGkOXʑ"y.fcvTB$k)Oe0jiGf*kC5fLg4(q8pl\Ӟeڴt,` tR3Z2'BjԨ͟[KXI[ŻToꔾ*%!^&cH.) w`^`jhtM{;h<$%4ӷ6T,$l5ڕ]76k"QE1h?mx,F=.wa hvEٳ8Ta_2 nϞCz\h/}X861EK v ;%,ӧoB_;ՀEa^r>E*aԢ֫\nϼy;~5;]8R`Q=`z>Dȿg|֜x^j͚} >jTH u TV³|3h1|!2 -nEp=2{郾mEn]c}+ !I{qK?G.G0>dx>d)ďˡJX*&6lcP 0} 7tYI&hd99n,d&7Kfd:{w';cjܸZw_?ob͹S"$/ ja74IKlظIj ISoB:ÀUu M7} 33$n&! ^8}wb] 3C/mH.J `-QCf7{k6m{c@>R~0s=)`-FLDx>.mb &"@Ͼ w6~-v͓t>"c}ьGH#v]fXcɒ=<)t} k765;hK/́|jd`g8AtkkI{C#Zؐ+*XC2PZz`vlJCK {GJ bvr}ZNRH{ȓz%f͊X1Èq1|Zgm,wcVzt,FcQ ^, kCtop[b}|ZUOPnT5R˳ct"4WKIn?)􀮿Fj91f:'/l³FQi0m._?I{sX3L]0rmkZjmZO}ҘX1A,0+`{7߬E;0*aWrY"vC3ޡp_nN9Î˿AeVg.wb{`aGABj?mCg$>UAcT/N4d 7, b iGw.moPDD Zb`'yL+Ur9M#_I$O0]1O]D6#}w4E&Nʕ{B-1gɼ" SOM/G(H4"m'T=#h@*ߵ 0pT/}A>"/Un][o7-hP:@Eή"m~C[_? .'ET4_'AI]tQG ̞EV[oFxm6t/m#7bWwݨv~sx뭆ʑ#02 kg NZ,1d3CYWG➴4b2QQ KK1@Zz=UutHvZS@`f 3nI9 ae5V2/÷C(w ]FX\2lt0-=!r7갼Là:JFk'ů4\!?aUc3E StpWӜҰHbH.4 Ig)n4"iq#IDbğaO<1 @pã6wbLKײ}*ϸ.n#Oj$ILn[~pwYwKbI.5M|%¢|Gcg/_ھի%#GMþv +}T<@2W@X„Vw Dۉ {m2>!)@pW5pSaR4gkh/ji$˫Đ v`=^::MZ!}*fP،N5`X'b׋]Ϟ o)t25k脻TͩSzm|bydd4^ 1!Z AG7޹}}QcܸnDuLo'/O%oK(ʶSj׮ %ts/7H&C1V1 D9>gYj=Ja5u}B qꁣVU _*3? 抽KUU]#VߩGL4)#"\<)i3g SO댕&)[SvvN}M=ƍ pdz|ͅ< I(kBaJu2fЭLѰxlTm/ ;vs˅T}TiCtcJIK2F k jժ}\hbq<`Jc.< / QFXI8NR9ֻ^jl%O# @աS2{Z!^$F m"~Z|< "CAV]0|ڊ|WRtt3fc0 v`Z1ƍΝTәr;ի=B4zPjG5]95e@tӶmhLZA$?$tEF5hd;#m˖C;O_Z4̀iBKS(v?sy_z.EEV-[һTh6޻r\,qTaߑOoӈ\zph5 _B)Ŕg` _Uz0ܬ>oA"/w.0m`rEo\O_4e;` K4xZ`CPKX(x $*h b i#%5=zۗ 4㺫2@FgZM SXm{<\MiS[~JɁբicN=,/^ [kXN#:XE 槟6 ^rB]E/Woߦz7MީʮPLWgq29[ U}p3J|͞EP $b7\R޿`ݰ=UVگcp"Xs⑸QaFJm@x$ ֤n `iXDV$ސk2]j*"fÅ w}v@Őw#.\sr( $7z$rk+YVxvTHVA5jh&Xa^R+V*QݑRRd2+W״٢ay.bcie5YOu rYqM_q) 0q"8bH9V"N~Hԃ>"]ƀED.iRGG/qn V! ئdj*LA]-)=&Wt#dqՠwhbZB\*gL$ǎCbDܥB;1pUxou̡Z dK, Izh {K.>va[4YgUƝq HxX F4QoΟv %сkK] )¢ 5m0ȇ, K5̙81 ߉x5^i"X!@;*dD1j#ޛv׾0wEDK`r+Z7 @1_/lv=:=H; ,0-SnC ixެ}t?KI~3^@u'!+(`+wΞAύGVE= P]6(?CY`iG| Spwm#D unZ+FS1~vB: $\Zo"8i*!pF<,rme*MGA;:!.!gne4=9 H1(f Tx{yp% eV>&j:N.:i /E;NqѢ{Ho aC\R tjh'Pc3gng*yIȥ!V琹 &761z~fdUCivM~j)o-:+_<ӡ?|Pi% 7 tiTߟt)u۲Y3'A.}+^|lڨ 8`u 63ܠbE1iCY=_ygoFrYM{qpd a8:j;)uĈ꣏bBH?KƅTmibLc-:}3Zp30E2!ӦmTQe7.928dm< CF`&jG\ֵb쯸kC: o#%QW~o0!i5b!n?얈Y0ji57F+F(XD08⥧fe %'xݭv#X=QD֣jԨM9\#:y7d_cWŒW\i!3adc)z/C92G7bgLap'\;ou`dU͝Mi2M}CcfM}:,>-d>z) U9gx+1+KժIep$ڶʕkrm}?:4n*v#ZiӡAH\H_=P(:yiemzz1i|L;|CU73=w[oiE%-oP4R qPsVt9=2g6HVb [ ̳t)%3;\n"wC/4}C 6]of w[jWmz&a@*Cmݺ|O|Hy [`SEu)8Z:@V4Sg}DC1yUy,IxQ׸.:p3lccC#3f؈J$~q߿YH6mZJBpYV=cf0p<i 8\gt7`;F$I8jhה>cmX$?tW>gHA# =BY hE$WgABUnSlgN\^y\Ss7߬D6#ZkNB3 n+"sn W~zVk!Ib #_z衟_bg\9NT\UwI)i^GG9x0ͽPYA::chD03J<նmH60mSh.0VQ>ixo8=SP',6d~n'^@n _5_{mwE#*ƎWKw `9:Đ!--c~o-8{kWcٜLj<X'MZ W1k7k1;[n#> HT;7it)/%05sD;QH"@DbNg 8ZŚZbo5]U4xY=Aa{$q24bx)EIfվ}KO4ϧ4?鞓!Yǻ|* o7r^(ި/ w9@IJ W)UcN1&`eKm_Q;7IL U~;~\i$Ȁx|$}Zwpj m` 3IqN fX&x7Vݺ5Ԟ u2yTH8 ԁq A~){_koADƟ'f³̂1Ҭ7f۱OdFu_2r?v,>v#@fQٵ+9yŊ:,ӶIAӱ&nXׄM(XܮV.1 $:>ڥEMVkk);<縳`)%Goߦ M6@C^UyJ;Dp?^^g'#H!+g$,@|OPǓymBE]xjW9c "ݶ "/.qu7㳱oXs/@IDATC #FkM:^(w=T$J:Ů4@"/b?'χ!1+cծC;&H}:7tSP$'|8Բep;ኳ[[6vj֬:BuxGoOxyn/|UL0%4}VڷPNj9m<1CzNnذ1!`R5fN96v(fᄏs۱?xOu@lA5B/rg.8Nќy )J OJh&}>ߟQUh\F#dHV"8u}f܀?70@s̰ǩTM$kIx\ ը8?MFZc!vo\H9<ċn+5zt{5n\|¾Ze-g3xS3k7AQ$flm61!l7Wu g:@u'7 幤(# }-%2$4`BGxxzϏοhW<&I;(o׮t0^}wc fEDG`>ыun%rUJ&T=6v^ E!RH\d^ pBzNlYR-9T=Ow&81E4nF{eDd=ݰ'-MTS\]yXԡ~a\5k"8# n Kudrc5Ly^ceu}644 JZM343>Wx1B%lZG q>y0F;`4OVY6DY0Ԉfi &O3A>JuT/p.=.tw PmdÐ,nxt x≳!죃2ժUՌoH,{ @IEgX0QNJ׿N3Ð S4NIsoxo: 8#AGvǎ6Ԙq?}IX!uǍ\mL}P"L=;$ŌO]~%Vo7Wy['(I]IwkP:!Ksx셺kC32Fر1%NӦm@KP#4Ki4|#f~,)p?s1xa ef- ~D6{|i tQؼp]-;M(;VԈ$7Rj-h6dϑhS: G(wG:CUϞ ug. B`G9oC=-`crxUMA*?[xdH|evJի1=i2e=. E_r/jϞ6ڶ3DTWMI`K>l)FH;8'Ҿbsi}6qf Ěf7KKzk"mՉ77ж4%FZ.l$#1 EBf]썰;W`P t.4+ڭ1S!.i/6nH<3( v6^S yy0~Ԁէ^ԡC`օO(JtB]Gv6!_ q5avht_h@\pkd:pu-??b6ur1t"/*Kt,+f$PL0czz4 -*PFgO0>"u(] j>O]yeWXk1$vxĬ@3r~ U ,Us__[2}%{Cĺo&F4Df*m)FHDg+v9rG5kyy00$eE!4a̜uV 5a¥XЪz}7:0 o1 GcLhe'~Oؑ^ kv:{CW\ZfALhە2!?; g_鯙fj9s!饉?2l^t.Ȑ8>Sm& $R`T !ֹI%g#{ x98."4,A1ąu ZӾ}]kBfEjoo> @Jh׮BP?~yV̈́  ?CKph?~xe8 {j߾ꪮhxX1 Q9?#̒9fL ~/; 5pJ9D> 80NQak{K5ߘ駧0OJ  PO;q/jTiHr62+}'BuHR3i e ]a62~xЭrQ_iG=찀F~#h.{QgBFk]}lY[n]GeУGX܏yv8eS ;s*U_mT~EJI+i5QV+kd*UJ/q"n]2ؗƱC`,fxOT7ցe^FK$#ڲ@P48S v6{BPSy៱pCq?' ςTo3Z*=]J|^}M-!/j/ ћ25膶e!, zT6lYI2f꥗fE$m}MMu/}S.؃t?g>AO[2=so85>V*e\Y?~z]V؃ϮC\Ce~Z{$o-7\NE?˵jUnmS_7^Pp^jy~Աfo+F iM7O7LF}]h/s֭ + ?"\r=GE·"]v۳?1v!1CXJG; ՠA!/NXovډ%Ñf+AgdrQ.>]PǏ; /:?\ V׫(|u:5`#G@I  #aڽD`@ɝ!"e(!i2|E21˗_}wΝ^F]!]R6}.@Ou]) wh*Ӵ[Ŋʼn+4fQ"uFizÇbQ>Ik]=V#6<3L <㰲H"~z0^Uah/sҮ쇌?3aue4yU Ht\./~h,mՐ!JLM.mLG?V2Kb\}_1wf;wU3E9EU0z{kQg_@go\HhraퟁEb7nBr燄?uWw5ao '>K͟-wgR4i/7CdMAZ`TI P %d!HMym;w;auflѫ.ʭc >ʸfp+ 䆵t,[b`|x_w=(cst zQF=X}ňzAYe ^prAgǩ?t} /]¿ akhtyRpE ,U 8Ywk4.m׎i:ro׫WCxҜSlQ8ОW0Z{F;G\/QI>K HeԯoxlX$"8r-G V`-qnqkc%3|헦~ tsa0<.wMSGgriU(OChs[DzcpPbu\u% ݖ"С- q5CF VoD*VNڭM!-̆?Ë \ۃymq:Hv2`Z)`jf@B4R=j8Z i3h-jS*^;:hT"8Q @~6ǒPfmmJZG,[n ƽY6}h.NŅa_3^i>\=e_{m6ڿ kqq+B0@]rI<*Xmjd3$/Q}lmf!oҤ"8!')9s3& Eo~PkBcKzҔm b{> ";Ð|mIW뮛;nx).]ڱj9џ VU{8^Uo/d1#2nTiʈ^~8l$HgnNY*EYg5Yc )yP%Yd}i67S˅jڃj}Pe)&>+a^^>v鼎ϹZuMr.N&%JH/4BvBO~sl0סÐ&h#o…OX$P8t#vJo聘SA?\Ӣԉ 7 FDzqS9*u`eϗҿwװax0s!ϚLjq_t-cGלC':)Nl v50?`(b;w7g"FRu2.]A9Rd7~4m٢E=DAS)2e6%KvHđh`qkz#k`1#`s:e{vv-a=ciކ!lucu%ڸA23STǎ  ոqݵ'Pg L޸VWє`)W mۘNIAFv*FLriBlҲeM*FG2((pIc;!V 7tG܈QK@3gfُ3m_g"Ur"8qO<q!EuEeGzL;[`ҐHK>hizB2 *84bI[x92rd{ S^ xDeeB(~oX[U?~4_ hr#wb]iUD L&\pAGt|3? :J]w ,ܥ,)aba* S\RZjوPES__sw}dvH=s +@k-2px s_2O?3`O}| ):nW_2 kV1_*N;j:WΨQnU-n1B =̐RF@op,4?!:u*wvqbHLN&cS?O1;袎V>5ݪo!ӧ>Mu/"1F'˦kUųϞZ3yc,dDbt.?HәJoK+ςڲ:,/U+h-Z4P?F}2i[K(bfgS 8ȼQ1++P|tzw',Z,!3n.y7"zrumGગc_q n]>wS;*`~p 2z:XVG\`&עˆ=PN䲈 {D[Ӷw x]0 _w?~6l?yL*i U۶ija u"IL',7vNKV LݦLYDmْE:w֍|-Z⟢&]A'jB-=U.m%mb_HN:^($ϐL= 90E,v[(-afjN]o Ś"r&|ܤb{'@wׯLj"@=' ݤ~q=Bphny=: 08{љs"ֵO?= FkZ dn @k+DB0c[IVeW\5 &W~z3$S) IQD`ΜUaXѻkj'C|yBP(Nv̍@@_˥b ѶvS2kx/2 FNR7*^z<z=Sy")WFť%|AM&C q Yx.!h֡CLKÅY"pe 6zn\  G`dCS^ Og+K&XL%2lL<س @4jK3*rmJKE NO es_nt xI?4 !gP@9a(RsU;w2Pqu­]DOq:r8`O~ɽ䫿 S22]wݗ:it9Uz䑩E8{Wo' 3Qf/vHOO }/-H5vPp =JĤYdd`kLL&^ د, _T"!zuŝտ<{ե~ 9TU6޶b`T aɀJڋ\pVaۻ(LW3*#,q>AHOr%U--,ɑPENS'K1X'//q]G5c;0jA 9缇֖Lğ, }}2j?uu=StB9Yb/Xc:b$. r",Rĉ/au!"0Y0UWuA8 w*MFk~00YƂxPrwбљGJr wLcxz)tOqG?YuxS4k 2c'w{ر. ]![VaUaH+hτ۳ kiL ˟"Dlld[QIF yRrs c{CIFӛ5Fa˾}"<~B^1k{ݿNL&N\O{T?ޚY3nA&3fl- RT^(FiT g a*᳠41%g +T'eG"C)n}f (%1 ^:1シw6'@㤭[E@LQP7K D~R@#aNՓ㉃=ǎcFH1*dALճgQVڵ+7߼xn`[ kJ#n p~iM1~##]rr5:F:J܉<# KyvB*6:9ضE%== FϼwXQ7F49 &D E1`jj|m?eʵO~յSR5k Џ>z7gQ~z.0NsQ+WN` 0!3nKx_xEjq޽"G*NDժeRiq,W 9zY(R}UVVu-5{kմi7BG(>Z/oCcWU9Sh3H"uGN.u݅o@3؁"eQ7[YCUXF 6D@\GZ۹D7Zt7t*UO}t Fݩ/ޡmh_}uӇ@TE:aճ ZI)G B6zt$YZ[?~DВGH[%IGjRYm'_! =HdTˋ/bOW0 =LڷLF5n\w5vl[uM`4LfLAi w ku%%$@W믧H0CMp5>mHHRp#.;m 4GCepfgà[$ӥZ*tK=I+# իJK>, XVS30hsn嗫e$^So Rv9hx65Ձf u"㨁2PRQzip&Y9mO=ig.J#s?+F#n { 8X zFiYyRep7Y>}ѷoSH(^l:!ChL\G3MT R[  iK8tBK׋5Xg^7^y,w3\FyY>u(}w!T( >d@Oul7LCȑm&$uTTabB`}AA R Nl>M^ *0h ? en e8~;Nñp.աC]$)>ˏr wID:tvDU[$-Ɉy %`z*&Mj֭kb4FL9D{4kV AU.[)%Z1,IIuP?`ӥK/{|s1mߍ5ov5kb  OuJiKNP6v{#Đ! AVVU& \N贈FW Б@1oTL9\)C(Tr"w1 8 FẀiU~pU3DN3QQݻСչW')7z }%penH4|,we:V=3ƞ\#N: ګM z:{yh"EG]8t#;UMJm\<6D0/ԁJr'f={CrԤIkt~Z@xFlEcϞ1FȰ⼑\N^y^}~do`9o6?_[z#F$l؟{E˪S4;w+q@j0<dV=.ˁǍT^tٖR$%@PGjTvц?4""x#0q g_ϒ{tu3SX+NkR3RMTsgva@ #T0{˝w@ÈgtbݣbqK?p[6GkWU^V^wonCR?JDJl lTp'.":夜l&OA7$'L؍}!@5^A` $I;3lUԷ]cך1+}{f~{a׭[V&P]zxKX3R%!AKXs0j~Um/ZZN[τTTZՀ:6$R;J$-@:vxlAr-QY ( ũ'h*wEh)E}Z Q#X=z4Pq#mPN?=K[3;~Z !& ?F{FCҐ&2}fφxGxJGR"Oq[{C ibl.SÆEHGs7#_]ߴMxslI"DŽhB,(Iԯ_z};['ď,}tw`RUggf;{W@"`A,aƚ3cijh챑("v" wXȖޙyٝ{)s|A+GN1Iu+6"UvAQna_Bn,`Yڟ=r #W/J@@@RޭlcŵRƌӕZ³A  gw7] G!b+4B: Nѣօ"@ڠ1euif G=.Kֵ_a,aO>VXC2n\7#qχ`C.Er9in=x$вe~ P(CKYVe(Mzz:_sd"{99*@lG=Snҥ3V떡Ke!IpL-rTWYwC>Wkprbp/\nV[@R SN=]#]|,h:toA瑡CۋHDҲzS#YRq) !țof|ि .VŊF?il/&^モ=Lw W ^@mVB *?ԙ|4~l;\mvE}l|q"fZ)-gB87z;)FTJ2٨eX=5o[wz/r@K_%&i$Eޖrd~QWˆB'2u*(Lć)$K`ˉpPr6qU2AD24IbtK о\2KҧP{B _KSݿ+ԹJ¯Y?ٟ@eGB kق4]*s箯P ݨQvC?Pi_OdĦ# =J`rIdMyx>[4co<c'p)NRJЎW^9xm xU_nT4ٵ6lW5Mzs|ɔm+lUIZX E/;|J>!\w(r&ʫ']7~>}Zg[ j65=Oi}JBT0wEJz_tf\{h?*'"tp9ЛN_чQy? p) \fzO0Ş@ƷV7w~mTW7e&NTB5^8vt0&MgH暑 MN nZK֬ىDU`߼T+<mJBgA)HEz.(1hw?ބўC<[V/[LH`ٲlɿ哌4M֔bl:;MmۦJg”ɴiT}:Qz[HQ!DuNnѣ%V('6|jgh'׸r׮bCOj(h5*SA55mWePxHiU=nxbG9>lHSQA~ +?q+.3v5[`5ztD[6 :-(׉g&`])l߾ !d{ʉCwytQŋu Ɏ=IVO.8kíYl(2+nmK֥%}ߦMcX&tB e{Æ`$K:&[ Wb *hs/xmɁ>;=IO8S?y|U?Unj5YxCq+W8_vc NhZf 8 쳵_c8gsE\+@ ?PV Ǜ=w /LՈA1tE {)キƬ wEXa]ֳgK`~3Y3}(f[N˴<1c}mر?_=yݨQڎPVhe&,27@mWJ(Ĩ7;oc_(کntJI1jzfN{4|ݟ)>}d'.ƕ7F t_骆ն ;o .DWTN^K6Qa˔aUtR%j&~>bvHYGfڄW/[oe69{Ԩҳg^X4ɽ_4((|Q6ͲI/J@@T~cb3K4 #k(g%ؔ):sK`+z;THZ}F,sȽ:0t@9?X@,(Gag bN :-ev1ٌ c*)BjND:4-CvCqٵK-[s}W!Տ,EÕkn9^pHpF éƍ|p.Ks?` tfFS(z@bu1y:8';Рv3K^6ӱ|*$,;^M55?5$8 L rVӆ qjت&K[Lt35?@ Knh ,fL>Sy,l fh;;hu' p8>zÌ>{v,\}!eR'ePl4n۶̛w|=v+> ' ; !i*dzydR9ܙ2s9xv}?7@ۏCĺb|3#tЯ0`jvCCys(K/aFB) .T*S/PWH(4(gޥ/UT耐䂻"2yLS0;?u+@U:ڧ+/ǝpZ6mISG92n\wήs@LE6FCb4]s(A^̢6w1&ù#֦>q]j .W"aI[DfG5gdn]՛X~dARtiXl!=z4JjyÚ#KJv"=Q$c6-4ĒC'P^7 fUW^YnBB'h3)XԿ,.(z짞ZОNi߾4lCO`4,*rqrqa!2 쬳AQt*}ױ{ZT aCbH`o"^88eVQ:1i6O^{m|:;s*8ڙB 戃f)h< 4,#Ү8b}"3Kzu\s͛.GD6uIȑХ([NmrPqHykm _*ns+h=rU1@iFx}ѣ pl sʽC3ebJ$<5$eP*Kو&Va)~ߛD@͟7oRkOW_=W5U\.2&Oi(F^[G 'tyY2gZc0B8Ig:jϜb.P)2SIXY3e h]nX&LSHdJy_m+\^ UΘ½CW2`@[#ن ù4w5u?l=X$[`nSG@TgVLi._ΊK:M_<#8XꀧC0<wr,|'F:8P,0>[nY-JO`<($trnU: F³@Y<2\N|ԒzGG)($vTgջ%Knٳh2@F5gSGW!t/7ЖV:ˍ7A*oVgJffZH 7iFH{l\qkxW}ף] vƔHVu”^|q|(^sKaf *pC5%1?rU1O#>Z`NRKp1'<˘Ƽ̰ Y`c d'v-k·G] \ z_{jE0ŹbA1($r"[/Ϸ8d7@Mw&Xnݫf .<ߑni{{azI}W_TrBŀ@&pV%iX)AgRW_m{ϊvxiLxv̭}L@^?a.̡tfdC;P o8LV ̿]feWeԩ).Ub%TBf!6u:2AX'CCW?܄5fy)ҥK.Y1%0|x|KCjXk痄\FǎMpn7x(!7-N`BwR#K?*H||,|`ly0">H#*+Sg2#G&r, 꾡s@ ;;' g"7!+?;7v}Kp5 <'luᰝ;,D=E(m> \8P" 7?CŅ9٥S![7TV˖92jT(Bᆛ˸q]B7ړsBmNqG![M0x tib^ {oCcxOZ0hF2O1KJ*a94 h5;U) zːuqnCC[4P}0)ӧ76$ N?s=1ހM 1ϰվC+?DD`莒n k5vjnc+䬳c&u٘W }j ./WTc;Oq@_{e˧nxٳ%,@n\wMAF*Nߵk L('3ŠG2k2Qo$q1 x#z<)nKɣNm}()%Vh2 {1g)S&c^TxUonh$3>DZn`-\|c]w͕o~j_zECΛ7C kRvZBuw @셣2\9a *<3V}BJfxvU3. F!4%2U۷SѶjZfA9(w9WSxʁ9X;@( p M7^[ٖHpM-?pJ1c0Pj/c;Q}K P22r0Α^XjtobA?$4xb@^$<ny<xR 2|JX>mٲer'Mg: KjeXZAc>rσrl `#N/7%ܿT3XGI$^>psLi,OΎ~">鶕ۭ[*N*fA' ͈:f"4Jjw??[s^o7]Br`9/H ,UK;Wvij5^(+~ NDAn@upK;ѷ_gO m_Wςw߽[HMd3e.3 QݘI 8쫯{Hea5#^: %T]3t6c( 1գ*j 4\/xS{*22Y%@OSYN;+b ۵˃9XEE'}-7ҥ¾#QNK뿹\K`̿>ky‘"-Tg?ԧX쪪wZeȈ$!{]S L>ߒg/kF"Px| ?Kgrtғ컍Iz&lPpN@sbTo@EB6рUY3GV텇88RfN(0h?&HޡGt1˦ME0m&{MȊO^Gܯ:x8竆$̸Włd f*m'V8Q2ؘ1Pמ;X_0BYkUpi2B]y`U1%R7>ڗX.p umR9N zΝfD4-h4Y%*jJ1܍R|#[M>@ҭ[s<8`+$ٌjtEǦy AhÖ1 ƏzL/Жmasn#}v'ԩZq*Ph<'YUov 5|^$-)T1=Hܯza6ݵ·GTMt!OުĒg(jǯeW?NEڷ:?՞S =P-'Q0/G.1c:V2!p䪫Þf=rmWofu8a qӃ0@JJ*¯zD,NOY;H/HBh?(MjDpr1PVj[񹯜/cċYS:P뻷p\)[ 5HJrTϤĉݱmmm* 7nՈmUQZ| ȗ% $ W@U;N}3Ŋ@Fo7+y%++C<|xH|?YY. DJ@b|gv䚚BubG]1Р2夶T{ig[nc$|ƃjyj<3HU@r챝9^~Ү]aާ /šðPױL$@#@ q,颋KvߤӓDCC2Ŗ nWoѥKs%ЖCo/2 >s#3 FI@JO8;"K}R)^O5¢Ex嫓E_VJMv>n)$:dϞCT5&! *W7WȮ]8#[7+8Z%{<9j;kô{UקfrlQ{ +\֦B<]b,_28 ʖ{#HhX`5jȪ gXnWW_aJ!5}׮b'yKgt#%&GlۊcUTlԪ!5ы.v4AҁWlxᒎՉS*r^e侈.YiQ{UTg~-fiAa̙VvVW՚Z+tE su B,Ri"=`*GU[2aBw㣈X1:J?~]^ԩB&h] okM<gכxoq@z 6-]&ڑ3ga4!@5U;XPs\8r8<Ơ _l#V)[c:'G}SYuTPǬG}; F6WW۴Q# {c f#/~k2X`Na "":klؠx Qe[uO1eٿ*|Xm;r*f?˵ݺ5$Ծ9@5-L%V;Qry罌{цRӽ#u^k4%C 5gC^\{UN}jǪA^IW^Yf!&P}+oփ\iUXR ɓ{ȑ'pf-pkx;TY>_QȫW+ ɣjhs&ҽ;Ⱥl盧Xm:eʂ;p<K'x\8 8` &^IH\HVnx.6tX!EBg{lwyp P gyy]{#י~$M`!-f8>uHQѡHc(X"xS%pw7\v`tq 98mo?p@R_ ݗL89|cO:{н_>K a>x{<Ѹv5 4{}Оwjݪ5̜n3<Ϛr˕.^8B*&tj}"&|7lpkl) AHqL'RuWf;%L7//_vQW 벚hzKΪe1]]r( ֫vH97oNtt݌!<=0Kc֬=z?nG`Ѣ-r-!~UTV|%So{ݓ_ThY#дUUPYRP 3^WHc-0k!ᅏ\b./C w ?3^a: ݿWaW`3EQ4l[E\J1+U:HY1ȨZ^8醠"ҧclHYè.Ĺ*gO)EæMj߾HMdF{Xfԡϵ׾@+jtK@F}B+BmU 3ó#4] }vFc[8߭dXq@PiUVV)ȗjxIU[ //mٳWw X})#ܲ$.+vzꙑ2vDJuw/g_4תu>M"]h. t;.=eĐ3,RNfJd|Q'QO_if ;+uctT^}:fcL;._6o-{KdU-Ze:$)aOu<J90xIߍҭ B`(#x=fSHcߐJ}m _FczSzl-TC&t?NIh^GwDU(Q1D^1ٶM}A$pQqmĬ}!g&23 ,*g5_Ja]4C!&*^h#jF|U*/^x$g~P k~/ӦKXyD z:+#9[T_dD)V"yɈc&M2W(zKs-]ii%<啣ɺ_pC)d?W; T4: "i_`xx _>xrL?>X3rð]sp;`Z$ucWKΦ(q**+j׶5 ѣ4jokꥯ+C ,+ u*!%%%cGt/E@Hǩ+q* lu& 4fDϞ-] PUx~Ha@9^y`ۧ(XPzc& .-`L$#PRRr(tbfd,ZG]muQ&8Ψ\< Ctk[*C`^ RGuu8ؖg}0tS(]@|rn$ݝ]|+&AK:4iUts0:}<"%3f F>nT;HV{ d77T 㦷SIzL; \x@֨SX+^H)TI^9n;WQn^H~~SҺ5}z{RN=7?)qJ30mK6]UE۴ürJ&V,ݟTeجx%77[nXnYͭ +/j޲YJ>}@U4$*Mz0omYOjﷇSjUm=#ּK(>f%kuC%R kcbf8FuVu[!Æʵ׎H\Yh8RUu, _KEuxB@M 5/,9x0[.`y&PG%GU 1`<$ TqE[Bkhd;JE=._CzYl6ή\W@n蠥ob Ug.]ԞɮsQpwuBn*Bvm=ɮ]PT;x#}=v$,Lz50V$ǎ,|Z̓WwImplEJu*[o\Hs%qrlzV?`׮bW.k_=I6/Cv8T[D ;WUT?7rqtθXwаSuns/<8z뱜 ڵ{ց~RPTN폭r!NА!mw[뀯"NrimoM Z&=im6Š+6~@o瑍\7ɑ#̗SNiE1%d#Ou^=Pk";7@f ǣO E-)]ՑPmOmjğV ]_|zFFi%/_[W hp8{Ie }d~Zpj-y@]۷^[HZZC'ci?^jW߸󟟣. M:ňZN~QMY3\իU{8Ԟ9{֮ ]4P2yf 9.07Oӟ.1,(1AY.2y9e˂T!|-16ONjcp!z333T-/&W]<ѮM߯L^YBHH rVXYҀi>G$1teBRQ^5{H%@ rɜ9keփ;  UhUA.SVgz3^m)Xw¨O5 <)۶j2 } T-#hۈgV d`K(X{BۭZOv.ž>̑H"!0|gԍ8裓eĈ|ɝdk)+W* @F`M mm=p+wYO'_З؛ƾ̑H%G´j **+!ӦM4Lm:f9ҬYvPb3HR@Zӈasg,vKqq`{%99ρ@..rY}pΊ@ mi+Xu0e/!r%GHH6<|"vo !|bئ9QW@AaaSܸD* ]eJv6o?'H99|G *[rdpco[x$@$@ILJIҹ;6j3FMnD{+n<HH(شjW[5O9;G}FnYfΜ*Md& 6HH!"d~,|^AZpquk!;j &  T"@ zY,:/Z|%lrv 1 ug,Y~ Q)5#bVJ,\dժV:B$@q'v>9ge)@oеks vf)L|Y" HeoW_=O:t3&MG@KyP˪r ̟9 bI/'NT/jXJ .9V L@Ȩw]d@逸^ΔA@HZtha}Gwo!m67 !i$@$($yǟsN?9heezC%ٿ>gMIH @D|f9dH(&ML $ D@ *.*wˌb?|2#QɋI TVzС )+k4pHZSҤQdj.bQ,1v[o ˖mA2fTVeÆҵks;7uO ;uHdmǕgm>X-o@(+zrHzK7ϕnݚKdx`@PZZ)۶ɦM&fҴiVٴ^nǨWESEBJz:wyQE3>ۈl?eVʜ9kc;ߐ@m:,^]^|q2Yf/N.Yf|Wc\D|Pj,c.Ҹq187n)yyY 1CUcej.裵[+u᥿쓯^5K8L4]~ժ$kdr2СYԨ#8[""WQ6V\#%%_rcBUJqq9 3cGRZC@ka)M f  v)s}mSru#YPlU B`̙̊K1H>tt9sȧQ:I'0%3 U4f:GQ{g[dfRZZ :7PZ5{76޿*o/HVv7:q}늷F_U~:s;]6c;хƫMFz Ppرj^e<[LeȽSΝW˻ﮒիwcg:c5>Zf4AwҺu.fMWْ뛙 3O}t>u%%:ֶTO߄v=wJH L.i ٻw|&/S2aBw2}tې: '7|- :t/S & ˘1r=7IM@/ކ-hVo~̦+n} (:<8P)˗k%XO3^:C˰aS۶qNiC2w:o|/7v 'Z`mXUMqjC#ᇿZdW]57D׌O _]W "n|[A RskwZt_wVc|95y!eUVu4 Y9%SӃX:8Gg'/*zS/TTyf~~#W=U՛X}U =Iaa,X,0ᅠ`+Y5..:۫+hsӰDֽҷoqI_\Jd'bMY~4~(u *Һu>wrG+jZGE/\ǟC@#yRiI-gH( 'cb1UP7X)|~e^WrcI@l/ C`8,$`TA54uM  kݛ_JMZ_=}0ō>|}+yrG63u\?p :W_m4\$̱_ӀgDR29$>/qBs NM m#, ŝ|+PR6W]6~bXgX:>N+wo`8Y`cb'9Bp ]R72)C Hq.k֬߆# 7jf;33MN?l}NVRAY`}g{ 2{jãz۹3`od]I@}{ wʽz 't9PD.ˢD۹s3,|;2lX->n.C2|wru_**˧׀$˗2XÃ*}<}h}ZaM;(@iVQQOX{,KMK~ yk$1]8-}qz45O,O?ֽ>//+E{M=Jx [a;@M7[=a)C&Pn<&N3# -&M1B!̬>pp[kj"!/̦RmI:Ϻ.~$X6[̒-r0T&1 ACp?l:z<'\nD2p@n#;,69WijMdҤ_4B;D|߸a5F5ق%=rWY4wWq뒺.{C^ ƒ^gq ik Kq]e9YTaYк@U{ŰSn0=H _kfCI™H,./3|ܿ*]/} :hu v`p {{+} _xk4|:#ֻncP\J?t{*m_[e ċ@Ix| @xm­F?;.oᯃ3 pOtUa/2 "tpg98MФ Kh/:9ՒЊ0J@TųIkvY#xhPugVY {Dug}82 ]kڵY3L޽‰v@ Znd8G}^Xhl=fg0Y= 4Lm)Loig 7M}'o}`U [wo]矫ރ 3/FmR  tp(~cک48VPDT!pt**\l? 0@r//7tyw[?Z/5i Fyœ7guIj_wC^]j~2졇6?YM_TT~".|u!鰞P'G}epTn8JҐ5@./ DCa~D~½AV^u/Ozj !)V:]xg F]9h6~.ׇ-.=UyCH{d" C_ES_)EEԷYb+Woru=1&b& F.)߹\NĠ?J]E,C頠{l~ 6?f9L$@ P7뛠Д)d5dH7s:>F_%O=vݫjs@PNL$@$`ɕWOIE8uFJ ~^r>kJ5S^Ja{ ?]/B`O.d_vꖐUu̘Buգyťo5@ y? ĖYqņM.;Rb[s D @m-w5A~[+*p |,).Q ߓ @ lNÇ9 ~RPr]C(".h$A!ηSZ~opIH >[8?vl@8PԌ {lub#@=5 Sӯm+ӧ3]-jwYoy#WsJ! )$@)E@=VJ}c g>%/TtP75˖SYg-X"_iP'@SIUk:u̯:0POf>v믯M>@ {ct14vU۶&U*N ʞVH!"alq<Ki[? M@ݬRN;m!n>ۙSQj ѣ Wg1 ":PX{K#1 @4Y =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M $THOwM$@$@%12-ͩS>`VIHH 8"_}7/G'p8vqb"  I@WRmfbW,? $n_" N] @ PH-}jra"  {P?e2vlƅҸqќ<O=5EnxAAHHHt,/[a?_:vl&rTW  ؏ƘHaaMi w]%6iU/0?IHH#~*(h"'v_b})hӦlFyeuz> ?'  9[r `E y V[AcLIENDB`ic10PNG  IHDR+sRGB pHYs%%IR$@IDATxTeVҥ* HXK1&j,QFMLILL4^ * * H]`i-3sg󜝙[=w{{VI.+gowd#gOR~9#      6m%--AuKi~Za< ytV2ZsS͑h9L3 K5h.\Ps!?J?Kv>eZxͱ1g"      r5gK^O.=Z\OC oezD1>W' E O8,edY]'T|WO[u&`      ޭҶ]c Ç%)-?_s$@$@$@$@$@$@$@~#pDKCD;y7t'~׍G 073su=Iu zku֓ZVfxg"      hx' N_\vi!k=        \|;⋋j-FP!8gd3 8@Ltm5 ͖6m\6nF       8,{>,ZW[@tߤX?&       P&aaRZEʩa?b  'Q 8@5LVJ6eI׮AU $@$@$@$@$@$@$@%-k#=z4?VJ;_HHHHHHH@n̞];u'U+      :aa3gDZq71~!      frS522e-6 @X`}4|rh-c HHHHHHH*go~G@_IHHHHHH $|1"{f˦M!(6HHHHHHH23s~?+/      Me>oB1 *sK Y>HHHHHHH@ ltP·lO 2͛IxFFn(m#      FO8+j HHHHHHB@AA @+pm![F$@$@$@$@$@$@$!`"      ufHHHHHHH@ PǀHHHHHH MfIHHHHHH>$@$@$@$@$@$@$Pn2H$@$@$@$@$@$@       F@FpD       44& |HHHHHHHd6HHHHHH(3@$@$@$@$@$@$@&$@$@$@$@$@$@$@      h(h7M$       @# @@#l" PgHHHHHH MfIHHHHHH>$@$@$@$@$@$@$Pn2H$@$@$@$@$@$@       F@I趱,tƖ H Ʋ7Y^HHHHHH  `L@Pݸ(ܹUPՙ%     hX7ܢMWY #;__i6K$@$@$@$@$@$9gL1&!0''4%6!Q$@$@$@$@$@$< YCVHHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^˗ #PJ (/K'      G       { P`/_N$@$@$@$@$@$@ @#n+A$@$@$@$@$@$@^,HHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^˗ #PJ (/K'      G       { P`/_N$@$@$@$@$@$@ @#n+A$@$@$@$@$@$@^,HHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^˗ #PJ (/K'      G       { P`/_N$@$@$@$@$@$@ @#n+A$@$@$@$@$@$@^,HHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^˗ #PJ (/K'      G       { P`/_N$@$@$@$@$@$@ @#n+A$@$@$@$@$@$@^,HHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^˗ #PJ (/K'      G       { P`/_N$@$@$@$@$@$@ @#n+A$@$@$@$@$@$@^,HHHHHHAGVHHHHHH%@|Y: 8  K{t      p qX       e$@$@$@$@$@$@$86$@$@$@$@$@$@$`/ IHHHHHH(pm`%HHHHHHH^M- 2)))R)--3߱J~77i.Aŋ$@$@$@$8N$@~!PPP,\PP"EEȥfB[XX"囌EE5Hs-b%%%FҚ [Hi3mȃ=/Xȓ#G $'|"9|8_?7(8|@[%1arώlJBB$%EW>HHHHFHEULL1Y=x0_o?,;v;mNpsu\+a*dG俣,Yrlc <OF-}r$#9L쳲r%++||ã(W[&ETKc XB*PDŪ VN;IڵKVu @P(Ҽ 0=zLcz惲~}]_?˺uY:ݯfkЌIkOl*ql 5i6X{h*`2_+gfʞ=Gs}-[6Xm1YY߫ClMڎ,LJaҿS3;KI^ P'H1 5׬/ wˢE{TWdLuYQ{kU+(Y8IL \xa 'aB_Xs 'slR{sd.|fOL싊j%0&$h;[ɫ3"i.{E~j_:B;\HHHH>ǖ% x@+ҥ{o6ɷnԉ.=utQXgfL$=M֤ Gy>ux4SOMh{ P([:f5gg Ac&5<&ZB[cLȒ[n(=Vr%y:ƃ!    0yYXƤ*HYJ:lN(oTݤgbR 5}͘$ ?>ct9AڴO$#Gvܱގ(ϵ#?Cf&VeʦMY啶&֧5@#Us(N˛ՇK3`rȻUAЯ$. ? PO,8[`Y_"Ӭp#lT{l.Æ6W>kvOe۶-J +ݘbRkj:Q:O6N84\WݻKWSOmfHHHG$ I۶ &V^OgLF`S!hUoe r`<N9svȴic2tlOzDk`W~'ebS6Xz    !@@+֔&u_~y ;K]rL0^>N0Oڳ稬\O;4Z-ft0Y@8B]O c@)kSDDiJ(ӧ$%  h(hԷ'{ r@LV/ʊBLS8IKk&ݺ-Lɲp*"b !),,\.g*|ke .0a"   PPn' ɓBms>5R~k9 &0+~B^~yNBI?2wJa $AӡBB2Bg[r*!  h(h7&@SdeÆ,.EEm߿*GN+5kʑ#X C`eK dtOC8E$@$@$@$P $@!p )PE8ysLinvH.0 -Ԑ !Eaa˗jd xJ`ǎFxcMeXk<HH@ p4ǀHQ<{qcLE>p8S&P,B~*4ceԨ2ztGѣn' @( 4r]u P큅r}?5KégaqIY O'u+WfʃΐO>M&RP\e-*(m2fLg9tcZ MUPi̚6Hp BaH$@@x x@K?< 8TC$3@O<H 4 ˖-ߘ?5҆ahU_,pTfWiFb eMc"d$&FIbbo J۶$&&0hPS& hh4Iw>]kj٩80ͩUcH@ 7HWcX\B3w]>XvjMsmp9:sH'>c'HNmsɅaL$@$(; 8آ.X)|[꺝|;g L32rԄ*Wv<"6͛1AQ'r`uTҶa+15W]Mu&L̗!C}vrc{UPEx % $@ I੧բץ IL^(&ME<N!,Μ="3_fLYf*kуh&bOdlo9ɪ cMQbyqq^H &Vp4O; X"SaH  ,\[9MλvQ|Ygkw.V!,g&z)Rl & meHl"?MK V ?I"lYwꠚ5|Uv8lV_}̞F+T)}Q40\.䊼 4$ >M$ƍ"vuD0*8uEBINmx>/_NYg#:8 R}ru¿]2JT/| 6?^HM@HB@BBt"x.۪sd]%ٸqƖOW^9+O0׿_,JcHɫنeDE$@!Li9C2MIIfUxAcV|m>(^c{ /!09`"#dy9Z&:aeb_+Wc{rM_iٚ#V+3=' @# O#ɍ%*\ Z]Qi!U8!4m_*2_Gp_ %r=hlwމL=6T. xf͸ϵEuu15΀(J!ܬPfѺ `[q7IČ9bHAaf59 *ƌvRA={e}j>ټy]* /X Jg? K.%'p JQ8RWzs L{lQ3~2e:H38Y) YDZ?${4?L 'ɽH H ̙CȸYQXvH˖pe>P{ן%(Sx6 WSHmh-Ze HiF|S~qӪP,$,^G/iU1Yes12^(4S{c`^ĺñK4"KWEYLBxcߟoU? niY3TMς?9yZ:253ΰ¯n,]vbCU%8zPƎ}8;_k?SM,][|K蘫>7G]R+B9`]IXw"PwW"Տ&-P}FYgu_=k68u&]30@B§ᗓU# CMϝ)H @(h^:ers~`}kbVA{# ˳ j Aj xQ]PycR J<̹fE `N0x6r&ؠ^uU_]}L7·3kZ` UTTbV.=?˾#9gor/ȊXhFcTh,[I"0dȫjζJtžFiżts Uku-V[$&haZfU-eFeu@]JB;KIU~0nع,[WMlܹ[lX(pgveRRt0 6𿔜 P K) [9 ZL] \ Aɻݬ}rt%\#GrCsv>'= ljejyW@l ^g-}M}=Q\fMeNF~r i9)P̀$Sj9K\xwAzfQyXj0<[咟_& ;|m~؄u= kdhYE;裳e үv ub/ii aXBOʀ:G/\U/MQ֧s#lmR^X 7x 涳$gFfQnU(fNMsX͂,=X7WIM-x7p8_$-tR Ǐ8'J= y-QCkRRFFܯmFzunCAt)x;@9RPa?7f/xn {8l\qܥС|* By!a ݸL K+N4[]BHᅱŋW$Twt;W[ KWPՁ Oݺ5Wes1`ۅLUMEV%AB5[0**'Z˖PK5]FBZ@( 1v&hTMhl꓾vӱ"W ?tyjOZI%7khGڴ" J\p}-Y~:qo{V>w.+?'ZPxA`g OH;9N&[4V$gӵ?^iD۵*x@cxߩ:5{x! G󎌱[jfi*<;ɘ@X(j- Fy!XӦmܪ^sk Y 50w  hM\tZI:8s8_ vوb@ p.:xX%0tߡby2yp}gkjܹ;5T]=[ER 'x!#9ӝw^7j5]_G".fVen0yxb]離y[?t{nd?{9a-nvnf ZǟձT[BGhH3L2~>f0T{YDؾlYQ 5jMفs.2jTG# 0LC8MȆgQejmTim~Ashn$ $q,\ tʘ 2q]QLhFG s]5oxUe'SPcUqN,أu2e š&VH7&dxqjSt0N.]8Y+Vdm8C̄3!x51 o$|0i6N 6q33s0nSOs{d nJu<.ꁟ|F.xnnbHC J+WfE}LɆ%7m`|j?GDMxedЀ$}cjt]32t}7^jcY#3WѯYVS-U%wͮ~;BBsƒh!aRy8/MH_*?X*Z{xϬFp}X!yͥL랭;VH $&_qۙgv6vc5Ob mա*M1SOM7*@zx0ƤJN|E%iO4cPZE5ռ&Xj>#Ձm%SYy뭥3-w m>m}W9¶>)Lt?լنEDO+..#ʕxA͎a bj'E'3sfZ]cǕRfNNјݻPgXqb^DD]AmRSr -rLed#-#ސY-IIⷕ~ŧ%lp͎  D,AukV'Ax=,\K~{<\m%T1Xr?o: ҕI$ɚ5f{n 1nҦ'ؐP_dXvpu'g`4y+yr#Gw wK{.t ls{𭖉D^{BoN'jer&RFl)8Qea=KCOjhgUsQC7H=j;z{lL9DЗC]XmTh\ iX ?8kVU~RMí4}>~dQvƌbذt~s0]Җ-q_ڼ'﫼ggU >Hv>E2O]&}_^pnGž /QnキRn}zCRuw,/.Zk 8Ɗa𘯶]G嗟TÁ!a;{z5+I.sD9D~Ҙ?j]!f_Clٌ|x訂p-Wa W7 8wΨk&4JO KooTYk?מ۷.s>ٓV{7AF4?~@w_]+$mRzjSk=BJ$,7uy(׎t(;Ww {d:u=2xX10 ٗά@mO+<ɬY <֖JJJ`+XxnҬP\]}i)w=L 9ӦcԎj^^ JVJT6B+.pk+WJV0g6Y!O?¶_ejnD*MWTo-+h/u>^1J]fT}(/̘Uoebχ/_`VǑgÂ|P s=V+~ٮ[Uwj߼_B ɼ5G_1Oǥb}I| m{WsVHnZE:M)t(.mYkJ `ny]SP!IreNxN /q'/UrML\qf$**L7n<(%%yR8D|rIɪoV+ڔb2{Q3_,Sf"EEa0 l2p a$d}~B%.'P 9Bg}{.[Օ RwO0/p^ho7o:zU mw\\ ,.Un`%._uU}lۍg L_mwj,9{Mm'wΩmM5D %84uB[4 z*ݮc#V_. :u[U6س H$afTz0CU*U>N$̬8葪4E0G8 {'$cysI ^TT,ؤy~*Wvh4HRۙ$m5l55F=m*1hquU/͌7bBŸ?ڿ[a+{_i`S[ 8kBT-\W덊 HsCIsz o-gYn Z1:yﵙ5;5;GĻu0#"kk:Ik>Dۨy~O2!/$LKwQ~ڡ)0T0YSh~Ʃv萨m~/a5YÀɊ)AXˊ۽1PDnT(\ӯJ@+110+lӟ/z]fk„0 D 8F| kĢE{5zn.dM,&HM&T 10560)LĦXMUʀL;8VAC +  KT`m OߪQf6Т!͸Kgo/X8.rLJHq@`UDB$MMjtno}yD+(\>ܹ7Ë橧ΪWNJe{=;CxV kdF3`QAJ7hiZjVAWX\U}GǿϜMÆYV1ԁ'ZTPpOc, 9&RL$@GhQ*c]_$|Z҅5W[cU4(W:-pJ? x0_,Sשo3G6Wcn_%Zo_v{n@8L,.xIϞ2~|wuwS+ƛvnC)hݔ`]RRA3STwm%fBWb^΄v8r\,8[Sϵk &0o@l &-CoLU /ˌkt?k>l Zx>F^{ISl4pYߴjUj*P~?iQx]{L$@$=^Zx/_߄y|*'@F1K px_w*[Ǜ>oB0V`c"]NSYgu5h~k8^+r=ÌaՒf]ڱw'JDDy3~>;;Cj]{F&u}Ju.j\'靤Db6c LN?uua2H K7ubL..'\|qo6mD`؆;3khc 9ꡎxLoݬ+RXihVҵkyN!ܪͤ%v&MZBOy?UEE* l+{4k湦oVz˵8k{YEɦ9Z3훫]ҩ˹ر]NTI>XrpcSfv8} ,ϻ??K.:IP/[N{ wD}:Ԟ5LOKP4y OmHhcS70CC&Ccȿ:#v=I'2kD'qusU_/1_N<0}AϊCjc6D2e7OŬkAӄHH rs${u:>5l$cѡF !!t#Ft0Ms 0W*ը&V{:s7o\Ux 33 L஻jThy^ H=m<.^CW $sJMU{~Mܷ)L9r9pӚR_HKNWDx)TH]㭷2ExE.L]O<5_}eK-.SeUr2kCyZzb^_ -a"5bD@(>XdUM$@v7\(W^yxڰ| ctyf#G6mukDEEeXg {w^o gxǤq7o>bܮaY5P0:nV1Tnbq> ~^fkv7  UpAv}u3S-46V?;xŅ*4;gz.RGCSGh=0-Zzş>|GB贴frp:=dbGZU-HHKl矯,0'0u `2]5~rptW@5*vs *Tk MnmʞwoWĂuo;L vm'wn*)udG@c6L6m2ТEz{Ã,@NVJ{߾UxF\~yϙ g1AHBDN|4׫T1вw+XA$BՈ '^Tm򏽵8“?^nT;; ؆<0D$@AMW/ި H.5,,0'2u [w@mK$2$jy[" -[UhWUnnyԨ5~s4[Q|INNf✟vZZ]^ޅ w &'p;|2c ; vk1!O*VGliէB`?~K~V{u;L}57<%"OZkeXRWpa~ۄ/ 3 L5~MMMG gL3JV-5g 2}CBvEcǑJɸK`*WCSYWPljx Ԏ49pF+qշ U(彗Q z@H&8#lHz=塇~bgoTvѺyz Kڛ@uLuY/vJ̨xbB%E]T*J^x\&>м XZ Q @`RY{5g|U=ՠڧODu; r U*Q)%: o5z9vmURRjJYRZAe5BԉE1Auɒ kwNaW2SQ9]ia=9DŽ0صRu:S&D&M"ǎ|:5,fK=j=fmc|ߨX4.v~~"!~'h0@Ƃ1)f<4wOUO$3>|C2 kNXTA&©ԫP'ډF?XU5].pB[ Qse>.\ ֚l~Xv]Q{yq֠☪aa?rq { aMǻ_ fX8Z:'PhuXZGw=̵ѝgQGKuJ#Pa.fgÔm05UC@kRWΐ;8I}KL.ukHLRP###un:DVYv "vĔcE݊]75~xj3pZH|\rIoy4YjgzcKUU_}4*28}BELjчX<c(>{ūBPrq Xx9ImB[?RJ8SzxEi-I2f\z TzqڤIF*6}4Z´PZĎ5/1N4iծ8)_&?MQl bׯvgر]l:`V7]T6 mrM5[Jٴ頚!,A"إ 0T5VB&=H!z,S;W%o<>ylIIj/Sc% A@{ȾԫW+ӛ+7K\_rGFǺ &R>ɪz)B8wgzLe!wjδ`iРFO yj8=tz3k;| 7ƫPpmpSx>uJY#ЬY_р|~̈́VǍn<>K;$>>JmGUT;=RS WUp-tOLD x1qÍỏQjQ:ԉa:4{QQᒓSdrvvQ>z*Ŗ-tegF'Ĥa̞8ڹα"f ʪ2jU|z3ezsWGgVSq|EB8kB'x &@ >r͓eJuҾtR+u J&kdmʝ; bGE5Q[o)E/ke .iVl =쮕orJdy$@$peΎU?㈲)ƼE83'g@{Mx"\`BZкu4&mKdl<-ZĚ7v\U2v Kʊ OPDL_zivg?t$>@?0F-' (IGz_&Ee{p@=?8M7MڙKUb5?xMp6ϵ!(@1"·I@E@UM%Ɩ/eW=;H sμW]B|^IHa i_绰#z"'ѣ{'Xȁf,4V[BVо} O={r75*CXųfm"3gnUe++,S։r`e8]q.S/9Fwss9/MqG4a~inp&\'b$H&L8Icy3Au}pٰ!+X$0F@B a&5kP3zBUL[ ̗5kiR$i2 fdd˔)eBkaǫ @e_*',GGW.iVf9eK~~{mr!Cj +2L0?@. ]pA5vTyEzm7`LM+]^}WݏKH60{S%x0ǠZan&+WfWP3Brw 6l8Q]?blj2p{7V|Bw -tmMpm @ HBBsN?R޹s WA@^V_Ä~mHl1~|3aa94(!tU$` 'N."nj"o1X8cK:Q2_,B1 M`4 Z|kODif"״o`E~w}cwQ]KxIpwhqW^K[-ub-C4}enʑ9{9#iڴ8 .gNF1mzƳXG+agx`@!ڪqP)Vk6fT;wGr(L @1sl4eJ{:.]>}A@!m_Mf[' H9ᇣ VCo= ӯ`7K}GGGrƗq2ۆ c#\H,#x4 ~{ &S֮űF󄴺߲e 5ߘfΜj"lEKexg֭;A_Q`` +9n:}Nz5Ok]OlIǮMpJupfҶ X@ ((iР&JzeX%<yH:B@YPPv~TZceVnKr@5q-,,V,(dLٞ%V 5kV'{QطarZu y!Ҍ [ӏ<d@dAO1 g>S0)W'di(Z H3yKԱcO?_vւX=F%F7wCN[,#PL3!< v׮H C _i,YrJ Ag&A4yrkgO eĊn))޽㏘? ʱci|1wblx`oY^~vR@rbcG,111Jݭ[]9_P6E@i?њ;y-KcvkzZQ`޿uRn4oTiݍ$IX}  >4yZy6;Jh {/Tx''Ijdޥ\UgB?GKIɦ뮛2j9 Ūױc$f=_a.}-_~29M eFp` L&!>ԩ]۩g_!jZpBjO5iKp3w۸ ڻ723Y1N <~2˙aʸCM(U.n2d-87Px ߚV_I5گ:$^"  Pӧ3ꦈNvIuFy#@2u~s@cG0.I\N9։ZQ.쟛A۶fKt@"w,2na&$5,pp^Zwq1ⱎ>`J |p1_7*.U`c)sU<6CYO7+(aЩ}\/UVD@.:sOE8MjQi&$`%4&XeE<6m: 乹گ\8 G+T9B+\B?4<0E.+$'_sB ￿WBCC#MVZD#N~BY4kV6o>E#ˈ}_fMkҥ F<~/~m3%&+}ym}ZP^}fl۶29\z%|ry|aEE7:6mk׵MZ(&rNW>\6j-Fx 6%tCIo`>9*Y8w.G"[k=z3>Ԃڵ˯EG8#fsݻCKzYQṰV&Úk̿']Ȑt%%ÇN,"|5E5e+! <%g" ݗ LX}bi2ߡCCUey%fWǤ:ڹ aDBeG9s4Ҷ!pp7Rz( aieIb2|Ƒ^SԢE+()n+U<蕻]>`)"PB';|<]~1Eye#`97 .}JB ФI-E\k!#髯ƕI]uy:֮M6?--swF |g7Я|S~tT(,cEts97n~#٧)zkw ۸Û9i32&Uܹ xJ땸۔ oM}fREk /dqعu;o@JkAjY@V0/OjQa1c>}Q=6 @8D۪tV+N7k勐 ~e^rrrHkׇ%|KJQXݹ:Ǐ{RX)JMfEH޽"YKսs@˼J g"Pz~mF@~ )06Oڴo.^j?HF3\ l(ڰx[mU/g+"O8p\ PPHp?lx'g]ѵ}J\Vfѻwa|w uE^n}A@p;:6nBKŢu(YX*(}Qi˫PI.SұUg5%G4Vm_NiR駟v ~O:r#}Ԅ F/ͥa?(bN֛W T{.w_O! 1SS0]1C[ؐN {]ӣt c78K8_zÄ\4O{^բ?iC#zMػw}Sc 7\{oO YFv˧pzG|;oË@"o߆Ի: AlׯOL8\JSSRpCQe/T7m:?{rּ,4wyvL{ (X&WYgt6?@`Р&`~Qiq 7ѫQ= &ޡ͞-ssPl [yzvA@p--[R¯k{uno [ % `zE*Ր!͜˜qXzB7,|F &J)KGng3``=`oREKhuw}?qM9pR!gg="LzkBZ>dKӭqU`}*)f3,@bs)99ϻ@~C/#T裏F]|+#SYv9_?˻A@9FHgg?XGB TB 2g)ZHڵ :Y###S\ 6#ٿJ3Rx1'7顇_y"@&~.sKѓO.g }1 JM͠g]< G`̘V#( bfv1&yNp1c 3$Ϲ+‰ ` 4th;9s<}X⋱-|xvYDu^=\5KOK̙_Y*$}R۶v⬭$@пin)//C /fƻJB!A@6BByK[Eyvm"soCH/O;ڵPÆh,Cʟ@^@̆|_op=Uq-Գt̾癙=̝oі7'J|7.&QtiNQQ ?H7<6m WoUU4E]/ nE֌FR.(VFɓs^ZɃRH1cZ^ ?hogݔStpb.9y:u*Es[M]x7)C5q aAo29/vKo7c1D>98zAfhwԛܿ24kws9tn -0Ռ=+ 3y sI܊*RD(}2ըA}6BCr]jXg(B7D$؅ '=)ǧNs= @챼JWJ񹋢p-VnBY@ݻ7p*?Nm{~_7|t5׆҄` A~Js?8D*ټY;(P?>R_!A:{l M6~uMBeեjs`1;NYש=rIdb12#a>@> Lݛ*A+xG|(<-μMϗ}|tnIQrYz`2;%< ޜHgn|QuB9r{kX2QQpf[LkZ* x'}}-~dE. "#Z:}6ƫnˊ,Q9+WN d̙,5#i ?KP~-> B*֭JLQtL ="JKer/ؙ}g AǎLbQlFph2E<]ŝI~bg!!&ˮPzsp9v7JStuE9$72hY@99G}pfy+wHd |gXk8t@ڻo&:\t|'Z3,D/Nwڦ*x`,Y1 nP |OL0Yfl2h`ů|[| BhUH܉@1[̙GxwFQvvcԫW}Er SۅMP͵ kqFэ7fvIY6 :ohҳ';&Rm[U0A (($lj?!`H[gsɝw֗_v,'Nq,=*E+=q̍EfTbߺD !fyIڵ > JEBb6(fVb.T%{wNj2 N B_jz۟{,'SV6~D`?vDtf!_:uZ7z¼uxa@.2+,C{.}FXԿ;zC1 s`z) xNdH),()  PL:5l@]̖A"2 ?7(eUIA'n]B{w{{Pdd0^K'<#!`na=о'aȐfVWD s A%- wPЕWZ|_A .s>ȋ)5n1őZHo3~q;L[A@@TT8CGիCI_j-Yr/T":H2KB}/69hPGvK[oV+$ƤS" ok )#A!X[":b-5]W̙l:C3wx,x>,;5o^*l!L;#GФImm\ |_^dLzɥo3ڠP%#>9ub"#s):Z" cY/D-]m+=W@alO_J#( |' eM.iCo12(R¯颽e C Z8$,Kp7XIe ؂ii4u\:w7Uȹ`$S8x<~ߨ:Oi]p ϖ֛cuc!VZ5g/Vjc&o ""g@SR&uLZHp. 1~'9ГiZsp~֬j?2  %%~sH"GazE &= GгdZ"UTzkjвe ukU`l 8<˃ˈ5%f⬩2 àՉ/$8oD,(Bg~g9]-p6o=}qʢ=)) ti9b|3EmiJj@g2ӬSiHkmnX*GZo-畸8}h53{6MIɤ5kȔ)_zz}||k?yt]WP7GF#$}L@77WexjmXj>#@F֎@׆&!KHr* ( mʋk駗Qa! ,;p{ XzOk&Gm1_(iE.<6N@D@hOup}|sw`N x룆έ5iڴE/Ic;X/ r;![Cߝygrqg |}L69*GS:U >0Q*:{ll_b .A(6{)7x/Q>b)AVz)<{]*C@f+kb`IIiTo!jkVFAu72#cz/4X^rEZh{|~3h nKZŨ|z)R7!!0GBo!{]H?k"{kF\,ȕ[Νg)&e! 7@|ӅlE ;;5y~ĉLB!H~#GS6TvB!V:RmCGl$bcҵ׶zz5c{; nEGр?tԴi ?i!A@z@b֟ @@ƌ ̣$Lyl30-%yo>|MA }t1LˑBo͚dڲ$?~A'&rkWD0߭ ش< M+&Pاh2}vm~ WM܎,uDBrBrVLߴa܌\^r}A@ bik&?IFlȪtݮ],X# -nL|#Ytp αJs A؀+#`| zu!:ҥ0e빚\2喹J<{+=(g, .a .g@|1  `@6ܮA%gassԯ_#oqmxo%y+)Ѿ}g9o1D PM\ݰr #( Cl_MRVb~F G !AݏA#+.R 7w :iKbj֬6uuV?h3~|^|p0cV[!`AvfB?V>gGȧԱcG@hhd&MpQ&$8}:28C@tK:v n|oӤImS*HB_}5ZpN̤^sz;e}?󕋌+ kRjӦ#|w!TߦBNsA_'Ұa|{~2IW*~llG  ZXV| 5L3f"~UA@f5tSS^u#[]sMO:ʼ5f+x 9tm]+9qZ?9VYmAǁ2תtk| $ݻS/ӧӸb%%PLL59s¥.V:q*GTcqeڴ^y{t'Ћ/~̹:uҸG"@k&⑷Ǐ>A2+ %'{/& b3VBw#XGW5eZsqD]gmQ&?bGz*{:Qmٰg%\8@@)9[P@\N!z/A-cF@G{52xC@x=۝ᇢpjsىА!MyU6a>""ym^? G{@g8ft%%sLJM֭͡cx|}ª|4`QDU֢0Ę $&JTPŠ{mӔ1cWfdK RMu_c*㫨>99[u\Ղcwy~% xE;f9ssZ@-q-_6kJד-nݪvw_FO?zg@37Ӳe DYYt <OghImڍ}/5oCvS27P@ȐŲ5FYۜlBst-sDA_x u6Pa!ރb i[/]@Ӟ6,_߅}Rl@@MҺk7\n壡5hnNjO۹Wjߚ~q-Z%'LҰɮa峘WθDеkvL;*h17 I_}uEhelݻnqMv)4oI 4D`Ѣ#矇w؁@{2v:EOh8 i/E(t?aKHCapjQr.\dZHmrI>9o#aԻw ޽EQqq ~N `يwWr9êǿ| Y`Z|?(+ ĝxdDGk^L|߼ox_ԬY '#Pך_[C\!Ah޼&` 2jjc=ÊzJ w,hÑ#8 _2 W62`{.؃Kt>}pAX%+@=~a3_G!REW,!Лy⮅~4iRCp< -v50Oeײh]yT~D;o )) ($>wՍڷh=mX! 'cH5U*}"liJ׳g=ZA i59T>dr=3e~ԥKc>ePq:^f}xPPx#Ai_o{9<<BlF@P!¹s9 i/ϕԄ|OKNQ<ᦱ [  Ca!d6V4]wǡ4-lYck0t&YAu'4jTgd1k׮u9q I 9lyЎ V'3ҪJMܝ#U B{zm6)(Ew1_A)O8ର.M&A@5nIAiEldtYw& RGxaU^U#ZУ5QSݺ%l}6?D3g8V2޽8֔{,LAn䝟?[AǨJR4>@oEVҶ]*?r|׵XD]քز~_={R` L ×igt͝W9%^yzL,c#ދ-,pmxTm*~sr 7wNּtL@ [0a΢}e.jX(XMD`'|1y׋49'ӋVر]\S&ӌywϷ+WiZJƵem3MJʰG *GX+i@ǘ 4ujޅgW4ȗ_ng sVGNx1:1ދ}H]pg?|+""±'`&Iu[M9Fp!>` Ń'Ea ‡X}!J͊XH]6Mt%͛dzKx^U"5״UUea>9###6AwmiٲiC Az t,YL?O!%?t ]l:zx1o"#CUE\xaٲvKz76n1#W ӦMɬ 11bjd#'Z"Pn5D6-A@ D'[ԩt.!PW/H%9_~9FMN` UvWV!sP4|x[ 68x+Ã8 ! Fee`VN]5*Gjܭ3?!C}6n<^ WMerNz h͜`لM{9⋭ +A ]VbMzMyJn\Hp :[N-"`bRdfг.=W {Y:J8#@Cnt:jU~y5kx.0?E_@Z5 Zs~ƄR:11@[̼ =mp1ae %wVnvshJ1yg7p oεqZ%qħׇmf{R5 9rJ>cg ^!<9'̥|^H!uFvmSSȵ%oWpsw~jBv>EiXmBX@(jNoT4 +;Ĕߡ(}"F fpŁwwB "WFP ]wМ9P }u*kOk!{n >4\ZqhP_|a+G-g;yC7J* 6#c6D$KWEw7[+Uʚg̍\D/VV(k薔dra/F?$!\IMΟ}%ۚs-oHG$C"ј]qZfPP ^Ŀ 9~r8X|hVho]9cǶbw"(%\OFSqB1 %6,W_]o}or Ts8`]9/(("PqVv|sfÄR Ļ)Tڮ]g8*.wqX`41"/M'hǎ3"v˱#цT'AE~VykӵoGqҤԧO#a%T7(> Ipg|J-5,Y9:1Ƹ ؞vdd38*:6Oɣ[RϚVlB :իNynv!!=y"}uO.h^Ī'I+w޼r%&LƟȑ#i:#K6\]/`!j<]{mJzK `I0wy,hd3:*[!ZaԠA YNVDrkhʔtD&[ i?s_nM ҫ`_*wߟ|1GV7A1cZ^tР9.o1LE9f!M7u/EߜVՇ x9YNx\e]v\V @1Hwi߸fs*^r,Ә=tlzs}6lJ@w_ԢLzh1_vTTT̓5zl%ӶmhjժN_=FjaG}"@`}6#iȐf,WU0V+?}YM*}TкO>o~~-)Uݠޞ*w̧4uu$xӪrF]|1zE灉s # @wC@(evvS&~ %QdRG#>A) 3;WLcp:t==$г݈gER5si5dI@ ߗU8[o 8Va:[)+@s3Yt.U:⾎'* ޝBoWS25n1}wfe3СC GƵ!r8!H||+;a`5M-  !!AP N]]R8j]A,7A[p}+#/oE5m ~p,*~ \`76mji/؟qD8gIϴi=oȥy:=21"OyQN) ѣͯ#.>L4t 6?ߴo n}[O$mL;'OfmzZMK={Z/K q縯`*&11zk@|/Es*i23L۶qld&q)r=tr'P[TSuݛʙ `EB(mQ& o piq[ w,*(}(fΆՕ+.WYM/>ʊ>nγS_2?&@뇀lRףo}{קhfҰhJYk#:~V7 =zt[4yrW/YA@LD7olStpO*;s&[mٔCǏ_"ê? k&o% ktt7A}L6Oi0>}WWлmcYKo}ZY9={֯\f;.W^I;7><|07(;zËV}á2F9Dau^^=!k^[K ـILՀ]wude7+W&)+\@ӦqOyͿ/U0ԓxEdד[IfK k5mmd4aOty| ?Vm1'M܈ Te!LV#.n]Aņ9[3( xf*b05pY@M_h+?:+ [)϶iׯo?@p‚"a`,7>8I FQ_p~nRAt?!`OX5?8D7&sY*\(*YE$h4vlJSkќ9w7@H`bϳR'rp ㎄D 7 鱫{7}D|T<[1\?)tqvJtYNpjaڹsmN5 \[ok4܁W[=A:Fhn]A)%x8bW z%܂=PE[n c4rg11c->ـo~6vdZY9 \wԱy!W\ F8(!;)9NnJXTTks{c7UܸL]\0gXZۑVW]Ն~{w<7J{m$l&HnuzňWCw9:j.J3" ծ]f4mEb޽?&`Ê̝FjqnæU͚0-? V*Ѧjш$2; AG,x`tS'и&]q8 _ ]Csf(77]pV4c?̩j֦76CBC#9FWY{<QTTsEo+'ZFWdas"_S˱&fo?,ӧ%̫cD7@# (;]Et٤{:DG0?-f#Gַ %%2xչx%{!sL˗*kH#MH]cAE0`5 KLg)$ b`ܻ75 \=gԢEyBHK9^$c e%oc̞*ˏq-dQGhMWTA6aN ~@jjERت7"#}_ȸ.P3|^ERxWEDTzMԠhrk !VAߠ! iJ_P~bhCYB7Б`j[.%6\~5HJ8i}YX"h6Ka~ ַ/qMhݣ(橢F|( [w*tTGV%ͧ()4Â?$_@=7Z xF.kHIqbۉԬ(oƂ*ލx#f1ۆuR`AE!!-̵\<~KK&(iX%qHڡ5qbkR)wiѿ!x6y V^zi0n]?نB_A@vIzkB{:v,UNܣGیֳkRaVP1aR.BVLv(|(Y 7LV )X!gRN-衇{*4{^={?mv `wmiw o' Jmpw WeݍOмy!!}ZÅ z)Ҁ TDڷoH?0QYw^Oy41sĚ#`$vt_nVK8od+7PB~8_H}K|z" ӹMy%rvねúiң̙)f!oDZҔMN_Vʇ={RYfL֣bQNNmr#4k>[*yEQLLڰz8+`R@@ TD3@>= X(ҧ])99EhǎOd8OOIeP~|MlA=|S|1yLkiसe,t869t1ҝ 8'ծ]q}26O:Nٕ~3:p ȥOXxmL=\';_7TR@5k.e":^x-6+#p)6=u]WЊ{tEEO3 P+3r@b&  PfFp*-Q8<*уNLVTss!Fc1o&nlZ{b_|ҧ(/Jggp,Ӌ BʿhĈʍ`خ2%k!G# <'-6"mBwWq&g65'?@`׮AƎNk[Fѣ[2eIIHgWWoXF;Ә1-2 ~ &tÛkFÆc8i=nFZ"x { _do_B=V~sJNY ܫز01%~b .]KD{A.u 9oذ,jkR^ICk>(qnK/Լ/iPp7:tABћoۀdpT Mi_Y|gzԿ?VB/fJ&kkk}(X`N3 5A ^xa"ӀeB͞DQdYA@֠TLJcRMɮ!P@W_ݍߍ\,8>u!#-/ rP>cH"U=4yr;fT$ӆ;L܃VCl\`ކLUˮLۖ[N֡pQ\9:?TO r;Y<Qx3 dcR'(zbF: 'A  `Oլ5PӦ >BFuKڛOW{0_Z hc޲kC+Rm\MΝkSddե 矏%X8&qPiɿ:[FF9p;Ҁ sNNYHKqEHJ?}dv#rԬ0]$PY`иq<,'.=oVhWa/:Wr=˭q}|CQ98851) x-p+ׯK< }Up U5,oO'۶ի*uQxw5ơJq(7 L!Ax#o?#k DNaL&+E6Bul>Z^}J?A/8@697(%s0Ή$d_˗\pCG+ZZ *k0Mm4f̏TT7znjiVbc8E  j7ₒ}RS"ڻ z.QxV<!;):A; -~հ@*97@R.Tȵ ={[ロ]@]J|LmJJ&&@IDATn:D:Tz тiH@o{pqѴiњ5cn?cZ ߳@ڼ5Ò2~(l|JHٔXW\J EnxC#={Sn8-'d-@gm宸͜9OŒMv\_ %Q ="Vz~B:L!AӐ!R߹|sB,YkTJw͖ QΈDmeR(we< #pUmhɒ؄լHS8""&MA|s On j2ي@6V)S;z+nnE az7*351nE|؟T@E{IJXGn( GTd_@讻:v,N뒾+uP^rM/CBW١6LU2e&|ږsG\9շ%<;d'11];w.PZQޯ:[ TF)&FoxmjwbΫջ" E֕ h::p,-[&𝇢 7CL0mo69syOz?ݻj=j՗)'VB WP@@[[֣jKS՜NjjWfp`Tt?%>ge /^| s֭ŠƇ*&׬Dyhei*swan1,#c0|,&%@ 44:vWFT\\BH(Ҟ{;t_E7QCQ#ZE;MH8ih˖tdOQ6'9XCN1Xj׮BHxl6UΊ #Uf'a.K`DRPI B1_862"8 JfG[Z@U?z%99zh[)#ٍŲkK/q Ep*,,}sx7J!pm+/ַz`/WeR gm`[[sa$(JXPxRr arf n "6jV,낀 {8qM03yU:Gp! [NN!Q~~1oSy G֭J]ԣm<9^ C?UW|䑾twsJCFroC/qMX YTP zu.U.\(r:( ڷr.z UÐBNC@!jUi]H v ciڵ+^`K=|(~1i5n0Yr =]`VJI{PyD-gdѪUr xa_p-PC!88PeEyu|=zMm -Qrr{\ 1LJJXf G. &Mjb%sDKqG :j)ʄAWؽ;ECx%O|_/&!(&a eJS 9itk_~U/:gi\|x2Pt͋n!|s'prWrA;I.Q\{- @*C@(c|T7ds+*5,[^A@$Eڵtx&G|}F06Xz筼Pϧ#8]9jƉ^tx͎`HGtj￿22w9sִt*=S}Sj$3QV$]}u;]܍68!j;0)$ޅ|e}$:z4G>WFt MTwiR`  P݁>p$3eJl,-_C )ҀۺQXSRr% };+@uԔqcӝz7ٜV ͟n=Ex@XA/I`^P  )ލ@xEdT3M,--cń`5UjY4p|>rܴi zs yD\>8,ֺG7Xe`w7?Uj>^CFDp tpUPl 8ObAXG1\Zq: ‚9 *lHH +)6Vd\@'\Z0bH@R yi&MЃ>pɤ n!ze,?f1oAC=rRPP S+k0Jo]ڟDXr\G`3l'`@24[1pN4#sF'O4w$fEZ=Τ{n9m1C~/lJOkacÊgeeA1!(xAHLwdYD`.4hM?|.RC/<^{JY^^ - D~%94D7U~y? plλDOrAQD(R_ E;)p!CC S}-//Yu+#lG૯/fHz)#XU^)NEJ)8dWSs~:v `QXȪ>;TUaBh4ujg CTD`Μt}_?e|1pA|4()I~P ގ@@@ۇ! NC@A[J(ǭT\7(Z&5o IF!x9sg>G?nIAA=b/;e N0dvp//һ  j|+8(ET{Ib^ /-Zf4CX| Awm 7 shRSsH.\<~فǗ0$xnDEȑR!nj9hV#pMsd>k¿~:]1=+]@ ! 2ȕ@;|elZ -P,5״+u$އ>7PϞ}XQ}vWUA*.gˣjUR"r,{5b yǛ`2DA~|y&e?*l>΁RսpŴpԻw}" @}] Bcx4yr[-`^(A(**\D3gn.]Pll |lСi ]fjp:JOp\-C-зNÛ{&{• hR@jGM qnڵ%  R&0m$ /,C:֭&LhMU=/\ ,b?Iᛑݏp ؇+_7|ୄ9E?-q:>u*zh%%p V\W]{He':; z< [<[?#DHU~|p0k5t=4cPj14th3:'@9!#PLMr?/ FWp^wQĸpeںiSM =Re;f% .zSpjvYVl_B;󀏢xsi$!!%{&ҤI+"* "T("R(t&Ho)};N˵ݽݽ|>Ny;w3<{l֯?ame[p刢$0;@ 3GP]V#ShhV/؞ .R<|[!h\In&m҅O_mLR> 矏rܞ]2D1Ϻ-h:6:Zbg"7JBђ%]̀t `=M86X>ҩ&}X 8'`?EA&EBeȐTxG?@bb~ Ż|Iov^?8: $fХK8^;lՋ=ԦkSHoX!b'^I?~]Ϟ.4I@LI p,)ʋyQޘ1YנHE5.Z&ӨhRG!djL:u*w8 W1]u6̀z${[Y,ga=JKyԱ<86>)ﮓZ#qSV*ESΕYR C˸[KG8;z2p]KDUo-@^,}}i^%>Ꝗ-˰gP`k] G$С-XWeKտ"? ''W"z;UٹI1 ֭企+ >%pb"]{e)|**MϞlݧ?#YO ȫ).w^0!L'=Yk_FERddQ RLL~*PۜoXez:"HrҬ6_b"HvC2D6%m! d'`Ǧ}P77ܭ+mڔ+HU+uF6!e0:fMmQBBjdz3g{ڢfʗ_glq&X'#Lê HH:2ɿVOG*ƍ+ow*`"6j=4yGX;؁V(}D jeLe%)DkSU,< c2LYر"}ER0峙YڔN`o-0׼wfgIfWd,@ ރz,lA F%>*U sZ}oEjSbeHN7۷u#+z Օ-N@C8ng0O@Ԭq6Uam G*倀3))$iSYR(ˇ](g4RFɞvlTJ,`=R'Y&_iQ+pFӂ QZJ`.5Μف%hH^бcW.@^cl]},:;ԫK{>D>jrv' :uY@|Od>^ΠwB{i!o Y+1ŷYu]!q?.>ͦ1V;]n$dfO q>5Xt0ьxtLq[- @s;CׄVT8;2G1Bh$G"I@s 24m_g~j}Ik0=dKxGbEL!@_GXC]y^Yݯ։gqz{,XW pr")˩k|2nCbp@J J t8!Oz)h$lʋc}A@tud?4&Z7z}w˞wQU+i4{& NϞKnwȣ$ЦM9c8@^ݻ)SD'*FUpUl|y2jBnw!nXdܞϳv7dw7i֬(13~:UӲeUn4jww F_:iWSYj6\TlUhZv`5N*hZ/*'0g&݌A&Oڿgp!}5kw7D&w$&&i:ochAlCt] ),,ɱg9EW8SDl` @*uVI@G}9rd=֟Yz׮Q,]og5 :B2C+kֈIaҤTJ,'x[HřmU/zӑ#cit >e`+/M CM@zbȢ! (M**݀5$UH'dzڻIݻKPF m|۶8w.T=M.!.y˻`A_N?:Q%'иqn wŧM UT7/M{Wge[ Zd:8͙3J~\$~F஻Y\'>7`}ML۶-3Jމ#úuI W'4YL@;HOw>mР؊+ӣ >pQ`K&Q DGGPf%u/'% @$Mzɖ'TҼ+l@nw fw;"`O?fk7]?e)ު 1rرMFR$?WxQs %D 5L0#n'P谷 `t1b&m[N Lx#->z,Cqkm +yKv {NDZԩSOي`?=3ʩ @SoFH>E"X @*=hswqJU^Ϙu벴~p[jj:+ ]c2(.)1,G }ʕssbk l/6Kܹ,+\Jm4<͛Kj~ΧɴoEV]ӧŋS nH˗oX-dkV? %l)o+>2nG| 4nku C i)mpB(/<2)TI.b.7ucHo?/ L z_[ػ.+ğ O~&i?iĈ|t_-[" x>6X#Egffx/$ ߲ޓ4655OF__~9A+We,'c[Ȏ6)|m~IղkCT1>ߌf}Ũ@֬9J;~m{3ij".Iz|[ֽeFڢD))B6Ij>z;TH:yfL>Ze$օ;kMYYSȤs,^ѢGZpz|\" XF^Hi.D*FݺUIӦ"_|3zٶ빋 P_*W.}Anɦ΅ M`ɒCſ? Z>>uHsm)87 ʫ;Oj  }pZ B `3EF1%4 `f9]YJmU|6 "?Hx_*ϵk7h}.7O?|;N/j&]7G,M˖˂k( 7rV 'QPLW/MҴ>T `|'8qQZ`3~qKX9+::ҭ<%d?WG/RÚzJ hASB!MT>tjѢ2ygU"̩S[ڭX4jk2@@/V"o?M{wl~;pք|~2ʶp UɭZ&ӧ}`7l+tz К\Ѣ=nL̐/q$g7}TO !l@ᄏ% ΝLG VSFХKbn0th]p' & xz^ +EetM ]wOvX>-Ldu~+  )S~xT#+; ׽@*()55xcU֛x/ V f"?SL!(IJ2o_~yeh(A %(jXƐ!u6u+Ba*04-[NinV ݑ>%I,tUڰDn7^0AupF b$~=^gfELj\M.c$ %JDO? et%1QcIqIkJ+V ek vyU1  kS~cٳ!O|'_ ʣY| r܊^j渮 2~(E1hϷI`$hlwOi̘V,# $ q&O}6_~y._~6m4|D Yi}TT>v%K|dUA$p%Ü 7!Ə&}GBK{N&MGtz=Q[=. cԭjٳ(U99^xh>%~1lYD.J2`Ԗ_MA   olvA@r:GIy|V'inҤ$*/[b@^%;YdKuޫq mUx- 6_GM?>*}h+JK|dueI$$ŁupX 8#OgPLn]֯R-vԹ<B֭P 6@&?9ß$O&5 6mTںח htcn5xb|r+%EuՔ5ߡ{eA2b*FԣGLZ'ٷw$'q ūn /QbFu;RaT!ЦͧnQGK噪^b6) @RGwSPm@ &7{x/u^/֯?ƢȤ86s?i5vUZ5 vUnB:͞;O(rNֆ.\%u+fרU4cF;^pu\]N7޸83J1grO"QٲhРX(J0=@uרQvVGC|k@v/ o[K@MWEsBsnwKPn1.JYHr B~5hذ0V0Le(Q_)s4bHPZd8OW߻yIbǕpÍrCr&W&c ;U -X˺- WBǎyE1kKKŊѮ86nIC|GǏ_N7/KRjj}vZVkaqObСTxL{ƦU .ÝU*1ʗ/N MիN-|Me/޺ BaAP-( իǨ&ybh@@ wG^DQq{p\RSxRd%|gr[f#.`DԡC] ޠA ھ}gZYe76$V\Ybw_9mI)1ʥm@@Y)S,JdoV(@G2I2v_ nw<ӖxnA0QnY'R^*Rx[U"͜y՜ے$83RȤ5kbo.$AlقI~F 'p( 0~Oh#gյv+Wwq6hAfG4n\3Vqz6ZF'PT_lǎyQ>i(6h[76 .}!Jͷ:{//r [kMP ~i䖮aʱcTz [B@ +r)_PzYA5(|_z_Tg{Tk*Tez/9@4%PT2b]裷s3+2A}>>4K[@>_.P=:ZkԈIuR98O]n%*U*ןP[ 1zut%JH+Wќ9ٳ& :"`큯u DɕV* /ԁ"#9uܓFԩ$m4C޽q&MLmڔUUƩSXy+@hh>z!@( ʠIӮ]1wi!ꫝˤMdOeZzf*T>} 7YG"ЈV!CrjlUC˜0A'˙쁹@:t,D;|ғ5k<͟TJ0#ީHr}`*^\hd+@2rD: C$Fh~@@/KOx GLL8 Ԅs*˴nqr?N{9T @ Ve {/,GCW1h@ lЈWL߆Od꫻^=Yԩ}8&c6wbFL?U}\˭[4 @>6Kţ6\?2(,,jU(#y(nwj޼v[%_VMYwbPզChϞ2Q(i `O￟R!C~GN]2oe~󔖦v/ #k} 2;ox,^\Qw4-@/TZX'JrXnnV7 `Ĉ6DYKH_mbdr~kgyvpyb3iŒ%bK5kN#bq"`aSʑ5qa |Ɉ x䓁dsUyou?v8hmBq|*7(?.K'?N=AE< .;ayyf]\l>;N)=Qx9W'ıShӦ'ĉaOs#$ N$,V3Wx4zر[,LYvQڗu)ԷocKJ|*kWG-tv˗L+hf>="QhSڰy%Ìo8W^&jr荃@o_Oc.7ܹ+x}I'1O3%07Ry/0 c{JŋG{_-!֬y/'´IXv$OL G˖ T;*U%ԯ_BҼ-&{v!?Phٲ =E:fq/rtW&GQ=гgu[#W $-D;:|"a_njiy`<)2\eԾ}b %TI$ʟ_oV 9/+dLh!l8wΛ4}oPQˑ]?8SQr9)@zGn6ώ;z0ϰ| <ij4m:[M8b(+a ;6J-~wVܠ)SPzXmۖ2Γ lR3 q)״tbW~8Y;we+Yt~gIqtK vzQ\y= e@E)\B"X?  `(;wc(y!,GB7~(X0W}i&~G}t'V?"ٞǎhSe9JmrBx?P'W_f'<_rɁ;w1w3&?aYht#w &m?%0`@-b![d?^-?l򠐏ۣGVPB0";Ql 7 X̙="2|x=Z g!ў=RBZVxKvWMֵkVZ :u g? 9-}w },cV|c'jk{U 70-GF4ّ4ti66=D֟ΝPꥩ@119Oz"dY TT"o4ؐn?c{pHRb;׽{ew@}wumI_tTE[GC(>>F:ʮDZcX娢$ @kPPN1sB?tF[Cg .}RRd4t.sqejhAAYrNt8 AjK/9Wq~=,ֺyj#5-ZEH E߈S,o(dOKi `TZ}Ӎr; P|4ՐOh߾iTtQNWԀWO4A"q)N[АX,EhSW 6BHcNc1pW/#YS>)+K-d:vSʖ"1 דڵdkfPNH =ymP:-o֬4?AE5>"-[6]wlY""Bќ4qb ~۝N#F|˨ض wiA 1(|-[`JYzp b>sosqH?  9g)1Qy}5 i̘ěJT{Jzy껽۞Uq#o z@@NisoiOѣћX4iR6o>qoЯ NPe)yA\$|ł 5yb%8=|eBW$Լ@jQ'HjgKŽKL9^ PF3{ITUj. ( q-|h%;]&\^JV4ҝT)/Q8(MNX!hMڵ$6aҺnKS˖UE%8g"tuOϠW_D [hs[ʼPk<4iRy5YH~.}P7#f-8];듓dD) 2@]W&AlϖR^_,oLL8(rz[B]ʕcTZbȖ9% 'YCPR4Zc}詧N;P]ko/+y#t1t$Cy*9ރ bu 1 ,du:aE>/~0ɹ>.کDIPHVW@XY!9x!5_K "e*@К@T#Ӛ9Ӓ7ӤIk\8I'KNONභڷ'y~\[tt"2C_Yzдik B@`2=v;8zL-Eei##gp|F=R8*C9(^~y9zU+QdzGDD_3"9j A;3@B"-dH>qgмea?GXy@n)O@=\;̜Ig d +g(6xr\k; /I:+%B3gs̈p6%qy&ڵrX{ |"pu8g ?ɭvMbyi8[nj $Z\&>>#0~|3Vh}ovY8({7"lܭ sINb:>A4 g3e& O> ;~ȭ"IԴ$f`s*֊A\! PW"*-NQJPh[上 &Ph~j֬Bb˰n&\u&H\?qTN1Ƿq@+Px iӽ|&ԢEUڼ~> fyZpG K/u$98ˇJY4_%XSV<@II~qҎYp~ʐZtD6 +VCgy.dPuxgC`0 ( U-u_GXփ:|XvB:J? a (\4   |e>n9rml2}{5+EVөAgv+V,D?x?Wq~4fL;zQQ M |̞OP*+⋿_ʳHY16l =t< M`9SlzIG ( @үNSyǣpJMuׄړ+C5;^ % Z۩SE5/G lE֐~{ip @@IcǿJ֤qY[k\+SW|W |Fj*Wd3:rDVDgD?FUQNyb2jwkެn#-.Q -:.\:@ΝSݺ'&_UO?o08yNHL3g%"fmKskJ|=E j+gԩ6[ :hSڰQAXE*OsNVH̓ ,WGH5{7Ocy=XtK`P!6K <{Nr,O|K))4r7;Yωyb{_).22tqϼmՅl,K5jZ?&R650LJ|@ @Gxh._cϬpɓl .=|(!! ;[&a3=bbfҳϮC.s:0&KZll٘=# T t}ӱcz=2g=ʳ"A Ӧbs):uu\=c(4417xKge>Mc"? [<,~J`֬+2篏50ϟ3܃ɒDy(k&EDfJSrtlmPjPTlFCT ?׮%Qϲ`2Adno!6%UggO׻رM_Z-MPl?>>%Wl+Zt:[Δ;F+X2 y f^PI ,^'˹uZ#ʕił A-11|<$XI jIrAY d! 8K;@;wNC24u F$ʀRi7W1G:uqJ'R׮_5=oB[~\|$,d*Ur:_% \j4yrk?xU&*E ܀KvwAcvs͚#7e?R>>jW?aEl8Dx饎,D#KON- 33r٭0:(ރ_uݷ[ :ӝ4~WMV%(d%#MP"A'ZBJ> HgeAjӄZc'mfQ1 "|Fc@XP??ąʪL1+>L2(xn1ʾ [omVl09gǖ  m˹$j=wxY q@`8uu1*fLE@IΞʯ4+fW䣇^Lr43UwtW URH  g'Ȉ< 99L\|EHzUŁMYϛ޲҅<p@DDy/!w{Fݙj` K9ϳ8bWD&IڔMM'O^_+hJ`Μ\BGe% ~3a  'F- &T޷4)f^wSxE He˾J SE 88n/Gb"E`Zy=k9igȑo 7*(s[q6\nGjz_&Jl_…_V@nٳuVA 6qO@4(U*^ni ~(ۅ@@)crb^ t\El̈́^IrqGbp$M(22El&%_0v,>D'J`C0ct# wpIq v21 DQ(ͮ8&"NzTraAw?y!._~fμͻn! @@R E B|&L(@1=8qwWL"d/ DT=x ݻ:.,B EC~2@̃@4vlSO2"xkX#2+[ihA 1'.^Y% ͞&MZ/F;uD`^t5XDI%V@HSIӡC}51c{fQZ, @@@(e#o1_W8G}N`ԠA#}<dz7>p8O_kLWN'0p`=>^N~@@@@}P5@X?Y;Ŧ5k =JEfmZKkd__xeѣ>9^E\ -(_ {˄EAdPc+LfO?Ɏшq%q?|f/Q&Ũi:uSZEc!*YR&?ty(~|ƨzRԼyic )AEkoEFJYLJOϤKE s'Z|uM䡞]K` 8~j~-Jס_lOP xaCVټ%`䳗IX՚x_a~_+@ۋ@B(Gmei J x0@ʅn /cPz<6`-^c٥-QuV&0#'݌-C@MI4ȤEV`8ʃ>ΜD3gfok <Qޟ.˯s'iΜ.IkWe' 2ee٢pi9?(](uP'аa,@~$XW5ߥKEZ{V_КZG}%.F^/)A 4kV-^%A(8[oÜ?U>9fR!OYG@@5 %L- xK*5I2 `^Po27 ZP>G}&;fO("8sQv6UCME[]=.)~oI 5cĠٻ %&e~÷ѣbmPNq!7TRLcWc%[U@$N|[b_E3I|܌H8ſR/Iw& ޘ@YkA~ 6mԷG,?wQ{;\5 (ғh9DQйsWyk '!>Z`\+gFꚦMKf78Ý8ڴl20+f}nmM,d8"11_?A0SkbTu&v8Aי\MU, O)K2dE8SJ/3ĉʁ7 `F<И,۪ ibFF&(<#6#0/(۷h6o>M))2'IChԨm/Nxfe{gPNEf[u:v1ϛ ` ދMdE~ z02q]|@?I TQ̞ev`j.:KYuӼ# `cҟ~CRRIhQT\AR#uqJTM/PflK{"EW[EWVN8Y0ýяۏ{)##ýLHM?HZZx%w^!nl|^= {Y'"|ѢPb$0-(L۵hzu\Mt.[+ 8x+(~bq*1p7'T $SV;*Pp@Ps-3CcXi&㏇Y>KEq@|HI(CR]tMkr1Aj5͟hÆ t `|̑ )=]OwHbo/C2%˅Qa t"B9j184,&/?;E A`."= 7`z˄:~z2"@jjg܄ z/h;y~\Ξ%fXnOL@#^!sp)LJ_oe2h_.#,XX%]bгg]3n\3v5/%@-i˖ZQuKiB4k֏3we矏_I7+B+VR:ނ9 @`~Eغ }NT^矫t5A `v۷c&Ծ7\swx.O}}gFb}-t\x7n_ڇsy{BaWQs+pr}'ُQj1Kc(4g"ҥ|V;*#HHHsATe,{ج!gQod1(%Ŷ?88t!3@D?t~b4#_8rXj[j |^iӲ7o^@:$@Ãm*4T2PٲokBVuS^p:#:K`̘\NbԕҜfs6 `V2=Z7kB[GkB^A?UTHjP:_t5{U~]}5J-=%(e@0jHNNU A[1cU60]!/8۱VҩZSsAMFWܹ×R?p BE> @~T*0G.UH{x IٳW=&i8s&NMWZ2=DKzN7Ri߾-A ȁ2 -?vpժɾ[-/^BÆ8&BwjO FjQ#̻j.M3ow27G(SJxIQ9vyڸ*--7z8]TREn z#zBOwpkT:% t8[)g-JȤ ;ƍ^Kkw_LOj">yy /cNJ*1N񉯏Ui(n!-@9 ,Z{7j͛E ))ꙴ꤉^NÇCdSys7֬M  `4B+Wtu^Ne"rfDc Xqg6Ȯ>OC~NWq5ҁ ,Z䨓{rmUZNN@8D%G!>l^]9>w3i̘ܝzVr @t غD':w~^~㊒J 0PŰp:/qgXM۴)HD\#0}z[n߭I֨¤XZU>4~|3UE GPW v㵰(TE +T+tZ"%0"%"($$4#J95*Rakמp)R`>409)SZq SB.\:1cpޱc5 t7O&>@{Y!Ж7jKV(|>*Q `| 9s#iO#/nT"[!F\]{VWÜD~:@P ѷq!CcE >NԷo w2&mR(h q?,2TPh@bbkGՎ @8*NII |7Ԭ |#Y#}nE@ǎ%J fM$K3""B۳gСj%hذ^ `^fuo^~QQJ=v[ƅ 8^zEu@dx!r~EFmfVE@47GWRSh5Ҕ33*)m^G7%>szn]{睭sEALy#DZ~dp( `zuMֆыgn{r?{Ҟ?JJkmr2pa"+)fTgPw "*W.H9(\nHGH]/߾h*U D̚g6뭷v(I7c"֍ y;7ߑ GIXyz5'Y {řX1^\A5  cj]-9(tA{/%( RltJLtt"zyY)|0C+KNrE#*͛+zq@N,J-Z|8/f@UG׫ZoH&+7$t 2>62eP6U= 6-EjѰFcTuuQ\]d?& St=\E{@0Az-93{y%#Ie26vEW9VPh~"#[-AM[ʕ1V?18[/9Y x30]hݺ,nvAbtgDs+4n4gN@3W$QBS9 0?L.Q굨a44-.qxڻw*NKrPVӯb f%c/*~ em|J6/ u+Z}5%7<[ʾz>y9!2|c?#0iJj|e~ .h^t 'E l,0:Rȥı&sihV*&ۅ2yBzn4rd}N`ܸUk_QB; "c: ڞ>̜ۥp: wƢwGָVT _D 4ɓ[S>յT|;HXi?o sѨQYqq㒴yT*Sa6b B*qTf=Zl Ub^'3nס^ !}{O@ q,Է;O>RV9t#X1V,cQZLYJQ}5yg˖F&z#Т,^M$s*Vl]pxQ zȦÇ(R 3Yi(Jqc}MUNajZt?Cر"5n\wN_5d 9ݻ }C!)+@NU r8qڷ+&P˖yYI 5l]úBhI@,dC[=߶z} | M`Ѣ,8]2{ɖGd/jWALBN=ؼoGSr3w$E@ ڸou'3jD @X*G:! ?uv p,jC: 2es|Y.R2htjk*=$X@>v*[(˟1w:.ֹۛ+W"]qܓٶ3z<*VJKö utM1q7zˀm+O>E ^ǃ=ύ>mo͚%paQ"(AhgZdR")X2y_fTT +V Bt% @WcA"`fnjXL|V:QQk1|^Ƣ*q:@RRR"oB))J*ցy /:gx9چ.4@ri⋿@6GEmrV@@r#p3Zb|V%L x? LŨ]hE (SJ ܀K1o٥Kp֭[BCepMs@@r'P\AvWo*_lBjP - 9G]jz2@4=Է[ '96'U|=o/[ڄ`ApD`|K s`JLL5vT5@ H}a>144f|Z`qD%н{en&{^g-[kJ61uR\O. {Յ4h\ڸY&ЫWu.\ewAC |M8-&GB[7QB 㭗K˷Ԋ TQ,hå&C `4l{0V bB ?!пMӵ?NhSF/49)t… b@@:tr"_*ׁ 3;s[ؿ714]~v8E 9[۪…=t-d]Uj>,i˖Ja]1pP g&NleEIg" ҏ?o1! X,lMhɒ9lڪ( HKg>(Ǐܥ^Ho$$ D@EWS:"M)JҥJPJ$tHO !].vw77;3vgg~.{|g"))g9Ŀ;,8AMbˬ2p$h0kY5Ӭ;dpLˆ,$S`„k3snoA*XO6[$Ά3v>#ps}[ ۡߔ|1ѳ瞣L)~/~ٯe3?#>#] ~AEG~)3;H#:TYYM_\8հ@ (YCtN`t.bN ߑ/Ѣd=l:E/gl@~N-[Z rx][OE3ʔ_wݬI~~o}kDzr J. ]Xk^CnPS2F8y\̜h~㽷ʈhQQʥoۭܰj+=I D \w\s5RtD c7qׯ:!^! AlT9=oA&N ;;G'W (@IDAT .]?@ TUWܢ3f1ްEzl@@KԚ2K/Q 5 RP [}[ (,}@ˆ Ʈ n ֢ 8蠁&"%dd^'IR'j6PQnmO(@\|N.e'`np;T-Gj7'#D@?x>{Icc9Ws1(n2|xUJ77oU%%9Qt 5 ZKgmzN9sKAAkC `%)yP@WLxyU颋f4{.p!mjZmVw1<;#+>Gg 2%pFSՂTVt] Z6"6 \~rtM4΅#Y{䨣0Yo-S!7Ź6r9LI89l+~DL– uM ܹZ֬wRϒ" ē# H=~/W\9\'0.3>Ƹli+pjr)o/__N `-){Dk25aGjealgE-\BK&^Jkk/ @3N J;q:?%;;}K̛\Y|y8k 42|%z+@M;'v}A@}w9I;/{}K-V{2ӛop%B/ z֚z/P&O_߯&sũtj(674bʭ6&5ɔ6wR@"poYLx<'&ySȤW_hwe?@ ˲rzo}~w#/@#pOӧ7ї_,. .kp%qϖٳ2%Mn1KJ ćГի4p9½4\QfA lRc:w9~d']6xzYٷ֗(̜yTWc;o-@ -@x̗^!lR貲Eӛ$KlxݯLlkhtr*7kwٸq\p&pvͫ|ٯ,^xa-ohʧnl%}3lgS2$S]-~OLO!KK;NS~4 z

U/@z둎@ʗ{yCzĜc^#UҮ0On>򳟽DZI!|wZxtS&7m,$.yҵ9n/OJWHNN̙Gٽ{ɣ'Mak$ؾ}{SNťrٺu<z=˲ek'ڞ0l})s8-(K6nDs{kjƠpW+Vlsmo{1oQ&o0 @$Q!`:יmu02* ll;ѿΒqy睵ŞO<i#G $J@|pr>ZEeesY4b@qǍ6&p}li&(wor/@K#F";w2UJw@d̤V,YsԴ }~O_VfL\+#n5et@e¢W4Pߓ jhQ)rxW{_&7mk ĉhKY`du %fJ~ɎNNM'[X @ @<#pɣɰaz%GOl -/gm'ek.sg] |nZAc#w9߶B裻96~{sꜙ.cTVF<M)@m0ziln[|L`-la%Q? deG-_<0pKtxYp@Fd;=zʟtt$k9Re[kqn4Gfn;ٳ! +Co6ewņt3N5q>fAUǧcTBvqDBx NsO0r?yr?yؖwee^};: 3 WOT?ɯo|ٗ2dMi'?yݼ+Vl=EJdJE`ڴ^RWwys2A;iOHeܸ3}oû[oakvÆ" zom4}e~@ q_~SNի:o%;4Gי?\i 8sڂxX`ٲdnzKSxSZrD#P\{H)\z̽odʔ;f߻E/>}Oζ(֓9؇dݺ&MKK3^'VpNt7h'U-<`t{ٴ!`Ќp@K)-N)-A9#3Z&G {[rESl޼M˯W_]!TWW7?s 8AZ2FO5u%2)Et(0zJ嬳!g񤔖Joi*}q󟟟#kr^u_ FG3!mɒэqfU4xi%N.1[,;r=zVl :]"C6X.@rRDmc!SVJ'A3L$QZ9tʉIO]wf2[';s啯go> b]R-Xc=m `*I"О-3$3 0]mҎωww^Y*4k$%%p}$ [֘؂2mZobS{\.PUU/skjOة۳̚*gycOϕ_=ؗ__AaIIef'7ȷ_G7|ڽ{df&#tL9R, '\]L0 1#}vYc;);wPUap'>bʧ;R{ j랟:wR|Uxd Hv /'!(&Lj x89,ctnPnY`TR]^}k|3eA7 Gyѷ_yߝ=m ` +"бЎ#('ϗHٳٕ@.9IG, qФ@s:|$bE:WR;P>+58uĉ:h\+uQRD5рGS+O*N43?:+BYk쐙30Ҭ3cQ2$Zpzb[e ՚ !opGAV3ra ˱Q-{!,e˶J߾יBiN'w(GY"@FA v!Cʘ0v6 a @ 9yy2gW#yԟ6UE1ݥ8Q%N `.䢓ٜ׽]I׎y_O:ܷ3Nh`pr814MR]]瘖Y~We 1 b?vA'TVɩ>.l{PO7s MQ"?AOM]'ЫWia_Owg3Hڸq44$?t`m G0 M>@1A3߻RX+7LJʕ'MN91#DMŎX/@G4vaúKG8@P>zXr0OR%8)n]e2ߛo3;>*,̑q= ,F%/7rYrϿ-*?_Z,u(_`WwoncGʧ-k^h%CO'8 thS_NL|UXhG>$^`ժrOIv%r5feȿ}g,Oٗ<)*@U6"9w׳ϛ7(͈J/88#4W_Es}do{~>GQ$`J@<<ts̪L-k۝ 7 $Zύ1->(,Jn\%:DoJYf)}y/ Uq.1E}Ni{Sӟ3m)Ռ$'GggAd4~\vٳ&f3k<&s˄ibڸV) K"5|,1X|Їؼ<Q\$s}F3?(G$N?E)nxK.P71,fe]Y, $ Ad@kűtb[KrMcq HnnsE=.0|xW))^9'H}}} Q@  ?_JϞךC&]ޯZlAb|fψ6 #vÇ+PTxggo65 74U"p[M6Dw*ɫSRQQ C"euud.WL֑)%KD)hQR}c7=_8,Zt,^C9RZ}yf FQM];I ʩ6cRC`P8=9j )G5.,(6E@nnϲV㯍׎@u+G=AyL;[Ir$.<"7'>У/=h0 Oe &?: C%#5b{\I51OIIO+_}u}X`_<)0mZoS/,j`0KnңGQYd$W"@ ;/v8h xa{DV!sߖc? S!~0&2_O!iGJ@oYdUɑNNz)Z^mYnNA',{…ߓcHYYu|8Fm}QO?VG?cm3cm%q: Ҩ([n{[ʰtO?NQ1O>@ۯj1n\7y8\?lZj˗o/)heF8 q tGӲ @yu"ddd믟 `@cc@*+kK&V&wۏ{@-qĞ-7:8}ܹC0tO,>F*+u / ֗^^F d@s\h."<7 G J9`o!~o[m/[yI4ٳF @+htv8 &uQsQT*{X,tV/W/u#pr2DDł L+C\('D TW7&>SrLm53#֥n вZnd t(.:\[KPtV X&P]a:4`0(6U@Z¥J`}{Gv0(+gJ;v[S#Ƨ вRRwsZ{fkPI%QA*^/bGuJqqvG;yb7(,d{s۠܄wD/0o`wFp@+Ϟ ;nGsl];sm%)!@x;x7Lk /?fLp9ᄑN. eC$ $7gdIv6VAJtS0靫uq2=([j 8(G4ā! j^o`8W9˶JtS --U52 tVओF$~.yy|?v@M rjF.zZ? &3Z()ab="/q 8ۋr0sx2nWnksF[pF;P 0u (ӧ{fD \r [oʠAe2ujDP9\h19(OaJU@'xI/(s'tB`Μ2|xI_D9"PU^n벲<?H89"ReԨ ޽%[@ .qnB91qՙ@_UUujs UQYP&: @u  a !Ct$7o~3'j/X^nsp/W0)u#v2E@qqN >|!3 \sI-WqVxX`.Fxy y KTD VX9}$++c:$_#ɀe nV, @t iu_]Pb.h$}\wOQRU**0^ϐQ=K5@ [$:8 ߉ԛc̪s޳kǴ"ھ4e2۞3 DS$p!PFg?e Vg"~kG_JnntRl;"}TH& [*yys=F{^Zeذ ҙu* ɹњw2yrOk#I`>r=t;7JQQ<&Kj ;LG:R\' NOm͜'/4P[[W)o<w9 4h]4 vif?~) g@\wW`:Uoz•ffwWX@6oN-ws,'7ơ7Dݷwӧ}Z]]/^o],˖m1 $㻺b[a}40\[ڒa; 2䘬DU6 s 1c*! 7.31OJgqǍLpd^+_L; f4"߿DNyESM5x@22LԸXVJDV8hw\ Z '2[7g;W`͚q+99yj|{ ŘFlOK'&I/dRM)yLlS,a$>5 92 3~;]( TṕMPd~~Ն.9zg_ Ssr 2svgDhM$K@!ҳg~Vz!*O&>:(TOW.\njȇ9Qtuk:yyD9[hsg|3L+ "6 lX%Q9XY_\WdĈr3_)>rd ukTŌ;/+WnmvKaa '!u3܉K'XL|TN՚v"7#Yy?pbaWټIfg:zIOO#uc+dذH~Vk^k?g^$:9B$͘\=wV['?:o>E'ZjjN[\0M4ѫW eSi PZ,:÷t[ MtH b'_ |pҮ]B}ᄑ%;ӄfFg,\fOA"S;:s^|8)2kV_gR-W:>1xviW;nD< p e$W=Q@h޽̐sZTU՛s}޴@ (`0م: !}ӧ6W{ۗ)#6ȤKs{O󒊊|ryS͕y6Iz thyo2iVVVFhfqu/EB@#RRR̓GJe x[ԩy2 /V H=9#B^9+tN@ \y^Z\ >v1r[D\XtPyBo (QH)!"C2[@gvuÒϛeA@p"6 s.i"U~T@S ^#d;"3q' dx=   3"A9Mxҿy4Ķvb{$;vcڵ75-:@@(0jTys׬er}{3,};F_Au@@-ѣu@31V3ϜVi lZ^, :,   @Ə"4H׮'$@,E}Y`66l./fG@FG).ΎfW ȑ]-L `," \ %  !0aBO;m#Ftڹ2gN6a8E(5駗Νn׿ZT@| 0n\RYS?O~CfO%DF 33͚J0(/ KFIQQtg̺[ ʽm޳Y[{Nk\I(ȉ'j@@ r5hWO1W̪"ytOw1&ݻɃ'7pv;gp G u,DqsY_! 8 lVy%a. ͐Ls?Kz(Izܹeƌ>3Gx!7 *5/f2vҢ~j(ɱo$V,  @D@G\r yUtYrTWׇ)T3??34i`.J]$ʰa]$=G$>2̔I'})** EnjsΙ,ӧ v/G@ 1 |=U^#Jq<6U;OC{ʘ1drM8"   B 9- $W` y-_\\ 6V.x涧$@@hU }Fa#2G2\Ork=   %j}{uHP蘃G&  y$_+n)Sz&AX~MLb@@ `*i" ]B_D84 ]6s(  .aMBpMI=D((}ʜ9@1@@@JVj (hi.7ڝ@@\&@e Fq!0zt ^n*QҫWy8SK@@|(@N!peMAl,05kɭfac~$   L}F Fɀ]v&n2arC) !  ^ʏ#堃FSMkg =}Kf[ HV_^=n  #=@fT'~B;ZƎFO@@R (<匌4$A@@p %C`w3ƼUM  Xb駛QajL@3 Lcn fm\R*@@jjSޑL~,Xw A p~QBd^RTcw/4=C@puG~e"[[XJfhIk4`++eÆ*+$-@@ \sBS\H?ВR,;ةKX(3[塇>6IRC@pL^rG,'WKX&0n\w '*?w%9@@ |2n\79a2dHӊGy$@ Ad@gFjЉS:/^2n  r⋧{b(&nH@Ŗg4ڵ;-O@@@y&V 3%'+ii֍(hlD@@GpD3Pӧ(+33[  n ֣ѣ:Ռ*`*KQI @@ phP,Z-qn ʌ}<@@@mbVr}I@@?6uu@EEeu(-͓ٳ[ !  T5kv/SrqoBk (7BRx5 C*  Xr<2š…ߕt^'_S @ric[τ  \`׮:y٥roo,6)>Yw]KM'P^n-{ȴiH@@իPfcjA9SbA@@/ rR7O \xᾦ~q4@   ơh'pCdf΍իH**ˊ@@@<ЈT^:TS3f   v*pɣO.GLO`A@@ z S?O ddWh\Æi@@.@-Lrs%%%8ȸq|mD@@4~0Q~_OеVf }   et/W!@Xg?. Ʒd;"@@44DO٧\^}uUc2~NȂ  ~ V8∡k{Νh:6dgў!  &pSkQVlr˷u?ds$y@@H%M>@ G˔4]{dfm႒SD@@H 9>HII#`j G  x[n_j@L)f|xeKxgg@@p %C )]LKJd   p }   c8)(    ϖ@@@p4A@@@>ْ2       '@>[RF@@@1@@@gK   8Fc    `lI@@@pLSP@@@ `-)#   i    }%e@@@#@1MAA@@@O}   c8)(    ϖ@@@p4A@@@>ْ2       '@>[RF@@@1@@@gK   8Fc    `lI@@@pLSP@@@ `-)#   i    }%e@@@#@1MAA@@@O}   c8)(    ϖ@@@p4A@@@>ْ2       '@>[RF@@@1@@@gK   8Fc @<|A{x@@|%RYo~/y䫯vImm,X0S2  X)@JMB46䬳;xWgTO&  n ֖T`9͕ I,Yŧ"T@@ :'BO"S -Վ{_@@Z 0 [@W\{v̚Ҭ55@@ 0@+x͔N7kkj Z   К#ZSa8N+_`єa _y kFM'd]iSlR-vK}]il J 4N4I[7] wB1kh_RypW7GSKLeC|$E +RVa:PpOJȴmy啲|6˝uǎ3&2b2\W(mRR-eeҫW[$#Gv/F}[omc[iՒ.EE2dHY|q ( 'hWР'kD^ziq@+VlG4ԙԫȫWo51k9&U/x6' :SF ݦ"ޙt[;V?yV͛?tN}Y[%c6~c @@v֎zY7G鈁 @]>xuP3b@'my_Ȼﮓk+e۶ 8 @߾2iR: 54T] #'lS~O[tοS]W{^UU' ?"30K)4kQÆu e̾4Ջ !G_ˊ?p?v@ЫO<,\j]#WC`ր S;l ԕa}4~$~Yn1p'CT סbAA(fg)f轚7_C o1Ap_;j;Ys20/Ҏ{QQ \Bh.\#￿AE`pI#;?5HT*= C#08eJ^^Y5sR_ ]ӱ?9GICC۴tk_ : h_fdgJ.9f3 V1th] cXHYw믯N~Al(F$`+I"'ЉdIWOYu+{ O<<2yufzvb($ݧάb:3MGp̟?4) m?/\~{}ij#%"]G:骶I0#~Țֲ#QjO:&A;:<Աvuڵz=;ߥ1;BH/uuZK8u'])OӟzLGDmmHZ]Ӥgn)2A]Kd̘ ]2Cϴ#h:!a3ɚ㟅&}dƌ>+f'.キތxRbDYH1h6י 9mD> kM[L!-C֬N~7b޿`SSqٵ%re,M?lhvЌh5k6+s5`2`@ Tka}{Bs04= @[ 9 Hџh F%ddnСz_FYLQ5v06KyLsU"P*z51;{byX~L_ﻏu(wf qN^0I#.I8 |z3yir・JȀٳ˼yo9mx ع3V!(:;4Sc+E@ )z7V˿eӯ:tByx6qMo˟\+aA ͛ f~.=qh3@x2|-@OpN`*6lSO}} U@'[x}hb8ڿtsbӐD<̣ ,øurf+呉2).2kvht},5t~C#́I_4x䓟O/ U֣Tٴi۾ɬK? ͱ'62v [@:KqlKʶ<9Uc;@Q>` ~|33$}yS/O$wgy4(P<άZV){ Bϡ * 4 ;[r=7քFOZٌ+Wk?Zŵ'HkO>¬_>CəgN00vD H4 @w2 M\sB91f2F~">~}\^_jGhmtX>lOwWtlٲClj'T3н,yˁhNoJM`unyܪNHu"׬,$R :'V;wr i,!y!TNmʅ{b rXyNq\{E6<"~P_VSfSHXQٸqY7yODgK?P,w'޺H~K[YWd0Y W@fI7 _9<4>C_WTIi!Xop@ :GVOc]CO #\͛e ڴS4 f!p~3hRjkMskRY$h^gAA<0l53" <-L/YV,ٳ@NZ-vb( @ ^ܩdl2';wN hn"rM `D0G-_U}vKLj46m.",6TDԈ̫iFK~X24*3L%7q'Κ@ zRv5WjѮ[1Gs?YJdV'bAg AٽZmm&׵y ֮zs"T@kgNiJ |k̺^^|q̞O w3Oz~W+˻}Do6To6#) F]ֺ;ٺuYseo_dd%9&;w֚No!4_iP Νc>,/Q,hl TWIC^%3ӻ73҇M]^UWz:?GCC0c޲K p}mkl ihh ct=N 4FkzU/r"ωrۧ2o߲JJrL&5j[kd~i2Y~ӆͣ8sCSOc'Z6G^ʢ4|TtuղLq\z~Zqy?#WYPьh֯H;hHTo5滫P ࠃ'&ඦm h@Nc#zv>1M1b^X.hi~6ywh׫:t^몁)ls5m`:[κ~΂ [{oye2xp_"}'XX-y6g pvP:<-LC]wjti S =U'yۼ*ȸ^+￿jS6le&2C5ؤCwLN{zՇλA`A +Ui;̺̼ϔУssӥK\sqf9L %,a$W`޼2iR9QyLR:/ɥ,?BvɮX"b6y/eɒ-c̪*'qs+@kHXH9[t.J6a2Ozo^!TNmʅ3~#uodn x>rJ3iٔ>Z)}n3Għ3K7o6ī2YU~3f׼Vւ@'OttS}CO;wYn&,v_(W' hg^ңGt^iGB#?>3ӎ{䝣mS~SiJLևFkjRY|WudfXAH@gرCWuA%2p`{bQ5H6..qԶJԱeVLBQTmڎ,. Dd b ˅$f{8!!{{y~̓s9}7>3y5]b2X/Nm @?{wU::&75 fyOG=>y|3"4M !gL%yfٯ'^عsG|[.nqB]+ q;Nczv{σz6Æ.#ݙn[H]]9edF{^Uoj0 @_|bE?@fSxW@|?[r;||^hF;wR՛][]u P+Ϩ&>Gs5N'Ijy|VKDҠ{{.~m} n5@l /'|w jP{~?H?ә"Bsߋ\@|Ԗ=3~ҬYQ5uFqy B ?]ט}J߷Tov{pg~"0`zG[ @\O>,8"tҔ<|6Gx5b /lIt^l7oO۶պwvخWpǸ[ts5_ fs;xCEz+Ӗ-۫ܳ*7};Lw_U4.P?. w~tɇ畔4~H{h 6 d6cm'קZ~zCZ|c5Y\LcLyW׶>|<<ƖQ^y[s1>Çnc{LIcGT%f?~d.ӄ #ĉ5c{{O8/sǎX\\O|<}{u~FC mKW\mo{MzkZ]@#F_|C%n1Cƍݩ+-Ս[tڽTϾw#cǨO31`k!UHĒ|SJ'2}ӧK~W@G 7\rޢ#/Y2}cwn{2DoW |@|wuOo}kӫh&E-$"׈|?}:5yyIMiZMW+~gz=WAw.os5Cs _ =&7c hN=uZ?i{׷q |K+/_=W?}^N'Xob>V<ů~ کj3| 1DGV"~W楅ɆfU%Vw(qqK gm @v.>sw-x]@#܏Ng:r^1_dk?;TStRqٲ+\7Z1VsXpf 8YՊMQT| V'kyָO>z|ZhV:Yim#]oiiZtM^ܮ ɿ  @I 'Lnکh8Znڴ5ǫry&/LÆ[.'r P;ȳޯf*y$N'3s/3fa?6cL'ݶ,ϧZW =?zjH8psJO4d$J~7njOȱ h/ Yde?='Rww|pο @;OַmִvmW.=()w  W:VW;6ėI"SΈs/iƍ]im饗* 鉮CF&gئ\bgm՟?")0$ >\Ç;vx $|L@%zxػ~&Ь>~Gޚ|$cviwH ԮRe'_=xr@k~}/7Q;^.qx6;6h}ꉀݙoߚδiSڑ럷1,7< #)Lͫk@ H@z[Ň^> +yz%P?I__X_h~/Kq,(]yXݟGg{Z~k.$v$zR7?>|7IOs!樑ZY`ƌ1u8t_LIA4@|?{֯7]U4LybĸutM#P H/BtM8}E-%S$0ԚD 0 %O{Tޔ@o$z+"5jh>!/_(k>+- @@|ޔ˖!};NaA`0-8bl;9ut]+ 7ܓ KUF @?z/:3uGe:)ճS@?5Xx7CL7@җ5e$*4qT @`b5pK.44eaV#oLQg}ʵ~G1&EYpF _x xc$bx@$bb @bB\/_N=uj<6`:ߚ>:& .KG,~tuKҪUOc1 @@)z\6 ye3һuZ:)i„F$Z;~}a =!r˲O/Ivy  @M,jt챳 d]t\:iaM\oU#; ygϞLL^:'s__@nst?~m q @/^|j?>=qc&'eH^>a9J?~nE疦_`x@P @Iw.qLz;.Ntᅧ+8Zo̱qh1~D8pC;+rᅳӲeӗPԧG@ 0iz% @\~#w?U:qb|W Ш@r@8qF5W/Hw޹<7-YP>v})A}v @@Kԯ<߼/L>=͘16 bhKP%^UӇ+8|4gĪoK >' |(]z3o @ Ԗ:tJ?:+=<9O t> ~a)g̨#;q;ͱL @`oqㆥwt3[O@,ONW]uv5i`?jgNjcl @{ D Pu~ЯF @@f(4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B$ f @ @@Ye[k  @ @P B @ P@YZ @(T@k6 @% PV @ (4M @e Ho%@ @B6paC f @ @@|.9(l5jh:\Eu#@ @&x imMVN&RBGQ @ @!Y>Z֦[m$4E @h@/5 @@{kh`i @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT@Q9 @ @h`* @hT 'v6 @ @IÇi$ @ ИȑRȑC^ @ @@KSGDeU @hL`ڴѩc&6 @ @8cΜ -QY$@ @8 㬳f5 @ @8YcseDU @tyGvo'@ @Z@`驚0VE @ @7oz ۚ5/l'{s %@ @Z`KZ##Ƥԩӂ4uU @ثJĝ ]qF @@WڋvbW 8ę sqsYIDAT @4ghёj+|[on; @ @@+ lJ; ٳ'w{Q~=^ @ @UgQ:{TZ`G#Fuޞ )? @ @M+3 ԑzzO ݘ&n  @ @@s 9|gZC>ӦNwI Ƀ @ @@ lHvE:u>+@쳏J7|\ @hNu9~s_}M>˫ v} @ @wy!]/;@}E}*xF @ @יn /|+*P ^qcW?{]D"F @ @g~iÆqFPOpOw|gsD @8tVWq~'Q{c6lNz}Z\F @ @@ lGۘ&M:6=GJG֦7+ᇗbQ ? @hX`kss./N:-t S>Z_AY 28m0( @ Pؙob&l%&1+_oؽ*K>~iɒU^H>ۙV~)  @ @!0x4}ܥl;wRZpF:YӦ;EFp IENDB`ic11PNG  IHDR szzsRGB pHYs%%IR$TIDATX WkLTWvYXaj1(D߯6c$15$FjbF`Q^^.zWӴ{y͜o9WS]\~m:Ł`ܾ Md gss||thB8tvH#tµ  jk;ielO!u,4\2Y6)*P#NWw~~>P' l6OYn>#wt w}}q\9Âhi1oKKpcwoF;C,jp/DLLL1իNNCTQ0cF8H!pʕjƊ3A#,v9:;{  9-S(`;dҥ P; X؄ b/iq/hc?r ]]V ~o  "k"k(44d={&&o!7&Y &CCvZܽuz}e:䭭$ʌFXO&Co3Ccc73ghTu{q~Xȑ%زe6΍V[[KUT""b| 8,hv .^;p./oAZZ 6oM`©Sx,jd>X.^/{fGbb$VIZwo2"˫p됓sΟ/2vb7e 緫: k~\[,;`„q8y2=atƍ:N9uJ,]OH$Wpx:vN`pdfƺq1z?Q;VKh^ճFϕ/:PЦ$@Z;M0]I}ؽ{YI?us:5X\> >p3<˫<̘dBaBi҈dPEXc[ada0~T kOċCR^VҸ7&`( E7;x(YYn#EzۙǪUqBŒ9,)N1kYQΦ\aM漼Lm!!ؾkcj'# peHJq .vRSMyY84I\NJ(^&~iY[b}"tss PYɓ$LgҪkalSpgŵk㉦ yVbuqs;+ apb _iQE=جUUm^zvĖj}( Fv}P'eg8n.anzna%5n`u_5cwTQ2$IENDB`ic12oPNG  IHDR@@iqsRGB pHYs%%IR$ IDATx[{t3ySHDxDHB/[VU^miZJ?,GҵJJPA%W!Ad2sofyd̤w53ws9{>Fĉ?Pyt`"//=͙ӋƎM ^o$tⱱ:D'(0,KHAM=ghO &-C,M5ɫtv UzH-I"?|I&ʺ ݡaSZP*--]Tv>&3& 'අ 3hݺc̴0utLmxRv[sU!̙;h v6RÆPA-ZSͤ@aL)yH_~yˈ8HCxW.D,I" 7XǛs<̣ ȑqE'NBUTi޼ i,!~McG.K' j-Dy3|]~ZG`µktX>Cnh잼 ` LMәrs?B!N&Y0 \HH Z^~9}4]0Z6} ;;ŋI+Ըq-Z)~> ,(>ӱ{SBB$EGЫv+: UFj$RSe?p˗d1>ΟCTİEM]FRfXKq:uw*_*ף@ݺ5͛!._.;rJvEw$IIQOy !ccesӦMUM^pSlDP3{rڰ$]2^~F6zԴi]ڶWEf͆24zl+["22|++SO=D;wш߰VPJJ&WU1oDKIPIMƏ*PzM n NCzn6p?*(A='xI6:ߒzhN2`"X]~ざؕlO,>͛S۶ 8VETb֮=2"X`P9Ch̘x&H}4g!P@o1P$ܰ5@:t"e0v" 99Y|+h`dGt۵ 61mwa,QHFaa1l[2plM:uEoՉl屖r5#$fmiG%~ e ٳ{pCo3SfdPW|,Qތdұwɖ ℩$24^c[vY3%C* #ڀ)P|Xn(=| |B*,8TvV7N_H0vT%!1( OT8u?$Kbw:jnCe&3s$+Fs$XxА>Eȭ]_ Kd{ڴt%[%- v_x*8zLd~X-n48O#"jWJv` kr@NJHBNK$R@#Ybv"k˗K8P~;P$qq7^^^8aN|/G>ryW_ aO IثѣE[rIn1AҶs*^zԠ@I(Z c@m k'A3ϴcPU 3w'Ҫ:[ @x,*6I{GDIZ0P  p b&OJ?en1ȇr\ŀi'VU:!E:!G2SQQ!@3w 8w2zϔoq@2 I. nVSpv%qR Z\C'M=}qln3pXұ#FrI:QaiT)xAkP%1wOӠAtwzKvLf%~p$bjš/T`ڵYT(A.5HTr:ڽ;cA^- FP `RJ׵f__{_^<uv!Ew0Yhm jKvK3?> iӶAZqBHst8EMHh6'soz!Ln%N\JnSYY?);GE,3E~^h u6K ӊ%[j3pBB!7gH%V0dʧ/٢ %BwDݻUHmH/W>\zˮSmp!3 *b+V(A58G>Ac@\llF|U멶 h: 1? g8o=dcU:`u6vmr(J  H~`x#ھ=W3ԩWd>.q0Q(Bk{@ehV cuU*]f BߑSr/Nt7o>t;9.Ysң5$3C7LP #`Lˑ+I-9hSiW[8r g,7>׌1hwFǖ-vAvdkyyB(&pFHs8R['@:M)vae`!MgU~bk+--/Eɶ՘Z%2YNN=Ơ:6K?L\M*z-ǍH8ȓ79;㨾f\E۱t&.;E٩2@6rOM 4\ eY9׽#lWeגB@!N긂@P |  ;u C@!ajP0,0ԩ+‡AAPS: >B@!N긂@P |  ;u C@!ajP0,0ԩ+‡AAPS: >B@!N긂@P | vatԩysȑ3p|V:tN>|u ZvܡCMqe Evv)u B@!'һ_f(l۷~DȥKgV99AdxckQLF((e"R= 4S=8'{\8XLY#znU2=v,6Jk9 HZLoXUTZNt^HA!@Ð+!2Xe*RSM;C|YZ,l SL&U}w C!-XClt H+3.^Kvta!Aj EGff:$| _)QFU͚UF>YuFd w>OӱAVe K2dl/b9ACNSk-rւI/%MV ~l'āPzM)w> %#N[xoz5E~NZ5`ns[#/eSȶ)ïH3+}~%*U*%a)ZMg'0@뼄s7EJ [KWqyyQ1ijHu5-t+v ~LE`XS"%꛴l9 i 7mȭݵ n6QT:J1r&47W矿 ZtŜ9Qaz)]JW^9QVEy-gG_$O%KH޹sR?ņ9Uk1cHB#_] ت':9_6Dj ՋK.Us^6o'^|qxbɒ+>{NV 6X% N+, |kc]|$:v) \gpSQK_6ln'3A)W9rV^#ۋo"ekG)n}nWa@8nC'ڋmrΨ4dpxEq å^VTZ xN)@))rMzu( #M@rL}Q8F@zb>.v3Pe^YBnvJ]s[o!~iSagW\zGROoyB*x]e'.ȃr[GVlmP9l,2{LR2̙kPy2Uci fU=6>]{1{$1N*^)cXwԓ!)ܳd`L:'Ϛ6y15jgmqH;BEr.05rM4UMYHȓ޾I̢7~..ݍOX1P΄zYGQԐ=䵉&x093F#4F|o+GhѢ26z"f:ki.\RēO5b, n*HNҶ_o̘!CZ?=>@ݠһmWE%2u\IY3uq}rVС׷,歬'P>fX^"w? \b޼@[cNX~8-ڃ=k?J xȸ#|?ȼ{G2XeY)7/|| qyJq'q [auѧOCVt ;U{R/({s)O1_Eq;A #s%gޱd&̓ /«=fJɅJ|:?lovbK0& *W.*D^ tۀ9";2Kqp ;VX, _dqRMI¶bx,:2!U*Ex h2̢SRǻT w?_qC MMR=\~J}ubw@{iHl`6{7ET&{oVm HUf[~&̮)? Jy]Mʩ|S{Q"4 #2RJH2.M:Hy2A 6?AӁ\%<»ݒ;3#6+΀G^1F)PZquNJD^z}DfaϞ޽'!ۮ5Oj·-zg$ Ҁ]І]{v\w#8k{ 1hԣJk 5kKDݹwqTHNR)U4v:}:_RS!O=Hb\*]g>ykSe.j4)zxkҠE^1uj`5)y^)7dv 0aI$$7& HifPvQ }.%u 7< Ds@<†<"Y΃};n M 9\#ْ)]3!QLgDHYcI\U}ݲYp䔶xh'?k0pC hNi 34'6A#ߙDSm a(sew.ߩE )8O: &`#,Vt8-zXő'IF9/j, }?*)@{9m_Ы؃dV~ɜlr,Xp+()Гv_~̘KĠATF:G2%2%[Iɕ&=B] [adS $ҤSc9 zdnIb^ṞoHBAbv}NZ37"0ءDS^/RDp8E YoĈvd U|/u9M^9}v>\'};#]f_>oux$,С yuq93Cx? pa4Fjei٧w.j`Q'u||-П륓|b3њ1ux%Sdԧb)ya?֐y.`rX`& %,Hz_AFf Ő}&ڲJ r9jƤ?SRRB a=L͚UBDhn SX|M/y3JGȌuN`/[q/{{`wj wI;-5`UIJvS$ׯl@@R"+ 1C,dj) Pϓd6i竝ɓ@' 6Mj' VlTv@[޹sikMo#MLV: ҅45j]Lş&S4KHH5W3Fl=.E+En4fIH' k>dm>C4CF:;Rpz*Gꪭ;hvt : 5B{%_{)zEkT%ڽl髯Y+y ;Ò.m h L&M'Çϐ' eH|&֓"O\79-+-Yi_PVo5Gsq{M{t(hTCs=7P#7i$"N0v <FN*'c畀*f7mN^}`vJeWX//DI ygLDF߾c/AH2pAo2 z7ԈLViE.(0ëQ3lZHX]X .{ػv}b}Il, } tdRGs1zf Po}Ff{ J_f=yL{\  @N&͸Bn TtJH8P )Bx;MSu:!%/BS dŸ %G~_~KTuA&?h(pV}ֱY,34iPCH0P`ln:nf]cXuO5Ev; Njt2dsl KpW]/ZfЙFilm3fJ9s6?n\B0i׃̕2+5gǯH}A`qƭyK>J>?x58gy3KTbεWQA0ޢR}V`٪pY:OH+ ǃkwbAd*N>Pu]`1/Ŧ2e1V 1p` oKׯ)) iosd㳕]P# W3ͥVOfv:#OoM6|sl֬PRTA(7zXsQ (b},})^uU#PM oRT]< %"؉ʳʘ\[q7ҽ,JFOvyo?k${Ձof"F|bIY] W駖"%woE\a^[PX_Gu 6bTu hdhf1w-Ӷo?dg:wI3ӽ2hd{^B+t/ZN2tLց^G5PD.>WK/,z5c'{sI,w2KEL۶S&Rt1Fwb"W_dީ>),]z˸}5A3E+_F^y(08 | b*N3pUZ'N\{{構n]ε]]6}g6.b'g }n~{9~gu)I[Pf-;ꄤSTn9;IMarNj#:v+N@"w͡@DD8f&*Ce \ $ErҞ<CHD OZȻ0V##7B M81fj2O 5S+7D~Cr'>+V\;g@G*:2Td[G*Y,f8] cͅ|>h.8csnu Sn_/djc/X3 J8fܸE0^D'a9pG.`d|:2ZGxw I~d>suj OziӦ z_L{RҢ!nty]/.4Ԑë9#Zxq@)9I W:}; 3pmE31A57Z=iNM'E)ܶ0'q^w4}ċ*s:Ih:4(#sW:Ӑ71Į=]&QSyS~q4UFS܈?2~b`^cHf7iǺu,Ϧ%D-=ADE! 80p@Be] IV7yOTOE1DnxZ0@{"׏xD>tF3ţH(C/7{p@gpLB!8ƺo Un@ ٦@lG'HWF6cjP߁>Qƺ7;&^ Pd <7?5Fͯ戻b`3p.ÿFP%oz+^p}Vn(DXq7o^IuWX5H!X:*qC"LI^xa!iQ}ة9ؿPߤs37@KZ뜏)Ǧ`;wM95Oݯڏ@°aeM k`Zxn塆]<J; pH1zdgk04_~Q֐Ɔ GޜlToD( bȦ7OK}4ɖm<=Ԫ78Pn>"k.`_v-AL0?.F@L5  *$!Mڵׯ_TX/|DSeAa`qݡ"0T)}S6M!4;nw]p&Q4%!nh.Mz ^."]̓IvH&ɓ t-z& J T؅ZB6i`:Jt{.x>{+ʨmˍk`0@pQ:xMJU"y[K53ge2N7سn|Tw:_MTd;%q}gm1bx*v>^i)yͫQdh׮{"~cբhrs;o~:GJCW^ER {&4|/{nM5'a3I7 @sԋ/ jr9TVP G86ibi^R QX[V(((|I-IAW) jOgf1 uPL D?o sjP6o]ŧ`4SWJO@O7 0w~n5:^7@*Nc5_:YD^CBwObr0o,"yɄ~z}EdLō#߉0T )]ѓ3K-v!, EG=Gpr $?'ypevK׋g[xVSG7оQwYHR eF,xvA׵Mc3 )M;/c_=_8 :g!,zs ;YN'"|\" D O 1e_{Tj n޽ mkwO>nv*Spt0Mz0Yfy2XLn:d7J jp社dzBQ2fL ;39Ɩ?zٹF$k.4'nڴ*P3bwv_I3 9r&5owXp'ĂEI4LpݚQC@~2-~.x:DzVK`ma7X@3v 5 p16#{swQ315nLL0{8Ƒ7ʈ6l֮= :msihaHWVUJmYw|ޘd J= UH7dzXO\w] *r2#D> _N$ڵ3*ٮ3 *,g˭sޢs4ؒ?h7$Xѓ5z"-!'+ݩ -8)%p\,^~/aӯW^NBSH7!f,Ѣ!Cm3y ǘ'D lP"zQAfZl3twM:ߖ>x`&ҥw@d>i2 ̟ \ :*54ܙ|tW!F"n+l97HhngzxmXr331=z}Ⱦ ƾum6 |%LτEtU{]'Nt|d':gK c5G4JUުUv #N:na {+>ZDվ6ws=}-v3%"M$yMhj68T^X̬SN)͸~oi7:iUZzjlb?6 7_%ΨJneI縉ᶓH#66Z^VT[F=yNFIx^ggѸ pEAIZ{޼mns<7k&5i,bܸ>%~Etz2U$q0L1 G!A 6"Ɇ!{&ʹG&tHe6׿4 Y ={[X"tonftolYHO>3#NnQcD„+9y07Mm9D4I#;`]2[Fiz8t!W&šT(݂ELG _FqE +2OAz|H:$F[]^o7=\tZ3 IM&d4MEBX}߉Ȩ 9\_$yU# +B5GҭU׳l,Җ-Gb+Ģ0<`dڈ>|ZrXF$!^};v^pЊaN'rb A= 6%a$ð#- cX|OE.KgBi ϒ% ?W^YJQ/C'Ýk  Fe7tqMm3Kdg]sԸq%A㉒A(]0y,Q"H _/{yلf j%ᛯ AU)8Ǩ Ko=IB n8e$:aݔjqjb~f/Zx`9GtO5kf?J߆GT)QPI ^zixe9X^`z<ʢRRr7iګc[_~9W@Mw?46)HnBy٧Q[X)-_cPP[={rvǿtR"hf~+K#3O?J*1SI=r$?&Cv}.z9?Lg#9~>}%nBQ -ZCW}~]qۗ 2?Hoа%=l~C u͒?y@X ʳI@" >`NE¨cwfO nOOj•ȓhH=BkXܾ5"h>g1rH2M?eIxdu>Բk bDzOawqlfW᝾Ut(bdXkIdDjRľ}ǁD¸ճip߰w)/@ԩS IС@TCa"dO>Cw~j$zk;\oNykYDG%CvFⵑ?4,XtugXI= z_&j"x{kU$ S̢{A V^emxmrM`ԁxVx%/z\]+/"}krn m6&8/=i YQ{\^x7x GQX_:6xIqU01KrSaH hr i3E2ޥ. 2e ĮdOD:Gzұ6[d:/ >?غͿg)"-L>RRe߾ lg1L?b`ڈn^:SL.O  S+-T`҅Vt28$@G{ 4$yK#]ibٲ$44o9HD6xKkzV4W;T`Zq/f`M3|Կ/VEn q=H\we)渾E ٲ%I<ﻯqԨQ6B^ ŵտ$z|KٌH#\{tn삎T'͊7l8{IbѢ<*a ɝ{9nmbCͪ ;诽v%QtsT4%< a^}(D:cQEfUEB'Dҍ'&<7S0>ƛTM@pɫICo6*ږМP30ZntD 0 M`u*1oa`"s`< Hl߿Qg&bW5Vp~"1ܵ( 89%ҵm[M*x;ɝGn{EЏp:RݑG4n@qHYY`U?x7[48&`Oh`h\E.L^j!Wǰvrp 3lWnfte *ٽ6o.=ҖK= )n=L۶DIZg-R*(o: ;S?0%Cg @A{Zr/oޭ8Մ=UW#;6SC^GڨɁ&>w٠H%yi+W $5h82"fΈ*Uk4O+hMElp\QZL>7͜xbi~dtz4(UY^GƯСĪUŮ]'Ĝ9[ZTj=ನ__ Bjl=;FA_=Tlٲ\F4pyS,B M7rTՀHɒ7E1}IQ:tQDgh&)w߽&)~q~ܹ'H1͟ CYJ@$DA1~&= 8]$ۏ6T Z%~J-y/ "٩bn)d @< !C<u?2q+#zgЏelR+W MC |V'u ʦv&0^K6mG.(*h7@eAZkXNj+!@42_܏Z(+CuɇK{C* hWfcJ! *Q njtλs!ZNY P\ P,Y'rp~o|-=ߙ2E˖U+nh%4D^OBaҹwOEOۂz_XpxvYˉ̈4qPqu)m~Bl~TL;ޥ |cǚ:~kΜM⭷ŋ']{мs{c],v:s,~mvW_]@dL"'Ky5FcT (_fАi<~+.d3NrĢE.I[,V9wRᩙȍ5;ggHҚ$2yvKI>X6?Xj'W6 vJ:2I,TJTP7İamn\ܯp(cS.5*f&|aa֭ŁF:q"O|yu  1px O7e(^/MDDDq fQ^%q-}ꦒgA+:VC;WtzPgf;\ q`SqchQ.nL8dR1kĔ.m;Ӝ'&tLO|oX5;AYW"`XS0dqgl"-[KwcI{@*}=zNm]yj7-Yp:6:Htpf3qڗU7 .._J"1rdH %)Nw1s]ޏ#f]pC=c9snm8)b"ԾNkӇO? |v,~lѧOCu93g/@ZIuop@"{֬ w H.u{(hC80Kܬ<}&Q,zǶ$Snbߠ(UZ!ܹ6aj3\YxUqOQfŧ XA׽KXX]R_ĿTAf1 S[tWfo@y) Fs5@s7!"kL"2)#q}E];Qc 8TT^DA.)V--@_w]sy U Gdf}\97$*GsYn=GDzb>qR;z3V 33hy: 0?8@6⿸:v<|G_ !@V1雜]o|1 ϥu̸C ng߄+`hFP?W`;.o#d꿋yvH -*P#n^[->,' j3bO}WC8C˖& x'R~3})sZbbfP(3ElB )ؑ'zSšp#W}W l`J0+@lzVQ#Kw;/p2eMxQYȰJ @ o˿TeТ>-@d!tLdajS(6PL'z Pl @j5PO( DA@@!b3j P&ꉂ@Bf@TzmHoR".uwյꮮW׵W\XPQQ{eiI=w.dn$d&)0ؙA@h!(l@X1UrKoCT*:-l|PM`k  -ܰA;\jԇش頺j=D/}  Ppt>Jռy͓w߲T A@n3{A'(zdyg5m&@v&@_A@HlHO=9XhMu D" $ :̙׫n(-x9 2A@A:~  $ )o~T9صA~N$4e"  S36q?+ᬈ! @"Pιsc~B&A@ojʹsQ. $/`PP >{ef @qbW9" $?bXf( C@bA@A  PA@(0  @# @c  P aA"A@G@2CA@AD ɏ0e @1(A@Nх" '?)1dܪM:w#bswA@@sPkxc#)0xpKKf A@X"p߂؃.cĦBEˇIA@HbM#c$m  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnH+A@,9( $7$  ` A@aA@KE  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnH+A@,9( $7$  ` A@aA@KE  ɍ0}ev %X"A@F@便2;A@Aa,a @r# @r_  `0AA@A  NA@D@KX  Wf' X" %,rPA@HnR{z2;Adx 4866ccb zm>*3"@#he1E`ӦCWs9_iS]uVk|Z*ş}vz N?qRNY$f3ZaZ[WS[|4iE߷`'bªǛmQ Ѕm 9>1ܸzj.~}]@ @܄x^>)jLitMJUdr8oF.jժ_?)ʿI꣏$, |>pȲdaP ʘ%82FK@# @߼ho]-O+evkU-9]Q^*TȀu=𿅪R%=P=z% 3a;)EHQ>8l9sz챟T΍O #@J  Sp,ZO^;w䎛wtȑkmPď0+P~Z`6Bgۧ![hQ[5.{D>՚5aH Q2(A0W2^MjTctPURW\1x1tvi]6Q#F 5BNi˖?}{$&KB6U\jZVdd>S_LY(c{A@#C80KM~5k+RTNuUVV5o iJj۶#A7 ^XS#^u\)^㢗yxa{S%0$+geUѯ^kԨ3aF'/ϭ\.7v/R|E2tLU]/1rar"hN] },uYe˚Rt!yoV$=K*̇*!CZ ;>bYN%3QAl9&LX^|q6"_v2VP'. Fld*F㙩RSTfuՙgn8p# @-0<\`_D1XB91UI1H)I@D9*= ` իW#նm1 R4hgKn{l{E3gnֆS^Sxp×`8zsJڀ\' aJaڽA8Uo3]tQGgaОz* c8y<OnUNcjnոq5XYUc@: mT "bɚع(WdO;@$vVpz睅x1331`<R-Ə]:Za*A@p*a]FeP{ -:䁱f|6W^ .h_2X{_oS:|8ǘ)|'MZT{̆;){WUkWV- p |Sj2L'O ^;O߸Mꭷ΋HOd`Xj? Jǐǩ6l8 MVhOb@($N0:6N7ժkT "13F*㐳abpׯ1iH$;č:4l9t_ԻEFK#&=9Tݺ`ҝ)Z;mk3Llz .cQ G@<լYLØ0azyFhR;;}JR̿a1~'hfv23`(R׏>}ZA:/[.dĹٿA 40XCO|bP R>2}wG~TKpa%^{tp i喾 #6?_ F=Q 5D#A"Ի&axpQʃ$-BvjC˗Q!vJfQ:֋Y즢 7f6gb"ҸXԀos O0Wjbe5|ogDJ_Pe"RY_"GD(+S2.HRu'8x45J֮ݯS]j0)y:8W*2ٺu-խ[=' uL- -x-+p$sq\-E02.C/;.b|s ^_or?Ag;[o-+Ǹ>샄C =c@mu}gt+R+O,ZoF~Vb48t(Gu*q3zl 钪}čaj.{J}*\g5dE0,4C)ȈC{o?<v"v5{Vu\3 Dݺy#0^MaTrJPQR %э`%x!gh]`p&  R`L>ߥKwC}v42 1zm۷8;eZ=A>}(6@b 'V#7k?`'Pײ\lvo!J,mS/P,srnf&- sY̙0Tذ!u}uO2 jW3ƇyDo̭eZ㩥ʅq1H:a`11>|۝;c=HKKiJ-05ҩ Cœv TQ24rݺJ@GIYb5[KpP <VQCTժ&DUTUt+xј&ʦM3L F %D4R@X["0imQB^P`J_ڨQ`;[ԎԿ=B]uU7gz2ZuW݀(xxfwM]q ǐE)x?L,fNdB/ߍ@4~7"h[WW=z4C VO87UZw_Hvjv o&`Ix53 uw\;o89!^6ߊ0vM͛N;5QzԇmˆC$80Cm:m'&0"w 4IW *5bSuΖ\'-eaV|1a u\tKaBF㵜m7o^Ciժj޼&^]%M \*Ě蚵k-@'uM|QW^i}WS Y`L/T |NhާR:(C`)+vIt1Mfn(X$9@ʤI+_VK0?ADF:^gjdsNkԞ }C@FHԷobngw" Fn5yy;.|vAت^ziNt kA,\K{/6W @ڜ8q9 w(BȇȞ9wFpڍ XW*62fn~+VʕպuPAA ،G >*8W&tuu\J"*ȝ7UFpcp}Zޕ3!NIp) b- ֋/<0 P}.E?\\.]m6l8aY1:rH꫕P5l1>Q(q`;d>w]|6FF%vSױcnԨڊW1˾}9Wgi&{d4-LTkq|,n _ ܖIWtFBLwjtߚY u j?gYx7>a1[  A~eń>R%Kv/X>h {>tNwi5;Iʪm[(UѠ.SReذV{e0Lw]J}Ύ J,_xyyΡF[`P@UZ}F`%ޡQ 7&15?‡r>FB@ed=>A :% #G~6`0@yd-W#Gr֨_ cXc;Cgׁ]=dܻZ[TA={4xne^yUԎGkOXʑ"y.fcvTB$k)Oe0jiGf*kC5fLg4(q8pl\Ӟeڴt,` tR3Z2'BjԨ͟[KXI[ŻToꔾ*%!^&cH.) w`^`jhtM{;h<$%4ӷ6T,$l5ڕ]76k"QE1h?mx,F=.wa hvEٳ8Ta_2 nϞCz\h/}X861EK v ;%,ӧoB_;ՀEa^r>E*aԢ֫\nϼy;~5;]8R`Q=`z>Dȿg|֜x^j͚} >jTH u TV³|3h1|!2 -nEp=2{郾mEn]c}+ !I{qK?G.G0>dx>d)ďˡJX*&6lcP 0} 7tYI&hd99n,d&7Kfd:{w';cjܸZw_?ob͹S"$/ ja74IKlظIj ISoB:ÀUu M7} 33$n&! ^8}wb] 3C/mH.J `-QCf7{k6m{c@>R~0s=)`-FLDx>.mb &"@Ͼ w6~-v͓t>"c}ьGH#v]fXcɒ=<)t} k765;hK/́|jd`g8AtkkI{C#Zؐ+*XC2PZz`vlJCK {GJ bvr}ZNRH{ȓz%f͊X1Èq1|Zgm,wcVzt,FcQ ^, kCtop[b}|ZUOPnT5R˳ct"4WKIn?)􀮿Fj91f:'/l³FQi0m._?I{sX3L]0rmkZjmZO}ҘX1A,0+`{7߬E;0*aWrY"vC3ޡp_nN9Î˿AeVg.wb{`aGABj?mCg$>UAcT/N4d 7, b iGw.moPDD Zb`'yL+Ur9M#_I$O0]1O]D6#}w4E&Nʕ{B-1gɼ" SOM/G(H4"m'T=#h@*ߵ 0pT/}A>"/Un][o7-hP:@Eή"m~C[_? .'ET4_'AI]tQG ̞EV[oFxm6t/m#7bWwݨv~sx뭆ʑ#02 kg NZ,1d3CYWG➴4b2QQ KK1@Zz=UutHvZS@`f 3nI9 ae5V2/÷C(w ]FX\2lt0-=!r7갼Là:JFk'ů4\!?aUc3E StpWӜҰHbH.4 Ig)n4"iq#IDbğaO<1 @pã6wbLKײ}*ϸ.n#Oj$ILn[~pwYwKbI.5M|%¢|Gcg/_ھի%#GMþv +}T<@2W@X„Vw Dۉ {m2>!)@pW5pSaR4gkh/ji$˫Đ v`=^::MZ!}*fP،N5`X'b׋]Ϟ o)t25k脻TͩSzm|bydd4^ 1!Z AG7޹}}QcܸnDuLo'/O%oK(ʶSj׮ %ts/7H&C1V1 D9>gYj=Ja5u}B qꁣVU _*3? 抽KUU]#VߩGL4)#"\<)i3g SO댕&)[SvvN}M=ƍ pdz|ͅ< I(kBaJu2fЭLѰxlTm/ ;vs˅T}TiCtcJIK2F k jժ}\hbq<`Jc.< / QFXI8NR9ֻ^jl%O# @աS2{Z!^$F m"~Z|< "CAV]0|ڊ|WRtt3fc0 v`Z1ƍΝTәr;ի=B4zPjG5]95e@tӶmhLZA$?$tEF5hd;#m˖C;O_Z4̀iBKS(v?sy_z.EEV-[һTh6޻r\,qTaߑOoӈ\zph5 _B)Ŕg` _Uz0ܬ>oA"/w.0m`rEo\O_4e;` K4xZ`CPKX(x $*h b i#%5=zۗ 4㺫2@FgZM SXm{<\MiS[~JɁբicN=,/^ [kXN#:XE 槟6 ^rB]E/Woߦz7MީʮPLWgq29[ U}p3J|͞EP $b7\R޿`ݰ=UVگcp"Xs⑸QaFJm@x$ ֤n `iXDV$ސk2]j*"fÅ w}v@Őw#.\sr( $7z$rk+YVxvTHVA5jh&Xa^R+V*QݑRRd2+W״٢ay.bcie5YOu rYqM_q) 0q"8bH9V"N~Hԃ>"]ƀED.iRGG/qn V! ئdj*LA]-)=&Wt#dqՠwhbZB\*gL$ǎCbDܥB;1pUxou̡Z dK, Izh {K.>va[4YgUƝq HxX F4QoΟv %сkK] )¢ 5m0ȇ, K5̙81 ߉x5^i"X!@;*dD1j#ޛv׾0wEDK`r+Z7 @1_/lv=:=H; ,0-SnC ixެ}t?KI~3^@u'!+(`+wΞAύGVE= P]6(?CY`iG| Spwm#D unZ+FS1~vB: $\Zo"8i*!pF<,rme*MGA;:!.!gne4=9 H1(f Tx{yp% eV>&j:N.:i /E;NqѢ{Ho aC\R tjh'Pc3gng*yIȥ!V琹 &761z~fdUCivM~j)o-:+_<ӡ?|Pi% 7 tiTߟt)u۲Y3'A.}+^|lڨ 8`u 63ܠbE1iCY=_ygoFrYM{qpd a8:j;)uĈ꣏bBH?KƅTmibLc-:}3Zp30E2!ӦmTQe7.928dm< CF`&jG\ֵb쯸kC: o#%QW~o0!i5b!n?얈Y0ji57F+F(XD08⥧fe %'xݭv#X=QD֣jԨM9\#:y7d_cWŒW\i!3adc)z/C92G7bgLap'\;ou`dU͝Mi2M}CcfM}:,>-d>z) U9gx+1+KժIep$ڶʕkrm}?:4n*v#ZiӡAH\H_=P(:yiemzz1i|L;|CU73=w[oiE%-oP4R qPsVt9=2g6HVb [ ̳t)%3;\n"wC/4}C 6]of w[jWmz&a@*Cmݺ|O|Hy [`SEu)8Z:@V4Sg}DC1yUy,IxQ׸.:p3lccC#3f؈J$~q߿YH6mZJBpYV=cf0p<i 8\gt7`;F$I8jhה>cmX$?tW>gHA# =BY hE$WgABUnSlgN\^y\Ss7߬D6#ZkNB3 n+"sn W~zVk!Ib #_z衟_bg\9NT\UwI)i^GG9x0ͽPYA::chD03J<նmH60mSh.0VQ>ixo8=SP',6d~n'^@n _5_{mwE#*ƎWKw `9:Đ!--c~o-8{kWcٜLj<X'MZ W1k7k1;[n#> HT;7it)/%05sD;QH"@DbNg 8ZŚZbo5]U4xY=Aa{$q24bx)EIfվ}KO4ϧ4?鞓!Yǻ|* o7r^(ި/ w9@IJ W)UcN1&`eKm_Q;7IL U~;~\i$Ȁx|$}Zwpj m` 3IqN fX&x7Vݺ5Ԟ u2yTH8 ԁq A~){_koADƟ'f³̂1Ҭ7f۱OdFu_2r?v,>v#@fQٵ+9yŊ:,ӶIAӱ&nXׄM(XܮV.1 $:>ڥEMVkk);<縳`)%Goߦ M6@C^UyJ;Dp?^^g'#H!+g$,@|OPǓymBE]xjW9c "ݶ "/.qu7㳱oXs/@IDATC #FkM:^(w=T$J:Ů4@"/b?'χ!1+cծC;&H}:7tSP$'|8Բep;ኳ[[6vj֬:BuxGoOxyn/|UL0%4}VڷPNj9m<1CzNnذ1!`R5fN96v(fᄏs۱?xOu@lA5B/rg.8Nќy )J OJh&}>ߟQUh\F#dHV"8u}f܀?70@s̰ǩTM$kIx\ ը8?MFZc!vo\H9<ċn+5zt{5n\|¾Ze-g3xS3k7AQ$flm61!l7Wu g:@u'7 幤(# }-%2$4`BGxxzϏοhW<&I;(o׮t0^}wc fEDG`>ыun%rUJ&T=6v^ E!RH\d^ pBzNlYR-9T=Ow&81E4nF{eDd=ݰ'-MTS\]yXԡ~a\5k"8# n Kudrc5Ly^ceu}644 JZM343>Wx1B%lZG q>y0F;`4OVY6DY0Ԉfi &O3A>JuT/p.=.tw PmdÐ,nxt x≳!죃2ժUՌoH,{ @IEgX0QNJ׿N3Ð S4NIsoxo: 8#AGvǎ6Ԙq?}IX!uǍ\mL}P"L=;$ŌO]~%Vo7Wy['(I]IwkP:!Ksx셺kC32Fر1%NӦm@KP#4Ki4|#f~,)p?s1xa ef- ~D6{|i tQؼp]-;M(;VԈ$7Rj-h6dϑhS: G(wG:CUϞ ug. B`G9oC=-`crxUMA*?[xdH|evJի1=i2e=. E_r/jϞ6ڶ3DTWMI`K>l)FH;8'Ҿbsi}6qf Ěf7KKzk"mՉ77ж4%FZ.l$#1 EBf]썰;W`P t.4+ڭ1S!.i/6nH<3( v6^S yy0~Ԁէ^ԡC`օO(JtB]Gv6!_ q5avht_h@\pkd:pu-??b6ur1t"/*Kt,+f$PL0czz4 -*PFgO0>"u(] j>O]yeWXk1$vxĬ@3r~ U ,Us__[2}%{Cĺo&F4Df*m)FHDg+v9rG5kyy00$eE!4a̜uV 5a¥XЪz}7:0 o1 GcLhe'~Oؑ^ kv:{CW\ZfALhە2!?; g_鯙fj9s!饉?2l^t.Ȑ8>Sm& $R`T !ֹI%g#{ x98."4,A1ąu ZӾ}]kBfEjoo> @Jh׮BP?~yV̈́  ?CKph?~xe8 {j߾ꪮhxX1 Q9?#̒9fL ~/; 5pJ9D> 80NQak{K5ߘ駧0OJ  PO;q/jTiHr62+}'BuHR3i e ]a62~xЭrQ_iG=찀F~#h.{QgBFk]}lY[n]GeУGX܏yv8eS ;s*U_mT~EJI+i5QV+kd*UJ/q"n]2ؗƱC`,fxOT7ցe^FK$#ڲ@P48S v6{BPSy៱pCq?' ςTo3Z*=]J|^}M-!/j/ ћ25膶e!, zT6lYI2f꥗fE$m}MMu/}S.؃t?g>AO[2=so85>V*e\Y?~z]V؃ϮC\Ce~Z{$o-7\NE?˵jUnmS_7^Pp^jy~Աfo+F iM7O7LF}]h/s֭ + ?"\r=GE·"]v۳?1v!1CXJG; ՠA!/NXovډ%Ñf+AgdrQ.>]PǏ; /:?\ V׫(|u:5`#G@I  #aڽD`@ɝ!"e(!i2|E21˗_}wΝ^F]!]R6}.@Ou]) wh*Ӵ[Ŋʼn+4fQ"uFizÇbQ>Ik]=V#6<3L <㰲H"~z0^Uah/sҮ쇌?3aue4yU Ht\./~h,mՐ!JLM.mLG?V2Kb\}_1wf;wU3E9EU0z{kQg_@go\HhraퟁEb7nBr燄?uWw5ao '>K͟-wgR4i/7CdMAZ`TI P %d!HMym;w;auflѫ.ʭc >ʸfp+ 䆵t,[b`|x_w=(cst zQF=X}ňzAYe ^prAgǩ?t} /]¿ akhtyRpE ,U 8Ywk4.m׎i:ro׫WCxҜSlQ8ОW0Z{F;G\/QI>K HeԯoxlX$"8r-G V`-qnqkc%3|헦~ tsa0<.wMSGgriU(OChs[DzcpPbu\u% ݖ"С- q5CF VoD*VNڭM!-̆?Ë \ۃymq:Hv2`Z)`jf@B4R=j8Z i3h-jS*^;:hT"8Q @~6ǒPfmmJZG,[n ƽY6}h.NŅa_3^i>\=e_{m6ڿ kqq+B0@]rI<*Xmjd3$/Q}lmf!oҤ"8!')9s3& Eo~PkBcKzҔm b{> ";Ð|mIW뮛;nx).]ڱj9џ VU{8^Uo/d1#2nTiʈ^~8l$HgnNY*EYg5Yc )yP%Yd}i67S˅jڃj}Pe)&>+a^^>v鼎ϹZuMr.N&%JH/4BvBO~sl0סÐ&h#o…OX$P8t#vJo聘SA?\Ӣԉ 7 FDzqS9*u`eϗҿwװax0s!ϚLjq_t-cGלC':)Nl v50?`(b;w7g"FRu2.]A9Rd7~4m٢E=DAS)2e6%KvHđh`qkz#k`1#`s:e{vv-a=ciކ!lucu%ڸA23STǎ  ոqݵ'Pg L޸VWє`)W mۘNIAFv*FLriBlҲeM*FG2((pIc;!V 7tG܈QK@3gfُ3m_g"Ur"8qO<q!EuEeGzL;[`ҐHK>hizB2 *84bI[x92rd{ S^ xDeeB(~oX[U?~4_ hr#wb]iUD L&\pAGt|3? :J]w ,ܥ,)aba* S\RZjوPES__sw}dvH=s +@k-2px s_2O?3`O}| ):nW_2 kV1_*N;j:WΨQnU-n1B =̐RF@op,4?!:u*wvqbHLN&cS?O1;袎V>5ݪo!ӧ>Mu/"1F'˦kUųϞZ3yc,dDbt.?HәJoK+ςڲ:,/U+h-Z4P?F}2i[K(bfgS 8ȼQ1++P|tzw',Z,!3n.y7"zrumGગc_q n]>wS;*`~p 2z:XVG\`&עˆ=PN䲈 {D[Ӷw x]0 _w?~6l?yL*i U۶ija u"IL',7vNKV LݦLYDmْE:w֍|-Z⟢&]A'jB-=U.m%mb_HN:^($ϐL= 90E,v[(-afjN]o Ś"r&|ܤb{'@wׯLj"@=' ݤ~q=Bphny=: 08{љs"ֵO?= FkZ dn @k+DB0c[IVeW\5 &W~z3$S) IQD`ΜUaXѻkj'C|yBP(Nv̍@@_˥b ѶvS2kx/2 FNR7*^z<z=Sy")WFť%|AM&C q Yx.!h֡CLKÅY"pe 6zn\  G`dCS^ Og+K&XL%2lL<س @4jK3*rmJKE NO es_nt xI?4 !gP@9a(RsU;w2Pqu­]DOq:r8`O~ɽ䫿 S22]wݗ:it9Uz䑩E8{Wo' 3Qf/vHOO }/-H5vPp =JĤYdd`kLL&^ د, _T"!zuŝտ<{ե~ 9TU6޶b`T aɀJڋ\pVaۻ(LW3*#,q>AHOr%U--,ɑPENS'K1X'//q]G5c;0jA 9缇֖Lğ, }}2j?uu=StB9Yb/Xc:b$. r",Rĉ/au!"0Y0UWuA8 w*MFk~00YƂxPrwбљGJr wLcxz)tOqG?YuxS4k 2c'w{ر. ]![VaUaH+hτ۳ kiL ˟"Dlld[QIF yRrs c{CIFӛ5Fa˾}"<~B^1k{ݿNL&N\O{T?ޚY3nA&3fl- RT^(FiT g a*᳠41%g +T'eG"C)n}f (%1 ^:1シw6'@㤭[E@LQP7K D~R@#aNՓ㉃=ǎcFH1*dALճgQVڵ+7߼xn`[ kJ#n p~iM1~##]rr5:F:J܉<# KyvB*6:9ضE%== FϼwXQ7F49 &D E1`jj|m?eʵO~յSR5k Џ>z7gQ~z.0NsQ+WN` 0!3nKx_xEjq޽"G*NDժeRiq,W 9zY(R}UVVu-5{kմi7BG(>Z/oCcWU9Sh3H"uGN.u݅o@3؁"eQ7[YCUXF 6D@\GZ۹D7Zt7t*UO}t Fݩ/ޡmh_}uӇ@TE:aճ ZI)G B6zt$YZ[?~DВGH[%IGjRYm'_! =HdTˋ/bOW0 =LڷLF5n\w5vl[uM`4LfLAi w ku%%$@W믧H0CMp5>mHHRp#.;m 4GCepfgà[$ӥZ*tK=I+# իJK>, XVS30hsn嗫e$^So Rv9hx65Ձf u"㨁2PRQzip&Y9mO=ig.J#s?+F#n { 8X zFiYyRep7Y>}ѷoSH(^l:!ChL\G3MT R[  iK8tBK׋5Xg^7^y,w3\FyY>u(}w!T( >d@Oul7LCȑm&$uTTabB`}AA R Nl>M^ *0h ? en e8~;Nñp.աC]$)>ˏr wID:tvDU[$-Ɉy %`z*&Mj֭kb4FL9D{4kV AU.[)%Z1,IIuP?`ӥK/{|s1mߍ5ov5kb  OuJiKNP6v{#Đ! AVVU& \N贈FW Б@1oTL9\)C(Tr"w1 8 FẀiU~pU3DN3QQݻСչW')7z }%penH4|,we:V=3ƞ\#N: ګM z:{yh"EG]8t#;UMJm\<6D0/ԁJr'f={CrԤIkt~Z@xFlEcϞ1FȰ⼑\N^y^}~do`9o6?_[z#F$l؟{E˪S4;w+q@j0<dV=.ˁǍT^tٖR$%@PGjTvц?4""x#0q g_ϒ{tu3SX+NkR3RMTsgva@ #T0{˝w@ÈgtbݣbqK?p[6GkWU^V^wonCR?JDJl lTp'.":夜l&OA7$'L؍}!@5^A` $I;3lUԷ]cך1+}{f~{a׭[V&P]zxKX3R%!AKXs0j~Um/ZZN[τTTZՀ:6$R;J$-@:vxlAr-QY ( ũ'h*wEh)E}Z Q#X=z4Pq#mPN?=K[3;~Z !& ?F{FCҐ&2}fφxGxJGR"Oq[{C ibl.SÆEHGs7#_]ߴMxslI"DŽhB,(Iԯ_z};['ď,}tw`RUggf;{W@"`A,aƚ3cijh챑("v" wXȖޙyٝ{)s|A+GN1Iu+6"UvAQna_Bn,`Yڟ=r #W/J@@@RޭlcŵRƌӕZ³A  gw7] G!b+4B: Nѣօ"@ڠ1euif G=.Kֵ_a,aO>VXC2n\7#qχ`C.Er9in=x$вe~ P(CKYVe(Mzz:_sd"{99*@lG=Snҥ3V떡Ke!IpL-rTWYwC>Wkprbp/\nV[@R SN=]#]|,h:toA瑡CۋHDҲzS#YRq) !țof|ि .VŊF?il/&^モ=Lw W ^@mVB *?ԙ|4~l;\mvE}l|q"fZ)-gB87z;)FTJ2٨eX=5o[wz/r@K_%&i$Eޖrd~QWˆB'2u*(Lć)$K`ˉpPr6qU2AD24IbtK о\2KҧP{B _KSݿ+ԹJ¯Y?ٟ@eGB kق4]*s箯P ݨQvC?Pi_OdĦ# =J`rIdMyx>[4co<c'p)NRJЎW^9xm xU_nT4ٵ6lW5Mzs|ɔm+lUIZX E/;|J>!\w(r&ʫ']7~>}Zg[ j65=Oi}JBT0wEJz_tf\{h?*'"tp9ЛN_чQy? p) \fzO0Ş@ƷV7w~mTW7e&NTB5^8vt0&MgH暑 MN nZK֬ىDU`߼T+<mJBgA)HEz.(1hw?ބўC<[V/[LH`ٲlɿ哌4M֔bl:;MmۦJg”ɴiT}:Qz[HQ!DuNnѣ%V('6|jgh'׸r׮bCOj(h5*SA55mWePxHiU=nxbG9>lHSQA~ +?q+.3v5[`5ztD[6 :-(׉g&`])l߾ !d{ʉCwytQŋu Ɏ=IVO.8kíYl(2+nmK֥%}ߦMcX&tB e{Æ`$K:&[ Wb *hs/xmɁ>;=IO8S?y|U?Unj5YxCq+W8_vc NhZf 8 쳵_c8gsE\+@ ?PV Ǜ=w /LՈA1tE {)キƬ wEXa]ֳgK`~3Y3}(f[N˴<1c}mر?_=yݨQڎPVhe&,27@mWJ(Ĩ7;oc_(کntJI1jzfN{4|ݟ)>}d'.ƕ7F t_骆ն ;o .DWTN^K6Qa˔aUtR%j&~>bvHYGfڄW/[oe69{Ԩҳg^X4ɽ_4((|Q6ͲI/J@@T~cb3K4 #k(g%ؔ):sK`+z;THZ}F,sȽ:0t@9?X@,(Gag bN :-ev1ٌ c*)BjND:4-CvCqٵK-[s}W!Տ,EÕkn9^pHpF éƍ|p.Ks?` tfFS(z@bu1y:8';Рv3K^6ӱ|*$,;^M55?5$8 L rVӆ qjت&K[Lt35?@ Knh ,fL>Sy,l fh;;hu' p8>zÌ>{v,\}!eR'ePl4n۶̛w|=v+> ' ; !i*dzydR9ܙ2s9xv}?7@ۏCĺb|3#tЯ0`jvCCys(K/aFB) .T*S/PWH(4(gޥ/UT耐䂻"2yLS0;?u+@U:ڧ+/ǝpZ6mISG92n\wήs@LE6FCb4]s(A^̢6w1&ù#֦>q]j .W"aI[DfG5gdn]՛X~dARtiXl!=z4JjyÚ#KJv"=Q$c6-4ĒC'P^7 fUW^YnBB'h3)XԿ,.(z짞ZОNi߾4lCO`4,*rqrqa!2 쬳AQt*}ױ{ZT aCbH`o"^88eVQ:1i6O^{m|:;s*8ڙB 戃f)h< 4,#Ү8b}"3Kzu\s͛.GD6uIȑХ([NmrPqHykm _*ns+h=rU1@iFx}ѣ pl sʽC3ebJ$<5$eP*Kو&Va)~ߛD@͟7oRkOW_=W5U\.2&Oi(F^[G 'tyY2gZc0B8Ig:jϜb.P)2SIXY3e h]nX&LSHdJy_m+\^ UΘ½CW2`@[#ن ù4w5u?l=X$[`nSG@TgVLi._ΊK:M_<#8XꀧC0<wr,|'F:8P,0>[nY-JO`<($trnU: F³@Y<2\N|ԒzGG)($vTgջ%Knٳh2@F5gSGW!t/7ЖV:ˍ7A*oVgJffZH 7iFH{l\qkxW}ף] vƔHVu”^|q|(^sKaf *pC5%1?rU1O#>Z`NRKp1'<˘Ƽ̰ Y`c d'v-k·G] \ z_{jE0ŹbA1($r"[/Ϸ8d7@Mw&Xnݫf .<ߑni{{azI}W_TrBŀ@&pV%iX)AgRW_m{ϊvxiLxv̭}L@^?a.̡tfdC;P o8LV ̿]feWeԩ).Ub%TBf!6u:2AX'CCW?܄5fy)ҥK.Y1%0|x|KCjXk痄\FǎMpn7x(!7-N`BwR#K?*H||,|`ly0">H#*+Sg2#G&r, 꾡s@ ;;' g"7!+?;7v}Kp5 <'luᰝ;,D=E(m> \8P" 7?CŅ9٥S![7TV˖92jT(Bᆛ˸q]B7ړsBmNqG![M0x tib^ {oCcxOZ0hF2O1KJ*a94 h5;U) zːuqnCC[4P}0)ӧ76$ N?s=1ހM 1ϰվC+?DD`莒n k5vjnc+䬳c&u٘W }j ./WTc;Oq@_{e˧nxٳ%,@n\wMAF*Nߵk L('3ŠG2k2Qo$q1 x#z<)nKɣNm}()%Vh2 {1g)S&c^TxUonh$3>DZn`-\|c]w͕o~j_zECΛ7C kRvZBuw @셣2\9a *<3V}BJfxvU3. F!4%2U۷SѶjZfA9(w9WSxʁ9X;@( p M7^[ٖHpM-?pJ1c0Pj/c;Q}K P22r0Α^XjtobA?$4xb@^$<ny<xR 2|JX>mٲer'Mg: KjeXZAc>rσrl `#N/7%ܿT3XGI$^>psLi,OΎ~">鶕ۭ[*N*fA' ͈:f"4Jjw??[s^o7]Br`9/H ,UK;Wvij5^(+~ NDAn@upK;ѷ_gO m_Wςw߽[HMd3e.3 QݘI 8쫯{Hea5#^: %T]3t6c( 1գ*j 4\/xS{*22Y%@OSYN;+b ۵˃9XEE'}-7ҥ¾#QNK뿹\K`̿>ky‘"-Tg?ԧX쪪wZeȈ$!{]S L>ߒg/kF"Px| ?Kgrtғ컍Iz&lPpN@sbTo@EB6рUY3GV텇88RfN(0h?&HޡGt1˦ME0m&{MȊO^Gܯ:x8竆$̸Włd f*m'V8Q2ؘ1Pמ;X_0BYkUpi2B]y`U1%R7>ڗX.p umR9N zΝfD4-h4Y%*jJ1܍R|#[M>@ҭ[s<8`+$ٌjtEǦy AhÖ1 ƏzL/Жmasn#}v'ԩZq*Ph<'YUov 5|^$-)T1=Hܯza6ݵ·GTMt!OުĒg(jǯeW?NEڷ:?՞S =P-'Q0/G.1c:V2!p䪫Þf=rmWofu8a qӃ0@JJ*¯zD,NOY;H/HBh?(MjDpr1PVj[񹯜/cċYS:P뻷p\)[ 5HJrTϤĉݱmmm* 7nՈmUQZ| ȗ% $ W@U;N}3Ŋ@Fo7+y%++C<|xH|?YY. DJ@b|gv䚚BubG]1Р2夶T{ig[nc$|ƃjyj<3HU@r챝9^~Ү]aާ /šðPױL$@#@ q,颋KvߤӓDCC2Ŗ nWoѥKs%ЖCo/2 >s#3 FI@JO8;"K}R)^O5¢Ex嫓E_VJMv>n)$:dϞCT5&! *W7WȮ]8#[7+8Z%{<9j;kô{UקfrlQ{ +\֦B<]b,_28 ʖ{#HhX`5jȪ gXnWW_aJ!5}׮b'yKgt#%&GlۊcUTlԪ!5ы.v4AҁWlxᒎՉS*r^e侈.YiQ{UTg~-fiAa̙VvVW՚Z+tE su B,Ri"=`*GU[2aBw㣈X1:J?~]^ԩB&h] okM<gכxoq@z 6-]&ڑ3ga4!@5U;XPs\8r8<Ơ _l#V)[c:'G}SYuTPǬG}; F6WW۴Q# {c f#/~k2X`Na "":klؠx Qe[uO1eٿ*|Xm;r*f?˵ݺ5$Ծ9@5-L%V;Qry罌{цRӽ#u^k4%C 5gC^\{UN}jǪA^IW^Yf!&P}+oփ\iUXR ɓ{ȑ'pf-pkx;TY>_QȫW+ ɣjhs&ҽ;Ⱥl盧Xm:eʂ;p<K'x\8 8` &^IH\HVnx.6tX!EBg{lwyp P gyy]{#י~$M`!-f8>uHQѡHc(X"xS%pw7\v`tq 98mo?p@R_ ݗL89|cO:{н_>K a>x{<Ѹv5 4{}Оwjݪ5̜n3<Ϛr˕.^8B*&tj}"&|7lpkl) AHqL'RuWf;%L7//_vQW 벚hzKΪe1]]r( ֫vH97oNtt݌!<=0Kc֬=z?nG`Ѣ-r-!~UTV|%So{ݓ_ThY#дUUPYRP 3^WHc-0k!ᅏ\b./C w ?3^a: ݿWaW`3EQ4l[E\J1+U:HY1ȨZ^8醠"ҧclHYè.Ĺ*gO)EæMj߾HMdF{Xfԡϵ׾@+jtK@F}B+BmU 3ó#4] }vFc[8߭dXq@PiUVV)ȗjxIU[ //mٳWw X})#ܲ$.+vzꙑ2vDJuw/g_4תu>M"]h. t;.=eĐ3,RNfJd|Q'QO_if ;+uctT^}:fcL;._6o-{KdU-Ze:$)aOu<J90xIߍҭ B`(#x=fSHcߐJ}m _FczSzl-TC&t?NIh^GwDU(Q1D^1ٶM}A$pQqmĬ}!g&23 ,*g5_Ja]4C!&*^h#jF|U*/^x$g~P k~/ӦKXyD z:+#9[T_dD)V"yɈc&M2W(zKs-]ii%<啣ɺ_pC)d?W; T4: "i_`xx _>xrL?>X3rð]sp;`Z$ucWKΦ(q**+j׶5 ѣ4jokꥯ+C ,+ u*!%%%cGt/E@Hǩ+q* lu& 4fDϞ-] PUx~Ha@9^y`ۧ(XPzc& .-`L$#PRRr(tbfd,ZG]muQ&8Ψ\< Ctk[*C`^ RGuu8ؖg}0tS(]@|rn$ݝ]|+&AK:4iUts0:}<"%3f F>nT;HV{ d77T 㦷SIzL; \x@֨SX+^H)TI^9n;WQn^H~~SҺ5}z{RN=7?)qJ30mK6]UE۴ürJ&V,ݟTeجx%77[nXnYͭ +/j޲YJ>}@U4$*Mz0omYOjﷇSjUm=#ּK(>f%kuC%R kcbf8FuVu[!Æʵ׎H\Yh8RUu, _KEuxB@M 5/,9x0[.`y&PG%GU 1`<$ TqE[Bkhd;JE=._CzYl6ή\W@n蠥ob Ug.]ԞɮsQpwuBn*Bvm=ɮ]PT;x#}=v$,Lz50V$ǎ,|Z̓WwImplEJu*[o\Hs%qrlzV?`׮bW.k_=I6/Cv8T[D ;WUT?7rqtθXwаSuns/<8z뱜 ڵ{ց~RPTN폭r!NА!mw[뀯"NrimoM Z&=im6Š+6~@o瑍\7ɑ#̗SNiE1%d#Ou^=Pk";7@f ǣO E-)]ՑPmOmjğV ]_|zFFi%/_[W hp8{Ie }d~Zpj-y@]۷^[HZZC'ci?^jW߸󟟣. M:ňZN~QMY3\իU{8Ԟ9{֮ ]4P2yf 9.07Oӟ.1,(1AY.2y9e˂T!|-16ONjcp!z333T-/&W]<ѮM߯L^YBHH rVXYҀi>G$1teBRQ^5{H%@ rɜ9keփ;  UhUA.SVgz3^m)Xw¨O5 <)۶j2 } T-#hۈgV d`K(X{BۭZOv.ž>̑H"!0|gԍ8裓eĈ|ɝdk)+W* @F`M mm=p+wYO'_З؛ƾ̑H%G´j **+!ӦM4Lm:f9ҬYvPb3HR@Zӈasg,vKqq`{%99ρ@..rY}pΊ@ mi+Xu0e/!r%GHH6<|"vo !|bئ9QW@AaaSܸD* ]eJv6o?'H99|G *[rdpco[x$@$@ILJIҹ;6j3FMnD{+n<HH(شjW[5O9;G}FnYfΜ*Md& 6HH!"d~,|^AZpquk!;j &  T"@ zY,:/Z|%lrv 1 ug,Y~ Q)5#bVJ,\dժV:B$@q'v>9ge)@oеks vf)L|Y" HeoW_=O:t3&MG@KyP˪r ̟9 bI/'NT/jXJ .9V L@Ȩw]d@逸^ΔA@HZtha}Gwo!m67 !i$@$($yǟsN?9heezC%ٿ>gMIH @D|f9dH(&ML $ D@ *.*wˌb?|2#QɋI TVzС )+k4pHZSҤQdj.bQ,1v[o ˖mA2fTVeÆҵks;7uO ;uHdmǕgm>X-o@(+zrHzK7ϕnݚKdx`@PZZ)۶ɦM&fҴiVٴ^nǨWESEBJz:wyQE3>ۈl?eVʜ9kc;ߐ@m:,^]^|q2Yf/N.Yf|Wc\D|Pj,c.Ҹq187n)yyY 1CUcej.裵[+u᥿쓯^5K8L4]~ժ$kdr2СYԨ#8[""WQ6V\#%%_rcBUJqq9 3cGRZC@ka)M f  v)s}mSru#YPlU B`̙̊K1H>tt9sȧQ:I'0%3 U4f:GQ{g[dfRZZ :7PZ5{76޿*o/HVv7:q}늷F_U~:s;]6c;хƫMFz Ppرj^e<[LeȽSΝW˻ﮒիwcg:c5>Zf4AwҺu.fMWْ뛙 3O}t>u%%:ֶTO߄v=wJH L.i ٻw|&/S2aBw2}tې: '7|- :t/S & ˘1r=7IM@/ކ-hVo~̦+n} (:<8P)˗k%XO3^:C˰aS۶qNiC2w:o|/7v 'Z`mXUMqjC#ᇿZdW]57D׌O _]W "n|[A RskwZt_wVc|95y!eUVu4 Y9%SӃX:8Gg'/*zS/TTyf~~#W=U՛X}U =Iaa,X,0ᅠ`+Y5..:۫+hsӰDֽҷoqI_\Jd'bMY~4~(u *Һu>wrG+jZGE/\ǟC@#yRiI-gH( 'cb1UP7X)|~e^WrcI@l/ C`8,$`TA54uM  kݛ_JMZ_=}0ō>|}+yrG63u\?p :W_m4\$̱_ӀgDR29$>/qBs NM m#, ŝ|+PR6W]6~bXgX:>N+wo`8Y`cb'9Bp ]R72)C Hq.k֬߆# 7jf;33MN?l}NVRAY`}g{ 2{jãz۹3`od]I@}{ wʽz 't9PD.ˢD۹s3,|;2lX->n.C2|wru_**˧׀$˗2XÃ*}<}h}ZaM;(@iVQQOX{,KMK~ yk$1]8-}qz45O,O?ֽ>//+E{M=Jx [a;@M7[=a)C&Pn<&N3# -&M1B!̬>pp[kj"!/̦RmI:Ϻ.~$X6[̒-r0T&1 ACp?l:z<'\nD2p@n#;,69WijMdҤ_4B;D|߸a5F5ق%=rWY4wWq뒺.{C^ ƒ^gq ik Kq]e9YTaYк@U{ŰSn0=H _kfCI™H,./3|ܿ*]/} :hu v`p {{+} _xk4|:#ֻncP\J?t{*m_[e ċ@Ix| @xm­F?;.oᯃ3 pOtUa/2 "tpg98MФ Kh/:9ՒЊ0J@TųIkvY#xhPugVY {Dug}82 ]kڵY3L޽‰v@ Znd8G}^Xhl=fg0Y= 4Lm)Loig 7M}'o}`U [wo]矫ރ 3/FmR  tp(~cک48VPDT!pt**\l? 0@r//7tyw[?Z/5i Fyœ7guIj_wC^]j~2졇6?YM_TT~".|u!鰞P'G}epTn8JҐ5@./ DCa~D~½AV^u/Ozj !)V:]xg F]9h6~.ׇ-.=UyCH{d" C_ES_)EEԷYb+Woru=1&b& F.)߹\NĠ?J]E,C頠{l~ 6?f9L$@ P7뛠Д)d5dH7s:>F_%O=vݫjs@PNL$@$`ɕWOIE8uFJ ~^r>kJ5S^Ja{ ?]/B`O.d_vꖐUu̘Buգyťo5@ y? ĖYqņM.;Rb[s D @m-w5A~[+*p |,).Q ߓ @ lNÇ9 ~RPr]C(".h$A!ηSZ~opIH >[8?vl@8PԌ {lub#@=5 Sӯm+ӧ3]-jwYoy#WsJ! )$@)E@=VJ}c g>%/TtP75˖SYg-X"_iP'@SIUk:u̯:0POf>v믯M>@ {ct14vU۶&U*N ʞVH!"alq<Ki[? M@ݬRN;m!n>ۙSQj ѣ Wg1 ":PX{K#1 @4Y =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M PiDZ$@$@$  $@$@$`Slq6 DC@4x- ؔvM$@$@ =^K$@$@6%@j @4(DCג M $THOwM$@$@%12-ͩS>`VIHH 8"_}7/G'p8vqb"  I@WRmfbW,? $n_" N] @ PH-}jra"  {P?e2vlƅҸqќ<O=5EnxAAHHHt,/[a?_:vl&rTW  ؏ƘHaaMi w]%6iU/0?IHH#~*(h"'v_b})hӦlFyeuz> ?'  9[r `E y V[AcLIENDB`il32q՗т؀œ Ǚ4UHhc;sb #&9Xyv!L铁e!2P0J:v@]V2Z4  ؂g9.OpZIuX+ GڴeE$h  cQcۀ:рG"߀$dݘ+ ^(ށ рр:ف{U 7 qсX Nсa :~сссуOʾPdYS75%  _( #N9   m՗՗т؀œ Ǚ4UHhc;sb #&9Xyv!L铁e!2P0J:v@]V2Z4  ؂g9.OpZIuX+ GڴeE$h  cQcۀ:рG"߀$dݘ+ ^(ށ рр:ف{U 7 qсX Nсa :~сссуOʾPdYS75%  _( #N9   m՗~~~~~՗Ղ~ꂀ肀ɆL肀͚ոݿ{邀{{}|邀ỵ}~肀}ꮩ肀ςy겚}~肀览ۂ|~ z肀ڲ }|xٍɀ肀փy~~ݨ肀Ԯ华|肀u肀}~Ձ 邀|zρ{邀|w 뚁ꂀvƂx w{⃀ ۜ낀ʏ炀ܑ悀肀H肀ԧʰ肀Б肀肀ꂀ~՗Ղ~~~~~is32zzЀzVbׇ]3Ss@~-et*NamSsHXԠQ{Ϛ滜(ߵp`UM㭨zzzzЀzVbׇ]3Ss@~-et*NamSsHXԠQ{Ϛ滜(ߵp`UM㭨zzɋ}}ڀـ}}z}í}~}⹿y}}u§}}ۢ}}{ڌ~}ޏՋ}~}}}ܿ}}؀}}چؽ}ɋ}l8mks8mkqmapshack-1.10.0/MacOSX/resources/Contents/Resources/cs.lproj/000755 001750 000144 00000000000 13216664445 025342 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/cs.lproj/locversion.plist000644 001750 000144 00000000644 12572255134 030601 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale cs LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/de.lproj/000755 001750 000144 00000000000 13216664445 025325 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/de.lproj/locversion.plist000644 001750 000144 00000000644 12572255134 030564 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale de LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/en.lproj/000755 001750 000144 00000000000 13216664445 025337 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/MacOSX/resources/Contents/Resources/en.lproj/locversion.plist000644 001750 000144 00000000644 12572255134 030576 0ustar00oeichlerxusers000000 000000 LprojCompatibleVersion 123 LprojLocale en LprojRevisionLevel 1 LprojVersion 123 qmapshack-1.10.0/MacOSX/resources/Contents/Info.plist000644 001750 000144 00000002370 12572255134 023603 0ustar00oeichlerxusers000000 000000 CFBundleDevelopmentRegion English CFBundleIconFile QMapShack CFBundleIdentifier org.qlandkarte.QMapShack CFBundleExecutable QMapShack CFBundleName QMapShack CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString APP_VERSION CFBundleVersion BUNDLE_VERSION BuildTime BUNDLE_VERSION BuildHashKey BUNDLE_VERSION NSPrincipalClass NSApplication CSResourcesFileMapped LSRequiresCarbon qmapshack-1.10.0/MacOSX/resources/QMapShack.png000644 001750 000144 00000266634 12572255134 022373 0ustar00oeichlerxusers000000 000000 PNG  IHDR+sBIT|dsRGBgAMA a pHYs+tEXtSoftwarewww.inkscape.org<pIDATx^TUwM.CPF1 @AAPBKRi̝vٙىy{̺l{$EllfIٸn>Oxr="+puIy^ҨQi޼**y爈 . "ׇ֭=2krUٿxY3w4@;@T].C=f* #F_)Rq1 ܹp|9B}5;sGɆxuĪKj('֖VJHѢcDDDD΁ rPc}esyYٲܼy^}FGZhK֬-[,ݺ^WX,G0Hh`i>?G1c9sGqqW@P&UQ7oay&ҡC\(1 r Ѿ|9Ro?/KK@z:|G_G^uH:^BR~a)Z4zzXEddܺ+ǎ]rSPK#Xgw3$"$WH^չ- """ b10#-!!~Iǚŋĉe#YA?_k~7o"|UeÆe~1 `E߲J._*Rd~)8pz3YKHUvmB}X駫e]H\ggo(_Jy1 JF˞=VGZ0slIL9[;K$tʕ$C> 6?I ZdI+VzQp{Dd(Ԇ`ɣp#(Ⱦ>{RG:0- Ǩ?@ʕ+,C6ԉ%?~ H3U ̼l^| $ձctI"""pY {JY >t!@Y=#"P2R/9$0 I²Iٲ9ᇫʠA&n 9u ; $UmĶm7%*aa2mZw\9,YK\Dg[sIݯ?}z6ymK{KaRZ~8tTV?kK rj.d|10aYg0:$Y.H Wg4wߵDDDd%&\DgKe}&p9BЏ#@ ӻ \Wֵ]Q?l㇀#y@jS*GЏ`*P9oo*={-Dfۘf|]gyᅺx b(aɓ3$RKd޷-ڶ-%RAN>&0¿{%3glpJn= A?1oʋ/3dj~;%;RJ>YQɑ ,""". "ЮYh:C< K`(Uʔ*5<@6oޣZ(B,^~؋R(v KwY>|\wx%+DDD b9$&&Oϓ>./G5.Z۵+-]#2p;v:Co do(F90 r.]kOJ\\x{{FQxt)B}w^}R^;DD`[ALL9!`^eL cU :-"""" bR$7օ O.7n o݊@"66A=-/FHD-" m-":uC'o}|W `ADd[L &(*+V?ܣw TiInR~aMD2ڂq[eދ:ϕ+H5+&>XLʕ-ǐ "(&\DdKclwG\1@7ߐ&T(uw__)3gW-N-bVqK".-~zY,>Û "J&\Ddk޽KT:Df >;6huݘ_\"WգPūÜ yʕC]gBaazlpJ":I3g,US\. "Z'Xa'VdF3DBqYxҾ}֭4lXX "&\Dd/u$6cYI1c:63.Dȕ+rM9r=z]._X]3gn箫h?Fg-?:fcɖ-Oc1@D~)ip$ޒ[Ξ}ErƔ^"׃@UY"uQQq:߷,_~TɎ37ՁvH"Gx,3j .#ۚ"" _YXZq5ڼ<<fԙ37eŊ˥q ҳ2v Q"ϥ0uq-h_f 1Ƚ1@Ddgu'"Er˧0Deǎ Ҽ$;wG=e3C|rFs>;{,]ԩM1&ЩSYqά3Zhɗ/LM¸Ɩ\ύңr iӦ^jH".Egd͚ u G^km!Qȋ/6Yz3CD ""+`KR0EiX)[[Wiܸa"$88T~g[<9o2v,:t8ɖ-DVcDI_d?69{eQτSBFXZ3p_ƼZ>""l4t2{̟MՆQu8:r#DFFGdeҩi7yͿe͚kMxɑ#T~ry6U!}+GO[:C aʔp!9v\ Ƚ_q L4/u3ߨZYՁMI[ V=5nB^,׬9%Oߔes褐xyeKtnތ8IJ>fPIpgR]K@?׮Txu[Ƀ3Э/ 3^qHJ=6W.\)˖_$kVV9?}C;(Wd??ϓ?9/w?_#oDBCu;f&J(X?ycեz|*͜QHr3*&Cf8>\&^#GgoQ$_)P T*T%EdyhQr?>8IwM%'7ll\Wxx}!RRnٵ9Tw>a+>V|3>s?# uXYf Y6>6 8cs6D8L &<ϦMgTpzEvM΅޽dϞKryM*/XOz K甜9S'o@%J}[ /%wM[e"lt]舘A2 gйs9i޼TGpOBk2+\8Tn_2ZDmɒ#Ҧ$u#UX:/K' 9HS'pKNm~A:!#G@ɂC9N5[/"-&\dキB۫ZcD BҳgEȖ1ʝ??}:4.ZhK]_:xzvngMk?`D_҂D fbD_Ny꩚2p`-\9>}ѿԙk֭K-"6rF2d>Qbƌ2lrTz#=]s:C"7sfI|4wqOlzB9R"aa뙍D bu9Ys:Kڛ _7`$J֬z;fY-￿RZΰilYu1,$2S)D.֭Xi7]tzMwf[؂Ϝt=j齌uPXsvJ #&mUg$75ٜ^#MRxҮV>g).^|Dbc/GЧ0'!>g1_rTWZ!#1 hyԜ7E:cDܤڵ=Z$O|5 $:֠>HU,l, IR=r ڵ"]{$JƏ-?^h;t>|U̹t)R""buz+Q"f nÆd:̪#{7ر'kشF:uS7.E~Rog~V 8̳KjT4n\DtR5.c1@yzt;2j!N R{`>Ӗ^Ԡhlb햀:K- %}ԗ^#ktiU]0{~3EDRϲqe$Y!=֬9)clL#7܂9fQڵ]Qj2]={!g{ln0/fzQ S(B[q^Og-k~ݞ]={~ݗr5H6&\tz&MڮGD `\J;5K"TXv8XƳ3mtVo83C,;׌PlKtnB\T*昈ԪolQ\VYz%9g钐[lH+uuNb/J}=|r rVwߒ:u*5D\AzAf`KttDEs.D״ٷl^/h% x͙xeҥ CRK,@] 9&\(p!Y oHP֋~*y 7^YԍG/}FvowB!Z={xQFr3I|7rȰaTSĘ12Z wX(r>_uR+W?#1IPFҠtAyt]:wBh'ɭgS\?<#'A"?9'N+Mͮg)]BBPxW'|t 8G} ඉL gH`2(s7EYXr,LiwY!lrk4lXBo qc͞=P^_^N {Q= `k7yLo /j[ܸ1h;~=Zb+/@ ̅)ժݝHU֭Ϥ_Ѣߪϼ x]3 :LvӁ׎sguςףk) Ӂ PӢL@YԴ!. dMϝ oٳ:DNW \nsUʸGeòqiwGtj۱[7RzcKMk,Yxmd I߾5dҤ.2m.ٰ\xY=)ѩ_-[?$˚5mrXbt ]k΋zz7Α@P #nU[a rW_]*#F5Zw_cdGSF^s엇%(g,"gf>mǑ4`XQZ>]Ȗ42c;%NjuXy99~kqCĜAM)z| V^߄5(z4)z,HwƐGJ^RdLceaXoczHiթS@ ^Voے3ά0Z Rn?i-e~A/0MN$Oגc]g@Jr7x'!:չs9 .VŃ(fA]~^=!a8FkR<`qiذ*aaQ%SRk$N$IdǎgҜa%f-EGcz8iL4҂xɟ]Iڵ+?yҏ# G!U(ΜA9đQӔρ.Th}ڧ2er..8dvT{azȵk~w&qɓSr;F´1L!3eӉ{*P`e\Lz)IFQ YWܹY]d'#{oY._Ô~ik֬Xu<oYF!sg:Ct'uc0e#:,(ܻKOBqƞITHx>PoƌkO>&[<. Lؽu~iĎ+%Vka*~T?^˗S/㒐pE=N9@"hլY@ʖͩ;bVm'=߸aZ#j>Pkq!E1J (:sLB<thrn.c1DsH웓a,gųkWѝ!r=ҿcY̞O]1ҏޛFLsKft2f:#3ܹ[=\ԩSP6n|hCILpk>Y11ߕW/ OUf 9Ɲ02@#ٴ,E0][堣Yy#@4fHŊv3PH疒%tBq`s׮ z6q" j,M̝|4TBXҀ8PsBj[7Ձŋ:n_Nϸa=}dtHr#ٝ?o.hYn}ңufyaihݻ/H5%ļc׉ץlQF˕5_+ò~C'5,\U^M #س{꺶_=k2ex?:5)sB H~#|8 $LJ)Ut1plw\ m ?;Y޲{a2˰a/n 7Zr%RC@7W_m"_~ !Ҧak!KDٳg޲șu̝W5i;xߙA:}TEF$+Չ7rm]ңzYM92õܜ RyTCS<ѵkeƌsS   Hoז^[*_}h%Z*III3p}QjTsܗMޯ5#$?G_Ȝsli?9rvcB0{v ǹx8ZT`A,AL Kخ#$'nivG{d6d0n3VEOJ*-׵ӏOˊ5㣽$Ys5^'/1_bdzF6`A: xdPsNR{хk,b>:G޷"Ǐ7{@Bm̲Ɉ1OΜ}D)aI7oN=߼i6vZ#>>QO֞wR^ufqM54;w!iٲz0fеkj`fMKL9~}'!Q_nA Щi u',pt͢kY""=yyÜ`H飿f5HfggzU gv<ŽΒ'L1dJ8;@G/:FTVJ$mۖpѺ;%/T>CwFwmÒ^I:{'O(K^ 2~|7y9{]{zݞUX :8e:řhgpfVLz,/:;¬תcjᚉ36udtdϞ_Z,g!ɋFFoxFo7kvJ~)X^FѰaa=c},5B)S(ٿ5A$P4l P0ض>a/nӦ햗^Z,/bZ;XB߁vh)S~SyzL6M"ɻ6k=ףȑ_WOl4XӧLM>_! +ݻW3ziw-'DKQ"xY5-aaaҦM)m#Z?7g$̀bŊJ4$Pҙ`Exxܺge-ڑ:rT/ٛѣ9vC_@Frݒ~GOc*ѣ]RS5dܸF+ea}#Pʗ/g6jTD L mL%>` 3L\#0G)NL/L1bLNYQU¥SZۍv킦3K@S0/?*a?Kz^>P3|X."k> i,$sq}#W_~Wq t^j61rN/Gϒ%K 8gO,:n*HETp  +c=~…pu |ݛ#h#|'ORn"u9!`J d˖O/ rW@2].(FU_y1xw:/mtd, \bwү_e=2bے%!!Qw0~*{UϤ65R#C6ԙSmʕ+P'z822Na`)H:tXtZ^fm;GTgRBa{;Xv԰T;"YV<KeV x}8cGX =+_r_azj N35}v}fFOke9s3P̛g7.G͚ԵͲ%ZDЯ5.U}F2Ԫ_gɬlfcؽ xn؁wW4bGQԴwrtu|vF0]Y#ה;{w츨cFS ?KΝ_'pqĚL\6(gb ">#D8pn2O p5u'PƷ Pt̘vz=#lpZYY ҡC1ٹ;O[wKk9Ffk $)W+ 3|o3fsߜ6wG GS"c2lX#]֐Hc2Ar ~eo>$ٸ)S'Yk{\JF3gM`gJO\^qi޴s `:t|ju7rWpPINE0sH #uku*H(" B}DEK}M:cNuYS|-;8̣B8m823 _nٷoѾ{6Q eK}*VITwK 俣8ɒ_6mzZOQs . 7# 5bO}uנ/OZ(!ՖU͡M߾S_8<~ͯk<`>.\Boˊ`_˨Q({i]\ՏduJ:w]ۯ\5DD/Sg[wV^L[w J-QkO-8ɛ78^D~˳0}S2iٸ#3;g_3g#wɡOԬD9rg\1DDFIŊd>zV;b5kVLVxh+KdB1;O03hB=zѢԡ#UsɄ U<˞_|@ZؤΐuN% R?<[Li f}jL{WfǷF6%'olY45kDݺ e&Yse_(zu]# T؋?4,e0۵낼2YIVN~f6hPT MmeG[&Lp)]ʖi<pA(V/u].ĉeCw]rQyP3c%ͦTMJ%KK6- 7IswJgNIBf(?1TgQOz?pLj]G%l˗#lyKw tq9so ::^ڶ"+W" n1ZE`̪UǨ3G۵+% 3ZFc~5/7ǽVGȓ,\W]KìY׮EKETv{a ԩu.3g:;'&x{ /_X:w.+oHWNIDD%jڎRUQwlYh9&M~ի1UT/_~RkBvrܱ._kYsu%ҪUY( 5lS)m1t]ԩkW]~>(N /g?t,mٳ碌^~ejر!VLHH}cyVݺ\bwNp&&&No(tZT3Uہ)G~LMJ-G⋋U.h_)p4;'LMO_>:a 2M~}}Jx=KkAVu4J[|%y꩚k=ӵw2}zty{(ohY[;KF =0Z>>ҲeI߿[o* ;V{?d+,SP 5l -!ݨ՝5y#%wҧOmرZ|S7矗ʔ)+Uz#-_~T׺`; {':Jwi*ە<\$< ΝAB]""{Adg!reYbpn_.=7E3浚hfBrv3N/LwF"BBCCK:G'ӣX0)_:I޼ÎDg}5iTvVys=Vce{MM8~z{?##&I*T(~*W_=NaM3Sg6v+Mɓ)7ZKʅ$g] gX>hy%v-bfel\T50-ֽ5RNٌZ#T*o{Zg.*(%>X\bbd޼)0*X)KbcY¤T0CH׮;œadw@|lY)XGE_ԙ9AeUM[u&eXi߾Nvf͚`]O?]#'oP-{&興 3"}Aw,Hd3 RD.4FΝ ſQ.)R$TVRmNŋ[4eiFzSr; O-e ҁ^k|\)E-??fbˤI;d9F˖lټ?@w/ǎ]SúEz#UԫW[[̌JPu,]M)o:-*U׽&ᄏB>_}nHuk,|:%7Xִh!yd솀Nk^/\O/{cFBC}IBb enw?|7nJ -H\J:yR>#u[Z)]: ^^g{?iРtVN}$$Ė2Q։GTVBmΝ϶mF lfD e6ivT?sIu&P[֯Gub^R=A] ӴW_]"#F`4Z>d T)NaH$(Ǝ ?b|-vC ""īc^ʘ u ʆ O-FΦ-Fro?[~mJMHeᇫH6tP}ʏ&ٳ8u\4Zi[ Dj,&:#T ¥lQo^3}^UP[bGT!0]I=|0=8 .H_'A#/!VxsG}X.kܹUhG࿤ {J"vȢEb J dUב9y;zϞU˜,(%J{Rrt%XLH*ydǎgɗ_CQ 2(Q"92hָYѺQRx2:, ʆ]*UH?p`-ubi_wmˎ׵$s}.Mʕ˥v$> ևUklbqC5dF< PռuqݻIpp] 8_ƎŲ&saXu.,gV{/_~heHb wdfH9uȱpDF[%#Fy|F=1@d#u #HjY-\8TN|hVr f /hiР|Isi֬t1c !!:C:v,9oԨ)7b7ی)]!S \ԅ2ԹY0@B|e$Yo_hvg:3o;/gŋˢRRH=K͙3WHl,~v\Lr`9bt*\]LL:uOYtV^gޒ˗# a z-*wO=z&w3}mL~ 2fL{4GPF~yZ2`@u[+Э[y_$s2"Q䧟:2'mó tRK[be__R ]3\;SiIeW ~Fˣ3-3)SZXZ8,A{NE Z>^ zyrXRU6}UQ|֬} :Kqӎ+J#oNO ز$$=]aCHQ갮VJnˮ]'#f'Ç4Z3yNt:3w wJΦORcJ"Akg-W$ ""O+#%5YzeN'Ov}I//_6&W%@3g69}eչKyϓ %w?ךÞ=R,y;Aʗ+˗c GNכzK"ĉv)YU94Z%J˖J_%SLS~ufn &]UOeSZu\>_uAQRLǺ$ӧLfYʕGk%/-Ze-[vDZRY0]M`|Nc^W_m bI_[rh#0-@ͮwBԡCX5CŨAF}QEKBydCR֤/z5FŬ ݺU3M֩S7H ELT??oL׿wOl׮=)s\,OcD̼lo4U7N~Lf4ow ի({W-KD m۞9u'C^[*/"kDٵkN/n܈?Wg)(W'R*^[ΟT4{WV>#FOiD_x`^ED~%I*^y HwV-&KٷL6m:%Z7.e\ ʐxu*(BZ.e9v;;=qORQ zIPGlСRHufbTRT/k-Y=wD5kݱKhT||(~)Wb:TF$ 'VSzo3g^P$L6m::YS<~{Jeȶҧk?~lvNhĖd@J,:4 !z1!@ȥ5=9^ykWM诿I-[KA3>/>B\mNŋA>HϞu;+3̿gzS/IBwcyy2~6ED>03׍=\._F+FV-kuUzH=Ean3G;uʔ]b'#;v` *aYy%y2T #^uˏ?w̽tA!CɇΓ/\?Ly)?]>7oy_6A&:w_'%$$H&OH-4Z!MSp6)V Uc@7tRC]KjouM1ϝGJ[bKQ""wdY3 1Ч@-{QϞen;JE,:xQӎ@lLy!|.~5x1|ր#?ϣ% f\V?6 L$/Kr__ŊzÇ,@ג)S (GS ck{.GBYٌX$Wސߠ=|u3*Æ5W7*n6Z>o4*"ai9~:sLJY>=˦ʓ'Loh…CЙ3{뵪iiܸ4hPh833gDD䎬I֦GDD !A?Ke JH魲-)CύB<!; qa*sls[$KVo8})ѷnȥKzر{C}Mt%3}Z.a1ղX?wVƴ$`?E=c+2=bm;/udzv$i4=Pdrzz/u_R% y#Et)V <͝_*W+%Jܿ_F}jyM$}Mp5vrUyE$xo%"w$K>+ ޸nZMoΡwc`?=H/_Vɟ?Dʖͥ~z2pIE;AXÌ}K ##xa;w[H9|.yYپuA"#Q)->ڶ-%SvOqd#2j&9sElW%vzV5u&nt:K 7C Sr魷?hzկ qa=H1M!QWXkח-͛7Zk̘Ms-0%+W.﫦$mDD%QΝ{M*!F6{@,Kbf/˃3j,gbVp0)a)*?^*V̝mW>!}LV:!'Ob"*n޽D@FLKά'P߸O?moHMnf`Je$ϸZ$"r r0e;K՝1R\yZҷo.ML'&l}G[,8Ge֬}2}^|kXc#:!ő%<[;!t53Z>I.[<P]r,{YL3Hn6Iԙ~~oݤw9ڵ3鈈i6i5wpA11x:V%d2n\Giٲz'.=KDC(4|{gûk>n\Odd+\QƼf#FR?9{zᶌ#H rSGbYZI88Iu359 x?IS\.7wZ1XBP  l *P)\zkZuy{WdƌF,%Nu^:@*]!e3C59r\ٲNm1嚾joƃ@C2꿘jk6JHynjs=(Vƍ 'v!Çƍm%6-&&uԖ"SOȔ֯?:Mՙil q˃^ooo;LK&O&~B0qIҢE9co]"W~p xޖJGrog`6A7uƊ%zU׸ԂGRy?~L-MCE?WBٲ k)Ŋec^4Z釭4s //zgt)B_3Eg,@sIyR'EfFu-ɧK/-oݠΒ~"{>gU\NJͳ.ܤlϕ+P.-ܬ5'޲z[bX쨴jey7mҫ2eF㻥KPF,%.șPH9rѢԡsQ1,Ik oի˗U(}@=fe eS^6ZV[n٪ +V<.͚V ]֣ڡ#gmz@תU@oe'nHbߨ8?% w4~13V}nEVR=zV'Ѻ;/utt-tcڗ|?7ob4"8|;g'sH7F}t :_rōs(]:qx#mOfڬgaoYrU9WqCD(ݺ6_kIݼLt8PX؝Ś(cϥhf>LE5Y^x>߿U24hPz5BuYF,Kvؗ;hQQs:8b"o"{R-ɓqҦM)>RN8rlrTbcH6DDw-:3b>[n z#emRf, 30wBs gjl_eyhYt e`8a3fyq,o@G_5(v*FA;b`KkhRvAmO;S pM:"\339t(=3ty}@\L8$#%RGW_E%ۙШ^nͿ,7g˄ [ǜ[֬YO`IΜ6I@aB"G6 4 ~.7|o޿Q%V]S̉eÆz{v?xȕ%Isp(S*@!Æ('cʗmy$֭Lvu1eպ #ɝ={SuVO/P7towׯ?}Q\Y'Pu/i/8+&L,?IƏ,|NAq} 'nuw؆4kVL}@oIHutTI(#Fk `w%CR9+fLgQ>v3Ho[7m4G~zE.Ij~eTQgw3g^3".Z?˵koQעE w7mŋ-w%g`yz{kעtB`L0EɃV矯-]VFg?eƌ}F˱0ο"uv;i;w;xƒzW6,"J0ɸH^Y: "rmePF=&HeԈIҨDuEI˖%(M'r_K0@\7Α(OS@N /l7Z6~(':cY~Ȍb?֍PdAiʥK*sJf^܊&'NhԩRHCPk +W>Ō6Aǎd̖bOD(Im$_|h͛$@\f֦ jo6Pesz Oݺyާv+ _SaSP`s<$ P? HuCY"=6iZEF\~k{׮=iɫkfkW䩧~>HoM9aiD侰{7X:C =㻾r}C ;間.ƍ;2A@jĨ`YfW!aIDc2͆mˮ~rӦ햨(XC3;z8WLRb^SᥗV~K ~$44^x*_FJ4(%Y^{  ?i7#C,ѣe}ڵ[z;HSr"`?mLx$maaO%K\Dã7f h\(%$rMI:ػ^="8w h>zP6P{,@*γ0IBCߦm +kT62qbg}`wߵoO9'ͥwJ2|xKMc`6@ZoϗQ ^ /c-_SHDQ sz‹/_/ӧgQ_fݼL]m;g=ß3ΞN,-""WРAaN^>2j:5F^7RO sB=gÒ3a `%ʨH)Y2|Yw/h)]ÌEڴ)%^^)j9+^Ɗ ]DML2dڊl uCu /,2Di"ÇPgMa"DlOj;B|Q9z^?t!VlzEٶ~c(U){Y-oD_梀UUGu1X ][{4)*V 0Z+VmrҬYY=Q"cJLL_%)WyQwE$$ebL}MfYFO> G'  K"JAdd- t1ŔFѣs^H=zi N}J ߂eӦ38Y`y!!$~~ꋊŊv([U_…puIJ)Q"LdKrf;uDS22wCFN޳OFnC'-[V!;,Yܻ֭gkwcINOմD=掘$u8heR|2~f/\P/YJ}ʕ.BG'dݺ'~])huf$_|Bm˕%`$J yeϞ6ѽ~mv'3~-g_Y2uj8IRH6 ?p{ho,_ݩCGpko0%5+He3'qq#n=TWtp'뚂G_ H=n[zhѢ;jHgWqYiժ^JQLNnhɒ#:7{'k9%qV}dܸNvur{Idh?h]Af):{Nϒ!J?oQM>3%AWN/g6od楂2avm?_0C=Jbb^}1YlL^~}XF\պƍU540;Dx qD!AڷOڇ?A(F((:|Z-2s^u=gV]ٵn]R0췧a]1Ixd$֭ԯ_hm۶GՒC{X ߵ뢼>~r6ZEph>nuIPuv뛬MMRŒE>lDGo(ɜ8qja4?x\̣{D8~|Nff"RpX1Ѻ׬Y3JY%))^֯?$?R^}<< Js7szG"#GH61{f` ;uŷq~XWRMILMǾ%Æ-:sQr}i|ߔ:b}ec;/GʤI;Dw& WܶGB]^7]P↓w=f)SPzh!ha_>ط,nr8`MDSUJ 3=DtP9LU^`{;KKﵝ$k֜4-|rb>Gɴ*8JDT.k-Sg$HHZuW2$$kgNV3ϴ߹_No7>[#7n/Yຐ ʈMSzU{#9xru36l8O^p oN"< 1JX~Mb;'.%'NOΏ L`ϋ5ʖeG3畞@k˾“oyR;;(zzJc&Md7ob+*p KyjmZe:"9GD睮]A(*ٛFqȑ "@&ɕ+HBB7VN{X=8::KFDK߾ dIg 1Rpn޽LMƍ(eTO($^H5Huܔҥ-G-1nU {*3KDwqPk٦Z(XG/ӧݻ3ˌ(0 ;'Ц'-tŋdڔ_-O?=_=L~zGO?uų996mu_X^iٲ>Qoq_5 >|qgԩT^\ŋʕTCɤI]-/3Qo"7$L)__!>:[ۮ̴hmDK]!OkjҤZ5h9!n==۲iɂ_<;C$j?ۅ0{o7;U s3}k\JNZ4s)s|!3g*(|,\8:BhlRX>'L.Eȹsz 9Ӳٰa/V3қ#"ʈ ʕʶm%:ڜ|d -Fa}reMN4&2A3u|\w :lUHIHH-y䐋12 7iذԯ_Xoe2x}8qV=i%JdM̭[1pd~o|k{*yHYyu35r ܹs-A*套ر(\OD ܗޟGg="W r@JeϞKF+8O4Zi̟OOP[M])i$  +`3n &(dڴ^ҧO%ݚ6m;]Yc]trrKٲ9>zsߚD^:y[T U#""Q\oȹ19?9U2nSR~!mwV8s斮+գ)g³e럐sKB_'uxk zz@ŋ-獖%g˖G5+&kJrֱLa{@KR-Tw\\:TXƕsC6Ӳ= TWWr%RV<.|Z~≹*G^j"w+ " ֽ%v䭷Q?[ p)Z4Z[:.&[srz!t ?~.KGIѢ䣏Gj". SAƍ먏_*/B=҆S$K %l d؎YomBaY_F <˫.W^Y$Q"#UEb[o׆k#ZKgɾ ?ܹ+*~][uJ"F+-'v)>X)|Dweo>R-$u ׇ u~"y睦e 1 PMvW<$HɒY*Wc<9ƌ,O=5_"y9g2ǂu31FH޼aRJaM,K?6T^\1KrU-Y^Blp"U5ȱLK'Ez`z8|FBB_~,eޛpgoɫ.i;OСKgDkuRj&r!*_/WL&[4#W֣GE:;w6Q{A 0G|WrqN<ثq".EgIG#VzwzEf9f4~|4n\heٳur#zN]Ή[baKꑴjH9CeҤ/JC2#W^|:WB9Ie >*Yy 3/Y\e(\p"?8#º@$[bTgK~ԭ[H?{?Cԓy-4p`-,s4ekOFu"-zԩGL3R$ɘ1qcS-ڼOo7j"mڔ6'$ٻqNpSFf0/UU^*$?^]gOk ԙDK'tQ6ʰaU'iCcA.Y?^8q]|r<_}1F$;=MExo܈a!R7|Ve޼!zG{V-Sho%́ r:[.mҤZ5h9/_3g9s͛Y^Rr yᅺҮ]i)P )+ܺbQ_IT…sJ,>+.േ?O;XʗύO[ɬYe׮ r-{;d`܊sK׮eK%8p<YE0'Z _4w[q|u\V-~}~Ned܇Ȅ t2lڴw$54m:ј~xDÇ/_Onjou3C֬ҥK9|ԩKry|Iپho5jWdܸP0o4aBg ɮb믧2ן^5B"[ ȩ=-YrD>9r 3kKF6?.!;q Yr.LdLƔkS^jBz^ժG2Sƙ+[8#>r&;gV[j̯F%K/Od_xk찄lqOuϐ!wȵk9AI%K(CgGo&!::F&ӻ yu/\!}Δ3ʔ);G0ےșp @&Xꄴla$Gx2n\Ge_Ug>Q}>|Uj0 ́ԯ_\j.(yKBBL]NI$o v*ݺ(&EdPIKP0_@}0_]y9sY7ob9gmɗqFF:.7%u嶆Qjl{.+U*|Isu׻,i}omi}ݦzK?cb&-bg:2{v3$oF eL@@u=2ZD΁ r%(0d`҆eiտU9a= u$JvvL@̆Zz&$Mbz駛7-*J` e\OSHtGw IM3G1fSC;Nz!a@jԫWJsIOA`Gƚ63~|'i# իfGSByyRx^XZ3*2C)G;w. ٲH99(^h>cXr"r& 22NF|`M&oiYr:u NoZme={U}t?=[*RybV2|x/^ҫWnH xyҹsY}oDEIc-J{cFne 9sZ_(ٹ@Vgic']6a6^-%w-XC\xuުn(C/=ŧz<- jZQzQL,(v>{EG:!ӦVDD ]YT^.k W3H͚Ew;ObYA& M?opdذF^.5nILJ|A3^XR<Ňرz^Z"C,hINR% %$$矯Qg9%I֬-mg 5b0'袅kKWRZq ,ɛ7:(m,hݺmG2+hi֭kWi۶zqۍKdGN?s/kߑYeP$y`d]H-LotJz.;NSJ,Ir/ Jl,0KG'eU&MʪUV=z 4ObcJ8pYڵ*GbM=kSQ+[ɇ 6mJ% *VlVhh }$66QΟ%gφY^ڰaUsٿ-h̙SeѢes{õ!l~^Wpru͗h?kr2kVo2Թ?l'a 1;Q~Z.)?l4m:Qr/Ju`/QU+"2کKJX w vzL{tUɺ2lX;Y!7Ni,/5ksY%g@]<(9mIkv駎ҡc OƮU >[ˡ?TO^}5WdD\\|_hGuH /vE= 9+^um/]B"isN2jT{TZ #{0ZO4f*Hru)ԈeIRLA1RVJI(HD;H瘑u"~Z@bKC\I,Y;*5|PgbnK293MΝÒ, G޿ry}"r$Z91`'o)Av$ bhę4?>}QQ,{Wk#&tց9~IpTrFHhh~'_~ #qsRT>y*{L&N`Hy6еk/"ޏ?v=0>v?O+g1c:Hǎ!a jX ˾flɖ-$""}Q)Q6w "gRvooo><v]O>Yΐ?أ,zK+njٲ.rUjAYk!xvܹI kmAy L~oG]KzʈǫˣV zրߛL~y_~g2+{BAlg6 p N!Ǐ_Vg%-h ,]ueȳ1`633sN#UHiy$&xMZ$8Oj6RyGu끛5+nze>b*QILF:y[=t!(7 K>rcUɓ;uP<4}0СmT /{I]7! MUv$.^>>-3f uJ|ygQz%HZȖ իl܈+)A|QJN=0oy:RwZjS9-.ҧO%1"ij.b#TCWϯ+ܣ e/ gSE d̈;#/FHr9T!Թ.L;G3;6i*Sf>DpaQ_$1ҷc*'vK҂D6^SpA# W7ȚpرX~d^7(_~Z^}N7_^GWOR~/ C?\%T;>$ٳ-}QTc42OuXL$쓼&LxIa/ZO)Svvò5뭬Y9z*7 `J# G7Z(|BuR:jUݝ[Y ¥[?%ٵu=k,lذev-n!MKl~/&9skHf6n ǎ]P-uhRBn)_>nWŊ~²uEuqLBtwj֬f+G;-ݻWTq#KV-xuf#"[u((WV*H6Եb= kwkO?Mm;-V??oĉ ~3l套˷߮Qg||ʕ-[#a^r*aJGNYsR^}[wDbTG~&9{>|EU'wI9u;=AR̛tXhDZU xɗ/N:XjKKT]BaB\w;h9'l ܷM&i=0g?c SQVpG$52gY yx}'<(͛%,0/u>t,]zTbbPoT+l ? G'йVG=7oըQaYqu/t8r[6N oUA9zziҫWu;DtX=*<}SQSN}ԪUP֭{Bu3>~֮=)>8Ibc1 ^ HFl~7[~mj?,.aF YD>2}zOҥ?._ֻ$YMS^ d5>2 @ֿҥԙ;d_o(h+Rپw.>.fjި io?Kg&J!s@ɗzx`9޳>KDD^4~5>'7>+udtC3 ңNָ~=ZWe߽?62Zm 5t-~=JmV-G]kke,d 9J|mG2&w ^5mK1z69US_⋋U !%ҥKyr %<2[ƌY&t, @رٺLQ"-WWAaٶ~_>|NNzk$pmFBLQ2l G(Qi-T-wڪSkTƖw[GL٥fD*m=xqLEљ<\m=u+$u\8D'#\_c4q}gXc9,ؿ[ԪUB}vAj:3%(lbʸ0:jT;W-\W!Iu=w\o||^ǟQzkYz;tR$uˆ^WVD@-\xH{{c-V:u*g~v]''O>9O٦Qȣ5NoJ^{D;v6#OƏ2thC{짟$dR`/Pk kh}"#;w?hg dƌ*-WkZr ,i!rmKgDQkr5R}ft]ʹsS;7:#o=C&LX/gϢ7Ks9Q|A3('ʌXin(y܇e˪zBvOKlHxΝ3ZW/@=[޽|mku{'>@F(O?=_db'IoJص:ˌ@ RvI @pr:ܹG#SgS#G&шmJٷkA5 ѩTGR=T'rViVz5S׉F;uTVWoժH|is_[^+2^Kgm@\9)?N^{mzu qN&@D x}T͜_aA2eJ73J郊#F:$}̐_ݬPmR3{>ifRٰu5fåA22c玺OnܰoѺ;I4ΣPP]0M]FNaT,*|cVKqra;g8A\FdZ]'eG}{kF]ϭ[1#TTiذ]QWϯglIg+}L?yc{ Rv|@[r*~K;/H.˱cz_{#T1sU|oNRtR\./!v鲶ڵ+% 3Z pAN?BW,>>^r zO?ܣΑ=:Y`1okwE D)A@ȾuwmТů:Nj+ QzfګmyٻˮP\k'dnJՑK/,k퐐32op8p#Z㛤rmF 7n<-7ZDt[TTHNg%W1OX/A>zCM d^ MFl%I:yꢷKN *悋"tdcoȋ/3=DD Ln2o(ZX֮} nE>)]beذeRl.1ش,^|X'$/cis?2$I``(Ur97omcc`$q>}SF mu]?cL_g$QǃUT+f2dzcvqZ:c}D~U/% g`࿌5(XpD燕I]~T!"GxxdѲ$پ}Th{*=(,7ظ[wJ_U8fuG-'gNt=-^^ޒOs" PH$y'cI(Yr\eDt[,\} Ɣ)dΜZedڀ>$/Ph`3PHif2txH{7l#||Ɖ FA{%^cZ73ڞrѲ{%u۬YkW?up ҥH9w.\Gș37a  !a_͚+5Z3f<\u/7#ZEFɁu醺EeY$ 33"O Wɛ+EQCe.zY"J/lZNȗ/D}AOTFxc:sgzufE^٪oÍ\)8̣nAxf 𑈈gɔ);ՙ{/I.{kUQ7c癩W:OJ~Gsf;=TYfTY+IJ//d>G=(ydWg{Nx@A-:%Çw-J;d C$))^k5TuuキRz!/4BbL䙐qWyK׮T @}e[͊&6q HY"I %_|h5ʗ%FBs:2 WQRSvA=::}*Rf^tĈuYƦ/Xp8LM&TQQۤciz;c;ʸq DϭŲeGҥp{{/ e5xdX6(# wsG̒u՘5Ͽy3]Hˋ8{mc==%|e Ju/ޒm+y6,>`ninMkn>TMׯj%IBBbYy:_\e310`!"J$[tZhQF!p1Qɛ롱=1[k]>̛t\@ ~iܸLKam 9[KtvD a,[_ZMo}(_ZdA #7nϔWLOf].Z}y(-LX(,=%ȑms"ȫ9Pau0G:믏RyRLNY|ƙu*3f<1 F5:{L] nZ|>_ D-C؃"ީﺠNJfQ]WF:v* 2Z?8÷WQr8fݾ.f~c+0j2x"EX9w 9%"J u_g/`BrU+"x07$ٳ`/ՙ3փ.WHNeUq].sWgLn +$0CJHHܼM¨ߪ/ 3 ^~6lxNOo'=7bAJf70;&`&ȅ z 3^8(/ZС |'yݧNݐj~WQ5kB8)L {%614OG$Sk4Gs}QCWڵh=qO@@ٝ$?7K7TMU+k'A•>QQsDITzɐ>|UJ['O=eO Nu뎪%I\ܻ˄aFs +B]1'r_}4nGM^26QD2[Aը8z I^Y:C2q{5jܸƒ\P 4n\N~B\Aҳ'(D-JJ* ӧk7ȵ`Mc͑mȏ?nÇϪGqmRF1loٍ3ʈ$'"`A/=ȬY^W3XvD5<#͚Uɓ!VVhxHZW?)Vw"WqRM޹48q=pKkO#g6bc9ԕ< ;Ǝ ]3,˙3/Wڷ&_|S֭,Sv~*KX2wﯔ>X#g.͚URCg)Z?QfȑɊGhQ J鐁~rM]DZc[ 뀂J2[h>|rED7Z ;>z eL Rǁ)xy͜Ku+oZصauF<շ߶!C-"q@J ˦Zv7%?B~"'0rFy9mq"3J?>&ȭ[r-c>wÑ{U4C{^Io6TDD( XQTD _@P&H% 7gwB e˽w͙A!w;s Dv>#"/& D(|q_;OEͧ%ȷlҥ1"Ax*d Ē%#Э[}I*p8{VA_e;o_D3P('LИ1֐NmZc"+c?.<]k^ziS^9 &|<0BaaڕO/aXt$7/9~}h31ax Ν'tDDJfP3ѕ1bTsEQbSDuᄏNE֙)GQɓmw{yʍ #S]lױlY1}jzM\d |uܙclsqBZf">>5k&ছW"B<ϺGDحVԩPGGSˣW{r֪l,_[ KNNCx*FM~ieCMt7C}"2^GY"+?/Hw|DRRfO*O_]oݮ{D$* ǎʒv.ѣ7 .p _c=i(G.Hd<0n\k f3x*$ؼy7%W'~g%wwmǯ9f|k6I;"% Ip<ďn(?VN~ 17o~:u#5QQ52,T\?l0L ii2疢r3SbÆ=x镨]5LTɥ^}u Z|ku뾎fC߇w˶mql ID$)㋛ܟ:7|n S3~]JFÆ0w50?X3FDqP2|w+q޼R: ۷#,W-3㏮yuYuwس0?N8??ձ;Aǎiӷ0}/8s}3O(eanJ> 7Xd ~#ʔg:v,k"0LpC}G-"2G] &L/Of;^}ŃJy?zNETs.Ap>v<5ۿ(~ywc°al.w͝A}u坿c/b t)m 8Oxl6@Ev۩"{rK(Z4&4Ms᧟Y7UgrAs H/Nʣq[71Ǚqu08(cql|7cN:I>Q^Qf9Yy@&$+ˎ'ԍ ׷^>`ݺ'X[^O;T5z@u39 <?xS~.^=wÆ]ycRШћؾ4"K2~!.ArcbH9%%Ǐ:\32u= Wg-"7izvL"IkI\IADސqbNO = w n=_}Ø}c3{cРJNNsY--ڎ3~CW"Ul 7믯-M\S354h֬:v, bQDz)oن? vQ'rmD vI_r=~MZA~/zUF||V\@D&Ic="'&L _'X{V%7t2^?_.-ZtI!*U޽0of7_I˅U'ȶDd$뿁k\_ ,,OYT2ޙxA'{ʾg}%0rdcLE"(߱A7qǷ-{&DFEFrI( &d/˜1螕ȍl#%7(Yj.ZS/\81_nDKP7A*XZ;Xz}su0cFgGLDư+kIVz4Owj Kt$`dCZz2cDc>d[<`g2'IAС:z6m &&3S>=cРUfy ]17/oVD=pMuuRR@fN@"TcSdFNrg9Y9^Tb:1$$`ʔ^ذn̝{`7BHJp{_ X_~Q Nqwo%{󣉬Z+Wq? O=G'#ұr#6ey r_xd]q5/߾k׎ƒDժqF4fLCut&]N`H&LXLYOF(ǎmz .y V11E2ͨm2g&jDNᥗb0rdm+ s&'v̑jޭ*_nl6L\S_9E6yRD6wd;ƍcpm SBxլeq">ٺsذUd%Q^| O&'Lc]::)נn]Jn?'Y,Ft &oߪh0cu6} KkCϞsp)?]Y hxv[;DFJjUƾym:ʝ`| $$DlKD$9"_Ie/3sx뭡榾H+'7SDdݺ}e˶(y R~ظq3/04R&OO?սܑv?0T3dܩ|yo`ᮻ8'YT3yazDVש*"dG;#[ʖo/tzKlxu{U7\E`=2ѠA1YP~U+{Tl<\_HIcxw` 26mfcѢU$C(ٶM_*,,Ç9noƩSt?Z(~0RAj!Q[uY bʔ6hB?vQQ@ FQ+fDVҢXTCsOy~٫vE2R՘Oʳ20}/7zUwݨ"yL,#rVJ;$n}TFɒEth2  t|-Sk<_X"{??(o-r% |`uwsg)fۣGE|Al>;v<[O?݋>mg,dQy_bb4ʖPLH@?&Lh"#][7k%VêU7!4ԹOOOA?v R wԴIL@2Q| 4)>}`f? 3"22\}`:" 3q!0X6mưV-)ED0bغU&s*8Idf^} [n"nÛoEDB⑸زv%ņ ^KD u\EXWvQ>)'|[t'}wy߹siX`]ٓOGXX,ȑ]7KHNj/vP=IpIGt70`@!!]V{ODuu_Ul=w_$_{R' WŜ9Rd+߱cG!,,L9Zv@ _d| $LzޞhG6uLD7S,Ů]R5J6,XnС5Q$8ȵۿFfU;v܁ٳo@ǎ5yRNvF5bP Unr"MnD I]w51-ynٲ-{擞gp71™3 <,7ϲ15]sk%4]&d|/)x7n\cLIrga8'wc1T_HHxJEFw(7^---gϦ_a„Eظq:g1/={ʑ\i`rQz*)vD?c漩"wct|uaf*2.;O[边ItZ?|=~uV xQ#m8' P *$'Ѷ-w ?36m:"~^OS 0Шumk/5DF[eVd+>>#G~f袎PrQ:<ԩT̛I.,,>VEeridZob$&Mj{bQ~rG}c<ˆ~ۇ [Ȉ?,،ܹP3(_̘>k<}V; Uw /tlJxf2u.>3(OYÇMm5@dlOgD ꫫ⧟bذy8t8o?~7pL7kaԞ*k'kF1O付0ٖSH:Eu|p:#S ZȈ;y/ea̘o@yTf ;4+Zt]*?}Oz1 +IEϞpuȷnDn:f:;nTl戈(7-ڎ;O;222[y!**LYYxд[X` 9;({gԪFZ˚/s%c0`ٚx|3ȖFMĐ%nݲ裾ODH"!h{WQD{ϧ f?~x:Ν@?Ge މ}")9>zw/ŸEf\D@ W D6|PlgQ@rI(̒h׮:,@+D;66:C\9&(wVއkOɝUALs9w~uZ38y㉿.3eP#?ٳ FsD"<),)AQ^}8.…ei ecd qb":""IV(?z3csLϋ]M4_;ĒmM1EYSҮ]BE9%xr")&y5?ރ/܈QP͎!mLLTT!ԩ-3Dd$[wmS?JȽƍȸt}b[Q{BtFЕ}+vk dΈ=_%iՎvD5y-5V<] Ü?#c}ѼyIGb/4Sr»6L;Ij^xaKvwkx5:Ν xq_Y&3df裢>C'U;?6Qc;t̚u=7^綉΁$Q {$u`t!Q-_Z,eFꞵ,Z :"o֬zuRv(Νs$DZBrr|ګzWɏáCw^ :O >=_ 3)lѨQ#y U{7ʓo+ĞEBBY]=zTt`*T13}Y$kO%g_z5+)6Zs] jժ`p_3&&XGDD'u3-۩{TtۖÇ` ܫ^X`cO[OxVh%g;-*D1= u$"2c@F޺2/dP/!2_|^ܤv8$Tw_7}=ڶ-?Q>1`BZ}86#?Bȓ)7El97NZ kYMU"yB=@h\d+WNDǐ"{- s0`x8޷O>#E`ذϱkIGrIhԨӳ[d ˿Bغu, yYXR&1 {eܹעJ"MeML"O2*Utz))P kǎ:d\j$< 8P3}:6uop,]:>WÐ!5wCqeUFx/{Of^-KݿQ~‚% pq&Ul&Yɛ322f2ɓۨ$-zܻpA4o/ċzHH} R0mZOǠʔ=SvL;>p>"bJ*#۹S]^j$ #No5wJ.nݪH*[]?9;h"3@˖1aB3w'hxYf`HJ2 "a̷{>6nB;DDDƔ 8w^~:,Lر5tud_Q9c*GY6DmLTѢ:r[ʮg<(V9G񥘘pWȨT@캻j"+'0p`$$|-7ɖyu=JqLyvUƩAugIU}#iX 0)k-[晊=#N]!9,N83~+Z!dt6,\'֭Z0gn*ȈRq}ЪU)wIZ9 y)@pp!#3601wpY!s?m|KR-HLDdT!3S.Ui]+Bv*}&C ZT)ki޼:1Q5J'P-X0X:k% 7eU"aZ.m:rݻOaFI2Huj,qI_"2٦lXfscrիs{\Ee7FFqEŷ}͞[ZPޣtHH]T)VGޖ9]Nh0`ڵcT$K^ TG;{ޚoV7cQ޽+DĂd6uuc(YR uɚ󂬏s20nB-<^}u5?|?v:Ŋ=-f~K9 Dd6'OmJ46qկ5K  pyA2UkWye=z|!wd3V-Kaٲv;&L>P"T+:{y/&7CppOV99G\%yp)iشNn)FdBSL&.Gy7=f|>Qo߲j>4j<$>mVĒ%ux34UEW rKcnHWZuZ8d;gK䃱 g?s8t脣>|B ]j$L(55] ]QgȓlotwzUBѢF\%c}r/6LBhjP_~9HI%ԩ{^71#7/3g@ǎ5TjT_~Ԯ^興d:"2?lv~Mnhɓ{8RhN*U6tR^˯CX4'RC\w0Cdˮ/ G3S ^B˫ SYDd&_'6?K}ꘁyȄaVǚ5pxaQ)mT դڿ$$By׵Χ:n_?m5Phas>Z[Se/;8ys)@߾s]IHWqY3A!2~Pɓ={T yϮ6{uن矙 +a޼K*睳;+[ N11!tE}VՑ+db6V9Sq _9 V~2 C%U|s{Dd7J"+8o"PI}xaXfDDHv gqD ĤItz%-?̚;w}٫LƑـɞ~{D˖NɳNS; BǎeKȻCJ kUdWz[~ >h(8zj/: wقΰ[̳_A9s(ycмyiuOd ZuZ [f?40ծ6MXمg>i2Xz#"O;x,QUmPoe-S+qku sj!SP~9}cϞ(Q"RQX*1 &Cݳw'2 +'\~$0ɔU3m2RvI71yގ'tDdϗ RNQ$Ϊv wFVd]@ft@|j/<0r|1@n1thM|*'W/I\I +VH2"SdO瀉:pi4o>KsNDu@SKGѵk>}#l6\k  ab:^[MӜΝǰ`'"wbfР;T$;ȍ+8Dp.8?[V܁޽?rʅPDF^n{*THŸN…G̑+/[W;|h)#:{x:&"wbܪuR8|xёLLvEe^*Yٳx:D 5YZ0{(bbwb˖֓{YK_xqߚMfpz~7aßo}"r& ɖ-cUOf`eVyZT##+s5kU5m*^ !$$~:ǎ݃N9_"i׮,][tt|7WGoc"r&c)ƒP=IW-#{̨5DnSK :O]A\[Tp|(<}Ud7 (H\QX6-{fÂ9ӌ͘ GS> ӧRgFjW- Vhpu\- Ӧ̙#tLqW?Tt#!Rb`f,Μ Jwu1I@)>:fnGTۧ!߷;{蘈܁ qn&tQ=YiUyRډM=zPͦƺؿ:{ȿs?=';O] \#OetJ}}[ ݺqK?oj֬$ e ݺU@RjiD6l}sTKWlm:&"w]yݴiXɴ֫V*DMv)Q?oZ5NG@bb&Lu؎zpvs}ՠe$yPVQ yې!5t7;@^= F?%מO?폿~>R&q޵4 "wa A@o)8@$|"hڴڶ-#?8##98 ݿTxx :wֺi[o'y_S#_Kk!TI^ɒڽ;=d(wWOP|X_~zYBBaG"QJ44y˷n5uX r5o-SLUvDFrǓYzPEƵvPDLԯÇTtѦM)7TRŋAWСûh]1W'q&z%Sq}Ạ u5OM7V 'ȉ 2P:uIk2ЧQ"l܂;d`ŋ`ɒ-<7d2rmu2r7z`&*ʹXfw@Fk ɓQ#bI]J"Uȋ:44X[e7 ү:&Ceu꒒0鋮]Iwtʙ5k&蘈\ 2_~w#5UnMʐ=dud-pǸ9~1믯2D(Q^,\8kK؂|.dag=x@0thMXq=4Hgn!UDg?1ňR w ο11@OL>KW:DLQ}`utŔO"a]:& õԽ++SF_vݡ2]S7obbBu܁ ""7s5ZKd~6|&/^ F ?/BضM xݛ܍ ""*?쫎ؾ(֮={dGR՞gnݢ:*W.}wrYw% "r7&4O{Ʊk <ď˓'F#F}-Ajj#"2@L&k6Y||r]3Xx݀tάq1ccOCBPXQAtXO?OEg'.+\S/MldKVojٲ-{dvvD2Ϩ(vdI/S`vy $4;6o*:^Xb2]֮>`Od~OٮcݺQV7o|NH!11\\̙4DF>@ҥhB'_2:vDѪl,_[3N]g u(S)5?zAɍD֯?,/{HBy]uwN/cCdy]5ݛ)̟~?) {_1>d,8^gJXXa "";μMƎ\iΜ~Z.XU9'&)ƍ?x/qܰ9&o%?$'_:W$-{-7 < [W̩IZls2gdqM_aNyzo[#c&w㵰eBɀ_>K|VC+Rοk :&Wڰa4U$bRѨQ,]ʙD%Dy+1qBɀ>{/iaa;y^d$M>Ѹq .]%JDLŽŋG(!*7Ds9.,ke`Cdupg_óeFH8+.~3Ǝm{j*H\T(5NdX|Ԯ]~>KdL\@D7o/P sۉ|_)C6oS 4ٳ)Xx3|g<>|ڵ{]ݰLCH&4nUU]5\>sA漦{Xl2Us:&w4IfH&[ L.qqض^ \u}~"9zW˖} &7Ҳ_R a͚]7n#!Х=h[u ];ؗEQeu@\͖ocrr家 #ЈrFW1&/g~QGNoW] &ݲo&/n |l/ w=du,7"u:3ftRG)x<!!!"6&⦛?:]f^{q.NH2@YxTL= 6$D߾UuL4ztCt\[}η3 +Xd|Si)"[p0eJ @t9~~ҥl*@8_oQG{M:u76DvyubǑ#PSDkםɭ1ꈌP!o6 3Lʻ0uprO& W_< "-5ەɇM ZxyȃW_ݨ"&ӌ_dwˎdT:WG)>Su^Q*:1y`DZJ/$@ VirtUtyd/3dMv4l)筞8$OR*T=2?[!ʻin_yDڹsr#/I |o?;)"zv23 e/_ o1GNjjowe6$Y " c61c~v(V,B!ʟ aP$aH B0}SDѺuU8O ~ |俎[oM7EloRn QQ2 Lʯ,|s=DZpK$ '~36 ] #ԑ[RnË/v1|_X/t f]%"3`H$ ѭ(\ o`UQKCtDjjojmXGrAXQýOZ7H~ @WVJq4iRB_}n#JR!6)#.&B|= $ 0:n>vjXp= 96Νk^`"""pnCv=pm ЪU)ClթS9,Y2^EgTe g /?W 1:{`<2gׄ6o>qǑ#qhDٲU-J50m"õ~$~俊WӧÌQVQ]նmi{S{dxuFUd,M%ѾAdN%T۟?\oTٶo1De'ls&K$)P~QV>' 0z> w ^S |-HJSJ͂gr/;Hśo19=SÆuφtX[aΜЫ* WMsdž]du1@1p5FgKG022֮ݯDt5Wþ}2z fDkFǎtȼw#ᇹs7U${C<--w0@m=a_yl"ۉ(77.I$&Ls~z6F ,YSkpM'dd\m'"scHFv<*MéS\L߅bŊV&MnkWջqmbDPZtظq?RRgm-|22X "-99MG7IBT%"ʽ={TGpLLE=趣P`V'Z-3nev_T=Ο "-%R?:t>3g̿Q4jTLGN޾9ضjƌY6Plش鈎eheɌ3B =# K/;Q^ XQQT\k;-j6DyUne$mٷ jxVE!!, Ms'})8` E~s]"ʵGi#*4/'@ɒ x鎺Od=&PG,Jlə3Qܣ&#"kbH[h`lXtQnhQJY|5l6l.%wi]"ٜO͏Iv|5,;"#Ur7!!u1@Zii\:A5+QnԩSt Bǎ9zYt;wޭc"k{[dXB\@2}/hO-ӳaփ^zFd^:~ /G9O9yFtºOdmCD{a[@o v,KjZD'R1Z6mjΟDVVQ5=fT?[OJĉ]лwe' V݄E<}/㍑ r&# 9;B6u-"ʍ-[ꈜ靬'bgU;Z^gH*yhQO=Aȓ9)?8 i} Kn=r=,تc"?<5P52K2$ mVõ6B.u*$TjL=sDll/N7b Y.i\~~S)vHBg1@>sg)5 ~Qn nI~d̝{-z0W^SA{RU}EYHzzny\lc+pW]dOA@PP ¸ YD妍a<ΰ ʍԫW-r^?Ս(Z4VR44V ??~!6"UOi׼mɒHL|XE2h/_+#"b|Қ5'Uķ8p{="oБoKM]={d}#H#\tz:u*2GOf__V:t^;P~ 8AI-ZRGOe⋿uLDnhOo,68gCɓJ`nFZs`?:w'UItȚZ*ٳ&ЇK/߭PS)4,OOW,g1@>W9yjg v]+OdGSM-S|͛<AAC[_~%0xvC{19xBV,E(Zϕ(#",;&NZEn ,ج#"?eX"1w/JGD_,xK[f:&;;G>)N?9QrrӧeO2ѨQ1Y3Ο믯T>8(g6cQ2y6I\xСXr,s:"6&'̞:fo_C!?L KD(1~|Aw?Dvѽ Jr| }K:t(#WKS'V3 駛ԑܽ} {'4mN9R_YDsuL仜.W @鞤f֥uZJ!1Qv!>',\:Amw"q>w=;p଎!KnD$qɎJ9 ;ӱk]}uy B1z勌Ydyk t"Щxye bIǎ[kg9jUJhʔ6u{ȵQcܸ:&>&~]5Qs N:p]io_?QGWujiO>BӝKp),XE]k躤i2e2lg ;v,E0쿏& 0mJ>=_' +Vt9K_~ة#W50{@g[cNk0l<ر3`G~Uul-I&F=|t:wL5y窟~~6df>Dw߽>BEWN/ vւcҤn&Փ$'PSv8'Jwahܸ%v0mIDAT h1 +V"y{/J݅xk,UX]zdyn<)Y#k˖3]w]i!{!&BogƖ-2E\.:Ď;阈ꦛ!.];m}Y71!HY&P 6Ar;=*Ș ۶턎ȺICjjaXbcT MÆo/6׈CrhР,9I2?1![VuLV-sI3u_!ŦM{7͛~r&vwY&Sdo8^z d;uru>t:J%<1%Jq]uLDꦢ4.~a^cVGaJAHʕx5d(LvK] Pus2O}0݃oard(tTCE{y[_}?>&\aʔ(U*^ER3\d4_=DeFv⦠bC[ny #> 4b2;@fk"/DFרT֭+OnTrzj^ժCl$ vMwfEf4RnŋǩpE@cp1ǢE| g}fmb-˗oT7)!ILPdbOׯagyÆ1Jj(O~gHKCډ+޽wgUeYɌ/ȫ K[xr"?~EOSﭧvm4~|u==)Æ1JB_vq(S&Yg8+2#K7r=vE@qx(UJ$ob,i3ܐQhdf^KFVh#y  *س0BB}&uDt5r9uYDӭ[u`u#:yk6DDWRDJ=W ¦M{u)LEG[ ʏp u|VC *r݆-[阈obEY> Ç|wzc^ז~νvضmf;԰_5gHE),"wP5YHDӢo%6uc{ >|:7};ߎqstǐ!5ѹsu4]4"+I\{wsۧb„'5Ƚ ]ԑ(hٲG[O(V}ETR {M ۶MwtoT$#_IΝCzqɆJ96x^, 0YMppc0Bm͚ ]l8{,jԸ4 `_8ȼʕAǎޣkÆЫWmɺK@*z5kF8w&Nlʕ f謎r" ;jۯYj%3̞ȾQX֯AL >3Ğ=]u+k,Zd~:{6dqG̛'Kh 5rdm7Y:&@,&JŤЦ =4w1NuRu}nVDDѶma'u\OȈ 6eJkudFUҺO}*ydc]wSfbɀ_G›@DT0sjO9 nq1@>{I;ƍc!2ctd>:U3tDv}R y5QN0i!23'&Mj#Сdy [pYy:;;DcԨFpor2s [oaY}۶Y"" a*2/7S%IDd,+|76Xv;OH,HDD "Y 0!H>ojdUIIhĥ^@YDDd}L)$^*24[Hǫvsv &:Z3+YRe5YR_T5E0@M,.&; ˧dX rysЫW-5|N& Һw…eY$2]]"*\̳\CB TQ'N$L#""&&.2iRKud:bc]>};E*!>Tu5۷ YD?w9?|Wg}c܎Ut ygcuτu on<.bbuȸ22XF89]sM%ݮ]tDDDdMLPGn 2\Opy&?(!;\ЧOu_3:"""&&Cn&[("=v XEp?Crl}J. 7興Ț Idt̘YDƶ?V*uilh*$ݡC1@t:s-YDABBۮ]'ѷwHH[/UfQ g1@jLLwNd۶I_~VllxrYD9P'[E*&Ndd?WG_!:ʛCuDDdn[W_mGm߮C0@tZL VdĉT[JJYT|"29sB`ݧ(Tz|޽_Bd(]zNc +z(7!, PMDwY_ի %aj?Ċ32{jR Ef6- wB^sT'OCF3Qd\L]A@ƌi"&E L"sx1aO`ϞSw֭tW6N%"SNIIbʔ/TO Ǫ&_~&8ĩ+ 9VچQ!#b*M렎`]vYYD0sZ:L􃎝Ο޽/]zz&bbāPs#88ߛW lVPl~y '+K._m̯i:"25kcϞG+֮DwTޤ2@DVK8^r5;6ot$XgȘ ʅ'hM2`56 M="{_Ց/(_ħnڵ0jWR>ꈈx|عs[:vcR9ܿ[D4cF'uTI+X1֑ 2,;{oq~*pͯ M…[Ѣ8rQΤc}`<7ӱk9" ;O8)11@Kc6FRM +Y|Vѿɠ]\'Vvzh„EyXg3CD94SuBӫWuosm:"a(,`%+ʠ7Tv;6LYgy\Ef&?[~ -ۤZ:rGSu$lڶRd4 ʃ%#U$SLyfqq!:"2 !66 I|_JO`LXBش6LZ$Ȋdfvb0kV?N:_(}d}k`߾ӨSeWY->HD'ȨpiT_SuJlؾul "7y[ML'^L d&f*V:<9oذ4~9sKvjZviSZDd}ȐwTt?͛AŊ/"+[u]];N舼 "7jҤ8&\xch 3UN1̙O5k7]UΜ3TIT77:OI/##Cڷ[3@dsSu?QPtn5ع32`LymcQRQr2 @fR֐ͤI-u$;Q*{9/Y27<&}~(wF`IeOnfI0v>gqէv r޺K "ټy e7 _J.#"T)&9ĉT/>YY2+OǜHu;yM,؂y֨(7-[]گyٱ%7&G@|T,]K)));-Q2&<LEŊ:"25d)yzx㗈y'OVg<s={;S.WǼm[$mٲOEf^XAhf:kY+;|+o4:nLyPE1dH1 }v/c"s&.s7f6[o-S,e~bݵkSf1@dvmW׷UdZN2{!=-̙!+#pmH6nȌd+=稈[ ݞŋwy G D^`ٸWѠA1G۶ъL]A=0p`u)} ..˔Z"2ѣ[{~xtLpMv4lȟ?O`?Z$ 0iR[y RlGJ:""쯽TEf;ݠ#&~}ΩPp(z]"c1:r+ :ѣG8Oyy;:u"3ڳZ"+UY0sZ#o`K{7[d^^[UGdt{d+"3ڶ8J"Bq;1yD^Rb, zݺU1];.]s=:r$YGWVV" l"2oي V6G]{i}yQɒw2ݷ K'$PAD4lX-u2#;x𬎮Ď>}蘈̙41]z[yB&MZ)D^Tx(wd[%KFD ܸ Ç"#ɐ[!9]=zpkk0}wG'a>1yD^āhU$O޽+ȼBCѺg7.?cYj:^*22u$xU {:#O#TwGS % /Mnþ}w|"l^1dHM5ԑ'd["cڵ$F ?@JLOQS' S "&_ Ӟv-ܲl@ѯ{3g$ n㫯aÙ(SA̜){& r?؃߮{ LyQ||(7o׬,|G{Y7/::M=ߖ{t.>bV]5yIDGY?GгXz:+3 {V0nu B:ܘ3W4mʔy-msK8D1`@5u,ȮYէ 7o^!!RE!55S.GXCxLj2UkeI'0@EQQLM~y 9L}P&kر:2Gfz)7dff~FhCx!46u$ N$;#[lĎaø){ e>[zxK3Xb+6m:{.LyQppXmd#~?x6þ DաCY#G3@fՎk蘈鯿diطOޛy?܅ "/s.~? ԪU1?|xΜSq|LJlYN:{ݧtteS'Q]v:5_T q|l;/_$֮unA5"_ѪUi#GRt9IcĈ:&"wh㽕y3?܁ "/ vvtƼyz(Ԯ]*/jذ:r| )I_nǠAuLD2k:)son~x_ r&390dHm8pz|ȇ5iRB}fyI zVѢHJҽ+V, 5k&˴i+ԑ|#Wc˘-…#C,GV$ AAw\^G]H<@lrXKtLq @n~v4lX ݍ9OkXf*;J.cj^vayȑ\OnKPGd%+Wgu\ "/ ]LÍ76mrP/N3w. [8""LmV 0^.`G˖}~"Oز:r?k /cr%&,,Kr&o RTw&&jHr%"a>u D^rb^{;RJ:26fCݺ%mX]7T]CT$40k5yѣ:"k ćcr&,,5.eM77}"R # 52O ZaQmDH\yj.x뭞_?IJDv9̛IG*Ly op?Q^Y@c%KGsQNQ8zt"#SuDV}!{Z 2p޽e=-UVM˯C9"" 33 gΜ=1D^_(/ʕsvǚ5uAV\ "/ e࿸o6Q+gUaКGDtAJ0(YתUtD1pb"tDDy|BEJnAΝY֭uD1phNQ#.5j$興RR2uDVuD*t "/cRQQtDDy.o-v)c"KIa 8r;= D^l6#ʯMK:Xr%S "/cR60yJ˖MuJʒ "p /p`SA1@e7;xi"ʯ]+ufѴm[FGDDe]69 łuDDy%k*{f阈R\`u潡0@eA5٢KQAWUͿ @8g4]^J V ʮ»l"/Cx$H+b_D5xp u4͒zUAXDT5uDDGIutDD%U۷/"3//cf:&"<:;Աʲ6c`X:͚Yo 3"ohev/ƍ>ѢnCpklvtTNDTڕE*nҌtLDd&,66 u&Dz$&F>OwPG#>>#F}"%'s uI-:&WaY&:&"W֭"*VIf'hc"+ +O*:&Wa ё İaR\iڴhYΧ__GY`nL@|||U Bt\k*lXa@|RDD%VeȑuLLJw~{#MF> +xGDVeǍ71D#_uqW"70cѽFkX+ơfMɆ\ "ӧwCP? F].]*rg"3,FG M"V- Fj/ILw_sTy D;3l>OqcIy Sl6f)"OQo~ҟX.O)h ;rQ~UQR,BCR'{Wq$$10eJku?XT"u 2qm P^1@d+ƪ/Yh׮,jJ}" b EfĉՍp5)"ؿ|-kUtv(}f~ei!9Lxc=  & Ībm[ Ulj('mۖd?sVvlʾ[S?UQKn4zUVǷnd_d=`;rCe-Jb Z, !)IRP|(2Pn ̜C[ldky.[6Ra­Cݳ_1cA泰rv<@n IRv.-aauS*7EZEѨQqkd,9_:\uBLL FѢaZ5^} WHjݸ4uv<'!2c7*;!zB|fr=7"YꨣPx>glZuZ 2ߎ=ߩxZ֬zُ֬.]>ѣRDK 9In5+:uvT{&NO?.7͞HG%v:f%5o^֛iGDHMRB[^ІO>Uu2&L 2ozWN A=\"(w!ʕ{{௿!(qqamDDDDVNQܳp}-p-o&LHPnĢEuuRJ߷㦛c6SdLޒ~Xbțڷ/sȺϤ 2@%l9#""""BѲeic;L՜YD~;CtLDDDDD "8:zzJŠ]2ODDDDDVSE MuLDDDDDVը*UUY(^<#G}"""""& ꡇZc2jëvCXX"""""& j([6NEJ(+3:{<YD6k5 R P}+W^nU1@d`ZwKa>|ި](  gʘ 2oHs@/`]ر~i/6m:ϐ/aM,^CGDDDDdux4k&LB "hܸ8Bt5f^#""""aZytaȧ0@dp~؉Culڴ II xn[ 2 Zv|zuRAR8f b+K 2:uu*~;w^z {-k 2ѵ$'YUll(&NlcELDu:YYط1@dA =鈈 ")Y2JGH#"""""+cD"tU!$$@ʘ 2Eu v4o^RDDDDDduLHB+Y۷ 20\LLZ.{DDDDDֵg);&&LuKׯ*l,lΓx5L=23 "p] #G1=O>ـ?ǭ_݋GiB|6D&%%JDIGDDDDd[øqߢbzE׮w.&L$1Q,%;%. zk'haj:1@d"qq׽>aٲC]CԽs y# "3 CRu/ʗq4"""""+HN>";*THkuǭwHLLrs?YQf%Px"u>>}W(D&SJOJJW㭷zbhР>Kcd5ɇwȑd#""""@?tXNr 2N?r4Ǝ @DDDDK 2ҥ #::D#} ݷYYR̂ "T`uP<x|D&)SW;O1@dBxJ c|U9Oe1@dB~~2xw%Ǹ 2!?s90@dBt6fQ1@dB $+S&ZGDDDDDdULPϞ{רQ1U1@dBŋGy*;O-[ "뮦P&LYD&գGE-(^< aGDDDDDVMJ3|j޼ʘ 2!Cjd"*,zdG""""":&L,0O=^EP$ 2V-/y"JYD쳝1 YDЮ]S]EfGTT!1@d3ftVp~&  Y 3ftү1@DRH(Əok6mDDDDDdvL&|DDDDDDD> """""""`0@DDDDDD """"""L&|DDDDDDD> """""""`0@DDDDDD """"""L&|DDDDDDD> """""""`0@DDDDDD """"""L&|DDDDDDD> """""""`0@DDDDDD """"""L&|DDDDDDD> """""""`0@DDDDDD """"""L&>|QN "z1l<||z}. "2,1s9ٳWr "S9w.C̙?]`Ղe1yr7>Z@ĩSuDDDDDDƔ)K2/ڿ/_:"""""aLaݺ2e䩿qbHIa('.z,-KaٲGDfק *0عsJ.DDD@ZZ&6l88r$ǎtg:'3ӎ,#88AA @bb8%"Qj{Zw략0@DwyLCFF>sy_~9=zT=""ʲvaժk)ǎ$2(lѢڶ-6ۉON;کS+R3&{إ3ʜfD`#::(^<JEZ8iSի/ȗ'38|8 FŊU"&&L "Xtњ+?u㎆1Ǝ'0o&`R"}\MUM!(]:ڕ 7E&EΟDrrcfCxx  pp7=_i2AvEdƀV-u&crիBB8항Z?kǾ}gpD*ΜIs8$@RѠA7.ʕ3Qȴ쯾 9:= D5D@EEd@ӬYI4o^d~ f=zWK\,{&./G~.n"Z-=ȕ~grA\\{ݲ`lh/㨵дi n]QS0!&iӷ$)73DD'Si?_ƶm_ʠ_lP҂ bKd$Ts rbɒoa\ w8! E)+E֭ˠk򹪷@TLDQ+-r' כ.&OWH*ʠ_ee<-I`Fam咒‘X睐:<^w~f Ȳ_\^={cC\^@˖%ѫWeԪUT0!&lsIˍ4uX ͩDmRnݺp2cض8OW)vAӞ\ l.\H`GA<Nҗի'OaK/…[Il>'wIBZ5Qc㦛2@. 1@d:*)M&MjGiD 6l8?<acSػ48^t+aI HN\F8Gm۲СlŠ{'Vާ~G__~2zę$lZ8t)QbXǫD 1@dOIEgwT޸q4ʖ["5yҿk)G'dZ\7dPzq3D@_ı6ZOڵڷ/λށg;]ز8vD,E RtjpwT;D 1@d MEZ|Un ^zU4s78nd*޽se?ݗ͊&(QY-j;@2{xյXJ =B~`QA~6$&Aj񎢛R8P℄0,$@ 1@d fll{DdvG: u3J}I ~d:t&K@q g~#,Ù3|"/[yKvbL~ @bb8"" !,,Uk+ƍ;ZR &5̘ ڻh;^OyNHHDs4F%j2j`Kwu-EUX*hSUʵN  Qa'Irι8'd[7}N콿^WԞX1yQ-/ǏwEYU>W^efM3<".dN9|to,\.яo|"ڲWՒk4|=tm&~=zdLr8[! Νrظ56mj-[vƶm;b{:_|{99iowe[`ŊM~˗o*{,-*pxߛo~q ʕg?\e׿^^.#kĎJBD4|d0cԨ1J~H|C~T `ӟ.ZuWqVe(P~yOlւu].nvEq;v>_)-[uVVnY|MGq~/mT綗-CVk9uyo[[ )3ԩcFT7gزnݶX4~\?Uuz\fwlю+ Hky(.XleqoC CsqvA̝;^YgEs^` Ջ߫uYxc^տ_w{___ɯut7m~j+on=`CUk5oyˌ^ST `vYߋ!=}QΎ}=zk}?eủ"xs{zw=go{Y"刪:u|̙3\b3ɓϠy |smޞG=!\US..y~}.-{[[B/{ϳe-鸾>+?rD@[ :2fӧ)S >0ƏRN9thLB34 4䱸{kv ]ٝ45kKW{WŲe-jXrKڕ^~gG=$^Oҁc_\  Hc-엾ř\'n (g~䑿qt,Z>niQ$}tm9\,O&~n]rd-;.r87WgL34 4⨧fsB|gtӨrH7/n[ZbѢueK.eo.Ngs̡q%skY1p3 q}+{^E:70FEHO…ˢǎM#Y׉WݲϹbswxᇏ'D H@#F묳W_PQwkY&ĂM4?W3,ѫ8?-fϞӦ*/gBЀ4;\{ݗ:eu_~1xs۠AbȐ- \&ק _o}{_r۷or)/ƦM;mZl;:;ʵׯ^ su۞y6s{ӅԧNuJ/+nXlUq&\SE-w2#f:(G#gQM$|sK_I=5SKYPZ^}` [lM=ׯOyܫWW|j};vm}hk뺆nc/zz;+Wm3eGo._k/Py= aPQZŜ9Cǔ)! f7)^fz@~zިmoS^i>ɗ}/'5cqq/ef̘^~tҴ9sLL4 b q1WC 1w?⪫.^OG9 tR\/g}Tt4 @YdC}S`xur喲W?g߸5ZZ~O"װkݞ|}?G}Qo)GkE ?~h$رL_m?;{93pᅯ+xkm޼e; B9yO]3tK/Y| b^dto}u1wC^@gۖ/-{WR۷g=ÞE~} { еu]/bР(qA +Ix`uytkkG~~\gذQ=$7oY4~ښ{F /A@ז-^!C B./v--;bZl֭;cϴ sh|0U.ykm{3o߾1`@s5ۀ}>|@ddQz4@z]vG,[8uA'ߢ9]@׋#zϖzA|>7}oR6޽s܎5(9f|YsyϣYP\Gb//s {hn_. {]?c3ѹxcq Y4s`J4iX{sr* 搅}GK36Gfڠ .Zk}o,(a'hB94/O<8hubԩqo*NФxQ|1L+ή/ZNC/m[\xǍ7Yw܄ ĉ]::~w׿x-nl9) -qOza\v)q!G*"?c{ss-R/;rI-ַ]wa#QH3q8q? ohͧegYm3Ϝ7xqQ3N=7nH h4ʉ_尥ǤIGm{L@5pv޽1no~;6?4^kJor~{cuqu ?Xq&9X\Uߟ`gE͎N;$MC/AuM޺x%K6=;~{39);@3ɹjetұ*^1}QIЀ/ڵ[5<_XfYq6@aqG168Knnzp]g󶀼4?1sx{И2ed B zƊ⡇׾6?3[A7MG;'8 E?"z24 @ڴ5.\]x| wŲeOgX\Wҳ79㬳iFر `_'Œ~_qr'4ΜIeo~M;$V?67Lë Yzw1cTOЀ='6ĵ>W]uO<\B0+!g̚uX|smj?p`R`{W7 dY~9X}0#''&h@KKKk<+ի,愁4%=tF'63:h%v$?˗w,+ٜ5' OB)IũΊ/~MA '@4 oݺmpy޾8[_J @=w .xU}1y=:g qK[%q啿y/֗4 @5{xիIG߾ne4 @cz-k;߹?.|^qh>a /,ˑѯ߸8!?>}dA m߾+,/<ۘZ[b\ݍ?ώ׾~ H<֯ kT+-e`w9(4 /V3f @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @PT*@ @4m0dH=;\KXG~S<_|#-[i7iZΉ9d|Iz聵I׎g^n{uV&p@yhbF?4fϞ^>4ٳg*OZv4Ϝֹ%%8b\:b'ww -Am3f;Y;4q'ᇏ<)W^@^zG{zŋ?ThƐ5|K<ԇkc0aи 6N q K4wԸsE3_gt?k_7?bot^0//?/.hv @qiV /ZJZ.SO} ƍc.-Ra#N{=?aG'P(ZZ6Vhmm[@ӧWxИ8qxz蘘3gR̝;%;nB3KRIENDB`qmapshack-1.10.0/MacOSX/build-routino.sh000644 001750 000144 00000007704 12705713523 021161 0ustar00oeichlerxusers000000 000000 #!/bin/bash if [[ "$ROUTINO_LIB_DIR" == "" ]]; then echo "ROUTINO_LIB_DIR not set" fi if [[ "$ROUTINO_SRC_DIR" == "" ]]; then echo "ROUTINO_SRC_DIR not set" fi ROUTINO_LIB_LIB_DIR=$ROUTINO_LIB_DIR/lib ROUTINO_LIB_H_DIR=$ROUTINO_LIB_DIR/include ROUTINO_LIB_XML_DIR=$ROUTINO_LIB_DIR/xml REPO_URL_B=http://routino.org/svn/branches/libroutino/ REPO_URL_T=http://routino.org/svn/trunk/ function checkoutRoutino { if ! [ -d "$ROUTINO_SRC_DIR" ]; then mkdir $ROUTINO_SRC_DIR svn checkout $REPO_URL_T fi } function updateRoutino { svn revert $ROUTINO_SRC_DIR svn update $ROUTINO_SRC_DIR } function buildRoutino { cd $ROUTINO_SRC_DIR rm $ROUTINO_SRC_DIR/src/*.o rm $ROUTINO_SRC_DIR/src/filedumper rm $ROUTINO_SRC_DIR/src/filedumper-slim rm $ROUTINO_SRC_DIR/src/filedumperx rm $ROUTINO_SRC_DIR/src/libroutino.so rm $ROUTINO_SRC_DIR/src/planetsplitter rm $ROUTINO_SRC_DIR/src/planetsplitter-slim rm $ROUTINO_SRC_DIR/src/router rm $ROUTINO_SRC_DIR/src/router-slim pimpMakefileConf make } function adjustLinking { sudo install_name_tool -id $ROUTINO_LIB_LIB_DIR/libroutino.so $ROUTINO_LIB_LIB_DIR/libroutino.so sudo install_name_tool -id $ROUTINO_LIB_LIB_DIR/routino.so $ROUTINO_LIB_LIB_DIR/routino.so sudo install_name_tool -id $ROUTINO_LIB_LIB_DIR/routino.a $ROUTINO_LIB_LIB_DIR/routino.a sudo install_name_tool -id $ROUTINO_LIB_LIB_DIR/libroutino.a $ROUTINO_LIB_LIB_DIR/libroutino.a } function pimpMakefileConf { sed 's/LDFLAGS_SONAME.*/LDFLAGS_SONAME=-dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,$(SOVERSION),-current_version,$(SOVERSION),-install_name,"libroutino.so" -o "libroutino.so"/' $ROUTINO_SRC_DIR/Makefile.conf> ./makefile.tmp sed 's/LDFLAGS_SLIM_SONAME.*/LDFLAGS_SLIM_SONAME=-dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,$(SOVERSION),-current_version,$(SOVERSION),-install_name,"libroutino-slim.so" -o "libroutino-slim.so"/' ./makefile.tmp > ./makefile2.tmp sed 's/LDFLAGS_LDSO.*/LDFLAGS_LDSO=-Wl/' ./makefile2.tmp > $ROUTINO_SRC_DIR/Makefile.conf rm ./makefile.tmp rm ./makefile2.tmp # Makefile.conf # LDFLAGS_SONAME=-dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,$(SOVERSION),-current_version,$(SOVERSION),-install_name,"libroutino.so" -o "libroutino.so" # LDFLAGS_SLIM_SONAME=-dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,$(SOVERSION),-current_version,$(SOVERSION),-install_name,"libroutino-slim.so" -o "libroutino-slim.so" # LDFLAGS_LDSO=-Wl } function releaseRoutino { rm -R $ROUTINO_LIB_DIR/* mkdir $ROUTINO_LIB_LIB_DIR mkdir $ROUTINO_LIB_H_DIR mkdir $ROUTINO_LIB_XML_DIR cp $ROUTINO_SRC_DIR/src/libroutino.so $ROUTINO_LIB_LIB_DIR cp $ROUTINO_SRC_DIR/src/routino.h $ROUTINO_LIB_H_DIR cp $ROUTINO_SRC_DIR/xml/routino-profiles.xml $ROUTINO_LIB_XML_DIR cp $ROUTINO_SRC_DIR/xml/routino-tagging.xml $ROUTINO_LIB_XML_DIR cp $ROUTINO_SRC_DIR/xml/routino-translations.xml $ROUTINO_LIB_XML_DIR cp $ROUTINO_SRC_DIR/src/planetsplitter $ROUTINO_LIB_LIB_DIR cp $ROUTINO_LIB_LIB_DIR/libroutino.so $ROUTINO_LIB_LIB_DIR/routino cp $ROUTINO_LIB_LIB_DIR/libroutino.so $ROUTINO_LIB_LIB_DIR/routino.so cp $ROUTINO_LIB_LIB_DIR/libroutino.so $ROUTINO_LIB_LIB_DIR/routino.a cp $ROUTINO_LIB_LIB_DIR/libroutino.so $ROUTINO_LIB_LIB_DIR/libroutino.a cp $ROUTINO_LIB_XML_DIR/routino-profiles.xml $ROUTINO_LIB_XML_DIR/profiles.xml cp $ROUTINO_LIB_XML_DIR/routino-tagging.xml $ROUTINO_LIB_XML_DIR/tagging.xml cp $ROUTINO_LIB_XML_DIR/routino-translations.xml $ROUTINO_LIB_XML_DIR/translations.xml } if [[ "$1" == "routino-build" ]]; then checkoutRoutino updateRoutino buildRoutino releaseRoutino adjustLinking fiqmapshack-1.10.0/.kdev4/000755 001750 000144 00000000000 12513726671 016027 5ustar00oeichlerxusers000000 000000 qmapshack-1.10.0/qmapshack.1000644 001750 000144 00000001777 12705713524 016776 0ustar00oeichlerxusers000000 000000 .TH QMAPSHACK 1 "July 2014" "" "" .SH NAME QMapShack \- GPS mapping (GeoTiff and vector) and GPSr management .SH SYNOPSIS \fBqmapshack\fP [\options\fP] [ .B \-d | .B \-\-debug ] [ .B \-h | .B \-\-help ] [ .B \-n | .B \-\-no-splash ] [ .IR files ... ] .SH DESCRIPTION GPS mapping (GeoTiff and vector) and GPSr management. QMapShack provides a versatile tool for GPS maps in GeoTiff format as well as Garmin's img vector map format. You can also view and edit your GPX tracks. QMapShack is the successor of QLandkarteGT. .TP Main features: \- Use of several workspaces. \- Use several maps on a workspace. \- Handle data project-oriented. .SH OPTIONS .TP \fB\-d\fR, \fB\-\-debug\fR Run with debugging output. .TP \fB\-h\fR, \fB\-\-help\fR Displays the help message. .TP \fB\-n\fR, \fB\-\-no-splash\fR Start without splash screen. .TP .SH SEE ALSO . .SH AUTHOR \fIQMapShack\fR was written and is currently maintained by Oliver Eichler \fB\fR. qmapshack-1.10.0/ConfigureChecks.cmake000644 001750 000144 00000001764 12374350216 021001 0ustar00oeichlerxusers000000 000000 include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) include(TestBigEndian) set(PACKAGE ${APPLICATION_NAME}) set(VERSION ${APPLICATION_VERSION}) set(DATADIR ${DATA_INSTALL_DIR}) set(LIBDIR ${LIB_INSTALL_DIR}) set(PLUGINDIR "${PLUGIN_INSTALL_DIR}") set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) set(BINARYDIR ${CMAKE_BINARY_DIR}) set(SOURCEDIR ${CMAKE_SOURCE_DIR}) set(SHARED_LIB_EXT ".dll") if (UNIX AND NOT WIN32) if (APPLE) set(SHARED_LIB_EXT ".dylib") else(APPLE) set(SHARED_LIB_EXT ".so") endif(APPLE) endif (UNIX AND NOT WIN32) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(inttypes.h HAVE_INTTYPES_H) check_include_file(byteswap.h HAVE_BYTESWAP_H) test_big_endian(HAVE_BIGENDIAN) check_function_exists(arc4random HAVE_ARC4RANDOM) # check if we're on a 64bit host if(CMAKE_SIZEOF_VOID_P MATCHES "8") SET(HOST_IS_64_BIT 1) endif(CMAKE_SIZEOF_VOID_P MATCHES "8") qmapshack-1.10.0/Doxyfile000644 001750 000144 00000312143 12627613665 016452 0ustar00oeichlerxusers000000 000000 # Doxyfile 1.8.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = MapRoom # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = /home/oeichler/Code/cpp/MapRoom/src/icons/48x48/MapRoom.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = ./doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = YES # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = ./src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf \ *.as \ *.js # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /

1 Introduction
    1.1 What is ALGLIB
    1.2 ALGLIB license
    1.3 Documentation license
    1.4 Reference Manual and User Guide
    1.5 Acknowledgements
2 ALGLIB structure
    2.1 Packages
    2.2 Subpackages
    2.3 Open Source and Commercial versions
3 Compatibility
    3.1 CPU
    3.2 OS
    3.3 Compiler
    3.4 Optimization settings
4 Compiling ALGLIB
    4.1 Adding to your project
    4.2 Configuring for your compiler
    4.3 Improving performance (CPU-specific and OS-specific optimizations)
5 Working with commercial version
    5.1 Benefits of commercial version
    5.2 Working with SSE support (Intel/AMD users)
    5.3 Using multithreading
        5.3.1 SMT (CMT/hyper-threading) issues
    5.4 Linking with Intel MKL
        5.4.1 Using lightweight Intel MKL supplied by ALGLIB Project
        5.4.2 Using your own installation of Intel MKL
    5.5 Examples - compiling commercial edition of ALGLIB
        5.5.1 Introduction
        5.5.2 Compiling under Windows
6 Using ALGLIB
    6.1 Thread-safety
    6.2 Global definitions
    6.3 Datatypes
    6.4 Constants
    6.5 Functions
    6.6 Working with vectors and matrices
    6.7 Using functions: 'expert' and 'friendly' interfaces
    6.8 Handling errors
    6.9 Working with Level 1 BLAS functions
    6.10 Reading data from CSV files
7 Advanced topics
    7.1 Testing ALGLIB
8 ALGLIB packages and subpackages
    8.1 AlglibMisc package
    8.2 DataAnalysis package
    8.3 DiffEquations package
    8.4 FastTransforms package
    8.5 Integration package
    8.6 Interpolation package
    8.7 LinAlg package
    8.8 Optimization package
    8.9 Solvers package
    8.10 SpecialFunctions package
    8.11 Statistics package